From 65b1a7431680da730f24316c92e125bef6298462 Mon Sep 17 00:00:00 2001 From: "xiangren.yuan" Date: Mon, 5 Dec 2022 12:25:10 +0800 Subject: [PATCH] add mips halley5 board kernel(small) patches Signed-off-by: xiangren.yuan Change-Id: I1270075f176f55e942ef3b93585b1f31419fe1ad --- linux-5.10/halley5_patch/halley5.patch | 1179626 +++++++++++++++++++++ linux-5.10/halley5_patch/hdf.patch | 341 + 2 files changed, 1179967 insertions(+) create mode 100644 linux-5.10/halley5_patch/halley5.patch create mode 100644 linux-5.10/halley5_patch/hdf.patch diff --git a/linux-5.10/halley5_patch/halley5.patch b/linux-5.10/halley5_patch/halley5.patch new file mode 100644 index 0000000..d69caee --- /dev/null +++ b/linux-5.10/halley5_patch/halley5.patch @@ -0,0 +1,1179626 @@ +From c861003ecee3406e2fd2aec131102b2fcbc70991 Mon Sep 17 00:00:00 2001 +From: "xiangren.yuan" +Date: Sat, 26 Nov 2022 12:37:47 +0800 +Subject: [PATCH] halley5 + +--- + Kconfig | 2 + + Makefile | 4 +- + arch/mips/Kbuild.platforms | 2 + + arch/mips/Kconfig | 63 +- + arch/mips/boot/dts/Makefile | 2 + + arch/mips/configs/halley5_small_defconfig | 4478 +++ + arch/mips/generic/board-ingenic.c | 3 + + arch/mips/include/asm/bootinfo.h | 1 + + arch/mips/include/asm/cpu-features.h | 12 + + arch/mips/include/asm/cpu-type.h | 1 + + arch/mips/include/asm/cpu.h | 17 +- + arch/mips/include/asm/mipsregs.h | 11 +- + arch/mips/include/asm/msa.h | 4 + + arch/mips/include/asm/pgtable-bits.h | 15 + + arch/mips/include/asm/processor.h | 56 +- + arch/mips/include/asm/stackframe.h | 2 +- + arch/mips/include/asm/switch_to.h | 19 + + arch/mips/kernel/cpu-probe.c | 19 +- + arch/mips/kernel/genex.S | 1 + + arch/mips/kernel/idle.c | 18 +- + arch/mips/kernel/setup.c | 2 +- + arch/mips/kernel/smp.c | 1 + + arch/mips/kernel/traps.c | 56 + + arch/mips/mm/c-r4k.c | 33 +- + arch/mips/mm/dma-noncoherent.c | 2 + + arch/mips/mm/sc-mips.c | 2 +- + arch/mips/mm/tlb-r4k.c | 7 +- + arch/mips/mm/tlbex.c | 1 + + arch/mips/xburst/Kconfig | 69 + + arch/mips/xburst/Makefile | 4 + + arch/mips/xburst/Platform | 7 + + arch/mips/xburst/common/Makefile | 5 + + .../mips/xburst/common/include/ingenic_proc.h | 18 + + arch/mips/xburst/common/include/jz_notifier.h | 45 + + arch/mips/xburst/common/include/mxu.h | 66 + + arch/mips/xburst/common/include/mxu_media.h | 1832 ++ + arch/mips/xburst/common/include/mxuv3.h | 47 + + arch/mips/xburst/common/initrd-check.c | 49 + + arch/mips/xburst/common/jz_notifier.c | 83 + + arch/mips/xburst/common/mxu-xburst.c | 85 + + arch/mips/xburst/common/proc.c | 92 + + arch/mips/xburst/common/prom.c | 63 + + arch/mips/xburst/common/sc-xburst.c | 238 + + arch/mips/xburst/debug/Makefile | 1 + + arch/mips/xburst/debug/trace-exit.c | 31 + + arch/mips/xburst/soc-x1000/Kconfig.DT | 9 + + arch/mips/xburst/soc-x1000/Makefile | 5 + + arch/mips/xburst/soc-x1000/early_printk.c | 76 + + .../soc-x1000/include/cpu-feature-overrides.h | 60 + + arch/mips/xburst/soc-x1000/include/irq.h | 30 + + arch/mips/xburst/soc-x1000/include/soc/base.h | 90 + + .../mips/xburst/soc-x1000/include/soc/cache.h | 116 + + arch/mips/xburst/soc-x1000/include/soc/cpm.h | 159 + + arch/mips/xburst/soc-x1000/include/soc/ost.h | 41 + + arch/mips/xburst/soc-x1000/include/soc/sfc.h | 152 + + .../soc-x1000/include/soc/tcsm_layout.h | 53 + + arch/mips/xburst/soc-x1000/include/soc/tcu.h | 37 + + arch/mips/xburst/soc-x1000/include/war.h | 27 + + arch/mips/xburst/soc-x1000/pm.c | 221 + + .../mips/xburst/soc-x1000/regs_save_restore.S | 174 + + arch/mips/xburst/soc-x1000/setup.c | 80 + + arch/mips/xburst/soc-x1000/socid.c | 110 + + arch/mips/xburst/soc-x1600/Kconfig.DT | 19 + + arch/mips/xburst/soc-x1600/Makefile | 6 + + arch/mips/xburst/soc-x1600/early_printk.c | 99 + + arch/mips/xburst/soc-x1600/gpio.c | 130 + + .../soc-x1600/include/cpu-feature-overrides.h | 61 + + arch/mips/xburst/soc-x1600/include/irq.h | 35 + + arch/mips/xburst/soc-x1600/include/libdmmu.h | 30 + + arch/mips/xburst/soc-x1600/include/soc/base.h | 66 + + .../mips/xburst/soc-x1600/include/soc/cache.h | 95 + + arch/mips/xburst/soc-x1600/include/soc/cpm.h | 135 + + arch/mips/xburst/soc-x1600/include/soc/ddr.h | 295 + + .../mips/xburst/soc-x1600/include/soc/efuse.h | 192 + + arch/mips/xburst/soc-x1600/include/soc/gpio.h | 44 + + arch/mips/xburst/soc-x1600/include/soc/ost.h | 41 + + arch/mips/xburst/soc-x1600/include/soc/sfc.h | 207 + + .../soc-x1600/include/soc/tcsm_layout.h | 53 + + arch/mips/xburst/soc-x1600/include/soc/tcu.h | 84 + + arch/mips/xburst/soc-x1600/include/war.h | 27 + + arch/mips/xburst/soc-x1600/libdmmu.c | 1087 + + arch/mips/xburst/soc-x1600/pm.c | 762 + + arch/mips/xburst/soc-x1600/pm.h | 136 + + .../mips/xburst/soc-x1600/regs_save_restore.S | 190 + + .../xburst/soc-x1600/regs_save_restore.py | 123 + + arch/mips/xburst/soc-x1600/setup.c | 93 + + arch/mips/xburst2/Kconfig | 105 + + arch/mips/xburst2/Makefile | 7 + + arch/mips/xburst2/Platform | 7 + + arch/mips/xburst2/common/Makefile | 11 + + .../mips/xburst2/common/cpu_ddr_test/Makefile | 11 + + .../common/cpu_ddr_test/cpu_ccu_test.c | 70 + + .../common/cpu_ddr_test/cpu_dma_test.c | 269 + + .../common/cpu_ddr_test/cpu_spinlock_test.c | 75 + + .../xburst2/common/cpu_ddr_test/cpu_tcsm.h | 16 + + .../common/cpu_ddr_test/cpu_watch_test.c | 200 + + .../cpu_ddr_test/ddr_bandwidth_monitor.c | 461 + + .../common/cpu_ddr_test/ddr_change_freq.c | 521 + + .../xburst2/common/cpu_ddr_test/l2c_test.c | 527 + + .../common/cpu_ddr_test/multithread_test.c | 258 + + .../common/cpu_ddr_test/multithread_test.h | 9 + + .../common/cpu_ddr_test/raw_dma_test.c | 273 + + arch/mips/xburst2/common/get-cpu-features.c | 98 + + arch/mips/xburst2/common/initrd-check.c | 58 + + arch/mips/xburst2/common/mxuv3.c | 697 + + arch/mips/xburst2/common/proc.c | 92 + + arch/mips/xburst2/core/Makefile | 4 + + arch/mips/xburst2/core/include/ccu.h | 42 + + arch/mips/xburst2/core/include/core_base.h | 6 + + arch/mips/xburst2/core/include/ingenic_proc.h | 18 + + arch/mips/xburst2/core/include/irq_cpu.h | 6 + + arch/mips/xburst2/core/include/mxu.h | 59 + + arch/mips/xburst2/core/include/mxuv3.h | 47 + + arch/mips/xburst2/core/prom.c | 79 + + arch/mips/xburst2/core/sc.c | 199 + + arch/mips/xburst2/core/smp.c | 505 + + arch/mips/xburst2/soc-m300/Kconfig.DT | 11 + + arch/mips/xburst2/soc-m300/Makefile | 12 + + .../soc-m300/include/cpu-feature-overrides.h | 66 + + arch/mips/xburst2/soc-m300/include/irq.h | 39 + + arch/mips/xburst2/soc-m300/include/libdmmu.h | 30 + + arch/mips/xburst2/soc-m300/include/soc/base.h | 77 + + .../mips/xburst2/soc-m300/include/soc/cache.h | 28 + + arch/mips/xburst2/soc-m300/include/soc/cpm.h | 136 + + arch/mips/xburst2/soc-m300/include/soc/ddr.h | 293 + + .../mips/xburst2/soc-m300/include/soc/extal.h | 12 + + arch/mips/xburst2/soc-m300/include/soc/rtc.h | 96 + + arch/mips/xburst2/soc-m300/include/soc/sfc.h | 211 + + .../soc-m300/include/soc/tcsm_layout.h | 53 + + arch/mips/xburst2/soc-m300/include/war.h | 27 + + arch/mips/xburst2/soc-m300/libdmmu.c | 1087 + + arch/mips/xburst2/soc-m300/pm.c | 252 + + arch/mips/xburst2/soc-m300/pm.h | 175 + + arch/mips/xburst2/soc-m300/pm_fastboot.c | 503 + + arch/mips/xburst2/soc-m300/pm_fastboot.h | 172 + + arch/mips/xburst2/soc-m300/pm_sleep.c | 357 + + arch/mips/xburst2/soc-m300/pm_sleep.h | 16 + + .../mips/xburst2/soc-m300/regs_save_restore.S | 190 + + .../xburst2/soc-m300/regs_save_restore.py | 124 + + arch/mips/xburst2/soc-m300/reset.c | 327 + + arch/mips/xburst2/soc-m300/serial.c | 91 + + arch/mips/xburst2/soc-m300/setup.c | 84 + + .../xburst2/soc-m300/sleep_firmware/Makefile | 42 + + .../xburst2/soc-m300/sleep_firmware/Readme | 14 + + .../soc-m300/sleep_firmware/include/base.h | 91 + + .../soc-m300/sleep_firmware/include/cpm.h | 230 + + .../soc-m300/sleep_firmware/include/ddr.h | 289 + + .../soc-m300/sleep_firmware/include/gpio.h | 267 + + .../sleep_firmware/include/pm_fastboot.h | 187 + + .../soc-m300/sleep_firmware/include/uart.h | 113 + + .../soc-m300/sleep_firmware/mkmodule.sh | 7 + + .../sleep_firmware/src/fastboot_resume.c | 314 + + .../soc-m300/sleep_firmware/src/uart.c | 97 + + .../xburst2/soc-m300/sleep_firmware/target.ld | 37 + + arch/mips/xburst2/soc-x2000/Kconfig.DT | 20 + + arch/mips/xburst2/soc-x2000/Makefile | 12 + + arch/mips/xburst2/soc-x2000/gpio.c | 123 + + .../soc-x2000/include/cpu-feature-overrides.h | 66 + + arch/mips/xburst2/soc-x2000/include/irq.h | 39 + + arch/mips/xburst2/soc-x2000/include/libdmmu.h | 30 + + .../mips/xburst2/soc-x2000/include/soc/base.h | 77 + + .../xburst2/soc-x2000/include/soc/cache.h | 73 + + arch/mips/xburst2/soc-x2000/include/soc/cpm.h | 136 + + arch/mips/xburst2/soc-x2000/include/soc/ddr.h | 293 + + .../xburst2/soc-x2000/include/soc/efuse.h | 365 + + .../xburst2/soc-x2000/include/soc/extal.h | 12 + + .../mips/xburst2/soc-x2000/include/soc/gpio.h | 42 + + arch/mips/xburst2/soc-x2000/include/soc/rtc.h | 96 + + arch/mips/xburst2/soc-x2000/include/soc/sfc.h | 211 + + .../soc-x2000/include/soc/tcsm_layout.h | 53 + + arch/mips/xburst2/soc-x2000/include/war.h | 27 + + arch/mips/xburst2/soc-x2000/libdmmu.c | 1087 + + arch/mips/xburst2/soc-x2000/pm.c | 539 + + arch/mips/xburst2/soc-x2000/pm.h | 169 + + arch/mips/xburst2/soc-x2000/pm_fastboot.c | 667 + + arch/mips/xburst2/soc-x2000/pm_fastboot.h | 106 + + .../xburst2/soc-x2000/regs_save_restore.S | 190 + + .../xburst2/soc-x2000/regs_save_restore.py | 124 + + arch/mips/xburst2/soc-x2000/reset.c | 327 + + arch/mips/xburst2/soc-x2000/serial.c | 91 + + arch/mips/xburst2/soc-x2000/setup.c | 84 + + .../xburst2/soc-x2000/sleep_firmware/Makefile | 42 + + .../xburst2/soc-x2000/sleep_firmware/Readme | 14 + + .../soc-x2000/sleep_firmware/include/base.h | 91 + + .../soc-x2000/sleep_firmware/include/cpm.h | 230 + + .../soc-x2000/sleep_firmware/include/ddr.h | 289 + + .../soc-x2000/sleep_firmware/include/gpio.h | 267 + + .../sleep_firmware/include/pm_fastboot.h | 106 + + .../soc-x2000/sleep_firmware/include/uart.h | 113 + + .../soc-x2000/sleep_firmware/mkmodule.sh | 7 + + .../sleep_firmware/src/fastboot_resume.c | 328 + + .../soc-x2000/sleep_firmware/src/uart.c | 97 + + .../soc-x2000/sleep_firmware/target.ld | 37 + + .../xburst2/soc-x2000/sleep_firmware/tmp.map | 75 + + arch/mips/xburst2/soc-x2500/Kconfig.DT | 15 + + arch/mips/xburst2/soc-x2500/Makefile | 8 + + arch/mips/xburst2/soc-x2500/gpio.c | 123 + + .../soc-x2500/include/cpu-feature-overrides.h | 67 + + arch/mips/xburst2/soc-x2500/include/irq.h | 40 + + arch/mips/xburst2/soc-x2500/include/libdmmu.h | 30 + + .../mips/xburst2/soc-x2500/include/soc/base.h | 97 + + .../xburst2/soc-x2500/include/soc/cache.h | 73 + + arch/mips/xburst2/soc-x2500/include/soc/cpm.h | 143 + + arch/mips/xburst2/soc-x2500/include/soc/ddr.h | 293 + + .../xburst2/soc-x2500/include/soc/extal.h | 8 + + .../mips/xburst2/soc-x2500/include/soc/gpio.h | 40 + + arch/mips/xburst2/soc-x2500/include/soc/mmc.h | 5 + + .../mips/xburst2/soc-x2500/include/soc/pdma.h | 49 + + arch/mips/xburst2/soc-x2500/include/soc/rtc.h | 96 + + arch/mips/xburst2/soc-x2500/include/soc/sfc.h | 211 + + .../soc-x2500/include/soc/tcsm_layout.h | 53 + + arch/mips/xburst2/soc-x2500/include/war.h | 27 + + arch/mips/xburst2/soc-x2500/libdmmu.c | 1087 + + arch/mips/xburst2/soc-x2500/pm.c | 608 + + arch/mips/xburst2/soc-x2500/pm.h | 136 + + arch/mips/xburst2/soc-x2500/pm_fastboot.c | 667 + + arch/mips/xburst2/soc-x2500/pm_fastboot.h | 106 + + .../xburst2/soc-x2500/regs_save_restore.S | 190 + + .../xburst2/soc-x2500/regs_save_restore.py | 124 + + arch/mips/xburst2/soc-x2500/reset.c | 331 + + arch/mips/xburst2/soc-x2500/serial.c | 91 + + arch/mips/xburst2/soc-x2500/setup.c | 84 + + block/partitions/efi.c | 2 + + drivers/char/Makefile | 2 + + drivers/char/jz_spinand_firmware.c | 486 + + drivers/char/jz_spinand_firmware.h | 63 + + drivers/media/platform/v4l2loopback/Makefile | 1 + + .../platform/v4l2loopback/v4l2loopback.c | 3016 +++ + .../platform/v4l2loopback/v4l2loopback.h | 92 + + .../v4l2loopback/v4l2loopback_formats.h | 427 + + drivers/mmc/core/block.c | 29 +- + drivers/mmc/core/core.c | 5 +- + drivers/mmc/core/host.c | 56 +- + drivers/mmc/core/sdio.c | 36 + + drivers/mmc/host/sdhci.c | 15 +- + drivers/mmc/host/sdhci.h | 3 +- + drivers/mtd/Kconfig | 15 + + drivers/mtd/Makefile | 1 + + drivers/mtd/mtdblock_bbt_ro.c | 184 + + drivers/usb/common/common.c | 122 +- + drivers/usb/common/debug.c | 22 +- + drivers/usb/common/usb-conn-gpio.c | 6 +- + drivers/usb/core/devices.c | 21 +- + drivers/usb/core/endpoint.c | 35 +- + drivers/usb/core/hcd.c | 45 +- + drivers/usb/core/hub.c | 37 +- + drivers/usb/core/sysfs.c | 29 +- + drivers/usb/core/urb.c | 9 + + drivers/usb/core/usb.c | 8 +- + drivers/usb/dwc2/Kconfig | 20 + + drivers/usb/dwc2/core.c | 214 +- + drivers/usb/dwc2/core.h | 102 +- + drivers/usb/dwc2/core_intr.c | 136 +- + drivers/usb/dwc2/debugfs.c | 5 +- + drivers/usb/dwc2/drd.c | 118 +- + drivers/usb/dwc2/gadget.c | 511 +- + drivers/usb/dwc2/hcd.c | 636 +- + drivers/usb/dwc2/hcd_queue.c | 2 +- + drivers/usb/dwc2/hw.h | 33 +- + drivers/usb/dwc2/params.c | 257 +- + drivers/usb/dwc2/pci.c | 18 - + drivers/usb/dwc2/platform.c | 195 +- + drivers/usb/gadget/Kconfig | 31 + + drivers/usb/gadget/composite.c | 100 +- + drivers/usb/gadget/configfs.c | 157 + + drivers/usb/gadget/function/Makefile | 4 + + drivers/usb/gadget/function/f_fs.c | 9 +- + drivers/usb/gadget/function/f_hid.c | 224 +- + drivers/usb/gadget/function/f_mass_storage.c | 34 +- + drivers/usb/gadget/function/f_midi.c | 12 +- + drivers/usb/gadget/function/f_mtp.c | 1536 ++ + drivers/usb/gadget/function/f_mtp.h | 18 + + drivers/usb/gadget/function/f_ncm.c | 50 +- + drivers/usb/gadget/function/f_printer.c | 5 +- + drivers/usb/gadget/function/f_ptp.c | 38 + + drivers/usb/gadget/function/f_uac1.c | 893 +- + drivers/usb/gadget/function/f_uac2.c | 1039 +- + drivers/usb/gadget/function/f_uvc.c | 2 +- + drivers/usb/gadget/function/rndis.c | 47 +- + drivers/usb/gadget/function/u_audio.c | 717 +- + drivers/usb/gadget/function/u_audio.h | 34 + + drivers/usb/gadget/function/u_ether.c | 46 +- + drivers/usb/gadget/function/u_ether.h | 12 + + .../usb/gadget/function/u_ether_configfs.h | 15 +- + drivers/usb/gadget/function/u_hid.h | 5 +- + drivers/usb/gadget/function/u_midi.h | 4 +- + drivers/usb/gadget/function/u_serial.c | 42 +- + drivers/usb/gadget/function/u_uac1.h | 22 +- + drivers/usb/gadget/function/u_uac2.h | 29 +- + drivers/usb/gadget/function/uvc.h | 17 +- + drivers/usb/gadget/function/uvc_configfs.c | 7 +- + drivers/usb/gadget/function/uvc_queue.c | 24 +- + drivers/usb/gadget/function/uvc_queue.h | 8 +- + drivers/usb/gadget/function/uvc_v4l2.c | 51 +- + drivers/usb/gadget/function/uvc_video.c | 156 +- + drivers/usb/gadget/function/uvc_video.h | 2 + + drivers/usb/gadget/legacy/Kconfig | 14 +- + drivers/usb/gadget/legacy/dbgp.c | 15 +- + drivers/usb/gadget/legacy/hid.c | 4 +- + drivers/usb/gadget/legacy/inode.c | 29 +- + drivers/usb/gadget/legacy/mass_storage.c | 4 +- + drivers/usb/gadget/legacy/multi.c | 14 +- + drivers/usb/gadget/legacy/printer.c | 1 + + drivers/usb/gadget/legacy/raw_gadget.c | 3 +- + drivers/usb/gadget/legacy/webcam.c | 2 +- + drivers/usb/gadget/udc/Kconfig | 1 - + drivers/usb/gadget/udc/amd5536udc_pci.c | 10 +- + drivers/usb/gadget/udc/aspeed-vhub/core.c | 3 +- + drivers/usb/gadget/udc/aspeed-vhub/epn.c | 2 +- + drivers/usb/gadget/udc/at91_udc.c | 4 +- + drivers/usb/gadget/udc/bdc/bdc_core.c | 30 +- + drivers/usb/gadget/udc/core.c | 107 +- + drivers/usb/gadget/udc/dummy_hcd.c | 14 +- + drivers/usb/gadget/udc/fotg210-udc.c | 26 +- + drivers/usb/gadget/udc/max3420_udc.c | 14 +- + drivers/usb/gadget/udc/mv_u3d_core.c | 19 +- + drivers/usb/gadget/udc/pch_udc.c | 123 +- + drivers/usb/gadget/udc/r8a66597-udc.c | 4 +- + drivers/usb/gadget/udc/renesas_usb3.c | 22 +- + drivers/usb/gadget/udc/s3c2410_udc.c | 32 +- + drivers/usb/gadget/udc/snps_udc_core.c | 30 +- + drivers/usb/gadget/udc/tegra-xudc.c | 7 +- + drivers/usb/gadget/udc/udc-xilinx.c | 6 - + drivers/usb/phy/Kconfig | 20 + + drivers/usb/phy/Makefile | 3 + + drivers/usb/phy/phy-fsl-usb.c | 2 - + drivers/usb/phy/phy-ingenic-inno.c | 748 + + drivers/usb/phy/phy-ingenic-x1000.c | 66 + + drivers/usb/phy/phy-ingenic-x1600.c | 139 + + drivers/usb/phy/phy-ingenic-x2000.c | 85 + + drivers/usb/phy/phy-ingenic-x2500.c | 117 + + drivers/usb/phy/phy-ingenic.c | 639 + + drivers/usb/phy/phy-ingenic.h | 111 + + drivers/usb/phy/phy-tahvo.c | 4 +- + drivers/usb/phy/phy-twl6030-usb.c | 5 - + drivers/usb/phy/phy.c | 61 +- + drivers/usb/roles/class.c | 9 + + include/dt-bindings/clock/ingenic-m300.h | 201 + + include/dt-bindings/clock/ingenic-tcu.h | 29 + + include/dt-bindings/clock/ingenic-x1600.h | 146 + + include/dt-bindings/clock/ingenic-x2000.h | 201 + + include/dt-bindings/clock/ingenic-x2500.h | 136 + + include/dt-bindings/dma/ingenic-pdma.h | 89 + + include/dt-bindings/gpio/ingenic-gpio.h | 8 + + .../interrupt-controller/m300-irq.h | 72 + + .../interrupt-controller/mips-irq.h | 16 + + .../interrupt-controller/x1000-irq.h | 72 + + .../interrupt-controller/x1600-irq.h | 72 + + .../interrupt-controller/x2000-irq.h | 72 + + .../interrupt-controller/x2500-irq.h | 75 + + include/dt-bindings/net/ingenic_gmac.h | 9 + + include/dt-bindings/pinctrl/ingenic-pinctrl.h | 79 + + include/dt-bindings/power/axp216-power.h | 21 + + include/dt-bindings/sound/ingenic-baic.h | 34 + + include/linux/dma-map-ops.h | 8 +- + include/linux/dmaengine.h | 8 + + include/linux/mfd/ingenic-tcu_v1.h | 202 + + include/linux/mfd/ingenic-tcu_v2.h | 383 + + include/linux/mfd/ingenic_adc.h | 317 + + include/linux/usb.h | 13 +- + include/linux/usb/audio-v2.h | 14 + + include/linux/usb/ch9.h | 62 +- + include/linux/usb/composite.h | 4 +- + include/linux/usb/f_mtp.h | 23 + + include/linux/usb/gadget.h | 20 +- + include/linux/usb/hcd.h | 21 +- + include/linux/usb/otg-fsm.h | 1 - + include/linux/usb/otg.h | 3 +- + include/linux/usb/pd.h | 2 +- + include/linux/usb/phy.h | 11 + + include/linux/usb/quirks.h | 2 +- + include/linux/usb/role.h | 6 + + include/linux/usb/usbnet.h | 2 - + include/media/ingenic_video_nr.h | 23 + + include/media/v4l2-ioctl.h | 6 + + include/media/v4l2-subdev.h | 3 + + include/media/videobuf2-dma-contig-ingenic.h | 32 + + include/uapi/linux/android/binder.h | 4 + + include/uapi/linux/tty_flags.h | 4 +- + include/uapi/linux/usb/ch9.h | 13 + + include/uapi/linux/usb/f_mtp.h | 61 + + include/uapi/linux/videodev2.h | 1 + + include/video/ingenic_logo.h | 15 + + kernel/dma/coherent.c | 64 +- + kernel/dma/mapping.c | 12 +- + module_drivers/Kconfig | 11 + + module_drivers/Makefile | 6 + + module_drivers/README.zh | 27 + + module_drivers/drivers/Kconfig | 111 + + module_drivers/drivers/Makefile | 25 + + module_drivers/drivers/char/Makefile | 2 + + module_drivers/drivers/char/hw_random/Kconfig | 12 + + .../drivers/char/hw_random/Makefile | 1 + + .../drivers/char/hw_random/ingenic-rng.c | 284 + + module_drivers/drivers/char/ingenic_cdbus.c | 733 + + module_drivers/drivers/clk/Makefile | 1 + + module_drivers/drivers/clk/ingenic-v2/Kconfig | 49 + + .../drivers/clk/ingenic-v2/Makefile | 35 + + .../drivers/clk/ingenic-v2/clk-bus.c | 238 + + .../drivers/clk/ingenic-v2/clk-bus.h | 24 + + .../drivers/clk/ingenic-v2/clk-div.c | 258 + + .../drivers/clk/ingenic-v2/clk-div.h | 18 + + .../drivers/clk/ingenic-v2/clk-m300.c | 395 + + .../drivers/clk/ingenic-v2/clk-pll-v1.c | 185 + + .../drivers/clk/ingenic-v2/clk-pll-v1.h | 53 + + .../drivers/clk/ingenic-v2/clk-pll-v2.c | 181 + + .../drivers/clk/ingenic-v2/clk-pll-v2.h | 53 + + .../drivers/clk/ingenic-v2/clk-pll.c | 185 + + .../drivers/clk/ingenic-v2/clk-pll.h | 11 + + .../drivers/clk/ingenic-v2/clk-x1600.c | 306 + + .../drivers/clk/ingenic-v2/clk-x2000.c | 361 + + .../drivers/clk/ingenic-v2/clk-x2500.c | 296 + + module_drivers/drivers/clk/ingenic-v2/clk.c | 518 + + module_drivers/drivers/clk/ingenic-v2/clk.h | 594 + + .../drivers/clk/ingenic-v2/power-gate.c | 197 + + .../drivers/clk/ingenic-v2/power-gate.h | 14 + + module_drivers/drivers/clocksource/Kconfig | 16 + + module_drivers/drivers/clocksource/Makefile | 2 + + .../drivers/clocksource/ingenic_core_ost.c | 569 + + .../drivers/clocksource/ingenic_sysost.c | 316 + + module_drivers/drivers/crypto/Kconfig | 23 + + module_drivers/drivers/crypto/Makefile | 2 + + module_drivers/drivers/crypto/ingenic-aes.c | 923 + + module_drivers/drivers/crypto/ingenic-aes.h | 113 + + module_drivers/drivers/crypto/ingenic-hash.c | 1111 + + module_drivers/drivers/crypto/ingenic-hash.h | 119 + + module_drivers/drivers/dma/Makefile | 1 + + module_drivers/drivers/dma/ingenic/Kconfig | 25 + + module_drivers/drivers/dma/ingenic/Makefile | 3 + + .../drivers/dma/ingenic/ingenic_dma.c | 1179 + + .../drivers/dma/ingenic/ingenic_dma.h | 253 + + module_drivers/drivers/i2c/Makefile | 1 + + module_drivers/drivers/i2c/busses/Kconfig | 27 + + module_drivers/drivers/i2c/busses/Makefile | 1 + + .../drivers/i2c/busses/i2c-ingenic.c | 1146 + + module_drivers/drivers/input/Makefile | 1 + + .../drivers/input/touchscreen/Kconfig | 17 + + .../drivers/input/touchscreen/Makefile | 11 + + .../input/touchscreen/focaltech_touch/Kconfig | 16 + + .../touchscreen/focaltech_touch/Makefile | 13 + + .../focaltech_touch/focaltech_common.h | 166 + + .../focaltech_touch/focaltech_config.h | 165 + + .../focaltech_touch/focaltech_core.c | 1723 ++ + .../focaltech_touch/focaltech_core.h | 260 + + .../focaltech_touch/focaltech_esdcheck.c | 464 + + .../focaltech_touch/focaltech_ex_fun.c | 1187 + + .../focaltech_touch/focaltech_ex_mode.c | 307 + + .../focaltech_touch/focaltech_flash.c | 2011 ++ + .../focaltech_touch/focaltech_flash.h | 205 + + .../focaltech_touch/focaltech_flash/Makefile | 1 + + .../focaltech_upgrade_ft7511.c | 154 + + .../focaltech_touch/focaltech_gesture.c | 460 + + .../focaltech_touch/focaltech_i2c.c | 193 + + .../focaltech_point_report_check.c | 135 + + .../input/touchscreen/ft6236_touch/Kconfig | 10 + + .../input/touchscreen/ft6236_touch/Makefile | 6 + + .../touchscreen/ft6236_touch/ft6236_touch.c | 592 + + .../touchscreen/ft6236_touch/ft6236_touch.h | 52 + + .../input/touchscreen/gt9xx_touch/Kconfig | 16 + + .../input/touchscreen/gt9xx_touch/Makefile | 6 + + .../input/touchscreen/gt9xx_touch/goodix.h | 69 + + .../touchscreen/gt9xx_touch/goodix_tool.c | 529 + + .../input/touchscreen/gt9xx_touch/gt9xx.c | 2576 ++ + .../input/touchscreen/gt9xx_touch/gt9xx.h | 384 + + .../touchscreen/gt9xx_touch/gt9xx_firmware.h | 2338 ++ + .../touchscreen/gt9xx_touch/gt9xx_update.c | 2092 ++ + .../hyn_cst3xx_0729_update1ok.c | 1602 ++ + .../hyn_cst3xx_RS659_fw.h | 1553 ++ + .../hyn_cst3xx_0729_update3_firmware.c | 1626 ++ + .../hyn_cst3xx_RS659_fw_0729_update2.h | 1552 ++ + .../hyn_cst3xx_RS659_fw_0729_update3.h | 1552 ++ + .../input/touchscreen/hyn_touch/Kconfig | 16 + + .../input/touchscreen/hyn_touch/Makefile | 4 + + .../cst3xx_MCU_driver-ori/cst3xx.c | 1422 + + .../cst3xx_MCU_driver-ori/cst3xx.h | 29 + + .../hyn_cst3xx_RS659_fw.h | 1553 ++ + .../cst3xx_MCU_driver_0729_update1/cst3xx.h | 29 + + .../cst3xx_MCU_driver_0729_update1/cst3xx_1.c | 1422 + + .../cst3xx_MCU_driver_0729_update1/cst3xx_2.c | 1422 + + .../hyn_cst3xx_RS659_fw.h | 1553 ++ + .../cst3xx_MCU_driver_0729_update2/cst3xx.c | 1437 + + .../cst3xx_MCU_driver_0729_update2/cst3xx.h | 29 + + .../hyn_cst3xx_RS659_fw.h | 1552 ++ + .../hyn_cst3xx_RS659_fw_0730_268_800.h | 1552 ++ + .../input/touchscreen/hyn_touch/Readme | 6 + + .../input/touchscreen/hyn_touch/hyn_cst3xx.c | 1645 ++ + .../input/touchscreen/hyn_touch/hyn_cst3xx.h | 136 + + .../hyn_touch/hyn_cst3xx_RS659_fw.h | 1550 ++ + .../input/touchscreen/hyn_touch/hyn_i2c.c | 99 + + module_drivers/drivers/irqchip/Kconfig | 20 + + module_drivers/drivers/irqchip/Makefile | 3 + + .../drivers/irqchip/irq-ingenic-chip.c | 560 + + .../drivers/irqchip/irq-ingenic-cpu.c | 128 + + module_drivers/drivers/irqchip/irq-ingenic.c | 266 + + module_drivers/drivers/md_export/Makefile | 1 + + module_drivers/drivers/md_export/md_export.c | 3 + + module_drivers/drivers/media/Makefile | 3 + + module_drivers/drivers/media/i2c/Kconfig | 4 + + module_drivers/drivers/media/i2c/Makefile | 3 + + .../drivers/media/i2c/ingenic-cim/Kconfig | 56 + + .../drivers/media/i2c/ingenic-cim/Makefile | 12 + + .../drivers/media/i2c/ingenic-cim/ar0144.c | 935 + + .../drivers/media/i2c/ingenic-cim/ov2735b.c | 999 + + .../drivers/media/i2c/ingenic-cim/ov4689.c | 3115 +++ + .../drivers/media/i2c/ingenic-cim/ov5640.c | 1925 ++ + .../drivers/media/i2c/ingenic-cim/ov5645.c | 1629 ++ + .../i2c/ingenic-cim/ov9281-dvp-snapshot.c | 1223 + + .../drivers/media/i2c/ingenic-cim/ov9281.c | 1068 + + .../media/i2c/ingenic-cim/sc031gs-mipi.c | 919 + + .../drivers/media/i2c/ingenic-cim/sc031gs.c | 985 + + .../drivers/media/i2c/ingenic-isp-v2/Kconfig | 49 + + .../drivers/media/i2c/ingenic-isp-v2/Makefile | 10 + + .../drivers/media/i2c/ingenic-isp-v2/gc2053.c | 1001 + + .../drivers/media/i2c/ingenic-isp-v2/gc2093.c | 1255 + + .../drivers/media/i2c/ingenic-isp-v2/gc2155.c | 1516 ++ + .../drivers/media/i2c/ingenic-isp-v2/imx327.c | 1109 + + .../media/i2c/ingenic-isp-v2/ov2735a.c | 1132 + + .../drivers/media/i2c/ingenic-isp-v2/ov4689.c | 1629 ++ + .../drivers/media/i2c/ingenic-isp-v2/ov7251.c | 1534 ++ + .../media/i2c/ingenic-isp-v2/sc230ai.c | 1972 ++ + .../drivers/media/i2c/ingenic-isp-v2/sc2310.c | 2461 ++ + .../drivers/media/i2c/ingenic-isp/Kconfig | 92 + + .../drivers/media/i2c/ingenic-isp/Makefile | 17 + + .../drivers/media/i2c/ingenic-isp/ar0144.c | 998 + + .../drivers/media/i2c/ingenic-isp/ar0234.c | 1183 + + .../drivers/media/i2c/ingenic-isp/cisadc.c | 602 + + .../drivers/media/i2c/ingenic-isp/gc1054.c | 1606 ++ + .../drivers/media/i2c/ingenic-isp/gc2093.c | 1043 + + .../i2c/ingenic-isp/gm8914_gm8913_gc2093.c | 1508 ++ + .../drivers/media/i2c/ingenic-isp/hm2140.c | 1091 + + .../drivers/media/i2c/ingenic-isp/imx335.c | 1429 + + .../drivers/media/i2c/ingenic-isp/ov2735a.c | 1157 + + .../drivers/media/i2c/ingenic-isp/ov2735b.c | 1202 + + .../drivers/media/i2c/ingenic-isp/ov4689.c | 3224 +++ + .../drivers/media/i2c/ingenic-isp/ov6710.c | 1549 ++ + .../drivers/media/i2c/ingenic-isp/ov7251.c | 1396 + + .../drivers/media/i2c/ingenic-isp/sc0132gs.c | 1630 ++ + .../drivers/media/i2c/ingenic-isp/sc031gs.c | 2226 ++ + .../drivers/media/i2c/ingenic-isp/sc2232h.c | 1173 + + .../drivers/media/i2c/ingenic-isp/sc230ai.c | 1653 ++ + module_drivers/drivers/media/platform/Kconfig | 41 + + .../drivers/media/platform/Makefile | 6 + + .../media/platform/ingenic-cim/Kconfig | 82 + + .../media/platform/ingenic-cim/Makefile | 2 + + .../platform/ingenic-cim/ingenic_camera.c | 2566 ++ + .../platform/ingenic-cim/ingenic_camera.h | 581 + + .../media/platform/ingenic-cim/mipi_csi.c | 222 + + .../media/platform/ingenic-cim/mipi_csi.h | 98 + + .../media/platform/ingenic-i2d/Kconfig | 16 + + .../media/platform/ingenic-i2d/Makefile | 1 + + .../media/platform/ingenic-i2d/i2d_video.c | 751 + + .../media/platform/ingenic-i2d/i2d_video.h | 75 + + .../media/platform/ingenic-i2d/ingenic_i2d.c | 252 + + .../media/platform/ingenic-i2d/ingenic_i2d.h | 157 + + .../media/platform/ingenic-isp-v2/Kconfig | 56 + + .../media/platform/ingenic-isp-v2/Makefile | 20 + + .../media/platform/ingenic-isp-v2/csi-regs.h | 69 + + .../media/platform/ingenic-isp-v2/csi.c | 554 + + .../platform/ingenic-isp-v2/isp-core-tuning.c | 704 + + .../platform/ingenic-isp-v2/isp-core/Makefile | 1 + + .../isp-core/inc/system_sensor_drv.h | 96 + + .../isp-core/inc/tiziano-core-ctrl.h | 868 + + .../ingenic-isp-v2/isp-core/inc/tiziano-isp.h | 257 + + .../ingenic-isp-v2/isp-core/inc/tiziano_sys.h | 11 + + .../ingenic-isp-v2/isp-core/inc/txx-funcs.h | 222 + + .../media/platform/ingenic-isp-v2/isp-drv.c | 451 + + .../media/platform/ingenic-isp-v2/isp-drv.h | 398 + + .../platform/ingenic-isp-v2/isp-regs-x2000.h | 1453 + + .../media/platform/ingenic-isp-v2/isp-regs.h | 4289 +++ + .../platform/ingenic-isp-v2/isp-sensor.h | 97 + + .../ingenic-isp-v2/isp-video-mplane.c | 729 + + .../media/platform/ingenic-isp-v2/isp-video.c | 992 + + .../media/platform/ingenic-isp-v2/isp.c | 1173 + + .../platform/ingenic-isp-v2/mscaler-bdev.c | 255 + + .../platform/ingenic-isp-v2/mscaler-regs.h | 80 + + .../media/platform/ingenic-isp-v2/mscaler.c | 1411 + + .../media/platform/ingenic-isp-v2/sensor.c | 463 + + .../platform/ingenic-isp-v2/tx-vic-regs.h | 182 + + .../media/platform/ingenic-isp-v2/vic-regs.h | 174 + + .../media/platform/ingenic-isp-v2/vic.c | 1486 + + .../media/platform/ingenic-isp/Kconfig | 113 + + .../media/platform/ingenic-isp/Makefile | 20 + + .../media/platform/ingenic-isp/csi-regs.h | 51 + + .../drivers/media/platform/ingenic-isp/csi.c | 482 + + .../platform/ingenic-isp/isp-core-tuning.c | 1130 + + .../platform/ingenic-isp/isp-core/Makefile | 3 + + .../isp-core/inc/system_sensor_drv.h | 85 + + .../ingenic-isp/isp-core/inc/tiziano_core.h | 1223 + + .../isp-core/inc/tiziano_core_tuning.h | 170 + + .../ingenic-isp/isp-core/inc/tiziano_isp.h | 104 + + .../isp-core/inc/tiziano_netlink.h | 12 + + .../ingenic-isp/isp-core/inc/tiziano_priv.h | 47 + + .../ingenic-isp/isp-core/inc/tiziano_sys.h | 10 + + .../ingenic-isp/isp-core/src/Makefile | 2 + + .../ingenic-isp/isp-core/tiziano_netlink.c | 125 + + .../ingenic-isp/isp-core/tiziano_priv.c | 56 + + .../media/platform/ingenic-isp/isp-drv.c | 451 + + .../media/platform/ingenic-isp/isp-drv.h | 415 + + .../media/platform/ingenic-isp/isp-regs.h | 1450 + + .../media/platform/ingenic-isp/isp-sensor.h | 80 + + .../platform/ingenic-isp/isp-video-mplane.c | 729 + + .../media/platform/ingenic-isp/isp-video.c | 890 + + .../drivers/media/platform/ingenic-isp/isp.c | 785 + + .../media/platform/ingenic-isp/mscaler-bdev.c | 255 + + .../media/platform/ingenic-isp/mscaler-regs.h | 82 + + .../media/platform/ingenic-isp/mscaler.c | 1531 ++ + .../media/platform/ingenic-isp/sensor.c | 302 + + .../media/platform/ingenic-isp/vic-regs.h | 157 + + .../drivers/media/platform/ingenic-isp/vic.c | 1224 + + .../media/platform/ingenic-rotate/Kconfig | 8 + + .../media/platform/ingenic-rotate/Makefile | 2 + + .../media/platform/ingenic-rotate/rotate-hw.c | 317 + + .../platform/ingenic-rotate/rotate-regs.h | 204 + + .../media/platform/ingenic-rotate/rotate.c | 876 + + .../media/platform/ingenic-rotate/rotate.h | 150 + + .../media/platform/ingenic-vcodec/Kconfig | 16 + + .../media/platform/ingenic-vcodec/Makefile | 2 + + .../platform/ingenic-vcodec/felix/Makefile | 29 + + .../platform/ingenic-vcodec/felix/felix_drv.c | 658 + + .../platform/ingenic-vcodec/felix/felix_drv.h | 159 + + .../platform/ingenic-vcodec/felix/felix_ops.c | 1235 + + .../platform/ingenic-vcodec/felix/felix_ops.h | 15 + + .../ingenic-vcodec/felix/libh264/Makefile | 25 + + .../felix/libh264/api/jzm_h264_dec.c | 1123 + + .../felix/libh264/api/jzm_h264_dec.h | 125 + + .../felix/libh264/api/jzm_vpu.h | 2674 ++ + .../felix/libh264/include/avassert.h | 53 + + .../felix/libh264/include/avcodec.h | 404 + + .../felix/libh264/include/bswap.h | 54 + + .../felix/libh264/include/buffer.h | 70 + + .../felix/libh264/include/bytestream.h | 358 + + .../felix/libh264/include/common.h | 476 + + .../felix/libh264/include/devmem.h | 26 + + .../felix/libh264/include/error.h | 108 + + .../felix/libh264/include/frame.h | 308 + + .../felix/libh264/include/get_bits.h | 810 + + .../felix/libh264/include/golomb.h | 715 + + .../felix/libh264/include/h264.h | 113 + + .../felix/libh264/include/h2645_parse.h | 93 + + .../felix/libh264/include/h264_parse.h | 70 + + .../felix/libh264/include/h264_ps.h | 184 + + .../felix/libh264/include/h264_sei.h | 189 + + .../felix/libh264/include/h264data.h | 41 + + .../felix/libh264/include/h264dec.h | 622 + + .../felix/libh264/include/intreadwrite.h | 509 + + .../felix/libh264/include/list.h | 169 + + .../felix/libh264/include/log.h | 341 + + .../felix/libh264/include/mathops.h | 63 + + .../felix/libh264/include/mem.h | 71 + + .../felix/libh264/include/mpegutils.h | 27 + + .../felix/libh264/include/put_bits.h | 337 + + .../felix/libh264/include/vpu_ops.h | 45 + + .../ingenic-vcodec/felix/libh264/src/Makefile | 25 + + .../ingenic-vcodec/felix/libh264/src/buffer.c | 194 + + .../ingenic-vcodec/felix/libh264/src/golomb.c | 145 + + .../felix/libh264/src/h2645_parse.c | 401 + + .../felix/libh264/src/h264_direct.c | 146 + + .../felix/libh264/src/h264_parse.c | 279 + + .../felix/libh264/src/h264_picture.c | 56 + + .../felix/libh264/src/h264_ps.c | 779 + + .../felix/libh264/src/h264_refs.c | 948 + + .../felix/libh264/src/h264_sei.c | 508 + + .../felix/libh264/src/h264_slice.c | 1730 ++ + .../felix/libh264/src/h264data.c | 114 + + .../felix/libh264/src/h264dec.c | 613 + + .../felix/libh264/src/hexdump.c | 13 + + .../ingenic-vcodec/felix/libh264/src/log.c | 108 + + .../felix/libh264/src/mathtables.c | 98 + + .../ingenic-vcodec/felix/libh264/src/mem.c | 311 + + .../felix/libh264/src/vpu_ops.c | 170 + + .../platform/ingenic-vcodec/helix/Makefile | 17 + + .../platform/ingenic-vcodec/helix/README | 4 + + .../platform/ingenic-vcodec/helix/api/helix.h | 3459 +++ + .../ingenic-vcodec/helix/api/helix_jpeg_dec.c | 51 + + .../ingenic-vcodec/helix/api/helix_jpeg_dec.h | 72 + + .../ingenic-vcodec/helix/api/helix_jpeg_enc.c | 241 + + .../ingenic-vcodec/helix/api/helix_jpeg_enc.h | 81 + + .../ingenic-vcodec/helix/api/helix_x264_enc.c | 1647 ++ + .../ingenic-vcodec/helix/api/helix_x264_enc.h | 418 + + .../ingenic-vcodec/helix/default_sliceinfo.c | 362 + + .../platform/ingenic-vcodec/helix/h264e.c | 1408 + + .../platform/ingenic-vcodec/helix/h264e.h | 134 + + .../platform/ingenic-vcodec/helix/h264e_rc.c | 664 + + .../platform/ingenic-vcodec/helix/h264e_rc.h | 85 + + .../ingenic-vcodec/helix/h264e_rc_nl.c | 285 + + .../ingenic-vcodec/helix/h264e_rc_nl.h | 16 + + .../ingenic-vcodec/helix/h264e_rc_proto.h | 113 + + .../ingenic-vcodec/helix/h264enc/bitstream.h | 242 + + .../ingenic-vcodec/helix/h264enc/cabac.c | 1334 + + .../ingenic-vcodec/helix/h264enc/cabac.h | 28 + + .../ingenic-vcodec/helix/h264enc/common.c | 11 + + .../ingenic-vcodec/helix/h264enc/common.h | 58 + + .../ingenic-vcodec/helix/h264enc/nal.h | 59 + + .../ingenic-vcodec/helix/h264enc/osdep.h | 39 + + .../ingenic-vcodec/helix/h264enc/set.c | 141 + + .../ingenic-vcodec/helix/h264enc/set.h | 150 + + .../ingenic-vcodec/helix/h264enc/slice.c | 162 + + .../ingenic-vcodec/helix/h264enc/slice.h | 99 + + .../platform/ingenic-vcodec/helix/helix_buf.h | 45 + + .../platform/ingenic-vcodec/helix/helix_drv.c | 550 + + .../platform/ingenic-vcodec/helix/helix_drv.h | 177 + + .../platform/ingenic-vcodec/helix/helix_ops.c | 1354 + + .../platform/ingenic-vcodec/helix/helix_ops.h | 17 + + .../platform/ingenic-vcodec/helix/jpgd.c | 569 + + .../platform/ingenic-vcodec/helix/jpgd.h | 54 + + .../platform/ingenic-vcodec/helix/jpge.c | 330 + + .../platform/ingenic-vcodec/helix/jpge.h | 46 + + .../platform/ingenic-vcodec/helix/jpge/head.h | 72 + + .../platform/ingenic-vcodec/helix/jpge/ht.h | 90 + + .../platform/ingenic-vcodec/helix/jpge/qt.h | 58 + + .../drivers/media/v4l2-core/Kconfig | 12 + + .../drivers/media/v4l2-core/Makefile | 1 + + .../v4l2-core/videobuf2-dma-contig-ingenic.c | 893 + + module_drivers/drivers/mfd/Kconfig | 75 + + module_drivers/drivers/mfd/Makefile | 5 + + module_drivers/drivers/mfd/ingenic-tcu.c | 908 + + module_drivers/drivers/mfd/ingenic-tcu_v1.c | 942 + + module_drivers/drivers/mfd/ingenic_adc_aux.c | 362 + + module_drivers/drivers/mfd/ingenic_adc_v13.c | 517 + + module_drivers/drivers/mfd/ricoh619-irq.c | 565 + + module_drivers/drivers/mfd/ricoh619.c | 727 + + module_drivers/drivers/misc/Kconfig | 41 + + module_drivers/drivers/misc/Makefile | 6 + + .../drivers/misc/bt_power_bluesleep.c | 311 + + module_drivers/drivers/misc/hamming.c | 374 + + .../drivers/misc/ingenic_efuse_v2.c | 745 + + .../drivers/misc/ingenic_efuse_x2000.c | 1128 + + module_drivers/drivers/misc/ingenic_rsa.c | 487 + + module_drivers/drivers/mmc/Makefile | 1 + + module_drivers/drivers/mmc/host/Kconfig | 40 + + module_drivers/drivers/mmc/host/Makefile | 5 + + module_drivers/drivers/mmc/host/ingenic_mmc.c | 1815 ++ + module_drivers/drivers/mmc/host/ingenic_mmc.h | 158 + + .../drivers/mmc/host/ingenic_mmc_reg.h | 232 + + .../drivers/mmc/host/ingenic_sdio.c | 275 + + .../drivers/mmc/host/sdhci-ingenic.c | 741 + + .../drivers/mmc/host/sdhci-ingenic.h | 97 + + module_drivers/drivers/mtd/Makefile | 1 + + module_drivers/drivers/mtd/devices/Kconfig | 90 + + module_drivers/drivers/mtd/devices/Makefile | 2 + + .../mtd/devices/ingenic_sfc_v2/Makefile | 8 + + .../drivers/mtd/devices/ingenic_sfc_v2/fmw.h | 72 + + .../ingenic_sfc_v2/ingenic_sfc_common.c | 957 + + .../ingenic_sfc_v2/ingenic_sfc_common.h | 36 + + .../devices/ingenic_sfc_v2/ingenic_sfc_drv.c | 280 + + .../devices/ingenic_sfc_v2/ingenic_sfc_drv.h | 18 + + .../devices/ingenic_sfc_v2/ingenic_sfc_nand.c | 1433 + + .../devices/ingenic_sfc_v2/ingenic_sfc_nor.c | 1000 + + .../devices/ingenic_sfc_v2/ingenic_sfc_ops.c | 225 + + .../ingenic_sfc_v2/nand_device/Makefile | 2 + + .../ingenic_sfc_v2/nand_device/ato_nand.c | 101 + + .../nand_device/dosilicon_nand.c | 217 + + .../ingenic_sfc_v2/nand_device/fm_nand.c | 126 + + .../ingenic_sfc_v2/nand_device/foresee_nand.c | 145 + + .../ingenic_sfc_v2/nand_device/gd_nand.c | 435 + + .../ingenic_sfc_v2/nand_device/issi_nand.c | 104 + + .../ingenic_sfc_v2/nand_device/mxic_nand.c | 239 + + .../ingenic_sfc_v2/nand_device/nand_common.c | 66 + + .../ingenic_sfc_v2/nand_device/nand_common.h | 74 + + .../ingenic_sfc_v2/nand_device/toshiba_nand.c | 102 + + .../ingenic_sfc_v2/nand_device/xcsp_nand.c | 197 + + .../nand_device/xtx_mid0b_nand.c | 234 + + .../nand_device/xtx_mid2c_nand.c | 124 + + .../ingenic_sfc_v2/nand_device/xtx_nand.c | 161 + + .../ingenic_sfc_v2/nand_device/yhy_nand.c | 122 + + .../ingenic_sfc_v2/nand_device/zetta_nand.c | 139 + + .../ingenic_sfc_v2/nor_device/Makefile | 1 + + .../ingenic_sfc_v2/nor_device/nor_device.c | 157 + + .../ingenic_sfc_v2/nor_device/nor_device.h | 66 + + .../drivers/mtd/devices/ingenic_sfc_v2/sfc.h | 116 + + .../mtd/devices/ingenic_sfc_v2/sfc_flash.h | 33 + + .../mtd/devices/ingenic_sfc_v2/spinand.h | 187 + + .../mtd/devices/ingenic_sfc_v2/spinand_cmd.h | 30 + + .../mtd/devices/ingenic_sfc_v2/spinor.h | 205 + + .../mtd/devices/ingenic_sfc_v2/spinor_cmd.h | 84 + + module_drivers/drivers/net/Makefile | 3 + + module_drivers/drivers/net/ethernet/Makefile | 1 + + .../drivers/net/ethernet/ingenic/Kconfig | 46 + + .../drivers/net/ethernet/ingenic/Makefile | 31 + + .../drivers/net/ethernet/ingenic/ethtool.c | 284 + + .../net/ethernet/ingenic/ingenic_mac.c | 3424 +++ + .../net/ethernet/ingenic/ingenic_mac.h | 194 + + .../drivers/net/ethernet/ingenic/readme | 26 + + .../net/ethernet/ingenic/synopGMAC_Dev.c | 3839 +++ + .../net/ethernet/ingenic/synopGMAC_Dev.h | 2011 ++ + .../net/ethernet/ingenic/synopGMAC_plat.c | 94 + + .../net/ethernet/ingenic/synopGMAC_plat.h | 211 + + module_drivers/drivers/net/wireless/Kconfig | 2 + + module_drivers/drivers/net/wireless/Makefile | 4 + + .../drivers/net/wireless/bcmdhd/Kconfig | 60 + + .../drivers/net/wireless/bcmdhd/Makefile | 169 + + .../drivers/net/wireless/bcmdhd/README | 2 + + .../drivers/net/wireless/bcmdhd/aiutils.c | 1810 ++ + .../net/wireless/bcmdhd/bcm_app_utils.c | 1015 + + .../drivers/net/wireless/bcmdhd/bcmevent.c | 385 + + .../drivers/net/wireless/bcmdhd/bcmsdh.c | 847 + + .../net/wireless/bcmdhd/bcmsdh_linux.c | 517 + + .../net/wireless/bcmdhd/bcmsdh_sdmmc.c | 1774 ++ + .../net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c | 405 + + .../net/wireless/bcmdhd/bcmsdspi_linux.c | 252 + + .../drivers/net/wireless/bcmdhd/bcmspibrcm.c | 1764 ++ + .../drivers/net/wireless/bcmdhd/bcmutils.c | 4106 +++ + .../net/wireless/bcmdhd/bcmwifi_channels.c | 1349 + + .../net/wireless/bcmdhd/bcmwifi_channels.h | 645 + + .../net/wireless/bcmdhd/bcmwifi_rates.h | 793 + + .../drivers/net/wireless/bcmdhd/bcmxtlv.c | 457 + + .../drivers/net/wireless/bcmdhd/dbus.c | 2904 ++ + .../drivers/net/wireless/bcmdhd/dbus_usb.c | 1172 + + .../net/wireless/bcmdhd/dbus_usb_linux.c | 3403 +++ + .../drivers/net/wireless/bcmdhd/dhd.h | 2594 ++ + .../drivers/net/wireless/bcmdhd/dhd_bus.h | 298 + + .../drivers/net/wireless/bcmdhd/dhd_buzzz.h | 37 + + .../drivers/net/wireless/bcmdhd/dhd_ccode.c | 234 + + .../drivers/net/wireless/bcmdhd/dhd_cdc.c | 962 + + .../net/wireless/bcmdhd/dhd_cfg80211.c | 269 + + .../net/wireless/bcmdhd/dhd_cfg80211.h | 54 + + .../drivers/net/wireless/bcmdhd/dhd_common.c | 6076 +++++ + .../drivers/net/wireless/bcmdhd/dhd_config.c | 3851 +++ + .../drivers/net/wireless/bcmdhd/dhd_config.h | 329 + + .../net/wireless/bcmdhd/dhd_custom_gpio.c | 299 + + .../wireless/bcmdhd/dhd_custom_memprealloc.c | 513 + + .../net/wireless/bcmdhd/dhd_custom_msm.c | 253 + + .../drivers/net/wireless/bcmdhd/dhd_dbg.h | 347 + + .../drivers/net/wireless/bcmdhd/dhd_debug.c | 2335 ++ + .../drivers/net/wireless/bcmdhd/dhd_debug.h | 868 + + .../net/wireless/bcmdhd/dhd_debug_linux.c | 520 + + .../net/wireless/bcmdhd/dhd_flowring.c | 1063 + + .../net/wireless/bcmdhd/dhd_flowring.h | 275 + + .../drivers/net/wireless/bcmdhd/dhd_gpio.c | 360 + + .../drivers/net/wireless/bcmdhd/dhd_ip.c | 1318 + + .../drivers/net/wireless/bcmdhd/dhd_ip.h | 85 + + .../drivers/net/wireless/bcmdhd/dhd_linux.c | 19882 ++++++++++++++ + .../drivers/net/wireless/bcmdhd/dhd_linux.h | 189 + + .../net/wireless/bcmdhd/dhd_linux_platdev.c | 1013 + + .../net/wireless/bcmdhd/dhd_linux_sched.c | 51 + + .../net/wireless/bcmdhd/dhd_linux_wq.c | 379 + + .../net/wireless/bcmdhd/dhd_linux_wq.h | 81 + + .../drivers/net/wireless/bcmdhd/dhd_mschdbg.c | 747 + + .../drivers/net/wireless/bcmdhd/dhd_mschdbg.h | 39 + + .../drivers/net/wireless/bcmdhd/dhd_msgbuf.c | 8951 ++++++ + .../drivers/net/wireless/bcmdhd/dhd_pcie.c | 8489 ++++++ + .../drivers/net/wireless/bcmdhd/dhd_pcie.h | 607 + + .../net/wireless/bcmdhd/dhd_pcie_linux.c | 2316 ++ + .../drivers/net/wireless/bcmdhd/dhd_pno.c | 4050 +++ + .../drivers/net/wireless/bcmdhd/dhd_pno.h | 572 + + .../drivers/net/wireless/bcmdhd/dhd_proto.h | 201 + + .../drivers/net/wireless/bcmdhd/dhd_rtt.c | 2421 ++ + .../drivers/net/wireless/bcmdhd/dhd_rtt.h | 387 + + .../drivers/net/wireless/bcmdhd/dhd_sdio.c | 10180 +++++++ + .../net/wireless/bcmdhd/dhd_static_buf.c | 535 + + .../drivers/net/wireless/bcmdhd/dhd_wlfc.c | 4567 ++++ + .../drivers/net/wireless/bcmdhd/dhd_wlfc.h | 562 + + .../drivers/net/wireless/bcmdhd/dngl_stats.h | 383 + + .../drivers/net/wireless/bcmdhd/dngl_wlhdr.h | 43 + + .../drivers/net/wireless/bcmdhd/hnd_pktpool.c | 1180 + + .../drivers/net/wireless/bcmdhd/hnd_pktq.c | 973 + + .../drivers/net/wireless/bcmdhd/hndpmu.c | 382 + + .../net/wireless/bcmdhd/include/802.11.h | 5128 ++++ + .../net/wireless/bcmdhd/include/802.11e.h | 134 + + .../net/wireless/bcmdhd/include/802.11s.h | 336 + + .../net/wireless/bcmdhd/include/802.1d.h | 53 + + .../net/wireless/bcmdhd/include/802.3.h | 55 + + .../net/wireless/bcmdhd/include/aidmp.h | 424 + + .../net/wireless/bcmdhd/include/bcm_cfg.h | 32 + + .../wireless/bcmdhd/include/bcm_mpool_pub.h | 364 + + .../net/wireless/bcmdhd/include/bcm_ring.h | 634 + + .../net/wireless/bcmdhd/include/bcmcdc.h | 135 + + .../net/wireless/bcmdhd/include/bcmdefs.h | 462 + + .../net/wireless/bcmdhd/include/bcmdevs.h | 933 + + .../net/wireless/bcmdhd/include/bcmdhcp.h | 92 + + .../net/wireless/bcmdhd/include/bcmendian.h | 332 + + .../net/wireless/bcmdhd/include/bcmeth.h | 117 + + .../net/wireless/bcmdhd/include/bcmevent.h | 948 + + .../net/wireless/bcmdhd/include/bcmip.h | 264 + + .../net/wireless/bcmdhd/include/bcmipv6.h | 163 + + .../net/wireless/bcmdhd/include/bcmmsgbuf.h | 1202 + + .../net/wireless/bcmdhd/include/bcmnvram.h | 329 + + .../net/wireless/bcmdhd/include/bcmpcie.h | 440 + + .../net/wireless/bcmdhd/include/bcmpcispi.h | 184 + + .../net/wireless/bcmdhd/include/bcmperf.h | 39 + + .../net/wireless/bcmdhd/include/bcmsdbus.h | 173 + + .../net/wireless/bcmdhd/include/bcmsdh.h | 273 + + .../wireless/bcmdhd/include/bcmsdh_sdmmc.h | 129 + + .../net/wireless/bcmdhd/include/bcmsdpcm.h | 302 + + .../net/wireless/bcmdhd/include/bcmsdspi.h | 138 + + .../net/wireless/bcmdhd/include/bcmsdstd.h | 285 + + .../net/wireless/bcmdhd/include/bcmspi.h | 43 + + .../net/wireless/bcmdhd/include/bcmspibrcm.h | 165 + + .../net/wireless/bcmdhd/include/bcmsrom_fmt.h | 973 + + .../net/wireless/bcmdhd/include/bcmsrom_tbl.h | 1408 + + .../net/wireless/bcmdhd/include/bcmtcp.h | 93 + + .../net/wireless/bcmdhd/include/bcmudp.h | 61 + + .../net/wireless/bcmdhd/include/bcmutils.h | 1355 + + .../wireless/bcmdhd/include/brcm_nl80211.h | 73 + + .../net/wireless/bcmdhd/include/dbus.h | 600 + + .../net/wireless/bcmdhd/include/dhd_daemon.h | 62 + + .../net/wireless/bcmdhd/include/dhdioctl.h | 159 + + .../net/wireless/bcmdhd/include/dnglevent.h | 120 + + .../net/wireless/bcmdhd/include/eapol.h | 218 + + .../net/wireless/bcmdhd/include/epivers.h | 51 + + .../net/wireless/bcmdhd/include/ethernet.h | 227 + + .../net/wireless/bcmdhd/include/event_log.h | 388 + + .../bcmdhd/include/event_log_payload.h | 673 + + .../wireless/bcmdhd/include/event_log_set.h | 53 + + .../wireless/bcmdhd/include/event_log_tag.h | 222 + + .../net/wireless/bcmdhd/include/event_trace.h | 123 + + .../net/wireless/bcmdhd/include/hnd_armtrap.h | 90 + + .../net/wireless/bcmdhd/include/hnd_cons.h | 84 + + .../net/wireless/bcmdhd/include/hnd_debug.h | 206 + + .../net/wireless/bcmdhd/include/hnd_pktpool.h | 225 + + .../net/wireless/bcmdhd/include/hnd_pktq.h | 284 + + .../net/wireless/bcmdhd/include/hndpmu.h | 56 + + .../net/wireless/bcmdhd/include/hndsoc.h | 327 + + .../net/wireless/bcmdhd/include/linux_osl.h | 1170 + + .../net/wireless/bcmdhd/include/linuxver.h | 812 + + .../net/wireless/bcmdhd/include/miniopt.h | 83 + + .../net/wireless/bcmdhd/include/msgtrace.h | 62 + + .../drivers/net/wireless/bcmdhd/include/nan.h | 1468 + + .../drivers/net/wireless/bcmdhd/include/osl.h | 260 + + .../net/wireless/bcmdhd/include/osl_decl.h | 37 + + .../net/wireless/bcmdhd/include/osl_ext.h | 697 + + .../drivers/net/wireless/bcmdhd/include/p2p.h | 713 + + .../bcmdhd/include/packed_section_end.h | 63 + + .../bcmdhd/include/packed_section_start.h | 67 + + .../net/wireless/bcmdhd/include/pcicfg.h | 330 + + .../net/wireless/bcmdhd/include/pcie_core.h | 959 + + .../net/wireless/bcmdhd/include/rte_ioctl.h | 87 + + .../net/wireless/bcmdhd/include/sbchipc.h | 4417 +++ + .../net/wireless/bcmdhd/include/sbconfig.h | 285 + + .../net/wireless/bcmdhd/include/sbgci.h | 248 + + .../net/wireless/bcmdhd/include/sbhnddma.h | 429 + + .../net/wireless/bcmdhd/include/sbpcmcia.h | 139 + + .../net/wireless/bcmdhd/include/sbsdio.h | 189 + + .../net/wireless/bcmdhd/include/sbsdpcmdev.h | 300 + + .../net/wireless/bcmdhd/include/sbsocram.h | 205 + + .../net/wireless/bcmdhd/include/sbsysmem.h | 180 + + .../net/wireless/bcmdhd/include/sdio.h | 630 + + .../net/wireless/bcmdhd/include/sdioh.h | 448 + + .../net/wireless/bcmdhd/include/sdiovar.h | 107 + + .../net/wireless/bcmdhd/include/sdspi.h | 78 + + .../net/wireless/bcmdhd/include/siutils.h | 729 + + .../net/wireless/bcmdhd/include/spid.h | 168 + + .../net/wireless/bcmdhd/include/trxhdr.h | 95 + + .../net/wireless/bcmdhd/include/typedefs.h | 386 + + .../net/wireless/bcmdhd/include/usbrdl.h | 134 + + .../net/wireless/bcmdhd/include/vlan.h | 98 + + .../net/wireless/bcmdhd/include/wlfc_proto.h | 376 + + .../net/wireless/bcmdhd/include/wlioctl.h | 13828 ++++++++++ + .../wireless/bcmdhd/include/wlioctl_defs.h | 2243 ++ + .../wireless/bcmdhd/include/wlioctl_utils.h | 61 + + .../drivers/net/wireless/bcmdhd/include/wpa.h | 217 + + .../drivers/net/wireless/bcmdhd/include/wps.h | 389 + + .../drivers/net/wireless/bcmdhd/linux_osl.c | 2842 ++ + .../drivers/net/wireless/bcmdhd/pcie_core.c | 135 + + .../drivers/net/wireless/bcmdhd/sbutils.c | 1101 + + .../drivers/net/wireless/bcmdhd/siutils.c | 3727 +++ + .../net/wireless/bcmdhd/siutils_priv.h | 333 + + .../drivers/net/wireless/bcmdhd/wl_android.c | 5511 ++++ + .../drivers/net/wireless/bcmdhd/wl_android.h | 311 + + .../net/wireless/bcmdhd/wl_android_ext.c | 6631 +++++ + .../drivers/net/wireless/bcmdhd/wl_cfg80211.c | 22544 ++++++++++++++++ + .../drivers/net/wireless/bcmdhd/wl_cfg80211.h | 1742 ++ + .../net/wireless/bcmdhd/wl_cfg_btcoex.c | 570 + + .../drivers/net/wireless/bcmdhd/wl_cfgnan.c | 27 + + .../drivers/net/wireless/bcmdhd/wl_cfgnan.h | 364 + + .../drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 2600 ++ + .../drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 451 + + .../net/wireless/bcmdhd/wl_cfgvendor.c | 3746 +++ + .../net/wireless/bcmdhd/wl_cfgvendor.h | 583 + + .../drivers/net/wireless/bcmdhd/wl_dbg.h | 246 + + .../drivers/net/wireless/bcmdhd/wl_escan.c | 1595 ++ + .../drivers/net/wireless/bcmdhd/wl_escan.h | 78 + + .../drivers/net/wireless/bcmdhd/wl_event.c | 557 + + .../drivers/net/wireless/bcmdhd/wl_iw.c | 4450 +++ + .../drivers/net/wireless/bcmdhd/wl_iw.h | 173 + + .../net/wireless/bcmdhd/wl_linux_mon.c | 406 + + .../drivers/net/wireless/bcmdhd/wl_roam.c | 28 + + .../drivers/net/wireless/bcmdhd/wlc_types.h | 337 + + .../net/wireless/bcmdhd/wldev_common.c | 540 + + .../net/wireless/bcmdhd/wldev_common.h | 130 + + .../net/wireless/bcmdhd_1_363_125_17/Kconfig | 68 + + .../net/wireless/bcmdhd_1_363_125_17/Makefile | 323 + + .../wireless/bcmdhd_1_363_125_17/aiutils.c | 1298 + + .../bcmdhd_1_363_125_17/bcm_app_utils.c | 1016 + + .../wireless/bcmdhd_1_363_125_17/bcmevent.c | 234 + + .../net/wireless/bcmdhd_1_363_125_17/bcmsdh.c | 723 + + .../bcmdhd_1_363_125_17/bcmsdh_linux.c | 471 + + .../bcmdhd_1_363_125_17/bcmsdh_sdmmc.c | 1536 ++ + .../bcmdhd_1_363_125_17/bcmsdh_sdmmc_linux.c | 413 + + .../bcmdhd_1_363_125_17/bcmsdspi_linux.c | 252 + + .../wireless/bcmdhd_1_363_125_17/bcmspibrcm.c | 1813 ++ + .../wireless/bcmdhd_1_363_125_17/bcmutils.c | 3677 +++ + .../bcmdhd_1_363_125_17/bcmwifi_channels.c | 1291 + + .../bcmdhd_1_363_125_17/bcmwifi_channels.h | 663 + + .../bcmdhd_1_363_125_17/bcmwifi_rates.h | 930 + + .../wireless/bcmdhd_1_363_125_17/bcmxtlv.c | 461 + + .../net/wireless/bcmdhd_1_363_125_17/dbus.c | 2500 ++ + .../wireless/bcmdhd_1_363_125_17/dbus_usb.c | 1227 + + .../bcmdhd_1_363_125_17/dbus_usb_linux.c | 4600 ++++ + .../net/wireless/bcmdhd_1_363_125_17/dhd.h | 1598 ++ + .../wireless/bcmdhd_1_363_125_17/dhd_bta.c | 354 + + .../wireless/bcmdhd_1_363_125_17/dhd_bta.h | 42 + + .../wireless/bcmdhd_1_363_125_17/dhd_bus.h | 222 + + .../wireless/bcmdhd_1_363_125_17/dhd_buzzz.h | 37 + + .../wireless/bcmdhd_1_363_125_17/dhd_cdc.c | 963 + + .../bcmdhd_1_363_125_17/dhd_cfg80211.c | 268 + + .../bcmdhd_1_363_125_17/dhd_cfg80211.h | 54 + + .../bcmdhd_1_363_125_17/dhd_cfg_vendor.c | 174 + + .../bcmdhd_1_363_125_17/dhd_chip_info.c | 38 + + .../bcmdhd_1_363_125_17/dhd_chip_info.h | 43 + + .../wireless/bcmdhd_1_363_125_17/dhd_common.c | 3467 +++ + .../bcmdhd_1_363_125_17/dhd_custom_gpio.c | 436 + + .../wireless/bcmdhd_1_363_125_17/dhd_dbg.h | 146 + + .../wireless/bcmdhd_1_363_125_17/dhd_debug.c | 1297 + + .../wireless/bcmdhd_1_363_125_17/dhd_debug.h | 348 + + .../bcmdhd_1_363_125_17/dhd_debug_linux.c | 418 + + .../bcmdhd_1_363_125_17/dhd_flowring.c | 996 + + .../bcmdhd_1_363_125_17/dhd_flowring.h | 252 + + .../net/wireless/bcmdhd_1_363_125_17/dhd_ip.c | 1285 + + .../net/wireless/bcmdhd_1_363_125_17/dhd_ip.h | 85 + + .../wireless/bcmdhd_1_363_125_17/dhd_linux.c | 14067 ++++++++++ + .../wireless/bcmdhd_1_363_125_17/dhd_linux.h | 136 + + .../bcmdhd_1_363_125_17/dhd_linux_platdev.c | 913 + + .../bcmdhd_1_363_125_17/dhd_linux_sched.c | 51 + + .../bcmdhd_1_363_125_17/dhd_linux_wq.c | 320 + + .../bcmdhd_1_363_125_17/dhd_linux_wq.h | 69 + + .../wireless/bcmdhd_1_363_125_17/dhd_msgbuf.c | 6332 +++++ + .../wireless/bcmdhd_1_363_125_17/dhd_pcie.c | 5662 ++++ + .../wireless/bcmdhd_1_363_125_17/dhd_pcie.h | 266 + + .../bcmdhd_1_363_125_17/dhd_pcie_linux.c | 1287 + + .../wireless/bcmdhd_1_363_125_17/dhd_pno.c | 4111 +++ + .../wireless/bcmdhd_1_363_125_17/dhd_pno.h | 562 + + .../wireless/bcmdhd_1_363_125_17/dhd_proto.h | 168 + + .../wireless/bcmdhd_1_363_125_17/dhd_rtt.c | 2063 ++ + .../wireless/bcmdhd_1_363_125_17/dhd_rtt.h | 338 + + .../wireless/bcmdhd_1_363_125_17/dhd_sdio.c | 8736 ++++++ + .../wireless/bcmdhd_1_363_125_17/dhd_wlfc.c | 4566 ++++ + .../wireless/bcmdhd_1_363_125_17/dhd_wlfc.h | 562 + + .../wireless/bcmdhd_1_363_125_17/dngl_stats.h | 285 + + .../wireless/bcmdhd_1_363_125_17/dngl_wlhdr.h | 43 + + .../bcmdhd_1_363_125_17/hnd_pktpool.c | 1131 + + .../wireless/bcmdhd_1_363_125_17/hnd_pktq.c | 888 + + .../net/wireless/bcmdhd_1_363_125_17/hndpmu.c | 292 + + .../wireless/bcmdhd_1_363_125_17/linux_osl.c | 2531 ++ + .../wireless/bcmdhd_1_363_125_17/pcie_core.c | 115 + + .../wireless/bcmdhd_1_363_125_17/sbutils.c | 1108 + + .../wireless/bcmdhd_1_363_125_17/siutils.c | 3310 +++ + .../bcmdhd_1_363_125_17/siutils_priv.h | 290 + + .../wireless/bcmdhd_1_363_125_17/uamp_api.h | 181 + + .../wireless/bcmdhd_1_363_125_17/wl_android.c | 2717 ++ + .../wireless/bcmdhd_1_363_125_17/wl_android.h | 94 + + .../bcmdhd_1_363_125_17/wl_cfg80211.c | 16532 +++++++++++ + .../bcmdhd_1_363_125_17/wl_cfg80211.h | 1380 + + .../bcmdhd_1_363_125_17/wl_cfg_btcoex.c | 562 + + .../wireless/bcmdhd_1_363_125_17/wl_cfgnan.c | 2126 ++ + .../wireless/bcmdhd_1_363_125_17/wl_cfgnan.h | 226 + + .../wireless/bcmdhd_1_363_125_17/wl_cfgp2p.c | 2536 ++ + .../wireless/bcmdhd_1_363_125_17/wl_cfgp2p.h | 441 + + .../bcmdhd_1_363_125_17/wl_cfgvendor.c | 2892 ++ + .../bcmdhd_1_363_125_17/wl_cfgvendor.h | 418 + + .../net/wireless/bcmdhd_1_363_125_17/wl_dbg.h | 211 + + .../net/wireless/bcmdhd_1_363_125_17/wl_iw.c | 3801 +++ + .../net/wireless/bcmdhd_1_363_125_17/wl_iw.h | 164 + + .../bcmdhd_1_363_125_17/wl_linux_mon.c | 406 + + .../wireless/bcmdhd_1_363_125_17/wl_roam.c | 28 + + .../bcmdhd_1_363_125_17/wldev_common.c | 465 + + .../bcmdhd_1_363_125_17/wldev_common.h | 123 + + .../drivers/net/wireless/realtek/Makefile | 4 + + .../net/wireless/realtek/rtl8723ds/Kconfig | 4 + + .../net/wireless/realtek/rtl8723ds/Makefile | 2439 ++ + .../net/wireless/realtek/rtl8723ds/clean | 5 + + .../realtek/rtl8723ds/core/crypto/aes-ccm.c | 211 + + .../realtek/rtl8723ds/core/crypto/aes-ctr.c | 70 + + .../realtek/rtl8723ds/core/crypto/aes-gcm.c | 326 + + .../rtl8723ds/core/crypto/aes-internal-enc.c | 129 + + .../rtl8723ds/core/crypto/aes-internal.c | 843 + + .../realtek/rtl8723ds/core/crypto/aes-omac1.c | 172 + + .../realtek/rtl8723ds/core/crypto/aes-siv.c | 207 + + .../realtek/rtl8723ds/core/crypto/aes.h | 21 + + .../realtek/rtl8723ds/core/crypto/aes_i.h | 125 + + .../realtek/rtl8723ds/core/crypto/aes_siv.h | 21 + + .../realtek/rtl8723ds/core/crypto/aes_wrap.h | 73 + + .../realtek/rtl8723ds/core/crypto/ccmp.c | 384 + + .../realtek/rtl8723ds/core/crypto/gcmp.c | 193 + + .../rtl8723ds/core/crypto/rtw_crypto_wrap.c | 90 + + .../rtl8723ds/core/crypto/rtw_crypto_wrap.h | 65 + + .../rtl8723ds/core/crypto/sha256-internal.c | 230 + + .../rtl8723ds/core/crypto/sha256-prf.c | 109 + + .../realtek/rtl8723ds/core/crypto/sha256.c | 104 + + .../realtek/rtl8723ds/core/crypto/sha256.h | 30 + + .../realtek/rtl8723ds/core/crypto/sha256_i.h | 25 + + .../rtl8723ds/core/crypto/wlancrypto_wrap.h | 34 + + .../realtek/rtl8723ds/core/efuse/rtw_efuse.c | 3538 +++ + .../realtek/rtl8723ds/core/mesh/rtw_mesh.c | 4392 +++ + .../realtek/rtl8723ds/core/mesh/rtw_mesh.h | 537 + + .../rtl8723ds/core/mesh/rtw_mesh_hwmp.c | 1674 ++ + .../rtl8723ds/core/mesh/rtw_mesh_hwmp.h | 60 + + .../rtl8723ds/core/mesh/rtw_mesh_pathtbl.c | 1242 + + .../rtl8723ds/core/mesh/rtw_mesh_pathtbl.h | 211 + + .../rtl8723ds/core/monitor/rtw_radiotap.c | 615 + + .../rtl8723ds/core/monitor/rtw_radiotap.h | 63 + + .../wireless/realtek/rtl8723ds/core/rtw_ap.c | 5941 ++++ + .../realtek/rtl8723ds/core/rtw_beamforming.c | 2121 ++ + .../realtek/rtl8723ds/core/rtw_br_ext.c | 1581 ++ + .../realtek/rtl8723ds/core/rtw_bt_mp.c | 1575 ++ + .../realtek/rtl8723ds/core/rtw_btcoex.c | 1801 ++ + .../rtl8723ds/core/rtw_btcoex_wifionly.c | 47 + + .../realtek/rtl8723ds/core/rtw_chplan.c | 1241 + + .../realtek/rtl8723ds/core/rtw_chplan.h | 77 + + .../wireless/realtek/rtl8723ds/core/rtw_cmd.c | 5511 ++++ + .../realtek/rtl8723ds/core/rtw_debug.c | 7601 ++++++ + .../realtek/rtl8723ds/core/rtw_eeprom.c | 329 + + .../wireless/realtek/rtl8723ds/core/rtw_ft.c | 668 + + .../realtek/rtl8723ds/core/rtw_ieee80211.c | 3090 +++ + .../wireless/realtek/rtl8723ds/core/rtw_io.c | 952 + + .../realtek/rtl8723ds/core/rtw_ioctl_query.c | 19 + + .../realtek/rtl8723ds/core/rtw_ioctl_set.c | 923 + + .../wireless/realtek/rtl8723ds/core/rtw_iol.c | 388 + + .../wireless/realtek/rtl8723ds/core/rtw_mbo.c | 803 + + .../wireless/realtek/rtl8723ds/core/rtw_mem.c | 128 + + .../wireless/realtek/rtl8723ds/core/rtw_mi.c | 1550 ++ + .../realtek/rtl8723ds/core/rtw_mlme.c | 5440 ++++ + .../realtek/rtl8723ds/core/rtw_mlme_ext.c | 16111 +++++++++++ + .../wireless/realtek/rtl8723ds/core/rtw_mp.c | 3971 +++ + .../wireless/realtek/rtl8723ds/core/rtw_odm.c | 586 + + .../wireless/realtek/rtl8723ds/core/rtw_p2p.c | 5437 ++++ + .../realtek/rtl8723ds/core/rtw_pwrctrl.c | 2943 ++ + .../realtek/rtl8723ds/core/rtw_recv.c | 4687 ++++ + .../wireless/realtek/rtl8723ds/core/rtw_rf.c | 2126 ++ + .../wireless/realtek/rtl8723ds/core/rtw_rm.c | 2471 ++ + .../realtek/rtl8723ds/core/rtw_rm_fsm.c | 1016 + + .../realtek/rtl8723ds/core/rtw_rm_util.c | 434 + + .../realtek/rtl8723ds/core/rtw_rson.c | 588 + + .../realtek/rtl8723ds/core/rtw_sdio.c | 157 + + .../realtek/rtl8723ds/core/rtw_security.c | 2872 ++ + .../realtek/rtl8723ds/core/rtw_sreset.c | 316 + + .../realtek/rtl8723ds/core/rtw_sta_mgt.c | 1352 + + .../realtek/rtl8723ds/core/rtw_swcrypto.c | 296 + + .../realtek/rtl8723ds/core/rtw_tdls.c | 3507 +++ + .../wireless/realtek/rtl8723ds/core/rtw_vht.c | 1134 + + .../realtek/rtl8723ds/core/rtw_wapi.c | 1320 + + .../realtek/rtl8723ds/core/rtw_wapi_sms4.c | 922 + + .../realtek/rtl8723ds/core/rtw_wlan_util.c | 5029 ++++ + .../wireless/realtek/rtl8723ds/core/rtw_wnm.c | 865 + + .../realtek/rtl8723ds/core/rtw_xmit.c | 6338 +++++ + .../realtek/rtl8723ds/core/wds/rtw_wds.c | 463 + + .../realtek/rtl8723ds/core/wds/rtw_wds.h | 54 + + .../realtek/rtl8723ds/hal/HalPwrSeqCmd.c | 185 + + .../rtl8723ds/hal/btc/btc_basic_types.h | 53 + + .../rtl8723ds/hal/btc/halbtc8723d1ant.c | 5319 ++++ + .../rtl8723ds/hal/btc/halbtc8723d1ant.h | 475 + + .../rtl8723ds/hal/btc/halbtc8723d2ant.c | 6236 +++++ + .../rtl8723ds/hal/btc/halbtc8723d2ant.h | 486 + + .../realtek/rtl8723ds/hal/btc/halbtcoutsrc.h | 2061 ++ + .../realtek/rtl8723ds/hal/btc/mp_precomp.h | 159 + + .../realtek/rtl8723ds/hal/efuse/efuse_mask.h | 181 + + .../efuse/rtl8723d/HalEfuseMask8723D_PCIE.c | 91 + + .../efuse/rtl8723d/HalEfuseMask8723D_PCIE.h | 32 + + .../efuse/rtl8723d/HalEfuseMask8723D_SDIO.c | 89 + + .../efuse/rtl8723d/HalEfuseMask8723D_SDIO.h | 31 + + .../efuse/rtl8723d/HalEfuseMask8723D_USB.c | 92 + + .../efuse/rtl8723d/HalEfuseMask8723D_USB.h | 34 + + .../realtek/rtl8723ds/hal/hal_btcoex.c | 6388 +++++ + .../rtl8723ds/hal/hal_btcoex_wifionly.c | 264 + + .../wireless/realtek/rtl8723ds/hal/hal_com.c | 15699 +++++++++++ + .../realtek/rtl8723ds/hal/hal_com_c2h.h | 140 + + .../realtek/rtl8723ds/hal/hal_com_phycfg.c | 6197 +++++ + .../wireless/realtek/rtl8723ds/hal/hal_dm.c | 1855 ++ + .../wireless/realtek/rtl8723ds/hal/hal_dm.h | 118 + + .../realtek/rtl8723ds/hal/hal_dm_acs.c | 554 + + .../realtek/rtl8723ds/hal/hal_dm_acs.h | 167 + + .../realtek/rtl8723ds/hal/hal_halmac.c | 5868 ++++ + .../realtek/rtl8723ds/hal/hal_halmac.h | 251 + + .../realtek/rtl8723ds/hal/hal_hci/hal_sdio.c | 810 + + .../rtl8723ds/hal/hal_hci/hal_sdio_coex.c | 35 + + .../wireless/realtek/rtl8723ds/hal/hal_intf.c | 2291 ++ + .../wireless/realtek/rtl8723ds/hal/hal_mcc.c | 4048 +++ + .../wireless/realtek/rtl8723ds/hal/hal_mp.c | 2634 ++ + .../wireless/realtek/rtl8723ds/hal/hal_phy.c | 257 + + .../realtek/rtl8723ds/hal/led/hal_led.c | 254 + + .../realtek/rtl8723ds/hal/led/hal_sdio_led.c | 2014 ++ + .../rtl8723ds/hal/phydm/ap_makefile.mk | 222 + + .../realtek/rtl8723ds/hal/phydm/halhwimg.h | 137 + + .../rtl8723ds/hal/phydm/halrf/halphyrf_ap.c | 1674 ++ + .../rtl8723ds/hal/phydm/halrf/halphyrf_ap.h | 170 + + .../rtl8723ds/hal/phydm/halrf/halphyrf_ce.c | 1176 + + .../rtl8723ds/hal/phydm/halrf/halphyrf_ce.h | 123 + + .../rtl8723ds/hal/phydm/halrf/halphyrf_iot.c | 652 + + .../rtl8723ds/hal/phydm/halrf/halphyrf_iot.h | 137 + + .../rtl8723ds/hal/phydm/halrf/halphyrf_win.c | 1091 + + .../rtl8723ds/hal/phydm/halrf/halphyrf_win.h | 132 + + .../realtek/rtl8723ds/hal/phydm/halrf/halrf.c | 4065 +++ + .../realtek/rtl8723ds/hal/phydm/halrf/halrf.h | 787 + + .../rtl8723ds/hal/phydm/halrf/halrf_debug.c | 390 + + .../rtl8723ds/hal/phydm/halrf/halrf_debug.h | 123 + + .../rtl8723ds/hal/phydm/halrf/halrf_dpk.h | 150 + + .../hal/phydm/halrf/halrf_features.h | 43 + + .../rtl8723ds/hal/phydm/halrf/halrf_iqk.h | 149 + + .../rtl8723ds/hal/phydm/halrf/halrf_kfree.c | 2940 ++ + .../rtl8723ds/hal/phydm/halrf/halrf_kfree.h | 234 + + .../hal/phydm/halrf/halrf_powertracking.c | 183 + + .../hal/phydm/halrf/halrf_powertracking.h | 43 + + .../hal/phydm/halrf/halrf_powertracking_ap.c | 1252 + + .../hal/phydm/halrf/halrf_powertracking_ap.h | 406 + + .../hal/phydm/halrf/halrf_powertracking_ce.c | 936 + + .../hal/phydm/halrf/halrf_powertracking_ce.h | 330 + + .../hal/phydm/halrf/halrf_powertracking_iot.c | 980 + + .../hal/phydm/halrf/halrf_powertracking_iot.h | 371 + + .../hal/phydm/halrf/halrf_powertracking_win.c | 909 + + .../hal/phydm/halrf/halrf_powertracking_win.h | 305 + + .../rtl8723ds/hal/phydm/halrf/halrf_psd.c | 531 + + .../rtl8723ds/hal/phydm/halrf/halrf_psd.h | 50 + + .../hal/phydm/halrf/halrf_txgapcal.c | 300 + + .../hal/phydm/halrf/halrf_txgapcal.h | 31 + + .../hal/phydm/halrf/rtl8723d/halrf_8723d.c | 2637 ++ + .../hal/phydm/halrf/rtl8723d/halrf_8723d.h | 83 + + .../realtek/rtl8723ds/hal/phydm/mp_precomp.h | 24 + + .../realtek/rtl8723ds/hal/phydm/phydm.c | 3684 +++ + .../realtek/rtl8723ds/hal/phydm/phydm.h | 1541 ++ + .../realtek/rtl8723ds/hal/phydm/phydm.mk | 233 + + .../rtl8723ds/hal/phydm/phydm_adaptivity.c | 847 + + .../rtl8723ds/hal/phydm/phydm_adaptivity.h | 126 + + .../rtl8723ds/hal/phydm/phydm_adc_sampling.c | 1597 ++ + .../rtl8723ds/hal/phydm/phydm_adc_sampling.h | 172 + + .../rtl8723ds/hal/phydm/phydm_antdect.c | 888 + + .../rtl8723ds/hal/phydm/phydm_antdect.h | 78 + + .../rtl8723ds/hal/phydm/phydm_antdiv.c | 6143 +++++ + .../rtl8723ds/hal/phydm/phydm_antdiv.h | 534 + + .../realtek/rtl8723ds/hal/phydm/phydm_api.c | 3383 +++ + .../realtek/rtl8723ds/hal/phydm/phydm_api.h | 214 + + .../rtl8723ds/hal/phydm/phydm_auto_dbg.c | 725 + + .../rtl8723ds/hal/phydm/phydm_auto_dbg.h | 115 + + .../rtl8723ds/hal/phydm/phydm_beamforming.c | 1986 ++ + .../rtl8723ds/hal/phydm/phydm_beamforming.h | 363 + + .../rtl8723ds/hal/phydm/phydm_cck_pd.c | 1359 + + .../rtl8723ds/hal/phydm/phydm_cck_pd.h | 192 + + .../hal/phydm/phydm_cck_rx_pathdiv.c | 164 + + .../hal/phydm/phydm_cck_rx_pathdiv.h | 67 + + .../realtek/rtl8723ds/hal/phydm/phydm_ccx.c | 1951 ++ + .../realtek/rtl8723ds/hal/phydm/phydm_ccx.h | 261 + + .../rtl8723ds/hal/phydm/phydm_cfotracking.c | 618 + + .../rtl8723ds/hal/phydm/phydm_cfotracking.h | 74 + + .../realtek/rtl8723ds/hal/phydm/phydm_debug.c | 5864 ++++ + .../realtek/rtl8723ds/hal/phydm/phydm_debug.h | 484 + + .../realtek/rtl8723ds/hal/phydm/phydm_dfs.c | 2196 ++ + .../realtek/rtl8723ds/hal/phydm/phydm_dfs.h | 191 + + .../realtek/rtl8723ds/hal/phydm/phydm_dig.c | 3447 +++ + .../realtek/rtl8723ds/hal/phydm/phydm_dig.h | 373 + + .../rtl8723ds/hal/phydm/phydm_direct_bf.c | 366 + + .../rtl8723ds/hal/phydm/phydm_direct_bf.h | 44 + + .../hal/phydm/phydm_dynamictxpower.c | 764 + + .../hal/phydm/phydm_dynamictxpower.h | 142 + + .../rtl8723ds/hal/phydm/phydm_features.h | 80 + + .../rtl8723ds/hal/phydm/phydm_features_ap.h | 218 + + .../rtl8723ds/hal/phydm/phydm_features_ce.h | 232 + + .../hal/phydm/phydm_features_ce2_kernel.h | 84 + + .../rtl8723ds/hal/phydm/phydm_features_iot.h | 171 + + .../rtl8723ds/hal/phydm/phydm_features_win.h | 210 + + .../rtl8723ds/hal/phydm/phydm_hwconfig.c | 1641 ++ + .../rtl8723ds/hal/phydm/phydm_hwconfig.h | 79 + + .../rtl8723ds/hal/phydm/phydm_interface.c | 1472 + + .../rtl8723ds/hal/phydm/phydm_interface.h | 326 + + .../rtl8723ds/hal/phydm/phydm_lna_sat.c | 1335 + + .../rtl8723ds/hal/phydm/phydm_lna_sat.h | 173 + + .../rtl8723ds/hal/phydm/phydm_math_lib.c | 285 + + .../rtl8723ds/hal/phydm/phydm_math_lib.h | 120 + + .../realtek/rtl8723ds/hal/phydm/phydm_mp.c | 302 + + .../realtek/rtl8723ds/hal/phydm/phydm_mp.h | 78 + + .../rtl8723ds/hal/phydm/phydm_noisemonitor.c | 467 + + .../rtl8723ds/hal/phydm/phydm_noisemonitor.h | 48 + + .../rtl8723ds/hal/phydm/phydm_pathdiv.c | 1115 + + .../rtl8723ds/hal/phydm/phydm_pathdiv.h | 145 + + .../rtl8723ds/hal/phydm/phydm_phystatus.c | 3134 +++ + .../rtl8723ds/hal/phydm/phydm_phystatus.h | 1178 + + .../hal/phydm/phydm_pmac_tx_setting.c | 510 + + .../hal/phydm/phydm_pmac_tx_setting.h | 109 + + .../rtl8723ds/hal/phydm/phydm_pow_train.c | 171 + + .../rtl8723ds/hal/phydm/phydm_pow_train.h | 84 + + .../rtl8723ds/hal/phydm/phydm_pre_define.h | 980 + + .../rtl8723ds/hal/phydm/phydm_precomp.h | 625 + + .../rtl8723ds/hal/phydm/phydm_primary_cca.c | 173 + + .../rtl8723ds/hal/phydm/phydm_primary_cca.h | 76 + + .../realtek/rtl8723ds/hal/phydm/phydm_psd.c | 486 + + .../realtek/rtl8723ds/hal/phydm/phydm_psd.h | 68 + + .../rtl8723ds/hal/phydm/phydm_rainfo.c | 2365 ++ + .../rtl8723ds/hal/phydm/phydm_rainfo.h | 306 + + .../realtek/rtl8723ds/hal/phydm/phydm_reg.h | 243 + + .../rtl8723ds/hal/phydm/phydm_regdefine11ac.h | 109 + + .../rtl8723ds/hal/phydm/phydm_regdefine11n.h | 220 + + .../rtl8723ds/hal/phydm/phydm_regtable.h | 969 + + .../rtl8723ds/hal/phydm/phydm_rssi_monitor.c | 189 + + .../rtl8723ds/hal/phydm/phydm_rssi_monitor.h | 58 + + .../rtl8723ds/hal/phydm/phydm_smt_ant.c | 2277 ++ + .../rtl8723ds/hal/phydm/phydm_smt_ant.h | 210 + + .../realtek/rtl8723ds/hal/phydm/phydm_soml.c | 1441 + + .../realtek/rtl8723ds/hal/phydm/phydm_soml.h | 199 + + .../realtek/rtl8723ds/hal/phydm/phydm_types.h | 413 + + .../hal/phydm/rtl8723d/hal8723dreg.h | 947 + + .../hal/phydm/rtl8723d/halhwimg8723d_bb.c | 908 + + .../hal/phydm/rtl8723d/halhwimg8723d_bb.h | 51 + + .../hal/phydm/rtl8723d/halhwimg8723d_mac.c | 294 + + .../hal/phydm/rtl8723d/halhwimg8723d_mac.h | 33 + + .../hal/phydm/rtl8723d/halhwimg8723d_rf.c | 1182 + + .../hal/phydm/rtl8723d/halhwimg8723d_rf.h | 78 + + .../hal/phydm/rtl8723d/phydm_regconfig8723d.c | 145 + + .../hal/phydm/rtl8723d/phydm_regconfig8723d.h | 44 + + .../hal/phydm/rtl8723d/phydm_rtl8723d.c | 50 + + .../hal/phydm/rtl8723d/phydm_rtl8723d.h | 24 + + .../hal/phydm/rtl8723d/version_rtl8723d.h | 4 + + .../rtl8723ds/hal/phydm/sd4_phydm_2_kernel.mk | 188 + + .../rtl8723ds/hal/phydm/txbf/halcomtxbf.c | 520 + + .../rtl8723ds/hal/phydm/txbf/halcomtxbf.h | 183 + + .../rtl8723ds/hal/phydm/txbf/haltxbf8192e.c | 384 + + .../rtl8723ds/hal/phydm/txbf/haltxbf8192e.h | 71 + + .../rtl8723ds/hal/phydm/txbf/haltxbf8814a.c | 675 + + .../rtl8723ds/hal/phydm/txbf/haltxbf8814a.h | 77 + + .../rtl8723ds/hal/phydm/txbf/haltxbf8822b.c | 1088 + + .../rtl8723ds/hal/phydm/txbf/haltxbf8822b.h | 78 + + .../hal/phydm/txbf/haltxbfinterface.c | 1484 + + .../hal/phydm/txbf/haltxbfinterface.h | 167 + + .../rtl8723ds/hal/phydm/txbf/haltxbfjaguar.c | 509 + + .../rtl8723ds/hal/phydm/txbf/haltxbfjaguar.h | 78 + + .../hal/phydm/txbf/phydm_hal_txbf_api.c | 748 + + .../hal/phydm/txbf/phydm_hal_txbf_api.h | 89 + + .../rtl8723ds/hal/rtl8723d/Hal8723DPwrSeq.c | 84 + + .../rtl8723ds/hal/rtl8723d/hal8723d_fw.c | 10915 ++++++++ + .../rtl8723ds/hal/rtl8723d/hal8723d_fw.h | 40 + + .../rtl8723ds/hal/rtl8723d/rtl8723d_cmd.c | 476 + + .../rtl8723ds/hal/rtl8723d/rtl8723d_dm.c | 310 + + .../hal/rtl8723d/rtl8723d_hal_init.c | 5476 ++++ + .../hal/rtl8723d/rtl8723d_lps_poff.c | 871 + + .../rtl8723ds/hal/rtl8723d/rtl8723d_phycfg.c | 1193 + + .../rtl8723ds/hal/rtl8723d/rtl8723d_rf6052.c | 235 + + .../rtl8723ds/hal/rtl8723d/rtl8723d_rxdesc.c | 57 + + .../rtl8723ds/hal/rtl8723d/rtl8723d_sreset.c | 101 + + .../hal/rtl8723d/sdio/rtl8723ds_led.c | 123 + + .../hal/rtl8723d/sdio/rtl8723ds_recv.c | 510 + + .../hal/rtl8723d/sdio/rtl8723ds_xmit.c | 797 + + .../hal/rtl8723d/sdio/sdio_halinit.c | 1761 ++ + .../rtl8723ds/hal/rtl8723d/sdio/sdio_ops.c | 1815 ++ + .../wireless/realtek/rtl8723ds/ifcfg-wlan0 | 4 + + .../rtl8723ds/include/Hal8188EPhyCfg.h | 249 + + .../rtl8723ds/include/Hal8188EPhyReg.h | 1100 + + .../rtl8723ds/include/Hal8188EPwrSeq.h | 170 + + .../rtl8723ds/include/Hal8188FPhyCfg.h | 120 + + .../rtl8723ds/include/Hal8188FPhyReg.h | 1165 + + .../rtl8723ds/include/Hal8188FPwrSeq.h | 212 + + .../rtl8723ds/include/Hal8192EPhyCfg.h | 136 + + .../rtl8723ds/include/Hal8192EPhyReg.h | 1146 + + .../rtl8723ds/include/Hal8192EPwrSeq.h | 169 + + .../rtl8723ds/include/Hal8192FPhyCfg.h | 115 + + .../rtl8723ds/include/Hal8192FPhyReg.h | 1134 + + .../rtl8723ds/include/Hal8192FPwrSeq.h | 220 + + .../rtl8723ds/include/Hal8703BPhyCfg.h | 116 + + .../rtl8723ds/include/Hal8703BPhyReg.h | 1133 + + .../rtl8723ds/include/Hal8703BPwrSeq.h | 198 + + .../rtl8723ds/include/Hal8710BPhyCfg.h | 111 + + .../rtl8723ds/include/Hal8710BPhyReg.h | 1134 + + .../rtl8723ds/include/Hal8710BPwrSeq.h | 167 + + .../rtl8723ds/include/Hal8723BPhyCfg.h | 116 + + .../rtl8723ds/include/Hal8723BPhyReg.h | 1131 + + .../rtl8723ds/include/Hal8723BPwrSeq.h | 246 + + .../rtl8723ds/include/Hal8723DPhyCfg.h | 115 + + .../rtl8723ds/include/Hal8723DPhyReg.h | 1134 + + .../rtl8723ds/include/Hal8723DPwrSeq.h | 206 + + .../realtek/rtl8723ds/include/Hal8723PwrSeq.h | 183 + + .../realtek/rtl8723ds/include/Hal8812PhyCfg.h | 134 + + .../realtek/rtl8723ds/include/Hal8812PhyReg.h | 735 + + .../realtek/rtl8723ds/include/Hal8812PwrSeq.h | 208 + + .../realtek/rtl8723ds/include/Hal8814PhyCfg.h | 236 + + .../realtek/rtl8723ds/include/Hal8814PhyReg.h | 863 + + .../realtek/rtl8723ds/include/Hal8814PwrSeq.h | 231 + + .../rtl8723ds/include/Hal8821APwrSeq.h | 200 + + .../realtek/rtl8723ds/include/HalPwrSeqCmd.h | 130 + + .../realtek/rtl8723ds/include/HalVerDef.h | 207 + + .../realtek/rtl8723ds/include/autoconf.h | 303 + + .../realtek/rtl8723ds/include/basic_types.h | 357 + + .../rtl8723ds/include/byteorder/big_endian.h | 82 + + .../rtl8723ds/include/byteorder/generic.h | 207 + + .../include/byteorder/little_endian.h | 84 + + .../rtl8723ds/include/byteorder/swab.h | 136 + + .../rtl8723ds/include/byteorder/swabb.h | 151 + + .../realtek/rtl8723ds/include/circ_buf.h | 23 + + .../realtek/rtl8723ds/include/cmd_osdep.h | 26 + + .../rtl8723ds/include/cmn_info/rtw_sta_info.h | 277 + + .../realtek/rtl8723ds/include/custom_gpio.h | 34 + + .../realtek/rtl8723ds/include/drv_conf.h | 729 + + .../realtek/rtl8723ds/include/drv_types.h | 1982 ++ + .../realtek/rtl8723ds/include/drv_types_ce.h | 86 + + .../rtl8723ds/include/drv_types_gspi.h | 49 + + .../rtl8723ds/include/drv_types_linux.h | 19 + + .../realtek/rtl8723ds/include/drv_types_pci.h | 60 + + .../rtl8723ds/include/drv_types_sdio.h | 94 + + .../realtek/rtl8723ds/include/drv_types_xp.h | 88 + + .../realtek/rtl8723ds/include/ethernet.h | 36 + + .../realtek/rtl8723ds/include/gspi_hal.h | 30 + + .../realtek/rtl8723ds/include/gspi_ops.h | 180 + + .../rtl8723ds/include/gspi_ops_linux.h | 18 + + .../realtek/rtl8723ds/include/gspi_osintf.h | 19 + + .../realtek/rtl8723ds/include/h2clbk.h | 26 + + .../realtek/rtl8723ds/include/hal_btcoex.h | 106 + + .../rtl8723ds/include/hal_btcoex_wifionly.h | 88 + + .../realtek/rtl8723ds/include/hal_com.h | 803 + + .../realtek/rtl8723ds/include/hal_com_h2c.h | 673 + + .../realtek/rtl8723ds/include/hal_com_led.h | 437 + + .../rtl8723ds/include/hal_com_phycfg.h | 350 + + .../realtek/rtl8723ds/include/hal_com_reg.h | 1889 ++ + .../realtek/rtl8723ds/include/hal_data.h | 879 + + .../realtek/rtl8723ds/include/hal_gspi.h | 26 + + .../realtek/rtl8723ds/include/hal_ic_cfg.h | 602 + + .../realtek/rtl8723ds/include/hal_intf.h | 895 + + .../realtek/rtl8723ds/include/hal_pg.h | 954 + + .../realtek/rtl8723ds/include/hal_phy.h | 234 + + .../realtek/rtl8723ds/include/hal_phy_reg.h | 270 + + .../realtek/rtl8723ds/include/hal_sdio.h | 84 + + .../realtek/rtl8723ds/include/hal_sdio_coex.h | 41 + + .../realtek/rtl8723ds/include/ieee80211.h | 2045 ++ + .../realtek/rtl8723ds/include/ieee80211_ext.h | 312 + + .../realtek/rtl8723ds/include/if_ether.h | 106 + + .../wireless/realtek/rtl8723ds/include/ip.h | 135 + + .../rtl8723ds/include/linux/wireless.h | 87 + + .../realtek/rtl8723ds/include/mlme_osdep.h | 25 + + .../realtek/rtl8723ds/include/nic_spec.h | 41 + + .../realtek/rtl8723ds/include/osdep_intf.h | 139 + + .../realtek/rtl8723ds/include/osdep_service.h | 825 + + .../rtl8723ds/include/osdep_service_bsd.h | 757 + + .../rtl8723ds/include/osdep_service_ce.h | 200 + + .../rtl8723ds/include/osdep_service_linux.h | 550 + + .../rtl8723ds/include/osdep_service_xp.h | 210 + + .../realtek/rtl8723ds/include/pci_hal.h | 60 + + .../realtek/rtl8723ds/include/pci_ops.h | 116 + + .../realtek/rtl8723ds/include/pci_osintf.h | 69 + + .../realtek/rtl8723ds/include/recv_osdep.h | 70 + + .../realtek/rtl8723ds/include/rtl8188e_cmd.h | 165 + + .../realtek/rtl8723ds/include/rtl8188e_dm.h | 27 + + .../realtek/rtl8723ds/include/rtl8188e_hal.h | 316 + + .../realtek/rtl8723ds/include/rtl8188e_led.h | 37 + + .../realtek/rtl8723ds/include/rtl8188e_recv.h | 156 + + .../realtek/rtl8723ds/include/rtl8188e_rf.h | 27 + + .../realtek/rtl8723ds/include/rtl8188e_spec.h | 159 + + .../rtl8723ds/include/rtl8188e_sreset.h | 24 + + .../realtek/rtl8723ds/include/rtl8188e_xmit.h | 293 + + .../realtek/rtl8723ds/include/rtl8188f_cmd.h | 206 + + .../realtek/rtl8723ds/include/rtl8188f_dm.h | 39 + + .../realtek/rtl8723ds/include/rtl8188f_hal.h | 260 + + .../realtek/rtl8723ds/include/rtl8188f_led.h | 45 + + .../realtek/rtl8723ds/include/rtl8188f_recv.h | 65 + + .../realtek/rtl8723ds/include/rtl8188f_rf.h | 25 + + .../realtek/rtl8723ds/include/rtl8188f_spec.h | 275 + + .../rtl8723ds/include/rtl8188f_sreset.h | 24 + + .../realtek/rtl8723ds/include/rtl8188f_xmit.h | 334 + + .../realtek/rtl8723ds/include/rtl8192e_cmd.h | 147 + + .../realtek/rtl8723ds/include/rtl8192e_dm.h | 28 + + .../realtek/rtl8723ds/include/rtl8192e_hal.h | 330 + + .../realtek/rtl8723ds/include/rtl8192e_led.h | 36 + + .../realtek/rtl8723ds/include/rtl8192e_recv.h | 175 + + .../realtek/rtl8723ds/include/rtl8192e_rf.h | 28 + + .../realtek/rtl8723ds/include/rtl8192e_spec.h | 313 + + .../rtl8723ds/include/rtl8192e_sreset.h | 24 + + .../realtek/rtl8723ds/include/rtl8192e_xmit.h | 448 + + .../realtek/rtl8723ds/include/rtl8192f_cmd.h | 194 + + .../realtek/rtl8723ds/include/rtl8192f_dm.h | 27 + + .../realtek/rtl8723ds/include/rtl8192f_hal.h | 316 + + .../realtek/rtl8723ds/include/rtl8192f_led.h | 59 + + .../realtek/rtl8723ds/include/rtl8192f_recv.h | 107 + + .../realtek/rtl8723ds/include/rtl8192f_rf.h | 88 + + .../realtek/rtl8723ds/include/rtl8192f_spec.h | 541 + + .../rtl8723ds/include/rtl8192f_sreset.h | 24 + + .../realtek/rtl8723ds/include/rtl8192f_xmit.h | 529 + + .../realtek/rtl8723ds/include/rtl8703b_cmd.h | 205 + + .../realtek/rtl8723ds/include/rtl8703b_dm.h | 39 + + .../realtek/rtl8723ds/include/rtl8703b_hal.h | 266 + + .../realtek/rtl8723ds/include/rtl8703b_led.h | 44 + + .../realtek/rtl8723ds/include/rtl8703b_recv.h | 82 + + .../realtek/rtl8723ds/include/rtl8703b_rf.h | 25 + + .../realtek/rtl8723ds/include/rtl8703b_spec.h | 464 + + .../rtl8723ds/include/rtl8703b_sreset.h | 24 + + .../realtek/rtl8723ds/include/rtl8703b_xmit.h | 333 + + .../realtek/rtl8723ds/include/rtl8710b_cmd.h | 175 + + .../realtek/rtl8723ds/include/rtl8710b_dm.h | 39 + + .../realtek/rtl8723ds/include/rtl8710b_hal.h | 277 + + .../realtek/rtl8723ds/include/rtl8710b_led.h | 44 + + .../rtl8723ds/include/rtl8710b_lps_poff.h | 56 + + .../realtek/rtl8723ds/include/rtl8710b_recv.h | 81 + + .../realtek/rtl8723ds/include/rtl8710b_rf.h | 20 + + .../realtek/rtl8723ds/include/rtl8710b_spec.h | 481 + + .../rtl8723ds/include/rtl8710b_sreset.h | 24 + + .../realtek/rtl8723ds/include/rtl8710b_xmit.h | 520 + + .../realtek/rtl8723ds/include/rtl8723b_cmd.h | 205 + + .../realtek/rtl8723ds/include/rtl8723b_dm.h | 38 + + .../realtek/rtl8723ds/include/rtl8723b_hal.h | 274 + + .../realtek/rtl8723ds/include/rtl8723b_led.h | 44 + + .../realtek/rtl8723ds/include/rtl8723b_recv.h | 82 + + .../realtek/rtl8723ds/include/rtl8723b_rf.h | 25 + + .../realtek/rtl8723ds/include/rtl8723b_spec.h | 280 + + .../rtl8723ds/include/rtl8723b_sreset.h | 24 + + .../realtek/rtl8723ds/include/rtl8723b_xmit.h | 333 + + .../realtek/rtl8723ds/include/rtl8723d_cmd.h | 189 + + .../realtek/rtl8723ds/include/rtl8723d_dm.h | 39 + + .../realtek/rtl8723ds/include/rtl8723d_hal.h | 303 + + .../realtek/rtl8723ds/include/rtl8723d_led.h | 44 + + .../rtl8723ds/include/rtl8723d_lps_poff.h | 56 + + .../realtek/rtl8723ds/include/rtl8723d_recv.h | 112 + + .../realtek/rtl8723ds/include/rtl8723d_rf.h | 21 + + .../realtek/rtl8723ds/include/rtl8723d_spec.h | 447 + + .../rtl8723ds/include/rtl8723d_sreset.h | 24 + + .../realtek/rtl8723ds/include/rtl8723d_xmit.h | 521 + + .../realtek/rtl8723ds/include/rtl8812a_cmd.h | 158 + + .../realtek/rtl8723ds/include/rtl8812a_dm.h | 27 + + .../realtek/rtl8723ds/include/rtl8812a_hal.h | 369 + + .../realtek/rtl8723ds/include/rtl8812a_led.h | 41 + + .../realtek/rtl8723ds/include/rtl8812a_recv.h | 149 + + .../realtek/rtl8723ds/include/rtl8812a_rf.h | 28 + + .../realtek/rtl8723ds/include/rtl8812a_spec.h | 263 + + .../rtl8723ds/include/rtl8812a_sreset.h | 24 + + .../realtek/rtl8723ds/include/rtl8812a_xmit.h | 365 + + .../realtek/rtl8723ds/include/rtl8814a_cmd.h | 166 + + .../realtek/rtl8723ds/include/rtl8814a_dm.h | 23 + + .../realtek/rtl8723ds/include/rtl8814a_hal.h | 329 + + .../realtek/rtl8723ds/include/rtl8814a_led.h | 36 + + .../realtek/rtl8723ds/include/rtl8814a_recv.h | 182 + + .../realtek/rtl8723ds/include/rtl8814a_rf.h | 28 + + .../realtek/rtl8723ds/include/rtl8814a_spec.h | 654 + + .../rtl8723ds/include/rtl8814a_sreset.h | 24 + + .../realtek/rtl8723ds/include/rtl8814a_xmit.h | 309 + + .../realtek/rtl8723ds/include/rtl8814b_hal.h | 239 + + .../realtek/rtl8723ds/include/rtl8814be_hal.h | 30 + + .../realtek/rtl8723ds/include/rtl8814bu_hal.h | 61 + + .../realtek/rtl8723ds/include/rtl8821a_spec.h | 90 + + .../realtek/rtl8723ds/include/rtl8821a_xmit.h | 173 + + .../realtek/rtl8723ds/include/rtl8821c_dm.h | 23 + + .../realtek/rtl8723ds/include/rtl8821c_hal.h | 84 + + .../realtek/rtl8723ds/include/rtl8821c_spec.h | 202 + + .../realtek/rtl8723ds/include/rtl8821ce_hal.h | 23 + + .../realtek/rtl8723ds/include/rtl8821cs_hal.h | 23 + + .../realtek/rtl8723ds/include/rtl8821cu_hal.h | 24 + + .../realtek/rtl8723ds/include/rtl8822b_hal.h | 234 + + .../realtek/rtl8723ds/include/rtl8822be_hal.h | 27 + + .../realtek/rtl8723ds/include/rtl8822bs_hal.h | 31 + + .../realtek/rtl8723ds/include/rtl8822bu_hal.h | 61 + + .../realtek/rtl8723ds/include/rtl8822c_hal.h | 246 + + .../realtek/rtl8723ds/include/rtl8822ce_hal.h | 27 + + .../realtek/rtl8723ds/include/rtl8822cs_hal.h | 31 + + .../realtek/rtl8723ds/include/rtl8822cu_hal.h | 61 + + .../realtek/rtl8723ds/include/rtw_android.h | 117 + + .../realtek/rtl8723ds/include/rtw_ap.h | 143 + + .../rtl8723ds/include/rtw_beamforming.h | 297 + + .../realtek/rtl8723ds/include/rtw_br_ext.h | 69 + + .../realtek/rtl8723ds/include/rtw_bt_mp.h | 288 + + .../realtek/rtl8723ds/include/rtw_btcoex.h | 460 + + .../rtl8723ds/include/rtw_btcoex_wifionly.h | 24 + + .../realtek/rtl8723ds/include/rtw_byteorder.h | 33 + + .../realtek/rtl8723ds/include/rtw_cmd.h | 778 + + .../realtek/rtl8723ds/include/rtw_debug.h | 700 + + .../realtek/rtl8723ds/include/rtw_eeprom.h | 116 + + .../realtek/rtl8723ds/include/rtw_efuse.h | 277 + + .../realtek/rtl8723ds/include/rtw_event.h | 94 + + .../realtek/rtl8723ds/include/rtw_ft.h | 183 + + .../realtek/rtl8723ds/include/rtw_ht.h | 217 + + .../realtek/rtl8723ds/include/rtw_io.h | 526 + + .../realtek/rtl8723ds/include/rtw_ioctl.h | 47 + + .../rtl8723ds/include/rtw_ioctl_query.h | 19 + + .../realtek/rtl8723ds/include/rtw_ioctl_set.h | 40 + + .../realtek/rtl8723ds/include/rtw_iol.h | 131 + + .../realtek/rtl8723ds/include/rtw_mbo.h | 114 + + .../realtek/rtl8723ds/include/rtw_mcc.h | 315 + + .../realtek/rtl8723ds/include/rtw_mem.h | 41 + + .../realtek/rtl8723ds/include/rtw_mi.h | 310 + + .../realtek/rtl8723ds/include/rtw_mlme.h | 1199 + + .../realtek/rtl8723ds/include/rtw_mlme_ext.h | 1179 + + .../realtek/rtl8723ds/include/rtw_mp.h | 937 + + .../rtl8723ds/include/rtw_mp_phy_regdef.h | 1094 + + .../realtek/rtl8723ds/include/rtw_odm.h | 102 + + .../realtek/rtl8723ds/include/rtw_p2p.h | 169 + + .../realtek/rtl8723ds/include/rtw_pwrctrl.h | 625 + + .../realtek/rtl8723ds/include/rtw_qos.h | 66 + + .../realtek/rtl8723ds/include/rtw_recv.h | 835 + + .../realtek/rtl8723ds/include/rtw_rf.h | 306 + + .../realtek/rtl8723ds/include/rtw_rm.h | 88 + + .../realtek/rtl8723ds/include/rtw_rm_fsm.h | 396 + + .../realtek/rtl8723ds/include/rtw_rm_util.h | 42 + + .../realtek/rtl8723ds/include/rtw_rson.h | 61 + + .../realtek/rtl8723ds/include/rtw_sdio.h | 26 + + .../realtek/rtl8723ds/include/rtw_security.h | 421 + + .../realtek/rtl8723ds/include/rtw_sreset.h | 66 + + .../realtek/rtl8723ds/include/rtw_swcrypto.h | 49 + + .../realtek/rtl8723ds/include/rtw_tdls.h | 185 + + .../realtek/rtl8723ds/include/rtw_version.h | 2 + + .../realtek/rtl8723ds/include/rtw_vht.h | 181 + + .../realtek/rtl8723ds/include/rtw_wapi.h | 230 + + .../realtek/rtl8723ds/include/rtw_wnm.h | 169 + + .../realtek/rtl8723ds/include/rtw_xmit.h | 1085 + + .../realtek/rtl8723ds/include/sdio_hal.h | 57 + + .../realtek/rtl8723ds/include/sdio_ops.h | 206 + + .../realtek/rtl8723ds/include/sdio_ops_ce.h | 49 + + .../rtl8723ds/include/sdio_ops_linux.h | 58 + + .../realtek/rtl8723ds/include/sdio_ops_xp.h | 49 + + .../realtek/rtl8723ds/include/sdio_osintf.h | 19 + + .../realtek/rtl8723ds/include/sta_info.h | 771 + + .../realtek/rtl8723ds/include/usb_hal.h | 71 + + .../realtek/rtl8723ds/include/usb_ops.h | 153 + + .../realtek/rtl8723ds/include/usb_ops_linux.h | 98 + + .../realtek/rtl8723ds/include/usb_osintf.h | 26 + + .../rtl8723ds/include/usb_vendor_req.h | 56 + + .../wireless/realtek/rtl8723ds/include/wifi.h | 1357 + + .../realtek/rtl8723ds/include/wlan_bssdef.h | 327 + + .../realtek/rtl8723ds/include/xmit_osdep.h | 96 + + .../os_dep/linux/custom_gpio_linux.c | 377 + + .../rtl8723ds/os_dep/linux/ioctl_cfg80211.c | 10775 ++++++++ + .../rtl8723ds/os_dep/linux/ioctl_cfg80211.h | 442 + + .../rtl8723ds/os_dep/linux/ioctl_linux.c | 12920 +++++++++ + .../realtek/rtl8723ds/os_dep/linux/ioctl_mp.c | 3393 +++ + .../rtl8723ds/os_dep/linux/mlme_linux.c | 444 + + .../realtek/rtl8723ds/os_dep/linux/os_intfs.c | 5646 ++++ + .../rtl8723ds/os_dep/linux/recv_linux.c | 678 + + .../rtl8723ds/os_dep/linux/rhashtable.c | 844 + + .../rtl8723ds/os_dep/linux/rhashtable.h | 827 + + .../rtl8723ds/os_dep/linux/rtw_android.c | 1344 + + .../rtl8723ds/os_dep/linux/rtw_cfgvendor.c | 2117 ++ + .../rtl8723ds/os_dep/linux/rtw_cfgvendor.h | 636 + + .../realtek/rtl8723ds/os_dep/linux/rtw_proc.c | 5614 ++++ + .../realtek/rtl8723ds/os_dep/linux/rtw_proc.h | 66 + + .../rtl8723ds/os_dep/linux/rtw_rhashtable.c | 77 + + .../rtl8723ds/os_dep/linux/rtw_rhashtable.h | 67 + + .../rtl8723ds/os_dep/linux/sdio_intf.c | 1374 + + .../rtl8723ds/os_dep/linux/sdio_ops_linux.c | 1347 + + .../rtl8723ds/os_dep/linux/wifi_regd.c | 128 + + .../rtl8723ds/os_dep/linux/wifi_regd.h | 22 + + .../rtl8723ds/os_dep/linux/xmit_linux.c | 538 + + .../realtek/rtl8723ds/os_dep/osdep_service.c | 3220 +++ + .../platform/custom_country_chplan.h | 22 + + .../platform/platform_ARM_SUN50IW1P1_sdio.c | 86 + + .../platform/platform_ARM_SUNnI_sdio.c | 130 + + .../platform/platform_ARM_SUNxI_sdio.c | 90 + + .../platform/platform_ARM_SUNxI_usb.c | 136 + + .../platform/platform_ARM_WMT_sdio.c | 46 + + .../rtl8723ds/platform/platform_RTK_DMP_usb.c | 30 + + .../platform/platform_aml_s905_sdio.c | 54 + + .../platform/platform_aml_s905_sdio.h | 28 + + .../platform/platform_arm_act_sdio.c | 53 + + .../platform/platform_hisilicon_hi3798_sdio.c | 110 + + .../platform/platform_hisilicon_hi3798_sdio.h | 28 + + .../realtek/rtl8723ds/platform/platform_ops.c | 34 + + .../realtek/rtl8723ds/platform/platform_ops.h | 26 + + .../rtl8723ds/platform/platform_sprd_sdio.c | 84 + + .../platform/platform_zte_zx296716_sdio.c | 53 + + .../platform/platform_zte_zx296716_sdio.h | 25 + + .../net/wireless/realtek/rtl8723ds/runwpa | 20 + + .../net/wireless/realtek/rtl8723ds/wlan0dhcp | 16 + + module_drivers/drivers/pinctrl/Kconfig | 16 + + module_drivers/drivers/pinctrl/Makefile | 3 + + module_drivers/drivers/pinctrl/multi-vgpio.c | 168 + + .../drivers/pinctrl/pinctrl-ingenic.c | 2056 ++ + .../drivers/pinctrl/pinctrl-ingenic.h | 370 + + module_drivers/drivers/power/Makefile | 1 + + module_drivers/drivers/power/supply/Makefile | 1 + + .../drivers/power/supply/axp_power/Kconfig | 37 + + .../drivers/power/supply/axp_power/Makefile | 12 + + .../power/supply/axp_power/axp-board.c | 476 + + .../drivers/power/supply/axp_power/axp-cfg.h | 344 + + .../power/supply/axp_power/axp-filenode.c | 511 + + .../drivers/power/supply/axp_power/axp-gpio.c | 542 + + .../drivers/power/supply/axp_power/axp-gpio.h | 30 + + .../power/supply/axp_power/axp-mfd-216.h | 191 + + .../drivers/power/supply/axp_power/axp-mfd.c | 302 + + .../drivers/power/supply/axp_power/axp-mfd.h | 95 + + .../drivers/power/supply/axp_power/axp-regu.c | 495 + + .../drivers/power/supply/axp_power/axp-regu.h | 186 + + .../drivers/power/supply/axp_power/axp-rw.c | 142 + + .../drivers/power/supply/axp_power/axp-rw.h | 209 + + .../drivers/power/supply/axp_power/axp-sply.c | 2297 ++ + .../drivers/power/supply/axp_power/axp-sply.h | 180 + + .../power/supply/axp_power/axp-state.c | 197 + + .../power/supply/axp_power/axp216-mfd.h | 385 + + .../power/supply/axp_power/virtual216.c | 472 + + .../power/supply/axp_power/virtual216_dev.c | 157 + + module_drivers/drivers/pwm/Kconfig | 36 + + module_drivers/drivers/pwm/Makefile | 4 + + module_drivers/drivers/pwm/pwm-ingenic-v2.c | 906 + + module_drivers/drivers/pwm/pwm-ingenic-v3.c | 1273 + + module_drivers/drivers/pwm/pwm-ingenic.c | 495 + + module_drivers/drivers/rtc/Kconfig | 22 + + module_drivers/drivers/rtc/Makefile | 1 + + module_drivers/drivers/rtc/rtc-ingenic.c | 644 + + module_drivers/drivers/rtc/rtc-ingenic.h | 141 + + module_drivers/drivers/spi/Kconfig | 27 + + module_drivers/drivers/spi/Makefile | 2 + + module_drivers/drivers/spi/ingenic_slv.c | 1201 + + module_drivers/drivers/spi/ingenic_slv.h | 564 + + module_drivers/drivers/spi/ingenic_spi.c | 1505 ++ + module_drivers/drivers/spi/ingenic_spi.h | 1175 + + module_drivers/drivers/tty/Makefile | 1 + + module_drivers/drivers/tty/serial/Kconfig | 41 + + module_drivers/drivers/tty/serial/Makefile | 1 + + .../drivers/tty/serial/ingenic_uart.c | 1219 + + .../drivers/tty/serial/ingenic_uart.h | 117 + + module_drivers/drivers/video/Makefile | 6 + + module_drivers/drivers/video/fbdev/Makefile | 1 + + .../drivers/video/fbdev/ingenic/Kconfig | 60 + + .../drivers/video/fbdev/ingenic/Makefile | 2 + + .../video/fbdev/ingenic/fb_stage/Kconfig | 12 + + .../video/fbdev/ingenic/fb_stage/Makefile | 12 + + .../video/fbdev/ingenic/fb_stage/README.md | 59 + + .../fbdev/ingenic/fb_stage/displays/Kconfig | 182 + + .../fbdev/ingenic/fb_stage/displays/Makefile | 29 + + .../jd9365/JD9365_8001280init-4lane.txt | 284 + + .../fb_stage/displays/jd9365/panel-jd9365.c | 692 + + ...280_FP7721BX2_Column_G2.2_190613_Nolan.txt | 245 + + .../fb_stage/displays/jd9365d/panel-jd9365d.c | 725 + + .../fbdev/ingenic/fb_stage/displays/lt9211.c | 585 + + .../fbdev/ingenic/fb_stage/displays/lt9211.h | 62 + + .../fb_stage/displays/panel-G104X1L04.c | 1124 + + .../fb_stage/displays/panel-MV238FHM-N30.c | 416 + + .../ingenic/fb_stage/displays/panel-atk7016.c | 309 + + .../ingenic/fb_stage/displays/panel-bm8766.c | 310 + + .../fb_stage/displays/panel-ek79007ad.c | 462 + + .../ingenic/fb_stage/displays/panel-fw035.c | 509 + + .../ingenic/fb_stage/displays/panel-fw040.c | 644 + + .../ingenic/fb_stage/displays/panel-fw050.c | 717 + + .../ingenic/fb_stage/displays/panel-gc9203.c | 507 + + .../fb_stage/displays/panel-gwmtf16499b.c | 304 + + .../ingenic/fb_stage/displays/panel-jd9161z.c | 528 + + .../ingenic/fb_stage/displays/panel-jd9366.c | 749 + + .../fb_stage/displays/panel-kd035hvfbd037.c | 563 + + .../fb_stage/displays/panel-kd035hvfmd057.c | 472 + + .../fb_stage/displays/panel-kd050hdfia019.c | 474 + + .../fb_stage/displays/panel-kd050hdfia020.c | 724 + + .../fb_stage/displays/panel-kd050wvfpa029.c | 307 + + .../ingenic/fb_stage/displays/panel-ma0060.c | 1115 + + .../ingenic/fb_stage/displays/panel-st7282.c | 271 + + .../fb_stage/displays/panel-st7701s-rgb666.c | 976 + + .../ingenic/fb_stage/displays/panel-st7701s.c | 580 + + .../fb_stage/displays/panel-tl040hds01ct.c | 373 + + .../fb_stage/displays/panel-tl040wvs03ct.c | 736 + + .../ingenic/fb_stage/displays/panel-y88249.c | 297 + + .../fb_stage/displays/panel-ylym286a.c | 490 + + .../fb_stage/displays/panel-yts500xlai.c | 494 + + ...T7701S_DX3.95IPS_mipi_480x480_V1.0-RGB.txt | 225 + + .../st7701s_dx3.95ips/panel-st7701sdx.c | 497 + + .../video/fbdev/ingenic/fb_stage/dpu_ctrl.c | 2005 ++ + .../video/fbdev/ingenic/fb_stage/dpu_ctrl.h | 196 + + .../fbdev/ingenic/fb_stage/dpu_dma_desc.h | 183 + + .../video/fbdev/ingenic/fb_stage/dpu_reg.h | 888 + + .../fbdev/ingenic/fb_stage/hw_composer.c | 135 + + .../fbdev/ingenic/fb_stage/hw_composer.h | 40 + + .../fbdev/ingenic/fb_stage/hw_composer_fb.c | 871 + + .../fbdev/ingenic/fb_stage/hw_composer_fb.h | 84 + + .../fbdev/ingenic/fb_stage/hw_composer_v4l2.c | 737 + + .../fbdev/ingenic/fb_stage/hw_composer_v4l2.h | 72 + + .../video/fbdev/ingenic/fb_stage/ingenicfb.c | 1487 + + .../video/fbdev/ingenic/fb_stage/ingenicfb.h | 144 + + .../video/fbdev/ingenic/fb_stage/jz_dsim.h | 298 + + .../ingenic/fb_stage/jz_mipi_dsi/Makefile | 1 + + .../fb_stage/jz_mipi_dsi/jz_mipi_dsi.c | 1031 + + .../jz_mipi_dsi/jz_mipi_dsi_lowlevel.c | 705 + + .../jz_mipi_dsi/jz_mipi_dsi_lowlevel.h | 29 + + .../fb_stage/jz_mipi_dsi/jz_mipi_dsi_regs.h | 79 + + .../fb_stage/jz_mipi_dsi/jz_mipi_dsih_hal.c | 1302 + + .../fb_stage/jz_mipi_dsi/jz_mipi_dsih_hal.h | 147 + + .../video/fbdev/ingenic/fb_stage/lcd_panel.h | 156 + + .../video/fbdev/ingenic/fb_stage/sysfs.c | 784 + + .../video/fbdev/ingenic/fb_stage/sysfs.h | 45 + + .../fbdev/ingenic/fb_stage/todo/colorbar.c | 247 + + .../video/fbdev/ingenic/fb_stage/todo/sysfs.c | 1259 + + .../fbdev/ingenic/fb_stage/uapi_ingenicfb.h | 121 + + .../drivers/video/ingenic-nna/Kconfig | 9 + + .../drivers/video/ingenic-nna/Makefile | 5 + + .../video/ingenic-nna/mpsys-firmware/Makefile | 4 + + .../ingenic-nna/mpsys-firmware/mpsys-funcs.c | 182 + + .../ingenic-nna/mpsys-firmware/mpsys-funcs.h | 65 + + .../ingenic-nna/mpsys-firmware/mpsys_module.c | 52 + + .../drivers/video/ingenic-nna/soc_nna.c | 883 + + .../drivers/video/ingenic-nna/soc_nna.h | 65 + + .../video/ingenic-nna/soc_nna_common.h | 24 + + .../drivers/video/ingenic-nna/soc_nna_hw.h | 40 + + .../drivers/video/ingenic_avpu/Kconfig | 9 + + .../drivers/video/ingenic_avpu/Makefile | 19 + + .../drivers/video/ingenic_avpu/avpu_alloc.c | 43 + + .../drivers/video/ingenic_avpu/avpu_alloc.h | 15 + + .../video/ingenic_avpu/avpu_alloc_ioctl.c | 92 + + .../video/ingenic_avpu/avpu_alloc_ioctl.h | 8 + + .../drivers/video/ingenic_avpu/avpu_dmabuf.c | 634 + + .../drivers/video/ingenic_avpu/avpu_dmabuf.h | 13 + + .../drivers/video/ingenic_avpu/avpu_ioctl.h | 22 + + .../drivers/video/ingenic_avpu/avpu_ip.c | 144 + + .../drivers/video/ingenic_avpu/avpu_ip.h | 84 + + .../drivers/video/ingenic_avpu/avpu_main.c | 706 + + .../video/ingenic_avpu/avpu_no_dmabuf.c | 21 + + .../drivers/video/ingenic_bscaler/Kconfig | 4 + + .../drivers/video/ingenic_bscaler/Makefile | 1 + + .../video/ingenic_bscaler/ingenic_bscaler.c | 387 + + .../drivers/video/ingenic_ipu/Kconfig | 18 + + .../drivers/video/ingenic_ipu/Makefile | 2 + + .../video/ingenic_ipu/ingenic_drawbox.c | 625 + + .../video/ingenic_ipu/ingenic_drawbox.h | 161 + + .../video/ingenic_ipu/ingenic_ipu_v13.c | 1206 + + .../video/ingenic_ipu/ingenic_ipu_v13.h | 210 + + .../video/ingenic_ipu/ingenic_regs_v13.h | 349 + + .../drivers/video/ingenic_ipu/ipu_dmabuf.c | 702 + + .../drivers/video/ingenic_ipu/ipu_dmabuf.h | 22 + + .../drivers/video/logo-ingenic/.gitignore | 1 + + .../drivers/video/logo-ingenic/Kconfig | 19 + + .../drivers/video/logo-ingenic/Makefile | 4 + + .../drivers/video/logo-ingenic/logo.c | 943 + + .../drivers/video/logo-ingenic/showlogo.c | 133 + + module_drivers/drivers/watchdog/Kconfig | 20 + + module_drivers/drivers/watchdog/Makefile | 3 + + module_drivers/drivers/watchdog/ingenic_wdt.c | 328 + + module_drivers/drivers/watchdog/ingenic_wdt.h | 65 + + .../drivers/watchdog/ingenic_wdt_v1.c | 601 + + module_drivers/drivers/watchdog/sgm820_wdt.c | 107 + + module_drivers/dts/Makefile | 18 + + .../RD_X2000_HALLEY5_CAMERA_2V1.dtsi | 83 + + .../RD_X2000_HALLEY5_CAMERA_3V2.dtsi | 38 + + .../RD_X2000_HALLEY5_CAMERA_3V2_4LANE.dtsi | 35 + + .../RD_X2000_HALLEY5_CAMERA_4V2.dtsi | 83 + + .../RD_X2000_HALLEY5_CAMERA_4V3.dtsi | 65 + + .../RD_X2000_HALLEY5_CAMERA_4V3_2KALE.dtsi | 58 + + .../RD_X2000_HALLEY5_CAMERA_5V0.dtsi | 38 + + .../RD_X2000_HALLEY5_CAMERA_cim.dtsi | 70 + + module_drivers/dts/halley5_v20.dts | 500 + + module_drivers/dts/halley5_v30.dts | 556 + + .../RD_X1600_HALLEY6_DVP_CAMERA.dtsi | 40 + + .../RD_X1600_HALLEY6_MIPI_CAMERA.dtsi | 35 + + .../RD_X1600_HALLEY6_RGB_LCD_1V0.dtsi | 117 + + .../RD_X1600_HALLEY6_RGB_SLCD_1V0.dtsi | 64 + + .../RD_X1600_HALLEY6_RGB_SPI_LCD_1V0.dtsi | 110 + + module_drivers/dts/halley6_v10.dts | 396 + + module_drivers/dts/halley6_v20.dts | 396 + + .../RD_X2000_HALLEY5_CAMERA_3V2.dtsi | 34 + + .../RD_X2000_HALLEY5_CAMERA_4V3.dtsi | 58 + + .../RD_X2500_HIPPO_CAMERA_1V0.dtsi | 105 + + .../RD_X2500_HIPPO_CAMERA_1V1.dtsi | 98 + + module_drivers/dts/hippo_cameras/ov2735a.dtsi | 35 + + module_drivers/dts/hippo_v10.dts | 421 + + module_drivers/dts/hippo_v12.dts | 431 + + module_drivers/dts/kale_v10.dts | 574 + + module_drivers/dts/m300-pinctrl.dtsi | 658 + + .../RD_X1600_PANDA_CAMERA_3V2.dtsi | 38 + + .../RD_X1600_PANDA_DVP_CAMERA_1V0.dtsi | 41 + + .../RD_X1600_PANDA_DVP_CAMERA_2V0.dtsi | 40 + + ...RD_X1600_PANDA_DVP_CAMERA_AND_LCD_1V0.dtsi | 42 + + .../RD_X1600_PANDA_MIPI_CAMERA_1V0.dtsi | 37 + + .../RD_X1600_PANDA_MIPI_CAMERA_2V0.dtsi | 37 + + .../panda_lcd/RD_X1600_IRIS_RGB_LCD_1V0.dtsi | 70 + + ...00_PANDA_LCD_AND_DVP_CAMERA_1V0_KD037.dtsi | 36 + + ...00_PANDA_LCD_AND_DVP_CAMERA_1V0_KD057.dtsi | 36 + + .../panda_lcd/RD_X1600_PANDA_RGB_LCD_1V0.dtsi | 124 + + .../panda_lcd/RD_X1600_PANDA_SPI_LCD_1V0.dtsi | 36 + + module_drivers/dts/panda_v10.dts | 423 + + module_drivers/dts/viomi_v2000.dts | 583 + + module_drivers/dts/x1600-pinctrl.dtsi | 380 + + module_drivers/dts/x1600.dtsi | 523 + + module_drivers/dts/x1600_module_base.dts | 154 + + module_drivers/dts/x2000-pinctrl.dtsi | 651 + + module_drivers/dts/x2000.dtsi | 800 + + .../dts/x2000_lifesmart_480p_harmony.dts | 423 + + module_drivers/dts/x2000_module_base.dts | 194 + + module_drivers/dts/x2500-pinctrl.dtsi | 297 + + module_drivers/dts/x2500.dtsi | 744 + + module_drivers/sound/Makefile | 1 + + module_drivers/sound/soc/Makefile | 1 + + module_drivers/sound/soc/ingenic/Kconfig | 329 + + module_drivers/sound/soc/ingenic/Makefile | 8 + + module_drivers/sound/soc/ingenic/README | 31 + + .../sound/soc/ingenic/as-v1/Makefile | 9 + + .../sound/soc/ingenic/as-v1/asoc-aic.c | 430 + + .../sound/soc/ingenic/as-v1/asoc-aic.h | 793 + + .../sound/soc/ingenic/as-v1/asoc-dma.c | 744 + + .../sound/soc/ingenic/as-v1/asoc-dma.h | 31 + + .../sound/soc/ingenic/as-v1/asoc-dmic.c | 540 + + .../sound/soc/ingenic/as-v1/asoc-dmic.h | 301 + + .../sound/soc/ingenic/as-v1/asoc-i2s-tloop.c | 331 + + .../sound/soc/ingenic/as-v1/asoc-i2s.c | 637 + + .../sound/soc/ingenic/as-v1/asoc-pcm.c | 417 + + .../sound/soc/ingenic/as-v1/asoc-pcm.h | 253 + + .../sound/soc/ingenic/as-v1/asoc-spdif.c | 490 + + .../sound/soc/ingenic/as-v1/assert.h | 16 + + .../sound/soc/ingenic/as-v2/Makefile | 17 + + .../sound/soc/ingenic/as-v2/as-baic.c | 919 + + .../sound/soc/ingenic/as-v2/as-baic.h | 175 + + .../sound/soc/ingenic/as-v2/as-dma.c | 967 + + .../sound/soc/ingenic/as-v2/as-dma.h | 205 + + .../sound/soc/ingenic/as-v2/as-dmic.c | 309 + + .../sound/soc/ingenic/as-v2/as-dmic.h | 64 + + .../sound/soc/ingenic/as-v2/as-dsp.c | 585 + + .../sound/soc/ingenic/as-v2/as-dsp.h | 150 + + .../sound/soc/ingenic/as-v2/as-fmtcov.c | 187 + + .../sound/soc/ingenic/as-v2/as-fmtcov.h | 57 + + .../sound/soc/ingenic/as-v2/as-mixer.c | 186 + + .../sound/soc/ingenic/as-v2/as-mixer.h | 50 + + .../sound/soc/ingenic/as-v2/as-spdif.c | 445 + + .../sound/soc/ingenic/as-v2/as-spdif.h | 99 + + .../sound/soc/ingenic/as-v2/as-vir-fe.c | 148 + + .../sound/soc/ingenic/boards/Makefile | 19 + + .../sound/soc/ingenic/boards/gewu.c | 547 + + .../sound/soc/ingenic/boards/halley5_v20.c | 624 + + .../sound/soc/ingenic/boards/halley6.c | 225 + + .../sound/soc/ingenic/boards/hippo-board.c | 258 + + .../sound/soc/ingenic/boards/kale_v10.c | 624 + + .../sound/soc/ingenic/boards/panda.c | 242 + + .../sound/soc/ingenic/ecodec/Kconfig | 37 + + .../sound/soc/ingenic/ecodec/Makefile | 5 + + .../sound/soc/ingenic/ecodec/ak4458.c | 685 + + .../sound/soc/ingenic/ecodec/ak4458.h | 88 + + .../sound/soc/ingenic/ecodec/ak5558.c | 425 + + .../sound/soc/ingenic/ecodec/ak5558.h | 52 + + .../sound/soc/ingenic/ecodec/nau8822.c | 1179 + + .../sound/soc/ingenic/ecodec/nau8822.h | 161 + + .../sound/soc/ingenic/ecodec/wm8594.c | 1177 + + .../sound/soc/ingenic/ecodec/wm8594.h | 64 + + .../sound/soc/ingenic/icodec/Makefile | 6 + + .../sound/soc/ingenic/icodec/dump.c | 119 + + .../sound/soc/ingenic/icodec/icdc_d3.c | 762 + + .../sound/soc/ingenic/icodec/icdc_d3.h | 407 + + .../sound/soc/ingenic/icodec/icdc_inno.c | 906 + + .../sound/soc/ingenic/icodec/icdc_inno_v2.c | 1239 + + net/wireless/core.c | 3 +- + scripts/Makefile | 3 +- + scripts/Makefile.lib | 4 + + .../pic2logo-include/stb_image/stb_image.h | 7464 +++++ + .../stb_image/stb_image_resize.h | 2627 ++ + .../stb_image/stb_image_write.h | 1568 ++ + scripts/pic2logo.c | 147 + + 1924 files changed, 1156993 insertions(+), 2123 deletions(-) + create mode 100644 arch/mips/configs/halley5_small_defconfig + create mode 100644 arch/mips/xburst/Kconfig + create mode 100644 arch/mips/xburst/Makefile + create mode 100644 arch/mips/xburst/Platform + create mode 100644 arch/mips/xburst/common/Makefile + create mode 100644 arch/mips/xburst/common/include/ingenic_proc.h + create mode 100644 arch/mips/xburst/common/include/jz_notifier.h + create mode 100755 arch/mips/xburst/common/include/mxu.h + create mode 100755 arch/mips/xburst/common/include/mxu_media.h + create mode 100644 arch/mips/xburst/common/include/mxuv3.h + create mode 100644 arch/mips/xburst/common/initrd-check.c + create mode 100644 arch/mips/xburst/common/jz_notifier.c + create mode 100644 arch/mips/xburst/common/mxu-xburst.c + create mode 100644 arch/mips/xburst/common/proc.c + create mode 100644 arch/mips/xburst/common/prom.c + create mode 100644 arch/mips/xburst/common/sc-xburst.c + create mode 100644 arch/mips/xburst/debug/Makefile + create mode 100644 arch/mips/xburst/debug/trace-exit.c + create mode 100644 arch/mips/xburst/soc-x1000/Kconfig.DT + create mode 100644 arch/mips/xburst/soc-x1000/Makefile + create mode 100644 arch/mips/xburst/soc-x1000/early_printk.c + create mode 100644 arch/mips/xburst/soc-x1000/include/cpu-feature-overrides.h + create mode 100644 arch/mips/xburst/soc-x1000/include/irq.h + create mode 100644 arch/mips/xburst/soc-x1000/include/soc/base.h + create mode 100644 arch/mips/xburst/soc-x1000/include/soc/cache.h + create mode 100644 arch/mips/xburst/soc-x1000/include/soc/cpm.h + create mode 100644 arch/mips/xburst/soc-x1000/include/soc/ost.h + create mode 100644 arch/mips/xburst/soc-x1000/include/soc/sfc.h + create mode 100644 arch/mips/xburst/soc-x1000/include/soc/tcsm_layout.h + create mode 100644 arch/mips/xburst/soc-x1000/include/soc/tcu.h + create mode 100644 arch/mips/xburst/soc-x1000/include/war.h + create mode 100644 arch/mips/xburst/soc-x1000/pm.c + create mode 100644 arch/mips/xburst/soc-x1000/regs_save_restore.S + create mode 100644 arch/mips/xburst/soc-x1000/setup.c + create mode 100644 arch/mips/xburst/soc-x1000/socid.c + create mode 100644 arch/mips/xburst/soc-x1600/Kconfig.DT + create mode 100644 arch/mips/xburst/soc-x1600/Makefile + create mode 100644 arch/mips/xburst/soc-x1600/early_printk.c + create mode 100644 arch/mips/xburst/soc-x1600/gpio.c + create mode 100644 arch/mips/xburst/soc-x1600/include/cpu-feature-overrides.h + create mode 100644 arch/mips/xburst/soc-x1600/include/irq.h + create mode 100644 arch/mips/xburst/soc-x1600/include/libdmmu.h + create mode 100644 arch/mips/xburst/soc-x1600/include/soc/base.h + create mode 100644 arch/mips/xburst/soc-x1600/include/soc/cache.h + create mode 100644 arch/mips/xburst/soc-x1600/include/soc/cpm.h + create mode 100644 arch/mips/xburst/soc-x1600/include/soc/ddr.h + create mode 100644 arch/mips/xburst/soc-x1600/include/soc/efuse.h + create mode 100644 arch/mips/xburst/soc-x1600/include/soc/gpio.h + create mode 100644 arch/mips/xburst/soc-x1600/include/soc/ost.h + create mode 100644 arch/mips/xburst/soc-x1600/include/soc/sfc.h + create mode 100644 arch/mips/xburst/soc-x1600/include/soc/tcsm_layout.h + create mode 100644 arch/mips/xburst/soc-x1600/include/soc/tcu.h + create mode 100644 arch/mips/xburst/soc-x1600/include/war.h + create mode 100644 arch/mips/xburst/soc-x1600/libdmmu.c + create mode 100644 arch/mips/xburst/soc-x1600/pm.c + create mode 100644 arch/mips/xburst/soc-x1600/pm.h + create mode 100644 arch/mips/xburst/soc-x1600/regs_save_restore.S + create mode 100755 arch/mips/xburst/soc-x1600/regs_save_restore.py + create mode 100644 arch/mips/xburst/soc-x1600/setup.c + create mode 100644 arch/mips/xburst2/Kconfig + create mode 100644 arch/mips/xburst2/Makefile + create mode 100644 arch/mips/xburst2/Platform + create mode 100644 arch/mips/xburst2/common/Makefile + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/Makefile + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/cpu_ccu_test.c + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/cpu_dma_test.c + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/cpu_spinlock_test.c + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/cpu_tcsm.h + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/cpu_watch_test.c + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/ddr_bandwidth_monitor.c + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/ddr_change_freq.c + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/l2c_test.c + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/multithread_test.c + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/multithread_test.h + create mode 100644 arch/mips/xburst2/common/cpu_ddr_test/raw_dma_test.c + create mode 100644 arch/mips/xburst2/common/get-cpu-features.c + create mode 100644 arch/mips/xburst2/common/initrd-check.c + create mode 100644 arch/mips/xburst2/common/mxuv3.c + create mode 100644 arch/mips/xburst2/common/proc.c + create mode 100644 arch/mips/xburst2/core/Makefile + create mode 100644 arch/mips/xburst2/core/include/ccu.h + create mode 100644 arch/mips/xburst2/core/include/core_base.h + create mode 100644 arch/mips/xburst2/core/include/ingenic_proc.h + create mode 100644 arch/mips/xburst2/core/include/irq_cpu.h + create mode 100755 arch/mips/xburst2/core/include/mxu.h + create mode 100644 arch/mips/xburst2/core/include/mxuv3.h + create mode 100644 arch/mips/xburst2/core/prom.c + create mode 100644 arch/mips/xburst2/core/sc.c + create mode 100644 arch/mips/xburst2/core/smp.c + create mode 100644 arch/mips/xburst2/soc-m300/Kconfig.DT + create mode 100644 arch/mips/xburst2/soc-m300/Makefile + create mode 100644 arch/mips/xburst2/soc-m300/include/cpu-feature-overrides.h + create mode 100644 arch/mips/xburst2/soc-m300/include/irq.h + create mode 100644 arch/mips/xburst2/soc-m300/include/libdmmu.h + create mode 100644 arch/mips/xburst2/soc-m300/include/soc/base.h + create mode 100644 arch/mips/xburst2/soc-m300/include/soc/cache.h + create mode 100644 arch/mips/xburst2/soc-m300/include/soc/cpm.h + create mode 100644 arch/mips/xburst2/soc-m300/include/soc/ddr.h + create mode 100644 arch/mips/xburst2/soc-m300/include/soc/extal.h + create mode 100644 arch/mips/xburst2/soc-m300/include/soc/rtc.h + create mode 100644 arch/mips/xburst2/soc-m300/include/soc/sfc.h + create mode 100644 arch/mips/xburst2/soc-m300/include/soc/tcsm_layout.h + create mode 100644 arch/mips/xburst2/soc-m300/include/war.h + create mode 100644 arch/mips/xburst2/soc-m300/libdmmu.c + create mode 100644 arch/mips/xburst2/soc-m300/pm.c + create mode 100644 arch/mips/xburst2/soc-m300/pm.h + create mode 100644 arch/mips/xburst2/soc-m300/pm_fastboot.c + create mode 100644 arch/mips/xburst2/soc-m300/pm_fastboot.h + create mode 100644 arch/mips/xburst2/soc-m300/pm_sleep.c + create mode 100644 arch/mips/xburst2/soc-m300/pm_sleep.h + create mode 100644 arch/mips/xburst2/soc-m300/regs_save_restore.S + create mode 100755 arch/mips/xburst2/soc-m300/regs_save_restore.py + create mode 100644 arch/mips/xburst2/soc-m300/reset.c + create mode 100644 arch/mips/xburst2/soc-m300/serial.c + create mode 100644 arch/mips/xburst2/soc-m300/setup.c + create mode 100644 arch/mips/xburst2/soc-m300/sleep_firmware/Makefile + create mode 100644 arch/mips/xburst2/soc-m300/sleep_firmware/Readme + create mode 100644 arch/mips/xburst2/soc-m300/sleep_firmware/include/base.h + create mode 100755 arch/mips/xburst2/soc-m300/sleep_firmware/include/cpm.h + create mode 100644 arch/mips/xburst2/soc-m300/sleep_firmware/include/ddr.h + create mode 100755 arch/mips/xburst2/soc-m300/sleep_firmware/include/gpio.h + create mode 100644 arch/mips/xburst2/soc-m300/sleep_firmware/include/pm_fastboot.h + create mode 100755 arch/mips/xburst2/soc-m300/sleep_firmware/include/uart.h + create mode 100755 arch/mips/xburst2/soc-m300/sleep_firmware/mkmodule.sh + create mode 100644 arch/mips/xburst2/soc-m300/sleep_firmware/src/fastboot_resume.c + create mode 100644 arch/mips/xburst2/soc-m300/sleep_firmware/src/uart.c + create mode 100644 arch/mips/xburst2/soc-m300/sleep_firmware/target.ld + create mode 100644 arch/mips/xburst2/soc-x2000/Kconfig.DT + create mode 100644 arch/mips/xburst2/soc-x2000/Makefile + create mode 100644 arch/mips/xburst2/soc-x2000/gpio.c + create mode 100644 arch/mips/xburst2/soc-x2000/include/cpu-feature-overrides.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/irq.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/libdmmu.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/soc/base.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/soc/cache.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/soc/cpm.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/soc/ddr.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/soc/efuse.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/soc/extal.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/soc/gpio.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/soc/rtc.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/soc/sfc.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/soc/tcsm_layout.h + create mode 100644 arch/mips/xburst2/soc-x2000/include/war.h + create mode 100644 arch/mips/xburst2/soc-x2000/libdmmu.c + create mode 100644 arch/mips/xburst2/soc-x2000/pm.c + create mode 100644 arch/mips/xburst2/soc-x2000/pm.h + create mode 100644 arch/mips/xburst2/soc-x2000/pm_fastboot.c + create mode 100644 arch/mips/xburst2/soc-x2000/pm_fastboot.h + create mode 100644 arch/mips/xburst2/soc-x2000/regs_save_restore.S + create mode 100755 arch/mips/xburst2/soc-x2000/regs_save_restore.py + create mode 100644 arch/mips/xburst2/soc-x2000/reset.c + create mode 100644 arch/mips/xburst2/soc-x2000/serial.c + create mode 100644 arch/mips/xburst2/soc-x2000/setup.c + create mode 100644 arch/mips/xburst2/soc-x2000/sleep_firmware/Makefile + create mode 100644 arch/mips/xburst2/soc-x2000/sleep_firmware/Readme + create mode 100644 arch/mips/xburst2/soc-x2000/sleep_firmware/include/base.h + create mode 100755 arch/mips/xburst2/soc-x2000/sleep_firmware/include/cpm.h + create mode 100644 arch/mips/xburst2/soc-x2000/sleep_firmware/include/ddr.h + create mode 100755 arch/mips/xburst2/soc-x2000/sleep_firmware/include/gpio.h + create mode 100644 arch/mips/xburst2/soc-x2000/sleep_firmware/include/pm_fastboot.h + create mode 100755 arch/mips/xburst2/soc-x2000/sleep_firmware/include/uart.h + create mode 100755 arch/mips/xburst2/soc-x2000/sleep_firmware/mkmodule.sh + create mode 100644 arch/mips/xburst2/soc-x2000/sleep_firmware/src/fastboot_resume.c + create mode 100644 arch/mips/xburst2/soc-x2000/sleep_firmware/src/uart.c + create mode 100644 arch/mips/xburst2/soc-x2000/sleep_firmware/target.ld + create mode 100644 arch/mips/xburst2/soc-x2000/sleep_firmware/tmp.map + create mode 100644 arch/mips/xburst2/soc-x2500/Kconfig.DT + create mode 100644 arch/mips/xburst2/soc-x2500/Makefile + create mode 100644 arch/mips/xburst2/soc-x2500/gpio.c + create mode 100644 arch/mips/xburst2/soc-x2500/include/cpu-feature-overrides.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/irq.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/libdmmu.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/base.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/cache.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/cpm.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/ddr.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/extal.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/gpio.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/mmc.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/pdma.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/rtc.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/sfc.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/soc/tcsm_layout.h + create mode 100644 arch/mips/xburst2/soc-x2500/include/war.h + create mode 100644 arch/mips/xburst2/soc-x2500/libdmmu.c + create mode 100644 arch/mips/xburst2/soc-x2500/pm.c + create mode 100644 arch/mips/xburst2/soc-x2500/pm.h + create mode 100644 arch/mips/xburst2/soc-x2500/pm_fastboot.c + create mode 100644 arch/mips/xburst2/soc-x2500/pm_fastboot.h + create mode 100644 arch/mips/xburst2/soc-x2500/regs_save_restore.S + create mode 100755 arch/mips/xburst2/soc-x2500/regs_save_restore.py + create mode 100644 arch/mips/xburst2/soc-x2500/reset.c + create mode 100644 arch/mips/xburst2/soc-x2500/serial.c + create mode 100644 arch/mips/xburst2/soc-x2500/setup.c + create mode 100644 drivers/char/jz_spinand_firmware.c + create mode 100644 drivers/char/jz_spinand_firmware.h + create mode 100644 drivers/media/platform/v4l2loopback/Makefile + create mode 100644 drivers/media/platform/v4l2loopback/v4l2loopback.c + create mode 100644 drivers/media/platform/v4l2loopback/v4l2loopback.h + create mode 100644 drivers/media/platform/v4l2loopback/v4l2loopback_formats.h + create mode 100644 drivers/mtd/mtdblock_bbt_ro.c + create mode 100755 drivers/usb/gadget/function/f_mtp.c + create mode 100644 drivers/usb/gadget/function/f_mtp.h + create mode 100644 drivers/usb/gadget/function/f_ptp.c + create mode 100644 drivers/usb/phy/phy-ingenic-inno.c + create mode 100644 drivers/usb/phy/phy-ingenic-x1000.c + create mode 100644 drivers/usb/phy/phy-ingenic-x1600.c + create mode 100644 drivers/usb/phy/phy-ingenic-x2000.c + create mode 100644 drivers/usb/phy/phy-ingenic-x2500.c + create mode 100644 drivers/usb/phy/phy-ingenic.c + create mode 100644 drivers/usb/phy/phy-ingenic.h + create mode 100644 include/dt-bindings/clock/ingenic-m300.h + create mode 100644 include/dt-bindings/clock/ingenic-tcu.h + create mode 100644 include/dt-bindings/clock/ingenic-x1600.h + create mode 100644 include/dt-bindings/clock/ingenic-x2000.h + create mode 100644 include/dt-bindings/clock/ingenic-x2500.h + create mode 100644 include/dt-bindings/dma/ingenic-pdma.h + create mode 100644 include/dt-bindings/gpio/ingenic-gpio.h + create mode 100644 include/dt-bindings/interrupt-controller/m300-irq.h + create mode 100644 include/dt-bindings/interrupt-controller/mips-irq.h + create mode 100644 include/dt-bindings/interrupt-controller/x1000-irq.h + create mode 100644 include/dt-bindings/interrupt-controller/x1600-irq.h + create mode 100644 include/dt-bindings/interrupt-controller/x2000-irq.h + create mode 100644 include/dt-bindings/interrupt-controller/x2500-irq.h + create mode 100644 include/dt-bindings/net/ingenic_gmac.h + create mode 100644 include/dt-bindings/pinctrl/ingenic-pinctrl.h + create mode 100644 include/dt-bindings/power/axp216-power.h + create mode 100644 include/dt-bindings/sound/ingenic-baic.h + create mode 100644 include/linux/mfd/ingenic-tcu_v1.h + create mode 100644 include/linux/mfd/ingenic-tcu_v2.h + create mode 100644 include/linux/mfd/ingenic_adc.h + create mode 100644 include/linux/usb/f_mtp.h + create mode 100644 include/media/ingenic_video_nr.h + create mode 100644 include/media/videobuf2-dma-contig-ingenic.h + create mode 100644 include/uapi/linux/usb/f_mtp.h + create mode 100644 include/video/ingenic_logo.h + create mode 100644 module_drivers/Kconfig + create mode 100644 module_drivers/Makefile + create mode 100644 module_drivers/README.zh + create mode 100644 module_drivers/drivers/Kconfig + create mode 100644 module_drivers/drivers/Makefile + create mode 100644 module_drivers/drivers/char/Makefile + create mode 100644 module_drivers/drivers/char/hw_random/Kconfig + create mode 100644 module_drivers/drivers/char/hw_random/Makefile + create mode 100644 module_drivers/drivers/char/hw_random/ingenic-rng.c + create mode 100644 module_drivers/drivers/char/ingenic_cdbus.c + create mode 100644 module_drivers/drivers/clk/Makefile + create mode 100644 module_drivers/drivers/clk/ingenic-v2/Kconfig + create mode 100644 module_drivers/drivers/clk/ingenic-v2/Makefile + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-bus.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-bus.h + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-div.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-div.h + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-m300.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-pll-v1.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-pll-v1.h + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-pll-v2.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-pll-v2.h + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-pll.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-pll.h + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-x1600.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-x2000.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk-x2500.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/clk.h + create mode 100644 module_drivers/drivers/clk/ingenic-v2/power-gate.c + create mode 100644 module_drivers/drivers/clk/ingenic-v2/power-gate.h + create mode 100644 module_drivers/drivers/clocksource/Kconfig + create mode 100644 module_drivers/drivers/clocksource/Makefile + create mode 100644 module_drivers/drivers/clocksource/ingenic_core_ost.c + create mode 100644 module_drivers/drivers/clocksource/ingenic_sysost.c + create mode 100644 module_drivers/drivers/crypto/Kconfig + create mode 100644 module_drivers/drivers/crypto/Makefile + create mode 100644 module_drivers/drivers/crypto/ingenic-aes.c + create mode 100644 module_drivers/drivers/crypto/ingenic-aes.h + create mode 100644 module_drivers/drivers/crypto/ingenic-hash.c + create mode 100644 module_drivers/drivers/crypto/ingenic-hash.h + create mode 100644 module_drivers/drivers/dma/Makefile + create mode 100644 module_drivers/drivers/dma/ingenic/Kconfig + create mode 100644 module_drivers/drivers/dma/ingenic/Makefile + create mode 100644 module_drivers/drivers/dma/ingenic/ingenic_dma.c + create mode 100644 module_drivers/drivers/dma/ingenic/ingenic_dma.h + create mode 100644 module_drivers/drivers/i2c/Makefile + create mode 100644 module_drivers/drivers/i2c/busses/Kconfig + create mode 100644 module_drivers/drivers/i2c/busses/Makefile + create mode 100644 module_drivers/drivers/i2c/busses/i2c-ingenic.c + create mode 100644 module_drivers/drivers/input/Makefile + create mode 100644 module_drivers/drivers/input/touchscreen/Kconfig + create mode 100644 module_drivers/drivers/input/touchscreen/Makefile + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/Kconfig + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/Makefile + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_common.h + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_config.h + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_core.c + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_core.h + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash.c + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash.h + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash/Makefile + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft7511.c + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c + create mode 100644 module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c + create mode 100644 module_drivers/drivers/input/touchscreen/ft6236_touch/Kconfig + create mode 100644 module_drivers/drivers/input/touchscreen/ft6236_touch/Makefile + create mode 100644 module_drivers/drivers/input/touchscreen/ft6236_touch/ft6236_touch.c + create mode 100644 module_drivers/drivers/input/touchscreen/ft6236_touch/ft6236_touch.h + create mode 100644 module_drivers/drivers/input/touchscreen/gt9xx_touch/Kconfig + create mode 100644 module_drivers/drivers/input/touchscreen/gt9xx_touch/Makefile + create mode 100644 module_drivers/drivers/input/touchscreen/gt9xx_touch/goodix.h + create mode 100644 module_drivers/drivers/input/touchscreen/gt9xx_touch/goodix_tool.c + create mode 100644 module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx.c + create mode 100644 module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx.h + create mode 100644 module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx_firmware.h + create mode 100644 module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx_update.c + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update1/hyn_cst3xx_0729_update1ok.c + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update1/hyn_cst3xx_RS659_fw.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_0729_update3_firmware.c + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw_0729_update2.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw_0729_update3.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Kconfig + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Makefile + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/cst3xx.c + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/cst3xx.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/hyn_cst3xx_RS659_fw.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx_1.c + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx_2.c + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/hyn_cst3xx_RS659_fw.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/cst3xx.c + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/cst3xx.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/hyn_cst3xx_RS659_fw_0730_268_800.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/Readme + create mode 100755 module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx.c + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx_RS659_fw.h + create mode 100644 module_drivers/drivers/input/touchscreen/hyn_touch/hyn_i2c.c + create mode 100644 module_drivers/drivers/irqchip/Kconfig + create mode 100644 module_drivers/drivers/irqchip/Makefile + create mode 100644 module_drivers/drivers/irqchip/irq-ingenic-chip.c + create mode 100644 module_drivers/drivers/irqchip/irq-ingenic-cpu.c + create mode 100644 module_drivers/drivers/irqchip/irq-ingenic.c + create mode 100644 module_drivers/drivers/md_export/Makefile + create mode 100644 module_drivers/drivers/md_export/md_export.c + create mode 100644 module_drivers/drivers/media/Makefile + create mode 100644 module_drivers/drivers/media/i2c/Kconfig + create mode 100644 module_drivers/drivers/media/i2c/Makefile + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/Kconfig + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/Makefile + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/ar0144.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/ov2735b.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/ov4689.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/ov5640.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/ov5645.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/ov9281-dvp-snapshot.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/ov9281.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/sc031gs-mipi.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-cim/sc031gs.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp-v2/Kconfig + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp-v2/Makefile + create mode 100755 module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2053.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2093.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2155.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp-v2/imx327.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp-v2/ov2735a.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp-v2/ov4689.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp-v2/ov7251.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp-v2/sc230ai.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp-v2/sc2310.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/Kconfig + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/Makefile + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/ar0144.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/ar0234.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/cisadc.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/gc1054.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/gc2093.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/gm8914_gm8913_gc2093.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/hm2140.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/imx335.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/ov2735a.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/ov2735b.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/ov4689.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/ov6710.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/ov7251.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/sc0132gs.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/sc031gs.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/sc2232h.c + create mode 100644 module_drivers/drivers/media/i2c/ingenic-isp/sc230ai.c + create mode 100644 module_drivers/drivers/media/platform/Kconfig + create mode 100644 module_drivers/drivers/media/platform/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-cim/Kconfig + create mode 100644 module_drivers/drivers/media/platform/ingenic-cim/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-cim/ingenic_camera.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-cim/ingenic_camera.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-cim/mipi_csi.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-cim/mipi_csi.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-i2d/Kconfig + create mode 100644 module_drivers/drivers/media/platform/ingenic-i2d/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-i2d/i2d_video.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-i2d/i2d_video.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-i2d/ingenic_i2d.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-i2d/ingenic_i2d.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/Kconfig + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/csi-regs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/csi.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core-tuning.c + create mode 100755 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/system_sensor_drv.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano-core-ctrl.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano-isp.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano_sys.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/txx-funcs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-drv.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-drv.h + create mode 100755 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-regs-x2000.h + create mode 100755 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-regs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-sensor.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-video-mplane.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp-video.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/isp.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler-bdev.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler-regs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/sensor.c + create mode 100755 module_drivers/drivers/media/platform/ingenic-isp-v2/tx-vic-regs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/vic-regs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp-v2/vic.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/Kconfig + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/csi-regs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/csi.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core-tuning.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/system_sensor_drv.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_core.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_core_tuning.h + create mode 100755 module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_isp.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_netlink.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_priv.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_sys.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core/src/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core/tiziano_netlink.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-core/tiziano_priv.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-drv.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-drv.h + create mode 100755 module_drivers/drivers/media/platform/ingenic-isp/isp-regs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-sensor.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-video-mplane.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp-video.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/isp.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/mscaler-bdev.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/mscaler-regs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/mscaler.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/sensor.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/vic-regs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-isp/vic.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-rotate/Kconfig + create mode 100644 module_drivers/drivers/media/platform/ingenic-rotate/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-rotate/rotate-hw.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-rotate/rotate-regs.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-rotate/rotate.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-rotate/rotate.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/Kconfig + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_drv.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_drv.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_ops.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_ops.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_h264_dec.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_h264_dec.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_vpu.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/avassert.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/avcodec.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/bswap.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/buffer.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/bytestream.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/common.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/devmem.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/error.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/frame.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/get_bits.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/golomb.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h2645_parse.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_parse.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_ps.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_sei.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264data.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264dec.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/intreadwrite.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/list.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/log.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mathops.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mem.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mpegutils.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/put_bits.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/vpu_ops.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/buffer.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/golomb.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h2645_parse.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_direct.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_parse.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_picture.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_ps.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_refs.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_sei.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_slice.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264data.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264dec.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/hexdump.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/log.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/mathtables.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/mem.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/vpu_ops.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/Makefile + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/README + create mode 100755 module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/default_sliceinfo.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_nl.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_nl.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_proto.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/bitstream.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/nal.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/osdep.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_buf.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_drv.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_drv.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_ops.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_ops.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpgd.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpgd.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge.c + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/head.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/ht.h + create mode 100644 module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/qt.h + create mode 100644 module_drivers/drivers/media/v4l2-core/Kconfig + create mode 100644 module_drivers/drivers/media/v4l2-core/Makefile + create mode 100644 module_drivers/drivers/media/v4l2-core/videobuf2-dma-contig-ingenic.c + create mode 100644 module_drivers/drivers/mfd/Kconfig + create mode 100644 module_drivers/drivers/mfd/Makefile + create mode 100644 module_drivers/drivers/mfd/ingenic-tcu.c + create mode 100644 module_drivers/drivers/mfd/ingenic-tcu_v1.c + create mode 100644 module_drivers/drivers/mfd/ingenic_adc_aux.c + create mode 100644 module_drivers/drivers/mfd/ingenic_adc_v13.c + create mode 100644 module_drivers/drivers/mfd/ricoh619-irq.c + create mode 100644 module_drivers/drivers/mfd/ricoh619.c + create mode 100644 module_drivers/drivers/misc/Kconfig + create mode 100644 module_drivers/drivers/misc/Makefile + create mode 100644 module_drivers/drivers/misc/bt_power_bluesleep.c + create mode 100644 module_drivers/drivers/misc/hamming.c + create mode 100644 module_drivers/drivers/misc/ingenic_efuse_v2.c + create mode 100644 module_drivers/drivers/misc/ingenic_efuse_x2000.c + create mode 100644 module_drivers/drivers/misc/ingenic_rsa.c + create mode 100644 module_drivers/drivers/mmc/Makefile + create mode 100644 module_drivers/drivers/mmc/host/Kconfig + create mode 100644 module_drivers/drivers/mmc/host/Makefile + create mode 100644 module_drivers/drivers/mmc/host/ingenic_mmc.c + create mode 100644 module_drivers/drivers/mmc/host/ingenic_mmc.h + create mode 100644 module_drivers/drivers/mmc/host/ingenic_mmc_reg.h + create mode 100644 module_drivers/drivers/mmc/host/ingenic_sdio.c + create mode 100644 module_drivers/drivers/mmc/host/sdhci-ingenic.c + create mode 100644 module_drivers/drivers/mmc/host/sdhci-ingenic.h + create mode 100644 module_drivers/drivers/mtd/Makefile + create mode 100644 module_drivers/drivers/mtd/devices/Kconfig + create mode 100644 module_drivers/drivers/mtd/devices/Makefile + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/Makefile + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/fmw.h + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.h + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_drv.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_drv.h + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nor.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_ops.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/Makefile + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/ato_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/dosilicon_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/fm_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/foresee_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/gd_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/issi_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/mxic_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.h + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/toshiba_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xcsp_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid0b_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid2c_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/yhy_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/zetta_nand.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/Makefile + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/nor_device.c + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/nor_device.h + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/sfc.h + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/sfc_flash.h + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinand.h + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinand_cmd.h + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinor.h + create mode 100644 module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinor_cmd.h + create mode 100644 module_drivers/drivers/net/Makefile + create mode 100644 module_drivers/drivers/net/ethernet/Makefile + create mode 100644 module_drivers/drivers/net/ethernet/ingenic/Kconfig + create mode 100644 module_drivers/drivers/net/ethernet/ingenic/Makefile + create mode 100644 module_drivers/drivers/net/ethernet/ingenic/ethtool.c + create mode 100644 module_drivers/drivers/net/ethernet/ingenic/ingenic_mac.c + create mode 100644 module_drivers/drivers/net/ethernet/ingenic/ingenic_mac.h + create mode 100644 module_drivers/drivers/net/ethernet/ingenic/readme + create mode 100644 module_drivers/drivers/net/ethernet/ingenic/synopGMAC_Dev.c + create mode 100644 module_drivers/drivers/net/ethernet/ingenic/synopGMAC_Dev.h + create mode 100644 module_drivers/drivers/net/ethernet/ingenic/synopGMAC_plat.c + create mode 100644 module_drivers/drivers/net/ethernet/ingenic/synopGMAC_plat.h + create mode 100644 module_drivers/drivers/net/wireless/Kconfig + create mode 100644 module_drivers/drivers/net/wireless/Makefile + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/Kconfig + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/Makefile + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/README + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/aiutils.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcm_app_utils.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmevent.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmsdh.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmspibrcm.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmutils.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_channels.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_channels.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_rates.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/bcmxtlv.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dbus.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dbus_usb.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dbus_usb_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_bus.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_buzzz.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_ccode.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_cdc.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_cfg80211.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_cfg80211.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_common.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_config.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_config.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_memprealloc.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_msm.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_dbg.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_debug.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_debug.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_debug_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_flowring.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_flowring.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_gpio.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_ip.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_ip.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_linux.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_sched.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_wq.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_wq.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_mschdbg.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_mschdbg.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_msgbuf.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_pno.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_pno.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_proto.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_rtt.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_rtt.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_static_buf.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_wlfc.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dhd_wlfc.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dngl_stats.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/dngl_wlhdr.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/hnd_pktpool.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/hnd_pktq.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/hndpmu.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/802.11.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/802.11e.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/802.11s.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/802.1d.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/802.3.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/aidmp.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcm_cfg.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcm_ring.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmcdc.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmdefs.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmdevs.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmdhcp.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmendian.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmeth.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmevent.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmip.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmipv6.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmnvram.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmpcie.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmpcispi.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmperf.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdbus.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdh.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdspi.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdstd.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmspi.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmtcp.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmudp.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/bcmutils.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/dbus.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/dhd_daemon.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/dhdioctl.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/dnglevent.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/eapol.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/epivers.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/ethernet.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/event_log.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/event_log_payload.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/event_log_set.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/event_log_tag.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/event_trace.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/hnd_armtrap.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/hnd_cons.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/hnd_debug.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/hnd_pktpool.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/hnd_pktq.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/hndpmu.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/hndsoc.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/linux_osl.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/linuxver.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/miniopt.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/msgtrace.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/nan.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/osl.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/osl_decl.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/osl_ext.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/p2p.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/packed_section_end.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/packed_section_start.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/pcicfg.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/pcie_core.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/rte_ioctl.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sbchipc.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sbconfig.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sbgci.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sbhnddma.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sbpcmcia.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sbsdio.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sbsocram.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sbsysmem.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sdio.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sdioh.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sdiovar.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/sdspi.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/siutils.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/spid.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/trxhdr.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/typedefs.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/usbrdl.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/vlan.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/wlfc_proto.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl_defs.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl_utils.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/wpa.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/include/wps.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/linux_osl.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/pcie_core.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/sbutils.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/siutils.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/siutils_priv.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_android.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_android.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_android_ext.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_cfg80211.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_cfg80211.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_cfgnan.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_cfgnan.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_cfgp2p.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_cfgp2p.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_cfgvendor.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_cfgvendor.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_dbg.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_escan.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_escan.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_event.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_iw.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_iw.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_linux_mon.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wl_roam.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wlc_types.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wldev_common.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd/wldev_common.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/Kconfig + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/Makefile + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/aiutils.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcm_app_utils.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmevent.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmsdh.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmsdh_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmsdh_sdmmc.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmsdh_sdmmc_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmsdspi_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmspibrcm.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmutils.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmwifi_channels.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmwifi_channels.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmwifi_rates.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/bcmxtlv.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dbus.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dbus_usb.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dbus_usb_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_bta.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_bta.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_bus.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_buzzz.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_cdc.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_cfg80211.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_cfg80211.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_cfg_vendor.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_chip_info.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_chip_info.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_common.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_custom_gpio.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_dbg.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_debug.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_debug.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_debug_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_flowring.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_flowring.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_ip.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_ip.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_linux.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_linux_platdev.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_linux_sched.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_linux_wq.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_linux_wq.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_msgbuf.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_pcie.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_pcie.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_pcie_linux.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_pno.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_pno.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_proto.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_rtt.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_rtt.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_wlfc.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dhd_wlfc.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dngl_stats.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/dngl_wlhdr.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/hnd_pktpool.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/hnd_pktq.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/hndpmu.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/linux_osl.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/pcie_core.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/sbutils.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/siutils.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/siutils_priv.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/uamp_api.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_android.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_android.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_cfg80211.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_cfg80211.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_cfg_btcoex.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_cfgnan.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_cfgnan.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_cfgp2p.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_cfgp2p.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_cfgvendor.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_cfgvendor.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_dbg.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_iw.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_iw.h + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_linux_mon.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wl_roam.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wldev_common.c + create mode 100644 module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/wldev_common.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/Makefile + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/Kconfig + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/Makefile + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/clean + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes-ccm.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes-ctr.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes-gcm.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes-internal-enc.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes-internal.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes-omac1.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes-siv.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes_i.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes_siv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/aes_wrap.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/ccmp.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/gcmp.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/rtw_crypto_wrap.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/rtw_crypto_wrap.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/sha256-internal.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/sha256-prf.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/sha256.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/sha256.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/sha256_i.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/crypto/wlancrypto_wrap.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/efuse/rtw_efuse.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/mesh/rtw_mesh.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/mesh/rtw_mesh.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/mesh/rtw_mesh_hwmp.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/mesh/rtw_mesh_hwmp.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/mesh/rtw_mesh_pathtbl.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/mesh/rtw_mesh_pathtbl.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/monitor/rtw_radiotap.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/monitor/rtw_radiotap.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_ap.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_beamforming.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_br_ext.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_bt_mp.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_btcoex.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_btcoex_wifionly.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_chplan.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_chplan.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_cmd.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_debug.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_eeprom.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_ft.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_ieee80211.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_io.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_ioctl_query.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_ioctl_set.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_iol.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_mbo.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_mem.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_mi.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_mlme.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_mlme_ext.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_mp.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_odm.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_p2p.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_pwrctrl.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_recv.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_rf.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_rm.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_rm_fsm.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_rm_util.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_rson.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_security.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_sreset.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_sta_mgt.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_swcrypto.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_tdls.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_vht.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_wapi.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_wapi_sms4.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_wlan_util.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_wnm.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/rtw_xmit.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/wds/rtw_wds.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/core/wds/rtw_wds.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/HalPwrSeqCmd.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/btc/btc_basic_types.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/btc/halbtc8723d1ant.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/btc/halbtc8723d1ant.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/btc/halbtc8723d2ant.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/btc/halbtc8723d2ant.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/btc/halbtcoutsrc.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/btc/mp_precomp.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/efuse/efuse_mask.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/efuse/rtl8723d/HalEfuseMask8723D_PCIE.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/efuse/rtl8723d/HalEfuseMask8723D_PCIE.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/efuse/rtl8723d/HalEfuseMask8723D_SDIO.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/efuse/rtl8723d/HalEfuseMask8723D_SDIO.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/efuse/rtl8723d/HalEfuseMask8723D_USB.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/efuse/rtl8723d/HalEfuseMask8723D_USB.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_btcoex.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_btcoex_wifionly.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_com.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_com_c2h.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_com_phycfg.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_dm.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_dm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_dm_acs.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_dm_acs.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_halmac.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_halmac.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_hci/hal_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_hci/hal_sdio_coex.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_intf.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_mcc.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_mp.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/hal_phy.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/led/hal_led.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/led/hal_sdio_led.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/ap_makefile.mk + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halhwimg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halphyrf_ap.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halphyrf_ap.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halphyrf_ce.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halphyrf_ce.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halphyrf_iot.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halphyrf_iot.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halphyrf_win.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halphyrf_win.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_debug.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_debug.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_dpk.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_features.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_iqk.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_kfree.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_kfree.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_powertracking.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_powertracking.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_powertracking_ap.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_powertracking_ap.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_powertracking_ce.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_powertracking_ce.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_powertracking_iot.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_powertracking_iot.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_powertracking_win.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_powertracking_win.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_psd.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_psd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_txgapcal.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/halrf_txgapcal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/rtl8723d/halrf_8723d.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/halrf/rtl8723d/halrf_8723d.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/mp_precomp.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm.mk + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_adaptivity.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_adaptivity.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_adc_sampling.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_adc_sampling.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_antdect.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_antdect.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_antdiv.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_antdiv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_api.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_api.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_auto_dbg.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_auto_dbg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_beamforming.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_beamforming.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_cck_pd.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_cck_pd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_cck_rx_pathdiv.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_cck_rx_pathdiv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_ccx.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_ccx.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_cfotracking.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_cfotracking.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_debug.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_debug.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_dfs.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_dfs.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_dig.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_dig.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_direct_bf.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_direct_bf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_dynamictxpower.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_dynamictxpower.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_features.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_features_ap.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_features_ce.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_features_ce2_kernel.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_features_iot.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_features_win.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_hwconfig.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_hwconfig.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_interface.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_interface.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_lna_sat.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_lna_sat.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_math_lib.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_math_lib.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_mp.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_mp.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_noisemonitor.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_noisemonitor.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_pathdiv.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_pathdiv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_phystatus.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_phystatus.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_pmac_tx_setting.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_pmac_tx_setting.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_pow_train.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_pow_train.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_pre_define.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_precomp.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_primary_cca.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_primary_cca.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_psd.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_psd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_rainfo.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_rainfo.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_reg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_regdefine11ac.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_regdefine11n.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_regtable.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_rssi_monitor.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_rssi_monitor.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_smt_ant.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_smt_ant.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_soml.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_soml.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/phydm_types.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/hal8723dreg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/halhwimg8723d_bb.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/halhwimg8723d_bb.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/halhwimg8723d_mac.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/halhwimg8723d_mac.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/halhwimg8723d_rf.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/halhwimg8723d_rf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/phydm_regconfig8723d.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/phydm_regconfig8723d.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/phydm_rtl8723d.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/phydm_rtl8723d.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/rtl8723d/version_rtl8723d.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/sd4_phydm_2_kernel.mk + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/halcomtxbf.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/halcomtxbf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/haltxbf8192e.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/haltxbf8192e.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/haltxbf8814a.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/haltxbf8814a.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/haltxbf8822b.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/haltxbf8822b.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/haltxbfinterface.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/haltxbfinterface.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/haltxbfjaguar.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/haltxbfjaguar.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/phydm_hal_txbf_api.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/phydm/txbf/phydm_hal_txbf_api.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/Hal8723DPwrSeq.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/hal8723d_fw.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/hal8723d_fw.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/rtl8723d_cmd.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/rtl8723d_dm.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/rtl8723d_hal_init.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/rtl8723d_lps_poff.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/rtl8723d_phycfg.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/rtl8723d_rf6052.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/rtl8723d_rxdesc.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/rtl8723d_sreset.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/sdio/rtl8723ds_led.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/sdio/rtl8723ds_recv.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/sdio/rtl8723ds_xmit.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/sdio/sdio_halinit.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/hal/rtl8723d/sdio/sdio_ops.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/ifcfg-wlan0 + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8188EPhyCfg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8188EPhyReg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8188EPwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8188FPhyCfg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8188FPhyReg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8188FPwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8192EPhyCfg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8192EPhyReg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8192EPwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8192FPhyCfg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8192FPhyReg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8192FPwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8703BPhyCfg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8703BPhyReg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8703BPwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8710BPhyCfg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8710BPhyReg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8710BPwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8723BPhyCfg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8723BPhyReg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8723BPwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8723DPhyCfg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8723DPhyReg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8723DPwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8723PwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8812PhyCfg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8812PhyReg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8812PwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8814PhyCfg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8814PhyReg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8814PwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/Hal8821APwrSeq.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/HalPwrSeqCmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/HalVerDef.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/autoconf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/basic_types.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/byteorder/big_endian.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/byteorder/generic.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/byteorder/little_endian.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/byteorder/swab.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/byteorder/swabb.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/circ_buf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/cmd_osdep.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/cmn_info/rtw_sta_info.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/custom_gpio.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/drv_conf.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/drv_types.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/drv_types_ce.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/drv_types_gspi.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/drv_types_linux.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/drv_types_pci.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/drv_types_sdio.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/drv_types_xp.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/ethernet.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/gspi_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/gspi_ops.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/gspi_ops_linux.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/gspi_osintf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/h2clbk.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_btcoex.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_btcoex_wifionly.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_com.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_com_h2c.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_com_led.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_com_phycfg.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_com_reg.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_data.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_gspi.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_ic_cfg.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_intf.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_pg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_phy.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_phy_reg.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_sdio.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/hal_sdio_coex.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/ieee80211.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/ieee80211_ext.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/if_ether.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/ip.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/linux/wireless.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/mlme_osdep.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/nic_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/osdep_intf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/osdep_service.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/osdep_service_bsd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/osdep_service_ce.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/osdep_service_linux.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/osdep_service_xp.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/pci_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/pci_ops.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/pci_osintf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/recv_osdep.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188e_cmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188e_dm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188e_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188e_led.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188e_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188e_rf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188e_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188e_sreset.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188e_xmit.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188f_cmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188f_dm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188f_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188f_led.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188f_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188f_rf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188f_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188f_sreset.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8188f_xmit.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192e_cmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192e_dm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192e_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192e_led.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192e_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192e_rf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192e_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192e_sreset.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192e_xmit.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192f_cmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192f_dm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192f_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192f_led.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192f_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192f_rf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192f_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192f_sreset.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8192f_xmit.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8703b_cmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8703b_dm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8703b_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8703b_led.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8703b_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8703b_rf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8703b_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8703b_sreset.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8703b_xmit.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8710b_cmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8710b_dm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8710b_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8710b_led.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8710b_lps_poff.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8710b_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8710b_rf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8710b_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8710b_sreset.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8710b_xmit.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723b_cmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723b_dm.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723b_hal.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723b_led.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723b_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723b_rf.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723b_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723b_sreset.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723b_xmit.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723d_cmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723d_dm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723d_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723d_led.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723d_lps_poff.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723d_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723d_rf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723d_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723d_sreset.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8723d_xmit.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8812a_cmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8812a_dm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8812a_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8812a_led.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8812a_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8812a_rf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8812a_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8812a_sreset.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8812a_xmit.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814a_cmd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814a_dm.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814a_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814a_led.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814a_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814a_rf.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814a_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814a_sreset.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814a_xmit.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814b_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814be_hal.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8814bu_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8821a_spec.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8821a_xmit.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8821c_dm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8821c_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8821c_spec.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8821ce_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8821cs_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8821cu_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8822b_hal.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8822be_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8822bs_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8822bu_hal.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8822c_hal.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8822ce_hal.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8822cs_hal.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtl8822cu_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_android.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_ap.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_beamforming.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_br_ext.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_bt_mp.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_btcoex.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_btcoex_wifionly.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_byteorder.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_cmd.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_debug.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_eeprom.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_efuse.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_event.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_ft.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_ht.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_io.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_ioctl.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_ioctl_query.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_ioctl_set.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_iol.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_mbo.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_mcc.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_mem.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_mi.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_mlme.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_mlme_ext.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_mp.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_mp_phy_regdef.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_odm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_p2p.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_pwrctrl.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_qos.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_recv.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_rf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_rm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_rm_fsm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_rm_util.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_rson.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_sdio.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_security.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_sreset.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_swcrypto.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_tdls.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_version.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_vht.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_wapi.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_wnm.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/rtw_xmit.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/sdio_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/sdio_ops.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/sdio_ops_ce.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/sdio_ops_linux.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/sdio_ops_xp.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/sdio_osintf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/sta_info.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/usb_hal.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/usb_ops.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/usb_ops_linux.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/usb_osintf.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/usb_vendor_req.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/wifi.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/wlan_bssdef.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/include/xmit_osdep.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/custom_gpio_linux.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/ioctl_cfg80211.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/ioctl_cfg80211.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/ioctl_linux.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/ioctl_mp.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/mlme_linux.c + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/os_intfs.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/recv_linux.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/rhashtable.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/rhashtable.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/rtw_android.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/rtw_cfgvendor.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/rtw_cfgvendor.h + create mode 100755 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/rtw_proc.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/rtw_proc.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/rtw_rhashtable.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/rtw_rhashtable.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/sdio_intf.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/sdio_ops_linux.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/wifi_regd.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/wifi_regd.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/linux/xmit_linux.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/os_dep/osdep_service.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/custom_country_chplan.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_ARM_SUN50IW1P1_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_ARM_SUNnI_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_ARM_SUNxI_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_ARM_SUNxI_usb.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_ARM_WMT_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_RTK_DMP_usb.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_aml_s905_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_aml_s905_sdio.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_arm_act_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_hisilicon_hi3798_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_hisilicon_hi3798_sdio.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_ops.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_ops.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_sprd_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_zte_zx296716_sdio.c + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/platform/platform_zte_zx296716_sdio.h + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/runwpa + create mode 100644 module_drivers/drivers/net/wireless/realtek/rtl8723ds/wlan0dhcp + create mode 100644 module_drivers/drivers/pinctrl/Kconfig + create mode 100644 module_drivers/drivers/pinctrl/Makefile + create mode 100644 module_drivers/drivers/pinctrl/multi-vgpio.c + create mode 100644 module_drivers/drivers/pinctrl/pinctrl-ingenic.c + create mode 100644 module_drivers/drivers/pinctrl/pinctrl-ingenic.h + create mode 100644 module_drivers/drivers/power/Makefile + create mode 100644 module_drivers/drivers/power/supply/Makefile + create mode 100644 module_drivers/drivers/power/supply/axp_power/Kconfig + create mode 100644 module_drivers/drivers/power/supply/axp_power/Makefile + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-board.c + create mode 100755 module_drivers/drivers/power/supply/axp_power/axp-cfg.h + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-filenode.c + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-gpio.c + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-gpio.h + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-mfd-216.h + create mode 100755 module_drivers/drivers/power/supply/axp_power/axp-mfd.c + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-mfd.h + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-regu.c + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-regu.h + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-rw.c + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-rw.h + create mode 100755 module_drivers/drivers/power/supply/axp_power/axp-sply.c + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-sply.h + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp-state.c + create mode 100644 module_drivers/drivers/power/supply/axp_power/axp216-mfd.h + create mode 100644 module_drivers/drivers/power/supply/axp_power/virtual216.c + create mode 100644 module_drivers/drivers/power/supply/axp_power/virtual216_dev.c + create mode 100644 module_drivers/drivers/pwm/Kconfig + create mode 100644 module_drivers/drivers/pwm/Makefile + create mode 100644 module_drivers/drivers/pwm/pwm-ingenic-v2.c + create mode 100644 module_drivers/drivers/pwm/pwm-ingenic-v3.c + create mode 100644 module_drivers/drivers/pwm/pwm-ingenic.c + create mode 100644 module_drivers/drivers/rtc/Kconfig + create mode 100644 module_drivers/drivers/rtc/Makefile + create mode 100644 module_drivers/drivers/rtc/rtc-ingenic.c + create mode 100644 module_drivers/drivers/rtc/rtc-ingenic.h + create mode 100644 module_drivers/drivers/spi/Kconfig + create mode 100644 module_drivers/drivers/spi/Makefile + create mode 100755 module_drivers/drivers/spi/ingenic_slv.c + create mode 100644 module_drivers/drivers/spi/ingenic_slv.h + create mode 100755 module_drivers/drivers/spi/ingenic_spi.c + create mode 100755 module_drivers/drivers/spi/ingenic_spi.h + create mode 100644 module_drivers/drivers/tty/Makefile + create mode 100644 module_drivers/drivers/tty/serial/Kconfig + create mode 100644 module_drivers/drivers/tty/serial/Makefile + create mode 100644 module_drivers/drivers/tty/serial/ingenic_uart.c + create mode 100644 module_drivers/drivers/tty/serial/ingenic_uart.h + create mode 100644 module_drivers/drivers/video/Makefile + create mode 100644 module_drivers/drivers/video/fbdev/Makefile + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/Kconfig + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/Makefile + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/Kconfig + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/Makefile + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/README.md + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/Kconfig + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/Makefile + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/jd9365/JD9365_8001280init-4lane.txt + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/jd9365/panel-jd9365.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/jd9365d/C_JD9365D_800x1280_FP7721BX2_Column_G2.2_190613_Nolan.txt + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/jd9365d/panel-jd9365d.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/lt9211.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/lt9211.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-G104X1L04.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-MV238FHM-N30.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-atk7016.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-bm8766.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-ek79007ad.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-fw035.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-fw040.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-fw050.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-gc9203.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-gwmtf16499b.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-jd9161z.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-jd9366.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-kd035hvfbd037.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-kd035hvfmd057.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-kd050hdfia019.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-kd050hdfia020.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-kd050wvfpa029.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-ma0060.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-st7282.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-st7701s-rgb666.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-st7701s.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-tl040hds01ct.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-tl040wvs03ct.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-y88249.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-ylym286a.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-yts500xlai.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/st7701s_dx3.95ips/ST7701S_DX3.95IPS_mipi_480x480_V1.0-RGB.txt + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/st7701s_dx3.95ips/panel-st7701sdx.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/dpu_ctrl.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/dpu_ctrl.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/dpu_dma_desc.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/dpu_reg.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/hw_composer.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/hw_composer.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/hw_composer_fb.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/hw_composer_fb.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/hw_composer_v4l2.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/hw_composer_v4l2.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/ingenicfb.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/ingenicfb.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/jz_dsim.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/jz_mipi_dsi/Makefile + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/jz_mipi_dsi/jz_mipi_dsi.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/jz_mipi_dsi/jz_mipi_dsi_lowlevel.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/jz_mipi_dsi/jz_mipi_dsi_lowlevel.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/jz_mipi_dsi/jz_mipi_dsi_regs.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/jz_mipi_dsi/jz_mipi_dsih_hal.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/jz_mipi_dsi/jz_mipi_dsih_hal.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/lcd_panel.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/sysfs.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/sysfs.h + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/todo/colorbar.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/todo/sysfs.c + create mode 100644 module_drivers/drivers/video/fbdev/ingenic/fb_stage/uapi_ingenicfb.h + create mode 100644 module_drivers/drivers/video/ingenic-nna/Kconfig + create mode 100644 module_drivers/drivers/video/ingenic-nna/Makefile + create mode 100644 module_drivers/drivers/video/ingenic-nna/mpsys-firmware/Makefile + create mode 100755 module_drivers/drivers/video/ingenic-nna/mpsys-firmware/mpsys-funcs.c + create mode 100755 module_drivers/drivers/video/ingenic-nna/mpsys-firmware/mpsys-funcs.h + create mode 100755 module_drivers/drivers/video/ingenic-nna/mpsys-firmware/mpsys_module.c + create mode 100644 module_drivers/drivers/video/ingenic-nna/soc_nna.c + create mode 100644 module_drivers/drivers/video/ingenic-nna/soc_nna.h + create mode 100644 module_drivers/drivers/video/ingenic-nna/soc_nna_common.h + create mode 100644 module_drivers/drivers/video/ingenic-nna/soc_nna_hw.h + create mode 100644 module_drivers/drivers/video/ingenic_avpu/Kconfig + create mode 100644 module_drivers/drivers/video/ingenic_avpu/Makefile + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_alloc.c + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_alloc.h + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_alloc_ioctl.c + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_alloc_ioctl.h + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_dmabuf.c + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_dmabuf.h + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_ioctl.h + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_ip.c + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_ip.h + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_main.c + create mode 100644 module_drivers/drivers/video/ingenic_avpu/avpu_no_dmabuf.c + create mode 100644 module_drivers/drivers/video/ingenic_bscaler/Kconfig + create mode 100644 module_drivers/drivers/video/ingenic_bscaler/Makefile + create mode 100644 module_drivers/drivers/video/ingenic_bscaler/ingenic_bscaler.c + create mode 100644 module_drivers/drivers/video/ingenic_ipu/Kconfig + create mode 100644 module_drivers/drivers/video/ingenic_ipu/Makefile + create mode 100644 module_drivers/drivers/video/ingenic_ipu/ingenic_drawbox.c + create mode 100644 module_drivers/drivers/video/ingenic_ipu/ingenic_drawbox.h + create mode 100644 module_drivers/drivers/video/ingenic_ipu/ingenic_ipu_v13.c + create mode 100644 module_drivers/drivers/video/ingenic_ipu/ingenic_ipu_v13.h + create mode 100644 module_drivers/drivers/video/ingenic_ipu/ingenic_regs_v13.h + create mode 100644 module_drivers/drivers/video/ingenic_ipu/ipu_dmabuf.c + create mode 100644 module_drivers/drivers/video/ingenic_ipu/ipu_dmabuf.h + create mode 100644 module_drivers/drivers/video/logo-ingenic/.gitignore + create mode 100644 module_drivers/drivers/video/logo-ingenic/Kconfig + create mode 100644 module_drivers/drivers/video/logo-ingenic/Makefile + create mode 100644 module_drivers/drivers/video/logo-ingenic/logo.c + create mode 100644 module_drivers/drivers/video/logo-ingenic/showlogo.c + create mode 100644 module_drivers/drivers/watchdog/Kconfig + create mode 100644 module_drivers/drivers/watchdog/Makefile + create mode 100644 module_drivers/drivers/watchdog/ingenic_wdt.c + create mode 100644 module_drivers/drivers/watchdog/ingenic_wdt.h + create mode 100644 module_drivers/drivers/watchdog/ingenic_wdt_v1.c + create mode 100644 module_drivers/drivers/watchdog/sgm820_wdt.c + create mode 100644 module_drivers/dts/Makefile + create mode 100644 module_drivers/dts/halley5_cameras/RD_X2000_HALLEY5_CAMERA_2V1.dtsi + create mode 100644 module_drivers/dts/halley5_cameras/RD_X2000_HALLEY5_CAMERA_3V2.dtsi + create mode 100644 module_drivers/dts/halley5_cameras/RD_X2000_HALLEY5_CAMERA_3V2_4LANE.dtsi + create mode 100644 module_drivers/dts/halley5_cameras/RD_X2000_HALLEY5_CAMERA_4V2.dtsi + create mode 100644 module_drivers/dts/halley5_cameras/RD_X2000_HALLEY5_CAMERA_4V3.dtsi + create mode 100644 module_drivers/dts/halley5_cameras/RD_X2000_HALLEY5_CAMERA_4V3_2KALE.dtsi + create mode 100644 module_drivers/dts/halley5_cameras/RD_X2000_HALLEY5_CAMERA_5V0.dtsi + create mode 100644 module_drivers/dts/halley5_cameras/RD_X2000_HALLEY5_CAMERA_cim.dtsi + create mode 100644 module_drivers/dts/halley5_v20.dts + create mode 100644 module_drivers/dts/halley5_v30.dts + create mode 100644 module_drivers/dts/halley6_cameras/RD_X1600_HALLEY6_DVP_CAMERA.dtsi + create mode 100644 module_drivers/dts/halley6_cameras/RD_X1600_HALLEY6_MIPI_CAMERA.dtsi + create mode 100644 module_drivers/dts/halley6_lcd/RD_X1600_HALLEY6_RGB_LCD_1V0.dtsi + create mode 100644 module_drivers/dts/halley6_lcd/RD_X1600_HALLEY6_RGB_SLCD_1V0.dtsi + create mode 100644 module_drivers/dts/halley6_lcd/RD_X1600_HALLEY6_RGB_SPI_LCD_1V0.dtsi + create mode 100644 module_drivers/dts/halley6_v10.dts + create mode 100644 module_drivers/dts/halley6_v20.dts + create mode 100644 module_drivers/dts/hippo_cameras/RD_X2000_HALLEY5_CAMERA_3V2.dtsi + create mode 100644 module_drivers/dts/hippo_cameras/RD_X2000_HALLEY5_CAMERA_4V3.dtsi + create mode 100644 module_drivers/dts/hippo_cameras/RD_X2500_HIPPO_CAMERA_1V0.dtsi + create mode 100644 module_drivers/dts/hippo_cameras/RD_X2500_HIPPO_CAMERA_1V1.dtsi + create mode 100644 module_drivers/dts/hippo_cameras/ov2735a.dtsi + create mode 100644 module_drivers/dts/hippo_v10.dts + create mode 100644 module_drivers/dts/hippo_v12.dts + create mode 100644 module_drivers/dts/kale_v10.dts + create mode 100644 module_drivers/dts/m300-pinctrl.dtsi + create mode 100644 module_drivers/dts/panda_cameras/RD_X1600_PANDA_CAMERA_3V2.dtsi + create mode 100644 module_drivers/dts/panda_cameras/RD_X1600_PANDA_DVP_CAMERA_1V0.dtsi + create mode 100644 module_drivers/dts/panda_cameras/RD_X1600_PANDA_DVP_CAMERA_2V0.dtsi + create mode 100644 module_drivers/dts/panda_cameras/RD_X1600_PANDA_DVP_CAMERA_AND_LCD_1V0.dtsi + create mode 100644 module_drivers/dts/panda_cameras/RD_X1600_PANDA_MIPI_CAMERA_1V0.dtsi + create mode 100644 module_drivers/dts/panda_cameras/RD_X1600_PANDA_MIPI_CAMERA_2V0.dtsi + create mode 100644 module_drivers/dts/panda_lcd/RD_X1600_IRIS_RGB_LCD_1V0.dtsi + create mode 100644 module_drivers/dts/panda_lcd/RD_X1600_PANDA_LCD_AND_DVP_CAMERA_1V0_KD037.dtsi + create mode 100644 module_drivers/dts/panda_lcd/RD_X1600_PANDA_LCD_AND_DVP_CAMERA_1V0_KD057.dtsi + create mode 100644 module_drivers/dts/panda_lcd/RD_X1600_PANDA_RGB_LCD_1V0.dtsi + create mode 100644 module_drivers/dts/panda_lcd/RD_X1600_PANDA_SPI_LCD_1V0.dtsi + create mode 100644 module_drivers/dts/panda_v10.dts + create mode 100644 module_drivers/dts/viomi_v2000.dts + create mode 100644 module_drivers/dts/x1600-pinctrl.dtsi + create mode 100644 module_drivers/dts/x1600.dtsi + create mode 100644 module_drivers/dts/x1600_module_base.dts + create mode 100644 module_drivers/dts/x2000-pinctrl.dtsi + create mode 100644 module_drivers/dts/x2000.dtsi + create mode 100644 module_drivers/dts/x2000_lifesmart_480p_harmony.dts + create mode 100644 module_drivers/dts/x2000_module_base.dts + create mode 100644 module_drivers/dts/x2500-pinctrl.dtsi + create mode 100644 module_drivers/dts/x2500.dtsi + create mode 100644 module_drivers/sound/Makefile + create mode 100644 module_drivers/sound/soc/Makefile + create mode 100644 module_drivers/sound/soc/ingenic/Kconfig + create mode 100644 module_drivers/sound/soc/ingenic/Makefile + create mode 100644 module_drivers/sound/soc/ingenic/README + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/Makefile + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-aic.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-aic.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-dma.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-dma.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-dmic.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-dmic.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-i2s-tloop.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-i2s.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-pcm.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-pcm.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/asoc-spdif.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v1/assert.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/Makefile + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-baic.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-baic.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-dma.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-dma.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-dmic.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-dmic.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-dsp.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-dsp.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-fmtcov.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-fmtcov.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-mixer.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-mixer.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-spdif.c + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-spdif.h + create mode 100644 module_drivers/sound/soc/ingenic/as-v2/as-vir-fe.c + create mode 100644 module_drivers/sound/soc/ingenic/boards/Makefile + create mode 100644 module_drivers/sound/soc/ingenic/boards/gewu.c + create mode 100644 module_drivers/sound/soc/ingenic/boards/halley5_v20.c + create mode 100644 module_drivers/sound/soc/ingenic/boards/halley6.c + create mode 100644 module_drivers/sound/soc/ingenic/boards/hippo-board.c + create mode 100644 module_drivers/sound/soc/ingenic/boards/kale_v10.c + create mode 100644 module_drivers/sound/soc/ingenic/boards/panda.c + create mode 100644 module_drivers/sound/soc/ingenic/ecodec/Kconfig + create mode 100644 module_drivers/sound/soc/ingenic/ecodec/Makefile + create mode 100644 module_drivers/sound/soc/ingenic/ecodec/ak4458.c + create mode 100644 module_drivers/sound/soc/ingenic/ecodec/ak4458.h + create mode 100644 module_drivers/sound/soc/ingenic/ecodec/ak5558.c + create mode 100644 module_drivers/sound/soc/ingenic/ecodec/ak5558.h + create mode 100644 module_drivers/sound/soc/ingenic/ecodec/nau8822.c + create mode 100644 module_drivers/sound/soc/ingenic/ecodec/nau8822.h + create mode 100644 module_drivers/sound/soc/ingenic/ecodec/wm8594.c + create mode 100644 module_drivers/sound/soc/ingenic/ecodec/wm8594.h + create mode 100644 module_drivers/sound/soc/ingenic/icodec/Makefile + create mode 100644 module_drivers/sound/soc/ingenic/icodec/dump.c + create mode 100644 module_drivers/sound/soc/ingenic/icodec/icdc_d3.c + create mode 100644 module_drivers/sound/soc/ingenic/icodec/icdc_d3.h + create mode 100644 module_drivers/sound/soc/ingenic/icodec/icdc_inno.c + create mode 100644 module_drivers/sound/soc/ingenic/icodec/icdc_inno_v2.c + create mode 100644 scripts/pic2logo-include/stb_image/stb_image.h + create mode 100644 scripts/pic2logo-include/stb_image/stb_image_resize.h + create mode 100644 scripts/pic2logo-include/stb_image/stb_image_write.h + create mode 100644 scripts/pic2logo.c + +diff --git a/Kconfig b/Kconfig +index ce7229470..ad919057a 100644 +--- a/Kconfig ++++ b/Kconfig +@@ -31,4 +31,6 @@ source "lib/Kconfig.debug" + + source "Documentation/Kconfig" + ++source "module_drivers/Kconfig" ++ + source "vendor/Kconfig" +diff --git a/Makefile b/Makefile +index b51f00f84..d164e2902 100644 +--- a/Makefile ++++ b/Makefile +@@ -655,6 +655,8 @@ drivers-y += net/ virt/ + libs-y := lib/ + vendor-$(CONFIG_OHOS_VENDOR) := vendor/ + endif # KBUILD_EXTMOD ++ ++drivers-y += module_drivers/ + + # The all: target is the default when no target is given on the + # command line. +@@ -1393,7 +1395,7 @@ kselftest-merge: + # Devicetree files + + ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/boot/dts/),) +-dtstree := arch/$(SRCARCH)/boot/dts ++dtstree := module_drivers/dts + endif + + ifneq ($(dtstree),) +diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms +index 5483e38b5..985c11af7 100644 +--- a/arch/mips/Kbuild.platforms ++++ b/arch/mips/Kbuild.platforms +@@ -36,6 +36,8 @@ platform-$(CONFIG_SNI_RM) += sni/ + platform-$(CONFIG_MACH_TX39XX) += txx9/ + platform-$(CONFIG_MACH_TX49XX) += txx9/ + platform-$(CONFIG_MACH_VR41XX) += vr41xx/ ++platform-$(CONFIG_MACH_XBURST) += xburst/ ++platform-$(CONFIG_MACH_XBURST2) += xburst2/ + + # include the platform specific files + include $(patsubst %, $(srctree)/arch/mips/%/Platform, $(platform-y)) +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index 896a29df1..ef8bf2f8a 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -421,8 +421,59 @@ config MACH_INGENIC_SOC + select MIPS_GENERIC + select MACH_INGENIC + select SYS_SUPPORTS_ZBOOT_UART16550 +- select CPU_SUPPORTS_CPUFREQ ++ ++config MACH_XBURST ++ bool "Ingenic Xburst based machines" ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_HAS_CPU_MIPS32_R2 ++ select SYS_HAS_EARLY_PRINTK + select MIPS_EXTERNAL_TIMER ++ select DMA_NONCOHERENT ++ select HAVE_CLK ++ select ARCH_REQUIRE_GPIOLIB ++ select SYS_SUPPORTS_HIGHMEM ++ select XBURST_CPU_SCACHE ++ select BOARD_SCACHE ++ select DMA_INGENIC_HIGHMEM_FLUSH ++ select HAVE_KERNEL_GZIP ++ select IRQ_MIPS_CPU ++ select USE_OF ++ select LIBFDT ++ select COMMON_CLK ++ select HARDIRQS_SW_RESEND ++ ++config MACH_XBURST2 ++ bool "Ingenic Xburst2 based machines" ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_HAS_CPU_MIPS32_R2 ++ select SYS_HAS_CPU_MIPS32_R5 ++ select SYS_HAS_EARLY_PRINTK ++ select SYS_SUPPORTS_SMP ++ select SYS_SUPPORTS_HOTPLUG_CPU ++ select MIPS_EXTERNAL_TIMER ++ select DMA_NONCOHERENT ++ select HAVE_CLK ++ select ARCH_REQUIRE_GPIOLIB ++ select SYS_SUPPORTS_HIGHMEM ++ select XBURST2_CPU_SCACHE ++ select DMA_INGENIC_HIGHMEM_FLUSH ++ select HAVE_KERNEL_GZIP ++ select IRQ_MIPS_CPU ++ select USE_OF ++ select LIBFDT ++ select MIPS_O32_FP64_SUPPORT ++ select WEAK_ORDERING ++ select WEAK_REORDERING_BEYOND_LLSC ++ select COMMON_CLK ++ select BOARD_SCACHE ++ select CPU_SUPPORTS_CPUFREQ ++ select HARDIRQS_SW_RESEND ++ ++ + + config LANTIQ + bool "Lantiq based platforms" +@@ -1045,6 +1096,8 @@ source "arch/mips/bcm63xx/Kconfig" + source "arch/mips/bmips/Kconfig" + source "arch/mips/generic/Kconfig" + source "arch/mips/ingenic/Kconfig" ++source "arch/mips/xburst/Kconfig" ++source "arch/mips/xburst2/Kconfig" + source "arch/mips/jazz/Kconfig" + source "arch/mips/lantiq/Kconfig" + source "arch/mips/pic32/Kconfig" +@@ -2305,6 +2358,14 @@ config MIPS_CPU_SCACHE + bool + select BOARD_SCACHE + ++config XBURST_CPU_SCACHE ++ bool ++ select BOARD_SCACHE ++ ++config XBURST2_CPU_SCACHE ++ bool ++ select BOARD_SCACHE ++ + config R5000_CPU_SCACHE + bool + select BOARD_SCACHE +diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile +index 19027129a..bcc5e9e8b 100644 +--- a/arch/mips/boot/dts/Makefile ++++ b/arch/mips/boot/dts/Makefile +@@ -15,5 +15,7 @@ subdir-$(CONFIG_MACH_PIC32) += pic32 + subdir-$(CONFIG_ATH79) += qca + subdir-$(CONFIG_RALINK) += ralink + subdir-$(CONFIG_FIT_IMAGE_FDT_XILFPGA) += xilfpga ++subdir-$(CONFIG_MACH_XBURST) += ingenic ++subdir-$(CONFIG_MACH_XBURST2) += ingenic + + obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y)) +diff --git a/arch/mips/configs/halley5_small_defconfig b/arch/mips/configs/halley5_small_defconfig +new file mode 100644 +index 000000000..44f9576cf +--- /dev/null ++++ b/arch/mips/configs/halley5_small_defconfig +@@ -0,0 +1,4478 @@ ++# ++# Automatically generated file; DO NOT EDIT. ++# Linux/mips 5.10.93 Kernel Configuration ++# ++CONFIG_CC_VERSION_TEXT="OHOS (dev) clang version 12.0.1 (llvm-project ca29bdb75cfb16ef1b9a01a42de3ebaa9281896f)" ++CONFIG_GCC_VERSION=0 ++CONFIG_LD_VERSION=227000000 ++CONFIG_CC_IS_CLANG=y ++CONFIG_CLANG_VERSION=120001 ++CONFIG_LLD_VERSION=0 ++CONFIG_CC_HAS_ASM_GOTO=y ++CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y ++CONFIG_CC_HAS_ASM_INLINE=y ++CONFIG_IRQ_WORK=y ++CONFIG_BUILDTIME_TABLE_SORT=y ++ ++# ++# General setup ++# ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++# CONFIG_COMPILE_TEST is not set ++CONFIG_LOCALVERSION="" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_BUILD_SALT="" ++CONFIG_HAVE_KERNEL_GZIP=y ++CONFIG_KERNEL_GZIP=y ++CONFIG_DEFAULT_INIT="" ++CONFIG_DEFAULT_HOSTNAME="(none)" ++# CONFIG_SWAP is not set ++CONFIG_SYSVIPC=y ++CONFIG_SYSVIPC_SYSCTL=y ++# CONFIG_POSIX_MQUEUE is not set ++# CONFIG_WATCH_QUEUE is not set ++# CONFIG_CROSS_MEMORY_ATTACH is not set ++CONFIG_USELIB=y ++# CONFIG_AUDIT is not set ++ ++# ++# IRQ subsystem ++# ++CONFIG_GENERIC_IRQ_PROBE=y ++CONFIG_GENERIC_IRQ_SHOW=y ++CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y ++CONFIG_HARDIRQS_SW_RESEND=y ++CONFIG_GENERIC_IRQ_CHIP=y ++CONFIG_IRQ_DOMAIN=y ++CONFIG_HANDLE_DOMAIN_IRQ=y ++CONFIG_IRQ_FORCED_THREADING=y ++# CONFIG_GENERIC_IRQ_DEBUGFS is not set ++# end of IRQ subsystem ++ ++CONFIG_GENERIC_TIME_VSYSCALL=y ++CONFIG_GENERIC_CLOCKEVENTS=y ++CONFIG_GENERIC_CMOS_UPDATE=y ++ ++# ++# Timers subsystem ++# ++CONFIG_TICK_ONESHOT=y ++CONFIG_NO_HZ_COMMON=y ++# CONFIG_HZ_PERIODIC is not set ++CONFIG_NO_HZ_IDLE=y ++# CONFIG_NO_HZ is not set ++CONFIG_HIGH_RES_TIMERS=y ++# end of Timers subsystem ++ ++# CONFIG_PREEMPT_NONE is not set ++# CONFIG_PREEMPT_VOLUNTARY is not set ++CONFIG_PREEMPT=y ++CONFIG_PREEMPT_COUNT=y ++CONFIG_PREEMPTION=y ++ ++# ++# CPU/Task time and stats accounting ++# ++CONFIG_TICK_CPU_ACCOUNTING=y ++# CONFIG_IRQ_TIME_ACCOUNTING is not set ++# CONFIG_SCHED_WALT is not set ++# CONFIG_BSD_PROCESS_ACCT is not set ++# CONFIG_TASKSTATS is not set ++# CONFIG_PSI is not set ++# end of CPU/Task time and stats accounting ++ ++CONFIG_CPU_ISOLATION=y ++# CONFIG_SCHED_RUNNING_AVG is not set ++# CONFIG_CPU_ISOLATION_OPT is not set ++ ++# ++# RCU Subsystem ++# ++CONFIG_TREE_RCU=y ++CONFIG_PREEMPT_RCU=y ++# CONFIG_RCU_EXPERT is not set ++CONFIG_SRCU=y ++CONFIG_TREE_SRCU=y ++CONFIG_TASKS_RCU_GENERIC=y ++CONFIG_TASKS_RCU=y ++CONFIG_RCU_STALL_COMMON=y ++CONFIG_RCU_NEED_SEGCBLIST=y ++# end of RCU Subsystem ++ ++# CONFIG_IKCONFIG is not set ++# CONFIG_IKHEADERS is not set ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 ++CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 ++CONFIG_GENERIC_SCHED_CLOCK=y ++ ++# ++# Scheduler features ++# ++# CONFIG_SCHED_LATENCY_NICE is not set ++ ++# ++# Related Thread Group ++# ++# end of Related Thread Group ++ ++# CONFIG_SCHED_EAS is not set ++# end of Scheduler features ++ ++# CONFIG_CGROUPS is not set ++# CONFIG_NAMESPACES is not set ++# CONFIG_CHECKPOINT_RESTORE is not set ++# CONFIG_SCHED_AUTOGROUP is not set ++# CONFIG_SYSFS_DEPRECATED is not set ++# CONFIG_RELAY is not set ++# CONFIG_BLK_DEV_INITRD is not set ++# CONFIG_BOOT_CONFIG is not set ++CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y ++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set ++CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y ++# CONFIG_LD_DEAD_CODE_DATA_ELIMINATION is not set ++CONFIG_SYSCTL=y ++CONFIG_SYSCTL_EXCEPTION_TRACE=y ++CONFIG_BPF=y ++CONFIG_EXPERT=y ++CONFIG_MULTIUSER=y ++CONFIG_SGETMASK_SYSCALL=y ++CONFIG_SYSFS_SYSCALL=y ++CONFIG_FHANDLE=y ++CONFIG_POSIX_TIMERS=y ++CONFIG_PRINTK=y ++CONFIG_PRINTK_NMI=y ++CONFIG_BUG=y ++CONFIG_BASE_FULL=y ++CONFIG_FUTEX=y ++CONFIG_FUTEX_PI=y ++CONFIG_EPOLL=y ++CONFIG_SIGNALFD=y ++CONFIG_TIMERFD=y ++CONFIG_EVENTFD=y ++CONFIG_SHMEM=y ++CONFIG_AIO=y ++CONFIG_IO_URING=y ++# CONFIG_ADVISE_SYSCALLS is not set ++CONFIG_MEMBARRIER=y ++# CONFIG_KALLSYMS is not set ++# CONFIG_BPF_SYSCALL is not set ++# CONFIG_USERFAULTFD is not set ++# CONFIG_KCMP is not set ++CONFIG_RSEQ=y ++# CONFIG_DEBUG_RSEQ is not set ++# CONFIG_EMBEDDED is not set ++CONFIG_HAVE_PERF_EVENTS=y ++CONFIG_PERF_USE_VMALLOC=y ++# CONFIG_PC104 is not set ++ ++# ++# Kernel Performance Events And Counters ++# ++# CONFIG_PERF_EVENTS is not set ++# end of Kernel Performance Events And Counters ++ ++# CONFIG_VM_EVENT_COUNTERS is not set ++# CONFIG_COMPAT_BRK is not set ++CONFIG_SLAB=y ++# CONFIG_SLUB is not set ++# CONFIG_SLOB is not set ++CONFIG_SLAB_MERGE_DEFAULT=y ++# CONFIG_SLAB_FREELIST_RANDOM is not set ++# CONFIG_SLAB_FREELIST_HARDENED is not set ++# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set ++CONFIG_SYSTEM_DATA_VERIFICATION=y ++# CONFIG_PROFILING is not set ++# end of General setup ++ ++CONFIG_MIPS=y ++ ++# ++# Machine selection ++# ++# CONFIG_MIPS_GENERIC_KERNEL is not set ++# CONFIG_MIPS_ALCHEMY is not set ++# CONFIG_AR7 is not set ++# CONFIG_ATH25 is not set ++# CONFIG_ATH79 is not set ++# CONFIG_BMIPS_GENERIC is not set ++# CONFIG_BCM47XX is not set ++# CONFIG_BCM63XX is not set ++# CONFIG_MIPS_COBALT is not set ++# CONFIG_MACH_DECSTATION is not set ++# CONFIG_MACH_JAZZ is not set ++# CONFIG_MACH_INGENIC_SOC is not set ++# CONFIG_MACH_XBURST is not set ++CONFIG_MACH_XBURST2=y ++# CONFIG_LANTIQ is not set ++# CONFIG_MACH_LOONGSON32 is not set ++# CONFIG_MACH_LOONGSON2EF is not set ++# CONFIG_MACH_LOONGSON64 is not set ++# CONFIG_MACH_PISTACHIO is not set ++# CONFIG_MIPS_MALTA is not set ++# CONFIG_MACH_PIC32 is not set ++# CONFIG_MACH_VR41XX is not set ++# CONFIG_RALINK is not set ++# CONFIG_SGI_IP22 is not set ++# CONFIG_SGI_IP27 is not set ++# CONFIG_SGI_IP28 is not set ++# CONFIG_SGI_IP30 is not set ++# CONFIG_SGI_IP32 is not set ++# CONFIG_SIBYTE_CRHINE is not set ++# CONFIG_SIBYTE_CARMEL is not set ++# CONFIG_SIBYTE_CRHONE is not set ++# CONFIG_SIBYTE_RHONE is not set ++# CONFIG_SIBYTE_SWARM is not set ++# CONFIG_SIBYTE_LITTLESUR is not set ++# CONFIG_SIBYTE_SENTOSA is not set ++# CONFIG_SIBYTE_BIGSUR is not set ++# CONFIG_SNI_RM is not set ++# CONFIG_MACH_TX39XX is not set ++# CONFIG_MACH_TX49XX is not set ++# CONFIG_MIKROTIK_RB532 is not set ++# CONFIG_CAVIUM_OCTEON_SOC is not set ++# CONFIG_NLM_XLR_BOARD is not set ++# CONFIG_NLM_XLP_BOARD is not set ++CONFIG_INGENIC_BUILTIN_DTB=y ++CONFIG_EXTAL_CLOCK=24 ++CONFIG_INGENIC_GPT_CHECK=y ++# CONFIG_SUSPEND_TEST is not set ++ ++# ++# SOC Type Selection ++# ++CONFIG_SOC_X2000=y ++# CONFIG_SOC_X2500 is not set ++# CONFIG_SOC_M300 is not set ++# CONFIG_SOC_X2100 is not set ++# CONFIG_DT_X2000_MODULE is not set ++# CONFIG_DT_HALLEY5_V20 is not set ++CONFIG_DT_HALLEY5_V30=y ++# CONFIG_DT_KALE_V10 is not set ++# CONFIG_DT_X2000_LIFESMART_480P is not set ++# CONFIG_RAW_BOOT is not set ++# CONFIG_FPGA_TEST is not set ++# CONFIG_XBURST2_CPU_TEST is not set ++# CONFIG_FASTBOOT is not set ++# end of SOC Type Selection ++# end of Machine selection ++ ++CONFIG_GENERIC_HWEIGHT=y ++CONFIG_GENERIC_CALIBRATE_DELAY=y ++CONFIG_SCHED_OMIT_FRAME_POINTER=y ++CONFIG_ARCH_SUPPORTS_UPROBES=y ++CONFIG_DMA_NONCOHERENT=y ++CONFIG_SYS_HAS_EARLY_PRINTK=y ++CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y ++CONFIG_CPU_LITTLE_ENDIAN=y ++CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y ++CONFIG_MIPS_SPRAM=y ++CONFIG_MIPS_L1_CACHE_SHIFT=5 ++ ++# ++# CPU selection ++# ++# CONFIG_CPU_MIPS32_R1 is not set ++# CONFIG_CPU_MIPS32_R2 is not set ++CONFIG_CPU_MIPS32_R5=y ++# CONFIG_CPU_MIPS32_R5_FEATURES is not set ++CONFIG_SYS_HAS_CPU_MIPS32_R1=y ++CONFIG_SYS_HAS_CPU_MIPS32_R2=y ++CONFIG_SYS_HAS_CPU_MIPS32_R5=y ++CONFIG_WEAK_ORDERING=y ++CONFIG_WEAK_REORDERING_BEYOND_LLSC=y ++# end of CPU selection ++ ++CONFIG_CPU_MIPS32=y ++CONFIG_CPU_MIPSR5=y ++CONFIG_TARGET_ISA_REV=5 ++CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y ++CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y ++CONFIG_CPU_SUPPORTS_CPUFREQ=y ++ ++# ++# Kernel type ++# ++CONFIG_32BIT=y ++CONFIG_PAGE_SIZE_4KB=y ++# CONFIG_PAGE_SIZE_16KB is not set ++# CONFIG_PAGE_SIZE_64KB is not set ++CONFIG_FORCE_MAX_ZONEORDER=15 ++CONFIG_BOARD_SCACHE=y ++CONFIG_XBURST2_CPU_SCACHE=y ++CONFIG_CPU_HAS_PREFETCH=y ++CONFIG_CPU_GENERIC_DUMP_TLB=y ++CONFIG_MIPS_FP_SUPPORT=y ++CONFIG_CPU_R4K_FPU=y ++CONFIG_CPU_R4K_CACHE_TLB=y ++CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y ++CONFIG_CPU_HAS_MSA=y ++CONFIG_CPU_HAS_DIEI=y ++CONFIG_CPU_HAS_RIXI=y ++CONFIG_CPU_HAS_SYNC=y ++CONFIG_MIPS_ASID_SHIFT=0 ++CONFIG_MIPS_ASID_BITS=8 ++# CONFIG_HIGHMEM is not set ++CONFIG_CPU_SUPPORTS_HIGHMEM=y ++CONFIG_SYS_SUPPORTS_HIGHMEM=y ++CONFIG_CPU_SUPPORTS_MSA=y ++CONFIG_ARCH_FLATMEM_ENABLE=y ++CONFIG_SMP=y ++CONFIG_HOTPLUG_CPU=y ++CONFIG_SYS_SUPPORTS_SMP=y ++CONFIG_NR_CPUS=2 ++CONFIG_MIPS_NR_CPU_NR_MAP=2 ++# CONFIG_HZ_24 is not set ++# CONFIG_HZ_48 is not set ++CONFIG_HZ_100=y ++# CONFIG_HZ_128 is not set ++# CONFIG_HZ_250 is not set ++# CONFIG_HZ_256 is not set ++# CONFIG_HZ_1000 is not set ++# CONFIG_HZ_1024 is not set ++CONFIG_SYS_SUPPORTS_ARBIT_HZ=y ++CONFIG_HZ=100 ++CONFIG_SCHED_HRTICK=y ++# CONFIG_KEXEC is not set ++# CONFIG_CRASH_DUMP is not set ++CONFIG_MIPS_O32_FP64_SUPPORT=y ++CONFIG_USE_OF=y ++CONFIG_BUILTIN_DTB=y ++CONFIG_MIPS_NO_APPENDED_DTB=y ++# CONFIG_MIPS_ELF_APPENDED_DTB is not set ++# CONFIG_MIPS_RAW_APPENDED_DTB is not set ++CONFIG_MIPS_CMDLINE_FROM_DTB=y ++# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set ++# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set ++# end of Kernel type ++ ++CONFIG_LOCKDEP_SUPPORT=y ++CONFIG_STACKTRACE_SUPPORT=y ++CONFIG_PGTABLE_LEVELS=2 ++ ++# ++# Bus options (PCI, PCMCIA, EISA, ISA, TC) ++# ++CONFIG_PCI_DRIVERS_LEGACY=y ++CONFIG_MMU=y ++CONFIG_ARCH_MMAP_RND_BITS_MIN=8 ++CONFIG_ARCH_MMAP_RND_BITS_MAX=15 ++CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 ++CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15 ++# end of Bus options (PCI, PCMCIA, EISA, ISA, TC) ++ ++CONFIG_TRAD_SIGNALS=y ++ ++# ++# Power management options ++# ++CONFIG_ARCH_HIBERNATION_POSSIBLE=y ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++CONFIG_SUSPEND=y ++CONFIG_SUSPEND_FREEZER=y ++# CONFIG_SUSPEND_SKIP_SYNC is not set ++CONFIG_PM_SLEEP=y ++CONFIG_PM_SLEEP_SMP=y ++# CONFIG_PM_AUTOSLEEP is not set ++# CONFIG_PM_WAKELOCKS is not set ++CONFIG_PM=y ++# CONFIG_PM_DEBUG is not set ++CONFIG_PM_CLK=y ++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set ++# end of Power management options ++ ++CONFIG_MIPS_EXTERNAL_TIMER=y ++ ++# ++# CPU Power Management ++# ++ ++# ++# CPU Frequency scaling ++# ++# CONFIG_CPU_FREQ is not set ++# end of CPU Frequency scaling ++ ++# ++# CPU Idle ++# ++# CONFIG_CPU_IDLE is not set ++# end of CPU Idle ++# end of CPU Power Management ++ ++# ++# Firmware Drivers ++# ++# CONFIG_FIRMWARE_MEMMAP is not set ++# CONFIG_GOOGLE_FIRMWARE is not set ++ ++# ++# Tegra firmware driver ++# ++# end of Tegra firmware driver ++# end of Firmware Drivers ++ ++CONFIG_HAVE_KVM=y ++# CONFIG_VIRTUALIZATION is not set ++CONFIG_MIPS_LD_CAN_LINK_VDSO=y ++ ++# ++# General architecture-dependent options ++# ++CONFIG_CRASH_CORE=y ++CONFIG_SET_FS=y ++CONFIG_HAVE_OPROFILE=y ++# CONFIG_KPROBES is not set ++# CONFIG_JUMP_LABEL is not set ++CONFIG_ARCH_USE_BUILTIN_BSWAP=y ++CONFIG_HAVE_IOREMAP_PROT=y ++CONFIG_HAVE_KPROBES=y ++CONFIG_HAVE_KRETPROBES=y ++CONFIG_HAVE_NMI=y ++CONFIG_HAVE_ARCH_TRACEHOOK=y ++CONFIG_HAVE_DMA_CONTIGUOUS=y ++CONFIG_GENERIC_SMP_IDLE_THREAD=y ++CONFIG_ARCH_HAS_FORTIFY_SOURCE=y ++CONFIG_ARCH_HAS_DMA_SET_UNCACHED=y ++CONFIG_ARCH_32BIT_OFF_T=y ++CONFIG_HAVE_ASM_MODVERSIONS=y ++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y ++CONFIG_HAVE_RSEQ=y ++CONFIG_HAVE_ARCH_JUMP_LABEL=y ++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y ++CONFIG_HAVE_ARCH_SECCOMP=y ++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y ++# CONFIG_SECCOMP is not set ++CONFIG_HAVE_STACKPROTECTOR=y ++CONFIG_STACKPROTECTOR=y ++CONFIG_STACKPROTECTOR_STRONG=y ++CONFIG_LTO_NONE=y ++CONFIG_HAVE_CONTEXT_TRACKING=y ++CONFIG_HAVE_TIF_NOHZ=y ++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y ++CONFIG_HAVE_MOD_ARCH_SPECIFIC=y ++CONFIG_MODULES_USE_ELF_REL=y ++CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y ++CONFIG_ARCH_HAS_ELF_RANDOMIZE=y ++CONFIG_HAVE_ARCH_MMAP_RND_BITS=y ++CONFIG_HAVE_EXIT_THREAD=y ++CONFIG_ARCH_MMAP_RND_BITS=8 ++CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y ++CONFIG_CLONE_BACKWARDS=y ++CONFIG_COMPAT_32BIT_TIME=y ++CONFIG_HAVE_ARCH_COMPILER_H=y ++# CONFIG_LOCK_EVENT_COUNTS is not set ++CONFIG_HAVE_SPARSE_SYSCALL_NR=y ++ ++# ++# GCOV-based kernel profiling ++# ++# CONFIG_GCOV_KERNEL is not set ++# end of GCOV-based kernel profiling ++ ++CONFIG_HAVE_GCC_PLUGINS=y ++# end of General architecture-dependent options ++ ++CONFIG_RT_MUTEXES=y ++CONFIG_BASE_SMALL=0 ++CONFIG_MODULES=y ++CONFIG_MODULE_FORCE_LOAD=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_MODULE_FORCE_UNLOAD=y ++# CONFIG_MODVERSIONS is not set ++# CONFIG_MODULE_SRCVERSION_ALL is not set ++# CONFIG_MODULE_SIG is not set ++# CONFIG_MODULE_COMPRESS is not set ++# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set ++# CONFIG_UNUSED_SYMBOLS is not set ++# CONFIG_TRIM_UNUSED_KSYMS is not set ++CONFIG_BLOCK=y ++CONFIG_BLK_SCSI_REQUEST=y ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_BLK_DEV_BSGLIB is not set ++CONFIG_BLK_DEV_INTEGRITY=y ++CONFIG_BLK_DEV_INTEGRITY_T10=y ++# CONFIG_BLK_DEV_ZONED is not set ++# CONFIG_BLK_CMDLINE_PARSER is not set ++# CONFIG_BLK_WBT is not set ++CONFIG_BLK_DEBUG_FS=y ++# CONFIG_BLK_SED_OPAL is not set ++# CONFIG_BLK_INLINE_ENCRYPTION is not set ++ ++# ++# Partition Types ++# ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_ACORN_PARTITION is not set ++# CONFIG_AIX_PARTITION is not set ++# CONFIG_OSF_PARTITION is not set ++# CONFIG_AMIGA_PARTITION is not set ++# CONFIG_ATARI_PARTITION is not set ++# CONFIG_MAC_PARTITION is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_BSD_DISKLABEL is not set ++# CONFIG_MINIX_SUBPARTITION is not set ++# CONFIG_SOLARIS_X86_PARTITION is not set ++# CONFIG_UNIXWARE_DISKLABEL is not set ++# CONFIG_LDM_PARTITION is not set ++# CONFIG_SGI_PARTITION is not set ++# CONFIG_ULTRIX_PARTITION is not set ++# CONFIG_SUN_PARTITION is not set ++# CONFIG_KARMA_PARTITION is not set ++CONFIG_EFI_PARTITION=y ++# CONFIG_SYSV68_PARTITION is not set ++# CONFIG_CMDLINE_PARTITION is not set ++# end of Partition Types ++ ++CONFIG_BLK_PM=y ++ ++# ++# IO Schedulers ++# ++CONFIG_MQ_IOSCHED_DEADLINE=y ++CONFIG_MQ_IOSCHED_KYBER=y ++# CONFIG_IOSCHED_BFQ is not set ++# end of IO Schedulers ++ ++CONFIG_ASN1=y ++CONFIG_UNINLINE_SPIN_UNLOCK=y ++CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y ++CONFIG_QUEUED_SPINLOCKS=y ++CONFIG_ARCH_USE_QUEUED_RWLOCKS=y ++CONFIG_QUEUED_RWLOCKS=y ++CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y ++CONFIG_FREEZER=y ++ ++# ++# Executable file formats ++# ++CONFIG_BINFMT_ELF=y ++CONFIG_ARCH_BINFMT_ELF_STATE=y ++CONFIG_ELFCORE=y ++CONFIG_BINFMT_SCRIPT=y ++# CONFIG_BINFMT_MISC is not set ++# CONFIG_COREDUMP is not set ++# end of Executable file formats ++ ++# ++# Memory Management options ++# ++# CONFIG_PAGE_TRACING is not set ++# CONFIG_RECLAIM_ACCT is not set ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++CONFIG_HAVE_FAST_GUP=y ++CONFIG_SPLIT_PTLOCK_CPUS=4 ++CONFIG_COMPACTION=y ++# CONFIG_PAGE_REPORTING is not set ++CONFIG_MIGRATION=y ++CONFIG_VIRT_TO_BUS=y ++CONFIG_MMU_NOTIFIER=y ++# CONFIG_KSM is not set ++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 ++# CONFIG_CLEANCACHE is not set ++# CONFIG_CMA is not set ++# CONFIG_ZPOOL is not set ++# CONFIG_ZBUD is not set ++# CONFIG_ZSMALLOC is not set ++# CONFIG_IDLE_PAGE_TRACKING is not set ++CONFIG_FRAME_VECTOR=y ++# CONFIG_PERCPU_STATS is not set ++# CONFIG_GUP_BENCHMARK is not set ++# CONFIG_LOWMEM is not set ++# CONFIG_LMKD_DBG is not set ++# end of Memory Management options ++ ++CONFIG_NET=y ++CONFIG_NET_INGRESS=y ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++# CONFIG_PACKET_DIAG is not set ++CONFIG_UNIX=y ++CONFIG_UNIX_SCM=y ++# CONFIG_UNIX_DIAG is not set ++# CONFIG_TLS is not set ++# CONFIG_XFRM_USER is not set ++# CONFIG_NET_KEY is not set ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE_DEMUX is not set ++# CONFIG_IP_MROUTE is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_NET_IPVTI is not set ++# CONFIG_NET_FOU is not set ++# CONFIG_INET_AH is not set ++# CONFIG_INET_ESP is not set ++# CONFIG_INET_IPCOMP is not set ++CONFIG_INET_DIAG=y ++CONFIG_INET_TCP_DIAG=y ++# CONFIG_INET_UDP_DIAG is not set ++# CONFIG_INET_RAW_DIAG is not set ++# CONFIG_INET_DIAG_DESTROY is not set ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_TCP_MD5SIG is not set ++# CONFIG_IPV6 is not set ++# CONFIG_MPTCP is not set ++# CONFIG_NETWORK_SECMARK is not set ++CONFIG_NET_PTP_CLASSIFY=y ++CONFIG_NETWORK_PHY_TIMESTAMPING=y ++CONFIG_NETFILTER=y ++CONFIG_NETFILTER_ADVANCED=y ++# CONFIG_BRIDGE_NETFILTER is not set ++ ++# ++# Core Netfilter Configuration ++# ++CONFIG_NETFILTER_INGRESS=y ++CONFIG_NETFILTER_NETLINK=y ++# CONFIG_NETFILTER_NETLINK_ACCT is not set ++CONFIG_NETFILTER_NETLINK_QUEUE=y ++CONFIG_NETFILTER_NETLINK_LOG=y ++# CONFIG_NETFILTER_NETLINK_OSF is not set ++# CONFIG_NF_CONNTRACK is not set ++# CONFIG_NF_LOG_NETDEV is not set ++# CONFIG_NF_TABLES is not set ++CONFIG_NETFILTER_XTABLES=y ++ ++# ++# Xtables combined modules ++# ++# CONFIG_NETFILTER_XT_MARK is not set ++# CONFIG_NETFILTER_XT_SET is not set ++ ++# ++# Xtables targets ++# ++# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set ++# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set ++# CONFIG_NETFILTER_XT_TARGET_DSCP is not set ++# CONFIG_NETFILTER_XT_TARGET_HL is not set ++# CONFIG_NETFILTER_XT_TARGET_HMARK is not set ++# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set ++# CONFIG_NETFILTER_XT_TARGET_LOG is not set ++# CONFIG_NETFILTER_XT_TARGET_MARK is not set ++CONFIG_NETFILTER_XT_TARGET_NFLOG=y ++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y ++# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set ++# CONFIG_NETFILTER_XT_TARGET_TEE is not set ++# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set ++# CONFIG_NETFILTER_XT_TARGET_TRACE is not set ++# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set ++# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set ++ ++# ++# Xtables matches ++# ++# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set ++# CONFIG_NETFILTER_XT_MATCH_BPF is not set ++# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set ++# CONFIG_NETFILTER_XT_MATCH_CPU is not set ++# CONFIG_NETFILTER_XT_MATCH_DCCP is not set ++# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set ++# CONFIG_NETFILTER_XT_MATCH_DSCP is not set ++# CONFIG_NETFILTER_XT_MATCH_ECN is not set ++# CONFIG_NETFILTER_XT_MATCH_ESP is not set ++# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set ++# CONFIG_NETFILTER_XT_MATCH_HL is not set ++# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set ++# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set ++# CONFIG_NETFILTER_XT_MATCH_L2TP is not set ++# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set ++# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set ++# CONFIG_NETFILTER_XT_MATCH_MAC is not set ++# CONFIG_NETFILTER_XT_MATCH_MARK is not set ++# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set ++# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set ++# CONFIG_NETFILTER_XT_MATCH_OSF is not set ++# CONFIG_NETFILTER_XT_MATCH_OWNER is not set ++# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set ++CONFIG_NETFILTER_XT_MATCH_QUOTA=y ++# CONFIG_NETFILTER_XT_MATCH_QUOTA2 is not set ++# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set ++# CONFIG_NETFILTER_XT_MATCH_REALM is not set ++# CONFIG_NETFILTER_XT_MATCH_RECENT is not set ++# CONFIG_NETFILTER_XT_MATCH_SCTP is not set ++# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set ++# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set ++# CONFIG_NETFILTER_XT_MATCH_STRING is not set ++# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set ++# CONFIG_NETFILTER_XT_MATCH_TIME is not set ++# CONFIG_NETFILTER_XT_MATCH_U32 is not set ++# end of Core Netfilter Configuration ++ ++CONFIG_IP_SET=y ++CONFIG_IP_SET_MAX=256 ++# CONFIG_IP_SET_BITMAP_IP is not set ++CONFIG_IP_SET_BITMAP_IPMAC=m ++# CONFIG_IP_SET_BITMAP_PORT is not set ++# CONFIG_IP_SET_HASH_IP is not set ++# CONFIG_IP_SET_HASH_IPMARK is not set ++# CONFIG_IP_SET_HASH_IPPORT is not set ++# CONFIG_IP_SET_HASH_IPPORTIP is not set ++# CONFIG_IP_SET_HASH_IPPORTNET is not set ++# CONFIG_IP_SET_HASH_IPMAC is not set ++# CONFIG_IP_SET_HASH_MAC is not set ++# CONFIG_IP_SET_HASH_NETPORTNET is not set ++# CONFIG_IP_SET_HASH_NET is not set ++# CONFIG_IP_SET_HASH_NETNET is not set ++# CONFIG_IP_SET_HASH_NETPORT is not set ++# CONFIG_IP_SET_HASH_NETIFACE is not set ++# CONFIG_IP_SET_LIST_SET is not set ++# CONFIG_IP_VS is not set ++ ++# ++# IP: Netfilter Configuration ++# ++# CONFIG_NF_SOCKET_IPV4 is not set ++# CONFIG_NF_TPROXY_IPV4 is not set ++# CONFIG_NF_DUP_IPV4 is not set ++# CONFIG_NF_LOG_ARP is not set ++# CONFIG_NF_LOG_IPV4 is not set ++# CONFIG_NF_REJECT_IPV4 is not set ++CONFIG_IP_NF_IPTABLES=y ++# CONFIG_IP_NF_MATCH_AH is not set ++# CONFIG_IP_NF_MATCH_ECN is not set ++# CONFIG_IP_NF_MATCH_RPFILTER is not set ++# CONFIG_IP_NF_MATCH_TTL is not set ++CONFIG_IP_NF_FILTER=y ++# CONFIG_IP_NF_TARGET_REJECT is not set ++CONFIG_IP_NF_MANGLE=y ++# CONFIG_IP_NF_TARGET_ECN is not set ++# CONFIG_IP_NF_TARGET_TTL is not set ++CONFIG_IP_NF_RAW=y ++# CONFIG_IP_NF_ARPTABLES is not set ++# end of IP: Netfilter Configuration ++ ++# CONFIG_BRIDGE_NF_EBTABLES is not set ++# CONFIG_BPFILTER is not set ++# CONFIG_IP_DCCP is not set ++# CONFIG_IP_SCTP is not set ++# CONFIG_RDS is not set ++# CONFIG_TIPC is not set ++# CONFIG_ATM is not set ++# CONFIG_L2TP is not set ++CONFIG_STP=y ++CONFIG_BRIDGE=y ++CONFIG_BRIDGE_IGMP_SNOOPING=y ++# CONFIG_BRIDGE_MRP is not set ++CONFIG_HAVE_NET_DSA=y ++# CONFIG_NET_DSA is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_DECNET is not set ++CONFIG_LLC=y ++# CONFIG_LLC2 is not set ++# CONFIG_ATALK is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_PHONET is not set ++# CONFIG_IEEE802154 is not set ++# CONFIG_NET_SCHED is not set ++# CONFIG_DCB is not set ++# CONFIG_DNS_RESOLVER is not set ++# CONFIG_BATMAN_ADV is not set ++# CONFIG_OPENVSWITCH is not set ++# CONFIG_VSOCKETS is not set ++# CONFIG_NETLINK_DIAG is not set ++# CONFIG_MPLS is not set ++# CONFIG_NET_NSH is not set ++# CONFIG_HSR is not set ++# CONFIG_NET_SWITCHDEV is not set ++# CONFIG_NET_L3_MASTER_DEV is not set ++# CONFIG_QRTR is not set ++# CONFIG_NET_NCSI is not set ++CONFIG_RPS=y ++CONFIG_RFS_ACCEL=y ++CONFIG_XPS=y ++CONFIG_NET_RX_BUSY_POLL=y ++CONFIG_BQL=y ++# CONFIG_BPF_JIT is not set ++CONFIG_NET_FLOW_LIMIT=y ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# end of Network testing ++# end of Networking options ++ ++# CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set ++# CONFIG_BT is not set ++# CONFIG_AF_RXRPC is not set ++# CONFIG_AF_KCM is not set ++CONFIG_WIRELESS=y ++CONFIG_WEXT_CORE=y ++CONFIG_WEXT_PROC=y ++CONFIG_CFG80211=y ++CONFIG_NL80211_TESTMODE=y ++# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set ++# CONFIG_CFG80211_CERTIFICATION_ONUS is not set ++CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y ++CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y ++CONFIG_CFG80211_DEFAULT_PS=y ++# CONFIG_CFG80211_DEBUGFS is not set ++CONFIG_CFG80211_CRDA_SUPPORT=y ++CONFIG_CFG80211_WEXT=y ++CONFIG_MAC80211=y ++CONFIG_MAC80211_HAS_RC=y ++CONFIG_MAC80211_RC_MINSTREL=y ++CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y ++CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" ++CONFIG_MAC80211_MESH=y ++# CONFIG_MAC80211_DEBUGFS is not set ++# CONFIG_MAC80211_MESSAGE_TRACING is not set ++# CONFIG_MAC80211_DEBUG_MENU is not set ++CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 ++# CONFIG_WIMAX is not set ++CONFIG_RFKILL=y ++CONFIG_RFKILL_INPUT=y ++# CONFIG_RFKILL_GPIO is not set ++# CONFIG_NET_9P is not set ++# CONFIG_CAIF is not set ++# CONFIG_CEPH_LIB is not set ++# CONFIG_NFC is not set ++# CONFIG_PSAMPLE is not set ++# CONFIG_NET_IFE is not set ++# CONFIG_LWTUNNEL is not set ++# CONFIG_FAILOVER is not set ++CONFIG_ETHTOOL_NETLINK=y ++CONFIG_HAVE_CBPF_JIT=y ++ ++# ++# Device Drivers ++# ++# CONFIG_PCCARD is not set ++# CONFIG_HYPERHOLD is not set ++ ++# ++# Generic Driver Options ++# ++CONFIG_UEVENT_HELPER=y ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++# CONFIG_PREVENT_FIRMWARE_BUILD is not set ++ ++# ++# Firmware loader ++# ++CONFIG_FW_LOADER=y ++CONFIG_EXTRA_FIRMWARE="" ++# CONFIG_FW_LOADER_USER_HELPER is not set ++# CONFIG_FW_LOADER_COMPRESS is not set ++CONFIG_FW_CACHE=y ++# end of Firmware loader ++ ++# CONFIG_ALLOW_DEV_COREDUMP is not set ++# CONFIG_DEBUG_DRIVER is not set ++# CONFIG_DEBUG_DEVRES is not set ++# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set ++# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set ++CONFIG_GENERIC_CPU_AUTOPROBE=y ++CONFIG_REGMAP=y ++CONFIG_REGMAP_I2C=y ++CONFIG_REGMAP_SPI=y ++CONFIG_REGMAP_MMIO=y ++CONFIG_DMA_SHARED_BUFFER=y ++# CONFIG_DMA_FENCE_TRACE is not set ++# end of Generic Driver Options ++ ++# ++# Bus devices ++# ++# CONFIG_BRCMSTB_GISB_ARB is not set ++# CONFIG_MOXTET is not set ++# CONFIG_MIPS_CDMM is not set ++# CONFIG_SIMPLE_PM_BUS is not set ++# CONFIG_MHI_BUS is not set ++# end of Bus devices ++ ++# CONFIG_CONNECTOR is not set ++# CONFIG_GNSS is not set ++CONFIG_MTD=y ++# CONFIG_MTD_TESTS is not set ++ ++# ++# Partition parsers ++# ++# CONFIG_MTD_AR7_PARTS is not set ++# CONFIG_MTD_CMDLINE_PARTS is not set ++CONFIG_MTD_OF_PARTS=y ++# CONFIG_MTD_REDBOOT_PARTS is not set ++# end of Partition parsers ++ ++# ++# User Modules And Translation Layers ++# ++CONFIG_MTD_BLKDEVS=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_MTD_BLOCK_BBT_RO is not set ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++# CONFIG_INFTL is not set ++# CONFIG_RFD_FTL is not set ++# CONFIG_SSFDC is not set ++# CONFIG_SM_FTL is not set ++# CONFIG_MTD_OOPS is not set ++# CONFIG_MTD_PARTITIONED_MASTER is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++# CONFIG_MTD_CFI is not set ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_MAP_BANK_WIDTH_1=y ++CONFIG_MTD_MAP_BANK_WIDTH_2=y ++CONFIG_MTD_MAP_BANK_WIDTH_4=y ++CONFIG_MTD_CFI_I1=y ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# end of RAM/ROM/Flash chip drivers ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_COMPLEX_MAPPINGS is not set ++# CONFIG_MTD_PLATRAM is not set ++# end of Mapping drivers for chip access ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_DATAFLASH is not set ++# CONFIG_MTD_MCHP23K256 is not set ++# CONFIG_MTD_SST25L is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_PHRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLOCK2MTD is not set ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_DOCG3 is not set ++# end of Self-contained MTD device drivers ++ ++# ++# NAND ++# ++CONFIG_MTD_NAND_CORE=y ++# CONFIG_MTD_ONENAND is not set ++CONFIG_MTD_NAND_ECC_SW_HAMMING=y ++# CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC is not set ++CONFIG_MTD_RAW_NAND=y ++# CONFIG_MTD_NAND_ECC_SW_BCH is not set ++ ++# ++# Raw/parallel NAND flash controllers ++# ++# CONFIG_MTD_NAND_DENALI_DT is not set ++# CONFIG_MTD_NAND_BRCMNAND is not set ++# CONFIG_MTD_NAND_MXIC is not set ++# CONFIG_MTD_NAND_GPIO is not set ++# CONFIG_MTD_NAND_PLATFORM is not set ++# CONFIG_MTD_NAND_CADENCE is not set ++# CONFIG_MTD_NAND_ARASAN is not set ++ ++# ++# Misc ++# ++# CONFIG_MTD_NAND_NANDSIM is not set ++# CONFIG_MTD_NAND_DISKONCHIP is not set ++# CONFIG_MTD_SPI_NAND is not set ++ ++# ++# ECC engine support ++# ++CONFIG_MTD_NAND_ECC=y ++# end of ECC engine support ++# end of NAND ++ ++# ++# LPDDR & LPDDR2 PCM memory drivers ++# ++# CONFIG_MTD_LPDDR is not set ++# end of LPDDR & LPDDR2 PCM memory drivers ++ ++# CONFIG_MTD_SPI_NOR is not set ++CONFIG_MTD_UBI=y ++CONFIG_MTD_UBI_WL_THRESHOLD=4096 ++CONFIG_MTD_UBI_BEB_LIMIT=20 ++# CONFIG_MTD_UBI_FASTMAP is not set ++# CONFIG_MTD_UBI_GLUEBI is not set ++# CONFIG_MTD_UBI_BLOCK is not set ++# CONFIG_MTD_HYPERBUS is not set ++CONFIG_DTC=y ++CONFIG_OF=y ++# CONFIG_OF_UNITTEST is not set ++CONFIG_OF_FLATTREE=y ++CONFIG_OF_EARLY_FLATTREE=y ++CONFIG_OF_KOBJ=y ++CONFIG_OF_ADDRESS=y ++CONFIG_OF_IRQ=y ++CONFIG_OF_NET=y ++CONFIG_OF_RESERVED_MEM=y ++# CONFIG_OF_OVERLAY is not set ++# CONFIG_PARPORT is not set ++CONFIG_BLK_DEV=y ++# CONFIG_BLK_DEV_NULL_BLK is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_DRBD is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_CDROM_PKTCDVD is not set ++# CONFIG_ATA_OVER_ETH is not set ++# CONFIG_BLK_DEV_RBD is not set ++ ++# ++# NVME Support ++# ++# CONFIG_NVME_FC is not set ++# CONFIG_NVME_TCP is not set ++# CONFIG_NVME_TARGET is not set ++# end of NVME Support ++ ++# ++# Misc devices ++# ++# CONFIG_AD525X_DPOT is not set ++# CONFIG_DUMMY_IRQ is not set ++# CONFIG_ICS932S401 is not set ++# CONFIG_ENCLOSURE_SERVICES is not set ++# CONFIG_APDS9802ALS is not set ++# CONFIG_ISL29003 is not set ++# CONFIG_ISL29020 is not set ++# CONFIG_SENSORS_TSL2550 is not set ++# CONFIG_SENSORS_BH1770 is not set ++# CONFIG_SENSORS_APDS990X is not set ++# CONFIG_HMC6352 is not set ++# CONFIG_DS1682 is not set ++# CONFIG_LATTICE_ECP3_CONFIG is not set ++# CONFIG_SRAM is not set ++# CONFIG_XILINX_SDFEC is not set ++# CONFIG_PVPANIC is not set ++# CONFIG_HISI_HIKEY_USB is not set ++# CONFIG_C2PORT is not set ++ ++# ++# EEPROM support ++# ++# CONFIG_EEPROM_AT24 is not set ++# CONFIG_EEPROM_AT25 is not set ++# CONFIG_EEPROM_LEGACY is not set ++# CONFIG_EEPROM_MAX6875 is not set ++# CONFIG_EEPROM_93CX6 is not set ++# CONFIG_EEPROM_93XX46 is not set ++# CONFIG_EEPROM_IDT_89HPESX is not set ++# CONFIG_EEPROM_EE1004 is not set ++# end of EEPROM support ++ ++# ++# Texas Instruments shared transport line discipline ++# ++# CONFIG_TI_ST is not set ++# end of Texas Instruments shared transport line discipline ++ ++# CONFIG_SENSORS_LIS3_SPI is not set ++# CONFIG_SENSORS_LIS3_I2C is not set ++# CONFIG_ALTERA_STAPL is not set ++# CONFIG_ECHO is not set ++# CONFIG_MISC_RTSX_USB is not set ++# end of Misc devices ++ ++CONFIG_HAVE_IDE=y ++# CONFIG_IDE is not set ++ ++# ++# SCSI device support ++# ++CONFIG_SCSI_MOD=y ++# CONFIG_RAID_ATTRS is not set ++CONFIG_SCSI=y ++CONFIG_SCSI_DMA=y ++CONFIG_SCSI_PROC_FS=y ++ ++# ++# SCSI support type (disk, tape, CD-ROM) ++# ++CONFIG_BLK_DEV_SD=y ++# CONFIG_CHR_DEV_ST is not set ++# CONFIG_BLK_DEV_SR is not set ++# CONFIG_CHR_DEV_SG is not set ++# CONFIG_CHR_DEV_SCH is not set ++# CONFIG_SCSI_CONSTANTS is not set ++# CONFIG_SCSI_LOGGING is not set ++# CONFIG_SCSI_SCAN_ASYNC is not set ++ ++# ++# SCSI Transports ++# ++# CONFIG_SCSI_SPI_ATTRS is not set ++# CONFIG_SCSI_FC_ATTRS is not set ++# CONFIG_SCSI_ISCSI_ATTRS is not set ++# CONFIG_SCSI_SAS_ATTRS is not set ++# CONFIG_SCSI_SAS_LIBSAS is not set ++# CONFIG_SCSI_SRP_ATTRS is not set ++# end of SCSI Transports ++ ++CONFIG_SCSI_LOWLEVEL=y ++# CONFIG_ISCSI_TCP is not set ++# CONFIG_ISCSI_BOOT_SYSFS is not set ++# CONFIG_SCSI_UFSHCD is not set ++# CONFIG_SCSI_DEBUG is not set ++# CONFIG_SCSI_DH is not set ++# end of SCSI device support ++ ++# CONFIG_ATA is not set ++# CONFIG_MD is not set ++# CONFIG_TARGET_CORE is not set ++CONFIG_NETDEVICES=y ++CONFIG_MII=y ++CONFIG_NET_CORE=y ++# CONFIG_BONDING is not set ++# CONFIG_DUMMY is not set ++# CONFIG_WIREGUARD is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_NET_TEAM is not set ++# CONFIG_MACVLAN is not set ++# CONFIG_IPVLAN is not set ++# CONFIG_VXLAN is not set ++# CONFIG_GENEVE is not set ++# CONFIG_BAREUDP is not set ++# CONFIG_GTP is not set ++# CONFIG_MACSEC is not set ++# CONFIG_NETCONSOLE is not set ++# CONFIG_TUN is not set ++# CONFIG_TUN_VNET_CROSS_LE is not set ++# CONFIG_VETH is not set ++# CONFIG_NLMON is not set ++ ++# ++# Distributed Switch Architecture drivers ++# ++# end of Distributed Switch Architecture drivers ++ ++CONFIG_ETHERNET=y ++CONFIG_NET_VENDOR_ALACRITECH=y ++# CONFIG_ALTERA_TSE is not set ++CONFIG_NET_VENDOR_AMAZON=y ++CONFIG_NET_VENDOR_AQUANTIA=y ++# CONFIG_NET_VENDOR_ARC is not set ++# CONFIG_NET_VENDOR_AURORA is not set ++# CONFIG_NET_VENDOR_BROADCOM is not set ++CONFIG_NET_VENDOR_CADENCE=y ++# CONFIG_MACB is not set ++CONFIG_NET_VENDOR_CAVIUM=y ++CONFIG_NET_VENDOR_CORTINA=y ++# CONFIG_GEMINI_ETHERNET is not set ++# CONFIG_DM9000 is not set ++# CONFIG_DNET is not set ++# CONFIG_NET_VENDOR_EZCHIP is not set ++CONFIG_NET_VENDOR_GOOGLE=y ++CONFIG_NET_VENDOR_HUAWEI=y ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++CONFIG_NET_VENDOR_MELLANOX=y ++# CONFIG_MLXSW_CORE is not set ++# CONFIG_MLXFW is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++CONFIG_NET_VENDOR_MICROCHIP=y ++# CONFIG_ENC28J60 is not set ++# CONFIG_ENCX24J600 is not set ++CONFIG_NET_VENDOR_MICROSEMI=y ++# CONFIG_NET_VENDOR_NATSEMI is not set ++CONFIG_NET_VENDOR_NETRONOME=y ++CONFIG_NET_VENDOR_NI=y ++# CONFIG_NI_XGE_MANAGEMENT_ENET is not set ++# CONFIG_ETHOC is not set ++CONFIG_NET_VENDOR_PENSANDO=y ++# CONFIG_NET_VENDOR_QUALCOMM is not set ++# CONFIG_NET_VENDOR_RENESAS is not set ++# CONFIG_NET_VENDOR_ROCKER is not set ++# CONFIG_NET_VENDOR_SAMSUNG is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++CONFIG_NET_VENDOR_SOLARFLARE=y ++# CONFIG_NET_VENDOR_SMSC is not set ++CONFIG_NET_VENDOR_SOCIONEXT=y ++# CONFIG_NET_VENDOR_STMICRO is not set ++# CONFIG_NET_VENDOR_SYNOPSYS is not set ++# CONFIG_NET_VENDOR_VIA is not set ++# CONFIG_NET_VENDOR_WIZNET is not set ++CONFIG_NET_VENDOR_XILINX=y ++# CONFIG_XILINX_EMACLITE is not set ++# CONFIG_XILINX_AXI_EMAC is not set ++# CONFIG_XILINX_LL_TEMAC is not set ++CONFIG_PHYLIB=y ++CONFIG_SWPHY=y ++CONFIG_FIXED_PHY=y ++ ++# ++# MII PHY device drivers ++# ++# CONFIG_AMD_PHY is not set ++# CONFIG_ADIN_PHY is not set ++# CONFIG_AQUANTIA_PHY is not set ++# CONFIG_AX88796B_PHY is not set ++# CONFIG_BROADCOM_PHY is not set ++# CONFIG_BCM54140_PHY is not set ++# CONFIG_BCM7XXX_PHY is not set ++# CONFIG_BCM84881_PHY is not set ++# CONFIG_BCM87XX_PHY is not set ++# CONFIG_CICADA_PHY is not set ++# CONFIG_CORTINA_PHY is not set ++# CONFIG_DAVICOM_PHY is not set ++# CONFIG_ICPLUS_PHY is not set ++# CONFIG_LXT_PHY is not set ++# CONFIG_INTEL_XWAY_PHY is not set ++# CONFIG_LSI_ET1011C_PHY is not set ++# CONFIG_MARVELL_PHY is not set ++# CONFIG_MARVELL_10G_PHY is not set ++# CONFIG_MICREL_PHY is not set ++# CONFIG_MICROCHIP_PHY is not set ++# CONFIG_MICROCHIP_T1_PHY is not set ++# CONFIG_MICROSEMI_PHY is not set ++# CONFIG_NATIONAL_PHY is not set ++# CONFIG_QSEMI_PHY is not set ++# CONFIG_REALTEK_PHY is not set ++# CONFIG_RENESAS_PHY is not set ++# CONFIG_ROCKCHIP_PHY is not set ++# CONFIG_SMSC_PHY is not set ++# CONFIG_STE10XP is not set ++# CONFIG_TERANETICS_PHY is not set ++# CONFIG_DP83822_PHY is not set ++# CONFIG_DP83TC811_PHY is not set ++# CONFIG_DP83848_PHY is not set ++# CONFIG_DP83867_PHY is not set ++# CONFIG_DP83869_PHY is not set ++# CONFIG_VITESSE_PHY is not set ++# CONFIG_XILINX_GMII2RGMII is not set ++# CONFIG_MICREL_KS8995MA is not set ++CONFIG_MDIO_DEVICE=y ++CONFIG_MDIO_BUS=y ++CONFIG_OF_MDIO=y ++CONFIG_MDIO_DEVRES=y ++# CONFIG_MDIO_BITBANG is not set ++# CONFIG_MDIO_BCM_UNIMAC is not set ++# CONFIG_MDIO_HISI_FEMAC is not set ++# CONFIG_MDIO_MVUSB is not set ++# CONFIG_MDIO_MSCC_MIIM is not set ++# CONFIG_MDIO_IPQ4019 is not set ++# CONFIG_MDIO_IPQ8064 is not set ++ ++# ++# MDIO Multiplexers ++# ++# CONFIG_MDIO_BUS_MUX_GPIO is not set ++# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set ++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set ++ ++# ++# PCS device drivers ++# ++# CONFIG_PCS_XPCS is not set ++# end of PCS device drivers ++ ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++CONFIG_USB_NET_DRIVERS=y ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_RTL8150 is not set ++# CONFIG_USB_RTL8152 is not set ++# CONFIG_USB_LAN78XX is not set ++# CONFIG_USB_USBNET is not set ++# CONFIG_USB_HSO is not set ++# CONFIG_USB_IPHETH is not set ++CONFIG_WLAN=y ++# CONFIG_WIRELESS_WDS is not set ++# CONFIG_WLAN_VENDOR_ADMTEK is not set ++# CONFIG_WLAN_VENDOR_ATH is not set ++# CONFIG_WLAN_VENDOR_ATMEL is not set ++# CONFIG_WLAN_VENDOR_BROADCOM is not set ++# CONFIG_WLAN_VENDOR_CISCO is not set ++# CONFIG_WLAN_VENDOR_INTEL is not set ++# CONFIG_WLAN_VENDOR_INTERSIL is not set ++# CONFIG_WLAN_VENDOR_MARVELL is not set ++# CONFIG_WLAN_VENDOR_MEDIATEK is not set ++# CONFIG_WLAN_VENDOR_MICROCHIP is not set ++# CONFIG_WLAN_VENDOR_RALINK is not set ++# CONFIG_WLAN_VENDOR_REALTEK is not set ++# CONFIG_WLAN_VENDOR_RSI is not set ++# CONFIG_WLAN_VENDOR_ST is not set ++# CONFIG_WLAN_VENDOR_TI is not set ++# CONFIG_WLAN_VENDOR_ZYDAS is not set ++# CONFIG_WLAN_VENDOR_QUANTENNA is not set ++# CONFIG_MAC80211_HWSIM is not set ++# CONFIG_USB_NET_RNDIS_WLAN is not set ++# CONFIG_VIRT_WIFI is not set ++ ++# ++# Enable WiMAX (Networking options) to see the WiMAX drivers ++# ++# CONFIG_WAN is not set ++# CONFIG_NETDEVSIM is not set ++# CONFIG_NET_FAILOVER is not set ++# CONFIG_ISDN is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_FF_MEMLESS is not set ++# CONFIG_INPUT_POLLDEV is not set ++# CONFIG_INPUT_SPARSEKMAP is not set ++# CONFIG_INPUT_MATRIXKMAP is not set ++ ++# ++# Userland interfaces ++# ++CONFIG_INPUT_MOUSEDEV=y ++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 ++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_EVBUG is not set ++ ++# ++# Input Device Drivers ++# ++CONFIG_INPUT_KEYBOARD=y ++# CONFIG_KEYBOARD_ADP5588 is not set ++# CONFIG_KEYBOARD_ADP5589 is not set ++CONFIG_KEYBOARD_ATKBD=y ++# CONFIG_KEYBOARD_QT1050 is not set ++# CONFIG_KEYBOARD_QT1070 is not set ++# CONFIG_KEYBOARD_QT2160 is not set ++# CONFIG_KEYBOARD_DLINK_DIR685 is not set ++# CONFIG_KEYBOARD_LKKBD is not set ++CONFIG_KEYBOARD_GPIO=y ++# CONFIG_KEYBOARD_GPIO_POLLED is not set ++# CONFIG_KEYBOARD_TCA6416 is not set ++# CONFIG_KEYBOARD_TCA8418 is not set ++# CONFIG_KEYBOARD_MATRIX is not set ++# CONFIG_KEYBOARD_LM8333 is not set ++# CONFIG_KEYBOARD_MAX7359 is not set ++# CONFIG_KEYBOARD_MCS is not set ++# CONFIG_KEYBOARD_MPR121 is not set ++# CONFIG_KEYBOARD_NEWTON is not set ++# CONFIG_KEYBOARD_OPENCORES is not set ++# CONFIG_KEYBOARD_SAMSUNG is not set ++# CONFIG_KEYBOARD_STOWAWAY is not set ++# CONFIG_KEYBOARD_SUNKBD is not set ++# CONFIG_KEYBOARD_OMAP4 is not set ++# CONFIG_KEYBOARD_XTKBD is not set ++# CONFIG_KEYBOARD_CAP11XX is not set ++# CONFIG_KEYBOARD_BCM is not set ++# CONFIG_INPUT_MOUSE is not set ++# CONFIG_INPUT_JOYSTICK is not set ++# CONFIG_INPUT_TABLET is not set ++# CONFIG_INPUT_TOUCHSCREEN is not set ++# CONFIG_INPUT_MISC is not set ++# CONFIG_RMI4_CORE is not set ++ ++# ++# Hardware I/O ports ++# ++CONFIG_SERIO=y ++CONFIG_SERIO_SERPORT=y ++CONFIG_SERIO_LIBPS2=y ++# CONFIG_SERIO_RAW is not set ++# CONFIG_SERIO_ALTERA_PS2 is not set ++# CONFIG_SERIO_PS2MULT is not set ++# CONFIG_SERIO_ARC_PS2 is not set ++# CONFIG_SERIO_APBPS2 is not set ++# CONFIG_SERIO_GPIO_PS2 is not set ++# CONFIG_USERIO is not set ++# CONFIG_GAMEPORT is not set ++# end of Hardware I/O ports ++# end of Input device support ++ ++# ++# Character devices ++# ++CONFIG_TTY=y ++CONFIG_VT=y ++CONFIG_CONSOLE_TRANSLATIONS=y ++CONFIG_VT_CONSOLE=y ++CONFIG_VT_CONSOLE_SLEEP=y ++CONFIG_HW_CONSOLE=y ++CONFIG_VT_HW_CONSOLE_BINDING=y ++CONFIG_UNIX98_PTYS=y ++CONFIG_LEGACY_PTYS=y ++CONFIG_LEGACY_PTY_COUNT=256 ++CONFIG_LDISC_AUTOLOAD=y ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_8250 is not set ++ ++# ++# Non-8250 serial port support ++# ++# CONFIG_SERIAL_MAX3100 is not set ++# CONFIG_SERIAL_MAX310X is not set ++# CONFIG_SERIAL_UARTLITE is not set ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++# CONFIG_SERIAL_SIFIVE is not set ++# CONFIG_SERIAL_SCCNXP is not set ++# CONFIG_SERIAL_SC16IS7XX is not set ++# CONFIG_SERIAL_BCM63XX is not set ++# CONFIG_SERIAL_ALTERA_JTAGUART is not set ++# CONFIG_SERIAL_ALTERA_UART is not set ++# CONFIG_SERIAL_IFX6X60 is not set ++# CONFIG_SERIAL_XILINX_PS_UART is not set ++# CONFIG_SERIAL_ARC is not set ++# CONFIG_SERIAL_FSL_LPUART is not set ++# CONFIG_SERIAL_FSL_LINFLEXUART is not set ++# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set ++# CONFIG_SERIAL_SPRD is not set ++# end of Serial drivers ++ ++# CONFIG_SERIAL_NONSTANDARD is not set ++# CONFIG_N_GSM is not set ++CONFIG_NULL_TTY=y ++# CONFIG_TRACE_SINK is not set ++CONFIG_SERIAL_DEV_BUS=y ++CONFIG_SERIAL_DEV_CTRL_TTYPORT=y ++CONFIG_TTY_PRINTK=y ++CONFIG_TTY_PRINTK_LEVEL=6 ++# CONFIG_VIRTIO_CONSOLE is not set ++# CONFIG_IPMI_HANDLER is not set ++CONFIG_HW_RANDOM=y ++# CONFIG_HW_RANDOM_TIMERIOMEM is not set ++# CONFIG_HW_RANDOM_BA431 is not set ++# CONFIG_HW_RANDOM_CCTRNG is not set ++# CONFIG_HW_RANDOM_XIPHERA is not set ++CONFIG_DEVMEM=y ++# CONFIG_DEVKMEM is not set ++# CONFIG_RAW_DRIVER is not set ++# CONFIG_TCG_TPM is not set ++# CONFIG_XILLYBUS is not set ++# end of Character devices ++ ++# CONFIG_RANDOM_TRUST_BOOTLOADER is not set ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++CONFIG_I2C_BOARDINFO=y ++CONFIG_I2C_COMPAT=y ++# CONFIG_I2C_CHARDEV is not set ++CONFIG_I2C_MUX=y ++ ++# ++# Multiplexer I2C Chip support ++# ++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set ++# CONFIG_I2C_MUX_GPIO is not set ++# CONFIG_I2C_MUX_GPMUX is not set ++# CONFIG_I2C_MUX_LTC4306 is not set ++# CONFIG_I2C_MUX_PCA9541 is not set ++# CONFIG_I2C_MUX_PCA954x is not set ++# CONFIG_I2C_MUX_PINCTRL is not set ++# CONFIG_I2C_MUX_REG is not set ++# CONFIG_I2C_DEMUX_PINCTRL is not set ++# CONFIG_I2C_MUX_MLXCPLD is not set ++# end of Multiplexer I2C Chip support ++ ++CONFIG_I2C_HELPER_AUTO=y ++ ++# ++# I2C Hardware Bus support ++# ++ ++# ++# I2C system bus drivers (mostly embedded / system-on-chip) ++# ++# CONFIG_I2C_CBUS_GPIO is not set ++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set ++# CONFIG_I2C_EMEV2 is not set ++# CONFIG_I2C_GPIO is not set ++# CONFIG_I2C_IMG is not set ++# CONFIG_I2C_JZ4780 is not set ++# CONFIG_I2C_OCORES is not set ++# CONFIG_I2C_PCA_PLATFORM is not set ++# CONFIG_I2C_RK3X is not set ++# CONFIG_I2C_SIMTEC is not set ++# CONFIG_I2C_XILINX is not set ++ ++# ++# External I2C/SMBus adapter drivers ++# ++# CONFIG_I2C_DIOLAN_U2C is not set ++# CONFIG_I2C_ROBOTFUZZ_OSIF is not set ++# CONFIG_I2C_TAOS_EVM is not set ++# CONFIG_I2C_TINY_USB is not set ++ ++# ++# Other I2C/SMBus bus drivers ++# ++# end of I2C Hardware Bus support ++ ++# CONFIG_I2C_STUB is not set ++# CONFIG_I2C_SLAVE is not set ++# CONFIG_I2C_DEBUG_CORE is not set ++# CONFIG_I2C_DEBUG_ALGO is not set ++# CONFIG_I2C_DEBUG_BUS is not set ++# end of I2C support ++ ++# CONFIG_I3C is not set ++CONFIG_SPI=y ++# CONFIG_SPI_DEBUG is not set ++CONFIG_SPI_MASTER=y ++# CONFIG_SPI_MEM is not set ++ ++# ++# SPI Master Controller Drivers ++# ++# CONFIG_SPI_ALTERA is not set ++# CONFIG_SPI_AXI_SPI_ENGINE is not set ++CONFIG_SPI_BITBANG=y ++# CONFIG_SPI_CADENCE is not set ++# CONFIG_SPI_DESIGNWARE is not set ++# CONFIG_SPI_NXP_FLEXSPI is not set ++# CONFIG_SPI_GPIO is not set ++# CONFIG_SPI_IMG_SPFI is not set ++# CONFIG_SPI_FSL_SPI is not set ++# CONFIG_SPI_OC_TINY is not set ++# CONFIG_SPI_ROCKCHIP is not set ++# CONFIG_SPI_SC18IS602 is not set ++# CONFIG_SPI_SIFIVE is not set ++# CONFIG_SPI_MXIC is not set ++# CONFIG_SPI_XCOMM is not set ++# CONFIG_SPI_XILINX is not set ++# CONFIG_SPI_ZYNQMP_GQSPI is not set ++# CONFIG_SPI_AMD is not set ++ ++# ++# SPI Multiplexer support ++# ++# CONFIG_SPI_MUX is not set ++ ++# ++# SPI Protocol Masters ++# ++CONFIG_SPI_SPIDEV=y ++# CONFIG_SPI_LOOPBACK_TEST is not set ++# CONFIG_SPI_TLE62X0 is not set ++# CONFIG_SPI_SLAVE is not set ++# CONFIG_SPMI is not set ++# CONFIG_HSI is not set ++# CONFIG_PPS is not set ++ ++# ++# PTP clock support ++# ++# CONFIG_PTP_1588_CLOCK is not set ++# end of PTP clock support ++ ++CONFIG_PINCTRL=y ++CONFIG_GENERIC_PINCTRL_GROUPS=y ++CONFIG_PINMUX=y ++CONFIG_GENERIC_PINMUX_FUNCTIONS=y ++CONFIG_PINCONF=y ++CONFIG_GENERIC_PINCONF=y ++# CONFIG_DEBUG_PINCTRL is not set ++# CONFIG_PINCTRL_MCP23S08 is not set ++# CONFIG_PINCTRL_SINGLE is not set ++# CONFIG_PINCTRL_SX150X is not set ++# CONFIG_PINCTRL_STMFX is not set ++# CONFIG_PINCTRL_INGENIC is not set ++# CONFIG_PINCTRL_OCELOT is not set ++ ++# ++# Renesas pinctrl drivers ++# ++# end of Renesas pinctrl drivers ++ ++CONFIG_GPIOLIB=y ++CONFIG_GPIOLIB_FASTPATH_LIMIT=512 ++CONFIG_OF_GPIO=y ++CONFIG_GPIOLIB_IRQCHIP=y ++# CONFIG_DEBUG_GPIO is not set ++CONFIG_GPIO_SYSFS=y ++CONFIG_GPIO_CDEV=y ++CONFIG_GPIO_CDEV_V1=y ++ ++# ++# Memory mapped GPIO drivers ++# ++# CONFIG_GPIO_74XX_MMIO is not set ++# CONFIG_GPIO_ALTERA is not set ++# CONFIG_GPIO_CADENCE is not set ++# CONFIG_GPIO_DWAPB is not set ++# CONFIG_GPIO_FTGPIO010 is not set ++# CONFIG_GPIO_GENERIC_PLATFORM is not set ++# CONFIG_GPIO_GRGPIO is not set ++# CONFIG_GPIO_HLWD is not set ++# CONFIG_GPIO_LOGICVC is not set ++# CONFIG_GPIO_MB86S7X is not set ++# CONFIG_GPIO_SAMA5D2_PIOBU is not set ++# CONFIG_GPIO_SIFIVE is not set ++# CONFIG_GPIO_SYSCON is not set ++# CONFIG_GPIO_XILINX is not set ++# CONFIG_GPIO_AMD_FCH is not set ++# end of Memory mapped GPIO drivers ++ ++# ++# I2C GPIO expanders ++# ++# CONFIG_GPIO_ADP5588 is not set ++# CONFIG_GPIO_ADNP is not set ++# CONFIG_GPIO_GW_PLD is not set ++# CONFIG_GPIO_MAX7300 is not set ++# CONFIG_GPIO_MAX732X is not set ++# CONFIG_GPIO_PCA953X is not set ++# CONFIG_GPIO_PCA9570 is not set ++# CONFIG_GPIO_PCF857X is not set ++# CONFIG_GPIO_TPIC2810 is not set ++# end of I2C GPIO expanders ++ ++# ++# MFD GPIO expanders ++# ++# end of MFD GPIO expanders ++ ++# ++# SPI GPIO expanders ++# ++# CONFIG_GPIO_74X164 is not set ++# CONFIG_GPIO_MAX3191X is not set ++# CONFIG_GPIO_MAX7301 is not set ++# CONFIG_GPIO_MC33880 is not set ++# CONFIG_GPIO_PISOSR is not set ++# CONFIG_GPIO_XRA1403 is not set ++# end of SPI GPIO expanders ++ ++# ++# USB GPIO expanders ++# ++# end of USB GPIO expanders ++ ++# CONFIG_GPIO_AGGREGATOR is not set ++# CONFIG_GPIO_MOCKUP is not set ++# CONFIG_W1 is not set ++# CONFIG_POWER_RESET is not set ++# CONFIG_POWER_SUPPLY is not set ++# CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set ++CONFIG_WATCHDOG=y ++CONFIG_WATCHDOG_CORE=y ++# CONFIG_WATCHDOG_NOWAYOUT is not set ++CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y ++CONFIG_WATCHDOG_OPEN_TIMEOUT=0 ++# CONFIG_WATCHDOG_SYSFS is not set ++ ++# ++# Watchdog Pretimeout Governors ++# ++# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set ++ ++# ++# Watchdog Device Drivers ++# ++# CONFIG_SOFT_WATCHDOG is not set ++# CONFIG_GPIO_WATCHDOG is not set ++# CONFIG_XILINX_WATCHDOG is not set ++# CONFIG_ZIIRAVE_WATCHDOG is not set ++# CONFIG_CADENCE_WATCHDOG is not set ++# CONFIG_DW_WATCHDOG is not set ++# CONFIG_MAX63XX_WATCHDOG is not set ++# CONFIG_JZ4740_WDT is not set ++# CONFIG_IMGPDC_WDT is not set ++# CONFIG_MEN_A21_WDT is not set ++ ++# ++# USB-based Watchdog Cards ++# ++# CONFIG_USBPCWATCHDOG is not set ++CONFIG_SSB_POSSIBLE=y ++# CONFIG_SSB is not set ++CONFIG_BCMA_POSSIBLE=y ++# CONFIG_BCMA is not set ++ ++# ++# Multifunction device drivers ++# ++CONFIG_MFD_CORE=y ++# CONFIG_MFD_ACT8945A is not set ++# CONFIG_MFD_AS3711 is not set ++# CONFIG_MFD_AS3722 is not set ++# CONFIG_PMIC_ADP5520 is not set ++# CONFIG_MFD_AAT2870_CORE is not set ++# CONFIG_MFD_ATMEL_FLEXCOM is not set ++# CONFIG_MFD_ATMEL_HLCDC is not set ++# CONFIG_MFD_BCM590XX is not set ++# CONFIG_MFD_BD9571MWV is not set ++# CONFIG_MFD_AXP20X_I2C is not set ++# CONFIG_MFD_MADERA is not set ++# CONFIG_PMIC_DA903X is not set ++# CONFIG_MFD_DA9052_SPI is not set ++# CONFIG_MFD_DA9052_I2C is not set ++# CONFIG_MFD_DA9055 is not set ++# CONFIG_MFD_DA9062 is not set ++# CONFIG_MFD_DA9063 is not set ++# CONFIG_MFD_DA9150 is not set ++# CONFIG_MFD_DLN2 is not set ++# CONFIG_MFD_GATEWORKS_GSC is not set ++# CONFIG_MFD_MC13XXX_SPI is not set ++# CONFIG_MFD_MC13XXX_I2C is not set ++# CONFIG_MFD_MP2629 is not set ++# CONFIG_MFD_HI6421_PMIC is not set ++# CONFIG_HTC_PASIC3 is not set ++# CONFIG_HTC_I2CPLD is not set ++# CONFIG_MFD_IQS62X is not set ++# CONFIG_MFD_KEMPLD is not set ++# CONFIG_MFD_88PM800 is not set ++# CONFIG_MFD_88PM805 is not set ++# CONFIG_MFD_88PM860X is not set ++# CONFIG_MFD_MAX14577 is not set ++# CONFIG_MFD_MAX77620 is not set ++# CONFIG_MFD_MAX77650 is not set ++# CONFIG_MFD_MAX77686 is not set ++# CONFIG_MFD_MAX77693 is not set ++# CONFIG_MFD_MAX77843 is not set ++# CONFIG_MFD_MAX8907 is not set ++# CONFIG_MFD_MAX8925 is not set ++# CONFIG_MFD_MAX8997 is not set ++# CONFIG_MFD_MAX8998 is not set ++# CONFIG_MFD_MT6360 is not set ++# CONFIG_MFD_MT6397 is not set ++# CONFIG_MFD_MENF21BMC is not set ++# CONFIG_EZX_PCAP is not set ++# CONFIG_MFD_CPCAP is not set ++# CONFIG_MFD_VIPERBOARD is not set ++# CONFIG_MFD_RETU is not set ++# CONFIG_MFD_PCF50633 is not set ++# CONFIG_MFD_RT5033 is not set ++# CONFIG_MFD_RC5T583 is not set ++# CONFIG_MFD_RK808 is not set ++# CONFIG_MFD_RN5T618 is not set ++# CONFIG_MFD_SEC_CORE is not set ++# CONFIG_MFD_SI476X_CORE is not set ++# CONFIG_MFD_SM501 is not set ++# CONFIG_MFD_SKY81452 is not set ++# CONFIG_ABX500_CORE is not set ++# CONFIG_MFD_STMPE is not set ++CONFIG_MFD_SYSCON=y ++# CONFIG_MFD_TI_AM335X_TSCADC is not set ++# CONFIG_MFD_LP3943 is not set ++# CONFIG_MFD_LP8788 is not set ++# CONFIG_MFD_TI_LMU is not set ++# CONFIG_MFD_PALMAS is not set ++# CONFIG_TPS6105X is not set ++# CONFIG_TPS65010 is not set ++# CONFIG_TPS6507X is not set ++# CONFIG_MFD_TPS65086 is not set ++# CONFIG_MFD_TPS65090 is not set ++# CONFIG_MFD_TPS65217 is not set ++# CONFIG_MFD_TI_LP873X is not set ++# CONFIG_MFD_TI_LP87565 is not set ++# CONFIG_MFD_TPS65218 is not set ++# CONFIG_MFD_TPS6586X is not set ++# CONFIG_MFD_TPS65910 is not set ++# CONFIG_MFD_TPS65912_I2C is not set ++# CONFIG_MFD_TPS65912_SPI is not set ++# CONFIG_MFD_TPS80031 is not set ++# CONFIG_TWL4030_CORE is not set ++# CONFIG_TWL6040_CORE is not set ++# CONFIG_MFD_WL1273_CORE is not set ++# CONFIG_MFD_LM3533 is not set ++# CONFIG_MFD_TC3589X is not set ++# CONFIG_MFD_TQMX86 is not set ++# CONFIG_MFD_LOCHNAGAR is not set ++# CONFIG_MFD_ARIZONA_I2C is not set ++# CONFIG_MFD_ARIZONA_SPI is not set ++# CONFIG_MFD_WM8400 is not set ++# CONFIG_MFD_WM831X_I2C is not set ++# CONFIG_MFD_WM831X_SPI is not set ++# CONFIG_MFD_WM8350_I2C is not set ++# CONFIG_MFD_WM8994 is not set ++# CONFIG_MFD_ROHM_BD718XX is not set ++# CONFIG_MFD_ROHM_BD70528 is not set ++# CONFIG_MFD_ROHM_BD71828 is not set ++# CONFIG_MFD_STPMIC1 is not set ++# CONFIG_MFD_STMFX is not set ++# CONFIG_RAVE_SP_CORE is not set ++# CONFIG_MFD_INTEL_M10_BMC is not set ++# end of Multifunction device drivers ++ ++# CONFIG_REGULATOR is not set ++# CONFIG_RC_CORE is not set ++# CONFIG_MEDIA_CEC_SUPPORT is not set ++CONFIG_MEDIA_SUPPORT=y ++# CONFIG_MEDIA_SUPPORT_FILTER is not set ++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set ++ ++# ++# Media device types ++# ++CONFIG_MEDIA_CAMERA_SUPPORT=y ++CONFIG_MEDIA_ANALOG_TV_SUPPORT=y ++CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y ++CONFIG_MEDIA_RADIO_SUPPORT=y ++CONFIG_MEDIA_SDR_SUPPORT=y ++CONFIG_MEDIA_PLATFORM_SUPPORT=y ++CONFIG_MEDIA_TEST_SUPPORT=y ++# end of Media device types ++ ++# ++# Media core support ++# ++CONFIG_VIDEO_DEV=y ++CONFIG_MEDIA_CONTROLLER=y ++CONFIG_DVB_CORE=y ++# end of Media core support ++ ++# ++# Video4Linux options ++# ++CONFIG_VIDEO_V4L2=y ++CONFIG_VIDEO_V4L2_I2C=y ++CONFIG_VIDEO_V4L2_SUBDEV_API=y ++# CONFIG_VIDEO_ADV_DEBUG is not set ++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set ++CONFIG_V4L2_MEM2MEM_DEV=y ++CONFIG_V4L2_FWNODE=y ++# end of Video4Linux options ++ ++# ++# Media controller options ++# ++# CONFIG_MEDIA_CONTROLLER_DVB is not set ++# end of Media controller options ++ ++# ++# Digital TV options ++# ++# CONFIG_DVB_MMAP is not set ++CONFIG_DVB_NET=y ++CONFIG_DVB_MAX_ADAPTERS=16 ++CONFIG_DVB_DYNAMIC_MINORS=y ++# CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set ++# CONFIG_DVB_ULE_DEBUG is not set ++# end of Digital TV options ++ ++# ++# Media drivers ++# ++CONFIG_MEDIA_USB_SUPPORT=y ++ ++# ++# Webcam devices ++# ++CONFIG_USB_VIDEO_CLASS=y ++CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y ++# CONFIG_USB_GSPCA is not set ++# CONFIG_USB_PWC is not set ++# CONFIG_VIDEO_CPIA2 is not set ++# CONFIG_USB_ZR364XX is not set ++# CONFIG_USB_STKWEBCAM is not set ++# CONFIG_USB_S2255 is not set ++# CONFIG_VIDEO_USBTV is not set ++ ++# ++# Analog TV USB devices ++# ++# CONFIG_VIDEO_PVRUSB2 is not set ++# CONFIG_VIDEO_HDPVR is not set ++# CONFIG_VIDEO_STK1160_COMMON is not set ++# CONFIG_VIDEO_GO7007 is not set ++ ++# ++# Analog/digital TV USB devices ++# ++# CONFIG_VIDEO_AU0828 is not set ++# CONFIG_VIDEO_CX231XX is not set ++ ++# ++# Digital TV USB devices ++# ++# CONFIG_DVB_USB_V2 is not set ++# CONFIG_SMS_USB_DRV is not set ++# CONFIG_DVB_B2C2_FLEXCOP_USB is not set ++# CONFIG_DVB_AS102 is not set ++ ++# ++# Webcam, TV (analog/digital) USB devices ++# ++# CONFIG_VIDEO_EM28XX is not set ++ ++# ++# Software defined radio USB devices ++# ++# CONFIG_USB_AIRSPY is not set ++# CONFIG_USB_HACKRF is not set ++# CONFIG_USB_MSI2500 is not set ++CONFIG_RADIO_ADAPTERS=y ++# CONFIG_RADIO_SI470X is not set ++# CONFIG_RADIO_SI4713 is not set ++# CONFIG_USB_MR800 is not set ++# CONFIG_USB_DSBR is not set ++# CONFIG_RADIO_SHARK is not set ++# CONFIG_RADIO_SHARK2 is not set ++# CONFIG_USB_KEENE is not set ++# CONFIG_USB_RAREMONO is not set ++# CONFIG_USB_MA901 is not set ++# CONFIG_RADIO_TEA5764 is not set ++# CONFIG_RADIO_SAA7706H is not set ++# CONFIG_RADIO_TEF6862 is not set ++# CONFIG_RADIO_WL1273 is not set ++CONFIG_VIDEOBUF2_CORE=y ++CONFIG_VIDEOBUF2_V4L2=y ++CONFIG_VIDEOBUF2_MEMOPS=y ++CONFIG_VIDEOBUF2_DMA_CONTIG=y ++CONFIG_VIDEOBUF2_VMALLOC=y ++CONFIG_VIDEOBUF2_DMA_SG=y ++CONFIG_V4L_PLATFORM_DRIVERS=y ++# CONFIG_VIDEO_CADENCE is not set ++# CONFIG_VIDEO_ASPEED is not set ++# CONFIG_VIDEO_MUX is not set ++# CONFIG_VIDEO_XILINX is not set ++CONFIG_V4L_MEM2MEM_DRIVERS=y ++# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set ++# CONFIG_DVB_PLATFORM_DRIVERS is not set ++# CONFIG_SDR_PLATFORM_DRIVERS is not set ++ ++# ++# MMC/SDIO DVB adapters ++# ++# CONFIG_SMS_SDIO_DRV is not set ++# CONFIG_V4L_TEST_DRIVERS is not set ++# CONFIG_DVB_TEST_DRIVERS is not set ++# end of Media drivers ++ ++# ++# Media ancillary drivers ++# ++CONFIG_MEDIA_ATTACH=y ++ ++# ++# Audio decoders, processors and mixers ++# ++# CONFIG_VIDEO_TVAUDIO is not set ++# CONFIG_VIDEO_TDA7432 is not set ++# CONFIG_VIDEO_TDA9840 is not set ++# CONFIG_VIDEO_TDA1997X is not set ++# CONFIG_VIDEO_TEA6415C is not set ++# CONFIG_VIDEO_TEA6420 is not set ++# CONFIG_VIDEO_MSP3400 is not set ++# CONFIG_VIDEO_CS3308 is not set ++# CONFIG_VIDEO_CS5345 is not set ++# CONFIG_VIDEO_CS53L32A is not set ++# CONFIG_VIDEO_TLV320AIC23B is not set ++# CONFIG_VIDEO_UDA1342 is not set ++# CONFIG_VIDEO_WM8775 is not set ++# CONFIG_VIDEO_WM8739 is not set ++# CONFIG_VIDEO_VP27SMPX is not set ++# CONFIG_VIDEO_SONY_BTF_MPX is not set ++# end of Audio decoders, processors and mixers ++ ++# ++# RDS decoders ++# ++# CONFIG_VIDEO_SAA6588 is not set ++# end of RDS decoders ++ ++# ++# Video decoders ++# ++# CONFIG_VIDEO_ADV7180 is not set ++# CONFIG_VIDEO_ADV7183 is not set ++# CONFIG_VIDEO_ADV748X is not set ++# CONFIG_VIDEO_ADV7604 is not set ++# CONFIG_VIDEO_ADV7842 is not set ++# CONFIG_VIDEO_BT819 is not set ++# CONFIG_VIDEO_BT856 is not set ++# CONFIG_VIDEO_BT866 is not set ++# CONFIG_VIDEO_KS0127 is not set ++# CONFIG_VIDEO_ML86V7667 is not set ++# CONFIG_VIDEO_SAA7110 is not set ++# CONFIG_VIDEO_SAA711X is not set ++# CONFIG_VIDEO_TC358743 is not set ++# CONFIG_VIDEO_TVP514X is not set ++# CONFIG_VIDEO_TVP5150 is not set ++# CONFIG_VIDEO_TVP7002 is not set ++# CONFIG_VIDEO_TW2804 is not set ++# CONFIG_VIDEO_TW9903 is not set ++# CONFIG_VIDEO_TW9906 is not set ++# CONFIG_VIDEO_TW9910 is not set ++# CONFIG_VIDEO_VPX3220 is not set ++# CONFIG_VIDEO_MAX9286 is not set ++ ++# ++# Video and audio decoders ++# ++# CONFIG_VIDEO_SAA717X is not set ++# CONFIG_VIDEO_CX25840 is not set ++# end of Video decoders ++ ++# ++# Video encoders ++# ++# CONFIG_VIDEO_SAA7127 is not set ++# CONFIG_VIDEO_SAA7185 is not set ++# CONFIG_VIDEO_ADV7170 is not set ++# CONFIG_VIDEO_ADV7175 is not set ++# CONFIG_VIDEO_ADV7343 is not set ++# CONFIG_VIDEO_ADV7393 is not set ++# CONFIG_VIDEO_ADV7511 is not set ++# CONFIG_VIDEO_AD9389B is not set ++# CONFIG_VIDEO_AK881X is not set ++# CONFIG_VIDEO_THS8200 is not set ++# end of Video encoders ++ ++# ++# Video improvement chips ++# ++# CONFIG_VIDEO_UPD64031A is not set ++# CONFIG_VIDEO_UPD64083 is not set ++# end of Video improvement chips ++ ++# ++# Audio/Video compression chips ++# ++# CONFIG_VIDEO_SAA6752HS is not set ++# end of Audio/Video compression chips ++ ++# ++# SDR tuner chips ++# ++# CONFIG_SDR_MAX2175 is not set ++# end of SDR tuner chips ++ ++# ++# Miscellaneous helper chips ++# ++# CONFIG_VIDEO_THS7303 is not set ++# CONFIG_VIDEO_M52790 is not set ++# CONFIG_VIDEO_I2C is not set ++# CONFIG_VIDEO_ST_MIPID02 is not set ++# end of Miscellaneous helper chips ++ ++# ++# Camera sensor devices ++# ++# CONFIG_VIDEO_HI556 is not set ++# CONFIG_VIDEO_IMX214 is not set ++# CONFIG_VIDEO_IMX219 is not set ++# CONFIG_VIDEO_IMX258 is not set ++# CONFIG_VIDEO_IMX274 is not set ++# CONFIG_VIDEO_IMX290 is not set ++# CONFIG_VIDEO_IMX319 is not set ++# CONFIG_VIDEO_IMX355 is not set ++# CONFIG_VIDEO_OV2640 is not set ++# CONFIG_VIDEO_OV2659 is not set ++# CONFIG_VIDEO_OV2680 is not set ++# CONFIG_VIDEO_OV2685 is not set ++# CONFIG_VIDEO_OV5640 is not set ++# CONFIG_VIDEO_OV5645 is not set ++# CONFIG_VIDEO_OV5647 is not set ++# CONFIG_VIDEO_OV6650 is not set ++# CONFIG_VIDEO_OV5670 is not set ++# CONFIG_VIDEO_OV5675 is not set ++# CONFIG_VIDEO_OV5695 is not set ++# CONFIG_VIDEO_OV7251 is not set ++# CONFIG_VIDEO_OV772X is not set ++# CONFIG_VIDEO_OV7640 is not set ++# CONFIG_VIDEO_OV7670 is not set ++# CONFIG_VIDEO_OV7740 is not set ++CONFIG_VIDEO_OV8856=y ++# CONFIG_VIDEO_OV9640 is not set ++# CONFIG_VIDEO_OV9650 is not set ++# CONFIG_VIDEO_OV13858 is not set ++# CONFIG_VIDEO_VS6624 is not set ++# CONFIG_VIDEO_MT9M001 is not set ++# CONFIG_VIDEO_MT9M032 is not set ++# CONFIG_VIDEO_MT9M111 is not set ++# CONFIG_VIDEO_MT9P031 is not set ++# CONFIG_VIDEO_MT9T001 is not set ++# CONFIG_VIDEO_MT9T112 is not set ++# CONFIG_VIDEO_MT9V011 is not set ++# CONFIG_VIDEO_MT9V032 is not set ++# CONFIG_VIDEO_MT9V111 is not set ++# CONFIG_VIDEO_SR030PC30 is not set ++# CONFIG_VIDEO_NOON010PC30 is not set ++# CONFIG_VIDEO_M5MOLS is not set ++# CONFIG_VIDEO_RDACM20 is not set ++# CONFIG_VIDEO_RJ54N1 is not set ++# CONFIG_VIDEO_S5K6AA is not set ++# CONFIG_VIDEO_S5K6A3 is not set ++# CONFIG_VIDEO_S5K4ECGX is not set ++# CONFIG_VIDEO_S5K5BAF is not set ++# CONFIG_VIDEO_SMIAPP is not set ++# CONFIG_VIDEO_ET8EK8 is not set ++# CONFIG_VIDEO_S5C73M3 is not set ++# end of Camera sensor devices ++ ++# ++# Lens drivers ++# ++# CONFIG_VIDEO_AD5820 is not set ++# CONFIG_VIDEO_AK7375 is not set ++# CONFIG_VIDEO_DW9714 is not set ++# CONFIG_VIDEO_DW9768 is not set ++# CONFIG_VIDEO_DW9807_VCM is not set ++# end of Lens drivers ++ ++# ++# Flash devices ++# ++# CONFIG_VIDEO_ADP1653 is not set ++# CONFIG_VIDEO_LM3560 is not set ++# CONFIG_VIDEO_LM3646 is not set ++# end of Flash devices ++ ++# ++# SPI helper chips ++# ++# CONFIG_VIDEO_GS1662 is not set ++# end of SPI helper chips ++ ++# ++# Media SPI Adapters ++# ++CONFIG_CXD2880_SPI_DRV=m ++# end of Media SPI Adapters ++ ++CONFIG_MEDIA_TUNER=y ++ ++# ++# Customize TV tuners ++# ++# CONFIG_MEDIA_TUNER_SIMPLE is not set ++# CONFIG_MEDIA_TUNER_TDA18250 is not set ++# CONFIG_MEDIA_TUNER_TDA8290 is not set ++# CONFIG_MEDIA_TUNER_TDA827X is not set ++# CONFIG_MEDIA_TUNER_TDA18271 is not set ++# CONFIG_MEDIA_TUNER_TDA9887 is not set ++# CONFIG_MEDIA_TUNER_TEA5761 is not set ++# CONFIG_MEDIA_TUNER_TEA5767 is not set ++CONFIG_MEDIA_TUNER_MSI001=m ++# CONFIG_MEDIA_TUNER_MT20XX is not set ++# CONFIG_MEDIA_TUNER_MT2060 is not set ++# CONFIG_MEDIA_TUNER_MT2063 is not set ++# CONFIG_MEDIA_TUNER_MT2266 is not set ++# CONFIG_MEDIA_TUNER_MT2131 is not set ++# CONFIG_MEDIA_TUNER_QT1010 is not set ++# CONFIG_MEDIA_TUNER_XC2028 is not set ++# CONFIG_MEDIA_TUNER_XC5000 is not set ++# CONFIG_MEDIA_TUNER_XC4000 is not set ++# CONFIG_MEDIA_TUNER_MXL5005S is not set ++# CONFIG_MEDIA_TUNER_MXL5007T is not set ++# CONFIG_MEDIA_TUNER_MC44S803 is not set ++# CONFIG_MEDIA_TUNER_MAX2165 is not set ++# CONFIG_MEDIA_TUNER_TDA18218 is not set ++# CONFIG_MEDIA_TUNER_FC0011 is not set ++# CONFIG_MEDIA_TUNER_FC0012 is not set ++# CONFIG_MEDIA_TUNER_FC0013 is not set ++# CONFIG_MEDIA_TUNER_TDA18212 is not set ++# CONFIG_MEDIA_TUNER_E4000 is not set ++# CONFIG_MEDIA_TUNER_FC2580 is not set ++# CONFIG_MEDIA_TUNER_M88RS6000T is not set ++# CONFIG_MEDIA_TUNER_TUA9001 is not set ++# CONFIG_MEDIA_TUNER_SI2157 is not set ++# CONFIG_MEDIA_TUNER_IT913X is not set ++# CONFIG_MEDIA_TUNER_R820T is not set ++# CONFIG_MEDIA_TUNER_MXL301RF is not set ++# CONFIG_MEDIA_TUNER_QM1D1C0042 is not set ++# CONFIG_MEDIA_TUNER_QM1D1B0004 is not set ++# end of Customize TV tuners ++ ++# ++# Customise DVB Frontends ++# ++ ++# ++# Multistandard (satellite) frontends ++# ++# CONFIG_DVB_STB0899 is not set ++# CONFIG_DVB_STB6100 is not set ++# CONFIG_DVB_STV090x is not set ++# CONFIG_DVB_STV0910 is not set ++# CONFIG_DVB_STV6110x is not set ++# CONFIG_DVB_STV6111 is not set ++# CONFIG_DVB_MXL5XX is not set ++# CONFIG_DVB_M88DS3103 is not set ++ ++# ++# Multistandard (cable + terrestrial) frontends ++# ++# CONFIG_DVB_DRXK is not set ++# CONFIG_DVB_TDA18271C2DD is not set ++# CONFIG_DVB_SI2165 is not set ++# CONFIG_DVB_MN88472 is not set ++# CONFIG_DVB_MN88473 is not set ++ ++# ++# DVB-S (satellite) frontends ++# ++# CONFIG_DVB_CX24110 is not set ++# CONFIG_DVB_CX24123 is not set ++# CONFIG_DVB_MT312 is not set ++# CONFIG_DVB_ZL10036 is not set ++# CONFIG_DVB_ZL10039 is not set ++# CONFIG_DVB_S5H1420 is not set ++# CONFIG_DVB_STV0288 is not set ++# CONFIG_DVB_STB6000 is not set ++# CONFIG_DVB_STV0299 is not set ++# CONFIG_DVB_STV6110 is not set ++# CONFIG_DVB_STV0900 is not set ++# CONFIG_DVB_TDA8083 is not set ++# CONFIG_DVB_TDA10086 is not set ++# CONFIG_DVB_TDA8261 is not set ++# CONFIG_DVB_VES1X93 is not set ++# CONFIG_DVB_TUNER_ITD1000 is not set ++# CONFIG_DVB_TUNER_CX24113 is not set ++# CONFIG_DVB_TDA826X is not set ++# CONFIG_DVB_TUA6100 is not set ++# CONFIG_DVB_CX24116 is not set ++# CONFIG_DVB_CX24117 is not set ++# CONFIG_DVB_CX24120 is not set ++# CONFIG_DVB_SI21XX is not set ++# CONFIG_DVB_TS2020 is not set ++# CONFIG_DVB_DS3000 is not set ++# CONFIG_DVB_MB86A16 is not set ++# CONFIG_DVB_TDA10071 is not set ++ ++# ++# DVB-T (terrestrial) frontends ++# ++# CONFIG_DVB_SP8870 is not set ++# CONFIG_DVB_SP887X is not set ++# CONFIG_DVB_CX22700 is not set ++# CONFIG_DVB_CX22702 is not set ++# CONFIG_DVB_S5H1432 is not set ++# CONFIG_DVB_DRXD is not set ++# CONFIG_DVB_L64781 is not set ++# CONFIG_DVB_TDA1004X is not set ++# CONFIG_DVB_NXT6000 is not set ++# CONFIG_DVB_MT352 is not set ++# CONFIG_DVB_ZL10353 is not set ++# CONFIG_DVB_DIB3000MB is not set ++# CONFIG_DVB_DIB3000MC is not set ++# CONFIG_DVB_DIB7000M is not set ++# CONFIG_DVB_DIB7000P is not set ++# CONFIG_DVB_DIB9000 is not set ++# CONFIG_DVB_TDA10048 is not set ++# CONFIG_DVB_AF9013 is not set ++# CONFIG_DVB_EC100 is not set ++# CONFIG_DVB_STV0367 is not set ++# CONFIG_DVB_CXD2820R is not set ++# CONFIG_DVB_CXD2841ER is not set ++# CONFIG_DVB_RTL2830 is not set ++# CONFIG_DVB_RTL2832 is not set ++# CONFIG_DVB_RTL2832_SDR is not set ++# CONFIG_DVB_SI2168 is not set ++# CONFIG_DVB_ZD1301_DEMOD is not set ++CONFIG_DVB_CXD2880=m ++ ++# ++# DVB-C (cable) frontends ++# ++# CONFIG_DVB_VES1820 is not set ++# CONFIG_DVB_TDA10021 is not set ++# CONFIG_DVB_TDA10023 is not set ++# CONFIG_DVB_STV0297 is not set ++ ++# ++# ATSC (North American/Korean Terrestrial/Cable DTV) frontends ++# ++# CONFIG_DVB_NXT200X is not set ++# CONFIG_DVB_OR51211 is not set ++# CONFIG_DVB_OR51132 is not set ++# CONFIG_DVB_BCM3510 is not set ++# CONFIG_DVB_LGDT330X is not set ++# CONFIG_DVB_LGDT3305 is not set ++# CONFIG_DVB_LGDT3306A is not set ++# CONFIG_DVB_LG2160 is not set ++# CONFIG_DVB_S5H1409 is not set ++# CONFIG_DVB_AU8522_DTV is not set ++# CONFIG_DVB_AU8522_V4L is not set ++# CONFIG_DVB_S5H1411 is not set ++ ++# ++# ISDB-T (terrestrial) frontends ++# ++# CONFIG_DVB_S921 is not set ++# CONFIG_DVB_DIB8000 is not set ++# CONFIG_DVB_MB86A20S is not set ++ ++# ++# ISDB-S (satellite) & ISDB-T (terrestrial) frontends ++# ++# CONFIG_DVB_TC90522 is not set ++# CONFIG_DVB_MN88443X is not set ++ ++# ++# Digital terrestrial only tuners/PLL ++# ++# CONFIG_DVB_PLL is not set ++# CONFIG_DVB_TUNER_DIB0070 is not set ++# CONFIG_DVB_TUNER_DIB0090 is not set ++ ++# ++# SEC control devices for DVB-S ++# ++# CONFIG_DVB_DRX39XYJ is not set ++# CONFIG_DVB_LNBH25 is not set ++# CONFIG_DVB_LNBH29 is not set ++# CONFIG_DVB_LNBP21 is not set ++# CONFIG_DVB_LNBP22 is not set ++# CONFIG_DVB_ISL6405 is not set ++# CONFIG_DVB_ISL6421 is not set ++# CONFIG_DVB_ISL6423 is not set ++# CONFIG_DVB_A8293 is not set ++# CONFIG_DVB_LGS8GL5 is not set ++# CONFIG_DVB_LGS8GXX is not set ++# CONFIG_DVB_ATBM8830 is not set ++# CONFIG_DVB_TDA665x is not set ++# CONFIG_DVB_IX2505V is not set ++# CONFIG_DVB_M88RS2000 is not set ++# CONFIG_DVB_AF9033 is not set ++# CONFIG_DVB_HORUS3A is not set ++# CONFIG_DVB_ASCOT2E is not set ++# CONFIG_DVB_HELENE is not set ++ ++# ++# Common Interface (EN50221) controller drivers ++# ++# CONFIG_DVB_CXD2099 is not set ++# CONFIG_DVB_SP2 is not set ++# end of Customise DVB Frontends ++ ++# ++# Tools to develop new frontends ++# ++# CONFIG_DVB_DUMMY_FE is not set ++# end of Media ancillary drivers ++ ++# ++# Graphics support ++# ++# CONFIG_DRM is not set ++ ++# ++# ARM devices ++# ++# end of ARM devices ++ ++# ++# Frame buffer Devices ++# ++CONFIG_FB_CMDLINE=y ++CONFIG_FB_NOTIFY=y ++CONFIG_FB=y ++# CONFIG_FIRMWARE_EDID is not set ++CONFIG_FB_CFB_FILLRECT=y ++CONFIG_FB_CFB_COPYAREA=y ++CONFIG_FB_CFB_IMAGEBLIT=y ++# CONFIG_FB_FOREIGN_ENDIAN is not set ++# CONFIG_FB_MODE_HELPERS is not set ++# CONFIG_FB_TILEBLITTING is not set ++ ++# ++# Frame buffer hardware drivers ++# ++# CONFIG_FB_OPENCORES is not set ++# CONFIG_FB_S1D13XXX is not set ++# CONFIG_FB_SMSCUFX is not set ++# CONFIG_FB_UDL is not set ++# CONFIG_FB_IBM_GXT4500 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FB_METRONOME is not set ++# CONFIG_FB_SIMPLE is not set ++# CONFIG_FB_SSD1307 is not set ++# end of Frame buffer Devices ++ ++# ++# Backlight & LCD device support ++# ++CONFIG_LCD_CLASS_DEVICE=y ++# CONFIG_LCD_L4F00242T03 is not set ++# CONFIG_LCD_LMS283GF05 is not set ++# CONFIG_LCD_LTV350QV is not set ++# CONFIG_LCD_ILI922X is not set ++# CONFIG_LCD_ILI9320 is not set ++# CONFIG_LCD_TDO24M is not set ++# CONFIG_LCD_VGG2432A4 is not set ++# CONFIG_LCD_PLATFORM is not set ++# CONFIG_LCD_AMS369FG06 is not set ++# CONFIG_LCD_LMS501KF03 is not set ++# CONFIG_LCD_HX8357 is not set ++# CONFIG_LCD_OTM3225A is not set ++CONFIG_BACKLIGHT_CLASS_DEVICE=y ++# CONFIG_BACKLIGHT_KTD253 is not set ++CONFIG_BACKLIGHT_PWM=y ++# CONFIG_BACKLIGHT_QCOM_WLED is not set ++# CONFIG_BACKLIGHT_ADP8860 is not set ++# CONFIG_BACKLIGHT_ADP8870 is not set ++# CONFIG_BACKLIGHT_LM3630A is not set ++# CONFIG_BACKLIGHT_LM3639 is not set ++# CONFIG_BACKLIGHT_LP855X is not set ++CONFIG_BACKLIGHT_GPIO=y ++# CONFIG_BACKLIGHT_LV5207LP is not set ++# CONFIG_BACKLIGHT_BD6107 is not set ++# CONFIG_BACKLIGHT_ARCXCNN is not set ++# end of Backlight & LCD device support ++ ++# ++# Console display driver support ++# ++# CONFIG_VGA_CONSOLE is not set ++CONFIG_DUMMY_CONSOLE=y ++CONFIG_DUMMY_CONSOLE_COLUMNS=80 ++CONFIG_DUMMY_CONSOLE_ROWS=25 ++# CONFIG_FRAMEBUFFER_CONSOLE is not set ++# end of Console display driver support ++ ++CONFIG_LOGO=y ++# CONFIG_LOGO_LINUX_MONO is not set ++# CONFIG_LOGO_LINUX_VGA16 is not set ++# CONFIG_LOGO_LINUX_CLUT224 is not set ++# end of Graphics support ++ ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_SND_TIMER=y ++CONFIG_SND_PCM=y ++CONFIG_SND_JACK=y ++CONFIG_SND_JACK_INPUT_DEV=y ++# CONFIG_SND_OSSEMUL is not set ++CONFIG_SND_PCM_TIMER=y ++# CONFIG_SND_HRTIMER is not set ++CONFIG_SND_DYNAMIC_MINORS=y ++CONFIG_SND_MAX_CARDS=32 ++CONFIG_SND_SUPPORT_OLD_API=y ++CONFIG_SND_PROC_FS=y ++CONFIG_SND_VERBOSE_PROCFS=y ++# CONFIG_SND_VERBOSE_PRINTK is not set ++# CONFIG_SND_DEBUG is not set ++# CONFIG_SND_SEQUENCER is not set ++CONFIG_SND_DRIVERS=y ++# CONFIG_SND_DUMMY is not set ++# CONFIG_SND_ALOOP is not set ++# CONFIG_SND_MTPAV is not set ++# CONFIG_SND_SERIAL_U16550 is not set ++# CONFIG_SND_MPU401 is not set ++ ++# ++# HD-Audio ++# ++# end of HD-Audio ++ ++CONFIG_SND_HDA_PREALLOC_SIZE=64 ++CONFIG_SND_SPI=y ++# CONFIG_SND_MIPS is not set ++# CONFIG_SND_USB is not set ++CONFIG_SND_SOC=y ++# CONFIG_SND_SOC_AMD_ACP is not set ++# CONFIG_SND_ATMEL_SOC is not set ++# CONFIG_SND_BCM63XX_I2S_WHISTLER is not set ++# CONFIG_SND_DESIGNWARE_I2S is not set ++ ++# ++# SoC Audio for Freescale CPUs ++# ++ ++# ++# Common SoC Audio options for Freescale CPUs: ++# ++# CONFIG_SND_SOC_FSL_ASRC is not set ++# CONFIG_SND_SOC_FSL_SAI is not set ++# CONFIG_SND_SOC_FSL_AUDMIX is not set ++# CONFIG_SND_SOC_FSL_SSI is not set ++# CONFIG_SND_SOC_FSL_SPDIF is not set ++# CONFIG_SND_SOC_FSL_ESAI is not set ++# CONFIG_SND_SOC_FSL_MICFIL is not set ++# CONFIG_SND_SOC_IMX_AUDMUX is not set ++# end of SoC Audio for Freescale CPUs ++ ++# CONFIG_SND_I2S_HI6210_I2S is not set ++# CONFIG_SND_JZ4740_SOC_I2S is not set ++# CONFIG_SND_SOC_IMG is not set ++# CONFIG_SND_SOC_MTK_BTCVSD is not set ++# CONFIG_SND_SOC_SOF_TOPLEVEL is not set ++ ++# ++# STMicroelectronics STM32 SOC audio support ++# ++# end of STMicroelectronics STM32 SOC audio support ++ ++# CONFIG_SND_SOC_XILINX_I2S is not set ++# CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER is not set ++# CONFIG_SND_SOC_XILINX_SPDIF is not set ++# CONFIG_SND_SOC_XTFPGA_I2S is not set ++# CONFIG_ZX_TDM is not set ++CONFIG_SND_SOC_I2C_AND_SPI=y ++ ++# ++# CODEC drivers ++# ++# CONFIG_SND_SOC_AC97_CODEC is not set ++# CONFIG_SND_SOC_ADAU1701 is not set ++# CONFIG_SND_SOC_ADAU1761_I2C is not set ++# CONFIG_SND_SOC_ADAU1761_SPI is not set ++# CONFIG_SND_SOC_ADAU7002 is not set ++# CONFIG_SND_SOC_ADAU7118_HW is not set ++# CONFIG_SND_SOC_ADAU7118_I2C is not set ++# CONFIG_SND_SOC_AK4104 is not set ++# CONFIG_SND_SOC_AK4118 is not set ++# CONFIG_SND_SOC_AK4458 is not set ++# CONFIG_SND_SOC_AK4554 is not set ++# CONFIG_SND_SOC_AK4613 is not set ++# CONFIG_SND_SOC_AK4642 is not set ++# CONFIG_SND_SOC_AK5386 is not set ++# CONFIG_SND_SOC_AK5558 is not set ++# CONFIG_SND_SOC_ALC5623 is not set ++# CONFIG_SND_SOC_BD28623 is not set ++# CONFIG_SND_SOC_BT_SCO is not set ++# CONFIG_SND_SOC_CS35L32 is not set ++# CONFIG_SND_SOC_CS35L33 is not set ++# CONFIG_SND_SOC_CS35L34 is not set ++# CONFIG_SND_SOC_CS35L35 is not set ++# CONFIG_SND_SOC_CS35L36 is not set ++# CONFIG_SND_SOC_CS42L42 is not set ++# CONFIG_SND_SOC_CS42L51_I2C is not set ++# CONFIG_SND_SOC_CS42L52 is not set ++# CONFIG_SND_SOC_CS42L56 is not set ++# CONFIG_SND_SOC_CS42L73 is not set ++# CONFIG_SND_SOC_CS4234 is not set ++# CONFIG_SND_SOC_CS4265 is not set ++# CONFIG_SND_SOC_CS4270 is not set ++# CONFIG_SND_SOC_CS4271_I2C is not set ++# CONFIG_SND_SOC_CS4271_SPI is not set ++# CONFIG_SND_SOC_CS42XX8_I2C is not set ++# CONFIG_SND_SOC_CS43130 is not set ++# CONFIG_SND_SOC_CS4341 is not set ++# CONFIG_SND_SOC_CS4349 is not set ++# CONFIG_SND_SOC_CS53L30 is not set ++# CONFIG_SND_SOC_CX2072X is not set ++# CONFIG_SND_SOC_JZ4740_CODEC is not set ++# CONFIG_SND_SOC_JZ4725B_CODEC is not set ++# CONFIG_SND_SOC_JZ4770_CODEC is not set ++# CONFIG_SND_SOC_DA7213 is not set ++# CONFIG_SND_SOC_DMIC is not set ++# CONFIG_SND_SOC_ES7134 is not set ++# CONFIG_SND_SOC_ES7241 is not set ++# CONFIG_SND_SOC_ES8316 is not set ++# CONFIG_SND_SOC_ES8328_I2C is not set ++# CONFIG_SND_SOC_ES8328_SPI is not set ++# CONFIG_SND_SOC_GTM601 is not set ++# CONFIG_SND_SOC_INNO_RK3036 is not set ++# CONFIG_SND_SOC_MAX98088 is not set ++# CONFIG_SND_SOC_MAX98357A is not set ++# CONFIG_SND_SOC_MAX98504 is not set ++# CONFIG_SND_SOC_MAX9867 is not set ++# CONFIG_SND_SOC_MAX98927 is not set ++# CONFIG_SND_SOC_MAX98373_I2C is not set ++# CONFIG_SND_SOC_MAX98390 is not set ++# CONFIG_SND_SOC_MAX9860 is not set ++# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set ++# CONFIG_SND_SOC_PCM1681 is not set ++# CONFIG_SND_SOC_PCM1789_I2C is not set ++# CONFIG_SND_SOC_PCM179X_I2C is not set ++# CONFIG_SND_SOC_PCM179X_SPI is not set ++# CONFIG_SND_SOC_PCM186X_I2C is not set ++# CONFIG_SND_SOC_PCM186X_SPI is not set ++# CONFIG_SND_SOC_PCM3060_I2C is not set ++# CONFIG_SND_SOC_PCM3060_SPI is not set ++# CONFIG_SND_SOC_PCM3168A_I2C is not set ++# CONFIG_SND_SOC_PCM3168A_SPI is not set ++# CONFIG_SND_SOC_PCM512x_I2C is not set ++# CONFIG_SND_SOC_PCM512x_SPI is not set ++# CONFIG_SND_SOC_RK3328 is not set ++# CONFIG_SND_SOC_RT5616 is not set ++# CONFIG_SND_SOC_RT5631 is not set ++# CONFIG_SND_SOC_SGTL5000 is not set ++# CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set ++# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set ++# CONFIG_SND_SOC_SPDIF is not set ++# CONFIG_SND_SOC_SSM2305 is not set ++# CONFIG_SND_SOC_SSM2602_SPI is not set ++# CONFIG_SND_SOC_SSM2602_I2C is not set ++# CONFIG_SND_SOC_SSM4567 is not set ++# CONFIG_SND_SOC_STA32X is not set ++# CONFIG_SND_SOC_STA350 is not set ++# CONFIG_SND_SOC_STI_SAS is not set ++# CONFIG_SND_SOC_TAS2552 is not set ++# CONFIG_SND_SOC_TAS2562 is not set ++# CONFIG_SND_SOC_TAS2764 is not set ++# CONFIG_SND_SOC_TAS2770 is not set ++# CONFIG_SND_SOC_TAS5086 is not set ++# CONFIG_SND_SOC_TAS571X is not set ++# CONFIG_SND_SOC_TAS5720 is not set ++# CONFIG_SND_SOC_TAS6424 is not set ++# CONFIG_SND_SOC_TDA7419 is not set ++# CONFIG_SND_SOC_TFA9879 is not set ++# CONFIG_SND_SOC_TLV320AIC23_I2C is not set ++# CONFIG_SND_SOC_TLV320AIC23_SPI is not set ++# CONFIG_SND_SOC_TLV320AIC31XX is not set ++# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set ++# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set ++# CONFIG_SND_SOC_TLV320AIC3X is not set ++# CONFIG_SND_SOC_TLV320ADCX140 is not set ++# CONFIG_SND_SOC_TS3A227E is not set ++# CONFIG_SND_SOC_TSCS42XX is not set ++# CONFIG_SND_SOC_TSCS454 is not set ++# CONFIG_SND_SOC_UDA1334 is not set ++# CONFIG_SND_SOC_WM8510 is not set ++# CONFIG_SND_SOC_WM8523 is not set ++# CONFIG_SND_SOC_WM8524 is not set ++# CONFIG_SND_SOC_WM8580 is not set ++# CONFIG_SND_SOC_WM8711 is not set ++# CONFIG_SND_SOC_WM8728 is not set ++# CONFIG_SND_SOC_WM8731 is not set ++# CONFIG_SND_SOC_WM8737 is not set ++# CONFIG_SND_SOC_WM8741 is not set ++# CONFIG_SND_SOC_WM8750 is not set ++# CONFIG_SND_SOC_WM8753 is not set ++# CONFIG_SND_SOC_WM8770 is not set ++# CONFIG_SND_SOC_WM8776 is not set ++# CONFIG_SND_SOC_WM8782 is not set ++# CONFIG_SND_SOC_WM8804_I2C is not set ++# CONFIG_SND_SOC_WM8804_SPI is not set ++# CONFIG_SND_SOC_WM8903 is not set ++# CONFIG_SND_SOC_WM8904 is not set ++# CONFIG_SND_SOC_WM8960 is not set ++# CONFIG_SND_SOC_WM8962 is not set ++# CONFIG_SND_SOC_WM8974 is not set ++# CONFIG_SND_SOC_WM8978 is not set ++# CONFIG_SND_SOC_WM8985 is not set ++# CONFIG_SND_SOC_ZL38060 is not set ++# CONFIG_SND_SOC_ZX_AUD96P22 is not set ++# CONFIG_SND_SOC_MAX9759 is not set ++# CONFIG_SND_SOC_MT6351 is not set ++# CONFIG_SND_SOC_MT6358 is not set ++# CONFIG_SND_SOC_MT6660 is not set ++# CONFIG_SND_SOC_NAU8540 is not set ++# CONFIG_SND_SOC_NAU8810 is not set ++# CONFIG_SND_SOC_NAU8822 is not set ++# CONFIG_SND_SOC_NAU8824 is not set ++# CONFIG_SND_SOC_TPA6130A2 is not set ++# end of CODEC drivers ++ ++# CONFIG_SND_SIMPLE_CARD is not set ++# CONFIG_SND_AUDIO_GRAPH_CARD is not set ++ ++# ++# HID support ++# ++CONFIG_HID=y ++# CONFIG_HID_BATTERY_STRENGTH is not set ++# CONFIG_HIDRAW is not set ++# CONFIG_UHID is not set ++# CONFIG_HID_GENERIC is not set ++ ++# ++# Special HID drivers ++# ++# CONFIG_HID_A4TECH is not set ++# CONFIG_HID_ACRUX is not set ++# CONFIG_HID_APPLE is not set ++# CONFIG_HID_AUREAL is not set ++# CONFIG_HID_BELKIN is not set ++# CONFIG_HID_CHERRY is not set ++# CONFIG_HID_COUGAR is not set ++# CONFIG_HID_MACALLY is not set ++# CONFIG_HID_CMEDIA is not set ++# CONFIG_HID_CYPRESS is not set ++# CONFIG_HID_DRAGONRISE is not set ++# CONFIG_HID_EMS_FF is not set ++# CONFIG_HID_ELECOM is not set ++# CONFIG_HID_EZKEY is not set ++# CONFIG_HID_GEMBIRD is not set ++# CONFIG_HID_GFRM is not set ++# CONFIG_HID_GLORIOUS is not set ++# CONFIG_HID_VIVALDI is not set ++# CONFIG_HID_KEYTOUCH is not set ++# CONFIG_HID_KYE is not set ++# CONFIG_HID_WALTOP is not set ++# CONFIG_HID_VIEWSONIC is not set ++# CONFIG_HID_GYRATION is not set ++# CONFIG_HID_ICADE is not set ++# CONFIG_HID_ITE is not set ++# CONFIG_HID_JABRA is not set ++# CONFIG_HID_TWINHAN is not set ++# CONFIG_HID_KENSINGTON is not set ++# CONFIG_HID_LCPOWER is not set ++# CONFIG_HID_LENOVO is not set ++# CONFIG_HID_MAGICMOUSE is not set ++# CONFIG_HID_MALTRON is not set ++# CONFIG_HID_MAYFLASH is not set ++# CONFIG_HID_REDRAGON is not set ++# CONFIG_HID_MICROSOFT is not set ++# CONFIG_HID_MONTEREY is not set ++# CONFIG_HID_MULTITOUCH is not set ++# CONFIG_HID_NTI is not set ++# CONFIG_HID_ORTEK is not set ++# CONFIG_HID_PANTHERLORD is not set ++# CONFIG_HID_PETALYNX is not set ++# CONFIG_HID_PICOLCD is not set ++# CONFIG_HID_PLANTRONICS is not set ++# CONFIG_HID_PRIMAX is not set ++# CONFIG_HID_SAITEK is not set ++# CONFIG_HID_SPEEDLINK is not set ++# CONFIG_HID_STEAM is not set ++# CONFIG_HID_STEELSERIES is not set ++# CONFIG_HID_SUNPLUS is not set ++# CONFIG_HID_RMI is not set ++# CONFIG_HID_GREENASIA is not set ++# CONFIG_HID_SMARTJOYPLUS is not set ++# CONFIG_HID_TIVO is not set ++# CONFIG_HID_TOPSEED is not set ++# CONFIG_HID_THRUSTMASTER is not set ++# CONFIG_HID_UDRAW_PS3 is not set ++# CONFIG_HID_XINMO is not set ++# CONFIG_HID_ZEROPLUS is not set ++# CONFIG_HID_ZYDACRON is not set ++# CONFIG_HID_SENSOR_HUB is not set ++# CONFIG_HID_ALPS is not set ++# end of Special HID drivers ++ ++# ++# USB HID support ++# ++# CONFIG_USB_HID is not set ++# CONFIG_HID_PID is not set ++ ++# ++# USB HID Boot Protocol drivers ++# ++CONFIG_USB_KBD=y ++CONFIG_USB_MOUSE=y ++# end of USB HID Boot Protocol drivers ++# end of USB HID support ++ ++# ++# I2C HID support ++# ++# CONFIG_I2C_HID is not set ++# end of I2C HID support ++# end of HID support ++ ++CONFIG_USB_OHCI_LITTLE_ENDIAN=y ++CONFIG_USB_SUPPORT=y ++CONFIG_USB_COMMON=y ++# CONFIG_USB_ULPI_BUS is not set ++# CONFIG_USB_CONN_GPIO is not set ++CONFIG_USB_ARCH_HAS_HCD=y ++CONFIG_USB=y ++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y ++ ++# ++# Miscellaneous USB options ++# ++CONFIG_USB_DEFAULT_PERSIST=y ++# CONFIG_USB_FEW_INIT_RETRIES is not set ++# CONFIG_USB_DYNAMIC_MINORS is not set ++CONFIG_USB_OTG=y ++# CONFIG_USB_OTG_PRODUCTLIST is not set ++# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set ++# CONFIG_USB_OTG_FSM is not set ++CONFIG_USB_AUTOSUSPEND_DELAY=2 ++# CONFIG_USB_MON is not set ++ ++# ++# USB Host Controller Drivers ++# ++# CONFIG_USB_C67X00_HCD is not set ++# CONFIG_USB_XHCI_HCD is not set ++# CONFIG_USB_EHCI_HCD is not set ++# CONFIG_USB_OXU210HP_HCD is not set ++# CONFIG_USB_ISP116X_HCD is not set ++# CONFIG_USB_FOTG210_HCD is not set ++# CONFIG_USB_MAX3421_HCD is not set ++# CONFIG_USB_OHCI_HCD is not set ++# CONFIG_USB_SL811_HCD is not set ++# CONFIG_USB_R8A66597_HCD is not set ++# CONFIG_USB_HCD_TEST_MODE is not set ++ ++# ++# USB Device Class drivers ++# ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++# CONFIG_USB_WDM is not set ++# CONFIG_USB_TMC is not set ++ ++# ++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may ++# ++ ++# ++# also be needed; see USB_STORAGE Help for more info ++# ++CONFIG_USB_STORAGE=y ++# CONFIG_USB_STORAGE_DEBUG is not set ++# CONFIG_USB_STORAGE_REALTEK is not set ++# CONFIG_USB_STORAGE_DATAFAB is not set ++# CONFIG_USB_STORAGE_FREECOM is not set ++# CONFIG_USB_STORAGE_ISD200 is not set ++# CONFIG_USB_STORAGE_USBAT is not set ++# CONFIG_USB_STORAGE_SDDR09 is not set ++# CONFIG_USB_STORAGE_SDDR55 is not set ++# CONFIG_USB_STORAGE_JUMPSHOT is not set ++# CONFIG_USB_STORAGE_ALAUDA is not set ++# CONFIG_USB_STORAGE_ONETOUCH is not set ++# CONFIG_USB_STORAGE_KARMA is not set ++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set ++# CONFIG_USB_STORAGE_ENE_UB6250 is not set ++# CONFIG_USB_UAS is not set ++ ++# ++# USB Imaging devices ++# ++# CONFIG_USB_MDC800 is not set ++# CONFIG_USB_MICROTEK is not set ++# CONFIG_USBIP_CORE is not set ++# CONFIG_USB_CDNS3 is not set ++# CONFIG_USB_MUSB_HDRC is not set ++# CONFIG_USB_DWC3 is not set ++CONFIG_USB_DWC2=y ++# CONFIG_USB_DWC2_HOST is not set ++ ++# ++# Gadget/Dual-role mode requires USB Gadget support to be enabled ++# ++# CONFIG_USB_DWC2_PERIPHERAL is not set ++CONFIG_USB_DWC2_DUAL_ROLE=y ++# CONFIG_USB_DWC2_DEBUG is not set ++# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set ++# CONFIG_USB_DWC2_FORCE_FULL_SPEED is not set ++# CONFIG_USB_DWC2_EXT_ID_PIN is not set ++CONFIG_USB_DWC2_EXT_VBUS_DETECT=y ++# CONFIG_USB_CHIPIDEA is not set ++# CONFIG_USB_ISP1760 is not set ++ ++# ++# USB port drivers ++# ++# CONFIG_USB_SERIAL is not set ++ ++# ++# USB Miscellaneous drivers ++# ++# CONFIG_USB_EMI62 is not set ++# CONFIG_USB_EMI26 is not set ++# CONFIG_USB_ADUTUX is not set ++# CONFIG_USB_SEVSEG is not set ++# CONFIG_USB_LEGOTOWER is not set ++# CONFIG_USB_LCD is not set ++# CONFIG_USB_CYPRESS_CY7C63 is not set ++# CONFIG_USB_CYTHERM is not set ++# CONFIG_USB_IDMOUSE is not set ++# CONFIG_USB_FTDI_ELAN is not set ++# CONFIG_USB_APPLEDISPLAY is not set ++# CONFIG_APPLE_MFI_FASTCHARGE is not set ++# CONFIG_USB_LD is not set ++# CONFIG_USB_TRANCEVIBRATOR is not set ++# CONFIG_USB_IOWARRIOR is not set ++# CONFIG_USB_TEST is not set ++# CONFIG_USB_EHSET_TEST_FIXTURE is not set ++# CONFIG_USB_ISIGHTFW is not set ++# CONFIG_USB_YUREX is not set ++# CONFIG_USB_EZUSB_FX2 is not set ++# CONFIG_USB_HUB_USB251XB is not set ++# CONFIG_USB_HSIC_USB3503 is not set ++# CONFIG_USB_HSIC_USB4604 is not set ++# CONFIG_USB_LINK_LAYER_TEST is not set ++# CONFIG_USB_CHAOSKEY is not set ++ ++# ++# USB Physical Layer drivers ++# ++CONFIG_USB_PHY=y ++# CONFIG_NOP_USB_XCEIV is not set ++# CONFIG_INGENIC_INNOPHY is not set ++CONFIG_INGENIC_USB_PHY=y ++# CONFIG_USB_GPIO_VBUS is not set ++# CONFIG_USB_ISP1301 is not set ++# CONFIG_JZ4770_PHY is not set ++# end of USB Physical Layer drivers ++ ++CONFIG_USB_GADGET=y ++# CONFIG_USB_GADGET_DEBUG is not set ++# CONFIG_USB_GADGET_DEBUG_FILES is not set ++# CONFIG_USB_GADGET_DEBUG_FS is not set ++CONFIG_USB_GADGET_VBUS_DRAW=2 ++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 ++# CONFIG_U_SERIAL_CONSOLE is not set ++ ++# ++# USB Peripheral Controller ++# ++# CONFIG_USB_FUSB300 is not set ++# CONFIG_USB_FOTG210_UDC is not set ++# CONFIG_USB_GR_UDC is not set ++# CONFIG_USB_R8A66597 is not set ++# CONFIG_USB_PXA27X is not set ++# CONFIG_USB_MV_UDC is not set ++# CONFIG_USB_MV_U3D is not set ++# CONFIG_USB_SNP_UDC_PLAT is not set ++# CONFIG_USB_M66592 is not set ++# CONFIG_USB_BDC_UDC is not set ++# CONFIG_USB_NET2272 is not set ++# CONFIG_USB_GADGET_XILINX is not set ++# CONFIG_USB_MAX3420_UDC is not set ++# CONFIG_USB_DUMMY_HCD is not set ++# end of USB Peripheral Controller ++ ++CONFIG_USB_LIBCOMPOSITE=y ++CONFIG_USB_F_ACM=y ++CONFIG_USB_U_SERIAL=y ++CONFIG_USB_U_ETHER=y ++CONFIG_USB_U_AUDIO=y ++CONFIG_USB_F_SERIAL=y ++CONFIG_USB_F_OBEX=y ++CONFIG_USB_F_RNDIS=y ++CONFIG_USB_F_MASS_STORAGE=y ++CONFIG_USB_F_FS=y ++CONFIG_USB_F_UAC1=y ++CONFIG_USB_F_UVC=y ++CONFIG_USB_F_HID=y ++CONFIG_USB_F_PRINTER=y ++CONFIG_USB_CONFIGFS=y ++# CONFIG_CONFIGFS_UEVENT_REPORT is not set ++CONFIG_USB_CONFIGFS_SERIAL=y ++CONFIG_USB_CONFIGFS_ACM=y ++CONFIG_USB_CONFIGFS_OBEX=y ++# CONFIG_USB_CONFIGFS_NCM is not set ++# CONFIG_USB_CONFIGFS_ECM is not set ++# CONFIG_USB_CONFIGFS_ECM_SUBSET is not set ++CONFIG_USB_CONFIGFS_RNDIS=y ++# CONFIG_USB_CONFIGFS_EEM is not set ++CONFIG_USB_CONFIGFS_MASS_STORAGE=y ++# CONFIG_USB_CONFIGFS_F_LB_SS is not set ++CONFIG_USB_CONFIGFS_F_FS=y ++CONFIG_USB_CONFIGFS_F_UAC1=y ++# CONFIG_USB_CONFIGFS_F_UAC1_LEGACY is not set ++# CONFIG_USB_CONFIGFS_F_UAC2 is not set ++# CONFIG_USB_CONFIGFS_F_MIDI is not set ++CONFIG_USB_CONFIGFS_F_HID=y ++CONFIG_USB_CONFIGFS_F_UVC=y ++CONFIG_USB_CONFIGFS_F_PRINTER=y ++# CONFIG_USB_CONFIGFS_F_MTP is not set ++ ++# ++# USB Gadget precomposed configurations ++# ++# CONFIG_USB_ZERO is not set ++# CONFIG_USB_AUDIO is not set ++# CONFIG_USB_ETH is not set ++# CONFIG_USB_G_NCM is not set ++# CONFIG_USB_GADGETFS is not set ++# CONFIG_USB_FUNCTIONFS is not set ++# CONFIG_USB_MASS_STORAGE is not set ++# CONFIG_USB_G_SERIAL is not set ++# CONFIG_USB_MIDI_GADGET is not set ++# CONFIG_USB_G_PRINTER is not set ++# CONFIG_USB_CDC_COMPOSITE is not set ++# CONFIG_USB_G_ACM_MS is not set ++# CONFIG_USB_G_MULTI is not set ++# CONFIG_USB_G_HID is not set ++# CONFIG_USB_G_DBGP is not set ++# CONFIG_USB_G_WEBCAM is not set ++# CONFIG_USB_RAW_GADGET is not set ++# end of USB Gadget precomposed configurations ++ ++# CONFIG_TYPEC is not set ++CONFIG_USB_ROLE_SWITCH=y ++CONFIG_MMC=y ++CONFIG_PWRSEQ_EMMC=y ++CONFIG_PWRSEQ_SIMPLE=y ++CONFIG_MMC_BLOCK=y ++CONFIG_MMC_BLOCK_MINORS=16 ++# CONFIG_SDIO_UART is not set ++# CONFIG_MMC_TEST is not set ++ ++# ++# MMC/SD/SDIO Host Controller Drivers ++# ++# CONFIG_MMC_DEBUG is not set ++CONFIG_MMC_SDHCI=y ++# CONFIG_MMC_SDHCI_PLTFM is not set ++# CONFIG_MMC_SPI is not set ++# CONFIG_MMC_DW is not set ++# CONFIG_MMC_JZ4740 is not set ++# CONFIG_MMC_VUB300 is not set ++# CONFIG_MMC_USHC is not set ++# CONFIG_MMC_USDHI6ROL0 is not set ++# CONFIG_MMC_CQHCI is not set ++# CONFIG_MMC_HSQ is not set ++# CONFIG_MMC_MTK is not set ++# CONFIG_MEMSTICK is not set ++# CONFIG_NEW_LEDS is not set ++# CONFIG_ACCESSIBILITY is not set ++# CONFIG_INFINIBAND is not set ++CONFIG_RTC_LIB=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_HCTOSYS=y ++CONFIG_RTC_HCTOSYS_DEVICE="rtc0" ++CONFIG_RTC_SYSTOHC=y ++CONFIG_RTC_SYSTOHC_DEVICE="rtc0" ++# CONFIG_RTC_DEBUG is not set ++# CONFIG_RTC_NVMEM is not set ++ ++# ++# RTC interfaces ++# ++CONFIG_RTC_INTF_SYSFS=y ++CONFIG_RTC_INTF_PROC=y ++CONFIG_RTC_INTF_DEV=y ++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set ++# CONFIG_RTC_DRV_TEST is not set ++ ++# ++# I2C RTC drivers ++# ++# CONFIG_RTC_DRV_ABB5ZES3 is not set ++# CONFIG_RTC_DRV_ABEOZ9 is not set ++# CONFIG_RTC_DRV_ABX80X is not set ++# CONFIG_RTC_DRV_DS1307 is not set ++# CONFIG_RTC_DRV_DS1374 is not set ++# CONFIG_RTC_DRV_DS1672 is not set ++# CONFIG_RTC_DRV_HYM8563 is not set ++# CONFIG_RTC_DRV_MAX6900 is not set ++# CONFIG_RTC_DRV_RS5C372 is not set ++# CONFIG_RTC_DRV_ISL1208 is not set ++# CONFIG_RTC_DRV_ISL12022 is not set ++# CONFIG_RTC_DRV_ISL12026 is not set ++# CONFIG_RTC_DRV_X1205 is not set ++# CONFIG_RTC_DRV_PCF8523 is not set ++# CONFIG_RTC_DRV_PCF85063 is not set ++# CONFIG_RTC_DRV_PCF85363 is not set ++# CONFIG_RTC_DRV_PCF8563 is not set ++# CONFIG_RTC_DRV_PCF8583 is not set ++# CONFIG_RTC_DRV_M41T80 is not set ++# CONFIG_RTC_DRV_BQ32K is not set ++# CONFIG_RTC_DRV_S35390A is not set ++# CONFIG_RTC_DRV_FM3130 is not set ++# CONFIG_RTC_DRV_RX8010 is not set ++# CONFIG_RTC_DRV_RX8581 is not set ++# CONFIG_RTC_DRV_RX8025 is not set ++# CONFIG_RTC_DRV_EM3027 is not set ++# CONFIG_RTC_DRV_RV3028 is not set ++# CONFIG_RTC_DRV_RV3032 is not set ++# CONFIG_RTC_DRV_RV8803 is not set ++# CONFIG_RTC_DRV_SD3078 is not set ++ ++# ++# SPI RTC drivers ++# ++# CONFIG_RTC_DRV_M41T93 is not set ++# CONFIG_RTC_DRV_M41T94 is not set ++# CONFIG_RTC_DRV_DS1302 is not set ++# CONFIG_RTC_DRV_DS1305 is not set ++# CONFIG_RTC_DRV_DS1343 is not set ++# CONFIG_RTC_DRV_DS1347 is not set ++# CONFIG_RTC_DRV_DS1390 is not set ++# CONFIG_RTC_DRV_MAX6916 is not set ++# CONFIG_RTC_DRV_R9701 is not set ++# CONFIG_RTC_DRV_RX4581 is not set ++# CONFIG_RTC_DRV_RX6110 is not set ++# CONFIG_RTC_DRV_RS5C348 is not set ++# CONFIG_RTC_DRV_MAX6902 is not set ++# CONFIG_RTC_DRV_PCF2123 is not set ++# CONFIG_RTC_DRV_MCP795 is not set ++CONFIG_RTC_I2C_AND_SPI=y ++ ++# ++# SPI and I2C RTC drivers ++# ++# CONFIG_RTC_DRV_DS3232 is not set ++# CONFIG_RTC_DRV_PCF2127 is not set ++# CONFIG_RTC_DRV_RV3029C2 is not set ++ ++# ++# Platform RTC drivers ++# ++# CONFIG_RTC_DRV_CMOS is not set ++# CONFIG_RTC_DRV_DS1286 is not set ++# CONFIG_RTC_DRV_DS1511 is not set ++# CONFIG_RTC_DRV_DS1553 is not set ++# CONFIG_RTC_DRV_DS1685_FAMILY is not set ++# CONFIG_RTC_DRV_DS1742 is not set ++# CONFIG_RTC_DRV_DS2404 is not set ++# CONFIG_RTC_DRV_STK17TA8 is not set ++# CONFIG_RTC_DRV_M48T86 is not set ++# CONFIG_RTC_DRV_M48T35 is not set ++# CONFIG_RTC_DRV_M48T59 is not set ++# CONFIG_RTC_DRV_MSM6242 is not set ++# CONFIG_RTC_DRV_BQ4802 is not set ++# CONFIG_RTC_DRV_RP5C01 is not set ++# CONFIG_RTC_DRV_V3020 is not set ++# CONFIG_RTC_DRV_ZYNQMP is not set ++ ++# ++# on-CPU RTC drivers ++# ++# CONFIG_RTC_DRV_CADENCE is not set ++# CONFIG_RTC_DRV_FTRTC010 is not set ++# CONFIG_RTC_DRV_JZ4740 is not set ++# CONFIG_RTC_DRV_R7301 is not set ++ ++# ++# HID Sensor RTC drivers ++# ++CONFIG_DMADEVICES=y ++# CONFIG_DMADEVICES_DEBUG is not set ++ ++# ++# DMA Devices ++# ++CONFIG_DMA_ENGINE=y ++CONFIG_DMA_VIRTUAL_CHANNELS=y ++CONFIG_DMA_OF=y ++# CONFIG_ALTERA_MSGDMA is not set ++# CONFIG_DMA_JZ4780 is not set ++# CONFIG_DW_AXI_DMAC is not set ++# CONFIG_FSL_EDMA is not set ++# CONFIG_IMG_MDC_DMA is not set ++# CONFIG_INTEL_IDMA64 is not set ++# CONFIG_XILINX_ZYNQMP_DPDMA is not set ++# CONFIG_QCOM_HIDMA_MGMT is not set ++# CONFIG_QCOM_HIDMA is not set ++# CONFIG_DW_DMAC is not set ++# CONFIG_SF_PDMA is not set ++ ++# ++# DMA Clients ++# ++# CONFIG_ASYNC_TX_DMA is not set ++CONFIG_DMATEST=y ++CONFIG_DMA_ENGINE_RAID=y ++ ++# ++# DMABUF options ++# ++# CONFIG_SYNC_FILE is not set ++# CONFIG_UDMABUF is not set ++# CONFIG_DMABUF_MOVE_NOTIFY is not set ++# CONFIG_DMABUF_SELFTESTS is not set ++# CONFIG_DMABUF_PROCESS_INFO is not set ++# CONFIG_DMABUF_HEAPS is not set ++# CONFIG_DMABUF_SYSFS_STATS is not set ++# end of DMABUF options ++ ++# CONFIG_AUXDISPLAY is not set ++# CONFIG_UIO is not set ++# CONFIG_VFIO is not set ++# CONFIG_VIRT_DRIVERS is not set ++# CONFIG_VIRTIO_MENU is not set ++# CONFIG_VDPA is not set ++# CONFIG_VHOST_MENU is not set ++ ++# ++# Microsoft Hyper-V guest support ++# ++# end of Microsoft Hyper-V guest support ++ ++# CONFIG_GREYBUS is not set ++CONFIG_STAGING=y ++# CONFIG_PRISM2_USB is not set ++# CONFIG_COMEDI is not set ++# CONFIG_RTLLIB is not set ++# CONFIG_RTL8723BS is not set ++# CONFIG_R8712U is not set ++# CONFIG_R8188EU is not set ++# CONFIG_VT6656 is not set ++# CONFIG_STAGING_MEDIA is not set ++ ++# ++# Android ++# ++# CONFIG_ASHMEM is not set ++# CONFIG_ION is not set ++# end of Android ++ ++# CONFIG_STAGING_BOARD is not set ++# CONFIG_LTE_GDM724X is not set ++# CONFIG_GS_FPGABOOT is not set ++# CONFIG_UNISYSSPAR is not set ++# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set ++# CONFIG_FB_TFT is not set ++# CONFIG_KS7010 is not set ++# CONFIG_PI433 is not set ++ ++# ++# Gasket devices ++# ++# end of Gasket devices ++ ++# CONFIG_XIL_AXIS_FIFO is not set ++# CONFIG_FIELDBUS_DEV is not set ++# CONFIG_WFX is not set ++CONFIG_HILOG=y ++CONFIG_HILOG_BUFFER_SIZE=4096 ++CONFIG_HIEVENT=y ++CONFIG_BBOX_BUFFER_SIZE=2048 ++# CONFIG_HISYSEVENT is not set ++# CONFIG_DFX_HUNGTASK is not set ++ ++# ++# Blackbox Options ++# ++CONFIG_BLACKBOX=y ++CONFIG_BLACKBOX_LOG_ROOT_PATH="" ++CONFIG_BLACKBOX_LOG_PART_REPRESENTATIVE="" ++# CONFIG_BLACKBOX_STORAGE_BY_MEMORY is not set ++# CONFIG_BLACKBOX_USE_PSTORE_BLK_DEBUG is not set ++# CONFIG_BLACKBOX_STORAGE_BY_RAW_PARTITION is not set ++# end of Blackbox Options ++ ++# CONFIG_MIPS_PLATFORM_DEVICES is not set ++# CONFIG_GOLDFISH is not set ++CONFIG_HAVE_CLK=y ++CONFIG_CLKDEV_LOOKUP=y ++CONFIG_HAVE_CLK_PREPARE=y ++CONFIG_COMMON_CLK=y ++# CONFIG_COMMON_CLK_MAX9485 is not set ++# CONFIG_COMMON_CLK_SI5341 is not set ++# CONFIG_COMMON_CLK_SI5351 is not set ++# CONFIG_COMMON_CLK_SI514 is not set ++# CONFIG_COMMON_CLK_SI544 is not set ++# CONFIG_COMMON_CLK_SI570 is not set ++# CONFIG_COMMON_CLK_CDCE706 is not set ++# CONFIG_COMMON_CLK_CDCE925 is not set ++# CONFIG_COMMON_CLK_CS2000_CP is not set ++# CONFIG_COMMON_CLK_PWM is not set ++# CONFIG_COMMON_CLK_VC5 is not set ++# CONFIG_COMMON_CLK_FIXED_MMIO is not set ++# CONFIG_COMMON_CLK_BOSTON is not set ++ ++# ++# Ingenic SoCs drivers ++# ++# CONFIG_INGENIC_CGU_JZ4740 is not set ++# CONFIG_INGENIC_CGU_JZ4725B is not set ++# CONFIG_INGENIC_CGU_JZ4770 is not set ++# CONFIG_INGENIC_CGU_JZ4780 is not set ++# CONFIG_INGENIC_CGU_X1000 is not set ++# CONFIG_INGENIC_CGU_X1830 is not set ++# CONFIG_INGENIC_TCU_CLK is not set ++# end of Ingenic SoCs drivers ++ ++# CONFIG_HWSPINLOCK is not set ++ ++# ++# Clock Source drivers ++# ++CONFIG_TIMER_OF=y ++CONFIG_TIMER_PROBE=y ++CONFIG_INGENIC_TIMER=y ++# CONFIG_INGENIC_SYSOST is not set ++# CONFIG_INGENIC_OST is not set ++# CONFIG_MICROCHIP_PIT64B is not set ++# end of Clock Source drivers ++ ++# CONFIG_MAILBOX is not set ++# CONFIG_IOMMU_SUPPORT is not set ++ ++# ++# Remoteproc drivers ++# ++# CONFIG_REMOTEPROC is not set ++# end of Remoteproc drivers ++ ++# ++# Rpmsg drivers ++# ++# CONFIG_RPMSG_VIRTIO is not set ++# end of Rpmsg drivers ++ ++# CONFIG_SOUNDWIRE is not set ++ ++# ++# SOC (System On Chip) specific Drivers ++# ++ ++# ++# Amlogic SoC drivers ++# ++# end of Amlogic SoC drivers ++ ++# ++# Aspeed SoC drivers ++# ++# end of Aspeed SoC drivers ++ ++# ++# Broadcom SoC drivers ++# ++# end of Broadcom SoC drivers ++ ++# ++# NXP/Freescale QorIQ SoC drivers ++# ++# end of NXP/Freescale QorIQ SoC drivers ++ ++# ++# i.MX SoC drivers ++# ++# end of i.MX SoC drivers ++ ++# ++# Qualcomm SoC drivers ++# ++# end of Qualcomm SoC drivers ++ ++# CONFIG_SOC_TI is not set ++ ++# ++# Xilinx SoC drivers ++# ++# CONFIG_XILINX_VCU is not set ++# end of Xilinx SoC drivers ++# end of SOC (System On Chip) specific Drivers ++ ++# CONFIG_PM_DEVFREQ is not set ++CONFIG_EXTCON=y ++ ++# ++# Extcon Device Drivers ++# ++# CONFIG_EXTCON_FSA9480 is not set ++# CONFIG_EXTCON_GPIO is not set ++# CONFIG_EXTCON_MAX3355 is not set ++# CONFIG_EXTCON_PTN5150 is not set ++# CONFIG_EXTCON_RT8973A is not set ++# CONFIG_EXTCON_SM5502 is not set ++# CONFIG_EXTCON_USB_GPIO is not set ++# CONFIG_MEMORY is not set ++# CONFIG_IIO is not set ++CONFIG_PWM=y ++CONFIG_PWM_SYSFS=y ++# CONFIG_PWM_DEBUG is not set ++# CONFIG_PWM_FSL_FTM is not set ++# CONFIG_PWM_IMG is not set ++# CONFIG_PWM_JZ4740 is not set ++# CONFIG_PWM_PCA9685 is not set ++ ++# ++# IRQ chip support ++# ++CONFIG_IRQCHIP=y ++# CONFIG_AL_FIC is not set ++CONFIG_IRQ_MIPS_CPU=y ++# CONFIG_INGENIC_TCU_IRQ is not set ++# end of IRQ chip support ++ ++# CONFIG_IPACK_BUS is not set ++# CONFIG_RESET_CONTROLLER is not set ++ ++# ++# PHY Subsystem ++# ++# CONFIG_GENERIC_PHY is not set ++# CONFIG_BCM_KONA_USB2_PHY is not set ++# CONFIG_PHY_CADENCE_TORRENT is not set ++# CONFIG_PHY_CADENCE_DPHY is not set ++# CONFIG_PHY_CADENCE_SALVO is not set ++# CONFIG_PHY_FSL_IMX8MQ_USB is not set ++# CONFIG_PHY_MIXEL_MIPI_DPHY is not set ++# CONFIG_PHY_PXA_28NM_HSIC is not set ++# CONFIG_PHY_PXA_28NM_USB2 is not set ++# CONFIG_PHY_MAPPHONE_MDM6600 is not set ++# CONFIG_PHY_OCELOT_SERDES is not set ++# CONFIG_PHY_SAMSUNG_USB2 is not set ++# end of PHY Subsystem ++ ++# CONFIG_POWERCAP is not set ++# CONFIG_MCB is not set ++# CONFIG_RAS is not set ++ ++# ++# Android ++# ++CONFIG_ANDROID=y ++CONFIG_ANDROID_BINDER_IPC=y ++# CONFIG_ANDROID_BINDERFS is not set ++CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder" ++# CONFIG_ANDROID_BINDER_IPC_SELFTEST is not set ++# CONFIG_BINDER_TRANSACTION_PROC_BRIEF is not set ++# end of Android ++ ++# CONFIG_DAX is not set ++CONFIG_NVMEM=y ++CONFIG_NVMEM_SYSFS=y ++ ++# ++# HW tracing support ++# ++# CONFIG_STM is not set ++# CONFIG_INTEL_TH is not set ++# end of HW tracing support ++ ++# CONFIG_FPGA is not set ++# CONFIG_FSI is not set ++# CONFIG_SIOX is not set ++# CONFIG_SLIMBUS is not set ++# CONFIG_INTERCONNECT is not set ++# CONFIG_COUNTER is not set ++CONFIG_DRIVERS_HDF=y ++CONFIG_HDF_SUPPORT_LEVEL=1 ++CONFIG_DRIVERS_HDF_PLATFORM=y ++# CONFIG_DRIVERS_HDF_PLATFORM_MIPI_DSI is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_MIPI_CSI is not set ++CONFIG_DRIVERS_HDF_PLATFORM_GPIO=y ++CONFIG_DRIVERS_HDF_PLATFORM_I2C=y ++# CONFIG_DRIVERS_HDF_PLATFORM_WATCHDOG is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_PWM is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_UART is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_EMMC is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_MMC is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_SPI is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_RTC is not set ++# CONFIG_PWM_HI35XX is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_REGULATOR is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_ADC is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_TRACE is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_DUMPER is not set ++# CONFIG_IMX8MM_EMMC is not set ++# CONFIG_IMX8MM_SDIO is not set ++# CONFIG_DRIVERS_HDF_PLATFORM_IMX8MM_MIPI_DSI is not set ++# CONFIG_DRIVERS_HDF_TEST is not set ++# CONFIG_DRIVERS_HDF_DISP is not set ++CONFIG_DRIVERS_HDF_INPUT=y ++CONFIG_DRIVERS_HDF_TP_5P5_GT911=y ++# CONFIG_DRIVERS_HDF_TP_2P35_FT6236 is not set ++# CONFIG_DRIVERS_HDF_INPUT_INFRARED is not set ++# CONFIG_DRIVERS_HDF_TP_5P43_FT5406 is not set ++# CONFIG_ARCH_NXP_TOUCH is not set ++# CONFIG_DRIVERS_HDF_NETDEV_EXT is not set ++# CONFIG_DRIVERS_HDF_BT is not set ++# CONFIG_DRIVERS_HDF_SENSOR is not set ++# CONFIG_DRIVERS_HDF_STORAGE is not set ++# CONFIG_IMX8MM_SDIO_TEST is not set ++# CONFIG_DRIVERS_HDF_USB_PNP_NOTIFY is not set ++# CONFIG_DRIVERS_HDF_AUDIO is not set ++# CONFIG_DRIVERS_HDF_VIBRATOR is not set ++# CONFIG_DRIVERS_HDF_DSOFTBUS is not set ++# CONFIG_DRIVERS_HDF_LIGHT is not set ++# CONFIG_DRIVERS_HDF_NETWORK is not set ++# CONFIG_MOST is not set ++# CONFIG_ACCESS_TOKENID is not set ++ ++# ++# Vendor Hooks ++# ++# end of Vendor Hooks ++# end of Device Drivers ++ ++# ++# File systems ++# ++# CONFIG_VALIDATE_FS_PARSER is not set ++# CONFIG_EXT2_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_EXT4_FS is not set ++# CONFIG_HMDFS_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_XFS_FS is not set ++# CONFIG_GFS2_FS is not set ++# CONFIG_OCFS2_FS is not set ++# CONFIG_BTRFS_FS is not set ++# CONFIG_NILFS2_FS is not set ++# CONFIG_F2FS_FS is not set ++CONFIG_EXPORTFS=y ++# CONFIG_EXPORTFS_BLOCK_OPS is not set ++CONFIG_FILE_LOCKING=y ++CONFIG_MANDATORY_FILE_LOCKING=y ++# CONFIG_FS_ENCRYPTION is not set ++# CONFIG_FS_VERITY is not set ++CONFIG_FSNOTIFY=y ++# CONFIG_DNOTIFY is not set ++CONFIG_INOTIFY_USER=y ++# CONFIG_FANOTIFY is not set ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_FUSE_FS is not set ++# CONFIG_OVERLAY_FS is not set ++ ++# ++# Caches ++# ++# CONFIG_FSCACHE is not set ++# end of Caches ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++# end of CD-ROM/DVD Filesystems ++ ++# ++# DOS/FAT/EXFAT/NT Filesystems ++# ++CONFIG_FAT_FS=y ++# CONFIG_MSDOS_FS is not set ++CONFIG_VFAT_FS=y ++CONFIG_FAT_DEFAULT_CODEPAGE=437 ++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" ++# CONFIG_FAT_DEFAULT_UTF8 is not set ++# CONFIG_EXFAT_FS is not set ++# CONFIG_NTFS_FS is not set ++# end of DOS/FAT/EXFAT/NT Filesystems ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++CONFIG_PROC_KCORE=y ++CONFIG_PROC_SYSCTL=y ++# CONFIG_PROC_PAGE_MONITOR is not set ++# CONFIG_PROC_CHILDREN is not set ++CONFIG_KERNFS=y ++CONFIG_SYSFS=y ++CONFIG_TMPFS=y ++# CONFIG_TMPFS_POSIX_ACL is not set ++# CONFIG_TMPFS_XATTR is not set ++CONFIG_MEMFD_CREATE=y ++CONFIG_CONFIGFS_FS=y ++# end of Pseudo filesystems ++ ++CONFIG_MISC_FILESYSTEMS=y ++# CONFIG_ORANGEFS_FS is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_ECRYPT_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS2_FS is not set ++CONFIG_UBIFS_FS=y ++CONFIG_UBIFS_FS_ADVANCED_COMPR=y ++CONFIG_UBIFS_FS_LZO=y ++# CONFIG_UBIFS_FS_ZLIB is not set ++CONFIG_UBIFS_FS_ZSTD=y ++CONFIG_UBIFS_ATIME_SUPPORT=y ++CONFIG_UBIFS_FS_XATTR=y ++CONFIG_UBIFS_FS_SECURITY=y ++# CONFIG_UBIFS_FS_AUTHENTICATION is not set ++# CONFIG_CRAMFS is not set ++# CONFIG_SQUASHFS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_OMFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX6FS_FS is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_PSTORE is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_EROFS_FS is not set ++CONFIG_NETWORK_FILESYSTEMS=y ++# CONFIG_NFS_FS is not set ++# CONFIG_NFSD is not set ++# CONFIG_CEPH_FS is not set ++# CONFIG_CIFS is not set ++# CONFIG_CODA_FS is not set ++# CONFIG_AFS_FS is not set ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=y ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ASCII=y ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_MAC_ROMAN is not set ++# CONFIG_NLS_MAC_CELTIC is not set ++# CONFIG_NLS_MAC_CENTEURO is not set ++# CONFIG_NLS_MAC_CROATIAN is not set ++# CONFIG_NLS_MAC_CYRILLIC is not set ++# CONFIG_NLS_MAC_GAELIC is not set ++# CONFIG_NLS_MAC_GREEK is not set ++# CONFIG_NLS_MAC_ICELAND is not set ++# CONFIG_NLS_MAC_INUIT is not set ++# CONFIG_NLS_MAC_ROMANIAN is not set ++# CONFIG_NLS_MAC_TURKISH is not set ++CONFIG_NLS_UTF8=y ++# CONFIG_DLM is not set ++# CONFIG_UNICODE is not set ++CONFIG_IO_WQ=y ++# end of File systems ++ ++# ++# Security options ++# ++CONFIG_KEYS=y ++# CONFIG_KEYS_REQUEST_CACHE is not set ++# CONFIG_PERSISTENT_KEYRINGS is not set ++# CONFIG_ENCRYPTED_KEYS is not set ++# CONFIG_KEY_DH_OPERATIONS is not set ++# CONFIG_SECURITY_DMESG_RESTRICT is not set ++# CONFIG_SECURITY is not set ++# CONFIG_SECURITYFS is not set ++CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y ++# CONFIG_HARDENED_USERCOPY is not set ++# CONFIG_STATIC_USERMODEHELPER is not set ++CONFIG_DEFAULT_SECURITY_DAC=y ++CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,bpf" ++ ++# ++# Kernel hardening options ++# ++ ++# ++# Memory initialization ++# ++CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y ++CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y ++CONFIG_INIT_STACK_NONE=y ++# CONFIG_INIT_STACK_ALL_PATTERN is not set ++# CONFIG_INIT_STACK_ALL_ZERO is not set ++# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set ++# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set ++# end of Memory initialization ++# end of Kernel hardening options ++# end of Security options ++ ++CONFIG_CRYPTO=y ++ ++# ++# Crypto core or helper ++# ++CONFIG_CRYPTO_ALGAPI=y ++CONFIG_CRYPTO_ALGAPI2=y ++CONFIG_CRYPTO_AEAD=y ++CONFIG_CRYPTO_AEAD2=y ++CONFIG_CRYPTO_SKCIPHER=y ++CONFIG_CRYPTO_SKCIPHER2=y ++CONFIG_CRYPTO_HASH=y ++CONFIG_CRYPTO_HASH2=y ++CONFIG_CRYPTO_RNG=y ++CONFIG_CRYPTO_RNG2=y ++CONFIG_CRYPTO_RNG_DEFAULT=y ++CONFIG_CRYPTO_AKCIPHER2=y ++CONFIG_CRYPTO_AKCIPHER=y ++CONFIG_CRYPTO_KPP2=y ++CONFIG_CRYPTO_ACOMP2=y ++CONFIG_CRYPTO_MANAGER=y ++CONFIG_CRYPTO_MANAGER2=y ++# CONFIG_CRYPTO_USER is not set ++# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set ++# CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is not set ++CONFIG_CRYPTO_GF128MUL=y ++CONFIG_CRYPTO_NULL=y ++CONFIG_CRYPTO_NULL2=y ++# CONFIG_CRYPTO_PCRYPT is not set ++# CONFIG_CRYPTO_CRYPTD is not set ++# CONFIG_CRYPTO_AUTHENC is not set ++# CONFIG_CRYPTO_TEST is not set ++ ++# ++# Public-key cryptography ++# ++CONFIG_CRYPTO_RSA=y ++# CONFIG_CRYPTO_DH is not set ++# CONFIG_CRYPTO_ECDH is not set ++# CONFIG_CRYPTO_ECRDSA is not set ++# CONFIG_CRYPTO_SM2 is not set ++# CONFIG_CRYPTO_CURVE25519 is not set ++ ++# ++# Authenticated Encryption with Associated Data ++# ++CONFIG_CRYPTO_CCM=y ++CONFIG_CRYPTO_GCM=y ++# CONFIG_CRYPTO_CHACHA20POLY1305 is not set ++# CONFIG_CRYPTO_AEGIS128 is not set ++CONFIG_CRYPTO_SEQIV=y ++# CONFIG_CRYPTO_ECHAINIV is not set ++ ++# ++# Block modes ++# ++# CONFIG_CRYPTO_CBC is not set ++# CONFIG_CRYPTO_CFB is not set ++CONFIG_CRYPTO_CTR=y ++# CONFIG_CRYPTO_CTS is not set ++CONFIG_CRYPTO_ECB=y ++# CONFIG_CRYPTO_LRW is not set ++# CONFIG_CRYPTO_OFB is not set ++# CONFIG_CRYPTO_PCBC is not set ++# CONFIG_CRYPTO_XTS is not set ++# CONFIG_CRYPTO_KEYWRAP is not set ++# CONFIG_CRYPTO_ADIANTUM is not set ++# CONFIG_CRYPTO_ESSIV is not set ++ ++# ++# Hash modes ++# ++CONFIG_CRYPTO_CMAC=y ++CONFIG_CRYPTO_HMAC=y ++# CONFIG_CRYPTO_XCBC is not set ++# CONFIG_CRYPTO_VMAC is not set ++ ++# ++# Digest ++# ++CONFIG_CRYPTO_CRC32C=y ++# CONFIG_CRYPTO_CRC32 is not set ++# CONFIG_CRYPTO_XXHASH is not set ++# CONFIG_CRYPTO_BLAKE2B is not set ++# CONFIG_CRYPTO_BLAKE2S is not set ++CONFIG_CRYPTO_CRCT10DIF=y ++CONFIG_CRYPTO_GHASH=y ++# CONFIG_CRYPTO_POLY1305 is not set ++# CONFIG_CRYPTO_POLY1305_MIPS is not set ++# CONFIG_CRYPTO_MD4 is not set ++# CONFIG_CRYPTO_MD5 is not set ++# CONFIG_CRYPTO_MICHAEL_MIC is not set ++# CONFIG_CRYPTO_RMD128 is not set ++# CONFIG_CRYPTO_RMD160 is not set ++# CONFIG_CRYPTO_RMD256 is not set ++# CONFIG_CRYPTO_RMD320 is not set ++# CONFIG_CRYPTO_SHA1 is not set ++CONFIG_CRYPTO_SHA256=y ++# CONFIG_CRYPTO_SHA512 is not set ++# CONFIG_CRYPTO_SHA3 is not set ++# CONFIG_CRYPTO_SM3 is not set ++# CONFIG_CRYPTO_STREEBOG is not set ++# CONFIG_CRYPTO_TGR192 is not set ++# CONFIG_CRYPTO_WP512 is not set ++ ++# ++# Ciphers ++# ++CONFIG_CRYPTO_AES=y ++# CONFIG_CRYPTO_AES_TI is not set ++# CONFIG_CRYPTO_BLOWFISH is not set ++# CONFIG_CRYPTO_CAMELLIA is not set ++# CONFIG_CRYPTO_CAST5 is not set ++# CONFIG_CRYPTO_CAST6 is not set ++# CONFIG_CRYPTO_DES is not set ++# CONFIG_CRYPTO_FCRYPT is not set ++# CONFIG_CRYPTO_SALSA20 is not set ++# CONFIG_CRYPTO_CHACHA20 is not set ++# CONFIG_CRYPTO_SERPENT is not set ++# CONFIG_CRYPTO_SM4 is not set ++# CONFIG_CRYPTO_TWOFISH is not set ++ ++# ++# Compression ++# ++CONFIG_CRYPTO_DEFLATE=y ++CONFIG_CRYPTO_LZO=y ++# CONFIG_CRYPTO_842 is not set ++# CONFIG_CRYPTO_LZ4 is not set ++# CONFIG_CRYPTO_LZ4HC is not set ++CONFIG_CRYPTO_ZSTD=y ++ ++# ++# Random Number Generation ++# ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_DRBG_MENU=y ++CONFIG_CRYPTO_DRBG_HMAC=y ++# CONFIG_CRYPTO_DRBG_HASH is not set ++# CONFIG_CRYPTO_DRBG_CTR is not set ++CONFIG_CRYPTO_DRBG=y ++CONFIG_CRYPTO_JITTERENTROPY=y ++# CONFIG_CRYPTO_USER_API_HASH is not set ++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set ++# CONFIG_CRYPTO_USER_API_RNG is not set ++# CONFIG_CRYPTO_USER_API_AEAD is not set ++CONFIG_CRYPTO_HASH_INFO=y ++ ++# ++# Crypto library routines ++# ++CONFIG_CRYPTO_LIB_AES=y ++CONFIG_CRYPTO_LIB_ARC4=y ++# CONFIG_CRYPTO_LIB_BLAKE2S is not set ++# CONFIG_CRYPTO_LIB_CHACHA is not set ++# CONFIG_CRYPTO_LIB_CURVE25519 is not set ++CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2 ++# CONFIG_CRYPTO_LIB_POLY1305 is not set ++# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set ++CONFIG_CRYPTO_LIB_SHA256=y ++CONFIG_CRYPTO_HW=y ++# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set ++# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set ++# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set ++# CONFIG_CRYPTO_DEV_SAFEXCEL is not set ++# CONFIG_CRYPTO_DEV_CCREE is not set ++# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set ++CONFIG_ASYMMETRIC_KEY_TYPE=y ++CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y ++CONFIG_X509_CERTIFICATE_PARSER=y ++# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set ++CONFIG_PKCS7_MESSAGE_PARSER=y ++# CONFIG_PKCS7_TEST_KEY is not set ++# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set ++ ++# ++# Certificates for signature checking ++# ++CONFIG_SYSTEM_TRUSTED_KEYRING=y ++CONFIG_SYSTEM_TRUSTED_KEYS="" ++# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set ++# CONFIG_SECONDARY_TRUSTED_KEYRING is not set ++# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set ++# end of Certificates for signature checking ++ ++# ++# Library routines ++# ++# CONFIG_PACKING is not set ++CONFIG_BITREVERSE=y ++CONFIG_GENERIC_NET_UTILS=y ++# CONFIG_CORDIC is not set ++# CONFIG_PRIME_NUMBERS is not set ++CONFIG_RATIONAL=y ++CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y ++CONFIG_GENERIC_PCI_IOMAP=y ++CONFIG_GENERIC_IOMAP=y ++# CONFIG_CRC_CCITT is not set ++CONFIG_CRC16=y ++CONFIG_CRC_T10DIF=y ++# CONFIG_CRC_ITU_T is not set ++CONFIG_CRC32=y ++# CONFIG_CRC32_SELFTEST is not set ++CONFIG_CRC32_SLICEBY8=y ++# CONFIG_CRC32_SLICEBY4 is not set ++# CONFIG_CRC32_SARWATE is not set ++# CONFIG_CRC32_BIT is not set ++# CONFIG_CRC64 is not set ++# CONFIG_CRC4 is not set ++# CONFIG_CRC7 is not set ++# CONFIG_LIBCRC32C is not set ++# CONFIG_CRC8 is not set ++CONFIG_XXHASH=y ++# CONFIG_RANDOM32_SELFTEST is not set ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=y ++CONFIG_LZO_COMPRESS=y ++CONFIG_LZO_DECOMPRESS=y ++CONFIG_ZSTD_COMPRESS=y ++CONFIG_ZSTD_DECOMPRESS=y ++# CONFIG_XZ_DEC is not set ++CONFIG_GENERIC_ALLOCATOR=y ++CONFIG_INTERVAL_TREE=y ++CONFIG_ASSOCIATIVE_ARRAY=y ++CONFIG_HAS_IOMEM=y ++CONFIG_HAS_IOPORT_MAP=y ++CONFIG_HAS_DMA=y ++CONFIG_NEED_DMA_MAP_STATE=y ++CONFIG_ARCH_HAS_DMA_WRITE_COMBINE=y ++CONFIG_DMA_DECLARE_COHERENT=y ++CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y ++CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y ++CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y ++CONFIG_DMA_NONCOHERENT_MMAP=y ++# CONFIG_DMA_API_DEBUG is not set ++CONFIG_SGL_ALLOC=y ++CONFIG_CPU_RMAP=y ++CONFIG_DQL=y ++CONFIG_NLATTR=y ++CONFIG_GENERIC_ATOMIC64=y ++CONFIG_CLZ_TAB=y ++# CONFIG_IRQ_POLL is not set ++CONFIG_MPILIB=y ++CONFIG_LIBFDT=y ++CONFIG_OID_REGISTRY=y ++CONFIG_HAVE_GENERIC_VDSO=y ++CONFIG_GENERIC_GETTIMEOFDAY=y ++CONFIG_SG_POOL=y ++CONFIG_SBITMAP=y ++# CONFIG_STRING_SELFTEST is not set ++# end of Library routines ++ ++CONFIG_GENERIC_LIB_ASHLDI3=y ++CONFIG_GENERIC_LIB_ASHRDI3=y ++CONFIG_GENERIC_LIB_LSHRDI3=y ++CONFIG_GENERIC_LIB_CMPDI2=y ++CONFIG_GENERIC_LIB_UCMPDI2=y ++ ++# ++# Kernel hacking ++# ++ ++# ++# printk and dmesg options ++# ++CONFIG_PRINTK_TIME=y ++# CONFIG_PRINTK_CALLER is not set ++CONFIG_CONSOLE_LOGLEVEL_DEFAULT=4 ++CONFIG_CONSOLE_LOGLEVEL_QUIET=4 ++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 ++# CONFIG_BOOT_PRINTK_DELAY is not set ++CONFIG_DYNAMIC_DEBUG=y ++CONFIG_DYNAMIC_DEBUG_CORE=y ++CONFIG_SYMBOLIC_ERRNAME=y ++# end of printk and dmesg options ++ ++# ++# Compile-time checks and compiler options ++# ++# CONFIG_DEBUG_INFO is not set ++# CONFIG_ENABLE_MUST_CHECK is not set ++CONFIG_FRAME_WARN=1024 ++# CONFIG_STRIP_ASM_SYMS is not set ++# CONFIG_READABLE_ASM is not set ++# CONFIG_HEADERS_INSTALL is not set ++# CONFIG_DEBUG_SECTION_MISMATCH is not set ++CONFIG_SECTION_MISMATCH_WARN_ONLY=y ++# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set ++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set ++# end of Compile-time checks and compiler options ++ ++# ++# Generic Kernel Debugging Instruments ++# ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 ++CONFIG_MAGIC_SYSRQ_SERIAL=y ++CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" ++CONFIG_DEBUG_FS=y ++CONFIG_DEBUG_FS_ALLOW_ALL=y ++# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set ++# CONFIG_DEBUG_FS_ALLOW_NONE is not set ++CONFIG_HAVE_ARCH_KGDB=y ++# CONFIG_KGDB is not set ++CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y ++# CONFIG_UBSAN is not set ++# end of Generic Kernel Debugging Instruments ++ ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_MISC is not set ++ ++# ++# Memory Debugging ++# ++# CONFIG_PAGE_EXTENSION is not set ++# CONFIG_DEBUG_PAGEALLOC is not set ++# CONFIG_PAGE_OWNER is not set ++# CONFIG_PAGE_POISONING is not set ++# CONFIG_DEBUG_OBJECTS is not set ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_HAVE_DEBUG_KMEMLEAK=y ++# CONFIG_DEBUG_KMEMLEAK is not set ++# CONFIG_DEBUG_STACK_USAGE is not set ++# CONFIG_SCHED_STACK_END_CHECK is not set ++# CONFIG_DEBUG_VM is not set ++# CONFIG_DEBUG_MEMORY_INIT is not set ++# CONFIG_DEBUG_PER_CPU_MAPS is not set ++CONFIG_HAVE_DEBUG_STACKOVERFLOW=y ++CONFIG_DEBUG_STACKOVERFLOW=y ++CONFIG_CC_HAS_KASAN_GENERIC=y ++CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y ++# end of Memory Debugging ++ ++# CONFIG_DEBUG_SHIRQ is not set ++ ++# ++# Debug Oops, Lockups and Hangs ++# ++# CONFIG_PANIC_ON_OOPS is not set ++CONFIG_PANIC_ON_OOPS_VALUE=0 ++CONFIG_PANIC_TIMEOUT=10 ++CONFIG_LOCKUP_DETECTOR=y ++CONFIG_SOFTLOCKUP_DETECTOR=y ++# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set ++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 ++CONFIG_DETECT_HUNG_TASK=y ++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 ++# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set ++CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 ++CONFIG_WQ_WATCHDOG=y ++# CONFIG_TEST_LOCKUP is not set ++# end of Debug Oops, Lockups and Hangs ++ ++# ++# Scheduler Debugging ++# ++CONFIG_SCHED_DEBUG=y ++# CONFIG_SCHEDSTATS is not set ++# end of Scheduler Debugging ++ ++# CONFIG_DEBUG_TIMEKEEPING is not set ++# CONFIG_DEBUG_PREEMPT is not set ++ ++# ++# Lock Debugging (spinlocks, mutexes, etc...) ++# ++CONFIG_LOCK_DEBUGGING_SUPPORT=y ++# CONFIG_PROVE_LOCKING is not set ++# CONFIG_LOCK_STAT is not set ++# CONFIG_DEBUG_RT_MUTEXES is not set ++CONFIG_DEBUG_SPINLOCK=y ++# CONFIG_DEBUG_MUTEXES is not set ++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set ++# CONFIG_DEBUG_RWSEMS is not set ++# CONFIG_DEBUG_LOCK_ALLOC is not set ++# CONFIG_DEBUG_ATOMIC_SLEEP is not set ++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set ++# CONFIG_LOCK_TORTURE_TEST is not set ++# CONFIG_WW_MUTEX_SELFTEST is not set ++# CONFIG_SCF_TORTURE_TEST is not set ++# end of Lock Debugging (spinlocks, mutexes, etc...) ++ ++CONFIG_STACKTRACE=y ++# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set ++# CONFIG_DEBUG_KOBJECT is not set ++ ++# ++# Debug kernel data structures ++# ++# CONFIG_DEBUG_LIST is not set ++# CONFIG_DEBUG_PLIST is not set ++# CONFIG_DEBUG_SG is not set ++CONFIG_DEBUG_NOTIFIERS=y ++# CONFIG_BUG_ON_DATA_CORRUPTION is not set ++# end of Debug kernel data structures ++ ++# CONFIG_DEBUG_CREDENTIALS is not set ++ ++# ++# RCU Debugging ++# ++# CONFIG_RCU_SCALE_TEST is not set ++# CONFIG_RCU_TORTURE_TEST is not set ++# CONFIG_RCU_REF_SCALE_TEST is not set ++CONFIG_RCU_CPU_STALL_TIMEOUT=21 ++# CONFIG_RCU_TRACE is not set ++# CONFIG_RCU_EQS_DEBUG is not set ++# end of RCU Debugging ++ ++# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set ++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set ++# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set ++# CONFIG_LATENCYTOP is not set ++CONFIG_HAVE_FUNCTION_TRACER=y ++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y ++CONFIG_HAVE_DYNAMIC_FTRACE=y ++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y ++CONFIG_HAVE_SYSCALL_TRACEPOINTS=y ++CONFIG_HAVE_C_RECORDMCOUNT=y ++CONFIG_TRACING_SUPPORT=y ++# CONFIG_FTRACE is not set ++# CONFIG_SAMPLES is not set ++ ++# ++# mips Debugging ++# ++CONFIG_TRACE_IRQFLAGS_SUPPORT=y ++CONFIG_EARLY_PRINTK=y ++# CONFIG_CMDLINE_BOOL is not set ++CONFIG_SPINLOCK_TEST=y ++# CONFIG_SCACHE_DEBUGFS is not set ++# end of mips Debugging ++ ++# ++# Kernel Testing and Coverage ++# ++# CONFIG_KUNIT is not set ++# CONFIG_NOTIFIER_ERROR_INJECTION is not set ++# CONFIG_FAULT_INJECTION is not set ++CONFIG_ARCH_HAS_KCOV=y ++CONFIG_CC_HAS_SANCOV_TRACE_PC=y ++# CONFIG_KCOV is not set ++CONFIG_RUNTIME_TESTING_MENU=y ++# CONFIG_LKDTM is not set ++# CONFIG_TEST_LIST_SORT is not set ++# CONFIG_TEST_MIN_HEAP is not set ++# CONFIG_TEST_SORT is not set ++# CONFIG_BACKTRACE_SELF_TEST is not set ++# CONFIG_RBTREE_TEST is not set ++# CONFIG_REED_SOLOMON_TEST is not set ++# CONFIG_INTERVAL_TREE_TEST is not set ++# CONFIG_PERCPU_TEST is not set ++# CONFIG_ATOMIC64_SELFTEST is not set ++# CONFIG_TEST_HEXDUMP is not set ++# CONFIG_TEST_STRING_HELPERS is not set ++# CONFIG_TEST_STRSCPY is not set ++# CONFIG_TEST_KSTRTOX is not set ++# CONFIG_TEST_PRINTF is not set ++# CONFIG_TEST_BITMAP is not set ++# CONFIG_TEST_UUID is not set ++# CONFIG_TEST_XARRAY is not set ++# CONFIG_TEST_OVERFLOW is not set ++# CONFIG_TEST_RHASHTABLE is not set ++# CONFIG_TEST_HASH is not set ++# CONFIG_TEST_IDA is not set ++# CONFIG_TEST_LKM is not set ++# CONFIG_TEST_BITOPS is not set ++# CONFIG_TEST_VMALLOC is not set ++# CONFIG_TEST_USER_COPY is not set ++# CONFIG_TEST_BPF is not set ++# CONFIG_TEST_BLACKHOLE_DEV is not set ++# CONFIG_FIND_BIT_BENCHMARK is not set ++# CONFIG_TEST_FIRMWARE is not set ++# CONFIG_TEST_SYSCTL is not set ++# CONFIG_TEST_UDELAY is not set ++# CONFIG_TEST_STATIC_KEYS is not set ++# CONFIG_TEST_KMOD is not set ++# CONFIG_TEST_MEMCAT_P is not set ++# CONFIG_TEST_STACKINIT is not set ++# CONFIG_TEST_MEMINIT is not set ++# CONFIG_TEST_FREE_PAGES is not set ++# CONFIG_MEMTEST is not set ++# end of Kernel Testing and Coverage ++# end of Kernel hacking ++ ++# ++# Ingenic device-drivers Configurations ++# ++CONFIG_OUTSIDE_DRIVERS_PATH="module_drivers" ++ ++# ++# ---- Minimal required Drivers ---- ++# ++ ++# ++# [Interrupt] Drivers ++# ++CONFIG_IRQ_INGENIC_CPU=y ++CONFIG_INGENIC_INTC_CHIP=y ++# end of [Interrupt] Drivers ++ ++# ++# [OST] clocksoure Drivers ++# ++CONFIG_CLKSRC_INGENIC_CORE_OST=y ++# end of [OST] clocksoure Drivers ++ ++# ++# [CPM] clk Drivers ++# ++CONFIG_COMMON_CLK_INGENIC=y ++CONFIG_INGENIC_CLK_DEBUG_FS=y ++CONFIG_CLK_X2000=y ++# end of [CPM] clk Drivers ++ ++# ++# [GPIO] Pinctroller Drivers ++# ++CONFIG_PINCTRL_INGENIC_V2=y ++# CONFIG_MULTI_VGPIO_INGENIC is not set ++# end of [GPIO] Pinctroller Drivers ++ ++# ++# [UART] Drivers ++# ++CONFIG_SERIAL_INGENIC_UART=y ++CONFIG_SERIAL_INGENIC_CONSOLE=y ++CONFIG_SERIAL_INGENIC_LARGE_BAUDRATE=y ++CONFIG_SERIAL_INGENIC_MAGIC_SYSRQ=y ++# end of [UART] Drivers ++ ++# ++# [MSC] (eMMC/SD/SDIO) and Device Drivers ++# ++CONFIG_MMC_SDHCI_INGENIC=y ++CONFIG_MMC_INDEX_MATCH_CONTROLLER=y ++# end of [MSC] (eMMC/SD/SDIO) and Device Drivers ++ ++# ++# [DMA] Drivers ++# ++CONFIG_INGENIC_PDMAC=y ++# CONFIG_INGENIC_AIC_USES_PDMA is not set ++# end of [DMA] Drivers ++ ++# ++# [SFC] (SPI Nand/Nor Flash) Drivers ++# ++CONFIG_INGENIC_SFC=y ++# CONFIG_MTD_INGENIC_SFC_V1 is not set ++CONFIG_MTD_INGENIC_SFC_V2=y ++CONFIG_MTD_INGENIC_SFC_NORFLASH=y ++# CONFIG_MTD_INGENIC_SFC_NANDFLASH is not set ++# CONFIG_INGENIC_BUILTIN_PARAMS is not set ++# end of [SFC] (SPI Nand/Nor Flash) Drivers ++ ++# ++# [SPI] Master/Slave Drivers ++# ++CONFIG_INGENIC_SPI=y ++CONFIG_INGENIC_SPI0=y ++# CONFIG_INGENIC_SPI_PIO_CE is not set ++# end of [SPI] Master/Slave Drivers ++ ++# ++# [I2C] Master Drivers ++# ++CONFIG_I2C_INGENIC=y ++# CONFIG_I2C_NON_RESTART_MODE is not set ++CONFIG_I2C_FIFO_LEN=64 ++# CONFIG_I2C_DEBUG_INFO is not set ++# end of [I2C] Master Drivers ++ ++# ++# ---- minimal OS requirements. ---- ++# ++ ++# ++# [LCD] Panel/Touchscreen Drivers ++# ++CONFIG_FB_INGENIC=y ++# CONFIG_FB_VSYNC_SKIP_DISABLE is not set ++CONFIG_FB_VSYNC_SKIP=9 ++CONFIG_FB_INGENIC_NR_FRAMES=3 ++CONFIG_FB_INGENIC_NR_LAYERS=2 ++# CONFIG_FB_INGENIC_DEBUG is not set ++# CONFIG_SLCDC_CONTINUA is not set ++# CONFIG_SLCDC_USE_TE is not set ++CONFIG_FB_INGENIC_STAGE=y ++CONFIG_FB_INGENIC_DISPLAYS_STAGE=y ++# CONFIG_STAGE_Y88249 is not set ++# CONFIG_STAGE_KD050HDFIA019 is not set ++# CONFIG_STAGE_MA0060 is not set ++CONFIG_STAGE_KD050HDFIA020=y ++# CONFIG_STAGE_FW050 is not set ++# CONFIG_STAGE_FW040 is not set ++# CONFIG_STAGE_FW035 is not set ++# CONFIG_STAGE_TL040WVS03CT is not set ++# CONFIG_STAGE_TL040HDS01CT is not set ++# CONFIG_STAGE_JD9161Z is not set ++# CONFIG_STAGE_JD9365D is not set ++# CONFIG_STAGE_ATK7016 is not set ++# CONFIG_STAGE_JD9365 is not set ++# CONFIG_STAGE_GC9203 is not set ++# CONFIG_STAGE_ST7701S is not set ++# CONFIG_STAGE_ST7701S_RGB666 is not set ++# CONFIG_STAGE_ST7701S_DX is not set ++# CONFIG_STAGE_YTS500XLAI is not set ++# CONFIG_STAGE_YLYM286A is not set ++# CONFIG_STAGE_KD035HVFBD037 is not set ++# CONFIG_PANEL_STAGE_MV238FHM_N30 is not set ++# CONFIG_STAGE_EK79007AD is not set ++# CONFIG_STAGE_JD9366 is not set ++# CONFIG_STAGE_BM8766 is not set ++# CONFIG_STAGE_KD050WVFPA029 is not set ++# CONFIG_STAGE_GWMTF16499B is not set ++# CONFIG_STAGE_ST7282 is not set ++# CONFIG_STAGE_G104X1L04 is not set ++# CONFIG_STAGE_KD035HVFMD057 is not set ++CONFIG_TRUE_COLOR_LOGO=y ++CONFIG_TRUE_COLOR_LOGO_FILE="module_drivers/drivers/video/logo-ingenic/logo.png" ++CONFIG_TRUE_COLOR_LOGO_BACKGROUND=0xffffffff ++ ++# ++# Touchscreen Drivers ++# ++# CONFIG_TOUCHSCREEN_FTS is not set ++# CONFIG_TOUCHSCREEN_HYN is not set ++# CONFIG_TOUCHSCREEN_GT9XX is not set ++# CONFIG_TOUCHSCREEN_FT6236 is not set ++# CONFIG_TOUCHSCREEN_MXT336U is not set ++# end of Touchscreen Drivers ++# end of [LCD] Panel/Touchscreen Drivers ++ ++# ++# [GMAC] (ethernet) Drivers ++# ++CONFIG_INGENIC_MAC=y ++CONFIG_INGENIC_MAC_DMA_INTERFACES=y ++CONFIG_INGENIC_MAC_AXI_BUS=y ++# CONFIG_INGENIC_MAC_AHB_BUS is not set ++# CONFIG_INGENIC_GMAC_USE_HWSTAMP is not set ++# CONFIG_INGENIC_GMAC_MUTUAL_TRANS is not set ++CONFIG_INGENIC_GMAC_RX_DESC_COUNT=512 ++# end of [GMAC] (ethernet) Drivers ++ ++# ++# [WIFI] Drivers ++# ++# CONFIG_BCMDHD_1_363_125_17 is not set ++CONFIG_BCMDHD=y ++CONFIG_BCMDHD_FW_PATH="/firmware/fw_bcm43456c5_ag.bin" ++CONFIG_BCMDHD_NVRAM_PATH="/firmware/nvram_ap6256.txt" ++CONFIG_BCMDHD_SDIO=y ++# CONFIG_BCMDHD_USB is not set ++CONFIG_BCMDHD_OOB=y ++# CONFIG_BCMDHD_SDIO_IRQ is not set ++# CONFIG_RTL8723DS is not set ++# end of [WIFI] Drivers ++ ++# ++# [CAN] (ethernet) Drivers ++# ++ ++# ++# ---- (V4L2) Media Device Drivers ---- ++# ++CONFIG_VIDEOBUF2_DMA_CONTIG_INGENIC=y ++CONFIG_CAMERA_RESERVE_KB_SIZE=0 ++ ++# ++# [ISP] Drivers ++# ++# CONFIG_VIDEO_INGENIC_ISP is not set ++# end of [ISP] Drivers ++ ++# ++# [CIM] Drivers ++# ++# CONFIG_VIDEO_INGENIC_CIM is not set ++# end of [CIM] Drivers ++ ++# ++# [Rotator] Drivers ++# ++CONFIG_VIDEO_INGENIC_ROTATE=y ++# end of [Rotator] Drivers ++ ++# ++# [VPU] Drivers ++# ++CONFIG_VIDEO_INGENIC_VCODEC=y ++CONFIG_INGENIC_HELIX=y ++CONFIG_INGENIC_FELIX=y ++# end of [VPU] Drivers ++ ++# ++# [Sensors] Camera Sensors ++# ++ ++# ++# ingenic-isp camera sensor drivers ++# ++ ++# ++# ingenic-isp-v2 camera sensor drivers ++# ++ ++# ++# ingenic-cim camera sensor drivers ++# ++# end of [Sensors] Camera Sensors ++ ++# ++# ---- MISC Device Drivers ---- ++# ++# CONFIG_INGENIC_RSA is not set ++# CONFIG_LINUX_PMEM is not set ++# CONFIG_INGENIC_EFUSE_X2000 is not set ++CONFIG_BCM_4345C5_RFKILL=y ++ ++# ++# [RANDOM] drivers ++# ++# CONFIG_HW_RANDOM_INGENIC is not set ++# end of [RANDOM] drivers ++ ++# ++# [MFD] Multi Function Device Drivers ++# ++CONFIG_MFD_INGENIC_SADC_V13=y ++CONFIG_MFD_INGENIC_SADC_AUX=y ++CONFIG_MFD_INGENIC_TCU=y ++# CONFIG_MFD_RICOH619 is not set ++ ++# ++# [Power] power and regulator Drivers ++# ++# CONFIG_CRYPTO_DEV_INGENIC_SHA is not set ++# CONFIG_CRYPTO_DEV_INGENIC_AES is not set ++ ++# ++# [WDT] watchdog Drivers ++# ++CONFIG_INGENIC_WDT=y ++# CONFIG_SGM820_WATCHDOG is not set ++# end of [WDT] watchdog Drivers ++ ++# ++# [PWM] drivers ++# ++CONFIG_PWM_INGENIC_V2=y ++# end of [PWM] drivers ++ ++# ++# [RTC] drivers ++# ++CONFIG_RTC_DRV_INGENIC=y ++# end of [RTC] drivers ++ ++CONFIG_SND_ASOC_INGENIC=y ++# CONFIG_SND_ASOC_INGENIC_DEBUG is not set ++# CONFIG_SND_ASOC_INGENIC_VERBOSE is not set ++# CONFIG_DMIC_AND_AMIC_SYNC is not set ++CONFIG_SND_ASOC_INGENIC_AS_V2=y ++CONFIG_SND_ASOC_INGENIC_DMA_PREALLOC_PAGES=128 ++CONFIG_SND_ASOC_INGENIC_AS_FE=y ++CONFIG_SND_ASOC_INGENIC_AS_BAIC=y ++CONFIG_SND_ASOC_INGENIC_AS_SPDIF=y ++CONFIG_SND_ASOC_INGENIC_AS_DMIC=y ++CONFIG_SND_ASOC_INGENIC_ICDC_INNO=y ++CONFIG_SND_ASOC_INGENIC_AS_VIR_FE=y ++ ++# ++# Ingenic Board Type Select ++# ++# CONFIG_SND_ASOC_INGENIC_BOARD_EXTERNAL_SOURCE is not set ++# CONFIG_SND_ASOC_INGENIC_ZEBRA is not set ++# CONFIG_SND_ASOC_INGENIC_ZEBRA_DMIC_ICDC is not set ++CONFIG_SND_ASOC_INGENIC_HALLEY5_V20=y ++# end of Ingenic Board Type Select ++ ++CONFIG_SND_ASOC_INGENIC_SPDIF_DUMMY_TIMES=800 ++CONFIG_SND_ASOC_INGENIC_PLAYBACK_DUMMY_TIMES=20 ++# CONFIG_SND_SOC_WM8594 is not set ++ ++# ++# ingenic external codec Type select ++# ++# end of ingenic external codec Type select ++# end of Ingenic device-drivers Configurations +diff --git a/arch/mips/generic/board-ingenic.c b/arch/mips/generic/board-ingenic.c +index 0cec0bea1..51937997f 100644 +--- a/arch/mips/generic/board-ingenic.c ++++ b/arch/mips/generic/board-ingenic.c +@@ -27,6 +27,8 @@ static __init char *ingenic_get_system_type(unsigned long machtype) + return "X2000"; + case MACH_INGENIC_X1830: + return "X1830"; ++ case MACH_INGENIC_X1600: ++ return "X1600"; + case MACH_INGENIC_X1000E: + return "X1000E"; + case MACH_INGENIC_X1000: +@@ -68,6 +70,7 @@ static const struct of_device_id ingenic_of_match[] __initconst = { + { .compatible = "ingenic,jz4780", .data = (void *)MACH_INGENIC_JZ4780 }, + { .compatible = "ingenic,x1000", .data = (void *)MACH_INGENIC_X1000 }, + { .compatible = "ingenic,x1000e", .data = (void *)MACH_INGENIC_X1000E }, ++ { .compatible = "ingenic,x1600", .data = (void *)MACH_INGENIC_X1600 }, + { .compatible = "ingenic,x1830", .data = (void *)MACH_INGENIC_X1830 }, + { .compatible = "ingenic,x2000", .data = (void *)MACH_INGENIC_X2000 }, + { .compatible = "ingenic,x2000e", .data = (void *)MACH_INGENIC_X2000E }, +diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h +index aa03b1237..a92b6b256 100644 +--- a/arch/mips/include/asm/bootinfo.h ++++ b/arch/mips/include/asm/bootinfo.h +@@ -80,6 +80,7 @@ enum ingenic_machine_type { + MACH_INGENIC_JZ4780, + MACH_INGENIC_X1000, + MACH_INGENIC_X1000E, ++ MACH_INGENIC_X1600, + MACH_INGENIC_X1830, + MACH_INGENIC_X2000, + MACH_INGENIC_X2000E, +diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h +index 8294eaa6f..947a5046a 100644 +--- a/arch/mips/include/asm/cpu-features.h ++++ b/arch/mips/include/asm/cpu-features.h +@@ -424,6 +424,18 @@ + #define cpu_has_loongson_ext2 __ase(MIPS_ASE_LOONGSON_EXT2) + #endif + ++#ifndef cpu_has_mxu //32bit simd for xburst Series soc. ++#define cpu_has_mxu 0 ++#endif ++ ++#ifndef cpu_has_mxuv2 //128bit simd for xburst series soc. ++#define cpu_has_mxuv2 0 ++#endif ++ ++#ifndef cpu_has_mxuv3 //512bit simd for xburst2 series soc. ++#define cpu_has_mxuv3 0 ++#endif ++ + #ifndef cpu_has_mipsmt + #define cpu_has_mipsmt __isa_range_and_ase(2, 6, MIPS_ASE_MIPSMT) + #endif +diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h +index 3288cef4b..1b33da2c2 100644 +--- a/arch/mips/include/asm/cpu-type.h ++++ b/arch/mips/include/asm/cpu-type.h +@@ -57,6 +57,7 @@ static inline int __pure __get_cpu_type(const int cpu_type) + #ifdef CONFIG_SYS_HAS_CPU_MIPS32_R5 + case CPU_M5150: + case CPU_P5600: ++ case CPU_XBURST2: + #endif + + #if defined(CONFIG_SYS_HAS_CPU_MIPS32_R2) || \ +diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h +index c9222cc22..38c414132 100644 +--- a/arch/mips/include/asm/cpu.h ++++ b/arch/mips/include/asm/cpu.h +@@ -47,7 +47,7 @@ + #define PRID_COMP_CAVIUM 0x0d0000 + #define PRID_COMP_LOONGSON 0x140000 + #define PRID_COMP_INGENIC_13 0x130000 /* X2000 */ +-#define PRID_COMP_INGENIC_D0 0xd00000 /* JZ4740, JZ4750, X1830 */ ++#define PRID_COMP_INGENIC_D0 0xd00000 /* JZ4740, JZ4750, X1830, X1600 */ + #define PRID_COMP_INGENIC_D1 0xd10000 /* JZ4770, JZ4775, X1000 */ + #define PRID_COMP_INGENIC_E1 0xe10000 /* JZ4780 */ + +@@ -186,9 +186,20 @@ + * These are the PRID's for when 23:16 == PRID_COMP_INGENIC_* + */ + ++#define PRID_IMP_XBURST 0x0000 /* XBurst®1 with ISA */ + #define PRID_IMP_XBURST_REV1 0x0200 /* XBurst®1 with MXU1.0/MXU1.1 SIMD ISA */ + #define PRID_IMP_XBURST_REV2 0x0100 /* XBurst®1 with MXU2.0 SIMD ISA */ +-#define PRID_IMP_XBURST2 0x2000 /* XBurst®2 with MXU2.1 SIMD ISA */ ++#define PRID_IMP_XBURST2 0x2000 /* XBurst®2 with MXU2.1 SIMD ISA */ ++#define PRID_IMP_XBURST2_R2 0x2100 /* XBurst®2 with MXU3.0 SIMD ISA */ ++ ++#define PRID_COMPANY_ID_MASK 0x00FF0000 ++#define PRID_CPU_ARCH_MASK 0x00001F00 ++#define PRID_CPU_FEATURE_MASK 0xFFFF0000 ++#define PRID_CPU_CHIPS_MASK 0x000FF000 ++#define PRID_IMP_PROCESSOR_ID_MSK 0x0000E000 ++#define PRID_CPU_ISA_MASK 0x00000FFF ++#define PRID_CPU_X2000 0x00130000 ++ + + /* + * These are the PRID's for when 23:16 == PRID_COMP_NETLOGIC +@@ -319,7 +330,7 @@ enum cpu_type_enum { + */ + CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K, + CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, +- CPU_BMIPS4380, CPU_BMIPS5000, CPU_XBURST, CPU_LOONGSON32, CPU_M14KC, ++ CPU_BMIPS4380, CPU_BMIPS5000, CPU_XBURST, CPU_XBURST2, CPU_LOONGSON32, CPU_M14KC, + CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, + CPU_M5150, CPU_I6400, CPU_P6600, CPU_M6250, + +diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h +index 7a7467d3f..dfabe15f7 100644 +--- a/arch/mips/include/asm/mipsregs.h ++++ b/arch/mips/include/asm/mipsregs.h +@@ -484,6 +484,9 @@ + /* Implementation specific trap codes used by Loongson cores */ + #define LOONGSON_EXCCODE_GSEXC 16 /* Loongson-specific exception */ + ++/* Ingenic MXUV2 exceptions. */ ++#define INGENIC_EXCCODE_MXUV2 16 ++ + /* + * Bits in the coprocessor 0 config register. + */ +@@ -2073,7 +2076,7 @@ _ASM_MACRO_0(tlbginvf, _ASM_INSN_IF_MIPS(0x4200000c) + ({ int __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ +- ".set\tmips32r5\n\t" \ ++ ".set\tmips32r2\n\t" \ + _ASM_SET_VIRT \ + "mfgc0\t%0, " #source ", %1\n\t" \ + ".set\tpop" \ +@@ -2086,7 +2089,7 @@ _ASM_MACRO_0(tlbginvf, _ASM_INSN_IF_MIPS(0x4200000c) + ({ unsigned long long __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ +- ".set\tmips64r5\n\t" \ ++ ".set\tmips64r2\n\t" \ + _ASM_SET_VIRT \ + "dmfgc0\t%0, " #source ", %1\n\t" \ + ".set\tpop" \ +@@ -2099,7 +2102,7 @@ _ASM_MACRO_0(tlbginvf, _ASM_INSN_IF_MIPS(0x4200000c) + do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ +- ".set\tmips32r5\n\t" \ ++ ".set\tmips32r2\n\t" \ + _ASM_SET_VIRT \ + "mtgc0\t%z0, " #register ", %1\n\t" \ + ".set\tpop" \ +@@ -2111,7 +2114,7 @@ do { \ + do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ +- ".set\tmips64r5\n\t" \ ++ ".set\tmips64r2\n\t" \ + _ASM_SET_VIRT \ + "dmtgc0\t%z0, " #register ", %1\n\t" \ + ".set\tpop" \ +diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h +index e0a3dd523..fa9197f46 100644 +--- a/arch/mips/include/asm/msa.h ++++ b/arch/mips/include/asm/msa.h +@@ -98,6 +98,8 @@ static inline void enable_msa(void) + { + if (cpu_has_msa) { + set_c0_config5(MIPS_CONF5_MSAEN); ++ set_c0_status(ST0_CU2); ++ KSTK_STATUS(current) |= ST0_CU2; + enable_fpu_hazard(); + } + } +@@ -106,6 +108,8 @@ static inline void disable_msa(void) + { + if (cpu_has_msa) { + clear_c0_config5(MIPS_CONF5_MSAEN); ++ clear_c0_status(ST0_CU2); ++ KSTK_STATUS(current) &= ~ST0_CU2; + disable_fpu_hazard(); + } + } +diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h +index 2362842ee..2e168130a 100644 +--- a/arch/mips/include/asm/pgtable-bits.h ++++ b/arch/mips/include/asm/pgtable-bits.h +@@ -249,6 +249,21 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val) + + #define _CACHE_CACHABLE_NONCOHERENT (5<<_CACHE_SHIFT) + ++#elif defined(CONFIG_MACH_INGENIC) ++/* Ingenic uses the WA bit to achieve write-combine memory writes */ ++#define _CACHE_UNCACHED_ACCELERATED (1<<_CACHE_SHIFT) ++#elif defined(CONFIG_MACH_XBURST) || defined(CONFIG_MACH_XBURST2) ++ ++#define _CACHE_CACHABLE_WT_WA (0<<_CACHE_SHIFT) /* R4600 only */ ++#define _CACHE_UNCACHED_ACCELERATED (1<<_CACHE_SHIFT) /* R4600 only */ ++#define _CACHE_UNCACHED (2<<_CACHE_SHIFT) /* R4[0246]00 */ ++#define _CACHE_CACHABLE_WB_WA (3<<_CACHE_SHIFT) /* R4[0246]00 */ ++#define _CACHE_CACHABLE_WT_WA_S (4<<_CACHE_SHIFT) /* R4[04]00MC only */ ++#define _CACHE_CACHABLE_WB_WA_S (5<<_CACHE_SHIFT) /* R4[04]00MC only */ ++#define _CACHE_CACHABLE_WA _CACHE_UNCACHED_ACCELERATED ++#define _CACHE_CACHABLE_NONCOHERENT _CACHE_CACHABLE_WB_WA ++ ++ + #endif + + #ifndef _CACHE_CACHABLE_NO_WA +diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h +index 7834e7c0c..ac3887a40 100644 +--- a/arch/mips/include/asm/processor.h ++++ b/arch/mips/include/asm/processor.h +@@ -87,6 +87,23 @@ extern unsigned long mips_stack_top(void); + + #define NUM_FPU_REGS 32 + ++ ++#if cpu_has_mxuv2 ++#define NUM_MXU_VPR_REGS 16 //vpr0~15 ++#define NUM_MXU_VSR_REGS 0 ++#endif ++ ++ ++#if cpu_has_mxuv3 ++#define NUM_MXU_VPR_REGS 32 //vpr0~31 ++#define NUM_MXU_VSR_REGS 4 //vsr0~3 ++#endif ++ ++#if !cpu_has_mxuv2 && !cpu_has_mxuv3 ++#define NUM_MXU_VPR_REGS 0 ++#define NUM_MXU_VSR_REGS 0 ++#endif ++ + #ifdef CONFIG_CPU_HAS_MSA + # define FPU_REG_WIDTH 128 + #else +@@ -98,6 +115,22 @@ union fpureg { + __u64 val64[FPU_REG_WIDTH / 64]; + }; + ++typedef union mxuvec { ++#if cpu_has_mxuv2 ++ uint8_t val128[16]; //simd128 ++#endif ++#if cpu_has_mxuv3 ++ uint8_t val512[64]; //simd512 ++#endif ++} mxuvec_t; ++ ++struct xburst_mxu_struct { ++ mxuvec_t vpr[NUM_MXU_VPR_REGS]; ++ mxuvec_t vsr[NUM_MXU_VSR_REGS]; ++ uint32_t csr; ++}; ++ ++ + #ifdef CONFIG_CPU_LITTLE_ENDIAN + # define FPR_IDX(width, idx) (idx) + #else +@@ -156,8 +189,20 @@ struct mips3264_watch_reg_state { + union mips_watch_reg_state { + struct mips3264_watch_reg_state mips3264; + }; ++#if defined(CONFIG_XBURST_MXUV2) ++typedef union { ++ u64 val64[2]; ++} vpr_t; ++ ++struct xburst_cop2_state { ++ u32 mxu_csr; ++ vpr_t vr[32]; ++}; ++ ++#define COP2_INIT \ ++ .cp2 = {0,}, + +-#if defined(CONFIG_CPU_CAVIUM_OCTEON) ++#elif defined(CONFIG_CPU_CAVIUM_OCTEON) + + struct octeon_cop2_state { + /* DMFC2 rt, 0x0201 */ +@@ -272,6 +317,11 @@ struct thread_struct { + /* Saved state of the DSP ASE, if available. */ + struct mips_dsp_state dsp; + ++ ++ /* Saved registers of the MXU, if available. */ ++ struct xburst_mxu_struct mxu; ++ ++ + /* Saved watch register state, if available. */ + union mips_watch_reg_state watch; + +@@ -280,6 +330,10 @@ struct thread_struct { + unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */ + unsigned long error_code; + unsigned long trap_nr; ++#ifdef CONFIG_XBURST_MXUV2 ++ struct xburst_cop2_state cp2; ++#endif ++ + #ifdef CONFIG_CPU_CAVIUM_OCTEON + struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128))); + struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128))); +diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h +index aa430a6c6..deb613d70 100644 +--- a/arch/mips/include/asm/stackframe.h ++++ b/arch/mips/include/asm/stackframe.h +@@ -424,7 +424,7 @@ + + .macro RESTORE_SP_AND_RET docfi=0 + RESTORE_SP \docfi +-#if defined(CONFIG_CPU_MIPSR5) || defined(CONFIG_CPU_MIPSR6) ++#ifdef CONFIG_CPU_MIPSR6 + eretnc + #else + .set push +diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h +index a4374b4cb..94f2d0bdf 100644 +--- a/arch/mips/include/asm/switch_to.h ++++ b/arch/mips/include/asm/switch_to.h +@@ -17,6 +17,8 @@ + #include + #include + #include ++#include ++#include + + struct task_struct; + +@@ -116,6 +118,23 @@ do { \ + __save_dsp(prev); \ + __restore_dsp(next); \ + } \ ++ if(cpu_has_mxu) { \ ++ if (KSTK_STATUS(prev) & ST0_CU2) { \ ++ __save_mxu(prev); \ ++ } \ ++ if (KSTK_STATUS(next) & ST0_CU2) { \ ++ __restore_mxu(next); \ ++ } \ ++ } \ ++ if (cpu_has_mxuv3) { \ ++ if ((KSTK_STATUS(prev) & ST0_CU2)) { \ ++ __save_mxuv3(prev); \ ++ } \ ++ if ((KSTK_STATUS(next) & ST0_CU2)) { \ ++ set_c0_status(ST0_CU2); \ ++ __restore_mxuv3(next); \ ++ } \ ++ } \ + if (cop2_present) { \ + u32 status = read_c0_status(); \ + \ +diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c +index d12020191..2b572f10d 100644 +--- a/arch/mips/kernel/cpu-probe.c ++++ b/arch/mips/kernel/cpu-probe.c +@@ -1721,6 +1721,8 @@ static inline void decode_cpucfg(struct cpuinfo_mips *c) + + static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) + { ++ decode_configs(c); ++ + /* All Loongson processors covered here define ExcCode 16 as GSExc. */ + c->options |= MIPS_CPU_GSEXCEX; + +@@ -1737,6 +1739,7 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) + set_isa(c, MIPS_CPU_ISA_M64R2); + break; + } ++ c->writecombine = _CACHE_UNCACHED_ACCELERATED; + c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_EXT | + MIPS_ASE_LOONGSON_EXT2); + break; +@@ -1766,6 +1769,7 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) + * register, we correct it here. + */ + c->options |= MIPS_CPU_FTLB | MIPS_CPU_TLBINV | MIPS_CPU_LDPTE; ++ c->writecombine = _CACHE_UNCACHED_ACCELERATED; + c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM | + MIPS_ASE_LOONGSON_EXT | MIPS_ASE_LOONGSON_EXT2); + c->ases &= ~MIPS_ASE_VZ; /* VZ of Loongson-3A2000/3000 is incomplete */ +@@ -1776,13 +1780,12 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) + set_elf_platform(cpu, "loongson3a"); + set_isa(c, MIPS_CPU_ISA_M64R2); + decode_cpucfg(c); ++ c->writecombine = _CACHE_UNCACHED_ACCELERATED; + break; + default: + panic("Unknown Loongson Processor ID!"); + break; + } +- +- decode_configs(c); + } + #else + static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu) { } +@@ -1807,6 +1810,14 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) + + switch (c->processor_id & PRID_IMP_MASK) { + ++ /* XBurst®1 with ISA */ ++ case PRID_IMP_XBURST: ++ c->cputype = CPU_XBURST; ++ c->writecombine = _CACHE_UNCACHED_ACCELERATED; ++ __cpu_name[cpu] = "Ingenic XBurst"; ++ break; ++ ++ + /* XBurst®1 with MXU1.0/MXU1.1 SIMD ISA */ + case PRID_IMP_XBURST_REV1: + +@@ -1863,7 +1874,9 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) + + /* XBurst®2 with MXU2.1 SIMD ISA */ + case PRID_IMP_XBURST2: +- c->cputype = CPU_XBURST; ++ case PRID_IMP_XBURST2_R2: ++ c->cputype = CPU_XBURST2; ++ c->writecombine = _CACHE_UNCACHED_ACCELERATED; + __cpu_name[cpu] = "Ingenic XBurst II"; + break; + +diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S +index bcce32a3d..70913c1e2 100644 +--- a/arch/mips/kernel/genex.S ++++ b/arch/mips/kernel/genex.S +@@ -568,6 +568,7 @@ NESTED(nmi_handler, PT_SIZE, sp) + #ifdef CONFIG_MIPS_FP_SUPPORT + BUILD_HANDLER fpe fpe fpe silent /* #15 */ + #endif ++ BUILD_HANDLER mfpe mfpe none silent /* #16 */ + BUILD_HANDLER ftlb ftlb none silent /* #16 */ + BUILD_HANDLER gsexc gsexc gsexc silent /* #16 */ + BUILD_HANDLER msa msa sti silent /* #21 */ +diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c +index 18e69ebf5..c440bfb1a 100644 +--- a/arch/mips/kernel/idle.c ++++ b/arch/mips/kernel/idle.c +@@ -67,6 +67,19 @@ void __cpuidle r4k_wait_irqoff(void) + raw_local_irq_enable(); + } + ++void ingenic_wait_irqoff(void) ++{ ++ WARN_ON_ONCE(!raw_irqs_disabled()); ++ if (!need_resched()) ++ __asm__( ++ " .set push \n" ++ " .set arch=r4000 \n" ++ " sync \n" ++ " wait \n" ++ " .set pop \n"); ++ raw_local_irq_enable(); ++} ++ + /* + * The RM7000 variant has to handle erratum 38. The workaround is to not + * have any pending stores when the WAIT instruction is executed. +@@ -172,12 +185,15 @@ void __init check_wait(void) + case CPU_CAVIUM_OCTEON_PLUS: + case CPU_CAVIUM_OCTEON2: + case CPU_CAVIUM_OCTEON3: +- case CPU_XBURST: + case CPU_LOONGSON32: + case CPU_XLR: + case CPU_XLP: + cpu_wait = r4k_wait; + break; ++ case CPU_XBURST: ++ case CPU_XBURST2: ++ cpu_wait = ingenic_wait_irqoff; ++ break; + case CPU_LOONGSON64: + if ((c->processor_id & (PRID_IMP_MASK | PRID_REV_MASK)) >= + (PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0) || +diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c +index 9d11f68a9..63de4bfde 100644 +--- a/arch/mips/kernel/setup.c ++++ b/arch/mips/kernel/setup.c +@@ -686,7 +686,7 @@ static void __init arch_mem_init(char **cmdline_p) + memblock_reserve(__pa_symbol(&__nosave_begin), + __pa_symbol(&__nosave_end) - __pa_symbol(&__nosave_begin)); + +- fdt_init_reserved_mem(); ++ //fdt_init_reserved_mem(); + + memblock_dump_all(); + +diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c +index 14db66dbc..48629da39 100644 +--- a/arch/mips/kernel/smp.c ++++ b/arch/mips/kernel/smp.c +@@ -348,6 +348,7 @@ asmlinkage void start_secondary(void) + */ + + calibrate_delay(); ++ preempt_disable(); + cpu = smp_processor_id(); + cpu_data[cpu].udelay_val = loops_per_jiffy; + +diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c +index b1fe4518b..13a388b18 100644 +--- a/arch/mips/kernel/traps.c ++++ b/arch/mips/kernel/traps.c +@@ -89,6 +89,7 @@ extern asmlinkage void handle_ov(void); + extern asmlinkage void handle_tr(void); + extern asmlinkage void handle_msa_fpe(void); + extern asmlinkage void handle_fpe(void); ++extern asmlinkage void handle_mfpe(void); + extern asmlinkage void handle_ftlb(void); + extern asmlinkage void handle_gsexc(void); + extern asmlinkage void handle_msa(void); +@@ -957,6 +958,14 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode, + + #endif /* !CONFIG_MIPS_FP_SUPPORT */ + ++//MACH_XBURST ++asmlinkage void do_mfpe(struct pt_regs * regs) ++{ ++ die_if_kernel("Kernel bug detected", regs); ++ force_sig(SIGILL); ++} ++ ++ + void do_trap_or_bp(struct pt_regs *regs, unsigned int code, int si_code, + const char *str) + { +@@ -1160,6 +1169,20 @@ asmlinkage void do_ri(struct pt_regs *regs) + unsigned int opcode = 0; + int status = -1; + ++ /* If Config1.CU2 is not set, the exc_code = 10 of cause reg */ ++ if (cpu_has_mxuv3 && (1 == smp_processor_id())) { ++ printk("%s(%d):reschedule to cpu0 to smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ //resched_cpu(0); ++ smp_send_reschedule(0); ++ if (0 == smp_processor_id()) { ++ printk("%s(%d):open cu2 field to cpu0 to smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ set_c0_status(ST0_CU2); ++ KSTK_STATUS(current) |= ST0_CU2; ++ } ++ printk("%s(%d):no cu2 coprocessor to smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ return; ++ } ++ + /* + * Avoid any kernel code. Just emulate the R2 instruction + * as quickly as possible. +@@ -1500,6 +1523,32 @@ asmlinkage void do_cpu(struct pt_regs *regs) + #endif /* CONFIG_MIPS_FP_SUPPORT */ + + case 2: ++ /* Processing of MXA instructions needs setting MSA enable. */ ++ ++ if(cpu_has_msa) { ++ int err = 0; ++ err = enable_restore_fp_context(1); ++ if (err) ++ force_sig(SIGILL); ++ ++ break; ++ } ++ /* To Xburst2 T40, If Status.CU2 is not set and Config1.CU2 is set, the exc_code is 10 and CE field is 2 to Cause Reg ++ * So here only need to open the Status.CU2 field */ ++ if (cpu_has_mxuv3 && (0 == smp_processor_id())) { ++ set_c0_status(ST0_CU2); ++ KSTK_STATUS(current) |= ST0_CU2; ++ printk("%s(%d):open cu2 field to cpu0 to smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ ++ break; ++ ++ } else if (cpu_has_mxuv3 && (1 == smp_processor_id())) { ++ printk("%s(%d):no cu2 coprocessor to smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ force_sig(SIGILL); ++ break; ++ } ++ ++ /*others case, call chain.*/ + raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs); + break; + } +@@ -2213,6 +2262,10 @@ static void configure_status(void) + if (cpu_has_dsp) + status_set |= ST0_MX; + ++ if (cpu_has_mxuv3 && (KSTK_STATUS(current) & ST0_CU2)) { ++ status_set |= ST0_CU2; ++ } ++ + change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, + status_set); + back_to_back_c0_hazard(); +@@ -2507,6 +2560,9 @@ void __init trap_init(void) + if (cpu_has_gsexcex) + set_except_vector(LOONGSON_EXCCODE_GSEXC, handle_gsexc); + ++ if (cpu_has_mxuv2) ++ set_except_vector(INGENIC_EXCCODE_MXUV2, handle_mfpe); ++ + if (cpu_has_rixiex) { + set_except_vector(EXCCODE_TLBRI, tlb_do_page_fault_0); + set_except_vector(EXCCODE_TLBXI, tlb_do_page_fault_0); +diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c +index 96adc3d23..f6237185b 100644 +--- a/arch/mips/mm/c-r4k.c ++++ b/arch/mips/mm/c-r4k.c +@@ -96,9 +96,12 @@ static inline void r4k_on_each_cpu(unsigned int type, + void (*func)(void *info), void *info) + { + preempt_disable(); ++ ++#ifndef CONFIG_MACH_XBURST2 + if (r4k_op_needs_ipi(type)) + smp_call_function_many(&cpu_foreign_map[smp_processor_id()], + func, info, 1); ++#endif + func(info); + preempt_enable(); + } +@@ -592,7 +595,7 @@ static inline void local_r4k_flush_cache_range(void * args) + * If executable, we must ensure any dirty lines are written back far + * enough to be visible to icache. + */ +- if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) ++ if (1 /*TODO bypzqi*/ || cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) + r4k_blast_dcache(); + /* If executable, blast stale lines from icache */ + if (exec) +@@ -885,7 +888,11 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) + * we have to use the HIT-type alternative as IPI cannot be used + * here due to interrupts possibly being disabled. + */ ++#ifndef CONFIG_MACH_XBURST2 + if (!r4k_op_needs_ipi(R4K_INDEX) && size >= dcache_size) { ++#else ++ if(size >= dcache_size) { ++#endif + r4k_blast_dcache(); + } else { + R4600_HIT_CACHEOP_WAR_IMPL; +@@ -955,10 +962,29 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) + return; + } + ++#ifndef CONFIG_MACH_XBURST2 + if (!r4k_op_needs_ipi(R4K_INDEX) && size >= dcache_size) { ++#else ++ if(size >= dcache_size) { ++#endif ++ + r4k_blast_dcache(); + } else { ++#if defined(CONFIG_MACH_XBURST) || defined(CONFIG_MACH_XBURST2) ++ unsigned long lsize = cpu_dcache_line_size(); ++ unsigned long cmask = (lsize - 1); ++ unsigned long lmask = ~(cmask); ++#endif + R4600_HIT_CACHEOP_WAR_IMPL; ++#if defined(CONFIG_MACH_XBURST) || defined(CONFIG_MACH_XBURST2) ++ if (addr & cmask) { ++ cache_op(Hit_Writeback_Inv_D, addr & lmask); ++ } ++ if ((addr + size) & cmask) { ++ cache_op(Hit_Writeback_Inv_D, (addr + size - 1) & lmask); ++ } ++#endif ++ + blast_inv_dcache_range(addr, addr + size); + } + preempt_enable(); +@@ -1645,6 +1671,7 @@ static void loongson3_sc_init(void) + extern int r5k_sc_init(void); + extern int rm7k_sc_init(void); + extern int mips_sc_init(void); ++extern int ingenic_sc_init(void); + + static void setup_scache(void) + { +@@ -1698,6 +1725,10 @@ static void setup_scache(void) + case CPU_LOONGSON64: + loongson3_sc_init(); + return; ++ case CPU_XBURST: ++ case CPU_XBURST2: ++ ingenic_sc_init(); ++ return; + + case CPU_CAVIUM_OCTEON3: + case CPU_XLP: +diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c +index 38d3d9143..918468645 100644 +--- a/arch/mips/mm/dma-noncoherent.c ++++ b/arch/mips/mm/dma-noncoherent.c +@@ -33,6 +33,8 @@ static inline bool cpu_needs_post_dma_flush(void) + case CPU_R12000: + case CPU_BMIPS5000: + case CPU_LOONGSON2EF: ++ case CPU_XBURST: ++ case CPU_XBURST2: + return true; + default: + /* +diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c +index 06ec304ad..831e98b8b 100644 +--- a/arch/mips/mm/sc-mips.c ++++ b/arch/mips/mm/sc-mips.c +@@ -216,7 +216,7 @@ static inline int mips_sc_probe(void) + return 0; + + tmp = (config2 >> 0) & 0x0f; +- if (tmp <= 7) ++ if ((tmp == 7) || (tmp == 15)) + c->scache.ways = tmp + 1; + else + return 0; +diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c +index 1b939abbe..14a0fd82b 100644 +--- a/arch/mips/mm/tlb-r4k.c ++++ b/arch/mips/mm/tlb-r4k.c +@@ -55,7 +55,7 @@ void local_flush_tlb_all(void) + { + unsigned long flags; + unsigned long old_ctx; +- int entry, ftlbhighset; ++ int entry; + + local_irq_save(flags); + /* Save old context and create impossible VPN2 value */ +@@ -71,6 +71,8 @@ void local_flush_tlb_all(void) + * If there are any wired entries, fall back to iterating + */ + if (cpu_has_tlbinv && !entry) { ++#ifndef CONFIG_MACH_XBURST2 ++ int ftlbhighset; + if (current_cpu_data.tlbsizevtlb) { + write_c0_index(0); + mtc0_tlbw_hazard(); +@@ -85,6 +87,9 @@ void local_flush_tlb_all(void) + mtc0_tlbw_hazard(); + tlbinvf(); /* invalidate one FTLB set */ + } ++#else ++ tlbinvf(); /* invalide FTLB/VTLB set */ ++#endif + } else { + while (entry < current_cpu_data.tlbsize) { + /* Make sure all entries differ. */ +diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c +index a7521b8f7..f702c645c 100644 +--- a/arch/mips/mm/tlbex.c ++++ b/arch/mips/mm/tlbex.c +@@ -613,6 +613,7 @@ void build_tlb_write_entry(u32 **p, struct uasm_label **l, + break; + + case CPU_XBURST: ++ case CPU_XBURST2: + tlbw(p); + uasm_i_nop(p); + break; +diff --git a/arch/mips/xburst/Kconfig b/arch/mips/xburst/Kconfig +new file mode 100644 +index 000000000..f3e839e5d +--- /dev/null ++++ b/arch/mips/xburst/Kconfig +@@ -0,0 +1,69 @@ ++menuconfig SOC_TYPE ++ tristate "SOC type" ++ depends on MACH_XBURST ++ default y ++ ++if SOC_TYPE ++choice ++ prompt "SOC types" ++ depends on MACH_XBURST ++ default SOC_X1600 ++ ++config SOC_X1000 ++ bool "x1000 socs" ++ select INGENIC_INTC ++ select CLK_X1000 ++ select CLKSRC_OF ++ select PINCTRL ++ select TIMER_OF ++ select CLKDEV_LOOKUP ++ select PINCTRL_INGENIC ++ select CLKSRC_INGENIC_SYS_OST ++ select MMU_NOTIFIER ++ ++config SOC_X1600 ++ bool "x1600 socs" ++ select INGENIC_INTC ++ select CLK_X1600 ++ select CLKSRC_OF ++ select PINCTRL ++ select TIMER_OF ++ select CLKDEV_LOOKUP ++ select PINCTRL_INGENIC ++ select CLKSRC_INGENIC_SYS_OST ++ select MMU_NOTIFIER ++endchoice ++ ++config INGENIC_BUILTIN_DTB ++ select BUILTIN_DTB ++ depends on MACH_XBURST ++ bool "Ingenic Device Tree build into Kernel." ++ default y ++ ++source "arch/mips/xburst/soc-x1000/Kconfig.DT" ++source "arch/mips/xburst/soc-x1600/Kconfig.DT" ++ ++config EXTAL_CLOCK ++ depends on MACH_XBURST ++ int "extal clock in MHz" ++ default 24 ++ ++config INGENIC_GPT_CHECK ++ depends on MACH_XBURST ++ bool "The physical space is larger than the virtual space" ++ default y ++ ++config SUSPEND_TEST ++ bool "auto suspend test" ++ default n ++ ++config SUSPEND_ALARM_TIME ++ int "suspend alarm time(second)" ++ depends on SUSPEND_TEST ++ default 2 ++ ++config XBURST_MXUV2 ++ bool ++ default n ++ ++endif +diff --git a/arch/mips/xburst/Makefile b/arch/mips/xburst/Makefile +new file mode 100644 +index 000000000..f2979647c +--- /dev/null ++++ b/arch/mips/xburst/Makefile +@@ -0,0 +1,4 @@ ++obj-y += common/ ++obj-y += debug/ ++obj-$(CONFIG_SOC_X1000) += soc-x1000/ ++obj-$(CONFIG_SOC_X1600) += soc-x1600/ +diff --git a/arch/mips/xburst/Platform b/arch/mips/xburst/Platform +new file mode 100644 +index 000000000..9930a99e8 +--- /dev/null ++++ b/arch/mips/xburst/Platform +@@ -0,0 +1,7 @@ ++platform-$(CONFIG_MACH_XBURST) += xburst/ ++load-$(CONFIG_MACH_XBURST) += 0xffffffff80010000 ++ ++cflags-$(CONFIG_MACH_XBURST) += -I$(srctree)/arch/mips/xburst/common/include ++cflags-$(CONFIG_SOC_X1000) += -I$(srctree)/arch/mips/xburst/soc-x1000/include ++cflags-$(CONFIG_SOC_X1600) += -I$(srctree)/arch/mips/xburst/soc-x1600/include ++ +diff --git a/arch/mips/xburst/common/Makefile b/arch/mips/xburst/common/Makefile +new file mode 100644 +index 000000000..ac731caeb +--- /dev/null ++++ b/arch/mips/xburst/common/Makefile +@@ -0,0 +1,5 @@ ++obj-y += prom.o mxu-xburst.o jz_notifier.o ++obj-$(CONFIG_XBURST_CPU_SCACHE) += sc-xburst.o ++#obj-y += initrd-check.o ++obj-y += proc.o ++obj-$(CONFIG_XBURST_MXUV2) += mxu-v2-ex.obj +diff --git a/arch/mips/xburst/common/include/ingenic_proc.h b/arch/mips/xburst/common/include/ingenic_proc.h +new file mode 100644 +index 000000000..a1883087e +--- /dev/null ++++ b/arch/mips/xburst/common/include/ingenic_proc.h +@@ -0,0 +1,18 @@ ++#ifndef _INGENIC_PROC_H_ ++#define _INGENIC_PROC_H_ ++ ++struct jz_single_file_ops { ++ ssize_t (*read) (struct seq_file *, void *); ++ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ++ void *data; ++}; ++ ++struct proc_dir_entry * jz_proc_mkdir(char *s); ++struct proc_dir_entry *jz_proc_create_data( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops, void *data); ++struct proc_dir_entry *jz_proc_create( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops); ++struct proc_dir_entry * get_jz_proc_root(void); ++#endif /* _INGENIC_PROC_H_ */ +diff --git a/arch/mips/xburst/common/include/jz_notifier.h b/arch/mips/xburst/common/include/jz_notifier.h +new file mode 100644 +index 000000000..ec582e9d3 +--- /dev/null ++++ b/arch/mips/xburst/common/include/jz_notifier.h +@@ -0,0 +1,45 @@ ++#ifndef _JZ_NOTIFIER_H_ ++#define _JZ_NOTIFIER_H_ ++ ++#include ++ ++/* ++ * Hibernation and suspend events ++ */ ++enum jz_notif_cmd { ++ JZ_CMD_START = 0, ++ JZ_CLK_PRECHANGE, ++ JZ_CLK_CHANGING, ++ JZ_CLK_CHANGED, ++ JZ_CLKGATE_CHANGE, ++ JZ_POST_HIBERNATION, /* Hibernation finished */ ++ JZ_PM_SUSPEND_STANDBY, /* Hibernation finished */ ++ MMU_CONTEXT_EXIT_MMAP, ++ JZ_CMD_END ++}; ++enum { ++ NOTEFY_PROI_START=1, ++ NOTEFY_PROI_HIGH, ++ NOTEFY_PROI_NORMAL, ++ NOTEFY_PROI_LOW, ++ NOTEFY_PROI_END ++}; ++ ++struct clk_notify_data ++{ ++ unsigned long current_rate; ++ unsigned long target_rate; ++}; ++ ++struct jz_notifier { ++ struct notifier_block nb; ++ int (*jz_notify)(struct jz_notifier *notify,void *d); ++ int level; ++ enum jz_notif_cmd msg; ++}; ++ ++int jz_notifier_register(struct jz_notifier *notify, unsigned int priority); ++int jz_notifier_unregister(struct jz_notifier *notify, unsigned int priority); ++int jz_notifier_call(unsigned int priority, unsigned long val, void *v); ++ ++#endif /* _JZ_NOTIFIER_H_ */ +diff --git a/arch/mips/xburst/common/include/mxu.h b/arch/mips/xburst/common/include/mxu.h +new file mode 100755 +index 000000000..a82d4d8e0 +--- /dev/null ++++ b/arch/mips/xburst/common/include/mxu.h +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) 2005 Mips Technologies ++ * Author: Chris Dearman, chris@mips.com derived from fpu.h ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++#ifndef _ASM_MXU_H ++#define _ASM_MXU_H ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++static inline void __init_mxu(void) ++{ ++ unsigned int register val asm("t0"); ++ val = 3; ++ asm volatile(".word 0x7008042f \n\t"::"r"(val)); ++} ++ ++void __save_mxu(void *); ++void __restore_mxu(void * tsk_void); ++ ++static inline void init_mxu(void) ++{ ++ if(cpu_has_mxu) ++ __init_mxu(); ++} ++ ++ ++#define save_mxu(tsk) \ ++ do { \ ++ if (cpu_has_mxu) \ ++ __save_mxu(tsk); \ ++ } while (0) ++ ++#define restore_mxu(tsk) \ ++ do { \ ++ if (cpu_has_mxu) \ ++ __restore_mxu(tsk); \ ++ } while (0) ++ ++#define __get_mxu_regs(tsk) \ ++ ({ \ ++ if (tsk == current) \ ++ __save_mxu(current); \ ++ \ ++ tsk->thread.mxu.regs; \ ++ }) ++ ++#define __let_mxu_regs(tsk,regs) \ ++ do{ \ ++ int i; \ ++ for(i = 0; i < NUM_MXU_REGS;i++) \ ++ tsk->thread.mxu.regs[i] = regs[i]; \ ++ if (tsk == current) \ ++ __save_mxu(current); \ ++ }while(0) ++ ++#endif /* _ASM_MXU_H */ +diff --git a/arch/mips/xburst/common/include/mxu_media.h b/arch/mips/xburst/common/include/mxu_media.h +new file mode 100755 +index 000000000..655b47a84 +--- /dev/null ++++ b/arch/mips/xburst/common/include/mxu_media.h +@@ -0,0 +1,1832 @@ ++#ifndef _MXU_H_ ++#define _MXU_H_ ++ ++#define xr00 ++#define xr11 ++#define xr22 ++#define xr33 ++#define xr44 ++#define xr55 ++#define xr66 ++#define xr77 ++#define xr88 ++#define xr99 ++#define xr1010 ++#define xr1111 ++#define xr1212 ++#define xr1313 ++#define xr1414 ++#define xr1515 ++#define xr1616 ++ ++#define ptn00 ++#define ptn11 ++#define ptn22 ++#define ptn33 ++#define ptn44 ++#define ptn55 ++#define ptn66 ++#define ptn77 ++ ++/***********************************LD/SD***********************************/ ++#define S32LDD(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32LDDxr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s12)); \ ++ }while(0) ++ ++#define S32STD(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32STDxr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s12):"memory"); \ ++ }while(0) ++ ++#define S32LDDV(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32LDDVxr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"d"(rc),"K"(strd2)); \ ++ }while(0) ++ ++#define S32STDV(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32STDVxr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"d"(rc),"K"(strd2):"memory"); \ ++ }while(0) ++ ++#define S32LDI(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32LDIxr%1,%z0,%2" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s12)); \ ++ }while(0) ++ ++#define S32SDI(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32SDIxr%1,%z0,%2" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s12):"memory"); \ ++ }while(0) ++ ++#define S32LDIV(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32LDIVxr%1,%z0,%z2,%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2)); \ ++ }while(0) ++ ++#define S32SDIV(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32SDIVxr%1,%z0,%z2,%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2):"memory"); \ ++ }while(0) ++//MXUenhancement ++#define S32LDDR(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32LDDRxr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s12)); \ ++ }while(0) ++ ++#define S32STDR(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32STDRxr%0,%z1,%2" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s12):"memory"); \ ++ }while(0) ++ ++#define S32LDDVR(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32LDDVRxr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"d"(rc),"K"(strd2)); \ ++ }while(0) ++ ++#define S32STDVR(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32STDVRxr%0,%z1,%z2,%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"d"(rc),"K"(strd2):"memory"); \ ++ }while(0) ++ ++#define S32LDIR(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32LDIRxr%1,%z0,%2" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s12)); \ ++ }while(0) ++ ++#define S32SDIR(xra,rb,s12) \ ++ do{ \ ++ __asm____volatile("S32SDIRxr%1,%z0,%2" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s12):"memory"); \ ++ }while(0) ++ ++#define S32LDIVR(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32LDIVRxr%1,%z0,%z2,%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2)); \ ++ }while(0) ++ ++#define S32SDIVR(xra,rb,rc,strd2) \ ++ do{ \ ++ __asm____volatile("S32SDIVRxr%1,%z0,%z2,%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"d"(rc),"K"(strd2):"memory"); \ ++ }while(0) ++ ++#define S8LDD(xra,rb,s8,optn3) \ ++ do{ \ ++ __asm____volatile("S8LDDxr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s8),"K"(optn3)); \ ++ }while(0) ++ ++#define S8STD(xra,rb,s8,optn3) \ ++ do{ \ ++ __asm____volatile("S8STDxr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s8),"K"(optn3):"memory"); \ ++ }while(0) ++ ++#define S8LDI(xra,rb,s8,optn3) \ ++ do{ \ ++ __asm____volatile("S8LDIxr%1,%z0,%2,ptn%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s8),"K"(optn3)); \ ++ }while(0) ++ ++#define S8SDI(xra,rb,s8,optn3) \ ++ do{ \ ++ __asm____volatile("S8SDIxr%1,%z0,%2,ptn%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s8),"K"(optn3):"memory"); \ ++ }while(0) ++ ++#define S16LDD(xra,rb,s10,optn2) \ ++ do{ \ ++ __asm____volatile("S16LDDxr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s10),"K"(optn2)); \ ++ }while(0) ++ ++#define S16STD(xra,rb,s10,optn2) \ ++ do{ \ ++ __asm____volatile("S16STDxr%0,%z1,%2,ptn%3" \ ++ : \ ++ :"K"(xra),"d"(rb),"I"(s10),"K"(optn2):"memory"); \ ++ }while(0) ++ ++#define S16LDI(xra,rb,s10,optn2) \ ++ do{ \ ++ __asm____volatile("S16LDIxr%1,%z0,%2,ptn%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s10),"K"(optn2)); \ ++ }while(0) ++ ++#define S16SDI(xra,rb,s10,optn2) \ ++ do{ \ ++ __asm____volatile("S16SDIxr%1,%z0,%2,ptn%3" \ ++ :"+d"(rb) \ ++ :"K"(xra),"I"(s10),"K"(optn2):"memory"); \ ++ }while(0) ++ ++#define LXW(rb,rc,strd2) \ ++ ({ \ ++ unsignedint_dst_; \ ++ __asm____volatile("LXW%0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++ _dst_; \ ++ }) ++ ++#define LXH(rb,rc,strd2) \ ++ ({ \ ++ unsignedint_dst_; \ ++ __asm____volatile("LXH%0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++ _dst_; \ ++ }) ++ ++#define LXHU(rb,rc,strd2) \ ++ ({ \ ++ unsignedint_dst_; \ ++ __asm____volatile("LXHU%0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++ _dst_; \ ++ }) ++ ++#define LXB(rb,rc,strd2) \ ++ ({ \ ++ unsignedint_dst_; \ ++ __asm____volatile("LXB%0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++ _dst_; \ ++ }) ++ ++#define LXBU(rb,rc,strd2) \ ++ ({ \ ++ unsignedint_dst_; \ ++ __asm____volatile("LXBU%0,%1,%2,%3":"=d"(_dst_):"d"(rb),"d"(rc),"K"(strd2)); \ ++ _dst_; \ ++ }) ++/***********************************D16MUL***********************************/ ++#define D16MUL_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULxr%0,xr%1,xr%2,xr%3,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MUL_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULxr%0,xr%1,xr%2,xr%3,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MUL_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULxr%0,xr%1,xr%2,xr%3,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MUL_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULxr%0,xr%1,xr%2,xr%3,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/**********************************D16MULF*******************************/ ++#define D16MULF_WW(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MULFxr%0,xr%1,xr%2,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MULF_LW(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MULFxr%0,xr%1,xr%2,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MULF_HW(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MULFxr%0,xr%1,xr%2,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MULF_XW(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MULFxr%0,xr%1,xr%2,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++//MXUenhancement ++#define D16MULE_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULExr%0,xr%1,xr%2,xr%3,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MULE_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULExr%0,xr%1,xr%2,xr%3,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MULE_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULExr%0,xr%1,xr%2,xr%3,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MULE_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MULExr%0,xr%1,xr%2,xr%3,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++/***********************************D16MAC********************************/ ++#define D16MAC_AA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_AS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MAC_SS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACxr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/**********************************D16MACF*******************************/ ++#define D16MACF_AA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_AS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACF_SS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACFxr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++//MXUenhancement ++/**********************************D16MACE*******************************/ ++#define D16MACE_AA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_AS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MACE_SS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MACExr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/**********************************D16MADL*******************************/ ++#define D16MADL_AA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_AS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D16MADL_SS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16MADLxr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************S16MAD*******************************/ ++#define S16MAD_A_HH(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,A,0" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_A_LL(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,A,1" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_A_HL(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,A,2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_A_LH(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,A,3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_S_HH(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,S,0" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_S_LL(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,S,1" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_S_HL(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,S,2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define S16MAD_S_LH(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("S16MADxr%0,xr%1,xr%2,xr%3,S,3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++ ++/***********************************Q8MUL********************************/ ++#define Q8MUL(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MULxr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++//MXUenhancement ++#define Q8MULSU(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MULSUxr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************Q8MAC********************************/ ++#define Q8MAC_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MAC_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MAC_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MAC_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++//MXUenhancement ++#define Q8MACSU_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACSUxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MACSU_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACSUxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MACSU_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACSUxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MACSU_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MACSUxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++/***********************************Q8MADL********************************/ ++#define Q8MADL_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MADLxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MADL_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MADLxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MADL_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MADLxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8MADL_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8MADLxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************D32ADD********************************/ ++#define D32ADD_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ADDxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ADD_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ADDxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ADD_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ADDxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ADD_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ADDxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************D32ACC********************************/ ++#define D32ACC_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACC_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACC_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACC_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++//MXUenhancement ++#define D32ACCM_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCMxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACCM_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCMxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACCM_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCMxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ACCM_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ACCMxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ASUM_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ASUMxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ASUM_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ASUMxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ASUM_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ASUMxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define D32ASUM_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D32ASUMxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************S32CPS********************************/ ++#define S32CPS(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32CPSxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++//MXUenhancement ++#define S32SLT(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32SLTxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32MOVZ(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32MOVZxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32MOVN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32MOVNxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32AND(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32ANDxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32OR(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32ORxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32XOR(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32XORxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32NOR(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32NORxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32ABS(xra,xrb) \ ++ do{ \ ++ __asm____volatile("S32CPSxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrb)); \ ++ }while(0) ++ ++/***********************************Q16ADD********************************/ ++#define Q16ADD_AA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++#define Q16ADD_AS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_AS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,AS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SA_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SA,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SA_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SA,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SA_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SA,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SA_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SA,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SS_WW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SS,WW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SS_LW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SS,LW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SS_HW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SS,HW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ADD_SS_XW(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ADDxr%0,xr%1,xr%2,xr%3,SS,XW" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/***********************************Q16ACC********************************/ ++#define Q16ACC_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACC_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACC_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACC_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++//MXUenhancement ++#define Q16ACCM_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCMxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACCM_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCMxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACCM_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCMxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ACCM_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ACCMxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ASUM_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ASUMxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ASUM_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ASUMxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ASUM_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ASUMxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q16ASUM_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16ASUMxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++/***********************************D16CPS********************************/ ++#define D16CPS(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16CPSxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++//MXUenhancement ++#define D16SLT(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16SLTxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MOVZ(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MOVZxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MOVN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MOVNxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16ABS(xra,xrb) \ ++ do{ \ ++ __asm____volatile("D16CPSxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrb)); \ ++ }while(0) ++ ++/*******************************D16ASUM************************************/ ++#define D16ASUM_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16ASUMxr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++#define D16ASUM_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16ASUMxr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++#define D16ASUM_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16ASUMxr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++#define D16ASUM_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("D16ASUMxr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++/*******************************D16AVG/D16AVGR*****************************/ ++#define D16AVG(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16AVGxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++#define D16AVGR(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16AVGRxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++/************************************Q8ADD********************************/ ++#define Q8ADD_AA(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8ADDxr%0,xr%1,xr%2,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8ADD_AS(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8ADDxr%0,xr%1,xr%2,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8ADD_SA(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8ADDxr%0,xr%1,xr%2,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8ADD_SS(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8ADDxr%0,xr%1,xr%2,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++ ++/************************************Q8ADDE********************************/ ++#define Q8ADDE_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ADDExr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ADDE_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ADDExr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ADDE_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ADDExr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ADDE_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ADDExr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++/************************************Q8ACCE********************************/ ++#define Q8ACCE_AA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ACCExr%0,xr%1,xr%2,xr%3,AA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ACCE_AS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ACCExr%0,xr%1,xr%2,xr%3,AS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ACCE_SA(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ACCExr%0,xr%1,xr%2,xr%3,SA" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++#define Q8ACCE_SS(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8ACCExr%0,xr%1,xr%2,xr%3,SS" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++ ++/************************************Q8ABD********************************/ ++#define Q8ABD(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8ABDxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++ ++/************************************Q8SLT********************************/ ++#define Q8SLT(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8SLTxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++//MXUenhancement ++#define Q8SLTU(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8SLTUxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8MOVZ(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8MOVZxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8MOVN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8MOVNxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D8SUM(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D8SUMxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D8SUMC(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D8SUMCxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++/************************************Q8SAD********************************/ ++#define Q8SAD(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q8SADxr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++/************************************Q16SCOP******************************/ ++#define Q16SCOP(xra,xrb,xrc,xrd) \ ++ do{ \ ++ __asm____volatile("Q16SCOPxr%0,xr%1,xr%2,xr%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd)); \ ++ }while(0) ++ ++/********************************Q8AVG/Q8AVGR*****************************/ ++#define Q8AVG(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8AVGxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++#define Q8AVGR(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8AVGRxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++ ++/**********************************D32SHIFT******************************/ ++#define D32SLL(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("D32SLLxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define D32SLR(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("D32SLRxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define D32SAR(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("D32SARxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define D32SARL(xra,xrb,xrc,SFT4) \ ++ do{ \ ++ __asm____volatile("D32SARLxr%0,xr%1,xr%2,%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(SFT4)); \ ++ }while(0) ++ ++#define D32SLLV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("D32SLLVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++#define D32SLRV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("D32SLRVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++#define D32SARV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("D32SARVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++#define D32SARW(xra,xrb,xrc,rb) \ ++ do{ \ ++ __asm____volatile("D32SARWxr%0,xr%1,xr%2,%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"d"(rb)); \ ++ }while(0) ++ ++ ++/**********************************Q16SHIFT******************************/ ++#define Q16SLL(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("Q16SLLxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define Q16SLR(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("Q16SLRxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define Q16SAR(xra,xrb,xrc,xrd,SFT4) \ ++ do{ \ ++ __asm____volatile("Q16SARxr%0,xr%1,xr%2,xr%3,%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(SFT4)); \ ++ }while(0) ++ ++#define Q16SLLV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("Q16SLLVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++#define Q16SLRV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("Q16SLRVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++#define Q16SARV(xra,xrd,rb) \ ++ do{ \ ++ __asm____volatile("Q16SARVxr%0,xr%1,%z2" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rb)); \ ++ }while(0) ++ ++ ++/*********************************MAX/MIN*********************************/ ++#define S32MAX(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32MAXxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32MIN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("S32MINxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MAX(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MAXxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define D16MIN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("D16MINxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8MAX(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8MAXxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define Q8MIN(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q8MINxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++ ++/*************************************MOVE********************************/ ++#define S32I2M(xra,rb) \ ++ do{ \ ++ __asm____volatile("S32I2Mxr%0,%z1" \ ++ : \ ++ :"K"(xra),"d"(rb)); \ ++ }while(0) ++ ++#define S32M2I(xra) \ ++ __extension__({ \ ++ int__d; \ ++ __asm____volatile("S32M2Ixr%1,%0" \ ++ :"=d"(__d) \ ++ :"K"(xra)); \ ++ __d; \ ++ }) ++ ++ ++/*********************************S32SFL**********************************/ ++#define S32SFL(xra,xrb,xrc,xrd,optn2) \ ++ do{ \ ++ __asm____volatile("S32SFLxr%0,xr%1,xr%2,xr%3,ptn%4" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(xrd),"K"(optn2)); \ ++ }while(0) ++ ++//MXUenhancement ++#define S32ALNI(xra,xrb,xrc,optn3) \ ++ do{ \ ++ __asm____volatile("S32ALNIxr%0,xr%1,xr%2,ptn%3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"K"(optn3)); \ ++ }while(0) ++ ++#define S32LUI(xra,s8,optn3) \ ++ do{ \ ++ __asm____volatile("S32LUIxr%0,%1,ptn%2" \ ++ : \ ++ :"K"(xra),"I"(s8),"K"(optn3)); \ ++ }while(0) ++ ++ ++/*********************************S32ALN**********************************/ ++#define S32ALN(xra,xrb,xrc,rs) \ ++ do{ \ ++ __asm____volatile("S32ALNxr%0,xr%1,xr%2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc),"d"(rs)); \ ++ }while(0) ++ ++ ++/*********************************Q16SAT**********************************/ ++#define Q16SAT(xra,xrb,xrc) \ ++ do{ \ ++ __asm____volatile("Q16SATxr%0,xr%1,xr%2" \ ++ : \ ++ :"K"(xra),"K"(xrb),"K"(xrc)); \ ++ }while(0) ++ ++#define S32EXTR(xra,xrd,rs,bits5) \ ++ do{ \ ++ __asm____volatile("S32EXTRxr%0,xr%1,%z2,%3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"I"(bits5)); \ ++ }while(0) ++ ++#define S32EXTRV(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32EXTRVxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++/*********************************S32MUL**********************************/ ++#define S32MUL(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MULxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#define S32MULU(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MULUxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#define S32MADD(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MADDxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#define S32MADDU(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MADDUxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#define S32MSUB(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MSUBxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#define S32MSUBU(xra,xrd,rs,rt) \ ++ do{ \ ++ __asm____volatile("S32MSUBUxr%0,xr%1,%z2,%z3" \ ++ : \ ++ :"K"(xra),"K"(xrd),"d"(rs),"d"(rt)); \ ++ }while(0) ++ ++#endif/*_MXU_H_*/ +diff --git a/arch/mips/xburst/common/include/mxuv3.h b/arch/mips/xburst/common/include/mxuv3.h +new file mode 100644 +index 000000000..10c631b0e +--- /dev/null ++++ b/arch/mips/xburst/common/include/mxuv3.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2005 Mips Technologies ++ * Author: Chris Dearman, chris@mips.com derived from fpu.h ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++#ifndef _ASM_MXU_V3_H ++#define _ASM_MXU_V3_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++void __init_mxuv3(void); ++void __save_mxuv3(void *tsk_void); ++void __restore_mxuv3(void *tsk_void); ++ ++static inline void init_mxuv3(void) ++{ ++ if(cpu_has_mxuv3) ++ __init_mxuv3(); ++} ++ ++ ++#define save_mxuv3(tsk) \ ++ do { \ ++ if (cpu_has_mxuv3) \ ++ __save_mxuv3(tsk); \ ++ } while (0) ++ ++static inline unsigned int is_mxuv3_enabled(void) ++{ ++ return ((cpu_has_mxuv3) && (read_c0_status() & ST0_CU2)); ++} ++ ++#define restore_mxuv3(tsk) \ ++ do { \ ++ if (cpu_has_mxuv3) \ ++ __restore_mxuv3(tsk); \ ++ } while (0) ++ ++#endif /* _ASM_MXU_V3_H */ +diff --git a/arch/mips/xburst/common/initrd-check.c b/arch/mips/xburst/common/initrd-check.c +new file mode 100644 +index 000000000..9ed9b5513 +--- /dev/null ++++ b/arch/mips/xburst/common/initrd-check.c +@@ -0,0 +1,49 @@ ++ ++#include ++#include ++#include ++#include ++ ++static void check_file(char *fname) ++{ ++ int err; ++ pr_info("check file %s ... ",fname); ++ err = sys_access((const char __user *) fname, O_RDONLY); ++ if (err < 0) ++ pr_info("failed %d.\n", err); ++ else ++ pr_info("successed.\n"); ++} ++ ++static int __init check_rootfs(void) ++{ ++ int err; ++ ++ if (sys_access((const char __user *) "/dev", O_RDWR) < 0) { ++ pr_info("Dir /dev is not exist.\n"); ++ sys_mkdir((const char __user *) "/dev", O_RDWR); ++ } ++ ++ if (sys_access((const char __user *) "/dev/console", O_RDWR) < 0) { ++ printk("create /dev/console\n"); ++ err = sys_mknod((const char __user __force *) "/dev/console", ++ S_IFCHR | S_IRUSR | S_IWUSR, ++ new_encode_dev(MKDEV(5, 1))); ++ if (err < 0) ++ goto out; ++ } ++ ++ check_file("/linuxrc"); ++ check_file("/init"); ++ check_file("/init.rc"); ++ check_file("/sbin/adbd"); ++ check_file("/bin/busybox"); ++ ++ return 0; ++ ++out: ++ printk(KERN_WARNING "Failed to create dev\n"); ++ return err; ++} ++ ++late_initcall(check_rootfs); +diff --git a/arch/mips/xburst/common/jz_notifier.c b/arch/mips/xburst/common/jz_notifier.c +new file mode 100644 +index 000000000..48621a797 +--- /dev/null ++++ b/arch/mips/xburst/common/jz_notifier.c +@@ -0,0 +1,83 @@ ++#include ++ ++static BLOCKING_NOTIFIER_HEAD(jz_notifier_chain_high); ++static BLOCKING_NOTIFIER_HEAD(jz_notifier_chain_normal); ++static BLOCKING_NOTIFIER_HEAD(jz_notifier_chain_low); ++static int jz_notifier(struct notifier_block *nb, unsigned long cmd, void *data) ++{ ++ struct jz_notifier *jz_nb = container_of(nb,struct jz_notifier,nb); ++ int ret = 0; ++ if(jz_nb->msg == cmd) { ++ ret = jz_nb->jz_notify(jz_nb,data); ++ } ++ return ret; ++} ++ ++int jz_notifier_register(struct jz_notifier *notify, unsigned int priority) ++{ ++ unsigned int ret = 0; ++ ++ if((notify->level < NOTEFY_PROI_START) && (notify->level >= NOTEFY_PROI_END)) ++ { ++ printk("notify level can not support this %d\n",notify->level); ++ dump_stack(); ++ return -1; ++ } ++ if((int)notify->msg >= JZ_CMD_END && (int)notify->msg <= JZ_CMD_START) ++ { ++ printk("notify msg can not support this %d\n",notify->msg); ++ dump_stack(); ++ return -1; ++ } ++ if(notify->jz_notify == NULL) ++ { ++ printk("notify function(jz_notify) cand not support NULL\n"); ++ dump_stack(); ++ return -1; ++ } ++ notify->nb.priority = notify->level; ++ notify->nb.notifier_call = jz_notifier; ++ ++ if(priority == NOTEFY_PROI_HIGH) ++ ret = blocking_notifier_chain_register(&jz_notifier_chain_high, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_NORMAL) ++ ret = blocking_notifier_chain_register(&jz_notifier_chain_normal, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_LOW) ++ ret = blocking_notifier_chain_register(&jz_notifier_chain_low, ¬ify->nb); ++ else ++ printk("not support\n"); ++ return ret; ++} ++EXPORT_SYMBOL(jz_notifier_register); ++ ++int jz_notifier_unregister(struct jz_notifier *notify, unsigned int priority) ++{ ++ unsigned int ret = 0; ++ ++ if(priority == NOTEFY_PROI_HIGH) ++ ret = blocking_notifier_chain_unregister(&jz_notifier_chain_high, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_NORMAL) ++ ret = blocking_notifier_chain_unregister(&jz_notifier_chain_normal, ¬ify->nb); ++ else if(priority == NOTEFY_PROI_LOW) ++ ret = blocking_notifier_chain_unregister(&jz_notifier_chain_low, ¬ify->nb); ++ else ++ printk("not support\n"); ++ return ret; ++} ++EXPORT_SYMBOL(jz_notifier_unregister); ++ ++int jz_notifier_call(unsigned int priority, unsigned long val, void *v) ++{ ++ unsigned int ret = 0; ++ ++ if(priority == NOTEFY_PROI_HIGH) ++ ret = blocking_notifier_call_chain(&jz_notifier_chain_high, val, v); ++ else if(priority == NOTEFY_PROI_NORMAL) ++ ret = blocking_notifier_call_chain(&jz_notifier_chain_normal, val, v); ++ else if(priority == NOTEFY_PROI_LOW) ++ ret = blocking_notifier_call_chain(&jz_notifier_chain_low, val, v); ++ else ++ printk("not support\n"); ++ return ret; ++} ++EXPORT_SYMBOL(jz_notifier_call); +diff --git a/arch/mips/xburst/common/mxu-xburst.c b/arch/mips/xburst/common/mxu-xburst.c +new file mode 100644 +index 000000000..dddaf6cc5 +--- /dev/null ++++ b/arch/mips/xburst/common/mxu-xburst.c +@@ -0,0 +1,85 @@ ++#include ++#include ++#include ++ ++void __save_mxu(void *tsk_void) ++{ ++#if 0 ++ struct task_struct *tsk = tsk_void; ++ register unsigned int reg_val asm("t0"); ++ asm volatile(".word 0x7008042e \n\t"); ++ tsk->thread.mxu.regs[0] = reg_val; ++ asm volatile(".word 0x7008006e \n\t"); ++ tsk->thread.mxu.regs[1] = reg_val; ++ asm volatile(".word 0x700800ae \n\t"); ++ tsk->thread.mxu.regs[2] = reg_val; ++ asm volatile(".word 0x700800ee \n\t"); ++ tsk->thread.mxu.regs[3] = reg_val; ++ asm volatile(".word 0x7008012e \n\t"); ++ tsk->thread.mxu.regs[4] = reg_val; ++ asm volatile(".word 0x7008016e \n\t"); ++ tsk->thread.mxu.regs[5] = reg_val; ++ asm volatile(".word 0x700801ae \n\t"); ++ tsk->thread.mxu.regs[6] = reg_val; ++ asm volatile(".word 0x700801ee \n\t"); ++ tsk->thread.mxu.regs[7] = reg_val; ++ asm volatile(".word 0x7008022e \n\t"); ++ tsk->thread.mxu.regs[8] = reg_val; ++ asm volatile(".word 0x7008026e \n\t"); ++ tsk->thread.mxu.regs[9] = reg_val; ++ asm volatile(".word 0x700802ae \n\t"); ++ tsk->thread.mxu.regs[10] = reg_val; ++ asm volatile(".word 0x700802ee \n\t"); ++ tsk->thread.mxu.regs[11] = reg_val; ++ asm volatile(".word 0x7008032e \n\t"); ++ tsk->thread.mxu.regs[12] = reg_val; ++ asm volatile(".word 0x7008036e \n\t"); ++ tsk->thread.mxu.regs[13] = reg_val; ++ asm volatile(".word 0x700803ae \n\t"); ++ tsk->thread.mxu.regs[14] = reg_val; ++ asm volatile(".word 0x700803ee \n\t"); ++ tsk->thread.mxu.regs[15] = reg_val; ++#endif ++} ++ ++void __restore_mxu(void * tsk_void) ++{ ++#if 0 ++ struct task_struct *tsk = tsk_void; ++ register unsigned int reg_val asm("t0"); ++ ++ reg_val = tsk->thread.mxu.regs[0]; ++ asm volatile(".word 0x7008042f \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[1]; ++ asm volatile(".word 0x7008006f \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[2]; ++ asm volatile(".word 0x700800af \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[3]; ++ asm volatile(".word 0x700800ef \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[4]; ++ asm volatile(".word 0x7008012f \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[5]; ++ asm volatile(".word 0x7008016f \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[6]; ++ asm volatile(".word 0x700801af \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[7]; ++ asm volatile(".word 0x700801ef \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[8]; ++ asm volatile(".word 0x7008022f \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[9]; ++ asm volatile(".word 0x7008026f \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[10]; ++ asm volatile(".word 0x700802af \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[11]; ++ asm volatile(".word 0x700802ef \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[12]; ++ asm volatile(".word 0x7008032f \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[13]; ++ asm volatile(".word 0x7008036f \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[14]; ++ asm volatile(".word 0x700803af \n\t"::"r"(reg_val)); ++ reg_val = tsk->thread.mxu.regs[15]; ++ asm volatile(".word 0x700803ef \n\t"::"r"(reg_val)); ++#endif ++} ++ +diff --git a/arch/mips/xburst/common/proc.c b/arch/mips/xburst/common/proc.c +new file mode 100644 +index 000000000..a32e05820 +--- /dev/null ++++ b/arch/mips/xburst/common/proc.c +@@ -0,0 +1,92 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++static struct proc_dir_entry *proc_jz_root; ++struct proc_dir_entry * jz_proc_mkdir(char *s) ++{ ++ struct proc_dir_entry *p; ++ if(!proc_jz_root) { ++ proc_jz_root = proc_mkdir("jz", 0); ++ if(!proc_jz_root) ++ return NULL; ++ } ++ p = proc_mkdir(s,proc_jz_root); ++ return p; ++} ++ ++EXPORT_SYMBOL(jz_proc_mkdir); ++ ++static int jz_proc_show(struct seq_file *filq, void *v) ++{ ++ int ret = 1; ++ struct jz_single_file_ops *proc_fops = filq->private; ++ filq->private = proc_fops->data; ++ ++ if(proc_fops->read) ++ ret = proc_fops->read(filq, v); ++ ++ filq->private = proc_fops; ++ return ret; ++} ++static int jz_proc_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, jz_proc_show, PDE_DATA(inode)); ++} ++static ssize_t jz_proc_write(struct file *file, const char __user *buffer, size_t usize, loff_t *off) ++{ ++ size_t ret; ++ struct jz_single_file_ops *proc_fops = ((struct seq_file *)file->private_data)->private; ++ ((struct seq_file *)file->private_data)->private = proc_fops->data; ++ ++ ret = proc_fops->write(file, buffer, usize, off); ++ ((struct seq_file *)file->private_data)->private = proc_fops; ++ ++ return ret; ++} ++ ++struct proc_dir_entry *jz_proc_create_data( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops, void *data) ++{ ++ struct proc_ops *jz_proc_fops; ++ ++ jz_proc_fops = kmalloc(sizeof(struct proc_ops), GFP_KERNEL); ++ if(!jz_proc_fops) { ++ return NULL; ++ } ++ ++ jz_proc_fops->proc_read = seq_read; ++ jz_proc_fops->proc_lseek = seq_lseek; ++ jz_proc_fops->proc_release = single_release; ++ jz_proc_fops->proc_open = jz_proc_open; ++ jz_proc_fops->proc_write = jz_proc_write; ++ proc_fops->data = data; ++ ++ return proc_create_data(name, mode, parent, jz_proc_fops, proc_fops); ++} ++ ++struct proc_dir_entry *jz_proc_create( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops) ++{ ++ return jz_proc_create_data(name, mode, parent, proc_fops, NULL); ++} ++ ++struct proc_dir_entry * get_jz_proc_root(void) ++{ ++ if(!proc_jz_root) { ++ proc_jz_root = proc_mkdir("jz", 0); ++ if(!proc_jz_root) ++ return NULL; ++ } ++ return proc_jz_root; ++} +diff --git a/arch/mips/xburst/common/prom.c b/arch/mips/xburst/common/prom.c +new file mode 100644 +index 000000000..d2dedbec0 +--- /dev/null ++++ b/arch/mips/xburst/common/prom.c +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (C) 2010, Lars-Peter Clausen ++ * INGENIC SoC prom code ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#ifdef CONFIG_XBURST_MXUV2 ++#include ++#include ++#endif ++ ++extern struct plat_smp_ops ingenic_soc_smp_ops; ++ ++static void *_fw_fdt_addr; ++ ++void __init prom_init(void) ++{ ++ fw_init_cmdline(); ++ ++ if (fw_arg0 == 0 && fw_arg1 == 0xffffffffUL) ++ _fw_fdt_addr = phys_to_virt(fw_arg2); ++ else if ((int)fw_arg0 == -2) /*UHI*/ ++ _fw_fdt_addr = (void *)fw_arg1; ++ else if (__dtb_start != __dtb_end) ++ _fw_fdt_addr = __dtb_start; ++ else ++ panic("no dtb found!\n"); ++ ++ //mips_machtype = MACH_INGENIC_X1600; ++} ++ ++void __init prom_free_prom_memory(void) ++{ ++} ++ ++const char *get_system_type(void) ++{ ++ return "XBurst-Based"; ++} ++ ++void __init *get_fdt_addr(void) ++{ ++ return _fw_fdt_addr; ++} ++#ifdef CONFIG_XBURST_MXUV2 ++noinline struct xburst_cop2_state *get_current_cp2(void) ++{ ++ return &(current->thread.cp2); ++} ++#endif +diff --git a/arch/mips/xburst/common/sc-xburst.c b/arch/mips/xburst/common/sc-xburst.c +new file mode 100644 +index 000000000..e50d9a160 +--- /dev/null ++++ b/arch/mips/xburst/common/sc-xburst.c +@@ -0,0 +1,238 @@ ++/* ++ * Copyright (C) 2006 Chris Dearman (chris@mips.com), ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * MIPS32/MIPS64 L2 cache handling ++ */ ++static unsigned long scache_size __read_mostly; ++static void (* r4k_blast_scache)(void); ++static void cache_noop(void) {} ++ ++void __weak platform_early_l2_init(void) ++{ ++} ++ ++#if 0 ++static void mips_bridge_sync_war(unsigned long addr, unsigned long size) ++{ ++ __fast_iob(); ++} ++#endif ++ ++static void r4k_blast_scache_setup(void) ++{ ++ unsigned long sc_lsize = cpu_scache_line_size(); ++ ++ /*default*/ ++ r4k_blast_scache = blast_scache32; ++ ++ if (scache_size == 0) { ++ //r4k_blast_scache = (void *)blast_inclusive_scache; ++ r4k_blast_scache = cache_noop; ++ } else if (sc_lsize == 16) ++ r4k_blast_scache = blast_scache16; ++ else if (sc_lsize == 32) ++ r4k_blast_scache = blast_scache32; ++ else if (sc_lsize == 64) ++ r4k_blast_scache = blast_scache64; ++ else if (sc_lsize == 128) ++ r4k_blast_scache = blast_scache128; ++} ++ ++/* ++ * Writeback and invalidate the secondary cache before DMA. ++ */ ++static void mips_sc_wback_inv(unsigned long addr, unsigned long size) ++{ ++ __sync(); ++ ++ if (size >= scache_size) ++ r4k_blast_scache(); ++ else ++ blast_scache_range(addr, addr + size); ++ ++#ifdef MIPS_BRIDGE_SYNC_WAR ++ if (MIPS_BRIDGE_SYNC_WAR) ++ __fast_iob(); ++#endif ++} ++ ++/* ++ * Invalidate the secondary cache before DMA. ++ */ ++static void mips_sc_inv(unsigned long addr, unsigned long size) ++{ ++ unsigned long lsize = cpu_scache_line_size(); ++ unsigned long almask = ~(lsize - 1); ++ ++ if (size >= scache_size) { ++ r4k_blast_scache(); ++ }else { ++ cache_op(Hit_Writeback_Inv_SD, addr & almask); ++ cache_op(Hit_Writeback_Inv_SD, (addr + size - 1) & almask); ++ blast_inv_scache_range(addr, addr + size); ++ } ++ ++#ifdef MIPS_BRIDGE_SYNC_WAR ++ if (MIPS_BRIDGE_SYNC_WAR) ++ __fast_iob(); ++#endif ++} ++ ++static struct bcache_ops mips_sc_ops = { ++ .bc_enable = (void *)cache_noop, ++ .bc_disable = (void *)cache_noop, ++ .bc_wback_inv = mips_sc_wback_inv, ++ .bc_inv = mips_sc_inv, ++}; ++ ++/* ++ * Check if the L2 cache controller is activated on a particular platform. ++ * MTI's L2 controller and the L2 cache controller of Broadcom's BMIPS ++ * cores both use c0_config2's bit 12 as "L2 Bypass" bit, that is the ++ * cache being disabled. However there is no guarantee for this to be ++ * true on all platforms. In an act of stupidity the spec defined bits ++ * 12..15 as implementation defined so below function will eventually have ++ * to be replaced by a platform specific probe. ++ */ ++static inline int mips_sc_is_activated(struct cpuinfo_mips *c) ++{ ++ unsigned int config2 = read_c0_config2(); ++ unsigned int tmp; ++ ++ /* Check the bypass bit (L2B) */ ++ switch (current_cpu_type()) { ++ case CPU_34K: ++ case CPU_74K: ++ case CPU_1004K: ++ case CPU_1074K: ++ case CPU_INTERAPTIV: ++ case CPU_PROAPTIV: ++ case CPU_P5600: ++ case CPU_BMIPS5000: ++ case CPU_QEMU_GENERIC: ++ if (config2 & (1 << 12)) ++ return 0; ++ } ++ ++ tmp = (config2 >> 4) & 0x0f; ++ if (0 < tmp && tmp <= 7) ++ c->scache.linesz = 2 << tmp; ++ else ++ return 0; ++ return 1; ++} ++ ++static inline int __init mips_sc_probe(void) ++{ ++ struct cpuinfo_mips *c = ¤t_cpu_data; ++ unsigned int config1, config2; ++ unsigned int tmp; ++ ++ /* Mark as not present until probe completed */ ++ c->scache.flags |= MIPS_CACHE_NOT_PRESENT; ++ ++ /* Ignore anything but MIPSxx processors */ ++ if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | ++ MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | ++ MIPS_CPU_ISA_M64R2 | MIPS_CPU_ISA_M64R6))) ++ return 0; ++ ++ /* ++ * Do we need some platform specific probing before ++ * we configure L2? ++ */ ++ platform_early_l2_init(); ++ ++#if 0 ++ switch(c->processor_id & PRID_CPU_FEATURE_MASK){ ++ case PRID_CPU_JZ4775S: ++ case PRID_CPU_JZ4780: ++ case PRID_CPU_X1000: ++ if (MIPS_BRIDGE_SYNC_WAR) { ++ mips_sc_ops.bc_wback_inv = mips_bridge_sync_war; ++ return 1; ++ } ++ return 0; ++ case PRID_CPU_X1800: ++ case PRID_CPU_M200: ++ mips_sc_ops.bc_wback_inv = mips_sc_wback_inv; ++ mips_sc_ops.bc_inv = mips_sc_inv; ++ break; ++ default: ++ pr_warn("processor_id[0x%08x] s-cache is not support\n", c->processor_id); ++ break; ++ } ++#endif ++ ++ /* Does this MIPS32/MIPS64 CPU have a config2 register? */ ++ config1 = read_c0_config1(); ++ if (!(config1 & MIPS_CONF_M)) ++ return 0; ++ ++ config2 = read_c0_config2(); ++ ++ if (!mips_sc_is_activated(c)) ++ return 0; ++ ++ tmp = (config2 >> 8) & 0x0f; ++ if (tmp <= 7) ++ c->scache.sets = 64 << tmp; ++ else ++ return 0; ++ ++ tmp = (config2 >> 0) & 0x0f; ++ if (tmp <= 7) ++ c->scache.ways = tmp + 1; ++ else ++ return 0; ++ ++ c->scache.waysize = c->scache.sets * c->scache.linesz; ++ c->scache.waybit = __ffs(c->scache.waysize); ++ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; ++ ++ scache_size = c->scache.ways * c->scache.sets * c->scache.linesz; ++ write_c0_ecc(0x0); ++ ++ r4k_blast_scache_setup(); ++ return 1; ++} ++ ++static char *way_string[] = { NULL, "direct mapped", "2-way", ++ "3-way", "4-way", "5-way", "6-way", "7-way", "8-way", ++ "9-way", "10-way", "11-way", "12-way", ++ "13-way", "14-way", "15-way", "16-way", ++}; ++ ++int ingenic_sc_init(void) ++{ ++ struct cpuinfo_mips *c = ¤t_cpu_data; ++ int found = mips_sc_probe(); ++ ++ if (found) { ++ bcops = &mips_sc_ops; ++ bc_enable(); ++ bc_prefetch_enable(); ++ } ++ ++ if (!scache_size) ++ return 0; ++ ++ printk("Unified secondary cache %ldkB %s, linesize %d bytes.\n", ++ scache_size >> 10, way_string[c->scache.ways], c->scache.linesz); ++ ++ return found; ++} +diff --git a/arch/mips/xburst/debug/Makefile b/arch/mips/xburst/debug/Makefile +new file mode 100644 +index 000000000..ebdd5af55 +--- /dev/null ++++ b/arch/mips/xburst/debug/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_TRACEPOINTS) += trace-exit.o +diff --git a/arch/mips/xburst/debug/trace-exit.c b/arch/mips/xburst/debug/trace-exit.c +new file mode 100644 +index 000000000..3fcfe2904 +--- /dev/null ++++ b/arch/mips/xburst/debug/trace-exit.c +@@ -0,0 +1,31 @@ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++probe_sched_process_exit(void *d,struct task_struct *p) ++{ ++ struct thread_struct *thread = &p->thread; ++ ++ printk("[EXIT] %s pid %d, ", p->comm, p->pid); ++ printk("exit_stat %d, exit_signal %d\n",p->exit_code,p->exit_signal); ++ printk(" badvaddr %lx, baduaddr %lx, error_code %ld\n", ++ thread->cp0_badvaddr,thread->cp0_baduaddr,thread->error_code); ++ ++ if (p->pid == 1) ++ ftrace_dump(DUMP_ALL); ++} ++ ++static int init_trace(void) ++{ ++ int ret = -1; ++ ++ ret = register_trace_sched_process_exit(probe_sched_process_exit, NULL); ++ if (ret) ++ printk("register process exit failed.\n"); ++ ++ return ret; ++} ++arch_initcall(init_trace); +diff --git a/arch/mips/xburst/soc-x1000/Kconfig.DT b/arch/mips/xburst/soc-x1000/Kconfig.DT +new file mode 100644 +index 000000000..3938067c6 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/Kconfig.DT +@@ -0,0 +1,9 @@ ++choice ++ prompt "device tree select for X1000 boards" ++ default DT_X1000_MODULE ++ depends on SOC_X1000 ++ ++config DT_X1000_MODULE ++ bool "x1000 module base" ++ ++endchoice +diff --git a/arch/mips/xburst/soc-x1000/Makefile b/arch/mips/xburst/soc-x1000/Makefile +new file mode 100644 +index 000000000..26cd0a5f7 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/Makefile +@@ -0,0 +1,5 @@ ++obj-y += setup.o ++obj-y += socid.o ++obj-y += regs_save_restore.o ++obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ++obj-$(CONFIG_PM) += pm.o +diff --git a/arch/mips/xburst/soc-x1000/early_printk.c b/arch/mips/xburst/soc-x1000/early_printk.c +new file mode 100644 +index 000000000..5d745d7c9 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/early_printk.c +@@ -0,0 +1,76 @@ ++/* ++ * INGENIC SOC serial routines for early_printk. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#define UART_OFF (0x1000) ++ ++static void check_uart(char c); ++ ++static volatile u32 *uart_base; ++typedef void (*putchar_f_t)(char); ++ ++static putchar_f_t putchar_f = check_uart; ++ ++static void putchar(char ch) ++{ ++ int timeout = 10000; ++ volatile u32 *base = uart_base; ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ((base[UART_LSR] & (UART_LSR_THRE | UART_LSR_TEMT)) ++ != (UART_LSR_THRE | UART_LSR_TEMT) && timeout--) ++ ; ++ base[UART_TX] = (u8)ch; ++} ++ ++static void putchar_dummy(char ch) ++{ ++ return; ++} ++ ++#define UART_SPR (0x1C/4) ++ ++static void check_uart(char c) ++{ ++ /* We Couldn't use ioremap() here */ ++ volatile u32 *base = (volatile u32*)CKSEG1ADDR(UART0_IOBASE); ++ int i; ++ for(i=0; i < 3; i++) { ++ if(base[UART_SPR] == 0xa9) ++ break; ++ base += (UART_OFF/sizeof(u32)); ++ } ++ ++ if(i < 3) { ++ uart_base = base; ++ putchar_f = putchar; ++ putchar_f(c); ++ } else { ++ putchar_f = putchar_dummy; ++ } ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ putchar_f(c); ++} ++ ++static int __init early_parse_console(char *p) ++{ ++ unsigned char *param = "null"; ++ ++ if(strstr(p, param)){ ++ putchar_f = putchar_dummy; ++ } ++ return 0; ++} ++early_param("console", early_parse_console); +diff --git a/arch/mips/xburst/soc-x1000/include/cpu-feature-overrides.h b/arch/mips/xburst/soc-x1000/include/cpu-feature-overrides.h +new file mode 100644 +index 000000000..88b84f5b5 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/include/cpu-feature-overrides.h +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++ ++#define cpu_dcache_size() (16 * 1024) ++#define cpu_dcache_ways() 4 ++#define cpu_dcache_line_size() 32 ++#define cpu_icache_size() (16 * 1024) ++#define cpu_icache_ways() 4 ++#define cpu_icache_line_size() 32 ++#define cpu_has_tlb 1 ++#define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_4k_cache 1 ++#define cpu_has_tx39_cache 0 ++#define cpu_has_fpu 1 ++#define cpu_has_32fpr 1 ++#define cpu_has_counter 0 ++#define cpu_has_watch 1 ++#define cpu_has_divec 1 ++#define cpu_has_vce 0 ++#define cpu_has_cache_cdex_p 0 ++#define cpu_has_cache_cdex_s 0 ++#define cpu_has_prefetch 1 ++#define cpu_has_mcheck 1 ++#define cpu_has_ejtag 1 ++#define cpu_has_llsc 1 ++#define cpu_has_mips16 0 ++#define cpu_has_mdmx 0 ++#define cpu_has_mips3d 0 ++#define cpu_has_smartmips 0 ++#define cpu_has_vtag_icache 0 ++#define cpu_has_dc_aliases 0 ++#define cpu_has_ic_fills_f_dc 0 ++#define cpu_has_pindexed_dcache 0 ++#define cpu_icache_snoops_remote_store 0 ++#define cpu_has_mips32r1 1 ++#define cpu_has_mips32r2 1 ++#define cpu_has_mips64r1 0 ++#define cpu_has_mips64r2 0 ++#define cpu_has_dsp 0 ++#define cpu_has_mipsmt 0 ++#define cpu_has_userlocal 0 ++#define cpu_has_nofpuex 0 ++#define cpu_has_64bits 0 ++#define cpu_has_64bit_zero_reg 0 ++#define cpu_has_vint 0 ++#define cpu_has_veic 0 ++#define cpu_has_inclusive_pcaches 0 ++ ++#endif +diff --git a/arch/mips/xburst/soc-x1000/include/irq.h b/arch/mips/xburst/soc-x1000/include/irq.h +new file mode 100644 +index 000000000..a3ce931ce +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/include/irq.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2010 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_IRQ_H__ ++#define __ASM_MACH_INGENIC_IRQ_H__ ++ ++/* IRQ for MIPS CPU */ ++#define MIPS_CPU_IRQ_BASE 0 ++#define MIPS_CPU_IRQ(x) (MIPS_CPU_IRQ_BASE + (x)) ++ ++#define XBURST_INT MIPS_CPU_IRQ(2) ++#define XBURST_SYS_OST MIPS_CPU_IRQ(3) ++ ++#define MIPS_CPU_IRQS (MIPS_CPU_IRQ(7) + 1 - MIPS_CPU_IRQ_BASE) ++#define XBURST_SOC_IRQ_BASE MIPS_CPU_IRQS ++ ++#define INTC_CHIP_NUM 2 ++ ++#ifndef NR_IRQS ++#define NR_IRQS (200) ++#endif ++ ++#endif +diff --git a/arch/mips/xburst/soc-x1000/include/soc/base.h b/arch/mips/xburst/soc-x1000/include/soc/base.h +new file mode 100644 +index 000000000..52a6ca30b +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/include/soc/base.h +@@ -0,0 +1,90 @@ ++ ++#ifndef __INGENIC_SOC_SOC_H__ ++#define __INGENIC_SOC_SOC_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 ++#define DDRC1_IOBASE 0x13010000 ++#define DDRC_IOBASE 0x13020000 ++#define X2D_IOBASE 0x13030000 ++#define GPU_IOBASE 0x13040000 ++#define LCDC_IOBASE 0x13050000 ++#define CIM_IOBASE 0x13060000 ++#define COMPRESS_IOBASE 0x13070000 ++#define IPU0_IOBASE 0x13080000 ++#define GPVLC_IOBASE 0x13090000 ++#define IPU1_IOBASE 0x130b0000 ++#define CIM1_IOBASE 0x130e0000 ++#define MONITOR_IOBASE 0x130f0000 ++#define EPDC_IOBASE 0x130c0000 ++#define EPDCE_IOBASE 0x130d0000 ++ ++/* AHB1 BUS Devices Base */ ++#define SCH_IOBASE 0x13200000 ++#define VDMA_IOBASE 0x13210000 ++#define EFE_IOBASE 0x13240000 ++#define MCE_IOBASE 0x13250000 ++#define DBLK_IOBASE 0x13270000 ++#define VMAU_IOBASE 0x13280000 ++#define SDE_IOBASE 0x13290000 ++#define AUX_IOBASE 0x132a0000 ++#define TCSM_IOBASE 0x132c0000 ++#define JPGC_IOBASE 0x132e0000 ++#define SRAM_IOBASE 0x132f0000 ++ ++/* AHB2 BUS Devices Base */ ++#define HARB2_IOBASE 0x13400000 ++#define NEMC_IOBASE 0x13410000 ++#define PDMA_IOBASE 0x13420000 ++#define SFC_IOBASE 0x13440000 ++#define MSC0_IOBASE 0x13450000 ++#define MSC1_IOBASE 0x13460000 ++#define MSC2_IOBASE 0x13470000 ++#define GPS_IOBASE 0x13480000 ++#define EHCI_IOBASE 0x13490000 ++#define OHCI_IOBASE 0x134a0000 ++#define ETHC_IOBASE 0x134b0000 ++#define BCH_IOBASE 0x134d0000 ++#define TSSI0_IOBASE 0x134e0000 ++#define TSSI1_IOBASE 0x134f0000 ++#define OTG_IOBASE 0x13500000 ++#define EFUSE_IOBASE 0x13540000 ++#define SECURITY_IOBASE 0x13430000 ++ ++ ++#define OST_IOBASE 0x12000000 ++#define HDMI_IOBASE 0x10180000 ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 ++#define INTC_IOBASE 0x10001000 ++#define TCU_IOBASE 0x10002000 ++#define RTC_IOBASE 0x10003000 ++#define GPIO_IOBASE 0x10010000 ++#define AIC_IOBASE 0x10020000 ++#define DMIC_IOBASE 0x10021000 ++#define SPDIF0_IOBASE 0x10020080 ++#define UART0_IOBASE 0x10030000 ++#define UART1_IOBASE 0x10031000 ++#define UART2_IOBASE 0x10032000 ++#define UART3_IOBASE 0x10033000 ++#define SSC_IOBASE 0x10040000 ++#define SSI0_IOBASE 0x10043000 ++#define SSI1_IOBASE 0x10044000 ++#define I2C0_IOBASE 0x10050000 ++#define I2C1_IOBASE 0x10051000 ++#define I2C2_IOBASE 0x10052000 ++#define KMC_IOBASE 0x10060000 ++#define DES_IOBASE 0x10061000 ++#define SADC_IOBASE 0x10070000 ++#define PCM_IOBASE 0x10071000 ++#define OWI_IOBASE 0x10072000 ++#define WDT_IOBASE 0x10002000 ++ ++#define AUX_IOBASE 0x132a0000 ++#define DDRC_BASE 0xb34f0000 ++#endif +diff --git a/arch/mips/xburst/soc-x1000/include/soc/cache.h b/arch/mips/xburst/soc-x1000/include/soc/cache.h +new file mode 100644 +index 000000000..393ad6861 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/include/soc/cache.h +@@ -0,0 +1,116 @@ ++#ifndef __CHIP_CACHE_H__ ++#define __CHIP_CACHE_H__ ++ ++#include ++ ++ ++#define cache_prefetch(label,size) \ ++ do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&label + size) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set mips32\n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set mips32\n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++ } \ ++ while(0) ++ ++#define cache_prefetch_lable(label,l2) \ ++ do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&l2) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set mips32\n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set mips32\n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++ } \ ++ while(0) ++ ++#define K0BASE KSEG0 ++#define CFG_DCACHE_SIZE 16384 ++#define CFG_ICACHE_SIZE 16384 ++#define CFG_CACHELINE_SIZE 32 ++ ++static inline void __jz_flush_cache_all(void) ++{ ++ register unsigned long addr; ++ /* Clear CP0 TagLo */ ++ asm volatile ("mtc0 $0, $28\n\t"); ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Writeback_Inv_D), "r"(addr)); ++ } ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ /* invalidate BTB */ ++ asm volatile ( ++ ".set mips32\n\t" ++ " mfc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ " ori $26, 2\n\t" ++ " mtc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ ".set mips32\n\t" ++ ); ++ asm volatile ("sync\n\t" ++ "lw $0,0(%0)" ++ ::"r" (0xa0000000)); ++ ++} ++ ++static inline void __jz_cache_init(void) ++{ ++ register unsigned long addr; ++ asm volatile ("mtc0 $0, $28\n\t"::); ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_D), "r"(addr)); ++ } ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ /* invalidate BTB */ ++ asm volatile ( ".set mips32\n\t" ++ " mfc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ " ori $26, 2\n\t" ++ " mtc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ "nop\n\t" ++ ".set mips32\n\t" ++ ); ++} ++ ++ ++#endif /* __CHIP_CACHE_H__ */ +diff --git a/arch/mips/xburst/soc-x1000/include/soc/cpm.h b/arch/mips/xburst/soc-x1000/include/soc/cpm.h +new file mode 100644 +index 000000000..bc6d0695b +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/include/soc/cpm.h +@@ -0,0 +1,159 @@ ++/* ++ * SOC CPM register definition. ++ * ++ * CPM (Clock reset and Power control Management) ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __SOC_CPM_H__ ++#define __SOC_CPM_H__ ++ ++#define CPM_CPCCR (0x00) ++#define CPM_CPCSR (0xd4) ++ ++#define CPM_DDRCDR (0x2c) ++#define CPM_I2SCDR (0x60) ++#define CPM_I2SCDR1 (0x70) ++#define CPM_LPCDR (0x64) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0xa4) ++#define CPM_USBCDR (0x50) ++#define CPM_MACCDR (0x54) ++#define CPM_SFCCDR (0x74) ++#define CPM_CIMCDR (0x7c) ++#define CPM_PCMCDR (0x84) ++#define CPM_PCMCDR1 (0xe0) ++#define CPM_MPHYC (0xe8) ++ ++#define CPM_INTR (0xb0) ++#define CPM_INTRE (0xb4) ++#define CPM_DRCG (0xd0) ++#define CPM_CPSPPR (0x38) ++#define CPM_CPPSR (0x34) ++ ++#define CPM_USBPCR (0x3c) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++ ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++ ++#define CPM_LCR (0x04) ++#define CPM_PSWC0ST (0x90) ++#define CPM_PSWC1ST (0x94) ++#define CPM_PSWC2ST (0x98) ++#define CPM_PSWC3ST (0x9c) ++#define CPM_CLKGR (0x20) ++#define CPM_MESTSEL (0xec) ++#define CPM_SRBC (0xc4) ++#define CPM_ERNG (0xd8) ++#define CPM_RNG (0xdc) ++#define CPM_SLBC (0xc8) ++#define CPM_SLPC (0xcc) ++#define CPM_OPCR (0x24) ++#define CPM_RSR (0x08) ++ ++#define LCR_LPM_MASK (0x3) ++#define LCR_LPM_SLEEP (0x1) ++ ++#ifndef BIT ++#define BIT(nr) (1UL << nr) ++#endif ++ ++/*USB Parameter Control Register*/ ++#define USBPCR_USB_MODE BIT(31) ++#define USBPCR_AVLD_REG BIT(30) ++#define USBPCR_IDPULLUP_MASK_BIT 28 ++#define USBPCR_IDPULLUP_MASK_MSK (0x3 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS_SUSPEND (0x1 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_INCR_MASK BIT(27) ++#define USBPCR_TXRISETUNE BIT(26) /*0*/ ++#define USBPCR_COMMONONN BIT(25) ++#define USBPCR_VBUSVLDEXT BIT(24) ++#define USBPCR_VBUSVLDEXTSEL BIT(23) ++#define USBPCR_POR_BIT 22 ++#define USBPCR_POR BIT(USBPCR_POR_BIT) ++#define USBPCR_SIDDQ BIT(21) ++#define USBPCR_OTG_DISABLE BIT(20) ++#define USBPCR_COMPDISTUNE_BIT 17 ++#define USBPCR_COMPDISTUNE_MSK (0x7 << USBPCR_COMPDISTUNE_BIT) ++#define USBPCR_COMPDISTUNE(x) (((x) << USBPCR_COMPDISTUNE_BIT) & USBPCR_COMPDISTUNE_MSK) /*4*/ ++#define USBPCR_OTGTUNE_BIT 14 ++#define USBPCR_OTGTUNE_MSK (0x7 << USBPCR_OTGTUNE_BIT) ++#define USBPCR_OTGTUNE(x) (((x) << USBPCR_OTGTUNE_BIT) & USBPCR_OTGTUNE_MSK) /*4*/ ++#define USBPCR_SQRXTUNE_BIT 11 ++#define USBPCR_SQRXTUNE_MSK (0x7 << USBPCR_SQRXTUNE_BIT) ++#define USBPCR_SQRXTUNE(x) (((x) << USBPCR_SQRXTUNE_BIT) & USBPCR_SQRXTUNE_MSK) /*3*/ ++#define USBPCR_TXFSLSTUNE_BIT 7 ++#define USBPCR_TXFSLSTUNE_MSK (0xf << USBPCR_TXFSLSTUNE_BIT) ++#define USBPCR_TXFSLSTUNE(x) (((x) << USBPCR_TXFSLSTUNE_BIT) & USBPCR_TXFSLSTUNE_MSK) /*2*/ ++#define USBPCR_TXPREEMPHTUNE BIT(6) /*0*/ ++#define USBPCR_TXHSXVTUNE_BIT 4 ++#define USBPCR_TXHSXVTUNE_MSK (0x3 << USBPCR_TXHSXVTUNE_BIT) ++#define USBPCR_TXHSXVTUNE(x) (((x) << USBPCR_TXHSXVTUNE_BIT) & USBPCR_TXHSXVTUNE_MSK) /*3*/ ++#define USBPCR_TXVREFTUNE_BIT 0 ++#define USBPCR_TXVREFTUNE_MSK (0xf << USBPCR_TXVREFTUNE_BIT) ++#define USBPCR_TXVREFTUNE(x) (((x) << USBPCR_TXVREFTUNE_BIT) & USBPCR_TXVREFTUNE_MSK) /*4*/ ++ ++/*USB Reset Detect Timer Register*/ ++#define USBRDT_HB_MASK BIT(26) ++#define USBRDT_VBFIL_LD_EN BIT(25) ++#define USBRDT_IDDIG_EN 24 ++#define USBRDT_IDDIG_REG 23 ++#define USBRDT_USBRDT_MSK (0x7fffff) ++#define USBRDT_USBRDT(x) ((x) & USBRDT_USBRDT_MSK) ++ ++/*USB VBUS Jitter Filter Register*/ ++#define USBVBFIL_USBVBFIL(x) ((x) & 0xffff) ++#define USBVBFIL_IDDIGFIL(x) ((x) & (0xffff << 16)) ++ ++/*USB Parameter Control Register1*/ ++#define USBPCR1_BVLD_REG BIT(31) ++#define USBPCR1_REFCLKSEL (0x3 << 26) ++#define USBPCR1_REFCLKDIV_MSK (0x3 << 24) ++#define USBPCR1_REFCLKDIV(x) (((x) & 0x3) << 24) ++#define USBPCR1_REFCLKDIV_48M (0x2) ++#define USBPCR1_REFCLKDIV_24M (0x1) ++#define USBPCR1_REFCLKDIV_12M (0x0) ++#define USBPCR1_PORT_RST BIT(21) ++#define USBPCR1_PORT1_RST BIT(20) ++#define USBPCR1_WORD_IF_16BIT BIT(19) ++#define USBPCR1_WORD_IF1_16BIT BIT(18) ++#define USBPCR1_COMPDISTUNE1_BIT 15 ++#define USBPCR1_COMPDISTUNE1_MSK (0x7 << USBPCR1_COMPDISTUNE1_BIT) ++#define USBPCR1_COMPDISTUNE1(x) (((x) << USBPCR1_COMPDISTUNE1_BIT) & USBPCR1_COMPDISTUNE1_MSK) ++#define USBPCR1_SQRXTUNE1_BIT 12 ++#define USBPCR1_SQRXTUNE1_MSK (0x7 << USBPCR1_SQRXTUNE1_BIT) ++#define USBPCR1_SQRXTUNE1(x) (((x) << USBPCR1_SQRXTUNE1_BIT) & USBPCR1_SQRXTUNE1_MSK) /*3*/ ++#define USBPCR1_TXFSLSTUNE1_BIT 8 ++#define USBPCR1_TXFSLSTUNE1_MSK (0xf << USBPCR1_TXFSLSTUNE1_BIT) ++#define USBPCR1_TXFSLSTUNE1(x) (((x) << USBPCR1_TXFSLSTUNE1_BIT) & USBPCR1_TXFSLSTUNE1_MSK) /*2*/ ++#define USBPCR1_TXPREEMPHTUNE1 BIT(6) /*0*/ ++#define USBPCR1_TXHSXVTUNE1_BIT 5 ++#define USBPCR1_TXHSXVTUNE1_MSK (0x3 << USBPCR1_TXHSXVTUNE1_BIT) ++#define USBPCR1_TXHSXVTUNE1(x) (((x) << USBPCR1_TXHSXVTUNE1_BIT) & USBPCR1_TXHSXVTUNE1_MSK) /*3*/ ++#define USBPCR1_TXVREFTUNE1_BIT 1 ++#define USBPCR1_TXVREFTUNE1_MSK (0xf << USBPCR1_TXVREFTUNE1_BIT) ++#define USBPCR1_TXVREFTUNE1(x) (((x) << USBPCR1_TXVREFTUNE1_BIT) & USBPCR1_TXVREFTUNE1_MSK) /*4*/ ++#define USBPCR1_TXRISETUNE1 BIT(0) ++ ++/*Oscillator and Power Control Register*/ ++#define OPCR_IDLE BIT(31) ++#define OPCR_USB_SPENDN BIT(7) ++#define OPCR_USB_SPENDN1 BIT(6) ++#define OPCR_PD BIT(3) ++#define OPCR_ERCS BIT(2) ++ ++/*Soft Reset and Bus Control Register*/ ++#define SRBC_OTG_SR BIT(12) ++ ++#define cpm_inl(off) inl(CPM_IOBASE + (off)) ++#define cpm_outl(val,off) outl(val,CPM_IOBASE + (off)) ++#define cpm_clear_bit(val,off) do{cpm_outl((cpm_inl(off) & ~(1<<(val))),off);}while(0) ++#define cpm_set_bit(val,off) do{cpm_outl((cpm_inl(off) | (1<>= 2; n++; }; (n-1);}) ++#define TCCRDIV2(x) (TCCRDIV1((x)) << TCCRDIV_SFT2) ++ ++#define TESR_OSTEN1 (1 << 0) /* enable the counter1 in ost */ ++#define TESR_OSTEN2 (1 << 1) /* enable the counter2 in ost */ ++ ++#define TCR_OSTCLR1 (1 << 0) ++#define TCR_OSTCLR2 (1 << 1) ++ ++#define TMR_OSTM (1 << 0) /* ost comparison match interrupt mask */ ++ ++#define TFR_OSTM (1 << 0) /* Comparison match */ ++ ++#define ost_readl(reg) readl_relaxed(reg) ++#define ost_writel(reg, val) writel_relaxed(val, reg) ++#endif +diff --git a/arch/mips/xburst/soc-x1000/include/soc/sfc.h b/arch/mips/xburst/soc-x1000/include/soc/sfc.h +new file mode 100644 +index 000000000..42477ab48 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/include/soc/sfc.h +@@ -0,0 +1,152 @@ ++#ifndef __SFC_REGISTER_H ++#define __SFC_REGISTER_H ++ ++/* SFC register */ ++ ++#define SFC_GLB (0x0000) ++#define SFC_DEV_CONF (0x0004) ++#define SFC_DEV_STA_EXP (0x0008) ++#define SFC_DEV_STA_RT (0x000c) ++#define SFC_DEV_STA_MSK (0x0010) ++#define SFC_TRAN_CONF(n) (0x0014 + (n * 4)) ++#define SFC_TRAN_LEN (0x002c) ++#define SFC_DEV_ADDR(n) (0x0030 + (n * 4)) ++#define SFC_DEV_ADDR_PLUS(n) (0x0048 + (n * 4)) ++#define SFC_MEM_ADDR (0x0060) ++#define SFC_TRIG (0x0064) ++#define SFC_SR (0x0068) ++#define SFC_SCR (0x006c) ++#define SFC_INTC (0x0070) ++#define SFC_FSM (0x0074) ++#define SFC_CGE (0x0078) ++#define SFC_RM_DR (0x1000) ++ ++/* For SFC_GLB */ ++#define GLB_TRAN_DIR (1 << 13) ++#define GLB_TRAN_DIR_WRITE (1) ++#define GLB_TRAN_DIR_READ (0) ++#define GLB_THRESHOLD_OFFSET (7) ++#define GLB_THRESHOLD_MSK (0x3f << GLB_THRESHOLD_OFFSET) ++#define GLB_OP_MODE (1 << 6) ++#define SLAVE_MODE (0x0) ++#define DMA_MODE (0x1) ++#define GLB_PHASE_NUM_OFFSET (3) ++#define GLB_PHASE_NUM_MSK (0x7 << GLB_PHASE_NUM_OFFSET) ++#define GLB_WP_EN (1 << 2) ++#define GLB_BURST_MD_OFFSET (0) ++#define GLB_BURST_MD_MSK (0x3 << GLB_BURST_MD_OFFSET) ++ ++/* For SFC_DEV_CONF */ ++#define DEV_CONF_ONE_AND_HALF_CYCLE_DELAY (3) ++#define DEV_CONF_ONE_CYCLE_DELAY (2) ++#define DEV_CONF_HALF_CYCLE_DELAY (1) ++#define DEV_CONF_NO_DELAY (0) ++#define DEV_CONF_SMP_DELAY_OFFSET (16) ++#define DEV_CONF_SMP_DELAY_MSK (0x3 << DEV_CONF_SMP_DELAY_OFFSET) ++#define DEV_CONF_CMD_TYPE (0x1 << 15) ++#define DEV_CONF_STA_TYPE_OFFSET (13) ++#define DEV_CONF_STA_TYPE_MSK (0x1 << DEV_CONF_STA_TYPE_OFFSET) ++#define DEV_CONF_THOLD_OFFSET (11) ++#define DEV_CONF_THOLD_MSK (0x3 << DEV_CONF_THOLD_OFFSET) ++#define DEV_CONF_TSETUP_OFFSET (9) ++#define DEV_CONF_TSETUP_MSK (0x3 << DEV_CONF_TSETUP_OFFSET) ++#define DEV_CONF_TSH_OFFSET (5) ++#define DEV_CONF_TSH_MSK (0xf << DEV_CONF_TSH_OFFSET) ++#define DEV_CONF_CPHA (0x1 << 4) ++#define DEV_CONF_CPOL (0x1 << 3) ++#define DEV_CONF_CEDL (0x1 << 2) ++#define DEV_CONF_HOLDDL (0x1 << 1) ++#define DEV_CONF_WPDL (0x1 << 0) ++ ++/* For SFC_TRAN_CONF */ ++#define TRAN_CONF_TRAN_MODE_OFFSET (29) ++#define TRAN_CONF_TRAN_MODE_MSK (0x7) ++#define TRAN_CONF_ADDR_WIDTH_OFFSET (26) ++#define TRAN_CONF_ADDR_WIDTH_MSK (0x7 << ADDR_WIDTH_OFFSET) ++#define TRAN_CONF_POLLEN (1 << 25) ++#define TRAN_CONF_POLL_OFFSET (25) ++#define TRAN_CONF_CMDEN (1 << 24) ++#define TRAN_CONF_FMAT (1 << 23) ++#define TRAN_CONF_FMAT_OFFSET (23) ++#define TRAN_CONF_DMYBITS_OFFSET (17) ++#define TRAN_CONF_DMYBITS_MSK (0x3f << DMYBITS_OFFSET) ++#define TRAN_CONF_DATEEN (1 << 16) ++#define TRAN_CONF_DATEEN_OFFSET (16) ++#define TRAN_CONF_CMD_OFFSET (0) ++#define TRAN_CONF_CMD_MSK (0xffff << CMD_OFFSET) ++#define TRAN_CONF_CMD_LEN (1 << 15) ++ ++/* For SFC_TRIG */ ++#define TRIG_FLUSH (1 << 2) ++#define TRIG_STOP (1 << 1) ++#define TRIG_START (1 << 0) ++ ++/* For SFC_SCR */ ++#define CLR_END (1 << 4) ++#define CLR_TREQ (1 << 3) ++#define CLR_RREQ (1 << 2) ++#define CLR_OVER (1 << 1) ++#define CLR_UNDER (1 << 0) ++ ++/* For SFC_TRAN_CONFx */ ++#define TRAN_MODE_OFFSET (29) ++#define TRAN_MODE_MSK (0x7 << TRAN_MODE_OFFSET) ++#define TRAN_SPI_STANDARD (0x0) ++#define TRAN_SPI_DUAL (0x1 ) ++#define TRAN_SPI_QUAD (0x5 ) ++#define TRAN_SPI_IO_QUAD (0x6 ) ++ ++ ++#define ADDR_WIDTH_OFFSET (26) ++#define ADDR_WIDTH_MSK (0x7 << ADDR_WIDTH_OFFSET) ++#define POLLEN (1 << 25) ++#define CMDEN (1 << 24) ++#define FMAT (1 << 23) ++#define DMYBITS_OFFSET (17) ++#define DMYBITS_MSK (0x3f << DMYBITS_OFFSET) ++#define DATEEN (1 << 16) ++#define CMD_OFFSET (0) ++#define CMD_MSK (0xffff << CMD_OFFSET) ++ ++#define N_MAX 6 ++#define MAX_SEGS 128 ++ ++#define CHANNEL_0 0 ++#define CHANNEL_1 1 ++#define CHANNEL_2 2 ++#define CHANNEL_3 3 ++#define CHANNEL_4 4 ++#define CHANNEL_5 5 ++ ++#define ENABLE 1 ++#define DISABLE 0 ++ ++#define COM_CMD 1 // common cmd ++#define POLL_CMD 2 // the cmd will poll the status of flash,ext: read status ++ ++#define DMA_OPS 1 ++#define CPU_OPS 0 ++ ++#define TM_STD_SPI 0 ++#define TM_DI_DO_SPI 1 ++#define TM_DIO_SPI 2 ++#define TM_FULL_DIO_SPI 3 ++#define TM_QI_QO_SPI 5 ++#define TM_QIO_SPI 6 ++#define TM_FULL_QIO_SPI 7 ++ ++ ++#define DEFAULT_ADDRSIZE 3 ++ ++ ++#define THRESHOLD 32 ++ ++#define SFC_NOR_RATE 110 ++#define DEF_ADDR_LEN 3 ++#define DEF_TCHSH 5 ++#define DEF_TSLCH 5 ++#define DEF_TSHSL_R 20 ++#define DEF_TSHSL_W 50 ++ ++ ++#endif +diff --git a/arch/mips/xburst/soc-x1000/include/soc/tcsm_layout.h b/arch/mips/xburst/soc-x1000/include/soc/tcsm_layout.h +new file mode 100644 +index 000000000..19ba6667d +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/include/soc/tcsm_layout.h +@@ -0,0 +1,53 @@ ++#ifndef __TCSM_LAYOUT_H__ ++#define __TCSM_LAYOUT_H__ ++ ++/** ++ * |-------------| ++ * | BANK0 | ++ * |-------------| <--- SLEEP_TCSM_BOOTCODE_TEXT ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * |-------------| ++ * | VO DMA DESC | ++ * |_____________| <--- VOICE_TCSM_DMA_DESC ++ * ++ * ++ * |-------------| ++ * | BANK1 | ++ * |-------------| <--- VOICE_TCSM_DATA_BUF ++ * | | ++ * | | ++ * | ... | ++ * | VOICE DATA | ++ * | ... | ++ * | | ++ * | | ++ * |_____________| ++ * ++ */ ++ ++/* ++ * If you use the VOICE TRIGGER, ++ * and you change the VOICE_* and TCSM_BANK_LEN, ++ * while compiling wakeup module ++ */ ++#define SLEEP_TCSM_SPACE 0xb3422000 ++#define VOICE_TCSM_DATA_BUF 0xb3423000 ++#define TCSM_BANK_LEN 4096 ++ ++#define SLEEP_TCSM_BOOT_TEXT (SLEEP_TCSM_SPACE) ++ ++#define VOICE_TCSM_DMA_DESC_LEN 512 ++#define SLEEP_TCSM_SPACE_END (SLEEP_TCSM_SPACE + TCSM_BANK_LEN - VOICE_TCSM_DMA_DESC_LEN) ++#define VOICE_TCSM_DMA_DESC_ADDR SLEEP_TCSM_SPACE_END ++ ++#define SLEEP_TCSM_CPU_RESMUE_SP SLEEP_TCSM_SPACE_END - 4 ++ ++#define VOICE_TCSM_DATA_BUF_SIZE TCSM_BANK_LEN ++ ++#endif /* __TCSM_LAYOUT_H__ */ +diff --git a/arch/mips/xburst/soc-x1000/include/soc/tcu.h b/arch/mips/xburst/soc-x1000/include/soc/tcu.h +new file mode 100644 +index 000000000..a8982aae7 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/include/soc/tcu.h +@@ -0,0 +1,37 @@ ++#ifndef __TCU_H__ ++#define __TCU_H__ ++ ++#define WDT_TDR (0x00) /* rw, 32, 0x???????? */ ++#define WDT_TCER (0x04) /* rw, 32, 0x???????? */ ++#define WDT_TCNT (0x08) /* rw, 32, 0x???????? */ ++#define WDT_TCSR (0x0c) /* rw, 32, 0x???????? */ ++ ++#define TCU_TSTR (0xF0) /* Timer Status Register,Only Used In Tcu2 Mode */ ++#define TCU_TSTSR (0xF4) /* Timer Status Set Register */ ++#define TCU_TSTCR (0xF8) /* Timer Status Clear Register */ ++#define TCU_TSR (0x1C) /* Timer Stop Register */ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++#define TCU_TER (0x10) /* Timer Counter Enable Register */ ++#define TCU_TESR (0x14) /* Timer Counter Enable Set Register */ ++#define TCU_TECR (0x18) /* Timer Counter Enable Clear Register */ ++#define TCU_TFR (0x20) /* Timer Flag Register */ ++#define TCU_TFSR (0x24) /* Timer Flag Set Register */ ++#define TCU_TFCR (0x28) /* Timer Flag Clear Register */ ++#define TCU_TMR (0x30) /* Timer Mask Register */ ++#define TCU_TMSR (0x34) /* Timer Mask Set Register */ ++#define TCU_TMCR (0x38) /* Timer Mask Clear Register */ ++ ++#define CH_TDFR(n) (0x40 + (n)*0x10) /* Timer Data Full Reg */ ++#define CH_TDHR(n) (0x44 + (n)*0x10) /* Timer Data Half Reg */ ++#define CH_TCNT(n) (0x48 + (n)*0x10) /* Timer Counter Reg */ ++#define CH_TCSR(n) (0x4C + (n)*0x10) /* Timer Control Reg */ ++ ++#define TCSR_PWM_BYPASS (1 << 11) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_CNT_CLRZ (1 << 10) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_PWM_SD (1 << 9) /* shut down the pwm output only used in TCU1 mode */ ++#define TCSR_PWM_HIGH (1 << 8) /* selects an initial output level for pwm output */ ++#define TCSR_PWM_EN (1 << 7) /* pwm pin output enable */ ++#define TCSR_PWM_IN (1 << 6) /* pwm pin output enable */ ++ ++#endif /* __TCU_H__ */ +diff --git a/arch/mips/xburst/soc-x1000/include/war.h b/arch/mips/xburst/soc-x1000/include/war.h +new file mode 100644 +index 000000000..fd1ef3147 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/include/war.h +@@ -0,0 +1,27 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MACH_INGENIC_WAR_H__ ++#define __ASM_MACH_INGENIC_WAR_H__ ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 1 ++#define MIPS_BRIDGE_SYNC_WAR 1 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif ++ +diff --git a/arch/mips/xburst/soc-x1000/pm.c b/arch/mips/xburst/soc-x1000/pm.c +new file mode 100644 +index 000000000..539b80ff7 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/pm.c +@@ -0,0 +1,221 @@ ++/* ++ * linux/arch/mips/xburst/soc-m200/common/pm_p0.c ++ * ++ * M200 Power Management Routines ++ * Copyright (C) 2006 - 2012 Ingenic Semiconductor Inc. ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++extern long long save_goto(unsigned int); ++extern int restore_goto(void); ++ ++unsigned int pm_firmware_new[] ={ ++#include "core_sleep.hex" ++}; ++ ++void load_pm_firmware_new(unsigned int addr) ++{ ++ void (*func)(unsigned int addr,unsigned int to); ++ unsigned int firmware_size = sizeof(pm_firmware_new); ++ ++ if(firmware_size > TCSM_BANK_LEN * 1024) ++ printk("WARN: firmware_size %d bigger than" \ ++ "TCSM_BANK_LEN %d\n", firmware_size, TCSM_BANK_LEN * 1024); ++ ++ func = (void (*)(unsigned int,unsigned int))addr; ++ memcpy((void *)addr,pm_firmware_new,firmware_size); ++ func(addr,0); ++} ++struct sleep_param ++{ ++ unsigned int pm_core_enter; ++ unsigned char pmu_i2c_scl; //default 0xff ++ unsigned char pmu_i2c_sda; //default 0xff ++ unsigned char pmu_addr; //default 0xff ++ unsigned char pmu_reg; //default 0xff ++ unsigned char pmu_register_val; ++ ++ unsigned char pmu_pin; //default 0xff ++ unsigned char pmu_pin_func; //default 0xff ++ unsigned char uart_id; //default 0xff ++ ++ unsigned int prev_resume_pc; //ddr is self-reflash default 0xffffffff ++ unsigned int post_resume_pc; //ddr is ok. default 0xffffffff ++ unsigned int prev_sleep_pc; //after flush cache. default 0xffffffff ++ unsigned int post_sleep_pc; //before wait. default 0xffffffff ++ ++}; ++struct sleep_save_register ++{ ++ unsigned int lcr; ++ unsigned int opcr; ++ unsigned int clkgr; ++ unsigned int sleep_voice_enable; ++ unsigned int ddr_training_space[20]; ++ suspend_state_t pm_state; ++}; ++ ++static struct sleep_save_register s_reg; ++struct sleep_param *sleep_param; ++ ++static int soc_pm_enter(suspend_state_t state) ++{ ++ unsigned int lcr,opcr, clkgr; ++ ++ /** ++ sleep code use PDMA_TCSM, so must enable pdma and nemc ++ */ ++ s_reg.clkgr = clkgr = cpm_inl(CPM_CLKGR); ++ clkgr &= ~(1 << 21); ++ cpm_outl(clkgr, CPM_CLKGR); ++ ++ memcpy(&s_reg.ddr_training_space,(void*)0x80000000,sizeof(s_reg.ddr_training_space)); ++ s_reg.opcr = cpm_inl(CPM_OPCR); ++ s_reg.lcr = cpm_inl(CPM_LCR); ++ ++ load_pm_firmware_new(SLEEP_TCSM_SPACE); ++ sleep_param = (struct sleep_param *)SLEEP_TCSM_SPACE; ++ ++ sleep_param->post_resume_pc = (unsigned int)restore_goto; ++ sleep_param->uart_id = -1; ++ /* ++ * set OPCR. ++ */ ++ opcr = s_reg.opcr; ++ lcr = s_reg.lcr; ++ ++ opcr &= ~((1 << 25) | (1 << 22) | (0xfff << 8) | (1 << 4) | (1 << 3) | (1 << 2)); ++ opcr |= (1 << 31) | (1 << 30) | (1 << 25) | (0xfff << 8) | (1 << 4) | (1 << 3); ++ lcr &= ~3; ++ ++#ifdef CONFIG_RTC_DRV_INGENIC ++ opcr &= ~((1 << 4) | (1 << 2)); ++ opcr |= (1 << 2); ++#endif ++ ++ if(s_reg.pm_state == PM_SUSPEND_STANDBY) { ++ opcr &= ~((1 << 31) | (1 << 30)); ++ } else { ++ lcr |= LCR_LPM_SLEEP; ++ } ++ cpm_outl(opcr,CPM_OPCR); ++ cpm_outl(lcr,CPM_LCR); ++ ++ lcr = cpm_inl(CPM_CLKGR); ++ lcr &= ~1; /* CPM_CLKGR bit0 NEMC: must not gate NEMC clock when sleeping */ ++ cpm_outl(lcr,CPM_CLKGR); ++ ++ printk("#####lcr:%08x\n", cpm_inl(CPM_LCR)); ++ printk("#####gate:%08x\n", cpm_inl(CPM_CLKGR)); ++ printk("#####opcr:%08x\n", cpm_inl(CPM_OPCR)); ++ printk("#####INT_MASK0:%08x\n", *(volatile unsigned int*)(0xB0001004)); ++ printk("#####INT_MASK1:%08x\n", *(volatile unsigned int*)(0xB0001024)); ++ printk("#####INT_PEND0:%08x\n", *(volatile unsigned int*)(0xB0001010)); ++ printk("#####INT_PEND1:%08x\n", *(volatile unsigned int*)(0xB0001030)); ++ ++ mb(); ++ save_goto((unsigned int)sleep_param->pm_core_enter); ++ mb(); ++ ++ memcpy((void*)0x80000000,&s_reg.ddr_training_space,sizeof(s_reg.ddr_training_space)); ++ dma_cache_wback_inv(0x80000000,sizeof(s_reg.ddr_training_space)); ++ cpm_outl(s_reg.lcr,CPM_LCR); ++ cpm_outl(s_reg.opcr,CPM_OPCR); ++ cpm_outl(s_reg.clkgr, CPM_CLKGR); ++ ++ return 0; ++} ++ ++static int soc_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++static void soc_finish(void) ++{ ++ s_reg.pm_state = 0; ++} ++static int soc_begin(suspend_state_t state) ++{ ++ s_reg.pm_state = state; ++ if(s_reg.pm_state == PM_SUSPEND_STANDBY) { ++ jz_notifier_call(NOTEFY_PROI_HIGH, JZ_PM_SUSPEND_STANDBY, &s_reg.pm_state); ++ } ++ return 0; ++} ++ ++/* ++ * Initialize power interface ++ */ ++struct platform_suspend_ops pm_ops = { ++ .valid = soc_valid, ++ .begin = soc_begin, ++ .enter = soc_pm_enter, ++ .end = soc_finish, ++}; ++ ++int __init soc_pm_init(void) ++{ ++ volatile unsigned int lcr,opcr; ++ ++ suspend_set_ops(&pm_ops); ++ ++ /* init opcr and lcr for idle */ ++ lcr = cpm_inl(CPM_LCR); ++ lcr &= ~(0x3); /* LCR.SLEEP.DS=1'b0,LCR.LPM=2'b00*/ ++ lcr |= 0xff << 8; /* power stable time */ ++ cpm_outl(lcr,CPM_LCR); ++ ++ opcr = cpm_inl(CPM_OPCR); ++ opcr |= 0xff << 8; /* EXCLK stable time */ ++ opcr &= ~(1 << 4); /* EXCLK oscillator is disabled in Sleep mode */ ++ cpm_outl(opcr,CPM_OPCR); ++ ++ /* sysfs */ ++ return 0; ++} ++ ++arch_initcall(soc_pm_init); +diff --git a/arch/mips/xburst/soc-x1000/regs_save_restore.S b/arch/mips/xburst/soc-x1000/regs_save_restore.S +new file mode 100644 +index 000000000..e4d013ccc +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/regs_save_restore.S +@@ -0,0 +1,174 @@ ++#include ++#include ++ ++#define CP0_CONTEXT $4,0 ++#define CP0_PAGEMASK $5,0 ++#define CP0_TLB_SPEC $5,4 ++#define CP0_STATUS $12,0 ++#define CP0_INTCTL $12,1 ++#define CP0_CAUSE $13,0 ++#define CP0_EBASE $15,1 ++#define CP0_CONFIG $16,0 ++#define CP0_CONFIG1 $16,1 ++#define CP0_CONFIG2 $16,2 ++#define CP0_CONFIG3 $16,3 ++#define CP0_CONFIG7 $16,7 ++#define CP0_LLADDR $17,0 ++#define PMON_CSR $17,7 ++#define PMON_HIGH $17,4 ++#define PMON_LC $17,5 ++#define PMON_RC $17,6 ++#define CP0_WATCHLo $18,0 ++#define CP0_WATCHHI $19,0 ++#define CP0_ERRCTL $26,0 ++ ++ .data ++ .global _regs_stack ++_regs_stack: ++ .align 5 ++ .space 128,0 ++ ++ .text ++ .global save_goto ++ .align 2 ++ .ent save_goto,0 ++ LEAF(save_goto) ++save_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sw s0,0(k0) ++ sw s1,4(k0) ++ sw s2,8(k0) ++ sw s3,12(k0) ++ sw s4,16(k0) ++ sw s5,20(k0) ++ sw s6,24(k0) ++ sw s7,28(k0) ++ sw gp,32(k0) ++ sw sp,36(k0) ++ sw fp,40(k0) ++ sw ra,44(k0) ++ ++ mfc0 k1,CP0_PAGEMASK ++ sw k1,48(k0) ++ mfc0 k1,CP0_TLB_SPEC ++ sw k1,52(k0) ++ mfc0 k1,CP0_STATUS ++ sw k1,56(k0) ++ mfc0 k1,CP0_INTCTL ++ sw k1,60(k0) ++ mfc0 k1,CP0_CAUSE ++ sw k1,64(k0) ++ mfc0 k1,CP0_EBASE ++ sw k1,68(k0) ++ mfc0 k1,CP0_CONFIG ++ sw k1,72(k0) ++ mfc0 k1,CP0_CONFIG1 ++ sw k1,76(k0) ++ mfc0 k1,CP0_CONFIG2 ++ sw k1,80(k0) ++ mfc0 k1,CP0_CONFIG3 ++ sw k1,84(k0) ++ mfc0 k1,CP0_CONFIG7 ++ sw k1,88(k0) ++ mfc0 k1,CP0_LLADDR ++ sw k1,92(k0) ++ mfc0 k1,PMON_CSR ++ sw k1,96(k0) ++ mfc0 k1,PMON_HIGH ++ sw k1,100(k0) ++ mfc0 k1,PMON_LC ++ sw k1,104(k0) ++ mfc0 k1,PMON_RC ++ sw k1,108(k0) ++ mfc0 k1,CP0_WATCHLo ++ sw k1,112(k0) ++ mfc0 k1,CP0_WATCHHI ++ sw k1,116(k0) ++ mfc0 k1,CP0_ERRCTL ++ sw k1,120(k0) ++ mfc0 k1,CP0_CONTEXT ++ sw k1,124(k0) ++ ++ jr a0 ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(save_goto) ++ .text ++ .global restore_goto ++ .align 2 ++ .ent restore_goto,0 ++ LEAF(restore_goto) ++restore_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ lw s0,0(k0) ++ lw s1,4(k0) ++ lw s2,8(k0) ++ lw s3,12(k0) ++ lw s4,16(k0) ++ lw s5,20(k0) ++ lw s6,24(k0) ++ lw s7,28(k0) ++ lw gp,32(k0) ++ lw sp,36(k0) ++ lw fp,40(k0) ++ lw ra,44(k0) ++ ++ lw k1,48(k0) ++ mtc0 k1,CP0_PAGEMASK ++ lw k1,52(k0) ++ mtc0 k1,CP0_TLB_SPEC ++ lw k1,56(k0) ++ mtc0 k1,CP0_STATUS ++ lw k1,60(k0) ++ mtc0 k1,CP0_INTCTL ++ lw k1,64(k0) ++ mtc0 k1,CP0_CAUSE ++ lw k1,68(k0) ++ mtc0 k1,CP0_EBASE ++ lw k1,72(k0) ++ mtc0 k1,CP0_CONFIG ++ lw k1,76(k0) ++ mtc0 k1,CP0_CONFIG1 ++ lw k1,80(k0) ++ mtc0 k1,CP0_CONFIG2 ++ lw k1,84(k0) ++ mtc0 k1,CP0_CONFIG3 ++ lw k1,88(k0) ++ mtc0 k1,CP0_CONFIG7 ++ lw k1,92(k0) ++ mtc0 k1,CP0_LLADDR ++ lw k1,96(k0) ++ mtc0 k1,PMON_CSR ++ lw k1,100(k0) ++ mtc0 k1,PMON_HIGH ++ lw k1,104(k0) ++ mtc0 k1,PMON_LC ++ lw k1,108(k0) ++ mtc0 k1,PMON_RC ++ lw k1,112(k0) ++ mtc0 k1,CP0_WATCHLo ++ lw k1,116(k0) ++ mtc0 k1,CP0_WATCHHI ++ lw k1,120(k0) ++ mtc0 k1,CP0_ERRCTL ++ lw k1,124(k0) ++ mtc0 k1,CP0_CONTEXT ++ ++ jr ra ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(restore_goto) +diff --git a/arch/mips/xburst/soc-x1000/setup.c b/arch/mips/xburst/soc-x1000/setup.c +new file mode 100644 +index 000000000..44a3b73b9 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/setup.c +@@ -0,0 +1,80 @@ ++/* ++ * INGENIC SOC Setup ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++extern void *get_fdt_addr(void); ++extern void __init soc_is_x1000e(void); ++ ++void __init plat_mem_setup(void) ++{ ++ void __iomem *cpm_iobase = (void __iomem *)CKSEG1ADDR(CPM_IOBASE); ++ ++ /* ingenic mips cpu special */ ++ __asm__ ( ++ "li $2, 0xa9000000 \n\t" ++ "mtc0 $2, $5, 4 \n\t" ++ "nop \n\t" ++ ::"r"(2)); ++ ++ set_io_port_base(IO_BASE); ++ /*Not have ioport*/ ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0x00000000; ++ iomem_resource.start = 0x10000000; ++ iomem_resource.end = 0x1fffffff; ++ ++ /*x1000 cpu special*/ ++ writel( 0, cpm_iobase + CPM_PSWC0ST); ++ writel(16, cpm_iobase + CPM_PSWC1ST); ++ writel(24, cpm_iobase + CPM_PSWC2ST); ++ writel( 8, cpm_iobase + CPM_PSWC3ST); ++ ++ __dt_setup_arch(get_fdt_addr()); ++ ++ early_init_fdt_scan_reserved_mem(); ++ ++ soc_is_x1000e(); ++ ++ return; ++} ++ ++void __init device_tree_init(void) ++{ ++ unflatten_and_copy_device_tree(); ++} ++ ++static int __init plat_of_populate(void) ++{ ++ of_platform_default_populate(NULL, NULL, NULL); ++ return 0; ++} ++arch_initcall(plat_of_populate); ++ ++void __init plat_time_init(void) ++{ ++ of_clk_init(NULL); ++ ++ timer_probe(); ++} ++ ++void __init arch_init_irq(void) { ++ ++ irqchip_init(); ++} +diff --git a/arch/mips/xburst/soc-x1000/socid.c b/arch/mips/xburst/soc-x1000/socid.c +new file mode 100644 +index 000000000..72698e4ef +--- /dev/null ++++ b/arch/mips/xburst/soc-x1000/socid.c +@@ -0,0 +1,110 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CLKGATE 0x20 ++#define CTRL_OFF 0x0 ++#define STATUS_OFF 0x8 ++#define DATA0_OFF 0xc ++ ++enum socid { ++ X1000 = 0xff00, ++ X1000E = 0xff01, ++ X1500 = 0xff02, ++ X1000_NEW = 0xff08, ++ X1000E_NEW = 0xff09, ++ X1500_NEW = 0xff0a, ++}; ++ ++static int read_socid(void) ++{ ++ void __iomem *efuse_iobase = (void __iomem *)CKSEG1ADDR(EFUSE_IOBASE); ++ void __iomem *cpm_iobase = (void __iomem *)CKSEG1ADDR(CPM_IOBASE); ++ uint32_t val = 0, timeout = 10; ++ uint32_t clkgat, clk_efuse_enable = 0; ++ int ret = 0; ++ ++ clkgat = readl(cpm_iobase + CLKGATE); ++ if(clkgat & (0x1 << 1)) { ++ clk_efuse_enable = 1; ++ writel(clkgat & ~(0x1 << 1), cpm_iobase + CLKGATE); ++ } ++ ++ writel(0, efuse_iobase + STATUS_OFF); ++ ++ val = 0x3c << 21 | 1 << 16 | 1; ++ writel(val, efuse_iobase + CTRL_OFF); ++ ++ while(!(readl(efuse_iobase + STATUS_OFF) & 1)) { ++ timeout --; ++ if(!timeout) { ++ ret = -EBUSY; ++ goto efuse_fail; ++ } ++ } ++ ret = readl(efuse_iobase + DATA0_OFF); ++efuse_fail: ++ if(clk_efuse_enable) ++ writel(clkgat, cpm_iobase + CLKGATE); ++ return ret; ++} ++ ++static int __init check_socid(void) { ++ ++ int socid = read_socid(); ++ if (socid < 0) { ++ pr_err("socid: efuse busy !\n"); ++ return -EBUSY; ++ } ++ switch(socid) { ++ case X1000: ++ case X1500: ++ case X1000E: ++ case X1000_NEW: ++ case X1000E_NEW: ++ case X1500_NEW: ++ case 0: ++ break; ++ default: ++ pr_err("socid: unknown x1000 socid !\n"); ++ return -ENODEV; ++ } ++ ++ return socid; ++} ++ ++static void __init ddr_param_change(int ddr_size) ++{ ++ int off; ++ ++ off = strcspn(arcs_cmdline, "M@"); ++ switch(ddr_size) { ++ case 64: ++ arcs_cmdline[off - 2] = '6'; ++ arcs_cmdline[off - 1] = '4'; ++ break; ++ case 256: ++ arcs_cmdline[off - 3] = '2'; ++ arcs_cmdline[off - 2] = '5'; ++ arcs_cmdline[off - 1] = '6'; ++ break; ++ default: ++ return; ++ } ++} ++ ++void __init soc_is_x1000e(void) ++{ ++ int socid; ++ ++ socid = check_socid(); ++ if(socid == X1000E || socid == X1000E_NEW){ ++ ddr_param_change(64); ++ } ++} ++ ++MODULE_DESCRIPTION("x1000 socid driver special used by itself"); +diff --git a/arch/mips/xburst/soc-x1600/Kconfig.DT b/arch/mips/xburst/soc-x1600/Kconfig.DT +new file mode 100644 +index 000000000..f05c35c30 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/Kconfig.DT +@@ -0,0 +1,19 @@ ++choice ++ prompt "device tree select for X1600 boards" ++ default DT_HALLEY6_V10 ++ depends on SOC_X1600 ++ ++config DT_X1600_MODULE ++ bool "x1600 module base" ++ ++config DT_PANDA_V10 ++ bool "x1600 panda v10" ++ ++config DT_HALLEY6_V10 ++ bool "x1600 halley6 v10" ++ ++config DT_HALLEY6_V20 ++ bool "x1600 halley6 v20" ++ ++endchoice ++ +diff --git a/arch/mips/xburst/soc-x1600/Makefile b/arch/mips/xburst/soc-x1600/Makefile +new file mode 100644 +index 000000000..a25ee9e2e +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/Makefile +@@ -0,0 +1,6 @@ ++obj-y += setup.o ++obj-y += libdmmu.o ++obj-y += regs_save_restore.o ++obj-y += gpio.o ++obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ++obj-$(CONFIG_PM) += pm.o +diff --git a/arch/mips/xburst/soc-x1600/early_printk.c b/arch/mips/xburst/soc-x1600/early_printk.c +new file mode 100644 +index 000000000..e2d76bce2 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/early_printk.c +@@ -0,0 +1,99 @@ ++/* ++ * INGENIC SOC serial routines for early_printk. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#define UART_OFF (0x1000) ++ ++static void check_uart(char c); ++ ++volatile u32 *uart_base; ++typedef void (*putchar_f_t)(char); ++ ++static putchar_f_t putchar_f = check_uart; ++ ++static void putchar(char ch) ++{ ++ int timeout = 10000; ++ volatile u32 *base = uart_base; ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ((base[UART_LSR] & (UART_LSR_THRE | UART_LSR_TEMT)) ++ != (UART_LSR_THRE | UART_LSR_TEMT) && timeout--) ++ ; ++ base[UART_TX] = (u8)ch; ++} ++ ++static void putchar_dummy(char ch) ++{ ++ return; ++} ++ ++static void check_uart(char c) ++{ ++ /* We Couldn't use ioremap() here */ ++ volatile u32 *base = (volatile u32*)CKSEG1ADDR(UART0_IOBASE); ++ int i; ++ for(i=0; i < 4; i++) { ++ if(base[UART_LCR]) ++ break; ++ base += (UART_OFF/sizeof(u32)); ++ } ++ ++ if(i < 4) { ++ uart_base = base; ++ putchar_f = putchar; ++ putchar_f(c); ++ } else { ++ putchar_f = putchar_dummy; ++ } ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ putchar_f(c); ++} ++ ++static int __init early_parse_console(char *p) ++{ ++ unsigned char *param = "null"; ++ ++ if(strstr(p, param)){ ++ putchar_f = putchar_dummy; ++ } ++ return 0; ++} ++early_param("console", early_parse_console); ++ ++#if 0 ++/* for debug */ ++void prom_putstr(char *s) ++{ ++ while(*s) { ++ if(*s == '\n') ++ putchar_f('\r'); ++ putchar_f(*s); ++ s++; ++ } ++} ++ ++static char pbuffer[4096]; ++void prom_printk(const char *fmt, ...) { ++ va_list args; ++ ++ va_start(args, fmt); ++ vsnprintf(pbuffer, 4096, fmt, args); ++ va_end(args); ++ ++ prom_putstr(pbuffer); ++} ++#endif ++ +diff --git a/arch/mips/xburst/soc-x1600/gpio.c b/arch/mips/xburst/soc-x1600/gpio.c +new file mode 100644 +index 000000000..b2437b9c0 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/gpio.c +@@ -0,0 +1,130 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#define GPIO_PORT_OFF 0x100 ++#define GPIO_SHADOW_OFF 0x700 ++ ++#define PXPIN 0x00 /* PIN Level Register */ ++#define PXINT 0x10 /* Port Interrupt Register */ ++#define PXINTS 0x14 /* Port Interrupt Set Register */ ++#define PXINTC 0x18 /* Port Interrupt Clear Register */ ++#define PXMSK 0x20 /* Port Interrupt Mask Reg */ ++#define PXMSKS 0x24 /* Port Interrupt Mask Set Reg */ ++#define PXMSKC 0x28 /* Port Interrupt Mask Clear Reg */ ++#define PXPAT1 0x30 /* Port Pattern 1 Register. */ ++#define PXPAT1S 0x34 /* Port Pattern 1 Set Register. */ ++#define PXPAT1C 0x38 /* Port Pattern 1 Clear Register. */ ++#define PXPAT0 0x40 /* Port Pattern 0 Register */ ++#define PXPAT0S 0x44 /* Port Pattern 0 Set Register */ ++#define PXPAT0C 0x48 /* Port Pattern 0 Clear Register */ ++#define PXFLG 0x50 /* Port Flag Register */ ++#define PXFLGC 0x58 /* Port Flag clear Register */ ++#define PXDEG 0x70 /* Port Dual Edge Register */ ++#define PXDEGS 0x74 /* Port Dual Edge Set Register */ ++#define PXDEGC 0x78 /* Port Dual Edge Clear Register */ ++#define PXPEN 0x80 /* Port Pull Enable Register */ ++#define PXPENS 0x84 /* Port Pull Enable Set Register */ ++#define PXPENC 0x88 /* Port Pull Enable Clear Register */ ++ ++#define PZGID2LD 0xF0 /* GPIOZ Group ID to load */ ++ ++#define SHADOW 4 ++ ++#define GPIO_FUNC_FLAG 0x0100 ++#define GPIO_FUNC_OFFSET 0 ++#define GPIO_FUNC_MASK 0x01ff ++ ++#define GPIO_PULL_FLAG 0x8000 ++#define GPIO_PULL_OFFSET 13 ++#define GPIO_PULL_MASK 0xe000 ++ ++static const unsigned long gpiobase[] = { ++ [0] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 0 * GPIO_PORT_OFF), ++ [1] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 1 * GPIO_PORT_OFF), ++ [2] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 2 * GPIO_PORT_OFF), ++ [3] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 3 * GPIO_PORT_OFF), ++ ++ [SHADOW] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + GPIO_SHADOW_OFF), ++}; ++ ++#define GPIO_ADDR(port, reg) ((volatile unsigned long *)(gpiobase[port] + reg)) ++ ++static inline void gpio_write(int port, unsigned int reg, int val) ++{ ++ *GPIO_ADDR(port, reg) = val; ++} ++ ++static inline unsigned int gpio_read(int port, unsigned int reg) ++{ ++ return *GPIO_ADDR(port, reg); ++} ++ ++static void hal_gpio_port_set_func(enum gpio_port port, unsigned int pins, enum gpio_function func) ++{ ++ /* func option */ ++ if (func & GPIO_FUNC_FLAG) { ++ /* No Shadows registers for EDG, set registers directly */ ++ if (func & 0x10) ++ gpio_write(port, PXDEGS, pins); ++ else ++ gpio_write(port, PXDEGC, pins); ++ ++ ++ if (func & 0x8) ++ gpio_write(SHADOW, PXINTS, pins); ++ else ++ gpio_write(SHADOW, PXINTC, pins); ++ ++ if (func & 0x4) ++ gpio_write(SHADOW, PXMSKS, pins); ++ else ++ gpio_write(SHADOW, PXMSKC, pins); ++ ++ if (func & 0x2) ++ gpio_write(SHADOW, PXPAT1S, pins); ++ else ++ gpio_write(SHADOW, PXPAT1C, pins); ++ ++ if (func & 0x1) ++ gpio_write(SHADOW, PXPAT0S, pins); ++ else ++ gpio_write(SHADOW, PXPAT0C, pins); ++ ++ /* configure PzGID2LD to specify which port group to load */ ++ gpio_write(SHADOW, PZGID2LD, port); ++ } ++ ++ /* pull option */ ++ if (func & GPIO_PULL_FLAG) { ++ if (func & 0x2000) ++ gpio_write(port, PXPENS, pins); ++ else ++ gpio_write(port, PXPENC, pins); ++ } ++ ++} ++ ++unsigned long ingenic_pinctrl_lock(int port); ++void ingenic_pinctrl_unlock(int port, unsigned long flags); ++ ++int jzgpio_set_func(int port, enum gpio_function func, unsigned long pins) ++{ ++ unsigned long flags; ++ ++ if (port < 0 || port > 3) { ++ printk(KERN_ERR "gpio: invalid gpio port for x1600: %d\n", port); ++ return -EINVAL; ++ } ++ ++ flags = ingenic_pinctrl_lock(port); ++ ++ hal_gpio_port_set_func(port, pins, func); ++ ++ ingenic_pinctrl_unlock(port, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL(jzgpio_set_func); +diff --git a/arch/mips/xburst/soc-x1600/include/cpu-feature-overrides.h b/arch/mips/xburst/soc-x1600/include/cpu-feature-overrides.h +new file mode 100644 +index 000000000..b33cfa6b7 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/cpu-feature-overrides.h +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++ ++#define cpu_dcache_size() (16 * 1024) ++#define cpu_dcache_ways() 8 ++#define cpu_dcache_line_size() 32 ++#define cpu_icache_size() (16 * 1024) ++#define cpu_icache_ways() 8 ++#define cpu_icache_line_size() 32 ++#define cpu_has_tlb 1 ++#define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_4k_cache 1 ++#define cpu_has_tx39_cache 0 ++#define cpu_has_fpu 1 ++#define cpu_has_32fpr 1 ++#define cpu_has_counter 0 ++#define cpu_has_watch 1 ++#define cpu_has_divec 1 ++#define cpu_has_vce 0 ++#define cpu_has_cache_cdex_p 0 ++#define cpu_has_cache_cdex_s 0 ++#define cpu_has_prefetch 1 ++#define cpu_has_mcheck 1 ++#define cpu_has_ejtag 1 ++#define cpu_has_llsc 1 ++#define cpu_has_mips16 0 ++#define cpu_has_mdmx 0 ++#define cpu_has_mips3d 0 ++#define cpu_has_smartmips 0 ++#define cpu_has_vtag_icache 0 ++#define cpu_has_dc_aliases 0 ++#define cpu_has_ic_fills_f_dc 0 ++#define cpu_has_pindexed_dcache 0 ++#define cpu_icache_snoops_remote_store 0 ++#define cpu_has_mips32r1 0 ++#define cpu_has_mips32r2 1 ++#define cpu_has_mips64r1 0 ++#define cpu_has_mips64r2 0 ++#define cpu_has_dsp 0 ++#define cpu_has_mipsmt 0 ++#define cpu_has_userlocal 0 ++#define cpu_has_nofpuex 0 ++#define cpu_has_64bits 0 ++#define cpu_has_64bit_zero_reg 0 ++#define cpu_has_vint 0 ++#define cpu_has_veic 0 ++#define cpu_has_inclusive_pcaches 0 ++#define kernel_uses_smartmips_rixi 1 ++#define cpu_has_mxu 0 ++#endif +diff --git a/arch/mips/xburst/soc-x1600/include/irq.h b/arch/mips/xburst/soc-x1600/include/irq.h +new file mode 100644 +index 000000000..c89c83538 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/irq.h +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (C) 2010 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_IRQ_H__ ++#define __ASM_MACH_INGENIC_IRQ_H__ ++ ++#include ++ ++/* IRQ for MIPS CPU */ ++//#define MIPS_CPU_IRQ_BASE 0 ++#define MIPS_CPU_IRQ(x) (MIPS_CPU_IRQ_BASE + (x)) ++ ++#define XBURST_INT MIPS_CPU_IRQ(2) ++#define XBURST_SYS_OST MIPS_CPU_IRQ(3) ++ ++#define MIPS_CPU_IRQS (MIPS_CPU_IRQ(7) + 1 - MIPS_CPU_IRQ_BASE) ++#define XBURST_SOC_IRQ_BASE MIPS_CPU_IRQS ++ ++#define INTC_CHIP_NUM 2 ++ ++#define TCU_NR_IRQS (8) ++ ++#ifndef NR_IRQS ++#define NR_IRQS (200) ++#endif ++ ++#endif ++ +diff --git a/arch/mips/xburst/soc-x1600/include/libdmmu.h b/arch/mips/xburst/soc-x1600/include/libdmmu.h +new file mode 100644 +index 000000000..6e0fbdb42 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/libdmmu.h +@@ -0,0 +1,30 @@ ++#ifndef _LIBDMMU_ ++#define _LIBDMMU_ ++ ++#include ++ ++ ++struct dmmu_mm_ops { ++ int (*mm_release)(void *data); ++}; ++ ++struct dmmu_mm_notifier { ++ ++ struct device *dev; ++ void *data; ++ struct list_head list; ++ ++ struct dmmu_mm_ops *ops; ++}; ++ ++int dmmu_register_mm_notifier(struct dmmu_mm_notifier *dmn); ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len); ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len); ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len); ++int dmmu_unmap_all(struct device *dev); ++void dmmu_dump_vaddr(unsigned long vaddr); ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode); ++int dmmu_dump_map(unsigned long vaddr); ++ ++#endif +diff --git a/arch/mips/xburst/soc-x1600/include/soc/base.h b/arch/mips/xburst/soc-x1600/include/soc/base.h +new file mode 100644 +index 000000000..ae3b9c28c +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/soc/base.h +@@ -0,0 +1,66 @@ ++ ++#ifndef __JZSOC_SOC_DEV_H__ ++#define __JZSOC_SOC_DEV_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 /* 64KB, AHB Bus Aribtier */ ++#define DDR_PHY_IOBASE 0x13011000 /* 4KB, DDR PHY */ ++#define DDRC_H0_IOBASE 0x13012000 /* 4KB, DDR Controller Registers@ASHB0 */ ++#define DPU_IOBASE 0x13050000 /* 64KB, LCD Controller */ ++#define CIM_IOBASE 0x13060000 /* 64KB, Camera Interface Module */ ++ ++ ++/* AHB2 Bus Devices Base */ ++#define HARB2_IOBASE 0x13400000 /* 64KB, AHB Bus Arbiter */ ++#define NEMC_IOBASE 0x13410000 /* 64KB, External Normal Memory/Boot ROM/OTP Controller */ ++#define PDMA_IOBASE 0x13420000 /* 64KB, Programmable DMA Controller */ ++#define AES_IOBASE 0x13430000 /* 64KB, AES */ ++#define SFC_IOBASE 0x13440000 /* 64KB, SPI Flash Controller */ ++#define MSC0_IOBASE 0x13450000 /* 64KB, MMC SD Controller0 */ ++#define MSC1_IOBASE 0x13460000 /* 64KB, MMC SD Controller1 */ ++#define HASH_IOBASE 0x13470000 /* 64KB, HASH */ ++#define MAC_IOBASE 0x134b0000 /* 64KB, GMAC/MAC */ ++#define PWM_IOBASE 0x134c0000 /* 64KB, PWM */ ++#define OTG_IOBASE 0x13500000 /* 256KB, OTG2.0 Controller */ ++#define EFUSE_IOBASE 0x13540000 /* 64KB, EFUSE */ ++#define CDBUS_IOBASE 0x13550000 /* 64KB, CDBUS */ ++#define CAN0_IOBASE 0x13560000 /* 64KB, CAN0 */ ++#define CAN1_IOBASE 0x13570000 /* 64KB, CAN0 */ ++#define INTC_IOBASE 0x10001000 /* Interrupt Controller */ ++ ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 /* 4KB, Clocks and Power Manager */ ++#define TCU_IOBASE 0x10002000 /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++#define WDT_IOBASE TCU_IOBASE /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++#define RTC_IOBASE 0x10003000 /* 4KB, Real-Time Clock */ ++#define GPIO_IOBASE 0x10010000 /* 4KB, General-Purpose I/O */ ++#define UART0_IOBASE 0x10030000 /* 4KB, UART0 Controller */ ++#define UART1_IOBASE 0x10031000 /* 4KB, UART1 Controller */ ++#define UART2_IOBASE 0x10032000 /* 4KB, UART2 Controller */ ++#define UART3_IOBASE 0x10033000 /* 4KB, UART3 Controller */ ++#define AIC_IOBASE 0x10079000 /* 4KB, Audio interface Controller */ ++#define SSI0_IOBASE 0x10043000 /* 4KB, Synchronous Serial Interface */ ++#define SSI_SLV0_IOBASE 0x10045000 /* 4KB, Synchronous Serial Interface slave */ ++#define I2C0_IOBASE 0x10050000 /* 4KB, I2C 0 Bus Interface */ ++#define I2C1_IOBASE 0x10051000 /* 4KB, I2C 1 Bus Interface */ ++#define SADC_IOBASE 0x10070000 /* 4KB, */ ++#define DTRNG_IOBASE 0x10072000 /* 4KB, */ ++#define MIPI_CSI_IOBASE 0x10073000 /* 4KB, */ ++#define MIPI_PHY_IOBASE 0x10076000 /* 4KB, */ ++#define USB_PHY_IOBASE 0x10078000 /* 4KB, */ ++ ++ ++/* Static Memory Base Address */ ++#define NEMC_CS1_IOBASE 0X1b000000 ++#define NEMC_CS2_IOBASE 0X1a000000 ++ ++#define OST_IOBASE 0x12000000 ++ ++#define DDRC_BASE 0xb34f0000 ++#endif ++ +diff --git a/arch/mips/xburst/soc-x1600/include/soc/cache.h b/arch/mips/xburst/soc-x1600/include/soc/cache.h +new file mode 100644 +index 000000000..350fe51fa +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/soc/cache.h +@@ -0,0 +1,95 @@ ++#ifndef __CHIP_CACHE_H__ ++#define __CHIP_CACHE_H__ ++#include ++#define cache_prefetch(label,size) \ ++do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&label + size) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set mips32\n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set mips32\n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++} \ ++while(0) ++ ++#define K0BASE KSEG0 ++#define CFG_DCACHE_SIZE 16384 ++#define CFG_ICACHE_SIZE 16384 ++#define CFG_CACHELINE_SIZE 32 ++ ++static inline void __jz_flush_cache_all(void) ++{ ++ register unsigned long addr; ++ /* Clear CP0 TagLo */ ++ asm volatile ("mtc0 $0, $28\n\t"); ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Writeback_Inv_D), "r"(addr)); ++ } ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ /* invalidate BTB */ ++ asm volatile ( ++ ".set mips32\n\t" ++ " mfc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ " ori $26, 2\n\t" ++ " mtc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ ".set mips32\n\t" ++ ); ++ asm volatile ("sync\n\t" ++ "lw $0,0(%0)" ++ ::"r" (0xa0000000)); ++ ++} ++ ++static inline void __jz_cache_init(void) ++{ ++ register unsigned long addr; ++ asm volatile ("mtc0 $0, $28\n\t"::); ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_D), "r"(addr)); ++ } ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Store_Tag_I), "r"(addr)); ++ } ++ /* invalidate BTB */ ++ asm volatile ( ".set mips32\n\t" ++ " mfc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ " ori $26, 2\n\t" ++ " mtc0 $26, $16, 7\n\t" ++ " nop\n\t" ++ "nop\n\t" ++ ".set mips32\n\t" ++ ); ++} ++ ++ ++#endif /* __CHIP_CACHE_H__ */ +diff --git a/arch/mips/xburst/soc-x1600/include/soc/cpm.h b/arch/mips/xburst/soc-x1600/include/soc/cpm.h +new file mode 100644 +index 000000000..c7fd73a09 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/soc/cpm.h +@@ -0,0 +1,135 @@ ++/* ++ * SOC CPM register definition. ++ * ++ * CPM (Clock reset and Power control Management) ++ * ++ * Copyright (C) 2021 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __SOC_CPM_H__ ++#define __SOC_CPM_H__ ++#include ++ ++/* ++ * CGU Register ++ * */ ++#define CPM_CPCCR (0x00) ++#define CPM_CPCSR (0xd4) ++ ++#define CPM_DDRCDR (0x2c) ++#define CPM_MACPHYCDR (0x54) ++#define CPM_I2SCDR (0x60) ++#define CPM_I2SCDR1 (0x7c) ++#define CPM_LPCDR (0x64) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0xa4) ++#define CPM_SFCCDR (0x74) ++#define CPM_SSICDR (0x5c) ++#define CPM_CIMCDR (0x78) ++#define CPM_PWMCDR (0x6c) ++#define CPM_MACPHYC0 (0xe4) ++#define CPM_CAN0CDR (0xa0) ++#define CPM_CAN1CDR (0xa8) ++#define CPM_CDBUSCDR (0xac) ++ ++#define CPM_INTR (0xb0) ++#define CPM_INTRE (0xb4) ++#define CPM_SFTINT (0xbc) ++#define CPM_DRCG (0xd0) ++#define CPM_CPSPR (0x34) ++#define CPM_CPSPPR (0x38) ++ ++#define CPM_USBPCR (0x3c) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++ ++#define CPM_CPPCR (0x0c) ++#define CPM_CPAPCR (0x10) ++#define CPM_CPAPACR (0x84) ++#define CPM_CPMPCR (0x14) ++#define CPM_CPMPACR (0x88) ++#define CPM_CPEPCR (0x18) ++#define CPM_CPEPACR (0x8c) ++ ++ ++/* ++ * Power Management Register ++ * */ ++#define CPM_LCR (0x04) ++#define CPM_PSWC0ST (0x90) ++#define CPM_PSWC1ST (0x94) ++#define CPM_PSWC2ST (0x98) ++#define CPM_PSWC3ST (0x9c) ++ ++#define CPM_SRBC (0xc4) ++#define CPM_SLBC (0xc8) ++#define CPM_SLPC (0xcc) ++#define CPM_CLKGR (0x20) ++#define CPM_CLKGR1 (0x28) ++#define CPM_MPDCR0 (0xF8) ++#define CPM_MPDCR1 (0xFC) ++#define CPM_OPCR (0x24) ++#define CPM_MESTSEL (0xEC) ++ ++ ++#ifndef BIT ++#define BIT(nr) (1UL << nr) ++#endif ++ ++/* USB Parameter Control Register */ ++#define USBPCR_USB_MODE BIT(31) ++#define USBPCR_AVLD_REG BIT(30) ++#define USBPCR_IDPULLUP_MASK_BIT 28 ++#define USBPCR_IDPULLUP_MASK (0x3 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS_SUSPEND (0x1 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_POR_BIT 22 ++#define USBPCR_POR BIT(USBPCR_POR_BIT) ++ ++/* USB Reset Detect Timer Register */ ++#define USBRDT_RESUME_INTEEN BIT(31) /*RW*/ ++#define USBRDT_RESUME_INTERCLR BIT(30) /*WO*/ ++#define USBRDT_RESUME_SPEED_BIT 28 /*RW*/ ++#define USBRDT_RESUME_SPEED_MSK (0x3 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_HIGH (0x0 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_FULL (0x1 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_LOW (0x2 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_STATUS BIT(27) /*RO*/ ++#define USBRDT_HB_MASK BIT(26) ++#define USBRDT_VBFIL_LD_EN BIT(25) ++#define USBRDT_IDDIG_EN BIT(24) ++#define USBRDT_IDDIG_REG BIT(23) ++#define USBRDT_USBRDT_MSK (0x7fffff) ++#define USBRDT_USBRDT(x) ((x) & USBRDT_USBRDT_MSK) ++ ++/* USB VBUS Jitter Filter Register */ ++#define USBVBFIL_USBVBFIL(x) ((x) & 0xffff) ++#define USBVBFIL_IDDIGFIL(x) ((x) & (0xffff << 16)) ++ ++/* USB Parameter Control Register1 */ ++#define USBPCR1_BVLD_REG BIT(31) ++#define USBPCR1_DPPULLDOWN BIT(29) ++#define USBPCR1_DMPULLDOWN BIT(28) ++#define USBPCR1_PORT_RST BIT(21) ++ ++/* Oscillator and Power Control Register */ ++#define OPCR_USB_SPENDN BIT(7) ++#define OPCR_USB_PHY_GATE BIT(23) ++#define OPCR_ERCS (0x1<<2) ++#define OPCR_PD (0x1<<3) ++#define OPCR_IDLE (0x1<<31) ++ ++/* Low Power Control Register */ ++#define LCR_LPM_MASK (0x3) ++#define LCR_LPM_SLEEP (0x1) ++ ++ ++#define cpm_inl(off) inl(CPM_IOBASE + (off)) ++#define cpm_outl(val,off) outl(val,CPM_IOBASE + (off)) ++#define cpm_clear_bit(val,off) do{cpm_outl((cpm_inl(off) & ~(1<<(val))),off);}while(0) ++#define cpm_set_bit(val,off) do{cpm_outl((cpm_inl(off) | (1< ++ ++/* ++ * DDR Controller Registers ++ **/ ++#define DDR_MEM_PHY_BASE 0x20000000 ++ ++#define DDRC_AHB2_OFFSET 0xb34f0000 ++#define DDRC_APB_OFFSET 0xb3012000 ++#define DDR_PHY_OFFSET (-0x4e0000 + 0x1000) ++ ++ ++ ++#define DDRC_STATUS 0x0 ++#define DDRC_CFG 0x4 ++#define DDRC_CTRL 0x8 ++#define DDRC_LMR 0xc ++#define DDRC_DLP 0xbc ++//#define DDRC_AUTOSR_EN 0x28 ++//#define DDRC_AUTOSR_CNT 0x30 ++#define DDRC_REFCNT 0x38 ++#define DDRC_DBGINFO 0xE8 ++#define DDRC_TIMING(n) (0x40 + 8 * (n - 1)) ++#define DDRC_MMAP0 0x78 ++#define DDRC_MMAP1 0x80 ++#define DDRC_HREGPRO 0xd8 ++#define DDRC_DWCFG (DDRC_APB_OFFSET + 0x00) ++#define DDRC_DWSTATUS (DDRC_APB_OFFSET + 0x04) ++#define DDRC_REMAP(n) (DDRC_APB_OFFSET + 0x08 + 4 * (n - 1)) ++#define DDRC_CGUC0 (DDRC_APB_OFFSET + 0x64) ++#define DDRC_CGUC1 (DDRC_APB_OFFSET + 0x68) ++#define DDRC_PREGPRO (DDRC_APB_OFFSET + 0x6c) ++ ++/* ++ * DDR Innophy registers ++ * */ ++#define DDRP_INNOPHY_PHY_RST (DDR_PHY_OFFSET + 0x000) ++#define DDRP_INNOPHY_MEM_CFG (DDR_PHY_OFFSET + 0x004) ++#define DDRP_INNOPHY_DQ_WIDTH (DDR_PHY_OFFSET + 0x07c) ++#define DDRP_INNOPHY_CL (DDR_PHY_OFFSET + 0x014) ++#define DDRP_INNOPHY_CWL (DDR_PHY_OFFSET + 0x01c) ++#define DDRP_INNOPHY_AL (DDR_PHY_OFFSET + 0x018) ++#define DDRP_INNOPHY_PLL_FBDIV (DDR_PHY_OFFSET + 0x080) ++#define DDRP_INNOPHY_PLL_CTRL (DDR_PHY_OFFSET + 0x084) ++#define DDRP_INNOPHY_PLL_PDIV (DDR_PHY_OFFSET + 0x088) ++#define DDRP_INNOPHY_PLL_LOCK (DDR_PHY_OFFSET + 0xc8) ++#define DDRP_INNOPHY_TRAINING_CTRL (DDR_PHY_OFFSET + 0x008) ++#define DDRP_INNOPHY_CALIB_DONE (DDR_PHY_OFFSET + 0x10c) ++#define DDRP_INNOPHY_CALIB_DELAY_AL (DDR_PHY_OFFSET + 0x1d0) ++#define DDRP_INNOPHY_CALIB_DELAY_AH (DDR_PHY_OFFSET + 0x1d4) ++#define DDRP_INNOPHY_CALIB_BYPASS_AL (DDR_PHY_OFFSET + 0x158) ++#define DDRP_INNOPHY_CALIB_BYPASS_AH (DDR_PHY_OFFSET + 0x198) ++#define DDRP_INNOPHY_WL_MODE1 (DDR_PHY_OFFSET + 0x00c) ++#define DDRP_INNOPHY_WL_MODE2 (DDR_PHY_OFFSET + 0x010) ++#define DDRP_INNOPHY_WL_DONE (DDR_PHY_OFFSET + 0x0c0) ++#define DDRP_INNOPHY_INIT_COMP (DDR_PHY_OFFSET + 0x0d0) ++ ++ ++/* ++ * DDRC REGISTER BITS DEFINE ++ * */ ++ ++/* DDRC Status Register */ ++#define DDRC_DSTATUS_MISS (1 << 6) ++#define DDRC_ST_DPDN (1 << 5) /* 0 DDR memory is NOT in deep-power-down state ++ 1 DDR memory is in deep-power-down state */ ++#define DDRC_ST_PDN (1 << 4) /* 0 DDR memory is NOT in power-down state ++ 1 DDR memory is in power-down state */ ++#define DDRC_ST_AREF (1 << 3) /* 0 DDR memory is NOT in auto-refresh state ++ 1 DDR memory is in auto-refresh state */ ++#define DDRC_ST_SREF (1 << 2) /* 0 DDR memory is NOT in self-refresh state ++ 1 DDR memory is in self-refresh state */ ++#define DDRC_ST_CKE1 (1 << 1) /* 0 CKE1 Pin is low ++ 1 CKE1 Pin is high */ ++#define DDRC_ST_CKE0 (1 << 0) /* 0 CKE0 Pin is low ++ 1 CKE0 Pin is high */ ++ ++/* DDRC Configure Register */ ++#define DDRC_CFG_ROW1_BIT 29 /* Row Address width. */ ++#define DDRC_CFG_ROW1_MASK (0x7 << DDRC_CFG_ROW1_BIT) ++#define DDRC_CFG_COL1_BIT 26 /* Row Address width. */ ++#define DDRC_CFG_COL1_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA1 25 /* Bank Address width of DDR memory */ ++#define DDRC_CFG_IMBA (1 << 16) ++#define DDRC_CFG_ROW0_BIT 13 /* Row Address width. */ ++#define DDRC_CFG_ROW0_MASK (0x7 << DDRC_CFG_ROW0_BIT) ++#define DDRC_CFG_COL0_BIT 10 /* Row Address width. */ ++#define DDRC_CFG_COL0_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA0 9 /* Bank Address width of DDR memory */ ++ ++#define DDRC_CFG_TYPE_BIT 3 ++#define DDRC_CFG_TYPE_MASK (0x7 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR1 (2 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_MDDR (3 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR2 (4 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR2 (5 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR3 (6 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR3 (7 << DDRC_CFG_TYPE_BIT) ++ ++#define DDRC_CFG_ODTEN (1 << 2) /* ODT EN */ ++#define DDRC_CFG_CS1EN (1 << 1) /* DDR Chip-Select-1 Enable */ ++#define DDRC_CFG_CS0EN (1 << 0) /* DDR Chip-Select-0 Enable */ ++ ++/* DDRC Control Register */ ++#define DDRC_CTRL_DFI_RST (1 << 23) ++#define DDRC_CTRL_DLL_RST (1 << 22) ++#define DDRC_CTRL_CTL_RST (1 << 21) ++#define DDRC_CTRL_CFG_RST (1 << 20) ++#define DDRC_CTRL_ACTPD (1 << 15) /* 0 Precharge all banks before entering power-down ++ 1 Do not precharge banks before entering power-down */ ++#define DDRC_CTRL_PDT_BIT 12 /* Power-Down Timer */ ++#define DDRC_CTRL_PDT_MASK (0x7 << DDRC_CTRL_PDT_BIT) ++#define DDRC_CTRL_PDT_DIS (0 << DDRC_CTRL_PDT_BIT) /* power-down disabled */ ++#define DDRC_CTRL_PDT_8 (1 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 8 tCK idle */ ++#define DDRC_CTRL_PDT_16 (2 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 16 tCK idle */ ++#define DDRC_CTRL_PDT_32 (3 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 32 tCK idle */ ++#define DDRC_CTRL_PDT_64 (4 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 64 tCK idle */ ++#define DDRC_CTRL_PDT_128 (5 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 128 tCK idle */ ++ ++#define DDRC_CTRL_PD_CCE (1 << 7) /* Power down clk freq change enable */ ++#define DDRC_CTRL_DPD (1 << 6) /* 1 Drive external MDDR device entering Deep-Power-Down mode */ ++#define DDRC_CTRL_SR (1 << 5) /* 1 Drive external DDR device entering self-refresh mode ++ 0 Drive external DDR device exiting self-refresh mode */ ++#define DDRC_CTRL_SR_CCE (1 << 4) /* Self refresh clk stop request enable */ ++#define DDRC_CTRL_CKE (1 << 1) /* 0 Not set CKE Pin High, 1 Set CKE Pin HIGH */ ++#define DDRC_CTRL_RESET (1 << 0) /* 0 End resetting ddrc_controller, 1 Resetting ddrc_controller */ ++ ++/* DDRC DFI low power handshake control register */ ++#define DDRC_DDLP_TCTLUDP_BIT 24 ++#define DDRC_DDLP_TCTLUDP_FF (0xff << DDRC_DDLP_TCTLUDP_BIT) ++ ++/* DDRC Load-Mode-Register */ ++#define DDRC_LMR_DDR_ADDR_BIT 12 /* When performing a DDR command, DDRC_ADDR[13:0] ++ corresponding to external DDR address Pin A[13:0] */ ++#define DDRC_LMR_DDR_ADDR_MASK (0xfffff << DDRC_LMR_DDR_ADDR_BIT) ++ ++#define DDRC_LMR_MA_BIT 16 /* FOR LPDDR2, MA[9:0] */ ++#define DDRC_LMR_OP_BIT 24 /* FOR LPDDR2, OP[9:0] */ ++ ++#define DDRC_LMR_BA_BIT 9 /* When performing a DDR command, BA[2:0] ++ corresponding to external DDR address Pin BA[2:0]. */ ++#define DDRC_LMR_BA_MASK (0x7 << DDRC_LMR_BA_BIT) ++#define DDRC_LMR_CMD_BIT 6 ++#define DDRC_LMR_CMD_MASK (0x7 << DDRC_LMR_CMD_BIT) ++#define DDRC_LMR_CMD_PREC (0 << DDRC_LMR_CMD_BIT)/* Precharge one bank/All banks */ ++#define DDRC_LMR_CMD_AUREF (1 << DDRC_LMR_CMD_BIT)/* Auto-Refresh */ ++#define DDRC_LMR_CMD_LMR (2 << DDRC_LMR_CMD_BIT)/* Load Mode Register */ ++#define DDRC_LMR_CMD_ZQCL_CS0 (3 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCL_CS1 (4 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS1 */ ++#define DDRC_LMR_CMD_ZQCS_CS0 (5 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCS_CS1 (6 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS1 */ ++ ++#define DDRC_LMR_TMRD_BIT 1 ++#define DDRC_LMR_TMRD_MASK (0x1f << DDRC_LMR_TMRD_BIT) ++#define DDRC_LMR_START (1 << 0) /* 0 No command is performed ++ 1 On the posedge of START, perform a command ++ defined by CMD field */ ++ ++/* DDRC Auto-Refresh Counter */ ++#define DDRC_REFCNT_REF_EN (1 << 0) /* Enable Refresh Counter */ ++#define DDRC_REFCNT_CLK_DIV_BIT 1 /* Clock Divider for auto-refresh counter. */ ++#define DDRC_REFCNT_CLK_DIV_MASK (0x7 << DDRC_REFCNT_CLKDIV_BIT) ++ ++#define DDRC_REFCNT_PREREF_CNT_BIT 4 ++#define DDRC_REFCNT_PREREF_CNT_MASK (0xf << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT(val) (val << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT_DEFAULT DDRC_REFCNT_PREREF_CNT(8) ++ ++#define DDRC_REFCNT_CNT_BIT 8 /* 8-bit counter */ ++#define DDRC_REFCNT_CNT_MASK (0xff << DDRC_REFCNT_CNT_BIT) ++ ++#define DDRC_REFCNT_CON_BIT 16 /* Constant value used to compare with CNT value. */ ++#define DDRC_REFCNT_CON_MASK (0xff << DDRC_REFCNT_CON_BIT) ++ ++#define DDRC_REFCNT_TRFC_BIT 24 ++#define DDRC_REFCNT_TRFC_MASK (0x3f << DDRC_REFCNT_TRFC_BIT) ++ ++#define DDRC_REFCNT_PREREF_EN_BIT 30 ++#define DDRC_REFCNT_PREREF_EN (1 << DDRC_REFCNT_PREREF_EN_BIT) ++ ++#define DDRC_REFCNT_PBREF_EN_BIT 31 ++#define DDRC_REFCNT_PBREF_EN (1 << DDRC_REFCNT_PBREF_EN_BIT) ++ ++/* DDRC Memory Map Config Register */ ++#define DDRC_MMAP_BASE_BIT 8 /* base address */ ++#define DDRC_MMAP_BASE_MASK (0xff << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP_MASK_BIT 0 /* address mask */ ++#define DDRC_MMAP_MASK_MASK (0xff << DDRC_MMAP_MASK_BIT) ++ ++#define DDRC_MMAP0_BASE (0x20 << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP1_BASE_64M (0x24 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_128M (0x28 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_256M (0x30 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++ ++#define DDRC_MMAP_MASK_64_64 (0xfc << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_128_128 (0xf8 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_256_256 (0xf0 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++ ++/* DDR device data width configure register */ ++#define DDRC_DWCFG_DFI_INIT_START (1 << 3) ++ ++/* DDR device status register */ ++#define DDRC_DWSTATUS_DFI_INIT_COMP (1 << 0) ++ ++/* DDRC AHB Bus Register Protection Register */ ++#define DDRC_HREGPRO_HPRO_EN (1 << 0) ++ ++/* DDRC APB Bus Register Protection Register */ ++#define DDRC_PREGPRO_PPRO_EN (1 << 0) ++ ++ ++/* DDRC clock gate unit configure 0 */ ++#define DDRC_CGU_PORT7 (1 << 28) ++#define DDRC_CGU_PORT6 (1 << 24) ++#define DDRC_CGU_PORT5 (1 << 20) ++#define DDRC_CGU_PORT4 (1 << 16) ++#define DDRC_CGU_PORT3 (1 << 12) ++#define DDRC_CGU_PORT2 (1 << 8) ++#define DDRC_CGU_PORT1 (1 << 4) ++#define DDRC_CGU_PORT0 (1 << 0) ++ ++/* DDRC clock gate unit configure 1 */ ++#define DDRC_CGU_BWM (1 << 8) ++#define DDRC_CGU_PCTRL (1 << 4) ++#define DDRC_CGU_SCH (1 << 1) ++#define DDRC_CGU_PA (1 << 0) ++ ++ ++ ++/* ++ * DDR INNOPHY REGISTER BITS DEFINE ++ * */ ++ ++/* DDRP DQ Width Register */ ++#define DDRP_DQ_WIDTH_DQ_H (1 << 1) ++#define DDRP_DQ_WIDTH_DQ_L (1 << 0) ++ ++/* DDRP Pll Ctrl Register */ ++#define DDRP_PLL_CTRL_PLLPDEN (1 << 1) ++ ++/* DDRP Training Ctrl Register */ ++#define DDRP_TRAINING_CTRL_WL_BP (1 << 3) ++#define DDRP_TRAINING_CTRL_WL_START (1 << 2) ++#define DDRP_TRAINING_CTRL_DSCSE_BP (1 << 1) ++#define DDRP_TRAINING_CTRL_DSACE_START (1 << 0) ++ ++/* DDRP Training Done Register */ ++#define DDRP_CALIB_DONE_HDQCFB (1 << 3) ++#define DDRP_CALIB_DONE_LDQCFB (1 << 2) ++#define DDRP_CALIB_DONE_HDQCFA (1 << 1) ++#define DDRP_CALIB_DONE_LDQCFA (1 << 0) ++#define DDRP_CALIB_DONE_HWRLFB (1 << 3) ++#define DDRP_CALIB_DONE_LWRLFB (1 << 2) ++#define DDRP_CALIB_DONE_HWRLFA (1 << 1) ++#define DDRP_CALIB_DONE_LWRLFA (1 << 0) ++ ++/* DDRP CALIB BP Register */ ++#define DDRP_CALIB_BP_CYCLESELBH_BIT 4 ++#define DDRP_CALIB_BP_OPHCSELBH_BIT 3 ++#define DDRP_CALIB_BP_DLLSELBH_BIT 0 ++ ++/* DDRP Init Complete Register */ ++#define DDRP_INIT_COMP (1 << 0) ++ ++#define DDRP_PLL_LOCK (1 << 3) ++ ++#define REG32(addr) *(volatile unsigned int *)(addr) ++ ++#define ddr_writel(value, reg) (REG32(DDRC_BASE + reg) = (value)) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++#endif /* __DDR_H__ */ +diff --git a/arch/mips/xburst/soc-x1600/include/soc/efuse.h b/arch/mips/xburst/soc-x1600/include/soc/efuse.h +new file mode 100644 +index 000000000..4d1f660c7 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/soc/efuse.h +@@ -0,0 +1,192 @@ ++#ifndef __INGENIC_EFUSE_H__ ++#define __INGENIC_EFUSE_H__ ++ ++#define EFUSE_CTRL 0x0 ++#define EFUSE_CFG 0x4 ++#define EFUSE_STATE 0x8 ++#define EFUSE_DATA(n) (0xC + (n) * 4) ++ ++ ++// efuse ctrl bits ++#define EFUSE_CTRL_ADDR (21) ++#define EFUSE_CTRL_ADDR_MASK (0x3f) ++#define EFUSE_CTRL_LEN (16) ++#define EFUSE_CTRL_LEN_MASK (0x1f) ++#define EFUSE_CTRL_PGEN (1 << 15) ++#define EFUSE_CTRL_WREN (1 << 1) ++#define EFUSE_CTRL_RDEN (1 << 0) ++ ++ ++// efuse cfg bits ++#define EFUSE_CFG_INT_EN (1 << 31) ++#define EFUSE_CFG_RD_ADJ (20) ++#define EFUSE_CFG_RD_ADJ_MASK (0xf) ++#define EFUSE_CFG_RD_STROBE (16) ++#define EFUSE_CFG_RD_STROBE_MASK (0xf) ++#define EFUSE_CFG_WR_ADJ (12) ++#define EFUSE_CFG_WR_ADJ_MASK (0xf) ++#define EFUSE_CFG_WR_STROBE (0) ++#define EFUSE_CFG_WR_STROBE_MASK (0x7ff) ++ ++ ++// efuse state bits ++#define EFUSE_STA_NKU_PRT (1 << 21) ++#define EFUSE_STA_USERKEY_PRT (1 << 20) ++#define EFUSE_STA_CHIPKEY_PRT (1 << 19) ++#define EFUSE_STA_HIDEBLK_PRT (1 << 18) ++#define EFUSE_STA_SOCINFO_PRT (1 << 17) ++#define EFUSE_STA_TRIM3_PRT (1 << 16) ++#define EFUSE_STA_TRIM2_PRT (1 << 15) ++#define EFUSE_STA_TRIM1_PRT (1 << 14) ++#define EFUSE_STA_TRIM0_PRT (1 << 13) ++#define EFUSE_STA_CUT_PRT (1 << 12) ++#define EFUSE_STA_CHIPID_PRT (1 << 11) ++#define EFUSE_STA_SCBT_PRT (1 << 10) ++#define EFUSE_STA_DIS_JTAG (1 << 9) ++#define EFUSE_STA_SCBT_EN (1 << 8) ++#define EFUSE_STA_WR_DONE (1 << 1) ++#define EFUSE_STA_RD_DONE (1 << 0) ++ ++ ++#define CHIPID_OFFSET_ADDR (0x0) ++#define CUT_OFFSET_ADDR (0x10) ++#define TRIM0_OFFSET_ADDR (0x1b) ++#define TRIM1_OFFSET_ADDR (0x1f) ++#define TRIM2_OFFSET_ADDR (0x23) ++#define TRIM3_OFFSET_ADDR (0x27) ++#define SOCINFO_OFFSET_ADDR (0x2b) ++#define HIDEBLK_OFFSET_ADDR (0x2d) ++#define PRT_OFFSET_ADDR (0x2e) ++#define CHIPKEY_OFFSET_ADDR (0x30) ++#define USERKEY_OFFSET_ADDR (0x50) ++#define NKU_OFFSET_ADDR (0x70) ++ ++ ++#define CHIPID_BIT_NUM (128) ++#define CUT_BIT_NUM (88) ++#define TRIM0_BIT_NUM (32) ++#define TRIM1_BIT_NUM (32) ++#define TRIM2_BIT_NUM (32) ++#define TRIM3_BIT_NUM (32) ++#define SOCINFO_BIT_NUM (16) ++#define HIDEBLK_BIT_NUM (8) ++#define PRT_BIT_NUM (16) ++#define CHIPKEY_BIT_NUM (256) ++#define USERKEY_BIT_NUM (256) ++#define NKU_BIT_NUM (128) ++ ++ ++enum segment_id { ++ CHIPID = 0, ++ CUTID, ++ TRIM0, ++ TRIM1, ++ TRIM2, ++ TRIM3, ++ SOCINFO, ++ HIDEBLK, ++ PRT, ++ CHIPKEY, ++ USERKEY, ++ NKU ++}; ++ ++ ++struct seg_info { ++ char seg_name[32]; ++ uint32_t seg_id; ++ uint32_t offset_address; ++ uint32_t bit_num; ++ uint32_t prt_bit; ++}; ++ ++static struct seg_info seg_info_array[] = { ++ [0] = { ++ .seg_name = "CHIPID", ++ .seg_id = CHIPID, ++ .offset_address = CHIPID_OFFSET_ADDR, ++ .bit_num = CHIPID_BIT_NUM, ++ .prt_bit = EFUSE_STA_CHIPID_PRT, ++ }, ++ [1] = { ++ .seg_name = "CUTID", ++ .seg_id = CUTID, ++ .offset_address = CUT_OFFSET_ADDR, ++ .bit_num = CUT_BIT_NUM, ++ .prt_bit = EFUSE_STA_CUT_PRT, ++ }, ++ [2] = { ++ .seg_name = "TRIM0", ++ .seg_id = TRIM0, ++ .offset_address = TRIM0_OFFSET_ADDR, ++ .bit_num = TRIM0_BIT_NUM, ++ .prt_bit = EFUSE_STA_TRIM0_PRT, ++ }, ++ [3] = { ++ .seg_name = "TRIM1", ++ .seg_id = TRIM1, ++ .offset_address = TRIM1_OFFSET_ADDR, ++ .bit_num = TRIM1_BIT_NUM, ++ .prt_bit = EFUSE_STA_TRIM1_PRT, ++ }, ++ [4] = { ++ .seg_name = "TRIM2", ++ .seg_id = TRIM2, ++ .offset_address = TRIM2_OFFSET_ADDR, ++ .bit_num = TRIM2_BIT_NUM, ++ .prt_bit = EFUSE_STA_TRIM2_PRT, ++ }, ++ [5] = { ++ .seg_name = "TRIM3", ++ .seg_id = TRIM3, ++ .offset_address = TRIM3_OFFSET_ADDR, ++ .bit_num = TRIM3_BIT_NUM, ++ .prt_bit = EFUSE_STA_TRIM3_PRT, ++ }, ++ [6] = { ++ .seg_name = "SOCINFO", ++ .seg_id = SOCINFO, ++ .offset_address = SOCINFO_OFFSET_ADDR, ++ .bit_num = SOCINFO_BIT_NUM, ++ .prt_bit = EFUSE_STA_SOCINFO_PRT, ++ }, ++ [7] = { ++ .seg_name = "HIDEBLK", ++ .seg_id = HIDEBLK, ++ .offset_address = HIDEBLK_OFFSET_ADDR, ++ .bit_num = HIDEBLK_BIT_NUM, ++ .prt_bit = EFUSE_STA_HIDEBLK_PRT, ++ }, ++ [8] = { ++ .seg_name = "PRT", ++ .seg_id = PRT, ++ .offset_address = PRT_OFFSET_ADDR, ++ .bit_num = PRT_BIT_NUM, ++ .prt_bit = 0xffffffff, ++ }, ++ [9] = { ++ .seg_name = "CHIPKEY", ++ .seg_id = CHIPKEY, ++ .offset_address = CHIPKEY_OFFSET_ADDR, ++ .bit_num = CHIPKEY_BIT_NUM, ++ .prt_bit = EFUSE_STA_CHIPKEY_PRT, ++ }, ++ [10] = { ++ .seg_name = "USERKEY", ++ .seg_id = USERKEY, ++ .offset_address = USERKEY_OFFSET_ADDR, ++ .bit_num = USERKEY_BIT_NUM, ++ .prt_bit = EFUSE_STA_USERKEY_PRT, ++ }, ++ [11] = { ++ .seg_name = "NKU", ++ .seg_id = NKU, ++ .offset_address = NKU_OFFSET_ADDR, ++ .bit_num = NKU_BIT_NUM, ++ .prt_bit = EFUSE_STA_NKU_PRT, ++ }, ++}; ++ ++void jz_efuse_id_read(int is_chip_id, uint8_t *buf); ++ ++#endif +diff --git a/arch/mips/xburst/soc-x1600/include/soc/gpio.h b/arch/mips/xburst/soc-x1600/include/soc/gpio.h +new file mode 100644 +index 000000000..aead63252 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/soc/gpio.h +@@ -0,0 +1,44 @@ ++#ifndef _SOC_GPIO_H_ ++#define _SOC_GPIO_H_ ++ ++enum gpio_function { ++ GPIO_FUNC_0 = 0x0100, //00000, GPIO as function 0 / device 0 ++ GPIO_FUNC_1 = 0x0101, //00001, GPIO as function 1 / device 1 ++ GPIO_FUNC_2 = 0x0102, //00010, GPIO as function 2 / device 2 ++ GPIO_FUNC_3 = 0x0103, //00011, GPIO as function 3 / device 3 ++ GPIO_OUTPUT0 = 0x0104, //00100, GPIO output low level ++ GPIO_OUTPUT1 = 0x0105, //00101, GPIO output high level ++ GPIO_INPUT = 0x0106, //00110, GPIO as input.7 also. ++ GPIO_INT_LO = 0x0108, //01000, Low Level trigger interrupt ++ GPIO_INT_HI = 0x0109, //01001, High Level trigger interrupt ++ GPIO_INT_FE = 0x010a, //01010, Fall Edge trigger interrupt ++ GPIO_INT_RE = 0x010b, //01011, Rise Edge trigger interrupt ++ GPIO_INT_RE_FE = 0x011b, //11011, Dual Edge(both rise and fall) trigger interrupt ++ GPIO_INT_MASK_LO = 0x010c, //01100, Port is low level triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_HI = 0x010d, //01101, Port is high level triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_FE = 0x010e, //01110, Port is fall edge triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_RE = 0x010f, //01111, Port is rise edge triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_RE_FE = 0x011f, //11111, Port is dual edge(both rise and fall edge) triggered interrupt input. Interrupt is masked. ++ ++ GPIO_PULL_HIZ = 0x8000, //no pull ++ GPIO_PULL = 0xa000, //pull, x1600åªæ”¯æŒpull,是什么类型的pull è¦çœ‹èŠ¯ç‰‡æ‰‹å†Œ ++}; ++ ++enum gpio_port { ++ GPIO_PORT_A = 0, ++ GPIO_PORT_B, ++ GPIO_PORT_C, ++ GPIO_PORT_D, ++ ++ /* this must be last */ ++ GPIO_NR_PORTS, ++}; ++ ++#define GPIO_PA(n) (0 * 32 + (n)) ++#define GPIO_PB(n) (1 * 32 + (n)) ++#define GPIO_PC(n) (2 * 32 + (n)) ++#define GPIO_PD(n) (3 * 32 + (n)) ++ ++int jzgpio_set_func(int port, enum gpio_function func, unsigned long pins); ++ ++#endif /* _SOC_GPIO_H_ */ +diff --git a/arch/mips/xburst/soc-x1600/include/soc/ost.h b/arch/mips/xburst/soc-x1600/include/soc/ost.h +new file mode 100644 +index 000000000..86fbcc3cc +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/soc/ost.h +@@ -0,0 +1,41 @@ ++/* ++ * INGENIC ost register definition. ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __OST_H__ ++#define __OST_H__ ++ ++#define OST_TCCR (0x00) /* OS Timer Clock Control Register*/ ++#define OST_TER (0x04) /* OS Timer Counter Enable Register */ ++#define OST_TCR (0x08) /* OS Timer clear Register */ ++#define OST_TFR (0x0C) /* OS Timer Flag Register */ ++#define OST_TMR (0x10) /* OS Timer Mask Register */ ++#define OST_T1DFR (0x14) /* OS Timer1 Data FULL Register */ ++#define OST_T1CNT (0x18) /* OS Timer1 Counter */ ++#define OST_T2CNTH (0x1c) /* OS Timer2 Counter High 32 Bits */ ++#define OST_T2CNTL (0x20) /* OS Timer2 Counter Lower 32 Bits */ ++#define OST_TCNT2HBUF (0x24) /* OS Timer2 Counter Higher 32 Bits Buffer */ ++#define OST_TESR (0x34) /* OS Timer Counter Enable Set Register */ ++#define OST_TECR (0x38) /* OS Timer Counter Enable Clear Register */ ++ ++#define TCCRDIV_MSK1 (0x3) ++#define TCCRDIV_SFT2 (2) ++#define TCCRDIV_MSK2 (TCCRDIV_MSK1 << TCCRDIV_SFT2) ++#define TCCRDIV1(x) ({int n = 0; int d = (x); while(d) { d >>= 2; n++; }; (n-1);}) ++#define TCCRDIV2(x) (TCCRDIV1((x)) << TCCRDIV_SFT2) ++ ++#define TESR_OSTEN1 (1 << 0) /* enable the counter1 in ost */ ++#define TESR_OSTEN2 (1 << 1) /* enable the counter2 in ost */ ++ ++#define TCR_OSTCLR1 (1 << 0) ++#define TCR_OSTCLR2 (1 << 1) ++ ++#define TMR_OSTM (1 << 0) /* ost comparison match interrupt mask */ ++ ++#define TFR_OSTM (1 << 0) /* Comparison match */ ++ ++#define ost_readl(reg) readl_relaxed(reg) ++#define ost_writel(reg, val) writel_relaxed(val, reg) ++#endif +diff --git a/arch/mips/xburst/soc-x1600/include/soc/sfc.h b/arch/mips/xburst/soc-x1600/include/soc/sfc.h +new file mode 100644 +index 000000000..62d3978c9 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/soc/sfc.h +@@ -0,0 +1,207 @@ ++#ifndef __SFC_REGISTER_H ++#define __SFC_REGISTER_H ++ ++/* SFC register */ ++#define SFC_GLB0 (0x0000) ++#define SFC_DEV_CONF (0x0004) ++#define SFC_DEV_STA_EXP (0x0008) ++#define SFC_DEV0_STA_RT (0x000c) ++#define SFC_DEV_STA_MSK (0x0010) ++#define SFC_TRAN_CONF0(n) (0x0014 + (n * 4)) ++#define SFC_TRAN_LEN (0x002c) ++#define SFC_DEV_ADDR(n) (0x0030 + (n * 4)) ++#define SFC_DEV_ADDR_PLUS(n) (0x0048 + (n * 4)) ++#define SFC_MEM_ADDR (0x0060) ++#define SFC_TRIG (0x0064) ++#define SFC_SR (0x0068) ++#define SFC_SCR (0x006c) ++#define SFC_INTC (0x0070) ++#define SFC_FSM (0x0074) ++#define SFC_CGE (0x0078) ++#define SFC_CMD_IDX (0x007c) ++#define SFC_COL_ADDR (0x0080) ++#define SFC_ROW_ADDR (0x0084) ++#define SFC_STA_ADDR0 (0x0088) ++#define SFC_STA_ADDR1 (0x008c) ++#define SFC_DES_ADDR (0x0090) ++#define SFC_GLB1 (0x0094) ++#define SFC_DEV1_STA_RT (0x0098) ++#define SFC_TRAN_CONF1(n) (0x009c + (n * 4)) ++#define SFC_CDT (0x0800) //0x800 ~ 0xbff ++#define SFC_RM_DR (0x1000) ++ ++/* For SFC_GLB0 */ ++#define GLB0_POLL_TIME_OFFSET (16) ++#define GLB0_POLL_TIME_MSK (0xffff << GLB0_POLL_TIME_OFFSET) ++#define GLB0_DES_EN (1 << 15) ++#define GLB0_CDT_EN (1 << 14) ++#define GLB0_TRAN_DIR (1 << 13) ++#define GLB0_TRAN_DIR_WRITE (1) ++#define GLB0_TRAN_DIR_READ (0) ++#define GLB0_THRESHOLD_OFFSET (7) ++#define GLB0_THRESHOLD_MSK (0x3f << GLB0_THRESHOLD_OFFSET) ++#define GLB0_OP_MODE (1 << 6) ++#define GLB0_OP_OFFSET (6) ++#define SLAVE_MODE (0x0) ++#define DMA_MODE (0x1) ++#define GLB0_PHASE_NUM_OFFSET (3) ++#define GLB0_PHASE_NUM_MSK (0x7 << GLB0_PHASE_NUM_OFFSET) ++#define GLB0_WP_EN (1 << 2) ++#define GLB0_BURST_MD_OFFSET (0) ++#define GLB0_BURST_MD_MSK (0x3 << GLB0_BURST_MD_OFFSET) ++ ++/* For SFC_DEV_CONF */ ++#define DEV_CONF_STA_ENDIAN_OFFSET (31) ++#define STA_ENDIAN_LSB (0) ++#define STA_ENDIAN_MSB (1) ++#define DEV_CONF_SMP_DELAY_OFFSET (16) ++#define DEV_CONF_SMP_DELAY_MSK (0x1f << DEV_CONF_SMP_DELAY_OFFSET) ++#define DEV_CONF_SMP_DELAY_0 (0) ++#define DEV_CONF_SMP_DELAY_45 (1) ++#define DEV_CONF_SMP_DELAY_90 (2) ++#define DEV_CONF_SMP_DELAY_135 (3) ++#define DEV_CONF_SMP_DELAY_180 (4) ++#define DEV_CONF_SMP_DELAY_225 (5) ++#define DEV_CONF_SMP_DELAY_270 (6) ++#define DEV_CONF_SMP_DELAY_315 (7) ++#define DEV_CONF_SMP_DELAY_1 (8) ++#define DEV_CONF_SMP_DELAY_2 (16) ++#define DEV_CONF_CMD_TYPE (0x1 << 15) ++#define DEV_CONF_STA_TYPE_OFFSET (13) ++#define DEV_CONF_STA_TYPE_MSK (0x3 << DEV_CONF_STA_TYPE_OFFSET) ++#define DEV_CONF_THOLD_OFFSET (11) ++#define DEV_CONF_THOLD_MSK (0x3 << DEV_CONF_THOLD_OFFSET) ++#define DEV_CONF_TSETUP_OFFSET (9) ++#define DEV_CONF_TSETUP_MSK (0x3 << DEV_CONF_TSETUP_OFFSET) ++#define DEV_CONF_TSH_OFFSET (5) ++#define DEV_CONF_TSH_MSK (0xf << DEV_CONF_TSH_OFFSET) ++#define DEV_CONF_CPHA (0x1 << 4) ++#define DEV_CONF_CPOL (0x1 << 3) ++#define DEV_CONF_CEDL (0x1 << 2) ++#define DEV_CONF_HOLDDL (0x1 << 1) ++#define DEV_CONF_WPDL (0x1 << 0) ++ ++/* For SFC_TRAN_CONF0 */ ++#define TRAN_CONF0_CLK_MODE (29) ++#define TRAN_CONF0_CLK_MODE_MSK (0x7 << TRAN_CONF0_CLK_MODE) ++#define TRAN_CONF0_CLK_MODE_SSS (0) ++#define TRAN_CONF0_CLK_MODE_SSD (1) ++#define TRAN_CONF0_CLK_MODE_SDS (2) ++#define TRAN_CONF0_CLK_MODE_SDD (3) ++#define TRAN_CONF0_CLK_MODE_DSS (4) ++#define TRAN_CONF0_CLK_MODE_DSD (5) ++#define TRAN_CONF0_CLK_MODE_DDS (6) ++#define TRAN_CONF0_CLK_MODE_DDD (7) ++#define TRAN_CONF0_ADDR_WIDTH_OFFSET (26) ++#define TRAN_CONF0_ADDR_WIDTH_MSK (0x7 << TRAN_CONF0_ADDR_WIDTH_OFFSET) ++#define TRAN_CONF0_POLLEN (1 << 25) ++#define TRAN_CONF0_POLL_OFFSET (25) ++#define TRAN_CONF0_CMDEN (1 << 24) ++#define TRAN_CONF0_FMAT (1 << 23) ++#define TRAN_CONF0_FMAT_OFFSET (23) ++#define TRAN_CONF0_DMYBITS_OFFSET (17) ++#define TRAN_CONF0_DMYBITS_MSK (0x3f << TRAN_CONF0_DMYBITS_OFFSET) ++#define TRAN_CONF0_DATEEN (1 << 16) ++#define TRAN_CONF0_DATEEN_OFFSET (16) ++#define TRAN_CONF0_CMD_OFFSET (0) ++#define TRAN_CONF0_CMD_MSK (0xffff << TRAN_CONF0_CMD_OFFSET) ++ ++/* For SFC_TRAN_CONF1 */ ++#define TRAN_CONF1_DATA_ENDIAN (1 << 18) ++#define TRAN_CONF1_DATA_ENDIAN_OFFSET (18) ++#define TRAN_CONF1_DATA_ENDIAN_LSB (0) ++#define TRAN_CONF1_DATA_ENDIAN_MSB (1) ++#define TRAN_CONF1_WORD_UNIT_OFFSET (16) ++#define TRAN_CONF1_WORD_UNIT_MSK (3 << 16) ++#define TRAN_CONF1_TRAN_MODE_OFFSET (4) ++#define TRAN_CONF1_TRAN_MODE_MSK (0xf << TRAN_CONF1_TRAN_MODE_OFFSET) ++#define TRAN_CONF1_SPI_STANDARD (0x0) ++#define TRAN_CONF1_SPI_DUAL (0x1) ++#define TRAN_CONF1_SPI_QUAD (0x5) ++#define TRAN_CONF1_SPI_IO_QUAD (0x6) ++#define TRAN_CONF1_SPI_OCTAL (0x9) ++#define TRAN_CONF1_SPI_IO_OCTAL (0xa) ++#define TRAN_CONF1_SPI_FULL_OCTAL (0xb) ++ ++ ++/* For SFC_TRIG */ ++#define TRIG_FLUSH (1 << 2) ++#define TRIG_STOP (1 << 1) ++#define TRIG_START (1 << 0) ++ ++/* For SFC_SR */ ++#define SFC_WORKING (1 << 7) ++#define SFC_BUSY (0x3 << 5) ++#define SFC_END (1 << 4) ++#define SFC_TREQ (1 << 3) ++#define SFC_RREQ (1 << 2) ++#define SFC_OVER (1 << 1) ++#define SFC_UNDER (1 << 0) ++ ++/* For SFC_SCR */ ++#define CLR_END (1 << 4) ++#define CLR_TREQ (1 << 3) ++#define CLR_RREQ (1 << 2) ++#define CLR_OVER (1 << 1) ++#define CLR_UNDER (1 << 0) ++ ++/* SFC_CMD_IDX */ ++#define CMD_IDX_MSK (0x3f << 0) ++#define CDT_DATAEN_MSK (0x1 << 31) ++#define CDT_DATAEN_OFF (31) ++#define CDT_DIR_MSK (0x1 << 30) ++#define CDT_DIR_OFF (30) ++ ++/* For SFC_GLB1 */ ++#define GLB1_CHIP1_SEL_OFFSET (31) ++#define GLB1_CHIP1_SEL_MSK (0x1 << GLB1_CHIP1_SEL_OFFSET) ++#define GLB1_CHIP_SEL_OFFSET (0) ++#define GLB1_CHIP_SEL_MSK (0x1 << GLB1_CHIP_SEL_OFFSET) ++#define GLB1_CHIP0_SEL (0x0) ++#define GLB1_CHIP1_SEL (0x1) ++ ++#define N_MAX 6 ++#define MAX_SEGS 128 ++ ++#define CHANNEL_0 0 ++#define CHANNEL_1 1 ++#define CHANNEL_2 2 ++#define CHANNEL_3 3 ++#define CHANNEL_4 4 ++#define CHANNEL_5 5 ++ ++#define ENABLE 1 ++#define DISABLE 0 ++ ++#define COM_CMD 1 // common cmd ++#define POLL_CMD 2 // the cmd will poll the status of flash,ext: read status ++ ++#define DMA_OPS 1 ++#define CPU_OPS 0 ++ ++#define TM_STD_SPI 0 ++#define TM_DI_DO_SPI 1 ++#define TM_DIO_SPI 2 ++#define TM_FULL_DIO_SPI 3 ++#define TM_QI_QO_SPI 5 ++#define TM_QIO_SPI 6 ++#define TM_FULL_QIO_SPI 7 ++ ++ ++#define DEFAULT_CDT 1 ++#define UPDATE_CDT 2 ++#define DEFAULT_ADDRSIZE 3 ++#define DEFAULT_ADDRMODE 0 ++ ++ ++#define THRESHOLD 32 ++ ++#define SFC_NOR_RATE 110 ++#define DEF_ADDR_LEN 3 ++#define DEF_TCHSH 6 ++#define DEF_TSLCH 6 ++#define DEF_TSHSL_R 20 ++#define DEF_TSHSL_W 50 ++ ++ ++#endif +diff --git a/arch/mips/xburst/soc-x1600/include/soc/tcsm_layout.h b/arch/mips/xburst/soc-x1600/include/soc/tcsm_layout.h +new file mode 100644 +index 000000000..19ba6667d +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/soc/tcsm_layout.h +@@ -0,0 +1,53 @@ ++#ifndef __TCSM_LAYOUT_H__ ++#define __TCSM_LAYOUT_H__ ++ ++/** ++ * |-------------| ++ * | BANK0 | ++ * |-------------| <--- SLEEP_TCSM_BOOTCODE_TEXT ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * |-------------| ++ * | VO DMA DESC | ++ * |_____________| <--- VOICE_TCSM_DMA_DESC ++ * ++ * ++ * |-------------| ++ * | BANK1 | ++ * |-------------| <--- VOICE_TCSM_DATA_BUF ++ * | | ++ * | | ++ * | ... | ++ * | VOICE DATA | ++ * | ... | ++ * | | ++ * | | ++ * |_____________| ++ * ++ */ ++ ++/* ++ * If you use the VOICE TRIGGER, ++ * and you change the VOICE_* and TCSM_BANK_LEN, ++ * while compiling wakeup module ++ */ ++#define SLEEP_TCSM_SPACE 0xb3422000 ++#define VOICE_TCSM_DATA_BUF 0xb3423000 ++#define TCSM_BANK_LEN 4096 ++ ++#define SLEEP_TCSM_BOOT_TEXT (SLEEP_TCSM_SPACE) ++ ++#define VOICE_TCSM_DMA_DESC_LEN 512 ++#define SLEEP_TCSM_SPACE_END (SLEEP_TCSM_SPACE + TCSM_BANK_LEN - VOICE_TCSM_DMA_DESC_LEN) ++#define VOICE_TCSM_DMA_DESC_ADDR SLEEP_TCSM_SPACE_END ++ ++#define SLEEP_TCSM_CPU_RESMUE_SP SLEEP_TCSM_SPACE_END - 4 ++ ++#define VOICE_TCSM_DATA_BUF_SIZE TCSM_BANK_LEN ++ ++#endif /* __TCSM_LAYOUT_H__ */ +diff --git a/arch/mips/xburst/soc-x1600/include/soc/tcu.h b/arch/mips/xburst/soc-x1600/include/soc/tcu.h +new file mode 100644 +index 000000000..0532718c0 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/soc/tcu.h +@@ -0,0 +1,84 @@ ++/* ++ * JZ4770 tcu register definition. ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __TCU_H__ ++#define __TCU_H__ ++ ++#define WDT_TDR (0x00) /* rw, 32, 0x???????? */ ++#define WDT_TCER (0x04) /* rw, 32, 0x???????? */ ++#define WDT_TCNT (0x08) /* rw, 32, 0x???????? */ ++#define WDT_TCSR (0x0c) /* rw, 32, 0x???????? */ ++ ++#define TCU_TSTR (0xF0) /* Timer Status Register,Only Used In Tcu2 Mode */ ++#define TCU_TSTSR (0xF4) /* Timer Status Set Register */ ++#define TCU_TSTCR (0xF8) /* Timer Status Clear Register */ ++#define TCU_TSR (0x1C) /* Timer Stop Register */ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++#define TCU_TER (0x10) /* Timer Counter Enable Register */ ++#define TCU_TESR (0x14) /* Timer Counter Enable Set Register */ ++#define TCU_TECR (0x18) /* Timer Counter Enable Clear Register */ ++#define TCU_TFR (0x20) /* Timer Flag Register */ ++#define TCU_TFSR (0x24) /* Timer Flag Set Register */ ++#define TCU_TFCR (0x28) /* Timer Flag Clear Register */ ++#define TCU_TMR (0x30) /* Timer Mask Register */ ++#define TCU_TMSR (0x34) /* Timer Mask Set Register */ ++#define TCU_TMCR (0x38) /* Timer Mask Clear Register */ ++ ++#define CH_TDFR(n) (0x40 + (n)*0x10) /* Timer Data Full Reg */ ++#define CH_TDHR(n) (0x44 + (n)*0x10) /* Timer Data Half Reg */ ++#define CH_TCNT(n) (0x48 + (n)*0x10) /* Timer Counter Reg */ ++#define CH_TCSR(n) (0x4C + (n)*0x10) /* Timer Control Reg */ ++ ++#define TER_OSTEN (1 << 15) /* enable the counter in ost */ ++#define TMR_OSTM (1 << 15) /* ost comparison match interrupt mask */ ++#define TFR_OSTF (1 << 15) /* ost interrupt flag */ ++#define TSR_OSTS (1 << 15) /*the clock supplies to osts is stopped */ ++ ++#define TSR_WDTS (1 << 16) /*the clock supplies to wdt is stopped */ ++ ++#define CSR_EXT_EN (1 << 2) /* select extal as the timer clock input */ ++#define CSR_RTC_EN (1 << 1) /* select rtcclk as the timer clock input */ ++#define CSR_PCK_EN (1 << 0) /* select pclk as the timer clock input */ ++#define CSR_CLK_MSK (0x7) ++ ++#define CSR_DIV1 (0x0 << 3) ++#define CSR_DIV4 (0x1 << 3) ++#define CSR_DIV16 (0x2 << 3) ++#define CSR_DIV64 (0x3 << 3) ++#define CSR_DIV256 (0x4 << 3) ++#define CSR_DIV1024 (0x5 << 3) ++#define CSR_DIV_MSK (0x7 << 3) ++ ++// Register bits definitions ++#define TSTR_REAL2 (1 << 18) /* only used in TCU2 mode */ ++#define TSTR_REAL1 (1 << 17) /* only used in TCU2 mode */ ++#define TSTR_BUSY2 (1 << 2) /* only used in TCU2 mode */ ++#define TSTR_BUSY1 (1 << 1) /* only used in TCU2 mode */ ++ ++#define TCSR_PWM_BYPASS (1 << 11) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_CNT_CLRZ (1 << 10) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_PWM_SD (1 << 9) /* shut down the pwm output only used in TCU1 mode */ ++#define TCSR_PWM_HIGH (1 << 8) /* selects an initial output level for pwm output */ ++#define TCSR_PWM_EN (1 << 7) /* pwm pin output enable */ ++#define TCSR_PWM_IN (1 << 6) /* pwm pin output enable */ ++ ++ ++/* ++ * Operating system timer module(OST) address definition ++ */ ++ ++#define OST_DR (0xe0) ++#define OST_CNTL (0xe4) ++#define OST_CNTH (0xe8) ++#define OST_CSR (0xec) ++#define OST_CNTH_BUF (0xfc) ++ ++/* Operating system control register(OSTCSR) */ ++#define OSTCSR_CNT_MD (1 << 15) ++ ++#endif ++ +diff --git a/arch/mips/xburst/soc-x1600/include/war.h b/arch/mips/xburst/soc-x1600/include/war.h +new file mode 100644 +index 000000000..fd1ef3147 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/include/war.h +@@ -0,0 +1,27 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MACH_INGENIC_WAR_H__ ++#define __ASM_MACH_INGENIC_WAR_H__ ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 1 ++#define MIPS_BRIDGE_SYNC_WAR 1 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif ++ +diff --git a/arch/mips/xburst/soc-x1600/libdmmu.c b/arch/mips/xburst/soc-x1600/libdmmu.c +new file mode 100644 +index 000000000..457799b7c +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/libdmmu.c +@@ -0,0 +1,1087 @@ ++/* ++ * This driver is used by VPU driver. ++ * ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: Yan Zhengting ++ * Modify by: Sun Jiwei ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#define print_dbg(f, arg...) printk(KERN_INFO "dpu: %s, %d: " f "\n", __func__, __LINE__, ## arg) ++ ++#define MAP_COUNT 0x10 ++#define MAP_CONUT_MASK 0xff0 ++ ++#define DMMU_PTE_VLD 0x01 ++#define DMMU_PMD_VLD 0x01 ++ ++#define KSEG0_LOW_LIMIT 0x80000000 ++#define KSEG1_HEIGH_LIMIT 0xC0000000 ++ ++enum mem_break{ ++ MODE1, /* 13 24 57 68 911 1012 ... */ ++ MODE2, /* 13 24 35 46 57 68 79 810 ... */ ++ MODE3 /* 12 34 56 78 ... */ ++}; ++ ++LIST_HEAD(handle_list); ++static unsigned long reserved_pte = 0; ++static unsigned long res_pte_paddr; ++ ++struct pmd_node { ++ unsigned int count; ++ unsigned long index; ++ unsigned long page; ++ struct list_head list; ++}; ++ ++struct map_node { ++ struct device *dev; ++ unsigned long start; ++ unsigned long len; ++ struct list_head list; ++}; ++ ++struct dmmu_handle { ++ pid_t tgid; ++ unsigned long pdg; ++ struct mutex lock; ++ struct list_head list; ++ struct list_head pmd_list; ++ struct list_head map_list; ++ struct list_head dev_notifier_list; ++ ++ struct mm_struct *handle_mm; /* mm struct used to match exit_mmap notify */ ++ ++ struct mmu_notifier mn; ++}; ++ ++ ++/* for test */ ++static struct dmmu_handle *find_handle(void); ++static struct dmmu_handle *create_handle(void); ++static void dmmu_cache_wback(struct dmmu_handle *h); ++static int dmmu_mm_dev_release(struct dmmu_handle *h); ++ ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h = NULL; ++ struct map_node *n = NULL; ++ unsigned long *pgd, *pte_phys, *pte; ++ unsigned long virpage_phy; ++ unsigned long v_end = vaddr+len; ++ int found = 0; ++ int index; ++ ++ h = find_handle(); ++ if(!h){ ++ printk("%s find handle err!\n",__func__); ++ return -1; ++ } ++ if (vaddr & 0xfff) { ++ printk("%s addr align page err!\n",__func__); ++ return -1; ++ } ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if((vaddr >= n->start) && ++ ((vaddr+len) <= (n->start + n->len))) { ++ found = 1; ++ break; ++ } ++ } ++ if(!found) { ++ printk("%s addr err!\n",__func__); ++ return -1; ++ } ++ pgd = (unsigned long *)h->pdg; ++ while(vaddr < v_end) { ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ index = ((vaddr & 0x3ff000) >> 12); ++ virpage_phy = pte[index] & ~DMMU_PTE_VLD; ++ dma_cache_wback((unsigned long)phys_to_virt(virpage_phy),PAGE_SIZE); ++ vaddr+=PAGE_SIZE; ++ } ++ return 0; ++} ++ ++EXPORT_SYMBOL(dmmu_flush_cache); ++static int make_smash_list(struct dmmu_handle *h, unsigned long vaddr, unsigned long (**base)[2], unsigned int *len) ++{ ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *pte, *pte_phys; ++ unsigned int i, index; ++ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start) { ++ list_len = (n->len) >> 12; ++ break; ++ } ++ } ++ ++ if (list_len) { ++ list_smash = kmalloc(list_len * 2 * 4, GFP_KERNEL); ++ if (list_smash) { ++ i = 0; ++ while(i < list_len) { ++ list_smash[i][0] = (unsigned long)(vaddr & 0xfffff000); ++ ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ ++ ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++// printk(">>>>>>virt = 0x%lx, phys = 0x%lx\n", vaddr, ++// *((unsigned long int *) (((unsigned long)pte_phys+index*4) | 0xa0000000))); ++ list_smash[i][1] = pte[index]; ++ ++ vaddr+=0x1000; ++ i++; ++ } ++ } ++ } ++ ++ if (list_smash) { ++ *base = list_smash; ++ *len = list_len; ++ return 0; ++ } else { ++ return -1; ++ } ++} ++EXPORT_SYMBOL(dmmu_dump_map); ++ ++int dmmu_dump_map(unsigned long vaddr) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *tmp; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return -1; ++ /* 检查4kå¯¹é½ */ ++ if (vaddr & 0xfff){ ++ return -1; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ unsigned int i; ++ for (i = 0; i phys: 0x%08lx] uncache: 0x%08lx\n", ++ list_smash[i][0],list_smash[i][1],(unsigned long)tmp); ++ ++ printk("value[0] = 0x%08lx, value[1] = 0x%08lx value[2] = 0x%08lx value[1013] = 0x%08lx\n", ++ tmp[0], tmp[1], tmp[2], tmp[1013]); ++ } ++ } ++ ++ mutex_unlock(&h->lock); ++ kfree((void*)list_smash); ++ ++ return 0; ++} ++ ++ /* 13 24 57 68 911 1012 ... */ ++static int smash_mode1(unsigned long (*base)[2], unsigned int len) ++{ ++ unsigned int i; ++ unsigned long tmp; ++ if (len >= 4) { ++ for (i=0; i= 4) { ++ for (i=0; ipdg; ++ unsigned long *pte; ++ unsigned int i, index; ++ ++ for (i=0; i>22; ++ pte = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++ pte[index] = (*base)[i][1]; ++ vaddr+=0x1000; ++ } ++ return 0; ++} ++ ++static int update_process_pte(unsigned long vaddr, unsigned long (**base)[2], unsigned int len) ++{ ++ unsigned int i; ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ spin_lock(¤t->mm->page_table_lock); ++ for (i=0; imm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) ++ return 0; ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) ++ return 0; ++ pte = pte_offset_kernel(pmdir,vaddr); ++ if (pte_present(*pte)){ ++ pte->pte = (*base)[i][1]; ++ } ++ vaddr += 4096; ++ } ++ spin_unlock(¤t->mm->page_table_lock); ++ return 0; ++} ++ ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ struct vm_area_struct * vma; ++ ++ h = find_handle(); ++ if(!h){ ++ h = create_handle(); ++ } ++ if(!h) ++ return -1; ++ ++ /* 检查4kå¯¹é½ */ ++ if (vaddr & 0xfff){ ++ return -1; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ switch (smash_mode) { ++ case MODE1: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode1(list_smash, list_len); ++ break; ++ case MODE2: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode2(list_smash, list_len); ++ break; ++ case MODE3: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode3(list_smash, list_len); ++ break; ++ default: ++ break; ++ } ++ } ++ update_dmmu_pte(h, vaddr, &list_smash, list_len); ++ update_process_pte(vaddr, &list_smash, list_len); ++ ++ dmmu_cache_wback(h); ++ vma = find_vma(current->mm, vaddr); ++ flush_tlb_range(vma, vaddr, vaddr+(list_len*PAGE_SIZE)); ++ ++ mutex_unlock(&h->lock); ++ kfree(list_smash); ++ ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_memory_smash); ++ ++static struct map_node *check_map(struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start && len == n->len) ++ return n; ++ } ++ return NULL; ++} ++ ++static void handle_add_map(struct device *dev,struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct map_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ if(n == NULL) { ++ printk("malloc map_list node failed !!\n"); ++ return; ++ } ++ n->dev = dev; ++ n->start = vaddr; ++ n->len = len; ++ INIT_LIST_HEAD(&n->list); ++ list_add(&n->list,&h->map_list); ++} ++ ++static unsigned int get_pfn(unsigned int vaddr) ++{ ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ pgdir = pgd_offset(current->mm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) { ++ return 0; ++ } ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) { ++ return 0; ++ } ++ pte = pte_offset_kernel(pmdir,vaddr); ++ if (pte_present(*pte)) { ++ ++ return pte_pfn(*pte) << PAGE_SHIFT; ++ } ++ ++ return 0; ++} ++ ++static unsigned long dmmu_v2pfn(unsigned long vaddr) ++{ ++ if(vaddr < KSEG0_LOW_LIMIT) ++ return get_pfn(vaddr); ++ ++ if(vaddr >= KSEG0_LOW_LIMIT && vaddr < KSEG1_HEIGH_LIMIT) ++ return virt_to_phys((void *)vaddr); ++ ++ panic("dmmu_v2pfn error!"); ++ return 0; ++} ++ ++static unsigned long unmap_node(struct pmd_node *n,unsigned long vaddr,unsigned long end,int check) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ int free = !check || (--n->count == 0); ++ struct page *page = NULL; ++ ++ if(vaddr && end) { ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] & MAP_CONUT_MASK) { ++ pte[index] -= MAP_COUNT; ++ } else { ++ page = pfn_to_page(pte[index] >> PAGE_SHIFT); ++ ++ ClearPageReserved(page); ++ pte[index] = reserved_pte; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ } ++ ++ if(free) { ++ ClearPageReserved(virt_to_page((void *)n->page)); ++ free_page(n->page); ++ list_del(&n->list); ++ kfree(n); ++ } ++ ++ return vaddr; ++} ++ ++static unsigned long map_node(struct pmd_node *n,unsigned int vaddr,unsigned int end) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ struct page * page = NULL; ++ unsigned long pfn = 0; ++ ++ ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] == reserved_pte) { ++ ++ mmap_write_lock(current->mm); ++ ++ pfn = dmmu_v2pfn(vaddr) >> PAGE_SHIFT; ++ page = pfn_to_page(pfn); ++ ++ SetPageReserved(page); ++ ++ pte[index] = (pfn << PAGE_SHIFT) | DMMU_PTE_VLD; ++ ++ mmap_write_unlock(current->mm); ++ } else { ++ pte[index] += MAP_COUNT; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ n->count++; ++ return vaddr; ++} ++ ++static struct pmd_node *find_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ if(n->index == (vaddr & 0xffc00000)) ++ return n; ++ } ++ return NULL; ++} ++ ++static struct pmd_node *add_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ int i; ++ unsigned long *pte; ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ struct pmd_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ INIT_LIST_HEAD(&n->list); ++ n->count = 0; ++ n->index = vaddr & 0xffc00000; ++ n->page = __get_free_page(GFP_KERNEL); ++ SetPageReserved(virt_to_page((void *)n->page)); ++ ++ pte = (unsigned long *)n->page; ++ for(i=0;i<1024;i++) ++ pte[i] = reserved_pte; ++ ++ list_add(&n->list, &h->pmd_list); ++ ++ pgd[vaddr>>22] = dmmu_v2pfn(n->page) | DMMU_PMD_VLD; ++ return n; ++} ++ ++static struct dmmu_handle *find_handle(void) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ ++ ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ if(h->tgid == current->tgid) ++ return h; ++ } ++ return NULL; ++} ++ ++/** ++* @brief unmap node from map list, clear each pmd_node in pmd_list, ++* Not free handle, let dmmu_unmap_all do it. ++* ++* @param h ++* ++* @return ++*/ ++static int dmmu_unmap_node_unlock(struct dmmu_handle *h) ++{ ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++ unsigned long vaddr; ++ int len; ++ unsigned long end; ++ ++ struct pmd_node *node; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ /* find and delete a map node from map_list */ ++ cn = list_entry(pos, struct map_node, list); ++ vaddr = cn->start; ++ len = cn->len; ++ end = vaddr + len; ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(node) ++ vaddr = unmap_node(node,vaddr,end,1); ++ } ++ ++ list_del(&cn->list); ++ kfree(cn); ++ } ++ ++ ++ return 0; ++ ++} ++ ++ ++void dmmu_mm_release(struct mmu_notifier *mn, ++ struct mm_struct *mm) ++{ ++ struct dmmu_handle *h = container_of(mn, struct dmmu_handle, mn); ++ ++ printk("===== dmmu release mm (TODO: not checked) ====h: %p\n", h); ++ ++ if(h->handle_mm != mm) { ++ return; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ dmmu_mm_dev_release(h); ++ ++ dmmu_unmap_node_unlock(h); ++ ++ mutex_unlock(&h->lock); ++} ++ ++static const struct mmu_notifier_ops dmmu_mm_notifier_ops = { ++ .release = dmmu_mm_release, ++}; ++ ++ ++static struct dmmu_handle *create_handle(void) ++{ ++ struct dmmu_handle *h; ++ unsigned int pgd_index; ++ unsigned long *pgd; ++ ++ h = kmalloc(sizeof(struct dmmu_handle),GFP_KERNEL); ++ if(!h) ++ return NULL; ++ ++ h->tgid = current->tgid; ++ h->pdg = __get_free_page(GFP_KERNEL); ++ if(!h->pdg) { ++ pr_err("%s %d, Get free page for PGD error\n", ++ __func__, __LINE__); ++ kfree(h); ++ return NULL; ++ } ++ SetPageReserved(virt_to_page((void *)h->pdg)); ++ ++ pgd = (unsigned long *)h->pdg; ++ ++ for (pgd_index=0; pgd_index < PTRS_PER_PGD; pgd_index++) ++ pgd[pgd_index] = res_pte_paddr; ++ ++ INIT_LIST_HEAD(&h->list); ++ INIT_LIST_HEAD(&h->pmd_list); ++ INIT_LIST_HEAD(&h->map_list); ++ INIT_LIST_HEAD(&h->dev_notifier_list); ++ mutex_init(&h->lock); ++ ++ /* register exit_mmap notify */ ++ h->handle_mm = current->mm; ++ ++ h->mn.ops = &dmmu_mm_notifier_ops; ++ ++ mmu_notifier_register(&h->mn, h->handle_mm); ++ ++ list_add(&h->list, &handle_list); ++ ++ return h; ++} ++ ++static int dmmu_make_present(unsigned long addr,unsigned long end) ++{ ++#if 0 ++ unsigned long i; ++ for(i = addr; i < end; i += 4096) { ++ *(volatile unsigned char *)(i) = 0; ++ } ++ *(volatile unsigned char *)(end - 1) = 0; ++ return 0; ++#else ++ int ret, len, write; ++ struct vm_area_struct * vma; ++ unsigned long vm_page_prot; ++ ++ mmap_write_lock(current->mm); ++ vma = find_vma(current->mm, addr); ++ if (!vma) { ++ printk("dmmu_make_present error. addr=%lx len=%lx\n",addr,end-addr); ++ mmap_write_unlock(current->mm); ++ return -1; ++ } ++ ++ if(vma->vm_flags & VM_PFNMAP) { ++ mmap_write_unlock(current->mm); ++ return 0; ++ } ++ write = (vma->vm_flags & VM_WRITE) != 0; ++ BUG_ON(addr >= end); ++ BUG_ON(end > vma->vm_end); ++ ++ vm_page_prot = pgprot_val(vma->vm_page_prot); ++ vma->vm_page_prot = __pgprot(vm_page_prot | _PAGE_VALID| _PAGE_ACCESSED | _PAGE_PRESENT); ++ ++ len = DIV_ROUND_UP(end, PAGE_SIZE) - addr/PAGE_SIZE; ++ ret = get_user_pages(addr, len, write, NULL, NULL); ++ vma->vm_page_prot = __pgprot(vm_page_prot); ++ if (ret < 0) { ++ printk("dmmu_make_present get_user_pages error(%d). addr=%lx len=%lx\n",0-ret,addr,end-addr); ++ mmap_write_unlock(current->mm); ++ return ret; ++ } ++ ++ mmap_write_unlock(current->mm); ++ return ret == len ? 0 : -1; ++#endif ++} ++ ++static void dmmu_cache_wback(struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ dma_cache_wback(h->pdg,PAGE_SIZE); ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ dma_cache_wback(n->page,PAGE_SIZE); ++ } ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h); ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len) ++{ ++ int end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ printk("(pid %d)dmmu_map %lx %lx================================================\n",h->tgid,vaddr,len); ++#endif ++ if(check_map(h,vaddr,len)) ++ { ++ mutex_unlock(&h->lock); ++ return dmmu_v2pfn(h->pdg); ++ } ++ ++ if(dmmu_make_present(vaddr,vaddr+len)) ++ { ++ mutex_unlock(&h->lock); ++ return 0; ++ } ++ ++ handle_add_map(dev,h,vaddr,len); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(!node) { ++ node = add_node(h,vaddr); ++ } ++ vaddr = map_node(node,vaddr,end); ++ } ++ dmmu_cache_wback(h); ++#ifdef DEBUG ++ dmmu_dump_handle(NULL,NULL,h); ++#endif ++ mutex_unlock(&h->lock); ++ ++ return dmmu_v2pfn(h->pdg); ++} ++EXPORT_SYMBOL(dmmu_map); ++ ++static int dmmu_mm_dev_release(struct dmmu_handle *h) ++{ ++ struct dmmu_mm_notifier *n = NULL; ++ struct list_head *pos, *next; ++ ++ list_for_each_safe(pos, next, &h->dev_notifier_list) { ++ n = list_entry(pos, struct dmmu_mm_notifier, list); ++ if(n && n->ops && n->ops->mm_release) { ++ n->ops->mm_release(n->data); ++ } ++ ++ list_del(&n->list); ++ } ++ ++ ++ return 0; ++} ++ ++ ++int dmmu_register_mm_notifier(struct dmmu_mm_notifier *dmn) ++{ ++ int dev_already_registered = 0; ++ struct dmmu_mm_notifier *n = NULL; ++ struct dmmu_handle *h; ++ struct list_head *pos, *next; ++ ++ h = find_handle(); ++ if(!h) { ++ return -EINVAL; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ list_for_each_safe(pos, next, &h->dev_notifier_list) { ++ n = list_entry(pos, struct dmmu_mm_notifier, list); ++ ++ if(n == dmn) { ++ /* already in dev_notifier_list*/ ++ dev_already_registered = 1; ++ } ++ ++ } ++ ++ if(dev_already_registered) { ++ goto out; ++ } ++ ++ list_add_tail(&dmn->list, &h->dev_notifier_list); ++out: ++ mutex_unlock(&h->lock); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_register_mm_notifier); ++ ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len) ++{ ++ unsigned long end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *n; ++ ++ h = find_handle(); ++ if(!h) { ++ return 0; ++ } ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ printk("dmmu_unmap %lx %x**********************************************\n",vaddr,len); ++#endif ++ n = check_map(h,vaddr,len); ++ if(!n) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ if(n->dev != dev) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ ++ list_del(&n->list); ++ kfree(n); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(node) ++ vaddr = unmap_node(node,vaddr,end,1); ++ } ++ ++ if(list_empty(&h->pmd_list) && list_empty(&h->map_list)) { ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ mutex_unlock(&h->lock); ++ ++ mmu_notifier_unregister(&h->mn, h->handle_mm); ++ ++ kfree(h); ++ return 0; ++ } ++ ++ mutex_unlock(&h->lock); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_unmap); ++ ++int dmmu_free_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++ h = find_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ node = find_node(h,cn->start); ++ if(node) ++ unmap_node(node,cn->start,cn->len,1); ++ list_del(&cn->list); ++ kfree(cn); ++ } ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ node = list_entry(pos, struct pmd_node, list); ++ if(node){ ++ printk("WARN: pmd list should NULL\n"); ++ unmap_node(node,0,0,0); ++ } ++ } ++ ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ ++ mutex_unlock(&h->lock); ++ mmu_notifier_unregister(&h->mn, h->handle_mm); ++ kfree(h); ++ return 0; ++} ++ ++/** ++* @brief release all resources, which should be called by driver close ++* ++* @param dev ++* ++* @return ++*/ ++int dmmu_unmap_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++#ifdef DEBUG ++ printk("dmmu_unmap_all\n"); ++#endif ++ ++ h = find_handle(); ++ if(!h) { ++ printk("dmmu unmap all not find hindle, maybe it has benn freed already, name: %s\n", dev->kobj.name); ++ return 0; ++ } ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ if(dev == cn->dev) { ++ dmmu_unmap(dev,cn->start,cn->len); ++ } ++ } ++ ++ ++ if(list_empty(&h->map_list)) ++ dmmu_free_all(dev); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_unmap_all); ++int __init dmmu_init(void) ++{ ++ unsigned int pte_index; ++ unsigned long res_page_paddr; ++ unsigned long reserved_page; ++ unsigned int *res_pte_vaddr; ++ ++ reserved_page = __get_free_page(GFP_KERNEL); ++ if (!reserved_page) { ++ pr_err("%s %d, Get reserved page error\n", ++ __func__, __LINE__); ++ return ENOMEM; ++ } ++ SetPageReserved(virt_to_page((void *)reserved_page)); ++ reserved_pte = dmmu_v2pfn(reserved_page) | DMMU_PTE_VLD; ++ ++ res_page_paddr = virt_to_phys((void *)reserved_page) | 0xFFF; ++ ++ res_pte_vaddr = (unsigned int *)__get_free_page(GFP_KERNEL); ++ if (!res_pte_vaddr) { ++ pr_err("%s %d, Get free page for PTE error\n", ++ __func__, __LINE__); ++ free_page(reserved_page); ++ return ENOMEM; ++ } ++ SetPageReserved(virt_to_page(res_pte_vaddr)); ++ res_pte_paddr = virt_to_phys((void *)res_pte_vaddr) | DMMU_PTE_VLD; ++ ++ for (pte_index = 0; pte_index < PTRS_PER_PTE; pte_index++) ++ res_pte_vaddr[pte_index] = res_page_paddr; ++ ++ ++ ++ return 0; ++} ++arch_initcall(dmmu_init); ++ ++void dmmu_dump_vaddr(unsigned long vaddr) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ unsigned long *pmd,*pte; ++ h = find_handle(); ++ if(!h) { ++ printk("dmmu_dump_vaddr %08lx error - h not found!\n",vaddr); ++ return; ++ } ++ ++ node = find_node(h,vaddr); ++ if(!node) { ++ printk("dmmu_dump_vaddr %08lx error - node not found!\n",vaddr); ++ return; ++ } ++ ++ pmd = (unsigned long *)h->pdg; ++ pte = (unsigned long *)node->page; ++ ++ printk("pmd base = %p; pte base = %p\n",pmd,pte); ++ printk("pmd = %08lx; pte = %08lx\n",pmd[vaddr>>22],pte[(vaddr&0x3ff000)>>12]); ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ { ++ int i = 0; ++ int vaddr = n->start; ++ struct pmd_node *pn = find_node(h,vaddr); ++ unsigned int *pte = (unsigned int *)pn->page; ++ ++ while(vaddr < (n->start + n->len)) { ++ if(i++%8 == 0) ++ printk("\nvaddr %08x : ",vaddr & 0xfffff000); ++ printk("%08x ",pte[(vaddr & 0x3ff000)>>12]); ++ vaddr += 4096; ++ } ++ printk("\n\n"); ++ } ++ } ++} ++ ++static int dmmu_proc_show(struct seq_file *m, void *v) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ volatile unsigned long flags; ++ local_irq_save(flags); ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ dmmu_dump_handle(m, v, h); ++ } ++ local_irq_restore(flags); ++ return 0; ++} ++ ++static int dmmu_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, dmmu_proc_show, PDE_DATA(inode)); ++} ++ ++static const struct proc_ops dmmus_proc_fops ={ ++ .proc_read = seq_read, ++ .proc_open = dmmu_open, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release, ++}; ++ ++static int __init init_dmmu_proc(void) ++{ ++ struct proc_dir_entry *p; ++ p = jz_proc_mkdir("dmmu"); ++ if (!p) { ++ printk("create_proc_entry for common dmmu failed.\n"); ++ return -ENODEV; ++ } ++ proc_create("dmmus", 0600,p,&dmmus_proc_fops); ++ ++ return 0; ++} ++ ++module_init(init_dmmu_proc); +diff --git a/arch/mips/xburst/soc-x1600/pm.c b/arch/mips/xburst/soc-x1600/pm.c +new file mode 100644 +index 000000000..946c483c8 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/pm.c +@@ -0,0 +1,762 @@ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pm.h" ++ ++#define CORE_PD ++#ifdef CORE_PD ++#define X1600_IDLE_PD ++#endif ++#define MEMORY_PD ++ ++//#define PM_TEST ++ ++ ++/*************************************************************************************/ ++#ifdef PM_TEST ++ ++#define GPIO_PB_BASE (0xb0010100) ++#define GPIO_PC_BASE (0xb0010200) ++ ++ ++unsigned int intc0_msk; ++unsigned int intc1_msk; ++unsigned int gpio_pb_int; ++unsigned int gpio_pb_msk; ++unsigned int gpio_pb_pat1; ++unsigned int gpio_pb_pat0; ++unsigned int gpio_pc_int; ++unsigned int gpio_pc_msk; ++unsigned int gpio_pc_pat1; ++unsigned int gpio_pc_pat0; ++ ++unsigned int clk_gate0; ++unsigned int clk_gate1; ++ ++ ++ ++static void enable_pc31_int_low(void) ++{ ++ unsigned int ahb2_intc = 0xb0001000; ++ ++ printk("intc0 src, ahb2_intc + 0x00: %08x\n", *(volatile unsigned int *)(ahb2_intc + 0x00)); ++ printk("intc0 msk, ahb2_intc + 0x04: %08x\n", *(volatile unsigned int *)(ahb2_intc + 0x04)); ++ printk("intc0 pnd, ahb2_intc + 0x10: %08x\n", *(volatile unsigned int *)(ahb2_intc + 0x10)); ++ ++ printk("intc1 src, ahb2_intc + 0x20: %08x\n", *(volatile unsigned int *)(ahb2_intc + 0x20)); ++ printk("intc1 msk, ahb2_intc + 0x24: %08x\n", *(volatile unsigned int *)(ahb2_intc + 0x24)); ++ printk("intc1 pnd, ahb2_intc + 0x30: %08x\n", *(volatile unsigned int *)(ahb2_intc + 0x30)); ++ ++ ++ ++ intc0_msk = *(volatile unsigned int *)0xb0001004; ++ *(volatile unsigned int *)0xb0001004 = intc0_msk & ~(1<<15); // GPIO2 INT MSK ++ gpio_pc_int = *(volatile unsigned int *) (GPIO_PC_BASE + 0x10); ++ gpio_pc_msk = *(volatile unsigned int *) (GPIO_PC_BASE + 0x20); ++ gpio_pc_pat1 = *(volatile unsigned int *)(GPIO_PC_BASE + 0x30); ++ gpio_pc_pat0 = *(volatile unsigned int *)(GPIO_PC_BASE + 0x40); ++ ++ ++ *(volatile unsigned int *)(GPIO_PC_BASE + 0x10) = gpio_pc_int | (1<<31); ++ *(volatile unsigned int *)(GPIO_PC_BASE + 0x20) = gpio_pc_msk & ~(1<<31); ++ *(volatile unsigned int *)(GPIO_PC_BASE + 0x30) = gpio_pc_pat1 & ~(1<<31); ++ *(volatile unsigned int *)(GPIO_PC_BASE + 0x40) = gpio_pc_pat0 & ~(1<<31); // low level trigger int ++ //*(volatile unsigned int *)(GPIO_PB_BASE + 0x40) = gpio_pb_pat0 | ~(1<<23); // high level trigger int ++ ++} ++ ++ ++ ++ ++static void enable_rtc_wakeup(void) ++{ ++ unsigned int tmp; ++ ++ intc1_msk = *(volatile unsigned int *)0xb0001024; ++ *(volatile unsigned int *)0xb0001024 = intc1_msk & ~(1<<0); // RTC INT MSK ++ tmp = rtc_read_reg(0xb0003048); ++ tmp |= (1 << 18); ++ rtc_write_reg(0xb0003048, tmp); ++ ++ tmp = rtc_read_reg(0xb000302c); ++ tmp |= 1; ++ rtc_write_reg(0xb000302c, tmp); ++} ++ ++ ++static void pm_test_config(void) ++{ ++ ++ //clk gate ++ clk_gate0 = cpm_inl(CPM_CLKGR); ++ clk_gate1 = cpm_inl(CPM_CLKGR1); ++ ++ clk_gate0 = 0xffffffff; ++ clk_gate0 &= ~(1 << 31); //ddr ++ clk_gate0 &= ~(1 << 29); //ahb0 ++ clk_gate0 &= ~(1 << 28); //apb0 ++ clk_gate0 &= ~(1 << 27); //rtc ++ clk_gate0 &= ~(1 << 21); //pdma ++ clk_gate0 &= ~(1 << 20); //ost ++ clk_gate0 &= ~(1 << 16); //uart2 ++ ++ clk_gate1 = 0xffffffff; ++ clk_gate1 &= ~(1 << 30); //arb ++ clk_gate1 &= ~(1 << 26); //intc ++ ++ cpm_outl(clk_gate0, CPM_CLKGR); ++ cpm_outl(clk_gate1, CPM_CLKGR1); ++ ++ // wakeup source ++ enable_pc31_int_low(); ++ ++ enable_rtc_wakeup(); ++ ++ ++} ++ ++ ++#endif //PM_TEST ++/*************************************************************************************/ ++ ++static void memory_pd_enter(void) ++{ ++#ifdef MEMORY_PD ++ unsigned int val; ++ val = 0xffffffff; ++ val &= ~(1 << 22); //msc1 ++ val &= ~(1 << 19); //pdma_slp ++ val &= ~(1 << 18); //pdma_sec ++ val &= ~(1 << 17); //pdma ++ val &= ~(1 << 2); //uart2 ++ *(volatile unsigned int *)0xb00000f8 = val; ++ val = 0xfffffff0; ++ *(volatile unsigned int *)0xb00000fc = val; ++#endif ++} ++ ++static void memory_pd_exit(void) ++{ ++#ifdef MEMORY_PD ++ *(volatile unsigned int *)0xb00000f8 = 0; ++ *(volatile unsigned int *)0xb00000fc = 0; ++#endif ++} ++ ++ ++#ifdef DEBUG_PM ++static void x1600_pm_gate_check(void) ++{ ++ unsigned int gate0 = cpm_inl(CPM_CLKGR); ++ unsigned int gate1 = cpm_inl(CPM_CLKGR1); ++ int i; ++ int x; ++ ++ printk("gate0 = 0x%08x\n", gate0); ++ printk("gate1 = 0x%08x\n", gate1); ++ for (i = 0; i < 32; i++) { ++ x = (gate0 >> i) & 1; ++ if (x == 0) ++ printk("warning : bit[%d] in clk gate0 is enabled\n", i); ++ } ++ for (i = 0; i < 32; i++) { ++ x = (gate1 >> i) & 1; ++ if (x == 0) ++ printk("warning : bit[%d] in clk gate1 is enabled\n", i); ++ } ++ ++} ++#endif ++ ++ ++ ++static void ddrp_auto_calibration(void) ++{ ++ unsigned int reg; ++ unsigned int timeout = 0xffffff; ++ unsigned int al, ah; ++ ++ reg = ddr_readl(DDRP_INNOPHY_TRAINING_CTRL); ++ reg &= ~(DDRP_TRAINING_CTRL_DSCSE_BP); ++ ddr_writel(reg, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ reg = ddr_readl(DDRP_INNOPHY_TRAINING_CTRL); ++ reg |= (DDRP_TRAINING_CTRL_DSACE_START); ++ ddr_writel(reg, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ while(!((ddr_readl(DDRP_INNOPHY_CALIB_DONE) & 0x13) == 3) && --timeout) { ++ TCSM_PCHAR('t'); ++ serial_put_hex(ddr_readl(DDRP_INNOPHY_CALIB_DONE)); ++ } ++ ++ if(!timeout) { ++ TCSM_PCHAR('f'); ++ } ++ ++ reg = ddr_readl(DDRP_INNOPHY_TRAINING_CTRL); ++ reg &= ~(1); ++ ddr_writel(reg, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ al = ddr_readl(DDRP_INNOPHY_CALIB_DELAY_AL); ++ ah = ddr_readl(DDRP_INNOPHY_CALIB_DELAY_AH); ++ ++ { ++ unsigned int cycsel, tmp; ++ unsigned int read_data0, read_data1; ++ unsigned int c0, c1; ++ unsigned int max; ++ ++ read_data0 = *(volatile unsigned int *)(0xb3011000 + (0x74 << 2)); ++ read_data1 = *(volatile unsigned int *)(0xb3011000 + (0x75 << 2)); ++ c0 = (read_data0 >> 4) & 0x7; ++ c1 = (read_data1 >> 4) & 0x7; ++ ++ max = max(c0, c1); ++ ++ cycsel = max + 1; ++ ++ tmp = *(volatile unsigned int *)(0xb3011000 + (0xa << 2)); ++ tmp &= ~(7 << 1); ++ tmp |= cycsel << 1; ++ *(volatile unsigned int *)(0xb3011000 + (0xa << 2)) = tmp; ++ ++ ++ tmp = *(volatile unsigned int *)(0xb3011000 + 0x4); ++ tmp |= 1 << 6; ++ *(volatile unsigned int *)(0xb3011000 + (0x1 << 2)) = tmp; ++ } ++ ++ TCSM_PCHAR('B'); ++ ++} ++ ++ ++ ++ ++static void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size) ++{ ++ unsigned int instr; ++ int offset; ++ int i; ++#ifdef DEBUG_PM ++ printk("tcsm addr = %p %p size = %d\n",tcsm_addr,f_addr,size); ++#endif ++ for(i = 0;i < size / 4;i++) { ++ instr = f_addr[i]; ++ if((instr >> 26) == 2){ ++ offset = instr & 0x3ffffff; ++ offset = (offset << 2) - ((unsigned int)f_addr & 0xfffffff); ++ if(offset > 0) { ++ offset = ((unsigned int)tcsm_addr & 0xfffffff) + offset; ++ instr = (2 << 26) | (offset >> 2); ++ } ++ } ++ tcsm_addr[i] = instr; ++ } ++} ++ ++ ++#ifdef X1600_IDLE_PD ++static int soc_pm_idle_pd(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ printk("lpm is idle pd\n"); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ lcr |= 2; ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~ (1<<31); ++ opcr |= (1 << 30); ++ opcr |= (1 << 26); //l2c power down ++ opcr |= 1 << 2; // select RTC clk ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++#else ++static int soc_pm_idle(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ printk("lpm is idle \n"); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 30); ++ opcr &= ~(1 << 31); ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++#endif ++ ++static int soc_pm_sleep(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; ++ lcr |= 1 << 0; // low power mode: SLEEP ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 31); ++ opcr |= (1 << 30); ++ opcr |= (1 << 21); // pdma ram clear sd. ++ opcr &= ~(1 << 4); // exclk disable; ++ opcr |= (1 << 2); // select RTC clk ++ opcr |= (1 << 22); ++ opcr |= (1 << 20); ++ ++#ifdef CORE_PD ++ opcr |= (1 << 3); // power down CPU ++ opcr |= (1 << 26); //L2C power down ++ printk("pd core and l2c\n"); ++#else ++ opcr &= ~(1 << 3); // no power down CPU ++ opcr &= ~(1 << 26); //L2C not power down ++ printk("not pd core and l2c\n"); ++#endif ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++ ++static int soc_post_wakeup(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ lcr &= ~0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ printk("post wakeup!\n"); ++ ++ ++ { ++ /* after power down cpu by set PD in OPCR, resume cpu's frequency and L2C's freq */ ++ unsigned int val; ++ ++ /* change disable */ ++ val = cpm_inl(CPM_CPCCR); ++ val &= ~(1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* resume cpu_div in CPCCR */ ++ val &= ~0xf; ++ val |= sleep_param->cpu_div; ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* change enable */ ++ val |= (1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ while (cpm_inl(CPM_CPCSR) & 1); ++ } ++ ++#ifdef PM_TEST ++ { ++ cpm_outl(clk_gate0, CPM_CLKGR); ++ cpm_outl(clk_gate1, CPM_CLKGR1); ++ ++ *(volatile unsigned int*)(GPIO_PB_BASE + 0x10) = gpio_pb_int; ++ *(volatile unsigned int*)(GPIO_PB_BASE + 0x20) = gpio_pb_msk; ++ *(volatile unsigned int *)(GPIO_PB_BASE + 0x30) = gpio_pb_pat1; ++ *(volatile unsigned int *)(GPIO_PB_BASE + 0x40) = gpio_pb_pat0; ++ ++ *(volatile unsigned int*)(0xb0001004) = intc0_msk; ++ ++ } ++#endif ++ ++ memory_pd_exit(); ++ ++ return 0; ++} ++ ++static noinline void cpu_resume_bootup(void) ++{ ++ TCSM_PCHAR('X'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "move $29, %0 \n\t" ++ "jr.hb %1 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ :"r" (SLEEP_CPU_RESUME_SP), "r"(SLEEP_CPU_RESUME_TEXT) ++ : ++ ); ++ ++} ++#define reg_ddr_phy(x) (*(volatile unsigned int *)(0xb3011000 + ((x) << 2))) ++static noinline void cpu_resume(void) ++{ ++ unsigned int ddrc_ctrl; ++ unsigned int r11s6; ++ unsigned int r16s6; ++ ++ TCSM_PCHAR('R'); ++ ++ /* set reset entry */ ++ r11s6 = __read_32bit_c0_register($11, 6); ++ __asm__ volatile("ehb\n\t"); ++ r16s6 = __read_32bit_c0_register($16, 6); ++ __asm__ volatile("ehb\n\t"); ++ r11s6 |= (1 << 8); ++ r16s6 &= ~0xfffff000; ++ r16s6 |= 0xbfc00000 & 0xfffff000; ++ __write_32bit_c0_register($11, 6, r11s6); ++ __write_32bit_c0_register($16, 6, r16s6); ++ ++ TCSM_PCHAR('D'); ++ ++ if (sleep_param->state == PM_SUSPEND_STANDBY) { ++ /* ddr auto clock gating */ ++ *(volatile unsigned int *)0xb3012068 &= ~(1 << 31); ++ } ++ ++ if (sleep_param->state == PM_SUSPEND_MEM) { ++ int tmp; ++ ++ /* enable pll */ ++ tmp = reg_ddr_phy(0x21); ++ tmp &= ~(1 << 1); ++ reg_ddr_phy(0x21) = tmp; ++ ++ while (!(reg_ddr_phy(0x42) & 0x8)) ++ serial_put_hex(reg_ddr_phy(0x42)); ++ ++ /* dfi_init_start = 0, wait dfi_init_complete */ ++ *(volatile unsigned int *)0xb301208c &= ~1; ++ while(!(*(volatile unsigned int *)0xb301208c & (0x1 << 1))); ++ ++ /* bufferen_core = 1 */ ++ tmp = *(volatile unsigned int *)0xb3012034; ++ tmp &= ~(1 << 2); //high ++ *(volatile unsigned int *)0xb3012034 = tmp; ++ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl &= ~(1<<5); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ while(ddr_readl(DDRC_STATUS) & (1<<2)); ++ ++ TCSM_DELAY(1000); ++ TCSM_PCHAR('1'); ++ ddrp_auto_calibration(); ++ TCSM_PCHAR('2'); ++ ++ /* restore ddr auto-sr */ ++ *(volatile unsigned int *)0xb3011304 = sleep_param->autorefresh; ++ TCSM_PCHAR('3'); ++ ++ /* restore ddr LPEN */ ++ ddr_writel(sleep_param->dlp, DDRC_DLP); ++ ++ /* restore ddr deep power down state */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= sleep_param->pdt; ++ ddrc_ctrl |= sleep_param->dpd; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ TCSM_PCHAR('4'); ++ ++ } ++ ++ ++ TCSM_PCHAR('5'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (restore_goto) ++ : ++ ); ++} ++ ++ ++static noinline void cpu_sleep(void) ++{ ++ ++ TCSM_PCHAR('C'); ++ ++ sleep_param->cpu_div = cpm_inl(CPM_CPCCR) & 0xf; ++ ++ blast_dcache32(); ++ blast_scache32(); ++ __sync(); ++ __fast_iob(); ++ ++ { ++ /* before power down cpu by set PD in OPCR, reduce cpu's frequency as the same as L2C's freq */ ++ unsigned int val, div; ++ ++ /* change disable */ ++ val = cpm_inl(CPM_CPCCR); ++ val &= ~(1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* div cpu = div l2c */ ++ div = val & (0xf << 4); ++ val &= ~0xf; ++ val |= (div >> 4); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* change enable */ ++ val |= (1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ while (cpm_inl(CPM_CPCSR) & 1); ++ } ++ ++ TCSM_PCHAR('D'); ++ ++ ++ if (sleep_param->state == PM_SUSPEND_STANDBY) { ++ /* ddr auto clock gating */ ++ *(volatile unsigned int *)0xb000002c |= (1 << 26); ++ *(volatile unsigned int *)0xb3012068 |= (1 << 31) | (1 << 28); ++ } ++ ++ if (sleep_param->state == PM_SUSPEND_MEM) { ++ unsigned int tmp; ++ unsigned int ddrc_ctrl; ++ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ++ /* save ddr low power state */ ++ sleep_param->pdt = ddrc_ctrl & DDRC_CTRL_PDT_MASK; ++ sleep_param->dpd = ddrc_ctrl & DDRC_CTRL_DPD; ++ sleep_param->dlp = ddr_readl(DDRC_DLP); ++ sleep_param->autorefresh = *(volatile unsigned int *)0xb3011304; ++ ++ /* ddr disable deep power down */ ++ ddrc_ctrl &= ~(DDRC_CTRL_PDT_MASK); ++ ddrc_ctrl &= ~(DDRC_CTRL_DPD); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ /* ddr diasble LPEN*/ ++ ddr_writel(0, DDRC_DLP); ++ ++ /* ddr disable auto-sr */ ++ *(volatile unsigned int *)0xb3011304 = 0; ++ tmp = *(volatile unsigned int *)0xa0000000; ++ ++ ++ /* DDR self refresh, */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= 1 << 5; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ while(!(ddr_readl(DDRC_STATUS) & (1<<2))); ++ ++ ++ /* bufferen_core = 0 */ ++ tmp = *(volatile unsigned int *)0xb3012034; ++ tmp |= (1 << 2); //low ++ *(volatile unsigned int *)0xb3012034 = tmp; ++ ++ ++ ++ /* dfi_init_start = 1 */ ++ *(volatile unsigned int *)0xb301208c |= 1; ++ ++ { ++ int i; ++ for (i = 0; i < 4; i++) { ++ ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ } ++ } ++ ++ /* disable pll */ ++ reg_ddr_phy(0x21) |= (1 << 1); ++ } ++ ++ TCSM_PCHAR('W'); ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "wait \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ ); ++ ++ TCSM_PCHAR('N'); ++ ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (SLEEP_CPU_RESUME_BOOTUP_TEXT) ++ : ++ ); ++ TCSM_PCHAR('F'); ++} ++ ++ ++int x1600_pm_enter(suspend_state_t state) ++{ ++ extern volatile u8 *uart_base; ++ unsigned int r11s6; ++ unsigned int r16s6; ++ ++ ++ printk("x1600 pm enter!!\n"); ++ ++ *(volatile unsigned int *)0xb0000020 &= ~(1 << 21); ++ set_c0_status(0x100 << 2); ++ ++ sleep_param->uart_base = (unsigned int)uart_base; ++ ++ sleep_param->state = state; ++ ++#ifdef DEBUG_PM ++ printk("sleep_param->state addr = %d\n", sleep_param->state); ++#endif ++ ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_RESUME_BOOTUP_TEXT, (unsigned int *)cpu_resume_bootup, SLEEP_CPU_RESUME_BOOTUP_LEN); ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_RESUME_TEXT, (unsigned int *)cpu_resume, SLEEP_CPU_RESUME_LEN); ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_SLEEP_TEXT, (unsigned int *)cpu_sleep, SLEEP_CPU_SLEEP_LEN); ++ ++ if (state == PM_SUSPEND_STANDBY) { ++#ifdef X1600_IDLE_PD ++ soc_pm_idle_pd(); ++#else ++ soc_pm_idle(); ++#endif ++ } else if (state == PM_SUSPEND_MEM) { ++ soc_pm_sleep(); ++ } else { ++ printk("WARNING : unsupport pm suspend state\n"); ++ } ++ ++ ++ /* set reset entry */ ++ r11s6 = __read_32bit_c0_register($11, 6); ++ __asm__ volatile("ehb\n\t"); ++ r16s6 = __read_32bit_c0_register($16, 6); ++ __asm__ volatile("ehb\n\t"); ++ r11s6 |= (1 << 8); ++ r16s6 &= ~0xfffff000; ++ r16s6 |= SLEEP_CPU_RESUME_BOOTUP_TEXT & 0xfffff000; ++ __write_32bit_c0_register($11, 6, r11s6); ++ __write_32bit_c0_register($16, 6, r16s6); ++ ++ ++ memory_pd_enter(); ++ ++#ifdef PM_TEST ++ pm_test_config(); ++#endif ++ ++#ifdef DEBUG_PM ++ printk("LCR: %08x\n", cpm_inl(CPM_LCR)); ++ printk("OPCR: %08x\n", cpm_inl(CPM_OPCR)); ++ x1600_pm_gate_check(); ++ printk("mem_pd0 = 0x%x\n", *(volatile unsigned int *)0xb00000f8); ++ printk("mem_pd1 = 0x%x\n", *(volatile unsigned int *)0xb00000fc); ++ printk("intc0 mask = 0x%x\n", *(volatile unsigned int *)0xb0001004); ++ printk("intc1 mask = 0x%x\n", *(volatile unsigned int *)0xb0001024); ++#endif ++ ++ mb(); ++ save_goto((unsigned int)SLEEP_CPU_SLEEP_TEXT); ++ mb(); ++ ++ soc_post_wakeup(); ++ ++ return 0; ++} ++ ++static int x1600_pm_begin(suspend_state_t state) ++{ ++ printk("x1600 suspend begin\n"); ++ return 0; ++} ++ ++static void x1600_pm_end(void) ++{ ++ printk("x1600 pm end!\n"); ++} ++static int x1600_suspend_prepare(void) ++{ ++ printk("x1600 suspend prepare\n"); ++ ++ return 0; ++} ++static void x1600_suspend_finish(void) ++{ ++ printk("x1600 suspend finish"); ++} ++ ++static int ingenic_pm_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++static const struct platform_suspend_ops x1600_pm_ops = { ++ .valid = ingenic_pm_valid, ++ .begin = x1600_pm_begin, ++ .enter = x1600_pm_enter, ++ .end = x1600_pm_end, ++ .prepare = x1600_suspend_prepare, ++ .finish = x1600_suspend_finish, ++}; ++ ++/* ++ * Initialize suspend interface ++ */ ++static int __init pm_init(void) ++{ ++ ++ suspend_set_ops(&x1600_pm_ops); ++ ++ ++ return 0; ++} ++ ++late_initcall(pm_init); +diff --git a/arch/mips/xburst/soc-x1600/pm.h b/arch/mips/xburst/soc-x1600/pm.h +new file mode 100644 +index 000000000..7be158159 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/pm.h +@@ -0,0 +1,136 @@ ++ ++ ++ ++struct sleep_param { ++ suspend_state_t state; ++ unsigned int pdt; ++ unsigned int dpd; ++ unsigned int dlp; ++ unsigned int autorefresh; ++ unsigned int cpu_div; ++ unsigned int uart_base; ++}; ++ ++ ++/* ++ * ++ * |-----------------------| ++ * | | ++ * | | ++ * | RESUME_SP | ++ * | | ++ * |-----------------------| ++ * | | ++ * | PARAM | ++ * | | ++ * |-----------------------| ++ * | | ++ * | | ++ * | SLEEP_TEXT | ++ * | | ++ * | | ++ * |-----------------------| ++ * | | ++ * | | ++ * | RESUME_TEXT | ++ * | | ++ * | | ++ * |-----------------------| ++ * | | ++* | RESUME_BOOTU_TEXTP | ++ * | | ++ * |-----------------------| <------------ TCSM_START 0xb3422000 ++ * ++ */ ++ ++ ++#define SLEEP_MEMORY_START 0xb3422000 ++#define SLEEP_MEMORY_END 0xb3429ff8 ++#define SLEEP_RESUME_SP SLEEP_MEMORY_END ++#define SLEEP_RESUME_BOOTUP_TEXT SLEEP_MEMORY_START ++ ++#define SLEEP_CPU_RESUME_BOOTUP_TEXT SLEEP_RESUME_BOOTUP_TEXT ++#define SLEEP_CPU_RESUME_BOOTUP_LEN 64 // 16 instructions ++#define SLEEP_CPU_RESUME_TEXT (SLEEP_CPU_RESUME_BOOTUP_TEXT + SLEEP_CPU_RESUME_BOOTUP_LEN) ++#define SLEEP_CPU_RESUME_LEN (4096) ++#define SLEEP_CPU_SLEEP_TEXT (SLEEP_CPU_RESUME_TEXT + SLEEP_CPU_RESUME_LEN) ++#define SLEEP_CPU_SLEEP_LEN (3072) ++#define SLEEP_CPU_PARAM_ADDR (SLEEP_CPU_SLEEP_TEXT + SLEEP_CPU_SLEEP_LEN) ++#define SLEEP_CPU_PARAM_SIZE (sizeof(struct sleep_param)) ++#define SLEEP_CPU_RESUME_SP SLEEP_RESUME_SP ++ ++#define sleep_param ((struct sleep_param *)SLEEP_CPU_PARAM_ADDR) ++ ++ ++ ++extern long long save_goto(unsigned int func); ++extern int restore_goto(unsigned int func); ++ ++ ++#define reg_ddr_phy(x) (*(volatile unsigned int *)(0xb3011000 + ((x) << 2))) ++ ++#define rtc_read_reg(reg) ({ \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++ *(volatile unsigned int *)reg;\ ++}) ++ ++#define rtc_write_reg(reg, val) do{ \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++ *(volatile unsigned int *)0xb000303c = 0xa55a; \ ++ while (!((*(volatile unsigned int *)0xb000303c >> 31) & 0x1) ); \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++ *(volatile unsigned int *)reg = val; \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++}while(0) ++ ++ ++ ++ ++/************************************************ ++ * debug interface ++ ***********************************************/ ++ ++#define DEBUG_PM ++#define PRINT_DEBUG ++ ++ ++#define U_IOBASE (sleep_param->uart_base) ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++ ++#ifdef PRINT_DEBUG ++#define TCSM_PCHAR(x) \ ++ *((volatile unsigned int*)(U_IOBASE+OFF_TDR)) = x; \ ++while ((*((volatile unsigned int*)(U_IOBASE + OFF_LSR)) & (LSR_TDRQ | LSR_TEMT)) != (LSR_TDRQ | LSR_TEMT)) ++#else ++#define TCSM_PCHAR(x) ++#endif ++ ++#define TCSM_DELAY(x) \ ++ do{ \ ++ register unsigned int i = x; \ ++ while(i--) \ ++ __asm__ volatile("nop\n\t"); \ ++ }while(0) ++ ++static inline void serial_put_hex(unsigned int x) { ++ int i; ++ unsigned int d; ++ for(i = 7;i >= 0;i--) { ++ d = (x >> (i * 4)) & 0xf; ++ if(d < 10) d += '0'; ++ else d += 'A' - 10; ++ TCSM_PCHAR(d); ++ } ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++} ++ ++ ++ ++ +diff --git a/arch/mips/xburst/soc-x1600/regs_save_restore.S b/arch/mips/xburst/soc-x1600/regs_save_restore.S +new file mode 100644 +index 000000000..abe8b49df +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/regs_save_restore.S +@@ -0,0 +1,190 @@ ++#include ++#include ++ ++#define CP0_PAGEMASK $5,0 ++#define CP0_STATUS $12,0 ++#define CP0_INTCTL $12,1 ++#define CP0_CAUSE $13,0 ++#define CP0_EBASE $15,1 ++#define CP0_CONFIG $16,0 ++#define CP0_CONFIG1 $16,1 ++#define CP0_CONFIG2 $16,2 ++#define CP0_CONFIG3 $16,3 ++#define CP0_CONFIG4 $16,4 ++#define CP0_CONFIG5 $16,5 ++#define CP0_CONFIG7 $16,7 ++#define CP0_LLADDR $17,0 ++#define CP0_WATCHLo $18,0 ++#define CP0_WATCHHI $19,0 ++#define CP0_ERRCTL $26,0 ++#define CP0_CONTEXT $4,0 ++#define CP0_KSCRATCH1 $31,2 ++#define CP0_KSCRATCH2 $31,3 ++#define CP0_KSCRATCH3 $31,4 ++#define CP0_KSCRATCH4 $31,5 ++#define CP0_KSCRATCH5 $31,6 ++#define CP0_KSCRATCH6 $31,7 ++ ++ .data ++ .global _regs_stack ++_regs_stack: ++ .align 5 ++ .space 140,0 ++ ++ .text ++ .global save_goto ++ .align 2 ++ .ent save_goto,0 ++ LEAF(save_goto) ++save_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sw s0,0(k0) ++ sw s1,4(k0) ++ sw s2,8(k0) ++ sw s3,12(k0) ++ sw s4,16(k0) ++ sw s5,20(k0) ++ sw s6,24(k0) ++ sw s7,28(k0) ++ sw gp,32(k0) ++ sw sp,36(k0) ++ sw fp,40(k0) ++ sw ra,44(k0) ++ ++ mfc0 k1,CP0_PAGEMASK ++ sw k1,48(k0) ++ mfc0 k1,CP0_STATUS ++ sw k1,52(k0) ++ mfc0 k1,CP0_INTCTL ++ sw k1,56(k0) ++ mfc0 k1,CP0_CAUSE ++ sw k1,60(k0) ++ mfc0 k1,CP0_EBASE ++ sw k1,64(k0) ++ mfc0 k1,CP0_CONFIG ++ sw k1,68(k0) ++ mfc0 k1,CP0_CONFIG1 ++ sw k1,72(k0) ++ mfc0 k1,CP0_CONFIG2 ++ sw k1,76(k0) ++ mfc0 k1,CP0_CONFIG3 ++ sw k1,80(k0) ++ mfc0 k1,CP0_CONFIG4 ++ sw k1,84(k0) ++ mfc0 k1,CP0_CONFIG5 ++ sw k1,88(k0) ++ mfc0 k1,CP0_CONFIG7 ++ sw k1,92(k0) ++ mfc0 k1,CP0_LLADDR ++ sw k1,96(k0) ++ mfc0 k1,CP0_WATCHLo ++ sw k1,100(k0) ++ mfc0 k1,CP0_WATCHHI ++ sw k1,104(k0) ++ mfc0 k1,CP0_ERRCTL ++ sw k1,108(k0) ++ mfc0 k1,CP0_CONTEXT ++ sw k1,112(k0) ++ mfc0 k1,CP0_KSCRATCH1 ++ sw k1,116(k0) ++ mfc0 k1,CP0_KSCRATCH2 ++ sw k1,120(k0) ++ mfc0 k1,CP0_KSCRATCH3 ++ sw k1,124(k0) ++ mfc0 k1,CP0_KSCRATCH4 ++ sw k1,128(k0) ++ mfc0 k1,CP0_KSCRATCH5 ++ sw k1,132(k0) ++ mfc0 k1,CP0_KSCRATCH6 ++ sw k1,136(k0) ++ ++ jr.hb a0 ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(save_goto) ++ ++ .text ++ .global restore_goto ++ .align 2 ++ .ent restore_goto,0 ++ LEAF(restore_goto) ++restore_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ lw s0,0(k0) ++ lw s1,4(k0) ++ lw s2,8(k0) ++ lw s3,12(k0) ++ lw s4,16(k0) ++ lw s5,20(k0) ++ lw s6,24(k0) ++ lw s7,28(k0) ++ lw gp,32(k0) ++ lw sp,36(k0) ++ lw fp,40(k0) ++ lw ra,44(k0) ++ ++ lw k1,48(k0) ++ mtc0 k1,CP0_PAGEMASK ++ lw k1,52(k0) ++ mtc0 k1,CP0_STATUS ++ lw k1,56(k0) ++ mtc0 k1,CP0_INTCTL ++ lw k1,60(k0) ++ mtc0 k1,CP0_CAUSE ++ lw k1,64(k0) ++ mtc0 k1,CP0_EBASE ++ lw k1,68(k0) ++ mtc0 k1,CP0_CONFIG ++ lw k1,72(k0) ++ mtc0 k1,CP0_CONFIG1 ++ lw k1,76(k0) ++ mtc0 k1,CP0_CONFIG2 ++ lw k1,80(k0) ++ mtc0 k1,CP0_CONFIG3 ++ lw k1,84(k0) ++ mtc0 k1,CP0_CONFIG4 ++ lw k1,88(k0) ++ mtc0 k1,CP0_CONFIG5 ++ lw k1,92(k0) ++ mtc0 k1,CP0_CONFIG7 ++ lw k1,96(k0) ++ mtc0 k1,CP0_LLADDR ++ lw k1,100(k0) ++ mtc0 k1,CP0_WATCHLo ++ lw k1,104(k0) ++ mtc0 k1,CP0_WATCHHI ++ lw k1,108(k0) ++ mtc0 k1,CP0_ERRCTL ++ lw k1,112(k0) ++ mtc0 k1,CP0_CONTEXT ++ lw k1,116(k0) ++ mtc0 k1,CP0_KSCRATCH1 ++ lw k1,120(k0) ++ mtc0 k1,CP0_KSCRATCH2 ++ lw k1,124(k0) ++ mtc0 k1,CP0_KSCRATCH3 ++ lw k1,128(k0) ++ mtc0 k1,CP0_KSCRATCH4 ++ lw k1,132(k0) ++ mtc0 k1,CP0_KSCRATCH5 ++ lw k1,136(k0) ++ mtc0 k1,CP0_KSCRATCH6 ++ ++ jr.hb ra ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(restore_goto) +diff --git a/arch/mips/xburst/soc-x1600/regs_save_restore.py b/arch/mips/xburst/soc-x1600/regs_save_restore.py +new file mode 100755 +index 000000000..df57fff6e +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/regs_save_restore.py +@@ -0,0 +1,123 @@ ++#!/usr/bin/env python ++import os ++import string ++ ++common_regs=["s0","s1","s2","s3", ++ "s4","s5","s6","s7", ++ "gp","sp","fp","ra"] ++cp0_regs=[ ++ ["CP0_PAGEMASK","$5","0"], ++ ["CP0_STATUS","$12","0"], ++ ["CP0_INTCTL","$12","1"], ++ ["CP0_CAUSE","$13","0"], ++ ["CP0_EBASE","$15","1"], ++ ["CP0_CONFIG","$16","0"], ++ ["CP0_CONFIG1","$16","1"], ++ ["CP0_CONFIG2","$16","2"], ++ ["CP0_CONFIG3","$16","3"], ++ ["CP0_CONFIG4", "$16", "4"], ++ ["CP0_CONFIG5", "$16", "5"], ++ ["CP0_CONFIG7","$16","7"], ++ ["CP0_LLADDR","$17","0"], ++ ["CP0_WATCHLo","$18","0"], ++ ["CP0_WATCHHI","$19","0"], ++ ["CP0_ERRCTL","$26","0"], ++ ["CP0_CONTEXT","$4","0"], ++ ["CP0_KSCRATCH1","$31","2"], ++ ["CP0_KSCRATCH2","$31","3"], ++ ["CP0_KSCRATCH3","$31","4"], ++ ["CP0_KSCRATCH4","$31","5"], ++ ["CP0_KSCRATCH5","$31","6"], ++ ["CP0_KSCRATCH6","$31","7"], ++ ] ++def gen_get_array_size(): ++ size=0 ++ size+=len(common_regs) ++ size+=len(cp0_regs) ++ return size ++ ++def gen_print_head_and_macro(): ++ print("#include ") ++ print("#include ") ++ print("") ++ for s in cp0_regs: ++ print("#define %s\t%s,%s" %(s[0],s[1],s[2])) ++ print("") ++def gen_define_global_arg(str, num): ++ print("\t.data") ++ print("\t.global %s" %(str)) ++ print("%s:" %(str)) ++ print("\t.align 5") ++ print("\t.space %s,0" %(num)) ++ print("") ++ ++def gen_save_common_regs(index): ++ for s in common_regs: ++ print("\tsw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_restore_common_regs(index): ++ for s in common_regs: ++ print("\tlw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_save_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tmfc0\tk1,%s" % (s[0])) ++ print("\tsw\tk1,%d(k0)" % (index)) ++ index=index+4 ++ return index ++def gen_restore_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tlw\tk1,%d(k0)" % (index)) ++ print("\tmtc0\tk1,%s" % (s[0])) ++ index=index+4 ++ return index ++def gen_print_function(f_name, regs_stack): ++ index=0 ++ print("\t.text") ++ print("\t.global %s" %(f_name)) ++ print("\t.align 2") ++ print("\t.ent %s,0" %(f_name)) ++ print("%s:" %(f_name)) ++ print("\t.set\tpush") ++ print("\t.set\tnoreorder") ++ print("\t.set\tnoat") ++ print("") ++ print("\tla\tk0, %s" %(regs_stack)) ++ if f_name == "save_goto": ++ index = gen_save_common_regs(index) ++ print("") ++ index = gen_save_cp0_regs(index) ++ print("") ++ print("\tjr.hb\ta0") ++ print("\tnop") ++ elif f_name == "restore_goto": ++ index = gen_restore_common_regs(index) ++ print("") ++ index = gen_restore_cp0_regs(index) ++ print("") ++ print("\tjr.hb\tra") ++ print("\tnop") ++ else: ++ print("not support") ++ print("") ++ print("\t.set\tat") ++ print("\t.set\treorder") ++ print("\t.set\tpop") ++ print("\tEND(%s)" %(f_name)) ++ ++ ++def main(): ++ regs_size=gen_get_array_size() ++ regs_size*=4 ++ ++ gen_print_head_and_macro() ++ gen_define_global_arg("_regs_stack", regs_size) ++ gen_print_function("save_goto", "_regs_stack") ++ print("") ++ gen_print_function("restore_goto", "_regs_stack") ++ pass ++ ++if __name__ == '__main__': ++ main() +diff --git a/arch/mips/xburst/soc-x1600/setup.c b/arch/mips/xburst/soc-x1600/setup.c +new file mode 100644 +index 000000000..ef88c0816 +--- /dev/null ++++ b/arch/mips/xburst/soc-x1600/setup.c +@@ -0,0 +1,93 @@ ++/* ++ * INGENIC SOC Setup ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++extern void *get_fdt_addr(void); ++ ++ ++static void __init cpm_reset(void) ++{ ++#ifndef CONFIG_FPGA_TEST ++ unsigned long clkgr = cpm_inl(CPM_CLKGR); ++ ++ clkgr &= ~(1 << 28 /* DES */ ++ | 1 << 26 /* TVE */ ++ | 1 << 13 /* SADC */ ++ ); ++ cpm_outl(clkgr, CPM_CLKGR); ++ ++ /* TODO set default clkgr here */ ++#endif ++} ++ ++static int __init setup_init(void) ++{ ++ cpm_reset(); ++ /* Set bus priority here */ ++ *(volatile unsigned int *)0xb34f0240 = 0x00010003; ++ *(volatile unsigned int *)0xb34f0244 = 0x00010003; ++ ++ return 0; ++} ++ ++ ++void __init plat_mem_setup(void) ++{ ++ ++ set_io_port_base(IO_BASE); ++ ++ /*Not have ioport*/ ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0xffffffff; ++ iomem_resource.start = 0x00000000; ++ iomem_resource.end = 0xffffffff; ++ ++ setup_init(); ++ ++ __dt_setup_arch(get_fdt_addr()); ++ ++ early_init_fdt_scan_reserved_mem(); ++ ++ return; ++} ++ ++void __init device_tree_init(void) ++{ ++ unflatten_and_copy_device_tree(); ++} ++ ++static int __init plat_of_populate(void) ++{ ++ of_platform_default_populate(NULL, NULL, NULL); ++ return 0; ++} ++arch_initcall(plat_of_populate); ++ ++void __init plat_time_init(void) ++{ ++ of_clk_init(NULL); ++ ++ timer_probe(); ++} ++ ++void __init arch_init_irq(void) { ++ ++ irqchip_init(); ++} +diff --git a/arch/mips/xburst2/Kconfig b/arch/mips/xburst2/Kconfig +new file mode 100644 +index 000000000..4195dfd71 +--- /dev/null ++++ b/arch/mips/xburst2/Kconfig +@@ -0,0 +1,105 @@ ++if MACH_XBURST2 ++ ++menu "SOC Type Selection" ++ depends on MACH_XBURST2 ++ ++ ++choice ++ prompt "SOC types" ++ depends on MACH_XBURST2 ++ default SOC_X2000 ++ ++config SOC_X2000 ++ bool "x2000" ++ select IRQ_INGENIC_CPU ++ select CLK_X2000 ++ select INGENIC_INTC_CHIP ++ select PINCTRL ++ select PINCTRL_INGENIC_V2 ++ select TIMER_OF ++ select CLKDEV_LOOKUP ++ select CLKSRC_INGENIC_CORE_OST ++ select MMU_NOTIFIER ++ ++config SOC_X2500 ++ bool "x2500" ++ select IRQ_INGENIC_CPU ++ select CLK_X2500 ++ select INGENIC_INTC_CHIP ++ select PINCTRL ++ select PINCTRL_INGENIC_V2 ++ select TIMER_OF ++ select CLKDEV_LOOKUP ++ select CLKSRC_INGENIC_CORE_OST ++ select MMU_NOTIFIER ++ ++config SOC_M300 ++ bool "m300" ++ select IRQ_INGENIC_CPU ++ select CLK_M300 ++ select INGENIC_INTC_CHIP ++ select PINCTRL ++ select PINCTRL_INGENIC_V2 ++ select TIMER_OF ++ select CLKDEV_LOOKUP ++ select CLKSRC_INGENIC_CORE_OST ++ select MMU_NOTIFIER ++ ++config SOC_X2100 ++ bool "x2100" ++ select IRQ_INGENIC_CPU ++ select CLK_X2100 ++ select INGENIC_INTC_CHIP ++ select PINCTRL ++ select PINCTRL_INGENIC_V2 ++ select TIMER_OF ++ select CLKDEV_LOOKUP ++ select CLKSRC_INGENIC_CORE_OST ++ select MMU_NOTIFIER ++ ++endchoice ++ ++config INGENIC_BUILTIN_DTB ++ select BUILTIN_DTB ++ depends on MACH_XBURST2 ++ bool "Ingenic Device Tree build into Kernel." ++ default y ++ ++source "arch/mips/xburst2/soc-x2000/Kconfig.DT" ++source "arch/mips/xburst2/soc-x2500/Kconfig.DT" ++source "arch/mips/xburst2/soc-m300/Kconfig.DT" ++ ++ ++config RAW_BOOT ++ bool "Raw Boot Kernel" ++ select BOOT_RAW ++ default n ++ ++config EXTAL_CLOCK ++ depends on MACH_XBURST2 ++ int "extal clock in MHz" ++ default 24 ++ ++config FPGA_TEST ++ depends on MACH_XBURST2 ++ bool "FPGA_TEST" ++ default n ++ ++config INGENIC_GPT_CHECK ++ depends on MACH_XBURST2 ++ bool "The physical space is larger than the virtual space" ++ default y ++ ++config XBURST2_CPU_TEST ++ depends on MACH_XBURST2 ++ bool "xburst2 cpu ddr test" ++ default n ++ ++ ++config FASTBOOT ++ bool "FastBoot" ++ depends on SOC_X2000 || SOC_M300 || SOC_X2100 ++ ++endmenu ++ ++endif +diff --git a/arch/mips/xburst2/Makefile b/arch/mips/xburst2/Makefile +new file mode 100644 +index 000000000..77dcad13f +--- /dev/null ++++ b/arch/mips/xburst2/Makefile +@@ -0,0 +1,7 @@ ++obj-y += core/ ++obj-y += common/ ++ ++obj-$(CONFIG_SOC_X2000) += soc-x2000/ ++obj-$(CONFIG_SOC_X2500) += soc-x2500/ ++obj-$(CONFIG_SOC_M300) += soc-m300/ ++obj-$(CONFIG_SOC_X2100) += soc-x2000/ +diff --git a/arch/mips/xburst2/Platform b/arch/mips/xburst2/Platform +new file mode 100644 +index 000000000..cba9ceb7e +--- /dev/null ++++ b/arch/mips/xburst2/Platform +@@ -0,0 +1,7 @@ ++load-$(CONFIG_MACH_XBURST2) += 0xffffffff80010000 ++cflags-$(CONFIG_MACH_XBURST2) += -I$(srctree)/arch/mips/xburst2/core/include ++ ++cflags-$(CONFIG_SOC_X2000) += -I$(srctree)/arch/mips/xburst2/soc-x2000/include ++cflags-$(CONFIG_SOC_X2500) += -I$(srctree)/arch/mips/xburst2/soc-x2500/include ++cflags-$(CONFIG_SOC_M300) += -I$(srctree)/arch/mips/xburst2/soc-m300/include ++cflags-$(CONFIG_SOC_X2100) += -I$(srctree)/arch/mips/xburst2/soc-x2000/include +diff --git a/arch/mips/xburst2/common/Makefile b/arch/mips/xburst2/common/Makefile +new file mode 100644 +index 000000000..52af9c04a +--- /dev/null ++++ b/arch/mips/xburst2/common/Makefile +@@ -0,0 +1,11 @@ ++ ++# add object if need ++ ++#obj-y += prom.o ++obj-y += get-cpu-features.o ++#obj-y += proc-exec.o ++obj-y += proc.o ++obj-y += mxuv3.o ++#obj-y += jz_notifier.o ++obj-$(CONFIG_XBURST2_CPU_TEST) += cpu_ddr_test/ ++#obj-y += initrd-check.o +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/Makefile b/arch/mips/xburst2/common/cpu_ddr_test/Makefile +new file mode 100644 +index 000000000..325683434 +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/Makefile +@@ -0,0 +1,11 @@ ++ ++obj-y += multithread_test.o ++obj-y += ddr_bandwidth_monitor.o ++obj-y += ddr_change_freq.o ++obj-y += l2c_test.o ++obj-y += cpu_spinlock_test.o ++obj-y += cpu_ccu_test.o ++obj-y += raw_dma_test.o ++obj-y += cpu_dma_test.o ++obj-y += cpu_watch_test.o ++ccflags-y += -Wno-unused-function +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/cpu_ccu_test.c b/arch/mips/xburst2/common/cpu_ddr_test/cpu_ccu_test.c +new file mode 100644 +index 000000000..62d34e66f +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/cpu_ccu_test.c +@@ -0,0 +1,70 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "multithread_test.h" ++#include ++ ++#define PALLADIUM_TRIGER_2() do {\ ++ volatile unsigned int *a; \ ++ a = (unsigned int *)0xAFFFFFFC; \ ++ *a = *a; \ ++ } while(0) ++ ++struct cpu_ccu_test { ++ void* multithread; ++ unsigned int cnt; ++} cpu_ccu; ++ ++ ++static int cpu_ccu_test_func(void * param) ++{ ++ struct cpu_ccu_test *p = (struct cpu_ccu_test *)param; ++ unsigned int cscr, cssr, csrr, rer; ++ ++ cscr = get_ccu_cscr(); ++ ++ cssr = get_ccu_cssr(); ++ ++ csrr = get_ccu_csrr(); ++ ++ rer = get_ccu_rer(); ++ ++ p->cnt++; ++ ++ if(p->cnt == 1000) { ++ p->cnt = 0; ++ printk("%s: cscr=0x%08x, cssr=0x%08x, csrr=0x%08x, rer=0x%08x\n", __func__, cscr, cssr, csrr, rer); ++ } ++#ifdef CONFIG_FPGA_TEST ++ mdelay(100); ++#endif ++ return 0; ++} ++ ++static int __init cpu_ccu_test_init(void) ++{ ++ cpu_ccu.multithread = multithread_test_init("cpu_ccu_test",1); ++ ++ if(cpu_ccu.multithread){ ++ multithread_test_add_func(cpu_ccu.multithread,"cpu_ccu_test",cpu_ccu_test_func,(void*)&cpu_ccu); ++ } ++ return 0; ++} ++static void __exit cpu_ccu_test_deinit(void) ++{ ++} ++ ++late_initcall(cpu_ccu_test_init); ++module_exit(cpu_ccu_test_deinit); +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/cpu_dma_test.c b/arch/mips/xburst2/common/cpu_ddr_test/cpu_dma_test.c +new file mode 100644 +index 000000000..68b428034 +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/cpu_dma_test.c +@@ -0,0 +1,269 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++#include ++ ++#include "multithread_test.h" ++#include "../../../../../drivers/dma/ingenic/ingenic_dma.h" ++ ++struct cpu_dma_test{ ++ void* multithread; ++ struct list_head dma_top; ++}cpu_dma; ++struct dma_channel { ++ struct list_head list; ++ struct dma_chan *chan; ++ struct hdma_desc *desc; ++ void *from; ++ unsigned long pfrom; ++ void *to; ++ unsigned long pto; ++ unsigned long test_len; ++ struct mutex lock; ++ unsigned long test_cnt; ++}; ++static void init_buf(struct dma_channel *dc) ++{ ++ int i; ++ ++ unsigned long *p = dc->from; ++ struct device *dev; ++ dev = (struct device *)kzalloc(sizeof(struct device), GFP_KERNEL); ++ for(i = 0;i < dc->test_len/4;i++){ ++ p[i] = (unsigned int)p + i * 4; ++ } ++ ++ p = dc->to; ++ for(i = 0;i < dc->test_len/4;i++){ ++ p[i] = 0x5a5a5a5a; ++ } ++ dma_cache_sync(dev,dc->from,dc->test_len,DMA_TO_DEVICE); ++ dma_cache_sync(dev,dc->to,dc->test_len,DMA_FROM_DEVICE); ++} ++ ++static int cpu_dma_test_func_nowait(void * param) ++{ ++ struct dma_channel *dc = (struct dma_channel *)param; ++ int i; ++ mutex_lock(&dc->lock); ++ init_buf(dc); ++ { ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(dc->chan); ++ writel((unsigned int)virt_to_phys(dc->desc), dmac->iomem + CH_DDA); ++ /* initiate descriptor fetch */ ++ writel(BIT(dmac->id), dmac->engine->iomem + DDRS); ++ writel(1 | (1 << 30),dmac->iomem + CH_DCS); ++ } ++ ++ dc->test_cnt ++; ++ { ++ volatile unsigned long *p = (unsigned long *)CKSEG1ADDR(dc->to); ++ unsigned long e = (unsigned long)dc->from; ++ int timeout = 0x10000; ++ for(i = 0;i < dc->test_len/4;i++){ ++ timeout = 0x10000; ++ while((p[i] != e) && --timeout); ++ if(timeout==0){ ++ printk("xxxxxx error data is not ready! xxxxxx\n"); ++ while(1); ++ } ++ e += 4; ++ } ++ } ++ mutex_unlock(&dc->lock); ++#ifdef CONFIG_FPGA_TEST ++ mdelay(100); ++#endif ++ return 0; ++} ++static int cpu_dma_test_func_wait(void * param) ++{ ++ struct dma_channel *dc = (struct dma_channel *)param; ++ unsigned long *p = (unsigned long*)((unsigned long)dc->to + dc->test_len - 4); ++ unsigned long e = (unsigned long)dc->from + dc->test_len - 4; ++ unsigned long r; ++ int timeout = 0x10000; ++ ++ struct device *dev; ++ dev = (struct device *)kzalloc(sizeof(struct device), GFP_KERNEL); ++ ++ mutex_lock(&dc->lock); ++ init_buf(dc); ++ { ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(dc->chan); ++ ++ writel((unsigned int)virt_to_phys(dc->desc), dmac->iomem + CH_DDA); ++ /* initiate descriptor fetch */ ++ writel(BIT(dmac->id), dmac->engine->iomem + DDRS); ++ writel(1 | (1 << 30),dmac->iomem + CH_DCS); ++ while(!(readl(dmac->iomem + CH_DCS) & (1 << 3)) && timeout--); ++ } ++ ++ dc->test_cnt ++; ++ ++ { ++ do ++ { ++ r = *p; ++ if(r != e){ ++ unsigned long *uc = (unsigned long *)((unsigned long)p | 0xa0000000); ++ ++ printk("error:from:%px to: %px data[%px] real: 0x%08lx, uc:0x%08lx expect: 0x%08lx, test_cnt: %ld\n", ++ dc->from, dc->to, p,r, *uc, e, dc->test_cnt); ++ break; ++ } ++ p--; ++ e -= 4; ++ }while((unsigned long)p != (unsigned long)dc->to - 4); ++ } ++ if(timeout==0){ ++ printk("xxxxxx error dmac is not ready! xxxxxx\n"); ++ while(1); ++ } ++ ++ mutex_unlock(&dc->lock); ++#ifdef CONFIG_FPGA_TEST ++ mdelay(100); ++#endif ++ return 0; ++} ++static bool filter(struct dma_chan *chan, void *param) ++{ ++#if 0 ++ if (!((unsigned int)chan->private == 8)) ++ return false; ++#endif ++ return true; ++} ++const static char dcm_tsz[8] = { 1, 2, 0, 0, 3, 4, 5, 6 }; ++static inline unsigned int get_max_tsz(unsigned long val, unsigned long *dcmp) ++{ ++ ++ int ord; ++ ++ ord = ffs(val) - 1; ++ if (ord < 0) ++ ord = 0; ++ else if (ord > 7) ++ ord = 7; ++ ++ *dcmp &= ~DCM_TSZ_MSK; ++ *dcmp |= dcm_tsz[ord] << DCM_TSZ_SFT; ++ ++ /* if tsz == 8, set it to 4 */ ++ return ord == 3 ? 4 : 1 << ord; ++} ++static struct dma_channel *new_dma_channel(struct cpu_dma_test* cd) ++{ ++ struct dma_channel *ch; ++ struct device *dev; ++ dev = (struct device *)kzalloc(sizeof(struct device), GFP_KERNEL); ++ ch = (struct dma_channel *)vmalloc(sizeof(struct dma_channel)); ++ memset(ch,0,sizeof(struct dma_channel)); ++ if(ch == NULL){ ++ printk("mem alloc failed! %s %d\n",__FILE__,__LINE__); ++ return 0; ++ } ++ ++ mutex_init(&ch->lock); ++ ++ ch->test_len = 4096; ++ ch->from = (void *)kmalloc(ch->test_len,GFP_KERNEL); ++ ch->to = (void *)kmalloc(ch->test_len,GFP_KERNEL); ++ if(ch->to == 0 || ch->from == 0){ ++ printk("mem alloc failed! %s %d\n",__FILE__,__LINE__); ++ goto error_exit; ++ } ++ ch->pfrom = virt_to_phys(ch->from); ++ ch->pto = virt_to_phys(ch->to); ++ ++ { ++ dma_cap_mask_t mask; ++ struct hdma_desc *desc; ++ unsigned long burst_len = 128; ++ unsigned long burst_bits = 0; ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_MEMCPY, mask); ++ ch->chan = dma_request_channel(mask, filter, 0); ++ if (!ch->chan) { ++ printk("dma channel request failed! %s %d\n",__FILE__,__LINE__); ++ goto error_exit; ++ } ++ ch->desc = (struct hdma_desc *)kmalloc(128,GFP_KERNEL); ++ if(!ch->desc){ ++ printk("dma channel request desc failed! %s %d\n",__FILE__,__LINE__); ++ goto error_exit; ++ } ++ desc = ch->desc; ++ burst_len = get_max_tsz(burst_len,&burst_bits); ++ desc->dcm = DCM_SAI | DCM_DAI | burst_bits; ++ desc->dsa = ch->pfrom; ++ desc->dta = ch->pto; ++ desc->dtc = ch->test_len / burst_len; ++ desc->drt = 8; ++ dma_cache_sync(dev,desc,128,DMA_TO_DEVICE); ++ } ++ ++ list_add_tail(&ch->list,&cd->dma_top); ++ return ch; ++error_exit: ++ if(ch->desc) ++ kfree(ch->desc); ++ if(ch->from) ++ kfree(ch->from); ++ if(ch->to) ++ kfree(ch->to); ++ vfree(ch); ++ return 0; ++} ++static void free_dma_channel(struct dma_channel *dc) ++{ ++ if(dc->desc) ++ kfree(dc->desc); ++ if(dc->from) ++ kfree(dc->from); ++ if(dc->to) ++ kfree(dc->to); ++ vfree(dc); ++} ++static int __init cpu_dma_test_init(void) ++{ ++ struct dma_channel *dc; ++ INIT_LIST_HEAD(&cpu_dma.dma_top); ++ cpu_dma.multithread = multithread_test_init("cpu_dma_test",2); ++ if(cpu_dma.multithread){ ++ dc = new_dma_channel(&cpu_dma); ++ if(dc) ++ multithread_test_add_func(cpu_dma.multithread,"cpu-dma-nowait",cpu_dma_test_func_nowait,(void*)dc); ++ ++ dc = new_dma_channel(&cpu_dma); ++ if(dc) ++ multithread_test_add_func(cpu_dma.multithread,"cpu-dma-wait",cpu_dma_test_func_wait,(void*)dc); ++ ++ printk("cpu_dma_test register ok.\n"); ++ } ++ return 0; ++} ++static void __exit cpu_dma_test_deinit(void) ++{ ++ struct dma_channel *dc,*_dc; ++ ++ list_for_each_entry_safe(dc, _dc, &cpu_dma.dma_top, list) { ++ list_del(&dc->list); ++ free_dma_channel(dc); ++ } ++ multithread_test_deinit(cpu_dma.multithread); ++} ++late_initcall(cpu_dma_test_init); ++module_exit(cpu_dma_test_deinit); +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/cpu_spinlock_test.c b/arch/mips/xburst2/common/cpu_ddr_test/cpu_spinlock_test.c +new file mode 100644 +index 000000000..e6773ab5d +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/cpu_spinlock_test.c +@@ -0,0 +1,75 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "multithread_test.h" ++ ++#define PALLADIUM_TRIGER_2() do {\ ++ volatile unsigned int *a; \ ++ a = (unsigned int *)0xAFFFFFFC; \ ++ *a = *a; \ ++ } while(0) ++ ++struct cpu_spinlock_test { ++ void* multithread; ++ spinlock_t lock; ++ unsigned int cnt; ++ atomic_t acnt; ++} cpu_spinlock; ++ ++ ++static int cpu_spinlock_test_func(void * param) ++{ ++ struct cpu_spinlock_test *p = (struct cpu_spinlock_test *)param; ++ unsigned int c; ++ ++ spin_lock(&p->lock); ++ ++#if 1 ++ c = atomic_read(&p->acnt); ++ if(p->cnt != c) { ++ // PALLADIUM_TRIGER_2(); ++ printk("========= spinlock cnt %x != atomic cnt, %x\n",p->cnt, c); ++ return -1; ++ } ++#endif ++ p->cnt++; ++ ++ udelay(10); ++ ++ atomic_inc(&p->acnt); ++ spin_unlock(&p->lock); ++ ++#ifdef CONFIG_FPGA_TEST ++ mdelay(100); ++#endif ++ return 0; ++} ++ ++static int __init cpu_spinlock_test_init(void) ++{ ++ cpu_spinlock.multithread = multithread_test_init("cpu_spinlock_test",1); ++ spin_lock_init(&cpu_spinlock.lock); ++ ++ if(cpu_spinlock.multithread){ ++ multithread_test_add_func(cpu_spinlock.multithread,"cpu_spinlock_test",cpu_spinlock_test_func,(void*)&cpu_spinlock); ++ } ++ return 0; ++} ++static void __exit cpu_spinlock_test_deinit(void) ++{ ++} ++ ++late_initcall(cpu_spinlock_test_init); ++module_exit(cpu_spinlock_test_deinit); +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/cpu_tcsm.h b/arch/mips/xburst2/common/cpu_ddr_test/cpu_tcsm.h +new file mode 100644 +index 000000000..4d3466812 +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/cpu_tcsm.h +@@ -0,0 +1,16 @@ ++#ifndef __CPU_TCSM_H__ ++#define __CPU_TCSM_H__ ++ ++#define CPU_TCSM_BASE (0xb2400000) ++ ++#define CPU_TCSM_BANK0 CPU_TCSM_BASE ++#define CPU_TCSM_BANK0_SIZE (4096) ++#define CPU_TCSM_FUNC CPU_TCSM_BANK0 ++#define CPU_TCSM_FUNC_SIZE 2048 ++#define CPU_TCSM_DATA (CPU_TCSM_FUNC + CPU_TCSM_FUNC_SIZE) ++#define CPU_TCSM_SP (CPU_TCSM_BANK0 + CPU_TCSM_BANK0_SIZE) ++ ++#define CPU_TCSM_DDR_CALIB (CPU_TCSM_DATA) ++#define CPU_TCSM_CPU_WAIT_STATUS (CPU_TCSM_DDR_CALIB + 0x4) ++ ++#endif /* __CPU_TCSM_H__ */ +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/cpu_watch_test.c b/arch/mips/xburst2/common/cpu_ddr_test/cpu_watch_test.c +new file mode 100644 +index 000000000..4f78454f3 +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/cpu_watch_test.c +@@ -0,0 +1,200 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++//#include ++ ++#include ++#include ++ ++ ++#include"../../../../../include/linux/mfd/ingenic-tcu_v2.h" ++ ++struct watch_struct ++{ ++ struct task_struct *child; ++ unsigned int watchhi; ++ unsigned int watchlo; ++ ++ /* debugfs */ ++ struct dentry *root; ++}; ++ ++struct watch_struct _cwt; /* cpu watch test */ ++struct watch_struct *cwt; /* cpu watch test */ ++ ++ ++static struct task_struct *trace_get_task_struct(pid_t pid) ++{ ++ struct task_struct *child; ++ ++ rcu_read_lock(); ++ child = find_task_by_vpid(pid); ++ if (child) ++ get_task_struct(child); ++ rcu_read_unlock(); ++ ++ if (!child) ++ return ERR_PTR(-ESRCH); ++ return child; ++} ++char g_buffer[256]; ++ ++static ssize_t cpu_watch_read_start(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ char *buf = g_buffer; ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++ ++} ++ ++static void local_set_watch(void *args) { ++ struct watch_struct *watch = (struct watch_struct *)args; ++ unsigned int cpu = smp_processor_id(); ++ unsigned int hi = 0; ++// struct mips3264_watch_reg_state *watches = ++ //&watch->child->thread.watch.mips3264; ++ ++ if(watch->watchhi & 0x40000000) ++ hi = watch->watchhi; ++ else ++ hi = (watch->watchhi & 0xffff) | (cpu_asid(cpu,watch->child->mm) << 16); ++ if(watch->watchlo == 0) hi = 0; ++// watches->watchlo[0][cpu] = watch->watchlo; ++// watches->watchhi[0][cpu] = hi; ++ ++ printk("watchlo: %x, watchhi: %x, cpu; %d\n", watch->watchlo, hi, cpu); ++ write_c0_watchlo0(watch->watchlo); ++ write_c0_watchhi0(hi); ++ ++} ++static inline void jz_on_each_cpu(void (*func) (void *info), void *info) ++{ ++ preempt_disable(); ++ smp_call_function(func, info, 1); ++ func(info); ++ preempt_enable(); ++} ++ ++static ssize_t cpu_watch_write_start(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ char s[20]; ++ char *s1,*s2; ++ pid_t pid; ++ unsigned int hi; ++ unsigned int lo; ++ struct task_struct *child = NULL; ++ struct watch_struct watch; ++// struct mips3264_watch_reg_state *watches; ++ ++ copy_from_user(g_buffer,user_buf,count); ++ ++ g_buffer[count] = 0; ++ printk("%s\n",g_buffer); ++ s1 = g_buffer; ++ s2 = strchr(s1,':'); ++ printk("s1 = %px s2 = %px\n",s1,s2); ++ if(!s2 || count == 0) { ++ pid = simple_strtoul(s1,0,0); ++ child = trace_get_task_struct(pid); ++ watch.child = child; ++ watch.watchlo = 0; ++ watch.watchhi = 0; ++ jz_on_each_cpu(local_set_watch,&watch); ++ //watches = &child->thread.watch.mips3264; ++ //watches->trace_type = 0; ++ clear_tsk_thread_flag(child, TIF_LOAD_WATCH); ++ ++ return count; ++ } ++ ++ memcpy(s,s1,s2 - s1); ++ s[s2 - s1] = 0; ++ pid = simple_strtoul(s,0,0); ++ ++ s1 = s2 + 1; ++ s2 = strchr(s1,':'); ++ printk("s1 = %px s2 = %px\n",s1,s2); ++ memcpy(s,s1,s2 - s1); ++ s[s2 - s1] = 0; ++ lo = simple_strtoul(s,0,0); ++ ++ s1 = s2 + 1; ++ hi = simple_strtoul(s1,0,0); ++ printk("pid = %d lo = 0x%08x hi = %d\n",pid,lo,hi); ++ child = trace_get_task_struct(pid); ++ printk("child = %px\n",child); ++ //child->thread.watch.mips3264.watchlo[0] = lo; ++ //child->thread.watch.mips3264.watchhi[0] = hi; ++ watch.child = child; ++ watch.watchlo = lo; ++ watch.watchhi = hi; ++ jz_on_each_cpu(local_set_watch,&watch); ++ //watches = &child->thread.watch.mips3264; ++ //watches->trace_type = 1; ++ ++ return count; ++} ++ ++static const struct file_operations cpu_watch_start_ops = { ++ .read = cpu_watch_read_start, ++ .write = cpu_watch_write_start, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ ++static int create_debugfs(struct watch_struct *cwt) ++{ ++ struct dentry *d; ++ d = debugfs_create_dir("cpu_watch", NULL); ++ if(IS_ERR(d)) { ++ pr_err("Create debugfs for tcu test failed!\n"); ++ return PTR_ERR(d); ++ } ++ ++ cwt->root = d; ++ ++ d = debugfs_create_file("start", S_IWUSR| S_IRUGO, cwt->root, cwt, &cpu_watch_start_ops); ++ if(IS_ERR_OR_NULL(d)) { ++ pr_err("Debugfs create failed!\n"); ++ goto err_node; ++ } ++ ++ return 0; ++ ++err_node: ++ debugfs_remove_recursive(cwt->root); ++ return -1; ++} ++ ++static int __init cpu_watch_test_init(void) ++{ ++ int ret; ++ ++ cwt = &_cwt; ++ ++ ret = create_debugfs(cwt); ++ ++ printk("cpu watch test probe ok!\n"); ++ return 0; ++} ++ ++static void __exit cpu_watch_test_deinit(void) ++{ ++ ++} ++ ++late_initcall(cpu_watch_test_init); ++module_exit(cpu_watch_test_deinit); +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/ddr_bandwidth_monitor.c b/arch/mips/xburst2/common/cpu_ddr_test/ddr_bandwidth_monitor.c +new file mode 100644 +index 000000000..fb8816460 +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/ddr_bandwidth_monitor.c +@@ -0,0 +1,461 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#define DDR_MONITOR_BASE 0x134F0000 ++#define DDR_DYNAMIC_CLK 0x13012068 ++#define DDR_DWCFG 0x13012000 ++#define DDR_CMONC0 0x13012050 ++ ++#define DB_MONITOR_BASE_OFF 0x88// DDR bandwidth monitor base offset address. ++ ++#define MAX_SUPPORTED_MONITORS 4 ++ ++struct dbw_channel_reg{ ++ volatile unsigned int write; ++ unsigned int reserve1; ++ volatile unsigned int read; ++ unsigned int reserve2; ++}; ++struct dbw_reg{ ++ volatile unsigned int dbwcfg; ++ unsigned int reserve; ++ volatile unsigned int period; ++ unsigned int reserver; ++ struct dbw_channel_reg chan[4]; ++}; ++ ++ ++#define GMAC_MSC_CHANNEL 0 //DDR ch0 ++#define VPU_CHANNEL 1 //DDR ch1 ++#define DPU_VPU_CHANNEL 3 //DDR ch3 ++#define AHB2_CHANNEL 5 //DDR ch5 ++#define CPU_CHANNEL 6 //DDR ch6 ++ ++struct ddr_mon_chan { ++ int chn; ++ const char *desc; ++}; ++ ++static struct ddr_mon_chan mon_chans[] = { ++ {0, "gmac&msc"}, ++ {1, "vpu&isp"}, ++ {3, "dpu&cim"}, ++ {5, "ahb2&audio&apb"}, ++ {6, "cpu"} ++}; ++ ++static unsigned int default_monitor_chn[MAX_SUPPORTED_MONITORS] = {0, 3, 5, 6}; ++ ++struct ddr_dbw_monitor { ++ struct ddr_mon_chan *ch; ++ unsigned int read; ++ unsigned int write; ++}; ++ ++ ++static inline struct ddr_mon_chan* get_mon_chn(int chn) ++{ ++ int i; ++ ++ for(i = 0; i < ARRAY_SIZE(mon_chans); i++) { ++ if(mon_chans[i].chn == chn) ++ return &mon_chans[i]; ++ } ++ ++ printk("Error find mon_chn, chn: %d\n", chn); ++ return NULL; ++} ++ ++static int set_mon_chn(struct ddr_dbw_monitor *monitors, int chn) ++{ ++ struct ddr_mon_chan *mon_chn = get_mon_chn(chn); ++ ++ printk("set _mon_chn :%d\n", chn); ++ ++ if(!mon_chn) { ++ return -EINVAL; ++ } ++ ++ monitors->ch = mon_chn; ++ ++ return 0; ++} ++ ++ ++struct ddr_statistics{ ++ struct dentry *root; ++ unsigned int periods; ++ unsigned int output; ++ int run; ++ ++ unsigned int ahb2_read_rate; ++ unsigned int ahb2_write_rate; ++ unsigned int cpu_read_rate; ++ unsigned int cpu_write_rate; ++ ++ /* 1 package = 4 * 32 = 8 * 16 */ ++ unsigned int pkg_cnt_to_cycle; ++ ++ int poll_periods_ms; ++ struct dbw_reg *reg; ++ ++ struct ddr_dbw_monitor dbw_monitors[4]; ++ ++ struct mutex lock; ++ struct timer_list timer; ++}; ++static struct ddr_statistics ddr_statistics = { ++ .periods = 25 * 1000 * 1000, ++ .run = 0, ++ .poll_periods_ms = 40, ++ .output = 1, ++}; ++#define BW_DONE (1 << 3) ++#define BW_INT_EN (1 << 2) ++#define BW_CLR (1 << 1) ++#define BW_EN (1 << 0) ++ ++#define DDR_PACKAGE_TO_CYCLE 4 ++static void ddr_stat_output(struct ddr_statistics *ddr) ++{ ++ uint64_t period = (uint64_t)ddr->reg->period; ++#define occupancy_show(title,chn,id) do{ \ ++ uint64_t w_occupancy = (uint64_t)ddr->dbw_monitors[id].write * ddr->pkg_cnt_to_cycle; \ ++ uint64_t r_occupancy = (uint64_t)ddr->dbw_monitors[id].read * ddr->pkg_cnt_to_cycle; \ ++ uint64_t d = 100000 * w_occupancy; \ ++ uint64_t hi; \ ++ do_div(d,period); \ ++ hi = (uint32_t)d / 1000; \ ++ printk("%s chn:%d write occupancy rate:%lld.%03lld%%\n",title,chn,hi,d - hi * 1000); \ ++ d = 100000 * r_occupancy; \ ++ do_div(d,period); \ ++ hi = (uint32_t)d / 1000; \ ++ printk("%s chn:%d read occupancy rate:%lld.%03lld%%\n",title,chn, hi,d - hi * 1000); \ ++ }while(0) ++ occupancy_show(ddr->dbw_monitors[0].ch->desc, ddr->dbw_monitors[0].ch->chn, 0); ++ occupancy_show(ddr->dbw_monitors[1].ch->desc, ddr->dbw_monitors[1].ch->chn, 1); ++ occupancy_show(ddr->dbw_monitors[2].ch->desc, ddr->dbw_monitors[2].ch->chn, 2); ++ occupancy_show(ddr->dbw_monitors[3].ch->desc, ddr->dbw_monitors[3].ch->chn, 3); ++#undef occupancy_show ++} ++ ++static struct ddr_dbw_monitor *get_dbw_monitor(struct ddr_statistics *ddr, int chn) ++{ ++ struct ddr_dbw_monitor *m; ++ int i = 0; ++ ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ m = &ddr->dbw_monitors[i]; ++ if(m->ch->chn == chn) ++ return m; ++ } ++ ++ return NULL; ++} ++ ++static ssize_t ddr_read_run(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ddr_statistics *ddr = file->private_data; ++ char *buf; ++ ++ mutex_lock(&ddr->lock); ++ if(ddr->reg->dbwcfg & BW_EN) ++ buf = "Runing\n"; ++ else ++ buf = "Stop\n"; ++ mutex_unlock(&ddr->lock); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++} ++ ++static ssize_t ddr_write_run(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ddr_statistics *ddr = file->private_data; ++ struct ddr_dbw_monitor *m; ++ char buf[16]; ++ bool bv; ++ int ret = 0; ++ unsigned int val; ++ int i = 0; ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ if (strtobool(buf, &bv) == 0) { ++ mutex_lock(&ddr->lock); ++ ++ if(bv){ ++ val = readl((void*)CKSEG1ADDR(DDR_DYNAMIC_CLK)); ++ val &= ~(1 << 8); ++ writel(val,(void*)CKSEG1ADDR(DDR_DYNAMIC_CLK)); ++ ++ del_timer_sync(&ddr->timer); ++ if(ddr->reg->period != ddr->periods) ++ ddr->poll_periods_ms = 0; ++ ddr->run = 1; ++ ddr->reg->period = ddr->periods; ++ val = ddr->reg->period; ++ ++ ddr->reg->dbwcfg = BW_EN | BW_CLR; ++ while((ddr->reg->dbwcfg & (BW_CLR | BW_EN)) != BW_EN); ++ printk("run!\n"); ++ mod_timer(&ddr->timer,jiffies + msecs_to_jiffies(ddr->poll_periods_ms)); ++ }else{ ++ ++ del_timer_sync(&ddr->timer); ++ ddr->run = 0; ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ ddr->dbw_monitors[i].write = ddr->reg->chan[i].write; ++ ddr->dbw_monitors[i].read = ddr->reg->chan[i].read; ++ } ++ ++ if(ddr->output){ ++ ddr_stat_output(ddr); ++ } ++ ++ ddr->ahb2_write_rate = (m = get_dbw_monitor(ddr, AHB2_CHANNEL)) == NULL ? 0:m->write; ++ ddr->ahb2_read_rate = (m = get_dbw_monitor(ddr, AHB2_CHANNEL)) == NULL ? 0:m->read; ++ ddr->cpu_write_rate = (m = get_dbw_monitor(ddr, CPU_CHANNEL)) == NULL ? 0:m->write; ++ ddr->cpu_read_rate = (m = get_dbw_monitor(ddr, CPU_CHANNEL)) == NULL ? 0:m->read; ++ ++ ++ ddr->reg->dbwcfg = 0; ++ printk("stopping!\n"); ++ } ++ mutex_unlock(&ddr->lock); ++ } ++ ++ return ret ? ret : count; ++} ++ ++static const struct file_operations ddr_run_fops = { ++ .read = ddr_read_run, ++ .write = ddr_write_run, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++static void ddr_stat_timer_handler(struct timer_list *timer) ++{ ++ struct ddr_statistics *ddr = container_of(timer, struct ddr_statistics, timer); ++ unsigned int dbwcfg = ddr->reg->dbwcfg; ++ struct ddr_dbw_monitor *m; ++ int i = 0; ++ if(dbwcfg & BW_DONE) ++ { ++ if(ddr->run){ ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ ddr->dbw_monitors[i].write = ddr->reg->chan[i].write; ++ ddr->dbw_monitors[i].read = ddr->reg->chan[i].read; ++ } ++ ++ if(ddr->output){ ++ ddr_stat_output(ddr); ++ } ++ if(ddr->reg->dbwcfg != dbwcfg) ++ ddr->poll_periods_ms = 0; ++ ++ ++ ddr->ahb2_write_rate = (m = get_dbw_monitor(ddr, AHB2_CHANNEL)) == NULL ? 0:m->write; ++ ddr->ahb2_read_rate = (m = get_dbw_monitor(ddr, AHB2_CHANNEL)) == NULL ? 0:m->read; ++ ddr->cpu_write_rate = (m = get_dbw_monitor(ddr, CPU_CHANNEL)) == NULL ? 0:m->write; ++ ddr->cpu_read_rate = (m = get_dbw_monitor(ddr, CPU_CHANNEL)) == NULL ? 0:m->read; ++ ++ dbwcfg |= BW_CLR; ++ ddr->reg->dbwcfg = dbwcfg; ++ ++ while(ddr->reg->dbwcfg & BW_CLR); ++ mod_timer(&ddr->timer,jiffies + msecs_to_jiffies(ddr->poll_periods_ms)); ++ }else{ ++ ddr->reg->dbwcfg = 0; ++ } ++ } else { ++ mod_timer(&ddr->timer,jiffies + msecs_to_jiffies(10)); ++ ddr->poll_periods_ms += 10; ++ } ++} ++ ++static int dbw_monitors_init(struct ddr_statistics *ddr) ++{ ++ unsigned int cmonc0; ++ int i; ++ ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ ddr->dbw_monitors[i].ch = get_mon_chn(default_monitor_chn[i]); ++ } ++ ++#if 0 ++ ddr->dbw_monitors[0].ch = &mon_chans[0]; ++ ddr->dbw_monitors[1].ch = &mon_chans[1]; ++ ddr->dbw_monitors[2].ch = &mon_chans[2]; ++ ddr->dbw_monitors[3].ch = &mon_chans[3]; ++#endif ++ cmonc0 = readl((void *)CKSEG1ADDR(DDR_CMONC0)); ++ /*cmonc0[15:4]*/ ++ cmonc0 &= ~0xfff0; ++ cmonc0 |= (ddr->dbw_monitors[0].ch->chn << 13) \ ++ | (ddr->dbw_monitors[1].ch->chn << 10) \ ++ | (ddr->dbw_monitors[2].ch->chn << 7) \ ++ | (ddr->dbw_monitors[3].ch->chn << 4); ++ writel(cmonc0, (void *)CKSEG1ADDR(DDR_CMONC0)); ++ ++ return 0; ++} ++static ssize_t ddr_read_monitors(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ddr_statistics *ddr = file->private_data; ++ struct ddr_dbw_monitor *m = NULL; ++ int i = 0; ++ int ret = 0; ++ ++ unsigned char *buf = kzalloc(1024, GFP_KERNEL); ++ unsigned char *p = buf; ++ ++ if(!buf) { ++ printk("Error alloc mem!\n"); ++ return -ENOMEM; ++ } ++ ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ m = &ddr->dbw_monitors[i]; ++ ret = sprintf(p, "monitor:%d, chn:%d, desc:%s\n\t read:%d, write:%d\n", ++ i, m->ch->chn, m->ch->desc, m->read, m->write); ++ p += ret; ++ } ++ ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++ kfree(buf); ++ return ret; ++} ++ ++static ssize_t ddr_write_monitors(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ ++ struct ddr_statistics *ddr = file->private_data; ++ char buf[16]; ++ int i = 0; ++ unsigned int val; ++ char *token, *cur = buf; ++ unsigned int cmonc0; ++ ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ for(i = 0; i < MAX_SUPPORTED_MONITORS; i++) { ++ token = strsep(&cur, ":"); ++ if(!token) { ++ printk("Invalid monitor settings!\n"); ++ return -EINVAL; ++ } ++ val = simple_strtoul(token, NULL, 10); ++ ++ if(set_mon_chn(&ddr->dbw_monitors[i], val) < 0) { ++ return -EINVAL; ++ } ++ } ++ ++ cmonc0 = readl((void *)CKSEG1ADDR(DDR_CMONC0)); ++ /*cmonc0[15:4]*/ ++ cmonc0 &= ~0xfff0; ++ cmonc0 |= (ddr->dbw_monitors[0].ch->chn << 13) \ ++ | (ddr->dbw_monitors[1].ch->chn << 10) \ ++ | (ddr->dbw_monitors[2].ch->chn << 7) \ ++ | (ddr->dbw_monitors[3].ch->chn << 4); ++ writel(cmonc0, (void *)CKSEG1ADDR(DDR_CMONC0)); ++ ++ return count; ++} ++ ++static const struct file_operations ddr_monitors_fops = { ++ .read = ddr_read_monitors, ++ .write = ddr_write_monitors, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ ++ ++static int __init ddr_stat_init(void) ++{ ++ struct dentry * d; ++ struct ddr_statistics *ddr = &ddr_statistics; ++ ++ d = debugfs_create_dir("ddr", NULL); ++ if (IS_ERR(d)){ ++ pr_err("create debugfs for ddr failed.\n"); ++ return PTR_ERR(d); ++ } ++ ++ ++ ddr->root = d; ++ ++ d = debugfs_create_file("monitors", S_IWUSR | S_IRUGO, ddr->root, ++ ddr, &ddr_monitors_fops); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ ++ debugfs_create_u32("periods", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->periods); ++ ++ debugfs_create_u32("output", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->output); ++ ++ debugfs_create_u32("ahb2_read_rate", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->ahb2_read_rate); ++ ++ debugfs_create_u32("ahb2_write_rate", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->ahb2_write_rate); ++ ++ debugfs_create_u32("cpu_read_rate", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->cpu_read_rate); ++ ++ debugfs_create_u32("cpu_write_rate", S_IWUSR | S_IRUGO, ddr->root, ++ (u32 *)&ddr->cpu_write_rate); ++ ++ ++ ++ d = debugfs_create_file("run", S_IWUSR | S_IRUGO, ddr->root, ++ ddr, &ddr_run_fops); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ mutex_init(&ddr->lock); ++ ++ ddr->reg = ioremap(DDR_MONITOR_BASE + DB_MONITOR_BASE_OFF,sizeof(struct dbw_reg)); ++ ++ if(readl((void *)CKSEG1ADDR(DDR_DWCFG)) & 1) { ++ /* 32bit ddr*/ ++ ddr->pkg_cnt_to_cycle = 4; ++ ++ } else { ++ ddr->pkg_cnt_to_cycle = 8; ++ ++ } ++ ++ dbw_monitors_init(ddr); ++ ++ ++ ++ init_timers(); ++ ddr->timer.function = ddr_stat_timer_handler; ++ ++ return 0; ++err_node: ++ debugfs_remove_recursive(ddr->root); ++ ++ return -1; ++} ++ ++static void __exit ddr_stat_deinit(void) ++{ ++ struct ddr_statistics *ddr = &ddr_statistics; ++ debugfs_remove_recursive(ddr->root); ++} ++ ++late_initcall(ddr_stat_init); ++module_exit(ddr_stat_deinit); +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/ddr_change_freq.c b/arch/mips/xburst2/common/cpu_ddr_test/ddr_change_freq.c +new file mode 100644 +index 000000000..3841d6f8c +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/ddr_change_freq.c +@@ -0,0 +1,521 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include "cpu_tcsm.h" ++ ++/* #define ALL_OTHER_CPU_WAITE */ ++struct ddr_calib_value { ++ unsigned int rate; ++ unsigned int refcnt; ++ unsigned char bypass_al; ++ unsigned char bypass_ah; ++}; ++ ++typedef void (*ddr_change_code)(unsigned int, unsigned int, ++ unsigned int,unsigned int); ++ ++struct ddr_cfreq { ++ struct dentry *root; ++ spinlock_t lock; ++ struct timer_list timer; ++ struct clk *clk_ddr; ++ ++ unsigned int ddr_cur_rate; ++ ddr_change_code tcsm_change_ddr_rate; ++}; ++ ++struct ddr_cfreq ddr_cfreq; ++ ++#define CPM_DDRCDR (0xb000002c) ++ ++static ssize_t ddr_read_rate(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ char buf[4]; ++ int pos = 0; ++ ++ pos = scnprintf(buf, 4, "%d\n", ddr_cfreq.ddr_cur_rate); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, pos); ++} ++ ++static unsigned int get_ddr_parent_rate(void) ++{ ++ unsigned int val; ++ struct clk *pll; ++ unsigned int pll_rate; ++ ++ val = REG32(CPM_DDRCDR); ++ switch(val >> 30) { ++ case 1: ++ pll = clk_get(NULL, "apll"); ++ break; ++ case 2: ++ pll = clk_get(NULL, "mpll"); ++ break; ++ default : ++ printk("not support\n"); ++ return 0; ++ } ++ ++ pll_rate = clk_get_rate(pll); ++ return pll_rate; ++} ++static unsigned int get_ddr_rate(void) ++{ ++ unsigned int pll_rate, ddr_rate; ++ unsigned int val; ++ ++ val = REG32(CPM_DDRCDR); ++ ++ pll_rate = get_ddr_parent_rate(); ++ ddr_rate = pll_rate / ((val & 0xf) + 1); ++ return ddr_rate; ++} ++ ++static unsigned int pp_mask, ost_mask, mailbox_mask; ++#ifdef ALL_OTHER_CPU_WAITE ++static unsigned int pp_pend,ost_pend, mailbox_pend; ++#endif ++ ++static inline void unmask_others_cpu(void); ++static void change_ddr_rate(unsigned char bal, unsigned char bah, unsigned int refcnt, int div) ++{ ++ unsigned int val, cur_div;//, div; ++ unsigned int hregpro, pregpro; ++ unsigned int autoself_en; ++#ifdef ALL_OTHER_CPU_WAITE ++ unsigned int wait_cpu; ++ unsigned int timeout = 10000; ++ ++ REG32(0xb0032000) = '0'; ++ ++ div = change_div & 0xffff; ++ wait_cpu = (change_div >> 16); ++ while(!REG32(0xb2407ff8) && timeout --) ++ ; ++ if(!timeout) ++ return; ++#endif ++ hregpro = ddr_readl(DDRC_HREGPRO); ++ pregpro = ddr_readl(DDRC_PREGPRO); ++ autoself_en = ddr_readl(DDRC_AUTOSR_EN); ++ ++ ddr_writel(0, DDRC_HREGPRO); ++ ddr_writel(0, DDRC_PREGPRO); ++ ddr_writel(0, DDRC_AUTOSR_EN); ++ ++ // Disable DFI lowpower handshake ++ /* val = ddr_readl(DDRC_DLP); */ ++ /* val &= ~(1); */ ++ /* ddr_writel(val, DDRC_DLP); */ ++ ++ val = REG32(CPM_DDRCDR); ++ cur_div = (val & 0xf); ++ ++ if(cur_div > div) { ++ val = ddr_readl(DDRC_REFCNT); ++ val &= ~(0x3ffff << 8 | 0xe); ++ val |= refcnt; ++ ddr_writel(val, DDRC_REFCNT); ++ } ++ /** ++ * don't use AHB0/2 APB BUS before freq exit. ++ */ ++ /** ++ * Set !change_en and ce ++ */ ++ val = REG32(CPM_DDRCDR); ++ val |= ((1 << 29) | (1 << 25)); ++ REG32(CPM_DDRCDR) = val; ++ /* while((REG32(CPM_DDRCDR) & (1 << 24))); */ ++ ++ /** ++ * Set clock divider ++ */ ++ val = REG32(CPM_DDRCDR); ++ val &= ~(0xf); ++ val |= div; ++ REG32(CPM_DDRCDR) = val; ++// while((REG32(CPM_DDRCDR) & (1 << 28))); ++ /** ++ * Polling PHY_FREQ_DONE ++ */ ++ while((ddr_readl(DDRC_DWSTATUS) & (1 << 3 | 1 << 1)) != 0xa) ++ ; ++ ++ ddr_writel(DDRP_TRAINING_CTRL_DSCSE_BP, DDRP_INNOPHY_TRAINING_CTRL); ++ ddr_writel(bal, DDRP_INNOPHY_CALIB_BYPASS_AL); ++ ddr_writel(bah, DDRP_INNOPHY_CALIB_BYPASS_AH); ++ ++ /** ++ * Set Controller Freq Exit ++ */ ++ val = ddr_readl(DDRC_DWCFG); ++ val |= (1 << 2); ++ ddr_writel(val, DDRC_DWCFG); ++ ++ /** ++ * Clear Controller Freq Exit ++ */ ++ val = ddr_readl(DDRC_DWCFG); ++ val &= ~(1 << 2); ++ ddr_writel(val, DDRC_DWCFG); ++ ++ /** ++ * clear change_en and ce ++ */ ++ val = REG32(CPM_DDRCDR); ++ val &= ~((1 << 29) | (1 << 25)); ++ REG32(CPM_DDRCDR) = val; ++ ++ unmask_others_cpu(); ++ ++#ifdef ALL_OTHER_CPU_WAITE ++ if(ost_pend) ++ set_ccu_oipr(get_ccu_oipr() | (1 << wait_cpu)); ++ if(pp_pend) ++ set_ccu_pipr(get_ccu_pipr() | (1 << wait_cpu)); ++ if(mailbox_pend) ++ set_ccu_mipr(get_ccu_mipr() | (1 << wait_cpu)); ++ ++ if(ost_mask) ++ set_ccu_oimr(get_ccu_oimr() | (1 << wait_cpu)); ++ if(pp_mask) ++ set_ccu_pimr(get_ccu_pimr() | (1 << wait_cpu)); ++ if(mailbox_mask) ++ set_ccu_mimr(get_ccu_mimr() | (1 << wait_cpu)); ++ /* REG32(0xb2407ff8) = 0; */ ++#endif ++ ++ if(cur_div < div) { ++ val = ddr_readl(DDRC_REFCNT); ++ val &= ~(0x3ffff << 8 | 0xe); ++ val |= refcnt; ++ ddr_writel(val, DDRC_REFCNT); ++ } ++ ++ if(autoself_en) ++ ddr_writel(1, DDRC_AUTOSR_EN); ++ if(hregpro & (1 << 1)) ++ ddr_writel(1, DDRC_HREGPRO); ++ if(pregpro & (1 << 1)) ++ ddr_writel(1, DDRC_PREGPRO); ++} ++ ++#define __read_32bit_register() \ ++ ({ int __res; \ ++ __asm__ __volatile__( \ ++ "move \t %0, $29\n\t" \ ++ : "=r" (__res)); \ ++ __res; \ ++ }) ++ ++#define __write_32bit_register(value) \ ++ do { \ ++ __asm__ __volatile__( \ ++ "move \t $29, %0\n\t" \ ++ : : "Jr" ((unsigned int)(value))); \ ++ } while (0) ++ ++#define read_sp_register() __read_32bit_register() ++#define write_sp_register(val) __write_32bit_register(val) ++static unsigned int change_count; ++static int try_and_lock_ccu(unsigned int cpu) ++{ ++ int timeout = 1000; ++ unsigned int cslr; ++ ++ do { ++ set_ccu_csar(cpu); ++ cslr = get_ccu_cslr(); ++ if((cslr & 1 << 31) && ((cslr & ((1 << CONFIG_NR_CPUS) -1)) == cpu)) ++ break; ++ } while(timeout --); ++ if(timeout < 0) ++ return -1; ++ return 0; ++} ++static void unlock_ccu(void) ++{ ++ set_ccu_cslr(0); ++} ++static int mask_and_wait_others_cpu(unsigned int cur_cpu) ++{ ++ unsigned int pp_mval, mb_mval, ost_mval; ++ unsigned int max_cpu_num = CONFIG_NR_CPUS; ++ unsigned int mask_cpus = ((1 << max_cpu_num) - 1); ++ unsigned int mask_other_cpus = (mask_cpus & (~(1 << cur_cpu))); ++ int timeout, ret = 0; ++ ++ pp_mval = get_ccu_pimr(); ++ mb_mval = get_ccu_mimr(); ++ ost_mval = get_ccu_oimr(); ++ ++ pp_mask = pp_mval & (mask_cpus); ++ mailbox_mask = mb_mval & (mask_cpus); ++ ost_mask = ost_mval & (mask_cpus); ++ ++ try_and_lock_ccu(cur_cpu); ++ if(ret < 0) { ++ printk("try to lock ccu failed\n"); ++ return ret; ++ } ++ ++ set_ccu_pimr(0); ++ set_ccu_mimr(0); ++ set_ccu_oimr(0); ++ ++ timeout = 100000; ++ while(((get_ccu_cssr() & mask_other_cpus) != mask_other_cpus) ++ && timeout--); ++ ++ if(!get_ccu_cssr() && timeout >= 0) { ++ printk("ERROR:get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("ERROR:get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("ERROR:get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("ERROR:get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("ERROR:get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("get_ccu_cssr() %x timeout %d mask_other_cpus %x\n", get_ccu_cssr(), timeout, mask_other_cpus); ++ printk("SMP: ------------------wakeup--------CPU%d: cause %x\n", cur_cpu, read_c0_cause()); ++ printk("SMP: ------------------wakeup--------CPU%d: pp pending %x\n", cur_cpu, REG32(0xb2200100)); ++ printk("SMP: ------------------wakeup--------CPU%d: ost pending %x\n", cur_cpu, REG32(0xb2200180)); ++ printk("SMP: ------------------wakeup--------CPU%d: mailbox pending %x\n", cur_cpu, REG32(0xb2200140)); ++ ++ printk("SMP: ------------------wakeup--------CPU%d: pp mask %x\n", cur_cpu, get_ccu_pimr()); ++ printk("SMP: ------------------wakeup--------CPU%d: mailbox mask %x\n", cur_cpu, get_ccu_mimr()); ++ printk("SMP: ------------------wakeup--------CPU%d: os mask %x\n", cur_cpu, get_ccu_oimr()); ++ while(1); ++ } ++ ++ if(timeout < 0) { ++ set_ccu_pimr(pp_mask); ++ set_ccu_mimr(mailbox_mask); ++ set_ccu_oimr(ost_mask); ++ ret = -1; ++ } ++ unlock_ccu(); ++ ++ return ret; ++} ++static inline void unmask_others_cpu(void) ++{ ++ /* try_and_lock_ccu(cur_cpu); */ ++ /* if(ret < 0) { */ ++ /* printk("try to lock ccu failed\n"); */ ++ /* return ret; */ ++ /* } */ ++ set_ccu_pimr(pp_mask); ++ set_ccu_mimr(mailbox_mask); ++ set_ccu_oimr(ost_mask); ++ /* unlock_ccu(); */ ++} ++#ifdef ALL_OTHER_CPU_WAITE ++static void disable_interrupt(void *args) ++{ ++ unsigned int cpu = smp_processor_id(); ++ printk("SMP: --------------------------CPU%d is offline\n", cpu); ++ ++ if(cpu != *(unsigned int *)args) { ++ unsigned int pp_mval, mb_mval, ost_mval; ++ unsigned int pp_pval, mb_pval, ost_pval; ++ pp_mval = get_ccu_pimr(); ++ mb_mval = get_ccu_mimr(); ++ ost_mval = get_ccu_oimr(); ++ ++ pp_mask = pp_mval & (1 << cpu); ++ mailbox_mask = mb_mval & (1 << cpu); ++ ost_mask = ost_mval & (1 << cpu); ++ ++ set_ccu_pimr(pp_mval & (~(1 << cpu))); ++ set_ccu_mimr(mb_mval & (~(1 << cpu))); ++ set_ccu_oimr(ost_mval & (~(1 << cpu))); ++ ++ pp_pval = get_ccu_pipr(); ++ mb_pval = get_ccu_mipr(); ++ ost_pval = get_ccu_oipr(); ++ ++ pp_pend = pp_pval & (1 << cpu); ++ mailbox_pend = mb_pval & (1 << cpu); ++ ost_pend = ost_pval & (1 << cpu); ++ ++ set_ccu_pipr(pp_pval & (~(1 << cpu))); ++ set_ccu_mipr(mb_pval & (~(1 << cpu))); ++ set_ccu_oipr(ost_pval & (~(1 << cpu))); ++ } ++ ++ REG32(0xb2407ff8) = 0xa5a5a5a5; ++ __asm__ __volatile__ ("wait \n\t"); ++ ++ printk("SMP: ------------------wakeup--------CPU%d: cause %x\n", cpu, read_c0_cause()); ++ printk("SMP: ------------------wakeup--------CPU%d: pp pending %x\n", cpu, REG32(0xb2200100)); ++ printk("SMP: ------------------wakeup--------CPU%d: ost pending %x\n", cpu, REG32(0xb2200180)); ++ printk("SMP: ------------------wakeup--------CPU%d: mailbox pending %x\n", cpu, REG32(0xb2200140)); ++} ++#endif ++ ++static ssize_t ddr_write_rate(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ char buf[16]; ++ unsigned int change_rate; ++ unsigned long flags; ++ unsigned int cpu = smp_processor_id(); ++ unsigned int sp, change_div; ++ int ret; ++ struct ddr_calib_value *dcv, *curdcv; ++ ++ dcv = (struct ddr_calib_value *)(CPU_TCSM_DDR_CALIB); ++ ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ change_rate = simple_strtoul(buf, NULL, 10) * 1000000; ++ printk("change_rate %d-----------------\n", change_rate); ++ if(change_rate == ddr_cfreq.ddr_cur_rate) { ++ printk("change rate equl current rate\n"); ++ return count; ++ } ++ ++ change_div = get_ddr_parent_rate() / change_rate - 1; ++ if(dcv[change_div].rate != change_rate) { ++ int i; ++ printk("rate %d not support %d\n", change_rate, dcv[change_div].rate); ++ for(i = 0; i< 6; i ++) ++ printk("div %d, rate %d\n", i, dcv[i].rate); ++ printk("change_div %d\n", change_div); ++ return count; ++ } ++ curdcv = &dcv[change_div]; ++ ++ change_count ++; ++ printk("------------cpu %d----------------%d------------------\n", cpu, change_count); ++ ++#ifdef ALL_OTHER_CPU_WAITE ++ REG32(0xb2407ff8) = 0; ++ change_div |= ((cpu?0:1) << 16); ++// preempt_disable(); ++ /* on_each_cpu(disable_interrupt, &cpu, 0); */ ++ smp_call_function(disable_interrupt, &cpu, 0); ++#endif ++ ++ spin_lock_irqsave(&ddr_cfreq.lock,flags); ++ ret = mask_and_wait_others_cpu(cpu); ++ if(ret < 0) { ++ printk("lock failed\n"); ++ change_count --; ++ spin_unlock_irqrestore(&ddr_cfreq.lock,flags); ++ return ret; ++ } ++ sp = read_sp_register(); ++ write_sp_register(CPU_TCSM_SP); ++ ddr_cfreq.tcsm_change_ddr_rate(curdcv->bypass_al, ++ curdcv->bypass_ah, curdcv->refcnt, change_div); ++ write_sp_register(sp); ++ spin_unlock_irqrestore(&ddr_cfreq.lock,flags); ++// preempt_enable(); ++ printk("change succeed\n"); ++ ++ ddr_cfreq.ddr_cur_rate = get_ddr_rate(); ++ clk_set_rate(ddr_cfreq.clk_ddr, ddr_cfreq.ddr_cur_rate); ++ /* ddr_cfreq.ddr_cur_rate = clk_get_rate(ddr_cfreq.clk_ddr); */ ++ printk("clk_get_rate(ddr_cfreq.clk_ddr) %d\n", (unsigned int)clk_get_rate(ddr_cfreq.clk_ddr)); ++ ++ return count; ++} ++ ++static const struct file_operations ddr_run_fops = { ++ .read = ddr_read_rate, ++ .write = ddr_write_rate, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ ++static void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size) ++{ ++ unsigned int instr; ++ int offset; ++ int i; ++ for(i = 0;i < size / 4;i++) { ++ instr = f_addr[i]; ++ if((instr >> 26) == 2){ ++ offset = instr & 0x3ffffff; ++ offset = (offset << 2) - ((unsigned int)f_addr & 0xfffffff); ++ if(offset > 0) { ++ printk("f_addr[i]%x: %x--------------------------------------------------\n", (unsigned int)&f_addr[i], f_addr[i]); ++ offset = ((unsigned int)tcsm_addr & 0xfffffff) + offset; ++ /* offset = ((unsigned int)0xf4000000 & 0xfffffff) + offset; */ ++ instr = (2 << 26) | (offset >> 2); ++ } ++ } ++ tcsm_addr[i] = instr; ++ } ++} ++ ++static int __init ddr_init(void) ++{ ++ struct dentry * d; ++ struct ddr_cfreq *cfreq = &ddr_cfreq; ++ ++ cfreq->clk_ddr = clk_get(NULL, "div_ddr"); ++ if(!cfreq->clk_ddr) { ++ printk("get ddr clk failed\n"); ++ return -1; ++ } ++ ++ cfreq->ddr_cur_rate = clk_get_rate(cfreq->clk_ddr); ++ { ++ unsigned int *tcsm_bank0 = (unsigned int *)CPU_TCSM_FUNC; ++ /* unsigned int *tcsm_bank0 = (unsigned int *)0xb3423000; */ ++ unsigned int *func0 = (unsigned int *)change_ddr_rate; ++ ++ load_func_to_tcsm(tcsm_bank0, func0, CPU_TCSM_FUNC_SIZE); ++ cfreq->tcsm_change_ddr_rate = (ddr_change_code)tcsm_bank0; ++ } ++ ++ ++ d = debugfs_create_dir("ddrfreq", NULL); ++ if (IS_ERR(d)){ ++ pr_err("create debugfs for ddr failed.\n"); ++ return PTR_ERR(d); ++ } ++ spin_lock_init(&cfreq->lock); ++ ++ cfreq->root = d; ++ debugfs_create_u32("ddr_cur_rate", S_IWUSR | S_IRUGO, cfreq->root, ++ (u32 *)&cfreq->ddr_cur_rate); ++ ++ d = debugfs_create_file("rate", S_IWUSR | S_IRUGO, cfreq->root, ++ cfreq, &ddr_run_fops); ++ if (IS_ERR_OR_NULL(d)) ++ goto err_node; ++ ++ return 0; ++err_node: ++ debugfs_remove_recursive(cfreq->root); ++ ++ return -1; ++} ++ ++static void __exit ddr_deinit(void) ++{ ++ struct ddr_cfreq *cfreq = &ddr_cfreq; ++ debugfs_remove_recursive(cfreq->root); ++} ++ ++late_initcall(ddr_init); ++module_exit(ddr_deinit); +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/l2c_test.c b/arch/mips/xburst2/common/cpu_ddr_test/l2c_test.c +new file mode 100644 +index 000000000..397cd86a2 +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/l2c_test.c +@@ -0,0 +1,527 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++/** ++ 1. start address align: 0-63 ++ 2. size align: 0-63 ++ 3. max size: 512k ++ 4. invalid: ++ 5. writeback: ++ 6. blast: ++ 7. 8 thread. ++*/ ++ ++struct l2c_test_thread; ++typedef int (*TEST_FUNC)(struct l2c_test_thread *); ++struct l2c_test_thread{ ++ struct list_head list; ++ struct task_struct *task; ++ TEST_FUNC test_func; ++ struct mutex *lock; ++ int id; ++ volatile int done; ++}; ++#define TO_UNC(x) ((unsigned int)x | 0x20000000) ++//#define TO_UNC(x) ((unsigned int)x) ++ ++#define L2C_SIZE (512 * 1024) ++#define L2C_LINESIZE (64) ++ ++#define PALLADIUM_TRIGER() do{ \ ++ void (*func)(void); \ ++ func = (void(*)(void)) 0xbfc00000; \ ++ func(); \ ++ }while(0) ++ ++#define info(x,y...) do{ \ ++ printk(x,##y); \ ++ }while(0) ++ ++static __maybe_unused int writeback_align_address(struct l2c_test_thread *data) ++{ ++ unsigned char *src; ++ unsigned char *src_org; ++ unsigned char *p; ++ unsigned char *unc_p; ++ int i,j; ++ struct device *dev; ++ dev = (struct device *)kzalloc(sizeof(struct device), GFP_KERNEL); ++ src_org = (unsigned char*)kmalloc(L2C_LINESIZE * 4,GFP_KERNEL); ++ ++ if(IS_ERR_OR_NULL(src_org)){ ++ src = 0; ++ info("kmalloc error!\n"); ++ }else{ ++ src = src_org + L2C_LINESIZE; ++ info("%s test addr: %px\n",__func__,src); ++ for(j = 0;j= &src[j] && p < (&src[j] + L2C_LINESIZE)){ ++ if(*unc_p != (i & 255)){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%px offset:%d e:0x%02x r:0x%02x\n",src,p-src,i & 255,*(unc_p)); ++ return -1; ++ } ++ }else{ ++ if(*p != (i & 255)){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%px offset:%d e:0x%02x r:0x%02x\n",src,p-src,i & 255,*(p)); ++ return -1; ++ } ++ } ++ p++; ++ unc_p++; ++ } ++ for(i = 0;i= &src[j] && p < (&src[j] + L2C_LINESIZE * 2)){ ++ if(*p != (0xff - n)){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%px offset:%d e:0x%02x r:0x%02x\n",src,p-src,0xff - n,*p); ++ return -1; ++ } ++ n++; ++ }else{ ++ if(*p != (i & 255)){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%px offset:%d e:0x%02x r:0x%02x\n",src,p-src,i & 255,*p); ++ return -1; ++ } ++ } ++ p++; ++ } ++ for(i = 0;i= L2C_SIZE / 2) && (i < L2C_SIZE / 2 + L2C_SIZE)) ++ { ++ eq = 0xff - (j & 0xff); ++ j++; ++ }else { ++ eq = i & 0xff; ++ } ++ if(p[i] != eq){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%px e:0x%02x r:0x%02x\n",p,eq,p[i]); ++ return -1; ++ } ++ } ++ } ++ if(src_org) ++ kfree(src_org); ++ return 0; ++} ++static __maybe_unused int blast_writeback_all(struct l2c_test_thread *data) ++{ ++ unsigned char *src; ++ unsigned char *src_org; ++ unsigned char *p; ++ unsigned char *unc_p; ++ int i; ++ unsigned char eq; ++ struct device *dev; ++ dev = (struct device *)kzalloc(sizeof(struct device), GFP_KERNEL); ++ src_org = (unsigned char*)kmalloc(L2C_SIZE * 2 + L2C_LINESIZE * 2,GFP_KERNEL); ++ if(IS_ERR_OR_NULL(src_org)){ ++ src = 0; ++ info("kmalloc error!\n"); ++ }else{ ++ src = src_org + L2C_LINESIZE; ++ info("%s test addr: %px\n",__func__,src); ++ p = src; ++ unc_p = (unsigned char *)TO_UNC(p); ++ for(i = 0;i < L2C_SIZE;i++){ ++ unc_p[L2C_SIZE / 2 + i] = 0xff - (i & 0xff); ++ __sync(); ++ } ++ for(i = 0;i < L2C_SIZE * 2;i++){ ++ src[i] = i & 0xff; ++ } ++ dma_cache_sync(dev,src,L2C_SIZE * 2,DMA_TO_DEVICE); ++ ++ for(i = 0;i < L2C_SIZE * 2;i++){ ++ eq = i & 0xff; ++ if(p[i] != eq){ ++ PALLADIUM_TRIGER(); ++ info("Err:addr:%px e:0x%02x r:0x%02x\n",p,eq,p[i]); ++ return -1; ++ } ++ } ++ } ++ if(src_org) ++ kfree(src_org); ++ return 0; ++} ++ ++struct l2c_test{ ++ struct dentry *root; ++ int run; ++ struct mutex lock; ++ struct mutex resultlock; ++ struct list_head top; ++ unsigned int thread_count; ++}; ++static TEST_FUNC g_test_func[] ={ ++ writeback_align_address, ++ writeback_align_size, ++ invalid_align_address, ++ invalid_align_size, ++ blast_invalid_all, ++ blast_writeback_all ++}; ++static int g_thread_id = 0; ++ ++ ++static int l2c_test_func(void *data) ++{ ++ struct l2c_test_thread *thread = data; ++ int index; ++ while (!kthread_should_stop()) ++ { ++ printk("d:%px\n",thread->test_func); ++ thread->test_func(thread); ++ index = prandom_u32() % ARRAY_SIZE(g_test_func); ++ thread->test_func = g_test_func[index]; ++ } ++ thread->done = 0; ++ return 0; ++} ++ ++ ++ ++static int l2c_test_add_threads(struct l2c_test *l2ctest) ++{ ++ struct l2c_test_thread *thread; ++ unsigned int index; ++ thread = (struct l2c_test_thread *)kmalloc(sizeof(struct l2c_test_thread), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(thread)){ ++ printk("thread kmalloc failed!\n"); ++ return -1; ++ } ++ memset(thread,0,sizeof(struct l2c_test_thread)); ++ thread->done = -1; ++ index = prandom_u32() % ARRAY_SIZE(g_test_func); ++ thread->test_func = g_test_func[index]; ++ thread->id = g_thread_id; ++ thread->lock = &l2ctest->resultlock; ++ thread->task = kthread_run(l2c_test_func, thread, "l2c_test%d-func%u",g_thread_id++,index); ++ if (IS_ERR(thread->task)) { ++ info("l2c_test: Failed to run thread l2c_test%d-func%u\n",g_thread_id,index); ++ kfree(thread); ++ return -1; ++ } ++ list_add_tail(&thread->list, &l2ctest->top); ++ return 0; ++} ++static void stop_threaded_test(struct l2c_test *l2ctest) ++{ ++ struct l2c_test_thread *thread,*_thread; ++ ++ list_for_each_entry_safe(thread, _thread, &l2ctest->top, list) { ++ list_del(&thread->list); ++ kthread_stop(thread->task); ++ while(thread->done); ++ kfree(thread); ++ } ++} ++ ++static int run_l2c_test(struct l2c_test *l2c) ++{ ++ int i = 0; ++ if(l2c->thread_count > 0){ ++ for(i = 0;i < l2c->thread_count;i++){ ++ l2c_test_add_threads(l2c); ++ } ++ } ++ return 0; ++} ++ ++static ssize_t l2c_test_read_run(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct l2c_test *l2c = file->private_data; ++ char *buf; ++ mutex_lock(&l2c->lock); ++ if(!list_empty(&l2c->top)) ++ buf = "Runing\n"; ++ else ++ buf = "Stop\n"; ++ mutex_unlock(&l2c->lock); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++} ++static ssize_t l2c_test_write_run(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct l2c_test *l2c = file->private_data; ++ char buf[16]; ++ bool bv; ++ int ret = 0; ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ if (strtobool(buf, &bv) == 0) { ++ mutex_lock(&l2c->lock); ++ if(bv){ ++ run_l2c_test(l2c); ++ }else{ ++ stop_threaded_test(l2c); ++ } ++ mutex_unlock(&l2c->lock); ++ } ++ ++ return ret ? ret : count; ++} ++ ++static const struct file_operations l2c_test_run_fops = { ++ .read = l2c_test_read_run, ++ .write = l2c_test_write_run, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++struct l2c_test g_l2c_test; ++ ++static int __init l2c_test_init(void) ++{ ++ struct dentry * d; ++ struct l2c_test *l2c= &g_l2c_test; ++ ++ memset(l2c,0,sizeof(struct l2c_test)); ++ mutex_init(&l2c->lock); ++ mutex_init(&l2c->resultlock); ++ INIT_LIST_HEAD(&l2c->top); ++ l2c->thread_count = 1; ++ ++ d = debugfs_create_dir("l2c_test", NULL); ++ if (IS_ERR(d)){ ++ pr_err("create debugfs for l2c_test failed.\n"); ++ return PTR_ERR(d); ++ } ++ l2c->root = d; ++ ++ debugfs_create_u32("thread_count", S_IWUSR | S_IRUGO, l2c->root, ++ (u32 *)&l2c->thread_count); ++ ++ d = debugfs_create_file("run", S_IWUSR | S_IRUGO, l2c->root, ++ l2c, &l2c_test_run_fops); ++ if (IS_ERR_OR_NULL(d)){ ++ pr_err("debugfs create run node failed\n"); ++ goto err_node; ++ } ++ pr_info("l2c_test debugfs init ok.\n"); ++ return 0; ++err_node: ++ debugfs_remove_recursive(l2c->root); ++ pr_err("l2c_test debugfs init failed.\n"); ++ return -1; ++} ++late_initcall(l2c_test_init); ++ ++static void __exit l2c_test_deinit(void) ++{ ++ struct l2c_test *l2c= &g_l2c_test; ++ stop_threaded_test(l2c); ++ debugfs_remove_recursive(l2c->root); ++} ++module_exit(l2c_test_deinit); +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.c b/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.c +new file mode 100644 +index 000000000..1878ed248 +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.c +@@ -0,0 +1,258 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "multithread_test.h" ++struct multithread_test{ ++ struct dentry *root; ++ const char *name; ++ int run; ++ struct mutex lock; ++ struct mutex resultlock; ++ struct list_head thread_top; ++ unsigned int thread_count; ++ struct list_head func_top; ++}; ++struct func_list { ++ struct list_head list; ++ const char *test_name; ++ TEST_FUNC testfunc; ++ void *param; ++ atomic_t testcount; ++}; ++struct thread_test{ ++ struct multithread_test *mt; ++ struct list_head list; ++ struct task_struct *task; ++ char thread_name[20]; ++ TEST_FUNC test_func; ++ void* param; ++ struct mutex *lock; ++ volatile int done; ++}; ++static int mt_test_func(void *data); ++static int mt_test_add_threads(struct multithread_test *mt) ++{ ++ struct thread_test *thread; ++ struct func_list *l_func; ++ struct func_list *min_func = NULL; ++ unsigned int testcount; ++ int retry = 100000; ++ ++ if(list_empty(&mt->func_top)) ++ { ++ printk("test func list is empty,please add func for multithread test.\n"); ++ return -1; ++ } ++ ++ thread = (struct thread_test *)vmalloc(sizeof(struct thread_test)); ++ if(IS_ERR_OR_NULL(thread)){ ++ printk("%s:thread kmalloc failed!\n",mt->name); ++ return -1; ++ } ++ memset(thread,0,sizeof(struct thread_test)); ++ thread->done = -1; ++ ++ testcount = 0xffffffff; ++ list_for_each_entry(l_func,&mt->func_top,list){ ++ unsigned int tc; ++ tc = atomic_read(&l_func->testcount); ++ if(testcount >= tc){ ++ min_func = l_func; ++ testcount = tc; ++ } ++ } ++ if(!min_func) ++ { ++ printk("Not find func %s %d\n",__FILE__,__LINE__); ++ goto err_exit; ++ } ++ atomic_inc(&min_func->testcount); ++ ++ thread->mt = mt; ++ thread->test_func = min_func->testfunc; ++ thread->param = min_func->param; ++ thread->lock = &mt->resultlock; ++ snprintf(thread->thread_name,sizeof(thread->thread_name),"%s-%d\n",min_func->test_name,atomic_read(&min_func->testcount)); ++ ++ do { ++ if(retry <= 0) { ++ break; ++ } ++ thread->task = kthread_run(mt_test_func, thread, thread->thread_name); ++ msleep(1); ++ ++ retry--; ++ ++ } while ((int)thread->task == -EAGAIN); ++ ++ if (IS_ERR(thread->task) || (retry == 0)) { ++ printk("%s: Failed to run thread func:%s, retry: %d\n",mt->name,thread->thread_name, retry); ++ goto err_exit; ++ } ++ list_add_tail(&thread->list, &mt->thread_top); ++ return 0; ++err_exit: ++ kfree(thread); ++ return -1; ++} ++ ++static int mt_test_func(void *data) ++{ ++ struct thread_test *thread = data; ++ while (!kthread_should_stop()) ++ { ++ if(thread->test_func(thread->param) == 0) ++ { ++ mutex_lock(&thread->mt->lock); ++ mt_test_add_threads(thread->mt); ++ mutex_unlock(&thread->mt->lock); ++ } ++ break; ++ } ++ ++ mutex_lock(&thread->mt->lock); ++ list_del(&thread->list); ++ thread->done = 0; ++ mutex_unlock(&thread->mt->lock); ++ ++ vfree(thread); ++ return 0; ++} ++ ++static int run_mt_test(struct multithread_test *mt) ++{ ++ int i = 0; ++ if(mt->thread_count > 0){ ++ for(i = 0;i < mt->thread_count;i++){ ++ mt_test_add_threads(mt); ++ } ++ } ++ return 0; ++} ++static void stop_threaded_test(struct multithread_test *mt) ++{ ++ struct thread_test *thread,*_thread; ++ ++ list_for_each_entry_safe(thread, _thread, &mt->thread_top, list) { ++ list_del(&thread->list); ++ kthread_stop(thread->task); ++ while(thread->done); ++ vfree(thread); ++ } ++} ++ ++static ssize_t mt_test_read_run(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct multithread_test *mt = file->private_data; ++ char *buf; ++ mutex_lock(&mt->lock); ++ if(!list_empty(&mt->thread_top)) ++ buf = "Runing\n"; ++ else ++ buf = "Stop\n"; ++ mutex_unlock(&mt->lock); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++} ++static ssize_t mt_test_write_run(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct multithread_test *mt = file->private_data; ++ char buf[16]; ++ bool bv; ++ int ret = 0; ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ if (strtobool(buf, &bv) == 0) { ++ mutex_lock(&mt->lock); ++ if(bv){ ++ run_mt_test(mt); ++ }else{ ++ stop_threaded_test(mt); ++ } ++ mutex_unlock(&mt->lock); ++ } ++ return ret ? ret : count; ++} ++static const struct file_operations mt_test_run_fops = { ++ .read = mt_test_read_run, ++ .write = mt_test_write_run, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++int multithread_test_add_func(void *handle,const char *name,TEST_FUNC testfunc,void *param) ++{ ++ struct multithread_test *mt = (struct multithread_test *)handle; ++ struct func_list *funclist = vmalloc(sizeof(struct multithread_test)); ++ if(funclist == NULL){ ++ printk("add func failed,%s %d\n",__FILE__,__LINE__); ++ return -1; ++ } ++ funclist->test_name = name; ++ funclist->testfunc = testfunc; ++ funclist->param = param; ++ atomic_set(&funclist->testcount,0); ++ list_add_tail(&funclist->list,&mt->func_top); ++ return 0; ++} ++void* multithread_test_init(const char *name,int threadcount) ++{ ++ struct dentry * d; ++ struct multithread_test *mt = vmalloc(sizeof(struct multithread_test)); ++ if(!mt){ ++ pr_err("%s:%s %d alloc struct multithread_test failed!\n",name,__FILE__,__LINE__); ++ return NULL; ++ } ++ memset(mt,0,sizeof(struct multithread_test)); ++ mutex_init(&mt->lock); ++ mutex_init(&mt->resultlock); ++ INIT_LIST_HEAD(&mt->thread_top); ++ INIT_LIST_HEAD(&mt->func_top); ++ mt->thread_count = threadcount; ++ mt->name = name; ++ d = debugfs_create_dir(name, NULL); ++ if (IS_ERR(d)){ ++ pr_err("create debugfs for %s failed.\n",name); ++ return NULL; ++ } ++ mt->root = d; ++ ++ debugfs_create_u32("thread_count", S_IWUSR | S_IRUGO, mt->root, ++ (u32 *)&mt->thread_count); ++ ++ d = debugfs_create_file("run", S_IWUSR | S_IRUGO, mt->root, ++ mt, &mt_test_run_fops); ++ if (IS_ERR_OR_NULL(d)){ ++ pr_err("%s:debugfs create run node failed\n",name); ++ goto err_node; ++ } ++ pr_info("%s:debugfs init ok.\n",name); ++ return (void*)mt; ++err_node: ++ debugfs_remove_recursive(mt->root); ++ pr_err("%s:debugfs init failed.\n",name); ++ return NULL; ++} ++ ++void multithread_test_deinit(void *handle) ++{ ++ struct multithread_test *mt = (struct multithread_test *)handle; ++ struct func_list *funclist,*_funclist; ++ stop_threaded_test(mt); ++ debugfs_remove_recursive(mt->root); ++ list_for_each_entry_safe(funclist, _funclist, &mt->thread_top, list) { ++ list_del(&funclist->list); ++ vfree(funclist); ++ } ++ vfree(mt); ++} +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.h b/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.h +new file mode 100644 +index 000000000..4c4223b85 +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/multithread_test.h +@@ -0,0 +1,9 @@ ++#ifndef _MULTITHREAD_TEST_H_ ++#define _MULTITHREAD_TEST_H_ ++ ++typedef int (*TEST_FUNC)(void *); ++int multithread_test_add_func(void *handle,const char *name,TEST_FUNC testfunc,void *param); ++void* multithread_test_init(const char *name,int threadcount); ++void multithread_test_deinit(void* handle); ++ ++#endif /* _MULTITHREAD_TEST_H_ */ +diff --git a/arch/mips/xburst2/common/cpu_ddr_test/raw_dma_test.c b/arch/mips/xburst2/common/cpu_ddr_test/raw_dma_test.c +new file mode 100644 +index 000000000..ad4b892fe +--- /dev/null ++++ b/arch/mips/xburst2/common/cpu_ddr_test/raw_dma_test.c +@@ -0,0 +1,273 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++ ++#include "../../../../../drivers/dma/ingenic/ingenic_dma.h" ++ ++const int dma_test_burst_len[] = {1,4,8,16,32,64,128}; ++ ++struct dma_channel{ ++ struct list_head list; ++ struct dma_chan *chan; ++ unsigned char *desc; ++ unsigned int blen_per_desc; ++}; ++ ++struct cycle_raw_dma_test{ ++ struct dentry *root; ++ int run; ++ struct mutex lock; ++ struct list_head top; ++}; ++ ++static struct cycle_raw_dma_test g_raw_cycle_dma; ++ ++static bool filter(struct dma_chan *chan, void *param) ++{ ++#if 0 ++ if (!((unsigned int)chan->private == 8)) { ++ return false; ++ } ++#endif ++ return true; ++} ++const static char dcm_tsz[8] = { 1, 2, 0, 0, 3, 4, 5, 6 }; ++static inline unsigned int get_max_tsz(unsigned long val, unsigned long *dcmp) ++{ ++ ++ int ord; ++ ++ ord = ffs(val) - 1; ++ if (ord < 0) ++ ord = 0; ++ else if (ord > 7) ++ ord = 7; ++ ++ *dcmp &= ~DCM_TSZ_MSK; ++ *dcmp |= dcm_tsz[ord] << DCM_TSZ_SFT; ++ ++ /* if tsz == 8, set it to 4 */ ++ return ord == 3 ? 4 : 1 << ord; ++} ++static void dump_desc(char *title,struct hdma_desc *desc) ++{ ++ printk("=========== %s =========== \n",title); ++ printk("dcm:0x%08lx\n",desc->dcm); ++ printk("dsa:0x%08x\n",(unsigned int)desc->dsa); ++ printk("dta:0x%08x\n",(unsigned int)desc->dta); ++ printk("dtc:0x%08lx\n",desc->dtc); ++ printk("drt:0x%08lx\n",desc->drt); ++ ++} ++static void build_desc(unsigned char *desc,int burst,int len) ++{ ++ /** ++ * 4 series A B A' B' desc. ++ * A desc is transmite (A B) to (A' B') ++ * A next desc is B' ++ * B desc is transmite (A' B') to (A B) ++ * B next desc is A ++ */ ++ unsigned long burst_bits = 0; ++ struct hdma_desc *A = (struct hdma_desc *)desc; ++ struct hdma_desc *B = (struct hdma_desc *)(desc + len * 1); ++ struct hdma_desc *A1 = (struct hdma_desc *)(desc + len * 2); ++ struct hdma_desc *B1 = (struct hdma_desc *)(desc + len * 3); ++ struct device *dev; ++ ++ dev = (struct device *)kzalloc(sizeof(struct device), GFP_KERNEL); ++ ++ burst = get_max_tsz(burst,&burst_bits); ++ A->dcm = DCM_SAI | DCM_DAI | DCM_LINK | burst_bits; ++ A->dsa = virt_to_phys(A); ++ A->dta = virt_to_phys(A1); ++ A->dtc = (len * 2 / burst) | ((((unsigned int)B1 & 0xff0) >> 4) << 24); ++ A->drt = 8; ++ ++ B->dcm = DCM_SAI | DCM_DAI | DCM_LINK | burst_bits; ++ B->dsa = virt_to_phys(A1); ++ B->dta = virt_to_phys(A); ++ B->dtc = (len * 2 / burst) | ((((unsigned int)A & 0xff0) >> 4) << 24); ++ B->drt = 8; ++ ++ dump_desc("A",A); ++ dump_desc("B",B); ++ dma_cache_sync(dev,A,len*4,DMA_TO_DEVICE); ++} ++static void start_dma_chans(struct cycle_raw_dma_test *dma) ++{ ++ struct dma_channel *ch; ++ list_for_each_entry(ch,&dma->top,list){ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(ch->chan); ++ writel((unsigned int)virt_to_phys(ch->desc), dmac->iomem + CH_DDA); ++ printk("dda:%px->0x%08lx\n",dmac->iomem + CH_DDA,virt_to_phys(ch->desc)); ++ /* initiate descriptor fetch */ ++ writel(BIT(dmac->id), dmac->engine->iomem + DDRS); ++ printk("ddrs:%px->0x%08lx\n",dmac->engine->iomem + DDRS,BIT(dmac->id)); ++ writel(1 | (1 << 30),dmac->iomem + CH_DCS); ++ } ++} ++static void stop_dma_chans(struct cycle_raw_dma_test *dma) ++{ ++ struct dma_channel *ch; ++ struct device *dev; ++ ++ dev = (struct device *)kzalloc(sizeof(struct device), GFP_KERNEL); ++ ++ list_for_each_entry(ch,&dma->top,list){ ++ struct hdma_desc *A,*B; ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(ch->chan); ++ int len = ch->blen_per_desc; ++ A = (struct hdma_desc *)(ch->desc); ++ B = (struct hdma_desc *)(ch->desc + len * 1); ++ A->dtc &= ~(0xff << 24); ++ B->dtc &= ~(0xff << 24); ++ dma_cache_sync(dev,A,len*4,DMA_TO_DEVICE); ++ while(readl(dmac->iomem + CH_DCS) & (1 << 3)); ++ writel(0,dmac->iomem + CH_DCS); ++ } ++ ++} ++static void start_cycle_raw_dma(struct cycle_raw_dma_test *dma) ++{ ++ int i; ++ int max; ++ struct dma_channel *ch; ++ struct dma_chan *chan; ++ dma_cap_mask_t mask; ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_MEMCPY, mask); ++ for(i = 0;i < ARRAY_SIZE(dma_test_burst_len);i++){ ++ chan = dma_request_channel(mask, filter, dma); ++ if (!chan) { ++ printk("dma channel request failed! curid = %d, burstlen: %d ignored\n",i,dma_test_burst_len[i]); ++// break; ++ continue; ++ } ++ if(dma_test_burst_len[i] < 32) ++ max = 32; ++ else ++ max = dma_test_burst_len[i]; ++ ++ //extra add 16 byte for descriptor align. ++ ch = kmalloc(sizeof(struct dma_channel) + max * 4 + 16,GFP_KERNEL); // max * 4 is (4's descs) ++ if(IS_ERR_OR_NULL(ch)){ ++ pr_err("dma request channel failed!\n"); ++ dma_release_channel(chan); ++ break; ++ } ++ ch->chan = chan; ++ ch->desc = (unsigned char*)(((unsigned int)(ch + 1) + 15) / 16 * 16); // aligned 16 byte for dma descriptor ++ ch->blen_per_desc = max; ++ build_desc(ch->desc,dma_test_burst_len[i],max); ++ list_add_tail(&ch->list,&dma->top); ++ } ++ start_dma_chans(dma); ++} ++static void stop_cycle_raw_dma(struct cycle_raw_dma_test *dma) ++{ ++ ++ struct list_head *pos; ++ struct list_head *next; ++ struct dma_channel *ch; ++ stop_dma_chans(dma); ++ list_for_each_safe(pos,next,&dma->top){ ++ ch = list_entry(pos,struct dma_channel,list); ++ dma_release_channel(ch->chan); ++ list_del(pos); ++ kfree(ch); ++ } ++} ++static int is_stop_cycle_raw_dma(struct cycle_raw_dma_test *dma) ++{ ++ return list_empty(&dma->top); ++} ++static ssize_t cycle_raw_dma_test_read_run(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct cycle_raw_dma_test *dma = file->private_data; ++ char *buf; ++ mutex_lock(&dma->lock); ++ if(!is_stop_cycle_raw_dma(dma)) ++ buf = "Runing\n"; ++ else ++ buf = "Stop\n"; ++ mutex_unlock(&dma->lock); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); ++} ++static ssize_t cycle_raw_dma_test_write_run(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct cycle_raw_dma_test *dma = file->private_data; ++ char buf[16]; ++ bool bv; ++ int ret = 0; ++ if (copy_from_user(buf, user_buf, min(count, (sizeof(buf) - 1)))) ++ return -EFAULT; ++ ++ if (strtobool(buf, &bv) == 0) { ++ mutex_lock(&dma->lock); ++ if(bv){ ++ start_cycle_raw_dma(dma); ++ }else{ ++ stop_cycle_raw_dma(dma); ++ } ++ mutex_unlock(&dma->lock); ++ } ++ ++ return ret ? ret : count; ++} ++ ++static const struct file_operations cycle_raw_dma_test_run_fops = { ++ .read = cycle_raw_dma_test_read_run, ++ .write = cycle_raw_dma_test_write_run, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++static int __init cycle_raw_dma_test_init(void) ++{ ++ struct dentry * d; ++ ++ struct cycle_raw_dma_test *dma= &g_raw_cycle_dma; ++ ++ memset(dma,0,sizeof(struct cycle_raw_dma_test)); ++ INIT_LIST_HEAD(&dma->top); ++ mutex_init(&dma->lock); ++ d = debugfs_create_dir("cycle_raw_dma_test", NULL); ++ if (IS_ERR(d)){ ++ pr_err("create debugfs for cycle_raw_dma_test failed.\n"); ++ return PTR_ERR(d); ++ } ++ dma->root = d; ++ ++ d = debugfs_create_file("run", S_IWUSR | S_IRUGO, dma->root, ++ dma, &cycle_raw_dma_test_run_fops); ++ if (IS_ERR_OR_NULL(d)){ ++ pr_err("debugfs create run node failed\n"); ++ goto err_node; ++ } ++ pr_info("cycle raw dma_test debugfs init ok.\n"); ++ return 0; ++err_node: ++ debugfs_remove_recursive(dma->root); ++ pr_err("cycle_raw_dma_test debugfs init failed.\n"); ++ return -1; ++} ++late_initcall(cycle_raw_dma_test_init); ++ ++static void __exit cycle_raw_dma_test_deinit(void) ++{ ++ struct cycle_raw_dma_test *dma= &g_raw_cycle_dma; ++ debugfs_remove_recursive(dma->root); ++} ++module_exit(cycle_raw_dma_test_deinit); +diff --git a/arch/mips/xburst2/common/get-cpu-features.c b/arch/mips/xburst2/common/get-cpu-features.c +new file mode 100644 +index 000000000..731fbdbce +--- /dev/null ++++ b/arch/mips/xburst2/common/get-cpu-features.c +@@ -0,0 +1,98 @@ ++/* ++ * Use this function to generate cpu-feature-override.h head file. ++ * Make sure of that, here is no cpu-feature-override.h in mach-xxx directory. ++ * ++ */ ++ ++#include ++#include ++#include ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#include ++#include ++ ++static int cpu_proc_show(struct seq_file *m, void *v) ++{ ++ ++#define PRINT(ARGS...) seq_printf (m, ##ARGS) ++ ++#define PRT0(X,Y) PRINT("#define " "%s()\t(%d * 1024)\n",#X,(Y)/1024) ++#define PRT1(X,Y) PRINT("#define " "%s()\t%d\n",#X,(Y)) ++ PRT0(cpu_dcache_size,(1< ++#include ++#include ++#include ++ ++static void check_file(char *fname) ++{ ++ int err; ++ pr_info("check file %s ... ",fname); ++ err = sys_access((const char __user *) fname, O_RDONLY); ++ if (err < 0) ++ pr_info("failed %d.\n", err); ++ else ++ pr_info("successed.\n"); ++} ++ ++static int __init check_rootfs(void) ++{ ++ int err; ++ ++ if (sys_access((const char __user *) "/dev", O_RDWR) < 0) { ++ pr_info("Dir /dev is not exist.\n"); ++ sys_mkdir((const char __user *) "/dev", O_RDWR); ++ } ++ ++ if (sys_access((const char __user *) "/dev/console", O_RDWR) < 0) { ++ printk("create /dev/console\n"); ++ err = sys_mknod((const char __user __force *) "/dev/console", ++ S_IFCHR | S_IRUSR | S_IWUSR, ++ new_encode_dev(MKDEV(5, 1))); ++ if (err < 0) ++ goto out; ++ } ++ ++ if (sys_access((const char __user *) "/dev/null", O_RDWR) < 0) { ++ printk("create /dev/null\n"); ++ err = sys_mknod((const char __user __force *) "/dev/null", ++ S_IFCHR | S_IRUSR | S_IWUSR, ++ new_encode_dev(MKDEV(1, 3))); ++ if (err < 0) ++ goto out; ++ } ++ ++ check_file("/linuxrc"); ++ check_file("/init"); ++ check_file("/init.rc"); ++ check_file("/sbin/adbd"); ++ check_file("/bin/busybox"); ++ ++ return 0; ++ ++out: ++ printk(KERN_WARNING "Failed to create dev\n"); ++ return err; ++} ++ ++late_initcall(check_rootfs); +diff --git a/arch/mips/xburst2/common/mxuv3.c b/arch/mips/xburst2/common/mxuv3.c +new file mode 100644 +index 000000000..e19cf46db +--- /dev/null ++++ b/arch/mips/xburst2/common/mxuv3.c +@@ -0,0 +1,697 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#define WORDCODE ++ ++#pragma clang optimize off ++/*__attribute__((optimize("O0")))*/ ++void __init_mxuv3(void) ++{ ++ unsigned int register val asm("t0"); ++ val = 0; ++ /* open mxuv3 and set thread status ST0_CU2 */ ++ set_c0_status(ST0_CU2); ++ KSTK_STATUS(current) |= ST0_CU2; ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid); ++ ++ /* dump mxuv3 control and status register */ ++#ifdef WORDCODE ++ //asm volatile(".word 0x70100203 | (0x0 << 11)\n\t":"=r"(val)); ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, mir=0x%x\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), KSTK_STATUS(current), current->tgid, current->pid, val); ++ //asm volatile(".word 0x70100203 | (0x1 << 11) \n\t":"=r"(val)); ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, mscr=0x%x\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), KSTK_STATUS(current), current->tgid, current->pid, val); ++ //dump_stack(); ++#else ++ CFCMXU(val, 0); ++ printk("mir=0x%x\n", val); ++ CFCMXU(val, 1); ++ printk("mcsr=0x%x\n", val); ++#endif ++} ++ ++/*__attribute__((optimize("O0")))*/ ++void __save_mxuv3(void *tsk_void) ++{ ++ register void *base asm("t0"); ++#ifndef WORDCODE ++ register void *base1 asm("t1"); ++#endif ++ struct task_struct *tsk = tsk_void; ++ struct xburst_mxu_struct *mxu = &tsk->thread.mxu; ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, , KSTK_STATUS(tsk)=0x%lx, task->tgid=%d, task->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), KSTK_STATUS(current), current->tgid, current->pid, KSTK_STATUS(tsk), tsk->tgid, tsk->pid); ++ //dump_stack(); ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, task_cpu(p)=%d, KSTK_STATUS(p)=0x%lx, p->tgid=%d, p->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid, task_cpu(tsk), KSTK_STATUS(tsk), tsk->tgid, tsk->pid); ++#ifdef WORDCODE ++ /** ++ * sao ins: hex(0x700000d5 | 8 << 21 | 1 << 16 | 0 << 11 | 1 << 9) ++ * 0x700000d5 ->sa0 ++ * 8 ->t0 ++ * 1 ->32>>5 ++ * 0 ->vpr0 ++ * 1 ->nn // o means to be divided by 512/256=2, so n=[0,1] ++ * because t0 is fixed, so 0x700000d5 | 8 << 21 = 0x710000d5 ++ * so the word format as follows: ++ * asm volatile(".word 0x710000d5 | offset << 16 | vprn << 11 | n << 9 \n\t"); ++ * mfsum ins: hex(0x4a60000f | vss << 11 | vrd << 7) ++ * for we fixed vrd to 0, so the word format as follows: ++ * asm volatile(".word 0x4a60000f | vss << 11 \n\t"); ++ */ ++ base = &mxu->vpr[0]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 0 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 0 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[1]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 1 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 1 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[2]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 2 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 2 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[3]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 3 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 3 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[4]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 4 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 4 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[5]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 5 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 5 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[6]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 6 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 6 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[7]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 7 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 7 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[8]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 8 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 8 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[9]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 9 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 9 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[10]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 10 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 10 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[11]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 11 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 11 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[12]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 12 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 12 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[13]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 13 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 13 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[14]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 14 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 14 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[15]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 15 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 15 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[16]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 16 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 16 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[17]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 17 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 17 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[18]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 18 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 18 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[19]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 19 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 19 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[20]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 20 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 20 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[21]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 21 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 21 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[22]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 22 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 22 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[23]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 23 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 23 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[24]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 24 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 24 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[25]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 25 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 25 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[26]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 26 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 26 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[27]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 27 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 27 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[28]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 28 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 28 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[29]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 29 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 29 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[30]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 30 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 30 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vpr[31]; ++ asm volatile(".word 0x710000d5 | 0 << 16 | 31 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 31 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vsr[0]; ++ asm volatile(".word 0x4a60000f | 0 << 11 \n\t"); ++ asm volatile(".word 0x710000d5 | 0 << 16 | 0 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 0 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vsr[1]; ++ asm volatile(".word 0x4a60000f | 1 << 11 \n\t"); ++ asm volatile(".word 0x710000d5 | 0 << 16 | 0 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 0 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vsr[2]; ++ asm volatile(".word 0x4a60000f | 2 << 11 \n\t"); ++ asm volatile(".word 0x710000d5 | 0 << 16 | 0 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 0 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->vsr[3]; ++ asm volatile(".word 0x4a60000f | 3 << 11 \n\t"); ++ asm volatile(".word 0x710000d5 | 0 << 16 | 0 << 11 | 0 << 9 \n\t"); ++ asm volatile(".word 0x710000d5 | 1 << 16 | 0 << 11 | 1 << 9 \n\t"); ++ ++ base = &mxu->csr; ++ asm volatile(".word 0x7010f803 | 9 << 6 \n\t"); // t1 <- mxu.csr ++ asm volatile(".word 0xac000000 | 8 << 21 | 9 << 16 \n\t"); // sw $t1 0($t0) ++#else ++ base = &mxu->vpr[0]; ++ SA(o, VR0, 0, base, 0); ++ SA(o, VR0, 1, base, 32); ++ ++ base = &mxu->vpr[1]; ++ SA(o, VR1, 0, base, 0); ++ SA(o, VR1, 1, base, 32); ++ ++ base = &mxu->vpr[2]; ++ SA(o, VR2, 0, base, 0); ++ SA(o, VR2, 1, base, 32); ++ ++ base = &mxu->vpr[3]; ++ SA(o, VR3, 0, base, 0); ++ SA(o, VR3, 1, base, 32); ++ ++ base = &mxu->vpr[4]; ++ SA(o, VR4, 0, base, 0); ++ SA(o, VR4, 1, base, 32); ++ ++ base = &mxu->vpr[5]; ++ SA(o, VR5, 0, base, 0); ++ SA(o, VR5, 1, base, 32); ++ ++ base = &mxu->vpr[6]; ++ SA(o, VR6, 0, base, 0); ++ SA(o, VR6, 1, base, 32); ++ ++ base = &mxu->vpr[7]; ++ SA(o, VR7, 0, base, 0); ++ SA(o, VR7, 1, base, 32); ++ ++ base = &mxu->vpr[8]; ++ SA(o, VR8, 0, base, 0); ++ SA(o, VR8, 1, base, 32); ++ ++ base = &mxu->vpr[9]; ++ SA(o, VR9, 0, base, 0); ++ SA(o, VR9, 1, base, 32); ++ ++ base = &mxu->vpr[10]; ++ SA(o, VR10, 0, base, 0); ++ SA(o, VR10, 1, base, 32); ++ ++ base = &mxu->vpr[11]; ++ SA(o, VR11, 0, base, 0); ++ SA(o, VR11, 1, base, 32); ++ ++ base = &mxu->vpr[12]; ++ SA(o, VR12, 0, base, 0); ++ SA(o, VR12, 1, base, 32); ++ ++ base = &mxu->vpr[13]; ++ SA(o, VR13, 0, base, 0); ++ SA(o, VR13, 1, base, 32); ++ ++ base = &mxu->vpr[14]; ++ SA(o, VR14, 0, base, 0); ++ SA(o, VR14, 1, base, 32); ++ ++ base = &mxu->vpr[15]; ++ SA(o, VR15, 0, base, 0); ++ SA(o, VR15, 1, base, 32); ++ ++ base = &mxu->vpr[16]; ++ SA(o, VR16, 0, base, 0); ++ SA(o, VR16, 1, base, 32); ++ ++ base = &mxu->vpr[17]; ++ SA(o, VR17, 0, base, 0); ++ SA(o, VR17, 1, base, 32); ++ ++ base = &mxu->vpr[18]; ++ SA(o, VR18, 0, base, 0); ++ SA(o, VR18, 1, base, 32); ++ ++ base = &mxu->vpr[19]; ++ SA(o, VR19, 0, base, 0); ++ SA(o, VR19, 1, base, 32); ++ ++ base = &mxu->vpr[20]; ++ SA(o, VR20, 0, base, 0); ++ SA(o, VR20, 1, base, 32); ++ ++ base = &mxu->vpr[21]; ++ SA(o, VR21, 0, base, 0); ++ SA(o, VR21, 1, base, 32); ++ ++ base = &mxu->vpr[22]; ++ SA(o, VR22, 0, base, 0); ++ SA(o, VR22, 1, base, 32); ++ ++ base = &mxu->vpr[23]; ++ SA(o, VR23, 0, base, 0); ++ SA(o, VR23, 1, base, 32); ++ ++ base = &mxu->vpr[24]; ++ SA(o, VR24, 0, base, 0); ++ SA(o, VR24, 1, base, 32); ++ ++ base = &mxu->vpr[25]; ++ SA(o, VR25, 0, base, 0); ++ SA(o, VR25, 1, base, 32); ++ ++ base = &mxu->vpr[26]; ++ SA(o, VR26, 0, base, 0); ++ SA(o, VR26, 1, base, 32); ++ ++ base = &mxu->vpr[27]; ++ SA(o, VR27, 0, base, 0); ++ SA(o, VR27, 1, base, 32); ++ ++ base = &mxu->vpr[28]; ++ SA(o, VR28, 0, base, 0); ++ SA(o, VR28, 1, base, 32); ++ ++ base = &mxu->vpr[29]; ++ SA(o, VR29, 0, base, 0); ++ SA(o, VR29, 1, base, 32); ++ ++ base = &mxu->vpr[30]; ++ SA(o, VR30, 0, base, 0); ++ SA(o, VR30, 1, base, 32); ++ ++ base = &mxu->vpr[31]; ++ SA(o, VR31, 0, base, 0); ++ SA(o, VR31, 1, base, 32); ++ ++ base = &mxu->vsr[0]; ++ MFSUM(VR0, VS0); ++ SA(o, VR0, 0, base, 0); ++ SA(o, VR0, 1, base, 32); ++ ++ base = &mxu->vsr[1]; ++ MFSUM(VR0, VS1); ++ SA(o, VR0, 0, base, 0); ++ SA(o, VR0, 1, base, 32); ++ ++ base = &mxu->vsr[2]; ++ MFSUM(VR0, VS2); ++ SA(o, VR0, 0, base, 0); ++ SA(o, VR0, 1, base, 32); ++ ++ base = &mxu->vsr[3]; ++ MFSUM(VR0, VS3); ++ SA(o, VR0, 0, base, 0); ++ SA(o, VR0, 1, base, 32); ++ ++ base = &mxu->csr; ++ CFCMXU(base1, 31); ++ asm volatile("sw $t1, 0($t0)\n\t"); ++#endif ++} ++ ++/*__attribute__((optimize("O0")))*/ ++void __restore_mxuv3(void * tsk_void) ++{ ++ register void *base asm("t0"); ++ struct task_struct *tsk = tsk_void; ++ struct xburst_mxu_struct *mxu = &tsk->thread.mxu; ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, , KSTK_STATUS(tsk)=0x%lx, task->tgid=%d, task->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), KSTK_STATUS(current), current->tgid, current->pid, KSTK_STATUS(tsk), tsk->tgid, tsk->pid); ++ //dump_stack(); ++ //printk("%s(%d):smp_processor_id()=%d, read_c0_status()=0x%x, task_cpu(current)=%d, KSTK_STATUS(current)=0x%lx, current->tgid=%d, current->pid=%d, task_cpu(p)=%d, KSTK_STATUS(p)=0x%lx, p->tgid=%d, p->pid=%d\n", __func__, __LINE__, smp_processor_id(), read_c0_status(), task_cpu(current), KSTK_STATUS(current), current->tgid, current->pid, task_cpu(tsk), KSTK_STATUS(tsk), tsk->tgid, tsk->pid); ++#ifdef WORDCODE ++ /** ++ * lao ins: hex(0x70001811 | 8 << 21 | 1 << 16 | 1 << 14 | 0 << 6) ++ * cmd: 0x70001811 ->la0 ++ * base: 8 ->t0 ++ * offset: 1 ->32>>5 ++ * nn: 1 ->nn // o means to be divided by 512/256=2, so n=[0,1] ++ * vpr: 0 ->vpr0 ++ * because t0 is fixed, so 0x70001811 | 8 << 21 = 0x71001811 ++ * so the word format as follows: ++ * asm volatile(".word 0x71001811 | offset << 16 | n << 14 | vprn << 6 \n\t"); ++ * ++ * mtsum ins: hex(0x4a60001d | vrs << 16 | vsd << 6) ++ * for we fixed vrs to 0, so the word format as follows: ++ * asm volatile(".word 0x4a60001d | vss << 6 \n\t"); ++ */ ++ base = &mxu->csr; ++ asm volatile(".word 0x8c000000 | 8 << 21 | 9 << 16\n\t");// lw $t1, 0($t0) ++ asm volatile(".word 0x7011f803 | 9 << 21 \n\t");// mxu.csr <- t1 ++ ++ base = &mxu->vsr[0]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x4a60001d | 0 << 6 \n\t"); ++ ++ base = &mxu->vsr[1]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x4a60001d | 1 << 6 \n\t"); ++ ++ base = &mxu->vsr[2]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x4a60001d | 2 << 6 \n\t"); ++ ++ base = &mxu->vsr[3]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x4a60001d | 3 << 6 \n\t"); ++ ++ base = &mxu->vpr[0]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 0 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 0 << 6 \n\t"); ++ ++ base = &mxu->vpr[1]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 1 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 1 << 6 \n\t"); ++ ++ base = &mxu->vpr[2]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 2 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 2 << 6 \n\t"); ++ ++ base = &mxu->vpr[3]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 3 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 3 << 6 \n\t"); ++ ++ base = &mxu->vpr[4]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 4 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 4 << 6 \n\t"); ++ ++ base = &mxu->vpr[5]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 5 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 5 << 6 \n\t"); ++ ++ base = &mxu->vpr[6]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 6 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 6 << 6 \n\t"); ++ ++ base = &mxu->vpr[7]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 7 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 7 << 6 \n\t"); ++ ++ base = &mxu->vpr[8]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 8 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 8 << 6 \n\t"); ++ ++ base = &mxu->vpr[9]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 9 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 9 << 6 \n\t"); ++ ++ base = &mxu->vpr[10]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 10 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 10 << 6 \n\t"); ++ ++ base = &mxu->vpr[11]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 11 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 11 << 6 \n\t"); ++ ++ base = &mxu->vpr[12]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 12 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 12 << 6 \n\t"); ++ ++ base = &mxu->vpr[13]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 13 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 13 << 6 \n\t"); ++ ++ base = &mxu->vpr[14]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 14 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 14 << 6 \n\t"); ++ ++ base = &mxu->vpr[15]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 15 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 15 << 6 \n\t"); ++ ++ base = &mxu->vpr[16]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 16 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 16 << 6 \n\t"); ++ ++ base = &mxu->vpr[17]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 17 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 17 << 6 \n\t"); ++ ++ base = &mxu->vpr[18]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 18 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 18 << 6 \n\t"); ++ ++ base = &mxu->vpr[19]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 19 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 19 << 6 \n\t"); ++ ++ base = &mxu->vpr[20]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 20 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 20 << 6 \n\t"); ++ ++ base = &mxu->vpr[21]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 21 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 21 << 6 \n\t"); ++ ++ base = &mxu->vpr[22]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 22 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 22 << 6 \n\t"); ++ ++ base = &mxu->vpr[23]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 23 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 23 << 6 \n\t"); ++ ++ base = &mxu->vpr[24]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 24 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 24 << 6 \n\t"); ++ ++ base = &mxu->vpr[25]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 25 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 25 << 6 \n\t"); ++ ++ base = &mxu->vpr[26]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 26 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 26 << 6 \n\t"); ++ ++ base = &mxu->vpr[27]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 27 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 27 << 6 \n\t"); ++ ++ base = &mxu->vpr[28]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 28 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 28 << 6 \n\t"); ++ ++ base = &mxu->vpr[29]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 29 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 29 << 6 \n\t"); ++ ++ base = &mxu->vpr[30]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 30 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 30 << 6 \n\t"); ++ ++ base = &mxu->vpr[31]; ++ asm volatile(".word 0x71001811 | 0 << 16 | 0 << 14 | 31 << 6 \n\t"); ++ asm volatile(".word 0x71001811 | 1 << 16 | 1 << 14 | 31 << 6 \n\t"); ++#else ++ base = &mxu->csr; ++ asm volatile("lw $t1, 0($t0)\n\t"); ++ CTCMXU(31, base1); ++ ++ base = &mxu->vsr[0]; ++ LA(o, VR0, 0, base, 0); ++ LA(o, VR0, 1, base, 32); ++ MTSUM(VS0, VR0); ++ ++ base = &mxu->vsr[1]; ++ LA(o, VR0, 0, base, 0); ++ LA(o, VR0, 1, base, 32); ++ MTSUM(VS1, VR0); ++ ++ base = &mxu->vsr[2]; ++ LA(o, VR0, 0, base, 0); ++ LA(o, VR0, 1, base, 32); ++ MTSUM(VS2, VR0); ++ ++ base = &mxu->vsr[3]; ++ LA(o, VR0, 0, base, 0); ++ LA(o, VR0, 1, base, 32); ++ MTSUM(VS3, VR0); ++ ++ base = &mxu->vpr[0]; ++ LA(o, VR0, 0, base, 0); ++ LA(o, VR0, 1, base, 32); ++ ++ base = &mxu->vpr[1]; ++ LA(o, VR1, 0, base, 0); ++ LA(o, VR1, 1, base, 32); ++ ++ base = &mxu->vpr[2]; ++ LA(o, VR2, 0, base, 0); ++ LA(o, VR2, 1, base, 32); ++ ++ base = &mxu->vpr[3]; ++ LA(o, VR3, 0, base, 0); ++ LA(o, VR3, 1, base, 32); ++ ++ base = &mxu->vpr[4]; ++ LA(o, VR4, 0, base, 0); ++ LA(o, VR4, 1, base, 32); ++ ++ base = &mxu->vpr[5]; ++ LA(o, VR5, 0, base, 0); ++ LA(o, VR5, 1, base, 32); ++ ++ base = &mxu->vpr[6]; ++ LA(o, VR6, 0, base, 0); ++ LA(o, VR6, 1, base, 32); ++ ++ base = &mxu->vpr[7]; ++ LA(o, VR7, 0, base, 0); ++ LA(o, VR7, 1, base, 32); ++ ++ base = &mxu->vpr[8]; ++ LA(o, VR8, 0, base, 0); ++ LA(o, VR8, 1, base, 32); ++ ++ base = &mxu->vpr[9]; ++ LA(o, VR9, 0, base, 0); ++ LA(o, VR9, 1, base, 32); ++ ++ base = &mxu->vpr[10]; ++ LA(o, VR10, 0, base, 0); ++ LA(o, VR10, 1, base, 32); ++ ++ base = &mxu->vpr[11]; ++ LA(o, VR11, 0, base, 0); ++ LA(o, VR11, 1, base, 32); ++ ++ base = &mxu->vpr[12]; ++ LA(o, VR12, 0, base, 0); ++ LA(o, VR12, 1, base, 32); ++ ++ base = &mxu->vpr[13]; ++ LA(o, VR13, 0, base, 0); ++ LA(o, VR13, 1, base, 32); ++ ++ base = &mxu->vpr[14]; ++ LA(o, VR14, 0, base, 0); ++ LA(o, VR14, 1, base, 32); ++ ++ base = &mxu->vpr[15]; ++ LA(o, VR15, 0, base, 0); ++ LA(o, VR15, 1, base, 32); ++ ++ base = &mxu->vpr[16]; ++ LA(o, VR16, 0, base, 0); ++ LA(o, VR16, 1, base, 32); ++ ++ base = &mxu->vpr[17]; ++ LA(o, VR17, 0, base, 0); ++ LA(o, VR17, 1, base, 32); ++ ++ base = &mxu->vpr[18]; ++ LA(o, VR18, 0, base, 0); ++ LA(o, VR18, 1, base, 32); ++ ++ base = &mxu->vpr[19]; ++ LA(o, VR19, 0, base, 0); ++ LA(o, VR19, 1, base, 32); ++ ++ base = &mxu->vpr[20]; ++ LA(o, VR20, 0, base, 0); ++ LA(o, VR20, 1, base, 32); ++ ++ base = &mxu->vpr[21]; ++ LA(o, VR21, 0, base, 0); ++ LA(o, VR21, 1, base, 32); ++ ++ base = &mxu->vpr[22]; ++ LA(o, VR22, 0, base, 0); ++ LA(o, VR22, 1, base, 32); ++ ++ base = &mxu->vpr[23]; ++ LA(o, VR23, 0, base, 0); ++ LA(o, VR23, 1, base, 32); ++ ++ base = &mxu->vpr[24]; ++ LA(o, VR24, 0, base, 0); ++ LA(o, VR24, 1, base, 32); ++ ++ base = &mxu->vpr[25]; ++ LA(o, VR25, 0, base, 0); ++ LA(o, VR25, 1, base, 32); ++ ++ base = &mxu->vpr[26]; ++ LA(o, VR26, 0, base, 0); ++ LA(o, VR26, 1, base, 32); ++ ++ base = &mxu->vpr[27]; ++ LA(o, VR27, 0, base, 0); ++ LA(o, VR27, 1, base, 32); ++ ++ base = &mxu->vpr[28]; ++ LA(o, VR28, 0, base, 0); ++ LA(o, VR28, 1, base, 32); ++ ++ base = &mxu->vpr[29]; ++ LA(o, VR29, 0, base, 0); ++ LA(o, VR29, 1, base, 32); ++ ++ base = &mxu->vpr[30]; ++ LA(o, VR30, 0, base, 0); ++ LA(o, VR30, 1, base, 32); ++ ++ base = &mxu->vpr[31]; ++ LA(o, VR31, 0, base, 0); ++ LA(o, VR31, 1, base, 32); ++#endif ++} +diff --git a/arch/mips/xburst2/common/proc.c b/arch/mips/xburst2/common/proc.c +new file mode 100644 +index 000000000..a32e05820 +--- /dev/null ++++ b/arch/mips/xburst2/common/proc.c +@@ -0,0 +1,92 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++static struct proc_dir_entry *proc_jz_root; ++struct proc_dir_entry * jz_proc_mkdir(char *s) ++{ ++ struct proc_dir_entry *p; ++ if(!proc_jz_root) { ++ proc_jz_root = proc_mkdir("jz", 0); ++ if(!proc_jz_root) ++ return NULL; ++ } ++ p = proc_mkdir(s,proc_jz_root); ++ return p; ++} ++ ++EXPORT_SYMBOL(jz_proc_mkdir); ++ ++static int jz_proc_show(struct seq_file *filq, void *v) ++{ ++ int ret = 1; ++ struct jz_single_file_ops *proc_fops = filq->private; ++ filq->private = proc_fops->data; ++ ++ if(proc_fops->read) ++ ret = proc_fops->read(filq, v); ++ ++ filq->private = proc_fops; ++ return ret; ++} ++static int jz_proc_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, jz_proc_show, PDE_DATA(inode)); ++} ++static ssize_t jz_proc_write(struct file *file, const char __user *buffer, size_t usize, loff_t *off) ++{ ++ size_t ret; ++ struct jz_single_file_ops *proc_fops = ((struct seq_file *)file->private_data)->private; ++ ((struct seq_file *)file->private_data)->private = proc_fops->data; ++ ++ ret = proc_fops->write(file, buffer, usize, off); ++ ((struct seq_file *)file->private_data)->private = proc_fops; ++ ++ return ret; ++} ++ ++struct proc_dir_entry *jz_proc_create_data( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops, void *data) ++{ ++ struct proc_ops *jz_proc_fops; ++ ++ jz_proc_fops = kmalloc(sizeof(struct proc_ops), GFP_KERNEL); ++ if(!jz_proc_fops) { ++ return NULL; ++ } ++ ++ jz_proc_fops->proc_read = seq_read; ++ jz_proc_fops->proc_lseek = seq_lseek; ++ jz_proc_fops->proc_release = single_release; ++ jz_proc_fops->proc_open = jz_proc_open; ++ jz_proc_fops->proc_write = jz_proc_write; ++ proc_fops->data = data; ++ ++ return proc_create_data(name, mode, parent, jz_proc_fops, proc_fops); ++} ++ ++struct proc_dir_entry *jz_proc_create( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops) ++{ ++ return jz_proc_create_data(name, mode, parent, proc_fops, NULL); ++} ++ ++struct proc_dir_entry * get_jz_proc_root(void) ++{ ++ if(!proc_jz_root) { ++ proc_jz_root = proc_mkdir("jz", 0); ++ if(!proc_jz_root) ++ return NULL; ++ } ++ return proc_jz_root; ++} +diff --git a/arch/mips/xburst2/core/Makefile b/arch/mips/xburst2/core/Makefile +new file mode 100644 +index 000000000..f24f8fa4d +--- /dev/null ++++ b/arch/mips/xburst2/core/Makefile +@@ -0,0 +1,4 @@ ++obj-y += prom.o ++ ++obj-$(CONFIG_XBURST2_CPU_SCACHE) += sc.o ++obj-$(CONFIG_SMP) += smp.o +diff --git a/arch/mips/xburst2/core/include/ccu.h b/arch/mips/xburst2/core/include/ccu.h +new file mode 100644 +index 000000000..af3b9c628 +--- /dev/null ++++ b/arch/mips/xburst2/core/include/ccu.h +@@ -0,0 +1,42 @@ ++ ++#ifndef __CCU_H__ ++#define __CCU_H__ ++ ++#include ++#define CCU_RESET_ENTRY 0xbfc00000 ++ ++#define get_ccu_cscr() inl(CCU_IO_BASE + 0) ++#define set_ccu_cscr(val) outl(val, CCU_IO_BASE + 0) ++ ++#define get_ccu_cssr() inl(CCU_IO_BASE + 0x20) ++ ++#define get_ccu_csrr() inl(CCU_IO_BASE + 0x40) ++#define set_ccu_csrr(val) outl(val, CCU_IO_BASE + 0x40) ++ ++#define get_ccu_pipr() inl(CCU_IO_BASE + 0x100) ++ ++#define get_ccu_pimr() inl(CCU_IO_BASE + 0x120) ++#define set_ccu_pimr(val) outl(val, CCU_IO_BASE + 0x120) ++ ++#define get_ccu_mipr() inl(CCU_IO_BASE + 0x140) ++ ++#define get_ccu_mimr() inl(CCU_IO_BASE + 0x160) ++#define set_ccu_mimr(val) outl(val, CCU_IO_BASE + 0x160) ++ ++#define get_ccu_oipr() inl(CCU_IO_BASE + 0x180) ++ ++#define get_ccu_oimr() inl(CCU_IO_BASE + 0x1a0) ++#define set_ccu_oimr(val) outl(val, CCU_IO_BASE + 0x1a0) ++ ++#define get_ccu_rer() inl(CCU_IO_BASE + 0xf00) ++#define set_ccu_rer(val) outl(val, CCU_IO_BASE + 0xf00) ++ ++#define get_ccu_cslr() inl(CCU_IO_BASE + 0xff8) ++#define set_ccu_cslr(val) outl(val, CCU_IO_BASE + 0xff8) ++ ++#define get_ccu_csar() inl(CCU_IO_BASE + 0xffc) ++#define set_ccu_csar(val) outl(val, CCU_IO_BASE + 0xffc) ++ ++//#define get_ccu_mbr(cpu_id) inl(CCU_IO_BASE + 0x1000 + cpu_id*4) ++//#define set_ccu_mbr(cpu_id, val) outl(val, CCU_IO_BASE + 0x1000 + cpu_id*4) ++#endif +diff --git a/arch/mips/xburst2/core/include/core_base.h b/arch/mips/xburst2/core/include/core_base.h +new file mode 100644 +index 000000000..14d0071bd +--- /dev/null ++++ b/arch/mips/xburst2/core/include/core_base.h +@@ -0,0 +1,6 @@ ++#ifndef __CORE_BASE_H__ ++#define __CORE_BASE_H__ ++ ++#define CCU_IO_BASE 0x12200000 ++ ++#endif /* __CORE_BASE_H__ */ +diff --git a/arch/mips/xburst2/core/include/ingenic_proc.h b/arch/mips/xburst2/core/include/ingenic_proc.h +new file mode 100644 +index 000000000..a1883087e +--- /dev/null ++++ b/arch/mips/xburst2/core/include/ingenic_proc.h +@@ -0,0 +1,18 @@ ++#ifndef _INGENIC_PROC_H_ ++#define _INGENIC_PROC_H_ ++ ++struct jz_single_file_ops { ++ ssize_t (*read) (struct seq_file *, void *); ++ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ++ void *data; ++}; ++ ++struct proc_dir_entry * jz_proc_mkdir(char *s); ++struct proc_dir_entry *jz_proc_create_data( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops, void *data); ++struct proc_dir_entry *jz_proc_create( ++ const char *name, umode_t mode, struct proc_dir_entry *parent, ++ struct jz_single_file_ops *proc_fops); ++struct proc_dir_entry * get_jz_proc_root(void); ++#endif /* _INGENIC_PROC_H_ */ +diff --git a/arch/mips/xburst2/core/include/irq_cpu.h b/arch/mips/xburst2/core/include/irq_cpu.h +new file mode 100644 +index 000000000..0584b7b84 +--- /dev/null ++++ b/arch/mips/xburst2/core/include/irq_cpu.h +@@ -0,0 +1,6 @@ ++#ifndef IRQ_CPU_H ++#define IRQ_CPU_H ++ ++void ingenic_irq_migration(int lock); ++void ingenic_irq_cpumask_idle(int idle); ++#endif /* IRQ_CPU_H */ +diff --git a/arch/mips/xburst2/core/include/mxu.h b/arch/mips/xburst2/core/include/mxu.h +new file mode 100755 +index 000000000..fae67540a +--- /dev/null ++++ b/arch/mips/xburst2/core/include/mxu.h +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (C) 2005 Mips Technologies ++ * Author: Chris Dearman, chris@mips.com derived from fpu.h ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++#ifndef _ASM_MXU_H ++#define _ASM_MXU_H ++ ++#include ++#include ++#include ++#include ++ ++#define NUM_MXU_REGS (0) ++ ++/* There is no mxu implement in XBURST2, leave empty */ ++static inline void __init_mxu(void) ++{ ++} ++static inline void __save_mxu(void * tsk_void) ++{ ++} ++static inline void __restore_mxu(void * tsk_void) ++{ ++} ++ ++static inline void init_mxu(void) ++{ ++ if(cpu_has_mxu) ++ __init_mxu(); ++} ++ ++ ++#define save_mxu(tsk) \ ++ do { \ ++ if (cpu_has_mxu) \ ++ __save_mxu(tsk); \ ++ } while (0) ++ ++#define restore_mxu(tsk) \ ++ do { \ ++ if (cpu_has_mxu) \ ++ __restore_mxu(tsk); \ ++ } while (0) ++ ++#define __get_mxu_regs(tsk) \ ++ ({ \ ++ NULL; \ ++ }) ++ ++#define __let_mxu_regs(tsk,regs) \ ++ do{ \ ++ }while(0) ++ ++#endif /* _ASM_MXU_H */ +diff --git a/arch/mips/xburst2/core/include/mxuv3.h b/arch/mips/xburst2/core/include/mxuv3.h +new file mode 100644 +index 000000000..10c631b0e +--- /dev/null ++++ b/arch/mips/xburst2/core/include/mxuv3.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2005 Mips Technologies ++ * Author: Chris Dearman, chris@mips.com derived from fpu.h ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++#ifndef _ASM_MXU_V3_H ++#define _ASM_MXU_V3_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++void __init_mxuv3(void); ++void __save_mxuv3(void *tsk_void); ++void __restore_mxuv3(void *tsk_void); ++ ++static inline void init_mxuv3(void) ++{ ++ if(cpu_has_mxuv3) ++ __init_mxuv3(); ++} ++ ++ ++#define save_mxuv3(tsk) \ ++ do { \ ++ if (cpu_has_mxuv3) \ ++ __save_mxuv3(tsk); \ ++ } while (0) ++ ++static inline unsigned int is_mxuv3_enabled(void) ++{ ++ return ((cpu_has_mxuv3) && (read_c0_status() & ST0_CU2)); ++} ++ ++#define restore_mxuv3(tsk) \ ++ do { \ ++ if (cpu_has_mxuv3) \ ++ __restore_mxuv3(tsk); \ ++ } while (0) ++ ++#endif /* _ASM_MXU_V3_H */ +diff --git a/arch/mips/xburst2/core/prom.c b/arch/mips/xburst2/core/prom.c +new file mode 100644 +index 000000000..8dcb80d5c +--- /dev/null ++++ b/arch/mips/xburst2/core/prom.c +@@ -0,0 +1,79 @@ ++/* ++ * Copyright (C) 2010, Lars-Peter Clausen ++ * JZ4740 SoC prom code ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static __init void prom_init_cmdline(int argc, char *argv[]) ++{ ++ unsigned int count = COMMAND_LINE_SIZE - 1; ++ int i; ++ char *dst = &(arcs_cmdline[0]); ++ char *src; ++ ++ for (i = 1; i < argc && count; ++i) { ++ src = argv[i]; ++ while (*src && count) { ++ *dst++ = *src++; ++ --count; ++ } ++ *dst++ = ' '; ++ } ++ if (i > 1) ++ --dst; ++ ++ *dst = 0; ++} ++extern struct plat_smp_ops xburst2_smp_ops; ++static void *_fw_fdt_addr; ++ ++void __init prom_init(void) ++{ ++ prom_init_cmdline((int)fw_arg0, (char **)fw_arg1); ++ ++ if (fw_arg0 == 0 && fw_arg1 == 0xffffffffUL) ++ _fw_fdt_addr = phys_to_virt(fw_arg2); ++ else if ((int)fw_arg0 == -2) /*UHI*/ ++ _fw_fdt_addr = (void *)fw_arg1; ++ else if ((void*)__dtb_start != (void*)__dtb_end) ++ _fw_fdt_addr = __dtb_start; ++ else ++ panic("no dtb found!\n"); ++ ++ mips_machtype = MACH_INGENIC_X2000; ++#ifdef CONFIG_SMP ++ register_smp_ops(&xburst2_smp_ops); ++#endif ++} ++ ++void __init prom_free_prom_memory(void) ++{ ++} ++ ++const char *get_system_type(void) ++{ ++// return CONFIG_BOARD_NAME; ++ return "xburst2-based"; ++} ++void __init *get_fdt_addr(void) ++{ ++ return _fw_fdt_addr; ++} +diff --git a/arch/mips/xburst2/core/sc.c b/arch/mips/xburst2/core/sc.c +new file mode 100644 +index 000000000..229a9c539 +--- /dev/null ++++ b/arch/mips/xburst2/core/sc.c +@@ -0,0 +1,199 @@ ++/* ++ * Copyright (C) 2006 Chris Dearman (chris@mips.com), ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * MIPS32/MIPS64 L2 cache handling ++ */ ++static unsigned long scache_size __read_mostly; ++/* ++ * Writeback and invalidate the secondary cache before DMA. ++ */ ++static void mips_sc_wback_inv(unsigned long addr, unsigned long size) ++{ ++ __sync(); ++ if (size >= scache_size) { ++ unsigned long lsize = cpu_scache_line_size(); ++ if (lsize == 64) ++ blast_scache64(); ++ else if (lsize == 32) ++ blast_scache32(); ++ else ++ printk("Error: Second CacheLine size.\n"); ++ } else { ++ blast_scache_range(addr, addr + size); ++ } ++#ifdef MIPS_BRIDGE_SYNC_WAR ++ if (MIPS_BRIDGE_SYNC_WAR) ++ __fast_iob(); ++#endif ++} ++ ++/* ++ * Invalidate the secondary cache before DMA. ++ */ ++static void mips_sc_inv(unsigned long addr, unsigned long size) ++{ ++ unsigned long lsize = cpu_scache_line_size(); ++ unsigned long almask = ~(lsize - 1); ++ ++ if (size >= scache_size) { ++ if (lsize == 64) ++ blast_scache64(); ++ else if (lsize == 32) ++ blast_scache32(); ++ else ++ printk("Error: Second CacheLine size.\n"); ++ }else { ++ cache_op(Hit_Writeback_Inv_SD, addr & almask); ++ cache_op(Hit_Writeback_Inv_SD, (addr + size - 1) & almask); ++ blast_inv_scache_range(addr, addr + size); ++ } ++#ifdef MIPS_BRIDGE_SYNC_WAR ++ if (MIPS_BRIDGE_SYNC_WAR) ++ __fast_iob(); ++#endif ++} ++ ++static void mips_sc_enable(void) ++{ ++ /* L2 cache is permanently enabled */ ++} ++ ++static void mips_sc_disable(void) ++{ ++ /* L2 cache is permanently enabled */ ++} ++ ++static struct bcache_ops mips_sc_ops = { ++ .bc_enable = mips_sc_enable, ++ .bc_disable = mips_sc_disable, ++ .bc_wback_inv = mips_sc_wback_inv, ++ .bc_inv = mips_sc_inv ++}; ++ ++/* ++ * Check if the L2 cache controller is activated on a particular platform. ++ * MTI's L2 controller and the L2 cache controller of Broadcom's BMIPS ++ * cores both use c0_config2's bit 12 as "L2 Bypass" bit, that is the ++ * cache being disabled. However there is no guarantee for this to be ++ * true on all platforms. In an act of stupidity the spec defined bits ++ * 12..15 as implementation defined so below function will eventually have ++ * to be replaced by a platform specific probe. ++ */ ++//static inline int mips_sc_is_activated(struct cpuinfo_mips *c) ++//{ ++// unsigned int config2 = read_c0_config2(); ++// unsigned int tmp; ++// ++// /* Check the bypass bit (L2B) */ ++// /*switch (c->cputype) { ++// case CPU_34K: ++// case CPU_74K: ++// case CPU_1004K: ++// case CPU_BMIPS5000: ++// if (config2 & (1 << 12)) ++// return 0; ++// }*/ ++// ++// tmp = (config2 >> 4) & 0x0f; ++// if (0 < tmp && tmp <= 7) ++// c->scache.linesz = 2 << tmp; ++// else ++// return 0; ++// return 1; ++//} ++ ++static inline int __init mips_sc_probe(void) ++{ ++ struct cpuinfo_mips *c = ¤t_cpu_data; ++ unsigned int config1, config2; ++ unsigned int tmp; ++ ++ /* Mark as not present until probe completed */ ++ c->scache.flags |= MIPS_CACHE_NOT_PRESENT; ++ ++ /* Ignore anything but MIPSxx processors */ ++ if((c->isa_level & (MIPS_CPU_ISA_M32R1 ++ | MIPS_CPU_ISA_M32R1 ++ | MIPS_CPU_ISA_M64R1 ++ | MIPS_CPU_ISA_M64R2)) == 0) { ++ return 0; ++ } ++ ++ switch (c->processor_id & PRID_CPU_FEATURE_MASK) { ++ case PRID_CPU_X2000: ++ break; ++ default: ++ printk("pls check processor_id[0x%08x],sc_jz not support!\n",c->processor_id); ++ } ++ ++ /* Does this MIPS32/MIPS64 CPU have a config2 register? */ ++ config1 = read_c0_config1(); ++ if (!(config1 & MIPS_CONF_M)) ++ return 0; ++ ++ config2 = read_c0_config2(); ++ ++ //if (!mips_sc_is_activated(c)) ++ tmp = (config2 >> 4) & 0x0f; ++ if (0 < tmp && tmp <= 7) ++ c->scache.linesz = 2 << tmp; ++ else ++ return 0; ++ ++ tmp = (config2 >> 8) & 0x0f; ++ if (0 <= tmp && tmp <= 7) ++ c->scache.sets = 64 << tmp; ++ else ++ return 0; ++ ++ tmp = (config2 >> 0) & 0x0f; ++ if ((tmp == 7) || (tmp == 15)) ++ c->scache.ways = tmp + 1; ++ else ++ return 0; ++ ++ c->scache.waysize = c->scache.sets * c->scache.linesz; ++ c->scache.waybit = __ffs(c->scache.waysize); ++ ++ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; ++ scache_size = c->scache.ways * c->scache.sets * c->scache.linesz; ++ //write_c0_ecc(0x0);//verify xburst2 whether CP0-$26-0 is implemented. ++ return 1; ++} ++ ++static char *way_string[] = { NULL, "direct mapped", "2-way", ++ "3-way", "4-way", "5-way", "6-way", "7-way", "8-way", ++ "9-way", "10-way", "11-way", "12-way", ++ "13-way", "14-way", "15-way", "16-way", ++}; ++ ++int ingenic_sc_init(void) ++{ ++ struct cpuinfo_mips *c = ¤t_cpu_data; ++ int found = mips_sc_probe(); ++ printk("=======found ...... ingenic sc cache ops ...!, found: %d\n\n", found); ++ if (found) { ++ mips_sc_enable(); ++ bcops = &mips_sc_ops; ++ } ++ ++ printk("Unified secondary cache %ldkB %s, linesize %d bytes.\n", ++ scache_size >> 10, way_string[c->scache.ways], c->scache.linesz); ++ ++ c->options |= MIPS_CPU_INCLUSIVE_CACHES; ++ return found; ++} +diff --git a/arch/mips/xburst2/core/smp.c b/arch/mips/xburst2/core/smp.c +new file mode 100644 +index 000000000..17e91f513 +--- /dev/null ++++ b/arch/mips/xburst2/core/smp.c +@@ -0,0 +1,505 @@ ++/* ++ * Copyright (C) 2001, 2002, 2003 Broadcom Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++//#define DEBUG ++//#define SMP_DEBUG ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++ ++#include ++ ++#include ++#include ++ ++#ifdef SMP_DEBUG ++static void xburst2_ccu_showregs(void) ++{ ++ int cpu = smp_processor_id(); ++ unsigned int val; ++ printk("CPU%d:\n",cpu); ++#define P(reg) do { \ ++ val = get_ccu_##reg(); \ ++ printk(#reg ":\t%08x\n", val); \ ++ } while(0) ++ ++ P(cscr); P(cssr); P(csrr); P(pipr); P(pimr); ++ P(mipr); P(mimr); P(oipr); P(oimr); P(rer); ++ P(cslr); P(csar); ++ //P(val); P(lock); ++ printk("cp0 status:\t%08x\n", read_c0_status()); ++ printk("cp0 cause:\t%08x\n", read_c0_cause()); ++} ++static void dump_code(const unsigned int *handler, const int count) ++{ ++ int i; ++ pr_info("\t.set push\n"); ++ pr_info("\t.set noreorder\n"); ++ ++ for (i = 0; i < count; i++) ++ pr_info("\t.word\t0x%08x\t\t# %p\n", handler[i], &handler[i]); ++ ++ pr_info("\t.set\tpop\n"); ++} ++#else ++static inline void xburst2_ccu_showregs(void) {} ++static inline void dump_code(const unsigned int *handler, const int count) {} ++#endif ++struct xburst2_mailbox{ ++ raw_spinlock_t lock; ++ void *__iomem *iobase; ++}; ++struct xburst2_smp { ++ unsigned long context_sp, context_gp; ++ unsigned long entry_base; ++ struct xburst2_mailbox mailbox[NR_CPUS]; ++ struct xburst2_mailbox * __percpu* percpu_mailbox; ++}; ++static struct xburst2_smp smp_core; ++void ingenic_percpu_timerevent_init(unsigned int cpu_num); ++void ingenic_percpu_irq_init(unsigned int cpu_num); ++ ++static irqreturn_t xburst2_mbox_interrupt(int irq, void *data) ++{ ++ unsigned int action = 0; ++ struct xburst2_mailbox *mailbox = *(struct xburst2_mailbox **)data; ++ raw_spin_lock(&mailbox->lock); ++ action = readl(mailbox->iobase); ++ writel(0,mailbox->iobase); ++ raw_spin_unlock(&mailbox->lock); ++ if (!action) { ++ pr_err("SMP[%d]:invalid mailboxes action is NULL\n",smp_processor_id()); ++ goto ipi_finish; ++ } ++ if (action & SMP_CALL_FUNCTION) { ++ generic_smp_call_function_interrupt(); ++ } ++ ++ if (action & SMP_RESCHEDULE_YOURSELF) { ++ scheduler_ipi(); ++ } ++ipi_finish: ++ return IRQ_HANDLED; ++} ++ ++void percpu_mailbox_init(int cpu) ++{ ++ smp_core.mailbox[cpu].iobase = ioremap(CCU_IO_BASE + cpu * 4 + 0x1000,4); ++ raw_spin_lock_init(&smp_core.mailbox[cpu].lock); ++ *this_cpu_ptr(smp_core.percpu_mailbox) = &smp_core.mailbox[cpu]; ++ writel(0, smp_core.mailbox[cpu].iobase); ++ enable_percpu_irq(CORE_MAILBOX_IRQ, IRQ_TYPE_NONE); ++} ++/* ++ * Code to run on secondary just after probing the CPU ++ */ ++static void xburst2_init_secondary(void) ++{ ++ int cpu = smp_processor_id(); ++ unsigned int mb_msk = get_ccu_mimr(); ++ unsigned int pmsk = get_ccu_pimr(); ++ unsigned int cpu_num = read_c0_ebase() & 0x1ff; ++// unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2; ++// int ret; ++ if(cpu == 0){ ++ pr_info("BUG: cpu0 is booted.\n"); ++ dump_stack(); ++ while(1); ++ } ++ pr_info("#### now starting init for cpu : %d\n", cpu); ++ clear_c0_cause(CAUSEF_IP); ++ clear_c0_status(ST0_IM); ++ mb_msk |= 1 << cpu; ++ set_ccu_mimr(mb_msk); ++ percpu_mailbox_init(cpu); ++ pr_debug("percpu %x\n",read_c0_status()); ++ ingenic_percpu_irq_init(cpu_num); ++ pmsk |= (1 << cpu); ++ set_ccu_pimr(pmsk); ++ ++ /* jzcpu_timer_setup(); */ ++ ++ xburst2_ccu_showregs(); ++ ingenic_percpu_timerevent_init(cpu_num); ++ set_ccu_oimr((1<common->affinity; ++ struct irq_chip *c; ++ bool ret = false; ++ ++ if (irqd_is_per_cpu(d) || !cpumask_test_cpu(cpu, affinity)) ++ return false; ++ ++ c = irq_data_get_irq_chip(d); ++ if(!c->irq_set_affinity) ++ return false; ++ if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { ++ affinity = cpu_online_mask; ++ ret = true; ++ } ++ ++ if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret) ++ cpumask_copy(d->common->affinity, affinity); ++ ++ return ret; ++} ++ ++static void migrate_irqs(int cpu) ++{ ++ unsigned int i; ++ struct irq_desc *desc; ++ for_each_irq_desc(i, desc) { ++ raw_spin_lock(&desc->lock); ++ migrate_one_irq(cpu,desc); ++ raw_spin_unlock(&desc->lock); ++ } ++} ++ ++/* ++ * Do any tidying up before marking online and running the idle ++ * loop ++ */ ++static void xburst2_smp_finish(void) ++{ ++ int cpu = smp_processor_id(); ++ migrate_irqs(cpu); ++ xburst2_ccu_showregs(); ++ local_irq_enable(); ++ pr_info("[SMP] slave cpu%d start up finished.\n",smp_processor_id()); ++} ++static void build_bounce_code(struct xburst2_smp *smp) ++{ ++ unsigned long *spp,*gpp; ++ unsigned int entry = (unsigned int)smp_bootstrap; ++ unsigned int *p; ++ p = (unsigned int*)__get_free_pages(GFP_KERNEL, 0); ++ spp = (unsigned long *)&smp->context_sp; ++ gpp = (unsigned long *)&smp->context_gp; ++ smp->entry_base = (unsigned int)p; ++ ++#define STATUS_BITS (ST0_CU0) ++#define CAUSE_BITS (1 << 27) ++#define C0_CAUSE 13,0 ++#define C0_STATUS 12,0 ++#define C0_COUNT 9,0 ++ ++ ++#define C0_CONFIG_0 16,0 ++#define V0 2 ++#define V1 3 ++#define GP 28 ++#define SP 29 ++#define RA 31 ++ /* the instructions'max size is 128 byte */ ++ ++ /* Disable IFU Small Buffer, system low power opt. */ ++ UASM_i_MFC0(&p, V0, 16, 7); ++ uasm_i_ori(&p, V0, V0, 7 << 3); ++ UASM_i_MTC0(&p, V0, 16, 7); ++ ++ /* kseg0 cache attribute */ ++ UASM_i_MFC0(&p,V0,C0_CONFIG_0); ++ UASM_i_LA(&p,V1,~7); ++ uasm_i_and(&p,V0,V0,V1); ++ uasm_i_ori(&p,V0,V0,3); ++ UASM_i_MTC0(&p,V0,C0_CONFIG_0); ++ ++ /* cause to DC disable. and status regitster reset */ ++ UASM_i_LA(&p,V0,CAUSE_BITS); ++ UASM_i_MTC0(&p,V0,C0_CAUSE); ++ ++ UASM_i_MTC0(&p,0,C0_COUNT); ++ ++ UASM_i_LA(&p,V0,STATUS_BITS); ++ UASM_i_MTC0(&p,V0,C0_STATUS); ++ ++ UASM_i_LA(&p, SP, (unsigned long)spp); ++ UASM_i_LW(&p, SP, 0,SP); ++ UASM_i_LA(&p, GP, (unsigned long)gpp); ++ UASM_i_LW(&p, GP, 0,GP); ++ UASM_i_LA(&p, RA, entry); ++ uasm_i_jr(&p, RA); ++ uasm_i_nop(&p); ++ dump_code((const unsigned int*)smp->entry_base,24); ++ //the code in ddr should be sure. ++ dma_cache_wback_inv(smp->entry_base,128); ++} ++ ++/* ++ * Setup the PC, SP, and GP of a secondary processor and start it ++ * running! ++ */ ++static int xburst2_boot_secondary(int cpu, struct task_struct *idle) ++{ ++ unsigned int reset;//,mb_msk; ++//TODO: clk enable. ++ /* set soft reset. */ ++ pr_info("[SMP] Booting CPU%d ...\n", cpu); ++ /* set reset entry! */ ++ set_ccu_rer(smp_core.entry_base); ++ ++ reset = get_ccu_csrr(); ++ reset |= 1 << cpu; ++ set_ccu_csrr(reset); ++ smp_core.context_sp = __KSTK_TOS(idle); ++ smp_core.context_gp = (unsigned long)task_thread_info(idle); ++ wmb(); ++/* clear soft reset. */ ++ reset &= ~(1 << cpu); ++ set_ccu_csrr(reset); ++ pr_debug("percpu %x\n",read_c0_status()); ++ ++ return 0; ++} ++ ++// prepare smp all core register but core0 should be hold. ++// the code is initialise core ccu register. ++ ++static void __init xburst2_smp_setup(void) ++{ ++ int i, num; ++ //set smp all core register disable. ++ set_ccu_mimr(0); ++ //note:core reset register and core0 shouldn't be set. ++ set_ccu_csrr(0xfffe); ++ ++ ++ cpumask_clear_cpu(NR_CPUS, (struct cpumask *)cpu_possible_mask); ++ cpumask_clear_cpu(NR_CPUS, (struct cpumask *)cpu_present_mask); ++ ++ //initial core0 register. ++ ++ cpumask_set_cpu(0, (struct cpumask *)cpu_possible_mask); ++ cpumask_set_cpu(0, (struct cpumask *)cpu_present_mask); ++ ++ __cpu_number_map[0] = 0; ++ __cpu_logical_map[0] = 0; ++ ++ for (i = 1, num = 0; i < NR_CPUS; i++) { ++ cpumask_set_cpu(i, (struct cpumask *)cpu_possible_mask); ++ cpumask_set_cpu(i, (struct cpumask *)cpu_present_mask); ++ ++ __cpu_number_map[i] = ++num; ++ __cpu_logical_map[num] = i; ++ } ++ ++ pr_info("[SMP] Slave CPU(s) %i available.\n", num); ++} ++ ++//prepare initial code for every core. ++static void __init xburst2_prepare_cpus(unsigned int max_cpus) ++{ ++ int ret; ++ pr_info("[SMP] Prepare %d cores., cpu: %d\n", max_cpus, smp_processor_id());//qiao ++ ++ if (max_cpus <= 1) ++ return; ++ ++ smp_core.percpu_mailbox = alloc_percpu(struct xburst2_mailbox*); ++ if(!smp_core.percpu_mailbox) ++ pr_err("ERROR:alloc mailbox percpu fail!\n"); ++ ++ ret = request_percpu_irq(CORE_MAILBOX_IRQ,xburst2_mbox_interrupt,"jz-mailbox", ++ smp_core.percpu_mailbox); ++ if(ret) { ++ pr_err("ERROR: cpu%d request ost error\n",smp_processor_id()); ++ } ++ percpu_mailbox_init(0); ++ set_ccu_mimr(1 << 0); ++ /* prepare slave cpus entry code */ ++ build_bounce_code(&smp_core); ++ /* set reset entry point */ ++ set_ccu_rer(smp_core.entry_base);//qiao ++ pr_debug("smp_bounce.base: %08lx\n", smp_core.entry_base); ++} ++ ++static void xburst2_send_ipi_single(int cpu, unsigned int action) ++{ ++ //unsigned int timeout=0x1000000; ++ ++ struct xburst2_mailbox *mailbox = per_cpu(*smp_core.percpu_mailbox,cpu); ++ unsigned int val; ++ unsigned long flags; ++#if 0 ++ while((readl(mailbox->iobase) & action) && (--timeout)); ++ if(timeout == 0){ ++ pr_err("SMP[%d] action:%d will reenter\n",cpu,action); ++ } ++#endif ++ ++ raw_spin_lock_irqsave(&mailbox->lock,flags); ++ val = readl(mailbox->iobase); ++ writel(action | val,mailbox->iobase); ++ raw_spin_unlock_irqrestore(&mailbox->lock,flags); ++} ++ ++static void xburst2_send_ipi_mask(const struct cpumask *mask, unsigned int action) ++{ ++ int i; ++ for(i = 0; i < NR_CPUS;i++){ ++ if(cpumask_test_cpu(i,(struct cpumask *)mask)){ ++ xburst2_send_ipi_single(i,action); ++ } ++ } ++} ++/** ++ * all cpu finish ++ */ ++void xburst2_cpus_done(void) ++{ ++// FIXME: will remove this code. ++ pr_debug("[SMP]: xburst2_cpus_done\n"); ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ ++void ingenic_percpu_timerevent_deinit(void); ++void ingenic_percpu_irq_deinit(void); ++static int xburst2_cpu_disable(void) ++{ ++ unsigned int cpu = smp_processor_id(); ++ unsigned int val; ++ if (cpu == 0) ++ return -EBUSY; ++ pr_info("SMP: CPU%d is offline\n", cpu); ++ set_cpu_online(cpu, false); ++// cpumask_clear_cpu(cpu, &cpu_callin_map); ++ calculate_cpu_foreign_map(); ++ ++ val = get_ccu_pimr(); ++ val &= ~(1 << cpu); ++ set_ccu_pimr(val); ++ ++ val = get_ccu_oimr(); ++ val &= ~(1 << cpu); ++ set_ccu_oimr(val); ++ ++ //val = get_ccu_mimr(); ++ //val &= ~(1 << cpu); ++ //set_ccu_mimr(val); ++ ++ ingenic_percpu_irq_deinit(); ++ ingenic_percpu_timerevent_deinit(); ++ migrate_irqs(cpu); ++ clear_tasks_mm_cpumask(cpu); ++ ++ pr_debug("disabled cpu %d\n",cpu); ++ return 0; ++} ++ ++void xburst2_cpu_die(unsigned int cpu) ++{ ++ unsigned int timeout = 0x100000; ++ unsigned int reset; ++ if (cpu == 0) ++ return; ++ ++ while((get_ccu_cssr() & (1< ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++ ++ ++#define cpu_dcache_size() (32 * 1024) ++#define cpu_dcache_ways() 8 ++#define cpu_dcache_line_size() 32 ++#define cpu_icache_size() (32 * 1024) ++#define cpu_icache_ways() 8 ++#define cpu_icache_line_size() 32 ++#define cpu_has_xpa 0 ++#define cpu_has_tlb 1 ++#define cpu_has_tlbinv 1 ++#define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_4k_cache 1 ++#define cpu_has_tx39_cache 0 ++#define cpu_has_fpu 1 ++#define cpu_has_32fpr 0 ++#define cpu_has_counter 0 ++#define cpu_has_watch 1 ++#define cpu_has_divec 1 ++#define cpu_has_vce 0 ++#define cpu_has_cache_cdex_p 0 ++#define cpu_has_cache_cdex_s 0 ++#define cpu_has_prefetch 1 ++#define cpu_has_mcheck 1 ++#define cpu_has_ejtag 0 ++#define cpu_has_llsc 1 ++#define kernel_uses_llsc cpu_has_llsc ++#define cpu_has_mips16 0 ++#define cpu_has_mdmx 0 ++#define cpu_has_mips3d 0 ++#define cpu_has_smartmips 0 ++#define cpu_has_vtag_icache 0 ++#define cpu_has_dc_aliases 0 ++#define cpu_has_ic_fills_f_dc 0 ++#define cpu_has_pindexed_dcache 0 ++#define cpu_icache_snoops_remote_store 0 ++#define cpu_has_mips32r1 0 ++#define cpu_has_mips32r2 1 ++#define cpu_has_mips64r1 0 ++#define cpu_has_mips64r2 0 ++#define cpu_has_dsp 0 ++#define cpu_has_mipsmt 0 ++#define cpu_has_userlocal 1 ++#define cpu_has_rixi 1 ++#define cpu_has_nofpuex 0 ++#define cpu_has_64bits 0 ++#define cpu_has_64bit_zero_reg 0 ++#define cpu_has_vint 0 ++#define cpu_has_veic 0 ++#define cpu_has_inclusive_pcaches 0 ++#define kernel_uses_smartmips_rixi 0 ++#define cpu_has_mxu 0 ++#endif +diff --git a/arch/mips/xburst2/soc-m300/include/irq.h b/arch/mips/xburst2/soc-m300/include/irq.h +new file mode 100644 +index 000000000..0c1410546 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/include/irq.h +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2010 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_IRQ_H__ ++#define __ASM_MACH_INGENIC_IRQ_H__ ++#include ++#include ++ ++enum { ++#define GPIO_NR_IRQS (32 * 5 + 16) ++ IRQ_GPIO_BASE = (IRQ_INTC_END + 1), ++ IRQ_GPIO_END = IRQ_GPIO_BASE + GPIO_NR_IRQS - 1, ++ ++#define TCU_NR_IRQS (8) ++ IRQ_TCU_BASE, ++ IRQ_TCU_END = IRQ_TCU_BASE + TCU_NR_IRQS - 1, ++ ++#define MCU_NR_IRQS (5) ++ IRQ_MCU_BASE, ++ IRQ_MCU_END = IRQ_MCU_BASE + MCU_NR_IRQS - 1, ++ ++#define RESERVED_NR_IRQS (150) ++ IRQ_RESERVED_BASE, ++ IRQ_RESERVED_END = IRQ_RESERVED_BASE + RESERVED_NR_IRQS - 1, ++ ++ NR_IRQS, ++ ++ ++ ++}; ++ ++#endif +diff --git a/arch/mips/xburst2/soc-m300/include/libdmmu.h b/arch/mips/xburst2/soc-m300/include/libdmmu.h +new file mode 100644 +index 000000000..6e0fbdb42 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/include/libdmmu.h +@@ -0,0 +1,30 @@ ++#ifndef _LIBDMMU_ ++#define _LIBDMMU_ ++ ++#include ++ ++ ++struct dmmu_mm_ops { ++ int (*mm_release)(void *data); ++}; ++ ++struct dmmu_mm_notifier { ++ ++ struct device *dev; ++ void *data; ++ struct list_head list; ++ ++ struct dmmu_mm_ops *ops; ++}; ++ ++int dmmu_register_mm_notifier(struct dmmu_mm_notifier *dmn); ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len); ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len); ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len); ++int dmmu_unmap_all(struct device *dev); ++void dmmu_dump_vaddr(unsigned long vaddr); ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode); ++int dmmu_dump_map(unsigned long vaddr); ++ ++#endif +diff --git a/arch/mips/xburst2/soc-m300/include/soc/base.h b/arch/mips/xburst2/soc-m300/include/soc/base.h +new file mode 100644 +index 000000000..1b7d3d130 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/include/soc/base.h +@@ -0,0 +1,77 @@ ++ ++#ifndef __JZSOC_SOC_DEV_H__ ++#define __JZSOC_SOC_DEV_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 /* 64KB, AHB Bus Aribtier */ ++#define DDR_PHY_IOBASE 0x13011000 /* 4KB, DDR PHY */ ++#define DDRC_H0_IOBASE 0x13012000 /* 4KB, DDR Controller Registers@ASHB0 */ ++#define DPU_IOBASE 0x13050000 /* 64KB, LCD Controller */ ++#define CIM_IOBASE 0x13060000 /* 64KB, Camera Interface Module */ ++#define ROTATE_IOBASE 0x13070000 /* 64KB, Rotate DMA */ ++#define JPEG_IOBASE 0x130d0000 /* 64KB, VPU-JPEG */ ++ ++ ++/* AHB2 Bus Devices Base */ ++#define HARB2_IOBASE 0x13400000 /* 64KB, AHB Bus Arbiter */ ++#define NEMC_IOBASE 0x13410000 /* 64KB, External Normal Memory/Boot ROM/OTP Controller */ ++#define PDMA_IOBASE 0x13420000 /* 64KB, Programmable DMA Controller */ ++#define AES_IOBASE 0x13430000 /* 64KB, AES */ ++#define SFC_IOBASE 0x13440000 /* 64KB, SPI Flash Controller */ ++#define MSC0_IOBASE 0x13450000 /* 64KB, MMC SD Controller0 */ ++#define MSC1_IOBASE 0x13460000 /* 64KB, MMC SD Controller1 */ ++#define HASH_IOBASE 0x13470000 /* 64KB, HASH */ ++#define MAC_IOBASE 0x134b0000 /* 64KB, GMAC/MAC */ ++#define PWM_IOBASE 0x134c0000 /* 64KB, PWM */ ++#define DDRC_H2_IOBASE 0x134f0000 /* 4KB, DDR Controller Register @AHB2 */ ++#define AUDIO_IOBASE 0x134e0000 /* 64KB, Aduio System */ ++#define OTG_IOBASE 0x13500000 /* 256KB, OTG2.0 Controller */ ++#define EFUSE_IOBASE 0x13540000 /* 64KB, EFUSE */ ++//#define INTC_IOBASE 0x135f0000 /* Interrupt Controller */ /* TODO: to be fix */ ++ ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 /* 4KB, Clocks and Power Manager */ ++#define TCU_IOBASE 0x10002000 /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++#define WDT_IOBASE TCU_IOBASE /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++ ++#define RTC_IOBASE 0x10003000 /* 4KB, Real-Time Clock */ ++#define GPIO_IOBASE 0x10010000 /* 4KB, General-Purpose I/O */ ++#define UART0_IOBASE 0x10030000 /* 4KB, UART0 Controller */ ++#define UART1_IOBASE 0x10031000 /* 4KB, UART1 Controller */ ++#define UART2_IOBASE 0x10032000 /* 4KB, UART2 Controller */ ++#define UART3_IOBASE 0x10033000 /* 4KB, UART3 Controller */ ++#define UART4_IOBASE 0x10034000 /* 4KB, UART4 Controller */ ++#define UART5_IOBASE 0x10035000 /* 4KB, UART4 Controller */ ++#define SCC_IOBASE 0x10040000 /* 4KB, Smart Card Controller */ ++#define SSI0_IOBASE 0x10043000 /* 4KB, Synchronous Serial Interface */ ++#define SSI1_IOBASE 0x10044000 /* 4KB, Synchronous Serial Interface */ ++#define I2C0_IOBASE 0x10050000 /* 4KB, I2C 0 Bus Interface */ ++#define I2C1_IOBASE 0x10051000 /* 4KB, I2C 1 Bus Interface */ ++#define I2C2_IOBASE 0x10052000 /* 4KB, I2C 2 Bus Interface */ ++#define I2C3_IOBASE 0x10053000 /* 4KB, I2C 3 Bus Interface */ ++#define I2C4_IOBASE 0x10054000 /* 4KB, I2C 4 Bus Interface */ ++#define I2C5_IOBASE 0x10055000 /* 4KB, I2C 5 Bus Interface */ ++ ++ ++ ++/* TODO: Others To Be add */ ++/* NAND CHIP Base Address */ ++#define NEMC_CS1_IOBASE 0X1b000000 ++#define NEMC_CS2_IOBASE 0X1a000000 ++#define NEMC_CS3_IOBASE 0X19000000 ++#define NEMC_CS4_IOBASE 0X18000000 ++#define NEMC_CS5_IOBASE 0X17000000 ++#define NEMC_CS6_IOBASE 0X16000000 ++ ++ ++#define OST_IOBASE 0x12000000 ++#define TCU_IOBASE 0x10002000 ++ ++#define DDRC_BASE 0xb34f0000 ++ ++#endif +diff --git a/arch/mips/xburst2/soc-m300/include/soc/cache.h b/arch/mips/xburst2/soc-m300/include/soc/cache.h +new file mode 100644 +index 000000000..ea3b935a8 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/include/soc/cache.h +@@ -0,0 +1,28 @@ ++#ifndef __CHIP_CACHE_H__ ++#define __CHIP_CACHE_H__ ++#include ++#include ++ ++#define Index_Prefetch_I 0x1c ++ ++ ++#define cache_prefetch(label,size) \ ++do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&label + size) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set push \n\t" \ ++ ".set mips32 \n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set pop \n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++} \ ++while(0) ++ ++#endif /* __CHIP_CACHE_H__ */ +diff --git a/arch/mips/xburst2/soc-m300/include/soc/cpm.h b/arch/mips/xburst2/soc-m300/include/soc/cpm.h +new file mode 100644 +index 000000000..d0fa6d8f0 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/include/soc/cpm.h +@@ -0,0 +1,136 @@ ++/* ++ * SOC CPM register definition. ++ * ++ * CPM (Clock reset and Power control Management) ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __SOC_CPM_H__ ++#define __SOC_CPM_H__ ++ ++#include ++ ++#define CPM_CPCCR (0x00) ++#define CPM_CPCSR (0xD4) ++ ++#define CPM_DDRCDR (0x2c) ++#define CPM_MACCDR (0x54) ++#define CPM_MACTXCDR (0x58) ++#define CPM_MACTXCDR1 (0xdc) ++#define CPM_MACPTP (0x4c) ++#define CPM_I2S0CDR (0x60) ++#define CPM_I2S1CDR (0x7c) ++#define CPM_I2S2CDR (0x84) ++#define CPM_I2S3CDR (0x8c) ++#define CPM_I2S0CDR1 (0x70) ++#define CPM_I2S1CDR1 (0x80) ++#define CPM_I2S2CDR1 (0x88) ++#define CPM_I2S3CDR1 (0xa0) ++#define CPM_AUDIOCR (0xac) ++#define CPM_LPCDR (0x64) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0xa4) ++#define CPM_MSC2CDR (0xa8) ++#define CPM_SFCCDR (0x74) ++#define CPM_SSICDR (0x5c) ++#define CPM_CIMCDR (0x78) ++#define CPM_PWMCDR (0x6c) ++#define CPM_ISPCDR (0x30) ++#define CPM_RSACDR (0x50) ++ ++#define CPM_INTR (0xB0) ++#define CPM_INTRE (0xB4) ++#define CPM_SFTINT (0xBC) ++#define CPM_DRCG (0xD0) ++#define CPM_CPPSR (0x34) ++#define CPM_CPSPPR (0x38) ++#define CPM_USBPCR (0x3C) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++ ++#define CPM_CPPCR (0x0C) ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++#define CPM_CPEPCR (0x18) ++ ++#define CPM_LCR (0x04) ++#define CPM_PSWC0ST (0x90) ++#define CPM_PSWC1ST (0x94) ++#define CPM_PSWC2ST (0x98) ++#define CPM_PSWC3ST (0x9C) ++#define CPM_CLKGR (0x20) ++#define CPM_CLKGR1 (0x28) ++#define CPM_MESTSEL (0xEC) ++#define CPM_SRBC (0xC4) ++#define CPM_EXCLK_DS (0xE0) ++#define CPM_MPDCR (0xF8) ++#define CPM_MPDCR1 (0xFC) ++#define CPM_SLBC (0xC8) ++#define CPM_SLPC (0xCC) ++#define CPM_OPCR (0x24) ++ ++#define CPM_RSR (0x08) ++ ++#ifndef BIT ++#define BIT(nr) (1UL << nr) ++#endif ++ ++/*USB Parameter Control Register*/ ++#define USBPCR_USB_MODE BIT(31) ++#define USBPCR_AVLD_REG BIT(30) ++#define USBPCR_IDPULLUP_MASK_BIT 28 ++#define USBPCR_IDPULLUP_MASK (0x3 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS_SUSPEND (0x1 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_INCR_MASK BIT(27) ++#define USBPCR_POR_BIT 22 ++#define USBPCR_POR BIT(USBPCR_POR_BIT) ++ ++/*USB Reset Detect Timer Register*/ ++#define USBRDT_RESUME_INTEEN BIT(31) /*RW*/ ++#define USBRDT_RESUME_INTERCLR BIT(30) /*W0*/ ++#define USBRDT_RESUME_SPEED_BIT 28 /*RW*/ ++#define USBRDT_RESUME_SPEED_MSK (0x3 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_HIGH (0x0 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_FULL (0x1 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_LOW (0x2 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_STATUS 27 /*RO*/ ++#define USBRDT_HB_MASK BIT(26) ++#define USBRDT_VBFIL_LD_EN BIT(25) ++#define USBRDT_IDDIG_EN 24 ++#define USBRDT_IDDIG_REG 23 ++#define USBRDT_USBRDT_MSK (0x7fffff) ++#define USBRDT_USBRDT(x) ((x) & USBRDT_USBRDT_MSK) ++ ++/*USB VBUS Jitter Filter Register*/ ++#define USBVBFIL_USBVBFIL(x) ((x) & 0xffff) ++#define USBVBFIL_IDDIGFIL(x) ((x) & (0xffff << 16)) ++ ++/*USB Parameter Control Register1*/ ++#define USBPCR1_BVLD_REG BIT(31) ++#define USBPCR1_DPPULLDOWN BIT(29) ++#define USBPCR1_DMPULLDOWN BIT(28) ++#define USBPCR1_PORT_RST BIT(21) ++ ++/*Oscillator and Power Control Register*/ ++#define OPCR_USB_SPENDN BIT(7) ++ ++ ++#define LCR_LPM_MASK (0x3) ++#define LCR_LPM_SLEEP (0x1) ++ ++#define OPCR_ERCS (0x1<<2) ++#define OPCR_PD (0x1<<3) ++#define OPCR_IDLE (0x1<<31) ++ ++ ++#define cpm_inl(off) inl(CPM_IOBASE + (off)) ++#define cpm_outl(val,off) outl(val,CPM_IOBASE + (off)) ++#define cpm_clear_bit(val,off) do{cpm_outl((cpm_inl(off) & ~(1<<(val))),off);}while(0) ++#define cpm_set_bit(val,off) do{cpm_outl((cpm_inl(off) | (1< ++ ++/* ++ * DDR Controller Registers ++ **/ ++#define DDR_MEM_PHY_BASE 0x20000000 ++ ++#define DDRC_AHB2_OFFSET 0xb34f0000 ++#define DDRC_APB_OFFSET 0xb3012000 ++#define DDR_PHY_OFFSET (-0x4e0000 + 0x1000) ++ ++#define DDRC_STATUS 0x0 ++#define DDRC_CFG 0x8 ++#define DDRC_CTRL 0x10 ++#define DDRC_LMR 0x18 ++#define DDRC_DLP 0x20 ++#define DDRC_AUTOSR_EN 0x28 ++#define DDRC_AUTOSR_CNT 0x30 ++#define DDRC_REFCNT 0x38 ++#define DDRC_DBGINFO 0xE8 ++#define DDRC_TIMING(n) (0x40 + 8 * (n - 1)) ++#define DDRC_MMAP0 0x78 ++#define DDRC_MMAP1 0x80 ++#define DDRC_HREGPRO 0xd8 ++#define DDRC_DWCFG (DDRC_APB_OFFSET + 0x00) ++#define DDRC_DWSTATUS (DDRC_APB_OFFSET + 0x04) ++#define DDRC_REMAP(n) (DDRC_APB_OFFSET + 0x08 + 4 * (n - 1)) ++#define DDRC_CGUC0 (DDRC_APB_OFFSET + 0x64) ++#define DDRC_CGUC1 (DDRC_APB_OFFSET + 0x68) ++#define DDRC_PREGPRO (DDRC_APB_OFFSET + 0x6c) ++ ++/* ++ * DDR Innophy registers ++ * */ ++#define DDRP_INNOPHY_PHY_RST (DDR_PHY_OFFSET + 0x000) ++#define DDRP_INNOPHY_MEM_CFG (DDR_PHY_OFFSET + 0x004) ++#define DDRP_INNOPHY_DQ_WIDTH (DDR_PHY_OFFSET + 0x07c) ++#define DDRP_INNOPHY_CL (DDR_PHY_OFFSET + 0x014) ++#define DDRP_INNOPHY_CWL (DDR_PHY_OFFSET + 0x01c) ++#define DDRP_INNOPHY_AL (DDR_PHY_OFFSET + 0x018) ++#define DDRP_INNOPHY_PLL_FBDIV (DDR_PHY_OFFSET + 0x080) ++#define DDRP_INNOPHY_PLL_CTRL (DDR_PHY_OFFSET + 0x084) ++#define DDRP_INNOPHY_PLL_PDIV (DDR_PHY_OFFSET + 0x088) ++#define DDRP_INNOPHY_PLL_LOCK (DDR_PHY_OFFSET + 0xc8) ++#define DDRP_INNOPHY_TRAINING_CTRL (DDR_PHY_OFFSET + 0x008) ++#define DDRP_INNOPHY_CALIB_DONE (DDR_PHY_OFFSET + 0xcc) ++#define DDRP_INNOPHY_CALIB_DELAY_AL (DDR_PHY_OFFSET + 0x190) ++#define DDRP_INNOPHY_CALIB_DELAY_AH (DDR_PHY_OFFSET + 0x194) ++#define DDRP_INNOPHY_CALIB_BYPASS_AL (DDR_PHY_OFFSET + 0x118) ++#define DDRP_INNOPHY_CALIB_BYPASS_AH (DDR_PHY_OFFSET + 0x158) ++#define DDRP_INNOPHY_WL_MODE1 (DDR_PHY_OFFSET + 0x00c) ++#define DDRP_INNOPHY_WL_MODE2 (DDR_PHY_OFFSET + 0x010) ++#define DDRP_INNOPHY_WL_DONE (DDR_PHY_OFFSET + 0x0c0) ++#define DDRP_INNOPHY_INIT_COMP (DDR_PHY_OFFSET + 0x0d0) ++ ++ ++/* ++ * DDRC REGISTER BITS DEFINE ++ * */ ++ ++/* DDRC Status Register */ ++#define DDRC_DSTATUS_MISS (1 << 6) ++#define DDRC_ST_DPDN (1 << 5) /* 0 DDR memory is NOT in deep-power-down state ++ 1 DDR memory is in deep-power-down state */ ++#define DDRC_ST_PDN (1 << 4) /* 0 DDR memory is NOT in power-down state ++ 1 DDR memory is in power-down state */ ++#define DDRC_ST_AREF (1 << 3) /* 0 DDR memory is NOT in auto-refresh state ++ 1 DDR memory is in auto-refresh state */ ++#define DDRC_ST_SREF (1 << 2) /* 0 DDR memory is NOT in self-refresh state ++ 1 DDR memory is in self-refresh state */ ++#define DDRC_ST_CKE1 (1 << 1) /* 0 CKE1 Pin is low ++ 1 CKE1 Pin is high */ ++#define DDRC_ST_CKE0 (1 << 0) /* 0 CKE0 Pin is low ++ 1 CKE0 Pin is high */ ++ ++/* DDRC Configure Register */ ++#define DDRC_CFG_ROW1_BIT 29 /* Row Address width. */ ++#define DDRC_CFG_ROW1_MASK (0x7 << DDRC_CFG_ROW1_BIT) ++#define DDRC_CFG_COL1_BIT 26 /* Row Address width. */ ++#define DDRC_CFG_COL1_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA1 25 /* Bank Address width of DDR memory */ ++#define DDRC_CFG_IMBA (1 << 16) ++#define DDRC_CFG_ROW0_BIT 13 /* Row Address width. */ ++#define DDRC_CFG_ROW0_MASK (0x7 << DDRC_CFG_ROW0_BIT) ++#define DDRC_CFG_COL0_BIT 10 /* Row Address width. */ ++#define DDRC_CFG_COL0_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA0 9 /* Bank Address width of DDR memory */ ++ ++#define DDRC_CFG_TYPE_BIT 3 ++#define DDRC_CFG_TYPE_MASK (0x7 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR1 (2 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_MDDR (3 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR2 (4 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR2 (5 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR3 (6 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR3 (7 << DDRC_CFG_TYPE_BIT) ++ ++#define DDRC_CFG_ODTEN (1 << 2) /* ODT EN */ ++#define DDRC_CFG_CS1EN (1 << 1) /* DDR Chip-Select-1 Enable */ ++#define DDRC_CFG_CS0EN (1 << 0) /* DDR Chip-Select-0 Enable */ ++ ++/* DDRC Control Register */ ++#define DDRC_CTRL_DFI_RST (1 << 23) ++#define DDRC_CTRL_DLL_RST (1 << 22) ++#define DDRC_CTRL_CTL_RST (1 << 21) ++#define DDRC_CTRL_CFG_RST (1 << 20) ++#define DDRC_CTRL_ACTPD (1 << 15) /* 0 Precharge all banks before entering power-down ++ 1 Do not precharge banks before entering power-down */ ++#define DDRC_CTRL_PDT_BIT 12 /* Power-Down Timer */ ++#define DDRC_CTRL_PDT_MASK (0x7 << DDRC_CTRL_PDT_BIT) ++#define DDRC_CTRL_PDT_DIS (0 << DDRC_CTRL_PDT_BIT) /* power-down disabled */ ++#define DDRC_CTRL_PDT_8 (1 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 8 tCK idle */ ++#define DDRC_CTRL_PDT_16 (2 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 16 tCK idle */ ++#define DDRC_CTRL_PDT_32 (3 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 32 tCK idle */ ++#define DDRC_CTRL_PDT_64 (4 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 64 tCK idle */ ++#define DDRC_CTRL_PDT_128 (5 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 128 tCK idle */ ++ ++#define DDRC_CTRL_PD_CCE (1 << 7) /* Power down clk freq change enable */ ++#define DDRC_CTRL_DPD (1 << 6) /* 1 Drive external MDDR device entering Deep-Power-Down mode */ ++#define DDRC_CTRL_SR (1 << 5) /* 1 Drive external DDR device entering self-refresh mode ++ 0 Drive external DDR device exiting self-refresh mode */ ++#define DDRC_CTRL_SR_CCE (1 << 4) /* Self refresh clk stop request enable */ ++#define DDRC_CTRL_CKE (1 << 1) /* 0 Not set CKE Pin High, 1 Set CKE Pin HIGH */ ++#define DDRC_CTRL_RESET (1 << 0) /* 0 End resetting ddrc_controller, 1 Resetting ddrc_controller */ ++ ++/* DDRC DFI low power handshake control register */ ++#define DDRC_DDLP_TCTLUDP_BIT 24 ++#define DDRC_DDLP_TCTLUDP_FF (0xff << DDRC_DDLP_TCTLUDP_BIT) ++ ++/* DDRC Load-Mode-Register */ ++#define DDRC_LMR_DDR_ADDR_BIT 12 /* When performing a DDR command, DDRC_ADDR[13:0] ++ corresponding to external DDR address Pin A[13:0] */ ++#define DDRC_LMR_DDR_ADDR_MASK (0xfffff << DDRC_LMR_DDR_ADDR_BIT) ++ ++#define DDRC_LMR_MA_BIT 16 /* FOR LPDDR2, MA[9:0] */ ++#define DDRC_LMR_OP_BIT 24 /* FOR LPDDR2, OP[9:0] */ ++ ++#define DDRC_LMR_BA_BIT 9 /* When performing a DDR command, BA[2:0] ++ corresponding to external DDR address Pin BA[2:0]. */ ++#define DDRC_LMR_BA_MASK (0x7 << DDRC_LMR_BA_BIT) ++#define DDRC_LMR_CMD_BIT 6 ++#define DDRC_LMR_CMD_MASK (0x7 << DDRC_LMR_CMD_BIT) ++#define DDRC_LMR_CMD_PREC (0 << DDRC_LMR_CMD_BIT)/* Precharge one bank/All banks */ ++#define DDRC_LMR_CMD_AUREF (1 << DDRC_LMR_CMD_BIT)/* Auto-Refresh */ ++#define DDRC_LMR_CMD_LMR (2 << DDRC_LMR_CMD_BIT)/* Load Mode Register */ ++#define DDRC_LMR_CMD_ZQCL_CS0 (3 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCL_CS1 (4 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS1 */ ++#define DDRC_LMR_CMD_ZQCS_CS0 (5 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCS_CS1 (6 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS1 */ ++ ++#define DDRC_LMR_TMRD_BIT 1 ++#define DDRC_LMR_TMRD_MASK (0x1f << DDRC_LMR_TMRD_BIT) ++#define DDRC_LMR_START (1 << 0) /* 0 No command is performed ++ 1 On the posedge of START, perform a command ++ defined by CMD field */ ++ ++/* DDRC Auto-Refresh Counter */ ++#define DDRC_REFCNT_REF_EN (1 << 0) /* Enable Refresh Counter */ ++#define DDRC_REFCNT_CLK_DIV_BIT 1 /* Clock Divider for auto-refresh counter. */ ++#define DDRC_REFCNT_CLK_DIV_MASK (0x7 << DDRC_REFCNT_CLKDIV_BIT) ++ ++#define DDRC_REFCNT_PREREF_CNT_BIT 4 ++#define DDRC_REFCNT_PREREF_CNT_MASK (0xf << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT(val) (val << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT_DEFAULT DDRC_REFCNT_PREREF_CNT(8) ++ ++#define DDRC_REFCNT_CNT_BIT 8 /* 8-bit counter */ ++#define DDRC_REFCNT_CNT_MASK (0xff << DDRC_REFCNT_CNT_BIT) ++ ++#define DDRC_REFCNT_CON_BIT 16 /* Constant value used to compare with CNT value. */ ++#define DDRC_REFCNT_CON_MASK (0xff << DDRC_REFCNT_CON_BIT) ++ ++#define DDRC_REFCNT_TRFC_BIT 24 ++#define DDRC_REFCNT_TRFC_MASK (0x3f << DDRC_REFCNT_TRFC_BIT) ++ ++#define DDRC_REFCNT_PREREF_EN_BIT 30 ++#define DDRC_REFCNT_PREREF_EN (1 << DDRC_REFCNT_PREREF_EN_BIT) ++ ++#define DDRC_REFCNT_PBREF_EN_BIT 31 ++#define DDRC_REFCNT_PBREF_EN (1 << DDRC_REFCNT_PBREF_EN_BIT) ++ ++/* DDRC Memory Map Config Register */ ++#define DDRC_MMAP_BASE_BIT 8 /* base address */ ++#define DDRC_MMAP_BASE_MASK (0xff << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP_MASK_BIT 0 /* address mask */ ++#define DDRC_MMAP_MASK_MASK (0xff << DDRC_MMAP_MASK_BIT) ++ ++#define DDRC_MMAP0_BASE (0x20 << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP1_BASE_64M (0x24 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_128M (0x28 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_256M (0x30 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++ ++#define DDRC_MMAP_MASK_64_64 (0xfc << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_128_128 (0xf8 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_256_256 (0xf0 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++ ++/* DDR device data width configure register */ ++#define DDRC_DWCFG_DFI_INIT_START (1 << 3) ++ ++/* DDR device status register */ ++#define DDRC_DWSTATUS_DFI_INIT_COMP (1 << 0) ++ ++/* DDRC AHB Bus Register Protection Register */ ++#define DDRC_HREGPRO_HPRO_EN (1 << 0) ++ ++/* DDRC APB Bus Register Protection Register */ ++#define DDRC_PREGPRO_PPRO_EN (1 << 0) ++ ++ ++/* DDRC clock gate unit configure 0 */ ++#define DDRC_CGU_PORT7 (1 << 28) ++#define DDRC_CGU_PORT6 (1 << 24) ++#define DDRC_CGU_PORT5 (1 << 20) ++#define DDRC_CGU_PORT4 (1 << 16) ++#define DDRC_CGU_PORT3 (1 << 12) ++#define DDRC_CGU_PORT2 (1 << 8) ++#define DDRC_CGU_PORT1 (1 << 4) ++#define DDRC_CGU_PORT0 (1 << 0) ++ ++/* DDRC clock gate unit configure 1 */ ++#define DDRC_CGU_BWM (1 << 8) ++#define DDRC_CGU_PCTRL (1 << 4) ++#define DDRC_CGU_SCH (1 << 1) ++#define DDRC_CGU_PA (1 << 0) ++ ++ ++ ++/* ++ * DDR INNOPHY REGISTER BITS DEFINE ++ * */ ++ ++/* DDRP DQ Width Register */ ++#define DDRP_DQ_WIDTH_DQ_H (1 << 1) ++#define DDRP_DQ_WIDTH_DQ_L (1 << 0) ++ ++/* DDRP Pll Ctrl Register */ ++#define DDRP_PLL_CTRL_PLLPDEN (1 << 1) ++ ++/* DDRP Training Ctrl Register */ ++#define DDRP_TRAINING_CTRL_WL_BP (1 << 3) ++#define DDRP_TRAINING_CTRL_WL_START (1 << 2) ++#define DDRP_TRAINING_CTRL_DSCSE_BP (1 << 1) ++#define DDRP_TRAINING_CTRL_DSACE_START (1 << 0) ++ ++/* DDRP Training Done Register */ ++#define DDRP_CALIB_DONE_HDQCFB (1 << 3) ++#define DDRP_CALIB_DONE_LDQCFB (1 << 2) ++#define DDRP_CALIB_DONE_HDQCFA (1 << 1) ++#define DDRP_CALIB_DONE_LDQCFA (1 << 0) ++#define DDRP_CALIB_DONE_HWRLFB (1 << 3) ++#define DDRP_CALIB_DONE_LWRLFB (1 << 2) ++#define DDRP_CALIB_DONE_HWRLFA (1 << 1) ++#define DDRP_CALIB_DONE_LWRLFA (1 << 0) ++ ++/* DDRP CALIB BP Register */ ++#define DDRP_CALIB_BP_CYCLESELBH_BIT 4 ++#define DDRP_CALIB_BP_OPHCSELBH_BIT 3 ++#define DDRP_CALIB_BP_DLLSELBH_BIT 0 ++ ++/* DDRP Init Complete Register */ ++#define DDRP_INIT_COMP (1 << 0) ++ ++#define DDRP_PLL_LOCK (1 << 3) ++ ++#define REG32(addr) *(volatile unsigned int *)(addr) ++ ++#define ddr_writel(value, reg) (REG32(DDRC_BASE + reg) = (value)) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++#endif /* __DDR_H__ */ +diff --git a/arch/mips/xburst2/soc-m300/include/soc/extal.h b/arch/mips/xburst2/soc-m300/include/soc/extal.h +new file mode 100644 +index 000000000..398b5912f +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/include/soc/extal.h +@@ -0,0 +1,12 @@ ++ ++#ifndef __JZSOC_EXTAL_H__ ++#define __JZSOC_EXTAL_H__ ++ ++#define JZ_EXTAL_RTC 32768 /* RTC extal freq: 32.768 KHz */ ++#define JZ_EXTAL (CONFIG_EXTAL_CLOCK * 1000000) ++ ++#ifdef CONFIG_PALLADIUM_PLATFORM ++#define PALLADIUM_CLK_INPURT (500*1000000) ++#endif ++ ++#endif +diff --git a/arch/mips/xburst2/soc-m300/include/soc/rtc.h b/arch/mips/xburst2/soc-m300/include/soc/rtc.h +new file mode 100644 +index 000000000..871add1fc +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/include/soc/rtc.h +@@ -0,0 +1,96 @@ ++#ifndef __RTC_H__ ++#define __RTC_H__ ++ ++/* ++ * RTC registers offset address definition ++ */ ++#define RTC_RTCCR (0x00) /* rw, 32, 0x00000081 */ ++#define RTC_RTCSR (0x04) /* rw, 32, 0x???????? */ ++#define RTC_RTCSAR (0x08) /* rw, 32, 0x???????? */ ++#define RTC_RTCGR (0x0c) /* rw, 32, 0x0??????? */ ++ ++#define RTC_HCR (0x20) /* rw, 32, 0x00000000 */ ++#define RTC_HWFCR (0x24) /* rw, 32, 0x0000???0 */ ++#define RTC_HRCR (0x28) /* rw, 32, 0x00000??0 */ ++#define RTC_HWCR (0x2c) /* rw, 32, 0x00000008 */ ++#define RTC_HWRSR (0x30) /* rw, 32, 0x00000000 */ ++#define RTC_HSPR (0x34) /* rw, 32, 0x???????? */ ++#define RTC_WENR (0x3c) /* rw, 32, 0x00000000 */ ++#define RTC_WKUPPINCR (0x48) /* rw, 32, 0x00050064*/ ++ ++/* ++ * RTC registers common define ++ */ ++ ++/* RTC control register(RTCCR) */ ++#define RTCCR_WRDY BIT(7) ++#define RTCCR_1HZ BIT(6) ++#define RTCCR_1HZIE BIT(5) ++#define RTCCR_AF BIT(4) ++#define RTCCR_AIE BIT(3) ++#define RTCCR_AE BIT(2) ++#define RTCCR_SELEXC BIT(1) ++#define RTCCR_RTCE BIT(0) ++ ++ ++/* Generate the bit field mask from msb to lsb */ ++#define BITS_H2L(msb, lsb) ((0xFFFFFFFF >> (32-((msb)-(lsb)+1))) << (lsb)) ++ ++/* RTC regulator register(RTCGR) */ ++#define RTCGR_LOCK BIT(31) ++#define RTCGR_ADJC_LSB 16 ++#define RTCGR_ADJC_MASK BITS_H2L(25, RTCGR_ADJC_LSB) ++#define RTCGR_NC1HZ_LSB 0 ++#define RTCGR_NC1HZ_MASK BITS_H2L(15, RTCGR_NC1HZ_LSB) ++ ++/* Hibernate control register(HCR) */ ++#define HCR_PD BIT(0) ++ ++/* Hibernate wakeup filter counter register(HWFCR) */ ++#define HWFCR_LSB 5 ++#define HWFCR_MASK BITS_H2L(15, HWFCR_LSB) ++#define HWFCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000+0xf) > HWFCR_MASK ? HWFCR_MASK : ((ms)*(clk)/1000+0xf) & HWFCR_MASK) ++ ++/* Hibernate reset counter register(HRCR) */ ++#define HRCR_LSB 11 ++#define HRCR_MASK BITS_H2L(14, HRCR_LSB) ++#define HRCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000 + 0x3ff - 0x800) > HRCR_MASK ? HRCR_MASK : \ ++ ((ms)*(clk)/1000 + 0x3ff - 0x800) & HRCR_MASK) ++ ++ ++/* Hibernate wakeup control register(HWCR) */ ++/* Power detect default value; this value means enable */ ++#define EPDET_LSB 3 ++#define EPDET_DEFAULT (0x5aa5a5a << EPDET_LSB) ++#define EPDET_ENABLE (0x5aa5a5a << EPDET_LSB) ++#define EPDET_DISABLE (0x1a55a5a5 << EPDET_LSB) ++#define HWCR_EALM BIT(0) ++ ++ ++/* Hibernate wakeup status register(HWRSR) */ ++#define HWRSR_APD BIT(8) ++#define HWRSR_HR BIT(5) ++#define HWRSR_PPR BIT(4) ++#define HWRSR_PIN BIT(1) ++#define HWRSR_ALM BIT(0) ++ ++/* write enable pattern register(WENR) */ ++#define WENR_WEN BIT(31) ++#define WENR_WENPAT_LSB 0 ++#define WENR_WENPAT_MASK BITS_H2L(15, WENR_WENPAT_LSB) ++#define WENR_WENPAT_WRITABLE (0xa55a) ++ ++/* Hibernate scratch pattern register(HSPR) */ ++#define HSPR_RTCV 0x52544356 /* The value is 'RTCV', means rtc is valid */ ++ ++/*WKUP_PIN_RST control register (WKUPPINCR)*/ ++#define WKUPPINCR_BIAS_CTRL (0x1 << 16) /* fix value*/ ++#define WKUPPINCR_OSC_EN BIT(18) ++#define WKUPPINCR_P_JUD_LEN_LSB 4 ++#define WKUPPINCR_P_JUD_LEN_MASK BITS_H2L(7, WKUPPINCR_P_JUD_LEN_LSB) ++#define WKUPPINCR_P_JUD_LEN(s) ((s) << WKUPPINCR_P_JUD_LEN_LSB) > WKUPPINCR_P_JUD_LEN_MASK ? \ ++ WKUPPINCR_P_JUD_LEN_MASK : (s) << WKUPPINCR_P_JUD_LEN_LSB ++#define WKUPPINCR_P_JUD_EN (0x4) ++/* The divider is decided by the RTC clock frequency. */ ++#define RTC_FREQ_DIVIDER (32768 - 1) ++#endif /* __RTC_H__ */ +diff --git a/arch/mips/xburst2/soc-m300/include/soc/sfc.h b/arch/mips/xburst2/soc-m300/include/soc/sfc.h +new file mode 100644 +index 000000000..b1684bec9 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/include/soc/sfc.h +@@ -0,0 +1,211 @@ ++#ifndef __SFC_REGISTER_H ++#define __SFC_REGISTER_H ++ ++/* SFC register */ ++ ++#define SFC_GLB0 (0x0000) ++#define SFC_DEV_CONF (0x0004) ++#define SFC_DEV_STA_EXP (0x0008) ++#define SFC_DEV0_STA_RT (0x000c) ++#define SFC_DEV_STA_MSK (0x0010) ++#define SFC_TRAN_CONF0(n) (0x0014 + (n * 4)) ++#define SFC_TRAN_LEN (0x002c) ++#define SFC_DEV_ADDR(n) (0x0030 + (n * 4)) ++#define SFC_DEV_ADDR_PLUS(n) (0x0048 + (n * 4)) ++#define SFC_MEM_ADDR (0x0060) ++#define SFC_TRIG (0x0064) ++#define SFC_SR (0x0068) ++#define SFC_SCR (0x006c) ++#define SFC_INTC (0x0070) ++#define SFC_FSM (0x0074) ++#define SFC_CGE (0x0078) ++#define SFC_CMD_IDX (0x007c) ++#define SFC_COL_ADDR (0x0080) ++#define SFC_ROW_ADDR (0x0084) ++#define SFC_STA_ADDR0 (0x0088) ++#define SFC_STA_ADDR1 (0x008c) ++#define SFC_DES_ADDR (0x0090) ++#define SFC_GLB1 (0x0094) ++#define SFC_DEV1_STA_RT (0x0098) ++#define SFC_TRAN_CONF1(n) (0x009c + (n * 4)) ++#define SFC_CDT (0x0800) //0x800 ~ 0xbff ++#define SFC_RM_DR (0x1000) ++ ++/* For SFC_GLB0 */ ++#define GLB0_POLL_TIME_OFFSET (16) ++#define GLB0_POLL_TIME_MSK (0xffff << GLB0_POLL_TIME_OFFSET) ++#define GLB0_DES_EN (1 << 15) ++#define GLB0_CDT_EN (1 << 14) ++#define GLB0_TRAN_DIR (1 << 13) ++#define GLB0_TRAN_DIR_WRITE (1) ++#define GLB0_TRAN_DIR_READ (0) ++#define GLB0_THRESHOLD_OFFSET (7) ++#define GLB0_THRESHOLD_MSK (0x3f << GLB0_THRESHOLD_OFFSET) ++#define GLB0_OP_MODE (1 << 6) ++#define GLB0_OP_OFFSET (6) ++#define SLAVE_MODE (0x0) ++#define DMA_MODE (0x1) ++#define GLB0_PHASE_NUM_OFFSET (3) ++#define GLB0_PHASE_NUM_MSK (0x7 << GLB0_PHASE_NUM_OFFSET) ++#define GLB0_WP_EN (1 << 2) ++#define GLB0_BURST_MD_OFFSET (0) ++#define GLB0_BURST_MD_MSK (0x3 << GLB0_BURST_MD_OFFSET) ++ ++/* For SFC_DEV_CONF */ ++#define DEV_CONF_STA_ENDIAN_OFFSET (31) ++#define STA_ENDIAN_LSB (0) ++#define STA_ENDIAN_MSB (1) ++#define DEV_CONF_SMP_DELAY_OFFSET (16) ++#define DEV_CONF_SMP_DELAY_MSK (0x1f << DEV_CONF_SMP_DELAY_OFFSET) ++#define DEV_CONF_SMP_DELAY_0 (0) ++#define DEV_CONF_SMP_DELAY_45 (1) ++#define DEV_CONF_SMP_DELAY_90 (2) ++#define DEV_CONF_SMP_DELAY_135 (3) ++#define DEV_CONF_SMP_DELAY_180 (4) ++#define DEV_CONF_SMP_DELAY_225 (5) ++#define DEV_CONF_SMP_DELAY_270 (6) ++#define DEV_CONF_SMP_DELAY_315 (7) ++#define DEV_CONF_SMP_DELAY_1 (8) ++#define DEV_CONF_SMP_DELAY_2 (16) ++#define DEV_CONF_CMD_TYPE (0x1 << 15) ++#define DEV_CONF_STA_TYPE_OFFSET (13) ++#define DEV_CONF_STA_TYPE_MSK (0x3 << DEV_CONF_STA_TYPE_OFFSET) ++#define DEV_CONF_THOLD_OFFSET (11) ++#define DEV_CONF_THOLD_MSK (0x3 << DEV_CONF_THOLD_OFFSET) ++#define DEV_CONF_TSETUP_OFFSET (9) ++#define DEV_CONF_TSETUP_MSK (0x3 << DEV_CONF_TSETUP_OFFSET) ++#define DEV_CONF_TSH_OFFSET (5) ++#define DEV_CONF_TSH_MSK (0xf << DEV_CONF_TSH_OFFSET) ++#define DEV_CONF_CPHA (0x1 << 4) ++#define DEV_CONF_CPOL (0x1 << 3) ++#define DEV_CONF_CEDL (0x1 << 2) ++#define DEV_CONF_HOLDDL (0x1 << 1) ++#define DEV_CONF_WPDL (0x1 << 0) ++ ++/* For SFC_TRAN_CONF0 */ ++#define TRAN_CONF0_CLK_MODE (29) ++#define TRAN_CONF0_CLK_MODE_MSK (0x7 << TRAN_CONF0_CLK_MODE) ++#define TRAN_CONF0_CLK_MODE_SSS (0) ++#define TRAN_CONF0_CLK_MODE_SSD (1) ++#define TRAN_CONF0_CLK_MODE_SDS (2) ++#define TRAN_CONF0_CLK_MODE_SDD (3) ++#define TRAN_CONF0_CLK_MODE_DSS (4) ++#define TRAN_CONF0_CLK_MODE_DSD (5) ++#define TRAN_CONF0_CLK_MODE_DDS (6) ++#define TRAN_CONF0_CLK_MODE_DDD (7) ++#define TRAN_CONF0_ADDR_WIDTH_OFFSET (26) ++#define TRAN_CONF0_ADDR_WIDTH_MSK (0x7 << TRAN_CONF0_ADDR_WIDTH_OFFSET) ++#define TRAN_CONF0_POLLEN (1 << 25) ++#define TRAN_CONF0_POLL_OFFSET (25) ++#define TRAN_CONF0_CMDEN (1 << 24) ++#define TRAN_CONF0_FMAT (1 << 23) ++#define TRAN_CONF0_FMAT_OFFSET (23) ++#define TRAN_CONF0_DMYBITS_OFFSET (17) ++#define TRAN_CONF0_DMYBITS_MSK (0x3f << TRAN_CONF0_DMYBITS_OFFSET) ++#define TRAN_CONF0_DATEEN (1 << 16) ++#define TRAN_CONF0_DATEEN_OFFSET (16) ++#define TRAN_CONF0_CMD_OFFSET (0) ++#define TRAN_CONF0_CMD_MSK (0xffff << TRAN_CONF0_CMD_OFFSET) ++ ++/* For SFC_TRAN_CONF1 */ ++#define TRAN_CONF1_DATA_ENDIAN (1 << 18) ++#define TRAN_CONF1_DATA_ENDIAN_OFFSET (18) ++#define TRAN_CONF1_DATA_ENDIAN_LSB (0) ++#define TRAN_CONF1_DATA_ENDIAN_MSB (1) ++#define TRAN_CONF1_WORD_UNIT_OFFSET (16) ++#define TRAN_CONF1_WORD_UNIT_MSK (3 << 16) ++#define TRAN_CONF1_TRAN_MODE_OFFSET (4) ++#define TRAN_CONF1_TRAN_MODE_MSK (0xf << TRAN_CONF1_TRAN_MODE_OFFSET) ++#define TRAN_CONF1_SPI_STANDARD (0x0) ++#define TRAN_CONF1_SPI_DUAL (0x1) ++#define TRAN_CONF1_SPI_QUAD (0x5) ++#define TRAN_CONF1_SPI_IO_QUAD (0x6) ++#define TRAN_CONF1_SPI_OCTAL (0x9) ++#define TRAN_CONF1_SPI_IO_OCTAL (0xa) ++#define TRAN_CONF1_SPI_FULL_OCTAL (0xb) ++ ++ ++/* For SFC_TRIG */ ++#define TRIG_FLUSH (1 << 2) ++#define TRIG_STOP (1 << 1) ++#define TRIG_START (1 << 0) ++ ++/* For SFC_SR */ ++#define SFC_WORKING (1 << 7) ++#define SFC_BUSY (0x3 << 5) ++#define SFC_END (1 << 4) ++#define SFC_TREQ (1 << 3) ++#define SFC_RREQ (1 << 2) ++#define SFC_OVER (1 << 1) ++#define SFC_UNDER (1 << 0) ++ ++/* For SFC_SCR */ ++#define CLR_END (1 << 4) ++#define CLR_TREQ (1 << 3) ++#define CLR_RREQ (1 << 2) ++#define CLR_OVER (1 << 1) ++#define CLR_UNDER (1 << 0) ++ ++//SFC_CMD_IDX ++#define CMD_IDX_MSK (0x3f << 0) ++#define CDT_DATAEN_MSK (0x1 << 31) ++#define CDT_DATAEN_OFF (31) ++#define CDT_DIR_MSK (0x1 << 30) ++#define CDT_DIR_OFF (30) ++ ++/* For SFC_GLB1 */ ++#define GLB1_DQS_EN (1 << 2) ++#define GLB1_CHIP_SEL_OFFSET (0) ++#define GLB1_CHIP_SEL_MSK (0x3 << 0) ++#define GLB1_CHIP_SEL_0 (0) ++#define GLB1_CHIP_SEL_1 (1) ++#define GLB1_CHIP_SEL_01 (2) ++ ++#define N_MAX 6 ++#define MAX_SEGS 128 ++ ++#define CHANNEL_0 0 ++#define CHANNEL_1 1 ++#define CHANNEL_2 2 ++#define CHANNEL_3 3 ++#define CHANNEL_4 4 ++#define CHANNEL_5 5 ++ ++#define ENABLE 1 ++#define DISABLE 0 ++ ++#define COM_CMD 1 // common cmd ++#define POLL_CMD 2 // the cmd will poll the status of flash,ext: read status ++ ++#define DMA_OPS 1 ++#define CPU_OPS 0 ++ ++#define TM_STD_SPI 0 ++#define TM_DI_DO_SPI 1 ++#define TM_DIO_SPI 2 ++#define TM_FULL_DIO_SPI 3 ++#define TM_QI_QO_SPI 5 ++#define TM_QIO_SPI 6 ++#define TM_FULL_QIO_SPI 7 ++#define TM_OCTAL_SPT 9 ++#define TM_OCTAL_IO_SPI 10 ++#define TM_OCTAL_FULL_SPI 11 ++ ++ ++#define DEFAULT_CDT 1 ++#define UPDATE_CDT 2 ++#define DEFAULT_ADDRSIZE 3 ++#define DEFAULT_ADDRMODE 0 ++ ++ ++#define THRESHOLD 32 ++ ++#define SFC_NOR_RATE 110 ++#define DEF_ADDR_LEN 3 ++#define DEF_TCHSH 6 ++#define DEF_TSLCH 6 ++#define DEF_TSHSL_R 20 ++#define DEF_TSHSL_W 50 ++ ++ ++#endif +diff --git a/arch/mips/xburst2/soc-m300/include/soc/tcsm_layout.h b/arch/mips/xburst2/soc-m300/include/soc/tcsm_layout.h +new file mode 100644 +index 000000000..2de46b7bd +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/include/soc/tcsm_layout.h +@@ -0,0 +1,53 @@ ++#ifndef __TCSM_LAYOUT_H__ ++#define __TCSM_LAYOUT_H__ ++ ++/** ++ * |-------------| ++ * | BANK0 | ++ * |-------------| <--- SLEEP_TCSM_BOOTCODE_TEXT ++ * | BOOT CODE | ++ * |-------------| <--- SLEEP_TCSM_RESUMECODE_TEXT ++ * | ... | ++ * | RESUME CODE | ++ * | ... | ++ * |-------------| <--- SLEEP_TCSM_RESUME_DATA ++ * | ... | ++ * | RESUME DATA | ++ * | ... | ++ * |_____________| <--- SLEEP_TCSM_CPU_RESMUE_SP ++ * ++ * ++ * |-------------| ++ * | BANK1 | ++ * |-------------| <--- TO BE DEFINED ++ * | | ++ * | | ++ * | ... | ++ * | VOICE DATA | ++ * | ... | ++ * | | ++ * | | ++ * |_____________| ++ * ++ */ ++ ++#define SLEEP_TCSM_SPACE 0xb3422000 ++#define VOICE_TCSM_DATA_BUF 0xb3423000 ++#define TCSM_BANK_LEN 4096 ++ ++#define SLEEP_TCSM_BOOT_TEXT (SLEEP_TCSM_SPACE) ++#define SLEEP_TCSM_BOOT_LEN 64 ++#define SLEEP_TCSM_BOOT_END (SLEEP_TCSM_BOOT_TEXT + SLEEP_TCSM_BOOT_LEN) ++ ++#define SLEEP_TCSM_RESUME_TEXT (SLEEP_TCSM_BOOT_END) ++#define SLEEP_TCSM_RESUME_LEN 2048 ++#define SLEEP_TCSM_RESUME_END (SLEEP_TCSM_RESUME_TEXT + SLEEP_TCSM_RESUME_LEN) ++ ++#define SLEEP_TCSM_RESUME_DATA (SLEEP_TCSM_RESUME_END) ++ ++#define SLEEP_TCSM_SPACE_END (SLEEP_TCSM_SPACE + TCSM_BANK_LEN) ++ ++#define SLEEP_TCSM_CPU_RESMUE_SP SLEEP_TCSM_SPACE_END - 4 ++ ++ ++#endif /* __TCSM_LAYOUT_H__ */ +diff --git a/arch/mips/xburst2/soc-m300/include/war.h b/arch/mips/xburst2/soc-m300/include/war.h +new file mode 100644 +index 000000000..fd1ef3147 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/include/war.h +@@ -0,0 +1,27 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MACH_INGENIC_WAR_H__ ++#define __ASM_MACH_INGENIC_WAR_H__ ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 1 ++#define MIPS_BRIDGE_SYNC_WAR 1 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif ++ +diff --git a/arch/mips/xburst2/soc-m300/libdmmu.c b/arch/mips/xburst2/soc-m300/libdmmu.c +new file mode 100644 +index 000000000..457799b7c +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/libdmmu.c +@@ -0,0 +1,1087 @@ ++/* ++ * This driver is used by VPU driver. ++ * ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: Yan Zhengting ++ * Modify by: Sun Jiwei ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#define print_dbg(f, arg...) printk(KERN_INFO "dpu: %s, %d: " f "\n", __func__, __LINE__, ## arg) ++ ++#define MAP_COUNT 0x10 ++#define MAP_CONUT_MASK 0xff0 ++ ++#define DMMU_PTE_VLD 0x01 ++#define DMMU_PMD_VLD 0x01 ++ ++#define KSEG0_LOW_LIMIT 0x80000000 ++#define KSEG1_HEIGH_LIMIT 0xC0000000 ++ ++enum mem_break{ ++ MODE1, /* 13 24 57 68 911 1012 ... */ ++ MODE2, /* 13 24 35 46 57 68 79 810 ... */ ++ MODE3 /* 12 34 56 78 ... */ ++}; ++ ++LIST_HEAD(handle_list); ++static unsigned long reserved_pte = 0; ++static unsigned long res_pte_paddr; ++ ++struct pmd_node { ++ unsigned int count; ++ unsigned long index; ++ unsigned long page; ++ struct list_head list; ++}; ++ ++struct map_node { ++ struct device *dev; ++ unsigned long start; ++ unsigned long len; ++ struct list_head list; ++}; ++ ++struct dmmu_handle { ++ pid_t tgid; ++ unsigned long pdg; ++ struct mutex lock; ++ struct list_head list; ++ struct list_head pmd_list; ++ struct list_head map_list; ++ struct list_head dev_notifier_list; ++ ++ struct mm_struct *handle_mm; /* mm struct used to match exit_mmap notify */ ++ ++ struct mmu_notifier mn; ++}; ++ ++ ++/* for test */ ++static struct dmmu_handle *find_handle(void); ++static struct dmmu_handle *create_handle(void); ++static void dmmu_cache_wback(struct dmmu_handle *h); ++static int dmmu_mm_dev_release(struct dmmu_handle *h); ++ ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h = NULL; ++ struct map_node *n = NULL; ++ unsigned long *pgd, *pte_phys, *pte; ++ unsigned long virpage_phy; ++ unsigned long v_end = vaddr+len; ++ int found = 0; ++ int index; ++ ++ h = find_handle(); ++ if(!h){ ++ printk("%s find handle err!\n",__func__); ++ return -1; ++ } ++ if (vaddr & 0xfff) { ++ printk("%s addr align page err!\n",__func__); ++ return -1; ++ } ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if((vaddr >= n->start) && ++ ((vaddr+len) <= (n->start + n->len))) { ++ found = 1; ++ break; ++ } ++ } ++ if(!found) { ++ printk("%s addr err!\n",__func__); ++ return -1; ++ } ++ pgd = (unsigned long *)h->pdg; ++ while(vaddr < v_end) { ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ index = ((vaddr & 0x3ff000) >> 12); ++ virpage_phy = pte[index] & ~DMMU_PTE_VLD; ++ dma_cache_wback((unsigned long)phys_to_virt(virpage_phy),PAGE_SIZE); ++ vaddr+=PAGE_SIZE; ++ } ++ return 0; ++} ++ ++EXPORT_SYMBOL(dmmu_flush_cache); ++static int make_smash_list(struct dmmu_handle *h, unsigned long vaddr, unsigned long (**base)[2], unsigned int *len) ++{ ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *pte, *pte_phys; ++ unsigned int i, index; ++ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start) { ++ list_len = (n->len) >> 12; ++ break; ++ } ++ } ++ ++ if (list_len) { ++ list_smash = kmalloc(list_len * 2 * 4, GFP_KERNEL); ++ if (list_smash) { ++ i = 0; ++ while(i < list_len) { ++ list_smash[i][0] = (unsigned long)(vaddr & 0xfffff000); ++ ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ ++ ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++// printk(">>>>>>virt = 0x%lx, phys = 0x%lx\n", vaddr, ++// *((unsigned long int *) (((unsigned long)pte_phys+index*4) | 0xa0000000))); ++ list_smash[i][1] = pte[index]; ++ ++ vaddr+=0x1000; ++ i++; ++ } ++ } ++ } ++ ++ if (list_smash) { ++ *base = list_smash; ++ *len = list_len; ++ return 0; ++ } else { ++ return -1; ++ } ++} ++EXPORT_SYMBOL(dmmu_dump_map); ++ ++int dmmu_dump_map(unsigned long vaddr) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *tmp; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return -1; ++ /* 检查4kå¯¹é½ */ ++ if (vaddr & 0xfff){ ++ return -1; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ unsigned int i; ++ for (i = 0; i phys: 0x%08lx] uncache: 0x%08lx\n", ++ list_smash[i][0],list_smash[i][1],(unsigned long)tmp); ++ ++ printk("value[0] = 0x%08lx, value[1] = 0x%08lx value[2] = 0x%08lx value[1013] = 0x%08lx\n", ++ tmp[0], tmp[1], tmp[2], tmp[1013]); ++ } ++ } ++ ++ mutex_unlock(&h->lock); ++ kfree((void*)list_smash); ++ ++ return 0; ++} ++ ++ /* 13 24 57 68 911 1012 ... */ ++static int smash_mode1(unsigned long (*base)[2], unsigned int len) ++{ ++ unsigned int i; ++ unsigned long tmp; ++ if (len >= 4) { ++ for (i=0; i= 4) { ++ for (i=0; ipdg; ++ unsigned long *pte; ++ unsigned int i, index; ++ ++ for (i=0; i>22; ++ pte = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++ pte[index] = (*base)[i][1]; ++ vaddr+=0x1000; ++ } ++ return 0; ++} ++ ++static int update_process_pte(unsigned long vaddr, unsigned long (**base)[2], unsigned int len) ++{ ++ unsigned int i; ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ spin_lock(¤t->mm->page_table_lock); ++ for (i=0; imm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) ++ return 0; ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) ++ return 0; ++ pte = pte_offset_kernel(pmdir,vaddr); ++ if (pte_present(*pte)){ ++ pte->pte = (*base)[i][1]; ++ } ++ vaddr += 4096; ++ } ++ spin_unlock(¤t->mm->page_table_lock); ++ return 0; ++} ++ ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ struct vm_area_struct * vma; ++ ++ h = find_handle(); ++ if(!h){ ++ h = create_handle(); ++ } ++ if(!h) ++ return -1; ++ ++ /* 检查4kå¯¹é½ */ ++ if (vaddr & 0xfff){ ++ return -1; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ switch (smash_mode) { ++ case MODE1: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode1(list_smash, list_len); ++ break; ++ case MODE2: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode2(list_smash, list_len); ++ break; ++ case MODE3: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode3(list_smash, list_len); ++ break; ++ default: ++ break; ++ } ++ } ++ update_dmmu_pte(h, vaddr, &list_smash, list_len); ++ update_process_pte(vaddr, &list_smash, list_len); ++ ++ dmmu_cache_wback(h); ++ vma = find_vma(current->mm, vaddr); ++ flush_tlb_range(vma, vaddr, vaddr+(list_len*PAGE_SIZE)); ++ ++ mutex_unlock(&h->lock); ++ kfree(list_smash); ++ ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_memory_smash); ++ ++static struct map_node *check_map(struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start && len == n->len) ++ return n; ++ } ++ return NULL; ++} ++ ++static void handle_add_map(struct device *dev,struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct map_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ if(n == NULL) { ++ printk("malloc map_list node failed !!\n"); ++ return; ++ } ++ n->dev = dev; ++ n->start = vaddr; ++ n->len = len; ++ INIT_LIST_HEAD(&n->list); ++ list_add(&n->list,&h->map_list); ++} ++ ++static unsigned int get_pfn(unsigned int vaddr) ++{ ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ pgdir = pgd_offset(current->mm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) { ++ return 0; ++ } ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) { ++ return 0; ++ } ++ pte = pte_offset_kernel(pmdir,vaddr); ++ if (pte_present(*pte)) { ++ ++ return pte_pfn(*pte) << PAGE_SHIFT; ++ } ++ ++ return 0; ++} ++ ++static unsigned long dmmu_v2pfn(unsigned long vaddr) ++{ ++ if(vaddr < KSEG0_LOW_LIMIT) ++ return get_pfn(vaddr); ++ ++ if(vaddr >= KSEG0_LOW_LIMIT && vaddr < KSEG1_HEIGH_LIMIT) ++ return virt_to_phys((void *)vaddr); ++ ++ panic("dmmu_v2pfn error!"); ++ return 0; ++} ++ ++static unsigned long unmap_node(struct pmd_node *n,unsigned long vaddr,unsigned long end,int check) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ int free = !check || (--n->count == 0); ++ struct page *page = NULL; ++ ++ if(vaddr && end) { ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] & MAP_CONUT_MASK) { ++ pte[index] -= MAP_COUNT; ++ } else { ++ page = pfn_to_page(pte[index] >> PAGE_SHIFT); ++ ++ ClearPageReserved(page); ++ pte[index] = reserved_pte; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ } ++ ++ if(free) { ++ ClearPageReserved(virt_to_page((void *)n->page)); ++ free_page(n->page); ++ list_del(&n->list); ++ kfree(n); ++ } ++ ++ return vaddr; ++} ++ ++static unsigned long map_node(struct pmd_node *n,unsigned int vaddr,unsigned int end) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ struct page * page = NULL; ++ unsigned long pfn = 0; ++ ++ ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] == reserved_pte) { ++ ++ mmap_write_lock(current->mm); ++ ++ pfn = dmmu_v2pfn(vaddr) >> PAGE_SHIFT; ++ page = pfn_to_page(pfn); ++ ++ SetPageReserved(page); ++ ++ pte[index] = (pfn << PAGE_SHIFT) | DMMU_PTE_VLD; ++ ++ mmap_write_unlock(current->mm); ++ } else { ++ pte[index] += MAP_COUNT; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ n->count++; ++ return vaddr; ++} ++ ++static struct pmd_node *find_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ if(n->index == (vaddr & 0xffc00000)) ++ return n; ++ } ++ return NULL; ++} ++ ++static struct pmd_node *add_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ int i; ++ unsigned long *pte; ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ struct pmd_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ INIT_LIST_HEAD(&n->list); ++ n->count = 0; ++ n->index = vaddr & 0xffc00000; ++ n->page = __get_free_page(GFP_KERNEL); ++ SetPageReserved(virt_to_page((void *)n->page)); ++ ++ pte = (unsigned long *)n->page; ++ for(i=0;i<1024;i++) ++ pte[i] = reserved_pte; ++ ++ list_add(&n->list, &h->pmd_list); ++ ++ pgd[vaddr>>22] = dmmu_v2pfn(n->page) | DMMU_PMD_VLD; ++ return n; ++} ++ ++static struct dmmu_handle *find_handle(void) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ ++ ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ if(h->tgid == current->tgid) ++ return h; ++ } ++ return NULL; ++} ++ ++/** ++* @brief unmap node from map list, clear each pmd_node in pmd_list, ++* Not free handle, let dmmu_unmap_all do it. ++* ++* @param h ++* ++* @return ++*/ ++static int dmmu_unmap_node_unlock(struct dmmu_handle *h) ++{ ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++ unsigned long vaddr; ++ int len; ++ unsigned long end; ++ ++ struct pmd_node *node; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ /* find and delete a map node from map_list */ ++ cn = list_entry(pos, struct map_node, list); ++ vaddr = cn->start; ++ len = cn->len; ++ end = vaddr + len; ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(node) ++ vaddr = unmap_node(node,vaddr,end,1); ++ } ++ ++ list_del(&cn->list); ++ kfree(cn); ++ } ++ ++ ++ return 0; ++ ++} ++ ++ ++void dmmu_mm_release(struct mmu_notifier *mn, ++ struct mm_struct *mm) ++{ ++ struct dmmu_handle *h = container_of(mn, struct dmmu_handle, mn); ++ ++ printk("===== dmmu release mm (TODO: not checked) ====h: %p\n", h); ++ ++ if(h->handle_mm != mm) { ++ return; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ dmmu_mm_dev_release(h); ++ ++ dmmu_unmap_node_unlock(h); ++ ++ mutex_unlock(&h->lock); ++} ++ ++static const struct mmu_notifier_ops dmmu_mm_notifier_ops = { ++ .release = dmmu_mm_release, ++}; ++ ++ ++static struct dmmu_handle *create_handle(void) ++{ ++ struct dmmu_handle *h; ++ unsigned int pgd_index; ++ unsigned long *pgd; ++ ++ h = kmalloc(sizeof(struct dmmu_handle),GFP_KERNEL); ++ if(!h) ++ return NULL; ++ ++ h->tgid = current->tgid; ++ h->pdg = __get_free_page(GFP_KERNEL); ++ if(!h->pdg) { ++ pr_err("%s %d, Get free page for PGD error\n", ++ __func__, __LINE__); ++ kfree(h); ++ return NULL; ++ } ++ SetPageReserved(virt_to_page((void *)h->pdg)); ++ ++ pgd = (unsigned long *)h->pdg; ++ ++ for (pgd_index=0; pgd_index < PTRS_PER_PGD; pgd_index++) ++ pgd[pgd_index] = res_pte_paddr; ++ ++ INIT_LIST_HEAD(&h->list); ++ INIT_LIST_HEAD(&h->pmd_list); ++ INIT_LIST_HEAD(&h->map_list); ++ INIT_LIST_HEAD(&h->dev_notifier_list); ++ mutex_init(&h->lock); ++ ++ /* register exit_mmap notify */ ++ h->handle_mm = current->mm; ++ ++ h->mn.ops = &dmmu_mm_notifier_ops; ++ ++ mmu_notifier_register(&h->mn, h->handle_mm); ++ ++ list_add(&h->list, &handle_list); ++ ++ return h; ++} ++ ++static int dmmu_make_present(unsigned long addr,unsigned long end) ++{ ++#if 0 ++ unsigned long i; ++ for(i = addr; i < end; i += 4096) { ++ *(volatile unsigned char *)(i) = 0; ++ } ++ *(volatile unsigned char *)(end - 1) = 0; ++ return 0; ++#else ++ int ret, len, write; ++ struct vm_area_struct * vma; ++ unsigned long vm_page_prot; ++ ++ mmap_write_lock(current->mm); ++ vma = find_vma(current->mm, addr); ++ if (!vma) { ++ printk("dmmu_make_present error. addr=%lx len=%lx\n",addr,end-addr); ++ mmap_write_unlock(current->mm); ++ return -1; ++ } ++ ++ if(vma->vm_flags & VM_PFNMAP) { ++ mmap_write_unlock(current->mm); ++ return 0; ++ } ++ write = (vma->vm_flags & VM_WRITE) != 0; ++ BUG_ON(addr >= end); ++ BUG_ON(end > vma->vm_end); ++ ++ vm_page_prot = pgprot_val(vma->vm_page_prot); ++ vma->vm_page_prot = __pgprot(vm_page_prot | _PAGE_VALID| _PAGE_ACCESSED | _PAGE_PRESENT); ++ ++ len = DIV_ROUND_UP(end, PAGE_SIZE) - addr/PAGE_SIZE; ++ ret = get_user_pages(addr, len, write, NULL, NULL); ++ vma->vm_page_prot = __pgprot(vm_page_prot); ++ if (ret < 0) { ++ printk("dmmu_make_present get_user_pages error(%d). addr=%lx len=%lx\n",0-ret,addr,end-addr); ++ mmap_write_unlock(current->mm); ++ return ret; ++ } ++ ++ mmap_write_unlock(current->mm); ++ return ret == len ? 0 : -1; ++#endif ++} ++ ++static void dmmu_cache_wback(struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ dma_cache_wback(h->pdg,PAGE_SIZE); ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ dma_cache_wback(n->page,PAGE_SIZE); ++ } ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h); ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len) ++{ ++ int end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ printk("(pid %d)dmmu_map %lx %lx================================================\n",h->tgid,vaddr,len); ++#endif ++ if(check_map(h,vaddr,len)) ++ { ++ mutex_unlock(&h->lock); ++ return dmmu_v2pfn(h->pdg); ++ } ++ ++ if(dmmu_make_present(vaddr,vaddr+len)) ++ { ++ mutex_unlock(&h->lock); ++ return 0; ++ } ++ ++ handle_add_map(dev,h,vaddr,len); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(!node) { ++ node = add_node(h,vaddr); ++ } ++ vaddr = map_node(node,vaddr,end); ++ } ++ dmmu_cache_wback(h); ++#ifdef DEBUG ++ dmmu_dump_handle(NULL,NULL,h); ++#endif ++ mutex_unlock(&h->lock); ++ ++ return dmmu_v2pfn(h->pdg); ++} ++EXPORT_SYMBOL(dmmu_map); ++ ++static int dmmu_mm_dev_release(struct dmmu_handle *h) ++{ ++ struct dmmu_mm_notifier *n = NULL; ++ struct list_head *pos, *next; ++ ++ list_for_each_safe(pos, next, &h->dev_notifier_list) { ++ n = list_entry(pos, struct dmmu_mm_notifier, list); ++ if(n && n->ops && n->ops->mm_release) { ++ n->ops->mm_release(n->data); ++ } ++ ++ list_del(&n->list); ++ } ++ ++ ++ return 0; ++} ++ ++ ++int dmmu_register_mm_notifier(struct dmmu_mm_notifier *dmn) ++{ ++ int dev_already_registered = 0; ++ struct dmmu_mm_notifier *n = NULL; ++ struct dmmu_handle *h; ++ struct list_head *pos, *next; ++ ++ h = find_handle(); ++ if(!h) { ++ return -EINVAL; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ list_for_each_safe(pos, next, &h->dev_notifier_list) { ++ n = list_entry(pos, struct dmmu_mm_notifier, list); ++ ++ if(n == dmn) { ++ /* already in dev_notifier_list*/ ++ dev_already_registered = 1; ++ } ++ ++ } ++ ++ if(dev_already_registered) { ++ goto out; ++ } ++ ++ list_add_tail(&dmn->list, &h->dev_notifier_list); ++out: ++ mutex_unlock(&h->lock); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_register_mm_notifier); ++ ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len) ++{ ++ unsigned long end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *n; ++ ++ h = find_handle(); ++ if(!h) { ++ return 0; ++ } ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ printk("dmmu_unmap %lx %x**********************************************\n",vaddr,len); ++#endif ++ n = check_map(h,vaddr,len); ++ if(!n) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ if(n->dev != dev) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ ++ list_del(&n->list); ++ kfree(n); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(node) ++ vaddr = unmap_node(node,vaddr,end,1); ++ } ++ ++ if(list_empty(&h->pmd_list) && list_empty(&h->map_list)) { ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ mutex_unlock(&h->lock); ++ ++ mmu_notifier_unregister(&h->mn, h->handle_mm); ++ ++ kfree(h); ++ return 0; ++ } ++ ++ mutex_unlock(&h->lock); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_unmap); ++ ++int dmmu_free_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++ h = find_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ node = find_node(h,cn->start); ++ if(node) ++ unmap_node(node,cn->start,cn->len,1); ++ list_del(&cn->list); ++ kfree(cn); ++ } ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ node = list_entry(pos, struct pmd_node, list); ++ if(node){ ++ printk("WARN: pmd list should NULL\n"); ++ unmap_node(node,0,0,0); ++ } ++ } ++ ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ ++ mutex_unlock(&h->lock); ++ mmu_notifier_unregister(&h->mn, h->handle_mm); ++ kfree(h); ++ return 0; ++} ++ ++/** ++* @brief release all resources, which should be called by driver close ++* ++* @param dev ++* ++* @return ++*/ ++int dmmu_unmap_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++#ifdef DEBUG ++ printk("dmmu_unmap_all\n"); ++#endif ++ ++ h = find_handle(); ++ if(!h) { ++ printk("dmmu unmap all not find hindle, maybe it has benn freed already, name: %s\n", dev->kobj.name); ++ return 0; ++ } ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ if(dev == cn->dev) { ++ dmmu_unmap(dev,cn->start,cn->len); ++ } ++ } ++ ++ ++ if(list_empty(&h->map_list)) ++ dmmu_free_all(dev); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_unmap_all); ++int __init dmmu_init(void) ++{ ++ unsigned int pte_index; ++ unsigned long res_page_paddr; ++ unsigned long reserved_page; ++ unsigned int *res_pte_vaddr; ++ ++ reserved_page = __get_free_page(GFP_KERNEL); ++ if (!reserved_page) { ++ pr_err("%s %d, Get reserved page error\n", ++ __func__, __LINE__); ++ return ENOMEM; ++ } ++ SetPageReserved(virt_to_page((void *)reserved_page)); ++ reserved_pte = dmmu_v2pfn(reserved_page) | DMMU_PTE_VLD; ++ ++ res_page_paddr = virt_to_phys((void *)reserved_page) | 0xFFF; ++ ++ res_pte_vaddr = (unsigned int *)__get_free_page(GFP_KERNEL); ++ if (!res_pte_vaddr) { ++ pr_err("%s %d, Get free page for PTE error\n", ++ __func__, __LINE__); ++ free_page(reserved_page); ++ return ENOMEM; ++ } ++ SetPageReserved(virt_to_page(res_pte_vaddr)); ++ res_pte_paddr = virt_to_phys((void *)res_pte_vaddr) | DMMU_PTE_VLD; ++ ++ for (pte_index = 0; pte_index < PTRS_PER_PTE; pte_index++) ++ res_pte_vaddr[pte_index] = res_page_paddr; ++ ++ ++ ++ return 0; ++} ++arch_initcall(dmmu_init); ++ ++void dmmu_dump_vaddr(unsigned long vaddr) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ unsigned long *pmd,*pte; ++ h = find_handle(); ++ if(!h) { ++ printk("dmmu_dump_vaddr %08lx error - h not found!\n",vaddr); ++ return; ++ } ++ ++ node = find_node(h,vaddr); ++ if(!node) { ++ printk("dmmu_dump_vaddr %08lx error - node not found!\n",vaddr); ++ return; ++ } ++ ++ pmd = (unsigned long *)h->pdg; ++ pte = (unsigned long *)node->page; ++ ++ printk("pmd base = %p; pte base = %p\n",pmd,pte); ++ printk("pmd = %08lx; pte = %08lx\n",pmd[vaddr>>22],pte[(vaddr&0x3ff000)>>12]); ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ { ++ int i = 0; ++ int vaddr = n->start; ++ struct pmd_node *pn = find_node(h,vaddr); ++ unsigned int *pte = (unsigned int *)pn->page; ++ ++ while(vaddr < (n->start + n->len)) { ++ if(i++%8 == 0) ++ printk("\nvaddr %08x : ",vaddr & 0xfffff000); ++ printk("%08x ",pte[(vaddr & 0x3ff000)>>12]); ++ vaddr += 4096; ++ } ++ printk("\n\n"); ++ } ++ } ++} ++ ++static int dmmu_proc_show(struct seq_file *m, void *v) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ volatile unsigned long flags; ++ local_irq_save(flags); ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ dmmu_dump_handle(m, v, h); ++ } ++ local_irq_restore(flags); ++ return 0; ++} ++ ++static int dmmu_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, dmmu_proc_show, PDE_DATA(inode)); ++} ++ ++static const struct proc_ops dmmus_proc_fops ={ ++ .proc_read = seq_read, ++ .proc_open = dmmu_open, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release, ++}; ++ ++static int __init init_dmmu_proc(void) ++{ ++ struct proc_dir_entry *p; ++ p = jz_proc_mkdir("dmmu"); ++ if (!p) { ++ printk("create_proc_entry for common dmmu failed.\n"); ++ return -ENODEV; ++ } ++ proc_create("dmmus", 0600,p,&dmmus_proc_fops); ++ ++ return 0; ++} ++ ++module_init(init_dmmu_proc); +diff --git a/arch/mips/xburst2/soc-m300/pm.c b/arch/mips/xburst2/soc-m300/pm.c +new file mode 100644 +index 000000000..74e8d94c1 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/pm.c +@@ -0,0 +1,252 @@ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pm.h" ++#include "pm_sleep.h" ++#include "pm_fastboot.h" ++ ++ ++#define SLEEP_LEVEL (*(volatile unsigned int *)0xb0000034 & 0xf) ++#define SLEEP_LEVEL_MAGIC ((*(volatile unsigned int *)0xb0000034 >> 16) & 0xffff) ++#define SLEEP_MAGIC (0x0915) ++ ++ ++#ifdef DEBUG_PM ++static void m300_pm_gate_check(void) ++{ ++ unsigned int gate0 = cpm_inl(CPM_CLKGR); ++ unsigned int gate1 = cpm_inl(CPM_CLKGR1); ++ int i; ++ int x; ++ ++ printk("gate0 = 0x%08x\n", gate0); ++ printk("gate1 = 0x%08x\n", gate1); ++ for (i = 0; i < 32; i++) { ++ x = (gate0 >> i) & 1; ++ if (x == 0) ++ printk("warning : bit[%d] in clk gate0 is enabled\n", i); ++ } ++ for (i = 0; i < 32; i++) { ++ x = (gate1 >> i) & 1; ++ if (x == 0) ++ printk("warning : bit[%d] in clk gate1 is enabled\n", i); ++ } ++ ++} ++#endif ++ ++ ++ ++void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size) ++{ ++ unsigned int instr; ++ int offset; ++ int i; ++#ifdef DEBUG_PM ++ printk("tcsm addr = %p %p size = %d\n",tcsm_addr,f_addr,size); ++#endif ++ for(i = 0;i < size / 4;i++) { ++ instr = f_addr[i]; ++ if((instr >> 26) == 2){ ++ offset = instr & 0x3ffffff; ++ offset = (offset << 2) - ((unsigned int)f_addr & 0xfffffff); ++ if(offset > 0) { ++ offset = ((unsigned int)tcsm_addr & 0xfffffff) + offset; ++ instr = (2 << 26) | (offset >> 2); ++ } ++ } ++ tcsm_addr[i] = instr; ++ } ++} ++ ++static int soc_pm_idle(void) ++{ ++ printk("soc pm idle \n"); ++ ++ load_func_to_sram(); ++ ++ soc_pm_idle_config(); ++ ++ return 0; ++} ++ ++static int soc_pm_idle_pd(void) ++{ ++ printk("soc pm idle pd \n"); ++ ++ load_func_to_sram(); ++ ++ soc_pm_idle_pd_config(); ++ ++ soc_set_reset_entry(); ++ ++ return 0; ++} ++ ++static void soc_pm_sleep(void) ++{ ++ printk("soc pm sleep \n"); ++ ++ load_func_to_sram(); ++ ++ soc_pm_sleep_config(); ++ ++ soc_set_reset_entry(); ++} ++ ++ ++static void soc_pm_fastboot(void) ++{ ++ printk("soc pm fastboot \n"); ++ ++ soc_pm_fastboot_config(); ++ ++ load_func_to_rtc_ram(); ++ ++ sys_save(); ++} ++ ++ ++static void goto_sleep(unsigned int sleep_addr) ++{ ++ mb(); ++ save_goto(sleep_addr); ++ mb(); ++} ++ ++int m300_pm_enter(suspend_state_t state) ++{ ++ unsigned int sleep_addr = 0; ++ unsigned int sleep_level = 0; ++ ++ printk("m300 pm enter!!\n"); ++ ++ sleep_param->uart_base = (UART0_IOBASE | 0xa0000000) + UART_OFF * bc_idx; ++ sleep_param->state = state; ++ ++ if (SLEEP_LEVEL_MAGIC == SLEEP_MAGIC) { ++ if ((state == PM_SUSPEND_STANDBY) && (SLEEP_LEVEL == IDLE)) { ++ soc_pm_idle(); ++ sleep_addr = NORMAL_SLEEP_CODE_ADDR; ++ } else if ((state == PM_SUSPEND_STANDBY) && (SLEEP_LEVEL == IDLE_PD)) { ++ soc_pm_idle_pd(); ++ sleep_addr = NORMAL_SLEEP_CODE_ADDR; ++ } else if ((state == PM_SUSPEND_MEM) && (SLEEP_LEVEL == SLEEP)) { ++ soc_pm_sleep(); ++ sleep_addr = NORMAL_SLEEP_CODE_ADDR; ++ } else if ((state == PM_SUSPEND_MEM) && (SLEEP_LEVEL == FASTBOOT)) { ++ soc_pm_fastboot(); ++ sleep_addr = FASTBOOT_SLEEP_CODE_ADDR; ++ sleep_level = FASTBOOT; ++ } else { ++ printk("error suspend state or suspend level ! \n"); ++ return -1; ++ } ++ } else { ++ if (state == PM_SUSPEND_STANDBY) { ++ soc_pm_idle(); ++ sleep_addr = NORMAL_SLEEP_CODE_ADDR; ++ } else if (state == PM_SUSPEND_MEM) { ++ soc_pm_sleep(); ++ sleep_addr = NORMAL_SLEEP_CODE_ADDR; ++ } else { ++ printk("error suspend state ! \n"); ++ return -1; ++ } ++ } ++ ++ ++#ifdef DEBUG_PM ++ printk("LCR: %08x\n", cpm_inl(CPM_LCR)); ++ printk("OPCR: %08x\n", cpm_inl(CPM_OPCR)); ++ m300_pm_gate_check(); ++#endif ++ ++ ++ goto_sleep(sleep_addr); ++ ++ ++ if (sleep_level == FASTBOOT) { ++ soc_pm_wakeup_fastboot(); ++ } else { ++ soc_pm_wakeup_idle_sleep(); ++ } ++ ++ return 0; ++} ++ ++static int m300_pm_begin(suspend_state_t state) ++{ ++ printk("m300 suspend begin\n"); ++ return 0; ++} ++ ++static void m300_pm_end(void) ++{ ++ printk("m300 pm end!\n"); ++} ++ ++static int ingenic_pm_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++static const struct platform_suspend_ops m300_pm_ops = { ++ .valid = ingenic_pm_valid, ++ .begin = m300_pm_begin, ++ .enter = m300_pm_enter, ++ .end = m300_pm_end, ++}; ++ ++ ++int bc_idx = 0; ++static int __init suspend_console_setup(char *str) ++{ ++ ++ char buf[32]; ++ char *s; ++ ++ strncpy(buf, str, sizeof(buf) - 1); ++ ++ for (s = buf; *s; s++) ++ if (isdigit(*s) || *s == ',') ++ break; ++ ++ bc_idx = simple_strtoul(s, NULL, 10); ++ ++ return 0; ++} ++ ++__setup("console=", suspend_console_setup); ++ ++ ++ ++ ++/* ++ * Initialize suspend interface ++ */ ++static int __init pm_init(void) ++{ ++ ++ suspend_set_ops(&m300_pm_ops); ++ ++ ++ return 0; ++} ++ ++late_initcall(pm_init); +diff --git a/arch/mips/xburst2/soc-m300/pm.h b/arch/mips/xburst2/soc-m300/pm.h +new file mode 100644 +index 000000000..183b00c45 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/pm.h +@@ -0,0 +1,175 @@ ++#ifndef __PM_H__ ++#define __PM_H__ ++ ++#include ++ ++ ++/* ++ * ++ * |-----------------------| ++ * | | ++ * | | ++ * | RESUME_SP | ++ * | | ++ * |-----------------------| ++ * | | ++ * | PARAM | ++ * | | ++ * |-----------------------| ++ * | | ++ * | | ++ * | SLEEP_TEXT | ++ * | | ++ * | | ++ * |-----------------------| ++ * | | ++ * | | ++ * | RESUME_TEXT | ++ * | | ++ * | | ++ * |-----------------------| ++ * | | ++ * | RESUME_BOOTU_TEXTP | ++ * | | ++ * |-----------------------| <------------ TCSM_START 0xb2400000 ++ * ++ */ ++#define SRAM_MEMORY_START 0xb2400000 ++#define SRAM_MEMORY_END 0xb2407ff8 ++#define RTC_MEMORY_START 0xb0004000 ++#define RTC_MEMORY_END 0xb0005000 ++ ++ ++#define NORMAL_RESUME_SP (SRAM_MEMORY_END - 4) ++#define NORMAL_RESUME_CODE1_ADDR SRAM_MEMORY_START ++#define NORMAL_RESUME_CODE1_LEN 64 ++#define NORMAL_RESUME_CODE2_ADDR (NORMAL_RESUME_CODE1_ADDR + NORMAL_RESUME_CODE1_LEN) ++#define NORMAL_RESUME_CODE2_LEN (4096) ++#define NORMAL_SLEEP_CODE_ADDR (NORMAL_RESUME_CODE2_ADDR + NORMAL_RESUME_CODE2_LEN) ++#define NORMAL_SLEEP_CODE_LEN (3072) ++#define NORMAL_PARAM_ADDR (NORMAL_SLEEP_CODE_ADDR + NORMAL_SLEEP_CODE_LEN) ++#define NORMAL_PARAM_LEN (sizeof(struct sleep_param)) ++ ++ ++#define FASTBOOT_RESUME_SP (FASTBOOT_DATA_ADDR - 4) ++#define FASTBOOT_RESUME_CODE1_ADDR RTC_MEMORY_START ++#define FASTBOOT_RESUME_CODE1_LEN 64 ++#define FASTBOOT_RESUME_CODE2_ADDR (FASTBOOT_RESUME_CODE1_ADDR + FASTBOOT_RESUME_CODE1_LEN) ++#define FASTBOOT_RESUME_CODE_LEN 0xb00 ++#define FASTBOOT_SLEEP_CODE_ADDR SRAM_MEMORY_START ++#define FASTBOOT_SLEEP_CODE_LEN 4096 ++#define FASTBOOT_DATA_ADDR 0xb0004c00 ++#define FASTBOOT_DATA_LEN 1024 ++ ++ ++ ++ ++ ++struct sleep_param { ++ suspend_state_t state; ++ unsigned int pdt; ++ unsigned int dpd; ++ unsigned int dlp; ++ unsigned int autorefresh; ++ unsigned int cpu_div; ++ unsigned int uart_base; ++ unsigned int sleep_level; ++}; ++ ++#define sleep_param ((struct sleep_param *)NORMAL_PARAM_ADDR) ++ ++enum { ++ IDLE, ++ IDLE_PD, ++ SLEEP, ++ FASTBOOT, ++}; ++ ++ ++void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size); ++ ++ ++ ++long long save_goto(unsigned int func); ++int restore_goto(unsigned int func); ++ ++ ++static inline void rtc_write_reg(unsigned int reg, unsigned int val) ++{ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ *(volatile unsigned int *)0xb000303c = 0xa55a; ++ while (!((*(volatile unsigned int *)0xb000303c >> 31) & 0x1) ); ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ ++ *(volatile unsigned int *)reg = val; ++ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++} ++ ++static inline unsigned int rtc_read_reg(unsigned int reg) ++{ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ ++ return *(volatile unsigned int *)reg; ++} ++ ++ ++ ++ ++#define reg_ddr_phy(x) (*(volatile unsigned int *)(0xb3011000 + ((x) << 2))) ++ ++ ++ ++extern int bc_idx; ++ ++ ++ ++/************************************************ ++ * debug interface ++ ***********************************************/ ++ ++#define DEBUG_PM ++#define PRINT_DEBUG ++ ++ ++#define U_IOBASE (sleep_param->uart_base) ++#define UART_OFF (0x1000) ++ ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++ ++#ifdef PRINT_DEBUG ++#define TCSM_PCHAR(x) \ ++ *((volatile unsigned int*)(U_IOBASE+OFF_TDR)) = x; \ ++while ((*((volatile unsigned int*)(U_IOBASE + OFF_LSR)) & (LSR_TDRQ | LSR_TEMT)) != (LSR_TDRQ | LSR_TEMT)) ++#else ++#define TCSM_PCHAR(x) ++#endif ++ ++#define TCSM_DELAY(x) \ ++ do{ \ ++ register unsigned int i = x; \ ++ while(i--) \ ++ __asm__ volatile("nop\n\t"); \ ++ }while(0) ++ ++static inline void serial_put_hex(unsigned int x) { ++ int i; ++ unsigned int d; ++ for(i = 7;i >= 0;i--) { ++ d = (x >> (i * 4)) & 0xf; ++ if(d < 10) d += '0'; ++ else d += 'A' - 10; ++ TCSM_PCHAR(d); ++ } ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++} ++ ++ ++#endif +diff --git a/arch/mips/xburst2/soc-m300/pm_fastboot.c b/arch/mips/xburst2/soc-m300/pm_fastboot.c +new file mode 100644 +index 000000000..69980521a +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/pm_fastboot.c +@@ -0,0 +1,503 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pm.h" ++#include "pm_fastboot.h" ++ ++ ++static int fastboot_resume_code[] = { ++#include "fastboot_resume_code.hex" ++}; ++ ++static noinline void fastboot_cpu_resume(void); ++static noinline void fastboot_cpu_sleep(void); ++ ++ ++ ++static void rtc_ram_write_enable(void) ++{ ++ unsigned int tmp; ++ ++ /* write RTC RAM enable */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp &= ~(1 << 23); ++ tmp &= ~(1 << 22); ++ tmp |= (1 << 21); ++ tmp |= (1 << 20); ++ rtc_write_reg(0xb0003048, tmp); ++ ++} ++ ++static void rtc_ram_write_disable(void) ++{ ++ unsigned int tmp; ++ ++ /*exit write RTC RAM enable */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp |= (1 << 22); ++ rtc_write_reg(0xb0003048, tmp); ++ ++} ++ ++ ++ ++ ++ ++static void ost_save(struct ost_regs *ost_regs) ++{ ++ ost_regs->ostccr = *(volatile unsigned int *)0xb2100000; ++ ost_regs->oster = *(volatile unsigned int *)0xb2100004; ++ ost_regs->ostcr = *(volatile unsigned int *)0xb2100008; ++ ost_regs->ostfr = *(volatile unsigned int *)0xb210000c; ++ ost_regs->ostmr = *(volatile unsigned int *)0xb2100010; ++ ost_regs->ostdfr = *(volatile unsigned int *)0xb2100014; ++ ost_regs->ostcnt = *(volatile unsigned int *)0xb2100018; ++ ++ ost_regs->g_ostccr = *(volatile unsigned int *)0xb2000000; ++ ost_regs->g_oster = *(volatile unsigned int *)0xb2000004; ++ ost_regs->g_ostcr = *(volatile unsigned int *)0xb2000008; ++ ost_regs->g_ostcnth = *(volatile unsigned int *)0xb200000c; ++ ost_regs->g_ostcntl = *(volatile unsigned int *)0xb2000010; ++ ost_regs->g_ostcntb = *(volatile unsigned int *)0xb2000014; ++ ++} ++ ++static void ost_restore(struct ost_regs *ost_regs) ++{ ++ *(volatile unsigned int *)0xb2100000 = ost_regs->ostccr; ++ *(volatile unsigned int *)0xb2100008 = ost_regs->ostcr; ++ *(volatile unsigned int *)0xb210000c = ost_regs->ostfr; ++ *(volatile unsigned int *)0xb2100010 = ost_regs->ostmr; ++ *(volatile unsigned int *)0xb2100014 = ost_regs->ostdfr; ++ *(volatile unsigned int *)0xb2100018 = ost_regs->ostcnt; ++ *(volatile unsigned int *)0xb2100004 = ost_regs->oster; ++ ++ *(volatile unsigned int *)0xb2000000 = ost_regs->g_ostccr; ++ *(volatile unsigned int *)0xb2000008 = ost_regs->g_ostcr; ++ *(volatile unsigned int *)0xb2000004 = ost_regs->g_oster; ++ ++} ++ ++static void cpm_save(struct cpm_regs *cpm_regs) ++{ ++ cpm_regs->cpm_sftint = *(volatile unsigned int *)0xb00000bc; ++ cpm_regs->cpsppr = *(volatile unsigned int *)0xb0000038; ++ cpm_regs->cpspr = *(volatile unsigned int *)0xb0000034; ++ cpm_regs->lcr = *(volatile unsigned int *)0xb0000004; ++ cpm_regs->pswc0st = *(volatile unsigned int *)0xb0000090; ++ cpm_regs->pswc1st = *(volatile unsigned int *)0xb0000094; ++ cpm_regs->pswc2st = *(volatile unsigned int *)0xb0000098; ++ cpm_regs->pswc3st = *(volatile unsigned int *)0xb000009c; ++ cpm_regs->clkgr0 = *(volatile unsigned int*)0xb0000020; ++ cpm_regs->clkgr1 = *(volatile unsigned int*)0xb0000028; ++ cpm_regs->mestsel = *(volatile unsigned int*)0xb00000ec; ++ cpm_regs->srbc = *(volatile unsigned int*)0xb00000c4; ++ cpm_regs->exclk_ds = *(volatile unsigned int*)0xb00000e0; ++ cpm_regs->memory_pd0 = *(volatile unsigned int*)0xb00000f8; ++ cpm_regs->memory_pd1 = *(volatile unsigned int*)0xb00000fc; ++ cpm_regs->slbc = *(volatile unsigned int*)0xb00000c8; ++ cpm_regs->slpc = *(volatile unsigned int*)0xb00000cc; ++ cpm_regs->opcr = *(volatile unsigned int*)0xb0000024; ++ cpm_regs->rsr = *(volatile unsigned int*)0xb0000008; ++ ++} ++ ++static void cpm_restore(struct cpm_regs *cpm_regs) ++{ ++ *(volatile unsigned int *)0xb0000020 = 0; ++ *(volatile unsigned int *)0xb0000028 = 0; ++ *(volatile unsigned int *)0xb00000bc = cpm_regs->cpm_sftint; ++ *(volatile unsigned int *)0xb0000038 = cpm_regs->cpsppr; ++ *(volatile unsigned int *)0xb0000034 = cpm_regs->cpspr; ++ *(volatile unsigned int *)0xb0000004 = cpm_regs->lcr; ++ *(volatile unsigned int *)0xb0000090 = cpm_regs->pswc0st; ++ *(volatile unsigned int *)0xb0000094 = cpm_regs->pswc1st; ++ *(volatile unsigned int *)0xb0000098 = cpm_regs->pswc2st; ++ *(volatile unsigned int *)0xb000009c = cpm_regs->pswc3st; ++ *(volatile unsigned int *)0xb00000ec = cpm_regs->mestsel; ++ *(volatile unsigned int *)0xb00000c4 = cpm_regs->srbc; ++ *(volatile unsigned int *)0xb00000e0 = cpm_regs->exclk_ds; ++ *(volatile unsigned int *)0xb00000f8 = cpm_regs->memory_pd0; ++ *(volatile unsigned int *)0xb00000fc = cpm_regs->memory_pd1; ++ *(volatile unsigned int *)0xb00000c8 = cpm_regs->slbc; ++ *(volatile unsigned int *)0xb00000cc = cpm_regs->slpc; ++ *(volatile unsigned int *)0xb0000024 = cpm_regs->opcr; ++ *(volatile unsigned int *)0xb0000008 = cpm_regs->rsr; ++ *(volatile unsigned int *)0xb0000020 = cpm_regs->clkgr0; ++ *(volatile unsigned int *)0xb0000028 = cpm_regs->clkgr1; ++ ++} ++ ++static void ccu_save(struct ccu_regs *ccu_regs) ++{ ++ ccu_regs->mscr = *(volatile unsigned int *)0xb2200060; ++ ccu_regs->pimr = *(volatile unsigned int *)0xb2200120; ++ ccu_regs->mimr = *(volatile unsigned int *)0xb2200160; ++ ccu_regs->oimr = *(volatile unsigned int *)0xb22001a0; ++ ccu_regs->dipr = *(volatile unsigned int *)0xb22001c0; ++ ccu_regs->gdimr = *(volatile unsigned int *)0xb22001e0; ++ ccu_regs->ldimr0 = *(volatile unsigned int *)0xb2200300; ++ ccu_regs->ldimr1 = *(volatile unsigned int *)0xb2200332; ++ ccu_regs->rer = *(volatile unsigned int *)0xb2200f00; ++ ccu_regs->mbr0 = *(volatile unsigned int *)0xb2201000; ++ ccu_regs->mbr1 = *(volatile unsigned int *)0xb2201004; ++ ccu_regs->cslr0 = *(volatile unsigned int *)0xb2200f10; ++ ccu_regs->cslr1 = *(volatile unsigned int *)0xb2200f18; ++ ccu_regs->csar0 = *(volatile unsigned int *)0xb2200f14; ++ ccu_regs->csar1 = *(volatile unsigned int *)0xb2200f1c; ++ ++} ++ ++static void ccu_restore(struct ccu_regs *ccu_regs) ++{ ++ *(volatile unsigned int *)0xb2200060 = ccu_regs->mscr; ++ *(volatile unsigned int *)0xb2200120 = ccu_regs->pimr; ++ *(volatile unsigned int *)0xb2200160 = ccu_regs->mimr; ++ *(volatile unsigned int *)0xb22001a0 = ccu_regs->oimr; ++ *(volatile unsigned int *)0xb22001c0 = ccu_regs->dipr; ++ *(volatile unsigned int *)0xb22001e0 = ccu_regs->gdimr; ++ *(volatile unsigned int *)0xb2200300 = ccu_regs->ldimr0; ++ *(volatile unsigned int *)0xb2200332 = ccu_regs->ldimr1; ++ *(volatile unsigned int *)0xb2200f00 = ccu_regs->rer; ++ *(volatile unsigned int *)0xb2201000 = ccu_regs->mbr0; ++ *(volatile unsigned int *)0xb2201004 = ccu_regs->mbr1; ++ *(volatile unsigned int *)0xb2200f10 = ccu_regs->cslr0; ++ *(volatile unsigned int *)0xb2200f18 = ccu_regs->cslr1; ++ *(volatile unsigned int *)0xb2200f14 = ccu_regs->csar0; ++ *(volatile unsigned int *)0xb2200f1c = ccu_regs->csar1; ++ ++} ++ ++ ++ ++ ++ ++struct uart_regs *uart_regs; ++struct ost_regs *ost_regs; ++struct cpm_regs *cpm_regs; ++struct ccu_regs *ccu_regs; ++ ++void sys_save(void) ++{ ++ uart_regs = kmalloc(sizeof(struct uart_regs), GFP_KERNEL); ++ ost_regs = kmalloc(sizeof(struct ost_regs), GFP_KERNEL); ++ cpm_regs = kmalloc(sizeof(struct cpm_regs), GFP_KERNEL); ++ ccu_regs = kmalloc(sizeof(struct ccu_regs), GFP_KERNEL); ++ ++ ost_save(ost_regs); ++ cpm_save(cpm_regs); ++ ccu_save(ccu_regs); ++} ++ ++void sys_restore(void) ++{ ++ ost_restore(ost_regs); ++ cpm_restore(cpm_regs); ++ ccu_restore(ccu_regs); ++ ++ ++ kfree(uart_regs); ++ kfree(ost_regs); ++} ++ ++ ++ ++ ++ ++ ++static struct store_regs *store_regs; ++ ++static void save_resume_pc(void) ++{ ++ ++ store_regs = (struct store_regs *)FASTBOOT_DATA_ADDR; ++ store_regs->resume_pc = (unsigned int)fastboot_cpu_resume; ++ printk("xxxxxxxxxxxxxxxxxxx save resume_pc = 0x%08x\n", store_regs->resume_pc); ++} ++ ++static void save_uart_index(void) ++{ ++ store_regs = (struct store_regs *)FASTBOOT_DATA_ADDR; ++ store_regs->uart_index = bc_idx; ++ printk("xxxxxxxxxxxxxxxxxxx save uart_index = %d\n", store_regs->uart_index); ++} ++ ++static void pll_store(void) ++{ ++ struct pll_resume_reg *pll_resume_reg; ++ ++ store_regs = (struct store_regs *)FASTBOOT_DATA_ADDR; ++ pll_resume_reg = &store_regs->pll_resume_reg; ++ ++ pll_resume_reg->cpccr = *(volatile unsigned int *)0xb0000000; ++ pll_resume_reg->cppcr = *(volatile unsigned int *)0xb000000c; ++ pll_resume_reg->cpapcr = *(volatile unsigned int *)0xb0000010; ++ pll_resume_reg->cpmpcr = *(volatile unsigned int *)0xb0000014; ++ pll_resume_reg->cpepcr = *(volatile unsigned int *)0xb0000018; ++ pll_resume_reg->ddrcdr = *(volatile unsigned int *)0xb000002c; ++ ++} ++ ++static void ddrc_store(void) ++{ ++ struct ddrc_resume_reg *ddrc_resume_reg; ++ ++ store_regs = (struct store_regs *)FASTBOOT_DATA_ADDR; ++ ddrc_resume_reg = &store_regs->ddrc_resume_reg; ++ ++ ddrc_resume_reg->dcfg = *(volatile unsigned int *)0xb34f0008; ++ ddrc_resume_reg->dctrl = *(volatile unsigned int *)0xb34f0010; ++ ddrc_resume_reg->dlmr = *(volatile unsigned int *)0xb34f0018; ++ ddrc_resume_reg->ddlp = *(volatile unsigned int *)0xb34f0020; ++ ddrc_resume_reg->dasr_en = *(volatile unsigned int *)0xb34f0030; ++ ddrc_resume_reg->dasr_cnt = *(volatile unsigned int *)0xb34f0028; ++ ddrc_resume_reg->drefcnt = *(volatile unsigned int *)0xb34f0038; ++ ddrc_resume_reg->dtimming1 = *(volatile unsigned int *)0xb34f0040; ++ ddrc_resume_reg->dtimming2 = *(volatile unsigned int *)0xb34f0048; ++ ddrc_resume_reg->dtimming3 = *(volatile unsigned int *)0xb34f0050; ++ ddrc_resume_reg->dtimming4 = *(volatile unsigned int *)0xb34f0058; ++ ddrc_resume_reg->dtimming5 = *(volatile unsigned int *)0xb34f0060; ++ ddrc_resume_reg->dmmap0 = *(volatile unsigned int *)0xb34f0078; ++ ddrc_resume_reg->dmmap1 = *(volatile unsigned int *)0xb34f0080; ++ ++ ddrc_resume_reg->dbwcfg = *(volatile unsigned int *)0xb34f0088; ++ ddrc_resume_reg->dbwstp = *(volatile unsigned int *)0xb34f0090; ++ ddrc_resume_reg->hregpro = *(volatile unsigned int *)0xb34f00d8; ++ ddrc_resume_reg->dbgen = *(volatile unsigned int *)0xb34f00e0; ++ ++ ddrc_resume_reg->dwcfg = *(volatile unsigned int *)0xb3012000; ++ ddrc_resume_reg->dremap1 = *(volatile unsigned int *)0xb3012008; ++ ddrc_resume_reg->dremap2 = *(volatile unsigned int *)0xb301200c; ++ ddrc_resume_reg->dremap3 = *(volatile unsigned int *)0xb3012010; ++ ddrc_resume_reg->dremap4 = *(volatile unsigned int *)0xb3012014; ++ ddrc_resume_reg->dremap5 = *(volatile unsigned int *)0xb3012018; ++ ++ ddrc_resume_reg->cpac = *(volatile unsigned int *)0xb301201c; ++ ddrc_resume_reg->cchc0 = *(volatile unsigned int *)0xb3012020; ++ ddrc_resume_reg->cchc1 = *(volatile unsigned int *)0xb3012024; ++ ddrc_resume_reg->cchc2 = *(volatile unsigned int *)0xb3012028; ++ ddrc_resume_reg->cchc3 = *(volatile unsigned int *)0xb301202c; ++ ddrc_resume_reg->cchc4 = *(volatile unsigned int *)0xb3012030; ++ ddrc_resume_reg->cchc5 = *(volatile unsigned int *)0xb3012034; ++ ddrc_resume_reg->cchc6 = *(volatile unsigned int *)0xb3012038; ++ ddrc_resume_reg->cchc7 = *(volatile unsigned int *)0xb301203c; ++ ddrc_resume_reg->cschc0 = *(volatile unsigned int *)0xb3012040; ++ ddrc_resume_reg->cschc1 = *(volatile unsigned int *)0xb3012044; ++ ddrc_resume_reg->cschc2 = *(volatile unsigned int *)0xb3012048; ++ ddrc_resume_reg->cschc3 = *(volatile unsigned int *)0xb301204c; ++ ddrc_resume_reg->cmonc0 = *(volatile unsigned int *)0xb3012050; ++ ddrc_resume_reg->cmonc1 = *(volatile unsigned int *)0xb3012054; ++ ddrc_resume_reg->cmonc2 = *(volatile unsigned int *)0xb3012058; ++ ddrc_resume_reg->cmonc3 = *(volatile unsigned int *)0xb301205c; ++ ddrc_resume_reg->cmonc4 = *(volatile unsigned int *)0xb3012060; ++ ++ ddrc_resume_reg->ccguc0 = *(volatile unsigned int *)0xb3012064; ++ ddrc_resume_reg->ccguc1 = *(volatile unsigned int *)0xb3012068; ++ ++ ddrc_resume_reg->pregpro = *(volatile unsigned int *)0xb301206c; ++ ddrc_resume_reg->bufcfg = *(volatile unsigned int *)0xb3012070; ++} ++ ++static void ddr_phy_store(void) ++{ ++ struct ddr_phy_resume_reg *ddr_phy_resume_reg; ++ ++ store_regs = (struct store_regs *)FASTBOOT_DATA_ADDR; ++ ddr_phy_resume_reg = &store_regs->ddr_phy_resume_reg; ++ ++ ddr_phy_resume_reg->mem_cfg = *(volatile unsigned int *)0xb3011004; ++ ddr_phy_resume_reg->dq_width = *(volatile unsigned int *)0xb301107c; ++ ddr_phy_resume_reg->cl = *(volatile unsigned int *)0xb3011014; ++ ddr_phy_resume_reg->al = *(volatile unsigned int *)0xb3011018; ++ ddr_phy_resume_reg->cwl = *(volatile unsigned int *)0xb301101c; ++ ddr_phy_resume_reg->pll_fbdiv = *(volatile unsigned int *)0xb3011080; ++ ddr_phy_resume_reg->pll_ctrl = *(volatile unsigned int *)0xb3011084; ++ ddr_phy_resume_reg->pll_pdiv = *(volatile unsigned int *)0xb3011088; ++ ddr_phy_resume_reg->training_ctrl = *(volatile unsigned int *)0xb3011008; ++ ddr_phy_resume_reg->calib_bypass_al = *(volatile unsigned int *)0xb3011118; ++ ddr_phy_resume_reg->calib_bypass_ah = *(volatile unsigned int *)0xb3011158; ++ ddr_phy_resume_reg->wl_mode1 = *(volatile unsigned int *)0xb301100c; ++ ddr_phy_resume_reg->wl_mode2 = *(volatile unsigned int *)0xb3011010; ++} ++ ++static void rtc_ram_store(void) ++{ ++ pll_store(); ++ ddrc_store(); ++ ddr_phy_store(); ++ save_resume_pc(); ++ save_uart_index(); ++} ++ ++ ++void load_func_to_rtc_ram(void) ++{ ++ ++ load_func_to_tcsm((unsigned int *)FASTBOOT_SLEEP_CODE_ADDR, (unsigned int *)fastboot_cpu_sleep, FASTBOOT_SLEEP_CODE_LEN); ++ ++ rtc_ram_write_enable(); ++ memset((unsigned int *)RTC_MEMORY_START, 0, 4096); ++ rtc_ram_store(); ++ memcpy((unsigned int *)FASTBOOT_RESUME_CODE1_ADDR, (unsigned int *)fastboot_resume_code, FASTBOOT_RESUME_CODE_LEN); ++ rtc_ram_write_disable(); ++} ++ ++ ++ ++ ++ ++static noinline void fastboot_cpu_resume(void) ++{ ++ ++ ++ *(volatile unsigned int *)0xb2200f00 = 0xbfc00000; /* RESET entry = 0xbfc00000 ,reset value */ ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (restore_goto) ++ : ++ ); ++} ++ ++ ++static noinline void fastboot_cpu_sleep(void) ++{ ++ ++ ++ unsigned int tmp; ++ unsigned int ddrc_ctrl; ++ ++ blast_dcache32(); ++ blast_scache64(); ++ __sync(); ++ __fast_iob(); ++ ++ ddr_writel(0, DDRC_AUTOSR_EN); ++ tmp = *(volatile unsigned int *)0xa0000000; ++ ++ ++ /* DDR self refresh */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= 1 << 5; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ while(!(ddr_readl(DDRC_STATUS) & (1<<2))); ++ ++ /* bufferen_core = 0 */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp &= ~(1 << 21); ++ rtc_write_reg(0xb0003048, tmp); ++ ++ /* dfi_init_start = 1 */ ++ *(volatile unsigned int *)0xb3012000 |= (1 << 3); ++ ++ ++ { ++ int i; ++ for (i = 0; i < 4; i++) { ++ ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ } ++ } ++ /* ddr phy pll power down */ ++ *(volatile unsigned int *)0xb3011084 |= (1 << 1); ++ ++ ++ TCSM_PCHAR('W'); ++ ++ ++ /* rtc disable power detect */ ++ rtc_write_reg(0xb000302c, (0x1a55a5a5 << 3) | 1); ++ /* RTC PD */ ++ rtc_write_reg(0xb0003020, 1); ++ ++ ++ while (1); ++} ++ ++ ++void soc_pm_fastboot_config(void) ++{ ++ ++ unsigned int tmp; ++ unsigned int intc1_msk; ++ unsigned int clk_gate0; ++ ++ clk_gate0 = cpm_inl(CPM_CLKGR); ++ ++ clk_gate0 &= ~(1 << 27); //enable rtc ++ ++ cpm_outl(clk_gate0, CPM_CLKGR); ++ ++ ++ intc1_msk = *(volatile unsigned int *)0xb0001024; ++ *(volatile unsigned int *)0xb0001024 = intc1_msk & ~(1<<0); // RTC INT MSK ++ ++ /* RTC EALM */ ++ tmp = rtc_read_reg(0xb000302c); ++ tmp |= 1; ++ rtc_write_reg(0xb000302c, tmp); ++ ++ /* RTC enable AE */ ++ tmp = rtc_read_reg(0xb0003000); ++ tmp |= (1 << 2) | (1 << 0); ++ rtc_write_reg(0xb0003000, tmp); ++ ++ /* 32k rtc clk */ ++ tmp = rtc_read_reg(0xb0003000); ++ tmp &= ~(1 << 1); ++ rtc_write_reg(0xb0003000, tmp); ++ ++ rtc_write_reg(0xb0003028, 0); ++ rtc_write_reg(0xb0003024, 0); ++} ++ ++ ++ ++static int soc_pm_wakeup_fastboot_config(void) ++{ ++ ++ return 0; ++} ++ ++void soc_pm_wakeup_fastboot(void) ++{ ++ ++ soc_pm_wakeup_fastboot_config(); ++ ++ sys_restore(); ++ ++} ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/arch/mips/xburst2/soc-m300/pm_fastboot.h b/arch/mips/xburst2/soc-m300/pm_fastboot.h +new file mode 100644 +index 000000000..7c9a4682d +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/pm_fastboot.h +@@ -0,0 +1,172 @@ ++#ifndef __PM_FASTBOOT_H__ ++#define __PM_FASTBOOT_H__ ++ ++struct pll_resume_reg { ++ unsigned int cpccr; ++ unsigned int cppcr; ++ unsigned int cpapcr; ++ unsigned int cpmpcr; ++ unsigned int cpepcr; ++ unsigned int ddrcdr; ++}; ++ ++struct ddrc_resume_reg { ++ unsigned int dcfg; ++ unsigned int dctrl; ++ unsigned int dlmr; ++ unsigned int ddlp; ++ unsigned int dasr_en; ++ unsigned int dasr_cnt; ++ unsigned int drefcnt; ++ unsigned int dtimming1; ++ unsigned int dtimming2; ++ unsigned int dtimming3; ++ unsigned int dtimming4; ++ unsigned int dtimming5; ++ unsigned int dmmap0; ++ unsigned int dmmap1; ++ unsigned int dbwcfg; ++ unsigned int dbwstp; ++ unsigned int hregpro; ++ unsigned int dbgen; ++ unsigned int dwcfg; ++ unsigned int dremap1; ++ unsigned int dremap2; ++ unsigned int dremap3; ++ unsigned int dremap4; ++ unsigned int dremap5; ++ unsigned int cpac; ++ unsigned int cchc0; ++ unsigned int cchc1; ++ unsigned int cchc2; ++ unsigned int cchc3; ++ unsigned int cchc4; ++ unsigned int cchc5; ++ unsigned int cchc6; ++ unsigned int cchc7; ++ unsigned int cschc0; ++ unsigned int cschc1; ++ unsigned int cschc2; ++ unsigned int cschc3; ++ unsigned int cmonc0; ++ unsigned int cmonc1; ++ unsigned int cmonc2; ++ unsigned int cmonc3; ++ unsigned int cmonc4; ++ unsigned int ccguc0; ++ unsigned int ccguc1; ++ unsigned int pregpro; ++ unsigned int bufcfg; ++}; ++ ++struct ddr_phy_resume_reg { ++ unsigned int phy_rst; ++ unsigned int mem_cfg; ++ unsigned int dq_width; ++ unsigned int cl; ++ unsigned int al; ++ unsigned int cwl; ++ unsigned int pll_fbdiv; ++ unsigned int pll_ctrl; ++ unsigned int pll_pdiv; ++ unsigned int training_ctrl; ++ unsigned int calib_bypass_al; ++ unsigned int calib_bypass_ah; ++ unsigned int wl_mode1; ++ unsigned int wl_mode2; ++ ++}; ++ ++struct store_regs { ++ unsigned int resume_pc; ++ unsigned int uart_index; ++ struct pll_resume_reg pll_resume_reg; ++ struct ddrc_resume_reg ddrc_resume_reg; ++ struct ddr_phy_resume_reg ddr_phy_resume_reg; ++}; ++ ++ ++ ++struct uart_regs { ++ unsigned int udllr; ++ unsigned int udlhr; ++ unsigned int uthr; ++ unsigned int uier; ++ unsigned int ufcr; ++ unsigned int ulcr; ++ unsigned int umcr; ++ unsigned int uspr; ++ unsigned int isr; ++ unsigned int umr; ++ unsigned int uacr; ++ unsigned int urcr; ++ unsigned int utcr; ++ ++}; ++ ++ ++struct ost_regs { ++ unsigned int ostccr; ++ unsigned int oster; ++ unsigned int ostcr; ++ unsigned int ostfr; ++ unsigned int ostmr; ++ unsigned int ostdfr; ++ unsigned int ostcnt; ++ ++ unsigned int g_ostccr; ++ unsigned int g_oster; ++ unsigned int g_ostcr; ++ unsigned int g_ostcnth; ++ unsigned int g_ostcntl; ++ unsigned int g_ostcntb; ++}; ++ ++struct cpm_regs { ++ unsigned int cpm_sftint; ++ unsigned int cpsppr; ++ unsigned int cpspr; ++ unsigned int lcr; ++ unsigned int pswc0st; ++ unsigned int pswc1st; ++ unsigned int pswc2st; ++ unsigned int pswc3st; ++ unsigned int clkgr0; ++ unsigned int clkgr1; ++ unsigned int mestsel; ++ unsigned int srbc; ++ unsigned int exclk_ds; ++ unsigned int memory_pd0; ++ unsigned int memory_pd1; ++ unsigned int slbc; ++ unsigned int slpc; ++ unsigned int opcr; ++ unsigned int rsr; ++}; ++ ++struct ccu_regs { ++ unsigned int mscr; ++ unsigned int pimr; ++ unsigned int mimr; ++ unsigned int oimr; ++ unsigned int dipr; ++ unsigned int gdimr; ++ unsigned int ldimr0; ++ unsigned int ldimr1; ++ unsigned int rer; ++ unsigned int mbr0; ++ unsigned int mbr1; ++ unsigned int cslr0; ++ unsigned int cslr1; ++ unsigned int csar0; ++ unsigned int csar1; ++}; ++ ++ ++void load_func_to_rtc_ram(void); ++void soc_pm_fastboot_config(void); ++void soc_pm_wakeup_fastboot(void); ++void sys_save(void); ++void sys_restore(void); ++ ++#endif +diff --git a/arch/mips/xburst2/soc-m300/pm_sleep.c b/arch/mips/xburst2/soc-m300/pm_sleep.c +new file mode 100644 +index 000000000..ca7cbbfa3 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/pm_sleep.c +@@ -0,0 +1,357 @@ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pm.h" ++#include "pm_sleep.h" ++ ++ ++ ++static inline void ddrp_auto_calibration(void) ++{ ++ unsigned int reg_val = ddr_readl(DDRP_INNOPHY_TRAINING_CTRL); ++ unsigned int timeout = 0xffffff; ++ unsigned int wait_cal_done = DDRP_CALIB_DONE_HDQCFA | DDRP_CALIB_DONE_LDQCFA; ++ ++ reg_val &= ~(DDRP_TRAINING_CTRL_DSCSE_BP); ++ reg_val |= DDRP_TRAINING_CTRL_DSACE_START; ++ ddr_writel(reg_val, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ while(!((ddr_readl(DDRP_INNOPHY_CALIB_DONE) & wait_cal_done) == wait_cal_done) && --timeout) { ++ TCSM_PCHAR('t'); ++ } ++ ++ if(!timeout) { ++ TCSM_PCHAR('f'); ++ } ++ ddr_writel(0, DDRP_INNOPHY_TRAINING_CTRL); ++} ++ ++int soc_pm_idle_config(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 30); ++ opcr &= ~(1 << 31); ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++ ++int soc_pm_idle_pd_config(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ lcr |= 2; ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~ (1<<31); ++ opcr |= (1 << 30); ++ opcr &= ~(1 << 26); //l2c power down ++ opcr |= 1 << 2; // select RTC clk ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++ ++int soc_pm_sleep_config(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; ++ lcr |= 1 << 0; // low power mode: SLEEP ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 31); ++ opcr |= (1 << 30); ++ opcr &= ~(1 << 26); //L2C power down ++ opcr |= (1 << 21); // cpu 32k ram retention. ++ opcr |= (1 << 3); // power down CPU ++ opcr &= ~(1 << 4); // exclk disable; ++ opcr |= (1 << 2); // select RTC clk ++ opcr |= (1 << 22); ++ opcr |= (1 << 20); ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++ ++int soc_pm_wakeup_idle_sleep(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ lcr &= ~0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ printk("post wakeup!\n"); ++ ++ ++ { ++ /* after power down cpu by set PD in OPCR, resume cpu's frequency and L2C's freq */ ++ unsigned int val; ++ ++ /* change disable */ ++ val = cpm_inl(CPM_CPCCR); ++ val &= ~(1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* resume cpu_div in CPCCR */ ++ val &= ~0xf; ++ val |= sleep_param->cpu_div; ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* change enable */ ++ val |= (1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ while (cpm_inl(CPM_CPCSR) & 1); ++ } ++ return 0; ++} ++ ++void soc_set_reset_entry(void) ++{ ++ *(volatile unsigned int *)0xb2200f00 = NORMAL_RESUME_CODE1_ADDR; ++ ++} ++ ++ ++static noinline void cpu_resume_bootup(void) ++{ ++ TCSM_PCHAR('X'); ++ /* set reset entry */ ++ *(volatile unsigned int *)0xb2200f00 = 0xbfc00000; ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "move $29, %0 \n\t" ++ "jr.hb %1 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ :"r" (NORMAL_RESUME_SP), "r"(NORMAL_RESUME_CODE2_ADDR) ++ : ++ ); ++ ++} ++static noinline void cpu_resume(void) ++{ ++ unsigned int ddrc_ctrl; ++ ++ TCSM_PCHAR('R'); ++ ++ if (sleep_param->state == PM_SUSPEND_MEM) { ++ int tmp; ++ ++ /* enable pll */ ++ tmp = reg_ddr_phy(0x21); ++ tmp &= ~(1 << 1); ++ reg_ddr_phy(0x21) = tmp; ++ ++ while (!(reg_ddr_phy(0x32) & 0x8)) ++ serial_put_hex(reg_ddr_phy(0x32)); ++ ++ /* dfi_init_start = 0, wait dfi_init_complete */ ++ *(volatile unsigned int *)0xb3012000 &= ~(1 << 3); ++ while(!(*(volatile unsigned int *)0xb3012004 & 0x1)); ++ ++ /* bufferen_core = 1 */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp |= (1 << 21); ++ rtc_write_reg(0xb0003048, tmp); ++ ++ /* exit sr */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl &= ~(1<<5); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ while(ddr_readl(DDRC_STATUS) & (1<<2)); ++ ++ TCSM_DELAY(1000); ++ TCSM_PCHAR('1'); ++ ddrp_auto_calibration(); ++ TCSM_PCHAR('2'); ++ ++ /* restore ddr auto-sr */ ++ ddr_writel(sleep_param->autorefresh, DDRC_AUTOSR_EN); ++ TCSM_PCHAR('3'); ++ ++ /* restore ddr LPEN */ ++ ddr_writel(sleep_param->dlp, DDRC_DLP); ++ ++ /* restore ddr deep power down state */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= sleep_param->pdt; ++ ddrc_ctrl |= sleep_param->dpd; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ TCSM_PCHAR('4'); ++ } ++ ++ ++ TCSM_PCHAR('5'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (restore_goto) ++ : ++ ); ++} ++ ++ ++static noinline void cpu_sleep(void) ++{ ++ ++ ++ sleep_param->cpu_div = cpm_inl(CPM_CPCCR) & 0xf; ++ ++ blast_dcache32(); ++ blast_scache64(); ++ __sync(); ++ __fast_iob(); ++ ++ { ++ /* before power down cpu by set PD in OPCR, reduce cpu's frequency as the same as L2C's freq */ ++ unsigned int val, div; ++ ++ /* change disable */ ++ val = cpm_inl(CPM_CPCCR); ++ val &= ~(1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* div cpu = div l2c */ ++ div = val & (0xf << 4); ++ val &= ~0xf; ++ val |= (div >> 4); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* change enable */ ++ val |= (1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ while (cpm_inl(CPM_CPCSR) & 1); ++ } ++ ++ TCSM_PCHAR('D'); ++ ++ if (sleep_param->state == PM_SUSPEND_MEM) { ++ unsigned int tmp; ++ unsigned int ddrc_ctrl; ++ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ++ /* save ddr low power state */ ++ sleep_param->pdt = ddrc_ctrl & DDRC_CTRL_PDT_MASK; ++ sleep_param->dpd = ddrc_ctrl & DDRC_CTRL_DPD; ++ sleep_param->dlp = ddr_readl(DDRC_DLP); ++ sleep_param->autorefresh = ddr_readl(DDRC_AUTOSR_EN); ++ ++ /* ddr disable deep power down */ ++ ddrc_ctrl &= ~(DDRC_CTRL_PDT_MASK); ++ ddrc_ctrl &= ~(DDRC_CTRL_DPD); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ /* ddr diasble LPEN*/ ++ ddr_writel(0, DDRC_DLP); ++ ++ /* ddr disable auto-sr */ ++ ddr_writel(0, DDRC_AUTOSR_EN); ++ tmp = *(volatile unsigned int *)0xa0000000; ++ ++ /* DDR self refresh */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= 1 << 5; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ while(!(ddr_readl(DDRC_STATUS) & (1<<2))); ++ ++ ++ /* bufferen_core = 0 */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp &= ~(1 << 21); ++ rtc_write_reg(0xb0003048, tmp); ++ ++ ++ /* dfi_init_start = 1 */ ++ *(volatile unsigned int *)0xb3012000 |= (1 << 3); ++ ++ { ++ int i; ++ for (i = 0; i < 4; i++) { ++ ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ } ++ } ++ ++ /* disable pll */ ++ reg_ddr_phy(0x21) |= (1 << 1); ++ } ++ ++ TCSM_PCHAR('W'); ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "wait \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ ); ++ ++ TCSM_PCHAR('N'); ++ ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (NORMAL_RESUME_CODE1_ADDR) ++ : ++ ); ++ TCSM_PCHAR('F'); ++} ++ ++ ++void load_func_to_sram(void) ++{ ++ load_func_to_tcsm((unsigned int *)NORMAL_RESUME_CODE1_ADDR, (unsigned int *)cpu_resume_bootup, NORMAL_RESUME_CODE1_LEN); ++ load_func_to_tcsm((unsigned int *)NORMAL_RESUME_CODE2_ADDR, (unsigned int *)cpu_resume, NORMAL_RESUME_CODE2_LEN); ++ load_func_to_tcsm((unsigned int *)NORMAL_SLEEP_CODE_ADDR, (unsigned int *)cpu_sleep, NORMAL_SLEEP_CODE_LEN); ++} ++ ++ ++ +diff --git a/arch/mips/xburst2/soc-m300/pm_sleep.h b/arch/mips/xburst2/soc-m300/pm_sleep.h +new file mode 100644 +index 000000000..01eb77aed +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/pm_sleep.h +@@ -0,0 +1,16 @@ ++#ifndef __PM_SLEEP_H__ ++#define __PM_SLEEP_H__ ++ ++ ++ ++void load_func_to_sram(void); ++int soc_pm_idle_pd_config(void); ++int soc_pm_idle_config(void); ++int soc_pm_sleep_config(void); ++int soc_pm_wakeup_idle_sleep(void); ++void soc_set_reset_entry(void); ++ ++ ++ ++#endif ++ +diff --git a/arch/mips/xburst2/soc-m300/regs_save_restore.S b/arch/mips/xburst2/soc-m300/regs_save_restore.S +new file mode 100644 +index 000000000..abe8b49df +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/regs_save_restore.S +@@ -0,0 +1,190 @@ ++#include ++#include ++ ++#define CP0_PAGEMASK $5,0 ++#define CP0_STATUS $12,0 ++#define CP0_INTCTL $12,1 ++#define CP0_CAUSE $13,0 ++#define CP0_EBASE $15,1 ++#define CP0_CONFIG $16,0 ++#define CP0_CONFIG1 $16,1 ++#define CP0_CONFIG2 $16,2 ++#define CP0_CONFIG3 $16,3 ++#define CP0_CONFIG4 $16,4 ++#define CP0_CONFIG5 $16,5 ++#define CP0_CONFIG7 $16,7 ++#define CP0_LLADDR $17,0 ++#define CP0_WATCHLo $18,0 ++#define CP0_WATCHHI $19,0 ++#define CP0_ERRCTL $26,0 ++#define CP0_CONTEXT $4,0 ++#define CP0_KSCRATCH1 $31,2 ++#define CP0_KSCRATCH2 $31,3 ++#define CP0_KSCRATCH3 $31,4 ++#define CP0_KSCRATCH4 $31,5 ++#define CP0_KSCRATCH5 $31,6 ++#define CP0_KSCRATCH6 $31,7 ++ ++ .data ++ .global _regs_stack ++_regs_stack: ++ .align 5 ++ .space 140,0 ++ ++ .text ++ .global save_goto ++ .align 2 ++ .ent save_goto,0 ++ LEAF(save_goto) ++save_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sw s0,0(k0) ++ sw s1,4(k0) ++ sw s2,8(k0) ++ sw s3,12(k0) ++ sw s4,16(k0) ++ sw s5,20(k0) ++ sw s6,24(k0) ++ sw s7,28(k0) ++ sw gp,32(k0) ++ sw sp,36(k0) ++ sw fp,40(k0) ++ sw ra,44(k0) ++ ++ mfc0 k1,CP0_PAGEMASK ++ sw k1,48(k0) ++ mfc0 k1,CP0_STATUS ++ sw k1,52(k0) ++ mfc0 k1,CP0_INTCTL ++ sw k1,56(k0) ++ mfc0 k1,CP0_CAUSE ++ sw k1,60(k0) ++ mfc0 k1,CP0_EBASE ++ sw k1,64(k0) ++ mfc0 k1,CP0_CONFIG ++ sw k1,68(k0) ++ mfc0 k1,CP0_CONFIG1 ++ sw k1,72(k0) ++ mfc0 k1,CP0_CONFIG2 ++ sw k1,76(k0) ++ mfc0 k1,CP0_CONFIG3 ++ sw k1,80(k0) ++ mfc0 k1,CP0_CONFIG4 ++ sw k1,84(k0) ++ mfc0 k1,CP0_CONFIG5 ++ sw k1,88(k0) ++ mfc0 k1,CP0_CONFIG7 ++ sw k1,92(k0) ++ mfc0 k1,CP0_LLADDR ++ sw k1,96(k0) ++ mfc0 k1,CP0_WATCHLo ++ sw k1,100(k0) ++ mfc0 k1,CP0_WATCHHI ++ sw k1,104(k0) ++ mfc0 k1,CP0_ERRCTL ++ sw k1,108(k0) ++ mfc0 k1,CP0_CONTEXT ++ sw k1,112(k0) ++ mfc0 k1,CP0_KSCRATCH1 ++ sw k1,116(k0) ++ mfc0 k1,CP0_KSCRATCH2 ++ sw k1,120(k0) ++ mfc0 k1,CP0_KSCRATCH3 ++ sw k1,124(k0) ++ mfc0 k1,CP0_KSCRATCH4 ++ sw k1,128(k0) ++ mfc0 k1,CP0_KSCRATCH5 ++ sw k1,132(k0) ++ mfc0 k1,CP0_KSCRATCH6 ++ sw k1,136(k0) ++ ++ jr.hb a0 ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(save_goto) ++ ++ .text ++ .global restore_goto ++ .align 2 ++ .ent restore_goto,0 ++ LEAF(restore_goto) ++restore_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ lw s0,0(k0) ++ lw s1,4(k0) ++ lw s2,8(k0) ++ lw s3,12(k0) ++ lw s4,16(k0) ++ lw s5,20(k0) ++ lw s6,24(k0) ++ lw s7,28(k0) ++ lw gp,32(k0) ++ lw sp,36(k0) ++ lw fp,40(k0) ++ lw ra,44(k0) ++ ++ lw k1,48(k0) ++ mtc0 k1,CP0_PAGEMASK ++ lw k1,52(k0) ++ mtc0 k1,CP0_STATUS ++ lw k1,56(k0) ++ mtc0 k1,CP0_INTCTL ++ lw k1,60(k0) ++ mtc0 k1,CP0_CAUSE ++ lw k1,64(k0) ++ mtc0 k1,CP0_EBASE ++ lw k1,68(k0) ++ mtc0 k1,CP0_CONFIG ++ lw k1,72(k0) ++ mtc0 k1,CP0_CONFIG1 ++ lw k1,76(k0) ++ mtc0 k1,CP0_CONFIG2 ++ lw k1,80(k0) ++ mtc0 k1,CP0_CONFIG3 ++ lw k1,84(k0) ++ mtc0 k1,CP0_CONFIG4 ++ lw k1,88(k0) ++ mtc0 k1,CP0_CONFIG5 ++ lw k1,92(k0) ++ mtc0 k1,CP0_CONFIG7 ++ lw k1,96(k0) ++ mtc0 k1,CP0_LLADDR ++ lw k1,100(k0) ++ mtc0 k1,CP0_WATCHLo ++ lw k1,104(k0) ++ mtc0 k1,CP0_WATCHHI ++ lw k1,108(k0) ++ mtc0 k1,CP0_ERRCTL ++ lw k1,112(k0) ++ mtc0 k1,CP0_CONTEXT ++ lw k1,116(k0) ++ mtc0 k1,CP0_KSCRATCH1 ++ lw k1,120(k0) ++ mtc0 k1,CP0_KSCRATCH2 ++ lw k1,124(k0) ++ mtc0 k1,CP0_KSCRATCH3 ++ lw k1,128(k0) ++ mtc0 k1,CP0_KSCRATCH4 ++ lw k1,132(k0) ++ mtc0 k1,CP0_KSCRATCH5 ++ lw k1,136(k0) ++ mtc0 k1,CP0_KSCRATCH6 ++ ++ jr.hb ra ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(restore_goto) +diff --git a/arch/mips/xburst2/soc-m300/regs_save_restore.py b/arch/mips/xburst2/soc-m300/regs_save_restore.py +new file mode 100755 +index 000000000..8a23de0d0 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/regs_save_restore.py +@@ -0,0 +1,124 @@ ++#!/usr/bin/env python ++import os ++import string ++ ++common_regs=["s0","s1","s2","s3", ++ "s4","s5","s6","s7", ++ "gp","sp","fp","ra"] ++cp0_regs=[ ++ ["CP0_PAGEMASK","$5","0"], ++ ["CP0_STATUS","$12","0"], ++ ["CP0_INTCTL","$12","1"], ++ ["CP0_CAUSE","$13","0"], ++ ["CP0_EBASE","$15","1"], ++ ["CP0_CONFIG","$16","0"], ++ ["CP0_CONFIG1","$16","1"], ++ ["CP0_CONFIG2","$16","2"], ++ ["CP0_CONFIG3","$16","3"], ++ ["CP0_CONFIG4", "$16", "4"], ++ ["CP0_CONFIG5", "$16", "5"], ++ ["CP0_CONFIG7", "$16", "7"], ++ ["CP0_LLADDR","$17","0"], ++ ["CP0_WATCHLo","$18","0"], ++ ["CP0_WATCHHI","$19","0"], ++ ["CP0_ERRCTL","$26","0"], ++ ["CP0_CONTEXT","$4","0"], ++ ["CP0_KSCRATCH1","$31","2"], ++ ["CP0_KSCRATCH2","$31","3"], ++ ["CP0_KSCRATCH3","$31","4"], ++ ["CP0_KSCRATCH4","$31","5"], ++ ["CP0_KSCRATCH5","$31","6"], ++ ["CP0_KSCRATCH6","$31","7"], ++ ] ++def gen_get_array_size(): ++ size=0 ++ size+=len(common_regs) ++ size+=len(cp0_regs) ++ return size ++ ++def gen_print_head_and_macro(): ++ print("#include ") ++ print("#include ") ++ print("") ++ for s in cp0_regs: ++ print("#define %s\t%s,%s" %(s[0],s[1],s[2])) ++ print("") ++def gen_define_global_arg(str, num): ++ print("\t.data") ++ print("\t.global %s" %(str)) ++ print("%s:" %(str)) ++ print("\t.align 5") ++ print("\t.space %s,0" %(num)) ++ print("") ++ ++def gen_save_common_regs(index): ++ for s in common_regs: ++ print("\tsw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_restore_common_regs(index): ++ for s in common_regs: ++ print("\tlw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_save_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tmfc0\tk1,%s" % (s[0])) ++ print("\tsw\tk1,%d(k0)" % (index)) ++ index=index+4 ++ return index ++def gen_restore_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tlw\tk1,%d(k0)" % (index)) ++ print("\tmtc0\tk1,%s" % (s[0])) ++ index=index+4 ++ return index ++def gen_print_function(f_name, regs_stack): ++ index=0 ++ print("\t.text") ++ print("\t.global %s" %(f_name)) ++ print("\t.align 2") ++ print("\t.ent %s,0" %(f_name)) ++ print("\tLEAF(%s)" %(f_name)) ++ print("%s:" %(f_name)) ++ print("\t.set\tpush") ++ print("\t.set\tnoreorder") ++ print("\t.set\tnoat") ++ print("") ++ print("\tla\tk0, %s" %(regs_stack)) ++ if f_name == "save_goto": ++ index = gen_save_common_regs(index) ++ print("") ++ index = gen_save_cp0_regs(index) ++ print("") ++ print("\tjr.hb\ta0") ++ print("\tnop") ++ elif f_name == "restore_goto": ++ index = gen_restore_common_regs(index) ++ print("") ++ index = gen_restore_cp0_regs(index) ++ print("") ++ print("\tjr.hb\tra") ++ print("\tnop") ++ else: ++ print("not support") ++ print("") ++ print("\t.set\tat") ++ print("\t.set\treorder") ++ print("\t.set\tpop") ++ print("\tEND(%s)" %(f_name)) ++ ++ ++def main(): ++ regs_size=gen_get_array_size() ++ regs_size*=4 ++ ++ gen_print_head_and_macro() ++ gen_define_global_arg("_regs_stack", regs_size) ++ gen_print_function("save_goto", "_regs_stack") ++ print("") ++ gen_print_function("restore_goto", "_regs_stack") ++ pass ++ ++if __name__ == '__main__': ++ main() +diff --git a/arch/mips/xburst2/soc-m300/reset.c b/arch/mips/xburst2/soc-m300/reset.c +new file mode 100644 +index 000000000..e792ef140 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/reset.c +@@ -0,0 +1,327 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#define RTC_RTCCR (0x00) /* rw, 32, 0x00000081 */ ++#define RTC_RTCSR (0x04) /* rw, 32, 0x???????? */ ++#define RTC_RTCSAR (0x08) /* rw, 32, 0x???????? */ ++#define RTC_RTCGR (0x0c) /* rw, 32, 0x0??????? */ ++#define RTC_HCR (0x20) /* rw, 32, 0x00000000 */ ++#define RTC_HWFCR (0x24) /* rw, 32, 0x0000???0 */ ++#define RTC_HRCR (0x28) /* rw, 32, 0x00000??0 */ ++#define RTC_HWCR (0x2c) /* rw, 32, 0x00000008 */ ++#define RTC_HWRSR (0x30) /* rw, 32, 0x00000000 */ ++#define RTC_HSPR (0x34) /* rw, 32, 0x???????? */ ++#define RTC_WENR (0x3c) /* rw, 32, 0x00000000 */ ++#define RTC_CKPCR (0x40) /* rw, 32, 0x00000010 */ ++#define RTC_OWIPCR (0x44) /* rw, 32, 0x00000010 */ ++#define RTC_PWRONCR (0x48) /* rw, 32, 0x???????? */ ++ ++#define WDT_TCSR (0x0c) /* rw, 32, 0x???????? */ ++#define WDT_TCER (0x04) /* rw, 32, 0x???????? */ ++#define WDT_TDR (0x00) /* rw, 32, 0x???????? */ ++#define WDT_TCNT (0x08) /* rw, 32, 0x???????? */ ++ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++ ++#define RTCCR_WRDY BIT(7) ++#define WENR_WEN BIT(31) ++ ++#define RECOVERY_SIGNATURE (0x001a1a) ++#define REBOOT_SIGNATURE (0x003535) ++#define UNMSAK_SIGNATURE (0x7c0000)//do not use these bits ++ ++static void wdt_start_count(int msecs) ++{ ++ int time = JZ_EXTAL_RTC / 64 * msecs / 1000; ++ if(time > 65535) ++ time = 65535; ++ ++// outl(1 << 16,TCU_IOBASE + TCU_TSCR); ++ ++ outl(0,WDT_IOBASE + WDT_TCNT); //counter ++ outl(time,WDT_IOBASE + WDT_TDR); //data ++ outl((3<<3 | 2<<0 | 1 << 10),WDT_IOBASE + WDT_TCSR); ++ outl(0,WDT_IOBASE + WDT_TCER); ++ outl(1,WDT_IOBASE + WDT_TCER); ++} ++ ++static void __attribute__((unused)) wdt_stop_count(void) ++{ ++ outl(1 << 16,TCU_IOBASE + TCU_TSCR); ++ outl(0,WDT_IOBASE + WDT_TCNT); //counter ++ outl(65535,WDT_IOBASE + WDT_TDR); //data ++ outl(1 << 16,TCU_IOBASE + TCU_TSSR); ++} ++ ++static int inline rtc_write_reg(int reg,int value) ++{ ++ int timeout = 0x2000; ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY) && timeout--); ++ if(!timeout) ++ { ++ printk("WARN:NO USE RTC!!!!!\n"); ++ return -1; ++ } ++ outl(0xa55a,(RTC_IOBASE + RTC_WENR)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ while(!(inl(RTC_IOBASE + RTC_WENR) & WENR_WEN)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ outl(value,(RTC_IOBASE + reg)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ ++ return 0; ++} ++ ++/* ++ * Function: Keep power for CPU core when reset. ++ * So that EPC, tcsm and so on can maintain it's status after reset-key pressed. ++ */ ++static int inline reset_keep_power(void) ++{ ++ return rtc_write_reg(RTC_PWRONCR, ++ inl(RTC_IOBASE + RTC_PWRONCR) & ~(1 << 0)); ++} ++ ++#define HWFCR_WAIT_TIME(x) ((x > 0x7fff ? 0x7fff: (0x7ff*(x)) / 2000) << 5) ++#define HRCR_WAIT_TIME(x) ((((x) > 1875 ? 1875: (x)) / 125) << 11) ++ ++void jz_hibernate(void) ++{ ++ uint32_t rtc_rtccr; ++ ++ local_irq_disable(); ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ ++ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000)); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(125)); ++ ++ /* clear wakeup status register */ ++ rtc_write_reg(RTC_HWRSR, 0x0); ++ ++ rtc_write_reg(RTC_HWCR, 0x0); ++ ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ rtc_rtccr |= 0x1 << 0; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ /* Put CPU to hibernate mode */ ++ rtc_write_reg(RTC_HCR, 0x1); ++ ++ /*poweroff the pmu*/ ++// jz_notifier_call(NOTEFY_PROI_HIGH, JZ_POST_HIBERNATION, NULL); ++ ++ mdelay(200); ++ ++ while(1) ++ printk("%s:We should NOT come here.%08x\n",__func__, inl(RTC_IOBASE + RTC_HCR)); ++} ++ ++void jz_wdt_restart(char *command) ++{ ++ printk("Restarting after 4 ms\n"); ++ if ((command != NULL) && !strcmp(command, "recovery")) { ++ while(cpm_inl(CPM_CPPSR) != RECOVERY_SIGNATURE) { ++ printk("set RECOVERY_SIGNATURE\n"); ++ cpm_outl(0x5a5a,CPM_CPSPPR); ++ cpm_outl(RECOVERY_SIGNATURE,CPM_CPPSR); ++ cpm_outl(0x0,CPM_CPSPPR); ++ udelay(100); ++ } ++ } else { ++ cpm_outl(0x5a5a,CPM_CPSPPR); ++ cpm_outl(REBOOT_SIGNATURE,CPM_CPPSR); ++ cpm_outl(0x0,CPM_CPSPPR); ++ } ++ ++ wdt_start_count(4); ++ mdelay(200); ++ while(1) ++ printk("check wdt.\n"); ++} ++ ++static void hibernate_restart(void) ++{ ++ uint32_t rtc_rtcsr,rtc_rtccr; ++ ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ ++ rtc_rtcsr = inl(RTC_IOBASE + RTC_RTCSR); ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ ++ rtc_write_reg(RTC_RTCSAR,rtc_rtcsr + 5); ++ rtc_rtccr &= ~(1 << 4 | 1 << 1); ++ rtc_rtccr |= 0x3 << 2; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ /* Clear reset status */ ++ cpm_outl(0,CPM_RSR); ++ ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ ++ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000)); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(125)); ++ ++ /* clear wakeup status register */ ++ rtc_write_reg(RTC_HWRSR, 0x0); ++ ++ rtc_write_reg(RTC_HWCR, 0x1); ++ ++ ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ rtc_rtccr |= 0x1 << 0; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ ++ /* Put CPU to hibernate mode */ ++ rtc_write_reg(RTC_HCR, 0x1); ++ ++ mdelay(200); ++ while(1) ++ printk("%s:We should NOT come here.%08x\n",__func__, inl(RTC_IOBASE + RTC_HCR)); ++} ++ ++#ifdef CONFIG_HIBERNATE_RESET ++void jz_hibernate_restart(char *command) ++{ ++ local_irq_disable(); ++ ++ if ((command != NULL) && !strcmp(command, "recovery")) { ++ jz_wdt_restart(command); ++ } ++ ++ hibernate_restart(); ++} ++#endif ++ ++int __init reset_init(void) ++{ ++ pm_power_off = jz_hibernate; ++#ifdef CONFIG_HIBERNATE_RESET ++ _machine_restart = jz_hibernate_restart; ++#else ++ _machine_restart = jz_wdt_restart; ++#endif ++ return 0; ++} ++arch_initcall(reset_init); ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////// ++struct wdt_reset { ++ unsigned stop; ++ unsigned msecs; ++ unsigned count; ++}; ++ ++/* ============================reset proc=================================== */ ++static char *reset_command[] = {"wdt","hibernate","recovery", "poweroff"}; ++ ++static int reset_show(struct seq_file *filq, void *v) ++{ ++ int len = 0, i; ++ ++ for(i = 0; i < ARRAY_SIZE(reset_command); i++) ++ seq_printf(filq, "%s\t", reset_command[i]); ++ seq_printf(filq,"\n"); ++ ++ return len; ++} ++ ++static int reset_write(struct file *file, const char __user *buffer, ++ size_t usize, loff_t *off) ++{ ++ int command_size = 0; ++ int i; ++ ++ if(usize == 0) ++ return -EINVAL; ++ ++ command_size = ARRAY_SIZE(reset_command); ++ for(i = 0;i < command_size; i++) { ++ if(!strncmp(buffer, reset_command[i], strlen(reset_command[i]))) ++ break; ++ } ++ if(i == command_size) ++ return -EINVAL; ++ ++ local_irq_disable(); ++ switch(i) { ++ case 0: ++ jz_wdt_restart(NULL); ++ break; ++ case 1: ++ hibernate_restart(); ++ break; ++ case 2: ++ jz_wdt_restart("recovery"); ++ break; ++ case 3: ++ jz_hibernate(); ++ break; ++ default: ++ printk("not support command %d\n", i); ++ } ++ ++ return usize; ++} ++static struct jz_single_file_ops reset_proc_fops = { ++ .read = reset_show, ++ .write = reset_write, ++}; ++/* ============================reset proc end=============================== */ ++ ++static int __init init_reset(void) ++{ ++ struct wdt_reset *wdt; ++ struct proc_dir_entry *p, *res; ++ ++ wdt = kmalloc(sizeof(struct wdt_reset),GFP_KERNEL); ++ if(!wdt) { ++ return -ENOMEM; ++ } ++ ++ wdt->count = 0; ++ wdt->msecs = 3000; ++ ++ wdt->stop = 1; ++ ++ p = jz_proc_mkdir("reset"); ++ if (!p) { ++ printk("create_proc_entry for common reset failed.\n"); ++ return -ENODEV; ++ } ++ ++ res = jz_proc_create_data("reset", 0444, p, &reset_proc_fops, wdt); ++ ++ return 0; ++} ++module_init(init_reset); +diff --git a/arch/mips/xburst2/soc-m300/serial.c b/arch/mips/xburst2/soc-m300/serial.c +new file mode 100644 +index 000000000..563208c52 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/serial.c +@@ -0,0 +1,91 @@ ++/* ++ * JZ SOC serial routines for early_printk. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ */ ++ ++#include ++ ++#include ++ ++#define UART_BASE UART0_IOBASE ++#define UART_OFF 0x1000 ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++ ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++static void check_uart(char c); ++ ++volatile u8 *uart_base; ++typedef void (*putchar_f_t)(char); ++static putchar_f_t putchar_f = check_uart; ++ ++static void putchar(char ch) ++{ ++ int timeout = 10000; ++ volatile u8 *base = uart_base; ++ /* Wait for fifo to shift out some bytes */ ++ while ((base[OFF_LSR] & (LSR_TDRQ | LSR_TEMT)) ++ != (LSR_TDRQ | LSR_TEMT) && timeout--) ++ ; ++ base[OFF_TDR] = (u8)ch; ++} ++ ++static void putchar_dummy(char ch) ++{ ++ return; ++} ++ ++static void check_uart(char c) ++{ ++ /* We Couldn't use ioremap() here */ ++ volatile u8 *base = (volatile u8*)CKSEG1ADDR(UART0_IOBASE); ++ int i = 0; ++ for(i=0; i<10; i++) { ++ if(base[OFF_LCR]) ++ break; ++ base += UART_OFF; ++ } ++ ++ if(i<10) { ++ uart_base = base; ++ putchar_f = putchar; ++ putchar_f(c); ++ } else { ++ putchar_f = putchar_dummy; ++ } ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ putchar_f(c); ++} ++ ++void prom_putstr(char *s) ++{ ++ while(*s) { ++ if(*s == '\n') ++ putchar_f('\r'); ++ putchar_f(*s); ++ s++; ++ } ++} ++ ++#if 1 ++static char pbuffer[4096]; ++void prom_printk(const char *fmt, ...) { ++ va_list args; ++ ++ va_start(args, fmt); ++ vsnprintf(pbuffer, 4096, fmt, args); ++ va_end(args); ++ ++ prom_putstr(pbuffer); ++} ++#endif +diff --git a/arch/mips/xburst2/soc-m300/setup.c b/arch/mips/xburst2/soc-m300/setup.c +new file mode 100644 +index 000000000..c4d68f03b +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/setup.c +@@ -0,0 +1,84 @@ ++/* ++ * Ingenic Soc Setup ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++void __init cpm_reset(void) ++{ ++} ++ ++int __init setup_init(void) ++{ ++#if 0 ++ cpm_reset(); ++ /* Set bus priority here */ ++ *(volatile unsigned int *)0xb34f0240 = 0x00010003; ++ *(volatile unsigned int *)0xb34f0244 = 0x00010003; ++#endif ++ ++ return 0; ++} ++extern void __init init_all_clk(void); ++/* used by linux-mti code */ ++extern void *get_fdt_addr(void); ++void __init plat_mem_setup(void) ++{ ++ /* use IO_BASE, so that we can use phy addr on hard manual ++ * directly with in(bwlq)/out(bwlq) in io.h. ++ */ ++ set_io_port_base(IO_BASE); ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0xffffffff; ++ iomem_resource.start = 0x00000000; ++ iomem_resource.end = 0xffffffff; ++ setup_init(); ++ ++ __dt_setup_arch(get_fdt_addr()); ++ ++ return; ++} ++void __init device_tree_init(void) ++{ ++ unflatten_and_copy_device_tree(); ++} ++ ++static int __init plat_of_populate(void) ++{ ++ of_platform_default_populate(NULL, NULL, NULL); ++ return 0; ++} ++arch_initcall(plat_of_populate); ++ ++void __init plat_time_init(void) ++{ ++ of_clk_init(NULL); ++ ++ timer_probe(); ++} ++ ++void __init arch_init_irq(void) ++{ ++ irqchip_init(); ++} +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/Makefile b/arch/mips/xburst2/soc-m300/sleep_firmware/Makefile +new file mode 100644 +index 000000000..45222b254 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/Makefile +@@ -0,0 +1,42 @@ ++TOPDIR = . ++ ++CC = mips-linux-gnu-gcc ++LD = mips-linux-gnu-ld ++OBJCOPY = mips-linux-gnu-objcopy ++OBJDUMP = mips-linux-gnu-objdump ++drop-sections := .reginfo .mdebug .oomment .note .pdr .options .MIPS.options ++strip-flags := $(addprefix --remove-section=,$(drop-sections)) ++ ++CFLAGS += -I$(TOPDIR)/include ++CFLAGS += -nostdinc -Wall -Wundef -Werror-implicit-function-declaration \ ++ -fno-common -EL -Os -march=mips32 -mabi=32 -G 0 -mno-abicalls -fno-pic\ ++ -msoft-float ++ ++LDFLAGS := -nostdlib -EL -T target.ld ++OBJCOPY_ARGS := -O elf32-tradlittlemips ++ ++OBJS := $(TOPDIR)/src/fastboot_resume.o \ ++ $(TOPDIR)/src/uart.o ++ ++ ++all: $(TOPDIR)/firmware.bin ++ @hexdump -v -e '"0x" 1/4 "%08x" "," "\n"' $< > $(TOPDIR)/fastboot_resume_code.hex ++ ++$(TOPDIR)/firmware.bin:$(TOPDIR)/firmware.o ++ @$(LD) -nostdlib -EL -T $(TOPDIR)/target.ld $(OBJS) -Map $(TOPDIR)/fastboot.map -o $(TOPDIR)/fastboot.elf ++ @$(OBJCOPY) $(strip-flags) $(OBJCOPY_ARGS) -O binary $(TOPDIR)/fastboot.elf $@ ++ @$(OBJDUMP) $(TOPDIR)/fastboot.elf -D > fastboot.dump ++$(TOPDIR)/firmware.o:$(OBJS) ++ ++ ++%.o:%.c ++ $(CC) $(CFLAGS) -o $@ -c $^ ++ ++%.o:%.S ++ $(CC) $(CFLAGS) -o $@ -c $^ ++ ++clean: ++ find . -name "*.o" | xargs rm -vf ++ find . -name "*.o.cmd" | xargs rm -vf ++ rm *.dump *.map *.elf *.bin *.hex ++ +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/Readme b/arch/mips/xburst2/soc-m300/sleep_firmware/Readme +new file mode 100644 +index 000000000..215604c5a +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/Readme +@@ -0,0 +1,14 @@ ++ ++! this wakeup module is none of bussiness with the kernel. ++if you want to modify the code in the module. you should use ++the script mkmodule.sh right here. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/include/base.h b/arch/mips/xburst2/soc-m300/sleep_firmware/include/base.h +new file mode 100644 +index 000000000..b2eb14f02 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/include/base.h +@@ -0,0 +1,91 @@ ++ ++#ifndef __JZSOC_SOC_DEV_H__ ++#define __JZSOC_SOC_DEV_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++#define DDRC_BASE 0xb34f0000 ++#define DDRC_APB_OFFSET (-0x4e0000 + 0x2000) ++#define DDR_PHY_OFFSET (-0x4e0000 + 0x1000) ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 /* 64KB, AHB Bus Aribtier */ ++#define DDR_PHY_IOBASE 0x13011000 /* 4KB, DDR PHY */ ++#define DDRC_H0_IOBASE 0x13012000 /* 4KB, DDR Controller Registers@ASHB0 */ ++#define DPU_IOBASE 0x13050000 /* 64KB, LCD Controller */ ++#define CIM_IOBASE 0x13060000 /* 64KB, Camera Interface Module */ ++#define ROTATE_IOBASE 0x13070000 /* 64KB, Rotate DMA */ ++#define HELIX_IOBASE 0x13200000 /* 64KB VPU encoder */ ++#define FELIX_IOBASE 0x13300000 /* 64KB VPU decoder */ ++#define ISP0_IOBASE 0x13700000 /* 64KB Tiziano ISP0 */ ++#define ISP1_IOBASE 0x13800000 /* 64KB Tiziano ISP1 */ ++ ++/* AHB2 Bus Devices Base */ ++#define HARB2_IOBASE 0x13400000 /* 64KB, AHB Bus Arbiter */ ++#define NEMC_IOBASE 0x13410000 /* 64KB, External Normal Memory/Boot ROM/OTP Controller */ ++#define PDMA_IOBASE 0x13420000 /* 64KB, Programmable DMA Controller */ ++#define AES_IOBASE 0x13430000 /* 64KB, AES */ ++#define SFC_IOBASE 0x13440000 /* 64KB, SPI Flash Controller */ ++#define MSC0_IOBASE 0x13450000 /* 64KB, MMC SD Controller0 */ ++#define MSC1_IOBASE 0x13460000 /* 64KB, MMC SD Controller1 */ ++#define MSC2_IOBASE 0x13490000 /* 64KB, MMC SD Controller2 */ ++#define HASH_IOBASE 0x13470000 /* 64KB, HASH */ ++#define RSA_IOBASE 0x13480000 /* 64KB, RSA */ ++#define MAC0_IOBASE 0x134b0000 /* 64KB, GMAC/MAC */ ++#define MAC1_IOBASE 0x134a0000 /* 64KB, GMAC/MAC */ ++#define PWM_IOBASE 0x134c0000 /* 64KB, PWM */ ++#define DDRC_H2_IOBASE 0x134f0000 /* 4KB, DDR Controller Register @AHB2 */ ++#define AUDIO_IOBASE 0x134d0000 /* 64KB, Aduio System */ ++#define OTG_IOBASE 0x13500000 /* 256KB, OTG2.0 Controller */ ++#define EFUSE_IOBASE 0x13540000 /* 64KB, EFUSE */ ++//#define INTC_IOBASE 0x13600000 /* Interrupt Controller */ ++ ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 /* 4KB, Clocks and Power Manager */ ++#define TCU_IOBASE 0x10002000 /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++#define WDT_IOBASE TCU_IOBASE /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++#define RTC_IOBASE 0x10003000 /* 4KB, Real-Time Clock */ ++#define GPIO_IOBASE 0x10010000 /* 4KB, General-Purpose I/O */ ++#define CODEC_IOBASE 0x10020000 /* 4KB, icodec I/O */ ++#define UART0_IOBASE 0x10030000 /* 4KB, UART0 Controller */ ++#define UART1_IOBASE 0x10031000 /* 4KB, UART1 Controller */ ++#define UART2_IOBASE 0x10032000 /* 4KB, UART2 Controller */ ++#define UART3_IOBASE 0x10033000 /* 4KB, UART3 Controller */ ++#define UART4_IOBASE 0x10034000 /* 4KB, UART4 Controller */ ++#define UART5_IOBASE 0x10035000 /* 4KB, UART5 Controller */ ++#define UART6_IOBASE 0x10036000 /* 4KB, UART6 Controller */ ++#define UART7_IOBASE 0x10037000 /* 4KB, UART7 Controller */ ++#define UART8_IOBASE 0x10038000 /* 4KB, UART8 Controller */ ++#define UART9_IOBASE 0x10039000 /* 4KB, UART9 Controller */ ++#define SCC_IOBASE 0x10040000 /* 4KB, Smart Card Controller */ ++#define SSI0_IOBASE 0x10043000 /* 4KB, Synchronous Serial Interface */ ++#define SSI1_IOBASE 0x10044000 /* 4KB, Synchronous Serial Interface */ ++#define I2C0_IOBASE 0x10050000 /* 4KB, I2C 0 Bus Interface */ ++#define I2C1_IOBASE 0x10051000 /* 4KB, I2C 1 Bus Interface */ ++#define I2C2_IOBASE 0x10052000 /* 4KB, I2C 2 Bus Interface */ ++#define I2C3_IOBASE 0x10053000 /* 4KB, I2C 3 Bus Interface */ ++#define I2C4_IOBASE 0x10054000 /* 4KB, I2C 4 Bus Interface */ ++#define I2C5_IOBASE 0x10055000 /* 4KB, I2C 5 Bus Interface */ ++#define SADC_IOBASE 0x10070000 /* 4KB, SADC */ ++#define DTRNG_IOBASE 0x10072000 /* 4KB, DTRNG */ ++#define MIPI_RX_2_IOBASE 0x10073000 /* 4KB, MIPI RX 2 Lane ctrl */ ++#define MIPI_RX_4_IOBASE 0x10074000 /* 4KB, MIPI RX 4 lane ctrl */ ++#define MIPI_TX_2_IOBASE 0x10075000 /* 4KB, MIPI TX 2 lane ctrl */ ++#define MIPI_RX_PHY_IOBASE 0x10076000 /* 4KB, MIPI RX PHY */ ++#define MIPI_TX_PHY_IOBASE 0x10077000 /* 4KB, MIPI TX PHY */ ++#define USB_PHY_IOBASE 0x10078000 /* 4KB, USB PHY */ ++ ++/* TODO: Others To Be add */ ++/* NAND CHIP Base Address */ ++#define NEMC_CS1_IOBASE 0X1b000000 ++#define NEMC_CS2_IOBASE 0X1a000000 ++#define NEMC_CS3_IOBASE 0X19000000 ++#define NEMC_CS4_IOBASE 0X18000000 ++#define NEMC_CS5_IOBASE 0X17000000 ++#define NEMC_CS6_IOBASE 0X16000000 ++ ++#define OST_IOBASE 0x12000000 ++ ++#endif +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/include/cpm.h b/arch/mips/xburst2/soc-m300/sleep_firmware/include/cpm.h +new file mode 100755 +index 000000000..495e3a4b1 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/include/cpm.h +@@ -0,0 +1,230 @@ ++/* ++ * X2000 CPM register definition ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __CPM_H__ ++#define __CPM_H__ ++ ++#define BIT0 (1 << 0) ++#define BIT1 (1 << 1) ++#define BIT2 (1 << 2) ++#define BIT3 (1 << 3) ++#define BIT4 (1 << 4) ++#define BIT5 (1 << 5) ++#define BIT6 (1 << 6) ++#define BIT7 (1 << 7) ++#define BIT8 (1 << 8) ++#define BIT9 (1 << 9) ++#define BIT10 (1 << 10) ++#define BIT11 (1 << 11) ++#define BIT12 (1 << 12) ++#define BIT13 (1 << 13) ++#define BIT14 (1 << 14) ++#define BIT15 (1 << 15) ++#define BIT16 (1 << 16) ++#define BIT17 (1 << 17) ++#define BIT18 (1 << 18) ++#define BIT19 (1 << 19) ++#define BIT20 (1 << 20) ++#define BIT21 (1 << 21) ++#define BIT22 (1 << 22) ++#define BIT23 (1 << 23) ++#define BIT24 (1 << 24) ++#define BIT25 (1 << 25) ++#define BIT26 (1 << 26) ++#define BIT27 (1 << 27) ++#define BIT28 (1 << 28) ++#define BIT29 (1 << 29) ++#define BIT30 (1 << 30) ++#define BIT31 (1 << 31) ++ ++/* ++ * Clock reset and power controller module(CPM) address definition ++ */ ++#define CPM_BASE 0xB0000000 ++ ++/* ++ * CPM registers offset address definition ++ */ ++#define CPM_CPCCR (0x00) ++#define CPM_RSR (0x08) ++#define CPM_RSACDR (0x50) ++#define CPM_CLKGR0 (0x20) ++#define CPM_OPCR (0x24) ++#define CPM_CLKGR1 (0x28) ++#define CPM_DDRCDR (0x2c) ++#define CPM_USBPCR (0x3c) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0xA4) ++#define CPM_MSC4CDR (0xA8) ++#define CPM_SFCCDR (0x74) ++#define CPM_CPCSR (0xd4) ++#define CPM_SLBC (0xc8) ++#define CPM_SLPC (0xcc) ++#define CPM_CPPCR (0x0c) ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++#define CPM_EXCLK_DS (0xE0) ++ ++/* ++ * CPM registers common define ++ */ ++/* Reset status register(RSR) */ ++#define RSR_P0R BIT2 ++#define RSR_WR BIT1 ++#define RSR_PR BIT0 ++ ++/* Clk Gate Register (CLKGR0) */ ++#define CLKGR0_DDR BIT31 ++#define CLKGR0_RSA BIT25 ++#define CLKGR0_AES BIT24 ++#define CLKGR0_PDMA BIT21 ++#define CLKGR0_OST BIT20 ++#define CLKGR0_TCU BIT18 ++#define CLKGR0_UART2 BIT16 ++#define CLKGR0_UART1 BIT15 ++#define CLKGR0_UART0 BIT14 ++#define CLKGR0_MSC1 BIT5 ++#define CLKGR0_MSC0 BIT4 ++#define CLKGR0_OTG BIT3 ++#define CLKGR0_SFC BIT2 ++#define CLKGR0_EFUSE BIT1 ++ ++/* Clk Gate Register (CLKGR1) */ ++#define CLKGR1_MSC4 BIT25 ++#define CLKGR1_HASH BIT6 ++ ++/* Msc Device Clock Divider Register (MSCnCDR) */ ++#define MSCCDR_DIV_LSB 0 ++#define MSCCDR_DIV_MASK BITS_H2L(7, MSCCDR_DIV_LSB) ++ ++#define MSCCDR_MPCS_LSB 30 ++#define MSCCDR_MPCS_MASK BITS_H2L(31, MSCCDR_MPCS_LSB) ++#define MSCCDR_MPCS_EXCLK (0x2 << MSCCDR_MPCS_LSB) ++ ++#define MSCCDR_BUSY BIT28 ++#define MSCCDR_CE BIT29 ++#define MSCCDR_EXCK_E BIT21 ++ ++/* Sleep Pc Register (SLPC) */ ++#define SLPC_SW_MAGIC 0x425753 // SWB (software boot) ++#define SLPC_SW_USB_BOOT (0x2 << 0) ++ ++/* APLL Control Register (CPAPCR) */ ++#define CPAPCR_PLLFD_LSB 20 ++#define CPAPCR_PLLFD_MASK BITS_H2L(28, CPAPCR_PLLFD_LSB) ++ ++#define CPAPCR_PLLRD_LSB 14 ++#define CPAPCR_PLLRD_MASK BITS_H2L(19, CPAPCR_PLLRD_LSB) ++ ++#define CPAPCR_PLLOD_LSB 11 ++#define CPAPCR_PLLOD_MASK BITS_H2L(13, CPAPCR_PLLOD_LSB) ++ ++#define CPAPCR_PLLRG_LSB 5 ++#define CPAPCR_PLLRG_MASK BITS_H2L(7, CPAPCR_PLLRG_LSB) ++ ++#define CPAPCR_PLL_ON BIT3 ++#define CPAPCR_PLL_LOCK BIT2 ++#define CPAPCR_PLL_EN BIT0 ++ ++/* EXCLK_DS MSC VOL SELECT */ ++#define EXCLKDS_POC_MSC BIT31 ++ ++ ++#define cpm_readl(o) readl(CPM_BASE + (o)) ++#define cpm_writel(b, o) writel(b, CPM_BASE + (o)) ++ ++ ++#define __cpm_start_sfc() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_SFC; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++#define __cpm_start_msc() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~(CLKGR0_MSC0 | CLKGR0_MSC1); \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ tmp = cpm_readl(CPM_CLKGR1); \ ++ tmp &= ~CLKGR1_MSC4; \ ++ cpm_writel(tmp, CPM_CLKGR1); \ ++ } while (0) ++#define __cpm_start_otg() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_OTG; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++ ++#define __cpm_start_uart0() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_UART0; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++#define __cpm_start_uart1() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_UART1; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++#define __cpm_start_uart2() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_UART2; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++#define __cpm_start_ost() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_OST; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++ ++#define __cpm_msc4_vol_1_8V() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_EXCLK_DS); \ ++ tmp |= EXCLKDS_POC_MSC; \ ++ cpm_writel(tmp, CPM_EXCLK_DS); \ ++ } while (0) ++ ++#define __cpm_msc4_vol_3_3V() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_EXCLK_DS); \ ++ tmp &= ~EXCLKDS_POC_MSC; \ ++ cpm_writel(tmp, CPM_EXCLK_DS); \ ++ } while (0) ++ ++#ifdef FPGA_TEST ++#define __cpm_msc_tuning_set(v, n) \ ++ do { \ ++ unsigned int tmp; \ ++ unsigned int off; \ ++ if(n==0) \ ++ off = CPM_MSC0CDR; \ ++ else if(n==4) \ ++ off = CPM_MSC4CDR; \ ++ else \ ++ off = CPM_MSC1CDR; \ ++ tmp = cpm_readl(off); \ ++ tmp &= ~(1 << 20); \ ++ tmp |= ((v) & 0x1) << 20; \ ++ cpm_writel(tmp, off); \ ++ } while (0) ++#endif ++ ++#endif /* __CPM_H__ */ +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/include/ddr.h b/arch/mips/xburst2/soc-m300/sleep_firmware/include/ddr.h +new file mode 100644 +index 000000000..241da4607 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/include/ddr.h +@@ -0,0 +1,289 @@ ++/* ++ * JZ4780 ddr definitions ++ * ++ * Copyright (c) 2013 Ingenic Semiconductor Co.,Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++ ++#ifndef __DDR_H__ ++#define __DDR_H__ ++ ++#include ++ ++/* ++ * DDR Controller Registers ++ **/ ++#define DDR_MEM_PHY_BASE 0x20000000 ++ ++#define DDRC_STATUS 0x0 ++#define DDRC_CFG 0x8 ++#define DDRC_CTRL 0x10 ++#define DDRC_LMR 0x18 ++#define DDRC_DLP 0x20 ++#define DDRC_AUTOSR_EN 0x28 ++#define DDRC_AUTOSR_CNT 0x30 ++#define DDRC_REFCNT 0x38 ++#define DDRC_DBGINFO 0xE8 ++#define DDRC_TIMING(n) (0x40 + 8 * (n - 1)) ++#define DDRC_MMAP0 0x78 ++#define DDRC_MMAP1 0x80 ++#define DDRC_HREGPRO 0xd8 ++#define DDRC_DWCFG (DDRC_APB_OFFSET + 0x00) ++#define DDRC_DWSTATUS (DDRC_APB_OFFSET + 0x04) ++#define DDRC_REMAP(n) (DDRC_APB_OFFSET + 0x08 + 4 * (n - 1)) ++#define DDRC_CGUC0 (DDRC_APB_OFFSET + 0x64) ++#define DDRC_CGUC1 (DDRC_APB_OFFSET + 0x68) ++#define DDRC_PREGPRO (DDRC_APB_OFFSET + 0x6c) ++ ++/* ++ * DDR Innophy registers ++ * */ ++#define DDRP_INNOPHY_PHY_RST (DDR_PHY_OFFSET + 0x000) ++#define DDRP_INNOPHY_MEM_CFG (DDR_PHY_OFFSET + 0x004) ++#define DDRP_INNOPHY_DQ_WIDTH (DDR_PHY_OFFSET + 0x07c) ++#define DDRP_INNOPHY_CL (DDR_PHY_OFFSET + 0x014) ++#define DDRP_INNOPHY_CWL (DDR_PHY_OFFSET + 0x01c) ++#define DDRP_INNOPHY_AL (DDR_PHY_OFFSET + 0x018) ++#define DDRP_INNOPHY_PLL_FBDIV (DDR_PHY_OFFSET + 0x080) ++#define DDRP_INNOPHY_PLL_CTRL (DDR_PHY_OFFSET + 0x084) ++#define DDRP_INNOPHY_PLL_PDIV (DDR_PHY_OFFSET + 0x088) ++#define DDRP_INNOPHY_PLL_LOCK (DDR_PHY_OFFSET + 0xc8) ++#define DDRP_INNOPHY_TRAINING_CTRL (DDR_PHY_OFFSET + 0x008) ++#define DDRP_INNOPHY_CALIB_DONE (DDR_PHY_OFFSET + 0xcc) ++#define DDRP_INNOPHY_CALIB_DELAY_AL (DDR_PHY_OFFSET + 0x190) ++#define DDRP_INNOPHY_CALIB_DELAY_AH (DDR_PHY_OFFSET + 0x194) ++#define DDRP_INNOPHY_CALIB_BYPASS_AL (DDR_PHY_OFFSET + 0x118) ++#define DDRP_INNOPHY_CALIB_BYPASS_AH (DDR_PHY_OFFSET + 0x158) ++#define DDRP_INNOPHY_WL_MODE1 (DDR_PHY_OFFSET + 0x00c) ++#define DDRP_INNOPHY_WL_MODE2 (DDR_PHY_OFFSET + 0x010) ++#define DDRP_INNOPHY_WL_DONE (DDR_PHY_OFFSET + 0x0c0) ++#define DDRP_INNOPHY_INIT_COMP (DDR_PHY_OFFSET + 0x0d0) ++ ++ ++/* ++ * DDRC REGISTER BITS DEFINE ++ * */ ++ ++/* DDRC Status Register */ ++#define DDRC_DSTATUS_MISS (1 << 6) ++#define DDRC_ST_DPDN (1 << 5) /* 0 DDR memory is NOT in deep-power-down state ++ 1 DDR memory is in deep-power-down state */ ++#define DDRC_ST_PDN (1 << 4) /* 0 DDR memory is NOT in power-down state ++ 1 DDR memory is in power-down state */ ++#define DDRC_ST_AREF (1 << 3) /* 0 DDR memory is NOT in auto-refresh state ++ 1 DDR memory is in auto-refresh state */ ++#define DDRC_ST_SREF (1 << 2) /* 0 DDR memory is NOT in self-refresh state ++ 1 DDR memory is in self-refresh state */ ++#define DDRC_ST_CKE1 (1 << 1) /* 0 CKE1 Pin is low ++ 1 CKE1 Pin is high */ ++#define DDRC_ST_CKE0 (1 << 0) /* 0 CKE0 Pin is low ++ 1 CKE0 Pin is high */ ++ ++/* DDRC Configure Register */ ++#define DDRC_CFG_ROW1_BIT 29 /* Row Address width. */ ++#define DDRC_CFG_ROW1_MASK (0x7 << DDRC_CFG_ROW1_BIT) ++#define DDRC_CFG_COL1_BIT 26 /* Row Address width. */ ++#define DDRC_CFG_COL1_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA1 25 /* Bank Address width of DDR memory */ ++#define DDRC_CFG_IMBA (1 << 16) ++#define DDRC_CFG_ROW0_BIT 13 /* Row Address width. */ ++#define DDRC_CFG_ROW0_MASK (0x7 << DDRC_CFG_ROW0_BIT) ++#define DDRC_CFG_COL0_BIT 10 /* Row Address width. */ ++#define DDRC_CFG_COL0_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA0 9 /* Bank Address width of DDR memory */ ++ ++#define DDRC_CFG_TYPE_BIT 3 ++#define DDRC_CFG_TYPE_MASK (0x7 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR1 (2 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_MDDR (3 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR2 (4 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR2 (5 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR3 (6 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR3 (7 << DDRC_CFG_TYPE_BIT) ++ ++#define DDRC_CFG_ODTEN (1 << 2) /* ODT EN */ ++#define DDRC_CFG_CS1EN (1 << 1) /* DDR Chip-Select-1 Enable */ ++#define DDRC_CFG_CS0EN (1 << 0) /* DDR Chip-Select-0 Enable */ ++ ++/* DDRC Control Register */ ++#define DDRC_CTRL_DFI_RST (1 << 23) ++#define DDRC_CTRL_DLL_RST (1 << 22) ++#define DDRC_CTRL_CTL_RST (1 << 21) ++#define DDRC_CTRL_CFG_RST (1 << 20) ++#define DDRC_CTRL_ACTPD (1 << 15) /* 0 Precharge all banks before entering power-down ++ 1 Do not precharge banks before entering power-down */ ++#define DDRC_CTRL_PDT_BIT 12 /* Power-Down Timer */ ++#define DDRC_CTRL_PDT_MASK (0x7 << DDRC_CTRL_PDT_BIT) ++#define DDRC_CTRL_PDT_DIS (0 << DDRC_CTRL_PDT_BIT) /* power-down disabled */ ++#define DDRC_CTRL_PDT_8 (1 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 8 tCK idle */ ++#define DDRC_CTRL_PDT_16 (2 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 16 tCK idle */ ++#define DDRC_CTRL_PDT_32 (3 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 32 tCK idle */ ++#define DDRC_CTRL_PDT_64 (4 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 64 tCK idle */ ++#define DDRC_CTRL_PDT_128 (5 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 128 tCK idle */ ++ ++#define DDRC_CTRL_PD_CCE (1 << 7) /* Power down clk freq change enable */ ++#define DDRC_CTRL_DPD (1 << 6) /* 1 Drive external MDDR device entering Deep-Power-Down mode */ ++#define DDRC_CTRL_SR (1 << 5) /* 1 Drive external DDR device entering self-refresh mode ++ 0 Drive external DDR device exiting self-refresh mode */ ++#define DDRC_CTRL_SR_CCE (1 << 4) /* Self refresh clk stop request enable */ ++#define DDRC_CTRL_CKE (1 << 1) /* 0 Not set CKE Pin High, 1 Set CKE Pin HIGH */ ++#define DDRC_CTRL_RESET (1 << 0) /* 0 End resetting ddrc_controller, 1 Resetting ddrc_controller */ ++ ++/* DDRC DFI low power handshake control register */ ++#define DDRC_DDLP_TCTLUDP_BIT 24 ++#define DDRC_DDLP_TCTLUDP_FF (0xff << DDRC_DDLP_TCTLUDP_BIT) ++ ++/* DDRC Load-Mode-Register */ ++#define DDRC_LMR_DDR_ADDR_BIT 12 /* When performing a DDR command, DDRC_ADDR[13:0] ++ corresponding to external DDR address Pin A[13:0] */ ++#define DDRC_LMR_DDR_ADDR_MASK (0xfffff << DDRC_LMR_DDR_ADDR_BIT) ++ ++#define DDRC_LMR_MA_BIT 16 /* FOR LPDDR2, MA[9:0] */ ++#define DDRC_LMR_OP_BIT 24 /* FOR LPDDR2, OP[9:0] */ ++ ++#define DDRC_LMR_BA_BIT 9 /* When performing a DDR command, BA[2:0] ++ corresponding to external DDR address Pin BA[2:0]. */ ++#define DDRC_LMR_BA_MASK (0x7 << DDRC_LMR_BA_BIT) ++#define DDRC_LMR_CMD_BIT 6 ++#define DDRC_LMR_CMD_MASK (0x7 << DDRC_LMR_CMD_BIT) ++#define DDRC_LMR_CMD_PREC (0 << DDRC_LMR_CMD_BIT)/* Precharge one bank/All banks */ ++#define DDRC_LMR_CMD_AUREF (1 << DDRC_LMR_CMD_BIT)/* Auto-Refresh */ ++#define DDRC_LMR_CMD_LMR (2 << DDRC_LMR_CMD_BIT)/* Load Mode Register */ ++#define DDRC_LMR_CMD_ZQCL_CS0 (3 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCL_CS1 (4 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS1 */ ++#define DDRC_LMR_CMD_ZQCS_CS0 (5 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCS_CS1 (6 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS1 */ ++ ++#define DDRC_LMR_TMRD_BIT 1 ++#define DDRC_LMR_TMRD_MASK (0x1f << DDRC_LMR_TMRD_BIT) ++#define DDRC_LMR_START (1 << 0) /* 0 No command is performed ++ 1 On the posedge of START, perform a command ++ defined by CMD field */ ++ ++/* DDRC Auto-Refresh Counter */ ++#define DDRC_REFCNT_REF_EN (1 << 0) /* Enable Refresh Counter */ ++#define DDRC_REFCNT_CLK_DIV_BIT 1 /* Clock Divider for auto-refresh counter. */ ++#define DDRC_REFCNT_CLK_DIV_MASK (0x7 << DDRC_REFCNT_CLKDIV_BIT) ++ ++#define DDRC_REFCNT_PREREF_CNT_BIT 4 ++#define DDRC_REFCNT_PREREF_CNT_MASK (0xf << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT(val) (val << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT_DEFAULT DDRC_REFCNT_PREREF_CNT(8) ++ ++#define DDRC_REFCNT_CNT_BIT 8 /* 8-bit counter */ ++#define DDRC_REFCNT_CNT_MASK (0xff << DDRC_REFCNT_CNT_BIT) ++ ++#define DDRC_REFCNT_CON_BIT 16 /* Constant value used to compare with CNT value. */ ++#define DDRC_REFCNT_CON_MASK (0xff << DDRC_REFCNT_CON_BIT) ++ ++#define DDRC_REFCNT_TRFC_BIT 24 ++#define DDRC_REFCNT_TRFC_MASK (0x3f << DDRC_REFCNT_TRFC_BIT) ++ ++#define DDRC_REFCNT_PREREF_EN_BIT 30 ++#define DDRC_REFCNT_PREREF_EN (1 << DDRC_REFCNT_PREREF_EN_BIT) ++ ++#define DDRC_REFCNT_PBREF_EN_BIT 31 ++#define DDRC_REFCNT_PBREF_EN (1 << DDRC_REFCNT_PBREF_EN_BIT) ++ ++/* DDRC Memory Map Config Register */ ++#define DDRC_MMAP_BASE_BIT 8 /* base address */ ++#define DDRC_MMAP_BASE_MASK (0xff << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP_MASK_BIT 0 /* address mask */ ++#define DDRC_MMAP_MASK_MASK (0xff << DDRC_MMAP_MASK_BIT) ++ ++#define DDRC_MMAP0_BASE (0x20 << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP1_BASE_64M (0x24 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_128M (0x28 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_256M (0x30 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++ ++#define DDRC_MMAP_MASK_64_64 (0xfc << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_128_128 (0xf8 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_256_256 (0xf0 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++ ++/* DDR device data width configure register */ ++#define DDRC_DWCFG_DFI_INIT_START (1 << 3) ++ ++/* DDR device status register */ ++#define DDRC_DWSTATUS_DFI_INIT_COMP (1 << 0) ++ ++/* DDRC AHB Bus Register Protection Register */ ++#define DDRC_HREGPRO_HPRO_EN (1 << 0) ++ ++/* DDRC APB Bus Register Protection Register */ ++#define DDRC_PREGPRO_PPRO_EN (1 << 0) ++ ++ ++/* DDRC clock gate unit configure 0 */ ++#define DDRC_CGU_PORT7 (1 << 28) ++#define DDRC_CGU_PORT6 (1 << 24) ++#define DDRC_CGU_PORT5 (1 << 20) ++#define DDRC_CGU_PORT4 (1 << 16) ++#define DDRC_CGU_PORT3 (1 << 12) ++#define DDRC_CGU_PORT2 (1 << 8) ++#define DDRC_CGU_PORT1 (1 << 4) ++#define DDRC_CGU_PORT0 (1 << 0) ++ ++/* DDRC clock gate unit configure 1 */ ++#define DDRC_CGU_BWM (1 << 8) ++#define DDRC_CGU_PCTRL (1 << 4) ++#define DDRC_CGU_SCH (1 << 1) ++#define DDRC_CGU_PA (1 << 0) ++ ++ ++ ++/* ++ * DDR INNOPHY REGISTER BITS DEFINE ++ * */ ++ ++/* DDRP DQ Width Register */ ++#define DDRP_DQ_WIDTH_DQ_H (1 << 1) ++#define DDRP_DQ_WIDTH_DQ_L (1 << 0) ++ ++/* DDRP Pll Ctrl Register */ ++#define DDRP_PLL_CTRL_PLLPDEN (1 << 1) ++ ++/* DDRP Training Ctrl Register */ ++#define DDRP_TRAINING_CTRL_WL_BP (1 << 3) ++#define DDRP_TRAINING_CTRL_WL_START (1 << 2) ++#define DDRP_TRAINING_CTRL_DSCSE_BP (1 << 1) ++#define DDRP_TRAINING_CTRL_DSACE_START (1 << 0) ++ ++/* DDRP Training Done Register */ ++#define DDRP_CALIB_DONE_HDQCFB (1 << 3) ++#define DDRP_CALIB_DONE_LDQCFB (1 << 2) ++#define DDRP_CALIB_DONE_HDQCFA (1 << 1) ++#define DDRP_CALIB_DONE_LDQCFA (1 << 0) ++#define DDRP_CALIB_DONE_HWRLFB (1 << 3) ++#define DDRP_CALIB_DONE_LWRLFB (1 << 2) ++#define DDRP_CALIB_DONE_HWRLFA (1 << 1) ++#define DDRP_CALIB_DONE_LWRLFA (1 << 0) ++ ++/* DDRP CALIB BP Register */ ++#define DDRP_CALIB_BP_CYCLESELBH_BIT 4 ++#define DDRP_CALIB_BP_OPHCSELBH_BIT 3 ++#define DDRP_CALIB_BP_DLLSELBH_BIT 0 ++ ++/* DDRP Init Complete Register */ ++#define DDRP_INIT_COMP (1 << 0) ++ ++#define DDRP_PLL_LOCK (1 << 3) ++ ++#define REG32(addr) *(volatile unsigned int *)(addr) ++ ++#define ddr_writel(value, reg) (REG32(DDRC_BASE + reg) = (value)) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++#endif /* __DDR_H__ */ +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/include/gpio.h b/arch/mips/xburst2/soc-m300/sleep_firmware/include/gpio.h +new file mode 100755 +index 000000000..8440f2a91 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/include/gpio.h +@@ -0,0 +1,267 @@ ++/* ++ * ++ * X2000 GPIO register definition. ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++/* check */ ++ ++#ifndef __GPIO_H__ ++#define __GPIO_H__ ++ ++ ++/************************************************************************* ++ * GPIO (General-Purpose I/O Ports) ++ *************************************************************************/ ++#define GPIO_BASE 0xB0010000 ++ ++#define GPA(x) (32 * 0 + (x)) ++#define GPB(x) (32 * 1 + (x)) ++#define GPC(x) (32 * 2 + (x)) ++#define GPD(x) (32 * 3 + (x)) ++#define GPE(x) (32 * 4 + (x)) ++#define GPF(x) (32 * 5 + (x)) ++ ++#define GPIO_PORT_NUM 6 ++#define MAX_GPIO_NUM 192 ++#define GPIO_WAKEUP GPF(31) //WAKE_UP key PF31 ++ ++//n = 0,1,2,3,4 (PORTA, PORTB, PORTC, PORTD, PORTE) ++#define GPIO_PXPIN(n) (0x00 + (n) * 0x100) /* PIN Level Register */ ++ ++#define GPIO_PXINT(n) (0x10 + (n) * 0x100) /* Port Interrupt Register */ ++#define GPIO_PXINTS(n) (0x14 + (n) * 0x100) /* Port Interrupt Set Register */ ++#define GPIO_PXINTC(n) (0x18 + (n) * 0x100) /* Port Interrupt Clear Register */ ++ ++#define GPIO_PXMASK(n) (0x20 + (n) * 0x100) /* Port Interrupt Mask Register */ ++#define GPIO_PXMASKS(n) (0x24 + (n) * 0x100) /* Port Interrupt Mask Set Reg */ ++#define GPIO_PXMASKC(n) (0x28 + (n) * 0x100) /* Port Interrupt Mask Clear Reg */ ++ ++#define GPIO_PXPAT1(n) (0x30 + (n) * 0x100) /* Port Pattern 1 Register */ ++#define GPIO_PXPAT1S(n) (0x34 + (n) * 0x100) /* Port Pattern 1 Set Reg. */ ++#define GPIO_PXPAT1C(n) (0x38 + (n) * 0x100) /* Port Pattern 1 Clear Reg. */ ++ ++#define GPIO_PXPAT0(n) (0x40 + (n) * 0x100) /* Port Pattern 0 Register */ ++#define GPIO_PXPAT0S(n) (0x44 + (n) * 0x100) /* Port Pattern 0 Set Register */ ++#define GPIO_PXPAT0C(n) (0x48 + (n) * 0x100) /* Port Pattern 0 Clear Register */ ++ ++#define GPIO_PXFLG(n) (0x50 + (n) * 0x100) /* Port Flag Register */ ++#define GPIO_PXFLGC(n) (0x58 + (n) * 0x100) /* Port Flag clear Register */ ++ ++#define GPIO_PXPU(n) (0x80 + (n) * 0x100) /* PORT PULL-UP State Register */ ++#define GPIO_PXPUS(n) (0x84 + (n) * 0x100) /* PORT PULL-UP State Set Register*/ ++#define GPIO_PXPUC(n) (0x88 + (n) * 0x100) /* PORT PULL-UP State Clear Register */ ++ ++#define GPIO_PXPD(n) (0x90 + (n) * 0x100) /* PORT PULL-DOWN State Register */ ++#define GPIO_PXPDS(n) (0x94 + (n) * 0x100) /* PORT PULL-DOWN State Set Register */ ++#define GPIO_PXPDC(n) (0x98 + (n) * 0x100) /* PORT PULL-DOWN State Set Register */ ++ ++#define gpio_readl(o) readl(GPIO_BASE + (o)) ++#define gpio_writel(b, o) writel(b, GPIO_BASE + (o)) ++ ++#ifndef __MIPS_ASSEMBLER ++ ++/*---------------------------------------------------------------- ++ * p is the port number (0,1,2,3,4,5) ++ * o is the pin offset (0-31) inside the port ++ * n is the absolute number of a pin (0-127), regardless of the port ++ */ ++ ++//---------------------------------------------------------------- ++/* ++ * Gpio Pull set ++ */ ++#define __gpio_set_hiz(v, p) \ ++do { \ ++ unsigned long val = v; \ ++ gpio_writel(val, GPIO_PXPUC(p)); \ ++ gpio_writel(val, GPIO_PXPDC(p)); \ ++} while (0) ++ ++/* ++ * UART0_TxD, UART0_RxD, PD27 ++ */ ++#define __gpio_as_uart0() \ ++do { \ ++ gpio_writel((3 << 23), GPIO_PXINTC(3)); \ ++ gpio_writel((3 << 23), GPIO_PXMASKC(3));\ ++ gpio_writel((3 << 23), GPIO_PXPAT1S(3));\ ++ gpio_writel((3 << 23), GPIO_PXPAT0C(3));\ ++} while (0) ++ ++/* ++ * UART1_TxD, UART1_RxD, PA23 ++ */ ++#define __gpio_as_uart1() \ ++do { \ ++ gpio_writel((3 << 23), GPIO_PXINTC(2)); \ ++ gpio_writel((3 << 23), GPIO_PXMASKC(2)); \ ++ gpio_writel((3 << 23), GPIO_PXPAT1C(2)); \ ++ gpio_writel((3 << 23), GPIO_PXPAT0S(2)); \ ++} while (0) ++ ++/* ++ * UART2_TxD, UART2_RxD ++ */ ++#define __gpio_as_uart2() \ ++do { \ ++ gpio_writel((3 << 30), GPIO_PXINTC(3)); \ ++ gpio_writel((3 << 30), GPIO_PXMASKC(3));\ ++ gpio_writel((3 << 30), GPIO_PXPAT1C(3));\ ++ gpio_writel((3 << 30), GPIO_PXPAT0C(3));\ ++} while (0) ++ ++/* ++ * CS2#, RD#, WR#, WAIT#, A0 ~ A5 ++ * @n: chip select number(1 ~ 4) ++ */ ++#define __gpio_as_nor(n) \ ++do { \ ++ gpio_writel((0x7 << 13), GPIO_PXINTC(1)); \ ++ gpio_writel((0x7 << 13), GPIO_PXMASKC(1)); \ ++ gpio_writel((0x7 << 13), GPIO_PXPAT1C(1)); \ ++ gpio_writel((0x7 << 13), GPIO_PXPAT0C(1)); \ ++ gpio_writel((0x3 << 23), GPIO_PXINTC(2)); \ ++ gpio_writel((0x3 << 23), GPIO_PXMASKC(2)); \ ++ gpio_writel((0x3 << 23), GPIO_PXPAT1S(2)); \ ++ gpio_writel((0x3 << 23), GPIO_PXPAT0S(2)); \ ++} while (0) ++/* ++ * D0 ~ D7 ++ */ ++#define __gpio_as_nor_8bit() \ ++do { \ ++ gpio_writel((0xffffffff), GPIO_PXINTC(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXMASKC(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXPAT1C(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXPAT0C(1)); \ ++} while (0) ++ ++/* ++ * D0 ~ D15 ++ */ ++#define __gpio_as_nor_16bit() \ ++do { \ ++ gpio_writel((0xffffffff), GPIO_PXINTC(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXMASKC(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXPAT1C(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXPAT0C(1)); \ ++} while (0) ++ ++ ++/* gpio as sfc disable pull */ ++/* PE16 - PE21 */ ++#define __gpio_as_3_3V_sfc() \ ++do { \ ++ gpio_writel((0x3f << 16), GPIO_PXINTC(4)); \ ++ gpio_writel((0x3f << 16), GPIO_PXMASKC(4)); \ ++ gpio_writel((0x3f << 16), GPIO_PXPAT1C(4)); \ ++ gpio_writel((0x3f << 16), GPIO_PXPAT0C(4)); \ ++ if(!EFUSE_SWC_SFC) \ ++ __gpio_set_hiz((0x3f) << 16, 4); \ ++} while (0) ++ ++/* gpio as sfc disable pull */ ++/* PD17 - PD22 */ ++#define __gpio_as_1_8V_sfc() \ ++do { \ ++ gpio_writel((0x3f << 17), GPIO_PXINTC(3)); \ ++ gpio_writel((0x3f << 17), GPIO_PXMASKC(3)); \ ++ gpio_writel((0x3f << 17), GPIO_PXPAT1C(3)); \ ++ gpio_writel((0x3f << 17), GPIO_PXPAT0S(3)); \ ++ if(!EFUSE_SWC_SFC) \ ++ __gpio_set_hiz((0x3f) << 17, 3); \ ++} while (0) ++ ++/* ++ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D7 ++ */ ++ ++/* pull disable */ ++ ++/* PD17 - PD26, func0, 1bit*/ ++#define __gpio_as_msc0_1bit() \ ++do { \ ++ gpio_writel(0x7 << 17, GPIO_PXINTC(3)); \ ++ gpio_writel(0x7 << 17, GPIO_PXMASKC(3)); \ ++ gpio_writel(0x7 << 17, GPIO_PXPAT1C(3)); \ ++ gpio_writel(0x7 << 17, GPIO_PXPAT0C(3)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x7 << 17), 3); \ ++} while (0) ++ ++/* PD17 - PD26, func0, 4bit*/ ++#define __gpio_as_msc0_4bit() \ ++do { \ ++ gpio_writel(0x3f << 17, GPIO_PXINTC(3)); \ ++ gpio_writel(0x3f << 17, GPIO_PXMASKC(3)); \ ++ gpio_writel(0x3f << 17, GPIO_PXPAT1C(3)); \ ++ gpio_writel(0x3f << 17, GPIO_PXPAT0C(3)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x3f << 17), 3); \ ++} while (0) ++ ++ ++/* PD08 - PD13, func0, 1bit*/ ++#define __gpio_as_msc1_1bit() \ ++do { \ ++ gpio_writel(0x7 << 8, GPIO_PXINTC(3)); \ ++ gpio_writel(0x7 << 8, GPIO_PXMASKC(3)); \ ++ gpio_writel(0x7 << 8, GPIO_PXPAT1C(3)); \ ++ gpio_writel(0x7 << 8, GPIO_PXPAT0C(3)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x7 << 8), 3); \ ++} while (0) ++ ++/* PD08 - PD13, func0, 4bit*/ ++#define __gpio_as_msc1_4bit() \ ++do { \ ++ gpio_writel(0x3f << 8, GPIO_PXINTC(3)); \ ++ gpio_writel(0x3f << 8, GPIO_PXMASKC(3)); \ ++ gpio_writel(0x3f << 8, GPIO_PXPAT1C(3)); \ ++ gpio_writel(0x3f << 8, GPIO_PXPAT0C(3)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x3f << 8), 3); \ ++} while (0) ++ ++ ++/* PE0 - PE5, func0 */ ++#define __gpio_as_msc4_1bit() \ ++do { \ ++ gpio_writel((0x7 << 0), GPIO_PXINTC(4)); \ ++ gpio_writel((0x7 << 0), GPIO_PXMASKC(4)); \ ++ gpio_writel((0x7 << 0), GPIO_PXPAT1C(4)); \ ++ gpio_writel((0x7 << 0), GPIO_PXPAT0C(4)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x7) << 0, 4); \ ++} while (0) ++ ++/* PE0 - PE5, func0 */ ++#define __gpio_as_msc4_4bit() \ ++do { \ ++ gpio_writel((0x3f << 0), GPIO_PXINTC(4)); \ ++ gpio_writel((0x3f << 0), GPIO_PXMASKC(4)); \ ++ gpio_writel((0x3f << 0), GPIO_PXPAT1C(4)); \ ++ gpio_writel((0x3f << 0), GPIO_PXPAT0C(4)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x3f) << 0, 4); \ ++} while (0) ++ ++#define bootsel_gpio_init() \ ++do{ \ ++ gpio_writel((0x7 << 25), GPIO_PXINTC(4)); \ ++ gpio_writel((0x7 << 25), GPIO_PXMASKS(4));\ ++ gpio_writel((0x7 << 25), GPIO_PXPAT1S(4));\ ++ gpio_writel((0x7 << 25), GPIO_PXPAT0C(4));\ ++ __gpio_set_hiz((0x7) << 25, 4); \ ++}while(0) ++ ++#define boot_select() ((gpio_readl(GPIO_PXPIN(4)) >> 25) & 0x7) ++ ++#define BOOT_SELECT_3_3V (0) ++#define BOOT_SELECT_1_8V (1) ++#endif /* __MIPS_ASSEMBLER */ ++ ++#endif /* __GPIO_H__ */ ++ +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/include/pm_fastboot.h b/arch/mips/xburst2/soc-m300/sleep_firmware/include/pm_fastboot.h +new file mode 100644 +index 000000000..1151e77a2 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/include/pm_fastboot.h +@@ -0,0 +1,187 @@ ++ ++ ++#define RTC_SLEEP_MEMORY_START 0xb0004000 ++#define RTC_SLEEP_MEMORY_END 0xb0005000 ++#define RTC_RAM_SP_ADDR (RTC_RAM_DATA_ADDR - 4) ++//#define RTC_RAM_SP_SIZE (256 - 4) ++#define RTC_RAM_DATA_ADDR 0xb0004c00 ++#define RTC_RAM_DATA_SIZE 1024 ++#define RTC_RAM_CODE_ADDR1 0xb0004000 ++#define RTC_RAM_CODE_ADDR2 (RTC_RAM_CODE_ADDR1 + 64) ++#define RTC_RAM_CODE_SIZE 0xb00 ++ ++#define SLEEP_CPU_SLEEP_TEXT 0xb2400000 ++#define SLEEP_CPU_SLEEP_LEN 4096 ++ ++ ++ ++struct pll_resume_reg { ++ unsigned int cpccr; ++ unsigned int cppcr; ++ unsigned int cpapcr; ++ unsigned int cpmpcr; ++ unsigned int cpepcr; ++ unsigned int ddrcdr; ++}; ++ ++struct ddrc_resume_reg { ++ unsigned int dcfg; ++ unsigned int dctrl; ++ unsigned int dlmr; ++ unsigned int ddlp; ++ unsigned int dasr_en; ++ unsigned int dasr_cnt; ++ unsigned int drefcnt; ++ unsigned int dtimming1; ++ unsigned int dtimming2; ++ unsigned int dtimming3; ++ unsigned int dtimming4; ++ unsigned int dtimming5; ++ unsigned int dmmap0; ++ unsigned int dmmap1; ++ unsigned int dbwcfg; ++ unsigned int dbwstp; ++ unsigned int hregpro; ++ unsigned int dbgen; ++ unsigned int dwcfg; ++ unsigned int dremap1; ++ unsigned int dremap2; ++ unsigned int dremap3; ++ unsigned int dremap4; ++ unsigned int dremap5; ++ unsigned int cpac; ++ unsigned int cchc0; ++ unsigned int cchc1; ++ unsigned int cchc2; ++ unsigned int cchc3; ++ unsigned int cchc4; ++ unsigned int cchc5; ++ unsigned int cchc6; ++ unsigned int cchc7; ++ unsigned int cschc0; ++ unsigned int cschc1; ++ unsigned int cschc2; ++ unsigned int cschc3; ++ unsigned int cmonc0; ++ unsigned int cmonc1; ++ unsigned int cmonc2; ++ unsigned int cmonc3; ++ unsigned int cmonc4; ++ unsigned int ccguc0; ++ unsigned int ccguc1; ++ unsigned int pregpro; ++ unsigned int bufcfg; ++}; ++ ++struct ddr_phy_resume_reg { ++ unsigned int phy_rst; ++ unsigned int mem_cfg; ++ unsigned int dq_width; ++ unsigned int cl; ++ unsigned int al; ++ unsigned int cwl; ++ unsigned int pll_fbdiv; ++ unsigned int pll_ctrl; ++ unsigned int pll_pdiv; ++ unsigned int training_ctrl; ++ unsigned int calib_bypass_al; ++ unsigned int calib_bypass_ah; ++ unsigned int wl_mode1; ++ unsigned int wl_mode2; ++ ++}; ++ ++struct store_regs { ++ unsigned int resume_pc; ++ unsigned int uart_index; ++ struct pll_resume_reg pll_resume_reg; ++ struct ddrc_resume_reg ddrc_resume_reg; ++ struct ddr_phy_resume_reg ddr_phy_resume_reg; ++}; ++ ++ ++ ++ ++#define DDR_PHY_OFFSET (-0x4e0000 + 0x1000) ++#define DDRP_INNOPHY_RXDLL_DELAY_AL (DDR_PHY_OFFSET + (0x48 << 2)) ++#define DDRP_INNOPHY_RXDLL_DELAY_AH (DDR_PHY_OFFSET + (0x58 << 2)) ++ ++#define REG32(addr) *(volatile unsigned int *)(addr) ++#define ddr_writel(value, reg) (REG32(DDRC_BASE + reg) = (value)) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++ ++ ++ ++static void rtc_write_reg(unsigned int reg, unsigned int val) ++{ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ *(volatile unsigned int *)0xb000303c = 0xa55a; ++ while (!((*(volatile unsigned int *)0xb000303c >> 31) & 0x1) ); ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ ++ *(volatile unsigned int *)reg = val; ++ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++} ++ ++static unsigned int rtc_read_reg(unsigned int reg) ++{ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ ++ return *(volatile unsigned int *)reg; ++} ++ ++ ++#define FASTBOOT_DEBUG ++ ++#ifdef FASTBOOT_DEBUG ++ ++#include ++ ++extern unsigned int get_uart_index(void); ++ ++void DEBUG(const char *s) ++{ ++ serial_puts(get_uart_index(), s); ++} ++ ++void DEBUG_HEX(unsigned int d) ++{ ++ serial_put_hex(get_uart_index(), d); ++} ++ ++ ++#define GPIO_PULSE() \ ++ while (1) { \ ++ *(volatile unsigned int *)0xb0010218 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010224 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010238 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010248 = (1 << 20); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ *(volatile unsigned int *)0xb0010218 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010224 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010238 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010244 = (1 << 20); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ } ++ ++ ++#else ++#define DEBUG(s) ++#define DEBUG_HEX(a) ++#endif ++ +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/include/uart.h b/arch/mips/xburst2/soc-m300/sleep_firmware/include/uart.h +new file mode 100755 +index 000000000..b87b2d236 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/include/uart.h +@@ -0,0 +1,113 @@ ++/* ++ * ++ * X2000 UART register definition. ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __UART_H__ ++#define __UART_H__ ++ ++#define readb(addr) (*(volatile unsigned char *)(addr)) ++#define readw(addr) (*(volatile unsigned short *)(addr)) ++#define readl(addr) (*(volatile unsigned int *)(addr)) ++#define writeb(b, addr) (*(volatile unsigned char *)(addr)) = (b) ++#define writew(b, addr) (*(volatile unsigned short *)(addr)) = (b) ++#define writel(b, addr) (*(volatile unsigned int *)(addr)) = (b) ++ ++void serial_init(int); ++void serial_puts(int, const char *); ++void serial_put_hex(int, unsigned int); ++ ++ ++#define UART0_BASE 0xB0030000 ++ ++/************************************************************************* ++ * UART ++ *************************************************************************/ ++ ++#define UART_BASE UART0_BASE ++#define UART_OFF 0x1000 ++ ++/* Register Offset */ ++#define OFF_RDR(n) ((n) * UART_OFF + 0x00) /* R 8b H'xx */ ++#define OFF_TDR(n) ((n) * UART_OFF + 0x00) /* W 8b H'xx */ ++#define OFF_DLLR(n) ((n) * UART_OFF + 0x00) /* RW 8b H'00 */ ++#define OFF_DLHR(n) ((n) * UART_OFF + 0x04) /* RW 8b H'00 */ ++#define OFF_IER(n) ((n) * UART_OFF + 0x04) /* RW 8b H'00 */ ++#define OFF_ISR(n) ((n) * UART_OFF + 0x08) /* R 8b H'01 */ ++#define OFF_FCR(n) ((n) * UART_OFF + 0x08) /* W 8b H'00 */ ++#define OFF_LCR(n) ((n) * UART_OFF + 0x0C) /* RW 8b H'00 */ ++#define OFF_MCR(n) ((n) * UART_OFF + 0x10) /* RW 8b H'00 */ ++#define OFF_LSR(n) ((n) * UART_OFF + 0x14) /* R 8b H'00 */ ++#define OFF_MSR(n) ((n) * UART_OFF + 0x18) /* R 8b H'00 */ ++#define OFF_SPR(n) ((n) * UART_OFF + 0x1C) /* RW 8b H'00 */ ++#define OFF_SIRCR(n) ((n) * UART_OFF + 0x20) /* RW 8b H'00, UART0 */ ++#define OFF_UMR(n) ((n) * UART_OFF + 0x24) /* RW 8b H'00, UART M Register */ ++#define OFF_UACR(n) ((n) * UART_OFF + 0x28) /* RW 8b H'00, UART Add Cycle Register */ ++#define OFF_URCR(n) ((n) * UART_OFF + 0x40) /* R 8b 00, UART RXFIFO Counter Register */ ++#define OFF_UTCR(n) ((n) * UART_OFF + 0x44) /* R 8b 00, UART TXFIFO Counter Register */ ++ ++/* ++ * Define macros for UARTFCR ++ * UART FIFO Control Register ++ */ ++#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */ ++#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */ ++#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */ ++#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */ ++#define UARTFCR_UUE (1 << 4) /* 0: disable UART */ ++#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */ ++#define UARTFCR_RTRG_1 (0 << 6) ++#define UARTFCR_RTRG_16 (1 << 6) ++#define UARTFCR_RTRG_32 (2 << 6) ++#define UARTFCR_RTRG_60 (3 << 6) ++ ++/* ++ * Define macros for UARTLCR ++ * UART Line Control Register ++ */ ++#define UARTLCR_WLEN (3 << 0) /* word length */ ++#define UARTLCR_WLEN_5 (0 << 0) ++#define UARTLCR_WLEN_6 (1 << 0) ++#define UARTLCR_WLEN_7 (2 << 0) ++#define UARTLCR_WLEN_8 (3 << 0) ++#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 ++ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ ++#define UARTLCR_STOP1 (0 << 2) ++#define UARTLCR_STOP2 (1 << 2) ++#define UARTLCR_PE (1 << 3) /* 0: parity disable */ ++#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */ ++#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */ ++#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */ ++#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */ ++ ++/* ++ * Define macros for SIRCR ++ * Slow IrDA Control Register ++ */ ++#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: SIR mode */ ++#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: SIR mode */ ++#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length ++ 1: 0 pulse width is 1.6us for 115.2Kbps */ ++#define SIRCR_TDPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */ ++#define SIRCR_RDPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */ ++ ++/* ++ * Define macros for UART_LSR ++ * UART Line Status Register ++ */ ++#define UART_LSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */ ++#define UART_LSR_ORER (1 << 1) /* 0: no overrun error */ ++#define UART_LSR_PER (1 << 2) /* 0: no parity error */ ++#define UART_LSR_FER (1 << 3) /* 0; no framing error */ ++#define UART_LSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */ ++#define UART_LSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */ ++#define UART_LSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */ ++#define UART_LSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */ ++ ++#define uart_readl(o) readl(UART_BASE + (o)) ++#define uart_writel(b, o) writel(b, UART_BASE + (o)) ++ ++#endif /* __UART_H__ */ ++ +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/mkmodule.sh b/arch/mips/xburst2/soc-m300/sleep_firmware/mkmodule.sh +new file mode 100755 +index 000000000..698e07160 +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/mkmodule.sh +@@ -0,0 +1,7 @@ ++#!/bin/sh ++ ++make clean ++ ++make ++ ++cp fastboot_resume_code.hex ../ +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/src/fastboot_resume.c b/arch/mips/xburst2/soc-m300/sleep_firmware/src/fastboot_resume.c +new file mode 100644 +index 000000000..a5debf77e +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/src/fastboot_resume.c +@@ -0,0 +1,314 @@ ++#include ++#include ++ ++ ++ ++static struct store_regs *store_regs; ++ ++ ++void sys_clk_restore(void) ++{ ++ unsigned int tmp; ++ struct pll_resume_reg *pll_resume_reg; ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ ++ pll_resume_reg = &store_regs->pll_resume_reg; ++ ++ tmp = *(volatile unsigned int *)0xb0000000; ++ ++ tmp &= ~(7 << 20); ++ tmp |= (pll_resume_reg->cpccr & 0x000fffff); ++ *(volatile unsigned int *)0xb0000000 = tmp; ++ *(volatile unsigned int *)0xb0000000 |= (7 << 20); ++ while ((*(volatile unsigned int *)0xb00000d4) & 0x7); ++ ++ tmp = *(volatile unsigned int *)0xb0000000; ++ tmp &= ~(0xff << 24); ++ tmp |= (pll_resume_reg->cpccr & 0xff000000); ++ *(volatile unsigned int *)0xb0000000 = tmp; ++ ++ ++ while (!((*(volatile unsigned int *)0xb00000d4 & 0xf0000000) == 0xf0000000)); ++ ++} ++ ++ ++static void pll_restore(void) ++{ ++ struct pll_resume_reg *pll_resume_reg; ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ ++ pll_resume_reg = &store_regs->pll_resume_reg; ++ ++ *(volatile unsigned int *)0xb000000c = pll_resume_reg->cppcr; ++ ++ *(volatile unsigned int *)0xb0000010 = (pll_resume_reg->cpapcr & 0xfffffff0) | 1; ++ while (!((*(volatile unsigned int *)0xb0000010 >> 3) & 1)); ++ ++ *(volatile unsigned int *)0xb0000014 = (pll_resume_reg->cpmpcr & 0xfffffff0) | 1; ++ while (!((*(volatile unsigned int *)0xb0000014 >> 3) & 1)); ++ ++ *(volatile unsigned int *)0xb0000018 = (pll_resume_reg->cpepcr & 0xfffffff0) | 1; ++ while (!((*(volatile unsigned int *)0xb0000018 >> 3) & 1)); ++ ++ ++ *(volatile unsigned int *)0xb000002c = (pll_resume_reg->ddrcdr & 0xc000000f); ++ *(volatile unsigned int *)0xb000002c |= (1 << 29); ++ while (((*(volatile unsigned int *)0xb000002c) >> 28) & 1); ++ ++ sys_clk_restore(); ++} ++ ++ ++ ++static void phy_pll_init(struct ddr_phy_resume_reg *ddr_phy_resume_reg) ++{ ++ *(volatile unsigned int *)0xb3011084 |= (1 << 1); ++ ++ *(volatile unsigned int *)0xb3010080 &= ~0xff; ++ *(volatile unsigned int *)0xb3011080 |= ddr_phy_resume_reg->pll_fbdiv; ++ ++ *(volatile unsigned int *)0xb3010088 &= ~0xff; ++ *(volatile unsigned int *)0xb3011088 |= ddr_phy_resume_reg->pll_pdiv; ++ ++ *(volatile unsigned int *)0xb3010084 &= ~3; ++ *(volatile unsigned int *)0xb3011084 |= (ddr_phy_resume_reg->pll_ctrl & 0x1); ++ ++ *(volatile unsigned int *)0xb3011084 &= ~(1 << 1); //enable pll ++ ++ while(!(*(volatile unsigned int *)0xb30110c8 & (1 << 3))); //wait pll lock ++} ++ ++static void phy_cfg(struct ddr_phy_resume_reg *ddr_phy_resume_reg) ++{ ++ *(volatile unsigned int *)0xb3011004 = ddr_phy_resume_reg->mem_cfg; ++ *(volatile unsigned int *)0xb301107c = ddr_phy_resume_reg->dq_width; ++ *(volatile unsigned int *)0xb3011014 = ddr_phy_resume_reg->cl; ++ *(volatile unsigned int *)0xb3011018 = ddr_phy_resume_reg->al; ++ *(volatile unsigned int *)0xb301101c = ddr_phy_resume_reg->cwl; ++} ++ ++ ++ ++static void dfi_init(struct ddrc_resume_reg *ddrc_resume_reg) ++{ ++ *(volatile unsigned int *)0xb3012000 &= ~(1 << 3); //dfi_init_start = 0 ++ while(!(*(volatile unsigned int *)0xb3012004 & 0x1)); //wait dfi_init_compllete ++ *(volatile unsigned int *)0xb34f0008 = ddrc_resume_reg->dcfg; ++ ++} ++ ++ ++static void ddrc_init(struct ddrc_resume_reg *ddrc_resume_reg) ++{ ++ *(volatile unsigned int *)0xb34f0040 = ddrc_resume_reg->dtimming1; ++ *(volatile unsigned int *)0xb34f0048 = ddrc_resume_reg->dtimming2; ++ *(volatile unsigned int *)0xb34f0050 = ddrc_resume_reg->dtimming3; ++ *(volatile unsigned int *)0xb34f0058 = ddrc_resume_reg->dtimming4; ++ *(volatile unsigned int *)0xb34f0060 = ddrc_resume_reg->dtimming5; ++ *(volatile unsigned int *)0xb34f0078 = ddrc_resume_reg->dmmap0; ++ *(volatile unsigned int *)0xb34f0080 = ddrc_resume_reg->dmmap1; ++ *(volatile unsigned int *)0xb34f0038 = ddrc_resume_reg->drefcnt; ++ *(volatile unsigned int *)0xb34f0010 = ddrc_resume_reg->dctrl; ++ ++ *(volatile unsigned int *)0xb3012008 = ddrc_resume_reg->dremap1; ++ *(volatile unsigned int *)0xb301200c = ddrc_resume_reg->dremap2; ++ *(volatile unsigned int *)0xb3012010 = ddrc_resume_reg->dremap3; ++ *(volatile unsigned int *)0xb3012014 = ddrc_resume_reg->dremap4; ++ *(volatile unsigned int *)0xb3012018 = ddrc_resume_reg->dremap5; ++ ++ *(volatile unsigned int *)0xb3012000 &= ~0x3; ++ *(volatile unsigned int *)0xb3012000 |= ddrc_resume_reg->dwcfg & 0x3; ++ ++ ++ *(volatile unsigned int *)0xb34f0088 = ddrc_resume_reg->dbwcfg; ++ *(volatile unsigned int *)0xb34f0090 = ddrc_resume_reg->dbwstp; ++ *(volatile unsigned int *)0xb34f00d8 = ddrc_resume_reg->hregpro; ++ *(volatile unsigned int *)0xb34f00e0 = ddrc_resume_reg->dbgen; ++ *(volatile unsigned int *)0xb301201c = ddrc_resume_reg->cpac; ++ *(volatile unsigned int *)0xb3012020 = ddrc_resume_reg->cchc0; ++ *(volatile unsigned int *)0xb3012024 = ddrc_resume_reg->cchc1; ++ *(volatile unsigned int *)0xb3012028 = ddrc_resume_reg->cchc2; ++ *(volatile unsigned int *)0xb301202c = ddrc_resume_reg->cchc3; ++ *(volatile unsigned int *)0xb3012030 = ddrc_resume_reg->cchc4; ++ *(volatile unsigned int *)0xb3012034 = ddrc_resume_reg->cchc5; ++ *(volatile unsigned int *)0xb3012038 = ddrc_resume_reg->cchc6; ++ *(volatile unsigned int *)0xb301203c = ddrc_resume_reg->cchc7; ++ *(volatile unsigned int *)0xb3012040 = ddrc_resume_reg->cschc0; ++ *(volatile unsigned int *)0xb3012044 = ddrc_resume_reg->cschc1; ++ *(volatile unsigned int *)0xb3012048 = ddrc_resume_reg->cschc2; ++ *(volatile unsigned int *)0xb301204c = ddrc_resume_reg->cschc3; ++ *(volatile unsigned int *)0xb3012050 = ddrc_resume_reg->cmonc0; ++ *(volatile unsigned int *)0xb3012054 = ddrc_resume_reg->cmonc1; ++ *(volatile unsigned int *)0xb3012058 = ddrc_resume_reg->cmonc2; ++ *(volatile unsigned int *)0xb301205c = ddrc_resume_reg->cmonc3; ++ *(volatile unsigned int *)0xb3012060 = ddrc_resume_reg->cmonc4; ++ *(volatile unsigned int *)0xb301206c = ddrc_resume_reg->pregpro; ++ *(volatile unsigned int *)0xb3012070 = ddrc_resume_reg->bufcfg ; ++ ++ ++} ++ ++static void ddr_lp_restore(struct ddrc_resume_reg *ddrc_resume_reg) ++{ ++ *(volatile unsigned int *)0xb34f0020 = ddrc_resume_reg->ddlp; ++ *(volatile unsigned int *)0xb34f0030 = ddrc_resume_reg->dasr_en; ++ *(volatile unsigned int *)0xb34f0028 = ddrc_resume_reg->dasr_cnt; ++ ++} ++ ++static void ddrp_auto_calibration(void) ++{ ++ unsigned int reg_val = ddr_readl(DDRP_INNOPHY_TRAINING_CTRL); ++ unsigned int timeout = 0xffffff; ++ unsigned int wait_cal_done = DDRP_CALIB_DONE_HDQCFA | DDRP_CALIB_DONE_LDQCFA; ++ ++ reg_val &= ~(DDRP_TRAINING_CTRL_DSCSE_BP); ++ reg_val |= DDRP_TRAINING_CTRL_DSACE_START; ++ ddr_writel(reg_val, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ while(!((ddr_readl(DDRP_INNOPHY_CALIB_DONE) & wait_cal_done) == wait_cal_done) && --timeout) { ++ DEBUG("t"); ++ } ++ ++ if(!timeout) { ++ DEBUG("f"); ++ } ++ ddr_writel(0, DDRP_INNOPHY_TRAINING_CTRL); ++ ++} ++ ++static void ddr_init(void) ++{ ++ struct ddrc_resume_reg *ddrc_resume_reg; ++ struct ddr_phy_resume_reg *ddr_phy_resume_reg; ++ ++ unsigned int ddrc_ctrl; ++ volatile unsigned int tmp; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ ddrc_resume_reg = &store_regs->ddrc_resume_reg; ++ ddr_phy_resume_reg = &store_regs->ddr_phy_resume_reg; ++ ++ ++// *(volatile unsigned int *)0xb34f0010 = (0x1 << 20); //phy reset ++ phy_cfg(ddr_phy_resume_reg); ++// *(volatile unsigned int *)0xb34f0010 &= ~(0x1 << 20); ++ ++ phy_pll_init(ddr_phy_resume_reg); ++ dfi_init(ddrc_resume_reg); ++ ddrc_init(ddrc_resume_reg); ++ ++ *(volatile unsigned int *)0xb34f0030 = 0; ++ *(volatile unsigned int *)0xb34f0028 = 0; ++ ++ ++ { ++ ddrc_ctrl = *(volatile unsigned int *)0xb34f0010; ++ ++ /* bufferen_core = 1 */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp |= (1 << 21); ++ rtc_write_reg(0xb0003048, tmp); ++ ++ /* exit ddr self refresh */ ++ ddrc_ctrl &= ~(1<<5); ++ ddrc_ctrl |= 1 << 1; ++ *(volatile unsigned int*)0xb34f0010 = ddrc_ctrl; ++ ++ while((*(volatile unsigned int *)0xb34f0000) & (1<<2)); ++ } ++ ++ ++ DEBUG("ddr restore finish\n"); ++ ++ ddrp_auto_calibration(); ++ ++ ++ ddr_lp_restore(ddrc_resume_reg); ++ ++ ++} ++ ++ ++ ++static unsigned int get_resume_pc(void) ++{ ++ unsigned int resume_pc; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ resume_pc = store_regs->resume_pc; ++ ++ return resume_pc; ++} ++ ++unsigned int get_uart_index(void) ++{ ++ unsigned int uart_index; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ uart_index = store_regs->uart_index; ++ ++ return uart_index; ++} ++ ++ ++ ++ ++void fastboot_restore_code_2(void) ++{ ++ unsigned int resume_pc; ++ unsigned int uart_index; ++ ++ uart_index = get_uart_index(); ++#ifdef FASTBOOT_DEBUG ++ serial_init(uart_index); ++ DEBUG_HEX(uart_index); ++#endif ++ ++ resume_pc = get_resume_pc(); ++ DEBUG_HEX(resume_pc); ++ ++ DEBUG("fastboot begin restore\n"); ++ ++ pll_restore(); ++ DEBUG("pll restore ok\n"); ++ ++ ddr_init(); ++ ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "sync \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (resume_pc) ++ : ++ ); ++ ++} ++ ++ ++__attribute__((section(".resume"))) void fastboot_restore_code_1(void) ++{ ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set noreorder \n\t" ++ ".set mips32r2 \n\t" ++ "move $29, %0 \n\t" ++ "jr.hb %1 \n\t" ++ "nop \n\t" ++ ".set reorder \n\t" ++ ".set pop \n\t" ++ : ++ :"r" (RTC_RAM_SP_ADDR), "r"(fastboot_restore_code_2) ++ : ++ ); ++ ++} ++ ++ +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/src/uart.c b/arch/mips/xburst2/soc-m300/sleep_firmware/src/uart.c +new file mode 100644 +index 000000000..abb6a82ac +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/src/uart.c +@@ -0,0 +1,97 @@ ++#include ++#include ++#include ++ ++static void serial_putc (int num, const char c) ++{ ++ if (c == '\n') ++ serial_putc (num, '\r'); ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ( !((uart_readl(OFF_LSR(num)) & (UART_LSR_TDRQ | UART_LSR_TEMT)) == 0x60) ); ++ ++ uart_writel((unsigned char)c, OFF_TDR(num)); ++} ++ ++static void serial_setbrg(int num) ++{ ++ unsigned int baud_div, tmp; ++ ++ uart_writel(16, OFF_UMR(num)); ++ uart_writel(0, OFF_UACR(num)); ++ baud_div = 13; ++ ++ tmp = uart_readl(OFF_LCR(num)); ++ tmp |= UARTLCR_DLAB; ++ uart_writel(tmp, OFF_LCR(num)); ++ ++ uart_writel((baud_div >> 8) & 0xff, OFF_DLHR(num)); ++ uart_writel(baud_div & 0xff, OFF_DLLR(num)); ++ ++ tmp &= ~UARTLCR_DLAB; ++ uart_writel(tmp, OFF_LCR(num)); ++} ++ ++void serial_init(int num) ++{ ++ switch(num){ ++ case 0: ++ __gpio_as_uart0(); ++ __cpm_start_uart0(); ++ break; ++ case 2: ++ __gpio_as_uart2(); ++ __cpm_start_uart2(); ++ break; ++ case 1: ++ default: ++ __gpio_as_uart1(); ++ __cpm_start_uart1(); ++ break; ++ } ++ ++ uart_writel(0, OFF_SPR(num)); ++ uart_writel(0, OFF_MCR(num)); ++ ++ /* Disable port interrupts while changing hardware */ ++ uart_writel(0, OFF_IER(num)); ++ ++ /* Disable UART unit function */ ++ uart_writel(~UARTFCR_UUE, OFF_FCR(num)); ++ ++ /* Set both receiver and transmitter in UART mode (not SIR) */ ++ uart_writel(~(SIRCR_RSIRE | SIRCR_TSIRE), OFF_SIRCR(num)); ++ ++ /* Set databits, stopbits and parity. (8-bit data, 1 stopbit, no parity) */ ++ uart_writel(UARTLCR_WLEN_8 & ~(UARTLCR_STOP2), OFF_LCR(num)); ++ ++ serial_setbrg(num); ++ ++ /* Enable UART unit, enable and clear FIFO */ ++ uart_writel(UARTFCR_UUE | UARTFCR_TFLS | UARTFCR_RFLS | UARTFCR_FE, OFF_FCR(num)); ++ ++} ++ ++void serial_puts (int num, const char *s) ++{ ++ while (*s) { ++ serial_putc (num, *s++); ++ } ++} ++ ++void serial_put_hex(int num, unsigned int d) ++{ ++ char c[12]; ++ unsigned char i; ++ for(i = 0; i < 8; i++) ++ { ++ c[i] = (d >> ((7 - i) * 4)) & 0xf; ++ if(c[i] < 10) ++ c[i] += 0x30; ++ else ++ c[i] += (0x41 - 10); ++ } ++ c[8] = '\n'; ++ c[9] = 0; ++ serial_puts(num, c); ++} +diff --git a/arch/mips/xburst2/soc-m300/sleep_firmware/target.ld b/arch/mips/xburst2/soc-m300/sleep_firmware/target.ld +new file mode 100644 +index 000000000..44f03a97a +--- /dev/null ++++ b/arch/mips/xburst2/soc-m300/sleep_firmware/target.ld +@@ -0,0 +1,37 @@ ++OUTPUT_ARCH(mips) ++MEMORY{ ++ /* TOTAL MEM :4KBytes */ ++ ram : ORIGIN = 0xb0004000 , LENGTH = 2784 ++} ++ ++ENTRY(fastboot_restore_code_1) ++SECTIONS ++{ ++ .text : { ++ *(.resume) ++ *(.text) ++ } > ram ++ ++ .data : { ++ *(.data) ++ *(.rodata) ++ } > ram /**(.data)*/ ++ .bss : { ++ . = ALIGN(4); ++ __bss_start = .; ++ *(.sbss.*) ++ *(.bss.*) ++ *(COMMON) ++ . = ALIGN(4); ++ __bss_end = .; ++ } > ram ++ ++ ++ /DISCARD/ : { ++ *(COMMON) ++ *(.pdri) ++ *(.comment) ++ *(.gnu.attributes) ++ *(.reginfo) ++ } ++} +diff --git a/arch/mips/xburst2/soc-x2000/Kconfig.DT b/arch/mips/xburst2/soc-x2000/Kconfig.DT +new file mode 100644 +index 000000000..a44823544 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/Kconfig.DT +@@ -0,0 +1,20 @@ ++choice ++ prompt "device tree select for X2000 X2100 boards" ++ depends on SOC_X2000 || SOC_X2100 ++ ++config DT_X2000_MODULE ++ bool "x2000 module base" ++ ++config DT_HALLEY5_V20 ++ bool "x2000 halley5_v20" ++ ++config DT_HALLEY5_V30 ++ bool "x2000 halley5_v30" ++ ++config DT_KALE_V10 ++ bool "x2100 kale_v10" ++ ++config DT_X2000_LIFESMART_480P ++ bool "x2000 lifesmart 480p" ++ ++endchoice +diff --git a/arch/mips/xburst2/soc-x2000/Makefile b/arch/mips/xburst2/soc-x2000/Makefile +new file mode 100644 +index 000000000..c0b63551f +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/Makefile +@@ -0,0 +1,12 @@ ++obj-y += setup.o ++obj-y += serial.o ++ ++ifdef CONFIG_FASTBOOT ++obj-y += pm_fastboot.o ++else ++obj-y += pm.o ++endif ++obj-y += regs_save_restore.o ++obj-y += libdmmu.o ++obj-y += gpio.o ++obj-y += reset.o +diff --git a/arch/mips/xburst2/soc-x2000/gpio.c b/arch/mips/xburst2/soc-x2000/gpio.c +new file mode 100644 +index 000000000..89984c014 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/gpio.c +@@ -0,0 +1,123 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#define GPIO_PORT_OFF 0x100 ++#define GPIO_SHADOW_OFF 0x700 ++ ++#define PXPIN 0x00 /* PIN Level Register */ ++#define PXINT 0x10 /* Port Interrupt Register */ ++#define PXINTS 0x14 /* Port Interrupt Set Register */ ++#define PXINTC 0x18 /* Port Interrupt Clear Register */ ++#define PXMSK 0x20 /* Port Interrupt Mask Reg */ ++#define PXMSKS 0x24 /* Port Interrupt Mask Set Reg */ ++#define PXMSKC 0x28 /* Port Interrupt Mask Clear Reg */ ++#define PXPAT1 0x30 /* Port Pattern 1 Set Reg. */ ++#define PXPAT1S 0x34 /* Port Pattern 1 Set Reg. */ ++#define PXPAT1C 0x38 /* Port Pattern 1 Clear Reg. */ ++#define PXPAT0 0x40 /* Port Pattern 0 Register */ ++#define PXPAT0S 0x44 /* Port Pattern 0 Set Register */ ++#define PXPAT0C 0x48 /* Port Pattern 0 Clear Register */ ++#define PXFLG 0x50 /* Port Flag Register */ ++#define PXFLGC 0x58 /* Port Flag clear Register */ ++#define PXPU 0x80 /* Port PULL-UP State Register */ ++#define PXPUS 0x84 /* Port PULL-UP State Set Register */ ++#define PXPUC 0x88 /* Port PULL-UP State Clear Register */ ++#define PXPD 0x90 /* Port PULL-DOWN State Register */ ++#define PXPDS 0x94 /* Port PULL-DOWN State Set Register */ ++#define PXPDC 0x98 /* Port PULL-DOWN State Clear Register */ ++ ++#define PZGID2LD 0xF0 /* GPIOZ Group ID to load */ ++ ++#define SHADOW 5 ++ ++static const unsigned long gpiobase[] = { ++ [0] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 0 * GPIO_PORT_OFF), ++ [1] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 1 * GPIO_PORT_OFF), ++ [2] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 2 * GPIO_PORT_OFF), ++ [3] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 3 * GPIO_PORT_OFF), ++ [4] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 4 * GPIO_PORT_OFF), ++ ++ [SHADOW] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + GPIO_SHADOW_OFF), ++}; ++ ++#define GPIO_ADDR(port, reg) ((volatile unsigned long *)(gpiobase[port] + reg)) ++ ++static inline void gpio_write(int port, unsigned int reg, int val) ++{ ++ *GPIO_ADDR(port, reg) = val; ++} ++ ++static inline unsigned int gpio_read(int port, unsigned int reg) ++{ ++ return *GPIO_ADDR(port, reg); ++} ++ ++static void hal_gpio_port_set_func(int port, unsigned int pins, enum gpio_function func) ++{ ++ /* func option */ ++ if (func & 0x10) { ++ if (func & 0x8) ++ gpio_write(SHADOW, PXINTS, pins); ++ else ++ gpio_write(SHADOW, PXINTC, pins); ++ ++ if (func & 0x4) ++ gpio_write(SHADOW, PXMSKS, pins); ++ else ++ gpio_write(SHADOW, PXMSKC, pins); ++ ++ if (func & 0x2) ++ gpio_write(SHADOW, PXPAT1S, pins); ++ else ++ gpio_write(SHADOW, PXPAT1C, pins); ++ ++ if (func & 0x1) ++ gpio_write(SHADOW, PXPAT0S, pins); ++ else ++ gpio_write(SHADOW, PXPAT0C, pins); ++ ++ /* configure PzGID2LD to specify which port group to load */ ++ gpio_write(SHADOW, PZGID2LD, port); ++ } ++ ++ if (func & 0x80) { ++ int pull = (func >> 5) & 0x3; ++ if (pull == 0) { // no pull ++ gpio_write(port, PXPUC, pins); ++ gpio_write(port, PXPDC, pins); ++ } ++ if (pull == 1) { // pull up ++ gpio_write(port, PXPDC, pins); ++ gpio_write(port, PXPUS, pins); ++ } ++ if (pull == 2) { // pull down ++ gpio_write(port, PXPUC, pins); ++ gpio_write(port, PXPDS, pins); ++ } ++ } ++} ++ ++unsigned long ingenic_pinctrl_lock(int port); ++void ingenic_pinctrl_unlock(int port, unsigned long flags); ++ ++int jzgpio_set_func(int port, enum gpio_function func, unsigned long pins) ++{ ++ unsigned long flags; ++ ++ if (port < 0 || port > 4) { ++ printk(KERN_ERR "gpio: invalid gpio port for x2000: %d\n", port); ++ return -EINVAL; ++ } ++ ++ flags = ingenic_pinctrl_lock(port); ++ ++ hal_gpio_port_set_func(port, pins, func); ++ ++ ingenic_pinctrl_unlock(port, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL(jzgpio_set_func); +diff --git a/arch/mips/xburst2/soc-x2000/include/cpu-feature-overrides.h b/arch/mips/xburst2/soc-x2000/include/cpu-feature-overrides.h +new file mode 100644 +index 000000000..46e526d6f +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/cpu-feature-overrides.h +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++ ++ ++#define cpu_dcache_size() (32 * 1024) ++#define cpu_dcache_ways() 8 ++#define cpu_dcache_line_size() 32 ++#define cpu_icache_size() (32 * 1024) ++#define cpu_icache_ways() 8 ++#define cpu_icache_line_size() 32 ++#define cpu_has_xpa 0 ++#define cpu_has_tlb 1 ++#define cpu_has_tlbinv 1 ++#define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_4k_cache 1 ++#define cpu_has_tx39_cache 0 ++#define cpu_has_fpu 1 ++#define cpu_has_32fpr 0 ++#define cpu_has_counter 0 ++#define cpu_has_watch 1 ++#define cpu_has_divec 1 ++#define cpu_has_vce 0 ++#define cpu_has_cache_cdex_p 0 ++#define cpu_has_cache_cdex_s 0 ++#define cpu_has_prefetch 1 ++#define cpu_has_mcheck 1 ++#define cpu_has_ejtag 0 ++#define cpu_has_llsc 1 ++#define kernel_uses_llsc cpu_has_llsc ++#define cpu_has_mips16 0 ++#define cpu_has_mdmx 0 ++#define cpu_has_mips3d 0 ++#define cpu_has_smartmips 0 ++#define cpu_has_vtag_icache 0 ++#define cpu_has_dc_aliases 0 ++#define cpu_has_ic_fills_f_dc 0 ++#define cpu_has_pindexed_dcache 0 ++#define cpu_icache_snoops_remote_store 0 ++#define cpu_has_mips32r1 0 ++#define cpu_has_mips32r2 1 ++#define cpu_has_mips64r1 0 ++#define cpu_has_mips64r2 0 ++#define cpu_has_dsp 0 ++#define cpu_has_mipsmt 0 ++#define cpu_has_userlocal 1 ++#define cpu_has_rixi 1 ++#define cpu_has_nofpuex 0 ++#define cpu_has_64bits 0 ++#define cpu_has_64bit_zero_reg 0 ++#define cpu_has_vint 0 ++#define cpu_has_veic 0 ++#define cpu_has_inclusive_pcaches 0 ++#define kernel_uses_smartmips_rixi 0 ++#define cpu_has_mxu 0 ++#endif +diff --git a/arch/mips/xburst2/soc-x2000/include/irq.h b/arch/mips/xburst2/soc-x2000/include/irq.h +new file mode 100644 +index 000000000..0c1410546 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/irq.h +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2010 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_IRQ_H__ ++#define __ASM_MACH_INGENIC_IRQ_H__ ++#include ++#include ++ ++enum { ++#define GPIO_NR_IRQS (32 * 5 + 16) ++ IRQ_GPIO_BASE = (IRQ_INTC_END + 1), ++ IRQ_GPIO_END = IRQ_GPIO_BASE + GPIO_NR_IRQS - 1, ++ ++#define TCU_NR_IRQS (8) ++ IRQ_TCU_BASE, ++ IRQ_TCU_END = IRQ_TCU_BASE + TCU_NR_IRQS - 1, ++ ++#define MCU_NR_IRQS (5) ++ IRQ_MCU_BASE, ++ IRQ_MCU_END = IRQ_MCU_BASE + MCU_NR_IRQS - 1, ++ ++#define RESERVED_NR_IRQS (150) ++ IRQ_RESERVED_BASE, ++ IRQ_RESERVED_END = IRQ_RESERVED_BASE + RESERVED_NR_IRQS - 1, ++ ++ NR_IRQS, ++ ++ ++ ++}; ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2000/include/libdmmu.h b/arch/mips/xburst2/soc-x2000/include/libdmmu.h +new file mode 100644 +index 000000000..6e0fbdb42 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/libdmmu.h +@@ -0,0 +1,30 @@ ++#ifndef _LIBDMMU_ ++#define _LIBDMMU_ ++ ++#include ++ ++ ++struct dmmu_mm_ops { ++ int (*mm_release)(void *data); ++}; ++ ++struct dmmu_mm_notifier { ++ ++ struct device *dev; ++ void *data; ++ struct list_head list; ++ ++ struct dmmu_mm_ops *ops; ++}; ++ ++int dmmu_register_mm_notifier(struct dmmu_mm_notifier *dmn); ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len); ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len); ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len); ++int dmmu_unmap_all(struct device *dev); ++void dmmu_dump_vaddr(unsigned long vaddr); ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode); ++int dmmu_dump_map(unsigned long vaddr); ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2000/include/soc/base.h b/arch/mips/xburst2/soc-x2000/include/soc/base.h +new file mode 100644 +index 000000000..1b7d3d130 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/soc/base.h +@@ -0,0 +1,77 @@ ++ ++#ifndef __JZSOC_SOC_DEV_H__ ++#define __JZSOC_SOC_DEV_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 /* 64KB, AHB Bus Aribtier */ ++#define DDR_PHY_IOBASE 0x13011000 /* 4KB, DDR PHY */ ++#define DDRC_H0_IOBASE 0x13012000 /* 4KB, DDR Controller Registers@ASHB0 */ ++#define DPU_IOBASE 0x13050000 /* 64KB, LCD Controller */ ++#define CIM_IOBASE 0x13060000 /* 64KB, Camera Interface Module */ ++#define ROTATE_IOBASE 0x13070000 /* 64KB, Rotate DMA */ ++#define JPEG_IOBASE 0x130d0000 /* 64KB, VPU-JPEG */ ++ ++ ++/* AHB2 Bus Devices Base */ ++#define HARB2_IOBASE 0x13400000 /* 64KB, AHB Bus Arbiter */ ++#define NEMC_IOBASE 0x13410000 /* 64KB, External Normal Memory/Boot ROM/OTP Controller */ ++#define PDMA_IOBASE 0x13420000 /* 64KB, Programmable DMA Controller */ ++#define AES_IOBASE 0x13430000 /* 64KB, AES */ ++#define SFC_IOBASE 0x13440000 /* 64KB, SPI Flash Controller */ ++#define MSC0_IOBASE 0x13450000 /* 64KB, MMC SD Controller0 */ ++#define MSC1_IOBASE 0x13460000 /* 64KB, MMC SD Controller1 */ ++#define HASH_IOBASE 0x13470000 /* 64KB, HASH */ ++#define MAC_IOBASE 0x134b0000 /* 64KB, GMAC/MAC */ ++#define PWM_IOBASE 0x134c0000 /* 64KB, PWM */ ++#define DDRC_H2_IOBASE 0x134f0000 /* 4KB, DDR Controller Register @AHB2 */ ++#define AUDIO_IOBASE 0x134e0000 /* 64KB, Aduio System */ ++#define OTG_IOBASE 0x13500000 /* 256KB, OTG2.0 Controller */ ++#define EFUSE_IOBASE 0x13540000 /* 64KB, EFUSE */ ++//#define INTC_IOBASE 0x135f0000 /* Interrupt Controller */ /* TODO: to be fix */ ++ ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 /* 4KB, Clocks and Power Manager */ ++#define TCU_IOBASE 0x10002000 /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++#define WDT_IOBASE TCU_IOBASE /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++ ++#define RTC_IOBASE 0x10003000 /* 4KB, Real-Time Clock */ ++#define GPIO_IOBASE 0x10010000 /* 4KB, General-Purpose I/O */ ++#define UART0_IOBASE 0x10030000 /* 4KB, UART0 Controller */ ++#define UART1_IOBASE 0x10031000 /* 4KB, UART1 Controller */ ++#define UART2_IOBASE 0x10032000 /* 4KB, UART2 Controller */ ++#define UART3_IOBASE 0x10033000 /* 4KB, UART3 Controller */ ++#define UART4_IOBASE 0x10034000 /* 4KB, UART4 Controller */ ++#define UART5_IOBASE 0x10035000 /* 4KB, UART4 Controller */ ++#define SCC_IOBASE 0x10040000 /* 4KB, Smart Card Controller */ ++#define SSI0_IOBASE 0x10043000 /* 4KB, Synchronous Serial Interface */ ++#define SSI1_IOBASE 0x10044000 /* 4KB, Synchronous Serial Interface */ ++#define I2C0_IOBASE 0x10050000 /* 4KB, I2C 0 Bus Interface */ ++#define I2C1_IOBASE 0x10051000 /* 4KB, I2C 1 Bus Interface */ ++#define I2C2_IOBASE 0x10052000 /* 4KB, I2C 2 Bus Interface */ ++#define I2C3_IOBASE 0x10053000 /* 4KB, I2C 3 Bus Interface */ ++#define I2C4_IOBASE 0x10054000 /* 4KB, I2C 4 Bus Interface */ ++#define I2C5_IOBASE 0x10055000 /* 4KB, I2C 5 Bus Interface */ ++ ++ ++ ++/* TODO: Others To Be add */ ++/* NAND CHIP Base Address */ ++#define NEMC_CS1_IOBASE 0X1b000000 ++#define NEMC_CS2_IOBASE 0X1a000000 ++#define NEMC_CS3_IOBASE 0X19000000 ++#define NEMC_CS4_IOBASE 0X18000000 ++#define NEMC_CS5_IOBASE 0X17000000 ++#define NEMC_CS6_IOBASE 0X16000000 ++ ++ ++#define OST_IOBASE 0x12000000 ++#define TCU_IOBASE 0x10002000 ++ ++#define DDRC_BASE 0xb34f0000 ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2000/include/soc/cache.h b/arch/mips/xburst2/soc-x2000/include/soc/cache.h +new file mode 100644 +index 000000000..249e4230a +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/soc/cache.h +@@ -0,0 +1,73 @@ ++#ifndef __CHIP_CACHE_H__ ++#define __CHIP_CACHE_H__ ++#include ++#include ++ ++#define Index_Prefetch_I 0x1c ++ ++ ++#define cache_prefetch(label,size) \ ++do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&label + size) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set push \n\t" \ ++ ".set mips32 \n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set pop \n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++} \ ++while(0) ++ ++#define K0BASE KSEG0 ++#define CFG_DCACHE_SIZE 32768 ++#define CFG_ICACHE_SIZE 32768 ++#define CFG_CACHELINE_SIZE 32 ++ ++#define CFG_SDCACHE_SIZE (512*1024) ++#define CFG_SDCACHELINE_SIZE 64 ++ ++static inline void __jz_flush_cache_all(void) ++{ ++ register unsigned long addr; ++ /* Clear CP0 TagLo */ ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Writeback_Inv_D), "r"(addr)); ++ } ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Invalidate_I), "r"(addr)); ++ } ++ ++ asm volatile ("sync\n\t" ++ "lw $0,0(%0)" ++ ::"r" (0xa0000000)); ++ /* 2nd cache */ ++ for (addr = K0BASE; addr < (K0BASE + CFG_SDCACHE_SIZE); addr += CFG_SDCACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Writeback_Inv_SD), "r"(addr)); ++ } ++ ++ asm volatile ("sync\n\t" ++ "lw $0,0(%0)" ++ ::"r" (0xa0000000)); ++} ++ ++#endif /* __CHIP_CACHE_H__ */ +diff --git a/arch/mips/xburst2/soc-x2000/include/soc/cpm.h b/arch/mips/xburst2/soc-x2000/include/soc/cpm.h +new file mode 100644 +index 000000000..3efdc80e1 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/soc/cpm.h +@@ -0,0 +1,136 @@ ++/* ++ * SOC CPM register definition. ++ * ++ * CPM (Clock reset and Power control Management) ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __SOC_CPM_H__ ++#define __SOC_CPM_H__ ++ ++#include ++ ++#define CPM_CPCCR (0x00) ++#define CPM_CPCSR (0xD4) ++ ++#define CPM_DDRCDR (0x2c) ++#define CPM_MACCDR (0x54) ++#define CPM_MACTXCDR (0x58) ++#define CPM_MACTXCDR1 (0xdc) ++#define CPM_MACPTP (0x4c) ++#define CPM_I2S0CDR (0x60) ++#define CPM_I2S1CDR (0x7c) ++#define CPM_I2S2CDR (0x84) ++#define CPM_I2S3CDR (0x8c) ++#define CPM_I2S0CDR1 (0x70) ++#define CPM_I2S1CDR1 (0x80) ++#define CPM_I2S2CDR1 (0x88) ++#define CPM_I2S3CDR1 (0xa0) ++#define CPM_AUDIOCR (0xac) ++#define CPM_LPCDR (0x64) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0xa4) ++#define CPM_MSC2CDR (0xa8) ++#define CPM_SFCCDR (0x74) ++#define CPM_SSICDR (0x5c) ++#define CPM_CIMCDR (0x78) ++#define CPM_PWMCDR (0x6c) ++#define CPM_ISPCDR (0x30) ++#define CPM_RSACDR (0x50) ++ ++#define CPM_INTR (0xB0) ++#define CPM_INTRE (0xB4) ++#define CPM_SFTINT (0xBC) ++#define CPM_DRCG (0xD0) ++#define CPM_CPPSR (0x34) ++#define CPM_CPSPPR (0x38) ++#define CPM_USBPCR (0x3C) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++ ++#define CPM_CPPCR (0x0C) ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++#define CPM_CPEPCR (0x18) ++ ++#define CPM_LCR (0x04) ++#define CPM_PSWC0ST (0x90) ++#define CPM_PSWC1ST (0x94) ++#define CPM_PSWC2ST (0x98) ++#define CPM_PSWC3ST (0x9C) ++#define CPM_CLKGR (0x20) ++#define CPM_CLKGR1 (0x28) ++#define CPM_MESTSEL (0xEC) ++#define CPM_SRBC (0xC4) ++#define CPM_EXCLK_DS (0xE0) ++#define CPM_MPDCR (0xF8) ++#define CPM_MPDCR1 (0xFC) ++#define CPM_SLBC (0xC8) ++#define CPM_SLPC (0xCC) ++#define CPM_OPCR (0x24) ++#define CPM_RSR (0x08) ++ ++#ifndef BIT ++#define BIT(nr) (1UL << nr) ++#endif ++ ++/*USB Parameter Control Register*/ ++#define USBPCR_USB_MODE BIT(31) ++#define USBPCR_AVLD_REG BIT(30) ++#define USBPCR_IDPULLUP_MASK_BIT 28 ++#define USBPCR_IDPULLUP_MASK (0x3 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS_SUSPEND (0x1 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_INCR_MASK BIT(27) ++#define USBPCR_POR_BIT 22 ++#define USBPCR_POR BIT(USBPCR_POR_BIT) ++ ++/*USB Reset Detect Timer Register*/ ++#define USBRDT_RESUME_INTEEN BIT(31) /*RW*/ ++#define USBRDT_RESUME_INTERCLR BIT(30) /*W0*/ ++#define USBRDT_RESUME_SPEED_BIT 28 /*RW*/ ++#define USBRDT_RESUME_SPEED_MSK (0x3 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_HIGH (0x0 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_FULL (0x1 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_LOW (0x2 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_STATUS BIT(27) /*RO*/ ++#define USBRDT_HB_MASK BIT(26) ++#define USBRDT_VBFIL_LD_EN BIT(25) ++#define USBRDT_IDDIG_EN BIT(24) ++#define USBRDT_IDDIG_REG BIT(23) ++#define USBRDT_USBRDT_MSK (0x7fffff) ++#define USBRDT_USBRDT(x) ((x) & USBRDT_USBRDT_MSK) ++ ++/*USB VBUS Jitter Filter Register*/ ++#define USBVBFIL_USBVBFIL(x) ((x) & 0xffff) ++#define USBVBFIL_IDDIGFIL(x) ((x) & (0xffff << 16)) ++ ++/*USB Parameter Control Register1*/ ++#define USBPCR1_BVLD_REG BIT(31) ++#define USBPCR1_DPPULLDOWN BIT(29) ++#define USBPCR1_DMPULLDOWN BIT(28) ++#define USBPCR1_PORT_RST BIT(21) ++ ++/*Oscillator and Power Control Register*/ ++#define OPCR_USB_SPENDN BIT(7) ++#define OPCR_USB_PHY_GATE BIT(23) ++ ++ ++#define LCR_LPM_MASK (0x3) ++#define LCR_LPM_SLEEP (0x1) ++ ++#define OPCR_ERCS (0x1<<2) ++#define OPCR_PD (0x1<<3) ++#define OPCR_IDLE (0x1<<31) ++ ++ ++#define cpm_inl(off) inl(CPM_IOBASE + (off)) ++#define cpm_outl(val,off) outl(val,CPM_IOBASE + (off)) ++#define cpm_clear_bit(val,off) do{cpm_outl((cpm_inl(off) & ~(1<<(val))),off);}while(0) ++#define cpm_set_bit(val,off) do{cpm_outl((cpm_inl(off) | (1< ++ ++/* ++ * DDR Controller Registers ++ **/ ++#define DDR_MEM_PHY_BASE 0x20000000 ++ ++#define DDRC_AHB2_OFFSET 0xb34f0000 ++#define DDRC_APB_OFFSET 0xb3012000 ++#define DDR_PHY_OFFSET (-0x4e0000 + 0x1000) ++ ++#define DDRC_STATUS 0x0 ++#define DDRC_CFG 0x8 ++#define DDRC_CTRL 0x10 ++#define DDRC_LMR 0x18 ++#define DDRC_DLP 0x20 ++#define DDRC_AUTOSR_EN 0x28 ++#define DDRC_AUTOSR_CNT 0x30 ++#define DDRC_REFCNT 0x38 ++#define DDRC_DBGINFO 0xE8 ++#define DDRC_TIMING(n) (0x40 + 8 * (n - 1)) ++#define DDRC_MMAP0 0x78 ++#define DDRC_MMAP1 0x80 ++#define DDRC_HREGPRO 0xd8 ++#define DDRC_DWCFG (DDRC_APB_OFFSET + 0x00) ++#define DDRC_DWSTATUS (DDRC_APB_OFFSET + 0x04) ++#define DDRC_REMAP(n) (DDRC_APB_OFFSET + 0x08 + 4 * (n - 1)) ++#define DDRC_CGUC0 (DDRC_APB_OFFSET + 0x64) ++#define DDRC_CGUC1 (DDRC_APB_OFFSET + 0x68) ++#define DDRC_PREGPRO (DDRC_APB_OFFSET + 0x6c) ++ ++/* ++ * DDR Innophy registers ++ * */ ++#define DDRP_INNOPHY_PHY_RST (DDR_PHY_OFFSET + 0x000) ++#define DDRP_INNOPHY_MEM_CFG (DDR_PHY_OFFSET + 0x004) ++#define DDRP_INNOPHY_DQ_WIDTH (DDR_PHY_OFFSET + 0x07c) ++#define DDRP_INNOPHY_CL (DDR_PHY_OFFSET + 0x014) ++#define DDRP_INNOPHY_CWL (DDR_PHY_OFFSET + 0x01c) ++#define DDRP_INNOPHY_AL (DDR_PHY_OFFSET + 0x018) ++#define DDRP_INNOPHY_PLL_FBDIV (DDR_PHY_OFFSET + 0x080) ++#define DDRP_INNOPHY_PLL_CTRL (DDR_PHY_OFFSET + 0x084) ++#define DDRP_INNOPHY_PLL_PDIV (DDR_PHY_OFFSET + 0x088) ++#define DDRP_INNOPHY_PLL_LOCK (DDR_PHY_OFFSET + 0xc8) ++#define DDRP_INNOPHY_TRAINING_CTRL (DDR_PHY_OFFSET + 0x008) ++#define DDRP_INNOPHY_CALIB_DONE (DDR_PHY_OFFSET + 0xcc) ++#define DDRP_INNOPHY_CALIB_DELAY_AL (DDR_PHY_OFFSET + 0x190) ++#define DDRP_INNOPHY_CALIB_DELAY_AH (DDR_PHY_OFFSET + 0x194) ++#define DDRP_INNOPHY_CALIB_BYPASS_AL (DDR_PHY_OFFSET + 0x118) ++#define DDRP_INNOPHY_CALIB_BYPASS_AH (DDR_PHY_OFFSET + 0x158) ++#define DDRP_INNOPHY_WL_MODE1 (DDR_PHY_OFFSET + 0x00c) ++#define DDRP_INNOPHY_WL_MODE2 (DDR_PHY_OFFSET + 0x010) ++#define DDRP_INNOPHY_WL_DONE (DDR_PHY_OFFSET + 0x0c0) ++#define DDRP_INNOPHY_INIT_COMP (DDR_PHY_OFFSET + 0x0d0) ++ ++ ++/* ++ * DDRC REGISTER BITS DEFINE ++ * */ ++ ++/* DDRC Status Register */ ++#define DDRC_DSTATUS_MISS (1 << 6) ++#define DDRC_ST_DPDN (1 << 5) /* 0 DDR memory is NOT in deep-power-down state ++ 1 DDR memory is in deep-power-down state */ ++#define DDRC_ST_PDN (1 << 4) /* 0 DDR memory is NOT in power-down state ++ 1 DDR memory is in power-down state */ ++#define DDRC_ST_AREF (1 << 3) /* 0 DDR memory is NOT in auto-refresh state ++ 1 DDR memory is in auto-refresh state */ ++#define DDRC_ST_SREF (1 << 2) /* 0 DDR memory is NOT in self-refresh state ++ 1 DDR memory is in self-refresh state */ ++#define DDRC_ST_CKE1 (1 << 1) /* 0 CKE1 Pin is low ++ 1 CKE1 Pin is high */ ++#define DDRC_ST_CKE0 (1 << 0) /* 0 CKE0 Pin is low ++ 1 CKE0 Pin is high */ ++ ++/* DDRC Configure Register */ ++#define DDRC_CFG_ROW1_BIT 29 /* Row Address width. */ ++#define DDRC_CFG_ROW1_MASK (0x7 << DDRC_CFG_ROW1_BIT) ++#define DDRC_CFG_COL1_BIT 26 /* Row Address width. */ ++#define DDRC_CFG_COL1_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA1 25 /* Bank Address width of DDR memory */ ++#define DDRC_CFG_IMBA (1 << 16) ++#define DDRC_CFG_ROW0_BIT 13 /* Row Address width. */ ++#define DDRC_CFG_ROW0_MASK (0x7 << DDRC_CFG_ROW0_BIT) ++#define DDRC_CFG_COL0_BIT 10 /* Row Address width. */ ++#define DDRC_CFG_COL0_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA0 9 /* Bank Address width of DDR memory */ ++ ++#define DDRC_CFG_TYPE_BIT 3 ++#define DDRC_CFG_TYPE_MASK (0x7 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR1 (2 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_MDDR (3 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR2 (4 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR2 (5 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR3 (6 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR3 (7 << DDRC_CFG_TYPE_BIT) ++ ++#define DDRC_CFG_ODTEN (1 << 2) /* ODT EN */ ++#define DDRC_CFG_CS1EN (1 << 1) /* DDR Chip-Select-1 Enable */ ++#define DDRC_CFG_CS0EN (1 << 0) /* DDR Chip-Select-0 Enable */ ++ ++/* DDRC Control Register */ ++#define DDRC_CTRL_DFI_RST (1 << 23) ++#define DDRC_CTRL_DLL_RST (1 << 22) ++#define DDRC_CTRL_CTL_RST (1 << 21) ++#define DDRC_CTRL_CFG_RST (1 << 20) ++#define DDRC_CTRL_ACTPD (1 << 15) /* 0 Precharge all banks before entering power-down ++ 1 Do not precharge banks before entering power-down */ ++#define DDRC_CTRL_PDT_BIT 12 /* Power-Down Timer */ ++#define DDRC_CTRL_PDT_MASK (0x7 << DDRC_CTRL_PDT_BIT) ++#define DDRC_CTRL_PDT_DIS (0 << DDRC_CTRL_PDT_BIT) /* power-down disabled */ ++#define DDRC_CTRL_PDT_8 (1 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 8 tCK idle */ ++#define DDRC_CTRL_PDT_16 (2 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 16 tCK idle */ ++#define DDRC_CTRL_PDT_32 (3 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 32 tCK idle */ ++#define DDRC_CTRL_PDT_64 (4 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 64 tCK idle */ ++#define DDRC_CTRL_PDT_128 (5 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 128 tCK idle */ ++ ++#define DDRC_CTRL_PD_CCE (1 << 7) /* Power down clk freq change enable */ ++#define DDRC_CTRL_DPD (1 << 6) /* 1 Drive external MDDR device entering Deep-Power-Down mode */ ++#define DDRC_CTRL_SR (1 << 5) /* 1 Drive external DDR device entering self-refresh mode ++ 0 Drive external DDR device exiting self-refresh mode */ ++#define DDRC_CTRL_SR_CCE (1 << 4) /* Self refresh clk stop request enable */ ++#define DDRC_CTRL_CKE (1 << 1) /* 0 Not set CKE Pin High, 1 Set CKE Pin HIGH */ ++#define DDRC_CTRL_RESET (1 << 0) /* 0 End resetting ddrc_controller, 1 Resetting ddrc_controller */ ++ ++/* DDRC DFI low power handshake control register */ ++#define DDRC_DDLP_TCTLUDP_BIT 24 ++#define DDRC_DDLP_TCTLUDP_FF (0xff << DDRC_DDLP_TCTLUDP_BIT) ++ ++/* DDRC Load-Mode-Register */ ++#define DDRC_LMR_DDR_ADDR_BIT 12 /* When performing a DDR command, DDRC_ADDR[13:0] ++ corresponding to external DDR address Pin A[13:0] */ ++#define DDRC_LMR_DDR_ADDR_MASK (0xfffff << DDRC_LMR_DDR_ADDR_BIT) ++ ++#define DDRC_LMR_MA_BIT 16 /* FOR LPDDR2, MA[9:0] */ ++#define DDRC_LMR_OP_BIT 24 /* FOR LPDDR2, OP[9:0] */ ++ ++#define DDRC_LMR_BA_BIT 9 /* When performing a DDR command, BA[2:0] ++ corresponding to external DDR address Pin BA[2:0]. */ ++#define DDRC_LMR_BA_MASK (0x7 << DDRC_LMR_BA_BIT) ++#define DDRC_LMR_CMD_BIT 6 ++#define DDRC_LMR_CMD_MASK (0x7 << DDRC_LMR_CMD_BIT) ++#define DDRC_LMR_CMD_PREC (0 << DDRC_LMR_CMD_BIT)/* Precharge one bank/All banks */ ++#define DDRC_LMR_CMD_AUREF (1 << DDRC_LMR_CMD_BIT)/* Auto-Refresh */ ++#define DDRC_LMR_CMD_LMR (2 << DDRC_LMR_CMD_BIT)/* Load Mode Register */ ++#define DDRC_LMR_CMD_ZQCL_CS0 (3 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCL_CS1 (4 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS1 */ ++#define DDRC_LMR_CMD_ZQCS_CS0 (5 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCS_CS1 (6 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS1 */ ++ ++#define DDRC_LMR_TMRD_BIT 1 ++#define DDRC_LMR_TMRD_MASK (0x1f << DDRC_LMR_TMRD_BIT) ++#define DDRC_LMR_START (1 << 0) /* 0 No command is performed ++ 1 On the posedge of START, perform a command ++ defined by CMD field */ ++ ++/* DDRC Auto-Refresh Counter */ ++#define DDRC_REFCNT_REF_EN (1 << 0) /* Enable Refresh Counter */ ++#define DDRC_REFCNT_CLK_DIV_BIT 1 /* Clock Divider for auto-refresh counter. */ ++#define DDRC_REFCNT_CLK_DIV_MASK (0x7 << DDRC_REFCNT_CLKDIV_BIT) ++ ++#define DDRC_REFCNT_PREREF_CNT_BIT 4 ++#define DDRC_REFCNT_PREREF_CNT_MASK (0xf << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT(val) (val << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT_DEFAULT DDRC_REFCNT_PREREF_CNT(8) ++ ++#define DDRC_REFCNT_CNT_BIT 8 /* 8-bit counter */ ++#define DDRC_REFCNT_CNT_MASK (0xff << DDRC_REFCNT_CNT_BIT) ++ ++#define DDRC_REFCNT_CON_BIT 16 /* Constant value used to compare with CNT value. */ ++#define DDRC_REFCNT_CON_MASK (0xff << DDRC_REFCNT_CON_BIT) ++ ++#define DDRC_REFCNT_TRFC_BIT 24 ++#define DDRC_REFCNT_TRFC_MASK (0x3f << DDRC_REFCNT_TRFC_BIT) ++ ++#define DDRC_REFCNT_PREREF_EN_BIT 30 ++#define DDRC_REFCNT_PREREF_EN (1 << DDRC_REFCNT_PREREF_EN_BIT) ++ ++#define DDRC_REFCNT_PBREF_EN_BIT 31 ++#define DDRC_REFCNT_PBREF_EN (1 << DDRC_REFCNT_PBREF_EN_BIT) ++ ++/* DDRC Memory Map Config Register */ ++#define DDRC_MMAP_BASE_BIT 8 /* base address */ ++#define DDRC_MMAP_BASE_MASK (0xff << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP_MASK_BIT 0 /* address mask */ ++#define DDRC_MMAP_MASK_MASK (0xff << DDRC_MMAP_MASK_BIT) ++ ++#define DDRC_MMAP0_BASE (0x20 << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP1_BASE_64M (0x24 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_128M (0x28 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_256M (0x30 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++ ++#define DDRC_MMAP_MASK_64_64 (0xfc << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_128_128 (0xf8 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_256_256 (0xf0 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++ ++/* DDR device data width configure register */ ++#define DDRC_DWCFG_DFI_INIT_START (1 << 3) ++ ++/* DDR device status register */ ++#define DDRC_DWSTATUS_DFI_INIT_COMP (1 << 0) ++ ++/* DDRC AHB Bus Register Protection Register */ ++#define DDRC_HREGPRO_HPRO_EN (1 << 0) ++ ++/* DDRC APB Bus Register Protection Register */ ++#define DDRC_PREGPRO_PPRO_EN (1 << 0) ++ ++ ++/* DDRC clock gate unit configure 0 */ ++#define DDRC_CGU_PORT7 (1 << 28) ++#define DDRC_CGU_PORT6 (1 << 24) ++#define DDRC_CGU_PORT5 (1 << 20) ++#define DDRC_CGU_PORT4 (1 << 16) ++#define DDRC_CGU_PORT3 (1 << 12) ++#define DDRC_CGU_PORT2 (1 << 8) ++#define DDRC_CGU_PORT1 (1 << 4) ++#define DDRC_CGU_PORT0 (1 << 0) ++ ++/* DDRC clock gate unit configure 1 */ ++#define DDRC_CGU_BWM (1 << 8) ++#define DDRC_CGU_PCTRL (1 << 4) ++#define DDRC_CGU_SCH (1 << 1) ++#define DDRC_CGU_PA (1 << 0) ++ ++ ++ ++/* ++ * DDR INNOPHY REGISTER BITS DEFINE ++ * */ ++ ++/* DDRP DQ Width Register */ ++#define DDRP_DQ_WIDTH_DQ_H (1 << 1) ++#define DDRP_DQ_WIDTH_DQ_L (1 << 0) ++ ++/* DDRP Pll Ctrl Register */ ++#define DDRP_PLL_CTRL_PLLPDEN (1 << 1) ++ ++/* DDRP Training Ctrl Register */ ++#define DDRP_TRAINING_CTRL_WL_BP (1 << 3) ++#define DDRP_TRAINING_CTRL_WL_START (1 << 2) ++#define DDRP_TRAINING_CTRL_DSCSE_BP (1 << 1) ++#define DDRP_TRAINING_CTRL_DSACE_START (1 << 0) ++ ++/* DDRP Training Done Register */ ++#define DDRP_CALIB_DONE_HDQCFB (1 << 3) ++#define DDRP_CALIB_DONE_LDQCFB (1 << 2) ++#define DDRP_CALIB_DONE_HDQCFA (1 << 1) ++#define DDRP_CALIB_DONE_LDQCFA (1 << 0) ++#define DDRP_CALIB_DONE_HWRLFB (1 << 3) ++#define DDRP_CALIB_DONE_LWRLFB (1 << 2) ++#define DDRP_CALIB_DONE_HWRLFA (1 << 1) ++#define DDRP_CALIB_DONE_LWRLFA (1 << 0) ++ ++/* DDRP CALIB BP Register */ ++#define DDRP_CALIB_BP_CYCLESELBH_BIT 4 ++#define DDRP_CALIB_BP_OPHCSELBH_BIT 3 ++#define DDRP_CALIB_BP_DLLSELBH_BIT 0 ++ ++/* DDRP Init Complete Register */ ++#define DDRP_INIT_COMP (1 << 0) ++ ++#define DDRP_PLL_LOCK (1 << 3) ++ ++#define REG32(addr) *(volatile unsigned int *)(addr) ++ ++#define ddr_writel(value, reg) (REG32(DDRC_BASE + reg) = (value)) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++#endif /* __DDR_H__ */ +diff --git a/arch/mips/xburst2/soc-x2000/include/soc/efuse.h b/arch/mips/xburst2/soc-x2000/include/soc/efuse.h +new file mode 100644 +index 000000000..1298986ea +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/soc/efuse.h +@@ -0,0 +1,365 @@ ++#ifndef __INGENIC_EFUSE_H__ ++#define __INGENIC_EFUSE_H__ ++ ++#define EFUSE_CTRL 0x0 ++#define EFUSE_CFG 0x4 ++#define EFUSE_STATE 0x8 ++#define EFUSE_DATA(n) (0xC + (n) * 4) ++ ++#define EFUSE_RIR_RF (0) ++#define EFUSE_RIR_DATA (1) ++#define EFUSE_RIR_ADDR (2) ++#define EFUSE_RIR_DISABLE (15) ++ ++ ++// efuse ctrl bits ++#define EFUSE_CTRL_ADDR (21) ++#define EFUSE_CTRL_ADDR_MASK (0x3f) ++#define EFUSE_CTRL_LEN (16) ++#define EFUSE_CTRL_LEN_MASK (7) ++#define EFUSE_CTRL_PGEN (1 << 15) ++#define EFUSE_CTRL_RWL (1 << 11) ++#define EFUSE_CTRL_MR (1 << 10) ++#define EFUSE_CTRL_PS (1 << 9) ++#define EFUSE_CTRL_PD (1 << 8) ++#define EFUSE_CTRL_WREN (1 << 1) ++#define EFUSE_CTRL_RDEN (1 << 0) ++ ++ ++// efuse cfg bits ++#define EFUSE_CFG_INT_EN (1 << 31) ++#define EFUSE_CFG_RD_ADJ (24) ++#define EFUSE_CFG_RD_ADJ_MASK (0xf) ++#define EFUSE_CFG_RD_STROBE (16) ++#define EFUSE_CFG_RD_STROBE_MASK (0x1f) ++#define EFUSE_CFG_WR_ADJ (12) ++#define EFUSE_CFG_WR_ADJ_MASK (0xf) ++#define EFUSE_CFG_WR_STROBE (16) ++#define EFUSE_CFG_WR_STROBE_MASK (0x3ff) ++ ++ ++// efuse state bits ++#define EFUSE_STA_NKU_PRT (1 << 23) ++#define EFUSE_STA_USERKEY1_PRT (1 << 22) ++#define EFUSE_STA_USERKEY0_PRT (1 << 21) ++#define EFUSE_STA_CHIPKEY_PRT (1 << 20) ++#define EFUSE_STA_HIDEBLK_PRT (1 << 19) ++#define EFUSE_STA_SOCINFO_PRT (1 << 18) ++#define EFUSE_STA_TRIM2_PRT (1 << 17) ++#define EFUSE_STA_TRIM1_PRT (1 << 16) ++#define EFUSE_STA_TRIM0_PRT (1 << 15) ++#define EFUSE_STA_CUSTID2_PRT (1 << 14) ++#define EFUSE_STA_CUSTID1_PRT (1 << 13) ++#define EFUSE_STA_CUSTID0_PRT (1 << 12) ++#define EFUSE_STA_CHIPID_PRT (1 << 11) ++#define EFUSE_STA_SECBOOT_PRT (1 << 10) ++#define EFUSE_STA_DIS_JTAG (1 << 9) ++#define EFUSE_STA_SECBOOT_EN (1 << 8) ++#define EFUSE_STA_WR_DONE (1 << 1) ++#define EFUSE_STA_RD_DONE (1 << 0) ++ ++ ++ ++#define CHIPID_OFFSET_ADDR (0x0) ++#define CUSTID0_OFFSET_ADDR (0x11) ++#define CUSTID1_OFFSET_ADDR (0x22) ++#define CUSTID2_OFFSET_ADDR (0x3f) ++#define TRIM0_OFFSET_ADDR (0x5c) ++#define TRIM1_OFFSET_ADDR (0x61) ++#define TRIM2_OFFSET_ADDR (0x66) ++#define SOCINFO_OFFSET_ADDR (0x6b) ++#define PRT_OFFSET_ADDR (0x70) ++#define HIDEBLK_OFFSET_ADDR (0x74) ++#define CHIPKEY_OFFSET_ADDR (0x78) ++#define USERKEY0_OFFSET_ADDR (0x9a) ++#define USERKEY1_OFFSET_ADDR (0xbc) ++#define NKU_OFFSET_ADDR (0xde) ++ ++#define CHIPID_WORD_ADDR (0x0) ++#define CUSTID0_WORD_ADDR (0x4) ++#define CUSTID1_WORD_ADDR (0x8) ++#define CUSTID2_WORD_ADDR (0xf) ++#define TRIM0_WORD_ADDR (0x17) ++#define TRIM1_WORD_ADDR (0x18) ++#define TRIM2_WORD_ADDR (0x19) ++#define SOCINFO_WORD_ADDR (0x1a) ++#define PRT_WORD_ADDR (0x1c) ++#define HIDEBLK_WORD_ADDR (0x1d) ++#define CHIPKEY_WORD_ADDR (0x1e) ++#define USERKEY0_WORD_ADDR (0x26) ++#define USERKEY1_WORD_ADDR (0x2f) ++#define NKU_WORD_ADDR (0x37) ++ ++#define CHIPID_BIT_NUM (128) ++#define CUSTID0_BIT_NUM (128) ++#define CUSTID1_BIT_NUM (216) ++#define CUSTID2_BIT_NUM (216) ++#define TRIM0_BIT_NUM (32) ++#define TRIM1_BIT_NUM (32) ++#define TRIM2_BIT_NUM (32) ++#define SOCINFO_BIT_NUM (32) ++#define PRT_BIT_NUM (16) ++#define HIDEBLK_BIT_NUM (16) ++#define CHIPKEY_BIT_NUM (256) ++#define USERKEY0_BIT_NUM (256) ++#define USERKEY1_BIT_NUM (256) ++#define NKU_BIT_NUM (256) ++ ++#define CHIPID_EXT_BIT_NUM (8) ++#define CUSTID0_EXT_BIT_NUM (8) ++#define CUSTID1_EXT_BIT_NUM (16) ++#define CUSTID2_EXT_BIT_NUM (16) ++#define TRIM0_EXT_BIT_NUM (8) ++#define TRIM1_EXT_BIT_NUM (8) ++#define TRIM2_EXT_BIT_NUM (8) ++#define SOCINFO_EXT_BIT_NUM (8) ++#define PRT_EXT_BIT_NUM (16) ++#define HIDEBLK_EXT_BIT_NUM (16) ++#define CHIPKEY_EXT_BIT_NUM (16) ++#define USERKEY0_EXT_BIT_NUM (16) ++#define USERKEY1_EXT_BIT_NUM (16) ++#define NKU_EXT_BIT_NUM (16) ++ ++#define CHIPID_WORD_NUM (((CHIPID_BIT_NUM + CHIPID_EXT_BIT_NUM ) / 32) + (((CHIPID_BIT_NUM + CHIPID_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define CUSTID0_WORD_NUM (((CUSTID0_BIT_NUM + CUSTID0_EXT_BIT_NUM ) / 32) + (((CUSTID0_BIT_NUM + CUSTID0_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define CUSTID1_WORD_NUM (((CUSTID1_BIT_NUM + CUSTID1_EXT_BIT_NUM ) / 32) + (((CUSTID1_BIT_NUM + CUSTID1_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define CUSTID2_WORD_NUM (((CUSTID2_BIT_NUM + CUSTID2_EXT_BIT_NUM ) / 32) + (((CUSTID2_BIT_NUM + CUSTID2_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define TRIM0_WORD_NUM (((TRIM0_BIT_NUM + TRIM0_EXT_BIT_NUM ) / 32) + (((TRIM0_BIT_NUM + TRIM0_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define TRIM1_WORD_NUM (((TRIM1_BIT_NUM + TRIM1_EXT_BIT_NUM ) / 32) + (((TRIM1_BIT_NUM + TRIM1_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define TRIM2_WORD_NUM (((TRIM2_BIT_NUM + TRIM2_EXT_BIT_NUM ) / 32) + (((TRIM2_BIT_NUM + TRIM2_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define SOCINFO_WORD_NUM (((SOCINFO_BIT_NUM + SOCINFO_EXT_BIT_NUM ) / 32) + (((SOCINFO_BIT_NUM + SOCINFO_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define PRT_WORD_NUM (((PRT_BIT_NUM + PRT_EXT_BIT_NUM ) / 32) + (((PRT_BIT_NUM + PRT_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define HIDEBLK_WORD_NUM (((HIDEBLK_BIT_NUM + HIDEBLK_EXT_BIT_NUM ) / 32) + (((HIDEBLK_BIT_NUM + HIDEBLK_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define CHIPKEY_WORD_NUM (((CHIPKEY_BIT_NUM + CHIPKEY_EXT_BIT_NUM ) / 32) + (((CHIPKEY_BIT_NUM + CHIPKEY_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define USERKEY0_WORD_NUM (((USERKEY0_BIT_NUM + USERKEY0_EXT_BIT_NUM ) / 32) + (((USERKEY0_BIT_NUM + USERKEY0_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define USERKEY1_WORD_NUM (((USERKEY1_BIT_NUM + USERKEY1_EXT_BIT_NUM ) / 32) + (((USERKEY1_BIT_NUM + USERKEY1_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++#define NKU_WORD_NUM (((NKU_BIT_NUM + NKU_EXT_BIT_NUM ) / 32) + (((NKU_BIT_NUM + NKU_EXT_BIT_NUM ) % 32) ? 1 : 0)) ++ ++ ++#define CHIPID_BEGIN_ALIGN (CHIPID_OFFSET_ADDR - (CHIPID_WORD_ADDR << 2)) ++#define CUSTID0_BEGIN_ALIGN (CUSTID0_OFFSET_ADDR - (CUSTID0_WORD_ADDR << 2)) ++#define CUSTID1_BEGIN_ALIGN (CUSTID1_OFFSET_ADDR - (CUSTID1_WORD_ADDR << 2)) ++#define CUSTID2_BEGIN_ALIGN (CUSTID2_OFFSET_ADDR - (CUSTID2_WORD_ADDR << 2)) ++#define TRIM0_BEGIN_ALIGN (TRIM0_OFFSET_ADDR - (TRIM0_WORD_ADDR << 2)) ++#define TRIM1_BEGIN_ALIGN (TRIM1_OFFSET_ADDR - (TRIM1_WORD_ADDR << 2)) ++#define TRIM2_BEGIN_ALIGN (TRIM2_OFFSET_ADDR - (TRIM2_WORD_ADDR << 2)) ++#define SOCINFO_BEGIN_ALIGN (SOCINFO_OFFSET_ADDR - (SOCINFO_WORD_ADDR << 2)) ++#define PRT_BEGIN_ALIGN (PRT_OFFSET_ADDR - (PRT_WORD_ADDR << 2)) ++#define HIDEBLK_BEGIN_ALIGN (HIDEBLK_OFFSET_ADDR - (HIDEBLK_WORD_ADDR << 2)) ++#define CHIPKEY_BEGIN_ALIGN (CHIPKEY_OFFSET_ADDR - (CHIPKEY_WORD_ADDR << 2)) ++#define USERKEY0_BEGIN_ALIGN (USERKEY0_OFFSET_ADDR - (USERKEY0_WORD_ADDR << 2)) ++#define USERKEY1_BEGIN_ALIGN (USERKEY1_OFFSET_ADDR - (USERKEY1_WORD_ADDR << 2)) ++#define NKU_BEGIN_ALIGN (NKU_OFFSET_ADDR - (NKU_WORD_ADDR << 2)) ++ ++ ++#define CHIPID_END_ALIGN (4 - CHIPID_BEGIN_ALIGN - (((CHIPID_BIT_NUM + CHIPID_EXT_BIT_NUM ) % 32) >> 3)) ++#define CUSTID0_END_ALIGN (4 - CUSTID0_BEGIN_ALIGN - (((CUSTID0_BIT_NUM + CUSTID0_EXT_BIT_NUM ) % 32) >> 3)) ++#define CUSTID1_END_ALIGN (4 - CUSTID1_BEGIN_ALIGN - (((CUSTID1_BIT_NUM + CUSTID1_EXT_BIT_NUM ) % 32) >> 3)) ++#define CUSTID2_END_ALIGN (4 - CUSTID2_BEGIN_ALIGN - (((CUSTID2_BIT_NUM + CUSTID2_EXT_BIT_NUM ) % 32) >> 3)) ++#define TRIM0_END_ALIGN (4 - TRIM0_BEGIN_ALIGN - (((TRIM0_BIT_NUM + TRIM0_EXT_BIT_NUM ) % 32) >> 3)) ++#define TRIM1_END_ALIGN (4 - TRIM1_BEGIN_ALIGN - (((TRIM1_BIT_NUM + TRIM1_EXT_BIT_NUM ) % 32) >> 3)) ++#define TRIM2_END_ALIGN (4 - TRIM2_BEGIN_ALIGN - (((TRIM2_BIT_NUM + TRIM2_EXT_BIT_NUM ) % 32) >> 3)) ++#define SOCINFO_END_ALIGN (4 - SOCINFO_BEGIN_ALIGN - (((SOCINFO_BIT_NUM + SOCINFO_EXT_BIT_NUM ) % 32) >> 3)) ++#define PRT_END_ALIGN (4 - PRT_BEGIN_ALIGN - (((PRT_BIT_NUM + PRT_EXT_BIT_NUM ) % 32) >> 3)) ++#define HIDEBLK_END_ALIGN (4 - HIDEBLK_BEGIN_ALIGN - (((HIDEBLK_BIT_NUM + HIDEBLK_EXT_BIT_NUM ) % 32) >> 3)) ++#define CHIPKEY_END_ALIGN (4 - CHIPKEY_BEGIN_ALIGN - (((CHIPKEY_BIT_NUM + CHIPKEY_EXT_BIT_NUM ) % 32) >> 3)) ++#define USERKEY0_END_ALIGN (4 - USERKEY0_BEGIN_ALIGN - (((USERKEY0_BIT_NUM + USERKEY0_EXT_BIT_NUM ) % 32) >> 3)) ++#define USERKEY1_END_ALIGN (4 - USERKEY1_BEGIN_ALIGN - (((USERKEY1_BIT_NUM + USERKEY1_EXT_BIT_NUM ) % 32) >> 3)) ++#define NKU_END_ALIGN (4 - NKU_BEGIN_ALIGN - (((NKU_BIT_NUM + NKU_EXT_BIT_NUM ) % 32) >> 3)) ++ ++ ++enum segment_id { ++ CHIPID = 0, ++ CUSTID0, ++ CUSTID1, ++ CUSTID2, ++ TRIM0, ++ TRIM1, ++ TRIM2, ++ SOCINFO, ++ PRT, ++ HIDEBLK, ++ CHIPKEY, ++ USERKEY0, ++ USERKEY1, ++ NKU ++}; ++ ++enum verify_mode { ++ NONE = 0, ++ DOUBLE, ++ HAMMING ++}; ++ ++struct seg_info { ++ char seg_name[32]; ++ uint32_t seg_id; ++ uint32_t word_address; ++ uint32_t word_num; ++ uint32_t bit_num; ++ uint32_t begin_align; ++ uint32_t end_align; ++ uint32_t prt_bit; ++ uint32_t verify_mode; ++}; ++ ++static struct seg_info seg_info_array[] = { ++ [0] = { ++ .seg_name = "CHIPID", ++ .seg_id = CHIPID, ++ .word_address = CHIPID_WORD_ADDR, ++ .begin_align = CHIPID_BEGIN_ALIGN, ++ .end_align = CHIPID_END_ALIGN, ++ .bit_num = CHIPID_BIT_NUM, ++ .word_num = CHIPID_WORD_NUM, ++ .prt_bit = EFUSE_STA_CHIPID_PRT, ++ .verify_mode = HAMMING, ++ }, ++ [1] = { ++ .seg_name = "CUSTID0", ++ .seg_id = CUSTID0, ++ .word_address = CUSTID0_WORD_ADDR, ++ .begin_align = CUSTID0_BEGIN_ALIGN, ++ .end_align = CUSTID0_END_ALIGN, ++ .bit_num = CUSTID0_BIT_NUM, ++ .word_num = CUSTID0_WORD_NUM, ++ .prt_bit = EFUSE_STA_CUSTID0_PRT, ++ .verify_mode = HAMMING, ++ }, ++ [2] = { ++ .seg_name = "CUSTID1", ++ .seg_id = CUSTID1, ++ .word_address = CUSTID1_WORD_ADDR, ++ .begin_align = CUSTID1_BEGIN_ALIGN, ++ .end_align = CUSTID1_END_ALIGN, ++ .bit_num = CUSTID1_BIT_NUM, ++ .word_num = CUSTID1_WORD_NUM, ++ .prt_bit = EFUSE_STA_CUSTID1_PRT, ++ .verify_mode = HAMMING, ++ }, ++ [3] = { ++ .seg_name = "CUSTID2", ++ .seg_id = CUSTID2, ++ .word_address = CUSTID2_WORD_ADDR, ++ .begin_align = CUSTID2_BEGIN_ALIGN, ++ .end_align = CUSTID2_END_ALIGN, ++ .bit_num = CUSTID2_BIT_NUM, ++ .word_num = CUSTID2_WORD_NUM, ++ .prt_bit = EFUSE_STA_CUSTID2_PRT, ++ .verify_mode = HAMMING, ++ }, ++ [4] = { ++ .seg_name = "TRIM0", ++ .seg_id = TRIM0, ++ .word_address = TRIM0_WORD_ADDR, ++ .begin_align = TRIM0_BEGIN_ALIGN, ++ .end_align = TRIM0_END_ALIGN, ++ .bit_num = TRIM0_BIT_NUM, ++ .word_num = TRIM0_WORD_NUM, ++ .prt_bit = EFUSE_STA_TRIM0_PRT, ++ .verify_mode = HAMMING, ++ }, ++ [5] = { ++ .seg_name = "TRIM1", ++ .seg_id = TRIM1, ++ .word_address = TRIM1_WORD_ADDR, ++ .begin_align = TRIM1_BEGIN_ALIGN, ++ .end_align = TRIM1_END_ALIGN, ++ .bit_num = TRIM1_BIT_NUM, ++ .word_num = TRIM1_WORD_NUM, ++ .prt_bit = EFUSE_STA_TRIM1_PRT, ++ .verify_mode = HAMMING, ++ }, ++ [6] = { ++ .seg_name = "TRIM2", ++ .seg_id = TRIM2, ++ .word_address = TRIM2_WORD_ADDR, ++ .begin_align = TRIM2_BEGIN_ALIGN, ++ .end_align = TRIM2_END_ALIGN, ++ .bit_num = TRIM2_BIT_NUM, ++ .word_num = TRIM2_WORD_NUM, ++ .prt_bit = EFUSE_STA_TRIM2_PRT, ++ .verify_mode = NONE, ++ }, ++ [7] = { ++ .seg_name = "SOCINFO", ++ .seg_id = SOCINFO, ++ .word_address = SOCINFO_WORD_ADDR, ++ .begin_align = SOCINFO_BEGIN_ALIGN, ++ .end_align = SOCINFO_END_ALIGN, ++ .bit_num = SOCINFO_BIT_NUM + SOCINFO_EXT_BIT_NUM, ++ .word_num = SOCINFO_WORD_NUM, ++ .prt_bit = EFUSE_STA_SOCINFO_PRT, ++ .verify_mode = DOUBLE, ++ }, ++ [8] = { ++ .seg_name = "PRT", ++ .seg_id = PRT, ++ .word_address = PRT_WORD_ADDR, ++ .begin_align = PRT_BEGIN_ALIGN, ++ .end_align = PRT_END_ALIGN, ++ .bit_num = PRT_BIT_NUM + PRT_EXT_BIT_NUM, ++ .word_num = PRT_WORD_NUM, ++ .prt_bit = 0xffffffff, ++ .verify_mode = DOUBLE, ++ }, ++ [9] = { ++ .seg_name = "HIDEBLK", ++ .seg_id = HIDEBLK, ++ .word_address = HIDEBLK_WORD_ADDR, ++ .begin_align = HIDEBLK_BEGIN_ALIGN, ++ .end_align = HIDEBLK_END_ALIGN, ++ .bit_num = HIDEBLK_BIT_NUM, ++ .word_num = HIDEBLK_WORD_NUM, ++ .prt_bit = EFUSE_STA_HIDEBLK_PRT, ++ .verify_mode = HAMMING, ++ }, ++ [10] = { ++ .seg_name = "CHIPKEY", ++ .seg_id = CHIPKEY, ++ .word_address = CHIPKEY_WORD_ADDR, ++ .begin_align = CHIPKEY_BEGIN_ALIGN, ++ .end_align = CHIPKEY_END_ALIGN, ++ .bit_num = CHIPKEY_BIT_NUM, ++ .word_num = CHIPKEY_WORD_NUM, ++ .prt_bit = EFUSE_STA_CHIPKEY_PRT, ++ .verify_mode = HAMMING, ++ }, ++ [11] = { ++ .seg_name = "USERKEY0", ++ .seg_id = USERKEY0, ++ .word_address = USERKEY0_WORD_ADDR, ++ .begin_align = USERKEY0_BEGIN_ALIGN, ++ .end_align = USERKEY0_END_ALIGN, ++ .bit_num = USERKEY0_BIT_NUM, ++ .word_num = USERKEY0_WORD_NUM, ++ .prt_bit = EFUSE_STA_USERKEY0_PRT, ++ .verify_mode = HAMMING, ++ }, ++ [12] = { ++ .seg_name = "USERKEY1", ++ .seg_id = USERKEY1, ++ .word_address = USERKEY1_WORD_ADDR, ++ .begin_align = USERKEY1_BEGIN_ALIGN, ++ .end_align = USERKEY1_END_ALIGN, ++ .bit_num = USERKEY1_BIT_NUM, ++ .word_num = USERKEY1_WORD_NUM, ++ .prt_bit = EFUSE_STA_USERKEY1_PRT, ++ .verify_mode = HAMMING, ++ }, ++ [13] = { ++ .seg_name = "NKU", ++ .seg_id = NKU, ++ .word_address = NKU_WORD_ADDR, ++ .begin_align = NKU_BEGIN_ALIGN, ++ .end_align = NKU_END_ALIGN, ++ .bit_num = NKU_BIT_NUM, ++ .word_num = NKU_WORD_NUM, ++ .prt_bit = EFUSE_STA_NKU_PRT, ++ .verify_mode = HAMMING, ++ }, ++}; ++ ++void jz_efuse_id_read(int is_chip_id, uint32_t *buf); ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2000/include/soc/extal.h b/arch/mips/xburst2/soc-x2000/include/soc/extal.h +new file mode 100644 +index 000000000..398b5912f +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/soc/extal.h +@@ -0,0 +1,12 @@ ++ ++#ifndef __JZSOC_EXTAL_H__ ++#define __JZSOC_EXTAL_H__ ++ ++#define JZ_EXTAL_RTC 32768 /* RTC extal freq: 32.768 KHz */ ++#define JZ_EXTAL (CONFIG_EXTAL_CLOCK * 1000000) ++ ++#ifdef CONFIG_PALLADIUM_PLATFORM ++#define PALLADIUM_CLK_INPURT (500*1000000) ++#endif ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2000/include/soc/gpio.h b/arch/mips/xburst2/soc-x2000/include/soc/gpio.h +new file mode 100644 +index 000000000..25656adc5 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/soc/gpio.h +@@ -0,0 +1,42 @@ ++#ifndef _SOC_GPIO_H_ ++#define _SOC_GPIO_H_ ++ ++enum gpio_function { ++ GPIO_FUNC_0 = 0x10, //0000, GPIO as function 0 / device 0 ++ GPIO_FUNC_1 = 0x11, //0001, GPIO as function 1 / device 1 ++ GPIO_FUNC_2 = 0x12, //0010, GPIO as function 2 / device 2 ++ GPIO_FUNC_3 = 0x13, //0011, GPIO as function 3 / device 3 ++ GPIO_OUTPUT0 = 0x14, //0100, GPIO output low level ++ GPIO_OUTPUT1 = 0x15, //0101, GPIO output high level ++ GPIO_INPUT = 0x16, //0110, GPIO as input.7 also. ++ GPIO_INT_LO = 0x18, //1000, Low Level trigger interrupt ++ GPIO_INT_HI = 0x19, //1001, High Level trigger interrupt ++ GPIO_INT_FE = 0x1a, //1010, Fall Edge trigger interrupt ++ GPIO_INT_RE = 0x1b, //1011, Rise Edge trigger interrupt ++ GPIO_INT_MASK_LO = 0x1c, //1100, Port is low level triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_HI = 0x1d, //1101, Port is high level triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_FE = 0x1e, //1110, Port is fall edge triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_RE = 0x1f, //1111, Port is rise edge triggered interrupt input. Interrupt is masked. ++ ++ GPIO_PULL_HIZ = 0x80, //no pull ++ GPIO_PULL_UP = 0xa0, //pull high ++ GPIO_PULL_DOWN = 0xc0, //pull low ++}; ++ ++#define GPIO_PA(n) (0 * 32 + (n)) ++#define GPIO_PB(n) (1 * 32 + (n)) ++#define GPIO_PC(n) (2 * 32 + (n)) ++#define GPIO_PD(n) (3 * 32 + (n)) ++#define GPIO_PE(n) (4 * 32 + (n)) ++#define GPIO_PF(n) (5 * 32 + (n)) ++ ++enum gpio_port { ++ GPIO_PORT_A, GPIO_PORT_B, ++ GPIO_PORT_C, GPIO_PORT_D, GPIO_PORT_E, ++ /* this must be last */ ++ GPIO_NR_PORTS, ++}; ++ ++int jzgpio_set_func(int port, enum gpio_function func, unsigned long pins); ++ ++#endif /* _SOC_GPIO_H_ */ +diff --git a/arch/mips/xburst2/soc-x2000/include/soc/rtc.h b/arch/mips/xburst2/soc-x2000/include/soc/rtc.h +new file mode 100644 +index 000000000..871add1fc +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/soc/rtc.h +@@ -0,0 +1,96 @@ ++#ifndef __RTC_H__ ++#define __RTC_H__ ++ ++/* ++ * RTC registers offset address definition ++ */ ++#define RTC_RTCCR (0x00) /* rw, 32, 0x00000081 */ ++#define RTC_RTCSR (0x04) /* rw, 32, 0x???????? */ ++#define RTC_RTCSAR (0x08) /* rw, 32, 0x???????? */ ++#define RTC_RTCGR (0x0c) /* rw, 32, 0x0??????? */ ++ ++#define RTC_HCR (0x20) /* rw, 32, 0x00000000 */ ++#define RTC_HWFCR (0x24) /* rw, 32, 0x0000???0 */ ++#define RTC_HRCR (0x28) /* rw, 32, 0x00000??0 */ ++#define RTC_HWCR (0x2c) /* rw, 32, 0x00000008 */ ++#define RTC_HWRSR (0x30) /* rw, 32, 0x00000000 */ ++#define RTC_HSPR (0x34) /* rw, 32, 0x???????? */ ++#define RTC_WENR (0x3c) /* rw, 32, 0x00000000 */ ++#define RTC_WKUPPINCR (0x48) /* rw, 32, 0x00050064*/ ++ ++/* ++ * RTC registers common define ++ */ ++ ++/* RTC control register(RTCCR) */ ++#define RTCCR_WRDY BIT(7) ++#define RTCCR_1HZ BIT(6) ++#define RTCCR_1HZIE BIT(5) ++#define RTCCR_AF BIT(4) ++#define RTCCR_AIE BIT(3) ++#define RTCCR_AE BIT(2) ++#define RTCCR_SELEXC BIT(1) ++#define RTCCR_RTCE BIT(0) ++ ++ ++/* Generate the bit field mask from msb to lsb */ ++#define BITS_H2L(msb, lsb) ((0xFFFFFFFF >> (32-((msb)-(lsb)+1))) << (lsb)) ++ ++/* RTC regulator register(RTCGR) */ ++#define RTCGR_LOCK BIT(31) ++#define RTCGR_ADJC_LSB 16 ++#define RTCGR_ADJC_MASK BITS_H2L(25, RTCGR_ADJC_LSB) ++#define RTCGR_NC1HZ_LSB 0 ++#define RTCGR_NC1HZ_MASK BITS_H2L(15, RTCGR_NC1HZ_LSB) ++ ++/* Hibernate control register(HCR) */ ++#define HCR_PD BIT(0) ++ ++/* Hibernate wakeup filter counter register(HWFCR) */ ++#define HWFCR_LSB 5 ++#define HWFCR_MASK BITS_H2L(15, HWFCR_LSB) ++#define HWFCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000+0xf) > HWFCR_MASK ? HWFCR_MASK : ((ms)*(clk)/1000+0xf) & HWFCR_MASK) ++ ++/* Hibernate reset counter register(HRCR) */ ++#define HRCR_LSB 11 ++#define HRCR_MASK BITS_H2L(14, HRCR_LSB) ++#define HRCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000 + 0x3ff - 0x800) > HRCR_MASK ? HRCR_MASK : \ ++ ((ms)*(clk)/1000 + 0x3ff - 0x800) & HRCR_MASK) ++ ++ ++/* Hibernate wakeup control register(HWCR) */ ++/* Power detect default value; this value means enable */ ++#define EPDET_LSB 3 ++#define EPDET_DEFAULT (0x5aa5a5a << EPDET_LSB) ++#define EPDET_ENABLE (0x5aa5a5a << EPDET_LSB) ++#define EPDET_DISABLE (0x1a55a5a5 << EPDET_LSB) ++#define HWCR_EALM BIT(0) ++ ++ ++/* Hibernate wakeup status register(HWRSR) */ ++#define HWRSR_APD BIT(8) ++#define HWRSR_HR BIT(5) ++#define HWRSR_PPR BIT(4) ++#define HWRSR_PIN BIT(1) ++#define HWRSR_ALM BIT(0) ++ ++/* write enable pattern register(WENR) */ ++#define WENR_WEN BIT(31) ++#define WENR_WENPAT_LSB 0 ++#define WENR_WENPAT_MASK BITS_H2L(15, WENR_WENPAT_LSB) ++#define WENR_WENPAT_WRITABLE (0xa55a) ++ ++/* Hibernate scratch pattern register(HSPR) */ ++#define HSPR_RTCV 0x52544356 /* The value is 'RTCV', means rtc is valid */ ++ ++/*WKUP_PIN_RST control register (WKUPPINCR)*/ ++#define WKUPPINCR_BIAS_CTRL (0x1 << 16) /* fix value*/ ++#define WKUPPINCR_OSC_EN BIT(18) ++#define WKUPPINCR_P_JUD_LEN_LSB 4 ++#define WKUPPINCR_P_JUD_LEN_MASK BITS_H2L(7, WKUPPINCR_P_JUD_LEN_LSB) ++#define WKUPPINCR_P_JUD_LEN(s) ((s) << WKUPPINCR_P_JUD_LEN_LSB) > WKUPPINCR_P_JUD_LEN_MASK ? \ ++ WKUPPINCR_P_JUD_LEN_MASK : (s) << WKUPPINCR_P_JUD_LEN_LSB ++#define WKUPPINCR_P_JUD_EN (0x4) ++/* The divider is decided by the RTC clock frequency. */ ++#define RTC_FREQ_DIVIDER (32768 - 1) ++#endif /* __RTC_H__ */ +diff --git a/arch/mips/xburst2/soc-x2000/include/soc/sfc.h b/arch/mips/xburst2/soc-x2000/include/soc/sfc.h +new file mode 100644 +index 000000000..b1684bec9 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/soc/sfc.h +@@ -0,0 +1,211 @@ ++#ifndef __SFC_REGISTER_H ++#define __SFC_REGISTER_H ++ ++/* SFC register */ ++ ++#define SFC_GLB0 (0x0000) ++#define SFC_DEV_CONF (0x0004) ++#define SFC_DEV_STA_EXP (0x0008) ++#define SFC_DEV0_STA_RT (0x000c) ++#define SFC_DEV_STA_MSK (0x0010) ++#define SFC_TRAN_CONF0(n) (0x0014 + (n * 4)) ++#define SFC_TRAN_LEN (0x002c) ++#define SFC_DEV_ADDR(n) (0x0030 + (n * 4)) ++#define SFC_DEV_ADDR_PLUS(n) (0x0048 + (n * 4)) ++#define SFC_MEM_ADDR (0x0060) ++#define SFC_TRIG (0x0064) ++#define SFC_SR (0x0068) ++#define SFC_SCR (0x006c) ++#define SFC_INTC (0x0070) ++#define SFC_FSM (0x0074) ++#define SFC_CGE (0x0078) ++#define SFC_CMD_IDX (0x007c) ++#define SFC_COL_ADDR (0x0080) ++#define SFC_ROW_ADDR (0x0084) ++#define SFC_STA_ADDR0 (0x0088) ++#define SFC_STA_ADDR1 (0x008c) ++#define SFC_DES_ADDR (0x0090) ++#define SFC_GLB1 (0x0094) ++#define SFC_DEV1_STA_RT (0x0098) ++#define SFC_TRAN_CONF1(n) (0x009c + (n * 4)) ++#define SFC_CDT (0x0800) //0x800 ~ 0xbff ++#define SFC_RM_DR (0x1000) ++ ++/* For SFC_GLB0 */ ++#define GLB0_POLL_TIME_OFFSET (16) ++#define GLB0_POLL_TIME_MSK (0xffff << GLB0_POLL_TIME_OFFSET) ++#define GLB0_DES_EN (1 << 15) ++#define GLB0_CDT_EN (1 << 14) ++#define GLB0_TRAN_DIR (1 << 13) ++#define GLB0_TRAN_DIR_WRITE (1) ++#define GLB0_TRAN_DIR_READ (0) ++#define GLB0_THRESHOLD_OFFSET (7) ++#define GLB0_THRESHOLD_MSK (0x3f << GLB0_THRESHOLD_OFFSET) ++#define GLB0_OP_MODE (1 << 6) ++#define GLB0_OP_OFFSET (6) ++#define SLAVE_MODE (0x0) ++#define DMA_MODE (0x1) ++#define GLB0_PHASE_NUM_OFFSET (3) ++#define GLB0_PHASE_NUM_MSK (0x7 << GLB0_PHASE_NUM_OFFSET) ++#define GLB0_WP_EN (1 << 2) ++#define GLB0_BURST_MD_OFFSET (0) ++#define GLB0_BURST_MD_MSK (0x3 << GLB0_BURST_MD_OFFSET) ++ ++/* For SFC_DEV_CONF */ ++#define DEV_CONF_STA_ENDIAN_OFFSET (31) ++#define STA_ENDIAN_LSB (0) ++#define STA_ENDIAN_MSB (1) ++#define DEV_CONF_SMP_DELAY_OFFSET (16) ++#define DEV_CONF_SMP_DELAY_MSK (0x1f << DEV_CONF_SMP_DELAY_OFFSET) ++#define DEV_CONF_SMP_DELAY_0 (0) ++#define DEV_CONF_SMP_DELAY_45 (1) ++#define DEV_CONF_SMP_DELAY_90 (2) ++#define DEV_CONF_SMP_DELAY_135 (3) ++#define DEV_CONF_SMP_DELAY_180 (4) ++#define DEV_CONF_SMP_DELAY_225 (5) ++#define DEV_CONF_SMP_DELAY_270 (6) ++#define DEV_CONF_SMP_DELAY_315 (7) ++#define DEV_CONF_SMP_DELAY_1 (8) ++#define DEV_CONF_SMP_DELAY_2 (16) ++#define DEV_CONF_CMD_TYPE (0x1 << 15) ++#define DEV_CONF_STA_TYPE_OFFSET (13) ++#define DEV_CONF_STA_TYPE_MSK (0x3 << DEV_CONF_STA_TYPE_OFFSET) ++#define DEV_CONF_THOLD_OFFSET (11) ++#define DEV_CONF_THOLD_MSK (0x3 << DEV_CONF_THOLD_OFFSET) ++#define DEV_CONF_TSETUP_OFFSET (9) ++#define DEV_CONF_TSETUP_MSK (0x3 << DEV_CONF_TSETUP_OFFSET) ++#define DEV_CONF_TSH_OFFSET (5) ++#define DEV_CONF_TSH_MSK (0xf << DEV_CONF_TSH_OFFSET) ++#define DEV_CONF_CPHA (0x1 << 4) ++#define DEV_CONF_CPOL (0x1 << 3) ++#define DEV_CONF_CEDL (0x1 << 2) ++#define DEV_CONF_HOLDDL (0x1 << 1) ++#define DEV_CONF_WPDL (0x1 << 0) ++ ++/* For SFC_TRAN_CONF0 */ ++#define TRAN_CONF0_CLK_MODE (29) ++#define TRAN_CONF0_CLK_MODE_MSK (0x7 << TRAN_CONF0_CLK_MODE) ++#define TRAN_CONF0_CLK_MODE_SSS (0) ++#define TRAN_CONF0_CLK_MODE_SSD (1) ++#define TRAN_CONF0_CLK_MODE_SDS (2) ++#define TRAN_CONF0_CLK_MODE_SDD (3) ++#define TRAN_CONF0_CLK_MODE_DSS (4) ++#define TRAN_CONF0_CLK_MODE_DSD (5) ++#define TRAN_CONF0_CLK_MODE_DDS (6) ++#define TRAN_CONF0_CLK_MODE_DDD (7) ++#define TRAN_CONF0_ADDR_WIDTH_OFFSET (26) ++#define TRAN_CONF0_ADDR_WIDTH_MSK (0x7 << TRAN_CONF0_ADDR_WIDTH_OFFSET) ++#define TRAN_CONF0_POLLEN (1 << 25) ++#define TRAN_CONF0_POLL_OFFSET (25) ++#define TRAN_CONF0_CMDEN (1 << 24) ++#define TRAN_CONF0_FMAT (1 << 23) ++#define TRAN_CONF0_FMAT_OFFSET (23) ++#define TRAN_CONF0_DMYBITS_OFFSET (17) ++#define TRAN_CONF0_DMYBITS_MSK (0x3f << TRAN_CONF0_DMYBITS_OFFSET) ++#define TRAN_CONF0_DATEEN (1 << 16) ++#define TRAN_CONF0_DATEEN_OFFSET (16) ++#define TRAN_CONF0_CMD_OFFSET (0) ++#define TRAN_CONF0_CMD_MSK (0xffff << TRAN_CONF0_CMD_OFFSET) ++ ++/* For SFC_TRAN_CONF1 */ ++#define TRAN_CONF1_DATA_ENDIAN (1 << 18) ++#define TRAN_CONF1_DATA_ENDIAN_OFFSET (18) ++#define TRAN_CONF1_DATA_ENDIAN_LSB (0) ++#define TRAN_CONF1_DATA_ENDIAN_MSB (1) ++#define TRAN_CONF1_WORD_UNIT_OFFSET (16) ++#define TRAN_CONF1_WORD_UNIT_MSK (3 << 16) ++#define TRAN_CONF1_TRAN_MODE_OFFSET (4) ++#define TRAN_CONF1_TRAN_MODE_MSK (0xf << TRAN_CONF1_TRAN_MODE_OFFSET) ++#define TRAN_CONF1_SPI_STANDARD (0x0) ++#define TRAN_CONF1_SPI_DUAL (0x1) ++#define TRAN_CONF1_SPI_QUAD (0x5) ++#define TRAN_CONF1_SPI_IO_QUAD (0x6) ++#define TRAN_CONF1_SPI_OCTAL (0x9) ++#define TRAN_CONF1_SPI_IO_OCTAL (0xa) ++#define TRAN_CONF1_SPI_FULL_OCTAL (0xb) ++ ++ ++/* For SFC_TRIG */ ++#define TRIG_FLUSH (1 << 2) ++#define TRIG_STOP (1 << 1) ++#define TRIG_START (1 << 0) ++ ++/* For SFC_SR */ ++#define SFC_WORKING (1 << 7) ++#define SFC_BUSY (0x3 << 5) ++#define SFC_END (1 << 4) ++#define SFC_TREQ (1 << 3) ++#define SFC_RREQ (1 << 2) ++#define SFC_OVER (1 << 1) ++#define SFC_UNDER (1 << 0) ++ ++/* For SFC_SCR */ ++#define CLR_END (1 << 4) ++#define CLR_TREQ (1 << 3) ++#define CLR_RREQ (1 << 2) ++#define CLR_OVER (1 << 1) ++#define CLR_UNDER (1 << 0) ++ ++//SFC_CMD_IDX ++#define CMD_IDX_MSK (0x3f << 0) ++#define CDT_DATAEN_MSK (0x1 << 31) ++#define CDT_DATAEN_OFF (31) ++#define CDT_DIR_MSK (0x1 << 30) ++#define CDT_DIR_OFF (30) ++ ++/* For SFC_GLB1 */ ++#define GLB1_DQS_EN (1 << 2) ++#define GLB1_CHIP_SEL_OFFSET (0) ++#define GLB1_CHIP_SEL_MSK (0x3 << 0) ++#define GLB1_CHIP_SEL_0 (0) ++#define GLB1_CHIP_SEL_1 (1) ++#define GLB1_CHIP_SEL_01 (2) ++ ++#define N_MAX 6 ++#define MAX_SEGS 128 ++ ++#define CHANNEL_0 0 ++#define CHANNEL_1 1 ++#define CHANNEL_2 2 ++#define CHANNEL_3 3 ++#define CHANNEL_4 4 ++#define CHANNEL_5 5 ++ ++#define ENABLE 1 ++#define DISABLE 0 ++ ++#define COM_CMD 1 // common cmd ++#define POLL_CMD 2 // the cmd will poll the status of flash,ext: read status ++ ++#define DMA_OPS 1 ++#define CPU_OPS 0 ++ ++#define TM_STD_SPI 0 ++#define TM_DI_DO_SPI 1 ++#define TM_DIO_SPI 2 ++#define TM_FULL_DIO_SPI 3 ++#define TM_QI_QO_SPI 5 ++#define TM_QIO_SPI 6 ++#define TM_FULL_QIO_SPI 7 ++#define TM_OCTAL_SPT 9 ++#define TM_OCTAL_IO_SPI 10 ++#define TM_OCTAL_FULL_SPI 11 ++ ++ ++#define DEFAULT_CDT 1 ++#define UPDATE_CDT 2 ++#define DEFAULT_ADDRSIZE 3 ++#define DEFAULT_ADDRMODE 0 ++ ++ ++#define THRESHOLD 32 ++ ++#define SFC_NOR_RATE 110 ++#define DEF_ADDR_LEN 3 ++#define DEF_TCHSH 6 ++#define DEF_TSLCH 6 ++#define DEF_TSHSL_R 20 ++#define DEF_TSHSL_W 50 ++ ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2000/include/soc/tcsm_layout.h b/arch/mips/xburst2/soc-x2000/include/soc/tcsm_layout.h +new file mode 100644 +index 000000000..2de46b7bd +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/soc/tcsm_layout.h +@@ -0,0 +1,53 @@ ++#ifndef __TCSM_LAYOUT_H__ ++#define __TCSM_LAYOUT_H__ ++ ++/** ++ * |-------------| ++ * | BANK0 | ++ * |-------------| <--- SLEEP_TCSM_BOOTCODE_TEXT ++ * | BOOT CODE | ++ * |-------------| <--- SLEEP_TCSM_RESUMECODE_TEXT ++ * | ... | ++ * | RESUME CODE | ++ * | ... | ++ * |-------------| <--- SLEEP_TCSM_RESUME_DATA ++ * | ... | ++ * | RESUME DATA | ++ * | ... | ++ * |_____________| <--- SLEEP_TCSM_CPU_RESMUE_SP ++ * ++ * ++ * |-------------| ++ * | BANK1 | ++ * |-------------| <--- TO BE DEFINED ++ * | | ++ * | | ++ * | ... | ++ * | VOICE DATA | ++ * | ... | ++ * | | ++ * | | ++ * |_____________| ++ * ++ */ ++ ++#define SLEEP_TCSM_SPACE 0xb3422000 ++#define VOICE_TCSM_DATA_BUF 0xb3423000 ++#define TCSM_BANK_LEN 4096 ++ ++#define SLEEP_TCSM_BOOT_TEXT (SLEEP_TCSM_SPACE) ++#define SLEEP_TCSM_BOOT_LEN 64 ++#define SLEEP_TCSM_BOOT_END (SLEEP_TCSM_BOOT_TEXT + SLEEP_TCSM_BOOT_LEN) ++ ++#define SLEEP_TCSM_RESUME_TEXT (SLEEP_TCSM_BOOT_END) ++#define SLEEP_TCSM_RESUME_LEN 2048 ++#define SLEEP_TCSM_RESUME_END (SLEEP_TCSM_RESUME_TEXT + SLEEP_TCSM_RESUME_LEN) ++ ++#define SLEEP_TCSM_RESUME_DATA (SLEEP_TCSM_RESUME_END) ++ ++#define SLEEP_TCSM_SPACE_END (SLEEP_TCSM_SPACE + TCSM_BANK_LEN) ++ ++#define SLEEP_TCSM_CPU_RESMUE_SP SLEEP_TCSM_SPACE_END - 4 ++ ++ ++#endif /* __TCSM_LAYOUT_H__ */ +diff --git a/arch/mips/xburst2/soc-x2000/include/war.h b/arch/mips/xburst2/soc-x2000/include/war.h +new file mode 100644 +index 000000000..fd1ef3147 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/include/war.h +@@ -0,0 +1,27 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MACH_INGENIC_WAR_H__ ++#define __ASM_MACH_INGENIC_WAR_H__ ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 1 ++#define MIPS_BRIDGE_SYNC_WAR 1 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif ++ +diff --git a/arch/mips/xburst2/soc-x2000/libdmmu.c b/arch/mips/xburst2/soc-x2000/libdmmu.c +new file mode 100644 +index 000000000..e3288d299 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/libdmmu.c +@@ -0,0 +1,1087 @@ ++/* ++ * This driver is used by VPU driver. ++ * ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: Yan Zhengting ++ * Modify by: Sun Jiwei ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#define print_dbg(f, arg...) printk(KERN_INFO "dpu: %s, %d: " f "\n", __func__, __LINE__, ## arg) ++ ++#define MAP_COUNT 0x10 ++#define MAP_CONUT_MASK 0xff0 ++ ++#define DMMU_PTE_VLD 0x01 ++#define DMMU_PMD_VLD 0x01 ++ ++#define KSEG0_LOW_LIMIT 0x80000000 ++#define KSEG1_HEIGH_LIMIT 0xC0000000 ++ ++enum mem_break{ ++ MODE1, /* 13 24 57 68 911 1012 ... */ ++ MODE2, /* 13 24 35 46 57 68 79 810 ... */ ++ MODE3 /* 12 34 56 78 ... */ ++}; ++ ++LIST_HEAD(handle_list); ++static unsigned long reserved_pte = 0; ++static unsigned long res_pte_paddr; ++ ++struct pmd_node { ++ unsigned int count; ++ unsigned long index; ++ unsigned long page; ++ struct list_head list; ++}; ++ ++struct map_node { ++ struct device *dev; ++ unsigned long start; ++ unsigned long len; ++ struct list_head list; ++}; ++ ++struct dmmu_handle { ++ pid_t tgid; ++ unsigned long pdg; ++ struct mutex lock; ++ struct list_head list; ++ struct list_head pmd_list; ++ struct list_head map_list; ++ struct list_head dev_notifier_list; ++ ++ struct mm_struct *handle_mm; /* mm struct used to match exit_mmap notify */ ++ ++ struct mmu_notifier mn; ++}; ++ ++/* for test */ ++static struct dmmu_handle *find_handle(void); ++static struct dmmu_handle *create_handle(void); ++static void dmmu_cache_wback(struct dmmu_handle *h); ++static int dmmu_mm_dev_release(struct dmmu_handle *h); ++ ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h = NULL; ++ struct map_node *n = NULL; ++ unsigned long *pgd, *pte_phys, *pte; ++ unsigned long virpage_phy; ++ unsigned long v_end = vaddr+len; ++ int found = 0; ++ int index; ++ ++ h = find_handle(); ++ if(!h){ ++ printk("%s find handle err!\n",__func__); ++ return -1; ++ } ++ if (vaddr & 0xfff) { ++ printk("%s addr align page err!\n",__func__); ++ return -1; ++ } ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if((vaddr >= n->start) && ++ ((vaddr+len) <= (n->start + n->len))) { ++ found = 1; ++ break; ++ } ++ } ++ if(!found) { ++ printk("%s addr err!\n",__func__); ++ return -1; ++ } ++ pgd = (unsigned long *)h->pdg; ++ while(vaddr < v_end) { ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ index = ((vaddr & 0x3ff000) >> 12); ++ virpage_phy = pte[index] & ~DMMU_PTE_VLD; ++ dma_cache_wback((unsigned long)phys_to_virt(virpage_phy),PAGE_SIZE); ++ vaddr+=PAGE_SIZE; ++ } ++ return 0; ++} ++ ++EXPORT_SYMBOL(dmmu_flush_cache); ++static int make_smash_list(struct dmmu_handle *h, unsigned long vaddr, unsigned long (**base)[2], unsigned int *len) ++{ ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *pte, *pte_phys; ++ unsigned int i, index; ++ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start) { ++ list_len = (n->len) >> 12; ++ break; ++ } ++ } ++ ++ if (list_len) { ++ list_smash = kmalloc(list_len * 2 * 4, GFP_KERNEL); ++ if (list_smash) { ++ i = 0; ++ while(i < list_len) { ++ list_smash[i][0] = (unsigned long)(vaddr & 0xfffff000); ++ ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ ++ ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++// printk(">>>>>>virt = 0x%lx, phys = 0x%lx\n", vaddr, ++// *((unsigned long int *) (((unsigned long)pte_phys+index*4) | 0xa0000000))); ++ list_smash[i][1] = pte[index]; ++ ++ vaddr+=0x1000; ++ i++; ++ } ++ } ++ } ++ ++ if (list_smash) { ++ *base = list_smash; ++ *len = list_len; ++ return 0; ++ } else { ++ return -1; ++ } ++} ++EXPORT_SYMBOL(dmmu_dump_map); ++ ++int dmmu_dump_map(unsigned long vaddr) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *tmp; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return -1; ++ /* 检查4kå¯¹é½ */ ++ if (vaddr & 0xfff){ ++ return -1; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ unsigned int i; ++ for (i = 0; i phys: 0x%08lx] uncache: 0x%08lx\n", ++ list_smash[i][0],list_smash[i][1],(unsigned long)tmp); ++ ++ printk("value[0] = 0x%08lx, value[1] = 0x%08lx value[2] = 0x%08lx value[1013] = 0x%08lx\n", ++ tmp[0], tmp[1], tmp[2], tmp[1013]); ++ } ++ } ++ ++ mutex_unlock(&h->lock); ++ kfree((void*)list_smash); ++ ++ return 0; ++} ++ ++ /* 13 24 57 68 911 1012 ... */ ++static int smash_mode1(unsigned long (*base)[2], unsigned int len) ++{ ++ unsigned int i; ++ unsigned long tmp; ++ if (len >= 4) { ++ for (i=0; i= 4) { ++ for (i=0; ipdg; ++ unsigned long *pte; ++ unsigned int i, index; ++ ++ for (i=0; i>22; ++ pte = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++ pte[index] = (*base)[i][1]; ++ vaddr+=0x1000; ++ } ++ return 0; ++} ++ ++static int update_process_pte(unsigned long vaddr, unsigned long (**base)[2], unsigned int len) ++{ ++ unsigned int i; ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ spin_lock(¤t->mm->page_table_lock); ++ for (i=0; imm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) ++ return 0; ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) ++ return 0; ++ pte = pte_offset_kernel(pmdir,vaddr); ++ if (pte_present(*pte)){ ++ pte->pte = (*base)[i][1]; ++ } ++ vaddr += 4096; ++ } ++ spin_unlock(¤t->mm->page_table_lock); ++ return 0; ++} ++ ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ struct vm_area_struct * vma; ++ ++ h = find_handle(); ++ if(!h){ ++ h = create_handle(); ++ } ++ if(!h) ++ return -1; ++ ++ /* 检查4kå¯¹é½ */ ++ if (vaddr & 0xfff){ ++ return -1; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ switch (smash_mode) { ++ case MODE1: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode1(list_smash, list_len); ++ break; ++ case MODE2: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode2(list_smash, list_len); ++ break; ++ case MODE3: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode3(list_smash, list_len); ++ break; ++ default: ++ break; ++ } ++ } ++ update_dmmu_pte(h, vaddr, &list_smash, list_len); ++ update_process_pte(vaddr, &list_smash, list_len); ++ ++ dmmu_cache_wback(h); ++ vma = find_vma(current->mm, vaddr); ++ flush_tlb_range(vma, vaddr, vaddr+(list_len*PAGE_SIZE)); ++ ++ mutex_unlock(&h->lock); ++ kfree(list_smash); ++ ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_memory_smash); ++ ++static struct map_node *check_map(struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start && len == n->len) ++ return n; ++ } ++ return NULL; ++} ++ ++static void handle_add_map(struct device *dev,struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct map_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ if(n == NULL) { ++ printk("malloc map_list node failed !!\n"); ++ return; ++ } ++ n->dev = dev; ++ n->start = vaddr; ++ n->len = len; ++ INIT_LIST_HEAD(&n->list); ++ list_add(&n->list,&h->map_list); ++} ++ ++static unsigned int get_pfn(unsigned int vaddr) ++{ ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ pgdir = pgd_offset(current->mm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) { ++ return 0; ++ } ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) { ++ return 0; ++ } ++ // TODO: 如果是kmap的地å€ï¼Œæ¯”如C空间的地å€è¿™é‡Œéœ€è¦å¤„ç†ä¸€ä¸‹ä½¿ç”¨pte_offset_kmap. ++ pte = pte_offset_kernel(pmdir,vaddr); ++ if (pte_present(*pte)) { ++ ++ return pte_pfn(*pte) << PAGE_SHIFT; ++ } ++ ++ return 0; ++} ++ ++static unsigned long dmmu_v2pfn(unsigned long vaddr) ++{ ++ if(vaddr < KSEG0_LOW_LIMIT) ++ return get_pfn(vaddr); ++ ++ if(vaddr >= KSEG0_LOW_LIMIT && vaddr < KSEG1_HEIGH_LIMIT) ++ return virt_to_phys((void *)vaddr); ++ ++ panic("dmmu_v2pfn error!"); ++ return 0; ++} ++ ++static unsigned long unmap_node(struct pmd_node *n,unsigned long vaddr,unsigned long end,int check) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ int free = !check || (--n->count == 0); ++ struct page *page = NULL; ++ ++ if(vaddr && end) { ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] & MAP_CONUT_MASK) { ++ pte[index] -= MAP_COUNT; ++ } else { ++ page = pfn_to_page(pte[index] >> PAGE_SHIFT); ++ ++ ClearPageReserved(page); ++ pte[index] = reserved_pte; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ } ++ ++ if(free) { ++ ClearPageReserved(virt_to_page((void *)n->page)); ++ free_page(n->page); ++ list_del(&n->list); ++ kfree(n); ++ } ++ ++ return vaddr; ++} ++ ++static unsigned long map_node(struct pmd_node *n,unsigned int vaddr,unsigned int end) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ struct page * page = NULL; ++ unsigned long pfn = 0; ++ ++ ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] == reserved_pte) { ++ ++ mmap_write_lock(current->mm); ++ ++ pfn = dmmu_v2pfn(vaddr) >> PAGE_SHIFT; ++ page = pfn_to_page(pfn); ++ ++ SetPageReserved(page); ++ ++ pte[index] = (pfn << PAGE_SHIFT) | DMMU_PTE_VLD; ++ ++ mmap_write_unlock(current->mm); ++ } else { ++ pte[index] += MAP_COUNT; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ n->count++; ++ return vaddr; ++} ++ ++static struct pmd_node *find_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ if(n->index == (vaddr & 0xffc00000)) ++ return n; ++ } ++ return NULL; ++} ++ ++static struct pmd_node *add_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ int i; ++ unsigned long *pte; ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ struct pmd_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ INIT_LIST_HEAD(&n->list); ++ n->count = 0; ++ n->index = vaddr & 0xffc00000; ++ n->page = __get_free_page(GFP_KERNEL); ++ SetPageReserved(virt_to_page((void *)n->page)); ++ ++ pte = (unsigned long *)n->page; ++ for(i=0;i<1024;i++) ++ pte[i] = reserved_pte; ++ ++ list_add(&n->list, &h->pmd_list); ++ ++ pgd[vaddr>>22] = dmmu_v2pfn(n->page) | DMMU_PMD_VLD; ++// printk(">>>>>>> n->page = %lx, pgd[vaddr>>22] = %lx <<<<<<<\n\n", n->page, pgd[vaddr>>22]); ++ return n; ++} ++ ++static struct dmmu_handle *find_handle(void) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ if(h->tgid == current->tgid) ++ return h; ++ } ++ return NULL; ++} ++ ++/** ++* @brief unmap node from map list, clear each pmd_node in pmd_list, ++* Not free handle, let dmmu_unmap_all do it. ++* ++* @param h ++* ++* @return ++*/ ++static int dmmu_unmap_node_unlock(struct dmmu_handle *h) ++{ ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++ unsigned long vaddr; ++ int len; ++ unsigned long end; ++ ++ struct pmd_node *node; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ /* find and delete a map node from map_list */ ++ cn = list_entry(pos, struct map_node, list); ++ vaddr = cn->start; ++ len = cn->len; ++ end = vaddr + len; ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(node) ++ vaddr = unmap_node(node,vaddr,end,1); ++ } ++ ++ list_del(&cn->list); ++ kfree(cn); ++ } ++ ++ ++ return 0; ++ ++} ++ ++ ++void dmmu_mm_release(struct mmu_notifier *mn, ++ struct mm_struct *mm) ++{ ++ struct dmmu_handle *h = container_of(mn, struct dmmu_handle, mn); ++ ++ printk("===== dmmu release mm (TODO: not checked) ====h: %p\n", h); ++ ++ if(h->handle_mm != mm) { ++ return; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ dmmu_mm_dev_release(h); ++ ++ dmmu_unmap_node_unlock(h); ++ ++ mutex_unlock(&h->lock); ++} ++ ++static const struct mmu_notifier_ops dmmu_mm_notifier_ops = { ++ .release = dmmu_mm_release, ++}; ++ ++ ++static struct dmmu_handle *create_handle(void) ++{ ++ struct dmmu_handle *h; ++ unsigned int pgd_index; ++ unsigned long *pgd; ++ ++ h = kmalloc(sizeof(struct dmmu_handle),GFP_KERNEL); ++ if(!h) ++ return NULL; ++ ++ h->tgid = current->tgid; ++ h->pdg = __get_free_page(GFP_KERNEL); ++ if(!h->pdg) { ++ pr_err("%s %d, Get free page for PGD error\n", ++ __func__, __LINE__); ++ kfree(h); ++ return NULL; ++ } ++ SetPageReserved(virt_to_page((void *)h->pdg)); ++ ++ pgd = (unsigned long *)h->pdg; ++ ++ for (pgd_index=0; pgd_index < PTRS_PER_PGD; pgd_index++) ++ pgd[pgd_index] = res_pte_paddr; ++ ++ INIT_LIST_HEAD(&h->list); ++ INIT_LIST_HEAD(&h->pmd_list); ++ INIT_LIST_HEAD(&h->map_list); ++ INIT_LIST_HEAD(&h->dev_notifier_list); ++ mutex_init(&h->lock); ++ ++ /* register exit_mmap notify */ ++ h->handle_mm = current->mm; ++ ++ h->mn.ops = &dmmu_mm_notifier_ops; ++ ++ mmu_notifier_register(&h->mn, h->handle_mm); ++ ++ list_add(&h->list, &handle_list); ++ ++ return h; ++} ++ ++static int dmmu_make_present(unsigned long addr,unsigned long end) ++{ ++#if 0 ++ unsigned long i; ++ for(i = addr; i < end; i += 4096) { ++ *(volatile unsigned char *)(i) = 0; ++ } ++ *(volatile unsigned char *)(end - 1) = 0; ++ return 0; ++#else ++ int ret, len, write; ++ struct vm_area_struct * vma; ++ unsigned long vm_page_prot; ++ ++ mmap_write_lock(current->mm); ++ vma = find_vma(current->mm, addr); ++ if (!vma) { ++ printk("dmmu_make_present error. addr=%lx len=%lx\n",addr,end-addr); ++ mmap_write_unlock(current->mm); ++ return -1; ++ } ++ ++ if(vma->vm_flags & VM_PFNMAP) { ++ mmap_write_unlock(current->mm); ++ return 0; ++ } ++ write = (vma->vm_flags & VM_WRITE) != 0; ++ BUG_ON(addr >= end); ++ BUG_ON(end > vma->vm_end); ++ ++ vm_page_prot = pgprot_val(vma->vm_page_prot); ++ vma->vm_page_prot = __pgprot(vm_page_prot | _PAGE_VALID| _PAGE_ACCESSED | _PAGE_PRESENT); ++ ++ len = DIV_ROUND_UP(end, PAGE_SIZE) - addr/PAGE_SIZE; ++ ret = get_user_pages(addr, len, write, NULL, NULL); ++ vma->vm_page_prot = __pgprot(vm_page_prot); ++ if (ret < 0) { ++ printk("dmmu_make_present get_user_pages error(%d). addr=%lx len=%lx\n",0-ret,addr,end-addr); ++ mmap_write_unlock(current->mm); ++ return ret; ++ } ++ ++ mmap_write_unlock(current->mm); ++ return ret == len ? 0 : -1; ++#endif ++} ++ ++static void dmmu_cache_wback(struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ dma_cache_wback(h->pdg,PAGE_SIZE); ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ dma_cache_wback(n->page,PAGE_SIZE); ++ } ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h); ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len) ++{ ++ int end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ printk("(pid %d)dmmu_map %lx %lx================================================\n",h->tgid,vaddr,len); ++#endif ++ if(check_map(h,vaddr,len)) ++ { ++ mutex_unlock(&h->lock); ++ return dmmu_v2pfn(h->pdg); ++ } ++ ++ if(dmmu_make_present(vaddr,vaddr+len)) ++ { ++ mutex_unlock(&h->lock); ++ return 0; ++ } ++ ++ handle_add_map(dev,h,vaddr,len); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(!node) { ++ node = add_node(h,vaddr); ++ } ++ vaddr = map_node(node,vaddr,end); ++ } ++ dmmu_cache_wback(h); ++#ifdef DEBUG ++ dmmu_dump_handle(NULL,NULL,h); ++#endif ++ mutex_unlock(&h->lock); ++ ++ return dmmu_v2pfn(h->pdg); ++} ++EXPORT_SYMBOL(dmmu_map); ++ ++static int dmmu_mm_dev_release(struct dmmu_handle *h) ++{ ++ struct dmmu_mm_notifier *n = NULL; ++ struct list_head *pos, *next; ++ ++ list_for_each_safe(pos, next, &h->dev_notifier_list) { ++ n = list_entry(pos, struct dmmu_mm_notifier, list); ++ if(n && n->ops && n->ops->mm_release) { ++ n->ops->mm_release(n->data); ++ } ++ ++ list_del(&n->list); ++ } ++ ++ ++ return 0; ++} ++ ++ ++int dmmu_register_mm_notifier(struct dmmu_mm_notifier *dmn) ++{ ++ int dev_already_registered = 0; ++ struct dmmu_mm_notifier *n = NULL; ++ struct dmmu_handle *h; ++ struct list_head *pos, *next; ++ ++ h = find_handle(); ++ if(!h) { ++ return -EINVAL; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ list_for_each_safe(pos, next, &h->dev_notifier_list) { ++ n = list_entry(pos, struct dmmu_mm_notifier, list); ++ ++ if(n == dmn) { ++ /* already in dev_notifier_list*/ ++ dev_already_registered = 1; ++ } ++ ++ } ++ ++ if(dev_already_registered) { ++ goto out; ++ } ++ ++ list_add_tail(&dmn->list, &h->dev_notifier_list); ++out: ++ mutex_unlock(&h->lock); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_register_mm_notifier); ++ ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len) ++{ ++ unsigned long end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *n; ++ ++ h = find_handle(); ++ if(!h) { ++ return 0; ++ } ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ /*This printk can cause a memory leak. */ ++ printk("dmmu_unmap %lx %x**********************************************\n",vaddr,len); ++#endif ++ n = check_map(h,vaddr,len); ++ if(!n) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ if(n->dev != dev) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ ++ list_del(&n->list); ++ kfree(n); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(node) ++ vaddr = unmap_node(node,vaddr,end,1); ++ } ++ ++ if(list_empty(&h->pmd_list) && list_empty(&h->map_list)) { ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ mutex_unlock(&h->lock); ++ ++ mmu_notifier_unregister(&h->mn, h->handle_mm); ++ ++ kfree(h); ++ return 0; ++ } ++ ++ mutex_unlock(&h->lock); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_unmap); ++ ++int dmmu_free_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++ h = find_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ node = find_node(h,cn->start); ++ if(node) ++ unmap_node(node,cn->start,cn->len,1); ++ list_del(&cn->list); ++ kfree(cn); ++ } ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ node = list_entry(pos, struct pmd_node, list); ++ if(node){ ++ printk("WARN: pmd list should NULL\n"); ++ unmap_node(node,0,0,0); ++ } ++ } ++ ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ ++ mutex_unlock(&h->lock); ++ mmu_notifier_unregister(&h->mn, h->handle_mm); ++ kfree(h); ++ return 0; ++} ++ ++/** ++* @brief release all resources, which should be called by driver close ++* ++* @param dev ++* ++* @return ++*/ ++int dmmu_unmap_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++#ifdef DEBUG ++ printk("dmmu_unmap_all\n"); ++#endif ++ ++ h = find_handle(); ++ if(!h) { ++ printk("dmmu unmap all not find hindle, maybe it has benn freed already, name: %s\n", dev->kobj.name); ++ return 0; ++ } ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ if(dev == cn->dev) { ++ dmmu_unmap(dev,cn->start,cn->len); ++ } ++ } ++ ++ ++ if(list_empty(&h->map_list)) ++ dmmu_free_all(dev); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_unmap_all); ++int __init dmmu_init(void) ++{ ++ unsigned int pte_index; ++ unsigned long res_page_paddr; ++ unsigned long reserved_page; ++ unsigned int *res_pte_vaddr; ++ ++ reserved_page = __get_free_page(GFP_KERNEL); ++ if (!reserved_page) { ++ pr_err("%s %d, Get reserved page error\n", ++ __func__, __LINE__); ++ return ENOMEM; ++ } ++ SetPageReserved(virt_to_page((void *)reserved_page)); ++ reserved_pte = dmmu_v2pfn(reserved_page) | DMMU_PTE_VLD; ++ ++ res_page_paddr = virt_to_phys((void *)reserved_page) | 0xFFF; ++ ++ res_pte_vaddr = (unsigned int *)__get_free_page(GFP_KERNEL); ++ if (!res_pte_vaddr) { ++ pr_err("%s %d, Get free page for PTE error\n", ++ __func__, __LINE__); ++ free_page(reserved_page); ++ return ENOMEM; ++ } ++ SetPageReserved(virt_to_page(res_pte_vaddr)); ++ res_pte_paddr = virt_to_phys((void *)res_pte_vaddr) | DMMU_PTE_VLD; ++ ++ for (pte_index = 0; pte_index < PTRS_PER_PTE; pte_index++) ++ res_pte_vaddr[pte_index] = res_page_paddr; ++ printk("%s %d PTRS_PER_PTE = %lu\n",__func__,__LINE__,PTRS_PER_PTE); ++ ++ return 0; ++} ++arch_initcall(dmmu_init); ++ ++void dmmu_dump_vaddr(unsigned long vaddr) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ unsigned long *pmd,*pte; ++ h = find_handle(); ++ if(!h) { ++ printk("dmmu_dump_vaddr %08lx error - h not found!\n",vaddr); ++ return; ++ } ++ ++ node = find_node(h,vaddr); ++ if(!node) { ++ printk("dmmu_dump_vaddr %08lx error - node not found!\n",vaddr); ++ return; ++ } ++ ++ pmd = (unsigned long *)h->pdg; ++ pte = (unsigned long *)node->page; ++ ++ printk("pmd base = %p; pte base = %p\n",pmd,pte); ++ printk("pmd = %08lx; pte = %08lx\n",pmd[vaddr>>22],pte[(vaddr&0x3ff000)>>12]); ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ { ++ int i = 0; ++ int vaddr = n->start; ++ struct pmd_node *pn = find_node(h,vaddr); ++ unsigned int *pte = (unsigned int *)pn->page; ++ ++ while(vaddr < (n->start + n->len)) { ++ if(i++%8 == 0) ++ printk("\nvaddr %08x : ",vaddr & 0xfffff000); ++ printk("%08x ",pte[(vaddr & 0x3ff000)>>12]); ++ vaddr += 4096; ++ } ++ printk("\n\n"); ++ } ++ } ++} ++ ++static int dmmu_proc_show(struct seq_file *m, void *v) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ volatile unsigned long flags; ++ local_irq_save(flags); ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ dmmu_dump_handle(m, v, h); ++ } ++ local_irq_restore(flags); ++ return 0; ++} ++ ++static int dmmu_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, dmmu_proc_show, PDE_DATA(inode)); ++} ++ ++static const struct proc_ops dmmus_proc_fops ={ ++ .proc_read = seq_read, ++ .proc_open = dmmu_open, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release, ++}; ++ ++static int __init init_dmmu_proc(void) ++{ ++ struct proc_dir_entry *p; ++ p = jz_proc_mkdir("dmmu"); ++ if (!p) { ++ printk("create_proc_entry for common dmmu failed.\n"); ++ return -ENODEV; ++ } ++ proc_create("dmmus", 0600,p,&dmmus_proc_fops); ++ ++ return 0; ++} ++ ++module_init(init_dmmu_proc); +diff --git a/arch/mips/xburst2/soc-x2000/pm.c b/arch/mips/xburst2/soc-x2000/pm.c +new file mode 100644 +index 000000000..c55425d5c +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/pm.c +@@ -0,0 +1,539 @@ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pm.h" ++#if defined CONFIG_KP_AXP ++#include ++#endif ++ ++ ++ ++//#define X2000_IDLE_PD ++// #define X2000_SLEEP_GPIO GPIO_PB(30) ++ ++#ifdef DEBUG_PM ++static void x2000_pm_gate_check(void) ++{ ++ unsigned int gate0 = cpm_inl(CPM_CLKGR); ++ unsigned int gate1 = cpm_inl(CPM_CLKGR1); ++ int i; ++ int x; ++ ++ printk("gate0 = 0x%08x\n", gate0); ++ printk("gate1 = 0x%08x\n", gate1); ++ for (i = 0; i < 32; i++) { ++ x = (gate0 >> i) & 1; ++ if (x == 0) ++ printk("warning : bit[%d] in clk gate0 is enabled\n", i); ++ } ++ for (i = 0; i < 32; i++) { ++ x = (gate1 >> i) & 1; ++ if (x == 0) ++ printk("warning : bit[%d] in clk gate1 is enabled\n", i); ++ } ++ ++} ++#endif ++ ++ ++ ++ ++static inline void ddrp_auto_calibration(void) ++{ ++ unsigned int reg_val = ddr_readl(DDRP_INNOPHY_TRAINING_CTRL); ++ unsigned int timeout = 0xffffff; ++ unsigned int wait_cal_done = DDRP_CALIB_DONE_HDQCFA | DDRP_CALIB_DONE_LDQCFA; ++ ++ reg_val &= ~(DDRP_TRAINING_CTRL_DSCSE_BP); ++ reg_val |= DDRP_TRAINING_CTRL_DSACE_START; ++ ddr_writel(reg_val, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ while(!((ddr_readl(DDRP_INNOPHY_CALIB_DONE) & wait_cal_done) == wait_cal_done) && --timeout) { ++ TCSM_PCHAR('t'); ++ } ++ ++ if(!timeout) { ++ TCSM_PCHAR('f'); ++ } ++ ddr_writel(0, DDRP_INNOPHY_TRAINING_CTRL); ++} ++ ++ ++ ++ ++static void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size) ++{ ++ unsigned int instr; ++ int offset; ++ int i; ++#ifdef DEBUG_PM ++ printk("tcsm addr = %p %p size = %d\n",tcsm_addr,f_addr,size); ++#endif ++ for(i = 0;i < size / 4;i++) { ++ instr = f_addr[i]; ++ if((instr >> 26) == 2){ ++ offset = instr & 0x3ffffff; ++ offset = (offset << 2) - ((unsigned int)f_addr & 0xfffffff); ++ if(offset > 0) { ++ offset = ((unsigned int)tcsm_addr & 0xfffffff) + offset; ++ instr = (2 << 26) | (offset >> 2); ++ } ++ } ++ tcsm_addr[i] = instr; ++ } ++} ++ ++ ++#ifdef X2000_IDLE_PD ++static int soc_pm_idle_pd(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ lcr |= 2; ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~ (1<<31); ++ opcr |= (1 << 30); ++ opcr &= ~(1 << 26); //l2c power down ++ opcr |= 1 << 2; // select RTC clk ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++#else ++static int soc_pm_idle(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 30); ++ opcr &= ~(1 << 31); ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++#endif ++ ++static int soc_pm_sleep(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; ++ lcr |= 1 << 0; // low power mode: SLEEP ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 31); ++ opcr |= (1 << 30); ++ opcr &= ~(1 << 26); //L2C power down ++ opcr |= (1 << 21); // cpu 32k ram retention. ++ opcr |= (1 << 3); // power down CPU ++ opcr &= ~(1 << 4); // exclk disable; ++ opcr |= (1 << 2); // select RTC clk ++ opcr |= (1 << 22); ++ opcr |= (1 << 20); ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++ ++static int soc_post_wakeup(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ lcr &= ~0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ printk("post wakeup!\n"); ++ ++ ++ { ++ /* after power down cpu by set PD in OPCR, resume cpu's frequency and L2C's freq */ ++ unsigned int val; ++ ++ /* change disable */ ++ val = cpm_inl(CPM_CPCCR); ++ val &= ~(1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* resume cpu_div in CPCCR */ ++ val &= ~0xf; ++ val |= sleep_param->cpu_div; ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* change enable */ ++ val |= (1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ while (cpm_inl(CPM_CPCSR) & 1); ++ } ++ return 0; ++} ++ ++static noinline void cpu_resume_bootup(void) ++{ ++ TCSM_PCHAR('X'); ++ /* set reset entry */ ++ *(volatile unsigned int *)0xb2200f00 = 0xbfc00000; ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "move $29, %0 \n\t" ++ "jr.hb %1 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ :"r" (SLEEP_CPU_RESUME_SP), "r"(SLEEP_CPU_RESUME_TEXT) ++ : ++ ); ++ ++} ++static noinline void cpu_resume(void) ++{ ++ unsigned int ddrc_ctrl; ++ ++ TCSM_PCHAR('R'); ++ ++#ifdef X2000_SLEEP_GPIO ++ /* resume normal voltage */ ++ gpio_writel(1 << (X2000_SLEEP_GPIO % 32), GPIO_PXPAT0S(X2000_SLEEP_GPIO / 32)); ++ /* wait voltage to stabilize unit: 3.33ns*/ ++ TCSM_DELAY(300000); ++ /* resume clk div */ ++ cpm_writel(0x55700000 | (sleep_param->cpccr & 0xFFFFF), CPM_CPCCR); ++ while(cpm_readl(CPM_CPCSR) & 7); ++ /* resume clk source */ ++ cpm_writel(sleep_param->cpccr, CPM_CPCCR); ++ while((cpm_readl(CPM_CPCSR) & 0xf0000000) != 0xf0000000); ++#endif ++ ++ if (sleep_param->state == PM_SUSPEND_MEM) { ++ int tmp; ++ ++ /* enable pll */ ++ tmp = reg_ddr_phy(0x21); ++ tmp &= ~(1 << 1); ++ reg_ddr_phy(0x21) = tmp; ++ ++ while (!(reg_ddr_phy(0x32) & 0x8)) ++ serial_put_hex(reg_ddr_phy(0x32)); ++ ++ /* dfi_init_start = 0, wait dfi_init_complete */ ++ *(volatile unsigned int *)0xb3012000 &= ~(1 << 3); ++ while(!(*(volatile unsigned int *)0xb3012004 & 0x1)); ++ ++ /* bufferen_core = 1 */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp |= (1 << 21); ++ rtc_write_reg(0xb0003048, tmp); ++ ++ /* exit sr */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl &= ~(1<<5); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ while(ddr_readl(DDRC_STATUS) & (1<<2)); ++ ++ TCSM_DELAY(1000); ++ TCSM_PCHAR('1'); ++ ddrp_auto_calibration(); ++ TCSM_PCHAR('2'); ++ ++ /* restore ddr auto-sr */ ++ ddr_writel(sleep_param->autorefresh, DDRC_AUTOSR_EN); ++ TCSM_PCHAR('3'); ++ ++ /* restore ddr LPEN */ ++ ddr_writel(sleep_param->dlp, DDRC_DLP); ++ ++ /* restore ddr deep power down state */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= sleep_param->pdt; ++ ddrc_ctrl |= sleep_param->dpd; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ TCSM_PCHAR('4'); ++ } ++ ++ ++ TCSM_PCHAR('5'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (restore_goto) ++ : ++ ); ++} ++ ++ ++static noinline void cpu_sleep(void) ++{ ++ ++ ++ sleep_param->cpu_div = cpm_inl(CPM_CPCCR) & 0xf; ++ ++ blast_dcache32(); ++ blast_scache64(); ++ __sync(); ++ __fast_iob(); ++ ++ { ++ /* before power down cpu by set PD in OPCR, reduce cpu's frequency as the same as L2C's freq */ ++ unsigned int val, div; ++ ++ /* change disable */ ++ val = cpm_inl(CPM_CPCCR); ++ val &= ~(1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* div cpu = div l2c */ ++ div = val & (0xf << 4); ++ val &= ~0xf; ++ val |= (div >> 4); ++ cpm_outl(val, CPM_CPCCR); ++ ++ /* change enable */ ++ val |= (1 << 22); ++ cpm_outl(val, CPM_CPCCR); ++ ++ while (cpm_inl(CPM_CPCSR) & 1); ++ } ++ ++ TCSM_PCHAR('D'); ++ ++ if (sleep_param->state == PM_SUSPEND_MEM) { ++ unsigned int tmp; ++ unsigned int ddrc_ctrl; ++ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ++ /* save ddr low power state */ ++ sleep_param->pdt = ddrc_ctrl & DDRC_CTRL_PDT_MASK; ++ sleep_param->dpd = ddrc_ctrl & DDRC_CTRL_DPD; ++ sleep_param->dlp = ddr_readl(DDRC_DLP); ++ sleep_param->autorefresh = ddr_readl(DDRC_AUTOSR_EN); ++ ++ /* ddr disable deep power down */ ++ ddrc_ctrl &= ~(DDRC_CTRL_PDT_MASK); ++ ddrc_ctrl &= ~(DDRC_CTRL_DPD); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ /* ddr diasble LPEN*/ ++ ddr_writel(0, DDRC_DLP); ++ ++ /* ddr disable auto-sr */ ++ ddr_writel(0, DDRC_AUTOSR_EN); ++ tmp = *(volatile unsigned int *)0xa0000000; ++ ++ /* DDR self refresh */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= 1 << 5; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ while(!(ddr_readl(DDRC_STATUS) & (1<<2))); ++ ++ ++ /* bufferen_core = 0 */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp &= ~(1 << 21); ++ rtc_write_reg(0xb0003048, tmp); ++ ++ ++ /* dfi_init_start = 1 */ ++ *(volatile unsigned int *)0xb3012000 |= (1 << 3); ++ ++ { ++ int i; ++ for (i = 0; i < 4; i++) { ++ ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ } ++ } ++ ++ /* disable pll */ ++ reg_ddr_phy(0x21) |= (1 << 1); ++ } ++ ++ TCSM_PCHAR('W'); ++ ++#ifdef X2000_SLEEP_GPIO ++ sleep_param->cpccr = cpm_readl(CPM_CPCCR); ++ /* set cpu clk to 24M */ ++ cpm_writel(0x55700000,CPM_CPCCR); ++ while((cpm_readl(CPM_CPCSR) & 0xf0000007) != 0xf0000000); ++ gpio_writel(1 << (X2000_SLEEP_GPIO % 32), GPIO_PXPAT0C(X2000_SLEEP_GPIO / 32)); ++#endif ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "wait \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ ); ++ ++ TCSM_PCHAR('N'); ++ ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (SLEEP_CPU_RESUME_BOOTUP_TEXT) ++ : ++ ); ++ TCSM_PCHAR('F'); ++} ++ ++ ++int x2000_pm_enter(suspend_state_t state) ++{ ++ extern volatile u8 *uart_base; ++ ++ printk("x2000 pm enter!!\n"); ++ ++ sleep_param->uart_base = (unsigned int)uart_base; ++ ++ sleep_param->state = state; ++ ++#ifdef DEBUG_PM ++ printk("sleep_param->state addr = %d\n", sleep_param->state); ++#endif ++ ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_RESUME_BOOTUP_TEXT, (unsigned int *)cpu_resume_bootup, SLEEP_CPU_RESUME_BOOTUP_LEN); ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_RESUME_TEXT, (unsigned int *)cpu_resume, SLEEP_CPU_RESUME_LEN); ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_SLEEP_TEXT, (unsigned int *)cpu_sleep, SLEEP_CPU_SLEEP_LEN); ++ ++ if (state == PM_SUSPEND_STANDBY) { ++#ifdef X2000_IDLE_PD ++ soc_pm_idle_pd(); ++#else ++ soc_pm_idle(); ++#endif ++ } else if (state == PM_SUSPEND_MEM) { ++ soc_pm_sleep(); ++ } else { ++ printk("WARNING : unsupport pm suspend state\n"); ++ } ++ ++ ++ /* set reset entry */ ++ *(volatile unsigned int *)0xb2200f00 = SLEEP_CPU_RESUME_BOOTUP_TEXT; ++ ++ ++#ifdef DEBUG_PM ++ printk("LCR: %08x\n", cpm_inl(CPM_LCR)); ++ printk("OPCR: %08x\n", cpm_inl(CPM_OPCR)); ++ x2000_pm_gate_check(); ++#endif ++ ++ mb(); ++ save_goto((unsigned int)SLEEP_CPU_SLEEP_TEXT); ++ mb(); ++ ++ soc_post_wakeup(); ++ ++ return 0; ++} ++ ++static int x2000_pm_begin(suspend_state_t state) ++{ ++ printk("x2000 suspend begin\n"); ++ return 0; ++} ++ ++static void x2000_pm_end(void) ++{ ++ printk("x2000 pm end!\n"); ++} ++#if defined CONFIG_KP_AXP ++static int x2000_suspend_prepare(void) ++{ ++ return regulator_suspend_prepare(PM_SUSPEND_MEM); ++} ++static void x2000_suspend_finish(void) ++{ ++ if (regulator_suspend_finish()) ++ pr_err("%s: Suspend finish failed\n", __func__); ++} ++#endif ++ ++static int ingenic_pm_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++static const struct platform_suspend_ops x2000_pm_ops = { ++ .valid = ingenic_pm_valid, ++ .begin = x2000_pm_begin, ++ .enter = x2000_pm_enter, ++ .end = x2000_pm_end, ++#if defined CONFIG_KP_AXP ++ .prepare = x2000_suspend_prepare, ++ .finish = x2000_suspend_finish, ++#endif ++}; ++ ++/* ++ * Initialize suspend interface ++ */ ++static int __init pm_init(void) ++{ ++ ++#ifdef X2000_SLEEP_GPIO ++ gpio_request(X2000_SLEEP_GPIO, "sleep_gpio"); ++ gpio_direction_output(X2000_SLEEP_GPIO, 1); ++#endif ++ ++ suspend_set_ops(&x2000_pm_ops); ++ ++ ++ return 0; ++} ++ ++late_initcall(pm_init); +diff --git a/arch/mips/xburst2/soc-x2000/pm.h b/arch/mips/xburst2/soc-x2000/pm.h +new file mode 100644 +index 000000000..5799b6399 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/pm.h +@@ -0,0 +1,169 @@ ++ ++ ++ ++struct sleep_param { ++ suspend_state_t state; ++ unsigned int pdt; ++ unsigned int dpd; ++ unsigned int dlp; ++ unsigned int autorefresh; ++ unsigned int cpu_div; ++ unsigned int uart_base; ++ unsigned int cpccr; ++}; ++ ++ ++/* ++ * ++ * |-----------------------| ++ * | | ++ * | | ++ * | RESUME_SP | ++ * | | ++ * |-----------------------| ++ * | | ++ * | PARAM | ++ * | | ++ * |-----------------------| ++ * | | ++ * | | ++ * | SLEEP_TEXT | ++ * | | ++ * | | ++ * |-----------------------| ++ * | | ++ * | | ++ * | RESUME_TEXT | ++ * | | ++ * | | ++ * |-----------------------| ++ * | | ++* | RESUME_BOOTU_TEXTP | ++ * | | ++ * |-----------------------| <------------ TCSM_START 0xb2400000 ++ * ++ */ ++ ++ ++#define SLEEP_MEMORY_START 0xb2400000 ++#define SLEEP_MEMORY_END 0xb2407ff8 ++#define SLEEP_RESUME_SP SLEEP_MEMORY_END ++#define SLEEP_RESUME_BOOTUP_TEXT SLEEP_MEMORY_START ++ ++#define SLEEP_CPU_RESUME_BOOTUP_TEXT SLEEP_RESUME_BOOTUP_TEXT ++#define SLEEP_CPU_RESUME_BOOTUP_LEN 64 // 16 instructions ++#define SLEEP_CPU_RESUME_TEXT (SLEEP_CPU_RESUME_BOOTUP_TEXT + SLEEP_CPU_RESUME_BOOTUP_LEN) ++#define SLEEP_CPU_RESUME_LEN (4096) ++#define SLEEP_CPU_SLEEP_TEXT (SLEEP_CPU_RESUME_TEXT + SLEEP_CPU_RESUME_LEN) ++#define SLEEP_CPU_SLEEP_LEN (3072) ++#define SLEEP_CPU_PARAM_ADDR (SLEEP_CPU_SLEEP_TEXT + SLEEP_CPU_SLEEP_LEN) ++#define SLEEP_CPU_PARAM_SIZE (sizeof(struct sleep_param)) ++#define SLEEP_CPU_RESUME_SP SLEEP_RESUME_SP ++ ++#define sleep_param ((struct sleep_param *)SLEEP_CPU_PARAM_ADDR) ++ ++ ++ ++extern long long save_goto(unsigned int func); ++extern int restore_goto(unsigned int func); ++ ++ ++#define reg_ddr_phy(x) (*(volatile unsigned int *)(0xb3011000 + ((x) << 2))) ++ ++#define rtc_read_reg(reg) ({ \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++ *(volatile unsigned int *)reg;\ ++}) ++ ++#define rtc_write_reg(reg, val) do{ \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++ *(volatile unsigned int *)0xb000303c = 0xa55a; \ ++ while (!((*(volatile unsigned int *)0xb000303c >> 31) & 0x1) ); \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++ *(volatile unsigned int *)reg = val; \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++}while(0) ++ ++#define readb(addr) (*(volatile unsigned char *)(addr)) ++#define readw(addr) (*(volatile unsigned short *)(addr)) ++#define readl(addr) (*(volatile unsigned int *)(addr)) ++#define writeb(b, addr) (*(volatile unsigned char *)(addr)) = (b) ++#define writew(b, addr) (*(volatile unsigned short *)(addr)) = (b) ++#define writel(b, addr) (*(volatile unsigned int *)(addr)) = (b) ++ ++#define GPIO_PXPIN(n) (0x00 + (n) * 0x100) /* PIN Level Register */ ++#define GPIO_PXINT(n) (0x10 + (n) * 0x100) /* Port Interrupt Register */ ++#define GPIO_PXINTS(n) (0x14 + (n) * 0x100) /* Port Interrupt Set Register */ ++#define GPIO_PXINTC(n) (0x18 + (n) * 0x100) /* Port Interrupt Clear Register */ ++#define GPIO_PXMASK(n) (0x20 + (n) * 0x100) /* Port Interrupt Mask Register */ ++#define GPIO_PXMASKS(n) (0x24 + (n) * 0x100) /* Port Interrupt Mask Set Reg */ ++#define GPIO_PXMASKC(n) (0x28 + (n) * 0x100) /* Port Interrupt Mask Clear Reg */ ++#define GPIO_PXPAT1(n) (0x30 + (n) * 0x100) /* Port Pattern 1 Register */ ++#define GPIO_PXPAT1S(n) (0x34 + (n) * 0x100) /* Port Pattern 1 Set Reg. */ ++#define GPIO_PXPAT1C(n) (0x38 + (n) * 0x100) /* Port Pattern 1 Clear Reg. */ ++#define GPIO_PXPAT0(n) (0x40 + (n) * 0x100) /* Port Pattern 0 Register */ ++#define GPIO_PXPAT0S(n) (0x44 + (n) * 0x100) /* Port Pattern 0 Set Register */ ++#define GPIO_PXPAT0C(n) (0x48 + (n) * 0x100) /* Port Pattern 0 Clear Register */ ++#define GPIO_PXFLG(n) (0x50 + (n) * 0x100) /* Port Flag Register */ ++#define GPIO_PXFLGC(n) (0x58 + (n) * 0x100) /* Port Flag clear Register */ ++#define GPIO_PXPU(n) (0x80 + (n) * 0x100) /* PORT PULL-UP State Register */ ++#define GPIO_PXPUS(n) (0x84 + (n) * 0x100) /* PORT PULL-UP State Set Register*/ ++#define GPIO_PXPUC(n) (0x88 + (n) * 0x100) /* PORT PULL-UP State Clear Register */ ++#define GPIO_PXPD(n) (0x90 + (n) * 0x100) /* PORT PULL-DOWN State Register */ ++#define GPIO_PXPDS(n) (0x94 + (n) * 0x100) /* PORT PULL-DOWN State Set Register */ ++#define GPIO_PXPDC(n) (0x98 + (n) * 0x100) /* PORT PULL-DOWN State Set Register */ ++ ++#define gpio_readl(o) readl(0xb0010000 + (o)) ++#define gpio_writel(b, o) writel(b, 0xb0010000 + (o)) ++ ++#define cpm_readl(o) readl(0xb0000000 + (o)) ++#define cpm_writel(b, o) writel(b, 0xb0000000 + (o)) ++ ++/************************************************ ++ * debug interface ++ ***********************************************/ ++ ++#define DEBUG_PM ++#define PRINT_DEBUG ++ ++ ++#define U_IOBASE (sleep_param->uart_base) ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++ ++#ifdef PRINT_DEBUG ++#define TCSM_PCHAR(x) \ ++ *((volatile unsigned int*)(U_IOBASE+OFF_TDR)) = x; \ ++while ((*((volatile unsigned int*)(U_IOBASE + OFF_LSR)) & (LSR_TDRQ | LSR_TEMT)) != (LSR_TDRQ | LSR_TEMT)) ++#else ++#define TCSM_PCHAR(x) ++#endif ++ ++#define TCSM_DELAY(x) \ ++ do{ \ ++ register unsigned int i = x; \ ++ while(i--) \ ++ __asm__ volatile("nop\n\t"); \ ++ }while(0) ++ ++static inline void serial_put_hex(unsigned int x) { ++ int i; ++ unsigned int d; ++ for(i = 7;i >= 0;i--) { ++ d = (x >> (i * 4)) & 0xf; ++ if(d < 10) d += '0'; ++ else d += 'A' - 10; ++ TCSM_PCHAR(d); ++ } ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++} ++ ++ ++ ++ +diff --git a/arch/mips/xburst2/soc-x2000/pm_fastboot.c b/arch/mips/xburst2/soc-x2000/pm_fastboot.c +new file mode 100644 +index 000000000..53d44a4be +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/pm_fastboot.c +@@ -0,0 +1,667 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pm_fastboot.h" ++ ++ ++volatile unsigned int intc0_msk; ++volatile unsigned int intc1_msk; ++volatile unsigned int gpio_pb_int; ++volatile unsigned int gpio_pb_msk; ++volatile unsigned int gpio_pb_pat1; ++volatile unsigned int gpio_pb_pat0; ++volatile unsigned int gpio_pe_int; ++volatile unsigned int gpio_pe_msk; ++volatile unsigned int gpio_pe_pat1; ++volatile unsigned int gpio_pe_pat0; ++ ++volatile unsigned int clk_gate0; ++volatile unsigned int clk_gate1; ++ ++volatile unsigned int mem_pd0; ++volatile unsigned int mem_pd1; ++ ++#define g_state ((volatile suspend_state_t *)0xb0000bfc) ++volatile unsigned int _regs_stack_0[136 / 4]; ++volatile unsigned int _regs_stack_1[136 / 4]; ++volatile unsigned int *_regs_stack; ++ ++static inline void rtc_write_reg(unsigned int reg, unsigned int val) ++{ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ *(volatile unsigned int *)0xb000303c = 0xa55a; ++ while (!((*(volatile unsigned int *)0xb000303c >> 31) & 0x1) ); ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ ++ *(volatile unsigned int *)reg = val; ++ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++} ++ ++static inline unsigned int rtc_read_reg(unsigned int reg) ++{ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ ++ return *(volatile unsigned int *)reg; ++} ++ ++#define PRINT_DEBUG ++ ++ ++#ifdef PRINT_DEBUG ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++#define U_IOBASE (UART2_IOBASE + 0xa0000000) ++#define TCSM_PCHAR(x) \ ++ *((volatile unsigned int*)(U_IOBASE+OFF_TDR)) = x; \ ++while ((*((volatile unsigned int*)(U_IOBASE + OFF_LSR)) & (LSR_TDRQ | LSR_TEMT)) != (LSR_TDRQ | LSR_TEMT)) ++#else ++#define TCSM_PCHAR(x) ++#endif ++ ++#define TCSM_DELAY(x) \ ++ do{ \ ++ register unsigned int i = x; \ ++ while(i--) \ ++ __asm__ volatile(".set mips32\n\t" \ ++ "nop\n\t" \ ++ ".set mips32"); \ ++ }while(0) \ ++ ++static inline void serial_put_hex(unsigned int x) { ++ int i; ++ unsigned int d; ++ for(i = 7;i >= 0;i--) { ++ d = (x >> (i * 4)) & 0xf; ++ if(d < 10) d += '0'; ++ else d += 'A' - 10; ++ TCSM_PCHAR(d); ++ } ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++} ++ ++#if 1 ++struct uart_regs { ++ unsigned int udllr; ++ unsigned int udlhr; ++ unsigned int uthr; ++ unsigned int uier; ++ unsigned int ufcr; ++ unsigned int ulcr; ++ unsigned int umcr; ++ unsigned int uspr; ++ unsigned int isr; ++ unsigned int umr; ++ unsigned int uacr; ++ unsigned int urcr; ++ unsigned int utcr; ++ ++}; ++ ++ ++static void uart_save(struct uart_regs *uart_regs) ++{ ++ printk("uart save\n"); ++ *(volatile unsigned int *)0xb003200c |= (1 << 7); ++ uart_regs->udllr = *(volatile unsigned int *)0xb0032000; ++ uart_regs->udlhr = *(volatile unsigned int *)0xb0032004; ++ ++ *(volatile unsigned int *)0xb003200c &= ~(1 << 7); ++ uart_regs->uthr = *(volatile unsigned int *)0xb0032000; ++ uart_regs->uier = *(volatile unsigned int *)0xb0032004; ++ ++ uart_regs->ufcr = *(volatile unsigned int *)0xb0032008; ++ uart_regs->ulcr = *(volatile unsigned int *)0xb003200c; ++ uart_regs->umcr = *(volatile unsigned int *)0xb0032010; ++ uart_regs->uspr = *(volatile unsigned int *)0xb003201c; ++ uart_regs->isr = *(volatile unsigned int *)0xb0032020; ++ uart_regs->umr = *(volatile unsigned int *)0xb0032024; ++ uart_regs->uacr = *(volatile unsigned int *)0xb0032028; ++ uart_regs->urcr = *(volatile unsigned int *)0xb0032040; ++ uart_regs->utcr = *(volatile unsigned int *)0xb0032044; ++ ++ printk("uthr = 0x%08x\n", uart_regs->uthr); ++ printk("uier = 0x%08x\n", uart_regs->uier); ++ printk("udllr = 0x%08x\n", uart_regs->udllr); ++ printk("udlhr = 0x%08x\n", uart_regs->udlhr); ++ printk("ULCR = 0x%08x\n", *(volatile unsigned int *)0xb003200c); ++ printk("UMCR = 0x%08x\n", *(volatile unsigned int *)0xb0032010); ++ printk("ULSR = 0x%08x\n", *(volatile unsigned int *)0xb0032014); ++ printk("UMSR = 0x%08x\n", *(volatile unsigned int *)0xb0032018); ++ printk("USPR = 0x%08x\n", *(volatile unsigned int *)0xb003201c); ++ printk("ISR = 0x%08x\n", *(volatile unsigned int *)0xb0032020); ++ printk("UMR = 0x%08x\n", *(volatile unsigned int *)0xb0032024); ++ printk("UACR = 0x%08x\n", *(volatile unsigned int *)0xb0032028); ++ printk("URCR = 0x%08x\n", *(volatile unsigned int *)0xb0032040); ++ printk("UTCR = 0x%08x\n", *(volatile unsigned int *)0xb0032044); ++ ++ ++} ++ ++static void uart_set_baud(struct uart_regs *uart_regs) ++{ ++ *(volatile unsigned int *)0xb0032024 = uart_regs->umr; ++ *(volatile unsigned int *)0xb0032028 = uart_regs->uacr; ++ ++ *(volatile unsigned int *)0xb003200c |= (1 << 7); ++ *(volatile unsigned int *)0xb0032000 = uart_regs->udllr; ++ *(volatile unsigned int *)0xb0032004 = uart_regs->udlhr; ++ *(volatile unsigned int *)0xb003200c &= ~(1 << 7); ++ ++} ++ ++ ++static void uart_restore(struct uart_regs *uart_regs) ++{ ++ ++ *(volatile unsigned int *)0xb0000020 &= ~(1 << 16); ++ ++ /*uart2 PD30 PD31 func0 */ ++ *(volatile unsigned int *)0xb0010318 |= (3 << 30); ++ *(volatile unsigned int *)0xb0010328 |= (3 << 30); ++ *(volatile unsigned int *)0xb0010338 |= (3 << 30); ++ *(volatile unsigned int *)0xb0010348 |= (3 << 30); ++ ++ ++ *(volatile unsigned int *)0xb0032008 = uart_regs->ufcr; ++ *(volatile unsigned int *)0xb003200c = uart_regs->ulcr; ++ *(volatile unsigned int *)0xb0032010 = uart_regs->umcr; ++ *(volatile unsigned int *)0xb003201c = uart_regs->uspr; ++ *(volatile unsigned int *)0xb0032020 = uart_regs->isr; ++ *(volatile unsigned int *)0xb0032024 = uart_regs->umr; ++ *(volatile unsigned int *)0xb0032028 = uart_regs->uacr; ++ *(volatile unsigned int *)0xb0032040 = uart_regs->urcr; ++ *(volatile unsigned int *)0xb0032044 = uart_regs->utcr; ++ ++ uart_set_baud(uart_regs); ++ ++ *(volatile unsigned int *)0xb0032008 = (1 << 4) | (1 << 0) | (1 << 1) | (1 << 2); ++ ++} ++#endif ++ ++struct ost_regs { ++ unsigned int ostccr; ++ unsigned int oster; ++ unsigned int ostcr; ++ unsigned int ostfr; ++ unsigned int ostmr; ++ unsigned int ostdfr; ++ unsigned int ostcnt; ++ ++ unsigned int g_ostccr; ++ unsigned int g_oster; ++ unsigned int g_ostcr; ++ unsigned int g_ostcnth; ++ unsigned int g_ostcntl; ++ unsigned int g_ostcntb; ++}; ++ ++static void ost_save(struct ost_regs *ost_regs) ++{ ++ ost_regs->ostccr = *(volatile unsigned int *)0xb2100000; ++ ost_regs->oster = *(volatile unsigned int *)0xb2100004; ++ ost_regs->ostcr = *(volatile unsigned int *)0xb2100008; ++ ost_regs->ostfr = *(volatile unsigned int *)0xb210000c; ++ ost_regs->ostmr = *(volatile unsigned int *)0xb2100010; ++ ost_regs->ostdfr = *(volatile unsigned int *)0xb2100014; ++ ost_regs->ostcnt = *(volatile unsigned int *)0xb2100018; ++ ++ ost_regs->g_ostccr = *(volatile unsigned int *)0xb2000000; ++ ost_regs->g_oster = *(volatile unsigned int *)0xb2000004; ++ ost_regs->g_ostcr = *(volatile unsigned int *)0xb2000008; ++ ost_regs->g_ostcnth = *(volatile unsigned int *)0xb200000c; ++ ost_regs->g_ostcntl = *(volatile unsigned int *)0xb2000010; ++ ost_regs->g_ostcntb = *(volatile unsigned int *)0xb2000014; ++ ++} ++ ++static void ost_restore(struct ost_regs *ost_regs) ++{ ++ *(volatile unsigned int *)0xb2100000 = ost_regs->ostccr; ++ *(volatile unsigned int *)0xb2100008 = ost_regs->ostcr; ++ *(volatile unsigned int *)0xb210000c = ost_regs->ostfr; ++ *(volatile unsigned int *)0xb2100010 = ost_regs->ostmr; ++ *(volatile unsigned int *)0xb2100014 = ost_regs->ostdfr; ++ *(volatile unsigned int *)0xb2100018 = ost_regs->ostcnt; ++ *(volatile unsigned int *)0xb2100004 = ost_regs->oster; ++ ++ *(volatile unsigned int *)0xb2000000 = ost_regs->g_ostccr; ++ *(volatile unsigned int *)0xb2000008 = ost_regs->g_ostcr; ++ *(volatile unsigned int *)0xb2000004 = ost_regs->g_oster; ++ ++} ++ ++static noinline void cpu_resume(void); ++ ++ ++static void rtc_ram_write_enable(void) ++{ ++ unsigned int tmp; ++ ++ /* write RTC RAM enable */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp &= ~(1 << 23); ++ tmp &= ~(1 << 22); ++ tmp |= (1 << 21); ++ tmp |= (1 << 20); ++ rtc_write_reg(0xb0003048, tmp); ++ ++} ++ ++static void rtc_ram_write_disable(void) ++{ ++ unsigned int tmp; ++ ++ /*exit write RTC RAM enable */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp |= (1 << 22); ++ rtc_write_reg(0xb0003048, tmp); ++ ++} ++ ++ ++static void soc_pm_fastboot(void) ++{ ++ ++ unsigned int tmp; ++ ++ clk_gate0 = cpm_inl(CPM_CLKGR); ++ clk_gate1 = cpm_inl(CPM_CLKGR1); ++ ++ clk_gate0 |= 1 << 20; // disable ost ++ clk_gate0 &= ~(1 << 28); // enable apb0 ++ clk_gate0 &= ~(1 << 27); //enable rtc ++ ++ cpm_outl(clk_gate0, CPM_CLKGR); ++ ++ printk("clk_gate0: 0x%08x, clk_gate1: 0x%08x\n", clk_gate0, clk_gate1); ++ ++ ++ ++ intc1_msk = *(volatile unsigned int *)0xb0001024; ++ *(volatile unsigned int *)0xb0001024 = intc1_msk & ~(1<<0); // RTC INT MSK ++ ++ /* RTC EALM */ ++ tmp = rtc_read_reg(0xb000302c); ++ tmp |= 1; ++ rtc_write_reg(0xb000302c, tmp); ++ ++ /* RTC enable AE */ ++ tmp = rtc_read_reg(0xb0003000); ++ tmp |= (1 << 2) | (1 << 0); ++ rtc_write_reg(0xb0003000, tmp); ++ ++ /* 32k rtc clk */ ++ tmp = rtc_read_reg(0xb0003000); ++ tmp &= ~(1 << 1); ++ rtc_write_reg(0xb0003000, tmp); ++} ++ ++static int soc_post_wakeup(void) ++{ ++ ++ clk_gate0 &= ~(1 << 20); //enable ost ++ cpm_outl(clk_gate0, CPM_CLKGR); ++ cpm_outl(clk_gate1, CPM_CLKGR1); ++ ++ ++ return 0; ++} ++ ++ ++ ++ ++ ++static struct store_regs *store_regs; ++ ++static void save_resume_pc(void) ++{ ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ store_regs->resume_pc = (unsigned int)cpu_resume; ++ printk("xxxxxxxxxxxxxxxxxxx save resume_pc = 0x%08x\n", store_regs->resume_pc); ++} ++static void pll_store(void) ++{ ++ struct pll_resume_reg *pll_resume_reg; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ pll_resume_reg = &store_regs->pll_resume_reg; ++ ++ pll_resume_reg->cpccr = *(volatile unsigned int *)0xb0000000; ++ pll_resume_reg->cppcr = *(volatile unsigned int *)0xb000000c; ++ pll_resume_reg->cpapcr = *(volatile unsigned int *)0xb0000010; ++ pll_resume_reg->cpmpcr = *(volatile unsigned int *)0xb0000014; ++ pll_resume_reg->cpepcr = *(volatile unsigned int *)0xb0000018; ++ pll_resume_reg->ddrcdr = *(volatile unsigned int *)0xb000002c; ++ ++} ++ ++static void ddrc_store(void) ++{ ++ struct ddrc_resume_reg *ddrc_resume_reg; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ ddrc_resume_reg = &store_regs->ddrc_resume_reg; ++ ++ ddrc_resume_reg->dcfg = *(volatile unsigned int *)0xb34f0008; ++ ddrc_resume_reg->dctrl = *(volatile unsigned int *)0xb34f0010; ++ ddrc_resume_reg->dlmr = *(volatile unsigned int *)0xb34f0018; ++ ddrc_resume_reg->ddlp = *(volatile unsigned int *)0xb34f0020; ++ ddrc_resume_reg->dasr_en = *(volatile unsigned int *)0xb34f0030; ++ ddrc_resume_reg->dasr_cnt = *(volatile unsigned int *)0xb34f0028; ++ ddrc_resume_reg->drefcnt = *(volatile unsigned int *)0xb34f0038; ++ ddrc_resume_reg->dtimming1 = *(volatile unsigned int *)0xb34f0040; ++ ddrc_resume_reg->dtimming2 = *(volatile unsigned int *)0xb34f0048; ++ ddrc_resume_reg->dtimming3 = *(volatile unsigned int *)0xb34f0050; ++ ddrc_resume_reg->dtimming4 = *(volatile unsigned int *)0xb34f0058; ++ ddrc_resume_reg->dtimming5 = *(volatile unsigned int *)0xb34f0060; ++ ddrc_resume_reg->dmmap0 = *(volatile unsigned int *)0xb34f0078; ++ ddrc_resume_reg->dmmap1 = *(volatile unsigned int *)0xb34f0080; ++ ddrc_resume_reg->dwcfg = *(volatile unsigned int *)0xb3012000; ++ ddrc_resume_reg->dremap1 = *(volatile unsigned int *)0xb3012008; ++ ddrc_resume_reg->dremap2 = *(volatile unsigned int *)0xb301200c; ++ ddrc_resume_reg->dremap3 = *(volatile unsigned int *)0xb3012010; ++ ddrc_resume_reg->dremap4 = *(volatile unsigned int *)0xb3012014; ++ ddrc_resume_reg->dremap5 = *(volatile unsigned int *)0xb3012018; ++ ddrc_resume_reg->ccguc0 = *(volatile unsigned int *)0xb3012064; ++ ddrc_resume_reg->ccguc1 = *(volatile unsigned int *)0xb3012068; ++ ++} ++ ++static void ddr_phy_store(void) ++{ ++ struct ddr_phy_resume_reg *ddr_phy_resume_reg; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ ddr_phy_resume_reg = &store_regs->ddr_phy_resume_reg; ++ ++ ddr_phy_resume_reg->mem_cfg = *(volatile unsigned int *)0xb3011004; ++ ddr_phy_resume_reg->dq_width = *(volatile unsigned int *)0xb301107c; ++ ddr_phy_resume_reg->cl = *(volatile unsigned int *)0xb3011014; ++ ddr_phy_resume_reg->al = *(volatile unsigned int *)0xb3011018; ++ ddr_phy_resume_reg->cwl = *(volatile unsigned int *)0xb301101c; ++ ddr_phy_resume_reg->pll_fbdiv = *(volatile unsigned int *)0xb3011080; ++ ddr_phy_resume_reg->pll_ctrl = *(volatile unsigned int *)0xb3011084; ++ ddr_phy_resume_reg->pll_pdiv = *(volatile unsigned int *)0xb3011088; ++ ddr_phy_resume_reg->training_ctrl = *(volatile unsigned int *)0xb3011008; ++ ddr_phy_resume_reg->calib_bypass_al = *(volatile unsigned int *)0xb3011118; ++ ddr_phy_resume_reg->calib_bypass_ah = *(volatile unsigned int *)0xb3011158; ++ ddr_phy_resume_reg->wl_mode1 = *(volatile unsigned int *)0xb301100c; ++ ddr_phy_resume_reg->wl_mode2 = *(volatile unsigned int *)0xb3011010; ++} ++ ++static void rtc_ram_store(void) ++{ ++ pll_store(); ++ ddrc_store(); ++ ddr_phy_store(); ++ save_resume_pc(); ++} ++ ++ ++static int fastboot_resume_code[] = { ++ ++#include "fastboot_resume_code.hex" ++ ++}; ++ ++ ++ ++ ++ ++ ++extern long long save_goto(unsigned int); ++extern int restore_goto(void); ++ ++ ++ ++static noinline void cpu_resume(void) ++{ ++ ++ unsigned int cpu_id; ++ ++ ++ cpu_id = read_c0_ebase() & 0x3ff; ++ ++ if (cpu_id == 0) { ++ _regs_stack = _regs_stack_0; ++ } else if (cpu_id == 1) { ++ _regs_stack = _regs_stack_1; ++ } ++ ++ *(volatile unsigned int *)0xb2200f00 = 0xbfc00000; /* RESET entry = 0xbfc00000 ,reset value */ ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (restore_goto) ++ : ++ ); ++} ++ ++ ++ ++ ++#define jump() do{ \ ++ void (*func)(void); \ ++ func = (void(*)(void)) 0xb0004000; \ ++ func(); \ ++ }while(0) ++ ++#if 0 ++static void ddrp_auto_calibration(void) ++{ ++ unsigned int reg_val = ddr_readl(DDRP_INNOPHY_TRAINING_CTRL); ++ unsigned int timeout = 0xffffff; ++ unsigned int wait_cal_done = DDRP_CALIB_DONE_HDQCFA | DDRP_CALIB_DONE_LDQCFA; ++ ++ reg_val &= ~(DDRP_TRAINING_CTRL_DSCSE_BP); ++ reg_val |= DDRP_TRAINING_CTRL_DSACE_START; ++ ddr_writel(reg_val, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ while(!((ddr_readl(DDRP_INNOPHY_CALIB_DONE) & wait_cal_done) == wait_cal_done) && --timeout) { ++ TCSM_PCHAR('t'); ++ serial_put_hex(*(volatile unsigned int *)(0x80015060 + 0 * 4)); ++ serial_put_hex(*(volatile unsigned int *)(0x80015060 + 1 * 4)); ++ serial_put_hex(*(volatile unsigned int *)(0x80015060 + 2 * 4)); ++ serial_put_hex(*(volatile unsigned int *)(0x80015060 + 3 * 4)); ++ } ++ ++ if(!timeout) { ++ TCSM_PCHAR('f'); ++ } ++ ddr_writel(0, DDRP_INNOPHY_TRAINING_CTRL); ++} ++#endif ++ ++ ++static noinline void cpu_sleep(void) ++{ ++ ++ ++ unsigned int tmp; ++ unsigned int ddrc_ctrl; ++ ++ blast_dcache32(); ++ blast_scache64(); ++ __sync(); ++ __fast_iob(); ++ ++ ddr_writel(0, DDRC_AUTOSR_EN); ++ tmp = *(volatile unsigned int *)0xa0000000; ++ ++ ++ /* DDR self refresh, */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= 1 << 5; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ while(!(ddr_readl(DDRC_STATUS) & (1<<2))); ++ ++ /* bufferen_core = 0 */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp &= ~(1 << 21); ++ rtc_write_reg(0xb0003048, tmp); ++ ++ /* dfi_init_start = 1 */ ++ *(volatile unsigned int *)0xb3012000 |= (1 << 3); ++ ++ ++ { ++ int i; ++ for (i = 0; i < 4; i++) { ++ ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ } ++ } ++ /* ddr phy pll power down */ ++ *(volatile unsigned int *)0xb3011084 |= (1 << 1); ++ ++ ++ ++ TCSM_PCHAR('o'); ++ ++ ++ /* rtc disable power detect */ ++ rtc_write_reg(0xb000302c, (0x1a55a5a5 << 3) | 1); ++ /* RTC PD */ ++ rtc_write_reg(0xb0003020, 1); ++ ++ ++ while (1); ++} ++ ++ ++ ++static void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size) ++{ ++ unsigned int instr; ++ int offset; ++ int i; ++#ifdef DEBUG_PM ++ printk("tcsm addr = %p %p size = %d\n",tcsm_addr,f_addr,size); ++#endif ++ for(i = 0;i < size / 4;i++) { ++ instr = f_addr[i]; ++ if((instr >> 26) == 2){ ++ offset = instr & 0x3ffffff; ++ offset = (offset << 2) - ((unsigned int)f_addr & 0xfffffff); ++ if(offset > 0) { ++ offset = ((unsigned int)tcsm_addr & 0xfffffff) + offset; ++ instr = (2 << 26) | (offset >> 2); ++ } ++ } ++ tcsm_addr[i] = instr; ++ } ++} ++ ++ ++static int x2000_pm_enter(suspend_state_t state) ++{ ++ unsigned int cpu_id; ++ struct uart_regs *uart_regs; ++ struct ost_regs *ost_regs; ++ ++ uart_regs = kmalloc(sizeof(struct uart_regs), GFP_KERNEL); ++ ost_regs = kmalloc(sizeof(struct ost_regs), GFP_KERNEL); ++ soc_pm_fastboot(); ++ ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_SLEEP_TEXT, (unsigned int *)cpu_sleep, SLEEP_CPU_SLEEP_LEN); ++ ++ rtc_ram_write_enable(); ++ rtc_ram_store(); ++ memcpy((unsigned int *)RTC_RAM_CODE_ADDR1, (unsigned int *)fastboot_resume_code, RTC_RAM_CODE_SIZE); ++ rtc_ram_write_disable(); ++ ++ uart_save(uart_regs); ++ ost_save(ost_regs); ++ ++ cpu_id = read_c0_ebase() & 0x3ff; ++ ++ printk("cpu_id = %d\n", cpu_id); ++ ++ if (cpu_id == 0) { ++ _regs_stack = _regs_stack_0; ++ } else if (cpu_id == 1) { ++ _regs_stack = _regs_stack_1; ++ } ++ ++ ++ mb(); ++ save_goto((unsigned int)SLEEP_CPU_SLEEP_TEXT); ++ mb(); ++ ++ ++ soc_post_wakeup(); ++ ++ ost_restore(ost_regs); ++ uart_restore(uart_regs); ++ set_ccu_mimr(1 << 0); ++ ++ ++ return 0; ++} ++ ++static int x2000_pm_begin(suspend_state_t state) ++{ ++ printk("x2000 suspend begin\n"); ++ ++ return 0; ++} ++ ++static void x2000_pm_end(void) ++{ ++ printk("x2000 pm end!\n"); ++ ++} ++ ++static const struct platform_suspend_ops x2000_pm_ops = { ++ .valid = suspend_valid_only_mem, ++ .begin = x2000_pm_begin, ++ .enter = x2000_pm_enter, ++ .end = x2000_pm_end, ++}; ++ ++/* ++ * Initialize suspend interface ++ */ ++static int __init pm_init(void) ++{ ++ ++ suspend_set_ops(&x2000_pm_ops); ++ ++ return 0; ++} ++ ++arch_initcall(pm_init); +diff --git a/arch/mips/xburst2/soc-x2000/pm_fastboot.h b/arch/mips/xburst2/soc-x2000/pm_fastboot.h +new file mode 100644 +index 000000000..3bad4d885 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/pm_fastboot.h +@@ -0,0 +1,106 @@ ++ ++ ++#define RTC_SLEEP_MEMORY_START 0xb0004000 ++#define RTC_SLEEP_MEMORY_END 0xb0005000 ++#define RTC_RAM_SP_ADDR (RTC_RAM_DATA_ADDR - 4) ++//#define RTC_RAM_SP_SIZE (256 - 4) ++#define RTC_RAM_DATA_ADDR 0xb0004c00 ++#define RTC_RAM_DATA_SIZE 1024 ++#define RTC_RAM_CODE_ADDR1 0xb0004000 ++#define RTC_RAM_CODE_ADDR2 (RTC_RAM_CODE_ADDR1 + 64) ++#define RTC_RAM_CODE_SIZE 0xb00 ++ ++#define SLEEP_CPU_SLEEP_TEXT 0xb2400000 ++#define SLEEP_CPU_SLEEP_LEN 4096 ++ ++ ++ ++struct pll_resume_reg { ++ unsigned int cpccr; ++ unsigned int cppcr; ++ unsigned int cpapcr; ++ unsigned int cpmpcr; ++ unsigned int cpepcr; ++ unsigned int ddrcdr; ++}; ++ ++struct ddrc_resume_reg { ++ unsigned int dcfg; ++ unsigned int dctrl; ++ unsigned int dlmr; ++ unsigned int ddlp; ++ unsigned int dasr_en; ++ unsigned int dasr_cnt; ++ unsigned int drefcnt; ++ unsigned int dtimming1; ++ unsigned int dtimming2; ++ unsigned int dtimming3; ++ unsigned int dtimming4; ++ unsigned int dtimming5; ++ unsigned int dmmap0; ++ unsigned int dmmap1; ++#if 0 ++ unsigned int dbwcfg; ++ unsigned int dbwstp; ++ unsigned int hregpro; ++ unsigned int dbgen; ++#endif ++ unsigned int dwcfg; ++ unsigned int dremap1; ++ unsigned int dremap2; ++ unsigned int dremap3; ++ unsigned int dremap4; ++ unsigned int dremap5; ++#if 0 ++ unsigned int cpac; ++ unsigned int cchc0; ++ unsigned int cchc1; ++ unsigned int cchc2; ++ unsigned int cchc3; ++ unsigned int cchc4; ++ unsigned int cchc5; ++ unsigned int cchc6; ++ unsigned int cchc7; ++ unsigned int cschc0; ++ unsigned int cschc1; ++ unsigned int cschc2; ++ unsigned int cschc3; ++ unsigned int cmonc0; ++ unsigned int cmonc1; ++ unsigned int cmonc2; ++ unsigned int cmonc3; ++ unsigned int cmonc4; ++#endif ++ unsigned int ccguc0; ++ unsigned int ccguc1; ++#if 0 ++ unsigned int pregpro; ++ unsigned int bufcfg; ++#endif ++}; ++ ++struct ddr_phy_resume_reg { ++ unsigned int phy_rst; ++ unsigned int mem_cfg; ++ unsigned int dq_width; ++ unsigned int cl; ++ unsigned int al; ++ unsigned int cwl; ++ unsigned int pll_fbdiv; ++ unsigned int pll_ctrl; ++ unsigned int pll_pdiv; ++ unsigned int training_ctrl; ++ unsigned int calib_bypass_al; ++ unsigned int calib_bypass_ah; ++ unsigned int wl_mode1; ++ unsigned int wl_mode2; ++ ++}; ++ ++struct store_regs { ++ unsigned int resume_pc; ++ struct pll_resume_reg pll_resume_reg; ++ struct ddrc_resume_reg ddrc_resume_reg; ++ struct ddr_phy_resume_reg ddr_phy_resume_reg; ++}; ++ +diff --git a/arch/mips/xburst2/soc-x2000/regs_save_restore.S b/arch/mips/xburst2/soc-x2000/regs_save_restore.S +new file mode 100644 +index 000000000..abe8b49df +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/regs_save_restore.S +@@ -0,0 +1,190 @@ ++#include ++#include ++ ++#define CP0_PAGEMASK $5,0 ++#define CP0_STATUS $12,0 ++#define CP0_INTCTL $12,1 ++#define CP0_CAUSE $13,0 ++#define CP0_EBASE $15,1 ++#define CP0_CONFIG $16,0 ++#define CP0_CONFIG1 $16,1 ++#define CP0_CONFIG2 $16,2 ++#define CP0_CONFIG3 $16,3 ++#define CP0_CONFIG4 $16,4 ++#define CP0_CONFIG5 $16,5 ++#define CP0_CONFIG7 $16,7 ++#define CP0_LLADDR $17,0 ++#define CP0_WATCHLo $18,0 ++#define CP0_WATCHHI $19,0 ++#define CP0_ERRCTL $26,0 ++#define CP0_CONTEXT $4,0 ++#define CP0_KSCRATCH1 $31,2 ++#define CP0_KSCRATCH2 $31,3 ++#define CP0_KSCRATCH3 $31,4 ++#define CP0_KSCRATCH4 $31,5 ++#define CP0_KSCRATCH5 $31,6 ++#define CP0_KSCRATCH6 $31,7 ++ ++ .data ++ .global _regs_stack ++_regs_stack: ++ .align 5 ++ .space 140,0 ++ ++ .text ++ .global save_goto ++ .align 2 ++ .ent save_goto,0 ++ LEAF(save_goto) ++save_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sw s0,0(k0) ++ sw s1,4(k0) ++ sw s2,8(k0) ++ sw s3,12(k0) ++ sw s4,16(k0) ++ sw s5,20(k0) ++ sw s6,24(k0) ++ sw s7,28(k0) ++ sw gp,32(k0) ++ sw sp,36(k0) ++ sw fp,40(k0) ++ sw ra,44(k0) ++ ++ mfc0 k1,CP0_PAGEMASK ++ sw k1,48(k0) ++ mfc0 k1,CP0_STATUS ++ sw k1,52(k0) ++ mfc0 k1,CP0_INTCTL ++ sw k1,56(k0) ++ mfc0 k1,CP0_CAUSE ++ sw k1,60(k0) ++ mfc0 k1,CP0_EBASE ++ sw k1,64(k0) ++ mfc0 k1,CP0_CONFIG ++ sw k1,68(k0) ++ mfc0 k1,CP0_CONFIG1 ++ sw k1,72(k0) ++ mfc0 k1,CP0_CONFIG2 ++ sw k1,76(k0) ++ mfc0 k1,CP0_CONFIG3 ++ sw k1,80(k0) ++ mfc0 k1,CP0_CONFIG4 ++ sw k1,84(k0) ++ mfc0 k1,CP0_CONFIG5 ++ sw k1,88(k0) ++ mfc0 k1,CP0_CONFIG7 ++ sw k1,92(k0) ++ mfc0 k1,CP0_LLADDR ++ sw k1,96(k0) ++ mfc0 k1,CP0_WATCHLo ++ sw k1,100(k0) ++ mfc0 k1,CP0_WATCHHI ++ sw k1,104(k0) ++ mfc0 k1,CP0_ERRCTL ++ sw k1,108(k0) ++ mfc0 k1,CP0_CONTEXT ++ sw k1,112(k0) ++ mfc0 k1,CP0_KSCRATCH1 ++ sw k1,116(k0) ++ mfc0 k1,CP0_KSCRATCH2 ++ sw k1,120(k0) ++ mfc0 k1,CP0_KSCRATCH3 ++ sw k1,124(k0) ++ mfc0 k1,CP0_KSCRATCH4 ++ sw k1,128(k0) ++ mfc0 k1,CP0_KSCRATCH5 ++ sw k1,132(k0) ++ mfc0 k1,CP0_KSCRATCH6 ++ sw k1,136(k0) ++ ++ jr.hb a0 ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(save_goto) ++ ++ .text ++ .global restore_goto ++ .align 2 ++ .ent restore_goto,0 ++ LEAF(restore_goto) ++restore_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ lw s0,0(k0) ++ lw s1,4(k0) ++ lw s2,8(k0) ++ lw s3,12(k0) ++ lw s4,16(k0) ++ lw s5,20(k0) ++ lw s6,24(k0) ++ lw s7,28(k0) ++ lw gp,32(k0) ++ lw sp,36(k0) ++ lw fp,40(k0) ++ lw ra,44(k0) ++ ++ lw k1,48(k0) ++ mtc0 k1,CP0_PAGEMASK ++ lw k1,52(k0) ++ mtc0 k1,CP0_STATUS ++ lw k1,56(k0) ++ mtc0 k1,CP0_INTCTL ++ lw k1,60(k0) ++ mtc0 k1,CP0_CAUSE ++ lw k1,64(k0) ++ mtc0 k1,CP0_EBASE ++ lw k1,68(k0) ++ mtc0 k1,CP0_CONFIG ++ lw k1,72(k0) ++ mtc0 k1,CP0_CONFIG1 ++ lw k1,76(k0) ++ mtc0 k1,CP0_CONFIG2 ++ lw k1,80(k0) ++ mtc0 k1,CP0_CONFIG3 ++ lw k1,84(k0) ++ mtc0 k1,CP0_CONFIG4 ++ lw k1,88(k0) ++ mtc0 k1,CP0_CONFIG5 ++ lw k1,92(k0) ++ mtc0 k1,CP0_CONFIG7 ++ lw k1,96(k0) ++ mtc0 k1,CP0_LLADDR ++ lw k1,100(k0) ++ mtc0 k1,CP0_WATCHLo ++ lw k1,104(k0) ++ mtc0 k1,CP0_WATCHHI ++ lw k1,108(k0) ++ mtc0 k1,CP0_ERRCTL ++ lw k1,112(k0) ++ mtc0 k1,CP0_CONTEXT ++ lw k1,116(k0) ++ mtc0 k1,CP0_KSCRATCH1 ++ lw k1,120(k0) ++ mtc0 k1,CP0_KSCRATCH2 ++ lw k1,124(k0) ++ mtc0 k1,CP0_KSCRATCH3 ++ lw k1,128(k0) ++ mtc0 k1,CP0_KSCRATCH4 ++ lw k1,132(k0) ++ mtc0 k1,CP0_KSCRATCH5 ++ lw k1,136(k0) ++ mtc0 k1,CP0_KSCRATCH6 ++ ++ jr.hb ra ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(restore_goto) +diff --git a/arch/mips/xburst2/soc-x2000/regs_save_restore.py b/arch/mips/xburst2/soc-x2000/regs_save_restore.py +new file mode 100755 +index 000000000..8a23de0d0 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/regs_save_restore.py +@@ -0,0 +1,124 @@ ++#!/usr/bin/env python ++import os ++import string ++ ++common_regs=["s0","s1","s2","s3", ++ "s4","s5","s6","s7", ++ "gp","sp","fp","ra"] ++cp0_regs=[ ++ ["CP0_PAGEMASK","$5","0"], ++ ["CP0_STATUS","$12","0"], ++ ["CP0_INTCTL","$12","1"], ++ ["CP0_CAUSE","$13","0"], ++ ["CP0_EBASE","$15","1"], ++ ["CP0_CONFIG","$16","0"], ++ ["CP0_CONFIG1","$16","1"], ++ ["CP0_CONFIG2","$16","2"], ++ ["CP0_CONFIG3","$16","3"], ++ ["CP0_CONFIG4", "$16", "4"], ++ ["CP0_CONFIG5", "$16", "5"], ++ ["CP0_CONFIG7", "$16", "7"], ++ ["CP0_LLADDR","$17","0"], ++ ["CP0_WATCHLo","$18","0"], ++ ["CP0_WATCHHI","$19","0"], ++ ["CP0_ERRCTL","$26","0"], ++ ["CP0_CONTEXT","$4","0"], ++ ["CP0_KSCRATCH1","$31","2"], ++ ["CP0_KSCRATCH2","$31","3"], ++ ["CP0_KSCRATCH3","$31","4"], ++ ["CP0_KSCRATCH4","$31","5"], ++ ["CP0_KSCRATCH5","$31","6"], ++ ["CP0_KSCRATCH6","$31","7"], ++ ] ++def gen_get_array_size(): ++ size=0 ++ size+=len(common_regs) ++ size+=len(cp0_regs) ++ return size ++ ++def gen_print_head_and_macro(): ++ print("#include ") ++ print("#include ") ++ print("") ++ for s in cp0_regs: ++ print("#define %s\t%s,%s" %(s[0],s[1],s[2])) ++ print("") ++def gen_define_global_arg(str, num): ++ print("\t.data") ++ print("\t.global %s" %(str)) ++ print("%s:" %(str)) ++ print("\t.align 5") ++ print("\t.space %s,0" %(num)) ++ print("") ++ ++def gen_save_common_regs(index): ++ for s in common_regs: ++ print("\tsw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_restore_common_regs(index): ++ for s in common_regs: ++ print("\tlw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_save_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tmfc0\tk1,%s" % (s[0])) ++ print("\tsw\tk1,%d(k0)" % (index)) ++ index=index+4 ++ return index ++def gen_restore_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tlw\tk1,%d(k0)" % (index)) ++ print("\tmtc0\tk1,%s" % (s[0])) ++ index=index+4 ++ return index ++def gen_print_function(f_name, regs_stack): ++ index=0 ++ print("\t.text") ++ print("\t.global %s" %(f_name)) ++ print("\t.align 2") ++ print("\t.ent %s,0" %(f_name)) ++ print("\tLEAF(%s)" %(f_name)) ++ print("%s:" %(f_name)) ++ print("\t.set\tpush") ++ print("\t.set\tnoreorder") ++ print("\t.set\tnoat") ++ print("") ++ print("\tla\tk0, %s" %(regs_stack)) ++ if f_name == "save_goto": ++ index = gen_save_common_regs(index) ++ print("") ++ index = gen_save_cp0_regs(index) ++ print("") ++ print("\tjr.hb\ta0") ++ print("\tnop") ++ elif f_name == "restore_goto": ++ index = gen_restore_common_regs(index) ++ print("") ++ index = gen_restore_cp0_regs(index) ++ print("") ++ print("\tjr.hb\tra") ++ print("\tnop") ++ else: ++ print("not support") ++ print("") ++ print("\t.set\tat") ++ print("\t.set\treorder") ++ print("\t.set\tpop") ++ print("\tEND(%s)" %(f_name)) ++ ++ ++def main(): ++ regs_size=gen_get_array_size() ++ regs_size*=4 ++ ++ gen_print_head_and_macro() ++ gen_define_global_arg("_regs_stack", regs_size) ++ gen_print_function("save_goto", "_regs_stack") ++ print("") ++ gen_print_function("restore_goto", "_regs_stack") ++ pass ++ ++if __name__ == '__main__': ++ main() +diff --git a/arch/mips/xburst2/soc-x2000/reset.c b/arch/mips/xburst2/soc-x2000/reset.c +new file mode 100644 +index 000000000..d7a87f1d8 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/reset.c +@@ -0,0 +1,327 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#define RTC_RTCCR (0x00) /* rw, 32, 0x00000081 */ ++#define RTC_RTCSR (0x04) /* rw, 32, 0x???????? */ ++#define RTC_RTCSAR (0x08) /* rw, 32, 0x???????? */ ++#define RTC_RTCGR (0x0c) /* rw, 32, 0x0??????? */ ++#define RTC_HCR (0x20) /* rw, 32, 0x00000000 */ ++#define RTC_HWFCR (0x24) /* rw, 32, 0x0000???0 */ ++#define RTC_HRCR (0x28) /* rw, 32, 0x00000??0 */ ++#define RTC_HWCR (0x2c) /* rw, 32, 0x00000008 */ ++#define RTC_HWRSR (0x30) /* rw, 32, 0x00000000 */ ++#define RTC_HSPR (0x34) /* rw, 32, 0x???????? */ ++#define RTC_WENR (0x3c) /* rw, 32, 0x00000000 */ ++#define RTC_CKPCR (0x40) /* rw, 32, 0x00000010 */ ++#define RTC_OWIPCR (0x44) /* rw, 32, 0x00000010 */ ++#define RTC_PWRONCR (0x48) /* rw, 32, 0x???????? */ ++ ++#define WDT_TCSR (0x0c) /* rw, 32, 0x???????? */ ++#define WDT_TCER (0x04) /* rw, 32, 0x???????? */ ++#define WDT_TDR (0x00) /* rw, 32, 0x???????? */ ++#define WDT_TCNT (0x08) /* rw, 32, 0x???????? */ ++ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++ ++#define RTCCR_WRDY BIT(7) ++#define WENR_WEN BIT(31) ++ ++#define RECOVERY_SIGNATURE (0x001a1a) ++#define REBOOT_SIGNATURE (0x003535) ++#define UNMSAK_SIGNATURE (0x7c0000)//do not use these bits ++ ++static void wdt_start_count(int msecs) ++{ ++ int time = JZ_EXTAL_RTC / 64 * msecs / 1000; ++ if(time > 65535) ++ time = 65535; ++ ++// outl(1 << 16,TCU_IOBASE + TCU_TSCR); ++ ++ outl(0,WDT_IOBASE + WDT_TCNT); //counter ++ outl(time,WDT_IOBASE + WDT_TDR); //data ++ outl((3<<3 | 2<<0 | 1 << 10),WDT_IOBASE + WDT_TCSR); ++ outl(0,WDT_IOBASE + WDT_TCER); ++ outl(1,WDT_IOBASE + WDT_TCER); ++} ++ ++static void __attribute__((unused)) wdt_stop_count(void) ++{ ++ outl(1 << 16,TCU_IOBASE + TCU_TSCR); ++ outl(0,WDT_IOBASE + WDT_TCNT); //counter ++ outl(65535,WDT_IOBASE + WDT_TDR); //data ++ outl(1 << 16,TCU_IOBASE + TCU_TSSR); ++} ++ ++static int inline rtc_write_reg(int reg,int value) ++{ ++ int timeout = 0x2000; ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY) && timeout--); ++ if(!timeout) ++ { ++ printk("WARN:NO USE RTC!!!!!\n"); ++ return -1; ++ } ++ outl(0xa55a,(RTC_IOBASE + RTC_WENR)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ while(!(inl(RTC_IOBASE + RTC_WENR) & WENR_WEN)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ outl(value,(RTC_IOBASE + reg)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ ++ return 0; ++} ++ ++/* ++ * Function: Keep power for CPU core when reset. ++ * So that EPC, tcsm and so on can maintain it's status after reset-key pressed. ++ */ ++static int inline reset_keep_power(void) ++{ ++ return rtc_write_reg(RTC_PWRONCR, ++ inl(RTC_IOBASE + RTC_PWRONCR) & ~(1 << 0)); ++} ++ ++#define HWFCR_WAIT_TIME(x) ((x > 0x7fff ? 0x7fff: (0x7ff*(x)) / 2000) << 5) ++#define HRCR_WAIT_TIME(x) ((((x) > 1875 ? 1875: (x)) / 125) << 11) ++ ++void jz_hibernate(void) ++{ ++ uint32_t rtc_rtccr; ++ ++ local_irq_disable(); ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ ++ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000)); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(125)); ++ ++ /* clear wakeup status register */ ++ rtc_write_reg(RTC_HWRSR, 0x0); ++ ++ rtc_write_reg(RTC_HWCR, 0x0); ++ ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ rtc_rtccr |= 0x1 << 0; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ /* Put CPU to hibernate mode */ ++ rtc_write_reg(RTC_HCR, 0x1); ++ ++ /*poweroff the pmu*/ ++// jz_notifier_call(NOTEFY_PROI_HIGH, JZ_POST_HIBERNATION, NULL); ++ ++ mdelay(200); ++ ++ while(1) ++ printk("%s:We should NOT come here.%08x\n",__func__, inl(RTC_IOBASE + RTC_HCR)); ++} ++ ++void jz_wdt_restart(char *command) ++{ ++ printk("Restarting after 4 ms\n"); ++ if ((command != NULL) && !strcmp(command, "recovery")) { ++ while(cpm_inl(CPM_CPPSR) != RECOVERY_SIGNATURE) { ++ printk("set RECOVERY_SIGNATURE\n"); ++ cpm_outl(0x5a5a,CPM_CPSPPR); ++ cpm_outl(RECOVERY_SIGNATURE,CPM_CPPSR); ++ cpm_outl(0x0,CPM_CPSPPR); ++ udelay(100); ++ } ++ } else { ++ cpm_outl(0x5a5a,CPM_CPSPPR); ++ cpm_outl(REBOOT_SIGNATURE,CPM_CPPSR); ++ cpm_outl(0x0,CPM_CPSPPR); ++ } ++ ++ wdt_start_count(4); ++ mdelay(200); ++ while(1) ++ printk("check wdt.\n"); ++} ++ ++static void hibernate_restart(void) ++{ ++ uint32_t rtc_rtcsr,rtc_rtccr; ++ ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ ++ rtc_rtcsr = inl(RTC_IOBASE + RTC_RTCSR); ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ ++ rtc_write_reg(RTC_RTCSAR,rtc_rtcsr + 5); ++ rtc_rtccr &= ~(1 << 4 | 1 << 1); ++ rtc_rtccr |= 0x3 << 2; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ /* Clear reset status */ ++ cpm_outl(0,CPM_RSR); ++ ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ ++ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000)); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(125)); ++ ++ /* clear wakeup status register */ ++ rtc_write_reg(RTC_HWRSR, 0x0); ++ ++ rtc_write_reg(RTC_HWCR, 0x1); ++ ++ ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ rtc_rtccr |= 0x1 << 0; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ ++ /* Put CPU to hibernate mode */ ++ rtc_write_reg(RTC_HCR, 0x1); ++ ++ mdelay(200); ++ while(1) ++ printk("%s:We should NOT come here.%08x\n",__func__, inl(RTC_IOBASE + RTC_HCR)); ++} ++ ++#ifdef CONFIG_HIBERNATE_RESET ++void jz_hibernate_restart(char *command) ++{ ++ local_irq_disable(); ++ ++ if ((command != NULL) && !strcmp(command, "recovery")) { ++ jz_wdt_restart(command); ++ } ++ ++ hibernate_restart(); ++} ++#endif ++ ++int __init reset_init(void) ++{ ++ pm_power_off = jz_hibernate; ++#ifdef CONFIG_HIBERNATE_RESET ++ _machine_restart = jz_hibernate_restart; ++#else ++ _machine_restart = jz_wdt_restart; ++#endif ++ return 0; ++} ++arch_initcall(reset_init); ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////// ++struct wdt_reset { ++ unsigned stop; ++ unsigned msecs; ++ unsigned count; ++}; ++ ++/* ============================reset proc=================================== */ ++static char *reset_command[] = {"wdt","hibernate","recovery", "poweroff"}; ++ ++static int reset_show(struct seq_file *filq, void *v) ++{ ++ int len = 0, i; ++ ++ for(i = 0; i < ARRAY_SIZE(reset_command); i++) ++ seq_printf(filq, "%s\t", reset_command[i]); ++ seq_printf(filq,"\n"); ++ ++ return len; ++} ++ ++static int reset_write(struct file *file, const char __user *buffer, ++ size_t usize, loff_t *off) ++{ ++ int command_size = 0; ++ int i; ++ ++ if(usize == 0) ++ return -EINVAL; ++ ++ command_size = ARRAY_SIZE(reset_command); ++ for(i = 0;i < command_size; i++) { ++ if(!strncmp(buffer, reset_command[i], strlen(reset_command[i]))) ++ break; ++ } ++ if(i == command_size) ++ return -EINVAL; ++ ++ local_irq_disable(); ++ switch(i) { ++ case 0: ++ jz_wdt_restart(NULL); ++ break; ++ case 1: ++ hibernate_restart(); ++ break; ++ case 2: ++ jz_wdt_restart("recovery"); ++ break; ++ case 3: ++ jz_hibernate(); ++ break; ++ default: ++ printk("not support command %d\n", i); ++ } ++ ++ return usize; ++} ++static struct jz_single_file_ops reset_proc_fops = { ++ .read = reset_show, ++ .write = reset_write, ++}; ++/* ============================reset proc end=============================== */ ++ ++static int __init init_reset(void) ++{ ++ struct wdt_reset *wdt; ++ struct proc_dir_entry *p, *res; ++ ++ wdt = kmalloc(sizeof(struct wdt_reset),GFP_KERNEL); ++ if(!wdt) { ++ return -ENOMEM; ++ } ++ ++ wdt->count = 0; ++ wdt->msecs = 3000; ++ ++ wdt->stop = 1; ++ ++ p = jz_proc_mkdir("reset"); ++ if (!p) { ++ pr_warn("create_proc_entry for common reset failed.\n"); ++ return -ENODEV; ++ } ++ ++ res = jz_proc_create_data("reset", 0444, p, &reset_proc_fops, wdt); ++ ++ return 0; ++} ++module_init(init_reset); +diff --git a/arch/mips/xburst2/soc-x2000/serial.c b/arch/mips/xburst2/soc-x2000/serial.c +new file mode 100644 +index 000000000..563208c52 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/serial.c +@@ -0,0 +1,91 @@ ++/* ++ * JZ SOC serial routines for early_printk. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ */ ++ ++#include ++ ++#include ++ ++#define UART_BASE UART0_IOBASE ++#define UART_OFF 0x1000 ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++ ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++static void check_uart(char c); ++ ++volatile u8 *uart_base; ++typedef void (*putchar_f_t)(char); ++static putchar_f_t putchar_f = check_uart; ++ ++static void putchar(char ch) ++{ ++ int timeout = 10000; ++ volatile u8 *base = uart_base; ++ /* Wait for fifo to shift out some bytes */ ++ while ((base[OFF_LSR] & (LSR_TDRQ | LSR_TEMT)) ++ != (LSR_TDRQ | LSR_TEMT) && timeout--) ++ ; ++ base[OFF_TDR] = (u8)ch; ++} ++ ++static void putchar_dummy(char ch) ++{ ++ return; ++} ++ ++static void check_uart(char c) ++{ ++ /* We Couldn't use ioremap() here */ ++ volatile u8 *base = (volatile u8*)CKSEG1ADDR(UART0_IOBASE); ++ int i = 0; ++ for(i=0; i<10; i++) { ++ if(base[OFF_LCR]) ++ break; ++ base += UART_OFF; ++ } ++ ++ if(i<10) { ++ uart_base = base; ++ putchar_f = putchar; ++ putchar_f(c); ++ } else { ++ putchar_f = putchar_dummy; ++ } ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ putchar_f(c); ++} ++ ++void prom_putstr(char *s) ++{ ++ while(*s) { ++ if(*s == '\n') ++ putchar_f('\r'); ++ putchar_f(*s); ++ s++; ++ } ++} ++ ++#if 1 ++static char pbuffer[4096]; ++void prom_printk(const char *fmt, ...) { ++ va_list args; ++ ++ va_start(args, fmt); ++ vsnprintf(pbuffer, 4096, fmt, args); ++ va_end(args); ++ ++ prom_putstr(pbuffer); ++} ++#endif +diff --git a/arch/mips/xburst2/soc-x2000/setup.c b/arch/mips/xburst2/soc-x2000/setup.c +new file mode 100644 +index 000000000..c4d68f03b +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/setup.c +@@ -0,0 +1,84 @@ ++/* ++ * Ingenic Soc Setup ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++void __init cpm_reset(void) ++{ ++} ++ ++int __init setup_init(void) ++{ ++#if 0 ++ cpm_reset(); ++ /* Set bus priority here */ ++ *(volatile unsigned int *)0xb34f0240 = 0x00010003; ++ *(volatile unsigned int *)0xb34f0244 = 0x00010003; ++#endif ++ ++ return 0; ++} ++extern void __init init_all_clk(void); ++/* used by linux-mti code */ ++extern void *get_fdt_addr(void); ++void __init plat_mem_setup(void) ++{ ++ /* use IO_BASE, so that we can use phy addr on hard manual ++ * directly with in(bwlq)/out(bwlq) in io.h. ++ */ ++ set_io_port_base(IO_BASE); ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0xffffffff; ++ iomem_resource.start = 0x00000000; ++ iomem_resource.end = 0xffffffff; ++ setup_init(); ++ ++ __dt_setup_arch(get_fdt_addr()); ++ ++ return; ++} ++void __init device_tree_init(void) ++{ ++ unflatten_and_copy_device_tree(); ++} ++ ++static int __init plat_of_populate(void) ++{ ++ of_platform_default_populate(NULL, NULL, NULL); ++ return 0; ++} ++arch_initcall(plat_of_populate); ++ ++void __init plat_time_init(void) ++{ ++ of_clk_init(NULL); ++ ++ timer_probe(); ++} ++ ++void __init arch_init_irq(void) ++{ ++ irqchip_init(); ++} +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/Makefile b/arch/mips/xburst2/soc-x2000/sleep_firmware/Makefile +new file mode 100644 +index 000000000..4014918a8 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/Makefile +@@ -0,0 +1,42 @@ ++TOPDIR = . ++ ++CC = mips-linux-gnu-gcc ++LD = mips-linux-gnu-ld ++OBJCOPY = mips-linux-gnu-objcopy ++OBJDUMP = mips-linux-gnu-objdump ++drop-sections := .reginfo .mdebug .oomment .note .pdr .options .MIPS.options ++strip-flags := $(addprefix --remove-section=,$(drop-sections)) ++ ++CFLAGS += -I$(TOPDIR)/include ++CFLAGS += -nostdinc -Wall -Wundef -Werror-implicit-function-declaration \ ++ -fno-common -EL -Os -march=mips32 -mabi=32 -G 0 -mno-abicalls -fno-pic\ ++ -msoft-float ++ ++LDFLAGS := -nostdlib -EL -T target.ld ++OBJCOPY_ARGS := -O elf32-tradlittlemips ++ ++OBJS := $(TOPDIR)/src/fastboot_resume.o \ ++ $(TOPDIR)/src/uart.o ++ ++ ++all: $(TOPDIR)/firmware.bin ++ @hexdump -v -e '"0x" 1/4 "%08x" "," "\n"' $< > $(TOPDIR)/fastboot_resume_code.hex ++ ++$(TOPDIR)/firmware.bin:$(TOPDIR)/firmware.o ++ @$(LD) -nostdlib -EL -T $(TOPDIR)/target.ld $(OBJS) -Map $(TOPDIR)/tmp.map -o $(TOPDIR)/tmp.elf ++ @$(OBJCOPY) $(strip-flags) $(OBJCOPY_ARGS) -O binary $(TOPDIR)/tmp.elf $@ ++ @$(OBJDUMP) $(TOPDIR)/tmp.elf -D > tmp.dump ++$(TOPDIR)/firmware.o:$(OBJS) ++ ++ ++%.o:%.c ++ $(CC) $(CFLAGS) -o $@ -c $^ ++ ++%.o:%.S ++ $(CC) $(CFLAGS) -o $@ -c $^ ++ ++clean: ++ find . -name "*.o" | xargs rm -vf ++ find . -name "*.o.cmd" | xargs rm -vf ++ rm *.dump *.map *.elf *.bin *.hex ++ +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/Readme b/arch/mips/xburst2/soc-x2000/sleep_firmware/Readme +new file mode 100644 +index 000000000..215604c5a +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/Readme +@@ -0,0 +1,14 @@ ++ ++! this wakeup module is none of bussiness with the kernel. ++if you want to modify the code in the module. you should use ++the script mkmodule.sh right here. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/include/base.h b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/base.h +new file mode 100644 +index 000000000..b2eb14f02 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/base.h +@@ -0,0 +1,91 @@ ++ ++#ifndef __JZSOC_SOC_DEV_H__ ++#define __JZSOC_SOC_DEV_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++#define DDRC_BASE 0xb34f0000 ++#define DDRC_APB_OFFSET (-0x4e0000 + 0x2000) ++#define DDR_PHY_OFFSET (-0x4e0000 + 0x1000) ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 /* 64KB, AHB Bus Aribtier */ ++#define DDR_PHY_IOBASE 0x13011000 /* 4KB, DDR PHY */ ++#define DDRC_H0_IOBASE 0x13012000 /* 4KB, DDR Controller Registers@ASHB0 */ ++#define DPU_IOBASE 0x13050000 /* 64KB, LCD Controller */ ++#define CIM_IOBASE 0x13060000 /* 64KB, Camera Interface Module */ ++#define ROTATE_IOBASE 0x13070000 /* 64KB, Rotate DMA */ ++#define HELIX_IOBASE 0x13200000 /* 64KB VPU encoder */ ++#define FELIX_IOBASE 0x13300000 /* 64KB VPU decoder */ ++#define ISP0_IOBASE 0x13700000 /* 64KB Tiziano ISP0 */ ++#define ISP1_IOBASE 0x13800000 /* 64KB Tiziano ISP1 */ ++ ++/* AHB2 Bus Devices Base */ ++#define HARB2_IOBASE 0x13400000 /* 64KB, AHB Bus Arbiter */ ++#define NEMC_IOBASE 0x13410000 /* 64KB, External Normal Memory/Boot ROM/OTP Controller */ ++#define PDMA_IOBASE 0x13420000 /* 64KB, Programmable DMA Controller */ ++#define AES_IOBASE 0x13430000 /* 64KB, AES */ ++#define SFC_IOBASE 0x13440000 /* 64KB, SPI Flash Controller */ ++#define MSC0_IOBASE 0x13450000 /* 64KB, MMC SD Controller0 */ ++#define MSC1_IOBASE 0x13460000 /* 64KB, MMC SD Controller1 */ ++#define MSC2_IOBASE 0x13490000 /* 64KB, MMC SD Controller2 */ ++#define HASH_IOBASE 0x13470000 /* 64KB, HASH */ ++#define RSA_IOBASE 0x13480000 /* 64KB, RSA */ ++#define MAC0_IOBASE 0x134b0000 /* 64KB, GMAC/MAC */ ++#define MAC1_IOBASE 0x134a0000 /* 64KB, GMAC/MAC */ ++#define PWM_IOBASE 0x134c0000 /* 64KB, PWM */ ++#define DDRC_H2_IOBASE 0x134f0000 /* 4KB, DDR Controller Register @AHB2 */ ++#define AUDIO_IOBASE 0x134d0000 /* 64KB, Aduio System */ ++#define OTG_IOBASE 0x13500000 /* 256KB, OTG2.0 Controller */ ++#define EFUSE_IOBASE 0x13540000 /* 64KB, EFUSE */ ++//#define INTC_IOBASE 0x13600000 /* Interrupt Controller */ ++ ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 /* 4KB, Clocks and Power Manager */ ++#define TCU_IOBASE 0x10002000 /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++#define WDT_IOBASE TCU_IOBASE /* 4KB, Timer/Count Unit,OperatingSystemTimer,Watchdog Timer */ ++#define RTC_IOBASE 0x10003000 /* 4KB, Real-Time Clock */ ++#define GPIO_IOBASE 0x10010000 /* 4KB, General-Purpose I/O */ ++#define CODEC_IOBASE 0x10020000 /* 4KB, icodec I/O */ ++#define UART0_IOBASE 0x10030000 /* 4KB, UART0 Controller */ ++#define UART1_IOBASE 0x10031000 /* 4KB, UART1 Controller */ ++#define UART2_IOBASE 0x10032000 /* 4KB, UART2 Controller */ ++#define UART3_IOBASE 0x10033000 /* 4KB, UART3 Controller */ ++#define UART4_IOBASE 0x10034000 /* 4KB, UART4 Controller */ ++#define UART5_IOBASE 0x10035000 /* 4KB, UART5 Controller */ ++#define UART6_IOBASE 0x10036000 /* 4KB, UART6 Controller */ ++#define UART7_IOBASE 0x10037000 /* 4KB, UART7 Controller */ ++#define UART8_IOBASE 0x10038000 /* 4KB, UART8 Controller */ ++#define UART9_IOBASE 0x10039000 /* 4KB, UART9 Controller */ ++#define SCC_IOBASE 0x10040000 /* 4KB, Smart Card Controller */ ++#define SSI0_IOBASE 0x10043000 /* 4KB, Synchronous Serial Interface */ ++#define SSI1_IOBASE 0x10044000 /* 4KB, Synchronous Serial Interface */ ++#define I2C0_IOBASE 0x10050000 /* 4KB, I2C 0 Bus Interface */ ++#define I2C1_IOBASE 0x10051000 /* 4KB, I2C 1 Bus Interface */ ++#define I2C2_IOBASE 0x10052000 /* 4KB, I2C 2 Bus Interface */ ++#define I2C3_IOBASE 0x10053000 /* 4KB, I2C 3 Bus Interface */ ++#define I2C4_IOBASE 0x10054000 /* 4KB, I2C 4 Bus Interface */ ++#define I2C5_IOBASE 0x10055000 /* 4KB, I2C 5 Bus Interface */ ++#define SADC_IOBASE 0x10070000 /* 4KB, SADC */ ++#define DTRNG_IOBASE 0x10072000 /* 4KB, DTRNG */ ++#define MIPI_RX_2_IOBASE 0x10073000 /* 4KB, MIPI RX 2 Lane ctrl */ ++#define MIPI_RX_4_IOBASE 0x10074000 /* 4KB, MIPI RX 4 lane ctrl */ ++#define MIPI_TX_2_IOBASE 0x10075000 /* 4KB, MIPI TX 2 lane ctrl */ ++#define MIPI_RX_PHY_IOBASE 0x10076000 /* 4KB, MIPI RX PHY */ ++#define MIPI_TX_PHY_IOBASE 0x10077000 /* 4KB, MIPI TX PHY */ ++#define USB_PHY_IOBASE 0x10078000 /* 4KB, USB PHY */ ++ ++/* TODO: Others To Be add */ ++/* NAND CHIP Base Address */ ++#define NEMC_CS1_IOBASE 0X1b000000 ++#define NEMC_CS2_IOBASE 0X1a000000 ++#define NEMC_CS3_IOBASE 0X19000000 ++#define NEMC_CS4_IOBASE 0X18000000 ++#define NEMC_CS5_IOBASE 0X17000000 ++#define NEMC_CS6_IOBASE 0X16000000 ++ ++#define OST_IOBASE 0x12000000 ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/include/cpm.h b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/cpm.h +new file mode 100755 +index 000000000..495e3a4b1 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/cpm.h +@@ -0,0 +1,230 @@ ++/* ++ * X2000 CPM register definition ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __CPM_H__ ++#define __CPM_H__ ++ ++#define BIT0 (1 << 0) ++#define BIT1 (1 << 1) ++#define BIT2 (1 << 2) ++#define BIT3 (1 << 3) ++#define BIT4 (1 << 4) ++#define BIT5 (1 << 5) ++#define BIT6 (1 << 6) ++#define BIT7 (1 << 7) ++#define BIT8 (1 << 8) ++#define BIT9 (1 << 9) ++#define BIT10 (1 << 10) ++#define BIT11 (1 << 11) ++#define BIT12 (1 << 12) ++#define BIT13 (1 << 13) ++#define BIT14 (1 << 14) ++#define BIT15 (1 << 15) ++#define BIT16 (1 << 16) ++#define BIT17 (1 << 17) ++#define BIT18 (1 << 18) ++#define BIT19 (1 << 19) ++#define BIT20 (1 << 20) ++#define BIT21 (1 << 21) ++#define BIT22 (1 << 22) ++#define BIT23 (1 << 23) ++#define BIT24 (1 << 24) ++#define BIT25 (1 << 25) ++#define BIT26 (1 << 26) ++#define BIT27 (1 << 27) ++#define BIT28 (1 << 28) ++#define BIT29 (1 << 29) ++#define BIT30 (1 << 30) ++#define BIT31 (1 << 31) ++ ++/* ++ * Clock reset and power controller module(CPM) address definition ++ */ ++#define CPM_BASE 0xB0000000 ++ ++/* ++ * CPM registers offset address definition ++ */ ++#define CPM_CPCCR (0x00) ++#define CPM_RSR (0x08) ++#define CPM_RSACDR (0x50) ++#define CPM_CLKGR0 (0x20) ++#define CPM_OPCR (0x24) ++#define CPM_CLKGR1 (0x28) ++#define CPM_DDRCDR (0x2c) ++#define CPM_USBPCR (0x3c) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0xA4) ++#define CPM_MSC4CDR (0xA8) ++#define CPM_SFCCDR (0x74) ++#define CPM_CPCSR (0xd4) ++#define CPM_SLBC (0xc8) ++#define CPM_SLPC (0xcc) ++#define CPM_CPPCR (0x0c) ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++#define CPM_EXCLK_DS (0xE0) ++ ++/* ++ * CPM registers common define ++ */ ++/* Reset status register(RSR) */ ++#define RSR_P0R BIT2 ++#define RSR_WR BIT1 ++#define RSR_PR BIT0 ++ ++/* Clk Gate Register (CLKGR0) */ ++#define CLKGR0_DDR BIT31 ++#define CLKGR0_RSA BIT25 ++#define CLKGR0_AES BIT24 ++#define CLKGR0_PDMA BIT21 ++#define CLKGR0_OST BIT20 ++#define CLKGR0_TCU BIT18 ++#define CLKGR0_UART2 BIT16 ++#define CLKGR0_UART1 BIT15 ++#define CLKGR0_UART0 BIT14 ++#define CLKGR0_MSC1 BIT5 ++#define CLKGR0_MSC0 BIT4 ++#define CLKGR0_OTG BIT3 ++#define CLKGR0_SFC BIT2 ++#define CLKGR0_EFUSE BIT1 ++ ++/* Clk Gate Register (CLKGR1) */ ++#define CLKGR1_MSC4 BIT25 ++#define CLKGR1_HASH BIT6 ++ ++/* Msc Device Clock Divider Register (MSCnCDR) */ ++#define MSCCDR_DIV_LSB 0 ++#define MSCCDR_DIV_MASK BITS_H2L(7, MSCCDR_DIV_LSB) ++ ++#define MSCCDR_MPCS_LSB 30 ++#define MSCCDR_MPCS_MASK BITS_H2L(31, MSCCDR_MPCS_LSB) ++#define MSCCDR_MPCS_EXCLK (0x2 << MSCCDR_MPCS_LSB) ++ ++#define MSCCDR_BUSY BIT28 ++#define MSCCDR_CE BIT29 ++#define MSCCDR_EXCK_E BIT21 ++ ++/* Sleep Pc Register (SLPC) */ ++#define SLPC_SW_MAGIC 0x425753 // SWB (software boot) ++#define SLPC_SW_USB_BOOT (0x2 << 0) ++ ++/* APLL Control Register (CPAPCR) */ ++#define CPAPCR_PLLFD_LSB 20 ++#define CPAPCR_PLLFD_MASK BITS_H2L(28, CPAPCR_PLLFD_LSB) ++ ++#define CPAPCR_PLLRD_LSB 14 ++#define CPAPCR_PLLRD_MASK BITS_H2L(19, CPAPCR_PLLRD_LSB) ++ ++#define CPAPCR_PLLOD_LSB 11 ++#define CPAPCR_PLLOD_MASK BITS_H2L(13, CPAPCR_PLLOD_LSB) ++ ++#define CPAPCR_PLLRG_LSB 5 ++#define CPAPCR_PLLRG_MASK BITS_H2L(7, CPAPCR_PLLRG_LSB) ++ ++#define CPAPCR_PLL_ON BIT3 ++#define CPAPCR_PLL_LOCK BIT2 ++#define CPAPCR_PLL_EN BIT0 ++ ++/* EXCLK_DS MSC VOL SELECT */ ++#define EXCLKDS_POC_MSC BIT31 ++ ++ ++#define cpm_readl(o) readl(CPM_BASE + (o)) ++#define cpm_writel(b, o) writel(b, CPM_BASE + (o)) ++ ++ ++#define __cpm_start_sfc() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_SFC; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++#define __cpm_start_msc() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~(CLKGR0_MSC0 | CLKGR0_MSC1); \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ tmp = cpm_readl(CPM_CLKGR1); \ ++ tmp &= ~CLKGR1_MSC4; \ ++ cpm_writel(tmp, CPM_CLKGR1); \ ++ } while (0) ++#define __cpm_start_otg() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_OTG; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++ ++#define __cpm_start_uart0() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_UART0; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++#define __cpm_start_uart1() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_UART1; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++#define __cpm_start_uart2() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_UART2; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++#define __cpm_start_ost() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_CLKGR0); \ ++ tmp &= ~CLKGR0_OST; \ ++ cpm_writel(tmp, CPM_CLKGR0); \ ++ } while (0) ++ ++#define __cpm_msc4_vol_1_8V() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_EXCLK_DS); \ ++ tmp |= EXCLKDS_POC_MSC; \ ++ cpm_writel(tmp, CPM_EXCLK_DS); \ ++ } while (0) ++ ++#define __cpm_msc4_vol_3_3V() \ ++ do { \ ++ unsigned int tmp; \ ++ tmp = cpm_readl(CPM_EXCLK_DS); \ ++ tmp &= ~EXCLKDS_POC_MSC; \ ++ cpm_writel(tmp, CPM_EXCLK_DS); \ ++ } while (0) ++ ++#ifdef FPGA_TEST ++#define __cpm_msc_tuning_set(v, n) \ ++ do { \ ++ unsigned int tmp; \ ++ unsigned int off; \ ++ if(n==0) \ ++ off = CPM_MSC0CDR; \ ++ else if(n==4) \ ++ off = CPM_MSC4CDR; \ ++ else \ ++ off = CPM_MSC1CDR; \ ++ tmp = cpm_readl(off); \ ++ tmp &= ~(1 << 20); \ ++ tmp |= ((v) & 0x1) << 20; \ ++ cpm_writel(tmp, off); \ ++ } while (0) ++#endif ++ ++#endif /* __CPM_H__ */ +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/include/ddr.h b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/ddr.h +new file mode 100644 +index 000000000..241da4607 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/ddr.h +@@ -0,0 +1,289 @@ ++/* ++ * JZ4780 ddr definitions ++ * ++ * Copyright (c) 2013 Ingenic Semiconductor Co.,Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++ ++#ifndef __DDR_H__ ++#define __DDR_H__ ++ ++#include ++ ++/* ++ * DDR Controller Registers ++ **/ ++#define DDR_MEM_PHY_BASE 0x20000000 ++ ++#define DDRC_STATUS 0x0 ++#define DDRC_CFG 0x8 ++#define DDRC_CTRL 0x10 ++#define DDRC_LMR 0x18 ++#define DDRC_DLP 0x20 ++#define DDRC_AUTOSR_EN 0x28 ++#define DDRC_AUTOSR_CNT 0x30 ++#define DDRC_REFCNT 0x38 ++#define DDRC_DBGINFO 0xE8 ++#define DDRC_TIMING(n) (0x40 + 8 * (n - 1)) ++#define DDRC_MMAP0 0x78 ++#define DDRC_MMAP1 0x80 ++#define DDRC_HREGPRO 0xd8 ++#define DDRC_DWCFG (DDRC_APB_OFFSET + 0x00) ++#define DDRC_DWSTATUS (DDRC_APB_OFFSET + 0x04) ++#define DDRC_REMAP(n) (DDRC_APB_OFFSET + 0x08 + 4 * (n - 1)) ++#define DDRC_CGUC0 (DDRC_APB_OFFSET + 0x64) ++#define DDRC_CGUC1 (DDRC_APB_OFFSET + 0x68) ++#define DDRC_PREGPRO (DDRC_APB_OFFSET + 0x6c) ++ ++/* ++ * DDR Innophy registers ++ * */ ++#define DDRP_INNOPHY_PHY_RST (DDR_PHY_OFFSET + 0x000) ++#define DDRP_INNOPHY_MEM_CFG (DDR_PHY_OFFSET + 0x004) ++#define DDRP_INNOPHY_DQ_WIDTH (DDR_PHY_OFFSET + 0x07c) ++#define DDRP_INNOPHY_CL (DDR_PHY_OFFSET + 0x014) ++#define DDRP_INNOPHY_CWL (DDR_PHY_OFFSET + 0x01c) ++#define DDRP_INNOPHY_AL (DDR_PHY_OFFSET + 0x018) ++#define DDRP_INNOPHY_PLL_FBDIV (DDR_PHY_OFFSET + 0x080) ++#define DDRP_INNOPHY_PLL_CTRL (DDR_PHY_OFFSET + 0x084) ++#define DDRP_INNOPHY_PLL_PDIV (DDR_PHY_OFFSET + 0x088) ++#define DDRP_INNOPHY_PLL_LOCK (DDR_PHY_OFFSET + 0xc8) ++#define DDRP_INNOPHY_TRAINING_CTRL (DDR_PHY_OFFSET + 0x008) ++#define DDRP_INNOPHY_CALIB_DONE (DDR_PHY_OFFSET + 0xcc) ++#define DDRP_INNOPHY_CALIB_DELAY_AL (DDR_PHY_OFFSET + 0x190) ++#define DDRP_INNOPHY_CALIB_DELAY_AH (DDR_PHY_OFFSET + 0x194) ++#define DDRP_INNOPHY_CALIB_BYPASS_AL (DDR_PHY_OFFSET + 0x118) ++#define DDRP_INNOPHY_CALIB_BYPASS_AH (DDR_PHY_OFFSET + 0x158) ++#define DDRP_INNOPHY_WL_MODE1 (DDR_PHY_OFFSET + 0x00c) ++#define DDRP_INNOPHY_WL_MODE2 (DDR_PHY_OFFSET + 0x010) ++#define DDRP_INNOPHY_WL_DONE (DDR_PHY_OFFSET + 0x0c0) ++#define DDRP_INNOPHY_INIT_COMP (DDR_PHY_OFFSET + 0x0d0) ++ ++ ++/* ++ * DDRC REGISTER BITS DEFINE ++ * */ ++ ++/* DDRC Status Register */ ++#define DDRC_DSTATUS_MISS (1 << 6) ++#define DDRC_ST_DPDN (1 << 5) /* 0 DDR memory is NOT in deep-power-down state ++ 1 DDR memory is in deep-power-down state */ ++#define DDRC_ST_PDN (1 << 4) /* 0 DDR memory is NOT in power-down state ++ 1 DDR memory is in power-down state */ ++#define DDRC_ST_AREF (1 << 3) /* 0 DDR memory is NOT in auto-refresh state ++ 1 DDR memory is in auto-refresh state */ ++#define DDRC_ST_SREF (1 << 2) /* 0 DDR memory is NOT in self-refresh state ++ 1 DDR memory is in self-refresh state */ ++#define DDRC_ST_CKE1 (1 << 1) /* 0 CKE1 Pin is low ++ 1 CKE1 Pin is high */ ++#define DDRC_ST_CKE0 (1 << 0) /* 0 CKE0 Pin is low ++ 1 CKE0 Pin is high */ ++ ++/* DDRC Configure Register */ ++#define DDRC_CFG_ROW1_BIT 29 /* Row Address width. */ ++#define DDRC_CFG_ROW1_MASK (0x7 << DDRC_CFG_ROW1_BIT) ++#define DDRC_CFG_COL1_BIT 26 /* Row Address width. */ ++#define DDRC_CFG_COL1_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA1 25 /* Bank Address width of DDR memory */ ++#define DDRC_CFG_IMBA (1 << 16) ++#define DDRC_CFG_ROW0_BIT 13 /* Row Address width. */ ++#define DDRC_CFG_ROW0_MASK (0x7 << DDRC_CFG_ROW0_BIT) ++#define DDRC_CFG_COL0_BIT 10 /* Row Address width. */ ++#define DDRC_CFG_COL0_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA0 9 /* Bank Address width of DDR memory */ ++ ++#define DDRC_CFG_TYPE_BIT 3 ++#define DDRC_CFG_TYPE_MASK (0x7 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR1 (2 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_MDDR (3 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR2 (4 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR2 (5 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR3 (6 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR3 (7 << DDRC_CFG_TYPE_BIT) ++ ++#define DDRC_CFG_ODTEN (1 << 2) /* ODT EN */ ++#define DDRC_CFG_CS1EN (1 << 1) /* DDR Chip-Select-1 Enable */ ++#define DDRC_CFG_CS0EN (1 << 0) /* DDR Chip-Select-0 Enable */ ++ ++/* DDRC Control Register */ ++#define DDRC_CTRL_DFI_RST (1 << 23) ++#define DDRC_CTRL_DLL_RST (1 << 22) ++#define DDRC_CTRL_CTL_RST (1 << 21) ++#define DDRC_CTRL_CFG_RST (1 << 20) ++#define DDRC_CTRL_ACTPD (1 << 15) /* 0 Precharge all banks before entering power-down ++ 1 Do not precharge banks before entering power-down */ ++#define DDRC_CTRL_PDT_BIT 12 /* Power-Down Timer */ ++#define DDRC_CTRL_PDT_MASK (0x7 << DDRC_CTRL_PDT_BIT) ++#define DDRC_CTRL_PDT_DIS (0 << DDRC_CTRL_PDT_BIT) /* power-down disabled */ ++#define DDRC_CTRL_PDT_8 (1 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 8 tCK idle */ ++#define DDRC_CTRL_PDT_16 (2 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 16 tCK idle */ ++#define DDRC_CTRL_PDT_32 (3 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 32 tCK idle */ ++#define DDRC_CTRL_PDT_64 (4 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 64 tCK idle */ ++#define DDRC_CTRL_PDT_128 (5 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 128 tCK idle */ ++ ++#define DDRC_CTRL_PD_CCE (1 << 7) /* Power down clk freq change enable */ ++#define DDRC_CTRL_DPD (1 << 6) /* 1 Drive external MDDR device entering Deep-Power-Down mode */ ++#define DDRC_CTRL_SR (1 << 5) /* 1 Drive external DDR device entering self-refresh mode ++ 0 Drive external DDR device exiting self-refresh mode */ ++#define DDRC_CTRL_SR_CCE (1 << 4) /* Self refresh clk stop request enable */ ++#define DDRC_CTRL_CKE (1 << 1) /* 0 Not set CKE Pin High, 1 Set CKE Pin HIGH */ ++#define DDRC_CTRL_RESET (1 << 0) /* 0 End resetting ddrc_controller, 1 Resetting ddrc_controller */ ++ ++/* DDRC DFI low power handshake control register */ ++#define DDRC_DDLP_TCTLUDP_BIT 24 ++#define DDRC_DDLP_TCTLUDP_FF (0xff << DDRC_DDLP_TCTLUDP_BIT) ++ ++/* DDRC Load-Mode-Register */ ++#define DDRC_LMR_DDR_ADDR_BIT 12 /* When performing a DDR command, DDRC_ADDR[13:0] ++ corresponding to external DDR address Pin A[13:0] */ ++#define DDRC_LMR_DDR_ADDR_MASK (0xfffff << DDRC_LMR_DDR_ADDR_BIT) ++ ++#define DDRC_LMR_MA_BIT 16 /* FOR LPDDR2, MA[9:0] */ ++#define DDRC_LMR_OP_BIT 24 /* FOR LPDDR2, OP[9:0] */ ++ ++#define DDRC_LMR_BA_BIT 9 /* When performing a DDR command, BA[2:0] ++ corresponding to external DDR address Pin BA[2:0]. */ ++#define DDRC_LMR_BA_MASK (0x7 << DDRC_LMR_BA_BIT) ++#define DDRC_LMR_CMD_BIT 6 ++#define DDRC_LMR_CMD_MASK (0x7 << DDRC_LMR_CMD_BIT) ++#define DDRC_LMR_CMD_PREC (0 << DDRC_LMR_CMD_BIT)/* Precharge one bank/All banks */ ++#define DDRC_LMR_CMD_AUREF (1 << DDRC_LMR_CMD_BIT)/* Auto-Refresh */ ++#define DDRC_LMR_CMD_LMR (2 << DDRC_LMR_CMD_BIT)/* Load Mode Register */ ++#define DDRC_LMR_CMD_ZQCL_CS0 (3 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCL_CS1 (4 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS1 */ ++#define DDRC_LMR_CMD_ZQCS_CS0 (5 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCS_CS1 (6 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS1 */ ++ ++#define DDRC_LMR_TMRD_BIT 1 ++#define DDRC_LMR_TMRD_MASK (0x1f << DDRC_LMR_TMRD_BIT) ++#define DDRC_LMR_START (1 << 0) /* 0 No command is performed ++ 1 On the posedge of START, perform a command ++ defined by CMD field */ ++ ++/* DDRC Auto-Refresh Counter */ ++#define DDRC_REFCNT_REF_EN (1 << 0) /* Enable Refresh Counter */ ++#define DDRC_REFCNT_CLK_DIV_BIT 1 /* Clock Divider for auto-refresh counter. */ ++#define DDRC_REFCNT_CLK_DIV_MASK (0x7 << DDRC_REFCNT_CLKDIV_BIT) ++ ++#define DDRC_REFCNT_PREREF_CNT_BIT 4 ++#define DDRC_REFCNT_PREREF_CNT_MASK (0xf << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT(val) (val << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT_DEFAULT DDRC_REFCNT_PREREF_CNT(8) ++ ++#define DDRC_REFCNT_CNT_BIT 8 /* 8-bit counter */ ++#define DDRC_REFCNT_CNT_MASK (0xff << DDRC_REFCNT_CNT_BIT) ++ ++#define DDRC_REFCNT_CON_BIT 16 /* Constant value used to compare with CNT value. */ ++#define DDRC_REFCNT_CON_MASK (0xff << DDRC_REFCNT_CON_BIT) ++ ++#define DDRC_REFCNT_TRFC_BIT 24 ++#define DDRC_REFCNT_TRFC_MASK (0x3f << DDRC_REFCNT_TRFC_BIT) ++ ++#define DDRC_REFCNT_PREREF_EN_BIT 30 ++#define DDRC_REFCNT_PREREF_EN (1 << DDRC_REFCNT_PREREF_EN_BIT) ++ ++#define DDRC_REFCNT_PBREF_EN_BIT 31 ++#define DDRC_REFCNT_PBREF_EN (1 << DDRC_REFCNT_PBREF_EN_BIT) ++ ++/* DDRC Memory Map Config Register */ ++#define DDRC_MMAP_BASE_BIT 8 /* base address */ ++#define DDRC_MMAP_BASE_MASK (0xff << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP_MASK_BIT 0 /* address mask */ ++#define DDRC_MMAP_MASK_MASK (0xff << DDRC_MMAP_MASK_BIT) ++ ++#define DDRC_MMAP0_BASE (0x20 << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP1_BASE_64M (0x24 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_128M (0x28 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_256M (0x30 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++ ++#define DDRC_MMAP_MASK_64_64 (0xfc << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_128_128 (0xf8 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_256_256 (0xf0 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++ ++/* DDR device data width configure register */ ++#define DDRC_DWCFG_DFI_INIT_START (1 << 3) ++ ++/* DDR device status register */ ++#define DDRC_DWSTATUS_DFI_INIT_COMP (1 << 0) ++ ++/* DDRC AHB Bus Register Protection Register */ ++#define DDRC_HREGPRO_HPRO_EN (1 << 0) ++ ++/* DDRC APB Bus Register Protection Register */ ++#define DDRC_PREGPRO_PPRO_EN (1 << 0) ++ ++ ++/* DDRC clock gate unit configure 0 */ ++#define DDRC_CGU_PORT7 (1 << 28) ++#define DDRC_CGU_PORT6 (1 << 24) ++#define DDRC_CGU_PORT5 (1 << 20) ++#define DDRC_CGU_PORT4 (1 << 16) ++#define DDRC_CGU_PORT3 (1 << 12) ++#define DDRC_CGU_PORT2 (1 << 8) ++#define DDRC_CGU_PORT1 (1 << 4) ++#define DDRC_CGU_PORT0 (1 << 0) ++ ++/* DDRC clock gate unit configure 1 */ ++#define DDRC_CGU_BWM (1 << 8) ++#define DDRC_CGU_PCTRL (1 << 4) ++#define DDRC_CGU_SCH (1 << 1) ++#define DDRC_CGU_PA (1 << 0) ++ ++ ++ ++/* ++ * DDR INNOPHY REGISTER BITS DEFINE ++ * */ ++ ++/* DDRP DQ Width Register */ ++#define DDRP_DQ_WIDTH_DQ_H (1 << 1) ++#define DDRP_DQ_WIDTH_DQ_L (1 << 0) ++ ++/* DDRP Pll Ctrl Register */ ++#define DDRP_PLL_CTRL_PLLPDEN (1 << 1) ++ ++/* DDRP Training Ctrl Register */ ++#define DDRP_TRAINING_CTRL_WL_BP (1 << 3) ++#define DDRP_TRAINING_CTRL_WL_START (1 << 2) ++#define DDRP_TRAINING_CTRL_DSCSE_BP (1 << 1) ++#define DDRP_TRAINING_CTRL_DSACE_START (1 << 0) ++ ++/* DDRP Training Done Register */ ++#define DDRP_CALIB_DONE_HDQCFB (1 << 3) ++#define DDRP_CALIB_DONE_LDQCFB (1 << 2) ++#define DDRP_CALIB_DONE_HDQCFA (1 << 1) ++#define DDRP_CALIB_DONE_LDQCFA (1 << 0) ++#define DDRP_CALIB_DONE_HWRLFB (1 << 3) ++#define DDRP_CALIB_DONE_LWRLFB (1 << 2) ++#define DDRP_CALIB_DONE_HWRLFA (1 << 1) ++#define DDRP_CALIB_DONE_LWRLFA (1 << 0) ++ ++/* DDRP CALIB BP Register */ ++#define DDRP_CALIB_BP_CYCLESELBH_BIT 4 ++#define DDRP_CALIB_BP_OPHCSELBH_BIT 3 ++#define DDRP_CALIB_BP_DLLSELBH_BIT 0 ++ ++/* DDRP Init Complete Register */ ++#define DDRP_INIT_COMP (1 << 0) ++ ++#define DDRP_PLL_LOCK (1 << 3) ++ ++#define REG32(addr) *(volatile unsigned int *)(addr) ++ ++#define ddr_writel(value, reg) (REG32(DDRC_BASE + reg) = (value)) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++#endif /* __DDR_H__ */ +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/include/gpio.h b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/gpio.h +new file mode 100755 +index 000000000..8440f2a91 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/gpio.h +@@ -0,0 +1,267 @@ ++/* ++ * ++ * X2000 GPIO register definition. ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++/* check */ ++ ++#ifndef __GPIO_H__ ++#define __GPIO_H__ ++ ++ ++/************************************************************************* ++ * GPIO (General-Purpose I/O Ports) ++ *************************************************************************/ ++#define GPIO_BASE 0xB0010000 ++ ++#define GPA(x) (32 * 0 + (x)) ++#define GPB(x) (32 * 1 + (x)) ++#define GPC(x) (32 * 2 + (x)) ++#define GPD(x) (32 * 3 + (x)) ++#define GPE(x) (32 * 4 + (x)) ++#define GPF(x) (32 * 5 + (x)) ++ ++#define GPIO_PORT_NUM 6 ++#define MAX_GPIO_NUM 192 ++#define GPIO_WAKEUP GPF(31) //WAKE_UP key PF31 ++ ++//n = 0,1,2,3,4 (PORTA, PORTB, PORTC, PORTD, PORTE) ++#define GPIO_PXPIN(n) (0x00 + (n) * 0x100) /* PIN Level Register */ ++ ++#define GPIO_PXINT(n) (0x10 + (n) * 0x100) /* Port Interrupt Register */ ++#define GPIO_PXINTS(n) (0x14 + (n) * 0x100) /* Port Interrupt Set Register */ ++#define GPIO_PXINTC(n) (0x18 + (n) * 0x100) /* Port Interrupt Clear Register */ ++ ++#define GPIO_PXMASK(n) (0x20 + (n) * 0x100) /* Port Interrupt Mask Register */ ++#define GPIO_PXMASKS(n) (0x24 + (n) * 0x100) /* Port Interrupt Mask Set Reg */ ++#define GPIO_PXMASKC(n) (0x28 + (n) * 0x100) /* Port Interrupt Mask Clear Reg */ ++ ++#define GPIO_PXPAT1(n) (0x30 + (n) * 0x100) /* Port Pattern 1 Register */ ++#define GPIO_PXPAT1S(n) (0x34 + (n) * 0x100) /* Port Pattern 1 Set Reg. */ ++#define GPIO_PXPAT1C(n) (0x38 + (n) * 0x100) /* Port Pattern 1 Clear Reg. */ ++ ++#define GPIO_PXPAT0(n) (0x40 + (n) * 0x100) /* Port Pattern 0 Register */ ++#define GPIO_PXPAT0S(n) (0x44 + (n) * 0x100) /* Port Pattern 0 Set Register */ ++#define GPIO_PXPAT0C(n) (0x48 + (n) * 0x100) /* Port Pattern 0 Clear Register */ ++ ++#define GPIO_PXFLG(n) (0x50 + (n) * 0x100) /* Port Flag Register */ ++#define GPIO_PXFLGC(n) (0x58 + (n) * 0x100) /* Port Flag clear Register */ ++ ++#define GPIO_PXPU(n) (0x80 + (n) * 0x100) /* PORT PULL-UP State Register */ ++#define GPIO_PXPUS(n) (0x84 + (n) * 0x100) /* PORT PULL-UP State Set Register*/ ++#define GPIO_PXPUC(n) (0x88 + (n) * 0x100) /* PORT PULL-UP State Clear Register */ ++ ++#define GPIO_PXPD(n) (0x90 + (n) * 0x100) /* PORT PULL-DOWN State Register */ ++#define GPIO_PXPDS(n) (0x94 + (n) * 0x100) /* PORT PULL-DOWN State Set Register */ ++#define GPIO_PXPDC(n) (0x98 + (n) * 0x100) /* PORT PULL-DOWN State Set Register */ ++ ++#define gpio_readl(o) readl(GPIO_BASE + (o)) ++#define gpio_writel(b, o) writel(b, GPIO_BASE + (o)) ++ ++#ifndef __MIPS_ASSEMBLER ++ ++/*---------------------------------------------------------------- ++ * p is the port number (0,1,2,3,4,5) ++ * o is the pin offset (0-31) inside the port ++ * n is the absolute number of a pin (0-127), regardless of the port ++ */ ++ ++//---------------------------------------------------------------- ++/* ++ * Gpio Pull set ++ */ ++#define __gpio_set_hiz(v, p) \ ++do { \ ++ unsigned long val = v; \ ++ gpio_writel(val, GPIO_PXPUC(p)); \ ++ gpio_writel(val, GPIO_PXPDC(p)); \ ++} while (0) ++ ++/* ++ * UART0_TxD, UART0_RxD, PD27 ++ */ ++#define __gpio_as_uart0() \ ++do { \ ++ gpio_writel((3 << 23), GPIO_PXINTC(3)); \ ++ gpio_writel((3 << 23), GPIO_PXMASKC(3));\ ++ gpio_writel((3 << 23), GPIO_PXPAT1S(3));\ ++ gpio_writel((3 << 23), GPIO_PXPAT0C(3));\ ++} while (0) ++ ++/* ++ * UART1_TxD, UART1_RxD, PA23 ++ */ ++#define __gpio_as_uart1() \ ++do { \ ++ gpio_writel((3 << 23), GPIO_PXINTC(2)); \ ++ gpio_writel((3 << 23), GPIO_PXMASKC(2)); \ ++ gpio_writel((3 << 23), GPIO_PXPAT1C(2)); \ ++ gpio_writel((3 << 23), GPIO_PXPAT0S(2)); \ ++} while (0) ++ ++/* ++ * UART2_TxD, UART2_RxD ++ */ ++#define __gpio_as_uart2() \ ++do { \ ++ gpio_writel((3 << 30), GPIO_PXINTC(3)); \ ++ gpio_writel((3 << 30), GPIO_PXMASKC(3));\ ++ gpio_writel((3 << 30), GPIO_PXPAT1C(3));\ ++ gpio_writel((3 << 30), GPIO_PXPAT0C(3));\ ++} while (0) ++ ++/* ++ * CS2#, RD#, WR#, WAIT#, A0 ~ A5 ++ * @n: chip select number(1 ~ 4) ++ */ ++#define __gpio_as_nor(n) \ ++do { \ ++ gpio_writel((0x7 << 13), GPIO_PXINTC(1)); \ ++ gpio_writel((0x7 << 13), GPIO_PXMASKC(1)); \ ++ gpio_writel((0x7 << 13), GPIO_PXPAT1C(1)); \ ++ gpio_writel((0x7 << 13), GPIO_PXPAT0C(1)); \ ++ gpio_writel((0x3 << 23), GPIO_PXINTC(2)); \ ++ gpio_writel((0x3 << 23), GPIO_PXMASKC(2)); \ ++ gpio_writel((0x3 << 23), GPIO_PXPAT1S(2)); \ ++ gpio_writel((0x3 << 23), GPIO_PXPAT0S(2)); \ ++} while (0) ++/* ++ * D0 ~ D7 ++ */ ++#define __gpio_as_nor_8bit() \ ++do { \ ++ gpio_writel((0xffffffff), GPIO_PXINTC(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXMASKC(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXPAT1C(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXPAT0C(1)); \ ++} while (0) ++ ++/* ++ * D0 ~ D15 ++ */ ++#define __gpio_as_nor_16bit() \ ++do { \ ++ gpio_writel((0xffffffff), GPIO_PXINTC(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXMASKC(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXPAT1C(1)); \ ++ gpio_writel((0xffffffff), GPIO_PXPAT0C(1)); \ ++} while (0) ++ ++ ++/* gpio as sfc disable pull */ ++/* PE16 - PE21 */ ++#define __gpio_as_3_3V_sfc() \ ++do { \ ++ gpio_writel((0x3f << 16), GPIO_PXINTC(4)); \ ++ gpio_writel((0x3f << 16), GPIO_PXMASKC(4)); \ ++ gpio_writel((0x3f << 16), GPIO_PXPAT1C(4)); \ ++ gpio_writel((0x3f << 16), GPIO_PXPAT0C(4)); \ ++ if(!EFUSE_SWC_SFC) \ ++ __gpio_set_hiz((0x3f) << 16, 4); \ ++} while (0) ++ ++/* gpio as sfc disable pull */ ++/* PD17 - PD22 */ ++#define __gpio_as_1_8V_sfc() \ ++do { \ ++ gpio_writel((0x3f << 17), GPIO_PXINTC(3)); \ ++ gpio_writel((0x3f << 17), GPIO_PXMASKC(3)); \ ++ gpio_writel((0x3f << 17), GPIO_PXPAT1C(3)); \ ++ gpio_writel((0x3f << 17), GPIO_PXPAT0S(3)); \ ++ if(!EFUSE_SWC_SFC) \ ++ __gpio_set_hiz((0x3f) << 17, 3); \ ++} while (0) ++ ++/* ++ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D7 ++ */ ++ ++/* pull disable */ ++ ++/* PD17 - PD26, func0, 1bit*/ ++#define __gpio_as_msc0_1bit() \ ++do { \ ++ gpio_writel(0x7 << 17, GPIO_PXINTC(3)); \ ++ gpio_writel(0x7 << 17, GPIO_PXMASKC(3)); \ ++ gpio_writel(0x7 << 17, GPIO_PXPAT1C(3)); \ ++ gpio_writel(0x7 << 17, GPIO_PXPAT0C(3)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x7 << 17), 3); \ ++} while (0) ++ ++/* PD17 - PD26, func0, 4bit*/ ++#define __gpio_as_msc0_4bit() \ ++do { \ ++ gpio_writel(0x3f << 17, GPIO_PXINTC(3)); \ ++ gpio_writel(0x3f << 17, GPIO_PXMASKC(3)); \ ++ gpio_writel(0x3f << 17, GPIO_PXPAT1C(3)); \ ++ gpio_writel(0x3f << 17, GPIO_PXPAT0C(3)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x3f << 17), 3); \ ++} while (0) ++ ++ ++/* PD08 - PD13, func0, 1bit*/ ++#define __gpio_as_msc1_1bit() \ ++do { \ ++ gpio_writel(0x7 << 8, GPIO_PXINTC(3)); \ ++ gpio_writel(0x7 << 8, GPIO_PXMASKC(3)); \ ++ gpio_writel(0x7 << 8, GPIO_PXPAT1C(3)); \ ++ gpio_writel(0x7 << 8, GPIO_PXPAT0C(3)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x7 << 8), 3); \ ++} while (0) ++ ++/* PD08 - PD13, func0, 4bit*/ ++#define __gpio_as_msc1_4bit() \ ++do { \ ++ gpio_writel(0x3f << 8, GPIO_PXINTC(3)); \ ++ gpio_writel(0x3f << 8, GPIO_PXMASKC(3)); \ ++ gpio_writel(0x3f << 8, GPIO_PXPAT1C(3)); \ ++ gpio_writel(0x3f << 8, GPIO_PXPAT0C(3)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x3f << 8), 3); \ ++} while (0) ++ ++ ++/* PE0 - PE5, func0 */ ++#define __gpio_as_msc4_1bit() \ ++do { \ ++ gpio_writel((0x7 << 0), GPIO_PXINTC(4)); \ ++ gpio_writel((0x7 << 0), GPIO_PXMASKC(4)); \ ++ gpio_writel((0x7 << 0), GPIO_PXPAT1C(4)); \ ++ gpio_writel((0x7 << 0), GPIO_PXPAT0C(4)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x7) << 0, 4); \ ++} while (0) ++ ++/* PE0 - PE5, func0 */ ++#define __gpio_as_msc4_4bit() \ ++do { \ ++ gpio_writel((0x3f << 0), GPIO_PXINTC(4)); \ ++ gpio_writel((0x3f << 0), GPIO_PXMASKC(4)); \ ++ gpio_writel((0x3f << 0), GPIO_PXPAT1C(4)); \ ++ gpio_writel((0x3f << 0), GPIO_PXPAT0C(4)); \ ++ if(!EFUSE_SWC_MSC) \ ++ __gpio_set_hiz((0x3f) << 0, 4); \ ++} while (0) ++ ++#define bootsel_gpio_init() \ ++do{ \ ++ gpio_writel((0x7 << 25), GPIO_PXINTC(4)); \ ++ gpio_writel((0x7 << 25), GPIO_PXMASKS(4));\ ++ gpio_writel((0x7 << 25), GPIO_PXPAT1S(4));\ ++ gpio_writel((0x7 << 25), GPIO_PXPAT0C(4));\ ++ __gpio_set_hiz((0x7) << 25, 4); \ ++}while(0) ++ ++#define boot_select() ((gpio_readl(GPIO_PXPIN(4)) >> 25) & 0x7) ++ ++#define BOOT_SELECT_3_3V (0) ++#define BOOT_SELECT_1_8V (1) ++#endif /* __MIPS_ASSEMBLER */ ++ ++#endif /* __GPIO_H__ */ ++ +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/include/pm_fastboot.h b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/pm_fastboot.h +new file mode 100644 +index 000000000..3bad4d885 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/pm_fastboot.h +@@ -0,0 +1,106 @@ ++ ++ ++#define RTC_SLEEP_MEMORY_START 0xb0004000 ++#define RTC_SLEEP_MEMORY_END 0xb0005000 ++#define RTC_RAM_SP_ADDR (RTC_RAM_DATA_ADDR - 4) ++//#define RTC_RAM_SP_SIZE (256 - 4) ++#define RTC_RAM_DATA_ADDR 0xb0004c00 ++#define RTC_RAM_DATA_SIZE 1024 ++#define RTC_RAM_CODE_ADDR1 0xb0004000 ++#define RTC_RAM_CODE_ADDR2 (RTC_RAM_CODE_ADDR1 + 64) ++#define RTC_RAM_CODE_SIZE 0xb00 ++ ++#define SLEEP_CPU_SLEEP_TEXT 0xb2400000 ++#define SLEEP_CPU_SLEEP_LEN 4096 ++ ++ ++ ++struct pll_resume_reg { ++ unsigned int cpccr; ++ unsigned int cppcr; ++ unsigned int cpapcr; ++ unsigned int cpmpcr; ++ unsigned int cpepcr; ++ unsigned int ddrcdr; ++}; ++ ++struct ddrc_resume_reg { ++ unsigned int dcfg; ++ unsigned int dctrl; ++ unsigned int dlmr; ++ unsigned int ddlp; ++ unsigned int dasr_en; ++ unsigned int dasr_cnt; ++ unsigned int drefcnt; ++ unsigned int dtimming1; ++ unsigned int dtimming2; ++ unsigned int dtimming3; ++ unsigned int dtimming4; ++ unsigned int dtimming5; ++ unsigned int dmmap0; ++ unsigned int dmmap1; ++#if 0 ++ unsigned int dbwcfg; ++ unsigned int dbwstp; ++ unsigned int hregpro; ++ unsigned int dbgen; ++#endif ++ unsigned int dwcfg; ++ unsigned int dremap1; ++ unsigned int dremap2; ++ unsigned int dremap3; ++ unsigned int dremap4; ++ unsigned int dremap5; ++#if 0 ++ unsigned int cpac; ++ unsigned int cchc0; ++ unsigned int cchc1; ++ unsigned int cchc2; ++ unsigned int cchc3; ++ unsigned int cchc4; ++ unsigned int cchc5; ++ unsigned int cchc6; ++ unsigned int cchc7; ++ unsigned int cschc0; ++ unsigned int cschc1; ++ unsigned int cschc2; ++ unsigned int cschc3; ++ unsigned int cmonc0; ++ unsigned int cmonc1; ++ unsigned int cmonc2; ++ unsigned int cmonc3; ++ unsigned int cmonc4; ++#endif ++ unsigned int ccguc0; ++ unsigned int ccguc1; ++#if 0 ++ unsigned int pregpro; ++ unsigned int bufcfg; ++#endif ++}; ++ ++struct ddr_phy_resume_reg { ++ unsigned int phy_rst; ++ unsigned int mem_cfg; ++ unsigned int dq_width; ++ unsigned int cl; ++ unsigned int al; ++ unsigned int cwl; ++ unsigned int pll_fbdiv; ++ unsigned int pll_ctrl; ++ unsigned int pll_pdiv; ++ unsigned int training_ctrl; ++ unsigned int calib_bypass_al; ++ unsigned int calib_bypass_ah; ++ unsigned int wl_mode1; ++ unsigned int wl_mode2; ++ ++}; ++ ++struct store_regs { ++ unsigned int resume_pc; ++ struct pll_resume_reg pll_resume_reg; ++ struct ddrc_resume_reg ddrc_resume_reg; ++ struct ddr_phy_resume_reg ddr_phy_resume_reg; ++}; ++ +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/include/uart.h b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/uart.h +new file mode 100755 +index 000000000..b87b2d236 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/include/uart.h +@@ -0,0 +1,113 @@ ++/* ++ * ++ * X2000 UART register definition. ++ * ++ * Copyright (C) 2010 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __UART_H__ ++#define __UART_H__ ++ ++#define readb(addr) (*(volatile unsigned char *)(addr)) ++#define readw(addr) (*(volatile unsigned short *)(addr)) ++#define readl(addr) (*(volatile unsigned int *)(addr)) ++#define writeb(b, addr) (*(volatile unsigned char *)(addr)) = (b) ++#define writew(b, addr) (*(volatile unsigned short *)(addr)) = (b) ++#define writel(b, addr) (*(volatile unsigned int *)(addr)) = (b) ++ ++void serial_init(int); ++void serial_puts(int, const char *); ++void serial_put_hex(int, unsigned int); ++ ++ ++#define UART0_BASE 0xB0030000 ++ ++/************************************************************************* ++ * UART ++ *************************************************************************/ ++ ++#define UART_BASE UART0_BASE ++#define UART_OFF 0x1000 ++ ++/* Register Offset */ ++#define OFF_RDR(n) ((n) * UART_OFF + 0x00) /* R 8b H'xx */ ++#define OFF_TDR(n) ((n) * UART_OFF + 0x00) /* W 8b H'xx */ ++#define OFF_DLLR(n) ((n) * UART_OFF + 0x00) /* RW 8b H'00 */ ++#define OFF_DLHR(n) ((n) * UART_OFF + 0x04) /* RW 8b H'00 */ ++#define OFF_IER(n) ((n) * UART_OFF + 0x04) /* RW 8b H'00 */ ++#define OFF_ISR(n) ((n) * UART_OFF + 0x08) /* R 8b H'01 */ ++#define OFF_FCR(n) ((n) * UART_OFF + 0x08) /* W 8b H'00 */ ++#define OFF_LCR(n) ((n) * UART_OFF + 0x0C) /* RW 8b H'00 */ ++#define OFF_MCR(n) ((n) * UART_OFF + 0x10) /* RW 8b H'00 */ ++#define OFF_LSR(n) ((n) * UART_OFF + 0x14) /* R 8b H'00 */ ++#define OFF_MSR(n) ((n) * UART_OFF + 0x18) /* R 8b H'00 */ ++#define OFF_SPR(n) ((n) * UART_OFF + 0x1C) /* RW 8b H'00 */ ++#define OFF_SIRCR(n) ((n) * UART_OFF + 0x20) /* RW 8b H'00, UART0 */ ++#define OFF_UMR(n) ((n) * UART_OFF + 0x24) /* RW 8b H'00, UART M Register */ ++#define OFF_UACR(n) ((n) * UART_OFF + 0x28) /* RW 8b H'00, UART Add Cycle Register */ ++#define OFF_URCR(n) ((n) * UART_OFF + 0x40) /* R 8b 00, UART RXFIFO Counter Register */ ++#define OFF_UTCR(n) ((n) * UART_OFF + 0x44) /* R 8b 00, UART TXFIFO Counter Register */ ++ ++/* ++ * Define macros for UARTFCR ++ * UART FIFO Control Register ++ */ ++#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */ ++#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */ ++#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */ ++#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */ ++#define UARTFCR_UUE (1 << 4) /* 0: disable UART */ ++#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */ ++#define UARTFCR_RTRG_1 (0 << 6) ++#define UARTFCR_RTRG_16 (1 << 6) ++#define UARTFCR_RTRG_32 (2 << 6) ++#define UARTFCR_RTRG_60 (3 << 6) ++ ++/* ++ * Define macros for UARTLCR ++ * UART Line Control Register ++ */ ++#define UARTLCR_WLEN (3 << 0) /* word length */ ++#define UARTLCR_WLEN_5 (0 << 0) ++#define UARTLCR_WLEN_6 (1 << 0) ++#define UARTLCR_WLEN_7 (2 << 0) ++#define UARTLCR_WLEN_8 (3 << 0) ++#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 ++ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ ++#define UARTLCR_STOP1 (0 << 2) ++#define UARTLCR_STOP2 (1 << 2) ++#define UARTLCR_PE (1 << 3) /* 0: parity disable */ ++#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */ ++#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */ ++#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */ ++#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */ ++ ++/* ++ * Define macros for SIRCR ++ * Slow IrDA Control Register ++ */ ++#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: SIR mode */ ++#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: SIR mode */ ++#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length ++ 1: 0 pulse width is 1.6us for 115.2Kbps */ ++#define SIRCR_TDPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */ ++#define SIRCR_RDPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */ ++ ++/* ++ * Define macros for UART_LSR ++ * UART Line Status Register ++ */ ++#define UART_LSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */ ++#define UART_LSR_ORER (1 << 1) /* 0: no overrun error */ ++#define UART_LSR_PER (1 << 2) /* 0: no parity error */ ++#define UART_LSR_FER (1 << 3) /* 0; no framing error */ ++#define UART_LSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */ ++#define UART_LSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */ ++#define UART_LSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */ ++#define UART_LSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */ ++ ++#define uart_readl(o) readl(UART_BASE + (o)) ++#define uart_writel(b, o) writel(b, UART_BASE + (o)) ++ ++#endif /* __UART_H__ */ ++ +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/mkmodule.sh b/arch/mips/xburst2/soc-x2000/sleep_firmware/mkmodule.sh +new file mode 100755 +index 000000000..698e07160 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/mkmodule.sh +@@ -0,0 +1,7 @@ ++#!/bin/sh ++ ++make clean ++ ++make ++ ++cp fastboot_resume_code.hex ../ +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/src/fastboot_resume.c b/arch/mips/xburst2/soc-x2000/sleep_firmware/src/fastboot_resume.c +new file mode 100644 +index 000000000..dae83e238 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/src/fastboot_resume.c +@@ -0,0 +1,328 @@ ++#include ++#include ++ ++ ++ ++//#define FASTBOOT_DEBUG ++#ifdef FASTBOOT_DEBUG ++ ++#include ++ ++#define DEBUG(s) serial_puts(2, s) ++#define DEBUG_HEX(a) serial_put_hex(2, a) ++ ++ ++#define GPIO_PULSE() \ ++ while (1) { \ ++ *(volatile unsigned int *)0xb0010218 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010224 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010238 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010248 = (1 << 20); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ *(volatile unsigned int *)0xb0010218 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010224 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010238 = (1 << 20); \ ++ *(volatile unsigned int *)0xb0010244 = (1 << 20); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ __asm__ __volatile__("nop\n\t"); \ ++ } ++ ++ ++#else ++#define DEBUG(s) ++#define DEBUG_HEX(a) ++#endif ++ ++ ++static struct store_regs *store_regs; ++ ++ ++ ++void sys_clk_restore(void) ++{ ++ unsigned int tmp; ++ struct pll_resume_reg *pll_resume_reg; ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ ++ pll_resume_reg = &store_regs->pll_resume_reg; ++ ++ tmp = *(volatile unsigned int *)0xb0000000; ++ ++ tmp &= ~(7 << 20); ++ tmp |= (pll_resume_reg->cpccr & 0x000fffff); ++ *(volatile unsigned int *)0xb0000000 = tmp; ++ *(volatile unsigned int *)0xb0000000 |= (7 << 20); ++ while ((*(volatile unsigned int *)0xb00000d4) & 0x7); ++ ++ tmp = *(volatile unsigned int *)0xb0000000; ++ tmp &= ~(0xff << 24); ++ tmp |= (pll_resume_reg->cpccr & 0xff000000); ++ *(volatile unsigned int *)0xb0000000 = tmp; ++ ++ ++ while (!((*(volatile unsigned int *)0xb00000d4 & 0xf0000000) == 0xf0000000)); ++ ++} ++ ++ ++static void pll_restore(void) ++{ ++ struct pll_resume_reg *pll_resume_reg; ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ ++ pll_resume_reg = &store_regs->pll_resume_reg; ++ ++ *(volatile unsigned int *)0xb000000c = pll_resume_reg->cppcr; ++ ++ *(volatile unsigned int *)0xb0000010 = (pll_resume_reg->cpapcr & 0xfffffff0) | 1; ++ while (!((*(volatile unsigned int *)0xb0000010 >> 3) & 1)); ++ ++ *(volatile unsigned int *)0xb0000014 = (pll_resume_reg->cpmpcr & 0xfffffff0) | 1; ++ while (!((*(volatile unsigned int *)0xb0000014 >> 3) & 1)); ++ ++ *(volatile unsigned int *)0xb0000018 = (pll_resume_reg->cpepcr & 0xfffffff0) | 1; ++ while (!((*(volatile unsigned int *)0xb0000018 >> 3) & 1)); ++ ++ ++ *(volatile unsigned int *)0xb000002c = (pll_resume_reg->ddrcdr & 0xc000000f); ++ *(volatile unsigned int *)0xb000002c |= (1 << 29); ++ while (((*(volatile unsigned int *)0xb000002c) >> 28) & 1); ++ ++ sys_clk_restore(); ++} ++ ++ ++ ++static void phy_pll_init(struct ddr_phy_resume_reg *ddr_phy_resume_reg) ++{ ++ *(volatile unsigned int *)0xb3011084 |= (1 << 1); ++ ++ *(volatile unsigned int *)0xb3010080 &= ~0xff; ++ *(volatile unsigned int *)0xb3011080 |= ddr_phy_resume_reg->pll_fbdiv; ++ ++ *(volatile unsigned int *)0xb3010088 &= ~0xff; ++ *(volatile unsigned int *)0xb3011088 |= ddr_phy_resume_reg->pll_pdiv; ++ ++ *(volatile unsigned int *)0xb3010084 &= ~3; ++ *(volatile unsigned int *)0xb3011084 |= (ddr_phy_resume_reg->pll_ctrl & 0x1); ++ ++ *(volatile unsigned int *)0xb3011084 &= ~(1 << 1); //enable pll ++ ++ while(!(*(volatile unsigned int *)0xb30110c8 & (1 << 3))); //wait pll lock ++} ++ ++static void phy_cfg(struct ddr_phy_resume_reg *ddr_phy_resume_reg) ++{ ++ *(volatile unsigned int *)0xb3011004 = ddr_phy_resume_reg->mem_cfg; ++ *(volatile unsigned int *)0xb301107c = ddr_phy_resume_reg->dq_width; ++ *(volatile unsigned int *)0xb3011014 = ddr_phy_resume_reg->cl; ++ *(volatile unsigned int *)0xb3011018 = ddr_phy_resume_reg->al; ++ *(volatile unsigned int *)0xb301101c = ddr_phy_resume_reg->cwl; ++} ++ ++ ++ ++static void dfi_init(struct ddrc_resume_reg *ddrc_resume_reg) ++{ ++ *(volatile unsigned int *)0xb3012000 &= ~(1 << 3); //dfi_init_start = 0 ++ while(!(*(volatile unsigned int *)0xb3012004 & 0x1)); //wait dfi_init_compllete ++ *(volatile unsigned int *)0xb34f0008 = ddrc_resume_reg->dcfg; ++ ++} ++ ++ ++static void ddrc_init(struct ddrc_resume_reg *ddrc_resume_reg) ++{ ++ *(volatile unsigned int *)0xb34f0040 = ddrc_resume_reg->dtimming1; ++ *(volatile unsigned int *)0xb34f0048 = ddrc_resume_reg->dtimming2; ++ *(volatile unsigned int *)0xb34f0050 = ddrc_resume_reg->dtimming3; ++ *(volatile unsigned int *)0xb34f0058 = ddrc_resume_reg->dtimming4; ++ *(volatile unsigned int *)0xb34f0060 = ddrc_resume_reg->dtimming5; ++ *(volatile unsigned int *)0xb34f0078 = ddrc_resume_reg->dmmap0; ++ *(volatile unsigned int *)0xb34f0080 = ddrc_resume_reg->dmmap1; ++ *(volatile unsigned int *)0xb34f0038 = ddrc_resume_reg->drefcnt; ++ *(volatile unsigned int *)0xb34f0010 = ddrc_resume_reg->dctrl; ++ ++ *(volatile unsigned int *)0xb3012008 = ddrc_resume_reg->dremap1; ++ *(volatile unsigned int *)0xb301200c = ddrc_resume_reg->dremap2; ++ *(volatile unsigned int *)0xb3012010 = ddrc_resume_reg->dremap3; ++ *(volatile unsigned int *)0xb3012014 = ddrc_resume_reg->dremap4; ++ *(volatile unsigned int *)0xb3012018 = ddrc_resume_reg->dremap5; ++ ++ *(volatile unsigned int *)0xb3012000 &= ~0x3; ++ *(volatile unsigned int *)0xb3012000 |= ddrc_resume_reg->dwcfg & 0x3; ++} ++ ++static void ddr_init(void) ++{ ++ struct ddrc_resume_reg *ddrc_resume_reg; ++ struct ddr_phy_resume_reg *ddr_phy_resume_reg; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ ddrc_resume_reg = &store_regs->ddrc_resume_reg; ++ ddr_phy_resume_reg = &store_regs->ddr_phy_resume_reg; ++ ++ ++// *(volatile unsigned int *)0xb34f0010 = (0x1 << 20); //phy reset ++ phy_cfg(ddr_phy_resume_reg); ++// *(volatile unsigned int *)0xb34f0010 &= ~(0x1 << 20); ++ ++ phy_pll_init(ddr_phy_resume_reg); ++ dfi_init(ddrc_resume_reg); ++ ddrc_init(ddrc_resume_reg); ++} ++ ++#define DDR_PHY_OFFSET (-0x4e0000 + 0x1000) ++#define DDRP_INNOPHY_RXDLL_DELAY_AL (DDR_PHY_OFFSET + (0x48 << 2)) ++#define DDRP_INNOPHY_RXDLL_DELAY_AH (DDR_PHY_OFFSET + (0x58 << 2)) ++ ++#define REG32(addr) *(volatile unsigned int *)(addr) ++#define ddr_writel(value, reg) (REG32(DDRC_BASE + reg) = (value)) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++ ++static void ddrp_auto_calibration(void) ++{ ++ unsigned int reg_val = ddr_readl(DDRP_INNOPHY_TRAINING_CTRL); ++ unsigned int timeout = 0xffffff; ++ unsigned int wait_cal_done = DDRP_CALIB_DONE_HDQCFA | DDRP_CALIB_DONE_LDQCFA; ++ ++ reg_val &= ~(DDRP_TRAINING_CTRL_DSCSE_BP); ++ reg_val |= DDRP_TRAINING_CTRL_DSACE_START; ++ ddr_writel(reg_val, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ while(!((ddr_readl(DDRP_INNOPHY_CALIB_DONE) & wait_cal_done) == wait_cal_done) && --timeout) { ++ DEBUG("t"); ++ } ++ ++ if(!timeout) { ++ DEBUG("f"); ++ } ++ ddr_writel(0, DDRP_INNOPHY_TRAINING_CTRL); ++ ++} ++ ++ ++ ++ ++ ++static unsigned int get_resume_pc(void) ++{ ++ unsigned int resume_pc; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ resume_pc = store_regs->resume_pc; ++ ++ return resume_pc; ++} ++ ++ ++static void rtc_write_reg(unsigned int reg, unsigned int val) ++{ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ *(volatile unsigned int *)0xb000303c = 0xa55a; ++ while (!((*(volatile unsigned int *)0xb000303c >> 31) & 0x1) ); ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ ++ *(volatile unsigned int *)reg = val; ++ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++} ++ ++static unsigned int rtc_read_reg(unsigned int reg) ++{ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ ++ return *(volatile unsigned int *)reg; ++} ++ ++void fastboot_restore_code_2(void) ++{ ++ unsigned int resume_pc; ++ ++#ifdef FASTBOOT_DEBUG ++ serial_init(2); ++#endif ++ ++ resume_pc = get_resume_pc(); ++ DEBUG_HEX(resume_pc); ++ ++ DEBUG("fastboot begin restore\n"); ++ ++ pll_restore(); ++ DEBUG("pll restore ok\n"); ++ ++ ddr_init(); ++ ++ { ++ unsigned int ddrc_ctrl = *(volatile unsigned int *)0xb34f0010; ++ volatile unsigned int tmp; ++ ++ /* bufferen_core = 1 */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp |= (1 << 21); ++ rtc_write_reg(0xb0003048, tmp); ++ ++ /* exit ddr self refresh */ ++ ddrc_ctrl &= ~(1<<5); ++ ddrc_ctrl |= 1 << 1; ++ *(volatile unsigned int*)0xb34f0010 = ddrc_ctrl; ++ ++ while((*(volatile unsigned int *)0xb34f0000) & (1<<2)); ++ } ++ ++ ++ ddr_writel(1, DDRC_AUTOSR_EN); ++ while(ddr_readl(DDRC_STATUS) & (1<<2)); ++ ++ DEBUG("ddr restore finish\n"); ++ ++ ddrp_auto_calibration(); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "sync \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (resume_pc) ++ : ++ ); ++ ++} ++ ++ ++__attribute__((section(".resume"))) void fastboot_restore_code_1(void) ++{ ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set noreorder \n\t" ++ ".set mips32r2 \n\t" ++ "move $29, %0 \n\t" ++ "jr.hb %1 \n\t" ++ "nop \n\t" ++ ".set reorder \n\t" ++ ".set pop \n\t" ++ : ++ :"r" (RTC_RAM_SP_ADDR), "r"(fastboot_restore_code_2) ++ : ++ ); ++ ++} ++ ++ +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/src/uart.c b/arch/mips/xburst2/soc-x2000/sleep_firmware/src/uart.c +new file mode 100644 +index 000000000..abb6a82ac +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/src/uart.c +@@ -0,0 +1,97 @@ ++#include ++#include ++#include ++ ++static void serial_putc (int num, const char c) ++{ ++ if (c == '\n') ++ serial_putc (num, '\r'); ++ ++ /* Wait for fifo to shift out some bytes */ ++ while ( !((uart_readl(OFF_LSR(num)) & (UART_LSR_TDRQ | UART_LSR_TEMT)) == 0x60) ); ++ ++ uart_writel((unsigned char)c, OFF_TDR(num)); ++} ++ ++static void serial_setbrg(int num) ++{ ++ unsigned int baud_div, tmp; ++ ++ uart_writel(16, OFF_UMR(num)); ++ uart_writel(0, OFF_UACR(num)); ++ baud_div = 13; ++ ++ tmp = uart_readl(OFF_LCR(num)); ++ tmp |= UARTLCR_DLAB; ++ uart_writel(tmp, OFF_LCR(num)); ++ ++ uart_writel((baud_div >> 8) & 0xff, OFF_DLHR(num)); ++ uart_writel(baud_div & 0xff, OFF_DLLR(num)); ++ ++ tmp &= ~UARTLCR_DLAB; ++ uart_writel(tmp, OFF_LCR(num)); ++} ++ ++void serial_init(int num) ++{ ++ switch(num){ ++ case 0: ++ __gpio_as_uart0(); ++ __cpm_start_uart0(); ++ break; ++ case 2: ++ __gpio_as_uart2(); ++ __cpm_start_uart2(); ++ break; ++ case 1: ++ default: ++ __gpio_as_uart1(); ++ __cpm_start_uart1(); ++ break; ++ } ++ ++ uart_writel(0, OFF_SPR(num)); ++ uart_writel(0, OFF_MCR(num)); ++ ++ /* Disable port interrupts while changing hardware */ ++ uart_writel(0, OFF_IER(num)); ++ ++ /* Disable UART unit function */ ++ uart_writel(~UARTFCR_UUE, OFF_FCR(num)); ++ ++ /* Set both receiver and transmitter in UART mode (not SIR) */ ++ uart_writel(~(SIRCR_RSIRE | SIRCR_TSIRE), OFF_SIRCR(num)); ++ ++ /* Set databits, stopbits and parity. (8-bit data, 1 stopbit, no parity) */ ++ uart_writel(UARTLCR_WLEN_8 & ~(UARTLCR_STOP2), OFF_LCR(num)); ++ ++ serial_setbrg(num); ++ ++ /* Enable UART unit, enable and clear FIFO */ ++ uart_writel(UARTFCR_UUE | UARTFCR_TFLS | UARTFCR_RFLS | UARTFCR_FE, OFF_FCR(num)); ++ ++} ++ ++void serial_puts (int num, const char *s) ++{ ++ while (*s) { ++ serial_putc (num, *s++); ++ } ++} ++ ++void serial_put_hex(int num, unsigned int d) ++{ ++ char c[12]; ++ unsigned char i; ++ for(i = 0; i < 8; i++) ++ { ++ c[i] = (d >> ((7 - i) * 4)) & 0xf; ++ if(c[i] < 10) ++ c[i] += 0x30; ++ else ++ c[i] += (0x41 - 10); ++ } ++ c[8] = '\n'; ++ c[9] = 0; ++ serial_puts(num, c); ++} +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/target.ld b/arch/mips/xburst2/soc-x2000/sleep_firmware/target.ld +new file mode 100644 +index 000000000..44f03a97a +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/target.ld +@@ -0,0 +1,37 @@ ++OUTPUT_ARCH(mips) ++MEMORY{ ++ /* TOTAL MEM :4KBytes */ ++ ram : ORIGIN = 0xb0004000 , LENGTH = 2784 ++} ++ ++ENTRY(fastboot_restore_code_1) ++SECTIONS ++{ ++ .text : { ++ *(.resume) ++ *(.text) ++ } > ram ++ ++ .data : { ++ *(.data) ++ *(.rodata) ++ } > ram /**(.data)*/ ++ .bss : { ++ . = ALIGN(4); ++ __bss_start = .; ++ *(.sbss.*) ++ *(.bss.*) ++ *(COMMON) ++ . = ALIGN(4); ++ __bss_end = .; ++ } > ram ++ ++ ++ /DISCARD/ : { ++ *(COMMON) ++ *(.pdri) ++ *(.comment) ++ *(.gnu.attributes) ++ *(.reginfo) ++ } ++} +diff --git a/arch/mips/xburst2/soc-x2000/sleep_firmware/tmp.map b/arch/mips/xburst2/soc-x2000/sleep_firmware/tmp.map +new file mode 100644 +index 000000000..9b5f0312d +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2000/sleep_firmware/tmp.map +@@ -0,0 +1,75 @@ ++ ++Discarded input sections ++ ++ .reginfo 0x0000000000000000 0x18 ./src/fastboot_resume.o ++ .comment 0x0000000000000000 0x2f ./src/fastboot_resume.o ++ .gnu.attributes ++ 0x0000000000000000 0x10 ./src/fastboot_resume.o ++ .reginfo 0x0000000000000000 0x18 ./src/uart.o ++ .MIPS.abiflags ++ 0x0000000000000000 0x18 ./src/uart.o ++ .comment 0x0000000000000000 0x2f ./src/uart.o ++ .gnu.attributes ++ 0x0000000000000000 0x10 ./src/uart.o ++ ++Memory Configuration ++ ++Name Origin Length Attributes ++ram 0x00000000b0004000 0x0000000000000ae0 ++*default* 0x0000000000000000 0xffffffffffffffff ++ ++Linker script and memory map ++ ++ ++.text 0x00000000b0004000 0x690 ++ *(.resume) ++ .resume 0x00000000b0004000 0x24 ./src/fastboot_resume.o ++ 0x00000000b0004000 fastboot_restore_code_1 ++ *(.text) ++ *fill* 0x00000000b0004024 0xc ++ .text 0x00000000b0004030 0x400 ./src/fastboot_resume.o ++ 0x00000000b0004030 sys_clk_restore ++ 0x00000000b00040c0 fastboot_restore_code_2 ++ .text 0x00000000b0004430 0x260 ./src/uart.o ++ 0x00000000b000449c serial_init ++ 0x00000000b00045e4 serial_puts ++ 0x00000000b000461c serial_put_hex ++ ++.MIPS.abiflags 0x00000000b0004690 0x18 ++ .MIPS.abiflags ++ 0x00000000b0004690 0x18 ./src/fastboot_resume.o ++ ++.data 0x00000000b00046b0 0x0 ++ *(.data) ++ .data 0x00000000b00046b0 0x0 ./src/fastboot_resume.o ++ .data 0x00000000b00046b0 0x0 ./src/uart.o ++ *(.rodata) ++ ++.bss 0x00000000b00046b0 0x0 ++ 0x00000000b00046b0 . = ALIGN (0x4) ++ 0x00000000b00046b0 __bss_start = . ++ *(.sbss.*) ++ *(.bss.*) ++ *(COMMON) ++ 0x00000000b00046b0 . = ALIGN (0x4) ++ 0x00000000b00046b0 __bss_end = . ++ .bss 0x00000000b00046b0 0x0 ./src/fastboot_resume.o ++ .bss 0x00000000b00046b0 0x0 ./src/uart.o ++ ++/DISCARD/ ++ *(COMMON) ++ *(.pdri) ++ *(.comment) ++ *(.gnu.attributes) ++ *(.reginfo) ++LOAD ./src/fastboot_resume.o ++LOAD ./src/uart.o ++OUTPUT(./tmp.elf elf32-tradlittlemips) ++ ++.pdr 0x0000000000000000 0xe0 ++ .pdr 0x0000000000000000 0x60 ./src/fastboot_resume.o ++ .pdr 0x0000000000000060 0x80 ./src/uart.o ++ ++.mdebug.abi32 0x0000000000000000 0x0 ++ .mdebug.abi32 0x0000000000000000 0x0 ./src/fastboot_resume.o ++ .mdebug.abi32 0x0000000000000000 0x0 ./src/uart.o +diff --git a/arch/mips/xburst2/soc-x2500/Kconfig.DT b/arch/mips/xburst2/soc-x2500/Kconfig.DT +new file mode 100644 +index 000000000..8324a4809 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/Kconfig.DT +@@ -0,0 +1,15 @@ ++choice ++ prompt "device tree select for X2500 boards" ++ default DT_HIPPO_V10 ++ depends on SOC_X2500 ++ ++config DT_GANDER_V10 ++ bool "x2500 gander_v10" ++config DT_DARWIN_V14 ++ bool "x2500 darwin_v14" ++config DT_HIPPO_V10 ++ bool "x2500 hippo_v10" ++config DT_HIPPO_V12 ++ bool "x2500 hippo_v12" ++ ++endchoice +diff --git a/arch/mips/xburst2/soc-x2500/Makefile b/arch/mips/xburst2/soc-x2500/Makefile +new file mode 100644 +index 000000000..ce532920c +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/Makefile +@@ -0,0 +1,8 @@ ++obj-y += setup.o ++obj-y += serial.o ++ ++obj-y += pm.o ++obj-y += regs_save_restore.o ++obj-y += libdmmu.o ++obj-y += gpio.o ++obj-y += reset.o +diff --git a/arch/mips/xburst2/soc-x2500/gpio.c b/arch/mips/xburst2/soc-x2500/gpio.c +new file mode 100644 +index 000000000..606920fda +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/gpio.c +@@ -0,0 +1,123 @@ ++#include ++#include ++#include ++#include ++#include ++ ++#define GPIO_PORT_OFF 0x1000 ++#define GPIO_SHADOW_OFF 0x7000 ++ ++#define PXPIN 0x00 /* PIN Level Register */ ++#define PXINT 0x10 /* Port Interrupt Register */ ++#define PXINTS 0x14 /* Port Interrupt Set Register */ ++#define PXINTC 0x18 /* Port Interrupt Clear Register */ ++#define PXMSK 0x20 /* Port Interrupt Mask Reg */ ++#define PXMSKS 0x24 /* Port Interrupt Mask Set Reg */ ++#define PXMSKC 0x28 /* Port Interrupt Mask Clear Reg */ ++#define PXPAT1 0x30 /* Port Pattern 1 Set Reg. */ ++#define PXPAT1S 0x34 /* Port Pattern 1 Set Reg. */ ++#define PXPAT1C 0x38 /* Port Pattern 1 Clear Reg. */ ++#define PXPAT0 0x40 /* Port Pattern 0 Register */ ++#define PXPAT0S 0x44 /* Port Pattern 0 Set Register */ ++#define PXPAT0C 0x48 /* Port Pattern 0 Clear Register */ ++#define PXFLG 0x50 /* Port Flag Register */ ++#define PXFLGC 0x58 /* Port Flag clear Register */ ++#define PXPU 0x110 /* Port PULL-UP State Register */ ++#define PXPUS 0x114 /* Port PULL-UP State Set Register */ ++#define PXPUC 0x118 /* Port PULL-UP State Clear Register */ ++#define PXPD 0x120 /* Port PULL-DOWN State Register */ ++#define PXPDS 0x124 /* Port PULL-DOWN State Set Register */ ++#define PXPDC 0x128 /* Port PULL-DOWN State Clear Register */ ++ ++#define PZGID2LD 0xF0 /* GPIOZ Group ID to load */ ++ ++#define SHADOW 5 ++ ++static const unsigned long gpiobase[] = { ++ [0] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 0 * GPIO_PORT_OFF), ++ [1] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 1 * GPIO_PORT_OFF), ++ [2] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 2 * GPIO_PORT_OFF), ++ [3] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 3 * GPIO_PORT_OFF), ++ [4] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + 4 * GPIO_PORT_OFF), ++ ++ [SHADOW] = (unsigned long)CKSEG1ADDR(GPIO_IOBASE + GPIO_SHADOW_OFF), ++}; ++ ++#define GPIO_ADDR(port, reg) ((volatile unsigned long *)(gpiobase[port] + reg)) ++ ++static inline void gpio_write(int port, unsigned int reg, int val) ++{ ++ *GPIO_ADDR(port, reg) = val; ++} ++ ++static inline unsigned int gpio_read(int port, unsigned int reg) ++{ ++ return *GPIO_ADDR(port, reg); ++} ++ ++static void hal_gpio_port_set_func(int port, unsigned int pins, enum gpio_function func) ++{ ++ /* func option */ ++ if (func & 0x10) { ++ if (func & 0x8) ++ gpio_write(SHADOW, PXINTS, pins); ++ else ++ gpio_write(SHADOW, PXINTC, pins); ++ ++ if (func & 0x4) ++ gpio_write(SHADOW, PXMSKS, pins); ++ else ++ gpio_write(SHADOW, PXMSKC, pins); ++ ++ if (func & 0x2) ++ gpio_write(SHADOW, PXPAT1S, pins); ++ else ++ gpio_write(SHADOW, PXPAT1C, pins); ++ ++ if (func & 0x1) ++ gpio_write(SHADOW, PXPAT0S, pins); ++ else ++ gpio_write(SHADOW, PXPAT0C, pins); ++ ++ /* configure PzGID2LD to specify which port group to load */ ++ gpio_write(SHADOW, PZGID2LD, port); ++ } ++ ++ if (func & 0x80) { ++ int pull = (func >> 5) & 0x3; ++ if (pull == 0) { // no pull ++ gpio_write(port, PXPUC, pins); ++ gpio_write(port, PXPDC, pins); ++ } ++ if (pull == 1) { // pull up ++ gpio_write(port, PXPDC, pins); ++ gpio_write(port, PXPUS, pins); ++ } ++ if (pull == 2) { // pull down ++ gpio_write(port, PXPUC, pins); ++ gpio_write(port, PXPDS, pins); ++ } ++ } ++} ++ ++unsigned long ingenic_pinctrl_lock(int port); ++void ingenic_pinctrl_unlock(int port, unsigned long flags); ++ ++int jzgpio_set_func(int port, enum gpio_function func, unsigned long pins) ++{ ++ unsigned long flags; ++ ++ if (port < 0 || port > 4) { ++ printk(KERN_ERR "gpio: invalid gpio port for x2000: %d\n", port); ++ return -EINVAL; ++ } ++ ++ flags = ingenic_pinctrl_lock(port); ++ ++ hal_gpio_port_set_func(port, pins, func); ++ ++ ingenic_pinctrl_unlock(port, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL(jzgpio_set_func); +diff --git a/arch/mips/xburst2/soc-x2500/include/cpu-feature-overrides.h b/arch/mips/xburst2/soc-x2500/include/cpu-feature-overrides.h +new file mode 100644 +index 000000000..a0d0c1ff3 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/cpu-feature-overrides.h +@@ -0,0 +1,67 @@ ++/* ++ * Copyright (C) 2008 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++#define __ASM_MACH_INGENIC_CPU_FEATURE_OVERRIDES_H__ ++ ++ ++#define cpu_dcache_size() (32 * 1024) ++#define cpu_dcache_ways() 8 ++#define cpu_dcache_line_size() 32 ++#define cpu_icache_size() (32 * 1024) ++#define cpu_icache_ways() 8 ++#define cpu_icache_line_size() 32 ++#define cpu_has_xpa 0 ++#define cpu_has_tlb 1 ++#define cpu_has_tlbinv 1 ++#define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_4k_cache 1 ++#define cpu_has_tx39_cache 0 ++#define cpu_has_fpu 1 ++#define cpu_has_32fpr 0 ++#define cpu_has_counter 0 ++#define cpu_has_watch 1 ++#define cpu_has_divec 1 ++#define cpu_has_vce 0 ++#define cpu_has_cache_cdex_p 0 ++#define cpu_has_cache_cdex_s 0 ++#define cpu_has_prefetch 1 ++#define cpu_has_mcheck 1 ++#define cpu_has_ejtag 0 ++#define cpu_has_llsc 1 ++#define kernel_uses_llsc cpu_has_llsc ++#define cpu_has_mips16 0 ++#define cpu_has_mdmx 0 ++#define cpu_has_mips3d 0 ++#define cpu_has_smartmips 0 ++#define cpu_has_vtag_icache 0 ++#define cpu_has_dc_aliases 0 ++#define cpu_has_ic_fills_f_dc 0 ++#define cpu_has_pindexed_dcache 0 ++#define cpu_icache_snoops_remote_store 0 ++#define cpu_has_mips32r1 0 ++#define cpu_has_mips32r2 1 ++#define cpu_has_mips64r1 0 ++#define cpu_has_mips64r2 0 ++#define cpu_has_dsp 0 ++#define cpu_has_mipsmt 0 ++#define cpu_has_userlocal 1 ++#define cpu_has_rixi 1 ++#define cpu_has_nofpuex 0 ++#define cpu_has_64bits 0 ++#define cpu_has_64bit_zero_reg 0 ++#define cpu_has_vint 0 ++#define cpu_has_veic 0 ++#define cpu_has_inclusive_pcaches 0 ++#define kernel_uses_smartmips_rixi 0 ++#define cpu_has_mxu 0 ++#define cpu_has_mxuv3 1 ++#endif +diff --git a/arch/mips/xburst2/soc-x2500/include/irq.h b/arch/mips/xburst2/soc-x2500/include/irq.h +new file mode 100644 +index 000000000..11cef19d6 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/irq.h +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 2010 Ingenic Semiconductor Inc. ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_MACH_INGENIC_IRQ_H__ ++#define __ASM_MACH_INGENIC_IRQ_H__ ++#include ++#include ++ ++enum { ++#define GPIO_NR_IRQS (32 * 5 + 16) ++ IRQ_GPIO_BASE = (IRQ_INTC_END + 1), ++ IRQ_GPIO_END = IRQ_GPIO_BASE + GPIO_NR_IRQS - 1, ++ ++#define TCU_NR_IRQS (8) ++ IRQ_TCU_BASE, ++ IRQ_TCU_END = IRQ_TCU_BASE + TCU_NR_IRQS - 1, ++ ++#define MCU_NR_IRQS (5) ++ IRQ_MCU_BASE, ++ IRQ_MCU_END = IRQ_MCU_BASE + MCU_NR_IRQS - 1, ++ ++#define SADC_NR_IRQS (8) ++ IRQ_SADC_BASE, ++ IRQ_SADC_END = IRQ_SADC_BASE + SADC_NR_IRQS - 1, ++ ++#define RESERVED_NR_IRQS (150) ++ IRQ_RESERVED_BASE, ++ IRQ_RESERVED_END = IRQ_RESERVED_BASE + RESERVED_NR_IRQS - 1, ++ ++ NR_IRQS, ++}; ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2500/include/libdmmu.h b/arch/mips/xburst2/soc-x2500/include/libdmmu.h +new file mode 100644 +index 000000000..6e0fbdb42 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/libdmmu.h +@@ -0,0 +1,30 @@ ++#ifndef _LIBDMMU_ ++#define _LIBDMMU_ ++ ++#include ++ ++ ++struct dmmu_mm_ops { ++ int (*mm_release)(void *data); ++}; ++ ++struct dmmu_mm_notifier { ++ ++ struct device *dev; ++ void *data; ++ struct list_head list; ++ ++ struct dmmu_mm_ops *ops; ++}; ++ ++int dmmu_register_mm_notifier(struct dmmu_mm_notifier *dmn); ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len); ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len); ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len); ++int dmmu_unmap_all(struct device *dev); ++void dmmu_dump_vaddr(unsigned long vaddr); ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode); ++int dmmu_dump_map(unsigned long vaddr); ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/base.h b/arch/mips/xburst2/soc-x2500/include/soc/base.h +new file mode 100644 +index 000000000..7e60f3f09 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/base.h +@@ -0,0 +1,97 @@ ++ ++#ifndef __JZSOC_SOC_DEV_H__ ++#define __JZSOC_SOC_DEV_H__ ++ ++/* ++ * Define the module base addresses ++ */ ++ ++/* AHB0 BUS Devices Base */ ++#define HARB0_IOBASE 0x13000000 ++#define DDRC_BASE 0xb34f0000 ++#define DDRC1_IOBASE 0x13010000 /*DDR_APB_BASE*/ ++#define DDRC_IOBASE 0x134f0000 /*TODO:*/ ++#define DDRPHY_IOBASE 0x13011000 /*TODO:*/ ++#define AXI_ARB1_IOBASE 0x13013000 /*TODO:*/ ++#define AXI_ARB2_IOBASE 0x13014000 /*TODO:*/ ++#define LCDC_IOBASE 0x13050000 ++#define MSC0_IOBASE 0x13060000 ++#define MSC1_IOBASE 0x13070000 ++#define IPU_IOBASE 0x13080000 ++#define BSCALER_IOBASE 0x13090000 ++#define MONITOR_IOBASE 0x130a0000 ++#define I2D_IOBASE 0x130b0000 ++#define VO_IOBASE 0x130c0000 ++#define DRAW_BOX_IOBASE 0x130d0000 ++#define ISP_IOBASE 0x13300000 ++#define LZMA_IOBASE 0x13090000 ++ ++/* AHB1 BUS Devices Base */ ++#define RTC_IOBASE 0x132a0000 ++#define EL150_IOBASE 0x13200000 ++#define RADIX_IOBASE 0x13100000 ++#define RADIX_IOBASE_UNIT(ID) (RADIX_IOBASE + 0x400000 * ID) ++#define AVPU_IOBASE 0x13200000 ++#define AVPU_IOBASE_UNIT(ID) (AVPU_IOBASE + 0x400000 * ID) ++ ++/* AHB2 BUS Devices Base */ ++#define HARB2_IOBASE 0x13400000 ++#define NEMC_IOBASE 0x13410000 ++#define PDMA_IOBASE 0x13420000 ++#define AES_IOBASE 0x13430000 ++#define SFC_IOBASE 0x13440000 ++#define HASH_IOBASE 0x13480000 ++#define GMAC_IOBASE 0x134b0000 ++#define RSA_IOBASE 0x134c0000 ++#define OTG_IOBASE 0x13500000 ++#define EFUSE_IOBASE 0x13540000 ++#define INTC_IOBASE 0x10001000 ++ ++/* CPU and OST */ ++#define G_OST_IOBASE 0x12000000 /* G_OST_BASE */ ++#define N_OST_IOBASE 0x12100000 /* N_OST_BASE */ ++#define CCU_IOBASE 0x12200000 ++#define INTCN_IOBASE 0x12300000 ++#define SRAM_IOBASE 0x12400000 ++#define NNDMA_IOBASE 0x12500000 ++#define LEPOST_IOBASE 0x12600000 /* RISC-V OST */ ++#define LEPCCU_IOBASE 0x12700000 /* RISC-V CCU */ ++ ++/* APB BUS Devices Base */ ++#define CPM_IOBASE 0x10000000 ++#define TCU_IOBASE 0x10002000 ++#define MIPI_DSI_TX_IOBASE 0x10003000 ++#define MIPI_DSI_PHY_IOBASE 0x10004000 ++#define GPIO_IOBASE 0x10010000 ++#define AIC0_IOBASE 0x10020000 ++#define CODEC_IOBASE 0x10021000 ++#define MIPI_PHY_IOBASE 0x10022000 ++#define MIPI_CSI_IOBASE 0x10023000 ++#define UART0_IOBASE 0x10030000 ++#define UART1_IOBASE 0x10031000 ++#define UART2_IOBASE 0x10032000 ++#define UART3_IOBASE 0x10033000 ++#define DMIC_IOBASE 0x10034000 ++#define SSISLV_IOBASE 0x10040000 ++#define SSI0_IOBASE 0x10043000 ++#define SSI1_IOBASE 0x10044000 ++#define I2C0_IOBASE 0x10050000 ++#define I2C1_IOBASE 0x10051000 ++#define I2C2_IOBASE 0x10052000 ++#define I2C3_IOBASE 0x10053000 ++#define MIPI_RX_4L_IOBASE 0x10054000 ++#define USB_IOBASE 0x10060000 ++#define DES_IOBASE 0x10061000 ++#define SADC_IOBASE 0x10070000 ++#define DTRNG_IOBASE 0x10072000 ++#define WDT_IOBASE 0x10002000 ++ ++/* NAND CHIP Base Address*/ ++#define NEMC_CS1_IOBASE 0X1b000000 ++#define NEMC_CS2_IOBASE 0X1a000000 ++#define NEMC_CS3_IOBASE 0X19000000 ++#define NEMC_CS4_IOBASE 0X18000000 ++#define NEMC_CS5_IOBASE 0X17000000 ++#define NEMC_CS6_IOBASE 0X16000000 ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/cache.h b/arch/mips/xburst2/soc-x2500/include/soc/cache.h +new file mode 100644 +index 000000000..249e4230a +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/cache.h +@@ -0,0 +1,73 @@ ++#ifndef __CHIP_CACHE_H__ ++#define __CHIP_CACHE_H__ ++#include ++#include ++ ++#define Index_Prefetch_I 0x1c ++ ++ ++#define cache_prefetch(label,size) \ ++do{ \ ++ unsigned long addr,end; \ ++ /* Prefetch codes from label */ \ ++ addr = (unsigned long)(&&label) & ~(32 - 1); \ ++ end = (unsigned long)(&&label + size) & ~(32 - 1); \ ++ end += 32; \ ++ for (; addr < end; addr += 32) { \ ++ __asm__ volatile ( \ ++ ".set push \n\t" \ ++ ".set mips32 \n\t" \ ++ " cache %0, 0(%1)\n\t" \ ++ ".set pop \n\t" \ ++ : \ ++ : "I" (Index_Prefetch_I), "r"(addr)); \ ++ } \ ++} \ ++while(0) ++ ++#define K0BASE KSEG0 ++#define CFG_DCACHE_SIZE 32768 ++#define CFG_ICACHE_SIZE 32768 ++#define CFG_CACHELINE_SIZE 32 ++ ++#define CFG_SDCACHE_SIZE (512*1024) ++#define CFG_SDCACHELINE_SIZE 64 ++ ++static inline void __jz_flush_cache_all(void) ++{ ++ register unsigned long addr; ++ /* Clear CP0 TagLo */ ++ for (addr = K0BASE; addr < (K0BASE + CFG_DCACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Writeback_Inv_D), "r"(addr)); ++ } ++ ++ for (addr = K0BASE; addr < (K0BASE + CFG_ICACHE_SIZE); addr += CFG_CACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Invalidate_I), "r"(addr)); ++ } ++ ++ asm volatile ("sync\n\t" ++ "lw $0,0(%0)" ++ ::"r" (0xa0000000)); ++ /* 2nd cache */ ++ for (addr = K0BASE; addr < (K0BASE + CFG_SDCACHE_SIZE); addr += CFG_SDCACHELINE_SIZE) { ++ asm volatile (".set mips32\n\t" ++ " cache %0, 0(%1)\n\t" ++ ".set mips32\n\t" ++ : ++ : "I" (Index_Writeback_Inv_SD), "r"(addr)); ++ } ++ ++ asm volatile ("sync\n\t" ++ "lw $0,0(%0)" ++ ::"r" (0xa0000000)); ++} ++ ++#endif /* __CHIP_CACHE_H__ */ +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/cpm.h b/arch/mips/xburst2/soc-x2500/include/soc/cpm.h +new file mode 100644 +index 000000000..21e2a56fd +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/cpm.h +@@ -0,0 +1,143 @@ ++/* ++ * JZSOC CPM register definition. ++ * ++ * CPM (Clock reset and Power control Management) ++ * ++ * Copyright (C) 2019 Ingenic Semiconductor Co., Ltd. ++ */ ++ ++#ifndef __CPM_H__ ++#define __CPM_H__ ++#include ++ ++#define CPM_CPCCR (0x00) ++#define CPM_CPPCR (0x0c) ++#define CPM_CPAPCR (0x10) ++#define CPM_CPMPCR (0x14) ++#define CPM_CPAPACR (0x18) ++#define CPM_CPMPACR (0x1c) ++#define CPM_DDRCDR (0x2c) ++#define CPM_EL150CDR (0x30) ++#define CPM_CPPSR (0x34) ++#define CPM_CPSPPR (0x38) ++#define CPM_USBPCR (0x3c) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++#define CPM_RSACDR (0x4c) ++#define CPM_MACCDR (0x54) ++#define CPM_CPEPCR (0x58) ++#define CPM_CPEPACR (0x5c) ++#define CPM_SFCCDR (0x60) ++#define CPM_LPCDR (0x64) ++#define CPM_MSC0CDR (0x68) ++#define CPM_MSC1CDR (0x6c) ++#define CPM_I2STCDR (0x70) ++#define CPM_I2STCDR1 (0x78) ++#define CPM_SSICDR (0x74) ++#define CPM_ISPCDR (0x80) ++#define CPM_I2SRCDR (0x84) ++#define CPM_I2SRCDR1 (0x88) ++#define CPM_BSCALERCDR (0xa0) ++#define CPM_EXCLKDS (0x8c) ++#define CPM_CIM0CDR (0x90) ++#define CPM_CIM1CDR (0x94) ++#define CPM_CIM2CDR (0x98) ++#define CPM_SOFTAPP (0x9c) ++#define CPM_BSCALERCDR (0xa0) ++#define CPM_RADIXCDR (0xa4) ++#define CPM_INTR (0xb0) ++#define CPM_INTRE (0xb4) ++#define CPM_BT0CDR (0xb8) ++#define CPM_DRCG (0xd0) ++#define CPM_CPCSR (0xd4) ++#define CPM_CPVPCR (0xe0) ++#define CPM_CPVPACR (0xe4) ++#define CPM_MACPHY (0xe8) ++ ++ ++#define CPM_LCR (0x04) ++#define CPM_CLKGR (0x20)/* def changed*/ ++#define CPM_OPCR (0x24) ++#define CPM_CLKGR1 (0x28)/* def changed*/ ++#define CPM_SRBC (0xc4) ++#define SRBC_USB_SR BIT (12) ++#define CPM_MESTSEL (0xec) ++ ++#define CPM_MEMCTRL_MA0 (0xf0) ++#define CPM_MEMCTRL_MA1 (0xf4) ++#define CPM_MEMCTRL_MA2 (0xf8) ++ ++#define CPM_RSR (0x08) ++ ++#ifndef BIT ++#define BIT(nr) (1UL << nr) ++#endif ++ ++/*USB Parameter Control Register*/ ++#define USBPCR_USB_MODE BIT(31) ++#define USBPCR_AVLD_REG BIT(30) ++#define USBPCR_IDPULLUP_MASK_BIT 28 ++#define USBPCR_IDPULLUP_MASK (0x3 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS_SUSPEND (0x1 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_MASK_BIT) ++#define USBPCR_INCR_MASK BIT(27) ++#define USBPCR_POR_BIT 22 ++#define USBPCR_POR BIT(USBPCR_POR_BIT) ++ ++/*USB Reset Detect Timer Register*/ ++#define USBRDT_RESUME_INTEEN BIT(31) /*RW*/ ++#define USBRDT_RESUME_INTERCLR BIT(30) /*W0*/ ++#define USBRDT_RESUME_SPEED_BIT 28 /*RW*/ ++#define USBRDT_RESUME_SPEED_MSK (0x3 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_HIGH (0x0 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_FULL (0x1 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_SPEED_LOW (0x2 << USBRDT_RESUME_SPEED_BIT) ++#define USBRDT_RESUME_STATUS BIT(27) /*RO*/ ++#define USBRDT_HB_MASK BIT(26) ++#define USBRDT_VBFIL_LD_EN BIT(25) ++#define USBRDT_IDDIG_EN BIT(1) ++#define USBRDT_IDDIG_REG BIT(0) ++#define USBRDT_USBRDT_MSK (0x7fffff) ++#define USBRDT_USBRDT(x) ((x) & USBRDT_USBRDT_MSK) ++#define USBRDT_UTMI_RST BIT(27) ++ ++/*USB VBUS Jitter Filter Register*/ ++#define USBVBFIL_USBVBFIL(x) ((x) & 0xffff) ++#define USBVBFIL_IDDIGFIL(x) ((x) & (0xffff << 16)) ++ ++/*USB Parameter Control Register1*/ ++#define USBPCR1_BVLD_REG BIT(31) ++#define USBPCR1_DPPULLDOWN BIT(29) ++#define USBPCR1_DMPULLDOWN BIT(28) ++#define USBPCR1_PORT_RST BIT(21) ++ ++/*Oscillator and Power Control Register*/ ++#define OPCR_USB_SPENDN BIT(7) ++#define OPCR_USB_PHY_GATE BIT(23) ++ ++#define LCR_LPM_MASK (0x3) ++#define LCR_LPM_SLEEP (0x1) ++ ++#define CPM_LCR_PD_X2D (0x1<<31) ++#define CPM_LCR_PD_VPU (0x1<<30) ++#define CPM_LCR_PD_MASK (0x3<<30) ++#define CPM_LCR_X2DS (0x1<<27) ++#define CPM_LCR_VPUS (0x1<<26) ++#define CPM_LCR_STATUS_MASK (0x3<<26) ++ ++#define OPCR_ERCS (0x1<<2) ++#define OPCR_PD (0x1<<3) //T31 delete ++#define OPCR_IDLE (0x1<<31) ++ ++#define CLKGR1_VPU (0x1<<0) ++ ++#define cpm_inl(off) inl(CPM_IOBASE + (off)) ++#define cpm_outl(val,off) outl(val,CPM_IOBASE + (off)) ++#define cpm_clear_bit(val,off) do{cpm_outl((cpm_inl(off) & ~(1 << (val))),off);}while(0) ++#define cpm_set_bit(val,off) do{cpm_outl((cpm_inl(off) | (1 << (val))),off);}while(0) ++#define cpm_test_bit(val,off) (cpm_inl(off) & (0x1 << (val))) ++ ++#endif ++/* __CPM_H__ */ +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/ddr.h b/arch/mips/xburst2/soc-x2500/include/soc/ddr.h +new file mode 100644 +index 000000000..4f80e31b6 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/ddr.h +@@ -0,0 +1,293 @@ ++/* ++ * JZ4780 ddr definitions ++ * ++ * Copyright (c) 2013 Ingenic Semiconductor Co.,Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ */ ++ ++#ifndef __DDR_H__ ++#define __DDR_H__ ++ ++#include ++ ++/* ++ * DDR Controller Registers ++ **/ ++#define DDR_MEM_PHY_BASE 0x20000000 ++ ++#define DDRC_AHB2_OFFSET 0xb34f0000 ++#define DDRC_APB_OFFSET 0xb3012000 ++#define DDR_PHY_OFFSET (-0x4e0000 + 0x1000) ++ ++#define DDRC_STATUS 0x0 ++#define DDRC_CFG 0x8 ++#define DDRC_CTRL 0x10 ++#define DDRC_LMR 0x18 ++#define DDRC_DLP 0x20 ++#define DDRC_AUTOSR_EN 0x28 ++#define DDRC_AUTOSR_CNT 0x30 ++#define DDRC_REFCNT 0x38 ++#define DDRC_DBGINFO 0xE8 ++#define DDRC_TIMING(n) (0x40 + 8 * (n - 1)) ++#define DDRC_MMAP0 0x78 ++#define DDRC_MMAP1 0x80 ++#define DDRC_HREGPRO 0xd8 ++#define DDRC_DWCFG (DDRC_APB_OFFSET + 0x00) ++#define DDRC_DWSTATUS (DDRC_APB_OFFSET + 0x04) ++#define DDRC_REMAP(n) (DDRC_APB_OFFSET + 0x08 + 4 * (n - 1)) ++#define DDRC_CGUC0 (DDRC_APB_OFFSET + 0x64) ++#define DDRC_CGUC1 (DDRC_APB_OFFSET + 0x68) ++#define DDRC_PREGPRO (DDRC_APB_OFFSET + 0x6c) ++ ++/* ++ * DDR Innophy registers ++ * */ ++#define DDRP_INNOPHY_PHY_RST (DDR_PHY_OFFSET + 0x000) ++#define DDRP_INNOPHY_MEM_CFG (DDR_PHY_OFFSET + 0x004) ++#define DDRP_INNOPHY_DQ_WIDTH (DDR_PHY_OFFSET + 0x07c) ++#define DDRP_INNOPHY_CL (DDR_PHY_OFFSET + 0x014) ++#define DDRP_INNOPHY_CWL (DDR_PHY_OFFSET + 0x01c) ++#define DDRP_INNOPHY_AL (DDR_PHY_OFFSET + 0x018) ++#define DDRP_INNOPHY_PLL_FBDIV (DDR_PHY_OFFSET + 0x080) ++#define DDRP_INNOPHY_PLL_CTRL (DDR_PHY_OFFSET + 0x084) ++#define DDRP_INNOPHY_PLL_PDIV (DDR_PHY_OFFSET + 0x088) ++#define DDRP_INNOPHY_PLL_LOCK (DDR_PHY_OFFSET + 0xc8) ++#define DDRP_INNOPHY_TRAINING_CTRL (DDR_PHY_OFFSET + 0x008) ++#define DDRP_INNOPHY_CALIB_DONE (DDR_PHY_OFFSET + 0x10c) ++#define DDRP_INNOPHY_CALIB_DELAY_AL (DDR_PHY_OFFSET + 0x190) ++#define DDRP_INNOPHY_CALIB_DELAY_AH (DDR_PHY_OFFSET + 0x194) ++#define DDRP_INNOPHY_CALIB_BYPASS_AL (DDR_PHY_OFFSET + 0x118) ++#define DDRP_INNOPHY_CALIB_BYPASS_AH (DDR_PHY_OFFSET + 0x158) ++#define DDRP_INNOPHY_WL_MODE1 (DDR_PHY_OFFSET + 0x00c) ++#define DDRP_INNOPHY_WL_MODE2 (DDR_PHY_OFFSET + 0x010) ++#define DDRP_INNOPHY_WL_DONE (DDR_PHY_OFFSET + 0x100) ++#define DDRP_INNOPHY_INIT_COMP (DDR_PHY_OFFSET + 0x0d0) ++ ++ ++/* ++ * DDRC REGISTER BITS DEFINE ++ * */ ++ ++/* DDRC Status Register */ ++#define DDRC_DSTATUS_MISS (1 << 6) ++#define DDRC_ST_DPDN (1 << 5) /* 0 DDR memory is NOT in deep-power-down state ++ 1 DDR memory is in deep-power-down state */ ++#define DDRC_ST_PDN (1 << 4) /* 0 DDR memory is NOT in power-down state ++ 1 DDR memory is in power-down state */ ++#define DDRC_ST_AREF (1 << 3) /* 0 DDR memory is NOT in auto-refresh state ++ 1 DDR memory is in auto-refresh state */ ++#define DDRC_ST_SREF (1 << 2) /* 0 DDR memory is NOT in self-refresh state ++ 1 DDR memory is in self-refresh state */ ++#define DDRC_ST_CKE1 (1 << 1) /* 0 CKE1 Pin is low ++ 1 CKE1 Pin is high */ ++#define DDRC_ST_CKE0 (1 << 0) /* 0 CKE0 Pin is low ++ 1 CKE0 Pin is high */ ++ ++/* DDRC Configure Register */ ++#define DDRC_CFG_ROW1_BIT 29 /* Row Address width. */ ++#define DDRC_CFG_ROW1_MASK (0x7 << DDRC_CFG_ROW1_BIT) ++#define DDRC_CFG_COL1_BIT 26 /* Row Address width. */ ++#define DDRC_CFG_COL1_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA1 25 /* Bank Address width of DDR memory */ ++#define DDRC_CFG_IMBA (1 << 16) ++#define DDRC_CFG_ROW0_BIT 13 /* Row Address width. */ ++#define DDRC_CFG_ROW0_MASK (0x7 << DDRC_CFG_ROW0_BIT) ++#define DDRC_CFG_COL0_BIT 10 /* Row Address width. */ ++#define DDRC_CFG_COL0_MASK (0x7 << DDRC_CFG_COL1_BIT) ++#define DDRC_CFG_BA0 9 /* Bank Address width of DDR memory */ ++ ++#define DDRC_CFG_TYPE_BIT 3 ++#define DDRC_CFG_TYPE_MASK (0x7 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR1 (2 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_MDDR (3 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR2 (4 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR2 (5 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_DDR3 (6 << DDRC_CFG_TYPE_BIT) ++#define DDRC_CFG_TYPE_LPDDR3 (7 << DDRC_CFG_TYPE_BIT) ++ ++#define DDRC_CFG_ODTEN (1 << 2) /* ODT EN */ ++#define DDRC_CFG_CS1EN (1 << 1) /* DDR Chip-Select-1 Enable */ ++#define DDRC_CFG_CS0EN (1 << 0) /* DDR Chip-Select-0 Enable */ ++ ++/* DDRC Control Register */ ++#define DDRC_CTRL_DFI_RST (1 << 23) ++#define DDRC_CTRL_DLL_RST (1 << 22) ++#define DDRC_CTRL_CTL_RST (1 << 21) ++#define DDRC_CTRL_CFG_RST (1 << 20) ++#define DDRC_CTRL_ACTPD (1 << 15) /* 0 Precharge all banks before entering power-down ++ 1 Do not precharge banks before entering power-down */ ++#define DDRC_CTRL_PDT_BIT 12 /* Power-Down Timer */ ++#define DDRC_CTRL_PDT_MASK (0x7 << DDRC_CTRL_PDT_BIT) ++#define DDRC_CTRL_PDT_DIS (0 << DDRC_CTRL_PDT_BIT) /* power-down disabled */ ++#define DDRC_CTRL_PDT_8 (1 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 8 tCK idle */ ++#define DDRC_CTRL_PDT_16 (2 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 16 tCK idle */ ++#define DDRC_CTRL_PDT_32 (3 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 32 tCK idle */ ++#define DDRC_CTRL_PDT_64 (4 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 64 tCK idle */ ++#define DDRC_CTRL_PDT_128 (5 << DDRC_CTRL_PDT_BIT) /* Enter power-down after 128 tCK idle */ ++ ++#define DDRC_CTRL_PD_CCE (1 << 7) /* Power down clk freq change enable */ ++#define DDRC_CTRL_DPD (1 << 6) /* 1 Drive external MDDR device entering Deep-Power-Down mode */ ++#define DDRC_CTRL_SR (1 << 5) /* 1 Drive external DDR device entering self-refresh mode ++ 0 Drive external DDR device exiting self-refresh mode */ ++#define DDRC_CTRL_SR_CCE (1 << 4) /* Self refresh clk stop request enable */ ++#define DDRC_CTRL_CKE (1 << 1) /* 0 Not set CKE Pin High, 1 Set CKE Pin HIGH */ ++#define DDRC_CTRL_RESET (1 << 0) /* 0 End resetting ddrc_controller, 1 Resetting ddrc_controller */ ++ ++/* DDRC DFI low power handshake control register */ ++#define DDRC_DDLP_TCTLUDP_BIT 24 ++#define DDRC_DDLP_TCTLUDP_FF (0xff << DDRC_DDLP_TCTLUDP_BIT) ++ ++/* DDRC Load-Mode-Register */ ++#define DDRC_LMR_DDR_ADDR_BIT 12 /* When performing a DDR command, DDRC_ADDR[13:0] ++ corresponding to external DDR address Pin A[13:0] */ ++#define DDRC_LMR_DDR_ADDR_MASK (0xfffff << DDRC_LMR_DDR_ADDR_BIT) ++ ++#define DDRC_LMR_MA_BIT 16 /* FOR LPDDR2, MA[9:0] */ ++#define DDRC_LMR_OP_BIT 24 /* FOR LPDDR2, OP[9:0] */ ++ ++#define DDRC_LMR_BA_BIT 9 /* When performing a DDR command, BA[2:0] ++ corresponding to external DDR address Pin BA[2:0]. */ ++#define DDRC_LMR_BA_MASK (0x7 << DDRC_LMR_BA_BIT) ++#define DDRC_LMR_CMD_BIT 6 ++#define DDRC_LMR_CMD_MASK (0x7 << DDRC_LMR_CMD_BIT) ++#define DDRC_LMR_CMD_PREC (0 << DDRC_LMR_CMD_BIT)/* Precharge one bank/All banks */ ++#define DDRC_LMR_CMD_AUREF (1 << DDRC_LMR_CMD_BIT)/* Auto-Refresh */ ++#define DDRC_LMR_CMD_LMR (2 << DDRC_LMR_CMD_BIT)/* Load Mode Register */ ++#define DDRC_LMR_CMD_ZQCL_CS0 (3 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCL_CS1 (4 << DDRC_LMR_CMD_BIT)/* ZQCL for DDR3 on CS1 */ ++#define DDRC_LMR_CMD_ZQCS_CS0 (5 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS0 */ ++#define DDRC_LMR_CMD_ZQCS_CS1 (6 << DDRC_LMR_CMD_BIT)/* ZQCS for DDR3 on CS1 */ ++ ++#define DDRC_LMR_TMRD_BIT 1 ++#define DDRC_LMR_TMRD_MASK (0x1f << DDRC_LMR_TMRD_BIT) ++#define DDRC_LMR_START (1 << 0) /* 0 No command is performed ++ 1 On the posedge of START, perform a command ++ defined by CMD field */ ++ ++/* DDRC Auto-Refresh Counter */ ++#define DDRC_REFCNT_REF_EN (1 << 0) /* Enable Refresh Counter */ ++#define DDRC_REFCNT_CLK_DIV_BIT 1 /* Clock Divider for auto-refresh counter. */ ++#define DDRC_REFCNT_CLK_DIV_MASK (0x7 << DDRC_REFCNT_CLKDIV_BIT) ++ ++#define DDRC_REFCNT_PREREF_CNT_BIT 4 ++#define DDRC_REFCNT_PREREF_CNT_MASK (0xf << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT(val) (val << DDRC_REFCNT_PREREF_CNT_BIT) ++#define DDRC_REFCNT_PREREF_CNT_DEFAULT DDRC_REFCNT_PREREF_CNT(8) ++ ++#define DDRC_REFCNT_CNT_BIT 8 /* 8-bit counter */ ++#define DDRC_REFCNT_CNT_MASK (0xff << DDRC_REFCNT_CNT_BIT) ++ ++#define DDRC_REFCNT_CON_BIT 16 /* Constant value used to compare with CNT value. */ ++#define DDRC_REFCNT_CON_MASK (0xff << DDRC_REFCNT_CON_BIT) ++ ++#define DDRC_REFCNT_TRFC_BIT 24 ++#define DDRC_REFCNT_TRFC_MASK (0x3f << DDRC_REFCNT_TRFC_BIT) ++ ++#define DDRC_REFCNT_PREREF_EN_BIT 30 ++#define DDRC_REFCNT_PREREF_EN (1 << DDRC_REFCNT_PREREF_EN_BIT) ++ ++#define DDRC_REFCNT_PBREF_EN_BIT 31 ++#define DDRC_REFCNT_PBREF_EN (1 << DDRC_REFCNT_PBREF_EN_BIT) ++ ++/* DDRC Memory Map Config Register */ ++#define DDRC_MMAP_BASE_BIT 8 /* base address */ ++#define DDRC_MMAP_BASE_MASK (0xff << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP_MASK_BIT 0 /* address mask */ ++#define DDRC_MMAP_MASK_MASK (0xff << DDRC_MMAP_MASK_BIT) ++ ++#define DDRC_MMAP0_BASE (0x20 << DDRC_MMAP_BASE_BIT) ++#define DDRC_MMAP1_BASE_64M (0x24 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_128M (0x28 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++#define DDRC_MMAP1_BASE_256M (0x30 << DDRC_MMAP_BASE_BIT) /*when bank0 is 128M*/ ++ ++#define DDRC_MMAP_MASK_64_64 (0xfc << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_128_128 (0xf8 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++#define DDRC_MMAP_MASK_256_256 (0xf0 << DDRC_MMAP_MASK_BIT) /*mask for two 128M SDRAM*/ ++ ++/* DDR device data width configure register */ ++#define DDRC_DWCFG_DFI_INIT_START (1 << 3) ++ ++/* DDR device status register */ ++#define DDRC_DWSTATUS_DFI_INIT_COMP (1 << 0) ++ ++/* DDRC AHB Bus Register Protection Register */ ++#define DDRC_HREGPRO_HPRO_EN (1 << 0) ++ ++/* DDRC APB Bus Register Protection Register */ ++#define DDRC_PREGPRO_PPRO_EN (1 << 0) ++ ++ ++/* DDRC clock gate unit configure 0 */ ++#define DDRC_CGU_PORT7 (1 << 28) ++#define DDRC_CGU_PORT6 (1 << 24) ++#define DDRC_CGU_PORT5 (1 << 20) ++#define DDRC_CGU_PORT4 (1 << 16) ++#define DDRC_CGU_PORT3 (1 << 12) ++#define DDRC_CGU_PORT2 (1 << 8) ++#define DDRC_CGU_PORT1 (1 << 4) ++#define DDRC_CGU_PORT0 (1 << 0) ++ ++/* DDRC clock gate unit configure 1 */ ++#define DDRC_CGU_BWM (1 << 8) ++#define DDRC_CGU_PCTRL (1 << 4) ++#define DDRC_CGU_SCH (1 << 1) ++#define DDRC_CGU_PA (1 << 0) ++ ++ ++ ++/* ++ * DDR INNOPHY REGISTER BITS DEFINE ++ * */ ++ ++/* DDRP DQ Width Register */ ++#define DDRP_DQ_WIDTH_DQ_H (1 << 1) ++#define DDRP_DQ_WIDTH_DQ_L (1 << 0) ++ ++/* DDRP Pll Ctrl Register */ ++#define DDRP_PLL_CTRL_PLLPDEN (1 << 1) ++ ++/* DDRP Training Ctrl Register */ ++#define DDRP_TRAINING_CTRL_WL_BP (1 << 3) ++#define DDRP_TRAINING_CTRL_WL_START (1 << 2) ++#define DDRP_TRAINING_CTRL_DSCSE_BP (1 << 1) ++#define DDRP_TRAINING_CTRL_DSACE_START (1 << 0) ++ ++/* DDRP Training Done Register */ ++#define DDRP_CALIB_DONE_HDQCFB (1 << 3) ++#define DDRP_CALIB_DONE_LDQCFB (1 << 2) ++#define DDRP_CALIB_DONE_HDQCFA (1 << 1) ++#define DDRP_CALIB_DONE_LDQCFA (1 << 0) ++#define DDRP_CALIB_DONE_HWRLFB (1 << 3) ++#define DDRP_CALIB_DONE_LWRLFB (1 << 2) ++#define DDRP_CALIB_DONE_HWRLFA (1 << 1) ++#define DDRP_CALIB_DONE_LWRLFA (1 << 0) ++ ++/* DDRP CALIB BP Register */ ++#define DDRP_CALIB_BP_CYCLESELBH_BIT 4 ++#define DDRP_CALIB_BP_OPHCSELBH_BIT 3 ++#define DDRP_CALIB_BP_DLLSELBH_BIT 0 ++ ++/* DDRP Init Complete Register */ ++#define DDRP_INIT_COMP (1 << 0) ++ ++#define DDRP_PLL_LOCK (1 << 3) ++ ++#define REG32(addr) *(volatile unsigned int *)(addr) ++ ++#define ddr_writel(value, reg) (REG32(DDRC_BASE + reg) = (value)) ++#define ddr_readl(reg) REG32(DDRC_BASE + reg) ++#endif /* __DDR_H__ */ +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/extal.h b/arch/mips/xburst2/soc-x2500/include/soc/extal.h +new file mode 100644 +index 000000000..78541e723 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/extal.h +@@ -0,0 +1,8 @@ ++ ++#ifndef __JZSOC_EXTAL_H__ ++#define __JZSOC_EXTAL_H__ ++ ++#define JZ_EXTAL_RTC 32768 /* RTC extal freq: 32.768 KHz */ ++#define JZ_EXTAL (CONFIG_EXTAL_CLOCK * 1000000) ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/gpio.h b/arch/mips/xburst2/soc-x2500/include/soc/gpio.h +new file mode 100644 +index 000000000..66c53e6e8 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/gpio.h +@@ -0,0 +1,40 @@ ++#ifndef _SOC_GPIO_H_ ++#define _SOC_GPIO_H_ ++ ++enum gpio_function { ++ GPIO_FUNC_0 = 0x10, //0000, GPIO as function 0 / device 0 ++ GPIO_FUNC_1 = 0x11, //0001, GPIO as function 1 / device 1 ++ GPIO_FUNC_2 = 0x12, //0010, GPIO as function 2 / device 2 ++ GPIO_FUNC_3 = 0x13, //0011, GPIO as function 3 / device 3 ++ GPIO_OUTPUT0 = 0x14, //0100, GPIO output low level ++ GPIO_OUTPUT1 = 0x15, //0101, GPIO output high level ++ GPIO_INPUT = 0x16, //0110, GPIO as input.7 also. ++ GPIO_INT_LO = 0x18, //1000, Low Level trigger interrupt ++ GPIO_INT_HI = 0x19, //1001, High Level trigger interrupt ++ GPIO_INT_FE = 0x1a, //1010, Fall Edge trigger interrupt ++ GPIO_INT_RE = 0x1b, //1011, Rise Edge trigger interrupt ++ GPIO_INT_MASK_LO = 0x1c, //1100, Port is low level triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_HI = 0x1d, //1101, Port is high level triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_FE = 0x1e, //1110, Port is fall edge triggered interrupt input. Interrupt is masked. ++ GPIO_INT_MASK_RE = 0x1f, //1111, Port is rise edge triggered interrupt input. Interrupt is masked. ++ ++ GPIO_PULL_HIZ = 0x80, //no pull ++ GPIO_PULL_UP = 0xa0, //pull high ++ GPIO_PULL_DOWN = 0xc0, //pull low ++}; ++ ++#define GPIO_PA(n) (0 * 32 + (n)) ++#define GPIO_PB(n) (1 * 32 + (n)) ++#define GPIO_PC(n) (2 * 32 + (n)) ++#define GPIO_PD(n) (3 * 32 + (n)) ++ ++enum gpio_port { ++ GPIO_PORT_A, GPIO_PORT_B, ++ GPIO_PORT_C, GPIO_PORT_D, ++ /* this must be last */ ++ GPIO_NR_PORTS, ++}; ++ ++int jzgpio_set_func(int port, enum gpio_function func, unsigned long pins); ++ ++#endif /* _SOC_GPIO_H_ */ +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/mmc.h b/arch/mips/xburst2/soc-x2500/include/soc/mmc.h +new file mode 100644 +index 000000000..6db74c179 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/mmc.h +@@ -0,0 +1,5 @@ ++#ifndef __MMC_H ++#define __MMC_H ++ ++extern int jzmmc_manual_detect(int index, int on); ++#endif +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/pdma.h b/arch/mips/xburst2/soc-x2500/include/soc/pdma.h +new file mode 100644 +index 000000000..2308505d1 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/pdma.h +@@ -0,0 +1,49 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2021 by nick shen ++ */ ++#ifndef __ASM_MACH_INGENIC_PDMA_H__ ++#define __ASM_MACH_INGENIC_PDMA_H__ ++ ++#include ++#define INGENIC_DMA_REQ_AUTO 0xff ++#define INGENIC_DMA_CHAN_CNT 32 ++unsigned int pdma_maps[INGENIC_DMA_CHAN_CNT] = { ++ INGENIC_DMA_REQ_AUTO, ++ INGENIC_DMA_REQ_AUTO, ++ INGENIC_DMA_REQ_AIC_LOOP_RX, ++ INGENIC_DMA_REQ_AIC_TX, ++ INGENIC_DMA_REQ_AIC_F_RX, ++ INGENIC_DMA_REQ_AUTO_TX, ++ INGENIC_DMA_REQ_SADC_RX, ++ INGENIC_DMA_REQ_DMIC_RX, ++ INGENIC_DMA_REQ_UART3_TX, ++ INGENIC_DMA_REQ_UART3_RX, ++ INGENIC_DMA_REQ_UART2_TX, ++ INGENIC_DMA_REQ_UART2_RX, ++ INGENIC_DMA_REQ_UART1_TX, ++ INGENIC_DMA_REQ_UART1_RX, ++ INGENIC_DMA_REQ_UART0_TX, ++ INGENIC_DMA_REQ_UART0_RX, ++ INGENIC_DMA_REQ_SSI0_TX, ++ INGENIC_DMA_REQ_SSI0_RX, ++ INGENIC_DMA_REQ_SSI1_TX, ++ INGENIC_DMA_REQ_SSI1_RX, ++ INGENIC_DMA_REQ_SLV_TX, ++ INGENIC_DMA_REQ_SLV_RX, ++ INGENIC_DMA_REQ_I2C0_TX, ++ INGENIC_DMA_REQ_I2C0_RX, ++ INGENIC_DMA_REQ_I2C1_TX, ++ INGENIC_DMA_REQ_I2C1_RX, ++ INGENIC_DMA_REQ_I2C2_TX, ++ INGENIC_DMA_REQ_I2C2_RX, ++ INGENIC_DMA_REQ_I2C3_TX, ++ INGENIC_DMA_REQ_I2C3_RX, ++ INGENIC_DMA_REQ_DES_TX, ++ INGENIC_DMA_REQ_DES_RX, ++}; ++#endif ++ +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/rtc.h b/arch/mips/xburst2/soc-x2500/include/soc/rtc.h +new file mode 100644 +index 000000000..871add1fc +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/rtc.h +@@ -0,0 +1,96 @@ ++#ifndef __RTC_H__ ++#define __RTC_H__ ++ ++/* ++ * RTC registers offset address definition ++ */ ++#define RTC_RTCCR (0x00) /* rw, 32, 0x00000081 */ ++#define RTC_RTCSR (0x04) /* rw, 32, 0x???????? */ ++#define RTC_RTCSAR (0x08) /* rw, 32, 0x???????? */ ++#define RTC_RTCGR (0x0c) /* rw, 32, 0x0??????? */ ++ ++#define RTC_HCR (0x20) /* rw, 32, 0x00000000 */ ++#define RTC_HWFCR (0x24) /* rw, 32, 0x0000???0 */ ++#define RTC_HRCR (0x28) /* rw, 32, 0x00000??0 */ ++#define RTC_HWCR (0x2c) /* rw, 32, 0x00000008 */ ++#define RTC_HWRSR (0x30) /* rw, 32, 0x00000000 */ ++#define RTC_HSPR (0x34) /* rw, 32, 0x???????? */ ++#define RTC_WENR (0x3c) /* rw, 32, 0x00000000 */ ++#define RTC_WKUPPINCR (0x48) /* rw, 32, 0x00050064*/ ++ ++/* ++ * RTC registers common define ++ */ ++ ++/* RTC control register(RTCCR) */ ++#define RTCCR_WRDY BIT(7) ++#define RTCCR_1HZ BIT(6) ++#define RTCCR_1HZIE BIT(5) ++#define RTCCR_AF BIT(4) ++#define RTCCR_AIE BIT(3) ++#define RTCCR_AE BIT(2) ++#define RTCCR_SELEXC BIT(1) ++#define RTCCR_RTCE BIT(0) ++ ++ ++/* Generate the bit field mask from msb to lsb */ ++#define BITS_H2L(msb, lsb) ((0xFFFFFFFF >> (32-((msb)-(lsb)+1))) << (lsb)) ++ ++/* RTC regulator register(RTCGR) */ ++#define RTCGR_LOCK BIT(31) ++#define RTCGR_ADJC_LSB 16 ++#define RTCGR_ADJC_MASK BITS_H2L(25, RTCGR_ADJC_LSB) ++#define RTCGR_NC1HZ_LSB 0 ++#define RTCGR_NC1HZ_MASK BITS_H2L(15, RTCGR_NC1HZ_LSB) ++ ++/* Hibernate control register(HCR) */ ++#define HCR_PD BIT(0) ++ ++/* Hibernate wakeup filter counter register(HWFCR) */ ++#define HWFCR_LSB 5 ++#define HWFCR_MASK BITS_H2L(15, HWFCR_LSB) ++#define HWFCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000+0xf) > HWFCR_MASK ? HWFCR_MASK : ((ms)*(clk)/1000+0xf) & HWFCR_MASK) ++ ++/* Hibernate reset counter register(HRCR) */ ++#define HRCR_LSB 11 ++#define HRCR_MASK BITS_H2L(14, HRCR_LSB) ++#define HRCR_WAIT_TIME(ms, clk) (((ms)*(clk)/1000 + 0x3ff - 0x800) > HRCR_MASK ? HRCR_MASK : \ ++ ((ms)*(clk)/1000 + 0x3ff - 0x800) & HRCR_MASK) ++ ++ ++/* Hibernate wakeup control register(HWCR) */ ++/* Power detect default value; this value means enable */ ++#define EPDET_LSB 3 ++#define EPDET_DEFAULT (0x5aa5a5a << EPDET_LSB) ++#define EPDET_ENABLE (0x5aa5a5a << EPDET_LSB) ++#define EPDET_DISABLE (0x1a55a5a5 << EPDET_LSB) ++#define HWCR_EALM BIT(0) ++ ++ ++/* Hibernate wakeup status register(HWRSR) */ ++#define HWRSR_APD BIT(8) ++#define HWRSR_HR BIT(5) ++#define HWRSR_PPR BIT(4) ++#define HWRSR_PIN BIT(1) ++#define HWRSR_ALM BIT(0) ++ ++/* write enable pattern register(WENR) */ ++#define WENR_WEN BIT(31) ++#define WENR_WENPAT_LSB 0 ++#define WENR_WENPAT_MASK BITS_H2L(15, WENR_WENPAT_LSB) ++#define WENR_WENPAT_WRITABLE (0xa55a) ++ ++/* Hibernate scratch pattern register(HSPR) */ ++#define HSPR_RTCV 0x52544356 /* The value is 'RTCV', means rtc is valid */ ++ ++/*WKUP_PIN_RST control register (WKUPPINCR)*/ ++#define WKUPPINCR_BIAS_CTRL (0x1 << 16) /* fix value*/ ++#define WKUPPINCR_OSC_EN BIT(18) ++#define WKUPPINCR_P_JUD_LEN_LSB 4 ++#define WKUPPINCR_P_JUD_LEN_MASK BITS_H2L(7, WKUPPINCR_P_JUD_LEN_LSB) ++#define WKUPPINCR_P_JUD_LEN(s) ((s) << WKUPPINCR_P_JUD_LEN_LSB) > WKUPPINCR_P_JUD_LEN_MASK ? \ ++ WKUPPINCR_P_JUD_LEN_MASK : (s) << WKUPPINCR_P_JUD_LEN_LSB ++#define WKUPPINCR_P_JUD_EN (0x4) ++/* The divider is decided by the RTC clock frequency. */ ++#define RTC_FREQ_DIVIDER (32768 - 1) ++#endif /* __RTC_H__ */ +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/sfc.h b/arch/mips/xburst2/soc-x2500/include/soc/sfc.h +new file mode 100644 +index 000000000..b1684bec9 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/sfc.h +@@ -0,0 +1,211 @@ ++#ifndef __SFC_REGISTER_H ++#define __SFC_REGISTER_H ++ ++/* SFC register */ ++ ++#define SFC_GLB0 (0x0000) ++#define SFC_DEV_CONF (0x0004) ++#define SFC_DEV_STA_EXP (0x0008) ++#define SFC_DEV0_STA_RT (0x000c) ++#define SFC_DEV_STA_MSK (0x0010) ++#define SFC_TRAN_CONF0(n) (0x0014 + (n * 4)) ++#define SFC_TRAN_LEN (0x002c) ++#define SFC_DEV_ADDR(n) (0x0030 + (n * 4)) ++#define SFC_DEV_ADDR_PLUS(n) (0x0048 + (n * 4)) ++#define SFC_MEM_ADDR (0x0060) ++#define SFC_TRIG (0x0064) ++#define SFC_SR (0x0068) ++#define SFC_SCR (0x006c) ++#define SFC_INTC (0x0070) ++#define SFC_FSM (0x0074) ++#define SFC_CGE (0x0078) ++#define SFC_CMD_IDX (0x007c) ++#define SFC_COL_ADDR (0x0080) ++#define SFC_ROW_ADDR (0x0084) ++#define SFC_STA_ADDR0 (0x0088) ++#define SFC_STA_ADDR1 (0x008c) ++#define SFC_DES_ADDR (0x0090) ++#define SFC_GLB1 (0x0094) ++#define SFC_DEV1_STA_RT (0x0098) ++#define SFC_TRAN_CONF1(n) (0x009c + (n * 4)) ++#define SFC_CDT (0x0800) //0x800 ~ 0xbff ++#define SFC_RM_DR (0x1000) ++ ++/* For SFC_GLB0 */ ++#define GLB0_POLL_TIME_OFFSET (16) ++#define GLB0_POLL_TIME_MSK (0xffff << GLB0_POLL_TIME_OFFSET) ++#define GLB0_DES_EN (1 << 15) ++#define GLB0_CDT_EN (1 << 14) ++#define GLB0_TRAN_DIR (1 << 13) ++#define GLB0_TRAN_DIR_WRITE (1) ++#define GLB0_TRAN_DIR_READ (0) ++#define GLB0_THRESHOLD_OFFSET (7) ++#define GLB0_THRESHOLD_MSK (0x3f << GLB0_THRESHOLD_OFFSET) ++#define GLB0_OP_MODE (1 << 6) ++#define GLB0_OP_OFFSET (6) ++#define SLAVE_MODE (0x0) ++#define DMA_MODE (0x1) ++#define GLB0_PHASE_NUM_OFFSET (3) ++#define GLB0_PHASE_NUM_MSK (0x7 << GLB0_PHASE_NUM_OFFSET) ++#define GLB0_WP_EN (1 << 2) ++#define GLB0_BURST_MD_OFFSET (0) ++#define GLB0_BURST_MD_MSK (0x3 << GLB0_BURST_MD_OFFSET) ++ ++/* For SFC_DEV_CONF */ ++#define DEV_CONF_STA_ENDIAN_OFFSET (31) ++#define STA_ENDIAN_LSB (0) ++#define STA_ENDIAN_MSB (1) ++#define DEV_CONF_SMP_DELAY_OFFSET (16) ++#define DEV_CONF_SMP_DELAY_MSK (0x1f << DEV_CONF_SMP_DELAY_OFFSET) ++#define DEV_CONF_SMP_DELAY_0 (0) ++#define DEV_CONF_SMP_DELAY_45 (1) ++#define DEV_CONF_SMP_DELAY_90 (2) ++#define DEV_CONF_SMP_DELAY_135 (3) ++#define DEV_CONF_SMP_DELAY_180 (4) ++#define DEV_CONF_SMP_DELAY_225 (5) ++#define DEV_CONF_SMP_DELAY_270 (6) ++#define DEV_CONF_SMP_DELAY_315 (7) ++#define DEV_CONF_SMP_DELAY_1 (8) ++#define DEV_CONF_SMP_DELAY_2 (16) ++#define DEV_CONF_CMD_TYPE (0x1 << 15) ++#define DEV_CONF_STA_TYPE_OFFSET (13) ++#define DEV_CONF_STA_TYPE_MSK (0x3 << DEV_CONF_STA_TYPE_OFFSET) ++#define DEV_CONF_THOLD_OFFSET (11) ++#define DEV_CONF_THOLD_MSK (0x3 << DEV_CONF_THOLD_OFFSET) ++#define DEV_CONF_TSETUP_OFFSET (9) ++#define DEV_CONF_TSETUP_MSK (0x3 << DEV_CONF_TSETUP_OFFSET) ++#define DEV_CONF_TSH_OFFSET (5) ++#define DEV_CONF_TSH_MSK (0xf << DEV_CONF_TSH_OFFSET) ++#define DEV_CONF_CPHA (0x1 << 4) ++#define DEV_CONF_CPOL (0x1 << 3) ++#define DEV_CONF_CEDL (0x1 << 2) ++#define DEV_CONF_HOLDDL (0x1 << 1) ++#define DEV_CONF_WPDL (0x1 << 0) ++ ++/* For SFC_TRAN_CONF0 */ ++#define TRAN_CONF0_CLK_MODE (29) ++#define TRAN_CONF0_CLK_MODE_MSK (0x7 << TRAN_CONF0_CLK_MODE) ++#define TRAN_CONF0_CLK_MODE_SSS (0) ++#define TRAN_CONF0_CLK_MODE_SSD (1) ++#define TRAN_CONF0_CLK_MODE_SDS (2) ++#define TRAN_CONF0_CLK_MODE_SDD (3) ++#define TRAN_CONF0_CLK_MODE_DSS (4) ++#define TRAN_CONF0_CLK_MODE_DSD (5) ++#define TRAN_CONF0_CLK_MODE_DDS (6) ++#define TRAN_CONF0_CLK_MODE_DDD (7) ++#define TRAN_CONF0_ADDR_WIDTH_OFFSET (26) ++#define TRAN_CONF0_ADDR_WIDTH_MSK (0x7 << TRAN_CONF0_ADDR_WIDTH_OFFSET) ++#define TRAN_CONF0_POLLEN (1 << 25) ++#define TRAN_CONF0_POLL_OFFSET (25) ++#define TRAN_CONF0_CMDEN (1 << 24) ++#define TRAN_CONF0_FMAT (1 << 23) ++#define TRAN_CONF0_FMAT_OFFSET (23) ++#define TRAN_CONF0_DMYBITS_OFFSET (17) ++#define TRAN_CONF0_DMYBITS_MSK (0x3f << TRAN_CONF0_DMYBITS_OFFSET) ++#define TRAN_CONF0_DATEEN (1 << 16) ++#define TRAN_CONF0_DATEEN_OFFSET (16) ++#define TRAN_CONF0_CMD_OFFSET (0) ++#define TRAN_CONF0_CMD_MSK (0xffff << TRAN_CONF0_CMD_OFFSET) ++ ++/* For SFC_TRAN_CONF1 */ ++#define TRAN_CONF1_DATA_ENDIAN (1 << 18) ++#define TRAN_CONF1_DATA_ENDIAN_OFFSET (18) ++#define TRAN_CONF1_DATA_ENDIAN_LSB (0) ++#define TRAN_CONF1_DATA_ENDIAN_MSB (1) ++#define TRAN_CONF1_WORD_UNIT_OFFSET (16) ++#define TRAN_CONF1_WORD_UNIT_MSK (3 << 16) ++#define TRAN_CONF1_TRAN_MODE_OFFSET (4) ++#define TRAN_CONF1_TRAN_MODE_MSK (0xf << TRAN_CONF1_TRAN_MODE_OFFSET) ++#define TRAN_CONF1_SPI_STANDARD (0x0) ++#define TRAN_CONF1_SPI_DUAL (0x1) ++#define TRAN_CONF1_SPI_QUAD (0x5) ++#define TRAN_CONF1_SPI_IO_QUAD (0x6) ++#define TRAN_CONF1_SPI_OCTAL (0x9) ++#define TRAN_CONF1_SPI_IO_OCTAL (0xa) ++#define TRAN_CONF1_SPI_FULL_OCTAL (0xb) ++ ++ ++/* For SFC_TRIG */ ++#define TRIG_FLUSH (1 << 2) ++#define TRIG_STOP (1 << 1) ++#define TRIG_START (1 << 0) ++ ++/* For SFC_SR */ ++#define SFC_WORKING (1 << 7) ++#define SFC_BUSY (0x3 << 5) ++#define SFC_END (1 << 4) ++#define SFC_TREQ (1 << 3) ++#define SFC_RREQ (1 << 2) ++#define SFC_OVER (1 << 1) ++#define SFC_UNDER (1 << 0) ++ ++/* For SFC_SCR */ ++#define CLR_END (1 << 4) ++#define CLR_TREQ (1 << 3) ++#define CLR_RREQ (1 << 2) ++#define CLR_OVER (1 << 1) ++#define CLR_UNDER (1 << 0) ++ ++//SFC_CMD_IDX ++#define CMD_IDX_MSK (0x3f << 0) ++#define CDT_DATAEN_MSK (0x1 << 31) ++#define CDT_DATAEN_OFF (31) ++#define CDT_DIR_MSK (0x1 << 30) ++#define CDT_DIR_OFF (30) ++ ++/* For SFC_GLB1 */ ++#define GLB1_DQS_EN (1 << 2) ++#define GLB1_CHIP_SEL_OFFSET (0) ++#define GLB1_CHIP_SEL_MSK (0x3 << 0) ++#define GLB1_CHIP_SEL_0 (0) ++#define GLB1_CHIP_SEL_1 (1) ++#define GLB1_CHIP_SEL_01 (2) ++ ++#define N_MAX 6 ++#define MAX_SEGS 128 ++ ++#define CHANNEL_0 0 ++#define CHANNEL_1 1 ++#define CHANNEL_2 2 ++#define CHANNEL_3 3 ++#define CHANNEL_4 4 ++#define CHANNEL_5 5 ++ ++#define ENABLE 1 ++#define DISABLE 0 ++ ++#define COM_CMD 1 // common cmd ++#define POLL_CMD 2 // the cmd will poll the status of flash,ext: read status ++ ++#define DMA_OPS 1 ++#define CPU_OPS 0 ++ ++#define TM_STD_SPI 0 ++#define TM_DI_DO_SPI 1 ++#define TM_DIO_SPI 2 ++#define TM_FULL_DIO_SPI 3 ++#define TM_QI_QO_SPI 5 ++#define TM_QIO_SPI 6 ++#define TM_FULL_QIO_SPI 7 ++#define TM_OCTAL_SPT 9 ++#define TM_OCTAL_IO_SPI 10 ++#define TM_OCTAL_FULL_SPI 11 ++ ++ ++#define DEFAULT_CDT 1 ++#define UPDATE_CDT 2 ++#define DEFAULT_ADDRSIZE 3 ++#define DEFAULT_ADDRMODE 0 ++ ++ ++#define THRESHOLD 32 ++ ++#define SFC_NOR_RATE 110 ++#define DEF_ADDR_LEN 3 ++#define DEF_TCHSH 6 ++#define DEF_TSLCH 6 ++#define DEF_TSHSL_R 20 ++#define DEF_TSHSL_W 50 ++ ++ ++#endif +diff --git a/arch/mips/xburst2/soc-x2500/include/soc/tcsm_layout.h b/arch/mips/xburst2/soc-x2500/include/soc/tcsm_layout.h +new file mode 100644 +index 000000000..2de46b7bd +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/soc/tcsm_layout.h +@@ -0,0 +1,53 @@ ++#ifndef __TCSM_LAYOUT_H__ ++#define __TCSM_LAYOUT_H__ ++ ++/** ++ * |-------------| ++ * | BANK0 | ++ * |-------------| <--- SLEEP_TCSM_BOOTCODE_TEXT ++ * | BOOT CODE | ++ * |-------------| <--- SLEEP_TCSM_RESUMECODE_TEXT ++ * | ... | ++ * | RESUME CODE | ++ * | ... | ++ * |-------------| <--- SLEEP_TCSM_RESUME_DATA ++ * | ... | ++ * | RESUME DATA | ++ * | ... | ++ * |_____________| <--- SLEEP_TCSM_CPU_RESMUE_SP ++ * ++ * ++ * |-------------| ++ * | BANK1 | ++ * |-------------| <--- TO BE DEFINED ++ * | | ++ * | | ++ * | ... | ++ * | VOICE DATA | ++ * | ... | ++ * | | ++ * | | ++ * |_____________| ++ * ++ */ ++ ++#define SLEEP_TCSM_SPACE 0xb3422000 ++#define VOICE_TCSM_DATA_BUF 0xb3423000 ++#define TCSM_BANK_LEN 4096 ++ ++#define SLEEP_TCSM_BOOT_TEXT (SLEEP_TCSM_SPACE) ++#define SLEEP_TCSM_BOOT_LEN 64 ++#define SLEEP_TCSM_BOOT_END (SLEEP_TCSM_BOOT_TEXT + SLEEP_TCSM_BOOT_LEN) ++ ++#define SLEEP_TCSM_RESUME_TEXT (SLEEP_TCSM_BOOT_END) ++#define SLEEP_TCSM_RESUME_LEN 2048 ++#define SLEEP_TCSM_RESUME_END (SLEEP_TCSM_RESUME_TEXT + SLEEP_TCSM_RESUME_LEN) ++ ++#define SLEEP_TCSM_RESUME_DATA (SLEEP_TCSM_RESUME_END) ++ ++#define SLEEP_TCSM_SPACE_END (SLEEP_TCSM_SPACE + TCSM_BANK_LEN) ++ ++#define SLEEP_TCSM_CPU_RESMUE_SP SLEEP_TCSM_SPACE_END - 4 ++ ++ ++#endif /* __TCSM_LAYOUT_H__ */ +diff --git a/arch/mips/xburst2/soc-x2500/include/war.h b/arch/mips/xburst2/soc-x2500/include/war.h +new file mode 100644 +index 000000000..fd1ef3147 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/include/war.h +@@ -0,0 +1,27 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle ++ */ ++#ifndef __ASM_MACH_INGENIC_WAR_H__ ++#define __ASM_MACH_INGENIC_WAR_H__ ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 1 ++#define MIPS_BRIDGE_SYNC_WAR 1 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif ++ +diff --git a/arch/mips/xburst2/soc-x2500/libdmmu.c b/arch/mips/xburst2/soc-x2500/libdmmu.c +new file mode 100644 +index 000000000..e3288d299 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/libdmmu.c +@@ -0,0 +1,1087 @@ ++/* ++ * This driver is used by VPU driver. ++ * ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: Yan Zhengting ++ * Modify by: Sun Jiwei ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#define print_dbg(f, arg...) printk(KERN_INFO "dpu: %s, %d: " f "\n", __func__, __LINE__, ## arg) ++ ++#define MAP_COUNT 0x10 ++#define MAP_CONUT_MASK 0xff0 ++ ++#define DMMU_PTE_VLD 0x01 ++#define DMMU_PMD_VLD 0x01 ++ ++#define KSEG0_LOW_LIMIT 0x80000000 ++#define KSEG1_HEIGH_LIMIT 0xC0000000 ++ ++enum mem_break{ ++ MODE1, /* 13 24 57 68 911 1012 ... */ ++ MODE2, /* 13 24 35 46 57 68 79 810 ... */ ++ MODE3 /* 12 34 56 78 ... */ ++}; ++ ++LIST_HEAD(handle_list); ++static unsigned long reserved_pte = 0; ++static unsigned long res_pte_paddr; ++ ++struct pmd_node { ++ unsigned int count; ++ unsigned long index; ++ unsigned long page; ++ struct list_head list; ++}; ++ ++struct map_node { ++ struct device *dev; ++ unsigned long start; ++ unsigned long len; ++ struct list_head list; ++}; ++ ++struct dmmu_handle { ++ pid_t tgid; ++ unsigned long pdg; ++ struct mutex lock; ++ struct list_head list; ++ struct list_head pmd_list; ++ struct list_head map_list; ++ struct list_head dev_notifier_list; ++ ++ struct mm_struct *handle_mm; /* mm struct used to match exit_mmap notify */ ++ ++ struct mmu_notifier mn; ++}; ++ ++/* for test */ ++static struct dmmu_handle *find_handle(void); ++static struct dmmu_handle *create_handle(void); ++static void dmmu_cache_wback(struct dmmu_handle *h); ++static int dmmu_mm_dev_release(struct dmmu_handle *h); ++ ++int dmmu_flush_cache(unsigned long vaddr, unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h = NULL; ++ struct map_node *n = NULL; ++ unsigned long *pgd, *pte_phys, *pte; ++ unsigned long virpage_phy; ++ unsigned long v_end = vaddr+len; ++ int found = 0; ++ int index; ++ ++ h = find_handle(); ++ if(!h){ ++ printk("%s find handle err!\n",__func__); ++ return -1; ++ } ++ if (vaddr & 0xfff) { ++ printk("%s addr align page err!\n",__func__); ++ return -1; ++ } ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if((vaddr >= n->start) && ++ ((vaddr+len) <= (n->start + n->len))) { ++ found = 1; ++ break; ++ } ++ } ++ if(!found) { ++ printk("%s addr err!\n",__func__); ++ return -1; ++ } ++ pgd = (unsigned long *)h->pdg; ++ while(vaddr < v_end) { ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ index = ((vaddr & 0x3ff000) >> 12); ++ virpage_phy = pte[index] & ~DMMU_PTE_VLD; ++ dma_cache_wback((unsigned long)phys_to_virt(virpage_phy),PAGE_SIZE); ++ vaddr+=PAGE_SIZE; ++ } ++ return 0; ++} ++ ++EXPORT_SYMBOL(dmmu_flush_cache); ++static int make_smash_list(struct dmmu_handle *h, unsigned long vaddr, unsigned long (**base)[2], unsigned int *len) ++{ ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *pte, *pte_phys; ++ unsigned int i, index; ++ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start) { ++ list_len = (n->len) >> 12; ++ break; ++ } ++ } ++ ++ if (list_len) { ++ list_smash = kmalloc(list_len * 2 * 4, GFP_KERNEL); ++ if (list_smash) { ++ i = 0; ++ while(i < list_len) { ++ list_smash[i][0] = (unsigned long)(vaddr & 0xfffff000); ++ ++ index = vaddr>>22; ++ pte_phys = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ ++ ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte_phys); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++// printk(">>>>>>virt = 0x%lx, phys = 0x%lx\n", vaddr, ++// *((unsigned long int *) (((unsigned long)pte_phys+index*4) | 0xa0000000))); ++ list_smash[i][1] = pte[index]; ++ ++ vaddr+=0x1000; ++ i++; ++ } ++ } ++ } ++ ++ if (list_smash) { ++ *base = list_smash; ++ *len = list_len; ++ return 0; ++ } else { ++ return -1; ++ } ++} ++EXPORT_SYMBOL(dmmu_dump_map); ++ ++int dmmu_dump_map(unsigned long vaddr) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ unsigned long *tmp; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return -1; ++ /* 检查4kå¯¹é½ */ ++ if (vaddr & 0xfff){ ++ return -1; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ unsigned int i; ++ for (i = 0; i phys: 0x%08lx] uncache: 0x%08lx\n", ++ list_smash[i][0],list_smash[i][1],(unsigned long)tmp); ++ ++ printk("value[0] = 0x%08lx, value[1] = 0x%08lx value[2] = 0x%08lx value[1013] = 0x%08lx\n", ++ tmp[0], tmp[1], tmp[2], tmp[1013]); ++ } ++ } ++ ++ mutex_unlock(&h->lock); ++ kfree((void*)list_smash); ++ ++ return 0; ++} ++ ++ /* 13 24 57 68 911 1012 ... */ ++static int smash_mode1(unsigned long (*base)[2], unsigned int len) ++{ ++ unsigned int i; ++ unsigned long tmp; ++ if (len >= 4) { ++ for (i=0; i= 4) { ++ for (i=0; ipdg; ++ unsigned long *pte; ++ unsigned int i, index; ++ ++ for (i=0; i>22; ++ pte = (unsigned long *)(pgd[index] & ~DMMU_PMD_VLD); ++ pte = (unsigned long *)phys_to_virt((unsigned long)pte); ++ ++ index = ((vaddr & 0x3ff000) >> 12); ++ pte[index] = (*base)[i][1]; ++ vaddr+=0x1000; ++ } ++ return 0; ++} ++ ++static int update_process_pte(unsigned long vaddr, unsigned long (**base)[2], unsigned int len) ++{ ++ unsigned int i; ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ spin_lock(¤t->mm->page_table_lock); ++ for (i=0; imm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) ++ return 0; ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) ++ return 0; ++ pte = pte_offset_kernel(pmdir,vaddr); ++ if (pte_present(*pte)){ ++ pte->pte = (*base)[i][1]; ++ } ++ vaddr += 4096; ++ } ++ spin_unlock(¤t->mm->page_table_lock); ++ return 0; ++} ++ ++int dmmu_memory_smash(unsigned long vaddr, int smash_mode) ++{ ++ struct dmmu_handle *h = NULL; ++ unsigned long (*list_smash)[2] = NULL; ++ unsigned int list_len = 0; ++ struct vm_area_struct * vma; ++ ++ h = find_handle(); ++ if(!h){ ++ h = create_handle(); ++ } ++ if(!h) ++ return -1; ++ ++ /* 检查4kå¯¹é½ */ ++ if (vaddr & 0xfff){ ++ return -1; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ if (make_smash_list(h, vaddr, &list_smash, &list_len)) { ++ mutex_unlock(&h->lock); ++ return -1; ++ } else { ++ switch (smash_mode) { ++ case MODE1: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode1(list_smash, list_len); ++ break; ++ case MODE2: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode2(list_smash, list_len); ++ break; ++ case MODE3: ++ print_dbg("smash_mode = %u\n",smash_mode); ++ smash_mode3(list_smash, list_len); ++ break; ++ default: ++ break; ++ } ++ } ++ update_dmmu_pte(h, vaddr, &list_smash, list_len); ++ update_process_pte(vaddr, &list_smash, list_len); ++ ++ dmmu_cache_wback(h); ++ vma = find_vma(current->mm, vaddr); ++ flush_tlb_range(vma, vaddr, vaddr+(list_len*PAGE_SIZE)); ++ ++ mutex_unlock(&h->lock); ++ kfree(list_smash); ++ ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_memory_smash); ++ ++static struct map_node *check_map(struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ if(vaddr == n->start && len == n->len) ++ return n; ++ } ++ return NULL; ++} ++ ++static void handle_add_map(struct device *dev,struct dmmu_handle *h,unsigned long vaddr,unsigned long len) ++{ ++ struct map_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ if(n == NULL) { ++ printk("malloc map_list node failed !!\n"); ++ return; ++ } ++ n->dev = dev; ++ n->start = vaddr; ++ n->len = len; ++ INIT_LIST_HEAD(&n->list); ++ list_add(&n->list,&h->map_list); ++} ++ ++static unsigned int get_pfn(unsigned int vaddr) ++{ ++ pgd_t *pgdir; ++ pmd_t *pmdir; ++ pte_t *pte; ++ pgdir = pgd_offset(current->mm, vaddr); ++ if(pgd_none(*pgdir) || pgd_bad(*pgdir)) { ++ return 0; ++ } ++ pmdir = pmd_offset((pud_t *)pgdir, vaddr); ++ if(pmd_none(*pmdir) || pmd_bad(*pmdir)) { ++ return 0; ++ } ++ // TODO: 如果是kmap的地å€ï¼Œæ¯”如C空间的地å€è¿™é‡Œéœ€è¦å¤„ç†ä¸€ä¸‹ä½¿ç”¨pte_offset_kmap. ++ pte = pte_offset_kernel(pmdir,vaddr); ++ if (pte_present(*pte)) { ++ ++ return pte_pfn(*pte) << PAGE_SHIFT; ++ } ++ ++ return 0; ++} ++ ++static unsigned long dmmu_v2pfn(unsigned long vaddr) ++{ ++ if(vaddr < KSEG0_LOW_LIMIT) ++ return get_pfn(vaddr); ++ ++ if(vaddr >= KSEG0_LOW_LIMIT && vaddr < KSEG1_HEIGH_LIMIT) ++ return virt_to_phys((void *)vaddr); ++ ++ panic("dmmu_v2pfn error!"); ++ return 0; ++} ++ ++static unsigned long unmap_node(struct pmd_node *n,unsigned long vaddr,unsigned long end,int check) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ int free = !check || (--n->count == 0); ++ struct page *page = NULL; ++ ++ if(vaddr && end) { ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] & MAP_CONUT_MASK) { ++ pte[index] -= MAP_COUNT; ++ } else { ++ page = pfn_to_page(pte[index] >> PAGE_SHIFT); ++ ++ ClearPageReserved(page); ++ pte[index] = reserved_pte; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ } ++ ++ if(free) { ++ ClearPageReserved(virt_to_page((void *)n->page)); ++ free_page(n->page); ++ list_del(&n->list); ++ kfree(n); ++ } ++ ++ return vaddr; ++} ++ ++static unsigned long map_node(struct pmd_node *n,unsigned int vaddr,unsigned int end) ++{ ++ unsigned int *pte = (unsigned int *)n->page; ++ int index = ((vaddr & 0x3ff000) >> 12); ++ struct page * page = NULL; ++ unsigned long pfn = 0; ++ ++ ++ while(index < 1024 && vaddr < end) { ++ if(pte[index] == reserved_pte) { ++ ++ mmap_write_lock(current->mm); ++ ++ pfn = dmmu_v2pfn(vaddr) >> PAGE_SHIFT; ++ page = pfn_to_page(pfn); ++ ++ SetPageReserved(page); ++ ++ pte[index] = (pfn << PAGE_SHIFT) | DMMU_PTE_VLD; ++ ++ mmap_write_unlock(current->mm); ++ } else { ++ pte[index] += MAP_COUNT; ++ } ++ index++; ++ vaddr += 4096; ++ } ++ n->count++; ++ return vaddr; ++} ++ ++static struct pmd_node *find_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ if(n->index == (vaddr & 0xffc00000)) ++ return n; ++ } ++ return NULL; ++} ++ ++static struct pmd_node *add_node(struct dmmu_handle *h,unsigned int vaddr) ++{ ++ int i; ++ unsigned long *pte; ++ unsigned long *pgd = (unsigned long *)h->pdg; ++ struct pmd_node *n = kmalloc(sizeof(*n),GFP_KERNEL); ++ INIT_LIST_HEAD(&n->list); ++ n->count = 0; ++ n->index = vaddr & 0xffc00000; ++ n->page = __get_free_page(GFP_KERNEL); ++ SetPageReserved(virt_to_page((void *)n->page)); ++ ++ pte = (unsigned long *)n->page; ++ for(i=0;i<1024;i++) ++ pte[i] = reserved_pte; ++ ++ list_add(&n->list, &h->pmd_list); ++ ++ pgd[vaddr>>22] = dmmu_v2pfn(n->page) | DMMU_PMD_VLD; ++// printk(">>>>>>> n->page = %lx, pgd[vaddr>>22] = %lx <<<<<<<\n\n", n->page, pgd[vaddr>>22]); ++ return n; ++} ++ ++static struct dmmu_handle *find_handle(void) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ if(h->tgid == current->tgid) ++ return h; ++ } ++ return NULL; ++} ++ ++/** ++* @brief unmap node from map list, clear each pmd_node in pmd_list, ++* Not free handle, let dmmu_unmap_all do it. ++* ++* @param h ++* ++* @return ++*/ ++static int dmmu_unmap_node_unlock(struct dmmu_handle *h) ++{ ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++ unsigned long vaddr; ++ int len; ++ unsigned long end; ++ ++ struct pmd_node *node; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ /* find and delete a map node from map_list */ ++ cn = list_entry(pos, struct map_node, list); ++ vaddr = cn->start; ++ len = cn->len; ++ end = vaddr + len; ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(node) ++ vaddr = unmap_node(node,vaddr,end,1); ++ } ++ ++ list_del(&cn->list); ++ kfree(cn); ++ } ++ ++ ++ return 0; ++ ++} ++ ++ ++void dmmu_mm_release(struct mmu_notifier *mn, ++ struct mm_struct *mm) ++{ ++ struct dmmu_handle *h = container_of(mn, struct dmmu_handle, mn); ++ ++ printk("===== dmmu release mm (TODO: not checked) ====h: %p\n", h); ++ ++ if(h->handle_mm != mm) { ++ return; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ dmmu_mm_dev_release(h); ++ ++ dmmu_unmap_node_unlock(h); ++ ++ mutex_unlock(&h->lock); ++} ++ ++static const struct mmu_notifier_ops dmmu_mm_notifier_ops = { ++ .release = dmmu_mm_release, ++}; ++ ++ ++static struct dmmu_handle *create_handle(void) ++{ ++ struct dmmu_handle *h; ++ unsigned int pgd_index; ++ unsigned long *pgd; ++ ++ h = kmalloc(sizeof(struct dmmu_handle),GFP_KERNEL); ++ if(!h) ++ return NULL; ++ ++ h->tgid = current->tgid; ++ h->pdg = __get_free_page(GFP_KERNEL); ++ if(!h->pdg) { ++ pr_err("%s %d, Get free page for PGD error\n", ++ __func__, __LINE__); ++ kfree(h); ++ return NULL; ++ } ++ SetPageReserved(virt_to_page((void *)h->pdg)); ++ ++ pgd = (unsigned long *)h->pdg; ++ ++ for (pgd_index=0; pgd_index < PTRS_PER_PGD; pgd_index++) ++ pgd[pgd_index] = res_pte_paddr; ++ ++ INIT_LIST_HEAD(&h->list); ++ INIT_LIST_HEAD(&h->pmd_list); ++ INIT_LIST_HEAD(&h->map_list); ++ INIT_LIST_HEAD(&h->dev_notifier_list); ++ mutex_init(&h->lock); ++ ++ /* register exit_mmap notify */ ++ h->handle_mm = current->mm; ++ ++ h->mn.ops = &dmmu_mm_notifier_ops; ++ ++ mmu_notifier_register(&h->mn, h->handle_mm); ++ ++ list_add(&h->list, &handle_list); ++ ++ return h; ++} ++ ++static int dmmu_make_present(unsigned long addr,unsigned long end) ++{ ++#if 0 ++ unsigned long i; ++ for(i = addr; i < end; i += 4096) { ++ *(volatile unsigned char *)(i) = 0; ++ } ++ *(volatile unsigned char *)(end - 1) = 0; ++ return 0; ++#else ++ int ret, len, write; ++ struct vm_area_struct * vma; ++ unsigned long vm_page_prot; ++ ++ mmap_write_lock(current->mm); ++ vma = find_vma(current->mm, addr); ++ if (!vma) { ++ printk("dmmu_make_present error. addr=%lx len=%lx\n",addr,end-addr); ++ mmap_write_unlock(current->mm); ++ return -1; ++ } ++ ++ if(vma->vm_flags & VM_PFNMAP) { ++ mmap_write_unlock(current->mm); ++ return 0; ++ } ++ write = (vma->vm_flags & VM_WRITE) != 0; ++ BUG_ON(addr >= end); ++ BUG_ON(end > vma->vm_end); ++ ++ vm_page_prot = pgprot_val(vma->vm_page_prot); ++ vma->vm_page_prot = __pgprot(vm_page_prot | _PAGE_VALID| _PAGE_ACCESSED | _PAGE_PRESENT); ++ ++ len = DIV_ROUND_UP(end, PAGE_SIZE) - addr/PAGE_SIZE; ++ ret = get_user_pages(addr, len, write, NULL, NULL); ++ vma->vm_page_prot = __pgprot(vm_page_prot); ++ if (ret < 0) { ++ printk("dmmu_make_present get_user_pages error(%d). addr=%lx len=%lx\n",0-ret,addr,end-addr); ++ mmap_write_unlock(current->mm); ++ return ret; ++ } ++ ++ mmap_write_unlock(current->mm); ++ return ret == len ? 0 : -1; ++#endif ++} ++ ++static void dmmu_cache_wback(struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct pmd_node *n; ++ ++ dma_cache_wback(h->pdg,PAGE_SIZE); ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ n = list_entry(pos, struct pmd_node, list); ++ dma_cache_wback(n->page,PAGE_SIZE); ++ } ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h); ++ ++unsigned long dmmu_map(struct device *dev,unsigned long vaddr,unsigned long len) ++{ ++ int end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ h = find_handle(); ++ if(!h) ++ h = create_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ printk("(pid %d)dmmu_map %lx %lx================================================\n",h->tgid,vaddr,len); ++#endif ++ if(check_map(h,vaddr,len)) ++ { ++ mutex_unlock(&h->lock); ++ return dmmu_v2pfn(h->pdg); ++ } ++ ++ if(dmmu_make_present(vaddr,vaddr+len)) ++ { ++ mutex_unlock(&h->lock); ++ return 0; ++ } ++ ++ handle_add_map(dev,h,vaddr,len); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(!node) { ++ node = add_node(h,vaddr); ++ } ++ vaddr = map_node(node,vaddr,end); ++ } ++ dmmu_cache_wback(h); ++#ifdef DEBUG ++ dmmu_dump_handle(NULL,NULL,h); ++#endif ++ mutex_unlock(&h->lock); ++ ++ return dmmu_v2pfn(h->pdg); ++} ++EXPORT_SYMBOL(dmmu_map); ++ ++static int dmmu_mm_dev_release(struct dmmu_handle *h) ++{ ++ struct dmmu_mm_notifier *n = NULL; ++ struct list_head *pos, *next; ++ ++ list_for_each_safe(pos, next, &h->dev_notifier_list) { ++ n = list_entry(pos, struct dmmu_mm_notifier, list); ++ if(n && n->ops && n->ops->mm_release) { ++ n->ops->mm_release(n->data); ++ } ++ ++ list_del(&n->list); ++ } ++ ++ ++ return 0; ++} ++ ++ ++int dmmu_register_mm_notifier(struct dmmu_mm_notifier *dmn) ++{ ++ int dev_already_registered = 0; ++ struct dmmu_mm_notifier *n = NULL; ++ struct dmmu_handle *h; ++ struct list_head *pos, *next; ++ ++ h = find_handle(); ++ if(!h) { ++ return -EINVAL; ++ } ++ ++ mutex_lock(&h->lock); ++ ++ list_for_each_safe(pos, next, &h->dev_notifier_list) { ++ n = list_entry(pos, struct dmmu_mm_notifier, list); ++ ++ if(n == dmn) { ++ /* already in dev_notifier_list*/ ++ dev_already_registered = 1; ++ } ++ ++ } ++ ++ if(dev_already_registered) { ++ goto out; ++ } ++ ++ list_add_tail(&dmn->list, &h->dev_notifier_list); ++out: ++ mutex_unlock(&h->lock); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_register_mm_notifier); ++ ++int dmmu_unmap(struct device *dev,unsigned long vaddr, int len) ++{ ++ unsigned long end = vaddr + len; ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *n; ++ ++ h = find_handle(); ++ if(!h) { ++ return 0; ++ } ++ ++ mutex_lock(&h->lock); ++#ifdef DEBUG ++ /*This printk can cause a memory leak. */ ++ printk("dmmu_unmap %lx %x**********************************************\n",vaddr,len); ++#endif ++ n = check_map(h,vaddr,len); ++ if(!n) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ if(n->dev != dev) { ++ mutex_unlock(&h->lock); ++ return -EAGAIN; ++ } ++ ++ list_del(&n->list); ++ kfree(n); ++ ++ while(vaddr < end) { ++ node = find_node(h,vaddr); ++ if(node) ++ vaddr = unmap_node(node,vaddr,end,1); ++ } ++ ++ if(list_empty(&h->pmd_list) && list_empty(&h->map_list)) { ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ mutex_unlock(&h->lock); ++ ++ mmu_notifier_unregister(&h->mn, h->handle_mm); ++ ++ kfree(h); ++ return 0; ++ } ++ ++ mutex_unlock(&h->lock); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_unmap); ++ ++int dmmu_free_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++ h = find_handle(); ++ if(!h) ++ return 0; ++ ++ mutex_lock(&h->lock); ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ node = find_node(h,cn->start); ++ if(node) ++ unmap_node(node,cn->start,cn->len,1); ++ list_del(&cn->list); ++ kfree(cn); ++ } ++ ++ list_for_each_safe(pos, next, &h->pmd_list) { ++ node = list_entry(pos, struct pmd_node, list); ++ if(node){ ++ printk("WARN: pmd list should NULL\n"); ++ unmap_node(node,0,0,0); ++ } ++ } ++ ++ list_del(&h->list); ++ ClearPageReserved(virt_to_page((void *)h->pdg)); ++ free_page(h->pdg); ++ ++ mutex_unlock(&h->lock); ++ mmu_notifier_unregister(&h->mn, h->handle_mm); ++ kfree(h); ++ return 0; ++} ++ ++/** ++* @brief release all resources, which should be called by driver close ++* ++* @param dev ++* ++* @return ++*/ ++int dmmu_unmap_all(struct device *dev) ++{ ++ struct dmmu_handle *h; ++ struct map_node *cn; ++ struct list_head *pos, *next; ++ ++#ifdef DEBUG ++ printk("dmmu_unmap_all\n"); ++#endif ++ ++ h = find_handle(); ++ if(!h) { ++ printk("dmmu unmap all not find hindle, maybe it has benn freed already, name: %s\n", dev->kobj.name); ++ return 0; ++ } ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ cn = list_entry(pos, struct map_node, list); ++ if(dev == cn->dev) { ++ dmmu_unmap(dev,cn->start,cn->len); ++ } ++ } ++ ++ ++ if(list_empty(&h->map_list)) ++ dmmu_free_all(dev); ++ return 0; ++} ++EXPORT_SYMBOL(dmmu_unmap_all); ++int __init dmmu_init(void) ++{ ++ unsigned int pte_index; ++ unsigned long res_page_paddr; ++ unsigned long reserved_page; ++ unsigned int *res_pte_vaddr; ++ ++ reserved_page = __get_free_page(GFP_KERNEL); ++ if (!reserved_page) { ++ pr_err("%s %d, Get reserved page error\n", ++ __func__, __LINE__); ++ return ENOMEM; ++ } ++ SetPageReserved(virt_to_page((void *)reserved_page)); ++ reserved_pte = dmmu_v2pfn(reserved_page) | DMMU_PTE_VLD; ++ ++ res_page_paddr = virt_to_phys((void *)reserved_page) | 0xFFF; ++ ++ res_pte_vaddr = (unsigned int *)__get_free_page(GFP_KERNEL); ++ if (!res_pte_vaddr) { ++ pr_err("%s %d, Get free page for PTE error\n", ++ __func__, __LINE__); ++ free_page(reserved_page); ++ return ENOMEM; ++ } ++ SetPageReserved(virt_to_page(res_pte_vaddr)); ++ res_pte_paddr = virt_to_phys((void *)res_pte_vaddr) | DMMU_PTE_VLD; ++ ++ for (pte_index = 0; pte_index < PTRS_PER_PTE; pte_index++) ++ res_pte_vaddr[pte_index] = res_page_paddr; ++ printk("%s %d PTRS_PER_PTE = %lu\n",__func__,__LINE__,PTRS_PER_PTE); ++ ++ return 0; ++} ++arch_initcall(dmmu_init); ++ ++void dmmu_dump_vaddr(unsigned long vaddr) ++{ ++ struct dmmu_handle *h; ++ struct pmd_node *node; ++ ++ unsigned long *pmd,*pte; ++ h = find_handle(); ++ if(!h) { ++ printk("dmmu_dump_vaddr %08lx error - h not found!\n",vaddr); ++ return; ++ } ++ ++ node = find_node(h,vaddr); ++ if(!node) { ++ printk("dmmu_dump_vaddr %08lx error - node not found!\n",vaddr); ++ return; ++ } ++ ++ pmd = (unsigned long *)h->pdg; ++ pte = (unsigned long *)node->page; ++ ++ printk("pmd base = %p; pte base = %p\n",pmd,pte); ++ printk("pmd = %08lx; pte = %08lx\n",pmd[vaddr>>22],pte[(vaddr&0x3ff000)>>12]); ++} ++ ++static void dmmu_dump_handle(struct seq_file *m, void *v, struct dmmu_handle *h) ++{ ++ struct list_head *pos, *next; ++ struct map_node *n; ++ ++ list_for_each_safe(pos, next, &h->map_list) { ++ n = list_entry(pos, struct map_node, list); ++ { ++ int i = 0; ++ int vaddr = n->start; ++ struct pmd_node *pn = find_node(h,vaddr); ++ unsigned int *pte = (unsigned int *)pn->page; ++ ++ while(vaddr < (n->start + n->len)) { ++ if(i++%8 == 0) ++ printk("\nvaddr %08x : ",vaddr & 0xfffff000); ++ printk("%08x ",pte[(vaddr & 0x3ff000)>>12]); ++ vaddr += 4096; ++ } ++ printk("\n\n"); ++ } ++ } ++} ++ ++static int dmmu_proc_show(struct seq_file *m, void *v) ++{ ++ struct list_head *pos, *next; ++ struct dmmu_handle *h; ++ volatile unsigned long flags; ++ local_irq_save(flags); ++ list_for_each_safe(pos, next, &handle_list) { ++ h = list_entry(pos, struct dmmu_handle, list); ++ dmmu_dump_handle(m, v, h); ++ } ++ local_irq_restore(flags); ++ return 0; ++} ++ ++static int dmmu_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, dmmu_proc_show, PDE_DATA(inode)); ++} ++ ++static const struct proc_ops dmmus_proc_fops ={ ++ .proc_read = seq_read, ++ .proc_open = dmmu_open, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release, ++}; ++ ++static int __init init_dmmu_proc(void) ++{ ++ struct proc_dir_entry *p; ++ p = jz_proc_mkdir("dmmu"); ++ if (!p) { ++ printk("create_proc_entry for common dmmu failed.\n"); ++ return -ENODEV; ++ } ++ proc_create("dmmus", 0600,p,&dmmus_proc_fops); ++ ++ return 0; ++} ++ ++module_init(init_dmmu_proc); +diff --git a/arch/mips/xburst2/soc-x2500/pm.c b/arch/mips/xburst2/soc-x2500/pm.c +new file mode 100644 +index 000000000..835f43e16 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/pm.c +@@ -0,0 +1,608 @@ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pm.h" ++ ++ ++#define DDR_DEEP_SLEEP ++ ++#ifdef DEBUG_PM ++static void x2500_pm_gate_check(void) ++{ ++ unsigned int gate0 = cpm_inl(CPM_CLKGR); ++ unsigned int gate1 = cpm_inl(CPM_CLKGR1); ++ int i; ++ int x; ++ ++ printk("gate0 = 0x%08x\n", gate0); ++ printk("gate1 = 0x%08x\n", gate1); ++ for (i = 0; i < 32; i++) { ++ x = (gate0 >> i) & 1; ++ if (x == 0) ++ printk("warning : bit[%d] in clk gate0 is enabled\n", i); ++ } ++ for (i = 0; i < 16; i++) { ++ x = (gate1 >> i) & 1; ++ if (x == 0) ++ printk("warning : bit[%d] in clk gate1 is enabled\n", i); ++ } ++ ++} ++#endif ++ ++ ++ ++#ifdef DDR_DEEP_SLEEP ++static void ddrp_auto_calibration(void) ++{ ++ unsigned int timeout = 0xffffff; ++ ++ serial_put_hex(*(volatile unsigned int *)(0xb3011000 + (0x74 << 2))); ++ serial_put_hex(*(volatile unsigned int *)(0xb3011000 + (0x75 << 2))); ++ serial_put_hex(*(volatile unsigned int *)(0xb3011000 + (0xa4 << 2))); ++ serial_put_hex(*(volatile unsigned int *)(0xb3011000 + (0xa5 << 2))); ++ ++ timeout = 0xffffff; ++ ddr_writel(0xa1, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ while(!((ddr_readl(DDRP_INNOPHY_CALIB_DONE) & 0xf) == 0xf) && --timeout) { ++ TCSM_PCHAR('t'); ++ } ++ ++ if(!timeout) { ++ TCSM_PCHAR('f'); ++ } ++ ++ ddr_writel(0xa0, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ serial_put_hex(*(volatile unsigned int *)(0xb3011000 + (0x74 << 2))); ++ serial_put_hex(*(volatile unsigned int *)(0xb3011000 + (0x75 << 2))); ++ serial_put_hex(*(volatile unsigned int *)(0xb3011000 + (0xa4 << 2))); ++ serial_put_hex(*(volatile unsigned int *)(0xb3011000 + (0xa5 << 2))); ++#if 1 ++ { ++ unsigned int cycsel, tmp; ++ unsigned int read_data0, read_data1; ++ unsigned int read_data2, read_data3; ++ unsigned int c0, c1, c2, c3; ++ unsigned int max; ++ ++ read_data0 = *(volatile unsigned int *)(0xb3011000 + (0x74 << 2)); ++ read_data1 = *(volatile unsigned int *)(0xb3011000 + (0x75 << 2)); ++ read_data2 = *(volatile unsigned int *)(0xb3011000 + (0xa4 << 2)); ++ read_data3 = *(volatile unsigned int *)(0xb3011000 + (0xa5 << 2)); ++ c0 = (read_data0 >> 4) & 0x7; ++ c1 = (read_data1 >> 4) & 0x7; ++ c2 = (read_data0 >> 4) & 0x7; ++ c3 = (read_data1 >> 4) & 0x7; ++ ++ max = max(max(c0, c1), max(c2, c3)); ++ ++ cycsel = max + 3; ++ ++ tmp = *(volatile unsigned int *)(0xb3011000 + (0xa << 2)); ++ tmp &= ~(7 << 1); ++ tmp |= cycsel << 1; ++ *(volatile unsigned int *)(0xb3011000 + (0xa << 2)) = tmp; ++ ++ ++ tmp = *(volatile unsigned int *)(0xb3011000 + 0x4); ++ tmp |= 1 << 6; ++ *(volatile unsigned int *)(0xb3011000 + (0x1 << 2)) = tmp; ++ TCSM_PCHAR('C'); ++ } ++#endif ++} ++ ++static void ddrp_hs_config(void) ++{ ++ ++ /* odt */ ++ reg_ddr_phy(0xb0) = 0xf; ++ reg_ddr_phy(0xb1) = 0xf; ++ reg_ddr_phy(0xb2) = 0x11; ++ reg_ddr_phy(0xb3) = 0x11; ++ ++ reg_ddr_phy(0xc0) = 0x3; ++ reg_ddr_phy(0xc1) = 0x3; ++ reg_ddr_phy(0xd0) = 0x3; ++ reg_ddr_phy(0xd1) = 0x3; ++ reg_ddr_phy(0xe0) = 0x3; ++ reg_ddr_phy(0xe1) = 0x3; ++ reg_ddr_phy(0xf0) = 0x3; ++ reg_ddr_phy(0xf1) = 0x3; ++ ++ reg_ddr_phy(0xc2) = 0x11; ++ reg_ddr_phy(0xc3) = 0x11; ++ reg_ddr_phy(0xd2) = 0x11; ++ reg_ddr_phy(0xd3) = 0x11; ++ reg_ddr_phy(0xe2) = 0x11; ++ reg_ddr_phy(0xe3) = 0x11; ++ reg_ddr_phy(0xf2) = 0x11; ++ reg_ddr_phy(0xf3) = 0x11; ++ ++ /* dll */ ++ reg_ddr_phy(0x15) = 0xc; ++ reg_ddr_phy(0x16) = 0x1; ++ ++ reg_ddr_phy(0x54) = 0xc; ++ reg_ddr_phy(0x64) = 0xc; ++ reg_ddr_phy(0x84) = 0xc; ++ reg_ddr_phy(0x94) = 0xc; ++ ++ reg_ddr_phy(0x55) = 0x1; ++ reg_ddr_phy(0x65) = 0x1; ++ reg_ddr_phy(0x85) = 0x1; ++ reg_ddr_phy(0x95) = 0x1; ++ ++ /* skew */ ++ reg_ddr_phy(0x100 + 0x0) = 0x8; ++ reg_ddr_phy(0x100 + 0x1) = 0x8; ++ reg_ddr_phy(0x100 + 0x2) = 0x8; ++ reg_ddr_phy(0x100 + 0x3) = 0x8; ++ reg_ddr_phy(0x100 + 0x4) = 0x8; ++ reg_ddr_phy(0x100 + 0x5) = 0x8; ++ reg_ddr_phy(0x100 + 0x6) = 0x8; ++ reg_ddr_phy(0x100 + 0x7) = 0x8; ++ reg_ddr_phy(0x100 + 0x8) = 0x8; ++ reg_ddr_phy(0x100 + 0x9) = 0x8; ++ reg_ddr_phy(0x100 + 0xa) = 0x8; ++ reg_ddr_phy(0x100 + 0xb) = 0x8; ++ reg_ddr_phy(0x100 + 0xc) = 0x8; ++ reg_ddr_phy(0x100 + 0xd) = 0x8; ++ reg_ddr_phy(0x100 + 0xe) = 0x8; ++ reg_ddr_phy(0x100 + 0xf) = 0x8; ++ reg_ddr_phy(0x100 + 0x10) = 0x8; ++ reg_ddr_phy(0x100 + 0x11) = 0x8; ++ reg_ddr_phy(0x100 + 0x12) = 0x8; ++ reg_ddr_phy(0x100 + 0x13) = 0x8; ++ reg_ddr_phy(0x100 + 0x14) = 0x8; ++ reg_ddr_phy(0x100 + 0x15) = 0x8; ++ reg_ddr_phy(0x100 + 0x16) = 0x8; ++ reg_ddr_phy(0x100 + 0x17) = 0x8; ++ reg_ddr_phy(0x100 + 0x18) = 0x8; ++ reg_ddr_phy(0x100 + 0x19) = 0x8; ++ reg_ddr_phy(0x100 + 0x1a) = 0x8; ++ reg_ddr_phy(0x100 + 0x1b) = 0x8; ++ reg_ddr_phy(0x100 + 0x1c) = 0x8; ++ reg_ddr_phy(0x100 + 0x1d) = 0x8; ++ reg_ddr_phy(0x100 + 0x1e) = 0x8; ++ ++ reg_ddr_phy(0x100 + 0x16) = 0x8; ++ reg_ddr_phy(0x100 + 0x17) = 0x8; ++ ++ reg_ddr_phy(0x120 + 0x0) = 0x8; ++ reg_ddr_phy(0x120 + 0x1) = 0x8; ++ reg_ddr_phy(0x120 + 0x2) = 0x8; ++ reg_ddr_phy(0x120 + 0x3) = 0x8; ++ reg_ddr_phy(0x120 + 0x4) = 0x8; ++ reg_ddr_phy(0x120 + 0x5) = 0x8; ++ reg_ddr_phy(0x120 + 0x6) = 0x8; ++ reg_ddr_phy(0x120 + 0x7) = 0x8; ++ reg_ddr_phy(0x120 + 0x8) = 0x8; ++ reg_ddr_phy(0x120 + 0xb) = 0x8; ++ reg_ddr_phy(0x120 + 0xc) = 0x8; ++ reg_ddr_phy(0x120 + 0xd) = 0x8; ++ reg_ddr_phy(0x120 + 0xe) = 0x8; ++ reg_ddr_phy(0x120 + 0xf) = 0x8; ++ reg_ddr_phy(0x120 + 0x10) = 0x8; ++ reg_ddr_phy(0x120 + 0x11) = 0x8; ++ reg_ddr_phy(0x120 + 0x12) = 0x8; ++ reg_ddr_phy(0x120 + 0x13) = 0x8; ++ ++ reg_ddr_phy(0x1a0 + 0x0) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x1) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x2) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x3) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x4) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x5) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x6) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x7) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x8) = 0x8; ++ reg_ddr_phy(0x1a0 + 0xb) = 0x8; ++ reg_ddr_phy(0x1a0 + 0xc) = 0x8; ++ reg_ddr_phy(0x1a0 + 0xd) = 0x8; ++ reg_ddr_phy(0x1a0 + 0xe) = 0x8; ++ reg_ddr_phy(0x1a0 + 0xf) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x10) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x11) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x12) = 0x8; ++ reg_ddr_phy(0x1a0 + 0x13) = 0x8; ++ ++ ++ reg_ddr_phy(2) |= 0x8; ++} ++ ++#endif ++ ++ ++ ++static void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size) ++{ ++ unsigned int instr; ++ int offset; ++ int i; ++#ifdef DEBUG_PM ++ printk("tcsm addr = %p %p size = %d\n",tcsm_addr,f_addr,size); ++#endif ++ for(i = 0;i < size / 4;i++) { ++ instr = f_addr[i]; ++ if((instr >> 26) == 2){ ++ offset = instr & 0x3ffffff; ++ offset = (offset << 2) - ((unsigned int)f_addr & 0xfffffff); ++ if(offset > 0) { ++ offset = ((unsigned int)tcsm_addr & 0xfffffff) + offset; ++ instr = (2 << 26) | (offset >> 2); ++ } ++ } ++ tcsm_addr[i] = instr; ++ } ++} ++ ++ ++static int soc_pm_idle(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 30); ++ opcr &= ~(1 << 31); ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++ ++static int soc_pm_sleep(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ unsigned int opcr = cpm_inl(CPM_OPCR); ++ ++ lcr &=~ 0x3; ++ lcr |= 1 << 0; // low power mode: SLEEP ++ cpm_outl(lcr, CPM_LCR); ++ ++ opcr &= ~(1 << 31); ++ opcr |= (1 << 30); ++ opcr |= (1 << 4); // exclk enable; ++ opcr &= ~(1 << 24); ++ cpm_outl(opcr, CPM_OPCR); ++ ++ return 0; ++} ++ ++static int soc_post_wakeup(void) ++{ ++ unsigned int lcr = cpm_inl(CPM_LCR); ++ lcr &= ~0x3; // low power mode: IDLE ++ cpm_outl(lcr, CPM_LCR); ++ ++ printk("post wakeup!\n"); ++ ++ ++ return 0; ++} ++ ++static noinline void cpu_resume_bootup(void) ++{ ++ ++ TCSM_PCHAR('X'); ++ /* set reset entry */ ++ *(volatile unsigned int *)0xb2200f00 = 0xbfc00000; ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "move $29, %0 \n\t" ++ "jr.hb %1 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ :"r" (SLEEP_CPU_RESUME_SP), "r"(SLEEP_CPU_RESUME_TEXT) ++ : ++ ); ++ ++} ++#define reg_ddr_phy(x) (*(volatile unsigned int *)(0xb3011000 + ((x) << 2))) ++static noinline void cpu_resume(void) ++{ ++ unsigned int ddrc_ctrl; ++ ++ TCSM_PCHAR('R'); ++ ++ if (sleep_param->state == PM_SUSPEND_MEM) { ++#ifdef DDR_DEEP_SLEEP ++ int tmp; ++ ++ /* enable pll */ ++ tmp = reg_ddr_phy(0x21); ++ tmp &= ~(1 << 1); ++ reg_ddr_phy(0x21) = tmp; ++ ++ while (!(reg_ddr_phy(0x42) & 0x8)) ++ serial_put_hex(reg_ddr_phy(0x42)); ++#endif ++ ++ /* dfi_init_start = 0, wait dfi_init_complete */ ++ *(volatile unsigned int *)0xb3012000 &= ~(1 << 3); ++ while(!(*(volatile unsigned int *)0xb3012004 & 0x1)); ++ ++#ifdef DDR_DEEP_SLEEP ++ /* bufferen_core = 1 */ ++ *(volatile unsigned int *)0xb3012000 &= ~(1 << 4); ++ ++#endif ++ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl &= ~(1<<5); ++ ddrc_ctrl |= (1<<1); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ while(ddr_readl(DDRC_STATUS) & (1<<2)); ++ while(REG32(DDRC_DWSTATUS) & (1<<4)); ++ ++ TCSM_DELAY(1000); ++ TCSM_PCHAR('1'); ++#ifdef DDR_DEEP_SLEEP ++ ddrp_hs_config(); ++ ddrp_auto_calibration(); ++#endif ++ TCSM_PCHAR('2'); ++ ++ /* restore ddr auto-sr */ ++ ddr_writel(sleep_param->autorefresh, DDRC_AUTOSR_EN); ++ TCSM_PCHAR('3'); ++ ++ /* restore ddr LPEN */ ++ ddr_writel(sleep_param->dlp, DDRC_DLP); ++ ++ /* restore ddr deep power down state */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= sleep_param->pdt; ++ ddrc_ctrl |= sleep_param->dpd; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ TCSM_PCHAR('4'); ++ } ++ ++ ++ TCSM_PCHAR('5'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (restore_goto) ++ : ++ ); ++} ++ ++ ++static noinline void cpu_sleep(void) ++{ ++ ++ ++ sleep_param->cpu_div = cpm_inl(CPM_CPCCR) & 0xf; ++ ++ blast_dcache32(); ++ blast_scache64(); ++ __sync(); ++ __fast_iob(); ++ ++ ++ TCSM_PCHAR('D'); ++ ++ if (sleep_param->state == PM_SUSPEND_MEM) { ++ unsigned int tmp; ++ unsigned int ddrc_ctrl; ++ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ++ /* save ddr low power state */ ++ sleep_param->pdt = ddrc_ctrl & DDRC_CTRL_PDT_MASK; ++ sleep_param->dpd = ddrc_ctrl & DDRC_CTRL_DPD; ++ sleep_param->dlp = ddr_readl(DDRC_DLP); ++ sleep_param->autorefresh = ddr_readl(DDRC_AUTOSR_EN); ++ ++ /* ddr disable deep power down */ ++ ddrc_ctrl &= ~(DDRC_CTRL_PDT_MASK); ++ ddrc_ctrl &= ~(DDRC_CTRL_DPD); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ ++ /* ddr diasble LPEN*/ ++ ddr_writel(0, DDRC_DLP); ++ ++ /* ddr disable auto-sr */ ++ ddr_writel(0, DDRC_AUTOSR_EN); ++ tmp = *(volatile unsigned int *)0xa0000000; ++ ++ ++ ++ /* DDR self refresh, */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= 1 << 5; ++ ddrc_ctrl &= ~(1 << 1); ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ while(!(ddr_readl(DDRC_STATUS) & (1<<2))); ++ while(!(REG32(DDRC_DWSTATUS) & (1<<4))); ++ ++#ifdef DDR_DEEP_SLEEP ++ /* bufferen_core = 0 */ ++ *(volatile unsigned int *)0xb3012000 |= (1 << 4); ++#endif ++ ++ /* dfi_init_start = 1 */ ++ *(volatile unsigned int *)0xb3012000 |= (1 << 3); ++ ++ { ++ int i; ++ for (i = 0; i < 4; i++) { ++ ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ } ++ } ++ ++#ifdef DDR_DEEP_SLEEP ++ /* disable pll */ ++ reg_ddr_phy(0x21) |= (1 << 1); ++#endif ++ } ++ ++ ++ TCSM_PCHAR('W'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "wait \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ ); ++ ++ TCSM_PCHAR('N'); ++ ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('?'); ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (SLEEP_CPU_RESUME_BOOTUP_TEXT) ++ : ++ ); ++ TCSM_PCHAR('F'); ++} ++ ++ ++int x2500_pm_enter(suspend_state_t state) ++{ ++ extern volatile u8 *uart_base; ++ ++ printk("x2500 pm enter!!\n"); ++ ++ sleep_param->uart_base = (unsigned int)uart_base; ++ ++ sleep_param->state = state; ++ ++#ifdef DEBUG_PM ++ printk("sleep_param->state addr = %d\n", sleep_param->state); ++#endif ++ ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_RESUME_BOOTUP_TEXT, (unsigned int *)cpu_resume_bootup, SLEEP_CPU_RESUME_BOOTUP_LEN); ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_RESUME_TEXT, (unsigned int *)cpu_resume, SLEEP_CPU_RESUME_LEN); ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_SLEEP_TEXT, (unsigned int *)cpu_sleep, SLEEP_CPU_SLEEP_LEN); ++ ++ if (state == PM_SUSPEND_STANDBY) { ++ soc_pm_idle(); ++ } else if (state == PM_SUSPEND_MEM) { ++ soc_pm_sleep(); ++ } else { ++ printk("WARNING : unsupport pm suspend state\n"); ++ } ++ ++ ++ /* set reset entry */ ++ *(volatile unsigned int *)0xb2200f00 = SLEEP_CPU_RESUME_BOOTUP_TEXT; ++ ++ ++#ifdef DEBUG_PM ++ printk("LCR: %08x\n", cpm_inl(CPM_LCR)); ++ printk("OPCR: %08x\n", cpm_inl(CPM_OPCR)); ++ x2500_pm_gate_check(); ++#endif ++ ++ mb(); ++ save_goto((unsigned int)SLEEP_CPU_SLEEP_TEXT); ++ mb(); ++ ++ soc_post_wakeup(); ++ ++ return 0; ++} ++ ++static int x2500_pm_begin(suspend_state_t state) ++{ ++ printk("x2500 suspend begin\n"); ++ return 0; ++} ++ ++static void x2500_pm_end(void) ++{ ++ printk("x2500 pm end!\n"); ++} ++ ++static int x2500_suspend_prepare(void) ++{ ++ printk("x2500 suspend prepare\n"); ++ return 0; ++} ++ ++static void x2500_suspend_finish(void) ++{ ++ printk("x2500 suspend finish\n"); ++} ++ ++static int ingenic_pm_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++static const struct platform_suspend_ops x2500_pm_ops = { ++ .valid = ingenic_pm_valid, ++ .begin = x2500_pm_begin, ++ .enter = x2500_pm_enter, ++ .end = x2500_pm_end, ++ .prepare = x2500_suspend_prepare, ++ .finish = x2500_suspend_finish, ++}; ++ ++/* ++ * Initialize suspend interface ++ */ ++static int __init pm_init(void) ++{ ++ ++ suspend_set_ops(&x2500_pm_ops); ++ ++ ++ return 0; ++} ++ ++late_initcall(pm_init); +diff --git a/arch/mips/xburst2/soc-x2500/pm.h b/arch/mips/xburst2/soc-x2500/pm.h +new file mode 100644 +index 000000000..b53f7dcd8 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/pm.h +@@ -0,0 +1,136 @@ ++ ++ ++ ++struct sleep_param { ++ suspend_state_t state; ++ unsigned int pdt; ++ unsigned int dpd; ++ unsigned int dlp; ++ unsigned int autorefresh; ++ unsigned int cpu_div; ++ unsigned int uart_base; ++}; ++ ++ ++/* ++ * ++ * |-----------------------| ++ * | | ++ * | | ++ * | RESUME_SP | ++ * | | ++ * |-----------------------| ++ * | | ++ * | PARAM | ++ * | | ++ * |-----------------------| ++ * | | ++ * | | ++ * | SLEEP_TEXT | ++ * | | ++ * | | ++ * |-----------------------| ++ * | | ++ * | | ++ * | RESUME_TEXT | ++ * | | ++ * | | ++ * |-----------------------| ++ * | | ++* | RESUME_BOOTU_TEXTP | ++ * | | ++ * |-----------------------| <------------ TCSM_START 0xb2400000 ++ * ++ */ ++ ++ ++#define SLEEP_MEMORY_START 0xb2400000 ++#define SLEEP_MEMORY_END 0xb2407ff8 ++#define SLEEP_RESUME_SP SLEEP_MEMORY_END ++#define SLEEP_RESUME_BOOTUP_TEXT SLEEP_MEMORY_START ++ ++#define SLEEP_CPU_RESUME_BOOTUP_TEXT SLEEP_RESUME_BOOTUP_TEXT ++#define SLEEP_CPU_RESUME_BOOTUP_LEN 64 // 16 instructions ++#define SLEEP_CPU_RESUME_TEXT (SLEEP_CPU_RESUME_BOOTUP_TEXT + SLEEP_CPU_RESUME_BOOTUP_LEN) ++#define SLEEP_CPU_RESUME_LEN (4096) ++#define SLEEP_CPU_SLEEP_TEXT (SLEEP_CPU_RESUME_TEXT + SLEEP_CPU_RESUME_LEN) ++#define SLEEP_CPU_SLEEP_LEN (3072) ++#define SLEEP_CPU_PARAM_ADDR (SLEEP_CPU_SLEEP_TEXT + SLEEP_CPU_SLEEP_LEN) ++#define SLEEP_CPU_PARAM_SIZE (sizeof(struct sleep_param)) ++#define SLEEP_CPU_RESUME_SP SLEEP_RESUME_SP ++ ++#define sleep_param ((struct sleep_param *)SLEEP_CPU_PARAM_ADDR) ++ ++ ++ ++extern long long save_goto(unsigned int func); ++extern int restore_goto(unsigned int func); ++ ++ ++#define reg_ddr_phy(x) (*(volatile unsigned int *)(0xb3011000 + ((x) << 2))) ++ ++#define rtc_read_reg(reg) ({ \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++ *(volatile unsigned int *)reg;\ ++}) ++ ++#define rtc_write_reg(reg, val) do{ \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++ *(volatile unsigned int *)0xb000303c = 0xa55a; \ ++ while (!((*(volatile unsigned int *)0xb000303c >> 31) & 0x1) ); \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++ *(volatile unsigned int *)reg = val; \ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); \ ++}while(0) ++ ++ ++ ++ ++/************************************************ ++ * debug interface ++ ***********************************************/ ++ ++#define DEBUG_PM ++#define PRINT_DEBUG ++ ++ ++#define U_IOBASE (sleep_param->uart_base) ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++ ++#ifdef PRINT_DEBUG ++#define TCSM_PCHAR(x) \ ++ *((volatile unsigned int*)(U_IOBASE+OFF_TDR)) = x; \ ++while ((*((volatile unsigned int*)(U_IOBASE + OFF_LSR)) & (LSR_TDRQ | LSR_TEMT)) != (LSR_TDRQ | LSR_TEMT)) ++#else ++#define TCSM_PCHAR(x) ++#endif ++ ++#define TCSM_DELAY(x) \ ++ do{ \ ++ register unsigned int i = x; \ ++ while(i--) \ ++ __asm__ volatile("nop\n\t"); \ ++ }while(0) ++ ++static inline void serial_put_hex(unsigned int x) { ++ int i; ++ unsigned int d; ++ for(i = 7;i >= 0;i--) { ++ d = (x >> (i * 4)) & 0xf; ++ if(d < 10) d += '0'; ++ else d += 'A' - 10; ++ TCSM_PCHAR(d); ++ } ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++} ++ ++ ++ ++ +diff --git a/arch/mips/xburst2/soc-x2500/pm_fastboot.c b/arch/mips/xburst2/soc-x2500/pm_fastboot.c +new file mode 100644 +index 000000000..53d44a4be +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/pm_fastboot.c +@@ -0,0 +1,667 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pm_fastboot.h" ++ ++ ++volatile unsigned int intc0_msk; ++volatile unsigned int intc1_msk; ++volatile unsigned int gpio_pb_int; ++volatile unsigned int gpio_pb_msk; ++volatile unsigned int gpio_pb_pat1; ++volatile unsigned int gpio_pb_pat0; ++volatile unsigned int gpio_pe_int; ++volatile unsigned int gpio_pe_msk; ++volatile unsigned int gpio_pe_pat1; ++volatile unsigned int gpio_pe_pat0; ++ ++volatile unsigned int clk_gate0; ++volatile unsigned int clk_gate1; ++ ++volatile unsigned int mem_pd0; ++volatile unsigned int mem_pd1; ++ ++#define g_state ((volatile suspend_state_t *)0xb0000bfc) ++volatile unsigned int _regs_stack_0[136 / 4]; ++volatile unsigned int _regs_stack_1[136 / 4]; ++volatile unsigned int *_regs_stack; ++ ++static inline void rtc_write_reg(unsigned int reg, unsigned int val) ++{ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ *(volatile unsigned int *)0xb000303c = 0xa55a; ++ while (!((*(volatile unsigned int *)0xb000303c >> 31) & 0x1) ); ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ ++ *(volatile unsigned int *)reg = val; ++ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++} ++ ++static inline unsigned int rtc_read_reg(unsigned int reg) ++{ ++ while (!((*(volatile unsigned int *)0xb0003000 >> 7) & 0x1) ); ++ ++ return *(volatile unsigned int *)reg; ++} ++ ++#define PRINT_DEBUG ++ ++ ++#ifdef PRINT_DEBUG ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++#define U_IOBASE (UART2_IOBASE + 0xa0000000) ++#define TCSM_PCHAR(x) \ ++ *((volatile unsigned int*)(U_IOBASE+OFF_TDR)) = x; \ ++while ((*((volatile unsigned int*)(U_IOBASE + OFF_LSR)) & (LSR_TDRQ | LSR_TEMT)) != (LSR_TDRQ | LSR_TEMT)) ++#else ++#define TCSM_PCHAR(x) ++#endif ++ ++#define TCSM_DELAY(x) \ ++ do{ \ ++ register unsigned int i = x; \ ++ while(i--) \ ++ __asm__ volatile(".set mips32\n\t" \ ++ "nop\n\t" \ ++ ".set mips32"); \ ++ }while(0) \ ++ ++static inline void serial_put_hex(unsigned int x) { ++ int i; ++ unsigned int d; ++ for(i = 7;i >= 0;i--) { ++ d = (x >> (i * 4)) & 0xf; ++ if(d < 10) d += '0'; ++ else d += 'A' - 10; ++ TCSM_PCHAR(d); ++ } ++ TCSM_PCHAR('\r'); ++ TCSM_PCHAR('\n'); ++} ++ ++#if 1 ++struct uart_regs { ++ unsigned int udllr; ++ unsigned int udlhr; ++ unsigned int uthr; ++ unsigned int uier; ++ unsigned int ufcr; ++ unsigned int ulcr; ++ unsigned int umcr; ++ unsigned int uspr; ++ unsigned int isr; ++ unsigned int umr; ++ unsigned int uacr; ++ unsigned int urcr; ++ unsigned int utcr; ++ ++}; ++ ++ ++static void uart_save(struct uart_regs *uart_regs) ++{ ++ printk("uart save\n"); ++ *(volatile unsigned int *)0xb003200c |= (1 << 7); ++ uart_regs->udllr = *(volatile unsigned int *)0xb0032000; ++ uart_regs->udlhr = *(volatile unsigned int *)0xb0032004; ++ ++ *(volatile unsigned int *)0xb003200c &= ~(1 << 7); ++ uart_regs->uthr = *(volatile unsigned int *)0xb0032000; ++ uart_regs->uier = *(volatile unsigned int *)0xb0032004; ++ ++ uart_regs->ufcr = *(volatile unsigned int *)0xb0032008; ++ uart_regs->ulcr = *(volatile unsigned int *)0xb003200c; ++ uart_regs->umcr = *(volatile unsigned int *)0xb0032010; ++ uart_regs->uspr = *(volatile unsigned int *)0xb003201c; ++ uart_regs->isr = *(volatile unsigned int *)0xb0032020; ++ uart_regs->umr = *(volatile unsigned int *)0xb0032024; ++ uart_regs->uacr = *(volatile unsigned int *)0xb0032028; ++ uart_regs->urcr = *(volatile unsigned int *)0xb0032040; ++ uart_regs->utcr = *(volatile unsigned int *)0xb0032044; ++ ++ printk("uthr = 0x%08x\n", uart_regs->uthr); ++ printk("uier = 0x%08x\n", uart_regs->uier); ++ printk("udllr = 0x%08x\n", uart_regs->udllr); ++ printk("udlhr = 0x%08x\n", uart_regs->udlhr); ++ printk("ULCR = 0x%08x\n", *(volatile unsigned int *)0xb003200c); ++ printk("UMCR = 0x%08x\n", *(volatile unsigned int *)0xb0032010); ++ printk("ULSR = 0x%08x\n", *(volatile unsigned int *)0xb0032014); ++ printk("UMSR = 0x%08x\n", *(volatile unsigned int *)0xb0032018); ++ printk("USPR = 0x%08x\n", *(volatile unsigned int *)0xb003201c); ++ printk("ISR = 0x%08x\n", *(volatile unsigned int *)0xb0032020); ++ printk("UMR = 0x%08x\n", *(volatile unsigned int *)0xb0032024); ++ printk("UACR = 0x%08x\n", *(volatile unsigned int *)0xb0032028); ++ printk("URCR = 0x%08x\n", *(volatile unsigned int *)0xb0032040); ++ printk("UTCR = 0x%08x\n", *(volatile unsigned int *)0xb0032044); ++ ++ ++} ++ ++static void uart_set_baud(struct uart_regs *uart_regs) ++{ ++ *(volatile unsigned int *)0xb0032024 = uart_regs->umr; ++ *(volatile unsigned int *)0xb0032028 = uart_regs->uacr; ++ ++ *(volatile unsigned int *)0xb003200c |= (1 << 7); ++ *(volatile unsigned int *)0xb0032000 = uart_regs->udllr; ++ *(volatile unsigned int *)0xb0032004 = uart_regs->udlhr; ++ *(volatile unsigned int *)0xb003200c &= ~(1 << 7); ++ ++} ++ ++ ++static void uart_restore(struct uart_regs *uart_regs) ++{ ++ ++ *(volatile unsigned int *)0xb0000020 &= ~(1 << 16); ++ ++ /*uart2 PD30 PD31 func0 */ ++ *(volatile unsigned int *)0xb0010318 |= (3 << 30); ++ *(volatile unsigned int *)0xb0010328 |= (3 << 30); ++ *(volatile unsigned int *)0xb0010338 |= (3 << 30); ++ *(volatile unsigned int *)0xb0010348 |= (3 << 30); ++ ++ ++ *(volatile unsigned int *)0xb0032008 = uart_regs->ufcr; ++ *(volatile unsigned int *)0xb003200c = uart_regs->ulcr; ++ *(volatile unsigned int *)0xb0032010 = uart_regs->umcr; ++ *(volatile unsigned int *)0xb003201c = uart_regs->uspr; ++ *(volatile unsigned int *)0xb0032020 = uart_regs->isr; ++ *(volatile unsigned int *)0xb0032024 = uart_regs->umr; ++ *(volatile unsigned int *)0xb0032028 = uart_regs->uacr; ++ *(volatile unsigned int *)0xb0032040 = uart_regs->urcr; ++ *(volatile unsigned int *)0xb0032044 = uart_regs->utcr; ++ ++ uart_set_baud(uart_regs); ++ ++ *(volatile unsigned int *)0xb0032008 = (1 << 4) | (1 << 0) | (1 << 1) | (1 << 2); ++ ++} ++#endif ++ ++struct ost_regs { ++ unsigned int ostccr; ++ unsigned int oster; ++ unsigned int ostcr; ++ unsigned int ostfr; ++ unsigned int ostmr; ++ unsigned int ostdfr; ++ unsigned int ostcnt; ++ ++ unsigned int g_ostccr; ++ unsigned int g_oster; ++ unsigned int g_ostcr; ++ unsigned int g_ostcnth; ++ unsigned int g_ostcntl; ++ unsigned int g_ostcntb; ++}; ++ ++static void ost_save(struct ost_regs *ost_regs) ++{ ++ ost_regs->ostccr = *(volatile unsigned int *)0xb2100000; ++ ost_regs->oster = *(volatile unsigned int *)0xb2100004; ++ ost_regs->ostcr = *(volatile unsigned int *)0xb2100008; ++ ost_regs->ostfr = *(volatile unsigned int *)0xb210000c; ++ ost_regs->ostmr = *(volatile unsigned int *)0xb2100010; ++ ost_regs->ostdfr = *(volatile unsigned int *)0xb2100014; ++ ost_regs->ostcnt = *(volatile unsigned int *)0xb2100018; ++ ++ ost_regs->g_ostccr = *(volatile unsigned int *)0xb2000000; ++ ost_regs->g_oster = *(volatile unsigned int *)0xb2000004; ++ ost_regs->g_ostcr = *(volatile unsigned int *)0xb2000008; ++ ost_regs->g_ostcnth = *(volatile unsigned int *)0xb200000c; ++ ost_regs->g_ostcntl = *(volatile unsigned int *)0xb2000010; ++ ost_regs->g_ostcntb = *(volatile unsigned int *)0xb2000014; ++ ++} ++ ++static void ost_restore(struct ost_regs *ost_regs) ++{ ++ *(volatile unsigned int *)0xb2100000 = ost_regs->ostccr; ++ *(volatile unsigned int *)0xb2100008 = ost_regs->ostcr; ++ *(volatile unsigned int *)0xb210000c = ost_regs->ostfr; ++ *(volatile unsigned int *)0xb2100010 = ost_regs->ostmr; ++ *(volatile unsigned int *)0xb2100014 = ost_regs->ostdfr; ++ *(volatile unsigned int *)0xb2100018 = ost_regs->ostcnt; ++ *(volatile unsigned int *)0xb2100004 = ost_regs->oster; ++ ++ *(volatile unsigned int *)0xb2000000 = ost_regs->g_ostccr; ++ *(volatile unsigned int *)0xb2000008 = ost_regs->g_ostcr; ++ *(volatile unsigned int *)0xb2000004 = ost_regs->g_oster; ++ ++} ++ ++static noinline void cpu_resume(void); ++ ++ ++static void rtc_ram_write_enable(void) ++{ ++ unsigned int tmp; ++ ++ /* write RTC RAM enable */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp &= ~(1 << 23); ++ tmp &= ~(1 << 22); ++ tmp |= (1 << 21); ++ tmp |= (1 << 20); ++ rtc_write_reg(0xb0003048, tmp); ++ ++} ++ ++static void rtc_ram_write_disable(void) ++{ ++ unsigned int tmp; ++ ++ /*exit write RTC RAM enable */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp |= (1 << 22); ++ rtc_write_reg(0xb0003048, tmp); ++ ++} ++ ++ ++static void soc_pm_fastboot(void) ++{ ++ ++ unsigned int tmp; ++ ++ clk_gate0 = cpm_inl(CPM_CLKGR); ++ clk_gate1 = cpm_inl(CPM_CLKGR1); ++ ++ clk_gate0 |= 1 << 20; // disable ost ++ clk_gate0 &= ~(1 << 28); // enable apb0 ++ clk_gate0 &= ~(1 << 27); //enable rtc ++ ++ cpm_outl(clk_gate0, CPM_CLKGR); ++ ++ printk("clk_gate0: 0x%08x, clk_gate1: 0x%08x\n", clk_gate0, clk_gate1); ++ ++ ++ ++ intc1_msk = *(volatile unsigned int *)0xb0001024; ++ *(volatile unsigned int *)0xb0001024 = intc1_msk & ~(1<<0); // RTC INT MSK ++ ++ /* RTC EALM */ ++ tmp = rtc_read_reg(0xb000302c); ++ tmp |= 1; ++ rtc_write_reg(0xb000302c, tmp); ++ ++ /* RTC enable AE */ ++ tmp = rtc_read_reg(0xb0003000); ++ tmp |= (1 << 2) | (1 << 0); ++ rtc_write_reg(0xb0003000, tmp); ++ ++ /* 32k rtc clk */ ++ tmp = rtc_read_reg(0xb0003000); ++ tmp &= ~(1 << 1); ++ rtc_write_reg(0xb0003000, tmp); ++} ++ ++static int soc_post_wakeup(void) ++{ ++ ++ clk_gate0 &= ~(1 << 20); //enable ost ++ cpm_outl(clk_gate0, CPM_CLKGR); ++ cpm_outl(clk_gate1, CPM_CLKGR1); ++ ++ ++ return 0; ++} ++ ++ ++ ++ ++ ++static struct store_regs *store_regs; ++ ++static void save_resume_pc(void) ++{ ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ store_regs->resume_pc = (unsigned int)cpu_resume; ++ printk("xxxxxxxxxxxxxxxxxxx save resume_pc = 0x%08x\n", store_regs->resume_pc); ++} ++static void pll_store(void) ++{ ++ struct pll_resume_reg *pll_resume_reg; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ pll_resume_reg = &store_regs->pll_resume_reg; ++ ++ pll_resume_reg->cpccr = *(volatile unsigned int *)0xb0000000; ++ pll_resume_reg->cppcr = *(volatile unsigned int *)0xb000000c; ++ pll_resume_reg->cpapcr = *(volatile unsigned int *)0xb0000010; ++ pll_resume_reg->cpmpcr = *(volatile unsigned int *)0xb0000014; ++ pll_resume_reg->cpepcr = *(volatile unsigned int *)0xb0000018; ++ pll_resume_reg->ddrcdr = *(volatile unsigned int *)0xb000002c; ++ ++} ++ ++static void ddrc_store(void) ++{ ++ struct ddrc_resume_reg *ddrc_resume_reg; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ ddrc_resume_reg = &store_regs->ddrc_resume_reg; ++ ++ ddrc_resume_reg->dcfg = *(volatile unsigned int *)0xb34f0008; ++ ddrc_resume_reg->dctrl = *(volatile unsigned int *)0xb34f0010; ++ ddrc_resume_reg->dlmr = *(volatile unsigned int *)0xb34f0018; ++ ddrc_resume_reg->ddlp = *(volatile unsigned int *)0xb34f0020; ++ ddrc_resume_reg->dasr_en = *(volatile unsigned int *)0xb34f0030; ++ ddrc_resume_reg->dasr_cnt = *(volatile unsigned int *)0xb34f0028; ++ ddrc_resume_reg->drefcnt = *(volatile unsigned int *)0xb34f0038; ++ ddrc_resume_reg->dtimming1 = *(volatile unsigned int *)0xb34f0040; ++ ddrc_resume_reg->dtimming2 = *(volatile unsigned int *)0xb34f0048; ++ ddrc_resume_reg->dtimming3 = *(volatile unsigned int *)0xb34f0050; ++ ddrc_resume_reg->dtimming4 = *(volatile unsigned int *)0xb34f0058; ++ ddrc_resume_reg->dtimming5 = *(volatile unsigned int *)0xb34f0060; ++ ddrc_resume_reg->dmmap0 = *(volatile unsigned int *)0xb34f0078; ++ ddrc_resume_reg->dmmap1 = *(volatile unsigned int *)0xb34f0080; ++ ddrc_resume_reg->dwcfg = *(volatile unsigned int *)0xb3012000; ++ ddrc_resume_reg->dremap1 = *(volatile unsigned int *)0xb3012008; ++ ddrc_resume_reg->dremap2 = *(volatile unsigned int *)0xb301200c; ++ ddrc_resume_reg->dremap3 = *(volatile unsigned int *)0xb3012010; ++ ddrc_resume_reg->dremap4 = *(volatile unsigned int *)0xb3012014; ++ ddrc_resume_reg->dremap5 = *(volatile unsigned int *)0xb3012018; ++ ddrc_resume_reg->ccguc0 = *(volatile unsigned int *)0xb3012064; ++ ddrc_resume_reg->ccguc1 = *(volatile unsigned int *)0xb3012068; ++ ++} ++ ++static void ddr_phy_store(void) ++{ ++ struct ddr_phy_resume_reg *ddr_phy_resume_reg; ++ ++ store_regs = (struct store_regs *)RTC_RAM_DATA_ADDR; ++ ddr_phy_resume_reg = &store_regs->ddr_phy_resume_reg; ++ ++ ddr_phy_resume_reg->mem_cfg = *(volatile unsigned int *)0xb3011004; ++ ddr_phy_resume_reg->dq_width = *(volatile unsigned int *)0xb301107c; ++ ddr_phy_resume_reg->cl = *(volatile unsigned int *)0xb3011014; ++ ddr_phy_resume_reg->al = *(volatile unsigned int *)0xb3011018; ++ ddr_phy_resume_reg->cwl = *(volatile unsigned int *)0xb301101c; ++ ddr_phy_resume_reg->pll_fbdiv = *(volatile unsigned int *)0xb3011080; ++ ddr_phy_resume_reg->pll_ctrl = *(volatile unsigned int *)0xb3011084; ++ ddr_phy_resume_reg->pll_pdiv = *(volatile unsigned int *)0xb3011088; ++ ddr_phy_resume_reg->training_ctrl = *(volatile unsigned int *)0xb3011008; ++ ddr_phy_resume_reg->calib_bypass_al = *(volatile unsigned int *)0xb3011118; ++ ddr_phy_resume_reg->calib_bypass_ah = *(volatile unsigned int *)0xb3011158; ++ ddr_phy_resume_reg->wl_mode1 = *(volatile unsigned int *)0xb301100c; ++ ddr_phy_resume_reg->wl_mode2 = *(volatile unsigned int *)0xb3011010; ++} ++ ++static void rtc_ram_store(void) ++{ ++ pll_store(); ++ ddrc_store(); ++ ddr_phy_store(); ++ save_resume_pc(); ++} ++ ++ ++static int fastboot_resume_code[] = { ++ ++#include "fastboot_resume_code.hex" ++ ++}; ++ ++ ++ ++ ++ ++ ++extern long long save_goto(unsigned int); ++extern int restore_goto(void); ++ ++ ++ ++static noinline void cpu_resume(void) ++{ ++ ++ unsigned int cpu_id; ++ ++ ++ cpu_id = read_c0_ebase() & 0x3ff; ++ ++ if (cpu_id == 0) { ++ _regs_stack = _regs_stack_0; ++ } else if (cpu_id == 1) { ++ _regs_stack = _regs_stack_1; ++ } ++ ++ *(volatile unsigned int *)0xb2200f00 = 0xbfc00000; /* RESET entry = 0xbfc00000 ,reset value */ ++ ++ __asm__ volatile( ++ ".set push \n\t" ++ ".set mips32r2 \n\t" ++ "jr.hb %0 \n\t" ++ "nop \n\t" ++ ".set pop \n\t" ++ : ++ : "r" (restore_goto) ++ : ++ ); ++} ++ ++ ++ ++ ++#define jump() do{ \ ++ void (*func)(void); \ ++ func = (void(*)(void)) 0xb0004000; \ ++ func(); \ ++ }while(0) ++ ++#if 0 ++static void ddrp_auto_calibration(void) ++{ ++ unsigned int reg_val = ddr_readl(DDRP_INNOPHY_TRAINING_CTRL); ++ unsigned int timeout = 0xffffff; ++ unsigned int wait_cal_done = DDRP_CALIB_DONE_HDQCFA | DDRP_CALIB_DONE_LDQCFA; ++ ++ reg_val &= ~(DDRP_TRAINING_CTRL_DSCSE_BP); ++ reg_val |= DDRP_TRAINING_CTRL_DSACE_START; ++ ddr_writel(reg_val, DDRP_INNOPHY_TRAINING_CTRL); ++ ++ while(!((ddr_readl(DDRP_INNOPHY_CALIB_DONE) & wait_cal_done) == wait_cal_done) && --timeout) { ++ TCSM_PCHAR('t'); ++ serial_put_hex(*(volatile unsigned int *)(0x80015060 + 0 * 4)); ++ serial_put_hex(*(volatile unsigned int *)(0x80015060 + 1 * 4)); ++ serial_put_hex(*(volatile unsigned int *)(0x80015060 + 2 * 4)); ++ serial_put_hex(*(volatile unsigned int *)(0x80015060 + 3 * 4)); ++ } ++ ++ if(!timeout) { ++ TCSM_PCHAR('f'); ++ } ++ ddr_writel(0, DDRP_INNOPHY_TRAINING_CTRL); ++} ++#endif ++ ++ ++static noinline void cpu_sleep(void) ++{ ++ ++ ++ unsigned int tmp; ++ unsigned int ddrc_ctrl; ++ ++ blast_dcache32(); ++ blast_scache64(); ++ __sync(); ++ __fast_iob(); ++ ++ ddr_writel(0, DDRC_AUTOSR_EN); ++ tmp = *(volatile unsigned int *)0xa0000000; ++ ++ ++ /* DDR self refresh, */ ++ ddrc_ctrl = ddr_readl(DDRC_CTRL); ++ ddrc_ctrl |= 1 << 5; ++ ddr_writel(ddrc_ctrl, DDRC_CTRL); ++ while(!(ddr_readl(DDRC_STATUS) & (1<<2))); ++ ++ /* bufferen_core = 0 */ ++ tmp = rtc_read_reg(0xb0003048); ++ tmp &= ~(1 << 21); ++ rtc_write_reg(0xb0003048, tmp); ++ ++ /* dfi_init_start = 1 */ ++ *(volatile unsigned int *)0xb3012000 |= (1 << 3); ++ ++ ++ { ++ int i; ++ for (i = 0; i < 4; i++) { ++ ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ __asm__ volatile("ssnop\t\n"); ++ } ++ } ++ /* ddr phy pll power down */ ++ *(volatile unsigned int *)0xb3011084 |= (1 << 1); ++ ++ ++ ++ TCSM_PCHAR('o'); ++ ++ ++ /* rtc disable power detect */ ++ rtc_write_reg(0xb000302c, (0x1a55a5a5 << 3) | 1); ++ /* RTC PD */ ++ rtc_write_reg(0xb0003020, 1); ++ ++ ++ while (1); ++} ++ ++ ++ ++static void load_func_to_tcsm(unsigned int *tcsm_addr,unsigned int *f_addr,unsigned int size) ++{ ++ unsigned int instr; ++ int offset; ++ int i; ++#ifdef DEBUG_PM ++ printk("tcsm addr = %p %p size = %d\n",tcsm_addr,f_addr,size); ++#endif ++ for(i = 0;i < size / 4;i++) { ++ instr = f_addr[i]; ++ if((instr >> 26) == 2){ ++ offset = instr & 0x3ffffff; ++ offset = (offset << 2) - ((unsigned int)f_addr & 0xfffffff); ++ if(offset > 0) { ++ offset = ((unsigned int)tcsm_addr & 0xfffffff) + offset; ++ instr = (2 << 26) | (offset >> 2); ++ } ++ } ++ tcsm_addr[i] = instr; ++ } ++} ++ ++ ++static int x2000_pm_enter(suspend_state_t state) ++{ ++ unsigned int cpu_id; ++ struct uart_regs *uart_regs; ++ struct ost_regs *ost_regs; ++ ++ uart_regs = kmalloc(sizeof(struct uart_regs), GFP_KERNEL); ++ ost_regs = kmalloc(sizeof(struct ost_regs), GFP_KERNEL); ++ soc_pm_fastboot(); ++ ++ load_func_to_tcsm((unsigned int *)SLEEP_CPU_SLEEP_TEXT, (unsigned int *)cpu_sleep, SLEEP_CPU_SLEEP_LEN); ++ ++ rtc_ram_write_enable(); ++ rtc_ram_store(); ++ memcpy((unsigned int *)RTC_RAM_CODE_ADDR1, (unsigned int *)fastboot_resume_code, RTC_RAM_CODE_SIZE); ++ rtc_ram_write_disable(); ++ ++ uart_save(uart_regs); ++ ost_save(ost_regs); ++ ++ cpu_id = read_c0_ebase() & 0x3ff; ++ ++ printk("cpu_id = %d\n", cpu_id); ++ ++ if (cpu_id == 0) { ++ _regs_stack = _regs_stack_0; ++ } else if (cpu_id == 1) { ++ _regs_stack = _regs_stack_1; ++ } ++ ++ ++ mb(); ++ save_goto((unsigned int)SLEEP_CPU_SLEEP_TEXT); ++ mb(); ++ ++ ++ soc_post_wakeup(); ++ ++ ost_restore(ost_regs); ++ uart_restore(uart_regs); ++ set_ccu_mimr(1 << 0); ++ ++ ++ return 0; ++} ++ ++static int x2000_pm_begin(suspend_state_t state) ++{ ++ printk("x2000 suspend begin\n"); ++ ++ return 0; ++} ++ ++static void x2000_pm_end(void) ++{ ++ printk("x2000 pm end!\n"); ++ ++} ++ ++static const struct platform_suspend_ops x2000_pm_ops = { ++ .valid = suspend_valid_only_mem, ++ .begin = x2000_pm_begin, ++ .enter = x2000_pm_enter, ++ .end = x2000_pm_end, ++}; ++ ++/* ++ * Initialize suspend interface ++ */ ++static int __init pm_init(void) ++{ ++ ++ suspend_set_ops(&x2000_pm_ops); ++ ++ return 0; ++} ++ ++arch_initcall(pm_init); +diff --git a/arch/mips/xburst2/soc-x2500/pm_fastboot.h b/arch/mips/xburst2/soc-x2500/pm_fastboot.h +new file mode 100644 +index 000000000..3bad4d885 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/pm_fastboot.h +@@ -0,0 +1,106 @@ ++ ++ ++#define RTC_SLEEP_MEMORY_START 0xb0004000 ++#define RTC_SLEEP_MEMORY_END 0xb0005000 ++#define RTC_RAM_SP_ADDR (RTC_RAM_DATA_ADDR - 4) ++//#define RTC_RAM_SP_SIZE (256 - 4) ++#define RTC_RAM_DATA_ADDR 0xb0004c00 ++#define RTC_RAM_DATA_SIZE 1024 ++#define RTC_RAM_CODE_ADDR1 0xb0004000 ++#define RTC_RAM_CODE_ADDR2 (RTC_RAM_CODE_ADDR1 + 64) ++#define RTC_RAM_CODE_SIZE 0xb00 ++ ++#define SLEEP_CPU_SLEEP_TEXT 0xb2400000 ++#define SLEEP_CPU_SLEEP_LEN 4096 ++ ++ ++ ++struct pll_resume_reg { ++ unsigned int cpccr; ++ unsigned int cppcr; ++ unsigned int cpapcr; ++ unsigned int cpmpcr; ++ unsigned int cpepcr; ++ unsigned int ddrcdr; ++}; ++ ++struct ddrc_resume_reg { ++ unsigned int dcfg; ++ unsigned int dctrl; ++ unsigned int dlmr; ++ unsigned int ddlp; ++ unsigned int dasr_en; ++ unsigned int dasr_cnt; ++ unsigned int drefcnt; ++ unsigned int dtimming1; ++ unsigned int dtimming2; ++ unsigned int dtimming3; ++ unsigned int dtimming4; ++ unsigned int dtimming5; ++ unsigned int dmmap0; ++ unsigned int dmmap1; ++#if 0 ++ unsigned int dbwcfg; ++ unsigned int dbwstp; ++ unsigned int hregpro; ++ unsigned int dbgen; ++#endif ++ unsigned int dwcfg; ++ unsigned int dremap1; ++ unsigned int dremap2; ++ unsigned int dremap3; ++ unsigned int dremap4; ++ unsigned int dremap5; ++#if 0 ++ unsigned int cpac; ++ unsigned int cchc0; ++ unsigned int cchc1; ++ unsigned int cchc2; ++ unsigned int cchc3; ++ unsigned int cchc4; ++ unsigned int cchc5; ++ unsigned int cchc6; ++ unsigned int cchc7; ++ unsigned int cschc0; ++ unsigned int cschc1; ++ unsigned int cschc2; ++ unsigned int cschc3; ++ unsigned int cmonc0; ++ unsigned int cmonc1; ++ unsigned int cmonc2; ++ unsigned int cmonc3; ++ unsigned int cmonc4; ++#endif ++ unsigned int ccguc0; ++ unsigned int ccguc1; ++#if 0 ++ unsigned int pregpro; ++ unsigned int bufcfg; ++#endif ++}; ++ ++struct ddr_phy_resume_reg { ++ unsigned int phy_rst; ++ unsigned int mem_cfg; ++ unsigned int dq_width; ++ unsigned int cl; ++ unsigned int al; ++ unsigned int cwl; ++ unsigned int pll_fbdiv; ++ unsigned int pll_ctrl; ++ unsigned int pll_pdiv; ++ unsigned int training_ctrl; ++ unsigned int calib_bypass_al; ++ unsigned int calib_bypass_ah; ++ unsigned int wl_mode1; ++ unsigned int wl_mode2; ++ ++}; ++ ++struct store_regs { ++ unsigned int resume_pc; ++ struct pll_resume_reg pll_resume_reg; ++ struct ddrc_resume_reg ddrc_resume_reg; ++ struct ddr_phy_resume_reg ddr_phy_resume_reg; ++}; ++ +diff --git a/arch/mips/xburst2/soc-x2500/regs_save_restore.S b/arch/mips/xburst2/soc-x2500/regs_save_restore.S +new file mode 100644 +index 000000000..abe8b49df +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/regs_save_restore.S +@@ -0,0 +1,190 @@ ++#include ++#include ++ ++#define CP0_PAGEMASK $5,0 ++#define CP0_STATUS $12,0 ++#define CP0_INTCTL $12,1 ++#define CP0_CAUSE $13,0 ++#define CP0_EBASE $15,1 ++#define CP0_CONFIG $16,0 ++#define CP0_CONFIG1 $16,1 ++#define CP0_CONFIG2 $16,2 ++#define CP0_CONFIG3 $16,3 ++#define CP0_CONFIG4 $16,4 ++#define CP0_CONFIG5 $16,5 ++#define CP0_CONFIG7 $16,7 ++#define CP0_LLADDR $17,0 ++#define CP0_WATCHLo $18,0 ++#define CP0_WATCHHI $19,0 ++#define CP0_ERRCTL $26,0 ++#define CP0_CONTEXT $4,0 ++#define CP0_KSCRATCH1 $31,2 ++#define CP0_KSCRATCH2 $31,3 ++#define CP0_KSCRATCH3 $31,4 ++#define CP0_KSCRATCH4 $31,5 ++#define CP0_KSCRATCH5 $31,6 ++#define CP0_KSCRATCH6 $31,7 ++ ++ .data ++ .global _regs_stack ++_regs_stack: ++ .align 5 ++ .space 140,0 ++ ++ .text ++ .global save_goto ++ .align 2 ++ .ent save_goto,0 ++ LEAF(save_goto) ++save_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ sw s0,0(k0) ++ sw s1,4(k0) ++ sw s2,8(k0) ++ sw s3,12(k0) ++ sw s4,16(k0) ++ sw s5,20(k0) ++ sw s6,24(k0) ++ sw s7,28(k0) ++ sw gp,32(k0) ++ sw sp,36(k0) ++ sw fp,40(k0) ++ sw ra,44(k0) ++ ++ mfc0 k1,CP0_PAGEMASK ++ sw k1,48(k0) ++ mfc0 k1,CP0_STATUS ++ sw k1,52(k0) ++ mfc0 k1,CP0_INTCTL ++ sw k1,56(k0) ++ mfc0 k1,CP0_CAUSE ++ sw k1,60(k0) ++ mfc0 k1,CP0_EBASE ++ sw k1,64(k0) ++ mfc0 k1,CP0_CONFIG ++ sw k1,68(k0) ++ mfc0 k1,CP0_CONFIG1 ++ sw k1,72(k0) ++ mfc0 k1,CP0_CONFIG2 ++ sw k1,76(k0) ++ mfc0 k1,CP0_CONFIG3 ++ sw k1,80(k0) ++ mfc0 k1,CP0_CONFIG4 ++ sw k1,84(k0) ++ mfc0 k1,CP0_CONFIG5 ++ sw k1,88(k0) ++ mfc0 k1,CP0_CONFIG7 ++ sw k1,92(k0) ++ mfc0 k1,CP0_LLADDR ++ sw k1,96(k0) ++ mfc0 k1,CP0_WATCHLo ++ sw k1,100(k0) ++ mfc0 k1,CP0_WATCHHI ++ sw k1,104(k0) ++ mfc0 k1,CP0_ERRCTL ++ sw k1,108(k0) ++ mfc0 k1,CP0_CONTEXT ++ sw k1,112(k0) ++ mfc0 k1,CP0_KSCRATCH1 ++ sw k1,116(k0) ++ mfc0 k1,CP0_KSCRATCH2 ++ sw k1,120(k0) ++ mfc0 k1,CP0_KSCRATCH3 ++ sw k1,124(k0) ++ mfc0 k1,CP0_KSCRATCH4 ++ sw k1,128(k0) ++ mfc0 k1,CP0_KSCRATCH5 ++ sw k1,132(k0) ++ mfc0 k1,CP0_KSCRATCH6 ++ sw k1,136(k0) ++ ++ jr.hb a0 ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(save_goto) ++ ++ .text ++ .global restore_goto ++ .align 2 ++ .ent restore_goto,0 ++ LEAF(restore_goto) ++restore_goto: ++ .set push ++ .set noreorder ++ .set noat ++ ++ la k0, _regs_stack ++ lw s0,0(k0) ++ lw s1,4(k0) ++ lw s2,8(k0) ++ lw s3,12(k0) ++ lw s4,16(k0) ++ lw s5,20(k0) ++ lw s6,24(k0) ++ lw s7,28(k0) ++ lw gp,32(k0) ++ lw sp,36(k0) ++ lw fp,40(k0) ++ lw ra,44(k0) ++ ++ lw k1,48(k0) ++ mtc0 k1,CP0_PAGEMASK ++ lw k1,52(k0) ++ mtc0 k1,CP0_STATUS ++ lw k1,56(k0) ++ mtc0 k1,CP0_INTCTL ++ lw k1,60(k0) ++ mtc0 k1,CP0_CAUSE ++ lw k1,64(k0) ++ mtc0 k1,CP0_EBASE ++ lw k1,68(k0) ++ mtc0 k1,CP0_CONFIG ++ lw k1,72(k0) ++ mtc0 k1,CP0_CONFIG1 ++ lw k1,76(k0) ++ mtc0 k1,CP0_CONFIG2 ++ lw k1,80(k0) ++ mtc0 k1,CP0_CONFIG3 ++ lw k1,84(k0) ++ mtc0 k1,CP0_CONFIG4 ++ lw k1,88(k0) ++ mtc0 k1,CP0_CONFIG5 ++ lw k1,92(k0) ++ mtc0 k1,CP0_CONFIG7 ++ lw k1,96(k0) ++ mtc0 k1,CP0_LLADDR ++ lw k1,100(k0) ++ mtc0 k1,CP0_WATCHLo ++ lw k1,104(k0) ++ mtc0 k1,CP0_WATCHHI ++ lw k1,108(k0) ++ mtc0 k1,CP0_ERRCTL ++ lw k1,112(k0) ++ mtc0 k1,CP0_CONTEXT ++ lw k1,116(k0) ++ mtc0 k1,CP0_KSCRATCH1 ++ lw k1,120(k0) ++ mtc0 k1,CP0_KSCRATCH2 ++ lw k1,124(k0) ++ mtc0 k1,CP0_KSCRATCH3 ++ lw k1,128(k0) ++ mtc0 k1,CP0_KSCRATCH4 ++ lw k1,132(k0) ++ mtc0 k1,CP0_KSCRATCH5 ++ lw k1,136(k0) ++ mtc0 k1,CP0_KSCRATCH6 ++ ++ jr.hb ra ++ nop ++ ++ .set at ++ .set reorder ++ .set pop ++ END(restore_goto) +diff --git a/arch/mips/xburst2/soc-x2500/regs_save_restore.py b/arch/mips/xburst2/soc-x2500/regs_save_restore.py +new file mode 100755 +index 000000000..8a23de0d0 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/regs_save_restore.py +@@ -0,0 +1,124 @@ ++#!/usr/bin/env python ++import os ++import string ++ ++common_regs=["s0","s1","s2","s3", ++ "s4","s5","s6","s7", ++ "gp","sp","fp","ra"] ++cp0_regs=[ ++ ["CP0_PAGEMASK","$5","0"], ++ ["CP0_STATUS","$12","0"], ++ ["CP0_INTCTL","$12","1"], ++ ["CP0_CAUSE","$13","0"], ++ ["CP0_EBASE","$15","1"], ++ ["CP0_CONFIG","$16","0"], ++ ["CP0_CONFIG1","$16","1"], ++ ["CP0_CONFIG2","$16","2"], ++ ["CP0_CONFIG3","$16","3"], ++ ["CP0_CONFIG4", "$16", "4"], ++ ["CP0_CONFIG5", "$16", "5"], ++ ["CP0_CONFIG7", "$16", "7"], ++ ["CP0_LLADDR","$17","0"], ++ ["CP0_WATCHLo","$18","0"], ++ ["CP0_WATCHHI","$19","0"], ++ ["CP0_ERRCTL","$26","0"], ++ ["CP0_CONTEXT","$4","0"], ++ ["CP0_KSCRATCH1","$31","2"], ++ ["CP0_KSCRATCH2","$31","3"], ++ ["CP0_KSCRATCH3","$31","4"], ++ ["CP0_KSCRATCH4","$31","5"], ++ ["CP0_KSCRATCH5","$31","6"], ++ ["CP0_KSCRATCH6","$31","7"], ++ ] ++def gen_get_array_size(): ++ size=0 ++ size+=len(common_regs) ++ size+=len(cp0_regs) ++ return size ++ ++def gen_print_head_and_macro(): ++ print("#include ") ++ print("#include ") ++ print("") ++ for s in cp0_regs: ++ print("#define %s\t%s,%s" %(s[0],s[1],s[2])) ++ print("") ++def gen_define_global_arg(str, num): ++ print("\t.data") ++ print("\t.global %s" %(str)) ++ print("%s:" %(str)) ++ print("\t.align 5") ++ print("\t.space %s,0" %(num)) ++ print("") ++ ++def gen_save_common_regs(index): ++ for s in common_regs: ++ print("\tsw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_restore_common_regs(index): ++ for s in common_regs: ++ print("\tlw\t%s,%d(k0)" % (s,index)) ++ index=index+4 ++ return index ++def gen_save_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tmfc0\tk1,%s" % (s[0])) ++ print("\tsw\tk1,%d(k0)" % (index)) ++ index=index+4 ++ return index ++def gen_restore_cp0_regs(index): ++ for s in cp0_regs: ++ print("\tlw\tk1,%d(k0)" % (index)) ++ print("\tmtc0\tk1,%s" % (s[0])) ++ index=index+4 ++ return index ++def gen_print_function(f_name, regs_stack): ++ index=0 ++ print("\t.text") ++ print("\t.global %s" %(f_name)) ++ print("\t.align 2") ++ print("\t.ent %s,0" %(f_name)) ++ print("\tLEAF(%s)" %(f_name)) ++ print("%s:" %(f_name)) ++ print("\t.set\tpush") ++ print("\t.set\tnoreorder") ++ print("\t.set\tnoat") ++ print("") ++ print("\tla\tk0, %s" %(regs_stack)) ++ if f_name == "save_goto": ++ index = gen_save_common_regs(index) ++ print("") ++ index = gen_save_cp0_regs(index) ++ print("") ++ print("\tjr.hb\ta0") ++ print("\tnop") ++ elif f_name == "restore_goto": ++ index = gen_restore_common_regs(index) ++ print("") ++ index = gen_restore_cp0_regs(index) ++ print("") ++ print("\tjr.hb\tra") ++ print("\tnop") ++ else: ++ print("not support") ++ print("") ++ print("\t.set\tat") ++ print("\t.set\treorder") ++ print("\t.set\tpop") ++ print("\tEND(%s)" %(f_name)) ++ ++ ++def main(): ++ regs_size=gen_get_array_size() ++ regs_size*=4 ++ ++ gen_print_head_and_macro() ++ gen_define_global_arg("_regs_stack", regs_size) ++ gen_print_function("save_goto", "_regs_stack") ++ print("") ++ gen_print_function("restore_goto", "_regs_stack") ++ pass ++ ++if __name__ == '__main__': ++ main() +diff --git a/arch/mips/xburst2/soc-x2500/reset.c b/arch/mips/xburst2/soc-x2500/reset.c +new file mode 100644 +index 000000000..52a2a16a9 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/reset.c +@@ -0,0 +1,331 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#define RTC_RTCCR (0x00) /* rw, 32, 0x00000081 */ ++#define RTC_RTCSR (0x04) /* rw, 32, 0x???????? */ ++#define RTC_RTCSAR (0x08) /* rw, 32, 0x???????? */ ++#define RTC_RTCGR (0x0c) /* rw, 32, 0x0??????? */ ++#define RTC_HCR (0x20) /* rw, 32, 0x00000000 */ ++#define RTC_HWFCR (0x24) /* rw, 32, 0x0000???0 */ ++#define RTC_HRCR (0x28) /* rw, 32, 0x00000??0 */ ++#define RTC_HWCR (0x2c) /* rw, 32, 0x00000008 */ ++#define RTC_HWRSR (0x30) /* rw, 32, 0x00000000 */ ++#define RTC_HSPR (0x34) /* rw, 32, 0x???????? */ ++#define RTC_WENR (0x3c) /* rw, 32, 0x00000000 */ ++#define RTC_CKPCR (0x40) /* rw, 32, 0x00000010 */ ++#define RTC_OWIPCR (0x44) /* rw, 32, 0x00000010 */ ++#define RTC_PWRONCR (0x48) /* rw, 32, 0x???????? */ ++ ++#define WDT_TCSR (0x0c) /* rw, 32, 0x???????? */ ++#define WDT_TCER (0x04) /* rw, 32, 0x???????? */ ++#define WDT_TDR (0x00) /* rw, 32, 0x???????? */ ++#define WDT_TCNT (0x08) /* rw, 32, 0x???????? */ ++ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++ ++#define RTCCR_WRDY BIT(7) ++#define WENR_WEN BIT(31) ++ ++#define RECOVERY_SIGNATURE (0x001a1a) ++#define REBOOT_SIGNATURE (0x003535) ++#define UNMSAK_SIGNATURE (0x7c0000)//do not use these bits ++ ++#if 0 ++static void wdt_start_count(int msecs) ++{ ++ int time = JZ_EXTAL_RTC / 64 * msecs / 1000; ++ if(time > 65535) ++ time = 65535; ++ ++// outl(1 << 16,TCU_IOBASE + TCU_TSCR); ++ ++ outl(0,WDT_IOBASE + WDT_TCNT); //counter ++ outl(time,WDT_IOBASE + WDT_TDR); //data ++ outl((3<<3 | 2<<0 | 1 << 10),WDT_IOBASE + WDT_TCSR); ++ outl(0,WDT_IOBASE + WDT_TCER); ++ outl(1,WDT_IOBASE + WDT_TCER); ++} ++#endif ++static void __attribute__((unused)) wdt_stop_count(void) ++{ ++ outl(1 << 16,TCU_IOBASE + TCU_TSCR); ++ outl(0,WDT_IOBASE + WDT_TCNT); //counter ++ outl(65535,WDT_IOBASE + WDT_TDR); //data ++ outl(1 << 16,TCU_IOBASE + TCU_TSSR); ++} ++ ++static int inline rtc_write_reg(int reg,int value) ++{ ++ int timeout = 0x2000; ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY) && timeout--); ++ if(!timeout) ++ { ++ printk("WARN:NO USE RTC!!!!!\n"); ++ return -1; ++ } ++ outl(0xa55a,(RTC_IOBASE + RTC_WENR)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ while(!(inl(RTC_IOBASE + RTC_WENR) & WENR_WEN)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ outl(value,(RTC_IOBASE + reg)); ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ ++ return 0; ++} ++ ++/* ++ * Function: Keep power for CPU core when reset. ++ * So that EPC, tcsm and so on can maintain it's status after reset-key pressed. ++ */ ++static int inline reset_keep_power(void) ++{ ++ return rtc_write_reg(RTC_PWRONCR, ++ inl(RTC_IOBASE + RTC_PWRONCR) & ~(1 << 0)); ++} ++ ++#define HWFCR_WAIT_TIME(x) ((x > 0x7fff ? 0x7fff: (0x7ff*(x)) / 2000) << 5) ++#define HRCR_WAIT_TIME(x) ((((x) > 1875 ? 1875: (x)) / 125) << 11) ++ ++void jz_hibernate(void) ++{ ++ uint32_t rtc_rtccr; ++ ++ local_irq_disable(); ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ ++ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000)); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(125)); ++ ++ /* clear wakeup status register */ ++ rtc_write_reg(RTC_HWRSR, 0x0); ++ ++ rtc_write_reg(RTC_HWCR, 0x0); ++ ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ rtc_rtccr |= 0x1 << 0; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ /* Put CPU to hibernate mode */ ++ rtc_write_reg(RTC_HCR, 0x1); ++ ++ /*poweroff the pmu*/ ++// jz_notifier_call(NOTEFY_PROI_HIGH, JZ_POST_HIBERNATION, NULL); ++ ++ mdelay(200); ++ ++ while(1) ++ printk("%s:We should NOT come here.%08x\n",__func__, inl(RTC_IOBASE + RTC_HCR)); ++} ++ ++void jz_wdt_restart(char *command) ++{ ++ return; ++#if 0 ++ printk("Restarting after 4 ms\n"); ++ if ((command != NULL) && !strcmp(command, "recovery")) { ++ while(cpm_inl(CPM_CPPSR) != RECOVERY_SIGNATURE) { ++ printk("set RECOVERY_SIGNATURE\n"); ++ cpm_outl(0x5a5a,CPM_CPSPPR); ++ cpm_outl(RECOVERY_SIGNATURE,CPM_CPPSR); ++ cpm_outl(0x0,CPM_CPSPPR); ++ udelay(100); ++ } ++ } else { ++ cpm_outl(0x5a5a,CPM_CPSPPR); ++ cpm_outl(REBOOT_SIGNATURE,CPM_CPPSR); ++ cpm_outl(0x0,CPM_CPSPPR); ++ } ++ ++ wdt_start_count(4); ++ mdelay(200); ++ while(1) ++ printk("check wdt.\n"); ++#endif ++} ++ ++static void hibernate_restart(void) ++{ ++ uint32_t rtc_rtcsr,rtc_rtccr; ++ ++ while(!(inl(RTC_IOBASE + RTC_RTCCR) & RTCCR_WRDY)); ++ ++ rtc_rtcsr = inl(RTC_IOBASE + RTC_RTCSR); ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ ++ rtc_write_reg(RTC_RTCSAR,rtc_rtcsr + 5); ++ rtc_rtccr &= ~(1 << 4 | 1 << 1); ++ rtc_rtccr |= 0x3 << 2; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ /* Clear reset status */ ++ cpm_outl(0,CPM_RSR); ++ ++ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ ++ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000)); ++ ++ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ ++ rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(125)); ++ ++ /* clear wakeup status register */ ++ rtc_write_reg(RTC_HWRSR, 0x0); ++ ++ rtc_write_reg(RTC_HWCR, 0x1); ++ ++ ++ rtc_rtccr = inl(RTC_IOBASE + RTC_RTCCR); ++ rtc_rtccr |= 0x1 << 0; ++ rtc_write_reg(RTC_RTCCR,rtc_rtccr); ++ ++ ++ /* Put CPU to hibernate mode */ ++ rtc_write_reg(RTC_HCR, 0x1); ++ ++ mdelay(200); ++ while(1) ++ printk("%s:We should NOT come here.%08x\n",__func__, inl(RTC_IOBASE + RTC_HCR)); ++} ++ ++#ifdef CONFIG_HIBERNATE_RESET ++void jz_hibernate_restart(char *command) ++{ ++ local_irq_disable(); ++ ++ if ((command != NULL) && !strcmp(command, "recovery")) { ++ jz_wdt_restart(command); ++ } ++ ++ hibernate_restart(); ++} ++#endif ++ ++int __init reset_init(void) ++{ ++ pm_power_off = jz_hibernate; ++#ifdef CONFIG_HIBERNATE_RESET ++ _machine_restart = jz_hibernate_restart; ++#else ++ _machine_restart = jz_wdt_restart; ++#endif ++ return 0; ++} ++arch_initcall(reset_init); ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////// ++struct wdt_reset { ++ unsigned stop; ++ unsigned msecs; ++ unsigned count; ++}; ++ ++/* ============================reset proc=================================== */ ++static char *reset_command[] = {"wdt","hibernate","recovery", "poweroff"}; ++ ++static int reset_show(struct seq_file *filq, void *v) ++{ ++ int len = 0, i; ++ ++ for(i = 0; i < ARRAY_SIZE(reset_command); i++) ++ seq_printf(filq, "%s\t", reset_command[i]); ++ seq_printf(filq,"\n"); ++ ++ return len; ++} ++ ++static int reset_write(struct file *file, const char __user *buffer, ++ size_t usize, loff_t *off) ++{ ++ int command_size = 0; ++ int i; ++ ++ if(usize == 0) ++ return -EINVAL; ++ ++ command_size = ARRAY_SIZE(reset_command); ++ for(i = 0;i < command_size; i++) { ++ if(!strncmp(buffer, reset_command[i], strlen(reset_command[i]))) ++ break; ++ } ++ if(i == command_size) ++ return -EINVAL; ++ ++ local_irq_disable(); ++ switch(i) { ++ case 0: ++ jz_wdt_restart(NULL); ++ break; ++ case 1: ++ hibernate_restart(); ++ break; ++ case 2: ++ jz_wdt_restart("recovery"); ++ break; ++ case 3: ++ jz_hibernate(); ++ break; ++ default: ++ printk("not support command %d\n", i); ++ } ++ ++ return usize; ++} ++static struct jz_single_file_ops reset_proc_fops = { ++ .read = reset_show, ++ .write = reset_write, ++}; ++/* ============================reset proc end=============================== */ ++ ++static int __init init_reset(void) ++{ ++ struct wdt_reset *wdt; ++ struct proc_dir_entry *p, *res; ++ ++ wdt = kmalloc(sizeof(struct wdt_reset),GFP_KERNEL); ++ if(!wdt) { ++ return -ENOMEM; ++ } ++ ++ wdt->count = 0; ++ wdt->msecs = 3000; ++ ++ wdt->stop = 1; ++ ++ p = jz_proc_mkdir("reset"); ++ if (!p) { ++ pr_warn("create_proc_entry for common reset failed.\n"); ++ return -ENODEV; ++ } ++ ++ res = jz_proc_create_data("reset", 0444, p, &reset_proc_fops, wdt); ++ ++ return 0; ++} ++module_init(init_reset); +diff --git a/arch/mips/xburst2/soc-x2500/serial.c b/arch/mips/xburst2/soc-x2500/serial.c +new file mode 100644 +index 000000000..563208c52 +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/serial.c +@@ -0,0 +1,91 @@ ++/* ++ * JZ SOC serial routines for early_printk. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ * ++ */ ++ ++#include ++ ++#include ++ ++#define UART_BASE UART0_IOBASE ++#define UART_OFF 0x1000 ++ ++#define OFF_TDR (0x00) ++#define OFF_LCR (0x0C) ++#define OFF_LSR (0x14) ++ ++#define LSR_TDRQ (1 << 5) ++#define LSR_TEMT (1 << 6) ++ ++static void check_uart(char c); ++ ++volatile u8 *uart_base; ++typedef void (*putchar_f_t)(char); ++static putchar_f_t putchar_f = check_uart; ++ ++static void putchar(char ch) ++{ ++ int timeout = 10000; ++ volatile u8 *base = uart_base; ++ /* Wait for fifo to shift out some bytes */ ++ while ((base[OFF_LSR] & (LSR_TDRQ | LSR_TEMT)) ++ != (LSR_TDRQ | LSR_TEMT) && timeout--) ++ ; ++ base[OFF_TDR] = (u8)ch; ++} ++ ++static void putchar_dummy(char ch) ++{ ++ return; ++} ++ ++static void check_uart(char c) ++{ ++ /* We Couldn't use ioremap() here */ ++ volatile u8 *base = (volatile u8*)CKSEG1ADDR(UART0_IOBASE); ++ int i = 0; ++ for(i=0; i<10; i++) { ++ if(base[OFF_LCR]) ++ break; ++ base += UART_OFF; ++ } ++ ++ if(i<10) { ++ uart_base = base; ++ putchar_f = putchar; ++ putchar_f(c); ++ } else { ++ putchar_f = putchar_dummy; ++ } ++} ++ ++/* used by early printk */ ++void prom_putchar(char c) ++{ ++ putchar_f(c); ++} ++ ++void prom_putstr(char *s) ++{ ++ while(*s) { ++ if(*s == '\n') ++ putchar_f('\r'); ++ putchar_f(*s); ++ s++; ++ } ++} ++ ++#if 1 ++static char pbuffer[4096]; ++void prom_printk(const char *fmt, ...) { ++ va_list args; ++ ++ va_start(args, fmt); ++ vsnprintf(pbuffer, 4096, fmt, args); ++ va_end(args); ++ ++ prom_putstr(pbuffer); ++} ++#endif +diff --git a/arch/mips/xburst2/soc-x2500/setup.c b/arch/mips/xburst2/soc-x2500/setup.c +new file mode 100644 +index 000000000..c4d68f03b +--- /dev/null ++++ b/arch/mips/xburst2/soc-x2500/setup.c +@@ -0,0 +1,84 @@ ++/* ++ * Ingenic Soc Setup ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2006 Ingenic Semiconductor Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++void __init cpm_reset(void) ++{ ++} ++ ++int __init setup_init(void) ++{ ++#if 0 ++ cpm_reset(); ++ /* Set bus priority here */ ++ *(volatile unsigned int *)0xb34f0240 = 0x00010003; ++ *(volatile unsigned int *)0xb34f0244 = 0x00010003; ++#endif ++ ++ return 0; ++} ++extern void __init init_all_clk(void); ++/* used by linux-mti code */ ++extern void *get_fdt_addr(void); ++void __init plat_mem_setup(void) ++{ ++ /* use IO_BASE, so that we can use phy addr on hard manual ++ * directly with in(bwlq)/out(bwlq) in io.h. ++ */ ++ set_io_port_base(IO_BASE); ++ ioport_resource.start = 0x00000000; ++ ioport_resource.end = 0xffffffff; ++ iomem_resource.start = 0x00000000; ++ iomem_resource.end = 0xffffffff; ++ setup_init(); ++ ++ __dt_setup_arch(get_fdt_addr()); ++ ++ return; ++} ++void __init device_tree_init(void) ++{ ++ unflatten_and_copy_device_tree(); ++} ++ ++static int __init plat_of_populate(void) ++{ ++ of_platform_default_populate(NULL, NULL, NULL); ++ return 0; ++} ++arch_initcall(plat_of_populate); ++ ++void __init plat_time_init(void) ++{ ++ of_clk_init(NULL); ++ ++ timer_probe(); ++} ++ ++void __init arch_init_irq(void) ++{ ++ irqchip_init(); ++} +diff --git a/block/partitions/efi.c b/block/partitions/efi.c +index b64bfdd43..d16b8d018 100644 +--- a/block/partitions/efi.c ++++ b/block/partitions/efi.c +@@ -406,7 +406,9 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, + pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", + (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), + (unsigned long long)lastlba); ++#ifndef CONFIG_INGENIC_GPT_CHECK + goto fail; ++#endif + } + if (le64_to_cpu((*gpt)->last_usable_lba) < le64_to_cpu((*gpt)->first_usable_lba)) { + pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", +diff --git a/drivers/char/Makefile b/drivers/char/Makefile +index ffce287ef..ffe6dd788 100644 +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -47,3 +47,5 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o + obj-$(CONFIG_XILLYBUS) += xillybus/ + obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o + obj-$(CONFIG_ADI) += adi.o ++obj-$(CONFIG_INGENIC_SFCNAND_FMW) += jz_spinand_firmware.o ++ccflags-$(CONFIG_INGENIC_SFCNAND_FMW) += -I$(srctree)/module_drivers/drivers/mtd/devices/ingenic_sfc_v2 +diff --git a/drivers/char/jz_spinand_firmware.c b/drivers/char/jz_spinand_firmware.c +new file mode 100644 +index 000000000..bb488bc0b +--- /dev/null ++++ b/drivers/char/jz_spinand_firmware.c +@@ -0,0 +1,486 @@ ++/** ++ * 兼容x1830å¹³å°ï¼Œä¾¿äºŽåº”ç”¨é›†æˆ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "jz_spinand_firmware.h" ++#include "sfc_flash.h" ++ ++ ++static int fmw_open(struct inode *inode, struct file *filp) ++{ ++ struct cdev *cdev = inode->i_cdev; ++ struct fmw_dev *fmw = container_of(cdev, struct fmw_dev, cdev); ++ ++ filp->private_data = fmw; ++ ++ if(!driver_find(JZ_SFC_NAND, &platform_bus_type)) { ++ printk(KERN_ERR "%s %s %d: %s driver module init failed!\n", ++ __FILE__, __func__, __LINE__, JZ_SFC_NAND); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int32_t fmw_read(uint32_t flash_off, void *buf, uint32_t len) ++{ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ uint32_t retlen = 0; ++ int ret; ++ ++ ret = mtd->_read(mtd, flash_off, len, &retlen, buf); ++ return ret; ++} ++ ++static int32_t fmw_write(uint32_t flash_off, void *buf, uint32_t len) ++{ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ uint32_t retlen = 0; ++ int ret; ++ ++ ret = mtd->_write(mtd, flash_off, len, &retlen, buf); ++ return ret; ++} ++ ++static int32_t fwm_erase(uint32_t flash_off, uint32_t flash_size) ++{ ++ int i; ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ struct erase_info info = { ++ .addr = flash_off, ++ .len = mtd->erasesize, ++ }; ++ ++ for (i = 0; i < flash_size / mtd->erasesize; i++) { ++ mtd->_erase(mtd, &info); ++ info.addr += info.len; ++ } ++ return 0; ++} ++ ++static int32_t fwm_buf_compare(uint8_t *wbuf, uint8_t *rbuf, uint32_t len) ++{ ++ int ret = memcmp(wbuf, rbuf, len); ++ if (ret) { ++ printk(KERN_ERR "compare err wbuf do not equal to rbuf.\n"); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static int32_t sn_read_config(struct fmw_dev *fmw) ++{ ++ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ int i,ret; ++ int32_t flash_off = CONFIG_MAC_FLASH_SIZE; ++ ++ for (i = 0; i < CONFIG_SN_FLASH_SIZE / mtd->erasesize; i++) { ++ ret = fmw_read(mtd->size + flash_off, &fmw->sn_config, sizeof(fmw->sn_config)); ++ if(ret >= 0 && fmw->sn_config.sn_len != 0 && fmw->sn_config.crc_val != 0) ++ break; ++ flash_off += mtd->erasesize; ++ } ++ ++ if(fmw->sn_config.sn_len == -1 || ++ fmw->sn_config.crc_val == -1 || ++ fmw->sn_config.sn_len >= SN_BUF_LEN) { ++ printk(KERN_ERR "%s %s %d: flash don`t save sn value!\n", ++ __FILE__, __func__, __LINE__); ++ return -ENODATA; ++ } ++ ++ if(i == CONFIG_SN_FLASH_SIZE / mtd->erasesize) { ++ printk(KERN_ERR "%s %s %d:flash all blocks ecc error!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int32_t sn_read(struct fmw_dev *fmw) ++{ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ uint32_t flash_off = mtd->size + CONFIG_MAC_FLASH_SIZE; ++ uint32_t blocksize = mtd->erasesize; ++ int32_t ret = 0; ++ uint8_t i; ++ ++ if(sn_read_config(fmw)) { ++ printk(KERN_ERR "%s %s %d:read sn config failed!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ for (i = 0; i < CONFIG_SN_FLASH_SIZE / blocksize; i++) { ++ ret = fmw_read(flash_off + sizeof(fmw->sn_config), fmw->buf, fmw->sn_config.sn_len); ++ if(ret < 0) { ++ flash_off += blocksize; ++ continue; ++ } ++ ++ if(local_crc32(0xffffffff, fmw->buf, fmw->sn_config.sn_len) == fmw->sn_config.crc_val) ++ break; ++ flash_off += blocksize; ++ } ++ if(i == CONFIG_SN_FLASH_SIZE / blocksize) { ++ printk(KERN_ERR "%s %s %d: sn flash all blocks ecc error!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int32_t mac_read_config(struct fmw_dev *fmw) ++{ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ int i,ret; ++ int32_t flash_off = 0; ++ ++ for (i = 0; i < CONFIG_MAC_FLASH_SIZE / mtd->erasesize; i++) { ++ ret = fmw_read(mtd->size + flash_off, &fmw->mac_config, sizeof(fmw->mac_config)); ++ if(ret >= 0 && fmw->mac_config.mac_len != 0 && fmw->mac_config.crc_val != 0) ++ break; ++ flash_off += mtd->erasesize; ++ ++ } ++ ++ if(fmw->mac_config.mac_len == -1 || ++ fmw->mac_config.crc_val == -1 || ++ fmw->mac_config.mac_len >= MAC_BUF_LEN) { ++ printk(KERN_ERR "%s %s %d: flash don`t save mac value!\n", ++ __FILE__, __func__, __LINE__); ++ return -ENODATA; ++ } ++ ++ if(i == CONFIG_MAC_FLASH_SIZE / mtd->erasesize) { ++ printk(KERN_ERR "%s %s %d:flash all blocks ecc error!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int32_t mac_read(struct fmw_dev *fmw) ++{ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ uint32_t flash_off = mtd->size; ++ uint32_t blocksize = mtd->erasesize; ++ int32_t ret = 0; ++ uint8_t i; ++ ++ if(mac_read_config(fmw)) { ++ printk(KERN_ERR "%s %s %d:read mac config failed!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ for (i = 0; i < CONFIG_MAC_FLASH_SIZE / blocksize; i++) { ++ ret = fmw_read(flash_off + sizeof(fmw->mac_config), fmw->buf, fmw->mac_config.mac_len); ++ if(ret < 0) { ++ flash_off += blocksize; ++ continue; ++ } ++ ++ if(local_crc32(0xffffffff, fmw->buf, fmw->mac_config.mac_len) == fmw->mac_config.crc_val) ++ break; ++ flash_off += blocksize; ++ } ++ ++ if(i == CONFIG_MAC_FLASH_SIZE / blocksize) { ++ printk(KERN_ERR "%s %s %d: mac flash all blocks ecc error!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int32_t license_read_config(struct fmw_dev *fmw) ++{ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ int i, ret; ++ int32_t flash_off = CONFIG_MAC_FLASH_SIZE + CONFIG_SN_FLASH_SIZE; ++ ++ for (i = 0; i < CONFIG_LICENSE_FLASH_SIZE / mtd->erasesize; i++) { ++ ret = fmw_read(mtd->size + flash_off, &fmw->license_config, sizeof(fmw->license_config)); ++ if (ret >= 0 && fmw->license_config.license_len != 0 && fmw->license_config.crc_val != 0) { ++ break; ++ } ++ flash_off += mtd->erasesize; ++ } ++ if (fmw->license_config.license_len == -1 || ++ fmw->license_config.crc_val == -1 || ++ fmw->license_config.license_len >= LICENSE_BUF_LEN) { ++ pr_err("%s %s %d: flash don't save license value!\n", ++ __FILE__, __func__, __LINE__); ++ return -ENODATA; ++ } ++ ++ if (i == CONFIG_LICENSE_FLASH_SIZE / mtd->erasesize) { ++ pr_err("%s %s %d:flash all blocks ecc error!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static int32_t license_read(struct fmw_dev *fmw) ++{ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ uint32_t flash_off = mtd->size + CONFIG_MAC_FLASH_SIZE + CONFIG_SN_FLASH_SIZE; ++ uint32_t blocksize = mtd->erasesize; ++ int32_t ret = 0; ++ uint32_t i; ++ ++ if (license_read_config(fmw)) { ++ pr_err("%s %s %d:license config failed\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ for (i = 0; i < CONFIG_LICENSE_FLASH_SIZE / blocksize; i++) { ++ ret = fmw_read(flash_off + sizeof(fmw->license_config), fmw->buf, fmw->license_config.license_len); ++ if (ret < 0) { ++ flash_off += blocksize; ++ continue; ++ } ++ if(local_crc32(0xffffffff, fmw->buf, fmw->license_config.license_len) == fmw->license_config.crc_val) ++ break; ++ flash_off += blocksize; ++ } ++ ++ if(i == CONFIG_LICENSE_FLASH_SIZE / blocksize) { ++ printk(KERN_ERR "%s %s %d: license flash all blocks ecc error!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int32_t license_write(struct fmw_dev *fmw) ++{ ++ int i; ++ uint8_t errcount = 0; ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ uint32_t flash_offs = mtd->size + CONFIG_MAC_FLASH_SIZE + CONFIG_SN_FLASH_SIZE; ++ uint32_t flash_size = CONFIG_LICENSE_FLASH_SIZE; ++ int32_t ret = 0; ++ uint8_t *rbuf; ++ ++ void *buf = kzalloc(sizeof(fmw->license_config) + fmw->license_config.license_len, GFP_KERNEL); ++ if(!buf) { ++ printk(KERN_ERR "alloc mem failed!\n"); ++ return -ENOMEM; ++ } ++ ++ memcpy(buf, &fmw->license_config, sizeof(fmw->license_config)); ++ memcpy(buf + sizeof(fmw->license_config), fmw->buf, fmw->license_config.license_len); ++ ++ fwm_erase(flash_offs, flash_size); ++ for (i = 0; i < flash_size / mtd->erasesize; i++) { ++ ret = fmw_write(flash_offs, buf, sizeof(fmw->license_config) + fmw->license_config.license_len); ++ if(ret) { ++ printk(KERN_ERR "%s %s %d:write data failed! errcount = %d\n", ++ __FILE__, __func__, __LINE__, errcount++); ++ flash_offs += mtd->erasesize; ++ continue; ++ } ++ ++ rbuf = kzalloc(sizeof(fmw->license_config) + fmw->license_config.license_len, GFP_KERNEL); ++ if (rbuf) { ++ ret = fmw_read(flash_offs, rbuf, sizeof(fmw->license_config) + fmw->license_config.license_len); ++ if (!ret) { ++ if ((ret = fwm_buf_compare(buf, rbuf, sizeof(fmw->license_config) + fmw->license_config.license_len))) { ++ printk(KERN_ERR "%s %s %d: buf compare err!\n", __FILE__, __func__, __LINE__); ++ } ++ } ++ kfree(rbuf); ++ } ++ } ++ if(errcount == flash_size / mtd->erasesize) { ++ printk(KERN_ERR "all blk write failed!\n"); ++ kfree(buf); ++ return -EIO; ++ } ++ ++ kfree(buf); ++ return ret; ++} ++ ++ ++static long fmw_ioctl(struct file *filp, unsigned int cmd, unsigned long args) ++{ ++ struct fmw_dev *fmw = filp->private_data; ++ uint32_t max_len; ++ int32_t ret = 0; ++ ++ switch(cmd) { ++ case SN_GET_CONFIG: ++ if((ret = sn_read_config(fmw))) { ++ printk(KERN_ERR "%s %s %d: sn get config failed, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ break; ++ } ++ copy_to_user((void *)args, &fmw->sn_config, sizeof(fmw->sn_config)); ++ break; ++ case SN_READ: ++ if((ret = sn_read(fmw))) { ++ printk(KERN_ERR "%s %s %d: sn_read failed, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ break; ++ } ++ copy_to_user((void *)args, fmw->buf, fmw->sn_config.sn_len); ++ break; ++ ++ case MAC_GET_CONFIG: ++ if((ret = mac_read_config(fmw))) { ++ printk(KERN_ERR "%s %s %d: mac get config failed, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ break; ++ } ++ copy_to_user((void *)args, &fmw->mac_config, sizeof(fmw->mac_config)); ++ break; ++ case MAC_READ: ++ if((ret = mac_read(fmw))) { ++ printk(KERN_ERR "%s %s %d: mac_read failed, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ break; ++ } ++ copy_to_user((void *)args, fmw->buf, fmw->mac_config.mac_len); ++ break; ++ ++ case LICENSE_GET_CONFIG: ++ if (license_read_config(fmw)) { ++ pr_err("%s %s %d:license get config failed, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ break; ++ } ++ copy_to_user((void *)args, &fmw->license_config, sizeof(fmw->license_config)); ++ break; ++ case LICENSE_MAX_LEN: ++ max_len = LICENSE_BUF_LEN; ++ copy_to_user((void *)args, &max_len, sizeof(uint32_t)); ++ break; ++ case LICENSE_READ: ++ if (license_read(fmw)) { ++ pr_err("%s %s %d:license read failed, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ break; ++ } ++ copy_to_user((void *)args, fmw->buf, fmw->license_config.license_len); ++ break; ++ case LICENSE_WRITE: ++ if((copy_from_user(&fmw->license_config, (void *)args, sizeof(fmw->license_config)))) { ++ printk(KERN_ERR "%s %s %d: get license_config error, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ break; ++ } ++ fmw->buf = kzalloc(fmw->license_config.license_len, GFP_KERNEL); ++ if (!fmw->buf) { ++ printk(KERN_ERR "%s %s %d: alloc fmw buf error.\n", __FILE__, __func__, __LINE__); ++ return -ENOMEM; ++ } ++ if((ret = copy_from_user(fmw->buf, (char*)args+sizeof(struct license_config), fmw->license_config.license_len))) { ++ printk(KERN_ERR "%s %s %d: get license data error, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ break; ++ } ++ if((ret = license_write(fmw))) { ++ printk(KERN_ERR "%s %s %d: license write failed, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ break; ++ } ++ break; ++ ++ default: ++ printk(KERN_ERR "%s %s %d: don`t support this cmd!\n", __FILE__, __func__, __LINE__); ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++static int fmw_close (struct inode * inode, struct file *filp) ++{ ++ return 0; ++ ++} ++ ++static struct file_operations fmw_ops = { ++ ++ .owner = THIS_MODULE, ++ .open = fmw_open, ++ .release = fmw_close, ++ .unlocked_ioctl = fmw_ioctl, ++}; ++ ++static int __init fmw_init(void) ++{ ++ dev_t dev; ++ int32_t ret = 0; ++ ++ struct fmw_dev *fmw = kzalloc(sizeof(*fmw), GFP_KERNEL); ++ if(!fmw) { ++ printk(KERN_ERR "%s %s %d :alloc sn failed!\n", ++ __FILE__, __func__, __LINE__); ++ return -ENOMEM; ++ } ++ ++ fmw->buf = kzalloc(SN_BUF_LEN, GFP_KERNEL); ++ if(!fmw->buf) { ++ printk(KERN_ERR "%s %s %d: alloc sn buf failed!\n", __FILE__, __func__, __LINE__); ++ kfree(fmw); ++ return -ENOMEM; ++ } ++ ++ fmw->class = class_create(THIS_MODULE, "jz-spinand-sn"); ++ fmw->minor = 0; ++ fmw->nr_devs = 1; ++ ++ if(alloc_chrdev_region(&dev, fmw->minor, fmw->nr_devs, "jz-spinand-fmw")) { ++ ++ printk(KERN_ERR "%s %s %d: alloc chrdev failed!\n", ++ __FILE__, __func__, __LINE__); ++ ret = -ENODEV; ++ goto failed; ++ } ++ ++ cdev_init(&fmw->cdev, &fmw_ops); ++ fmw->cdev.owner = THIS_MODULE; ++ cdev_add(&fmw->cdev, dev, fmw->nr_devs); ++ ++ fmw->dev = device_create(fmw->class, NULL, dev, NULL, "jz-spinand-fmw"); ++ if(IS_ERR_OR_NULL(fmw->dev)) { ++ printk(KERN_ERR "%s %s %d :creates a device and register sysfs failed !\n", ++ __FILE__, __func__, __LINE__); ++ ret = -ENODEV; ++ goto free_all; ++ } ++ ++ return 0; ++ ++free_all: ++ unregister_chrdev_region(dev, fmw->nr_devs); ++failed: ++ kfree(fmw->buf); ++ kfree(fmw); ++ return ret; ++} ++ ++module_init(fmw_init); ++MODULE_AUTHOR("zhangronghua"); ++MODULE_DESCRIPTION("sn speace read driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/char/jz_spinand_firmware.h b/drivers/char/jz_spinand_firmware.h +new file mode 100644 +index 000000000..b18aceb2e +--- /dev/null ++++ b/drivers/char/jz_spinand_firmware.h +@@ -0,0 +1,63 @@ ++#ifndef __JZ_SPINAND_FIRMWARE_H ++#define __JZ_SPINAND_FIRMWARE_H ++#include ++#include ++#include "fmw.h" ++ ++#define JZ_SFC_NAND "ingenic-sfc" ++#define SN_BUF_LEN 512 ++#define MAC_BUF_LEN 512 ++#define LICENSE_BUF_LEN CONFIG_LICENSE_FLASH_SIZE ++ ++ ++#define SN_GET_CONFIG _IOR('S', 0x0, uint32_t) ++#define SN_READ _IOR('S', 0x1, uint32_t) ++#define MAC_GET_CONFIG _IOR('S', 0x2, uint32_t) ++#define MAC_READ _IOR('S', 0x3, uint32_t) ++#define LICENSE_GET_CONFIG _IOR('S', 0x4, uint32_t) ++#define LICENSE_READ _IOR('S', 0x5, uint32_t) ++#define LICENSE_WRITE _IOR('S', 0x6, uint32_t) ++#define LICENSE_MAX_LEN _IOR('S', 0x7, uint32_t) ++ ++struct sn_config { ++ uint32_t sn_len; ++ uint32_t crc_val; ++}; ++ ++struct mac_config { ++ uint32_t mac_len; ++ uint32_t crc_val; ++}; ++ ++struct license_config { ++ uint32_t license_len; ++ uint32_t crc_val; ++}; ++ ++struct fmw_dev { ++ ++ uint8_t minor; ++ uint8_t nr_devs; ++ ++ struct class *class; ++ struct cdev cdev; ++ struct device *dev; ++ ++ uint8_t *buf; ++ ++ /*mac*/ ++ struct mac_config mac_config; ++ ++ /*sn*/ ++ struct sn_config sn_config; ++ ++ /*license*/ ++ struct license_config license_config; ++}; ++ ++extern struct bus_type platform_bus_type; ++extern struct sfc_flash *fmw_flash; ++ ++#endif ++ ++ +diff --git a/drivers/media/platform/v4l2loopback/Makefile b/drivers/media/platform/v4l2loopback/Makefile +new file mode 100644 +index 000000000..8c58cedf9 +--- /dev/null ++++ b/drivers/media/platform/v4l2loopback/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_V4L2_LOOPBACK_DEVICE) += v4l2loopback.o +diff --git a/drivers/media/platform/v4l2loopback/v4l2loopback.c b/drivers/media/platform/v4l2loopback/v4l2loopback.c +new file mode 100644 +index 000000000..29af286d0 +--- /dev/null ++++ b/drivers/media/platform/v4l2loopback/v4l2loopback.c +@@ -0,0 +1,3016 @@ ++/* -*- c-file-style: "linux" -*- */ ++/* ++ * v4l2loopback.c -- video4linux2 loopback driver ++ * ++ * Copyright (C) 2005-2009 Vasily Levin (vasaka@gmail.com) ++ * Copyright (C) 2010-2019 IOhannes m zmoelnig (zmoelnig@iem.at) ++ * Copyright (C) 2011 Stefan Diewald (stefan.diewald@mytum.de) ++ * Copyright (C) 2012 Anton Novikov (random.plant@gmail.com) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++#define HAVE__V4L2_DEVICE ++#include ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) ++#define HAVE__V4L2_CTRLS ++#include ++#endif ++#include ++ ++#include ++#include "v4l2loopback.h" ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 1) ++#define kstrtoul strict_strtoul ++#endif ++ ++#if defined(timer_setup) && defined(from_timer) ++#define HAVE_TIMER_SETUP ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0) ++#define VFL_TYPE_VIDEO VFL_TYPE_GRABBER ++#endif ++ ++//#define USING_DMA_ALLOC_BUFFER ++ ++#define V4L2LOOPBACK_VERSION_CODE \ ++ KERNEL_VERSION(V4L2LOOPBACK_VERSION_MAJOR, V4L2LOOPBACK_VERSION_MINOR, \ ++ V4L2LOOPBACK_VERSION_BUGFIX) ++ ++MODULE_DESCRIPTION("V4L2 loopback video device"); ++MODULE_AUTHOR("Vasily Levin, " ++ "IOhannes m zmoelnig ," ++ "Stefan Diewald," ++ "Anton Novikov" ++ "et al."); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * helpers ++ */ ++#define STRINGIFY(s) #s ++#define STRINGIFY2(s) STRINGIFY(s) ++ ++#define dprintk(fmt, args...) \ ++ do { \ ++ if (debug > 0) { \ ++ printk(KERN_INFO "v4l2-loopback[" STRINGIFY2( \ ++ __LINE__) "]: " fmt, \ ++ ##args); \ ++ } \ ++ } while (0) ++ ++#define MARK() \ ++ do { \ ++ if (debug > 1) { \ ++ printk(KERN_INFO "%s:%d[%s]\n", __FILE__, __LINE__, \ ++ __func__); \ ++ } \ ++ } while (0) ++ ++#define dprintkrw(fmt, args...) \ ++ do { \ ++ if (debug > 2) { \ ++ printk(KERN_INFO "v4l2-loopback[" STRINGIFY2( \ ++ __LINE__) "]: " fmt, \ ++ ##args); \ ++ } \ ++ } while (0) ++ ++/* ++ * compatibility hacks ++ */ ++ ++#ifndef HAVE__V4L2_CTRLS ++struct v4l2_ctrl_handler { ++ int error; ++}; ++struct v4l2_ctrl_config { ++ void *ops; ++ u32 id; ++ const char *name; ++ int type; ++ s32 min; ++ s32 max; ++ u32 step; ++ s32 def; ++}; ++int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, ++ unsigned nr_of_controls_hint) ++{ ++ hdl->error = 0; ++ return 0; ++} ++void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) ++{ ++} ++void *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, ++ const struct v4l2_ctrl_config *conf, void *priv) ++{ ++ return NULL; ++} ++#endif /* HAVE__V4L2_CTRLS */ ++ ++#ifndef HAVE__V4L2_DEVICE ++/* dummy v4l2_device struct/functions */ ++#define V4L2_DEVICE_NAME_SIZE (20 + 16) ++struct v4l2_device { ++ char name[V4L2_DEVICE_NAME_SIZE]; ++ struct v4l2_ctrl_handler *ctrl_handler; ++}; ++static inline int v4l2_device_register(void *dev, void *v4l2_dev) ++{ ++ return 0; ++} ++static inline void v4l2_device_unregister(struct v4l2_device *v4l2_dev) ++{ ++ return; ++} ++#endif /* HAVE__V4L2_DEVICE */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) ++#define v4l2_file_operations file_operations ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) ++void *v4l2l_vzalloc(unsigned long size) ++{ ++ void *data = vmalloc(size); ++ ++ memset(data, 0, size); ++ return data; ++} ++#else ++#define v4l2l_vzalloc vzalloc ++#endif ++ ++static inline void v4l2l_get_timestamp(struct v4l2_buffer *b) ++{ ++ /* ktime_get_ts is considered deprecated, so use ktime_get_ts64 if possible */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ++ struct timespec ts; ++ ktime_get_ts(&ts); ++#else ++ struct timespec64 ts; ++ ktime_get_ts64(&ts); ++#endif ++ ++ b->timestamp.tv_sec = ts.tv_sec; ++ b->timestamp.tv_usec = (ts.tv_nsec / NSEC_PER_USEC); ++} ++ ++#if !defined(__poll_t) ++typedef unsigned __poll_t; ++#endif ++ ++/* module constants ++ * can be overridden during he build process using something like ++ * make KCPPFLAGS="-DMAX_DEVICES=100" ++ */ ++ ++/* maximum number of v4l2loopback devices that can be created */ ++#ifndef MAX_DEVICES ++#define MAX_DEVICES 8 ++#endif ++ ++/* whether the default is to announce capabilities exclusively or not */ ++#ifndef V4L2LOOPBACK_DEFAULT_EXCLUSIVECAPS ++#define V4L2LOOPBACK_DEFAULT_EXCLUSIVECAPS 0 ++#endif ++ ++/* when a producer is considered to have gone stale */ ++#ifndef MAX_TIMEOUT ++#define MAX_TIMEOUT (100 * 1000) /* in msecs */ ++#endif ++ ++/* max buffers that can be mapped, actually they ++ * are all mapped to max_buffers buffers */ ++#ifndef MAX_BUFFERS ++#define MAX_BUFFERS 32 ++#endif ++ ++/* module parameters */ ++static int debug = 0; ++module_param(debug, int, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(debug, "debugging level (higher values == more verbose)"); ++ ++#define V4L2LOOPBACK_DEFAULT_MAX_BUFFERS 2 ++static int max_buffers = V4L2LOOPBACK_DEFAULT_MAX_BUFFERS; ++module_param(max_buffers, int, S_IRUGO); ++MODULE_PARM_DESC(max_buffers, ++ "how many buffers should be allocated [DEFAULT: " STRINGIFY2( ++ V4L2LOOPBACK_DEFAULT_MAX_BUFFERS) "]"); ++ ++/* how many times a device can be opened ++ * the per-module default value can be overridden on a per-device basis using ++ * the /sys/devices interface ++ * ++ * note that max_openers should be at least 2 in order to get a working system: ++ * one opener for the producer and one opener for the consumer ++ * however, we leave that to the user ++ */ ++#define V4L2LOOPBACK_DEFAULT_MAX_OPENERS 10 ++static int max_openers = V4L2LOOPBACK_DEFAULT_MAX_OPENERS; ++module_param(max_openers, int, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC( ++ max_openers, ++ "how many users can open the loopback device [DEFAULT: " STRINGIFY2( ++ V4L2LOOPBACK_DEFAULT_MAX_OPENERS) "]"); ++ ++static int devices = -1; ++module_param(devices, int, 0); ++MODULE_PARM_DESC(devices, "how many devices should be created"); ++ ++static int video_nr[MAX_DEVICES] = { [0 ...(MAX_DEVICES - 1)] = -1 }; ++module_param_array(video_nr, int, NULL, 0444); ++MODULE_PARM_DESC(video_nr, ++ "video device numbers (-1=auto, 0=/dev/video0, etc.)"); ++ ++static char *card_label[MAX_DEVICES]; ++module_param_array(card_label, charp, NULL, 0000); ++MODULE_PARM_DESC(card_label, "card labels for each device"); ++ ++static bool exclusive_caps[MAX_DEVICES] = { ++ [0 ...(MAX_DEVICES - 1)] = V4L2LOOPBACK_DEFAULT_EXCLUSIVECAPS ++}; ++module_param_array(exclusive_caps, bool, NULL, 0444); ++/* FIXXME: wording */ ++MODULE_PARM_DESC( ++ exclusive_caps, ++ "whether to announce OUTPUT/CAPTURE capabilities exclusively or not [DEFAULT: " STRINGIFY2( ++ V4L2LOOPBACK_DEFAULT_EXCLUSIVECAPS) "]"); ++ ++/* format specifications */ ++#define V4L2LOOPBACK_SIZE_MIN_WIDTH 48 ++#define V4L2LOOPBACK_SIZE_MIN_HEIGHT 32 ++#define V4L2LOOPBACK_SIZE_DEFAULT_MAX_WIDTH 8192 ++#define V4L2LOOPBACK_SIZE_DEFAULT_MAX_HEIGHT 8192 ++ ++#define V4L2LOOPBACK_SIZE_DEFAULT_WIDTH 640 ++#define V4L2LOOPBACK_SIZE_DEFAULT_HEIGHT 480 ++ ++static int max_width = V4L2LOOPBACK_SIZE_DEFAULT_MAX_WIDTH; ++module_param(max_width, int, S_IRUGO); ++MODULE_PARM_DESC(max_width, "maximum allowed frame width [DEFAULT: " STRINGIFY2( ++ V4L2LOOPBACK_SIZE_DEFAULT_MAX_WIDTH) "]"); ++static int max_height = V4L2LOOPBACK_SIZE_DEFAULT_MAX_HEIGHT; ++module_param(max_height, int, S_IRUGO); ++MODULE_PARM_DESC(max_height, ++ "maximum allowed frame height [DEFAULT: " STRINGIFY2( ++ V4L2LOOPBACK_SIZE_DEFAULT_MAX_HEIGHT) "]"); ++ ++static DEFINE_IDR(v4l2loopback_index_idr); ++static DEFINE_MUTEX(v4l2loopback_ctl_mutex); ++ ++/* control IDs */ ++#ifndef HAVE__V4L2_CTRLS ++#define V4L2LOOPBACK_CID_BASE (V4L2_CID_PRIVATE_BASE) ++#else ++#define V4L2LOOPBACK_CID_BASE (V4L2_CID_USER_BASE | 0xf000) ++#endif ++#define CID_KEEP_FORMAT (V4L2LOOPBACK_CID_BASE + 0) ++#define CID_SUSTAIN_FRAMERATE (V4L2LOOPBACK_CID_BASE + 1) ++#define CID_TIMEOUT (V4L2LOOPBACK_CID_BASE + 2) ++#define CID_TIMEOUT_IMAGE_IO (V4L2LOOPBACK_CID_BASE + 3) ++ ++static int v4l2loopback_s_ctrl(struct v4l2_ctrl *ctrl); ++static const struct v4l2_ctrl_ops v4l2loopback_ctrl_ops = { ++ .s_ctrl = v4l2loopback_s_ctrl, ++}; ++static const struct v4l2_ctrl_config v4l2loopback_ctrl_keepformat = { ++ // clang-format off ++ .ops = &v4l2loopback_ctrl_ops, ++ .id = CID_KEEP_FORMAT, ++ .name = "keep_format", ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .min = 0, ++ .max = 1, ++ .step = 1, ++ .def = 0, ++ // clang-format on ++}; ++static const struct v4l2_ctrl_config v4l2loopback_ctrl_sustainframerate = { ++ // clang-format off ++ .ops = &v4l2loopback_ctrl_ops, ++ .id = CID_SUSTAIN_FRAMERATE, ++ .name = "sustain_framerate", ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .min = 0, ++ .max = 1, ++ .step = 1, ++ .def = 0, ++ // clang-format on ++}; ++static const struct v4l2_ctrl_config v4l2loopback_ctrl_timeout = { ++ // clang-format off ++ .ops = &v4l2loopback_ctrl_ops, ++ .id = CID_TIMEOUT, ++ .name = "timeout", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .min = 0, ++ .max = MAX_TIMEOUT, ++ .step = 1, ++ .def = 0, ++ // clang-format on ++}; ++static const struct v4l2_ctrl_config v4l2loopback_ctrl_timeoutimageio = { ++ // clang-format off ++ .ops = &v4l2loopback_ctrl_ops, ++ .id = CID_TIMEOUT_IMAGE_IO, ++ .name = "timeout_image_io", ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .min = 0, ++ .max = 1, ++ .step = 1, ++ .def = 0, ++ // clang-format on ++}; ++ ++/* module structures */ ++struct v4l2loopback_private { ++ int device_nr; ++}; ++ ++/* TODO(vasaka) use typenames which are common to kernel, but first find out if ++ * it is needed */ ++/* struct keeping state and settings of loopback device */ ++ ++struct v4l2l_buffer { ++ struct v4l2_buffer buffer; ++ struct list_head list_head; ++ int use_count; ++}; ++ ++struct v4l2_loopback_device { ++ struct v4l2_device v4l2_dev; ++ struct v4l2_ctrl_handler ctrl_handler; ++ struct video_device *vdev; ++ /* pixel and stream format */ ++ struct v4l2_pix_format pix_format; ++ struct v4l2_captureparm capture_param; ++ unsigned long frame_jiffies; ++ ++ /* ctrls */ ++ int keep_format; /* CID_KEEP_FORMAT; stay ready_for_capture even when all ++ openers close() the device */ ++ int sustain_framerate; /* CID_SUSTAIN_FRAMERATE; duplicate frames to maintain ++ (close to) nominal framerate */ ++ ++ /* buffers stuff */ ++ u8 *image; /* pointer to actual buffers data */ ++ dma_addr_t image_paddr; /* pointer to actual buffers data */ ++ unsigned long int imagesize; /* size of buffers data */ ++ int buffers_number; /* should not be big, 4 is a good choice */ ++ struct v4l2l_buffer buffers[MAX_BUFFERS]; /* inner driver buffers */ ++ int used_buffers; /* number of the actually used buffers */ ++ int max_openers; /* how many times can this device be opened */ ++ ++ int write_position; /* number of last written frame + 1 */ ++ struct list_head outbufs_list; /* buffers in output DQBUF order */ ++ int bufpos2index ++ [MAX_BUFFERS]; /* mapping of (read/write_position % used_buffers) ++ * to inner buffer index */ ++ long buffer_size; ++ ++ /* sustain_framerate stuff */ ++ struct timer_list sustain_timer; ++ unsigned int reread_count; ++ ++ /* timeout stuff */ ++ unsigned long timeout_jiffies; /* CID_TIMEOUT; 0 means disabled */ ++ int timeout_image_io; /* CID_TIMEOUT_IMAGE_IO; next opener will ++ * read/write to timeout_image */ ++ u8 *timeout_image; /* copy of it will be captured when timeout passes */ ++ struct v4l2l_buffer timeout_image_buffer; ++ struct timer_list timeout_timer; ++ int timeout_happened; ++ ++ /* sync stuff */ ++ atomic_t open_count; ++ ++ int ready_for_capture; /* set to the number of writers that opened the ++ * device and negotiated format. */ ++ int ready_for_output; /* set to true when no writer is currently attached ++ * this differs slightly from !ready_for_capture, ++ * e.g. when using fallback images */ ++ int announce_all_caps; /* set to false, if device caps (OUTPUT/CAPTURE) ++ * should only be announced if the resp. "ready" ++ * flag is set; default=TRUE */ ++ int gen_timestamp; /*whether generate timestamp by kernel or not.*/ ++ ++ ++ struct list_head queued_list; /*list for capture queued buffer.*/ ++ struct list_head done_list; /*list for output queued buffer.*/ ++ ++ spinlock_t done_lock; ++ unsigned int output_sequence; ++ ++ ++ int max_width; ++ int max_height; ++ ++ char card_label[32]; ++ ++ wait_queue_head_t read_event; ++ spinlock_t lock; ++}; ++ ++/* types of opener shows what opener wants to do with loopback */ ++enum opener_type { ++ // clang-format off ++ UNNEGOTIATED = 0, ++ READER = 1, ++ WRITER = 2, ++ // clang-format on ++}; ++ ++/* struct keeping state and type of opener */ ++struct v4l2_loopback_opener { ++ enum opener_type type; ++ int vidioc_enum_frameintervals_calls; ++ int read_position; /* number of last processed frame + 1 or ++ * write_position - 1 if reader went out of sync */ ++ unsigned int reread_count; ++ struct v4l2_buffer *buffers; ++ int buffers_number; /* should not be big, 4 is a good choice */ ++ int timeout_image_io; ++ ++ struct v4l2_fh fh; ++}; ++ ++#define fh_to_opener(ptr) container_of((ptr), struct v4l2_loopback_opener, fh) ++ ++/* this is heavily inspired by the bttv driver found in the linux kernel */ ++struct v4l2l_format { ++ char *name; ++ int fourcc; /* video4linux 2 */ ++ int depth; /* bit/pixel */ ++ int flags; ++}; ++/* set the v4l2l_format.flags to PLANAR for non-packed formats */ ++#define FORMAT_FLAGS_PLANAR 0x01 ++#define FORMAT_FLAGS_COMPRESSED 0x02 ++ ++static const struct v4l2l_format formats[] = { ++#include "v4l2loopback_formats.h" ++}; ++ ++static const unsigned int FORMATS = ARRAY_SIZE(formats); ++ ++static char *fourcc2str(unsigned int fourcc, char buf[4]) ++{ ++ buf[0] = (fourcc >> 0) & 0xFF; ++ buf[1] = (fourcc >> 8) & 0xFF; ++ buf[2] = (fourcc >> 16) & 0xFF; ++ buf[3] = (fourcc >> 24) & 0xFF; ++ ++ return buf; ++} ++ ++static const struct v4l2l_format *format_by_fourcc(int fourcc) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < FORMATS; i++) { ++ if (formats[i].fourcc == fourcc) ++ return formats + i; ++ } ++ ++ dprintk("unsupported format '%c%c%c%c'\n", (fourcc >> 0) & 0xFF, ++ (fourcc >> 8) & 0xFF, (fourcc >> 16) & 0xFF, ++ (fourcc >> 24) & 0xFF); ++ return NULL; ++} ++ ++static void pix_format_set_size(struct v4l2_pix_format *f, ++ const struct v4l2l_format *fmt, ++ unsigned int width, unsigned int height) ++{ ++ f->width = width; ++ f->height = height; ++ ++ if (fmt->flags & FORMAT_FLAGS_PLANAR) { ++ f->bytesperline = width; /* Y plane */ ++ f->sizeimage = (width * height * fmt->depth) >> 3; ++ } else if (fmt->flags & FORMAT_FLAGS_COMPRESSED) { ++ /* doesn't make sense for compressed formats */ ++ f->bytesperline = 0; ++ f->sizeimage = (width * height * fmt->depth) >> 3; ++ } else { ++ f->bytesperline = (width * fmt->depth) >> 3; ++ f->sizeimage = height * f->bytesperline; ++ } ++} ++ ++static int set_timeperframe(struct v4l2_loopback_device *dev, ++ struct v4l2_fract *tpf) ++{ ++ if ((tpf->denominator < 1) || (tpf->numerator < 1)) { ++ return -EINVAL; ++ } ++ dev->capture_param.timeperframe = *tpf; ++ dev->frame_jiffies = max(1UL, msecs_to_jiffies(1000) * tpf->numerator / ++ tpf->denominator); ++ return 0; ++} ++ ++static struct v4l2_loopback_device *v4l2loopback_cd2dev(struct device *cd); ++ ++/* device attributes */ ++/* available via sysfs: /sys/devices/virtual/video4linux/video* */ ++ ++static ssize_t attr_show_format(struct device *cd, ++ struct device_attribute *attr, char *buf) ++{ ++ /* gets the current format as "FOURCC:WxH@f/s", e.g. "YUYV:320x240@1000/30" */ ++ struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd); ++ const struct v4l2_fract *tpf; ++ char buf4cc[5], buf_fps[32]; ++ ++ if (!dev || !dev->ready_for_capture) ++ return 0; ++ tpf = &dev->capture_param.timeperframe; ++ ++ fourcc2str(dev->pix_format.pixelformat, buf4cc); ++ buf4cc[4] = 0; ++ if (tpf->numerator == 1) ++ snprintf(buf_fps, sizeof(buf_fps), "%d", tpf->denominator); ++ else ++ snprintf(buf_fps, sizeof(buf_fps), "%d/%d", tpf->denominator, ++ tpf->numerator); ++ return sprintf(buf, "%4s:%dx%d@%s\n", buf4cc, dev->pix_format.width, ++ dev->pix_format.height, buf_fps); ++} ++ ++static ssize_t attr_store_format(struct device *cd, ++ struct device_attribute *attr, const char *buf, ++ size_t len) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd); ++ int fps_num = 0, fps_den = 1; ++ ++ /* only fps changing is supported */ ++ if (sscanf(buf, "@%d/%d", &fps_num, &fps_den) > 0) { ++ struct v4l2_fract f = { .numerator = fps_den, ++ .denominator = fps_num }; ++ int err = 0; ++ if ((err = set_timeperframe(dev, &f)) < 0) ++ return err; ++ return len; ++ } ++ return -EINVAL; ++} ++ ++static DEVICE_ATTR(format, S_IRUGO | S_IWUSR, attr_show_format, ++ attr_store_format); ++ ++static ssize_t attr_show_buffers(struct device *cd, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd); ++ ++ return sprintf(buf, "%d\n", dev->used_buffers); ++} ++ ++static DEVICE_ATTR(buffers, S_IRUGO, attr_show_buffers, NULL); ++ ++static ssize_t attr_show_maxopeners(struct device *cd, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd); ++ ++ return sprintf(buf, "%d\n", dev->max_openers); ++} ++ ++static ssize_t attr_store_maxopeners(struct device *cd, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ struct v4l2_loopback_device *dev = NULL; ++ unsigned long curr = 0; ++ ++ if (kstrtoul(buf, 0, &curr)) ++ return -EINVAL; ++ ++ dev = v4l2loopback_cd2dev(cd); ++ ++ if (dev->max_openers == curr) ++ return len; ++ ++ if (dev->open_count.counter > curr) { ++ /* request to limit to less openers as are currently attached to us */ ++ return -EINVAL; ++ } ++ ++ dev->max_openers = (int)curr; ++ ++ return len; ++} ++ ++static DEVICE_ATTR(max_openers, S_IRUGO | S_IWUSR, attr_show_maxopeners, ++ attr_store_maxopeners); ++ ++static void v4l2loopback_remove_sysfs(struct video_device *vdev) ++{ ++#define V4L2_SYSFS_DESTROY(x) device_remove_file(&vdev->dev, &dev_attr_##x) ++ ++ if (vdev) { ++ V4L2_SYSFS_DESTROY(format); ++ V4L2_SYSFS_DESTROY(buffers); ++ V4L2_SYSFS_DESTROY(max_openers); ++ /* ... */ ++ } ++} ++ ++static void v4l2loopback_create_sysfs(struct video_device *vdev) ++{ ++ int res = 0; ++ ++#define V4L2_SYSFS_CREATE(x) \ ++ res = device_create_file(&vdev->dev, &dev_attr_##x); \ ++ if (res < 0) \ ++ break ++ if (!vdev) ++ return; ++ do { ++ V4L2_SYSFS_CREATE(format); ++ V4L2_SYSFS_CREATE(buffers); ++ V4L2_SYSFS_CREATE(max_openers); ++ /* ... */ ++ } while (0); ++ ++ if (res >= 0) ++ return; ++ dev_err(&vdev->dev, "%s error: %d\n", __func__, res); ++} ++ ++/* global module data */ ++/* find a device based on it's device-number (e.g. '3' for /dev/video3) */ ++struct v4l2loopback_lookup_cb_data { ++ int device_nr; ++ struct v4l2_loopback_device *device; ++}; ++static int v4l2loopback_lookup_cb(int id, void *ptr, void *data) ++{ ++ struct v4l2_loopback_device *device = ptr; ++ struct v4l2loopback_lookup_cb_data *cbdata = data; ++ if (cbdata && device && device->vdev) { ++ if (device->vdev->num == cbdata->device_nr) { ++ cbdata->device = device; ++ cbdata->device_nr = id; ++ return 1; ++ } ++ } ++ return 0; ++} ++static int v4l2loopback_lookup(int device_nr, ++ struct v4l2_loopback_device **device) ++{ ++ struct v4l2loopback_lookup_cb_data data = { ++ .device_nr = device_nr, ++ .device = NULL, ++ }; ++ int err = idr_for_each(&v4l2loopback_index_idr, &v4l2loopback_lookup_cb, ++ &data); ++ if (1 == err) { ++ if (device) ++ *device = data.device; ++ return data.device_nr; ++ } ++ return -ENODEV; ++} ++static struct v4l2_loopback_device *v4l2loopback_cd2dev(struct device *cd) ++{ ++ struct video_device *loopdev = to_video_device(cd); ++ struct v4l2loopback_private *ptr = ++ (struct v4l2loopback_private *)video_get_drvdata(loopdev); ++ int nr = ptr->device_nr; ++ ++ return idr_find(&v4l2loopback_index_idr, nr); ++} ++ ++static struct v4l2_loopback_device *v4l2loopback_getdevice(struct file *f) ++{ ++ struct video_device *loopdev = video_devdata(f); ++ struct v4l2loopback_private *ptr = ++ (struct v4l2loopback_private *)video_get_drvdata(loopdev); ++ int nr = ptr->device_nr; ++ ++ return idr_find(&v4l2loopback_index_idr, nr); ++} ++ ++/* forward declarations */ ++static void init_buffers(struct v4l2_loopback_device *dev); ++static int allocate_buffers(struct v4l2_loopback_device *dev); ++static int free_buffers(struct v4l2_loopback_device *dev); ++static void try_free_buffers(struct v4l2_loopback_device *dev); ++static int allocate_timeout_image(struct v4l2_loopback_device *dev); ++static void check_timers(struct v4l2_loopback_device *dev); ++static const struct v4l2_file_operations v4l2_loopback_fops; ++static const struct v4l2_ioctl_ops v4l2_loopback_ioctl_ops; ++ ++/* Queue helpers */ ++/* next functions sets buffer flags and adjusts counters accordingly */ ++static inline void set_done(struct v4l2l_buffer *buffer) ++{ ++ buffer->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; ++ buffer->buffer.flags |= V4L2_BUF_FLAG_DONE; ++} ++ ++static inline void set_queued(struct v4l2l_buffer *buffer) ++{ ++ buffer->buffer.flags &= ~V4L2_BUF_FLAG_DONE; ++ buffer->buffer.flags |= V4L2_BUF_FLAG_QUEUED; ++} ++ ++static inline void unset_flags(struct v4l2l_buffer *buffer) ++{ ++ buffer->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; ++ buffer->buffer.flags &= ~V4L2_BUF_FLAG_DONE; ++} ++ ++/* V4L2 ioctl caps and params calls */ ++/* returns device capabilities ++ * called on VIDIOC_QUERYCAP ++ */ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); ++ int labellen = (sizeof(cap->card) < sizeof(dev->card_label)) ? ++ sizeof(cap->card) : ++ sizeof(dev->card_label); ++ int device_nr = ++ ((struct v4l2loopback_private *)video_get_drvdata(dev->vdev)) ++ ->device_nr; ++ __u32 capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; ++ ++ strlcpy(cap->driver, "v4l2 loopback", sizeof(cap->driver)); ++ snprintf(cap->card, labellen, dev->card_label); ++ snprintf(cap->bus_info, sizeof(cap->bus_info), ++ "platform:v4l2loopback-%03d", device_nr); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) ++ /* since 3.1.0, the v4l2-core system is supposed to set the version */ ++ cap->version = V4L2LOOPBACK_VERSION_CODE; ++#endif ++ ++#ifdef V4L2_CAP_VIDEO_M2M ++ capabilities |= V4L2_CAP_VIDEO_M2M; ++#endif /* V4L2_CAP_VIDEO_M2M */ ++ ++ if (dev->announce_all_caps) { ++ capabilities |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT; ++ } else { ++ if (dev->ready_for_capture) { ++ capabilities |= V4L2_CAP_VIDEO_CAPTURE; ++ } ++ if (dev->ready_for_output) { ++ capabilities |= V4L2_CAP_VIDEO_OUTPUT; ++ } ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) ++ dev->vdev->device_caps = ++#endif /* >=linux-4.7.0 */ ++ cap->device_caps = cap->capabilities = capabilities; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) ++ cap->capabilities |= V4L2_CAP_DEVICE_CAPS; ++#endif ++ ++ memset(cap->reserved, 0, sizeof(cap->reserved)); ++ return 0; ++} ++ ++static int vidioc_enum_framesizes(struct file *file, void *fh, ++ struct v4l2_frmsizeenum *argp) ++{ ++ struct v4l2_loopback_device *dev; ++ ++ /* LATER: what does the index really mean? ++ * if it's about enumerating formats, we can safely ignore it ++ * (CHECK) ++ */ ++ ++ /* there can be only one... */ ++ if (argp->index) ++ return -EINVAL; ++ ++ dev = v4l2loopback_getdevice(file); ++ if (dev->ready_for_capture) { ++ /* format has already been negotiated ++ * cannot change during runtime ++ */ ++ argp->type = V4L2_FRMSIZE_TYPE_DISCRETE; ++ ++ argp->discrete.width = dev->pix_format.width; ++ argp->discrete.height = dev->pix_format.height; ++ } else { ++ /* if the format has not been negotiated yet, we accept anything ++ */ ++ argp->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; ++ ++ argp->stepwise.min_width = V4L2LOOPBACK_SIZE_MIN_WIDTH; ++ argp->stepwise.min_height = V4L2LOOPBACK_SIZE_MIN_HEIGHT; ++ ++ argp->stepwise.max_width = dev->max_width; ++ argp->stepwise.max_height = dev->max_height; ++ ++ argp->stepwise.step_width = 1; ++ argp->stepwise.step_height = 1; ++ } ++ return 0; ++} ++ ++/* returns frameinterval (fps) for the set resolution ++ * called on VIDIOC_ENUM_FRAMEINTERVALS ++ */ ++static int vidioc_enum_frameintervals(struct file *file, void *fh, ++ struct v4l2_frmivalenum *argp) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); ++ struct v4l2_loopback_opener *opener = fh_to_opener(fh); ++ ++ if (dev->ready_for_capture) { ++ if (opener->vidioc_enum_frameintervals_calls > 0) ++ return -EINVAL; ++ if (argp->width == dev->pix_format.width && ++ argp->height == dev->pix_format.height) { ++ argp->type = V4L2_FRMIVAL_TYPE_DISCRETE; ++ argp->discrete = dev->capture_param.timeperframe; ++ opener->vidioc_enum_frameintervals_calls++; ++ return 0; ++ } ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/* ------------------ CAPTURE ----------------------- */ ++ ++/* returns device formats ++ * called on VIDIOC_ENUM_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_CAPTURE ++ */ ++static int vidioc_enum_fmt_cap(struct file *file, void *fh, ++ struct v4l2_fmtdesc *f) ++{ ++ struct v4l2_loopback_device *dev; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ ++ if (f->index) ++ return -EINVAL; ++ if (dev->ready_for_capture) { ++ const __u32 format = dev->pix_format.pixelformat; ++ ++ snprintf(f->description, sizeof(f->description), "[%c%c%c%c]", ++ (format >> 0) & 0xFF, (format >> 8) & 0xFF, ++ (format >> 16) & 0xFF, (format >> 24) & 0xFF); ++ ++ f->pixelformat = dev->pix_format.pixelformat; ++ } else { ++ return -EINVAL; ++ } ++ f->flags = 0; ++ MARK(); ++ return 0; ++} ++ ++/* returns current video format format fmt ++ * called on VIDIOC_G_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_CAPTURE ++ */ ++static int vidioc_g_fmt_cap(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ struct v4l2_loopback_device *dev; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ ++ if (!dev->ready_for_capture) ++ return -EINVAL; ++ ++ fmt->fmt.pix = dev->pix_format; ++ MARK(); ++ return 0; ++} ++ ++/* checks if it is OK to change to format fmt; ++ * actual check is done by inner_try_fmt_cap ++ * just checking that pixelformat is OK and set other parameters, app should ++ * obey this decision ++ * called on VIDIOC_TRY_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_CAPTURE ++ */ ++static int vidioc_try_fmt_cap(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ struct v4l2_loopback_device *dev; ++ char buf[5]; ++ ++ dev = v4l2loopback_getdevice(file); ++ ++ if (0 == dev->ready_for_capture) { ++ dprintk("setting fmt_cap not possible yet\n"); ++ return -EBUSY; ++ } ++ ++ if (fmt->fmt.pix.pixelformat != dev->pix_format.pixelformat) ++ return -EINVAL; ++ ++ fmt->fmt.pix = dev->pix_format; ++ ++ buf[4] = 0; ++ dprintk("capFOURCC=%s\n", fourcc2str(dev->pix_format.pixelformat, buf)); ++ return 0; ++} ++ ++/* sets new output format, if possible ++ * actually format is set by input and we even do not check it, just return ++ * current one, but it is possible to set subregions of input TODO(vasaka) ++ * called on VIDIOC_S_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_CAPTURE ++ */ ++static int vidioc_s_fmt_cap(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ return vidioc_try_fmt_cap(file, priv, fmt); ++} ++ ++/* ------------------ OUTPUT ----------------------- */ ++ ++/* returns device formats; ++ * LATER: allow all formats ++ * called on VIDIOC_ENUM_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT ++ */ ++static int vidioc_enum_fmt_out(struct file *file, void *fh, ++ struct v4l2_fmtdesc *f) ++{ ++ struct v4l2_loopback_device *dev; ++ const struct v4l2l_format *fmt; ++ ++ dev = v4l2loopback_getdevice(file); ++ ++ if (dev->ready_for_capture) { ++ const __u32 format = dev->pix_format.pixelformat; ++ ++ /* format has been fixed by the writer, so only one single format is supported */ ++ if (f->index) ++ return -EINVAL; ++ ++ fmt = format_by_fourcc(format); ++ if (NULL == fmt) ++ return -EINVAL; ++ ++ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ /* f->flags = ??; */ ++ snprintf(f->description, sizeof(f->description), "%s", ++ fmt->name); ++ ++ f->pixelformat = dev->pix_format.pixelformat; ++ } else { ++ /* fill in a dummy format */ ++ /* coverity[unsigned_compare] */ ++ if (f->index < 0 || f->index >= FORMATS) ++ return -EINVAL; ++ ++ fmt = &formats[f->index]; ++ ++ f->pixelformat = fmt->fourcc; ++ snprintf(f->description, sizeof(f->description), "%s", ++ fmt->name); ++ } ++ f->flags = 0; ++ ++ return 0; ++} ++ ++/* returns current video format format fmt */ ++/* NOTE: this is called from the producer ++ * so if format has not been negotiated yet, ++ * it should return ALL of available formats, ++ * called on VIDIOC_G_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT ++ */ ++static int vidioc_g_fmt_out(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ struct v4l2_loopback_device *dev; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ ++ /* ++ * LATER: this should return the currently valid format ++ * gstreamer doesn't like it, if this returns -EINVAL, as it ++ * then concludes that there is _no_ valid format ++ * CHECK whether this assumption is wrong, ++ * or whether we have to always provide a valid format ++ */ ++ ++ fmt->fmt.pix = dev->pix_format; ++ return 0; ++} ++ ++/* checks if it is OK to change to format fmt; ++ * if format is negotiated do not change it ++ * called on VIDIOC_TRY_FMT with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT ++ */ ++static int vidioc_try_fmt_out(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ struct v4l2_loopback_device *dev; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ ++ /* TODO(vasaka) loopback does not care about formats writer want to set, ++ * maybe it is a good idea to restrict format somehow */ ++ if (dev->ready_for_capture) { ++ fmt->fmt.pix = dev->pix_format; ++ } else { ++ __u32 w = fmt->fmt.pix.width; ++ __u32 h = fmt->fmt.pix.height; ++ __u32 pixfmt = fmt->fmt.pix.pixelformat; ++ const struct v4l2l_format *format = format_by_fourcc(pixfmt); ++ ++ if (w > dev->max_width) ++ w = dev->max_width; ++ if (h > dev->max_height) ++ h = dev->max_height; ++ ++ dprintk("trying image %dx%d\n", w, h); ++ ++ if (w < 1) ++ w = V4L2LOOPBACK_SIZE_DEFAULT_WIDTH; ++ ++ if (h < 1) ++ h = V4L2LOOPBACK_SIZE_DEFAULT_HEIGHT; ++ ++ if (NULL == format) ++ format = &formats[0]; ++ ++ pix_format_set_size(&fmt->fmt.pix, format, w, h); ++ ++ fmt->fmt.pix.pixelformat = format->fourcc; ++ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; ++ ++ if (V4L2_FIELD_ANY == fmt->fmt.pix.field) ++ fmt->fmt.pix.field = V4L2_FIELD_NONE; ++ ++ /* FIXXME: try_fmt should never modify the device-state */ ++ dev->pix_format = fmt->fmt.pix; ++ } ++ return 0; ++} ++ ++/* sets new output format, if possible; ++ * allocate data here because we do not know if it will be streaming or ++ * read/write IO ++ * called on VIDIOC_S_FMT with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT ++ */ ++static int vidioc_s_fmt_out(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ struct v4l2_loopback_device *dev; ++ char buf[5]; ++ int ret; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ ret = vidioc_try_fmt_out(file, priv, fmt); ++ ++ dprintk("s_fmt_out(%d) %d...%d\n", ret, dev->ready_for_capture, ++ dev->pix_format.sizeimage); ++ ++ buf[4] = 0; ++ dprintk("outFOURCC=%s\n", fourcc2str(dev->pix_format.pixelformat, buf)); ++ ++ if (ret < 0) ++ return ret; ++ ++ if (!dev->ready_for_capture) { ++ dev->buffer_size = PAGE_ALIGN(dev->pix_format.sizeimage); ++ fmt->fmt.pix.sizeimage = dev->buffer_size; ++ allocate_buffers(dev); ++ } ++ return ret; ++} ++ ++// #define V4L2L_OVERLAY ++#ifdef V4L2L_OVERLAY ++/* ------------------ OVERLAY ----------------------- */ ++/* currently unsupported */ ++/* GSTreamer's v4l2sink is buggy, as it requires the overlay to work ++ * while it should only require it, if overlay is requested ++ * once the gstreamer element is fixed, remove the overlay dummies ++ */ ++#warning OVERLAY dummies ++static int vidioc_g_fmt_overlay(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ return 0; ++} ++ ++static int vidioc_s_fmt_overlay(struct file *file, void *priv, ++ struct v4l2_format *fmt) ++{ ++ return 0; ++} ++#endif /* V4L2L_OVERLAY */ ++ ++/* ------------------ PARAMs ----------------------- */ ++ ++/* get some data flow parameters, only capability, fps and readbuffers has ++ * effect on this driver ++ * called on VIDIOC_G_PARM ++ */ ++static int vidioc_g_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *parm) ++{ ++ /* do not care about type of opener, hope these enums would always be ++ * compatible */ ++ struct v4l2_loopback_device *dev; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ parm->parm.capture = dev->capture_param; ++ return 0; ++} ++ ++/* get some data flow parameters, only capability, fps and readbuffers has ++ * effect on this driver ++ * called on VIDIOC_S_PARM ++ */ ++static int vidioc_s_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *parm) ++{ ++ struct v4l2_loopback_device *dev; ++ int err = 0; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ dprintk("vidioc_s_parm called frate=%d/%d\n", ++ parm->parm.capture.timeperframe.numerator, ++ parm->parm.capture.timeperframe.denominator); ++ ++ switch (parm->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ if ((err = set_timeperframe( ++ dev, &parm->parm.capture.timeperframe)) < 0) ++ return err; ++ break; ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ if ((err = set_timeperframe( ++ dev, &parm->parm.capture.timeperframe)) < 0) ++ return err; ++ break; ++ default: ++ return -1; ++ } ++ ++ parm->parm.capture = dev->capture_param; ++ return 0; ++} ++ ++#ifdef V4L2LOOPBACK_WITH_STD ++/* sets a tv standard, actually we do not need to handle this any special way ++ * added to support effecttv ++ * called on VIDIOC_S_STD ++ */ ++static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *_std) ++{ ++ v4l2_std_id req_std = 0, supported_std = 0; ++ const v4l2_std_id all_std = V4L2_STD_ALL, no_std = 0; ++ ++ if (_std) { ++ req_std = *_std; ++ *_std = all_std; ++ } ++ ++ /* we support everything in V4L2_STD_ALL, but not more... */ ++ supported_std = (all_std & req_std); ++ if (no_std == supported_std) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/* gets a fake video standard ++ * called on VIDIOC_G_STD ++ */ ++static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) ++{ ++ if (norm) ++ *norm = V4L2_STD_ALL; ++ return 0; ++} ++/* gets a fake video standard ++ * called on VIDIOC_QUERYSTD ++ */ ++static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *norm) ++{ ++ if (norm) ++ *norm = V4L2_STD_ALL; ++ return 0; ++} ++#endif /* V4L2LOOPBACK_WITH_STD */ ++ ++/* get ctrls info ++ * called on VIDIOC_QUERYCTRL ++ */ ++static int vidioc_queryctrl(struct file *file, void *fh, ++ struct v4l2_queryctrl *q) ++{ ++ const struct v4l2_ctrl_config *cnf = 0; ++ switch (q->id) { ++ case CID_KEEP_FORMAT: ++ cnf = &v4l2loopback_ctrl_keepformat; ++ break; ++ case CID_SUSTAIN_FRAMERATE: ++ cnf = &v4l2loopback_ctrl_sustainframerate; ++ break; ++ case CID_TIMEOUT: ++ cnf = &v4l2loopback_ctrl_timeout; ++ break; ++ case CID_TIMEOUT_IMAGE_IO: ++ cnf = &v4l2loopback_ctrl_timeoutimageio; ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (!cnf) ++ BUG(); ++ ++ strcpy(q->name, cnf->name); ++ q->default_value = cnf->def; ++ q->type = cnf->type; ++ q->minimum = cnf->min; ++ q->maximum = cnf->max; ++ q->step = cnf->step; ++ ++ memset(q->reserved, 0, sizeof(q->reserved)); ++ return 0; ++} ++ ++static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); ++ ++ switch (c->id) { ++ case CID_KEEP_FORMAT: ++ c->value = dev->keep_format; ++ break; ++ case CID_SUSTAIN_FRAMERATE: ++ c->value = dev->sustain_framerate; ++ break; ++ case CID_TIMEOUT: ++ c->value = jiffies_to_msecs(dev->timeout_jiffies); ++ break; ++ case CID_TIMEOUT_IMAGE_IO: ++ c->value = dev->timeout_image_io; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int v4l2loopback_set_ctrl(struct v4l2_loopback_device *dev, u32 id, ++ s64 val) ++{ ++ switch (id) { ++ case CID_KEEP_FORMAT: ++ if (val < 0 || val > 1) ++ return -EINVAL; ++ dev->keep_format = val; ++ try_free_buffers(dev); /* will only free buffers if !keep_format */ ++ break; ++ case CID_SUSTAIN_FRAMERATE: ++ if (val < 0 || val > 1) ++ return -EINVAL; ++ spin_lock_bh(&dev->lock); ++ dev->sustain_framerate = val; ++ check_timers(dev); ++ spin_unlock_bh(&dev->lock); ++ break; ++ case CID_TIMEOUT: ++ if (val < 0 || val > MAX_TIMEOUT) ++ return -EINVAL; ++ spin_lock_bh(&dev->lock); ++ dev->timeout_jiffies = msecs_to_jiffies(val); ++ check_timers(dev); ++ spin_unlock_bh(&dev->lock); ++ allocate_timeout_image(dev); ++ break; ++ case CID_TIMEOUT_IMAGE_IO: ++ if (val < 0 || val > 1) ++ return -EINVAL; ++ dev->timeout_image_io = val; ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int v4l2loopback_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_loopback_device *dev = container_of( ++ ctrl->handler, struct v4l2_loopback_device, ctrl_handler); ++ return v4l2loopback_set_ctrl(dev, ctrl->id, ctrl->val); ++} ++static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); ++ return v4l2loopback_set_ctrl(dev, c->id, c->value); ++} ++ ++/* returns set of device outputs, in our case there is only one ++ * called on VIDIOC_ENUMOUTPUT ++ */ ++static int vidioc_enum_output(struct file *file, void *fh, ++ struct v4l2_output *outp) ++{ ++ __u32 index = outp->index; ++ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); ++ MARK(); ++ ++ if (!dev->announce_all_caps && !dev->ready_for_output) ++ return -ENOTTY; ++ ++ if (0 != index) ++ return -EINVAL; ++ ++ /* clear all data (including the reserved fields) */ ++ memset(outp, 0, sizeof(*outp)); ++ ++ outp->index = index; ++ strlcpy(outp->name, "loopback in", sizeof(outp->name)); ++ outp->type = V4L2_OUTPUT_TYPE_ANALOG; ++ outp->audioset = 0; ++ outp->modulator = 0; ++#ifdef V4L2LOOPBACK_WITH_STD ++ outp->std = V4L2_STD_ALL; ++#ifdef V4L2_OUT_CAP_STD ++ outp->capabilities |= V4L2_OUT_CAP_STD; ++#endif /* V4L2_OUT_CAP_STD */ ++#endif /* V4L2LOOPBACK_WITH_STD */ ++ ++ return 0; ++} ++ ++/* which output is currently active, ++ * called on VIDIOC_G_OUTPUT ++ */ ++static int vidioc_g_output(struct file *file, void *fh, unsigned int *i) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); ++ if (!dev->announce_all_caps && !dev->ready_for_output) ++ return -ENOTTY; ++ if (i) ++ *i = 0; ++ return 0; ++} ++ ++/* set output, can make sense if we have more than one video src, ++ * called on VIDIOC_S_OUTPUT ++ */ ++static int vidioc_s_output(struct file *file, void *fh, unsigned int i) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); ++ if (!dev->announce_all_caps && !dev->ready_for_output) ++ return -ENOTTY; ++ ++ if (i) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/* returns set of device inputs, in our case there is only one, ++ * but later I may add more ++ * called on VIDIOC_ENUMINPUT ++ */ ++static int vidioc_enum_input(struct file *file, void *fh, ++ struct v4l2_input *inp) ++{ ++ __u32 index = inp->index; ++ MARK(); ++ ++ if (0 != index) ++ return -EINVAL; ++ ++ /* clear all data (including the reserved fields) */ ++ memset(inp, 0, sizeof(*inp)); ++ ++ inp->index = index; ++ strlcpy(inp->name, "loopback", sizeof(inp->name)); ++ inp->type = V4L2_INPUT_TYPE_CAMERA; ++ inp->audioset = 0; ++ inp->tuner = 0; ++ inp->status = 0; ++ ++#ifdef V4L2LOOPBACK_WITH_STD ++ inp->std = V4L2_STD_ALL; ++#ifdef V4L2_IN_CAP_STD ++ inp->capabilities |= V4L2_IN_CAP_STD; ++#endif ++#endif /* V4L2LOOPBACK_WITH_STD */ ++ ++ return 0; ++} ++ ++/* which input is currently active, ++ * called on VIDIOC_G_INPUT ++ */ ++static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); ++ if (!dev->announce_all_caps && !dev->ready_for_capture) ++ return -ENOTTY; ++ if (i) ++ *i = 0; ++ return 0; ++} ++ ++/* set input, can make sense if we have more than one video src, ++ * called on VIDIOC_S_INPUT ++ */ ++static int vidioc_s_input(struct file *file, void *fh, unsigned int i) ++{ ++ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); ++ if (!dev->announce_all_caps && !dev->ready_for_capture) ++ return -ENOTTY; ++ if (i == 0) ++ return 0; ++ return -EINVAL; ++} ++ ++/* --------------- V4L2 ioctl buffer related calls ----------------- */ ++ ++/* negotiate buffer type ++ * only mmap streaming supported ++ * called on VIDIOC_REQBUFS ++ */ ++static int vidioc_reqbufs(struct file *file, void *fh, ++ struct v4l2_requestbuffers *b) ++{ ++ struct v4l2_loopback_device *dev; ++ struct v4l2_loopback_opener *opener; ++ int i; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ opener = fh_to_opener(fh); ++ dev->gen_timestamp = 0; ++ ++ dprintk("reqbufs: %d\t%d=%d\n", b->memory, b->count, ++ dev->buffers_number); ++ if (opener->timeout_image_io) { ++ if (b->memory != V4L2_MEMORY_MMAP) ++ return -EINVAL; ++ b->count = 1; ++ return 0; ++ } ++ ++ INIT_LIST_HEAD(&dev->queued_list); ++ INIT_LIST_HEAD(&dev->done_list); ++ ++ switch (b->memory) { ++ case V4L2_MEMORY_MMAP: ++ /* do nothing here, buffers are always allocated */ ++ if (b->count < 1 || dev->buffers_number < 1) ++ return 0; ++ ++ ++ if(b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ++ if(b->count > dev->used_buffers) { ++ b->count = dev->used_buffers; ++ } ++ } else { ++ /*OUTPUT*/ ++ if (b->count > dev->buffers_number) ++ b->count = dev->buffers_number; ++ ++ } ++ ++#if 0 ++ /* make sure that outbufs_list contains buffers from 0 to used_buffers-1 ++ * actually, it will have been already populated via v4l2_loopback_init() ++ * at this point */ ++ if (list_empty(&dev->outbufs_list)) { ++ for (i = 0; i < dev->used_buffers; ++i) ++ list_add_tail(&dev->buffers[i].list_head, ++ &dev->outbufs_list); ++ } ++#endif ++ ++#if 0 ++ ++ /* also, if dev->used_buffers is going to be decreased, we should remove ++ * out-of-range buffers from outbufs_list, and fix bufpos2index mapping */ ++ if (b->count < dev->used_buffers) { ++ struct v4l2l_buffer *pos, *n; ++ ++ list_for_each_entry_safe (pos, n, &dev->outbufs_list, ++ list_head) { ++ if (pos->buffer.index >= b->count) ++ list_del(&pos->list_head); ++ } ++ ++ /* after we update dev->used_buffers, buffers in outbufs_list will ++ * correspond to dev->write_position + [0;b->count-1] range */ ++ i = dev->write_position; ++ list_for_each_entry (pos, &dev->outbufs_list, ++ list_head) { ++ dev->bufpos2index[i % b->count] = ++ pos->buffer.index; ++ ++i; ++ } ++ } ++#endif ++ opener->buffers_number = b->count; ++ if (opener->buffers_number < dev->used_buffers) ++ dev->used_buffers = opener->buffers_number; ++ ++ init_buffers(dev); ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++/* returns buffer asked for; ++ * give app as many buffers as it wants, if it less than MAX, ++ * but map them in our inner buffers ++ * called on VIDIOC_QUERYBUF ++ */ ++static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) ++{ ++ enum v4l2_buf_type type; ++ int index; ++ struct v4l2_loopback_device *dev; ++ struct v4l2_loopback_opener *opener; ++ ++ MARK(); ++ ++ type = b->type; ++ index = b->index; ++ dev = v4l2loopback_getdevice(file); ++ opener = fh_to_opener(fh); ++ ++ if ((b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && ++ (b->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) { ++ return -EINVAL; ++ } ++ if (b->index > max_buffers) ++ return -EINVAL; ++ ++ if (opener->timeout_image_io) ++ *b = dev->timeout_image_buffer.buffer; ++ else ++ *b = dev->buffers[b->index % dev->used_buffers].buffer; ++ ++ b->type = type; ++ b->index = index; ++ dprintkrw("buffer type: %d (of %d with size=%ld)\n", b->memory, ++ dev->buffers_number, dev->buffer_size); ++ ++ /* Hopefully fix 'DQBUF return bad index if queue bigger then 2 for capture' ++ https://github.com/umlaeute/v4l2loopback/issues/60 */ ++ b->flags &= ~V4L2_BUF_FLAG_DONE; ++ b->flags |= V4L2_BUF_FLAG_QUEUED; ++ ++ return 0; ++} ++ ++static void buffer_written(struct v4l2_loopback_device *dev, ++ struct v4l2l_buffer *buf) ++{ ++ del_timer_sync(&dev->sustain_timer); ++ del_timer_sync(&dev->timeout_timer); ++ spin_lock_bh(&dev->lock); ++ ++ dev->bufpos2index[dev->write_position % dev->used_buffers] = ++ buf->buffer.index; ++ list_move_tail(&buf->list_head, &dev->outbufs_list); ++ ++dev->write_position; ++ dev->reread_count = 0; ++ ++ check_timers(dev); ++ spin_unlock_bh(&dev->lock); ++} ++ ++/* put buffer to queue ++ * called on VIDIOC_QBUF ++ */ ++static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) ++{ ++ struct v4l2_loopback_device *dev; ++ struct v4l2_loopback_opener *opener; ++ struct v4l2l_buffer *b; ++ int index; ++ unsigned long flags; ++ ++ dev = v4l2loopback_getdevice(file); ++ opener = fh_to_opener(fh); ++ ++ if (buf->index > max_buffers) ++ return -EINVAL; ++ if (opener->timeout_image_io) ++ return 0; ++ ++ index = buf->index % dev->used_buffers; ++ b = &dev->buffers[index]; ++ ++ switch (buf->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ ++ spin_lock_irqsave(&dev->done_lock, flags); ++ set_queued(b); ++ list_add_tail(&b->list_head, &dev->queued_list); ++ spin_unlock_irqrestore(&dev->done_lock, flags); ++ ++ dprintkrw("[capture] qbuf: %d, b: %x, add_to queued_list.\n", buf->index, b); ++ return 0; ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ ++ if(!(b->buffer.flags & V4L2_BUF_FLAG_QUEUED)) { ++ printk("[output] qbuf [%d] without V4L2_BUF_FLAG_QUEUED.\n", b->buffer.index); ++ return -EINVAL; ++ } ++ ++ v4l2l_get_timestamp(&b->buffer); ++ b->buffer.bytesused = buf->bytesused; ++ b->buffer.sequence = dev->output_sequence ++; ++ ++ spin_lock_irqsave(&dev->done_lock, flags); ++ set_done(b); ++ list_add_tail(&b->list_head, &dev->done_list); ++ ++ dprintkrw("[output] qbuf: %d, b: %x, add_to done_list\n", b->buffer.index, b); ++ spin_unlock_irqrestore(&dev->done_lock, flags); ++ ++ wake_up_all(&dev->read_event); ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int can_read(struct v4l2_loopback_device *dev, ++ struct v4l2_loopback_opener *opener) ++{ ++ int ret = 0; ++ ++ ret = (!list_empty(&dev->done_list) || dev->ready_for_output); ++ ++ return ret; ++} ++ ++/* put buffer to dequeue ++ * called on VIDIOC_DQBUF ++ */ ++static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) ++{ ++ struct v4l2_loopback_device *dev; ++ struct v4l2_loopback_opener *opener; ++ int index; ++ struct v4l2l_buffer *b; ++ unsigned long flags; ++ ++ dev = v4l2loopback_getdevice(file); ++ opener = fh_to_opener(fh); ++ if (opener->timeout_image_io) { ++ *buf = dev->timeout_image_buffer.buffer; ++ return 0; ++ } ++ ++ switch (buf->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ ++ wait_event_interruptible(dev->read_event, (!list_empty(&dev->done_list) || dev->ready_for_output)); ++ if(dev->ready_for_output) { ++ printk("output is not streaming!\n"); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&dev->done_lock, flags); ++ ++ b = list_first_entry_or_null(&dev->done_list, struct v4l2l_buffer, list_head); ++ ++ if(!b) { ++ printk("no available buffer on done_list.!\n"); ++ spin_unlock_irqrestore(&dev->done_lock, flags); ++ return -EINVAL; ++ } ++ ++ /*remove from done list*/ ++ list_del(&b->list_head); ++ ++ unset_flags(b); ++ *buf = b->buffer; //dev->buffers[index].buffer; ++ spin_unlock_irqrestore(&dev->done_lock, flags); ++ ++ dprintkrw("[capture] [dbuf: %x index: %d - %d userptr: %x]: tv_sec: %d, tv_usec: %d, sequence: %d\n", b, index, buf->index, buf->m.userptr, buf->timestamp.tv_sec, buf->timestamp.tv_usec, buf->sequence); ++ return 0; ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ ++ spin_lock_irqsave(&dev->done_lock, flags); ++ b = list_first_entry_or_null(&dev->queued_list, struct v4l2l_buffer, list_head); ++ if(!b) { ++ spin_unlock_irqrestore(&dev->done_lock, flags); ++ return -EINVAL; ++ } ++ ++ dprintkrw("[output] dqbuf get b: %x, b->buffer.index: %d, b->buffer.flags: %x\n", b, b->buffer.index, b->buffer.flags); ++ ++ list_del(&b->list_head); ++ spin_unlock_irqrestore(&dev->done_lock, flags); ++ ++ *buf = b->buffer; ++ buf->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++/* ------------- STREAMING ------------------- */ ++ ++/* start streaming ++ * called on VIDIOC_STREAMON ++ */ ++static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type type) ++{ ++ struct v4l2_loopback_device *dev; ++ struct v4l2_loopback_opener *opener; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ opener = fh_to_opener(fh); ++ ++ switch (type) { ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ opener->type = WRITER; ++ dev->ready_for_output = 0; ++ if (!dev->ready_for_capture) { ++ int ret = allocate_buffers(dev); ++ if (ret < 0) ++ return ret; ++ } ++ dev->ready_for_capture++; ++ return 0; ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ opener->type = READER; ++ if (!dev->ready_for_capture) ++ return -EIO; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++/* stop streaming ++ * called on VIDIOC_STREAMOFF ++ */ ++static int vidioc_streamoff(struct file *file, void *fh, ++ enum v4l2_buf_type type) ++{ ++ struct v4l2_loopback_device *dev; ++ MARK(); ++ dprintk("%d\n", type); ++ ++ dev = v4l2loopback_getdevice(file); ++ ++ switch (type) { ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ if (dev->ready_for_capture > 0) ++ dev->ready_for_capture--; ++ return 0; ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ return 0; ++ default: ++ return -EINVAL; ++ } ++ return -EINVAL; ++} ++ ++#ifdef CONFIG_VIDEO_V4L1_COMPAT ++static int vidiocgmbuf(struct file *file, void *fh, struct video_mbuf *p) ++{ ++ struct v4l2_loopback_device *dev; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ p->frames = dev->buffers_number; ++ p->offsets[0] = 0; ++ p->offsets[1] = 0; ++ p->size = dev->buffer_size; ++ return 0; ++} ++#endif ++ ++static int vidioc_subscribe_event(struct v4l2_fh *fh, ++ const struct v4l2_event_subscription *sub) ++{ ++ switch (sub->type) { ++ case V4L2_EVENT_CTRL: ++ return v4l2_ctrl_subscribe_event(fh, sub); ++ } ++ ++ return -EINVAL; ++} ++ ++/* file operations */ ++static void vm_open(struct vm_area_struct *vma) ++{ ++ struct v4l2l_buffer *buf; ++ MARK(); ++ ++ buf = vma->vm_private_data; ++ buf->use_count++; ++} ++ ++static void vm_close(struct vm_area_struct *vma) ++{ ++ struct v4l2l_buffer *buf; ++ MARK(); ++ ++ buf = vma->vm_private_data; ++ buf->use_count--; ++} ++ ++static struct vm_operations_struct vm_ops = { ++ .open = vm_open, ++ .close = vm_close, ++}; ++ ++#ifdef USING_DMA_ALLOC_BUFFER ++static int dma_mmap_noncoherent(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size) ++{ ++ int ret = -ENXIO; ++ unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; ++ unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; ++ unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr)); ++ unsigned long off = vma->vm_pgoff; ++ ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++ pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; ++ ++ if (off < count && user_count <= (count - off)) { ++ ++ ret = remap_pfn_range(vma, vma->vm_start, ++ pfn + off, ++ user_count << PAGE_SHIFT, ++ vma->vm_page_prot); ++ } ++ ++ return ret; ++} ++#endif ++ ++static int v4l2_loopback_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ unsigned long addr; ++ unsigned long addr_p; ++ unsigned long start; ++ unsigned long size; ++ struct v4l2_loopback_device *dev; ++ struct v4l2_loopback_opener *opener; ++ struct v4l2l_buffer *buffer = NULL; ++ int ret = 0; ++ MARK(); ++ ++ start = (unsigned long)vma->vm_start; ++ size = (unsigned long)(vma->vm_end - vma->vm_start); ++ ++ dev = v4l2loopback_getdevice(file); ++ opener = fh_to_opener(file->private_data); ++ ++ if (size > dev->buffer_size) { ++ dprintk("userspace tries to mmap too much, fail\n"); ++ return -EINVAL; ++ } ++ if (opener->timeout_image_io) { ++ /* we are going to map the timeout_image_buffer */ ++ if ((vma->vm_pgoff << PAGE_SHIFT) != ++ dev->buffer_size * MAX_BUFFERS) { ++ dprintk("invalid mmap offset for timeout_image_io mode\n"); ++ return -EINVAL; ++ } ++ } else if ((vma->vm_pgoff << PAGE_SHIFT) > ++ dev->buffer_size * (dev->buffers_number - 1)) { ++ dprintk("userspace tries to mmap too far, fail\n"); ++ return -EINVAL; ++ } ++ ++ /* FIXXXXXME: allocation should not happen here! */ ++ if (NULL == dev->image) ++ if (allocate_buffers(dev) < 0) ++ return -EINVAL; ++ ++ if (opener->timeout_image_io) { ++ buffer = &dev->timeout_image_buffer; ++ addr = (unsigned long)dev->timeout_image; ++ } else { ++ int i; ++ for (i = 0; i < dev->buffers_number; ++i) { ++ buffer = &dev->buffers[i]; ++ if ((buffer->buffer.m.offset >> PAGE_SHIFT) == ++ vma->vm_pgoff) ++ break; ++ } ++ ++ if (NULL == buffer) ++ return -EINVAL; ++ ++ addr = (unsigned long)dev->image + ++ (vma->vm_pgoff << PAGE_SHIFT); ++#ifdef USING_DMA_ALLOC_BUFFER ++ // TODO: ++ addr_p = (unsigned long)dev->image_paddr + (vma->vm_pgoff << PAGE_SHIFT); ++#endif ++ } ++ ++#ifdef USING_DMA_ALLOC_BUFFER ++ vma->vm_pgoff = 0; ++ ret = dma_mmap_noncoherent(&dev->vdev->dev, vma, addr, addr_p, size); ++ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; ++ //printk("-----%s, %d addr:%x, dma_addr: %x size: %d, start:%x vma->vm_pgoff: %d, ret: %d\n", __func__, __LINE__, addr, addr_p, size, start, vma->vm_pgoff, ret); ++#else ++ while (size > 0) { ++ struct page *page; ++ ++ page = (void *)vmalloc_to_page((void *)addr); ++ ++ if (vm_insert_page(vma, start, page) < 0) ++ return -EAGAIN; ++ ++ start += PAGE_SIZE; ++ addr += PAGE_SIZE; ++ size -= PAGE_SIZE; ++ } ++#endif ++ vma->vm_ops = &vm_ops; ++ vma->vm_private_data = buffer; ++ buffer->buffer.flags |= V4L2_BUF_FLAG_MAPPED; ++ ++ vm_open(vma); ++ ++ MARK(); ++ return 0; ++} ++ ++static unsigned int v4l2_loopback_poll(struct file *file, ++ struct poll_table_struct *pts) ++{ ++ struct v4l2_loopback_opener *opener; ++ struct v4l2_loopback_device *dev; ++ __poll_t req_events = poll_requested_events(pts); ++ int ret_mask = 0; ++ MARK(); ++ ++ opener = fh_to_opener(file->private_data); ++ dev = v4l2loopback_getdevice(file); ++ ++ if (req_events & POLLPRI) { ++ if (!v4l2_event_pending(&opener->fh)) ++ poll_wait(file, &opener->fh.wait, pts); ++ if (v4l2_event_pending(&opener->fh)) { ++ ret_mask |= POLLPRI; ++ if (!(req_events & DEFAULT_POLLMASK)) ++ return ret_mask; ++ } ++ } ++ ++ switch (opener->type) { ++ case WRITER: ++ ret_mask |= POLLOUT | POLLWRNORM; ++ break; ++ case READER: ++ if (!can_read(dev, opener)) { ++ if (ret_mask) ++ return ret_mask; ++ poll_wait(file, &dev->read_event, pts); ++ } ++ if (can_read(dev, opener)) ++ ret_mask |= POLLIN | POLLRDNORM; ++ if (v4l2_event_pending(&opener->fh)) ++ ret_mask |= POLLPRI; ++ break; ++ default: ++ break; ++ } ++ ++ MARK(); ++ return ret_mask; ++} ++ ++/* do not want to limit device opens, it can be as many readers as user want, ++ * writers are limited by means of setting writer field */ ++static int v4l2_loopback_open(struct file *file) ++{ ++ struct v4l2_loopback_device *dev; ++ struct v4l2_loopback_opener *opener; ++ MARK(); ++ dev = v4l2loopback_getdevice(file); ++ if (dev->open_count.counter >= dev->max_openers) ++ return -EBUSY; ++ /* kfree on close */ ++ opener = kzalloc(sizeof(*opener), GFP_KERNEL); ++ if (opener == NULL) ++ return -ENOMEM; ++ ++ v4l2_fh_init(&opener->fh, video_devdata(file)); ++ file->private_data = &opener->fh; ++ atomic_inc(&dev->open_count); ++ ++ opener->timeout_image_io = dev->timeout_image_io; ++ dev->timeout_image_io = 0; ++ ++ if (opener->timeout_image_io) { ++ int r = allocate_timeout_image(dev); ++ ++ if (r < 0) { ++ dprintk("timeout image allocation failed\n"); ++ return r; ++ } ++ } ++ ++ v4l2_fh_add(&opener->fh); ++ dprintk("opened dev:%p with image:%p\n", dev, dev ? dev->image : NULL); ++ MARK(); ++ return 0; ++} ++ ++static int v4l2_loopback_close(struct file *file) ++{ ++ struct v4l2_loopback_opener *opener; ++ struct v4l2_loopback_device *dev; ++ int iswriter = 0; ++ MARK(); ++ ++ opener = fh_to_opener(file->private_data); ++ dev = v4l2loopback_getdevice(file); ++ ++ if (WRITER == opener->type) ++ iswriter = 1; ++ ++ atomic_dec(&dev->open_count); ++ if (dev->open_count.counter == 0) { ++ del_timer_sync(&dev->sustain_timer); ++ del_timer_sync(&dev->timeout_timer); ++ } ++ try_free_buffers(dev); ++ ++ v4l2_fh_del(&opener->fh); ++ v4l2_fh_exit(&opener->fh); ++ ++ kfree(opener); ++ if (iswriter) { ++ dev->ready_for_output = 1; ++ /*try to wakeup all readers. */ ++ wake_up_all(&dev->read_event); ++ } ++ MARK(); ++ return 0; ++} ++ ++static ssize_t v4l2_loopback_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ int read_index; ++ struct v4l2_loopback_device *dev; ++ struct v4l2l_buffer *b; ++ unsigned long flags; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ //TODO. not support ++#if 0 ++ ++ /* ++ * for capture stream: ++ * ++ * 1. get done buffer from done list? ++ * ++ * 2. memcpy from done buffer. ++ * ++ * 3. put it back to queued list? ++ * ++ * ++ * */ ++ wait_event_interruptible(dev->read_event, !list_empty(&dev->read_list)); ++ ++ spin_lock_irqsave(&dev->read_write_lock, flags); ++ ++ b = list_first_entry_or_null(&dev->read_list, struct v4l2l_buffer, list_head); ++ ++ if(!b) { ++ printk("error no buffer on read list.!\n"); ++ //TODO: ++ } ++ list_del(&b->list_head); ++ ++ spin_unlock_irqrestore(&dev->read_write_lock, flags); ++ ++ if (count > b->bytesused) ++ count = b->bytesused; ++ if (copy_to_user((void *)buf, (void *)(dev->image + b->m.offset), ++ count)) { ++ printk(KERN_ERR ++ "v4l2-loopback: failed copy_to_user() in read buf\n"); ++ return -EFAULT; ++ } ++ ++ // give back buffer to write list. ++ list_add_tail(&b->list_head, &dev->write_list); ++#endif ++ dprintkrw("leave v4l2_loopback_read()\n"); ++ return count; ++} ++ ++static ssize_t v4l2_loopback_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct v4l2_loopback_device *dev; ++ int write_index; ++ struct v4l2l_buffer *b; ++ unsigned flags; ++ MARK(); ++ ++ dev = v4l2loopback_getdevice(file); ++ ++ /* there's at least one writer, so don't stop announcing output capabilities */ ++ dev->ready_for_output = 0; ++ ++ if (!dev->ready_for_capture) { ++ int ret = allocate_buffers(dev); ++ if (ret < 0) ++ return ret; ++ dev->ready_for_capture = 1; ++ } ++ dprintkrw("v4l2_loopback_write() trying to write %zu bytes\n", count); ++ if (count > dev->buffer_size) ++ count = dev->buffer_size; ++ ++ spin_lock_irqsave(&dev->done_lock, flags); ++ ++ b = list_first_entry_or_null(&dev->queued_list, struct v4l2l_buffer, list_head); ++ ++ if(!b) { ++ // ++ spin_unlock_irqrestore(&dev->done_lock, flags); ++ return count; //direct return. ++ } ++ ++ list_del(&b->list_head); ++ ++ spin_unlock_irqrestore(&dev->done_lock, flags); ++ ++ if (copy_from_user((void *)(dev->image + b->buffer.m.offset), (void *)buf, ++ count)) { ++ printk(KERN_ERR ++ "v4l2-loopback: failed copy_from_user() in write buf, could not write %zu\n", ++ count); ++ return -EFAULT; ++ } ++ ++ // update timestamp. ++ v4l2l_get_timestamp(&b->buffer); ++ b->buffer.bytesused = count; ++ b->buffer.sequence = dev->output_sequence ++; //TODO: ++ set_done(b); ++ ++ list_add_tail(&b->list_head, &dev->done_list); ++ ++ wake_up_all(&dev->read_event); ++ dprintkrw("leave v4l2_loopback_write()\n"); ++ return count; ++} ++ ++/* init functions */ ++/* frees buffers, if already allocated */ ++static int free_buffers(struct v4l2_loopback_device *dev) ++{ ++ MARK(); ++ dprintk("freeing image@%p for dev:%p\n", dev ? dev->image : NULL, dev); ++ if (dev->image) { ++#ifdef USING_DMA_ALLOC_BUFFER ++ dma_free_noncoherent(&dev->vdev->dev, dev->imagesize, dev->image, dev->image_paddr); ++#else ++ vfree(dev->image); ++#endif ++ dev->image = NULL; ++ } ++ if (dev->timeout_image) { ++ vfree(dev->timeout_image); ++ dev->timeout_image = NULL; ++ } ++ dev->imagesize = 0; ++ ++ return 0; ++} ++/* frees buffers, if they are no longer needed */ ++static void try_free_buffers(struct v4l2_loopback_device *dev) ++{ ++ MARK(); ++ if (0 == dev->open_count.counter && !dev->keep_format) { ++ free_buffers(dev); ++ dev->ready_for_capture = 0; ++ dev->buffer_size = 0; ++ dev->write_position = 0; ++ } ++} ++/* allocates buffers, if buffer_size is set */ ++static int allocate_buffers(struct v4l2_loopback_device *dev) ++{ ++ MARK(); ++ /* vfree on close file operation in case no open handles left */ ++ if (0 == dev->buffer_size) ++ return -EINVAL; ++ ++ if (dev->image) { ++ dprintk("allocating buffers again: %ld %ld\n", ++ dev->buffer_size * dev->buffers_number, dev->imagesize); ++ /* FIXME: prevent double allocation more intelligently! */ ++ if (dev->buffer_size * dev->buffers_number == dev->imagesize) ++ return 0; ++ ++ /* if there is only one writer, no problem should occur */ ++ if (dev->open_count.counter == 1) ++ free_buffers(dev); ++ else ++ return -EINVAL; ++ } ++ ++ dev->imagesize = dev->buffer_size * dev->buffers_number; ++ ++ dprintk("allocating %ld = %ldx%d\n", dev->imagesize, dev->buffer_size, ++ dev->buffers_number); ++ ++#ifdef USING_DMA_ALLOC_BUFFER ++ dev->image = dma_alloc_noncoherent(&dev->vdev->dev, dev->imagesize, &dev->image_paddr, GFP_KERNEL); ++#else ++ dev->image = vmalloc(dev->imagesize); ++#endif ++ if (dev->timeout_jiffies > 0) ++ allocate_timeout_image(dev); ++ ++ if (dev->image == NULL) ++ return -ENOMEM; ++ dprintk("vmallocated %ld bytes\n", dev->imagesize); ++ MARK(); ++ ++ dev->output_sequence = 0; ++ //init_buffers(dev); ++ return 0; ++} ++ ++/* init inner buffers, they are capture mode and flags are set as ++ * for capture mod buffers */ ++static void init_buffers(struct v4l2_loopback_device *dev) ++{ ++ int i; ++ int buffer_size; ++ int bytesused; ++ MARK(); ++ ++ buffer_size = dev->buffer_size; ++ bytesused = dev->pix_format.sizeimage; ++ ++ for (i = 0; i < dev->buffers_number; ++i) { ++ struct v4l2_buffer *b = &dev->buffers[i].buffer; ++ b->index = i; ++ b->bytesused = bytesused; ++ b->length = buffer_size; ++ b->field = V4L2_FIELD_NONE; ++ // b->flags = 0; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 1) ++ b->input = 0; ++#endif ++ b->m.offset = i * buffer_size; ++ b->memory = V4L2_MEMORY_MMAP; ++ b->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++#if 0 ++ /*dev->buffers 作为output å’Œ capture å…±åŒæ“作的数æ®, æ˜¯ä¸æ˜¯åº”该加é”处ç†????*/ ++ b->sequence = 0; ++ b->timestamp.tv_sec = 0; ++ b->timestamp.tv_usec = 0; ++ ++ v4l2l_get_timestamp(b); ++#endif ++ } ++ dev->timeout_image_buffer = dev->buffers[0]; ++ dev->timeout_image_buffer.buffer.m.offset = MAX_BUFFERS * buffer_size; ++ MARK(); ++} ++ ++static int allocate_timeout_image(struct v4l2_loopback_device *dev) ++{ ++ MARK(); ++ if (dev->buffer_size <= 0) ++ return -EINVAL; ++ ++ if (dev->timeout_image == NULL) { ++ dev->timeout_image = v4l2l_vzalloc(dev->buffer_size); ++ if (dev->timeout_image == NULL) ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++/* fills and register video device */ ++static void init_vdev(struct video_device *vdev, int nr) ++{ ++ MARK(); ++ ++#ifdef V4L2LOOPBACK_WITH_STD ++ vdev->tvnorms = V4L2_STD_ALL; ++#endif /* V4L2LOOPBACK_WITH_STD */ ++ ++ vdev->vfl_type = VFL_TYPE_VIDEO; ++ vdev->fops = &v4l2_loopback_fops; ++ vdev->ioctl_ops = &v4l2_loopback_ioctl_ops; ++ vdev->release = &video_device_release; ++ vdev->minor = -1; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) ++ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | ++ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; ++#ifdef V4L2_CAP_VIDEO_M2M ++ vdev->device_caps |= V4L2_CAP_VIDEO_M2M; ++#endif ++#endif /* >=linux-4.7.0 */ ++ ++ if (debug > 1) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 20, 0) ++ vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; ++#else ++ vdev->dev_debug = ++ V4L2_DEV_DEBUG_IOCTL | V4L2_DEV_DEBUG_IOCTL_ARG; ++#endif ++ ++ /* since kernel-3.7, there is a new field 'vfl_dir' that has to be ++ * set to VFL_DIR_M2M for bidirectional devices */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) ++ vdev->vfl_dir = VFL_DIR_M2M; ++#endif ++ ++ MARK(); ++} ++ ++/* init default capture parameters, only fps may be changed in future */ ++static void init_capture_param(struct v4l2_captureparm *capture_param) ++{ ++ MARK(); ++ capture_param->capability = 0; ++ capture_param->capturemode = 0; ++ capture_param->extendedmode = 0; ++ capture_param->readbuffers = max_buffers; ++ capture_param->timeperframe.numerator = 1; ++ capture_param->timeperframe.denominator = 30; ++} ++ ++static void check_timers(struct v4l2_loopback_device *dev) ++{ ++ if (!dev->ready_for_capture) ++ return; ++ ++ if (dev->timeout_jiffies > 0 && !timer_pending(&dev->timeout_timer)) ++ mod_timer(&dev->timeout_timer, jiffies + dev->timeout_jiffies); ++ if (dev->sustain_framerate && !timer_pending(&dev->sustain_timer)) ++ mod_timer(&dev->sustain_timer, ++ jiffies + dev->frame_jiffies * 3 / 2); ++} ++#ifdef HAVE_TIMER_SETUP ++static void sustain_timer_clb(struct timer_list *t) ++{ ++ struct v4l2_loopback_device *dev = from_timer(dev, t, sustain_timer); ++#else ++static void sustain_timer_clb(unsigned long nr) ++{ ++ struct v4l2_loopback_device *dev = ++ idr_find(&v4l2loopback_index_idr, nr); ++#endif ++ spin_lock(&dev->lock); ++ if (dev->sustain_framerate) { ++ dev->reread_count++; ++ dprintkrw("reread: %d %d\n", dev->write_position, ++ dev->reread_count); ++ if (dev->reread_count == 1) ++ mod_timer(&dev->sustain_timer, ++ jiffies + max(1UL, dev->frame_jiffies / 2)); ++ else ++ mod_timer(&dev->sustain_timer, ++ jiffies + dev->frame_jiffies); ++ wake_up_all(&dev->read_event); ++ } ++ spin_unlock(&dev->lock); ++} ++#ifdef HAVE_TIMER_SETUP ++static void timeout_timer_clb(struct timer_list *t) ++{ ++ struct v4l2_loopback_device *dev = from_timer(dev, t, timeout_timer); ++#else ++static void timeout_timer_clb(unsigned long nr) ++{ ++ struct v4l2_loopback_device *dev = ++ idr_find(&v4l2loopback_index_idr, nr); ++#endif ++ spin_lock(&dev->lock); ++ if (dev->timeout_jiffies > 0) { ++ dev->timeout_happened = 1; ++ mod_timer(&dev->timeout_timer, jiffies + dev->timeout_jiffies); ++ wake_up_all(&dev->read_event); ++ } ++ spin_unlock(&dev->lock); ++} ++ ++/* init loopback main structure */ ++#define DEFAULT_FROM_CONF(confmember, default_condition, default_value) \ ++ ((conf) ? \ ++ ((conf->confmember default_condition) ? (default_value) : \ ++ (conf->confmember)) : \ ++ default_value) ++ ++static int v4l2_loopback_add(struct v4l2_loopback_config *conf, int *ret_nr) ++{ ++ struct v4l2_loopback_device *dev; ++ struct v4l2_ctrl_handler *hdl; ++ ++ int err = -ENOMEM; ++ ++ int _max_width = DEFAULT_FROM_CONF( ++ max_width, <= V4L2LOOPBACK_SIZE_MIN_WIDTH, max_width); ++ int _max_height = DEFAULT_FROM_CONF( ++ max_height, <= V4L2LOOPBACK_SIZE_MIN_HEIGHT, max_height); ++ bool _announce_all_caps = (conf && conf->announce_all_caps >= 0) ? ++ (conf->announce_all_caps) : ++ V4L2LOOPBACK_DEFAULT_EXCLUSIVECAPS; ++ ++ int _max_buffers = DEFAULT_FROM_CONF(max_buffers, <= 0, max_buffers); ++ int _max_openers = DEFAULT_FROM_CONF(max_openers, <= 0, max_openers); ++ ++ int nr = -1; ++ if (conf) { ++ if (conf->capture_nr >= 0 && ++ conf->output_nr == conf->capture_nr) { ++ nr = conf->capture_nr; ++ } else if (conf->capture_nr < 0 && conf->output_nr < 0) { ++ nr = -1; ++ } else if (conf->capture_nr < 0) { ++ nr = conf->output_nr; ++ } else if (conf->output_nr < 0) { ++ nr = conf->capture_nr; ++ } else { ++ printk(KERN_ERR ++ "split OUTPUT and CAPTURE devices not yet supported."); ++ printk(KERN_INFO ++ "both devices must have the same number (%d != %d).", ++ conf->output_nr, conf->capture_nr); ++ return -EINVAL; ++ } ++ } ++ ++ if (idr_find(&v4l2loopback_index_idr, nr)) ++ return -EEXIST; ++ ++ dprintk("creating v4l2loopback-device #%d\n", nr); ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ ++ /* allocate id, if @id >= 0, we're requesting that specific id */ ++ if (nr >= 0) { ++ err = idr_alloc(&v4l2loopback_index_idr, dev, nr, nr + 1, ++ GFP_KERNEL); ++ if (err == -ENOSPC) ++ err = -EEXIST; ++ } else { ++ err = idr_alloc(&v4l2loopback_index_idr, dev, 0, 0, GFP_KERNEL); ++ } ++ if (err < 0) ++ goto out_free_dev; ++ nr = err; ++ err = -ENOMEM; ++ ++ if (conf && conf->card_label && *(conf->card_label)) { ++ snprintf(dev->card_label, sizeof(dev->card_label), "%s", ++ conf->card_label); ++ } else { ++ snprintf(dev->card_label, sizeof(dev->card_label), ++ "Dummy video device (0x%04X)", nr); ++ } ++ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), ++ "v4l2loopback-%03d", nr); ++ ++ err = v4l2_device_register(NULL, &dev->v4l2_dev); ++ if (err) ++ goto out_free_idr; ++ MARK(); ++ ++ dev->vdev = video_device_alloc(); ++ if (dev->vdev == NULL) { ++ err = -ENOMEM; ++ goto out_unregister; ++ } ++ video_set_drvdata(dev->vdev, ++ kzalloc(sizeof(struct v4l2loopback_private), ++ GFP_KERNEL)); ++ if (video_get_drvdata(dev->vdev) == NULL) { ++ err = -ENOMEM; ++ goto out_unregister; ++ } ++ ++ MARK(); ++ snprintf(dev->vdev->name, sizeof(dev->vdev->name), dev->card_label); ++ ++ ((struct v4l2loopback_private *)video_get_drvdata(dev->vdev)) ++ ->device_nr = nr; ++ ++ init_vdev(dev->vdev, nr); ++ dev->vdev->v4l2_dev = &dev->v4l2_dev; ++ init_capture_param(&dev->capture_param); ++ set_timeperframe(dev, &dev->capture_param.timeperframe); ++ dev->keep_format = 0; ++ dev->sustain_framerate = 0; ++ ++ dev->announce_all_caps = _announce_all_caps; ++ dev->max_width = _max_width; ++ dev->max_height = _max_height; ++ dev->max_openers = _max_openers; ++ dev->buffers_number = dev->used_buffers = _max_buffers; ++ ++ dev->write_position = 0; ++ ++ MARK(); ++ spin_lock_init(&dev->lock); ++ INIT_LIST_HEAD(&dev->outbufs_list); ++ if (list_empty(&dev->outbufs_list)) { ++ int i; ++ ++ for (i = 0; i < dev->used_buffers; ++i) ++ list_add_tail(&dev->buffers[i].list_head, ++ &dev->outbufs_list); ++ } ++ ++ INIT_LIST_HEAD(&dev->queued_list); ++ INIT_LIST_HEAD(&dev->done_list); ++ spin_lock_init(&dev->done_lock); ++ ++ memset(dev->bufpos2index, 0, sizeof(dev->bufpos2index)); ++ atomic_set(&dev->open_count, 0); ++ dev->ready_for_capture = 0; ++ dev->ready_for_output = 1; ++ ++ dev->buffer_size = 0; ++ dev->image = NULL; ++ dev->imagesize = 0; ++#ifdef HAVE_TIMER_SETUP ++ timer_setup(&dev->sustain_timer, sustain_timer_clb, 0); ++ timer_setup(&dev->timeout_timer, timeout_timer_clb, 0); ++#else ++ setup_timer(&dev->sustain_timer, sustain_timer_clb, nr); ++ setup_timer(&dev->timeout_timer, timeout_timer_clb, nr); ++#endif ++ dev->reread_count = 0; ++ dev->timeout_jiffies = 0; ++ dev->timeout_image = NULL; ++ dev->timeout_happened = 0; ++ ++ hdl = &dev->ctrl_handler; ++ err = v4l2_ctrl_handler_init(hdl, 4); ++ if (err) ++ goto out_unregister; ++ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_keepformat, NULL); ++ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_sustainframerate, NULL); ++ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_timeout, NULL); ++ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_timeoutimageio, NULL); ++ if (hdl->error) { ++ err = hdl->error; ++ goto out_free_handler; ++ } ++ dev->v4l2_dev.ctrl_handler = hdl; ++ ++ err = v4l2_ctrl_handler_setup(hdl); ++ ++ /* FIXME set buffers to 0 */ ++ ++ /* Set initial format */ ++ dev->pix_format.width = 0; /* V4L2LOOPBACK_SIZE_DEFAULT_WIDTH; */ ++ dev->pix_format.height = 0; /* V4L2LOOPBACK_SIZE_DEFAULT_HEIGHT; */ ++ dev->pix_format.pixelformat = formats[0].fourcc; ++ dev->pix_format.colorspace = ++ V4L2_COLORSPACE_SRGB; /* do we need to set this ? */ ++ dev->pix_format.field = V4L2_FIELD_NONE; ++ ++ dev->buffer_size = PAGE_ALIGN(dev->pix_format.sizeimage); ++ dprintk("buffer_size = %ld (=%d)\n", dev->buffer_size, ++ dev->pix_format.sizeimage); ++ allocate_buffers(dev); ++ ++ init_waitqueue_head(&dev->read_event); ++ ++ /* register the device -> it creates /dev/video* */ ++ if (video_register_device(dev->vdev, VFL_TYPE_VIDEO, nr) < 0) { ++ printk(KERN_ERR ++ "v4l2loopback: failed video_register_device()\n"); ++ err = -EFAULT; ++ goto out_free_device; ++ } ++ v4l2loopback_create_sysfs(dev->vdev); ++ ++ MARK(); ++ if (ret_nr) ++ *ret_nr = dev->vdev->num; ++ return 0; ++ ++out_free_device: ++ video_device_release(dev->vdev); ++out_free_handler: ++ v4l2_ctrl_handler_free(&dev->ctrl_handler); ++out_unregister: ++ v4l2_device_unregister(&dev->v4l2_dev); ++out_free_idr: ++ idr_remove(&v4l2loopback_index_idr, nr); ++out_free_dev: ++ kfree(dev); ++ return err; ++} ++ ++static void v4l2_loopback_remove(struct v4l2_loopback_device *dev) ++{ ++ free_buffers(dev); ++ v4l2loopback_remove_sysfs(dev->vdev); ++ kfree(video_get_drvdata(dev->vdev)); ++ video_unregister_device(dev->vdev); ++ v4l2_device_unregister(&dev->v4l2_dev); ++ v4l2_ctrl_handler_free(&dev->ctrl_handler); ++ kfree(dev); ++} ++ ++static long v4l2loopback_control_ioctl(struct file *file, unsigned int cmd, ++ unsigned long parm) ++{ ++ struct v4l2_loopback_device *dev; ++ struct v4l2_loopback_config conf; ++ struct v4l2_loopback_config *confptr = &conf; ++ int device_nr; ++ int ret; ++ ++ ret = mutex_lock_killable(&v4l2loopback_ctl_mutex); ++ if (ret) ++ return ret; ++ ++ ret = -EINVAL; ++ switch (cmd) { ++ default: ++ ret = -ENOSYS; ++ break; ++ /* add a v4l2loopback device (pair), based on the user-provided specs */ ++ case V4L2LOOPBACK_CTL_ADD: ++ if (parm) { ++ if ((ret = copy_from_user(&conf, (void *)parm, ++ sizeof(conf))) < 0) ++ break; ++ } else ++ confptr = NULL; ++ ret = v4l2_loopback_add(confptr, &device_nr); ++ if (ret >= 0) ++ ret = device_nr; ++ break; ++ /* remove a v4l2loopback device (both capture and output) */ ++ case V4L2LOOPBACK_CTL_REMOVE: ++ ret = v4l2loopback_lookup((int)parm, &dev); ++ if (ret >= 0 && dev) { ++ int nr = ret; ++ ret = -EBUSY; ++ if (dev->open_count.counter > 0) ++ break; ++ idr_remove(&v4l2loopback_index_idr, nr); ++ v4l2_loopback_remove(dev); ++ ret = 0; ++ }; ++ break; ++ /* get information for a loopback device. ++ * this is mostly about limits (which cannot be queried directly with VIDIOC_G_FMT and friends ++ */ ++ case V4L2LOOPBACK_CTL_QUERY: ++ if (!parm) ++ break; ++ if ((ret = copy_from_user(&conf, (void *)parm, sizeof(conf))) < ++ 0) ++ break; ++ device_nr = ++ (conf.output_nr < 0) ? conf.capture_nr : conf.output_nr; ++ MARK(); ++ /* get the device from either capture_nr or output_nr (whatever is valid) */ ++ if ((ret = v4l2loopback_lookup(device_nr, &dev)) < 0) ++ break; ++ MARK(); ++ /* if we got the device from output_nr and there is a valid capture_nr, ++ * make sure that both refer to the same device (or bail out) ++ */ ++ if ((device_nr != conf.capture_nr) && (conf.capture_nr >= 0) && ++ (ret != v4l2loopback_lookup(conf.capture_nr, 0))) ++ break; ++ MARK(); ++ /* if otoh, we got the device from capture_nr and there is a valid output_nr, ++ * make sure that both refer to the same device (or bail out) ++ */ ++ if ((device_nr != conf.output_nr) && (conf.output_nr >= 0) && ++ (ret != v4l2loopback_lookup(conf.output_nr, 0))) ++ break; ++ MARK(); ++ ++ /* v4l2_loopback_config identified a single device, so fetch the data */ ++ snprintf(conf.card_label, sizeof(conf.card_label), "%s", ++ dev->card_label); ++ MARK(); ++ conf.output_nr = conf.capture_nr = dev->vdev->num; ++ conf.max_width = dev->max_width; ++ conf.max_height = dev->max_height; ++ conf.announce_all_caps = dev->announce_all_caps; ++ conf.max_buffers = dev->buffers_number; ++ conf.max_openers = dev->max_openers; ++ conf.debug = debug; ++ MARK(); ++ if (copy_to_user((void *)parm, &conf, sizeof(conf))) { ++ ret = -EFAULT; ++ break; ++ } ++ MARK(); ++ ret = 0; ++ ; ++ break; ++ } ++ ++ MARK(); ++ mutex_unlock(&v4l2loopback_ctl_mutex); ++ MARK(); ++ return ret; ++} ++ ++/* LINUX KERNEL */ ++ ++static const struct file_operations v4l2loopback_ctl_fops = { ++ // clang-format off ++ .open = nonseekable_open, ++ .unlocked_ioctl = v4l2loopback_control_ioctl, ++ .compat_ioctl = v4l2loopback_control_ioctl, ++ .owner = THIS_MODULE, ++ .llseek = noop_llseek, ++ // clang-format on ++}; ++ ++static struct miscdevice v4l2loopback_misc = { ++ // clang-format off ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "v4l2loopback", ++ .fops = &v4l2loopback_ctl_fops, ++ // clang-format on ++}; ++ ++static const struct v4l2_file_operations v4l2_loopback_fops = { ++ // clang-format off ++ .owner = THIS_MODULE, ++ .open = v4l2_loopback_open, ++ .release = v4l2_loopback_close, ++ .read = v4l2_loopback_read, ++ .write = v4l2_loopback_write, ++ .poll = v4l2_loopback_poll, ++ .mmap = v4l2_loopback_mmap, ++ .unlocked_ioctl = video_ioctl2, ++ // clang-format on ++}; ++ ++static const struct v4l2_ioctl_ops v4l2_loopback_ioctl_ops = { ++ // clang-format off ++ .vidioc_querycap = &vidioc_querycap, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++ .vidioc_enum_framesizes = &vidioc_enum_framesizes, ++ .vidioc_enum_frameintervals = &vidioc_enum_frameintervals, ++#endif ++ ++#ifndef HAVE__V4L2_CTRLS ++ .vidioc_queryctrl = &vidioc_queryctrl, ++ .vidioc_g_ctrl = &vidioc_g_ctrl, ++ .vidioc_s_ctrl = &vidioc_s_ctrl, ++#endif /* HAVE__V4L2_CTRLS */ ++ ++ .vidioc_enum_output = &vidioc_enum_output, ++ .vidioc_g_output = &vidioc_g_output, ++ .vidioc_s_output = &vidioc_s_output, ++ ++ .vidioc_enum_input = &vidioc_enum_input, ++ .vidioc_g_input = &vidioc_g_input, ++ .vidioc_s_input = &vidioc_s_input, ++ ++ .vidioc_enum_fmt_vid_cap = &vidioc_enum_fmt_cap, ++ .vidioc_g_fmt_vid_cap = &vidioc_g_fmt_cap, ++ .vidioc_s_fmt_vid_cap = &vidioc_s_fmt_cap, ++ .vidioc_try_fmt_vid_cap = &vidioc_try_fmt_cap, ++ ++ .vidioc_enum_fmt_vid_out = &vidioc_enum_fmt_out, ++ .vidioc_s_fmt_vid_out = &vidioc_s_fmt_out, ++ .vidioc_g_fmt_vid_out = &vidioc_g_fmt_out, ++ .vidioc_try_fmt_vid_out = &vidioc_try_fmt_out, ++ ++#ifdef V4L2L_OVERLAY ++ .vidioc_s_fmt_vid_overlay = &vidioc_s_fmt_overlay, ++ .vidioc_g_fmt_vid_overlay = &vidioc_g_fmt_overlay, ++#endif ++ ++#ifdef V4L2LOOPBACK_WITH_STD ++ .vidioc_s_std = &vidioc_s_std, ++ .vidioc_g_std = &vidioc_g_std, ++ .vidioc_querystd = &vidioc_querystd, ++#endif /* V4L2LOOPBACK_WITH_STD */ ++ ++ .vidioc_g_parm = &vidioc_g_parm, ++ .vidioc_s_parm = &vidioc_s_parm, ++ ++ .vidioc_reqbufs = &vidioc_reqbufs, ++ .vidioc_querybuf = &vidioc_querybuf, ++ .vidioc_qbuf = &vidioc_qbuf, ++ .vidioc_dqbuf = &vidioc_dqbuf, ++ ++ .vidioc_streamon = &vidioc_streamon, ++ .vidioc_streamoff = &vidioc_streamoff, ++ ++#ifdef CONFIG_VIDEO_V4L1_COMPAT ++ .vidiocgmbuf = &vidiocgmbuf, ++#endif ++ ++ .vidioc_subscribe_event = &vidioc_subscribe_event, ++ .vidioc_unsubscribe_event = &v4l2_event_unsubscribe, ++ // clang-format on ++}; ++ ++static int free_device_cb(int id, void *ptr, void *data) ++{ ++ struct v4l2_loopback_device *dev = ptr; ++ v4l2_loopback_remove(dev); ++ return 0; ++} ++static void free_devices(void) ++{ ++ idr_for_each(&v4l2loopback_index_idr, &free_device_cb, NULL); ++ idr_destroy(&v4l2loopback_index_idr); ++} ++ ++static int __init v4l2loopback_init_module(void) ++{ ++ int err; ++ int i; ++ MARK(); ++ ++ err = misc_register(&v4l2loopback_misc); ++ if (err < 0) ++ return err; ++ ++ if (devices < 0) { ++ devices = 1; ++ ++ /* try guessing the devices from the "video_nr" parameter */ ++ for (i = MAX_DEVICES - 1; i >= 0; i--) { ++ if (video_nr[i] >= 0) { ++ devices = i + 1; ++ break; ++ } ++ } ++ } ++ ++ if (devices > MAX_DEVICES) { ++ devices = MAX_DEVICES; ++ printk(KERN_INFO ++ "v4l2loopback: number of initial devices is limited to: %d\n", ++ MAX_DEVICES); ++ } ++ ++ if (max_buffers > MAX_BUFFERS) { ++ max_buffers = MAX_BUFFERS; ++ printk(KERN_INFO ++ "v4l2loopback: number of buffers is limited to: %d\n", ++ MAX_BUFFERS); ++ } ++ ++ if (max_openers < 0) { ++ printk(KERN_INFO ++ "v4l2loopback: allowing %d openers rather than %d\n", ++ 2, max_openers); ++ max_openers = 2; ++ } ++ ++ if (max_width < 1) { ++ max_width = V4L2LOOPBACK_SIZE_DEFAULT_MAX_WIDTH; ++ printk(KERN_INFO "v4l2loopback: using max_width %d\n", ++ max_width); ++ } ++ if (max_height < 1) { ++ max_height = V4L2LOOPBACK_SIZE_DEFAULT_MAX_HEIGHT; ++ printk(KERN_INFO "v4l2loopback: using max_height %d\n", ++ max_height); ++ } ++ ++ /* kfree on module release */ ++ for (i = 0; i < devices; i++) { ++ struct v4l2_loopback_config cfg = { ++ // clang-format off ++ .output_nr = video_nr[i], ++ .capture_nr = video_nr[i], ++ .max_width = max_width, ++ .max_height = max_height, ++ .announce_all_caps = (!exclusive_caps[i]), ++ .max_buffers = max_buffers, ++ .max_openers = max_openers, ++ .debug = debug, ++ // clang-format on ++ }; ++ cfg.card_label[0] = 0; ++ if (card_label[i]) ++ snprintf(cfg.card_label, sizeof(cfg.card_label), "%s", ++ card_label[i]); ++ err = v4l2_loopback_add(&cfg, 0); ++ if (err) { ++ free_devices(); ++ goto error; ++ } ++ } ++ ++ dprintk("module installed\n"); ++ ++ printk(KERN_INFO "v4l2loopback driver version %d.%d.%d loaded\n", ++ // clang-format off ++ (V4L2LOOPBACK_VERSION_CODE >> 16) & 0xff, ++ (V4L2LOOPBACK_VERSION_CODE >> 8) & 0xff, ++ (V4L2LOOPBACK_VERSION_CODE ) & 0xff); ++ // clang-format on ++ ++ return 0; ++error: ++ misc_deregister(&v4l2loopback_misc); ++ return err; ++} ++ ++static void v4l2loopback_cleanup_module(void) ++{ ++ MARK(); ++ /* unregister the device -> it deletes /dev/video* */ ++ free_devices(); ++ /* and get rid of /dev/v4l2loopback */ ++ misc_deregister(&v4l2loopback_misc); ++ dprintk("module removed\n"); ++} ++ ++MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR); ++MODULE_ALIAS("devname:v4l2loopback"); ++ ++#ifdef MODULE ++int __init init_module(void) ++{ ++ return v4l2loopback_init_module(); ++} ++void __exit cleanup_module(void) ++{ ++ return v4l2loopback_cleanup_module(); ++} ++#else ++late_initcall(v4l2loopback_init_module); ++#endif ++ ++/* ++ * fake usage of unused functions ++ */ ++#ifdef HAVE__V4L2_CTRLS ++static int vidioc_queryctrl(struct file *file, void *fh, ++ struct v4l2_queryctrl *q) __attribute__((unused)); ++static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) ++ __attribute__((unused)); ++static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) ++ __attribute__((unused)); ++#endif /* HAVE__V4L2_CTRLS */ +diff --git a/drivers/media/platform/v4l2loopback/v4l2loopback.h b/drivers/media/platform/v4l2loopback/v4l2loopback.h +new file mode 100644 +index 000000000..77c671971 +--- /dev/null ++++ b/drivers/media/platform/v4l2loopback/v4l2loopback.h +@@ -0,0 +1,92 @@ ++/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ ++/* ++ * v4l2loopback.h ++ * ++ * Written by IOhannes m zmölnig, 7/1/20. ++ * ++ * Copyright 2020 by IOhannes m zmölnig. Redistribution of this file is ++ * permitted under the GNU General Public License. ++ */ ++#ifndef _V4L2LOOPBACK_H ++#define _V4L2LOOPBACK_H ++ ++#define V4L2LOOPBACK_VERSION_MAJOR 0 ++#define V4L2LOOPBACK_VERSION_MINOR 12 ++#define V4L2LOOPBACK_VERSION_BUGFIX 5 ++ ++/* /dev/v4l2loopback interface */ ++ ++struct v4l2_loopback_config { ++ /** ++ * the device-number (/dev/video) ++ * V4L2LOOPBACK_CTL_ADD: ++ * setting this to a value<0, will allocate an available one ++ * if nr>=0 and the device already exists, the ioctl will EEXIST ++ * if output_nr and capture_nr are the same, only a single device will be created ++ * ++ * V4L2LOOPBACK_CTL_QUERY: ++ * either both output_nr and capture_nr must refer to the same loopback, ++ * or one (and only one) of them must be -1 ++ * ++ */ ++ int output_nr; ++ int capture_nr; ++ ++ /** ++ * a nice name for your device ++ * if (*card_label)==0, an automatic name is assigned ++ */ ++ char card_label[32]; ++ ++ /** ++ * maximum allowed frame size ++ * if too low, default values are used ++ */ ++ int max_width; ++ int max_height; ++ ++ /** ++ * whether to announce OUTPUT/CAPTURE capabilities exclusively ++ * for this device or not ++ * (!exclusive_caps) ++ * FIXXME: this ought to be removed (if superseded by output_nr vs capture_nr) ++ */ ++ int announce_all_caps; ++ ++ /** ++ * number of buffers to allocate for the queue ++ * if set to <=0, default values are used ++ */ ++ int max_buffers; ++ ++ /** ++ * how many consumers are allowed to open this device concurrently ++ * if set to <=0, default values are used ++ */ ++ int max_openers; ++ ++ /** ++ * set the debugging level for this device ++ */ ++ int debug; ++}; ++ ++/* a pointer to a (struct v4l2_loopback_config) that has all values you wish to impose on the ++ * to-be-created device set. ++ * if the ptr is NULL, a new device is created with default values at the driver's discretion. ++ * ++ * returns the device_nr of the OUTPUT device (which can be used with V4L2LOOPBACK_CTL_QUERY, ++ * to get more information on the device) ++ */ ++#define V4L2LOOPBACK_CTL_ADD 0x4C80 ++ ++/* a pointer to a (struct v4l2_loopback_config) that has output_nr and/or capture_nr set ++ * (the two values must either refer to video-devices associated with the same loopback device ++ * or exactly one of them must be <0 ++ */ ++#define V4L2LOOPBACK_CTL_QUERY 0x4C82 ++ ++/* the device-number (either CAPTURE or OUTPUT) associated with the loopback-device */ ++#define V4L2LOOPBACK_CTL_REMOVE 0x4C81 ++ ++#endif /* _V4L2LOOPBACK_H */ +diff --git a/drivers/media/platform/v4l2loopback/v4l2loopback_formats.h b/drivers/media/platform/v4l2loopback/v4l2loopback_formats.h +new file mode 100644 +index 000000000..6cb6f842c +--- /dev/null ++++ b/drivers/media/platform/v4l2loopback/v4l2loopback_formats.h +@@ -0,0 +1,427 @@ ++#ifndef V4L2_PIX_FMT_VP9 ++#define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0') ++#endif ++#ifndef V4L2_PIX_FMT_HEVC ++#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') ++#endif ++ ++/* here come the packed formats */ ++{ ++ .name = "32 bpp RGB, le", ++ .fourcc = V4L2_PIX_FMT_BGR32, ++ .depth = 32, ++ .flags = 0, ++}, ++ { ++ .name = "32 bpp RGB, be", ++ .fourcc = V4L2_PIX_FMT_RGB32, ++ .depth = 32, ++ .flags = 0, ++ }, ++ { ++ .name = "24 bpp RGB, le", ++ .fourcc = V4L2_PIX_FMT_BGR24, ++ .depth = 24, ++ .flags = 0, ++ }, ++ { ++ .name = "24 bpp RGB, be", ++ .fourcc = V4L2_PIX_FMT_RGB24, ++ .depth = 24, ++ .flags = 0, ++ }, ++#ifdef V4L2_PIX_FMT_RGB332 ++ { ++ .name = "8 bpp RGB-3-3-2", ++ .fourcc = V4L2_PIX_FMT_RGB332, ++ .depth = 8, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_RGB332 */ ++#ifdef V4L2_PIX_FMT_RGB444 ++ { ++ .name = "16 bpp RGB (xxxxrrrr ggggbbbb)", ++ .fourcc = V4L2_PIX_FMT_RGB444, ++ .depth = 16, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_RGB444 */ ++#ifdef V4L2_PIX_FMT_RGB555 ++ { ++ .name = "16 bpp RGB-5-5-5", ++ .fourcc = V4L2_PIX_FMT_RGB555, ++ .depth = 16, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_RGB555 */ ++#ifdef V4L2_PIX_FMT_RGB565 ++ { ++ .name = "16 bpp RGB-5-6-5", ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .depth = 16, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_RGB565 */ ++#ifdef V4L2_PIX_FMT_RGB555X ++ { ++ .name = "16 bpp RGB-5-5-5 BE", ++ .fourcc = V4L2_PIX_FMT_RGB555X, ++ .depth = 16, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_RGB555X */ ++#ifdef V4L2_PIX_FMT_RGB565X ++ { ++ .name = "16 bpp RGB-5-6-5 BE", ++ .fourcc = V4L2_PIX_FMT_RGB565X, ++ .depth = 16, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_RGB565X */ ++#ifdef V4L2_PIX_FMT_BGR666 ++ { ++ .name = "18 bpp BGR-6-6-6", ++ .fourcc = V4L2_PIX_FMT_BGR666, ++ .depth = 18, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_BGR666 */ ++ { ++ .name = "4:2:2, packed, YUYV", ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .depth = 16, ++ .flags = 0, ++ }, ++ { ++ .name = "4:2:2, packed, UYVY", ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .depth = 16, ++ .flags = 0, ++ }, ++#ifdef V4L2_PIX_FMT_YVYU ++ { ++ .name = "4:2:2, packed YVYU", ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .depth = 16, ++ .flags = 0, ++ }, ++#endif ++#ifdef V4L2_PIX_FMT_VYUY ++ { ++ .name = "4:2:2, packed VYUY", ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .depth = 16, ++ .flags = 0, ++ }, ++#endif ++ { ++ .name = "4:2:2, packed YYUV", ++ .fourcc = V4L2_PIX_FMT_YYUV, ++ .depth = 16, ++ .flags = 0, ++ }, ++ { ++ .name = "YUV-8-8-8-8", ++ .fourcc = V4L2_PIX_FMT_YUV32, ++ .depth = 32, ++ .flags = 0, ++ }, ++ { ++ .name = "8 bpp, Greyscale", ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .depth = 8, ++ .flags = 0, ++ }, ++#ifdef V4L2_PIX_FMT_Y4 ++ { ++ .name = "4 bpp Greyscale", ++ .fourcc = V4L2_PIX_FMT_Y4, ++ .depth = 4, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_Y4 */ ++#ifdef V4L2_PIX_FMT_Y6 ++ { ++ .name = "6 bpp Greyscale", ++ .fourcc = V4L2_PIX_FMT_Y6, ++ .depth = 6, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_Y6 */ ++#ifdef V4L2_PIX_FMT_Y10 ++ { ++ .name = "10 bpp Greyscale", ++ .fourcc = V4L2_PIX_FMT_Y10, ++ .depth = 10, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_Y10 */ ++#ifdef V4L2_PIX_FMT_Y12 ++ { ++ .name = "12 bpp Greyscale", ++ .fourcc = V4L2_PIX_FMT_Y12, ++ .depth = 12, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_Y12 */ ++ { ++ .name = "16 bpp, Greyscale", ++ .fourcc = V4L2_PIX_FMT_Y16, ++ .depth = 16, ++ .flags = 0, ++ }, ++#ifdef V4L2_PIX_FMT_YUV444 ++ { ++ .name = "16 bpp xxxxyyyy uuuuvvvv", ++ .fourcc = V4L2_PIX_FMT_YUV444, ++ .depth = 16, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_YUV444 */ ++#ifdef V4L2_PIX_FMT_YUV555 ++ { ++ .name = "16 bpp YUV-5-5-5", ++ .fourcc = V4L2_PIX_FMT_YUV555, ++ .depth = 16, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_YUV555 */ ++#ifdef V4L2_PIX_FMT_YUV565 ++ { ++ .name = "16 bpp YUV-5-6-5", ++ .fourcc = V4L2_PIX_FMT_YUV565, ++ .depth = 16, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_YUV565 */ ++ ++/* bayer formats */ ++#ifdef V4L2_PIX_FMT_SRGGB8 ++ { ++ .name = "Bayer RGGB 8bit", ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .depth = 8, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_SRGGB8 */ ++#ifdef V4L2_PIX_FMT_SGRBG8 ++ { ++ .name = "Bayer GRBG 8bit", ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .depth = 8, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_SGRBG8 */ ++#ifdef V4L2_PIX_FMT_SGBRG8 ++ { ++ .name = "Bayer GBRG 8bit", ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .depth = 8, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_SGBRG8 */ ++#ifdef V4L2_PIX_FMT_SBGGR8 ++ { ++ .name = "Bayer BA81 8bit", ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .depth = 8, ++ .flags = 0, ++ }, ++#endif /* V4L2_PIX_FMT_SBGGR8 */ ++ ++ /* here come the planar formats */ ++ { ++ .name = "4:1:0, planar, Y-Cr-Cb", ++ .fourcc = V4L2_PIX_FMT_YVU410, ++ .depth = 9, ++ .flags = FORMAT_FLAGS_PLANAR, ++ }, ++ { ++ .name = "4:2:0, planar, Y-Cr-Cb", ++ .fourcc = V4L2_PIX_FMT_YVU420, ++ .depth = 12, ++ .flags = FORMAT_FLAGS_PLANAR, ++ }, ++ { ++ .name = "4:1:0, planar, Y-Cb-Cr", ++ .fourcc = V4L2_PIX_FMT_YUV410, ++ .depth = 9, ++ .flags = FORMAT_FLAGS_PLANAR, ++ }, ++ { ++ .name = "4:2:0, planar, Y-Cb-Cr", ++ .fourcc = V4L2_PIX_FMT_YUV420, ++ .depth = 12, ++ .flags = FORMAT_FLAGS_PLANAR, ++ }, ++#ifdef V4L2_PIX_FMT_YUV422P ++ { ++ .name = "16 bpp YVU422 planar", ++ .fourcc = V4L2_PIX_FMT_YUV422P, ++ .depth = 16, ++ .flags = FORMAT_FLAGS_PLANAR, ++ }, ++#endif /* V4L2_PIX_FMT_YUV422P */ ++#ifdef V4L2_PIX_FMT_YUV411P ++ { ++ .name = "16 bpp YVU411 planar", ++ .fourcc = V4L2_PIX_FMT_YUV411P, ++ .depth = 16, ++ .flags = FORMAT_FLAGS_PLANAR, ++ }, ++#endif /* V4L2_PIX_FMT_YUV411P */ ++#ifdef V4L2_PIX_FMT_Y41P ++ { ++ .name = "12 bpp YUV 4:1:1", ++ .fourcc = V4L2_PIX_FMT_Y41P, ++ .depth = 12, ++ .flags = FORMAT_FLAGS_PLANAR, ++ }, ++#endif /* V4L2_PIX_FMT_Y41P */ ++#ifdef V4L2_PIX_FMT_NV12 ++ { ++ .name = "12 bpp Y/CbCr 4:2:0 ", ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .depth = 12, ++ .flags = FORMAT_FLAGS_PLANAR, ++ }, ++#endif /* V4L2_PIX_FMT_NV12 */ ++ ++/* here come the compressed formats */ ++ ++#ifdef V4L2_PIX_FMT_MJPEG ++ { ++ .name = "Motion-JPEG", ++ .fourcc = V4L2_PIX_FMT_MJPEG, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_MJPEG */ ++#ifdef V4L2_PIX_FMT_JPEG ++ { ++ .name = "JFIF JPEG", ++ .fourcc = V4L2_PIX_FMT_JPEG, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_JPEG */ ++#ifdef V4L2_PIX_FMT_DV ++ { ++ .name = "DV1394", ++ .fourcc = V4L2_PIX_FMT_DV, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_DV */ ++#ifdef V4L2_PIX_FMT_MPEG ++ { ++ .name = "MPEG-1/2/4 Multiplexed", ++ .fourcc = V4L2_PIX_FMT_MPEG, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_MPEG */ ++#ifdef V4L2_PIX_FMT_H264 ++ { ++ .name = "H264 with start codes", ++ .fourcc = V4L2_PIX_FMT_H264, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_H264 */ ++#ifdef V4L2_PIX_FMT_H264_NO_SC ++ { ++ .name = "H264 without start codes", ++ .fourcc = V4L2_PIX_FMT_H264_NO_SC, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_H264_NO_SC */ ++#ifdef V4L2_PIX_FMT_H264_MVC ++ { ++ .name = "H264 MVC", ++ .fourcc = V4L2_PIX_FMT_H264_MVC, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_H264_MVC */ ++#ifdef V4L2_PIX_FMT_H263 ++ { ++ .name = "H263", ++ .fourcc = V4L2_PIX_FMT_H263, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_H263 */ ++#ifdef V4L2_PIX_FMT_MPEG1 ++ { ++ .name = "MPEG-1 ES", ++ .fourcc = V4L2_PIX_FMT_MPEG1, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_MPEG1 */ ++#ifdef V4L2_PIX_FMT_MPEG2 ++ { ++ .name = "MPEG-2 ES", ++ .fourcc = V4L2_PIX_FMT_MPEG2, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_MPEG2 */ ++#ifdef V4L2_PIX_FMT_MPEG4 ++ { ++ .name = "MPEG-4 part 2 ES", ++ .fourcc = V4L2_PIX_FMT_MPEG4, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_MPEG4 */ ++#ifdef V4L2_PIX_FMT_XVID ++ { ++ .name = "Xvid", ++ .fourcc = V4L2_PIX_FMT_XVID, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_XVID */ ++#ifdef V4L2_PIX_FMT_VC1_ANNEX_G ++ { ++ .name = "SMPTE 421M Annex G compliant stream", ++ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_VC1_ANNEX_G */ ++#ifdef V4L2_PIX_FMT_VC1_ANNEX_L ++ { ++ .name = "SMPTE 421M Annex L compliant stream", ++ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_VC1_ANNEX_L */ ++#ifdef V4L2_PIX_FMT_VP8 ++ { ++ .name = "VP8", ++ .fourcc = V4L2_PIX_FMT_VP8, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_VP8 */ ++#ifdef V4L2_PIX_FMT_VP9 ++ { ++ .name = "VP9", ++ .fourcc = V4L2_PIX_FMT_VP9, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_VP9 */ ++#ifdef V4L2_PIX_FMT_HEVC ++ { ++ .name = "HEVC", ++ .fourcc = V4L2_PIX_FMT_HEVC, ++ .depth = 32, ++ .flags = FORMAT_FLAGS_COMPRESSED, ++ }, ++#endif /* V4L2_PIX_FMT_HEVC */ +diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c +index 66a00b7c7..0af727295 100644 +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -94,6 +94,9 @@ static int max_devices; + + static DEFINE_IDA(mmc_blk_ida); + static DEFINE_IDA(mmc_rpmb_ida); ++#ifndef CONFIG_MMC_INDEX_MATCH_CONTROLLER ++static DECLARE_BITMAP(name_use, MAX_DEVICES); ++#endif + + /* + * There is one mmc_blk_data per slot. +@@ -112,6 +115,7 @@ struct mmc_blk_data { + unsigned int usage; + unsigned int read_only; + unsigned int part_type; ++ unsigned int name_idx; + unsigned int reset_done; + #define MMC_BLK_READ BIT(0) + #define MMC_BLK_WRITE BIT(1) +@@ -2303,6 +2307,24 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, + goto out; + } + ++#ifdef CONFIG_MMC_INDEX_MATCH_CONTROLLER ++ /* Corresponding to the controller node */ ++ md->name_idx = card->host->index; ++#else ++ /* ++ * !subname implies we are creating main mmc_blk_data that will be ++ * associated with mmc_card with dev_set_drvdata. Due to device ++ * partitions, devidx will not coincide with a per-physical card ++ * index anymore so we keep track of a name index. ++ */ ++ if (!subname) { ++ md->name_idx = find_first_zero_bit(name_use, max_devices); ++ __set_bit(md->name_idx, name_use); ++ } else ++ md->name_idx = ((struct mmc_blk_data *) ++ dev_to_disk(parent)->private_data)->name_idx; ++#endif ++ + md->area_type = area_type; + + /* +@@ -2364,7 +2386,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, + */ + + snprintf(md->disk->disk_name, sizeof(md->disk->disk_name), +- "mmcblk%u%s", card->host->index, subname ? subname : ""); ++ "mmcblk%u%s", md->name_idx, subname ? subname : ""); + + set_capacity(md->disk, size); + +@@ -2551,7 +2573,7 @@ static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, + } + + snprintf(rpmb_name, sizeof(rpmb_name), +- "mmcblk%u%s", card->host->index, subname ? subname : ""); ++ "mmcblk%u%s", md->name_idx, subname ? subname : ""); + + rpmb->id = devidx; + rpmb->part_index = part_index; +@@ -2670,6 +2692,9 @@ static void mmc_blk_remove_parts(struct mmc_card *card, + struct mmc_blk_data *part_md; + struct mmc_rpmb_data *rpmb; + ++#ifndef CONFIG_MMC_INDEX_MATCH_CONTROLLER ++ __clear_bit(md->name_idx, name_use); ++#endif + /* Remove RPMB partitions */ + list_for_each_safe(pos, q, &md->rpmbs) { + rpmb = list_entry(pos, struct mmc_rpmb_data, node); +diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +index eb82f6aac..d79dda762 100644 +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -2249,7 +2249,7 @@ void mmc_rescan(struct work_struct *work) + /* If there is a non-removable card registered, only scan once */ + if (!mmc_card_is_removable(host) && host->rescan_entered) + return; +- host->rescan_entered = 1; ++ //host->rescan_entered = 1; /* To support wifi rescan. */ + + if (host->trigger_card_event && host->ops->card_event) { + mmc_claim_host(host); +@@ -2261,7 +2261,8 @@ void mmc_rescan(struct work_struct *work) + mmc_bus_get(host); + + /* Verify a registered card to be functional, else remove it. */ +- if (host->bus_ops && !host->bus_dead) ++ if (host->bus_ops && !host->bus_dead ++ && !(host->caps & MMC_CAP_NONREMOVABLE)) + host->bus_ops->detect(host); + + host->detect_change = 0; +diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c +index 03e2f965a..0d31a7d58 100644 +--- a/drivers/mmc/core/host.c ++++ b/drivers/mmc/core/host.c +@@ -32,7 +32,12 @@ + + #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) + ++#ifdef CONFIG_MMC_INDEX_MATCH_CONTROLLER + static DEFINE_IDA(mmc_host_ida); ++#else ++static DEFINE_IDR(mmc_host_idr); ++static DEFINE_SPINLOCK(mmc_host_lock); ++#endif + + #ifdef CONFIG_PM_SLEEP + static int mmc_host_class_prepare(struct device *dev) +@@ -66,16 +71,19 @@ static const struct dev_pm_ops mmc_host_class_dev_pm_ops = { + }; + + #define MMC_HOST_CLASS_DEV_PM_OPS (&mmc_host_class_dev_pm_ops) +-#else +-#define MMC_HOST_CLASS_DEV_PM_OPS NULL + #endif + + static void mmc_host_classdev_release(struct device *dev) + { + struct mmc_host *host = cls_dev_to_mmc_host(dev); + wakeup_source_unregister(host->ws); +- if (of_alias_get_id(host->parent->of_node, "mmc") < 0) +- ida_simple_remove(&mmc_host_ida, host->index); ++#ifdef CONFIG_MMC_INDEX_MATCH_CONTROLLER ++ ida_simple_remove(&mmc_host_ida, host->index); ++#else ++ spin_lock(&mmc_host_lock); ++ idr_remove(&mmc_host_idr, host->index); ++ spin_unlock(&mmc_host_lock); ++#endif + kfree(host); + } + +@@ -423,6 +431,7 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask) + } + EXPORT_SYMBOL(mmc_of_parse_voltage); + ++#ifdef CONFIG_MMC_INDEX_MATCH_CONTROLLER + /** + * mmc_first_nonreserved_index() - get the first index that is not reserved + */ +@@ -436,6 +445,7 @@ static int mmc_first_nonreserved_index(void) + + return max + 1; + } ++#endif + + /** + * mmc_alloc_host - initialise the per-host structure. +@@ -448,7 +458,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) + { + int index; + struct mmc_host *host; +- int alias_id, min_idx, max_idx; + + host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); + if (!host) +@@ -457,21 +466,40 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) + /* scanning will be enabled when we're ready */ + host->rescan_disable = 1; + +- alias_id = of_alias_get_id(dev->of_node, "mmc"); +- if (alias_id >= 0) { +- index = alias_id; +- } else { +- min_idx = mmc_first_nonreserved_index(); +- max_idx = 0; ++#ifdef CONFIG_MMC_INDEX_MATCH_CONTROLLER ++ int err = 0; ++ { ++ int alias_id, min_idx, max_idx; ++ alias_id = of_alias_get_id(dev->of_node, "mmc"); ++ if (alias_id >= 0) { ++ min_idx = alias_id; ++ max_idx = alias_id + 1; ++ } else { ++ min_idx = mmc_first_nonreserved_index(); ++ max_idx = 0; ++ } + +- index = ida_simple_get(&mmc_host_ida, min_idx, max_idx, GFP_KERNEL); +- if (index < 0) { ++ err = ida_simple_get(&mmc_host_ida, min_idx, max_idx, GFP_KERNEL); ++ if (err < 0) { + kfree(host); + return NULL; + } + } + +- host->index = index; ++ host->index = err; ++#else ++ idr_preload(GFP_KERNEL); ++ spin_lock(&mmc_host_lock); ++ err = idr_alloc(&mmc_host_idr, host, 0, 0, GFP_NOWAIT); ++ if (err >= 0) ++ host->index = err; ++ spin_unlock(&mmc_host_lock); ++ idr_preload_end(); ++ if (err < 0) { ++ kfree(host); ++ return NULL; ++ } ++#endif + + dev_set_name(&host->class_dev, "mmc%d", host->index); + host->ws = wakeup_source_register(NULL, dev_name(&host->class_dev)); +diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c +index 99a4ce68d..63bc6b3d9 100644 +--- a/drivers/mmc/core/sdio.c ++++ b/drivers/mmc/core/sdio.c +@@ -1308,3 +1308,39 @@ int mmc_attach_sdio(struct mmc_host *host) + return err; + } + ++int sdio_reset_comm(struct mmc_card *card) ++{ ++ struct mmc_host *host = card->host; ++ u32 ocr; ++ int err; ++ ++ printk("%s():\n", __func__); ++ mmc_claim_host(host); ++ ++ mmc_go_idle(host); ++ ++ mmc_set_clock(host, host->f_min); ++ ++ err = mmc_send_io_op_cond(host, 0, &ocr); ++ if (err) ++ goto err; ++ ++ host->ocr_avail_sdio = mmc_select_voltage(host, ocr); ++ if (!host->ocr_avail_sdio) { ++ err = -EINVAL; ++ goto err; ++ } ++ ++ err = mmc_sdio_init_card(host, host->ocr_avail_sdio, card); ++ if (err) ++ goto err; ++ ++ mmc_release_host(host); ++ return 0; ++err: ++ printk("%s: Error resetting SDIO communications (%d)\n", ++ mmc_hostname(host), err); ++ mmc_release_host(host); ++ return err; ++} ++EXPORT_SYMBOL(sdio_reset_comm); +diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +index d42e86cdf..0a37f59ff 100644 +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -1541,8 +1541,7 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout) + */ + if (data->error) { + if (!host->cmd || host->cmd == data_cmd) +- sdhci_do_reset(host, SDHCI_RESET_CMD); +- sdhci_do_reset(host, SDHCI_RESET_DATA); ++ sdhci_do_reset(host, SDHCI_RESET_DATA); + } + + if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) == +@@ -2096,6 +2095,8 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, + sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + + pwr |= SDHCI_POWER_ON; ++ if(host->ops->power_set) ++ host->ops->power_set(host,MMC_POWER_UP); + + sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + +@@ -2280,6 +2281,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + if (ios->power_mode == MMC_POWER_OFF) { + sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); + sdhci_reinit(host); ++ if(host->ops->power_set) ++ host->ops->power_set(host,MMC_POWER_OFF); + } + + if (host->version >= SDHCI_SPEC_300 && +@@ -2558,6 +2561,8 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, + ctrl &= ~SDHCI_CTRL_VDD_180; + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + ++ if (host->ops->voltage_switch) ++ host->ops->voltage_switch(host,MMC_SIGNAL_VOLTAGE_330); + if (!IS_ERR(mmc->supply.vqmmc)) { + ret = mmc_regulator_set_vqmmc(mmc, ios); + if (ret < 0) { +@@ -2599,7 +2604,7 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, + + /* Some controller need to do more when switching */ + if (host->ops->voltage_switch) +- host->ops->voltage_switch(host); ++ host->ops->voltage_switch(host,MMC_SIGNAL_VOLTAGE_180); + + /* 1.8V regulator output should be stable within 5 ms */ + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); +@@ -2969,8 +2974,8 @@ static void sdhci_card_event(struct mmc_host *mmc) + pr_err("%s: Resetting controller.\n", + mmc_hostname(host->mmc)); + +- sdhci_do_reset(host, SDHCI_RESET_CMD); + sdhci_do_reset(host, SDHCI_RESET_DATA); ++ sdhci_do_reset(host, SDHCI_RESET_CMD); + + sdhci_error_out_mrqs(host, -ENOMEDIUM); + } +@@ -3865,8 +3870,8 @@ void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery) + host->cqe_on = false; + + if (recovery) { +- sdhci_do_reset(host, SDHCI_RESET_CMD); + sdhci_do_reset(host, SDHCI_RESET_DATA); ++ sdhci_do_reset(host, SDHCI_RESET_CMD); + } + + pr_debug("%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x\n", +diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h +index 8b1650f37..6e8faec4b 100644 +--- a/drivers/mmc/host/sdhci.h ++++ b/drivers/mmc/host/sdhci.h +@@ -646,7 +646,8 @@ struct sdhci_ops { + void (*hw_reset)(struct sdhci_host *host); + void (*adma_workaround)(struct sdhci_host *host, u32 intmask); + void (*card_event)(struct sdhci_host *host); +- void (*voltage_switch)(struct sdhci_host *host); ++ void (*voltage_switch)(struct sdhci_host *host,int vlotage); ++ void (*power_set)(struct sdhci_host *host,int vlotage); + void (*adma_write_desc)(struct sdhci_host *host, void **desc, + dma_addr_t addr, int len, unsigned int cmd); + void (*copy_to_bounce_buffer)(struct sdhci_host *host, +diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig +index 6ddab7962..bbddeccf5 100644 +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -70,6 +70,21 @@ config MTD_BLOCK_RO + You do not need this option for use with the DiskOnChip devices. For + those, enable NFTL support (CONFIG_NFTL) instead. + ++config MTD_BLOCK_BBT_RO ++ tristate "Bad block tab based readonly block device access to MTD devices, " ++ depends on BLOCK ++ select MTD_BLKDEVS ++ help ++ This allows you to mount read-only file systems (such as squashfs) ++ There is a bad block tab to skip the bad block on nand for readonly use. ++ It's a sample bad block tab, create at init, so you'd better don't write ++ the nand at runtime. ++ ++config MTD_BLOCK_BBT_RO_BLOCK_SIZE ++ int "block size of /dev/mtdblock_bbt_ro" ++ depends on MTD_BLOCK_BBT_RO ++ default 4096 ++ + config FTL + tristate "FTL (Flash Translation Layer) support" + depends on BLOCK +diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile +index 593d0593a..bfecfa486 100644 +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -13,6 +13,7 @@ obj-y += parsers/ + obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o + obj-$(CONFIG_MTD_BLOCK) += mtdblock.o + obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o ++obj-$(CONFIG_MTD_BLOCK_BBT_RO) += mtdblock_bbt_ro.o + obj-$(CONFIG_FTL) += ftl.o + obj-$(CONFIG_NFTL) += nftl.o + obj-$(CONFIG_INFTL) += inftl.o +diff --git a/drivers/mtd/mtdblock_bbt_ro.c b/drivers/mtd/mtdblock_bbt_ro.c +new file mode 100644 +index 000000000..5f6d5a135 +--- /dev/null ++++ b/drivers/mtd/mtdblock_bbt_ro.c +@@ -0,0 +1,184 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct m_mtd_data { ++ struct mtd_blktrans_dev dev; ++ void *bbt; ++ int block_count; ++ int usable_count; ++}; ++ ++#define MY_BLOCK_SIZE CONFIG_MTD_BLOCK_BBT_RO_BLOCK_SIZE ++ ++static void create_bbt(struct m_mtd_data *data, struct mtd_info *mtd) ++{ ++ int i, bad_count; ++ loff_t offs = 0; ++ int block_count = mtd_div_by_eb(mtd->size, mtd); ++ int item_size; ++ void *bbt; ++ ++ ++ if (block_count < 256) ++ item_size = 1; ++ else if (block_count < 65536) ++ item_size = 2; ++ else ++ item_size = 4; ++ ++ bbt = kzalloc(block_count * item_size, GFP_KERNEL); ++ BUG_ON(!bbt); ++ ++ for (i = 0, bad_count = 0; i < block_count; i++) { ++ int is_bad = mtd_block_isbad(mtd, offs) > 0; ++ offs += mtd->erasesize; ++ if (is_bad) { ++ bad_count++; ++ continue; ++ } ++ ++ switch (item_size) { ++ case 1: ++ ((unsigned char *)bbt)[i-bad_count] = i; break; ++ case 2: ++ ((unsigned short *)bbt)[i-bad_count] = i; break; ++ case 4: ++ ((unsigned int *)bbt)[i-bad_count] = i; break; ++ } ++ } ++ ++ printk("mtd: %s %lld %d %d\n", ++ mtd->name, mtd->size, mtd->erasesize, bad_count); ++ ++ data->usable_count = block_count - bad_count; ++ data->block_count = block_count; ++ data->bbt = bbt; ++} ++ ++static unsigned int get_from_bbt(struct m_mtd_data *data, int index) ++{ ++ int block_count = data->block_count; ++ void *bbt = data->bbt; ++ int ret; ++ ++ if (block_count < 256) ++ ret = ((unsigned char *)bbt)[index]; ++ else if (block_count < 65536) ++ ret = ((unsigned short *)bbt)[index]; ++ else ++ ret = ((unsigned int *)bbt)[index]; ++ ++ if (ret == 0) ++ return index ? -1 : 0; ++ else ++ return ret; ++} ++ ++static int mtdblock_readsect(struct mtd_blktrans_dev *dev, ++ unsigned long block, char *buf) ++{ ++ struct m_mtd_data *data = (struct m_mtd_data *)dev; ++ struct mtd_info *mtd = dev->mtd; ++ int index = mtd_div_by_eb(((uint64_t)block * MY_BLOCK_SIZE), mtd); ++ int delta = mtd_mod_by_eb(((uint64_t)block * MY_BLOCK_SIZE), mtd); ++ int err; ++ loff_t off; ++ size_t retlen; ++ ++ if (!data->bbt) ++ create_bbt(data, mtd); ++ ++ if (!data->usable_count) ++ return -EOVERFLOW; ++ ++ index = get_from_bbt(data, index); ++ if (index < 0) ++ return -EOVERFLOW; ++ ++ off = index * mtd->erasesize + delta; ++ ++ err = mtd_read(dev->mtd, off, MY_BLOCK_SIZE, &retlen, buf); ++ if (err) { ++ /* ++ * -EUCLEAN is reported if there was a bit-flip which ++ * was corrected, so this is harmless. ++ * ++ * We do not report about it here unless debugging is ++ * enabled. A corresponding message will be printed ++ * later, when it is has been scrubbed. ++ */ ++ if (mtd_is_bitflip(err) && (MY_BLOCK_SIZE == retlen)) ++ return 0; ++ else ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int mtdblock_writesect(struct mtd_blktrans_dev *dev, ++ unsigned long block, char *buf) ++{ ++ return 1; ++} ++ ++static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ++{ ++ struct m_mtd_data *data = kzalloc(sizeof(*data), GFP_KERNEL); ++ struct mtd_blktrans_dev *dev = (struct mtd_blktrans_dev *)data; ++ BUG_ON(!data); ++ ++ dev->mtd = mtd; ++ dev->devnum = mtd->index; ++ dev->size = mtd->size / MY_BLOCK_SIZE; ++ dev->tr = tr; ++ dev->readonly = 1; ++ ++ if (add_mtd_blktrans_dev(dev)) ++ kfree(dev); ++} ++ ++static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) ++{ ++ struct m_mtd_data *data = (struct m_mtd_data *)dev; ++ ++ if (data->bbt) ++ kfree(data->bbt); ++ ++ del_mtd_blktrans_dev(dev); ++ ++} ++ ++static struct mtd_blktrans_ops mtdblock_tr = { ++ .name = "mtdblock_bbt_ro", ++ .major = MTD_BLOCK_MAJOR, ++ .part_bits = 0, ++ .blksize = MY_BLOCK_SIZE, ++ .readsect = mtdblock_readsect, ++ .writesect = mtdblock_writesect, ++ .add_mtd = mtdblock_add_mtd, ++ .remove_dev = mtdblock_remove_dev, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init mtdblock_init(void) ++{ ++ return register_mtd_blktrans(&mtdblock_tr); ++} ++ ++static void __exit mtdblock_exit(void) ++{ ++ deregister_mtd_blktrans(&mtdblock_tr); ++} ++ ++module_init(mtdblock_init); ++module_exit(mtdblock_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("wujiao"); ++MODULE_DESCRIPTION("Simple bad block tab based read-only block device emulation access to MTD devices"); +diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c +index 1433260d9..c9bdeb4dd 100644 +--- a/drivers/usb/common/common.c ++++ b/drivers/usb/common/common.c +@@ -25,6 +25,12 @@ static const char *const ep_type_names[] = { + [USB_ENDPOINT_XFER_INT] = "intr", + }; + ++/** ++ * usb_ep_type_string() - Returns human readable-name of the endpoint type. ++ * @ep_type: The endpoint type to return human-readable name for. If it's not ++ * any of the types: USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT}, ++ * usually got by usb_endpoint_type(), the string 'unknown' will be returned. ++ */ + const char *usb_ep_type_string(int ep_type) + { + if (ep_type < 0 || ep_type >= ARRAY_SIZE(ep_type_names)) +@@ -69,6 +75,19 @@ static const char *const speed_names[] = { + [USB_SPEED_SUPER_PLUS] = "super-speed-plus", + }; + ++static const char *const ssp_rate[] = { ++ [USB_SSP_GEN_UNKNOWN] = "UNKNOWN", ++ [USB_SSP_GEN_2x1] = "super-speed-plus-gen2x1", ++ [USB_SSP_GEN_1x2] = "super-speed-plus-gen1x2", ++ [USB_SSP_GEN_2x2] = "super-speed-plus-gen2x2", ++}; ++ ++/** ++ * usb_speed_string() - Returns human readable-name of the speed. ++ * @speed: The speed to return human-readable name for. If it's not ++ * any of the speeds defined in usb_device_speed enum, string for ++ * USB_SPEED_UNKNOWN will be returned. ++ */ + const char *usb_speed_string(enum usb_device_speed speed) + { + if (speed < 0 || speed >= ARRAY_SIZE(speed_names)) +@@ -77,6 +96,14 @@ const char *usb_speed_string(enum usb_device_speed speed) + } + EXPORT_SYMBOL_GPL(usb_speed_string); + ++/** ++ * usb_get_maximum_speed - Get maximum requested speed for a given USB ++ * controller. ++ * @dev: Pointer to the given USB controller device ++ * ++ * The function gets the maximum speed string from property "maximum-speed", ++ * and returns the corresponding enum usb_device_speed. ++ */ + enum usb_device_speed usb_get_maximum_speed(struct device *dev) + { + const char *maximum_speed; +@@ -86,12 +113,44 @@ enum usb_device_speed usb_get_maximum_speed(struct device *dev) + if (ret < 0) + return USB_SPEED_UNKNOWN; + +- ret = match_string(speed_names, ARRAY_SIZE(speed_names), maximum_speed); ++ ret = match_string(ssp_rate, ARRAY_SIZE(ssp_rate), maximum_speed); ++ if (ret > 0) ++ return USB_SPEED_SUPER_PLUS; + ++ ret = match_string(speed_names, ARRAY_SIZE(speed_names), maximum_speed); + return (ret < 0) ? USB_SPEED_UNKNOWN : ret; + } + EXPORT_SYMBOL_GPL(usb_get_maximum_speed); + ++/** ++ * usb_get_maximum_ssp_rate - Get the signaling rate generation and lane count ++ * of a SuperSpeed Plus capable device. ++ * @dev: Pointer to the given USB controller device ++ * ++ * If the string from "maximum-speed" property is super-speed-plus-genXxY where ++ * 'X' is the generation number and 'Y' is the number of lanes, then this ++ * function returns the corresponding enum usb_ssp_rate. ++ */ ++enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev) ++{ ++ const char *maximum_speed; ++ int ret; ++ ++ ret = device_property_read_string(dev, "maximum-speed", &maximum_speed); ++ if (ret < 0) ++ return USB_SSP_GEN_UNKNOWN; ++ ++ ret = match_string(ssp_rate, ARRAY_SIZE(ssp_rate), maximum_speed); ++ return (ret < 0) ? USB_SSP_GEN_UNKNOWN : ret; ++} ++EXPORT_SYMBOL_GPL(usb_get_maximum_ssp_rate); ++ ++/** ++ * usb_state_string - Returns human readable name for the state. ++ * @state: The state to return a human-readable name for. If it's not ++ * any of the states devices in usb_device_state_string enum, ++ * the string UNKNOWN will be returned. ++ */ + const char *usb_state_string(enum usb_device_state state) + { + static const char *const names[] = { +@@ -141,6 +200,67 @@ enum usb_dr_mode usb_get_dr_mode(struct device *dev) + } + EXPORT_SYMBOL_GPL(usb_get_dr_mode); + ++/** ++ * usb_get_role_switch_default_mode - Get default mode for given device ++ * @dev: Pointer to the given device ++ * ++ * The function gets string from property 'role-switch-default-mode', ++ * and returns the corresponding enum usb_dr_mode. ++ */ ++enum usb_dr_mode usb_get_role_switch_default_mode(struct device *dev) ++{ ++ const char *str; ++ int ret; ++ ++ ret = device_property_read_string(dev, "role-switch-default-mode", &str); ++ if (ret < 0) ++ return USB_DR_MODE_UNKNOWN; ++ ++ return usb_get_dr_mode_from_string(str); ++} ++EXPORT_SYMBOL_GPL(usb_get_role_switch_default_mode); ++ ++/** ++ * usb_decode_interval - Decode bInterval into the time expressed in 1us unit ++ * @epd: The descriptor of the endpoint ++ * @speed: The speed that the endpoint works as ++ * ++ * Function returns the interval expressed in 1us unit for servicing ++ * endpoint for data transfers. ++ */ ++unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd, ++ enum usb_device_speed speed) ++{ ++ unsigned int interval = 0; ++ ++ switch (usb_endpoint_type(epd)) { ++ case USB_ENDPOINT_XFER_CONTROL: ++ /* uframes per NAK */ ++ if (speed == USB_SPEED_HIGH) ++ interval = epd->bInterval; ++ break; ++ case USB_ENDPOINT_XFER_ISOC: ++ interval = 1 << (epd->bInterval - 1); ++ break; ++ case USB_ENDPOINT_XFER_BULK: ++ /* uframes per NAK */ ++ if (speed == USB_SPEED_HIGH && usb_endpoint_dir_out(epd)) ++ interval = epd->bInterval; ++ break; ++ case USB_ENDPOINT_XFER_INT: ++ if (speed >= USB_SPEED_HIGH) ++ interval = 1 << (epd->bInterval - 1); ++ else ++ interval = epd->bInterval; ++ break; ++ } ++ ++ interval *= (speed >= USB_SPEED_HIGH) ? 125 : 1000; ++ ++ return interval; ++} ++EXPORT_SYMBOL_GPL(usb_decode_interval); ++ + #ifdef CONFIG_OF + /** + * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device +diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c +index ba849c7bc..a76a086b9 100644 +--- a/drivers/usb/common/debug.c ++++ b/drivers/usb/common/debug.c +@@ -207,8 +207,26 @@ static void usb_decode_set_isoch_delay(__u8 wValue, char *str, size_t size) + snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", wValue); + } + +-/* +- * usb_decode_ctrl - returns a string representation of ctrl request ++/** ++ * usb_decode_ctrl - Returns human readable representation of control request. ++ * @str: buffer to return a human-readable representation of control request. ++ * This buffer should have about 200 bytes. ++ * @size: size of str buffer. ++ * @bRequestType: matches the USB bmRequestType field ++ * @bRequest: matches the USB bRequest field ++ * @wValue: matches the USB wValue field (CPU byte order) ++ * @wIndex: matches the USB wIndex field (CPU byte order) ++ * @wLength: matches the USB wLength field (CPU byte order) ++ * ++ * Function returns decoded, formatted and human-readable description of ++ * control request packet. ++ * ++ * The usage scenario for this is for tracepoints, so function as a return ++ * use the same value as in parameters. This approach allows to use this ++ * function in TP_printk ++ * ++ * Important: wValue, wIndex, wLength parameters before invoking this function ++ * should be processed by le16_to_cpu macro. + */ + const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType, + __u8 bRequest, __u16 wValue, __u16 wIndex, +diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c +index c9545a4ef..581d6db36 100644 +--- a/drivers/usb/common/usb-conn-gpio.c ++++ b/drivers/usb/common/usb-conn-gpio.c +@@ -83,11 +83,11 @@ static void usb_conn_detect_cable(struct work_struct *work) + else + role = USB_ROLE_NONE; + +- dev_dbg(info->dev, "role %d/%d, gpios: id %d, vbus %d\n", +- info->last_role, role, id, vbus); ++ dev_dbg(info->dev, "role %s -> %s, gpios: id %d, vbus %d\n", ++ usb_role_string(info->last_role), usb_role_string(role), id, vbus); + + if (info->last_role == role) { +- dev_warn(info->dev, "repeated role: %d\n", role); ++ dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role)); + return; + } + +diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c +index 1ef2de6e3..d8b0041de 100644 +--- a/drivers/usb/core/devices.c ++++ b/drivers/usb/core/devices.c +@@ -157,38 +157,25 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, + switch (usb_endpoint_type(desc)) { + case USB_ENDPOINT_XFER_CONTROL: + type = "Ctrl"; +- if (speed == USB_SPEED_HIGH) /* uframes per NAK */ +- interval = desc->bInterval; +- else +- interval = 0; + dir = 'B'; /* ctrl is bidirectional */ + break; + case USB_ENDPOINT_XFER_ISOC: + type = "Isoc"; +- interval = 1 << (desc->bInterval - 1); + break; + case USB_ENDPOINT_XFER_BULK: + type = "Bulk"; +- if (speed == USB_SPEED_HIGH && dir == 'O') /* uframes per NAK */ +- interval = desc->bInterval; +- else +- interval = 0; + break; + case USB_ENDPOINT_XFER_INT: + type = "Int."; +- if (speed == USB_SPEED_HIGH || speed >= USB_SPEED_SUPER) +- interval = 1 << (desc->bInterval - 1); +- else +- interval = desc->bInterval; + break; + default: /* "can't happen" */ + return start; + } +- interval *= (speed == USB_SPEED_HIGH || +- speed >= USB_SPEED_SUPER) ? 125 : 1000; +- if (interval % 1000) ++ ++ interval = usb_decode_interval(desc, speed); ++ if (interval % 1000) { + unit = 'u'; +- else { ++ } else { + unit = 'm'; + interval /= 1000; + } +diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c +index 1c2c04079..fc3341f2b 100644 +--- a/drivers/usb/core/endpoint.c ++++ b/drivers/usb/core/endpoint.c +@@ -84,40 +84,13 @@ static ssize_t interval_show(struct device *dev, struct device_attribute *attr, + char *buf) + { + struct ep_device *ep = to_ep_device(dev); ++ unsigned int interval; + char unit; +- unsigned interval = 0; +- unsigned in; + +- in = (ep->desc->bEndpointAddress & USB_DIR_IN); +- +- switch (usb_endpoint_type(ep->desc)) { +- case USB_ENDPOINT_XFER_CONTROL: +- if (ep->udev->speed == USB_SPEED_HIGH) +- /* uframes per NAK */ +- interval = ep->desc->bInterval; +- break; +- +- case USB_ENDPOINT_XFER_ISOC: +- interval = 1 << (ep->desc->bInterval - 1); +- break; +- +- case USB_ENDPOINT_XFER_BULK: +- if (ep->udev->speed == USB_SPEED_HIGH && !in) +- /* uframes per NAK */ +- interval = ep->desc->bInterval; +- break; +- +- case USB_ENDPOINT_XFER_INT: +- if (ep->udev->speed == USB_SPEED_HIGH) +- interval = 1 << (ep->desc->bInterval - 1); +- else +- interval = ep->desc->bInterval; +- break; +- } +- interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000; +- if (interval % 1000) ++ interval = usb_decode_interval(ep->desc, ep->udev->speed); ++ if (interval % 1000) { + unit = 'u'; +- else { ++ } else { + unit = 'm'; + interval /= 1000; + } +diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c +index ac347f9d5..1103bc58a 100644 +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -2649,6 +2649,26 @@ static void usb_put_invalidate_rhdev(struct usb_hcd *hcd) + usb_put_dev(rhdev); + } + ++/** ++ * usb_stop_hcd - Halt the HCD ++ * @hcd: the usb_hcd that has to be halted ++ * ++ * Stop the root-hub polling timer and invoke the HCD's ->stop callback. ++ */ ++static void usb_stop_hcd(struct usb_hcd *hcd) ++{ ++ hcd->rh_pollable = 0; ++ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); ++ del_timer_sync(&hcd->rh_timer); ++ ++ hcd->driver->stop(hcd); ++ hcd->state = HC_STATE_HALT; ++ ++ /* In case the HCD restarted the timer, stop it again. */ ++ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); ++ del_timer_sync(&hcd->rh_timer); ++} ++ + /** + * usb_add_hcd - finish generic HCD structure initialization and register + * @hcd: the usb_hcd structure to initialize +@@ -2741,6 +2761,7 @@ int usb_add_hcd(struct usb_hcd *hcd, + + rhdev->rx_lanes = 1; + rhdev->tx_lanes = 1; ++ rhdev->ssp_rate = USB_SSP_GEN_UNKNOWN; + + switch (hcd->speed) { + case HCD_USB11: +@@ -2758,8 +2779,11 @@ int usb_add_hcd(struct usb_hcd *hcd, + case HCD_USB32: + rhdev->rx_lanes = 2; + rhdev->tx_lanes = 2; +- fallthrough; ++ rhdev->ssp_rate = USB_SSP_GEN_2x2; ++ rhdev->speed = USB_SPEED_SUPER_PLUS; ++ break; + case HCD_USB31: ++ rhdev->ssp_rate = USB_SSP_GEN_2x1; + rhdev->speed = USB_SPEED_SUPER_PLUS; + break; + default: +@@ -2846,13 +2870,7 @@ int usb_add_hcd(struct usb_hcd *hcd, + return retval; + + err_register_root_hub: +- hcd->rh_pollable = 0; +- clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); +- del_timer_sync(&hcd->rh_timer); +- hcd->driver->stop(hcd); +- hcd->state = HC_STATE_HALT; +- clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); +- del_timer_sync(&hcd->rh_timer); ++ usb_stop_hcd(hcd); + err_hcd_driver_start: + if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0) + free_irq(irqnum, hcd); +@@ -2924,16 +2942,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) + * interrupt occurs), but usb_hcd_poll_rh_status() won't invoke + * the hub_status_data() callback. + */ +- hcd->rh_pollable = 0; +- clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); +- del_timer_sync(&hcd->rh_timer); +- +- hcd->driver->stop(hcd); +- hcd->state = HC_STATE_HALT; +- +- /* In case the HCD restarted the timer, stop it again. */ +- clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); +- del_timer_sync(&hcd->rh_timer); ++ usb_stop_hcd(hcd); + + if (usb_hcd_is_primary_hcd(hcd)) { + if (hcd->irq > 0) +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index 18ee3914b..e230027cb 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -31,6 +31,7 @@ + #include + #include + ++#include + #include + #include + +@@ -2861,12 +2862,11 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, + } else { + udev->rx_lanes = 1; + udev->tx_lanes = 1; ++ udev->ssp_rate = USB_SSP_GEN_UNKNOWN; + } + if (hub_is_wusb(hub)) + udev->speed = USB_SPEED_WIRELESS; +- else if (hub_is_superspeedplus(hub->hdev) && +- port_speed_is_ssp(hub->hdev, ext_portstatus & +- USB_EXT_PORT_STAT_RX_SPEED_ID)) ++ else if (udev->ssp_rate != USB_SSP_GEN_UNKNOWN) + udev->speed = USB_SPEED_SUPER_PLUS; + else if (hub_is_superspeed(hub->hdev)) + udev->speed = USB_SPEED_SUPER; +@@ -3344,6 +3344,26 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) + status = 0; + } + if (status) { ++ /* Check if the port has been suspended for the timeout case ++ * to prevent the suspended port from incorrect handling. ++ */ ++ if (status == -ETIMEDOUT) { ++ int ret; ++ u16 portstatus, portchange; ++ ++ portstatus = portchange = 0; ++ ret = hub_port_status(hub, port1, &portstatus, ++ &portchange); ++ ++ dev_dbg(&port_dev->dev, ++ "suspend timeout, status %04x\n", portstatus); ++ ++ if (ret == 0 && port_is_suspended(hub, portstatus)) { ++ status = 0; ++ goto suspend_done; ++ } ++ } ++ + dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status); + + /* Try to enable USB3 LTM again */ +@@ -3360,6 +3380,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) + if (!PMSG_IS_AUTO(msg)) + status = 0; + } else { ++ suspend_done: + dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n", + (PMSG_IS_AUTO(msg) ? "auto-" : ""), + udev->do_remote_wakeup); +@@ -4831,9 +4852,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, + "%s SuperSpeed%s%s USB device number %d using %s\n", + (udev->config) ? "reset" : "new", + (udev->speed == USB_SPEED_SUPER_PLUS) ? +- "Plus Gen 2" : " Gen 1", +- (udev->rx_lanes == 2 && udev->tx_lanes == 2) ? +- "x2" : "", ++ " Plus" : "", ++ (udev->ssp_rate == USB_SSP_GEN_2x2) ? ++ " Gen 2x2" : ++ (udev->ssp_rate == USB_SSP_GEN_2x1) ? ++ " Gen 2x1" : ++ (udev->ssp_rate == USB_SSP_GEN_1x2) ? ++ " Gen 1x2" : "", + devnum, driver_name); + } + +diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c +index 8d134193f..3014c9356 100644 +--- a/drivers/usb/core/sysfs.c ++++ b/drivers/usb/core/sysfs.c +@@ -167,7 +167,10 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr, + speed = "5000"; + break; + case USB_SPEED_SUPER_PLUS: +- speed = "10000"; ++ if (udev->ssp_rate == USB_SSP_GEN_2x2) ++ speed = "20000"; ++ else ++ speed = "10000"; + break; + default: + speed = "unknown"; +@@ -298,29 +301,6 @@ static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr, + } + static DEVICE_ATTR_RO(urbnum); + +-static ssize_t removable_show(struct device *dev, struct device_attribute *attr, +- char *buf) +-{ +- struct usb_device *udev; +- char *state; +- +- udev = to_usb_device(dev); +- +- switch (udev->removable) { +- case USB_DEVICE_REMOVABLE: +- state = "removable"; +- break; +- case USB_DEVICE_FIXED: +- state = "fixed"; +- break; +- default: +- state = "unknown"; +- } +- +- return sprintf(buf, "%s\n", state); +-} +-static DEVICE_ATTR_RO(removable); +- + static ssize_t ltm_capable_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +@@ -825,7 +805,6 @@ static struct attribute *dev_attrs[] = { + &dev_attr_avoid_reset_quirk.attr, + &dev_attr_authorized.attr, + &dev_attr_remove.attr, +- &dev_attr_removable.attr, + &dev_attr_ltm_capable.attr, + #ifdef CONFIG_OF + &dev_attr_devspec.attr, +diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c +index 9c285026f..33d62d7e3 100644 +--- a/drivers/usb/core/urb.c ++++ b/drivers/usb/core/urb.c +@@ -407,6 +407,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) + return -ENOEXEC; + is_out = !(setup->bRequestType & USB_DIR_IN) || + !setup->wLength; ++ dev_WARN_ONCE(&dev->dev, (usb_pipeout(urb->pipe) != is_out), ++ "BOGUS control dir, pipe %x doesn't match bRequestType %x\n", ++ urb->pipe, setup->bRequestType); ++ if (le16_to_cpu(setup->wLength) != urb->transfer_buffer_length) { ++ dev_dbg(&dev->dev, "BOGUS control len %d doesn't match transfer length %d\n", ++ le16_to_cpu(setup->wLength), ++ urb->transfer_buffer_length); ++ return -EBADR; ++ } + } else { + is_out = usb_endpoint_dir_out(&ep->desc); + } +diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c +index db4de5367..b241d1bbf 100644 +--- a/drivers/usb/core/usb.c ++++ b/drivers/usb/core/usb.c +@@ -982,17 +982,15 @@ static struct notifier_block usb_bus_nb = { + .notifier_call = usb_bus_notify, + }; + +-static struct dentry *usb_devices_root; +- + static void usb_debugfs_init(void) + { +- usb_devices_root = debugfs_create_file("devices", 0444, usb_debug_root, +- NULL, &usbfs_devices_fops); ++ debugfs_create_file("devices", 0444, usb_debug_root, NULL, ++ &usbfs_devices_fops); + } + + static void usb_debugfs_cleanup(void) + { +- debugfs_remove(usb_devices_root); ++ debugfs_remove(debugfs_lookup("devices", usb_debug_root)); + } + + /* +diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig +index c13171936..0376d8f4f 100644 +--- a/drivers/usb/dwc2/Kconfig ++++ b/drivers/usb/dwc2/Kconfig +@@ -94,4 +94,24 @@ config USB_DWC2_DEBUG_PERIODIC + non-periodic transfers, but of course the debug logs will be + incomplete. Note that this also disables some debug messages + for which the transfer type cannot be deduced. ++ ++config USB_DWC2_FORCE_FULL_SPEED ++ bool "Force full speed mode" ++ help ++ Say Y here to force full speed mode in the DWC2 Driver. ++ ++config USB_DWC2_EXT_ID_PIN ++ bool "External Id Pin" ++ help ++ Say Y here to enable external id pin in the DWC2 Driver. ++ Example: ++ echo "device" > /sys/class/usb_role/dwc2_new-role-switch/role ++ echo "host" > /sys/class/usb_role/dwc2_new-role-switch/role ++ echo "none" > /sys/class/usb_role/dwc2_new-role-switch/role ++ ++config USB_DWC2_EXT_VBUS_DETECT ++ bool "External Vbus Detect" ++ help ++ Say Y here to enable external vbus detect in the DWC2 Driver. ++ + endif +diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c +index 15911ac75..3d9259f8f 100644 +--- a/drivers/usb/dwc2/core.c ++++ b/drivers/usb/dwc2/core.c +@@ -80,10 +80,8 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) + gr->grxfsiz = dwc2_readl(hsotg, GRXFSIZ); + gr->gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ); + gr->gdfifocfg = dwc2_readl(hsotg, GDFIFOCFG); +- gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); + gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG); + gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL); +- gr->pcgcctl = dwc2_readl(hsotg, PCGCTL); + + gr->valid = true; + return 0; +@@ -119,9 +117,7 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) + dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ); + dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ); + dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG); +- dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1); + dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG); +- dwc2_writel(hsotg, gr->pcgcctl, PCGCTL); + dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL); + + return 0; +@@ -131,54 +127,26 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) + * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down. + * + * @hsotg: Programming view of the DWC_otg controller ++ * @rem_wakeup: indicates whether resume is initiated by Reset. + * @restore: Controller registers need to be restored + */ +-int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) ++int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup, ++ bool restore) + { +- u32 pcgcctl; +- int ret = 0; +- +- if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) +- return -ENOTSUPP; +- +- pcgcctl = dwc2_readl(hsotg, PCGCTL); +- pcgcctl &= ~PCGCTL_STOPPCLK; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- +- pcgcctl = dwc2_readl(hsotg, PCGCTL); +- pcgcctl &= ~PCGCTL_PWRCLMP; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- +- pcgcctl = dwc2_readl(hsotg, PCGCTL); +- pcgcctl &= ~PCGCTL_RSTPDWNMODULE; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- +- udelay(100); +- if (restore) { +- ret = dwc2_restore_global_registers(hsotg); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to restore registers\n", +- __func__); +- return ret; +- } +- if (dwc2_is_host_mode(hsotg)) { +- ret = dwc2_restore_host_registers(hsotg); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to restore host registers\n", +- __func__); +- return ret; +- } +- } else { +- ret = dwc2_restore_device_registers(hsotg, 0); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to restore device registers\n", +- __func__); +- return ret; +- } +- } +- } ++ struct dwc2_gregs_backup *gr; ++ ++ gr = &hsotg->gr_backup; + +- return ret; ++ /* ++ * Restore host or device regisers with the same mode core enterted ++ * to partial power down by checking "GOTGCTL_CURMODE_HOST" backup ++ * value of the "gotgctl" register. ++ */ ++ if (gr->gotgctl & GOTGCTL_CURMODE_HOST) ++ return dwc2_host_exit_partial_power_down(hsotg, rem_wakeup, ++ restore); ++ else ++ return dwc2_gadget_exit_partial_power_down(hsotg, restore); + } + + /** +@@ -188,57 +156,10 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore) + */ + int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) + { +- u32 pcgcctl; +- int ret = 0; +- +- if (!hsotg->params.power_down) +- return -ENOTSUPP; +- +- /* Backup all registers */ +- ret = dwc2_backup_global_registers(hsotg); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to backup global registers\n", +- __func__); +- return ret; +- } +- +- if (dwc2_is_host_mode(hsotg)) { +- ret = dwc2_backup_host_registers(hsotg); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to backup host registers\n", +- __func__); +- return ret; +- } +- } else { +- ret = dwc2_backup_device_registers(hsotg); +- if (ret) { +- dev_err(hsotg->dev, "%s: failed to backup device registers\n", +- __func__); +- return ret; +- } +- } +- +- /* +- * Clear any pending interrupts since dwc2 will not be able to +- * clear them after entering partial_power_down. +- */ +- dwc2_writel(hsotg, 0xffffffff, GINTSTS); +- +- /* Put the controller in low power state */ +- pcgcctl = dwc2_readl(hsotg, PCGCTL); +- +- pcgcctl |= PCGCTL_PWRCLMP; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- ndelay(20); +- +- pcgcctl |= PCGCTL_RSTPDWNMODULE; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- ndelay(20); +- +- pcgcctl |= PCGCTL_STOPPCLK; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- +- return ret; ++ if (dwc2_is_host_mode(hsotg)) ++ return dwc2_host_enter_partial_power_down(hsotg); ++ else ++ return dwc2_gadget_enter_partial_power_down(hsotg); + } + + /** +@@ -251,7 +172,6 @@ int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg) + static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode, + int is_host) + { +- u32 pcgcctl; + struct dwc2_gregs_backup *gr; + struct dwc2_dregs_backup *dr; + struct dwc2_hregs_backup *hr; +@@ -262,18 +182,6 @@ static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode, + + dev_dbg(hsotg->dev, "%s: restoring essential regs\n", __func__); + +- /* Load restore values for [31:14] bits */ +- pcgcctl = (gr->pcgcctl & 0xffffc000); +- /* If High Speed */ +- if (is_host) { +- if (!(pcgcctl & PCGCTL_P2HD_PRT_SPD_MASK)) +- pcgcctl |= BIT(17); +- } else { +- if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK)) +- pcgcctl |= BIT(17); +- } +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- + /* Umnask global Interrupt in GAHBCFG and restore it */ + dwc2_writel(hsotg, gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, GAHBCFG); + +@@ -288,23 +196,9 @@ static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode, + + if (is_host) { + dwc2_writel(hsotg, hr->hcfg, HCFG); +- if (rmode) +- pcgcctl |= PCGCTL_RESTOREMODE; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- udelay(10); +- +- pcgcctl |= PCGCTL_ESS_REG_RESTORED; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); + udelay(10); + } else { + dwc2_writel(hsotg, dr->dcfg, DCFG); +- if (!rmode) +- pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- udelay(10); +- +- pcgcctl |= PCGCTL_ESS_REG_RESTORED; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); + udelay(10); + } + } +@@ -370,11 +264,16 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, + if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_RESTOREDONE, + 20000)) { + dev_dbg(hsotg->dev, +- "%s: Restore Done wan't generated here\n", ++ "%s: Restore Done wasn't generated here\n", + __func__); + } else { + dev_dbg(hsotg->dev, "restore done generated here\n"); +- } ++ ++ /* ++ * To avoid restore done interrupt storm after restore is ++ * generated clear GINTSTS_RESTOREDONE bit. ++ */ ++ dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTSTS); } + } + + /** +@@ -387,7 +286,7 @@ static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg, + { + ktime_t start; + ktime_t end; +- unsigned int timeout = 110; ++ unsigned int timeout = 5000; + + dev_vdbg(hsotg->dev, "Waiting for %s mode\n", + host_mode ? "host" : "device"); +@@ -460,9 +359,6 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg) + */ + int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host) + { +- if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_HIBERNATION) +- return -ENOTSUPP; +- + if (is_host) + return dwc2_host_enter_hibernation(hsotg); + else +@@ -527,14 +423,14 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait) + if ((hsotg->hw_params.snpsid & DWC2_CORE_REV_MASK) < + (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) { + if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, +- GRSTCTL_CSFTRST, 10000)) { ++ GRSTCTL_CSFTRST, 100000)) { + dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST\n", + __func__); + return -EBUSY; + } + } else { + if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, +- GRSTCTL_CSFTRST_DONE, 10000)) { ++ GRSTCTL_CSFTRST_DONE, 100000)) { + dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST_DONE\n", + __func__); + return -EBUSY; +@@ -545,6 +441,22 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait) + dwc2_writel(hsotg, greset, GRSTCTL); + } + ++ /* ++ * Switching from device mode to host mode by disconnecting ++ * device cable core enters and exits form hibernation. ++ * However, the fifo map remains not cleared. It results ++ * to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/ ++ * gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2]) ++ * if in host mode we disconnect the micro a to b host ++ * cable. Because core reset occurs. ++ * To avoid the WARNING, fifo_map should be cleared ++ * in dwc2_core_reset() function by taking into account configs. ++ * fifo_map must be cleared only if driver is configured in ++ * "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE" ++ * mode. ++ */ ++ dwc2_clear_fifo_map(hsotg); ++ + /* Wait for AHB master IDLE state */ + if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) { + dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n", +@@ -682,16 +594,7 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) + /* + * dwc2_enable_acg - enable active clock gating feature + */ +-void dwc2_enable_acg(struct dwc2_hsotg *hsotg) +-{ +- if (hsotg->params.acg_enable) { +- u32 pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1); +- +- dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n"); +- pcgcctl1 |= PCGCCTL1_GATEEN; +- dwc2_writel(hsotg, pcgcctl1, PCGCCTL1); +- } +-} ++void dwc2_enable_acg(struct dwc2_hsotg *hsotg) { } + + /** + * dwc2_dump_host_registers() - Prints the host registers +@@ -819,9 +722,6 @@ void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg) + addr = hsotg->regs + GPVNDCTL; + dev_dbg(hsotg->dev, "GPVNDCTL @0x%08lX : 0x%08X\n", + (unsigned long)addr, dwc2_readl(hsotg, GPVNDCTL)); +- addr = hsotg->regs + GGPIO; +- dev_dbg(hsotg->dev, "GGPIO @0x%08lX : 0x%08X\n", +- (unsigned long)addr, dwc2_readl(hsotg, GGPIO)); + addr = hsotg->regs + GUID; + dev_dbg(hsotg->dev, "GUID @0x%08lX : 0x%08X\n", + (unsigned long)addr, dwc2_readl(hsotg, GUID)); +@@ -852,10 +752,6 @@ void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg) + addr = hsotg->regs + HPTXFSIZ; + dev_dbg(hsotg->dev, "HPTXFSIZ @0x%08lX : 0x%08X\n", + (unsigned long)addr, dwc2_readl(hsotg, HPTXFSIZ)); +- +- addr = hsotg->regs + PCGCTL; +- dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n", +- (unsigned long)addr, dwc2_readl(hsotg, PCGCTL)); + #endif + } + +@@ -1063,7 +959,7 @@ void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) + + static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) + { +- u32 usbcfg, ggpio, i2cctl; ++ u32 usbcfg, i2cctl; + int retval = 0; + + /* +@@ -1087,19 +983,6 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) + return retval; + } + } +- +- if (hsotg->params.activate_stm_fs_transceiver) { +- ggpio = dwc2_readl(hsotg, GGPIO); +- if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { +- dev_dbg(hsotg->dev, "Activating transceiver\n"); +- /* +- * STM32F4x9 uses the GGPIO register as general +- * core configuration register. +- */ +- ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; +- dwc2_writel(hsotg, ggpio, GGPIO); +- } +- } + } + + /* +@@ -1206,6 +1089,7 @@ static void dwc2_set_turnaround_time(struct dwc2_hsotg *hsotg) + dwc2_writel(hsotg, usbcfg, GUSBCFG); + } + ++ + int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) + { + u32 usbcfg; +diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h +index 03d16a082..598817d99 100644 +--- a/drivers/usb/dwc2/core.h ++++ b/drivers/usb/dwc2/core.h +@@ -121,6 +121,7 @@ struct dwc2_hsotg_req; + * @periodic: Set if this is a periodic ep, such as Interrupt + * @isochronous: Set if this is a isochronous ep + * @send_zlp: Set if we need to send a zero-length packet. ++ * @wedged: Set if ep is wedged. + * @desc_list_dma: The DMA address of descriptor chain currently in use. + * @desc_list: Pointer to descriptor DMA chain head currently in use. + * @desc_count: Count of entries within the DMA descriptor chain of EP. +@@ -171,6 +172,7 @@ struct dwc2_hsotg_ep { + unsigned int periodic:1; + unsigned int isochronous:1; + unsigned int send_zlp:1; ++ unsigned int wedged:1; + unsigned int target_frame; + #define TARGET_FRAME_INITIAL 0xFFFFFFFF + bool frame_overrun; +@@ -208,8 +210,21 @@ do { \ + spin_lock(&_hs->lock); \ + } \ + } while (0) ++ ++#define call_gadget_set_state(_hs, _state) \ ++ usb_gadget_set_state(&_hs->gadget, _state) ++ ++#define set_gadget_resume_state(_hs) _hs->resume_state = _hs->gadget.state ++#define get_gadget_resume_state(_hs) _hs->resume_state ++#define get_gadget_enabled(_hs) _hs->enabled + #else ++ + #define call_gadget(_hs, _entry) do {} while (0) ++#define call_gadget_set_state(_hs, _state) do {} while (0) ++ ++#define set_gadget_resume_state(_hs) do {} while (0) ++#define get_gadget_resume_state(_hs) 0 ++#define get_gadget_enabled(_hs) 0 + #endif + + struct dwc2_hsotg; +@@ -235,11 +250,14 @@ enum dwc2_ep0_state { + /** + * struct dwc2_core_params - Parameters for configuring the core + * +- * @otg_cap: Specifies the OTG capabilities. +- * 0 - HNP and SRP capable +- * 1 - SRP Only capable +- * 2 - No HNP/SRP capable (always available) +- * Defaults to best available option (0, 1, then 2) ++ * @otg_caps: Specifies the OTG capabilities. OTG caps from the platform parameters, ++ * used to setup the: ++ * - HNP and SRP capable ++ * - SRP Only capable ++ * - No HNP/SRP capable (always available) ++ * Defaults to best available option ++ * - OTG revision number the device is compliant with, in binary-coded ++ * decimal (i.e. 2.0 is 0200H). (see struct usb_otg_caps) + * @host_dma: Specifies whether to use slave or DMA mode for accessing + * the data FIFOs. The driver will automatically detect the + * value for this parameter if none is specified. +@@ -375,6 +393,9 @@ enum dwc2_ep0_state { + * case. + * 0 - No (default) + * 1 - Yes ++ * @external_vbus_detect: Specifies whether VBUS detect is handled externally. ++ * 0 - No (default) ++ * 1 - Yes + * @power_down: Specifies whether the controller support power_down. + * If power_down is enabled, the controller will enter + * power_down in both peripheral and host mode when +@@ -409,14 +430,6 @@ enum dwc2_ep0_state { + * device had been in L1 state until that period. + * This is used by SW to initiate Remote WakeUp in the + * controller so as to sync to the uF number from the host. +- * @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO +- * register. +- * 0 - Deactivate the transceiver (default) +- * 1 - Activate the transceiver +- * @activate_stm_id_vb_detection: Activate external ID pin and Vbus level +- * detection using GGPIO register. +- * 0 - Deactivate the external level detection (default) +- * 1 - Activate the external level detection + * @g_dma: Enables gadget dma usage (default: autodetect). + * @g_dma_desc: Enables gadget descriptor DMA (default: autodetect). + * @g_rx_fifo_size: The periodic rx fifo size for the device, in +@@ -428,7 +441,7 @@ enum dwc2_ep0_state { + * @g_tx_fifo_size: An array of TX fifo sizes in dedicated fifo + * mode. Each value corresponds to one EP + * starting from EP1 (max 15 values). Sizes are +- * in DWORDS with possible values from from ++ * in DWORDS with possible values from + * 16-32768 (default: 256, 256, 256, 256, 768, + * 768, 768, 768, 0, 0, 0, 0, 0, 0, 0). + * @change_speed_quirk: Change speed configuration to DWC2_SPEED_PARAM_FULL +@@ -447,10 +460,7 @@ enum dwc2_ep0_state { + * default described above. + */ + struct dwc2_core_params { +- u8 otg_cap; +-#define DWC2_CAP_PARAM_HNP_SRP_CAPABLE 0 +-#define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE 1 +-#define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 ++ struct usb_otg_caps otg_caps; + + u8 phy_type; + #define DWC2_PHY_TYPE_PARAM_FS 0 +@@ -474,6 +484,7 @@ struct dwc2_core_params { + bool reload_ctl; + bool uframe_sched; + bool external_id_pin_ctl; ++ bool external_vbus_detect; + + int power_down; + #define DWC2_POWER_DOWN_PARAM_NONE 0 +@@ -486,8 +497,6 @@ struct dwc2_core_params { + bool hird_threshold_en; + bool service_interval; + u8 hird_threshold; +- bool activate_stm_fs_transceiver; +- bool activate_stm_id_vb_detection; + bool ipg_isoc_en; + u16 max_packet_count; + u32 max_transfer_size; +@@ -690,7 +699,6 @@ struct dwc2_hw_params { + * @glpmcfg: Backup of GLPMCFG register + * @gdfifocfg: Backup of GDFIFOCFG register + * @pcgcctl: Backup of PCGCCTL register +- * @pcgcctl1: Backup of PCGCCTL1 register + * @dtxfsiz: Backup of DTXFSIZ registers for each endpoint + * @gpwrdn: Backup of GPWRDN register + * @valid: True if registers values backuped. +@@ -704,8 +712,6 @@ struct dwc2_gregs_backup { + u32 gnptxfsiz; + u32 gi2cctl; + u32 glpmcfg; +- u32 pcgcctl; +- u32 pcgcctl1; + u32 gdfifocfg; + u32 gpwrdn; + bool valid; +@@ -867,6 +873,8 @@ struct dwc2_hregs_backup { + * @gadget_enabled: Peripheral mode sub-driver initialization indicator. + * @ll_hw_enabled: Status of low-level hardware resources. + * @hibernated: True if core is hibernated ++ * @in_ppd: True if core is partial power down mode. ++ * @bus_suspended: True if bus is suspended + * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a + * remote wakeup. + * @phy_off_for_suspend: Status of whether we turned the PHY off at suspend. +@@ -1024,7 +1032,6 @@ struct dwc2_hregs_backup { + * a pointer to an array of register definitions, the + * array size and the base address where the register bank + * is to be found. +- * @bus_suspended: True if bus is suspended + * @last_frame_num: Number of last frame. Range from 0 to 32768 + * @frame_num_array: Used only if CONFIG_USB_DWC2_TRACK_MISSED_SOFS is + * defined, for missed SOFs tracking. Array holds that +@@ -1062,9 +1069,12 @@ struct dwc2_hsotg { + unsigned int gadget_enabled:1; + unsigned int ll_hw_enabled:1; + unsigned int hibernated:1; ++ unsigned int in_ppd:1; ++ bool bus_suspended; + unsigned int reset_phy_on_wake:1; + unsigned int need_phy_for_wake:1; + unsigned int phy_off_for_suspend:1; ++ unsigned int vbus_supply_enabled:1; + u16 frame_number; + + struct phy *phy; +@@ -1072,7 +1082,6 @@ struct dwc2_hsotg { + struct dwc2_hsotg_plat *plat; + struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; + struct regulator *vbus_supply; +- struct regulator *usb33d; + + spinlock_t lock; + void *priv; +@@ -1145,7 +1154,6 @@ struct dwc2_hsotg { + unsigned long hs_periodic_bitmap[ + DIV_ROUND_UP(DWC2_HS_SCHEDULE_US, BITS_PER_LONG)]; + u16 periodic_qh_count; +- bool bus_suspended; + bool new_connection; + + u16 last_frame_num; +@@ -1206,6 +1214,7 @@ struct dwc2_hsotg { + struct dwc2_dma_desc *ctrl_out_desc; + + struct usb_gadget gadget; ++ enum usb_device_state resume_state; + unsigned int enabled:1; + unsigned int connected:1; + unsigned int remote_wakeup_allowed:1; +@@ -1303,7 +1312,8 @@ static inline bool dwc2_is_hs_iot(struct dwc2_hsotg *hsotg) + */ + int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait); + int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg); +-int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore); ++int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup, ++ bool restore); + int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host); + int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, + int reset, int is_host); +@@ -1381,8 +1391,6 @@ static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg) + } + + int dwc2_drd_init(struct dwc2_hsotg *hsotg); +-void dwc2_drd_suspend(struct dwc2_hsotg *hsotg); +-void dwc2_drd_resume(struct dwc2_hsotg *hsotg); + void dwc2_drd_exit(struct dwc2_hsotg *hsotg); + + /* +@@ -1412,11 +1420,19 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup); + int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg); + int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, + int rem_wakeup, int reset); ++int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg); ++int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg, ++ bool restore); ++void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg); ++void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, ++ int rem_wakeup); + int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg); + int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg); + int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg); + void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg); + void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg); ++static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg) ++{ hsotg->fifo_map = 0; } + #else + static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2) + { return 0; } +@@ -1446,6 +1462,14 @@ static inline int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) + static inline int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, + int rem_wakeup, int reset) + { return 0; } ++static inline int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg) ++{ return 0; } ++static inline int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg, ++ bool restore) ++{ return 0; } ++static inline void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg) {} ++static inline void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, ++ int rem_wakeup) {} + static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) + { return 0; } + static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) +@@ -1454,6 +1478,7 @@ static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) + { return 0; } + static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {} + static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {} ++static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg) {} + #endif + + #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +@@ -1463,11 +1488,18 @@ void dwc2_hcd_connect(struct dwc2_hsotg *hsotg); + void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force); + void dwc2_hcd_start(struct dwc2_hsotg *hsotg); + int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup); ++int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex); ++int dwc2_port_resume(struct dwc2_hsotg *hsotg); + int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg); + int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg); + int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg); + int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, + int rem_wakeup, int reset); ++int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg); ++int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg, ++ int rem_wakeup, bool restore); ++void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg); ++void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup); + bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2); + static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) + { schedule_work(&hsotg->phy_reset_work); } +@@ -1483,6 +1515,10 @@ static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {} + static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {} + static inline int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup) + { return 0; } ++static inline int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) ++{ return 0; } ++static inline int dwc2_port_resume(struct dwc2_hsotg *hsotg) ++{ return 0; } + static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg) + { return 0; } + static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg) +@@ -1494,6 +1530,14 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg) + static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, + int rem_wakeup, int reset) + { return 0; } ++static inline int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg) ++{ return 0; } ++static inline int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg, ++ int rem_wakeup, bool restore) ++{ return 0; } ++static inline void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg) {} ++static inline void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, ++ int rem_wakeup) {} + static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2) + { return false; } + static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {} +diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c +index e3f429f15..b1a4a1a0a 100644 +--- a/drivers/usb/dwc2/core_intr.c ++++ b/drivers/usb/dwc2/core_intr.c +@@ -317,10 +317,17 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) + + if (dwc2_is_device_mode(hsotg)) { + if (hsotg->lx_state == DWC2_L2) { +- ret = dwc2_exit_partial_power_down(hsotg, true); +- if (ret && (ret != -ENOTSUPP)) +- dev_err(hsotg->dev, +- "exit power_down failed\n"); ++ if (hsotg->in_ppd) { ++ ret = dwc2_exit_partial_power_down(hsotg, 0, true); ++ if (ret) ++ dev_err(hsotg->dev, ++ "exit power_down failed\n"); ++ } ++ ++ /* Exit gadget mode clock gating. */ ++ if (hsotg->params.power_down == ++ DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) ++ dwc2_gadget_exit_clock_gating(hsotg, 0); + } + + /* +@@ -387,6 +394,7 @@ static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg) + + /* Inform gadget to exit from L1 */ + call_gadget(hsotg, resume); ++ call_gadget_set_state(hsotg, get_gadget_resume_state(hsotg)); + } + + /* +@@ -415,32 +423,39 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) + dev_dbg(hsotg->dev, "DSTS=0x%0x\n", + dwc2_readl(hsotg, DSTS)); + if (hsotg->lx_state == DWC2_L2) { +- u32 dctl = dwc2_readl(hsotg, DCTL); +- +- /* Clear Remote Wakeup Signaling */ +- dctl &= ~DCTL_RMTWKUPSIG; +- dwc2_writel(hsotg, dctl, DCTL); +- ret = dwc2_exit_partial_power_down(hsotg, true); +- if (ret && (ret != -ENOTSUPP)) +- dev_err(hsotg->dev, "exit power_down failed\n"); ++ if (hsotg->in_ppd) { ++ u32 dctl = dwc2_readl(hsotg, DCTL); ++ /* Clear Remote Wakeup Signaling */ ++ dctl &= ~DCTL_RMTWKUPSIG; ++ dwc2_writel(hsotg, dctl, DCTL); ++ ret = dwc2_exit_partial_power_down(hsotg, 1, true); ++ if (ret) ++ dev_err(hsotg->dev, ++ "exit partial_power_down failed\n"); ++ call_gadget(hsotg, resume); ++ call_gadget_set_state(hsotg, get_gadget_resume_state(hsotg)); ++ } + +- /* Change to L0 state */ +- hsotg->lx_state = DWC2_L0; +- call_gadget(hsotg, resume); ++ /* Exit gadget mode clock gating. */ ++ if (hsotg->params.power_down == ++ DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) ++ dwc2_gadget_exit_clock_gating(hsotg, 0); + } else { + /* Change to L0 state */ + hsotg->lx_state = DWC2_L0; + } + } else { +- if (hsotg->params.power_down) +- return; +- +- if (hsotg->lx_state != DWC2_L1) { +- u32 pcgcctl = dwc2_readl(hsotg, PCGCTL); ++ if (hsotg->lx_state == DWC2_L2) { ++ if (hsotg->in_ppd) { ++ ret = dwc2_exit_partial_power_down(hsotg, 1, true); ++ if (ret) ++ dev_err(hsotg->dev, ++ "exit partial_power_down failed\n"); ++ } + +- /* Restart the Phy Clock */ +- pcgcctl &= ~PCGCTL_STOPPCLK; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); ++ if (hsotg->params.power_down == ++ DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) ++ dwc2_host_exit_clock_gating(hsotg, 1); + + /* + * If we've got this quirk then the PHY is stuck upon +@@ -516,31 +531,32 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) + return; + } + if (dsts & DSTS_SUSPSTS) { +- if (hsotg->hw_params.power_optimized) { ++ switch (hsotg->params.power_down) { ++ case DWC2_POWER_DOWN_PARAM_PARTIAL: + ret = dwc2_enter_partial_power_down(hsotg); +- if (ret) { +- if (ret != -ENOTSUPP) +- dev_err(hsotg->dev, +- "%s: enter partial_power_down failed\n", +- __func__); +- goto skip_power_saving; +- } ++ if (ret) ++ dev_err(hsotg->dev, ++ "enter partial_power_down failed\n"); + + udelay(100); + + /* Ask phy to be suspended */ +- if (!IS_ERR_OR_NULL(hsotg->uphy)) +- usb_phy_set_suspend(hsotg->uphy, true); +- } +- +- if (hsotg->hw_params.hibernation) { ++ usb_phy_set_suspend(hsotg->uphy, true); ++ break; ++ case DWC2_POWER_DOWN_PARAM_HIBERNATION: + ret = dwc2_enter_hibernation(hsotg, 0); +- if (ret && ret != -ENOTSUPP) ++ if (ret) + dev_err(hsotg->dev, +- "%s: enter hibernation failed\n", +- __func__); ++ "enter hibernation failed\n"); ++ break; ++ case DWC2_POWER_DOWN_PARAM_NONE: ++ /* ++ * If neither hibernation nor partial power down are supported, ++ * clock gating is used to save power. ++ */ ++ dwc2_gadget_enter_clock_gating(hsotg); + } +-skip_power_saving: ++ + /* + * Change to L2 (suspend) state before releasing + * spinlock +@@ -549,6 +565,8 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) + + /* Call gadget suspend callback */ + call_gadget(hsotg, suspend); ++ set_gadget_resume_state(hsotg); ++ call_gadget_set_state(hsotg, USB_STATE_SUSPENDED); + } + } else { + if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) { +@@ -565,6 +583,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) + } + } + ++ + /** + * dwc2_handle_lpm_intr - GINTSTS_LPMTRANRCVD Interrupt handler + * +@@ -574,7 +593,6 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) + static void dwc2_handle_lpm_intr(struct dwc2_hsotg *hsotg) + { + u32 glpmcfg; +- u32 pcgcctl; + u32 hird; + u32 hird_thres; + u32 hird_thres_en; +@@ -605,10 +623,6 @@ static void dwc2_handle_lpm_intr(struct dwc2_hsotg *hsotg) + dev_dbg(hsotg->dev, "L1 with utmi_sleep_n\n"); + } else { + dev_dbg(hsotg->dev, "Entering Sleep with L1 Gating\n"); +- +- pcgcctl = dwc2_readl(hsotg, PCGCTL); +- pcgcctl |= PCGCTL_ENBL_SLEEP_GATING; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); + } + /** + * Examine prt_sleep_sts after TL1TokenTetry period max (10 us) +@@ -625,6 +639,8 @@ static void dwc2_handle_lpm_intr(struct dwc2_hsotg *hsotg) + + /* Inform gadget that we are in L1 state */ + call_gadget(hsotg, suspend); ++ set_gadget_resume_state(hsotg); ++ call_gadget_set_state(hsotg, USB_STATE_SUSPENDED); + } + } + } +@@ -707,11 +723,7 @@ static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg, + dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN); + + hsotg->hibernated = 0; +- +-#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || \ +- IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) + hsotg->bus_suspended = 0; +-#endif + + if (gpwrdn & GPWRDN_IDSTS) { + hsotg->op_state = OTG_STATE_B_PERIPHERAL; +@@ -735,10 +747,11 @@ static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg, + * The GPWRDN interrupts are those that occur in both Host and + * Device mode while core is in hibernated state. + */ +-static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg) ++static int dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg) + { + u32 gpwrdn; + int linestate; ++ int ret = 0; + + gpwrdn = dwc2_readl(hsotg, GPWRDN); + /* clear all interrupt */ +@@ -762,17 +775,28 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg) + if (hsotg->hw_params.hibernation && + hsotg->hibernated) { + if (gpwrdn & GPWRDN_IDSTS) { +- dwc2_exit_hibernation(hsotg, 0, 0, 0); ++ ret = dwc2_exit_hibernation(hsotg, 0, 0, 0); ++ if (ret) ++ dev_err(hsotg->dev, ++ "exit hibernation failed.\n"); + call_gadget(hsotg, resume); ++ call_gadget_set_state(hsotg, get_gadget_resume_state(hsotg)); + } else { +- dwc2_exit_hibernation(hsotg, 1, 0, 1); ++ ret = dwc2_exit_hibernation(hsotg, 1, 0, 1); ++ if (ret) ++ dev_err(hsotg->dev, ++ "exit hibernation failed.\n"); + } + } + } else if ((gpwrdn & GPWRDN_RST_DET) && + (gpwrdn & GPWRDN_RST_DET_MSK)) { + dev_dbg(hsotg->dev, "%s: GPWRDN_RST_DET\n", __func__); +- if (!linestate && (gpwrdn & GPWRDN_BSESSVLD)) +- dwc2_exit_hibernation(hsotg, 0, 1, 0); ++ if (!linestate) { ++ ret = dwc2_exit_hibernation(hsotg, 0, 1, 0); ++ if (ret) ++ dev_err(hsotg->dev, ++ "exit hibernation failed.\n"); ++ } + } else if ((gpwrdn & GPWRDN_STS_CHGINT) && + (gpwrdn & GPWRDN_STS_CHGINT_MSK)) { + dev_dbg(hsotg->dev, "%s: GPWRDN_STS_CHGINT\n", __func__); +@@ -784,6 +808,8 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg) + */ + dwc_handle_gpwrdn_disc_det(hsotg, gpwrdn); + } ++ ++ return ret; + } + + /* +@@ -841,7 +867,7 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev) + dwc2_handle_disconnect_intr(hsotg); + if (gintsts & GINTSTS_SESSREQINT) + dwc2_handle_session_req_intr(hsotg); +- if (gintsts & GINTSTS_WKUPINT) ++ if (usb_phy_get_wakeup(hsotg->uphy) || (gintsts & GINTSTS_WKUPINT)) + dwc2_handle_wakeup_detected_intr(hsotg); + if (gintsts & GINTSTS_USBSUSP) + dwc2_handle_usb_suspend_intr(hsotg); +diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c +index aaafd463d..0455491b8 100644 +--- a/drivers/usb/dwc2/debugfs.c ++++ b/drivers/usb/dwc2/debugfs.c +@@ -535,7 +535,6 @@ static const struct debugfs_reg32 dwc2_regs[] = { + dump_register(DTXFSTS(13)), + dump_register(DTXFSTS(14)), + dump_register(DTXFSTS(15)), +- dump_register(PCGCTL), + dump_register(HCFG), + dump_register(HFIR), + dump_register(HFNUM), +@@ -670,7 +669,9 @@ static int params_show(struct seq_file *seq, void *v) + struct dwc2_core_params *p = &hsotg->params; + int i; + +- print_param(seq, p, otg_cap); ++ print_param(seq, p, otg_caps.hnp_support); ++ print_param(seq, p, otg_caps.srp_support); ++ print_param(seq, p, otg_caps.otg_rev); + print_param(seq, p, dma_desc_enable); + print_param(seq, p, dma_desc_fs_enable); + print_param(seq, p, speed); +diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c +index 36f2c3841..a5d23f1d1 100644 +--- a/drivers/usb/dwc2/drd.c ++++ b/drivers/usb/dwc2/drd.c +@@ -13,6 +13,22 @@ + #include + #include "core.h" + ++static void dwc2_vbus_valid(struct dwc2_hsotg *hsotg) ++{ ++ unsigned long flags; ++ u32 gotgctl; ++ ++ spin_lock_irqsave(&hsotg->lock, flags); ++ ++ gotgctl = dwc2_readl(hsotg, GOTGCTL); ++ gotgctl |= GOTGCTL_VBVALOEN | GOTGCTL_VBVALOVAL; ++ gotgctl |= GOTGCTL_AVALOEN | GOTGCTL_AVALOVAL; ++ gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL; ++ dwc2_writel(hsotg, gotgctl, GOTGCTL); ++ ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++} ++ + static void dwc2_ovr_init(struct dwc2_hsotg *hsotg) + { + unsigned long flags; +@@ -35,11 +51,6 @@ static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid) + { + u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); + +- /* Check if A-Session is already in the right state */ +- if ((valid && (gotgctl & GOTGCTL_ASESVLD)) || +- (!valid && !(gotgctl & GOTGCTL_ASESVLD))) +- return -EALREADY; +- + gotgctl &= ~GOTGCTL_BVALOVAL; + if (valid) + gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; +@@ -54,11 +65,6 @@ static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid) + { + u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); + +- /* Check if B-Session is already in the right state */ +- if ((valid && (gotgctl & GOTGCTL_BSESVLD)) || +- (!valid && !(gotgctl & GOTGCTL_BSESVLD))) +- return -EALREADY; +- + gotgctl &= ~GOTGCTL_AVALOVAL; + if (valid) + gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; +@@ -73,22 +79,12 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) + { + struct dwc2_hsotg *hsotg = usb_role_switch_get_drvdata(sw); + unsigned long flags; +- int already = 0; + + /* Skip session not in line with dr_mode */ + if ((role == USB_ROLE_DEVICE && hsotg->dr_mode == USB_DR_MODE_HOST) || + (role == USB_ROLE_HOST && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)) + return -EINVAL; + +-#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ +- IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +- /* Skip session if core is in test mode */ +- if (role == USB_ROLE_NONE && hsotg->test_mode) { +- dev_dbg(hsotg->dev, "Core is in test mode\n"); +- return -EBUSY; +- } +-#endif +- + /* + * In case of USB_DR_MODE_PERIPHERAL, clock is disabled at the end of + * the probe and enabled on udc_start. +@@ -106,18 +102,18 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) + spin_lock_irqsave(&hsotg->lock, flags); + + if (role == USB_ROLE_HOST) { +- already = dwc2_ovr_avalid(hsotg, true); ++ dwc2_ovr_avalid(hsotg, true); + } else if (role == USB_ROLE_DEVICE) { +- already = dwc2_ovr_bvalid(hsotg, true); ++ dwc2_ovr_bvalid(hsotg, true); + if (dwc2_is_device_enabled(hsotg)) { + /* This clear DCTL.SFTDISCON bit */ + dwc2_hsotg_core_connect(hsotg); + } + } else { + if (dwc2_is_device_mode(hsotg)) { +- if (!dwc2_ovr_bvalid(hsotg, false)) +- /* This set DCTL.SFTDISCON bit */ +- dwc2_hsotg_core_disconnect(hsotg); ++ dwc2_ovr_bvalid(hsotg, false); ++ /* This set DCTL.SFTDISCON bit */ ++ dwc2_hsotg_core_disconnect(hsotg); + } else { + dwc2_ovr_avalid(hsotg, false); + } +@@ -125,9 +121,29 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) + + spin_unlock_irqrestore(&hsotg->lock, flags); + +- if (!already && hsotg->dr_mode == USB_DR_MODE_OTG) +- /* This will raise a Connector ID Status Change Interrupt */ +- dwc2_force_mode(hsotg, role == USB_ROLE_HOST); ++ /* Wait for the session parameters to take effect */ ++ msleep(100); ++ ++ if (role == USB_ROLE_HOST) { ++ if (dwc2_is_device_mode(hsotg)) { ++ dwc2_force_mode(hsotg, true); ++ ++ if (hsotg->wq_otg) ++ queue_work(hsotg->wq_otg, &hsotg->wf_otg); ++ } ++ } else if (role == USB_ROLE_DEVICE) { ++ if (dwc2_is_host_mode(hsotg)) { ++ dwc2_force_mode(hsotg, false); ++ ++ if (hsotg->wq_otg) ++ queue_work(hsotg->wq_otg, &hsotg->wf_otg); ++ } else { ++ spin_lock_irqsave(&hsotg->lock, flags); ++ if (get_gadget_enabled(hsotg)) ++ dwc2_hsotg_core_connect(hsotg); ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ } ++ } + + if (!hsotg->ll_hw_enabled && hsotg->clk) + clk_disable_unprepare(hsotg->clk); +@@ -139,23 +155,35 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) + return 0; + } + ++static const struct software_node ingenic_usb_node = { ++ "ingenic-usb-sw", ++}; ++ + int dwc2_drd_init(struct dwc2_hsotg *hsotg) + { + struct usb_role_switch_desc role_sw_desc = {0}; + struct usb_role_switch *role_sw; + int ret; + +- if (!device_property_read_bool(hsotg->dev, "usb-role-switch")) ++ if (hsotg->params.external_vbus_detect) ++ dwc2_vbus_valid(hsotg); ++ ++ if (!hsotg->params.external_id_pin_ctl) + return 0; + ++ ret = software_node_register(&ingenic_usb_node); ++ if (ret) ++ return ret; ++ + role_sw_desc.driver_data = hsotg; +- role_sw_desc.fwnode = dev_fwnode(hsotg->dev); ++ role_sw_desc.fwnode = software_node_fwnode(&ingenic_usb_node); + role_sw_desc.set = dwc2_drd_role_sw_set; + role_sw_desc.allow_userspace_control = true; + + role_sw = usb_role_switch_register(hsotg->dev, &role_sw_desc); + if (IS_ERR(role_sw)) { + ret = PTR_ERR(role_sw); ++ fwnode_handle_put(role_sw_desc.fwnode); + dev_err(hsotg->dev, + "failed to register role switch: %d\n", ret); + return ret; +@@ -169,34 +197,10 @@ int dwc2_drd_init(struct dwc2_hsotg *hsotg) + return 0; + } + +-void dwc2_drd_suspend(struct dwc2_hsotg *hsotg) +-{ +- u32 gintsts, gintmsk; +- +- if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) { +- gintmsk = dwc2_readl(hsotg, GINTMSK); +- gintmsk &= ~GINTSTS_CONIDSTSCHNG; +- dwc2_writel(hsotg, gintmsk, GINTMSK); +- gintsts = dwc2_readl(hsotg, GINTSTS); +- dwc2_writel(hsotg, gintsts | GINTSTS_CONIDSTSCHNG, GINTSTS); +- } +-} +- +-void dwc2_drd_resume(struct dwc2_hsotg *hsotg) +-{ +- u32 gintsts, gintmsk; +- +- if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) { +- gintsts = dwc2_readl(hsotg, GINTSTS); +- dwc2_writel(hsotg, gintsts | GINTSTS_CONIDSTSCHNG, GINTSTS); +- gintmsk = dwc2_readl(hsotg, GINTMSK); +- gintmsk |= GINTSTS_CONIDSTSCHNG; +- dwc2_writel(hsotg, gintmsk, GINTMSK); +- } +-} +- + void dwc2_drd_exit(struct dwc2_hsotg *hsotg) + { +- if (hsotg->role_sw) ++ if (hsotg->role_sw) { + usb_role_switch_unregister(hsotg->role_sw); ++ fwnode_handle_put(software_node_fwnode(&ingenic_usb_node)); ++ } + } +diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c +index 64485f82d..650a674cd 100644 +--- a/drivers/usb/dwc2/gadget.c ++++ b/drivers/usb/dwc2/gadget.c +@@ -1030,12 +1030,6 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) + dwc2_writel(hsotg, ctrl, depctl); + } + +-static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep); +-static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, +- struct dwc2_hsotg_ep *hs_ep, +- struct dwc2_hsotg_req *hs_req, +- int result); +- + /** + * dwc2_hsotg_start_req - start a USB request from an endpoint's queue + * @hsotg: The controller state. +@@ -1188,21 +1182,14 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, + } + } + +- if (hs_ep->isochronous) { +- if (!dwc2_gadget_target_frame_elapsed(hs_ep)) { +- if (hs_ep->interval == 1) { +- if (hs_ep->target_frame & 0x1) +- ctrl |= DXEPCTL_SETODDFR; +- else +- ctrl |= DXEPCTL_SETEVENFR; +- } +- ctrl |= DXEPCTL_CNAK; +- } else { +- hs_req->req.frame_number = hs_ep->target_frame; +- hs_req->req.actual = 0; +- dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA); +- return; +- } ++ if (hs_ep->isochronous && hs_ep->interval == 1) { ++ hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg); ++ dwc2_gadget_incr_frame_num(hs_ep); ++ ++ if (hs_ep->target_frame & 0x1) ++ ctrl |= DXEPCTL_SETODDFR; ++ else ++ ctrl |= DXEPCTL_SETEVENFR; + } + + ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ +@@ -1525,8 +1512,8 @@ static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, + { + struct dwc2_hsotg_ep *hs_ep = our_ep(ep); + struct dwc2_hsotg *hs = hs_ep->parent; +- unsigned long flags = 0; +- int ret = 0; ++ unsigned long flags; ++ int ret; + + spin_lock_irqsave(&hs->lock, flags); + ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags); +@@ -1742,9 +1729,11 @@ static struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep) + */ + static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) + { ++ u32 mask; + struct dwc2_hsotg *hsotg = hs_ep->parent; + int dir_in = hs_ep->dir_in; + struct dwc2_hsotg_req *hs_req; ++ u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; + + if (!list_empty(&hs_ep->queue)) { + hs_req = get_ep_head(hs_ep); +@@ -1760,6 +1749,9 @@ static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) + } else { + dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n", + __func__); ++ mask = dwc2_readl(hsotg, epmsk_reg); ++ mask |= DOEPMSK_OUTTKNEPDISMSK; ++ dwc2_writel(hsotg, mask, epmsk_reg); + } + } + +@@ -1791,6 +1783,8 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, + switch (recip) { + case USB_RECIP_DEVICE: + switch (wValue) { ++ case USB_DEVICE_B_HNP_ENABLE: ++ break; + case USB_DEVICE_REMOTE_WAKEUP: + if (set) + hsotg->remote_wakeup_allowed = 1; +@@ -1830,7 +1824,8 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, + case USB_ENDPOINT_HALT: + halted = ep->halted; + +- dwc2_hsotg_ep_sethalt(&ep->ep, set, true); ++ if (!ep->wedged) ++ dwc2_hsotg_ep_sethalt(&ep->ep, set, true); + + ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); + if (ret) { +@@ -1961,6 +1956,10 @@ static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, + dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); + + ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); ++ if (ctrl->wValue) ++ call_gadget_set_state(hsotg, USB_STATE_ADDRESS); ++ else ++ call_gadget_set_state(hsotg, USB_STATE_DEFAULT); + return; + + case USB_REQ_GET_STATUS: +@@ -2329,6 +2328,19 @@ static void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) + dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]); + } + ++static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg, ++ u32 epctl_reg) ++{ ++ u32 ctrl; ++ ++ ctrl = dwc2_readl(hsotg, epctl_reg); ++ if (ctrl & DXEPCTL_EOFRNUM) ++ ctrl |= DXEPCTL_SETEVENFR; ++ else ++ ctrl |= DXEPCTL_SETODDFR; ++ dwc2_writel(hsotg, ctrl, epctl_reg); ++} ++ + /* + * dwc2_gadget_get_xfersize_ddma - get transferred bytes amount from desc + * @hs_ep - The endpoint on which transfer went +@@ -2449,12 +2461,21 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) + dwc2_hsotg_ep0_zlp(hsotg, true); + } + +- /* Set actual frame number for completed transfers */ +- if (!using_desc_dma(hsotg) && hs_ep->isochronous) { +- req->frame_number = hs_ep->target_frame; +- dwc2_gadget_incr_frame_num(hs_ep); ++ /* ++ * Slave mode OUT transfers do not go through XferComplete so ++ * adjust the ISOC parity here. ++ */ ++ if (!using_dma(hsotg)) { ++ if (hs_ep->isochronous && hs_ep->interval == 1) ++ dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum)); ++ else if (hs_ep->isochronous && hs_ep->interval > 1) ++ dwc2_gadget_incr_frame_num(hs_ep); + } + ++ /* Set actual frame number for completed transfers */ ++ if (!using_desc_dma(hsotg) && hs_ep->isochronous) ++ req->frame_number = hsotg->frame_number; ++ + dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result); + } + +@@ -2767,12 +2788,6 @@ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, + return; + } + +- /* Set actual frame number for completed transfers */ +- if (!using_desc_dma(hsotg) && hs_ep->isochronous) { +- hs_req->req.frame_number = hs_ep->target_frame; +- dwc2_gadget_incr_frame_num(hs_ep); +- } +- + dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); + } + +@@ -2833,18 +2848,23 @@ static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) + + dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); + ++ if (hs_ep->isochronous) { ++ dwc2_hsotg_complete_in(hsotg, hs_ep); ++ return; ++ } ++ + if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) { + int dctl = dwc2_readl(hsotg, DCTL); + + dctl |= DCTL_CGNPINNAK; + dwc2_writel(hsotg, dctl, DCTL); + } +- } else { ++ return; ++ } + +- if (dctl & DCTL_GOUTNAKSTS) { +- dctl |= DCTL_CGOUTNAK; +- dwc2_writel(hsotg, dctl, DCTL); +- } ++ if (dctl & DCTL_GOUTNAKSTS) { ++ dctl |= DCTL_CGOUTNAK; ++ dwc2_writel(hsotg, dctl, DCTL); + } + + if (!hs_ep->isochronous) +@@ -2861,13 +2881,14 @@ static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) + if (hs_req) { + hs_req->req.frame_number = hs_ep->target_frame; + hs_req->req.actual = 0; +- dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, +- -ENODATA); ++ dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA); + } + dwc2_gadget_incr_frame_num(hs_ep); + /* Update current frame number value. */ + hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); + } while (dwc2_gadget_target_frame_elapsed(hs_ep)); ++ ++ dwc2_gadget_start_next_request(hs_ep); + } + + /** +@@ -2884,8 +2905,8 @@ static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) + static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) + { + struct dwc2_hsotg *hsotg = ep->parent; +- struct dwc2_hsotg_req *hs_req; + int dir_in = ep->dir_in; ++ u32 doepmsk; + + if (dir_in || !ep->isochronous) + return; +@@ -2899,42 +2920,28 @@ static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) + return; + } + +- if (ep->target_frame == TARGET_FRAME_INITIAL) { ++ if (ep->interval > 1 && ++ ep->target_frame == TARGET_FRAME_INITIAL) { + u32 ctrl; + + ep->target_frame = hsotg->frame_number; +- if (ep->interval > 1) { +- ctrl = dwc2_readl(hsotg, DOEPCTL(ep->index)); +- if (ep->target_frame & 0x1) +- ctrl |= DXEPCTL_SETODDFR; +- else +- ctrl |= DXEPCTL_SETEVENFR; +- +- dwc2_writel(hsotg, ctrl, DOEPCTL(ep->index)); +- } +- } ++ dwc2_gadget_incr_frame_num(ep); + +- while (dwc2_gadget_target_frame_elapsed(ep)) { +- hs_req = get_ep_head(ep); +- if (hs_req) { +- hs_req->req.frame_number = ep->target_frame; +- hs_req->req.actual = 0; +- dwc2_hsotg_complete_request(hsotg, ep, hs_req, -ENODATA); +- } ++ ctrl = dwc2_readl(hsotg, DOEPCTL(ep->index)); ++ if (ep->target_frame & 0x1) ++ ctrl |= DXEPCTL_SETODDFR; ++ else ++ ctrl |= DXEPCTL_SETEVENFR; + +- dwc2_gadget_incr_frame_num(ep); +- /* Update current frame number value. */ +- hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); ++ dwc2_writel(hsotg, ctrl, DOEPCTL(ep->index)); + } + +- if (!ep->req) +- dwc2_gadget_start_next_request(ep); +- ++ dwc2_gadget_start_next_request(ep); ++ doepmsk = dwc2_readl(hsotg, DOEPMSK); ++ doepmsk &= ~DOEPMSK_OUTTKNEPDISMSK; ++ dwc2_writel(hsotg, doepmsk, DOEPMSK); + } + +-static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, +- struct dwc2_hsotg_ep *hs_ep); +- + /** + * dwc2_gadget_handle_nak - handle NAK interrupt + * @hs_ep: The endpoint on which interrupt is asserted. +@@ -2952,9 +2959,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, + static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) + { + struct dwc2_hsotg *hsotg = hs_ep->parent; +- struct dwc2_hsotg_req *hs_req; + int dir_in = hs_ep->dir_in; +- u32 ctrl; + + if (!dir_in || !hs_ep->isochronous) + return; +@@ -2996,32 +3001,13 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) + + dwc2_writel(hsotg, ctrl, DIEPCTL(hs_ep->index)); + } +- } + +- if (using_desc_dma(hsotg)) +- return; +- +- ctrl = dwc2_readl(hsotg, DIEPCTL(hs_ep->index)); +- if (ctrl & DXEPCTL_EPENA) +- dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep); +- else +- dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); +- +- while (dwc2_gadget_target_frame_elapsed(hs_ep)) { +- hs_req = get_ep_head(hs_ep); +- if (hs_req) { +- hs_req->req.frame_number = hs_ep->target_frame; +- hs_req->req.actual = 0; +- dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA); +- } +- +- dwc2_gadget_incr_frame_num(hs_ep); +- /* Update current frame number value. */ +- hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); ++ dwc2_hsotg_complete_request(hsotg, hs_ep, ++ get_ep_head(hs_ep), 0); + } + +- if (!hs_ep->req) +- dwc2_gadget_start_next_request(hs_ep); ++ if (!using_desc_dma(hsotg)) ++ dwc2_gadget_incr_frame_num(hs_ep); + } + + /** +@@ -3084,8 +3070,12 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, + * need to look at completing IN requests here + * if operating slave mode + */ +- if (!hs_ep->isochronous || !(ints & DXEPINT_NAKINTRPT)) +- dwc2_hsotg_complete_in(hsotg, hs_ep); ++ if (hs_ep->isochronous && hs_ep->interval > 1) ++ dwc2_gadget_incr_frame_num(hs_ep); ++ ++ dwc2_hsotg_complete_in(hsotg, hs_ep); ++ if (ints & DXEPINT_NAKINTRPT) ++ ints &= ~DXEPINT_NAKINTRPT; + + if (idx == 0 && !hs_ep->req) + dwc2_hsotg_enqueue_setup(hsotg); +@@ -3094,8 +3084,10 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, + * We're using DMA, we need to fire an OutDone here + * as we ignore the RXFIFO. + */ +- if (!hs_ep->isochronous || !(ints & DXEPINT_OUTTKNEPDIS)) +- dwc2_hsotg_handle_outdone(hsotg, idx); ++ if (hs_ep->isochronous && hs_ep->interval > 1) ++ dwc2_gadget_incr_frame_num(hs_ep); ++ ++ dwc2_hsotg_handle_outdone(hsotg, idx); + } + } + +@@ -3312,6 +3304,7 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) + { + unsigned int ep; + ++ + if (!hsotg->connected) + return; + +@@ -3329,9 +3322,8 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) + } + + call_gadget(hsotg, disconnect); ++ call_gadget_set_state(hsotg, USB_STATE_NOTATTACHED); + hsotg->lx_state = DWC2_L3; +- +- usb_gadget_set_state(&hsotg->gadget, USB_STATE_NOTATTACHED); + } + + /** +@@ -3371,7 +3363,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) + + static int dwc2_hsotg_ep_disable(struct usb_ep *ep); + /** +- * dwc2_hsotg_core_init - issue softreset to the core ++ * dwc2_hsotg_core_init_disconnected - issue softreset to the core + * @hsotg: The device state + * @is_usb_reset: Usb resetting flag + * +@@ -3456,8 +3448,14 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, + GINTSTS_USBSUSP | GINTSTS_WKUPINT | + GINTSTS_LPMTRANRCVD; + +- if (!using_desc_dma(hsotg)) +- intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; ++ /* ++ * Ignoring the abnormal transmission of the synchronization endpoint, ++ * the controller classifies the missing frame as abnormal transmission. ++ * Some embedded hosts are unstable in the synchronization cycle, ++ * missing frame causes the abnormal transmission of data to be discarded. ++ */ ++ // if (!using_desc_dma(hsotg)) ++ // intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; + + if (!hsotg->params.external_id_pin_ctl) + intmsk |= GINTSTS_CONIDSTSCHNG; +@@ -3723,14 +3721,13 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) + dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS); + + /* This event must be used only if controller is suspended */ +- if (hsotg->lx_state == DWC2_L2) { +- dwc2_exit_partial_power_down(hsotg, true); +- hsotg->lx_state = DWC2_L0; +- } ++ if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2) ++ dwc2_exit_partial_power_down(hsotg, 0, true); ++ ++ hsotg->lx_state = DWC2_L0; + } + + if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { +- u32 usb_status = dwc2_readl(hsotg, GOTGCTL); + u32 connected = hsotg->connected; + + dev_dbg(hsotg->dev, "%s: USBRst\n", __func__); +@@ -3745,8 +3742,10 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) + /* Reset device address to zero */ + dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK); + +- if (usb_status & GOTGCTL_BSESVLD && connected) ++ if (connected) + dwc2_hsotg_core_init_disconnected(hsotg, true); ++ ++ call_gadget_set_state(hsotg, USB_STATE_DEFAULT); + } + + if (gintsts & GINTSTS_ENUMDONE) { +@@ -4097,6 +4096,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, + hs_ep->isochronous = 0; + hs_ep->periodic = 0; + hs_ep->halted = 0; ++ hs_ep->wedged = 0; + hs_ep->interval = desc->bInterval; + + switch (ep_type) { +@@ -4114,7 +4114,6 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, + mask |= DIEPMSK_NAKMSK; + dwc2_writel(hsotg, mask, DIEPMSK); + } else { +- epctrl |= DXEPCTL_SNAK; + mask = dwc2_readl(hsotg, DOEPMSK); + mask |= DOEPMSK_OUTTKNEPDISMSK; + dwc2_writel(hsotg, mask, DOEPMSK); +@@ -4338,6 +4337,27 @@ static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) + return 0; + } + ++/** ++ * dwc2_gadget_ep_set_wedge - set wedge on a given endpoint ++ * @ep: The endpoint to be wedged. ++ * ++ */ ++static int dwc2_gadget_ep_set_wedge(struct usb_ep *ep) ++{ ++ struct dwc2_hsotg_ep *hs_ep = our_ep(ep); ++ struct dwc2_hsotg *hs = hs_ep->parent; ++ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&hs->lock, flags); ++ hs_ep->wedged = 1; ++ ret = dwc2_hsotg_ep_sethalt(ep, 1, false); ++ spin_unlock_irqrestore(&hs->lock, flags); ++ ++ return ret; ++} ++ + /** + * dwc2_hsotg_ep_sethalt - set halt on a given endpoint + * @ep: The endpoint to set halt. +@@ -4389,6 +4409,7 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) + epctl |= DXEPCTL_EPDIS; + } else { + epctl &= ~DXEPCTL_STALL; ++ hs_ep->wedged = 0; + xfertype = epctl & DXEPCTL_EPTYPE_MASK; + if (xfertype == DXEPCTL_EPTYPE_BULK || + xfertype == DXEPCTL_EPTYPE_INTERRUPT) +@@ -4408,6 +4429,7 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) + // STALL bit will be set in GOUTNAKEFF interrupt handler + } else { + epctl &= ~DXEPCTL_STALL; ++ hs_ep->wedged = 0; + xfertype = epctl & DXEPCTL_EPTYPE_MASK; + if (xfertype == DXEPCTL_EPTYPE_BULK || + xfertype == DXEPCTL_EPTYPE_INTERRUPT) +@@ -4429,8 +4451,8 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) + { + struct dwc2_hsotg_ep *hs_ep = our_ep(ep); + struct dwc2_hsotg *hs = hs_ep->parent; +- unsigned long flags = 0; +- int ret = 0; ++ unsigned long flags; ++ int ret; + + spin_lock_irqsave(&hs->lock, flags); + ret = dwc2_hsotg_ep_sethalt(ep, value, false); +@@ -4447,6 +4469,7 @@ static const struct usb_ep_ops dwc2_hsotg_ep_ops = { + .queue = dwc2_hsotg_ep_queue_lock, + .dequeue = dwc2_hsotg_ep_dequeue, + .set_halt = dwc2_hsotg_ep_sethalt_lock, ++ .set_wedge = dwc2_gadget_ep_set_wedge, + /* note, don't believe we have any call for the fifo routines */ + }; + +@@ -4559,7 +4582,7 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, + static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) + { + struct dwc2_hsotg *hsotg = to_hsotg(gadget); +- unsigned long flags = 0; ++ unsigned long flags; + int ep; + + if (!hsotg) +@@ -4631,7 +4654,7 @@ static int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget, + static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) + { + struct dwc2_hsotg *hsotg = to_hsotg(gadget); +- unsigned long flags = 0; ++ unsigned long flags; + + dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, + hsotg->op_state); +@@ -4667,20 +4690,28 @@ static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) + unsigned long flags; + + dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active); ++ ++ /* called in host mode? */ ++ if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) ++ return -EINVAL; ++ + spin_lock_irqsave(&hsotg->lock, flags); + + /* +- * If controller is hibernated, it must exit from power_down +- * before being initialized / de-initialized ++ * If controller is in partial power down state, it must exit from ++ * that state before being initialized / de-initialized + */ +- if (hsotg->lx_state == DWC2_L2) +- dwc2_exit_partial_power_down(hsotg, false); ++ if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) ++ /* ++ * No need to check the return value as ++ * registers are not being restored. ++ */ ++ dwc2_exit_partial_power_down(hsotg, 0, false); + + if (is_active) { +- hsotg->op_state = OTG_STATE_B_PERIPHERAL; +- ++ call_gadget_set_state(hsotg, USB_STATE_POWERED); + dwc2_hsotg_core_init_disconnected(hsotg, false); +- if (hsotg->enabled) { ++ if (get_gadget_enabled(hsotg)) { + /* Enable ACG feature in device mode,if supported */ + dwc2_enable_acg(hsotg); + dwc2_hsotg_core_connect(hsotg); +@@ -4710,14 +4741,90 @@ static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA) + return usb_phy_set_power(hsotg->uphy, mA); + } + ++static void dwc2_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed) ++{ ++ struct dwc2_hsotg *hsotg = to_hsotg(g); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&hsotg->lock, flags); ++ switch (speed) { ++ case USB_SPEED_HIGH: ++ hsotg->params.speed = DWC2_SPEED_PARAM_HIGH; ++ break; ++ case USB_SPEED_FULL: ++ hsotg->params.speed = DWC2_SPEED_PARAM_FULL; ++ break; ++ case USB_SPEED_LOW: ++ hsotg->params.speed = DWC2_SPEED_PARAM_LOW; ++ break; ++ default: ++ dev_err(hsotg->dev, "invalid speed (%d)\n", speed); ++ } ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++} ++ ++static int dwc2_hsotg_wakeup(struct usb_gadget *gadget) ++{ ++ int ret; ++ u32 dsts, dctl; ++ unsigned long flags; ++ struct dwc2_hsotg *hsotg = to_hsotg(gadget); ++ ++ if (!dwc2_is_device_mode(hsotg)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&hsotg->lock, flags); ++ ++ if (hsotg->connected) { ++ if (hsotg->remote_wakeup_allowed) { ++ dsts = dwc2_readl(hsotg, DSTS); ++ if (dsts & DSTS_SUSPSTS) { ++ dctl = dwc2_readl(hsotg, DCTL); ++ dctl |= DCTL_RMTWKUPSIG; ++ dwc2_writel(hsotg, dctl, DCTL); ++ mdelay(10); ++ dctl &= ~DCTL_RMTWKUPSIG; ++ dwc2_writel(hsotg, dctl, DCTL); ++ ++ if (hsotg->lx_state == DWC2_L2) { ++ if (hsotg->in_ppd) { ++ ret = dwc2_exit_partial_power_down(hsotg, 1, true); ++ if (ret) ++ dev_err(hsotg->dev, ++ "exit partial_power_down failed\n"); ++ call_gadget(hsotg, resume); ++ call_gadget_set_state(hsotg, hsotg->resume_state); ++ } ++ ++ /* Exit gadget mode clock gating. */ ++ if (hsotg->params.power_down == ++ DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) ++ dwc2_gadget_exit_clock_gating(hsotg, 0); ++ } else { ++ /* Change to L0 state */ ++ hsotg->lx_state = DWC2_L0; ++ } ++ } ++ } else { ++ dev_info(hsotg->dev, "Remote Wakeup is disabled\n"); ++ } ++ } ++ ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ ++ return 0; ++} ++ + static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { + .get_frame = dwc2_hsotg_gadget_getframe, + .set_selfpowered = dwc2_hsotg_set_selfpowered, + .udc_start = dwc2_hsotg_udc_start, + .udc_stop = dwc2_hsotg_udc_stop, + .pullup = dwc2_hsotg_pullup, ++ .udc_set_speed = dwc2_gadget_set_speed, + .vbus_session = dwc2_hsotg_vbus_session, + .vbus_draw = dwc2_hsotg_vbus_draw, ++ .wakeup = dwc2_hsotg_wakeup, + }; + + /** +@@ -4923,6 +5030,7 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg) + hsotg->gadget.max_speed = USB_SPEED_HIGH; + hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; + hsotg->gadget.name = dev_name(dev); ++ hsotg->gadget.otg_caps = &hsotg->params.otg_caps; + hsotg->remote_wakeup_allowed = 0; + + if (hsotg->params.lpm) +@@ -5025,7 +5133,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) + hsotg->driver->driver.name); + + spin_lock_irqsave(&hsotg->lock, flags); +- if (hsotg->enabled) ++ if (get_gadget_enabled(hsotg)) + dwc2_hsotg_core_disconnect(hsotg); + dwc2_hsotg_disconnect(hsotg); + hsotg->gadget.speed = USB_SPEED_UNKNOWN; +@@ -5055,7 +5163,7 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg) + + spin_lock_irqsave(&hsotg->lock, flags); + dwc2_hsotg_core_init_disconnected(hsotg, false); +- if (hsotg->enabled) { ++ if (get_gadget_enabled(hsotg)) { + /* Enable ACG feature in device mode,if supported */ + dwc2_enable_acg(hsotg); + dwc2_hsotg_core_connect(hsotg); +@@ -5314,7 +5422,6 @@ int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) + int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, + int rem_wakeup, int reset) + { +- u32 pcgcctl; + u32 gpwrdn; + u32 dctl; + int ret = 0; +@@ -5345,17 +5452,15 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, + dwc2_writel(hsotg, gpwrdn, GPWRDN); + udelay(10); + +- if (!rem_wakeup) { +- pcgcctl = dwc2_readl(hsotg, PCGCTL); +- pcgcctl &= ~PCGCTL_RSTPDWNMODULE; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- } +- + /* Restore GUSBCFG, DCFG and DCTL */ + dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); + dwc2_writel(hsotg, dr->dcfg, DCFG); + dwc2_writel(hsotg, dr->dctl, DCTL); + ++ /* On USB Reset, reset device address to zero */ ++ if (reset) ++ dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK); ++ + /* De-assert Wakeup Logic */ + gpwrdn = dwc2_readl(hsotg, GPWRDN); + gpwrdn &= ~GPWRDN_PMUACTV; +@@ -5406,3 +5511,149 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, + + return ret; + } ++ ++ ++/** ++ * dwc2_gadget_enter_partial_power_down() - Put controller in partial ++ * power down. ++ * ++ * @hsotg: Programming view of the DWC_otg controller ++ * ++ * Return: non-zero if failed to enter device partial power down. ++ * ++ * This function is for entering device mode partial power down. ++ */ ++int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg) ++{ ++ int ret = 0; ++ ++ dev_dbg(hsotg->dev, "Entering device partial power down started.\n"); ++ ++ /* Backup all registers */ ++ ret = dwc2_backup_global_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to backup global registers\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = dwc2_backup_device_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to backup device registers\n", ++ __func__); ++ return ret; ++ } ++ ++ /* ++ * Clear any pending interrupts since dwc2 will not be able to ++ * clear them after entering partial_power_down. ++ */ ++ dwc2_writel(hsotg, 0xffffffff, GINTSTS); ++ ++ /* Set in_ppd flag to 1 as here core enters suspend. */ ++ hsotg->in_ppd = 1; ++ hsotg->lx_state = DWC2_L2; ++ ++ dev_dbg(hsotg->dev, "Entering device partial power down completed.\n"); ++ ++ return ret; ++} ++ ++/* ++ * dwc2_gadget_exit_partial_power_down() - Exit controller from device partial ++ * power down. ++ * ++ * @hsotg: Programming view of the DWC_otg controller ++ * @restore: indicates whether need to restore the registers or not. ++ * ++ * Return: non-zero if failed to exit device partial power down. ++ * ++ * This function is for exiting from device mode partial power down. ++ */ ++int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg, ++ bool restore) ++{ ++ u32 dctl; ++ struct dwc2_dregs_backup *dr; ++ int ret = 0; ++ ++ dr = &hsotg->dr_backup; ++ ++ dev_dbg(hsotg->dev, "Exiting device partial Power Down started.\n"); ++ ++ udelay(100); ++ if (restore) { ++ ret = dwc2_restore_global_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to restore registers\n", ++ __func__); ++ return ret; ++ } ++ /* Restore DCFG */ ++ dwc2_writel(hsotg, dr->dcfg, DCFG); ++ ++ ret = dwc2_restore_device_registers(hsotg, 0); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to restore device registers\n", ++ __func__); ++ return ret; ++ } ++ } ++ ++ /* Set the Power-On Programming done bit */ ++ dctl = dwc2_readl(hsotg, DCTL); ++ dctl |= DCTL_PWRONPRGDONE; ++ dwc2_writel(hsotg, dctl, DCTL); ++ ++ /* Set in_ppd flag to 0 as here core exits from suspend. */ ++ hsotg->in_ppd = 0; ++ hsotg->lx_state = DWC2_L0; ++ ++ dev_dbg(hsotg->dev, "Exiting device partial Power Down completed.\n"); ++ return ret; ++} ++ ++/** ++ * dwc2_gadget_enter_clock_gating() - Put controller in clock gating. ++ * ++ * @hsotg: Programming view of the DWC_otg controller ++ * ++ * Return: non-zero if failed to enter device partial power down. ++ * ++ * This function is for entering device mode clock gating. ++ */ ++void dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg) ++{ ++ dev_dbg(hsotg->dev, "Entering device clock gating.\n"); ++ ++ hsotg->lx_state = DWC2_L2; ++ hsotg->bus_suspended = true; ++} ++ ++/* ++ * dwc2_gadget_exit_clock_gating() - Exit controller from device clock gating. ++ * ++ * @hsotg: Programming view of the DWC_otg controller ++ * @rem_wakeup: indicates whether remote wake up is enabled. ++ * ++ * This function is for exiting from device mode clock gating. ++ */ ++void dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup) ++{ ++ u32 dctl; ++ ++ dev_dbg(hsotg->dev, "Exiting device clock gating.\n"); ++ ++ if (rem_wakeup) { ++ /* Set Remote Wakeup Signaling */ ++ dctl = dwc2_readl(hsotg, DCTL); ++ dctl |= DCTL_RMTWKUPSIG; ++ dwc2_writel(hsotg, dctl, DCTL); ++ } ++ ++ /* Change to L0 state */ ++ call_gadget(hsotg, resume); ++ hsotg->lx_state = DWC2_L0; ++ hsotg->bus_suspended = false; ++ call_gadget_set_state(hsotg, hsotg->resume_state); ++} +diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c +index 9279d3d36..e228bfbe0 100644 +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -56,8 +56,6 @@ + #include "core.h" + #include "hcd.h" + +-static void dwc2_port_resume(struct dwc2_hsotg *hsotg); +- + /* + * ========================================================================= + * Host Core Layer Functions +@@ -140,19 +138,17 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg) + + switch (hsotg->hw_params.op_mode) { + case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: +- if (hsotg->params.otg_cap == +- DWC2_CAP_PARAM_HNP_SRP_CAPABLE) ++ if (hsotg->params.otg_caps.hnp_support && ++ hsotg->params.otg_caps.srp_support) + usbcfg |= GUSBCFG_HNPCAP; +- if (hsotg->params.otg_cap != +- DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE) ++ if (hsotg->params.otg_caps.srp_support) + usbcfg |= GUSBCFG_SRPCAP; + break; + + case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: +- if (hsotg->params.otg_cap != +- DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE) ++ if (hsotg->params.otg_caps.srp_support) + usbcfg |= GUSBCFG_SRPCAP; + break; + +@@ -168,16 +164,28 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg) + + static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg) + { +- if (hsotg->vbus_supply) +- return regulator_enable(hsotg->vbus_supply); ++ if (!hsotg->vbus_supply_enabled) { ++ hsotg->vbus_supply_enabled = 1; ++ ++ usb_phy_vbus_on(hsotg->uphy); ++ ++ if (hsotg->vbus_supply) ++ regulator_enable(hsotg->vbus_supply); ++ } + + return 0; + } + + static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg) + { +- if (hsotg->vbus_supply) +- return regulator_disable(hsotg->vbus_supply); ++ if (hsotg->vbus_supply_enabled) { ++ hsotg->vbus_supply_enabled = 0; ++ ++ if (hsotg->vbus_supply) ++ regulator_disable(hsotg->vbus_supply); ++ ++ usb_phy_vbus_off(hsotg->uphy); ++ } + + return 0; + } +@@ -1748,6 +1756,8 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) + } + } + ++extern void usb_kick_hub_wq(struct usb_device *hdev); ++ + /** + * dwc2_hcd_connect() - Handles connect of the HCD + * +@@ -1776,6 +1786,8 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force) + { + u32 intr; + u32 hprt0; ++ struct usb_hcd *hcd = (struct usb_hcd *)hsotg->priv; ++ struct usb_device *rhdev = hcd->self.root_hub; + + /* Set status flags for the hub driver */ + hsotg->flags.b.port_connect_status_change = 1; +@@ -1815,6 +1827,10 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force) + + dwc2_host_disconnect(hsotg); + ++ /* Handling hub disconnect events */ ++ if (rhdev->state == USB_STATE_SUSPENDED) { ++ usb_kick_hub_wq(rhdev); ++ } + /* + * Add an extra check here to see if we're actually connected but + * we don't have a detection interrupt pending. This can happen if: +@@ -2179,9 +2195,6 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) + usbcfg |= GUSBCFG_TOUTCAL(7); + dwc2_writel(hsotg, usbcfg, GUSBCFG); + +- /* Restart the Phy Clock */ +- dwc2_writel(hsotg, 0, PCGCTL); +- + /* Initialize Host Configuration Register */ + dwc2_init_fs_ls_pclk_sel(hsotg); + if (hsotg->params.speed == DWC2_SPEED_PARAM_FULL || +@@ -3208,15 +3221,26 @@ static void dwc2_conn_id_status_change(struct work_struct *work) + if (count > 250) + dev_err(hsotg->dev, + "Connection id status change timed out\n"); ++ ++ /* ++ * Exit Partial Power Down without restoring registers. ++ * No need to check the return value as registers ++ * are not being restored. ++ */ ++ if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2) ++ dwc2_exit_partial_power_down(hsotg, 0, false); ++ + hsotg->op_state = OTG_STATE_B_PERIPHERAL; + dwc2_core_init(hsotg, false); + dwc2_enable_global_interrupts(hsotg); + spin_lock_irqsave(&hsotg->lock, flags); + dwc2_hsotg_core_init_disconnected(hsotg, false); ++ if (get_gadget_enabled(hsotg)) { ++ /* Enable ACG feature in device mode,if supported */ ++ dwc2_enable_acg(hsotg); ++ dwc2_hsotg_core_connect(hsotg); ++ } + spin_unlock_irqrestore(&hsotg->lock, flags); +- /* Enable ACG feature in device mode,if supported */ +- dwc2_enable_acg(hsotg); +- dwc2_hsotg_core_connect(hsotg); + } else { + host: + /* A-Device connector (Host Mode) */ +@@ -3277,13 +3301,22 @@ static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg *hsotg) + return hcd->self.b_hnp_enable; + } + +-/* Must NOT be called with interrupt disabled or spinlock held */ +-static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) ++/** ++ * dwc2_port_suspend() - Put controller in suspend mode for host. ++ * ++ * @hsotg: Programming view of the DWC_otg controller ++ * @windex: The control request wIndex field ++ * ++ * Return: non-zero if failed to enter suspend mode for host. ++ * ++ * This function is for entering Host mode suspend. ++ * Must NOT be called with interrupt disabled or spinlock held. ++ */ ++int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) + { + unsigned long flags; +- u32 hprt0; +- u32 pcgctl; + u32 gotgctl; ++ int ret = 0; + + dev_dbg(hsotg->dev, "%s()\n", __func__); + +@@ -3296,74 +3329,88 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) + hsotg->op_state = OTG_STATE_A_SUSPEND; + } + +- hprt0 = dwc2_read_hprt0(hsotg); +- hprt0 |= HPRT0_SUSP; +- dwc2_writel(hsotg, hprt0, HPRT0); +- +- hsotg->bus_suspended = true; +- +- /* +- * If power_down is supported, Phy clock will be suspended +- * after registers are backuped. +- */ +- if (!hsotg->params.power_down) { +- /* Suspend the Phy Clock */ +- pcgctl = dwc2_readl(hsotg, PCGCTL); +- pcgctl |= PCGCTL_STOPPCLK; +- dwc2_writel(hsotg, pcgctl, PCGCTL); +- udelay(10); ++ switch (hsotg->params.power_down) { ++ case DWC2_POWER_DOWN_PARAM_PARTIAL: ++ ret = dwc2_enter_partial_power_down(hsotg); ++ if (ret) ++ dev_err(hsotg->dev, ++ "enter partial_power_down failed.\n"); ++ break; ++ case DWC2_POWER_DOWN_PARAM_HIBERNATION: ++ /* ++ * Perform spin unlock and lock because in ++ * "dwc2_host_enter_hibernation()" function there is a spinlock ++ * logic which prevents servicing of any IRQ during entering ++ * hibernation. ++ */ ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ ret = dwc2_enter_hibernation(hsotg, 1); ++ if (ret) ++ dev_err(hsotg->dev, "enter hibernation failed.\n"); ++ spin_lock_irqsave(&hsotg->lock, flags); ++ break; ++ case DWC2_POWER_DOWN_PARAM_NONE: ++ /* ++ * If not hibernation nor partial power down are supported, ++ * clock gating is used to save power. ++ */ ++ dwc2_host_enter_clock_gating(hsotg); ++ break; + } + +- /* For HNP the bus must be suspended for at least 200ms */ +- if (dwc2_host_is_b_hnp_enabled(hsotg)) { +- pcgctl = dwc2_readl(hsotg, PCGCTL); +- pcgctl &= ~PCGCTL_STOPPCLK; +- dwc2_writel(hsotg, pcgctl, PCGCTL); +- +- spin_unlock_irqrestore(&hsotg->lock, flags); ++ spin_unlock_irqrestore(&hsotg->lock, flags); + ++ /* For HNP the bus must be suspended for at least 200ms */ ++ if (dwc2_host_is_b_hnp_enabled(hsotg)) + msleep(200); +- } else { +- spin_unlock_irqrestore(&hsotg->lock, flags); +- } ++ ++ return ret; + } + +-/* Must NOT be called with interrupt disabled or spinlock held */ +-static void dwc2_port_resume(struct dwc2_hsotg *hsotg) ++/** ++ * dwc2_port_resume() - Exit controller from suspend mode for host. ++ * ++ * @hsotg: Programming view of the DWC_otg controller ++ * ++ * Return: non-zero if failed to exit suspend mode for host. ++ * ++ * This function is for exiting Host mode suspend. ++ * Must NOT be called with interrupt disabled or spinlock held. ++ */ ++int dwc2_port_resume(struct dwc2_hsotg *hsotg) + { + unsigned long flags; +- u32 hprt0; +- u32 pcgctl; ++ int ret = 0; + + spin_lock_irqsave(&hsotg->lock, flags); + +- /* +- * If power_down is supported, Phy clock is already resumed +- * after registers restore. +- */ +- if (!hsotg->params.power_down) { +- pcgctl = dwc2_readl(hsotg, PCGCTL); +- pcgctl &= ~PCGCTL_STOPPCLK; +- dwc2_writel(hsotg, pcgctl, PCGCTL); ++ switch (hsotg->params.power_down) { ++ case DWC2_POWER_DOWN_PARAM_PARTIAL: ++ ret = dwc2_exit_partial_power_down(hsotg, 0, true); ++ if (ret) ++ dev_err(hsotg->dev, ++ "exit partial_power_down failed.\n"); ++ break; ++ case DWC2_POWER_DOWN_PARAM_HIBERNATION: ++ /* Exit host hibernation. */ ++ ret = dwc2_exit_hibernation(hsotg, 0, 0, 1); ++ if (ret) ++ dev_err(hsotg->dev, "exit hibernation failed.\n"); ++ break; ++ case DWC2_POWER_DOWN_PARAM_NONE: ++ /* ++ * If not hibernation nor partial power down are supported, ++ * port resume is done using the clock gating programming flow. ++ */ + spin_unlock_irqrestore(&hsotg->lock, flags); +- msleep(20); ++ dwc2_host_exit_clock_gating(hsotg, 0); + spin_lock_irqsave(&hsotg->lock, flags); ++ break; + } + +- hprt0 = dwc2_read_hprt0(hsotg); +- hprt0 |= HPRT0_RES; +- hprt0 &= ~HPRT0_SUSP; +- dwc2_writel(hsotg, hprt0, HPRT0); + spin_unlock_irqrestore(&hsotg->lock, flags); + +- msleep(USB_RESUME_TIMEOUT); +- +- spin_lock_irqsave(&hsotg->lock, flags); +- hprt0 = dwc2_read_hprt0(hsotg); +- hprt0 &= ~(HPRT0_RES | HPRT0_SUSP); +- dwc2_writel(hsotg, hprt0, HPRT0); +- hsotg->bus_suspended = false; +- spin_unlock_irqrestore(&hsotg->lock, flags); ++ return ret; + } + + /* Handles hub class-specific requests */ +@@ -3375,7 +3422,6 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + u32 hprt0; + u32 port_status; + u32 speed; +- u32 pcgctl; + u32 pwr; + + switch (typereq) { +@@ -3413,12 +3459,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + dev_dbg(hsotg->dev, + "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); + +- if (hsotg->bus_suspended) { +- if (hsotg->hibernated) +- dwc2_exit_hibernation(hsotg, 0, 0, 1); +- else +- dwc2_port_resume(hsotg); +- } ++ if (hsotg->bus_suspended) ++ retval = dwc2_port_resume(hsotg); + break; + + case USB_PORT_FEAT_POWER: +@@ -3629,10 +3671,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); + if (windex != hsotg->otg_port) + goto error; +- if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_HIBERNATION) +- dwc2_enter_hibernation(hsotg, 1); +- else +- dwc2_port_suspend(hsotg, windex); ++ if (!hsotg->bus_suspended) ++ retval = dwc2_port_suspend(hsotg, windex); + break; + + case USB_PORT_FEAT_POWER: +@@ -3647,17 +3687,29 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + break; + + case USB_PORT_FEAT_RESET: +- if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_HIBERNATION && +- hsotg->hibernated) +- dwc2_exit_hibernation(hsotg, 0, 1, 1); +- hprt0 = dwc2_read_hprt0(hsotg); + dev_dbg(hsotg->dev, + "SetPortFeature - USB_PORT_FEAT_RESET\n"); +- pcgctl = dwc2_readl(hsotg, PCGCTL); +- pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK); +- dwc2_writel(hsotg, pcgctl, PCGCTL); +- /* ??? Original driver does this */ +- dwc2_writel(hsotg, 0, PCGCTL); ++ ++ hprt0 = dwc2_read_hprt0(hsotg); ++ ++ if (hsotg->hibernated) { ++ retval = dwc2_exit_hibernation(hsotg, 0, 1, 1); ++ if (retval) ++ dev_err(hsotg->dev, ++ "exit hibernation failed\n"); ++ } ++ ++ if (hsotg->in_ppd) { ++ retval = dwc2_exit_partial_power_down(hsotg, 1, ++ true); ++ if (retval) ++ dev_err(hsotg->dev, ++ "exit partial_power_down failed\n"); ++ } ++ ++ if (hsotg->params.power_down == ++ DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended) ++ dwc2_host_exit_clock_gating(hsotg, 0); + + hprt0 = dwc2_read_hprt0(hsotg); + pwr = hprt0 & HPRT0_PWR; +@@ -4305,8 +4357,6 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + unsigned long flags; + int ret = 0; +- u32 hprt0; +- u32 pcgctl; + + spin_lock_irqsave(&hsotg->lock, flags); + +@@ -4322,47 +4372,43 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) + if (hsotg->op_state == OTG_STATE_B_PERIPHERAL) + goto unlock; + +- if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL || +- hsotg->flags.b.port_connect_status == 0) ++ if (hsotg->bus_suspended) + goto skip_power_saving; + +- /* +- * Drive USB suspend and disable port Power +- * if usb bus is not suspended. +- */ +- if (!hsotg->bus_suspended) { +- hprt0 = dwc2_read_hprt0(hsotg); +- if (hprt0 & HPRT0_CONNSTS) { +- hprt0 |= HPRT0_SUSP; +- if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) +- hprt0 &= ~HPRT0_PWR; +- dwc2_writel(hsotg, hprt0, HPRT0); +- } +- if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { +- spin_unlock_irqrestore(&hsotg->lock, flags); +- dwc2_vbus_supply_exit(hsotg); +- spin_lock_irqsave(&hsotg->lock, flags); +- } else { +- pcgctl = readl(hsotg->regs + PCGCTL); +- pcgctl |= PCGCTL_STOPPCLK; +- writel(pcgctl, hsotg->regs + PCGCTL); +- } +- } ++ if (hsotg->flags.b.port_connect_status == 0) ++ goto skip_power_saving; + +- if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { ++ switch (hsotg->params.power_down) { ++ case DWC2_POWER_DOWN_PARAM_PARTIAL: + /* Enter partial_power_down */ + ret = dwc2_enter_partial_power_down(hsotg); +- if (ret) { +- if (ret != -ENOTSUPP) +- dev_err(hsotg->dev, +- "enter partial_power_down failed\n"); +- goto skip_power_saving; +- } +- +- /* After entering partial_power_down, hardware is no more accessible */ +- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); ++ if (ret) ++ dev_err(hsotg->dev, ++ "enter partial_power_down failed\n"); ++ break; ++ case DWC2_POWER_DOWN_PARAM_HIBERNATION: ++ /* Enter hibernation */ ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ ret = dwc2_enter_hibernation(hsotg, 1); ++ if (ret) ++ dev_err(hsotg->dev, "enter hibernation failed\n"); ++ spin_lock_irqsave(&hsotg->lock, flags); ++ break; ++ case DWC2_POWER_DOWN_PARAM_NONE: ++ /* ++ * If not hibernation nor partial power down are supported, ++ * clock gating is used to save power. ++ */ ++ dwc2_host_enter_clock_gating(hsotg); ++ break; ++ default: ++ goto skip_power_saving; + } + ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ dwc2_vbus_supply_exit(hsotg); ++ spin_lock_irqsave(&hsotg->lock, flags); ++ + /* Ask phy to be suspended */ + if (!IS_ERR_OR_NULL(hsotg->uphy)) { + spin_unlock_irqrestore(&hsotg->lock, flags); +@@ -4382,7 +4428,6 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) + { + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + unsigned long flags; +- u32 pcgctl; + int ret = 0; + + spin_lock_irqsave(&hsotg->lock, flags); +@@ -4393,11 +4438,53 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) + if (hsotg->lx_state != DWC2_L2) + goto unlock; + +- if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL) { ++ /* ++ if (dwc2_read_hprt0(hsotg) & HPRT0_CONNSTS) dont use. ++ GOTGCTL_VBVALOEN is setting when external_vbus_detect mode, so dont use HPRT0_CONNSTS to judge Port Connect Status. ++ use vbus_supply_enabled flag to judge Port Connect Status. ++ */ ++ if (hsotg->vbus_supply_enabled) { + hsotg->lx_state = DWC2_L0; + goto unlock; + } + ++ switch (hsotg->params.power_down) { ++ case DWC2_POWER_DOWN_PARAM_PARTIAL: ++ ret = dwc2_exit_partial_power_down(hsotg, 0, true); ++ if (ret) ++ dev_err(hsotg->dev, ++ "exit partial_power_down failed\n"); ++ break; ++ case DWC2_POWER_DOWN_PARAM_HIBERNATION: ++ ret = dwc2_exit_hibernation(hsotg, 0, 0, 1); ++ if (ret) ++ dev_err(hsotg->dev, "exit hibernation failed.\n"); ++ break; ++ case DWC2_POWER_DOWN_PARAM_NONE: ++ /* ++ * If not hibernation nor partial power down are supported, ++ * port resume is done using the clock gating programming flow. ++ */ ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ dwc2_host_exit_clock_gating(hsotg, 0); ++ ++ /* ++ * Initialize the Core for Host mode, as after system resume ++ * the global interrupts are disabled. ++ */ ++ dwc2_core_init(hsotg, false); ++ dwc2_enable_global_interrupts(hsotg); ++ dwc2_hcd_reinit(hsotg); ++ spin_lock_irqsave(&hsotg->lock, flags); ++ break; ++ default: ++ hsotg->lx_state = DWC2_L0; ++ goto unlock; ++ } ++ ++ /* Change Root port status, as port status change occurred after resume.*/ ++ hsotg->flags.b.port_suspend_change = 1; ++ + /* + * Enable power if not already done. + * This must not be spinlocked since duration +@@ -4409,52 +4496,25 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) + spin_lock_irqsave(&hsotg->lock, flags); + } + +- if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { +- /* +- * Set HW accessible bit before powering on the controller +- * since an interrupt may rise. +- */ +- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); +- +- +- /* Exit partial_power_down */ +- ret = dwc2_exit_partial_power_down(hsotg, true); +- if (ret && (ret != -ENOTSUPP)) +- dev_err(hsotg->dev, "exit partial_power_down failed\n"); +- } else { +- pcgctl = readl(hsotg->regs + PCGCTL); +- pcgctl &= ~PCGCTL_STOPPCLK; +- writel(pcgctl, hsotg->regs + PCGCTL); +- } +- +- hsotg->lx_state = DWC2_L0; +- ++ /* Enable external vbus supply after resuming the port. */ + spin_unlock_irqrestore(&hsotg->lock, flags); ++ dwc2_vbus_supply_init(hsotg); + +- if (hsotg->bus_suspended) { +- spin_lock_irqsave(&hsotg->lock, flags); +- hsotg->flags.b.port_suspend_change = 1; +- spin_unlock_irqrestore(&hsotg->lock, flags); +- dwc2_port_resume(hsotg); +- } else { +- if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { +- dwc2_vbus_supply_init(hsotg); +- +- /* Wait for controller to correctly update D+/D- level */ +- usleep_range(3000, 5000); +- } ++ /* Wait for controller to correctly update D+/D- level */ ++ usleep_range(3000, 5000); ++ spin_lock_irqsave(&hsotg->lock, flags); + +- /* +- * Clear Port Enable and Port Status changes. +- * Enable Port Power. +- */ +- dwc2_writel(hsotg, HPRT0_PWR | HPRT0_CONNDET | +- HPRT0_ENACHG, HPRT0); +- /* Wait for controller to detect Port Connect */ +- usleep_range(5000, 7000); +- } ++ /* ++ * Clear Port Enable and Port Status changes. ++ * Enable Port Power. ++ */ ++ dwc2_writel(hsotg, HPRT0_PWR | HPRT0_CONNDET | ++ HPRT0_ENACHG, HPRT0); + +- return ret; ++ /* Wait for controller to detect Port Connect */ ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ usleep_range(5000, 7000); ++ spin_lock_irqsave(&hsotg->lock, flags); + unlock: + spin_unlock_irqrestore(&hsotg->lock, flags); + +@@ -4565,12 +4625,41 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, + struct dwc2_qh *qh; + bool qh_allocated = false; + struct dwc2_qtd *qtd; ++ struct dwc2_gregs_backup *gr; ++ ++ gr = &hsotg->gr_backup; + + if (dbg_urb(urb)) { + dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n"); + dwc2_dump_urb_info(hcd, urb, "urb_enqueue"); + } + ++ if (hsotg->hibernated) { ++ if (gr->gotgctl & GOTGCTL_CURMODE_HOST) ++ retval = dwc2_exit_hibernation(hsotg, 0, 0, 1); ++ else ++ retval = dwc2_exit_hibernation(hsotg, 0, 0, 0); ++ ++ if (retval) ++ dev_err(hsotg->dev, ++ "exit hibernation failed.\n"); ++ } ++ ++ if (hsotg->in_ppd) { ++ retval = dwc2_exit_partial_power_down(hsotg, 0, true); ++ if (retval) ++ dev_err(hsotg->dev, ++ "exit partial_power_down failed\n"); ++ } ++ ++ if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE && ++ hsotg->bus_suspended) { ++ if (dwc2_is_device_mode(hsotg)) ++ dwc2_gadget_exit_clock_gating(hsotg, 0); ++ else ++ dwc2_host_exit_clock_gating(hsotg, 0); ++ } ++ + if (!ep) + return -EINVAL; + +@@ -5378,7 +5467,6 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg) + unsigned long flags; + int ret = 0; + u32 hprt0; +- u32 pcgcctl; + u32 gusbcfg; + u32 gpwrdn; + +@@ -5416,12 +5504,6 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg) + gusbcfg = dwc2_readl(hsotg, GUSBCFG); + if (gusbcfg & GUSBCFG_ULPI_UTMI_SEL) { + /* ULPI interface */ +- /* Suspend the Phy Clock */ +- pcgcctl = dwc2_readl(hsotg, PCGCTL); +- pcgcctl |= PCGCTL_STOPPCLK; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- udelay(10); +- + gpwrdn = dwc2_readl(hsotg, GPWRDN); + gpwrdn |= GPWRDN_PMUACTV; + dwc2_writel(hsotg, gpwrdn, GPWRDN); +@@ -5432,11 +5514,6 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg) + gpwrdn |= GPWRDN_PMUACTV; + dwc2_writel(hsotg, gpwrdn, GPWRDN); + udelay(10); +- +- pcgcctl = dwc2_readl(hsotg, PCGCTL); +- pcgcctl |= PCGCTL_STOPPCLK; +- dwc2_writel(hsotg, pcgcctl, PCGCTL); +- udelay(10); + } + + /* Enable interrupts from wake up logic */ +@@ -5619,3 +5696,192 @@ bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2) + /* No reason to keep the PHY powered, so allow poweroff */ + return true; + } ++ ++/** ++ * dwc2_host_enter_partial_power_down() - Put controller in partial ++ * power down. ++ * ++ * @hsotg: Programming view of the DWC_otg controller ++ * ++ * Return: non-zero if failed to enter host partial power down. ++ * ++ * This function is for entering Host mode partial power down. ++ */ ++int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg) ++{ ++ u32 hprt0; ++ int ret = 0; ++ ++ dev_dbg(hsotg->dev, "Entering host partial power down started.\n"); ++ ++ /* Put this port in suspend mode. */ ++ hprt0 = dwc2_read_hprt0(hsotg); ++ hprt0 |= HPRT0_SUSP; ++ dwc2_writel(hsotg, hprt0, HPRT0); ++ udelay(5); ++ ++ /* Wait for the HPRT0.PrtSusp register field to be set */ ++ if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 3000)) ++ dev_warn(hsotg->dev, "Suspend wasn't generated\n"); ++ ++ /* Backup all registers */ ++ ret = dwc2_backup_global_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to backup global registers\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = dwc2_backup_host_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to backup host registers\n", ++ __func__); ++ return ret; ++ } ++ ++ /* ++ * Clear any pending interrupts since dwc2 will not be able to ++ * clear them after entering partial_power_down. ++ */ ++ dwc2_writel(hsotg, 0xffffffff, GINTSTS); ++ ++ /* Set in_ppd flag to 1 as here core enters suspend. */ ++ hsotg->in_ppd = 1; ++ hsotg->lx_state = DWC2_L2; ++ hsotg->bus_suspended = true; ++ ++ dev_dbg(hsotg->dev, "Entering host partial power down completed.\n"); ++ ++ return ret; ++} ++ ++/* ++ * dwc2_host_exit_partial_power_down() - Exit controller from host partial ++ * power down. ++ * ++ * @hsotg: Programming view of the DWC_otg controller ++ * @rem_wakeup: indicates whether resume is initiated by Reset. ++ * @restore: indicates whether need to restore the registers or not. ++ * ++ * Return: non-zero if failed to exit host partial power down. ++ * ++ * This function is for exiting from Host mode partial power down. ++ */ ++int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg, ++ int rem_wakeup, bool restore) ++{ ++ int ret = 0; ++ u32 hprt0; ++ ++ dev_dbg(hsotg->dev, "Exiting host partial power down started.\n"); ++ ++ if (restore) { ++ ret = dwc2_restore_global_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to restore registers\n", ++ __func__); ++ return ret; ++ } ++ ++ ret = dwc2_restore_host_registers(hsotg); ++ if (ret) { ++ dev_err(hsotg->dev, "%s: failed to restore host registers\n", ++ __func__); ++ return ret; ++ } ++ } ++ ++ /* Drive resume signaling and exit suspend mode on the port. */ ++ hprt0 = dwc2_read_hprt0(hsotg); ++ hprt0 |= HPRT0_RES; ++ hprt0 &= ~HPRT0_SUSP; ++ dwc2_writel(hsotg, hprt0, HPRT0); ++ udelay(5); ++ ++ if (!rem_wakeup) { ++ /* Stop driveing resume signaling on the port. */ ++ hprt0 = dwc2_read_hprt0(hsotg); ++ hprt0 &= ~HPRT0_RES; ++ dwc2_writel(hsotg, hprt0, HPRT0); ++ ++ hsotg->bus_suspended = false; ++ } else { ++ /* Turn on the port power bit. */ ++ hprt0 = dwc2_read_hprt0(hsotg); ++ hprt0 |= HPRT0_PWR; ++ dwc2_writel(hsotg, hprt0, HPRT0); ++ ++ /* Connect hcd. */ ++ dwc2_hcd_connect(hsotg); ++ ++ mod_timer(&hsotg->wkp_timer, ++ jiffies + msecs_to_jiffies(71)); ++ } ++ ++ /* Set lx_state to and in_ppd to 0 as here core exits from suspend. */ ++ hsotg->in_ppd = 0; ++ hsotg->lx_state = DWC2_L0; ++ ++ dev_dbg(hsotg->dev, "Exiting host partial power down completed.\n"); ++ return ret; ++} ++ ++/** ++ * dwc2_host_enter_clock_gating() - Put controller in clock gating. ++ * ++ * @hsotg: Programming view of the DWC_otg controller ++ * ++ * This function is for entering Host mode clock gating. ++ */ ++void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg) ++{ ++ u32 hprt0; ++ ++ dev_dbg(hsotg->dev, "Entering host clock gating.\n"); ++ ++ /* Put this port in suspend mode. */ ++ hprt0 = dwc2_read_hprt0(hsotg); ++ hprt0 |= HPRT0_SUSP; ++ dwc2_writel(hsotg, hprt0, HPRT0); ++ ++ hsotg->bus_suspended = true; ++ hsotg->lx_state = DWC2_L2; ++} ++ ++/** ++ * dwc2_host_exit_clock_gating() - Exit controller from clock gating. ++ * ++ * @hsotg: Programming view of the DWC_otg controller ++ * @rem_wakeup: indicates whether resume is initiated by remote wakeup ++ * ++ * This function is for exiting Host mode clock gating. ++ */ ++void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup) ++{ ++ u32 hprt0; ++ ++ dev_dbg(hsotg->dev, "Exiting host clock gating.\n"); ++ ++ /* Drive resume signaling and exit suspend mode on the port. */ ++ hprt0 = dwc2_read_hprt0(hsotg); ++ hprt0 |= HPRT0_RES; ++ hprt0 &= ~HPRT0_SUSP; ++ dwc2_writel(hsotg, hprt0, HPRT0); ++ udelay(5); ++ ++ if (!rem_wakeup) { ++ /* In case of port resume need to wait for 40 ms */ ++ msleep(USB_RESUME_TIMEOUT); ++ ++ /* Stop driveing resume signaling on the port. */ ++ hprt0 = dwc2_read_hprt0(hsotg); ++ hprt0 &= ~HPRT0_RES; ++ dwc2_writel(hsotg, hprt0, HPRT0); ++ ++ hsotg->bus_suspended = false; ++ hsotg->lx_state = DWC2_L0; ++ } else { ++ mod_timer(&hsotg->wkp_timer, ++ jiffies + msecs_to_jiffies(71)); ++ } ++} +diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c +index 94af71e98..24beff610 100644 +--- a/drivers/usb/dwc2/hcd_queue.c ++++ b/drivers/usb/dwc2/hcd_queue.c +@@ -675,7 +675,7 @@ static int dwc2_hs_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, + } + + /** +- * dwc2_ls_pmap_unschedule() - Undo work done by dwc2_hs_pmap_schedule() ++ * dwc2_hs_pmap_unschedule() - Undo work done by dwc2_hs_pmap_schedule() + * + * @hsotg: The HCD state structure for the DWC OTG controller. + * @qh: QH for the periodic transfer. +diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h +index c3d6dde2a..1cc216ebd 100644 +--- a/drivers/usb/dwc2/hw.h ++++ b/drivers/usb/dwc2/hw.h +@@ -44,6 +44,7 @@ + #define GOTGCTL_CHIRPEN BIT(27) + #define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22) + #define GOTGCTL_MULT_VALID_BC_SHIFT 22 ++#define GOTGCTL_CURMODE_HOST BIT(21) + #define GOTGCTL_OTGVER BIT(20) + #define GOTGCTL_BSESVLD BIT(19) + #define GOTGCTL_ASESVLD BIT(18) +@@ -648,38 +649,6 @@ + + #define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20)) + +-#define PCGCTL HSOTG_REG(0x0e00) +-#define PCGCTL_IF_DEV_MODE BIT(31) +-#define PCGCTL_P2HD_PRT_SPD_MASK (0x3 << 29) +-#define PCGCTL_P2HD_PRT_SPD_SHIFT 29 +-#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3 << 27) +-#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27 +-#define PCGCTL_MAC_DEV_ADDR_MASK (0x7f << 20) +-#define PCGCTL_MAC_DEV_ADDR_SHIFT 20 +-#define PCGCTL_MAX_TERMSEL BIT(19) +-#define PCGCTL_MAX_XCVRSELECT_MASK (0x3 << 17) +-#define PCGCTL_MAX_XCVRSELECT_SHIFT 17 +-#define PCGCTL_PORT_POWER BIT(16) +-#define PCGCTL_PRT_CLK_SEL_MASK (0x3 << 14) +-#define PCGCTL_PRT_CLK_SEL_SHIFT 14 +-#define PCGCTL_ESS_REG_RESTORED BIT(13) +-#define PCGCTL_EXTND_HIBER_SWITCH BIT(12) +-#define PCGCTL_EXTND_HIBER_PWRCLMP BIT(11) +-#define PCGCTL_ENBL_EXTND_HIBER BIT(10) +-#define PCGCTL_RESTOREMODE BIT(9) +-#define PCGCTL_RESETAFTSUSP BIT(8) +-#define PCGCTL_DEEP_SLEEP BIT(7) +-#define PCGCTL_PHY_IN_SLEEP BIT(6) +-#define PCGCTL_ENBL_SLEEP_GATING BIT(5) +-#define PCGCTL_RSTPDWNMODULE BIT(3) +-#define PCGCTL_PWRCLMP BIT(2) +-#define PCGCTL_GATEHCLK BIT(1) +-#define PCGCTL_STOPPCLK BIT(0) +- +-#define PCGCCTL1 HSOTG_REG(0xe04) +-#define PCGCCTL1_TIMER (0x3 << 1) +-#define PCGCCTL1_GATEEN BIT(0) +- + #define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000)) + + /* Host Mode Registers */ +diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c +index 267543c3d..0850a6669 100644 +--- a/drivers/usb/dwc2/params.c ++++ b/drivers/usb/dwc2/params.c +@@ -39,210 +39,65 @@ + + #include "core.h" + +-static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; +- +- p->host_rx_fifo_size = 774; +- p->max_transfer_size = 65535; +- p->max_packet_count = 511; +- p->ahbcfg = 0x10; +-} +- +-static void dwc2_set_his_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; +- +- p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; +- p->speed = DWC2_SPEED_PARAM_HIGH; +- p->host_rx_fifo_size = 512; +- p->host_nperio_tx_fifo_size = 512; +- p->host_perio_tx_fifo_size = 512; +- p->max_transfer_size = 65535; +- p->max_packet_count = 511; +- p->host_channels = 16; +- p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI; +- p->phy_utmi_width = 8; +- p->i2c_enable = false; +- p->reload_ctl = false; +- p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << +- GAHBCFG_HBSTLEN_SHIFT; +- p->change_speed_quirk = true; +- p->power_down = DWC2_POWER_DOWN_PARAM_NONE; +-} +- +-static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; +- +- p->power_down = DWC2_POWER_DOWN_PARAM_NONE; +- p->phy_utmi_width = 8; +-} +- +-static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; +- +- p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; +- p->host_rx_fifo_size = 525; +- p->host_nperio_tx_fifo_size = 128; +- p->host_perio_tx_fifo_size = 256; +- p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << +- GAHBCFG_HBSTLEN_SHIFT; +- p->power_down = DWC2_POWER_DOWN_PARAM_NONE; +-} +- +-static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; +- +- p->otg_cap = 2; +- p->host_rx_fifo_size = 288; +- p->host_nperio_tx_fifo_size = 128; +- p->host_perio_tx_fifo_size = 96; +- p->max_transfer_size = 65535; +- p->max_packet_count = 511; +- p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << +- GAHBCFG_HBSTLEN_SHIFT; +-} +- +-static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; +- +- p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; +- p->speed = DWC2_SPEED_PARAM_HIGH; +- p->host_rx_fifo_size = 512; +- p->host_nperio_tx_fifo_size = 500; +- p->host_perio_tx_fifo_size = 500; +- p->host_channels = 16; +- p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI; +- p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 << +- GAHBCFG_HBSTLEN_SHIFT; +- p->power_down = DWC2_POWER_DOWN_PARAM_NONE; +-} +- +-static void dwc2_set_amlogic_g12a_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; +- +- p->lpm = false; +- p->lpm_clock_gating = false; +- p->besl = false; +- p->hird_threshold_en = false; +-} +- +-static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) ++static void dwc2_set_hsotg_params(struct dwc2_hsotg *hsotg) + { + struct dwc2_core_params *p = &hsotg->params; + + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; +-} + +-static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; ++ p->otg_caps.otg_rev = 0x200; + +- p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; +- p->speed = DWC2_SPEED_PARAM_FULL; +- p->host_rx_fifo_size = 128; +- p->host_nperio_tx_fifo_size = 96; +- p->host_perio_tx_fifo_size = 96; +- p->max_packet_count = 256; +- p->phy_type = DWC2_PHY_TYPE_PARAM_FS; +- p->i2c_enable = false; +- p->activate_stm_fs_transceiver = true; +-} ++ p->host_rx_fifo_size = 1528; ++ p->host_nperio_tx_fifo_size = 1024; ++ p->host_perio_tx_fifo_size = 1024; + +-static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; ++#ifdef CONFIG_USB_DWC2_EXT_ID_PIN ++ p->external_id_pin_ctl = true; ++#endif + +- p->host_rx_fifo_size = 622; +- p->host_nperio_tx_fifo_size = 128; +- p->host_perio_tx_fifo_size = 256; +-} ++#ifdef CONFIG_USB_DWC2_EXT_VBUS_DETECT ++ p->external_vbus_detect = true; ++#endif + +-static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; +- +- p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; ++#ifdef CONFIG_USB_DWC2_FORCE_FULL_SPEED + p->speed = DWC2_SPEED_PARAM_FULL; +- p->host_rx_fifo_size = 128; +- p->host_nperio_tx_fifo_size = 96; +- p->host_perio_tx_fifo_size = 96; +- p->max_packet_count = 256; +- p->phy_type = DWC2_PHY_TYPE_PARAM_FS; +- p->i2c_enable = false; +- p->activate_stm_fs_transceiver = true; +- p->activate_stm_id_vb_detection = true; +- p->power_down = DWC2_POWER_DOWN_PARAM_NONE; +-} +- +-static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg) +-{ +- struct dwc2_core_params *p = &hsotg->params; +- +- p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; +- p->activate_stm_id_vb_detection = !device_property_read_bool(hsotg->dev, "usb-role-switch"); +- p->host_rx_fifo_size = 440; +- p->host_nperio_tx_fifo_size = 256; +- p->host_perio_tx_fifo_size = 256; +- p->power_down = DWC2_POWER_DOWN_PARAM_NONE; ++#endif + } + + const struct of_device_id dwc2_of_match_table[] = { +- { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params }, +- { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params }, +- { .compatible = "rockchip,rk3066-usb", .data = dwc2_set_rk_params }, +- { .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params }, +- { .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params }, + { .compatible = "snps,dwc2" }, +- { .compatible = "samsung,s3c6400-hsotg", +- .data = dwc2_set_s3c6400_params }, +- { .compatible = "amlogic,meson8-usb", +- .data = dwc2_set_amlogic_params }, +- { .compatible = "amlogic,meson8b-usb", +- .data = dwc2_set_amlogic_params }, +- { .compatible = "amlogic,meson-gxbb-usb", +- .data = dwc2_set_amlogic_params }, +- { .compatible = "amlogic,meson-g12a-usb", +- .data = dwc2_set_amlogic_g12a_params }, +- { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params }, +- { .compatible = "apm,apm82181-dwc-otg", .data = dwc2_set_amcc_params }, +- { .compatible = "st,stm32f4x9-fsotg", +- .data = dwc2_set_stm32f4x9_fsotg_params }, +- { .compatible = "st,stm32f4x9-hsotg" }, +- { .compatible = "st,stm32f7-hsotg", +- .data = dwc2_set_stm32f7_hsotg_params }, +- { .compatible = "st,stm32mp15-fsotg", +- .data = dwc2_set_stm32mp15_fsotg_params }, +- { .compatible = "st,stm32mp15-hsotg", +- .data = dwc2_set_stm32mp15_hsotg_params }, ++ { .compatible = "ingenic,x1000-dwc2-hsotg", ++ .data = dwc2_set_hsotg_params }, ++ { .compatible = "ingenic,x1600-dwc2-hsotg", ++ .data = dwc2_set_hsotg_params }, ++ { .compatible = "ingenic,x2000-dwc2-hsotg", ++ .data = dwc2_set_hsotg_params }, ++ { .compatible = "ingenic,x2500-dwc2-hsotg", ++ .data = dwc2_set_hsotg_params }, ++ { .compatible = "ingenic,m300-dwc2-hsotg", ++ .data = dwc2_set_hsotg_params }, + {}, + }; + MODULE_DEVICE_TABLE(of, dwc2_of_match_table); + + static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg) + { +- u8 val; +- + switch (hsotg->hw_params.op_mode) { + case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: +- val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE; ++ hsotg->params.otg_caps.hnp_support = true; ++ hsotg->params.otg_caps.srp_support = true; + break; + case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: +- val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE; ++ hsotg->params.otg_caps.hnp_support = false; ++ hsotg->params.otg_caps.srp_support = true; + break; + default: +- val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; ++ hsotg->params.otg_caps.hnp_support = false; ++ hsotg->params.otg_caps.srp_support = false; + break; + } +- +- hsotg->params.otg_cap = val; + } + + static void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg) +@@ -412,8 +267,8 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) + * auto-detect if the hardware does not support the + * default. + */ +- p->g_rx_fifo_size = 2048; +- p->g_np_tx_fifo_size = 1024; ++ p->g_rx_fifo_size = 768; ++ p->g_np_tx_fifo_size = 256; + dwc2_set_param_tx_fifo_sizes(hsotg); + } + } +@@ -452,35 +307,47 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) + + if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL)) + p->oc_disable = true; ++ ++ if (of_find_property(hsotg->dev->of_node, "force-full-speed", NULL)) ++ p->speed = DWC2_SPEED_PARAM_FULL; ++ ++ if (of_find_property(hsotg->dev->of_node, "external-id-pin", NULL)) ++ p->external_id_pin_ctl = true; ++ ++ if (of_find_property(hsotg->dev->of_node, "external-vbus-detect", NULL)) ++ p->external_vbus_detect = true; ++ ++ if (of_find_property(hsotg->dev->of_node, "device-using-dma", NULL)) { ++ p->g_dma_desc = false; ++ p->g_dma = true; ++ } + } + + static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) + { + int valid = 1; + +- switch (hsotg->params.otg_cap) { +- case DWC2_CAP_PARAM_HNP_SRP_CAPABLE: ++ if (hsotg->params.otg_caps.hnp_support && hsotg->params.otg_caps.srp_support) { ++ /* check HNP && SRP capable */ + if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) + valid = 0; +- break; +- case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE: +- switch (hsotg->hw_params.op_mode) { +- case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: +- case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: +- case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: +- case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: +- break; +- default: +- valid = 0; +- break; ++ } else if (!hsotg->params.otg_caps.hnp_support) { ++ /* check SRP only capable */ ++ if (hsotg->params.otg_caps.srp_support) { ++ switch (hsotg->hw_params.op_mode) { ++ case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: ++ case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: ++ case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: ++ case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: ++ break; ++ default: ++ valid = 0; ++ break; ++ } + } +- break; +- case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE: +- /* always valid */ +- break; +- default: ++ /* else: NO HNP && NO SRP capable: always valid */ ++ } else { + valid = 0; +- break; + } + + if (!valid) +diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c +index 7afc10872..0000151e3 100644 +--- a/drivers/usb/dwc2/pci.c ++++ b/drivers/usb/dwc2/pci.c +@@ -63,20 +63,6 @@ struct dwc2_pci_glue { + struct platform_device *phy; + }; + +-static int dwc2_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc2) +-{ +- if (pdev->vendor == PCI_VENDOR_ID_SYNOPSYS && +- pdev->device == PCI_PRODUCT_ID_HAPS_HSOTG) { +- struct property_entry properties[] = { +- { }, +- }; +- +- return platform_device_add_properties(dwc2, properties); +- } +- +- return 0; +-} +- + /** + * dwc2_pci_probe() - Provides the cleanup entry points for the DWC_otg PCI + * driver +@@ -143,10 +129,6 @@ static int dwc2_pci_probe(struct pci_dev *pci, + + dwc2->dev.parent = dev; + +- ret = dwc2_pci_quirks(pci, dwc2); +- if (ret) +- goto err; +- + glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); + if (!glue) { + ret = -ENOMEM; +diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c +index 49d333f02..6b88e5dd5 100644 +--- a/drivers/usb/dwc2/platform.c ++++ b/drivers/usb/dwc2/platform.c +@@ -49,7 +49,6 @@ + #include + + #include +- + #include "core.h" + #include "hcd.h" + #include "debug.h" +@@ -281,7 +280,7 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) + hsotg->plat = dev_get_platdata(hsotg->dev); + + /* Clock */ +- hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg"); ++ hsotg->clk = devm_clk_get_optional(hsotg->dev, "gate_otg"); + if (IS_ERR(hsotg->clk)) { + dev_err(hsotg->dev, "cannot get otg clock\n"); + return PTR_ERR(hsotg->clk); +@@ -299,6 +298,7 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) + ret); + return ret; + } ++ + return 0; + } + +@@ -316,6 +316,31 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) + static int dwc2_driver_remove(struct platform_device *dev) + { + struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); ++ struct dwc2_gregs_backup *gr; ++ int ret = 0; ++ ++ gr = &hsotg->gr_backup; ++ ++ /* Exit Hibernation when driver is removed. */ ++ if (hsotg->hibernated) { ++ if (gr->gotgctl & GOTGCTL_CURMODE_HOST) ++ ret = dwc2_exit_hibernation(hsotg, 0, 0, 1); ++ else ++ ret = dwc2_exit_hibernation(hsotg, 0, 0, 0); ++ ++ if (ret) ++ dev_err(hsotg->dev, ++ "exit hibernation failed.\n"); ++ } ++ ++ /* Exit clock gating when driver is removed. */ ++ if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE && ++ hsotg->bus_suspended) { ++ if (dwc2_is_device_mode(hsotg)) ++ dwc2_gadget_exit_clock_gating(hsotg, 0); ++ else ++ dwc2_host_exit_clock_gating(hsotg, 0); ++ } + + dwc2_debugfs_exit(hsotg); + if (hsotg->hcd_enabled) +@@ -325,16 +350,13 @@ static int dwc2_driver_remove(struct platform_device *dev) + + dwc2_drd_exit(hsotg); + +- if (hsotg->params.activate_stm_id_vb_detection) +- regulator_disable(hsotg->usb33d); +- + if (hsotg->ll_hw_enabled) + dwc2_lowlevel_hw_disable(hsotg); + + reset_control_assert(hsotg->reset); + reset_control_assert(hsotg->reset_ecc); + +- return 0; ++ return ret; + } + + /** +@@ -375,7 +397,7 @@ static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg) + } + + /** +- * Check core version ++ * dwc2_check_core_version() - Check core version + * + * @hsotg: Programming view of the DWC_otg controller + * +@@ -405,6 +427,44 @@ int dwc2_check_core_version(struct dwc2_hsotg *hsotg) + return 0; + } + ++static ssize_t show_id_status(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct dwc2_hsotg *hsotg = dev_get_drvdata(dev); ++ unsigned long gotgctl = dwc2_readl(hsotg, GOTGCTL); ++ return sprintf(buf, "%s\n", (gotgctl & GOTGCTL_CONID_B) ? "device" : "host"); ++} ++ ++static ssize_t dwc2_mode_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ char *mode; ++ struct dwc2_hsotg *hsotg = dev_get_drvdata(dev); ++ ++ if (hsotg->dr_mode == USB_DR_MODE_HOST) { ++ mode = "host"; ++ } else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) { ++ mode = "peripheral"; ++ } else { ++ mode = "otg"; ++ } ++ ++ return sprintf(buf, "%s\n", mode); ++} ++ ++static DEVICE_ATTR(id_status, S_IRUGO, show_id_status, NULL); ++static DEVICE_ATTR(dwc2_mode, S_IRUGO, dwc2_mode_show, NULL); ++ ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ ++ IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) ++static ssize_t show_connected(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ ++ struct dwc2_hsotg *hsotg = dev_get_drvdata(dev); ++ return sprintf(buf, "%s\n", hsotg->connected ? "connect" : "disconnect"); ++} ++ ++static DEVICE_ATTR(connected, S_IRUGO, show_connected, NULL); ++#endif /* CONFIG_USB_DWC2_NEW_PERIPHERAL || CONFIG_USB_DWC2_NEW_DUAL_ROLE */ ++ + /** + * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg + * driver +@@ -519,39 +579,11 @@ static int dwc2_driver_probe(struct platform_device *dev) + if (retval) + goto error; + +- if (hsotg->params.activate_stm_id_vb_detection) { +- u32 ggpio; +- +- hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d"); +- if (IS_ERR(hsotg->usb33d)) { +- retval = PTR_ERR(hsotg->usb33d); +- if (retval != -EPROBE_DEFER) +- dev_err(hsotg->dev, +- "failed to request usb33d supply: %d\n", +- retval); +- goto error; +- } +- retval = regulator_enable(hsotg->usb33d); +- if (retval) { +- dev_err(hsotg->dev, +- "failed to enable usb33d supply: %d\n", retval); +- goto error; +- } +- +- ggpio = dwc2_readl(hsotg, GGPIO); +- ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; +- ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; +- dwc2_writel(hsotg, ggpio, GGPIO); +- +- /* ID/VBUS detection startup time */ +- usleep_range(5000, 7000); +- } +- + retval = dwc2_drd_init(hsotg); + if (retval) { + if (retval != -EPROBE_DEFER) + dev_err(hsotg->dev, "failed to initialize dual-role\n"); +- goto error_init; ++ goto error; + } + + if (hsotg->dr_mode != USB_DR_MODE_HOST) { +@@ -597,8 +629,12 @@ static int dwc2_driver_probe(struct platform_device *dev) + if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) + dwc2_lowlevel_hw_disable(hsotg); + ++ device_create_file(hsotg->dev, &dev_attr_id_status); ++ device_create_file(hsotg->dev, &dev_attr_dwc2_mode); ++ + #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ + IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) ++ device_create_file(hsotg->dev, &dev_attr_connected); + /* Postponed adding a new gadget to the udc class driver list */ + if (hsotg->gadget_enabled) { + retval = usb_add_gadget_udc(hsotg->dev, &hsotg->gadget); +@@ -620,10 +656,6 @@ static int dwc2_driver_probe(struct platform_device *dev) + #endif + error_drd: + dwc2_drd_exit(hsotg); +- +-error_init: +- if (hsotg->params.activate_stm_id_vb_detection) +- regulator_disable(hsotg->usb33d); + error: + if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) + dwc2_lowlevel_hw_disable(hsotg); +@@ -633,51 +665,23 @@ static int dwc2_driver_probe(struct platform_device *dev) + static int __maybe_unused dwc2_suspend(struct device *dev) + { + struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); +- bool is_device_mode = dwc2_is_device_mode(dwc2); + int ret = 0; + +- if (is_device_mode) ++#if 0 /* not close endpoint and disconnet */ ++ if (dwc2_is_device_mode(dwc2)) + dwc2_hsotg_suspend(dwc2); ++#endif + +- dwc2_drd_suspend(dwc2); +- +- if (dwc2->params.activate_stm_id_vb_detection) { +- unsigned long flags; +- u32 ggpio, gotgctl; +- +- /* +- * Need to force the mode to the current mode to avoid Mode +- * Mismatch Interrupt when ID detection will be disabled. +- */ +- dwc2_force_mode(dwc2, !is_device_mode); +- +- spin_lock_irqsave(&dwc2->lock, flags); +- gotgctl = dwc2_readl(dwc2, GOTGCTL); +- /* bypass debounce filter, enable overrides */ +- gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; +- gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN; +- /* Force A / B session if needed */ +- if (gotgctl & GOTGCTL_ASESVLD) +- gotgctl |= GOTGCTL_AVALOVAL; +- if (gotgctl & GOTGCTL_BSESVLD) +- gotgctl |= GOTGCTL_BVALOVAL; +- dwc2_writel(dwc2, gotgctl, GOTGCTL); +- spin_unlock_irqrestore(&dwc2->lock, flags); +- +- ggpio = dwc2_readl(dwc2, GGPIO); +- ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN; +- ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN; +- dwc2_writel(dwc2, ggpio, GGPIO); +- +- regulator_disable(dwc2->usb33d); +- } ++ usb_phy_set_wakeup(dwc2->uphy, true); + +- if (dwc2->ll_hw_enabled && +- (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) { ++ if (dwc2->ll_hw_enabled && !dwc2->need_phy_for_wake) { + ret = __dwc2_lowlevel_hw_disable(dwc2); + dwc2->phy_off_for_suspend = true; + } + ++ if (dwc2->need_phy_for_wake) ++ enable_irq_wake(dwc2->irq); ++ + return ret; + } + +@@ -686,6 +690,9 @@ static int __maybe_unused dwc2_resume(struct device *dev) + struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); + int ret = 0; + ++ if (dwc2->need_phy_for_wake) ++ disable_irq_wake(dwc2->irq); ++ + if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) { + ret = __dwc2_lowlevel_hw_enable(dwc2); + if (ret) +@@ -693,38 +700,12 @@ static int __maybe_unused dwc2_resume(struct device *dev) + } + dwc2->phy_off_for_suspend = false; + +- if (dwc2->params.activate_stm_id_vb_detection) { +- unsigned long flags; +- u32 ggpio, gotgctl; +- +- ret = regulator_enable(dwc2->usb33d); +- if (ret) +- return ret; +- +- ggpio = dwc2_readl(dwc2, GGPIO); +- ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; +- ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; +- dwc2_writel(dwc2, ggpio, GGPIO); +- +- /* ID/VBUS detection startup time */ +- usleep_range(5000, 7000); +- +- spin_lock_irqsave(&dwc2->lock, flags); +- gotgctl = dwc2_readl(dwc2, GOTGCTL); +- gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS; +- gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | +- GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL); +- dwc2_writel(dwc2, gotgctl, GOTGCTL); +- spin_unlock_irqrestore(&dwc2->lock, flags); +- } +- +- /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ +- dwc2_force_dr_mode(dwc2); +- +- dwc2_drd_resume(dwc2); ++ usb_phy_set_wakeup(dwc2->uphy, false); + ++#if 0 /* not close endpoint and disconnet */ + if (dwc2_is_device_mode(dwc2)) + ret = dwc2_hsotg_resume(dwc2); ++#endif + + return ret; + } +@@ -745,7 +726,3 @@ static struct platform_driver dwc2_platform_driver = { + }; + + module_platform_driver(dwc2_platform_driver); +- +-MODULE_DESCRIPTION("DESIGNWARE HS OTG Platform Glue"); +-MODULE_AUTHOR("Matthijs Kooijman "); +-MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig +index 2d152571a..5b19024ae 100644 +--- a/drivers/usb/gadget/Kconfig ++++ b/drivers/usb/gadget/Kconfig +@@ -216,6 +216,13 @@ config USB_F_PRINTER + config USB_F_TCM + tristate + ++config USB_F_MTP ++ tristate ++ ++config USB_F_PTP ++ tristate ++ ++ + # this first set of drivers all depend on bulk-capable hardware. + + config USB_CONFIGFS +@@ -230,6 +237,14 @@ config USB_CONFIGFS + appropriate symbolic links. + For more information see Documentation/usb/gadget_configfs.rst. + ++config CONFIGFS_UEVENT_REPORT ++ tristate "Support configfs uevent report, Legacy Usage" ++ depends on USB_CONFIGFS ++ default no ++ help ++ Support uevent report, which is compatible for old android usage. ++ some platform still need these reports. ++ + config USB_CONFIGFS_SERIAL + bool "Generic serial bulk in/out" + depends on USB_CONFIGFS +@@ -450,6 +465,7 @@ config USB_CONFIGFS_F_UVC + depends on USB_CONFIGFS + depends on VIDEO_V4L2 + depends on VIDEO_DEV ++ select VIDEOBUF2_DMA_SG + select VIDEOBUF2_VMALLOC + select USB_F_UVC + help +@@ -485,6 +501,21 @@ config USB_CONFIGFS_F_TCM + Both protocols can work on USB2.0 and USB3.0. + UAS utilizes the USB 3.0 feature called streams support. + ++config USB_CONFIGFS_F_MTP ++ bool "MTP gadget" ++ depends on USB_CONFIGFS ++ select USB_F_MTP ++ help ++ USB gadget MTP support ++ ++config USB_CONFIGFS_F_PTP ++ bool "PTP gadget" ++ depends on USB_CONFIGFS && USB_CONFIGFS_F_MTP ++ select USB_F_PTP ++ help ++ USB gadget PTP support ++ ++ + source "drivers/usb/gadget/legacy/Kconfig" + + endif # USB_GADGET +diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c +index a98079990..a03522dfb 100644 +--- a/drivers/usb/gadget/composite.c ++++ b/drivers/usb/gadget/composite.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -734,47 +735,77 @@ static int bos_desc(struct usb_composite_dev *cdev) + /* The SuperSpeedPlus USB Device Capability descriptor */ + if (gadget_is_superspeed_plus(cdev->gadget)) { + struct usb_ssp_cap_descriptor *ssp_cap; ++ u8 ssac = 1; ++ u8 ssic; ++ int i; + +- ssp_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); +- bos->bNumDeviceCaps++; ++ if (cdev->gadget->max_ssp_rate == USB_SSP_GEN_2x2) ++ ssac = 3; + + /* +- * Report typical values. ++ * Paired RX and TX sublink speed attributes share ++ * the same SSID. + */ ++ ssic = (ssac + 1) / 2 - 1; ++ ++ ssp_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); ++ bos->bNumDeviceCaps++; + +- le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SSP_CAP_SIZE(1)); +- ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(1); ++ le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SSP_CAP_SIZE(ssac)); ++ ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(ssac); + ssp_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + ssp_cap->bDevCapabilityType = USB_SSP_CAP_TYPE; + ssp_cap->bReserved = 0; + ssp_cap->wReserved = 0; + +- /* SSAC = 1 (2 attributes) */ +- ssp_cap->bmAttributes = cpu_to_le32(1); ++ ssp_cap->bmAttributes = ++ cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_ATTRIBS, ssac) | ++ FIELD_PREP(USB_SSP_SUBLINK_SPEED_IDS, ssic)); + +- /* Min RX/TX Lane Count = 1 */ + ssp_cap->wFunctionalitySupport = +- cpu_to_le16((1 << 8) | (1 << 12)); ++ cpu_to_le16(FIELD_PREP(USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, 0) | ++ FIELD_PREP(USB_SSP_MIN_RX_LANE_COUNT, 1) | ++ FIELD_PREP(USB_SSP_MIN_TX_LANE_COUNT, 1)); + + /* +- * bmSublinkSpeedAttr[0]: +- * ST = Symmetric, RX +- * LSE = 3 (Gbps) +- * LP = 1 (SuperSpeedPlus) +- * LSM = 10 (10 Gbps) ++ * Use 1 SSID if the gadget supports up to gen2x1 or not ++ * specified: ++ * - SSID 0 for symmetric RX/TX sublink speed of 10 Gbps. ++ * ++ * Use 1 SSID if the gadget supports up to gen1x2: ++ * - SSID 0 for symmetric RX/TX sublink speed of 5 Gbps. ++ * ++ * Use 2 SSIDs if the gadget supports up to gen2x2: ++ * - SSID 0 for symmetric RX/TX sublink speed of 5 Gbps. ++ * - SSID 1 for symmetric RX/TX sublink speed of 10 Gbps. + */ +- ssp_cap->bmSublinkSpeedAttr[0] = +- cpu_to_le32((3 << 4) | (1 << 14) | (0xa << 16)); +- /* +- * bmSublinkSpeedAttr[1] = +- * ST = Symmetric, TX +- * LSE = 3 (Gbps) +- * LP = 1 (SuperSpeedPlus) +- * LSM = 10 (10 Gbps) +- */ +- ssp_cap->bmSublinkSpeedAttr[1] = +- cpu_to_le32((3 << 4) | (1 << 14) | +- (0xa << 16) | (1 << 7)); ++ for (i = 0; i < ssac + 1; i++) { ++ u8 ssid; ++ u8 mantissa; ++ u8 type; ++ ++ ssid = i >> 1; ++ ++ if (cdev->gadget->max_ssp_rate == USB_SSP_GEN_2x1 || ++ cdev->gadget->max_ssp_rate == USB_SSP_GEN_UNKNOWN) ++ mantissa = 10; ++ else ++ mantissa = 5 << ssid; ++ ++ if (i % 2) ++ type = USB_SSP_SUBLINK_SPEED_ST_SYM_TX; ++ else ++ type = USB_SSP_SUBLINK_SPEED_ST_SYM_RX; ++ ++ ssp_cap->bmSublinkSpeedAttr[i] = ++ cpu_to_le32(FIELD_PREP(USB_SSP_SUBLINK_SPEED_SSID, ssid) | ++ FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSE, ++ USB_SSP_SUBLINK_SPEED_LSE_GBPS) | ++ FIELD_PREP(USB_SSP_SUBLINK_SPEED_ST, type) | ++ FIELD_PREP(USB_SSP_SUBLINK_SPEED_LP, ++ USB_SSP_SUBLINK_SPEED_LP_SSP) | ++ FIELD_PREP(USB_SSP_SUBLINK_SPEED_LSM, mantissa)); ++ } + } + + return le16_to_cpu(bos->wTotalLength); +@@ -1648,18 +1679,6 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) + struct usb_function *f = NULL; + u8 endp; + +- if (w_length > USB_COMP_EP0_BUFSIZ) { +- if (ctrl->bRequestType & USB_DIR_IN) { +- /* Cast away the const, we are going to overwrite on purpose. */ +- __le16 *temp = (__le16 *)&ctrl->wLength; +- +- *temp = cpu_to_le16(USB_COMP_EP0_BUFSIZ); +- w_length = USB_COMP_EP0_BUFSIZ; +- } else { +- goto done; +- } +- } +- + /* partial re-init of the response message; the function or the + * gadget might need to intercept e.g. a control-OUT completion + * when we delegate to it. +@@ -1944,9 +1963,6 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) + if (w_index != 0x5 || (w_value >> 8)) + break; + interface = w_value & 0xFF; +- if (interface >= MAX_CONFIG_INTERFACES || +- !os_desc_cfg->interface[interface]) +- break; + buf[6] = w_index; + count = count_ext_prop(os_desc_cfg, + interface); +@@ -2176,7 +2192,7 @@ int composite_dev_prepare(struct usb_composite_driver *composite, + if (!cdev->req) + return -ENOMEM; + +- cdev->req->buf = kzalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL); ++ cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL); + if (!cdev->req->buf) + goto fail; + +diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c +index d51ea1c05..576490f78 100644 +--- a/drivers/usb/gadget/configfs.c ++++ b/drivers/usb/gadget/configfs.c +@@ -10,6 +10,13 @@ + #include "u_f.h" + #include "u_os_desc.h" + ++#include ++#include ++ ++static struct class *android_class; ++static struct device *android_device; ++ ++ + int check_user_usb_string(const char *name, + struct usb_gadget_strings *stringtab_dev) + { +@@ -51,6 +58,7 @@ struct gadget_info { + char qw_sign[OS_STRING_QW_SIGN_LEN]; + spinlock_t spinlock; + bool unbind; ++ bool connected; + }; + + static inline struct gadget_info *to_gadget_info(struct config_item *item) +@@ -1404,6 +1412,10 @@ static int configfs_composite_bind(struct usb_gadget *gadget, + goto err_purge_funcs; + } + } ++ ret = usb_gadget_check_config(cdev->gadget); ++ if (ret) ++ goto err_purge_funcs; ++ + usb_ep_autoconfig_reset(cdev->gadget); + } + if (cdev->use_os_string) { +@@ -1449,6 +1461,52 @@ static void configfs_composite_unbind(struct usb_gadget *gadget) + spin_unlock_irqrestore(&gi->spinlock, flags); + } + ++static void configfs_uevent_report(struct usb_gadget *gadget, enum usb_device_state s) ++{ ++#ifdef CONFIG_CONFIGFS_UEVENT_REPORT ++ struct usb_composite_dev *cdev; ++ char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL }; ++ char *connected[2] = { "USB_STATE=CONNECTED", NULL }; ++ char *configured[2] = { "USB_STATE=CONFIGURED", NULL }; ++ /* 0-connected 1-configured 2-disconnected*/ ++ bool status[3] = { false, false, false }; ++ bool uevent_sent = false; ++ ++ cdev = get_gadget_data(gadget); ++ ++ if(s == USB_STATE_ATTACHED) { ++ status[0] = true; ++ } else if(s == USB_STATE_CONFIGURED) { ++ status[1] = true; ++ } else if(s == USB_STATE_NOTATTACHED) { ++ status[2] = true; ++ } else { ++ /*Invalid Status.*/ ++ } ++ ++ if (status[0]) { ++ kobject_uevent_env(&android_device->kobj, ++ KOBJ_CHANGE, connected); ++ pr_info("%s: sent uevent %s\n", __func__, connected[0]); ++ uevent_sent = true; ++ } ++ ++ if (status[1]) { ++ kobject_uevent_env(&android_device->kobj, ++ KOBJ_CHANGE, configured); ++ pr_info("%s: sent uevent %s\n", __func__, configured[0]); ++ uevent_sent = true; ++ } ++ ++ if (status[2]) { ++ kobject_uevent_env(&android_device->kobj, ++ KOBJ_CHANGE, disconnected); ++ pr_info("%s: sent uevent %s\n", __func__, disconnected[0]); ++ uevent_sent = true; ++ } ++#endif ++} ++ + static int configfs_composite_setup(struct usb_gadget *gadget, + const struct usb_ctrlrequest *ctrl) + { +@@ -1469,7 +1527,15 @@ static int configfs_composite_setup(struct usb_gadget *gadget, + return 0; + } + ++ if(!gi->connected) { ++ configfs_uevent_report(gadget, USB_STATE_ATTACHED); ++ gi->connected = 1; ++ } ++ + ret = composite_setup(gadget, ctrl); ++ if((ctrl->bRequest == USB_REQ_SET_CONFIGURATION) && cdev->config) { ++ configfs_uevent_report(gadget, USB_STATE_CONFIGURED); ++ } + spin_unlock_irqrestore(&gi->spinlock, flags); + return ret; + } +@@ -1493,6 +1559,11 @@ static void configfs_composite_disconnect(struct usb_gadget *gadget) + } + + composite_disconnect(gadget); ++ ++ configfs_uevent_report(gadget, USB_STATE_NOTATTACHED); ++ ++ gi->connected = 0; ++ + spin_unlock_irqrestore(&gi->spinlock, flags); + } + +@@ -1559,6 +1630,79 @@ static const struct usb_gadget_driver configfs_driver_template = { + .match_existing_only = 1, + }; + ++static ssize_t state_show(struct device *pdev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct gadget_info *gi = dev_get_drvdata(pdev); ++ struct usb_composite_dev *cdev; ++ char *state = "DISCONNECTED"; ++ unsigned long flags; ++ ++ if (!gi) ++ goto out; ++ ++ cdev = &gi->cdev; ++ ++ if (!cdev) ++ goto out; ++ ++ spin_lock_irqsave(&gi->spinlock, flags); ++ if (cdev->config) ++ state = "CONFIGURED"; ++ else if (gi->connected) ++ state = "CONNECTED"; ++ spin_unlock_irqrestore(&gi->spinlock, flags); ++out: ++ return sprintf(buf, "%s\n", state); ++} ++ ++static DEVICE_ATTR(state, S_IRUGO, state_show, NULL); ++ ++static struct device_attribute *android_usb_attributes[] = { ++ &dev_attr_state, ++ NULL ++}; ++ ++static int android_device_create(struct gadget_info *gi) ++{ ++ struct device_attribute **attrs; ++ struct device_attribute *attr; ++ ++ android_device = device_create(android_class, NULL, ++ MKDEV(0, 0), NULL, "android0"); ++ if (IS_ERR(android_device)) ++ return PTR_ERR(android_device); ++ ++ dev_set_drvdata(android_device, gi); ++ ++ attrs = android_usb_attributes; ++ while ((attr = *attrs++)) { ++ int err; ++ ++ err = device_create_file(android_device, attr); ++ if (err) { ++ device_destroy(android_device->class, ++ android_device->devt); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++static void android_device_destroy(void) ++{ ++ struct device_attribute **attrs; ++ struct device_attribute *attr; ++ ++ attrs = android_usb_attributes; ++ while ((attr = *attrs++)) ++ device_remove_file(android_device, attr); ++ device_destroy(android_device->class, android_device->devt); ++} ++ ++ ++ + static struct config_group *gadgets_make( + struct config_group *group, + const char *name) +@@ -1611,6 +1755,9 @@ static struct config_group *gadgets_make( + if (!gi->composite.gadget_driver.function) + goto err; + ++ if (android_device_create(gi) < 0) ++ goto err; ++ + return &gi->group; + err: + kfree(gi); +@@ -1620,6 +1767,7 @@ static struct config_group *gadgets_make( + static void gadgets_drop(struct config_group *group, struct config_item *item) + { + config_item_put(item); ++ android_device_destroy(); + } + + static struct configfs_group_operations gadgets_ops = { +@@ -1659,6 +1807,11 @@ static int __init gadget_cfs_init(void) + config_group_init(&gadget_subsys.su_group); + + ret = configfs_register_subsystem(&gadget_subsys); ++ ++ android_class = class_create(THIS_MODULE, "android_usb"); ++ if (IS_ERR(android_class)) ++ return PTR_ERR(android_class); ++ + return ret; + } + module_init(gadget_cfs_init); +@@ -1666,5 +1819,9 @@ module_init(gadget_cfs_init); + static void __exit gadget_cfs_exit(void) + { + configfs_unregister_subsystem(&gadget_subsys); ++ ++ if (!IS_ERR(android_class)) ++ class_destroy(android_class); ++ + } + module_exit(gadget_cfs_exit); +diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile +index 5d3a6cf02..346f460a1 100644 +--- a/drivers/usb/gadget/function/Makefile ++++ b/drivers/usb/gadget/function/Makefile +@@ -50,3 +50,7 @@ usb_f_printer-y := f_printer.o + obj-$(CONFIG_USB_F_PRINTER) += usb_f_printer.o + usb_f_tcm-y := f_tcm.o + obj-$(CONFIG_USB_F_TCM) += usb_f_tcm.o ++usb_f_mtp-y := f_mtp.o ++obj-$(CONFIG_USB_F_MTP) += usb_f_mtp.o ++usb_f_ptp-y := f_ptp.o ++obj-$(CONFIG_USB_F_PTP) += usb_f_ptp.o +diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c +index bb0d92837..8042d812b 100644 +--- a/drivers/usb/gadget/function/f_fs.c ++++ b/drivers/usb/gadget/function/f_fs.c +@@ -614,7 +614,7 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) + file->private_data = ffs; + ffs_data_opened(ffs); + +- return stream_open(inode, file); ++ return 0; + } + + static int ffs_ep0_release(struct inode *inode, struct file *file) +@@ -1152,7 +1152,7 @@ ffs_epfile_open(struct inode *inode, struct file *file) + file->private_data = epfile; + ffs_data_opened(epfile->ffs); + +- return stream_open(inode, file); ++ return 0; + } + + static int ffs_aio_cancel(struct kiocb *kiocb) +@@ -1562,13 +1562,13 @@ static int ffs_fs_get_tree(struct fs_context *fc) + return invalf(fc, "No source specified"); + + ffs = ffs_data_new(fc->source); +- if (unlikely(!ffs)) ++ if (!ffs) + return -ENOMEM; + ffs->file_perms = ctx->perms; + ffs->no_disconnect = ctx->no_disconnect; + + ffs->dev_name = kstrdup(fc->source, GFP_KERNEL); +- if (unlikely(!ffs->dev_name)) { ++ if (!ffs->dev_name) { + ffs_data_put(ffs); + return -ENOMEM; + } +@@ -1814,6 +1814,7 @@ static void ffs_data_reset(struct ffs_data *ffs) + + ffs_data_clear(ffs); + ++ ffs->epfiles = NULL; + ffs->raw_descs_data = NULL; + ffs->raw_descs = NULL; + ffs->raw_strings = NULL; +diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c +index 6742271cd..ddccfa8fc 100644 +--- a/drivers/usb/gadget/function/f_hid.c ++++ b/drivers/usb/gadget/function/f_hid.c +@@ -45,12 +45,25 @@ struct f_hidg { + unsigned short report_desc_length; + char *report_desc; + unsigned short report_length; ++ /* ++ * use_out_ep - if true, the OUT Endpoint (interrupt out method) ++ * will be used to receive reports from the host ++ * using functions with the "intout" suffix. ++ * Otherwise, the OUT Endpoint will not be configured ++ * and the SETUP/SET_REPORT method ("ssreport" suffix) ++ * will be used to receive reports. ++ */ ++ bool use_out_ep; + + /* recv report */ +- struct list_head completed_out_req; + spinlock_t read_spinlock; + wait_queue_head_t read_queue; ++ /* recv report - interrupt out only (use_out_ep == 1) */ ++ struct list_head completed_out_req; + unsigned int qlen; ++ /* recv report - setup set_report only (use_out_ep == 0) */ ++ char *set_report_buf; ++ unsigned int set_report_length; + + /* send report */ + spinlock_t write_spinlock; +@@ -79,7 +92,7 @@ static struct usb_interface_descriptor hidg_interface_desc = { + .bDescriptorType = USB_DT_INTERFACE, + /* .bInterfaceNumber = DYNAMIC */ + .bAlternateSetting = 0, +- .bNumEndpoints = 2, ++ /* .bNumEndpoints = DYNAMIC (depends on use_out_ep) */ + .bInterfaceClass = USB_CLASS_HID, + /* .bInterfaceSubClass = DYNAMIC */ + /* .bInterfaceProtocol = DYNAMIC */ +@@ -140,7 +153,7 @@ static struct usb_ss_ep_comp_descriptor hidg_ss_out_comp_desc = { + /* .wBytesPerInterval = DYNAMIC */ + }; + +-static struct usb_descriptor_header *hidg_ss_descriptors[] = { ++static struct usb_descriptor_header *hidg_ss_descriptors_intout[] = { + (struct usb_descriptor_header *)&hidg_interface_desc, + (struct usb_descriptor_header *)&hidg_desc, + (struct usb_descriptor_header *)&hidg_ss_in_ep_desc, +@@ -150,6 +163,14 @@ static struct usb_descriptor_header *hidg_ss_descriptors[] = { + NULL, + }; + ++static struct usb_descriptor_header *hidg_ss_descriptors_ssreport[] = { ++ (struct usb_descriptor_header *)&hidg_interface_desc, ++ (struct usb_descriptor_header *)&hidg_desc, ++ (struct usb_descriptor_header *)&hidg_ss_in_ep_desc, ++ (struct usb_descriptor_header *)&hidg_ss_in_comp_desc, ++ NULL, ++}; ++ + /* High-Speed Support */ + + static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = { +@@ -176,7 +197,7 @@ static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = { + */ + }; + +-static struct usb_descriptor_header *hidg_hs_descriptors[] = { ++static struct usb_descriptor_header *hidg_hs_descriptors_intout[] = { + (struct usb_descriptor_header *)&hidg_interface_desc, + (struct usb_descriptor_header *)&hidg_desc, + (struct usb_descriptor_header *)&hidg_hs_in_ep_desc, +@@ -184,6 +205,13 @@ static struct usb_descriptor_header *hidg_hs_descriptors[] = { + NULL, + }; + ++static struct usb_descriptor_header *hidg_hs_descriptors_ssreport[] = { ++ (struct usb_descriptor_header *)&hidg_interface_desc, ++ (struct usb_descriptor_header *)&hidg_desc, ++ (struct usb_descriptor_header *)&hidg_hs_in_ep_desc, ++ NULL, ++}; ++ + /* Full-Speed Support */ + + static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = { +@@ -210,7 +238,7 @@ static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = { + */ + }; + +-static struct usb_descriptor_header *hidg_fs_descriptors[] = { ++static struct usb_descriptor_header *hidg_fs_descriptors_intout[] = { + (struct usb_descriptor_header *)&hidg_interface_desc, + (struct usb_descriptor_header *)&hidg_desc, + (struct usb_descriptor_header *)&hidg_fs_in_ep_desc, +@@ -218,6 +246,13 @@ static struct usb_descriptor_header *hidg_fs_descriptors[] = { + NULL, + }; + ++static struct usb_descriptor_header *hidg_fs_descriptors_ssreport[] = { ++ (struct usb_descriptor_header *)&hidg_interface_desc, ++ (struct usb_descriptor_header *)&hidg_desc, ++ (struct usb_descriptor_header *)&hidg_fs_in_ep_desc, ++ NULL, ++}; ++ + /*-------------------------------------------------------------------------*/ + /* Strings */ + +@@ -241,8 +276,8 @@ static struct usb_gadget_strings *ct_func_strings[] = { + /*-------------------------------------------------------------------------*/ + /* Char Device */ + +-static ssize_t f_hidg_read(struct file *file, char __user *buffer, +- size_t count, loff_t *ptr) ++static ssize_t f_hidg_intout_read(struct file *file, char __user *buffer, ++ size_t count, loff_t *ptr) + { + struct f_hidg *hidg = file->private_data; + struct f_hidg_req_list *list; +@@ -255,15 +290,15 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, + + spin_lock_irqsave(&hidg->read_spinlock, flags); + +-#define READ_COND (!list_empty(&hidg->completed_out_req)) ++#define READ_COND_INTOUT (!list_empty(&hidg->completed_out_req)) + + /* wait for at least one buffer to complete */ +- while (!READ_COND) { ++ while (!READ_COND_INTOUT) { + spin_unlock_irqrestore(&hidg->read_spinlock, flags); + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + +- if (wait_event_interruptible(hidg->read_queue, READ_COND)) ++ if (wait_event_interruptible(hidg->read_queue, READ_COND_INTOUT)) + return -ERESTARTSYS; + + spin_lock_irqsave(&hidg->read_spinlock, flags); +@@ -313,6 +348,60 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, + return count; + } + ++#define READ_COND_SSREPORT (hidg->set_report_buf != NULL) ++ ++static ssize_t f_hidg_ssreport_read(struct file *file, char __user *buffer, ++ size_t count, loff_t *ptr) ++{ ++ struct f_hidg *hidg = file->private_data; ++ char *tmp_buf = NULL; ++ unsigned long flags; ++ ++ if (!count) ++ return 0; ++ ++ spin_lock_irqsave(&hidg->read_spinlock, flags); ++ ++ while (!READ_COND_SSREPORT) { ++ spin_unlock_irqrestore(&hidg->read_spinlock, flags); ++ if (file->f_flags & O_NONBLOCK) ++ return -EAGAIN; ++ ++ if (wait_event_interruptible(hidg->read_queue, READ_COND_SSREPORT)) ++ return -ERESTARTSYS; ++ ++ spin_lock_irqsave(&hidg->read_spinlock, flags); ++ } ++ ++ count = min_t(unsigned int, count, hidg->set_report_length); ++ tmp_buf = hidg->set_report_buf; ++ hidg->set_report_buf = NULL; ++ ++ spin_unlock_irqrestore(&hidg->read_spinlock, flags); ++ ++ if (tmp_buf != NULL) { ++ count -= copy_to_user(buffer, tmp_buf, count); ++ kfree(tmp_buf); ++ } else { ++ count = -ENOMEM; ++ } ++ ++ wake_up(&hidg->read_queue); ++ ++ return count; ++} ++ ++static ssize_t f_hidg_read(struct file *file, char __user *buffer, ++ size_t count, loff_t *ptr) ++{ ++ struct f_hidg *hidg = file->private_data; ++ ++ if (hidg->use_out_ep) ++ return f_hidg_intout_read(file, buffer, count, ptr); ++ else ++ return f_hidg_ssreport_read(file, buffer, count, ptr); ++} ++ + static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req) + { + struct f_hidg *hidg = (struct f_hidg *)ep->driver_data; +@@ -433,14 +522,20 @@ static __poll_t f_hidg_poll(struct file *file, poll_table *wait) + if (WRITE_COND) + ret |= EPOLLOUT | EPOLLWRNORM; + +- if (READ_COND) +- ret |= EPOLLIN | EPOLLRDNORM; ++ if (hidg->use_out_ep) { ++ if (READ_COND_INTOUT) ++ ret |= EPOLLIN | EPOLLRDNORM; ++ } else { ++ if (READ_COND_SSREPORT) ++ ret |= EPOLLIN | EPOLLRDNORM; ++ } + + return ret; + } + + #undef WRITE_COND +-#undef READ_COND ++#undef READ_COND_SSREPORT ++#undef READ_COND_INTOUT + + static int f_hidg_release(struct inode *inode, struct file *fd) + { +@@ -467,7 +562,7 @@ static inline struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, + return alloc_ep_req(ep, length); + } + +-static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) ++static void hidg_intout_complete(struct usb_ep *ep, struct usb_request *req) + { + struct f_hidg *hidg = (struct f_hidg *) req->context; + struct usb_composite_dev *cdev = hidg->func.config->cdev; +@@ -502,6 +597,37 @@ static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) + } + } + ++static void hidg_ssreport_complete(struct usb_ep *ep, struct usb_request *req) ++{ ++ struct f_hidg *hidg = (struct f_hidg *)req->context; ++ struct usb_composite_dev *cdev = hidg->func.config->cdev; ++ char *new_buf = NULL; ++ unsigned long flags; ++ ++ if (req->status != 0 || req->buf == NULL || req->actual == 0) { ++ ERROR(cdev, ++ "%s FAILED: status=%d, buf=%p, actual=%d\n", ++ __func__, req->status, req->buf, req->actual); ++ return; ++ } ++ ++ spin_lock_irqsave(&hidg->read_spinlock, flags); ++ ++ new_buf = krealloc(hidg->set_report_buf, req->actual, GFP_ATOMIC); ++ if (new_buf == NULL) { ++ spin_unlock_irqrestore(&hidg->read_spinlock, flags); ++ return; ++ } ++ hidg->set_report_buf = new_buf; ++ ++ hidg->set_report_length = req->actual; ++ memcpy(hidg->set_report_buf, req->buf, req->actual); ++ ++ spin_unlock_irqrestore(&hidg->read_spinlock, flags); ++ ++ wake_up(&hidg->read_queue); ++} ++ + static int hidg_setup(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) + { +@@ -549,7 +675,11 @@ static int hidg_setup(struct usb_function *f, + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 + | HID_REQ_SET_REPORT): + VDBG(cdev, "set_report | wLength=%d\n", ctrl->wLength); +- goto stall; ++ if (hidg->use_out_ep) ++ goto stall; ++ req->complete = hidg_ssreport_complete; ++ req->context = hidg; ++ goto respond; + break; + + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 +@@ -637,15 +767,18 @@ static void hidg_disable(struct usb_function *f) + unsigned long flags; + + usb_ep_disable(hidg->in_ep); +- usb_ep_disable(hidg->out_ep); + +- spin_lock_irqsave(&hidg->read_spinlock, flags); +- list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) { +- free_ep_req(hidg->out_ep, list->req); +- list_del(&list->list); +- kfree(list); ++ if (hidg->out_ep) { ++ usb_ep_disable(hidg->out_ep); ++ ++ spin_lock_irqsave(&hidg->read_spinlock, flags); ++ list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) { ++ free_ep_req(hidg->out_ep, list->req); ++ list_del(&list->list); ++ kfree(list); ++ } ++ spin_unlock_irqrestore(&hidg->read_spinlock, flags); + } +- spin_unlock_irqrestore(&hidg->read_spinlock, flags); + + spin_lock_irqsave(&hidg->write_spinlock, flags); + if (!hidg->write_pending) { +@@ -691,8 +824,7 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + } + } + +- +- if (hidg->out_ep != NULL) { ++ if (hidg->use_out_ep && hidg->out_ep != NULL) { + /* restart endpoint */ + usb_ep_disable(hidg->out_ep); + +@@ -717,7 +849,7 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + hidg_alloc_ep_req(hidg->out_ep, + hidg->report_length); + if (req) { +- req->complete = hidg_set_report_complete; ++ req->complete = hidg_intout_complete; + req->context = hidg; + status = usb_ep_queue(hidg->out_ep, req, + GFP_ATOMIC); +@@ -743,7 +875,8 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + } + return 0; + disable_out_ep: +- usb_ep_disable(hidg->out_ep); ++ if (hidg->out_ep) ++ usb_ep_disable(hidg->out_ep); + free_req_in: + if (req_in) + free_ep_req(hidg->in_ep, req_in); +@@ -795,14 +928,21 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) + goto fail; + hidg->in_ep = ep; + +- ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc); +- if (!ep) +- goto fail; +- hidg->out_ep = ep; ++ hidg->out_ep = NULL; ++ if (hidg->use_out_ep) { ++ ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc); ++ if (!ep) ++ goto fail; ++ hidg->out_ep = ep; ++ } ++ ++ /* used only if use_out_ep == 1 */ ++ hidg->set_report_buf = NULL; + + /* set descriptor dynamic values */ + hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass; + hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol; ++ hidg_interface_desc.bNumEndpoints = hidg->use_out_ep ? 2 : 1; + hidg->protocol = HID_REPORT_PROTOCOL; + hidg->idle = 1; + hidg_ss_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); +@@ -833,9 +973,19 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) + hidg_ss_out_ep_desc.bEndpointAddress = + hidg_fs_out_ep_desc.bEndpointAddress; + +- status = usb_assign_descriptors(f, hidg_fs_descriptors, +- hidg_hs_descriptors, hidg_ss_descriptors, +- hidg_ss_descriptors); ++ if (hidg->use_out_ep) ++ status = usb_assign_descriptors(f, ++ hidg_fs_descriptors_intout, ++ hidg_hs_descriptors_intout, ++ hidg_ss_descriptors_intout, ++ hidg_ss_descriptors_intout); ++ else ++ status = usb_assign_descriptors(f, ++ hidg_fs_descriptors_ssreport, ++ hidg_hs_descriptors_ssreport, ++ hidg_ss_descriptors_ssreport, ++ hidg_ss_descriptors_ssreport); ++ + if (status) + goto fail; + +@@ -950,6 +1100,7 @@ CONFIGFS_ATTR(f_hid_opts_, name) + + F_HID_OPT(subclass, 8, 255); + F_HID_OPT(protocol, 8, 255); ++F_HID_OPT(no_out_endpoint, 8, 1); + F_HID_OPT(report_length, 16, 65535); + + static ssize_t f_hid_opts_report_desc_show(struct config_item *item, char *page) +@@ -1009,6 +1160,7 @@ CONFIGFS_ATTR_RO(f_hid_opts_, dev); + static struct configfs_attribute *hid_attrs[] = { + &f_hid_opts_attr_subclass, + &f_hid_opts_attr_protocol, ++ &f_hid_opts_attr_no_out_endpoint, + &f_hid_opts_attr_report_length, + &f_hid_opts_attr_report_desc, + &f_hid_opts_attr_dev, +@@ -1093,6 +1245,7 @@ static void hidg_free(struct usb_function *f) + hidg = func_to_hidg(f); + opts = container_of(f->fi, struct f_hid_opts, func_inst); + kfree(hidg->report_desc); ++ kfree(hidg->set_report_buf); + kfree(hidg); + mutex_lock(&opts->lock); + --opts->refcnt; +@@ -1139,6 +1292,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi) + return ERR_PTR(-ENOMEM); + } + } ++ hidg->use_out_ep = !opts->no_out_endpoint; + + mutex_unlock(&opts->lock); + +@@ -1150,7 +1304,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi) + hidg->func.setup = hidg_setup; + hidg->func.free_func = hidg_free; + +- /* this could me made configurable at some point */ ++ /* this could be made configurable at some point */ + hidg->qlen = 4; + + return &hidg->func; +@@ -1194,4 +1348,4 @@ void ghid_cleanup(void) + + class_destroy(hidg_class); + hidg_class = NULL; +-} ++} +\ No newline at end of file +diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c +index 950c9435b..665a97496 100644 +--- a/drivers/usb/gadget/function/f_mass_storage.c ++++ b/drivers/usb/gadget/function/f_mass_storage.c +@@ -6,36 +6,6 @@ + * Copyright (C) 2009 Samsung Electronics + * Author: Michal Nazarewicz + * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions, and the following disclaimer, +- * without modification. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 3. The names of the above-listed copyright holders may not be used +- * to endorse or promote products derived from this software without +- * specific prior written permission. +- * +- * ALTERNATIVELY, this software may be distributed under the terms of the +- * GNU General Public License ("GPL") as published by the Free Software +- * Foundation, either version 2 of that License or (at your option) any +- * later version. +- * +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /* +@@ -351,8 +321,6 @@ static inline struct fsg_dev *fsg_from_func(struct usb_function *f) + return container_of(f, struct fsg_dev, function); + } + +-typedef void (*fsg_routine_t)(struct fsg_dev *); +- + static int exception_in_progress(struct fsg_common *common) + { + return common->state > FSG_STATE_NORMAL; +@@ -3473,4 +3441,4 @@ void fsg_config_from_params(struct fsg_config *cfg, + cfg->can_stall = params->stall; + cfg->fsg_num_buffers = fsg_num_buffers; + } +-EXPORT_SYMBOL_GPL(fsg_config_from_params); ++EXPORT_SYMBOL_GPL(fsg_config_from_params); +\ No newline at end of file +diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c +index 8fff995b8..71a1a26e8 100644 +--- a/drivers/usb/gadget/function/f_midi.c ++++ b/drivers/usb/gadget/function/f_midi.c +@@ -87,7 +87,7 @@ struct f_midi { + struct snd_rawmidi_substream *out_substream[MAX_PORTS]; + + unsigned long out_triggered; +- struct tasklet_struct tasklet; ++ struct work_struct work; + unsigned int in_ports; + unsigned int out_ports; + int index; +@@ -698,9 +698,11 @@ static void f_midi_transmit(struct f_midi *midi) + f_midi_drop_out_substreams(midi); + } + +-static void f_midi_in_tasklet(struct tasklet_struct *t) ++static void f_midi_in_work(struct work_struct *work) + { +- struct f_midi *midi = from_tasklet(midi, t, tasklet); ++ struct f_midi *midi; ++ ++ midi = container_of(work, struct f_midi, work); + f_midi_transmit(midi); + } + +@@ -737,7 +739,7 @@ static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up) + VDBG(midi, "%s() %d\n", __func__, up); + midi->in_ports_array[substream->number].active = up; + if (up) +- tasklet_hi_schedule(&midi->tasklet); ++ queue_work(system_highpri_wq, &midi->work); + } + + static int f_midi_out_open(struct snd_rawmidi_substream *substream) +@@ -875,7 +877,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) + int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0; + + midi->gadget = cdev->gadget; +- tasklet_setup(&midi->tasklet, f_midi_in_tasklet); ++ INIT_WORK(&midi->work, f_midi_in_work); + status = f_midi_register_card(midi); + if (status < 0) + goto fail_register; +diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c +new file mode 100755 +index 000000000..133dcfaca +--- /dev/null ++++ b/drivers/usb/gadget/function/f_mtp.c +@@ -0,0 +1,1536 @@ ++/* ++ * Gadget Function Driver for MTP ++ * ++ * Copyright (C) 2010 Google, Inc. ++ * Author: Mike Lockwood ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++/* #define DEBUG */ ++/* #define VERBOSE_DEBUG */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "configfs.h" ++ ++#define MTP_BULK_BUFFER_SIZE 16384 ++#define INTR_BUFFER_SIZE 28 ++#define MAX_INST_NAME_LEN 40 ++ ++/* String IDs */ ++#define INTERFACE_STRING_INDEX 0 ++ ++/* values for mtp_dev.state */ ++#define STATE_OFFLINE 0 /* initial state, disconnected */ ++#define STATE_READY 1 /* ready for userspace calls */ ++#define STATE_BUSY 2 /* processing userspace calls */ ++#define STATE_CANCELED 3 /* transaction canceled by host */ ++#define STATE_ERROR 4 /* error from completion routine */ ++ ++/* number of tx and rx requests to allocate */ ++#define TX_REQ_MAX 4 ++#define RX_REQ_MAX 2 ++#define INTR_REQ_MAX 5 ++ ++/* ID for Microsoft MTP OS String */ ++#define MTP_OS_STRING_ID 0xEE ++ ++/* MTP class reqeusts */ ++#define MTP_REQ_CANCEL 0x64 ++#define MTP_REQ_GET_EXT_EVENT_DATA 0x65 ++#define MTP_REQ_RESET 0x66 ++#define MTP_REQ_GET_DEVICE_STATUS 0x67 ++ ++/* constants for device status */ ++#define MTP_RESPONSE_OK 0x2001 ++#define MTP_RESPONSE_DEVICE_BUSY 0x2019 ++#define DRIVER_NAME "mtp" ++ ++static const char mtp_shortname[] = DRIVER_NAME "_usb"; ++ ++struct mtp_dev { ++ struct usb_function function; ++ struct usb_composite_dev *cdev; ++ spinlock_t lock; ++ ++ struct usb_ep *ep_in; ++ struct usb_ep *ep_out; ++ struct usb_ep *ep_intr; ++ ++ int state; ++ ++ /* synchronize access to our device file */ ++ atomic_t open_excl; ++ /* to enforce only one ioctl at a time */ ++ atomic_t ioctl_excl; ++ ++ struct list_head tx_idle; ++ struct list_head intr_idle; ++ ++ wait_queue_head_t read_wq; ++ wait_queue_head_t write_wq; ++ wait_queue_head_t intr_wq; ++ struct usb_request *rx_req[RX_REQ_MAX]; ++ int rx_done; ++ ++ /* for processing MTP_SEND_FILE, MTP_RECEIVE_FILE and ++ * MTP_SEND_FILE_WITH_HEADER ioctls on a work queue ++ */ ++ struct workqueue_struct *wq; ++ struct work_struct send_file_work; ++ struct work_struct receive_file_work; ++ struct file *xfer_file; ++ loff_t xfer_file_offset; ++ int64_t xfer_file_length; ++ unsigned xfer_send_header; ++ uint16_t xfer_command; ++ uint32_t xfer_transaction_id; ++ int xfer_result; ++}; ++ ++static struct usb_interface_descriptor mtp_interface_desc = { ++ .bLength = USB_DT_INTERFACE_SIZE, ++ .bDescriptorType = USB_DT_INTERFACE, ++ .bInterfaceNumber = 0, ++ .bNumEndpoints = 3, ++ .bInterfaceClass = USB_CLASS_STILL_IMAGE, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 1, ++}; ++ ++static struct usb_interface_descriptor ptp_interface_desc = { ++ .bLength = USB_DT_INTERFACE_SIZE, ++ .bDescriptorType = USB_DT_INTERFACE, ++ .bInterfaceNumber = 0, ++ .bNumEndpoints = 3, ++ .bInterfaceClass = USB_CLASS_STILL_IMAGE, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 1, ++}; ++ ++static struct usb_endpoint_descriptor mtp_ss_in_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ .wMaxPacketSize = __constant_cpu_to_le16(1024), ++}; ++ ++static struct usb_ss_ep_comp_descriptor mtp_ss_in_comp_desc = { ++ .bLength = sizeof(mtp_ss_in_comp_desc), ++ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, ++ /* .bMaxBurst = DYNAMIC, */ ++}; ++ ++static struct usb_endpoint_descriptor mtp_ss_out_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ .bEndpointAddress = USB_DIR_OUT, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ .wMaxPacketSize = __constant_cpu_to_le16(1024), ++}; ++ ++static struct usb_ss_ep_comp_descriptor mtp_ss_out_comp_desc = { ++ .bLength = sizeof(mtp_ss_out_comp_desc), ++ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, ++ /* .bMaxBurst = DYNAMIC, */ ++}; ++ ++static struct usb_endpoint_descriptor mtp_highspeed_in_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ .wMaxPacketSize = __constant_cpu_to_le16(512), ++}; ++ ++static struct usb_endpoint_descriptor mtp_highspeed_out_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ .bEndpointAddress = USB_DIR_OUT, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ .wMaxPacketSize = __constant_cpu_to_le16(512), ++}; ++ ++static struct usb_endpoint_descriptor mtp_fullspeed_in_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++}; ++ ++static struct usb_endpoint_descriptor mtp_fullspeed_out_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ .bEndpointAddress = USB_DIR_OUT, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++}; ++ ++static struct usb_endpoint_descriptor mtp_intr_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_INT, ++ .wMaxPacketSize = __constant_cpu_to_le16(INTR_BUFFER_SIZE), ++ .bInterval = 6, ++}; ++ ++static struct usb_ss_ep_comp_descriptor mtp_intr_ss_comp_desc = { ++ .bLength = sizeof(mtp_intr_ss_comp_desc), ++ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, ++ .wBytesPerInterval = cpu_to_le16(INTR_BUFFER_SIZE), ++}; ++ ++static struct usb_descriptor_header *fs_mtp_descs[] = { ++ (struct usb_descriptor_header *) &mtp_interface_desc, ++ (struct usb_descriptor_header *) &mtp_fullspeed_in_desc, ++ (struct usb_descriptor_header *) &mtp_fullspeed_out_desc, ++ (struct usb_descriptor_header *) &mtp_intr_desc, ++ NULL, ++}; ++ ++static struct usb_descriptor_header *hs_mtp_descs[] = { ++ (struct usb_descriptor_header *) &mtp_interface_desc, ++ (struct usb_descriptor_header *) &mtp_highspeed_in_desc, ++ (struct usb_descriptor_header *) &mtp_highspeed_out_desc, ++ (struct usb_descriptor_header *) &mtp_intr_desc, ++ NULL, ++}; ++ ++static struct usb_descriptor_header *ss_mtp_descs[] = { ++ (struct usb_descriptor_header *) &mtp_interface_desc, ++ (struct usb_descriptor_header *) &mtp_ss_in_desc, ++ (struct usb_descriptor_header *) &mtp_ss_in_comp_desc, ++ (struct usb_descriptor_header *) &mtp_ss_out_desc, ++ (struct usb_descriptor_header *) &mtp_ss_out_comp_desc, ++ (struct usb_descriptor_header *) &mtp_intr_desc, ++ (struct usb_descriptor_header *) &mtp_intr_ss_comp_desc, ++ NULL, ++}; ++ ++static struct usb_descriptor_header *fs_ptp_descs[] = { ++ (struct usb_descriptor_header *) &ptp_interface_desc, ++ (struct usb_descriptor_header *) &mtp_fullspeed_in_desc, ++ (struct usb_descriptor_header *) &mtp_fullspeed_out_desc, ++ (struct usb_descriptor_header *) &mtp_intr_desc, ++ NULL, ++}; ++ ++static struct usb_descriptor_header *hs_ptp_descs[] = { ++ (struct usb_descriptor_header *) &ptp_interface_desc, ++ (struct usb_descriptor_header *) &mtp_highspeed_in_desc, ++ (struct usb_descriptor_header *) &mtp_highspeed_out_desc, ++ (struct usb_descriptor_header *) &mtp_intr_desc, ++ NULL, ++}; ++ ++static struct usb_descriptor_header *ss_ptp_descs[] = { ++ (struct usb_descriptor_header *) &ptp_interface_desc, ++ (struct usb_descriptor_header *) &mtp_ss_in_desc, ++ (struct usb_descriptor_header *) &mtp_ss_in_comp_desc, ++ (struct usb_descriptor_header *) &mtp_ss_out_desc, ++ (struct usb_descriptor_header *) &mtp_ss_out_comp_desc, ++ (struct usb_descriptor_header *) &mtp_intr_desc, ++ (struct usb_descriptor_header *) &mtp_intr_ss_comp_desc, ++ NULL, ++}; ++ ++static struct usb_string mtp_string_defs[] = { ++ /* Naming interface "MTP" so libmtp will recognize us */ ++ [INTERFACE_STRING_INDEX].s = "MTP", ++ { }, /* end of list */ ++}; ++ ++static struct usb_gadget_strings mtp_string_table = { ++ .language = 0x0409, /* en-US */ ++ .strings = mtp_string_defs, ++}; ++ ++static struct usb_gadget_strings *mtp_strings[] = { ++ &mtp_string_table, ++ NULL, ++}; ++ ++/* Microsoft MTP OS String */ ++static u8 mtp_os_string[] = { ++ 18, /* sizeof(mtp_os_string) */ ++ USB_DT_STRING, ++ /* Signature field: "MSFT100" */ ++ 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0, ++ /* vendor code */ ++ 1, ++ /* padding */ ++ 0 ++}; ++ ++/* Microsoft Extended Configuration Descriptor Header Section */ ++struct mtp_ext_config_desc_header { ++ __le32 dwLength; ++ __u16 bcdVersion; ++ __le16 wIndex; ++ __u8 bCount; ++ __u8 reserved[7]; ++}; ++ ++/* Microsoft Extended Configuration Descriptor Function Section */ ++struct mtp_ext_config_desc_function { ++ __u8 bFirstInterfaceNumber; ++ __u8 bInterfaceCount; ++ __u8 compatibleID[8]; ++ __u8 subCompatibleID[8]; ++ __u8 reserved[6]; ++}; ++ ++/* MTP Extended Configuration Descriptor */ ++struct { ++ struct mtp_ext_config_desc_header header; ++ struct mtp_ext_config_desc_function function; ++} mtp_ext_config_desc = { ++ .header = { ++ .dwLength = __constant_cpu_to_le32(sizeof(mtp_ext_config_desc)), ++ .bcdVersion = __constant_cpu_to_le16(0x0100), ++ .wIndex = __constant_cpu_to_le16(4), ++ .bCount = 1, ++ }, ++ .function = { ++ .bFirstInterfaceNumber = 0, ++ .bInterfaceCount = 1, ++ .compatibleID = { 'M', 'T', 'P' }, ++ }, ++}; ++ ++struct mtp_device_status { ++ __le16 wLength; ++ __le16 wCode; ++}; ++ ++struct mtp_data_header { ++ /* length of packet, including this header */ ++ __le32 length; ++ /* container type (2 for data packet) */ ++ __le16 type; ++ /* MTP command code */ ++ __le16 command; ++ /* MTP transaction ID */ ++ __le32 transaction_id; ++}; ++ ++struct mtp_instance { ++ struct usb_function_instance func_inst; ++ const char *name; ++ struct mtp_dev *dev; ++ char mtp_ext_compat_id[16]; ++ struct usb_os_desc mtp_os_desc; ++}; ++ ++/* temporary variable used between mtp_open() and mtp_gadget_bind() */ ++static struct mtp_dev *_mtp_dev; ++ ++static inline struct mtp_dev *func_to_mtp(struct usb_function *f) ++{ ++ return container_of(f, struct mtp_dev, function); ++} ++ ++static struct usb_request *mtp_request_new(struct usb_ep *ep, int buffer_size) ++{ ++ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); ++ ++ if (!req) ++ return NULL; ++ ++ /* now allocate buffers for the requests */ ++ req->buf = kmalloc(buffer_size, GFP_KERNEL); ++ if (!req->buf) { ++ usb_ep_free_request(ep, req); ++ return NULL; ++ } ++ ++ return req; ++} ++ ++static void mtp_request_free(struct usb_request *req, struct usb_ep *ep) ++{ ++ if (req) { ++ kfree(req->buf); ++ usb_ep_free_request(ep, req); ++ } ++} ++ ++static inline int mtp_lock(atomic_t *excl) ++{ ++ if (atomic_inc_return(excl) == 1) { ++ return 0; ++ } else { ++ atomic_dec(excl); ++ return -1; ++ } ++} ++ ++static inline void mtp_unlock(atomic_t *excl) ++{ ++ atomic_dec(excl); ++} ++ ++/* add a request to the tail of a list */ ++static void mtp_req_put(struct mtp_dev *dev, struct list_head *head, ++ struct usb_request *req) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ list_add_tail(&req->list, head); ++ spin_unlock_irqrestore(&dev->lock, flags); ++} ++ ++/* remove a request from the head of a list */ ++static struct usb_request ++*mtp_req_get(struct mtp_dev *dev, struct list_head *head) ++{ ++ unsigned long flags; ++ struct usb_request *req; ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ if (list_empty(head)) { ++ req = 0; ++ } else { ++ req = list_first_entry(head, struct usb_request, list); ++ list_del(&req->list); ++ } ++ spin_unlock_irqrestore(&dev->lock, flags); ++ return req; ++} ++ ++static void mtp_complete_in(struct usb_ep *ep, struct usb_request *req) ++{ ++ struct mtp_dev *dev = _mtp_dev; ++ ++ if (req->status != 0) ++ dev->state = STATE_ERROR; ++ ++ mtp_req_put(dev, &dev->tx_idle, req); ++ ++ wake_up(&dev->write_wq); ++} ++ ++static void mtp_complete_out(struct usb_ep *ep, struct usb_request *req) ++{ ++ struct mtp_dev *dev = _mtp_dev; ++ ++ dev->rx_done = 1; ++ if (req->status != 0) ++ dev->state = STATE_ERROR; ++ ++ wake_up(&dev->read_wq); ++} ++ ++static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req) ++{ ++ struct mtp_dev *dev = _mtp_dev; ++ ++ if (req->status != 0) ++ dev->state = STATE_ERROR; ++ ++ mtp_req_put(dev, &dev->intr_idle, req); ++ ++ wake_up(&dev->intr_wq); ++} ++ ++static int mtp_create_bulk_endpoints(struct mtp_dev *dev, ++ struct usb_endpoint_descriptor *in_desc, ++ struct usb_endpoint_descriptor *out_desc, ++ struct usb_endpoint_descriptor *intr_desc) ++{ ++ struct usb_composite_dev *cdev = dev->cdev; ++ struct usb_request *req; ++ struct usb_ep *ep; ++ int i; ++ ++ DBG(cdev, "create_bulk_endpoints dev: %p\n", dev); ++ ++ ep = usb_ep_autoconfig(cdev->gadget, in_desc); ++ if (!ep) { ++ DBG(cdev, "usb_ep_autoconfig for ep_in failed\n"); ++ return -ENODEV; ++ } ++ DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name); ++ ep->driver_data = dev; /* claim the endpoint */ ++ dev->ep_in = ep; ++ ++ ep = usb_ep_autoconfig(cdev->gadget, out_desc); ++ if (!ep) { ++ DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); ++ return -ENODEV; ++ } ++ DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name); ++ ep->driver_data = dev; /* claim the endpoint */ ++ dev->ep_out = ep; ++ ++ ep = usb_ep_autoconfig(cdev->gadget, intr_desc); ++ if (!ep) { ++ DBG(cdev, "usb_ep_autoconfig for ep_intr failed\n"); ++ return -ENODEV; ++ } ++ DBG(cdev, "usb_ep_autoconfig for mtp ep_intr got %s\n", ep->name); ++ ep->driver_data = dev; /* claim the endpoint */ ++ dev->ep_intr = ep; ++ ++ /* now allocate requests for our endpoints */ ++ for (i = 0; i < TX_REQ_MAX; i++) { ++ req = mtp_request_new(dev->ep_in, MTP_BULK_BUFFER_SIZE); ++ if (!req) ++ goto fail; ++ req->complete = mtp_complete_in; ++ mtp_req_put(dev, &dev->tx_idle, req); ++ } ++ for (i = 0; i < RX_REQ_MAX; i++) { ++ req = mtp_request_new(dev->ep_out, MTP_BULK_BUFFER_SIZE); ++ if (!req) ++ goto fail; ++ req->complete = mtp_complete_out; ++ dev->rx_req[i] = req; ++ } ++ for (i = 0; i < INTR_REQ_MAX; i++) { ++ req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE); ++ if (!req) ++ goto fail; ++ req->complete = mtp_complete_intr; ++ mtp_req_put(dev, &dev->intr_idle, req); ++ } ++ ++ return 0; ++ ++fail: ++ pr_err("mtp_bind() could not allocate requests\n"); ++ return -1; ++} ++ ++static ssize_t mtp_read(struct file *fp, char __user *buf, ++ size_t count, loff_t *pos) ++{ ++ struct mtp_dev *dev = fp->private_data; ++ struct usb_composite_dev *cdev = dev->cdev; ++ struct usb_request *req; ++ ssize_t r = count; ++ unsigned xfer; ++ int ret = 0; ++ ++ DBG(cdev, "mtp_read(%zu)\n", count); ++ ++ if (count > MTP_BULK_BUFFER_SIZE) ++ return -EINVAL; ++ ++ /* we will block until we're online */ ++ DBG(cdev, "mtp_read: waiting for online state\n"); ++ ret = wait_event_interruptible(dev->read_wq, ++ dev->state != STATE_OFFLINE); ++ if (ret < 0) { ++ r = ret; ++ goto done; ++ } ++ spin_lock_irq(&dev->lock); ++ if (dev->state == STATE_CANCELED) { ++ /* report cancelation to userspace */ ++ dev->state = STATE_READY; ++ spin_unlock_irq(&dev->lock); ++ return -ECANCELED; ++ } ++ dev->state = STATE_BUSY; ++ spin_unlock_irq(&dev->lock); ++ ++requeue_req: ++ /* queue a request */ ++ req = dev->rx_req[0]; ++ req->length = count; ++ dev->rx_done = 0; ++ ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL); ++ if (ret < 0) { ++ r = -EIO; ++ goto done; ++ } else { ++ DBG(cdev, "rx %p queue\n", req); ++ } ++ ++ /* wait for a request to complete */ ++ ret = wait_event_interruptible(dev->read_wq, dev->rx_done); ++ if (ret < 0) { ++ r = ret; ++ usb_ep_dequeue(dev->ep_out, req); ++ goto done; ++ } ++ if (dev->state == STATE_BUSY) { ++ /* If we got a 0-len packet, throw it back and try again. */ ++ if (req->actual == 0) ++ goto requeue_req; ++ ++ DBG(cdev, "rx %p %d\n", req, req->actual); ++ xfer = (req->actual < count) ? req->actual : count; ++ r = xfer; ++ if (copy_to_user(buf, req->buf, xfer)) ++ r = -EFAULT; ++ } else ++ r = -EIO; ++ ++done: ++ spin_lock_irq(&dev->lock); ++ if (dev->state == STATE_CANCELED) ++ r = -ECANCELED; ++ else if (dev->state != STATE_OFFLINE) ++ dev->state = STATE_READY; ++ spin_unlock_irq(&dev->lock); ++ ++ DBG(cdev, "mtp_read returning %zd\n", r); ++ return r; ++} ++ ++static ssize_t mtp_write(struct file *fp, const char __user *buf, ++ size_t count, loff_t *pos) ++{ ++ struct mtp_dev *dev = fp->private_data; ++ struct usb_composite_dev *cdev = dev->cdev; ++ struct usb_request *req = 0; ++ ssize_t r = count; ++ unsigned xfer; ++ int sendZLP = 0; ++ int ret; ++ ++ DBG(cdev, "mtp_write(%zu)\n", count); ++ ++ spin_lock_irq(&dev->lock); ++ if (dev->state == STATE_CANCELED) { ++ /* report cancelation to userspace */ ++ dev->state = STATE_READY; ++ spin_unlock_irq(&dev->lock); ++ return -ECANCELED; ++ } ++ if (dev->state == STATE_OFFLINE) { ++ spin_unlock_irq(&dev->lock); ++ return -ENODEV; ++ } ++ dev->state = STATE_BUSY; ++ spin_unlock_irq(&dev->lock); ++ ++ /* we need to send a zero length packet to signal the end of transfer ++ * if the transfer size is aligned to a packet boundary. ++ */ ++ if ((count & (dev->ep_in->maxpacket - 1)) == 0) ++ sendZLP = 1; ++ ++ while (count > 0 || sendZLP) { ++ /* so we exit after sending ZLP */ ++ if (count == 0) ++ sendZLP = 0; ++ ++ if (dev->state != STATE_BUSY) { ++ DBG(cdev, "mtp_write dev->error\n"); ++ r = -EIO; ++ break; ++ } ++ ++ /* get an idle tx request to use */ ++ req = 0; ++ ret = wait_event_interruptible(dev->write_wq, ++ ((req = mtp_req_get(dev, &dev->tx_idle)) ++ || dev->state != STATE_BUSY)); ++ if (!req) { ++ r = ret; ++ break; ++ } ++ ++ if (count > MTP_BULK_BUFFER_SIZE) ++ xfer = MTP_BULK_BUFFER_SIZE; ++ else ++ xfer = count; ++ if (xfer && copy_from_user(req->buf, buf, xfer)) { ++ r = -EFAULT; ++ break; ++ } ++ ++ req->length = xfer; ++ ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); ++ if (ret < 0) { ++ DBG(cdev, "mtp_write: xfer error %d\n", ret); ++ r = -EIO; ++ break; ++ } ++ ++ buf += xfer; ++ count -= xfer; ++ ++ /* zero this so we don't try to free it on error exit */ ++ req = 0; ++ } ++ ++ if (req) ++ mtp_req_put(dev, &dev->tx_idle, req); ++ ++ spin_lock_irq(&dev->lock); ++ if (dev->state == STATE_CANCELED) ++ r = -ECANCELED; ++ else if (dev->state != STATE_OFFLINE) ++ dev->state = STATE_READY; ++ spin_unlock_irq(&dev->lock); ++ ++ DBG(cdev, "mtp_write returning %zd\n", r); ++ return r; ++} ++ ++/* read from a local file and write to USB */ ++static void send_file_work(struct work_struct *data) ++{ ++ struct mtp_dev *dev = container_of(data, struct mtp_dev, ++ send_file_work); ++ struct usb_composite_dev *cdev = dev->cdev; ++ struct usb_request *req = 0; ++ struct mtp_data_header *header; ++ struct file *filp; ++ loff_t offset; ++ int64_t count; ++ int xfer, ret, hdr_size; ++ int r = 0; ++ int sendZLP = 0; ++ ++ /* read our parameters */ ++ smp_rmb(); ++ filp = dev->xfer_file; ++ offset = dev->xfer_file_offset; ++ count = dev->xfer_file_length; ++ ++ DBG(cdev, "send_file_work(%lld %lld)\n", offset, count); ++ ++ if (dev->xfer_send_header) { ++ hdr_size = sizeof(struct mtp_data_header); ++ count += hdr_size; ++ } else { ++ hdr_size = 0; ++ } ++ ++ /* we need to send a zero length packet to signal the end of transfer ++ * if the transfer size is aligned to a packet boundary. ++ */ ++ if ((count & (dev->ep_in->maxpacket - 1)) == 0) ++ sendZLP = 1; ++ ++ while (count > 0 || sendZLP) { ++ /* so we exit after sending ZLP */ ++ if (count == 0) ++ sendZLP = 0; ++ ++ /* get an idle tx request to use */ ++ req = 0; ++ ret = wait_event_interruptible(dev->write_wq, ++ (req = mtp_req_get(dev, &dev->tx_idle)) ++ || dev->state != STATE_BUSY); ++ if (dev->state == STATE_CANCELED) { ++ r = -ECANCELED; ++ break; ++ } ++ if (!req) { ++ r = ret; ++ break; ++ } ++ ++ if (count > MTP_BULK_BUFFER_SIZE) ++ xfer = MTP_BULK_BUFFER_SIZE; ++ else ++ xfer = count; ++ ++ if (hdr_size) { ++ /* prepend MTP data header */ ++ header = (struct mtp_data_header *)req->buf; ++ header->length = __cpu_to_le32(count); ++ header->type = __cpu_to_le16(2); /* data packet */ ++ header->command = __cpu_to_le16(dev->xfer_command); ++ header->transaction_id = ++ __cpu_to_le32(dev->xfer_transaction_id); ++ } ++ ++ ret = vfs_read(filp, req->buf + hdr_size, xfer - hdr_size, ++ &offset); ++ if (ret < 0) { ++ r = ret; ++ break; ++ } ++ xfer = ret + hdr_size; ++ hdr_size = 0; ++ ++ req->length = xfer; ++ ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); ++ if (ret < 0) { ++ DBG(cdev, "send_file_work: xfer error %d\n", ret); ++ dev->state = STATE_ERROR; ++ r = -EIO; ++ break; ++ } ++ ++ count -= xfer; ++ ++ /* zero this so we don't try to free it on error exit */ ++ req = 0; ++ } ++ ++ if (req) ++ mtp_req_put(dev, &dev->tx_idle, req); ++ ++ DBG(cdev, "send_file_work returning %d\n", r); ++ /* write the result */ ++ dev->xfer_result = r; ++ smp_wmb(); ++} ++ ++/* read from USB and write to a local file */ ++static void receive_file_work(struct work_struct *data) ++{ ++ struct mtp_dev *dev = container_of(data, struct mtp_dev, ++ receive_file_work); ++ struct usb_composite_dev *cdev = dev->cdev; ++ struct usb_request *read_req = NULL, *write_req = NULL; ++ struct file *filp; ++ loff_t offset; ++ int64_t count; ++ int ret, cur_buf = 0; ++ int r = 0; ++ ++ /* read our parameters */ ++ smp_rmb(); ++ filp = dev->xfer_file; ++ offset = dev->xfer_file_offset; ++ count = dev->xfer_file_length; ++ ++ DBG(cdev, "receive_file_work(%lld)\n", count); ++ ++ while (count > 0 || write_req) { ++ if (count > 0) { ++ /* queue a request */ ++ read_req = dev->rx_req[cur_buf]; ++ cur_buf = (cur_buf + 1) % RX_REQ_MAX; ++ ++ read_req->length = (count > MTP_BULK_BUFFER_SIZE ++ ? MTP_BULK_BUFFER_SIZE : count); ++ dev->rx_done = 0; ++ ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL); ++ if (ret < 0) { ++ r = -EIO; ++ dev->state = STATE_ERROR; ++ break; ++ } ++ } ++ ++ if (write_req) { ++ DBG(cdev, "rx %p %d\n", write_req, write_req->actual); ++ ret = vfs_write(filp, write_req->buf, write_req->actual, ++ &offset); ++ DBG(cdev, "vfs_write %d\n", ret); ++ if (ret != write_req->actual) { ++ r = -EIO; ++ dev->state = STATE_ERROR; ++ break; ++ } ++ write_req = NULL; ++ } ++ ++ if (read_req) { ++ /* wait for our last read to complete */ ++ ret = wait_event_interruptible(dev->read_wq, ++ dev->rx_done || dev->state != STATE_BUSY); ++ if (dev->state == STATE_CANCELED) { ++ r = -ECANCELED; ++ if (!dev->rx_done) ++ usb_ep_dequeue(dev->ep_out, read_req); ++ break; ++ } ++ /* if xfer_file_length is 0xFFFFFFFF, then we read until ++ * we get a zero length packet ++ */ ++ if (count != 0xFFFFFFFF) ++ count -= read_req->actual; ++ if (read_req->actual < read_req->length) { ++ /* ++ * short packet is used to signal EOF for ++ * sizes > 4 gig ++ */ ++ DBG(cdev, "got short packet\n"); ++ count = 0; ++ } ++ ++ write_req = read_req; ++ read_req = NULL; ++ } ++ } ++ ++ DBG(cdev, "receive_file_work returning %d\n", r); ++ /* write the result */ ++ dev->xfer_result = r; ++ smp_wmb(); ++} ++ ++static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) ++{ ++ struct usb_request *req = NULL; ++ int ret; ++ int length = event->length; ++ ++ DBG(dev->cdev, "mtp_send_event(%zu)\n", event->length); ++ ++ if (length < 0 || length > INTR_BUFFER_SIZE) ++ return -EINVAL; ++ if (dev->state == STATE_OFFLINE) ++ return -ENODEV; ++ ++ ret = wait_event_interruptible_timeout(dev->intr_wq, ++ (req = mtp_req_get(dev, &dev->intr_idle)), ++ msecs_to_jiffies(1000)); ++ if (!req) ++ return -ETIME; ++ ++ if (copy_from_user(req->buf, (void __user *)event->data, length)) { ++ mtp_req_put(dev, &dev->intr_idle, req); ++ return -EFAULT; ++ } ++ req->length = length; ++ ret = usb_ep_queue(dev->ep_intr, req, GFP_KERNEL); ++ if (ret) ++ mtp_req_put(dev, &dev->intr_idle, req); ++ ++ return ret; ++} ++ ++static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) ++{ ++ struct mtp_dev *dev = fp->private_data; ++ struct file *filp = NULL; ++ int ret = -EINVAL; ++ ++ if (mtp_lock(&dev->ioctl_excl)) ++ return -EBUSY; ++ ++ switch (code) { ++ case MTP_SEND_FILE: ++ case MTP_RECEIVE_FILE: ++ case MTP_SEND_FILE_WITH_HEADER: ++ { ++ struct mtp_file_range mfr; ++ struct work_struct *work; ++ ++ spin_lock_irq(&dev->lock); ++ if (dev->state == STATE_CANCELED) { ++ /* report cancelation to userspace */ ++ dev->state = STATE_READY; ++ spin_unlock_irq(&dev->lock); ++ ret = -ECANCELED; ++ goto out; ++ } ++ if (dev->state == STATE_OFFLINE) { ++ spin_unlock_irq(&dev->lock); ++ ret = -ENODEV; ++ goto out; ++ } ++ dev->state = STATE_BUSY; ++ spin_unlock_irq(&dev->lock); ++ ++ if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) { ++ ret = -EFAULT; ++ goto fail; ++ } ++ /* hold a reference to the file while we are working with it */ ++ filp = fget(mfr.fd); ++ if (!filp) { ++ ret = -EBADF; ++ goto fail; ++ } ++ ++ /* write the parameters */ ++ dev->xfer_file = filp; ++ dev->xfer_file_offset = mfr.offset; ++ dev->xfer_file_length = mfr.length; ++ smp_wmb(); ++ ++ if (code == MTP_SEND_FILE_WITH_HEADER) { ++ work = &dev->send_file_work; ++ dev->xfer_send_header = 1; ++ dev->xfer_command = mfr.command; ++ dev->xfer_transaction_id = mfr.transaction_id; ++ } else if (code == MTP_SEND_FILE) { ++ work = &dev->send_file_work; ++ dev->xfer_send_header = 0; ++ } else { ++ work = &dev->receive_file_work; ++ } ++ ++ /* We do the file transfer on a work queue so it will run ++ * in kernel context, which is necessary for vfs_read and ++ * vfs_write to use our buffers in the kernel address space. ++ */ ++ queue_work(dev->wq, work); ++ /* wait for operation to complete */ ++ flush_workqueue(dev->wq); ++ fput(filp); ++ ++ /* read the result */ ++ smp_rmb(); ++ ret = dev->xfer_result; ++ break; ++ } ++ case MTP_SEND_EVENT: ++ { ++ struct mtp_event event; ++ /* return here so we don't change dev->state below, ++ * which would interfere with bulk transfer state. ++ */ ++ if (copy_from_user(&event, (void __user *)value, sizeof(event))) ++ ret = -EFAULT; ++ else ++ ret = mtp_send_event(dev, &event); ++ goto out; ++ } ++ } ++ ++fail: ++ spin_lock_irq(&dev->lock); ++ if (dev->state == STATE_CANCELED) ++ ret = -ECANCELED; ++ else if (dev->state != STATE_OFFLINE) ++ dev->state = STATE_READY; ++ spin_unlock_irq(&dev->lock); ++out: ++ mtp_unlock(&dev->ioctl_excl); ++ DBG(dev->cdev, "ioctl returning %d\n", ret); ++ return ret; ++} ++ ++static int mtp_open(struct inode *ip, struct file *fp) ++{ ++ printk(KERN_INFO "mtp_open\n"); ++ if (mtp_lock(&_mtp_dev->open_excl)) ++ return -EBUSY; ++ ++ /* clear any error condition */ ++ if (_mtp_dev->state != STATE_OFFLINE) ++ _mtp_dev->state = STATE_READY; ++ ++ fp->private_data = _mtp_dev; ++ return 0; ++} ++ ++static int mtp_release(struct inode *ip, struct file *fp) ++{ ++ printk(KERN_INFO "mtp_release\n"); ++ ++ mtp_unlock(&_mtp_dev->open_excl); ++ return 0; ++} ++ ++/* file operations for /dev/mtp_usb */ ++static const struct file_operations mtp_fops = { ++ .owner = THIS_MODULE, ++ .read = mtp_read, ++ .write = mtp_write, ++ .unlocked_ioctl = mtp_ioctl, ++ .open = mtp_open, ++ .release = mtp_release, ++}; ++ ++static struct miscdevice mtp_device = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = mtp_shortname, ++ .fops = &mtp_fops, ++}; ++ ++static int mtp_ctrlrequest(struct usb_composite_dev *cdev, ++ const struct usb_ctrlrequest *ctrl) ++{ ++ struct mtp_dev *dev = _mtp_dev; ++ 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); ++ unsigned long flags; ++ ++ VDBG(cdev, "mtp_ctrlrequest " ++ "%02x.%02x v%04x i%04x l%u\n", ++ ctrl->bRequestType, ctrl->bRequest, ++ w_value, w_index, w_length); ++ ++ /* Handle MTP OS string */ ++ if (ctrl->bRequestType == ++ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) ++ && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR ++ && (w_value >> 8) == USB_DT_STRING ++ && (w_value & 0xFF) == MTP_OS_STRING_ID) { ++ value = (w_length < sizeof(mtp_os_string) ++ ? w_length : sizeof(mtp_os_string)); ++ memcpy(cdev->req->buf, mtp_os_string, value); ++ } else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) { ++ /* Handle MTP OS descriptor */ ++ DBG(cdev, "vendor request: %d index: %d value: %d length: %d\n", ++ ctrl->bRequest, w_index, w_value, w_length); ++ ++ if (ctrl->bRequest == 1 ++ && (ctrl->bRequestType & USB_DIR_IN) ++ && (w_index == 4 || w_index == 5)) { ++ value = (w_length < sizeof(mtp_ext_config_desc) ? ++ w_length : sizeof(mtp_ext_config_desc)); ++ memcpy(cdev->req->buf, &mtp_ext_config_desc, value); ++ } ++ } else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { ++ DBG(cdev, "class request: %d index: %d value: %d length: %d\n", ++ ctrl->bRequest, w_index, w_value, w_length); ++ ++ if (ctrl->bRequest == MTP_REQ_CANCEL && w_index == 0 ++ && w_value == 0) { ++ DBG(cdev, "MTP_REQ_CANCEL\n"); ++ ++ spin_lock_irqsave(&dev->lock, flags); ++ if (dev->state == STATE_BUSY) { ++ dev->state = STATE_CANCELED; ++ wake_up(&dev->read_wq); ++ wake_up(&dev->write_wq); ++ } ++ spin_unlock_irqrestore(&dev->lock, flags); ++ ++ /* We need to queue a request to read the remaining ++ * bytes, but we don't actually need to look at ++ * the contents. ++ */ ++ value = w_length; ++ } else if (ctrl->bRequest == MTP_REQ_GET_DEVICE_STATUS ++ && w_index == 0 && w_value == 0) { ++ struct mtp_device_status *status = cdev->req->buf; ++ ++ status->wLength = ++ __constant_cpu_to_le16(sizeof(*status)); ++ ++ DBG(cdev, "MTP_REQ_GET_DEVICE_STATUS\n"); ++ spin_lock_irqsave(&dev->lock, flags); ++ /* device status is "busy" until we report ++ * the cancelation to userspace ++ */ ++ if (dev->state == STATE_CANCELED) ++ status->wCode = ++ __cpu_to_le16(MTP_RESPONSE_DEVICE_BUSY); ++ else ++ status->wCode = ++ __cpu_to_le16(MTP_RESPONSE_OK); ++ spin_unlock_irqrestore(&dev->lock, flags); ++ value = sizeof(*status); ++ } ++ } ++ ++ /* respond with data transfer or status phase? */ ++ if (value >= 0) { ++ int rc; ++ ++ cdev->req->zero = value < w_length; ++ cdev->req->length = value; ++ rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); ++ if (rc < 0) ++ ERROR(cdev, "%s: response queue error\n", __func__); ++ } ++ return value; ++} ++ ++static int ++mtp_function_bind(struct usb_configuration *c, struct usb_function *f) ++{ ++ struct usb_composite_dev *cdev = c->cdev; ++ struct mtp_dev *dev = func_to_mtp(f); ++ int id; ++ int ret; ++ struct mtp_instance *fi_mtp; ++ ++ dev->cdev = cdev; ++ DBG(cdev, "mtp_function_bind dev: %p\n", dev); ++ ++ /* allocate interface ID(s) */ ++ id = usb_interface_id(c, f); ++ if (id < 0) ++ return id; ++ mtp_interface_desc.bInterfaceNumber = id; ++ ++ if (mtp_string_defs[INTERFACE_STRING_INDEX].id == 0) { ++ ret = usb_string_id(c->cdev); ++ if (ret < 0) ++ return ret; ++ mtp_string_defs[INTERFACE_STRING_INDEX].id = ret; ++ mtp_interface_desc.iInterface = ret; ++ } ++ ++ fi_mtp = container_of(f->fi, struct mtp_instance, func_inst); ++ ++ if (cdev->use_os_string) { ++ f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), ++ GFP_KERNEL); ++ if (!f->os_desc_table) ++ return -ENOMEM; ++ f->os_desc_n = 1; ++ f->os_desc_table[0].os_desc = &fi_mtp->mtp_os_desc; ++ } ++ ++ /* allocate endpoints */ ++ ret = mtp_create_bulk_endpoints(dev, &mtp_fullspeed_in_desc, ++ &mtp_fullspeed_out_desc, &mtp_intr_desc); ++ if (ret) ++ return ret; ++ ++ /* support high speed hardware */ ++ if (gadget_is_dualspeed(c->cdev->gadget)) { ++ mtp_highspeed_in_desc.bEndpointAddress = ++ mtp_fullspeed_in_desc.bEndpointAddress; ++ mtp_highspeed_out_desc.bEndpointAddress = ++ mtp_fullspeed_out_desc.bEndpointAddress; ++ } ++ /* support super speed hardware */ ++ if (gadget_is_superspeed(c->cdev->gadget)) { ++ unsigned max_burst; ++ ++ /* Calculate bMaxBurst, we know packet size is 1024 */ ++ max_burst = min_t(unsigned, MTP_BULK_BUFFER_SIZE / 1024, 15); ++ mtp_ss_in_desc.bEndpointAddress = ++ mtp_fullspeed_in_desc.bEndpointAddress; ++ mtp_ss_in_comp_desc.bMaxBurst = max_burst; ++ mtp_ss_out_desc.bEndpointAddress = ++ mtp_fullspeed_out_desc.bEndpointAddress; ++ mtp_ss_out_comp_desc.bMaxBurst = max_burst; ++ } ++ ++ DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", ++ gadget_is_superspeed(c->cdev->gadget) ? "super" : ++ (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full"), ++ f->name, dev->ep_in->name, dev->ep_out->name); ++ return 0; ++} ++ ++static void ++mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) ++{ ++ struct mtp_dev *dev = func_to_mtp(f); ++ struct usb_request *req; ++ int i; ++ ++ mtp_string_defs[INTERFACE_STRING_INDEX].id = 0; ++ while ((req = mtp_req_get(dev, &dev->tx_idle))) ++ mtp_request_free(req, dev->ep_in); ++ for (i = 0; i < RX_REQ_MAX; i++) ++ mtp_request_free(dev->rx_req[i], dev->ep_out); ++ while ((req = mtp_req_get(dev, &dev->intr_idle))) ++ mtp_request_free(req, dev->ep_intr); ++ dev->state = STATE_OFFLINE; ++ kfree(f->os_desc_table); ++ f->os_desc_n = 0; ++} ++ ++static int mtp_function_set_alt(struct usb_function *f, ++ unsigned intf, unsigned alt) ++{ ++ struct mtp_dev *dev = func_to_mtp(f); ++ struct usb_composite_dev *cdev = f->config->cdev; ++ int ret; ++ ++ DBG(cdev, "mtp_function_set_alt intf: %d alt: %d\n", intf, alt); ++ ++ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in); ++ if (ret) ++ return ret; ++ ++ ret = usb_ep_enable(dev->ep_in); ++ if (ret) ++ return ret; ++ ++ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out); ++ if (ret) ++ return ret; ++ ++ ret = usb_ep_enable(dev->ep_out); ++ if (ret) { ++ usb_ep_disable(dev->ep_in); ++ return ret; ++ } ++ ++ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_intr); ++ if (ret) ++ return ret; ++ ++ ret = usb_ep_enable(dev->ep_intr); ++ if (ret) { ++ usb_ep_disable(dev->ep_out); ++ usb_ep_disable(dev->ep_in); ++ return ret; ++ } ++ dev->state = STATE_READY; ++ ++ /* readers may be blocked waiting for us to go online */ ++ wake_up(&dev->read_wq); ++ return 0; ++} ++ ++static void mtp_function_disable(struct usb_function *f) ++{ ++ struct mtp_dev *dev = func_to_mtp(f); ++ struct usb_composite_dev *cdev = dev->cdev; ++ ++ DBG(cdev, "mtp_function_disable\n"); ++ dev->state = STATE_OFFLINE; ++ usb_ep_disable(dev->ep_in); ++ usb_ep_disable(dev->ep_out); ++ usb_ep_disable(dev->ep_intr); ++ ++ /* readers may be blocked waiting for us to go online */ ++ wake_up(&dev->read_wq); ++ ++ VDBG(cdev, "%s disabled\n", dev->function.name); ++} ++ ++static int __mtp_setup(struct mtp_instance *fi_mtp) ++{ ++ struct mtp_dev *dev; ++ int ret; ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ ++ if (fi_mtp != NULL) ++ fi_mtp->dev = dev; ++ ++ if (!dev) ++ return -ENOMEM; ++ ++ spin_lock_init(&dev->lock); ++ init_waitqueue_head(&dev->read_wq); ++ init_waitqueue_head(&dev->write_wq); ++ init_waitqueue_head(&dev->intr_wq); ++ atomic_set(&dev->open_excl, 0); ++ atomic_set(&dev->ioctl_excl, 0); ++ INIT_LIST_HEAD(&dev->tx_idle); ++ INIT_LIST_HEAD(&dev->intr_idle); ++ ++ dev->wq = create_singlethread_workqueue("f_mtp"); ++ if (!dev->wq) { ++ ret = -ENOMEM; ++ goto err1; ++ } ++ INIT_WORK(&dev->send_file_work, send_file_work); ++ INIT_WORK(&dev->receive_file_work, receive_file_work); ++ ++ _mtp_dev = dev; ++ ++ ret = misc_register(&mtp_device); ++ if (ret) ++ goto err2; ++ ++ return 0; ++ ++err2: ++ destroy_workqueue(dev->wq); ++err1: ++ _mtp_dev = NULL; ++ kfree(dev); ++ printk(KERN_ERR "mtp gadget driver failed to initialize\n"); ++ return ret; ++} ++ ++static int mtp_setup_configfs(struct mtp_instance *fi_mtp) ++{ ++ return __mtp_setup(fi_mtp); ++} ++ ++ ++static void mtp_cleanup(void) ++{ ++ struct mtp_dev *dev = _mtp_dev; ++ ++ if (!dev) ++ return; ++ ++ misc_deregister(&mtp_device); ++ destroy_workqueue(dev->wq); ++ _mtp_dev = NULL; ++ kfree(dev); ++} ++ ++static struct mtp_instance *to_mtp_instance(struct config_item *item) ++{ ++ return container_of(to_config_group(item), struct mtp_instance, ++ func_inst.group); ++} ++ ++static void mtp_attr_release(struct config_item *item) ++{ ++ struct mtp_instance *fi_mtp = to_mtp_instance(item); ++ ++ usb_put_function_instance(&fi_mtp->func_inst); ++} ++ ++static struct configfs_item_operations mtp_item_ops = { ++ .release = mtp_attr_release, ++}; ++ ++static struct config_item_type mtp_func_type = { ++ .ct_item_ops = &mtp_item_ops, ++ .ct_owner = THIS_MODULE, ++}; ++ ++ ++static struct mtp_instance *to_fi_mtp(struct usb_function_instance *fi) ++{ ++ return container_of(fi, struct mtp_instance, func_inst); ++} ++ ++static int mtp_set_inst_name(struct usb_function_instance *fi, const char *name) ++{ ++ struct mtp_instance *fi_mtp; ++ char *ptr; ++ int name_len; ++ ++ name_len = strlen(name) + 1; ++ if (name_len > MAX_INST_NAME_LEN) ++ return -ENAMETOOLONG; ++ ++ ptr = kstrndup(name, name_len, GFP_KERNEL); ++ if (!ptr) ++ return -ENOMEM; ++ ++ fi_mtp = to_fi_mtp(fi); ++ fi_mtp->name = ptr; ++ ++ return 0; ++} ++ ++static void mtp_free_inst(struct usb_function_instance *fi) ++{ ++ struct mtp_instance *fi_mtp; ++ ++ fi_mtp = to_fi_mtp(fi); ++ kfree(fi_mtp->name); ++ mtp_cleanup(); ++ //kfree(fi_mtp->mtp_os_desc.group.default_groups); ++ kfree(fi_mtp); ++} ++ ++struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config) ++{ ++ struct mtp_instance *fi_mtp; ++ int ret = 0; ++ struct usb_os_desc *descs[1]; ++ char *names[1]; ++ ++ fi_mtp = kzalloc(sizeof(*fi_mtp), GFP_KERNEL); ++ if (!fi_mtp) ++ return ERR_PTR(-ENOMEM); ++ fi_mtp->func_inst.set_inst_name = mtp_set_inst_name; ++ fi_mtp->func_inst.free_func_inst = mtp_free_inst; ++ ++ fi_mtp->mtp_os_desc.ext_compat_id = fi_mtp->mtp_ext_compat_id; ++ INIT_LIST_HEAD(&fi_mtp->mtp_os_desc.ext_prop); ++ descs[0] = &fi_mtp->mtp_os_desc; ++ names[0] = "MTP"; ++ config_group_init_type_name(&fi_mtp->func_inst.group, ++ "", &mtp_func_type); ++ usb_os_desc_prepare_interf_dir(&fi_mtp->func_inst.group, 1, ++ descs, names, THIS_MODULE); ++ ++ if (mtp_config) { ++ ret = mtp_setup_configfs(fi_mtp); ++ if (ret) { ++ kfree(fi_mtp); ++ pr_err("Error setting MTP\n"); ++ return ERR_PTR(ret); ++ } ++ } else ++ fi_mtp->dev = _mtp_dev; ++ ++ return &fi_mtp->func_inst; ++} ++EXPORT_SYMBOL_GPL(alloc_inst_mtp_ptp); ++ ++static struct usb_function_instance *mtp_alloc_inst(void) ++{ ++ return alloc_inst_mtp_ptp(true); ++} ++ ++static int mtp_ctrlreq_configfs(struct usb_function *f, ++ const struct usb_ctrlrequest *ctrl) ++{ ++ return mtp_ctrlrequest(f->config->cdev, ctrl); ++} ++ ++static void mtp_free(struct usb_function *f) ++{ ++ /*NO-OP: no function specific resource allocation in mtp_alloc*/ ++} ++ ++struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi, ++ bool mtp_config) ++{ ++ struct mtp_instance *fi_mtp = to_fi_mtp(fi); ++ struct mtp_dev *dev; ++ ++ /* ++ * PTP piggybacks on MTP function so make sure we have ++ * created MTP function before we associate this PTP ++ * function with a gadget configuration. ++ */ ++ if (fi_mtp->dev == NULL) { ++ pr_err("Error: Create MTP function before linking" ++ " PTP function with a gadget configuration\n"); ++ pr_err("\t1: Delete existing PTP function if any\n"); ++ pr_err("\t2: Create MTP function\n"); ++ pr_err("\t3: Create and symlink PTP function" ++ " with a gadget configuration\n"); ++ return ERR_PTR(-EINVAL); /* Invalid Configuration */ ++ } ++ ++ dev = fi_mtp->dev; ++ dev->function.name = DRIVER_NAME; ++ dev->function.strings = mtp_strings; ++ if (mtp_config) { ++ dev->function.fs_descriptors = fs_mtp_descs; ++ dev->function.hs_descriptors = hs_mtp_descs; ++ dev->function.ss_descriptors = ss_mtp_descs; ++ } else { ++ dev->function.fs_descriptors = fs_ptp_descs; ++ dev->function.hs_descriptors = hs_ptp_descs; ++ dev->function.ss_descriptors = ss_ptp_descs; ++ } ++ dev->function.bind = mtp_function_bind; ++ dev->function.unbind = mtp_function_unbind; ++ dev->function.set_alt = mtp_function_set_alt; ++ dev->function.disable = mtp_function_disable; ++ dev->function.setup = mtp_ctrlreq_configfs; ++ dev->function.free_func = mtp_free; ++ ++ return &dev->function; ++} ++EXPORT_SYMBOL_GPL(function_alloc_mtp_ptp); ++ ++static struct usb_function *mtp_alloc(struct usb_function_instance *fi) ++{ ++ return function_alloc_mtp_ptp(fi, true); ++} ++ ++DECLARE_USB_FUNCTION_INIT(mtp, mtp_alloc_inst, mtp_alloc); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/usb/gadget/function/f_mtp.h b/drivers/usb/gadget/function/f_mtp.h +new file mode 100644 +index 000000000..7adb1ff08 +--- /dev/null ++++ b/drivers/usb/gadget/function/f_mtp.h +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2014 Google, Inc. ++ * Author: Badhri Jagan Sridharan ++ * ++ * 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. ++ * ++ */ ++ ++extern struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config); ++extern struct usb_function *function_alloc_mtp_ptp( ++ struct usb_function_instance *fi, bool mtp_config); +diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c +index 855127249..dc8f078f9 100644 +--- a/drivers/usb/gadget/function/f_ncm.c ++++ b/drivers/usb/gadget/function/f_ncm.c +@@ -72,9 +72,7 @@ struct f_ncm { + struct sk_buff *skb_tx_data; + struct sk_buff *skb_tx_ndp; + u16 ndp_dgram_count; +- bool timer_force_tx; + struct hrtimer task_timer; +- bool timer_stopping; + }; + + static inline struct f_ncm *func_to_ncm(struct usb_function *f) +@@ -890,7 +888,6 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + + if (ncm->port.in_ep->enabled) { + DBG(cdev, "reset ncm\n"); +- ncm->timer_stopping = true; + ncm->netdev = NULL; + gether_disconnect(&ncm->port); + ncm_reset_values(ncm); +@@ -928,7 +925,6 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + if (IS_ERR(net)) + return PTR_ERR(net); + ncm->netdev = net; +- ncm->timer_stopping = false; + } + + spin_lock(&ncm->lock); +@@ -1017,22 +1013,20 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, + { + struct f_ncm *ncm = func_to_ncm(&port->func); + struct sk_buff *skb2 = NULL; +- int ncb_len = 0; +- __le16 *ntb_data; +- __le16 *ntb_ndp; +- int dgram_pad; +- +- unsigned max_size = ncm->port.fixed_in_len; +- const struct ndp_parser_opts *opts = ncm->parser_opts; +- const int ndp_align = le16_to_cpu(ntb_parameters.wNdpInAlignment); +- const int div = le16_to_cpu(ntb_parameters.wNdpInDivisor); +- const int rem = le16_to_cpu(ntb_parameters.wNdpInPayloadRemainder); +- const int dgram_idx_len = 2 * 2 * opts->dgram_item_len; +- +- if (!skb && !ncm->skb_tx_data) +- return NULL; + + if (skb) { ++ int ncb_len = 0; ++ __le16 *ntb_data; ++ __le16 *ntb_ndp; ++ int dgram_pad; ++ ++ unsigned max_size = ncm->port.fixed_in_len; ++ const struct ndp_parser_opts *opts = ncm->parser_opts; ++ const int ndp_align = le16_to_cpu(ntb_parameters.wNdpInAlignment); ++ const int div = le16_to_cpu(ntb_parameters.wNdpInDivisor); ++ const int rem = le16_to_cpu(ntb_parameters.wNdpInPayloadRemainder); ++ const int dgram_idx_len = 2 * 2 * opts->dgram_item_len; ++ + /* Add the CRC if required up front */ + if (ncm->is_crc) { + uint32_t crc; +@@ -1126,8 +1120,11 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, + dev_consume_skb_any(skb); + skb = NULL; + +- } else if (ncm->skb_tx_data && ncm->timer_force_tx) { +- /* If the tx was requested because of a timeout then send */ ++ } else if (ncm->skb_tx_data) { ++ /* If we get here ncm_wrap_ntb() was called with NULL skb, ++ * because eth_start_xmit() was called with NULL skb by ++ * ncm_tx_timeout() - hence, this is our signal to flush/send. ++ */ + skb2 = package_for_tx(ncm); + if (!skb2) + goto err; +@@ -1155,20 +1152,18 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port, + static enum hrtimer_restart ncm_tx_timeout(struct hrtimer *data) + { + struct f_ncm *ncm = container_of(data, struct f_ncm, task_timer); ++ struct net_device *netdev = READ_ONCE(ncm->netdev); + +- /* Only send if data is available. */ +- if (!ncm->timer_stopping && ncm->skb_tx_data) { +- ncm->timer_force_tx = true; +- ++ if (netdev) { + /* XXX This allowance of a NULL skb argument to ndo_start_xmit + * XXX is not sane. The gadget layer should be redesigned so + * XXX that the dev->wrap() invocations to build SKBs is transparent + * XXX and performed in some way outside of the ndo_start_xmit + * XXX interface. ++ * ++ * This will call directly into u_ether's eth_start_xmit() + */ +- ncm->netdev->netdev_ops->ndo_start_xmit(NULL, ncm->netdev); +- +- ncm->timer_force_tx = false; ++ netdev->netdev_ops->ndo_start_xmit(NULL, netdev); + } + return HRTIMER_NORESTART; + } +@@ -1357,7 +1352,6 @@ static void ncm_disable(struct usb_function *f) + DBG(cdev, "ncm deactivated\n"); + + if (ncm->port.in_ep->enabled) { +- ncm->timer_stopping = true; + ncm->netdev = NULL; + gether_disconnect(&ncm->port); + } +diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c +index 236ecc968..53158477f 100644 +--- a/drivers/usb/gadget/function/f_printer.c ++++ b/drivers/usb/gadget/function/f_printer.c +@@ -665,8 +665,7 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) + value = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC); + spin_lock(&dev->lock); + if (value) { +- list_del(&req->list); +- list_add(&req->list, &dev->tx_reqs); ++ list_move(&req->list, &dev->tx_reqs); + spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock_printer_io); + return -EAGAIN; +@@ -823,7 +822,7 @@ set_printer_interface(struct printer_dev *dev) + + result = usb_ep_enable(dev->out_ep); + if (result != 0) { +- DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); ++ DBG(dev, "enable %s --> %d\n", dev->out_ep->name, result); + goto done; + } + +diff --git a/drivers/usb/gadget/function/f_ptp.c b/drivers/usb/gadget/function/f_ptp.c +new file mode 100644 +index 000000000..da3e4d53e +--- /dev/null ++++ b/drivers/usb/gadget/function/f_ptp.c +@@ -0,0 +1,38 @@ ++/* ++ * Gadget Function Driver for PTP ++ * ++ * Copyright (C) 2014 Google, Inc. ++ * Author: Badhri Jagan Sridharan ++ * ++ * 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 ++#include ++ ++#include ++#include ++ ++#include "f_mtp.h" ++ ++static struct usb_function_instance *ptp_alloc_inst(void) ++{ ++ return alloc_inst_mtp_ptp(false); ++} ++ ++static struct usb_function *ptp_alloc(struct usb_function_instance *fi) ++{ ++ return function_alloc_mtp_ptp(fi, false); ++} ++ ++DECLARE_USB_FUNCTION_INIT(ptp, ptp_alloc_inst, ptp_alloc); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Badhri Jagan Sridharan"); +diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c +index e65f474ad..51772f430 100644 +--- a/drivers/usb/gadget/function/f_uac1.c ++++ b/drivers/usb/gadget/function/f_uac1.c +@@ -22,10 +22,26 @@ + /* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */ + #define UAC1_CHANNEL_MASK 0x0FFF + ++#define USB_OUT_FU_ID (out_feature_unit_desc->bUnitID) ++#define USB_IN_FU_ID (in_feature_unit_desc->bUnitID) ++ ++#define EPIN_EN(_opts) ((_opts)->p_chmask != 0) ++#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) ++#define FUIN_EN(_opts) ((_opts)->p_mute_present \ ++ || (_opts)->p_volume_present) ++#define FUOUT_EN(_opts) ((_opts)->c_mute_present \ ++ || (_opts)->c_volume_present) ++ + struct f_uac1 { + struct g_audio g_audio; + u8 ac_intf, as_in_intf, as_out_intf; + u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ ++ ++ struct usb_ctrlrequest setup_cr; /* will be used in data stage */ ++ ++ /* Interrupt IN endpoint of AC interface */ ++ struct usb_ep *int_ep; ++ atomic_t int_count; + }; + + static inline struct f_uac1 *func_to_uac1(struct usb_function *f) +@@ -50,88 +66,70 @@ static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio) + * USB-OUT -> IT_1 -> OT_2 -> ALSA_Capture + * ALSA_Playback -> IT_3 -> OT_4 -> USB-IN + */ +-#define F_AUDIO_AC_INTERFACE 0 +-#define F_AUDIO_AS_OUT_INTERFACE 1 +-#define F_AUDIO_AS_IN_INTERFACE 2 +-/* Number of streaming interfaces */ +-#define F_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, ++ /* .bNumEndpoints = DYNAMIC */ + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, + }; + +-/* +- * The number of AudioStreaming and MIDIStreaming interfaces +- * in the Audio Interface Collection +- */ +-DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); +- +-#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) +-/* 2 input terminals and 2 output terminals */ +-#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \ +- + 2*UAC_DT_INPUT_TERMINAL_SIZE + 2*UAC_DT_OUTPUT_TERMINAL_SIZE) + /* 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 = cpu_to_le16(0x0100), +- .wTotalLength = cpu_to_le16(UAC_DT_TOTAL_LENGTH), +- .bInCollection = F_AUDIO_NUM_INTERFACES, +- .baInterfaceNr = { +- /* Interface number of the AudioStream interfaces */ +- [0] = 1, +- [1] = 2, +- } +-}; ++static struct uac1_ac_header_descriptor *ac_header_desc; + +-#define USB_OUT_IT_ID 1 + static struct uac_input_terminal_descriptor usb_out_it_desc = { + .bLength = UAC_DT_INPUT_TERMINAL_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC_INPUT_TERMINAL, +- .bTerminalID = USB_OUT_IT_ID, ++ /* .bTerminalID = DYNAMIC */ + .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), + .bAssocTerminal = 0, + .wChannelConfig = cpu_to_le16(0x3), + }; + +-#define IO_OUT_OT_ID 2 + static struct uac1_output_terminal_descriptor io_out_ot_desc = { + .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, +- .bTerminalID = IO_OUT_OT_ID, ++ /* .bTerminalID = DYNAMIC */ + .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER), + .bAssocTerminal = 0, +- .bSourceID = USB_OUT_IT_ID, ++ /* .bSourceID = DYNAMIC */ + }; + +-#define IO_IN_IT_ID 3 + static struct uac_input_terminal_descriptor io_in_it_desc = { + .bLength = UAC_DT_INPUT_TERMINAL_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC_INPUT_TERMINAL, +- .bTerminalID = IO_IN_IT_ID, ++ /* .bTerminalID = DYNAMIC */ + .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE), + .bAssocTerminal = 0, + .wChannelConfig = cpu_to_le16(0x3), + }; + +-#define USB_IN_OT_ID 4 + static struct uac1_output_terminal_descriptor usb_in_ot_desc = { + .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, +- .bTerminalID = USB_IN_OT_ID, ++ /* .bTerminalID = DYNAMIC */ + .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), + .bAssocTerminal = 0, +- .bSourceID = IO_IN_IT_ID, ++ /* .bSourceID = DYNAMIC */ ++}; ++ ++static struct uac_feature_unit_descriptor *in_feature_unit_desc; ++static struct uac_feature_unit_descriptor *out_feature_unit_desc; ++ ++/* AC IN Interrupt Endpoint */ ++static struct usb_endpoint_descriptor ac_int_ep_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_INT, ++ .wMaxPacketSize = cpu_to_le16(2), ++ .bInterval = 4, + }; + + /* B.4.1 Standard AS Interface Descriptor */ +@@ -176,7 +174,7 @@ static struct uac1_as_header_descriptor as_out_header_desc = { + .bLength = UAC_DT_AS_HEADER_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC_AS_GENERAL, +- .bTerminalLink = USB_OUT_IT_ID, ++ /* .bTerminalLink = DYNAMIC */ + .bDelay = 1, + .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), + }; +@@ -185,7 +183,7 @@ static struct uac1_as_header_descriptor as_in_header_desc = { + .bLength = UAC_DT_AS_HEADER_SIZE, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubtype = UAC_AS_GENERAL, +- .bTerminalLink = USB_IN_OT_ID, ++ /* .bTerminalLink = DYNAMIC */ + .bDelay = 1, + .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), + }; +@@ -260,8 +258,13 @@ static struct usb_descriptor_header *f_audio_desc[] = { + + (struct usb_descriptor_header *)&usb_out_it_desc, + (struct usb_descriptor_header *)&io_out_ot_desc, ++ (struct usb_descriptor_header *)&out_feature_unit_desc, ++ + (struct usb_descriptor_header *)&io_in_it_desc, + (struct usb_descriptor_header *)&usb_in_ot_desc, ++ (struct usb_descriptor_header *)&in_feature_unit_desc, ++ ++ (struct usb_descriptor_header *)&ac_int_ep_desc, + + (struct usb_descriptor_header *)&as_out_interface_alt_0_desc, + (struct usb_descriptor_header *)&as_out_interface_alt_1_desc, +@@ -291,6 +294,8 @@ enum { + STR_IO_IN_IT, + STR_IO_IN_IT_CH_NAMES, + STR_USB_IN_OT, ++ STR_FU_IN, ++ STR_FU_OUT, + STR_AS_OUT_IF_ALT0, + STR_AS_OUT_IF_ALT1, + STR_AS_IN_IF_ALT0, +@@ -305,6 +310,8 @@ static struct usb_string strings_uac1[] = { + [STR_IO_IN_IT].s = "Capture Input terminal", + [STR_IO_IN_IT_CH_NAMES].s = "Capture Channels", + [STR_USB_IN_OT].s = "Capture Output terminal", ++ [STR_FU_IN].s = "Capture Volume", ++ [STR_FU_OUT].s = "Playback Volume", + [STR_AS_OUT_IF_ALT0].s = "Playback Inactive", + [STR_AS_OUT_IF_ALT1].s = "Playback Active", + [STR_AS_IN_IF_ALT0].s = "Capture Inactive", +@@ -326,6 +333,376 @@ static struct usb_gadget_strings *uac1_strings[] = { + * This function is an ALSA sound card following USB Audio Class Spec 1.0. + */ + ++static void audio_notify_complete(struct usb_ep *_ep, struct usb_request *req) ++{ ++ struct g_audio *audio = req->context; ++ struct f_uac1 *uac1 = func_to_uac1(&audio->func); ++ ++ atomic_dec(&uac1->int_count); ++ kfree(req->buf); ++ usb_ep_free_request(_ep, req); ++} ++ ++static int audio_notify(struct g_audio *audio, int unit_id, int cs) ++{ ++ struct f_uac1 *uac1 = func_to_uac1(&audio->func); ++ struct usb_request *req; ++ struct uac1_status_word *msg; ++ int ret; ++ ++ if (!uac1->int_ep->enabled) ++ return 0; ++ ++ if (atomic_inc_return(&uac1->int_count) > UAC1_DEF_INT_REQ_NUM) { ++ atomic_dec(&uac1->int_count); ++ return 0; ++ } ++ ++ req = usb_ep_alloc_request(uac1->int_ep, GFP_ATOMIC); ++ if (req == NULL) { ++ ret = -ENOMEM; ++ goto err_dec_int_count; ++ } ++ ++ msg = kmalloc(sizeof(*msg), GFP_ATOMIC); ++ if (msg == NULL) { ++ ret = -ENOMEM; ++ goto err_free_request; ++ } ++ ++ msg->bStatusType = UAC1_STATUS_TYPE_IRQ_PENDING ++ | UAC1_STATUS_TYPE_ORIG_AUDIO_CONTROL_IF; ++ msg->bOriginator = unit_id; ++ ++ req->length = sizeof(*msg); ++ req->buf = msg; ++ req->context = audio; ++ req->complete = audio_notify_complete; ++ ++ ret = usb_ep_queue(uac1->int_ep, req, GFP_ATOMIC); ++ ++ if (ret) ++ goto err_free_msg; ++ ++ return 0; ++ ++err_free_msg: ++ kfree(msg); ++err_free_request: ++ usb_ep_free_request(uac1->int_ep, req); ++err_dec_int_count: ++ atomic_dec(&uac1->int_count); ++ ++ return ret; ++} ++ ++static int ++in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) ++{ ++ struct usb_request *req = fn->config->cdev->req; ++ struct g_audio *audio = func_to_g_audio(fn); ++ struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); ++ u16 w_length = le16_to_cpu(cr->wLength); ++ u16 w_index = le16_to_cpu(cr->wIndex); ++ u16 w_value = le16_to_cpu(cr->wValue); ++ u8 entity_id = (w_index >> 8) & 0xff; ++ u8 control_selector = w_value >> 8; ++ int value = -EOPNOTSUPP; ++ ++ if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || ++ (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { ++ unsigned int is_playback = 0; ++ ++ if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) ++ is_playback = 1; ++ ++ if (control_selector == UAC_FU_MUTE) { ++ unsigned int mute; ++ ++ u_audio_get_mute(audio, is_playback, &mute); ++ ++ *(u8 *)req->buf = mute; ++ value = min_t(unsigned int, w_length, 1); ++ } else if (control_selector == UAC_FU_VOLUME) { ++ __le16 c; ++ s16 volume; ++ ++ u_audio_get_volume(audio, is_playback, &volume); ++ ++ c = cpu_to_le16(volume); ++ ++ value = min_t(unsigned int, w_length, sizeof(c)); ++ memcpy(req->buf, &c, value); ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d control_selector=%d TODO!\n", ++ __func__, __LINE__, control_selector); ++ } ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d entity_id=%d control_selector=%d TODO!\n", ++ __func__, __LINE__, entity_id, control_selector); ++ } ++ ++ return value; ++} ++ ++static int ++in_rq_min(struct usb_function *fn, const struct usb_ctrlrequest *cr) ++{ ++ struct usb_request *req = fn->config->cdev->req; ++ struct g_audio *audio = func_to_g_audio(fn); ++ struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); ++ u16 w_length = le16_to_cpu(cr->wLength); ++ u16 w_index = le16_to_cpu(cr->wIndex); ++ u16 w_value = le16_to_cpu(cr->wValue); ++ u8 entity_id = (w_index >> 8) & 0xff; ++ u8 control_selector = w_value >> 8; ++ int value = -EOPNOTSUPP; ++ ++ if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || ++ (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { ++ unsigned int is_playback = 0; ++ ++ if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) ++ is_playback = 1; ++ ++ if (control_selector == UAC_FU_VOLUME) { ++ __le16 r; ++ s16 min_db; ++ ++ if (is_playback) ++ min_db = opts->p_volume_min; ++ else ++ min_db = opts->c_volume_min; ++ ++ r = cpu_to_le16(min_db); ++ ++ value = min_t(unsigned int, w_length, sizeof(r)); ++ memcpy(req->buf, &r, value); ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d control_selector=%d TODO!\n", ++ __func__, __LINE__, control_selector); ++ } ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d entity_id=%d control_selector=%d TODO!\n", ++ __func__, __LINE__, entity_id, control_selector); ++ } ++ ++ return value; ++} ++ ++static int ++in_rq_max(struct usb_function *fn, const struct usb_ctrlrequest *cr) ++{ ++ struct usb_request *req = fn->config->cdev->req; ++ struct g_audio *audio = func_to_g_audio(fn); ++ struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); ++ u16 w_length = le16_to_cpu(cr->wLength); ++ u16 w_index = le16_to_cpu(cr->wIndex); ++ u16 w_value = le16_to_cpu(cr->wValue); ++ u8 entity_id = (w_index >> 8) & 0xff; ++ u8 control_selector = w_value >> 8; ++ int value = -EOPNOTSUPP; ++ ++ if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || ++ (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { ++ unsigned int is_playback = 0; ++ ++ if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) ++ is_playback = 1; ++ ++ if (control_selector == UAC_FU_VOLUME) { ++ __le16 r; ++ s16 max_db; ++ ++ if (is_playback) ++ max_db = opts->p_volume_max; ++ else ++ max_db = opts->c_volume_max; ++ ++ r = cpu_to_le16(max_db); ++ ++ value = min_t(unsigned int, w_length, sizeof(r)); ++ memcpy(req->buf, &r, value); ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d control_selector=%d TODO!\n", ++ __func__, __LINE__, control_selector); ++ } ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d entity_id=%d control_selector=%d TODO!\n", ++ __func__, __LINE__, entity_id, control_selector); ++ } ++ ++ return value; ++} ++ ++static int ++in_rq_res(struct usb_function *fn, const struct usb_ctrlrequest *cr) ++{ ++ struct usb_request *req = fn->config->cdev->req; ++ struct g_audio *audio = func_to_g_audio(fn); ++ struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); ++ u16 w_length = le16_to_cpu(cr->wLength); ++ u16 w_index = le16_to_cpu(cr->wIndex); ++ u16 w_value = le16_to_cpu(cr->wValue); ++ u8 entity_id = (w_index >> 8) & 0xff; ++ u8 control_selector = w_value >> 8; ++ int value = -EOPNOTSUPP; ++ ++ if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || ++ (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { ++ unsigned int is_playback = 0; ++ ++ if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) ++ is_playback = 1; ++ ++ if (control_selector == UAC_FU_VOLUME) { ++ __le16 r; ++ s16 res_db; ++ ++ if (is_playback) ++ res_db = opts->p_volume_res; ++ else ++ res_db = opts->c_volume_res; ++ ++ r = cpu_to_le16(res_db); ++ ++ value = min_t(unsigned int, w_length, sizeof(r)); ++ memcpy(req->buf, &r, value); ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d control_selector=%d TODO!\n", ++ __func__, __LINE__, control_selector); ++ } ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d entity_id=%d control_selector=%d TODO!\n", ++ __func__, __LINE__, entity_id, control_selector); ++ } ++ ++ return value; ++} ++ ++static void ++out_rq_cur_complete(struct usb_ep *ep, struct usb_request *req) ++{ ++ struct g_audio *audio = req->context; ++ struct usb_composite_dev *cdev = audio->func.config->cdev; ++ struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); ++ struct f_uac1 *uac1 = func_to_uac1(&audio->func); ++ struct usb_ctrlrequest *cr = &uac1->setup_cr; ++ u16 w_index = le16_to_cpu(cr->wIndex); ++ u16 w_value = le16_to_cpu(cr->wValue); ++ u8 entity_id = (w_index >> 8) & 0xff; ++ u8 control_selector = w_value >> 8; ++ ++ if (req->status != 0) { ++ dev_dbg(&cdev->gadget->dev, "completion err %d\n", req->status); ++ return; ++ } ++ ++ if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || ++ (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { ++ unsigned int is_playback = 0; ++ ++ if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) ++ is_playback = 1; ++ ++ if (control_selector == UAC_FU_MUTE) { ++ u8 mute = *(u8 *)req->buf; ++ ++ u_audio_set_mute(audio, is_playback, mute); ++ ++ return; ++ } else if (control_selector == UAC_FU_VOLUME) { ++ __le16 *c = req->buf; ++ s16 volume; ++ ++ volume = le16_to_cpu(*c); ++ u_audio_set_volume(audio, is_playback, volume); ++ ++ return; ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d control_selector=%d TODO!\n", ++ __func__, __LINE__, control_selector); ++ usb_ep_set_halt(ep); ++ } ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d entity_id=%d control_selector=%d TODO!\n", ++ __func__, __LINE__, entity_id, control_selector); ++ usb_ep_set_halt(ep); ++ ++ } ++} ++ ++static int ++out_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) ++{ ++ struct usb_request *req = fn->config->cdev->req; ++ struct g_audio *audio = func_to_g_audio(fn); ++ struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); ++ struct f_uac1 *uac1 = func_to_uac1(&audio->func); ++ u16 w_length = le16_to_cpu(cr->wLength); ++ u16 w_index = le16_to_cpu(cr->wIndex); ++ u16 w_value = le16_to_cpu(cr->wValue); ++ u8 entity_id = (w_index >> 8) & 0xff; ++ u8 control_selector = w_value >> 8; ++ ++ if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || ++ (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { ++ memcpy(&uac1->setup_cr, cr, sizeof(*cr)); ++ req->context = audio; ++ req->complete = out_rq_cur_complete; ++ ++ return w_length; ++ } else { ++ dev_err(&audio->gadget->dev, ++ "%s:%d entity_id=%d control_selector=%d TODO!\n", ++ __func__, __LINE__, entity_id, control_selector); ++ } ++ return -EOPNOTSUPP; ++} ++ ++static int ac_rq_in(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); ++ ++ DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", ++ ctrl->bRequest, w_value, len, ep); ++ ++ switch (ctrl->bRequest) { ++ case UAC_GET_CUR: ++ return in_rq_cur(f, ctrl); ++ case UAC_GET_MIN: ++ return in_rq_min(f, ctrl); ++ case UAC_GET_MAX: ++ return in_rq_max(f, ctrl); ++ case UAC_GET_RES: ++ return in_rq_res(f, ctrl); ++ case UAC_GET_MEM: ++ break; ++ case UAC_GET_STAT: ++ value = len; ++ break; ++ default: ++ break; ++ } ++ ++ return value; ++} ++ + static int audio_set_endpoint_req(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) + { +@@ -411,7 +788,13 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) + case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: + value = audio_get_endpoint_req(f, ctrl); + break; +- ++ case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE: ++ if (ctrl->bRequest == UAC_SET_CUR) ++ value = out_rq_cur(f, ctrl); ++ break; ++ case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE: ++ value = ac_rq_in(f, ctrl); ++ break; + default: + ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, +@@ -439,6 +822,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_gadget *gadget = cdev->gadget; + struct device *dev = &gadget->dev; ++ struct g_audio *audio = func_to_g_audio(f); + struct f_uac1 *uac1 = func_to_uac1(f); + int ret = 0; + +@@ -454,6 +838,14 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return -EINVAL; + } ++ ++ /* restart interrupt endpoint */ ++ if (uac1->int_ep) { ++ usb_ep_disable(uac1->int_ep); ++ config_ep_by_speed(gadget, &audio->func, uac1->int_ep); ++ usb_ep_enable(uac1->int_ep); ++ } ++ + return 0; + } + +@@ -509,9 +901,159 @@ static void f_audio_disable(struct usb_function *f) + + u_audio_stop_playback(&uac1->g_audio); + u_audio_stop_capture(&uac1->g_audio); ++ if (uac1->int_ep) ++ usb_ep_disable(uac1->int_ep); + } + + /*-------------------------------------------------------------------------*/ ++static struct uac_feature_unit_descriptor *build_fu_desc(int chmask) ++{ ++ struct uac_feature_unit_descriptor *fu_desc; ++ int channels = num_channels(chmask); ++ int fu_desc_size = UAC_DT_FEATURE_UNIT_SIZE(channels); ++ ++ fu_desc = kzalloc(fu_desc_size, GFP_KERNEL); ++ if (!fu_desc) ++ return NULL; ++ ++ fu_desc->bLength = fu_desc_size; ++ fu_desc->bDescriptorType = USB_DT_CS_INTERFACE; ++ ++ fu_desc->bDescriptorSubtype = UAC_FEATURE_UNIT; ++ fu_desc->bControlSize = 2; ++ ++ /* bUnitID, bSourceID and bmaControls will be defined later */ ++ ++ return fu_desc; ++} ++ ++/* B.3.2 Class-Specific AC Interface Descriptor */ ++static struct ++uac1_ac_header_descriptor *build_ac_header_desc(struct f_uac1_opts *opts) ++{ ++ struct uac1_ac_header_descriptor *ac_desc; ++ int ac_header_desc_size; ++ int num_ifaces = 0; ++ ++ if (EPOUT_EN(opts)) ++ num_ifaces++; ++ if (EPIN_EN(opts)) ++ num_ifaces++; ++ ++ ac_header_desc_size = UAC_DT_AC_HEADER_SIZE(num_ifaces); ++ ++ ac_desc = kzalloc(ac_header_desc_size, GFP_KERNEL); ++ if (!ac_desc) ++ return NULL; ++ ++ ac_desc->bLength = ac_header_desc_size; ++ ac_desc->bDescriptorType = USB_DT_CS_INTERFACE; ++ ac_desc->bDescriptorSubtype = UAC_HEADER; ++ ac_desc->bcdADC = cpu_to_le16(0x0100); ++ ac_desc->bInCollection = num_ifaces; ++ ++ /* wTotalLength and baInterfaceNr will be defined later */ ++ ++ return ac_desc; ++} ++ ++/* Use macro to overcome line length limitation */ ++#define USBDHDR(p) (struct usb_descriptor_header *)(p) ++ ++static void setup_descriptor(struct f_uac1_opts *opts) ++{ ++ /* patch descriptors */ ++ int i = 1; /* ID's start with 1 */ ++ ++ if (EPOUT_EN(opts)) ++ usb_out_it_desc.bTerminalID = i++; ++ if (EPIN_EN(opts)) ++ io_in_it_desc.bTerminalID = i++; ++ if (EPOUT_EN(opts)) ++ io_out_ot_desc.bTerminalID = i++; ++ if (EPIN_EN(opts)) ++ usb_in_ot_desc.bTerminalID = i++; ++ if (FUOUT_EN(opts)) ++ out_feature_unit_desc->bUnitID = i++; ++ if (FUIN_EN(opts)) ++ in_feature_unit_desc->bUnitID = i++; ++ ++ if (FUIN_EN(opts)) { ++ usb_in_ot_desc.bSourceID = in_feature_unit_desc->bUnitID; ++ in_feature_unit_desc->bSourceID = io_in_it_desc.bTerminalID; ++ } else { ++ usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; ++ } ++ if (FUOUT_EN(opts)) { ++ io_out_ot_desc.bSourceID = out_feature_unit_desc->bUnitID; ++ out_feature_unit_desc->bSourceID = usb_out_it_desc.bTerminalID; ++ } else { ++ io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; ++ } ++ ++ as_out_header_desc.bTerminalLink = usb_out_it_desc.bTerminalID; ++ as_in_header_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; ++ ++ ac_header_desc->wTotalLength = cpu_to_le16(ac_header_desc->bLength); ++ ++ if (EPIN_EN(opts)) { ++ u16 len = le16_to_cpu(ac_header_desc->wTotalLength); ++ ++ len += sizeof(usb_in_ot_desc); ++ len += sizeof(io_in_it_desc); ++ if (FUIN_EN(opts)) ++ len += in_feature_unit_desc->bLength; ++ ac_header_desc->wTotalLength = cpu_to_le16(len); ++ } ++ if (EPOUT_EN(opts)) { ++ u16 len = le16_to_cpu(ac_header_desc->wTotalLength); ++ ++ len += sizeof(usb_out_it_desc); ++ len += sizeof(io_out_ot_desc); ++ if (FUOUT_EN(opts)) ++ len += out_feature_unit_desc->bLength; ++ ac_header_desc->wTotalLength = cpu_to_le16(len); ++ } ++ ++ i = 0; ++ f_audio_desc[i++] = USBDHDR(&ac_interface_desc); ++ f_audio_desc[i++] = USBDHDR(ac_header_desc); ++ ++ if (EPOUT_EN(opts)) { ++ f_audio_desc[i++] = USBDHDR(&usb_out_it_desc); ++ f_audio_desc[i++] = USBDHDR(&io_out_ot_desc); ++ if (FUOUT_EN(opts)) ++ f_audio_desc[i++] = USBDHDR(out_feature_unit_desc); ++ } ++ ++ if (EPIN_EN(opts)) { ++ f_audio_desc[i++] = USBDHDR(&io_in_it_desc); ++ f_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); ++ if (FUIN_EN(opts)) ++ f_audio_desc[i++] = USBDHDR(in_feature_unit_desc); ++ } ++ ++ if (FUOUT_EN(opts) || FUIN_EN(opts)) ++ f_audio_desc[i++] = USBDHDR(&ac_int_ep_desc); ++ ++ if (EPOUT_EN(opts)) { ++ f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_0_desc); ++ f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_1_desc); ++ f_audio_desc[i++] = USBDHDR(&as_out_header_desc); ++ f_audio_desc[i++] = USBDHDR(&as_out_type_i_desc); ++ f_audio_desc[i++] = USBDHDR(&as_out_ep_desc); ++ f_audio_desc[i++] = USBDHDR(&as_iso_out_desc); ++ } ++ if (EPIN_EN(opts)) { ++ f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_0_desc); ++ f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_1_desc); ++ f_audio_desc[i++] = USBDHDR(&as_in_header_desc); ++ f_audio_desc[i++] = USBDHDR(&as_in_type_i_desc); ++ f_audio_desc[i++] = USBDHDR(&as_in_ep_desc); ++ f_audio_desc[i++] = USBDHDR(&as_iso_in_desc); ++ } ++ f_audio_desc[i] = NULL; ++} + + static int f_audio_validate_opts(struct g_audio *audio, struct device *dev) + { +@@ -540,6 +1082,28 @@ static int f_audio_validate_opts(struct g_audio *audio, struct device *dev) + return -EINVAL; + } + ++ if (opts->p_volume_max <= opts->p_volume_min) { ++ dev_err(dev, "Error: incorrect playback volume max/min\n"); ++ return -EINVAL; ++ } else if (opts->c_volume_max <= opts->c_volume_min) { ++ dev_err(dev, "Error: incorrect capture volume max/min\n"); ++ return -EINVAL; ++ } else if (opts->p_volume_res <= 0) { ++ dev_err(dev, "Error: negative/zero playback volume resolution\n"); ++ return -EINVAL; ++ } else if (opts->c_volume_res <= 0) { ++ dev_err(dev, "Error: negative/zero capture volume resolution\n"); ++ return -EINVAL; ++ } ++ ++ if ((opts->p_volume_max - opts->p_volume_min) % opts->p_volume_res) { ++ dev_err(dev, "Error: incorrect playback volume resolution\n"); ++ return -EINVAL; ++ } else if ((opts->c_volume_max - opts->c_volume_min) % opts->c_volume_res) { ++ dev_err(dev, "Error: incorrect capture volume resolution\n"); ++ return -EINVAL; ++ } ++ + return 0; + } + +@@ -556,6 +1120,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) + struct usb_string *us; + u8 *sam_freq; + int rate; ++ int ba_iface_id; + int status; + + status = f_audio_validate_opts(audio, dev); +@@ -567,6 +1132,26 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) + us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1)); + if (IS_ERR(us)) + return PTR_ERR(us); ++ ++ ac_header_desc = build_ac_header_desc(audio_opts); ++ if (!ac_header_desc) ++ return -ENOMEM; ++ ++ if (FUOUT_EN(audio_opts)) { ++ out_feature_unit_desc = build_fu_desc(audio_opts->c_chmask); ++ if (!out_feature_unit_desc) { ++ status = -ENOMEM; ++ goto fail; ++ } ++ } ++ if (FUIN_EN(audio_opts)) { ++ in_feature_unit_desc = build_fu_desc(audio_opts->p_chmask); ++ if (!in_feature_unit_desc) { ++ status = -ENOMEM; ++ goto err_free_fu; ++ } ++ } ++ + ac_interface_desc.iInterface = us[STR_AC_IF].id; + usb_out_it_desc.iTerminal = us[STR_USB_OUT_IT].id; + usb_out_it_desc.iChannelNames = us[STR_USB_OUT_IT_CH_NAMES].id; +@@ -579,6 +1164,21 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) + as_in_interface_alt_0_desc.iInterface = us[STR_AS_IN_IF_ALT0].id; + as_in_interface_alt_1_desc.iInterface = us[STR_AS_IN_IF_ALT1].id; + ++ if (FUOUT_EN(audio_opts)) { ++ u8 *i_feature; ++ ++ i_feature = (u8 *)out_feature_unit_desc + ++ out_feature_unit_desc->bLength - 1; ++ *i_feature = us[STR_FU_OUT].id; ++ } ++ if (FUIN_EN(audio_opts)) { ++ u8 *i_feature; ++ ++ i_feature = (u8 *)in_feature_unit_desc + ++ in_feature_unit_desc->bLength - 1; ++ *i_feature = us[STR_FU_IN].id; ++ } ++ + /* Set channel numbers */ + usb_out_it_desc.bNrChannels = num_channels(audio_opts->c_chmask); + usb_out_it_desc.wChannelConfig = cpu_to_le16(audio_opts->c_chmask); +@@ -591,6 +1191,27 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) + as_in_type_i_desc.bSubframeSize = audio_opts->p_ssize; + as_in_type_i_desc.bBitResolution = audio_opts->p_ssize * 8; + ++ if (FUOUT_EN(audio_opts)) { ++ __le16 *bma = (__le16 *)&out_feature_unit_desc->bmaControls[0]; ++ u32 control = 0; ++ ++ if (audio_opts->c_mute_present) ++ control |= UAC_FU_MUTE; ++ if (audio_opts->c_volume_present) ++ control |= UAC_FU_VOLUME; ++ *bma = cpu_to_le16(control); ++ } ++ if (FUIN_EN(audio_opts)) { ++ __le16 *bma = (__le16 *)&in_feature_unit_desc->bmaControls[0]; ++ u32 control = 0; ++ ++ if (audio_opts->p_mute_present) ++ control |= UAC_FU_MUTE; ++ if (audio_opts->p_volume_present) ++ control |= UAC_FU_VOLUME; ++ *bma = cpu_to_le16(control); ++ } ++ + /* Set sample rates */ + rate = audio_opts->c_srate; + sam_freq = as_out_type_i_desc.tSamFreq[0]; +@@ -602,61 +1223,106 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) + /* allocate instance-specific interface IDs, and patch descriptors */ + status = usb_interface_id(c, f); + if (status < 0) +- goto fail; ++ goto err_free_fu; + ac_interface_desc.bInterfaceNumber = status; + uac1->ac_intf = status; + uac1->ac_alt = 0; + +- status = usb_interface_id(c, f); +- if (status < 0) +- goto fail; +- as_out_interface_alt_0_desc.bInterfaceNumber = status; +- as_out_interface_alt_1_desc.bInterfaceNumber = status; +- ac_header_desc.baInterfaceNr[0] = status; +- uac1->as_out_intf = status; +- uac1->as_out_alt = 0; ++ ba_iface_id = 0; ++ ++ if (EPOUT_EN(audio_opts)) { ++ status = usb_interface_id(c, f); ++ if (status < 0) ++ goto err_free_fu; ++ as_out_interface_alt_0_desc.bInterfaceNumber = status; ++ as_out_interface_alt_1_desc.bInterfaceNumber = status; ++ ac_header_desc->baInterfaceNr[ba_iface_id++] = status; ++ uac1->as_out_intf = status; ++ uac1->as_out_alt = 0; ++ } + +- status = usb_interface_id(c, f); +- if (status < 0) +- goto fail; +- as_in_interface_alt_0_desc.bInterfaceNumber = status; +- as_in_interface_alt_1_desc.bInterfaceNumber = status; +- ac_header_desc.baInterfaceNr[1] = status; +- uac1->as_in_intf = status; +- uac1->as_in_alt = 0; ++ if (EPIN_EN(audio_opts)) { ++ status = usb_interface_id(c, f); ++ if (status < 0) ++ goto err_free_fu; ++ as_in_interface_alt_0_desc.bInterfaceNumber = status; ++ as_in_interface_alt_1_desc.bInterfaceNumber = status; ++ ac_header_desc->baInterfaceNr[ba_iface_id++] = status; ++ uac1->as_in_intf = status; ++ uac1->as_in_alt = 0; ++ } + + audio->gadget = gadget; + + status = -ENODEV; + ++ ac_interface_desc.bNumEndpoints = 0; ++ ++ /* allocate AC interrupt endpoint */ ++ if (FUOUT_EN(audio_opts) || FUIN_EN(audio_opts)) { ++ ep = usb_ep_autoconfig(cdev->gadget, &ac_int_ep_desc); ++ if (!ep) ++ goto err_free_fu; ++ uac1->int_ep = ep; ++ uac1->int_ep->desc = &ac_int_ep_desc; ++ ++ ac_interface_desc.bNumEndpoints = 1; ++ } ++ + /* allocate instance-specific endpoints */ +- ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); +- if (!ep) +- goto fail; +- audio->out_ep = ep; +- audio->out_ep->desc = &as_out_ep_desc; +- +- ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); +- if (!ep) +- goto fail; +- audio->in_ep = ep; +- audio->in_ep->desc = &as_in_ep_desc; ++ if (EPOUT_EN(audio_opts)) { ++ ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); ++ if (!ep) ++ goto err_free_fu; ++ audio->out_ep = ep; ++ audio->out_ep->desc = &as_out_ep_desc; ++ } ++ ++ if (EPIN_EN(audio_opts)) { ++ ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); ++ if (!ep) ++ goto err_free_fu; ++ audio->in_ep = ep; ++ audio->in_ep->desc = &as_in_ep_desc; ++ } ++ ++ setup_descriptor(audio_opts); + + /* copy descriptors, and track endpoint copies */ + status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL, + NULL); + if (status) +- goto fail; ++ goto err_free_fu; + + audio->out_ep_maxpsize = le16_to_cpu(as_out_ep_desc.wMaxPacketSize); + audio->in_ep_maxpsize = le16_to_cpu(as_in_ep_desc.wMaxPacketSize); + audio->params.c_chmask = audio_opts->c_chmask; + audio->params.c_srate = audio_opts->c_srate; + audio->params.c_ssize = audio_opts->c_ssize; ++ if (FUIN_EN(audio_opts)) { ++ audio->params.p_fu.id = USB_IN_FU_ID; ++ audio->params.p_fu.mute_present = audio_opts->p_mute_present; ++ audio->params.p_fu.volume_present = ++ audio_opts->p_volume_present; ++ audio->params.p_fu.volume_min = audio_opts->p_volume_min; ++ audio->params.p_fu.volume_max = audio_opts->p_volume_max; ++ audio->params.p_fu.volume_res = audio_opts->p_volume_res; ++ } + audio->params.p_chmask = audio_opts->p_chmask; + audio->params.p_srate = audio_opts->p_srate; + audio->params.p_ssize = audio_opts->p_ssize; ++ if (FUOUT_EN(audio_opts)) { ++ audio->params.c_fu.id = USB_OUT_FU_ID; ++ audio->params.c_fu.mute_present = audio_opts->c_mute_present; ++ audio->params.c_fu.volume_present = ++ audio_opts->c_volume_present; ++ audio->params.c_fu.volume_min = audio_opts->c_volume_min; ++ audio->params.c_fu.volume_max = audio_opts->c_volume_max; ++ audio->params.c_fu.volume_res = audio_opts->c_volume_res; ++ } + audio->params.req_number = audio_opts->req_number; ++ if (FUOUT_EN(audio_opts) || FUIN_EN(audio_opts)) ++ audio->notify = audio_notify; + + status = g_audio_setup(audio, "UAC1_PCM", "UAC1_Gadget"); + if (status) +@@ -666,7 +1332,14 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) + + err_card_register: + usb_free_all_descriptors(f); ++err_free_fu: ++ kfree(out_feature_unit_desc); ++ out_feature_unit_desc = NULL; ++ kfree(in_feature_unit_desc); ++ in_feature_unit_desc = NULL; + fail: ++ kfree(ac_header_desc); ++ ac_header_desc = NULL; + return status; + } + +@@ -689,7 +1362,15 @@ static struct configfs_item_operations f_uac1_item_ops = { + .release = f_uac1_attr_release, + }; + +-#define UAC1_ATTRIBUTE(name) \ ++#define uac1_kstrtou32 kstrtou32 ++#define uac1_kstrtos16 kstrtos16 ++#define uac1_kstrtobool(s, base, res) kstrtobool((s), (res)) ++ ++static const char *u32_fmt = "%u\n"; ++static const char *s16_fmt = "%hd\n"; ++static const char *bool_fmt = "%u\n"; ++ ++#define UAC1_ATTRIBUTE(type, name) \ + static ssize_t f_uac1_opts_##name##_show( \ + struct config_item *item, \ + char *page) \ +@@ -698,7 +1379,7 @@ static ssize_t f_uac1_opts_##name##_show( \ + int result; \ + \ + mutex_lock(&opts->lock); \ +- result = sprintf(page, "%u\n", opts->name); \ ++ result = sprintf(page, type##_fmt, opts->name); \ + mutex_unlock(&opts->lock); \ + \ + return result; \ +@@ -710,7 +1391,7 @@ static ssize_t f_uac1_opts_##name##_store( \ + { \ + struct f_uac1_opts *opts = to_f_uac1_opts(item); \ + int ret; \ +- u32 num; \ ++ type num; \ + \ + mutex_lock(&opts->lock); \ + if (opts->refcnt) { \ +@@ -718,7 +1399,7 @@ static ssize_t f_uac1_opts_##name##_store( \ + goto end; \ + } \ + \ +- ret = kstrtou32(page, 0, &num); \ ++ ret = uac1_kstrto##type(page, 0, &num); \ + if (ret) \ + goto end; \ + \ +@@ -732,13 +1413,25 @@ end: \ + \ + CONFIGFS_ATTR(f_uac1_opts_, name) + +-UAC1_ATTRIBUTE(c_chmask); +-UAC1_ATTRIBUTE(c_srate); +-UAC1_ATTRIBUTE(c_ssize); +-UAC1_ATTRIBUTE(p_chmask); +-UAC1_ATTRIBUTE(p_srate); +-UAC1_ATTRIBUTE(p_ssize); +-UAC1_ATTRIBUTE(req_number); ++UAC1_ATTRIBUTE(u32, c_chmask); ++UAC1_ATTRIBUTE(u32, c_srate); ++UAC1_ATTRIBUTE(u32, c_ssize); ++UAC1_ATTRIBUTE(u32, p_chmask); ++UAC1_ATTRIBUTE(u32, p_srate); ++UAC1_ATTRIBUTE(u32, p_ssize); ++UAC1_ATTRIBUTE(u32, req_number); ++ ++UAC1_ATTRIBUTE(bool, p_mute_present); ++UAC1_ATTRIBUTE(bool, p_volume_present); ++UAC1_ATTRIBUTE(s16, p_volume_min); ++UAC1_ATTRIBUTE(s16, p_volume_max); ++UAC1_ATTRIBUTE(s16, p_volume_res); ++ ++UAC1_ATTRIBUTE(bool, c_mute_present); ++UAC1_ATTRIBUTE(bool, c_volume_present); ++UAC1_ATTRIBUTE(s16, c_volume_min); ++UAC1_ATTRIBUTE(s16, c_volume_max); ++UAC1_ATTRIBUTE(s16, c_volume_res); + + static struct configfs_attribute *f_uac1_attrs[] = { + &f_uac1_opts_attr_c_chmask, +@@ -748,6 +1441,19 @@ static struct configfs_attribute *f_uac1_attrs[] = { + &f_uac1_opts_attr_p_srate, + &f_uac1_opts_attr_p_ssize, + &f_uac1_opts_attr_req_number, ++ ++ &f_uac1_opts_attr_p_mute_present, ++ &f_uac1_opts_attr_p_volume_present, ++ &f_uac1_opts_attr_p_volume_min, ++ &f_uac1_opts_attr_p_volume_max, ++ &f_uac1_opts_attr_p_volume_res, ++ ++ &f_uac1_opts_attr_c_mute_present, ++ &f_uac1_opts_attr_c_volume_present, ++ &f_uac1_opts_attr_c_volume_min, ++ &f_uac1_opts_attr_c_volume_max, ++ &f_uac1_opts_attr_c_volume_res, ++ + NULL, + }; + +@@ -785,6 +1491,19 @@ static struct usb_function_instance *f_audio_alloc_inst(void) + opts->p_chmask = UAC1_DEF_PCHMASK; + opts->p_srate = UAC1_DEF_PSRATE; + opts->p_ssize = UAC1_DEF_PSSIZE; ++ ++ opts->p_mute_present = UAC1_DEF_MUTE_PRESENT; ++ opts->p_volume_present = UAC1_DEF_VOLUME_PRESENT; ++ opts->p_volume_min = UAC1_DEF_MIN_DB; ++ opts->p_volume_max = UAC1_DEF_MAX_DB; ++ opts->p_volume_res = UAC1_DEF_RES_DB; ++ ++ opts->c_mute_present = UAC1_DEF_MUTE_PRESENT; ++ opts->c_volume_present = UAC1_DEF_VOLUME_PRESENT; ++ opts->c_volume_min = UAC1_DEF_MIN_DB; ++ opts->c_volume_max = UAC1_DEF_MAX_DB; ++ opts->c_volume_res = UAC1_DEF_RES_DB; ++ + opts->req_number = UAC1_DEF_REQ_NUM; + return &opts->func_inst; + } +@@ -809,6 +1528,14 @@ static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f) + g_audio_cleanup(audio); + usb_free_all_descriptors(f); + ++ kfree(out_feature_unit_desc); ++ out_feature_unit_desc = NULL; ++ kfree(in_feature_unit_desc); ++ in_feature_unit_desc = NULL; ++ ++ kfree(ac_header_desc); ++ ac_header_desc = NULL; ++ + audio->gadget = NULL; + } + +@@ -841,4 +1568,4 @@ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi) + + DECLARE_USB_FUNCTION_INIT(uac1, f_audio_alloc_inst, f_audio_alloc); + MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Ruslan Bilovol"); ++MODULE_AUTHOR("Ruslan Bilovol"); +\ No newline at end of file +diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c +index 11cc6056b..5226a47b6 100644 +--- a/drivers/usb/gadget/function/f_uac2.c ++++ b/drivers/usb/gadget/function/f_uac2.c +@@ -5,6 +5,9 @@ + * Copyright (C) 2011 + * Yadwinder Singh (yadi.brar01@gmail.com) + * Jaswinder Singh (jaswinder.singh@linaro.org) ++ * ++ * Copyright (C) 2020 ++ * Ruslan Bilovol (ruslan.bilovol@gmail.com) + */ + + #include +@@ -19,14 +22,16 @@ + + /* + * The driver implements a simple UAC_2 topology. +- * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture +- * ALSA_Playback -> IT_2 -> OT_4 -> USB-IN ++ * USB-OUT -> IT_1 -> FU -> OT_3 -> ALSA_Capture ++ * ALSA_Playback -> IT_2 -> FU -> OT_4 -> USB-IN + * Capture and Playback sampling rates are independently + * controlled by two clock sources : + * CLK_5 := c_srate, and CLK_6 := p_srate + */ + #define USB_OUT_CLK_ID (out_clk_src_desc.bClockID) + #define USB_IN_CLK_ID (in_clk_src_desc.bClockID) ++#define USB_OUT_FU_ID (out_feature_unit_desc->bUnitID) ++#define USB_IN_FU_ID (in_feature_unit_desc->bUnitID) + + #define CONTROL_ABSENT 0 + #define CONTROL_RDONLY 1 +@@ -34,6 +39,8 @@ + + #define CLK_FREQ_CTRL 0 + #define CLK_VLD_CTRL 2 ++#define FU_MUTE_CTRL 0 ++#define FU_VOL_CTRL 2 + + #define COPY_CTRL 0 + #define CONN_CTRL 2 +@@ -44,11 +51,24 @@ + + #define EPIN_EN(_opts) ((_opts)->p_chmask != 0) + #define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) ++#define FUIN_EN(_opts) (EPIN_EN(_opts) \ ++ && ((_opts)->p_mute_present \ ++ || (_opts)->p_volume_present)) ++#define FUOUT_EN(_opts) (EPOUT_EN(_opts) \ ++ && ((_opts)->c_mute_present \ ++ || (_opts)->c_volume_present)) ++#define EPOUT_FBACK_IN_EN(_opts) ((_opts)->c_sync == USB_ENDPOINT_SYNC_ASYNC) + + struct f_uac2 { + struct g_audio g_audio; + u8 ac_intf, as_in_intf, as_out_intf; + u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ ++ ++ struct usb_ctrlrequest setup_cr; /* will be used in data stage */ ++ ++ /* Interrupt IN endpoint of AC interface */ ++ struct usb_ep *int_ep; ++ atomic_t int_count; + }; + + static inline struct f_uac2 *func_to_uac2(struct usb_function *f) +@@ -62,6 +82,8 @@ struct f_uac2_opts *g_audio_to_uac2_opts(struct g_audio *agdev) + return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); + } + ++static int afunc_notify(struct g_audio *agdev, int unit_id, int cs); ++ + /* --------- USB Function Interface ------------- */ + + enum { +@@ -73,6 +95,8 @@ enum { + STR_IO_IT, + STR_USB_OT, + STR_IO_OT, ++ STR_FU_IN, ++ STR_FU_OUT, + STR_AS_OUT_ALT0, + STR_AS_OUT_ALT1, + STR_AS_IN_ALT0, +@@ -91,6 +115,8 @@ static struct usb_string strings_fn[] = { + [STR_IO_IT].s = "USBD Out", + [STR_USB_OT].s = "USBH In", + [STR_IO_OT].s = "USBD In", ++ [STR_FU_IN].s = "Capture Volume", ++ [STR_FU_OUT].s = "Playback Volume", + [STR_AS_OUT_ALT0].s = "Playback Inactive", + [STR_AS_OUT_ALT1].s = "Playback Active", + [STR_AS_IN_ALT0].s = "Capture Inactive", +@@ -125,7 +151,7 @@ static struct usb_interface_descriptor std_ac_if_desc = { + .bDescriptorType = USB_DT_INTERFACE, + + .bAlternateSetting = 0, +- .bNumEndpoints = 0, ++ /* .bNumEndpoints = DYNAMIC */ + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, + .bInterfaceProtocol = UAC_VERSION_2, +@@ -211,6 +237,9 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = { + .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), + }; + ++static struct uac2_feature_unit_descriptor *in_feature_unit_desc; ++static struct uac2_feature_unit_descriptor *out_feature_unit_desc; ++ + static struct uac2_ac_header_descriptor ac_hdr_desc = { + .bLength = sizeof ac_hdr_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, +@@ -222,6 +251,36 @@ static struct uac2_ac_header_descriptor ac_hdr_desc = { + .bmControls = 0, + }; + ++/* AC IN Interrupt Endpoint */ ++static struct usb_endpoint_descriptor fs_ep_int_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_INT, ++ .wMaxPacketSize = cpu_to_le16(6), ++ .bInterval = 1, ++}; ++ ++static struct usb_endpoint_descriptor hs_ep_int_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bmAttributes = USB_ENDPOINT_XFER_INT, ++ .wMaxPacketSize = cpu_to_le16(6), ++ .bInterval = 4, ++}; ++ ++static struct usb_endpoint_descriptor ss_ep_int_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_INT, ++ .wMaxPacketSize = cpu_to_le16(6), ++ .bInterval = 4, ++}; ++ + /* Audio Streaming OUT Interface - Alt0 */ + static struct usb_interface_descriptor std_as_out_if0_desc = { + .bLength = sizeof std_as_out_if0_desc, +@@ -273,7 +332,7 @@ static struct usb_endpoint_descriptor fs_epout_desc = { + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, +- .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, ++ /* .bmAttributes = DYNAMIC */ + /* .wMaxPacketSize = DYNAMIC */ + .bInterval = 1, + }; +@@ -282,11 +341,29 @@ static struct usb_endpoint_descriptor hs_epout_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + +- .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, ++ /* .bmAttributes = DYNAMIC */ ++ /* .wMaxPacketSize = DYNAMIC */ ++ .bInterval = 4, ++}; ++ ++static struct usb_endpoint_descriptor ss_epout_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bEndpointAddress = USB_DIR_OUT, ++ /* .bmAttributes = DYNAMIC */ + /* .wMaxPacketSize = DYNAMIC */ + .bInterval = 4, + }; + ++static struct usb_ss_ep_comp_descriptor ss_epout_desc_comp = { ++ .bLength = sizeof(ss_epout_desc_comp), ++ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, ++ .bMaxBurst = 0, ++ .bmAttributes = 0, ++ /* wBytesPerInterval = DYNAMIC */ ++}; ++ + /* CS AS ISO OUT Endpoint */ + static struct uac2_iso_endpoint_descriptor as_iso_out_desc = { + .bLength = sizeof as_iso_out_desc, +@@ -299,6 +376,45 @@ static struct uac2_iso_endpoint_descriptor as_iso_out_desc = { + .wLockDelay = 0, + }; + ++/* STD AS ISO IN Feedback Endpoint */ ++static struct usb_endpoint_descriptor fs_epin_fback_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, ++ .wMaxPacketSize = cpu_to_le16(3), ++ .bInterval = 1, ++}; ++ ++static struct usb_endpoint_descriptor hs_epin_fback_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, ++ .wMaxPacketSize = cpu_to_le16(4), ++ .bInterval = 4, ++}; ++ ++static struct usb_endpoint_descriptor ss_epin_fback_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, ++ .wMaxPacketSize = cpu_to_le16(4), ++ .bInterval = 4, ++}; ++ ++static struct usb_ss_ep_comp_descriptor ss_epin_fback_desc_comp = { ++ .bLength = sizeof(ss_epin_fback_desc_comp), ++ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, ++ .bMaxBurst = 0, ++ .bmAttributes = 0, ++ .wBytesPerInterval = cpu_to_le16(4), ++}; ++ ++ + /* Audio Streaming IN Interface - Alt0 */ + static struct usb_interface_descriptor std_as_in_if0_desc = { + .bLength = sizeof std_as_in_if0_desc, +@@ -364,6 +480,24 @@ static struct usb_endpoint_descriptor hs_epin_desc = { + .bInterval = 4, + }; + ++static struct usb_endpoint_descriptor ss_epin_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bEndpointAddress = USB_DIR_IN, ++ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, ++ /* .wMaxPacketSize = DYNAMIC */ ++ .bInterval = 4, ++}; ++ ++static struct usb_ss_ep_comp_descriptor ss_epin_desc_comp = { ++ .bLength = sizeof(ss_epin_desc_comp), ++ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, ++ .bMaxBurst = 0, ++ .bmAttributes = 0, ++ /* wBytesPerInterval = DYNAMIC */ ++}; ++ + /* CS AS ISO IN Endpoint */ + static struct uac2_iso_endpoint_descriptor as_iso_in_desc = { + .bLength = sizeof as_iso_in_desc, +@@ -384,10 +518,14 @@ static struct usb_descriptor_header *fs_audio_desc[] = { + (struct usb_descriptor_header *)&in_clk_src_desc, + (struct usb_descriptor_header *)&out_clk_src_desc, + (struct usb_descriptor_header *)&usb_out_it_desc, ++ (struct usb_descriptor_header *)&out_feature_unit_desc, + (struct usb_descriptor_header *)&io_in_it_desc, + (struct usb_descriptor_header *)&usb_in_ot_desc, ++ (struct usb_descriptor_header *)&in_feature_unit_desc, + (struct usb_descriptor_header *)&io_out_ot_desc, + ++ (struct usb_descriptor_header *)&fs_ep_int_desc, ++ + (struct usb_descriptor_header *)&std_as_out_if0_desc, + (struct usb_descriptor_header *)&std_as_out_if1_desc, + +@@ -395,6 +533,7 @@ static struct usb_descriptor_header *fs_audio_desc[] = { + (struct usb_descriptor_header *)&as_out_fmt1_desc, + (struct usb_descriptor_header *)&fs_epout_desc, + (struct usb_descriptor_header *)&as_iso_out_desc, ++ (struct usb_descriptor_header *)&fs_epin_fback_desc, + + (struct usb_descriptor_header *)&std_as_in_if0_desc, + (struct usb_descriptor_header *)&std_as_in_if1_desc, +@@ -414,10 +553,14 @@ static struct usb_descriptor_header *hs_audio_desc[] = { + (struct usb_descriptor_header *)&in_clk_src_desc, + (struct usb_descriptor_header *)&out_clk_src_desc, + (struct usb_descriptor_header *)&usb_out_it_desc, ++ (struct usb_descriptor_header *)&out_feature_unit_desc, + (struct usb_descriptor_header *)&io_in_it_desc, + (struct usb_descriptor_header *)&usb_in_ot_desc, ++ (struct usb_descriptor_header *)&in_feature_unit_desc, + (struct usb_descriptor_header *)&io_out_ot_desc, + ++ (struct usb_descriptor_header *)&hs_ep_int_desc, ++ + (struct usb_descriptor_header *)&std_as_out_if0_desc, + (struct usb_descriptor_header *)&std_as_out_if1_desc, + +@@ -425,6 +568,7 @@ static struct usb_descriptor_header *hs_audio_desc[] = { + (struct usb_descriptor_header *)&as_out_fmt1_desc, + (struct usb_descriptor_header *)&hs_epout_desc, + (struct usb_descriptor_header *)&as_iso_out_desc, ++ (struct usb_descriptor_header *)&hs_epin_fback_desc, + + (struct usb_descriptor_header *)&std_as_in_if0_desc, + (struct usb_descriptor_header *)&std_as_in_if1_desc, +@@ -436,6 +580,55 @@ static struct usb_descriptor_header *hs_audio_desc[] = { + NULL, + }; + ++static struct usb_descriptor_header *ss_audio_desc[] = { ++ (struct usb_descriptor_header *)&iad_desc, ++ (struct usb_descriptor_header *)&std_ac_if_desc, ++ ++ (struct usb_descriptor_header *)&ac_hdr_desc, ++ (struct usb_descriptor_header *)&in_clk_src_desc, ++ (struct usb_descriptor_header *)&out_clk_src_desc, ++ (struct usb_descriptor_header *)&usb_out_it_desc, ++ (struct usb_descriptor_header *)&out_feature_unit_desc, ++ (struct usb_descriptor_header *)&io_in_it_desc, ++ (struct usb_descriptor_header *)&usb_in_ot_desc, ++ (struct usb_descriptor_header *)&in_feature_unit_desc, ++ (struct usb_descriptor_header *)&io_out_ot_desc, ++ ++ (struct usb_descriptor_header *)&ss_ep_int_desc, ++ ++ (struct usb_descriptor_header *)&std_as_out_if0_desc, ++ (struct usb_descriptor_header *)&std_as_out_if1_desc, ++ ++ (struct usb_descriptor_header *)&as_out_hdr_desc, ++ (struct usb_descriptor_header *)&as_out_fmt1_desc, ++ (struct usb_descriptor_header *)&ss_epout_desc, ++ (struct usb_descriptor_header *)&ss_epout_desc_comp, ++ (struct usb_descriptor_header *)&as_iso_out_desc, ++ (struct usb_descriptor_header *)&ss_epin_fback_desc, ++ (struct usb_descriptor_header *)&ss_epin_fback_desc_comp, ++ ++ (struct usb_descriptor_header *)&std_as_in_if0_desc, ++ (struct usb_descriptor_header *)&std_as_in_if1_desc, ++ ++ (struct usb_descriptor_header *)&as_in_hdr_desc, ++ (struct usb_descriptor_header *)&as_in_fmt1_desc, ++ (struct usb_descriptor_header *)&ss_epin_desc, ++ (struct usb_descriptor_header *)&ss_epin_desc_comp, ++ (struct usb_descriptor_header *)&as_iso_in_desc, ++ NULL, ++}; ++ ++struct cntrl_cur_lay2 { ++ __le16 wCUR; ++}; ++ ++struct cntrl_range_lay2 { ++ __le16 wNumSubRanges; ++ __le16 wMIN; ++ __le16 wMAX; ++ __le16 wRES; ++} __packed; ++ + struct cntrl_cur_lay3 { + __le32 dCUR; + }; +@@ -462,6 +655,7 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, + break; + + case USB_SPEED_HIGH: ++ case USB_SPEED_SUPER: + max_size_ep = 1024; + factor = 8000; + break; +@@ -480,17 +674,143 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, + ssize = uac2_opts->c_ssize; + } + +- max_size_bw = num_channels(chmask) * ssize * +- ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); ++ if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) { ++ // Win10 requires max packet size + 1 frame ++ srate = srate * (1000 + uac2_opts->fb_max) / 1000; ++ // updated srate is always bigger, therefore DIV_ROUND_UP always yields +1 ++ max_size_bw = num_channels(chmask) * ssize * ++ (DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)))); ++ } else { ++ // adding 1 frame provision for Win10 ++ max_size_bw = num_channels(chmask) * ssize * ++ (DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))) + 1); ++ } + ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, + max_size_ep)); + + return 0; + } + ++static struct uac2_feature_unit_descriptor *build_fu_desc(int chmask) ++{ ++ struct uac2_feature_unit_descriptor *fu_desc; ++ int channels = num_channels(chmask); ++ int fu_desc_size = UAC2_DT_FEATURE_UNIT_SIZE(channels); ++ ++ fu_desc = kzalloc(fu_desc_size, GFP_KERNEL); ++ if (!fu_desc) ++ return NULL; ++ ++ fu_desc->bLength = fu_desc_size; ++ fu_desc->bDescriptorType = USB_DT_CS_INTERFACE; ++ ++ fu_desc->bDescriptorSubtype = UAC_FEATURE_UNIT; ++ ++ /* bUnitID, bSourceID and bmaControls will be defined later */ ++ ++ return fu_desc; ++} ++ + /* Use macro to overcome line length limitation */ + #define USBDHDR(p) (struct usb_descriptor_header *)(p) + ++static void setup_headers(struct f_uac2_opts *opts, ++ struct usb_descriptor_header **headers, ++ enum usb_device_speed speed) ++{ ++ struct usb_ss_ep_comp_descriptor *epout_desc_comp = NULL; ++ struct usb_ss_ep_comp_descriptor *epin_desc_comp = NULL; ++ struct usb_ss_ep_comp_descriptor *epin_fback_desc_comp = NULL; ++ struct usb_endpoint_descriptor *epout_desc; ++ struct usb_endpoint_descriptor *epin_desc; ++ struct usb_endpoint_descriptor *epin_fback_desc; ++ struct usb_endpoint_descriptor *ep_int_desc; ++ int i; ++ ++ switch (speed) { ++ case USB_SPEED_FULL: ++ epout_desc = &fs_epout_desc; ++ epin_desc = &fs_epin_desc; ++ epin_fback_desc = &fs_epin_fback_desc; ++ ep_int_desc = &fs_ep_int_desc; ++ break; ++ case USB_SPEED_HIGH: ++ epout_desc = &hs_epout_desc; ++ epin_desc = &hs_epin_desc; ++ epin_fback_desc = &hs_epin_fback_desc; ++ ep_int_desc = &hs_ep_int_desc; ++ break; ++ default: ++ epout_desc = &ss_epout_desc; ++ epin_desc = &ss_epin_desc; ++ epout_desc_comp = &ss_epout_desc_comp; ++ epin_desc_comp = &ss_epin_desc_comp; ++ epin_fback_desc = &ss_epin_fback_desc; ++ epin_fback_desc_comp = &ss_epin_fback_desc_comp; ++ ep_int_desc = &ss_ep_int_desc; ++ } ++ ++ i = 0; ++ headers[i++] = USBDHDR(&iad_desc); ++ headers[i++] = USBDHDR(&std_ac_if_desc); ++ headers[i++] = USBDHDR(&ac_hdr_desc); ++ if (EPIN_EN(opts)) ++ headers[i++] = USBDHDR(&in_clk_src_desc); ++ if (EPOUT_EN(opts)) { ++ headers[i++] = USBDHDR(&out_clk_src_desc); ++ headers[i++] = USBDHDR(&usb_out_it_desc); ++ ++ if (FUOUT_EN(opts)) ++ headers[i++] = USBDHDR(out_feature_unit_desc); ++ } ++ ++ if (EPIN_EN(opts)) { ++ headers[i++] = USBDHDR(&io_in_it_desc); ++ ++ if (FUIN_EN(opts)) ++ headers[i++] = USBDHDR(in_feature_unit_desc); ++ ++ headers[i++] = USBDHDR(&usb_in_ot_desc); ++ } ++ ++ if (EPOUT_EN(opts)) ++ headers[i++] = USBDHDR(&io_out_ot_desc); ++ ++ if (FUOUT_EN(opts) || FUIN_EN(opts)) ++ headers[i++] = USBDHDR(ep_int_desc); ++ ++ if (EPOUT_EN(opts)) { ++ headers[i++] = USBDHDR(&std_as_out_if0_desc); ++ headers[i++] = USBDHDR(&std_as_out_if1_desc); ++ headers[i++] = USBDHDR(&as_out_hdr_desc); ++ headers[i++] = USBDHDR(&as_out_fmt1_desc); ++ headers[i++] = USBDHDR(epout_desc); ++ if (epout_desc_comp) ++ headers[i++] = USBDHDR(epout_desc_comp); ++ ++ headers[i++] = USBDHDR(&as_iso_out_desc); ++ ++ if (EPOUT_FBACK_IN_EN(opts)) { ++ headers[i++] = USBDHDR(epin_fback_desc); ++ if (epin_fback_desc_comp) ++ headers[i++] = USBDHDR(epin_fback_desc_comp); ++ } ++ } ++ ++ if (EPIN_EN(opts)) { ++ headers[i++] = USBDHDR(&std_as_in_if0_desc); ++ headers[i++] = USBDHDR(&std_as_in_if1_desc); ++ headers[i++] = USBDHDR(&as_in_hdr_desc); ++ headers[i++] = USBDHDR(&as_in_fmt1_desc); ++ headers[i++] = USBDHDR(epin_desc); ++ if (epin_desc_comp) ++ headers[i++] = USBDHDR(epin_desc_comp); ++ ++ headers[i++] = USBDHDR(&as_iso_in_desc); ++ } ++ headers[i] = NULL; ++} ++ + static void setup_descriptor(struct f_uac2_opts *opts) + { + /* patch descriptors */ +@@ -504,17 +824,35 @@ static void setup_descriptor(struct f_uac2_opts *opts) + io_out_ot_desc.bTerminalID = i++; + if (EPIN_EN(opts)) + usb_in_ot_desc.bTerminalID = i++; ++ if (FUOUT_EN(opts)) ++ out_feature_unit_desc->bUnitID = i++; ++ if (FUIN_EN(opts)) ++ in_feature_unit_desc->bUnitID = i++; + if (EPOUT_EN(opts)) + out_clk_src_desc.bClockID = i++; + if (EPIN_EN(opts)) + in_clk_src_desc.bClockID = i++; + + usb_out_it_desc.bCSourceID = out_clk_src_desc.bClockID; +- usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; ++ ++ if (FUIN_EN(opts)) { ++ usb_in_ot_desc.bSourceID = in_feature_unit_desc->bUnitID; ++ in_feature_unit_desc->bSourceID = io_in_it_desc.bTerminalID; ++ } else { ++ usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; ++ } ++ + usb_in_ot_desc.bCSourceID = in_clk_src_desc.bClockID; + io_in_it_desc.bCSourceID = in_clk_src_desc.bClockID; + io_out_ot_desc.bCSourceID = out_clk_src_desc.bClockID; +- io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; ++ ++ if (FUOUT_EN(opts)) { ++ io_out_ot_desc.bSourceID = out_feature_unit_desc->bUnitID; ++ out_feature_unit_desc->bSourceID = usb_out_it_desc.bTerminalID; ++ } else { ++ io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; ++ } ++ + as_out_hdr_desc.bTerminalLink = usb_out_it_desc.bTerminalID; + as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; + +@@ -526,6 +864,10 @@ static void setup_descriptor(struct f_uac2_opts *opts) + + len += sizeof(in_clk_src_desc); + len += sizeof(usb_in_ot_desc); ++ ++ if (FUIN_EN(opts)) ++ len += in_feature_unit_desc->bLength; ++ + len += sizeof(io_in_it_desc); + ac_hdr_desc.wTotalLength = cpu_to_le16(len); + iad_desc.bInterfaceCount++; +@@ -535,76 +877,18 @@ static void setup_descriptor(struct f_uac2_opts *opts) + + len += sizeof(out_clk_src_desc); + len += sizeof(usb_out_it_desc); ++ ++ if (FUOUT_EN(opts)) ++ len += out_feature_unit_desc->bLength; ++ + len += sizeof(io_out_ot_desc); + ac_hdr_desc.wTotalLength = cpu_to_le16(len); + iad_desc.bInterfaceCount++; + } + +- i = 0; +- fs_audio_desc[i++] = USBDHDR(&iad_desc); +- fs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); +- fs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); +- if (EPIN_EN(opts)) +- fs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); +- if (EPOUT_EN(opts)) { +- fs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); +- fs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); +- } +- if (EPIN_EN(opts)) { +- fs_audio_desc[i++] = USBDHDR(&io_in_it_desc); +- fs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); +- } +- if (EPOUT_EN(opts)) { +- fs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); +- fs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); +- fs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); +- fs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); +- fs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); +- fs_audio_desc[i++] = USBDHDR(&fs_epout_desc); +- fs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); +- } +- if (EPIN_EN(opts)) { +- fs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); +- fs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); +- fs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); +- fs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); +- fs_audio_desc[i++] = USBDHDR(&fs_epin_desc); +- fs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); +- } +- fs_audio_desc[i] = NULL; +- +- i = 0; +- hs_audio_desc[i++] = USBDHDR(&iad_desc); +- hs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); +- hs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); +- if (EPIN_EN(opts)) +- hs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); +- if (EPOUT_EN(opts)) { +- hs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); +- hs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); +- } +- if (EPIN_EN(opts)) { +- hs_audio_desc[i++] = USBDHDR(&io_in_it_desc); +- hs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); +- } +- if (EPOUT_EN(opts)) { +- hs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); +- hs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); +- hs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); +- hs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); +- hs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); +- hs_audio_desc[i++] = USBDHDR(&hs_epout_desc); +- hs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); +- } +- if (EPIN_EN(opts)) { +- hs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); +- hs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); +- hs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); +- hs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); +- hs_audio_desc[i++] = USBDHDR(&hs_epin_desc); +- hs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); +- } +- hs_audio_desc[i] = NULL; ++ setup_headers(opts, fs_audio_desc, USB_SPEED_FULL); ++ setup_headers(opts, hs_audio_desc, USB_SPEED_HIGH); ++ setup_headers(opts, ss_audio_desc, USB_SPEED_SUPER); + } + + static int afunc_validate_opts(struct g_audio *agdev, struct device *dev) +@@ -634,6 +918,28 @@ static int afunc_validate_opts(struct g_audio *agdev, struct device *dev) + return -EINVAL; + } + ++ if (opts->p_volume_max <= opts->p_volume_min) { ++ dev_err(dev, "Error: incorrect playback volume max/min\n"); ++ return -EINVAL; ++ } else if (opts->c_volume_max <= opts->c_volume_min) { ++ dev_err(dev, "Error: incorrect capture volume max/min\n"); ++ return -EINVAL; ++ } else if (opts->p_volume_res <= 0) { ++ dev_err(dev, "Error: negative/zero playback volume resolution\n"); ++ return -EINVAL; ++ } else if (opts->c_volume_res <= 0) { ++ dev_err(dev, "Error: negative/zero capture volume resolution\n"); ++ return -EINVAL; ++ } ++ ++ if ((opts->p_volume_max - opts->p_volume_min) % opts->p_volume_res) { ++ dev_err(dev, "Error: incorrect playback volume resolution\n"); ++ return -EINVAL; ++ } else if ((opts->c_volume_max - opts->c_volume_min) % opts->c_volume_res) { ++ dev_err(dev, "Error: incorrect capture volume resolution\n"); ++ return -EINVAL; ++ } ++ + return 0; + } + +@@ -656,6 +962,20 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) + us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn)); + if (IS_ERR(us)) + return PTR_ERR(us); ++ ++ if (FUOUT_EN(uac2_opts)) { ++ out_feature_unit_desc = build_fu_desc(uac2_opts->c_chmask); ++ if (!out_feature_unit_desc) ++ return -ENOMEM; ++ } ++ if (FUIN_EN(uac2_opts)) { ++ in_feature_unit_desc = build_fu_desc(uac2_opts->p_chmask); ++ if (!in_feature_unit_desc) { ++ ret = -ENOMEM; ++ goto err_free_fu; ++ } ++ } ++ + iad_desc.iFunction = us[STR_ASSOC].id; + std_ac_if_desc.iInterface = us[STR_IF_CTRL].id; + in_clk_src_desc.iClockSource = us[STR_CLKSRC_IN].id; +@@ -669,6 +989,17 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) + std_as_in_if0_desc.iInterface = us[STR_AS_IN_ALT0].id; + std_as_in_if1_desc.iInterface = us[STR_AS_IN_ALT1].id; + ++ if (FUOUT_EN(uac2_opts)) { ++ u8 *i_feature = (u8 *)out_feature_unit_desc + ++ out_feature_unit_desc->bLength - 1; ++ *i_feature = us[STR_FU_OUT].id; ++ } ++ if (FUIN_EN(uac2_opts)) { ++ u8 *i_feature = (u8 *)in_feature_unit_desc + ++ in_feature_unit_desc->bLength - 1; ++ *i_feature = us[STR_FU_IN].id; ++ } ++ + + /* Initialize the configurable parameters */ + usb_out_it_desc.bNrChannels = num_channels(uac2_opts->c_chmask); +@@ -683,6 +1014,26 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) + as_out_fmt1_desc.bBitResolution = uac2_opts->c_ssize * 8; + as_in_fmt1_desc.bSubslotSize = uac2_opts->p_ssize; + as_in_fmt1_desc.bBitResolution = uac2_opts->p_ssize * 8; ++ if (FUOUT_EN(uac2_opts)) { ++ __le32 *bma = (__le32 *)&out_feature_unit_desc->bmaControls[0]; ++ u32 control = 0; ++ ++ if (uac2_opts->c_mute_present) ++ control |= CONTROL_RDWR << FU_MUTE_CTRL; ++ if (uac2_opts->c_volume_present) ++ control |= CONTROL_RDWR << FU_VOL_CTRL; ++ *bma = cpu_to_le32(control); ++ } ++ if (FUIN_EN(uac2_opts)) { ++ __le32 *bma = (__le32 *)&in_feature_unit_desc->bmaControls[0]; ++ u32 control = 0; ++ ++ if (uac2_opts->p_mute_present) ++ control |= CONTROL_RDWR << FU_MUTE_CTRL; ++ if (uac2_opts->p_volume_present) ++ control |= CONTROL_RDWR << FU_VOL_CTRL; ++ *bma = cpu_to_le32(control); ++ } + + snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", uac2_opts->p_srate); + snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", uac2_opts->c_srate); +@@ -690,7 +1041,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) + ret = usb_interface_id(cfg, fn); + if (ret < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); +- return ret; ++ goto err_free_fu; + } + iad_desc.bFirstInterface = ret; + +@@ -702,19 +1053,36 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) + ret = usb_interface_id(cfg, fn); + if (ret < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); +- return ret; ++ goto err_free_fu; + } + std_as_out_if0_desc.bInterfaceNumber = ret; + std_as_out_if1_desc.bInterfaceNumber = ret; + uac2->as_out_intf = ret; + uac2->as_out_alt = 0; ++ ++ if (EPOUT_FBACK_IN_EN(uac2_opts)) { ++ fs_epout_desc.bmAttributes = ++ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC; ++ hs_epout_desc.bmAttributes = ++ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC; ++ ss_epout_desc.bmAttributes = ++ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC; ++ std_as_out_if1_desc.bNumEndpoints++; ++ } else { ++ fs_epout_desc.bmAttributes = ++ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE; ++ hs_epout_desc.bmAttributes = ++ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE; ++ ss_epout_desc.bmAttributes = ++ USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE; ++ } + } + + if (EPIN_EN(uac2_opts)) { + ret = usb_interface_id(cfg, fn); + if (ret < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); +- return ret; ++ goto err_free_fu; + } + std_as_in_if0_desc.bInterfaceNumber = ret; + std_as_in_if1_desc.bInterfaceNumber = ret; +@@ -722,6 +1090,17 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) + uac2->as_in_alt = 0; + } + ++ if (FUOUT_EN(uac2_opts) || FUIN_EN(uac2_opts)) { ++ uac2->int_ep = usb_ep_autoconfig(gadget, &fs_ep_int_desc); ++ if (!uac2->int_ep) { ++ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); ++ ret = -ENODEV; ++ goto err_free_fu; ++ } ++ ++ std_ac_if_desc.bNumEndpoints = 1; ++ } ++ + /* Calculate wMaxPacketSize according to audio bandwidth */ + ret = set_ep_max_packet_size(uac2_opts, &fs_epin_desc, USB_SPEED_FULL, + true); +@@ -751,11 +1130,36 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) + return ret; + } + ++ ret = set_ep_max_packet_size(uac2_opts, &ss_epin_desc, USB_SPEED_SUPER, ++ true); ++ if (ret < 0) { ++ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); ++ return ret; ++ } ++ ++ ret = set_ep_max_packet_size(uac2_opts, &ss_epout_desc, USB_SPEED_SUPER, ++ false); ++ if (ret < 0) { ++ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); ++ return ret; ++ } ++ + if (EPOUT_EN(uac2_opts)) { + agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); + if (!agdev->out_ep) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); +- return -ENODEV; ++ ret = -ENODEV; ++ goto err_free_fu; ++ } ++ if (EPOUT_FBACK_IN_EN(uac2_opts)) { ++ agdev->in_ep_fback = usb_ep_autoconfig(gadget, ++ &fs_epin_fback_desc); ++ if (!agdev->in_ep_fback) { ++ dev_err(dev, "%s:%d Error!\n", ++ __func__, __LINE__); ++ ret = -ENODEV; ++ goto err_free_fu; ++ } + } + } + +@@ -763,7 +1167,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) + agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); + if (!agdev->in_ep) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); +- return -ENODEV; ++ ret = -ENODEV; ++ goto err_free_fu; + } + } + +@@ -774,33 +1179,145 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) + le16_to_cpu(fs_epout_desc.wMaxPacketSize), + le16_to_cpu(hs_epout_desc.wMaxPacketSize)); + ++ agdev->in_ep_maxpsize = max_t(u16, agdev->in_ep_maxpsize, ++ le16_to_cpu(ss_epin_desc.wMaxPacketSize)); ++ agdev->out_ep_maxpsize = max_t(u16, agdev->out_ep_maxpsize, ++ le16_to_cpu(ss_epout_desc.wMaxPacketSize)); ++ ++ ss_epin_desc_comp.wBytesPerInterval = ss_epin_desc.wMaxPacketSize; ++ ss_epout_desc_comp.wBytesPerInterval = ss_epout_desc.wMaxPacketSize; ++ ++ // HS and SS endpoint addresses are copied from autoconfigured FS descriptors ++ hs_ep_int_desc.bEndpointAddress = fs_ep_int_desc.bEndpointAddress; + hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; ++ hs_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress; + hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; ++ ss_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; ++ ss_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress; ++ ss_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; ++ ss_ep_int_desc.bEndpointAddress = fs_ep_int_desc.bEndpointAddress; + + setup_descriptor(uac2_opts); + +- ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL, +- NULL); ++ ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, ss_audio_desc, ++ ss_audio_desc); + if (ret) +- return ret; ++ goto err_free_fu; + + agdev->gadget = gadget; + + agdev->params.p_chmask = uac2_opts->p_chmask; + agdev->params.p_srate = uac2_opts->p_srate; + agdev->params.p_ssize = uac2_opts->p_ssize; ++ if (FUIN_EN(uac2_opts)) { ++ agdev->params.p_fu.id = USB_IN_FU_ID; ++ agdev->params.p_fu.mute_present = uac2_opts->p_mute_present; ++ agdev->params.p_fu.volume_present = uac2_opts->p_volume_present; ++ agdev->params.p_fu.volume_min = uac2_opts->p_volume_min; ++ agdev->params.p_fu.volume_max = uac2_opts->p_volume_max; ++ agdev->params.p_fu.volume_res = uac2_opts->p_volume_res; ++ } + agdev->params.c_chmask = uac2_opts->c_chmask; + agdev->params.c_srate = uac2_opts->c_srate; + agdev->params.c_ssize = uac2_opts->c_ssize; ++ if (FUOUT_EN(uac2_opts)) { ++ agdev->params.c_fu.id = USB_OUT_FU_ID; ++ agdev->params.c_fu.mute_present = uac2_opts->c_mute_present; ++ agdev->params.c_fu.volume_present = uac2_opts->c_volume_present; ++ agdev->params.c_fu.volume_min = uac2_opts->c_volume_min; ++ agdev->params.c_fu.volume_max = uac2_opts->c_volume_max; ++ agdev->params.c_fu.volume_res = uac2_opts->c_volume_res; ++ } + agdev->params.req_number = uac2_opts->req_number; ++ agdev->params.fb_max = uac2_opts->fb_max; ++ ++ if (FUOUT_EN(uac2_opts) || FUIN_EN(uac2_opts)) ++ agdev->notify = afunc_notify; ++ + ret = g_audio_setup(agdev, "UAC2 PCM", "UAC2_Gadget"); + if (ret) + goto err_free_descs; ++ + return 0; + + err_free_descs: + usb_free_all_descriptors(fn); + agdev->gadget = NULL; ++err_free_fu: ++ kfree(out_feature_unit_desc); ++ out_feature_unit_desc = NULL; ++ kfree(in_feature_unit_desc); ++ in_feature_unit_desc = NULL; ++ return ret; ++} ++ ++static void ++afunc_notify_complete(struct usb_ep *_ep, struct usb_request *req) ++{ ++ struct g_audio *agdev = req->context; ++ struct f_uac2 *uac2 = func_to_uac2(&agdev->func); ++ ++ atomic_dec(&uac2->int_count); ++ kfree(req->buf); ++ usb_ep_free_request(_ep, req); ++} ++ ++static int ++afunc_notify(struct g_audio *agdev, int unit_id, int cs) ++{ ++ struct f_uac2 *uac2 = func_to_uac2(&agdev->func); ++ struct usb_request *req; ++ struct uac2_interrupt_data_msg *msg; ++ u16 w_index, w_value; ++ int ret; ++ ++ if (!uac2->int_ep->enabled) ++ return 0; ++ ++ if (atomic_inc_return(&uac2->int_count) > UAC2_DEF_INT_REQ_NUM) { ++ atomic_dec(&uac2->int_count); ++ return 0; ++ } ++ ++ req = usb_ep_alloc_request(uac2->int_ep, GFP_ATOMIC); ++ if (req == NULL) { ++ ret = -ENOMEM; ++ goto err_dec_int_count; ++ } ++ ++ msg = kzalloc(sizeof(*msg), GFP_ATOMIC); ++ if (msg == NULL) { ++ ret = -ENOMEM; ++ goto err_free_request; ++ } ++ ++ w_index = unit_id << 8 | uac2->ac_intf; ++ w_value = cs << 8; ++ ++ msg->bInfo = 0; /* Non-vendor, interface interrupt */ ++ msg->bAttribute = UAC2_CS_CUR; ++ msg->wIndex = cpu_to_le16(w_index); ++ msg->wValue = cpu_to_le16(w_value); ++ ++ req->length = sizeof(*msg); ++ req->buf = msg; ++ req->context = agdev; ++ req->complete = afunc_notify_complete; ++ ++ ret = usb_ep_queue(uac2->int_ep, req, GFP_ATOMIC); ++ ++ if (ret) ++ goto err_free_msg; ++ ++ return 0; ++ ++err_free_msg: ++ kfree(msg); ++err_free_request: ++ usb_ep_free_request(uac2->int_ep, req); ++err_dec_int_count: ++ atomic_dec(&uac2->int_count); ++ + return ret; + } + +@@ -809,6 +1326,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) + { + struct usb_composite_dev *cdev = fn->config->cdev; + struct f_uac2 *uac2 = func_to_uac2(fn); ++ struct g_audio *agdev = func_to_g_audio(fn); + struct usb_gadget *gadget = cdev->gadget; + struct device *dev = &gadget->dev; + int ret = 0; +@@ -825,6 +1343,14 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return -EINVAL; + } ++ ++ /* restart interrupt endpoint */ ++ if (uac2->int_ep) { ++ usb_ep_disable(uac2->int_ep); ++ config_ep_by_speed(gadget, &agdev->func, uac2->int_ep); ++ usb_ep_enable(uac2->int_ep); ++ } ++ + return 0; + } + +@@ -879,6 +1405,8 @@ afunc_disable(struct usb_function *fn) + uac2->as_out_alt = 0; + u_audio_stop_capture(&uac2->g_audio); + u_audio_stop_playback(&uac2->g_audio); ++ if (uac2->int_ep) ++ usb_ep_disable(uac2->int_ep); + } + + static int +@@ -886,7 +1414,7 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) + { + struct usb_request *req = fn->config->cdev->req; + struct g_audio *agdev = func_to_g_audio(fn); +- struct f_uac2_opts *opts; ++ struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); + u16 w_length = le16_to_cpu(cr->wLength); + u16 w_index = le16_to_cpu(cr->wIndex); + u16 w_value = le16_to_cpu(cr->wValue); +@@ -895,28 +1423,64 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) + int value = -EOPNOTSUPP; + int p_srate, c_srate; + +- opts = g_audio_to_uac2_opts(agdev); + p_srate = opts->p_srate; + c_srate = opts->c_srate; + +- if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { +- struct cntrl_cur_lay3 c; +- memset(&c, 0, sizeof(struct cntrl_cur_lay3)); ++ if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { ++ if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { ++ struct cntrl_cur_lay3 c; ++ ++ memset(&c, 0, sizeof(struct cntrl_cur_lay3)); ++ ++ if (entity_id == USB_IN_CLK_ID) ++ c.dCUR = cpu_to_le32(p_srate); ++ else if (entity_id == USB_OUT_CLK_ID) ++ c.dCUR = cpu_to_le32(c_srate); ++ ++ value = min_t(unsigned int, w_length, sizeof(c)); ++ memcpy(req->buf, &c, value); ++ } else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) { ++ *(u8 *)req->buf = 1; ++ value = min_t(unsigned int, w_length, 1); ++ } else { ++ dev_err(&agdev->gadget->dev, ++ "%s:%d control_selector=%d TODO!\n", ++ __func__, __LINE__, control_selector); ++ } ++ } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || ++ (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { ++ unsigned int is_playback = 0; ++ ++ if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) ++ is_playback = 1; ++ ++ if (control_selector == UAC_FU_MUTE) { ++ unsigned int mute; + +- if (entity_id == USB_IN_CLK_ID) +- c.dCUR = cpu_to_le32(p_srate); +- else if (entity_id == USB_OUT_CLK_ID) +- c.dCUR = cpu_to_le32(c_srate); ++ u_audio_get_mute(agdev, is_playback, &mute); + +- value = min_t(unsigned, w_length, sizeof c); +- memcpy(req->buf, &c, value); +- } else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) { +- *(u8 *)req->buf = 1; +- value = min_t(unsigned, w_length, 1); ++ *(u8 *)req->buf = mute; ++ value = min_t(unsigned int, w_length, 1); ++ } else if (control_selector == UAC_FU_VOLUME) { ++ struct cntrl_cur_lay2 c; ++ s16 volume; ++ ++ memset(&c, 0, sizeof(struct cntrl_cur_lay2)); ++ ++ u_audio_get_volume(agdev, is_playback, &volume); ++ c.wCUR = cpu_to_le16(volume); ++ ++ value = min_t(unsigned int, w_length, sizeof(c)); ++ memcpy(req->buf, &c, value); ++ } else { ++ dev_err(&agdev->gadget->dev, ++ "%s:%d control_selector=%d TODO!\n", ++ __func__, __LINE__, control_selector); ++ } + } else { + dev_err(&agdev->gadget->dev, +- "%s:%d control_selector=%d TODO!\n", +- __func__, __LINE__, control_selector); ++ "%s:%d entity_id=%d control_selector=%d TODO!\n", ++ __func__, __LINE__, entity_id, control_selector); + } + + return value; +@@ -927,38 +1491,77 @@ in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) + { + struct usb_request *req = fn->config->cdev->req; + struct g_audio *agdev = func_to_g_audio(fn); +- struct f_uac2_opts *opts; ++ struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); + u16 w_length = le16_to_cpu(cr->wLength); + u16 w_index = le16_to_cpu(cr->wIndex); + u16 w_value = le16_to_cpu(cr->wValue); + u8 entity_id = (w_index >> 8) & 0xff; + u8 control_selector = w_value >> 8; +- struct cntrl_range_lay3 r; + int value = -EOPNOTSUPP; + int p_srate, c_srate; + +- opts = g_audio_to_uac2_opts(agdev); + p_srate = opts->p_srate; + c_srate = opts->c_srate; + +- if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { +- if (entity_id == USB_IN_CLK_ID) +- r.dMIN = cpu_to_le32(p_srate); +- else if (entity_id == USB_OUT_CLK_ID) +- r.dMIN = cpu_to_le32(c_srate); +- else +- return -EOPNOTSUPP; ++ if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { ++ if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { ++ struct cntrl_range_lay3 r; ++ ++ if (entity_id == USB_IN_CLK_ID) ++ r.dMIN = cpu_to_le32(p_srate); ++ else if (entity_id == USB_OUT_CLK_ID) ++ r.dMIN = cpu_to_le32(c_srate); ++ else ++ return -EOPNOTSUPP; + +- r.dMAX = r.dMIN; +- r.dRES = 0; +- r.wNumSubRanges = cpu_to_le16(1); ++ r.dMAX = r.dMIN; ++ r.dRES = 0; ++ r.wNumSubRanges = cpu_to_le16(1); + +- value = min_t(unsigned, w_length, sizeof r); +- memcpy(req->buf, &r, value); ++ value = min_t(unsigned int, w_length, sizeof(r)); ++ memcpy(req->buf, &r, value); ++ } else { ++ dev_err(&agdev->gadget->dev, ++ "%s:%d control_selector=%d TODO!\n", ++ __func__, __LINE__, control_selector); ++ } ++ } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || ++ (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { ++ unsigned int is_playback = 0; ++ ++ if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) ++ is_playback = 1; ++ ++ if (control_selector == UAC_FU_VOLUME) { ++ struct cntrl_range_lay2 r; ++ s16 max_db, min_db, res_db; ++ ++ if (is_playback) { ++ max_db = opts->p_volume_max; ++ min_db = opts->p_volume_min; ++ res_db = opts->p_volume_res; ++ } else { ++ max_db = opts->c_volume_max; ++ min_db = opts->c_volume_min; ++ res_db = opts->c_volume_res; ++ } ++ ++ r.wMAX = cpu_to_le16(max_db); ++ r.wMIN = cpu_to_le16(min_db); ++ r.wRES = cpu_to_le16(res_db); ++ r.wNumSubRanges = cpu_to_le16(1); ++ ++ value = min_t(unsigned int, w_length, sizeof(r)); ++ memcpy(req->buf, &r, value); ++ } else { ++ dev_err(&agdev->gadget->dev, ++ "%s:%d control_selector=%d TODO!\n", ++ __func__, __LINE__, control_selector); ++ } + } else { + dev_err(&agdev->gadget->dev, +- "%s:%d control_selector=%d TODO!\n", +- __func__, __LINE__, control_selector); ++ "%s:%d entity_id=%d control_selector=%d TODO!\n", ++ __func__, __LINE__, entity_id, control_selector); + } + + return value; +@@ -975,16 +1578,82 @@ ac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr) + return -EOPNOTSUPP; + } + ++static void ++out_rq_cur_complete(struct usb_ep *ep, struct usb_request *req) ++{ ++ struct g_audio *agdev = req->context; ++ struct usb_composite_dev *cdev = agdev->func.config->cdev; ++ struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); ++ struct f_uac2 *uac2 = func_to_uac2(&agdev->func); ++ struct usb_ctrlrequest *cr = &uac2->setup_cr; ++ u16 w_index = le16_to_cpu(cr->wIndex); ++ u16 w_value = le16_to_cpu(cr->wValue); ++ u8 entity_id = (w_index >> 8) & 0xff; ++ u8 control_selector = w_value >> 8; ++ ++ if (req->status != 0) { ++ dev_dbg(&cdev->gadget->dev, "completion err %d\n", req->status); ++ return; ++ } ++ ++ if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || ++ (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { ++ unsigned int is_playback = 0; ++ ++ if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) ++ is_playback = 1; ++ ++ if (control_selector == UAC_FU_MUTE) { ++ u8 mute = *(u8 *)req->buf; ++ ++ u_audio_set_mute(agdev, is_playback, mute); ++ ++ return; ++ } else if (control_selector == UAC_FU_VOLUME) { ++ struct cntrl_cur_lay2 *c = req->buf; ++ s16 volume; ++ ++ volume = le16_to_cpu(c->wCUR); ++ u_audio_set_volume(agdev, is_playback, volume); ++ ++ return; ++ } else { ++ dev_err(&agdev->gadget->dev, ++ "%s:%d control_selector=%d TODO!\n", ++ __func__, __LINE__, control_selector); ++ usb_ep_set_halt(ep); ++ } ++ } ++} ++ + static int + out_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) + { ++ struct usb_request *req = fn->config->cdev->req; ++ struct g_audio *agdev = func_to_g_audio(fn); ++ struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); ++ struct f_uac2 *uac2 = func_to_uac2(fn); + u16 w_length = le16_to_cpu(cr->wLength); ++ u16 w_index = le16_to_cpu(cr->wIndex); + u16 w_value = le16_to_cpu(cr->wValue); ++ u8 entity_id = (w_index >> 8) & 0xff; + u8 control_selector = w_value >> 8; + +- if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) +- return w_length; ++ if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { ++ if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) ++ return w_length; ++ } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || ++ (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { ++ memcpy(&uac2->setup_cr, cr, sizeof(*cr)); ++ req->context = agdev; ++ req->complete = out_rq_cur_complete; + ++ return w_length; ++ } else { ++ dev_err(&agdev->gadget->dev, ++ "%s:%d entity_id=%d control_selector=%d TODO!\n", ++ __func__, __LINE__, entity_id, control_selector); ++ } + return -EOPNOTSUPP; + } + +@@ -1060,7 +1729,15 @@ static struct configfs_item_operations f_uac2_item_ops = { + .release = f_uac2_attr_release, + }; + +-#define UAC2_ATTRIBUTE(name) \ ++#define uac2_kstrtou32 kstrtou32 ++#define uac2_kstrtos16 kstrtos16 ++#define uac2_kstrtobool(s, base, res) kstrtobool((s), (res)) ++ ++static const char *u32_fmt = "%u\n"; ++static const char *s16_fmt = "%hd\n"; ++static const char *bool_fmt = "%u\n"; ++ ++#define UAC2_ATTRIBUTE(type, name) \ + static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ + char *page) \ + { \ +@@ -1068,7 +1745,7 @@ static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ + int result; \ + \ + mutex_lock(&opts->lock); \ +- result = sprintf(page, "%u\n", opts->name); \ ++ result = sprintf(page, type##_fmt, opts->name); \ + mutex_unlock(&opts->lock); \ + \ + return result; \ +@@ -1079,7 +1756,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ + { \ + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ + int ret; \ +- u32 num; \ ++ type num; \ + \ + mutex_lock(&opts->lock); \ + if (opts->refcnt) { \ +@@ -1087,7 +1764,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ + goto end; \ + } \ + \ +- ret = kstrtou32(page, 0, &num); \ ++ ret = uac2_kstrto##type(page, 0, &num); \ + if (ret) \ + goto end; \ + \ +@@ -1101,13 +1778,83 @@ end: \ + \ + CONFIGFS_ATTR(f_uac2_opts_, name) + +-UAC2_ATTRIBUTE(p_chmask); +-UAC2_ATTRIBUTE(p_srate); +-UAC2_ATTRIBUTE(p_ssize); +-UAC2_ATTRIBUTE(c_chmask); +-UAC2_ATTRIBUTE(c_srate); +-UAC2_ATTRIBUTE(c_ssize); +-UAC2_ATTRIBUTE(req_number); ++#define UAC2_ATTRIBUTE_SYNC(name) \ ++static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ ++ char *page) \ ++{ \ ++ struct f_uac2_opts *opts = to_f_uac2_opts(item); \ ++ int result; \ ++ char *str; \ ++ \ ++ mutex_lock(&opts->lock); \ ++ switch (opts->name) { \ ++ case USB_ENDPOINT_SYNC_ASYNC: \ ++ str = "async"; \ ++ break; \ ++ case USB_ENDPOINT_SYNC_ADAPTIVE: \ ++ str = "adaptive"; \ ++ break; \ ++ default: \ ++ str = "unknown"; \ ++ break; \ ++ } \ ++ result = sprintf(page, "%s\n", str); \ ++ mutex_unlock(&opts->lock); \ ++ \ ++ return result; \ ++} \ ++ \ ++static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ ++ const char *page, size_t len) \ ++{ \ ++ struct f_uac2_opts *opts = to_f_uac2_opts(item); \ ++ int ret = 0; \ ++ \ ++ mutex_lock(&opts->lock); \ ++ if (opts->refcnt) { \ ++ ret = -EBUSY; \ ++ goto end; \ ++ } \ ++ \ ++ if (!strncmp(page, "async", 5)) \ ++ opts->name = USB_ENDPOINT_SYNC_ASYNC; \ ++ else if (!strncmp(page, "adaptive", 8)) \ ++ opts->name = USB_ENDPOINT_SYNC_ADAPTIVE; \ ++ else { \ ++ ret = -EINVAL; \ ++ goto end; \ ++ } \ ++ \ ++ ret = len; \ ++ \ ++end: \ ++ mutex_unlock(&opts->lock); \ ++ return ret; \ ++} \ ++ \ ++CONFIGFS_ATTR(f_uac2_opts_, name) ++ ++UAC2_ATTRIBUTE(u32, p_chmask); ++UAC2_ATTRIBUTE(u32, p_srate); ++UAC2_ATTRIBUTE(u32, p_ssize); ++UAC2_ATTRIBUTE(u32, c_chmask); ++UAC2_ATTRIBUTE(u32, c_srate); ++UAC2_ATTRIBUTE_SYNC(c_sync); ++UAC2_ATTRIBUTE(u32, c_ssize); ++UAC2_ATTRIBUTE(u32, req_number); ++ ++UAC2_ATTRIBUTE(bool, p_mute_present); ++UAC2_ATTRIBUTE(bool, p_volume_present); ++UAC2_ATTRIBUTE(s16, p_volume_min); ++UAC2_ATTRIBUTE(s16, p_volume_max); ++UAC2_ATTRIBUTE(s16, p_volume_res); ++ ++UAC2_ATTRIBUTE(bool, c_mute_present); ++UAC2_ATTRIBUTE(bool, c_volume_present); ++UAC2_ATTRIBUTE(s16, c_volume_min); ++UAC2_ATTRIBUTE(s16, c_volume_max); ++UAC2_ATTRIBUTE(s16, c_volume_res); ++UAC2_ATTRIBUTE(u32, fb_max); + + static struct configfs_attribute *f_uac2_attrs[] = { + &f_uac2_opts_attr_p_chmask, +@@ -1116,7 +1863,22 @@ static struct configfs_attribute *f_uac2_attrs[] = { + &f_uac2_opts_attr_c_chmask, + &f_uac2_opts_attr_c_srate, + &f_uac2_opts_attr_c_ssize, ++ &f_uac2_opts_attr_c_sync, + &f_uac2_opts_attr_req_number, ++ &f_uac2_opts_attr_fb_max, ++ ++ &f_uac2_opts_attr_p_mute_present, ++ &f_uac2_opts_attr_p_volume_present, ++ &f_uac2_opts_attr_p_volume_min, ++ &f_uac2_opts_attr_p_volume_max, ++ &f_uac2_opts_attr_p_volume_res, ++ ++ &f_uac2_opts_attr_c_mute_present, ++ &f_uac2_opts_attr_c_volume_present, ++ &f_uac2_opts_attr_c_volume_min, ++ &f_uac2_opts_attr_c_volume_max, ++ &f_uac2_opts_attr_c_volume_res, ++ + NULL, + }; + +@@ -1154,7 +1916,22 @@ static struct usb_function_instance *afunc_alloc_inst(void) + opts->c_chmask = UAC2_DEF_CCHMASK; + opts->c_srate = UAC2_DEF_CSRATE; + opts->c_ssize = UAC2_DEF_CSSIZE; ++ opts->c_sync = UAC2_DEF_CSYNC; ++ ++ opts->p_mute_present = UAC2_DEF_MUTE_PRESENT; ++ opts->p_volume_present = UAC2_DEF_VOLUME_PRESENT; ++ opts->p_volume_min = UAC2_DEF_MIN_DB; ++ opts->p_volume_max = UAC2_DEF_MAX_DB; ++ opts->p_volume_res = UAC2_DEF_RES_DB; ++ ++ opts->c_mute_present = UAC2_DEF_MUTE_PRESENT; ++ opts->c_volume_present = UAC2_DEF_VOLUME_PRESENT; ++ opts->c_volume_min = UAC2_DEF_MIN_DB; ++ opts->c_volume_max = UAC2_DEF_MAX_DB; ++ opts->c_volume_res = UAC2_DEF_RES_DB; ++ + opts->req_number = UAC2_DEF_REQ_NUM; ++ opts->fb_max = UAC2_DEF_FB_MAX; + return &opts->func_inst; + } + +@@ -1179,6 +1956,11 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f) + usb_free_all_descriptors(f); + + agdev->gadget = NULL; ++ ++ kfree(out_feature_unit_desc); ++ out_feature_unit_desc = NULL; ++ kfree(in_feature_unit_desc); ++ in_feature_unit_desc = NULL; + } + + static struct usb_function *afunc_alloc(struct usb_function_instance *fi) +@@ -1211,3 +1993,4 @@ DECLARE_USB_FUNCTION_INIT(uac2, afunc_alloc_inst, afunc_alloc); + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Yadwinder Singh"); + MODULE_AUTHOR("Jaswinder Singh"); ++MODULE_AUTHOR("Ruslan Bilovol"); +diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c +index fecdba85a..762c646bf 100644 +--- a/drivers/usb/gadget/function/f_uvc.c ++++ b/drivers/usb/gadget/function/f_uvc.c +@@ -418,6 +418,7 @@ uvc_register_video(struct uvc_device *uvc) + + /* TODO reference counting. */ + uvc->vdev.v4l2_dev = &uvc->v4l2_dev; ++ uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev; + uvc->vdev.fops = &uvc_v4l2_fops; + uvc->vdev.ioctl_ops = &uvc_v4l2_ioctl_ops; + uvc->vdev.release = video_device_release_empty; +@@ -633,7 +634,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) + + uvc_hs_streaming_ep.wMaxPacketSize = + cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11)); +- + /* A high-bandwidth endpoint must specify a bInterval value of 1 */ + if (max_packet_mult > 1) + uvc_hs_streaming_ep.bInterval = 1; +diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c +index eef71a12f..65e3626e2 100644 +--- a/drivers/usb/gadget/function/rndis.c ++++ b/drivers/usb/gadget/function/rndis.c +@@ -506,10 +506,6 @@ static int gen_ndis_set_resp(struct rndis_params *params, u32 OID, + + switch (OID) { + case RNDIS_OID_GEN_CURRENT_PACKET_FILTER: +- if (buf_len < 2) { +- pr_err("%s:Not support for buf_len < 2\n", __func__); +- break; +- } + + /* these NDIS_PACKET_TYPE_* bitflags are shared with + * cdc_filter; it's not RNDIS-specific +@@ -596,7 +592,6 @@ static int rndis_query_response(struct rndis_params *params, + rndis_query_msg_type *buf) + { + rndis_query_cmplt_type *resp; +- u32 BufOffset, BufLength; + rndis_resp_t *r; + + /* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */ +@@ -617,25 +612,12 @@ static int rndis_query_response(struct rndis_params *params, + + resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C); + resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ +- BufOffset = le32_to_cpu(buf->InformationBufferOffset); +- BufLength = le32_to_cpu(buf->InformationBufferLength); +- +- /* +- * If the address of the buf to be accessed exceeds the valid +- * range of the buf, then return RNDIS_STATUS_NOT_SUPPORTED. +- */ +- if (8 + BufOffset + BufLength >= USB_COMP_EP0_BUFSIZ) { +- resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED); +- resp->MessageLength = cpu_to_le32(sizeof(*resp)); +- resp->InformationBufferLength = cpu_to_le32(0); +- resp->InformationBufferOffset = cpu_to_le32(0); +- params->resp_avail(params->v); +- return 0; +- } + + if (gen_ndis_query_resp(params, le32_to_cpu(buf->OID), +- BufOffset + 8 + (u8 *)buf, BufLength, +- r)) { ++ le32_to_cpu(buf->InformationBufferOffset) ++ + 8 + (u8 *)buf, ++ le32_to_cpu(buf->InformationBufferLength), ++ r)) { + /* OID not supported */ + resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED); + resp->MessageLength = cpu_to_le32(sizeof *resp); +@@ -655,18 +637,14 @@ static int rndis_set_response(struct rndis_params *params, + rndis_set_cmplt_type *resp; + rndis_resp_t *r; + +- BufLength = le32_to_cpu(buf->InformationBufferLength); +- BufOffset = le32_to_cpu(buf->InformationBufferOffset); +- if ((BufLength > RNDIS_MAX_TOTAL_SIZE) || +- (BufOffset > RNDIS_MAX_TOTAL_SIZE) || +- (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE)) +- return -EINVAL; +- + r = rndis_add_response(params, sizeof(rndis_set_cmplt_type)); + if (!r) + return -ENOMEM; + resp = (rndis_set_cmplt_type *)r->buf; + ++ BufLength = le32_to_cpu(buf->InformationBufferLength); ++ BufOffset = le32_to_cpu(buf->InformationBufferOffset); ++ + #ifdef VERBOSE_DEBUG + pr_debug("%s: Length: %d\n", __func__, BufLength); + pr_debug("%s: Offset: %d\n", __func__, BufOffset); +@@ -682,17 +660,6 @@ static int rndis_set_response(struct rndis_params *params, + resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C); + resp->MessageLength = cpu_to_le32(16); + resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ +- +- /* +- * If the address of the buf to be accessed exceeds the valid +- * range of the buf, then return RNDIS_STATUS_NOT_SUPPORTED. +- */ +- if (8 + BufOffset + BufLength >= USB_COMP_EP0_BUFSIZ) { +- resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED); +- params->resp_avail(params->v); +- return 0; +- } +- + if (gen_ndis_set_resp(params, le32_to_cpu(buf->OID), + ((u8 *)buf) + 8 + BufOffset, BufLength, r)) + resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED); +diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c +index 95605b1ef..7037a555c 100644 +--- a/drivers/usb/gadget/function/u_audio.c ++++ b/drivers/usb/gadget/function/u_audio.c +@@ -12,10 +12,14 @@ + * Jaswinder Singh (jaswinder.singh@linaro.org) + */ + ++#include + #include + #include + #include + #include ++#include ++#include ++#include + + #include "u_audio.h" + +@@ -23,9 +27,10 @@ + #define PRD_SIZE_MAX PAGE_SIZE + #define MIN_PERIODS 4 + +-struct uac_req { +- struct uac_rtd_params *pp; /* parent param */ +- struct usb_request *req; ++enum { ++ UAC_FBACK_CTRL, ++ UAC_MUTE_CTRL, ++ UAC_VOLUME_CTRL, + }; + + /* Runtime data params for one stream */ +@@ -40,10 +45,24 @@ struct uac_rtd_params { + + void *rbuf; + ++ unsigned int pitch; /* Stream pitch ratio to 1000000 */ + unsigned int max_psize; /* MaxPacketSize of endpoint */ +- struct uac_req *ureq; + +- spinlock_t lock; ++ struct usb_request **reqs; ++ ++ struct usb_request *req_fback; /* Feedback endpoint request */ ++ bool fb_ep_enabled; /* if the ep is enabled */ ++ ++ /* Volume/Mute controls and their state */ ++ int fu_id; /* Feature Unit ID */ ++ struct snd_kcontrol *snd_kctl_volume; ++ struct snd_kcontrol *snd_kctl_mute; ++ s16 volume_min, volume_max, volume_res; ++ s16 volume; ++ int mute; ++ ++ spinlock_t lock; /* lock for control transfers */ ++ + }; + + struct snd_uac_chip { +@@ -76,16 +95,63 @@ static const struct snd_pcm_hardware uac_pcm_hardware = { + .periods_min = MIN_PERIODS, + }; + ++static void u_audio_set_fback_frequency(enum usb_device_speed speed, ++ struct usb_ep *out_ep, ++ unsigned long long freq, ++ unsigned int pitch, ++ void *buf) ++{ ++ u32 ff = 0; ++ const struct usb_endpoint_descriptor *ep_desc; ++ ++ /* ++ * Because the pitch base is 1000000, the final divider here ++ * will be 1000 * 1000000 = 1953125 << 9 ++ * ++ * Instead of dealing with big numbers lets fold this 9 left shift ++ */ ++ ++ if (speed == USB_SPEED_FULL) { ++ /* ++ * Full-speed feedback endpoints report frequency ++ * in samples/frame ++ * Format is encoded in Q10.10 left-justified in the 24 bits, ++ * so that it has a Q10.14 format. ++ * ++ * ff = (freq << 14) / 1000 ++ */ ++ freq <<= 5; ++ } else { ++ /* ++ * High-speed feedback endpoints report frequency ++ * in samples/microframe. ++ * Format is encoded in Q12.13 fitted into four bytes so that ++ * the binary point is located between the second and the third ++ * byte fromat (that is Q16.16) ++ * ++ * ff = (freq << 16) / 8000 ++ * ++ * Win10 and OSX UAC2 drivers require number of samples per packet ++ * in order to honor the feedback value. ++ * Linux snd-usb-audio detects the applied bit-shift automatically. ++ */ ++ ep_desc = out_ep->desc; ++ freq <<= 4 + (ep_desc->bInterval - 1); ++ } ++ ++ ff = DIV_ROUND_CLOSEST_ULL((freq * pitch), 1953125); ++ ++ *(__le32 *)buf = cpu_to_le32(ff); ++} ++ + static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) + { + unsigned int pending; +- unsigned long flags, flags2; + unsigned int hw_ptr; + int status = req->status; +- struct uac_req *ur = req->context; + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; +- struct uac_rtd_params *prm = ur->pp; ++ struct uac_rtd_params *prm = req->context; + struct snd_uac_chip *uac = prm->uac; + + /* i/f shutting down */ +@@ -111,16 +177,14 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) + if (!substream) + goto exit; + +- snd_pcm_stream_lock_irqsave(substream, flags2); ++ snd_pcm_stream_lock(substream); + + runtime = substream->runtime; + if (!runtime || !snd_pcm_running(substream)) { +- snd_pcm_stream_unlock_irqrestore(substream, flags2); ++ snd_pcm_stream_unlock(substream); + goto exit; + } + +- spin_lock_irqsave(&prm->lock, flags); +- + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* + * For each IN packet, take the quotient of the current data +@@ -147,8 +211,6 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) + + hw_ptr = prm->hw_ptr; + +- spin_unlock_irqrestore(&prm->lock, flags); +- + /* Pack USB load in ALSA ring buffer */ + pending = runtime->dma_bytes - hw_ptr; + +@@ -172,12 +234,10 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) + } + } + +- spin_lock_irqsave(&prm->lock, flags); + /* update hw_ptr after data is copied to memory */ + prm->hw_ptr = (hw_ptr + req->actual) % runtime->dma_bytes; + hw_ptr = prm->hw_ptr; +- spin_unlock_irqrestore(&prm->lock, flags); +- snd_pcm_stream_unlock_irqrestore(substream, flags2); ++ snd_pcm_stream_unlock(substream); + + if ((hw_ptr % snd_pcm_lib_period_bytes(substream)) < req->actual) + snd_pcm_period_elapsed(substream); +@@ -187,13 +247,47 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) + dev_err(uac->card->dev, "%d Error!\n", __LINE__); + } + ++static void u_audio_iso_fback_complete(struct usb_ep *ep, ++ struct usb_request *req) ++{ ++ struct uac_rtd_params *prm = req->context; ++ struct snd_uac_chip *uac = prm->uac; ++ struct g_audio *audio_dev = uac->audio_dev; ++ struct uac_params *params = &audio_dev->params; ++ int status = req->status; ++ ++ /* i/f shutting down */ ++ if (!prm->fb_ep_enabled) { ++ kfree(req->buf); ++ usb_ep_free_request(ep, req); ++ return; ++ } ++ ++ if (req->status == -ESHUTDOWN) ++ return; ++ ++ /* ++ * We can't really do much about bad xfers. ++ * Afterall, the ISOCH xfers could fail legitimately. ++ */ ++ if (status) ++ pr_debug("%s: iso_complete status(%d) %d/%d\n", ++ __func__, status, req->actual, req->length); ++ ++ u_audio_set_fback_frequency(audio_dev->gadget->speed, audio_dev->out_ep, ++ params->c_srate, prm->pitch, ++ req->buf); ++ ++ if (usb_ep_queue(ep, req, GFP_ATOMIC)) ++ dev_err(uac->card->dev, "%d Error!\n", __LINE__); ++} ++ + static int uac_pcm_trigger(struct snd_pcm_substream *substream, int cmd) + { + struct snd_uac_chip *uac = snd_pcm_substream_chip(substream); + struct uac_rtd_params *prm; + struct g_audio *audio_dev; + struct uac_params *params; +- unsigned long flags; + int err = 0; + + audio_dev = uac->audio_dev; +@@ -204,8 +298,6 @@ static int uac_pcm_trigger(struct snd_pcm_substream *substream, int cmd) + else + prm = &uac->c_prm; + +- spin_lock_irqsave(&prm->lock, flags); +- + /* Reset */ + prm->hw_ptr = 0; + +@@ -222,8 +314,6 @@ static int uac_pcm_trigger(struct snd_pcm_substream *substream, int cmd) + err = -EINVAL; + } + +- spin_unlock_irqrestore(&prm->lock, flags); +- + /* Clear buffer after Play stops */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !prm->ss) + memset(prm->rbuf, 0, prm->max_psize * params->req_number); +@@ -244,6 +334,25 @@ static snd_pcm_uframes_t uac_pcm_pointer(struct snd_pcm_substream *substream) + return bytes_to_frames(substream->runtime, prm->hw_ptr); + } + ++static u64 uac_ssize_to_fmt(int ssize) ++{ ++ u64 ret; ++ ++ switch (ssize) { ++ case 3: ++ ret = SNDRV_PCM_FMTBIT_S24_3LE; ++ break; ++ case 4: ++ ret = SNDRV_PCM_FMTBIT_S32_LE; ++ break; ++ default: ++ ret = SNDRV_PCM_FMTBIT_S16_LE; ++ break; ++ } ++ ++ return ret; ++} ++ + static int uac_pcm_open(struct snd_pcm_substream *substream) + { + struct snd_uac_chip *uac = snd_pcm_substream_chip(substream); +@@ -267,36 +376,14 @@ static int uac_pcm_open(struct snd_pcm_substream *substream) + runtime->hw = uac_pcm_hardware; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { +- spin_lock_init(&uac->p_prm.lock); + runtime->hw.rate_min = p_srate; +- switch (p_ssize) { +- case 3: +- runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_3LE; +- break; +- case 4: +- runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; +- break; +- default: +- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; +- break; +- } ++ runtime->hw.formats = uac_ssize_to_fmt(p_ssize); + runtime->hw.channels_min = num_channels(p_chmask); + runtime->hw.period_bytes_min = 2 * uac->p_prm.max_psize + / runtime->hw.periods_min; + } else { +- spin_lock_init(&uac->c_prm.lock); + runtime->hw.rate_min = c_srate; +- switch (c_ssize) { +- case 3: +- runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_3LE; +- break; +- case 4: +- runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; +- break; +- default: +- runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; +- break; +- } ++ runtime->hw.formats = uac_ssize_to_fmt(c_ssize); + runtime->hw.channels_min = num_channels(c_chmask); + runtime->hw.period_bytes_min = 2 * uac->c_prm.max_psize + / runtime->hw.periods_min; +@@ -338,16 +425,16 @@ static inline void free_ep(struct uac_rtd_params *prm, struct usb_ep *ep) + params = &audio_dev->params; + + for (i = 0; i < params->req_number; i++) { +- if (prm->ureq[i].req) { +- if (usb_ep_dequeue(ep, prm->ureq[i].req)) +- usb_ep_free_request(ep, prm->ureq[i].req); ++ if (prm->reqs[i]) { ++ if (usb_ep_dequeue(ep, prm->reqs[i])) ++ usb_ep_free_request(ep, prm->reqs[i]); + /* + * If usb_ep_dequeue() cannot successfully dequeue the + * request, the request will be freed by the completion + * callback. + */ + +- prm->ureq[i].req = NULL; ++ prm->reqs[i] = NULL; + } + } + +@@ -357,13 +444,34 @@ static inline void free_ep(struct uac_rtd_params *prm, struct usb_ep *ep) + dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__); + } + ++static inline void free_ep_fback(struct uac_rtd_params *prm, struct usb_ep *ep) ++{ ++ struct snd_uac_chip *uac = prm->uac; ++ ++ if (!prm->fb_ep_enabled) ++ return; ++ ++ if (prm->req_fback) { ++ if (usb_ep_dequeue(ep, prm->req_fback)) { ++ kfree(prm->req_fback->buf); ++ usb_ep_free_request(ep, prm->req_fback); ++ } ++ prm->req_fback = NULL; ++ } ++ ++ prm->fb_ep_enabled = false; ++ ++ if (usb_ep_disable(ep)) ++ dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__); ++} ++ + int u_audio_start_capture(struct g_audio *audio_dev) + { + struct snd_uac_chip *uac = audio_dev->uac; + struct usb_gadget *gadget = audio_dev->gadget; + struct device *dev = &gadget->dev; +- struct usb_request *req; +- struct usb_ep *ep; ++ struct usb_request *req, *req_fback; ++ struct usb_ep *ep, *ep_fback; + struct uac_rtd_params *prm; + struct uac_params *params = &audio_dev->params; + int req_len, i; +@@ -377,25 +485,61 @@ int u_audio_start_capture(struct g_audio *audio_dev) + usb_ep_enable(ep); + + for (i = 0; i < params->req_number; i++) { +- if (!prm->ureq[i].req) { ++ if (!prm->reqs[i]) { + req = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (req == NULL) + return -ENOMEM; + +- prm->ureq[i].req = req; +- prm->ureq[i].pp = prm; ++ prm->reqs[i] = req; + + req->zero = 0; +- req->context = &prm->ureq[i]; ++ req->context = prm; + req->length = req_len; + req->complete = u_audio_iso_complete; + req->buf = prm->rbuf + i * ep->maxpacket; + } + +- if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC)) ++ if (usb_ep_queue(ep, prm->reqs[i], GFP_ATOMIC)) + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + } + ++ ep_fback = audio_dev->in_ep_fback; ++ if (!ep_fback) ++ return 0; ++ ++ /* Setup feedback endpoint */ ++ config_ep_by_speed(gadget, &audio_dev->func, ep_fback); ++ prm->fb_ep_enabled = true; ++ usb_ep_enable(ep_fback); ++ req_len = ep_fback->maxpacket; ++ ++ req_fback = usb_ep_alloc_request(ep_fback, GFP_ATOMIC); ++ if (req_fback == NULL) ++ return -ENOMEM; ++ ++ prm->req_fback = req_fback; ++ req_fback->zero = 0; ++ req_fback->context = prm; ++ req_fback->length = req_len; ++ req_fback->complete = u_audio_iso_fback_complete; ++ ++ req_fback->buf = kzalloc(req_len, GFP_ATOMIC); ++ if (!req_fback->buf) ++ return -ENOMEM; ++ ++ /* ++ * Configure the feedback endpoint's reported frequency. ++ * Always start with original frequency since its deviation can't ++ * be meauserd at start of playback ++ */ ++ prm->pitch = 1000000; ++ u_audio_set_fback_frequency(audio_dev->gadget->speed, ep, ++ params->c_srate, prm->pitch, ++ req_fback->buf); ++ ++ if (usb_ep_queue(ep_fback, req_fback, GFP_ATOMIC)) ++ dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); ++ + return 0; + } + EXPORT_SYMBOL_GPL(u_audio_start_capture); +@@ -404,6 +548,8 @@ void u_audio_stop_capture(struct g_audio *audio_dev) + { + struct snd_uac_chip *uac = audio_dev->uac; + ++ if (audio_dev->in_ep_fback) ++ free_ep_fback(&uac->c_prm, audio_dev->in_ep_fback); + free_ep(&uac->c_prm, audio_dev->out_ep); + } + EXPORT_SYMBOL_GPL(u_audio_stop_capture); +@@ -455,22 +601,21 @@ int u_audio_start_playback(struct g_audio *audio_dev) + usb_ep_enable(ep); + + for (i = 0; i < params->req_number; i++) { +- if (!prm->ureq[i].req) { ++ if (!prm->reqs[i]) { + req = usb_ep_alloc_request(ep, GFP_ATOMIC); + if (req == NULL) + return -ENOMEM; + +- prm->ureq[i].req = req; +- prm->ureq[i].pp = prm; ++ prm->reqs[i] = req; + + req->zero = 0; +- req->context = &prm->ureq[i]; ++ req->context = prm; + req->length = req_len; + req->complete = u_audio_iso_complete; + req->buf = prm->rbuf + i * ep->maxpacket; + } + +- if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC)) ++ if (usb_ep_queue(ep, prm->reqs[i], GFP_ATOMIC)) + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + } + +@@ -486,15 +631,326 @@ void u_audio_stop_playback(struct g_audio *audio_dev) + } + EXPORT_SYMBOL_GPL(u_audio_stop_playback); + ++int u_audio_get_volume(struct g_audio *audio_dev, int playback, s16 *val) ++{ ++ struct snd_uac_chip *uac = audio_dev->uac; ++ struct uac_rtd_params *prm; ++ unsigned long flags; ++ ++ if (playback) ++ prm = &uac->p_prm; ++ else ++ prm = &uac->c_prm; ++ ++ spin_lock_irqsave(&prm->lock, flags); ++ *val = prm->volume; ++ spin_unlock_irqrestore(&prm->lock, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(u_audio_get_volume); ++ ++int u_audio_set_volume(struct g_audio *audio_dev, int playback, s16 val) ++{ ++ struct snd_uac_chip *uac = audio_dev->uac; ++ struct uac_rtd_params *prm; ++ unsigned long flags; ++ int change = 0; ++ ++ if (playback) ++ prm = &uac->p_prm; ++ else ++ prm = &uac->c_prm; ++ ++ spin_lock_irqsave(&prm->lock, flags); ++ val = clamp(val, prm->volume_min, prm->volume_max); ++ if (prm->volume != val) { ++ prm->volume = val; ++ change = 1; ++ } ++ spin_unlock_irqrestore(&prm->lock, flags); ++ ++ if (change) ++ snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE, ++ &prm->snd_kctl_volume->id); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(u_audio_set_volume); ++ ++int u_audio_get_mute(struct g_audio *audio_dev, int playback, int *val) ++{ ++ struct snd_uac_chip *uac = audio_dev->uac; ++ struct uac_rtd_params *prm; ++ unsigned long flags; ++ ++ if (playback) ++ prm = &uac->p_prm; ++ else ++ prm = &uac->c_prm; ++ ++ spin_lock_irqsave(&prm->lock, flags); ++ *val = prm->mute; ++ spin_unlock_irqrestore(&prm->lock, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(u_audio_get_mute); ++ ++int u_audio_set_mute(struct g_audio *audio_dev, int playback, int val) ++{ ++ struct snd_uac_chip *uac = audio_dev->uac; ++ struct uac_rtd_params *prm; ++ unsigned long flags; ++ int change = 0; ++ int mute; ++ ++ if (playback) ++ prm = &uac->p_prm; ++ else ++ prm = &uac->c_prm; ++ ++ mute = val ? 1 : 0; ++ ++ spin_lock_irqsave(&prm->lock, flags); ++ if (prm->mute != mute) { ++ prm->mute = mute; ++ change = 1; ++ } ++ spin_unlock_irqrestore(&prm->lock, flags); ++ ++ if (change) ++ snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE, ++ &prm->snd_kctl_mute->id); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(u_audio_set_mute); ++ ++ ++static int u_audio_pitch_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); ++ struct snd_uac_chip *uac = prm->uac; ++ struct g_audio *audio_dev = uac->audio_dev; ++ struct uac_params *params = &audio_dev->params; ++ unsigned int pitch_min, pitch_max; ++ ++ pitch_min = (1000 - FBACK_SLOW_MAX) * 1000; ++ pitch_max = (1000 + params->fb_max) * 1000; ++ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = pitch_min; ++ uinfo->value.integer.max = pitch_max; ++ uinfo->value.integer.step = 1; ++ return 0; ++} ++ ++static int u_audio_pitch_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); ++ ++ ucontrol->value.integer.value[0] = prm->pitch; ++ ++ return 0; ++} ++ ++static int u_audio_pitch_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); ++ struct snd_uac_chip *uac = prm->uac; ++ struct g_audio *audio_dev = uac->audio_dev; ++ struct uac_params *params = &audio_dev->params; ++ unsigned int val; ++ unsigned int pitch_min, pitch_max; ++ int change = 0; ++ ++ pitch_min = (1000 - FBACK_SLOW_MAX) * 1000; ++ pitch_max = (1000 + params->fb_max) * 1000; ++ ++ val = ucontrol->value.integer.value[0]; ++ ++ if (val < pitch_min) ++ val = pitch_min; ++ if (val > pitch_max) ++ val = pitch_max; ++ ++ if (prm->pitch != val) { ++ prm->pitch = val; ++ change = 1; ++ } ++ ++ return change; ++} ++ ++static int u_audio_mute_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; ++ uinfo->count = 1; ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = 1; ++ uinfo->value.integer.step = 1; ++ ++ return 0; ++} ++ ++static int u_audio_mute_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&prm->lock, flags); ++ ucontrol->value.integer.value[0] = !prm->mute; ++ spin_unlock_irqrestore(&prm->lock, flags); ++ ++ return 0; ++} ++ ++static int u_audio_mute_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); ++ struct snd_uac_chip *uac = prm->uac; ++ struct g_audio *audio_dev = uac->audio_dev; ++ unsigned int val; ++ unsigned long flags; ++ int change = 0; ++ ++ val = !ucontrol->value.integer.value[0]; ++ ++ spin_lock_irqsave(&prm->lock, flags); ++ if (val != prm->mute) { ++ prm->mute = val; ++ change = 1; ++ } ++ spin_unlock_irqrestore(&prm->lock, flags); ++ ++ if (change && audio_dev->notify) ++ audio_dev->notify(audio_dev, prm->fu_id, UAC_FU_MUTE); ++ ++ return change; ++} ++ ++/* ++ * TLV callback for mixer volume controls ++ */ ++static int u_audio_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag, ++ unsigned int size, unsigned int __user *_tlv) ++{ ++ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); ++ DECLARE_TLV_DB_MINMAX(scale, 0, 0); ++ ++ if (size < sizeof(scale)) ++ return -ENOMEM; ++ ++ /* UAC volume resolution is 1/256 dB, TLV is 1/100 dB */ ++ scale[2] = (prm->volume_min * 100) / 256; ++ scale[3] = (prm->volume_max * 100) / 256; ++ if (copy_to_user(_tlv, scale, sizeof(scale))) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static int u_audio_volume_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); ++ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = ++ (prm->volume_max - prm->volume_min + prm->volume_res - 1) ++ / prm->volume_res; ++ uinfo->value.integer.step = 1; ++ ++ return 0; ++} ++ ++static int u_audio_volume_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&prm->lock, flags); ++ ucontrol->value.integer.value[0] = ++ (prm->volume - prm->volume_min) / prm->volume_res; ++ spin_unlock_irqrestore(&prm->lock, flags); ++ ++ return 0; ++} ++ ++static int u_audio_volume_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); ++ struct snd_uac_chip *uac = prm->uac; ++ struct g_audio *audio_dev = uac->audio_dev; ++ unsigned int val; ++ s16 volume; ++ unsigned long flags; ++ int change = 0; ++ ++ val = ucontrol->value.integer.value[0]; ++ ++ spin_lock_irqsave(&prm->lock, flags); ++ volume = (val * prm->volume_res) + prm->volume_min; ++ volume = clamp(volume, prm->volume_min, prm->volume_max); ++ if (volume != prm->volume) { ++ prm->volume = volume; ++ change = 1; ++ } ++ spin_unlock_irqrestore(&prm->lock, flags); ++ ++ if (change && audio_dev->notify) ++ audio_dev->notify(audio_dev, prm->fu_id, UAC_FU_VOLUME); ++ ++ return change; ++} ++ ++ ++static struct snd_kcontrol_new u_audio_controls[] = { ++ [UAC_FBACK_CTRL] { ++ .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .name = "Capture Pitch 1000000", ++ .info = u_audio_pitch_info, ++ .get = u_audio_pitch_get, ++ .put = u_audio_pitch_put, ++ }, ++ [UAC_MUTE_CTRL] { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "", /* will be filled later */ ++ .info = u_audio_mute_info, ++ .get = u_audio_mute_get, ++ .put = u_audio_mute_put, ++ }, ++ [UAC_VOLUME_CTRL] { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "", /* will be filled later */ ++ .info = u_audio_volume_info, ++ .get = u_audio_volume_get, ++ .put = u_audio_volume_put, ++ }, ++}; ++ + int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, + const char *card_name) + { + struct snd_uac_chip *uac; + struct snd_card *card; + struct snd_pcm *pcm; ++ struct snd_kcontrol *kctl; + struct uac_params *params; + int p_chmask, c_chmask; +- int err; ++ int i, err; + + if (!g_audio) + return -EINVAL; +@@ -512,12 +968,14 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, + if (c_chmask) { + struct uac_rtd_params *prm = &uac->c_prm; + +- uac->c_prm.uac = uac; ++ spin_lock_init(&prm->lock); ++ uac->c_prm.uac = uac; + prm->max_psize = g_audio->out_ep_maxpsize; + +- prm->ureq = kcalloc(params->req_number, sizeof(struct uac_req), +- GFP_KERNEL); +- if (!prm->ureq) { ++ prm->reqs = kcalloc(params->req_number, ++ sizeof(struct usb_request *), ++ GFP_KERNEL); ++ if (!prm->reqs) { + err = -ENOMEM; + goto fail; + } +@@ -534,12 +992,14 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, + if (p_chmask) { + struct uac_rtd_params *prm = &uac->p_prm; + ++ spin_lock_init(&prm->lock); + uac->p_prm.uac = uac; + prm->max_psize = g_audio->in_ep_maxpsize; + +- prm->ureq = kcalloc(params->req_number, sizeof(struct uac_req), +- GFP_KERNEL); +- if (!prm->ureq) { ++ prm->reqs = kcalloc(params->req_number, ++ sizeof(struct usb_request *), ++ GFP_KERNEL); ++ if (!prm->reqs) { + err = -ENOMEM; + goto fail; + } +@@ -570,15 +1030,116 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, + if (err < 0) + goto snd_fail; + +- strlcpy(pcm->name, pcm_name, sizeof(pcm->name)); ++ strscpy(pcm->name, pcm_name, sizeof(pcm->name)); + pcm->private_data = uac; + uac->pcm = pcm; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops); + +- strlcpy(card->driver, card_name, sizeof(card->driver)); +- strlcpy(card->shortname, card_name, sizeof(card->shortname)); ++ /* ++ * Create mixer and controls ++ * Create only if it's required on USB side ++ */ ++ if ((c_chmask && g_audio->in_ep_fback) ++ || (p_chmask && params->p_fu.id) ++ || (c_chmask && params->c_fu.id)) ++ strscpy(card->mixername, card_name, sizeof(card->driver)); ++ ++ if (c_chmask && g_audio->in_ep_fback) { ++ kctl = snd_ctl_new1(&u_audio_controls[UAC_FBACK_CTRL], ++ &uac->c_prm); ++ if (!kctl) { ++ err = -ENOMEM; ++ goto snd_fail; ++ } ++ ++ kctl->id.device = pcm->device; ++ kctl->id.subdevice = 0; ++ ++ err = snd_ctl_add(card, kctl); ++ if (err < 0) ++ goto snd_fail; ++ } ++ ++ for (i = 0; i <= SNDRV_PCM_STREAM_LAST; i++) { ++ struct uac_rtd_params *prm; ++ struct uac_fu_params *fu; ++ char ctrl_name[24]; ++ char *direction; ++ ++ if (!pcm->streams[i].substream_count) ++ continue; ++ ++ if (i == SNDRV_PCM_STREAM_PLAYBACK) { ++ prm = &uac->p_prm; ++ fu = ¶ms->p_fu; ++ direction = "Playback"; ++ } else { ++ prm = &uac->c_prm; ++ fu = ¶ms->c_fu; ++ direction = "Capture"; ++ } ++ ++ prm->fu_id = fu->id; ++ ++ if (fu->mute_present) { ++ snprintf(ctrl_name, sizeof(ctrl_name), ++ "PCM %s Switch", direction); ++ ++ u_audio_controls[UAC_MUTE_CTRL].name = ctrl_name; ++ ++ kctl = snd_ctl_new1(&u_audio_controls[UAC_MUTE_CTRL], ++ prm); ++ if (!kctl) { ++ err = -ENOMEM; ++ goto snd_fail; ++ } ++ ++ kctl->id.device = pcm->device; ++ kctl->id.subdevice = i; ++ ++ err = snd_ctl_add(card, kctl); ++ if (err < 0) ++ goto snd_fail; ++ prm->snd_kctl_mute = kctl; ++ prm->mute = 0; ++ } ++ ++ if (fu->volume_present) { ++ snprintf(ctrl_name, sizeof(ctrl_name), ++ "PCM %s Volume", direction); ++ ++ u_audio_controls[UAC_VOLUME_CTRL].name = ctrl_name; ++ ++ kctl = snd_ctl_new1(&u_audio_controls[UAC_VOLUME_CTRL], ++ prm); ++ if (!kctl) { ++ err = -ENOMEM; ++ goto snd_fail; ++ } ++ ++ kctl->id.device = pcm->device; ++ kctl->id.subdevice = i; ++ ++ ++ kctl->tlv.c = u_audio_volume_tlv; ++ kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ | ++ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; ++ ++ err = snd_ctl_add(card, kctl); ++ if (err < 0) ++ goto snd_fail; ++ prm->snd_kctl_volume = kctl; ++ prm->volume = fu->volume_max; ++ prm->volume_max = fu->volume_max; ++ prm->volume_min = fu->volume_min; ++ prm->volume_res = fu->volume_res; ++ } ++ } ++ ++ strscpy(card->driver, card_name, sizeof(card->driver)); ++ strscpy(card->shortname, card_name, sizeof(card->shortname)); + sprintf(card->longname, "%s %i", card_name, card->dev->id); + + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, +@@ -592,8 +1153,8 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, + snd_fail: + snd_card_free(card); + fail: +- kfree(uac->p_prm.ureq); +- kfree(uac->c_prm.ureq); ++ kfree(uac->p_prm.reqs); ++ kfree(uac->c_prm.reqs); + kfree(uac->p_prm.rbuf); + kfree(uac->c_prm.rbuf); + kfree(uac); +@@ -615,8 +1176,8 @@ void g_audio_cleanup(struct g_audio *g_audio) + if (card) + snd_card_free(card); + +- kfree(uac->p_prm.ureq); +- kfree(uac->c_prm.ureq); ++ kfree(uac->p_prm.reqs); ++ kfree(uac->c_prm.reqs); + kfree(uac->p_prm.rbuf); + kfree(uac->c_prm.rbuf); + kfree(uac); +@@ -625,4 +1186,4 @@ EXPORT_SYMBOL_GPL(g_audio_cleanup); + + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("USB gadget \"ALSA sound card\" utilities"); +-MODULE_AUTHOR("Ruslan Bilovol"); ++MODULE_AUTHOR("Ruslan Bilovol"); +\ No newline at end of file +diff --git a/drivers/usb/gadget/function/u_audio.h b/drivers/usb/gadget/function/u_audio.h +index 5ea6b86f1..001a79a46 100644 +--- a/drivers/usb/gadget/function/u_audio.h ++++ b/drivers/usb/gadget/function/u_audio.h +@@ -11,18 +11,41 @@ + + #include + ++/* ++ * Same maximum frequency deviation on the slower side as in ++ * sound/usb/endpoint.c. Value is expressed in per-mil deviation. ++ * The maximum deviation on the faster side will be provided as ++ * parameter, as it impacts the endpoint required bandwidth. ++ */ ++#define FBACK_SLOW_MAX 250 ++ ++/* Feature Unit parameters */ ++struct uac_fu_params { ++ int id; /* Feature Unit ID */ ++ ++ bool mute_present; /* mute control enable */ ++ ++ bool volume_present; /* volume control enable */ ++ s16 volume_min; /* min volume in 1/256 dB */ ++ s16 volume_max; /* max volume in 1/256 dB */ ++ s16 volume_res; /* volume resolution in 1/256 dB */ ++}; ++ + struct uac_params { + /* playback */ + int p_chmask; /* channel mask */ + int p_srate; /* rate in Hz */ + int p_ssize; /* sample size */ ++ struct uac_fu_params p_fu; /* Feature Unit parameters */ + + /* capture */ + int c_chmask; /* channel mask */ + int c_srate; /* rate in Hz */ + int c_ssize; /* sample size */ ++ struct uac_fu_params c_fu; /* Feature Unit parameters */ + + int req_number; /* number of preallocated requests */ ++ int fb_max; /* upper frequency drift feedback limit per-mil */ + }; + + struct g_audio { +@@ -30,13 +53,19 @@ struct g_audio { + struct usb_gadget *gadget; + + struct usb_ep *in_ep; ++ + struct usb_ep *out_ep; ++ /* feedback IN endpoint corresponding to out_ep */ ++ struct usb_ep *in_ep_fback; + + /* Max packet size for all in_ep possible speeds */ + unsigned int in_ep_maxpsize; + /* Max packet size for all out_ep possible speeds */ + unsigned int out_ep_maxpsize; + ++ /* Notify UAC driver about control change */ ++ int (*notify)(struct g_audio *g_audio, int unit_id, int cs); ++ + /* The ALSA Sound Card it represents on the USB-Client side */ + struct snd_uac_chip *uac; + +@@ -82,4 +111,9 @@ void u_audio_stop_capture(struct g_audio *g_audio); + int u_audio_start_playback(struct g_audio *g_audio); + void u_audio_stop_playback(struct g_audio *g_audio); + ++int u_audio_get_volume(struct g_audio *g_audio, int playback, s16 *val); ++int u_audio_set_volume(struct g_audio *g_audio, int playback, s16 val); ++int u_audio_get_mute(struct g_audio *g_audio, int playback, int *val); ++int u_audio_set_mute(struct g_audio *g_audio, int playback, int val); ++ + #endif /* __U_AUDIO_H */ +diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c +index 64ef97ab9..904c394df 100644 +--- a/drivers/usb/gadget/function/u_ether.c ++++ b/drivers/usb/gadget/function/u_ether.c +@@ -80,6 +80,7 @@ struct eth_dev { + + bool zlp; + bool no_skb_reserve; ++ bool ifname_set; + u8 host_mac[ETH_ALEN]; + u8 dev_mac[ETH_ALEN]; + }; +@@ -867,6 +868,7 @@ int gether_register_netdev(struct net_device *net) + { + struct eth_dev *dev; + struct usb_gadget *g; ++ struct sockaddr sa; + int status; + + if (!net->dev.parent) +@@ -874,15 +876,12 @@ int gether_register_netdev(struct net_device *net) + dev = netdev_priv(net); + g = dev->gadget; + +- memcpy(net->dev_addr, dev->dev_mac, ETH_ALEN); +- + status = register_netdev(net); + if (status < 0) { + dev_dbg(&g->dev, "register_netdev failed, %d\n", status); + return status; + } else { + INFO(dev, "HOST MAC %pM\n", dev->host_mac); +- INFO(dev, "MAC %pM\n", dev->dev_mac); + + /* two kinds of host-initiated state changes: + * - iff DATA transfer is active, carrier is "on" +@@ -890,6 +889,15 @@ int gether_register_netdev(struct net_device *net) + */ + netif_carrier_off(net); + } ++ sa.sa_family = net->type; ++ memcpy(sa.sa_data, dev->dev_mac, ETH_ALEN); ++ rtnl_lock(); ++ status = dev_set_mac_address(net, &sa, NULL); ++ rtnl_unlock(); ++ if (status) ++ pr_warn("cannot set self ethernet address: %d\n", status); ++ else ++ INFO(dev, "MAC %pM\n", dev->dev_mac); + + return status; + } +@@ -1007,15 +1015,45 @@ EXPORT_SYMBOL_GPL(gether_get_qmult); + + int gether_get_ifname(struct net_device *net, char *name, int len) + { ++ struct eth_dev *dev = netdev_priv(net); + int ret; + + rtnl_lock(); +- ret = scnprintf(name, len, "%s\n", netdev_name(net)); ++ ret = scnprintf(name, len, "%s\n", ++ dev->ifname_set ? net->name : netdev_name(net)); + rtnl_unlock(); + return ret; + } + EXPORT_SYMBOL_GPL(gether_get_ifname); + ++int gether_set_ifname(struct net_device *net, const char *name, int len) ++{ ++ struct eth_dev *dev = netdev_priv(net); ++ char tmp[IFNAMSIZ]; ++ const char *p; ++ ++ if (name[len - 1] == '\n') ++ len--; ++ ++ if (len >= sizeof(tmp)) ++ return -E2BIG; ++ ++ strscpy(tmp, name, len + 1); ++ if (!dev_valid_name(tmp)) ++ return -EINVAL; ++ ++ /* Require exactly one %d, so binding will not fail with EEXIST. */ ++ p = strchr(name, '%'); ++ if (!p || p[1] != 'd' || strchr(p + 2, '%')) ++ return -EINVAL; ++ ++ strncpy(net->name, tmp, sizeof(net->name)); ++ dev->ifname_set = true; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(gether_set_ifname); ++ + /* + * gether_cleanup - remove Ethernet-over-USB device + * Context: may sleep +diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h +index 10dd64068..40144546d 100644 +--- a/drivers/usb/gadget/function/u_ether.h ++++ b/drivers/usb/gadget/function/u_ether.h +@@ -244,6 +244,18 @@ unsigned gether_get_qmult(struct net_device *net); + */ + int gether_get_ifname(struct net_device *net, char *name, int len); + ++/** ++ * gether_set_ifname - set an ethernet-over-usb link interface name ++ * @net: device representing this link ++ * @name: new interface name ++ * @len: length of @name ++ * ++ * This sets the interface name of this ethernet-over-usb link. ++ * A single terminating newline, if any, is ignored. ++ * Returns zero on success, else negative errno. ++ */ ++int gether_set_ifname(struct net_device *net, const char *name, int len); ++ + void gether_cleanup(struct eth_dev *dev); + + /* connect/disconnect is handled by individual functions */ +diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h +index f982e18a5..f558c3139 100644 +--- a/drivers/usb/gadget/function/u_ether_configfs.h ++++ b/drivers/usb/gadget/function/u_ether_configfs.h +@@ -148,7 +148,20 @@ out: \ + return ret; \ + } \ + \ +- CONFIGFS_ATTR_RO(_f_##_opts_, ifname) ++ static ssize_t _f_##_opts_ifname_store(struct config_item *item, \ ++ const char *page, size_t len)\ ++ { \ ++ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ ++ int ret = -EBUSY; \ ++ \ ++ mutex_lock(&opts->lock); \ ++ if (!opts->refcnt) \ ++ ret = gether_set_ifname(opts->net, page, len); \ ++ mutex_unlock(&opts->lock); \ ++ return ret ?: len; \ ++ } \ ++ \ ++ CONFIGFS_ATTR(_f_##_opts_, ifname) + + #define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \ + static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\ +diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h +index 84e6da302..84bb70292 100644 +--- a/drivers/usb/gadget/function/u_hid.h ++++ b/drivers/usb/gadget/function/u_hid.h +@@ -20,6 +20,7 @@ struct f_hid_opts { + int minor; + unsigned char subclass; + unsigned char protocol; ++ unsigned char no_out_endpoint; + unsigned short report_length; + unsigned short report_desc_length; + unsigned char *report_desc; +@@ -29,8 +30,8 @@ struct f_hid_opts { + * Protect the data form concurrent access by read/write + * and create symlink/remove symlink. + */ +- struct mutex lock; +- int refcnt; ++ struct mutex lock; ++ int refcnt; + }; + + int ghid_setup(struct usb_gadget *g, int count); +diff --git a/drivers/usb/gadget/function/u_midi.h b/drivers/usb/gadget/function/u_midi.h +index f6e14af7f..2e400b495 100644 +--- a/drivers/usb/gadget/function/u_midi.h ++++ b/drivers/usb/gadget/function/u_midi.h +@@ -29,8 +29,8 @@ struct f_midi_opts { + * Protect the data form concurrent access by read/write + * and create symlink/remove symlink. + */ +- struct mutex lock; +- int refcnt; ++ struct mutex lock; ++ int refcnt; + }; + + #endif /* U_MIDI_H */ +diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c +index 2caccbb6e..d70f6dc9f 100644 +--- a/drivers/usb/gadget/function/u_serial.c ++++ b/drivers/usb/gadget/function/u_serial.c +@@ -346,7 +346,7 @@ __acquires(&port->port_lock) + } + + /* +- * RX tasklet takes data out of the RX queue and hands it up to the TTY ++ * RX work takes data out of the RX queue and hands it up to the TTY + * layer until it refuses to take any more data (or is throttled back). + * Then it issues reads for any further data. + * +@@ -709,7 +709,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) + + /* Iff we're disconnected, there can be no I/O in flight so it's + * ok to free the circular buffer; else just scrub it. And don't +- * let the push tasklet fire again until we're re-opened. ++ * let the push async work fire again until we're re-opened. + */ + if (gser == NULL) + kfifo_free(&port->port_write_buf); +@@ -1200,7 +1200,7 @@ void gserial_free_line(unsigned char port_num) + struct gs_port *port; + + mutex_lock(&ports[port_num].lock); +- if (WARN_ON(!ports[port_num].port)) { ++ if (!ports[port_num].port) { + mutex_unlock(&ports[port_num].lock); + return; + } +@@ -1447,51 +1447,53 @@ EXPORT_SYMBOL_GPL(gserial_resume); + + static int userial_init(void) + { ++ struct tty_driver *driver; + unsigned i; + int status; + +- gs_tty_driver = alloc_tty_driver(MAX_U_SERIAL_PORTS); +- if (!gs_tty_driver) +- return -ENOMEM; ++ driver = tty_alloc_driver(MAX_U_SERIAL_PORTS, TTY_DRIVER_REAL_RAW | ++ TTY_DRIVER_DYNAMIC_DEV); ++ if (IS_ERR(driver)) ++ return PTR_ERR(driver); + +- gs_tty_driver->driver_name = "g_serial"; +- gs_tty_driver->name = "ttyGS"; ++ driver->driver_name = "g_serial"; ++ driver->name = "ttyGS"; + /* uses dynamically assigned dev_t values */ + +- gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; +- gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; +- gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; +- gs_tty_driver->init_termios = tty_std_termios; ++ driver->type = TTY_DRIVER_TYPE_SERIAL; ++ driver->subtype = SERIAL_TYPE_NORMAL; ++ driver->init_termios = tty_std_termios; + + /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on + * MS-Windows. Otherwise, most of these flags shouldn't affect + * anything unless we were to actually hook up to a serial line. + */ +- gs_tty_driver->init_termios.c_cflag = ++ driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; +- gs_tty_driver->init_termios.c_ispeed = 9600; +- gs_tty_driver->init_termios.c_ospeed = 9600; ++ driver->init_termios.c_ispeed = 9600; ++ driver->init_termios.c_ospeed = 9600; + +- tty_set_operations(gs_tty_driver, &gs_tty_ops); ++ tty_set_operations(driver, &gs_tty_ops); + for (i = 0; i < MAX_U_SERIAL_PORTS; i++) + mutex_init(&ports[i].lock); + + /* export the driver ... */ +- status = tty_register_driver(gs_tty_driver); ++ status = tty_register_driver(driver); + if (status) { + pr_err("%s: cannot register, err %d\n", + __func__, status); + goto fail; + } + ++ gs_tty_driver = driver; ++ + pr_debug("%s: registered %d ttyGS* device%s\n", __func__, + MAX_U_SERIAL_PORTS, + (MAX_U_SERIAL_PORTS == 1) ? "" : "s"); + + return status; + fail: +- put_tty_driver(gs_tty_driver); +- gs_tty_driver = NULL; ++ tty_driver_kref_put(driver); + return status; + } + module_init(userial_init); +@@ -1499,7 +1501,7 @@ module_init(userial_init); + static void userial_cleanup(void) + { + tty_unregister_driver(gs_tty_driver); +- put_tty_driver(gs_tty_driver); ++ tty_driver_kref_put(gs_tty_driver); + gs_tty_driver = NULL; + } + module_exit(userial_cleanup); +diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h +index 39c0e29e1..9979514ba 100644 +--- a/drivers/usb/gadget/function/u_uac1.h ++++ b/drivers/usb/gadget/function/u_uac1.h +@@ -18,6 +18,13 @@ + #define UAC1_DEF_PSRATE 48000 + #define UAC1_DEF_PSSIZE 2 + #define UAC1_DEF_REQ_NUM 2 ++#define UAC1_DEF_INT_REQ_NUM 10 ++ ++#define UAC1_DEF_MUTE_PRESENT 1 ++#define UAC1_DEF_VOLUME_PRESENT 1 ++#define UAC1_DEF_MIN_DB (-100*256) /* -100 dB */ ++#define UAC1_DEF_MAX_DB 0 /* 0 dB */ ++#define UAC1_DEF_RES_DB (1*256) /* 1 dB */ + + + struct f_uac1_opts { +@@ -28,6 +35,19 @@ struct f_uac1_opts { + int p_chmask; + int p_srate; + int p_ssize; ++ ++ bool p_mute_present; ++ bool p_volume_present; ++ s16 p_volume_min; ++ s16 p_volume_max; ++ s16 p_volume_res; ++ ++ bool c_mute_present; ++ bool c_volume_present; ++ s16 c_volume_min; ++ s16 c_volume_max; ++ s16 c_volume_res; ++ + int req_number; + unsigned bound:1; + +@@ -35,4 +55,4 @@ struct f_uac1_opts { + int refcnt; + }; + +-#endif /* __U_UAC1_H */ ++#endif /* __U_UAC1_H */ +\ No newline at end of file +diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h +index b50357111..569897f87 100644 +--- a/drivers/usb/gadget/function/u_uac2.h ++++ b/drivers/usb/gadget/function/u_uac2.h +@@ -21,7 +21,17 @@ + #define UAC2_DEF_CCHMASK 0x3 + #define UAC2_DEF_CSRATE 64000 + #define UAC2_DEF_CSSIZE 2 ++#define UAC2_DEF_CSYNC USB_ENDPOINT_SYNC_ASYNC ++ ++#define UAC2_DEF_MUTE_PRESENT 1 ++#define UAC2_DEF_VOLUME_PRESENT 1 ++#define UAC2_DEF_MIN_DB (-100*256) /* -100 dB */ ++#define UAC2_DEF_MAX_DB 0 /* 0 dB */ ++#define UAC2_DEF_RES_DB (1*256) /* 1 dB */ ++ + #define UAC2_DEF_REQ_NUM 2 ++#define UAC2_DEF_FB_MAX 5 ++#define UAC2_DEF_INT_REQ_NUM 10 + + struct f_uac2_opts { + struct usb_function_instance func_inst; +@@ -31,11 +41,26 @@ struct f_uac2_opts { + int c_chmask; + int c_srate; + int c_ssize; ++ int c_sync; ++ ++ bool p_mute_present; ++ bool p_volume_present; ++ s16 p_volume_min; ++ s16 p_volume_max; ++ s16 p_volume_res; ++ ++ bool c_mute_present; ++ bool c_volume_present; ++ s16 c_volume_min; ++ s16 c_volume_max; ++ s16 c_volume_res; ++ + int req_number; +- bool bound; ++ int fb_max; ++ bool bound; + + struct mutex lock; + int refcnt; + }; + +-#endif ++#endif +\ No newline at end of file +diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h +index 6c4fc4913..f3e9c764f 100644 +--- a/drivers/usb/gadget/function/uvc.h ++++ b/drivers/usb/gadget/function/uvc.h +@@ -66,13 +66,19 @@ extern unsigned int uvc_gadget_trace_param; + * Driver specific constants + */ + +-#define UVC_NUM_REQUESTS 4 + #define UVC_MAX_REQUEST_SIZE 64 + #define UVC_MAX_EVENTS 4 + + /* ------------------------------------------------------------------------ + * Structures + */ ++struct uvc_request { ++ struct usb_request *req; ++ u8 *req_buffer; ++ struct uvc_video *video; ++ struct sg_table sgt; ++ u8 header[2]; ++}; + + struct uvc_video { + struct uvc_device *uvc; +@@ -88,13 +94,16 @@ struct uvc_video { + unsigned int imagesize; + struct mutex mutex; /* protects frame parameters */ + ++ unsigned int uvc_num_requests; ++ + /* Requests */ + unsigned int req_size; +- struct usb_request *req[UVC_NUM_REQUESTS]; +- __u8 *req_buffer[UVC_NUM_REQUESTS]; ++ struct uvc_request *ureq; + struct list_head req_free; + spinlock_t req_lock; + ++ unsigned int req_int_count; ++ + void (*encode) (struct usb_request *req, struct uvc_video *video, + struct uvc_buffer *buf); + +@@ -118,7 +127,7 @@ struct uvc_device { + enum uvc_state state; + struct usb_function func; + struct uvc_video video; +- bool func_connected; ++ bool func_connected; + wait_queue_head_t func_connected_queue; + + /* Descriptors */ +diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c +index 00fb58e50..77d64031a 100644 +--- a/drivers/usb/gadget/function/uvc_configfs.c ++++ b/drivers/usb/gadget/function/uvc_configfs.c +@@ -231,7 +231,7 @@ static struct config_item *uvcg_control_header_make(struct config_group *group, + h->desc.bLength = UVC_DT_HEADER_SIZE(1); + h->desc.bDescriptorType = USB_DT_CS_INTERFACE; + h->desc.bDescriptorSubType = UVC_VC_HEADER; +- h->desc.bcdUVC = cpu_to_le16(0x0100); ++ h->desc.bcdUVC = cpu_to_le16(0x0110); + h->desc.dwClockFrequency = cpu_to_le32(48000000); + + config_item_init_type_name(&h->item, name, &uvcg_control_header_type); +@@ -914,8 +914,6 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, + + target_fmt = container_of(to_config_group(target), struct uvcg_format, + group); +- if (!target_fmt) +- goto out; + + uvcg_format_set_indices(to_config_group(target)); + +@@ -955,8 +953,6 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, + mutex_lock(&opts->lock); + target_fmt = container_of(to_config_group(target), struct uvcg_format, + group); +- if (!target_fmt) +- goto out; + + list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry) + if (format_ptr->fmt == target_fmt) { +@@ -968,7 +964,6 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, + + --target_fmt->linked; + +-out: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + } +diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c +index cab1e3046..cd99d6c4a 100644 +--- a/drivers/usb/gadget/function/uvc_queue.c ++++ b/drivers/usb/gadget/function/uvc_queue.c +@@ -17,6 +17,7 @@ + #include + + #include ++#include + #include + + #include "uvc.h" +@@ -43,6 +44,7 @@ static int uvc_queue_setup(struct vb2_queue *vq, + { + struct uvc_video_queue *queue = vb2_get_drv_priv(vq); + struct uvc_video *video = container_of(queue, struct uvc_video, queue); ++ struct usb_composite_dev *cdev = video->uvc->func.config->cdev; + + if (*nbuffers > UVC_MAX_VIDEO_BUFFERS) + *nbuffers = UVC_MAX_VIDEO_BUFFERS; +@@ -70,7 +72,12 @@ static int uvc_buffer_prepare(struct vb2_buffer *vb) + return -ENODEV; + + buf->state = UVC_BUF_STATE_QUEUED; +- buf->mem = vb2_plane_vaddr(vb, 0); ++ if (queue->use_sg) { ++ buf->sgt = vb2_dma_sg_plane_desc(vb, 0); ++ buf->sg = buf->sgt->sgl; ++ } else { ++ buf->mem = vb2_plane_vaddr(vb, 0); ++ } + buf->length = vb2_plane_size(vb, 0); + if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + buf->bytesused = 0; +@@ -110,9 +117,11 @@ static const struct vb2_ops uvc_queue_qops = { + .wait_finish = vb2_ops_wait_finish, + }; + +-int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, ++int uvcg_queue_init(struct uvc_video_queue *queue, struct device *dev, enum v4l2_buf_type type, + struct mutex *lock) + { ++ struct uvc_video *video = container_of(queue, struct uvc_video, queue); ++ struct usb_composite_dev *cdev = video->uvc->func.config->cdev; + int ret; + + queue->queue.type = type; +@@ -121,9 +130,17 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, + queue->queue.buf_struct_size = sizeof(struct uvc_buffer); + queue->queue.ops = &uvc_queue_qops; + queue->queue.lock = lock; +- queue->queue.mem_ops = &vb2_vmalloc_memops; ++ if (cdev->gadget->sg_supported) { ++ queue->queue.mem_ops = &vb2_dma_sg_memops; ++ queue->use_sg = 1; ++ } else { ++ queue->queue.mem_ops = &vb2_vmalloc_memops; ++ } ++ + queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC + | V4L2_BUF_FLAG_TSTAMP_SRC_EOF; ++ queue->queue.dev = dev; ++ + ret = vb2_queue_init(&queue->queue); + if (ret) + return ret; +@@ -347,4 +364,3 @@ struct uvc_buffer *uvcg_queue_head(struct uvc_video_queue *queue) + + return buf; + } +- +diff --git a/drivers/usb/gadget/function/uvc_queue.h b/drivers/usb/gadget/function/uvc_queue.h +index 2f0fff769..13275e932 100644 +--- a/drivers/usb/gadget/function/uvc_queue.h ++++ b/drivers/usb/gadget/function/uvc_queue.h +@@ -34,6 +34,9 @@ struct uvc_buffer { + + enum uvc_buffer_state state; + void *mem; ++ struct sg_table *sgt; ++ struct scatterlist *sg; ++ unsigned int offset; + unsigned int length; + unsigned int bytesused; + }; +@@ -50,6 +53,8 @@ struct uvc_video_queue { + + unsigned int buf_used; + ++ bool use_sg; ++ + spinlock_t irqlock; /* Protects flags and irqqueue */ + struct list_head irqqueue; + }; +@@ -59,7 +64,7 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue) + return vb2_is_streaming(&queue->queue); + } + +-int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, ++int uvcg_queue_init(struct uvc_video_queue *queue, struct device *dev, enum v4l2_buf_type type, + struct mutex *lock); + + void uvcg_free_buffers(struct uvc_video_queue *queue); +@@ -94,4 +99,3 @@ struct uvc_buffer *uvcg_queue_next_buffer(struct uvc_video_queue *queue, + struct uvc_buffer *uvcg_queue_head(struct uvc_video_queue *queue); + + #endif /* _UVC_QUEUE_H_ */ +- +diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c +index 65abd55ce..d036d11dd 100644 +--- a/drivers/usb/gadget/function/uvc_v4l2.c ++++ b/drivers/usb/gadget/function/uvc_v4l2.c +@@ -227,56 +227,16 @@ static int + uvc_v4l2_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) + { +- struct uvc_device *uvc = video_get_drvdata(fh->vdev); +- struct uvc_file_handle *handle = to_uvc_file_handle(fh); +- int ret; +- + if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) + return -EINVAL; +- +- if (sub->type == UVC_EVENT_SETUP && uvc->func_connected) +- return -EBUSY; +- +- ret = v4l2_event_subscribe(fh, sub, 2, NULL); +- if (ret < 0) +- return ret; +- +- if (sub->type == UVC_EVENT_SETUP) { +- uvc->func_connected = true; +- handle->is_uvc_app_handle = true; +- uvc_function_connect(uvc); +- } +- +- return 0; +-} +- +-static void uvc_v4l2_disable(struct uvc_device *uvc) +-{ +- uvc_function_disconnect(uvc); +- uvcg_video_enable(&uvc->video, 0); +- uvcg_free_buffers(&uvc->video.queue); +- uvc->func_connected = false; +- wake_up_interruptible(&uvc->func_connected_queue); ++ return v4l2_event_subscribe(fh, sub, 2, NULL); + } + + static int + uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) + { +- struct uvc_device *uvc = video_get_drvdata(fh->vdev); +- struct uvc_file_handle *handle = to_uvc_file_handle(fh); +- int ret; +- +- ret = v4l2_event_unsubscribe(fh, sub); +- if (ret < 0) +- return ret; +- +- if (sub->type == UVC_EVENT_SETUP && handle->is_uvc_app_handle) { +- uvc_v4l2_disable(uvc); +- handle->is_uvc_app_handle = false; +- } +- +- return 0; ++ return v4l2_event_unsubscribe(fh, sub); + } + + static long +@@ -331,6 +291,7 @@ uvc_v4l2_open(struct file *file) + handle->device = &uvc->video; + file->private_data = &handle->vfh; + ++ uvc_function_connect(uvc); + return 0; + } + +@@ -342,9 +303,11 @@ uvc_v4l2_release(struct file *file) + struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); + struct uvc_video *video = handle->device; + ++ uvc_function_disconnect(uvc); ++ + mutex_lock(&video->mutex); +- if (handle->is_uvc_app_handle) +- uvc_v4l2_disable(uvc); ++ uvcg_video_enable(video, 0); ++ uvcg_free_buffers(&video->queue); + mutex_unlock(&video->mutex); + + file->private_data = NULL; +diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c +index 633e23d58..db273e9a0 100644 +--- a/drivers/usb/gadget/function/uvc_video.c ++++ b/drivers/usb/gadget/function/uvc_video.c +@@ -27,10 +27,10 @@ static int + uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf, + u8 *data, int len) + { +- data[0] = 2; ++ data[0] = UVCG_REQUEST_HEADER_LEN; + data[1] = UVC_STREAM_EOH | video->fid; + +- if (buf->bytesused - video->queue.buf_used <= len - 2) ++ if (buf->bytesused - video->queue.buf_used <= len - UVCG_REQUEST_HEADER_LEN) + data[1] |= UVC_STREAM_EOF; + + return 2; +@@ -94,6 +94,71 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video, + video->payload_size = 0; + } + ++static void ++uvc_video_encode_isoc_sg(struct usb_request *req, struct uvc_video *video, ++ struct uvc_buffer *buf) ++{ ++ unsigned int pending = buf->bytesused - video->queue.buf_used; ++ struct uvc_request *ureq = req->context; ++ struct scatterlist *sg, *iter; ++ unsigned int len = video->req_size; ++ unsigned int sg_left, part = 0; ++ unsigned int i; ++ int ret; ++ ++ sg = ureq->sgt.sgl; ++ sg_init_table(sg, ureq->sgt.nents); ++ ++ /* Init the header. */ ++ ret = uvc_video_encode_header(video, buf, ureq->header, ++ video->req_size); ++ sg_set_buf(sg, ureq->header, UVCG_REQUEST_HEADER_LEN); ++ len -= ret; ++ ++ if (pending <= len) ++ len = pending; ++ ++ req->length = (len == pending) ? ++ len + UVCG_REQUEST_HEADER_LEN : video->req_size; ++ ++ /* Init the pending sgs with payload */ ++ sg = sg_next(sg); ++ ++ for_each_sg(sg, iter, ureq->sgt.nents - 1, i) { ++ if (!len || !buf->sg) ++ break; ++ ++ sg_left = sg_dma_len(buf->sg) - buf->offset; ++ part = min_t(unsigned int, len, sg_left); ++ ++ sg_set_page(iter, sg_page(buf->sg), part, buf->offset); ++ ++ if (part == sg_left) { ++ buf->offset = 0; ++ buf->sg = sg_next(buf->sg); ++ } else { ++ buf->offset += part; ++ } ++ len -= part; ++ } ++ ++ /* Assign the video data with header. */ ++ req->buf = NULL; ++ req->sg = ureq->sgt.sgl; ++ req->num_sgs = i + 1; ++ ++ req->length -= len; ++ video->queue.buf_used += req->length - UVCG_REQUEST_HEADER_LEN; ++ ++ if (buf->bytesused == video->queue.buf_used || !buf->sg) { ++ video->queue.buf_used = 0; ++ buf->state = UVC_BUF_STATE_DONE; ++ buf->offset = 0; ++ uvcg_queue_next_buffer(&video->queue, buf); ++ video->fid ^= UVC_STREAM_FID; ++ } ++} ++ + static void + uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, + struct uvc_buffer *buf) +@@ -145,7 +210,8 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) + static void + uvc_video_complete(struct usb_ep *ep, struct usb_request *req) + { +- struct uvc_video *video = req->context; ++ struct uvc_request *ureq = req->context; ++ struct uvc_video *video = ureq->video; + struct uvc_video_queue *queue = &video->queue; + unsigned long flags; + +@@ -177,16 +243,23 @@ uvc_video_free_requests(struct uvc_video *video) + { + unsigned int i; + +- for (i = 0; i < UVC_NUM_REQUESTS; ++i) { +- if (video->req[i]) { +- usb_ep_free_request(video->ep, video->req[i]); +- video->req[i] = NULL; +- } ++ if (video->ureq) { ++ for (i = 0; i < video->uvc_num_requests; ++i) { ++ sg_free_table(&video->ureq[i].sgt); ++ ++ if (video->ureq[i].req) { ++ usb_ep_free_request(video->ep, video->ureq[i].req); ++ video->ureq[i].req = NULL; ++ } + +- if (video->req_buffer[i]) { +- kfree(video->req_buffer[i]); +- video->req_buffer[i] = NULL; ++ if (video->ureq[i].req_buffer) { ++ kfree(video->ureq[i].req_buffer); ++ video->ureq[i].req_buffer = NULL; ++ } + } ++ ++ kfree(video->ureq); ++ video->ureq = NULL; + } + + INIT_LIST_HEAD(&video->req_free); +@@ -207,21 +280,30 @@ uvc_video_alloc_requests(struct uvc_video *video) + * max_t(unsigned int, video->ep->maxburst, 1) + * (video->ep->mult); + +- for (i = 0; i < UVC_NUM_REQUESTS; ++i) { +- video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL); +- if (video->req_buffer[i] == NULL) +- goto error; ++ video->ureq = kcalloc(video->uvc_num_requests, sizeof(struct uvc_request), GFP_KERNEL); ++ if (video->ureq == NULL) ++ return -ENOMEM; + +- video->req[i] = usb_ep_alloc_request(video->ep, GFP_KERNEL); +- if (video->req[i] == NULL) ++ for (i = 0; i < video->uvc_num_requests; ++i) { ++ video->ureq[i].req_buffer = kmalloc(req_size, GFP_KERNEL); ++ if (video->ureq[i].req_buffer == NULL) + goto error; + +- video->req[i]->buf = video->req_buffer[i]; +- video->req[i]->length = 0; +- video->req[i]->complete = uvc_video_complete; +- video->req[i]->context = video; ++ video->ureq[i].req = usb_ep_alloc_request(video->ep, GFP_KERNEL); ++ if (video->ureq[i].req == NULL) ++ goto error; + +- list_add_tail(&video->req[i]->list, &video->req_free); ++ video->ureq[i].req->buf = video->ureq[i].req_buffer; ++ video->ureq[i].req->length = 0; ++ video->ureq[i].req->complete = uvc_video_complete; ++ video->ureq[i].req->context = &video->ureq[i]; ++ video->ureq[i].video = video; ++ ++ list_add_tail(&video->ureq[i].req->list, &video->req_free); ++ /* req_size/PAGE_SIZE + 1 for overruns and + 1 for header */ ++ sg_alloc_table(&video->ureq[i].sgt, ++ DIV_ROUND_UP(req_size - 2, PAGE_SIZE) + 2, ++ GFP_KERNEL); + } + + video->req_size = req_size; +@@ -278,6 +360,19 @@ static void uvcg_video_pump(struct work_struct *work) + + video->encode(req, video, buf); + ++ /* With usb3 we have more requests. This will decrease the ++ * interrupt load to a quarter but also catches the corner ++ * cases, which needs to be handled */ ++ if (list_empty(&video->req_free) || ++ buf->state == UVC_BUF_STATE_DONE || ++ !(video->req_int_count % ++ DIV_ROUND_UP(video->uvc_num_requests, 4))) { ++ video->req_int_count = 0; ++ req->no_interrupt = 0; ++ } else { ++ req->no_interrupt = 1; ++ } ++ + /* Queue the USB request */ + ret = uvcg_video_ep_queue(video, req); + spin_unlock_irqrestore(&queue->irqlock, flags); +@@ -286,6 +381,7 @@ static void uvcg_video_pump(struct work_struct *work) + uvcg_queue_cancel(queue, 0); + break; + } ++ video->req_int_count++; + } + + spin_lock_irqsave(&video->req_lock, flags); +@@ -312,9 +408,9 @@ int uvcg_video_enable(struct uvc_video *video, int enable) + cancel_work_sync(&video->pump); + uvcg_queue_cancel(&video->queue, 0); + +- for (i = 0; i < UVC_NUM_REQUESTS; ++i) +- if (video->req[i]) +- usb_ep_dequeue(video->ep, video->req[i]); ++ for (i = 0; i < video->uvc_num_requests; ++i) ++ if (video->ureq && video->ureq[i].req) ++ usb_ep_dequeue(video->ep, video->ureq[i].req); + + uvc_video_free_requests(video); + uvcg_queue_enable(&video->queue, 0); +@@ -331,7 +427,10 @@ int uvcg_video_enable(struct uvc_video *video, int enable) + video->encode = uvc_video_encode_bulk; + video->payload_size = 0; + } else +- video->encode = uvc_video_encode_isoc; ++ video->encode = video->queue.use_sg ? ++ uvc_video_encode_isoc_sg : uvc_video_encode_isoc; ++ ++ video->req_int_count = 0; + + schedule_work(&video->pump); + +@@ -355,8 +454,7 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) + video->imagesize = 320 * 240 * 2; + + /* Initialize the video buffers queue. */ +- uvcg_queue_init(&video->queue, V4L2_BUF_TYPE_VIDEO_OUTPUT, +- &video->mutex); ++ uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent, ++ V4L2_BUF_TYPE_VIDEO_OUTPUT, &video->mutex); + return 0; + } +- +diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h +index 03adeefa3..9bf19475f 100644 +--- a/drivers/usb/gadget/function/uvc_video.h ++++ b/drivers/usb/gadget/function/uvc_video.h +@@ -12,6 +12,8 @@ + #ifndef __UVC_VIDEO_H__ + #define __UVC_VIDEO_H__ + ++#define UVCG_REQUEST_HEADER_LEN 2 ++ + struct uvc_video; + + int uvcg_video_enable(struct uvc_video *video, int enable); +diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig +index f02c38b32..de6668e58 100644 +--- a/drivers/usb/gadget/legacy/Kconfig ++++ b/drivers/usb/gadget/legacy/Kconfig +@@ -502,6 +502,7 @@ config USB_G_WEBCAM + tristate "USB Webcam Gadget" + depends on VIDEO_V4L2 + select USB_LIBCOMPOSITE ++ select VIDEOBUF2_DMA_SG + select VIDEOBUF2_VMALLOC + select USB_F_UVC + help +@@ -515,10 +516,15 @@ config USB_G_WEBCAM + config USB_RAW_GADGET + tristate "USB Raw Gadget" + help +- USB Raw Gadget is a kernel module that provides a userspace interface +- for the USB Gadget subsystem. Essentially it allows to emulate USB +- devices from userspace. See Documentation/usb/raw-gadget.rst for +- details. ++ USB Raw Gadget is a gadget driver that gives userspace low-level ++ control over the gadget's communication process. ++ ++ Like any other gadget driver, Raw Gadget implements USB devices via ++ the USB gadget API. Unlike most gadget drivers, Raw Gadget does not ++ implement any concrete USB functions itself but requires userspace ++ to do that. ++ ++ See Documentation/usb/raw-gadget.rst for details. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "raw_gadget". +diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c +index 6bcbad382..e1d566c99 100644 +--- a/drivers/usb/gadget/legacy/dbgp.c ++++ b/drivers/usb/gadget/legacy/dbgp.c +@@ -137,7 +137,7 @@ static int dbgp_enable_ep_req(struct usb_ep *ep) + goto fail_1; + } + +- req->buf = kzalloc(DBGP_REQ_LEN, GFP_KERNEL); ++ req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL); + if (!req->buf) { + err = -ENOMEM; + stp = 2; +@@ -345,19 +345,6 @@ static int dbgp_setup(struct usb_gadget *gadget, + void *data = NULL; + u16 len = 0; + +- if (length > DBGP_REQ_LEN) { +- if (ctrl->bRequestType & USB_DIR_IN) { +- /* Cast away the const, we are going to overwrite on purpose. */ +- __le16 *temp = (__le16 *)&ctrl->wLength; +- +- *temp = cpu_to_le16(DBGP_REQ_LEN); +- length = DBGP_REQ_LEN; +- } else { +- return err; +- } +- } +- +- + if (request == USB_REQ_GET_DESCRIPTOR) { + switch (value>>8) { + case USB_DT_DEVICE: +diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c +index 3912cc805..5b27d2894 100644 +--- a/drivers/usb/gadget/legacy/hid.c ++++ b/drivers/usb/gadget/legacy/hid.c +@@ -99,10 +99,8 @@ static int do_config(struct usb_configuration *c) + + list_for_each_entry(e, &hidg_func_list, node) { + e->f = usb_get_function(e->fi); +- if (IS_ERR(e->f)) { +- status = PTR_ERR(e->f); ++ if (IS_ERR(e->f)) + goto put; +- } + status = usb_add_function(c, e->f); + if (status < 0) { + usb_put_function(e->f); +diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c +index 454860d52..cd8e27379 100644 +--- a/drivers/usb/gadget/legacy/inode.c ++++ b/drivers/usb/gadget/legacy/inode.c +@@ -110,8 +110,6 @@ enum ep0_state { + /* enough for the whole queue: most events invalidate others */ + #define N_EVENT 5 + +-#define RBUF_SIZE 256 +- + struct dev_data { + spinlock_t lock; + refcount_t count; +@@ -146,7 +144,7 @@ struct dev_data { + struct dentry *dentry; + + /* except this scratch i/o buffer for ep0 */ +- u8 rbuf[RBUF_SIZE]; ++ u8 rbuf [256]; + }; + + static inline void get_dev (struct dev_data *data) +@@ -500,7 +498,8 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) + iocb->private = NULL; + /* aio_complete() reports bytes-transferred _and_ faults */ + +- iocb->ki_complete(iocb, req->actual ? req->actual : req->status, ++ iocb->ki_complete(iocb, ++ req->actual ? req->actual : (long)req->status, + req->status); + } else { + /* ep_copy_to_user() won't report both; we hide some faults */ +@@ -1335,18 +1334,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + +- if (w_length > RBUF_SIZE) { +- if (ctrl->bRequestType & USB_DIR_IN) { +- /* Cast away the const, we are going to overwrite on purpose. */ +- __le16 *temp = (__le16 *)&ctrl->wLength; +- +- *temp = cpu_to_le16(RBUF_SIZE); +- w_length = RBUF_SIZE; +- } else { +- return value; +- } +- } +- + spin_lock (&dev->lock); + dev->setup_abort = 0; + if (dev->state == STATE_DEV_UNCONNECTED) { +@@ -1828,9 +1815,8 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) + spin_lock_irq (&dev->lock); + value = -EINVAL; + if (dev->buf) { +- spin_unlock_irq(&dev->lock); + kfree(kbuf); +- return value; ++ goto fail; + } + dev->buf = kbuf; + +@@ -1877,8 +1863,8 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) + + value = usb_gadget_probe_driver(&gadgetfs_driver); + if (value != 0) { +- spin_lock_irq(&dev->lock); +- goto fail; ++ kfree (dev->buf); ++ dev->buf = NULL; + } else { + /* at this point "good" hardware has for the first time + * let the USB the host see us. alternatively, if users +@@ -1895,9 +1881,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) + return value; + + fail: +- dev->config = NULL; +- dev->hs_config = NULL; +- dev->dev = NULL; + spin_unlock_irq (&dev->lock); + pr_debug ("%s: %s fail %zd, %p\n", shortname, __func__, value, dev); + kfree (dev->buf); +diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c +index 9ed22c5fb..ac1741126 100644 +--- a/drivers/usb/gadget/legacy/mass_storage.c ++++ b/drivers/usb/gadget/legacy/mass_storage.c +@@ -175,8 +175,10 @@ static int msg_bind(struct usb_composite_dev *cdev) + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); +- if (!usb_desc) ++ if (!usb_desc) { ++ status = -ENOMEM; + goto fail_string_ids; ++ } + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; +diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c +index ec9749845..8db5c91ae 100644 +--- a/drivers/usb/gadget/legacy/multi.c ++++ b/drivers/usb/gadget/legacy/multi.c +@@ -182,7 +182,7 @@ static int rndis_do_config(struct usb_configuration *c) + return ret; + } + +-static __ref int rndis_config_register(struct usb_composite_dev *cdev) ++static int rndis_config_register(struct usb_composite_dev *cdev) + { + static struct usb_configuration config = { + .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM, +@@ -197,7 +197,7 @@ static __ref int rndis_config_register(struct usb_composite_dev *cdev) + + #else + +-static __ref int rndis_config_register(struct usb_composite_dev *cdev) ++static int rndis_config_register(struct usb_composite_dev *cdev) + { + return 0; + } +@@ -265,7 +265,7 @@ static int cdc_do_config(struct usb_configuration *c) + return ret; + } + +-static __ref int cdc_config_register(struct usb_composite_dev *cdev) ++static int cdc_config_register(struct usb_composite_dev *cdev) + { + static struct usb_configuration config = { + .bConfigurationValue = MULTI_CDC_CONFIG_NUM, +@@ -280,7 +280,7 @@ static __ref int cdc_config_register(struct usb_composite_dev *cdev) + + #else + +-static __ref int cdc_config_register(struct usb_composite_dev *cdev) ++static int cdc_config_register(struct usb_composite_dev *cdev) + { + return 0; + } +@@ -291,7 +291,7 @@ static __ref int cdc_config_register(struct usb_composite_dev *cdev) + + /****************************** Gadget Bind ******************************/ + +-static int __ref multi_bind(struct usb_composite_dev *cdev) ++static int multi_bind(struct usb_composite_dev *cdev) + { + struct usb_gadget *gadget = cdev->gadget; + #ifdef CONFIG_USB_G_MULTI_CDC +@@ -399,8 +399,10 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); +- if (!usb_desc) ++ if (!usb_desc) { ++ status = -ENOMEM; + goto fail_string_ids; ++ } + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; +diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c +index 2cd389575..ed762ba9b 100644 +--- a/drivers/usb/gadget/legacy/printer.c ++++ b/drivers/usb/gadget/legacy/printer.c +@@ -50,6 +50,7 @@ MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"); + /* Number of requests to allocate per endpoint, not used for ep0. */ + static unsigned qlen = 10; + module_param(qlen, uint, S_IRUGO|S_IWUSR); ++MODULE_PARM_DESC(qlen, "The number of 8k buffers to use per endpoint"); + + #define QLEN qlen + +diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c +index b496ca937..2869bda64 100644 +--- a/drivers/usb/gadget/legacy/raw_gadget.c ++++ b/drivers/usb/gadget/legacy/raw_gadget.c +@@ -3,7 +3,8 @@ + * USB Raw Gadget driver. + * See Documentation/usb/raw-gadget.rst for more details. + * +- * Andrey Konovalov ++ * Copyright (c) 2020 Google, Inc. ++ * Author: Andrey Konovalov + */ + + #include +diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c +index 2c9eab2b8..94e22867d 100644 +--- a/drivers/usb/gadget/legacy/webcam.c ++++ b/drivers/usb/gadget/legacy/webcam.c +@@ -90,7 +90,7 @@ static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = { + .bLength = UVC_DT_HEADER_SIZE(1), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = UVC_VC_HEADER, +- .bcdUVC = cpu_to_le16(0x0100), ++ .bcdUVC = cpu_to_le16(0x0110), + .wTotalLength = 0, /* dynamic */ + .dwClockFrequency = cpu_to_le32(48000000), + .bInCollection = 0, /* dynamic */ +diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig +index f28e1bbd5..6c8842e54 100644 +--- a/drivers/usb/gadget/udc/Kconfig ++++ b/drivers/usb/gadget/udc/Kconfig +@@ -330,7 +330,6 @@ config USB_AMD5536UDC + config USB_FSL_QE + tristate "Freescale QE/CPM USB Device Controller" + depends on FSL_SOC && (QUICC_ENGINE || CPM) +- depends on !64BIT || BROKEN + help + Some of Freescale PowerPC processors have a Full Speed + QE/CPM2 USB controller, which support device mode with 4 +diff --git a/drivers/usb/gadget/udc/amd5536udc_pci.c b/drivers/usb/gadget/udc/amd5536udc_pci.c +index c80f9bd51..8d387e0e4 100644 +--- a/drivers/usb/gadget/udc/amd5536udc_pci.c ++++ b/drivers/usb/gadget/udc/amd5536udc_pci.c +@@ -153,11 +153,6 @@ static int udc_pci_probe( + pci_set_master(pdev); + pci_try_set_mwi(pdev); + +- dev->phys_addr = resource; +- dev->irq = pdev->irq; +- dev->pdev = pdev; +- dev->dev = &pdev->dev; +- + /* init dma pools */ + if (use_dma) { + retval = init_dma_pools(dev); +@@ -165,6 +160,11 @@ static int udc_pci_probe( + goto err_dma; + } + ++ dev->phys_addr = resource; ++ dev->irq = pdev->irq; ++ dev->pdev = pdev; ++ dev->dev = &pdev->dev; ++ + /* general probing */ + if (udc_probe(dev)) { + retval = -ENODEV; +diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c +index d11d3d143..be7bb64e3 100644 +--- a/drivers/usb/gadget/udc/aspeed-vhub/core.c ++++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c +@@ -36,7 +36,6 @@ void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req, + int status) + { + bool internal = req->internal; +- struct ast_vhub *vhub = ep->vhub; + + EPVDBG(ep, "completing request @%p, status %d\n", req, status); + +@@ -47,7 +46,7 @@ void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req, + + if (req->req.dma) { + if (!WARN_ON(!ep->dev)) +- usb_gadget_unmap_request_by_dev(&vhub->pdev->dev, ++ usb_gadget_unmap_request(&ep->dev->gadget, + &req->req, ep->epn.is_in); + req->req.dma = 0; + } +diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c +index cb164c615..02d8bfae5 100644 +--- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c ++++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c +@@ -376,7 +376,7 @@ static int ast_vhub_epn_queue(struct usb_ep* u_ep, struct usb_request *u_req, + if (ep->epn.desc_mode || + ((((unsigned long)u_req->buf & 7) == 0) && + (ep->epn.is_in || !(u_req->length & (u_ep->maxpacket - 1))))) { +- rc = usb_gadget_map_request_by_dev(&vhub->pdev->dev, u_req, ++ rc = usb_gadget_map_request(&ep->dev->gadget, u_req, + ep->epn.is_in); + if (rc) { + dev_warn(&vhub->pdev->dev, +diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c +index d9ad9adf7..eede5ceda 100644 +--- a/drivers/usb/gadget/udc/at91_udc.c ++++ b/drivers/usb/gadget/udc/at91_udc.c +@@ -1876,9 +1876,7 @@ static int at91udc_probe(struct platform_device *pdev) + clk_disable(udc->iclk); + + /* request UDC and maybe VBUS irqs */ +- udc->udp_irq = retval = platform_get_irq(pdev, 0); +- if (retval < 0) +- goto err_unprepare_iclk; ++ udc->udp_irq = platform_get_irq(pdev, 0); + retval = devm_request_irq(dev, udc->udp_irq, at91_udc_irq, 0, + driver_name, udc); + if (retval) { +diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c +index fa1a3908e..0bef6b3f0 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_core.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_core.c +@@ -488,14 +488,27 @@ static int bdc_probe(struct platform_device *pdev) + int irq; + u32 temp; + struct device *dev = &pdev->dev; ++ struct clk *clk; + int phy_num; + + dev_dbg(dev, "%s()\n", __func__); + ++ clk = devm_clk_get_optional(dev, "sw_usbd"); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ ret = clk_prepare_enable(clk); ++ if (ret) { ++ dev_err(dev, "could not enable clock\n"); ++ return ret; ++ } ++ + bdc = devm_kzalloc(dev, sizeof(*bdc), GFP_KERNEL); + if (!bdc) + return -ENOMEM; + ++ bdc->clk = clk; ++ + bdc->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(bdc->regs)) + return PTR_ERR(bdc->regs); +@@ -532,20 +545,10 @@ static int bdc_probe(struct platform_device *pdev) + } + } + +- bdc->clk = devm_clk_get_optional(dev, "sw_usbd"); +- if (IS_ERR(bdc->clk)) +- return PTR_ERR(bdc->clk); +- +- ret = clk_prepare_enable(bdc->clk); +- if (ret) { +- dev_err(dev, "could not enable clock\n"); +- return ret; +- } +- + ret = bdc_phy_init(bdc); + if (ret) { + dev_err(bdc->dev, "BDC phy init failure:%d\n", ret); +- goto disable_clk; ++ return ret; + } + + temp = bdc_readl(bdc->regs, BDC_BDCCAP1); +@@ -557,8 +560,7 @@ static int bdc_probe(struct platform_device *pdev) + if (ret) { + dev_err(dev, + "No suitable DMA config available, abort\n"); +- ret = -ENOTSUPP; +- goto phycleanup; ++ return -ENOTSUPP; + } + dev_dbg(dev, "Using 32-bit address\n"); + } +@@ -578,8 +580,6 @@ static int bdc_probe(struct platform_device *pdev) + bdc_hw_exit(bdc); + phycleanup: + bdc_phy_exit(bdc); +-disable_clk: +- clk_disable_unprepare(bdc->clk); + return ret; + } + +diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c +index 3a3b5a03d..5e8fb3598 100644 +--- a/drivers/usb/gadget/udc/core.c ++++ b/drivers/usb/gadget/udc/core.c +@@ -29,6 +29,7 @@ + * @list: for use by the udc class driver + * @vbus: for udcs who care about vbus status, this value is real vbus status; + * for udcs who do not care about vbus status, this value is always true ++ * @started: the UDC's started state. True if the UDC had started. + * + * This represents the internal data structure which is used by the UDC-class + * to hold information about udc driver and gadget together. +@@ -39,6 +40,7 @@ struct usb_udc { + struct device dev; + struct list_head list; + bool vbus; ++ bool started; + }; + + static struct class *udc_class; +@@ -1004,6 +1006,25 @@ int usb_gadget_ep_match_desc(struct usb_gadget *gadget, + } + EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc); + ++/** ++ * usb_gadget_check_config - checks if the UDC can support the binded ++ * configuration ++ * @gadget: controller to check the USB configuration ++ * ++ * Ensure that a UDC is able to support the requested resources by a ++ * configuration, and that there are no resource limitations, such as ++ * internal memory allocated to all requested endpoints. ++ * ++ * Returns zero on success, else a negative errno. ++ */ ++int usb_gadget_check_config(struct usb_gadget *gadget) ++{ ++ if (gadget->ops->check_config) ++ return gadget->ops->check_config(gadget); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(usb_gadget_check_config); ++ + /* ------------------------------------------------------------------------- */ + + static void usb_gadget_state_work(struct work_struct *work) +@@ -1085,7 +1106,18 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); + */ + static inline int usb_gadget_udc_start(struct usb_udc *udc) + { +- return udc->gadget->ops->udc_start(udc->gadget, udc->driver); ++ int ret; ++ ++ if (udc->started) { ++ dev_err(&udc->dev, "UDC had already started\n"); ++ return -EBUSY; ++ } ++ ++ ret = udc->gadget->ops->udc_start(udc->gadget, udc->driver); ++ if (!ret) ++ udc->started = true; ++ ++ return ret; + } + + /** +@@ -1101,7 +1133,13 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc) + */ + static inline void usb_gadget_udc_stop(struct usb_udc *udc) + { ++ if (!udc->started) { ++ dev_err(&udc->dev, "UDC had already stopped\n"); ++ return; ++ } ++ + udc->gadget->ops->udc_stop(udc->gadget); ++ udc->started = false; + } + + /** +@@ -1117,12 +1155,65 @@ static inline void usb_gadget_udc_stop(struct usb_udc *udc) + static inline void usb_gadget_udc_set_speed(struct usb_udc *udc, + enum usb_device_speed speed) + { +- if (udc->gadget->ops->udc_set_speed) { +- enum usb_device_speed s; ++ struct usb_gadget *gadget = udc->gadget; ++ enum usb_device_speed s; + +- s = min(speed, udc->gadget->max_speed); +- udc->gadget->ops->udc_set_speed(udc->gadget, s); +- } ++ if (speed == USB_SPEED_UNKNOWN) ++ s = gadget->max_speed; ++ else ++ s = min(speed, gadget->max_speed); ++ ++ if (s == USB_SPEED_SUPER_PLUS && gadget->ops->udc_set_ssp_rate) ++ gadget->ops->udc_set_ssp_rate(gadget, gadget->max_ssp_rate); ++ else if (gadget->ops->udc_set_speed) ++ gadget->ops->udc_set_speed(gadget, s); ++} ++ ++/** ++ * usb_gadget_enable_async_callbacks - tell usb device controller to enable asynchronous callbacks ++ * @udc: The UDC which should enable async callbacks ++ * ++ * This routine is used when binding gadget drivers. It undoes the effect ++ * of usb_gadget_disable_async_callbacks(); the UDC driver should enable IRQs ++ * (if necessary) and resume issuing callbacks. ++ * ++ * This routine will always be called in process context. ++ */ ++static inline void usb_gadget_enable_async_callbacks(struct usb_udc *udc) ++{ ++ struct usb_gadget *gadget = udc->gadget; ++ ++ if (gadget->ops->udc_async_callbacks) ++ gadget->ops->udc_async_callbacks(gadget, true); ++} ++ ++/** ++ * usb_gadget_disable_async_callbacks - tell usb device controller to disable asynchronous callbacks ++ * @udc: The UDC which should disable async callbacks ++ * ++ * This routine is used when unbinding gadget drivers. It prevents a race: ++ * The UDC driver doesn't know when the gadget driver's ->unbind callback ++ * runs, so unless it is told to disable asynchronous callbacks, it might ++ * issue a callback (such as ->disconnect) after the unbind has completed. ++ * ++ * After this function runs, the UDC driver must suppress all ->suspend, ++ * ->resume, ->disconnect, ->reset, and ->setup callbacks to the gadget driver ++ * until async callbacks are again enabled. A simple-minded but effective ++ * way to accomplish this is to tell the UDC hardware not to generate any ++ * more IRQs. ++ * ++ * Request completion callbacks must still be issued. However, it's okay ++ * to defer them until the request is cancelled, since the pull-up will be ++ * turned off during the time period when async callbacks are disabled. ++ * ++ * This routine will always be called in process context. ++ */ ++static inline void usb_gadget_disable_async_callbacks(struct usb_udc *udc) ++{ ++ struct usb_gadget *gadget = udc->gadget; ++ ++ if (gadget->ops->udc_async_callbacks) ++ gadget->ops->udc_async_callbacks(gadget, false); + } + + /** +@@ -1225,6 +1316,8 @@ int usb_add_gadget(struct usb_gadget *gadget) + udc->gadget = gadget; + gadget->udc = udc; + ++ udc->started = false; ++ + mutex_lock(&udc_lock); + list_add_tail(&udc->list, &udc_list); + +@@ -1337,6 +1430,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) + kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); + + usb_gadget_disconnect(udc->gadget); ++ usb_gadget_disable_async_callbacks(udc); + if (udc->gadget->irq) + synchronize_irq(udc->gadget->irq); + udc->driver->unbind(udc->gadget); +@@ -1416,6 +1510,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri + driver->unbind(udc->gadget); + goto err1; + } ++ usb_gadget_enable_async_callbacks(udc); + usb_udc_connect_control(udc); + + kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); +diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c +index 92d01ddae..9ae5fc8da 100644 +--- a/drivers/usb/gadget/udc/dummy_hcd.c ++++ b/drivers/usb/gadget/udc/dummy_hcd.c +@@ -932,6 +932,15 @@ static void dummy_udc_set_speed(struct usb_gadget *_gadget, + dummy_udc_update_ep0(dum); + } + ++static void dummy_udc_async_callbacks(struct usb_gadget *_gadget, bool enable) ++{ ++ struct dummy *dum = gadget_dev_to_dummy(&_gadget->dev); ++ ++ spin_lock_irq(&dum->lock); ++ dum->ints_enabled = enable; ++ spin_unlock_irq(&dum->lock); ++} ++ + static int dummy_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); + static int dummy_udc_stop(struct usb_gadget *g); +@@ -944,6 +953,7 @@ static const struct usb_gadget_ops dummy_ops = { + .udc_start = dummy_udc_start, + .udc_stop = dummy_udc_stop, + .udc_set_speed = dummy_udc_set_speed, ++ .udc_async_callbacks = dummy_udc_async_callbacks, + }; + + /*-------------------------------------------------------------------------*/ +@@ -1003,7 +1013,6 @@ static int dummy_udc_start(struct usb_gadget *g, + spin_lock_irq(&dum->lock); + dum->devstatus = 0; + dum->driver = driver; +- dum->ints_enabled = 1; + spin_unlock_irq(&dum->lock); + + return 0; +@@ -1017,6 +1026,7 @@ static int dummy_udc_stop(struct usb_gadget *g) + spin_lock_irq(&dum->lock); + dum->ints_enabled = 0; + stop_activity(dum); ++ + dum->driver = NULL; + spin_unlock_irq(&dum->lock); + +@@ -1869,7 +1879,7 @@ static void dummy_timer(struct timer_list *t) + /* handle control requests */ + if (ep == &dum->ep[0] && ep->setup_stage) { + struct usb_ctrlrequest setup; +- int value = 1; ++ int value; + + setup = *(struct usb_ctrlrequest *) urb->setup_packet; + /* paranoia, in case of stale queued data */ +diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c +index 75bf446f4..d6ca50f01 100644 +--- a/drivers/usb/gadget/udc/fotg210-udc.c ++++ b/drivers/usb/gadget/udc/fotg210-udc.c +@@ -338,16 +338,15 @@ static void fotg210_start_dma(struct fotg210_ep *ep, + } else { + buffer = req->req.buf + req->req.actual; + length = ioread32(ep->fotg210->reg + +- FOTG210_FIBCR(ep->epnum - 1)) & FIBCR_BCFX; +- if (length > req->req.length - req->req.actual) +- length = req->req.length - req->req.actual; ++ FOTG210_FIBCR(ep->epnum - 1)); ++ length &= FIBCR_BCFX; + } + } else { + buffer = req->req.buf + req->req.actual; + if (req->req.length - req->req.actual > ep->ep.maxpacket) + length = ep->ep.maxpacket; + else +- length = req->req.length - req->req.actual; ++ length = req->req.length; + } + + d = dma_map_single(dev, buffer, length, +@@ -380,7 +379,8 @@ static void fotg210_ep0_queue(struct fotg210_ep *ep, + } + if (ep->dir_in) { /* if IN */ + fotg210_start_dma(ep, req); +- if (req->req.length == req->req.actual) ++ if ((req->req.length == req->req.actual) || ++ (req->req.actual < ep->ep.maxpacket)) + fotg210_done(ep, req, 0); + } else { /* OUT */ + u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR0); +@@ -820,7 +820,7 @@ static void fotg210_ep0in(struct fotg210_udc *fotg210) + if (req->req.length) + fotg210_start_dma(ep, req); + +- if (req->req.actual == req->req.length) ++ if ((req->req.length - req->req.actual) < ep->ep.maxpacket) + fotg210_done(ep, req, 0); + } else { + fotg210_set_cxdone(fotg210); +@@ -849,16 +849,12 @@ static void fotg210_out_fifo_handler(struct fotg210_ep *ep) + { + struct fotg210_request *req = list_entry(ep->queue.next, + struct fotg210_request, queue); +- int disgr1 = ioread32(ep->fotg210->reg + FOTG210_DISGR1); + + fotg210_start_dma(ep, req); + +- /* Complete the request when it's full or a short packet arrived. +- * Like other drivers, short_not_ok isn't handled. +- */ +- ++ /* finish out transfer */ + if (req->req.length == req->req.actual || +- (disgr1 & DISGR1_SPK_INT(ep->epnum - 1))) ++ req->req.actual < ep->ep.maxpacket) + fotg210_done(ep, req, 0); + } + +@@ -1031,12 +1027,6 @@ static void fotg210_init(struct fotg210_udc *fotg210) + value &= ~DMCR_GLINT_EN; + iowrite32(value, fotg210->reg + FOTG210_DMCR); + +- /* enable only grp2 irqs we handle */ +- iowrite32(~(DISGR2_DMA_ERROR | DISGR2_RX0BYTE_INT | DISGR2_TX0BYTE_INT +- | DISGR2_ISO_SEQ_ABORT_INT | DISGR2_ISO_SEQ_ERR_INT +- | DISGR2_RESM_INT | DISGR2_SUSP_INT | DISGR2_USBRST_INT), +- fotg210->reg + FOTG210_DMISGR2); +- + /* disable all fifo interrupt */ + iowrite32(~(u32)0, fotg210->reg + FOTG210_DMISGR1); + +diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c +index 91c9e9057..35179543c 100644 +--- a/drivers/usb/gadget/udc/max3420_udc.c ++++ b/drivers/usb/gadget/udc/max3420_udc.c +@@ -1260,14 +1260,12 @@ static int max3420_probe(struct spi_device *spi) + err = devm_request_irq(&spi->dev, irq, max3420_irq_handler, 0, + "max3420", udc); + if (err < 0) +- goto del_gadget; ++ return err; + + udc->thread_task = kthread_create(max3420_thread, udc, + "max3420-thread"); +- if (IS_ERR(udc->thread_task)) { +- err = PTR_ERR(udc->thread_task); +- goto del_gadget; +- } ++ if (IS_ERR(udc->thread_task)) ++ return PTR_ERR(udc->thread_task); + + irq = of_irq_get_byname(spi->dev.of_node, "vbus"); + if (irq <= 0) { /* no vbus irq implies self-powered design */ +@@ -1287,14 +1285,10 @@ static int max3420_probe(struct spi_device *spi) + err = devm_request_irq(&spi->dev, irq, + max3420_vbus_handler, 0, "vbus", udc); + if (err < 0) +- goto del_gadget; ++ return err; + } + + return 0; +- +-del_gadget: +- usb_del_gadget_udc(&udc->gadget); +- return err; + } + + static int max3420_remove(struct spi_device *spi) +diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c +index 0db97fecf..5486f5a70 100644 +--- a/drivers/usb/gadget/udc/mv_u3d_core.c ++++ b/drivers/usb/gadget/udc/mv_u3d_core.c +@@ -1921,6 +1921,14 @@ static int mv_u3d_probe(struct platform_device *dev) + goto err_get_irq; + } + u3d->irq = r->start; ++ if (request_irq(u3d->irq, mv_u3d_irq, ++ IRQF_SHARED, driver_name, u3d)) { ++ u3d->irq = 0; ++ dev_err(&dev->dev, "Request irq %d for u3d failed\n", ++ u3d->irq); ++ retval = -ENODEV; ++ goto err_request_irq; ++ } + + /* initialize gadget structure */ + u3d->gadget.ops = &mv_u3d_ops; /* usb_gadget_ops */ +@@ -1933,15 +1941,6 @@ static int mv_u3d_probe(struct platform_device *dev) + + mv_u3d_eps_init(u3d); + +- if (request_irq(u3d->irq, mv_u3d_irq, +- IRQF_SHARED, driver_name, u3d)) { +- u3d->irq = 0; +- dev_err(&dev->dev, "Request irq %d for u3d failed\n", +- u3d->irq); +- retval = -ENODEV; +- goto err_request_irq; +- } +- + /* external vbus detection */ + if (u3d->vbus) { + u3d->clock_gating = 1; +@@ -1965,8 +1964,8 @@ static int mv_u3d_probe(struct platform_device *dev) + + err_unregister: + free_irq(u3d->irq, u3d); +-err_get_irq: + err_request_irq: ++err_get_irq: + kfree(u3d->status_req); + err_alloc_status_req: + kfree(u3d->eps); +diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c +index fd3656d0f..a3c1fc924 100644 +--- a/drivers/usb/gadget/udc/pch_udc.c ++++ b/drivers/usb/gadget/udc/pch_udc.c +@@ -7,14 +7,12 @@ + #include + #include + #include +-#include + #include +-#include +-#include + #include + #include + #include + #include ++#include + #include + + #define PCH_VBUS_PERIOD 3000 /* VBUS polling period (msec) */ +@@ -598,22 +596,18 @@ static void pch_udc_reconnect(struct pch_udc_dev *dev) + static inline void pch_udc_vbus_session(struct pch_udc_dev *dev, + int is_active) + { +- unsigned long iflags; +- +- spin_lock_irqsave(&dev->lock, iflags); + if (is_active) { + pch_udc_reconnect(dev); + dev->vbus_session = 1; + } else { + if (dev->driver && dev->driver->disconnect) { +- spin_unlock_irqrestore(&dev->lock, iflags); ++ spin_lock(&dev->lock); + dev->driver->disconnect(&dev->gadget); +- spin_lock_irqsave(&dev->lock, iflags); ++ spin_unlock(&dev->lock); + } + pch_udc_set_disconnect(dev); + dev->vbus_session = 0; + } +- spin_unlock_irqrestore(&dev->lock, iflags); + } + + /** +@@ -1172,25 +1166,20 @@ static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value) + static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on) + { + struct pch_udc_dev *dev; +- unsigned long iflags; + + if (!gadget) + return -EINVAL; +- + dev = container_of(gadget, struct pch_udc_dev, gadget); +- +- spin_lock_irqsave(&dev->lock, iflags); + if (is_on) { + pch_udc_reconnect(dev); + } else { + if (dev->driver && dev->driver->disconnect) { +- spin_unlock_irqrestore(&dev->lock, iflags); ++ spin_lock(&dev->lock); + dev->driver->disconnect(&dev->gadget); +- spin_lock_irqsave(&dev->lock, iflags); ++ spin_unlock(&dev->lock); + } + pch_udc_set_disconnect(dev); + } +- spin_unlock_irqrestore(&dev->lock, iflags); + + return 0; + } +@@ -1361,43 +1350,6 @@ static irqreturn_t pch_vbus_gpio_irq(int irq, void *data) + return IRQ_HANDLED; + } + +-static struct gpiod_lookup_table minnowboard_udc_gpios = { +- .dev_id = "0000:02:02.4", +- .table = { +- GPIO_LOOKUP("sch_gpio.33158", 12, NULL, GPIO_ACTIVE_HIGH), +- {} +- }, +-}; +- +-static const struct dmi_system_id pch_udc_gpio_dmi_table[] = { +- { +- .ident = "MinnowBoard", +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "MinnowBoard"), +- }, +- .driver_data = &minnowboard_udc_gpios, +- }, +- { } +-}; +- +-static void pch_vbus_gpio_remove_table(void *table) +-{ +- gpiod_remove_lookup_table(table); +-} +- +-static int pch_vbus_gpio_add_table(struct pch_udc_dev *dev) +-{ +- struct device *d = &dev->pdev->dev; +- const struct dmi_system_id *dmi; +- +- dmi = dmi_first_match(pch_udc_gpio_dmi_table); +- if (!dmi) +- return 0; +- +- gpiod_add_lookup_table(dmi->driver_data); +- return devm_add_action_or_reset(d, pch_vbus_gpio_remove_table, dmi->driver_data); +-} +- + /** + * pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS. + * @dev: Reference to the driver structure +@@ -1408,7 +1360,6 @@ static int pch_vbus_gpio_add_table(struct pch_udc_dev *dev) + */ + static int pch_vbus_gpio_init(struct pch_udc_dev *dev) + { +- struct device *d = &dev->pdev->dev; + int err; + int irq_num = 0; + struct gpio_desc *gpiod; +@@ -1416,12 +1367,8 @@ static int pch_vbus_gpio_init(struct pch_udc_dev *dev) + dev->vbus_gpio.port = NULL; + dev->vbus_gpio.intr = 0; + +- err = pch_vbus_gpio_add_table(dev); +- if (err) +- return err; +- + /* Retrieve the GPIO line from the USB gadget device */ +- gpiod = devm_gpiod_get_optional(d, NULL, GPIOD_IN); ++ gpiod = devm_gpiod_get(dev->gadget.dev.parent, NULL, GPIOD_IN); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + gpiod_set_consumer_name(gpiod, "pch_vbus"); +@@ -1809,7 +1756,7 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, + } + /* prevent from using desc. - set HOST BUSY */ + dma_desc->status |= PCH_UDC_BS_HST_BSY; +- dma_desc->dataptr = lower_32_bits(DMA_ADDR_INVALID); ++ dma_desc->dataptr = cpu_to_le32(DMA_ADDR_INVALID); + req->td_data = dma_desc; + req->td_data_last = dma_desc; + req->chain_len = 1; +@@ -2351,21 +2298,6 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num) + pch_udc_set_dma(dev, DMA_DIR_RX); + } + +-static int pch_udc_gadget_setup(struct pch_udc_dev *dev) +- __must_hold(&dev->lock) +-{ +- int rc; +- +- /* In some cases we can get an interrupt before driver gets setup */ +- if (!dev->driver) +- return -ESHUTDOWN; +- +- spin_unlock(&dev->lock); +- rc = dev->driver->setup(&dev->gadget, &dev->setup_data); +- spin_lock(&dev->lock); +- return rc; +-} +- + /** + * pch_udc_svc_control_in() - Handle Control IN endpoint interrupts + * @dev: Reference to the device structure +@@ -2437,12 +2369,15 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) + dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep; + else /* OUT */ + dev->gadget.ep0 = &ep->ep; ++ spin_lock(&dev->lock); + /* If Mass storage Reset */ + if ((dev->setup_data.bRequestType == 0x21) && + (dev->setup_data.bRequest == 0xFF)) + dev->prot_stall = 0; + /* call gadget with setup data received */ +- setup_supported = pch_udc_gadget_setup(dev); ++ setup_supported = dev->driver->setup(&dev->gadget, ++ &dev->setup_data); ++ spin_unlock(&dev->lock); + + if (dev->setup_data.bRequestType & USB_DIR_IN) { + ep->td_data->status = (ep->td_data->status & +@@ -2690,7 +2625,9 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) + dev->ep[i].halted = 0; + } + dev->stall = 0; +- pch_udc_gadget_setup(dev); ++ spin_unlock(&dev->lock); ++ dev->driver->setup(&dev->gadget, &dev->setup_data); ++ spin_lock(&dev->lock); + } + + /** +@@ -2725,7 +2662,9 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) + dev->stall = 0; + + /* call gadget zero with setup data received */ +- pch_udc_gadget_setup(dev); ++ spin_unlock(&dev->lock); ++ dev->driver->setup(&dev->gadget, &dev->setup_data); ++ spin_lock(&dev->lock); + } + + /** +@@ -2931,20 +2870,14 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev) + * @dev: Reference to the driver structure + * + * Return codes: +- * 0: Success +- * -%ERRNO: All kind of errors when retrieving VBUS GPIO ++ * 0: Success + */ + static int pch_udc_pcd_init(struct pch_udc_dev *dev) + { +- int ret; +- + pch_udc_init(dev); + pch_udc_pcd_reinit(dev); +- +- ret = pch_vbus_gpio_init(dev); +- if (ret) +- pch_udc_exit(dev); +- return ret; ++ pch_vbus_gpio_init(dev); ++ return 0; + } + + /** +@@ -3005,7 +2938,7 @@ static int init_dma_pools(struct pch_udc_dev *dev) + dev->dma_addr = dma_map_single(&dev->pdev->dev, ep0out_buf, + UDC_EP0OUT_BUFF_SIZE * 4, + DMA_FROM_DEVICE); +- return dma_mapping_error(&dev->pdev->dev, dev->dma_addr); ++ return 0; + } + + static int pch_udc_start(struct usb_gadget *g, +@@ -3130,7 +3063,6 @@ static int pch_udc_probe(struct pci_dev *pdev, + if (retval) + return retval; + +- dev->pdev = pdev; + pci_set_drvdata(pdev, dev); + + /* Determine BAR based on PCI ID */ +@@ -3146,10 +3078,16 @@ static int pch_udc_probe(struct pci_dev *pdev, + + dev->base_addr = pcim_iomap_table(pdev)[bar]; + ++ /* ++ * FIXME: add a GPIO descriptor table to pdev.dev using ++ * gpiod_add_descriptor_table() from based on ++ * the PCI subsystem ID. The system-dependent GPIO is necessary for ++ * VBUS operation. ++ */ ++ + /* initialize the hardware */ +- retval = pch_udc_pcd_init(dev); +- if (retval) +- return retval; ++ if (pch_udc_pcd_init(dev)) ++ return -ENODEV; + + pci_enable_msi(pdev); + +@@ -3166,6 +3104,7 @@ static int pch_udc_probe(struct pci_dev *pdev, + + /* device struct setup */ + spin_lock_init(&dev->lock); ++ dev->pdev = pdev; + dev->gadget.ops = &pch_udc_ops; + + retval = init_dma_pools(dev); +diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c +index 38e4d6b50..896c1a016 100644 +--- a/drivers/usb/gadget/udc/r8a66597-udc.c ++++ b/drivers/usb/gadget/udc/r8a66597-udc.c +@@ -1250,7 +1250,7 @@ static void set_feature(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl) + do { + tmp = r8a66597_read(r8a66597, INTSTS0) & CTSQ; + udelay(1); +- } while (tmp != CS_IDST && timeout-- > 0); ++ } while (tmp != CS_IDST || timeout-- > 0); + + if (tmp == CS_IDST) + r8a66597_bset(r8a66597, +@@ -1849,8 +1849,6 @@ static int r8a66597_probe(struct platform_device *pdev) + return PTR_ERR(reg); + + ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); +- if (!ires) +- return -EINVAL; + irq = ires->start; + irq_trigger = ires->flags & IRQF_TRIGGER_MASK; + +diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c +index 601829a6b..e91cbe43d 100644 +--- a/drivers/usb/gadget/udc/renesas_usb3.c ++++ b/drivers/usb/gadget/udc/renesas_usb3.c +@@ -1488,7 +1488,7 @@ static void usb3_start_pipen(struct renesas_usb3_ep *usb3_ep, + struct renesas_usb3_request *usb3_req) + { + struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); +- struct renesas_usb3_request *usb3_req_first; ++ struct renesas_usb3_request *usb3_req_first = usb3_get_request(usb3_ep); + unsigned long flags; + int ret = -EAGAIN; + u32 enable_bits = 0; +@@ -1496,8 +1496,7 @@ static void usb3_start_pipen(struct renesas_usb3_ep *usb3_ep, + spin_lock_irqsave(&usb3->lock, flags); + if (usb3_ep->halt || usb3_ep->started) + goto out; +- usb3_req_first = __usb3_get_request(usb3_ep); +- if (!usb3_req_first || usb3_req != usb3_req_first) ++ if (usb3_req != usb3_req_first) + goto out; + + if (usb3_pn_change(usb3, usb3_ep->num) < 0) +@@ -2709,15 +2708,10 @@ static const struct renesas_usb3_priv renesas_usb3_priv_r8a77990 = { + + static const struct of_device_id usb3_of_match[] = { + { +- .compatible = "renesas,r8a774c0-usb3-peri", +- .data = &renesas_usb3_priv_r8a77990, +- }, { + .compatible = "renesas,r8a7795-usb3-peri", + .data = &renesas_usb3_priv_gen3, +- }, { +- .compatible = "renesas,r8a77990-usb3-peri", +- .data = &renesas_usb3_priv_r8a77990, +- }, { ++ }, ++ { + .compatible = "renesas,rcar-gen3-usb3-peri", + .data = &renesas_usb3_priv_gen3, + }, +@@ -2726,10 +2720,18 @@ static const struct of_device_id usb3_of_match[] = { + MODULE_DEVICE_TABLE(of, usb3_of_match); + + static const struct soc_device_attribute renesas_usb3_quirks_match[] = { ++ { ++ .soc_id = "r8a774c0", ++ .data = &renesas_usb3_priv_r8a77990, ++ }, + { + .soc_id = "r8a7795", .revision = "ES1.*", + .data = &renesas_usb3_priv_r8a7795_es1, + }, ++ { ++ .soc_id = "r8a77990", ++ .data = &renesas_usb3_priv_r8a77990, ++ }, + { /* sentinel */ }, + }; + +diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c +index 82c4f3fb2..f1ea51476 100644 +--- a/drivers/usb/gadget/udc/s3c2410_udc.c ++++ b/drivers/usb/gadget/udc/s3c2410_udc.c +@@ -54,6 +54,8 @@ static struct clk *udc_clock; + static struct clk *usb_bus_clock; + static void __iomem *base_addr; + static int irq_usbd; ++static u64 rsrc_start; ++static u64 rsrc_len; + static struct dentry *s3c2410_udc_debugfs_root; + + static inline u32 udc_read(u32 reg) +@@ -1750,8 +1752,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) + udc_clock = clk_get(NULL, "usb-device"); + if (IS_ERR(udc_clock)) { + dev_err(dev, "failed to get udc clock source\n"); +- retval = PTR_ERR(udc_clock); +- goto err_usb_bus_clk; ++ return PTR_ERR(udc_clock); + } + + clk_prepare_enable(udc_clock); +@@ -1772,9 +1773,9 @@ static int s3c2410_udc_probe(struct platform_device *pdev) + udc_info = dev_get_platdata(&pdev->dev); + + base_addr = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(base_addr)) { +- retval = PTR_ERR(base_addr); +- goto err_udc_clk; ++ if (!base_addr) { ++ retval = -ENOMEM; ++ goto err_mem; + } + + the_controller = udc; +@@ -1784,10 +1785,6 @@ static int s3c2410_udc_probe(struct platform_device *pdev) + s3c2410_udc_reinit(udc); + + irq_usbd = platform_get_irq(pdev, 0); +- if (irq_usbd < 0) { +- retval = irq_usbd; +- goto err_udc_clk; +- } + + /* irq setup after old hardware state is cleaned up */ + retval = request_irq(irq_usbd, s3c2410_udc_irq, +@@ -1796,7 +1793,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) + if (retval != 0) { + dev_err(dev, "cannot get irq %i, err %d\n", irq_usbd, retval); + retval = -EBUSY; +- goto err_udc_clk; ++ goto err_map; + } + + dev_dbg(dev, "got irq %i\n", irq_usbd); +@@ -1867,14 +1864,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev) + gpio_free(udc_info->vbus_pin); + err_int: + free_irq(irq_usbd, udc); +-err_udc_clk: +- clk_disable_unprepare(udc_clock); +- clk_put(udc_clock); +- udc_clock = NULL; +-err_usb_bus_clk: +- clk_disable_unprepare(usb_bus_clock); +- clk_put(usb_bus_clock); +- usb_bus_clock = NULL; ++err_map: ++ iounmap(base_addr); ++err_mem: ++ release_mem_region(rsrc_start, rsrc_len); + + return retval; + } +@@ -1906,6 +1899,9 @@ static int s3c2410_udc_remove(struct platform_device *pdev) + + free_irq(irq_usbd, udc); + ++ iounmap(base_addr); ++ release_mem_region(rsrc_start, rsrc_len); ++ + if (!IS_ERR(udc_clock) && udc_clock != NULL) { + clk_disable_unprepare(udc_clock); + clk_put(udc_clock); +diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c +index 6c726d2e1..d046c09fa 100644 +--- a/drivers/usb/gadget/udc/snps_udc_core.c ++++ b/drivers/usb/gadget/udc/snps_udc_core.c +@@ -36,7 +36,6 @@ + #include + #include "amd5536udc.h" + +-static void udc_tasklet_disconnect(unsigned long); + static void udc_setup_endpoints(struct udc *dev); + static void udc_soft_reset(struct udc *dev); + static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep); +@@ -95,9 +94,6 @@ static struct timer_list udc_pollstall_timer; + static int stop_pollstall_timer; + static DECLARE_COMPLETION(on_pollstall_exit); + +-/* tasklet for usb disconnect */ +-static DECLARE_TASKLET_OLD(disconnect_tasklet, udc_tasklet_disconnect); +- + /* endpoint names used for print */ + static const char ep0_string[] = "ep0in"; + static const struct { +@@ -1637,6 +1633,8 @@ static void usb_connect(struct udc *dev) + */ + static void usb_disconnect(struct udc *dev) + { ++ u32 tmp; ++ + /* Return if already disconnected */ + if (!dev->connected) + return; +@@ -1648,23 +1646,6 @@ static void usb_disconnect(struct udc *dev) + /* mask interrupts */ + udc_mask_unused_interrupts(dev); + +- /* REVISIT there doesn't seem to be a point to having this +- * talk to a tasklet ... do it directly, we already hold +- * the spinlock needed to process the disconnect. +- */ +- +- tasklet_schedule(&disconnect_tasklet); +-} +- +-/* Tasklet for disconnect to be outside of interrupt context */ +-static void udc_tasklet_disconnect(unsigned long par) +-{ +- struct udc *dev = udc; +- u32 tmp; +- +- DBG(dev, "Tasklet disconnect\n"); +- spin_lock_irq(&dev->lock); +- + if (dev->driver) { + spin_unlock(&dev->lock); + dev->driver->disconnect(&dev->gadget); +@@ -1673,13 +1654,10 @@ static void udc_tasklet_disconnect(unsigned long par) + /* empty queues */ + for (tmp = 0; tmp < UDC_EP_NUM; tmp++) + empty_req_queue(&dev->ep[tmp]); +- + } + + /* disable ep0 */ +- ep_init(dev->regs, +- &dev->ep[UDC_EP0IN_IX]); +- ++ ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]); + + if (!soft_reset_occured) { + /* init controller by soft reset */ +@@ -1695,8 +1673,6 @@ static void udc_tasklet_disconnect(unsigned long par) + tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD); + writel(tmp, &dev->regs->cfg); + } +- +- spin_unlock_irq(&dev->lock); + } + + /* Reset the UDC core */ +diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c +index 3ebc8c541..95826f953 100644 +--- a/drivers/usb/gadget/udc/tegra-xudc.c ++++ b/drivers/usb/gadget/udc/tegra-xudc.c +@@ -1612,7 +1612,7 @@ static void tegra_xudc_ep_context_setup(struct tegra_xudc_ep *ep) + u16 maxpacket, maxburst = 0, esit = 0; + u32 val; + +- maxpacket = usb_endpoint_maxp(desc); ++ maxpacket = usb_endpoint_maxp(desc) & 0x7ff; + if (xudc->gadget.speed == USB_SPEED_SUPER) { + if (!usb_endpoint_xfer_control(desc)) + maxburst = comp_desc->bMaxBurst; +@@ -1623,7 +1623,7 @@ static void tegra_xudc_ep_context_setup(struct tegra_xudc_ep *ep) + (usb_endpoint_xfer_int(desc) || + usb_endpoint_xfer_isoc(desc))) { + if (xudc->gadget.speed == USB_SPEED_HIGH) { +- maxburst = usb_endpoint_maxp_mult(desc) - 1; ++ maxburst = (usb_endpoint_maxp(desc) >> 11) & 0x3; + if (maxburst == 0x3) { + dev_warn(xudc->dev, + "invalid endpoint maxburst\n"); +@@ -3861,7 +3861,6 @@ static int tegra_xudc_probe(struct platform_device *pdev) + return 0; + + free_eps: +- pm_runtime_disable(&pdev->dev); + tegra_xudc_free_eps(xudc); + free_event_ring: + tegra_xudc_free_event_ring(xudc); +@@ -3884,7 +3883,7 @@ static int tegra_xudc_remove(struct platform_device *pdev) + + pm_runtime_get_sync(xudc->dev); + +- cancel_delayed_work_sync(&xudc->plc_reset_work); ++ cancel_delayed_work(&xudc->plc_reset_work); + cancel_work_sync(&xudc->usb_role_sw_work); + + usb_del_gadget_udc(&xudc->gadget); +diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c +index 096f56a09..d5e9d20c0 100644 +--- a/drivers/usb/gadget/udc/udc-xilinx.c ++++ b/drivers/usb/gadget/udc/udc-xilinx.c +@@ -1612,8 +1612,6 @@ static void xudc_getstatus(struct xusb_udc *udc) + break; + case USB_RECIP_ENDPOINT: + epnum = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK; +- if (epnum >= XUSB_MAX_ENDPOINTS) +- goto stall; + target_ep = &udc->ep[epnum]; + epcfgreg = udc->read_fn(udc->addr + target_ep->offset); + halt = epcfgreg & XUSB_EP_CFG_STALL_MASK; +@@ -1681,10 +1679,6 @@ static void xudc_set_clear_feature(struct xusb_udc *udc) + case USB_RECIP_ENDPOINT: + if (!udc->setup.wValue) { + endpoint = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK; +- if (endpoint >= XUSB_MAX_ENDPOINTS) { +- xudc_ep0_stall(udc); +- return; +- } + target_ep = &udc->ep[endpoint]; + outinbit = udc->setup.wIndex & USB_ENDPOINT_DIR_MASK; + outinbit = outinbit >> 7; +diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig +index ef4787cd3..cb6a714bc 100644 +--- a/drivers/usb/phy/Kconfig ++++ b/drivers/usb/phy/Kconfig +@@ -76,6 +76,26 @@ config AM335X_PHY_USB + This driver provides PHY support for that phy which part for the + AM335x SoC. + ++choice ++ prompt "Ingenic usb Phy selects" ++ ++config INGENIC_INNOPHY ++ tristate "Ingenic usb phy(INNO) implemented." ++ select USB_PHY ++ help ++ Enable this to support Ingenic USB phy helper driver for ingenic SoCs. ++ This driver provides common interface to interact, for ingenic Inno PHY, ++ typically used for X2000 SOCs. ++ ++config INGENIC_USB_PHY ++ tristate "Ingenic usb phy." ++ select USB_PHY ++ help ++ Enable this to support Ingenic USB phy helper driver for ingenic SoCs. ++ This driver provides common interface to interact, typically used for INGENIC SOCs. ++ ++endchoice ++ + config TWL6030_USB + tristate "TWL6030 USB Transceiver Driver" + depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS +diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile +index b352bdbe8..08b70220f 100644 +--- a/drivers/usb/phy/Makefile ++++ b/drivers/usb/phy/Makefile +@@ -25,3 +25,6 @@ obj-$(CONFIG_USB_ULPI) += phy-ulpi.o + obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o + obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o + obj-$(CONFIG_JZ4770_PHY) += phy-jz4770.o ++obj-$(CONFIG_INGENIC_INNOPHY) += phy-ingenic-inno.o ++obj-$(CONFIG_INGENIC_USB_PHY) += phy-ingenic.o phy-ingenic-x1000.o phy-ingenic-x1600.o phy-ingenic-x2000.o phy-ingenic-x2500.o ++ +diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c +index 972704262..f34c9437a 100644 +--- a/drivers/usb/phy/phy-fsl-usb.c ++++ b/drivers/usb/phy/phy-fsl-usb.c +@@ -873,8 +873,6 @@ int usb_otg_start(struct platform_device *pdev) + + /* request irq */ + p_otg->irq = platform_get_irq(pdev, 0); +- if (p_otg->irq < 0) +- return p_otg->irq; + status = request_irq(p_otg->irq, fsl_otg_isr, + IRQF_SHARED, driver_name, p_otg); + if (status) { +diff --git a/drivers/usb/phy/phy-ingenic-inno.c b/drivers/usb/phy/phy-ingenic-inno.c +new file mode 100644 +index 000000000..8cbb313dc +--- /dev/null ++++ b/drivers/usb/phy/phy-ingenic-inno.c +@@ -0,0 +1,748 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../dwc2/core.h" ++#include "../dwc2/hcd.h" ++#include ++ ++#define usb_phy_readb(addr) readb((addr)) ++#define usb_phy_writeb(val, addr) writeb(val,(addr)) ++ ++#define PHY_TX_HS_STRENGTH_CONF (0x40) ++#define PHY_EYES_MAP_ADJ_CONF (0x60) ++#define PHY_REG_100 (0x100) ++#define PHY_SUSPEND_LPM (0x108) ++ ++#define PHY_RX_SQU_TRI (0x64) ++#define PHY_RX_SQU_TRI_112MV (0x0) ++#define PHY_RX_SQU_TRI_125MV (0x8) ++ ++/* just define for x2500 */ ++#define SRBC_USB_SR BIT (12) ++#define USBRDT_UTMI_RST BIT(27) ++ ++ ++static const struct of_device_id of_matchs[]; ++ ++struct inno_phy_tuning { ++ u8 val; ++ u8 msk; ++ u8 bit_off; ++ u32 reg_addr; ++}; ++ ++struct ingenic_usb_phy_priv { ++ bool phy_remote_wakeup; ++ bool phy_vbus_detect_ctl; ++ bool phy_ls_fs_driver_ctl; ++ int (*phyinit)(struct usb_phy*); ++ u32 phy_tuning_num; ++ struct inno_phy_tuning phy_tuning[]; ++}; ++ ++struct ingenic_usb_phy { ++ struct usb_phy phy; ++ struct device *dev; ++ struct clk *gate_clk; ++ struct regmap *regmap; ++ void __iomem *base; ++ char hsotg_sw_switch[8]; ++ struct ingenic_usb_phy_priv *iphy_priv; ++ ++ /*otg phy*/ ++ spinlock_t phy_lock; ++ struct gpio_desc *gpiod_drvvbus; ++ struct gpio_desc *gpiod_id; ++ struct gpio_desc *gpiod_vbus; ++ ++#define USB_DETE_VBUS 0x1 ++#define USB_DETE_ID 0x2 ++ unsigned int usb_dete_state; ++ unsigned int forced_dev_flags; ++ struct delayed_work work; ++ ++ enum usb_device_speed roothub_port_speed; ++}; ++ ++static inline int inno_usbphy_read(struct usb_phy *x, u32 reg) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ u32 val = 0; ++ regmap_read(iphy->regmap, reg, &val); ++ return val; ++} ++ ++static inline int inno_usbphy_write(struct usb_phy *x, u32 val, u32 reg) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ return regmap_write(iphy->regmap, reg, val); ++} ++ ++static inline int inno_usbphy_update_bits(struct usb_phy *x, u32 reg, u32 mask, u32 bits) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ return regmap_update_bits_check(iphy->regmap, reg, mask, bits, NULL); ++} ++ ++#ifdef CONFIG_USB_DWC2_DETECT_CONNECT ++static irqreturn_t usb_dete_irq_handler(int irq, void *data) ++{ ++ struct ingenic_usb_phy *iphy = (struct ingenic_usb_phy *)data; ++ ++ schedule_delayed_work(&iphy->work, msecs_to_jiffies(100)); ++ return IRQ_HANDLED; ++} ++ ++static void usb_dete_work(struct work_struct *work) ++{ ++ struct ingenic_usb_phy *iphy = ++ container_of(work, struct ingenic_usb_phy, work.work); ++ struct usb_otg *otg = iphy->phy.otg; ++ int vbus = 0, id_level = 1, usb_state = 0; ++ char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL }; ++ char *connected[2] = { "USB_STATE=CONNECTED", NULL }; ++ char *configured[2] = { "USB_STATE=CONFIGURED", NULL }; ++ ++ if (iphy->gpiod_vbus) ++ vbus = gpiod_get_value_cansleep(iphy->gpiod_vbus); ++ ++ if (iphy->gpiod_id) ++ id_level = gpiod_get_value_cansleep(iphy->gpiod_id); ++ ++ if (!strcmp(iphy->hsotg_sw_switch, "device")) { ++ id_level = 1; ++ } ++ ++ if (vbus && id_level) ++ usb_state |= USB_DETE_VBUS; ++ else ++ usb_state &= ~USB_DETE_VBUS; ++ ++ if (id_level) ++ usb_state |= USB_DETE_ID; ++ else ++ usb_state &= ~USB_DETE_ID; ++ ++ ++ if (usb_state != iphy->usb_dete_state) { ++ enum usb_phy_events status; ++ ++ iphy->usb_dete_state = usb_state; ++ printk(KERN_DEBUG "%s() usb_state=0x%x, iphy->phy.devname=%s\n", __func__, usb_state, dev_name(iphy->phy.dev)); ++ if (!(usb_state & USB_DETE_VBUS)) { ++ status = USB_EVENT_NONE; ++ otg->state = OTG_STATE_B_IDLE; ++ iphy->phy.last_event = status; ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) ++ if (otg->gadget){ ++ usb_gadget_vbus_disconnect(otg->gadget); ++ atomic_notifier_call_chain(&iphy->phy.notifier, status, ++ otg->gadget); ++ } ++#endif ++ kobject_uevent_env(&iphy->phy.dev->kobj, ++ KOBJ_CHANGE, disconnected); ++ } ++ ++ if (!(usb_state & USB_DETE_ID)) { ++ status = USB_EVENT_ID; ++ otg->state = OTG_STATE_A_IDLE; ++ iphy->phy.last_event = status; ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) ++ if (otg->gadget) { ++ usb_gadget_vbus_connect(otg->gadget); ++ } ++#endif ++ if (otg->host) { ++ atomic_notifier_call_chain(&iphy->phy.notifier, status, ++ otg->host); ++ } ++ kobject_uevent_env(&iphy->phy.dev->kobj, ++ KOBJ_CHANGE, connected); ++ } ++ ++ if (usb_state & USB_DETE_VBUS) { ++ status = USB_EVENT_VBUS; ++ otg->state = OTG_STATE_B_PERIPHERAL; ++ iphy->phy.last_event = status; ++ ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) ++ if (otg->gadget){ ++ usb_gadget_vbus_connect(otg->gadget); ++ atomic_notifier_call_chain(&iphy->phy.notifier, status, ++ otg->gadget); ++ } ++#endif ++ kobject_uevent_env(&iphy->phy.dev->kobj, ++ KOBJ_CHANGE, connected); ++ } ++ iphy->usb_dete_state = usb_state; ++ } ++ ++ return; ++} ++#endif ++ ++static int iphy_init(struct usb_phy *x) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ struct inno_phy_tuning *phy_tuning = iphy->iphy_priv->phy_tuning; ++ u32 phy_tuning_num = iphy->iphy_priv->phy_tuning_num; ++ u32 usbpcr, usbpcr1; ++ unsigned long flags; ++ u32 i; ++ u8 reg; ++ ++ /* USB phy clk opened. */ ++ if (!IS_ERR_OR_NULL(iphy->gate_clk)) ++ clk_prepare_enable(iphy->gate_clk); ++ ++ spin_lock_irqsave(&iphy->phy_lock, flags); ++ usbpcr1 = inno_usbphy_read(x, CPM_USBPCR1); ++ usbpcr1 &= ~(USBPCR1_DPPULLDOWN | USBPCR1_DMPULLDOWN); ++ inno_usbphy_write(x, usbpcr1, CPM_USBPCR1); ++ ++ usbpcr = inno_usbphy_read(x, CPM_USBPCR); ++ usbpcr &= ~USBPCR_IDPULLUP_MASK; ++#if (IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)) ++ usbpcr |= USBPCR_USB_MODE | USBPCR_IDPULLUP_OTG; ++#elif IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) ++ usbpcr &= ~USBPCR_USB_MODE | USBPCR_IDPULLUP_OTG; ++#endif ++ inno_usbphy_write(x, usbpcr, CPM_USBPCR); ++ ++ inno_usbphy_update_bits(x, CPM_USBPCR1, USBPCR1_PORT_RST, USBPCR1_PORT_RST); ++ inno_usbphy_update_bits(x, CPM_USBPCR, USBPCR_POR, USBPCR_POR); ++ udelay(11); ++ inno_usbphy_update_bits(x, CPM_USBPCR, USBPCR_POR, 0); ++ udelay(11); ++ inno_usbphy_update_bits(x, CPM_OPCR, OPCR_USB_SPENDN, OPCR_USB_SPENDN); ++ udelay(501); ++ inno_usbphy_update_bits(x, CPM_USBPCR1, USBPCR1_PORT_RST, 0); ++ udelay(1); ++ ++ usbpcr1 = inno_usbphy_read(x, CPM_USBPCR1); ++ usbpcr1 |= USBPCR1_DPPULLDOWN | USBPCR1_DMPULLDOWN; ++ inno_usbphy_write(x, usbpcr1, CPM_USBPCR1); ++ ++ /* set squelch trigger point */ ++ reg = usb_phy_readb(iphy->base + PHY_RX_SQU_TRI); ++ reg &= ~(0xf << 3); ++ reg |= PHY_RX_SQU_TRI_125MV << 3; ++ usb_phy_writeb(reg,iphy->base + PHY_RX_SQU_TRI); ++ ++ /* set inno usb phy tuning */ ++ for (i = 0; i < phy_tuning_num; i++) { ++ reg = usb_phy_readb(iphy->base + phy_tuning[i].reg_addr); ++ reg &= ~(phy_tuning[i].msk << phy_tuning[i].bit_off); ++ reg |= (phy_tuning[i].val << phy_tuning[i].bit_off); ++ usb_phy_writeb(reg, iphy->base + phy_tuning[i].reg_addr); ++ } ++ ++ spin_unlock_irqrestore(&iphy->phy_lock, flags); ++ return 0; ++} ++ ++static int iphy_init_x2500(struct usb_phy *x) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ u32 usbpcr, usbpcr1; ++ unsigned long flags; ++ u8 reg; ++ ++ if (!IS_ERR_OR_NULL(iphy->gate_clk)) ++ clk_prepare_enable(iphy->gate_clk); ++ ++ spin_lock_irqsave(&iphy->phy_lock, flags); ++ usbpcr1 = inno_usbphy_read(x, CPM_USBPCR1); ++ usbpcr1 |= USBPCR1_DPPULLDOWN | USBPCR1_DMPULLDOWN; ++ inno_usbphy_write(x, usbpcr1, CPM_USBPCR1); ++ ++ usbpcr = inno_usbphy_read(x, CPM_USBPCR); ++ usbpcr &= ~USBPCR_IDPULLUP_MASK; ++#if IS_ENABLED(CONFIG_USB_DWC2_HOST) ++ usbpcr |= USBPCR_USB_MODE | USBPCR_IDPULLUP_OTG; ++#elif IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) ++ usbpcr &= ~USBPCR_USB_MODE; ++#endif ++ inno_usbphy_write(x, usbpcr, CPM_USBPCR); ++ inno_usbphy_update_bits(x, CPM_USBPCR1, USBPCR1_PORT_RST, USBPCR1_PORT_RST); ++ inno_usbphy_update_bits(x, CPM_USBRDT, USBRDT_UTMI_RST, 0); ++ inno_usbphy_update_bits(x, CPM_USBPCR, USBPCR_POR, USBPCR_POR); ++ inno_usbphy_update_bits(x, CPM_SRBC, SRBC_USB_SR, SRBC_USB_SR); ++ udelay(5); ++ inno_usbphy_update_bits(x, CPM_USBPCR, USBPCR_POR, 0); ++ udelay(10); ++ inno_usbphy_update_bits(x, CPM_OPCR, OPCR_USB_SPENDN, OPCR_USB_SPENDN); ++ udelay(550); ++ inno_usbphy_update_bits(x, CPM_USBRDT, USBRDT_UTMI_RST, USBRDT_UTMI_RST); ++ udelay(10); ++ inno_usbphy_update_bits(x, CPM_SRBC, SRBC_USB_SR, 0); ++ ++ /* set squelch trigger point */ ++ reg = usb_phy_readb(iphy->base + PHY_RX_SQU_TRI); ++ reg &= ~(0xf << 3); ++ reg |= PHY_RX_SQU_TRI_125MV << 3; ++ usb_phy_writeb(reg,iphy->base + PHY_RX_SQU_TRI); ++ ++ ++ spin_unlock_irqrestore(&iphy->phy_lock, flags); ++ return 0; ++} ++ ++static int iphy_set_suspend(struct usb_phy *x, int suspend); ++static void iphy_shutdown(struct usb_phy *x) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ bool vbus_detect_ctl = iphy->iphy_priv->phy_vbus_detect_ctl; ++ bool ls_fs_driver_ctl = iphy->iphy_priv->phy_ls_fs_driver_ctl; ++ ++ iphy_set_suspend(x, 1); ++ ++ /* VBUS voltage level detection power down. */ ++ if (vbus_detect_ctl) ++ usb_phy_writeb(0x8, iphy->base + PHY_SUSPEND_LPM); ++ ++ /* disable full/low speed driver at the receiver */ ++ /* NOTE: it is used to reducepower consumption. */ ++ if (ls_fs_driver_ctl) { ++ unsigned int reg = usb_phy_readb(iphy->base + PHY_REG_100); ++ reg &= ~(1<<6); ++ usb_phy_writeb(reg, iphy->base + PHY_REG_100); ++ } ++ ++ /* USB phy clk gate. */ ++ if (!IS_ERR_OR_NULL(iphy->gate_clk)) ++ clk_disable_unprepare(iphy->gate_clk); ++} ++ ++static int iphy_set_vbus(struct usb_phy *x, int on) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ if (!(IS_ERR_OR_NULL(iphy->gpiod_drvvbus))) { ++ printk("OTG VBUS %s\n", on ? "ON" : "OFF"); ++ ++#ifdef CONFIG_HALLEY5_V10_HOST_TO_4GMODULE ++ if(!(IS_ENABLED(CONFIG_DT_HALLEY5_V10) && IS_ENABLED(CONFIG_USB_DWC2_HOST))) ++#endif ++ gpiod_set_value(iphy->gpiod_drvvbus, on); ++ } ++ return 0; ++} ++ ++static int iphy_set_wakeup(struct usb_phy *x, bool enabled); ++static int iphy_set_suspend(struct usb_phy *x, int suspend) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&iphy->phy_lock, flags); ++ ++ if(suspend){ ++ /* USB phy port reset is low. */ ++ inno_usbphy_update_bits(x, CPM_OPCR, USBPCR1_PORT_RST, 0); ++ ++ /* USB phy enter suspend. */ ++ inno_usbphy_update_bits(x, CPM_OPCR, OPCR_USB_SPENDN, 0); ++ ++ udelay(10); ++ } else { ++ /* USB PHY resume. */ ++ inno_usbphy_update_bits(x, CPM_OPCR, OPCR_USB_SPENDN, OPCR_USB_SPENDN); ++ udelay(501); ++ ++ inno_usbphy_update_bits(x, CPM_USBPCR1, USBPCR1_PORT_RST, USBPCR1_PORT_RST); ++ udelay(2); ++ ++ inno_usbphy_update_bits(x, CPM_USBPCR1, USBPCR1_PORT_RST, 0); ++ udelay(1); ++ ++ } ++ ++ spin_unlock_irqrestore(&iphy->phy_lock, flags); ++ ++ return 0; ++} ++ ++static int iphy_set_wakeup(struct usb_phy *x, bool enabled) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ struct usb_otg *otg = iphy->phy.otg; ++ enum usb_device_speed speed; ++ unsigned long flags; ++ int timeout; ++ unsigned int usbrdt; ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) ++ struct dwc2_hsotg *hsotg = (struct dwc2_hsotg *)container_of(otg->gadget, struct dwc2_hsotg, gadget); ++#endif ++ ++ spin_lock_irqsave(&iphy->phy_lock, flags); ++ ++ if (enabled) { ++ /* Enable resume interrupt */ ++ usbrdt = inno_usbphy_read(x, CPM_USBRDT); ++ usbrdt &= ~USBRDT_RESUME_SPEED_MSK; ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) ++ if (dwc2_is_device_mode(hsotg)) { ++ speed = (otg && otg->gadget) ? otg->gadget->speed : USB_SPEED_FULL; ++ if(speed == USB_SPEED_HIGH) ++ usbrdt |= USBRDT_RESUME_SPEED_HIGH; ++ if(speed == USB_SPEED_FULL) ++ usbrdt |= USBRDT_RESUME_SPEED_FULL; ++ if(speed == USB_SPEED_LOW) ++ usbrdt |= USBRDT_RESUME_SPEED_LOW; ++ } else { ++ /* Remote wakeup device speed. */ ++ usbrdt |= USBRDT_RESUME_SPEED_LOW; ++ } ++#else ++ usbrdt |= USBRDT_RESUME_SPEED_LOW; ++#endif ++ inno_usbphy_write(x, usbrdt, CPM_USBRDT); ++ ++ //TODO: the function be in suspend. ++ inno_usbphy_update_bits(x, CPM_USBRDT, USBRDT_RESUME_INTEEN, USBRDT_RESUME_INTEEN); ++ ++ } else { ++ /* Disable usb resume interrupt. */ ++ inno_usbphy_update_bits(x, CPM_USBRDT, USBRDT_RESUME_INTEEN, 0); ++ ++ /* Clear usb resume interrupt. */ ++ usbrdt = inno_usbphy_read(x, CPM_USBRDT); ++ if(usbrdt & (USBRDT_RESUME_STATUS)){ ++ usbrdt |= USBRDT_RESUME_INTERCLR; ++ inno_usbphy_write(x, usbrdt, CPM_USBRDT); ++ timeout = 100; ++ while(1){ ++ if(timeout-- < 0){ ++ printk("%s:%d resume interrupt clear failed\n", __func__, __LINE__); ++ return -EAGAIN; ++ } ++ usbrdt = inno_usbphy_read(x, CPM_USBRDT); ++ if(!(usbrdt & (USBRDT_RESUME_STATUS))) ++ break; ++ } ++ } ++ ++ } ++ /* Clear usb resume interrupt bit. */ ++ inno_usbphy_update_bits(x, CPM_USBRDT, USBRDT_RESUME_INTERCLR, 0); ++ ++ spin_unlock_irqrestore(&iphy->phy_lock, flags); ++ ++ return 0; ++} ++ ++static int iphy_set_host(struct usb_otg *otg, struct usb_bus *host) ++{ ++ if (!otg) ++ return -ENODEV; ++ otg->host = host; ++ return 0; ++} ++ ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) ++static int iphy_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) ++{ ++ if (!otg) ++ return -ENODEV; ++ ++ otg->gadget = gadget; ++#ifdef CONFIG_USB_DWC2_DETECT_CONNECT ++ struct ingenic_usb_phy *iphy = container_of(otg->usb_phy, struct ingenic_usb_phy, phy); ++ if(gadget){ ++ iphy->usb_dete_state = ~iphy->usb_dete_state; ++ schedule_delayed_work(&iphy->work, msecs_to_jiffies(100)); ++ } ++#endif ++ return 0; ++} ++#else ++#define iphy_set_peripheral NULL ++#endif ++ ++static int iphy_notify_connect(struct usb_phy *x, ++ enum usb_device_speed speed) ++{ ++ struct ingenic_usb_phy *iphy = container_of(x, struct ingenic_usb_phy, phy); ++ ++ iphy->roothub_port_speed = speed; ++ ++ return 0; ++} ++ ++static int usb_phy_ingenic_probe(struct platform_device *pdev) ++{ ++ struct ingenic_usb_phy *iphy; ++ struct resource *res; ++ const struct of_device_id *match; ++ int ret; ++#ifdef CONFIG_USB_DWC2_DETECT_CONNECT ++ int vbus; ++#endif ++ ++ iphy = (struct ingenic_usb_phy *) ++ devm_kzalloc(&pdev->dev, sizeof(*iphy), GFP_KERNEL); ++ if (!iphy) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ iphy->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(iphy->base)) ++ return PTR_ERR(iphy->base); ++ match = of_match_node(of_matchs, pdev->dev.of_node); ++ if (!match) ++ return -ENODEV; ++ iphy->iphy_priv = (struct ingenic_usb_phy_priv*)match->data; ++ iphy->phy.init = iphy->iphy_priv->phyinit; ++ iphy->phy.shutdown = iphy_shutdown; ++ iphy->phy.dev = &pdev->dev; ++ iphy->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, NULL); ++ if (IS_ERR(iphy->regmap)) { ++ dev_err(&pdev->dev, "failed to find regmap for usb phy %ld\n", PTR_ERR(iphy->regmap)); ++ return PTR_ERR(iphy->regmap); ++ } ++ ++ spin_lock_init(&iphy->phy_lock); ++ ++#ifdef CONFIG_USB_DWC2_DETECT_CONNECT ++ iphy->gpiod_id = devm_gpiod_get_optional(&pdev->dev,"ingenic,id-dete", GPIOD_IN); ++ iphy->gpiod_vbus = devm_gpiod_get_optional(&pdev->dev,"ingenic,vbus-dete", GPIOD_ASIS); ++ if (iphy->gpiod_id || iphy->gpiod_vbus) { ++ INIT_DELAYED_WORK(&iphy->work, usb_dete_work); ++ } ++ ++ ++ if (!IS_ERR_OR_NULL(iphy->gpiod_id)) { ++ ret = devm_request_irq(&pdev->dev, ++ gpiod_to_irq(iphy->gpiod_id), ++ usb_dete_irq_handler, ++ IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_ONESHOT, ++ "id_dete", ++ (void *)iphy); ++ if (ret) ++ return ret; ++ } else { ++ iphy->usb_dete_state |= USB_DETE_ID; ++ iphy->gpiod_id = NULL; ++ } ++ ++ if (!IS_ERR_OR_NULL(iphy->gpiod_vbus)) { ++ ret = devm_request_irq(&pdev->dev, ++ gpiod_to_irq(iphy->gpiod_vbus), ++ usb_dete_irq_handler, ++ IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_ONESHOT, ++ "vbus_dete", ++ (void *)iphy); ++ if (ret) ++ return ret; ++ vbus = gpiod_get_value_cansleep(iphy->gpiod_vbus); ++ if(vbus) ++ iphy->usb_dete_state |= USB_DETE_VBUS; ++ else ++ iphy->usb_dete_state &= ~USB_DETE_VBUS; ++ } else { ++ iphy->usb_dete_state &= ~USB_DETE_VBUS; ++ iphy->gpiod_vbus = NULL; ++ } ++#else ++ iphy->usb_dete_state |= USB_DETE_ID; ++ iphy->gpiod_id = NULL; ++ ++ iphy->usb_dete_state &= ~USB_DETE_VBUS; ++ iphy->gpiod_vbus = NULL; ++#endif ++ iphy->gpiod_drvvbus = devm_gpiod_get_optional(&pdev->dev,"ingenic,drvvbus", GPIOD_OUT_LOW); ++ if (IS_ERR_OR_NULL(iphy->gpiod_drvvbus)) ++ iphy->gpiod_drvvbus = NULL; ++ iphy->phy.set_vbus = iphy_set_vbus; ++ iphy->phy.set_suspend = iphy_set_suspend; ++ if (iphy->iphy_priv->phy_remote_wakeup) { ++ iphy->phy.set_wakeup = iphy_set_wakeup; ++ } ++ ++ iphy->phy.notify_connect = iphy_notify_connect; ++ iphy->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*iphy->phy.otg), ++ GFP_KERNEL); ++ iphy->phy.io_ops = devm_kzalloc(&pdev->dev, sizeof(*iphy->phy.io_ops), ++ GFP_KERNEL); ++ ++ if (!iphy->phy.otg) ++ return -ENOMEM; ++ ++ iphy->phy.type = USB_PHY_TYPE_USB2; ++ iphy->phy.otg->state = OTG_STATE_UNDEFINED; ++ iphy->phy.otg->usb_phy = &iphy->phy; ++ iphy->phy.otg->set_host = iphy_set_host; ++ iphy->phy.otg->set_peripheral = iphy_set_peripheral; ++ iphy->phy.io_ops->read = inno_usbphy_read; ++ iphy->phy.io_ops->write = inno_usbphy_write; ++ ++ iphy->gate_clk = devm_clk_get(&pdev->dev, "gate_usbphy"); ++ if (IS_ERR_OR_NULL(iphy->gate_clk)){ ++ iphy->gate_clk = NULL; ++ dev_err(&pdev->dev, "cannot get usbphy clock !\n"); ++ return -ENODEV; ++ } ++ ++ ret = usb_add_phy_dev(&iphy->phy); ++ if (ret) { ++ dev_err(&pdev->dev, "can't register transceiver, err: %d\n", ++ ret); ++ return ret; ++ } ++ platform_set_drvdata(pdev, iphy); ++ pr_info("inno phy probe success\n"); ++ return 0; ++} ++ ++static int usb_phy_ingenic_remove(struct platform_device *pdev) ++{ ++ struct ingenic_usb_phy *iphy = platform_get_drvdata(pdev); ++ ++ usb_remove_phy(&iphy->phy); ++ return 0; ++} ++ ++static int usb_gpio_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ ++ return 0; ++} ++ ++static int usb_gpio_resume(struct platform_device *dev) ++{ ++#ifdef CONFIG_USB_DWC2_DETECT_CONNECT ++ struct ingenic_usb_phy *iphy = platform_get_drvdata(dev); ++ ++ ++ schedule_delayed_work(&iphy->work, msecs_to_jiffies(100)); ++#endif ++ ++ return 0; ++} ++ ++/* for x1600 */ ++struct ingenic_usb_phy_priv usb_phy_x1600_priv = { ++ .phyinit = iphy_init, ++ .phy_tuning_num = 8, ++ .phy_tuning = { ++ /* set 45ohm HS ODT value */ ++ [0].reg_addr = 0x11c, ++ [0].msk = 0x1f, ++ [0].bit_off = 0, ++ [0].val = 0x1c, ++ ++ /* always enable pre-emphasis */ ++ [1].reg_addr = 0x30, ++ [1].msk = 0x7, ++ [1].bit_off = 0, ++ [1].val = 0x7, ++ ++ /* Tx HS pre_emphasize strength */ ++ [2].reg_addr = 0x40, ++ [2].msk = 0x7, ++ [2].bit_off = 3, ++ [2].val = 0x7, ++ ++ /* set A session valid reference tuning */ ++ [3].reg_addr = 0x10c, ++ [3].msk = 0x7, ++ [3].bit_off = 0, ++ [3].val = 0x5, ++ ++ /* set B session valid reference tuning */ ++ [4].reg_addr = 0x10c, ++ [4].msk = 0x7, ++ [4].bit_off = 3, ++ [4].val = 0x5, ++ ++ /* set vbus valid reference tuning */ ++ [5].reg_addr = 0x110, ++ [5].msk = 0x7, ++ [5].bit_off = 0, ++ [5].val = 0x5, ++ ++ /* set session end reference tuning */ ++ [6].reg_addr = 0x110, ++ [6].msk = 0x7, ++ [6].bit_off = 3, ++ [6].val = 0x5, ++ ++ /* enable control of full/low speed driver at the receiver */ ++ /* NOTE: Set to 0 during suspend, it is used to reducepower consumption. Restore here. */ ++ [7].reg_addr = 0x100, ++ [7].msk = 0x1, ++ [7].bit_off = 6, ++ [7].val = 0x1, ++ }, ++ .phy_remote_wakeup = 1, ++ .phy_vbus_detect_ctl = 1, ++ .phy_ls_fs_driver_ctl = 1, ++}; ++ ++/* for x2500 */ ++struct ingenic_usb_phy_priv usb_phy_x2500_priv = { ++ .phyinit = iphy_init_x2500, ++ .phy_tuning_num = 0, ++ .phy_remote_wakeup = 0, ++ .phy_vbus_detect_ctl = 0, ++ .phy_ls_fs_driver_ctl = 0, ++}; ++ ++/* usb_phy_common for x2000/x2000E x2100 m300 */ ++struct ingenic_usb_phy_priv usb_phy_common_priv = { ++ .phyinit = iphy_init, ++ .phy_tuning_num = 0, ++ .phy_remote_wakeup = 0, ++ .phy_vbus_detect_ctl = 1, ++ .phy_ls_fs_driver_ctl = 0, ++}; ++ ++static const struct of_device_id of_matchs[] = { ++ { .compatible = "ingenic,innophy",.data = (void*)&usb_phy_common_priv}, ++ { .compatible = "ingenic,innophy-x1600",.data = (void*)&usb_phy_x1600_priv}, ++ { .compatible = "ingenic,innophy-x2500",.data = (void*)&usb_phy_x2500_priv}, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_xceiv_dt_ids); ++ ++static struct platform_driver usb_phy_ingenic_driver = { ++ .probe = usb_phy_ingenic_probe, ++ .remove = usb_phy_ingenic_remove, ++ .suspend = usb_gpio_suspend, ++ .resume = usb_gpio_resume, ++ .driver = { ++ .name = "usb_phy", ++ .of_match_table = of_matchs, ++ }, ++}; ++ ++static int __init usb_phy_ingenic_init(void) ++{ ++ return platform_driver_register(&usb_phy_ingenic_driver); ++} ++subsys_initcall(usb_phy_ingenic_init); ++ ++static void __exit usb_phy_ingenic_exit(void) ++{ ++ platform_driver_unregister(&usb_phy_ingenic_driver); ++} ++module_exit(usb_phy_ingenic_exit); +diff --git a/drivers/usb/phy/phy-ingenic-x1000.c b/drivers/usb/phy/phy-ingenic-x1000.c +new file mode 100644 +index 000000000..81b90e6f4 +--- /dev/null ++++ b/drivers/usb/phy/phy-ingenic-x1000.c +@@ -0,0 +1,66 @@ ++#include ++#include "phy-ingenic.h" ++ ++#define CPM_USBPCR (0x3c) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++ ++#define CPM_SRBC (0xc4) ++#define CPM_OPCR (0x24) ++ ++#define OPCR_SPENDN0_BIT 7 ++#define OPCR_GATE_USBPHY_CLK_BIT 23 ++#define SRBC_USB_SR 12 ++ ++static int x1000_priv_data_init(struct usb_phy_data *usb_phy) ++{ ++ /* reset usb */ ++ usb_cpm_set_bit(usb_phy, SRBC_USB_SR, CPM_SRBC); ++ udelay(10); ++ usb_cpm_clear_bit(usb_phy, SRBC_USB_SR, CPM_SRBC); ++ ++ usb_cpm_set_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ ++ return 0; ++} ++ ++static int x1000_phy_init(struct usb_phy_data *usb_phy) ++{ ++ /* vbus signal always valid, id pin always pullup */ ++ usb_cpm_writel(usb_phy, 0xA3C919FF, CPM_USBPCR); ++ usb_cpm_writel(usb_phy, 0x0D280000, CPM_USBPCR1); ++ udelay(500); ++#ifdef CONFIG_USB_DWC2_EXT_VBUS_DETECT ++ usb_cpm_writel(usb_phy, 0xA38919FF, CPM_USBPCR); ++#else ++ usb_cpm_writel(usb_phy, 0xA20919FF, CPM_USBPCR); ++#endif ++ usb_cpm_writel(usb_phy, 0x0D080000, CPM_USBPCR1); ++ udelay(500); ++ ++ /* jitter filter */ ++ usb_cpm_writel(usb_phy, 0x00FF0080, CPM_USBVBFIL); ++ ++ /* reset detect time */ ++ usb_cpm_writel(usb_phy, 0x02000096, CPM_USBRDT); ++ ++ return 0; ++} ++ ++static int x1000_phy_set_wakeup(struct usb_phy_data *usb_phy, bool enabled) ++{ ++ if (enabled) ++ usb_cpm_clear_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ else ++ usb_cpm_set_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ ++ return 0; ++} ++ ++struct usb_phy_priv usb_phy_x1000_priv = { ++ .priv_data_init = x1000_priv_data_init, ++ ++ .phy_init = x1000_phy_init, ++ .phy_set_wakeup = x1000_phy_set_wakeup, ++}; +\ No newline at end of file +diff --git a/drivers/usb/phy/phy-ingenic-x1600.c b/drivers/usb/phy/phy-ingenic-x1600.c +new file mode 100644 +index 000000000..5b3017702 +--- /dev/null ++++ b/drivers/usb/phy/phy-ingenic-x1600.c +@@ -0,0 +1,139 @@ ++#include ++#include "phy-ingenic.h" ++ ++#define CPM_USBPCR (0x3C) ++#define CPM_USBRDT (0x40) ++#define CPM_USBVBFIL (0x44) ++#define CPM_USBPCR1 (0x48) ++ ++#define CPM_SRBC (0xC4) ++#define CPM_OPCR (0x24) ++ ++#define OPCR_SPENDN0_BIT 7 ++#define OPCR_GATE_USBPHY_CLK_BIT 23 ++#define SRBC_USB_SR 12 ++ ++#define USBRDT_RESUME_IRQ_ENABLE 31 ++#define USBRDT_RESUME_CLEAR_IRQ 30 ++#define USBRDT_RESUME_STATUS 27 ++ ++static int x1600_priv_data_init(struct usb_phy_data *usb_phy) ++{ ++ /* reset usb */ ++ usb_cpm_set_bit(usb_phy, SRBC_USB_SR, CPM_SRBC); ++ udelay(10); ++ usb_cpm_clear_bit(usb_phy, SRBC_USB_SR, CPM_SRBC); ++ ++ usb_cpm_set_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ ++ return 0; ++} ++ ++static int x1600_phy_init(struct usb_phy_data *usb_phy) ++{ ++ unsigned int value; ++ ++ /* vbus signal always valid, id pin always pullup */ ++ usb_cpm_writel(usb_phy, 0x00200000, CPM_USBPCR1); ++ usb_cpm_writel(usb_phy, 0x80400000, CPM_USBPCR); ++ udelay(500); ++ usb_cpm_writel(usb_phy, 0x80000000, CPM_USBPCR); ++ usb_cpm_writel(usb_phy, 0x70000000, CPM_USBPCR1); ++ udelay(500); ++ ++ /* always enable pre-emphasis */ ++ value = usb_phy_readl(usb_phy, 0x30); ++ // value &= ~(0x7 << 0); ++ value |= 0x7 << 0; ++ usb_phy_writel(usb_phy, value, 0x30); ++ ++ /* Tx HS pre_emphasize strength configure */ ++ value = usb_phy_readl(usb_phy, 0x40); ++ // value &= ~(0x7 << 3); ++ value |= 0x7 << 3; ++ usb_phy_writel(usb_phy, value, 0x40); ++ ++ /* Vbus 5V mode */ ++ value = usb_phy_readl(usb_phy, 0x10C); ++ value &= ~((0x7 << 0) | (0x7 << 3)); ++ value |= ((0x5 << 0) | (0x5 << 3)); ++ usb_phy_writel(usb_phy, value, 0x10C); ++ ++ /* Vbus 5V mode */ ++ value = usb_phy_readl(usb_phy, 0x110); ++ value &= ~((0x7 << 0) | (0x7 << 3)); ++ value |= ((0x5 << 0) | (0x5 << 3)); ++ usb_phy_writel(usb_phy, value, 0x110); ++ ++#ifdef CONFIG_USB_DWC2_EXT_VBUS_DETECT ++ /* VBUS voltage level detection power down. */ ++ value = usb_phy_readl(usb_phy, 0x108); ++ value |= 0x1 << 3; ++ usb_phy_writel(usb_phy, value, 0x108); ++#endif ++ ++ return 0; ++} ++ ++static int x1600_phy_set_wakeup(struct usb_phy_data *usb_phy, bool enabled) ++{ ++ unsigned long value; ++ ++ if (enabled) { ++#ifndef CONFIG_USB_DWC2_EXT_VBUS_DETECT ++ /* VBUS voltage level detection power down. */ ++ value = usb_phy_readl(usb_phy, 0x108); ++ value |= 1 << 3; ++ usb_phy_writel(usb_phy, value, 0x108); ++#endif ++ ++ /* disable full/low speed driver at the receiver */ ++ value = usb_phy_readl(usb_phy, 0x100); ++ value &= ~(1 << 6); ++ usb_phy_writel(usb_phy, value, 0x100); ++ ++ usb_cpm_clear_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ if (usb_phy->usb_wakeup) { ++ usb_cpm_clear_bit(usb_phy, USBRDT_RESUME_CLEAR_IRQ, CPM_USBRDT); ++ usb_cpm_set_bit(usb_phy, USBRDT_RESUME_IRQ_ENABLE, CPM_USBRDT); ++ } ++ } else { ++ if (usb_phy->usb_wakeup) ++ usb_cpm_clear_bit(usb_phy, USBRDT_RESUME_IRQ_ENABLE, CPM_USBRDT); ++ usb_cpm_set_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ ++ /* enable full/low speed driver at the receiver */ ++ value = usb_phy_readl(usb_phy, 0x100); ++ value |= 1 << 6; ++ usb_phy_writel(usb_phy, value, 0x100); ++ ++#ifndef CONFIG_USB_DWC2_EXT_VBUS_DETECT ++ /* VBUS voltage level detection power on. */ ++ value = usb_phy_readl(usb_phy, 0x108); ++ value &= ~(1 << 3); ++ usb_phy_writel(usb_phy, value, 0x108); ++#endif ++ } ++ ++ return 0; ++} ++ ++static int x1600_phy_get_wakeup(struct usb_phy_data *usb_phy) ++{ ++ if (usb_phy->usb_wakeup) { ++ if (usb_cpm_test_bit(usb_phy, USBRDT_RESUME_STATUS,CPM_USBRDT)) { ++ usb_cpm_set_bit(usb_phy, USBRDT_RESUME_CLEAR_IRQ, CPM_USBRDT); ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++struct usb_phy_priv usb_phy_x1600_priv = { ++ .priv_data_init = x1600_priv_data_init, ++ ++ .phy_init = x1600_phy_init, ++ .phy_set_wakeup = x1600_phy_set_wakeup, ++ .phy_get_wakeup = x1600_phy_get_wakeup, ++}; +diff --git a/drivers/usb/phy/phy-ingenic-x2000.c b/drivers/usb/phy/phy-ingenic-x2000.c +new file mode 100644 +index 000000000..08446648e +--- /dev/null ++++ b/drivers/usb/phy/phy-ingenic-x2000.c +@@ -0,0 +1,85 @@ ++#include ++#include "phy-ingenic.h" ++ ++#define CPM_USBPCR 0x3C ++#define CPM_USBRDT 0x40 ++#define CPM_USBVBFIL 0x44 ++#define CPM_USBPCR1 0x48 ++ ++#define CPM_SRBC 0xC4 ++#define CPM_OPCR 0x24 ++ ++#define OPCR_SPENDN0_BIT 7 ++#define OPCR_GATE_USBPHY_CLK_BIT 23 ++#define SRBC_USB_SR 12 ++ ++#define USBRDT_RESUME_IRQ_ENABLE 31 ++#define USBRDT_RESUME_CLEAR_IRQ 30 ++#define USBRDT_RESUME_STATUS 27 ++ ++static int x2000_priv_data_init(struct usb_phy_data *usb_phy) ++{ ++ usb_cpm_set_bit(usb_phy, SRBC_USB_SR, CPM_SRBC); ++ udelay(10); ++ usb_cpm_clear_bit(usb_phy, SRBC_USB_SR, CPM_SRBC); ++ ++ usb_cpm_set_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ return 0; ++} ++ ++static int x2000_phy_init(struct usb_phy_data *usb_phy) ++{ ++ unsigned int value; ++ ++ /* vbus signal always valid, id pin always pullup */ ++ usb_cpm_writel(usb_phy, 0x00200000, CPM_USBPCR1); ++ usb_cpm_writel(usb_phy, 0x80400000, CPM_USBPCR); ++ udelay(800); ++ usb_cpm_writel(usb_phy, 0x80000000, CPM_USBPCR); ++ usb_cpm_writel(usb_phy, 0x70000000, CPM_USBPCR1); ++ udelay(800); ++ ++ /* TX HS driver strength configure */ ++ value = usb_phy_readl(usb_phy, 0x40); ++ value |= 0x7 << 3; ++ usb_phy_writel(usb_phy, value, 0x40); ++ ++ return 0; ++} ++ ++static int x2000_phy_set_wakeup(struct usb_phy_data *usb_phy, bool enabled) ++{ ++ if (enabled) { ++ usb_cpm_clear_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ if (usb_phy->usb_wakeup) { ++ usb_cpm_clear_bit(usb_phy, USBRDT_RESUME_CLEAR_IRQ, CPM_USBRDT); ++ usb_cpm_set_bit(usb_phy, USBRDT_RESUME_IRQ_ENABLE, CPM_USBRDT); ++ } ++ } else { ++ if (usb_phy->usb_wakeup) ++ usb_cpm_clear_bit(usb_phy, USBRDT_RESUME_IRQ_ENABLE, CPM_USBRDT); ++ usb_cpm_set_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ } ++ ++ return 0; ++} ++ ++static int x2000_phy_get_wakeup(struct usb_phy_data *usb_phy) ++{ ++ if (usb_phy->usb_wakeup) { ++ if (usb_cpm_test_bit(usb_phy, USBRDT_RESUME_STATUS,CPM_USBRDT)) { ++ usb_cpm_set_bit(usb_phy, USBRDT_RESUME_CLEAR_IRQ, CPM_USBRDT); ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++struct usb_phy_priv usb_phy_x2000_priv = { ++ .priv_data_init = x2000_priv_data_init, ++ ++ .phy_init = x2000_phy_init, ++ .phy_set_wakeup = x2000_phy_set_wakeup, ++ .phy_get_wakeup = x2000_phy_get_wakeup, ++}; +\ No newline at end of file +diff --git a/drivers/usb/phy/phy-ingenic-x2500.c b/drivers/usb/phy/phy-ingenic-x2500.c +new file mode 100644 +index 000000000..636ce2060 +--- /dev/null ++++ b/drivers/usb/phy/phy-ingenic-x2500.c +@@ -0,0 +1,117 @@ ++#include ++#include "phy-ingenic.h" ++ ++#define CPM_USBPCR 0x3C ++#define CPM_USBRDT 0x40 ++#define CPM_USBVBFIL 0x44 ++#define CPM_USBPCR1 0x48 ++ ++#define CPM_SRBC (0xC4) ++#define CPM_OPCR (0x24) ++ ++#define OPCR_SPENDN0_BIT 7 ++#define OPCR_GATE_USBPHY_CLK_BIT 23 ++#define SRBC_USB_SR 12 ++ ++#define USBRDT_RESUME_IRQ_ENABLE 31 ++#define USBRDT_RESUME_CLEAR_IRQ 30 ++#define USBRDT_RESUME_STATUS 27 ++ ++static int x2500_priv_data_init(struct usb_phy_data *usb_phy) ++{ ++ /* reset usb */ ++ usb_cpm_clear_bit(usb_phy, 27, CPM_USBRDT); ++ usb_cpm_set_bit(usb_phy, SRBC_USB_SR, CPM_SRBC); ++ udelay(10); ++ usb_cpm_set_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ udelay(550); ++ usb_cpm_set_bit(usb_phy, 27, CPM_USBRDT); ++ udelay(10); ++ usb_cpm_clear_bit(usb_phy, SRBC_USB_SR, CPM_SRBC); ++ ++ ++ return 0; ++} ++ ++static int x2500_phy_init(struct usb_phy_data *usb_phy) ++{ ++ unsigned int value; ++ ++ /* vbus signal always valid, id pin always pullup */ ++ usb_cpm_writel(usb_phy, 0x00200000, CPM_USBPCR1); ++ usb_cpm_writel(usb_phy, 0x80400000, CPM_USBPCR); ++ udelay(800); ++ usb_cpm_writel(usb_phy, 0x80000000, CPM_USBPCR); ++ usb_cpm_writel(usb_phy, 0x70000000, CPM_USBPCR1); ++ udelay(800); ++ ++ /* TX HS driver strength configure */ ++ value = usb_phy_readl(usb_phy, 0x40); ++ value |= 0x7 << 3; ++ usb_phy_writel(usb_phy, value, 0x40); ++ ++ return 0; ++} ++ ++static int x2500_phy_set_wakeup(struct usb_phy_data *usb_phy, bool enabled) ++{ ++ unsigned long value; ++ ++ if (enabled) { ++#ifndef CONFIG_USB_DWC2_EXT_VBUS_DETECT ++ /* VBUS voltage level detection power down. */ ++ value = usb_phy_readl(usb_phy, 0x108); ++ value |= 1 << 3; ++ usb_phy_writel(usb_phy, value, 0x108); ++#endif ++ ++ /* disable full/low speed driver at the receiver */ ++ value = usb_phy_readl(usb_phy, 0x100); ++ value &= ~(1 << 6); ++ usb_phy_writel(usb_phy, value, 0x100); ++ ++ usb_cpm_clear_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ if (usb_phy->usb_wakeup) { ++ usb_cpm_clear_bit(usb_phy, USBRDT_RESUME_CLEAR_IRQ, CPM_USBRDT); ++ usb_cpm_set_bit(usb_phy, USBRDT_RESUME_IRQ_ENABLE, CPM_USBRDT); ++ } ++ } else { ++ if (usb_phy->usb_wakeup) ++ usb_cpm_clear_bit(usb_phy, USBRDT_RESUME_IRQ_ENABLE, CPM_USBRDT); ++ usb_cpm_set_bit(usb_phy, OPCR_SPENDN0_BIT, CPM_OPCR); ++ ++ /* enable full/low speed driver at the receiver */ ++ value = usb_phy_readl(usb_phy, 0x100); ++ value |= 1 << 6; ++ usb_phy_writel(usb_phy, value, 0x100); ++ ++#ifndef CONFIG_USB_DWC2_EXT_VBUS_DETECT ++ /* VBUS voltage level detection power on. */ ++ value = usb_phy_readl(usb_phy, 0x108); ++ value &= ~(1 << 3); ++ usb_phy_writel(usb_phy, value, 0x108); ++#endif ++ } ++ ++ return 0; ++} ++ ++static int x2500_phy_get_wakeup(struct usb_phy_data *usb_phy) ++{ ++ if (usb_phy->usb_wakeup) { ++ if (usb_cpm_test_bit(usb_phy, USBRDT_RESUME_STATUS,CPM_USBRDT)) { ++ usb_cpm_set_bit(usb_phy, USBRDT_RESUME_CLEAR_IRQ, CPM_USBRDT); ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++struct usb_phy_priv usb_phy_x2500_priv = { ++ .priv_data_init = x2500_priv_data_init, ++ ++ .phy_init = x2500_phy_init, ++ .phy_set_wakeup = x2500_phy_set_wakeup, ++ .phy_get_wakeup = x2500_phy_get_wakeup, ++}; +diff --git a/drivers/usb/phy/phy-ingenic.c b/drivers/usb/phy/phy-ingenic.c +new file mode 100644 +index 000000000..370fa853c +--- /dev/null ++++ b/drivers/usb/phy/phy-ingenic.c +@@ -0,0 +1,639 @@ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "phy-ingenic.h" ++ ++/* ++ * This driver relies on "both edges" triggering. VBUS has 100 msec to ++ * stabilize, so the peripheral controller driver may need to cope with ++ * some bouncing due to current surges (e.g. charging local capacitance) ++ * and contact chatter. ++ * ++ * REVISIT in desperate straits, toggling between rising and falling ++ * edges might be workable. ++ */ ++#define VBUS_IRQ_FLAGS \ ++ (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING) ++ ++#define ID_IRQ_FLAGS \ ++ (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING) ++ ++#define WAKEUP_IRQ_FLAGS \ ++ (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING) ++ ++#define FORCE_NONE 0 ++#define FORCE_DEVICE 1 ++#define FORCE_HOST 2 ++ ++static const struct of_device_id of_matchs[] = { ++ { .compatible = "ingenic,usbphy-x1000", .data = (void*)&usb_phy_x1000_priv}, ++ { .compatible = "ingenic,usbphy-x1600", .data = (void*)&usb_phy_x1600_priv}, ++ { .compatible = "ingenic,usbphy-x2000", .data = (void*)&usb_phy_x2000_priv}, ++ { .compatible = "ingenic,usbphy-m300", .data = (void*)&usb_phy_x2000_priv}, ++ { .compatible = "ingenic,usbphy-x2500", .data = (void*)&usb_phy_x2500_priv}, ++ { }, ++}; ++ ++static int common_phy_init(struct usb_phy *phy) ++{ ++ int ret = 0; ++ struct usb_phy_data *usb_phy = container_of(phy, struct usb_phy_data, phy); ++ ++ if (usb_phy->gate_clk) ++ clk_prepare_enable(usb_phy->gate_clk); ++ ++ usleep_range(5000, 5000); ++ ++ if (usb_phy->phy_priv->phy_init) ++ ret = usb_phy->phy_priv->phy_init(usb_phy); ++ ++ return ret; ++} ++ ++static void common_phy_shutdown(struct usb_phy *phy) ++{ ++ struct usb_phy_data *usb_phy = container_of(phy, struct usb_phy_data, phy); ++ ++ if (usb_phy->phy_priv->phy_shutdown) ++ usb_phy->phy_priv->phy_shutdown(usb_phy); ++ ++ if (usb_phy->gate_clk) ++ clk_disable_unprepare(usb_phy->gate_clk); ++} ++ ++static int common_phy_set_suspend(struct usb_phy *phy, int suspend) ++{ ++ int ret = 0; ++ struct usb_phy_data *usb_phy = container_of(phy, struct usb_phy_data, phy); ++ ++ if (usb_phy->phy_priv->phy_set_suspend) ++ ret = usb_phy->phy_priv->phy_set_suspend(usb_phy, suspend); ++ ++ return ret; ++} ++ ++static int common_phy_set_wakeup(struct usb_phy *phy, bool enabled) ++{ ++ struct usb_phy_data *usb_phy = container_of(phy, struct usb_phy_data, phy); ++ ++ if (enabled){ ++ if (usb_phy->phy_priv->phy_set_wakeup) ++ usb_phy->phy_priv->phy_set_wakeup(usb_phy, 1); ++ ++ /* change usb switch to gpio */ ++ if (usb_phy->switch_gpiod) ++ gpiod_set_value(usb_phy->switch_gpiod, 1); ++ ++ /* enable usb wakeup irq */ ++ if (usb_phy->wakeup_gpiod) { ++#ifdef TEST_USB_WAKEUP_FLAG ++ usb_phy->wakeup_flag = 0; ++#endif ++ enable_irq(usb_phy->wakeup_irq); ++ enable_irq_wake(usb_phy->wakeup_irq); ++ } ++ } else { ++ /* disable usb wakeup irq */ ++ if (usb_phy->wakeup_gpiod) { ++ disable_irq_wake(usb_phy->wakeup_irq); ++ disable_irq(usb_phy->wakeup_irq); ++ } ++ ++ /* change usb switch to phy */ ++ if (usb_phy->switch_gpiod) ++ gpiod_set_value(usb_phy->switch_gpiod, 0); ++ ++ if (usb_phy->phy_priv->phy_set_wakeup) ++ usb_phy->phy_priv->phy_set_wakeup(usb_phy, 0); ++ } ++ ++ return 0; ++} ++ ++static int common_phy_get_wakeup(struct usb_phy *phy) ++{ ++ struct usb_phy_data *usb_phy = container_of(phy, struct usb_phy_data, phy); ++ int ret = 0; ++ ++ if (usb_phy->phy_priv->phy_get_wakeup) ++ ret = usb_phy->phy_priv->phy_get_wakeup(usb_phy); ++ ++#ifdef TEST_USB_WAKEUP_FLAG ++ if (usb_phy->wakeup_flag) { ++ usb_phy->wakeup_flag = 0; ++ ret = 1; ++ } ++#endif ++ ++ return ret; ++} ++ ++static irqreturn_t usb_wakeup_irq_handler(int irq, void *data) ++{ ++#ifdef TEST_USB_WAKEUP_FLAG ++ struct usb_phy_data *usb_phy = (struct usb_phy_data *)data; ++ usb_phy->wakeup_flag = 1; ++#endif ++ ++ return IRQ_HANDLED; ++} ++ ++static int is_vbus_powered(struct usb_phy_data *usb_phy) ++{ ++ return gpiod_get_value(usb_phy->vbus_gpiod); ++} ++ ++static int is_id_host(struct usb_phy_data *usb_phy) ++{ ++ return gpiod_get_value(usb_phy->id_gpiod); ++} ++ ++static void gpio_vbus_work(struct work_struct *work) ++{ ++ struct usb_phy_data *usb_phy = ++ container_of(work, struct usb_phy_data, vbus_work.work); ++ int status, vbus; ++ ++ if (!usb_phy->phy.otg->gadget) ++ return; ++ ++ vbus = is_vbus_powered(usb_phy); ++ if ((vbus ^ usb_phy->vbus) == 0) ++ return; ++ usb_phy->vbus = vbus; ++ ++ /* Peripheral controllers which manage the pullup themselves won't have ++ * a pullup GPIO configured here. If it's configured here, we'll do ++ * what isp1301_omap::b_peripheral() does and enable the pullup here... ++ * although that may complicate usb_gadget_{,dis}connect() support. ++ */ ++ ++ if (vbus) { ++ status = USB_EVENT_VBUS; ++ usb_phy->phy.otg->state = OTG_STATE_B_PERIPHERAL; ++ usb_phy->phy.last_event = status; ++ usb_gadget_vbus_connect(usb_phy->phy.otg->gadget); ++ ++ atomic_notifier_call_chain(&usb_phy->phy.notifier, ++ status, usb_phy->phy.otg->gadget); ++ usb_phy_set_event(&usb_phy->phy, USB_EVENT_ENUMERATED); ++ } else { ++ usb_gadget_vbus_disconnect(usb_phy->phy.otg->gadget); ++ status = USB_EVENT_NONE; ++ usb_phy->phy.otg->state = OTG_STATE_B_IDLE; ++ usb_phy->phy.last_event = status; ++ ++ atomic_notifier_call_chain(&usb_phy->phy.notifier, ++ status, usb_phy->phy.otg->gadget); ++ usb_phy_set_event(&usb_phy->phy, USB_EVENT_NONE); ++ } ++} ++ ++/* VBUS change IRQ handler */ ++static irqreturn_t gpio_vbus_irq(int irq, void *data) ++{ ++ struct platform_device *pdev = data; ++ struct usb_phy_data *usb_phy = platform_get_drvdata(pdev); ++ struct usb_otg *otg = usb_phy->phy.otg; ++ ++ dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n", ++ is_vbus_powered(usb_phy) ? "supplied" : "inactive", ++ otg->gadget ? otg->gadget->name : "none"); ++ ++ if (otg->gadget) ++ schedule_delayed_work(&usb_phy->vbus_work, msecs_to_jiffies(100)); ++ ++ return IRQ_HANDLED; ++} ++ ++static void gpio_id_work(struct work_struct *work) ++{ ++ struct usb_phy_data *usb_phy = ++ container_of(work, struct usb_phy_data, id_work.work); ++ const struct software_node *swnode; ++ struct fwnode_handle *fwnode; ++ struct usb_role_switch *role_sw; ++ int id; ++ ++ id = is_id_host(usb_phy); ++ if ((id ^ usb_phy->id) == 0) ++ return; ++ usb_phy->id = id; ++ ++ swnode = software_node_find_by_name(NULL, "ingenic-usb-sw"); ++ if (!swnode) ++ return; ++ ++ fwnode = software_node_fwnode(swnode); ++ role_sw = usb_role_switch_find_by_fwnode(fwnode); ++ fwnode_handle_put(fwnode); ++ ++ if (role_sw) { ++ usb_role_switch_set_role(role_sw, id ? USB_ROLE_HOST : USB_ROLE_DEVICE); ++ usb_role_switch_put(role_sw); ++ } ++ ++} ++ ++/* ID change IRQ handler */ ++static irqreturn_t gpio_id_irq(int irq, void *data) ++{ ++ struct platform_device *pdev = data; ++ struct usb_phy_data *usb_phy = platform_get_drvdata(pdev); ++ ++ dev_dbg(&pdev->dev, "ID %s\n", is_id_host(usb_phy) ? "host" : "device"); ++ ++ schedule_delayed_work(&usb_phy->id_work, msecs_to_jiffies(100)); ++ ++ return IRQ_HANDLED; ++} ++ ++static int usb_phy_set_vbus(struct usb_phy *phy, int on) ++{ ++ struct usb_phy_data *usb_phy = container_of(phy, struct usb_phy_data, phy); ++ ++ dev_dbg(usb_phy->dev, "OTG VBUS %s\n", on ? "ON" : "OFF"); ++ ++ if (usb_phy->drvvbus_gpiod) ++ gpiod_set_value(usb_phy->drvvbus_gpiod, on); ++ return 0; ++} ++ ++/* bind/unbind the peripheral controller */ ++static int usb_phy_set_peripheral(struct usb_otg *otg, ++ struct usb_gadget *gadget) ++{ ++ struct usb_phy_data *usb_phy; ++ struct platform_device *pdev; ++ ++ usb_phy = container_of(otg->usb_phy, struct usb_phy_data, phy); ++ pdev = to_platform_device(usb_phy->dev); ++ ++ if (!gadget) { ++ dev_dbg(&pdev->dev, "unregistering gadget '%s'\n", ++ otg->gadget->name); ++ ++ usb_gadget_vbus_disconnect(otg->gadget); ++ otg->state = OTG_STATE_UNDEFINED; ++ ++ otg->gadget = NULL; ++ return 0; ++ } ++ ++ otg->gadget = gadget; ++ dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name); ++ ++ /* initialize connection state */ ++ usb_phy->vbus = 0; /* start with disconnected */ ++ if (usb_phy->vbus_gpiod) ++ gpio_vbus_irq(usb_phy->vbus_irq, pdev); ++ return 0; ++} ++ ++static ssize_t sw_switch_hsotg_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct usb_phy_data *usb_phy = (struct usb_phy_data *)dev->driver_data; ++ struct usb_otg *otg = usb_phy->phy.otg; ++ unsigned int usbrdt; ++ ++ if (!sscanf(buf, "%s", usb_phy->hsotg_sw_switch)){ ++ printk("input %s not invailed\n", usb_phy->hsotg_sw_switch); ++ return count; ++ } ++ ++ if (!strcmp(usb_phy->hsotg_sw_switch, "device")) { ++ if(usb_phy->sw_switch_mode == FORCE_DEVICE){ ++ printk("OTG aleady in Device Mode\n"); ++ return count; ++ } ++ printk("---Forced switching Device mode!\n"); ++ ++ usb_phy->sw_switch_mode = FORCE_DEVICE; ++ ++ if (usb_phy->drvvbus_gpiod){ ++ gpiod_set_value(usb_phy->drvvbus_gpiod,0); ++ } ++ ++ usbrdt = cpm_inl(CPM_USBRDT); ++ usbrdt |= USBRDT_IDDIG_EN; ++ usbrdt |= USBRDT_IDDIG_REG; ++ /*ID level is high*/ ++ cpm_outl(usbrdt, CPM_USBRDT); ++ ++ } else if (!strcmp(usb_phy->hsotg_sw_switch, "host")){ ++ if(usb_phy->sw_switch_mode == FORCE_HOST){ ++ printk("OTG aleady in Host Mode\n"); ++ return count; ++ } ++ printk("---Forced switching Host mode!\n"); ++ ++ usb_phy->sw_switch_mode = FORCE_HOST; ++ ++ usbrdt = cpm_inl(CPM_USBRDT); ++ usbrdt |= USBRDT_IDDIG_EN; ++ usbrdt &= ~USBRDT_IDDIG_REG; ++ /*ID level is low*/ ++ cpm_outl(usbrdt, CPM_USBRDT); ++ ++ if(usb_phy->drvvbus_gpiod){ ++ gpiod_set_value(usb_phy->drvvbus_gpiod,1); ++ } ++ ++ } else if (!strcmp(usb_phy->hsotg_sw_switch, "none")){ ++ printk("---switching mode from pin!\n"); ++ ++ usb_phy->sw_switch_mode = FORCE_NONE; ++ ++ usbrdt = cpm_inl(CPM_USBRDT); ++ usbrdt &= ~(USBRDT_IDDIG_EN | USBRDT_IDDIG_REG); ++ cpm_outl(usbrdt, CPM_USBRDT); ++ ++ if (otg->gadget) ++ schedule_delayed_work(&usb_phy->vbus_work, msecs_to_jiffies(100)); ++ ++ } ++ ++ memset(usb_phy->hsotg_sw_switch, 0 , sizeof(usb_phy->hsotg_sw_switch)); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(sw_switch_hsotg, S_IWUSR, NULL, sw_switch_hsotg_store); ++ ++static struct device_attribute *usb_phy_attributes[] = { ++ &dev_attr_sw_switch_hsotg, ++ NULL ++}; ++ ++static int device_create_node(struct device * dev, struct device_attribute **attrs) ++{ ++ struct device_attribute *attr; ++ while ((attr = *attrs++)) { ++ int err; ++ err = device_create_file(dev, attr); ++ if (err) { ++ printk("%s() device_create_file() failed.\n", __func__); ++ return err; ++ } ++ } ++ return 0; ++} ++static int device_remove_node(struct device * dev, struct device_attribute **attrs) ++{ ++ struct device_attribute *attr; ++ while ((attr = *attrs++)) { ++ device_remove_file(dev, attr); ++ } ++ return 0; ++} ++ ++/* platform driver interface */ ++static int ingenic_usb_phy_probe(struct platform_device *pdev) ++{ ++ struct usb_phy_data *usb_phy; ++ const struct of_device_id *match; ++ struct device *dev = &pdev->dev; ++ int err; ++ ++ usb_phy = devm_kzalloc(dev, sizeof(struct usb_phy_data), ++ GFP_KERNEL); ++ if (!usb_phy) ++ return -ENOMEM; ++ ++ usb_phy->phy.otg = devm_kzalloc(dev, sizeof(struct usb_otg), ++ GFP_KERNEL); ++ if (!usb_phy->phy.otg) ++ return -ENOMEM; ++ ++ usb_phy->cpm_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(usb_phy->cpm_base)) ++ return PTR_ERR(usb_phy->cpm_base); ++ ++ usb_phy->phy_base = devm_platform_ioremap_resource(pdev, 1); ++ if (IS_ERR(usb_phy->phy_base)) ++ dev_warn(dev, "dont have usb phy base addr !\n"); ++ ++ match = of_match_node(of_matchs, dev->of_node); ++ if (!match) ++ return -ENODEV; ++ usb_phy->phy_priv = (struct usb_phy_priv*)match->data; ++ ++ platform_set_drvdata(pdev, usb_phy); ++ usb_phy->dev = dev; ++ usb_phy->phy.label = "ingenic_usb_phy"; ++ usb_phy->phy.dev = dev; ++ usb_phy->phy.set_vbus = usb_phy_set_vbus; ++ ++ usb_phy->phy.init = common_phy_init; ++ usb_phy->phy.shutdown = common_phy_shutdown; ++ usb_phy->phy.set_suspend = common_phy_set_suspend; ++ usb_phy->phy.set_wakeup = common_phy_set_wakeup; ++ usb_phy->phy.get_wakeup = common_phy_get_wakeup; ++ ++ usb_phy->phy.otg->state = OTG_STATE_UNDEFINED; ++ usb_phy->phy.otg->usb_phy = &usb_phy->phy; ++ usb_phy->phy.otg->set_peripheral = usb_phy_set_peripheral; ++ ++ usb_phy->gate_clk = devm_clk_get(&pdev->dev, "gate_usbphy"); ++ if (IS_ERR(usb_phy->gate_clk)){ ++ usb_phy->gate_clk = NULL; ++ dev_err(dev, "cannot get usbphy clock !\n"); ++ return -ENODEV; ++ } ++ ++ usb_phy->drvvbus_gpiod = devm_gpiod_get_optional(dev, "ingenic,drvvbus", GPIOD_OUT_LOW); ++ if (IS_ERR(usb_phy->drvvbus_gpiod)) { ++ err = PTR_ERR(usb_phy->drvvbus_gpiod); ++ dev_err(dev, "can't request vbus draw gpio, err: %d\n", err); ++ return err; ++ } ++ if (usb_phy->drvvbus_gpiod) ++ gpiod_set_consumer_name(usb_phy->drvvbus_gpiod, "drvvbus"); ++ ++ usb_phy->vbus_gpiod = devm_gpiod_get_optional(dev, "ingenic,vbus-dete", GPIOD_IN); ++ if (IS_ERR(usb_phy->vbus_gpiod)) { ++ err = PTR_ERR(usb_phy->vbus_gpiod); ++ dev_err(dev, "can't request vbus gpio, err: %d\n", err); ++ return err; ++ } ++ ++ if (usb_phy->vbus_gpiod) { ++ gpiod_set_consumer_name(usb_phy->vbus_gpiod, "vbus_detect"); ++ INIT_DELAYED_WORK(&usb_phy->vbus_work, gpio_vbus_work); ++ usb_phy->vbus_irq = gpiod_to_irq(usb_phy->vbus_gpiod); ++ ++ err = devm_request_irq(dev, usb_phy->vbus_irq, gpio_vbus_irq, VBUS_IRQ_FLAGS, ++ "vbus_detect", pdev); ++ if (err) { ++ dev_err(dev, "can't request vbus irq %i, err: %d\n", ++ usb_phy->vbus_irq, err); ++ return err; ++ } ++ } ++ ++ usb_phy->id_gpiod = devm_gpiod_get_optional(dev, "ingenic,id-dete", GPIOD_IN); ++ if (IS_ERR(usb_phy->id_gpiod)) { ++ err = PTR_ERR(usb_phy->id_gpiod); ++ dev_err(dev, "can't request id gpio, err: %d\n", err); ++ return err; ++ } ++ ++ if (usb_phy->id_gpiod) { ++ gpiod_set_consumer_name(usb_phy->id_gpiod, "id_detect"); ++ INIT_DELAYED_WORK(&usb_phy->id_work, gpio_id_work); ++ usb_phy->id_irq = gpiod_to_irq(usb_phy->id_gpiod); ++ ++ err = devm_request_irq(dev, usb_phy->id_irq, gpio_id_irq, ID_IRQ_FLAGS, ++ "id_detect", pdev); ++ if (err) { ++ dev_err(dev, "can't request id irq %i, err: %d\n", ++ usb_phy->id_irq, err); ++ return err; ++ } ++ } ++ ++ device_init_wakeup(dev, true); ++ ++ if (of_find_property(dev->of_node, "enable-vbus-wakeup", NULL)) ++ usb_phy->vbus_wakeup = true; ++ ++ if (of_find_property(dev->of_node, "enable-id-wakeup", NULL)) ++ usb_phy->id_wakeup = true; ++ ++ if (of_find_property(dev->of_node, "enable-usb-wakeup", NULL)) ++ usb_phy->usb_wakeup = true; ++ ++ if (usb_phy->usb_wakeup) { ++ usb_phy->switch_gpiod = devm_gpiod_get_optional(dev, "ingenic,usb-switch", GPIOD_OUT_LOW); ++ if (IS_ERR(usb_phy->switch_gpiod)) { ++ err = PTR_ERR(usb_phy->switch_gpiod); ++ dev_err(dev, "can't request usb switch gpio, err: %d\n", err); ++ return err; ++ } ++ if (usb_phy->switch_gpiod) ++ gpiod_set_consumer_name(usb_phy->switch_gpiod, "usb_switch"); ++ ++ usb_phy->wakeup_gpiod = devm_gpiod_get_optional(dev, "ingenic,usb-wakeup", GPIOD_IN); ++ if (IS_ERR(usb_phy->wakeup_gpiod)) { ++ err = PTR_ERR(usb_phy->wakeup_gpiod); ++ dev_err(dev, "can't request usb wakeup gpio, err: %d\n", err); ++ return err; ++ } ++ ++ if (usb_phy->wakeup_gpiod) { ++ gpiod_set_consumer_name(usb_phy->wakeup_gpiod, "usb_wakeup"); ++ usb_phy->wakeup_irq = gpiod_to_irq(usb_phy->wakeup_gpiod); ++ err = devm_request_irq(dev, usb_phy->wakeup_irq, usb_wakeup_irq_handler, ++ WAKEUP_IRQ_FLAGS, "usb_wakeup", usb_phy); ++ if (err) { ++ dev_err(dev, "can't request usb wakeup irq, err: %d\n", err); ++ return err; ++ } ++ ++ disable_irq(usb_phy->wakeup_irq); ++ } ++ } ++ ++ err = usb_phy->phy_priv->priv_data_init(usb_phy); ++ if (err) { ++ dev_err(dev, "priv_data_init fail, err: %d\n", err); ++ return err; ++ } ++ ++ /* only active when a gadget is registered */ ++ err = usb_add_phy(&usb_phy->phy, USB_PHY_TYPE_USB2); ++ if (err) { ++ dev_err(dev, "can't register transceiver, err: %d\n", err); ++ return err; ++ } ++ ++ device_create_node(&pdev->dev, usb_phy_attributes); ++ ++ return 0; ++} ++ ++static int ingenic_usb_phy_remove(struct platform_device *pdev) ++{ ++ struct usb_phy_data *usb_phy = platform_get_drvdata(pdev); ++ ++ device_init_wakeup(&pdev->dev, 0); ++ ++ if (usb_phy->vbus_gpiod) ++ cancel_delayed_work_sync(&usb_phy->vbus_work); ++ ++ if (usb_phy->id_gpiod) ++ cancel_delayed_work_sync(&usb_phy->id_work); ++ ++ usb_phy->phy_priv->priv_data_exit(usb_phy); ++ ++ usb_remove_phy(&usb_phy->phy); ++ ++ device_remove_node(usb_phy->dev, usb_phy_attributes); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ingenic_usb_phy_pm_suspend(struct device *dev) ++{ ++ struct usb_phy_data *usb_phy = dev_get_drvdata(dev); ++ ++ if (usb_phy->vbus_wakeup && usb_phy->vbus_gpiod) ++ enable_irq_wake(usb_phy->vbus_irq); ++ ++ if (usb_phy->id_wakeup && usb_phy->id_gpiod) ++ enable_irq_wake(usb_phy->id_irq); ++ ++ return 0; ++} ++ ++static int ingenic_usb_phy_pm_resume(struct device *dev) ++{ ++ struct usb_phy_data *usb_phy = dev_get_drvdata(dev); ++ ++ if (usb_phy->vbus_gpiod) { ++ if (usb_phy->vbus_wakeup) ++ disable_irq_wake(usb_phy->vbus_irq); ++ if (usb_phy->phy.otg->gadget) ++ schedule_delayed_work(&usb_phy->vbus_work, msecs_to_jiffies(100)); ++ } ++ ++ if (usb_phy->id_gpiod) { ++ if (usb_phy->id_wakeup) ++ disable_irq_wake(usb_phy->id_irq); ++ ++ schedule_delayed_work(&usb_phy->id_work, msecs_to_jiffies(100)); ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops ingenic_usb_phy_pm_ops = { ++ .suspend = ingenic_usb_phy_pm_suspend, ++ .resume = ingenic_usb_phy_pm_resume, ++}; ++#endif ++ ++static struct platform_driver ingenic_usb_phy_driver = { ++ .driver = { ++ .name = "ingenic_usb_phy", ++ .of_match_table = of_matchs, ++#ifdef CONFIG_PM ++ ++ .pm = &ingenic_usb_phy_pm_ops, ++#endif ++ }, ++ .probe = ingenic_usb_phy_probe, ++ .remove = ingenic_usb_phy_remove, ++}; ++ ++module_platform_driver(ingenic_usb_phy_driver); +diff --git a/drivers/usb/phy/phy-ingenic.h b/drivers/usb/phy/phy-ingenic.h +new file mode 100644 +index 000000000..c49337fc2 +--- /dev/null ++++ b/drivers/usb/phy/phy-ingenic.h +@@ -0,0 +1,111 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _PHY_INGENIC_H_ ++#define _PHY_INGENIC_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* If gpio wake-up mode, OTG cannot detect wake-up interrupt, enable this macro definition */ ++//#define TEST_USB_WAKEUP_FLAG ++ ++ ++struct usb_phy_priv; ++ ++struct usb_phy_data { ++ void __iomem *cpm_base; ++ void __iomem *phy_base; ++ char hsotg_sw_switch[8]; ++ unsigned char sw_switch_mode; ++ struct clk *gate_clk; ++ struct gpio_desc *vbus_gpiod; ++ struct gpio_desc *id_gpiod; ++ struct gpio_desc *drvvbus_gpiod; ++ struct usb_phy phy; ++ struct device *dev; ++ struct delayed_work vbus_work; ++ struct delayed_work id_work; ++ int vbus; ++ int vbus_irq; ++ int id; ++ int id_irq; ++ bool usb_wakeup; ++ bool vbus_wakeup; ++ bool id_wakeup; ++ ++#ifdef TEST_USB_WAKEUP_FLAG ++ unsigned int wakeup_flag; ++#endif ++ struct gpio_desc *switch_gpiod; ++ struct gpio_desc *wakeup_gpiod; ++ int wakeup_irq; ++ ++ struct usb_phy_priv *phy_priv; ++ void *priv_data; ++}; ++ ++struct usb_phy_priv { ++ int (*priv_data_init)(struct usb_phy_data *usb_phy); ++ void (*priv_data_exit)(struct usb_phy_data *usb_phy); ++ ++ int (*phy_init)(struct usb_phy_data *usb_phy); ++ void (*phy_shutdown)(struct usb_phy_data *usb_phy); ++ ++ int (*phy_set_suspend)(struct usb_phy_data *usb_phy, int suspend); ++ ++ int (*phy_set_wakeup)(struct usb_phy_data *usb_phy, bool enabled); ++ int (*phy_get_wakeup)(struct usb_phy_data *usb_phy); ++}; ++ ++ ++static inline unsigned int usb_cpm_readl(struct usb_phy_data *usb_phy, unsigned int reg_offset) ++{ ++ return readl(usb_phy->cpm_base + reg_offset); ++} ++ ++static inline void usb_cpm_writel(struct usb_phy_data *usb_phy, unsigned int reg_data, unsigned int reg_offset) ++{ ++ writel(reg_data, (usb_phy->cpm_base + reg_offset)); ++} ++ ++#define usb_cpm_clear_bit(_data,_val,_off) \ ++ do{usb_cpm_writel(_data, (usb_cpm_readl(_data, _off) & ~(1 << (_val))),(_off));}while(0) ++#define usb_cpm_set_bit(_data,_val,_off) \ ++ do{usb_cpm_writel(_data, (usb_cpm_readl(_data, _off) | (1 << (_val))),(_off));}while(0) ++#define usb_cpm_test_bit(_data,_val,_off) \ ++ (usb_cpm_readl(_data, _off) & (0x1 << (_val))) ++ ++ ++static inline unsigned int usb_phy_readl(struct usb_phy_data *usb_phy, unsigned int reg_offset) ++{ ++ unsigned int data = 0; ++ ++ if (!IS_ERR_OR_NULL(usb_phy->phy_base)) ++ data = readl(usb_phy->phy_base + reg_offset); ++ ++ return data; ++} ++ ++static inline void usb_phy_writel(struct usb_phy_data *usb_phy, unsigned int reg_data, unsigned int reg_offset) ++{ ++ if (!IS_ERR_OR_NULL(usb_phy->phy_base)) ++ writel(reg_data, (usb_phy->phy_base + reg_offset)); ++} ++ ++#define usb_phy_clear_bit(_data,_val,_off) \ ++ do{usb_phy_writel(_data, (usb_phy_readl(_data, _off) & ~(1 << (_val))),(_off));}while(0) ++#define usb_phy_set_bit(_data,_val,_off) \ ++ do{usb_phy_writel(_data, (usb_phy_readl(_data, _off) | (1 << (_val))),(_off));}while(0) ++#define usb_phy_test_bit(_data,_val,_off) \ ++ (usb_phy_readl(_data, _off) & (0x1 << (_val))) ++ ++ ++extern struct usb_phy_priv usb_phy_x1000_priv; ++extern struct usb_phy_priv usb_phy_x1600_priv; ++extern struct usb_phy_priv usb_phy_x2000_priv; ++extern struct usb_phy_priv usb_phy_x2500_priv; ++ ++#endif /* _PHY_INGENIC_H_ */ +diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c +index a3e043e3e..baebb1f5a 100644 +--- a/drivers/usb/phy/phy-tahvo.c ++++ b/drivers/usb/phy/phy-tahvo.c +@@ -393,9 +393,7 @@ static int tahvo_usb_probe(struct platform_device *pdev) + + dev_set_drvdata(&pdev->dev, tu); + +- tu->irq = ret = platform_get_irq(pdev, 0); +- if (ret < 0) +- return ret; ++ tu->irq = platform_get_irq(pdev, 0); + ret = request_threaded_irq(tu->irq, NULL, tahvo_usb_vbus_interrupt, + IRQF_ONESHOT, + "tahvo-vbus", tu); +diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c +index ab3c38a7d..8ba6c5a91 100644 +--- a/drivers/usb/phy/phy-twl6030-usb.c ++++ b/drivers/usb/phy/phy-twl6030-usb.c +@@ -348,11 +348,6 @@ static int twl6030_usb_probe(struct platform_device *pdev) + twl->irq2 = platform_get_irq(pdev, 1); + twl->linkstat = MUSB_UNKNOWN; + +- if (twl->irq1 < 0) +- return twl->irq1; +- if (twl->irq2 < 0) +- return twl->irq2; +- + twl->comparator.set_vbus = twl6030_set_vbus; + twl->comparator.start_srp = twl6030_start_srp; + +diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c +index b47285f02..1b24492bb 100644 +--- a/drivers/usb/phy/phy.c ++++ b/drivers/usb/phy/phy.c +@@ -42,6 +42,12 @@ static const char *const usb_chger_type[] = { + [ACA_TYPE] = "USB_CHARGER_ACA_TYPE", + }; + ++static const char *const usb_chger_state[] = { ++ [USB_CHARGER_DEFAULT] = "USB_CHARGER_DEFAULT", ++ [USB_CHARGER_PRESENT] = "USB_CHARGER_PRESENT", ++ [USB_CHARGER_ABSENT] = "USB_CHARGER_ABSENT", ++}; ++ + static struct usb_phy *__usb_find_phy(struct list_head *list, + enum usb_phy_type type) + { +@@ -74,6 +80,18 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node) + return ERR_PTR(-EPROBE_DEFER); + } + ++static struct usb_phy *__device_to_usb_phy(struct device *dev) ++{ ++ struct usb_phy *usb_phy; ++ ++ list_for_each_entry(usb_phy, &phy_list, head) { ++ if (usb_phy->dev == dev) ++ return usb_phy; ++ } ++ ++ return NULL; ++} ++ + static void usb_phy_set_default_current(struct usb_phy *usb_phy) + { + usb_phy->chg_cur.sdp_min = DEFAULT_SDP_CUR_MIN; +@@ -105,9 +123,6 @@ static void usb_phy_set_default_current(struct usb_phy *usb_phy) + static void usb_phy_notify_charger_work(struct work_struct *work) + { + struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work); +- char uchger_state[50] = { 0 }; +- char uchger_type[50] = { 0 }; +- char *envp[] = { uchger_state, uchger_type, NULL }; + unsigned int min, max; + + switch (usb_phy->chg_state) { +@@ -115,15 +130,11 @@ static void usb_phy_notify_charger_work(struct work_struct *work) + usb_phy_get_charger_current(usb_phy, &min, &max); + + atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy); +- snprintf(uchger_state, ARRAY_SIZE(uchger_state), +- "USB_CHARGER_STATE=%s", "USB_CHARGER_PRESENT"); + break; + case USB_CHARGER_ABSENT: + usb_phy_set_default_current(usb_phy); + + atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy); +- snprintf(uchger_state, ARRAY_SIZE(uchger_state), +- "USB_CHARGER_STATE=%s", "USB_CHARGER_ABSENT"); + break; + default: + dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n", +@@ -131,9 +142,36 @@ static void usb_phy_notify_charger_work(struct work_struct *work) + return; + } + ++ kobject_uevent(&usb_phy->dev->kobj, KOBJ_CHANGE); ++} ++ ++static int usb_phy_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++ struct usb_phy *usb_phy; ++ char uchger_state[50] = { 0 }; ++ char uchger_type[50] = { 0 }; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&phy_lock, flags); ++ usb_phy = __device_to_usb_phy(dev); ++ spin_unlock_irqrestore(&phy_lock, flags); ++ ++ if (!usb_phy) ++ return -ENODEV; ++ ++ snprintf(uchger_state, ARRAY_SIZE(uchger_state), ++ "USB_CHARGER_STATE=%s", usb_chger_state[usb_phy->chg_state]); ++ + snprintf(uchger_type, ARRAY_SIZE(uchger_type), + "USB_CHARGER_TYPE=%s", usb_chger_type[usb_phy->chg_type]); +- kobject_uevent_env(&usb_phy->dev->kobj, KOBJ_CHANGE, envp); ++ ++ if (add_uevent_var(env, uchger_state)) ++ return -ENOMEM; ++ ++ if (add_uevent_var(env, uchger_type)) ++ return -ENOMEM; ++ ++ return 0; + } + + static void __usb_phy_get_charger_type(struct usb_phy *usb_phy) +@@ -661,6 +699,11 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type) + } + EXPORT_SYMBOL_GPL(usb_add_phy); + ++static struct device_type usb_phy_dev_type = { ++ .name = "usb_phy", ++ .uevent = usb_phy_uevent, ++}; ++ + /** + * usb_add_phy_dev - declare the USB PHY + * @x: the USB phy to be used; or NULL +@@ -684,6 +727,8 @@ int usb_add_phy_dev(struct usb_phy *x) + if (ret) + return ret; + ++ x->dev->type = &usb_phy_dev_type; ++ + ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); + + spin_lock_irqsave(&phy_lock, flags); +diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c +index 33b637d0d..dfaed7eee 100644 +--- a/drivers/usb/roles/class.c ++++ b/drivers/usb/roles/class.c +@@ -214,6 +214,15 @@ static const char * const usb_roles[] = { + [USB_ROLE_DEVICE] = "device", + }; + ++const char *usb_role_string(enum usb_role role) ++{ ++ if (role < 0 || role >= ARRAY_SIZE(usb_roles)) ++ return "unknown"; ++ ++ return usb_roles[role]; ++} ++EXPORT_SYMBOL_GPL(usb_role_string); ++ + static ssize_t + role_show(struct device *dev, struct device_attribute *attr, char *buf) + { +diff --git a/include/dt-bindings/clock/ingenic-m300.h b/include/dt-bindings/clock/ingenic-m300.h +new file mode 100644 +index 000000000..edee16efb +--- /dev/null ++++ b/include/dt-bindings/clock/ingenic-m300.h +@@ -0,0 +1,201 @@ ++#ifndef _DT_BINDINGS_CLOCK_M300_H ++#define _DT_BINDINGS_CLOCK_M300_H ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_EXT_DIV_512 (CLK_ID_FIEXED + 2) ++#define CLK_NR_FIXED (3) ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_PLL_EPLL (CLK_ID_PLL + 2) ++#define CLK_NR_PLL (3) ++ ++/* MUX clk */ ++#define CLK_ID_MUX (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_MUX + 0) ++#define CLK_MUX_CPU_L2C (CLK_ID_MUX + 1) ++#define CLK_MUX_AHB0 (CLK_ID_MUX + 2) ++#define CLK_MUX_AHB2 (CLK_ID_MUX + 3) ++#define CLK_MUX_DDR (CLK_ID_MUX + 4) ++#define CLK_MUX_MACPHY (CLK_ID_MUX + 5) ++#define CLK_MUX_MACTXPHY (CLK_ID_MUX + 6) ++#define CLK_MUX_MACTXPHY1 (CLK_ID_MUX + 7) ++#define CLK_MUX_I2S0 (CLK_ID_MUX + 8) ++#define CLK_MUX_I2S1 (CLK_ID_MUX + 9) ++#define CLK_MUX_I2S2 (CLK_ID_MUX + 10) ++#define CLK_MUX_I2S3 (CLK_ID_MUX + 11) ++#define CLK_MUX_AUDIO_RAM (CLK_ID_MUX + 12) ++#define CLK_MUX_SPDIF (CLK_ID_MUX + 13) ++#define CLK_MUX_PCM (CLK_ID_MUX + 14) ++#define CLK_MUX_DMIC (CLK_ID_MUX + 15) ++#define CLK_MUX_LCD (CLK_ID_MUX + 16) ++#define CLK_MUX_MSC0 (CLK_ID_MUX + 17) ++#define CLK_MUX_MSC1 (CLK_ID_MUX + 18) ++#define CLK_MUX_MSC2 (CLK_ID_MUX + 19) ++#define CLK_MUX_SFC (CLK_ID_MUX + 20) ++#define CLK_MUX_SSI (CLK_ID_MUX + 21) ++#define CLK_MUX_CIM (CLK_ID_MUX + 22) ++#define CLK_MUX_PWM (CLK_ID_MUX + 23) ++#define CLK_MUX_ISP (CLK_ID_MUX + 24) ++#define CLK_MUX_RSA (CLK_ID_MUX + 25) ++#define CLK_MUX_MACPTP (CLK_ID_MUX + 26) ++#define CLK_MUX_WDT (CLK_ID_MUX + 27) ++ ++ ++#define CLK_NR_MUX (28) ++ ++ ++#define CLK_ID_DIV (CLK_ID_MUX + CLK_NR_MUX) ++#define CLK_DIV_DDR (CLK_ID_DIV + 0) ++#define CLK_DIV_MACPHY (CLK_ID_DIV + 1) ++#define CLK_DIV_MACTXPHY (CLK_ID_DIV + 2) ++#define CLK_DIV_MACTXPHY1 (CLK_ID_DIV + 3) ++#define CLK_DIV_I2S0 (CLK_ID_DIV + 4) ++#define CLK_DIV_I2S1 (CLK_ID_DIV + 5) ++#define CLK_DIV_I2S2 (CLK_ID_DIV + 6) ++#define CLK_DIV_I2S3 (CLK_ID_DIV + 7) ++#define CLK_DIV_LCD (CLK_ID_DIV + 8) ++#define CLK_DIV_MSC0 (CLK_ID_DIV + 9) ++#define CLK_DIV_MSC1 (CLK_ID_DIV + 10) ++#define CLK_DIV_MSC2 (CLK_ID_DIV + 11) ++#define CLK_DIV_SFC (CLK_ID_DIV + 12) ++#define CLK_DIV_SSI (CLK_ID_DIV + 13) ++#define CLK_DIV_CIM (CLK_ID_DIV + 14) ++#define CLK_DIV_PWM (CLK_ID_DIV + 15) ++#define CLK_DIV_ISP (CLK_ID_DIV + 16) ++#define CLK_DIV_RSA (CLK_ID_DIV + 17) ++#define CLK_DIV_MACPTP (CLK_ID_DIV + 18) ++ ++#define CLK_DIV_CPU (CLK_ID_DIV + 19) ++#define CLK_DIV_L2C (CLK_ID_DIV + 20) ++#define CLK_DIV_AHB0 (CLK_ID_DIV + 21) ++#define CLK_DIV_AHB2 (CLK_ID_DIV + 22) ++#define CLK_DIV_APB (CLK_ID_DIV + 23) ++#define CLK_DIV_CPU_L2C_X1 (CLK_ID_DIV + 24) ++#define CLK_DIV_CPU_L2C_X2 (CLK_ID_DIV + 25) ++ ++#define CLK_NR_DIV (26) ++ ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_DIV + CLK_NR_DIV) ++#define CLK_GATE_DDR (CLK_ID_GATE + 0) ++#define CLK_GATE_IPU (CLK_ID_GATE + 1) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 2) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 3) ++#define CLK_GATE_RTC (CLK_ID_GATE + 4) ++#define CLK_GATE_SSI1 (CLK_ID_GATE + 5) ++#define CLK_GATE_RSA (CLK_ID_GATE + 6) ++#define CLK_GATE_AES (CLK_ID_GATE + 7) ++#define CLK_GATE_LCD (CLK_ID_GATE + 8) ++#define CLK_GATE_CIM (CLK_ID_GATE + 9) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 10) ++#define CLK_GATE_OST (CLK_ID_GATE + 11) ++#define CLK_GATE_SSI0 (CLK_ID_GATE + 12) ++#define CLK_GATE_TCU (CLK_ID_GATE + 13) ++#define CLK_GATE_DTRNG (CLK_ID_GATE + 14) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 15) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 16) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 17) ++#define CLK_GATE_SADC (CLK_ID_GATE + 18) ++#define CLK_GATE_HELIX (CLK_ID_GATE + 19) ++#define CLK_GATE_AUDIO (CLK_ID_GATE + 20) ++#define CLK_GATE_SMB3 (CLK_ID_GATE + 21) ++#define CLK_GATE_SMB2 (CLK_ID_GATE + 22) ++#define CLK_GATE_SMB1 (CLK_ID_GATE + 23) ++#define CLK_GATE_SMB0 (CLK_ID_GATE + 24) ++#define CLK_GATE_SCC (CLK_ID_GATE + 25) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 26) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 27) ++#define CLK_GATE_OTG (CLK_ID_GATE + 28) ++#define CLK_GATE_SFC (CLK_ID_GATE + 29) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 30) ++#define CLK_GATE_NEMC (CLK_ID_GATE + 31) ++#define CLK_GATE_ARB (CLK_ID_GATE + 32) ++#define CLK_GATE_MIPI_DSI (CLK_ID_GATE + 33) ++#define CLK_GATE_MIPI_CSI (CLK_ID_GATE + 34) ++#define CLK_GATE_INTC (CLK_ID_GATE + 35) ++#define CLK_GATE_MSC2 (CLK_ID_GATE + 36) ++#define CLK_GATE_GMAC1 (CLK_ID_GATE + 37) ++#define CLK_GATE_GMAC0 (CLK_ID_GATE + 38) ++#define CLK_GATE_UART9 (CLK_ID_GATE + 39) ++#define CLK_GATE_UART8 (CLK_ID_GATE + 40) ++#define CLK_GATE_UART7 (CLK_ID_GATE + 41) ++#define CLK_GATE_UATR6 (CLK_ID_GATE + 42) ++#define CLK_GATE_UART5 (CLK_ID_GATE + 43) ++#define CLK_GATE_UART4 (CLK_ID_GATE + 44) ++#define CLK_GATE_UART3 (CLK_ID_GATE + 45) ++#define CLK_GATE_SPDIF (CLK_ID_GATE + 46) ++#define CLK_GATE_DMIC (CLK_ID_GATE + 47) ++#define CLK_GATE_PCM (CLK_ID_GATE + 48) ++#define CLK_GATE_I2S3 (CLK_ID_GATE + 49) ++#define CLK_GATE_I2S2 (CLK_ID_GATE + 50) ++#define CLK_GATE_I2S1 (CLK_ID_GATE + 51) ++#define CLK_GATE_I2S0 (CLK_ID_GATE + 52) ++#define CLK_GATE_ROT (CLK_ID_GATE + 53) ++#define CLK_GATE_HASH (CLK_ID_GATE + 54) ++#define CLK_GATE_PWM (CLK_ID_GATE + 55) ++#define CLK_GATE_FELIX (CLK_ID_GATE + 56) ++#define CLK_GATE_ISP1 (CLK_ID_GATE + 57) ++#define CLK_GATE_ISP0 (CLK_ID_GATE + 58) ++#define CLK_GATE_SMB5 (CLK_ID_GATE + 59) ++#define CLK_GATE_SMB4 (CLK_ID_GATE + 60) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 61) ++#define CLK_CE_I2S0 (CLK_ID_GATE + 62) ++#define CLK_CE_I2S1 (CLK_ID_GATE + 63) ++#define CLK_CE_I2S2 (CLK_ID_GATE + 64) ++#define CLK_CE_I2S3 (CLK_ID_GATE + 65) ++#define CLK_NR_GATE (66) ++ ++#define POWER_ID (CLK_ID_GATE + CLK_NR_GATE) ++#define POWER_ISP0 (POWER_ID + 0) ++#define POWER_ISP1 (POWER_ID + 1) ++#define POWER_FELIX (POWER_ID + 2) ++#define POWER_HELIX (POWER_ID + 3) ++ ++#define PD_MEM_NEMC (POWER_ID + 4) ++#define PD_MEM_USB (POWER_ID + 5) ++#define PD_MEM_SFC (POWER_ID + 6) ++#define PD_MEM_PDMA_SEC (POWER_ID + 7) ++#define PD_MEM_PDMA (POWER_ID + 8) ++#define PD_MEM_MSC2 (POWER_ID + 9) ++#define PD_MEM_MSC1 (POWER_ID + 10) ++#define PD_MEM_MSC0 (POWER_ID + 11) ++#define PD_MEM_GMAC1 (POWER_ID + 12) ++#define PD_MEM_GMAC0 (POWER_ID + 13) ++#define PD_MEM_DMIC (POWER_ID + 14) ++#define PD_MEM_AUDIO (POWER_ID + 15) ++#define PD_MEM_AES (POWER_ID + 16) ++#define PD_MEM_DSI (POWER_ID + 17) ++#define PD_MEM_SSI1 (POWER_ID + 18) ++#define PD_MEM_SSI0 (POWER_ID + 19) ++#define PD_MEM_UART9 (POWER_ID + 20) ++#define PD_MEM_UART8 (POWER_ID + 21) ++#define PD_MEM_UART7 (POWER_ID + 22) ++#define PD_MEM_UART6 (POWER_ID + 23) ++#define PD_MEM_UART5 (POWER_ID + 24) ++#define PD_MEM_UART4 (POWER_ID + 25) ++#define PD_MEM_UART3 (POWER_ID + 26) ++#define PD_MEM_UART2 (POWER_ID + 27) ++#define PD_MEM_UART1 (POWER_ID + 28) ++#define PD_MEM_UART0 (POWER_ID + 29) ++#define PD_MEM_ROT (POWER_ID + 30) ++#define PD_MEM_CIM (POWER_ID + 31) ++#define PD_MEM_DPU (POWER_ID + 32) ++#define PD_MEM_DDR_CH6 (POWER_ID + 33) ++#define PD_MEM_DDR_CH5 (POWER_ID + 34) ++#define PD_MEM_DDR_CH3 (POWER_ID + 35) ++#define PD_MEM_DDR_CH1 (POWER_ID + 36) ++#define PD_MEM_DDR_CH0 (POWER_ID + 37) ++#define PD_MEM_DDR_TOP (POWER_ID + 38) ++#define CLK_NR_POWER (39) ++ ++#define CLK_ID_OTHER (POWER_ID + CLK_NR_POWER) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_MUX + CLK_NR_DIV + CLK_NR_GATE + CLK_NR_POWER) ++#endif +diff --git a/include/dt-bindings/clock/ingenic-tcu.h b/include/dt-bindings/clock/ingenic-tcu.h +new file mode 100644 +index 000000000..d92493c33 +--- /dev/null ++++ b/include/dt-bindings/clock/ingenic-tcu.h +@@ -0,0 +1,29 @@ ++#ifndef __DT_BINDINGS_CLOCK_INGENIC_TCU_H__ ++#define __DT_BINDINGS_CLOCK_INGENIC_TCU_H__ ++ ++#define TCU_MODE1 1 ++#define TCU_MODE2 2 ++ ++#define PWM_FUNC 1 ++#define TRACKBALL_FUNC 2 ++#define PWM_AND_TRACKBALL_FUNC (PWM_FUNC | TRACKBALL_FUNC) ++ ++#define NO_PWM_IN 0 ++#define PWM_IN 1 ++ ++#define NOWORK_SLEEP 0 ++#define WORK_SLEEP 1 ++ ++#define CHANNEL_BASE_OFF 4 ++#define CHANNEL_ID_OFF 0 ++#define CHANNEL_MODE_OFF (CHANNEL_ID_OFF + CHANNEL_BASE_OFF*2) ++#define CHANNEL_FUNC_OFF (CHANNEL_MODE_OFF + CHANNEL_BASE_OFF) ++#define CHANNEL_IN_OFF (CHANNEL_FUNC_OFF + CHANNEL_BASE_OFF) ++#define CHANNEL_SLEEP_OFF (CHANNEL_IN_OFF + CHANNEL_BASE_OFF) ++ ++#define CHANNEL_INFO(ID, MODE, FUNC, IN, SLEEP) \ ++ ((ID << CHANNEL_ID_OFF)|(MODE << CHANNEL_MODE_OFF) \ ++ |(FUNC << CHANNEL_FUNC_OFF)|(IN << CHANNEL_IN_OFF) \ ++ |(SLEEP << CHANNEL_SLEEP_OFF)) ++ ++#endif /* __DT_BINDINGS_CLOCK_INGENIC_TCU_H__ */ +diff --git a/include/dt-bindings/clock/ingenic-x1600.h b/include/dt-bindings/clock/ingenic-x1600.h +new file mode 100644 +index 000000000..c5ea4975e +--- /dev/null ++++ b/include/dt-bindings/clock/ingenic-x1600.h +@@ -0,0 +1,146 @@ ++#ifndef _DT_BINDINGS_CLOCK_X2000_V12_H ++#define _DT_BINDINGS_CLOCK_X2000_V12_H ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_EXT_DIV_512 (CLK_ID_FIEXED + 2) ++#define CLK_NR_FIXED (3) ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_PLL_EPLL (CLK_ID_PLL + 2) ++#define CLK_NR_PLL (3) ++ ++/* MUX clk */ ++#define CLK_ID_MUX (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_MUX + 0) ++#define CLK_MUX_CPU_L2C (CLK_ID_MUX + 1) ++#define CLK_MUX_AHB0 (CLK_ID_MUX + 2) ++#define CLK_MUX_AHB2 (CLK_ID_MUX + 3) ++#define CLK_MUX_DDR (CLK_ID_MUX + 4) ++#define CLK_MUX_MACPHY (CLK_ID_MUX + 5) ++#define CLK_MUX_I2S0T (CLK_ID_MUX + 6) ++#define CLK_MUX_LCD (CLK_ID_MUX + 7) ++#define CLK_MUX_MSC0 (CLK_ID_MUX + 8) ++#define CLK_MUX_MSC1 (CLK_ID_MUX + 9) ++#define CLK_MUX_SFC (CLK_ID_MUX + 10) ++#define CLK_MUX_SSI (CLK_ID_MUX + 11) ++#define CLK_MUX_CIM (CLK_ID_MUX + 12) ++#define CLK_MUX_PWM (CLK_ID_MUX + 13) ++#define CLK_MUX_CAN0 (CLK_ID_MUX + 14) ++#define CLK_MUX_CAN1 (CLK_ID_MUX + 15) ++#define CLK_MUX_CDBUS (CLK_ID_MUX + 16) ++#define CLK_MUX_I2S0R (CLK_ID_MUX + 17) ++#define CLK_MUX_WDT (CLK_ID_MUX + 18) ++ ++#define CLK_NR_MUX (19) ++ ++ ++#define CLK_ID_DIV (CLK_ID_MUX + CLK_NR_MUX) ++#define CLK_DIV_DDR (CLK_ID_DIV + 0) ++#define CLK_DIV_MACPHY (CLK_ID_DIV + 1) ++#define CLK_DIV_I2S0T (CLK_ID_DIV + 2) ++#define CLK_DIV_LCD (CLK_ID_DIV + 3) ++#define CLK_DIV_MSC0 (CLK_ID_DIV + 4) ++#define CLK_DIV_MSC1 (CLK_ID_DIV + 5) ++#define CLK_DIV_SFC (CLK_ID_DIV + 6) ++#define CLK_DIV_SSI (CLK_ID_DIV + 7) ++#define CLK_DIV_CIM (CLK_ID_DIV + 8) ++#define CLK_DIV_PWM (CLK_ID_DIV + 9) ++#define CLK_DIV_CAN0 (CLK_ID_DIV + 10) ++#define CLK_DIV_CAN1 (CLK_ID_DIV + 11) ++#define CLK_DIV_CDBUS (CLK_ID_DIV + 12) ++ ++#define CLK_DIV_CPU (CLK_ID_DIV + 13) ++#define CLK_DIV_L2C (CLK_ID_DIV + 14) ++#define CLK_DIV_AHB0 (CLK_ID_DIV + 15) ++#define CLK_DIV_AHB2 (CLK_ID_DIV + 16) ++#define CLK_DIV_APB (CLK_ID_DIV + 17) ++#define CLK_DIV_CPU_L2C_X1 (CLK_ID_DIV + 18) ++#define CLK_DIV_CPU_L2C_X2 (CLK_ID_DIV + 19) ++#define CLK_DIV_I2S0R (CLK_ID_DIV + 20) ++ ++#define CLK_NR_DIV (21) ++ ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_DIV + CLK_NR_DIV) ++#define CLK_GATE_DDR (CLK_ID_GATE + 0) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 1) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 2) ++#define CLK_GATE_RTC (CLK_ID_GATE + 3) ++#define CLK_GATE_AES (CLK_ID_GATE + 4) ++#define CLK_GATE_LCD (CLK_ID_GATE + 5) ++#define CLK_GATE_CIM (CLK_ID_GATE + 6) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 7) ++#define CLK_GATE_OST (CLK_ID_GATE + 8) ++#define CLK_GATE_SSI0 (CLK_ID_GATE + 9) ++#define CLK_GATE_TCU (CLK_ID_GATE + 10) ++#define CLK_GATE_DTRNG (CLK_ID_GATE + 11) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 12) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 13) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 14) ++#define CLK_GATE_SADC (CLK_ID_GATE + 15) ++#define CLK_GATE_AUDIO (CLK_ID_GATE + 16) ++#define CLK_GATE_SSISLV (CLK_ID_GATE + 17) ++#define CLK_GATE_SMB1 (CLK_ID_GATE + 18) ++#define CLK_GATE_SMB0 (CLK_ID_GATE + 19) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 20) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 21) ++#define CLK_GATE_OTG (CLK_ID_GATE + 22) ++#define CLK_GATE_SFC (CLK_ID_GATE + 23) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 24) ++#define CLK_GATE_NEMC (CLK_ID_GATE + 25) ++#define CLK_GATE_ARB (CLK_ID_GATE + 26) ++#define CLK_GATE_MIPI_CSI (CLK_ID_GATE + 27) ++#define CLK_GATE_INTC (CLK_ID_GATE + 28) ++#define CLK_GATE_GMAC0 (CLK_ID_GATE + 29) ++#define CLK_GATE_UART3 (CLK_ID_GATE + 30) ++#define CLK_GATE_I2S0T (CLK_ID_GATE + 31) ++#define CLK_GATE_I2S0R (CLK_ID_GATE + 32) ++#define CLK_GATE_HASH (CLK_ID_GATE + 33) ++#define CLK_GATE_PWM (CLK_ID_GATE + 34) ++#define CLK_GATE_CDBUS (CLK_ID_GATE + 35) ++#define CLK_GATE_CAN1 (CLK_ID_GATE + 36) ++#define CLK_GATE_CAN0 (CLK_ID_GATE + 37) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 38) ++#define CLK_CE_I2S0T (CLK_ID_GATE + 39) ++#define CLK_CE_I2S0R (CLK_ID_GATE + 40) ++#define CLK_NR_GATE (41) ++ ++#define POWER_ID (CLK_ID_GATE + CLK_NR_GATE) ++#define PD_MEM_CDBUS (POWER_ID + 4) ++#define PD_MEM_PWM (POWER_ID + 5) ++#define PD_MEM_GMAC (POWER_ID + 6) ++#define PD_MEM_USB (POWER_ID + 7) ++#define PD_MEM_SFC (POWER_ID + 8) ++#define PD_MEM_MSC1 (POWER_ID + 9) ++#define PD_MEM_MSC0 (POWER_ID + 10) ++#define PD_MEM_AES (POWER_ID + 11) ++#define PD_MEM_PDMA_SLP (POWER_ID + 12) ++#define PD_MEM_PDMA_SEC (POWER_ID + 13) ++#define PD_MEM_PDMA (POWER_ID + 14) ++#define PD_MEM_NEMC (POWER_ID + 15) ++#define PD_MEM_AIC (POWER_ID + 16) ++#define PD_MEM_SSISLV (POWER_ID + 17) ++#define PD_MEM_SSI0 (POWER_ID + 18) ++#define PD_MEM_UART3 (POWER_ID + 19) ++#define PD_MEM_UART2 (POWER_ID + 20) ++#define PD_MEM_UART1 (POWER_ID + 21) ++#define PD_MEM_UART0 (POWER_ID + 22) ++#define PD_MEM_CIM (POWER_ID + 23) ++#define PD_MEM_DPU (POWER_ID + 24) ++#define PD_MEM_DDR_CH6 (POWER_ID + 25) ++#define PD_MEM_DDR_CH5 (POWER_ID + 26) ++#define PD_MEM_DDR_CH3 (POWER_ID + 27) ++#define PD_MEM_DDR_TOP (POWER_ID + 28) ++#define CLK_NR_POWER (29) ++ ++#define CLK_ID_OTHER (POWER_ID + CLK_NR_POWER) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_MUX + CLK_NR_DIV + CLK_NR_GATE + CLK_NR_POWER) ++#endif +diff --git a/include/dt-bindings/clock/ingenic-x2000.h b/include/dt-bindings/clock/ingenic-x2000.h +new file mode 100644 +index 000000000..25ce88570 +--- /dev/null ++++ b/include/dt-bindings/clock/ingenic-x2000.h +@@ -0,0 +1,201 @@ ++#ifndef _DT_BINDINGS_CLOCK_X2000_H ++#define _DT_BINDINGS_CLOCK_X2000_H ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_EXT_DIV_512 (CLK_ID_FIEXED + 2) ++#define CLK_NR_FIXED (3) ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_PLL_EPLL (CLK_ID_PLL + 2) ++#define CLK_NR_PLL (3) ++ ++/* MUX clk */ ++#define CLK_ID_MUX (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_MUX + 0) ++#define CLK_MUX_CPU_L2C (CLK_ID_MUX + 1) ++#define CLK_MUX_AHB0 (CLK_ID_MUX + 2) ++#define CLK_MUX_AHB2 (CLK_ID_MUX + 3) ++#define CLK_MUX_DDR (CLK_ID_MUX + 4) ++#define CLK_MUX_MACPHY (CLK_ID_MUX + 5) ++#define CLK_MUX_MACTXPHY (CLK_ID_MUX + 6) ++#define CLK_MUX_MACTXPHY1 (CLK_ID_MUX + 7) ++#define CLK_MUX_I2S0 (CLK_ID_MUX + 8) ++#define CLK_MUX_I2S1 (CLK_ID_MUX + 9) ++#define CLK_MUX_I2S2 (CLK_ID_MUX + 10) ++#define CLK_MUX_I2S3 (CLK_ID_MUX + 11) ++#define CLK_MUX_AUDIO_RAM (CLK_ID_MUX + 12) ++#define CLK_MUX_SPDIF (CLK_ID_MUX + 13) ++#define CLK_MUX_PCM (CLK_ID_MUX + 14) ++#define CLK_MUX_DMIC (CLK_ID_MUX + 15) ++#define CLK_MUX_LCD (CLK_ID_MUX + 16) ++#define CLK_MUX_MSC0 (CLK_ID_MUX + 17) ++#define CLK_MUX_MSC1 (CLK_ID_MUX + 18) ++#define CLK_MUX_MSC2 (CLK_ID_MUX + 19) ++#define CLK_MUX_SFC (CLK_ID_MUX + 20) ++#define CLK_MUX_SSI (CLK_ID_MUX + 21) ++#define CLK_MUX_CIM (CLK_ID_MUX + 22) ++#define CLK_MUX_PWM (CLK_ID_MUX + 23) ++#define CLK_MUX_ISP (CLK_ID_MUX + 24) ++#define CLK_MUX_RSA (CLK_ID_MUX + 25) ++#define CLK_MUX_MACPTP (CLK_ID_MUX + 26) ++#define CLK_MUX_WDT (CLK_ID_MUX + 27) ++ ++ ++#define CLK_NR_MUX (28) ++ ++ ++#define CLK_ID_DIV (CLK_ID_MUX + CLK_NR_MUX) ++#define CLK_DIV_DDR (CLK_ID_DIV + 0) ++#define CLK_DIV_MACPHY (CLK_ID_DIV + 1) ++#define CLK_DIV_MACTXPHY (CLK_ID_DIV + 2) ++#define CLK_DIV_MACTXPHY1 (CLK_ID_DIV + 3) ++#define CLK_DIV_I2S0 (CLK_ID_DIV + 4) ++#define CLK_DIV_I2S1 (CLK_ID_DIV + 5) ++#define CLK_DIV_I2S2 (CLK_ID_DIV + 6) ++#define CLK_DIV_I2S3 (CLK_ID_DIV + 7) ++#define CLK_DIV_LCD (CLK_ID_DIV + 8) ++#define CLK_DIV_MSC0 (CLK_ID_DIV + 9) ++#define CLK_DIV_MSC1 (CLK_ID_DIV + 10) ++#define CLK_DIV_MSC2 (CLK_ID_DIV + 11) ++#define CLK_DIV_SFC (CLK_ID_DIV + 12) ++#define CLK_DIV_SSI (CLK_ID_DIV + 13) ++#define CLK_DIV_CIM (CLK_ID_DIV + 14) ++#define CLK_DIV_PWM (CLK_ID_DIV + 15) ++#define CLK_DIV_ISP (CLK_ID_DIV + 16) ++#define CLK_DIV_RSA (CLK_ID_DIV + 17) ++#define CLK_DIV_MACPTP (CLK_ID_DIV + 18) ++ ++#define CLK_DIV_CPU (CLK_ID_DIV + 19) ++#define CLK_DIV_L2C (CLK_ID_DIV + 20) ++#define CLK_DIV_AHB0 (CLK_ID_DIV + 21) ++#define CLK_DIV_AHB2 (CLK_ID_DIV + 22) ++#define CLK_DIV_APB (CLK_ID_DIV + 23) ++#define CLK_DIV_CPU_L2C_X1 (CLK_ID_DIV + 24) ++#define CLK_DIV_CPU_L2C_X2 (CLK_ID_DIV + 25) ++ ++#define CLK_NR_DIV (26) ++ ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_DIV + CLK_NR_DIV) ++#define CLK_GATE_DDR (CLK_ID_GATE + 0) ++#define CLK_GATE_IPU (CLK_ID_GATE + 1) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 2) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 3) ++#define CLK_GATE_RTC (CLK_ID_GATE + 4) ++#define CLK_GATE_SSI1 (CLK_ID_GATE + 5) ++#define CLK_GATE_RSA (CLK_ID_GATE + 6) ++#define CLK_GATE_AES (CLK_ID_GATE + 7) ++#define CLK_GATE_LCD (CLK_ID_GATE + 8) ++#define CLK_GATE_CIM (CLK_ID_GATE + 9) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 10) ++#define CLK_GATE_OST (CLK_ID_GATE + 11) ++#define CLK_GATE_SSI0 (CLK_ID_GATE + 12) ++#define CLK_GATE_TCU (CLK_ID_GATE + 13) ++#define CLK_GATE_DTRNG (CLK_ID_GATE + 14) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 15) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 16) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 17) ++#define CLK_GATE_SADC (CLK_ID_GATE + 18) ++#define CLK_GATE_HELIX (CLK_ID_GATE + 19) ++#define CLK_GATE_AUDIO (CLK_ID_GATE + 20) ++#define CLK_GATE_SMB3 (CLK_ID_GATE + 21) ++#define CLK_GATE_SMB2 (CLK_ID_GATE + 22) ++#define CLK_GATE_SMB1 (CLK_ID_GATE + 23) ++#define CLK_GATE_SMB0 (CLK_ID_GATE + 24) ++#define CLK_GATE_SCC (CLK_ID_GATE + 25) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 26) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 27) ++#define CLK_GATE_OTG (CLK_ID_GATE + 28) ++#define CLK_GATE_SFC (CLK_ID_GATE + 29) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 30) ++#define CLK_GATE_NEMC (CLK_ID_GATE + 31) ++#define CLK_GATE_ARB (CLK_ID_GATE + 32) ++#define CLK_GATE_MIPI_DSI (CLK_ID_GATE + 33) ++#define CLK_GATE_MIPI_CSI (CLK_ID_GATE + 34) ++#define CLK_GATE_INTC (CLK_ID_GATE + 35) ++#define CLK_GATE_MSC2 (CLK_ID_GATE + 36) ++#define CLK_GATE_GMAC1 (CLK_ID_GATE + 37) ++#define CLK_GATE_GMAC0 (CLK_ID_GATE + 38) ++#define CLK_GATE_UART9 (CLK_ID_GATE + 39) ++#define CLK_GATE_UART8 (CLK_ID_GATE + 40) ++#define CLK_GATE_UART7 (CLK_ID_GATE + 41) ++#define CLK_GATE_UATR6 (CLK_ID_GATE + 42) ++#define CLK_GATE_UART5 (CLK_ID_GATE + 43) ++#define CLK_GATE_UART4 (CLK_ID_GATE + 44) ++#define CLK_GATE_UART3 (CLK_ID_GATE + 45) ++#define CLK_GATE_SPDIF (CLK_ID_GATE + 46) ++#define CLK_GATE_DMIC (CLK_ID_GATE + 47) ++#define CLK_GATE_PCM (CLK_ID_GATE + 48) ++#define CLK_GATE_I2S3 (CLK_ID_GATE + 49) ++#define CLK_GATE_I2S2 (CLK_ID_GATE + 50) ++#define CLK_GATE_I2S1 (CLK_ID_GATE + 51) ++#define CLK_GATE_I2S0 (CLK_ID_GATE + 52) ++#define CLK_GATE_ROT (CLK_ID_GATE + 53) ++#define CLK_GATE_HASH (CLK_ID_GATE + 54) ++#define CLK_GATE_PWM (CLK_ID_GATE + 55) ++#define CLK_GATE_FELIX (CLK_ID_GATE + 56) ++#define CLK_GATE_ISP1 (CLK_ID_GATE + 57) ++#define CLK_GATE_ISP0 (CLK_ID_GATE + 58) ++#define CLK_GATE_SMB5 (CLK_ID_GATE + 59) ++#define CLK_GATE_SMB4 (CLK_ID_GATE + 60) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 61) ++#define CLK_CE_I2S0 (CLK_ID_GATE + 62) ++#define CLK_CE_I2S1 (CLK_ID_GATE + 63) ++#define CLK_CE_I2S2 (CLK_ID_GATE + 64) ++#define CLK_CE_I2S3 (CLK_ID_GATE + 65) ++#define CLK_NR_GATE (66) ++ ++#define POWER_ID (CLK_ID_GATE + CLK_NR_GATE) ++#define POWER_ISP0 (POWER_ID + 0) ++#define POWER_ISP1 (POWER_ID + 1) ++#define POWER_FELIX (POWER_ID + 2) ++#define POWER_HELIX (POWER_ID + 3) ++ ++#define PD_MEM_NEMC (POWER_ID + 4) ++#define PD_MEM_USB (POWER_ID + 5) ++#define PD_MEM_SFC (POWER_ID + 6) ++#define PD_MEM_PDMA_SEC (POWER_ID + 7) ++#define PD_MEM_PDMA (POWER_ID + 8) ++#define PD_MEM_MSC2 (POWER_ID + 9) ++#define PD_MEM_MSC1 (POWER_ID + 10) ++#define PD_MEM_MSC0 (POWER_ID + 11) ++#define PD_MEM_GMAC1 (POWER_ID + 12) ++#define PD_MEM_GMAC0 (POWER_ID + 13) ++#define PD_MEM_DMIC (POWER_ID + 14) ++#define PD_MEM_AUDIO (POWER_ID + 15) ++#define PD_MEM_AES (POWER_ID + 16) ++#define PD_MEM_DSI (POWER_ID + 17) ++#define PD_MEM_SSI1 (POWER_ID + 18) ++#define PD_MEM_SSI0 (POWER_ID + 19) ++#define PD_MEM_UART9 (POWER_ID + 20) ++#define PD_MEM_UART8 (POWER_ID + 21) ++#define PD_MEM_UART7 (POWER_ID + 22) ++#define PD_MEM_UART6 (POWER_ID + 23) ++#define PD_MEM_UART5 (POWER_ID + 24) ++#define PD_MEM_UART4 (POWER_ID + 25) ++#define PD_MEM_UART3 (POWER_ID + 26) ++#define PD_MEM_UART2 (POWER_ID + 27) ++#define PD_MEM_UART1 (POWER_ID + 28) ++#define PD_MEM_UART0 (POWER_ID + 29) ++#define PD_MEM_ROT (POWER_ID + 30) ++#define PD_MEM_CIM (POWER_ID + 31) ++#define PD_MEM_DPU (POWER_ID + 32) ++#define PD_MEM_DDR_CH6 (POWER_ID + 33) ++#define PD_MEM_DDR_CH5 (POWER_ID + 34) ++#define PD_MEM_DDR_CH3 (POWER_ID + 35) ++#define PD_MEM_DDR_CH1 (POWER_ID + 36) ++#define PD_MEM_DDR_CH0 (POWER_ID + 37) ++#define PD_MEM_DDR_TOP (POWER_ID + 38) ++#define CLK_NR_POWER (39) ++ ++#define CLK_ID_OTHER (POWER_ID + CLK_NR_POWER) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_MUX + CLK_NR_DIV + CLK_NR_GATE + CLK_NR_POWER) ++#endif +diff --git a/include/dt-bindings/clock/ingenic-x2500.h b/include/dt-bindings/clock/ingenic-x2500.h +new file mode 100644 +index 000000000..02630d04d +--- /dev/null ++++ b/include/dt-bindings/clock/ingenic-x2500.h +@@ -0,0 +1,136 @@ ++#ifndef _DT_BINDINGS_CLOCK_X2500_H ++#define _DT_BINDINGS_CLOCK_X2500_H ++ ++/* Fixed Clk */ ++#define CLK_ID_FIEXED 0 ++#define CLK_EXT (CLK_ID_FIEXED + 0) ++#define CLK_RTC_EXT (CLK_ID_FIEXED + 1) ++#define CLK_NR_FIXED (2) ++ ++/* PLL clk */ ++#define CLK_ID_PLL (CLK_ID_FIEXED + CLK_NR_FIXED) ++#define CLK_PLL_APLL (CLK_ID_PLL + 0) ++#define CLK_PLL_MPLL (CLK_ID_PLL + 1) ++#define CLK_PLL_VPLL (CLK_ID_PLL + 2) ++#define CLK_PLL_EPLL (CLK_ID_PLL + 3) ++#define CLK_NR_PLL (4) ++ ++/* MUX clk */ ++#define CLK_ID_MUX (CLK_ID_PLL + CLK_NR_PLL) ++#define CLK_MUX_SCLKA (CLK_ID_MUX + 0) ++#define CLK_MUX_CPU_L2C (CLK_ID_MUX + 1) ++#define CLK_MUX_AHB0 (CLK_ID_MUX + 2) ++#define CLK_MUX_AHB2 (CLK_ID_MUX + 3) ++#define CLK_MUX_PCLK (CLK_ID_MUX + 4) ++#define CLK_MUX_DDR (CLK_ID_MUX + 5) ++#define CLK_MUX_MACPHY (CLK_ID_MUX + 6) ++#define CLK_MUX_LCD (CLK_ID_MUX + 7) ++#define CLK_MUX_MSC0 (CLK_ID_MUX + 8) ++#define CLK_MUX_MSC1 (CLK_ID_MUX + 9) ++#define CLK_MUX_SFC (CLK_ID_MUX + 10) ++#define CLK_MUX_SSI (CLK_ID_MUX + 11) ++#define CLK_MUX_CIM0 (CLK_ID_MUX + 12) ++#define CLK_MUX_CIM1 (CLK_ID_MUX + 13) ++#define CLK_MUX_CIM2 (CLK_ID_MUX + 14) ++#define CLK_MUX_ISP (CLK_ID_MUX + 15) ++#define CLK_MUX_RSA (CLK_ID_MUX + 16) ++#define CLK_MUX_EL150 (CLK_ID_MUX + 17) ++#define CLK_MUX_I2ST (CLK_ID_MUX + 18) ++#define CLK_MUX_I2SR (CLK_ID_MUX + 19) ++#define CLK_MUX_BSCALER (CLK_ID_MUX + 20) ++#define CLK_MUX_BT0 (CLK_ID_MUX + 21) ++#define CLK_MUX_BT1 (CLK_ID_MUX + 22) ++ ++#define CLK_NR_MUX (23) ++ ++ ++#define CLK_ID_DIV (CLK_ID_MUX + CLK_NR_MUX) ++#define CLK_DIV_DDR (CLK_ID_DIV + 0) ++#define CLK_DIV_MACPHY (CLK_ID_DIV + 1) ++#define CLK_DIV_LCD (CLK_ID_DIV + 2) ++#define CLK_DIV_MSC0 (CLK_ID_DIV + 3) ++#define CLK_DIV_MSC1 (CLK_ID_DIV + 4) ++#define CLK_DIV_SFC (CLK_ID_DIV + 5) ++#define CLK_DIV_SSI (CLK_ID_DIV + 6) ++#define CLK_DIV_CIM0 (CLK_ID_DIV + 7) ++#define CLK_DIV_CIM1 (CLK_ID_DIV + 8) ++#define CLK_DIV_CIM2 (CLK_ID_DIV + 9) ++#define CLK_DIV_ISP (CLK_ID_DIV + 10) ++#define CLK_DIV_RSA (CLK_ID_DIV + 11) ++#define CLK_DIV_EL150 (CLK_ID_DIV + 12) ++#define CLK_DIV_I2ST (CLK_ID_DIV + 13) ++#define CLK_DIV_I2SR (CLK_ID_DIV + 14) ++#define CLK_DIV_BSCALER (CLK_ID_DIV + 15) ++#define CLK_DIV_BT0 (CLK_ID_DIV + 16) ++#define CLK_DIV_BT1 (CLK_ID_DIV + 17) ++ ++#define CLK_DIV_CPU (CLK_ID_DIV + 18) ++#define CLK_DIV_L2C (CLK_ID_DIV + 19) ++#define CLK_DIV_AHB0 (CLK_ID_DIV + 20) ++#define CLK_DIV_AHB2 (CLK_ID_DIV + 21) ++#define CLK_DIV_APB (CLK_ID_DIV + 22) ++#define CLK_DIV_CPU_L2C (CLK_ID_DIV + 23) ++#define CLK_DIV_CPU_L2C_X1 (CLK_ID_DIV + 24) ++#define CLK_DIV_CPU_L2C_X2 (CLK_ID_DIV + 25) ++ ++#define CLK_NR_DIV (26) ++ ++ ++/* Gate Clocks */ ++#define CLK_ID_GATE (CLK_ID_DIV + CLK_NR_DIV) ++#define CLK_GATE_DDR (CLK_ID_GATE + 0) ++#define CLK_GATE_TCU (CLK_ID_GATE + 1) ++#define CLK_GATE_RESERVER29 (CLK_ID_GATE + 2) ++#define CLK_GATE_DES (CLK_ID_GATE + 3) ++#define CLK_GATE_RSA (CLK_ID_GATE + 4) ++#define CLK_GATE_VO (CLK_ID_GATE + 5) ++#define CLK_GATE_MIPI_CSI (CLK_ID_GATE + 6) ++#define CLK_GATE_LCD (CLK_ID_GATE + 7) ++#define CLK_GATE_ISP (CLK_ID_GATE + 8) ++#define CLK_GATE_PDMA (CLK_ID_GATE + 9) ++#define CLK_GATE_SFC (CLK_ID_GATE + 10) ++#define CLK_GATE_SSI1 (CLK_ID_GATE + 11) ++#define CLK_GATE_HASH (CLK_ID_GATE + 12) ++#define CLK_GATE_SLV (CLK_ID_GATE + 13) ++#define CLK_GATE_UART3 (CLK_ID_GATE + 14) ++#define CLK_GATE_UART2 (CLK_ID_GATE + 15) ++#define CLK_GATE_UART1 (CLK_ID_GATE + 16) ++#define CLK_GATE_UART0 (CLK_ID_GATE + 17) ++#define CLK_GATE_SADC (CLK_ID_GATE + 18) ++#define CLK_GATE_DMIC (CLK_ID_GATE + 19) ++#define CLK_GATE_AIC (CLK_ID_GATE + 20) ++#define CLK_GATE_SMB3 (CLK_ID_GATE + 21) ++#define CLK_GATE_SMB2 (CLK_ID_GATE + 22) ++#define CLK_GATE_SMB1 (CLK_ID_GATE + 23) ++#define CLK_GATE_SMB0 (CLK_ID_GATE + 24) ++#define CLK_GATE_SSI0 (CLK_ID_GATE + 25) ++#define CLK_GATE_MSC1 (CLK_ID_GATE + 26) ++#define CLK_GATE_MSC0 (CLK_ID_GATE + 27) ++#define CLK_GATE_OTG (CLK_ID_GATE + 28) ++#define CLK_GATE_BSCALER (CLK_ID_GATE + 29) ++#define CLK_GATE_EFUSE (CLK_ID_GATE + 30) ++#define CLK_GATE_NEMC (CLK_ID_GATE + 31) ++#define CLK_GATE_CPU (CLK_ID_GATE + 32) ++#define CLK_GATE_APB0 (CLK_ID_GATE + 33) ++#define CLK_GATE_RESERVER13 (CLK_ID_GATE + 34) ++#define CLK_GATE_RESERVER12 (CLK_ID_GATE + 35) ++#define CLK_GATE_OST (CLK_ID_GATE + 36) ++#define CLK_GATE_AHB0 (CLK_ID_GATE + 37) ++#define CLK_GATE_BUS_MONITOR (CLK_ID_GATE + 38) ++#define CLK_GATE_I2D (CLK_ID_GATE + 39) ++#define CLK_GATE_MIPI_DSI (CLK_ID_GATE + 40) ++#define CLK_GATE_DRAWBOX (CLK_ID_GATE + 41) ++#define CLK_GATE_AES (CLK_ID_GATE + 42) ++#define CLK_GATE_GMAC (CLK_ID_GATE + 43) ++#define CLK_GATE_AHB1 (CLK_ID_GATE + 44) ++#define CLK_GATE_IPU (CLK_ID_GATE + 45) ++#define CLK_GATE_DTRNG (CLK_ID_GATE + 46) ++#define CLK_GATE_EL150 (CLK_ID_GATE + 47) ++#define CLK_CE_I2ST (CLK_ID_GATE + 48) ++#define CLK_CE_I2SR (CLK_ID_GATE + 49) ++#define CLK_GATE_USBPHY (CLK_ID_GATE + 50) ++#define CLK_NR_GATE (61) ++#define CLK_ID_OTHER (CLK_ID_GATE + CLK_NR_GATE) ++ ++#define NR_CLKS (CLK_NR_FIXED + CLK_NR_PLL + CLK_NR_MUX + CLK_NR_DIV + CLK_NR_GATE) ++#endif +diff --git a/include/dt-bindings/dma/ingenic-pdma.h b/include/dt-bindings/dma/ingenic-pdma.h +new file mode 100644 +index 000000000..d06583ed3 +--- /dev/null ++++ b/include/dt-bindings/dma/ingenic-pdma.h +@@ -0,0 +1,89 @@ ++#ifndef __INGENIC_PDMA_H__ ++#define __INGENIC_PDMA_H__ ++#include ++ ++#ifndef CONFIG_SOC_X2500 ++#define INGENIC_DMA_REQ_DMIC_RX 0x5 ++#else ++#define INGENIC_DMA_REQ_DMIC_RX 0xd ++#endif ++#define INGENIC_DMA_REQ_I2S_TX 0x6 ++#define INGENIC_DMA_REQ_I2S_RX 0x7 ++#define INGENIC_DMA_REQ_AUTO_TX 0x8 ++#define INGENIC_DMA_REQ_SADC_RX 0x9 ++#define INGENIC_DMA_REQ_UART4_TX 0xc ++#define INGENIC_DMA_REQ_UART4_RX 0xd ++#define INGENIC_DMA_REQ_UART3_TX 0xe ++#define INGENIC_DMA_REQ_UART3_RX 0xf ++#define INGENIC_DMA_REQ_UART2_TX 0x10 ++#define INGENIC_DMA_REQ_UART2_RX 0x11 ++#define INGENIC_DMA_REQ_UART1_TX 0x12 ++#define INGENIC_DMA_REQ_UART1_RX 0x13 ++#define INGENIC_DMA_REQ_UART0_TX 0x14 ++#define INGENIC_DMA_REQ_UART0_RX 0x15 ++#define INGENIC_DMA_REQ_SSI0_TX 0x16 ++#define INGENIC_DMA_REQ_SSI0_RX 0x17 ++#define INGENIC_DMA_REQ_SSI1_TX 0x18 ++#define INGENIC_DMA_REQ_SSI1_RX 0x19 ++#define INGENIC_DMA_REQ_MSC0_TX 0x1a ++#define INGENIC_DMA_REQ_MSC0_RX 0x1b ++#define INGENIC_DMA_REQ_MSC1_TX 0x1c ++#define INGENIC_DMA_REQ_MSC1_RX 0x1d ++#define INGENIC_DMA_REQ_MSC2_TX 0x1e ++#define INGENIC_DMA_REQ_MSC2_RX 0x1f ++#define INGENIC_DMA_REQ_PCM_TX 0X20 ++#define INGENIC_DMA_REQ_PCM_RX 0X21 ++#define INGENIC_DMA_REQ_I2C0_TX 0x24 ++#define INGENIC_DMA_REQ_I2C0_RX 0x25 ++#define INGENIC_DMA_REQ_I2C1_TX 0x26 ++#define INGENIC_DMA_REQ_I2C1_RX 0x27 ++#define INGENIC_DMA_REQ_I2C2_TX 0x28 ++#define INGENIC_DMA_REQ_I2C2_RX 0x29 ++#define INGENIC_DMA_REQ_I2C3_TX 0x2a ++#define INGENIC_DMA_REQ_I2C3_RX 0x2b ++#define INGENIC_DMA_REQ_I2C4_TX 0x2c ++#define INGENIC_DMA_REQ_I2C4_RX 0x2d ++#define INGENIC_DMA_REQ_DES_TX 0x2e ++#define INGENIC_DMA_REQ_DES_RX 0x2f ++ ++ ++/* define for x1600 */ ++ ++#define INGENIC_DMA_REQ_CAN0_TX 0xa ++#define INGENIC_DMA_REQ_CAN0_RX 0xb ++#define INGENIC_DMA_REQ_CAN1_TX 0xc ++#define INGENIC_DMA_REQ_CAN1_RX 0xd ++#define INGENIC_DMA_REQ_SLV0_TX 0x2a ++#define INGENIC_DMA_REQ_SLV0_RX 0x2b ++#define INGENIC_DMA_REQ_PWM0_TX 0x2c ++#define INGENIC_DMA_REQ_PWM1_TX 0x2d ++#define INGENIC_DMA_REQ_PWM2_TX 0x2e ++#define INGENIC_DMA_REQ_PWM3_TX 0x2f ++#define INGENIC_DMA_REQ_PWM4_TX 0x30 ++#define INGENIC_DMA_REQ_PWM5_TX 0x31 ++#define INGENIC_DMA_REQ_PWM6_TX 0x32 ++#define INGENIC_DMA_REQ_PWM7_TX 0x33 ++#define INGENIC_DMA_REQ_ASOC_AIC_LOOP 0x3d ++#define INGENIC_DMA_REQ_ASOC_AIC_TX 0x3e ++#define INGENIC_DMA_REQ_ASOC_AIC_RX 0x3f ++ ++/* define for x2500 */ ++#define INGENIC_DMA_REQ_AIC_LOOP_RX 0x5 ++#define INGENIC_DMA_REQ_AIC_TX 0x6 ++#define INGENIC_DMA_REQ_AIC_F_RX 0x7 ++#define INGENIC_DMA_REQ_SLV_TX 0x1a ++#define INGENIC_DMA_REQ_SLV_RX 0x1b ++ ++#define INGENIC_DMA_TYPE_REQ_MSK 0xff ++#define INGENIC_DMA_TYPE_CH_SFT 8 ++#define INGENIC_DMA_TYPE_CH_MSK (0xff << INGENIC_DMA_TYPE_CH_SFT) ++#define INGENIC_DMA_TYPE_CH_EN (1 << 16) ++#define INGENIC_DMA_TYPE_PROG (1 << 17) ++#define INGENIC_DMA_TYPE_SPEC (1 << 18) ++ ++#define INGENIC_DMA_CH(ch) ((((ch) << INGENIC_DMA_TYPE_CH_SFT) & INGENIC_DMA_TYPE_CH_MSK) | INGENIC_DMA_TYPE_CH_EN) ++#define INGENIC_DMA_TYPE(type) ((type) & INGENIC_DMA_TYPE_REQ_MSK) ++#define INGENIC_DMA_TYPE_CH(type, ch) (INGENIC_DMA_TYPE((type)) | INGENIC_DMA_CH((ch))) ++#define INGENIC_DMA_PG_CH(type, ch) (INGENIC_DMA_TYPE_CH((type), (ch)) | INGENIC_DMA_TYPE_PROG_MSK) ++#define INGENIC_DMA_SP_CH(type, ch) (INGENIC_DMA_PG_CH(type, id) | INGENIC_DMA_TYPE_SPEC_MSK) ++#endif /* __INGENIC_PDMA_H__ */ +diff --git a/include/dt-bindings/gpio/ingenic-gpio.h b/include/dt-bindings/gpio/ingenic-gpio.h +new file mode 100644 +index 000000000..6df94b339 +--- /dev/null ++++ b/include/dt-bindings/gpio/ingenic-gpio.h +@@ -0,0 +1,8 @@ ++#ifndef __INGENIC_GPIO_H_ ++#define __INGENIC_GPIO_H_ ++ ++#define GPIO_VOLTAGE_1V8 1 ++#define GPIO_VOLTAGE_3V3 2 ++ ++#endif ++ +diff --git a/include/dt-bindings/interrupt-controller/m300-irq.h b/include/dt-bindings/interrupt-controller/m300-irq.h +new file mode 100644 +index 000000000..afd5069c6 +--- /dev/null ++++ b/include/dt-bindings/interrupt-controller/m300-irq.h +@@ -0,0 +1,72 @@ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_M300_IRQ_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_M300_IRQ_H ++ ++#include ++ ++#define IRQ_AUDIO (0) ++#define IRQ_OTG (1) ++#define IRQ_RESERVED0_2 (2) ++#define IRQ_PDMA (3) ++#define IRQ_PDMAD (4) ++#define IRQ_PDMAM (5) ++#define IRQ_PWM (6) ++#define IRQ_SFC (7) ++#define IRQ_SSI1 (8) ++#define IRQ_SSI0 (9) ++#define IRQ_MIPI_DSI (10) ++#define IRQ_SADC (11) ++#define IRQ_MIPI_CSI_4 (12) ++#define IRQ_GPIO4 (13) ++#define IRQ_GPIO3 (14) ++#define IRQ_GPIO2 (15) ++#define IRQ_GPIO1 (16) ++#define IRQ_GPIO0 (17) ++#define IRQ_VIC1 (18) ++#define IRQ_VIC0 (19) ++#define IRQ_ISP1 (20) ++#define IRQ_ISP0 (21) ++#define IRQ_HASH (22) ++#define IRQ_AES (23) ++#define IRQ_RSA (24) ++#define IRQ_TCU2 (25) ++#define IRQ_TCU1 (26) ++#define IRQ_TCU0 (27) ++#define IRQ_MIPI_CSI2 (28) ++#define IRQ_ROTATE (29) ++#define IRQ_CIM (30) ++#define IRQ_LCD (31) ++ ++#define IRQ_RTC (32 + 0) ++#define IRQ_SOFT (32 + 1) ++#define IRQ_DTRNG (32 + 2) ++#define IRQ_SCC (32 + 3) ++#define IRQ_MSC1 (32 + 4) ++#define IRQ_MSC0 (32 + 5) ++#define IRQ_UART9 (32 + 6) ++#define IRQ_UART8 (32 + 7) ++#define IRQ_UART7 (32 + 8) ++#define IRQ_UART6 (32 + 9) ++#define IRQ_UART5 (32 + 10) ++#define IRQ_UART4 (32 + 11) ++#define IRQ_UART3 (32 + 12) ++#define IRQ_UART2 (32 + 13) ++#define IRQ_UART1 (32 + 14) ++#define IRQ_UART0 (32 + 15) ++#define IRQ_MSC2 (32 + 16) ++#define IRQ_HARB2 (32 + 17) ++#define IRQ_HARB0 (32 + 18) ++#define IRQ_CPM (32 + 19) ++#define IRQ_DDR (32 + 20) ++#define IRQ_GMAC1 (32 + 21) ++#define IRQ_EFUSE (32 + 22) ++#define IRQ_GMAC0 (32 + 23) ++#define IRQ_I2C5 (32 + 24) ++#define IRQ_I2C4 (32 + 25) ++#define IRQ_I2C3 (32 + 26) ++#define IRQ_I2C2 (32 + 27) ++#define IRQ_I2C1 (32 + 28) ++#define IRQ_I2C0 (32 + 29) ++#define IRQ_HELIX (32 + 30) ++#define IRQ_FELIX (32 + 31) ++ ++#endif +diff --git a/include/dt-bindings/interrupt-controller/mips-irq.h b/include/dt-bindings/interrupt-controller/mips-irq.h +new file mode 100644 +index 000000000..963d38f58 +--- /dev/null ++++ b/include/dt-bindings/interrupt-controller/mips-irq.h +@@ -0,0 +1,16 @@ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_IRQ_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_IRQ_H ++ ++#define MIPS_CPU_IRQ_BASE (0) ++ ++#define CORE_INTC_IRQ (MIPS_CPU_IRQ_BASE + 2) ++#define CORE_MAILBOX_IRQ (MIPS_CPU_IRQ_BASE + 3) ++#define CORE_SYS_OST_IRQ (MIPS_CPU_IRQ_BASE + 4) ++ ++#define CORE_IRQS_END (7) ++ ++#define INTC_NR_IRQS (64) ++#define IRQ_INTC_BASE (CORE_IRQS_END + 1) ++#define IRQ_INTC_END (IRQ_INTC_BASE + INTC_NR_IRQS - 1) ++ ++#endif +diff --git a/include/dt-bindings/interrupt-controller/x1000-irq.h b/include/dt-bindings/interrupt-controller/x1000-irq.h +new file mode 100644 +index 000000000..4cc671674 +--- /dev/null ++++ b/include/dt-bindings/interrupt-controller/x1000-irq.h +@@ -0,0 +1,72 @@ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_X1000_IRQ_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_X1000_IRQ_H ++ ++#include ++ ++#define IRQ_DMIC (0) ++#define IRQ_AIC0 (1) ++#define IRQ_RESERVED0_2 (2) ++#define IRQ_RESERVED0_3 (3) ++#define IRQ_RESERVED0_4 (4) ++#define IRQ_RESERVED0_5 (5) ++#define IRQ_RESERVED0_6 (6) ++#define IRQ_SFC (7) ++#define IRQ_SSI0 (8) ++#define IRQ_RESERVED0_9 (9) ++#define IRQ_PDMA (10) ++#define IRQ_PDMAD (11) ++#define IRQ_RESERVED0_12 (12) ++#define IRQ_RESERVED0_13 (13) ++#define IRQ_GPIO3 (14) ++#define IRQ_GPIO2 (15) ++#define IRQ_GPIO1 (16) ++#define IRQ_GPIO0 (17) ++#define IRQ_RESERVED0_18 (18) ++#define IRQ_RESERVED0_19 (19) ++#define IRQ_RESERVED0_20 (20) ++#define IRQ_OTG (21) ++#define IRQ_RESERVED0_22 (22) ++#define IRQ_AES (23) ++#define IRQ_RESERVED0_24 (24) ++#define IRQ_TCU2 (25) ++#define IRQ_TCU1 (26) ++#define IRQ_TCU0 (27) ++#define IRQ_RESERVED0_28 (28) ++#define IRQ_RESERVED0_29 (29) ++#define IRQ_CIM (30) ++#define IRQ_LCD (31) ++ ++#define IRQ_RTC (32 + 0) ++#define IRQ_RESERVED1_1 (32 + 1) ++#define IRQ_RESERVED1_2 (32 + 2) ++#define IRQ_RESERVED1_3 (32 + 3) ++#define IRQ_MSC1 (32 + 4) ++#define IRQ_MSC0 (32 + 5) ++#define IRQ_SCC (32 + 6) ++#define IRQ_RESERVED1_7 (32 + 7) ++#define IRQ_PCM0 (32 + 8) ++#define IRQ_RESERVED1_9 (32 + 9) ++#define IRQ_RESERVED1_10 (32 + 10) ++#define IRQ_RESERVED1_11 (32 + 11) ++#define IRQ_HARB2 (32 + 12) ++#define IRQ_RESERVED1_13 (32 + 13) ++#define IRQ_HARB0 (32 + 14) ++#define IRQ_CPM (32 + 15) ++#define IRQ_RESERVED1_16 (32 + 16) ++#define IRQ_UART2 (32 + 17) ++#define IRQ_UART1 (32 + 18) ++#define IRQ_UART0 (32 + 19) ++#define IRQ_DDR (32 + 20) ++#define IRQ_RESERVED1_21 (32 + 21) ++#define IRQ_EFUSE (32 + 22) ++#define IRQ_MAC (32 + 23) ++#define IRQ_RESERVED1_24 (32 + 24) ++#define IRQ_RESERVED1_25 (32 + 25) ++#define IRQ_I2C2 (32 + 26) ++#define IRQ_I2C1 (32 + 27) ++#define IRQ_I2C0 (32 + 28) ++#define IRQ_PDMAM (32 + 29) ++#define IRQ_JPEG (32 + 30) ++#define IRQ_RESERVED1_31 (32 + 31) ++ ++#endif +diff --git a/include/dt-bindings/interrupt-controller/x1600-irq.h b/include/dt-bindings/interrupt-controller/x1600-irq.h +new file mode 100644 +index 000000000..2d313dc28 +--- /dev/null ++++ b/include/dt-bindings/interrupt-controller/x1600-irq.h +@@ -0,0 +1,72 @@ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_X1600_IRQ_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_X1600_IRQ_H ++ ++#include ++ ++#define IRQ_AUDIO (0) ++#define IRQ_OTG (1) ++#define IRQ_RESERVED0_2 (2) ++#define IRQ_PDMA (3) ++#define IRQ_PDMAD (4) ++#define IRQ_PDMAM (5) ++#define IRQ_PWM (6) ++#define IRQ_SFC (7) ++#define IRQ_RESERVED0_8 (8) ++#define IRQ_SSI0 (9) ++#define IRQ_RESERVED0_10 (10) ++#define IRQ_SADC (11) ++#define IRQ_RESERVED0_12 (12) ++#define IRQ_RESERVED0_13 (13) ++#define IRQ_GPIO3 (14) ++#define IRQ_GPIO2 (15) ++#define IRQ_GPIO1 (16) ++#define IRQ_GPIO0 (17) ++#define IRQ_RESERVED0_18 (18) ++#define IRQ_RESERVED0_19 (19) ++#define IRQ_RESERVED0_20 (20) ++#define IRQ_RESERVED0_21 (21) ++#define IRQ_HASH (22) ++#define IRQ_AES (23) ++#define IRQ_RESERVED0_14 (24) ++#define IRQ_TCU2 (25) ++#define IRQ_TCU1 (26) ++#define IRQ_TCU0 (27) ++#define IRQ_MIPI_CSI_2 (28) ++#define IRQ_RESERVED0_29 (29) ++#define IRQ_CIM (30) ++#define IRQ_LCD (31) ++ ++#define IRQ_RTC (32 + 0) ++#define IRQ_SOFT (32 + 1) ++#define IRQ_DTRNG (32 + 2) ++#define IRQ_RESERVED1_3 (32 + 3) ++#define IRQ_MSC1 (32 + 4) ++#define IRQ_MSC0 (32 + 5) ++#define IRQ_RESERVED1_6 (32 + 6) ++#define IRQ_RESERVED1_7 (32 + 7) ++#define IRQ_CAN0 (32 + 8) ++#define IRQ_CAN1 (32 + 9) ++#define IRQ_CDBUS (32 + 10) ++#define IRQ_RESERVED1_11 (32 + 11) ++#define IRQ_UART3 (32 + 12) ++#define IRQ_UART2 (32 + 13) ++#define IRQ_UART1 (32 + 14) ++#define IRQ_UART0 (32 + 15) ++#define IRQ_RESERVED1_16 (32 + 16) ++#define IRQ_HARB2 (32 + 17) ++#define IRQ_HARB0 (32 + 18) ++#define IRQ_CPM (32 + 19) ++#define IRQ_DDR (32 + 20) ++#define IRQ_RESERVED1_21 (32 + 21) ++#define IRQ_EFUSE (32 + 22) ++#define IRQ_GMAC0 (32 + 23) ++#define IRQ_RESERVED1_24 (32 + 24) ++#define IRQ_RESERVED1_25 (32 + 25) ++#define IRQ_RESERVED1_26 (32 + 26) ++#define IRQ_RESERVED1_27 (32 + 27) ++#define IRQ_I2C1 (32 + 28) ++#define IRQ_I2C0 (32 + 29) ++#define IRQ_SSI_SLV (32 + 30) ++#define IRQ_RESERVED1_31 (32 + 31) ++ ++#endif +diff --git a/include/dt-bindings/interrupt-controller/x2000-irq.h b/include/dt-bindings/interrupt-controller/x2000-irq.h +new file mode 100644 +index 000000000..ad684f85c +--- /dev/null ++++ b/include/dt-bindings/interrupt-controller/x2000-irq.h +@@ -0,0 +1,72 @@ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_X2000_IRQ_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_X2000_IRQ_H ++ ++#include ++ ++#define IRQ_AUDIO (0) ++#define IRQ_OTG (1) ++#define IRQ_RESERVED0_2 (2) ++#define IRQ_PDMA (3) ++#define IRQ_PDMAD (4) ++#define IRQ_PDMAM (5) ++#define IRQ_PWM (6) ++#define IRQ_SFC (7) ++#define IRQ_SSI1 (8) ++#define IRQ_SSI0 (9) ++#define IRQ_MIPI_DSI (10) ++#define IRQ_SADC (11) ++#define IRQ_MIPI_CSI_4 (12) ++#define IRQ_GPIO4 (13) ++#define IRQ_GPIO3 (14) ++#define IRQ_GPIO2 (15) ++#define IRQ_GPIO1 (16) ++#define IRQ_GPIO0 (17) ++#define IRQ_VIC1 (18) ++#define IRQ_VIC0 (19) ++#define IRQ_ISP1 (20) ++#define IRQ_ISP0 (21) ++#define IRQ_HASH (22) ++#define IRQ_AES (23) ++#define IRQ_RSA (24) ++#define IRQ_TCU2 (25) ++#define IRQ_TCU1 (26) ++#define IRQ_TCU0 (27) ++#define IRQ_MIPI_CSI2 (28) ++#define IRQ_ROTATE (29) ++#define IRQ_CIM (30) ++#define IRQ_LCD (31) ++ ++#define IRQ_RTC (32 + 0) ++#define IRQ_SOFT (32 + 1) ++#define IRQ_DTRNG (32 + 2) ++#define IRQ_SCC (32 + 3) ++#define IRQ_MSC1 (32 + 4) ++#define IRQ_MSC0 (32 + 5) ++#define IRQ_UART9 (32 + 6) ++#define IRQ_UART8 (32 + 7) ++#define IRQ_UART7 (32 + 8) ++#define IRQ_UART6 (32 + 9) ++#define IRQ_UART5 (32 + 10) ++#define IRQ_UART4 (32 + 11) ++#define IRQ_UART3 (32 + 12) ++#define IRQ_UART2 (32 + 13) ++#define IRQ_UART1 (32 + 14) ++#define IRQ_UART0 (32 + 15) ++#define IRQ_MSC2 (32 + 16) ++#define IRQ_HARB2 (32 + 17) ++#define IRQ_HARB0 (32 + 18) ++#define IRQ_CPM (32 + 19) ++#define IRQ_DDR (32 + 20) ++#define IRQ_GMAC1 (32 + 21) ++#define IRQ_EFUSE (32 + 22) ++#define IRQ_GMAC0 (32 + 23) ++#define IRQ_I2C5 (32 + 24) ++#define IRQ_I2C4 (32 + 25) ++#define IRQ_I2C3 (32 + 26) ++#define IRQ_I2C2 (32 + 27) ++#define IRQ_I2C1 (32 + 28) ++#define IRQ_I2C0 (32 + 29) ++#define IRQ_HELIX (32 + 30) ++#define IRQ_FELIX (32 + 31) ++ ++#endif +diff --git a/include/dt-bindings/interrupt-controller/x2500-irq.h b/include/dt-bindings/interrupt-controller/x2500-irq.h +new file mode 100644 +index 000000000..fed7771d6 +--- /dev/null ++++ b/include/dt-bindings/interrupt-controller/x2500-irq.h +@@ -0,0 +1,75 @@ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_X2500_IRQ_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_X2500_IRQ_H ++ ++#include ++ ++#define IRQ_RESERVED0 (0) ++#define IRQ_AIC0 (1) ++#define IRQ_SYS_LEP (2) /* RISC-V */ ++#define IRQ_MIPI_DSI (3) ++#define IRQ_MIPI_RX_4L (4) ++#define IRQ_MIPI_RX_2L (5) ++#define IRQ_IPU (6) ++#define IRQ_SFC (7) ++#define IRQ_SSI1 (8) ++#define IRQ_SSI0 (9) ++#define IRQ_PDMA (10) ++#define IRQ_SSISLV (11) ++#define IRQ_DMIC (12) ++#define IRQ_RESERVED13 (13) ++#define IRQ_GPIO3 (14) ++#define IRQ_GPIO2 (15) ++#define IRQ_GPIO1 (16) ++#define IRQ_GPIO0 (17) ++#define IRQ_GPIO_PORT(N) (IRQ_GPIO0 - (N)) ++#define IRQ_SADC (18) ++#define IRQ_RESERVED19 (19) ++#define IRQ_LCD (20) ++#define IRQ_OTG (21) ++#define IRQ_HASH (22) ++#define IRQ_AES (23) ++#define IRQ_RSA (24) ++#define IRQ_TCU2 (25) ++#define IRQ_TCU1 (26) ++#define IRQ_TCU0 (27) ++#define IRQ_S2_VIC (28) ++#define IRQ_S1_VIC (29) ++#define IRQ_S0_VIC (30) ++#define IRQ_ISP (31) ++ ++#define IRQ_RESERVED32 (32 + 0) ++#define IRQ_RESERVED33 (32 + 1) ++#define IRQ_DTRNG (32 + 2) ++#define IRQ_RESERVED35 (32 + 3) ++#define IRQ_MSC1 (32 + 4) ++#define IRQ_MSC0 (32 + 5) ++#define IRQ_RESERVED38 (32 + 6) ++#define IRQ_BSCALER1 (32 + 7) ++#define IRQ_BSCALER0 (32 + 8) ++#define IRQ_DDR_DWU (32 + 9) ++#define IRQ_DRAW_BOX (32 + 10) ++#define IRQ_VO (32 + 11) ++#define IRQ_HARB2 (32 + 12) ++#define IRQ_I2D (32 + 13) ++#define IRQ_RESERVED46 (32 + 14) ++#define IRQ_CPM (32 + 15) ++#define IRQ_UART3 (32 + 16) ++#define IRQ_UART2 (32 + 17) ++#define IRQ_UART1 (32 + 18) ++#define IRQ_UART0 (32 + 19) ++#define IRQ_DDR (32 + 20) ++#define IRQ_MON (32 + 21) ++#define IRQ_EFUSE (32 + 22) ++#define IRQ_GMAC0 (32 + 23) ++#define IRQ_RESERVED56 (32 + 24) ++#define IRQ_I2C3 (32 + 25) ++#define IRQ_I2C2 (32 + 26) ++#define IRQ_I2C1 (32 + 27) ++#define IRQ_I2C0 (32 + 28) ++#define IRQ_PDMAM (32 + 29) ++#define IRQ_EL150 (32 + 30) ++#define IRQ_RADIX (32 + 31) ++#define IRQ_PCM0 (32 + 32) ++ ++ ++#endif +diff --git a/include/dt-bindings/net/ingenic_gmac.h b/include/dt-bindings/net/ingenic_gmac.h +new file mode 100644 +index 000000000..32207f24e +--- /dev/null ++++ b/include/dt-bindings/net/ingenic_gmac.h +@@ -0,0 +1,9 @@ ++#ifndef __INGENIC_GMAC_H__ ++#define __INGENIC_GMAC_H__ ++ ++#define GMII 0 ++#define RGMII 1 ++#define MII 2 ++#define RMII 4 ++ ++#endif +diff --git a/include/dt-bindings/pinctrl/ingenic-pinctrl.h b/include/dt-bindings/pinctrl/ingenic-pinctrl.h +new file mode 100644 +index 000000000..d574e2326 +--- /dev/null ++++ b/include/dt-bindings/pinctrl/ingenic-pinctrl.h +@@ -0,0 +1,79 @@ ++#ifndef _DT_INGENIC_PINCTL_H__ ++#define _DT_INGENIC_PINCTL_H__ ++#include ++ ++#define PINCTL_FUNCTION0 0 ++#define PINCTL_FUNCTION1 1 ++#define PINCTL_FUNCTION2 2 ++#define PINCTL_FUNCTION3 3 ++#define PINCTL_FUNCHILVL 4 ++#define PINCTL_FUNCLOLVL 5 ++#define PINCTL_FUNCINPUT 6 ++#define PINCTL_FUNCINPUT_LO 7 ++#define PINCTL_FUNCINPUT_HI 8 ++#define PINCTL_FUNCINPUT_FE 9 ++#define PINCTL_FUNCINPUT_RE 10 ++#define PINCTL_FUNCINPUT_RE_FE 11 ++#define PINCTL_FUNCTIONS 12 ++ ++ ++#define PINCTL_CFG_TYPES 1 ++ ++/* Used in device tree for gpio function settings. ingenic,pincfg*/ ++#define PINCTL_CFG_BIAS_DISABLE 1 ++#define PINCTL_CFG_BIAS_HIGH_IMPEDANCE 2 ++#define PINCTL_CFG_BIAS_PULL_DOWN 3 ++#define PINCTL_CFG_BIAS_PULL_PIN_DEFAULT 4 ++#define PINCTL_CFG_BIAS_PULL_UP 5 ++#define PINCTL_CFG_DRIVE_STRENGTH 9 ++#define PINCTL_CFG_FILTER 10 ++#define PINCTL_CFG_INPUT_SCHMITT_ENABLE 11 ++#define PINCTL_CFG_SLEW_RATE 17 ++ ++#define PINCTL_CFG_TYPE_MSK 0xFFFF ++#define PINCTL_CFGVAL_SFT 16 ++#define PINCTL_CFGVAL_MSK (0xFFFF << PINCTL_CFGVAL_SFT) ++ ++#define PINCFG_PACK(type, value) (((value) << PINCTL_CFGVAL_SFT) | type) ++#define PINCFG_UNPACK_TYPE(cfg) ((cfg) & PINCTL_CFG_TYPE_MSK) ++#define PINCFG_UNPACK_VALUE(cfg) (((cfg) & PINCTL_CFGVAL_MSK) >> \ ++ PINCTL_CFGVAL_SFT) ++ ++#define PINCTL_NOBIAS ((0 << PINCTL_CFGVAL_SFT) | PINCTL_CFG_PULL) ++#define PINCTL_PULLEN ((1 << PINCTL_CFGVAL_SFT) | PINCTL_CFG_PULL) ++ ++ ++/* Used in device tree for gpio settings. eg, <&gpb 0, GPIO_ACTIVE_LOW INGENIC_GPIO_PULL_UP | INGENIC_GPIO_DS_0> */ ++#define INGENIC_GPIO_BIAS_MASK 0x7 ++#define INGENIC_GPIO_BIAS_SFT 0 ++#define INGENIC_GPIO_NOBIAS (0 << INGENIC_GPIO_BIAS_SFT) ++#define INGENIC_GPIO_PULLEN (1 << INGENIC_GPIO_BIAS_SFT) ++#define INGENIC_GPIO_PULLUP (2 << INGENIC_GPIO_BIAS_SFT) ++#define INGENIC_GPIO_PULLDOWN (3 << INGENIC_GPIO_BIAS_SFT) ++#define INGENIC_GPIO_HIZ (4 << INGENIC_GPIO_BIAS_SFT) ++ ++#define INGENIC_GPIO_DS_SFT 3 ++#define INGENIC_GPIO_DS_MSK 0x7 ++#define INGENIC_GPIO_DS_0 (0 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_1 (1 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_2 (2 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_3 (3 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_4 (4 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_5 (5 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_6 (6 << INGENIC_GPIO_DS_SFT) ++#define INGENIC_GPIO_DS_7 (7 << INGENIC_GPIO_DS_SFT) ++ ++#define INGENIC_GPIO_SLEW_RATE_SFT 6 ++#define INGENIC_GPIO_SLEW_RATE (1 << INGENIC_GPIO_SLEW_RATE_SFT) ++ ++#define INGENIC_GPIO_SCHMITT_SFT 7 ++#define INGENIC_GPIO_SCHMITT (1 << INGENIC_GPIO_SCHMITT_SFT) ++ ++/* Use in pinctrl drivers.*/ ++#define INGENIC_GPIO_PULL(x) (((x) >> INGENIC_GPIO_BIAS_SFT) & INGENIC_GPIO_BIAS_MASK) ++#define INGENIC_GPIO_DRIVE_STRENGTH(x) (((x) >> INGENIC_GPIO_DS_SFT) & INGENIC_GPIO_DS_MSK) ++#define INGENIC_GPIO_SCHMITT_ENABLE(x) ((x) >> INGENIC_GPIO_SCHMITT_SFT) ++#define INGENIC_GPIO_SLEW_RATE_ENABLE(x) ((x) >> INGENIC_GPIO_SLEW_RATE_SFT) ++ ++ ++#endif /*_DT_INGENIC_PINCTL_H__*/ +diff --git a/include/dt-bindings/power/axp216-power.h b/include/dt-bindings/power/axp216-power.h +new file mode 100644 +index 000000000..fd28e910b +--- /dev/null ++++ b/include/dt-bindings/power/axp216-power.h +@@ -0,0 +1,21 @@ ++#ifndef _DT_BINDINGS_POWER_AXP216_POWER_H ++#define _DT_BINDINGS_POWER_AXP216_POWER_H ++ ++#define AXP216_POWER_DOMAIN_ID_RTC 0 ++#define AXP216_POWER_DOMAIN_ID_ALDO1 1 ++#define AXP216_POWER_DOMAIN_ID_ALDO2 2 ++#define AXP216_POWER_DOMAIN_ID_ALDO3 3 ++#define AXP216_POWER_DOMAIN_ID_ELDO1 4 ++#define AXP216_POWER_DOMAIN_ID_ELDO2 5 ++#define AXP216_POWER_DOMAIN_ID_DCDC1 6 ++#define AXP216_POWER_DOMAIN_ID_DCDC2 7 ++#define AXP216_POWER_DOMAIN_ID_DCDC3 8 ++#define AXP216_POWER_DOMAIN_ID_DCDC4 9 ++#define AXP216_POWER_DOMAIN_ID_DCDC5 10 ++#define AXP216_POWER_DOMAIN_ID_LDOIO1 11 ++#define AXP216_POWER_DOMAIN_ID_SUPPLY 12 ++#define AXP216_POWER_DOMAIN_ID_GPIO 13 ++ ++#define POWER_SUPPLY_TECHNOLOGY_LION 2 ++ ++#endif /* _DT_BINDINGS_POWER_AXP216_POWER_H */ +diff --git a/include/dt-bindings/sound/ingenic-baic.h b/include/dt-bindings/sound/ingenic-baic.h +new file mode 100644 +index 000000000..b33d9bffd +--- /dev/null ++++ b/include/dt-bindings/sound/ingenic-baic.h +@@ -0,0 +1,34 @@ ++#ifndef __INGENIC_BAIC_H__ ++#define __INGENIC_BAIC_H__ ++ ++#undef BIT ++#define BIT(n) (1 << (n)) ++#define BAIC_DAIFMT_NO_GRP (0x0 << 0) ++#define BAIC_DAIFMT_I2S_GRP (0x1 << 0) ++#define BAIC_DAIFMT_DSP_GRP (0x2 << 0) ++#define BAIC_DAIFMT_GRP_MSK (0x3 << 0) ++#define BAIC_DAIFMT_MODEA (BIT(0) << 2) /*dsp grp*/ ++#define BAIC_DAIFMT_MODEB (BIT(1) << 2) ++#define BAIC_DAIFMT_PCM (BIT(0) << 4) ++#define BAIC_DAIFMT_DSP (BIT(1) << 4) ++#define BAIC_DAIFMT_TDM2 (BIT(2) << 4) ++#define BAIC_DAIFMT_TDM1 (BIT(3) << 4) ++#define BAIC_DAIFMT_I2S (BIT(4) << 4) /*i2s grp*/ ++#define BAIC_DAIFMT_RIGHTJ (BIT(5) << 4) ++#define BAIC_DAIFMT_LEFTJ (BIT(6) << 4) ++ ++#define BAIC_NO_REPLAY (BIT(7) << 4) /*just support replay or record*/ ++#define BAIC_NO_RECORD (BIT(8) << 4) ++ ++#define BAIC_PCM_MODE (BAIC_DAIFMT_PCM|BAIC_DAIFMT_DSP_GRP|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_MODEB) ++#define BAIC_DSP_MODE (BAIC_DAIFMT_DSP|BAIC_DAIFMT_DSP_GRP|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_MODEB) ++#define BAIC_TDM1_MODE (BAIC_DAIFMT_TDM1|BAIC_DAIFMT_DSP_GRP|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_MODEB) ++#define BAIC_TDM2_MODE (BAIC_DAIFMT_TDM2|BAIC_DAIFMT_DSP_GRP|BAIC_DAIFMT_MODEA|BAIC_DAIFMT_MODEB) ++#define BAIC_I2S_MODE (BAIC_DAIFMT_I2S|BAIC_DAIFMT_RIGHTJ|BAIC_DAIFMT_LEFTJ|BAIC_DAIFMT_I2S_GRP) ++ ++#define BAIC_2AND(x,y) ((x) | (y)) ++#define BAIC_3AND(x,y,z) ((x) | (y) | (z)) ++#define BAIC_4AND(x,y,z,m) ((x) | (y) | (z) | (m)) ++#define BAIC_5AND(x,y,z,m,n) ((x) | (y) | (z) | (m) | (n)) ++ ++#endif /*__INGENIC_BAIC_H__*/ +diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h +index a5f89fc4d..9d48ccfb9 100644 +--- a/include/linux/dma-map-ops.h ++++ b/include/linux/dma-map-ops.h +@@ -167,13 +167,13 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, + dma_addr_t device_addr, size_t size); + int dma_alloc_from_dev_coherent(struct device *dev, ssize_t size, + dma_addr_t *dma_handle, void **ret); +-int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr); ++int dma_release_from_dev_coherent(struct device *dev, ssize_t size, void *vaddr); + int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, size_t size, int *ret); + + void *dma_alloc_from_global_coherent(struct device *dev, ssize_t size, + dma_addr_t *dma_handle); +-int dma_release_from_global_coherent(int order, void *vaddr); ++int dma_release_from_global_coherent(ssize_t size, void *vaddr); + int dma_mmap_from_global_coherent(struct vm_area_struct *vma, void *cpu_addr, + size_t size, int *ret); + +@@ -184,7 +184,7 @@ static inline int dma_declare_coherent_memory(struct device *dev, + return -ENOSYS; + } + #define dma_alloc_from_dev_coherent(dev, size, handle, ret) (0) +-#define dma_release_from_dev_coherent(dev, order, vaddr) (0) ++#define dma_release_from_dev_coherent(dev, size, vaddr) (0) + #define dma_mmap_from_dev_coherent(dev, vma, vaddr, order, ret) (0) + + static inline void *dma_alloc_from_global_coherent(struct device *dev, +@@ -192,7 +192,7 @@ static inline void *dma_alloc_from_global_coherent(struct device *dev, + { + return NULL; + } +-static inline int dma_release_from_global_coherent(int order, void *vaddr) ++static inline int dma_release_from_global_coherent(ssize_t size, void *vaddr) + { + return 0; + } +diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h +index dd357a747..8d0993f7d 100644 +--- a/include/linux/dmaengine.h ++++ b/include/linux/dmaengine.h +@@ -876,6 +876,14 @@ struct dma_device { + int (*device_alloc_chan_resources)(struct dma_chan *chan); + void (*device_free_chan_resources)(struct dma_chan *chan); + ++ /* Legacy Interface For ingenic chips. New DMA Driver should never use.*/ ++ struct dma_async_tx_descriptor *(*device_add_desc)( ++ struct dma_chan *chan, dma_addr_t src,dma_addr_t dst, ++ unsigned cnt,enum dma_transfer_direction direction,int flag); ++ dma_addr_t (*get_current_trans_addr)( ++ struct dma_chan *chan,dma_addr_t *dst_addr, ++ dma_addr_t *src_addr,enum dma_transfer_direction direction); ++ + struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)( + struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, + size_t len, unsigned long flags); +diff --git a/include/linux/mfd/ingenic-tcu_v1.h b/include/linux/mfd/ingenic-tcu_v1.h +new file mode 100644 +index 000000000..bd8ff03e2 +--- /dev/null ++++ b/include/linux/mfd/ingenic-tcu_v1.h +@@ -0,0 +1,202 @@ ++#ifndef __INGENIC_TCU_H__ ++#define __INGENIC_TCU_H__ ++ ++#include ++ ++#define NR_TCU_CHNS TCU_NR_IRQS ++ ++enum irq_bit { ++ FULL_BIT, ++ HALF_BIT, ++}; ++enum tcu_prescale { ++ TCU_PRESCALE_1, ++ TCU_PRESCALE_4, ++ TCU_PRESCALE_16, ++ TCU_PRESCALE_64, ++ TCU_PRESCALE_256, ++ TCU_PRESCALE_1024 ++}; ++ ++enum tcu_clksrc { ++ TCU_CLKSRC_PCK = 1, ++ TCU_CLKSRC_RTC = 2, ++ TCU_CLKSRC_EXT = 4 ++}; ++ ++enum tcu_irq_type { ++ NULL_IRQ_MODE, ++ FULL_IRQ_MODE, ++ HALF_IRQ_MODE, ++ FULL_HALF_IRQ_MODE, ++}; ++ ++struct info_bits { ++ unsigned int id:CHANNEL_BASE_OFF*2; ++ unsigned int mode:CHANNEL_BASE_OFF; ++ unsigned int func:CHANNEL_BASE_OFF; ++ unsigned int pwmin:CHANNEL_BASE_OFF; ++}; ++ ++struct ingenic_tcu_chn { ++ union { ++ unsigned int chn_info; ++ struct info_bits cib; ++ }; ++ unsigned int index; ++ char virq[2]; ++ char irq_type; ++ char clk_src; ++ ++ char clk_div; ++ char init_level; ++ char shutdown_mode; ++ char pwm_bapass_mode; ++ ++ char is_pwm; ++ char is_count_clear; ++ char pwm_in_en; ++ char work_sleep; ++ ++ int half_num; ++ int full_num; ++ struct device_node *np; ++ void (*enable)(int id); ++ void (*disable)(int id); ++}; ++ ++void tcu_start_counter(int id); ++void tcu_stop_counter(int id); ++void tcu_set_counter(int id, unsigned int val); ++int tcu_get_counter(int id); ++void tcu_enable_counter(int id); ++void tcu_disable_counter(int id); ++ ++/** ++ * ingenic_tcu_set_full_num - set the number of tcu Timer Data FULL Register (TDFR) ++ * ++ * @id: tcu channel id. ++ * @full_num: the number of set TDFR. ++ * ++ */ ++void ingenic_tcu_set_period(int id, uint16_t period); ++/** ++ * ingenic_tcu_set_half_num - set the number of tcu Timer Data FULL Register (TDHR) ++ * ++ * @id: tcu channel id. ++ * @half_num: the number of set TDFR. ++ * ++ */ ++void ingenic_tcu_set_duty(int id, uint16_t duty); ++/** ++ * ingenic_tcu_set_prescale - set clk div of TCU prescale. ++ * Don‘t call the function when the channel is running. ++ * ++ * @id: tcu channel id. ++ * @prescale: the div of clk value. ++ * ++ */ ++void ingenic_tcu_set_prescale(int id, enum tcu_prescale prescale); ++/** ++ * ingenic_tcu_set_pwm_output_init_level - set an initial output level for PWM output. ++ * ++ * @id: tcu channel id. ++ * @level: 0 LOW, 1 HIGH. ++ * ++ */ ++void ingenic_tcu_set_pwm_output_init_level(int id, int level); ++/** ++ * ingenic_tcu_set_clksrc - set clk soruce of the timer clock input. ++ * Don‘t call the function when the channel is running. ++ * ++ * @id: tcu channel id. ++ * @src: the clk source;0 PCLK, 1 RTC, 2 EXT. ++ * ++ */ ++void ingenic_tcu_set_clksrc(int id, enum tcu_clksrc src); ++/** ++ * ingenic_tcu_channel_to_virq - get virtual irq though to tcu channel id ++ * (channel 0 ~ 4, 6 ~ 7 use common hardware irq(TCU2)) ++ * ++ * @tcu_chn: the struct of request cell(TCU channel). ++ * ++ * Search for a virq in a irq domain and save irq to struct ingenic_tcu_chn ++ * ->virq[2]. ++ */ ++void ingenic_tcu_channel_to_virq(struct ingenic_tcu_chn *tcu_chn); ++/** ++ * ingenic_tcu_get_count - get the value of the timer counter (TCNT). ++ * ++ * @id: tcu channel id. ++ * ++ * Returns number of timer counter on sucess, ++ * -EINVAL if The value read from counter 1 or 2 is a false value. ++ * ++ */ ++int ingenic_tcu_get_count(int id); ++/** ++ * ingenic_tcu_config - init the current channel struct. ++ * ++ * @tcu_chn: tcu channel struct. ++ * ++ * Returns 0 on sucess, ++ * Returns < 0 if init failed. ++ * ++ */ ++int ingenic_tcu_config(struct ingenic_tcu_chn *tcu_chn); ++/** ++ * ingenic_tcu_counter_begin - begin counting up, if channel function is pwm, enable pwm. ++ * ++ * @tcu_chn: tcu channel struct. ++ * ++ */ ++int ingenic_tcu_counter_begin(struct ingenic_tcu_chn *tcu_chn); ++/** ++ * ingenic_tcu_counter_stop - stop counting up, if channel function is pwm, disable pwm. ++ * ++ * @tcu_chn: tcu channel struct. ++ * ++ * Explain: ++ * TCU count stop, is the next stop after match, not immediately stop. ++ * If you want to stop immediately, you can use cell->disable. ++ * ++ */ ++void ingenic_tcu_counter_stop(struct ingenic_tcu_chn *tcu_chn); ++ ++/** ++ * ingenic_watchdog_set_count - setwatchdog timer counter. ++ * This function is only used for watchdog. ++ * ++ * @value: the number of set watchdog counter. ++ * ++ */ ++void ingenic_watchdog_set_count(unsigned int value); ++/** ++ * ingenic_watchdog_config - init watchdog. ++ * This function is only used for watchdog. ++ * ++ * @tcsr_val: the number of set watchdog TCSR. ++ * @timeout_value: the number of set watchdog TCNT. ++ * ++ */ ++void ingenic_watchdog_config(unsigned int tcsr_val, unsigned int timeout_value); ++ ++/** ++ * request_cell - request tcu channel cell. ++ * ++ * @id: tcu channel id. ++ * ++ * Returns struct cell on sucess, ++ * NULL if The channel busy. ++ * ++ */ ++struct mfd_cell *request_cell(int id); ++/** ++ * free_cell - free tcu channel cell. ++ * ++ * @id: tcu channel id. ++ * ++ */ ++void free_cell(int id); ++ ++#endif /* __INGENIC_TCU_H__ */ +diff --git a/include/linux/mfd/ingenic-tcu_v2.h b/include/linux/mfd/ingenic-tcu_v2.h +new file mode 100644 +index 000000000..a342b0d99 +--- /dev/null ++++ b/include/linux/mfd/ingenic-tcu_v2.h +@@ -0,0 +1,383 @@ ++#ifndef __INGENIC_TCU_H__ ++#define __INGENIC_TCU_H__ ++ ++#define CHN_TDFR (0x0) /*channel N data full register*/ ++#define CHN_TDHR (0x4) /*channel N data half register*/ ++#define CHN_TCNT (0x8) /*channel N counter register*/ ++#define CHN_TCSR (0xc) /*channel N control register*/ ++ ++#define TCU_TSR (0x1C) /* Timer Stop Register */ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++#define TCU_TER (0x10) /* Timer Counter Enable Register */ ++#define TCU_TESR (0x14) /* Timer Counter Enable Set Register */ ++#define TCU_TECR (0x18) /* Timer Counter Enable Clear Register */ ++#define TCU_TFR (0x20) /* Timer Flag Register */ ++#define TCU_TFSR (0x24) /* Timer Flag Set Register */ ++#define TCU_TFCR (0x28) /* Timer Flag Clear Register */ ++#define TCU_TMR (0x30) /* Timer Mask Register */ ++#define TCU_TMSR (0x34) /* Timer Mask Set Register */ ++#define TCU_TMCR (0x38) /* Timer Mask Clear Register */ ++#define TCU_STORE_FLAG (0x200) ++#define TCU_STORE_FLAG_SET (0x204) ++#define TCU_STORE_FLAG_CLR (0x208) ++#define TCU_STORE_MASK_RD (0x210) ++#define TCU_STORE_MASK_SET (0x214) ++#define TCU_STORE_MASK_CLR (0x218) ++ ++#define CH_TDFR(n) (0x40 + (n)*0x10) /* Timer Data Full Reg */ ++#define CH_TDHR(n) (0x44 + (n)*0x10) /* Timer Data Half Reg */ ++#define CH_TCNT(n) (0x48 + (n)*0x10) /* Timer Counter Reg */ ++#define CH_TCSR(n) (0x4C + (n)*0x10) /* Timer Control Reg */ ++ ++#define CHN_CAP(n) (0xc0 + (n)*0x04) /*Capture register*/ ++#define CHN_CAP_VAL(n) (0xe0 + (n)*0x04) /*Capture Value register*/ ++#define CHN_FIL_VAL(n) (0x1a0 + (n)*0x04) /*filter value*/ ++ ++#define TCU_STORE_VAL(n) (0x220 + (n)*0x04) ++#define TCU_STORE_FIL_VAL(n) (0x240 + (n)*0x04) ++ ++//OST control ++#define TER_OSTEN (1 << 15) /* enable the counter in ost */ ++#define TMR_OSTM (1 << 15) /* ost comparison match interrupt mask */ ++#define TFR_OSTF (1 << 15) /* ost interrupt flag */ ++#define TSR_OSTS (1 << 15) /*the clock supplies to osts is stopped */ ++ ++//watchdog bit ++#define TSR_WDTS (1 << 16) /*the clock supplies to wdt is stopped */ ++#define TCU_FLAG_RD (1 << 24) /*HALF comparison match flag of WDT. (TCNT = TDHR) */ ++ ++//timer control Register bit operation ++#define CSR_EXT_EN (1 << 2) /* select extal as the timer clock input */ ++#define CSR_DIV1 (0x0 << 3) /*select the TCNT count clock frequency*/ ++#define CSR_DIV4 (0x1 << 3) ++#define CSR_DIV16 (0x2 << 3) ++#define CSR_DIV64 (0x3 << 3) ++#define CSR_DIV256 (0x4 << 3) ++#define CSR_DIV1024 (0x5 << 3) ++#define CSR_DIV_MSK (0x7 << 3) ++ ++#define CSR_DIR_HIGH (0x0 << 8) /*0:direction signal hold on 1*/ ++#define CSR_DIR_CLK (0x1 << 8) /*1:use clock with direction signal*/ ++#define CSR_DIR_GPIO0 (0x2 << 8) /*2:use gpio0 with direction signal*/ ++#define CSR_DIR_GPIO1 (0x3 << 8) /*3:use gpio1 with direction signal*/ ++#define CSR_DIR_QUADRATURE (0x4 << 8) /*4:use gpio0 and gpio1 quadrature result with direction signal*/ ++#define CSR_DIR_MSK (0x7 << 8) ++ ++#define CSR_GATE_LOW (0x0 << 11) /*0:gate signal hold on 0*/ ++#define CSR_GATE_CLK (0x1 << 11) /*1:use clock with gate signal*/ ++#define CSR_GATE_GPIO0 (0x2 << 11) /*2:use gpio0 with gate signal*/ ++#define CSR_GATE_GPIO1 (0x3 << 11) /*3:use gpio1 with gate signal*/ ++#define CSR_GATE_MSK (0x3 << 11) ++ ++#define CLK_POS (16) ++#define CLK_NEG (17) ++#define GPIO0_POS (18) ++#define GPIO0_NEG (19) ++#define GPIO1_POS (20) ++#define GPIO1_NEG (21) ++#define STORE_EN (24) ++#define STORE_POS_EN (25) ++#define STORE_NEG_EN (26) ++ ++ ++#define CSR_CM_FCZ (0x0 << 22) /*count range 0 <-> full with clear to 0*/ ++#define CSR_CM_MCZ (0x1 << 22) /*count range 0 <-> 0xffff with clear to 0*/ ++#define CSR_CM_MH (0x2 << 22) /*count range 0 <-> 0xffff with hold on*/ ++#define CSR_CM_MSK (0x3 << 22) ++ ++#define TCU_CONTROL_BIT(n) (1 << n) ++ ++//Capture register bit operation ++#define CAP_SEL_CLK (0x0 << 16) /*TCU will capture clock*/ ++#define CAP_SEL_GPIO0 (0x1 << 16) /*TCU will capture gpio0*/ ++#define CAP_SEL_GPIO1 (0x2 << 16) /*TCU will capture gpio1*/ ++/*if capture mode is disable then these bits will:*/ ++#define CAP_SEL_CCG0P (0x1 << 16) /*counter will clear when gpio0 posedge*/ ++#define CAP_SEL_CCG1P (0x2 << 16) /*counter will clear when gpio1 posedge*/ ++#define CAP_SEL_MSK (0x7 << 16) ++#define CAP_NUM_MSK (0xff) ++ ++//filter value register bit operation ++#define FIL_VAL_GPIO1_MSK (0x3ff << 16) /*Gpio1 filter counter value*/ ++#define FIL_VAL_GPIO0_MSK (0x3ff) /*Gpio0 filter counter value*/ ++ ++//Common 1 bit offset ++#define ONE_BIT_OFFSET(n) TCU_CONTROL_BIT(n) ++ ++ ++#define timeout (500) ++#define CAPTURE_LOOP_FLAGS (0x1 << 7) ++ ++#define TCU_CHN_TDFR (0x0) ++#define TCU_CHN_TDHR (0x4) ++#define TCU_CHN_TCNT (0x8) ++#define TCU_CHN_TCSR (0xc) ++#define TCU_FULL0 (0x40) ++#define TCU_CHN_OFFSET (0x10) ++ ++ ++#define tcu_readl(tcu,reg) \ ++ __raw_readl((tcu)->iomem + reg) ++#define tcu_writel(tcu,reg,value) \ ++ __raw_writel((value), (tcu)->iomem + reg) ++ ++#define tcu_chn_readl(tcu_chn,reg) \ ++ __raw_readl((tcu_chn)->tcu->iomem + (tcu_chn)->reg_base + reg) ++#define tcu_chn_writel(tcu_chn,reg,value) \ ++ __raw_writel((value), (tcu_chn)->tcu->iomem + (tcu_chn)->reg_base + reg) ++ ++enum tcu_prescale { ++ TCU_PRESCALE_1, ++ TCU_PRESCALE_4, ++ TCU_PRESCALE_16, ++ TCU_PRESCALE_64, ++ TCU_PRESCALE_256, ++ TCU_PRESCALE_1024 ++}; ++ ++enum tcu_irq_type { ++ NULL_IRQ_MODE, ++ FULL_IRQ_MODE, ++ HALF_IRQ_MODE, ++ FULL_HALF_IRQ_MODE, ++}; ++ ++enum tcu_clksrc { ++ TCU_CLKSRC_NULL, ++ TCU_CLKSRC_EXT = ONE_BIT_OFFSET(2), ++ TCU_CLKSRC_GPIO0 = ONE_BIT_OFFSET(6), ++ TCU_CLKSRC_GPIO1 = ONE_BIT_OFFSET(7) ++}; ++ ++enum tcu_count_mode{ ++ COUNT_MODE_FCZ, ++ COUNT_MODE_MCZ, ++ COUNT_MODE_MH ++}; ++ ++enum tcu_gate_sel{ ++ GATE_SEL_HZ, ++ GATE_SEL_CLK, ++ GATE_SEL_GPIO0, ++ GATE_SEL_GPIO1 ++}; ++ ++enum tcu_gate_pola{ ++ GATE_POLA_LOW, ++ GATE_POLA_HIGH ++}; ++ ++enum tcu_dir_sel{ ++ DIR_SEL_HH, ++ DIR_SEL_CLK, ++ DIR_SEL_GPIO0, ++ DIR_SEL_GPIO1, ++ DIR_SEL_GPIO_QUA ++}; ++ ++enum tcu_dir_pola{ ++ DIR_POLA_LOW, ++ DIR_POLA_HIGH ++}; ++ ++enum tcu_mode_sel{ ++ GENERAL_MODE, ++ GATE_MODE, ++ DIRECTION_MODE, ++ QUADRATURE_MODE, ++ POS_MODE, ++ CAPTURE_MODE, ++ FILTER_MODE ++}; ++ ++enum tcu_pos_sel{ ++ GPIO0_POS_CLR = 1, ++ GPIO1_POS_CLR, ++ GPIO0_NEG_CLR ++}; ++ ++enum tcu_capture_sel{ ++ CAPTURE_CLK, ++ CAPTURE_GPIO0, ++ CAPTURE_GPIO1 ++}; ++ ++enum signal_pos_neg{ ++ SIG_INIT, ++ SIG_NEG_EN, ++ SIG_POS_EN, ++ SIG_POS_NEG_EN ++}; ++ ++struct ingenic_tcu { ++ void __iomem *iomem; ++ struct resource *res; ++ struct clk *clk; ++ int irq; ++ int irq_trigger; ++ int irq_base; ++ spinlock_t lock; ++}; ++ ++ ++struct ingenic_tcu_chn { ++ int index; /* Channel number */ ++ int id; /* Channel number */ ++ int en_flag; ++ u32 reg_base; ++ void __iomem *iomem; ++ int using; ++ ++ enum tcu_irq_type irq_type; ++ enum tcu_clksrc clk_ext,clk_gpio0,clk_gpio1; ++ enum tcu_prescale prescale; ++ enum tcu_count_mode count_mode; ++ enum tcu_gate_sel gate_sel; ++ enum tcu_gate_pola gate_pola; ++ enum tcu_dir_sel dir_sel; ++ enum tcu_dir_pola dir_pola; ++ enum tcu_mode_sel mode_sel; ++ enum signal_pos_neg sig_ext,sig_gpio0,sig_gpio1; ++ enum tcu_pos_sel pos_sel; ++ enum tcu_capture_sel capture_sel; ++ ++ int capture_num; ++ int half_num; ++ int full_num; ++ int fil_a_num; ++ int fil_b_num; ++ int count_value; ++ unsigned int divi_ratio; /* 0/1/2/3/4/5/something else------>1/4/16/64/256/1024/mask */ ++ int shutdown_mode; ++ struct ingenic_tcu *tcu; ++ bool gpio_trigger; ++}; ++static inline void ingenic_tcu_enable_counter(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TESR, 1 << tcu_chn->index); ++} ++ ++static inline int ingenic_tcu_disable_counter(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TECR, 1 << tcu_chn->index); ++ return 1; ++} ++ ++static inline void ingenic_tcu_start_counter(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TSCR, 1 << tcu_chn->index); ++} ++ ++static inline void ingenic_tcu_stop_counter(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TSSR, 1 << tcu_chn->index); ++} ++ ++static inline void ingenic_tcu_set_count(struct ingenic_tcu_chn *tcu_chn, u16 cnt) ++{ ++ tcu_chn_writel(tcu_chn, CHN_TCNT, cnt); ++} ++ ++static inline unsigned long ingenic_tcu_flag_st(struct ingenic_tcu_chn *tcu_chn) ++{ ++ return tcu_readl(tcu_chn->tcu, TCU_TFR); ++} ++ ++static inline int ingenic_tcu_get_count(struct ingenic_tcu_chn *tcu_chn) ++{ ++ return tcu_chn_readl(tcu_chn, CHN_TCNT); ++} ++ ++static inline int ingenic_tcu_get_cap_val(struct ingenic_tcu_chn *tcu_chn) ++{ ++ return tcu_readl(tcu_chn->tcu,CHN_CAP_VAL(tcu_chn->index)); ++} ++ ++static inline unsigned int ingenic_tcu_store_flag_st(struct ingenic_tcu *tcu) ++{ ++ return tcu_readl(tcu, TCU_STORE_FLAG); ++} ++ ++static inline void ingenic_tcu_store_flag_clr(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_STORE_FLAG_CLR, 1 << tcu_chn->index); ++} ++ ++static inline void ingenic_tcu_store_flag_set(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_STORE_FLAG_SET, 1 << tcu_chn->index); ++} ++ ++static inline unsigned int ingenic_tcu_store_mask_val(struct ingenic_tcu *tcu) ++{ ++ return tcu_readl(tcu, TCU_STORE_MASK_RD); ++} ++ ++static inline void ingenic_tcu_store_mask_clr(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_STORE_MASK_CLR, 1 << tcu_chn->index); ++} ++ ++static inline void ingenic_tcu_store_mask_set(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_STORE_MASK_SET, 1 << tcu_chn->index); ++} ++ ++static inline unsigned int ingenic_tcu_store_val(struct ingenic_tcu_chn *tcu_chn) ++{ ++ return tcu_readl(tcu_chn->tcu, TCU_STORE_VAL(tcu_chn->index)); ++} ++ ++static inline void ingenic_tcu_store_set_filter(struct ingenic_tcu_chn *tcu_chn, ++ unsigned int val) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_STORE_FIL_VAL(tcu_chn->index), val & 0x3ff); ++} ++ ++static inline void ingenic_tcu_store_enable(struct ingenic_tcu_chn *tcu_chn) ++{ ++ unsigned int tmp; ++ tmp = tcu_chn_readl(tcu_chn, CHN_TCSR); ++ tcu_chn_writel(tcu_chn, CHN_TCSR, (1 << STORE_EN) | tmp); ++} ++ ++static inline void ingenic_tcu_store_disable(struct ingenic_tcu_chn *tcu_chn) ++{ ++ unsigned int tmp; ++ tmp = tcu_chn_readl(tcu_chn, CHN_TCSR); ++ tcu_chn_writel(tcu_chn, CHN_TCSR, ~(1 << STORE_EN) & tmp); ++} ++ ++static inline void ingenic_tcu_store_neg_enable(struct ingenic_tcu_chn *tcu_chn) ++{ ++ unsigned int tmp; ++ tmp = tcu_readl(tcu_chn->tcu, CH_TCSR(tcu_chn->index)); ++ tcu_writel(tcu_chn->tcu, CH_TCSR(tcu_chn->index), (1 << STORE_NEG_EN) | tmp); ++} ++ ++static inline void ingenic_tcu_store_neg_disable(struct ingenic_tcu_chn *tcu_chn) ++{ ++ unsigned int tmp; ++ tmp = tcu_readl(tcu_chn->tcu, CH_TCSR(tcu_chn->index)); ++ tcu_writel(tcu_chn->tcu, CH_TCSR(tcu_chn->index), ~(1 << STORE_NEG_EN) | tmp); ++} ++ ++static inline void ingenic_tcu_store_pos_enable(struct ingenic_tcu_chn *tcu_chn) ++{ ++ unsigned int tmp; ++ tmp = tcu_readl(tcu_chn->tcu, CH_TCSR(tcu_chn->index)); ++ tcu_writel(tcu_chn->tcu, CH_TCSR(tcu_chn->index), (1 << STORE_POS_EN) | tmp); ++} ++ ++static inline void ingenic_tcu_store_pos_disable(struct ingenic_tcu_chn *tcu_chn) ++{ ++ unsigned int tmp; ++ tmp = tcu_readl(tcu_chn->tcu, CH_TCSR(tcu_chn->index)); ++ tcu_writel(tcu_chn->tcu, CH_TCSR(tcu_chn->index), ~(1 << STORE_POS_EN) | tmp); ++} ++ ++void sws_pr_debug(struct ingenic_tcu_chn *tcu_chn); ++void ingenic_tcu_config_chn(struct ingenic_tcu_chn *tcu_chn); ++void ingenic_tcu_clear_irq_flag(struct ingenic_tcu_chn *tcu_chn); ++#endif /* __ingenic_TCU_H__ */ +diff --git a/include/linux/mfd/ingenic_adc.h b/include/linux/mfd/ingenic_adc.h +new file mode 100644 +index 000000000..ec652f1fe +--- /dev/null ++++ b/include/linux/mfd/ingenic_adc.h +@@ -0,0 +1,317 @@ ++#ifndef __LINUX_INGENIC_ADC_H__ ++#define __LINUX_INGENIC_ADC_H__ ++ ++#include ++ ++/* ++ * SAR A/D Controller(SADC) address definition ++ */ ++#define SADC_BASE 0xb0070000 ++ ++/************************************************************************* ++ * SADC (Smart A/D Controller) ++ *************************************************************************/ ++#define BIT0 (1 << 0) ++#define BIT1 (1 << 1) ++#define BIT2 (1 << 2) ++#define BIT3 (1 << 3) ++#define BIT4 (1 << 4) ++#define BIT5 (1 << 5) ++#define BIT6 (1 << 6) ++#define BIT7 (1 << 7) ++#define BIT8 (1 << 8) ++#define BIT9 (1 << 9) ++#define BIT10 (1 << 10) ++#define BIT11 (1 << 11) ++#define BIT12 (1 << 12) ++#define BIT13 (1 << 13) ++#define BIT14 (1 << 14) ++#define BIT15 (1 << 15) ++#define BIT16 (1 << 16) ++#define BIT17 (1 << 17) ++#define BIT18 (1 << 18) ++#define BIT19 (1 << 19) ++#define BIT20 (1 << 20) ++#define BIT21 (1 << 21) ++#define BIT22 (1 << 22) ++#define BIT23 (1 << 23) ++#define BIT24 (1 << 24) ++#define BIT25 (1 << 25) ++#define BIT26 (1 << 26) ++#define BIT27 (1 << 27) ++#define BIT28 (1 << 28) ++#define BIT29 (1 << 29) ++#define BIT30 (1 << 30) ++#define BIT31 (1 << 31) ++ ++ ++ ++ ++ ++#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */ ++#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */ ++#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */ ++#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/ ++#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */ ++#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */ ++#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */ ++#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC VBAT Data Register */ ++#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC AUX Data Register */ ++#define SADC_FLT (SADC_BASE + 0x24) /* ADC Filter Register */ ++ ++#define REG_SADC_ENA REG8(SADC_ENA) ++#define REG_SADC_CFG REG32(SADC_CFG) ++#define REG_SADC_CTRL REG8(SADC_CTRL) ++#define REG_SADC_STATE REG8(SADC_STATE) ++#define REG_SADC_SAMETIME REG16(SADC_SAMETIME) ++#define REG_SADC_WAITTIME REG16(SADC_WAITTIME) ++#define REG_SADC_TSDAT REG32(SADC_TSDAT) ++#define REG_SADC_BATDAT REG16(SADC_BATDAT) ++#define REG_SADC_SADDAT REG16(SADC_SADDAT) ++#define REG_SADC_ADCLK REG32(SADC_ADCLK) ++#define REG_SADC_FLT REG16(SADC_FLT) ++ #define SADC_FLT_ENA (1 << 15) ++ ++/* ADENA: ADC Enable Register */ ++#define SADC_ENA_POWER (1 << 7) /* SADC Power control bit */ ++#define SADC_ENA_SLP_MD (1 << 6) /* SLEEP mode control */ ++#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ ++#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ ++#define SADC_ENA_SADCINEN (1 << 0) /* AUX n Enable */ ++ ++/* ADC Configure Register */ ++#define SADC_CFG_SPZZ (1 << 31) ++#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ ++#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ ++#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) ++ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) ++#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ ++#define SADC_CFG_SNUM(x) (((x) - 1) << SADC_CFG_SNUM_BIT) ++#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) ++ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) ++#define SADC_CFG_CMD_BIT 0 /* ADC Command */ ++#define SADC_CFG_CMD_MASK (0x3 << SADC_CFG_CMD_BIT) ++ #define SADC_CFG_CMD_AUX0 (0x0 << SADC_CFG_CMD_BIT) /* AUX voltage */ ++ #define SADC_CFG_CMD_AUX1 (0x1 << SADC_CFG_CMD_BIT) /* AUX1 voltage */ ++ #define SADC_CFG_CMD_AUX2 (0x2 << SADC_CFG_CMD_BIT) /* AUX2 voltage */ ++ #define SADC_CFG_CMD_RESERVED (0x3 << SADC_CFG_CMD_BIT) /* Reserved */ ++ ++/* ADCCTRL: ADC Control Register */ ++#define SADC_CTRL_SLPENDM (1 << 5) /* Sleep Interrupt Mask */ ++#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ ++#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ ++#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ ++#define SADC_CTRL_PBATRDYM (1 << 1) /* VBAT Data Ready Interrupt Mask */ ++#define SADC_CTRL_SRDYM (1 << 0) /* AUX Data Ready Interrupt Mask */ ++ ++/* ADSTATE: ADC Status Register */ ++#define SADC_STATE_SLP_RDY (1 << 7) /* Sleep state bit */ ++#define SADC_STATE_SLEEPND (1 << 5) /* Pen Down Interrupt Flag */ ++#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ ++#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ ++#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ ++#define SADC_STATE_PBATRDY (1 << 1) /* VBAT Data Ready Interrupt Flag */ ++#define SADC_STATE_SRDY (1 << 0) /* AUX Data Ready Interrupt Flag */ ++ ++/* ADTCH: ADC Touch Screen Data Register */ ++#define SADC_TSDAT_TYPE1 (1 << 31) ++#define SADC_TSDAT_DATA1_BIT 16 ++#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) ++#define SADC_TSDAT_TYPE0 (1 << 15) ++#define SADC_TSDAT_DATA0_BIT 0 ++#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) ++ ++/* ADCLK: ADC Clock Divide Register */ ++#define SADC_ADCLK_CLKDIV_MS 16 ++#define SADC_ADCLK_CLKDIV_MS_MASK (0xffff << SADC_ADCLK_CLKDIV_MS) ++#define SADC_ADCLK_CLKDIV_US 8 ++#define SADC_ADCLK_CLKDIV_US_MASK (0xff << SADC_ADCLK_CLKDIV_US) ++#define SADC_ADCLK_CLKDIV_BIT 0 ++#define SADC_ADCLK_CLKDIV_MASK (0xff << SADC_ADCLK_CLKDIV_BIT) ++ ++/* ++ * SADC registers offset definition ++ */ ++#define SADC_ADENA_OFFSET (0x00) /* rw, 8, 0x00 */ ++#define SADC_ADCFG_OFFSET (0x04) /* rw, 32, 0x0002000c */ ++#define SADC_ADCTRL_OFFSET (0x08) /* rw, 8, 0x3f */ ++#define SADC_ADSTATE_OFFSET (0x0c) /* rw, 8, 0x00 */ ++#define SADC_ADSAME_OFFSET (0x10) /* rw, 16, 0x0000 */ ++#define SADC_ADWAIT_OFFSET (0x14) /* rw, 16, 0x0000 */ ++#define SADC_ADTCH_OFFSET (0x18) /* rw, 32, 0x00000000 */ ++#define SADC_ADVDAT_OFFSET (0x1c) /* rw, 16, 0x0000 */ ++#define SADC_ADADAT_OFFSET (0x20) /* rw, 16, 0x0000 */ ++#define SADC_ADCMD_OFFSET (0x24) /* rw, 32, 0x00000000 */ ++#define SADC_ADCLK_OFFSET (0x28) /* rw, 32, 0x00000000 */ ++ ++/* ++ * SADC registers address definition ++ */ ++#define SADC_ADENA (SADC_BASE + SADC_ADENA_OFFSET) /* ADC Enable Register */ ++#define SADC_ADCFG (SADC_BASE + SADC_ADCFG_OFFSET) /* ADC Configure Register */ ++#define SADC_ADCTRL (SADC_BASE + SADC_ADCTRL_OFFSET) /* ADC Control Register */ ++#define SADC_ADSTATE (SADC_BASE + SADC_ADSTATE_OFFSET)/* ADC Status Register*/ ++#define SADC_ADSAME (SADC_BASE + SADC_ADSAME_OFFSET) /* ADC Same Point Time Register */ ++#define SADC_ADWAIT (SADC_BASE + SADC_ADWAIT_OFFSET) /* ADC Wait Time Register */ ++#define SADC_ADTCH (SADC_BASE + SADC_ADTCH_OFFSET) /* ADC Touch Screen Data Register */ ++#define SADC_ADVDAT (SADC_BASE + SADC_ADVDAT_OFFSET) /* ADC VBAT Data Register */ ++#define SADC_ADADAT (SADC_BASE + SADC_ADADAT_OFFSET) /* ADC AUX Data Register */ ++#define SADC_ADCMD (SADC_BASE + SADC_ADCMD_OFFSET) /* ADC COMMAND Register */ ++#define SADC_ADCLK (SADC_BASE + SADC_ADCLK_OFFSET) /* ADC Clock Divide Register */ ++ ++ ++/* ++ * SADC registers common define ++ */ ++ ++/* ADC Enable Register (ADENA) */ ++#define ADENA_POWER BIT7 ++#define ADENA_SLP_MD BIT6 ++#define ADENA_TCHEN BIT2 ++#define ADENA_PENDEN BIT3 ++#define ADENA_VBATEN BIT1 ++#define ADENA_AUXEN BIT0 ++ ++/* ADC Configure Register (ADCFG) */ ++#define ADCFG_SPZZ BIT31 ++ ++#define ADCFG_CMD_SEL BIT22 ++ ++#define ADCFG_DMA_EN BIT15 ++ ++#define ADCFG_XYZ_LSB 13 ++#define ADCFG_XYZ_MASK BITS_H2L(14, ADCFG_XYZ_LSB) ++#define ADCFG_XYZ_XYS (0x0 << ADCFG_XYZ_LSB) ++#define ADCFG_XYZ_XYD (0x1 << ADCFG_XYZ_LSB) ++#define ADCFG_XYZ_XYZ1Z2 (0x2 << ADCFG_XYZ_LSB) ++#define ADCFG_XYZ_XYZ1Z2X2Y2 (0x3 << ADCFG_XYZ_LSB) ++ ++#define ADCFG_SNUM_LSB 10 ++#define ADCFG_SNUM_MASK BITS_H2L(12, ADCFG_SNUM_LSB) ++#define ADCFG_SNUM(n) (((n) <= 6 ? ((n)-1) : ((n)-2)) << ADCFG_SNUM_LSB) ++ ++#define ADCFG_CMD_LSB 0 ++#define ADCFG_CMD_MASK BITS_H2L(1, ADCFG_CMD_LSB) ++#define ADCFG_CMD_AUX(n) ((n) << ADCFG_CMD_LSB) ++ ++/* ADC Control Register (ADCCTRL) */ ++#define ADCTRL_SLPENDM BIT5 ++#define ADCTRL_PENDM BIT4 ++#define ADCTRL_PENUM BIT3 ++#define ADCTRL_DTCHM BIT2 ++#define ADCTRL_VRDYM BIT1 ++#define ADCTRL_ARDYM BIT0 ++#define ADCTRL_MASK_ALL (ADCTRL_SLPENDM | ADCTRL_PENDM | ADCTRL_PENUM \ ++ | ADCTRL_DTCHM | ADCTRL_VRDYM | ADCTRL_ARDYM) ++ ++/* ADC Status Register (ADSTATE) */ ++#define ADSTATE_SLP_RDY BIT7 ++#define ADSTATE_SLPEND BIT5 ++#define ADSTATE_PEND BIT4 ++#define ADSTATE_PENU BIT3 ++#define ADSTATE_DTCH BIT2 ++#define ADSTATE_VRDY BIT1 ++#define ADSTATE_ARDY BIT0 ++ ++/* ADC Same Point Time Register (ADSAME) */ ++#define ADSAME_SCNT_LSB 0 ++#define ADSAME_SCNT_MASK BITS_H2L(15, ADSAME_SCNT_LSB) ++ ++/* ADC Wait Pen Down Time Register (ADWAIT) */ ++#define ADWAIT_WCNT_LSB 0 ++#define ADWAIT_WCNT_MASK BITS_H2L(15, ADWAIT_WCNT_LSB) ++ ++/* ADC Touch Screen Data Register (ADTCH) */ ++#define ADTCH_TYPE1 BIT31 ++#define ADTCH_TYPE0 BIT15 ++ ++#define ADTCH_DATA1_LSB 16 ++#define ADTCH_DATA1_MASK BITS_H2L(27, ADTCH_DATA1_LSB) ++ ++#define ADTCH_DATA0_LSB 0 ++#define ADTCH_DATA0_MASK BITS_H2L(11, ADTCH_DATA0_LSB) ++ ++/* ADC VBAT Date Register (ADVDAT) */ ++#define ADVDAT_VDATA_LSB 0 ++#define ADVDAT_VDATA_MASK BITS_H2L(11, ADVDAT_VDATA_LSB) ++ ++/* ADC AUX Data Register (ADADAT) */ ++#define ADADAT_ADATA_LSB 0 ++#define ADADAT_ADATA_MASK BITS_H2L(11, ADADAT_ADATA_LSB) ++ ++/* ADC Clock Divide Register (ADCLK) */ ++#define ADCLK_CLKDIV_MS_LSB 16 ++#define ADCLK_CLKDIV_MS_MASK BITS_H2L(31, ADCLK_CLKDIV_MS_LSB) ++ ++#define ADCLK_CLKDIV_US_LSB 8 ++#define ADCLK_CLKDIV_US_MASK BITS_H2L(15, ADCLK_CLKDIV_US_LSB) ++ ++#define ADCLK_CLKDIV_LSB 0 ++#define ADCLK_CLKDIV_MASK BITS_H2L(7, ADCLK_CLKDIV_LSB) ++ ++/* ADC Filter Register (ADFLT) */ ++#define ADFLT_FLT_EN BIT15 ++ ++#define ADFLT_FLT_D_LSB 0 ++#define ADFLT_FLT_D_MASK BITS_H2L(11, ADFLT_FLT_D_LSB) ++ ++/* ADC Command Register (ADCMD) */ ++#define ADCMD_PIL BIT31 ++#define ADCMD_RPU(n) ((n) << 26) ++#define ADCMD_XPSUP BIT25 ++#define ADCMD_YPSUP BIT23 ++#define ADCMD_XNGRU BIT21 ++#define ADCMD_YNGRU BIT20 ++#define ADCMD_VREFNXN BIT18 ++#define ADCMD_VREFNYN BIT16 ++#define ADCMD_VREFPXP BIT12 ++#define ADCMD_VREFPYP BIT11 ++#define ADCMD_XPADC BIT10 ++#define ADCMD_YPADC BIT8 ++struct ingenic_ts_info{ ++ unsigned int x_max; ++ unsigned int x_min; ++ unsigned int y_max; ++ unsigned int y_min; ++ unsigned int z_max; ++ unsigned int z_min; ++ unsigned short x_resolution; ++ unsigned short y_resolution; ++ unsigned short y_r_plate; ++ unsigned short x_r_plate; ++ unsigned short pressure_max; ++ unsigned int use_5_wire; ++ unsigned int support_keypad; ++ unsigned int support_mt_touch; ++ unsigned int support_sleepmode; ++ void *private_data; ++}; ++ ++ ++ ++/* ++ * ingenic_adc_set_config - Configure a ingenic adc device ++ * @dev: Pointer to a ingenic-adc device ++ * @mask: Mask for the config value to be set ++ * @val: Value to be set ++ * ++ * This function can be used by the ingenic ++ * ADC mfd cells to confgure their options in the shared config register. ++ */ ++ ++#if 0 ++ int ingenic_adc_set_config(struct device *dev, uint32_t mask, uint32_t val); ++#endif ++ ++int adc_write_reg(struct device *dev,uint8_t addr_offset,uint32_t mask,uint32_t val); ++uint32_t adc_read_reg(struct device *dev,uint8_t addr_offset); ++#endif /*ingenic_adc.h*/ +diff --git a/include/linux/usb.h b/include/linux/usb.h +index d6a41841b..b7d079728 100644 +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -560,6 +560,7 @@ struct usb3_lpm_parameters { + * @speed: device speed: high/full/low (or error) + * @rx_lanes: number of rx lanes in use, USB 3.2 adds dual-lane support + * @tx_lanes: number of tx lanes in use, USB 3.2 adds dual-lane support ++ * @ssp_rate: SuperSpeed Plus phy signaling rate and lane count + * @tt: Transaction Translator info; used with low/full speed dev, highspeed hub + * @ttport: device port on that tt hub + * @toggle: one bit for each endpoint, with ([0] = IN, [1] = OUT) endpoints +@@ -636,6 +637,7 @@ struct usb_device { + enum usb_device_speed speed; + unsigned int rx_lanes; + unsigned int tx_lanes; ++ enum usb_ssp_rate ssp_rate; + + struct usb_tt *tt; + int ttport; +@@ -880,6 +882,15 @@ extern struct usb_host_interface *usb_find_alt_setting( + unsigned int iface_num, + unsigned int alt_num); + ++#if IS_REACHABLE(CONFIG_USB) ++int usb_for_each_port(void *data, int (*fn)(struct device *, void *)); ++#else ++static inline int usb_for_each_port(void *data, int (*fn)(struct device *, void *)) ++{ ++ return 0; ++} ++#endif ++ + /* port claiming functions */ + int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, + struct usb_dev_state *owner); +@@ -1476,7 +1487,7 @@ typedef void (*usb_complete_t)(struct urb *); + * + * Note that transfer_buffer must still be set if the controller + * does not support DMA (as indicated by hcd_uses_dma()) and when talking +- * to root hub. If you have to trasfer between highmem zone and the device ++ * to root hub. If you have to transfer between highmem zone and the device + * on such controller, create a bounce buffer or bail out with an error. + * If transfer_buffer cannot be set (is in highmem) and the controller is DMA + * capable, assign NULL to it, so that usbmon knows not to use the value. +diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h +index ead8c9a47..8fc2abd7a 100644 +--- a/include/linux/usb/audio-v2.h ++++ b/include/linux/usb/audio-v2.h +@@ -156,6 +156,20 @@ struct uac2_feature_unit_descriptor { + __u8 bmaControls[]; /* variable length */ + } __attribute__((packed)); + ++#define UAC2_DT_FEATURE_UNIT_SIZE(ch) (6 + ((ch) + 1) * 4) ++ ++/* As above, but more useful for defining your own descriptors: */ ++#define DECLARE_UAC2_FEATURE_UNIT_DESCRIPTOR(ch) \ ++struct uac2_feature_unit_descriptor_##ch { \ ++ __u8 bLength; \ ++ __u8 bDescriptorType; \ ++ __u8 bDescriptorSubtype; \ ++ __u8 bUnitID; \ ++ __u8 bSourceID; \ ++ __le32 bmaControls[ch + 1]; \ ++ __u8 iFeature; \ ++} __packed ++ + /* 4.7.2.10 Effect Unit Descriptor */ + + struct uac2_effect_unit_descriptor { +diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h +index 604c6c514..1cffa3474 100644 +--- a/include/linux/usb/ch9.h ++++ b/include/linux/usb/ch9.h +@@ -36,62 +36,24 @@ + #include + #include + +-/** +- * usb_ep_type_string() - Returns human readable-name of the endpoint type. +- * @ep_type: The endpoint type to return human-readable name for. If it's not +- * any of the types: USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT}, +- * usually got by usb_endpoint_type(), the string 'unknown' will be returned. +- */ +-extern const char *usb_ep_type_string(int ep_type); ++/* USB 3.2 SuperSpeed Plus phy signaling rate generation and lane count */ + +-/** +- * usb_speed_string() - Returns human readable-name of the speed. +- * @speed: The speed to return human-readable name for. If it's not +- * any of the speeds defined in usb_device_speed enum, string for +- * USB_SPEED_UNKNOWN will be returned. +- */ +-extern const char *usb_speed_string(enum usb_device_speed speed); ++enum usb_ssp_rate { ++ USB_SSP_GEN_UNKNOWN = 0, ++ USB_SSP_GEN_2x1, ++ USB_SSP_GEN_1x2, ++ USB_SSP_GEN_2x2, ++}; + +-/** +- * usb_get_maximum_speed - Get maximum requested speed for a given USB +- * controller. +- * @dev: Pointer to the given USB controller device +- * +- * The function gets the maximum speed string from property "maximum-speed", +- * and returns the corresponding enum usb_device_speed. +- */ ++extern const char *usb_ep_type_string(int ep_type); ++extern const char *usb_speed_string(enum usb_device_speed speed); + extern enum usb_device_speed usb_get_maximum_speed(struct device *dev); +- +-/** +- * usb_state_string - Returns human readable name for the state. +- * @state: The state to return a human-readable name for. If it's not +- * any of the states devices in usb_device_state_string enum, +- * the string UNKNOWN will be returned. +- */ ++extern enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev); + extern const char *usb_state_string(enum usb_device_state state); ++unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd, ++ enum usb_device_speed speed); + + #ifdef CONFIG_TRACING +-/** +- * usb_decode_ctrl - Returns human readable representation of control request. +- * @str: buffer to return a human-readable representation of control request. +- * This buffer should have about 200 bytes. +- * @size: size of str buffer. +- * @bRequestType: matches the USB bmRequestType field +- * @bRequest: matches the USB bRequest field +- * @wValue: matches the USB wValue field (CPU byte order) +- * @wIndex: matches the USB wIndex field (CPU byte order) +- * @wLength: matches the USB wLength field (CPU byte order) +- * +- * Function returns decoded, formatted and human-readable description of +- * control request packet. +- * +- * The usage scenario for this is for tracepoints, so function as a return +- * use the same value as in parameters. This approach allows to use this +- * function in TP_printk +- * +- * Important: wValue, wIndex, wLength parameters before invoking this function +- * should be processed by le16_to_cpu macro. +- */ + extern const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType, + __u8 bRequest, __u16 wValue, __u16 wIndex, + __u16 wLength); +diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h +index a2d229ab6..5e002c39c 100644 +--- a/include/linux/usb/composite.h ++++ b/include/linux/usb/composite.h +@@ -271,7 +271,7 @@ int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, + * @bConfigurationValue: Copied into configuration descriptor. + * @iConfiguration: Copied into configuration descriptor. + * @bmAttributes: Copied into configuration descriptor. +- * @MaxPower: Power consumtion in mA. Used to compute bMaxPower in the ++ * @MaxPower: Power consumption in mA. Used to compute bMaxPower in the + * configuration descriptor after considering the bus speed. + * @cdev: assigned by @usb_add_config() before calling @bind(); this is + * the device associated with this configuration. +@@ -525,6 +525,8 @@ extern struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev, + extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n); + + extern void composite_disconnect(struct usb_gadget *gadget); ++extern void composite_reset(struct usb_gadget *gadget); ++ + extern int composite_setup(struct usb_gadget *gadget, + const struct usb_ctrlrequest *ctrl); + extern void composite_suspend(struct usb_gadget *gadget); +diff --git a/include/linux/usb/f_mtp.h b/include/linux/usb/f_mtp.h +new file mode 100644 +index 000000000..4e8417791 +--- /dev/null ++++ b/include/linux/usb/f_mtp.h +@@ -0,0 +1,23 @@ ++/* ++ * Gadget Function Driver for MTP ++ * ++ * Copyright (C) 2010 Google, Inc. ++ * Author: Mike Lockwood ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#ifndef __LINUX_USB_F_MTP_H ++#define __LINUX_USB_F_MTP_H ++ ++#include ++ ++#endif /* __LINUX_USB_F_MTP_H */ +diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h +index e7351d64f..10fe57cf4 100644 +--- a/include/linux/usb/gadget.h ++++ b/include/linux/usb/gadget.h +@@ -197,7 +197,7 @@ struct usb_ep_caps { + * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk" + * @ops: Function pointers used to access hardware-specific operations. + * @ep_list:the gadget's ep_list holds all of its endpoints +- * @caps:The structure describing types and directions supported by endoint. ++ * @caps:The structure describing types and directions supported by endpoint. + * @enabled: The current endpoint enabled/disabled state. + * @claimed: True if this endpoint is claimed by a function. + * @maxpacket:The maximum packet size used on this endpoint. The initial +@@ -323,9 +323,13 @@ struct usb_gadget_ops { + struct usb_gadget_driver *); + int (*udc_stop)(struct usb_gadget *); + void (*udc_set_speed)(struct usb_gadget *, enum usb_device_speed); ++ void (*udc_set_ssp_rate)(struct usb_gadget *gadget, ++ enum usb_ssp_rate rate); ++ void (*udc_async_callbacks)(struct usb_gadget *gadget, bool enable); + struct usb_ep *(*match_ep)(struct usb_gadget *, + struct usb_endpoint_descriptor *, + struct usb_ss_ep_comp_descriptor *); ++ int (*check_config)(struct usb_gadget *gadget); + }; + + /** +@@ -339,6 +343,10 @@ struct usb_gadget_ops { + * @speed: Speed of current connection to USB host. + * @max_speed: Maximal speed the UDC can handle. UDC must support this + * and all slower speeds. ++ * @ssp_rate: Current connected SuperSpeed Plus signaling rate and lane count. ++ * @max_ssp_rate: Maximum SuperSpeed Plus signaling rate and lane count the UDC ++ * can handle. The UDC must support this and all slower speeds and lower ++ * number of lanes. + * @state: the state we are now (attached, suspended, configured, etc) + * @name: Identifies the controller hardware type. Used in diagnostics + * and sometimes configuration. +@@ -406,6 +414,11 @@ struct usb_gadget { + struct list_head ep_list; /* of usb_ep */ + enum usb_device_speed speed; + enum usb_device_speed max_speed; ++ ++ /* USB SuperSpeed Plus only */ ++ enum usb_ssp_rate ssp_rate; ++ enum usb_ssp_rate max_ssp_rate; ++ + enum usb_device_state state; + const char *name; + struct device dev; +@@ -479,7 +492,7 @@ extern char *usb_get_gadget_udc_name(void); + */ + static inline size_t usb_ep_align(struct usb_ep *ep, size_t len) + { +- int max_packet_size = (size_t)usb_endpoint_maxp(ep->desc) & 0x7ff; ++ int max_packet_size = (size_t)usb_endpoint_maxp(ep->desc); + + return round_up(len, max_packet_size); + } +@@ -596,6 +609,7 @@ int usb_gadget_connect(struct usb_gadget *gadget); + int usb_gadget_disconnect(struct usb_gadget *gadget); + int usb_gadget_deactivate(struct usb_gadget *gadget); + int usb_gadget_activate(struct usb_gadget *gadget); ++int usb_gadget_check_config(struct usb_gadget *gadget); + #else + static inline int usb_gadget_frame_number(struct usb_gadget *gadget) + { return 0; } +@@ -619,6 +633,8 @@ static inline int usb_gadget_deactivate(struct usb_gadget *gadget) + { return 0; } + static inline int usb_gadget_activate(struct usb_gadget *gadget) + { return 0; } ++static inline int usb_gadget_check_config(struct usb_gadget *gadget) ++{ return 0; } + #endif /* CONFIG_USB_GADGET */ + + /*-------------------------------------------------------------------------*/ +diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h +index c0cf20b19..98d1921f0 100644 +--- a/include/linux/usb/hcd.h ++++ b/include/linux/usb/hcd.h +@@ -59,7 +59,7 @@ + * USB Host Controller Driver (usb_hcd) framework + * + * Since "struct usb_bus" is so thin, you can't share much code in it. +- * This framework is a layer over that, and should be more sharable. ++ * This framework is a layer over that, and should be more shareable. + */ + + /*-------------------------------------------------------------------------*/ +@@ -302,7 +302,7 @@ struct hc_driver { + * (optional) these hooks allow an HCD to override the default DMA + * mapping and unmapping routines. In general, they shouldn't be + * necessary unless the host controller has special DMA requirements, +- * such as alignment contraints. If these are not specified, the ++ * such as alignment constraints. If these are not specified, the + * general usb_hcd_(un)?map_urb_for_dma functions will be used instead + * (and it may be a good idea to call these functions in your HCD + * implementation) +@@ -412,7 +412,10 @@ struct hc_driver { + int (*find_raw_port_number)(struct usb_hcd *, int); + /* Call for power on/off the port if necessary */ + int (*port_power)(struct usb_hcd *hcd, int portnum, bool enable); +- ++ /* Call for SINGLE_STEP_SET_FEATURE Test for USB2 EH certification */ ++#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06 ++ int (*submit_single_step_set_feature)(struct usb_hcd *, ++ struct urb *, int); + }; + + static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd) +@@ -477,6 +480,14 @@ int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr, + + struct platform_device; + extern void usb_hcd_platform_shutdown(struct platform_device *dev); ++#ifdef CONFIG_USB_HCD_TEST_MODE ++extern int ehset_single_step_set_feature(struct usb_hcd *hcd, int port); ++#else ++static inline int ehset_single_step_set_feature(struct usb_hcd *hcd, int port) ++{ ++ return 0; ++} ++#endif /* CONFIG_USB_HCD_TEST_MODE */ + + #ifdef CONFIG_USB_PCI + struct pci_dev; +@@ -737,10 +748,6 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb, + + /* random stuff */ + +-#define RUN_CONTEXT (in_irq() ? "in_irq" \ +- : (in_interrupt() ? "in_interrupt" : "can sleep")) +- +- + /* This rwsem is for use only by the hub driver and ehci-hcd. + * Nobody else should touch it. + */ +diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h +index 8ef7d148c..e78eb577d 100644 +--- a/include/linux/usb/otg-fsm.h ++++ b/include/linux/usb/otg-fsm.h +@@ -196,7 +196,6 @@ struct otg_fsm { + struct mutex lock; + u8 *host_req_flag; + struct delayed_work hnp_polling_work; +- bool hnp_work_inited; + bool state_changed; + }; + +diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h +index 69f1b6328..6475f880b 100644 +--- a/include/linux/usb/otg.h ++++ b/include/linux/usb/otg.h +@@ -125,8 +125,9 @@ enum usb_dr_mode { + * @dev: Pointer to the given device + * + * The function gets phy interface string from property 'dr_mode', +- * and returns the correspondig enum usb_dr_mode ++ * and returns the corresponding enum usb_dr_mode + */ + extern enum usb_dr_mode usb_get_dr_mode(struct device *dev); ++extern enum usb_dr_mode usb_get_role_switch_default_mode(struct device *dev); + + #endif /* __LINUX_USB_OTG_H */ +diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h +index 433040ff8..3a805e2ec 100644 +--- a/include/linux/usb/pd.h ++++ b/include/linux/usb/pd.h +@@ -459,7 +459,7 @@ static inline unsigned int rdo_max_power(u32 rdo) + #define PD_T_RECEIVER_RESPONSE 15 /* 15ms max */ + #define PD_T_SOURCE_ACTIVITY 45 + #define PD_T_SINK_ACTIVITY 135 +-#define PD_T_SINK_WAIT_CAP 310 /* 310 - 620 ms */ ++#define PD_T_SINK_WAIT_CAP 240 + #define PD_T_PS_TRANSITION 500 + #define PD_T_SRC_TRANSITION 35 + #define PD_T_DRP_SNK 40 +diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h +index e4de6bc1f..a9971c273 100644 +--- a/include/linux/usb/phy.h ++++ b/include/linux/usb/phy.h +@@ -144,6 +144,8 @@ struct usb_phy { + */ + int (*set_wakeup)(struct usb_phy *x, bool enabled); + ++ int (*get_wakeup)(struct usb_phy *x); ++ + /* notify phy connect status change */ + int (*notify_connect)(struct usb_phy *x, + enum usb_device_speed speed); +@@ -316,6 +318,15 @@ usb_phy_set_wakeup(struct usb_phy *x, bool enabled) + return 0; + } + ++static inline int ++usb_phy_get_wakeup(struct usb_phy *x) ++{ ++ if (x && x->get_wakeup) ++ return x->get_wakeup(x); ++ else ++ return 0; ++} ++ + static inline int + usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) + { +diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h +index 5e4c497f5..eeb7c2157 100644 +--- a/include/linux/usb/quirks.h ++++ b/include/linux/usb/quirks.h +@@ -32,7 +32,7 @@ + #define USB_QUIRK_DELAY_INIT BIT(6) + + /* +- * For high speed and super speed interupt endpoints, the USB 2.0 and ++ * For high speed and super speed interrupt endpoints, the USB 2.0 and + * USB 3.0 spec require the interval in microframes + * (1 microframe = 125 microseconds) to be calculated as + * interval = 2 ^ (bInterval-1). +diff --git a/include/linux/usb/role.h b/include/linux/usb/role.h +index b9ccaeb8a..b5deafd91 100644 +--- a/include/linux/usb/role.h ++++ b/include/linux/usb/role.h +@@ -65,6 +65,7 @@ void usb_role_switch_unregister(struct usb_role_switch *sw); + + void usb_role_switch_set_drvdata(struct usb_role_switch *sw, void *data); + void *usb_role_switch_get_drvdata(struct usb_role_switch *sw); ++const char *usb_role_string(enum usb_role role); + #else + static inline int usb_role_switch_set_role(struct usb_role_switch *sw, + enum usb_role role) +@@ -115,6 +116,11 @@ static inline void *usb_role_switch_get_drvdata(struct usb_role_switch *sw) + return NULL; + } + ++static inline const char *usb_role_string(enum usb_role role) ++{ ++ return "unknown"; ++} ++ + #endif + + #endif /* __LINUX_USB_ROLE_H */ +diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h +index 8110c29fa..2e4f7721f 100644 +--- a/include/linux/usb/usbnet.h ++++ b/include/linux/usb/usbnet.h +@@ -83,8 +83,6 @@ struct usbnet { + # define EVENT_LINK_CHANGE 11 + # define EVENT_SET_RX_MODE 12 + # define EVENT_NO_IP_ALIGN 13 +- u32 rx_speed; /* in bps - NOT Mbps */ +- u32 tx_speed; /* in bps - NOT Mbps */ + }; + + static inline struct usb_driver *driver_of(struct usb_interface *intf) +diff --git a/include/media/ingenic_video_nr.h b/include/media/ingenic_video_nr.h +new file mode 100644 +index 000000000..70ec7bcbd +--- /dev/null ++++ b/include/media/ingenic_video_nr.h +@@ -0,0 +1,23 @@ ++#ifndef __INGENIC_VIDEO_NR_H__ ++#define __INGENIC_VIDEO_NR_H__ ++ ++enum ingenic_video_nr { ++ INGENIC_ROTATE_VIDEO_NR = 0, ++ INGENIC_HELIX_VIDEO_NR, /*1*/ ++ INGENIC_FELIX_VIDEO_NR, /*2*/ ++ INGENIC_VIC0_VIDEO_NR, /*3*/ ++ INGENIC_MSCA0_CH0_VIDEO_NR, /*4*/ ++ INGENIC_MSCA0_CH1_VIDEO_NR, /*5*/ ++ INGENIC_MSCA0_CH2_VIDEO_NR, /*6*/ ++ INGENIC_VIC1_VIDEO_NR, /*7*/ ++ INGENIC_MSCA1_CH0_VIDEO_NR, /*8*/ ++ INGENIC_MSCA1_CH1_VIDEO_NR, /*9*/ ++ INGENIC_MSCA1_CH2_VIDEO_NR, /*10*/ ++ INGENIC_CIM_VIDEO_NR_0, /*11*/ ++ INGENIC_UVC_VIDEO_NR, /*12*/ ++ INGENIC_VIC2_VIDEO_NR, /*13*/ ++ INGENIC_CIM_VIDEO_NR_1, /*14*/ ++ INGENIC_DPU_COMP_VIDEO_NR, /*15*/ ++}; ++ ++#endif +diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h +index 86878fba3..3aaaf9eb3 100644 +--- a/include/media/v4l2-ioctl.h ++++ b/include/media/v4l2-ioctl.h +@@ -496,6 +496,12 @@ struct v4l2_ioctl_ops { + /* Crop ioctls */ + int (*vidioc_g_pixelaspect)(struct file *file, void *fh, + int buf_type, struct v4l2_fract *aspect); ++ int (*vidioc_cropcap)(struct file *file, void *fh, ++ struct v4l2_cropcap *a); ++ int (*vidioc_g_crop)(struct file *file, void *fh, ++ struct v4l2_crop *a); ++ int (*vidioc_s_crop)(struct file *file, void *fh, ++ const struct v4l2_crop *a); + int (*vidioc_g_selection)(struct file *file, void *fh, + struct v4l2_selection *s); + int (*vidioc_s_selection)(struct file *file, void *fh, +diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h +index 73150520c..fadfe6418 100644 +--- a/include/media/v4l2-subdev.h ++++ b/include/media/v4l2-subdev.h +@@ -422,6 +422,9 @@ struct v4l2_subdev_video_ops { + int (*g_tvnorms_output)(struct v4l2_subdev *sd, v4l2_std_id *std); + int (*g_input_status)(struct v4l2_subdev *sd, u32 *status); + int (*s_stream)(struct v4l2_subdev *sd, int enable); ++ int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cc); ++ int (*g_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop); ++ int (*s_crop)(struct v4l2_subdev *sd, const struct v4l2_crop *crop); + int (*g_pixelaspect)(struct v4l2_subdev *sd, struct v4l2_fract *aspect); + int (*g_frame_interval)(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval); +diff --git a/include/media/videobuf2-dma-contig-ingenic.h b/include/media/videobuf2-dma-contig-ingenic.h +new file mode 100644 +index 000000000..5f9378c74 +--- /dev/null ++++ b/include/media/videobuf2-dma-contig-ingenic.h +@@ -0,0 +1,32 @@ ++/* ++ * videobuf2-dma-contig.h - DMA contig memory allocator for videobuf2 ++ * ++ * Copyright (C) 2010 Samsung Electronics ++ * ++ * Author: Pawel Osciak ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation. ++ */ ++ ++#ifndef _MEDIA_VIDEOBUF2_DMA_CONTIG_H ++#define _MEDIA_VIDEOBUF2_DMA_CONTIG_H ++ ++#include ++#include ++ ++static inline dma_addr_t ++ingenic_vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no) ++{ ++ dma_addr_t *addr = vb2_plane_cookie(vb, plane_no); ++ ++ return *addr; ++} ++ ++void *ingenic_vb2_dma_contig_init_ctx(struct device *dev); ++void ingenic_vb2_dma_contig_cleanup_ctx(void *alloc_ctx); ++ ++extern const struct vb2_mem_ops ingenic_vb2_dma_contig_memops; ++ ++#endif +diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h +index 3abb5b15a..5756df2f5 100644 +--- a/include/uapi/linux/android/binder.h ++++ b/include/uapi/linux/android/binder.h +@@ -24,6 +24,10 @@ + #include + #include + ++#ifndef CONFIG_ANDROID_BINDER_IPC_64BIT ++#define BINDER_IPC_32BIT 1 ++#endif ++ + #define B_PACK_CHARS(c1, c2, c3, c4) \ + ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4)) + #define B_TYPE_LARGE 0x85 +diff --git a/include/uapi/linux/tty_flags.h b/include/uapi/linux/tty_flags.h +index 6a3ac496a..900a32e63 100644 +--- a/include/uapi/linux/tty_flags.h ++++ b/include/uapi/linux/tty_flags.h +@@ -39,7 +39,7 @@ + * WARNING: These flags are no longer used and have been superceded by the + * TTY_PORT_ flags in the iflags field (and not userspace-visible) + */ +-#ifndef __KERNEL__ ++#ifndef _KERNEL_ + #define ASYNCB_INITIALIZED 31 /* Serial port was initialized */ + #define ASYNCB_SUSPENDED 30 /* Serial port is suspended */ + #define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */ +@@ -81,7 +81,7 @@ + #define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI) + #define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI) + +-#ifndef __KERNEL__ ++#ifndef _KERNEL_ + /* These flags are no longer used (and were always masked from userspace) */ + #define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED) + #define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE) +diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h +index 0f865ae4b..17ce56198 100644 +--- a/include/uapi/linux/usb/ch9.h ++++ b/include/uapi/linux/usb/ch9.h +@@ -968,9 +968,22 @@ struct usb_ssp_cap_descriptor { + __le32 bmSublinkSpeedAttr[1]; /* list of sublink speed attrib entries */ + #define USB_SSP_SUBLINK_SPEED_SSID (0xf) /* sublink speed ID */ + #define USB_SSP_SUBLINK_SPEED_LSE (0x3 << 4) /* Lanespeed exponent */ ++#define USB_SSP_SUBLINK_SPEED_LSE_BPS 0 ++#define USB_SSP_SUBLINK_SPEED_LSE_KBPS 1 ++#define USB_SSP_SUBLINK_SPEED_LSE_MBPS 2 ++#define USB_SSP_SUBLINK_SPEED_LSE_GBPS 3 ++ + #define USB_SSP_SUBLINK_SPEED_ST (0x3 << 6) /* Sublink type */ ++#define USB_SSP_SUBLINK_SPEED_ST_SYM_RX 0 ++#define USB_SSP_SUBLINK_SPEED_ST_ASYM_RX 1 ++#define USB_SSP_SUBLINK_SPEED_ST_SYM_TX 2 ++#define USB_SSP_SUBLINK_SPEED_ST_ASYM_TX 3 ++ + #define USB_SSP_SUBLINK_SPEED_RSVD (0x3f << 8) /* Reserved */ + #define USB_SSP_SUBLINK_SPEED_LP (0x3 << 14) /* Link protocol */ ++#define USB_SSP_SUBLINK_SPEED_LP_SS 0 ++#define USB_SSP_SUBLINK_SPEED_LP_SSP 1 ++ + #define USB_SSP_SUBLINK_SPEED_LSM (0xff << 16) /* Lanespeed mantissa */ + } __attribute__((packed)); + +diff --git a/include/uapi/linux/usb/f_mtp.h b/include/uapi/linux/usb/f_mtp.h +new file mode 100644 +index 000000000..503291855 +--- /dev/null ++++ b/include/uapi/linux/usb/f_mtp.h +@@ -0,0 +1,61 @@ ++/* ++ * Gadget Function Driver for MTP ++ * ++ * Copyright (C) 2010 Google, Inc. ++ * Author: Mike Lockwood ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#ifndef _UAPI_LINUX_USB_F_MTP_H ++#define _UAPI_LINUX_USB_F_MTP_H ++ ++#include ++#include ++ ++struct mtp_file_range { ++ /* file descriptor for file to transfer */ ++ int fd; ++ /* offset in file for start of transfer */ ++ loff_t offset; ++ /* number of bytes to transfer */ ++ int64_t length; ++ /* MTP command ID for data header, ++ * used only for MTP_SEND_FILE_WITH_HEADER ++ */ ++ uint16_t command; ++ /* MTP transaction ID for data header, ++ * used only for MTP_SEND_FILE_WITH_HEADER ++ */ ++ uint32_t transaction_id; ++}; ++ ++struct mtp_event { ++ /* size of the event */ ++ size_t length; ++ /* event data to send */ ++ void *data; ++}; ++ ++/* Sends the specified file range to the host */ ++#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range) ++/* Receives data from the host and writes it to a file. ++ * The file is created if it does not exist. ++ */ ++#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range) ++/* Sends an event to the host via the interrupt endpoint */ ++#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event) ++/* Sends the specified file range to the host, ++ * with a 12 byte MTP data packet header at the beginning. ++ */ ++#define MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, struct mtp_file_range) ++ ++#endif /* _UAPI_LINUX_USB_F_MTP_H */ +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +index 534eaa4d3..52ca5ba4c 100644 +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -583,6 +583,7 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_UV8 v4l2_fourcc('U', 'V', '8', ' ') /* 8 UV 4:4 */ + + /* Luminance+Chrominance formats */ ++#define V4L2_PIX_FMT_JZ420B v4l2_fourcc('J', 'Z', '1', '2') /* 12 YUV 4:2:0 B */ + #define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */ + #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16 YUV 4:2:2 */ + #define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */ +diff --git a/include/video/ingenic_logo.h b/include/video/ingenic_logo.h +new file mode 100644 +index 000000000..8d6602df1 +--- /dev/null ++++ b/include/video/ingenic_logo.h +@@ -0,0 +1,15 @@ ++#ifndef __LOGO_H__ ++#define __LOGO_H__ ++ ++struct _logo_info { ++ int width; ++ int height; ++ int bpp; ++ unsigned char *p8; ++ unsigned int background_color; ++} __attribute__ ((packed)); ++ ++extern struct _logo_info logo_info; ++extern unsigned char logo_buf_initdata[]; ++ ++#endif /* __LOGO_H__ */ +diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c +index 5b5b6c7ec..470b6111e 100644 +--- a/kernel/dma/coherent.c ++++ b/kernel/dma/coherent.c +@@ -52,11 +52,13 @@ static int dma_init_coherent_memory(phys_addr_t phys_addr, + goto out; + } + +- mem_base = memremap(phys_addr, size, MEMREMAP_WC); ++ //mem_base = memremap(phys_addr, size, MEMREMAP_WB); ++ mem_base = ioremap(phys_addr, size); + if (!mem_base) { + ret = -EINVAL; + goto out; + } ++ + dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); + if (!dma_mem) { + ret = -ENOMEM; +@@ -80,7 +82,7 @@ static int dma_init_coherent_memory(phys_addr_t phys_addr, + out: + kfree(dma_mem); + if (mem_base) +- memunmap(mem_base); ++ iounmap(mem_base); + return ret; + } + +@@ -89,7 +91,7 @@ static void dma_release_coherent_memory(struct dma_coherent_mem *mem) + if (!mem) + return; + +- memunmap(mem->virt_base); ++ iounmap(mem->virt_base); + kfree(mem->bitmap); + kfree(mem); + } +@@ -111,7 +113,7 @@ static int dma_assign_coherent_memory(struct device *dev, + * Declare a region of memory to be handed out by dma_alloc_coherent() when it + * is asked for coherent memory for this device. This shall only be used + * from platform code, usually based on the device tree description. +- * ++ * + * phys_addr is the CPU physical address to which the memory is currently + * assigned (this will be ioremapped so the CPU can access the region). + * +@@ -140,11 +142,40 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, + return ret; + } + ++static int dma_bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, unsigned int pages) ++{ ++ unsigned int pos, end; /* scans bitmap by regions of size order */ ++ unsigned long start = 0; ++ ++ /*step = 1 << 5 pages. */ ++ for (pos = 0; (end = pos + (1U << 5)) <= bits; pos = end) { ++ start = bitmap_find_next_zero_area(bitmap, bits, pos, pages, 0); ++ if( start > bits) { ++ return -ENOMEM; ++ } ++ ++ break; ++ } ++ ++ //ALLOC buffer. ++ bitmap_set(bitmap, start, pages); ++ ++ return start; ++} ++ ++static int dma_bitmap_release_region(unsigned long *bitmap, unsigned int bits, int pages) ++{ ++ bitmap_clear(bitmap, bits, pages); ++ ++ return 0; ++} ++ ++ + static void *__dma_alloc_from_coherent(struct device *dev, + struct dma_coherent_mem *mem, + ssize_t size, dma_addr_t *dma_handle) + { +- int order = get_order(size); ++ unsigned int pages = ALIGN(size, PAGE_SIZE) >> PAGE_SHIFT; + unsigned long flags; + int pageno; + void *ret; +@@ -154,7 +185,8 @@ static void *__dma_alloc_from_coherent(struct device *dev, + if (unlikely(size > ((dma_addr_t)mem->size << PAGE_SHIFT))) + goto err; + +- pageno = bitmap_find_free_region(mem->bitmap, mem->size, order); ++ //pageno = bitmap_find_free_region(mem->bitmap, mem->size, order); ++ pageno = dma_bitmap_find_free_region(mem->bitmap, mem->size, pages); + if (unlikely(pageno < 0)) + goto err; + +@@ -164,8 +196,11 @@ static void *__dma_alloc_from_coherent(struct device *dev, + *dma_handle = dma_get_device_base(dev, mem) + + ((dma_addr_t)pageno << PAGE_SHIFT); + ret = mem->virt_base + ((dma_addr_t)pageno << PAGE_SHIFT); ++ ++ dev_dbg(dev, "%s, allocated@ 0x%p, start: %d, pages: %d\n", __func__, ret, pageno, pages); ++ + spin_unlock_irqrestore(&mem->spinlock, flags); +- memset(ret, 0, size); ++ //memset(ret, 0, size); + return ret; + err: + spin_unlock_irqrestore(&mem->spinlock, flags); +@@ -209,15 +244,16 @@ void *dma_alloc_from_global_coherent(struct device *dev, ssize_t size, + } + + static int __dma_release_from_coherent(struct dma_coherent_mem *mem, +- int order, void *vaddr) ++ ssize_t size, void *vaddr) + { ++ unsigned int pages = ALIGN(size, PAGE_SIZE) >> PAGE_SHIFT; + if (mem && vaddr >= mem->virt_base && vaddr < + (mem->virt_base + ((dma_addr_t)mem->size << PAGE_SHIFT))) { + int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; + unsigned long flags; + + spin_lock_irqsave(&mem->spinlock, flags); +- bitmap_release_region(mem->bitmap, page, order); ++ dma_bitmap_release_region(mem->bitmap, page, pages); + spin_unlock_irqrestore(&mem->spinlock, flags); + return 1; + } +@@ -236,19 +272,21 @@ static int __dma_release_from_coherent(struct dma_coherent_mem *mem, + * Returns 1 if we correctly released the memory, or 0 if the caller should + * proceed with releasing memory from generic pools. + */ +-int dma_release_from_dev_coherent(struct device *dev, int order, void *vaddr) ++int dma_release_from_dev_coherent(struct device *dev, ssize_t size, void *vaddr) + { + struct dma_coherent_mem *mem = dev_get_coherent_memory(dev); ++ ++ dev_dbg(dev, "%s, vaddr: %p, size: %d\n", __func__, vaddr, size); + +- return __dma_release_from_coherent(mem, order, vaddr); ++ return __dma_release_from_coherent(mem, size, vaddr); + } + +-int dma_release_from_global_coherent(int order, void *vaddr) ++int dma_release_from_global_coherent(ssize_t size, void *vaddr) + { + if (!dma_coherent_default_memory) + return 0; + +- return __dma_release_from_coherent(dma_coherent_default_memory, order, ++ return __dma_release_from_coherent(dma_coherent_default_memory, size, + vaddr); + } + +diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c +index 51bb8fa8e..1af3e1dd1 100644 +--- a/kernel/dma/mapping.c ++++ b/kernel/dma/mapping.c +@@ -449,7 +449,7 @@ void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr, + { + const struct dma_map_ops *ops = get_dma_ops(dev); + +- if (dma_release_from_dev_coherent(dev, get_order(size), cpu_addr)) ++ if (dma_release_from_dev_coherent(dev, size, cpu_addr)) + return; + /* + * On non-coherent platforms which implement DMA-coherent buffers via +@@ -517,6 +517,12 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size, + const struct dma_map_ops *ops = get_dma_ops(dev); + void *vaddr; + ++ ++ /*1. try to alloc from dev coheren area.*/ ++ if(dma_alloc_from_dev_coherent(dev, size, dma_handle, &vaddr)) { ++ return (void *)CKSEG0ADDR(vaddr); ++ } ++ + if (!ops || !ops->alloc_noncoherent) { + struct page *page; + +@@ -540,6 +546,10 @@ void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, + { + const struct dma_map_ops *ops = get_dma_ops(dev); + ++ if(dma_release_from_dev_coherent(dev, size, (void *)CKSEG1ADDR(vaddr))) { ++ return; ++ } ++ + if (!ops || !ops->free_noncoherent) { + dma_free_pages(dev, size, virt_to_page(vaddr), dma_handle, dir); + return; +diff --git a/module_drivers/Kconfig b/module_drivers/Kconfig +new file mode 100644 +index 000000000..e617b4c83 +--- /dev/null ++++ b/module_drivers/Kconfig +@@ -0,0 +1,11 @@ ++menu "Ingenic device-drivers Configurations" ++ ++ ++config OUTSIDE_DRIVERS_PATH ++ string ++ default "module_drivers" ++ ++source "module_drivers/drivers/Kconfig" ++source "module_drivers/sound/soc/ingenic/Kconfig" ++ ++endmenu +diff --git a/module_drivers/Makefile b/module_drivers/Makefile +new file mode 100644 +index 000000000..f68d62266 +--- /dev/null ++++ b/module_drivers/Makefile +@@ -0,0 +1,6 @@ ++# Device Tree ++obj-$(CONFIG_BUILTIN_DTB) := dts/ ++ ++# Device Drivers ++obj-y += sound/ ++obj-y += drivers/ +diff --git a/module_drivers/README.zh b/module_drivers/README.zh +new file mode 100644 +index 000000000..f8c7256c3 +--- /dev/null ++++ b/module_drivers/README.zh +@@ -0,0 +1,27 @@ ++囿­£ç§æœ‰çš„内核驱动,按照æ¯ä¸ªé©±åŠ¨åŸºäºŽçš„æ¡†æž¶ï¼Œä»¥å†…æ ¸çš„ç›®å½•ç»“æž„å±•å¼€ï¼Œ ++独立存放在该module_drivers目录. ++ ++Kconfig å®šä¹‰åŽŸåˆ™ï¼Œå°½é‡æ¸…晰,贴近SOC本身. åªæ˜¾ç¤ºSOC支æŒçš„æŽ§åˆ¶å™¨é©±åЍ. ++ ++ ++ ++1. 如何嵌入到内核æºç ç¼–译 ++ ++内核æºç é¡¶å±‚Kconfig添加 ++ ++``` ++config OUTSIDE_DRIVERS ++ string ++ option env="OUTSIDE_DRIVERS" ++ default "module_drivers" ++ ++ ++source "$OUTSIDE_DRIVERS/Kconfig" ++``` ++ ++内核Makefile添加 ++ ++``` ++drivers-y += module_drivers/ ++``` ++ +diff --git a/module_drivers/drivers/Kconfig b/module_drivers/drivers/Kconfig +new file mode 100644 +index 000000000..4cd5b3c17 +--- /dev/null ++++ b/module_drivers/drivers/Kconfig +@@ -0,0 +1,111 @@ ++comment "---- Minimal required Drivers ----" ++menu "[Interrupt] Drivers" ++source "module_drivers/drivers/irqchip/Kconfig" ++endmenu ++ ++menu "[OST] clocksoure Drivers" ++source "module_drivers/drivers/clocksource/Kconfig" ++endmenu ++ ++menu "[CPM] clk Drivers" ++source "module_drivers/drivers/clk/ingenic-v2/Kconfig" ++endmenu ++ ++menu "[GPIO] Pinctroller Drivers" ++source "module_drivers/drivers/pinctrl/Kconfig" ++endmenu ++ ++menu "[UART] Drivers" ++source "module_drivers/drivers/tty/serial/Kconfig" ++endmenu ++ ++menu "[MSC] (eMMC/SD/SDIO) and Device Drivers" ++source "module_drivers/drivers/mmc/host/Kconfig" ++endmenu ++ ++menu "[DMA] Drivers" ++source "module_drivers/drivers/dma/ingenic/Kconfig" ++endmenu ++ ++menu "[SFC] (SPI Nand/Nor Flash) Drivers" ++source "module_drivers/drivers/mtd/devices/Kconfig" ++endmenu ++ ++menu "[SPI] Master/Slave Drivers" ++source "module_drivers/drivers/spi/Kconfig" ++endmenu ++ ++menu "[I2C] Master Drivers" ++source "module_drivers/drivers/i2c/busses/Kconfig" ++endmenu ++ ++comment "---- minimal OS requirements. ----" ++ ++menu "[LCD] Panel/Touchscreen Drivers" ++ ++source "module_drivers/drivers/video/fbdev/ingenic/Kconfig" ++source "module_drivers/drivers/video/logo-ingenic/Kconfig" ++ ++menu "Touchscreen Drivers" ++source "module_drivers/drivers/input/touchscreen/Kconfig" ++endmenu ++endmenu ++ ++ ++ ++menu "[GMAC] (ethernet) Drivers" ++source "module_drivers/drivers/net/ethernet/ingenic/Kconfig" ++endmenu ++menu "[WIFI] Drivers" ++source "module_drivers/drivers/net/wireless/bcmdhd_1_363_125_17/Kconfig" ++source "module_drivers/drivers/net/wireless/bcmdhd/Kconfig" ++source "module_drivers/drivers/net/wireless/realtek/rtl8723ds/Kconfig" ++endmenu ++ ++menu "[CAN] (ethernet) Drivers" ++#source "module_drivers/drivers/net/can/ingenic/Kconfig" ++endmenu ++ ++comment "---- (V4L2) Media Device Drivers ----" ++source "module_drivers/drivers/media/v4l2-core/Kconfig" ++source "module_drivers/drivers/media/platform/Kconfig" ++menu "[Sensors] Camera Sensors" ++source "module_drivers/drivers/media/i2c/Kconfig" ++endmenu ++ ++source "module_drivers/drivers/video/ingenic_bscaler/Kconfig" ++source "module_drivers/drivers/video/ingenic-nna/Kconfig" ++source "module_drivers/drivers/video/ingenic_ipu/Kconfig" ++source "module_drivers/drivers/video/ingenic_avpu/Kconfig" ++ ++ ++ ++comment "---- MISC Device Drivers ----" ++source "module_drivers/drivers/misc/Kconfig" ++ ++menu "[RANDOM] drivers" ++source "module_drivers/drivers/char/hw_random/Kconfig" ++endmenu ++ ++comment "[MFD] Multi Function Device Drivers" ++source "module_drivers/drivers/mfd/Kconfig" ++ ++comment "[Power] power and regulator Drivers" ++#source "module_drivers/drivers/power/Kconfig" ++#source "module_drivers/drivers/regulator/Kconfig" ++ ++source "module_drivers/drivers/crypto/Kconfig" ++ ++ ++menu "[WDT] watchdog Drivers" ++source "module_drivers/drivers/watchdog/Kconfig" ++endmenu ++ ++ ++menu "[PWM] drivers" ++source "module_drivers/drivers/pwm/Kconfig" ++endmenu ++ ++menu "[RTC] drivers" ++source "module_drivers/drivers/rtc/Kconfig" ++endmenu +diff --git a/module_drivers/drivers/Makefile b/module_drivers/drivers/Makefile +new file mode 100644 +index 000000000..a38e6da10 +--- /dev/null ++++ b/module_drivers/drivers/Makefile +@@ -0,0 +1,25 @@ ++obj-y += char/ ++obj-y += clk/ ++obj-y += clocksource/ ++obj-y += crypto/ ++obj-y += dma/ ++obj-y += i2c/ ++obj-y += video/ ++obj-y += media/ ++obj-y += mfd/ ++obj-y += misc/ ++obj-y += mmc/ ++obj-y += mtd/ ++obj-y += net/ ++obj-y += pinctrl/ ++obj-y += power/ ++obj-y += pwm/ ++#obj-y += regulator/ ++#obj-y += remoteproc/ ++obj-y += spi/ ++obj-y += tty/ ++obj-y += rtc/ ++obj-y += watchdog/ ++obj-y += irqchip/ ++obj-y += input/ ++obj-y += md_export/ +diff --git a/module_drivers/drivers/char/Makefile b/module_drivers/drivers/char/Makefile +new file mode 100644 +index 000000000..ae402d410 +--- /dev/null ++++ b/module_drivers/drivers/char/Makefile +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_INGENIC_CDBUS) += ingenic_cdbus.o ++obj-$(CONFIG_HW_RANDOM) += hw_random/ +diff --git a/module_drivers/drivers/char/hw_random/Kconfig b/module_drivers/drivers/char/hw_random/Kconfig +new file mode 100644 +index 000000000..c96be1d94 +--- /dev/null ++++ b/module_drivers/drivers/char/hw_random/Kconfig +@@ -0,0 +1,12 @@ ++config HW_RANDOM_INGENIC ++ tristate "[RANDOM] Ingenic HW Random Number Generator support" ++ depends on MIPS ++ help ++ This driver provides kernel-side support for the Random Number ++ Generator hardware found on Ingenic processors. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ingenic-rng. ++ ++ If unsure, say N. ++ +diff --git a/module_drivers/drivers/char/hw_random/Makefile b/module_drivers/drivers/char/hw_random/Makefile +new file mode 100644 +index 000000000..e89c182cc +--- /dev/null ++++ b/module_drivers/drivers/char/hw_random/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_HW_RANDOM_INGENIC) += ingenic-rng.o +diff --git a/module_drivers/drivers/char/hw_random/ingenic-rng.c b/module_drivers/drivers/char/hw_random/ingenic-rng.c +new file mode 100644 +index 000000000..8334de3af +--- /dev/null ++++ b/module_drivers/drivers/char/hw_random/ingenic-rng.c +@@ -0,0 +1,284 @@ ++ ++/* ++ * dtrng driver of Ingenic's SoC X2000 ++ * ++ * Copyright (C) 2020 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Author: wenshuo.song ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TRNG_INT_SWITCH ++#undef TRNG_INT_SWITCH ++ ++#define TRNG_CFG 0x00 ++#define TRNG_RANDOMNUM 0x04 ++#define TRNG_STATUS 0x08 ++ ++#define TRNG_CFG_RDY_CLR (1 << 12) ++#define TRNG_CFG_GEN_EN (1 << 0) ++#define TRNG_CFG_INT_MASK (1 << 11) ++ ++/*f(clk)=f(pclk)/(div_num+1)*/ ++#define TRNG_CFG_DIV_NUM 0x00 ++ ++struct ingenic_trng { ++ int irq; ++ struct clk *clk_gate; ++ void __iomem *base; ++ struct hwrng rng; ++}; ++ ++ ++ ++static irqreturn_t ingenic_trng_interrupt(int irq, void *dev_id) ++{ ++ ++ unsigned int trng_cfg; ++ unsigned int trng_randomnum; ++ struct ingenic_trng *trng = (struct ingenic_trng *)(dev_id); ++ ++ //TODO? ++ ++ trng_randomnum = readl(trng->base + TRNG_RANDOMNUM); ++ ++ /* Clear the interupt */ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg |= TRNG_CFG_RDY_CLR; ++ writel(trng_cfg,trng->base + TRNG_CFG); ++ trng_cfg &= ~TRNG_CFG_RDY_CLR; ++ writel(trng_cfg,trng->base + TRNG_CFG); ++ ++ return IRQ_HANDLED; ++} ++ ++static void ingenic_trng_enable(struct hwrng *rng) ++{ ++ unsigned int trng_cfg; ++ struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng); ++ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg |= (1 << 0); ++ writel(trng_cfg, trng->base + TRNG_CFG); ++ ++} ++ ++static void ingenic_trng_disable(struct hwrng *rng) ++{ ++ unsigned int trng_cfg; ++ struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng); ++ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg &= ~(1 << 0); ++ writel(trng_cfg, trng->base + TRNG_CFG); ++ ++} ++ ++static int ingenic_trng_init(struct hwrng *rng) ++{ ++ ++ unsigned int trng_cfg; ++ struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng); ++ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg |= (1 << 0); ++ writel(trng_cfg, trng->base + TRNG_CFG); ++ ++ return 0; ++} ++ ++static void ingenic_trng_cleanup(struct hwrng *rng) ++{ ++ unsigned int trng_cfg; ++ struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng); ++ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg &= ~TRNG_CFG_GEN_EN; ++ writel(trng_cfg, trng->base + TRNG_CFG); ++} ++ ++static int ingenic_trng_read(struct hwrng *rng, void *buf, size_t max, ++ bool wait) ++{ ++ ++ ++ struct ingenic_trng *trng = container_of(rng, struct ingenic_trng, rng); ++ unsigned int trng_cfg; ++ u32 val,tmp_data; ++ u32 *data = buf; ++ int ret; ++ ++ ingenic_trng_enable(rng); ++ ++ /* data ready? */ ++ if (readl(trng->base + TRNG_STATUS) & 1) { ++ get_random_bytes(&val, sizeof(u32)); ++ tmp_data = readl(trng->base + TRNG_RANDOMNUM); ++ tmp_data ^= val; ++ *data = tmp_data; ++ ++ /* Clear the ramdom_rdy */ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg |= TRNG_CFG_RDY_CLR; ++ writel(trng_cfg,trng->base + TRNG_CFG); ++ trng_cfg &= ~TRNG_CFG_RDY_CLR; ++ writel(trng_cfg,trng->base + TRNG_CFG); ++ ++ ret = 4; ++ } else ++ ret = 0; ++ ++ ingenic_trng_disable(rng); ++ ++ return ret; ++} ++ ++static int ingenic_trng_probe(struct platform_device *pdev) ++{ ++ struct ingenic_trng *trng; ++ struct resource *res; ++ int ret; ++ ++ trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL); ++ if (!trng) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ trng->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(trng->base)) ++ return PTR_ERR(trng->base); ++ ++ trng->irq = platform_get_irq(pdev, 0); ++ if(trng->irq < 0){ ++ dev_err(&pdev->dev, "Cannot get %d IORESOURCE_IRQ\n",trng->irq); ++ return -ENOENT; ++ } ++ ++ trng->clk_gate = devm_clk_get(&pdev->dev, "gate_dtrng"); ++ if (IS_ERR(trng->clk_gate)) ++ return PTR_ERR(trng->clk_gate); ++ ++ ret = clk_prepare_enable(trng->clk_gate); ++ if (ret) ++ return ret; ++ ++ ++ trng->rng.name = pdev->name; ++ trng->rng.init = ingenic_trng_init; ++ trng->rng.cleanup = ingenic_trng_cleanup; ++ trng->rng.read = ingenic_trng_read; ++ ++#ifdef TRNG_INT_SWITCH ++ writel(readl(TRNG_CFG) & ~TRNG_CFG_INT_MASK, TRNG_CFG); ++ ret = request_irq(trng->irq,ingenic_trng_interrupt, ++ IRQF_SHARED | IRQF_TRIGGER_LOW,"trng-interrupt",trng); ++ if (ret) { ++ dev_err(&pdev->dev, "request_irq failed !! %d-\n",trng->irq); ++ goto err_register; ++ } ++#endif ++ ret = hwrng_register(&trng->rng); ++ if (ret) ++ goto err_register; ++ ++ platform_set_drvdata(pdev, trng); ++ ++ ingenic_trng_disable(&trng->rng); ++ ++ dev_info(&pdev->dev, "ingenic HW dtrng Probe success!\n"); ++ return 0; ++ ++err_register: ++ clk_disable(trng->clk_gate); ++ return ret; ++} ++ ++static int ingenic_trng_remove(struct platform_device *pdev) ++{ ++ struct ingenic_trng *trng = platform_get_drvdata(pdev); ++ unsigned int trng_cfg; ++ ++ hwrng_unregister(&trng->rng); ++ ++ trng_cfg = readl(trng->base + TRNG_CFG); ++ trng_cfg &= ~(1 << 0); ++ writel(trng_cfg, trng->base + TRNG_CFG); ++ ++ clk_disable_unprepare(trng->clk_gate); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ingenic_trng_suspend(struct device *dev) ++{ ++ struct ingenic_trng *trng = dev_get_drvdata(dev); ++ ++ clk_disable_unprepare(trng->clk_gate); ++ ++ return 0; ++} ++ ++static int ingenic_trng_resume(struct device *dev) ++{ ++ struct ingenic_trng *trng = dev_get_drvdata(dev); ++ ++ return clk_prepare_enable(trng->clk_gate); ++} ++ ++static const struct dev_pm_ops ingenic_trng_pm_ops = { ++ .suspend = ingenic_trng_suspend, ++ .resume = ingenic_trng_resume, ++}; ++#endif /* CONFIG_PM */ ++ ++static const struct of_device_id ingenic_trng_dt_ids[] = { ++ { .compatible = "ingenic,dtrng" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, ingenic_trng_dt_ids); ++ ++static struct platform_driver ingenic_trng_driver = { ++ .probe = ingenic_trng_probe, ++ .remove = ingenic_trng_remove, ++ .driver = { ++ .name = "ingenic-trng", ++#ifdef CONFIG_PM ++ .pm = &ingenic_trng_pm_ops, ++#endif /* CONFIG_PM */ ++ .of_match_table = ingenic_trng_dt_ids, ++ }, ++}; ++ ++module_platform_driver(ingenic_trng_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("wenshuo.song "); ++MODULE_DESCRIPTION("ingenic true random number generator driver"); +diff --git a/module_drivers/drivers/char/ingenic_cdbus.c b/module_drivers/drivers/char/ingenic_cdbus.c +new file mode 100644 +index 000000000..ba51c09df +--- /dev/null ++++ b/module_drivers/drivers/char/ingenic_cdbus.c +@@ -0,0 +1,733 @@ ++/* linux/drivers/char/jz_cdbus.c ++ * ++ * Ingenic cdbus driver, use kernel char device framework ++ * ++ * Copyright (c) 2021 Ingenic ++ * Author:zhangxu ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define VERSION 0x00 ++#define SETTING 0x04 ++#define IDLE_WAIT_LEN 0x08 ++#define TX_PERMIT_LEN 0x0c ++#define MAX_IDLE_LEN 0x10 ++#define TX_PRE_LEN 0x14 ++#define FILTER 0x18 ++#define DIV_LS 0x1c ++#define DIV_HS 0x20 ++#define INT_FLAG 0x24 ++#define INT_MASK 0x28 ++#define RX_CTRL 0x2c ++#define TX_CTRL 0x30 ++#define RX_PAGE_FLAG 0x34 ++#define FILTER_M 0x38 ++#define TX_FIFO 0x200 ++#define RX_FIFO 0x500 ++#define SELFTEST 0x900 ++ ++/* SETTING */ ++#define BIT_SETTING_TX_PUSH_PULL (1 << 0) ++#define BIT_SETTING_TX_INVERT (1 << 1) ++#define BIT_SETTING_USER_CRC (1 << 2) ++#define BIT_SETTING_NO_DROP (1 << 3) ++#define BIT_SETTING_ARBITRATION (1 << 4) ++#define BIT_SETTING_BREAK_SYNC (1 << 5) ++#define BIT_SETTING_FULL_DUPLEX (1 << 6) ++ ++/* INT_MASK */ ++#define BIT_MASK_BUS_IDLE (1 << 0) ++#define BIT_MASK_RX_PENDING (1 << 1) ++#define BIT_MASK_RX_BREAK (1 << 2) ++//#define BIT_MASK_RX_LOST (1 << 3) ++#define BIT_MASK_RX_ERROR (1 << 4) ++#define BIT_MASK_TX_PENDING (1 << 5) ++#define BIT_MASK_TX_CD (1 << 6) ++#define BIT_MASK_TX_ERROR (1 << 7) ++ ++/* INT_FLAG */ ++#define BIT_FLAG_BUS_IDLE (1 << 0) ++#define BIT_FLAG_RX_PENDING (1 << 1) ++#define BIT_FLAG_RX_BREAK (1 << 2) ++//#define BIT_FLAG_RX_LOST (1 << 3) ++#define BIT_FLAG_RX_ERROR (1 << 4) ++#define BIT_FLAG_TX_BUF_CLEAN (1 << 5) ++#define BIT_FLAG_TX_CD (1 << 6) ++#define BIT_FLAG_TX_ERROR (1 << 7) ++ ++/* TX_CTRL */ ++#define BIT_TX_RST_POINTER (1 << 0) ++#define BIT_TX_START (1 << 1) ++#define BIT_TX_CLR_CD (1 << 2) ++#define BIT_TX_CLR_ERROR (1 << 3) ++#define BIT_TX_ABORT (1 << 4) ++#define BIT_TX_SEND_BREAK (1 << 5) ++ ++/* RX_CTRL */ ++#define BIT_RX_RST_POINTER (1 << 0) ++#define BIT_RX_SWITCH_PAGE (1 << 1) ++#define BIT_RX_CLR_LOST (1 << 2) ++#define BIT_RX_CLR_ERROR (1 << 3) ++#define BIT_RX_RST (1 << 4) ++#define BIT_RX_CLR_BREAK (1 << 5) ++ ++ ++#define CDBUS_BUF_SIZE (4 * 6) ++#define CDBUS_KERNEL_BUF_SIZE 500 ++ ++struct cdbus_kernel_buf_info { ++ unsigned char data[CDBUS_KERNEL_BUF_SIZE][256]; ++ unsigned int wr_ptr; ++ unsigned int rd_ptr; ++}; ++ ++struct cdbus_buf_info { ++ unsigned char data[CDBUS_BUF_SIZE][256]; ++ unsigned int wr_ptr; ++ unsigned int rd_ptr; ++}; ++ ++struct cdbus_info { ++ unsigned int tx_flag; ++ unsigned int rx_flag; ++ unsigned int rx_buf_full; ++ unsigned int rx_underrun; ++ unsigned int tx_cd_flag; ++ unsigned int tx_err_flag; ++ unsigned int rx_err_flag; ++ unsigned int rx_break_flag; ++ unsigned int rx_page; ++ struct cdbus_buf_info tx_buf; ++ struct cdbus_buf_info rx_buf; ++}; ++ ++struct jz_cdbus { ++ int major; ++ int minor; ++ dev_t dev_num; ++ int nr_devs; ++ ++ struct class *class; ++ struct cdev cdev; ++ struct device *dev; ++ ++ void __iomem *iomem; ++ struct completion done_tx; ++ struct completion done_rx; ++ struct timer_list timer; ++ ++ struct cdbus_info *dev_info; ++ struct cdbus_buf_info *tx_buf_info; ++ struct cdbus_buf_info *rx_buf_info; ++ ++ struct cdbus_kernel_buf_info *rx_buf; ++}; ++ ++enum cdbus_ioctl_cmd { ++ CDBUS_A_MODE, ++ CDBUS_BS_MODE, ++ CDBUS_HAIF_FULL_DUPLEX_MODE, ++ CDBUS_FULL_DUPLEX_MODE, ++ CDBUS_SET_LOW_RATE, ++ CDBUS_SET_HIGH_RATE, ++ CDBUS_WRITE_FILTER, ++ CDBUS_WRITE_FILTERM, ++ CDBUS_ENABLE_LOOPBACK, ++}; ++ ++static struct jz_cdbus *global_cdbus; ++ ++static unsigned char *cdbus_kernel_buf_get_wr_ptr(struct cdbus_kernel_buf_info *buf) ++{ ++ return buf->data[buf->wr_ptr % CDBUS_KERNEL_BUF_SIZE]; ++} ++ ++static unsigned char *cdbus_kernel_buf_get_rd_ptr(struct cdbus_kernel_buf_info *buf) ++{ ++ return buf->data[buf->rd_ptr % CDBUS_KERNEL_BUF_SIZE]; ++} ++ ++static int cdbus_kernel_buf_is_full(struct cdbus_kernel_buf_info *buf) ++{ ++ return buf->wr_ptr - buf->rd_ptr == CDBUS_KERNEL_BUF_SIZE; ++} ++ ++static int cdbus_kernel_buf_is_empty(struct cdbus_kernel_buf_info *buf) ++{ ++ return buf->wr_ptr == buf->rd_ptr; ++} ++ ++static unsigned char *cdbus_buf_get_wr_ptr(struct cdbus_buf_info *buf) ++{ ++ return buf->data[buf->wr_ptr % CDBUS_BUF_SIZE]; ++} ++ ++static unsigned char *cdbus_buf_get_rd_ptr(struct cdbus_buf_info *buf) ++{ ++ return buf->data[buf->rd_ptr % CDBUS_BUF_SIZE]; ++} ++ ++static int cdbus_buf_is_full(struct cdbus_buf_info *buf) ++{ ++ return buf->wr_ptr - buf->rd_ptr == CDBUS_BUF_SIZE; ++} ++ ++static int cdbus_buf_is_empty(struct cdbus_buf_info *buf) ++{ ++ return buf->wr_ptr == buf->rd_ptr; ++} ++ ++static int cdbus_buf_get_valid_len(struct cdbus_buf_info *buf) ++{ ++ return (buf->wr_ptr - buf->rd_ptr); ++} ++ ++static void ingenic_cdbus_reset_rx_block(struct jz_cdbus *cdbus) ++{ ++ writel(1 << 4, cdbus->iomem + RX_CTRL); ++ cdbus->dev_info->rx_page = 0; ++} ++ ++ ++static unsigned int ingenic_cdbus_recv_frame(struct jz_cdbus *cdbus, unsigned char *buf) ++{ ++ unsigned int frm_len, data_len; ++ unsigned char *rx_buf = cdbus_buf_get_rd_ptr(cdbus->rx_buf_info); ++ ++ data_len = rx_buf[2] & 0xff; ++ frm_len = data_len + 3; ++ memcpy(buf, rx_buf, frm_len); ++ ++ cdbus->rx_buf_info->rd_ptr++; ++ ++ return frm_len; ++} ++ ++static int ingenic_cdbus_send_frame(struct jz_cdbus *cdbus, unsigned char *buf, int frm_len) ++{ ++ unsigned char *tx_buf = cdbus_buf_get_wr_ptr(cdbus->tx_buf_info); ++ ++ memcpy(tx_buf, buf, frm_len); ++ cdbus->tx_buf_info->wr_ptr++; ++ ++ if (cdbus_buf_get_valid_len(cdbus->tx_buf_info) == 1) { ++ writel(readl(cdbus->iomem + INT_MASK) | (1 << 5), cdbus->iomem + INT_MASK); ++ } ++ ++ return 0; ++} ++ ++static int ingenic_cdbus_send_frame_to_user(struct jz_cdbus *cdbus, unsigned char **buf) ++{ ++ unsigned int frm_len, data_len; ++ unsigned char *rx_buf = cdbus_kernel_buf_get_rd_ptr(cdbus->rx_buf); ++ ++ data_len = rx_buf[2] & 0xff; ++ frm_len = data_len + 3; ++ ++ *buf = rx_buf; ++ cdbus->rx_buf->rd_ptr++; ++ ++ //printk("%s():%d >>> ##### read buffer >>> wr_ptr = %d, rd_ptr = %d\n", __func__, __LINE__, cdbus->rx_buf->wr_ptr, cdbus->rx_buf->rd_ptr); ++ return frm_len; ++} ++ ++static unsigned int ingenic_cdbus_recv_frame_from_mcu(struct jz_cdbus *cdbus) ++{ ++ unsigned char *rx_buf; ++ unsigned int frm_len; ++ ++ while (!cdbus_buf_is_empty(cdbus->rx_buf_info)) { ++ rx_buf = cdbus_kernel_buf_get_wr_ptr(cdbus->rx_buf); ++ frm_len = ingenic_cdbus_recv_frame(cdbus, rx_buf); ++ cdbus->rx_buf->wr_ptr++; ++ //printk("%s():%d >>> ##### write buffer >>> wr_ptr = %d, rd_ptr = %d\n", __func__, __LINE__, cdbus->rx_buf->wr_ptr, cdbus->rx_buf->rd_ptr); ++ } ++ ++ return 0; ++} ++ ++extern void mygpio_cdbus_output(unsigned gpio, int value); ++int ingenic_cdbus_irq_handler(void) ++{ ++ struct jz_cdbus *cdbus = global_cdbus; ++ ++ /* Receive */ ++ if (cdbus->dev_info->rx_flag == 1) { ++#if 1 ++ if (!cdbus_kernel_buf_is_full(cdbus->rx_buf)) { ++ // printk("%s:%d >>> kernel buffer is not full!\n", __func__, __LINE__); ++ ingenic_cdbus_recv_frame_from_mcu(cdbus); ++ //complete(&cdbus->done_rx); ++ } else { ++ cdbus->rx_buf->rd_ptr = 0; ++ cdbus->rx_buf->wr_ptr = 0; ++ printk("%s:%d >>> kernel buffer is full!\n", __func__, __LINE__); ++ } ++#endif ++ cdbus->dev_info->rx_flag = 0; ++ } ++ ++ /* Rxfifo underrun */ ++ if (cdbus->dev_info->rx_underrun != 0) { ++ //printk("Rxfifo Underrun:%d: wr_ptr = %d, rd_ptr = %d, rx_underrun = %d\n", __LINE__, cdbus->rx_buf_info->wr_ptr, cdbus->rx_buf_info->rd_ptr, cdbus->dev_info->rx_underrun); ++ printk("ru%d %d\n", cdbus->rx_buf_info->wr_ptr, cdbus->rx_buf_info->rd_ptr); ++ cdbus->dev_info->rx_underrun = 0; ++ } ++ ++ /* Rxfifo full */ ++ if (cdbus->dev_info->rx_buf_full != 0) { ++ //printk("Rxfifo Full:%d: wr_ptr = %d, rd_ptr = %d, rx_buf_full = %d\n", __LINE__, cdbus->rx_buf_info->wr_ptr, cdbus->rx_buf_info->rd_ptr, cdbus->dev_info->rx_buf_full); ++ printk("rf%d %d\n", cdbus->rx_buf_info->wr_ptr, cdbus->rx_buf_info->rd_ptr); ++ cdbus->dev_info->rx_buf_full = 0; ++ cdbus->rx_buf_info->rd_ptr = 0; ++ cdbus->rx_buf_info->wr_ptr = 0; ++ } ++ ++#if 1 ++ /* Send */ ++ if (cdbus->dev_info->tx_flag == 1) { ++ if (!cdbus_buf_is_full(cdbus->tx_buf_info)) { ++ // printk("########%s:%d >>> tx_buf is not full\n", __func__, __LINE__); ++ complete(&cdbus->done_tx); ++ } ++ ++ cdbus->dev_info->tx_flag = 0; ++ } ++#endif ++ ++ /* Rx break */ ++ if (cdbus->dev_info->rx_break_flag == 1) { ++ dev_err(cdbus->dev, "%s():%d >>> Receive break character\n", __func__, __LINE__); ++ cdbus->dev_info->rx_break_flag = 0; ++ } ++ ++ /* Rx error */ ++ if (cdbus->dev_info->rx_err_flag == 1) { ++ dev_err(cdbus->dev, "%s():%d >>> RX error: frame broken\n", __func__, __LINE__); ++ cdbus->dev_info->rx_err_flag = 0; ++ } ++ ++ /* Tx collision detected */ ++ if (cdbus->dev_info->tx_cd_flag == 1) { ++ dev_err(cdbus->dev, "%s():%d >>> TX collision detected\n", __func__, __LINE__); ++ cdbus->dev_info->tx_cd_flag = 0; ++ } ++ ++ /* Tx error */ ++ if (cdbus->dev_info->tx_err_flag == 1) { ++ dev_err(cdbus->dev, "%s():%d >>> TX error: tx is 0, but rx is 1\n", __func__, __LINE__); ++ cdbus->dev_info->tx_err_flag = 0; ++ } ++ ++ return 0; ++} ++ ++static void ingenic_cdbus_timer_handler(unsigned long data) ++{ ++ struct jz_cdbus *cdbus = (struct jz_cdbus *)data; ++ ++ if (!cdbus_kernel_buf_is_empty(cdbus->rx_buf)) { ++ complete(&cdbus->done_rx); ++ } else { ++ printk("%s:%d >>> kernel buffer is empty\n", __func__, __LINE__); ++ } ++ ++ //cdbus->timer.expires = jiffies + msecs_to_jiffies(50); ++ cdbus->timer.expires = jiffies + usecs_to_jiffies(100); ++ add_timer(&cdbus->timer); ++} ++ ++//#define CDBUS_CPU_BREAK_SYNC_MODE ++/* ++ * Init cdbus controler ++ */ ++static void jz_cdbus_hw_init(struct jz_cdbus *cdbus) ++{ ++ /* Enable tx push-pull output */ ++#ifndef CDBUS_CPU_BREAK_SYNC_MODE ++ printk("%s:%d >>> mode CDBUS-A mode\n", __func__, __LINE__); ++ writel(BIT_SETTING_ARBITRATION | BIT_SETTING_TX_PUSH_PULL, cdbus->iomem + SETTING); ++#else ++ printk("%s:%d >>> mode CDBUS-BS mode\n", __func__, __LINE__); ++ writel(BIT_SETTING_BREAK_SYNC | BIT_SETTING_TX_PUSH_PULL, cdbus->iomem + SETTING); ++#endif ++ ++ /* Set baudrates */ ++ // CDBUS dve_clk = 150Mhz ++#ifndef CDBUS_CPU_BREAK_SYNC_MODE ++ /* a mode */ ++ printk("%s:%d >>> clock CDBUS-A mode\n", __func__, __LINE__); ++ writel(149, cdbus->iomem + DIV_LS); // low_speed rate = 1Mhz ++ writel(14, cdbus->iomem + DIV_HS); // high_speed rate = 10Mhz ++#else ++ /* bs mode */ ++ printk("%s:%d >>> clock CDBUS-BS mode\n", __func__, __LINE__); ++ writel(14, cdbus->iomem + DIV_LS); // low_speed rate = 50Mhz ++ writel(14, cdbus->iomem + DIV_HS); // high_speed rate = 50Mhz ++#endif ++ ++ /* Clean RX buffer */ ++ //writel(BIT_RX_RST_POINTER, cdbus->iomem + RX_CTRL); ++ ++ /* Enable interrupts */ ++#ifndef CDBUS_CPU_BREAK_SYNC_MODE ++ printk("%s:%d >>> interrupt CDBUS-A mode\n", __func__, __LINE__); ++ writel(BIT_MASK_TX_ERROR | BIT_MASK_TX_CD | BIT_MASK_RX_ERROR | ++ BIT_MASK_RX_BREAK | BIT_MASK_RX_PENDING, cdbus->iomem + INT_MASK); ++#else ++ printk("%s:%d >>> interrupt CDBUS-BS mode\n", __func__, __LINE__); ++ writel(BIT_MASK_TX_ERROR | BIT_MASK_TX_CD | BIT_MASK_RX_ERROR | ++ BIT_MASK_RX_PENDING, cdbus->iomem + INT_MASK); ++#endif ++ ++ /* Set time length */ ++ writel(1, cdbus->iomem + TX_PERMIT_LEN); ++ writel(1, cdbus->iomem + MAX_IDLE_LEN); ++ writel(1, cdbus->iomem + IDLE_WAIT_LEN); ++ ++ /* Set local address and Multicast filter */ ++ writel(0x0, cdbus->iomem + FILTER); ++ writel(0x0, cdbus->iomem + FILTER_M); ++} ++ ++static int jz_cdbus_open(struct inode *inode, struct file *filp) ++{ ++ struct jz_cdbus *cdbus; ++ unsigned int mcu_ddr = *(volatile unsigned int *)(0xb342201c); ++ ++ cdbus = container_of(inode->i_cdev, struct jz_cdbus, cdev); ++ if (!cdbus) ++ return -EINVAL; ++ filp->private_data = cdbus; ++ ++#if 1 ++ mcu_ddr = ((mcu_ddr & 0xffff) + 0x2000) | 0xb3420000; ++ cdbus->dev_info = (struct cdbus_info *)mcu_ddr; ++ ++ cdbus->tx_buf_info = &cdbus->dev_info->tx_buf; ++ cdbus->rx_buf_info = &cdbus->dev_info->rx_buf; ++ cdbus->rx_buf_info->rd_ptr = 0; ++ cdbus->rx_buf_info->wr_ptr = 0; ++ cdbus->tx_buf_info->rd_ptr = 0; ++ cdbus->tx_buf_info->wr_ptr = 0; ++ cdbus->dev_info->rx_underrun = 0; ++ cdbus->dev_info->rx_buf_full = 0; ++ cdbus->dev_info->tx_cd_flag = 0; ++ cdbus->dev_info->tx_err_flag = 0; ++ cdbus->dev_info->rx_err_flag = 0; ++ cdbus->dev_info->rx_break_flag = 0; ++ cdbus->dev_info->rx_page = 0; ++ ++ //cdbus->rx_buf = devm_kzalloc(cdbus->dev, sizeof(struct cdbus_kernel_buf_info), GFP_KERNEL); ++ cdbus->rx_buf = kzalloc(sizeof(struct cdbus_kernel_buf_info), GFP_KERNEL); ++ if (!cdbus->rx_buf) { ++ printk("%s:%d >>> rx_buf kzalloc failed!\n", __func__, __LINE__); ++ return -ENOMEM; ++ } ++ ++ ++ cdbus->rx_buf->rd_ptr = 0; ++ cdbus->rx_buf->wr_ptr = 0; ++#endif ++ ++ jz_cdbus_hw_init(cdbus); ++ ++ return 0; ++} ++ ++int cdbus_debug = 0; ++static int jz_cdbus_read(struct file *filp, char *user_buf, size_t count, loff_t *f_pos) ++{ ++ struct jz_cdbus *cdbus = filp->private_data; ++ //unsigned char rx_buf[256]; ++ unsigned char *rx_buf; ++ int frm_len; ++ ++ if (!cdbus_debug) { ++ printk("cdbus debug\n"); ++ cdbus_debug = 1; ++ } ++ ++#if 1 ++ if (cdbus_kernel_buf_is_empty(cdbus->rx_buf)) { ++ //printk("%s:%d >>> kernel buffer is empty\n", __func__, __LINE__); ++ return -1; ++ } ++#endif ++#if 0 ++ wait_for_completion_interruptible(&cdbus->done_rx); ++#endif ++ frm_len = ingenic_cdbus_send_frame_to_user(cdbus, &rx_buf); ++ copy_to_user(user_buf, rx_buf, frm_len); ++ ++ return frm_len; ++} ++ ++static int jz_cdbus_write(struct file *filp, const char *user_buf, size_t count, loff_t *f_pos) ++{ ++ struct jz_cdbus *cdbus = filp->private_data; ++ unsigned char tx_buf[256]; ++ ++ copy_from_user(tx_buf, user_buf, count); ++ ingenic_cdbus_send_frame(cdbus, tx_buf, count); ++#if 1 ++ wait_for_completion_interruptible(&cdbus->done_tx); ++#endif ++ ++ return count; ++} ++ ++static long jz_cdbus_ioctl(struct file *filp, unsigned int cmd, unsigned long args) ++{ ++ int ret = 0; ++ struct jz_cdbus *cdbus = filp->private_data; ++ ++ switch (cmd) { ++ case CDBUS_A_MODE: ++ writel(readl(cdbus->iomem + SETTING) & ~(0x7 << 4), cdbus->iomem + SETTING); ++ writel(readl(cdbus->iomem + SETTING) | BIT_SETTING_ARBITRATION, cdbus->iomem + SETTING); ++ break; ++ case CDBUS_BS_MODE: ++ writel(readl(cdbus->iomem + SETTING) & ~(0x7 << 4), cdbus->iomem + SETTING); ++ writel(readl(cdbus->iomem + SETTING) | BIT_SETTING_BREAK_SYNC, cdbus->iomem + SETTING); ++ break; ++ case CDBUS_HAIF_FULL_DUPLEX_MODE: ++ writel(readl(cdbus->iomem + SETTING) & ~(0x7 << 4), cdbus->iomem + SETTING); ++ break; ++ case CDBUS_FULL_DUPLEX_MODE: ++ writel(readl(cdbus->iomem + SETTING) & ~(0x7 << 4), cdbus->iomem + SETTING); ++ writel(readl(cdbus->iomem + SETTING) | BIT_SETTING_FULL_DUPLEX, cdbus->iomem + SETTING); ++ break; ++ case CDBUS_SET_LOW_RATE: ++ writel(150 / args - 1, cdbus->iomem + DIV_LS); ++ break; ++ case CDBUS_SET_HIGH_RATE: ++ writel(150 / args - 1, cdbus->iomem + DIV_HS); ++ break; ++ case CDBUS_WRITE_FILTER: ++ writel(args, cdbus->iomem + FILTER); ++ break; ++ case CDBUS_WRITE_FILTERM: ++ writel(args, cdbus->iomem + FILTER_M); ++ break; ++ case CDBUS_ENABLE_LOOPBACK: ++ dev_info(cdbus->dev, "Loopback Mode\n"); ++ writel(0x1, cdbus->iomem + SELFTEST); ++ break; ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++static int jz_cdbus_close(struct inode *inode, struct file *filp) ++{ ++ struct jz_cdbus *cdbus = filp->private_data; ++ ++ /* Disable interrupts */ ++ writel(0x0, cdbus->iomem + INT_MASK); ++ kfree(cdbus->rx_buf); ++ ++ return 0; ++} ++ ++static struct file_operations jz_cdbus_ops = { ++ .owner = THIS_MODULE, ++ .write = jz_cdbus_write, ++ .read = jz_cdbus_read, ++ .open = jz_cdbus_open, ++ .release = jz_cdbus_close, ++ .unlocked_ioctl = jz_cdbus_ioctl, ++}; ++ ++static int jz_cdbus_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct jz_cdbus *cdbus; ++ struct resource *res; ++ dev_t devno; ++ struct clk *clk_cgu; ++ struct clk *clk_gate; ++ unsigned int cdbus_clk_freq = 150000000; ++ ++ cdbus = devm_kzalloc(&pdev->dev, sizeof(struct jz_cdbus), GFP_KERNEL); ++ if (!cdbus) ++ return -ENOMEM; ++ ++ global_cdbus = cdbus; ++ ++ cdbus->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); ++ return -ENODEV; ++ } ++ ++ cdbus->iomem = devm_ioremap(cdbus->dev, res->start, res->end - res->start + 1); ++ if (!cdbus->iomem) { ++ dev_err(&pdev->dev, "ioremap failed!\n"); ++ return -ENOMEM; ++ } ++ ++ platform_set_drvdata(pdev, cdbus); ++ ++ init_completion(&cdbus->done_tx); ++ init_completion(&cdbus->done_rx); ++ ++ clk_gate = devm_clk_get(&pdev->dev, "gate_cdbus"); ++ if (IS_ERR(clk_gate)) { ++ dev_err(&pdev->dev, "%s Cannot get clock: %s\n", __func__, "gate_cdbus"); ++ goto __err0; ++ } ++ ++ clk_cgu = devm_clk_get(&pdev->dev, "div_cdbus"); ++ if (IS_ERR(clk_cgu)) { ++ dev_err(&pdev->dev, "%s Cannot get clock: %s\n", __func__, "div_cdbus"); ++ goto __err0; ++ } ++ ++ clk_set_parent(clk_get(NULL, "mux_cdbus"), clk_get(NULL, "epll")); ++ ++ if (clk_set_rate(clk_cgu, cdbus_clk_freq)) { ++ dev_err(&pdev->dev, "Set cgu_cdbus clk rate faild\n"); ++ goto __err0; ++ } ++ ++ if ((ret = clk_prepare_enable(clk_gate)) < 0) { ++ dev_err(&pdev->dev, "Enable gate_cdbus clk failed\n"); ++ goto __err0; ++ } ++ ++ //printk("############# cdbus clock: clk_get_clk = %ld, set clk = %d\n", clk_get_rate(clk_cgu), cdbus_clk_freq); ++ ++ cdbus->minor = 0; ++ cdbus->nr_devs = 1; ++ ret = alloc_chrdev_region(&devno, cdbus->minor, cdbus->nr_devs, "jz-cdbus"); ++ if (ret) { ++ dev_err(cdbus->dev, "alloc chrdev failed\n"); ++ return ret; ++ } ++ cdbus->major = MAJOR(devno); ++ cdbus->dev_num = MKDEV(cdbus->major, cdbus->minor); ++ dev_dbg(&pdev->dev, "%s():%d >>> cdbus->major = %d, cdbus->minor = %d, cdbus->dev_num = %x\n", ++ __func__, __LINE__, cdbus->major, cdbus->minor, cdbus->dev_num); ++ ++ cdev_init(&cdbus->cdev, &jz_cdbus_ops); ++ cdbus->cdev.owner = THIS_MODULE; ++ cdev_add(&cdbus->cdev, cdbus->dev_num, 1); ++ if (ret) { ++ dev_err(cdbus->dev, "cdev_add failed\n"); ++ goto __err1; ++ } ++ ++ cdbus->class = class_create(THIS_MODULE, "jz-cdbus"); ++ if (IS_ERR(cdbus->class)) { ++ dev_err(cdbus->dev, "class_create failed\n"); ++ ret = PTR_ERR(cdbus->class); ++ goto __err2; ++ } ++ ++ cdbus->dev = device_create(cdbus->class, NULL, cdbus->dev_num, NULL, "cdbus"); ++ if (IS_ERR(cdbus->dev)) { ++ dev_err(cdbus->dev, "device_create failed\n"); ++ ret = PTR_ERR(cdbus->dev); ++ goto __err3; ++ } ++ ++ init_timer(&cdbus->timer); ++ cdbus->timer.expires = jiffies + msecs_to_jiffies(100); ++ cdbus->timer.function = ingenic_cdbus_timer_handler; ++ cdbus->timer.data = (unsigned long)cdbus; ++ ++ dev_info(cdbus->dev, "Ingenic cdbus driver init successfully!\n"); ++ ++ return 0; ++ ++__err3: ++ class_destroy(cdbus->class); ++__err2: ++ cdev_del(&cdbus->cdev); ++__err1: ++ unregister_chrdev_region(cdbus->dev_num, cdbus->nr_devs); ++__err0: ++ return ret; ++} ++ ++static int jz_cdbus_remove(struct platform_device *pdev) ++{ ++ struct jz_cdbus *cdbus = platform_get_drvdata(pdev); ++ ++ device_destroy(cdbus->class, cdbus->dev_num); ++ class_destroy(cdbus->class); ++ cdev_del(&cdbus->cdev); ++ unregister_chrdev_region(cdbus->dev_num, cdbus->nr_devs); ++ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_cdbus_match[] = { ++ { .compatible = "ingenic,x1600-cdbus", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, ingenic_cdbus_match); ++ ++static struct platform_driver jz_cdbus_driver = { ++ .probe = jz_cdbus_probe, ++ .remove = jz_cdbus_remove, ++ .driver = { ++ .name = "jz-cdbus", ++ .owner = THIS_MODULE, ++ .of_match_table = ingenic_cdbus_match, ++ }, ++}; ++ ++static int __init jz_cdbus_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&jz_cdbus_driver); ++ if (ret) ++ platform_driver_unregister(&jz_cdbus_driver); ++ ++ return ret; ++} ++ ++static void __exit jz_cdbus_exit(void) ++{ ++ platform_driver_unregister(&jz_cdbus_driver); ++} ++ ++module_init(jz_cdbus_init); ++module_exit(jz_cdbus_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Ingenic cdbus driver"); ++MODULE_AUTHOR("xu.zhang@ingenic.com"); ++ +diff --git a/module_drivers/drivers/clk/Makefile b/module_drivers/drivers/clk/Makefile +new file mode 100644 +index 000000000..e55de3616 +--- /dev/null ++++ b/module_drivers/drivers/clk/Makefile +@@ -0,0 +1 @@ ++obj-y += ingenic-v2/ +diff --git a/module_drivers/drivers/clk/ingenic-v2/Kconfig b/module_drivers/drivers/clk/ingenic-v2/Kconfig +new file mode 100644 +index 000000000..659f97293 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/Kconfig +@@ -0,0 +1,49 @@ ++config COMMON_CLK_INGENIC ++ bool ++ depends on MACH_XBURST || MACH_XBURST2 ++ select MFD_SYSCON ++ select INGENIC_CLK_DEBUG_FS ++ ++config INGENIC_CLK_DEBUG_FS ++ bool ++ depends on DEBUG_FS ++ help ++ enable ingenic common clock debugfs ++ ++ ++config CLK_X2000 ++ bool "clk x2000" ++ depends on SOC_X2000 ++ select COMMON_CLK_INGENIC ++ help ++ build the ingenic x2000 soc clock driver. ++ ++config CLK_X2100 ++ bool "clk x2100" ++ depends on SOC_X2100 ++ select COMMON_CLK_INGENIC ++ help ++ build the ingenic x2000-v12 soc clock driver. ++ ++config CLK_M300 ++ bool "clk m300" ++ depends on SOC_M300 ++ select COMMON_CLK_INGENIC ++ help ++ build the ingenic m300 soc clock driver. ++ ++ ++config CLK_X2500 ++ bool "clk x2500" ++ depends on SOC_X2500 ++ select COMMON_CLK_INGENIC ++ help ++ build the ingenic x2500 soc clock driver. ++ ++config CLK_X1600 ++ bool "clk x1600" ++ depends on SOC_X1600 ++ select COMMON_CLK_INGENIC ++ help ++ build the ingenic x1600 soc clock driver. ++ +diff --git a/module_drivers/drivers/clk/ingenic-v2/Makefile b/module_drivers/drivers/clk/ingenic-v2/Makefile +new file mode 100644 +index 000000000..43fcf84c8 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/Makefile +@@ -0,0 +1,35 @@ ++ ++ifdef CONFIG_CLK_X2000 ++ EXTRA_CFLAGS += -DCLK_PLL_V1 ++ CLK_PLL_V1 := y ++endif ++ifdef CONFIG_CLK_X2100 ++ EXTRA_CFLAGS += -DCLK_PLL_V1 ++ CLK_PLL_V1 := y ++endif ++ifdef CONFIG_CLK_M300 ++ EXTRA_CFLAGS += -DCLK_PLL_V1 ++ CLK_PLL_V1 := y ++endif ++ifdef CONFIG_CLK_X1600 ++ EXTRA_CFLAGS += -DCLK_PLL_V2 ++ CLK_PLL_V2 := y ++endif ++ifdef CONFIG_CLK_X2500 ++ EXTRA_CFLAGS += -DCLK_PLL_V2 ++ CLK_PLL_V2 := y ++endif ++ ++obj-$(CONFIG_COMMON_CLK_INGENIC) += clk.o clk-div.o clk-bus.o power-gate.o ++obj-$(CLK_PLL_V1) += clk-pll-v1.o ++obj-$(CLK_PLL_V2) += clk-pll-v2.o ++ ++ ++obj-$(CONFIG_CLK_X2000) += clk-x2000.o ++obj-$(CONFIG_CLK_X2100) += clk-x2000.o ++obj-$(CONFIG_CLK_M300) += clk-m300.o ++obj-$(CONFIG_CLK_X1600) += clk-x1600.o ++obj-$(CONFIG_CLK_X2500) += clk-x2500.o ++ ++ ++ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-bus.c b/module_drivers/drivers/clk/ingenic-v2/clk-bus.c +new file mode 100644 +index 000000000..7fa55378b +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-bus.c +@@ -0,0 +1,238 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "clk.h" ++ ++static int clk_bus_wait(void __iomem *reg, u8 shift) ++{ ++ unsigned int timeout = 0xfffff; ++ ++ while (((readl(reg) >> shift) & 1) && --timeout); ++ if (!timeout) { ++ printk("WARNING : why cannot wait bus stable ???\n"); ++ return -EIO; ++ } else { ++ return 0; ++ } ++} ++ ++struct clk_bus_divider { ++ struct clk_divider div; ++ const struct clk_ops *div_ops; ++ ++ void __iomem *busy_reg; ++ ++ int busy_shift; ++ int ce_shift; ++ ++ int shift1; ++ int width1; ++ int shift2; ++ int width2; ++ ++ int div_flags; ++ ++ spinlock_t * lock; ++}; ++ ++//static inline struct clk_bus *to_clk_bus_divider(struct clk_hw *hw) ++static inline struct clk_bus_divider *to_clk_bus_divider(struct clk_hw *hw) ++{ ++ struct clk_divider *div = container_of(hw, struct clk_divider, hw); ++ ++ return container_of(div, struct clk_bus_divider, div); ++} ++ ++static unsigned long clk_bus_divider_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_bus_divider *bus_div = to_clk_bus_divider(hw); ++ struct clk_divider *divider = &bus_div->div; ++ ++ divider->shift = bus_div->shift1; ++ divider->width = bus_div->width1; ++ ++ return bus_div->div_ops->recalc_rate(&bus_div->div.hw, parent_rate); ++} ++ ++static long clk_bus_divider_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_bus_divider *bus_div = to_clk_bus_divider(hw); ++ ++ return bus_div->div_ops->round_rate(&bus_div->div.hw, rate, prate); ++} ++ ++static int clk_bus_divider_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_bus_divider *bus_div = to_clk_bus_divider(hw); ++ struct clk_divider *divider = &bus_div->div; ++ int ret; ++ unsigned long flags = 0; ++ unsigned int val; ++ int ce = bus_div->ce_shift; ++ ++ ++ if(bus_div->lock) { ++ spin_lock_irqsave(bus_div->lock, flags); ++ } ++ ++ /* set bus rate . */ ++ if (bus_div->div_flags == BUS_DIV_SELF) { ++ ret = bus_div->div_ops->set_rate(&bus_div->div.hw, rate, parent_rate); ++ } else if (bus_div->div_flags == BUS_DIV_ONE) { ++ ++ divider->shift = bus_div->shift1; ++ divider->width = bus_div->width1; ++ ret = bus_div->div_ops->set_rate(&bus_div->div.hw, rate, parent_rate); ++ ++ divider->shift = bus_div->shift2; ++ divider->width = bus_div->width2; ++ ret = bus_div->div_ops->set_rate(&bus_div->div.hw, rate, parent_rate); ++ } else if (bus_div->div_flags == BUS_DIV_TWO) { ++ ++ divider->shift = bus_div->shift1; ++ divider->width = bus_div->width1; ++ ret = bus_div->div_ops->set_rate(&bus_div->div.hw, rate, parent_rate); ++ ++ divider->shift = bus_div->shift2; ++ divider->width = bus_div->width2; ++ ret = bus_div->div_ops->set_rate(&bus_div->div.hw, rate / 2, parent_rate); ++ } ++ ++ /* ce */ ++ if(ce > 0) { ++ val = readl(bus_div->div.reg); ++ val |= (1 << ce); ++ writel(val, bus_div->div.reg); ++ ++ ret = clk_bus_wait(bus_div->busy_reg, bus_div->busy_shift); ++ if(ret < 0) { ++ pr_err("wait bus clk: (%s) stable timeout!\n", __clk_get_name(hw->clk)); ++ } ++ ++ val &= ~(1 << ce); ++ writel(val, bus_div->div.reg); ++ } ++ if(bus_div->lock) { ++ spin_unlock_irqrestore(bus_div->lock, flags); ++ } ++ ++ return ret; ++} ++ ++ ++static struct clk_ops clk_bus_divider_ops = { ++ .recalc_rate = clk_bus_divider_recalc_rate, ++ .round_rate = clk_bus_divider_round_rate, ++ .set_rate = clk_bus_divider_set_rate, ++}; ++ ++struct clk *_register_bus_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift1, u8 width1, u8 shift2, u8 width2, ++ void __iomem *busy_reg, u8 busy_shift, ++ int ce_shift, ++ u8 clk_divider_flags, u8 div_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock) ++{ ++ struct clk_bus_divider *bus_div; ++ struct clk *clk; ++ struct clk_init_data init; ++ ++ bus_div = kzalloc(sizeof(*bus_div), GFP_KERNEL); ++ if (!bus_div) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ init.ops = &clk_bus_divider_ops; ++ init.flags = flags; ++ init.parent_names = (parent_name ? &parent_name: NULL); ++ init.num_parents = (parent_name ? 1 : 0); ++ ++ bus_div->busy_reg = busy_reg; ++ bus_div->busy_shift = busy_shift; ++ bus_div->ce_shift = ce_shift; ++ bus_div->lock = lock; ++ ++ bus_div->div.reg = reg; ++ bus_div->div.shift = shift1; ++ bus_div->div.width = width1; ++ bus_div->shift1 = shift1; ++ bus_div->width1 = width1; ++ bus_div->shift2 = shift2; ++ bus_div->width2 = width2; ++ //bus_div->div.lock = lock; ++ bus_div->div.lock = NULL; /* keep common block unlocked. add lock in this file */ ++ bus_div->div.table = table; ++ bus_div->div.flags = clk_divider_flags ; ++ bus_div->div_ops = &clk_divider_ops; ++ bus_div->div_flags = div_flags ; ++ ++ ++ bus_div->div.hw.init = &init; ++ ++ clk = clk_register(dev, &bus_div->div.hw); ++ if (IS_ERR(clk)) ++ kfree(bus_div); ++ ++ return clk; ++} ++ ++/** ++ * clk_register_bus_divider_table - register a table based divider clock with ++ * the clock framework ++ * @dev: device registering this clock ++ * @name: name of this clock ++ * @parent_name: name of clock's parent ++ * @flags: framework-specific flags ++ * @reg: register address to adjust divider ++ * @shift: number of bits to shift the bitfield ++ * @busy_reg: register address of busy bit waiting. ++ * @busy_shift: bit index of busy in busy register. ++ * @width: width of the bitfield ++ * @clk_divider_flags: divider-specific flags for this clock ++ * @table: array of divider/value pairs ending with a div set to 0 ++ * @lock: shared register lock for this clock ++ */ ++struct clk *clk_register_bus_divider_table(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift1, u8 width1, u8 shift2, u8 width2, ++ void __iomem *busy_reg, u8 busy_shift, int ce_shift, ++ u8 clk_divider_flags, u8 div_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock) ++{ ++ return _register_bus_divider(dev, name, parent_name, flags, reg, shift1, ++ width1, shift2, width2, busy_reg, busy_shift, ce_shift, clk_divider_flags, div_flags, table, lock); ++} ++ ++ ++/** ++ * clk_register_bus_divider - register a divider clock with the clock framework ++ * @dev: device registering this clock ++ * @name: name of this clock ++ * @parent_name: name of clock's parent ++ * @flags: framework-specific flags ++ * @reg: register address to adjust divider ++ * @shift: number of bits to shift the bitfield ++ * @width: width of the bitfield ++ * @busy_reg: register address of busy bit waiting. ++ * @busy_shift: bit index of busy in busy register. ++ * @clk_divider_flags: divider-specific flags for this clock ++ * @lock: shared register lock for this clock ++ */ ++struct clk *clk_register_bus_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift1 , u8 width1, u8 shift2, u8 width2, ++ void __iomem *busy_reg, u8 busy_shift, int ce_shift, ++ u8 clk_divider_flags, u8 div_flags, spinlock_t *lock) ++{ ++ return _register_bus_divider(dev, name, parent_name, flags, reg, shift1, width1, shift2, width2, busy_reg, busy_shift, ce_shift, clk_divider_flags, div_flags, NULL, lock); ++} ++ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-bus.h b/module_drivers/drivers/clk/ingenic-v2/clk-bus.h +new file mode 100644 +index 000000000..56e0b710b +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-bus.h +@@ -0,0 +1,24 @@ ++#ifndef __INGENIC_CLK_BUS_DIVIDER_H ++#define __INGENIC_CLK_BUS_DIVIDER_H ++ ++#define BUS_DIV_SELF BIT(6) + 1 ++#define BUS_DIV_ONE BIT(6) + 2 ++#define BUS_DIV_TWO BIT(6) + 3 ++#define BUS_DIV_THREE BIT(6) + 4 ++#define BUS_DIV_FORE BIT(6) + 5 ++ ++ ++struct clk *clk_register_bus_divider_table(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift1, u8 width1, u8 shift2, u8 width2, ++ void __iomem *busy_reg, u8 busy_shift, int ce_shift, ++ u8 clk_divider_flags, u8 divider_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock); ++ ++struct clk *clk_register_bus_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift1, u8 width1, u8 shift2, u8 width2, ++ void __iomem *busy_reg, u8 busy_shift, int ce_shift, ++ u8 clk_divider_flags, u8 divider_flags, spinlock_t *lock); ++#endif +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-div.c b/module_drivers/drivers/clk/ingenic-v2/clk-div.c +new file mode 100644 +index 000000000..49aebd46a +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-div.c +@@ -0,0 +1,258 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "clk.h" ++ ++ ++struct clk_cgu_divider { ++ struct clk_divider div; ++ const struct clk_ops *div_ops; ++ int busy_shift; ++ int en_shift; ++ int stop_shift; ++ spinlock_t *lock; ++}; ++ ++ ++static int clk_cgu_wait(void __iomem *reg, u8 shift) ++{ ++ unsigned int timeout = 0xfffff; ++ ++ while (((readl(reg) >> shift) & 1) && --timeout); ++ if (!timeout) { ++ printk("WARNING : why cannot wait cgu stable ???\n"); ++ return -ETIMEDOUT; ++ } else { ++ return 0; ++ } ++ ++} ++ ++static int cgu_divider_enable(struct clk_cgu_divider *cgu_div) ++{ ++ int ret; ++ unsigned int val; ++ int ce, stop; ++ ++ val = readl(cgu_div->div.reg); ++ ++ ce = cgu_div->en_shift; ++ stop = cgu_div->stop_shift; ++ ++ val |= (1 << ce); ++ val &= ~(1 << stop); ++ writel(val, cgu_div->div.reg); ++ ++ ret = clk_cgu_wait(cgu_div->div.reg, cgu_div->busy_shift); ++ if(ret < 0) { ++ printk("wait cgu stable timeout!\n"); ++ } ++ ++ val &= ~(1 << ce); ++ writel(val, cgu_div->div.reg); ++ ++ return ret; ++} ++ ++static void cgu_divider_disable(struct clk_cgu_divider *cgu_div) ++{ ++ unsigned int val; ++ int ce, stop; ++ ++ val = readl(cgu_div->div.reg); ++ ++ ce = cgu_div->en_shift; ++ stop = cgu_div->stop_shift; ++ ++ val |= (1 << ce); ++ val |= (1 << stop); ++ writel(val, cgu_div->div.reg); ++ ++ val &= ~(1 << ce); ++ writel(val, cgu_div->div.reg); ++ ++} ++ ++static inline struct clk_cgu_divider *to_clk_cgu_divider(struct clk_hw *hw) ++{ ++ struct clk_divider *div = container_of(hw, struct clk_divider, hw); ++ ++ return container_of(div, struct clk_cgu_divider, div); ++} ++ ++static unsigned long clk_cgu_divider_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_cgu_divider *cgu_div = to_clk_cgu_divider(hw); ++ struct clk_divider *divider = &cgu_div->div; ++ ++ return cgu_div->div_ops->recalc_rate(&cgu_div->div.hw, parent_rate); ++} ++ ++static long clk_cgu_divider_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_cgu_divider *cgu_div = to_clk_cgu_divider(hw); ++ unsigned long bestrate; ++ ++ return cgu_div->div_ops->round_rate(&cgu_div->div.hw, rate, prate); ++} ++ ++static int clk_cgu_divider_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) ++{ ++ struct clk_cgu_divider *cgu_div = to_clk_cgu_divider(hw); ++ struct clk_divider *divider = &cgu_div->div; ++ int ret; ++ unsigned long flags = 0; ++ ++ if(cgu_div->lock) ++ spin_lock_irqsave(cgu_div->lock, flags); ++ ++ ret = cgu_div->div_ops->set_rate(&cgu_div->div.hw, rate, parent_rate); ++ ++ cgu_divider_enable(cgu_div); ++ ++ ++ if(cgu_div->lock) ++ spin_unlock_irqrestore(cgu_div->lock, flags); ++ ++ return ret; ++} ++ ++static void clk_cgu_divider_disable(struct clk_hw *hw) ++{ ++ struct clk_cgu_divider *cgu_div = to_clk_cgu_divider(hw); ++ unsigned long flags = 0; ++ ++ if(cgu_div->lock) ++ spin_lock_irqsave(cgu_div->lock, flags); ++ ++ cgu_divider_disable(cgu_div); ++ ++ if(cgu_div->lock) ++ spin_unlock_irqrestore(cgu_div->lock, flags); ++ ++} ++ ++ ++static int clk_cgu_divider_enable(struct clk_hw *hw) ++{ ++ struct clk_cgu_divider *cgu_div = to_clk_cgu_divider(hw); ++ unsigned long flags = 0; ++ ++ if(cgu_div->lock) ++ spin_lock_irqsave(cgu_div->lock, flags); ++ ++ cgu_divider_enable(cgu_div); ++ ++ if(cgu_div->lock) ++ spin_unlock_irqrestore(cgu_div->lock, flags); ++ ++ return 0; ++} ++ ++static struct clk_ops clk_cgu_divider_ops = { ++ .recalc_rate = clk_cgu_divider_recalc_rate, ++ .round_rate = clk_cgu_divider_round_rate, ++ .set_rate = clk_cgu_divider_set_rate, ++ .enable = clk_cgu_divider_enable, ++ .disable = clk_cgu_divider_disable, ++}; ++ ++struct clk *_register_cgu_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift, u8 width, u8 busy_shift, ++ int en_shift, u8 stop_shift, u8 clk_divider_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock) ++{ ++ struct clk_cgu_divider *cgu_div; ++ struct clk *clk; ++ struct clk_init_data init; ++ ++ cgu_div = kzalloc(sizeof(*cgu_div), GFP_KERNEL); ++ if (!cgu_div) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ init.ops = &clk_cgu_divider_ops; ++ init.flags = flags; ++ init.parent_names = (parent_name ? &parent_name: NULL); ++ init.num_parents = (parent_name ? 1 : 0); ++ ++ cgu_div->busy_shift = busy_shift; ++ cgu_div->en_shift = en_shift; ++ cgu_div->stop_shift = stop_shift; ++ cgu_div->lock = lock; ++ ++ cgu_div->div.reg = reg; ++ cgu_div->div.shift = shift; ++ cgu_div->div.width = width; ++ //cgu_div->div.lock = lock; ++ cgu_div->div.lock = NULL; /* keep common block unlocked. add lock in this file */ ++ cgu_div->div.table = table; ++ cgu_div->div.flags = clk_divider_flags; ++ cgu_div->div_ops = &clk_divider_ops; ++ ++ ++ cgu_div->div.hw.init = &init; ++ ++ clk = clk_register(dev, &cgu_div->div.hw); ++ if (IS_ERR(clk)) ++ kfree(cgu_div); ++ ++ return clk; ++} ++ ++/** ++ * clk_register_divider_table - register a table based divider clock with ++ * the clock framework ++ * @dev: device registering this clock ++ * @name: name of this clock ++ * @parent_name: name of clock's parent ++ * @flags: framework-specific flags ++ * @reg: register address to adjust divider ++ * @shift: number of bits to shift the bitfield ++ * @busy_shift: bit index of busy in busy register. ++ * @width: width of the bitfield ++ * @clk_divider_flags: divider-specific flags for this clock ++ * @table: array of divider/value pairs ending with a div set to 0 ++ * @lock: shared register lock for this clock ++ */ ++struct clk *clk_register_cgu_divider_table(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift, u8 width, u8 busy_shift, ++ int en_shift, u8 stop_shift, u8 clk_divider_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock) ++{ ++ return _register_cgu_divider(dev, name, parent_name, flags, reg, shift, ++ width, busy_shift, en_shift, stop_shift, clk_divider_flags, table, lock); ++} ++ ++ ++/** ++ * clk_register_divider - register a divider clock with the clock framework ++ * @dev: device registering this clock ++ * @name: name of this clock ++ * @parent_name: name of clock's parent ++ * @flags: framework-specific flags ++ * @reg: register address to adjust divider ++ * @shift: number of bits to shift the bitfield ++ * @width: width of the bitfield ++ * @busy_shift: bit index of busy in busy register. ++ * @clk_divider_flags: divider-specific flags for this clock ++ * @lock: shared register lock for this clock ++ */ ++struct clk *clk_register_cgu_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift, u8 width, u8 busy_shift, ++ int en_shift, u8 stop_shift, ++ u8 clk_divider_flags, spinlock_t *lock) ++{ ++ return _register_cgu_divider(dev, name, parent_name, flags, reg, shift, width, busy_shift, en_shift, stop_shift, clk_divider_flags, NULL, lock); ++} ++ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-div.h b/module_drivers/drivers/clk/ingenic-v2/clk-div.h +new file mode 100644 +index 000000000..e9e9d9949 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-div.h +@@ -0,0 +1,18 @@ ++#ifndef __INGENIC_CLK_CGU_DIVIDER_H ++#define __INGENIC_CLK_CGU_DIVIDER_H ++ ++ ++struct clk *clk_register_cgu_divider_table(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift, u8 width, u8 busy_shift, ++ int en_shift, u8 stop_shift, u8 clk_divider_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock); ++ ++struct clk *clk_register_cgu_divider(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 shift, u8 width, u8 busy_shift, ++ int en_shift, u8 stop_shift, ++ u8 clk_divider_flags, spinlock_t *lock); ++ ++#endif /* __SAMSUNG_CLK_PLL_H */ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-m300.c b/module_drivers/drivers/clk/ingenic-v2/clk-m300.c +new file mode 100644 +index 000000000..40375492c +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-m300.c +@@ -0,0 +1,395 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "clk.h" ++ ++ ++ ++/******************************************************************************* ++ * FIXED CLK ++ ********************************************************************************/ ++static struct ingenic_fixed_rate_clock m300_fixed_rate_ext_clks[] __initdata = { ++ FRATE(CLK_EXT, "ext", NULL, 0, 24000000), ++ FRATE(CLK_RTC_EXT, "rtc_ext", NULL, 0, 32768), ++ FRATE(CLK_EXT_DIV_512, "ext_div_512", NULL,0, 46875), ++}; ++ ++ ++ ++/******************************************************************************* ++ * PLL ++ ********************************************************************************/ ++ ++static struct ingenic_pll_rate_table m300_pll_rate_table[] = { ++ PLL_RATE(1500000000, 124, 1, 1), ++ PLL_RATE(1200000000, 49, 0, 1), ++ PLL_RATE(800000000, 199, 2, 2), ++ PLL_RATE(600000000, 49, 0, 2), ++ PLL_RATE(300000000, 49, 0, 3), ++}; ++ ++ ++ ++/*PLL HWDESC*/ ++static struct ingenic_pll_hwdesc apll_hwdesc = \ ++ PLL_DESC(CPM_CPAPCR, 20, 9, 14, 6, 11, 3, 3, 0, pll_od_encode); ++ ++static struct ingenic_pll_hwdesc mpll_hwdesc = \ ++ PLL_DESC(CPM_CPMPCR, 20, 9, 14, 6, 11, 3, 3, 0, pll_od_encode); ++ ++static struct ingenic_pll_hwdesc epll_hwdesc = \ ++ PLL_DESC(CPM_CPEPCR, 20, 9, 14, 6, 11, 3, 3, 0, pll_od_encode); ++ ++ ++ ++static struct ingenic_pll_clock m300_pll_clks[] __initdata = { ++ PLL(CLK_PLL_APLL, "apll", "ext", &apll_hwdesc, m300_pll_rate_table), ++ PLL(CLK_PLL_MPLL, "mpll", "ext", &mpll_hwdesc, m300_pll_rate_table), ++ PLL(CLK_PLL_EPLL, "epll", "ext", &epll_hwdesc, m300_pll_rate_table), ++}; ++ ++ ++/******************************************************************************* ++ * MUX ++ ********************************************************************************/ ++PNAME(mux_table_0) = {"stop", "ext", "apll"}; ++PNAME(mux_table_1) = {"stop", "sclka", "mpll"}; ++PNAME(mux_table_2) = {"sclka", "mpll", "epll"}; ++PNAME(mux_table_3) = {"sclka", "mpll", "ext"}; ++PNAME(mux_table_4) = {"sclka", "epll"}; ++PNAME(mux_table_5) = {"mux_ahb2", "ext"}; ++PNAME(mux_table_6) = {"ext", "div_i2s3"}; ++PNAME(mux_table_7) = {"div_i2s0", "div_i2s1", "div_i2s2", "div_i2s3"}; ++PNAME(mux_table_8) = {"ext_div_512", "rtc_ext"}; ++ ++static unsigned int ingenic_mux_table[] = {0, 1, 2, 3}; ++ ++ ++static struct ingenic_mux_clock m300_mux_clks[] __initdata = { ++ MUX(CLK_MUX_SCLKA, "sclka", ingenic_mux_table, mux_table_0, CPM_CPCCR, 30, 2, 0), ++ MUX(CLK_MUX_CPU_L2C, "mux_cpu_l2c", ingenic_mux_table, mux_table_1, CPM_CPCCR, 28, 2, 0), ++ MUX(CLK_MUX_AHB0, "mux_ahb0", ingenic_mux_table, mux_table_1, CPM_CPCCR, 26, 2, 0), ++ MUX(CLK_MUX_AHB2, "mux_ahb2", ingenic_mux_table, mux_table_1, CPM_CPCCR, 24, 2, 0), ++ ++ MUX(CLK_MUX_DDR, "mux_ddr", ingenic_mux_table, mux_table_1, CPM_DDRCDR, 30, 2, 0), ++ MUX(CLK_MUX_MACPHY, "mux_macphy", ingenic_mux_table, mux_table_2, CPM_MACCDR, 30, 2, 0), ++ MUX(CLK_MUX_MACTXPHY, "mux_mactxphy", ingenic_mux_table, mux_table_2, CPM_MACTXCDR, 30, 2, 0), ++ MUX(CLK_MUX_MACTXPHY1, "mux_mactxphy1", ingenic_mux_table, mux_table_2, CPM_MACTXCDR1, 30, 2, 0), ++ MUX(CLK_MUX_MACPTP, "mux_macptp", ingenic_mux_table, mux_table_2, CPM_MACPTP, 30, 2, 0), ++ MUX(CLK_MUX_I2S0, "mux_i2s0", ingenic_mux_table, mux_table_4, CPM_I2S0CDR, 30, 1, 0), ++ MUX(CLK_MUX_I2S1, "mux_i2s1", ingenic_mux_table, mux_table_4, CPM_I2S1CDR, 30, 1, 0), ++ MUX(CLK_MUX_I2S2, "mux_i2s2", ingenic_mux_table, mux_table_4, CPM_I2S2CDR, 30, 1, 0), ++ MUX(CLK_MUX_I2S3, "mux_i2s3", ingenic_mux_table, mux_table_4, CPM_I2S3CDR, 30, 1, 0), ++ MUX(CLK_MUX_AUDIO_RAM, "mux_audio_ram", ingenic_mux_table, mux_table_5, CPM_AUDIOCR, 30, 1, 0), ++ MUX(CLK_MUX_SPDIF, "mux_spdif", ingenic_mux_table, mux_table_7, CPM_AUDIOCR, 3, 2, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), ++ MUX(CLK_MUX_PCM, "mux_pcm", ingenic_mux_table, mux_table_7, CPM_AUDIOCR, 1, 2, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), ++ MUX(CLK_MUX_DMIC, "mux_dmic", ingenic_mux_table, mux_table_6, CPM_AUDIOCR, 0, 1, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), ++ MUX(CLK_MUX_LCD, "mux_lcd", ingenic_mux_table, mux_table_2, CPM_LPCDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC0, "mux_msc0", ingenic_mux_table, mux_table_3, CPM_MSC0CDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC1, "mux_msc1", ingenic_mux_table, mux_table_3, CPM_MSC1CDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC2, "mux_msc2", ingenic_mux_table, mux_table_3, CPM_MSC2CDR, 30, 2, 0), ++ MUX(CLK_MUX_SFC, "mux_sfc", ingenic_mux_table, mux_table_2, CPM_SFCCDR, 30, 2, 0), ++ MUX(CLK_MUX_SSI, "mux_ssi", ingenic_mux_table, mux_table_2, CPM_SSICDR, 30, 2, 0), ++ MUX(CLK_MUX_CIM, "mux_cim", ingenic_mux_table, mux_table_2, CPM_CIMCDR, 30, 2, 0), ++ MUX(CLK_MUX_PWM, "mux_pwm", ingenic_mux_table, mux_table_2, CPM_PWMCDR, 30, 2, 0), ++ MUX(CLK_MUX_ISP, "mux_isp", ingenic_mux_table, mux_table_2, CPM_ISPCDR, 30, 2, 0), ++ MUX(CLK_MUX_RSA, "mux_rsa", ingenic_mux_table, mux_table_2, CPM_RSACDR, 30, 2, 0), ++ MUX(CLK_MUX_WDT, "mux_wdt", ingenic_mux_table, mux_table_8, CPM_OPCR, 2, 1, 0), ++ ++}; ++ ++/******************************************************************************* ++ * DIV BUS ++ ********************************************************************************/ ++ ++static struct ingenic_bus_clock m300_bus_div_clks[] __initdata = { ++ BUS_DIV(CLK_DIV_CPU, "div_cpu", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_L2C, "div_l2c", "mux_cpu_l2c", CPM_CPCCR, 4, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB0, "div_ahb0", "mux_ahb0", CPM_CPCCR, 8, 4, 0, 0, CPM_CPCSR, 1, 21, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB2, "div_ahb2", "mux_ahb2", CPM_CPCCR, 12, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_APB, "div_apb", "mux_ahb2", CPM_CPCCR, 16, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_CPU_L2C_X1, "div_cpu_l2c_x1", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_ONE), ++ BUS_DIV(CLK_DIV_CPU_L2C_X2, "div_cpu_l2c_x2", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_TWO), ++}; ++ ++ ++/******************************************************************************* ++ * DIV ++ ********************************************************************************/ ++ ++static struct clk_div_table m300_clk_div_table[256] = {}; ++ ++static struct ingenic_div_clock m300_div_clks[] __initdata = { ++ DIV(CLK_DIV_DDR, "div_ddr", "mux_ddr", CPM_DDRCDR, 4, 0, NULL), ++ DIV(CLK_DIV_MACPHY, "div_macphy", "mux_macphy", CPM_MACCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MACTXPHY, "div_mactxphy0", "mux_mactxphy", CPM_MACTXCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MACTXPHY1, "div_mactxphy1", "mux_mactxphy1", CPM_MACTXCDR1, 8, 0, NULL), ++ DIV(CLK_DIV_MACPTP, "div_macptp", "mux_macptp", CPM_MACPTP, 8, 0, NULL), ++ DIV(CLK_DIV_LCD, "div_lcd", "mux_lcd", CPM_LPCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MSC0, "div_msc0", "mux_msc0", CPM_MSC0CDR, 8, 0, m300_clk_div_table), ++ DIV(CLK_DIV_MSC1, "div_msc1", "mux_msc1", CPM_MSC1CDR, 8, 0, m300_clk_div_table), ++ DIV(CLK_DIV_MSC2, "div_msc2", "mux_msc2", CPM_MSC2CDR, 8, 0, m300_clk_div_table), ++ DIV(CLK_DIV_SFC, "div_sfc", "mux_sfc", CPM_SFCCDR, 8, 0, NULL), ++ DIV(CLK_DIV_SSI, "div_ssi", "mux_ssi", CPM_SSICDR, 8, 0, NULL), ++ DIV(CLK_DIV_CIM, "div_cim", "mux_cim", CPM_CIMCDR, 8, 0, NULL), ++ DIV(CLK_DIV_PWM, "div_pwm", "mux_pwm", CPM_PWMCDR, 4, 0, NULL), ++ DIV(CLK_DIV_ISP, "div_isp", "mux_isp", CPM_ISPCDR, 4, 0, NULL), ++ DIV(CLK_DIV_RSA, "div_rsa", "mux_rsa", CPM_RSACDR, 4, 0, NULL), ++ ++}; ++ ++/******************************************************************************* ++ * FRACTIONAL-DIVIDER ++ ********************************************************************************/ ++ ++static struct ingenic_fra_div_clock m300_fdiv_clks[] __initdata = { ++ FRA_DIV(CLK_DIV_I2S0, "div_i2s0", "mux_i2s0", CPM_I2S0CDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2S1, "div_i2s1", "mux_i2s1", CPM_I2S1CDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2S2, "div_i2s2", "mux_i2s2", CPM_I2S2CDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2S3, "div_i2s3", "mux_i2s3", CPM_I2S3CDR, 20, 9, 0, 20), ++}; ++ ++/******************************************************************************* ++ * GATE ++ ********************************************************************************/ ++static struct ingenic_gate_clock m300_gate_clks[] __initdata = { ++ ++ GATE(CLK_GATE_DDR, "gate_ddr", "div_ddr", CPM_CLKGR, 31, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++// GATE(CLK_GATE_IPU, "gate_ipu", "div_ipu", CPM_CLKGR, 30, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AHB0, "gate_ahb0", "div_ahb0", CPM_CLKGR, 29, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_APB0, "gate_apb0", "div_ahb0", CPM_CLKGR, 28, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_RTC, "gate_rtc", "rtc_ext", CPM_CLKGR, 27, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI1, "gate_ssi1", "div_ssi", CPM_CLKGR, 26, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_RSA, "gate_rsa", "div_rsa", CPM_CLKGR, 25, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AES, "gate_aes", "div_ahb2", CPM_CLKGR, 24, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_LCD, "gate_lcd", "div_lcd", CPM_CLKGR, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_CIM, "gate_cim", "div_cim", CPM_CLKGR, 22, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PDMA, "gate_pdma", "div_ahb2", CPM_CLKGR, 21, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OST, "gate_ost", "ext", CPM_CLKGR, 20, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI0, "gate_ssi0", "div_ssi", CPM_CLKGR, 19, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_TCU, "gate_tcu", "div_apb", CPM_CLKGR, 18, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DTRNG, "gate_dtrng", "div_apb", CPM_CLKGR, 17, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART2, "gate_uart2", "div_apb", CPM_CLKGR, 16, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART1, "gate_uart1", "div_apb", CPM_CLKGR, 15, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART0, "gate_uart0", "div_apb", CPM_CLKGR, 14, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SADC, "gate_sadc", "div_apb", CPM_CLKGR, 13, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_HELIX, "gate_helix", "div_ahb0", CPM_CLKGR, 12, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AUDIO, "gate_audio", "div_ahb2", CPM_CLKGR, 11, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB3, "gate_i2c3", "div_apb", CPM_CLKGR, 10, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB2, "gate_i2c2", "div_apb", CPM_CLKGR, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB1, "gate_i2c1", "div_apb", CPM_CLKGR, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB0, "gate_i2c0", "div_apb", CPM_CLKGR, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SCC, "gate_scc", "div_apb", CPM_CLKGR, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC1, "gate_msc1", "div_msc1", CPM_CLKGR, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC0, "gate_msc0", "div_msc0", CPM_CLKGR, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OTG, "gate_otg", "div_ahb2", CPM_CLKGR, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SFC, "gate_sfc", "div_sfc", CPM_CLKGR, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_EFUSE, "gate_efuse", "div_ahb2", CPM_CLKGR, 1, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_NEMC, "gate_nemc", "div_ahb2", CPM_CLKGR, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ARB, "gate_arb", "div_ahb0", CPM_CLKGR1, 30, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_DSI, "gate_dsi", "div_ahb0", CPM_CLKGR1, 29, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_CSI, "gate_csi", "div_ahb0", CPM_CLKGR1, 28, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_INTC, "gate_intc", "div_ahb2", CPM_CLKGR1, 26, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC2, "gate_msc2", "div_msc2", CPM_CLKGR1, 25, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_GMAC1, "gate_gmac1", "div_ahb2", CPM_CLKGR1, 24, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_GMAC0, "gate_gmac0", "div_ahb2", CPM_CLKGR1, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART9, "gate_uart9", "div_apb", CPM_CLKGR1, 22, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART8, "gate_uart8", "div_apb", CPM_CLKGR1, 21, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART7, "gate_uart7", "div_apb", CPM_CLKGR1, 20, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UATR6, "gate_uart6", "div_apb", CPM_CLKGR1, 19, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART5, "gate_uart5", "div_apb", CPM_CLKGR1, 18, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART4, "gate_uart4", "div_apb", CPM_CLKGR1, 17, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART3, "gate_uart3", "div_apb", CPM_CLKGR1, 16, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SPDIF, "gate_spdif", "mux_spdif", CPM_CLKGR1, 14, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DMIC, "gate_dmic", "mux_dmic", CPM_CLKGR1, 13, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PCM, "gate_pcm", "mux_pcm", CPM_CLKGR1, 12, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S3, "gate_i2s3", "div_i2s3", CPM_CLKGR1, 11, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S2, "gate_i2s2", "div_i2s2", CPM_CLKGR1, 10, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S1, "gate_i2s1", "div_i2s1", CPM_CLKGR1, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S0, "gate_i2s0", "div_i2s0", CPM_CLKGR1, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ROT, "gate_rot", "div_ahb0", CPM_CLKGR1, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_HASH, "gate_hash", "div_ahb2", CPM_CLKGR1, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PWM, "gate_pwm", "div_pwm", CPM_CLKGR1, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_FELIX, "gate_felix", "div_ahb0", CPM_CLKGR1, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ISP1, "gate_isp1", "div_apb", CPM_CLKGR1, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ISP0, "gate_isp0", "div_apb", CPM_CLKGR1, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB5, "gate_i2c5", "div_apb", CPM_CLKGR1, 1, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB4, "gate_i2c4", "div_apb", CPM_CLKGR1, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_USBPHY, "gate_usbphy", "div_apb", CPM_OPCR, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_CE_I2S0, "ce_i2s0", "div_i2s0", CPM_I2S0CDR, 29, 0, 0), ++ GATE(CLK_CE_I2S1, "ce_i2s1", "div_i2s1", CPM_I2S1CDR, 29, 0, 0), ++ GATE(CLK_CE_I2S2, "ce_i2s2", "div_i2s2", CPM_I2S2CDR, 29, 0, 0), ++ GATE(CLK_CE_I2S3, "ce_i2s3", "div_i2s3", CPM_I2S3CDR, 29, 0, 0), ++}; ++ ++static struct ingenic_gate_power m300_gate_power[] __initdata = { ++ ++ POWER(POWER_ISP0, "power_isp0", "gate_isp0", CPM_LCR, 31, 27, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ POWER(POWER_ISP1, "power_isp1", "gate_isp1", CPM_LCR, 30, 26, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ POWER(POWER_FELIX, "power_felix", "gate_felix", CPM_LCR, 29, 25, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ POWER(POWER_HELIX, "power_helix", "gate_helix", CPM_LCR, 28, 24, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ ++ POWER(PD_MEM_NEMC, "pd_mem_nemc", "gate_nemc", CPM_MPDCR, 28, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_USB, "pd_mem_usb", "gate_usb", CPM_MPDCR, 27, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SFC, "pd_mem_sfc", "gate_sfc", CPM_MPDCR, 26, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_PDMA_SEC, "pd_mem_pdma_sec", "gate_pdma", CPM_MPDCR, 25, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_PDMA, "pd_mem_pdma", "gate_pdma", CPM_MPDCR, 24, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC2, "pd_mem_msc2", "gate_msc2", CPM_MPDCR, 23, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC1, "pd_mem_msc1", "gate_msc1", CPM_MPDCR, 22, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC0, "pd_mem_msc0", "gate_msc0", CPM_MPDCR, 21, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_GMAC1, "pd_mem_gmac1", "gate_gmac1", CPM_MPDCR, 20, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_GMAC0, "pd_mem_gmac0", "gate_gmac0", CPM_MPDCR, 19, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DMIC, "pd_mem_dmic", "gate_dmic", CPM_MPDCR, 18, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_AUDIO, "pd_mem_audio", "gate_audio", CPM_MPDCR, 17, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_AES, "pd_mem_aes", "gate_aes", CPM_MPDCR, 16, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DSI, "pd_mem_dsi", "gate_dsi", CPM_MPDCR, 12, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SSI1, "pd_mem_ssi1", "gate_ssi1", CPM_MPDCR, 11, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SSI0, "pd_mem_ssi0", "gate_ssi0", CPM_MPDCR, 10, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART9, "pd_mem_uart9", "gate_uart9", CPM_MPDCR, 9, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART8, "pd_mem_uart8", "gate_uart8", CPM_MPDCR, 8, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART7, "pd_mem_uart7", "gate_uart7", CPM_MPDCR, 7, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART6, "pd_mem_uart6", "gate_uart6", CPM_MPDCR, 6, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART5, "pd_mem_uart5", "gate_uart5", CPM_MPDCR, 5, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART4, "pd_mem_uart4", "gate_uart4", CPM_MPDCR, 4, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART3, "pd_mem_uart3", "gate_uart3", CPM_MPDCR, 3, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART2, "pd_mem_uart2", "gate_uart2", CPM_MPDCR, 2, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART1, "pd_mem_uart1", "gate_uart1", CPM_MPDCR, 1, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART0, "pd_mem_uart0", "gate_uart0", CPM_MPDCR, 0, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_ROT, "pd_mem_rot", "gate_rot", CPM_MPDCR1, 8, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_CIM, "pd_mem_cim", "gate_cim", CPM_MPDCR1, 7, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DPU, "pd_mem_dpu", "gate_dpu", CPM_MPDCR1, 6, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH6, "pd_mem_ddr_ch6", "gate_ddr", CPM_MPDCR1, 5, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH5, "pd_mem_ddr_ch5", "gate_ddr", CPM_MPDCR1, 4, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH3, "pd_mem_ddr_ch3", "gate_ddr", CPM_MPDCR1, 3, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH1, "pd_mem_ddr_ch1", "gate_ddr", CPM_MPDCR1, 2, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH0, "pd_mem_ddr_ch0", "gate_ddr", CPM_MPDCR1, 1, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_TOP, "pd_mem_ddr_top", "gate_ddr", CPM_MPDCR1, 0, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ ++}; ++ ++static void clk_div_table_generate(void) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(m300_clk_div_table); i++) { ++ m300_clk_div_table[i].val = i; ++ m300_clk_div_table[i].div = (i + 1) * 4; ++ } ++ ++} ++ ++static const struct of_device_id ext_clk_match[] __initconst = { ++ { .compatible = "ingenic,fixed-clock", .data = (void *)0, }, ++ {}, ++}; ++ ++ ++struct ingenic_clk_reg_sleep m300_clk_reg_sleep[] = { ++ ++ REG_SLEEP(CPM_MACCDR, 29, 28, 0), ++ REG_SLEEP(CPM_MACTXCDR, 29, 28, 0), ++ REG_SLEEP(CPM_MACTXCDR1,29, 28, 0), ++ REG_SLEEP(CPM_MACPTP, 29, 28, 0), ++ REG_SLEEP(CPM_I2S0CDR, 0,0,0), ++ REG_SLEEP(CPM_I2S1CDR, 0,0,0), ++ REG_SLEEP(CPM_I2S2CDR, 0,0,0), ++ REG_SLEEP(CPM_I2S3CDR, 0,0,0), ++ REG_SLEEP(CPM_I2S0CDR1, 0,0,0), ++ REG_SLEEP(CPM_I2S1CDR1, 0,0,0), ++ REG_SLEEP(CPM_I2S2CDR1, 0,0,0), ++ REG_SLEEP(CPM_I2S3CDR1, 0,0,0), ++ REG_SLEEP(CPM_AUDIOCR, 0,0,0), ++ REG_SLEEP(CPM_LPCDR, 29,28,0), ++ REG_SLEEP(CPM_MSC0CDR, 29,28,0), ++ REG_SLEEP(CPM_MSC1CDR, 29,28,0), ++ REG_SLEEP(CPM_MSC2CDR, 29,28,0), ++ REG_SLEEP(CPM_SFCCDR, 29,28,0), ++ REG_SLEEP(CPM_SSICDR, 29,28,0), ++ REG_SLEEP(CPM_CIMCDR, 29,28,0), ++ REG_SLEEP(CPM_PWMCDR, 29,28,0), ++ REG_SLEEP(CPM_ISPCDR, 29,28,0), ++ REG_SLEEP(CPM_RSACDR, 29,28,0), ++}; ++ ++unsigned int m300_nr_clk_reg_sleep = ARRAY_SIZE(m300_clk_reg_sleep); ++ ++ ++/* Register m300 clocks. */ ++static void __init m300_clk_init(struct device_node *np, void __iomem *base) ++{ ++ struct ingenic_clk_provider *ctx; ++ void __iomem *reg_base; ++ ++ ++ printk("m300 Clock Power Management Unit init!\n"); ++ ++ reg_base = base; ++ ++ if (np) { ++ reg_base = of_iomap(np, 0); ++ if (!reg_base) ++ panic("%s: failed to map registers\n", __func__); ++ } ++ ++ ++ ctx = ingenic_clk_init(np, reg_base, NR_CLKS); ++ if (!ctx) ++ panic("%s: unable to allocate context.\n", __func__); ++ ++ /* Register Ext Clocks From DT */ ++ ingenic_clk_of_register_fixed_ext(ctx, m300_fixed_rate_ext_clks, ++ ARRAY_SIZE(m300_fixed_rate_ext_clks), ext_clk_match); ++ ++ /* Register PLLs. */ ++ ingenic_clk_register_pll(ctx, m300_pll_clks, ++ ARRAY_SIZE(m300_pll_clks), reg_base); ++ ++ ++ /* Register Muxs */ ++ ingenic_clk_register_mux(ctx, m300_mux_clks, ARRAY_SIZE(m300_mux_clks)); ++ ++ /* Register Bus Divs */ ++ ingenic_clk_register_bus_div(ctx, m300_bus_div_clks, ARRAY_SIZE(m300_bus_div_clks)); ++ ++ /* Register Divs */ ++ clk_div_table_generate(); ++ ingenic_clk_register_cgu_div(ctx, m300_div_clks, ARRAY_SIZE(m300_div_clks)); ++ ++ /* Register Fractional Divs */ ++ ingenic_clk_register_fra_div(ctx, m300_fdiv_clks, ARRAY_SIZE(m300_fdiv_clks)); ++ ++ /* Register Gates */ ++ ingenic_clk_register_gate(ctx, m300_gate_clks, ARRAY_SIZE(m300_gate_clks)); ++ ++ /* Register Powers */ ++ ingenic_power_register_gate(ctx, m300_gate_power, ARRAY_SIZE(m300_gate_power)); ++ ++ ++ ingenic_clk_of_add_provider(np, ctx); ++ ++ ++ ingenic_clk_sleep_init(reg_base, m300_clk_reg_sleep, m300_nr_clk_reg_sleep); ++ ++ ++// ingenic_clk_of_dump(ctx); ++ ++ ++ pr_info("=========== m300 clocks: =============\n" ++ "\tapll = %lu , mpll = %lu\n" ++ "\tcpu_clk = %lu , l2c_clk = %lu\n" ++ "\tahb0_clk = %lu , ahb2_clk = %lu\n" ++ "\tapb_clk = %lu , ext_clk = %lu\n\n", ++ _get_rate("apll"), _get_rate("mpll"), ++ _get_rate("div_cpu"), _get_rate("div_l2c"), ++ _get_rate("div_ahb0"), _get_rate("div_ahb2"), ++ _get_rate("div_apb"), _get_rate("ext")); ++ ++} ++ ++CLK_OF_DECLARE(m300_clk, "ingenic,m300-clocks", m300_clk_init); ++ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-pll-v1.c b/module_drivers/drivers/clk/ingenic-v2/clk-pll-v1.c +new file mode 100644 +index 000000000..3834cf9cb +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-pll-v1.c +@@ -0,0 +1,185 @@ ++#include ++#include ++#include ++#include ++#include ++#include "clk.h" ++#include "clk-pll-v1.h" ++ ++#define PLL_TIMEOUT_MS 10 ++ ++struct ingenic_clk_pll { ++ struct clk_hw hw; ++ void __iomem *lock_reg; ++ void __iomem *con_reg; ++ unsigned int rate_count; ++ ++ struct ingenic_pll_hwdesc *hwdesc; ++ struct ingenic_pll_rate_table *rate_table; ++ ++}; ++ ++#define to_clk_pll(_hw) container_of(_hw, struct ingenic_clk_pll, hw) ++ ++ ++ ++static long ingenic_pll_round_rate(struct clk_hw *hw, unsigned long drate, unsigned long *prate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ const struct ingenic_pll_rate_table *rate_table = pll->rate_table; ++ int i; ++ unsigned int rate; ++ ++ for (i = 0; i < pll->rate_count; i++) { ++ if (drate >= rate_table[i].rate) ++ return rate_table[i].rate; ++ } ++ ++ return rate_table[i - 1].rate; ++ ++ ++} ++ ++ ++static unsigned long ingenic_v1_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ unsigned int val; ++ unsigned int fd, rd, od; ++ unsigned int nf, nr, no; ++ unsigned long fout; ++ ++ ++ val = readl(pll->con_reg); ++ ++ fd = (val >> pll->hwdesc->fd_sft) & ((1 << pll->hwdesc->fd_width) - 1); ++ rd = (val >> pll->hwdesc->rd_sft) & ((1 << pll->hwdesc->rd_width) - 1); ++ od = (val >> pll->hwdesc->od_sft) & ((1 << pll->hwdesc->od_width) - 1); ++ ++ nf = 1 + fd; ++ nr = 1 + rd; ++ no = pll_od_encode[od]; ++ ++ fout = parent_rate / (nr * no) * 2 * nf; ++ ++ return fout; ++} ++ ++static int wait_pll_stable(void __iomem *reg, u32 shift) ++{ ++ unsigned int timeout = 0xffff; ++ ++ while ((!((readl(reg) >> shift) & 1)) && --timeout); ++ if (!timeout) { ++ printk("WARNING : why cannot wait pll stable ???\n"); ++ return -ETIMEDOUT; ++ } else { ++ return 0; ++ } ++} ++ ++static int ingenic_v1_pll_set_rate(struct clk_hw *hw, unsigned long drate, unsigned long prate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ ++ unsigned int fd; ++ unsigned int rd; ++ unsigned int od; ++ unsigned int val, i; ++ ++ for (i = 0; i < pll->rate_count; i++) { ++ if (drate == pll->rate_table[i].rate) { ++ fd = pll->rate_table[i].fd; ++ rd = pll->rate_table[i].rd; ++ od = pll->rate_table[i].od; ++ } ++ } ++ ++ ++ ++ writel(0, pll->con_reg); ++ val = (fd << pll->hwdesc->fd_sft) | (rd << pll->hwdesc->rd_sft) | (od << pll->hwdesc->od_sft) | 1; ++ writel(val, pll->con_reg); ++ ++ wait_pll_stable(pll->con_reg, pll->hwdesc->on_bit); ++ ++ return 0; ++} ++ ++ ++static const struct clk_ops ingenic_v1_pll_clk_ops = { ++ .recalc_rate = ingenic_v1_pll_recalc_rate, ++ .round_rate = ingenic_pll_round_rate, ++ .set_rate = ingenic_v1_pll_set_rate, ++}; ++ ++static void __init _ingenic_clk_register_pll(struct ingenic_clk_provider *ctx, ++ const struct ingenic_pll_clock *pll_clk, ++ void __iomem *base) ++{ ++ struct ingenic_clk_pll *pll; ++ struct clk *clk; ++ struct clk_init_data init; ++ int ret, len; ++ ++ pll = kzalloc(sizeof(*pll), GFP_KERNEL); ++ if (!pll) { ++ pr_err("%s: could not allocate pll clk %s\n", ++ __func__, pll_clk->dev_name); ++ return; ++ } ++ ++ init.name = pll_clk->dev_name; ++// init.flags = pll_clk->flags; ++ init.parent_names = &pll_clk->parent_name; ++ init.num_parents = 1; ++ init.ops = &ingenic_v1_pll_clk_ops; ++ ++ ++ pll->hw.init = &init; ++ pll->hwdesc = pll_clk->hwdesc; ++ pll->con_reg = base + pll_clk->hwdesc->regoff; ++ ++ if (pll_clk->rate_table) { ++ /* find count of rates in rate_table */ ++ for (len = 0; pll_clk->rate_table[len].rate != 0; ) ++ len++; ++ ++ pll->rate_count = len - 1; ++ pll->rate_table = kmemdup(pll_clk->rate_table, ++ pll->rate_count * ++ sizeof(struct ingenic_pll_rate_table), ++ GFP_KERNEL); ++ WARN(!pll->rate_table, ++ "%s: could not allocate rate table for %s\n", ++ __func__, pll_clk->name); ++ } ++ ++ ++ ++ clk = clk_register(NULL, &pll->hw); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register pll clock %s : %ld\n", ++ __func__, pll_clk->dev_name, PTR_ERR(clk)); ++ kfree(pll); ++ return; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, pll_clk->id); ++ ++ ++ ret = clk_register_clkdev(clk, pll_clk->dev_name, NULL); ++ if (ret) ++ pr_err("%s: failed to register lookup for %s : %d", ++ __func__, pll_clk->dev_name, ret); ++} ++ ++void __init ingenic_clk_register_pll(struct ingenic_clk_provider *ctx, ++ const struct ingenic_pll_clock *pll_list, ++ unsigned int nr_pll, void __iomem *base) ++{ ++ int cnt; ++ ++ for (cnt = 0; cnt < nr_pll; cnt++) ++ _ingenic_clk_register_pll(ctx, &pll_list[cnt], base); ++} +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-pll-v1.h b/module_drivers/drivers/clk/ingenic-v2/clk-pll-v1.h +new file mode 100644 +index 000000000..32c77cab6 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-pll-v1.h +@@ -0,0 +1,53 @@ ++#ifndef __INGENIC_CLK_PLLV_H__ ++#define __INGENIC_CLK_PLLV_H__ ++ ++ ++extern const struct clk_ops ingenic_pll_ro_ops; ++ ++static const s8 pll_od_encode[7] = {-1, 2, 4, 8, 16, 32, 64}; ++ ++#define PLL_RATE(_rate, _fd, _rd, _od) \ ++{ \ ++ .rate = _rate, \ ++ .fd = _fd, \ ++ .rd = _rd, \ ++ .od = _od, \ ++} ++ ++struct ingenic_pll_rate_table { ++ unsigned int rate; ++ unsigned int fd; ++ unsigned int rd; ++ unsigned int od; ++}; ++ ++ ++ ++#define PLL_DESC(_regoff, _fd, _fd_w, _rd, _rd_w, _od, _od_w, _on, _en, _od_code) \ ++{ \ ++ .regoff = _regoff, \ ++ .fd_sft = _fd, \ ++ .fd_width = _fd_w, \ ++ .rd_sft = _rd, \ ++ .rd_width = _rd_w, \ ++ .od_sft = _od, \ ++ .od_width = _od_w, \ ++ .od_encode = _od_code, \ ++ .on_bit = _on, \ ++ .en_bit = _en, \ ++} ++ ++struct ingenic_pll_hwdesc { ++ u32 regoff; ++ u8 fd_sft; ++ u8 fd_width; ++ u8 rd_sft; ++ u8 rd_width; ++ u8 od_sft; ++ u8 od_width; ++ u8 on_bit; ++ u8 en_bit; ++ const s8 *od_encode; /*od rules, -1 not support*/ ++}; ++ ++#endif /*__INGENIC_CLK_PLLV1_H__*/ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-pll-v2.c b/module_drivers/drivers/clk/ingenic-v2/clk-pll-v2.c +new file mode 100644 +index 000000000..1503a3443 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-pll-v2.c +@@ -0,0 +1,181 @@ ++#include ++#include ++#include ++#include ++#include ++#include "clk.h" ++#include "clk-pll-v2.h" ++ ++#define PLL_TIMEOUT_MS 10 ++ ++struct ingenic_clk_pll { ++ struct clk_hw hw; ++ void __iomem *lock_reg; ++ void __iomem *con_reg; ++ unsigned int rate_count; ++ ++ struct ingenic_pll_hwdesc *hwdesc; ++ struct ingenic_pll_rate_table *rate_table; ++ ++}; ++ ++#define to_clk_pll(_hw) container_of(_hw, struct ingenic_clk_pll, hw) ++ ++ ++ ++static long ingenic_pll_round_rate(struct clk_hw *hw, unsigned long drate, unsigned long *prate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ const struct ingenic_pll_rate_table *rate_table = pll->rate_table; ++ int i; ++ unsigned int rate; ++ ++ for (i = 0; i < pll->rate_count; i++) { ++ if (drate >= rate_table[i].rate) ++ return rate_table[i].rate; ++ } ++ ++ return rate_table[i - 1].rate; ++ ++ ++} ++ ++ ++static unsigned long ingenic_v2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ unsigned int val; ++ unsigned int m, n, od0, od1; ++ unsigned long fout; ++ ++ ++ val = readl(pll->con_reg); ++ ++ m = (val >> pll->hwdesc->m_sft) & ((1 << pll->hwdesc->m_width) - 1); ++ n = (val >> pll->hwdesc->n_sft) & ((1 << pll->hwdesc->n_width) - 1); ++ od0 = (val >> pll->hwdesc->od0_sft) & ((1 << pll->hwdesc->od0_width) - 1); ++ od1 = (val >> pll->hwdesc->od1_sft) & ((1 << pll->hwdesc->od1_width) - 1); ++ ++ ++ fout = parent_rate / (od1 * od0) / n * m; ++ ++ return fout; ++} ++ ++static int wait_pll_stable(void __iomem *reg, u32 shift) ++{ ++ unsigned int timeout = 0xffff; ++ ++ while ((!((readl(reg) >> shift) & 1)) && --timeout); ++ if (!timeout) { ++ printk("WARNING : why cannot wait pll stable ???\n"); ++ return -ETIMEDOUT; ++ } else { ++ return 0; ++ } ++} ++ ++static int ingenic_v2_pll_set_rate(struct clk_hw *hw, unsigned long drate, unsigned long prate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ ++ unsigned int m, n, od0, od1; ++ unsigned int val, i; ++ ++ for (i = 0; i < pll->rate_count; i++) { ++ if (drate == pll->rate_table[i].rate) { ++ m = pll->rate_table[i].m; ++ n = pll->rate_table[i].n; ++ od0 = pll->rate_table[i].od0; ++ od1 = pll->rate_table[i].od1; ++ } ++ } ++ ++ ++ ++ writel(0, pll->con_reg); ++ val = (m << pll->hwdesc->m_sft) | (n << pll->hwdesc->n_sft) | (od0 << pll->hwdesc->od0_sft) | (od1 << pll->hwdesc->od1_sft) | 1; ++ writel(val, pll->con_reg); ++ ++ wait_pll_stable(pll->con_reg, pll->hwdesc->on_bit); ++ ++ return 0; ++} ++ ++ ++static const struct clk_ops ingenic_v2_pll_clk_ops = { ++ .recalc_rate = ingenic_v2_pll_recalc_rate, ++ .round_rate = ingenic_pll_round_rate, ++ .set_rate = ingenic_v2_pll_set_rate, ++}; ++ ++static void __init _ingenic_clk_register_pll(struct ingenic_clk_provider *ctx, ++ const struct ingenic_pll_clock *pll_clk, ++ void __iomem *base) ++{ ++ struct ingenic_clk_pll *pll; ++ struct clk *clk; ++ struct clk_init_data init; ++ int ret, len; ++ ++ pll = kzalloc(sizeof(*pll), GFP_KERNEL); ++ if (!pll) { ++ pr_err("%s: could not allocate pll clk %s\n", ++ __func__, pll_clk->dev_name); ++ return; ++ } ++ ++ init.name = pll_clk->dev_name; ++// init.flags = pll_clk->flags; ++ init.parent_names = &pll_clk->parent_name; ++ init.num_parents = 1; ++ init.ops = &ingenic_v2_pll_clk_ops; ++ ++ ++ pll->hw.init = &init; ++ pll->hwdesc = pll_clk->hwdesc; ++ pll->con_reg = base + pll_clk->hwdesc->regoff; ++ ++ if (pll_clk->rate_table) { ++ /* find count of rates in rate_table */ ++ for (len = 0; pll_clk->rate_table[len].rate != 0; ) ++ len++; ++ ++ pll->rate_count = len - 1; ++ pll->rate_table = kmemdup(pll_clk->rate_table, ++ pll->rate_count * ++ sizeof(struct ingenic_pll_rate_table), ++ GFP_KERNEL); ++ WARN(!pll->rate_table, ++ "%s: could not allocate rate table for %s\n", ++ __func__, pll_clk->name); ++ } ++ ++ ++ ++ clk = clk_register(NULL, &pll->hw); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register pll clock %s : %ld\n", ++ __func__, pll_clk->dev_name, PTR_ERR(clk)); ++ kfree(pll); ++ return; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, pll_clk->id); ++ ++ ++ ret = clk_register_clkdev(clk, pll_clk->dev_name, NULL); ++ if (ret) ++ pr_err("%s: failed to register lookup for %s : %d", ++ __func__, pll_clk->dev_name, ret); ++} ++ ++void __init ingenic_clk_register_pll(struct ingenic_clk_provider *ctx, ++ const struct ingenic_pll_clock *pll_list, ++ unsigned int nr_pll, void __iomem *base) ++{ ++ int cnt; ++ ++ for (cnt = 0; cnt < nr_pll; cnt++) ++ _ingenic_clk_register_pll(ctx, &pll_list[cnt], base); ++} +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-pll-v2.h b/module_drivers/drivers/clk/ingenic-v2/clk-pll-v2.h +new file mode 100644 +index 000000000..80c037c6e +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-pll-v2.h +@@ -0,0 +1,53 @@ ++#ifndef __INGENIC_CLK_PLLV_H__ ++#define __INGENIC_CLK_PLLV_H__ ++ ++ ++extern const struct clk_ops ingenic_pll_ro_ops; ++ ++#define PLL_RATE(_rate, _m, _n, _od1, _od0) \ ++{ \ ++ .rate = _rate, \ ++ .m = _m, \ ++ .n = _n, \ ++ .od1 = _od1, \ ++ .od0 = _od0, \ ++} ++ ++struct ingenic_pll_rate_table { ++ unsigned int rate; ++ unsigned int m; ++ unsigned int n; ++ unsigned int od1; ++ unsigned int od0; ++}; ++ ++#define PLL_DESC(_regoff, _m, _m_w, _n, _n_w, _od1, _od1_w, _od0, _od0_w, _on, _en) \ ++{ \ ++ .regoff = _regoff, \ ++ .m_sft = _m, \ ++ .m_width = _m_w, \ ++ .n_sft = _n, \ ++ .n_width = _n_w, \ ++ .od1_sft = _od1, \ ++ .od1_width = _od1_w, \ ++ .od0_sft = _od0, \ ++ .od0_width = _od0_w, \ ++ .on_bit = _on, \ ++ .en_bit = _en, \ ++} ++ ++struct ingenic_pll_hwdesc { ++ u32 regoff; ++ u8 m_sft; ++ u8 m_width; ++ u8 n_sft; ++ u8 n_width; ++ u8 od1_sft; ++ u8 od1_width; ++ u8 od0_sft; ++ u8 od0_width; ++ u8 on_bit; ++ u8 en_bit; ++}; ++ ++#endif /*__INGENIC_CLK_PLLV1_H__*/ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-pll.c b/module_drivers/drivers/clk/ingenic-v2/clk-pll.c +new file mode 100644 +index 000000000..7e440eb59 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-pll.c +@@ -0,0 +1,185 @@ ++#include ++#include ++#include ++#include ++#include ++#include "clk.h" ++#include "clk-pll.h" ++ ++#define PLL_TIMEOUT_MS 10 ++ ++struct ingenic_clk_pll { ++ struct clk_hw hw; ++ void __iomem *lock_reg; ++ void __iomem *con_reg; ++ unsigned int rate_count; ++ ++ struct ingenic_pll_hwdesc *hwdesc; ++ struct ingenic_pll_rate_table *rate_table; ++ ++}; ++ ++#define to_clk_pll(_hw) container_of(_hw, struct ingenic_clk_pll, hw) ++ ++ ++ ++static long ingenic_pll_round_rate(struct clk_hw *hw, unsigned long drate, unsigned long *prate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ const struct ingenic_pll_rate_table *rate_table = pll->rate_table; ++ int i; ++ unsigned int rate; ++ ++ for (i = 0; i < pll->rate_count; i++) { ++ if (drate >= rate_table[i].rate) ++ return rate_table[i].rate; ++ } ++ ++ return rate_table[i - 1].rate; ++ ++ ++} ++ ++ ++static unsigned long ingenic_x2000_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ unsigned int val; ++ unsigned int fd, rd, od; ++ unsigned int nf, nr, no; ++ unsigned long fout; ++ ++ ++ val = readl(pll->con_reg); ++ ++ fd = (val >> pll->hwdesc->fd_sft) & ((1 << pll->hwdesc->fd_width) - 1); ++ rd = (val >> pll->hwdesc->rd_sft) & ((1 << pll->hwdesc->rd_width) - 1); ++ od = (val >> pll->hwdesc->od_sft) & ((1 << pll->hwdesc->od_width) - 1); ++ ++ nf = 1 + fd; ++ nr = 1 + rd; ++ no = pll_od_encode[od]; ++ ++ fout = parent_rate / (nr * no) * 2 * nf; ++ ++ return fout; ++} ++ ++static int wait_pll_stable(void __iomem *reg, u32 shift) ++{ ++ unsigned int timeout = 0xffff; ++ ++ while ((!((readl(reg) >> shift) & 1)) && timeout--); ++ if (!timeout) { ++ printk("WARNING : why cannot wait pll stable ???\n"); ++ return -EIO; ++ } else { ++ return 0; ++ } ++} ++ ++static int ingenic_x2000_pll_set_rate(struct clk_hw *hw, unsigned long drate, unsigned long prate) ++{ ++ struct ingenic_clk_pll *pll = to_clk_pll(hw); ++ ++ unsigned int fd; ++ unsigned int rd; ++ unsigned int od; ++ unsigned int val, i; ++ ++ for (i = 0; i < pll->rate_count; i++) { ++ if (drate == pll->rate_table[i].rate) { ++ fd = pll->rate_table[i].fd; ++ rd = pll->rate_table[i].rd; ++ od = pll->rate_table[i].od; ++ } ++ } ++ ++ ++ ++ writel(0, pll->con_reg); ++ val = (fd << pll->hwdesc->fd_sft) | (rd << pll->hwdesc->rd_sft) | (od << pll->hwdesc->od_sft) | 1; ++ writel(val, pll->con_reg); ++ ++ wait_pll_stable(pll->con_reg, pll->hwdesc->on_bit); ++ ++ return 0; ++} ++ ++ ++static const struct clk_ops ingenic_x2000_pll_clk_ops = { ++ .recalc_rate = ingenic_x2000_pll_recalc_rate, ++ .round_rate = ingenic_pll_round_rate, ++ .set_rate = ingenic_x2000_pll_set_rate, ++}; ++ ++static void __init _ingenic_clk_register_pll(struct ingenic_clk_provider *ctx, ++ const struct ingenic_pll_clock *pll_clk, ++ void __iomem *base) ++{ ++ struct ingenic_clk_pll *pll; ++ struct clk *clk; ++ struct clk_init_data init; ++ int ret, len; ++ ++ pll = kzalloc(sizeof(*pll), GFP_KERNEL); ++ if (!pll) { ++ pr_err("%s: could not allocate pll clk %s\n", ++ __func__, pll_clk->dev_name); ++ return; ++ } ++ ++ init.name = pll_clk->dev_name; ++// init.flags = pll_clk->flags; ++ init.parent_names = &pll_clk->parent_name; ++ init.num_parents = 1; ++ init.ops = &ingenic_x2000_pll_clk_ops; ++ ++ ++ pll->hw.init = &init; ++ pll->hwdesc = pll_clk->hwdesc; ++ pll->con_reg = base + pll_clk->hwdesc->regoff; ++ ++ if (pll_clk->rate_table) { ++ /* find count of rates in rate_table */ ++ for (len = 0; pll_clk->rate_table[len].rate != 0; ) ++ len++; ++ ++ pll->rate_count = len - 1; ++ pll->rate_table = kmemdup(pll_clk->rate_table, ++ pll->rate_count * ++ sizeof(struct ingenic_pll_rate_table), ++ GFP_KERNEL); ++ WARN(!pll->rate_table, ++ "%s: could not allocate rate table for %s\n", ++ __func__, pll_clk->name); ++ } ++ ++ ++ ++ clk = clk_register(NULL, &pll->hw); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register pll clock %s : %ld\n", ++ __func__, pll_clk->dev_name, PTR_ERR(clk)); ++ kfree(pll); ++ return; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, pll_clk->id); ++ ++ ++ ret = clk_register_clkdev(clk, pll_clk->dev_name, NULL); ++ if (ret) ++ pr_err("%s: failed to register lookup for %s : %d", ++ __func__, pll_clk->dev_name, ret); ++} ++ ++void __init ingenic_clk_register_pll(struct ingenic_clk_provider *ctx, ++ const struct ingenic_pll_clock *pll_list, ++ unsigned int nr_pll, void __iomem *base) ++{ ++ int cnt; ++ ++ for (cnt = 0; cnt < nr_pll; cnt++) ++ _ingenic_clk_register_pll(ctx, &pll_list[cnt], base); ++} +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-pll.h b/module_drivers/drivers/clk/ingenic-v2/clk-pll.h +new file mode 100644 +index 000000000..c55824756 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-pll.h +@@ -0,0 +1,11 @@ ++ ++#ifdef CLK_PLL_V1 ++#include "clk-pll-v1.h" ++#endif ++ ++#ifdef CLK_PLL_V2 ++#include "clk-pll-v2.h" ++#endif ++ ++ ++ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-x1600.c b/module_drivers/drivers/clk/ingenic-v2/clk-x1600.c +new file mode 100644 +index 000000000..7923422ee +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-x1600.c +@@ -0,0 +1,306 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "clk.h" ++ ++ ++ ++/******************************************************************************* ++ * FIXED CLK ++ ********************************************************************************/ ++static struct ingenic_fixed_rate_clock x1600_fixed_rate_ext_clks[] __initdata = { ++ FRATE(CLK_EXT, "ext", NULL, 0, 24000000), ++ FRATE(CLK_RTC_EXT, "rtc_ext", NULL, 0, 32768), ++ FRATE(CLK_EXT_DIV_512, "ext_div_512", NULL, 0, 46875), ++}; ++ ++ ++ ++/******************************************************************************* ++ * PLL ++ ********************************************************************************/ ++ ++static struct ingenic_pll_rate_table x1600_pll_rate_table[] = { ++ PLL_RATE(1000000000, 125, 3, 1, 1), ++ PLL_RATE(900000000, 75, 1, 2, 1), ++ PLL_RATE(800000000, 100, 1, 3, 1), ++ PLL_RATE(700000000, 175, 2, 3, 1), ++ PLL_RATE(600000000, 25, 1, 1, 1), ++ PLL_RATE(500000000, 125, 2, 3, 1), ++ PLL_RATE(400000000, 50, 1, 3, 1), ++}; ++ ++ ++ ++/*PLL HWDESC*/ ++static struct ingenic_pll_hwdesc apll_hwdesc = \ ++ PLL_DESC(CPM_CPAPCR, 20,12, 14, 6, 11, 3, 8, 3, 3, 0); ++ ++static struct ingenic_pll_hwdesc mpll_hwdesc = \ ++ PLL_DESC(CPM_CPMPCR, 20,12, 14, 6, 11, 3, 8, 3, 3, 0); ++ ++static struct ingenic_pll_hwdesc epll_hwdesc = \ ++ PLL_DESC(CPM_CPEPCR, 20,12, 14, 6, 11, 3, 8, 3, 3, 0); ++ ++ ++ ++static struct ingenic_pll_clock x1600_pll_clks[] __initdata = { ++ PLL(CLK_PLL_APLL, "apll", "ext", &apll_hwdesc, x1600_pll_rate_table), ++ PLL(CLK_PLL_MPLL, "mpll", "ext", &mpll_hwdesc, x1600_pll_rate_table), ++ PLL(CLK_PLL_EPLL, "epll", "ext", &epll_hwdesc, x1600_pll_rate_table), ++}; ++ ++ ++/******************************************************************************* ++ * MUX ++ ********************************************************************************/ ++PNAME(mux_table_0) = {"stop", "ext", "apll"}; ++PNAME(mux_table_1) = {"stop", "sclka", "mpll"}; ++PNAME(mux_table_2) = {"sclka", "mpll", "epll"}; ++PNAME(mux_table_3) = {"sclka", "mpll", "epll", "ext"}; ++PNAME(mux_table_4) = {"sclka", "epll"}; ++PNAME(mux_table_5) = {"ext_div_512", "rtc_ext"}; ++ ++static unsigned int ingenic_mux_table[] = {0, 1, 2, 3, 4}; ++ ++ ++static struct ingenic_mux_clock x1600_mux_clks[] __initdata = { ++ MUX(CLK_MUX_SCLKA, "sclka", ingenic_mux_table, mux_table_0, CPM_CPCCR, 30, 2, 0), ++ MUX(CLK_MUX_CPU_L2C, "mux_cpu_l2c", ingenic_mux_table, mux_table_1, CPM_CPCCR, 28, 2, 0), ++ MUX(CLK_MUX_AHB0, "mux_ahb0", ingenic_mux_table, mux_table_1, CPM_CPCCR, 26, 2, 0), ++ MUX(CLK_MUX_AHB2, "mux_ahb2", ingenic_mux_table, mux_table_1, CPM_CPCCR, 24, 2, 0), ++ ++ MUX(CLK_MUX_DDR, "mux_ddr", ingenic_mux_table, mux_table_1, CPM_DDRCDR, 30, 2, 0), ++ MUX(CLK_MUX_MACPHY, "mux_macphy", ingenic_mux_table, mux_table_2, CPM_MACPHYCDR, 30, 2, 0), ++ MUX(CLK_MUX_I2S0T, "mux_i2s0t", ingenic_mux_table, mux_table_4, CPM_I2SCDR1, 30, 1, 0), ++ MUX(CLK_MUX_I2S0R, "mux_i2s0r", ingenic_mux_table, mux_table_4, CPM_I2SCDR, 30, 1, 0), ++ MUX(CLK_MUX_LCD, "mux_lcd", ingenic_mux_table, mux_table_2, CPM_LPCDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC0, "mux_msc0", ingenic_mux_table, mux_table_2, CPM_MSC0CDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC1, "mux_msc1", ingenic_mux_table, mux_table_2, CPM_MSC1CDR, 30, 2, 0), ++ MUX(CLK_MUX_SFC, "mux_sfc", ingenic_mux_table, mux_table_2, CPM_SFCCDR, 30, 2, 0), ++ MUX(CLK_MUX_SSI, "mux_ssi", ingenic_mux_table, mux_table_2, CPM_SSICDR, 30, 2, 0), ++ MUX(CLK_MUX_CIM, "mux_cim", ingenic_mux_table, mux_table_2, CPM_CIMCDR, 30, 2, 0), ++ MUX(CLK_MUX_PWM, "mux_pwm", ingenic_mux_table, mux_table_2, CPM_PWMCDR, 30, 2, 0), ++ MUX(CLK_MUX_CAN0, "mux_can0", ingenic_mux_table, mux_table_3, CPM_CAN0CDR, 30, 2, 0), ++ MUX(CLK_MUX_CAN1, "mux_can1", ingenic_mux_table, mux_table_3, CPM_CAN1CDR, 30, 2, 0), ++ MUX(CLK_MUX_CDBUS, "mux_cdbus", ingenic_mux_table, mux_table_2, CPM_CDBUSCDR, 30, 2, 0), ++ MUX(CLK_MUX_WDT, "mux_wdt", ingenic_mux_table, mux_table_5, CPM_OPCR, 2, 1, 0), ++ ++}; ++ ++/******************************************************************************* ++ * DIV BUS ++ ********************************************************************************/ ++ ++static struct ingenic_bus_clock x1600_bus_div_clks[] __initdata = { ++ BUS_DIV(CLK_DIV_CPU, "div_cpu", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_L2C, "div_l2c", "mux_cpu_l2c", CPM_CPCCR, 4, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB0, "div_ahb0", "mux_ahb0", CPM_CPCCR, 8, 4, 0, 0, CPM_CPCSR, 1, 21, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB2, "div_ahb2", "mux_ahb2", CPM_CPCCR, 12, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_APB, "div_apb", "mux_ahb2", CPM_CPCCR, 16, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_CPU_L2C_X1, "div_cpu_l2c_x1", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_ONE), ++ BUS_DIV(CLK_DIV_CPU_L2C_X2, "div_cpu_l2c_x2", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_TWO), ++}; ++ ++ ++/******************************************************************************* ++ * DIV ++ ********************************************************************************/ ++ ++static struct clk_div_table x1600_clk_div_table[256] = {}; ++ ++static struct ingenic_div_clock x1600_div_clks[] __initdata = { ++ DIV(CLK_DIV_DDR, "div_ddr", "mux_ddr", CPM_DDRCDR, 4, 0, NULL), ++ DIV(CLK_DIV_MACPHY, "div_macphy", "mux_macphy", CPM_MACPHYCDR, 8, 0, NULL), ++ DIV(CLK_DIV_LCD, "div_lcd", "mux_lcd", CPM_LPCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MSC0, "div_msc0", "mux_msc0", CPM_MSC0CDR, 8, 0, x1600_clk_div_table), ++ DIV(CLK_DIV_MSC1, "div_msc1", "mux_msc1", CPM_MSC1CDR, 8, 0, x1600_clk_div_table), ++ DIV(CLK_DIV_SFC, "div_sfc", "mux_sfc", CPM_SFCCDR, 8, 0, NULL), ++ DIV(CLK_DIV_SSI, "div_ssi", "mux_ssi", CPM_SSICDR, 8, 0, NULL), ++ DIV(CLK_DIV_CIM, "div_cim", "mux_cim", CPM_CIMCDR, 8, 0, NULL), ++ DIV(CLK_DIV_PWM, "div_pwm", "mux_pwm", CPM_PWMCDR, 4, 0, NULL), ++ DIV(CLK_DIV_CAN0, "div_can0", "mux_can0", CPM_CAN0CDR, 8, 0, NULL), ++ DIV(CLK_DIV_CAN1, "div_can1", "mux_can1", CPM_CAN1CDR, 8, 0, NULL), ++ DIV(CLK_DIV_CDBUS, "div_cdbus", "mux_cdbus", CPM_CDBUSCDR, 8, 0, NULL), ++ ++}; ++ ++/******************************************************************************* ++ * FRACTIONAL-DIVIDER ++ ********************************************************************************/ ++ ++static struct ingenic_fra_div_clock x1600_fdiv_clks[] __initdata = { ++ FRA_DIV(CLK_DIV_I2S0R, "div_i2s0r", "mux_i2s0r", CPM_I2SCDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2S0T, "div_i2s0t", "mux_i2s0t", CPM_I2SCDR1, 20, 9, 0, 20), ++}; ++ ++/******************************************************************************* ++ * GATE ++ ********************************************************************************/ ++static struct ingenic_gate_clock x1600_gate_clks[] __initdata = { ++ ++ GATE(CLK_GATE_DDR, "gate_ddr", "div_ddr", CPM_CLKGR, 31, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AHB0, "gate_ahb0", "div_ahb0", CPM_CLKGR, 29, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_APB0, "gate_apb0", "div_ahb0", CPM_CLKGR, 28, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_RTC, "gate_rtc", "rtc_ext", CPM_CLKGR, 27, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AES, "gate_aes", "div_ahb2", CPM_CLKGR, 24, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_LCD, "gate_lcd", "div_lcd", CPM_CLKGR, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_CIM, "gate_cim", "div_cim", CPM_CLKGR, 22, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PDMA, "gate_pdma", "div_ahb2", CPM_CLKGR, 21, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OST, "gate_ost", "ext", CPM_CLKGR, 20, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI0, "gate_ssi0", "div_ssi", CPM_CLKGR, 19, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_TCU, "gate_tcu", "div_apb", CPM_CLKGR, 18, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DTRNG, "gate_dtrng", "div_apb", CPM_CLKGR, 17, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART2, "gate_uart2", "div_apb", CPM_CLKGR, 16, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART1, "gate_uart1", "div_apb", CPM_CLKGR, 15, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART0, "gate_uart0", "div_apb", CPM_CLKGR, 14, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SADC, "gate_sadc", "div_apb", CPM_CLKGR, 13, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AUDIO, "gate_audio", "div_ahb2", CPM_CLKGR, 11, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSISLV, "gate_ssislv", "div_apb", CPM_CLKGR, 10, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB1, "gate_i2c1", "div_apb", CPM_CLKGR, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB0, "gate_i2c0", "div_apb", CPM_CLKGR, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC1, "gate_msc1", "div_msc1", CPM_CLKGR, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC0, "gate_msc0", "div_msc0", CPM_CLKGR, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OTG, "gate_otg", "div_ahb2", CPM_CLKGR, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SFC, "gate_sfc", "div_sfc", CPM_CLKGR, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_EFUSE, "gate_efuse", "div_ahb2", CPM_CLKGR, 1, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_NEMC, "gate_nemc", "div_ahb2", CPM_CLKGR, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ARB, "gate_arb", "div_ahb0", CPM_CLKGR1, 30, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_CSI, "gate_csi", "div_ahb0", CPM_CLKGR1, 28, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_INTC, "gate_intc", "div_ahb2", CPM_CLKGR1, 26, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_GMAC0, "gate_gmac0", "div_ahb2", CPM_CLKGR1, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART3, "gate_uart3", "div_apb", CPM_CLKGR1, 16, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S0T, "gate_i2s0t", "div_i2s0t", CPM_CLKGR1, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S0R, "gate_i2s0r", "div_i2s0r", CPM_CLKGR1, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_HASH, "gate_hash", "div_ahb2", CPM_CLKGR1, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PWM, "gate_pwm", "div_pwm", CPM_CLKGR1, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_CDBUS, "gate_cdbus", "div_apb", CPM_CLKGR1, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_CAN1, "gate_can1", "div_apb", CPM_CLKGR1, 1, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_CAN0, "gate_can0", "div_apb", CPM_CLKGR1, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_USBPHY, "gate_usbphy", "div_apb", CPM_OPCR, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_CE_I2S0T, "ce_i2s0t", "div_i2s0t", CPM_I2SCDR1, 29, 0, 0), ++ GATE(CLK_CE_I2S0R, "ce_i2s0r", "div_i2s0r", CPM_I2SCDR, 29, 0, 0), ++}; ++ ++static struct ingenic_gate_power x1600_gate_power[] __initdata = { ++ ++ POWER(PD_MEM_CDBUS, "pd_mem_cdbus", "gate_cdbus", CPM_MPDCR0, 29, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_PWM, "pd_mem_pwm", "gate_cdbus", CPM_MPDCR0, 26, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_GMAC, "pd_mem_gmac", "gate_cdbus", CPM_MPDCR0, 25, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_USB, "pd_mem_usb", "gate_usb", CPM_MPDCR0, 24, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SFC, "pd_mem_sfc", "gate_sfc", CPM_MPDCR0, 23, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC1, "pd_mem_msc1", "gate_msc1", CPM_MPDCR0, 22, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC0, "pd_mem_msc0", "gate_msc0", CPM_MPDCR0, 21, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_AES, "pd_mem_aes", "gate_aes", CPM_MPDCR0, 20, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_PDMA_SLP, "pd_mem_pdma_slp", "gate_pdma", CPM_MPDCR0, 19, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_PDMA_SEC, "pd_mem_pdma_sec", "gate_pdma", CPM_MPDCR0, 18, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_PDMA, "pd_mem_pdma", "gate_pdma", CPM_MPDCR0, 17, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_NEMC, "pd_mem_nemc", "gate_nemc", CPM_MPDCR0, 16, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_AIC, "pd_mem_aic", "gate_audio", CPM_MPDCR0, 6, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SSISLV, "pd_mem_ssislv", "gate_ssislv", CPM_MPDCR0, 5, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SSI0, "pd_mem_ssi0", "gate_ssi0", CPM_MPDCR0, 4, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART3, "pd_mem_uart3", "gate_uart3", CPM_MPDCR0, 3, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART2, "pd_mem_uart2", "gate_uart2", CPM_MPDCR0, 2, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART1, "pd_mem_uart1", "gate_uart1", CPM_MPDCR0, 1, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART0, "pd_mem_uart0", "gate_uart0", CPM_MPDCR0, 0, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_CIM, "pd_mem_cim", "gate_cim", CPM_MPDCR1, 5, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DPU, "pd_mem_dpu", "gate_dpu", CPM_MPDCR1, 4, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH6, "pd_mem_ddr_ch6", "gate_ddr", CPM_MPDCR1, 3, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH5, "pd_mem_ddr_ch5", "gate_ddr", CPM_MPDCR1, 2, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH3, "pd_mem_ddr_ch3", "gate_ddr", CPM_MPDCR1, 1, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_TOP, "pd_mem_ddr_top", "gate_ddr", CPM_MPDCR1, 0, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ ++}; ++ ++static void clk_div_table_generate(void) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(x1600_clk_div_table); i++) { ++ x1600_clk_div_table[i].val = i; ++ x1600_clk_div_table[i].div = (i + 1) * 2; ++ } ++ ++} ++ ++static const struct of_device_id ext_clk_match[] __initconst = { ++ { .compatible = "ingenic,fixed-clock", .data = (void *)0, }, ++ {}, ++}; ++ ++ ++/* Register x1600 clocks. */ ++static void __init x1600_clk_init(struct device_node *np, void __iomem *base) ++{ ++ struct ingenic_clk_provider *ctx; ++ void __iomem *reg_base; ++ ++ ++ printk("x1600 Clock Power Management Unit init!\n"); ++ ++ reg_base = base; ++ ++ if (np) { ++ reg_base = of_iomap(np, 0); ++ if (!reg_base) ++ panic("%s: failed to map registers\n", __func__); ++ } ++ ++ ++ ctx = ingenic_clk_init(np, reg_base, NR_CLKS); ++ if (!ctx) ++ panic("%s: unable to allocate context.\n", __func__); ++ ++ /* Register Ext Clocks From DT */ ++ ingenic_clk_of_register_fixed_ext(ctx, x1600_fixed_rate_ext_clks, ++ ARRAY_SIZE(x1600_fixed_rate_ext_clks), ext_clk_match); ++ ++ /* Register PLLs. */ ++ ingenic_clk_register_pll(ctx, x1600_pll_clks, ++ ARRAY_SIZE(x1600_pll_clks), reg_base); ++ ++ ++ /* Register Muxs */ ++ ingenic_clk_register_mux(ctx, x1600_mux_clks, ARRAY_SIZE(x1600_mux_clks)); ++ ++ /* Register Bus Divs */ ++ ingenic_clk_register_bus_div(ctx, x1600_bus_div_clks, ARRAY_SIZE(x1600_bus_div_clks)); ++ ++ /* Register Divs */ ++ clk_div_table_generate(); ++ ingenic_clk_register_cgu_div(ctx, x1600_div_clks, ARRAY_SIZE(x1600_div_clks)); ++ ++ /* Register Fractional Divs */ ++ ingenic_clk_register_fra_div(ctx, x1600_fdiv_clks, ARRAY_SIZE(x1600_fdiv_clks)); ++ ++ /* Register Gates */ ++ ingenic_clk_register_gate(ctx, x1600_gate_clks, ARRAY_SIZE(x1600_gate_clks)); ++ ++ /* Register Powers */ ++ ingenic_power_register_gate(ctx, x1600_gate_power, ARRAY_SIZE(x1600_gate_power)); ++ ++ ingenic_clk_of_add_provider(np, ctx); ++ ++ ++ //ingenic_clk_of_dump(ctx); ++ ++ ++ pr_info("=========== x1600 clocks: =============\n" ++ "\tapll = %lu , mpll = %lu, ddr = %lu\n" ++ "\tcpu_clk = %lu , l2c_clk = %lu\n" ++ "\tahb0_clk = %lu , ahb2_clk = %lu\n" ++ "\tapb_clk = %lu , ext_clk = %lu\n\n", ++ _get_rate("apll"), _get_rate("mpll"), _get_rate("div_ddr"), ++ _get_rate("div_cpu"), _get_rate("div_l2c"), ++ _get_rate("div_ahb0"), _get_rate("div_ahb2"), ++ _get_rate("div_apb"), _get_rate("ext")); ++ ++} ++ ++CLK_OF_DECLARE(x1600_clk, "ingenic,x1600-clocks", x1600_clk_init); ++ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-x2000.c b/module_drivers/drivers/clk/ingenic-v2/clk-x2000.c +new file mode 100644 +index 000000000..d5be8c7e3 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-x2000.c +@@ -0,0 +1,361 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "clk.h" ++#include "clk-pll-v1.h" ++ ++ ++/******************************************************************************* ++ * FIXED CLK ++ ********************************************************************************/ ++static struct ingenic_fixed_rate_clock x2000_fixed_rate_ext_clks[] __initdata = { ++ FRATE(CLK_EXT, "ext", NULL, 0, 24000000), ++ FRATE(CLK_RTC_EXT, "rtc_ext", NULL, 0, 32768), ++ FRATE(CLK_EXT_DIV_512, "ext_div_512", NULL,0, 46875), ++}; ++ ++ ++ ++/******************************************************************************* ++ * PLL ++ ********************************************************************************/ ++ ++static struct ingenic_pll_rate_table x2000_pll_rate_table[] = { ++ PLL_RATE(1500000000, 124, 1, 1), ++ PLL_RATE(1200000000, 49, 0, 1), ++ PLL_RATE(800000000, 199, 2, 2), ++ PLL_RATE(600000000, 49, 0, 2), ++ PLL_RATE(300000000, 49, 0, 3), ++}; ++ ++ ++ ++/*PLL HWDESC*/ ++static struct ingenic_pll_hwdesc apll_hwdesc = \ ++ PLL_DESC(CPM_CPAPCR, 20, 9, 14, 6, 11, 3, 3, 0, pll_od_encode); ++ ++static struct ingenic_pll_hwdesc mpll_hwdesc = \ ++ PLL_DESC(CPM_CPMPCR, 20, 9, 14, 6, 11, 3, 3, 0, pll_od_encode); ++ ++static struct ingenic_pll_hwdesc epll_hwdesc = \ ++ PLL_DESC(CPM_CPEPCR, 20, 9, 14, 6, 11, 3, 3, 0, pll_od_encode); ++ ++ ++ ++static struct ingenic_pll_clock x2000_pll_clks[] __initdata = { ++ PLL(CLK_PLL_APLL, "apll", "ext", &apll_hwdesc, x2000_pll_rate_table), ++ PLL(CLK_PLL_MPLL, "mpll", "ext", &mpll_hwdesc, x2000_pll_rate_table), ++ PLL(CLK_PLL_EPLL, "epll", "ext", &epll_hwdesc, x2000_pll_rate_table), ++}; ++ ++ ++/******************************************************************************* ++ * MUX ++ ********************************************************************************/ ++PNAME(mux_table_0) = {"stop", "ext", "apll"}; ++PNAME(mux_table_1) = {"stop", "sclka", "mpll"}; ++PNAME(mux_table_2) = {"sclka", "mpll", "epll"}; ++PNAME(mux_table_3) = {"sclka", "mpll", "ext"}; ++PNAME(mux_table_4) = {"sclka", "epll"}; ++PNAME(mux_table_5) = {"mux_ahb2", "ext"}; ++PNAME(mux_table_6) = {"ext", "div_i2s3"}; ++PNAME(mux_table_7) = {"div_i2s0", "div_i2s1", "div_i2s2", "div_i2s3"}; ++PNAME(mux_table_8) = {"ext_div_512", "rtc_ext"}; ++ ++static unsigned int ingenic_mux_table[] = {0, 1, 2, 3}; ++ ++ ++static struct ingenic_mux_clock x2000_mux_clks[] __initdata = { ++ MUX(CLK_MUX_SCLKA, "sclka", ingenic_mux_table, mux_table_0, CPM_CPCCR, 30, 2, 0), ++ MUX(CLK_MUX_CPU_L2C, "mux_cpu_l2c", ingenic_mux_table, mux_table_1, CPM_CPCCR, 28, 2, 0), ++ MUX(CLK_MUX_AHB0, "mux_ahb0", ingenic_mux_table, mux_table_1, CPM_CPCCR, 26, 2, 0), ++ MUX(CLK_MUX_AHB2, "mux_ahb2", ingenic_mux_table, mux_table_1, CPM_CPCCR, 24, 2, 0), ++ ++ MUX(CLK_MUX_DDR, "mux_ddr", ingenic_mux_table, mux_table_1, CPM_DDRCDR, 30, 2, 0), ++ MUX(CLK_MUX_MACPHY, "mux_macphy", ingenic_mux_table, mux_table_2, CPM_MACCDR, 30, 2, 0), ++ MUX(CLK_MUX_MACTXPHY, "mux_mactxphy", ingenic_mux_table, mux_table_2, CPM_MACTXCDR, 30, 2, 0), ++ MUX(CLK_MUX_MACTXPHY1, "mux_mactxphy1", ingenic_mux_table, mux_table_2, CPM_MACTXCDR1, 30, 2, 0), ++ MUX(CLK_MUX_MACPTP, "mux_macptp", ingenic_mux_table, mux_table_2, CPM_MACPTP, 30, 2, 0), ++ MUX(CLK_MUX_I2S0, "mux_i2s0", ingenic_mux_table, mux_table_4, CPM_I2S0CDR, 30, 1, 0), ++ MUX(CLK_MUX_I2S1, "mux_i2s1", ingenic_mux_table, mux_table_4, CPM_I2S1CDR, 30, 1, 0), ++ MUX(CLK_MUX_I2S2, "mux_i2s2", ingenic_mux_table, mux_table_4, CPM_I2S2CDR, 30, 1, 0), ++ MUX(CLK_MUX_I2S3, "mux_i2s3", ingenic_mux_table, mux_table_4, CPM_I2S3CDR, 30, 1, 0), ++ MUX(CLK_MUX_AUDIO_RAM, "mux_audio_ram", ingenic_mux_table, mux_table_5, CPM_AUDIOCR, 30, 1, 0), ++ MUX(CLK_MUX_SPDIF, "mux_spdif", ingenic_mux_table, mux_table_7, CPM_AUDIOCR, 3, 2, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), ++ MUX(CLK_MUX_PCM, "mux_pcm", ingenic_mux_table, mux_table_7, CPM_AUDIOCR, 1, 2, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), ++ MUX(CLK_MUX_DMIC, "mux_dmic", ingenic_mux_table, mux_table_6, CPM_AUDIOCR, 0, 1, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), ++ MUX(CLK_MUX_LCD, "mux_lcd", ingenic_mux_table, mux_table_2, CPM_LPCDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC0, "mux_msc0", ingenic_mux_table, mux_table_3, CPM_MSC0CDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC1, "mux_msc1", ingenic_mux_table, mux_table_3, CPM_MSC1CDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC2, "mux_msc2", ingenic_mux_table, mux_table_3, CPM_MSC2CDR, 30, 2, 0), ++ MUX(CLK_MUX_SFC, "mux_sfc", ingenic_mux_table, mux_table_2, CPM_SFCCDR, 30, 2, 0), ++ MUX(CLK_MUX_SSI, "mux_ssi", ingenic_mux_table, mux_table_2, CPM_SSICDR, 30, 2, 0), ++ MUX(CLK_MUX_CIM, "mux_cim", ingenic_mux_table, mux_table_2, CPM_CIMCDR, 30, 2, 0), ++ MUX(CLK_MUX_PWM, "mux_pwm", ingenic_mux_table, mux_table_2, CPM_PWMCDR, 30, 2, 0), ++ MUX(CLK_MUX_ISP, "mux_isp", ingenic_mux_table, mux_table_2, CPM_ISPCDR, 30, 2, 0), ++ MUX(CLK_MUX_RSA, "mux_rsa", ingenic_mux_table, mux_table_2, CPM_RSACDR, 30, 2, 0), ++ MUX(CLK_MUX_WDT, "mux_wdt", ingenic_mux_table, mux_table_8, CPM_OPCR, 2, 1, 0), ++ ++}; ++ ++/******************************************************************************* ++ * DIV BUS ++ ********************************************************************************/ ++ ++static struct ingenic_bus_clock x2000_bus_div_clks[] __initdata = { ++ BUS_DIV(CLK_DIV_CPU, "div_cpu", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_L2C, "div_l2c", "mux_cpu_l2c", CPM_CPCCR, 4, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB0, "div_ahb0", "mux_ahb0", CPM_CPCCR, 8, 4, 0, 0, CPM_CPCSR, 1, 21, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB2, "div_ahb2", "mux_ahb2", CPM_CPCCR, 12, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_APB, "div_apb", "mux_ahb2", CPM_CPCCR, 16, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_CPU_L2C_X1, "div_cpu_l2c_x1", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_ONE), ++ BUS_DIV(CLK_DIV_CPU_L2C_X2, "div_cpu_l2c_x2", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_TWO), ++}; ++ ++ ++/******************************************************************************* ++ * DIV ++ ********************************************************************************/ ++ ++static struct clk_div_table x2000_clk_div_table[256] = {}; ++ ++static struct ingenic_div_clock x2000_div_clks[] __initdata = { ++ DIV(CLK_DIV_DDR, "div_ddr", "mux_ddr", CPM_DDRCDR, 4, 0, NULL), ++ DIV(CLK_DIV_MACPHY, "div_macphy", "mux_macphy", CPM_MACCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MACTXPHY, "div_mactxphy0", "mux_mactxphy", CPM_MACTXCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MACTXPHY1, "div_mactxphy1", "mux_mactxphy1", CPM_MACTXCDR1, 8, 0, NULL), ++ DIV(CLK_DIV_MACPTP, "div_macptp", "mux_macptp", CPM_MACPTP, 8, 0, NULL), ++ DIV(CLK_DIV_LCD, "div_lcd", "mux_lcd", CPM_LPCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MSC0, "div_msc0", "mux_msc0", CPM_MSC0CDR, 8, 0, x2000_clk_div_table), ++ DIV(CLK_DIV_MSC1, "div_msc1", "mux_msc1", CPM_MSC1CDR, 8, 0, x2000_clk_div_table), ++ DIV(CLK_DIV_MSC2, "div_msc2", "mux_msc2", CPM_MSC2CDR, 8, 0, x2000_clk_div_table), ++ DIV(CLK_DIV_SFC, "div_sfc", "mux_sfc", CPM_SFCCDR, 8, 0, NULL), ++ DIV(CLK_DIV_SSI, "div_ssi", "mux_ssi", CPM_SSICDR, 8, 0, NULL), ++ DIV(CLK_DIV_CIM, "div_cim", "mux_cim", CPM_CIMCDR, 8, 0, NULL), ++ DIV(CLK_DIV_PWM, "div_pwm", "mux_pwm", CPM_PWMCDR, 4, 0, NULL), ++ DIV(CLK_DIV_ISP, "div_isp", "mux_isp", CPM_ISPCDR, 4, 0, NULL), ++ DIV(CLK_DIV_RSA, "div_rsa", "mux_rsa", CPM_RSACDR, 4, 0, NULL), ++ ++}; ++ ++/******************************************************************************* ++ * FRACTIONAL-DIVIDER ++ ********************************************************************************/ ++ ++static struct ingenic_fra_div_clock x2000_fdiv_clks[] __initdata = { ++ FRA_DIV(CLK_DIV_I2S0, "div_i2s0", "mux_i2s0", CPM_I2S0CDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2S1, "div_i2s1", "mux_i2s1", CPM_I2S1CDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2S2, "div_i2s2", "mux_i2s2", CPM_I2S2CDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2S3, "div_i2s3", "mux_i2s3", CPM_I2S3CDR, 20, 9, 0, 20), ++}; ++ ++/******************************************************************************* ++ * GATE ++ ********************************************************************************/ ++static struct ingenic_gate_clock x2000_gate_clks[] __initdata = { ++ ++ GATE(CLK_GATE_DDR, "gate_ddr", "div_ddr", CPM_CLKGR, 31, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++// GATE(CLK_GATE_IPU, "gate_ipu", "div_ipu", CPM_CLKGR, 30, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AHB0, "gate_ahb0", "div_ahb0", CPM_CLKGR, 29, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_APB0, "gate_apb0", "div_ahb0", CPM_CLKGR, 28, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_RTC, "gate_rtc", "rtc_ext", CPM_CLKGR, 27, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI1, "gate_ssi1", "div_ssi", CPM_CLKGR, 26, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_RSA, "gate_rsa", "div_rsa", CPM_CLKGR, 25, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AES, "gate_aes", "div_ahb2", CPM_CLKGR, 24, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_LCD, "gate_lcd", "div_lcd", CPM_CLKGR, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_CIM, "gate_cim", "div_cim", CPM_CLKGR, 22, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PDMA, "gate_pdma", "div_ahb2", CPM_CLKGR, 21, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OST, "gate_ost", "ext", CPM_CLKGR, 20, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI0, "gate_ssi0", "div_ssi", CPM_CLKGR, 19, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_TCU, "gate_tcu", "div_apb", CPM_CLKGR, 18, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DTRNG, "gate_dtrng", "div_apb", CPM_CLKGR, 17, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART2, "gate_uart2", "div_apb", CPM_CLKGR, 16, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART1, "gate_uart1", "div_apb", CPM_CLKGR, 15, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART0, "gate_uart0", "div_apb", CPM_CLKGR, 14, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SADC, "gate_sadc", "div_apb", CPM_CLKGR, 13, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_HELIX, "gate_helix", "div_ahb0", CPM_CLKGR, 12, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AUDIO, "gate_audio", "div_ahb2", CPM_CLKGR, 11, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB3, "gate_i2c3", "div_apb", CPM_CLKGR, 10, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB2, "gate_i2c2", "div_apb", CPM_CLKGR, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB1, "gate_i2c1", "div_apb", CPM_CLKGR, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB0, "gate_i2c0", "div_apb", CPM_CLKGR, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SCC, "gate_scc", "div_apb", CPM_CLKGR, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC1, "gate_msc1", "div_msc1", CPM_CLKGR, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC0, "gate_msc0", "div_msc0", CPM_CLKGR, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OTG, "gate_otg", "div_ahb2", CPM_CLKGR, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SFC, "gate_sfc", "div_sfc", CPM_CLKGR, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_EFUSE, "gate_efuse", "div_ahb2", CPM_CLKGR, 1, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_NEMC, "gate_nemc", "div_ahb2", CPM_CLKGR, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ARB, "gate_arb", "div_ahb0", CPM_CLKGR1, 30, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_DSI, "gate_dsi", "div_ahb0", CPM_CLKGR1, 29, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_CSI, "gate_csi", "div_ahb0", CPM_CLKGR1, 28, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_INTC, "gate_intc", "div_ahb2", CPM_CLKGR1, 26, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC2, "gate_msc2", "div_msc2", CPM_CLKGR1, 25, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_GMAC1, "gate_gmac1", "div_ahb2", CPM_CLKGR1, 24, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_GMAC0, "gate_gmac0", "div_ahb2", CPM_CLKGR1, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART9, "gate_uart9", "div_apb", CPM_CLKGR1, 22, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART8, "gate_uart8", "div_apb", CPM_CLKGR1, 21, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART7, "gate_uart7", "div_apb", CPM_CLKGR1, 20, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UATR6, "gate_uart6", "div_apb", CPM_CLKGR1, 19, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART5, "gate_uart5", "div_apb", CPM_CLKGR1, 18, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART4, "gate_uart4", "div_apb", CPM_CLKGR1, 17, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART3, "gate_uart3", "div_apb", CPM_CLKGR1, 16, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SPDIF, "gate_spdif", "mux_spdif", CPM_CLKGR1, 14, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DMIC, "gate_dmic", "mux_dmic", CPM_CLKGR1, 13, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PCM, "gate_pcm", "mux_pcm", CPM_CLKGR1, 12, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S3, "gate_i2s3", "div_i2s3", CPM_CLKGR1, 11, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S2, "gate_i2s2", "div_i2s2", CPM_CLKGR1, 10, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S1, "gate_i2s1", "div_i2s1", CPM_CLKGR1, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2S0, "gate_i2s0", "div_i2s0", CPM_CLKGR1, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ROT, "gate_rot", "div_ahb0", CPM_CLKGR1, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_HASH, "gate_hash", "div_ahb2", CPM_CLKGR1, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PWM, "gate_pwm", "div_pwm", CPM_CLKGR1, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_FELIX, "gate_felix", "div_ahb0", CPM_CLKGR1, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ISP1, "gate_isp1", "div_apb", CPM_CLKGR1, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ISP0, "gate_isp0", "div_apb", CPM_CLKGR1, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB5, "gate_i2c5", "div_apb", CPM_CLKGR1, 1, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB4, "gate_i2c4", "div_apb", CPM_CLKGR1, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_USBPHY, "gate_usbphy", "div_apb", CPM_OPCR, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_CE_I2S0, "ce_i2s0", "div_i2s0", CPM_I2S0CDR, 29, 0, 0), ++ GATE(CLK_CE_I2S1, "ce_i2s1", "div_i2s1", CPM_I2S1CDR, 29, 0, 0), ++ GATE(CLK_CE_I2S2, "ce_i2s2", "div_i2s2", CPM_I2S2CDR, 29, 0, 0), ++ GATE(CLK_CE_I2S3, "ce_i2s3", "div_i2s3", CPM_I2S3CDR, 29, 0, 0), ++}; ++ ++static struct ingenic_gate_power x2000_gate_power[] __initdata = { ++ ++ POWER(POWER_ISP0, "power_isp0", "gate_isp0", CPM_LCR, 31, 27, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ POWER(POWER_ISP1, "power_isp1", "gate_isp1", CPM_LCR, 30, 26, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ POWER(POWER_FELIX, "power_felix", "gate_felix", CPM_LCR, 29, 25, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ POWER(POWER_HELIX, "power_helix", "gate_helix", CPM_LCR, 28, 24, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, POWER_GATE_WAIT), ++ ++ POWER(PD_MEM_NEMC, "pd_mem_nemc", "gate_nemc", CPM_MPDCR, 28, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_USB, "pd_mem_usb", "gate_usb", CPM_MPDCR, 27, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SFC, "pd_mem_sfc", "gate_sfc", CPM_MPDCR, 26, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_PDMA_SEC, "pd_mem_pdma_sec", "gate_pdma", CPM_MPDCR, 25, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_PDMA, "pd_mem_pdma", "gate_pdma", CPM_MPDCR, 24, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC2, "pd_mem_msc2", "gate_msc2", CPM_MPDCR, 23, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC1, "pd_mem_msc1", "gate_msc1", CPM_MPDCR, 22, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_MSC0, "pd_mem_msc0", "gate_msc0", CPM_MPDCR, 21, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_GMAC1, "pd_mem_gmac1", "gate_gmac1", CPM_MPDCR, 20, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_GMAC0, "pd_mem_gmac0", "gate_gmac0", CPM_MPDCR, 19, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DMIC, "pd_mem_dmic", "gate_dmic", CPM_MPDCR, 18, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_AUDIO, "pd_mem_audio", "gate_audio", CPM_MPDCR, 17, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_AES, "pd_mem_aes", "gate_aes", CPM_MPDCR, 16, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DSI, "pd_mem_dsi", "gate_dsi", CPM_MPDCR, 12, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SSI1, "pd_mem_ssi1", "gate_ssi1", CPM_MPDCR, 11, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_SSI0, "pd_mem_ssi0", "gate_ssi0", CPM_MPDCR, 10, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART9, "pd_mem_uart9", "gate_uart9", CPM_MPDCR, 9, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART8, "pd_mem_uart8", "gate_uart8", CPM_MPDCR, 8, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART7, "pd_mem_uart7", "gate_uart7", CPM_MPDCR, 7, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART6, "pd_mem_uart6", "gate_uart6", CPM_MPDCR, 6, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART5, "pd_mem_uart5", "gate_uart5", CPM_MPDCR, 5, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART4, "pd_mem_uart4", "gate_uart4", CPM_MPDCR, 4, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART3, "pd_mem_uart3", "gate_uart3", CPM_MPDCR, 3, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART2, "pd_mem_uart2", "gate_uart2", CPM_MPDCR, 2, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART1, "pd_mem_uart1", "gate_uart1", CPM_MPDCR, 1, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_UART0, "pd_mem_uart0", "gate_uart0", CPM_MPDCR, 0, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_ROT, "pd_mem_rot", "gate_rot", CPM_MPDCR1, 8, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_CIM, "pd_mem_cim", "gate_cim", CPM_MPDCR1, 7, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DPU, "pd_mem_dpu", "gate_dpu", CPM_MPDCR1, 6, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH6, "pd_mem_ddr_ch6", "gate_ddr", CPM_MPDCR1, 5, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH5, "pd_mem_ddr_ch5", "gate_ddr", CPM_MPDCR1, 4, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH3, "pd_mem_ddr_ch3", "gate_ddr", CPM_MPDCR1, 3, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH1, "pd_mem_ddr_ch1", "gate_ddr", CPM_MPDCR1, 2, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_CH0, "pd_mem_ddr_ch0", "gate_ddr", CPM_MPDCR1, 1, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ POWER(PD_MEM_DDR_TOP, "pd_mem_ddr_top", "gate_ddr", CPM_MPDCR1, 0, 0, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE, 0), ++ ++}; ++ ++static void clk_div_table_generate(void) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(x2000_clk_div_table); i++) { ++ x2000_clk_div_table[i].val = i; ++ x2000_clk_div_table[i].div = (i + 1) * 4; ++ } ++ ++} ++ ++static const struct of_device_id ext_clk_match[] __initconst = { ++ { .compatible = "ingenic,fixed-clock", .data = (void *)0, }, ++ {}, ++}; ++ ++ ++/* Register x2000 clocks. */ ++static void __init x2000_clk_init(struct device_node *np, void __iomem *base) ++{ ++ struct ingenic_clk_provider *ctx; ++ void __iomem *reg_base; ++ ++ ++ printk("x2000 Clock Power Management Unit init!\n"); ++ ++ reg_base = base; ++ ++ if (np) { ++ reg_base = of_iomap(np, 0); ++ if (!reg_base) ++ panic("%s: failed to map registers\n", __func__); ++ } ++ ++ ++ ctx = ingenic_clk_init(np, reg_base, NR_CLKS); ++ if (!ctx) ++ panic("%s: unable to allocate context.\n", __func__); ++ ++ /* Register Ext Clocks From DT */ ++ ingenic_clk_of_register_fixed_ext(ctx, x2000_fixed_rate_ext_clks, ++ ARRAY_SIZE(x2000_fixed_rate_ext_clks), ext_clk_match); ++ ++ /* Register PLLs. */ ++ ingenic_clk_register_pll(ctx, x2000_pll_clks, ++ ARRAY_SIZE(x2000_pll_clks), reg_base); ++ ++ ++ /* Register Muxs */ ++ ingenic_clk_register_mux(ctx, x2000_mux_clks, ARRAY_SIZE(x2000_mux_clks)); ++ ++ /* Register Bus Divs */ ++ ingenic_clk_register_bus_div(ctx, x2000_bus_div_clks, ARRAY_SIZE(x2000_bus_div_clks)); ++ ++ /* Register Divs */ ++ clk_div_table_generate(); ++ ingenic_clk_register_cgu_div(ctx, x2000_div_clks, ARRAY_SIZE(x2000_div_clks)); ++ ++ /* Register Fractional Divs */ ++ ingenic_clk_register_fra_div(ctx, x2000_fdiv_clks, ARRAY_SIZE(x2000_fdiv_clks)); ++ ++ /* Register Gates */ ++ ingenic_clk_register_gate(ctx, x2000_gate_clks, ARRAY_SIZE(x2000_gate_clks)); ++ ++ /* Register Powers */ ++ ingenic_power_register_gate(ctx, x2000_gate_power, ARRAY_SIZE(x2000_gate_power)); ++ ++ ingenic_clk_of_add_provider(np, ctx); ++ ++ ++ //ingenic_clk_of_dump(ctx); ++ ++ ++ pr_info("=========== x2000 clocks: =============\n" ++ "\tapll = %lu , mpll = %lu\n" ++ "\tcpu_clk = %lu , l2c_clk = %lu\n" ++ "\tahb0_clk = %lu , ahb2_clk = %lu\n" ++ "\tapb_clk = %lu , ext_clk = %lu\n\n", ++ _get_rate("apll"), _get_rate("mpll"), ++ _get_rate("div_cpu"), _get_rate("div_l2c"), ++ _get_rate("div_ahb0"), _get_rate("div_ahb2"), ++ _get_rate("div_apb"), _get_rate("ext")); ++ ++} ++ ++CLK_OF_DECLARE(x2000_clk, "ingenic,x2000-clocks", x2000_clk_init); ++ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk-x2500.c b/module_drivers/drivers/clk/ingenic-v2/clk-x2500.c +new file mode 100644 +index 000000000..be585d0d3 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk-x2500.c +@@ -0,0 +1,296 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "clk.h" ++ ++#define CLK_FLG_ENABLE BIT(1) ++static struct ingenic_clk_provider *ctx; ++ ++extern void __clk_set_flags(struct clk *clk, unsigned long enable); ++/******************************************************************************* ++ * FIXED CLK ++ ********************************************************************************/ ++static struct ingenic_fixed_rate_clock x2500_fixed_rate_ext_clks[] __initdata = { ++ FRATE(CLK_EXT, "ext", NULL, 0, 24000000), ++ FRATE(CLK_RTC_EXT, "rtc_ext", NULL, 0, 32768), ++}; ++ ++ ++ ++/******************************************************************************* ++ * PLL ++ ********************************************************************************/ ++ ++static struct ingenic_pll_rate_table x2500_pll_rate_table[] = { ++ PLL_RATE(1500000000, 125, 1, 2, 1), ++ PLL_RATE(1404000000, 117, 1, 2, 1), ++ PLL_RATE(1392000000, 116, 1, 2, 1), ++ PLL_RATE(1296000000, 108, 1, 2, 1), ++ PLL_RATE(1200000000, 100, 1, 2, 1), ++ PLL_RATE(1000000000, 125, 1, 3, 1), ++ PLL_RATE(900000000, 75, 1, 2, 1), ++ PLL_RATE(891000000, 297, 4, 2, 1), ++ PLL_RATE(864000000, 72, 1, 2, 1), ++ PLL_RATE(600000000, 75, 1, 3, 1), ++}; ++ ++ ++ ++/*PLL HWDESC*/ ++static struct ingenic_pll_hwdesc apll_hwdesc = \ ++ PLL_DESC(CPM_CPAPCR, 20, 12, 14, 6, 11, 3, 8, 3, 3, 0); ++ ++static struct ingenic_pll_hwdesc mpll_hwdesc = \ ++ PLL_DESC(CPM_CPMPCR, 20, 12, 14, 6, 11, 3, 8, 3, 3, 0); ++ ++static struct ingenic_pll_hwdesc vpll_hwdesc = \ ++ PLL_DESC(CPM_CPVPCR, 20, 12, 14, 6, 11, 3, 8, 3, 3, 0); ++ ++static struct ingenic_pll_hwdesc epll_hwdesc = \ ++ PLL_DESC(CPM_CPEPCR, 20, 12, 14, 6, 11, 3, 8, 3, 3, 0); ++ ++ ++ ++static struct ingenic_pll_clock x2500_pll_clks[] __initdata = { ++ PLL(CLK_PLL_APLL, "apll", "ext", &apll_hwdesc, x2500_pll_rate_table), ++ PLL(CLK_PLL_MPLL, "mpll", "ext", &mpll_hwdesc, x2500_pll_rate_table), ++ PLL(CLK_PLL_VPLL, "vpll", "ext", &vpll_hwdesc, x2500_pll_rate_table), ++ PLL(CLK_PLL_EPLL, "epll", "ext", &epll_hwdesc, x2500_pll_rate_table), ++}; ++ ++ ++/******************************************************************************* ++ * MUX ++ ********************************************************************************/ ++PNAME(mux_table_0) = {"stop", "ext", "apll"}; ++PNAME(mux_table_1) = {"stop", "sclka", "mpll"}; ++PNAME(mux_table_2) = {"sclka", "mpll", "vpll", "epll"}; ++PNAME(mux_table_3) = {"sclka", "mpll", "epll", "ext"}; ++PNAME(mux_table_4) = {"sclka", "vpll", "ext"}; ++PNAME(mux_table_5) = {"mux_ahb2", "ext"}; ++ ++static unsigned int ingenic_mux_table[] = {0, 1, 2, 3}; ++ ++ ++static struct ingenic_mux_clock x2500_mux_clks[] __initdata = { ++ MUX(CLK_MUX_SCLKA, "sclka", ingenic_mux_table, mux_table_0, CPM_CPCCR, 30, 2, 0), ++ MUX(CLK_MUX_CPU_L2C, "mux_cpu_l2c", ingenic_mux_table, mux_table_1, CPM_CPCCR, 28, 2, 0), ++ MUX(CLK_MUX_AHB0, "mux_ahb0", ingenic_mux_table, mux_table_1, CPM_CPCCR, 26, 2, 0), ++ MUX(CLK_MUX_AHB2, "mux_ahb2", ingenic_mux_table, mux_table_1, CPM_CPCCR, 24, 2, 0), ++ ++ MUX(CLK_MUX_DDR, "mux_ddr", ingenic_mux_table, mux_table_1, CPM_DDRCDR, 30, 2, 0), ++ MUX(CLK_MUX_EL150, "mux_el150", ingenic_mux_table, mux_table_2, CPM_EL150CDR, 30, 2, 0), ++ MUX(CLK_MUX_RSA, "mux_rsa", ingenic_mux_table, mux_table_2, CPM_RSACDR, 30, 2, 0), ++ MUX(CLK_MUX_MACPHY, "mux_macphy", ingenic_mux_table, mux_table_2, CPM_MACCDR, 30, 2, 0), ++ MUX(CLK_MUX_SFC, "mux_sfc", ingenic_mux_table, mux_table_2, CPM_SFCCDR, 30, 2, 0), ++ MUX(CLK_MUX_LCD, "mux_lcd", ingenic_mux_table, mux_table_2, CPM_LPCDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC0, "mux_msc0", ingenic_mux_table, mux_table_2, CPM_MSC0CDR, 30, 2, 0), ++ MUX(CLK_MUX_MSC1, "mux_msc1", ingenic_mux_table, mux_table_2, CPM_MSC1CDR, 30, 2, 0), ++ MUX(CLK_MUX_SSI, "mux_ssi", ingenic_mux_table, mux_table_2, CPM_SSICDR, 30, 2, 0), ++ MUX(CLK_MUX_I2ST, "mux_i2st", ingenic_mux_table, mux_table_2, CPM_I2STCDR, 30, 2, 0), ++ MUX(CLK_MUX_ISP, "mux_isp", ingenic_mux_table, mux_table_2, CPM_ISPCDR, 30, 2, 0), ++ MUX(CLK_MUX_I2SR, "mux_i2sr", ingenic_mux_table, mux_table_2, CPM_I2SRCDR, 30, 2, 0), ++ MUX(CLK_MUX_CIM0, "mux_cim0", ingenic_mux_table, mux_table_2, CPM_CIM0CDR, 30, 2, 0), ++ MUX(CLK_MUX_CIM1, "mux_cim1", ingenic_mux_table, mux_table_2, CPM_CIM1CDR, 30, 2, 0), ++ MUX(CLK_MUX_CIM2, "mux_cim2", ingenic_mux_table, mux_table_2, CPM_CIM2CDR, 30, 2, 0), ++ MUX(CLK_MUX_BSCALER, "mux_bscaler", ingenic_mux_table, mux_table_2, CPM_BSCALERCDR, 30, 2, 0), ++ MUX(CLK_MUX_BT0, "mux_bt0", ingenic_mux_table, mux_table_2, CPM_BT0CDR, 30, 2, 0), ++ ++}; ++ ++/******************************************************************************* ++ * DIV BUS ++ ********************************************************************************/ ++ ++static struct ingenic_bus_clock x2500_bus_div_clks[] __initdata = { ++ BUS_DIV(CLK_DIV_CPU, "div_cpu", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_L2C, "div_l2c", "mux_cpu_l2c", CPM_CPCCR, 4, 4, 0, 0, CPM_CPCSR, 0, 22, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB0, "div_ahb0", "mux_ahb0", CPM_CPCCR, 8, 4, 0, 0, CPM_CPCSR, 1, 21, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_AHB2, "div_ahb2", "mux_ahb2", CPM_CPCCR, 12, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_APB, "div_apb", "mux_ahb2", CPM_CPCCR, 16, 4, 0, 0, CPM_CPCSR, 2, 20, BUS_DIV_SELF), ++ BUS_DIV(CLK_DIV_CPU_L2C_X1, "div_cpu_l2c_x1", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_ONE), ++ BUS_DIV(CLK_DIV_CPU_L2C_X2, "div_cpu_l2c_x2", "mux_cpu_l2c", CPM_CPCCR, 0, 4, 4, 4, CPM_CPCSR, 0, 22, BUS_DIV_TWO), ++}; ++ ++ ++/******************************************************************************* ++ * DIV ++ ********************************************************************************/ ++ ++static struct clk_div_table x2500_clk_div_table[256] = {}; ++ ++static struct ingenic_div_clock x2500_div_clks[] __initdata = { ++ DIV(CLK_DIV_DDR, "div_ddr", "mux_ddr", CPM_DDRCDR, 4, 0, NULL), ++ DIV(CLK_DIV_MACPHY, "div_macphy", "mux_macphy", CPM_MACCDR, 8, 0, NULL), ++ DIV(CLK_DIV_LCD, "div_lcd", "mux_lcd", CPM_LPCDR, 8, 0, NULL), ++ DIV(CLK_DIV_MSC0, "div_msc0", "mux_msc0", CPM_MSC0CDR, 8, 0, x2500_clk_div_table), ++ DIV(CLK_DIV_MSC1, "div_msc1", "mux_msc1", CPM_MSC1CDR, 8, 0, x2500_clk_div_table), ++ DIV(CLK_DIV_SFC, "div_sfc", "mux_sfc", CPM_SFCCDR, 8, 0, NULL), ++ DIV(CLK_DIV_SSI, "div_ssi", "mux_ssi", CPM_SSICDR, 8, 0, NULL), ++ DIV(CLK_DIV_CIM0, "div_cim0", "mux_cim0", CPM_CIM0CDR, 8, 0, NULL), ++ DIV(CLK_DIV_CIM1, "div_cim1", "mux_cim1", CPM_CIM1CDR, 8, 0, NULL), ++ DIV(CLK_DIV_CIM2, "div_cim2", "mux_cim2", CPM_CIM2CDR, 8, 0, NULL), ++ DIV(CLK_DIV_ISP, "div_isp", "mux_isp", CPM_ISPCDR, 4, 0, NULL), ++ DIV(CLK_DIV_RSA, "div_rsa", "mux_rsa", CPM_RSACDR, 4, 0, NULL), ++ DIV(CLK_DIV_EL150, "div_el150", "mux_el150", CPM_EL150CDR, 4, 0, NULL), ++ DIV(CLK_DIV_BSCALER, "div_bscaler", "mux_bscaler", CPM_BSCALERCDR, 4, 0, NULL), ++ DIV(CLK_DIV_BT0, "div_bt0", "mux_bt0", CPM_BT0CDR, 8, 0, NULL), ++ ++}; ++ ++/******************************************************************************* ++ * FRACTIONAL-DIVIDER ++ ********************************************************************************/ ++ ++static struct ingenic_fra_div_clock x2500_fdiv_clks[] __initdata = { ++ FRA_DIV(CLK_DIV_I2ST, "div_i2st", "mux_i2st", CPM_I2STCDR, 20, 9, 0, 20), ++ FRA_DIV(CLK_DIV_I2SR, "div_i2sr", "mux_i2sr", CPM_I2SRCDR, 20, 9, 0, 20), ++}; ++ ++/******************************************************************************* ++ * GATE ++ ********************************************************************************/ ++static struct ingenic_gate_clock x2500_gate_clks[] __initdata = { ++ ++ GATE(CLK_GATE_DDR, "gate_ddr", "div_ddr", CPM_CLKGR, 31, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_TCU, "gate_tcu", "div_apb", CPM_CLKGR, 30, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DES, "gate_des", "div_apb", CPM_CLKGR, 28, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_RSA, "gate_rsa", "div_rsa", CPM_CLKGR, 27, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_CSI, "gate_csi", "div_ahb0", CPM_CLKGR, 25, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_LCD, "gate_lcd", "div_lcd", CPM_CLKGR, 24, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_ISP, "gate_isp", "div_isp", CPM_CLKGR, 23, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_PDMA, "gate_pdma", "div_ahb2", CPM_CLKGR, 22, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SFC, "gate_sfc", "div_sfc", CPM_CLKGR, 21, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI1, "gate_ssi1", "div_ssi", CPM_CLKGR, 20, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_HASH, "gate_hash", "div_ahb2", CPM_CLKGR, 19, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SLV, "gate_slv", "div_apb", CPM_CLKGR, 18, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART3, "gate_uart3", "div_apb", CPM_CLKGR, 17, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART2, "gate_uart2", "div_apb", CPM_CLKGR, 16, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART1, "gate_uart1", "div_apb", CPM_CLKGR, 15, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_UART0, "gate_uart0", "div_apb", CPM_CLKGR, 14, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SADC, "gate_sadc", "div_apb", CPM_CLKGR, 13, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DMIC, "gate_dmic", "mux_apb", CPM_CLKGR, 12, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AIC, "gate_aic", "div_i2st", CPM_CLKGR, 11, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB3, "gate_i2c3", "div_apb", CPM_CLKGR, 10, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB2, "gate_i2c2", "div_apb", CPM_CLKGR, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB1, "gate_i2c1", "div_apb", CPM_CLKGR, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SMB0, "gate_i2c0", "div_apb", CPM_CLKGR, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_SSI0, "gate_ssi0", "div_ssi", CPM_CLKGR, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC1, "gate_msc1", "div_msc1", CPM_CLKGR, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MSC0, "gate_msc0", "div_msc0", CPM_CLKGR, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OTG, "gate_otg", "div_ahb2", CPM_CLKGR, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_BSCALER, "gate_bscaler", "div_bscaler", CPM_CLKGR, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_EFUSE, "gate_efuse", "div_ahb2", CPM_CLKGR, 1, 0, CLK_GATE_HIWORD_MASK), ++ GATE(CLK_GATE_NEMC, "gate_nemc", "div_ahb2", CPM_CLKGR, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_CPU, "gate_cpu", "div_cpu", CPM_CLKGR1, 15, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_APB0, "gate_apb0", "div_ahb0", CPM_CLKGR1, 14, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_OST, "gate_ost", "ext", CPM_CLKGR1, 11, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AHB0, "gate_ahb0", "div_ahb0", CPM_CLKGR1, 10, CLK_IGNORE_UNUSED, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_BUS_MONITOR, "gate_bus_monitor", "div_ahb0", CPM_CLKGR1, 9, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_I2D, "gate_i2d", "div_ahb0", CPM_CLKGR1, 8, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_MIPI_DSI, "gate_dsi", "div_ahb0", CPM_CLKGR1, 7, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DRAWBOX, "gate_drawbox", "div_ahb0", CPM_CLKGR1, 6, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AES, "gate_aes", "div_ahb2", CPM_CLKGR1, 5, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_GMAC, "gate_gmac", "div_ahb2", CPM_CLKGR1, 4, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_AHB1, "gate_ahb1", "div_ahb2", CPM_CLKGR1, 3, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_IPU, "gate_ipu", "div_ahb0", CPM_CLKGR1, 2, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_DTRNG, "gate_dtrng", "div_apb", CPM_CLKGR1, 1, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_GATE_EL150, "gate_el150", "div_el150", CPM_CLKGR1, 0, 0, CLK_GATE_SET_TO_DISABLE), ++ GATE(CLK_CE_I2ST, "ce_i2st", "div_i2st", CPM_I2STCDR, 29, 0, 0), ++ GATE(CLK_CE_I2SR, "ce_i2sr", "div_i2sr", CPM_I2SRCDR, 29, 0, 0), ++ GATE(CLK_GATE_USBPHY, "gate_usbphy", "div_apb", CPM_OPCR, 23, 0, CLK_GATE_SET_TO_DISABLE) ++}; ++ ++static void clk_div_table_generate(void) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(x2500_clk_div_table); i++) { ++ x2500_clk_div_table[i].val = i; ++ x2500_clk_div_table[i].div = (i + 1) * 4; ++ } ++ ++} ++ ++static const struct of_device_id ext_clk_match[] __initconst = { ++ { .compatible = "ingenic,fixed-clock", .data = (void *)0, }, ++ {}, ++}; ++ ++/* Register x2500 clocks. */ ++static void __init x2500_clk_init(struct device_node *np, void __iomem *base) ++{ ++ void __iomem *reg_base; ++ ++ printk("x2500 Clock Power Management Unit init!\n"); ++ ++ reg_base = base; ++ ++ if (np) { ++ reg_base = of_iomap(np, 0); ++ if (!reg_base) ++ panic("%s: failed to map registers\n", __func__); ++ } ++ ++ ++ ctx = ingenic_clk_init(np, reg_base, NR_CLKS); ++ if (!ctx) ++ panic("%s: unable to allocate context.\n", __func__); ++ ++ /* Register Ext Clocks From DT */ ++ ingenic_clk_of_register_fixed_ext(ctx, x2500_fixed_rate_ext_clks, ++ ARRAY_SIZE(x2500_fixed_rate_ext_clks), ext_clk_match); ++ ++ /* Register PLLs. */ ++ ingenic_clk_register_pll(ctx, x2500_pll_clks, ++ ARRAY_SIZE(x2500_pll_clks), reg_base); ++ ++ ++ /* Register Muxs */ ++ ingenic_clk_register_mux(ctx, x2500_mux_clks, ARRAY_SIZE(x2500_mux_clks)); ++ ++ /* Register Bus Divs */ ++ ingenic_clk_register_bus_div(ctx, x2500_bus_div_clks, ARRAY_SIZE(x2500_bus_div_clks)); ++ ++ /* Register Divs */ ++ clk_div_table_generate(); ++ ingenic_clk_register_cgu_div(ctx, x2500_div_clks, ARRAY_SIZE(x2500_div_clks)); ++ ++ /* Register Fractional Divs */ ++ ingenic_clk_register_fra_div(ctx, x2500_fdiv_clks, ARRAY_SIZE(x2500_fdiv_clks)); ++ ++ /* Register Gates */ ++ ingenic_clk_register_gate(ctx, x2500_gate_clks, ARRAY_SIZE(x2500_gate_clks)); ++ ++ /* Register Powers */ ++// ingenic_power_register_gate(ctx, x2500_gate_power, ARRAY_SIZE(x2500_gate_power)); ++ ++ ingenic_clk_of_add_provider(np, ctx); ++ ++ ++ //ingenic_clk_of_dump(ctx); ++ ++ ++ pr_info("=========== x2500 clocks: =============\n" ++ "\tapll = %lu , mpll = %lu\n" ++ "\tcpu_clk = %lu , l2c_clk = %lu\n" ++ "\tahb0_clk = %lu , ahb2_clk = %lu\n" ++ "\tapb_clk = %lu , ext_clk = %lu\n\n", ++ _get_rate("apll"), _get_rate("mpll"), ++ _get_rate("div_cpu"), _get_rate("div_l2c"), ++ _get_rate("div_ahb0"), _get_rate("div_ahb2"), ++ _get_rate("div_apb"), _get_rate("ext")); ++ ++} ++ ++CLK_OF_DECLARE(x2500_clk, "ingenic,x2500-clocks", x2500_clk_init); +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk.c b/module_drivers/drivers/clk/ingenic-v2/clk.c +new file mode 100644 +index 000000000..aa34d7f0a +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk.c +@@ -0,0 +1,518 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "clk.h" ++ ++static LIST_HEAD(clock_reg_cache_list); ++ ++void ingenic_clk_save(void __iomem *base, ++ struct ingenic_clk_reg_sleep *rd, ++ unsigned int num_regs) ++{ ++ for (; num_regs > 0; --num_regs, ++rd) ++ rd->value = readl(base + rd->offset); ++} ++ ++void ingenic_clk_restore(void __iomem *base, ++ struct ingenic_clk_reg_sleep *rd, ++ unsigned int num_regs) ++{ ++ unsigned int timeout = 0xffff; ++ for (; num_regs > 0; --num_regs, ++rd) { ++ ++ if(!rd->ce && !rd->busy) { ++ writel(rd->value, base + rd->offset); ++ } else { ++ writel(rd->value | 1 << rd->ce, base + rd->offset); ++ ++ timeout = 0xffff; ++ ++#if 0 ++ while(--timeout && readl(base + rd->offset) & (1 << rd->busy)); ++ ++ if(!timeout) { ++ printk("Error restore clk regs: %x\n", rd->offset); ++ } ++#endif ++ } ++ } ++} ++ ++/* setup the essentials required to support clock lookup using ccf */ ++struct ingenic_clk_provider *__init ingenic_clk_init(struct device_node *np, ++ void __iomem *base, unsigned long nr_clks) ++{ ++ struct ingenic_clk_provider *ctx; ++ struct clk **clk_table; ++ int i; ++ ++ ctx = kzalloc(sizeof(struct ingenic_clk_provider), GFP_KERNEL); ++ if (!ctx) ++ panic("could not allocate clock provider context.\n"); ++ ++ clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); ++ if (!clk_table) ++ panic("could not allocate clock lookup table\n"); ++ ++ for (i = 0; i < nr_clks; ++i) ++ clk_table[i] = ERR_PTR(-ENOENT); ++ ++ ctx->reg_base = base; ++ ctx->clk_data.clks = clk_table; ++ ctx->clk_data.clk_num = nr_clks; ++ spin_lock_init(&ctx->lock); ++ ++ return ctx; ++} ++ ++void __init ingenic_clk_of_add_provider(struct device_node *np, ++ struct ingenic_clk_provider *ctx) ++{ ++ if (np) { ++ if (of_clk_add_provider(np, of_clk_src_onecell_get, ++ &ctx->clk_data)) ++ panic("could not register clk provider\n"); ++ } ++} ++ ++void ingenic_clk_of_dump(struct ingenic_clk_provider *ctx) ++{ ++ struct clk_onecell_data * clk_data; ++ struct clk *clk; ++ int i; ++ ++ clk_data = &ctx->clk_data; ++ ++ for(i = 0; i < clk_data->clk_num; i++) { ++ ++ clk = clk_data->clks[i]; ++ if(clk != ERR_PTR(-ENOENT)) { ++ printk("clk->id: %d clk->name: %s \n", i, __clk_get_name(clk)); ++ } else { ++ printk("clk->id: %d , clk: %p\n", i, clk); ++ } ++ } ++ ++ ++ ++} ++ ++ ++/* add a clock instance to the clock lookup table used for dt based lookup */ ++void ingenic_clk_add_lookup(struct ingenic_clk_provider *ctx, struct clk *clk, ++ unsigned int id) ++{ ++ if (ctx->clk_data.clks && id) { ++ ctx->clk_data.clks[id] = clk; ++ } ++} ++ ++/* register a list of aliases */ ++void __init ingenic_clk_register_alias(struct ingenic_clk_provider *ctx, ++ const struct ingenic_clock_alias *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ if (!ctx->clk_data.clks) { ++ pr_err("%s: clock table missing\n", __func__); ++ return; ++ } ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ if (!list->id) { ++ pr_err("%s: clock id missing for index %d\n", __func__, ++ idx); ++ continue; ++ } ++ ++ clk = ctx->clk_data.clks[list->id]; ++ if (!clk) { ++ pr_err("%s: failed to find clock %d\n", __func__, ++ list->id); ++ continue; ++ } ++ ++ ret = clk_register_clkdev(clk, list->alias, list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++} ++ ++/* register a list of fixed clocks */ ++void __init ingenic_clk_register_fixed_rate(struct ingenic_clk_provider *ctx, ++ const struct ingenic_fixed_rate_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ clk = clk_register_fixed_rate(NULL, list->name, ++ list->parent_name, list->flags, list->fixed_rate); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ ret = clk_register_clkdev(clk, list->name, NULL); ++ if (ret) ++ pr_err("%s: failed to register clock lookup for %s", ++ __func__, list->name); ++ } ++} ++ ++/* register a list of fixed factor clocks */ ++void __init ingenic_clk_register_fixed_factor(struct ingenic_clk_provider *ctx, ++ const struct ingenic_fixed_factor_clock *list, unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ clk = clk_register_fixed_factor(NULL, list->name, ++ list->parent_name, list->flags, list->mult, list->div); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ } ++} ++ ++/* register a list of mux clocks */ ++void __init ingenic_clk_register_mux(struct ingenic_clk_provider *ctx, ++ const struct ingenic_mux_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ if(list->table) { ++ clk = clk_register_mux_table(NULL, list->name, list->parent_names, ++ list->num_parents, list->flags, ++ ctx->reg_base + list->offset, ++ list->shift, BIT(list->width) - 1, list->mux_flags, list->table, &ctx->lock); ++ } else { ++ clk = clk_register_mux(NULL, list->name, list->parent_names, ++ list->num_parents, list->flags, ++ ctx->reg_base + list->offset, ++ list->shift, list->width, list->mux_flags, &ctx->lock); ++ ++ } ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++ } ++} ++ ++/* register a list of div clocks */ ++void __init ingenic_clk_register_cgu_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_div_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ if (list->table) ++ clk = clk_register_cgu_divider_table(NULL, list->name, ++ list->parent_name, list->flags, ++ ctx->reg_base + list->offset, ++ list->shift, list->width, ++ list->busy_shift, list->en_shift, list->stop_shift, ++ list->div_flags, list->table, &ctx->lock); ++ else ++ clk = clk_register_cgu_divider(NULL, list->name, ++ list->parent_name, list->flags, ++ ctx->reg_base + list->offset, ++ list->shift, list->width, ++ list->busy_shift, list->en_shift, list->stop_shift, ++ list->div_flags, &ctx->lock); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++ } ++} ++ ++/* register a list of div clocks */ ++void __init ingenic_clk_register_bus_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_bus_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ if (list->table) ++ clk = clk_register_bus_divider_table(NULL, list->name, ++ list->parent_name, list->flags, ++ ctx->reg_base + list->cfg_offset, ++ list->div_shift1, list->div_width1, ++ list->div_shift2, list->div_width2, ++ ctx->reg_base + list->busy_offset, ++ list->busy_shift, list->ce_shift, ++ list->div_flags, list->div_flags_2, ++ list->table, &ctx->lock); ++ else ++ clk = clk_register_bus_divider(NULL, list->name, ++ list->parent_name, list->flags, ++ ctx->reg_base + list->cfg_offset, ++ list->div_shift1, list->div_width1, ++ list->div_shift2, list->div_width2, ++ ctx->reg_base + list->busy_offset, ++ list->busy_shift, list->ce_shift, ++ list->div_flags, list->div_flags_2, ++ &ctx->lock); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++ } ++} ++ ++void __init ingenic_clk_register_fra_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_fra_div_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ clk = clk_register_fractional_divider(NULL, ++ list->name, list->parent_name, list->flags, ++ ctx->reg_base + list->offset, ++ list->mshift, list->mwidth, list->nshift, list->nwidth, ++ list->div_flags, &ctx->lock); ++ ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", __func__, list->alias); ++ } ++ } ++} ++ ++ ++/* register a list of gate clocks */ ++void __init ingenic_clk_register_gate(struct ingenic_clk_provider *ctx, ++ const struct ingenic_gate_clock *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret, i; ++ ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ ++ clk = clk_register_gate(NULL, list->name, list->parent_name, list->flags, ++ ctx->reg_base + list->offset, list->bit_idx, ++ list->gate_flags, &ctx->lock); ++ ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ ++ } ++ ++ ++ ++} ++ ++void __init ingenic_power_register_gate(struct ingenic_clk_provider *ctx, ++ const struct ingenic_gate_power *list, ++ unsigned int nr_clk) ++{ ++ struct clk *clk; ++ unsigned int idx, ret, i; ++ ++ for (idx = 0; idx < nr_clk; idx++, list++) { ++ ++ clk = power_register_gate(NULL, list->name, list->parent_name, list->flags, ++ ctx->reg_base + list->offset, list->ctrl_bit, list->wait_bit, ++ list->gate_flags, list->power_flags, &ctx->lock); ++ ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ list->name); ++ continue; ++ } ++ ++ /* register a clock lookup only if a clock alias is specified */ ++ if (list->alias) { ++ ret = clk_register_clkdev(clk, list->alias, ++ list->dev_name); ++ if (ret) ++ pr_err("%s: failed to register lookup %s\n", ++ __func__, list->alias); ++ } ++ ++ ingenic_clk_add_lookup(ctx, clk, list->id); ++ ++ } ++ ++} ++/* ++ * obtain the clock speed of all external fixed clock sources from device ++ * tree and register it ++ */ ++void __init ingenic_clk_of_register_fixed_ext(struct ingenic_clk_provider *ctx, ++ struct ingenic_fixed_rate_clock *fixed_rate_clk, ++ unsigned int nr_fixed_rate_clk, ++ const struct of_device_id *clk_matches) ++{ ++ const struct of_device_id *match; ++ struct device_node *clk_np; ++ u32 freq; ++ u32 index = 0; ++ ++ for_each_matching_node_and_match(clk_np, clk_matches, &match) { ++ if (of_property_read_u32(clk_np, "clock-frequency", &freq)) ++ continue; ++ fixed_rate_clk[index].fixed_rate = freq; ++ index++; ++ } ++ ingenic_clk_register_fixed_rate(ctx, fixed_rate_clk, nr_fixed_rate_clk); ++} ++ ++/* utility function to get the rate of a specified clock */ ++unsigned long _get_rate(const char *clk_name) ++{ ++ struct clk *clk; ++ ++ clk = __clk_lookup(clk_name); ++ if (!clk) { ++ pr_err("%s: could not find clock %s\n", __func__, clk_name); ++ return 0; ++ } ++ ++ return clk_get_rate(clk); ++} ++ ++#ifdef CONFIG_PM ++static int ingenic_clk_suspend(void) ++{ ++ struct ingenic_clock_reg_cache *reg_cache; ++ ++ list_for_each_entry(reg_cache, &clock_reg_cache_list, node) ++ ingenic_clk_save(reg_cache->reg_base, reg_cache->reg_sleep, ++ reg_cache->nr_reg_sleep); ++ return 0; ++} ++ ++static void ingenic_clk_resume(void) ++{ ++ struct ingenic_clock_reg_cache *reg_cache; ++ ++ list_for_each_entry(reg_cache, &clock_reg_cache_list, node) ++ ingenic_clk_restore(reg_cache->reg_base, reg_cache->reg_sleep, ++ reg_cache->nr_reg_sleep); ++} ++ ++static struct syscore_ops ingenic_clk_syscore_ops = { ++ .suspend = ingenic_clk_suspend, ++ .resume = ingenic_clk_resume, ++}; ++ ++void __init ingenic_clk_sleep_init(void __iomem *reg_base, ++ struct ingenic_clk_reg_sleep *reg_sleep, ++ unsigned long nr_reg_sleep) ++{ ++ struct ingenic_clock_reg_cache *reg_cache; ++ ++ reg_cache = kzalloc(sizeof(struct ingenic_clock_reg_cache), ++ GFP_KERNEL); ++ if (!reg_cache) ++ panic("could not allocate register reg_cache.\n"); ++ ++ reg_cache->reg_sleep = reg_sleep; ++ reg_cache->nr_reg_sleep = nr_reg_sleep; ++ ++ ++ if (list_empty(&clock_reg_cache_list)) ++ register_syscore_ops(&ingenic_clk_syscore_ops); ++ ++ reg_cache->reg_base = reg_base; ++ list_add_tail(®_cache->node, &clock_reg_cache_list); ++} ++ ++#else ++static void ingenic_clk_sleep_init(void __iomem *reg_base, ++ unsigned long *rdump, ++ unsigned long nr_rdump) {} ++#endif ++ +diff --git a/module_drivers/drivers/clk/ingenic-v2/clk.h b/module_drivers/drivers/clk/ingenic-v2/clk.h +new file mode 100644 +index 000000000..c636430a8 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/clk.h +@@ -0,0 +1,594 @@ ++#ifndef __INGENIC_CLK_H ++#define __INGENIC_CLK_H ++ ++#include ++#include "clk-pll.h" ++#include "clk-div.h" ++#include "clk-bus.h" ++#include "power-gate.h" ++#include ++ ++struct clk; ++ ++/** ++ * struct ingenic_clk_provider: information about clock provider ++ * @reg_base: virtual address for the register base. ++ * @clk_data: holds clock related data like clk* and number of clocks. ++ * @lock: maintains exclusion between callbacks for a given clock-provider. ++ */ ++struct ingenic_clk_provider { ++ void __iomem *reg_base; ++ struct clk_onecell_data clk_data; ++ spinlock_t lock; ++}; ++ ++/** ++ * struct ingenic_clock_alias: information about mux clock ++ * @id: platform specific id of the clock. ++ * @dev_name: name of the device to which this clock belongs. ++ * @alias: optional clock alias name to be assigned to this clock. ++ */ ++struct ingenic_clock_alias { ++ unsigned int id; ++ const char *dev_name; ++ const char *alias; ++}; ++ ++#define ALIAS(_id, dname, a) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .alias = a, \ ++ } ++ ++#define MHZ (1000 * 1000) ++ ++/** ++ * struct ingenic_fixed_rate_clock: information about fixed-rate clock ++ * @id: platform specific id of the clock. ++ * @name: name of this fixed-rate clock. ++ * @parent_name: optional parent clock name. ++ * @flags: optional fixed-rate clock flags. ++ * @fixed-rate: fixed clock rate of this clock. ++ */ ++struct ingenic_fixed_rate_clock { ++ unsigned int id; ++ char *name; ++ const char *parent_name; ++ unsigned long flags; ++ unsigned long fixed_rate; ++}; ++ ++#define FRATE(_id, cname, pname, f, frate) \ ++ { \ ++ .id = _id, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = (f | CLK_IGNORE_UNUSED), \ ++ .fixed_rate = frate, \ ++ } ++ ++/* ++ * struct ingenic_fixed_factor_clock: information about fixed-factor clock ++ * @id: platform specific id of the clock. ++ * @name: name of this fixed-factor clock. ++ * @parent_name: parent clock name. ++ * @mult: fixed multiplication factor. ++ * @div: fixed division factor. ++ * @flags: optional fixed-factor clock flags. ++ */ ++struct ingenic_fixed_factor_clock { ++ unsigned int id; ++ char *name; ++ const char *parent_name; ++ unsigned long mult; ++ unsigned long div; ++ unsigned long flags; ++}; ++ ++#define FFACTOR(_id, cname, pname, m, d, f) \ ++ { \ ++ .id = _id, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .mult = m, \ ++ .div = d, \ ++ .flags = f, \ ++ } ++ ++/** ++ * struct ingenic_mux_clock: information about mux clock ++ * @id: platform specific id of the clock. ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this mux clock. ++ * @table: mux table in regs. ++ * @parent_names: array of pointer to parent clock names. ++ * @num_parents: number of parents listed in @parent_names. ++ * @flags: optional flags for basic clock. ++ * @offset: offset of the register for configuring the mux. ++ * @shift: starting bit location of the mux control bit-field in @reg. ++ * @width: width of the mux control bit-field in @reg. ++ * @mux_flags: flags for mux-type clock. ++ * @alias: optional clock alias name to be assigned to this clock. ++ */ ++struct ingenic_mux_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ unsigned int *table; ++ const char **parent_names; ++ u8 num_parents; ++ unsigned long flags; ++ unsigned long offset; ++ u8 shift; ++ u8 width; ++ u8 mux_flags; ++ const char *alias; ++}; ++ ++#define __MUX(_id, dname, cname, tb, pnames, o, s, w, f, mf, a) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .table = tb, \ ++ .parent_names = pnames, \ ++ .num_parents = ARRAY_SIZE(pnames), \ ++ .flags = f, \ ++ .offset = o, \ ++ .shift = s, \ ++ .width = w, \ ++ .mux_flags = mf, \ ++ .alias = a, \ ++ } ++ ++#define MUX(_id, cname, tb, pnames, o, s, w, f) \ ++ __MUX(_id, NULL, cname, tb, pnames, o, s, w, f, 0, cname) ++ ++#define MUX_A(_id, cname, tb, pnames, o, s, w, a) \ ++ __MUX(_id, NULL, cname, tb, pnames, o, s, w, 0, 0, a) ++ ++#define MUX_F(_id, cname, tb, pnames, o, s, w, f, mf) \ ++ __MUX(_id, NULL, cname, tb, pnames, o, s, w, f, mf, NULL) ++ ++#define MUX_FA(_id, cname, tb, pnames, o, s, w, f, mf, a) \ ++ __MUX(_id, NULL, cname, tb, pnames, o, s, w, f, mf, a) ++ ++/** ++ * @id: platform specific id of the clock. ++ * struct ingenic_div_clock: information about div clock ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this div clock. ++ * @parent_name: name of the parent clock. ++ * @flags: optional flags for basic clock. ++ * @offset: offset of the register for configuring the div. ++ * @shift: starting bit location of the div control bit-field in @reg. ++ * @busy_offset: offset of the register waiting for div stable. ++ * @busy_shift: bit-field of the busy bit in busy_reg, by finding the busy shift, we can also find the ce, and stop bit. ++ * @en_shift: points to some gateble clk in div cfg, ugly we gate clock in div clocks. ++ * @div_flags: divider flags. ++ * @alias: optional clock alias name to be assigned to this clock. ++ * @table: clk div table if possible. ++ */ ++struct ingenic_div_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ unsigned long flags; ++ unsigned long offset; ++ u8 shift; ++ u8 width; ++ ++ unsigned long busy_offset; ++ int busy_shift; ++ int en_shift; ++ int stop_shift; ++ ++ int div_flags; ++ const char *alias; ++ struct clk_div_table *table; ++}; ++ ++#define __DIV(_id, dname, cname, pname, o, s, w, bs, e, st, f, df, a, t) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = (f | CLK_IGNORE_UNUSED), \ ++ .offset = o, \ ++ .shift = s, \ ++ .width = w, \ ++ .div_flags = df, \ ++ .busy_shift = bs, \ ++ .en_shift = e, \ ++ .stop_shift = st, \ ++ .alias = a, \ ++ .table = t, \ ++ } ++ ++#define DIV(_id, cname, pname, o, w, df, t) \ ++ __DIV(_id, NULL, cname, pname, o, 0, w, 28, 29, 27, 0, df, cname, t) ++ ++#define DIV_EN(_id, cname, pname, o, s, w, bs, e) \ ++ __DIV(_id, NULL, cname, pname, o, s, w, bs, e, 0, 0, NULL, NULL) ++ ++/** ++ * @id: platform specific id of the clock. ++ * struct ingenic_bus_clock: information about div clock ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this div clock. ++ * @parent_name: name of the parent clock. ++ * @flags: optional flags for basic clock. ++ * @cfg_offset: offset of the register for configuring the div. ++ * @div_shift: starting bit location of the div control bit-field in @reg. ++ * @div_width: bit width of the div field. ++ * @busy_offset: offset of the register waiting for div stable. ++ * @busy_shift: bit-field of the busy bit in busy_reg, by finding the busy shift, we can also find the ce, and stop bit. ++ * @en_shift: points to some gateble clk in div cfg, ugly we gate clock in div clocks. ++ * @div_flags: flags for div-type clock, For example, DIV_NO_BUSY. ++ * @alias: optional clock alias name to be assigned to this clock. ++ * @table: clk div table if possible. ++ */ ++ ++ ++struct ingenic_bus_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ unsigned long flags; ++ unsigned long cfg_offset; ++ u8 div_shift1; ++ u8 div_width1; ++ u8 div_shift2; ++ u8 div_width2; ++ int ce_shift; ++ ++ int busy_offset; ++ int busy_shift; ++ ++ int div_flags; ++ int div_flags_2; ++ const char *alias; ++ struct clk_div_table *table; ++}; ++ ++#define __BUS_DIV(_id, dname, cname, pname, o, s1, w1, s2, w2, bo, bs, ce, f, df, df2, a, t) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = (f | CLK_IGNORE_UNUSED), \ ++ .cfg_offset = o, \ ++ .div_shift1 = s1, \ ++ .div_width1 = w1, \ ++ .div_shift2 = s2, \ ++ .div_width2 = w2, \ ++ .ce_shift = ce, \ ++ .busy_offset = bo, \ ++ .busy_shift = bs, \ ++ .div_flags = df, \ ++ .alias = a, \ ++ .table = t, \ ++ .div_flags_2 = df2, \ ++ } ++ ++#define BUS_DIV(_id, cname, pname, o, s1, w1, s2, w2, bo, bs, ce, df2) \ ++ __BUS_DIV(_id, NULL, cname, pname, o, s1, w1, s2, w2, bo, bs, ce, CLK_GET_RATE_NOCACHE, 0, df2, cname, NULL) ++ ++ ++ ++struct ingenic_fra_div_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ unsigned long flags; ++ ++ unsigned long offset; ++ u8 mshift; ++ u8 mwidth; ++ u8 nshift; ++ u8 nwidth; ++ ++ int div_flags; ++ const char *alias; ++}; ++ ++#define __FRA_DIV(_id, dname, cname, pname, f, o, ms, mw, ns, nw, df, a) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = f, \ ++ .offset = o, \ ++ .mshift = ms, \ ++ .mwidth = mw, \ ++ .nshift = ns, \ ++ .nwidth = nw, \ ++ .div_flags = df, \ ++ .alias = a, \ ++ } ++ ++#define FRA_DIV(_id, cname, pname, o, ms, mw, ns, nw) \ ++ __FRA_DIV(_id, NULL, cname, pname, 0, o, ms, mw, ns, nw, 0, cname) ++ ++/** ++ * struct ingenic_gate_clock: information about gate clock ++ * @id: platform specific id of the clock. ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this gate clock. ++ * @parent_name: name of the parent clock. ++ * @pwc_name: name of the power control clk under this clock gate. ++ * @flags: optional flags for basic clock. ++ * @offset: offset of the register for configuring the gate. ++ * @bit_idx: bit index of the gate control bit-field in @reg. ++ * @sram_offset: offset of the corresponding sram contrl reg. ++ * @sram_shift: shift for the sram control bit idx in sram_reg. ++ * @gate_flags: flags for gate-type clock. ++ * @alias: optional clock alias name to be assigned to this clock. ++ * @gate_flags: flags for gate clock. ++ * @alias: alias name for this clock. ++ */ ++struct ingenic_gate_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ ++ unsigned long flags; ++ unsigned long offset; ++ u8 bit_idx; ++ int sram_offset; ++ int sram_shift; ++ u8 gate_flags; ++ const char *alias; ++ ++}; ++ ++#define __GATE(_id, dname, cname, pname, o, b, f, so, sps, gf, a) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = f, \ ++ .offset = o, \ ++ .bit_idx = b, \ ++ .sram_offset = so, \ ++ .sram_shift = sps, \ ++ .gate_flags = gf, \ ++ .alias = a, \ ++ } ++ ++#define GATE(_id, cname, pname, o, b, f, gf) \ ++ __GATE(_id, NULL, cname, pname, o, b, f, -1, -1, gf, cname) ++ ++ ++#define GATE_SRAM(_id, cname, pname, o, b, f, gf, so, sps) \ ++ __GATE(_id, NULL, cname, pname, NULL, o, b, f, so, sps, gf, cname) ++ ++ ++/** ++ * struct ingenic_power_clock: information about power clock ++ * @id: platform specific id of the clock. ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this gate clock. ++ * @parent_name: name of the parent clock. ++ * @flags: optional flags for basic clock. ++ * @offset: offset of the register for configuring the gate. ++ * @ctrl_bit: bit index of the power control bit-field in @reg. ++ * @wait_bit: bit index of the power status bit-field in @reg. ++ * @delay_ms: wait for ms time stable @reg. ++ * @gate_flags: flags for gate-type clock. ++ * @alias: optional clock alias name to be assigned to this clock. ++ * @clk_flags: ingneic special flags. ++ */ ++struct ingenic_gate_power { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ ++ unsigned long flags; ++ unsigned long offset; ++ u8 ctrl_bit; ++ u8 wait_bit; ++ u8 gate_flags; ++ const char *alias; ++ unsigned long power_flags; ++}; ++ ++#define __POWER(_id, dname, cname, pname, f, o, cb, wb, gf, a, pf) \ ++ { \ ++ .id = _id, \ ++ .dev_name = dname, \ ++ .name = cname, \ ++ .parent_name = pname, \ ++ .flags = f, \ ++ .offset = o, \ ++ .ctrl_bit = cb, \ ++ .wait_bit = wb, \ ++ .gate_flags = gf, \ ++ .alias = a, \ ++ .power_flags = pf, \ ++ } ++ ++#define POWER(_id, cname, pname, o, cb, wb, f, gf, pf) \ ++ __POWER(_id, NULL, cname, pname, f, o, cb, wb, gf, cname, pf) ++ ++#define PNAME(x) static const char *x[] __initdata ++ ++#define REG_SLEEP(o, c, b, f) \ ++{ \ ++ .offset = o, \ ++ .ce = c, \ ++ .busy = b, \ ++ .flags = f, \ ++} ++ ++/** ++ * struct ingenic_clk_reg_sleep: register dump of clock controller registers. ++ * @offset: clock register offset from the controller base address. ++ * @value: the value to be register at offset. ++ */ ++struct ingenic_clk_reg_sleep { ++ u32 offset; ++ u32 value; ++ u32 ce; ++ u32 busy; ++ u32 flags; ++}; ++ ++ ++/** ++ * struct ingenic_pll_clock: information about pll clock ++ * @id: platform specific id of the clock. ++ * @dev_name: name of the device to which this clock belongs. ++ * @name: name of this pll clock. ++ * @parent_name: name of the parent clock. ++ * @flags: optional flags for basic clock. ++ * @con_offset: offset of the register for configuring the PLL. ++ * @lock_offset: offset of the register for locking the PLL. ++ * @type: Type of PLL to be registered. ++ * @alias: optional clock alias name to be assigned to this clock. ++ */ ++struct ingenic_pll_clock { ++ unsigned int id; ++ const char *dev_name; ++ const char *name; ++ const char *parent_name; ++ ++ unsigned long flags; ++ int con_offset; ++ int lock_offset; ++ const char *alias; ++ struct ingenic_pll_hwdesc *hwdesc; ++ struct ingenic_pll_rate_table *rate_table; ++}; ++ ++#define PLL(_id, _name, _parent_name, _hwdesc, _rtable) \ ++{ \ ++ .id = _id, \ ++ .dev_name = _name, \ ++ .name = _name, \ ++ .parent_name = _parent_name, \ ++ .hwdesc = _hwdesc, \ ++ .rate_table = _rtable, \ ++} ++ ++struct ingenic_clock_reg_cache { ++ struct list_head node; ++ void __iomem *reg_base; ++ struct ingenic_clk_reg_sleep *reg_sleep; ++ unsigned int nr_reg_sleep; ++}; ++ ++struct ingenic_cmu_info { ++ /* list of pll clocks and respective count */ ++ struct ingenic_pll_clock *pll_clks; ++ unsigned int nr_pll_clks; ++ /* list of mux clocks and respective count */ ++ struct ingenic_mux_clock *mux_clks; ++ unsigned int nr_mux_clks; ++ /* list of div clocks and respective count */ ++ struct ingenic_div_clock *div_clks; ++ unsigned int nr_div_clks; ++ /* list of gate clocks and respective count */ ++ struct ingenic_gate_clock *gate_clks; ++ unsigned int nr_gate_clks; ++ /* list of fixed clocks and respective count */ ++ struct ingenic_fixed_rate_clock *fixed_clks; ++ unsigned int nr_fixed_clks; ++ /* list of fixed factor clocks and respective count */ ++ struct ingenic_fixed_factor_clock *fixed_factor_clks; ++ unsigned int nr_fixed_factor_clks; ++ /* total number of clocks with IDs assigned*/ ++ unsigned int nr_clk_ids; ++ ++ /* list and number of clocks registers */ ++ unsigned long *clk_regs; ++ unsigned int nr_clk_regs; ++}; ++ ++struct ingenic_cpm_info { ++ struct ingenic_power_clock *pwc_clks; ++ unsigned int nr_pwc_clks; ++ ++}; ++ ++extern struct ingenic_clk_provider *__init ingenic_clk_init( ++ struct device_node *np, void __iomem *base, ++ unsigned long nr_clks); ++extern void __init ingenic_clk_of_add_provider(struct device_node *np, ++ struct ingenic_clk_provider *ctx); ++extern void __init ingenic_clk_of_register_fixed_ext( ++ struct ingenic_clk_provider *ctx, ++ struct ingenic_fixed_rate_clock *fixed_rate_clk, ++ unsigned int nr_fixed_rate_clk, ++ const struct of_device_id *clk_matches); ++ ++extern void ingenic_clk_add_lookup(struct ingenic_clk_provider *ctx, ++ struct clk *clk, unsigned int id); ++ ++extern void __init ingenic_clk_register_alias(struct ingenic_clk_provider *ctx, ++ const struct ingenic_clock_alias *list, ++ unsigned int nr_clk); ++extern void __init ingenic_clk_register_fixed_rate( ++ struct ingenic_clk_provider *ctx, ++ const struct ingenic_fixed_rate_clock *clk_list, ++ unsigned int nr_clk); ++extern void __init ingenic_clk_register_fixed_factor( ++ struct ingenic_clk_provider *ctx, ++ const struct ingenic_fixed_factor_clock *list, ++ unsigned int nr_clk); ++extern void __init ingenic_clk_register_mux(struct ingenic_clk_provider *ctx, ++ const struct ingenic_mux_clock *clk_list, ++ unsigned int nr_clk); ++extern void __init ingenic_clk_register_cgu_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_div_clock *clk_list, ++ unsigned int nr_clk); ++ ++extern void __init ingenic_clk_register_gate(struct ingenic_clk_provider *ctx, ++ const struct ingenic_gate_clock *list, ++ unsigned int nr_clk); ++ ++extern void __init ingenic_power_register_gate(struct ingenic_clk_provider *ctx, ++ const struct ingenic_gate_power *list, ++ unsigned int nr_clk); ++ ++extern void __init ingenic_clk_register_pll(struct ingenic_clk_provider *ctx, ++ const struct ingenic_pll_clock *pll_list, ++ unsigned int nr_clk, void __iomem *base); ++ ++extern struct ingenic_clk_provider __init *ingenic_cmu_register_one( ++ struct device_node *, ++ struct ingenic_cmu_info *); ++ ++extern unsigned long _get_rate(const char *clk_name); ++ ++extern void ingenic_clk_save(void __iomem *base, ++ struct ingenic_clk_reg_sleep *rd, ++ unsigned int num_regs); ++extern void ingenic_clk_restore(void __iomem *base, ++ struct ingenic_clk_reg_sleep *rd, ++ unsigned int num_regs); ++ ++extern void __init ingenic_clk_register_bus_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_bus_clock *list, ++ unsigned int nr_clk); ++ ++extern void __init ingenic_clk_register_fra_div(struct ingenic_clk_provider *ctx, ++ const struct ingenic_fra_div_clock *list, ++ unsigned int nr_clk); ++ ++extern void __init ingenic_clk_sleep_init(void __iomem *reg_base, ++ struct ingenic_clk_reg_sleep *rdump, ++ unsigned long nr_rdump); ++ ++void ingenic_clk_of_dump(struct ingenic_clk_provider *ctx); ++#endif /* __INGENIC_CLK_H */ +diff --git a/module_drivers/drivers/clk/ingenic-v2/power-gate.c b/module_drivers/drivers/clk/ingenic-v2/power-gate.c +new file mode 100644 +index 000000000..91bd19a2c +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/power-gate.c +@@ -0,0 +1,197 @@ ++/* ++ * Copyright (C) 2010-2011 Canonical Ltd ++ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Gated clock implementation ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "power-gate.h" ++ ++ ++struct power_gate { ++ struct clk_hw hw; ++ void __iomem *reg; ++ u8 ctrl_bit; ++ u8 wait_bit; ++ u8 flags; ++ unsigned long power_flags; ++ spinlock_t *lock; ++ ++}; ++ ++ ++/** ++ * DOC: basic gatable clock which can gate and ungate it's ouput ++ * ++ * Traits of this clock: ++ * prepare - clk_(un)prepare only ensures parent is (un)prepared ++ * enable - clk_enable and clk_disable are functional & control gating ++ * rate - inherits rate from parent. No clk_set_rate support ++ * parent - fixed parent. No clk_set_parent support ++ */ ++ ++#define to_power_gate(_hw) container_of(_hw, struct power_gate, hw) ++ ++/* ++ * It works on following logic: ++ * ++ * For enabling clock, enable = 1 ++ * set2dis = 1 -> clear bit -> set = 0 ++ * set2dis = 0 -> set bit -> set = 1 ++ * ++ * For disabling clock, enable = 0 ++ * set2dis = 1 -> set bit -> set = 1 ++ * set2dis = 0 -> clear bit -> set = 0 ++ * ++ * So, result is always: enable xor set2dis. ++ */ ++static int power_gate_is_enabled(struct clk_hw *hw) ++{ ++ u32 reg; ++ struct power_gate *gate = to_power_gate(hw); ++ ++ reg = readl(gate->reg); ++ ++ /* if a set bit disables this clk, flip it before masking */ ++ if (gate->flags & CLK_GATE_SET_TO_DISABLE) ++ reg ^= BIT(gate->wait_bit); ++ ++ reg &= BIT(gate->wait_bit); ++ ++ return reg ? 1 : 0; ++} ++ ++static void power_gate_endisable(struct clk_hw *hw, int enable) ++{ ++ struct power_gate *gate = to_power_gate(hw); ++ int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; ++ unsigned long flags; ++ u32 reg; ++ ++ set ^= enable; ++ ++ if (gate->lock) ++ spin_lock_irqsave(gate->lock, flags); ++ else ++ __acquire(gate->lock); ++ ++ reg = readl(gate->reg); ++ ++ if (set) ++ reg |= BIT(gate->ctrl_bit); ++ else ++ reg &= ~BIT(gate->ctrl_bit); ++ writel(reg, gate->reg); ++ ++ if (gate->lock) ++ spin_unlock_irqrestore(gate->lock, flags); ++ else ++ __release(gate->lock); ++} ++ ++static int power_gate_enable(struct clk_hw *hw) ++{ ++ struct power_gate *gate = to_power_gate(hw); ++ ++ power_gate_endisable(hw, 1); ++ ++ if (gate->power_flags & POWER_GATE_WAIT) { ++ while (!power_gate_is_enabled(hw)); ++ } ++ ++ return 0; ++} ++ ++static void power_gate_disable(struct clk_hw *hw) ++{ ++ struct power_gate *gate = to_power_gate(hw); ++ ++ power_gate_endisable(hw, 0); ++ ++ if (gate->power_flags & POWER_GATE_WAIT) { ++ while (power_gate_is_enabled(hw)); ++ } ++} ++ ++const struct clk_ops power_gate_ops = { ++ .enable = power_gate_enable, ++ .disable = power_gate_disable, ++ .is_enabled = power_gate_is_enabled, ++}; ++EXPORT_SYMBOL_GPL(power_gate_ops); ++ ++/** ++ * clk_register_gate - register a gate clock with the clock framework ++ * @dev: device that is registering this clock ++ * @name: name of this clock ++ * @parent_name: name of this clock's parent ++ * @flags: framework-specific flags for this clock ++ * @reg: register address to control gating of this clock ++ * @bit_idx: which bit in the register controls gating of this clock ++ * @clk_gate_flags: gate-specific flags for this clock ++ * @lock: shared register lock for this clock ++ */ ++struct clk *power_register_gate(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 ctrl_bit, u8 wait_bit, ++ u8 clk_gate_flags, unsigned long power_flags, spinlock_t *lock) ++{ ++ struct power_gate *gate; ++ struct clk *clk; ++ struct clk_init_data init; ++ ++ /* allocate the gate */ ++ gate = kzalloc(sizeof(*gate), GFP_KERNEL); ++ if (!gate) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ init.ops = &power_gate_ops; ++ init.flags = flags; ++ init.parent_names = (parent_name ? &parent_name: NULL); ++ init.num_parents = (parent_name ? 1 : 0); ++ ++ /* struct power_gate assignments */ ++ gate->reg = reg; ++ gate->ctrl_bit = ctrl_bit; ++ gate->wait_bit = wait_bit; ++ gate->flags = clk_gate_flags; ++ gate->power_flags = power_flags; ++ gate->lock = lock; ++ gate->hw.init = &init; ++ ++ clk = clk_register(dev, &gate->hw); ++ ++ if (IS_ERR(clk)) ++ kfree(gate); ++ ++ return clk; ++} ++EXPORT_SYMBOL_GPL(power_register_gate); ++ ++void power_unregister_gate(struct clk *clk) ++{ ++ struct power_gate *gate; ++ struct clk_hw *hw; ++ ++ hw = __clk_get_hw(clk); ++ if (!hw) ++ return; ++ ++ gate = to_power_gate(hw); ++ ++ clk_unregister(clk); ++ kfree(gate); ++} ++EXPORT_SYMBOL_GPL(power_unregister_gate); +diff --git a/module_drivers/drivers/clk/ingenic-v2/power-gate.h b/module_drivers/drivers/clk/ingenic-v2/power-gate.h +new file mode 100644 +index 000000000..bcf34c8b8 +--- /dev/null ++++ b/module_drivers/drivers/clk/ingenic-v2/power-gate.h +@@ -0,0 +1,14 @@ ++#ifndef __INGENIC_POWER_GATE_H ++#define __INGENIC_CLK_CGU_DIVIDER_H ++ ++ ++#define POWER_GATE_WAIT BIT(1) ++ ++struct clk *power_register_gate(struct device *dev, const char *name, ++ const char *parent_name, unsigned long flags, ++ void __iomem *reg, u8 ctrl_bit, u8 wait_bit, ++ u8 clk_gate_flags, unsigned long power_flags, spinlock_t *lock); ++ ++void power_unregister_gate(struct clk *clk); ++ ++#endif /* __SAMSUNG_CLK_PLL_H */ +diff --git a/module_drivers/drivers/clocksource/Kconfig b/module_drivers/drivers/clocksource/Kconfig +new file mode 100644 +index 000000000..18c97e867 +--- /dev/null ++++ b/module_drivers/drivers/clocksource/Kconfig +@@ -0,0 +1,16 @@ ++config CLKSRC_INGENIC_SYS_OST ++ bool "OST clocksource." ++ select CLKSRC_OF ++ depends on SOC_X1600 ++ help ++ sys ost for ingenic xburst base socs. ++ ++config CLKSRC_INGENIC_CORE_OST ++ bool "Core OST clocksource." ++ select CLKSRC_OF ++ depends on SOC_X2000 || SOC_X2000_V12 || SOC_M300 || SOC_X2100 || SOC_X2500 ++ help ++ core sys ost for ingenic xburst2 based SOCs. each cpu has ++ an ost and all cpu shares a global clocksource. ++ ++ +diff --git a/module_drivers/drivers/clocksource/Makefile b/module_drivers/drivers/clocksource/Makefile +new file mode 100644 +index 000000000..13c2dad38 +--- /dev/null ++++ b/module_drivers/drivers/clocksource/Makefile +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_CLKSRC_INGENIC_SYS_OST) += ingenic_sysost.o ++obj-$(CONFIG_CLKSRC_INGENIC_CORE_OST) += ingenic_core_ost.o +diff --git a/module_drivers/drivers/clocksource/ingenic_core_ost.c b/module_drivers/drivers/clocksource/ingenic_core_ost.c +new file mode 100644 +index 000000000..f30f5d482 +--- /dev/null ++++ b/module_drivers/drivers/clocksource/ingenic_core_ost.c +@@ -0,0 +1,569 @@ ++/* ++ * Setting up the xburst2 system ost, including: ++ * ----> core system ost; ++ * ----> global system ost. ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author: dongsheng.qiu, dongsheng.qiu@ingenic.com ++ * Modified by qipengzhen, aric.pzqi@ingenic.com ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ */ ++ ++/* #define DEBUG */ ++/* #define VERBOSE_DEBUG */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define OSTCCR 0x00 ++#define OSTER 0x04 ++#define OSTCR 0x08 ++#define OSTFR 0x0C ++#define OSTMR 0x10 ++#define OSTDFR 0x14 ++#define OSTCNT 0x18 ++ ++#define G_OSTCCR 0x00 ++#define G_OSTER 0x04 ++#define G_OSTCR 0x08 ++#define G_OSTCNTH 0x0C ++#define G_OSTCNTL 0x10 ++#define G_OSTCNTB 0x14 ++/*----------------------------------------------------------------------------- ++ * -- global ost, clocksource, the whole system shares only one. ++ * -- core ost, each cpu owns one. ++ * ++ * ----------------------------------------------- ++ * | | | | ++ * | -------- -------- -------- ++ * | | cpu0 | | cpu1 | | cpuN | ++ * | -------- -------- -------- ++ * | ^ ^ ^ ++ * V | | | ++ * ------------ ------------ ----------- ----------- ++ * | global OST | | core ost0 | | core ost1 | ... | core ostN | ++ * ------------ ----------- ----------- ----------- ++ * ++ *-----------------------------------------------------------------------------*/ ++ ++struct cpu_ost_map { ++ unsigned int cpu_num; ++ unsigned int dev_base; ++}; ++static struct cpu_ost_map cpu_ost_map[NR_CPUS]; ++ ++struct core_timerevent { ++ struct clock_event_device clkevt; ++ struct irqaction evt_action; ++ void __iomem *iobase; ++ unsigned int rate; ++ raw_spinlock_t lock; ++ unsigned int prev_set; ++}; ++ ++static struct core_timerevent timerevent_buf[NR_CPUS]; ++#define CLK_DIV 1 ++#define CSRDIV(x) ({int n = 0;int d = x; while(d){ d >>= 2;n++;};(n-1);}) ++ ++#define ost_readl(reg) readl(reg) ++#define ost_writel(value,reg) writel(value, reg) ++ ++struct tmr_src { ++ struct clocksource cs; ++ struct core_global_ost_resource *resource; ++ struct clk *clk_gate; ++ void __iomem *iobase; ++ raw_spinlock_t lock; ++}; ++#ifdef CONFIG_SMP ++#define ost_lock(lock,flags) raw_spin_lock_irqsave(&(lock),flags) ++#define ost_unlock(lock,flags) raw_spin_unlock_irqrestore(&(lock),flags) ++#else ++#define ost_lock(lock,flags) (flags = 0) ++#define ost_unlock(lock,flags) (flags = 0) ++#endif ++ ++struct core_ost_chip{ ++ struct tmr_src *tmrsrc; ++ ++ struct core_timerevent* __percpu *percpu_timerevent; ++ struct clk *core_gate; ++ void __iomem *iobase; ++ unsigned int rate; ++ int irq; ++} g_core_ost; ++ ++static raw_spinlock_t clocksource_lock; ++ ++static u64 core_clocksource_get_cycles(struct clocksource *cs) ++{ ++ union clycle_type { ++ u64 cycle64; ++ unsigned int cycle32[2]; ++ } cycle; ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ unsigned long flags; ++ raw_spin_lock_irqsave(&clocksource_lock,flags); ++ void __iomem *iobase = tmr->iobase; ++ ++ do { ++ cycle.cycle32[1] = ost_readl(iobase + G_OSTCNTH); ++ cycle.cycle32[0] = ost_readl(iobase + G_OSTCNTL); ++ } while(cycle.cycle32[1] != ost_readl(iobase + G_OSTCNTH)); ++ raw_spin_unlock_irqrestore(&clocksource_lock,flags); ++ ++ return cycle.cycle64; ++} ++ ++static int tmr_src_enable(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ void __iomem *iobase = tmr->iobase; ++ unsigned long flags; ++ ost_lock(tmr->lock,flags); ++ ost_writel(1,iobase + G_OSTER); ++ ost_unlock(tmr->lock,flags); ++ return 0; ++} ++ ++static void tmr_src_disable(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ void __iomem *iobase = tmr->iobase; ++ unsigned long flags; ++ ost_lock(tmr->lock,flags); ++ ost_writel(0,iobase + G_OSTER); ++ ost_unlock(tmr->lock,flags); ++} ++static void tmr_src_suspend(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ struct core_ost_chip *core_ost = &g_core_ost; ++ ++ if(core_ost->core_gate) ++ clk_disable_unprepare(core_ost->core_gate); ++ if(tmr->clk_gate) ++ clk_disable_unprepare(tmr->clk_gate); ++} ++static void tmr_src_resume(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ struct core_ost_chip *core_ost = &g_core_ost; ++ ++ if(tmr->clk_gate) ++ clk_prepare_enable(tmr->clk_gate); ++ if(core_ost->core_gate) ++ clk_prepare_enable(core_ost->core_gate); ++ ++} ++static struct tmr_src g_tmr_src = { ++ .cs = { ++ .name = "jz_clocksource", ++ .rating = 400, ++ .read = core_clocksource_get_cycles, ++ .mask = 0x7FFFFFFFFFFFFFFFULL, ++ .shift = 10, ++ .flags = CLOCK_SOURCE_WATCHDOG | CLOCK_SOURCE_IS_CONTINUOUS, ++ .enable = tmr_src_enable, ++ .disable = tmr_src_disable, ++ .suspend = tmr_src_suspend, ++ .resume = tmr_src_resume, ++ } ++}; ++ ++static unsigned long long sched_clock(void) ++{ ++ struct tmr_src *tmr = &g_tmr_src; ++ if(!tmr->iobase) ++ return 0LL; ++ if(!ost_readl(tmr->iobase + G_OSTER)) ++ return 0LL; ++ return ((u64)core_clocksource_get_cycles(&tmr->cs)); // * tmr_src.cs.mult) >> tmr_src.cs.shift; ++} ++ ++void __init core_clocksource_init(struct core_ost_chip *core_ost, struct tmr_src *tmr) ++{ ++ unsigned long hz; ++ void __iomem *iobase; ++ ++ core_ost->tmrsrc = tmr; ++ tmr->cs.mult = clocksource_hz2mult(core_ost->rate, tmr->cs.shift); ++ iobase = tmr->iobase; ++ ++ if(tmr->clk_gate) ++ clk_prepare_enable(tmr->clk_gate); ++ ++ hz = core_ost->rate; ++ ++ raw_spin_lock_init(&clocksource_lock); ++ ++ raw_spin_lock_init(&tmr->lock); ++ ost_writel(0,iobase + G_OSTER); ++ ost_writel(CSRDIV(CLK_DIV),iobase + OSTCCR); ++ ost_writel(1,iobase + G_OSTCR); ++ ++ clocksource_register_hz(&tmr->cs, hz); ++ sched_clock_register(sched_clock, 64, hz); ++} ++ ++static int core_timerevent_set_next_event(unsigned long evt, ++ struct clock_event_device *clk_evt_dev) ++{ ++ struct core_timerevent *evt_dev = container_of(clk_evt_dev, struct core_timerevent, clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned long flags; ++ ost_lock(evt_dev->lock,flags); ++ if(evt <= 1) { ++ WARN_ON(1); ++ evt = 2; ++ } ++ ost_writel(0,iobase + OSTER); ++ if(!ost_readl(iobase + OSTFR)) ++ { ++ ost_writel(evt,iobase + OSTDFR); ++ ost_writel(1,iobase + OSTCR); ++ ost_writel(1,iobase + OSTER); ++ }else{ ++ //pr_err("OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO evt = %ld\n",evt); ++ evt_dev->prev_set = evt; ++ } ++ ++ ost_unlock(evt_dev->lock,flags); ++ return 0; ++} ++extern void sysrq_handle_showallcpus(int key); ++extern void sysrq_handle_showlocks(int key); ++static int time_count[4] = {100,100,100,100}; ++static irqreturn_t core_timerevent_interrupt(int irq, void *dev_id) ++{ ++ struct core_timerevent *evt_dev = *(struct core_timerevent **)dev_id; ++ void __iomem *iobase = evt_dev->iobase; ++ int cpu = smp_processor_id(); ++ unsigned long flags; ++ if (ost_readl(iobase + OSTFR)){ ++#if 0 ++ if(time_count[cpu] >= 1000) { ++#if 0 ++ printk("\n\n---timer interrupt , 100 count, on cpu: %d %x %x\n", cpu,read_c0_status(),read_c0_cause()); ++ printk("intc src0:%x: %x\n", 0xb2300000 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300000 + cpu * 0x1000 )); ++ printk("intc msk0:%x: %x\n", 0xb2300004 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300004 + cpu * 0x1000 )); ++ printk("intc pnd0:%x: %x\n", 0xb2300010 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300010 + cpu * 0x1000 )); ++ printk("intc src1:%x: %x\n", 0xb2300020 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300020 + cpu * 0x1000 )); ++ printk("intc msk1:%x: %x\n", 0xb2300024 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300024 + cpu * 0x1000 )); ++ printk("intc pnd1:%x: %x\n", 0xb2300030 + cpu * 0x1000, *(volatile unsigned int *)(0xb2300030 + cpu * 0x1000 )); ++ printk("ccu msk: %x: %x\n", 0xb2200120, *(volatile unsigned int *)(0xb2200120)); ++ printk("ccu pnd: %x: %x\n", 0xb2200100, *(volatile unsigned int *)(0xb2200100)); ++ ++ printk("uart0 ier: %x\n", *(volatile unsigned int *)0xb0030004); ++ printk("uart0 isr: %x\n", *(volatile unsigned int *)0xb0030014); ++ ++ printk("\n\n"); ++#endif ++ time_count[cpu] = 0; ++ } ++ time_count[cpu]++; ++#endif ++ ost_lock(evt_dev->lock,flags); ++ ost_writel(0,iobase + OSTFR); ++ ++ if( clockevent_state_oneshot(&evt_dev->clkevt) || ++ clockevent_state_oneshot_stopped(&evt_dev->clkevt)) { ++ if(evt_dev->prev_set == 0){ ++ ost_writel(0,iobase + OSTER); ++ }else{ ++ ost_writel(evt_dev->prev_set,iobase + OSTDFR); ++ ost_writel(1,iobase + OSTCR); ++ ost_writel(1,iobase + OSTER); ++ evt_dev->prev_set = 0; ++ } ++ ++ } ++ ++ ost_unlock(evt_dev->lock,flags); ++ evt_dev->clkevt.event_handler(&evt_dev->clkevt); ++ }else{ ++ pr_err("\nERROR: cpu: %d c0_status:%x c0_cause:%x\n", cpu,read_c0_status(),read_c0_cause()); ++ pr_err("CPU[%d]: ost couldn't find ostfr.\n",cpu); ++ } ++ return IRQ_HANDLED; ++} ++ ++static int set_state_periodic(struct clock_event_device *clkevt) ++{ ++ struct core_timerevent *evt_dev = container_of(clkevt,struct core_timerevent,clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned int latch = (evt_dev->rate + (HZ >> 1)) / HZ; ++ unsigned long flags; ++ ++ ost_lock(evt_dev->lock,flags); ++ ++ ost_writel(latch,iobase + OSTDFR); ++ ost_writel(1,iobase + OSTER); ++ ost_unlock(evt_dev->lock,flags); ++ return 0; ++} ++#if 0 ++static int set_state_oneshot(struct clock_event_device *clkevt) ++{ ++ struct core_timerevent *evt_dev = container_of(clkevt,struct core_timerevent,clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned int latch = (evt_dev->rate + (HZ >> 1)) / HZ; ++ unsigned long flags; ++ ++ ost_lock(evt_dev->lock,flags); ++ ost_writel(latch,iobase + OSTDFR); ++ ost_writel(1,iobase + OSTER); ++ ost_unlock(evt_dev->lock,flags); ++ return 0; ++ ++} ++static int set_state_oneshot_stopped(struct clock_event_device *clkevt) ++{ ++ struct core_timerevent *evt_dev = container_of(clkevt,struct core_timerevent,clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned long flags; ++ ++ ost_lock(evt_dev->lock,flags); ++ ost_writel(1,iobase + OSTER); ++ ost_unlock(evt_dev->lock,flags); ++ return 0; ++} ++#endif ++ ++static int set_state_shutdown(struct clock_event_device *clkevt) ++{ ++ struct core_timerevent *evt_dev = container_of(clkevt,struct core_timerevent,clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned long flags; ++ ++ ost_lock(evt_dev->lock,flags); ++ ost_writel(0,iobase + OSTER); ++ ost_unlock(evt_dev->lock,flags); ++ return 0; ++} ++#if 0 ++static int tick_resume(struct clock_event_device *clkevt) ++{ ++ struct core_timerevent *evt_dev = container_of(clkevt,struct core_timerevent,clkevt); ++ void __iomem *iobase = evt_dev->iobase; ++ unsigned int latch = (evt_dev->rate + (HZ >> 1)) / HZ; ++ unsigned long flags; ++ unsigned int val; ++ ++ ost_lock(evt_dev->lock,flags); ++ val = ost_readl(iobase + OSTCNT); ++ if(val >= latch) ++ ost_writel(latch,iobase + OSTDFR); ++ ost_writel(1,iobase + OSTER); ++ ++ ost_unlock(evt_dev->lock,flags); ++ ++ return 0; ++} ++#endif ++ ++static void percpu_timerevent_init(struct core_ost_chip *core_ost, int cpu_num) ++{ ++ int i; ++ void __iomem *iobase; ++ unsigned int base = 0; ++ struct core_timerevent *timerevent = NULL; ++ struct clock_event_device *cd = NULL; ++ pr_info("percpu cpu_num:%d timerevent init\n",cpu_num); ++ for(i = 0;i < NR_CPUS;i++) ++ { ++ if(cpu_ost_map[i].cpu_num == cpu_num) { ++ base = cpu_ost_map[i].dev_base; ++ timerevent = &timerevent_buf[i]; ++ break; ++ } ++ } ++ ++ if(base == 0){ ++ pr_err("Error: CPU[%d] don't finded ost base address\n",cpu_num); ++ return; ++ } ++ ++ iobase = (void *)base; ++ if(timerevent->iobase == NULL) ++ { ++ timerevent->iobase = iobase; ++ timerevent->rate = core_ost->rate; ++ ++ raw_spin_lock_init(&timerevent->lock); ++ cd = &timerevent->clkevt; ++ memset(cd,0,sizeof(struct clock_event_device)); ++ cd->name = "clockenvent"; ++ cd->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; ++ cd->shift = 10; ++ cd->rating = 400; ++ cd->set_state_periodic = set_state_periodic; ++ cd->set_state_oneshot = set_state_shutdown; ++ cd->set_state_oneshot_stopped = set_state_shutdown; ++ cd->set_state_shutdown = set_state_shutdown; ++ cd->tick_resume = set_state_shutdown; ++ cd->set_next_event = core_timerevent_set_next_event; ++ cd->irq = core_ost->irq; ++ cd->cpumask = cpumask_of(smp_processor_id()); ++ }else { ++ iobase = timerevent->iobase; ++ cd = &timerevent->clkevt; ++ } ++ ost_writel(0,iobase + OSTER); //disable ost ++ ost_writel(CSRDIV(CLK_DIV),iobase + OSTCCR); ++ ost_writel(1,iobase + OSTCR); ++ ost_writel(0,iobase + OSTMR); ++ ++ clockevents_config_and_register(cd, timerevent->rate, 0xf, 0xffffffff); ++ ++ *this_cpu_ptr(core_ost->percpu_timerevent) = timerevent; ++ ++ enable_percpu_irq(core_ost->irq, IRQ_TYPE_NONE); ++ printk("clockevents_config_and_register success.\n"); ++} ++void ingenic_percpu_timerevent_init(unsigned int cpu_num) ++{ ++ percpu_timerevent_init(&g_core_ost, cpu_num); ++} ++EXPORT_SYMBOL_GPL(ingenic_percpu_timerevent_init); ++ ++ ++static void percpu_timerevent_deinit(struct core_ost_chip * core_ost) ++{ ++ struct core_timerevent *timerevent = *this_cpu_ptr(core_ost->percpu_timerevent); ++ disable_percpu_irq(core_ost->irq); ++ ost_writel(0,timerevent->iobase + OSTER); //disable ost ++ ost_writel(1,timerevent->iobase + OSTMR); ++} ++void ingenic_percpu_timerevent_deinit(void) ++{ ++ percpu_timerevent_deinit(&g_core_ost); ++} ++EXPORT_SYMBOL_GPL(ingenic_percpu_timerevent_deinit); ++ ++ ++static void __init core_ost_setup(struct core_ost_chip *core_ost, unsigned long ext_rate) ++{ ++ int ret; ++ ++ if(core_ost->core_gate) { ++ clk_prepare_enable(core_ost->core_gate); ++ } ++ ++ core_ost->rate = (ext_rate / CLK_DIV); /* TODO: should be clk_get_rate(extclk) / CLK_DIV in real chip */ ++ ++ core_ost->percpu_timerevent = alloc_percpu(struct core_timerevent *); ++ if(!core_ost->percpu_timerevent) { ++ pr_err("ost percpu alloc fail!\n"); ++ return; ++ } ++ ret = request_percpu_irq(core_ost->irq, core_timerevent_interrupt,"core_timerevent",core_ost->percpu_timerevent); ++ if(ret < 0) { ++ pr_err("dddd timer request ost error %d \n",ret); ++ } ++ memset(timerevent_buf,0,sizeof(timerevent_buf)); ++ ++} ++ ++static void __init ingenic_ost_init(struct device_node *np) ++{ ++ struct core_ost_chip *core_ost = &g_core_ost; ++ struct tmr_src *tmr = &g_tmr_src ; ++ struct clk *ext_clk = NULL; ++ unsigned long ext_rate; ++ void __iomem *g_iobase = NULL; ++ void __iomem *core_iobase = NULL; ++ int irq = -1; ++ struct property *prop; ++ const unsigned int *vp; ++ unsigned int pv; ++ int index = 0; ++ ++ g_iobase = of_io_request_and_map(np, 0, "ost"); ++ if(g_iobase == NULL) { ++ pr_err("Failed to map global clocksource iobase!\n"); ++ return; ++ } ++ core_iobase = of_io_request_and_map(np, 1, "core-ost"); ++ if(core_iobase == NULL) { ++ pr_err("Failed to map core clockevent iobase!\n"); ++ return; ++ } ++ ++ irq = of_irq_get_byname(np, "sys_ost"); ++ if (irq < 0) { ++ pr_err("ftm: unable to get IRQ from DT, %d\n", irq); ++ return; ++ } ++ ++ of_property_for_each_u32(np, "cpu-ost-map", prop, vp, pv) { ++ if(index % 2) { ++ cpu_ost_map[index/2].dev_base = (unsigned int)core_iobase + pv; ++ } else { ++ cpu_ost_map[index/2].cpu_num = pv; ++ } ++ index ++; ++ if(index > NR_CPUS * 2 - 1) { ++ printk("parse cpu-ost-iomap, ost number define in dt is too large!\n"); ++ break; ++ } ++ } ++ ++ ext_clk = clk_get(NULL, "ext"); ++ if (IS_ERR_OR_NULL(ext_clk)) { ++ pr_err("Warnning ... Ingenic Ost: Failed to get ext clk, Using default clk rate(24MHz),\n"); ++ ext_rate = 24000000; ++ } else { ++ ext_rate = clk_get_rate(ext_clk); ++ clk_put(ext_clk); ++ } ++ ++ tmr->iobase = g_iobase; ++ core_ost->iobase = core_iobase; ++ core_ost->irq = irq; ++ ++ tmr->clk_gate = clk_get(NULL, "gate_ost"); ++ if(IS_ERR_OR_NULL(tmr->clk_gate)) { ++ pr_err("Failed to get global ost clk gate!\n"); ++ tmr->clk_gate = NULL; ++ } ++ ++ core_ost->core_gate = clk_get(NULL, "gate_ost"); ++ if(IS_ERR_OR_NULL(core_ost->core_gate)) { ++ pr_err("Failed to get core ost clk gate!\n"); ++ core_ost->core_gate = NULL; ++ } ++ ++ core_ost_setup(core_ost, ext_rate); ++ percpu_timerevent_init(core_ost, 0); ++ core_clocksource_init(core_ost, tmr); ++} ++ ++TIMER_OF_DECLARE(ingenic_ost_init, "ingenic,core-ost", ingenic_ost_init); +diff --git a/module_drivers/drivers/clocksource/ingenic_sysost.c b/module_drivers/drivers/clocksource/ingenic_sysost.c +new file mode 100644 +index 000000000..1994135f3 +--- /dev/null ++++ b/module_drivers/drivers/clocksource/ingenic_sysost.c +@@ -0,0 +1,316 @@ ++/* ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * Author: xyfu (kernel.3.10.14) ++ * Modified: cli ++ * ++ * Operating System Timer interface for Ingenic's SOC, such as X1000, ++ * and so on. (kernel.4.4) ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++/* #define DEBUG */ ++/* #define VERBOSE_DEBUG */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CLKSOURCE_DIV (16) ++#define CLKEVENT_DIV (16) ++ ++/*----------------------------------------------------------------------------- ++ * C L O C K S O U R C E ++ *-----------------------------------------------------------------------------*/ ++struct tmr_src { ++ struct clocksource cs; ++ struct clk *clk_gate; ++ void __iomem *iobase; ++}; ++ ++/* clocksource cycle base type */ ++typedef u64 cycle_t; ++ ++static cycle_t ingenic_read_cycles(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs, struct tmr_src, cs); ++ union clycle_type ++ { ++ cycle_t cycle64; ++ unsigned int cycle32[2]; ++ } cycle; ++ ++ cycle.cycle32[0] = ost_readl(tmr->iobase + OST_T2CNTL); ++ cycle.cycle32[1] = ost_readl(tmr->iobase + OST_TCNT2HBUF); ++ ++ return cycle.cycle64; ++} ++ ++static int tmr_src_enable(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ ++ ost_writel(tmr->iobase + OST_TESR, TESR_OSTEN2); ++ return 0; ++} ++static void tmr_src_disable(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs,struct tmr_src,cs); ++ ++ ost_writel(tmr->iobase + OST_TCR, TCR_OSTCLR2); ++ ost_writel(tmr->iobase + OST_TECR, TESR_OSTEN2); ++} ++static void tmr_src_suspend(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs, struct tmr_src, cs); ++ ++ ost_writel(tmr->iobase + OST_TFR , ~TFR_OSTM); ++ if (tmr->clk_gate) { ++ clk_disable_unprepare(tmr->clk_gate); ++ ++ } ++} ++static void tmr_src_resume(struct clocksource *cs) ++{ ++ struct tmr_src *tmr = container_of(cs, struct tmr_src, cs); ++ if (tmr->clk_gate) ++ clk_prepare_enable(tmr->clk_gate); ++} ++ ++static struct tmr_src tmr_src = { ++ .cs = { ++ .name = "ingenic_clocksource", ++ .rating = 400, ++ .read = ingenic_read_cycles, ++ .mask = CLOCKSOURCE_MASK(64), ++ .flags = CLOCK_SOURCE_WATCHDOG | CLOCK_SOURCE_IS_CONTINUOUS, ++ .enable = tmr_src_enable, ++ .disable = tmr_src_disable, ++ .suspend = tmr_src_suspend, ++ .resume = tmr_src_resume, ++ } ++}; ++ ++static u64 notrace ingenic_read_sched_clock(void) ++{ ++ union clycle_type { ++ uint64_t cycle64; ++ uint32_t cycle32[2]; ++ } cycle; ++ cycle.cycle32[0] = ost_readl(tmr_src.iobase + OST_T2CNTL); ++ cycle.cycle32[1] = ost_readl(tmr_src.iobase + OST_TCNT2HBUF); ++ ++ return cycle.cycle64; ++} ++ ++static void __init ingenic_clocksource_init(struct tmr_src *tmr, unsigned long ext_rate) ++{ ++ unsigned long hz = ext_rate / CLKSOURCE_DIV; ++ unsigned int val; ++ ++ tmr->clk_gate = clk_get(NULL, "gate_ost"); ++ if (IS_ERR_OR_NULL(tmr->clk_gate)) { ++ pr_err("ERROR: Failed to get clk, Please check clk driver.\n"); ++ pr_err("%s, incase of Debug at the very beginning, we ignore the clk_gate. \n \ ++ You must implemented clk driver immediately\n\n\t\n", __func__); ++ } else { ++ clk_prepare_enable(tmr->clk_gate); ++ } ++ ++ val = ost_readl(tmr->iobase + OST_TCCR); ++ if (ost_readl(tmr->iobase + OST_TER) & TESR_OSTEN2) { ++ u32 div = 0; ++ /* ++ * get previous boot time ++ */ ++ switch ((val & TCCRDIV_MSK2) >> TCCRDIV_SFT2) { ++ case 0: div = 1; break; ++ case 1: div = 4; break; ++ case 2: div = 16; break; ++ } ++ if (likely(div)) { ++ u64 cycles = ingenic_read_sched_clock(); ++ u32 pre_hz = ext_rate / div; ++ cycles = cycles * USEC_PER_SEC; ++ do_div(cycles, pre_hz); ++ pr_info("Previous Boot Time is %u us\n", (u32)cycles); ++ } ++ ost_writel(tmr->iobase + OST_TECR, TESR_OSTEN2); ++ } ++ val &= ~TCCRDIV_MSK2; ++ val |= TCCRDIV2(CLKSOURCE_DIV); ++ ost_writel(tmr->iobase + OST_TCCR, val); ++ ost_writel(tmr->iobase + OST_TCR, TCR_OSTCLR2); ++ ost_writel(tmr->iobase + OST_TESR, TESR_OSTEN2); ++ ++ clocksource_register_hz(&tmr->cs, hz); ++ sched_clock_register(ingenic_read_sched_clock, 64, hz); ++} ++ ++/*----------------------------------------------------------------------------- ++ * C L O C K E V E N T ++ *-----------------------------------------------------------------------------*/ ++struct ingenic_timerevent { ++ struct clock_event_device clkevt; ++ void __iomem *iobase; ++ unsigned int periodic_ticks; ++ struct clk *clk_gate; ++ unsigned int rate; ++ int irq; ++ struct irqaction evt_action; ++} ingenic_clockevent; ++ ++ ++static int ingenic_set_state_periodic(struct clock_event_device *cd) ++{ ++ struct ingenic_timerevent *evt_dev = container_of(cd, ++ struct ingenic_timerevent, clkevt); ++ ++ ost_writel(evt_dev->iobase + OST_TMR , TMR_OSTM); ++ ost_writel(evt_dev->iobase + OST_TECR , TESR_OSTEN1); ++ ost_writel(evt_dev->iobase + OST_TFR , ~TFR_OSTM); ++ ost_writel(evt_dev->iobase + OST_T1DFR, evt_dev->periodic_ticks); ++ ost_writel(evt_dev->iobase + OST_TCR , TCR_OSTCLR1); ++ ost_writel(evt_dev->iobase + OST_TESR , TESR_OSTEN1); ++ ost_writel(evt_dev->iobase + OST_TMR , ~TMR_OSTM); ++ return 0; ++} ++ ++static int ingenic_set_state_shutdown(struct clock_event_device *cd) ++{ ++ struct ingenic_timerevent *evt_dev = container_of(cd, ++ struct ingenic_timerevent, clkevt); ++ ost_writel(evt_dev->iobase + OST_TECR , TESR_OSTEN1); ++ return 0; ++ ++} ++static int ingenic_set_next_event(unsigned long evt, struct clock_event_device *cd) ++{ ++ struct ingenic_timerevent *evt_dev = container_of(cd, ++ struct ingenic_timerevent, clkevt); ++ ++ ost_writel(evt_dev->iobase + OST_TMR , TMR_OSTM); ++ ost_writel(evt_dev->iobase + OST_TECR , TESR_OSTEN1); ++ ost_writel(evt_dev->iobase + OST_TFR , ~TFR_OSTM); ++ ost_writel(evt_dev->iobase + OST_T1DFR, evt); ++ ost_writel(evt_dev->iobase + OST_TCR , TCR_OSTCLR1); ++ ost_writel(evt_dev->iobase + OST_TESR , TESR_OSTEN1); ++ ost_writel(evt_dev->iobase + OST_TMR , ~TMR_OSTM); ++ return 0; ++} ++ ++static irqreturn_t ingenic_timer_interrupt(int irq, void *dev_id) ++{ ++ struct ingenic_timerevent *evt_dev = dev_id; ++ struct clock_event_device *cd = &evt_dev->clkevt; ++ ++ ost_writel(evt_dev->iobase + OST_TFR, ~TFR_OSTM); ++ ++ if (clockevent_state_oneshot(cd)) ++ ost_writel(evt_dev->iobase + OST_TECR , TESR_OSTEN1); ++ ++ evt_dev->clkevt.event_handler(&evt_dev->clkevt); ++ return IRQ_HANDLED; ++} ++ ++static void __init ingenic_clockevent_init(struct ingenic_timerevent *evt_dev, unsigned long ext_rate) ++{ ++ struct clock_event_device *cd = &evt_dev->clkevt; ++ unsigned int val; ++ int ret; ++ ++ ost_writel(evt_dev->iobase + OST_TMR, TMR_OSTM); ++ ost_writel(evt_dev->iobase + OST_TECR, TESR_OSTEN1); ++ ost_writel(evt_dev->iobase + OST_TFR, ~TFR_OSTM); ++ val = ost_readl(evt_dev->iobase + OST_TCCR); ++ val &= ~TCCRDIV_MSK1; ++ val |= TCCRDIV1(CLKEVENT_DIV); ++ ost_writel(evt_dev->iobase + OST_TCCR, val); ++ ost_writel(evt_dev->iobase + OST_TCR, TCR_OSTCLR1); ++ ++ evt_dev->evt_action.handler = ingenic_timer_interrupt; ++ evt_dev->evt_action.flags = IRQF_TIMER; ++ evt_dev->evt_action.name = "ingenic-timerost"; ++ evt_dev->evt_action.dev_id = (void*)evt_dev; ++ evt_dev->rate = ext_rate / CLKEVENT_DIV; ++ evt_dev->periodic_ticks = ((evt_dev->rate + (HZ >> 1)) / HZ) - 1; /* - 1 for scroll back */ ++ ++ memset(cd, 0, sizeof(struct clock_event_device)); ++ ret = request_irq(evt_dev->irq, evt_dev->evt_action.handler, evt_dev->evt_action.flags, evt_dev->evt_action.name, (void *)cd); ++ if(ret < 0) { ++ pr_err("request system ost error %d \n",ret); ++ } ++ ++ cd->name = "ingenic-clockenvent"; ++ cd->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; ++ cd->rating = 400; ++ cd->set_state_periodic = ingenic_set_state_periodic; ++ cd->set_state_oneshot = ingenic_set_state_shutdown; ++ cd->set_state_shutdown = ingenic_set_state_shutdown; ++ cd->set_next_event = ingenic_set_next_event; ++ cd->irq = evt_dev->irq; ++ cd->cpumask = cpumask_of(0); ++ ++ clockevents_config_and_register(cd, evt_dev->rate, 4, 0xffffffff); ++} ++ ++static int __init ingenic_ost_init(struct device_node *np) ++{ ++ struct ingenic_timerevent *evt = &ingenic_clockevent; ++ struct tmr_src *tmr = &tmr_src ; ++ struct clk *ext_clk = NULL; ++ unsigned long ext_rate; ++ void __iomem *iobase = NULL; ++ int irq_ost = -1; ++ ++ iobase = of_io_request_and_map(np, 0, "ost"); ++ if(iobase == NULL) { ++ pr_err("Failed to map clocksource iobase!\n"); ++ return -EINVAL; ++ } ++ ++ irq_ost = of_irq_get_byname(np, "sys_ost"); ++ if (irq_ost < 0) { ++ pr_err("ftm: unable to get IRQ from DT, %d\n", irq_ost); ++ return -EINVAL; ++ } ++ ++ ext_clk = clk_get(NULL, "ext"); ++ if (IS_ERR_OR_NULL(ext_clk)) { ++ pr_warn("Warning Ingenic Ost: Can not get extern clock, Please check clk driver !!\n\n\t\n"); ++ ext_rate = 24000000; ++ } else { ++ ++ ext_rate = clk_get_rate(ext_clk); ++ clk_put(ext_clk); ++ } ++ ++ tmr->iobase = iobase; ++ evt->iobase = iobase; ++ evt->irq = irq_ost; ++ ++ ingenic_clocksource_init(tmr, ext_rate); ++ ingenic_clockevent_init(evt, ext_rate); ++ ++ return 0; ++} ++ ++TIMER_OF_DECLARE(x1000_ost_init, "ingenic,x1000-ost", ingenic_ost_init); ++TIMER_OF_DECLARE(x1800_ost_init, "ingenic,x1800-ost", ingenic_ost_init); ++TIMER_OF_DECLARE(x1021_ost_init, "ingenic,x1021-ost", ingenic_ost_init); ++TIMER_OF_DECLARE(x1520_ost_init, "ingenic,x1520-ost", ingenic_ost_init); ++TIMER_OF_DECLARE(x1600_ost_init, "ingenic,x1600-ost", ingenic_ost_init); ++TIMER_OF_DECLARE(x1630_ost_init, "ingenic,x1630-ost", ingenic_ost_init); +diff --git a/module_drivers/drivers/crypto/Kconfig b/module_drivers/drivers/crypto/Kconfig +new file mode 100644 +index 000000000..6081b8635 +--- /dev/null ++++ b/module_drivers/drivers/crypto/Kconfig +@@ -0,0 +1,23 @@ ++config CRYPTO_DEV_INGENIC_SHA ++ tristate "[SHA] Support for Ingenic SHA hw accelerator" ++ depends on MACH_XBURST || MACH_XBURST2 ++ select CRYPTO_ALGAPI ++ help ++ Some Ingenic processors have MD5/SHA1/SHA224/SHA256/SHA384/SHA512 ++ hw accelerator. ++ Select this if you want to use the Ingenic module for ++ MD5/SHA1/SHA224/SHA256/SHA384/SHA512 algorithms. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called ingenic-sha. ++ ++ ++config CRYPTO_DEV_INGENIC_AES ++ tristate "[AES] Support for INGENIC AES hw engine" ++ depends on MACH_XBURST || MACH_XBURST2 ++ select CRYPTO_AES ++ select CRYPTO_BLKCIPHER2 ++ help ++ INGENIC processors have AES module accelerator. Select this if you ++ want to use the INGENIC module for AES algorithms. ++ +diff --git a/module_drivers/drivers/crypto/Makefile b/module_drivers/drivers/crypto/Makefile +new file mode 100644 +index 000000000..b31d46a02 +--- /dev/null ++++ b/module_drivers/drivers/crypto/Makefile +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_CRYPTO_DEV_INGENIC_AES) += ingenic-aes.o ++obj-$(CONFIG_CRYPTO_DEV_INGENIC_SHA) += ingenic-hash.o +diff --git a/module_drivers/drivers/crypto/ingenic-aes.c b/module_drivers/drivers/crypto/ingenic-aes.c +new file mode 100644 +index 000000000..6d1981356 +--- /dev/null ++++ b/module_drivers/drivers/crypto/ingenic-aes.c +@@ -0,0 +1,923 @@ ++/* ++ * Cryptographic API. ++ * ++ * Support for Ingenic AES HW acceleration. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic-aes.h" ++#include ++ ++/* keep registered devices data here */ ++static LIST_HEAD(dev_list); ++static DEFINE_SPINLOCK(list_lock); ++ ++ ++static inline unsigned long aes_read(struct ingenic_aes_dev *aes, unsigned long offset) ++{ ++ return readl(aes->io_base + offset); ++} ++ ++static inline void aes_write(struct ingenic_aes_dev *aes, unsigned long offset, ++ unsigned long value) ++{ ++ writel(value, aes->io_base + offset); ++} ++ ++void dump_aes_reg(struct ingenic_aes_dev *aes){ ++ dev_info(aes->dev,"AES_ASCR: 0x%08lx\n",aes_read(aes,AES_ASCR)); ++ dev_info(aes->dev,"AES_ASSR: 0x%08lx\n",aes_read(aes,AES_ASSR)); ++ dev_info(aes->dev,"AES_ASINTM: 0x%08lx\n",aes_read(aes,AES_ASINTM)); ++ dev_info(aes->dev,"AES_ASSA: 0x%08lx\n",aes_read(aes,AES_ASSA)); ++ dev_info(aes->dev,"AES_ASDA: 0x%08lx\n",aes_read(aes,AES_ASDA)); ++ dev_info(aes->dev,"AES_ASTC: 0x%08lx\n",aes_read(aes,AES_ASTC)); ++} ++ ++static inline int ingenic_aes_hw_init(struct ingenic_aes_dev *aes) ++{ ++ /* ++ * clocks are enabled when request starts and disabled when finished. ++ * It may be long delays between requests. ++ * Device might go to off mode to save power. ++ */ ++ pm_runtime_get_sync(aes->dev); ++ ++ if (!(aes->flags & FLAGS_INIT)) { ++ aes->flags |= FLAGS_INIT; ++ aes->err = 0; ++ } ++ ++ return 0; ++} ++ ++static inline int check_keydone(struct ingenic_aes_dev *aes) ++{ ++ unsigned long timeout = 1000; ++ while(!(aes_read(aes,AES_ASSR) & (1 << 0)) && --timeout); ++ if(timeout == 0){ ++ dev_err(aes->dev,"Write keys is timeout.\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static inline void ingenic_aes_stop(struct ingenic_aes_dev *aes) ++{ ++ unsigned long d; ++ d = aes_read(aes, AES_ASCR); ++ d &= ~1; ++ aes_write(aes, AES_ASCR,d); ++ aes->flags = 0; ++ pm_runtime_put_sync(aes->dev); ++ pr_debug("ingenic aes stop. finished!\n"); ++} ++static inline int ingenic_aes_write_ctrl(struct ingenic_aes_dev *aes) ++{ ++ unsigned int key32; ++ int i; ++ unsigned long val,init_data,mode,alg; ++ int err; ++ err = ingenic_aes_hw_init(aes); ++ if (err){ ++ dev_err(aes->dev,"aes hw init failed.\n"); ++ return err; ++ } ++ // 1. Mask interrupt and clear interrupt. ++ aes_write(aes,AES_ASINTM,0); ++ aes_read(aes,AES_ASSR); ++ ++ // 2. AES enable and clear data for new process. ++ init_data = ASCR_PS_DEF | ASCR_CLR | ASCR_EN; ++ aes_write(aes,AES_ASCR,init_data); ++ ++ // 3. configure AES ++ ++ key32 = aes->ctx->keylen / sizeof(unsigned long); ++ switch(aes->ctx->keylen){ ++ case AES_KEYSIZE_128: ++ val = 0; ++ break; ++ case AES_KEYSIZE_192: ++ val = 1; ++ break; ++ case AES_KEYSIZE_256: ++ val = 2; ++ break; ++ default: ++ dev_err(aes->dev,"len error\n"); ++ return -EINVAL; ++ } ++ alg = (aes->flags & FLAGS_CBC) == FLAGS_CBC ? CBC_ALG:ECB_ALG; ++ mode = (aes->flags & FLAGS_DECRYPT) == FLAGS_DECRYPT ? DECRYPTO_MODE : ENCRYPTO_MODE; ++ init_data = ASCR_PS_DEF | ASCR_KEYL(val) | ASCR_ALGS(alg) | ASCR_DECE(mode) | ASCR_EN; ++ aes_write(aes,AES_ASCR,init_data); ++ ++ if (alg == CBC_ALG){ ++ // Initialize IV of cbc alg ++ unsigned int *dat = (unsigned int *)aes->req->iv; ++ if(dat == NULL){ ++ dev_err(aes->dev,"no set iv data in cbc(aes)\n"); ++ } ++ for (i = 0; i < 4; i++) { ++ aes_write(aes, AES_ASIV,__be32_to_cpu(dat[i])); ++ /* printk("======== iv:0x%08lx 0x%08x\n",dat[i],__be32_to_cpu(dat[i])); */ ++ } ++ init_data = aes_read(aes,AES_ASCR); ++ aes_write(aes,AES_ASCR,init_data | ASCR_INIT_IV); ++ } ++ // Initialize Key. ++ for (i = 0; i < key32; i++) { ++ aes_write(aes, AES_ASKY, ++ __be32_to_cpu(aes->ctx->key[i])); ++ /* printk("======== 0x%08lx 0x%08x\n",aes->ctx->key[i],__be32_to_cpu(aes->ctx->key[i])); */ ++ } ++ ++ init_data = aes_read(aes,AES_ASCR); ++ aes_write(aes,AES_ASCR,init_data | ASCR_KEYS); // check key done in dma process. ++ return 0; ++} ++ ++static struct ingenic_aes_dev *ingenic_aes_find_dev(struct ingenic_aes_ctx *ctx) ++{ ++ struct ingenic_aes_dev *aes = NULL, *tmp; ++ ++ spin_lock(&list_lock); ++ if (!ctx->aes) { ++ list_for_each_entry(tmp, &dev_list, list) { ++ /* FIXME: take fist available aes core */ ++ aes = tmp; ++ break; ++ } ++ ctx->aes = aes; ++ } else { ++ /* already found before */ ++ aes = ctx->aes; ++ } ++ spin_unlock(&list_lock); ++ ++ return aes; ++} ++ ++static int ingenic_aes_dma_init(struct ingenic_aes_dev *aes) ++{ ++ int err = -ENOMEM; ++ aes->buf_in = (void *)__get_free_pages(GFP_KERNEL, INGENIC_AES_CACHE_PAGE_SHIFT); ++ aes->buf_out = (void *)__get_free_pages(GFP_KERNEL, INGENIC_AES_CACHE_PAGE_SHIFT); ++ aes->buflen = PAGE_SIZE << INGENIC_AES_CACHE_PAGE_SHIFT; ++ aes->buflen &= ~(AES_BLOCK_SIZE - 1); ++ ++ if (!aes->buf_in || !aes->buf_out) { ++ dev_err(aes->dev, "unable to alloc pages.\n"); ++ goto err_alloc; ++ } ++ aes->dma_addr_in = dma_map_single(aes->dev, aes->buf_in, aes->buflen, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(aes->dev, aes->dma_addr_in)) { ++ dev_err(aes->dev, "dma %d bytes error\n", aes->buflen); ++ err = -EINVAL; ++ goto err_map_in; ++ } ++ ++ aes->dma_addr_out = dma_map_single(aes->dev, aes->buf_out, aes->buflen, ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(aes->dev, aes->dma_addr_out)) { ++ dev_err(aes->dev, "dma %d bytes error\n", aes->buflen); ++ err = -EINVAL; ++ goto err_map_out; ++ } ++ return 0; ++err_map_out: ++ dma_unmap_single(aes->dev, aes->dma_addr_in, aes->buflen, DMA_TO_DEVICE); ++err_map_in: ++ free_pages((unsigned long)aes->buf_out, INGENIC_AES_CACHE_PAGE_SHIFT); ++ free_pages((unsigned long)aes->buf_in, INGENIC_AES_CACHE_PAGE_SHIFT); ++err_alloc: ++ if (err) ++ pr_err("error: %d\n", err); ++ return err; ++} ++ ++static void ingenic_aes_dma_cleanup(struct ingenic_aes_dev *aes) ++{ ++ free_pages((unsigned long)aes->buf_out, INGENIC_AES_CACHE_PAGE_SHIFT); ++ free_pages((unsigned long)aes->buf_in, INGENIC_AES_CACHE_PAGE_SHIFT); ++} ++ ++static void sg_copy_buf(void *buf, struct scatterlist *sg, ++ unsigned int start, unsigned int nbytes, int out) ++{ ++ struct scatter_walk walk; ++ ++ if (!nbytes) ++ return; ++ ++ scatterwalk_start(&walk, sg); ++ scatterwalk_advance(&walk, start); ++ scatterwalk_copychunks(buf, &walk, nbytes, out); ++ scatterwalk_done(&walk, out, 0); ++} ++ ++static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf, ++ size_t buflen, size_t total, int out) ++{ ++ unsigned int count, off = 0; ++ ++ while (buflen && total) { ++ count = min((*sg)->length - *offset, total); ++ count = min(count, buflen); ++ ++ if (!count) ++ return off; ++ ++ /* ++ * buflen and total are AES_BLOCK_SIZE size aligned, ++ * so count should be also aligned ++ */ ++ ++ sg_copy_buf(buf + off, *sg, *offset, count, out); ++ ++ off += count; ++ buflen -= count; ++ *offset += count; ++ total -= count; ++ ++ if (*offset == (*sg)->length) { ++ *sg = sg_next(*sg); ++ if (*sg) ++ *offset = 0; ++ else ++ total = 0; ++ } ++ } ++ ++ return off; ++} ++ ++void dump_sgdata(struct scatterlist *sg) ++{ ++ int i; ++ unsigned int *d = sg_virt(sg); ++ for(i = 0;i < sg->length;i += 4) ++ { ++ printk("%5d:0x%08x\n",i,d[i/4]); ++ } ++} ++ ++void prep_sgdata(struct scatterlist *sg) ++{ ++ int i; ++ unsigned int *d = sg_virt(sg); ++ unsigned int dat; ++ for(i = 0;i < sg->length + 16;i += 4) ++ { ++ dat = d[i/4]; ++ d[i/4] = __be32_to_cpu(dat); ++ } ++} ++ ++ ++static int ingenic_aes_crypt_dma(struct crypto_tfm *tfm, ++ struct scatterlist *in_sg, struct scatterlist *out_sg) ++{ ++ struct ingenic_aes_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct ingenic_aes_dev *aes = ctx->aes; ++ ++ dma_addr_t dma_addr_in = sg_dma_address(in_sg); ++ dma_addr_t dma_addr_out = sg_dma_address(out_sg); ++ int length = sg_dma_len(in_sg); ++ int blen = 0; ++ ++ unsigned int config; ++// dev_info(aes->dev,"len: %d\n", length); ++ if(check_keydone(aes) != 0){ ++ dev_err(aes->dev,"check key done failed!\n"); ++ return -EINPROGRESS; ++ } ++ ++ config = aes_read(aes,AES_ASCR); ++ ++ aes->dma_size = length; ++ aes_write(aes,AES_ASSA,dma_addr_in); ++ aes_write(aes,AES_ASDA,dma_addr_out); ++ ++ blen = length / 16; // perblock is 128bit. ++ ++ if(length % 16) ++ return -EINVAL; ++ ++ aes_write(aes,AES_ASTC,blen); ++ aes_write(aes,AES_ASINTM,4); ++ config |= (ASCR_DMAE | ASCR_DMAS); ++ aes_write(aes,AES_ASCR,config); ++ return 0; ++} ++static int ingenic_aes_crypt_dma_start(struct ingenic_aes_dev *aes) ++{ ++ struct crypto_tfm *tfm = crypto_skcipher_tfm(crypto_skcipher_reqtfm(aes->req)); ++ int err, fast = 0, in, out; ++ size_t count; ++ dma_addr_t addr_in, addr_out; ++ struct scatterlist *in_sg, *out_sg; ++ int len32; ++ ++ unsigned int ivoffset = aes->req->cryptlen - AES_BLOCK_SIZE; ++ dev_dbg(aes->dev,"total: %d\n", aes->total); ++ ++ if (sg_is_last(aes->in_sg) && sg_is_last(aes->out_sg)) { ++ /* check for alignment */ ++ in = IS_ALIGNED((unsigned long)aes->in_sg->offset, sizeof(unsigned long)); ++ out = IS_ALIGNED((unsigned long)aes->out_sg->offset, sizeof(unsigned long)); ++ ++ fast = in && out; ++ } ++ if (fast) { ++ count = min(aes->total, sg_dma_len(aes->in_sg)); ++ count = min(count, sg_dma_len(aes->out_sg)); ++ if (count != aes->total) { ++ pr_err("request length != buffer length\n"); ++ return -EINVAL; ++ } ++ ++ if(aes->flags & FLAGS_CBC){ ++ if(aes->flags & FLAGS_DECRYPT){ ++ memcpy(aes->req->iv, sg_virt(aes->in_sg) + ivoffset, AES_BLOCK_SIZE); ++ } ++ } ++ ++ prep_sgdata(aes->in_sg); ++ //dump_sgdata(aes->in_sg); ++ ++ pr_debug("fast\n"); ++ err = dma_map_sg(aes->dev, aes->in_sg, 1, DMA_TO_DEVICE); ++ ++ if (!err) { ++ dev_err(aes->dev, "dma_map_sg() error\n"); ++ return -EINVAL; ++ } ++ ++ err = dma_map_sg(aes->dev, aes->out_sg, 1, DMA_FROM_DEVICE); ++ if (!err) { ++ dev_err(aes->dev, "dma_map_sg() error\n"); ++ dma_unmap_sg(aes->dev, aes->in_sg, 1, DMA_TO_DEVICE); ++ return -EINVAL; ++ } ++ ++ addr_in = sg_dma_address(aes->in_sg); ++ addr_out = sg_dma_address(aes->out_sg); ++ in_sg = aes->in_sg; ++ out_sg = aes->out_sg; ++ ++ aes->flags |= FLAGS_FAST; ++ ++ } else { ++ /* use cache buffers */ ++ count = sg_copy(&aes->in_sg, &aes->in_offset, aes->buf_in, ++ aes->buflen, aes->total, 0); ++ ++ len32 = DIV_ROUND_UP(count, DMA_MIN) * DMA_MIN; ++ /* ++ * The data going into the AES module has been copied ++ * to a local buffer and the data coming out will go ++ * into a local buffer so set up local SG entries for ++ * both. ++ */ ++ ++ sg_init_one(&aes->in_sgl,aes->buf_in,len32); ++ sg_dma_len(&aes->in_sgl) = len32; ++ sg_dma_address(&aes->in_sgl) = aes->dma_addr_in; ++ sg_init_one(&aes->out_sgl,aes->buf_out,len32); ++ sg_dma_len(&aes->out_sgl) = len32; ++ sg_dma_address(&aes->out_sgl) = aes->dma_addr_out; ++ ++ in_sg = &aes->in_sgl; ++ out_sg = &aes->out_sgl; ++ ++ addr_in = aes->dma_addr_in; ++ addr_out = aes->dma_addr_out; ++ ++ if(aes->flags & FLAGS_CBC){ ++ if(aes->flags & FLAGS_DECRYPT){ ++ memcpy(aes->req->iv, aes->buf_in + ivoffset, AES_BLOCK_SIZE); ++ } ++ } ++ ++ prep_sgdata(in_sg); ++ //dump_sgdata(in_sg); ++ ++ aes->flags &= ~FLAGS_FAST; ++ dma_sync_sg_for_device(aes->dev, in_sg, 1, DMA_TO_DEVICE); ++ dma_sync_sg_for_device(aes->dev, out_sg, 1, DMA_FROM_DEVICE); ++ } ++ ++ aes->total -= count; ++ err = ingenic_aes_crypt_dma(tfm, in_sg, out_sg); ++ if (err) { ++ dma_unmap_sg(aes->dev, aes->in_sg, 1, DMA_TO_DEVICE); ++ dma_unmap_sg(aes->dev, aes->out_sg, 1, DMA_FROM_DEVICE); ++ } ++ ++ return err; ++} ++ ++static void ingenic_aes_finish_req(struct ingenic_aes_dev *aes, int err) ++{ ++ struct skcipher_request *req = aes->req; ++ ++ pr_debug("err: %d\n", err); ++ ++ aes->flags &= ~FLAGS_BUSY; ++ req->base.complete(&req->base, err); ++ ++#ifdef CONFIG_HIGHMEM ++ if (PageHighMem(sg_page(req->src))) ++ kunmap_high(sg_page(req->src)); ++ if (PageHighMem(sg_page(req->dst))) ++ kunmap_high(sg_page(req->dst)); ++#endif ++} ++ ++static int ingenic_aes_crypt_dma_stop(struct ingenic_aes_dev *aes) ++{ ++ int err = 0; ++ size_t count; ++ /* unsigned int val; */ ++ pr_debug("total: %d\n", aes->total); ++ ++ /* val = aes_read(aes,AES_ASCR); */ ++ /* val &= ~(3 << 8); */ ++ /* aes_write(aes,AES_ASCR,val); */ ++ ++ ++ unsigned int ivoffset = aes->req->cryptlen - AES_BLOCK_SIZE; ++ ++ if (aes->flags & FLAGS_FAST) ++ { ++ dma_unmap_sg(aes->dev, aes->out_sg, 1, DMA_FROM_DEVICE); ++ prep_sgdata(aes->out_sg); ++ //dump_sgdata(aes->out_sg); ++ dma_unmap_sg(aes->dev, aes->in_sg, 1, DMA_TO_DEVICE); ++ if(aes->flags & FLAGS_CBC){ ++ if(!(aes->flags & FLAGS_DECRYPT)){ ++ memcpy(aes->req->iv, sg_virt(aes->out_sg) + ivoffset, AES_BLOCK_SIZE); ++ } ++ } ++ ++ } else { ++ dma_sync_single_for_device(aes->dev, aes->dma_addr_out, ++ aes->dma_size, DMA_FROM_DEVICE); ++ ++ prep_sgdata(&aes->out_sgl); ++ //dump_sgdata(&aes->out_sgl); ++ ++ /* copy data */ ++ count = sg_copy(&aes->out_sg, &aes->out_offset, aes->buf_out, ++ aes->buflen, aes->dma_size, 1); ++ if(aes->flags & FLAGS_CBC){ ++ if(!(aes->flags & FLAGS_DECRYPT)){ ++ unsigned int ivoffset = aes->req->cryptlen - AES_BLOCK_SIZE; ++ memcpy(aes->req->iv, aes->buf_out + ivoffset, AES_BLOCK_SIZE); ++ } ++ } ++ if (count != aes->dma_size) { ++ err = -EINVAL; ++ pr_err("not all data converted: %u\n", count); ++ } ++ } ++ return err; ++} ++ ++static int ingenic_aes_start(struct ingenic_aes_dev *aes, ++ struct skcipher_request *req) ++{ ++ struct crypto_async_request *async_req, *backlog; ++ struct ingenic_aes_ctx *ctx; ++ struct ingenic_aes_reqctx *rctx; ++ unsigned long flags; ++ int err, ret = 0; ++ spin_lock_irqsave(&aes->lock, flags); ++ if (req) { ++ ++#ifdef CONFIG_HIGHMEM ++ if (PageHighMem(sg_page(req->src))) ++ kmap_high(sg_page(req->src)); ++ if (PageHighMem(sg_page(req->dst))) ++ kmap_high(sg_page(req->dst)); ++#endif ++ ++ ret = crypto_enqueue_request(&aes->queue, &req->base); ++ } ++ if (aes->flags & FLAGS_BUSY) { ++ spin_unlock_irqrestore(&aes->lock, flags); ++ return ret; ++ } ++ backlog = crypto_get_backlog(&aes->queue); ++ async_req = crypto_dequeue_request(&aes->queue); ++ if (async_req) ++ aes->flags |= FLAGS_BUSY; ++ spin_unlock_irqrestore(&aes->lock, flags); ++ ++ if (!async_req){ ++ ingenic_aes_stop(aes); ++ return ret; ++ } ++ if (backlog) ++ backlog->complete(backlog, -EINPROGRESS); ++ req = skcipher_request_cast(async_req); ++ ++ /* assign new request to device */ ++ aes->req = req; ++ aes->total = req->cryptlen; ++ aes->in_offset = 0; ++ aes->in_sg = req->src; ++ aes->out_offset = 0; ++ aes->out_sg = req->dst; ++ ++ rctx = skcipher_request_ctx(req); ++ ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); ++ rctx->mode &= FLAGS_MODE_MASK; ++ aes->flags = (aes->flags & ~FLAGS_MODE_MASK) | rctx->mode; ++ ++ aes->ctx = ctx; ++ ctx->aes = aes; ++ ++ err = ingenic_aes_write_ctrl(aes); ++ if (!err) ++ err = ingenic_aes_crypt_dma_start(aes); ++ ++ if (err) { ++ ++ dev_err(aes->dev,"dma start failed.!\n"); ++ ingenic_aes_stop(aes); ++ /* aes_task will not finish it, so do it here */ ++ ingenic_aes_finish_req(aes, err); ++ } ++ return ret; /* return ret, which is enqueue return value */ ++} ++ ++static int ingenic_aes_crypt(struct skcipher_request *req, unsigned long mode) ++{ ++ struct ingenic_aes_ctx *ctx = crypto_skcipher_ctx( ++ crypto_skcipher_reqtfm(req)); ++ struct ingenic_aes_reqctx *rctx = skcipher_request_ctx(req); ++ struct ingenic_aes_dev *aes; ++ pr_info("nbytes: %d, enc: %d, cbc: %d\n", req->cryptlen, ++ !(mode & FLAGS_DECRYPT), ++ !!(mode & FLAGS_CBC)); ++ ++ if (!IS_ALIGNED(req->cryptlen, AES_BLOCK_SIZE)) { ++ pr_err("request size is not exact amount of AES blocks\n"); ++ return -EINVAL; ++ } ++ aes = ingenic_aes_find_dev(ctx); ++ if (!aes) ++ return -ENODEV; ++ rctx->mode = mode; ++ return ingenic_aes_start(aes, req); ++} ++static irqreturn_t ingenic_aec_irqthread(int irq, void *data) ++{ ++ struct ingenic_aes_dev *aes = (struct ingenic_aes_dev *)data; ++ unsigned long val; ++ unsigned long mask; ++ ++ val = aes_read(aes,AES_ASSR); ++ mask = aes_read(aes,AES_ASINTM); ++ val = val & mask; ++ ++ if(val & 4){ ++ int err; ++ err = ingenic_aes_crypt_dma_stop(aes); ++ aes_write(aes,AES_ASSR,4); ++ err = aes->err ? : err; ++ if (aes->total && !err) { ++ err = ingenic_aes_crypt_dma_start(aes); ++ if (!err) ++ return IRQ_HANDLED; /* DMA started. Not fininishing. */ ++ } ++ ingenic_aes_finish_req(aes, err); ++ ingenic_aes_start(aes,NULL); ++ }else if(val & 2){ ++ aes_write(aes,AES_ASSR,2); ++ }else if(val & 1){ ++ aes_write(aes,AES_ASSR,1); ++ }else{ ++ dev_err(aes->dev,"unknown irq!!!\n"); ++ dump_aes_reg(aes); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* ********************** ALG API ************************************ */ ++ ++static int ingenic_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, ++ unsigned int keylen) ++{ ++ struct ingenic_aes_ctx *ctx = crypto_skcipher_ctx(tfm); ++ ++ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 && ++ keylen != AES_KEYSIZE_256) ++ return -EINVAL; ++ ++ pr_debug("enter, keylen: %d\n", keylen); ++ ++ memcpy(ctx->key, key, keylen); ++ ctx->keylen = keylen; ++ ++ return 0; ++} ++ ++static int ingenic_aes_ecb_encrypt(struct skcipher_request *req) ++{ ++ return ingenic_aes_crypt(req, 0); ++} ++ ++static int ingenic_aes_ecb_decrypt(struct skcipher_request *req) ++{ ++ return ingenic_aes_crypt(req, FLAGS_DECRYPT); ++} ++ ++static int ingenic_aes_cbc_encrypt(struct skcipher_request *req) ++{ ++ return ingenic_aes_crypt(req, FLAGS_CBC); ++} ++ ++static int ingenic_aes_cbc_decrypt(struct skcipher_request *req) ++{ ++ return ingenic_aes_crypt(req, FLAGS_DECRYPT | FLAGS_CBC); ++} ++ ++static int ingenic_aes_cra_init(struct crypto_skcipher *tfm) ++{ ++ pr_debug("enter\n"); ++ tfm->reqsize = sizeof(struct ingenic_aes_reqctx); ++ return 0; ++} ++ ++static void ingenic_aes_cra_exit(struct crypto_skcipher *tfm) ++{ ++ pr_debug("exit\n"); ++} ++ ++/* ********************** ALGS ************************************ */ ++static struct skcipher_alg algs_ecb_cbc[] = { ++ { ++ .base.cra_name = "ecb(aes)", ++ .base.cra_driver_name = "ecb-aes-ingenic", ++ .base.cra_priority = 100, ++ .base.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC, ++ .base.cra_blocksize = AES_BLOCK_SIZE, ++ .base.cra_ctxsize = sizeof(struct ingenic_aes_ctx), ++ .base.cra_alignmask = 0, ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .setkey = ingenic_aes_setkey, ++ .encrypt = ingenic_aes_ecb_encrypt, ++ .decrypt = ingenic_aes_ecb_decrypt, ++ ++ .init = ingenic_aes_cra_init, ++ .exit = ingenic_aes_cra_exit, ++ }, ++ { ++ .base.cra_name = "cbc(aes)", ++ .base.cra_driver_name = "cbc-aes-ingenic", ++ .base.cra_priority = 100, ++ .base.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC, ++ .base.cra_blocksize = AES_BLOCK_SIZE, ++ .base.cra_ctxsize = sizeof(struct ingenic_aes_ctx), ++ .base.cra_alignmask = 0, ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ .setkey = ingenic_aes_setkey, ++ .encrypt = ingenic_aes_cbc_encrypt, ++ .decrypt = ingenic_aes_cbc_decrypt, ++ ++ .init = ingenic_aes_cra_init, ++ .exit = ingenic_aes_cra_exit, ++ }, ++}; ++ ++static struct ingenic_aes_pdata ingenic_aes_pdata = { ++ .algs_list = algs_ecb_cbc, ++ .size = ARRAY_SIZE(algs_ecb_cbc), ++}; ++static int ingenic_aes_get_res_pdev(struct ingenic_aes_dev *aes, ++ struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *r; ++ int err; ++ int ret = 0; ++ /* Get the base address */ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!r) { ++ dev_err(dev, "no MEM resource info\n"); ++ err = -ENODEV; ++ goto err; ++ } ++ ++ aes->io_base = devm_ioremap(aes->dev, r->start, resource_size(r)); ++ if(IS_ERR_OR_NULL(aes->io_base)) { ++ dev_err(&pdev->dev, "Failed to remap io resources!\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ aes->irq = platform_get_irq(pdev,0); ++ if(aes->irq < 0){ ++ dev_err(dev,"Failed to request irq resource info\n"); ++ ret = -EBUSY; ++ goto err; ++ } ++ ++ err = request_threaded_irq(aes->irq,NULL,ingenic_aec_irqthread, ++ IRQF_ONESHOT,dev_name(dev),aes); ++ ++ aes->pdata = &ingenic_aes_pdata; ++ ++err: ++ return ret; ++} ++static noinline void pdma_wait(void) ++{ ++ __asm__ volatile ( ++ " .set push \n\t" ++ " .set noreorder \n\t" ++ " .set mips32 \n\t" ++ " li $26, 0 \n\t" ++ " mtc0 $26, $12 \n\t" ++ " nop \n\t" ++ "1: \n\t" ++ " wait \n\t" ++ " b 1b \n\t" ++ " nop \n\t" ++ " .set reorder \n\t" ++ " .set pop \n\t" ++ ); ++} ++ ++static int ingenic_aes_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ingenic_aes_dev *aes; ++ struct skcipher_alg *algp; ++ int err = -ENOMEM, i; ++ ++ aes = devm_kzalloc(dev,sizeof(struct ingenic_aes_dev), GFP_KERNEL); ++ if (aes == NULL) { ++ dev_err(dev, "unable to alloc data struct.\n"); ++ goto err_data; ++ } ++ aes->dev = dev; ++ aes->clk_gate = devm_clk_get(&pdev->dev, "gate_aes"); ++ if (IS_ERR(aes->clk_gate)) { ++ dev_err(&pdev->dev, "cannot find RTC clock\n"); ++ err = PTR_ERR(aes->clk_gate); ++ goto err_data; ++ } ++ ++ clk_prepare_enable(aes->clk_gate); ++ aes->clk_gate = devm_clk_get(&pdev->dev, "gate_pdma"); ++ if (IS_ERR(aes->clk_gate)) { ++ dev_err(&pdev->dev, "cannot find aes clock\n"); ++ err = PTR_ERR(aes->clk_gate); ++ goto err_data; ++ } ++ ++ clk_prepare_enable(aes->clk_gate); ++ printk("gate = %lx\n", *(unsigned long*)0xb0000020); ++ ++ platform_set_drvdata(pdev, aes); ++ ++ reset_mcu(); ++ memcpy((void*)MCU_BOOT,pdma_wait,64); ++ boot_up_mcu(); ++ ++ mdelay(100); ++ /* *(unsigned long*)0xb3421030 = 1; */ ++ ++ spin_lock_init(&aes->lock); ++ crypto_init_queue(&aes->queue, INGENIC_AES_QUEUE_LENGTH); ++ ++ err = ingenic_aes_get_res_pdev(aes, pdev); ++ if (err) ++ goto err_data; ++ ++ err = ingenic_aes_dma_init(aes); ++ if (err) ++ goto err_data; ++ ++ INIT_LIST_HEAD(&aes->list); ++ spin_lock(&list_lock); ++ list_add_tail(&aes->list, &dev_list); ++ spin_unlock(&list_lock); ++ for (i = 0; i < aes->pdata->size; i++) { ++ algp = &aes->pdata->algs_list[i]; ++ pr_info("reg alg: %s\n", algp->base.cra_name); ++ err = crypto_register_skcipher(algp); ++ if (err) ++ goto err_algs; ++ aes->pdata->registered++; ++ } ++ printk("ingenic aes[%d] register ok.",aes->pdata->registered); ++ return 0; ++err_algs: ++ for (i = aes->pdata->registered - 1; i >= 0; i--) ++ crypto_unregister_skcipher(&aes->pdata->algs_list[i]); ++ ingenic_aes_dma_cleanup(aes); ++err_data: ++ dev_err(dev, "initialization failed.\n"); ++ return err; ++} ++ ++static int ingenic_aes_remove(struct platform_device *pdev) ++{ ++ struct ingenic_aes_dev *aes = platform_get_drvdata(pdev); ++ int i; ++ ++ if (!aes) ++ return -ENODEV; ++ ++ spin_lock(&list_lock); ++ list_del(&aes->list); ++ spin_unlock(&list_lock); ++ for (i = aes->pdata->registered - 1; i >= 0; i--) ++ crypto_unregister_skcipher(&aes->pdata->algs_list[i]); ++ aes->pdata->registered = 0; ++ ingenic_aes_dma_cleanup(aes); ++ pm_runtime_disable(aes->dev); ++ kfree(aes); ++ aes = NULL; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int ingenic_aes_suspend(struct device *dev) ++{ ++ pm_runtime_put_sync(dev); ++ return 0; ++} ++ ++static int ingenic_aes_resume(struct device *dev) ++{ ++ pm_runtime_get_sync(dev); ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops ingenic_aes_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(ingenic_aes_suspend, ingenic_aes_resume) ++}; ++ ++static const struct of_device_id ingenic_aes_dt_match[] = { ++ { .compatible = "ingenic,aes", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, aic_dt_match); ++ ++ ++static struct platform_driver ingenic_aes_driver = { ++ .probe = ingenic_aes_probe, ++ .remove = ingenic_aes_remove, ++ .driver = { ++ .name = "aes", ++ .owner = THIS_MODULE, ++ .pm = &ingenic_aes_pm_ops, ++ .of_match_table = of_match_ptr(ingenic_aes_dt_match), ++ }, ++}; ++ ++module_platform_driver(ingenic_aes_driver); ++ ++MODULE_DESCRIPTION("Ingenic AES hw acceleration support."); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Stephon.Qiu"); +diff --git a/module_drivers/drivers/crypto/ingenic-aes.h b/module_drivers/drivers/crypto/ingenic-aes.h +new file mode 100644 +index 000000000..f0f4a2b85 +--- /dev/null ++++ b/module_drivers/drivers/crypto/ingenic-aes.h +@@ -0,0 +1,113 @@ ++#ifndef __INGENIC_AES_H__ ++#define __INGENIC_AES_H__ ++ ++#define INGENIC_AES_QUEUE_LENGTH (50) ++#define INGENIC_AES_CACHE_PAGE_SHIFT (0) ++#define DMA_MIN 4 ++ ++#define AES_ASCR (0x00) ++#define AES_ASSR (0x04) ++#define AES_ASINTM (0x08) ++#define AES_ASSA (0x0c) ++#define AES_ASDA (0x10) ++#define AES_ASTC (0x14) ++#define AES_ASDI (0x18) ++#define AES_ASDO (0x1c) ++#define AES_ASKY (0x20) ++#define AES_ASIV (0x24) ++ ++#define ASCR_PS_DEF (3 << 28) ++#define ASCR_CLR (1 << 10) ++ ++#define ASCR_DMAS (1 << 9) ++#define ASCR_DMAE (1 << 8) ++ ++#define ASCR_KEYL(len) ((len) << 6) ++ ++#define ECB_ALG (0) ++#define CBC_ALG (1) ++#define ASCR_ALGS(alg) ((alg) << 5) ++ ++#define ENCRYPTO_MODE (0) ++#define DECRYPTO_MODE (1) ++#define ASCR_DECE(m) ((m) << 4) ++ ++ ++#define ASCR_AESS (1 << 3) ++#define ASCR_KEYS (1 << 2) ++#define ASCR_INIT_IV (1 << 1) ++#define ASCR_EN (1 << 0) ++ ++struct ingenic_aes_reqctx { ++ unsigned long mode; ++}; ++ ++struct ingenic_aes_ctx { ++ struct ingenic_aes_dev *aes; ++ ++ int keylen; ++ unsigned long key[AES_KEYSIZE_256 / sizeof(unsigned long)]; ++ unsigned long flags; ++ struct crypto_skcipher *fallback; ++}; ++ ++/* struct ingenic_aes_algs_info { */ ++/* struct crypto_alg *algs_list; */ ++/* unsigned int size; */ ++/* unsigned int registered; */ ++/* }; */ ++struct ingenic_aes_pdata { ++ struct skcipher_alg *algs_list; ++ unsigned int size; ++ unsigned int registered; ++}; ++ ++struct ingenic_aes_dev { ++ struct list_head list; ++ void __iomem *io_base; ++ int irq; ++ struct clk *clk_gate; ++ struct ingenic_aes_ctx *ctx; ++ struct device *dev; ++ unsigned long flags; ++ int err; ++ ++ spinlock_t lock; ++ struct crypto_queue queue; ++ struct skcipher_request *req; ++ size_t total; ++ ++ struct scatterlist *in_sg; ++ ++ struct scatterlist in_sgl; ++ size_t in_offset; ++ struct scatterlist *out_sg; ++ struct scatterlist out_sgl; ++ size_t out_offset; ++ ++ size_t buflen; ++ void *buf_in; ++ void *buf_out; ++ dma_addr_t dma_addr_in; ++ dma_addr_t dma_addr_out; ++ ++ size_t dma_size; ++ struct ingenic_aes_pdata *pdata; ++}; ++ ++ ++#define FLAGS_MODE_MASK 0x000f ++#define FLAGS_DECRYPT BIT(0) ++#define FLAGS_CBC BIT(1) ++ ++#define FLAGS_INIT BIT(4) ++#define FLAGS_FAST BIT(5) ++#define FLAGS_BUSY BIT(6) ++ ++#define MCU_BOOT 0xb3422000 ++ ++#define DMCS 0xb3421030 ++#define boot_up_mcu() *(volatile unsigned int *)(DMCS) = 0; ++#define reset_mcu() *(volatile unsigned int *)(DMCS) = 1; ++ ++#endif /*__INGENIC_AES_H__*/ +diff --git a/module_drivers/drivers/crypto/ingenic-hash.c b/module_drivers/drivers/crypto/ingenic-hash.c +new file mode 100644 +index 000000000..fee8942a3 +--- /dev/null ++++ b/module_drivers/drivers/crypto/ingenic-hash.c +@@ -0,0 +1,1111 @@ ++/* ++ * Cryptographic API. ++ * ++ * Support for Ingenic HASH HW acceleration. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic-hash.h" ++#include ++ ++/* keep registered devices data here */ ++static LIST_HEAD(dev_list); ++static DEFINE_SPINLOCK(list_lock); ++ ++ ++static inline unsigned long hash_read(struct ingenic_hash_dev *hash, unsigned long offset) ++{ ++ return readl(hash->io_base + offset); ++} ++ ++static inline void hash_write(struct ingenic_hash_dev *hash, unsigned long offset, ++ unsigned long value) ++{ ++ writel(value, hash->io_base + offset); ++} ++ ++static inline void dump_reg(struct ingenic_hash_dev *hash) ++{ ++ dev_info(hash->dev,"HASH_HSCR: 0x%08lx\n",hash_read(hash,HASH_HSCR)); ++ dev_info(hash->dev,"HASH_HSSR: 0x%08lx\n",hash_read(hash,HASH_HSSR)); ++ dev_info(hash->dev,"hash_ASINTM: 0x%08lx\n",hash_read(hash,HASH_HSINTM)); ++ dev_info(hash->dev,"HASH_HSSA: 0x%08lx\n",hash_read(hash,HASH_HSSA)); ++ dev_info(hash->dev,"HASH_HSTC: 0x%08lx\n",hash_read(hash,HASH_HSTC)); ++} ++static inline int ingenic_hash_hw_init(struct ingenic_hash_dev *hash,struct ingenic_hash_reqctx *ctx) ++{ ++ /* ++ * clocks are enabled when request starts and disabled when finished. ++ * It may be long delays between requests. ++ * Device might go to off mode to save power. ++ */ ++ unsigned int alg = -1; ++ unsigned int init_data = 0; ++ pm_runtime_get_sync(hash->dev); ++ ++ if(ctx->flags & HASH_FLAGS_MD5){ ++ alg = 0; ++ init_data = 0; ++ }else if(ctx->flags & HASH_FLAGS_SHA1) ++ { ++ init_data = 3 << 7; ++ alg = 1; ++ }else if(ctx->flags & HASH_FLAGS_SHA224) ++ { ++ init_data = 3 << 7; ++ alg = 2; ++ }else if(ctx->flags & HASH_FLAGS_SHA256) ++ { ++ init_data = 3 << 7; ++ alg = 3; ++ }else if(ctx->flags & HASH_FLAGS_SHA384) ++ { ++ init_data = 3 << 7; ++ alg = 4; ++ }else if(ctx->flags & HASH_FLAGS_SHA512) ++ { ++ init_data = 3 << 7; ++ alg = 5; ++ } ++ init_data |= 3 << 28 | 1 << 4 | alg << 1 | 1; ++ hash_write(hash, HASH_HSCR,init_data); ++ hash_write(hash,HASH_HSINTM,0); ++ hash->flags |= HASH_FLAGS_INIT; ++ return 0; ++} ++static int ingenic_hash_update_dma_stop(struct ingenic_hash_dev *hash) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(hash->req); ++ ++ if (ctx->flags & HASH_FLAGS_SG) { ++ dma_unmap_sg(hash->dev, ctx->sg, 1, DMA_TO_DEVICE); ++ if (ctx->sg->length == ctx->offset) { ++ ctx->sg = sg_next(ctx->sg); ++ if (ctx->sg) ++ ctx->offset = 0; ++ } ++ if (ctx->flags & HASH_FLAGS_PAD) { ++ dma_unmap_single(hash->dev, ctx->dma_addr, ++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE); ++ } ++ } else { ++ dma_unmap_single(hash->dev, ctx->dma_addr, ctx->buflen + ++ ctx->block_size, DMA_TO_DEVICE); ++ } ++ ++ return 0; ++} ++static void ingenic_hash_copy_hash(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ u32 *hash = (u32 *)ctx->digest; ++ int i; ++ if(ctx->flags & HASH_FLAGS_MD5){ ++ for (i = 0; i < MD5_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++ }else if (ctx->flags & HASH_FLAGS_SHA1) ++ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++ else if (ctx->flags & HASH_FLAGS_SHA224) ++ for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++ else if (ctx->flags & HASH_FLAGS_SHA256) ++ for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++ else if (ctx->flags & HASH_FLAGS_SHA384) ++ for (i = 0; i < SHA384_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++ else ++ for (i = 0; i < SHA512_DIGEST_SIZE / sizeof(u32); i++) ++ hash[i] = hash_read(ctx->hash, HASH_HSDO); ++} ++ ++static void ingenic_hash_copy_ready_hash(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ if (!req->result) ++ return; ++ if (ctx->flags & HASH_FLAGS_MD5) ++ memcpy(req->result, ctx->digest, MD5_DIGEST_SIZE); ++ if (ctx->flags & HASH_FLAGS_SHA1) ++ memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE); ++ else if (ctx->flags & HASH_FLAGS_SHA224) ++ memcpy(req->result, ctx->digest, SHA224_DIGEST_SIZE); ++ else if (ctx->flags & HASH_FLAGS_SHA256) ++ memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE); ++ else if (ctx->flags & HASH_FLAGS_SHA384) ++ memcpy(req->result, ctx->digest, SHA384_DIGEST_SIZE); ++ else ++ memcpy(req->result, ctx->digest, SHA512_DIGEST_SIZE); ++} ++ ++static int ingenic_hash_finish(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ struct ingenic_hash_dev *hash = ctx->hash; ++ int err = 0; ++ ++ if (ctx->digcnt[0] || ctx->digcnt[1]) ++ ingenic_hash_copy_ready_hash(req); ++ ++ dev_dbg(hash->dev, "digcnt: 0x%llx 0x%llx, bufcnt: %d\n", ctx->digcnt[1], ++ ctx->digcnt[0], ctx->bufcnt); ++ ++ return err; ++} ++static void ingenic_hash_finish_req(struct ahash_request *req, int err) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ struct ingenic_hash_dev *hash = ctx->hash; ++ if(ctx->bufcnt == 0){ ++ if (!err) { ++ ingenic_hash_copy_hash(req); ++ if (HASH_FLAGS_FINAL & hash->flags) ++ err = ingenic_hash_finish(req); ++ } else { ++ ctx->flags |= HASH_FLAGS_ERROR; ++ } ++ ++ /* atomic operation is not needed here */ ++ hash->flags &= ~(HASH_FLAGS_BUSY | HASH_FLAGS_FINAL | HASH_FLAGS_INIT); ++ pm_runtime_put_sync(hash->dev); ++ } ++ /* clk_disable_unprepare(hash->iclk); */ ++ if (req->base.complete) ++ req->base.complete(&req->base, err); ++} ++ ++static struct ingenic_hash_dev *ingenic_hash_find_dev(struct ingenic_hash_ctx *ctx) ++{ ++ struct ingenic_hash_dev *hash = NULL, *tmp; ++ ++ spin_lock(&list_lock); ++ hash = ctx->hash; ++ if (!hash) { ++ list_for_each_entry(tmp, &dev_list, list) { ++ /* FIXME: take fist available hash core */ ++ hash = tmp; ++ ctx->hash = tmp; ++ break; ++ } ++ } ++ spin_unlock(&list_lock); ++ return hash; ++} ++/* ++ * The purpose of this padding is to ensure that the padded message is a ++ * multiple of 512 bits (SHA1/SHA224/SHA256) or 1024 bits (SHA384/SHA512). ++ * The bit "1" is appended at the end of the message followed by ++ * "padlen-1" zero bits. Then a 64 bits block (SHA1/SHA224/SHA256) or ++ * 128 bits block (SHA384/SHA512) equals to the message length in bits ++ * is appended. ++ * ++ * For SHA1/SHA224/SHA256, padlen is calculated as followed: ++ * - if message length < 56 bytes then padlen = 56 - message length ++ * - else padlen = 64 + 56 - message length ++ * ++ * For SHA384/SHA512, padlen is calculated as followed: ++ * - if message length < 112 bytes then padlen = 112 - message length ++ * - else padlen = 128 + 112 - message length ++ */ ++static void ingenic_hash_fill_padding(struct ingenic_hash_reqctx *ctx, int length) ++{ ++ ++ unsigned int index, padlen; ++ u64 bits[2]; ++ u64 size[2]; ++ ++ size[0] = ctx->digcnt[0]; ++ size[1] = ctx->digcnt[1]; ++ ++ size[0] += ctx->bufcnt; ++ if (size[0] < ctx->bufcnt) ++ size[1]++; ++ ++ size[0] += length; ++ if (size[0] < length) ++ size[1]++; ++ ++ bits[1] = cpu_to_be64(size[0] << 3); ++ bits[0] = cpu_to_be64(size[1] << 3 | size[0] >> 61); ++ if (ctx->flags & (HASH_FLAGS_SHA384 | HASH_FLAGS_SHA512)) { ++ index = ctx->bufcnt & 0x7f; ++ padlen = (index < 112) ? (112 - index) : ((128+112) - index); ++ *(ctx->buffer + ctx->bufcnt) = 0x80; ++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1); ++ memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16); ++ ctx->bufcnt += padlen + 16; ++ ctx->flags |= HASH_FLAGS_PAD; ++ } else if(ctx->flags & HASH_FLAGS_MD5){ ++ unsigned int *d; ++ index = ctx->bufcnt & 0x3f; ++ padlen = (index < 56) ? (56 - index) : ((64+56) - index); ++ *(ctx->buffer + ctx->bufcnt) = 0x80; ++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1); ++ d = (unsigned int *)((unsigned char*)ctx->buffer + ctx->bufcnt + padlen); ++ d[0] = cpu_to_le32(size[0] << 3); ++ d[1] = cpu_to_le32(size[0] >> 29); ++ //memcpy(ctx->buffer + ctx->bufcnt + padlen + 1, &bits1[1], 4); ++ ctx->bufcnt += padlen + 8; ++ ctx->flags |= HASH_FLAGS_PAD; ++ }else { ++ index = ctx->bufcnt & 0x3f; ++ padlen = (index < 56) ? (56 - index) : ((64+56) - index); ++ *(ctx->buffer + ctx->bufcnt) = 0x80; ++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1); ++ memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8); ++ ctx->bufcnt += padlen + 8; ++ ctx->flags |= HASH_FLAGS_PAD; ++ } ++ /* for(int i = 0;i < 64/4;i++){ */ ++ /* unsigned int *d = ctx->buffer; */ ++ /* d +=(ctx->bufcnt - 64) / sizeof(unsigned int); */ ++ /* printk("buffer[%p]%03d: 0x%08x\n",d+i,i,d[i]); */ ++ /* } */ ++} ++ ++static size_t ingenic_hash_append_sg(struct ingenic_hash_reqctx *ctx) ++{ ++ size_t count; ++ ++ while ((ctx->bufcnt < ctx->buflen) && ctx->total) { ++ count = min(ctx->sg->length - ctx->offset, ctx->total); ++ count = min(count, ctx->buflen - ctx->bufcnt); ++ ++ if (count <= 0) ++ break; ++ ++ scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, ctx->sg, ++ ctx->offset, count, 0); ++ ++ ctx->bufcnt += count; ++ ctx->offset += count; ++ ctx->total -= count; ++ ++ if (ctx->offset == ctx->sg->length) { ++ ctx->sg = sg_next(ctx->sg); ++ if (ctx->sg) ++ ctx->offset = 0; ++ else ++ ctx->total = 0; ++ } ++ } ++ return 0; ++} ++static int ingenic_hash_xmit_start(struct ingenic_hash_dev *hash, dma_addr_t dma_addr, ++ size_t length, int final) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(hash->req); ++ ctx->digcnt[0] += length; ++ if (ctx->digcnt[0] < length) ++ ctx->digcnt[1]++; ++ ++ if (final) ++ hash->flags |= HASH_FLAGS_FINAL; ++ hash->flags |= HASH_FLAGS_DMA_ACTIVE; ++ hash_write(hash,HASH_HSSA,dma_addr); ++ hash_write(hash, HASH_HSTC, length / (512 / 8)); ++ ++ hash_write(hash, HASH_HSINTM,2); ++// dump_reg(hash); ++ { ++ unsigned int val; ++ val = hash_read(hash, HASH_HSCR); ++ hash_write(hash, HASH_HSCR, val | (3 << 5)); ++ } ++ return -EINPROGRESS; ++} ++ ++static int ingenic_hash_xmit_dma_map(struct ingenic_hash_dev *hash, ++ struct ingenic_hash_reqctx *ctx, ++ size_t length, int final) ++{ ++ ctx->dma_addr = dma_map_single(hash->dev, ctx->buffer, ++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE); ++ ++ if (dma_mapping_error(hash->dev, ctx->dma_addr)) { ++ dev_err(hash->dev, "dma %u bytes error\n", ctx->buflen + ++ ctx->block_size); ++ return -EINVAL; ++ } ++ ++ ctx->flags &= ~HASH_FLAGS_SG; ++ ++ /* next call does not fail... so no unmap in the case of error */ ++ return ingenic_hash_xmit_start(hash, ctx->dma_addr, length, final); ++} ++static int ingenic_hash_final_req(struct ingenic_hash_dev *hash) ++{ ++ struct ahash_request *req = hash->req; ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ int err = 0; ++ int count; ++ ++ ingenic_hash_fill_padding(ctx, 0); ++ count = ctx->bufcnt; ++ ctx->bufcnt = 0; ++ err = ingenic_hash_xmit_dma_map(hash, ctx, count, 1); ++ dev_dbg(hash->dev, "final_req: err: %d\n", err); ++ ++ return err; ++} ++ ++static int ingenic_hash_update_dma_slow(struct ingenic_hash_dev *hash) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(hash->req); ++ unsigned int final; ++ size_t count; ++ ++ ingenic_hash_append_sg(ctx); ++ ++ final = (ctx->flags & HASH_FLAGS_FINUP) && !ctx->total; ++ ++ dev_dbg(hash->dev, "slow: bufcnt: %u, digcnt: 0x%llx 0x%llx, final: %d\n", ++ ctx->bufcnt, ctx->digcnt[1], ctx->digcnt[0], final); ++ ++ if (final) ++ ingenic_hash_fill_padding(ctx, 0); ++ ++ if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) { ++ count = ctx->bufcnt; ++ ctx->bufcnt = 0; ++ return ingenic_hash_xmit_dma_map(hash, ctx, count, final); ++ } ++ ++ return 0; ++} ++ ++ ++static int ingenic_hash_update_dma_start(struct ingenic_hash_dev *hash) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(hash->req); ++ unsigned int length, final, tail; ++ struct scatterlist *sg; ++ unsigned int count; ++ sg = ctx->sg; ++ if (!ctx->total && !ctx->bufcnt){ ++ return 0; ++ } ++ if(ctx->flags & HASH_FLAGS_FINUP) ++ { ++ if (ctx->bufcnt || ctx->offset) ++ return ingenic_hash_update_dma_slow(hash); ++ dev_dbg(hash->dev, "fast: digcnt: 0x%llx 0x%llx, bufcnt: %u, total: %u\n", ++ ctx->digcnt[1], ctx->digcnt[0], ctx->bufcnt, ctx->total); ++ ++ if (!IS_ALIGNED(sg->offset, sizeof(u32))) ++ return ingenic_hash_update_dma_slow(hash); ++ ++ if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, ctx->block_size)){ ++ /* size is not ctx->block_size aligned */ ++ return ingenic_hash_update_dma_slow(hash); ++ } ++ } ++ length = min(ctx->total, sg->length); ++ if (sg_is_last(sg)) { ++ if (!(ctx->flags & HASH_FLAGS_FINUP)) ++ { ++ /* not last sg must be ctx->block_size aligned */ ++ tail = length & (ctx->block_size - 1); ++ length -= tail; ++ if(length == 0){ ++ ingenic_hash_append_sg(ctx); ++ hash->flags &= ~HASH_FLAGS_BUSY; ++ return 0; ++ } ++ }else if(length + ctx->bufcnt > ctx->buflen) ++ { ++ length = ctx->buflen - ctx->bufcnt; ++ } ++ } ++ final = (ctx->flags & HASH_FLAGS_FINUP) && !(ctx->total - length); ++ /* Add padding */ ++ if (final) { ++ ++ sg = ctx->sg; ++ ingenic_hash_append_sg(ctx); ++ ++ ingenic_hash_fill_padding(ctx, 0); ++ ++ ctx->dma_addr = dma_map_single(hash->dev, ctx->buffer, ++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE); ++ ++ if (dma_mapping_error(hash->dev, ctx->dma_addr)) { ++ dev_err(hash->dev, "dma %u bytes error\n", ++ ctx->buflen + ctx->block_size); ++ return -EINVAL; ++ } ++ ++ if (ctx->bufcnt != 0) { ++ ctx->flags &= ~HASH_FLAGS_SG; ++ count = ctx->bufcnt; ++ ctx->bufcnt = 0; ++ return ingenic_hash_xmit_start(hash, ctx->dma_addr, count, final); ++ } ++ }else if(ctx->bufcnt && (ctx->flags & HASH_FLAGS_FINUP)){ ++ return ingenic_hash_update_dma_slow(hash); ++ }else{ ++ ctx->total -= length; ++ ctx->offset = length; /* offset where to start slow */ ++ } ++ ++ if (!dma_map_sg(hash->dev, ctx->sg, 1, DMA_TO_DEVICE)) { ++ dev_err(hash->dev, "dma_map_sg error\n"); ++ return -EINVAL; ++ } ++ ctx->flags |= HASH_FLAGS_SG; ++ ++ /* next call does not fail... so no unmap in the case of error */ ++ return ingenic_hash_xmit_start(hash, sg_dma_address(ctx->sg), length, final); ++} ++ ++static int ingenic_hash_update_req(struct ingenic_hash_dev *hash) ++{ ++ struct ahash_request *req = hash->req; ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ int err; ++ ++ dev_dbg(hash->dev, "update_req: total: %u, digcnt: 0x%llx 0x%llx\n", ++ ctx->total, ctx->digcnt[1], ctx->digcnt[0]); ++ ++ err = ingenic_hash_update_dma_start(hash); ++ ++ /* wait for dma completion before can take more data */ ++ dev_dbg(hash->dev, "update: err: %d, digcnt: 0x%llx 0%llx\n", ++ err, ctx->digcnt[1], ctx->digcnt[0]); ++ ++ return err; ++} ++static int ingenic_hash_handle_queue(struct ingenic_hash_dev *hash, ++ struct ahash_request *req) ++{ ++ struct crypto_async_request *async_req, *backlog; ++ struct ingenic_hash_reqctx *ctx; ++ unsigned long flags; ++ int err = 0, ret = 0; ++ spin_lock_irqsave(&hash->lock, flags); ++ if (req) ++ ret = ahash_enqueue_request(&hash->queue, req); ++ ++ if (HASH_FLAGS_BUSY & hash->flags) { ++ spin_unlock_irqrestore(&hash->lock, flags); ++ return ret; ++ } ++ ++ backlog = crypto_get_backlog(&hash->queue); ++ async_req = crypto_dequeue_request(&hash->queue); ++ if (async_req) ++ hash->flags |= HASH_FLAGS_BUSY; ++ ++ spin_unlock_irqrestore(&hash->lock, flags); ++ ++ if (!async_req) ++ return ret; ++ ++ if (backlog) ++ backlog->complete(backlog, -EINPROGRESS); ++ ++ req = ahash_request_cast(async_req); ++ hash->req = req; ++ ctx = ahash_request_ctx(req); ++ ++ dev_dbg(hash->dev, "handling new req, op: %lu, nbytes: %d\n", ++ ctx->op, req->nbytes); ++ ++ if(!(hash->flags & HASH_FLAGS_INIT)){ ++ err = ingenic_hash_hw_init(hash,ctx); ++ if (err) ++ goto err1; ++ } ++ /* if (ctx->op == HASH_OP_UPDATE) { */ ++ err = ingenic_hash_update_req(hash); ++ /* if (err != -EINPROGRESS && (ctx->flags & HASH_FLAGS_FINUP)) */ ++ /* /\* no final() after finup() *\/ */ ++ /* err = ingenic_hash_final_req(hash); */ ++ /* } else if (ctx->op == HASH_OP_FINAL) { */ ++ /* err = ingenic_hash_final_req(hash); */ ++ /* } */ ++err1: ++ return err; ++#if 0 ++err1: ++ if (err != -EINPROGRESS) ++ /* done_task will not finish it, so do it here */ ++ ingenic_hash_finish_req(req, err); ++ ++ dev_dbg(hash->dev, "exit, err: %d\n", err); ++ ++ return err; ++#endif ++} ++ ++static int ingenic_hash_enqueue(struct ahash_request *req, unsigned int op) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ struct ingenic_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); ++ struct ingenic_hash_dev *hash = tctx->hash; ++ ++ ctx->op = op; ++ ++ return ingenic_hash_handle_queue(hash, req); ++} ++static void hash_dma_done(struct ingenic_hash_dev *hash) ++{ ++ int err = 0; ++ if (HASH_FLAGS_DMA_ACTIVE & hash->flags) { ++ hash->flags &= ~HASH_FLAGS_DMA_ACTIVE; ++ ingenic_hash_update_dma_stop(hash); ++ } ++ err = ingenic_hash_update_dma_start(hash); ++ if (err != -EINPROGRESS){ ++ ingenic_hash_finish_req(hash->req, err); ++ }else if (!(HASH_FLAGS_BUSY & hash->flags)) { ++ ingenic_hash_handle_queue(hash, NULL); ++ } ++} ++static irqreturn_t ingenic_hash_irqthread(int irq, void *data) ++{ ++ struct ingenic_hash_dev *hash = (struct ingenic_hash_dev *)data; ++ unsigned int val; ++ val = hash_read(hash,HASH_HSSR); ++ hash_write(hash,HASH_HSSR,val); ++ if(val & 2){ ++ hash_dma_done(hash); ++ }else{ ++ printk("Don't support the irq"); ++ } ++ return IRQ_HANDLED; ++} ++ ++/* ********************** ALG API ************************************ */ ++ ++static int ingenic_hash_init(struct ahash_request *req) ++{ ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); ++ struct ingenic_hash_ctx *ctx = crypto_ahash_ctx(tfm); ++ struct ingenic_hash_reqctx *rctx = ahash_request_ctx(req); ++ struct ingenic_hash_dev *hash = NULL; ++ /* struct ingenic_hash_dev *tmp; */ ++ ENTER(); ++ hash = ingenic_hash_find_dev(ctx); ++ ++ rctx->hash = hash; ++ rctx->flags = 0; ++ dev_dbg(hash->dev, "init: digest size: %d\n", ++ crypto_ahash_digestsize(tfm)); ++ ++ switch (crypto_ahash_digestsize(tfm)) { ++ case MD5_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_MD5; ++ rctx->block_size = MD5_BLOCK_SIZE; ++ case SHA1_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_SHA1; ++ rctx->block_size = SHA1_BLOCK_SIZE; ++ break; ++ case SHA224_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_SHA224; ++ rctx->block_size = SHA224_BLOCK_SIZE; ++ break; ++ case SHA256_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_SHA256; ++ rctx->block_size = SHA256_BLOCK_SIZE; ++ break; ++ case SHA384_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_SHA384; ++ rctx->block_size = SHA384_BLOCK_SIZE; ++ break; ++ case SHA512_DIGEST_SIZE: ++ rctx->flags |= HASH_FLAGS_SHA512; ++ rctx->block_size = SHA512_BLOCK_SIZE; ++ break; ++ default: ++ return -EINVAL; ++ break; ++ } ++ rctx->bufcnt = 0; ++ rctx->total = 0; ++ rctx->digcnt[0] = 0; ++ rctx->digcnt[1] = 0; ++ rctx->buffer = ctx->buf; ++ rctx->buflen = HASH_BUFFER_LEN; ++ EXIT(); ++ ++ return 0; ++} ++static int ingenic_hash_final(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ struct ingenic_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); ++ struct ingenic_hash_dev *hash = tctx->hash; ++ ++ int err = 0; ++ ENTER(); ++ ctx->flags |= HASH_FLAGS_FINUP; ++ if (ctx->flags & HASH_FLAGS_ERROR){ ++ EXIT(); ++ return 0; /* uncompleted hash is not needed */ ++ } ++ if (ctx->bufcnt) { ++ err = ingenic_hash_enqueue(req, HASH_OP_FINAL); ++ EXIT(); ++ return err; ++ } else if (!(ctx->flags & HASH_FLAGS_PAD)) { /* add padding */ ++ err = ingenic_hash_hw_init(hash,ctx); ++ if (err) ++ goto err1; ++ hash->req = req; ++ hash->flags |= HASH_FLAGS_BUSY; ++ err = ingenic_hash_final_req(hash); ++ } else { ++ /* copy ready hash (+ finalize hmac) */ ++ return ingenic_hash_finish(req); ++ } ++err1: ++ if (err != -EINPROGRESS) ++ /* done_task will not finish it, so do it here */ ++ ingenic_hash_finish_req(req, err); ++ EXIT(); ++ return err; ++} ++ ++static int ingenic_hash_update(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ int ret; ++ ENTER(); ++ if (!req->nbytes){ ++ EXIT(); ++ return 0; ++ } ++ ++ ctx->total = req->nbytes; ++ ctx->sg = req->src; ++ ++ ctx->offset = 0; ++ if (ctx->bufcnt + ctx->total < ctx->buflen) { ++ ingenic_hash_append_sg(ctx); ++ return 0; ++ } ++ ret = ingenic_hash_enqueue(req, HASH_OP_UPDATE); ++ EXIT(); ++ return ret; ++} ++ ++static int ingenic_hash_finup(struct ahash_request *req) ++{ ++ struct ingenic_hash_reqctx *ctx = ahash_request_ctx(req); ++ int err1, err2; ++ ENTER(); ++ ctx->flags |= HASH_FLAGS_FINUP; ++ ++ err1 = ingenic_hash_update(req); ++ if (err1 == -EINPROGRESS || err1 == -EBUSY) ++ return err1; ++ ++ /* ++ * final() has to be always called to cleanup resources ++ * even if udpate() failed, except EINPROGRESS ++ */ ++ err2 = ingenic_hash_final(req); ++ EXIT(); ++ return err1 ?: err2; ++} ++ ++static int ingenic_hash_digest(struct ahash_request *req) ++{ ++ return ingenic_hash_init(req) ?: ingenic_hash_finup(req); ++} ++ ++static int ingenic_hash_export(struct ahash_request *req, void *out) ++{ ++ struct ingenic_hash_reqctx *rctx = ahash_request_ctx(req); ++ ++ memcpy(out, rctx, sizeof(*rctx)); ++ ++ return 0; ++} ++ ++static int ingenic_hash_import(struct ahash_request *req, const void *in) ++{ ++ struct ingenic_hash_reqctx *rctx = ahash_request_ctx(req); ++ ++ memcpy(rctx, in, sizeof(*rctx)); ++ ++ return 0; ++} ++ ++static int ingenic_hash_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base) ++{ ++// struct ingenic_hash_ctx *tctx = crypto_tfm_ctx(tfm); ++// const char *alg_name = crypto_tfm_alg_name(tfm); ++// ENTER(); ++// /* Allocate a fallback and abort if it failed. */ ++// tctx->fallback = crypto_alloc_shash(alg_name, 0, ++// CRYPTO_ALG_NEED_FALLBACK); ++// if (IS_ERR(tctx->fallback)) { ++// pr_err("ingenic-hash: fallback driver '%s' could not be loaded.\n", ++// alg_name); ++// EXIT(); ++// return PTR_ERR(tctx->fallback); ++// } ++ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), ++ sizeof(struct ingenic_hash_reqctx)); ++// EXIT(); ++ return 0; ++} ++ ++static int ingenic_hash_cra_init(struct crypto_tfm *tfm) ++{ ++ return ingenic_hash_cra_init_alg(tfm, NULL); ++} ++ ++static void ingenic_hash_cra_exit(struct crypto_tfm *tfm) ++{ ++ struct ingenic_hash_ctx *tctx = crypto_tfm_ctx(tfm); ++ ENTER(); ++ tctx->fallback = NULL; ++ EXIT(); ++} ++ ++ ++/* ********************** ALGS ************************************ */ ++static struct ahash_alg hash_md5_algs[] = { ++#if 0 ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .digest = ingenic_hash_digest, ++ .halg = { ++ .digestsize = MD5_DIGEST_SIZE, ++ .statesize = 1, ++ .base = { ++ .cra_name = "md5", ++ .cra_driver_name= "ingenic-sha1", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, ++ .cra_blocksize = MD5_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++#endif ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .export = ingenic_hash_export, ++ .import = ingenic_hash_import, ++ .digest = ingenic_hash_digest, ++ .halg = { ++ .digestsize = SHA1_DIGEST_SIZE, ++ .statesize = sizeof(struct ingenic_hash_reqctx), ++ .base = { ++ .cra_name = "sha1", ++ .cra_driver_name = "ingenic-sha1", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_blocksize = SHA1_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .export = ingenic_hash_export, ++ .import = ingenic_hash_import, ++ .digest = ingenic_hash_digest, ++ .halg = { ++ .digestsize = SHA224_DIGEST_SIZE, ++ .statesize = sizeof(struct ingenic_hash_reqctx), ++ .base = { ++ .cra_name = "sha224", ++ .cra_driver_name = "ingenic-sha224", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_blocksize = SHA224_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .export = ingenic_hash_export, ++ .import = ingenic_hash_import, ++ .digest = ingenic_hash_digest, ++ .halg = { ++ .digestsize = SHA256_DIGEST_SIZE, ++ .statesize = sizeof(struct ingenic_hash_reqctx), ++ .base = { ++ .cra_name = "sha256", ++ .cra_driver_name = "ingenic-sha256", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_blocksize = SHA256_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .digest = ingenic_hash_digest, ++ .export = ingenic_hash_export, ++ .import = ingenic_hash_import, ++ .halg = { ++ .digestsize = SHA384_DIGEST_SIZE, ++ .statesize = sizeof(struct ingenic_hash_reqctx), ++ .base = { ++ .cra_name = "sha384", ++ .cra_driver_name = "ingenic-sha384", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_blocksize = SHA384_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0x3, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++ { ++ .init = ingenic_hash_init, ++ .update = ingenic_hash_update, ++ .final = ingenic_hash_final, ++ .finup = ingenic_hash_finup, ++ .digest = ingenic_hash_digest, ++ .export = ingenic_hash_export, ++ .import = ingenic_hash_import, ++ .halg = { ++ .digestsize = SHA512_DIGEST_SIZE, ++ .statesize = sizeof(struct ingenic_hash_reqctx), ++ .base = { ++ .cra_name = "sha512", ++ .cra_driver_name = "ingenic-sha512", ++ .cra_priority = 100, ++ .cra_flags = CRYPTO_ALG_ASYNC, ++ .cra_blocksize = SHA512_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ingenic_hash_ctx), ++ .cra_alignmask = 0x3, ++ .cra_module = THIS_MODULE, ++ .cra_init = ingenic_hash_cra_init, ++ .cra_exit = ingenic_hash_cra_exit, ++ } ++ } ++ }, ++}; ++ ++static struct ingenic_hash_pdata ingenic_hash_pdata = { ++ .algs_list = hash_md5_algs, ++ .size = ARRAY_SIZE(hash_md5_algs), ++}; ++static int ingenic_hash_get_res_pdev(struct ingenic_hash_dev *hash, ++ struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *r; ++ int err; ++ int ret = 0; ++ /* Get the base address */ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!r) { ++ dev_err(dev, "no MEM resource info\n"); ++ err = -ENODEV; ++ goto err; ++ } ++ ++ hash->io_base = devm_ioremap(hash->dev, r->start, resource_size(r)); ++ if(IS_ERR_OR_NULL(hash->io_base)) { ++ dev_err(&pdev->dev, "Failed to remap io resources!\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ hash->irq = platform_get_irq(pdev,0); ++ if(hash->irq < 0){ ++ dev_err(dev,"Failed to request irq resource info\n"); ++ ret = -EBUSY; ++ goto err; ++ } ++ ++ err = request_threaded_irq(hash->irq,NULL,ingenic_hash_irqthread, ++ IRQF_ONESHOT,dev_name(dev),hash); ++ ++ hash->pdata = &ingenic_hash_pdata; ++ ++err: ++ return ret; ++} ++ ++static int ingenic_hash_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ingenic_hash_dev *hash; ++ struct ahash_alg *algp; ++ int err = -ENOMEM, i; ++ ++ hash = devm_kzalloc(dev,sizeof(struct ingenic_hash_dev), GFP_KERNEL); ++ if (hash == NULL) { ++ dev_err(dev, "unable to alloc data struct.\n"); ++ goto err_data; ++ } ++ hash->dev = dev; ++ ++ hash->clk_gate = devm_clk_get(&pdev->dev, "gate_hash"); ++ if (IS_ERR(hash->clk_gate)) { ++ dev_err(&pdev->dev, "cannot find hash clock\n"); ++ err = PTR_ERR(hash->clk_gate); ++ goto err_data; ++ } ++ ++ clk_prepare_enable(hash->clk_gate); ++ ++ platform_set_drvdata(pdev, hash); ++ ++ crypto_init_queue(&hash->queue, INGENIC_HASH_QUEUE_LENGTH); ++ spin_lock_init(&hash->lock); ++ err = ingenic_hash_get_res_pdev(hash, pdev); ++ if (err) ++ goto err_data; ++ ++ pm_runtime_enable(dev); ++ ++ INIT_LIST_HEAD(&hash->list); ++ spin_lock(&list_lock); ++ list_add_tail(&hash->list, &dev_list); ++ ++ spin_unlock(&list_lock); ++ for (i = 0; i < hash->pdata->size; i++) { ++ algp = &hash->pdata->algs_list[i]; ++ pr_info("reg alg: %s\n", algp->halg.base.cra_name); ++// INIT_LIST_HEAD(&algp->cra_list); ++ err = crypto_register_ahash(algp); ++ if (err) ++ goto err_algs; ++ hash->pdata->registered++; ++ } ++ printk("ingenic hash[%d] register ok.",hash->pdata->registered); ++ return 0; ++err_algs: ++ for (i = hash->pdata->registered - 1; i >= 0; i--) ++ crypto_unregister_ahash( ++ &hash->pdata->algs_list[i]); ++ pm_runtime_disable(dev); ++err_data: ++ dev_err(dev, "initialization failed.\n"); ++ return err; ++} ++ ++static int ingenic_hash_remove(struct platform_device *pdev) ++{ ++ struct ingenic_hash_dev *hash = platform_get_drvdata(pdev); ++ int i; ++ ++ if (!hash) ++ return -ENODEV; ++ ++ spin_lock(&list_lock); ++ list_del(&hash->list); ++ spin_unlock(&list_lock); ++ for (i = hash->pdata->registered - 1; i >= 0; i--) ++ crypto_unregister_ahash( ++ &hash->pdata->algs_list[i]); ++ hash->pdata->registered = 0; ++ pm_runtime_disable(hash->dev); ++ kfree(hash); ++ hash = NULL; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int ingenic_hash_suspend(struct device *dev) ++{ ++ pm_runtime_put_sync(dev); ++ return 0; ++} ++ ++static int ingenic_hash_resume(struct device *dev) ++{ ++ pm_runtime_get_sync(dev); ++ return 0; ++} ++#endif ++ ++static const struct dev_pm_ops ingenic_hash_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(ingenic_hash_suspend, ingenic_hash_resume) ++}; ++ ++static const struct of_device_id ingenic_hash_dt_match[] = { ++ { .compatible = "ingenic,hash", .data = NULL }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_hash_dt_match); ++static struct platform_driver ingenic_hash_driver = { ++ .probe = ingenic_hash_probe, ++ .remove = ingenic_hash_remove, ++ .driver = { ++ .name = "hash", ++ .owner = THIS_MODULE, ++ .pm = &ingenic_hash_pm_ops, ++ .of_match_table = of_match_ptr(ingenic_hash_dt_match), ++ }, ++}; ++ ++module_platform_driver(ingenic_hash_driver); ++ ++MODULE_DESCRIPTION("Ingenic MD5,SHA(160,224,256,384,512) hw acceleration support."); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Stephon.Qiu"); +diff --git a/module_drivers/drivers/crypto/ingenic-hash.h b/module_drivers/drivers/crypto/ingenic-hash.h +new file mode 100644 +index 000000000..be045a571 +--- /dev/null ++++ b/module_drivers/drivers/crypto/ingenic-hash.h +@@ -0,0 +1,119 @@ ++#ifndef __INGENIC_HASH_H__ ++#define __INGENIC_HASH_H__ ++ ++#define ENTER() ++#define EXIT() ++ ++#define INGENIC_HASH_QUEUE_LENGTH (50) ++#define INGENIC_HASH_CACHE_PAGE_SHIFT (0) ++#define DMA_MIN 4 ++#define HASH_BUFFER_LEN PAGE_SIZE ++ ++/* HASH flags */ ++#define HASH_FLAGS_BUSY BIT(0) ++#define HASH_FLAGS_FINAL BIT(1) ++#define HASH_FLAGS_DMA_ACTIVE BIT(2) ++#define HASH_FLAGS_OUTPUT_READY BIT(3) ++#define HASH_FLAGS_INIT BIT(4) ++#define HASH_FLAGS_CPU BIT(5) ++#define HASH_FLAGS_DMA_READY BIT(6) ++ ++#define HASH_FLAGS_FINUP BIT(16) ++#define HASH_FLAGS_SG BIT(17) ++#define HASH_FLAGS_MD5 BIT(18) ++#define HASH_FLAGS_SHA1 BIT(19) ++#define HASH_FLAGS_SHA224 BIT(20) ++#define HASH_FLAGS_SHA256 BIT(21) ++#define HASH_FLAGS_SHA384 BIT(22) ++#define HASH_FLAGS_SHA512 BIT(23) ++#define HASH_FLAGS_ERROR BIT(24) ++#define HASH_FLAGS_PAD BIT(25) ++ ++#define HASH_OP_UPDATE 1 ++#define HASH_OP_FINAL 2 ++ ++ ++#define INGENIC_HASH_DMA_THRESHOLD 56 ++ ++#define MD5_DIGEST_SIZE 16 ++#define MD5_BLOCK_SIZE 64 ++ ++#define SHA1_DIGEST_SIZE 20 ++#define SHA1_BLOCK_SIZE 64 ++ ++#define SHA224_DIGEST_SIZE 28 ++#define SHA224_BLOCK_SIZE 64 ++ ++#define SHA256_DIGEST_SIZE 32 ++#define SHA256_BLOCK_SIZE 64 ++ ++#define SHA384_DIGEST_SIZE 48 ++#define SHA384_BLOCK_SIZE 128 ++ ++#define SHA512_DIGEST_SIZE 64 ++#define SHA512_BLOCK_SIZE 128 ++ ++#define HASH_HSCR 0 ++#define HASH_HSSR 4 ++#define HASH_HSINTM 8 ++#define HASH_HSSA 0xc ++#define HASH_HSTC 0x10 ++#define HASH_HSDI 0x14 ++#define HASH_HSDO 0x18 ++ ++ ++struct ingenic_hash_reqctx { ++ struct ingenic_hash_dev *hash; ++ unsigned long flags; ++ unsigned long op; ++ ++ u8 digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32)); ++ u64 digcnt[2]; ++ size_t bufcnt; ++ size_t buflen; ++ dma_addr_t dma_addr; ++ ++ /* walk state */ ++ struct scatterlist *sg; ++ unsigned int offset; /* offset in current sg */ ++ unsigned int total; /* total request */ ++ ++ size_t block_size; ++ u8 *buffer; ++ ++}; ++ ++struct ingenic_hash_ctx { ++ struct ingenic_hash_dev *hash; ++ unsigned long flags; ++ /* fallback stuff */ ++ struct crypto_ahash *fallback; ++ u8 buf[HASH_BUFFER_LEN] __aligned(sizeof(u32)); ++}; ++ ++struct ingenic_hash_pdata { ++ struct ahash_alg *algs_list; ++ unsigned int size; ++ unsigned int registered; ++}; ++ ++struct ingenic_hash_dev { ++ struct list_head list; ++ void __iomem *io_base; ++ int irq; ++ struct clk *clk_gate; ++ struct ingenic_hash_ctx *ctx; ++ struct device *dev; ++ unsigned long flags; ++ spinlock_t lock; ++ struct crypto_queue queue; ++ struct ahash_request *req; ++ struct ingenic_hash_pdata *pdata; ++}; ++ ++#define MCU_BOOT 0xb3422000 ++ ++#define DMCS 0xb3421030 ++#define boot_up_mcu() *(volatile unsigned int *)(DMCS) = 0; ++ ++#endif /*__INGENIC_HASH_H__*/ +diff --git a/module_drivers/drivers/dma/Makefile b/module_drivers/drivers/dma/Makefile +new file mode 100644 +index 000000000..10e2febc6 +--- /dev/null ++++ b/module_drivers/drivers/dma/Makefile +@@ -0,0 +1 @@ ++obj-y += ingenic/ +diff --git a/module_drivers/drivers/dma/ingenic/Kconfig b/module_drivers/drivers/dma/ingenic/Kconfig +new file mode 100644 +index 000000000..fff749d74 +--- /dev/null ++++ b/module_drivers/drivers/dma/ingenic/Kconfig +@@ -0,0 +1,25 @@ ++config INGENIC_PDMAC ++ bool "Ingenic programmable dma controller (Of Driver)" ++ depends on MACH_XBURST || MACH_XBURST2 ++ select DMA_VIRTUAL_CHANNELS ++ select DMA_ENGINE ++ help ++ This selects support for the DMA controller in Ingenic X1000 M200 SoCs. ++ If you have a board based on such a SoC and wish to use DMA for ++ devices which can use the DMA controller, say Y or M here. ++ ++ ++ ++# DMA engine configuration for ingenic ++config INGENIC_DMA_RECEIVE_DXTERNAL_DECIDE ++ tristate "ingenic dma receiving data is externally determined" ++ depends on INGENIC_PDMAC && SOC_X1600 ++ default n ++ help ++ How much data is received is externally determined ++ ++config INGENIC_AIC_USES_PDMA ++ bool "Ingenic AIC use pdma as dma." ++ depends on INGENIC_PDMAC ++ default n ++ +diff --git a/module_drivers/drivers/dma/ingenic/Makefile b/module_drivers/drivers/dma/ingenic/Makefile +new file mode 100644 +index 000000000..0fe3db703 +--- /dev/null ++++ b/module_drivers/drivers/dma/ingenic/Makefile +@@ -0,0 +1,3 @@ ++ccflags-y := -I$(srctree)/drivers/dma/ ++ ++obj-$(CONFIG_INGENIC_PDMAC) += ingenic_dma.o +diff --git a/module_drivers/drivers/dma/ingenic/ingenic_dma.c b/module_drivers/drivers/dma/ingenic/ingenic_dma.c +new file mode 100644 +index 000000000..0a98a6df0 +--- /dev/null ++++ b/module_drivers/drivers/dma/ingenic/ingenic_dma.c +@@ -0,0 +1,1179 @@ ++/* ++ * Copyright (C) 2016 Ingenic Semiconductor Co., Ltd. ++ * Author: cli ++ * ++ * Programmable DMA Controller Driver For Ingenic's SOC, ++ * such as X1000, and so on. (kernel.4.4) ++ * ++ * Author: cli ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#undef DEBUG ++/* #define VERBOSE_DEBUG */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic_dma.h" ++ ++#if defined(CONFIG_SOC_X2500) || defined(CONFIG_INGENIC_AIC_USES_PDMA) ++#define AIC_USES_PDMA ++#endif ++ ++#ifdef CONFIG_SOC_X2500 ++#include ++#endif ++ ++#define JZCAN_RX_DATA_OFFSET 0x90 ++ ++/* tsz for 1,2,4,8,16,32,64 128bytes */ ++const static char dcm_tsz[8] = { 1, 2, 0, 0, 3, 4, 5, 6}; ++static inline unsigned int get_current_tsz(unsigned long dcmp) ++{ ++ int i; ++ int val = (dcmp & DCM_TSZ_MSK) >> DCM_TSZ_SFT; ++ ++ if (DCM_TSZ_AUTO == val) ++ return 0; ++ ++ for (i = 0; i < ARRAY_SIZE(dcm_tsz); i++) { ++ if (val == dcm_tsz[i]) ++ break; ++ } ++ ++ return i; ++} ++ ++static inline unsigned get_max_tsz(unsigned long val, unsigned int *shift) ++{ ++ int ord = ffs(val) - 1; ++ ++ /* ++ * 8 byte transfer sizes unsupported so fall back on 4. If it's larger ++ * than the maximum, just limit it. It is perfectly safe to fall back ++ * in this way since we won't exceed the maximum burst size supported ++ * by the device, the only effect is reduced efficiency. This is better ++ * than refusing to perform the request at all. ++ */ ++ if (ord == 3) ++ ord = 2; ++ else if (ord > 7) ++ ord = 7; ++ ++ if (shift) ++ *shift = ord; ++ ++ return dcm_tsz[ord]; ++} ++ ++static const struct of_device_id ingenic_dma_dt_match[]; ++static struct ingenic_dma_engine *ingenic_dma_parse_dt(struct platform_device *pdev) ++{ ++ const struct of_device_id *match; ++ struct ingenic_dma_engine *ingenic_dma; ++ u32 nr_chs; ++ ++ if (!pdev->dev.of_node) ++ return ERR_PTR(-ENODEV); ++ ++ match = of_match_node(ingenic_dma_dt_match, pdev->dev.of_node); ++ if (!match) ++ return ERR_PTR(-ENODEV); ++ ++ if (of_property_read_u32(pdev->dev.of_node, "#dma-channels", &nr_chs)) ++ nr_chs = 32; ++ ++ ingenic_dma = devm_kzalloc(&pdev->dev, sizeof(*ingenic_dma) + ++ sizeof(struct ingenic_dma_chan *) * nr_chs, GFP_KERNEL); ++ if (!ingenic_dma) ++ return ERR_PTR(-ENOMEM); ++ ++ ingenic_dma->dev = &pdev->dev; ++ ingenic_dma->nr_chs = nr_chs; ++ ingenic_dma->hwattr = (unsigned int)match->data; ++ ++ /* Property is optional, if it doesn't exist the value will remain 0. */ ++ of_property_read_u32(pdev->dev.of_node, "ingenic,reserved-chs", ++ &ingenic_dma->chan_reserved); ++ ++ if (!of_property_read_u32(pdev->dev.of_node, "ingenic,programed-chs", ++ &ingenic_dma->chan_programed)) ++ ingenic_dma->chan_reserved |= ingenic_dma->chan_programed; ++ ++ if (HWATTR_SPECIAL_CH01_SUP(ingenic_dma->hwattr) && ++ of_property_read_bool(pdev->dev.of_node, "ingenic,special-chs")) { ++ ingenic_dma->chan_reserved |= DMA_SPECAIL_CHS; ++ ingenic_dma->chan_programed |= DMA_SPECAIL_CHS; ++ ingenic_dma->special_ch = true; ++ } ++ ++ ingenic_dma->intc_ch = -1; ++ if (HWATTR_INTC_IRQ_SUP(ingenic_dma->hwattr) && ++ !of_property_read_u32(pdev->dev.of_node, "ingenic,intc-ch", ++ (u32 *)&ingenic_dma->intc_ch)) { ++ ++ if (ingenic_dma->intc_ch >= ingenic_dma->nr_chs) ++ ingenic_dma->intc_ch = (ingenic_dma->nr_chs - 1); ++ ++ if (BIT(ingenic_dma->intc_ch) & ingenic_dma->chan_reserved) ++ dev_warn(ingenic_dma->dev, "WARN: intc irq channel %d is already reserved\n", ++ ingenic_dma->intc_ch); ++ ++ ingenic_dma->chan_reserved |= BIT(ingenic_dma->intc_ch); ++ } ++ return ingenic_dma; ++} ++ ++#define ALIGN_DOWN(addr, size) ((addr)&(~((size)-1))) ++ ++static int dump_dma_hdesc(struct hdma_desc * desc, const char * d) ++{ ++ int i; ++ unsigned long *p; ++ printk(KERN_DEBUG "%s(): %s\n", __func__, d); ++ p = (unsigned long *)desc; ++ for (i=0;i<8;i++) { ++ printk(KERN_DEBUG "\t%08lx\n", (unsigned long)*p); ++ p++; ++ } ++ ++ return 0; ++} ++ ++static unsigned int build_one_desc(dma_addr_t saddr, dma_addr_t daddr, ++ unsigned int length, struct hdma_desc *desc) ++{ ++ unsigned len = length; ++ ++ if (length < DTC_TC_MSK) { ++ desc->dcm = DCM_DAI | DCM_SAI | \ ++ (DCM_TSZ_AUTO << DCM_TSZ_SFT) | (DCM_RDIL_MAX << DCM_RDIL_SFT); ++ desc->dtc = len; /* DCM_TSZ_AUTO in bytes */ ++ } else { ++ unsigned int tsz, transfer_shift; ++ len = ALIGN_DOWN(len, sizeof(uint32_t)); ++ tsz = get_max_tsz(len , &transfer_shift); ++ desc->dcm = DCM_DAI | DCM_SAI | tsz << DCM_TSZ_SFT; ++ desc->dtc = len >> transfer_shift; /* in burst unit */ ++ barrier(); ++ len = desc->dtc << transfer_shift; ++ } ++ ++ desc->dsa = saddr; ++ desc->dta = daddr; ++ desc->sd = 0; ++ desc->drt = INGENIC_DMA_REQ_AUTO_TX; ++ ++ return len; ++} ++ ++static unsigned int build_one_slave_desc(struct ingenic_dma_chan *dmac, dma_addr_t addr, ++ unsigned int length, ++ enum dma_transfer_direction direction, ++ struct hdma_desc *desc) ++{ ++ enum dma_transfer_direction dir; ++ unsigned int rdil; ++ ++ desc->dcm = dmac->dcm; ++ desc->drt = dmac->slave_id; ++ desc->sd = 0; ++ ++ if ((direction != DMA_DEV_TO_MEM) && (direction != DMA_MEM_TO_DEV)) ++ dir = dmac->direction; ++ else ++ dir = direction; ++ ++ if (dir == DMA_DEV_TO_MEM) { ++ desc->dta = addr; ++ desc->dsa = dmac->slave_addr; ++ desc->dcm |= DCM_DAI; ++ } else { ++ desc->dsa = addr; ++ desc->dta = dmac->slave_addr; ++ desc->dcm |= DCM_SAI; ++ } ++ ++ rdil = dmac->maxburst * dmac->transfer_width; ++ if (rdil > 4) ++ rdil = min((int)fls(rdil) + 1, (int)DCM_RDIL_MAX); ++ ++ WARN_ON(length & (~DTC_TC_MSK)); ++ if (WARN_ON(!IS_ALIGNED(length, dmac->transfer_width))) { ++ desc->dtc = ALIGN_DOWN((length & DTC_TC_MSK), dmac->transfer_width); ++ } else { ++ desc->dtc = (length & DTC_TC_MSK); ++ } ++ desc->dcm |= DCM_TSZ_MSK | (rdil << DCM_RDIL_SFT); ++ ++ return desc->dtc; ++} ++ ++static void ingenic_dma_free_swdesc(struct virt_dma_desc *vd) ++{ ++ struct ingenic_dma_sdesc *sdesc = to_ingenic_dma_sdesc(vd); ++ struct ingenic_dma_chan *dmac = sdesc->dmac; ++ unsigned long flags; ++ int i; ++ ++ WARN_ON(!sdesc->dmac); ++ ++ spin_lock_irqsave(&dmac->hdesc_lock, flags); ++ if (dmac->hdesc_pool) { ++ for (i = 0; i < sdesc->nb_desc; i++) ++ dma_pool_free(dmac->hdesc_pool, sdesc->hw_desc[i], sdesc->hw_desc_dma[i]); ++ dmac->hdesc_num -= sdesc->nb_desc; ++ } ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++ ++ kfree(sdesc); ++ return; ++} ++ ++static struct ingenic_dma_sdesc *ingenic_dma_alloc_swdesc(struct ingenic_dma_chan *dmac, int num_hdesc) ++{ ++ struct ingenic_dma_sdesc *sdesc; ++ int i; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dmac->hdesc_lock, flags); ++ if (num_hdesc > (dmac->hdesc_max - dmac->hdesc_num) || !dmac->hdesc_pool) { ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++ return NULL; ++ } ++ ++ sdesc = (struct ingenic_dma_sdesc *)kzalloc(sizeof(struct ingenic_dma_sdesc) + ++ num_hdesc * (sizeof(void **) + sizeof(dma_addr_t)), ++ GFP_NOWAIT); ++ if (!sdesc) { ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++ return NULL; ++ } ++ ++ sdesc->hw_desc = (struct hdma_desc**)(sdesc + 1); ++ sdesc->hw_desc_dma = (dma_addr_t *)(sdesc->hw_desc + num_hdesc); ++ sdesc->dmac = dmac; ++ ++ for (i = 0; i < num_hdesc; i++) { ++ sdesc->hw_desc[i] = dma_pool_alloc(dmac->hdesc_pool, GFP_NOWAIT, &sdesc->hw_desc_dma[i]); ++ pr_debug("sdesc->hw_desc[%d] = %p, sdesc->hw_desc_dma[%d] = 0x%08x\n", ++ i, sdesc->hw_desc[i], ++ i, sdesc->hw_desc_dma[i]); ++ if (!sdesc->hw_desc[i]) { ++ dev_err(&dmac->vc.chan.dev->device, ++ "%s(): Couldn't allocate the hw_desc from dma_pool %p\n", ++ __func__, dmac->hdesc_pool); ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++ goto err; ++ } ++ sdesc->nb_desc++; ++ } ++ dmac->hdesc_num += sdesc->nb_desc; ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++ return sdesc; ++err: ++ ingenic_dma_free_swdesc(&sdesc->vd); ++ return NULL; ++} ++ ++#ifdef CONFIG_INGENIC_DMA_RECEIVE_DXTERNAL_DECIDE ++static void ingenic_dma_use_external_trigger(struct dma_chan *chan, ++ struct ingenic_dma_sdesc *sdesc, unsigned int desc_len) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ int i; ++ unsigned long des_offset = 0; ++ ++ for(i = 0; i < desc_len; i++) { ++ if(sdesc->hw_desc[i]->drt == INGENIC_DMA_REQ_CAN0_TX || ++ sdesc->hw_desc[i]->drt == INGENIC_DMA_REQ_CAN1_TX) { ++ sdesc->hw_desc[i]->dcm = DCM_SAI | DCM_DAI; ++ des_offset = sdesc->hw_desc[i]->dtc & (~DTC_TC_MSK); ++ sdesc->hw_desc[i]->dtc = sdesc->hw_desc[i]->dtc - des_offset; ++ sdesc->hw_desc[i]->dtc /= 4; ++ sdesc->hw_desc[i]->dtc += des_offset; ++ } else if(sdesc->hw_desc[i]->drt == INGENIC_DMA_REQ_CAN0_RX || ++ sdesc->hw_desc[i]->drt == INGENIC_DMA_REQ_CAN1_RX) { ++ des_offset = sdesc->hw_desc[i]->dtc & (~DTC_TC_MSK); ++ sdesc->hw_desc[i]->dtc = sdesc->hw_desc[i]->dtc - des_offset; ++ sdesc->hw_desc[i]->dtc /= 16; ++ sdesc->hw_desc[i]->dtc += des_offset; ++ sdesc->hw_desc[i]->dcm = DCM_DAI | DCM_SAIW | DCM_TSZ_EXTR; ++ writel(JZCAN_RX_DATA_OFFSET, dmac->engine->iomem + DSN0); ++ } else if ((sdesc->hw_desc[i]->drt == INGENIC_DMA_REQ_UART0_RX) || ++ (sdesc->hw_desc[i]->drt == INGENIC_DMA_REQ_UART1_RX) || ++ (sdesc->hw_desc[i]->drt == INGENIC_DMA_REQ_UART2_RX) || ++ (sdesc->hw_desc[i]->drt == INGENIC_DMA_REQ_UART3_RX)) { ++ sdesc->hw_desc[i]->dcm &= ~DCM_RDIL_MSK; ++ sdesc->hw_desc[i]->dcm &= ~DCM_TSZ_MSK; ++ sdesc->hw_desc[i]->dcm |= DCM_DAI | DCM_TSZ_EXTR; ++ } else { ++ /* add other need external trigger controller*/ ++ } ++ ++ if (i) { ++ sdesc->hw_desc[i - 1]->dcm |= DCM_LINK; ++ } ++ } ++ sdesc->hw_desc[i - 1]->dcm |= DCM_TIE; ++} ++#endif ++ ++static struct dma_async_tx_descriptor *ingenic_dma_prep_slave_sg( ++ struct dma_chan *chan, struct scatterlist *sgl, ++ unsigned int sg_len, enum dma_transfer_direction direction, ++ unsigned long flags, void *context) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ struct ingenic_dma_sdesc *sdesc; ++ int i; ++ ++ sdesc = ingenic_dma_alloc_swdesc(dmac, sg_len); ++ if (!sdesc) ++ return NULL; ++ ++ for (i = 0; i < sg_len; i++) { ++ sdesc->len += build_one_slave_desc(dmac, sg_dma_address(&sgl[i]), ++ sg_dma_len(&sgl[i]), direction, sdesc->hw_desc[i]); ++ if (i) { ++ sdesc->hw_desc[i - 1]->dcm |= DCM_LINK; ++ sdesc->hw_desc[i - 1]->dtc |= PHY_TO_DESC_DOA(sdesc->hw_desc_dma[i]); ++ } ++ } ++ sdesc->hw_desc[i - 1]->dcm |= DCM_TIE; ++ ++#ifdef CONFIG_INGENIC_DMA_RECEIVE_DXTERNAL_DECIDE ++ ingenic_dma_use_external_trigger(chan, sdesc, sg_len); ++#endif ++ /* use 8-word descriptors */ ++ sdesc->dcs = DCS_DES8; ++ ++ return vchan_tx_prep(&dmac->vc, &sdesc->vd, flags); ++} ++ ++static struct dma_async_tx_descriptor *ingenic_dma_prep_dma_cyclic( ++ struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, ++ size_t period_len, enum dma_transfer_direction direction, ++ unsigned long flags) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ unsigned int periods = buf_len / period_len; ++ struct ingenic_dma_sdesc *sdesc; ++ int i; ++ ++ sdesc = ingenic_dma_alloc_swdesc(dmac, periods); ++ if (!sdesc) ++ return NULL; ++ ++ for (i = 0; i < periods; i++) { ++ sdesc->len += build_one_slave_desc(dmac, buf_addr + (i * period_len), ++ period_len, direction, sdesc->hw_desc[i]); ++ if (i) { ++ sdesc->hw_desc[i - 1]->dcm |= DCM_LINK | DCM_TIE; ++ sdesc->hw_desc[i - 1]->dtc |= PHY_TO_DESC_DOA(sdesc->hw_desc_dma[i]); ++ } ++ } ++ ++#ifdef CONFIG_INGENIC_DMA_RECEIVE_DXTERNAL_DECIDE ++ ingenic_dma_use_external_trigger(chan, sdesc, periods); ++#endif ++ /*make it cyclic*/ ++ sdesc->hw_desc[i - 1]->dcm |= DCM_LINK | DCM_TIE; ++ sdesc->hw_desc[i - 1]->dtc |= PHY_TO_DESC_DOA(sdesc->hw_desc_dma[0]); ++ sdesc->cyclic = true; ++ ++ /* use 8-word descriptors */ ++ sdesc->dcs = DCS_DES8; ++ ++ return vchan_tx_prep(&dmac->vc, &sdesc->vd, flags); ++} ++ ++static struct dma_async_tx_descriptor *ingenic_dma_prep_dma_memcpy(struct dma_chan *chan, ++ dma_addr_t dma_dest, ++ dma_addr_t dma_src, ++ size_t len, ++ unsigned long flags) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ struct ingenic_dma_sdesc *sdesc; ++ ++ sdesc = ingenic_dma_alloc_swdesc(dmac, 1); ++ if (!sdesc) ++ return NULL; ++ ++ sdesc->len = build_one_desc(dma_src, dma_dest, len, sdesc->hw_desc[0]); ++ sdesc->hw_desc[0]->dcm |= DCM_TIE; ++ ++ /* use 8-word descriptors */ ++ sdesc->dcs = DCS_DES8; ++ ++ return vchan_tx_prep(&dmac->vc, &sdesc->vd, flags); ++} ++ ++static int build_dma_sg_desc(struct ingenic_dma_sdesc *sdesc, ++ struct scatterlist *dst_sg, unsigned int dst_nents, ++ struct scatterlist *src_sg, unsigned int src_nents) ++{ ++ int src_sg_avail = 0; ++ int dst_sg_avail = 0; ++ int size; ++ dma_addr_t src_addr; ++ dma_addr_t dst_addr; ++ int i = 0; ++ ++ src_nents--; ++ dst_nents--; ++ dst_sg_avail = sg_dma_len(src_sg); ++ src_sg_avail = sg_dma_len(dst_sg); ++ while (true) { ++ src_addr = sg_dma_address(src_sg) + sg_dma_len(src_sg) - src_sg_avail; ++ dst_addr = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - dst_sg_avail; ++ ++ size = min(src_sg_avail, dst_sg_avail); ++ size = min(size, (DTC_TC_MSK & (~0x3))); ++ ++ if (NULL != sdesc) { ++ sdesc->len += build_one_desc(src_addr, dst_addr, size, sdesc->hw_desc[i]); ++ if (i) { ++ sdesc->hw_desc[i - 1]->dcm |= DCM_LINK; ++ sdesc->hw_desc[i - 1]->dtc |= PHY_TO_DESC_DOA(sdesc->hw_desc_dma[i]); ++ } ++ } ++ ++ dst_sg_avail -= size; ++ src_sg_avail -= size; ++ ++ if (0 == src_sg_avail) { ++ if (0 == src_nents) ++ break; ++ src_sg = sg_next(src_sg); ++ src_sg_avail = sg_dma_len(src_sg); ++ src_nents--; ++ } ++ ++ if (0 == dst_sg_avail) { ++ if (0 == dst_nents) ++ break; ++ dst_sg = sg_next(dst_sg); ++ dst_sg_avail = sg_dma_len(dst_sg); ++ dst_nents--; ++ } ++ i++; ++ } ++ if (sdesc) ++ sdesc->hw_desc[i]->dcm |= DCM_TIE; ++ return ++i; ++} ++ ++static struct dma_async_tx_descriptor* ingenic_dma_prep_dma_sg( ++ struct dma_chan *chan, ++ struct scatterlist *dst_sg, unsigned int dst_nents, ++ struct scatterlist *src_sg, unsigned int src_nents, ++ unsigned long flags) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ struct ingenic_dma_sdesc *sdesc; ++ int hw_nums; ++ ++ if (0 == dst_nents || 0 == src_nents) ++ return NULL; ++ ++ if (NULL == dst_sg || NULL == src_sg) ++ return NULL; ++ ++ hw_nums = build_dma_sg_desc(NULL, dst_sg, dst_nents, src_sg, src_nents); ++ ++ sdesc = ingenic_dma_alloc_swdesc(dmac, hw_nums); ++ if (!sdesc) ++ return NULL; ++ ++ build_dma_sg_desc(sdesc, dst_sg, dst_nents, src_sg, src_nents); ++ ++ /* use 8-word descriptors */ ++ sdesc->dcs = DCS_DES8; ++ ++ return vchan_tx_prep(&dmac->vc, &sdesc->vd, flags); ++} ++ ++static size_t ingenic_dma_desc_residue(struct ingenic_dma_chan *dmac, struct ingenic_dma_sdesc *sdesc) ++{ ++ unsigned int residue = 0, shift, pass = 0; ++ unsigned int i; ++ bool dsa = false; ++ dma_addr_t start, end, compare; ++ ++ if (sdesc->hw_desc[0]->dcm & DCM_SAI) { ++ compare = readl(dmac->iomem + CH_DSA); ++ dsa = true; ++ } else { ++ compare = readl(dmac->iomem + CH_DTA); ++ } ++ ++ for (i = 0; i < sdesc->nb_desc; i++) { ++ start = dsa ? sdesc->hw_desc[i]->dsa : sdesc->hw_desc[i]->dta; ++ shift = get_current_tsz(sdesc->hw_desc[i]->dcm); ++ end = start + (sdesc->hw_desc[i]->dtc << shift); ++ if (start <= compare && end > compare) { ++ pass += (compare - start); ++ break; ++ } else { ++ pass += sdesc->hw_desc[i]->dtc << shift; ++ } ++ } ++ ++ residue = sdesc->len - pass; ++ return residue; ++} ++ ++static enum dma_status ingenic_dma_tx_status(struct dma_chan *chan, ++ dma_cookie_t cookie, ++ struct dma_tx_state *txstate) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ struct virt_dma_desc *vd; ++ enum dma_status status; ++ unsigned long flags; ++ ++ status = dma_cookie_status(chan, cookie, txstate); ++ if ((status == DMA_COMPLETE) || (txstate == NULL)) ++ return status; ++ ++ spin_lock_irqsave(&dmac->vc.lock, flags); ++ ++ vd = vchan_find_desc(&dmac->vc, cookie); ++ if (vd) { ++ dma_set_residue(txstate, to_ingenic_dma_sdesc(vd)->len); ++ } else if (dmac->sdesc && cookie == dmac->sdesc->vd.tx.cookie) { ++ dma_set_residue(txstate, ingenic_dma_desc_residue(dmac, dmac->sdesc)); ++ } else ++ dma_set_residue(txstate, 0); ++ ++ spin_unlock_irqrestore(&dmac->vc.lock, flags); ++ return status; ++} ++ ++static void ingenic_dma_start_trans(struct ingenic_dma_chan *dmac) ++{ ++ static struct virt_dma_desc *vd = NULL; ++ struct ingenic_dma_sdesc *sdesc; ++ int i; ++ ++ if (!dmac->sdesc) { ++ vd = vchan_next_desc(&dmac->vc); ++ if (!vd) ++ return; ++ ++ list_del(&vd->node); ++ ++ sdesc = dmac->sdesc = to_ingenic_dma_sdesc(vd); ++ ++ if (dmac->fake_cyclic && sdesc->cyclic && vd->tx.callback) { ++ /* ++ * The DMA controller doesn't support triggering an interrupt ++ * after processing each descriptor, only after processing an ++ * entire terminated list of descriptors.For a cyclic DMA ++ * setup the list of descriptors is not terminated so we can ++ * never get an interrupt. ++ * ++ * If the user requested a callback for a cyclic DMA setup then ++ * we workaround this hardware limitation here by degrading to ++ * a set of unlinked descriptors which we will submit in ++ * sequence in response to the completion of processing the ++ * previous descriptor ++ */ ++ for (i = 0; i < sdesc->nb_desc; i++) { ++ sdesc->hw_desc[i]->dcm &= ~DCM_LINK; ++ } ++ } ++ ++ for (i = 0; i < sdesc->nb_desc; i++) { ++ int j; ++ uint32_t *vaddr = (void *)sdesc->hw_desc[i]; ++ for (j = 0; j < 8; j++) { ++ pr_debug("<%d>: &vaddr[0] %p vaddr[0] %x\n",i, &vaddr[j], vaddr[j]); ++ } ++ pr_debug("sdesc->hw_desc_dma[0] 0x%08x dmac->iomem %p\n", sdesc->hw_desc_dma[i], dmac->iomem); ++ } ++ ++ sdesc->curr_desc = 0; ++ sdesc->status = STAT_RUNNING; ++ } else { ++ sdesc = dmac->sdesc; ++ WARN_ON_ONCE((!sdesc->cyclic)); ++ WARN_ON_ONCE((!vd->tx.callback)); ++ WARN_ON_ONCE((!dmac->fake_cyclic)); ++ sdesc->status = STAT_RUNNING; ++ sdesc->curr_desc++; ++ sdesc->curr_desc = sdesc->curr_desc % sdesc->nb_desc; ++ } ++ ++ /* dump_dma_hdesc(sdesc->hw_desc[sdesc->curr_desc], __func__); */ ++ /* dma descriptor address */ ++ writel(sdesc->hw_desc_dma[sdesc->curr_desc], dmac->iomem + CH_DDA); ++ /* initiate descriptor fetch */ ++ writel(BIT(dmac->id), dmac->engine->iomem + DDRS); ++ /* transfer start */ ++ dev_dbg(chan2dev(&dmac->vc.chan), "dcs:%x start transfer\n", ++ readl(dmac->iomem + CH_DCS)); ++ ++ writel(sdesc->dcs | DCS_CTE, dmac->iomem + CH_DCS); ++ return; ++} ++ ++static void ingenic_dma_issue_pending(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dmac->vc.lock, flags); ++ ++ if (vchan_issue_pending(&dmac->vc) && !dmac->sdesc) ++ ingenic_dma_start_trans(dmac); ++ ++ spin_unlock_irqrestore(&dmac->vc.lock, flags); ++} ++ ++#ifdef AIC_USES_PDMA ++/* ++ * get dma current transfer address ++ */ ++static dma_addr_t jzdma_get_current_trans_addr(struct dma_chan *chan, ++ dma_addr_t * dst_addr, ++ dma_addr_t * src_addr, ++ enum dma_transfer_direction ++ direction) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ dma_addr_t ret_val = 0; ++ ++ if(!dmac->sdesc) ++ return 0; ++ if (dmac->sdesc->status == STAT_STOPPED) ++ return 0; ++ ++ if (direction == DMA_MEM_TO_DEV) { ++ ret_val = readl(dmac->iomem + CH_DSA); ++ if (src_addr) ++ *src_addr = ret_val; ++ if (dst_addr) ++ *dst_addr = readl(dmac->iomem + CH_DTA); ++ } else if (direction == DMA_DEV_TO_MEM) { ++ ret_val = readl(dmac->iomem + CH_DTA); ++ if (dst_addr) ++ *dst_addr = ret_val; ++ if (src_addr) ++ *src_addr = readl(dmac->iomem + CH_DSA); ++ } else if (direction == DMA_MEM_TO_MEM) { ++ if (dst_addr) ++ *dst_addr = readl(dmac->iomem + CH_DTA); ++ if (src_addr) ++ *src_addr = readl(dmac->iomem + CH_DSA); ++ } ++ ++ return ret_val; ++} ++#endif ++ ++static int ingenic_dma_terminate_all(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ unsigned long flags; ++ int ret = 0; ++ LIST_HEAD(head); ++ ++ spin_lock_irqsave(&dmac->vc.lock, flags); ++#ifdef AIC_USES_PDMA ++ /* the part handler audio driver */ ++ if(dmac->slave_id == INGENIC_DMA_REQ_AIC_LOOP_RX || dmac->slave_id == INGENIC_DMA_REQ_AIC_TX || dmac->slave_id == INGENIC_DMA_REQ_ASOC_AIC_RX ++ || dmac->slave_id == INGENIC_DMA_REQ_ASOC_AIC_TX || dmac->slave_id == INGENIC_DMA_REQ_AIC_F_RX || dmac->slave_id == INGENIC_DMA_REQ_DMIC_RX) ++ { ++ if (dmac->sdesc) { /*DMA transfer is running*/ ++ if (dmac->sdesc->status != STAT_STOPPED) { ++ dmac->sdesc->status = STAT_STOPPED; ++ writel(0, dmac->iomem + CH_DCS); ++ } ++ ingenic_dma_free_swdesc(&dmac->sdesc->vd); ++ dmac->sdesc = NULL; ++ } ++ ++// printk("%s[%d]: pdma%d\n",__func__,__LINE__,dmac->slave_id); ++ goto done; ++ } ++#endif ++ if (dmac->sdesc) { /*DMA transfer is running*/ ++ int i; ++ ret = -EBUSY; ++ if (dmac->sdesc->status != STAT_STOPPED) { ++ dmac->sdesc->status = STAT_STOPPED; ++ reinit_completion(&dmac->completion); ++ ++ for (i = 0; i < dmac->sdesc->nb_desc; i++) { ++ dmac->sdesc->hw_desc[i]->dcm |= DCM_TIE; ++ dmac->sdesc->hw_desc[i]->dcm &= ~DCM_LINK; ++ } ++ ++ if (HWATTR_DESC_INTER_SUP(dmac->engine->hwattr)) { ++ /* ++ * The version of controller support descriptor interrupt ++ * can clear LINK on runtime ++ */ ++ unsigned int dcm = readl(dmac->iomem + CH_DCM); ++ if (dcm & DCM_LINK) { ++ dcm &= ~DCM_LINK; ++ writel(dcm, dmac->iomem + CH_DCM); ++ } ++ } ++ } else if (readl(dmac->iomem + CH_DRT) != INGENIC_DMA_REQ_AUTO_TX) { ++ writel(0, dmac->iomem + CH_DCS); ++ ingenic_dma_free_swdesc(&dmac->sdesc->vd); ++ dmac->sdesc = NULL; ++ complete(&dmac->completion); ++ ret = 0; /*DMA transfer force stop !!!!!*/ ++ } ++ } else { /*DMA transfer already stoped*/ ++ writel(0, dmac->iomem + CH_DCS); ++ } ++done: ++ vchan_get_all_descriptors(&dmac->vc, &head); ++ ++ spin_unlock_irqrestore(&dmac->vc.lock, flags); ++ ++ vchan_dma_desc_free_list(&dmac->vc, &head); ++ ++ return ret; ++} ++ ++static int ingenic_dma_wait_terminate_complete(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ ++ if (dmac->sdesc) ++ wait_for_completion(&dmac->completion); ++ return 0; ++} ++ ++static int ingenic_dma_config(struct dma_chan *chan, struct dma_slave_config *config) ++{ ++ struct ingenic_dma_chan* dmac = to_ingenic_dma_chan(chan); ++ enum dma_slave_buswidth transfer_width; ++ ++ if (!config) ++ return -EINVAL; ++ ++ switch (config->direction) { ++ case DMA_MEM_TO_DEV: ++ if (!config->dst_addr_width || !config->dst_addr) ++ return -EINVAL; ++ if (!config->dst_maxburst) ++ config->dst_maxburst = 1; ++ transfer_width = config->dst_addr_width; ++ dmac->slave_addr = config->dst_addr; ++ dmac->maxburst = config->dst_maxburst; ++ break; ++ case DMA_DEV_TO_MEM: ++ if (!config->src_addr_width || !config->src_addr) ++ return -EINVAL; ++ if (!config->src_maxburst) ++ config->src_maxburst = 1; ++ transfer_width = config->src_addr_width; ++ dmac->slave_addr = config->src_addr; ++ dmac->maxburst = config->src_maxburst; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (transfer_width) { ++ case DMA_SLAVE_BUSWIDTH_1_BYTE: ++ dmac->dcm = DCM_PORT_8; ++ dmac->transfer_width = 1; ++ break; ++ case DMA_SLAVE_BUSWIDTH_2_BYTES: ++ dmac->dcm = DCM_PORT_16; ++ dmac->transfer_width = 2; ++ break; ++ case DMA_SLAVE_BUSWIDTH_4_BYTES: ++ dmac->dcm = DCM_PORT_32; ++ dmac->transfer_width = 4; ++ break; ++ default: ++ return -EINVAL; ++ } ++#ifndef CONFIG_SOC_X2500 ++ if (config->slave_id & INGENIC_DMA_TYPE_REQ_MSK) ++ dmac->slave_id = config->slave_id & INGENIC_DMA_TYPE_REQ_MSK; ++#endif ++ return 0; ++} ++ ++static void pdma_handle_chan_irq(struct ingenic_dma_engine *ingenic_dma, int ch_id) ++{ ++ struct ingenic_dma_chan *dmac = ingenic_dma->chan[ch_id]; ++ struct ingenic_dma_sdesc *sdesc; ++ unsigned int dcs; ++ ++ spin_lock(&dmac->vc.lock); ++ ++ dcs = readl(dmac->iomem + CH_DCS); ++ writel(0, dmac->iomem + CH_DCS); ++ ++ if (dcs & DCS_AR) ++ dev_warn(&dmac->vc.chan.dev->device, ++ "address error (DCS=0x%x)\n", dcs); ++ ++ if (dcs & DCS_HLT) ++ dev_warn(&dmac->vc.chan.dev->device, ++ "channel halt (DCS=0x%x)\n", dcs); ++ sdesc = dmac->sdesc; ++ if (sdesc) { ++ if (sdesc->status == STAT_STOPPED) { ++ dma_cookie_complete(&sdesc->vd.tx); ++ dmac->sdesc = NULL; ++ ingenic_dma_free_swdesc(&sdesc->vd); ++ complete(&dmac->completion); ++ } else if (dmac->fake_cyclic && sdesc->cyclic) { ++ vchan_cyclic_callback(&sdesc->vd); ++ } else { ++ vchan_cookie_complete(&sdesc->vd); ++ dmac->sdesc = NULL; ++ } ++ ingenic_dma_start_trans(dmac); ++ } else { ++ dev_warn(&dmac->vc.chan.dev->device, ++ "channel irq with no active transfer, channel stop\n"); ++ } ++ ++ spin_unlock(&dmac->vc.lock); ++} ++ ++static irqreturn_t pdma_int_handler(int irq, void *dev) ++{ ++ struct ingenic_dma_engine *ingenic_dma = (struct ingenic_dma_engine *)dev; ++ unsigned long pending, dmac; ++ int i; ++ ++ pending = readl(ingenic_dma->iomem + DIRQP); ++ writel(~pending, ingenic_dma->iomem + DIRQP); ++ ++ for (i = 0; i < ingenic_dma->nr_chs ; i++) { ++ if (!(pending & (1 << i))) ++ continue; ++ pdma_handle_chan_irq(ingenic_dma, i); ++ } ++ ++ dmac = readl(ingenic_dma->iomem + DMAC); ++ dmac &= ~(DMAC_HLT | DMAC_AR); ++ writel(dmac, ingenic_dma->iomem + DMAC); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t pdmam_int_handler(int irq, void *dev) ++{ ++ /*TODO*/ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t pdmad_int_handler(int irq, void *dev) ++{ ++ struct ingenic_dma_engine *ingenic_dma = (struct ingenic_dma_engine *)dev; ++ unsigned long pending; ++ int i; ++ ++ pending = readl(ingenic_dma->iomem + DIP); ++ writel(readl(ingenic_dma->iomem + DIP) & (~pending), ingenic_dma->iomem + DIC); ++ ++ for (i = 0; i < ingenic_dma->nr_chs; i++) { ++ struct ingenic_dma_chan *dmac = ingenic_dma->chan[i]; ++ struct ingenic_dma_sdesc *sdesc; ++ ++ if (!(pending & (1 << i))) ++ continue; ++ sdesc = dmac->sdesc; ++ if (sdesc && sdesc->cyclic) { ++ spin_lock(&dmac->vc.lock); ++ vchan_cyclic_callback(&sdesc->vd); ++ spin_unlock(&dmac->vc.lock); ++ } ++ } ++ return IRQ_HANDLED; ++ ++} ++ ++static int ingenic_dma_alloc_chan_resources(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ ++ dmac->hdesc_pool = dma_pool_create(dev_name(&chan->dev->device), ++ chan->device->dev, ++ sizeof(struct hdma_desc), ++ 0, PAGE_SIZE); ++ if (!dmac->hdesc_pool) { ++ dev_err(&chan->dev->device, ++ "failed to allocate descriptor pool\n"); ++ return -ENOMEM; ++ } ++ dmac->hdesc_max = PAGE_SIZE / sizeof(struct hdma_desc); ++ dmac->hdesc_num = 0; ++ return 0; ++} ++ ++static void ingenic_dma_free_chan_resources(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ unsigned long flags; ++ ++ ingenic_dma_terminate_all(chan); ++ ++ ingenic_dma_wait_terminate_complete(chan); ++ ++ spin_lock_irqsave(&dmac->hdesc_lock, flags); ++ dma_pool_destroy(dmac->hdesc_pool); ++ dmac->hdesc_pool = NULL; ++ dmac->hdesc_max = 0; ++ dmac->hdesc_num = 0; ++ spin_unlock_irqrestore(&dmac->hdesc_lock, flags); ++} ++ ++static bool ingenic_dma_filter_fn(struct dma_chan *chan, void *param) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ unsigned int private = *(unsigned int *)param; ++ int channel = -1; ++ ++ if (private & INGENIC_DMA_TYPE_CH_EN) { ++ channel = (private & INGENIC_DMA_TYPE_CH_MSK) >> INGENIC_DMA_TYPE_CH_SFT; ++ if (dmac->id == channel) ++ return true; ++ return false; ++ } ++ ++ if (dmac->engine->chan_reserved & BIT(dmac->id)) ++ return false; ++ ++ dmac->slave_id = private & INGENIC_DMA_TYPE_REQ_MSK; ++ return true; ++} ++ ++static struct of_dma_filter_info of_ingenic_dma_info = { ++ .filter_fn = ingenic_dma_filter_fn, ++}; ++ ++static int ingenic_dma_chan_init(struct ingenic_dma_engine *dma, int id) ++{ ++ struct ingenic_dma_chan *dmac = NULL; ++ ++ dmac = devm_kzalloc(dma->dev, sizeof(*dmac), GFP_KERNEL); ++ if (!dmac) ++ return -ENOMEM; ++ dmac->id = id; ++ dmac->iomem = dma->iomem + dmac->id * DMACH_OFF; ++ dmac->engine = dma; ++ dmac->fake_cyclic = HWATTR_DESC_INTER_SUP(dma->hwattr) ? false : true; ++ spin_lock_init(&dmac->hdesc_lock); ++ init_completion(&dmac->completion); ++ ++ vchan_init(&dmac->vc, &dma->dma_device); ++ ++ dmac->vc.desc_free = ingenic_dma_free_swdesc; ++#ifdef CONFIG_SOC_X2500 ++ dmac->vc.chan.private = (void*)pdma_maps[id]; ++ dmac->slave_id = pdma_maps[id] & INGENIC_DMA_TYPE_REQ_MSK; ++#endif ++ dma->chan[id] = dmac; ++ return 0; ++} ++ ++static int __init ingenic_dma_probe(struct platform_device *pdev) ++{ ++ struct ingenic_dma_engine *dma = NULL; ++ struct resource *iores; ++ u32 reg_dmac = DMAC_DMAE; ++ int i, ret = 0; ++ ++ /* check of first. if of failed, use platform */ ++ dma = ingenic_dma_parse_dt(pdev); ++ if (IS_ERR(dma)) ++ return PTR_ERR(dma); ++ ++ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ dma->iomem = devm_ioremap_resource(&pdev->dev, iores); ++ if (IS_ERR(dma->iomem)) ++ return PTR_ERR(dma->iomem); ++ ++ /* PDMA interrupt*/ ++ dma->irq_pdma = platform_get_irq_byname(pdev, "pdma"); ++ if (dma->irq_pdma < 0) ++ return dma->irq_pdma; ++ ret = devm_request_irq(&pdev->dev, dma->irq_pdma, pdma_int_handler, ++ 0, "pdma", dma); ++ if (ret) ++ return ret; ++ ++ /* PDMA mcu interrupt*/ ++ dma->irq_pdmam = platform_get_irq_byname(pdev, "pdmam"); ++ if (dma->irq_pdmam >= 0) { ++ ret = devm_request_irq(&pdev->dev, dma->irq_pdmam, pdmam_int_handler, ++ 0, "pdmam", dma); ++ if (ret) ++ return ret; ++ } ++ ++ /* PDMA descriptor interrupt */ ++ if (HWATTR_DESC_INTER_SUP(dma->hwattr)) { ++ dma->irq_pdmad = platform_get_irq_byname(pdev, "pdmad"); ++ if (dma->irq_pdmad < 0) ++ return dma->irq_pdmad; ++ ret = devm_request_irq(&pdev->dev, dma->irq_pdmad, pdmad_int_handler, ++ 0, "pdmad", dma); ++ if (ret) ++ return ret; ++ irq_set_irq_wake(dma->irq_pdmad, 1); ++ } ++ ++ /* Initialize dma engine */ ++ INIT_LIST_HEAD(&dma->dma_device.channels); ++ for (i = 0; i < dma->nr_chs; i++ ) { ++ /*reserved one channel for intc interrupt*/ ++ if (dma->intc_ch == i) ++ continue; ++ ingenic_dma_chan_init(dma, i); ++ } ++ dma_cap_set(DMA_MEMCPY, dma->dma_device.cap_mask); ++ dma_cap_set(DMA_SLAVE, dma->dma_device.cap_mask); ++ dma_cap_set(DMA_CYCLIC, dma->dma_device.cap_mask); ++ ++ dma->dma_device.dev = &pdev->dev; ++ dma->dma_device.device_alloc_chan_resources = ingenic_dma_alloc_chan_resources; ++ dma->dma_device.device_free_chan_resources = ingenic_dma_free_chan_resources; ++ dma->dma_device.device_tx_status = ingenic_dma_tx_status; ++ dma->dma_device.device_prep_slave_sg = ingenic_dma_prep_slave_sg; ++ dma->dma_device.device_prep_dma_cyclic = ingenic_dma_prep_dma_cyclic; ++ dma->dma_device.device_prep_dma_memcpy = ingenic_dma_prep_dma_memcpy; ++ dma->dma_device.device_config = ingenic_dma_config; ++ dma->dma_device.device_terminate_all = ingenic_dma_terminate_all; ++ dma->dma_device.device_issue_pending = ingenic_dma_issue_pending; ++ dma->dma_device.copy_align = DMAENGINE_ALIGN_4_BYTES; ++ dma->dma_device.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) ++ | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); ++ dma->dma_device.dst_addr_widths = dma->dma_device.src_addr_widths; ++ dma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | BIT(DMA_MEM_TO_MEM); ++ dma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; ++ dma->dma_device.dev->dma_parms = &dma->dma_parms; ++ dma_set_max_seg_size(dma->dma_device.dev, DTC_TC_MSK); /*At least*/ ++ ++#ifdef AIC_USES_PDMA ++ dma->dma_device.get_current_trans_addr = jzdma_get_current_trans_addr; ++#endif ++ ++ dma->gate_clk = devm_clk_get(&pdev->dev, "gate_pdma"); ++ if (IS_ERR(dma->gate_clk)) ++ return PTR_ERR(dma->gate_clk); ++ ++ ret = dma_async_device_register(&dma->dma_device); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to register\n"); ++ clk_disable(dma->gate_clk); ++ return ret; ++ } ++ ++ of_ingenic_dma_info.dma_cap = dma->dma_device.cap_mask; ++ ret = of_dma_controller_register(pdev->dev.of_node, ++ of_dma_simple_xlate, &of_ingenic_dma_info); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to register dma to device tree\n"); ++ dma_async_device_unregister(&dma->dma_device); ++ clk_disable(dma->gate_clk); ++ return ret; ++ } ++ platform_set_drvdata(pdev, dma); ++ ++ /*enable pdma controller*/ ++ clk_prepare_enable(dma->gate_clk); ++ ++ if (dma->chan_programed) ++ writel(dma->chan_programed, dma->iomem + DMACP); ++ if (dma->intc_ch >= 0) ++ reg_dmac |= DMAC_INTCE | ((dma->intc_ch << DMAC_INTCC_SFT) & DMAC_INTCC_MSK); ++ if (dma->special_ch) ++ reg_dmac |= DMAC_CH01; ++ writel(reg_dmac, dma->iomem + DMAC); ++ dev_info(dma->dev, "INGENIC SoC DMA initialized\n"); ++ return 0; ++} ++ ++static int ingenic_dma_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct ingenic_dma_engine *ingenic_dma = platform_get_drvdata(pdev); ++ struct dma_chan *chan; ++ ++ list_for_each_entry(chan, &ingenic_dma->dma_device.channels, device_node) { ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ struct ingenic_dma_sdesc *sdesc = dmac->sdesc; ++ ++ if (sdesc && (sdesc->hw_desc[0]->drt != INGENIC_DMA_REQ_UART0_RX) && ++ (sdesc->hw_desc[0]->drt != INGENIC_DMA_REQ_UART1_RX) && ++ (sdesc->hw_desc[0]->drt != INGENIC_DMA_REQ_UART2_RX) && ++ (sdesc->hw_desc[0]->drt != INGENIC_DMA_REQ_UART3_RX) && ++ (sdesc->hw_desc[0]->drt != INGENIC_DMA_REQ_CAN0_RX) && ++ (sdesc->hw_desc[0]->drt != INGENIC_DMA_REQ_CAN1_RX)) { ++ return -EBUSY; ++ } ++ } ++ clk_disable_unprepare(ingenic_dma->gate_clk); ++ return 0; ++} ++ ++static int ingenic_dma_resume(struct platform_device * pdev) ++{ ++ struct ingenic_dma_engine *ingenic_dma = platform_get_drvdata(pdev); ++ clk_prepare_enable(ingenic_dma->gate_clk); ++ return 0; ++} ++ ++static const struct of_device_id ingenic_dma_dt_match[] = { ++ { .compatible = "ingenic,m200-pdma", .data = (void *)(HWATTR_SPECIAL_CH01|HWATTR_INTC_IRQ)}, ++ { .compatible = "ingenic,x1000-pdma", .data = (void *)HWATTR_DESC_INTER}, ++ { .compatible = "ingenic,x1021-pdma", .data = (void *)HWATTR_DESC_INTER}, ++ { .compatible = "ingenic,x1520-pdma", .data = (void *)HWATTR_DESC_INTER}, ++ { .compatible = "ingenic,x1630-pdma", .data = (void *)HWATTR_DESC_INTER}, ++ { .compatible = "ingenic,x2000-pdma", .data = (void *)HWATTR_DESC_INTER}, ++ { .compatible = "ingenic,x2500-pdma", .data = (void *)HWATTR_INTC_IRQ}, ++ { .compatible = "ingenic,m300-pdma", .data = (void *)HWATTR_DESC_INTER}, ++ { .compatible = "ingenic,x1600-pdma", .data = (void *)HWATTR_DESC_INTER}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_dma_dt_match); ++ ++static struct platform_driver ingenic_dma_driver = { ++ .driver = { ++ .name = "ingenic-dma", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_dma_dt_match), ++ }, ++ .suspend = ingenic_dma_suspend, ++ .resume = ingenic_dma_resume, ++}; ++ ++static int __init ingenic_dma_module_init(void) ++{ ++ return platform_driver_probe(&ingenic_dma_driver, ingenic_dma_probe); ++} ++subsys_initcall(ingenic_dma_module_init); ++MODULE_AUTHOR("Chen.li "); ++MODULE_DESCRIPTION("Ingenic dma driver"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/dma/ingenic/ingenic_dma.h b/module_drivers/drivers/dma/ingenic/ingenic_dma.h +new file mode 100644 +index 000000000..56c66f74f +--- /dev/null ++++ b/module_drivers/drivers/dma/ingenic/ingenic_dma.h +@@ -0,0 +1,253 @@ ++/* ++ * Copyright (C) 2016 Ingenic Semiconductor Co., Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++ ++#ifndef __INGENIC_DMA_H__ ++#define __INGENIC_DMA_H__ ++#include ++#include "virt-dma.h" ++#include "dmaengine.h" ++#define CH_DSA 0x00 ++#define CH_DTA 0x04 ++#define CH_DTC 0x08 ++#define CH_DRT 0x0C ++#define CH_DCS 0x10 ++#define CH_DCM 0x14 ++#define CH_DDA 0x18 ++#define CH_DSD 0x1C ++ ++#define TCSM 0x2000 ++ ++#define DMAC 0x1000 ++#define DIRQP 0x1004 ++#define DDR 0x1008 ++#define DDRS 0x100C ++#define DIP 0x1010 ++#define DIC 0x1014 ++#define DMACP 0x101C ++#define DSIRQP 0x1020 ++#define DSIRQM 0x1024 ++#define DCIRQP 0x1028 ++#define DCIRQM 0x102C ++#define DSN0 0x1060 ++#define DSN1 0x1064 ++#define DSCIDX0 0x1068 ++#define DSCIDX1 0x106C ++ ++#define DMACH_OFF 0x20 ++/* DCS */ ++#define DCS_NDES BIT(31) ++#define DCS_DES8 BIT(30) ++#define DCS_CDOA_SFT 8 ++#define DCS_CDOA_MSK (0xff << DCS_CDOA_SFT) ++#define DCS_AR BIT(4) ++#define DCS_TT BIT(3) ++#define DCS_HLT BIT(2) ++#define DCS_CTE BIT(0) ++ ++/* DTC */ ++#define DTC_TC_SFT 0 ++#define DTC_TC_MSK 0xffffff ++ ++/* DCM */ ++#define DCM_SAI BIT(23) ++#define DCM_DAI BIT(22) ++#define DCM_SAIW BIT(21) ++#define DCM_DAIW BIT(20) ++#define DCM_PORT_MSK (0xf << 12) ++#define DCM_PORT_8 (0x1 << 14 | 0x1 <<12) ++#define DCM_PORT_16 (0x2 << 14 | 0x2 <<12) ++#define DCM_PORT_32 (0x0 << 14 | 0x0 <<12) ++#define DCM_RDIL_SFT 16 ++#define DCM_RDIL_MAX 0x9 ++#define DCM_RDIL_MSK (0xf << DCM_RDIL_SFT) ++#define DCM_TSZ_SFT 8 ++#define DCM_TSZ_AUTO 0x7 ++#define DCM_TSZ_MSK (0x7 << DCM_TSZ_SFT) ++#define DCM_TSZ_EXTR (0x8 << DCM_TSZ_SFT) ++#define DCM_STDE BIT(2) ++#define DCM_TIE BIT(1) ++#define DCM_LINK BIT(0) ++ ++/* DDA */ ++#define DDA_DBA_SFT 12 ++#define DDA_DBA_MSK (0xfffff << DDA_DBA_SFT) ++#define DDA_DOA_SFT 4 ++#define DDA_DOA_MSK (0xff << DDA_DOA_SFT) ++#define PHY_TO_DESC_DOA(dma) ((((dma) & DDA_DOA_MSK) >> DDA_DOA_SFT) << 24) ++ ++/* DSD */ ++#define DSD_TSD_SFT 16 ++#define DSD_TSD_MSK (0xffff << DSD_TSD_SFT) ++#define DSD_SSD_SFT 0 ++#define DSD_SSD_MSK (0xffff << DSD_SSD_SFT) ++ ++/* DMAC */ ++#define DMAC_FMSC BIT(31) ++#define DMAC_FSSI BIT(30) ++#define DMAC_FTSSI BIT(29) ++#define DMAC_FUART BIT(28) ++#define DMAC_FAIC BIT(27) ++#define DMAC_INTCC_SFT 17 ++#define DMAC_INTCC_MSK (0x1f << 17) ++#define DMAC_INTCE BIT(16) ++#define DMAC_HLT BIT(3) ++#define DMAC_AR BIT(2) ++#define DMAC_CH01 BIT(1) ++#define DMAC_DMAE BIT(0) ++ ++/* MCU of PDMA */ ++#define DMCS 0x1030 ++#define DMNMB 0x1034 ++#define DMSMB 0x1038 ++#define DMINT 0x103C ++ ++/* MCU of PDMA */ ++#define DMINT_S_IP BIT(17) ++#define DMINT_N_IP BIT(16) ++ ++#define DMA_SPECAIL_CHS 0x3 /*Channel 0 & 1*/ ++ ++ ++/*8-word hardware dma descriptor*/ ++struct hdma_desc { ++ unsigned long dcm; ++ dma_addr_t dsa; ++ dma_addr_t dta; ++ unsigned long dtc; ++ unsigned long sd; ++ unsigned long drt; ++ unsigned long reserved[2]; ++}; ++ ++enum sdesc_status { ++ STAT_STOPPED = 0, STAT_RUNNING, STAT_ERROR ++}; ++ ++struct ingenic_dma_chan; ++struct ingenic_dma_sdesc { ++ struct virt_dma_desc vd; /* Virtual descriptor */ ++ int nb_desc; /* Number of hw. descriptors */ ++ size_t len; /* Number of bytes xfered */ ++ bool cyclic; ++ struct hdma_desc **hw_desc; /* DMA coherent descriptors */ ++ dma_addr_t *hw_desc_dma; /* DMA address of the Descriptors*/ ++ struct ingenic_dma_chan *dmac; /* for free*/ ++ int dcs; /* The DCS initial value */ ++ int curr_desc; ++ enum sdesc_status status; ++}; ++ ++struct ingenic_dma_chan { ++ struct virt_dma_chan vc; /* Virtual channel */ ++ int id; /* Channel id*/ ++ void __iomem *iomem; ++ struct ingenic_dma_engine *engine; ++ bool fake_cyclic; ++ ++ /*dma slave channel config*/ ++ unsigned int slave_id; /* Request type of the channel */ ++ enum dma_transfer_direction direction; ++ dma_addr_t slave_addr; ++ unsigned int maxburst; ++ unsigned int transfer_width; ++ unsigned int fast_mode; /* The fast mode bit of dmac*/ ++ unsigned int dcm; /* The DCM of HW Descriptor initial value*/ ++ ++ ++ /*Descriptors*/ ++ struct dma_pool *hdesc_pool; /*HW Descriptors pool */ ++ spinlock_t hdesc_lock; /*HW Descriptor assign lock*/ ++ int hdesc_num; /*HW Descriptors assigned num*/ ++ int hdesc_max; /*HW Descriptors maxnum capacity*/ ++ ++ struct ingenic_dma_sdesc *sdesc; /*Current Running Async Tx Desc*/ ++ ++ /*channel terminated completion*/ ++ struct completion completion; ++}; ++ ++struct ingenic_dma_engine { ++ struct device *dev; ++ void __iomem *iomem; ++ struct clk *gate_clk; ++ struct dma_device dma_device; ++ struct device_dma_parameters dma_parms; ++ ++ uint32_t chan_reserved; ++ uint32_t chan_programed; ++ int intc_ch; ++ bool special_ch; ++ ++ /*hardware interrupt*/ ++ int irq_pdma; /* pdma interrupt*/ ++ int irq_pdmam; /* pdma mcu interrupt */ ++ int irq_pdmad; /* pdma per-descriptor interrupt*/ ++ ++ /*hardware params*/ ++#define HWATTR_INTC_IRQ (1 << 0) ++#define HWATTR_SPECIAL_CH01 (1 << 1) ++#define HWATTR_DESC_INTER (1 << 2) ++#define HWATTR_INTC_IRQ_SUP(x) (HWATTR_INTC_IRQ & (x)) ++#define HWATTR_SPECIAL_CH01_SUP(x) (HWATTR_SPECIAL_CH01 & (x)) ++#define HWATTR_DESC_INTER_SUP(x) (HWATTR_DESC_INTER & (x)) ++ unsigned int hwattr; ++ /*channels*/ ++ int nr_chs; ++ struct ingenic_dma_chan* chan[]; ++}; ++ ++static inline struct device *chan2dev(struct dma_chan *chan) ++{ ++ return &chan->dev->device; ++} ++ ++static inline struct ingenic_dma_chan *to_ingenic_dma_chan(struct dma_chan *chan) ++{ ++ return container_of(chan, struct ingenic_dma_chan, vc.chan); ++} ++ ++static inline struct ingenic_dma_sdesc *to_ingenic_dma_sdesc(struct virt_dma_desc *vd) ++{ ++ return container_of(vd, struct ingenic_dma_sdesc, vd); ++} ++ ++u32 ingenic_dma_read_dtc(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ return readl(dmac->iomem + CH_DTC); ++} ++EXPORT_SYMBOL_GPL(ingenic_dma_read_dtc); ++ ++u32 ingenic_dma_read_dda(struct dma_chan *chan) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ return readl(dmac->iomem + CH_DDA); ++} ++EXPORT_SYMBOL_GPL(ingenic_dma_read_dda); ++ ++int ingenic_dma_get_desc_index(struct dma_chan *chan, unsigned int doa, int desc_num) ++{ ++ struct ingenic_dma_chan *dmac = to_ingenic_dma_chan(chan); ++ struct ingenic_dma_sdesc *sdesc = dmac->sdesc; ++ int i; ++ for(i = 0; i < desc_num; i++) { ++ if ((doa << 24) == PHY_TO_DESC_DOA(sdesc->hw_desc_dma[i])){ ++ if (i == 0) ++ return desc_num - 1; ++ else ++ return i - 1; ++ } ++ } ++ ++ return -1; ++} ++EXPORT_SYMBOL_GPL(ingenic_dma_get_desc_index); ++ ++#endif /*__INGENIC_DMA_H__*/ +diff --git a/module_drivers/drivers/i2c/Makefile b/module_drivers/drivers/i2c/Makefile +new file mode 100644 +index 000000000..0717b752f +--- /dev/null ++++ b/module_drivers/drivers/i2c/Makefile +@@ -0,0 +1 @@ ++obj-y += busses/ +diff --git a/module_drivers/drivers/i2c/busses/Kconfig b/module_drivers/drivers/i2c/busses/Kconfig +new file mode 100644 +index 000000000..b67e622de +--- /dev/null ++++ b/module_drivers/drivers/i2c/busses/Kconfig +@@ -0,0 +1,27 @@ ++config I2C_INGENIC ++ bool "Ingenic SoC based on Xburst arch's I2C controler Driver support" ++ help ++ Say Y here in order to support Ingenic SoC's I2C Controller Drvier ++ ++config I2C_NON_RESTART_MODE ++ bool "controler i2c no restart mode" ++ depends on I2C_INGENIC ++ default n ++ ++config I2C_FIFO_LEN ++ int "INGENIC I2C Controller FIFO length" ++ default 64 ++ depends on I2C_INGENIC ++ help ++ M200 and JZ4775 have 64 entries FIFO. ++ ++config I2C_DEBUG_INFO ++ bool "enable or disable Ingenic Soc's I2C driver debug info" ++ default n ++ depends on I2C_INGENIC ++ help ++ I2C debug print info, you can get the debug information from ++ /sys/devices/platform/i2c-ingenic.x/debug_info, ++ for example, echo 3 > /sys/devices/platform/i2c-ingenic.x/debug ++ ++ +diff --git a/module_drivers/drivers/i2c/busses/Makefile b/module_drivers/drivers/i2c/busses/Makefile +new file mode 100644 +index 000000000..6d81983b5 +--- /dev/null ++++ b/module_drivers/drivers/i2c/busses/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_I2C_INGENIC) += i2c-ingenic.o +diff --git a/module_drivers/drivers/i2c/busses/i2c-ingenic.c b/module_drivers/drivers/i2c/busses/i2c-ingenic.c +new file mode 100644 +index 000000000..a62e93ed7 +--- /dev/null ++++ b/module_drivers/drivers/i2c/busses/i2c-ingenic.c +@@ -0,0 +1,1146 @@ ++/* drivers/i2c/busses/i2c-v12-ingenic.c ++ * ++ * Copyright (C) 2014 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Sun Jiwei ++ * ++ * I2C adapter driver for the Ingenic I2C controller ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define I2C_CTRL (0x00) ++#define I2C_TAR (0x04) ++#define I2C_SAR (0x08) ++#define I2C_DC (0x10) ++#define I2C_SHCNT (0x14) ++#define I2C_SLCNT (0x18) ++#define I2C_FHCNT (0x1C) ++#define I2C_FLCNT (0x20) ++#define I2C_INTST (0x2C) ++#define I2C_INTM (0x30) ++#define I2C_RAW_INTR_STAT (0x34) ++#define I2C_RXTL (0x38) ++#define I2C_TXTL (0x3c) ++#define I2C_CINTR (0x40) ++#define I2C_CRXUF (0x44) ++#define I2C_CRXOF (0x48) ++#define I2C_CTXOF (0x4C) ++#define I2C_CRXREQ (0x50) ++#define I2C_CTXABRT (0x54) ++#define I2C_CRXDONE (0x58) ++#define I2C_CACT (0x5C) ++#define I2C_CSTP (0x60) ++#define I2C_CSTT (0x64) ++#define I2C_CGC (0x68) ++#define I2C_ENB (0x6C) ++#define I2C_STA (0x70) ++#define I2C_TXFLR (0x74) ++#define I2C_RXFLR (0x78) ++#define I2C_SDAHD (0x7C) ++#define I2C_TXABRT (0x80) ++#define I2C_DMACR (0x88) ++#define I2C_DMATDLR (0x8c) ++#define I2C_DMARDLR (0x90) ++#define I2C_SDASU (0x94) ++#define I2C_ACKGC (0x98) ++#define I2C_ENSTA (0x9C) ++#define I2C_FLT (0xA0) ++ ++/* I2C Control Register (I2C_CTRL) */ ++#define I2C_CTRL_SLVDIS (1 << 6) /* after reset slave is disabled */ ++#define I2C_CTRL_REST (1 << 5) ++#define I2C_CTRL_MATP (1 << 4) /* 1: 10bit address 0: 7bit addressing */ ++#define I2C_CTRL_SATP (1 << 3) /* 1: 10bit address 0: 7bit address */ ++#define I2C_CTRL_SPDF (2 << 1) /* fast mode 400kbps */ ++#define I2C_CTRL_SPDS (1 << 1) /* standard mode 100kbps */ ++#define I2C_CTRL_MD (1 << 0) /* master enabled */ ++ ++/* I2C Status Register (I2C_STA) */ ++#define I2C_STA_SLVACT (1 << 6) /* Slave FSM is not in IDLE state */ ++#define I2C_STA_MSTACT (1 << 5) /* Master FSM is not in IDLE state */ ++#define I2C_STA_RFF (1 << 4) /* RFIFO if full */ ++#define I2C_STA_RFNE (1 << 3) /* RFIFO is not empty */ ++#define I2C_STA_TFE (1 << 2) /* TFIFO is empty */ ++#define I2C_STA_TFNF (1 << 1) /* TFIFO is not full */ ++#define I2C_STA_ACT (1 << 0) /* I2C Activity Status */ ++ ++/* i2c interrupt status (I2C_INTST) */ ++#define I2C_INTST_IGC (1 << 11) ++#define I2C_INTST_ISTT (1 << 10) ++#define I2C_INTST_ISTP (1 << 9) ++#define I2C_INTST_IACT (1 << 8) ++#define I2C_INTST_RXDN (1 << 7) ++#define I2C_INTST_TXABT (1 << 6) ++#define I2C_INTST_RDREQ (1 << 5) ++#define I2C_INTST_TXEMP (1 << 4) ++#define I2C_INTST_TXOF (1 << 3) ++#define I2C_INTST_RXFL (1 << 2) ++#define I2C_INTST_RXOF (1 << 1) ++#define I2C_INTST_RXUF (1 << 0) ++ ++/* i2c interrupt mask status (I2C_INTM) */ ++#define I2C_INTM_MIGC (1 << 11) ++#define I2C_INTM_MISTT (1 << 10) ++#define I2C_INTM_MISTP (1 << 9) ++#define I2C_INTM_MIACT (1 << 8) ++#define I2C_INTM_MRXDN (1 << 7) ++#define I2C_INTM_MTXABT (1 << 6) ++#define I2C_INTM_MRDREQ (1 << 5) ++#define I2C_INTM_MTXEMP (1 << 4) ++#define I2C_INTM_MTXOF (1 << 3) ++#define I2C_INTM_MRXFL (1 << 2) ++#define I2C_INTM_MRXOF (1 << 1) ++#define I2C_INTM_MRXUF (1 << 0) ++ ++#define I2C_DC_REST (1 << 10) ++#define I2C_DC_STP (1 << 9) ++#define I2C_DC_READ (1 << 8) ++ ++#define I2C_ENB_I2CENB (1 << 0) /* Enable the i2c */ ++ ++#ifdef CONFIG_I2C_FIFO_LEN ++#define I2C_FIFO_LEN (CONFIG_I2C_FIFO_LEN) ++#else ++#define I2C_FIFO_LEN (64) ++#endif ++ ++#define TX_LEVEL (I2C_FIFO_LEN / 2) ++#define RX_LEVEL (I2C_FIFO_LEN / 2 - 1) ++#define TIMEOUT 0xff ++#define DEBUG_INFO 2 ++#define DEBUG_WARN 1 ++ ++//#define I2C_DEBUG ++/* ++ * msg_end_type: The bus control which need to be send at end of transfer. ++ * @MSG_END_STOP: Send stop pulse at end of transfer. ++ * @MSG_END_REPEAT_START: Send repeat start at end of transfer. ++ */ ++enum msg_end_type { ++ MSG_END_STOP, ++ MSG_END_CONTINUE, ++ MSG_END_REPEAT_START, ++}; ++ ++/* I2C Transmit Abort Status Register (I2C_TXABRT) */ ++static const char *abrt_src[] = { ++ "I2C_TXABRT_ABRT_7B_ADDR_NOACK", ++ "I2C_TXABRT_ABRT_10ADDR1_NOACK", ++ "I2C_TXABRT_ABRT_10ADDR2_NOACK", ++ "I2C_TXABRT_ABRT_XDATA_NOACK", ++ "I2C_TXABRT_ABRT_GCALL_NOACK", ++ "I2C_TXABRT_ABRT_GCALL_READ", ++ "I2C_TXABRT_ABRT_HS_ACKD", ++ "I2C_TXABRT_SBYTE_ACKDET", ++ "I2C_TXABRT_ABRT_HS_NORSTRT", ++ "I2C_TXABRT_SBYTE_NORSTRT", ++ "I2C_TXABRT_ABRT_10B_RD_NORSTRT", ++ "I2C_TXABRT_ABRT_MASTER_DIS", ++ "I2C_TXABRT_ARB_LOST", ++ "I2C_TXABRT_SLVFLUSH_TXFIFO", ++ "I2C_TXABRT_SLV_ARBLOST", ++ "I2C_TXABRT_SLVRD_INTX", ++}; ++ ++/* I2C standard mode high count register(I2CSHCNT) */ ++#define I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) ++/* I2C standard mode low count register(I2CSLCNT) */ ++#define I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) ++/* I2C fast mode high count register(I2CFHCNT) */ ++#define I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8)) ++/* I2C fast mode low count register(I2CFLCNT) */ ++#define I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1)) ++ ++struct i2c_ingenic { ++ void __iomem *iomem; ++ struct device *dev; ++ int irq; ++ struct clk *clk; ++ struct i2c_adapter adap; ++ ++ enum msg_end_type w_end_type; ++ enum msg_end_type r_end_type; ++ unsigned char *rbuf; ++ unsigned char *wbuf; ++ unsigned int rd_len; ++ int len; ++ ++ struct completion complete; ++ ++ int debug; ++ unsigned int rate; ++ ++ unsigned int timeout_ms; /*ms*/ ++ unsigned int speed_hz; /*hz*/ ++ unsigned int id; /*chip id*/ ++ bool clk_always_enable; ++}; ++ ++static inline unsigned short i2c_readl(struct i2c_ingenic *i2c, ++ unsigned short offset); ++#ifdef I2C_DEBUG ++static void i2c_ingenic_dump_regs(struct i2c_ingenic *i2c) ++{ ++ struct i2c_ingenic *i2c_id = i2c; ++ ++#define PRINT_REG_WITH_ID(reg_name, id) \ ++ dev_info(&(i2c->adap.dev),"--"#reg_name " 0x%08x\n",i2c_readl(id, reg_name)) ++ ++ PRINT_REG_WITH_ID(I2C_CTRL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_INTST, i2c_id); ++ PRINT_REG_WITH_ID(I2C_INTM, i2c_id); ++ PRINT_REG_WITH_ID(I2C_RAW_INTR_STAT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_RXTL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_TXTL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_STA, i2c_id); ++ PRINT_REG_WITH_ID(0x78, i2c_id); ++ return; ++ ++ PRINT_REG_WITH_ID(I2C_CTRL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_TAR, i2c_id); ++ PRINT_REG_WITH_ID(I2C_SAR, i2c_id); ++ // PRINT_REG_WITH_ID(I2C_DC, i2c_id); ++ PRINT_REG_WITH_ID(I2C_SHCNT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_SLCNT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_FHCNT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_FLCNT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_INTST, i2c_id); ++ PRINT_REG_WITH_ID(I2C_INTM, i2c_id); ++ PRINT_REG_WITH_ID(I2C_RXTL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_TXTL, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CINTR, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CRXUF, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CRXOF, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CTXOF, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CRXREQ, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CTXABRT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CRXDONE, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CACT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CSTP, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CSTT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_CGC, i2c_id); ++ PRINT_REG_WITH_ID(I2C_ENB, i2c_id); ++ PRINT_REG_WITH_ID(I2C_STA, i2c_id); ++ /*debug trans & recive fifo count */ ++ PRINT_REG_WITH_ID(0x74, i2c_id); ++ PRINT_REG_WITH_ID(0x78, i2c_id); ++ ++ PRINT_REG_WITH_ID(I2C_TXABRT, i2c_id); ++ PRINT_REG_WITH_ID(I2C_DMACR, i2c_id); ++ PRINT_REG_WITH_ID(I2C_DMATDLR, i2c_id); ++ PRINT_REG_WITH_ID(I2C_DMARDLR, i2c_id); ++ PRINT_REG_WITH_ID(I2C_SDASU, i2c_id); ++ PRINT_REG_WITH_ID(I2C_ACKGC, i2c_id); ++ PRINT_REG_WITH_ID(I2C_ENSTA, i2c_id); ++ PRINT_REG_WITH_ID(I2C_SDAHD, i2c_id); ++#undef PRINT_REG_WITH_ID ++} ++#else /* I2C_DEBUG */ ++static void i2c_ingenic_dump_regs(struct i2c_ingenic *i2c) {} ++#endif /* !I2C_DEBUG */ ++ ++static inline unsigned short i2c_readl(struct i2c_ingenic *i2c, ++ unsigned short offset) ++{ ++ return readl(i2c->iomem + offset); ++} ++ ++static inline void i2c_writel(struct i2c_ingenic *i2c, unsigned short offset, ++ unsigned short value) ++{ ++ writel(value, i2c->iomem + offset); ++} ++ ++static int i2c_ingenic_enable(struct i2c_ingenic *i2c, int enable) ++{ ++ int timeout = TIMEOUT; ++ ++ i2c_writel(i2c, I2C_ENB, enable); ++ while (((i2c_readl(i2c, I2C_ENSTA) & I2C_ENB_I2CENB) == !enable) && (--timeout > 0)) ++ msleep(1); ++ ++ if (timeout) ++ return 0; ++ ++ dev_err(&(i2c->adap.dev), "%s i2c%d failed\n", enable?"enable":"disable", i2c->adap.nr); ++ return -ETIMEDOUT; ++} ++ ++static void i2c_ingenic_reset(struct i2c_ingenic *i2c) ++{ ++ i2c_readl(i2c, I2C_CTXABRT); ++ i2c_readl(i2c, I2C_INTST); ++ ++ i2c_ingenic_enable(i2c, 0); ++ udelay(10); /* Don't know why to wait for 10us */ ++ i2c_ingenic_enable(i2c, 1); ++} ++ ++/* function: send read command ++ * return: 0, successful ++ * 1, txfifo valid entry is more than receive fifo, before send read command, ++ * must be read. ++ * 2, txfifo count is 0 or rxfifo count is 0. ++ * */ ++static inline unsigned int i2c_send_rcmd(struct i2c_ingenic *i2c) ++{ ++ unsigned int tx_count, rx_count, count, tx_valid, rx_valid; ++ ++ tx_valid = i2c_readl(i2c, I2C_TXFLR); ++ rx_valid = i2c_readl(i2c, I2C_RXFLR); ++ tx_count = I2C_FIFO_LEN - tx_valid; ++ rx_count = I2C_FIFO_LEN - rx_valid; ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if(i2c->debug > DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), ++ "%s, tx_valid = %d, rx_valid = %d," ++ " tx_count = %d, rx_count = %d\n", ++ __func__, tx_valid, rx_valid, tx_count, rx_count); ++#endif ++ ++ if (tx_valid > rx_count) { ++ dev_warn(&(i2c->adap.dev), ++ "\n\n###Warrning: I2C transfer fifo valid entry is more receive fifo, " ++ "before send read cmd, please read data from " ++ "the read fifo.\n\n"); ++ return 1; ++ } ++ ++ if (!tx_count || !rx_count) { ++ dev_warn(&(i2c->adap.dev), ++ "\n\n###Warrning: I2C receive fifo or transfer fifo is full, " ++ "before send read cmd, please read data from " ++ "the read fifo or wait some time.\n\n"); ++ return 2; ++ } ++ ++ count = min3(i2c->rd_len, tx_count, rx_count); ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), ++ "%s, Before send read cmd, " ++ "need_send = %d, left_send = %d\n", ++ __func__, count ,i2c->rd_len); ++#endif ++ ++ i2c->rd_len -= count; ++ ++ if (!i2c->rd_len) { ++ while (count > 1) { ++ i2c_writel(i2c, I2C_DC, I2C_DC_READ); ++ count--; ++ } ++ if (i2c->r_end_type == MSG_END_STOP) { ++ i2c_writel(i2c, I2C_DC, I2C_DC_READ | I2C_DC_STP); ++ } else { ++ i2c_writel(i2c, I2C_DC, I2C_DC_READ); ++ } ++ } else { ++ while (count > 0) { ++ i2c_writel(i2c, I2C_DC, I2C_DC_READ); ++ count--; ++ } ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if(i2c->debug > DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), ++ "%s, After send read cmd, " ++ "left_send = %d\n", ++ __func__, i2c->rd_len); ++#endif ++ return 0; ++} ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++static ssize_t enable_debug(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ int rc; ++ unsigned long enable; ++ struct i2c_ingenic *i2c = (struct i2c_ingenic *)dev_get_drvdata(dev); ++ ++ rc = kstrtol(buf, 0, &enable); ++ if (rc) ++ return rc; ++ ++ if ((enable >= 0) && (enable <= DEBUG_INFO + 1)) ++ i2c->debug = enable; ++ else ++ goto err; ++ ++ return size; ++err: ++ pr_err("Please input correct number(enable >= 0 && enable <= 5)" ++ " to disable or enable debug info print\n"); ++ return -EAGAIN; ++} ++ ++static struct device_attribute attributes[] = { ++ __ATTR(debug_info, 0200, NULL, enable_debug), ++}; ++ ++static int create_debug_sysfs_interface(struct device *dev) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(attributes); i++) ++ if (device_create_file(dev, attributes + i)) ++ goto err; ++ return 0; ++ ++err: ++ for( ; i >= 0; i--) ++ device_remove_file(dev, attributes + i); ++ return -1; ++} ++#endif ++ ++static irqreturn_t i2c_ingenic_irq(int irqno, void *dev_id) ++{ ++ unsigned short tmp, intst, intmsk; ++ struct i2c_ingenic *i2c = dev_id; ++ ++ intst = i2c_readl(i2c, I2C_INTST); ++ intmsk = i2c_readl(i2c, I2C_INTM); ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), "--I2C irq register INTST:0x%08x\n", intst); ++#endif ++ ++ if ((intst & I2C_INTST_TXABT) && (intmsk & I2C_INTM_MTXABT)) { ++ dev_err(&(i2c->adap.dev), ++ "%s %d, I2C transfer error, ABORT interrupt\n", ++ __func__, __LINE__); ++ goto END_TRSF_IRQ_HND; ++ } ++ ++ if ((intst & I2C_INTST_ISTP) && (intmsk & I2C_INTM_MISTP)) { ++ i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_INFO) { ++ dev_info(&(i2c->adap.dev), ++ "%s, Now stop condition has occurred," ++ "and left data length is %d\n", ++ __func__, i2c->len); ++ } ++#endif ++ ++ if (i2c->len == 0) ++ goto END_TRSF_IRQ_HND; ++ } ++ ++ if ((intmsk & I2C_INTM_MTXEMP) && (intst & I2C_INTST_TXEMP)) { ++ if (!i2c->len) { ++ if (i2c->w_end_type == MSG_END_REPEAT_START) { ++ goto END_TRSF_IRQ_HND; ++ } else { ++ tmp = i2c_readl(i2c, I2C_INTM); ++ tmp &= ~I2C_INTM_MTXEMP; ++ i2c_writel(i2c, I2C_INTM, tmp); ++ } ++ } else { ++ while ((i2c->len > 0) && ++ (i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF)) { ++ tmp = *i2c->wbuf++; ++ if (i2c->len == 1) { ++ if (i2c->w_end_type == MSG_END_STOP) ++ tmp |= I2C_DC_STP; ++ } ++ ++ i2c_writel(i2c, I2C_DC, tmp); ++ i2c->len -= 1; ++ } ++ ++ if (i2c->len == 0) { ++ i2c_writel(i2c, I2C_TXTL, 0); ++ } ++ } ++ } ++ ++ if ((intst & I2C_INTST_RXFL) && (intmsk & I2C_INTM_MRXFL)) { ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug >= DEBUG_INFO) { ++ dev_info(&(i2c->adap.dev), ++ "%s, Before read I2C_DC, " ++ "left_send_cmd = %d, left_read_cnt = %d," ++ " rx_valid = %d, tx_valid = %d\n", ++ __func__, i2c->rd_len, i2c->len, ++ i2c_readl(i2c, I2C_RXFLR), i2c_readl(i2c, I2C_TXFLR)); ++ } ++#endif ++ ++ while ((i2c_readl(i2c, I2C_STA) & I2C_STA_RFNE) && ++ (i2c->len > 0)) { ++ tmp = i2c_readl(i2c, I2C_DC) & 0xff; ++ *i2c->rbuf++ = tmp; ++ i2c->len--; ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug >= DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), ++ "%s, After read I2C_DC, " ++ "left_read_cnt = %d," ++ " rx_valid = %d, tx_valid = %d\n", ++ __func__, i2c->len, ++ i2c_readl(i2c, I2C_RXFLR), i2c_readl(i2c, I2C_TXFLR)); ++#endif ++ ++ if (i2c->len == 0) { ++ goto END_RECE_IRQ_HND; ++ } ++ ++ if (i2c->len <= I2C_FIFO_LEN) { ++ i2c_writel(i2c, I2C_RXTL, i2c->len - 1); ++ } ++ ++ if (i2c_send_rcmd(i2c)) { ++ dev_err(&(i2c->adap.dev), ++ "%s %d, I2C controller has BUG," ++ " RXFLR or TXFLR can not clear\n", ++ __func__, __LINE__); ++ BUG(); ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_INFO) ++ dev_info(&(i2c->adap.dev), ++ "%s, After send read command, " ++ "left_send_cmd = %d, " ++ "left_read_cnt = %d\n", ++ __func__, i2c->rd_len, i2c->len); ++#endif ++ } ++ ++ if ((intst & I2C_INTST_RXOF) && (intmsk & I2C_INTM_MRXOF)) { ++ dev_err(&(i2c->adap.dev), ++ "%s %d, I2C transfer error, RXFIFO over full\n", ++ __func__, __LINE__); ++ i2c_readl(i2c, I2C_CRXOF); /* clear RXOF bit */ ++ } ++ ++ if ((intst & I2C_INTST_TXOF) && (intmsk & I2C_INTM_MTXOF)) { ++ dev_err(&(i2c->adap.dev), ++ "%s %d, I2C transfer error, TXFIFO over full\n", ++ __func__, __LINE__); ++ i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ ++ goto END_TRSF_IRQ_HND; ++ } ++ ++ return IRQ_HANDLED; ++END_RECE_IRQ_HND: ++END_TRSF_IRQ_HND: ++ i2c_writel(i2c, I2C_INTM, 0); ++ complete(&i2c->complete); ++ return IRQ_HANDLED; ++} ++ ++static void txabrt(struct i2c_ingenic *i2c, int src) ++{ ++ int i; ++ ++ dev_err(&(i2c->adap.dev), "--I2C txabrt:\n"); ++ for (i = 0; i < 16; i++) { ++ if (src & (0x1 << i)) ++ dev_info(&(i2c->adap.dev), "--I2C TXABRT[%d]=%s\n", i, ++ abrt_src[i]); ++ } ++} ++ ++static inline int xfer_read(struct i2c_ingenic *i2c, unsigned char *buf, int len, ++ enum msg_end_type end_type) ++{ ++ int ret = 0; ++ long timeout; ++ unsigned short tmp; ++ unsigned int wait_complete_timeout_ms; ++ ++ wait_complete_timeout_ms = ++ len * 1000 * 9 * 2 / i2c->rate + i2c->timeout_ms; ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Begin read msg, want to read length is %d\n", ++ __func__, len); ++ memset(buf, 0, len); ++#endif ++ ++ i2c->rd_len = len; ++ i2c->len = len; ++ i2c->rbuf = buf; ++ i2c->r_end_type = end_type; ++ ++ i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ ++ i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ ++ i2c_readl(i2c, I2C_CTXABRT); /* clear TXABRT bit */ ++ ++ if (len <= I2C_FIFO_LEN) { ++ i2c_writel(i2c, I2C_RXTL, len - 1); ++ } else { ++ i2c_writel(i2c, I2C_RXTL, RX_LEVEL); ++ } ++ ++ while (i2c_readl(i2c, I2C_STA) & I2C_STA_RFNE) { ++ i2c_readl(i2c, I2C_DC); ++ } ++ if (i2c_send_rcmd(i2c)) ++ BUG(); ++ ++ tmp = I2C_INTM_MRXFL | I2C_INTM_MTXABT; ++ if (end_type == MSG_END_STOP) ++ tmp |= I2C_INTM_MISTP; ++ i2c_writel(i2c, I2C_INTM, tmp); ++ ++ ++ timeout = wait_for_completion_timeout(&i2c->complete, ++ msecs_to_jiffies ++ (wait_complete_timeout_ms)); ++ if (!timeout) { ++ dev_err(&(i2c->adap.dev), "--I2C irq read timeout\n"); ++ i2c_ingenic_dump_regs(i2c); ++ ret = -ETIMEDOUT; ++ } ++ ++ tmp = i2c_readl(i2c, I2C_TXABRT); ++ if (tmp) { ++ txabrt(i2c, tmp); ++ if (tmp > 0x1 && tmp < 0x10) ++ ret = -ENXIO; ++ else ++ ret = -EIO; ++ // ABRT_GCALL_READ ++ if (tmp & (1 << 5)) { ++ ret = -EAGAIN; ++ } ++ i2c_readl(i2c, I2C_CTXABRT); ++ } ++ ++ if (ret < 0) ++ i2c_ingenic_reset(i2c); ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Reading msg over\n", __func__); ++#endif ++ ++ return ret; ++} ++ ++static inline int xfer_write(struct i2c_ingenic *i2c, unsigned char *buf, int len, ++ enum msg_end_type end_type) ++{ ++ int ret = 0; ++ long timeout = TIMEOUT; ++ unsigned short reg_tmp; ++ unsigned int wait_complete_timeout_ms; ++ ++ wait_complete_timeout_ms = ++ len * 1000 * 9 * 2 / i2c->rate + i2c->timeout_ms; ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Begin write msg, want to write length is %d\n", ++ __func__, len); ++#endif ++ i2c->wbuf = buf; ++ i2c->len = len; ++ ++ i2c_writel(i2c, I2C_TXTL, TX_LEVEL); ++ ++ i2c_readl(i2c, I2C_CSTP); /* clear STP bit */ ++ i2c_readl(i2c, I2C_CTXOF); /* clear TXOF bit */ ++ i2c_readl(i2c, I2C_CTXABRT); /* clear TXABRT bit */ ++ ++ i2c->w_end_type = end_type; ++ while ((i2c_readl(i2c, I2C_STA) & I2C_STA_TFNF) && (i2c->len > 0)) { ++ reg_tmp = *i2c->wbuf++; ++ if (i2c->len == 1) { ++ if (end_type == MSG_END_STOP) { ++ reg_tmp |= I2C_DC_STP; ++ } ++ } ++ i2c_writel(i2c, I2C_DC, reg_tmp); ++ ++ i2c->len -= 1; ++ } ++ ++ if (i2c->len == 0) { ++ i2c_writel(i2c, I2C_TXTL, 0); ++ } ++ ++ reg_tmp = I2C_INTM_MTXEMP | I2C_INTM_MTXABT | I2C_INTM_MTXOF; ++ if (end_type == MSG_END_STOP) ++ reg_tmp |= I2C_INTM_MISTP; ++ ++ i2c_writel(i2c, I2C_INTM, reg_tmp); ++ ++ timeout = wait_for_completion_timeout(&i2c->complete, ++ msecs_to_jiffies ++ (wait_complete_timeout_ms)); ++ ++ if (!timeout) { ++ dev_err(&(i2c->adap.dev), "--I2C pio write wait timeout\n"); ++ i2c_ingenic_dump_regs(i2c); ++ ret = -ETIMEDOUT; ++ } ++ ++ reg_tmp = i2c_readl(i2c, I2C_TXABRT); ++ if (reg_tmp) { ++ txabrt(i2c, reg_tmp); ++ if (reg_tmp > 0x1 && reg_tmp < 0x10) ++ ret = -ENXIO; ++ else ++ ret = -EIO; ++ //after I2C_TXABRT_ABRT_XDATA_NOACK error,this required core to resend ++ if (reg_tmp & 8) { ++ ret = -EAGAIN; ++ } ++ i2c_readl(i2c, I2C_CTXABRT); ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Write msg over\n", __func__); ++#endif ++ return ret; ++} ++ ++static int i2c_disable_clk(struct i2c_ingenic *i2c) ++{ ++ int timeout = 10; ++ int tmp = i2c_readl(i2c, I2C_STA); ++ ++ while ((tmp & I2C_STA_MSTACT) && (--timeout > 0)) { ++ udelay(90); ++ tmp = i2c_readl(i2c, I2C_STA); ++ } ++ if (timeout > 0) { ++ if ((!IS_ERR(i2c->clk)) && (!i2c->clk_always_enable)) ++ clk_disable_unprepare(i2c->clk); ++ return 0; ++ } else { ++ dev_err(&(i2c->adap.dev), ++ "--I2C disable clk timeout, I2C_STA = 0x%x\n", tmp); ++ i2c_ingenic_reset(i2c); ++ if ((!IS_ERR(i2c->clk)) && (!i2c->clk_always_enable)) ++ clk_disable_unprepare(i2c->clk); ++ return -ETIMEDOUT; ++ } ++} ++ ++static int i2c_ingenic_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int count) ++{ ++ int i, ret = 0; ++ struct i2c_ingenic *i2c = adap->algo_data; ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) { ++ dev_info(&(i2c->adap.dev), ++ "\n\n\n%s, Begin master xfer, want to transfer msg count is %d\n", ++ __func__, count); ++ } ++#endif ++ ++ if ((!IS_ERR(i2c->clk)) && (!i2c->clk_always_enable)) ++ clk_prepare_enable(i2c->clk); ++ ++ i2c_writel(i2c, I2C_TAR, msg->addr); ++ ++ for (i = 0; i < count; i++, msg++) { ++ enum msg_end_type end_type = MSG_END_STOP; ++ if (i < (count - 1)) { ++ if (msg[i + 1].flags & I2C_M_NOSTART) { ++ end_type = MSG_END_CONTINUE; /* have no STOP and START */ ++ } else { ++ end_type = MSG_END_REPEAT_START; /* have no STOP but have RESTART */ ++ } ++ } ++ ++ reinit_completion(&i2c->complete); ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Now transfer msg: %d\n", __func__, i); ++#endif ++ if (msg->flags & I2C_M_RD) { ++ ret = xfer_read(i2c, msg->buf, msg->len, end_type); ++ } else { ++ ret = xfer_write(i2c, msg->buf, msg->len, end_type); ++ } ++ if (ret < 0) { ++ i2c_ingenic_reset(i2c); ++ if ((!IS_ERR(i2c->clk)) && (!i2c->clk_always_enable)) ++ clk_disable_unprepare(i2c->clk); ++ goto ERR; ++ } ++ } ++ ++ if (i2c_disable_clk(i2c)) { ++ ret = -ETIMEDOUT; ++ goto ERR; ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ if (i2c->debug > DEBUG_WARN) ++ dev_info(&(i2c->adap.dev), ++ "%s, Transfer msg over\n\n\n", __func__); ++#endif ++ ++ERR: ++ return ret ? : i; ++} ++ ++static u32 i2c_ingenic_functionality(struct i2c_adapter *adap) ++{ ++ unsigned int ret; ++ ret = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; ++ ++ return ret; ++} ++ ++static const struct i2c_algorithm i2c_ingenic_algorithm = { ++ .master_xfer = i2c_ingenic_xfer, ++ .functionality = i2c_ingenic_functionality, ++}; ++ ++static int i2c_set_speed(struct i2c_ingenic *i2c, int rate) ++{ ++ long dev_clk = clk_get_rate(i2c->clk); ++ long cnt_high = 0; /* HIGH period count of the SCL clock */ ++ long cnt_low = 0; /* LOW period count of the SCL clock */ ++ long setup_time = 0; ++ long hold_time = 0; ++ unsigned short tmp; ++ ++ i2c->rate = rate; ++ if (i2c_ingenic_enable(i2c, 0)) ++ dev_info(&(i2c->adap.dev), "i2c not disable\n"); ++ if (rate <= 100000) { ++ tmp = 0x43 | (1 << 5); /* standard speed mode */ ++ i2c_writel(i2c, I2C_CTRL, tmp); ++ } else { ++ tmp = 0x45 | (1 << 5); /* fast speed mode */ ++ i2c_writel(i2c, I2C_CTRL, tmp); ++ } ++ ++ /* high ++ * ____ ____ ____ ____ ++ * clk __| | |___| |____| |____| |___ ++ * | | | ++ * | | | ++ * |_|_| _________ ____ ++ * data __/ | |\___/ \____/ \____ ++ * setup->| |<| ++ * ->| |<-hold ++ */ ++ ++ //setup_time = (10 000 000/(rate*4)) + 1; ++ setup_time = (dev_clk / (rate * 4)); ++ if (setup_time > 1) ++ setup_time -= 1; ++ //hold_time = (10000000/(rate*4)) - 1; ++ hold_time = (dev_clk / (rate * 4)); ++ ++ /* high ++ * ____ ____ ++ * clk __| |___| |____ ++ * low ++ * |<--period--->| ++ * ++ */ ++ cnt_high = dev_clk / (rate * 2); ++ cnt_low = dev_clk / (rate * 2); ++ ++ dev_info(&(i2c->adap.dev), "set:%ld hold:%ld dev=%ld h=%ld l=%ld\n", ++ setup_time, hold_time, dev_clk, cnt_high, cnt_low); ++ if (setup_time > 255) ++ setup_time = 255; ++ if (setup_time <= 0) ++ setup_time = 1; ++ if (hold_time > 0xFFFF) ++ hold_time = 0xFFFF; ++ ++ if (rate <= 100000) { ++ i2c_writel(i2c, I2C_SHCNT, I2CSHCNT_ADJUST(cnt_high)); ++ i2c_writel(i2c, I2C_SLCNT, I2CSLCNT_ADJUST(cnt_low)); ++ } else { ++ i2c_writel(i2c, I2C_FHCNT, I2CFHCNT_ADJUST(cnt_high)); ++ i2c_writel(i2c, I2C_FLCNT, I2CFLCNT_ADJUST(cnt_low)); ++ } ++ ++ i2c_writel(i2c, I2C_SDASU, setup_time & 0xff); ++ i2c_writel(i2c, I2C_SDAHD, hold_time); ++ ++ return 0; ++} ++ ++#ifndef CONFIG_I2C_INGENICV10_WAIT_MS ++#define DEF_INGENIC_I2C_WAIT_TIMEOUT_MS (1000) ++#else ++#define DEF_INGENIC_I2C_WAIT_TIMEOUT_MS (CONFIG_I2C_INGENICV10_WAIT_MS) ++#endif ++ ++#define DEF_INGENIC_I2C_SPEED_HZ (100000) ++static void ingenic_i2c_parse_dt(struct device_node *np, struct i2c_ingenic *i2c) ++{ ++ u32 timeout, speed; ++ int id; ++ ++ if (!of_property_read_u32(np, "timeout", &timeout)) ++ i2c->timeout_ms = timeout; ++ else ++ i2c->timeout_ms = DEF_INGENIC_I2C_WAIT_TIMEOUT_MS; ++ ++ if (!of_property_read_u32(np, "clock-frequency", &speed)) ++ i2c->speed_hz = speed; ++ else ++ i2c->speed_hz = DEF_INGENIC_I2C_SPEED_HZ; ++ ++ if ((id = of_alias_get_id(np, "i2c")) >= 0) ++ i2c->id = id; ++ else ++ i2c->id = -1; ++} ++ ++ ++static int i2c_ingenic_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct i2c_ingenic *i2c; ++ struct resource *res; ++ unsigned int reg_tmp; ++ char name[20]; ++ int i2c_id; ++ ++ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); ++ if (!i2c) ++ return -ENOMEM; ++ ++ i2c->dev = &pdev->dev; ++ if (!pdev->dev.of_node) { ++ i2c->timeout_ms = DEF_INGENIC_I2C_WAIT_TIMEOUT_MS; ++ i2c->speed_hz = DEF_INGENIC_I2C_SPEED_HZ; ++ i2c->id = pdev->id; ++ res = platform_get_resource(pdev, IORESOURCE_BUS, 0); ++ if (res) ++ i2c->speed_hz = res->start * 1000; ++ } else ++ ingenic_i2c_parse_dt(pdev->dev.of_node, i2c); ++ ++ i2c->clk_always_enable = of_property_read_bool(pdev->dev.of_node, "clk-always-enable"); ++ ++ i2c->adap.owner = THIS_MODULE; ++ i2c->adap.algo = &i2c_ingenic_algorithm; ++ i2c->adap.retries = 5; ++ i2c->adap.timeout = 5; ++ i2c->adap.algo_data = i2c; ++ i2c->adap.dev.parent = &pdev->dev; ++ i2c->adap.nr = i2c->id; ++ ++ i2c->adap.dev.of_node = pdev->dev.of_node; ++ ++ i2c_id = i2c->id; ++ if (i2c_id >= 0) ++ sprintf(i2c->adap.name, "i2c%u", i2c->id); ++ else ++ sprintf(i2c->adap.name, "%s", dev_name(&pdev->dev)); ++ ++ sprintf(name, "gate_%s", i2c->adap.name); ++ ++ i2c->clk = devm_clk_get(&pdev->dev, name); ++ if (!i2c->clk) ++ return -ENODEV; ++ ++ if(clk_prepare(i2c->clk) < 0) { ++ dev_err(&pdev->dev, "failed to prepare for clk %s\n", __clk_get_name(i2c->clk)); ++ return -ENODEV; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ ++ i2c->iomem = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(i2c->iomem)) ++ return PTR_ERR(i2c->iomem); ++ ++ i2c->irq = platform_get_irq(pdev, 0); ++ if (i2c->irq < 0) ++ return i2c->irq; ++ ++ ret = devm_request_irq(&pdev->dev, i2c->irq, ++ i2c_ingenic_irq, 0, i2c->adap.name, i2c); ++ if (ret) ++ return -ENODEV; ++ ++ ++ clk_enable(i2c->clk); ++ ++ i2c_set_speed(i2c, i2c->speed_hz); ++ ++#if 0 ++ reg_tmp = i2c_readl(i2c, I2C_DC); ++ reg_tmp &= ~I2C_DC_STP; ++ i2c_writel(i2c, I2C_DC, reg_tmp); ++#endif ++ ++ reg_tmp = i2c_readl(i2c, I2C_CTRL); ++#if defined(CONFIG_I2C_NON_RESTART_MODE) ++ reg_tmp &= ~I2C_CTRL_REST; ++#else ++ reg_tmp |= I2C_CTRL_REST; ++#endif ++ i2c_writel(i2c, I2C_CTRL, reg_tmp); ++ ++ // for jgao WHY? ++ // i2c_writel(i2c, I2C_FLT, 0xF); /*set filter*/ ++ ++ i2c_writel(i2c, I2C_INTM, 0x0); ++ ++ platform_set_drvdata(pdev, i2c); ++ ++ i2c_ingenic_enable(i2c, 1); ++ ++ if ((!IS_ERR(i2c->clk)) && (!i2c->clk_always_enable)) ++ clk_disable_unprepare(i2c->clk); ++ ++ init_completion(&i2c->complete); ++ ++ ret = i2c_add_numbered_adapter(&i2c->adap); ++ if (ret < 0) { ++ dev_err(&pdev->dev, KERN_INFO"I2C: Failed to add bus\n"); ++ if ((!IS_ERR(i2c->clk)) && (!i2c->clk_always_enable)) ++ clk_disable_unprepare(i2c->clk); ++ return ret; ++ } ++ ++#ifdef CONFIG_I2C_DEBUG_INFO ++ ret = create_debug_sysfs_interface(&pdev->dev); ++ if (ret < 0) ++ dev_err(&pdev->dev, "create debug sysfs interface failed\n"); ++#endif ++ dev_info(&pdev->dev, "%s success.\n", __func__); ++ return 0; ++} ++ ++static int i2c_ingenic_remove(struct platform_device *pdev) ++{ ++ struct i2c_ingenic *i2c = platform_get_drvdata(pdev); ++ if ((!IS_ERR(i2c->clk)) && (!i2c->clk_always_enable)) ++ clk_disable_unprepare(i2c->clk); ++ i2c_del_adapter(&i2c->adap); ++ return 0; ++} ++ ++static int i2c_ingenic_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ ++ struct i2c_ingenic *i2c = platform_get_drvdata(pdev); ++ ++ if ((!IS_ERR(i2c->clk)) && (!i2c->clk_always_enable)) ++ if(__clk_is_enabled(i2c->clk)) ++ clk_disable_unprepare(i2c->clk); ++ ++ return 0; ++} ++ ++static int i2c_ingenic_resume(struct platform_device *pdev) ++{ ++ struct i2c_ingenic *i2c = platform_get_drvdata(pdev); ++ unsigned int reg_tmp; ++ ++ if ((!IS_ERR(i2c->clk)) && (!i2c->clk_always_enable)) ++ clk_prepare_enable(i2c->clk); ++ ++ i2c_set_speed(i2c, i2c->speed_hz); ++ reg_tmp = i2c_readl(i2c, I2C_CTRL); ++#if defined(CONFIG_I2C_NON_RESTART_MODE) ++ reg_tmp &= ~I2C_CTRL_REST; ++#else ++ reg_tmp |= I2C_CTRL_REST; ++#endif ++ i2c_writel(i2c, I2C_CTRL, reg_tmp); ++ i2c_writel(i2c, I2C_INTM, 0x0); ++ ++ i2c_ingenic_reset(i2c); ++ ++ if ((!IS_ERR(i2c->clk)) && (!i2c->clk_always_enable)) ++ clk_disable_unprepare(i2c->clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_i2c_dt_match[] = { ++ { .compatible = "ingenic,i2c" }, ++ { .compatible = "ingenic,x2000-i2c" }, ++ { .compatible = "ingenic,x2500-i2c" }, ++ { .compatible = "ingenic,x1600-i2c" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_i2c_dt_match); ++ ++static struct platform_driver i2c_ingenic_driver = { ++ .probe = i2c_ingenic_probe, ++ .remove = i2c_ingenic_remove, ++ .driver = { ++ .name = "ingenic-i2c", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_i2c_dt_match), ++ }, ++ .suspend = i2c_ingenic_suspend, ++ .resume = i2c_ingenic_resume, ++}; ++ ++static int __init i2c_ingenic_init(void) ++{ ++ return platform_driver_register(&i2c_ingenic_driver); ++} ++subsys_initcall(i2c_ingenic_init); ++ ++static void __exit i2c_ingenic_exit(void) ++{ ++ platform_driver_unregister(&i2c_ingenic_driver); ++} ++module_exit(i2c_ingenic_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("i2c driver for INGENIC SoCs"); +diff --git a/module_drivers/drivers/input/Makefile b/module_drivers/drivers/input/Makefile +new file mode 100644 +index 000000000..035a93f92 +--- /dev/null ++++ b/module_drivers/drivers/input/Makefile +@@ -0,0 +1 @@ ++obj-y += touchscreen/ +diff --git a/module_drivers/drivers/input/touchscreen/Kconfig b/module_drivers/drivers/input/touchscreen/Kconfig +new file mode 100644 +index 000000000..5271c1495 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/Kconfig +@@ -0,0 +1,17 @@ ++ ++#source "module_drivers/drivers/input/touchscreen/cyttsp5/Kconfig" ++source "module_drivers/drivers/input/touchscreen/focaltech_touch/Kconfig" ++#source "module_drivers/drivers/input/touchscreen/focaltech_ft5x16_touch/Kconfig" ++source "module_drivers/drivers/input/touchscreen/hyn_touch/Kconfig" ++#source "module_drivers/drivers/input/touchscreen/chipone_touch/Kconfig" ++#source "module_drivers/drivers/input/touchscreen/msm8909w/Kconfig" ++source "module_drivers/drivers/input/touchscreen/gt9xx_touch/Kconfig" ++source "module_drivers/drivers/input/touchscreen/ft6236_touch/Kconfig" ++ ++ ++config TOUCHSCREEN_MXT336U ++ tristate "MicroChip MXT336U TouchScreen driver" ++ depends on I2C ++ default n ++ help ++ MicroChip MXT336U TouchScreen driver implemented by Ingenic for Robam. +diff --git a/module_drivers/drivers/input/touchscreen/Makefile b/module_drivers/drivers/input/touchscreen/Makefile +new file mode 100644 +index 000000000..718ee4847 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/Makefile +@@ -0,0 +1,11 @@ ++ ++#obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5) += cyttsp5/ ++obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/ ++#obj-$(CONFIG_TOUCHSCREEN_FT5X16) += focaltech_ft5x16_touch/ ++obj-$(CONFIG_TOUCHSCREEN_HYN) += hyn_touch/ ++#obj-$(CONFIG_TOUCHSCREEN_CHIPONE) += chipone_touch/ ++obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx_touch/ ++obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236_touch/ ++#obj-$(CONFIG_TOUCHSCREEN_MSM8909W) += msm8909w/ ++ ++obj-$(CONFIG_TOUCHSCREEN_MXT336U) += mxt_336u_ts.o +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/Kconfig b/module_drivers/drivers/input/touchscreen/focaltech_touch/Kconfig +new file mode 100644 +index 000000000..e2bf1085b +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/Kconfig +@@ -0,0 +1,16 @@ ++# ++# Focaltech Touchscreen driver configuration ++# ++ ++config TOUCHSCREEN_FTS ++ bool "Focaltech Touchscreen" ++ default n ++ help ++ Say Y here if you have Focaltech touch panel. ++ If unsure, say N. ++ ++config TOUCHSCREEN_FTS_DIRECTORY ++ string "Focaltech ts directory name" ++ default "focaltech_touch" ++ depends on TOUCHSCREEN_FTS ++ +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/Makefile b/module_drivers/drivers/input/touchscreen/focaltech_touch/Makefile +new file mode 100644 +index 000000000..b0d546e92 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/Makefile +@@ -0,0 +1,13 @@ ++# Makefile for the focaltech touchscreen drivers. ++ ++ ++obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_core.o ++#obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_ex_fun.o ++#obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_ex_mode.o ++#obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_gesture.o ++#obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_esdcheck.o ++#obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_point_report_check.o ++ ++obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_i2c.o ++#obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_flash.o ++#obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_flash/ +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_common.h b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_common.h +new file mode 100644 +index 000000000..d636d97dc +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_common.h +@@ -0,0 +1,166 @@ ++/* ++ * ++ * FocalTech fts TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, Focaltech Ltd. 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. ++ * ++ */ ++/***************************************************************************** ++* ++* File Name: focaltech_common.h ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-16 ++* ++* Abstract: ++* ++* Reference: ++* ++*****************************************************************************/ ++ ++#ifndef __LINUX_FOCALTECH_COMMON_H__ ++#define __LINUX_FOCALTECH_COMMON_H__ ++ ++#include "focaltech_config.h" ++ ++/***************************************************************************** ++* Macro definitions using #define ++*****************************************************************************/ ++#define FTS_DRIVER_VERSION "Focaltech V3.1 20190807" ++ ++#define BYTE_OFF_0(x) (u8)((x) & 0xFF) ++#define BYTE_OFF_8(x) (u8)(((x) >> 8) & 0xFF) ++#define BYTE_OFF_16(x) (u8)(((x) >> 16) & 0xFF) ++#define BYTE_OFF_24(x) (u8)(((x) >> 24) & 0xFF) ++#define FLAGBIT(x) (0x00000001 << (x)) ++#define FLAGBITS(x, y) ((0xFFFFFFFF >> (32 - (y) - 1)) & (0xFFFFFFFF << (x))) ++ ++#define FLAG_ICSERIALS_LEN 8 ++#define FLAG_HID_BIT 10 ++#define FLAG_IDC_BIT 11 ++ ++#define IC_SERIALS (FTS_CHIP_TYPE & FLAGBITS(0, FLAG_ICSERIALS_LEN-1)) ++#define IC_TO_SERIALS(x) ((x) & FLAGBITS(0, FLAG_ICSERIALS_LEN-1)) ++#define FTS_CHIP_IDC ((FTS_CHIP_TYPE & FLAGBIT(FLAG_IDC_BIT)) == FLAGBIT(FLAG_IDC_BIT)) ++#define FTS_HID_SUPPORTTED ((FTS_CHIP_TYPE & FLAGBIT(FLAG_HID_BIT)) == FLAGBIT(FLAG_HID_BIT)) ++ ++#define FTS_CHIP_TYPE_MAPPING {{0x02, 0x54, 0x22, 0x54, 0x22, 0x00, 0x00, 0x54, 0x2C}, {0x02, 0x64, 0x26, 0x64, 0x26, 0x00, 0x00, 0x54, 0x2C}} ++ ++#define FILE_NAME_LENGTH 128 ++#define ENABLE 1 ++#define DISABLE 0 ++#define VALID 1 ++#define INVALID 0 ++#define FTS_CMD_START1 0x55 ++#define FTS_CMD_START2 0xAA ++#define FTS_CMD_START_DELAY 12 ++#define FTS_CMD_READ_ID 0x90 ++#define FTS_CMD_READ_ID_LEN 4 ++#define FTS_CMD_READ_ID_LEN_INCELL 1 ++/*register address*/ ++#define FTS_REG_INT_CNT 0x8F ++#define FTS_REG_FLOW_WORK_CNT 0x91 ++#define FTS_REG_WORKMODE 0x00 ++#define FTS_REG_WORKMODE_FACTORY_VALUE 0x40 ++#define FTS_REG_WORKMODE_WORK_VALUE 0x00 ++#define FTS_REG_ESDCHECK_DISABLE 0x8D ++#define FTS_REG_CHIP_ID 0xA3 ++#define FTS_REG_CHIP_ID2 0x9F ++#define FTS_REG_POWER_MODE 0xA5 ++#define FTS_REG_POWER_MODE_SLEEP 0x03 ++#define FTS_REG_FW_VER 0xA6 ++#define FTS_REG_VENDOR_ID 0xA8 ++#define FTS_REG_LCD_BUSY_NUM 0xAB ++#define FTS_REG_FACE_DEC_MODE_EN 0xB0 ++#define FTS_REG_FACTORY_MODE_DETACH_FLAG 0xB4 ++#define FTS_REG_FACE_DEC_MODE_STATUS 0x01 ++#define FTS_REG_IDE_PARA_VER_ID 0xB5 ++#define FTS_REG_IDE_PARA_STATUS 0xB6 ++#define FTS_REG_GLOVE_MODE_EN 0xC0 ++#define FTS_REG_COVER_MODE_EN 0xC1 ++#define FTS_REG_CHARGER_MODE_EN 0x8B ++#define FTS_REG_GESTURE_EN 0xD0 ++#define FTS_REG_GESTURE_OUTPUT_ADDRESS 0xD3 ++#define FTS_REG_MODULE_ID 0xE3 ++#define FTS_REG_LIC_VER 0xE4 ++#define FTS_REG_ESD_SATURATE 0xED ++ ++#define FTS_SYSFS_ECHO_ON(buf) (buf[0] == '1') ++#define FTS_SYSFS_ECHO_OFF(buf) (buf[0] == '0') ++ ++#define kfree_safe(pbuf) do {\ ++ if (pbuf) {\ ++ kfree(pbuf);\ ++ pbuf = NULL;\ ++ }\ ++} while(0) ++ ++/***************************************************************************** ++* Alternative mode (When something goes wrong, the modules may be able to solve the problem.) ++*****************************************************************************/ ++/* ++ * point report check ++ * default: disable ++ */ ++#define FTS_POINT_REPORT_CHECK_EN 0 ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++struct ft_chip_t { ++ u64 type; ++ u8 chip_idh; ++ u8 chip_idl; ++ u8 rom_idh; ++ u8 rom_idl; ++ u8 pb_idh; ++ u8 pb_idl; ++ u8 bl_idh; ++ u8 bl_idl; ++}; ++ ++struct ts_ic_info { ++ bool is_incell; ++ bool hid_supported; ++ struct ft_chip_t ids; ++}; ++ ++/***************************************************************************** ++* DEBUG function define here ++*****************************************************************************/ ++#if FTS_DEBUG_EN ++#define FTS_DEBUG(fmt, args...) do { \ ++ printk("[FTS_TS]%s:"fmt"\n", __func__, ##args); \ ++} while (0) ++ ++#define FTS_FUNC_ENTER() do { \ ++ printk("[FTS_TS]%s: Enter\n", __func__); \ ++} while (0) ++ ++#define FTS_FUNC_EXIT() do { \ ++ printk("[FTS_TS]%s: Exit(%d)\n", __func__, __LINE__); \ ++} while (0) ++#else /* #if FTS_DEBUG_EN*/ ++#define FTS_DEBUG(fmt, args...) ++#define FTS_FUNC_ENTER() ++#define FTS_FUNC_EXIT() ++#endif ++ ++#define FTS_INFO(fmt, args...) do { \ ++ printk(KERN_INFO "[FTS_TS/I]%s:"fmt"\n", __func__, ##args); \ ++} while (0) ++ ++#define FTS_ERROR(fmt, args...) do { \ ++ printk(KERN_ERR "[FTS_TS/E]%s:"fmt"\n", __func__, ##args); \ ++} while (0) ++#endif /* __LINUX_FOCALTECH_COMMON_H__ */ +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_config.h b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_config.h +new file mode 100644 +index 000000000..7b12417a8 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_config.h +@@ -0,0 +1,165 @@ ++/* ++ * ++ * FocalTech TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. ++ * ++ */ ++/************************************************************************ ++* ++* File Name: focaltech_config.h ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-08 ++* ++* Abstract: global configurations ++* ++* Version: v1.0 ++* ++************************************************************************/ ++#ifndef _LINUX_FOCLATECH_CONFIG_H_ ++#define _LINUX_FOCLATECH_CONFIG_H_ ++ ++/**************************************************/ ++/****** G: A, I: B, S: C, U: D ******************/ ++/****** chip type defines, do not modify *********/ ++ ++#define _FT7511 0x75110402 ++#define _FT7661 0x76610402 ++/*************************************************/ ++ ++/* ++ * choose your ic chip type of focaltech ++ */ ++//#define FTS_CHIP_TYPE _FT7511 ++#define FTS_CHIP_TYPE 0x0402 ++ ++/******************* Enables *********************/ ++/*********** 1 to enable, 0 to disable ***********/ ++ ++/* ++ * show debug log info ++ * enable it for debug, disable it for release ++ */ ++#define FTS_DEBUG_EN 0 ++ ++/* ++ * Linux MultiTouch Protocol ++ * 1: Protocol B(default), 0: Protocol A ++ */ ++#if defined (CONFIG_STAGE_TL040WVS03CT) || defined (CONFIG_STAGE_ST7701S_RGB666) ++#define FTS_MT_PROTOCOL_B_EN 0 ++#else ++#define FTS_MT_PROTOCOL_B_EN 1 ++#endif /*CONFIG_PANEL_V12_TL040WVS03CT*/ ++ ++ ++/* ++ * Report Pressure in multitouch ++ * 1:enable(default),0:disable ++*/ ++#define FTS_REPORT_PRESSURE_EN 1 ++ ++/* ++ * Gesture function enable ++ * default: disable ++ */ ++#define FTS_GESTURE_EN 0 ++ ++/* ++ * ESD check & protection ++ * default: disable ++ */ ++#define FTS_ESDCHECK_EN 0 ++ ++ ++/* ++ * Pinctrl enable ++ * default: disable ++ */ ++#define FTS_PINCTRL_EN 0 ++ ++ ++/* ++ * Customer power enable ++ * enable it when customer need control TP power ++ * default: disable ++ */ ++#define FTS_POWER_SOURCE_CUST_EN 0 ++ ++#define FTS_EX_MODE_EN 0 ++#define FTS_EX_FUNC_EN 0 ++ ++/****************************************************/ ++ ++/********************** Upgrade ****************************/ ++/* ++ * auto upgrade ++ */ ++#define FTS_AUTO_UPGRADE_EN 0 ++ ++/* ++ * auto upgrade for lcd cfg ++ */ ++#define FTS_AUTO_LIC_UPGRADE_EN 0 ++ ++/* ++ * Numbers of modules support ++ */ ++#define FTS_GET_MODULE_NUM 0 ++ ++/* ++ * module_id: mean vendor_id generally, also maybe gpio or lcm_id... ++ * If means vendor_id, the FTS_MODULE_ID = PANEL_ID << 8 + VENDOR_ID ++ * FTS_GET_MODULE_NUM == 0/1, no check module id, you may ignore them ++ * FTS_GET_MODULE_NUM >= 2, compatible with FTS_MODULE2_ID ++ * FTS_GET_MODULE_NUM >= 3, compatible with FTS_MODULE3_ID ++ */ ++#define FTS_MODULE_ID 0x0000 ++#define FTS_MODULE2_ID 0x0000 ++#define FTS_MODULE3_ID 0x0000 ++ ++/* ++ * Need set the following when get firmware via firmware_request() ++ * For example: if module'vendor is tianma, ++ * #define FTS_MODULE_NAME "tianma" ++ * then file_name will be "focaltech_ts_fw_tianma" ++ * You should rename fw to "focaltech_ts_fw_tianma", and push it into ++ * etc/firmware or by customers ++ */ ++#define FTS_MODULE_NAME "" ++#define FTS_MODULE2_NAME "" ++#define FTS_MODULE3_NAME "" ++ ++/* ++ * FW.i file for auto upgrade, you must replace it with your own ++ * define your own fw_file, the sample one to be replaced is invalid ++ * NOTE: if FTS_GET_MODULE_NUM > 1, it's the fw corresponding with FTS_VENDOR_ID ++ */ ++#define FTS_UPGRADE_FW_FILE "include/firmware/fw_sample.i" ++ ++/* ++ * if FTS_GET_MODULE_NUM >= 2, fw corrsponding with FTS_VENDOR_ID2 ++ * define your own fw_file, the sample one is invalid ++ */ ++#define FTS_UPGRADE_FW2_FILE "include/firmware/fw_sample.i" ++ ++/* ++ * if FTS_GET_MODULE_NUM >= 3, fw corrsponding with FTS_VENDOR_ID3 ++ * define your own fw_file, the sample one is invalid ++ */ ++#define FTS_UPGRADE_FW3_FILE "include/firmware/fw_sample.i" ++ ++/*********************************************************/ ++ ++#endif /* _LINUX_FOCLATECH_CONFIG_H_ */ +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_core.c b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_core.c +new file mode 100644 +index 000000000..6cd45dffb +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_core.c +@@ -0,0 +1,1723 @@ ++/* ++ * ++ * FocalTech TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. ++ * ++ */ ++/***************************************************************************** ++* ++* File Name: focaltech_core.c ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-08 ++* ++* Abstract: entrance for focaltech ts driver ++* ++* Version: V1.0 ++* ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Included header files ++*****************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(CONFIG_FB) ++#include ++#include ++#elif defined(CONFIG_HAS_EARLYSUSPEND) ++#include ++#define FTS_SUSPEND_LEVEL 1 /* Early-suspend level */ ++#endif ++#include "focaltech_core.h" ++ ++/***************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++#define FTS_DRIVER_NAME "fts_ts" ++#define INTERVAL_READ_REG 200 /* unit:ms */ ++#define TIMEOUT_READ_REG 600 /* unit:ms */ ++#if FTS_POWER_SOURCE_CUST_EN ++#define FTS_VTG_MIN_UV 2800000 ++#define FTS_VTG_MAX_UV 3300000 ++#define FTS_I2C_VTG_MIN_UV 1800000 ++#define FTS_I2C_VTG_MAX_UV 1800000 ++#endif ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++struct fts_ts_data *fts_data; ++ ++/***************************************************************************** ++* Static function prototypes ++*****************************************************************************/ ++static int fts_ts_suspend(struct device *dev); ++static int fts_ts_resume(struct device *dev); ++ ++/***************************************************************************** ++* Name: fts_wait_tp_to_valid ++* Brief: Read chip id until TP FW become valid(Timeout: TIMEOUT_READ_REG), ++* need call when reset/power on/resume... ++* Input: ++* Output: ++* Return: return 0 if tp valid, otherwise return error code ++*****************************************************************************/ ++int fts_wait_tp_to_valid(void) ++{ ++ int ret = 0; ++ int cnt = 0; ++ u8 idh = 0; ++ u8 idl = 0; ++ u8 chip_idh = fts_data->ic_info.ids.chip_idh; ++ u8 chip_idl = fts_data->ic_info.ids.chip_idl; ++ ++ do { ++ ret = fts_read_reg(FTS_REG_CHIP_ID, &idh); ++ ret = fts_read_reg(FTS_REG_CHIP_ID2, &idl); ++ if ((ret < 0) || (idh != chip_idh) || (idl != chip_idl)) { ++ FTS_DEBUG("TP Not Ready,ReadData:0x%02x%02x", idh, idl); ++ } else if ((idh == chip_idh) && (idl == chip_idl)) { ++ FTS_INFO("TP Ready,Device ID:0x%02x%02x", idh, idl); ++ return 0; ++ } ++ cnt++; ++ msleep(INTERVAL_READ_REG); ++ } while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG); ++ ++ return -EIO; ++} ++ ++/***************************************************************************** ++* Name: fts_tp_state_recovery ++* Brief: Need execute this function when reset ++* Input: ++* Output: ++* Return: ++*****************************************************************************/ ++void fts_tp_state_recovery(struct fts_ts_data *ts_data) ++{ ++ FTS_FUNC_ENTER(); ++ /* wait tp stable */ ++ fts_wait_tp_to_valid(); ++ /* recover TP charger state 0x8B */ ++ /* recover TP glove state 0xC0 */ ++ /* recover TP cover state 0xC1 */ ++#if FTS_EX_MODE_EN ++ fts_ex_mode_recovery(ts_data); ++#endif ++#if FTS_GESTURE_EN ++ /* recover TP gesture state 0xD0 */ ++ fts_gesture_recovery(ts_data); ++ FTS_FUNC_EXIT(); ++#endif ++} ++ ++int fts_reset_proc(int hdelayms) ++{ ++ FTS_DEBUG("tp reset"); ++ gpio_direction_output(fts_data->pdata->reset_gpio, 0); ++ msleep(1); ++ gpio_direction_output(fts_data->pdata->reset_gpio, 1); ++ if (hdelayms) { ++ msleep(hdelayms); ++ } ++ ++ return 0; ++} ++ ++void fts_irq_disable(void) ++{ ++ unsigned long irqflags; ++ ++ FTS_FUNC_ENTER(); ++ spin_lock_irqsave(&fts_data->irq_lock, irqflags); ++ ++ if (!fts_data->irq_disabled) { ++ disable_irq_nosync(fts_data->irq); ++ fts_data->irq_disabled = true; ++ } ++ ++ spin_unlock_irqrestore(&fts_data->irq_lock, irqflags); ++ FTS_FUNC_EXIT(); ++} ++ ++void fts_irq_enable(void) ++{ ++ unsigned long irqflags = 0; ++ ++ FTS_FUNC_ENTER(); ++ spin_lock_irqsave(&fts_data->irq_lock, irqflags); ++ ++ if (fts_data->irq_disabled) { ++ enable_irq(fts_data->irq); ++ fts_data->irq_disabled = false; ++ } ++ ++ spin_unlock_irqrestore(&fts_data->irq_lock, irqflags); ++ FTS_FUNC_EXIT(); ++} ++ ++void fts_hid2std(void) ++{ ++ int ret = 0; ++ u8 buf[3] = {0xEB, 0xAA, 0x09}; ++ ++ ret = fts_write(buf, 3); ++ if (ret < 0) { ++ FTS_ERROR("hid2std cmd write fail"); ++ } else { ++ msleep(10); ++ buf[0] = buf[1] = buf[2] = 0; ++ ret = fts_read(NULL, 0, buf, 3); ++ if (ret < 0) { ++ FTS_ERROR("hid2std cmd read fail"); ++ } else if ((0xEB == buf[0]) && (0xAA == buf[1]) && (0x08 == buf[2])) { ++ FTS_DEBUG("hidi2c change to stdi2c successful"); ++ } else { ++ FTS_DEBUG("hidi2c change to stdi2c not support or fail"); ++ } ++ } ++} ++ ++static int fts_get_chip_types( ++ struct fts_ts_data *ts_data, ++ u8 id_h, u8 id_l, bool fw_valid) ++{ ++ int i = 0; ++ struct ft_chip_t ctype[] = FTS_CHIP_TYPE_MAPPING; ++ u32 ctype_entries = sizeof(ctype) / sizeof(struct ft_chip_t); ++ ++ if ((0x0 == id_h) || (0x0 == id_l)) { ++ FTS_ERROR("id_h/id_l is 0"); ++ return -EINVAL; ++ } ++ ++ FTS_DEBUG("verify id:0x%02x%02x", id_h, id_l); ++ for (i = 0; i < ctype_entries; i++) { ++ if (VALID == fw_valid) { ++ if ((id_h == ctype[i].chip_idh) && (id_l == ctype[i].chip_idl)) ++ break; ++ } else { ++ if (((id_h == ctype[i].rom_idh) && (id_l == ctype[i].rom_idl)) ++ || ((id_h == ctype[i].pb_idh) && (id_l == ctype[i].pb_idl)) ++ || ((id_h == ctype[i].bl_idh) && (id_l == ctype[i].bl_idl))) ++ break; ++ } ++ } ++ ++ if (i >= ctype_entries) { ++ return -ENODATA; ++ } ++ ++ ts_data->ic_info.ids = ctype[i]; ++ return 0; ++} ++ ++static int fts_read_bootid(struct fts_ts_data *ts_data, u8 *id) ++{ ++ int ret = 0; ++ u8 chip_id[2] = { 0 }; ++ u8 id_cmd[4] = { 0 }; ++ u32 id_cmd_len = 0; ++ ++ id_cmd[0] = FTS_CMD_START1; ++ id_cmd[1] = FTS_CMD_START2; ++ ret = fts_write(id_cmd, 2); ++ if (ret < 0) { ++ FTS_ERROR("start cmd write fail"); ++ return ret; ++ } ++ ++ msleep(FTS_CMD_START_DELAY); ++ id_cmd[0] = FTS_CMD_READ_ID; ++ id_cmd[1] = id_cmd[2] = id_cmd[3] = 0x00; ++ if (ts_data->ic_info.is_incell) ++ id_cmd_len = FTS_CMD_READ_ID_LEN_INCELL; ++ else ++ id_cmd_len = FTS_CMD_READ_ID_LEN; ++ ret = fts_read(id_cmd, id_cmd_len, chip_id, 2); ++ if ((ret < 0) || (0x0 == chip_id[0]) || (0x0 == chip_id[1])) { ++ FTS_ERROR("read boot id fail,read:0x%02x%02x", chip_id[0], chip_id[1]); ++ return -EIO; ++ } ++ ++ id[0] = chip_id[0]; ++ id[1] = chip_id[1]; ++ return 0; ++} ++ ++/***************************************************************************** ++* Name: fts_get_ic_information ++* Brief: read chip id to get ic information, after run the function, driver w- ++* ill know which IC is it. ++* If cant get the ic information, maybe not focaltech's touch IC, need ++* unregister the driver ++* Input: ++* Output: ++* Return: return 0 if get correct ic information, otherwise return error code ++*****************************************************************************/ ++static int fts_get_ic_information(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ int cnt = 0; ++ u8 chip_id[2] = { 0 }; ++ ++ ts_data->ic_info.is_incell = FTS_CHIP_IDC; ++ ts_data->ic_info.hid_supported = FTS_HID_SUPPORTTED; ++ ++ ++ do { ++ ret = fts_read_reg(FTS_REG_CHIP_ID, &chip_id[0]); ++ ret = fts_read_reg(FTS_REG_CHIP_ID2, &chip_id[1]); ++ if ((ret < 0) || (0x0 == chip_id[0]) || (0x0 == chip_id[1])) { ++ FTS_DEBUG("i2c read invalid, read:0x%02x%02x", ++ chip_id[0], chip_id[1]); ++ if (((cnt + 1) * INTERVAL_READ_REG) >= TIMEOUT_READ_REG) ++ return ret; ++ } else { ++ ret = fts_get_chip_types(ts_data, chip_id[0], chip_id[1], VALID); ++ if (!ret) ++ break; ++ else ++ FTS_DEBUG("TP not ready, read:0x%02x%02x", ++ chip_id[0], chip_id[1]); ++ } ++ ++ cnt++; ++ msleep(INTERVAL_READ_REG); ++ } while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG); ++ ++ if ((cnt * INTERVAL_READ_REG) >= TIMEOUT_READ_REG) { ++ FTS_INFO("fw is invalid, need read boot id"); ++ if (ts_data->ic_info.hid_supported) { ++ fts_hid2std(); ++ } ++ ++ ret = fts_read_bootid(ts_data, &chip_id[0]); ++ if (ret < 0) { ++ FTS_ERROR("read boot id fail"); ++ return ret; ++ } ++ ++ ret = fts_get_chip_types(ts_data, chip_id[0], chip_id[1], INVALID); ++ if (ret < 0) { ++ FTS_ERROR("can't get ic informaton"); ++ return ret; ++ } ++ } ++ ++ FTS_INFO("get ic information, chip id = 0x%02x%02x", ++ ts_data->ic_info.ids.chip_idh, ts_data->ic_info.ids.chip_idl); ++ ++ return 0; ++} ++ ++/***************************************************************************** ++* Reprot related ++*****************************************************************************/ ++static void fts_show_touch_buffer(u8 *data, int datalen) ++{ ++ int i = 0; ++ int count = 0; ++ char *tmpbuf = NULL; ++ ++ tmpbuf = kzalloc(1024, GFP_KERNEL); ++ if (!tmpbuf) { ++ FTS_ERROR("tmpbuf zalloc fail"); ++ return; ++ } ++ ++ for (i = 0; i < datalen; i++) { ++ count += snprintf(tmpbuf + count, 1024 - count, "%02X,", data[i]); ++ if (count >= 1024) ++ break; ++ } ++ FTS_DEBUG("point buffer:%s", tmpbuf); ++ ++ if (tmpbuf) { ++ kfree(tmpbuf); ++ tmpbuf = NULL; ++ } ++} ++ ++void fts_release_all_finger(void) ++{ ++ struct input_dev *input_dev = fts_data->input_dev; ++#if FTS_MT_PROTOCOL_B_EN ++ u32 finger_count = 0; ++ u32 max_touches = fts_data->pdata->max_touch_number; ++#endif ++ ++ FTS_FUNC_ENTER(); ++ mutex_lock(&fts_data->report_mutex); ++#if FTS_MT_PROTOCOL_B_EN ++ for (finger_count = 0; finger_count < max_touches; finger_count++) { ++ input_mt_slot(input_dev, finger_count); ++ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false); ++ } ++#else ++ input_mt_sync(input_dev); ++#endif ++ input_report_key(input_dev, BTN_TOUCH, 0); ++ input_sync(input_dev); ++ ++ fts_data->touchs = 0; ++ fts_data->key_state = 0; ++ mutex_unlock(&fts_data->report_mutex); ++ FTS_FUNC_EXIT(); ++} ++ ++/***************************************************************************** ++* Name: fts_input_report_key ++* Brief: process key events,need report key-event if key enable. ++* if point's coordinate is in (x_dim-50,y_dim-50) ~ (x_dim+50,y_dim+50), ++* need report it to key event. ++* x_dim: parse from dts, means key x_coordinate, dimension:+-50 ++* y_dim: parse from dts, means key y_coordinate, dimension:+-50 ++* Input: ++* Output: ++* Return: return 0 if it's key event, otherwise return error code ++*****************************************************************************/ ++static int fts_input_report_key(struct fts_ts_data *data, int index) ++{ ++ int i = 0; ++ int x = data->events[index].x; ++ int y = data->events[index].y; ++ int *x_dim = &data->pdata->key_x_coords[0]; ++ int *y_dim = &data->pdata->key_y_coords[0]; ++ ++ if (!data->pdata->have_key) { ++ return -EINVAL; ++ } ++ for (i = 0; i < data->pdata->key_number; i++) { ++ if ((x >= x_dim[i] - FTS_KEY_DIM) && (x <= x_dim[i] + FTS_KEY_DIM) && ++ (y >= y_dim[i] - FTS_KEY_DIM) && (y <= y_dim[i] + FTS_KEY_DIM)) { ++ if (EVENT_DOWN(data->events[index].flag) ++ && !(data->key_state & (1 << i))) { ++ input_report_key(data->input_dev, data->pdata->keys[i], 1); ++ data->key_state |= (1 << i); ++ FTS_DEBUG("Key%d(%d,%d) DOWN!", i, x, y); ++ } else if (EVENT_UP(data->events[index].flag) ++ && (data->key_state & (1 << i))) { ++ input_report_key(data->input_dev, data->pdata->keys[i], 0); ++ data->key_state &= ~(1 << i); ++ FTS_DEBUG("Key%d(%d,%d) Up!", i, x, y); ++ } ++ return 0; ++ } ++ } ++ return -EINVAL; ++} ++ ++#if FTS_MT_PROTOCOL_B_EN ++static int fts_input_report_b(struct fts_ts_data *data) ++{ ++ int i = 0; ++ int uppoint = 0; ++ int touchs = 0; ++ bool va_reported = false; ++ u32 max_touch_num = data->pdata->max_touch_number; ++ struct ts_event *events = data->events; ++ ++ for (i = 0; i < data->touch_point; i++) { ++ if (fts_input_report_key(data, i) == 0) { ++ continue; ++ } ++ ++ va_reported = true; ++ input_mt_slot(data->input_dev, events[i].id); ++ ++ if (EVENT_DOWN(events[i].flag)) { ++ input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, true); ++ ++#if FTS_REPORT_PRESSURE_EN ++ if (events[i].p <= 0) { ++ events[i].p = 0x3f; ++ } ++ input_report_abs(data->input_dev, ABS_MT_PRESSURE, events[i].p); ++#endif ++ if (events[i].area <= 0) { ++ events[i].area = 0x09; ++ } ++ input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, events[i].area); ++ input_report_abs(data->input_dev, ABS_MT_POSITION_X, events[i].x); ++ input_report_abs(data->input_dev, ABS_MT_POSITION_Y, events[i].y); ++ ++ touchs |= BIT(events[i].id); ++ data->touchs |= BIT(events[i].id); ++ ++ if ((data->log_level >= 2) || ++ ((1 == data->log_level) && (FTS_TOUCH_DOWN == events[i].flag))) { ++ FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!", ++ events[i].id, ++ events[i].x, events[i].y, ++ events[i].p, events[i].area); ++ } ++ } else { ++ uppoint++; ++ input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, false); ++ data->touchs &= ~BIT(events[i].id); ++ if (data->log_level >= 1) { ++ FTS_DEBUG("[B]P%d UP!", events[i].id); ++ } ++ } ++ } ++ ++ if (unlikely(data->touchs ^ touchs)) { ++ for (i = 0; i < max_touch_num; i++) { ++ if (BIT(i) & (data->touchs ^ touchs)) { ++ if (data->log_level >= 1) { ++ FTS_DEBUG("[B]P%d UP!", i); ++ } ++ va_reported = true; ++ input_mt_slot(data->input_dev, i); ++ input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, false); ++ } ++ } ++ } ++ data->touchs = touchs; ++ ++ if (va_reported) { ++ /* touchs==0, there's no point but key */ ++ if (EVENT_NO_DOWN(data) || (!touchs)) { ++ if (data->log_level >= 1) { ++ FTS_DEBUG("[B]Points All Up!"); ++ } ++ input_report_key(data->input_dev, BTN_TOUCH, 0); ++ } else { ++ input_report_key(data->input_dev, BTN_TOUCH, 1); ++ } ++ } ++ ++ input_sync(data->input_dev); ++ return 0; ++} ++ ++#else ++static int fts_input_report_a(struct fts_ts_data *data) ++{ ++ int i = 0; ++ int touchs = 0; ++ bool va_reported = false; ++ struct ts_event *events = data->events; ++ ++ for (i = 0; i < data->touch_point; i++) { ++ if (fts_input_report_key(data, i) == 0) { ++ continue; ++ } ++ ++ va_reported = true; ++ if (EVENT_DOWN(events[i].flag)) { ++ input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, events[i].id); ++#if FTS_REPORT_PRESSURE_EN ++ if (events[i].p <= 0) { ++ events[i].p = 0x3f; ++ } ++ input_report_abs(data->input_dev, ABS_MT_PRESSURE, events[i].p); ++#endif ++ if (events[i].area <= 0) { ++ events[i].area = 0x09; ++ } ++ input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, events[i].area); ++ ++ input_report_abs(data->input_dev, ABS_MT_POSITION_X, events[i].x); ++ input_report_abs(data->input_dev, ABS_MT_POSITION_Y, events[i].y); ++ ++ input_mt_sync(data->input_dev); ++ ++ if ((data->log_level >= 2) || ++ ((1 == data->log_level) && (FTS_TOUCH_DOWN == events[i].flag))) { ++ FTS_DEBUG("[A]P%d(%d, %d)[p:%d,tm:%d] DOWN!", ++ events[i].id, ++ events[i].x, events[i].y, ++ events[i].p, events[i].area); ++ } ++ touchs++; ++ } ++ } ++ ++ /* last point down, current no point but key */ ++ if (data->touchs && !touchs) { ++ va_reported = true; ++ } ++ data->touchs = touchs; ++ ++ if (va_reported) { ++ if (EVENT_NO_DOWN(data)) { ++ if (data->log_level >= 1) { ++ FTS_DEBUG("[A]Points All Up!"); ++ } ++ input_report_key(data->input_dev, BTN_TOUCH, 0); ++ input_mt_sync(data->input_dev); ++ } else { ++ input_report_key(data->input_dev, BTN_TOUCH, 1); ++ } ++ } ++ ++ input_sync(data->input_dev); ++ return 0; ++} ++#endif ++ ++static int fts_read_touchdata(struct fts_ts_data *data) ++{ ++ int ret = 0; ++ u8 *buf = data->point_buf; ++ ++ memset(buf, 0xFF, data->pnt_buf_size); ++ buf[0] = 0x01; ++ ++ ++#if FTS_GESTURE_EN ++ if (data->gesture_mode) { ++ if (0 == fts_gesture_readdata(data, NULL)) { ++ FTS_INFO("succuss to get gesture data in irq handler"); ++ return 1; ++ } ++ } ++#endif ++ ++ ret = fts_read(buf, 1, buf + 1, data->pnt_buf_size - 1); ++ if (ret < 0) { ++ FTS_ERROR("read touchdata failed, ret:%d", ret); ++ return ret; ++ } ++ ++ if (data->log_level >= 3) { ++ fts_show_touch_buffer(buf, data->pnt_buf_size); ++ } ++ ++ return 0; ++} ++ ++static int fts_read_parse_touchdata(struct fts_ts_data *data) ++{ ++ int ret = 0; ++ int i = 0; ++ u8 pointid = 0; ++ int base = 0; ++ struct ts_event *events = data->events; ++ int max_touch_num = data->pdata->max_touch_number; ++ u8 *buf = data->point_buf; ++ ++ ret = fts_read_touchdata(data); ++ if (ret) { ++ return ret; ++ } ++ ++ data->point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F; ++ data->touch_point = 0; ++ ++ if (data->ic_info.is_incell) { ++ if ((data->point_num == 0x0F) && (buf[2] == 0xFF) && (buf[3] == 0xFF) ++ && (buf[4] == 0xFF) && (buf[5] == 0xFF) && (buf[6] == 0xFF)) { ++ FTS_DEBUG("touch buff is 0xff, need recovery state"); ++ fts_release_all_finger(); ++ fts_tp_state_recovery(data); ++ return -EIO; ++ } ++ } ++ ++ if (data->point_num > max_touch_num) { ++ FTS_INFO("invalid point_num(%d)", data->point_num); ++ return -EIO; ++ } ++ ++ for (i = 0; i < max_touch_num; i++) { ++ base = FTS_ONE_TCH_LEN * i; ++ pointid = (buf[FTS_TOUCH_ID_POS + base]) >> 4; ++ if (pointid >= FTS_MAX_ID) ++ break; ++ else if (pointid >= max_touch_num) { ++ FTS_ERROR("ID(%d) beyond max_touch_number", pointid); ++ return -EINVAL; ++ } ++ ++ data->touch_point++; ++ events[i].x = ((buf[FTS_TOUCH_X_H_POS + base] & 0x0F) << 8) + ++ (buf[FTS_TOUCH_X_L_POS + base] & 0xFF); ++ events[i].y = ((buf[FTS_TOUCH_Y_H_POS + base] & 0x0F) << 8) + ++ (buf[FTS_TOUCH_Y_L_POS + base] & 0xFF); ++ events[i].flag = buf[FTS_TOUCH_EVENT_POS + base] >> 6; ++ events[i].id = buf[FTS_TOUCH_ID_POS + base] >> 4; ++ events[i].area = buf[FTS_TOUCH_AREA_POS + base] >> 4; ++ events[i].p = buf[FTS_TOUCH_PRE_POS + base]; ++ ++ if (EVENT_DOWN(events[i].flag) && (data->point_num == 0)) { ++ FTS_INFO("abnormal touch data from fw"); ++ return -EIO; ++ } ++ } ++ ++ if (data->touch_point == 0) { ++ FTS_INFO("no touch point information"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static void fts_irq_read_report(void) ++{ ++ int ret = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_set_intr(1); ++#endif ++ ++#if FTS_POINT_REPORT_CHECK_EN ++ fts_prc_queue_work(ts_data); ++#endif ++ ++ ret = fts_read_parse_touchdata(ts_data); ++ if (ret == 0) { ++ mutex_lock(&ts_data->report_mutex); ++#if FTS_MT_PROTOCOL_B_EN ++ fts_input_report_b(ts_data); ++#else ++ fts_input_report_a(ts_data); ++#endif ++ mutex_unlock(&ts_data->report_mutex); ++ } ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_set_intr(0); ++#endif ++} ++ ++static irqreturn_t fts_irq_handler(int irq, void *data) ++{ ++ fts_irq_read_report(); ++ return IRQ_HANDLED; ++} ++ ++static int fts_irq_registration(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ struct fts_ts_platform_data *pdata = ts_data->pdata; ++ ++ ts_data->irq = gpio_to_irq(pdata->irq_gpio); ++ pdata->irq_gpio_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; ++ FTS_INFO("irq:%d, flag:%x", ts_data->irq, pdata->irq_gpio_flags); ++ ret = request_threaded_irq(ts_data->irq, NULL, fts_irq_handler, ++ pdata->irq_gpio_flags, ++ FTS_DRIVER_NAME, ts_data); ++ ++ return ret; ++} ++ ++static int fts_input_init(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ int key_num = 0; ++ struct fts_ts_platform_data *pdata = ts_data->pdata; ++ struct input_dev *input_dev; ++ ++ FTS_FUNC_ENTER(); ++ input_dev = input_allocate_device(); ++ if (!input_dev) { ++ FTS_ERROR("Failed to allocate memory for input device"); ++ return -ENOMEM; ++ } ++ ++ /* Init and register Input device */ ++ input_dev->name = FTS_DRIVER_NAME; ++ ++ input_dev->id.bustype = BUS_I2C; ++ input_dev->dev.parent = ts_data->dev; ++ ++ input_set_drvdata(input_dev, ts_data); ++ ++ __set_bit(EV_SYN, input_dev->evbit); ++ __set_bit(EV_ABS, input_dev->evbit); ++ __set_bit(EV_KEY, input_dev->evbit); ++ __set_bit(BTN_TOUCH, input_dev->keybit); ++ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); ++ ++ if (pdata->have_key) { ++ FTS_INFO("set key capabilities"); ++ for (key_num = 0; key_num < pdata->key_number; key_num++) ++ input_set_capability(input_dev, EV_KEY, pdata->keys[key_num]); ++ } ++ ++#if FTS_MT_PROTOCOL_B_EN ++ input_mt_init_slots(input_dev, pdata->max_touch_number, INPUT_MT_DIRECT); ++#else ++ input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 0x0F, 0, 0); ++#endif ++ input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min, pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min, pdata->y_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0); ++#if FTS_REPORT_PRESSURE_EN ++ input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 0xFF, 0, 0); ++#endif ++ ++ ret = input_register_device(input_dev); ++ if (ret) { ++ FTS_ERROR("Input device registration failed"); ++ input_set_drvdata(input_dev, NULL); ++ input_free_device(input_dev); ++ input_dev = NULL; ++ return ret; ++ } ++ ++ ts_data->input_dev = input_dev; ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++static int fts_report_buffer_init(struct fts_ts_data *ts_data) ++{ ++ int point_num = 0; ++ int events_num = 0; ++ ++ ++ point_num = ts_data->pdata->max_touch_number; ++ ts_data->pnt_buf_size = point_num * FTS_ONE_TCH_LEN + 3; ++ ts_data->point_buf = (u8 *)kzalloc(ts_data->pnt_buf_size + 1, GFP_KERNEL); ++ if (!ts_data->point_buf) { ++ FTS_ERROR("failed to alloc memory for point buf"); ++ return -ENOMEM; ++ } ++ ++ events_num = point_num * sizeof(struct ts_event); ++ ts_data->events = (struct ts_event *)kzalloc(events_num, GFP_KERNEL); ++ if (!ts_data->events) { ++ FTS_ERROR("failed to alloc memory for point events"); ++ kfree_safe(ts_data->point_buf); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++#if FTS_POWER_SOURCE_CUST_EN ++/***************************************************************************** ++* Power Control ++*****************************************************************************/ ++#if FTS_PINCTRL_EN ++static int fts_pinctrl_init(struct fts_ts_data *ts) ++{ ++ int ret = 0; ++ ++ ts->pinctrl = devm_pinctrl_get(ts->dev); ++ if (IS_ERR_OR_NULL(ts->pinctrl)) { ++ FTS_ERROR("Failed to get pinctrl, please check dts"); ++ ret = PTR_ERR(ts->pinctrl); ++ goto err_pinctrl_get; ++ } ++ ++ ts->pins_active = pinctrl_lookup_state(ts->pinctrl, "pmx_ts_active"); ++ if (IS_ERR_OR_NULL(ts->pins_active)) { ++ FTS_ERROR("Pin state[active] not found"); ++ ret = PTR_ERR(ts->pins_active); ++ goto err_pinctrl_lookup; ++ } ++ ++ ts->pins_suspend = pinctrl_lookup_state(ts->pinctrl, "pmx_ts_suspend"); ++ if (IS_ERR_OR_NULL(ts->pins_suspend)) { ++ FTS_ERROR("Pin state[suspend] not found"); ++ ret = PTR_ERR(ts->pins_suspend); ++ goto err_pinctrl_lookup; ++ } ++ ++ ts->pins_release = pinctrl_lookup_state(ts->pinctrl, "pmx_ts_release"); ++ if (IS_ERR_OR_NULL(ts->pins_release)) { ++ FTS_ERROR("Pin state[release] not found"); ++ ret = PTR_ERR(ts->pins_release); ++ } ++ ++ return 0; ++err_pinctrl_lookup: ++ if (ts->pinctrl) { ++ devm_pinctrl_put(ts->pinctrl); ++ } ++err_pinctrl_get: ++ ts->pinctrl = NULL; ++ ts->pins_release = NULL; ++ ts->pins_suspend = NULL; ++ ts->pins_active = NULL; ++ return ret; ++} ++ ++static int fts_pinctrl_select_normal(struct fts_ts_data *ts) ++{ ++ int ret = 0; ++ ++ if (ts->pinctrl && ts->pins_active) { ++ ret = pinctrl_select_state(ts->pinctrl, ts->pins_active); ++ if (ret < 0) { ++ FTS_ERROR("Set normal pin state error:%d", ret); ++ } ++ } ++ ++ return ret; ++} ++ ++static int fts_pinctrl_select_suspend(struct fts_ts_data *ts) ++{ ++ int ret = 0; ++ ++ if (ts->pinctrl && ts->pins_suspend) { ++ ret = pinctrl_select_state(ts->pinctrl, ts->pins_suspend); ++ if (ret < 0) { ++ FTS_ERROR("Set suspend pin state error:%d", ret); ++ } ++ } ++ ++ return ret; ++} ++ ++static int fts_pinctrl_select_release(struct fts_ts_data *ts) ++{ ++ int ret = 0; ++ ++ if (ts->pinctrl) { ++ if (IS_ERR_OR_NULL(ts->pins_release)) { ++ devm_pinctrl_put(ts->pinctrl); ++ ts->pinctrl = NULL; ++ } else { ++ ret = pinctrl_select_state(ts->pinctrl, ts->pins_release); ++ if (ret < 0) ++ FTS_ERROR("Set gesture pin state error:%d", ret); ++ } ++ } ++ ++ return ret; ++} ++#endif /* FTS_PINCTRL_EN */ ++ ++static int fts_power_source_ctrl(struct fts_ts_data *ts_data, int enable) ++{ ++ int ret = 0; ++ ++ if (IS_ERR_OR_NULL(ts_data->vdd)) { ++ FTS_ERROR("vdd is invalid"); ++ return -EINVAL; ++ } ++ ++ FTS_FUNC_ENTER(); ++ if (enable) { ++ if (ts_data->power_disabled) { ++ FTS_DEBUG("regulator enable !"); ++ gpio_direction_output(ts_data->pdata->reset_gpio, 0); ++ msleep(1); ++ ret = regulator_enable(ts_data->vdd); ++ if (ret) { ++ FTS_ERROR("enable vdd regulator failed,ret=%d", ret); ++ } ++ ++ if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) { ++ ret = regulator_enable(ts_data->vcc_i2c); ++ if (ret) { ++ FTS_ERROR("enable vcc_i2c regulator failed,ret=%d", ret); ++ } ++ } ++ ts_data->power_disabled = false; ++ } ++ } else { ++ if (!ts_data->power_disabled) { ++ FTS_DEBUG("regulator disable !"); ++ gpio_direction_output(ts_data->pdata->reset_gpio, 0); ++ msleep(1); ++ ret = regulator_disable(ts_data->vdd); ++ if (ret) { ++ FTS_ERROR("disable vdd regulator failed,ret=%d", ret); ++ } ++ if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) { ++ ret = regulator_disable(ts_data->vcc_i2c); ++ if (ret) { ++ FTS_ERROR("disable vcc_i2c regulator failed,ret=%d", ret); ++ } ++ } ++ ts_data->power_disabled = true; ++ } ++ } ++ ++ FTS_FUNC_EXIT(); ++ return ret; ++} ++ ++/***************************************************************************** ++* Name: fts_power_source_init ++* Brief: Init regulator power:vdd/vcc_io(if have), generally, no vcc_io ++* vdd---->vdd-supply in dts, kernel will auto add "-supply" to parse ++* Must be call after fts_gpio_configure() execute,because this function ++* will operate reset-gpio which request gpio in fts_gpio_configure() ++* Input: ++* Output: ++* Return: return 0 if init power successfully, otherwise return error code ++*****************************************************************************/ ++static int fts_power_source_init(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ ++ FTS_FUNC_ENTER(); ++ ts_data->vdd = regulator_get(ts_data->dev, "vdd"); ++ if (IS_ERR_OR_NULL(ts_data->vdd)) { ++ ret = PTR_ERR(ts_data->vdd); ++ FTS_ERROR("get vdd regulator failed,ret=%d", ret); ++ return ret; ++ } ++ ++ if (regulator_count_voltages(ts_data->vdd) > 0) { ++ ret = regulator_set_voltage(ts_data->vdd, FTS_VTG_MIN_UV, ++ FTS_VTG_MAX_UV); ++ if (ret) { ++ FTS_ERROR("vdd regulator set_vtg failed ret=%d", ret); ++ regulator_put(ts_data->vdd); ++ return ret; ++ } ++ } ++ ++ ts_data->vcc_i2c = regulator_get(ts_data->dev, "vcc_i2c"); ++ if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) { ++ if (regulator_count_voltages(ts_data->vcc_i2c) > 0) { ++ ret = regulator_set_voltage(ts_data->vcc_i2c, ++ FTS_I2C_VTG_MIN_UV, ++ FTS_I2C_VTG_MAX_UV); ++ if (ret) { ++ FTS_ERROR("vcc_i2c regulator set_vtg failed,ret=%d", ret); ++ regulator_put(ts_data->vcc_i2c); ++ } ++ } ++ } ++ ++#if FTS_PINCTRL_EN ++ fts_pinctrl_init(ts_data); ++ fts_pinctrl_select_normal(ts_data); ++#endif ++ ++ ts_data->power_disabled = true; ++ ret = fts_power_source_ctrl(ts_data, ENABLE); ++ if (ret) { ++ FTS_ERROR("fail to enable power(regulator)"); ++ } ++ ++ FTS_FUNC_EXIT(); ++ return ret; ++} ++ ++static int fts_power_source_exit(struct fts_ts_data *ts_data) ++{ ++#if FTS_PINCTRL_EN ++ fts_pinctrl_select_release(ts_data); ++#endif ++ ++ fts_power_source_ctrl(ts_data, DISABLE); ++ ++ if (!IS_ERR_OR_NULL(ts_data->vdd)) { ++ if (regulator_count_voltages(ts_data->vdd) > 0) ++ regulator_set_voltage(ts_data->vdd, 0, FTS_VTG_MAX_UV); ++ regulator_put(ts_data->vdd); ++ } ++ ++ if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) { ++ if (regulator_count_voltages(ts_data->vcc_i2c) > 0) ++ regulator_set_voltage(ts_data->vcc_i2c, 0, FTS_I2C_VTG_MAX_UV); ++ regulator_put(ts_data->vcc_i2c); ++ } ++ ++ return 0; ++} ++ ++static int fts_power_source_suspend(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ ++#if FTS_PINCTRL_EN ++ fts_pinctrl_select_suspend(ts_data); ++#endif ++ ++ ret = fts_power_source_ctrl(ts_data, DISABLE); ++ if (ret < 0) { ++ FTS_ERROR("power off fail, ret=%d", ret); ++ } ++ ++ return ret; ++} ++ ++static int fts_power_source_resume(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ ++#if FTS_PINCTRL_EN ++ fts_pinctrl_select_normal(ts_data); ++#endif ++ ++ ret = fts_power_source_ctrl(ts_data, ENABLE); ++ if (ret < 0) { ++ FTS_ERROR("power on fail, ret=%d", ret); ++ } ++ ++ return ret; ++} ++#endif /* FTS_POWER_SOURCE_CUST_EN */ ++ ++static int fts_gpio_configure(struct fts_ts_data *data) ++{ ++ int ret = 0; ++ ++ FTS_FUNC_ENTER(); ++ /* request irq gpio */ ++ if (gpio_is_valid(data->pdata->irq_gpio)) { ++ ret = gpio_request(data->pdata->irq_gpio, "fts_irq_gpio"); ++ if (ret) { ++ FTS_ERROR("[GPIO]irq gpio request failed"); ++ goto err_irq_gpio_req; ++ } ++ ++ ret = gpio_direction_input(data->pdata->irq_gpio); ++ if (ret) { ++ FTS_ERROR("[GPIO]set_direction for irq gpio failed"); ++ goto err_irq_gpio_dir; ++ } ++ } ++ ++ /* request reset gpio */ ++ if (gpio_is_valid(data->pdata->reset_gpio)) { ++ ret = gpio_request(data->pdata->reset_gpio, "fts_reset_gpio"); ++ if (ret) { ++ FTS_ERROR("[GPIO]reset gpio request failed"); ++ goto err_irq_gpio_dir; ++ } ++ ++ ret = gpio_direction_output(data->pdata->reset_gpio, 1); ++ if (ret) { ++ FTS_ERROR("[GPIO]set_direction for reset gpio failed"); ++ goto err_reset_gpio_dir; ++ } ++ } ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++ ++err_reset_gpio_dir: ++ if (gpio_is_valid(data->pdata->reset_gpio)) ++ gpio_free(data->pdata->reset_gpio); ++err_irq_gpio_dir: ++ if (gpio_is_valid(data->pdata->irq_gpio)) ++ gpio_free(data->pdata->irq_gpio); ++err_irq_gpio_req: ++ FTS_FUNC_EXIT(); ++ return ret; ++} ++ ++static int fts_get_dt_coords(struct device *dev, char *name, ++ struct fts_ts_platform_data *pdata) ++{ ++ int ret = 0; ++ u32 coords[FTS_COORDS_ARR_SIZE] = { 0 }; ++ struct property *prop; ++ struct device_node *np = dev->of_node; ++ int coords_size; ++ ++ prop = of_find_property(np, name, NULL); ++ if (!prop) ++ return -EINVAL; ++ if (!prop->value) ++ return -ENODATA; ++ ++ coords_size = prop->length / sizeof(u32); ++ if (coords_size != FTS_COORDS_ARR_SIZE) { ++ FTS_ERROR("invalid:%s, size:%d", name, coords_size); ++ return -EINVAL; ++ } ++ ++ ret = of_property_read_u32_array(np, name, coords, coords_size); ++ if (ret < 0) { ++ FTS_ERROR("Unable to read %s, please check dts", name); ++ pdata->x_min = FTS_X_MIN_DISPLAY_DEFAULT; ++ pdata->y_min = FTS_Y_MIN_DISPLAY_DEFAULT; ++ pdata->x_max = FTS_X_MAX_DISPLAY_DEFAULT; ++ pdata->y_max = FTS_Y_MAX_DISPLAY_DEFAULT; ++ return -ENODATA; ++ } else { ++ pdata->x_min = coords[0]; ++ pdata->y_min = coords[1]; ++ pdata->x_max = coords[2]; ++ pdata->y_max = coords[3]; ++ } ++ ++ FTS_INFO("display x(%d %d) y(%d %d)", pdata->x_min, pdata->x_max, ++ pdata->y_min, pdata->y_max); ++ return 0; ++} ++ ++static int fts_parse_dt(struct device *dev, struct fts_ts_platform_data *pdata) ++{ ++ int ret = 0; ++ struct device_node *np = dev->of_node; ++ u32 temp_val = 0; ++ ++ FTS_FUNC_ENTER(); ++ ++ ret = fts_get_dt_coords(dev, "focaltech,display-coords", pdata); ++ if (ret < 0) ++ FTS_ERROR("Unable to get display-coords"); ++ ++ /* key */ ++ pdata->have_key = of_property_read_bool(np, "focaltech,have-key"); ++ if (pdata->have_key) { ++ ret = of_property_read_u32(np, "focaltech,key-number", &pdata->key_number); ++ if (ret < 0) ++ FTS_ERROR("Key number undefined!"); ++ ++ ret = of_property_read_u32_array(np, "focaltech,keys", ++ pdata->keys, pdata->key_number); ++ if (ret < 0) ++ FTS_ERROR("Keys undefined!"); ++ else if (pdata->key_number > FTS_MAX_KEYS) ++ pdata->key_number = FTS_MAX_KEYS; ++ ++ ret = of_property_read_u32_array(np, "focaltech,key-x-coords", ++ pdata->key_x_coords, ++ pdata->key_number); ++ if (ret < 0) ++ FTS_ERROR("Key Y Coords undefined!"); ++ ++ ret = of_property_read_u32_array(np, "focaltech,key-y-coords", ++ pdata->key_y_coords, ++ pdata->key_number); ++ if (ret < 0) ++ FTS_ERROR("Key X Coords undefined!"); ++ ++ FTS_INFO("VK Number:%d, key:(%d,%d,%d), " ++ "coords:(%d,%d),(%d,%d),(%d,%d)", ++ pdata->key_number, ++ pdata->keys[0], pdata->keys[1], pdata->keys[2], ++ pdata->key_x_coords[0], pdata->key_y_coords[0], ++ pdata->key_x_coords[1], pdata->key_y_coords[1], ++ pdata->key_x_coords[2], pdata->key_y_coords[2]); ++ } ++ ++ /* reset, irq gpio info */ ++ pdata->reset_gpio = of_get_named_gpio_flags(np, "focaltech,reset-gpio", ++ 0, &pdata->reset_gpio_flags); ++ if (pdata->reset_gpio < 0) ++ FTS_ERROR("Unable to get reset_gpio"); ++ ++ pdata->irq_gpio = of_get_named_gpio_flags(np, "focaltech,irq-gpio", ++ 0, &pdata->irq_gpio_flags); ++ if (pdata->irq_gpio < 0) ++ FTS_ERROR("Unable to get irq_gpio"); ++ ++ ret = of_property_read_u32(np, "focaltech,max-touch-number", &temp_val); ++ if (ret < 0) { ++ FTS_ERROR("Unable to get max-touch-number, please check dts"); ++ pdata->max_touch_number = FTS_MAX_POINTS_SUPPORT; ++ } else { ++ if (temp_val < 2) ++ pdata->max_touch_number = 2; /* max_touch_number must >= 2 */ ++ else if (temp_val > FTS_MAX_POINTS_SUPPORT) ++ pdata->max_touch_number = FTS_MAX_POINTS_SUPPORT; ++ else ++ pdata->max_touch_number = temp_val; ++ } ++ ++ FTS_INFO("max touch number:%d, irq gpio:%d, reset gpio:%d", ++ pdata->max_touch_number, pdata->irq_gpio, pdata->reset_gpio); ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++#if defined(CONFIG_FB) ++static void fts_resume_work(struct work_struct *work) ++{ ++ struct fts_ts_data *ts_data = container_of(work, struct fts_ts_data, ++ resume_work); ++ ++ fts_ts_resume(ts_data->dev); ++} ++ ++static int fb_notifier_callback(struct notifier_block *self, ++ unsigned long event, void *data) ++{ ++ struct fb_event *evdata = data; ++ int *blank = NULL; ++ struct fts_ts_data *ts_data = container_of(self, struct fts_ts_data, ++ fb_notif); ++ ++ if (!(event == FB_EVENT_BLANK)) { ++ FTS_INFO("event(%lu) do not need process\n", event); ++ return 0; ++ } ++ ++ blank = evdata->data; ++ FTS_INFO("FB event:%lu,blank:%d", event, *blank); ++ switch (*blank) { ++ case FB_BLANK_UNBLANK: ++ if (FB_EVENT_BLANK == event) { ++ queue_work(fts_data->ts_workqueue, &fts_data->resume_work); ++ } ++ break; ++ case FB_BLANK_POWERDOWN: ++ if (FB_EVENT_BLANK == event) { ++ FTS_INFO("suspend: event = %lu, not care\n", event); ++ } ++ break; ++ default: ++ FTS_INFO("FB BLANK(%d) do not need process\n", *blank); ++ break; ++ } ++ ++ return 0; ++} ++#elif defined(CONFIG_HAS_EARLYSUSPEND) ++static void fts_ts_early_suspend(struct early_suspend *handler) ++{ ++ struct fts_ts_data *ts_data = container_of(handler, struct fts_ts_data, ++ early_suspend); ++ ++ fts_ts_suspend(ts_data->dev); ++} ++ ++static void fts_ts_late_resume(struct early_suspend *handler) ++{ ++ struct fts_ts_data *ts_data = container_of(handler, struct fts_ts_data, ++ early_suspend); ++ ++ fts_ts_resume(ts_data->dev); ++} ++#endif ++ ++static int fts_ts_probe_entry(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ int pdata_size = sizeof(struct fts_ts_platform_data); ++ ++ FTS_FUNC_ENTER(); ++ FTS_INFO("%s", FTS_DRIVER_VERSION); ++ ts_data->pdata = kzalloc(pdata_size, GFP_KERNEL); ++ if (!ts_data->pdata) { ++ FTS_ERROR("allocate memory for platform_data fail"); ++ return -ENOMEM; ++ } ++ ++ if (ts_data->dev->of_node) { ++ ret = fts_parse_dt(ts_data->dev, ts_data->pdata); ++ if (ret) ++ FTS_ERROR("device-tree parse fail"); ++ } else { ++ if (ts_data->dev->platform_data) { ++ memcpy(ts_data->pdata, ts_data->dev->platform_data, pdata_size); ++ } else { ++ FTS_ERROR("platform_data is null"); ++ return -ENODEV; ++ } ++ } ++ ++ ts_data->ts_workqueue = create_singlethread_workqueue("fts_wq"); ++ if (!ts_data->ts_workqueue) { ++ FTS_ERROR("create fts workqueue fail"); ++ } ++ ++ spin_lock_init(&ts_data->irq_lock); ++ mutex_init(&ts_data->report_mutex); ++ mutex_init(&ts_data->bus_lock); ++ ++ /* Init communication interface */ ++ ret = fts_bus_init(ts_data); ++ if (ret) { ++ FTS_ERROR("bus initialize fail"); ++ goto err_bus_init; ++ } ++ ++ ret = fts_input_init(ts_data); ++ if (ret) { ++ FTS_ERROR("input initialize fail"); ++ goto err_input_init; ++ } ++ ++ ret = fts_report_buffer_init(ts_data); ++ if (ret) { ++ FTS_ERROR("report buffer init fail"); ++ goto err_report_buffer; ++ } ++ ++ ret = fts_gpio_configure(ts_data); ++ if (ret) { ++ FTS_ERROR("configure the gpios fail"); ++ goto err_gpio_config; ++ } ++ ++#if FTS_POWER_SOURCE_CUST_EN ++ ret = fts_power_source_init(ts_data); ++ if (ret) { ++ FTS_ERROR("fail to get power(regulator)"); ++ goto err_power_init; ++ } ++#endif ++ ++#if (!FTS_CHIP_IDC) ++ fts_reset_proc(200); ++#endif ++ ++ ret = fts_get_ic_information(ts_data); ++ if (ret) { ++ FTS_ERROR("not focal IC, unregister driver"); ++ goto err_irq_req; ++ } ++ ++#if FTS_EX_FUNC_EN ++ ret = fts_create_apk_debug_channel(ts_data); ++ if (ret) { ++ FTS_ERROR("create apk debug node fail"); ++ } ++ ++ ret = fts_create_sysfs(ts_data); ++ if (ret) { ++ FTS_ERROR("create sysfs node fail"); ++ } ++#endif ++ ++#if FTS_POINT_REPORT_CHECK_EN ++ ret = fts_point_report_check_init(ts_data); ++ if (ret) { ++ FTS_ERROR("init point report check fail"); ++ } ++#endif ++ ++#if FTS_EX_MODE_EN ++ ret = fts_ex_mode_init(ts_data); ++ if (ret) { ++ FTS_ERROR("init glove/cover/charger fail"); ++ } ++#endif ++ ++#if FTS_GESTURE_EN ++ ret = fts_gesture_init(ts_data); ++ if (ret) { ++ FTS_ERROR("init gesture fail"); ++ } ++#endif ++ ++ ++#if FTS_ESDCHECK_EN ++ ret = fts_esdcheck_init(ts_data); ++ if (ret) { ++ FTS_ERROR("init esd check fail"); ++ } ++#endif ++ ++ ret = fts_irq_registration(ts_data); ++ if (ret) { ++ FTS_ERROR("request irq failed"); ++ goto err_irq_req; ++ } ++ ++#if FTS_AUTO_UPGRADE_EN ++ ret = fts_fwupg_init(ts_data); ++ if (ret) { ++ FTS_ERROR("init fw upgrade fail"); ++ } ++#endif ++ ++#if defined(CONFIG_FB) ++ /*if (ts_data->ts_workqueue) { ++ INIT_WORK(&ts_data->resume_work, fts_resume_work); ++ } ++ ts_data->fb_notif.notifier_call = fb_notifier_callback; ++ ret = fb_register_client(&ts_data->fb_notif); ++ if (ret) { ++ FTS_ERROR("[FB]Unable to register fb_notifier: %d", ret); ++ }*/ ++#elif defined(CONFIG_HAS_EARLYSUSPEND) ++ ts_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + FTS_SUSPEND_LEVEL; ++ ts_data->early_suspend.suspend = fts_ts_early_suspend; ++ ts_data->early_suspend.resume = fts_ts_late_resume; ++ register_early_suspend(&ts_data->early_suspend); ++#endif ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++ ++err_irq_req: ++#if FTS_POWER_SOURCE_CUST_EN ++err_power_init: ++ fts_power_source_exit(ts_data); ++#endif ++ if (gpio_is_valid(ts_data->pdata->reset_gpio)) ++ gpio_free(ts_data->pdata->reset_gpio); ++ if (gpio_is_valid(ts_data->pdata->irq_gpio)) ++ gpio_free(ts_data->pdata->irq_gpio); ++err_gpio_config: ++ kfree_safe(ts_data->point_buf); ++ kfree_safe(ts_data->events); ++err_report_buffer: ++ input_unregister_device(ts_data->input_dev); ++err_input_init: ++ if (ts_data->ts_workqueue) ++ destroy_workqueue(ts_data->ts_workqueue); ++err_bus_init: ++ kfree_safe(ts_data->bus_tx_buf); ++ kfree_safe(ts_data->bus_rx_buf); ++ kfree_safe(ts_data->pdata); ++ ++ FTS_FUNC_EXIT(); ++ return ret; ++} ++ ++static int fts_ts_remove_entry(struct fts_ts_data *ts_data) ++{ ++ FTS_FUNC_ENTER(); ++ ++#if FTS_POINT_REPORT_CHECK_EN ++ fts_point_report_check_exit(ts_data); ++#endif ++ ++#if FTS_EX_FUNC_EN ++ fts_release_apk_debug_channel(ts_data); ++ fts_remove_sysfs(ts_data); ++#endif ++#if FTS_EX_MODE_EN ++ fts_ex_mode_exit(ts_data); ++#endif ++ ++#if FTS_AUTO_UPGRADE_EN ++ fts_fwupg_exit(ts_data); ++#endif ++ ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_exit(ts_data); ++#endif ++ ++#if FTS_GESTURE_EN ++ fts_gesture_exit(ts_data); ++#endif ++ fts_bus_exit(ts_data); ++ ++ free_irq(ts_data->irq, ts_data); ++ input_unregister_device(ts_data->input_dev); ++ ++ if (ts_data->ts_workqueue) ++ destroy_workqueue(ts_data->ts_workqueue); ++ ++#if defined(CONFIG_FB) ++ if (fb_unregister_client(&ts_data->fb_notif)) ++ FTS_ERROR("Error occurred while unregistering fb_notifier."); ++#elif defined(CONFIG_HAS_EARLYSUSPEND) ++ unregister_early_suspend(&ts_data->early_suspend); ++#endif ++ ++ if (gpio_is_valid(ts_data->pdata->reset_gpio)) ++ gpio_free(ts_data->pdata->reset_gpio); ++ ++ if (gpio_is_valid(ts_data->pdata->irq_gpio)) ++ gpio_free(ts_data->pdata->irq_gpio); ++ ++#if FTS_POWER_SOURCE_CUST_EN ++ fts_power_source_exit(ts_data); ++#endif ++ ++ kfree_safe(ts_data->point_buf); ++ kfree_safe(ts_data->events); ++ ++ kfree_safe(ts_data->pdata); ++ kfree_safe(ts_data); ++ ++ FTS_FUNC_EXIT(); ++ ++ return 0; ++} ++ ++static int fts_ts_suspend(struct device *dev) ++{ ++ int ret = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ ++ FTS_FUNC_ENTER(); ++ if (ts_data->suspended) { ++ FTS_INFO("Already in suspend state"); ++ return 0; ++ } ++ ++ if (ts_data->fw_loading) { ++ FTS_INFO("fw upgrade in process, can't suspend"); ++ return 0; ++ } ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_suspend(); ++#endif ++ ++ if (ts_data->gesture_mode) { ++#if FTS_GESTURE_EN ++ fts_gesture_suspend(ts_data); ++#endif ++ } else { ++ fts_irq_disable(); ++ ++ FTS_INFO("make TP enter into sleep mode"); ++ ret = fts_write_reg(FTS_REG_POWER_MODE, FTS_REG_POWER_MODE_SLEEP); ++ if (ret < 0) ++ FTS_ERROR("set TP to sleep mode fail, ret=%d", ret); ++ ++ if (!ts_data->ic_info.is_incell) { ++#if FTS_POWER_SOURCE_CUST_EN ++ ret = fts_power_source_suspend(ts_data); ++ if (ret < 0) { ++ FTS_ERROR("power enter suspend fail"); ++ } ++#endif ++ } ++ } ++ ++ fts_release_all_finger(); ++ ts_data->suspended = true; ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++static int fts_ts_resume(struct device *dev) ++{ ++ struct fts_ts_data *ts_data = fts_data; ++ ++ FTS_FUNC_ENTER(); ++ if (!ts_data->suspended) { ++ FTS_DEBUG("Already in awake state"); ++ return 0; ++ } ++ ++ fts_release_all_finger(); ++ ++ if (!ts_data->ic_info.is_incell) { ++#if FTS_POWER_SOURCE_CUST_EN ++ fts_power_source_resume(ts_data); ++#endif ++ fts_reset_proc(200); ++ } ++ ++ fts_wait_tp_to_valid(); ++#if FTS_EX_MODE_EN ++ fts_ex_mode_recovery(ts_data); ++#endif ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_resume(); ++#endif ++ ++ if (ts_data->gesture_mode) { ++#if FTS_GESTURE_EN ++ fts_gesture_resume(ts_data); ++#endif ++ } else { ++ fts_irq_enable(); ++ } ++ ++ ts_data->suspended = false; ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(fts_pm_ops, fts_ts_suspend, fts_ts_resume); ++/***************************************************************************** ++* TP Driver ++*****************************************************************************/ ++ ++static int fts_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ int ret = 0; ++ struct fts_ts_data *ts_data = NULL; ++ ++ FTS_INFO("Touch Screen(I2C BUS) driver prboe..."); ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ FTS_ERROR("I2C not supported"); ++ return -ENODEV; ++ } ++ ++ /* malloc memory for global struct variable */ ++ ts_data = (struct fts_ts_data *)kzalloc(sizeof(*ts_data), GFP_KERNEL); ++ if (!ts_data) { ++ FTS_ERROR("allocate memory for fts_data fail"); ++ return -ENOMEM; ++ } ++ ++ fts_data = ts_data; ++ ts_data->client = client; ++ ts_data->dev = &client->dev; ++ ts_data->log_level = 1; ++ ts_data->fw_is_running = 0; ++ i2c_set_clientdata(client, ts_data); ++ ++ ret = fts_ts_probe_entry(ts_data); ++ if (ret) { ++ FTS_ERROR("Touch Screen(I2C BUS) driver probe fail"); ++ kfree_safe(ts_data); ++ return ret; ++ } ++ ++ FTS_INFO("Touch Screen(I2C BUS) driver prboe successfully"); ++ return 0; ++} ++ ++static int fts_ts_remove(struct i2c_client *client) ++{ ++ return fts_ts_remove_entry(i2c_get_clientdata(client)); ++} ++ ++static const struct i2c_device_id fts_ts_id[] = { ++ {FTS_DRIVER_NAME, 0}, ++ {}, ++}; ++static const struct of_device_id fts_dt_match[] = { ++ {.compatible = "focaltech,fts", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, fts_dt_match); ++ ++static struct i2c_driver fts_ts_driver = { ++ .probe = fts_ts_probe, ++ .remove = fts_ts_remove, ++ .driver = { ++ .name = FTS_DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(fts_dt_match), ++ .pm = &fts_pm_ops, ++ }, ++ .id_table = fts_ts_id, ++}; ++ ++static int __init fts_ts_init(void) ++{ ++ int ret = 0; ++ ++ FTS_FUNC_ENTER(); ++ ret = i2c_add_driver(&fts_ts_driver); ++ if ( ret != 0 ) { ++ FTS_ERROR("Focaltech touch screen driver init failed!"); ++ } ++ FTS_FUNC_EXIT(); ++ return ret; ++} ++ ++static void __exit fts_ts_exit(void) ++{ ++ i2c_del_driver(&fts_ts_driver); ++} ++module_init(fts_ts_init); ++module_exit(fts_ts_exit); ++ ++MODULE_AUTHOR("FocalTech Driver Team"); ++MODULE_DESCRIPTION("FocalTech Touchscreen Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_core.h b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_core.h +new file mode 100644 +index 000000000..669561af4 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_core.h +@@ -0,0 +1,260 @@ ++/* ++ * ++ * FocalTech TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, Focaltech Ltd. 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. ++ * ++ */ ++/***************************************************************************** ++* ++* File Name: focaltech_core.h ++ ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-08 ++* ++* Abstract: ++* ++* Reference: ++* ++*****************************************************************************/ ++ ++#ifndef __LINUX_FOCALTECH_CORE_H__ ++#define __LINUX_FOCALTECH_CORE_H__ ++/***************************************************************************** ++* Included header files ++*****************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "focaltech_common.h" ++ ++/***************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++#define FTS_MAX_POINTS_SUPPORT 10 /* constant value, can't be changed */ ++#define FTS_MAX_KEYS 4 ++#define FTS_KEY_DIM 10 ++#define FTS_ONE_TCH_LEN 6 ++#define FTS_TOUCH_DATA_LEN (FTS_MAX_POINTS_SUPPORT * FTS_ONE_TCH_LEN + 3) ++ ++#define FTS_GESTURE_POINTS_MAX 6 ++#define FTS_GESTURE_DATA_LEN (FTS_GESTURE_POINTS_MAX * 4 + 4) ++ ++#define FTS_MAX_ID 0x0A ++#define FTS_TOUCH_X_H_POS 3 ++#define FTS_TOUCH_X_L_POS 4 ++#define FTS_TOUCH_Y_H_POS 5 ++#define FTS_TOUCH_Y_L_POS 6 ++#define FTS_TOUCH_PRE_POS 7 ++#define FTS_TOUCH_AREA_POS 8 ++#define FTS_TOUCH_POINT_NUM 2 ++#define FTS_TOUCH_EVENT_POS 3 ++#define FTS_TOUCH_ID_POS 5 ++#define FTS_COORDS_ARR_SIZE 4 ++#define FTS_X_MIN_DISPLAY_DEFAULT 0 ++#define FTS_Y_MIN_DISPLAY_DEFAULT 0 ++#define FTS_X_MAX_DISPLAY_DEFAULT 720 ++#define FTS_Y_MAX_DISPLAY_DEFAULT 1280 ++ ++#define FTS_TOUCH_DOWN 0 ++#define FTS_TOUCH_UP 1 ++#define FTS_TOUCH_CONTACT 2 ++#define EVENT_DOWN(flag) ((FTS_TOUCH_DOWN == flag) || (FTS_TOUCH_CONTACT == flag)) ++#define EVENT_UP(flag) (FTS_TOUCH_UP == flag) ++#define EVENT_NO_DOWN(data) (!data->point_num) ++ ++#define FTX_MAX_COMPATIBLE_TYPE 4 ++#define FTX_MAX_COMMMAND_LENGTH 16 ++ ++ ++/***************************************************************************** ++* Private enumerations, structures and unions using typedef ++*****************************************************************************/ ++struct ftxxxx_proc { ++ struct proc_dir_entry *proc_entry; ++ u8 opmode; ++ u8 cmd_len; ++ u8 cmd[FTX_MAX_COMMMAND_LENGTH]; ++}; ++ ++struct fts_ts_platform_data { ++ u32 irq_gpio; ++ u32 irq_gpio_flags; ++ u32 reset_gpio; ++ u32 reset_gpio_flags; ++ bool have_key; ++ u32 key_number; ++ u32 keys[FTS_MAX_KEYS]; ++ u32 key_y_coords[FTS_MAX_KEYS]; ++ u32 key_x_coords[FTS_MAX_KEYS]; ++ u32 x_max; ++ u32 y_max; ++ u32 x_min; ++ u32 y_min; ++ u32 max_touch_number; ++}; ++ ++struct ts_event { ++ int x; /*x coordinate */ ++ int y; /*y coordinate */ ++ int p; /* pressure */ ++ int flag; /* touch event flag: 0 -- down; 1-- up; 2 -- contact */ ++ int id; /*touch ID */ ++ int area; ++}; ++ ++struct fts_ts_data { ++ struct i2c_client *client; ++ struct spi_device *spi; ++ struct device *dev; ++ struct input_dev *input_dev; ++ struct fts_ts_platform_data *pdata; ++ struct ts_ic_info ic_info; ++ struct workqueue_struct *ts_workqueue; ++ struct work_struct fwupg_work; ++ struct delayed_work esdcheck_work; ++ struct delayed_work prc_work; ++ struct work_struct resume_work; ++ struct ftxxxx_proc proc; ++ spinlock_t irq_lock; ++ struct mutex report_mutex; ++ struct mutex bus_lock; ++ int irq; ++ int log_level; ++ int fw_is_running; /* confirm fw is running when using spi:default 0 */ ++ int dummy_byte; ++ bool suspended; ++ bool fw_loading; ++ bool irq_disabled; ++ bool power_disabled; ++ bool glove_mode; ++ bool cover_mode; ++ bool charger_mode; ++ bool gesture_mode; /* gesture enable or disable, default: disable */ ++ /* multi-touch */ ++ struct ts_event *events; ++ u8 *bus_tx_buf; ++ u8 *bus_rx_buf; ++ u8 *point_buf; ++ int pnt_buf_size; ++ int touchs; ++ int key_state; ++ int touch_point; ++ int point_num; ++ struct regulator *vdd; ++ struct regulator *vcc_i2c; ++#if FTS_PINCTRL_EN ++ struct pinctrl *pinctrl; ++ struct pinctrl_state *pins_active; ++ struct pinctrl_state *pins_suspend; ++ struct pinctrl_state *pins_release; ++#endif ++#if defined(CONFIG_FB) ++ struct notifier_block fb_notif; ++#elif defined(CONFIG_HAS_EARLYSUSPEND) ++ struct early_suspend early_suspend; ++#endif ++}; ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++extern struct fts_ts_data *fts_data; ++ ++/* communication interface */ ++int fts_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen); ++int fts_read_reg(u8 addr, u8 *value); ++int fts_write(u8 *writebuf, u32 writelen); ++int fts_write_reg(u8 addr, u8 value); ++void fts_hid2std(void); ++int fts_bus_init(struct fts_ts_data *ts_data); ++int fts_bus_exit(struct fts_ts_data *ts_data); ++ ++/* Gesture functions */ ++int fts_gesture_init(struct fts_ts_data *ts_data); ++int fts_gesture_exit(struct fts_ts_data *ts_data); ++void fts_gesture_recovery(struct fts_ts_data *ts_data); ++int fts_gesture_readdata(struct fts_ts_data *ts_data, u8 *data); ++int fts_gesture_suspend(struct fts_ts_data *ts_data); ++int fts_gesture_resume(struct fts_ts_data *ts_data); ++ ++/* Apk and functions */ ++int fts_create_apk_debug_channel(struct fts_ts_data *); ++void fts_release_apk_debug_channel(struct fts_ts_data *); ++ ++/* ADB functions */ ++int fts_create_sysfs(struct fts_ts_data *ts_data); ++int fts_remove_sysfs(struct fts_ts_data *ts_data); ++ ++/* ESD */ ++#if FTS_ESDCHECK_EN ++int fts_esdcheck_init(struct fts_ts_data *ts_data); ++int fts_esdcheck_exit(struct fts_ts_data *ts_data); ++int fts_esdcheck_switch(bool enable); ++int fts_esdcheck_proc_busy(bool proc_debug); ++int fts_esdcheck_set_intr(bool intr); ++int fts_esdcheck_suspend(void); ++int fts_esdcheck_resume(void); ++#endif ++ ++ ++/* Point Report Check*/ ++#if FTS_POINT_REPORT_CHECK_EN ++int fts_point_report_check_init(struct fts_ts_data *ts_data); ++int fts_point_report_check_exit(struct fts_ts_data *ts_data); ++void fts_prc_queue_work(struct fts_ts_data *ts_data); ++#endif ++ ++/* FW upgrade */ ++int fts_fwupg_init(struct fts_ts_data *ts_data); ++int fts_fwupg_exit(struct fts_ts_data *ts_data); ++int fts_upgrade_bin(char *fw_name, bool force); ++int fts_enter_test_environment(bool test_state); ++ ++/* Other */ ++int fts_reset_proc(int hdelayms); ++int fts_wait_tp_to_valid(void); ++void fts_release_all_finger(void); ++void fts_tp_state_recovery(struct fts_ts_data *ts_data); ++int fts_ex_mode_init(struct fts_ts_data *ts_data); ++int fts_ex_mode_exit(struct fts_ts_data *ts_data); ++int fts_ex_mode_recovery(struct fts_ts_data *ts_data); ++ ++void fts_irq_disable(void); ++void fts_irq_enable(void); ++#endif /* __LINUX_FOCALTECH_CORE_H__ */ +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c +new file mode 100644 +index 000000000..b34bb26e8 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c +@@ -0,0 +1,464 @@ ++/* ++ * ++ * FocalTech TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. ++ * ++ */ ++ ++/***************************************************************************** ++* ++* File Name: focaltech_esdcheck.c ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-03 ++* ++* Abstract: ESD check function ++* ++* Version: v1.0 ++* ++* Revision History: ++* v1.0: ++* First release. By luougojin 2016-08-03 ++* v1.1: By luougojin 2017-02-15 ++* 1. Add LCD_ESD_PATCH to control idc_esdcheck_lcderror ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Included header files ++*****************************************************************************/ ++#include "focaltech_core.h" ++ ++#if FTS_ESDCHECK_EN ++/***************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++#define ESDCHECK_WAIT_TIME 1000 /* ms */ ++#define LCD_ESD_PATCH 0 ++#define ESDCHECK_INTRCNT_MAX 2 ++ ++/***************************************************************************** ++* Private enumerations, structures and unions using typedef ++*****************************************************************************/ ++struct fts_esdcheck_st { ++ u8 mode : 1; /* 1- need check esd 0- no esd check */ ++ u8 suspend : 1; ++ u8 proc_debug : 1; /* apk or adb use */ ++ u8 intr : 1; /* 1- Interrupt trigger */ ++ u8 unused : 4; ++ u8 intr_cnt; ++ u8 flow_work_hold_cnt; /* Flow Work Cnt(reg0x91) keep a same value for x times. >=5 times is ESD, need reset */ ++ u8 flow_work_cnt_last; /* Save Flow Work Cnt(reg0x91) value */ ++ u32 hardware_reset_cnt; ++ u32 nack_cnt; ++ u32 dataerror_cnt; ++}; ++ ++/***************************************************************************** ++* Static variables ++*****************************************************************************/ ++static struct fts_esdcheck_st fts_esdcheck_data; ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Static function prototypes ++*****************************************************************************/ ++ ++/***************************************************************************** ++* functions body ++*****************************************************************************/ ++#if LCD_ESD_PATCH ++int lcd_need_reset; ++static int tp_need_recovery; /* LCD reset cause Tp reset */ ++int idc_esdcheck_lcderror(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ u8 val = 0; ++ ++ FTS_DEBUG("check LCD ESD"); ++ if ( (tp_need_recovery == 1) && (lcd_need_reset == 0) ) { ++ tp_need_recovery = 0; ++ /* LCD reset, need recover TP state */ ++ fts_release_all_finger(); ++ fts_tp_state_recovery(ts_data); ++ } ++ ++ ret = fts_read_reg(FTS_REG_ESD_SATURATE, &val); ++ if ( ret < 0) { ++ FTS_ERROR("read reg0xED fail,ret:%d", ret); ++ return -EIO; ++ } ++ ++ if (val == 0xAA) { ++ /* ++ * 1. Set flag lcd_need_reset = 1; ++ * 2. LCD driver need reset(recovery) LCD and set lcd_need_reset to 0 ++ * 3. recover TP state ++ */ ++ FTS_INFO("LCD ESD, need execute LCD reset"); ++ lcd_need_reset = 1; ++ tp_need_recovery = 1; ++ } ++ ++ return 0; ++} ++#endif ++ ++static int fts_esdcheck_tp_reset(struct fts_ts_data *ts_data) ++{ ++ FTS_FUNC_ENTER(); ++ ++ fts_esdcheck_data.flow_work_hold_cnt = 0; ++ fts_esdcheck_data.hardware_reset_cnt++; ++ ++ fts_reset_proc(200); ++ fts_release_all_finger(); ++ fts_tp_state_recovery(ts_data); ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++static bool get_chip_id(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ int i = 0; ++ u8 reg_value = 0; ++ u8 reg_addr = 0; ++ u8 chip_id = ts_data->ic_info.ids.chip_idh; ++ ++ for (i = 0; i < 3; i++) { ++ reg_addr = FTS_REG_CHIP_ID; ++ ret = fts_read(®_addr, 1, ®_value, 1); ++ if (ret < 0) { ++ FTS_ERROR("read chip id fail,ret:%d", ret); ++ fts_esdcheck_data.nack_cnt++; ++ } else { ++ if (reg_value == chip_id) { ++ break; ++ } else { ++ FTS_DEBUG("read chip_id:%x,retry:%d", reg_value, i); ++ fts_esdcheck_data.dataerror_cnt++; ++ } ++ } ++ msleep(10); ++ } ++ ++ /* if can't get correct data in 3 times, then need hardware reset */ ++ if (i >= 3) { ++ FTS_ERROR("read chip id 3 times fail, need execute TP reset"); ++ return true; ++ } ++ ++ return false; ++} ++ ++/***************************************************************************** ++* Name: get_flow_cnt ++* Brief: Read flow cnt(0x91) ++* Input: ++* Output: ++* Return: 1(true) - Reg 0x91(flow cnt) abnormal: hold a value for 5 times ++* 0(false) - Reg 0x91(flow cnt) normal ++*****************************************************************************/ ++static bool get_flow_cnt(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ u8 reg_value = 0; ++ u8 reg_addr = 0; ++ ++ reg_addr = FTS_REG_FLOW_WORK_CNT; ++ ret = fts_read(®_addr, 1, ®_value, 1); ++ if (ret < 0) { ++ FTS_ERROR("read reg0x91 fail,ret:%d", ret); ++ fts_esdcheck_data.nack_cnt++; ++ } else { ++ if ( reg_value == fts_esdcheck_data.flow_work_cnt_last ) { ++ FTS_DEBUG("reg0x91,val:%x,last:%x", reg_value, ++ fts_esdcheck_data.flow_work_cnt_last); ++ fts_esdcheck_data.flow_work_hold_cnt++; ++ } else { ++ fts_esdcheck_data.flow_work_hold_cnt = 0; ++ } ++ ++ fts_esdcheck_data.flow_work_cnt_last = reg_value; ++ } ++ ++ /* Flow Work Cnt keep a value for 5 times, need execute TP reset */ ++ if (fts_esdcheck_data.flow_work_hold_cnt >= 5) { ++ FTS_DEBUG("reg0x91 keep a value for 5 times, need execute TP reset"); ++ return true; ++ } ++ ++ return false; ++} ++ ++static int esdcheck_algorithm(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ u8 reg_value = 0; ++ u8 reg_addr = 0; ++ bool hardware_reset = 0; ++ ++ /* 1. esdcheck is interrupt, then return */ ++ if (fts_esdcheck_data.intr == 1) { ++ fts_esdcheck_data.intr_cnt++; ++ if (fts_esdcheck_data.intr_cnt > ESDCHECK_INTRCNT_MAX) ++ fts_esdcheck_data.intr = 0; ++ else ++ return 0; ++ } ++ ++ /* 2. check power state, if suspend, no need check esd */ ++ if (fts_esdcheck_data.suspend == 1) { ++ FTS_DEBUG("In suspend, not check esd"); ++ /* because in suspend state, adb can be used, when upgrade FW, will ++ * active ESD check(active = 1); But in suspend, then will don't ++ * queue_delayed_work, when resume, don't check ESD again ++ */ ++ return 0; ++ } ++ ++ /* 3. check fts_esdcheck_data.proc_debug state, if 1-proc busy, no need check esd*/ ++ if (fts_esdcheck_data.proc_debug == 1) { ++ FTS_INFO("In apk/adb command mode, not check esd"); ++ return 0; ++ } ++ ++ /* 4. In factory mode, can't check esd */ ++ reg_addr = FTS_REG_WORKMODE; ++ ret = fts_read_reg(reg_addr, ®_value); ++ if ( ret < 0 ) { ++ fts_esdcheck_data.nack_cnt++; ++ } else if ( (reg_value & 0x70) != FTS_REG_WORKMODE_WORK_VALUE) { ++ FTS_DEBUG("not in work mode(%x), no check esd", reg_value); ++ return 0; ++ } ++ ++ /* 5. IDC esd check lcd default:close */ ++#if LCD_ESD_PATCH ++ idc_esdcheck_lcderror(ts_data); ++#endif ++ ++ /* 6. Get Chip ID */ ++ hardware_reset = get_chip_id(ts_data); ++ ++ /* 7. get Flow work cnt: 0x91 If no change for 5 times, then ESD and reset */ ++ if (!hardware_reset) { ++ hardware_reset = get_flow_cnt(ts_data); ++ } ++ ++ /* 8. If need hardware reset, then handle it here */ ++ if (hardware_reset == 1) { ++ FTS_DEBUG("NoACK=%d, Error Data=%d, Hardware Reset=%d", ++ fts_esdcheck_data.nack_cnt, ++ fts_esdcheck_data.dataerror_cnt, ++ fts_esdcheck_data.hardware_reset_cnt); ++ fts_esdcheck_tp_reset(ts_data); ++ } ++ ++ return 0; ++} ++ ++static void esdcheck_func(struct work_struct *work) ++{ ++ struct fts_ts_data *ts_data = container_of(work, ++ struct fts_ts_data, esdcheck_work.work); ++ ++ if (ENABLE == fts_esdcheck_data.mode) { ++ esdcheck_algorithm(ts_data); ++ queue_delayed_work(ts_data->ts_workqueue, &ts_data->esdcheck_work, ++ msecs_to_jiffies(ESDCHECK_WAIT_TIME)); ++ } ++ ++} ++ ++int fts_esdcheck_set_intr(bool intr) ++{ ++ /* interrupt don't add debug message */ ++ fts_esdcheck_data.intr = intr; ++ fts_esdcheck_data.intr_cnt = (u8)intr; ++ return 0; ++} ++ ++static int fts_esdcheck_get_status(void) ++{ ++ /* interrupt don't add debug message */ ++ return fts_esdcheck_data.mode; ++} ++ ++/***************************************************************************** ++* Name: fts_esdcheck_proc_busy ++* Brief: When APK or ADB command access TP via driver, then need set proc_debug, ++* then will not check ESD. ++* Input: ++* Output: ++* Return: ++*****************************************************************************/ ++int fts_esdcheck_proc_busy(bool proc_debug) ++{ ++ fts_esdcheck_data.proc_debug = proc_debug; ++ return 0; ++} ++ ++/***************************************************************************** ++* Name: fts_esdcheck_switch ++* Brief: FTS esd check function switch. ++* Input: enable: 1 - Enable esd check ++* 0 - Disable esd check ++* Output: ++* Return: ++*****************************************************************************/ ++int fts_esdcheck_switch(bool enable) ++{ ++ struct fts_ts_data *ts_data = fts_data; ++ FTS_FUNC_ENTER(); ++ if (fts_esdcheck_data.mode == ENABLE) { ++ if (enable) { ++ FTS_DEBUG("ESD check start"); ++ fts_esdcheck_data.flow_work_hold_cnt = 0; ++ fts_esdcheck_data.flow_work_cnt_last = 0; ++ fts_esdcheck_data.intr = 0; ++ fts_esdcheck_data.intr_cnt = 0; ++ queue_delayed_work(ts_data->ts_workqueue, ++ &ts_data->esdcheck_work, ++ msecs_to_jiffies(ESDCHECK_WAIT_TIME)); ++ } else { ++ FTS_DEBUG("ESD check stop"); ++ cancel_delayed_work_sync(&ts_data->esdcheck_work); ++ } ++ } ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++int fts_esdcheck_suspend(void) ++{ ++ FTS_FUNC_ENTER(); ++ fts_esdcheck_switch(DISABLE); ++ fts_esdcheck_data.suspend = 1; ++ fts_esdcheck_data.intr = 0; ++ fts_esdcheck_data.intr_cnt = 0; ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++int fts_esdcheck_resume( void ) ++{ ++ FTS_FUNC_ENTER(); ++ fts_esdcheck_switch(ENABLE); ++ fts_esdcheck_data.suspend = 0; ++ fts_esdcheck_data.intr = 0; ++ fts_esdcheck_data.intr_cnt = 0; ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++static ssize_t fts_esdcheck_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++ if (FTS_SYSFS_ECHO_ON(buf)) { ++ FTS_DEBUG("enable esdcheck"); ++ fts_esdcheck_data.mode = ENABLE; ++ fts_esdcheck_switch(ENABLE); ++ } else if (FTS_SYSFS_ECHO_OFF(buf)) { ++ FTS_DEBUG("disable esdcheck"); ++ fts_esdcheck_switch(DISABLE); ++ fts_esdcheck_data.mode = DISABLE; ++ } ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_esdcheck_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count; ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++ count = snprintf(buf, PAGE_SIZE, "Esd check: %s\n", \ ++ fts_esdcheck_get_status() ? "On" : "Off"); ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++/* sysfs esd node ++ * read example: cat fts_esd_mode ---read esd mode ++ * write example:echo 01 > fts_esd_mode ---make esdcheck enable ++ * ++ */ ++static DEVICE_ATTR (fts_esd_mode, S_IRUGO | S_IWUSR, fts_esdcheck_show, fts_esdcheck_store); ++ ++static struct attribute *fts_esd_mode_attrs[] = { ++ ++ &dev_attr_fts_esd_mode.attr, ++ NULL, ++}; ++ ++static struct attribute_group fts_esd_group = { ++ .attrs = fts_esd_mode_attrs, ++}; ++ ++int fts_create_esd_sysfs(struct device *dev) ++{ ++ int ret = 0; ++ ++ ret = sysfs_create_group(&dev->kobj, &fts_esd_group); ++ if ( ret != 0) { ++ FTS_ERROR("fts_create_esd_sysfs(sysfs) create fail"); ++ sysfs_remove_group(&dev->kobj, &fts_esd_group); ++ return ret; ++ } ++ return 0; ++} ++ ++int fts_esdcheck_init(struct fts_ts_data *ts_data) ++{ ++ FTS_FUNC_ENTER(); ++ ++ if (ts_data->ts_workqueue) { ++ INIT_DELAYED_WORK(&ts_data->esdcheck_work, esdcheck_func); ++ } else { ++ FTS_ERROR("fts workqueue is NULL, can't run esd check function"); ++ return -EINVAL; ++ } ++ ++ memset((u8 *)&fts_esdcheck_data, 0, sizeof(struct fts_esdcheck_st)); ++ ++ fts_esdcheck_data.mode = ENABLE; ++ fts_esdcheck_data.intr = 0; ++ fts_esdcheck_data.intr_cnt = 0; ++ fts_esdcheck_switch(ENABLE); ++ fts_create_esd_sysfs(ts_data->dev); ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++int fts_esdcheck_exit(struct fts_ts_data *ts_data) ++{ ++ sysfs_remove_group(&ts_data->dev->kobj, &fts_esd_group); ++ return 0; ++} ++#endif /* FTS_ESDCHECK_EN */ ++ +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c +new file mode 100644 +index 000000000..75962a093 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_ex_fun.c +@@ -0,0 +1,1187 @@ ++/* ++ * ++ * FocalTech TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, Focaltech Ltd. 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. ++ * ++ */ ++ ++/***************************************************************************** ++* ++* File Name: Focaltech_ex_fun.c ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-08 ++* ++* Abstract: ++* ++* Reference: ++* ++*****************************************************************************/ ++ ++/***************************************************************************** ++* 1.Included header files ++*****************************************************************************/ ++#include "focaltech_core.h" ++ ++/***************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++#define PROC_UPGRADE 0 ++#define PROC_READ_REGISTER 1 ++#define PROC_WRITE_REGISTER 2 ++#define PROC_AUTOCLB 4 ++#define PROC_UPGRADE_INFO 5 ++#define PROC_WRITE_DATA 6 ++#define PROC_READ_DATA 7 ++#define PROC_SET_TEST_FLAG 8 ++#define PROC_SET_SLAVE_ADDR 10 ++#define PROC_HW_RESET 11 ++#define PROC_READ_STATUS 12 ++#define PROC_SET_BOOT_MODE 13 ++#define PROC_ENTER_TEST_ENVIRONMENT 14 ++#define PROC_NAME "ftxxxx-debug" ++#define PROC_BUF_SIZE 256 ++ ++/***************************************************************************** ++* Private enumerations, structures and unions using typedef ++*****************************************************************************/ ++enum { ++ RWREG_OP_READ = 0, ++ RWREG_OP_WRITE = 1, ++}; ++ ++/***************************************************************************** ++* Static variables ++*****************************************************************************/ ++static struct rwreg_operation_t { ++ int type; /* 0: read, 1: write */ ++ int reg; /* register */ ++ int len; /* read/write length */ ++ int val; /* length = 1; read: return value, write: op return */ ++ int res; /* 0: success, otherwise: fail */ ++ char *opbuf; /* length >= 1, read return value, write: op return */ ++} rw_op; ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Static function prototypes ++*****************************************************************************/ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) ++static ssize_t fts_debug_write( ++ struct file *filp, const char __user *buff, size_t count, loff_t *ppos) ++{ ++ u8 *writebuf = NULL; ++ u8 tmpbuf[PROC_BUF_SIZE] = { 0 }; ++ int buflen = count; ++ int writelen = 0; ++ int ret = 0; ++ char tmp[PROC_BUF_SIZE]; ++ struct fts_ts_data *ts_data = fts_data; ++ struct ftxxxx_proc *proc = &ts_data->proc; ++ ++ if ((buflen <= 1) || (buflen > PAGE_SIZE)) { ++ FTS_ERROR("apk proc wirte count(%d>%d) fail", buflen, (int)PAGE_SIZE); ++ return -EINVAL; ++ } ++ ++ if (buflen > PROC_BUF_SIZE) { ++ writebuf = (u8 *)kzalloc(buflen * sizeof(u8), GFP_KERNEL); ++ if (NULL == writebuf) { ++ FTS_ERROR("apk proc wirte buf zalloc fail"); ++ return -ENOMEM; ++ } ++ } else { ++ writebuf = tmpbuf; ++ } ++ ++ if (copy_from_user(writebuf, buff, buflen)) { ++ FTS_ERROR("[APK]: copy from user error!!"); ++ ret = -EFAULT; ++ goto proc_write_err; ++ } ++ ++ proc->opmode = writebuf[0]; ++ switch (proc->opmode) { ++ case PROC_SET_TEST_FLAG: ++ FTS_DEBUG("[APK]: PROC_SET_TEST_FLAG = %x", writebuf[1]); ++ if (writebuf[1] == 0) { ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_switch(ENABLE); ++#endif ++ } else { ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_switch(DISABLE); ++#endif ++ } ++ break; ++ ++ case PROC_READ_REGISTER: ++ proc->cmd[0] = writebuf[1]; ++ break; ++ ++ case PROC_WRITE_REGISTER: ++ ret = fts_write_reg(writebuf[1], writebuf[2]); ++ if (ret < 0) { ++ FTS_ERROR("PROC_WRITE_REGISTER write error"); ++ goto proc_write_err; ++ } ++ break; ++ ++ case PROC_READ_DATA: ++ writelen = buflen - 1; ++ if (writelen >= FTX_MAX_COMMMAND_LENGTH) { ++ FTS_ERROR("cmd(PROC_READ_DATA) length(%d) fail", writelen); ++ goto proc_write_err; ++ } ++ memcpy(proc->cmd, writebuf + 1, writelen); ++ proc->cmd_len = writelen; ++ ret = fts_write(writebuf + 1, writelen); ++ if (ret < 0) { ++ FTS_ERROR("PROC_READ_DATA write error"); ++ goto proc_write_err; ++ } ++ break; ++ ++ case PROC_WRITE_DATA: ++ writelen = buflen - 1; ++ ret = fts_write(writebuf + 1, writelen); ++ if (ret < 0) { ++ FTS_ERROR("PROC_WRITE_DATA write error"); ++ goto proc_write_err; ++ } ++ break; ++ ++ case PROC_SET_SLAVE_ADDR: ++ break; ++ ++ case PROC_HW_RESET: ++ snprintf(tmp, PROC_BUF_SIZE, "%s", writebuf + 1); ++ tmp[buflen - 1] = '\0'; ++ if (strncmp(tmp, "focal_driver", 12) == 0) { ++ FTS_INFO("APK execute HW Reset"); ++ fts_reset_proc(0); ++ } ++ break; ++ ++ case PROC_SET_BOOT_MODE: ++ FTS_DEBUG("[APK]: PROC_SET_BOOT_MODE = %x", writebuf[1]); ++ if (0 == writebuf[1]) { ++ ts_data->fw_is_running = true; ++ } else { ++ ts_data->fw_is_running = false; ++ } ++ break; ++ case PROC_ENTER_TEST_ENVIRONMENT: ++ FTS_DEBUG("[APK]: PROC_ENTER_TEST_ENVIRONMENT = %x", writebuf[1]); ++#if FTS_AUTO_UPGRADE_EN ++ if (0 == writebuf[1]) { ++ fts_enter_test_environment(0); ++ } else { ++ fts_enter_test_environment(1); ++ } ++#endif ++ break; ++ ++ default: ++ break; ++ } ++ ++ ret = buflen; ++proc_write_err: ++ if ((buflen > PROC_BUF_SIZE) && writebuf) { ++ kfree(writebuf); ++ writebuf = NULL; ++ } ++ return ret; ++} ++ ++static ssize_t fts_debug_read( ++ struct file *filp, char __user *buff, size_t count, loff_t *ppos) ++{ ++ int ret = 0; ++ int num_read_chars = 0; ++ int buflen = count; ++ u8 *readbuf = NULL; ++ u8 tmpbuf[PROC_BUF_SIZE] = { 0 }; ++ struct fts_ts_data *ts_data = fts_data; ++ struct ftxxxx_proc *proc = &ts_data->proc; ++ ++ if ((buflen <= 0) || (buflen > PAGE_SIZE)) { ++ FTS_ERROR("apk proc read count(%d>%d) fail", buflen, (int)PAGE_SIZE); ++ return -EINVAL; ++ } ++ ++ if (buflen > PROC_BUF_SIZE) { ++ readbuf = (u8 *)kzalloc(buflen * sizeof(u8), GFP_KERNEL); ++ if (NULL == readbuf) { ++ FTS_ERROR("apk proc wirte buf zalloc fail"); ++ return -ENOMEM; ++ } ++ } else { ++ readbuf = tmpbuf; ++ } ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_proc_busy(1); ++#endif ++ ++ switch (proc->opmode) { ++ case PROC_READ_REGISTER: ++ num_read_chars = 1; ++ ret = fts_read_reg(proc->cmd[0], &readbuf[0]); ++ if (ret < 0) { ++ FTS_ERROR("PROC_READ_REGISTER read error"); ++ goto proc_read_err; ++ } ++ break; ++ case PROC_WRITE_REGISTER: ++ break; ++ ++ case PROC_READ_DATA: ++ num_read_chars = buflen; ++ ret = fts_read(NULL, 0, readbuf, num_read_chars); ++ if (ret < 0) { ++ FTS_ERROR("PROC_READ_DATA read error"); ++ goto proc_read_err; ++ } ++ break; ++ ++ case PROC_WRITE_DATA: ++ break; ++ ++ default: ++ break; ++ } ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_proc_busy(0); ++#endif ++ ++ if (copy_to_user(buff, readbuf, num_read_chars)) { ++ FTS_ERROR("copy to user error"); ++ ret = -EFAULT; ++ goto proc_read_err; ++ } ++ ++ ret = num_read_chars; ++proc_read_err: ++ if ((buflen > PROC_BUF_SIZE) && readbuf) { ++ kfree(readbuf); ++ readbuf = NULL; ++ } ++ return ret; ++} ++ ++static const struct file_operations fts_proc_fops = { ++ .owner = THIS_MODULE, ++ .read = fts_debug_read, ++ .write = fts_debug_write, ++}; ++#else ++static int fts_debug_write( ++ struct file *filp, const char __user *buff, unsigned long len, void *data) ++{ ++ u8 *writebuf = NULL; ++ u8 tmpbuf[PROC_BUF_SIZE] = { 0 }; ++ int buflen = count; ++ int writelen = 0; ++ int ret = 0; ++ char tmp[PROC_BUF_SIZE]; ++ struct fts_ts_data *ts_data = fts_data; ++ struct ftxxxx_proc *proc = &ts_data->proc; ++ ++ if ((buflen <= 1) || (buflen > PAGE_SIZE)) { ++ FTS_ERROR("apk proc wirte count(%d>%d) fail", buflen, (int)PAGE_SIZE); ++ return -EINVAL; ++ } ++ ++ if (buflen > PROC_BUF_SIZE) { ++ writebuf = (u8 *)kzalloc(buflen * sizeof(u8), GFP_KERNEL); ++ if (NULL == writebuf) { ++ FTS_ERROR("apk proc wirte buf zalloc fail"); ++ return -ENOMEM; ++ } ++ } else { ++ writebuf = tmpbuf; ++ } ++ ++ if (copy_from_user(writebuf, buff, buflen)) { ++ FTS_ERROR("[APK]: copy from user error!!"); ++ ret = -EFAULT; ++ goto proc_write_err; ++ } ++ ++ proc->opmode = writebuf[0]; ++ switch (proc->opmode) { ++ case PROC_SET_TEST_FLAG: ++ FTS_DEBUG("[APK]: PROC_SET_TEST_FLAG = %x", writebuf[1]); ++ if (writebuf[1] == 0) { ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_switch(ENABLE); ++#endif ++ } else { ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_switch(DISABLE); ++#endif ++ } ++ break; ++ ++ case PROC_READ_REGISTER: ++ proc->cmd[0] = writebuf[1]; ++ break; ++ ++ case PROC_WRITE_REGISTER: ++ ret = fts_write_reg(writebuf[1], writebuf[2]); ++ if (ret < 0) { ++ FTS_ERROR("PROC_WRITE_REGISTER write error"); ++ goto proc_write_err; ++ } ++ break; ++ ++ case PROC_READ_DATA: ++ writelen = buflen - 1; ++ if (writelen >= FTX_MAX_COMMMAND_LENGTH) { ++ FTS_ERROR("cmd(PROC_READ_DATA) length(%d) fail", writelen); ++ goto proc_write_err; ++ } ++ memcpy(proc->cmd, writebuf + 1, writelen); ++ proc->cmd_len = writelen; ++ ret = fts_write(writebuf + 1, writelen); ++ if (ret < 0) { ++ FTS_ERROR("PROC_READ_DATA write error"); ++ goto proc_write_err; ++ } ++ break; ++ ++ case PROC_WRITE_DATA: ++ writelen = buflen - 1; ++ ret = fts_write(writebuf + 1, writelen); ++ if (ret < 0) { ++ FTS_ERROR("PROC_WRITE_DATA write error"); ++ goto proc_write_err; ++ } ++ break; ++ ++ case PROC_SET_SLAVE_ADDR: ++ break; ++ ++ case PROC_HW_RESET: ++ snprintf(tmp, PROC_BUF_SIZE, "%s", writebuf + 1); ++ tmp[buflen - 1] = '\0'; ++ if (strncmp(tmp, "focal_driver", 12) == 0) { ++ FTS_INFO("APK execute HW Reset"); ++ fts_reset_proc(0); ++ } ++ break; ++ ++ case PROC_SET_BOOT_MODE: ++ FTS_DEBUG("[APK]: PROC_SET_BOOT_MODE = %x", writebuf[1]); ++ if (0 == writebuf[1]) { ++ ts_data->fw_is_running = true; ++ } else { ++ ts_data->fw_is_running = false; ++ } ++ break; ++ case PROC_ENTER_TEST_ENVIRONMENT: ++ FTS_DEBUG("[APK]: PROC_ENTER_TEST_ENVIRONMENT = %x", writebuf[1]); ++ if (0 == writebuf[1]) { ++ fts_enter_test_environment(0); ++ } else { ++ fts_enter_test_environment(1); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ ret = buflen; ++proc_write_err: ++ if ((buflen > PROC_BUF_SIZE) && writebuf) { ++ kfree(writebuf); ++ writebuf = NULL; ++ } ++ return ret; ++} ++ ++static int fts_debug_read( ++ char *page, char **start, off_t off, int count, int *eof, void *data ) ++{ ++ int ret = 0; ++ int num_read_chars = 0; ++ int buflen = count; ++ u8 *readbuf = NULL; ++ u8 tmpbuf[PROC_BUF_SIZE] = { 0 }; ++ struct fts_ts_data *ts_data = fts_data; ++ struct ftxxxx_proc *proc = &ts_data->proc; ++ ++ if ((buflen <= 0) || (buflen > PAGE_SIZE)) { ++ FTS_ERROR("apk proc read count(%d>%d) fail", buflen, (int)PAGE_SIZE); ++ return -EINVAL; ++ } ++ ++ if (buflen > PROC_BUF_SIZE) { ++ readbuf = (u8 *)kzalloc(buflen * sizeof(u8), GFP_KERNEL); ++ if (NULL == readbuf) { ++ FTS_ERROR("apk proc wirte buf zalloc fail"); ++ return -ENOMEM; ++ } ++ } else { ++ readbuf = tmpbuf; ++ } ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_proc_busy(1); ++#endif ++ ++ switch (proc->opmode) { ++ case PROC_READ_REGISTER: ++ num_read_chars = 1; ++ ret = fts_read_reg(proc->cmd[0], &readbuf[0]); ++ if (ret < 0) { ++ FTS_ERROR("PROC_READ_REGISTER read error"); ++ goto proc_read_err; ++ } ++ break; ++ case PROC_WRITE_REGISTER: ++ break; ++ ++ case PROC_READ_DATA: ++ num_read_chars = buflen; ++ ret = fts_read(NULL, 0, readbuf, num_read_chars); ++ if (ret < 0) { ++ FTS_ERROR("PROC_READ_DATA read error"); ++ goto proc_read_err; ++ } ++ break; ++ ++ case PROC_WRITE_DATA: ++ break; ++ ++ default: ++ break; ++ } ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_proc_busy(0); ++#endif ++ ++ if (copy_to_user(buff, readbuf, num_read_chars)) { ++ FTS_ERROR("copy to user error"); ++ ret = -EFAULT; ++ goto proc_read_err; ++ } ++ ++ ret = num_read_chars; ++proc_read_err: ++ if ((buflen > PROC_BUF_SIZE) && readbuf) { ++ kfree(readbuf); ++ readbuf = NULL; ++ } ++ return ret; ++} ++#endif ++ ++int fts_create_apk_debug_channel(struct fts_ts_data *ts_data) ++{ ++ struct ftxxxx_proc *proc = &ts_data->proc; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) ++ proc->proc_entry = proc_create(PROC_NAME, 0777, NULL, &fts_proc_fops); ++ if (NULL == proc->proc_entry) { ++ FTS_ERROR("create proc entry fail"); ++ return -ENOMEM; ++ } ++#else ++ proc->proc_entry = create_proc_entry(PROC_NAME, 0777, NULL); ++ if (NULL == proc->proc_entry) { ++ FTS_ERROR("create proc entry fail"); ++ return -ENOMEM; ++ } ++ proc->proc_entry->write_proc = fts_debug_write; ++ proc->proc_entry->read_proc = fts_debug_read; ++#endif ++ ++ FTS_INFO("Create proc entry success!"); ++ return 0; ++} ++ ++void fts_release_apk_debug_channel(struct fts_ts_data *ts_data) ++{ ++ struct ftxxxx_proc *proc = &ts_data->proc; ++ ++ if (proc->proc_entry) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) ++ proc_remove(proc->proc_entry); ++#else ++ remove_proc_entry(PROC_NAME, NULL); ++#endif ++ } ++} ++ ++/************************************************************************ ++ * sysfs interface ++ ***********************************************************************/ ++/* fts_hw_reset interface */ ++static ssize_t fts_hw_reset_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct input_dev *input_dev = fts_data->input_dev; ++ ssize_t count = 0; ++ ++ mutex_lock(&input_dev->mutex); ++ fts_reset_proc(0); ++ count = snprintf(buf, PAGE_SIZE, "hw reset executed\n"); ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_hw_reset_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ return -EPERM; ++} ++ ++/* fts_irq interface */ ++static ssize_t fts_irq_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ ssize_t count = 0; ++ struct irq_desc *desc = irq_to_desc(fts_data->irq); ++ ++ count = snprintf(buf, PAGE_SIZE, "irq_depth:%d\n", desc->depth); ++ ++ return count; ++} ++ ++static ssize_t fts_irq_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++ if (FTS_SYSFS_ECHO_ON(buf)) { ++ FTS_INFO("enable irq"); ++ fts_irq_enable(); ++ } else if (FTS_SYSFS_ECHO_OFF(buf)) { ++ FTS_INFO("disable irq"); ++ fts_irq_disable(); ++ } ++ mutex_unlock(&input_dev->mutex); ++ return count; ++} ++ ++/* fts_boot_mode interface */ ++static ssize_t fts_bootmode_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ FTS_FUNC_ENTER(); ++ mutex_lock(&input_dev->mutex); ++ if (FTS_SYSFS_ECHO_ON(buf)) { ++ FTS_INFO("[EX-FUN]set to boot mode"); ++ fts_data->fw_is_running = false; ++ } else if (FTS_SYSFS_ECHO_OFF(buf)) { ++ FTS_INFO("[EX-FUN]set to fw mode"); ++ fts_data->fw_is_running = true; ++ } ++ mutex_unlock(&input_dev->mutex); ++ FTS_FUNC_EXIT(); ++ ++ return count; ++} ++ ++static ssize_t fts_bootmode_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ ssize_t count = 0; ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ FTS_FUNC_ENTER(); ++ mutex_lock(&input_dev->mutex); ++ if (true == fts_data->fw_is_running) { ++ count = snprintf(buf, PAGE_SIZE, "tp is in fw mode\n"); ++ } else { ++ count = snprintf(buf, PAGE_SIZE, "tp is in boot mode\n"); ++ } ++ mutex_unlock(&input_dev->mutex); ++ FTS_FUNC_EXIT(); ++ ++ return count; ++} ++ ++/* fts_tpfwver interface */ ++static ssize_t fts_tpfwver_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct fts_ts_data *ts_data = fts_data; ++ struct input_dev *input_dev = ts_data->input_dev; ++ ssize_t num_read_chars = 0; ++ u8 fwver = 0; ++ ++ mutex_lock(&input_dev->mutex); ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_proc_busy(1); ++#endif ++ fts_read_reg(FTS_REG_FW_VER, &fwver); ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_proc_busy(0); ++#endif ++ if ((fwver == 0xFF) || (fwver == 0x00)) ++ num_read_chars = snprintf(buf, PAGE_SIZE, "get tp fw version fail!\n"); ++ else ++ num_read_chars = snprintf(buf, PAGE_SIZE, "%02x\n", fwver); ++ ++ mutex_unlock(&input_dev->mutex); ++ return num_read_chars; ++} ++ ++static ssize_t fts_tpfwver_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ return -EPERM; ++} ++ ++/* fts_rw_reg */ ++static ssize_t fts_tprwreg_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count; ++ int i; ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++ ++ if (rw_op.len < 0) { ++ count = snprintf(buf, PAGE_SIZE, "Invalid cmd line\n"); ++ } else if (rw_op.len == 1) { ++ if (RWREG_OP_READ == rw_op.type) { ++ if (rw_op.res == 0) { ++ count = snprintf(buf, PAGE_SIZE, "Read %02X: %02X\n", rw_op.reg, rw_op.val); ++ } else { ++ count = snprintf(buf, PAGE_SIZE, "Read %02X failed, ret: %d\n", rw_op.reg, rw_op.res); ++ } ++ } else { ++ if (rw_op.res == 0) { ++ count = snprintf(buf, PAGE_SIZE, "Write %02X, %02X success\n", rw_op.reg, rw_op.val); ++ } else { ++ count = snprintf(buf, PAGE_SIZE, "Write %02X failed, ret: %d\n", rw_op.reg, rw_op.res); ++ } ++ } ++ } else { ++ if (RWREG_OP_READ == rw_op.type) { ++ count = snprintf(buf, PAGE_SIZE, "Read Reg: [%02X]-[%02X]\n", rw_op.reg, rw_op.reg + rw_op.len); ++ count += snprintf(buf + count, PAGE_SIZE, "Result: "); ++ if (rw_op.res) { ++ count += snprintf(buf + count, PAGE_SIZE, "failed, ret: %d\n", rw_op.res); ++ } else { ++ if (rw_op.opbuf) { ++ for (i = 0; i < rw_op.len; i++) { ++ count += snprintf(buf + count, PAGE_SIZE, "%02X ", rw_op.opbuf[i]); ++ } ++ count += snprintf(buf + count, PAGE_SIZE, "\n"); ++ } ++ } ++ } else { ++ ; ++ count = snprintf(buf, PAGE_SIZE, "Write Reg: [%02X]-[%02X]\n", rw_op.reg, rw_op.reg + rw_op.len - 1); ++ count += snprintf(buf + count, PAGE_SIZE, "Write Data: "); ++ if (rw_op.opbuf) { ++ for (i = 1; i < rw_op.len; i++) { ++ count += snprintf(buf + count, PAGE_SIZE, "%02X ", rw_op.opbuf[i]); ++ } ++ count += snprintf(buf + count, PAGE_SIZE, "\n"); ++ } ++ if (rw_op.res) { ++ count += snprintf(buf + count, PAGE_SIZE, "Result: failed, ret: %d\n", rw_op.res); ++ } else { ++ count += snprintf(buf + count, PAGE_SIZE, "Result: success\n"); ++ } ++ } ++ /*if (rw_op.opbuf) { ++ kfree(rw_op.opbuf); ++ rw_op.opbuf = NULL; ++ }*/ ++ } ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static int shex_to_int(const char *hex_buf, int size) ++{ ++ int i; ++ int base = 1; ++ int value = 0; ++ char single; ++ ++ for (i = size - 1; i >= 0; i--) { ++ single = hex_buf[i]; ++ ++ if ((single >= '0') && (single <= '9')) { ++ value += (single - '0') * base; ++ } else if ((single >= 'a') && (single <= 'z')) { ++ value += (single - 'a' + 10) * base; ++ } else if ((single >= 'A') && (single <= 'Z')) { ++ value += (single - 'A' + 10) * base; ++ } else { ++ return -EINVAL; ++ } ++ ++ base *= 16; ++ } ++ ++ return value; ++} ++ ++ ++static u8 shex_to_u8(const char *hex_buf, int size) ++{ ++ return (u8)shex_to_int(hex_buf, size); ++} ++/* ++ * Format buf: ++ * [0]: '0' write, '1' read(reserved) ++ * [1-2]: addr, hex ++ * [3-4]: length, hex ++ * [5-6]...[n-(n+1)]: data, hex ++ */ ++static int fts_parse_buf(const char *buf, size_t cmd_len) ++{ ++ int length; ++ int i; ++ char *tmpbuf; ++ ++ rw_op.reg = shex_to_u8(buf + 1, 2); ++ length = shex_to_int(buf + 3, 2); ++ ++ if (buf[0] == '1') { ++ rw_op.len = length; ++ rw_op.type = RWREG_OP_READ; ++ FTS_DEBUG("read %02X, %d bytes", rw_op.reg, rw_op.len); ++ } else { ++ if (cmd_len < (length * 2 + 5)) { ++ pr_err("data invalided!\n"); ++ return -EINVAL; ++ } ++ FTS_DEBUG("write %02X, %d bytes", rw_op.reg, length); ++ ++ /* first byte is the register addr */ ++ rw_op.type = RWREG_OP_WRITE; ++ rw_op.len = length + 1; ++ } ++ ++ if (rw_op.len > 0) { ++ tmpbuf = (char *)kzalloc(rw_op.len, GFP_KERNEL); ++ if (!tmpbuf) { ++ FTS_ERROR("allocate memory failed!\n"); ++ return -ENOMEM; ++ } ++ ++ if (RWREG_OP_WRITE == rw_op.type) { ++ tmpbuf[0] = rw_op.reg & 0xFF; ++ FTS_DEBUG("write buffer: "); ++ for (i = 1; i < rw_op.len; i++) { ++ tmpbuf[i] = shex_to_u8(buf + 5 + i * 2 - 2, 2); ++ FTS_DEBUG("buf[%d]: %02X", i, tmpbuf[i] & 0xFF); ++ } ++ } ++ rw_op.opbuf = tmpbuf; ++ } ++ ++ return rw_op.len; ++} ++ ++static ssize_t fts_tprwreg_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct input_dev *input_dev = fts_data->input_dev; ++ ssize_t cmd_length = 0; ++ ++ mutex_lock(&input_dev->mutex); ++ cmd_length = count - 1; ++ ++ if (rw_op.opbuf) { ++ kfree(rw_op.opbuf); ++ rw_op.opbuf = NULL; ++ } ++ ++ FTS_DEBUG("cmd len: %d, buf: %s", (int)cmd_length, buf); ++ /* compatible old ops */ ++ if (2 == cmd_length) { ++ rw_op.type = RWREG_OP_READ; ++ rw_op.len = 1; ++ rw_op.reg = shex_to_int(buf, 2); ++ } else if (4 == cmd_length) { ++ rw_op.type = RWREG_OP_WRITE; ++ rw_op.len = 1; ++ rw_op.reg = shex_to_int(buf, 2); ++ rw_op.val = shex_to_int(buf + 2, 2); ++ } else if (cmd_length < 5) { ++ FTS_ERROR("Invalid cmd buffer"); ++ mutex_unlock(&input_dev->mutex); ++ return -EINVAL; ++ } else { ++ rw_op.len = fts_parse_buf(buf, cmd_length); ++ } ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_proc_busy(1); ++#endif ++ if (rw_op.len < 0) { ++ FTS_ERROR("cmd buffer error!"); ++ ++ } else { ++ if (RWREG_OP_READ == rw_op.type) { ++ if (rw_op.len == 1) { ++ u8 reg, val; ++ reg = rw_op.reg & 0xFF; ++ rw_op.res = fts_read_reg(reg, &val); ++ rw_op.val = val; ++ } else { ++ char reg; ++ reg = rw_op.reg & 0xFF; ++ ++ rw_op.res = fts_read(®, 1, rw_op.opbuf, rw_op.len); ++ } ++ ++ if (rw_op.res < 0) { ++ FTS_ERROR("Could not read 0x%02x", rw_op.reg); ++ } else { ++ FTS_INFO("read 0x%02x, %d bytes successful", rw_op.reg, rw_op.len); ++ rw_op.res = 0; ++ } ++ ++ } else { ++ if (rw_op.len == 1) { ++ u8 reg, val; ++ reg = rw_op.reg & 0xFF; ++ val = rw_op.val & 0xFF; ++ rw_op.res = fts_write_reg(reg, val); ++ } else { ++ rw_op.res = fts_write(rw_op.opbuf, rw_op.len); ++ } ++ if (rw_op.res < 0) { ++ FTS_ERROR("Could not write 0x%02x", rw_op.reg); ++ ++ } else { ++ FTS_INFO("Write 0x%02x, %d bytes successful", rw_op.val, rw_op.len); ++ rw_op.res = 0; ++ } ++ } ++ } ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_proc_busy(0); ++#endif ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++/* fts_upgrade_bin interface */ ++static ssize_t fts_fwupgradebin_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return -EPERM; ++} ++ ++static ssize_t fts_fwupgradebin_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ char fwname[FILE_NAME_LENGTH] = { 0 }; ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ if ((count <= 1) || (count >= FILE_NAME_LENGTH - 32)) { ++ FTS_ERROR("fw bin name's length(%d) fail", (int)count); ++ return -EINVAL; ++ } ++ memset(fwname, 0, sizeof(fwname)); ++ snprintf(fwname, FILE_NAME_LENGTH, "%s", buf); ++ fwname[count - 1] = '\0'; ++ ++ FTS_INFO("upgrade with bin file through sysfs node"); ++ mutex_lock(&input_dev->mutex); ++#if FTS_AUTO_UPGRADE_EN ++ fts_upgrade_bin(fwname, 0); ++#endif ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++/* fts_force_upgrade interface */ ++static ssize_t fts_fwforceupg_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return -EPERM; ++} ++ ++static ssize_t fts_fwforceupg_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ char fwname[FILE_NAME_LENGTH]; ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ if ((count <= 1) || (count >= FILE_NAME_LENGTH - 32)) { ++ FTS_ERROR("fw bin name's length(%d) fail", (int)count); ++ return -EINVAL; ++ } ++ memset(fwname, 0, sizeof(fwname)); ++ snprintf(fwname, FILE_NAME_LENGTH, "%s", buf); ++ fwname[count - 1] = '\0'; ++ ++ FTS_INFO("force upgrade through sysfs node"); ++#if FTS_AUTO_UPGRADE_EN ++ mutex_lock(&input_dev->mutex); ++ fts_upgrade_bin(fwname, 1); ++ mutex_unlock(&input_dev->mutex); ++#endif ++ ++ return count; ++} ++ ++/* fts_driver_info interface */ ++static ssize_t fts_driverinfo_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ struct fts_ts_platform_data *pdata = ts_data->pdata; ++ struct input_dev *input_dev = ts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++ count += snprintf(buf + count, PAGE_SIZE, "Driver Ver:%s\n", FTS_DRIVER_VERSION); ++ ++ count += snprintf(buf + count, PAGE_SIZE, "Resolution:(%d,%d)~(%d,%d)\n", ++ pdata->x_min, pdata->y_min, pdata->x_max, pdata->y_max); ++ ++ count += snprintf(buf + count, PAGE_SIZE, "Max Touchs:%d\n", pdata->max_touch_number); ++ ++ count += snprintf(buf + count, PAGE_SIZE, "reset gpio:%d,int gpio:%d,irq:%d\n", ++ pdata->reset_gpio, pdata->irq_gpio, ts_data->irq); ++ ++ count += snprintf(buf + count, PAGE_SIZE, "IC ID:0x%02x%02x\n", ++ ts_data->ic_info.ids.chip_idh, ts_data->ic_info.ids.chip_idl); ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_driverinfo_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ return -EPERM; ++} ++ ++/* fts_dump_reg interface */ ++static ssize_t fts_dumpreg_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count = 0; ++ u8 val = 0; ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_proc_busy(1); ++#endif ++ fts_read_reg(FTS_REG_POWER_MODE, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "Power Mode:0x%02x\n", val); ++ ++ fts_read_reg(FTS_REG_FW_VER, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "FW Ver:0x%02x\n", val); ++ ++ fts_read_reg(FTS_REG_LIC_VER, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "LCD Initcode Ver:0x%02x\n", val); ++ ++ fts_read_reg(FTS_REG_IDE_PARA_VER_ID, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "Param Ver:0x%02x\n", val); ++ ++ fts_read_reg(FTS_REG_IDE_PARA_STATUS, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "Param status:0x%02x\n", val); ++ ++ fts_read_reg(FTS_REG_VENDOR_ID, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "Vendor ID:0x%02x\n", val); ++ ++ fts_read_reg(FTS_REG_LCD_BUSY_NUM, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "LCD Busy Number:0x%02x\n", val); ++ ++ fts_read_reg(FTS_REG_GESTURE_EN, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "Gesture Mode:0x%02x\n", val); ++ ++ fts_read_reg(FTS_REG_CHARGER_MODE_EN, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "charge stat:0x%02x\n", val); ++ ++ fts_read_reg(FTS_REG_INT_CNT, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "INT count:0x%02x\n", val); ++ ++ fts_read_reg(FTS_REG_FLOW_WORK_CNT, &val); ++ count += snprintf(buf + count, PAGE_SIZE, "ESD count:0x%02x\n", val); ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_proc_busy(0); ++#endif ++ ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_dumpreg_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ return -EPERM; ++} ++ ++/* fts_dump_reg interface */ ++static ssize_t fts_tpbuf_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count = 0; ++ int i = 0; ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++ count += snprintf(buf + count, PAGE_SIZE, "touch point buffer:\n"); ++ for (i = 0; i < fts_data->pnt_buf_size; i++) { ++ count += snprintf(buf + count, PAGE_SIZE, "%02x ", fts_data->point_buf[i]); ++ } ++ count += snprintf(buf + count, PAGE_SIZE, "\n"); ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_tpbuf_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ return -EPERM; ++} ++ ++/* fts_log_level interface */ ++static ssize_t fts_log_level_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count = 0; ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++ count += snprintf(buf + count, PAGE_SIZE, "log level:%d\n", ++ fts_data->log_level); ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_log_level_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int value = 0; ++ struct input_dev *input_dev = fts_data->input_dev; ++ ++ FTS_FUNC_ENTER(); ++ mutex_lock(&input_dev->mutex); ++ sscanf(buf, "%d", &value); ++ FTS_DEBUG("log level:%d->%d", fts_data->log_level, value); ++ fts_data->log_level = value; ++ mutex_unlock(&input_dev->mutex); ++ FTS_FUNC_EXIT(); ++ ++ return count; ++} ++ ++/* get the fw version example:cat fw_version */ ++static DEVICE_ATTR(fts_fw_version, S_IRUGO | S_IWUSR, fts_tpfwver_show, fts_tpfwver_store); ++ ++/* read and write register(s) ++* All data type is **HEX** ++* Single Byte: ++* read: echo 88 > rw_reg ---read register 0x88 ++* write: echo 8807 > rw_reg ---write 0x07 into register 0x88 ++* Multi-bytes: ++* [0:rw-flag][1-2: reg addr, hex][3-4: length, hex][5-6...n-n+1: write data, hex] ++* rw-flag: 0, write; 1, read ++* read: echo 10005 > rw_reg ---read reg 0x00-0x05 ++* write: echo 000050102030405 > rw_reg ---write reg 0x00-0x05 as 01,02,03,04,05 ++* Get result: ++* cat rw_reg ++*/ ++static DEVICE_ATTR(fts_rw_reg, S_IRUGO | S_IWUSR, fts_tprwreg_show, fts_tprwreg_store); ++/* upgrade from fw bin file example:echo "*.bin" > fts_upgrade_bin */ ++static DEVICE_ATTR(fts_upgrade_bin, S_IRUGO | S_IWUSR, fts_fwupgradebin_show, fts_fwupgradebin_store); ++static DEVICE_ATTR(fts_force_upgrade, S_IRUGO | S_IWUSR, fts_fwforceupg_show, fts_fwforceupg_store); ++static DEVICE_ATTR(fts_driver_info, S_IRUGO | S_IWUSR, fts_driverinfo_show, fts_driverinfo_store); ++static DEVICE_ATTR(fts_dump_reg, S_IRUGO | S_IWUSR, fts_dumpreg_show, fts_dumpreg_store); ++static DEVICE_ATTR(fts_hw_reset, S_IRUGO | S_IWUSR, fts_hw_reset_show, fts_hw_reset_store); ++static DEVICE_ATTR(fts_irq, S_IRUGO | S_IWUSR, fts_irq_show, fts_irq_store); ++static DEVICE_ATTR(fts_boot_mode, S_IRUGO | S_IWUSR, fts_bootmode_show, fts_bootmode_store); ++static DEVICE_ATTR(fts_touch_point, S_IRUGO | S_IWUSR, fts_tpbuf_show, fts_tpbuf_store); ++static DEVICE_ATTR(fts_log_level, S_IRUGO | S_IWUSR, fts_log_level_show, fts_log_level_store); ++ ++/* add your attr in here*/ ++static struct attribute *fts_attributes[] = { ++ &dev_attr_fts_fw_version.attr, ++ &dev_attr_fts_rw_reg.attr, ++ &dev_attr_fts_dump_reg.attr, ++ &dev_attr_fts_upgrade_bin.attr, ++ &dev_attr_fts_force_upgrade.attr, ++ &dev_attr_fts_driver_info.attr, ++ &dev_attr_fts_hw_reset.attr, ++ &dev_attr_fts_irq.attr, ++ &dev_attr_fts_boot_mode.attr, ++ &dev_attr_fts_touch_point.attr, ++ &dev_attr_fts_log_level.attr, ++ NULL ++}; ++ ++static struct attribute_group fts_attribute_group = { ++ .attrs = fts_attributes ++}; ++ ++int fts_create_sysfs(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ ++ ret = sysfs_create_group(&ts_data->dev->kobj, &fts_attribute_group); ++ if (ret) { ++ FTS_ERROR("[EX]: sysfs_create_group() failed!!"); ++ sysfs_remove_group(&ts_data->dev->kobj, &fts_attribute_group); ++ return -ENOMEM; ++ } else { ++ FTS_INFO("[EX]: sysfs_create_group() succeeded!!"); ++ } ++ ++ return ret; ++} ++ ++int fts_remove_sysfs(struct fts_ts_data *ts_data) ++{ ++ sysfs_remove_group(&ts_data->dev->kobj, &fts_attribute_group); ++ return 0; ++} +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c +new file mode 100644 +index 000000000..c0c970b12 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c +@@ -0,0 +1,307 @@ ++/* ++ * ++ * FocalTech ftxxxx TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, Focaltech Ltd. 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. ++ * ++ */ ++ ++/***************************************************************************** ++* ++* File Name: focaltech_ex_mode.c ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-31 ++* ++* Abstract: ++* ++* Reference: ++* ++*****************************************************************************/ ++ ++/***************************************************************************** ++* 1.Included header files ++*****************************************************************************/ ++#include "focaltech_core.h" ++ ++/***************************************************************************** ++* 2.Private constant and macro definitions using #define ++*****************************************************************************/ ++ ++/***************************************************************************** ++* 3.Private enumerations, structures and unions using typedef ++*****************************************************************************/ ++enum _ex_mode { ++ MODE_GLOVE = 0, ++ MODE_COVER, ++ MODE_CHARGER, ++}; ++ ++/***************************************************************************** ++* 4.Static variables ++*****************************************************************************/ ++ ++/***************************************************************************** ++* 5.Global variable or extern global variabls/functions ++*****************************************************************************/ ++ ++/***************************************************************************** ++* 6.Static function prototypes ++*******************************************************************************/ ++static int fts_ex_mode_switch(enum _ex_mode mode, u8 value) ++{ ++ int ret = 0; ++ u8 m_val = 0; ++ ++ if (value) ++ m_val = 0x01; ++ else ++ m_val = 0x00; ++ ++ switch (mode) { ++ case MODE_GLOVE: ++ ret = fts_write_reg(FTS_REG_GLOVE_MODE_EN, m_val); ++ if (ret < 0) { ++ FTS_ERROR("MODE_GLOVE switch to %d fail", m_val); ++ } ++ break; ++ case MODE_COVER: ++ ret = fts_write_reg(FTS_REG_COVER_MODE_EN, m_val); ++ if (ret < 0) { ++ FTS_ERROR("MODE_COVER switch to %d fail", m_val); ++ } ++ break; ++ case MODE_CHARGER: ++ ret = fts_write_reg(FTS_REG_CHARGER_MODE_EN, m_val); ++ if (ret < 0) { ++ FTS_ERROR("MODE_CHARGER switch to %d fail", m_val); ++ } ++ break; ++ default: ++ FTS_ERROR("mode(%d) unsupport", mode); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static ssize_t fts_glove_mode_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count = 0; ++ u8 val = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ struct input_dev *input_dev = ts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++ fts_read_reg(FTS_REG_GLOVE_MODE_EN, &val); ++ count = snprintf(buf + count, PAGE_SIZE, "Glove Mode:%s\n", ++ ts_data->glove_mode ? "On" : "Off"); ++ count += snprintf(buf + count, PAGE_SIZE, "Glove Reg(0xC0):%d\n", val); ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_glove_mode_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int ret = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ ++ if (FTS_SYSFS_ECHO_ON(buf)) { ++ if (!ts_data->glove_mode) { ++ FTS_DEBUG("enter glove mode"); ++ ret = fts_ex_mode_switch(MODE_GLOVE, ENABLE); ++ if (ret >= 0) { ++ ts_data->glove_mode = ENABLE; ++ } ++ } ++ } else if (FTS_SYSFS_ECHO_OFF(buf)) { ++ if (ts_data->glove_mode) { ++ FTS_DEBUG("exit glove mode"); ++ ret = fts_ex_mode_switch(MODE_GLOVE, DISABLE); ++ if (ret >= 0) { ++ ts_data->glove_mode = DISABLE; ++ } ++ } ++ } ++ ++ FTS_DEBUG("glove mode:%d", ts_data->glove_mode); ++ return count; ++} ++ ++ ++static ssize_t fts_cover_mode_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count = 0; ++ u8 val = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ struct input_dev *input_dev = ts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++ fts_read_reg(FTS_REG_COVER_MODE_EN, &val); ++ count = snprintf(buf + count, PAGE_SIZE, "Cover Mode:%s\n", ++ ts_data->cover_mode ? "On" : "Off"); ++ count += snprintf(buf + count, PAGE_SIZE, "Cover Reg(0xC1):%d\n", val); ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_cover_mode_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int ret = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ ++ if (FTS_SYSFS_ECHO_ON(buf)) { ++ if (!ts_data->cover_mode) { ++ FTS_DEBUG("enter cover mode"); ++ ret = fts_ex_mode_switch(MODE_COVER, ENABLE); ++ if (ret >= 0) { ++ ts_data->cover_mode = ENABLE; ++ } ++ } ++ } else if (FTS_SYSFS_ECHO_OFF(buf)) { ++ if (ts_data->cover_mode) { ++ FTS_DEBUG("exit cover mode"); ++ ret = fts_ex_mode_switch(MODE_COVER, DISABLE); ++ if (ret >= 0) { ++ ts_data->cover_mode = DISABLE; ++ } ++ } ++ } ++ ++ FTS_DEBUG("cover mode:%d", ts_data->cover_mode); ++ return count; ++} ++ ++static ssize_t fts_charger_mode_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count = 0; ++ u8 val = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ struct input_dev *input_dev = ts_data->input_dev; ++ ++ mutex_lock(&input_dev->mutex); ++ fts_read_reg(FTS_REG_CHARGER_MODE_EN, &val); ++ count = snprintf(buf + count, PAGE_SIZE, "Charger Mode:%s\n", ++ ts_data->charger_mode ? "On" : "Off"); ++ count += snprintf(buf + count, PAGE_SIZE, "Charger Reg(0x8B):%d\n", val); ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_charger_mode_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int ret = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ ++ if (FTS_SYSFS_ECHO_ON(buf)) { ++ if (!ts_data->charger_mode) { ++ FTS_DEBUG("enter charger mode"); ++ ret = fts_ex_mode_switch(MODE_CHARGER, ENABLE); ++ if (ret >= 0) { ++ ts_data->charger_mode = ENABLE; ++ } ++ } ++ } else if (FTS_SYSFS_ECHO_OFF(buf)) { ++ if (ts_data->charger_mode) { ++ FTS_DEBUG("exit charger mode"); ++ ret = fts_ex_mode_switch(MODE_CHARGER, DISABLE); ++ if (ret >= 0) { ++ ts_data->charger_mode = DISABLE; ++ } ++ } ++ } ++ ++ FTS_DEBUG("charger mode:%d", ts_data->glove_mode); ++ return count; ++} ++ ++ ++/* read and write charger mode ++ * read example: cat fts_glove_mode ---read glove mode ++ * write example:echo 1 > fts_glove_mode ---write glove mode to 01 ++ */ ++static DEVICE_ATTR(fts_glove_mode, S_IRUGO | S_IWUSR, ++ fts_glove_mode_show, fts_glove_mode_store); ++ ++static DEVICE_ATTR(fts_cover_mode, S_IRUGO | S_IWUSR, ++ fts_cover_mode_show, fts_cover_mode_store); ++ ++static DEVICE_ATTR(fts_charger_mode, S_IRUGO | S_IWUSR, ++ fts_charger_mode_show, fts_charger_mode_store); ++ ++static struct attribute *fts_touch_mode_attrs[] = { ++ &dev_attr_fts_glove_mode.attr, ++ &dev_attr_fts_cover_mode.attr, ++ &dev_attr_fts_charger_mode.attr, ++ NULL, ++}; ++ ++static struct attribute_group fts_touch_mode_group = { ++ .attrs = fts_touch_mode_attrs, ++}; ++ ++int fts_ex_mode_recovery(struct fts_ts_data *ts_data) ++{ ++ if (ts_data->glove_mode) { ++ fts_ex_mode_switch(MODE_GLOVE, ENABLE); ++ } ++ ++ if (ts_data->cover_mode) { ++ fts_ex_mode_switch(MODE_COVER, ENABLE); ++ } ++ ++ if (ts_data->charger_mode) { ++ fts_ex_mode_switch(MODE_CHARGER, ENABLE); ++ } ++ ++ return 0; ++} ++ ++int fts_ex_mode_init(struct fts_ts_data *ts_data) ++{ ++ int ret = 0; ++ ++ ts_data->glove_mode = DISABLE; ++ ts_data->cover_mode = DISABLE; ++ ts_data->charger_mode = DISABLE; ++ ++ ret = sysfs_create_group(&ts_data->dev->kobj, &fts_touch_mode_group); ++ if (ret < 0) { ++ FTS_ERROR("create sysfs(ex_mode) fail"); ++ sysfs_remove_group(&ts_data->dev->kobj, &fts_touch_mode_group); ++ return ret; ++ } else { ++ FTS_DEBUG("create sysfs(ex_mode) succeedfully"); ++ } ++ ++ return 0; ++} ++ ++int fts_ex_mode_exit(struct fts_ts_data *ts_data) ++{ ++ sysfs_remove_group(&ts_data->dev->kobj, &fts_touch_mode_group); ++ return 0; ++} +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash.c b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash.c +new file mode 100644 +index 000000000..d42540b01 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash.c +@@ -0,0 +1,2011 @@ ++/* ++ * ++ * FocalTech fts TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, Focaltech Ltd. 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. ++ * ++ */ ++ ++/***************************************************************************** ++* ++* File Name: focaltech_flash.c ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-08 ++* ++* Abstract: ++* ++* Reference: ++* ++*****************************************************************************/ ++ ++/***************************************************************************** ++* 1.Included header files ++*****************************************************************************/ ++#include "focaltech_core.h" ++#include "focaltech_flash.h" ++ ++/***************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++#define FTS_FW_REQUEST_SUPPORT 1 ++/* Example: focaltech_ts_fw_tianma.bin */ ++#define FTS_FW_NAME_PREX_WITH_REQUEST "focaltech_ts_fw_" ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++u8 fw_file[] = { ++#include FTS_UPGRADE_FW_FILE ++}; ++ ++u8 fw_file2[] = { ++#include FTS_UPGRADE_FW2_FILE ++}; ++ ++u8 fw_file3[] = { ++#include FTS_UPGRADE_FW3_FILE ++}; ++ ++struct upgrade_module module_list[] = { ++ {FTS_MODULE_ID, FTS_MODULE_NAME, fw_file, sizeof(fw_file)}, ++ {FTS_MODULE2_ID, FTS_MODULE2_NAME, fw_file2, sizeof(fw_file2)}, ++ {FTS_MODULE3_ID, FTS_MODULE3_NAME, fw_file3, sizeof(fw_file3)}, ++}; ++ ++struct upgrade_func *upgrade_func_list[] = { ++ &upgrade_func_ft7511, ++}; ++ ++struct fts_upgrade *fwupgrade; ++ ++/***************************************************************************** ++* Static function prototypes ++*****************************************************************************/ ++static bool fts_fwupg_check_state( ++ struct fts_upgrade *upg, enum FW_STATUS rstate); ++ ++/************************************************************************ ++* Name: fts_fwupg_get_boot_state ++* Brief: read boot id(rom/pram/bootloader), confirm boot environment ++* Input: ++* Output: ++* Return: return 0 if success, otherwise return error code ++***********************************************************************/ ++static int fts_fwupg_get_boot_state( ++ struct fts_upgrade *upg, ++ enum FW_STATUS *fw_sts) ++{ ++ int ret = 0; ++ u8 cmd[4] = { 0 }; ++ u32 cmd_len = 0; ++ u8 val[2] = { 0 }; ++ struct ft_chip_t *ids = NULL; ++ ++ FTS_INFO("**********read boot id**********"); ++ if ((!upg) || (!upg->func) || (!upg->ts_data) || (!fw_sts)) { ++ FTS_ERROR("upg/func/ts_data/fw_sts is null"); ++ return -EINVAL; ++ } ++ ++ if (upg->func->hid_supported) ++ fts_hid2std(); ++ ++ cmd[0] = FTS_CMD_START1; ++ cmd[1] = FTS_CMD_START2; ++ ret = fts_write(cmd, 2); ++ if (ret < 0) { ++ FTS_ERROR("write 55 aa cmd fail"); ++ return ret; ++ } ++ ++ msleep(FTS_CMD_START_DELAY); ++ cmd[0] = FTS_CMD_READ_ID; ++ cmd[1] = cmd[2] = cmd[3] = 0x00; ++ if (fts_data->ic_info.is_incell) ++ cmd_len = FTS_CMD_READ_ID_LEN_INCELL; ++ else ++ cmd_len = FTS_CMD_READ_ID_LEN; ++ ret = fts_read(cmd, cmd_len, val, 2); ++ if (ret < 0) { ++ FTS_ERROR("write 90 cmd fail"); ++ return ret; ++ } ++ FTS_INFO("read boot id:0x%02x%02x", val[0], val[1]); ++ ++ ids = &upg->ts_data->ic_info.ids; ++ if ((val[0] == ids->rom_idh) && (val[1] == ids->rom_idl)) { ++ FTS_INFO("tp run in romboot"); ++ *fw_sts = FTS_RUN_IN_ROM; ++ } else if ((val[0] == ids->pb_idh) && (val[1] == ids->pb_idl)) { ++ FTS_INFO("tp run in pramboot"); ++ *fw_sts = FTS_RUN_IN_PRAM; ++ } else if ((val[0] == ids->bl_idh) && (val[1] == ids->bl_idl)) { ++ FTS_INFO("tp run in bootloader"); ++ *fw_sts = FTS_RUN_IN_BOOTLOADER; ++ } ++ ++ return 0; ++} ++ ++static int fts_fwupg_reset_to_boot(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ u8 reg = FTS_REG_UPGRADE; ++ ++ FTS_INFO("send 0xAA and 0x55 to FW, reset to boot environment"); ++ if (upg && upg->func && upg->func->is_reset_register_BC) { ++ reg = FTS_REG_UPGRADE2; ++ } ++ ++ ret = fts_write_reg(reg, FTS_UPGRADE_AA); ++ if (ret < 0) { ++ FTS_ERROR("write FC=0xAA fail"); ++ return ret; ++ } ++ msleep(FTS_DELAY_UPGRADE_AA); ++ ++ ret = fts_write_reg(reg, FTS_UPGRADE_55); ++ if (ret < 0) { ++ FTS_ERROR("write FC=0x55 fail"); ++ return ret; ++ } ++ ++ msleep(FTS_DELAY_UPGRADE_RESET); ++ return 0; ++} ++ ++/************************************************************************ ++* Name: fts_fwupg_reset_to_romboot ++* Brief: reset to romboot, to load pramboot ++* Input: ++* Output: ++* Return: return 0 if success, otherwise return error code ++***********************************************************************/ ++static int fts_fwupg_reset_to_romboot(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ int i = 0; ++ u8 cmd = FTS_CMD_RESET; ++ enum FW_STATUS state = FTS_RUN_IN_ERROR; ++ ++ ret = fts_write(&cmd, 1); ++ if (ret < 0) { ++ FTS_ERROR("pram/rom/bootloader reset cmd write fail"); ++ return ret; ++ } ++ mdelay(10); ++ ++ for (i = 0; i < FTS_UPGRADE_LOOP; i++) { ++ ret = fts_fwupg_get_boot_state(upg, &state); ++ if (FTS_RUN_IN_ROM == state) ++ break; ++ mdelay(5); ++ } ++ if (i >= FTS_UPGRADE_LOOP) { ++ FTS_ERROR("reset to romboot fail"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static u16 fts_crc16_calc_host(u8 *pbuf, u16 length) ++{ ++ u16 ecc = 0; ++ u16 i = 0; ++ u16 j = 0; ++ ++ for ( i = 0; i < length; i += 2 ) { ++ ecc ^= ((pbuf[i] << 8) | (pbuf[i + 1])); ++ for (j = 0; j < 16; j ++) { ++ if (ecc & 0x01) ++ ecc = (u16)((ecc >> 1) ^ AL2_FCS_COEF); ++ else ++ ecc >>= 1; ++ } ++ } ++ ++ return ecc; ++} ++ ++static u16 fts_pram_ecc_calc_host(u8 *pbuf, u16 length) ++{ ++ return fts_crc16_calc_host(pbuf, length); ++} ++ ++static int fts_pram_ecc_cal_algo( ++ struct fts_upgrade *upg, ++ u32 start_addr, ++ u32 ecc_length) ++{ ++ int ret = 0; ++ int i = 0; ++ int ecc = 0; ++ u8 val[2] = { 0 }; ++ u8 tmp = 0; ++ u8 cmd[FTS_ROMBOOT_CMD_ECC_NEW_LEN] = { 0 }; ++ ++ FTS_INFO("read out pramboot checksum"); ++ if ((!upg) || (!upg->func)) { ++ FTS_ERROR("upg/func is null"); ++ return -EINVAL; ++ } ++ ++ cmd[0] = FTS_ROMBOOT_CMD_ECC; ++ cmd[1] = BYTE_OFF_16(start_addr); ++ cmd[2] = BYTE_OFF_8(start_addr); ++ cmd[3] = BYTE_OFF_0(start_addr); ++ cmd[4] = BYTE_OFF_16(ecc_length); ++ cmd[5] = BYTE_OFF_8(ecc_length); ++ cmd[6] = BYTE_OFF_0(ecc_length); ++ ret = fts_write(cmd, FTS_ROMBOOT_CMD_ECC_NEW_LEN); ++ if (ret < 0) { ++ FTS_ERROR("write pramboot ecc cal cmd fail"); ++ return ret; ++ } ++ ++ cmd[0] = FTS_ROMBOOT_CMD_ECC_FINISH; ++ for (i = 0; i < FTS_ECC_FINISH_TIMEOUT; i++) { ++ msleep(1); ++ ret = fts_read(cmd, 1, val, 1); ++ if (ret < 0) { ++ FTS_ERROR("ecc_finish read cmd fail"); ++ return ret; ++ } ++ if (upg->func->new_return_value_from_ic) { ++ tmp = FTS_ROMBOOT_CMD_ECC_FINISH_OK_A5; ++ } else { ++ tmp = FTS_ROMBOOT_CMD_ECC_FINISH_OK_00; ++ } ++ if (tmp == val[0]) ++ break; ++ } ++ if (i >= 100) { ++ FTS_ERROR("wait ecc finish fail"); ++ return -EIO; ++ } ++ ++ cmd[0] = FTS_ROMBOOT_CMD_ECC_READ; ++ ret = fts_read(cmd, 1, val, 2); ++ if (ret < 0) { ++ FTS_ERROR("read pramboot ecc fail"); ++ return ret; ++ } ++ ++ ecc = ((u16)(val[0] << 8) + val[1]) & 0x0000FFFF; ++ return ecc; ++} ++ ++static int fts_pram_ecc_cal_xor(void) ++{ ++ int ret = 0; ++ u8 reg_val = 0; ++ ++ FTS_INFO("read out pramboot checksum"); ++ ++ ret = fts_read_reg(FTS_ROMBOOT_CMD_ECC, ®_val); ++ if (ret < 0) { ++ FTS_ERROR("read pramboot ecc fail"); ++ return ret; ++ } ++ ++ return (int)reg_val; ++} ++ ++static int fts_pram_ecc_cal(struct fts_upgrade *upg, u32 saddr, u32 len) ++{ ++ if ((!upg) || (!upg->func)) { ++ FTS_ERROR("upg/func is null"); ++ return -EINVAL; ++ } ++ ++ if (ECC_CHECK_MODE_CRC16 == upg->func->pram_ecc_check_mode) { ++ return fts_pram_ecc_cal_algo(upg, saddr, len); ++ } else { ++ return fts_pram_ecc_cal_xor(); ++ } ++} ++ ++static int fts_pram_write_buf(struct fts_upgrade *upg, u8 *buf, u32 len) ++{ ++ int ret = 0; ++ u32 i = 0; ++ u32 j = 0; ++ u32 offset = 0; ++ u32 remainder = 0; ++ u32 packet_number; ++ u32 packet_len = 0; ++ u8 packet_buf[FTS_FLASH_PACKET_LENGTH + FTS_CMD_WRITE_LEN] = { 0 }; ++ u8 ecc_tmp = 0; ++ int ecc_in_host = 0; ++ ++ FTS_INFO("write pramboot to pram"); ++ if ((!upg) || (!upg->func) || !buf) { ++ FTS_ERROR("upg/func/buf is null"); ++ return -EINVAL; ++ } ++ ++ FTS_INFO("pramboot len=%d", len); ++ if ((len < PRAMBOOT_MIN_SIZE) || (len > PRAMBOOT_MAX_SIZE)) { ++ FTS_ERROR("pramboot length(%d) fail", len); ++ return -EINVAL; ++ } ++ ++ packet_number = len / FTS_FLASH_PACKET_LENGTH; ++ remainder = len % FTS_FLASH_PACKET_LENGTH; ++ if (remainder > 0) ++ packet_number++; ++ packet_len = FTS_FLASH_PACKET_LENGTH; ++ ++ packet_buf[0] = FTS_ROMBOOT_CMD_WRITE; ++ for (i = 0; i < packet_number; i++) { ++ offset = i * FTS_FLASH_PACKET_LENGTH; ++ packet_buf[1] = BYTE_OFF_16(offset); ++ packet_buf[2] = BYTE_OFF_8(offset); ++ packet_buf[3] = BYTE_OFF_0(offset); ++ ++ /* last packet */ ++ if ((i == (packet_number - 1)) && remainder) ++ packet_len = remainder; ++ ++ packet_buf[4] = BYTE_OFF_8(packet_len); ++ packet_buf[5] = BYTE_OFF_0(packet_len); ++ ++ for (j = 0; j < packet_len; j++) { ++ packet_buf[FTS_CMD_WRITE_LEN + j] = buf[offset + j]; ++ if (ECC_CHECK_MODE_XOR == upg->func->pram_ecc_check_mode) { ++ ecc_tmp ^= packet_buf[FTS_CMD_WRITE_LEN + j]; ++ } ++ } ++ ++ ret = fts_write(packet_buf, packet_len + FTS_CMD_WRITE_LEN); ++ if (ret < 0) { ++ FTS_ERROR("pramboot write data(%d) fail", i); ++ return ret; ++ } ++ } ++ ++ if (ECC_CHECK_MODE_CRC16 == upg->func->pram_ecc_check_mode) { ++ ecc_in_host = (int)fts_pram_ecc_calc_host(buf, len); ++ } else { ++ ecc_in_host = (int)ecc_tmp; ++ } ++ ++ return ecc_in_host; ++} ++ ++static int fts_pram_start(void) ++{ ++ u8 cmd = FTS_ROMBOOT_CMD_START_APP; ++ int ret = 0; ++ ++ FTS_INFO("remap to start pramboot"); ++ ++ ret = fts_write(&cmd, 1); ++ if (ret < 0) { ++ FTS_ERROR("write start pram cmd fail"); ++ return ret; ++ } ++ msleep(FTS_DELAY_PRAMBOOT_START); ++ ++ return 0; ++} ++ ++static int fts_pram_write_remap(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ int ecc_in_host = 0; ++ int ecc_in_tp = 0; ++ u8 *pb_buf = NULL; ++ u32 pb_len = 0; ++ ++ FTS_INFO("write pram and remap"); ++ if (!upg || !upg->func || !upg->func->pramboot) { ++ FTS_ERROR("upg/func/pramboot is null"); ++ return -EINVAL; ++ } ++ ++ if (upg->func->pb_length < FTS_MIN_LEN) { ++ FTS_ERROR("pramboot length(%d) fail", upg->func->pb_length); ++ return -EINVAL; ++ } ++ ++ pb_buf = upg->func->pramboot; ++ pb_len = upg->func->pb_length; ++ ++ /* write pramboot to pram */ ++ ecc_in_host = fts_pram_write_buf(upg, pb_buf, pb_len); ++ if (ecc_in_host < 0) { ++ FTS_ERROR( "write pramboot fail"); ++ return ecc_in_host; ++ } ++ ++ /* read out checksum */ ++ ecc_in_tp = fts_pram_ecc_cal(upg, 0, pb_len); ++ if (ecc_in_tp < 0) { ++ FTS_ERROR( "read pramboot ecc fail"); ++ return ecc_in_tp; ++ } ++ ++ FTS_INFO("pram ecc in tp:%x, host:%x", ecc_in_tp, ecc_in_host); ++ /* pramboot checksum != fw checksum, upgrade fail */ ++ if (ecc_in_host != ecc_in_tp) { ++ FTS_ERROR("pramboot ecc check fail"); ++ return -EIO; ++ } ++ ++ /*start pram*/ ++ ret = fts_pram_start(); ++ if (ret < 0) { ++ FTS_ERROR("pram start fail"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int fts_pram_init(void) ++{ ++ int ret = 0; ++ u8 reg_val = 0; ++ u8 wbuf[3] = { 0 }; ++ ++ FTS_INFO("pramboot initialization"); ++ ++ /* read flash ID */ ++ wbuf[0] = FTS_CMD_FLASH_TYPE; ++ ret = fts_read(wbuf, 1, ®_val, 1); ++ if (ret < 0) { ++ FTS_ERROR("read flash type fail"); ++ return ret; ++ } ++ ++ /* set flash clk */ ++ wbuf[0] = FTS_CMD_FLASH_TYPE; ++ wbuf[1] = reg_val; ++ wbuf[2] = 0x00; ++ ret = fts_write(wbuf, 3); ++ if (ret < 0) { ++ FTS_ERROR("write flash type fail"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int fts_pram_write_init(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ bool state = 0; ++ enum FW_STATUS status = FTS_RUN_IN_ERROR; ++ ++ FTS_INFO("**********pram write and init**********"); ++ if ((NULL == upg) || (NULL == upg->func)) { ++ FTS_ERROR("upgrade/func is null"); ++ return -EINVAL; ++ } ++ ++ if (!upg->func->pramboot_supported) { ++ FTS_ERROR("ic not support pram"); ++ return -EINVAL; ++ } ++ ++ FTS_DEBUG("check whether tp is in romboot or not "); ++ /* need reset to romboot when non-romboot state */ ++ ret = fts_fwupg_get_boot_state(upg, &status); ++ if (status != FTS_RUN_IN_ROM) { ++ if (FTS_RUN_IN_PRAM == status) { ++ FTS_INFO("tp is in pramboot, need send reset cmd before upgrade"); ++ ret = fts_pram_init(); ++ if (ret < 0) { ++ FTS_ERROR("pramboot(before) init fail"); ++ return ret; ++ } ++ } ++ ++ FTS_INFO("tp isn't in romboot, need send reset to romboot"); ++ ret = fts_fwupg_reset_to_romboot(upg); ++ if (ret < 0) { ++ FTS_ERROR("reset to romboot fail"); ++ return ret; ++ } ++ } ++ ++ /* check the length of the pramboot */ ++ ret = fts_pram_write_remap(upg); ++ if (ret < 0) { ++ FTS_ERROR("pram write fail, ret=%d", ret); ++ return ret; ++ } ++ ++ FTS_DEBUG("after write pramboot, confirm run in pramboot"); ++ state = fts_fwupg_check_state(upg, FTS_RUN_IN_PRAM); ++ if (!state) { ++ FTS_ERROR("not in pramboot"); ++ return -EIO; ++ } ++ ++ ret = fts_pram_init(); ++ if (ret < 0) { ++ FTS_ERROR("pramboot init fail"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static bool fts_fwupg_check_fw_valid(void) ++{ ++ int ret = 0; ++ ++ ret = fts_wait_tp_to_valid(); ++ if (ret < 0) { ++ FTS_INFO("tp fw invaild"); ++ return false; ++ } ++ ++ FTS_INFO("tp fw vaild"); ++ return true; ++} ++ ++/************************************************************************ ++* Name: fts_fwupg_check_state ++* Brief: confirm tp run in which mode: romboot/pramboot/bootloader ++* Input: ++* Output: ++* Return: return true if state is match, otherwise return false ++***********************************************************************/ ++static bool fts_fwupg_check_state( ++ struct fts_upgrade *upg, enum FW_STATUS rstate) ++{ ++ int ret = 0; ++ int i = 0; ++ enum FW_STATUS cstate = FTS_RUN_IN_ERROR; ++ ++ for (i = 0; i < FTS_UPGRADE_LOOP; i++) { ++ ret = fts_fwupg_get_boot_state(upg, &cstate); ++ /* FTS_DEBUG("fw state=%d, retries=%d", cstate, i); */ ++ if (cstate == rstate) ++ return true; ++ msleep(FTS_DELAY_READ_ID); ++ } ++ ++ return false; ++} ++ ++/************************************************************************ ++* Name: fts_fwupg_reset_in_boot ++* Brief: RST CMD(07), reset to romboot(bootloader) in boot environment ++* Input: ++* Output: ++* Return: return 0 if success, otherwise return error code ++***********************************************************************/ ++int fts_fwupg_reset_in_boot(void) ++{ ++ int ret = 0; ++ u8 cmd = FTS_CMD_RESET; ++ ++ FTS_INFO("reset in boot environment"); ++ ret = fts_write(&cmd, 1); ++ if (ret < 0) { ++ FTS_ERROR("pram/rom/bootloader reset cmd write fail"); ++ return ret; ++ } ++ ++ msleep(FTS_DELAY_UPGRADE_RESET); ++ return 0; ++} ++ ++/************************************************************************ ++* Name: fts_fwupg_enter_into_boot ++* Brief: enter into boot environment, ready for upgrade ++* Input: ++* Output: ++* Return: return 0 if success, otherwise return error code ++***********************************************************************/ ++int fts_fwupg_enter_into_boot(void) ++{ ++ int ret = 0; ++ bool fwvalid = false; ++ bool state = false; ++ struct fts_upgrade *upg = fwupgrade; ++ ++ FTS_INFO("***********enter into pramboot/bootloader***********"); ++ if ((!upg) || (NULL == upg->func)) { ++ FTS_ERROR("upgrade/func is null"); ++ return -EINVAL; ++ } ++ ++ fwvalid = fts_fwupg_check_fw_valid(); ++ if (fwvalid) { ++ ret = fts_fwupg_reset_to_boot(upg); ++ if (ret < 0) { ++ FTS_ERROR("enter into romboot/bootloader fail"); ++ return ret; ++ } ++ } else if (upg->func->read_boot_id_need_reset) { ++ ret = fts_fwupg_reset_in_boot(); ++ if (ret < 0) { ++ FTS_ERROR("reset before read boot id when fw invalid fail"); ++ return ret; ++ } ++ } ++ ++ if (upg->func->pramboot_supported) { ++ FTS_INFO("pram supported, write pramboot and init"); ++ /* pramboot */ ++ ret = fts_pram_write_init(upg); ++ if (ret < 0) { ++ FTS_ERROR("pram write_init fail"); ++ return ret; ++ } ++ } else { ++ FTS_DEBUG("pram not supported, confirm in bootloader"); ++ /* bootloader */ ++ state = fts_fwupg_check_state(upg, FTS_RUN_IN_BOOTLOADER); ++ if (!state) { ++ FTS_ERROR("fw not in bootloader, fail"); ++ return -EIO; ++ } ++ } ++ ++ return 0; ++} ++ ++/************************************************************************ ++ * Name: fts_fwupg_check_flash_status ++ * Brief: read status from tp ++ * Input: flash_status: correct value from tp ++ * retries: read retry times ++ * retries_delay: retry delay ++ * Output: ++ * Return: return true if flash status check pass, otherwise return false ++***********************************************************************/ ++static bool fts_fwupg_check_flash_status( ++ u16 flash_status, ++ int retries, ++ int retries_delay) ++{ ++ int ret = 0; ++ int i = 0; ++ u8 cmd = 0; ++ u8 val[FTS_CMD_FLASH_STATUS_LEN] = { 0 }; ++ u16 read_status = 0; ++ ++ for (i = 0; i < retries; i++) { ++ cmd = FTS_CMD_FLASH_STATUS; ++ ret = fts_read(&cmd , 1, val, FTS_CMD_FLASH_STATUS_LEN); ++ read_status = (((u16)val[0]) << 8) + val[1]; ++ if (flash_status == read_status) { ++ /* FTS_DEBUG("[UPGRADE]flash status ok"); */ ++ return true; ++ } ++ /* FTS_DEBUG("flash status fail,ok:%04x read:%04x, retries:%d", flash_status, read_status, i); */ ++ msleep(retries_delay); ++ } ++ ++ return false; ++} ++ ++/************************************************************************ ++ * Name: fts_fwupg_erase ++ * Brief: erase flash area ++ * Input: delay - delay after erase ++ * Output: ++ * Return: return 0 if success, otherwise return error code ++ ***********************************************************************/ ++int fts_fwupg_erase(u32 delay) ++{ ++ int ret = 0; ++ u8 cmd = 0; ++ bool flag = false; ++ ++ FTS_INFO("**********erase now**********"); ++ ++ /*send to erase flash*/ ++ cmd = FTS_CMD_ERASE_APP; ++ ret = fts_write(&cmd, 1); ++ if (ret < 0) { ++ FTS_ERROR("erase cmd fail"); ++ return ret; ++ } ++ msleep(delay); ++ ++ /* read status 0xF0AA: success */ ++ flag = fts_fwupg_check_flash_status(FTS_CMD_FLASH_STATUS_ERASE_OK, ++ FTS_RETRIES_REASE, ++ FTS_RETRIES_DELAY_REASE); ++ if (!flag) { ++ FTS_ERROR("ecc flash status check fail"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/************************************************************************ ++ * Name: fts_fwupg_ecc_cal ++ * Brief: calculate and get ecc from tp ++ * Input: saddr - start address need calculate ecc ++ * len - length need calculate ecc ++ * Output: ++ * Return: return data ecc of tp if success, otherwise return error code ++ ***********************************************************************/ ++int fts_fwupg_ecc_cal(u32 saddr, u32 len) ++{ ++ int ret = 0; ++ u32 i = 0; ++ u8 wbuf[FTS_CMD_ECC_CAL_LEN] = { 0 }; ++ u8 val[FTS_CMD_FLASH_STATUS_LEN] = { 0 }; ++ int ecc = 0; ++ int ecc_len = 0; ++ u32 packet_num = 0; ++ u32 packet_len = 0; ++ u32 remainder = 0; ++ u32 addr = 0; ++ u32 offset = 0; ++ struct fts_upgrade *upg = fwupgrade; ++ ++ FTS_INFO( "**********read out checksum**********"); ++ if ((NULL == upg) || (NULL == upg->func)) { ++ FTS_ERROR("upgrade/func is null"); ++ return -EINVAL; ++ } ++ ++ /* check sum init */ ++ wbuf[0] = FTS_CMD_ECC_INIT; ++ ret = fts_write(wbuf, 1); ++ if (ret < 0) { ++ FTS_ERROR("ecc init cmd write fail"); ++ return ret; ++ } ++ ++ packet_num = len / FTS_MAX_LEN_ECC_CALC; ++ remainder = len % FTS_MAX_LEN_ECC_CALC; ++ if (remainder) ++ packet_num++; ++ packet_len = FTS_MAX_LEN_ECC_CALC; ++ FTS_INFO("ecc calc num:%d, remainder:%d", packet_num, remainder); ++ ++ /* send commond to start checksum */ ++ wbuf[0] = FTS_CMD_ECC_CAL; ++ for (i = 0; i < packet_num; i++) { ++ offset = FTS_MAX_LEN_ECC_CALC * i; ++ addr = saddr + offset; ++ wbuf[1] = BYTE_OFF_16(addr); ++ wbuf[2] = BYTE_OFF_8(addr); ++ wbuf[3] = BYTE_OFF_0(addr); ++ ++ if ((i == (packet_num - 1)) && remainder) ++ packet_len = remainder; ++ wbuf[4] = BYTE_OFF_8(packet_len); ++ wbuf[5] = BYTE_OFF_0(packet_len); ++ ++ FTS_DEBUG("ecc calc startaddr:0x%04x, len:%d", addr, packet_len); ++ ret = fts_write(wbuf, FTS_CMD_ECC_CAL_LEN); ++ if (ret < 0) { ++ FTS_ERROR("ecc calc cmd write fail"); ++ return ret; ++ } ++ ++ msleep(packet_len / 256); ++ ++ /* read status if check sum is finished */ ++ ret = fts_fwupg_check_flash_status(FTS_CMD_FLASH_STATUS_ECC_OK, ++ FTS_RETRIES_ECC_CAL, ++ FTS_RETRIES_DELAY_ECC_CAL); ++ if (ret < 0) { ++ FTS_ERROR("ecc flash status read fail"); ++ return ret; ++ } ++ } ++ ++ ecc_len = 1; ++ if (ECC_CHECK_MODE_CRC16 == upg->func->fw_ecc_check_mode) { ++ ecc_len = 2; ++ } ++ ++ /* read out check sum */ ++ wbuf[0] = FTS_CMD_ECC_READ; ++ ret = fts_read(wbuf, 1, val, ecc_len); ++ if (ret < 0) { ++ FTS_ERROR( "ecc read cmd write fail"); ++ return ret; ++ } ++ ++ if (ECC_CHECK_MODE_CRC16 == upg->func->fw_ecc_check_mode) { ++ ecc = (int)((u16)(val[0] << 8) + val[1]); ++ } else { ++ ecc = (int)val[0]; ++ } ++ ++ return ecc; ++} ++ ++/************************************************************************ ++ * Name: fts_flash_write_buf ++ * Brief: write buf data to flash address ++ * Input: saddr - start address data write to flash ++ * buf - data buffer ++ * len - data length ++ * delay - delay after write ++ * Output: ++ * Return: return data ecc of host if success, otherwise return error code ++ ***********************************************************************/ ++int fts_flash_write_buf( ++ u32 saddr, ++ u8 *buf, ++ u32 len, ++ u32 delay) ++{ ++ int ret = 0; ++ u32 i = 0; ++ u32 j = 0; ++ u32 packet_number = 0; ++ u32 packet_len = 0; ++ u32 addr = 0; ++ u32 offset = 0; ++ u32 remainder = 0; ++ u8 packet_buf[FTS_FLASH_PACKET_LENGTH + FTS_CMD_WRITE_LEN] = { 0 }; ++ u8 ecc_tmp = 0; ++ int ecc_in_host = 0; ++ u8 cmd = 0; ++ u8 val[FTS_CMD_FLASH_STATUS_LEN] = { 0 }; ++ u16 read_status = 0; ++ u16 wr_ok = 0; ++ struct fts_upgrade *upg = fwupgrade; ++ ++ FTS_INFO( "**********write data to flash**********"); ++ if ((!upg) || (!upg->func || !buf || !len)) { ++ FTS_ERROR("upgrade/func/buf/len is invalid"); ++ return -EINVAL; ++ } ++ ++ FTS_INFO("data buf start addr=0x%x, len=0x%x", saddr, len); ++ packet_number = len / FTS_FLASH_PACKET_LENGTH; ++ remainder = len % FTS_FLASH_PACKET_LENGTH; ++ if (remainder > 0) ++ packet_number++; ++ packet_len = FTS_FLASH_PACKET_LENGTH; ++ FTS_INFO("write data, num:%d remainder:%d", packet_number, remainder); ++ ++ packet_buf[0] = FTS_CMD_WRITE; ++ for (i = 0; i < packet_number; i++) { ++ offset = i * FTS_FLASH_PACKET_LENGTH; ++ addr = saddr + offset; ++ packet_buf[1] = BYTE_OFF_16(addr); ++ packet_buf[2] = BYTE_OFF_8(addr); ++ packet_buf[3] = BYTE_OFF_0(addr); ++ ++ /* last packet */ ++ if ((i == (packet_number - 1)) && remainder) ++ packet_len = remainder; ++ ++ packet_buf[4] = BYTE_OFF_8(packet_len); ++ packet_buf[5] = BYTE_OFF_0(packet_len); ++ ++ for (j = 0; j < packet_len; j++) { ++ packet_buf[FTS_CMD_WRITE_LEN + j] = buf[offset + j]; ++ ecc_tmp ^= packet_buf[FTS_CMD_WRITE_LEN + j]; ++ } ++ ++ ret = fts_write(packet_buf, packet_len + FTS_CMD_WRITE_LEN); ++ if (ret < 0) { ++ FTS_ERROR("app write fail"); ++ return ret; ++ } ++ mdelay(delay); ++ ++ /* read status */ ++ wr_ok = FTS_CMD_FLASH_STATUS_WRITE_OK + addr / packet_len; ++ for (j = 0; j < FTS_RETRIES_WRITE; j++) { ++ cmd = FTS_CMD_FLASH_STATUS; ++ ret = fts_read(&cmd , 1, val, FTS_CMD_FLASH_STATUS_LEN); ++ read_status = (((u16)val[0]) << 8) + val[1]; ++ /* FTS_INFO("%x %x", wr_ok, read_status); */ ++ if (wr_ok == read_status) { ++ break; ++ } ++ mdelay(FTS_RETRIES_DELAY_WRITE); ++ } ++ } ++ ++ ecc_in_host = (int)ecc_tmp; ++ if (ECC_CHECK_MODE_CRC16 == upg->func->fw_ecc_check_mode) { ++ ecc_in_host = (int)fts_crc16_calc_host(buf, len); ++ } ++ ++ return ecc_in_host; ++} ++ ++/************************************************************************ ++ * Name: fts_flash_read_buf ++ * Brief: read data from flash ++ * Input: saddr - start address data write to flash ++ * buf - buffer to store data read from flash ++ * len - read length ++ * Output: ++ * Return: return 0 if success, otherwise return error code ++ * ++ * Warning: can't call this function directly, need call in boot environment ++ ***********************************************************************/ ++static int fts_flash_read_buf(u32 saddr, u8 *buf, u32 len) ++{ ++ int ret = 0; ++ u32 i = 0; ++ u32 packet_number = 0; ++ u32 packet_len = 0; ++ u32 addr = 0; ++ u32 offset = 0; ++ u32 remainder = 0; ++ u8 wbuf[FTS_CMD_READ_LEN] = { 0 }; ++ ++ if ((NULL == buf) || (0 == len)) { ++ FTS_ERROR("buf is NULL or len is 0"); ++ return -EINVAL; ++ } ++ ++ packet_number = len / FTS_FLASH_PACKET_LENGTH; ++ remainder = len % FTS_FLASH_PACKET_LENGTH; ++ if (remainder > 0) { ++ packet_number++; ++ } ++ packet_len = FTS_FLASH_PACKET_LENGTH; ++ FTS_INFO("read packet_number:%d, remainder:%d", packet_number, remainder); ++ ++ wbuf[0] = FTS_CMD_READ; ++ for (i = 0; i < packet_number; i++) { ++ offset = i * FTS_FLASH_PACKET_LENGTH; ++ addr = saddr + offset; ++ wbuf[1] = BYTE_OFF_16(addr); ++ wbuf[2] = BYTE_OFF_8(addr); ++ wbuf[3] = BYTE_OFF_0(addr); ++ ++ /* last packet */ ++ if ((i == (packet_number - 1)) && remainder) ++ packet_len = remainder; ++ ++ ret = fts_write(wbuf, FTS_CMD_READ_LEN); ++ if (ret < 0) { ++ FTS_ERROR("pram/bootloader write 03 command fail"); ++ return ret; ++ } ++ ++ msleep(FTS_CMD_READ_DELAY); /* must wait, otherwise read wrong data */ ++ ret = fts_read(NULL, 0, buf + offset, packet_len); ++ if (ret < 0) { ++ FTS_ERROR("pram/bootloader read 03 command fail"); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++/************************************************************************ ++ * Name: fts_flash_read ++ * Brief: ++ * Input: addr - address of flash ++ * len - length of read ++ * Output: buf - data read from flash ++ * Return: return 0 if success, otherwise return error code ++ ***********************************************************************/ ++static int fts_flash_read(u32 addr, u8 *buf, u32 len) ++{ ++ int ret = 0; ++ ++ FTS_INFO("***********read flash***********"); ++ if ((NULL == buf) || (0 == len)) { ++ FTS_ERROR("buf is NULL or len is 0"); ++ return -EINVAL; ++ } ++ ++ ret = fts_fwupg_enter_into_boot(); ++ if (ret < 0) { ++ FTS_ERROR("enter into pramboot/bootloader fail"); ++ goto read_flash_err; ++ } ++ ++ ret = fts_flash_read_buf(addr, buf, len); ++ if (ret < 0) { ++ FTS_ERROR("read flash fail"); ++ goto read_flash_err; ++ } ++ ++read_flash_err: ++ /* reset to normal boot */ ++ ret = fts_fwupg_reset_in_boot(); ++ if (ret < 0) { ++ FTS_ERROR("reset to normal boot fail"); ++ } ++ return ret; ++} ++ ++static int fts_read_file(char *file_name, u8 **file_buf) ++{ ++ int ret = 0; ++ char file_path[FILE_NAME_LENGTH] = { 0 }; ++ struct file *filp = NULL; ++ struct inode *inode; ++ mm_segment_t old_fs; ++ loff_t pos; ++ loff_t file_len = 0; ++ ++ if ((NULL == file_name) || (NULL == file_buf)) { ++ FTS_ERROR("filename/filebuf is NULL"); ++ return -EINVAL; ++ } ++ ++ snprintf(file_path, FILE_NAME_LENGTH, "%s%s", FTS_FW_BIN_FILEPATH, file_name); ++ filp = filp_open(file_path, O_RDONLY, 0); ++ if (IS_ERR(filp)) { ++ FTS_ERROR("open %s file fail", file_path); ++ return -ENOENT; ++ } ++ ++#if 1 ++ inode = filp->f_inode; ++#else ++ /* reserved for linux earlier verion */ ++ inode = filp->f_dentry->d_inode; ++#endif ++ ++ file_len = inode->i_size; ++ *file_buf = (u8 *)vmalloc(file_len); ++ if (NULL == *file_buf) { ++ FTS_ERROR("file buf malloc fail"); ++ filp_close(filp, NULL); ++ return -ENOMEM; ++ } ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ pos = 0; ++ ret = vfs_read(filp, *file_buf, file_len , &pos); ++ if (ret < 0) ++ FTS_ERROR("read file fail"); ++ FTS_INFO("file len:%d read len:%d pos:%d", (u32)file_len, ret, (u32)pos); ++ filp_close(filp, NULL); ++ set_fs(old_fs); ++ ++ return ret; ++} ++ ++int fts_upgrade_bin(char *fw_name, bool force) ++{ ++ int ret = 0; ++ u32 fw_file_len = 0; ++ u8 *fw_file_buf = NULL; ++ struct fts_upgrade *upg = fwupgrade; ++ ++ FTS_INFO("start upgrade with fw bin"); ++ if ((!upg) || (!upg->func) || !upg->ts_data) { ++ FTS_ERROR("upgrade/func/ts_data is null"); ++ return -EINVAL; ++ } ++ ++ upg->ts_data->fw_loading = 1; ++ fts_irq_disable(); ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_switch(DISABLE); ++#endif ++ ++ ret = fts_read_file(fw_name, &fw_file_buf); ++ if ((ret < 0) || (ret < FTS_MIN_LEN) || (ret > FTS_MAX_LEN_FILE)) { ++ FTS_ERROR("read fw bin file(sdcard) fail, len:%d", fw_file_len); ++ goto err_bin; ++ } ++ ++ fw_file_len = ret; ++ FTS_INFO("fw bin file len:%d", fw_file_len); ++ if (force) { ++ if (upg->func->force_upgrade) { ++ ret = upg->func->force_upgrade(fw_file_buf, fw_file_len); ++ } else { ++ FTS_INFO("force_upgrade function is null, no upgrade"); ++ goto err_bin; ++ } ++ } else { ++#if FTS_AUTO_LIC_UPGRADE_EN ++ if (upg->func->lic_upgrade) { ++ ret = upg->func->lic_upgrade(fw_file_buf, fw_file_len); ++ } else { ++ FTS_INFO("lic_upgrade function is null, no upgrade"); ++ } ++#endif ++ if (upg->func->upgrade) { ++ ret = upg->func->upgrade(fw_file_buf, fw_file_len); ++ } else { ++ FTS_INFO("upgrade function is null, no upgrade"); ++ } ++ } ++ ++ if (ret < 0) { ++ FTS_ERROR("upgrade fw bin failed"); ++ fts_fwupg_reset_in_boot(); ++ goto err_bin; ++ } ++ ++ FTS_INFO("upgrade fw bin success"); ++ ret = 0; ++ ++err_bin: ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_switch(ENABLE); ++#endif ++ fts_irq_enable(); ++ upg->ts_data->fw_loading = 0; ++ ++ if (fw_file_buf) { ++ vfree(fw_file_buf); ++ fw_file_buf = NULL; ++ } ++ return ret; ++} ++ ++int fts_enter_test_environment(bool test_state) ++{ ++ return 0; ++} ++#if FTS_AUTO_LIC_UPGRADE_EN ++static int fts_lic_get_vid_in_tp(u16 *vid) ++{ ++ int ret = 0; ++ u8 val[2] = { 0 }; ++ ++ if (NULL == vid) { ++ FTS_ERROR("vid is NULL"); ++ return -EINVAL; ++ } ++ ++ ret = fts_read_reg(FTS_REG_VENDOR_ID, &val[0]); ++ if (fts_data->ic_info.is_incell) ++ ret = fts_read_reg(FTS_REG_MODULE_ID, &val[1]); ++ if (ret < 0) { ++ FTS_ERROR("read vid from tp fail"); ++ return ret; ++ } ++ ++ *vid = *(u16 *)val; ++ return 0; ++} ++ ++static int fts_lic_get_vid_in_host(struct fts_upgrade *upg, u16 *vid) ++{ ++ u8 val[2] = { 0 }; ++ u8 *licbuf = NULL; ++ u32 conf_saddr = 0; ++ ++ if (!upg || !upg->func || !upg->lic || !vid) { ++ FTS_ERROR("upgrade/func/get_hlic_ver/lic/vid is null"); ++ return -EINVAL; ++ } ++ ++ if (upg->lic_length < FTS_MAX_LEN_SECTOR) { ++ FTS_ERROR("lic length(%x) fail", upg->lic_length); ++ return -EINVAL; ++ } ++ ++ licbuf = upg->lic; ++ conf_saddr = upg->func->fwcfgoff; ++ val[0] = licbuf[conf_saddr + FTS_CONIFG_VENDORID_OFF]; ++ if (fts_data->ic_info.is_incell) ++ val[1] = licbuf[conf_saddr + FTS_CONIFG_MODULEID_OFF]; ++ ++ *vid = *(u16 *)val; ++ return 0; ++} ++ ++static int fts_lic_get_ver_in_tp(u8 *ver) ++{ ++ int ret = 0; ++ ++ if (NULL == ver) { ++ FTS_ERROR("ver is NULL"); ++ return -EINVAL; ++ } ++ ++ ret = fts_read_reg(FTS_REG_LIC_VER, ver); ++ if (ret < 0) { ++ FTS_ERROR("read lcd initcode ver from tp fail"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int fts_lic_get_ver_in_host(struct fts_upgrade *upg, u8 *ver) ++{ ++ int ret = 0; ++ ++ if (!upg || !upg->func || !upg->func->get_hlic_ver || !upg->lic) { ++ FTS_ERROR("upgrade/func/get_hlic_ver/lic is null"); ++ return -EINVAL; ++ } ++ ++ ret = upg->func->get_hlic_ver(upg->lic); ++ if (ret < 0) { ++ FTS_ERROR("get host lcd initial code version fail"); ++ return ret; ++ } ++ ++ *ver = (u8)ret; ++ return ret; ++} ++ ++static bool fts_lic_need_upgrade(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ u8 initcode_ver_in_tp = 0; ++ u8 initcode_ver_in_host = 0; ++ u16 vid_in_tp = 0; ++ u16 vid_in_host = 0; ++ bool fwvalid = false; ++ ++ fwvalid = fts_fwupg_check_fw_valid(); ++ if ( !fwvalid) { ++ FTS_INFO("fw is invalid, no upgrade lcd init code"); ++ return false; ++ } ++ ++ ret = fts_lic_get_vid_in_host(upg, &vid_in_host); ++ if (ret < 0) { ++ FTS_ERROR("vendor id in host invalid"); ++ return false; ++ } ++ ++ ret = fts_lic_get_vid_in_tp(&vid_in_tp); ++ if (ret < 0) { ++ FTS_ERROR("vendor id in tp invalid"); ++ return false; ++ } ++ ++ FTS_DEBUG("vid in tp:0x%04x, host:0x%04x", vid_in_tp, vid_in_host); ++ if (vid_in_tp != vid_in_host) { ++ FTS_INFO("vendor id in tp&host are different, no upgrade lic"); ++ return false; ++ } ++ ++ ret = fts_lic_get_ver_in_host(upg, &initcode_ver_in_host); ++ if (ret < 0) { ++ FTS_ERROR("init code in host invalid"); ++ return false; ++ } ++ ++ ret = fts_lic_get_ver_in_tp(&initcode_ver_in_tp); ++ if (ret < 0) { ++ FTS_ERROR("read reg0xE4 fail"); ++ return false; ++ } ++ ++ FTS_DEBUG("lcd initial code version in tp:%x, host:%x", ++ initcode_ver_in_tp, initcode_ver_in_host); ++ if (0xA5 == initcode_ver_in_tp) { ++ FTS_INFO("lcd init code ver is 0xA5, don't upgade init code"); ++ return false; ++ } else if (0xFF == initcode_ver_in_tp) { ++ FTS_DEBUG("lcd init code in tp is invalid, need upgrade init code"); ++ return true; ++ } else if (initcode_ver_in_tp < initcode_ver_in_host) ++ return true; ++ else ++ return false; ++} ++ ++static int fts_lic_upgrade(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ bool hlic_upgrade = false; ++ int upgrade_count = 0; ++ u8 ver = 0; ++ ++ FTS_INFO("lcd initial code auto upgrade function"); ++ if ((!upg) || (!upg->func) || (!upg->func->lic_upgrade)) { ++ FTS_ERROR("lcd upgrade function is null"); ++ return -EINVAL; ++ } ++ ++ hlic_upgrade = fts_lic_need_upgrade(upg); ++ FTS_INFO("lcd init code upgrade flag:%d", hlic_upgrade); ++ if (hlic_upgrade) { ++ FTS_INFO("lcd initial code need upgrade, upgrade begin..."); ++ do { ++ FTS_INFO("lcd initial code upgrade times:%d", upgrade_count); ++ upgrade_count++; ++ ++ ret = upg->func->lic_upgrade(upg->lic, upg->lic_length); ++ if (ret < 0) { ++ fts_fwupg_reset_in_boot(); ++ } else { ++ fts_lic_get_ver_in_tp(&ver); ++ FTS_INFO("success upgrade to lcd initcode ver:%02x", ver); ++ break; ++ } ++ } while (upgrade_count < 2); ++ } else { ++ FTS_INFO("lcd initial code don't need upgrade"); ++ } ++ ++ return ret; ++} ++#endif /* FTS_AUTO_LIC_UPGRADE_EN */ ++ ++ ++static int fts_param_get_ver_in_tp(u8 *ver) ++{ ++ int ret = 0; ++ ++ if (NULL == ver) { ++ FTS_ERROR("ver is NULL"); ++ return -EINVAL; ++ } ++ ++ ret = fts_read_reg(FTS_REG_IDE_PARA_VER_ID, ver); ++ if (ret < 0) { ++ FTS_ERROR("read fw param ver from tp fail"); ++ return ret; ++ } ++ ++ if ((0x00 == *ver) || (0xFF == *ver)) { ++ FTS_INFO("param version in tp invalid"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int fts_param_get_ver_in_host(struct fts_upgrade *upg, u8 *ver) ++{ ++ if ((!upg) || (!upg->func) || (!upg->fw) || (!ver)) { ++ FTS_ERROR("fts_data/upgrade/func/fw/ver is NULL"); ++ return -EINVAL; ++ } ++ ++ if (upg->fw_length < upg->func->paramcfgveroff) { ++ FTS_ERROR("fw len(%x) < paramcfg ver offset(%x)", ++ upg->fw_length, upg->func->paramcfgveroff); ++ return -EINVAL; ++ } ++ ++ FTS_INFO("fw paramcfg version offset:%x", upg->func->paramcfgveroff); ++ *ver = upg->fw[upg->func->paramcfgveroff]; ++ ++ if ((0x00 == *ver) || (0xFF == *ver)) { ++ FTS_INFO("param version in host invalid"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/* ++ * return: < 0 : error ++ * == 0: no ide ++ * == 1: ide ++ */ ++static int fts_param_ide_in_host(struct fts_upgrade *upg) ++{ ++ u32 off = 0; ++ ++ if ((!upg) || (!upg->func) || (!upg->fw)) { ++ FTS_ERROR("fts_data/upgrade/func/fw is NULL"); ++ return -EINVAL; ++ } ++ ++ if (upg->fw_length < upg->func->paramcfgoff + FTS_FW_IDE_SIG_LEN) { ++ FTS_INFO("fw len(%x) < paramcfg offset(%x), no IDE", ++ upg->fw_length, upg->func->paramcfgoff + FTS_FW_IDE_SIG_LEN); ++ return 0; ++ } ++ ++ off = upg->func->paramcfgoff; ++ if (0 == memcmp(&upg->fw[off], FTS_FW_IDE_SIG, FTS_FW_IDE_SIG_LEN)) { ++ FTS_INFO("fw in host is IDE version"); ++ return 1; ++ } ++ ++ FTS_INFO("fw in host isn't IDE version"); ++ return 0; ++} ++ ++/* ++ * return: < 0 : error ++ * 0 : no ide ++ * 1 : ide ++ */ ++static int fts_param_ide_in_tp(u8 *val) ++{ ++ int ret = 0; ++ ++ ret = fts_read_reg(FTS_REG_IDE_PARA_STATUS, val); ++ if (ret < 0) { ++ FTS_ERROR("read IDE PARAM STATUS in tp fail"); ++ return ret; ++ } ++ ++ if ((*val != 0xFF) && ((*val & 0x80) == 0x80)) { ++ FTS_INFO("fw in tp is IDE version"); ++ return 1; ++ } ++ ++ FTS_INFO("fw in tp isn't IDE version"); ++ return 0; ++} ++ ++/************************************************************************ ++ * fts_param_need_upgrade - check fw paramcfg need upgrade or not ++ * ++ * Return: < 0 : error if paramcfg need upgrade ++ * 0 : no need upgrade ++ * 1 : need upgrade app + param ++ * 2 : need upgrade param ++ ***********************************************************************/ ++static int fts_param_need_upgrade(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ u8 val = 0; ++ int ide_in_host = 0; ++ int ide_in_tp = 0; ++ u8 ver_in_host = 0; ++ u8 ver_in_tp = 0; ++ bool fwvalid = false; ++ ++ fwvalid = fts_fwupg_check_fw_valid(); ++ if ( !fwvalid) { ++ FTS_INFO("fw is invalid, upgrade app+param"); ++ return 1; ++ } ++ ++ ide_in_host = fts_param_ide_in_host(upg); ++ if (ide_in_host < 0) { ++ FTS_INFO("fts_param_ide_in_host fail"); ++ return ide_in_host; ++ } ++ ++ ide_in_tp = fts_param_ide_in_tp(&val); ++ if (ide_in_tp < 0) { ++ FTS_INFO("fts_param_ide_in_tp fail"); ++ return ide_in_tp; ++ } ++ ++ if ((0 == ide_in_host) && (0 == ide_in_tp)) { ++ FTS_INFO("fw in host&tp are both no ide"); ++ return 0; ++ } else if (ide_in_host != ide_in_tp) { ++ FTS_INFO("fw in host&tp not equal, need upgrade app+param"); ++ return 1; ++ } else if ((1 == ide_in_host) && (1 == ide_in_tp)) { ++ FTS_INFO("fw in host&tp are both ide"); ++ if ((val & 0x7F) != 0x00) { ++ FTS_INFO("param invalid, need upgrade param"); ++ return 2; ++ } ++ ++ ret = fts_param_get_ver_in_host(upg, &ver_in_host); ++ if (ret < 0) { ++ FTS_ERROR("param version in host invalid"); ++ return ret; ++ } ++ ++ ret = fts_param_get_ver_in_tp(&ver_in_tp); ++ if (ret < 0) { ++ FTS_ERROR("get IDE param ver in tp fail"); ++ return ret; ++ } ++ ++ FTS_INFO("fw paramcfg version in tp:%x, host:%x", ++ ver_in_tp, ver_in_host); ++ if (ver_in_tp != ver_in_host) { ++ return 2; ++ } ++ } ++ ++ return 0; ++} ++ ++static int fts_fwupg_get_ver_in_tp(u8 *ver) ++{ ++ int ret = 0; ++ ++ if (NULL == ver) { ++ FTS_ERROR("ver is NULL"); ++ return -EINVAL; ++ } ++ ++ ret = fts_read_reg(FTS_REG_FW_VER, ver); ++ if (ret < 0) { ++ FTS_ERROR("read fw ver from tp fail"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int fts_fwupg_get_ver_in_host(struct fts_upgrade *upg, u8 *ver) ++{ ++ if ((!upg) || (!upg->func) || (!upg->fw) || (!ver)) { ++ FTS_ERROR("fts_data/upgrade/func/fw/ver is NULL"); ++ return -EINVAL; ++ } ++ ++ if (upg->fw_length < upg->func->fwveroff) { ++ FTS_ERROR("fw len(0x%0x) < fw ver offset(0x%x)", ++ upg->fw_length, upg->func->fwveroff); ++ return -EINVAL; ++ } ++ ++ FTS_INFO("fw version offset:0x%x", upg->func->fwveroff); ++ *ver = upg->fw[upg->func->fwveroff]; ++ return 0; ++} ++ ++static bool fts_fwupg_need_upgrade(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ bool fwvalid = false; ++ u8 fw_ver_in_host = 0; ++ u8 fw_ver_in_tp = 0; ++ ++ fwvalid = fts_fwupg_check_fw_valid(); ++ if (fwvalid) { ++ ret = fts_fwupg_get_ver_in_host(upg, &fw_ver_in_host); ++ if (ret < 0) { ++ FTS_ERROR("get fw ver in host fail"); ++ return false; ++ } ++ ++ ret = fts_fwupg_get_ver_in_tp(&fw_ver_in_tp); ++ if (ret < 0) { ++ FTS_ERROR("get fw ver in tp fail"); ++ return false; ++ } ++ ++ FTS_INFO("fw version in tp:%x, host:%x", fw_ver_in_tp, fw_ver_in_host); ++ if (fw_ver_in_tp != fw_ver_in_host) { ++ return true; ++ } ++ } else { ++ FTS_INFO("fw invalid, need upgrade fw"); ++ return true; ++ } ++ ++ return false; ++} ++ ++/************************************************************************ ++ * Name: fts_fw_upgrade ++ * Brief: fw upgrade main entry, run in following steps ++ * 1. check fw version(A6), not equal, will upgrade app(+param) ++ * 2. if fw version equal, will check ide, will upgrade app(+param) ++ * in the follow situation ++ * a. host&tp IDE's type are not equal, will upgrade app+param ++ * b. host&tp are both IDE's type, and param's version are not ++ * equal, will upgrade param ++ * Input: ++ * Output: ++ * Return: return 0 if success, otherwise return error code ++ ***********************************************************************/ ++int fts_fwupg_upgrade(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ bool upgrade_flag = false; ++ int upgrade_count = 0; ++ u8 ver = 0; ++ ++ FTS_INFO("fw auto upgrade function"); ++ if ((NULL == upg) || (NULL == upg->func)) { ++ FTS_ERROR("upg/upg->func is null"); ++ return -EINVAL; ++ } ++ ++ upgrade_flag = fts_fwupg_need_upgrade(upg); ++ FTS_INFO("fw upgrade flag:%d", upgrade_flag); ++ do { ++ upgrade_count++; ++ if (upgrade_flag) { ++ FTS_INFO("upgrade fw app(times:%d)", upgrade_count); ++ if (upg->func->upgrade) { ++ ret = upg->func->upgrade(upg->fw, upg->fw_length); ++ if (ret < 0) { ++ fts_fwupg_reset_in_boot(); ++ } else { ++ fts_fwupg_get_ver_in_tp(&ver); ++ FTS_INFO("success upgrade to fw version %02x", ver); ++ break; ++ } ++ } else { ++ FTS_ERROR("upgrade func/upgrade is null, return immediately"); ++ ret = -ENODATA; ++ break; ++ } ++ } else { ++ if (upg->func->param_upgrade) { ++ ret = fts_param_need_upgrade(upg); ++ if (ret <= 0) { ++ FTS_INFO("param don't need upgrade"); ++ break; ++ } else if (1 == ret) { ++ FTS_INFO("force upgrade fw app(times:%d)", upgrade_count); ++ if (upg->func->upgrade) { ++ ret = upg->func->upgrade(upg->fw, upg->fw_length); ++ if (ret < 0) { ++ fts_fwupg_reset_in_boot(); ++ } else { ++ break; ++ } ++ } ++ } else if (2 == ret) { ++ FTS_INFO("upgrade param area(times:%d)", upgrade_count); ++ ret = upg->func->param_upgrade(upg->fw, upg->fw_length); ++ if (ret < 0) { ++ fts_fwupg_reset_in_boot(); ++ } else { ++ fts_param_get_ver_in_tp(&ver); ++ FTS_INFO("success upgrade to fw param version %02x", ver); ++ break; ++ } ++ } else ++ break; ++ } else { ++ break; ++ } ++ } ++ } while (upgrade_count < 2); ++ ++ return ret; ++} ++ ++/************************************************************************ ++ * fts_fwupg_auto_upgrade - upgrade main entry ++ ***********************************************************************/ ++static void fts_fwupg_auto_upgrade(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ ++ FTS_INFO("********************FTS enter upgrade********************"); ++ if (!upg || !upg->ts_data) { ++ FTS_ERROR("upg/ts_data is null"); ++ return ; ++ } ++ ++ ret = fts_fwupg_upgrade(upg); ++ if (ret < 0) ++ FTS_ERROR("**********tp fw(app/param) upgrade failed**********"); ++ else ++ FTS_INFO("**********tp fw(app/param) no upgrade/upgrade success**********"); ++ ++#if FTS_AUTO_LIC_UPGRADE_EN ++ ret = fts_lic_upgrade(upg); ++ if (ret < 0) ++ FTS_ERROR("**********lcd init code upgrade failed**********"); ++ else ++ FTS_INFO("**********lcd init code no upgrade/upgrade success**********"); ++#endif ++ ++ FTS_INFO("********************FTS exit upgrade********************"); ++} ++ ++static int fts_fwupg_get_vendorid(struct fts_upgrade *upg, int *vid) ++{ ++ int ret = 0; ++ bool fwvalid = false; ++ u8 vendor_id = 0; ++ u8 module_id = 0; ++ u32 fwcfg_addr = 0; ++ u8 cfgbuf[FTS_HEADER_LEN] = { 0 }; ++ ++ FTS_INFO("read vendor id from tp"); ++ if ((!upg) || (!upg->func) || (!upg->ts_data) || (!vid)) { ++ FTS_ERROR("upgrade/func/ts_data/vid is null"); ++ return -EINVAL; ++ } ++ ++ fwvalid = fts_fwupg_check_fw_valid(); ++ if (fwvalid) { ++ ret = fts_read_reg(FTS_REG_VENDOR_ID, &vendor_id); ++ if (upg->ts_data->ic_info.is_incell) ++ ret = fts_read_reg(FTS_REG_MODULE_ID, &module_id); ++ } else { ++ fwcfg_addr = upg->func->fwcfgoff; ++ ret = fts_flash_read(fwcfg_addr, cfgbuf, FTS_HEADER_LEN); ++ vendor_id = cfgbuf[FTS_CONIFG_VENDORID_OFF]; ++ if (upg->ts_data->ic_info.is_incell) { ++ if ((cfgbuf[FTS_CONIFG_MODULEID_OFF] + ++ cfgbuf[FTS_CONIFG_MODULEID_OFF + 1]) == 0xFF) ++ module_id = cfgbuf[FTS_CONIFG_MODULEID_OFF]; ++ } ++ } ++ ++ if (ret < 0) { ++ FTS_ERROR("fail to get vendor id from tp"); ++ return ret; ++ } ++ ++ *vid = (int)((module_id << 8) + vendor_id); ++ return 0; ++} ++ ++static int fts_fwupg_get_module_info(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ int i = 0; ++ struct upgrade_module *info = &module_list[0]; ++ ++ if (!upg || !upg->ts_data) { ++ FTS_ERROR("upg/ts_data is null"); ++ return -EINVAL; ++ } ++ ++ if (FTS_GET_MODULE_NUM > 1) { ++ /* support multi modules, must read correct module id(vendor id) */ ++ ret = fts_fwupg_get_vendorid(upg, &upg->module_id); ++ if (ret < 0) { ++ FTS_ERROR("get vendor id failed"); ++ return ret; ++ } ++ FTS_INFO("module id:%04x", upg->module_id); ++ for (i = 0; i < FTS_GET_MODULE_NUM; i++) { ++ info = &module_list[i]; ++ if (upg->module_id == info->id) { ++ FTS_INFO("module id match, get module info pass"); ++ break; ++ } ++ } ++ if (i >= FTS_GET_MODULE_NUM) { ++ FTS_ERROR("no module id match, don't get file"); ++ return -ENODATA; ++ } ++ } ++ ++ upg->module_info = info; ++ return 0; ++} ++ ++static int fts_get_fw_file_via_request_firmware(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ const struct firmware *fw = NULL; ++ u8 *tmpbuf = NULL; ++ char fwname[FILE_NAME_LENGTH] = { 0 }; ++ ++ if (!upg || !upg->ts_data || !upg->ts_data->dev) { ++ FTS_ERROR("upg/ts_data/dev is null"); ++ return -EINVAL; ++ } ++ ++ snprintf(fwname, FILE_NAME_LENGTH, "%s%s.bin", \ ++ FTS_FW_NAME_PREX_WITH_REQUEST, \ ++ upg->module_info->vendor_name); ++ ++ ret = request_firmware(&fw, fwname, upg->ts_data->dev); ++ if (0 == ret) { ++ FTS_INFO("firmware(%s) request successfully", fwname); ++ tmpbuf = vmalloc(fw->size); ++ if (NULL == tmpbuf) { ++ FTS_ERROR("fw buffer vmalloc fail"); ++ ret = -ENOMEM; ++ } else { ++ memcpy(tmpbuf, fw->data, fw->size); ++ upg->fw = tmpbuf; ++ upg->fw_length = fw->size; ++ upg->fw_from_request = 1; ++ } ++ } else { ++ FTS_INFO("firmware(%s) request fail,ret=%d", fwname, ret); ++ } ++ ++ if (fw != NULL) { ++ release_firmware(fw); ++ fw = NULL; ++ } ++ ++ return ret; ++} ++ ++static int fts_get_fw_file_via_i(struct fts_upgrade *upg) ++{ ++ upg->fw = upg->module_info->fw_file; ++ upg->fw_length = upg->module_info->fw_len; ++ upg->fw_from_request = 0; ++ ++ return 0; ++} ++ ++/***************************************************************************** ++ * Name: fts_fwupg_get_fw_file ++ * Brief: get fw image/file, ++ * If support muitl modules, please set FTS_GET_MODULE_NUM, and FTS_- ++ * MODULE_ID/FTS_MODULE_NAME; ++ * If get fw via .i file, please set FTS_FW_REQUEST_SUPPORT=0, and F- ++ * TS_MODULE_ID; will use module id to distingwish different modules; ++ * If get fw via reques_firmware(), please set FTS_FW_REQUEST_SUPPORT ++ * =1, and FTS_MODULE_NAME; fw file name will be composed of "focalt- ++ * ech_ts_fw_" & FTS_VENDOR_NAME; ++ * ++ * If have flash, module_id=vendor_id, If non-flash,module_id need ++ * transfer from LCD driver(gpio or lcm_id or ...); ++ * Input: ++ * Output: ++ * Return: return 0 if success, otherwise return error code ++ *****************************************************************************/ ++static int fts_fwupg_get_fw_file(struct fts_upgrade *upg) ++{ ++ int ret = 0; ++ bool get_fw_i_flag = false; ++ ++ FTS_DEBUG("get upgrade fw file"); ++ if (!upg || !upg->ts_data) { ++ FTS_ERROR("upg/ts_data is null"); ++ return -EINVAL; ++ } ++ ++ ret = fts_fwupg_get_module_info(upg); ++ if ((ret < 0) || (!upg->module_info)) { ++ FTS_ERROR("get module info fail"); ++ return ret; ++ } ++ ++ if (FTS_FW_REQUEST_SUPPORT) { ++ ret = fts_get_fw_file_via_request_firmware(upg); ++ if (ret != 0) { ++ get_fw_i_flag = true; ++ } ++ } else { ++ get_fw_i_flag = true; ++ } ++ ++ if (get_fw_i_flag) { ++ ret = fts_get_fw_file_via_i(upg); ++ } ++ ++ upg->lic = upg->fw; ++ upg->lic_length = upg->fw_length; ++ ++ FTS_INFO("upgrade fw file len:%d", upg->fw_length); ++ if ((upg->fw_length < FTS_MIN_LEN) ++ || (upg->fw_length > FTS_MAX_LEN_FILE)) { ++ FTS_ERROR("fw file len(%d) fail", upg->fw_length); ++ return -ENODATA; ++ } ++ ++ return ret; ++} ++ ++static void fts_fwupg_init_ic_detail(struct fts_upgrade *upg) ++{ ++ if (upg && upg->func && upg->func->init) { ++ upg->func->init(upg->fw, upg->fw_length); ++ } ++} ++ ++/***************************************************************************** ++ * Name: fts_fwupg_work ++ * Brief: 1. get fw image/file ++ * 2. ic init if have ++ * 3. call upgrade main function(fts_fwupg_auto_upgrade) ++ * Input: ++ * Output: ++ * Return: ++ *****************************************************************************/ ++static void fts_fwupg_work(struct work_struct *work) ++{ ++ int ret = 0; ++ struct fts_upgrade *upg = fwupgrade; ++ ++#if !FTS_AUTO_UPGRADE_EN ++ FTS_INFO("FTS_AUTO_UPGRADE_EN is disabled, not upgrade when power on"); ++ return ; ++#endif ++ ++ FTS_INFO("fw upgrade work function"); ++ if (!upg || !upg->ts_data) { ++ FTS_ERROR("upg/ts_data is null"); ++ return ; ++ } ++ ++ upg->ts_data->fw_loading = 1; ++ fts_irq_disable(); ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_switch(DISABLE); ++#endif ++ ++ /* get fw */ ++ ret = fts_fwupg_get_fw_file(upg); ++ if (ret < 0) { ++ FTS_ERROR("get file fail, can't upgrade"); ++ } else { ++ /* ic init if have */ ++ fts_fwupg_init_ic_detail(upg); ++ /* run auto upgrade */ ++ fts_fwupg_auto_upgrade(upg); ++ } ++ ++#if FTS_ESDCHECK_EN ++ fts_esdcheck_switch(ENABLE); ++#endif ++ fts_irq_enable(); ++ upg->ts_data->fw_loading = 0; ++} ++ ++int fts_fwupg_init(struct fts_ts_data *ts_data) ++{ ++ int i = 0; ++ int j = 0; ++ int ic_stype = 0; ++ struct upgrade_func *func = upgrade_func_list[0]; ++ int func_count = sizeof(upgrade_func_list) / sizeof(upgrade_func_list[0]); ++ ++ FTS_INFO("fw upgrade init function"); ++ ++ if (!ts_data || !ts_data->ts_workqueue) { ++ FTS_ERROR("ts_data/workqueue is NULL, can't run upgrade function"); ++ return -EINVAL; ++ } ++ ++ if (0 == func_count) { ++ FTS_ERROR("no upgrade function in tp driver"); ++ return -ENODATA; ++ } ++ ++ fwupgrade = (struct fts_upgrade *)kzalloc(sizeof(*fwupgrade), GFP_KERNEL); ++ if (NULL == fwupgrade) { ++ FTS_ERROR("malloc memory for upgrade fail"); ++ return -ENOMEM; ++ } ++ ++ ic_stype = ts_data->ic_info.ids.type; ++ if (1 == func_count) { ++ fwupgrade->func = func; ++ } else { ++ for (i = 0; i < func_count; i++) { ++ func = upgrade_func_list[i]; ++ for (j = 0; j < FTX_MAX_COMPATIBLE_TYPE; j++) { ++ if (0 == func->ctype[j]) ++ break; ++ else if (func->ctype[j] == ic_stype) { ++ FTS_INFO("match upgrade function,type:%x", (int)func->ctype[j]); ++ fwupgrade->func = func; ++ } ++ } ++ } ++ } ++ ++ if (NULL == fwupgrade->func) { ++ FTS_ERROR("no upgrade function match, can't upgrade"); ++ kfree(fwupgrade); ++ fwupgrade = NULL; ++ return -ENODATA; ++ } ++ ++ fwupgrade->ts_data = ts_data; ++ INIT_WORK(&ts_data->fwupg_work, fts_fwupg_work); ++ queue_work(ts_data->ts_workqueue, &ts_data->fwupg_work); ++ ++ return 0; ++} ++ ++int fts_fwupg_exit(struct fts_ts_data *ts_data) ++{ ++ FTS_FUNC_ENTER(); ++ if (fwupgrade) { ++ if (fwupgrade->fw_from_request) { ++ vfree(fwupgrade->fw); ++ fwupgrade->fw = NULL; ++ } ++ ++ kfree(fwupgrade); ++ fwupgrade = NULL; ++ } ++ FTS_FUNC_EXIT(); ++ return 0; ++} +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash.h b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash.h +new file mode 100644 +index 000000000..fc6050272 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash.h +@@ -0,0 +1,205 @@ ++/************************************************************************ ++* Copyright (C) 2012-2019, Focaltech Systems (R)£¬All Rights Reserved. ++* ++* File Name: focaltech_flash.h ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-07 ++* ++* Abstract: ++* ++************************************************************************/ ++#ifndef __LINUX_FOCALTECH_FLASH_H__ ++#define __LINUX_FOCALTECH_FLASH_H__ ++ ++/***************************************************************************** ++* 1.Included header files ++*****************************************************************************/ ++#include "focaltech_core.h" ++ ++/***************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++#define FTS_CMD_RESET 0x07 ++#define FTS_ROMBOOT_CMD_SET_PRAM_ADDR 0xAD ++#define FTS_ROMBOOT_CMD_SET_PRAM_ADDR_LEN 4 ++#define FTS_ROMBOOT_CMD_WRITE 0xAE ++#define FTS_ROMBOOT_CMD_START_APP 0x08 ++#define FTS_DELAY_PRAMBOOT_START 10 ++#define FTS_ROMBOOT_CMD_ECC 0xCC ++#define FTS_PRAM_SADDR 0x000000 ++#define FTS_DRAM_SADDR 0xD00000 ++ ++#define FTS_CMD_READ 0x03 ++#define FTS_CMD_READ_DELAY 1 ++#define FTS_CMD_READ_LEN 4 ++#define FTS_CMD_FLASH_TYPE 0x05 ++#define FTS_CMD_FLASH_MODE 0x09 ++#define FLASH_MODE_WRITE_FLASH_VALUE 0x0A ++#define FLASH_MODE_UPGRADE_VALUE 0x0B ++#define FLASH_MODE_LIC_VALUE 0x0C ++#define FLASH_MODE_PARAM_VALUE 0x0D ++#define FTS_CMD_ERASE_APP 0x61 ++#define FTS_REASE_APP_DELAY 1350 ++#define FTS_ERASE_SECTOR_DELAY 60 ++#define FTS_RETRIES_REASE 50 ++#define FTS_RETRIES_DELAY_REASE 200 ++#define FTS_CMD_FLASH_STATUS 0x6A ++#define FTS_CMD_FLASH_STATUS_LEN 2 ++#define FTS_CMD_FLASH_STATUS_NOP 0x0000 ++#define FTS_CMD_FLASH_STATUS_ECC_OK 0xF055 ++#define FTS_CMD_FLASH_STATUS_ERASE_OK 0xF0AA ++#define FTS_CMD_FLASH_STATUS_WRITE_OK 0x1000 ++#define FTS_CMD_ECC_INIT 0x64 ++#define FTS_CMD_ECC_CAL 0x65 ++#define FTS_CMD_ECC_CAL_LEN 6 ++#define FTS_RETRIES_ECC_CAL 10 ++#define FTS_RETRIES_DELAY_ECC_CAL 50 ++#define FTS_CMD_ECC_READ 0x66 ++#define FTS_CMD_DATA_LEN 0xB0 ++#define FTS_CMD_APP_DATA_LEN_INCELL 0x7A ++#define FTS_CMD_DATA_LEN_LEN 4 ++#define FTS_CMD_WRITE 0xBF ++#define FTS_RETRIES_WRITE 100 ++#define FTS_RETRIES_DELAY_WRITE 1 ++#define FTS_CMD_WRITE_LEN 6 ++#define FTS_DELAY_READ_ID 20 ++#define FTS_DELAY_UPGRADE_RESET 80 ++#define PRAMBOOT_MIN_SIZE 0x120 ++#define PRAMBOOT_MAX_SIZE (64*1024) ++#define FTS_FLASH_PACKET_LENGTH 32 /* max=128 */ ++#define FTS_MAX_LEN_ECC_CALC 0xFFFE /* must be even */ ++#define FTS_MIN_LEN 0x120 ++#define FTS_MAX_LEN_FILE (128 * 1024) ++#define FTS_MAX_LEN_APP (64 * 1024) ++#define FTS_MAX_LEN_SECTOR (4 * 1024) ++#define FTS_CONIFG_VENDORID_OFF 0x04 ++#define FTS_CONIFG_MODULEID_OFF 0x1E ++#define FTS_CONIFG_PROJECTID_OFF 0x20 ++#define FTS_APPINFO_OFF 0x100 ++#define FTS_APPINFO_APPLEN_OFF 0x00 ++#define FTS_APPINFO_APPLEN2_OFF 0x12 ++#define FTS_REG_UPGRADE 0xFC ++#define FTS_REG_UPGRADE2 0xBC ++#define FTS_UPGRADE_AA 0xAA ++#define FTS_UPGRADE_55 0x55 ++#define FTS_DELAY_UPGRADE_AA 10 ++#define FTS_UPGRADE_LOOP 30 ++#define FTS_HEADER_LEN 32 ++#define FTS_FW_BIN_FILEPATH "/sdcard/" ++#define FTS_FW_IDE_SIG "IDE_" ++#define FTS_FW_IDE_SIG_LEN 4 ++#define MAX_MODULE_VENDOR_NAME_LEN 16 ++ ++#define FTS_ROMBOOT_CMD_ECC_NEW_LEN 7 ++#define FTS_ECC_FINISH_TIMEOUT 100 ++#define FTS_ROMBOOT_CMD_ECC_FINISH 0xCE ++#define FTS_ROMBOOT_CMD_ECC_FINISH_OK_A5 0xA5 ++#define FTS_ROMBOOT_CMD_ECC_FINISH_OK_00 0x00 ++#define FTS_ROMBOOT_CMD_ECC_READ 0xCD ++#define AL2_FCS_COEF ((1 << 15) + (1 << 10) + (1 << 3)) ++ ++#define FTS_APP_INFO_OFFSET 0x100 ++ ++enum FW_STATUS { ++ FTS_RUN_IN_ERROR, ++ FTS_RUN_IN_APP, ++ FTS_RUN_IN_ROM, ++ FTS_RUN_IN_PRAM, ++ FTS_RUN_IN_BOOTLOADER, ++}; ++ ++enum FW_FLASH_MODE { ++ FLASH_MODE_APP, ++ FLASH_MODE_LIC, ++ FLASH_MODE_PARAM, ++ FLASH_MODE_ALL, ++}; ++ ++enum ECC_CHECK_MODE { ++ ECC_CHECK_MODE_XOR, ++ ECC_CHECK_MODE_CRC16, ++}; ++ ++/***************************************************************************** ++* Private enumerations, structures and unions using typedef ++*****************************************************************************/ ++/* IC info */ ++struct upgrade_func { ++ u64 ctype[FTX_MAX_COMPATIBLE_TYPE]; ++ u32 fwveroff; ++ u32 fwcfgoff; ++ u32 appoff; ++ u32 licoff; ++ u32 paramcfgoff; ++ u32 paramcfgveroff; ++ u32 paramcfg2off; ++ int pram_ecc_check_mode; ++ int fw_ecc_check_mode; ++ bool new_return_value_from_ic; ++ bool appoff_handle_in_ic; ++ bool is_reset_register_BC; ++ bool read_boot_id_need_reset; ++ bool hid_supported; ++ bool pramboot_supported; ++ u8 *pramboot; ++ u32 pb_length; ++ int (*init)(u8 *, u32); ++ int (*upgrade)(u8 *, u32); ++ int (*get_hlic_ver)(u8 *); ++ int (*lic_upgrade)(u8 *, u32); ++ int (*param_upgrade)(u8 *, u32); ++ int (*force_upgrade)(u8 *, u32); ++}; ++ ++struct upgrade_setting_nf { ++ u8 rom_idh; ++ u8 rom_idl; ++ u16 reserved; ++ u32 app2_offset; ++ u32 ecclen_max; ++ u8 eccok_val; ++ u8 upgsts_boot; ++ u8 delay_init; ++ bool spi_pe; ++ bool half_length; ++ bool fd_check; ++ bool drwr_support; ++}; ++ ++struct upgrade_module { ++ int id; ++ char vendor_name[MAX_MODULE_VENDOR_NAME_LEN]; ++ u8 *fw_file; ++ u32 fw_len; ++}; ++ ++struct fts_upgrade { ++ struct fts_ts_data *ts_data; ++ struct upgrade_module *module_info; ++ struct upgrade_func *func; ++ struct upgrade_setting_nf *setting_nf; ++ int module_id; ++ bool fw_from_request; ++ u8 *fw; ++ u32 fw_length; ++ u8 *lic; ++ u32 lic_length; ++}; ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++extern struct upgrade_func upgrade_func_ft7511; ++ ++/***************************************************************************** ++* Static function prototypes ++*****************************************************************************/ ++int fts_fwupg_reset_in_boot(void); ++int fts_fwupg_enter_into_boot(void); ++int fts_fwupg_erase(u32 delay); ++int fts_fwupg_ecc_cal(u32 saddr, u32 len); ++int fts_flash_write_buf(u32 saddr, u8 *buf, u32 len, u32 delay); ++int fts_fwupg_upgrade(struct fts_upgrade *upg); ++#endif +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash/Makefile b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash/Makefile +new file mode 100644 +index 000000000..46829118f +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_ft7511.o +\ No newline at end of file +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft7511.c b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft7511.c +new file mode 100644 +index 000000000..f5d0e06e3 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft7511.c +@@ -0,0 +1,154 @@ ++/* ++ * ++ * FocalTech fts TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, Focaltech Ltd. 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. ++ * ++ */ ++ ++/***************************************************************************** ++* ++* File Name: focaltech_upgrade_ft7511.c ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-15 ++* ++* Abstract: ++* ++* Reference: ++* ++*****************************************************************************/ ++/***************************************************************************** ++* 1.Included header files ++*****************************************************************************/ ++#include "../focaltech_flash.h" ++ ++/***************************************************************************** ++* Static function prototypes ++*****************************************************************************/ ++static int fts_ft7511_init(u8 *buf, u32 len) ++{ ++ if ((!buf) || (len < FTS_MIN_LEN)) { ++ FTS_ERROR("upg is null/fw length fail"); ++ return -EINVAL; ++ } ++ ++ upgrade_func_ft7511.fwveroff = len - 2; ++ return 0; ++} ++ ++/************************************************************************ ++* Name: fts_ft7511_upgrade ++* Brief: ++* Input: ++* Output: ++* Return: return 0 if success, otherwise return error code ++***********************************************************************/ ++static int fts_ft7511_upgrade(u8 *buf, u32 len) ++{ ++ int ret = 0; ++ u32 start_addr = 0; ++ u8 cmd[4] = { 0 }; ++ int ecc_in_host = 0; ++ int ecc_in_tp = 0; ++ ++ if (NULL == buf) { ++ FTS_ERROR("fw buf is null"); ++ return -EINVAL; ++ } ++ ++ if ((len < FTS_MIN_LEN) || (len > (60 * 1024))) { ++ FTS_ERROR("fw buffer len(%x) fail", len); ++ return -EINVAL; ++ } ++ ++ /* enter into upgrade environment */ ++ ret = fts_fwupg_enter_into_boot(); ++ if (ret < 0) { ++ FTS_ERROR("enter into pramboot/bootloader fail,ret=%d", ret); ++ goto fw_reset; ++ } ++ ++ cmd[0] = FTS_CMD_FLASH_MODE; ++ cmd[1] = FLASH_MODE_UPGRADE_VALUE; ++ ret = fts_write(cmd, 2); ++ if (ret < 0) { ++ FTS_ERROR("upgrade mode(09) cmd write fail"); ++ goto fw_reset; ++ } ++ ++ cmd[0] = FTS_CMD_DATA_LEN; ++ cmd[1] = BYTE_OFF_16(len); ++ cmd[2] = BYTE_OFF_8(len); ++ cmd[3] = BYTE_OFF_0(len); ++ ret = fts_write(cmd, FTS_CMD_DATA_LEN_LEN); ++ if (ret < 0) { ++ FTS_ERROR("data len cmd write fail"); ++ goto fw_reset; ++ } ++ ++ ret = fts_fwupg_erase(FTS_REASE_APP_DELAY); ++ if (ret < 0) { ++ FTS_ERROR("erase cmd write fail"); ++ goto fw_reset; ++ } ++ ++ /* write app */ ++ start_addr = upgrade_func_ft7511.appoff; ++ ecc_in_host = fts_flash_write_buf(start_addr, buf, len, 1); ++ if (ecc_in_host < 0 ) { ++ FTS_ERROR("lcd initial code write fail"); ++ goto fw_reset; ++ } ++ ++ /* ecc */ ++ ecc_in_tp = fts_fwupg_ecc_cal(start_addr, len); ++ if (ecc_in_tp < 0 ) { ++ FTS_ERROR("ecc read fail"); ++ goto fw_reset; ++ } ++ ++ FTS_INFO("ecc in tp:%x, host:%x", ecc_in_tp, ecc_in_host); ++ if (ecc_in_tp != ecc_in_host) { ++ FTS_ERROR("ecc check fail"); ++ goto fw_reset; ++ } ++ ++ FTS_INFO("upgrade success, reset to normal boot"); ++ ret = fts_fwupg_reset_in_boot(); ++ if (ret < 0) { ++ FTS_ERROR("reset to normal boot fail"); ++ } ++ ++ msleep(200); ++ return 0; ++ ++fw_reset: ++ FTS_INFO("upgrade fail, reset to normal boot"); ++ ret = fts_fwupg_reset_in_boot(); ++ if (ret < 0) { ++ FTS_ERROR("reset to normal boot fail"); ++ } ++ return -EIO; ++} ++ ++struct upgrade_func upgrade_func_ft7511 = { ++ .ctype = {0x02}, ++ .fwveroff = 0x0000, ++ .fwcfgoff = 0xD780, ++ .appoff = 0x0000, ++ .pramboot_supported = false, ++ .hid_supported = true, ++ .init = fts_ft7511_init, ++ .upgrade = fts_ft7511_upgrade, ++}; +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c +new file mode 100644 +index 000000000..b65cf3945 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c +@@ -0,0 +1,460 @@ ++/* ++ * ++ * FocalTech TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, Focaltech Ltd. 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. ++ * ++ */ ++ ++/***************************************************************************** ++* ++* File Name: focaltech_gestrue.c ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-08 ++* ++* Abstract: ++* ++* Reference: ++* ++*****************************************************************************/ ++ ++/***************************************************************************** ++* 1.Included header files ++*****************************************************************************/ ++#include "focaltech_core.h" ++ ++/****************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++#define KEY_GESTURE_U KEY_U ++#define KEY_GESTURE_UP KEY_UP ++#define KEY_GESTURE_DOWN KEY_DOWN ++#define KEY_GESTURE_LEFT KEY_LEFT ++#define KEY_GESTURE_RIGHT KEY_RIGHT ++#define KEY_GESTURE_O KEY_O ++#define KEY_GESTURE_E KEY_E ++#define KEY_GESTURE_M KEY_M ++#define KEY_GESTURE_L KEY_L ++#define KEY_GESTURE_W KEY_W ++#define KEY_GESTURE_S KEY_S ++#define KEY_GESTURE_V KEY_V ++#define KEY_GESTURE_C KEY_C ++#define KEY_GESTURE_Z KEY_Z ++ ++#define GESTURE_LEFT 0x20 ++#define GESTURE_RIGHT 0x21 ++#define GESTURE_UP 0x22 ++#define GESTURE_DOWN 0x23 ++#define GESTURE_DOUBLECLICK 0x24 ++#define GESTURE_O 0x30 ++#define GESTURE_W 0x31 ++#define GESTURE_M 0x32 ++#define GESTURE_E 0x33 ++#define GESTURE_L 0x44 ++#define GESTURE_S 0x46 ++#define GESTURE_V 0x54 ++#define GESTURE_Z 0x41 ++#define GESTURE_C 0x34 ++ ++/***************************************************************************** ++* Private enumerations, structures and unions using typedef ++*****************************************************************************/ ++/* ++* gesture_id - mean which gesture is recognised ++* point_num - points number of this gesture ++* coordinate_x - All gesture point x coordinate ++* coordinate_y - All gesture point y coordinate ++* mode - gesture enable/disable, need enable by host ++* - 1:enable gesture function(default) 0:disable ++* active - gesture work flag, ++* always set 1 when suspend, set 0 when resume ++*/ ++struct fts_gesture_st { ++ u8 gesture_id; ++ u8 point_num; ++ u16 coordinate_x[FTS_GESTURE_POINTS_MAX]; ++ u16 coordinate_y[FTS_GESTURE_POINTS_MAX]; ++}; ++ ++/***************************************************************************** ++* Static variables ++*****************************************************************************/ ++static struct fts_gesture_st fts_gesture_data; ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Static function prototypes ++*****************************************************************************/ ++static ssize_t fts_gesture_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count = 0; ++ u8 val = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ ++ mutex_lock(&ts_data->input_dev->mutex); ++ fts_read_reg(FTS_REG_GESTURE_EN, &val); ++ count = snprintf(buf, PAGE_SIZE, "Gesture Mode:%s\n", ++ ts_data->gesture_mode ? "On" : "Off"); ++ count += snprintf(buf + count, PAGE_SIZE, "Reg(0xD0)=%d\n", val); ++ mutex_unlock(&ts_data->input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_gesture_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct fts_ts_data *ts_data = fts_data; ++ ++ mutex_lock(&ts_data->input_dev->mutex); ++ if (FTS_SYSFS_ECHO_ON(buf)) { ++ FTS_DEBUG("enable gesture"); ++ ts_data->gesture_mode = ENABLE; ++ } else if (FTS_SYSFS_ECHO_OFF(buf)) { ++ FTS_DEBUG("disable gesture"); ++ ts_data->gesture_mode = DISABLE; ++ } ++ mutex_unlock(&ts_data->input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_gesture_buf_show( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int count = 0; ++ int i = 0; ++ struct input_dev *input_dev = fts_data->input_dev; ++ struct fts_gesture_st *gesture = &fts_gesture_data; ++ ++ mutex_lock(&input_dev->mutex); ++ count = snprintf(buf, PAGE_SIZE, "Gesture ID:%d\n", gesture->gesture_id); ++ count += snprintf(buf + count, PAGE_SIZE, "Gesture PointNum:%d\n", ++ gesture->point_num); ++ count += snprintf(buf + count, PAGE_SIZE, "Gesture Points Buffer:\n"); ++ ++ /* save point data,max:6 */ ++ for (i = 0; i < FTS_GESTURE_POINTS_MAX; i++) { ++ count += snprintf(buf + count, PAGE_SIZE, "%3d(%4d,%4d) ", i, ++ gesture->coordinate_x[i], gesture->coordinate_y[i]); ++ if ((i + 1) % 4 == 0) ++ count += snprintf(buf + count, PAGE_SIZE, "\n"); ++ } ++ count += snprintf(buf + count, PAGE_SIZE, "\n"); ++ mutex_unlock(&input_dev->mutex); ++ ++ return count; ++} ++ ++static ssize_t fts_gesture_buf_store( ++ struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ return -EPERM; ++} ++ ++ ++/* sysfs gesture node ++ * read example: cat fts_gesture_mode ---read gesture mode ++ * write example:echo 1 > fts_gesture_mode --- write gesture mode to 1 ++ * ++ */ ++static DEVICE_ATTR(fts_gesture_mode, S_IRUGO | S_IWUSR, fts_gesture_show, ++ fts_gesture_store); ++/* ++ * read example: cat fts_gesture_buf --- read gesture buf ++ */ ++static DEVICE_ATTR(fts_gesture_buf, S_IRUGO | S_IWUSR, ++ fts_gesture_buf_show, fts_gesture_buf_store); ++ ++static struct attribute *fts_gesture_mode_attrs[] = { ++ &dev_attr_fts_gesture_mode.attr, ++ &dev_attr_fts_gesture_buf.attr, ++ NULL, ++}; ++ ++static struct attribute_group fts_gesture_group = { ++ .attrs = fts_gesture_mode_attrs, ++}; ++ ++static int fts_create_gesture_sysfs(struct device *dev) ++{ ++ int ret = 0; ++ ++ ret = sysfs_create_group(&dev->kobj, &fts_gesture_group); ++ if (ret) { ++ FTS_ERROR("gesture sys node create fail"); ++ sysfs_remove_group(&dev->kobj, &fts_gesture_group); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void fts_gesture_report(struct input_dev *input_dev, int gesture_id) ++{ ++ int gesture; ++ ++ FTS_DEBUG("gesture_id:0x%x", gesture_id); ++ switch (gesture_id) { ++ case GESTURE_LEFT: ++ gesture = KEY_GESTURE_LEFT; ++ break; ++ case GESTURE_RIGHT: ++ gesture = KEY_GESTURE_RIGHT; ++ break; ++ case GESTURE_UP: ++ gesture = KEY_GESTURE_UP; ++ break; ++ case GESTURE_DOWN: ++ gesture = KEY_GESTURE_DOWN; ++ break; ++ case GESTURE_DOUBLECLICK: ++ gesture = KEY_GESTURE_U; ++ break; ++ case GESTURE_O: ++ gesture = KEY_GESTURE_O; ++ break; ++ case GESTURE_W: ++ gesture = KEY_GESTURE_W; ++ break; ++ case GESTURE_M: ++ gesture = KEY_GESTURE_M; ++ break; ++ case GESTURE_E: ++ gesture = KEY_GESTURE_E; ++ break; ++ case GESTURE_L: ++ gesture = KEY_GESTURE_L; ++ break; ++ case GESTURE_S: ++ gesture = KEY_GESTURE_S; ++ break; ++ case GESTURE_V: ++ gesture = KEY_GESTURE_V; ++ break; ++ case GESTURE_Z: ++ gesture = KEY_GESTURE_Z; ++ break; ++ case GESTURE_C: ++ gesture = KEY_GESTURE_C; ++ break; ++ default: ++ gesture = -1; ++ break; ++ } ++ /* report event key */ ++ if (gesture != -1) { ++ FTS_DEBUG("Gesture Code=%d", gesture); ++ input_report_key(input_dev, gesture, 1); ++ input_sync(input_dev); ++ input_report_key(input_dev, gesture, 0); ++ input_sync(input_dev); ++ } ++} ++ ++/***************************************************************************** ++* Name: fts_gesture_readdata ++* Brief: Read information about gesture: enable flag/gesture points..., if ges- ++* ture enable, save gesture points' information, and report to OS. ++* It will be called this function every intrrupt when FTS_GESTURE_EN = 1 ++* ++* gesture data length: 1(enable) + 1(reserve) + 2(header) + 6 * 4 ++* Input: ts_data - global struct data ++* data - gesture data buffer if non-flash, else NULL ++* Output: ++* Return: 0 - read gesture data successfully, the report data is gesture data ++* 1 - tp not in suspend/gesture not enable in TP FW ++* -Exx - error ++*****************************************************************************/ ++int fts_gesture_readdata(struct fts_ts_data *ts_data, u8 *data) ++{ ++ int ret = 0; ++ int i = 0; ++ int index = 0; ++ u8 buf[FTS_GESTURE_DATA_LEN] = { 0 }; ++ struct input_dev *input_dev = ts_data->input_dev; ++ struct fts_gesture_st *gesture = &fts_gesture_data; ++ ++ if (!ts_data->suspended || !ts_data->gesture_mode) { ++ return 1; ++ } ++ ++ ++ ret = fts_read_reg(FTS_REG_GESTURE_EN, &buf[0]); ++ if ((ret < 0) || (buf[0] != ENABLE)) { ++ FTS_DEBUG("gesture not enable in fw, don't process gesture"); ++ return 1; ++ } ++ ++ buf[2] = FTS_REG_GESTURE_OUTPUT_ADDRESS; ++ ret = fts_read(&buf[2], 1, &buf[2], FTS_GESTURE_DATA_LEN - 2); ++ if (ret < 0) { ++ FTS_ERROR("read gesture header data fail"); ++ return ret; ++ } ++ ++ /* init variable before read gesture point */ ++ memset(gesture->coordinate_x, 0, FTS_GESTURE_POINTS_MAX * sizeof(u16)); ++ memset(gesture->coordinate_y, 0, FTS_GESTURE_POINTS_MAX * sizeof(u16)); ++ gesture->gesture_id = buf[2]; ++ gesture->point_num = buf[3]; ++ FTS_DEBUG("gesture_id=%d, point_num=%d", ++ gesture->gesture_id, gesture->point_num); ++ ++ /* save point data,max:6 */ ++ for (i = 0; i < FTS_GESTURE_POINTS_MAX; i++) { ++ index = 4 * i + 4; ++ gesture->coordinate_x[i] = (u16)(((buf[0 + index] & 0x0F) << 8) ++ + buf[1 + index]); ++ gesture->coordinate_y[i] = (u16)(((buf[2 + index] & 0x0F) << 8) ++ + buf[3 + index]); ++ } ++ ++ /* report gesture to OS */ ++ fts_gesture_report(input_dev, gesture->gesture_id); ++ return 0; ++} ++ ++void fts_gesture_recovery(struct fts_ts_data *ts_data) ++{ ++ if (ts_data->gesture_mode && ts_data->suspended) { ++ FTS_DEBUG("gesture recovery..."); ++ fts_write_reg(0xD1, 0xFF); ++ fts_write_reg(0xD2, 0xFF); ++ fts_write_reg(0xD5, 0xFF); ++ fts_write_reg(0xD6, 0xFF); ++ fts_write_reg(0xD7, 0xFF); ++ fts_write_reg(0xD8, 0xFF); ++ fts_write_reg(FTS_REG_GESTURE_EN, ENABLE); ++ } ++} ++ ++int fts_gesture_suspend(struct fts_ts_data *ts_data) ++{ ++ int i = 0; ++ u8 state = 0xFF; ++ ++ FTS_FUNC_ENTER(); ++ if (enable_irq_wake(ts_data->irq)) { ++ FTS_DEBUG("enable_irq_wake(irq:%d) fail", ts_data->irq); ++ } ++ ++ for (i = 0; i < 5; i++) { ++ fts_write_reg(0xD1, 0xFF); ++ fts_write_reg(0xD2, 0xFF); ++ fts_write_reg(0xD5, 0xFF); ++ fts_write_reg(0xD6, 0xFF); ++ fts_write_reg(0xD7, 0xFF); ++ fts_write_reg(0xD8, 0xFF); ++ fts_write_reg(FTS_REG_GESTURE_EN, ENABLE); ++ msleep(1); ++ fts_read_reg(FTS_REG_GESTURE_EN, &state); ++ if (state == ENABLE) ++ break; ++ } ++ ++ if (i >= 5) ++ FTS_ERROR("make IC enter into gesture(suspend) fail,state:%x", state); ++ else ++ FTS_INFO("Enter into gesture(suspend) successfully"); ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++int fts_gesture_resume(struct fts_ts_data *ts_data) ++{ ++ int i = 0; ++ u8 state = 0xFF; ++ ++ FTS_FUNC_ENTER(); ++ if (disable_irq_wake(ts_data->irq)) { ++ FTS_DEBUG("disable_irq_wake(irq:%d) fail", ts_data->irq); ++ } ++ ++ for (i = 0; i < 5; i++) { ++ fts_write_reg(FTS_REG_GESTURE_EN, DISABLE); ++ msleep(1); ++ fts_read_reg(FTS_REG_GESTURE_EN, &state); ++ if (state == DISABLE) ++ break; ++ } ++ ++ if (i >= 5) ++ FTS_ERROR("make IC exit gesture(resume) fail,state:%x", state); ++ else ++ FTS_INFO("resume from gesture successfully"); ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++int fts_gesture_init(struct fts_ts_data *ts_data) ++{ ++ struct input_dev *input_dev = ts_data->input_dev; ++ ++ FTS_FUNC_ENTER(); ++ input_set_capability(input_dev, EV_KEY, KEY_POWER); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_U); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_UP); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_DOWN); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_LEFT); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_RIGHT); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_O); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_E); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_M); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_L); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_W); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_S); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_V); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_Z); ++ input_set_capability(input_dev, EV_KEY, KEY_GESTURE_C); ++ ++ __set_bit(KEY_GESTURE_RIGHT, input_dev->keybit); ++ __set_bit(KEY_GESTURE_LEFT, input_dev->keybit); ++ __set_bit(KEY_GESTURE_UP, input_dev->keybit); ++ __set_bit(KEY_GESTURE_DOWN, input_dev->keybit); ++ __set_bit(KEY_GESTURE_U, input_dev->keybit); ++ __set_bit(KEY_GESTURE_O, input_dev->keybit); ++ __set_bit(KEY_GESTURE_E, input_dev->keybit); ++ __set_bit(KEY_GESTURE_M, input_dev->keybit); ++ __set_bit(KEY_GESTURE_W, input_dev->keybit); ++ __set_bit(KEY_GESTURE_L, input_dev->keybit); ++ __set_bit(KEY_GESTURE_S, input_dev->keybit); ++ __set_bit(KEY_GESTURE_V, input_dev->keybit); ++ __set_bit(KEY_GESTURE_C, input_dev->keybit); ++ __set_bit(KEY_GESTURE_Z, input_dev->keybit); ++ ++ fts_create_gesture_sysfs(ts_data->dev); ++ ++ memset(&fts_gesture_data, 0, sizeof(struct fts_gesture_st)); ++ ts_data->gesture_mode = FTS_GESTURE_EN; ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++int fts_gesture_exit(struct fts_ts_data *ts_data) ++{ ++ FTS_FUNC_ENTER(); ++ sysfs_remove_group(&ts_data->dev->kobj, &fts_gesture_group); ++ FTS_FUNC_EXIT(); ++ return 0; ++} +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c +new file mode 100644 +index 000000000..ef129824a +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c +@@ -0,0 +1,193 @@ ++/* ++ * ++ * FocalTech TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. ++ * ++ */ ++ ++/************************************************************************ ++* ++* File Name: focaltech_i2c.c ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-04 ++* ++* Abstract: i2c communication with TP ++* ++* Version: v1.0 ++* ++* Revision History: ++* ++************************************************************************/ ++ ++/***************************************************************************** ++* Included header files ++*****************************************************************************/ ++#include "focaltech_core.h" ++ ++/***************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++#define I2C_RETRY_NUMBER 1 ++#define I2C_BUF_LENGTH 256 ++ ++/***************************************************************************** ++* Private enumerations, structures and unions using typedef ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Static variables ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Static function prototypes ++*****************************************************************************/ ++ ++/***************************************************************************** ++* functions body ++*****************************************************************************/ ++int fts_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen) ++{ ++ int ret = 0; ++ int i = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ struct i2c_msg msg_list[2]; ++ struct i2c_msg *msg = NULL; ++ int msg_num = 0; ++ ++ /* must have data when read */ ++ if (!ts_data || !ts_data->client || !data || !datalen ++ || (datalen >= I2C_BUF_LENGTH) || (cmdlen >= I2C_BUF_LENGTH)) { ++ FTS_ERROR("fts_data/client/cmdlen(%d)/data/datalen(%d) is invalid", ++ cmdlen, datalen); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&ts_data->bus_lock); ++ memset(&msg_list[0], 0, sizeof(struct i2c_msg)); ++ memset(&msg_list[1], 0, sizeof(struct i2c_msg)); ++ memcpy(ts_data->bus_tx_buf, cmd, cmdlen); ++ msg_list[0].addr = ts_data->client->addr; ++ msg_list[0].flags = 0; ++ msg_list[0].len = cmdlen; ++ msg_list[0].buf = ts_data->bus_tx_buf; ++ msg_list[1].addr = ts_data->client->addr; ++ msg_list[1].flags = I2C_M_RD; ++ msg_list[1].len = datalen; ++ msg_list[1].buf = ts_data->bus_rx_buf; ++ if (cmd && cmdlen) { ++ msg = &msg_list[0]; ++ msg_num = 2; ++ } else { ++ msg = &msg_list[1]; ++ msg_num = 1; ++ } ++ ++ for (i = 0; i < I2C_RETRY_NUMBER; i++) { ++ ret = i2c_transfer(ts_data->client->adapter, msg, msg_num); ++ if (ret < 0) { ++ FTS_ERROR("i2c_transfer(read) fail,ret:%d", ret); ++ } else { ++ memcpy(data, ts_data->bus_rx_buf, datalen); ++ break; ++ } ++ } ++ ++ mutex_unlock(&ts_data->bus_lock); ++ return ret; ++} ++ ++int fts_write(u8 *writebuf, u32 writelen) ++{ ++ int ret = 0; ++ int i = 0; ++ struct fts_ts_data *ts_data = fts_data; ++ struct i2c_msg msgs; ++ ++ if (!ts_data || !ts_data->client || !writebuf || !writelen ++ || (writelen >= I2C_BUF_LENGTH)) { ++ FTS_ERROR("fts_data/client/data/datalen(%d) is invalid", writelen); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&ts_data->bus_lock); ++ memset(&msgs, 0, sizeof(struct i2c_msg)); ++ memcpy(ts_data->bus_tx_buf, writebuf, writelen); ++ msgs.addr = ts_data->client->addr; ++ msgs.flags = 0; ++ msgs.len = writelen; ++ msgs.buf = ts_data->bus_tx_buf; ++ for (i = 0; i < I2C_RETRY_NUMBER; i++) { ++ ret = i2c_transfer(ts_data->client->adapter, &msgs, 1); ++ if (ret < 0) { ++ FTS_ERROR("i2c_transfer(write) fail,ret:%d", ret); ++ } else { ++ break; ++ } ++ } ++ mutex_unlock(&ts_data->bus_lock); ++ return ret; ++} ++ ++int fts_read_reg(u8 addr, u8 *value) ++{ ++ return fts_read(&addr, 1, value, 1); ++} ++ ++int fts_write_reg(u8 addr, u8 value) ++{ ++ u8 buf[2] = { 0 }; ++ ++ buf[0] = addr; ++ buf[1] = value; ++ return fts_write(buf, sizeof(buf)); ++} ++ ++int fts_bus_init(struct fts_ts_data *ts_data) ++{ ++ FTS_FUNC_ENTER(); ++ ts_data->bus_tx_buf = kzalloc(I2C_BUF_LENGTH, GFP_KERNEL); ++ if (NULL == ts_data->bus_tx_buf) { ++ FTS_ERROR("failed to allocate memory for bus_tx_buf"); ++ return -ENOMEM; ++ } ++ ++ ts_data->bus_rx_buf = kzalloc(I2C_BUF_LENGTH, GFP_KERNEL); ++ if (NULL == ts_data->bus_rx_buf) { ++ FTS_ERROR("failed to allocate memory for bus_rx_buf"); ++ return -ENOMEM; ++ } ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++int fts_bus_exit(struct fts_ts_data *ts_data) ++{ ++ FTS_FUNC_ENTER(); ++ if (ts_data && ts_data->bus_tx_buf) { ++ kfree(ts_data->bus_tx_buf); ++ ts_data->bus_tx_buf = NULL; ++ } ++ ++ if (ts_data && ts_data->bus_rx_buf) { ++ kfree(ts_data->bus_rx_buf); ++ ts_data->bus_rx_buf = NULL; ++ } ++ FTS_FUNC_EXIT(); ++ return 0; ++} +diff --git a/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c +new file mode 100644 +index 000000000..1296af155 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c +@@ -0,0 +1,135 @@ ++/* ++ * ++ * FocalTech TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. ++ * ++ */ ++ ++/***************************************************************************** ++* ++* File Name: focaltech_point_report_check.c ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-11-16 ++* ++* Abstract: point report check function ++* ++* Version: v1.0 ++* ++* Revision History: ++* ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Included header files ++*****************************************************************************/ ++#include "focaltech_core.h" ++ ++#if FTS_POINT_REPORT_CHECK_EN ++/***************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++#define POINT_REPORT_CHECK_WAIT_TIME 200 /* unit:ms */ ++ ++/***************************************************************************** ++* functions body ++*****************************************************************************/ ++/***************************************************************************** ++* Name: fts_prc_func ++* Brief: fts point report check work func, report whole up of points ++* Input: ++* Output: ++* Return: ++*****************************************************************************/ ++static void fts_prc_func(struct work_struct *work) ++{ ++ struct fts_ts_data *ts_data = container_of(work, ++ struct fts_ts_data, prc_work.work); ++ struct input_dev *input_dev = ts_data->input_dev; ++#if FTS_MT_PROTOCOL_B_EN ++ u32 finger_count = 0; ++ u32 max_touches = fts_data->pdata->max_touch_number; ++#endif ++ ++ FTS_FUNC_ENTER(); ++ mutex_lock(&ts_data->report_mutex); ++ ++#if FTS_MT_PROTOCOL_B_EN ++ for (finger_count = 0; finger_count < max_touches; finger_count++) { ++ input_mt_slot(input_dev, finger_count); ++ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false); ++ } ++#else ++ input_mt_sync(input_dev); ++#endif ++ input_report_key(input_dev, BTN_TOUCH, 0); ++ input_sync(input_dev); ++ ++ mutex_unlock(&ts_data->report_mutex); ++ ++ FTS_FUNC_EXIT(); ++} ++ ++/***************************************************************************** ++* Name: fts_prc_queue_work ++* Brief: fts point report check queue work, call it when interrupt comes ++* Input: ++* Output: ++* Return: ++*****************************************************************************/ ++void fts_prc_queue_work(struct fts_ts_data *ts_data) ++{ ++ cancel_delayed_work_sync(&ts_data->prc_work); ++ queue_delayed_work(ts_data->ts_workqueue, &ts_data->prc_work, ++ msecs_to_jiffies(POINT_REPORT_CHECK_WAIT_TIME)); ++} ++ ++/***************************************************************************** ++* Name: fts_point_report_check_init ++* Brief: ++* Input: ++* Output: ++* Return: < 0: Fail to create esd check queue ++*****************************************************************************/ ++int fts_point_report_check_init(struct fts_ts_data *ts_data) ++{ ++ FTS_FUNC_ENTER(); ++ ++ if (ts_data->ts_workqueue) { ++ INIT_DELAYED_WORK(&ts_data->prc_work, fts_prc_func); ++ } else { ++ FTS_ERROR("fts workqueue is NULL, can't run point report check function"); ++ return -EINVAL; ++ } ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++ ++/***************************************************************************** ++* Name: fts_point_report_check_exit ++* Brief: ++* Input: ++* Output: ++* Return: ++*****************************************************************************/ ++int fts_point_report_check_exit(struct fts_ts_data *ts_data) ++{ ++ FTS_FUNC_ENTER(); ++ ++ FTS_FUNC_EXIT(); ++ return 0; ++} ++#endif /* FTS_POINT_REPORT_CHECK_EN */ ++ +diff --git a/module_drivers/drivers/input/touchscreen/ft6236_touch/Kconfig b/module_drivers/drivers/input/touchscreen/ft6236_touch/Kconfig +new file mode 100644 +index 000000000..80ce09e7f +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/ft6236_touch/Kconfig +@@ -0,0 +1,10 @@ ++# ++# Focaltech Touchscreen driver configuration ++# ++ ++config TOUCHSCREEN_FT6236 ++ bool "FT6236 Touchscreen" ++ default n ++ help ++ Say Y here if you have Focaltech touch panel. ++ If unsure, say N. +diff --git a/module_drivers/drivers/input/touchscreen/ft6236_touch/Makefile b/module_drivers/drivers/input/touchscreen/ft6236_touch/Makefile +new file mode 100644 +index 000000000..2bb05d5fd +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/ft6236_touch/Makefile +@@ -0,0 +1,6 @@ ++# Makefile for the focaltech touchscreen drivers. ++#EXTRA_CFLAGS +=-Wno-error=date-time ++# EXTRA_CFLAGS += -Wno-date-time ++obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236_touch.o ++# obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx_update.o ++# obj-$(CONFIG_TOUCHSCREEN_GT9XX) += goodix_tool.o +diff --git a/module_drivers/drivers/input/touchscreen/ft6236_touch/ft6236_touch.c b/module_drivers/drivers/input/touchscreen/ft6236_touch/ft6236_touch.c +new file mode 100644 +index 000000000..8960d23fa +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/ft6236_touch/ft6236_touch.c +@@ -0,0 +1,592 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ft6236_touch.h" ++ ++static const struct i2c_device_id ft6236_tpd_id[] = {{TPD_DRIVER_NAME,0},{}}; ++ ++static int ft_parse_dt(struct device *dev, ++ struct ft6236_platform_data *pdata) ++{ ++ int ret; ++ struct device_node *np = dev->of_node; ++ ++ ret = of_property_read_u32(np, "irq-flags", ++ &pdata->irq_flags); ++ if (ret) { ++ dev_info(dev, ++ "Failed get int-trigger-type from dts,set default\n"); ++ } ++ ++ ret = of_property_read_u32(np, "touchscreen-max-x", ++ &pdata->max_x); ++ if (ret) { ++ dev_info(dev, ++ "Failed get max_x from dts,set default\n"); ++ } ++ ++ ret = of_property_read_u32(np, "touchscreen-max-y", ++ &pdata->max_y); ++ if (ret) { ++ dev_info(dev, ++ "Failed get max_y from dts,set default\n"); ++ } ++ ++ ret = of_property_read_u32(np, "touchscreen-invert-x", ++ &pdata->invert_x); ++ if (ret) { ++ dev_info(dev, ++ "Failed get invert_x from dts,set default\n"); ++ } ++ ++ ret = of_property_read_u32(np, "touchscreen-invert-y", ++ &pdata->invert_y); ++ if (ret) { ++ dev_info(dev, ++ "Failed get invert_y from dts,set default\n"); ++ } ++ ++ of_property_read_u32(np, "ft6236,swap-xy", &pdata->swap_xy); ++ if (pdata->swap_xy) ++ dev_info(dev, "swap-xy enabled\n"); ++ ++ pdata->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0); ++ if (!gpio_is_valid(pdata->irq_gpio)) ++ dev_err(dev, "No valid irq gpio"); ++ ++ pdata->rst_gpio = of_get_named_gpio(np, "reset-gpios", 0); ++ if (!gpio_is_valid(pdata->rst_gpio)) ++ dev_err(dev, "No valid rst gpio"); ++ ++ return 0; ++} ++ ++static int ft_power_init(struct ft6236_data *ts) ++{ ++ int ret; ++ ++ ts->vdd_ana = regulator_get(&ts->client->dev, "vdd_ana"); ++ if (IS_ERR(ts->vdd_ana)) { ++ ts->vdd_ana = NULL; ++ ret = PTR_ERR(ts->vdd_ana); ++ dev_info(&ts->client->dev, ++ "Regulator get failed vdd ret=%d\n", ret); ++ } ++ ++ ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc_i2c"); ++ if (IS_ERR(ts->vcc_i2c)) { ++ ts->vcc_i2c = NULL; ++ ret = PTR_ERR(ts->vcc_i2c); ++ dev_info(&ts->client->dev, ++ "Regulator get failed vcc_i2c ret=%d\n", ret); ++ } ++ return 0; ++} ++ ++static int ft_power_deinit(struct ft6236_data *ts) ++{ ++ if (ts->vdd_ana) ++ regulator_put(ts->vdd_ana); ++ if (ts->vcc_i2c) ++ regulator_put(ts->vcc_i2c); ++ ++ return 0; ++} ++ ++static int ft_power_on(struct ft6236_data *ts) ++{ ++ int ret = 0; ++ ++ if (ts->vdd_ana) { ++ ret = regulator_enable(ts->vdd_ana); ++ if (ret) { ++ dev_err(&ts->client->dev, ++ "Regulator vdd enable failed ret=%d\n", ++ ret); ++ goto err_enable_vdd_ana; ++ } ++ } ++ ++ if (ts->vcc_i2c) { ++ ret = regulator_enable(ts->vcc_i2c); ++ if (ret) { ++ dev_err(&ts->client->dev, ++ "Regulator vcc_i2c enable failed ret=%d\n", ++ ret); ++ goto err_enable_vcc_i2c; ++ } ++ } ++ clear_bit(6, &ts->flags); ++ return 0; ++ ++err_enable_vcc_i2c: ++ if (ts->vdd_ana) ++ regulator_disable(ts->vdd_ana); ++err_enable_vdd_ana: ++ set_bit(6, &ts->flags); ++ return ret; ++} ++ ++static int ft6236_chip_power(struct ft6236_data *ft6236) ++{ ++ int ret = 0; ++ ++ if (NULL != ft6236->vdd_ana){ ++ ret = regulator_enable(ft6236->vdd_ana); ++ if(ret){ ++ dev_err(&ft6236->client->dev, ++ "Regulator vdd enable failed ret=%d\n", ++ ret); ++ goto err_enable_vdd_ana; ++ } ++ } ++ if (NULL != ft6236->vcc_i2c) { ++ ret = regulator_enable(ft6236->vcc_i2c); ++ if (ret) { ++ dev_err(&ft6236->client->dev, ++ "Regulator vcc_i2c enable failed ret=%d\n", ++ ret); ++ goto err_enable_vcc_i2c; ++ } ++ } ++ ++ return 0; ++ ++err_enable_vcc_i2c: ++ if (ft6236->vdd_ana) ++ regulator_disable(ft6236->vdd_ana); ++err_enable_vdd_ana: ++/* set_bit(POWER_OFF_MODE, &ft6236->flags);*/ ++ return ret; ++} ++ ++static void ft6236_chip_reset(struct ft6236_data *ft6236) ++{ ++ if (ft6236->pdata->rst_gpio) { ++ gpio_direction_output(ft6236->pdata->rst_gpio, 0); ++ msleep(50); ++ gpio_direction_output(ft6236->pdata->rst_gpio, 1); ++ msleep(300); ++ } ++} ++ ++ ++static int ft6236_read(struct i2c_client *client, u8 address, u8 len, u8 *buf) ++{ ++ unsigned int transfer_length = 0; ++ unsigned int pos = 0; ++ unsigned char get_buf[64], addr_buf[2]; ++ int retry, r = 2; ++ struct i2c_msg msgs[] = { ++ { ++ .addr = client->addr, ++ .flags = !I2C_M_RD, ++ .buf = &addr_buf[0], ++ .len = 1, ++ }, { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ } ++ }; ++ ++ if (likely(len < sizeof(get_buf))) { ++ /* code optimize, use stack memory */ ++ msgs[1].buf = &get_buf[0]; ++ } else { ++ msgs[1].buf = kzalloc(len > I2C_MAX_TRANSFER_SIZE ++ ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL); ++ if (!msgs[1].buf) ++ return -ENOMEM; ++ } ++ ++ while (pos != len) { ++ if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE)) ++ transfer_length = I2C_MAX_TRANSFER_SIZE; ++ else ++ transfer_length = len - pos; ++ msgs[0].buf[0] = address; ++ msgs[1].len = transfer_length; ++ for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { ++ if (likely(i2c_transfer(client->adapter, msgs, 2) == 2)) { ++ memcpy(&buf[pos], msgs[1].buf, transfer_length); ++ pos += transfer_length; ++ address += transfer_length; ++ break; ++ } ++ dev_dbg(&client->dev, "I2c read retry[%d]:0x%x\n", ++ retry + 1, address); ++ usleep_range(2000, 2100); ++ } ++ if (unlikely(retry == RETRY_MAX_TIMES)) { ++ dev_err(&client->dev, ++ "I2c read failed,dev:%02x,reg:%04x,size:%u\n", ++ client->addr, address, len); ++ r = -EAGAIN; ++ goto read_exit; ++ } ++ } ++read_exit: ++ if (len >= sizeof(get_buf)) ++ kfree(msgs[1].buf); ++ ++ return r; ++} ++ ++static int ft6236_i2c_test(struct i2c_client *client) ++{ ++ u8 test; ++ ++ ft6236_read(client, 0xa8, 1, &test); ++ if (0x11 == test) ++ return 0; ++ ++ return -EAGAIN; ++} ++static int ft_request_io_port(struct ft6236_data *ts) ++{ ++ int ret; ++ ++ if (gpio_is_valid(ts->pdata->irq_gpio)) { ++ ret = gpio_request(ts->pdata->irq_gpio, "ft6236_ts_int"); ++ if (ret < 0) { ++ dev_err(&ts->client->dev, ++ "Failed to request GPIO:%d, ERRNO:%d\n", ++ (s32)ts->pdata->irq_gpio, ret); ++ return -ENODEV; ++ } ++ gpio_direction_input(ts->pdata->irq_gpio); ++ dev_info(&ts->client->dev, "Success request irq-gpio\n"); ++ } ++ if (gpio_is_valid(ts->pdata->rst_gpio)) { ++ ret = gpio_request(ts->pdata->rst_gpio, "ft6236_ts_rst"); ++ if (ret < 0) { ++ dev_err(&ts->client->dev, ++ "Failed to request GPIO:%d, ERRNO:%d\n", ++ (s32)ts->pdata->rst_gpio, ret); ++ ++ if (gpio_is_valid(ts->pdata->irq_gpio)) ++ gpio_free(ts->pdata->irq_gpio); ++ ++ return -ENODEV; ++ } ++ ++ gpio_direction_input(ts->pdata->rst_gpio); ++ dev_info(&ts->client->dev, "Success request rst-gpio\n"); ++ } ++ return 0; ++} ++ ++static void ft6236_touch_report(struct ft6236_data *ft6236) ++{ ++ u8 touches; ++ int i, error; ++ struct ft6236_packet buf; ++ ++ struct input_dev *input = ft6236->input; ++ ++ error = ft6236_read(ft6236->client, 0, sizeof(buf), (u8 *)&buf); ++ if (error < 0) { ++ printk(KERN_ERR "ft6236_touch: read touchdata failed %d\n", error); ++ return; ++ } ++ ++ touches = buf.touches & 0xf; ++ ++ for (i = 0; i < touches; i++) { ++ struct ft6236_touchpoint *point = &buf.points[i]; ++ u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo; ++ u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo; ++ u8 id = point->id >> 4; ++ ++ if (ft6236->pdata->invert_x) ++ x = ft6236->pdata->max_x - x; ++ ++ if (ft6236->pdata->invert_y) ++ y = ft6236->pdata->max_y - y; ++ ++ input_report_key(input, BTN_TOUCH, 1); ++ input_report_abs(input, ABS_MT_TOOL_TYPE, 1); ++ input_report_abs(input, ABS_MT_TRACKING_ID, id); ++ input_report_abs(input, ABS_MT_PRESSURE, 20); ++ input_report_abs(input, ABS_MT_TOUCH_MAJOR, 20); ++ input_report_abs(input, ABS_MT_WIDTH_MAJOR, 20); ++ ++ input_report_key(input, BTN_TOOL_FINGER, true); ++ ++ if (ft6236->pdata->swap_xy) { ++ input_report_abs(input, ABS_MT_POSITION_X, y); ++ input_report_abs(input, ABS_MT_POSITION_Y, x); ++ } else { ++ input_report_abs(input, ABS_MT_POSITION_X, x); ++ input_report_abs(input, ABS_MT_POSITION_Y, y); ++ } ++ ++ input_mt_sync(input); ++ } ++ ++ if (touches == 0) { ++ input_report_key(input, BTN_TOUCH, 0); ++ input_mt_sync(input); ++ } ++ ++ input_sync(input); ++} ++ ++static irqreturn_t ft6236_ts_irq_handler(int irq, void *dev_id) ++{ ++ struct ft6236_data *ft6236 = dev_id; ++ ++ ft6236_touch_report(ft6236); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ft_request_irq(struct ft6236_data *ts) ++{ ++ int ret = -1; ++ ++ if (gpio_is_valid(ts->pdata->irq_gpio)) ++ ts->client->irq = gpio_to_irq(ts->pdata->irq_gpio); ++ ++ dev_info(&ts->client->dev, "INT num %d, trigger type:%d\n", ++ ts->client->irq, ts->pdata->irq_flags); ++ ret = request_threaded_irq(ts->client->irq, NULL, ++ ft6236_ts_irq_handler, ++ ts->pdata->irq_flags | IRQF_ONESHOT, ++ ts->client->name, ++ ts); ++ if (ret < 0) { ++ dev_err(&ts->client->dev, ++ "Failed to request irq %d\n", ts->client->irq); ++ return ret; ++ } ++ return ret; ++} ++ ++static int ft6236_tpd_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ int ret; ++ struct input_dev *input; ++ struct device *dev = &client->dev; ++ struct ft6236_platform_data *pdata; ++ struct ft6236_data *ft6236; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ dev_err(&client->dev, "Failed check I2C functionality"); ++ return -ENODEV; ++ } ++ ++ ft6236 = devm_kzalloc(&client->dev, sizeof(*ft6236), GFP_KERNEL); ++ if (ft6236 == NULL) { ++ printk(KERN_ERR "ft6236_touch: alloc ft6236 memory failed."); ++ return -ENOMEM; ++ } ++ ++ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); ++ if (ft6236 == NULL) { ++ printk(KERN_ERR "ft6236_touch: alloc ft6236_platform_data memory failed."); ++ devm_kfree(&client->dev, ft6236); ++ return -EINVAL; ++ } ++ ++ ret = ft_parse_dt(&client->dev, pdata); ++ if (ret) { ++ dev_err(&client->dev, "Failed parse dts\n"); ++ goto exit_free_client_data; ++ } ++ ++ ft6236->client = client; ++ ft6236->pdata = pdata; ++ ++ ret = ft_request_io_port(ft6236); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed request IO port\n"); ++ goto free_gpio; ++ } ++ ++ ret = ft_power_init(ft6236); ++ if (ret) { ++ dev_err(&client->dev, "Failed get regulator\n"); ++ ret = -EINVAL; ++ goto free_gpio; ++ } ++ ++ i2c_set_clientdata(client, ft6236); ++ ft6236_chip_power(ft6236); ++ ft6236_chip_reset(ft6236); ++ ++ input = devm_input_allocate_device(dev); ++ if (input == NULL) { ++ ret = -ENOMEM; ++ goto exit_deinit_power; ++ } ++ ++ ft6236->input = input; ++ input->name = TPD_DRIVER_NAME; ++ input->phys = TPD_DRIVER_PHY; ++ input->id.bustype = BUS_I2C; ++ ++ __set_bit(EV_SYN, input->evbit); ++ __set_bit(EV_KEY, input->evbit); ++ __set_bit(EV_ABS, input->evbit); ++ __set_bit(BTN_TOUCH, input->keybit); ++ __set_bit(INPUT_PROP_DIRECT, input->propbit); ++ ++ if (ft6236->pdata->swap_xy) { ++ input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->max_y, 0, 0); ++ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->max_x, 0, 0); ++ } else { ++ input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->max_x, 0, 0); ++ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->max_y, 0, 0); ++ } ++ ++ input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); ++ input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); ++ input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 255, 0, 0); ++ ++ input_set_abs_params(input, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); ++ input_set_abs_params(input, ABS_MT_PRESSURE, 0, 479, 0, 0); ++ ++ ret = ft_request_irq(ft6236); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed create work thread"); ++ goto free_input; ++ } ++ ++ ret = input_register_device(input); ++ if (ret) { ++ printk(KERN_ERR "ft6236_touch: failed to register input device: %d\n", ret); ++ goto free_irq; ++ } ++ ++ spin_lock_init(&ft6236->irq_lock); ++ ++ ret = ft6236_i2c_test(client); ++ if (ret) { ++ dev_err(&client->dev, "Failed communicate with IC use I2C\n"); ++ goto free_input_dev; ++ } ++ ++ return 0; ++ ++free_input_dev: ++ input_unregister_device(ft6236->input); ++free_irq: ++ free_irq(ft6236->client->irq, ft6236); ++free_input: ++ input_free_device(ft6236->input); ++exit_deinit_power: ++ ft_power_deinit(ft6236); ++free_gpio: ++ if (gpio_is_valid(ft6236->pdata->rst_gpio)) ++ gpio_free(ft6236->pdata->rst_gpio); ++ if (gpio_is_valid(ft6236->pdata->irq_gpio)) ++ gpio_free(ft6236->pdata->irq_gpio); ++exit_free_client_data: ++ devm_kfree(&client->dev, pdata); ++ devm_kfree(&client->dev, ft6236); ++ i2c_set_clientdata(client, NULL); ++ ++ return ret; ++} ++ ++static int ft6236_tpd_remove(struct i2c_client *client) ++{ ++ struct ft6236_data *ft6236 = i2c_get_clientdata(client); ++ ++ free_irq(ft6236->client->irq, ft6236); ++ ++ if (gpio_is_valid(ft6236->pdata->rst_gpio)) ++ gpio_free(ft6236->pdata->rst_gpio); ++ if (gpio_is_valid(ft6236->pdata->irq_gpio)) ++ gpio_free(ft6236->pdata->irq_gpio); ++ ++ input_unregister_device(ft6236->input); ++ input_free_device(ft6236->input); ++ kfree(ft6236); ++ ++ return 0; ++} ++ ++static int ft6236_tpd_suspend(struct device *device) ++{ ++ struct i2c_client *client = to_i2c_client(device); ++ struct ft6236_data *ft6236 = i2c_get_clientdata(client); ++ unsigned long irqflags; ++ ++ spin_lock_irqsave(&ft6236->irq_lock, irqflags); ++ disable_irq(client->irq); ++ spin_unlock_irqrestore(&ft6236->irq_lock, irqflags); ++ return 0; ++} ++ ++static int ft6236_tpd_resume(struct device *device) ++{ ++ struct i2c_client *client = to_i2c_client(device); ++ struct ft6236_data *ft6236 = i2c_get_clientdata(client); ++ unsigned long irqflags; ++ ++ spin_lock_irqsave(&ft6236->irq_lock, irqflags); ++ enable_irq(client->irq); ++ spin_unlock_irqrestore(&ft6236->irq_lock, irqflags); ++ return 0; ++} ++ ++static const struct dev_pm_ops ft6236_pm_ops = { ++ .suspend = ft6236_tpd_suspend, ++ .resume = ft6236_tpd_resume, ++}; ++ ++static const struct of_device_id ft_match_table[] = { ++ {.compatible = "goodix,ft6236",}, ++ { }, ++}; ++ ++static struct i2c_driver ft6236_ts_driver = { ++ .driver = { ++ .name = TPD_DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = ft_match_table, ++ .pm = &ft6236_pm_ops, ++ }, ++ ++ .probe = ft6236_tpd_probe, ++ .remove = ft6236_tpd_remove, ++ .id_table = ft6236_tpd_id, ++}; ++ ++static int __init ft6236_touch_init(void) ++{ ++ int ret = i2c_add_driver(&ft6236_ts_driver); ++ if (ret) { ++ printk(KERN_ERR "ft6236_touch: failed to register i2c driver\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void __exit ft6236_touch_exit(void) ++{ ++ i2c_del_driver(&ft6236_ts_driver); ++} ++ ++module_init(ft6236_touch_init); ++module_exit(ft6236_touch_exit); ++ ++MODULE_DESCRIPTION("Ft6236 Series Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/input/touchscreen/ft6236_touch/ft6236_touch.h b/module_drivers/drivers/input/touchscreen/ft6236_touch/ft6236_touch.h +new file mode 100644 +index 000000000..fd090df00 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/ft6236_touch/ft6236_touch.h +@@ -0,0 +1,52 @@ ++#ifndef __TOUCH_FT6236_H_ ++#define __TOUCH_FT6236_H_ ++ ++#define I2C_ADDR 0x38 ++#define I2C_MAX_TRANSFER_SIZE 255 ++#define RETRY_MAX_TIMES 5 ++#define TPD_DRIVER_NAME "ft6236-ts" ++#define TPD_DRIVER_PHY "input/ts" ++ ++struct ft6236_platform_data { ++ int irq_gpio; ++ int rst_gpio; ++ u32 irq_flags; ++ u32 max_x; ++ u32 max_y; ++ u32 invert_x; ++ u32 invert_y; ++ u32 swap_xy; ++}; ++ ++struct ft6236_data { ++ unsigned long flags; /* This member record the device status */ ++ struct i2c_client *client; ++ struct input_dev *input; ++ struct ft6236_platform_data *pdata; ++ struct mutex lock; ++ struct regulator *vdd_ana; ++ struct regulator *vcc_i2c; ++ spinlock_t irq_lock; ++}; ++ ++struct ft6236_touchpoint { ++ union { ++ u8 xhi; ++ u8 event; ++ }; ++ u8 xlo; ++ union { ++ u8 yhi; ++ u8 id; ++ }; ++ u8 ylo; ++}; ++ ++struct ft6236_packet { ++ u8 dev_mode; ++ u8 gest_id; ++ u8 touches; ++ struct ft6236_touchpoint points[2]; ++}; ++ ++#endif //__TOUCH_FT6236_h_ +diff --git a/module_drivers/drivers/input/touchscreen/gt9xx_touch/Kconfig b/module_drivers/drivers/input/touchscreen/gt9xx_touch/Kconfig +new file mode 100644 +index 000000000..f857fea85 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/gt9xx_touch/Kconfig +@@ -0,0 +1,16 @@ ++# ++# Focaltech Touchscreen driver configuration ++# ++ ++config TOUCHSCREEN_GT9XX ++ bool "GT9XX Touchscreen" ++ default n ++ help ++ Say Y here if you have Focaltech touch panel. ++ If unsure, say N. ++ ++config TOUCHSCREEN_GT9XX_DIRECTORY ++ string "gt ts directory name" ++ default "gt9xx_touch" ++ depends on TOUCHSCREEN_GT9XX ++ +diff --git a/module_drivers/drivers/input/touchscreen/gt9xx_touch/Makefile b/module_drivers/drivers/input/touchscreen/gt9xx_touch/Makefile +new file mode 100644 +index 000000000..2da8bc005 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/gt9xx_touch/Makefile +@@ -0,0 +1,6 @@ ++# Makefile for the focaltech touchscreen drivers. ++#EXTRA_CFLAGS +=-Wno-error=date-time ++EXTRA_CFLAGS += -Wno-date-time ++obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx.o ++obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx_update.o ++obj-$(CONFIG_TOUCHSCREEN_GT9XX) += goodix_tool.o +diff --git a/module_drivers/drivers/input/touchscreen/gt9xx_touch/goodix.h b/module_drivers/drivers/input/touchscreen/gt9xx_touch/goodix.h +new file mode 100644 +index 000000000..b7c6f2e6e +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/gt9xx_touch/goodix.h +@@ -0,0 +1,69 @@ ++#ifndef TOUCHSCREEN_GT9XX__H ++#define TOUCHSCREEN_GT9XX__H ++ ++/***************************************************************************** ++* Included header files ++*****************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/***************************************************************************** ++* Debug interface. ++*****************************************************************************/ ++ ++#if GT9_DEBUG_EN ++ ++#define GT9_DEBUG(fmt, args...) do { \ ++ printk("[GT9_TS]%s:"fmt"\n", __func__, ##args); \ ++} while (0) ++ ++#define GT9_FUNC_ENTER() do { \ ++ printk("[GT9_TS]%s: Enter(%d)\n", __func__,__LINE__); \ ++} while (0) ++ ++#define GT9_FUNC_EXIT() do { \ ++ printk("[GT9_TS]%s: Exit(%d)\n", __func__, __LINE__); \ ++} while (0) ++#else /* #if GT9_DEBUG_EN*/ ++#define GT9_DEBUG(fmt, args...) ++#define GT9_FUNC_ENTER() ++#define GT9_FUNC_EXIT() ++#endif ++ ++#define GT9_INFO(fmt, args...) do { \ ++ printk(KERN_INFO "[GT9_TS/I]%s:"fmt"\n", __func__, ##args); \ ++} while (0) ++ ++#define GT9_ERROR(fmt, args...) do { \ ++ printk(KERN_ERR "[GT9_TS/E]%s:"fmt"\n", __func__, ##args); \ ++} while (0) ++ ++#endif /* TOUCHSCREEN_CST3XX__H */ ++ ++ +diff --git a/module_drivers/drivers/input/touchscreen/gt9xx_touch/goodix_tool.c b/module_drivers/drivers/input/touchscreen/gt9xx_touch/goodix_tool.c +new file mode 100644 +index 000000000..a1828f972 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/gt9xx_touch/goodix_tool.c +@@ -0,0 +1,529 @@ ++/* ++ * Goodix GT9xx touchscreen driver ++ * ++ * Copyright (C) 2016 - 2017 Goodix. Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be a reference ++ * to you, when you are integrating the GOODiX's CTP IC into your system, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * Version: 2.8.0.1 ++ * Release Date: 2017/11/24 ++ */ ++ ++#include "gt9xx.h" ++ ++#define DATA_LENGTH_UINT 512 ++#define CMD_HEAD_LENGTH (sizeof(struct st_cmd_head) - sizeof(u8 *)) ++static char procname[20] = {0}; ++ ++#pragma pack(1) ++struct st_cmd_head { ++ u8 wr; /*write read flag 0:R 1:W 2:PID 3:*/ ++ u8 flag; /*0:no need flag/int 1: need flag 2:need int*/ ++ u8 flag_addr[2]; /*flag address*/ ++ u8 flag_val; /*flag val*/ ++ u8 flag_relation; /*flag_val:flag 0:not equal 1:equal 2:> 3:<*/ ++ u16 circle; /*polling cycle*/ ++ u8 times; /*plling times*/ ++ u8 retry; /*I2C retry times*/ ++ u16 delay; /*delay before read or after write*/ ++ u16 data_len; /*data length*/ ++ u8 addr_len; /*address length*/ ++ u8 addr[2]; /*address*/ ++ u8 res[3]; /*reserved*/ ++ u8 *data; }; /*data pointer*/ ++#pragma pack() ++struct st_cmd_head cmd_head; ++ ++static struct i2c_client *gt_client; ++static struct proc_dir_entry *goodix_proc_entry; ++ ++static ssize_t goodix_tool_read(struct file *, char __user *, size_t, loff_t *); ++static ssize_t goodix_tool_write(struct file *, const char __user *, size_t, loff_t *); ++static const struct proc_ops gtp_proc_ops = { ++ .proc_read = goodix_tool_read, ++ .proc_write = goodix_tool_write, ++}; ++ ++/* static s32 goodix_tool_write(struct file *filp, ++ * const char __user *buff, unsigned long len, void *data); ++ */ ++/*static s32 goodix_tool_read( char *page, char ++ **start, off_t off, int count, int *eof, void *data ); ++ */ ++static s32 (*tool_i2c_read)(u8 *, u16); ++static s32 (*tool_i2c_write)(u8 *, u16); ++ ++static s32 DATA_LENGTH = (s32)0; ++static s8 IC_TYPE[16] = "GT9XX"; ++ ++static void tool_set_proc_name(char *procname) ++{ ++ snprintf(procname, 20, "gmnode"); /* modify for moto */ ++} ++ ++static s32 tool_i2c_read_no_extra(u8 *buf, u16 len) ++{ ++ s32 ret = -1; ++ s32 i = 0; ++ struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); ++ ++ for (i = 0; i < cmd_head.retry; i++) { ++ ret = gtp_i2c_read(ts->client, buf, len + GTP_ADDR_LENGTH); ++ if (ret > 0) ++ break; ++ } ++ return ret; ++} ++ ++static s32 tool_i2c_write_no_extra(u8 *buf, u16 len) ++{ ++ s32 ret = -1; ++ s32 i = 0; ++ struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); ++ ++ for (i = 0; i < cmd_head.retry; i++) { ++ ret = gtp_i2c_write(ts->client, buf, len); ++ if (ret > 0) ++ break; ++ } ++ ++ return ret; ++} ++ ++static s32 tool_i2c_read_with_extra(u8 *buf, u16 len) ++{ ++ s32 ret = -1; ++ u8 pre[2] = {0x0f, 0xff}; ++ u8 end[2] = {0x80, 0x00}; ++ ++ tool_i2c_write_no_extra(pre, 2); ++ ret = tool_i2c_read_no_extra(buf, len); ++ tool_i2c_write_no_extra(end, 2); ++ ++ return ret; ++} ++ ++static s32 tool_i2c_write_with_extra(u8 *buf, u16 len) ++{ ++ s32 ret = -1; ++ u8 pre[2] = {0x0f, 0xff}; ++ u8 end[2] = {0x80, 0x00}; ++ ++ tool_i2c_write_no_extra(pre, 2); ++ ret = tool_i2c_write_no_extra(buf, len); ++ tool_i2c_write_no_extra(end, 2); ++ ++ return ret; ++} ++ ++static void register_i2c_func(void) ++{ ++ /* if (!strncmp(IC_TYPE, "GT818", 5) ++ * || !strncmp(IC_TYPE, "GT816", 5) ++ * || !strncmp(IC_TYPE, "GT811", 5) ++ * || !strncmp(IC_TYPE, "GT818F", 6) ++ * || !strncmp(IC_TYPE, "GT827", 5) ++ * || !strncmp(IC_TYPE,"GT828", 5) ++ * || !strncmp(IC_TYPE, "GT813", 5)) ++ */ ++ if (strncmp(IC_TYPE, "GT8110", 6) && ++ strncmp(IC_TYPE, "GT8105", 6) && ++ strncmp(IC_TYPE, "GT801", 5) && ++ strncmp(IC_TYPE, "GT800", 5) && ++ strncmp(IC_TYPE, "GT801PLUS", 9) && ++ strncmp(IC_TYPE, "GT811", 5) && ++ strncmp(IC_TYPE, "GTxxx", 5) && ++ strncmp(IC_TYPE, "GT9XX", 5)) { ++ tool_i2c_read = tool_i2c_read_with_extra; ++ tool_i2c_write = tool_i2c_write_with_extra; ++ dev_dbg(>_client->dev, "I2C function: with pre and end cmd!"); ++ } else { ++ tool_i2c_read = tool_i2c_read_no_extra; ++ tool_i2c_write = tool_i2c_write_no_extra; ++ dev_info(>_client->dev, "I2C function: without pre and end cmd!"); ++ } ++} ++ ++static void unregister_i2c_func(void) ++{ ++ tool_i2c_read = NULL; ++ tool_i2c_write = NULL; ++ dev_info(>_client->dev, "I2C function: unregister i2c transfer function!"); ++} ++ ++s32 init_wr_node(struct i2c_client *client) ++{ ++ s32 i; ++ ++ gt_client = client; ++ memset(&cmd_head, 0, sizeof(cmd_head)); ++ cmd_head.data = NULL; ++ ++ i = 6; ++ while ((!cmd_head.data) && i) { ++ cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL); ++ if (cmd_head.data) ++ break; ++ i--; ++ } ++ if (i) { ++ DATA_LENGTH = i * DATA_LENGTH_UINT - GTP_ADDR_LENGTH; ++ dev_info(>_client->dev, ++ "Alloc memory size:%d.", DATA_LENGTH); ++ } else { ++ dev_err(>_client->dev, "Apply for memory failed."); ++ return FAIL; ++ } ++ ++ cmd_head.addr_len = 2; ++ cmd_head.retry = 5; ++ ++ register_i2c_func(); ++ ++ tool_set_proc_name(procname); ++ goodix_proc_entry = proc_create(procname, 0666, NULL, >p_proc_ops); ++ if (!goodix_proc_entry) { ++ dev_err(>_client->dev, "Couldn't create proc entry!"); ++ return FAIL; ++ } ++ ++ dev_info(>_client->dev, "Create proc entry success!"); ++ return SUCCESS; ++} ++ ++void uninit_wr_node(void) ++{ ++ kfree(cmd_head.data); ++ cmd_head.data = NULL; ++ unregister_i2c_func(); ++ remove_proc_entry(procname, NULL); ++} ++ ++static u8 relation(u8 src, u8 dst, u8 rlt) ++{ ++ u8 ret = 0; ++ ++ switch (rlt) { ++ case 0: ++ ret = (src != dst) ? true : false; ++ break; ++ ++ case 1: ++ ret = (src == dst) ? true : false; ++ dev_dbg(>_client->dev, ++ "equal:src:0x%02x dst:0x%02x ret:%d.", ++ src, dst, (s32)ret); ++ break; ++ ++ case 2: ++ ret = (src > dst) ? true : false; ++ break; ++ ++ case 3: ++ ret = (src < dst) ? true : false; ++ break; ++ ++ case 4: ++ ret = (src & dst) ? true : false; ++ break; ++ ++ case 5: ++ ret = (!(src | dst)) ? true : false; ++ break; ++ ++ default: ++ ret = false; ++ break; ++ } ++ ++ return ret; ++} ++ ++/******************************************************* ++ * Function: ++ * Comfirm function. ++ * Input: ++ * None. ++ * Output: ++ * Return write length. ++ ********************************************************/ ++static u8 comfirm(void) ++{ ++ s32 i = 0; ++ u8 buf[32]; ++ ++ memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len); ++ ++ for (i = 0; i < cmd_head.times; i++) { ++ if (tool_i2c_read(buf, 1) <= 0) { ++ dev_err(>_client->dev, "Read flag data failed!"); ++ return FAIL; ++ } ++ if (true == relation(buf[GTP_ADDR_LENGTH], ++ cmd_head.flag_val, cmd_head.flag_relation)) { ++ dev_dbg(>_client->dev, "value at flag addr:0x%02x.", ++ buf[GTP_ADDR_LENGTH]); ++ dev_dbg(>_client->dev, "flag value:0x%02x.", ++ cmd_head.flag_val); ++ break; ++ } ++ ++ msleep(cmd_head.circle); ++ } ++ ++ if (i >= cmd_head.times) { ++ dev_err(>_client->dev, "Can't get the continue flag!"); ++ return FAIL; ++ } ++ ++ return SUCCESS; ++} ++ ++ssize_t goodix_tool_write(struct file *filp, const char __user *buff, ++ size_t len, loff_t *off) ++{ ++ s32 ret = 0; ++ struct goodix_ts_data *ts = i2c_get_clientdata(gt_client); ++ ++ ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); ++ if (ret) { ++ dev_err(>_client->dev, "copy_from_user failed."); ++ return -EPERM; ++ } ++ ++ dev_dbg(>_client->dev, "[Operation]wr: %02X", cmd_head.wr); ++ dev_dbg(>_client->dev, ++ "[Flag]flag: %02X,addr: %02X%02X,value: %02X,relation: %02X", ++ cmd_head.flag, cmd_head.flag_addr[0], ++ cmd_head.flag_addr[1], cmd_head.flag_val, ++ cmd_head.flag_relation); ++ dev_dbg(>_client->dev, ++ "[Retry]circle: %d,times: %d,retry: %d, delay: %d", ++ (s32)cmd_head.circle, ++ (s32)cmd_head.times, (s32)cmd_head.retry, ++ (s32)cmd_head.delay); ++ ++ if (1 == cmd_head.wr) { ++ if (cmd_head.data_len > DATA_LENGTH) { ++ dev_err(>_client->dev, ++ "Tool write failed data too long"); ++ return -EPERM; ++ } ++ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], ++ &buff[CMD_HEAD_LENGTH], ++ cmd_head.data_len); ++ if (ret) { ++ dev_err(>_client->dev, "copy_from_user failed."); ++ return -EPERM; ++ } ++ memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], ++ cmd_head.addr, cmd_head.addr_len); ++ ++ GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + ++ cmd_head.addr_len); ++ ++ if (1 == cmd_head.flag) { ++ if (FAIL == comfirm()) { ++ dev_err(>_client->dev, ++ "[WRITE]Comfirm fail!"); ++ return -EPERM; ++ } ++ } else if (2 == cmd_head.flag) { ++ /*Need interrupt!*/ ++ } ++ if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - ++ cmd_head.addr_len], cmd_head.data_len + ++ cmd_head.addr_len) <= 0) { ++ dev_err(>_client->dev, "[WRITE]Write data failed!"); ++ return -EPERM; ++ } ++ ++ GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - ++ cmd_head.addr_len], ++ cmd_head.data_len + cmd_head.addr_len); ++ if (cmd_head.delay) ++ msleep(cmd_head.delay); ++ } else if (3 == cmd_head.wr) { ++ if (cmd_head.data_len > DATA_LENGTH) { ++ dev_err(>_client->dev, ++ "Tool write failed data too long"); ++ return -EPERM; ++ } ++ ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], ++ cmd_head.data_len); ++ if (ret) { ++ dev_err(>_client->dev, "copy_from_user failed."); ++ return -EPERM; ++ } ++ memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); ++ ++ register_i2c_func(); ++ } else if (5 == cmd_head.wr) { ++ /*memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);*/ ++ } else if (7 == cmd_head.wr) {/*disable irq!*/ ++ gtp_work_control_enable(i2c_get_clientdata(gt_client), false); ++ ++ if (ts->pdata->esd_protect) ++ gtp_esd_off(ts); ++ } else if (9 == cmd_head.wr) {/*enable irq!*/ ++ gtp_work_control_enable(i2c_get_clientdata(gt_client), true); ++ ++ if (ts->pdata->esd_protect) ++ gtp_esd_on(ts); ++ } else if (17 == cmd_head.wr) { ++ if (cmd_head.data_len > DATA_LENGTH) { ++ dev_err(>_client->dev, ++ "Tool write failed data too long"); ++ return -EPERM; ++ } ++ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], ++ &buff[CMD_HEAD_LENGTH], ++ cmd_head.data_len); ++ if (ret) { ++ dev_dbg(>_client->dev, "copy_from_user failed."); ++ return -EPERM; ++ } ++ if (cmd_head.data[GTP_ADDR_LENGTH]) { ++ dev_info(>_client->dev, "gtp enter rawdiff."); ++ set_bit(RAW_DATA_MODE, &ts->flags); ++ } else { ++ clear_bit(RAW_DATA_MODE, &ts->flags); ++ dev_info(>_client->dev, "gtp leave rawdiff."); ++ } ++ } else if (19 == cmd_head.wr) { ++ /* add new command: reset guitar */ ++ gtp_reset_guitar(gt_client, 20); ++ } ++#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE ++ else if (11 == cmd_head.wr) {/*Enter update mode!*/ ++ if (FAIL == gup_enter_update_mode(gt_client)) ++ return -EPERM; ++ } else if (13 == cmd_head.wr) {/*Leave update mode!*/ ++ gup_leave_update_mode(gt_client); ++ } else if (15 == cmd_head.wr) {/*Update firmware!*/ ++ show_len = 0; ++ total_len = 0; ++ if (cmd_head.data_len > DATA_LENGTH) { ++ dev_err(>_client->dev, ++ "Tool write failed data too long"); ++ return -EPERM; ++ } ++ memset(cmd_head.data, 0, DATA_LENGTH); ++ ret = copy_from_user(cmd_head.data, ++ &buff[CMD_HEAD_LENGTH], ++ cmd_head.data_len); ++ if (ret) { ++ dev_dbg(>_client->dev, "copy_from_user failed."); ++ return -EPERM; ++ } ++ ++ if (FAIL == gup_update_proc((void *)cmd_head.data)) ++ return -EPERM; ++ } ++#endif ++ ++ return len; ++} ++ ++/******************************************************* ++ * Function: ++ * Goodix tool read function. ++ * Input: ++ * standard proc read function param. ++ * Output: ++ * Return read length. ++ ********************************************************/ ++ssize_t goodix_tool_read(struct file *file, char __user *page, ++ size_t size, loff_t *ppos) ++{ ++ s32 ret = 0; ++ ++ if (*ppos) { ++ /* ADB call again ++ * dev_dbg(>_client->dev, "[HEAD]wr: %d", cmd_head.wr); ++ * dev_dbg(>_client->dev, ++ * "[PARAM]size: %d, *ppos: %d", size, (int)*ppos); ++ * dev_dbg(>_client->dev, ++ * "[TOOL_READ]ADB call again, return it."); ++ */ ++ *ppos = 0; ++ return 0; ++ } ++ ++ if (cmd_head.wr % 2) { ++ return -EPERM; ++ } else if (!cmd_head.wr) { ++ u16 len, data_len, loc, addr; ++ ++ if (1 == cmd_head.flag) { ++ if (FAIL == comfirm()) { ++ dev_err(>_client->dev, "[READ]Comfirm fail!"); ++ return -EPERM; ++ } ++ } else if (2 == cmd_head.flag) { ++ /*Need interrupt!*/ ++ } ++ ++ if (cmd_head.delay) ++ msleep(cmd_head.delay); ++ ++ data_len = cmd_head.data_len; ++ addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1]; ++ loc = 0; ++ ++ while (data_len > 0) { ++ len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; ++ cmd_head.data[0] = (addr >> 8) & 0xFF; ++ cmd_head.data[1] = (addr & 0xFF); ++ if (tool_i2c_read(cmd_head.data, len) <= 0) { ++ dev_err(>_client->dev, "[READ]Read data failed!"); ++ return -EPERM; ++ } ++ ret = simple_read_from_buffer(&page[loc], size, ppos, ++ &cmd_head.data[GTP_ADDR_LENGTH], len); ++ if (ret < 0) ++ return ret; ++ loc += len; ++ addr += len; ++ data_len -= len; ++ } ++ return cmd_head.data_len; ++ } else if (2 == cmd_head.wr) { ++ ret = simple_read_from_buffer(page, size, ppos, ++ IC_TYPE, sizeof(IC_TYPE)); ++ return ret; ++ } ++#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE ++ else if (4 == cmd_head.wr) { ++ u8 progress_buf[4]; ++ ++ progress_buf[0] = show_len >> 8; ++ progress_buf[1] = show_len & 0xff; ++ progress_buf[2] = total_len >> 8; ++ progress_buf[3] = total_len & 0xff; ++ ++ ret = simple_read_from_buffer(page, size, ppos, ++ progress_buf, 4); ++ return ret; ++ } ++#endif ++ else if (6 == cmd_head.wr) { ++ /*Read error code!*/ ++ } else if (8 == cmd_head.wr) { /*Read driver version*/ ++ ret = simple_read_from_buffer(page, size, ppos, ++ GTP_DRIVER_VERSION, ++ strlen(GTP_DRIVER_VERSION)); ++ return ret; ++ } ++ ++ return -EPERM; ++} +diff --git a/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx.c b/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx.c +new file mode 100644 +index 000000000..4c2005e93 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx.c +@@ -0,0 +1,2576 @@ ++/* ++ * Goodix GT9xx touchscreen driver ++ * ++ * Copyright (C) 2016 - 2017 Goodix. Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be a reference ++ * to you, when you are integrating the GOODiX's CTP IC into your system, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * Version: 2.8.0.1 ++ * Release Date: 2017/11/24 ++ */ ++ ++#include ++#include ++#include ++#include ++#include "gt9xx.h" ++ ++#define GOODIX_COORDS_ARR_SIZE 4 ++#define PROP_NAME_SIZE 24 ++#define I2C_MAX_TRANSFER_SIZE 255 ++#define GTP_PEN_BUTTON1 BTN_STYLUS ++#define GTP_PEN_BUTTON2 BTN_STYLUS2 ++ ++static const char *goodix_ts_name = "goodix-ts"; ++static const char *goodix_input_phys = "input/ts"; ++struct i2c_client *i2c_connect_client; ++static struct proc_dir_entry *gtp_config_proc; ++ ++enum doze { ++ DOZE_DISABLED = 0, ++ DOZE_ENABLED = 1, ++ DOZE_WAKEUP = 2, ++}; ++ ++static enum doze doze_status = DOZE_DISABLED; ++ ++static int gtp_i2c_test(struct i2c_client *client); ++static int gtp_enter_doze(struct goodix_ts_data *ts); ++ ++static int gtp_unregister_powermanager(struct goodix_ts_data *ts); ++static int gtp_register_powermanager(struct goodix_ts_data *ts); ++ ++static int gtp_esd_init(struct goodix_ts_data *ts); ++static void gtp_esd_check_func(struct work_struct *); ++static int gtp_init_ext_watchdog(struct i2c_client *client); ++ ++/* ++ * return: 2 - ok, < 0 - i2c transfer error ++ */ ++int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len) ++{ ++ unsigned int transfer_length = 0; ++ unsigned int pos = 0, address = (buf[0] << 8) + buf[1]; ++ unsigned char get_buf[64], addr_buf[2]; ++ int retry, r = 2; ++ struct i2c_msg msgs[] = { ++ { ++ .addr = client->addr, ++ .flags = !I2C_M_RD, ++ .buf = &addr_buf[0], ++ .len = GTP_ADDR_LENGTH, ++ }, { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ } ++ }; ++ ++ len -= GTP_ADDR_LENGTH; ++ if (likely(len < sizeof(get_buf))) { ++ /* code optimize, use stack memory */ ++ msgs[1].buf = &get_buf[0]; ++ } else { ++ msgs[1].buf = kzalloc(len > I2C_MAX_TRANSFER_SIZE ++ ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL); ++ if (!msgs[1].buf) ++ return -ENOMEM; ++ } ++ ++ while (pos != len) { ++ if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE)) ++ transfer_length = I2C_MAX_TRANSFER_SIZE; ++ else ++ transfer_length = len - pos; ++ msgs[0].buf[0] = (address >> 8) & 0xFF; ++ msgs[0].buf[1] = address & 0xFF; ++ msgs[1].len = transfer_length; ++ for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { ++ if (likely(i2c_transfer(client->adapter, msgs, 2) == 2)) { ++ memcpy(&buf[2 + pos], msgs[1].buf, transfer_length); ++ pos += transfer_length; ++ address += transfer_length; ++ break; ++ } ++ dev_dbg(&client->dev, "I2c read retry[%d]:0x%x\n", ++ retry + 1, address); ++ usleep_range(2000, 2100); ++ } ++ if (unlikely(retry == RETRY_MAX_TIMES)) { ++ dev_err(&client->dev, ++ "I2c read failed,dev:%02x,reg:%04x,size:%u\n", ++ client->addr, address, len); ++ r = -EAGAIN; ++ goto read_exit; ++ } ++ } ++read_exit: ++ if (len >= sizeof(get_buf)) ++ kfree(msgs[1].buf); ++ return r; ++} ++ ++/******************************************************* ++ * Function: ++ * Write data to the i2c slave device. ++ * Input: ++ * client: i2c device. ++ * buf[0~1]: write start address. ++ * buf[2~len-1]: data buffer ++ * len: GTP_ADDR_LENGTH + write bytes count ++ * Output: ++ * numbers of i2c_msgs to transfer: ++ * 1: succeed, otherwise: failed ++ *********************************************************/ ++int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len) ++ ++{ ++ unsigned int pos = 0, transfer_length = 0; ++ unsigned int address = (buf[0] << 8) + buf[1]; ++ unsigned char put_buf[64]; ++ int retry, r = 1; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = !I2C_M_RD, ++ }; ++ ++ if (likely(len < sizeof(put_buf))) { ++ /* code optimize,use stack memory*/ ++ msg.buf = &put_buf[0]; ++ } else { ++ msg.buf = kmalloc(len > I2C_MAX_TRANSFER_SIZE ++ ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL); ++ if (!msg.buf) ++ return -ENOMEM; ++ } ++ ++ len -= GTP_ADDR_LENGTH; ++ while (pos != len) { ++ if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE - GTP_ADDR_LENGTH)) ++ transfer_length = I2C_MAX_TRANSFER_SIZE - GTP_ADDR_LENGTH; ++ else ++ transfer_length = len - pos; ++ msg.buf[0] = (unsigned char)((address >> 8) & 0xFF); ++ msg.buf[1] = (unsigned char)(address & 0xFF); ++ msg.len = transfer_length + 2; ++ memcpy(&msg.buf[2], &buf[2 + pos], transfer_length); ++ for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { ++ if (likely(i2c_transfer(client->adapter, &msg, 1) == 1)) { ++ pos += transfer_length; ++ address += transfer_length; ++ break; ++ } ++ dev_dbg(&client->dev, "I2C write retry[%d]\n", retry + 1); ++ usleep_range(2000, 2100); ++ } ++ if (unlikely(retry == RETRY_MAX_TIMES)) { ++ dev_err(&client->dev, ++ "I2c write failed,dev:%02x,reg:%04x,size:%u\n", ++ client->addr, address, len); ++ r = -EAGAIN; ++ goto write_exit; ++ } ++ } ++write_exit: ++ if (len + GTP_ADDR_LENGTH >= sizeof(put_buf)) ++ kfree(msg.buf); ++ return r; ++} ++ ++/******************************************************* ++ * Function: ++ * i2c read twice, compare the results ++ * Input: ++ * client: i2c device ++ * addr: operate address ++ * rxbuf: read data to store, if compare successful ++ * len: bytes to read ++ * Output: ++ * FAIL: read failed ++ * SUCCESS: read successful ++ *********************************************************/ ++s32 gtp_i2c_read_dbl_check(struct i2c_client *client, ++ u16 addr, u8 *rxbuf, int len) ++{ ++ u8 buf[16] = {0}; ++ u8 confirm_buf[16] = {0}; ++ u8 retry = 0; ++ ++ if (len + 2 > sizeof(buf)) { ++ dev_warn(&client->dev, ++ "%s, only support length less then %zu\n", ++ __func__, sizeof(buf) - 2); ++ return FAIL; ++ } ++ while (retry++ < 3) { ++ memset(buf, 0xAA, 16); ++ buf[0] = (u8)(addr >> 8); ++ buf[1] = (u8)(addr & 0xFF); ++ gtp_i2c_read(client, buf, len + 2); ++ ++ memset(confirm_buf, 0xAB, 16); ++ confirm_buf[0] = (u8)(addr >> 8); ++ confirm_buf[1] = (u8)(addr & 0xFF); ++ gtp_i2c_read(client, confirm_buf, len + 2); ++ ++ if (!memcmp(buf, confirm_buf, len + 2)) { ++ memcpy(rxbuf, confirm_buf + 2, len); ++ return SUCCESS; ++ } ++ } ++ dev_err(&client->dev, ++ "I2C read 0x%04X, %d bytes, double check failed!\n", ++ addr, len); ++ ++ return FAIL; ++} ++ ++/******************************************************* ++ * Function: ++ * Send config. ++ * Input: ++ * client: i2c device. ++ * Output: ++ * result of i2c write operation. ++ * 1: succeed, otherwise ++ * 0: Not executed ++ * < 0: failed ++ *********************************************************/ ++s32 gtp_send_cfg(struct i2c_client *client) ++{ ++ s32 ret, i; ++ u8 check_sum; ++ s32 retry = 0; ++ struct goodix_ts_data *ts = i2c_get_clientdata(client); ++ struct goodix_config_data *cfg = &ts->pdata->config; ++ ++ if (!cfg->length || !ts->pdata->driver_send_cfg) { ++ dev_info(&ts->client->dev, ++ "No config data or error occurred in panel_init\n"); ++ return 0; ++ } ++ ++ check_sum = 0; ++ for (i = GTP_ADDR_LENGTH; i < cfg->length; i++) ++ check_sum += cfg->data[i]; ++ cfg->data[cfg->length] = (~check_sum) + 1; ++ ++ dev_info(&ts->client->dev, "Driver send config\n"); ++ for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { ++ ret = gtp_i2c_write(client, cfg->data, ++ GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH); ++ if (ret > 0) ++ break; ++ } ++ ++ return ret; ++} ++ ++/******************************************************* ++ * Function: ++ * Control enable or disable of work thread. ++ * Input: ++ * ts: goodix i2c_client private data ++ * enable: enable var. ++ *********************************************************/ ++void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable) ++{ ++ if (enable) { ++ set_bit(WORK_THREAD_ENABLED, &ts->flags); ++ dev_dbg(&ts->client->dev, "Input report thread enabled!\n"); ++ } else { ++ clear_bit(WORK_THREAD_ENABLED, &ts->flags); ++ dev_dbg(&ts->client->dev, "Input report thread disabled!\n"); ++ } ++} ++ ++static int gtp_gesture_handler(struct goodix_ts_data *ts) ++{ ++ u8 doze_buf[3] = {GTP_REG_DOZE_BUF >> 8, GTP_REG_DOZE_BUF & 0xFF}; ++ int ret; ++ ++ ret = gtp_i2c_read(ts->client, doze_buf, 3); ++ if (ret < 0) { ++ dev_err(&ts->client->dev, "Failed read doze buf"); ++ return -EINVAL; ++ } ++ ++ dev_dbg(&ts->client->dev, "0x814B = 0x%02X", doze_buf[2]); ++ if ((doze_buf[2] == 'a') || (doze_buf[2] == 'b') || ++ (doze_buf[2] == 'c') || (doze_buf[2] == 'd') || ++ (doze_buf[2] == 'e') || (doze_buf[2] == 'g') || ++ (doze_buf[2] == 'h') || (doze_buf[2] == 'm') || ++ (doze_buf[2] == 'o') || (doze_buf[2] == 'q') || ++ (doze_buf[2] == 's') || (doze_buf[2] == 'v') || ++ (doze_buf[2] == 'w') || (doze_buf[2] == 'y') || ++ (doze_buf[2] == 'z') || (doze_buf[2] == 0x5E) || ++ (doze_buf[2] == 0xAA) || (doze_buf[2] == 0xAB) || ++ (doze_buf[2] == 0xBA) || (doze_buf[2] == 0xBB) || ++ (doze_buf[2] == 0xCC)) { ++ doze_status = DOZE_WAKEUP; ++ input_report_key(ts->input_dev, KEY_POWER, 1); ++ input_sync(ts->input_dev); ++ input_report_key(ts->input_dev, KEY_POWER, 0); ++ input_sync(ts->input_dev); ++ /* clear 0x814B */ ++ doze_buf[2] = 0x00; ++ gtp_i2c_write(ts->client, doze_buf, 3); ++ } else { ++ /* clear 0x814B */ ++ doze_buf[2] = 0x00; ++ gtp_i2c_write(ts->client, doze_buf, 3); ++ gtp_enter_doze(ts); ++ } ++ return 0; ++} ++ ++/* ++ * return touch state register value ++ * pen event id fixed with 9 and set tool type TOOL_PEN ++ * ++ */ ++static u8 gtp_get_points(struct goodix_ts_data *ts, ++ struct goodix_point_t *points, ++ u8 *key_value) ++{ ++ int ret; ++ int i; ++ u8 *coor_data = NULL; ++ u8 finger_state = 0; ++ u8 touch_num = 0; ++ u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8, ++ GTP_READ_COOR_ADDR & 0xFF, 0 }; ++ u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH_ID + 1] = { ++ GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF }; ++ ++ ret = gtp_i2c_read(ts->client, point_data, 12); ++ if (ret < 0) { ++ dev_err(&ts->client->dev, ++ "I2C transfer error. errno:%d\n ", ret); ++ return 0; ++ } ++ finger_state = point_data[GTP_ADDR_LENGTH]; ++ if (finger_state == 0x00) ++ return 0; ++ ++ touch_num = finger_state & 0x0f; ++ if ((finger_state & MASK_BIT_8) == 0 || ++ touch_num > ts->pdata->max_touch_id) { ++ dev_err(&ts->client->dev, ++ "Invalid touch state: 0x%x", finger_state); ++ finger_state = 0; ++ goto exit_get_point; ++ } ++ ++ if (touch_num > 1) { ++ u8 buf[8 * GTP_MAX_TOUCH_ID] = { ++ (GTP_READ_COOR_ADDR + 10) >> 8, ++ (GTP_READ_COOR_ADDR + 10) & 0xff }; ++ ++ ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1)); ++ if (ret < 0) { ++ dev_err(&ts->client->dev, "I2C error. %d\n", ret); ++ finger_state = 0; ++ goto exit_get_point; ++ } ++ memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1)); ++ } ++ ++ /* panel have touch key */ ++ /* 0x20_UPKEY 0X10_DOWNKEY 0X40_ALLKEYDOWN */ ++ *key_value = point_data[3 + 8 * touch_num]; ++ ++ memset(points, 0, sizeof(*points) * GTP_MAX_TOUCH_ID); ++ for (i = 0; i < touch_num; i++) { ++ coor_data = &point_data[i * 8 + 3]; ++ points[i].id = coor_data[0]; ++ points[i].x = coor_data[1] | (coor_data[2] << 8); ++ points[i].y = coor_data[3] | (coor_data[4] << 8); ++ points[i].w = coor_data[5] | (coor_data[6] << 8); ++ /* if pen hover points[].p must set to zero */ ++ points[i].p = coor_data[5] | (coor_data[6] << 8); ++ ++ if (ts->pdata->swap_x2y) ++ GTP_SWAP(points[i].x, points[i].y); ++ ++ dev_dbg(&ts->client->dev, "[%d][%d %d %d]\n", ++ points[i].id, points[i].x, points[i].y, points[i].p); ++ ++ /* pen device coordinate */ ++ if (points[i].id & 0x80) { ++ points[i].tool_type = GTP_TOOL_PEN; ++ points[i].id = 10; ++ if (ts->pdata->pen_suppress_finger) { ++ points[0] = points[i]; ++ memset(++points, 0, sizeof(*points) * (GTP_MAX_TOUCH_ID - 1)); ++ finger_state &= 0xf0; ++ finger_state |= 0x01; ++ break; ++ } ++ } else { ++ points[i].tool_type = GTP_TOOL_FINGER; ++ } ++ } ++ ++exit_get_point: ++ if (!test_bit(RAW_DATA_MODE, &ts->flags)) { ++ ret = gtp_i2c_write(ts->client, end_cmd, 3); ++ if (ret < 0) ++ dev_info(&ts->client->dev, "I2C write end_cmd error!"); ++ } ++ return finger_state; ++} ++ ++static void gtp_type_a_report(struct goodix_ts_data *ts, u8 touch_num, ++ struct goodix_point_t *points) ++{ ++ int i; ++ u16 cur_touch = 0; ++ static u16 pre_touch; ++ static u8 pre_pen_id; ++ ++ if (touch_num) ++ input_report_key(ts->input_dev, BTN_TOUCH, 1); ++ ++ for (i = 0; i < ts->pdata->max_touch_id; i++) { ++ if (touch_num && i == points->id) { ++ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, points->id); ++ ++ if (points->tool_type == GTP_TOOL_PEN) { ++ input_report_key(ts->input_dev, BTN_TOOL_PEN, true); ++ pre_pen_id = points->id; ++ } else { ++ input_report_key(ts->input_dev, BTN_TOOL_FINGER, true); ++ } ++ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, ++ points->x); ++ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, ++ points->y); ++ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, ++ points->w); ++ input_report_abs(ts->input_dev, ABS_MT_PRESSURE, ++ points->p); ++ input_mt_sync(ts->input_dev); ++ ++ cur_touch |= 0x01 << points->id; ++ points++; ++ } else if (pre_touch & 0x01 << i) { ++ if (pre_pen_id == i) { ++ input_report_key(ts->input_dev, BTN_TOOL_PEN, false); ++ /* valid id will < 10, so id to 0xff to indicate a invalid state */ ++ pre_pen_id = 0xff; ++ } else { ++ input_report_key(ts->input_dev, BTN_TOOL_FINGER, false); ++ } ++ } ++ } ++ ++ pre_touch = cur_touch; ++ if (!pre_touch) { ++ input_mt_sync(ts->input_dev); ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ } ++ input_sync(ts->input_dev); ++} ++ ++static void gtp_mt_slot_report(struct goodix_ts_data *ts, u8 touch_num, ++ struct goodix_point_t *points) ++{ ++ int i; ++ u16 cur_touch = 0; ++ static u16 pre_touch; ++ static u8 pre_pen_id; ++ ++ for (i = 0; i < ts->pdata->max_touch_id; i++) { ++ if (touch_num && i == points->id) { ++ input_mt_slot(ts->input_dev, points->id); ++ ++ if (points->tool_type == GTP_TOOL_PEN) { ++ input_mt_report_slot_state(ts->input_dev, ++ MT_TOOL_PEN, true); ++ pre_pen_id = points->id; ++ } else { ++ input_mt_report_slot_state(ts->input_dev, ++ MT_TOOL_FINGER, true); ++ } ++ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, ++ points->x); ++ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, ++ points->y); ++ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, ++ points->w); ++ input_report_abs(ts->input_dev, ABS_MT_PRESSURE, ++ points->p); ++ ++ cur_touch |= 0x01 << points->id; ++ points++; ++ } else if (pre_touch & 0x01 << i) { ++ input_mt_slot(ts->input_dev, i); ++ if (pre_pen_id == i) { ++ input_mt_report_slot_state(ts->input_dev, ++ MT_TOOL_PEN, false); ++ /* valid id will < 10, so set id to 0xff to ++ * indicate a invalid state ++ */ ++ pre_pen_id = 0xff; ++ } else { ++ input_mt_report_slot_state(ts->input_dev, ++ MT_TOOL_FINGER, false); ++ } ++ } ++ } ++ ++ pre_touch = cur_touch; ++ /* report BTN_TOUCH event */ ++ input_mt_sync_frame(ts->input_dev); ++ input_sync(ts->input_dev); ++} ++ ++/******************************************************* ++ * Function: ++ * Goodix touchscreen sensor report function ++ * Input: ++ * ts: goodix tp private data ++ * Output: ++ * None. ++ *********************************************************/ ++static void gtp_work_func(struct goodix_ts_data *ts) ++{ ++ u8 point_state = 0; ++ u8 key_value = 0; ++ s32 i = 0; ++ s32 ret = -1; ++ static u8 pre_key; ++ struct goodix_point_t points[GTP_MAX_TOUCH_ID]; ++ ++ if (test_bit(PANEL_RESETTING, &ts->flags)) ++ return; ++ if (!test_bit(WORK_THREAD_ENABLED, &ts->flags)) ++ return; ++ ++ /* gesture event */ ++ if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) { ++ ret = gtp_gesture_handler(ts); ++ if (ret) ++ dev_err(&ts->client->dev, ++ "Failed handler gesture event %d\n", ret); ++ return; ++ } ++ ++ point_state = gtp_get_points(ts, points, &key_value); ++ if (!point_state) { ++ dev_dbg(&ts->client->dev, "Invalid finger points\n"); ++ return; ++ } ++ ++ /* touch key event */ ++ if (key_value & 0xf0 || pre_key & 0xf0) { ++ /* pen button */ ++ switch (key_value) { ++ case 0x40: ++ input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1); ++ input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1); ++ break; ++ case 0x10: ++ input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1); ++ input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0); ++ dev_dbg(&ts->client->dev, "pen button1 down\n"); ++ break; ++ case 0x20: ++ input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0); ++ input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1); ++ break; ++ default: ++ input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0); ++ input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0); ++ dev_dbg(&ts->client->dev, "button1 up\n"); ++ break; ++ } ++ input_sync(ts->input_dev); ++ pre_key = key_value; ++ } else if (key_value & 0x0f || pre_key & 0x0f) { ++ /* panel key */ ++ for (i = 0; i < ts->pdata->key_nums; i++) { ++ if ((pre_key | key_value) & (0x01 << i)) ++ input_report_key(ts->input_dev, ++ ts->pdata->key_map[i], ++ key_value & (0x01 << i)); ++ } ++ input_sync(ts->input_dev); ++ pre_key = key_value; ++ } ++ ++ if (!ts->pdata->type_a_report) ++ gtp_mt_slot_report(ts, point_state & 0x0f, points); ++ else ++ gtp_type_a_report(ts, point_state & 0x0f, points); ++} ++ ++/******************************************************* ++ * Function: ++ * Timer interrupt service routine for polling mode. ++ * Input: ++ * timer: timer struct pointer ++ * Output: ++ * Timer work mode. ++ * HRTIMER_NORESTART: ++ * no restart mode ++ *********************************************************/ ++static enum hrtimer_restart gtp_timer_handler(struct hrtimer *timer) ++{ ++ struct goodix_ts_data *ts = ++ container_of(timer, struct goodix_ts_data, timer); ++ ++ gtp_work_func(ts); ++ hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000), ++ HRTIMER_MODE_REL); ++ ++ return HRTIMER_NORESTART; ++} ++ ++static irqreturn_t gtp_irq_handler(int irq, void *dev_id) ++{ ++ struct goodix_ts_data *ts = dev_id; ++ ++ gtp_work_func(ts); ++ return IRQ_HANDLED; ++} ++ ++void gtp_int_output(struct goodix_ts_data *ts, int level) ++{ ++ if (!ts->pdata->int_sync) ++ return; ++ ++ if (level == 0) { ++ if (ts->pinctrl.pinctrl) ++ pinctrl_select_state(ts->pinctrl.pinctrl, ++ ts->pinctrl.int_out_low); ++ else if (gpio_is_valid(ts->pdata->irq_gpio)) ++ gpio_direction_output(ts->pdata->irq_gpio, 0); ++ else ++ dev_err(&ts->client->dev, ++ "Failed set int pin output low\n"); ++ } else { ++ if (ts->pinctrl.pinctrl) ++ pinctrl_select_state(ts->pinctrl.pinctrl, ++ ts->pinctrl.int_out_high); ++ else if (gpio_is_valid(ts->pdata->irq_gpio)) ++ gpio_direction_output(ts->pdata->irq_gpio, 1); ++ else ++ dev_err(&ts->client->dev, ++ "Failed set int pin output high\n"); ++ } ++} ++ ++void gtp_int_sync(struct goodix_ts_data *ts, s32 ms) ++{ ++ if (!ts->pdata->int_sync) ++ return; ++ ++ if (ts->pinctrl.pinctrl) { ++ gtp_int_output(ts, 0); ++ msleep(ms); ++ pinctrl_select_state(ts->pinctrl.pinctrl, ++ ts->pinctrl.int_input); ++ } else if (gpio_is_valid(ts->pdata->irq_gpio)) { ++ gpio_direction_output(ts->pdata->irq_gpio, 0); ++ msleep(ms); ++ gpio_direction_input(ts->pdata->irq_gpio); ++ } else { ++ dev_err(&ts->client->dev, "Failed sync int pin\n"); ++ } ++} ++ ++/******************************************************* ++ * Function: ++ * Reset chip. Control the reset pin and int-pin(if ++ * defined), ++ * Input: ++ * client: i2c device. ++ * ms: reset time in millisecond ++ * Output: ++ * None. ++ *******************************************************/ ++void gtp_reset_guitar(struct i2c_client *client, s32 ms) ++{ ++ struct goodix_ts_data *ts = i2c_get_clientdata(client); ++ ++ dev_info(&client->dev, "Guitar reset"); ++ set_bit(PANEL_RESETTING, &ts->flags); ++ if (!gpio_is_valid(ts->pdata->rst_gpio)) { ++ dev_warn(&client->dev, "reset failed no valid reset gpio"); ++ return; ++ } ++ ++ gpio_direction_output(ts->pdata->rst_gpio, 0); ++ usleep_range(ms * 1000, ms * 1000 + 100); /* T2: > 10ms */ ++ ++ gtp_int_output(ts, client->addr == 0x14); ++ ++ usleep_range(2000, 3000); /* T3: > 100us (2ms)*/ ++ gpio_direction_output(ts->pdata->rst_gpio, 1); ++ ++ usleep_range(6000, 7000); /* T4: > 5ms */ ++ gpio_direction_output(ts->pdata->rst_gpio, 1); ++ ++ gtp_int_sync(ts, 50); ++ if (ts->pdata->esd_protect) ++ gtp_init_ext_watchdog(client); ++ ++ clear_bit(PANEL_RESETTING, &ts->flags); ++} ++ ++/******************************************************* ++ * Function: ++ * Enter doze mode for sliding wakeup. ++ * Input: ++ * ts: goodix tp private data ++ * Output: ++ * 1: succeed, otherwise failed ++ *******************************************************/ ++static int gtp_enter_doze(struct goodix_ts_data *ts) ++{ ++ int ret = -1; ++ int retry = 0; ++ u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8), ++ (u8)GTP_REG_COMMAND, 8 }; ++ ++ /* resend doze command ++ * if (test_and_set_bit(DOZE_MODE, &ts->flags)) { ++ * dev_info(&ts->client->dev, "Already in doze mode\n"); ++ * return SUCCESS; ++ * } ++ */ ++ set_bit(DOZE_MODE, &ts->flags); ++ dev_dbg(&ts->client->dev, "Entering gesture mode."); ++ while (retry++ < 5) { ++ i2c_control_buf[0] = (u8)(GTP_REG_COMMAND_CHECK >> 8); ++ i2c_control_buf[1] = (u8)GTP_REG_COMMAND_CHECK; ++ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); ++ if (ret < 0) { ++ dev_dbg(&ts->client->dev, ++ "failed to set doze flag into 0x8046, %d\n", ++ retry); ++ continue; ++ } ++ i2c_control_buf[0] = (u8)(GTP_REG_COMMAND >> 8); ++ i2c_control_buf[1] = (u8)GTP_REG_COMMAND; ++ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); ++ if (ret > 0) { ++ dev_dbg(&ts->client->dev, "Gesture mode enabled\n"); ++ return ret; ++ } ++ usleep_range(10000, 11000); ++ } ++ ++ dev_err(&ts->client->dev, "Failed enter doze mode\n"); ++ clear_bit(DOZE_MODE, &ts->flags); ++ return ret; ++} ++ ++static s8 gtp_enter_sleep(struct goodix_ts_data *ts) ++{ ++ s8 ret = -1; ++ s8 retry = 0; ++ u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8), ++ (u8)GTP_REG_COMMAND, 5 }; ++ ++ gtp_int_output(ts, 0); ++// usleep_range(5000, 6000); ++ ++ while (retry++ < 5) { ++ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); ++ if (ret > 0) { ++ dev_info(&ts->client->dev, "Enter sleep mode\n"); ++ ++ return ret; ++ } ++ usleep_range(10000, 11000); ++ } ++ dev_err(&ts->client->dev, "Failed send sleep cmd\n"); ++ ++ return ret; ++} ++ ++static int gtp_wakeup_sleep(struct goodix_ts_data *ts) ++{ ++ u8 retry = 0; ++ int ret = -1; ++ ++ while (retry++ < 10) { ++ gtp_int_output(ts, 1); ++ usleep_range(5000, 6000); ++ ++ ret = gtp_i2c_test(ts->client); ++ if (!ret) { ++ dev_dbg(&ts->client->dev, "Success wakeup sleep\n"); ++ ++ gtp_int_sync(ts, 25); ++ if (ts->pdata->esd_protect) ++ gtp_init_ext_watchdog(ts->client); ++ ++ return ret; ++ } ++ gtp_reset_guitar(ts->client, 20); ++ } ++ ++ dev_err(&ts->client->dev, "Failed wakeup from sleep mode\n"); ++ return -EINVAL; ++} ++ ++static int gtp_find_valid_cfg_data(struct goodix_ts_data *ts) ++{ ++ int ret = -1; ++ u8 sensor_id = 0; ++ struct goodix_config_data *cfg = &ts->pdata->config; ++ ++ /* if defined CONFIG_OF, parse config data from dtsi ++ * else parse config data form header file. ++ */ ++ cfg->length = 0; ++ ++#ifndef CONFIG_OF ++ u8 cfg_info_group0[] = CTP_CFG_GROUP0; ++ u8 cfg_info_group1[] = CTP_CFG_GROUP1; ++ u8 cfg_info_group2[] = CTP_CFG_GROUP2; ++ u8 cfg_info_group3[] = CTP_CFG_GROUP3; ++ u8 cfg_info_group4[] = CTP_CFG_GROUP4; ++ u8 cfg_info_group5[] = CTP_CFG_GROUP5; ++ ++ u8 *send_cfg_buf[] = { cfg_info_group0, cfg_info_group1, ++ cfg_info_group2, cfg_info_group3, ++ cfg_info_group4, cfg_info_group5 }; ++ u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group0), ++ CFG_GROUP_LEN(cfg_info_group1), ++ CFG_GROUP_LEN(cfg_info_group2), ++ CFG_GROUP_LEN(cfg_info_group3), ++ CFG_GROUP_LEN(cfg_info_group4), ++ CFG_GROUP_LEN(cfg_info_group5)}; ++ ++ dev_dbg(&ts->client->dev, ++ "Config Groups\' Lengths: %d, %d, %d, %d, %d, %d", ++ cfg_info_len[0], cfg_info_len[1], cfg_info_len[2], ++ cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]); ++#endif ++ ++ /* read sensor id */ ++ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, ++ &sensor_id, 1); ++ if (SUCCESS != ret || sensor_id >= 0x06) { ++ dev_err(&ts->client->dev, ++ "Failed get valid sensor_id(0x%02X), No Config Sent\n", ++ sensor_id); ++ return -EINVAL; ++ } ++ ++ dev_dbg(&ts->client->dev, "Sensor_ID: %d", sensor_id); ++ /* parse config data */ ++#ifdef CONFIG_OF ++ dev_dbg(&ts->client->dev, "Get config data from device tree\n"); ++ ret = gtp_parse_dt_cfg(&ts->client->dev, ++ &cfg->data[GTP_ADDR_LENGTH], ++ &cfg->length, sensor_id); ++ if (ret < 0) { ++ dev_err(&ts->client->dev, ++ "Failed to parse config data form device tree\n"); ++ cfg->length = 0; ++ return -EPERM; ++ } ++#else ++ dev_dbg(&ts->client->dev, "Get config data from header file\n"); ++ if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && ++ (!cfg_info_len[3]) && (!cfg_info_len[4]) && ++ (!cfg_info_len[5])) { ++ sensor_id = 0; ++ } ++ cfg->length = cfg_info_len[sensor_id]; ++ memset(&cfg->data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); ++ memcpy(&cfg->data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ++ cfg->length); ++#endif ++ ++ if (cfg->length < GTP_CONFIG_MIN_LENGTH) { ++ dev_err(&ts->client->dev, ++ "Failed get valid config data with sensor id %d\n", ++ sensor_id); ++ cfg->length = 0; ++ return -EPERM; ++ } ++ ++ dev_info(&ts->client->dev, "Config group%d used,length: %d\n", ++ sensor_id, cfg->length); ++ ++ return 0; ++} ++ ++/******************************************************* ++ * Function: ++ * Get valid config data from dts or .h file. ++ * Read firmware version info and judge firmware ++ * working state ++ * Input: ++ * ts: goodix private data ++ * Output: ++ * Executive outcomes. ++ * 0: succeed, otherwise: failed ++ *******************************************************/ ++static s32 gtp_init_panel(struct goodix_ts_data *ts) ++{ ++ s32 ret = -1; ++ u8 opr_buf[16] = {0}; ++ u8 drv_cfg_version = 0; ++ u8 flash_cfg_version = 0; ++ struct goodix_config_data *cfg = &ts->pdata->config; ++ ++ if (!ts->pdata->driver_send_cfg) { ++ dev_info(&ts->client->dev, "Driver set not send config\n"); ++ cfg->length = GTP_CONFIG_MAX_LENGTH; ++ ret = gtp_i2c_read(ts->client, ++ cfg->data, cfg->length + ++ GTP_ADDR_LENGTH); ++ if (ret < 0) ++ dev_err(&ts->client->dev, "Read origin Config Failed\n"); ++ ++ return 0; ++ } ++ ++ gtp_find_valid_cfg_data(ts); ++ ++ /* check firmware */ ++ ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1); ++ if (SUCCESS == ret) { ++ if (opr_buf[0] != 0xBE) { ++ set_bit(FW_ERROR, &ts->flags); ++ dev_err(&ts->client->dev, ++ "Firmware error, no config sent!\n"); ++ return -EINVAL; ++ } ++ } ++ ++ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, ++ &opr_buf[0], 1); ++ if (ret == SUCCESS) { ++ dev_dbg(&ts->client->dev, ++ "Config Version: %d; IC Config Version: %d\n", ++ cfg->data[GTP_ADDR_LENGTH], opr_buf[0]); ++ flash_cfg_version = opr_buf[0]; ++ drv_cfg_version = cfg->data[GTP_ADDR_LENGTH]; ++ ++ if (flash_cfg_version < 90 && ++ flash_cfg_version > drv_cfg_version) ++ cfg->data[GTP_ADDR_LENGTH] = 0x00; ++ } else { ++ dev_err(&ts->client->dev, ++ "Failed to get ic config version!No config sent\n"); ++ return -EPERM; ++ } ++ ++ ret = gtp_send_cfg(ts->client); ++ if (ret < 0) ++ dev_err(&ts->client->dev, "Send config error\n"); ++ else ++ usleep_range(10000, 11000); /* 10 ms */ ++ ++ /* restore config version */ ++ cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version; ++ ++ return 0; ++} ++ ++static ssize_t gtp_config_read_proc(struct file *file, char __user *page, ++ size_t size, loff_t *ppos) ++{ ++ int i, ret; ++ char *ptr; ++ size_t data_len = 0; ++ char temp_data[GTP_CONFIG_MAX_LENGTH + 2] = { ++ (u8)(GTP_REG_CONFIG_DATA >> 8), ++ (u8)GTP_REG_CONFIG_DATA }; ++ struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); ++ struct goodix_config_data *cfg = &ts->pdata->config; ++ ++ ptr = kzalloc(4096, GFP_KERNEL); ++ if (!ptr) { ++ dev_err(&ts->client->dev, "Failed alloc memory for config\n"); ++ return -ENOMEM; ++ } ++ ++ data_len += snprintf(ptr + data_len, 4096 - data_len, ++ "====init value====\n"); ++ for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++) { ++ data_len += snprintf(ptr + data_len, 4096 - data_len, ++ "0x%02X ", cfg->data[i + 2]); ++ ++ if (i % 8 == 7) ++ data_len += snprintf(ptr + data_len, ++ 4096 - data_len, "\n"); ++ } ++ data_len += snprintf(ptr + data_len, 4096 - data_len, "\n"); ++ ++ data_len += snprintf(ptr + data_len, 4096 - data_len, ++ "====real value====\n"); ++ ret = gtp_i2c_read(i2c_connect_client, temp_data, ++ GTP_CONFIG_MAX_LENGTH + 2); ++ if (ret < 0) { ++ data_len += snprintf(ptr + data_len, 4096 - data_len, ++ "Failed read real config data\n"); ++ } else { ++ for (i = 0; i < GTP_CONFIG_MAX_LENGTH; i++) { ++ data_len += snprintf(ptr + data_len, 4096 - data_len, ++ "0x%02X ", temp_data[i + 2]); ++ ++ if (i % 8 == 7) ++ data_len += snprintf(ptr + data_len, ++ 4096 - data_len, "\n"); ++ } ++ } ++ ++ data_len = simple_read_from_buffer(page, size, ppos, ptr, data_len); ++ kfree(ptr); ++ ptr = NULL; ++ return data_len; ++} ++ ++static u8 ascii2hex(u8 a) ++{ ++ s8 value = 0; ++ ++ if (a >= '0' && a <= '9') ++ value = a - '0'; ++ else if (a >= 'A' && a <= 'F') ++ value = a - 'A' + 0x0A; ++ else if (a >= 'a' && a <= 'f') ++ value = a - 'a' + 0x0A; ++ else ++ value = 0xff; ++ ++ return value; ++} ++ ++int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf) ++{ ++ int i, ret; ++ int cfg_len = 0; ++ u8 high, low; ++ ++ for (i = 0; i < src_len;) { ++ if (src_buf[i] == ' ' || src_buf[i] == '\r' || ++ src_buf[i] == '\n') { ++ i++; ++ continue; ++ } ++ ++ if ((src_buf[i] == '0') && ((src_buf[i + 1] == 'x') || ++ (src_buf[i + 1] == 'X'))) { ++ high = ascii2hex(src_buf[i + 2]); ++ low = ascii2hex(src_buf[i + 3]); ++ ++ if ((high == 0xFF) || (low == 0xFF)) { ++ ret = -1; ++ goto convert_failed; ++ } ++ ++ if (cfg_len < GTP_CONFIG_MAX_LENGTH) { ++ dst_buf[cfg_len++] = (high << 4) + low; ++ i += 5; ++ } else { ++ ret = -2; ++ goto convert_failed; ++ } ++ } else { ++ ret = -3; ++ goto convert_failed; ++ } ++ } ++ return cfg_len; ++ ++convert_failed: ++ return ret; ++} ++ ++static ssize_t gtp_config_write_proc(struct file *filp, ++ const char __user *buffer, ++ size_t count, loff_t *off) ++{ ++ u8 *temp_buf; ++ u8 *file_config; ++ int file_cfg_len; ++ s32 ret = 0, i; ++ struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); ++ ++ dev_dbg(&ts->client->dev, "write count %zu\n", count); ++ ++ if (count > PAGE_SIZE) { ++ dev_err(&ts->client->dev, "config to long %zu\n", count); ++ return -EFAULT; ++ } ++ ++ temp_buf = kzalloc(count, GFP_KERNEL); ++ if (!temp_buf) { ++ dev_err(&ts->client->dev, "failed alloc temp memory"); ++ return -ENOMEM; ++ } ++ ++ file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, ++ GFP_KERNEL); ++ if (!file_config) { ++ dev_err(&ts->client->dev, "failed alloc config memory"); ++ kfree(temp_buf); ++ return -ENOMEM; ++ } ++ file_config[0] = GTP_REG_CONFIG_DATA >> 8; ++ file_config[1] = GTP_REG_CONFIG_DATA & 0xff; ++ ++ if (copy_from_user(temp_buf, buffer, count)) { ++ dev_err(&ts->client->dev, "Failed copy from user\n"); ++ ret = -EFAULT; ++ goto send_cfg_err; ++ } ++ ++ file_cfg_len = gtp_ascii_to_array(temp_buf, (int)count, ++ &file_config[GTP_ADDR_LENGTH]); ++ if (file_cfg_len < 0) { ++ dev_err(&ts->client->dev, "failed covert ascii to hex"); ++ ret = -EFAULT; ++ goto send_cfg_err; ++ } ++ ++ GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len); ++ ++ i = 0; ++ while (i++ < 5) { ++ ret = gtp_i2c_write(ts->client, file_config, file_cfg_len + 2); ++ if (ret > 0) { ++ dev_info(&ts->client->dev, "Send config SUCCESS."); ++ break; ++ } ++ dev_err(&ts->client->dev, "Send config i2c error."); ++ ret = -EFAULT; ++ goto send_cfg_err; ++ } ++ ++ ret = count; ++send_cfg_err: ++ kfree(temp_buf); ++ kfree(file_config); ++ return ret; ++} ++ ++static const struct proc_ops config_proc_ops = { ++ .proc_read = gtp_config_read_proc, ++ .proc_write = gtp_config_write_proc, ++}; ++ ++static ssize_t gtp_workmode_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ size_t data_len = 0; ++ struct goodix_ts_data *data = dev_get_drvdata(dev); ++ ++ if (test_bit(DOZE_MODE, &data->flags)) ++ data_len = scnprintf(buf, PAGE_SIZE, "%s\n", ++ "doze_mode"); ++ else if (test_bit(SLEEP_MODE, &data->flags)) ++ data_len = scnprintf(buf, PAGE_SIZE, "%s\n", ++ "sleep_mode"); ++ else ++ data_len = scnprintf(buf, PAGE_SIZE, "%s\n", ++ "normal_mode"); ++ ++ return data_len; ++} ++static DEVICE_ATTR(workmode, 0444, gtp_workmode_show, NULL); ++ ++#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE ++#define FW_NAME_MAX_LEN 80 ++static ssize_t gtp_dofwupdate_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct goodix_ts_data *ts = dev_get_drvdata(dev); ++ char update_file_name[FW_NAME_MAX_LEN]; ++ int retval; ++ ++ if (count > FW_NAME_MAX_LEN) { ++ dev_info(&ts->client->dev, "FW filename is too long\n"); ++ retval = -EINVAL; ++ goto exit; ++ } ++ ++ strlcpy(update_file_name, buf, count); ++ ++ ts->force_update = true; ++ retval = gup_update_proc(update_file_name); ++ if (retval == FAIL) ++ dev_err(&ts->client->dev, "Fail to update GTP firmware.\n"); ++ else ++ dev_info(&ts->client->dev, "Update success\n"); ++ ++ return count; ++ ++exit: ++ return retval; ++} ++static DEVICE_ATTR(dofwupdate, 0664, NULL, gtp_dofwupdate_store); ++#endif ++ ++static ssize_t gtp_productinfo_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct goodix_ts_data *data = dev_get_drvdata(dev); ++ struct goodix_fw_info *fw_info = &data->fw_info; ++ ++ return scnprintf(buf, PAGE_SIZE, "GT%s_%x_%d\n", ++ fw_info->pid, fw_info->version, fw_info->sensor_id); ++} ++static DEVICE_ATTR(productinfo, 0444, gtp_productinfo_show, NULL); ++ ++static ssize_t gtp_drv_irq_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned long value = 0; ++ int err = 0; ++ struct goodix_ts_data *data = dev_get_drvdata(dev); ++ ++ err = kstrtoul(buf, 10, &value); ++ if (err < 0) { ++ dev_err(dev, "Failed to convert value\n"); ++ return -EINVAL; ++ } ++ ++ switch (value) { ++ case 0: ++ /* Disable irq */ ++ gtp_work_control_enable(data, false); ++ break; ++ case 1: ++ /* Enable irq */ ++ gtp_work_control_enable(data, true); ++ break; ++ default: ++ dev_err(dev, "Invalid value\n"); ++ return -EINVAL; ++ } ++ ++ return count; ++} ++ ++static ssize_t gtp_drv_irq_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct goodix_ts_data *data = dev_get_drvdata(dev); ++ ++ return scnprintf(buf, PAGE_SIZE, "%s\n", ++ test_bit(WORK_THREAD_ENABLED, &data->flags) ++ ? "enabled" : "disabled"); ++} ++static DEVICE_ATTR(drv_irq, 0664, gtp_drv_irq_show, gtp_drv_irq_store); ++ ++static ssize_t gtp_reset_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct goodix_ts_data *data = dev_get_drvdata(dev); ++ ++ if ('1' != buf[0]) { ++ dev_err(dev, "Invalid argument for reset\n"); ++ return -EINVAL; ++ } ++ ++ gtp_reset_guitar(data->client, 20); ++ ++ return count; ++} ++static DEVICE_ATTR(reset, 0220, NULL, gtp_reset_store); ++ ++static struct attribute *gtp_attrs[] = { ++ &dev_attr_workmode.attr, ++ &dev_attr_productinfo.attr, ++ ++#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE ++ &dev_attr_dofwupdate.attr, ++#endif ++ ++ &dev_attr_drv_irq.attr, ++ &dev_attr_reset.attr, ++ NULL ++}; ++ ++static const struct attribute_group gtp_attr_group = { ++ .attrs = gtp_attrs, ++}; ++ ++static int gtp_create_file(struct goodix_ts_data *ts) ++{ ++ int ret; ++ struct i2c_client *client = ts->client; ++ ++ /* Create proc file system */ ++ gtp_config_proc = NULL; ++ gtp_config_proc = proc_create(GT91XX_CONFIG_PROC_FILE, 0664, ++ NULL, &config_proc_ops); ++ if (!gtp_config_proc) ++ dev_err(&client->dev, "create_proc_entry %s failed\n", ++ GT91XX_CONFIG_PROC_FILE); ++ else ++ dev_info(&client->dev, "create proc entry %s success\n", ++ GT91XX_CONFIG_PROC_FILE); ++ ++ ret = sysfs_create_group(&client->dev.kobj, >p_attr_group); ++ if (ret) { ++ dev_err(&client->dev, "Failure create sysfs group %d\n", ret); ++ /*TODO: debug change */ ++ goto exit_free_config_proc; ++ } ++ return 0; ++ ++exit_free_config_proc: ++ remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc); ++ return -ENODEV; ++} ++ ++s32 gtp_get_fw_info(struct i2c_client *client, struct goodix_fw_info *fw_info) ++{ ++ s32 ret = -1; ++ u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff}; ++ ++ ret = gtp_i2c_read(client, buf, sizeof(buf)); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed read fw_info\n"); ++ return ret; ++ } ++ ++ /* product id */ ++ memset(fw_info, 0, sizeof(*fw_info)); ++ ++ if (buf[5] == 0x00) { ++ memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 3); ++ dev_info(&client->dev, "IC Version: %c%c%c_%02X%02X\n", ++ buf[2], buf[3], buf[4], buf[7], buf[6]); ++ } else { ++ memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 4); ++ dev_info(&client->dev, "IC Version: %c%c%c%c_%02X%02X\n", ++ buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]); ++ } ++ ++ /* current firmware version */ ++ fw_info->version = (buf[7] << 8) | buf[6]; ++ ++ /* read sensor id */ ++ fw_info->sensor_id = 0xff; ++ ret = gtp_i2c_read_dbl_check(client, GTP_REG_SENSOR_ID, ++ &fw_info->sensor_id, 1); ++ if (SUCCESS != ret || fw_info->sensor_id >= 0x06) { ++ dev_err(&client->dev, ++ "Failed get valid sensor_id(0x%02X), No Config Sent\n", ++ fw_info->sensor_id); ++ ++ fw_info->sensor_id = 0xff; ++ } ++ ++ return ret; ++} ++ ++static int gtp_i2c_test(struct i2c_client *client) ++{ ++ u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff}; ++ u8 retry = 0; ++ int ret = -1; ++ ++ while (retry++ < 3) { ++ ret = gtp_i2c_read(client, test, 3); ++ if (ret == 2) ++ return 0; ++ ++ dev_err(&client->dev, "GTP i2c test failed time %d\n", retry); ++ usleep_range(10000, 11000); /* 10 ms */ ++ } ++ ++ return -EAGAIN; ++} ++ ++static int gtp_pinctrl_init(struct goodix_ts_data *ts) ++{ ++ struct goodix_pinctrl *pinctrl = &ts->pinctrl; ++ ++ pinctrl->pinctrl = devm_pinctrl_get(&ts->client->dev); ++ if (IS_ERR_OR_NULL(pinctrl->pinctrl)) { ++ dev_info(&ts->client->dev, "No pinctrl found\n"); ++ pinctrl->pinctrl = NULL; ++ return 0; ++ } ++ ++ pinctrl->default_sta = pinctrl_lookup_state(pinctrl->pinctrl, ++ "default"); ++ if (IS_ERR_OR_NULL(pinctrl->default_sta)) { ++ dev_info(&ts->client->dev, ++ "Failed get pinctrl state:default state\n"); ++ goto exit_pinctrl_init; ++ } ++ ++ pinctrl->int_out_high = pinctrl_lookup_state(pinctrl->pinctrl, ++ "int-output-high"); ++ if (IS_ERR_OR_NULL(pinctrl->int_out_high)) { ++ dev_info(&ts->client->dev, ++ "Failed get pinctrl state:output_high\n"); ++ goto exit_pinctrl_init; ++ } ++ ++ pinctrl->int_out_low = pinctrl_lookup_state(pinctrl->pinctrl, ++ "int-output-low"); ++ if (IS_ERR_OR_NULL(pinctrl->int_out_low)) { ++ dev_info(&ts->client->dev, ++ "Failed get pinctrl state:output_low\n"); ++ goto exit_pinctrl_init; ++ } ++ ++ pinctrl->int_input = pinctrl_lookup_state(pinctrl->pinctrl, ++ "int-input"); ++ if (IS_ERR_OR_NULL(pinctrl->int_input)) { ++ dev_info(&ts->client->dev, ++ "Failed get pinctrl state:int-input\n"); ++ goto exit_pinctrl_init; ++ } ++ dev_info(&ts->client->dev, "Success init pinctrl\n"); ++ return 0; ++exit_pinctrl_init: ++ devm_pinctrl_put(pinctrl->pinctrl); ++ pinctrl->pinctrl = NULL; ++ pinctrl->int_out_high = NULL; ++ pinctrl->int_out_low = NULL; ++ pinctrl->int_input = NULL; ++ return 0; ++} ++ ++static void gtp_pinctrl_deinit(struct goodix_ts_data *ts) ++{ ++ if (ts->pinctrl.pinctrl) ++ devm_pinctrl_put(ts->pinctrl.pinctrl); ++} ++ ++static int gtp_request_io_port(struct goodix_ts_data *ts) ++{ ++ int ret = 0; ++ ++ if (!ts->pinctrl.pinctrl) { ++ if (gpio_is_valid(ts->pdata->irq_gpio)) { ++ ret = gpio_request(ts->pdata->irq_gpio, "goodix_ts_int"); ++ if (ret < 0) { ++ dev_err(&ts->client->dev, ++ "Failed to request GPIO:%d, ERRNO:%d\n", ++ (s32)ts->pdata->irq_gpio, ret); ++ return -ENODEV; ++ } ++ ++ gpio_direction_input(ts->pdata->irq_gpio); ++ dev_info(&ts->client->dev, "Success request irq-gpio\n"); ++ } ++ } ++ ++ if (gpio_is_valid(ts->pdata->rst_gpio)) { ++ ret = gpio_request(ts->pdata->rst_gpio, "goodix_ts_rst"); ++ if (ret < 0) { ++ dev_err(&ts->client->dev, ++ "Failed to request GPIO:%d, ERRNO:%d\n", ++ (s32)ts->pdata->rst_gpio, ret); ++ ++ if (gpio_is_valid(ts->pdata->irq_gpio)) ++ gpio_free(ts->pdata->irq_gpio); ++ ++ return -ENODEV; ++ } ++ ++ gpio_direction_input(ts->pdata->rst_gpio); ++ dev_info(&ts->client->dev, "Success request rst-gpio\n"); ++ } ++ ++ return 0; ++} ++ ++/******************************************************* ++ * Function: ++ * Request interrupt if define irq pin, else use hrtimer ++ * as interrupt source ++ * Input: ++ * ts: private data. ++ * Output: ++ * Executive outcomes. ++ * 0: succeed, -1: failed. ++ *******************************************************/ ++static int gtp_request_irq(struct goodix_ts_data *ts) ++{ ++ int ret = -1; ++ ++ /* use irq */ ++ if (gpio_is_valid(ts->pdata->irq_gpio) || ts->client->irq > 0) { ++ if (gpio_is_valid(ts->pdata->irq_gpio)) ++ ts->client->irq = gpio_to_irq(ts->pdata->irq_gpio); ++ ++ dev_info(&ts->client->dev, "INT num %d, trigger type:%d\n", ++ ts->client->irq, ts->pdata->irq_flags); ++ ret = request_threaded_irq(ts->client->irq, NULL, ++ gtp_irq_handler, ++ ts->pdata->irq_flags | IRQF_ONESHOT, ++ ts->client->name, ++ ts); ++ if (ret < 0) { ++ dev_err(&ts->client->dev, ++ "Failed to request irq %d\n", ts->client->irq); ++ return ret; ++ } ++ } else { /* use hrtimer */ ++ dev_info(&ts->client->dev, "No hardware irq, use hrtimer\n"); ++ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ ts->timer.function = gtp_timer_handler; ++ hrtimer_start(&ts->timer, ++ ktime_set(0, (GTP_POLL_TIME + 6) * 1000000), ++ HRTIMER_MODE_REL); ++ set_bit(HRTIMER_USED, &ts->flags); ++ ret = 0; ++ } ++ return ret; ++} ++ ++static s8 gtp_request_input_dev(struct goodix_ts_data *ts) ++{ ++ s8 ret = -1; ++ u8 index = 0; ++ ++ ts->input_dev = input_allocate_device(); ++ if (!ts->input_dev) { ++ dev_err(&ts->client->dev, "Failed to allocate input device\n"); ++ return -ENOMEM; ++ } ++ ++ ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) ++ | BIT_MASK(EV_ABS); ++ if (!ts->pdata->type_a_report) { ++ input_mt_init_slots(ts->input_dev, 16, INPUT_MT_DIRECT); ++ dev_info(&ts->client->dev, "Use slot report protocol\n"); ++ } else { ++ __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); ++ __set_bit(BTN_TOUCH, ts->input_dev->keybit); ++ dev_info(&ts->client->dev, "Use type A report protocol\n"); ++ } ++ ++ input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON1); ++ input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON2); ++ ++ /* touch key register */ ++ for (index = 0; index < ts->pdata->key_nums; index++) ++ input_set_capability(ts->input_dev, EV_KEY, ++ ts->pdata->key_map[index]); ++ ++ if (ts->pdata->slide_wakeup) ++ input_set_capability(ts->input_dev, EV_KEY, KEY_POWER); ++ ++ if (ts->pdata->swap_x2y) ++ GTP_SWAP(ts->pdata->abs_size_x, ts->pdata->abs_size_y); ++ ++ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ++ ts->pdata->abs_size_x, 0, 0); ++ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ++ ts->pdata->abs_size_y, 0, 0); ++ input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, ++ ts->pdata->max_touch_width, 0, 0); ++ input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, ++ ts->pdata->max_touch_pressure, 0, 0); ++ input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, ++ ts->pdata->max_touch_id, 0, 0); ++ if (!ts->pdata->type_a_report) { ++ input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE, ++ 0, MT_TOOL_MAX, 0, 0); ++ } else { ++ __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit); ++ __set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit); ++ } ++ ++ ts->input_dev->name = goodix_ts_name; ++ ts->input_dev->phys = goodix_input_phys; ++ ts->input_dev->id.bustype = BUS_I2C; ++ ts->input_dev->id.vendor = 0xDEAD; ++ ts->input_dev->id.product = 0xBEEF; ++ ts->input_dev->id.version = 10427; ++ ++ ret = input_register_device(ts->input_dev); ++ if (ret) { ++ dev_err(&ts->client->dev, "Register %s input device failed\n", ++ ts->input_dev->name); ++ input_free_device(ts->input_dev); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Devices Tree support ++ */ ++#ifdef CONFIG_OF ++static void gtp_parse_dt_coords(struct device *dev, ++ struct goodix_ts_platform_data *pdata) ++{ ++ struct device_node *np = dev->of_node; ++ int ret; ++ ++ ret = of_property_read_u32(np, "touchscreen-max-id", ++ &pdata->max_touch_id); ++ if (ret || pdata->max_touch_id > GTP_MAX_TOUCH_ID) { ++ dev_info(dev, "Unset touchscreen-max-id, use default\n"); ++ pdata->max_touch_id = GTP_MAX_TOUCH_ID; ++ } ++ ++ ret = of_property_read_u32(np, "touchscreen-size-x", ++ &pdata->abs_size_x); ++ if (ret) { ++ dev_info(dev, "Unset touchscreen-size-x, use default\n"); ++ pdata->abs_size_x = GTP_DEFAULT_MAX_X; ++ } ++ ++ ret = of_property_read_u32(np, "touchscreen-size-y", ++ &pdata->abs_size_y); ++ if (ret) { ++ dev_info(dev, "Unset touchscreen-size-y, use default\n"); ++ pdata->abs_size_y = GTP_DEFAULT_MAX_Y; ++ } ++ ++ ret = of_property_read_u32(np, "touchscreen-max-w", ++ &pdata->max_touch_width); ++ if (ret) { ++ dev_info(dev, "Unset touchscreen-max-w, use default\n"); ++ pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH; ++ } ++ ++ ret = of_property_read_u32(np, "touchscreen-max-p", ++ &pdata->max_touch_pressure); ++ if (ret) { ++ dev_info(dev, "Unset touchscreen-max-p, use default\n"); ++ pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE; ++ } ++ dev_info(dev, "touch input parameters is [id x y w p]<%d %d %d %d %d>\n", ++ pdata->max_touch_id, pdata->abs_size_x, pdata->abs_size_y, ++ pdata->max_touch_width, pdata->max_touch_pressure); ++} ++ ++static int gtp_parse_dt(struct device *dev, ++ struct goodix_ts_platform_data *pdata) ++{ ++ int ret; ++ u32 key_nums; ++ struct property *prop; ++ u32 key_map[MAX_KEY_NUMS]; ++ struct device_node *np = dev->of_node; ++ ++ gtp_parse_dt_coords(dev, pdata); ++ ++ ret = of_property_read_u32(np, "irq-flags", ++ &pdata->irq_flags); ++ if (ret) { ++ dev_info(dev, ++ "Failed get int-trigger-type from dts,set default\n"); ++ pdata->irq_flags = GTP_DEFAULT_INT_TRIGGER; ++ } ++ of_property_read_u32(np, "goodix,int-sync", &pdata->int_sync); ++ if (pdata->int_sync) ++ dev_info(dev, "int-sync enabled\n"); ++ ++ of_property_read_u32(np, "goodix,driver-send-cfg", ++ &pdata->driver_send_cfg); ++ if (pdata->driver_send_cfg) ++ dev_info(dev, "driver-send-cfg enabled\n"); ++ ++ of_property_read_u32(np, "goodix,swap-x2y", &pdata->swap_x2y); ++ if (pdata->swap_x2y) ++ dev_info(dev, "swap-x2y enabled\n"); ++ ++ of_property_read_u32(np, "goodix,slide-wakeup", &pdata->slide_wakeup); ++ if (pdata->slide_wakeup) ++ dev_info(dev, "slide-wakeup enabled\n"); ++ ++ of_property_read_u32(np, "goodix,auto-update", &pdata->auto_update); ++ if (pdata->auto_update) ++ dev_info(dev, "auto-update enabled\n"); ++ ++ of_property_read_u32(np, "goodix,auto-update-cfg", ++ &pdata->auto_update_cfg); ++ if (pdata->auto_update_cfg) ++ dev_info(dev, "auto-update-cfg enabled\n"); ++ ++ of_property_read_u32(np, "goodix,esd-protect", &pdata->esd_protect); ++ if (pdata->esd_protect) ++ dev_info(dev, "esd-protect enabled\n"); ++ ++ of_property_read_u32(np, "goodix,type-a-report", ++ &pdata->type_a_report); ++ if (pdata->type_a_report) ++ dev_info(dev, "type-a-report enabled\n"); ++ ++ of_property_read_u32(np, "goodix,resume-in-workqueue", ++ &pdata->resume_in_workqueue); ++ if (pdata->resume_in_workqueue) ++ dev_info(dev, "resume-in-workqueue enabled\n"); ++ ++ of_property_read_u32(np, "goodix,power-off-sleep", ++ &pdata->power_off_sleep); ++ if (pdata->power_off_sleep) ++ dev_info(dev, "power-off-sleep enabled\n"); ++ ++ of_property_read_u32(np, "goodix,pen-suppress-finger", ++ &pdata->pen_suppress_finger); ++ if (pdata->pen_suppress_finger) ++ dev_info(dev, "pen-suppress-finger enabled\n"); ++ ++ prop = of_find_property(np, "touchscreen-key-map", NULL); ++ if (prop) { ++ key_nums = prop->length / sizeof(key_map[0]); ++ key_nums = key_nums > MAX_KEY_NUMS ? MAX_KEY_NUMS : key_nums; ++ ++ dev_dbg(dev, "key nums %d\n", key_nums); ++ ret = of_property_read_u32_array(np, ++ "touchscreen-key-map", key_map, ++ key_nums); ++ if (ret) { ++ dev_err(dev, "Unable to read key codes\n"); ++ pdata->key_nums = 0; ++ memset(pdata->key_map, 0, ++ MAX_KEY_NUMS * sizeof(pdata->key_map[0])); ++ } ++ pdata->key_nums = key_nums; ++ memcpy(pdata->key_map, key_map, ++ key_nums * sizeof(pdata->key_map[0])); ++ dev_info(dev, "key-map is [%x %x %x %x]\n", ++ pdata->key_map[0], pdata->key_map[1], ++ pdata->key_map[2], pdata->key_map[3]); ++ } ++ ++ pdata->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0); ++ if (!gpio_is_valid(pdata->irq_gpio)) ++ dev_err(dev, "No valid irq gpio"); ++ ++ pdata->rst_gpio = of_get_named_gpio(np, "reset-gpios", 0); ++ if (!gpio_is_valid(pdata->rst_gpio)) ++ dev_err(dev, "No valid rst gpio"); ++ ++ return 0; ++} ++ ++/******************************************************* ++ * Function: ++ * parse config data from devices tree. ++ * Input: ++ * dev: device that this driver attached. ++ * cfg: pointer of the config array. ++ * cfg_len: pointer of the config length. ++ * sid: sensor id. ++ * Output: ++ * Executive outcomes. ++ * 0-succeed, -1-faileds. ++ *******************************************************/ ++int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid) ++{ ++ struct device_node *np = dev->of_node; ++ struct property *prop; ++ char cfg_name[18]; ++ int ret; ++ ++ snprintf(cfg_name, sizeof(cfg_name), "goodix,cfg-group%d", sid); ++ prop = of_find_property(np, cfg_name, cfg_len); ++ ++ if (!prop || !prop->value || *cfg_len == 0 || ++ *cfg_len > GTP_CONFIG_MAX_LENGTH) { ++ *cfg_len = 0; ++ ret = -EPERM;/* failed */ ++ } else { ++ memcpy(cfg, prop->value, *cfg_len); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++#endif ++ ++static int gtp_power_on(struct goodix_ts_data *ts) ++{ ++ int ret = 0; ++ ++ if (ts->vdd_ana) { ++ ret = regulator_enable(ts->vdd_ana); ++ if (ret) { ++ dev_err(&ts->client->dev, ++ "Regulator vdd enable failed ret=%d\n", ++ ret); ++ goto err_enable_vdd_ana; ++ } ++ } ++ ++ if (ts->vcc_i2c) { ++ ret = regulator_enable(ts->vcc_i2c); ++ if (ret) { ++ dev_err(&ts->client->dev, ++ "Regulator vcc_i2c enable failed ret=%d\n", ++ ret); ++ goto err_enable_vcc_i2c; ++ } ++ } ++ clear_bit(POWER_OFF_MODE, &ts->flags); ++ return 0; ++ ++err_enable_vcc_i2c: ++ if (ts->vdd_ana) ++ regulator_disable(ts->vdd_ana); ++err_enable_vdd_ana: ++ set_bit(POWER_OFF_MODE, &ts->flags); ++ return ret; ++} ++ ++static int gtp_power_off(struct goodix_ts_data *ts) ++{ ++ int ret = 0; ++ ++ if (ts->vcc_i2c) { ++ set_bit(POWER_OFF_MODE, &ts->flags); ++ ret = regulator_disable(ts->vcc_i2c); ++ if (ret) { ++ dev_err(&ts->client->dev, ++ "Regulator vcc_i2c disable failed ret=%d\n", ++ ret); ++ goto err_disable_vcc_i2c; ++ } ++ dev_info(&ts->client->dev, ++ "Regulator vcc_i2c disabled\n"); ++ } ++ ++ if (ts->vdd_ana) { ++ set_bit(POWER_OFF_MODE, &ts->flags); ++ ret = regulator_disable(ts->vdd_ana); ++ if (ret) { ++ dev_err(&ts->client->dev, ++ "Regulator vdd disable failed ret=%d\n", ++ ret); ++ goto err_disable_vdd_ana; ++ } ++ dev_info(&ts->client->dev, ++ "Regulator vdd_ana disabled\n"); ++ } ++ return ret; ++ ++err_disable_vdd_ana: ++ if (ts->vcc_i2c) ++ ret = regulator_enable(ts->vcc_i2c); ++err_disable_vcc_i2c: ++ clear_bit(POWER_OFF_MODE, &ts->flags); ++ return ret; ++} ++ ++static int gtp_power_init(struct goodix_ts_data *ts) ++{ ++ int ret; ++ ++ ts->vdd_ana = regulator_get(&ts->client->dev, "vdd_ana"); ++ if (IS_ERR(ts->vdd_ana)) { ++ ts->vdd_ana = NULL; ++ ret = PTR_ERR(ts->vdd_ana); ++ dev_info(&ts->client->dev, ++ "Regulator get failed vdd ret=%d\n", ret); ++ } ++ ++ ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc_i2c"); ++ if (IS_ERR(ts->vcc_i2c)) { ++ ts->vcc_i2c = NULL; ++ ret = PTR_ERR(ts->vcc_i2c); ++ dev_info(&ts->client->dev, ++ "Regulator get failed vcc_i2c ret=%d\n", ret); ++ } ++ return 0; ++} ++ ++static int gtp_power_deinit(struct goodix_ts_data *ts) ++{ ++ if (ts->vdd_ana) ++ regulator_put(ts->vdd_ana); ++ if (ts->vcc_i2c) ++ regulator_put(ts->vcc_i2c); ++ ++ return 0; ++} ++ ++static void gtp_shutdown(struct i2c_client *client) ++{ ++ struct goodix_ts_data *data = i2c_get_clientdata(client); ++ ++ if (!data->init_done) ++ return; ++ ++ gtp_work_control_enable(data, false); ++ gtp_power_off(data); ++ ++ return; ++} ++ ++static int gtp_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ int ret = -1; ++ struct goodix_ts_data *ts; ++ struct goodix_ts_platform_data *pdata; ++ ++ /* do NOT remove these logs */ ++ dev_info(&client->dev, "GTP Driver Version: %s\n", GTP_DRIVER_VERSION); ++ dev_info(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr); ++ ++ i2c_connect_client = client; ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ dev_err(&client->dev, "Failed check I2C functionality"); ++ return -ENODEV; ++ } ++ ++ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); ++ if (!ts) { ++ dev_err(&client->dev, "Failed alloc ts memory"); ++ return -ENOMEM; ++ } ++ ++ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) { ++ dev_err(&client->dev, "Failed alloc pdata memory\n"); ++ devm_kfree(&client->dev, ts); ++ return -EINVAL; ++ } ++ ++ ts->init_done = false; ++ ++#ifdef CONFIG_OF ++ if (client->dev.of_node) { ++ ret = gtp_parse_dt(&client->dev, pdata); ++ if (ret) { ++ dev_err(&client->dev, "Failed parse dts\n"); ++ goto exit_free_client_data; ++ } ++ } ++#else ++ /* set parameters at here if you platform doesn't DTS */ ++ pdata->rst_gpio = GTP_RST_PORT; ++ pdata->irq_gpio = GTP_INT_PORT; ++ pdata->slide_wakeup = false; ++ pdata->auto_update = true; ++ pdata->auto_update_cfg = false; ++ pdata->type_a_report = false; ++ pdata->esd_protect = false; ++ pdata->max_touch_id = GTP_MAX_TOUCH_ID; ++ pdata->abs_size_x = GTP_DEFAULT_MAX_X; ++ pdata->abs_size_y = GTP_DEFAULT_MAX_Y; ++ pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH; ++ pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE; ++#endif ++ ++ ts->client = client; ++ ts->pdata = pdata; ++ ++ i2c_set_clientdata(client, ts); ++ ++ ret = gtp_power_init(ts); ++ if (ret) { ++ dev_err(&client->dev, "Failed get regulator\n"); ++ ret = -EINVAL; ++ goto exit_free_client_data; ++ } ++ ++ ret = gtp_power_on(ts); ++ if (ret) { ++ dev_err(&client->dev, "Failed power on device\n"); ++ ret = -EINVAL; ++ goto exit_deinit_power; ++ } ++ ++ ret = gtp_pinctrl_init(ts); ++ if (ret < 0) { ++ /* if define pinctrl must define the following state ++ * to let int-pin work normally: default, int_output_high, ++ * int_output_low, int_input ++ */ ++ dev_err(&client->dev, "Failed get wanted pinctrl state\n"); ++ goto exit_deinit_power; ++ } ++ ++ ret = gtp_request_io_port(ts); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed request IO port\n"); ++ goto exit_power_off; ++ } ++ ++ gtp_reset_guitar(ts->client, 20); ++ ++ /* During the first initialization, the input status is configured ++ * to ensure that no abnormal interrupt will be triggered when the ++ * screen is not connected. ++ */ ++ pinctrl_select_state(ts->pinctrl.pinctrl, ts->pinctrl.default_sta); ++ ++ ret = gtp_i2c_test(client); ++ if (ret) { ++ dev_err(&client->dev, "Failed communicate with IC use I2C\n"); ++ goto exit_free_io_port; ++ } ++ ++ dev_info(&client->dev, "I2C Addr is %x\n", client->addr); ++ ++ ret = gtp_get_fw_info(client, &ts->fw_info); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed read FW version\n"); ++ goto exit_free_io_port; ++ } ++ ++ pdata->config.data[0] = GTP_REG_CONFIG_DATA >> 8; ++ pdata->config.data[1] = GTP_REG_CONFIG_DATA & 0xff; ++ ret = gtp_init_panel(ts); ++ if (ret < 0) ++ dev_info(&client->dev, "Panel un-initialize\n"); ++ ++#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE ++ if (ts->pdata->auto_update) { ++ ret = gup_init_update_proc(ts); ++ if (ret < 0) ++ dev_err(&client->dev, "Failed create update thread\n"); ++ } ++#endif ++ ret = gtp_request_input_dev(ts); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed request input device\n"); ++ goto exit_power_off; ++ } ++ mutex_init(&ts->lock); ++ ret = gtp_request_irq(ts); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed create work thread"); ++ goto exit_unreg_input_dev; ++ } ++ ++ gtp_work_control_enable(ts, false); ++ if (ts->pdata->slide_wakeup) { ++ dev_info(&client->dev, "slide wakeup enabled\n"); ++ ret = enable_irq_wake(client->irq); ++ if (ret < 0) ++ dev_err(&client->dev, "Failed set irq wake\n"); ++ } ++ ++ gtp_register_powermanager(ts); ++ ++ ret = gtp_create_file(ts); ++ if (ret) { ++ dev_info(&client->dev, "Failed create attributes file"); ++ goto exit_powermanager; ++ } ++ ++#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL ++ init_wr_node(client);/*TODO judge return value */ ++#endif ++ ++ gtp_esd_init(ts); ++ gtp_esd_on(ts); ++ /* probe init finished */ ++ ts->init_done = true; ++ gtp_work_control_enable(ts, true); ++ ++ return 0; ++ ++exit_powermanager: ++ gtp_unregister_powermanager(ts); ++exit_unreg_input_dev: ++ input_unregister_device(ts->input_dev); ++exit_free_io_port: ++ if (gpio_is_valid(ts->pdata->rst_gpio)) ++ gpio_free(ts->pdata->rst_gpio); ++ if (gpio_is_valid(ts->pdata->irq_gpio)) ++ gpio_free(ts->pdata->irq_gpio); ++exit_power_off: ++ gtp_power_off(ts); ++ gtp_pinctrl_deinit(ts); ++exit_deinit_power: ++ gtp_power_deinit(ts); ++exit_free_client_data: ++ devm_kfree(&client->dev, pdata); ++ devm_kfree(&client->dev, ts); ++ i2c_set_clientdata(client, NULL); ++ ++ return ret; ++} ++ ++static int gtp_drv_remove(struct i2c_client *client) ++{ ++ struct goodix_ts_data *ts = i2c_get_clientdata(client); ++ ++ gtp_work_control_enable(ts, false); ++ gtp_unregister_powermanager(ts); ++ ++ remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc); ++ ++ sysfs_remove_group(&client->dev.kobj, >p_attr_group); ++ ++#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL ++ uninit_wr_node(); ++#endif ++ ++ if (ts->pdata->esd_protect) ++ gtp_esd_off(ts); ++ ++ /* TODO: how to judge a irq numbers validity */ ++ if (ts->client->irq) ++ free_irq(client->irq, ts); ++ else ++ hrtimer_cancel(&ts->timer); ++ ++ if (gpio_is_valid(ts->pdata->rst_gpio)) ++ gpio_free(ts->pdata->rst_gpio); ++ ++ if (gpio_is_valid(ts->pdata->irq_gpio)) ++ gpio_free(ts->pdata->irq_gpio); ++ ++ gtp_power_off(ts); ++ gtp_power_deinit(ts); ++ gtp_pinctrl_deinit(ts); ++ dev_info(&client->dev, "goodix ts driver removed"); ++ i2c_set_clientdata(client, NULL); ++ input_unregister_device(ts->input_dev); ++ mutex_destroy(&ts->lock); ++ ++ devm_kfree(&client->dev, ts->pdata); ++ devm_kfree(&client->dev, ts); ++ ++ return 0; ++} ++ ++static void gtp_suspend(struct goodix_ts_data *ts) ++{ ++ int ret = -1; ++ ++ if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) { ++ dev_warn(&ts->client->dev, ++ "Fw upgrade in progress, can't go to suspend\n"); ++ return; ++ } ++ ++ if (test_and_set_bit(SLEEP_MODE, &ts->flags)) { ++ dev_info(&ts->client->dev, "Already in suspend state\n"); ++ return; ++ } ++ ++ dev_dbg(&ts->client->dev, "Try enter suspend mode\n"); ++ ++ gtp_esd_off(ts); ++ gtp_work_control_enable(ts, false); ++ if (ts->pdata->slide_wakeup) { ++ ret = gtp_enter_doze(ts); ++ gtp_work_control_enable(ts, true); ++ } else if (ts->pdata->power_off_sleep) { ++ /*TODO: power off routine */ ++ gtp_power_off(ts); ++ ret = SUCCESS; ++ } else { ++ ret = gtp_enter_sleep(ts); ++ } ++ ++ if (ret < 0) ++ dev_err(&ts->client->dev, "Failed enter suspend\n"); ++ ++ /* to avoid waking up while not sleeping */ ++ /* delay 48 + 10ms to ensure reliability */ ++ msleep(GTP_58_DLY_MS); ++} ++ ++static int gtp_gesture_wakeup(struct goodix_ts_data *ts) ++{ ++ int ret; ++ int retry = 10; ++ ++ do { ++ gtp_reset_guitar(ts->client, 10); ++ ret = gtp_i2c_test(ts->client); ++ if (!ret) ++ break; ++ } while (--retry); ++ ++ if (!retry) ++ ret = -EIO; ++ ++ clear_bit(DOZE_MODE, &ts->flags); ++ return ret; ++} ++ ++static void gtp_resume(struct goodix_ts_data *ts) ++{ ++ int ret = 0; ++ ++ if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) { ++ dev_info(&ts->client->dev, ++ "Fw upgrade in progress, can't do resume\n"); ++ return; ++ } ++ ++ if (!test_bit(SLEEP_MODE, &ts->flags)) { ++ dev_dbg(&ts->client->dev, "Already in awake state\n"); ++ return; ++ } ++ ++ dev_info(&ts->client->dev, "Try resume from sleep mode\n"); ++ ++ gtp_work_control_enable(ts, false); ++ ++ if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) { ++ ret = gtp_gesture_wakeup(ts); ++ if (ret) ++ dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n"); ++ } else if (ts->pdata->power_off_sleep) { ++ ret = gtp_power_on(ts); ++ if (ret) { ++ dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n"); ++ } else { ++ gtp_reset_guitar(ts->client, 20); ++ ret = gtp_i2c_test(ts->client); ++ if (ret) ++ dev_warn(&ts->client->dev, ++ "I2C communicate failed after power on\n"); ++ } ++ } else { ++ gtp_reset_guitar(ts->client, 20); ++ ret = gtp_wakeup_sleep(ts); ++ if (ret) ++ dev_warn(&ts->client->dev, ++ "Failed wakeup from sleep mode\n"); ++ } ++ ++ if (ret) ++ dev_warn(&ts->client->dev, "Later resume failed\n"); ++ else ++ gtp_esd_on(ts); ++ ++ clear_bit(SLEEP_MODE, &ts->flags); ++ gtp_work_control_enable(ts, true); ++} ++#if 0 ++#if defined(CONFIG_FB) ++static void fb_notify_resume_work(struct work_struct *work) ++{ ++ struct goodix_ts_data *ts = ++ container_of(work, struct goodix_ts_data, fb_notify_work); ++ dev_info(&ts->client->dev, "try resume in workqueue\n"); ++ gtp_resume(ts); ++} ++ ++/* frame buffer notifier block control the suspend/resume procedure */ ++static int gtp_fb_notifier_callback(struct notifier_block *noti, ++ unsigned long event, void *data) ++{ ++ struct fb_event *ev_data = data; ++ struct goodix_ts_data *ts = container_of(noti, ++ struct goodix_ts_data, notifier); ++ int *blank; ++ ++ if (ev_data && ev_data->data && event == FB_EVENT_BLANK && ts) { ++ blank = ev_data->data; ++ if (*blank == FB_BLANK_UNBLANK || ++ *blank == FB_BLANK_NORMAL) { ++ dev_dbg(&ts->client->dev, "ts_resume"); ++ if (ts->pdata->resume_in_workqueue) ++ schedule_work(&ts->fb_notify_work); ++ else ++ gtp_resume(ts); ++ } else if (*blank == FB_BLANK_POWERDOWN) { ++ dev_dbg(&ts->client->dev, "ts_suspend"); ++ if (ts->pdata->resume_in_workqueue) ++ flush_work(&ts->fb_notify_work); ++ gtp_suspend(ts); ++ } ++ } ++ ++ return 0; ++} ++ ++#endif ++#endif ++ ++#if defined(CONFIG_PM) ++static int gtp_pm_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct goodix_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (ts) { ++ dev_dbg(&ts->client->dev, "Suspend by i2c pm."); ++ gtp_suspend(ts); ++ } ++ ++ return 0; ++} ++ ++static int gtp_pm_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct goodix_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (ts) { ++ dev_dbg(&ts->client->dev, "Resume by i2c pm."); ++ gtp_resume(ts); ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops gtp_pm_ops = { ++ .suspend = gtp_pm_suspend, ++ .resume = gtp_pm_resume, ++}; ++ ++#elif defined(CONFIG_HAS_EARLYSUSPEND) ++static void gtp_early_suspend(struct early_suspend *h) ++{ ++ struct goodix_ts_data *ts = container_of(h, ++ struct goodix_ts_data, early_suspend); ++ ++ if (ts) { ++ dev_dbg(&ts->client->dev, "Suspend by earlysuspend module."); ++ gtp_suspend(ts); ++ } ++} ++ ++static void gtp_late_resume(struct early_suspend *h) ++{ ++ struct goodix_ts_data *ts = container_of(h, ++ struct goodix_ts_data, early_suspend); ++ ++ if (ts) { ++ dev_dbg(&ts->client->dev, "Resume by earlysuspend module."); ++ gtp_resume(ts); ++ } ++} ++#endif ++ ++static int gtp_register_powermanager(struct goodix_ts_data *ts) ++{ ++ int ret; ++#if defined(CONFIG_FB) ++/* INIT_WORK(&ts->fb_notify_work, fb_notify_resume_work); ++ ts->notifier.notifier_call = gtp_fb_notifier_callback; ++ ret = fb_register_client(&ts->notifier); ++ if (ret) ++ dev_err(&ts->client->dev, ++ "Unable to register fb_notifier: %d\n", ret); ++*/ ++#elif defined(CONFIG_HAS_EARLYSUSPEND) ++ ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; ++ ts->early_suspend.suspend = goodix_ts_early_suspend; ++ ts->early_suspend.resume = goodix_ts_late_resume; ++ register_early_suspend(&ts->early_suspend); ++#endif ++ ++ return ret; ++} ++ ++static int gtp_unregister_powermanager(struct goodix_ts_data *ts) ++{ ++#if defined(CONFIG_FB) ++ fb_unregister_client(&ts->notifier); ++#elif defined(CONFIG_HAS_EARLYSUSPEND) ++ unregister_early_suspend(&ts->early_suspend); ++#endif ++ ++ return 0; ++} ++ ++/******************************************************* ++ * Function: ++ * Initialize external watchdog for esd protect ++ * Input: ++ * client: i2c device. ++ * Output: ++ * result of i2c write operation. ++ * 0: succeed, otherwise: failed ++ ********************************************************/ ++static int gtp_init_ext_watchdog(struct i2c_client *client) ++{ ++ int ret; ++ u8 opr_buffer[3] = { (u8)(GTP_REG_ESD_CHECK >> 8), ++ (u8)GTP_REG_ESD_CHECK, ++ (u8)GTP_ESD_CHECK_VALUE }; ++ ++ dev_dbg(&client->dev, "[Esd]Init external watchdog\n"); ++ ret = gtp_i2c_write(client, opr_buffer, 3); ++ if (ret == 1) ++ return 0; ++ ++ dev_err(&client->dev, "Failed init ext watchdog\n"); ++ return -EINVAL; ++} ++ ++static void gtp_esd_check_func(struct work_struct *work) ++{ ++ s32 i; ++ s32 ret = -1; ++ u8 esd_buf[5] = { (u8)(GTP_REG_COMMAND >> 8), (u8)GTP_REG_COMMAND }; ++ struct delayed_work *dwork = to_delayed_work(work); ++ struct goodix_ts_esd *ts_esd = container_of(dwork, struct goodix_ts_esd, ++ delayed_work); ++ struct goodix_ts_data *ts = container_of(ts_esd, struct goodix_ts_data, ++ ts_esd); ++ ++ if (test_bit(SLEEP_MODE, &ts->flags) || ++ test_bit(FW_UPDATE_RUNNING, &ts->flags)) { ++ dev_dbg(&ts->client->dev, ++ "Esd cancled by power_suspend or fw_update!"); ++ return; ++ } ++ ++ if (ts_esd->esd_on == false) ++ return; ++ ++ for (i = 0; i < 3; i++) { ++ ret = gtp_i2c_read(ts->client, esd_buf, 4); ++ if (ret < 0) ++ continue; ++ ++ dev_dbg(&ts->client->dev, ++ "[Esd]0x8040 = 0x%02X, 0x8041 = 0x%02X", ++ esd_buf[2], esd_buf[3]); ++ if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE || ++ esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) { ++ gtp_i2c_read(ts->client, esd_buf, 4); ++ if (ret < 0) ++ continue; ++ ++ if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE || ++ esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) { ++ i = 3; ++ break; ++ } ++ } else { ++ /* IC works normally, Write 0x8040 0xAA, feed the dog */ ++ esd_buf[2] = (u8)GTP_ESD_CHECK_VALUE; ++ gtp_i2c_write(ts->client, esd_buf, 3); ++ break; ++ } ++ } ++ if (i >= 3) { ++ dev_err(&ts->client->dev, "IC working abnormally! Reset IC\n"); ++ esd_buf[0] = 0x42; ++ esd_buf[1] = 0x26; ++ esd_buf[2] = 0x01; ++ esd_buf[3] = 0x01; ++ esd_buf[4] = 0x01; ++ gtp_i2c_write(ts->client, esd_buf, 5); ++ /* TODO: Is power off really need? */ ++ msleep(GTP_50_DLY_MS); ++ gtp_power_off(ts); ++ msleep(GTP_20_DLY_MS); ++ gtp_power_on(ts); ++ msleep(GTP_20_DLY_MS); ++ ++ gtp_reset_guitar(ts->client, 50); ++ msleep(GTP_50_DLY_MS); ++ gtp_send_cfg(ts->client); ++ } ++ ++ if (ts_esd->esd_on == true && !test_bit(SLEEP_MODE, &ts->flags)) { ++ schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ); ++ dev_dbg(&ts->client->dev, "ESD work rescheduled\n"); ++ } ++} ++ ++static int gtp_esd_init(struct goodix_ts_data *ts) ++{ ++ struct goodix_ts_esd *ts_esd = &ts->ts_esd; ++ ++ INIT_DELAYED_WORK(&ts_esd->delayed_work, gtp_esd_check_func); ++ mutex_init(&ts_esd->mutex); ++ ts_esd->esd_on = false; ++ ++ return 0; ++} ++ ++void gtp_esd_on(struct goodix_ts_data *ts) ++{ ++ struct goodix_ts_esd *ts_esd = &ts->ts_esd; ++ ++ if (!ts->pdata->esd_protect) ++ return; ++ mutex_lock(&ts_esd->mutex); ++ if (ts_esd->esd_on == false) { ++ ts_esd->esd_on = true; ++ schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ); ++ dev_info(&ts->client->dev, "ESD on"); ++ } ++ mutex_unlock(&ts_esd->mutex); ++} ++ ++void gtp_esd_off(struct goodix_ts_data *ts) ++{ ++ struct goodix_ts_esd *ts_esd = &ts->ts_esd; ++ ++ if (!ts->pdata->esd_protect) ++ return; ++ mutex_lock(&ts_esd->mutex); ++ if (ts_esd->esd_on == true) { ++ ts_esd->esd_on = false; ++ cancel_delayed_work_sync(&ts_esd->delayed_work); ++ dev_info(&ts->client->dev, "ESD off"); ++ } ++ mutex_unlock(&ts_esd->mutex); ++} ++ ++#ifdef CONFIG_OF ++static const struct of_device_id gtp_match_table[] = { ++ {.compatible = "goodix,gt9xx",}, ++ { }, ++}; ++#endif ++ ++static const struct i2c_device_id gtp_device_id[] = { ++ { GTP_I2C_NAME, 0 }, ++ { } ++}; ++ ++static struct i2c_driver goodix_ts_driver = { ++ .probe = gtp_probe, ++ .remove = gtp_drv_remove, ++ .id_table = gtp_device_id, ++ .shutdown = gtp_shutdown, ++ .driver = { ++ .name = GTP_I2C_NAME, ++ .owner = THIS_MODULE, ++#ifdef CONFIG_OF ++ .of_match_table = gtp_match_table, ++#endif ++#if defined(CONFIG_PM) ++ .pm = >p_pm_ops, ++#endif ++ }, ++}; ++ ++static int __init gtp_init(void) ++{ ++ s32 ret; ++ ++ pr_info("Gt9xx driver installing..\n"); ++ ret = i2c_add_driver(&goodix_ts_driver); ++ ++ return ret; ++} ++ ++static void __exit gtp_exit(void) ++{ ++ pr_info("Gt9xx driver exited\n"); ++ i2c_del_driver(&goodix_ts_driver); ++} ++ ++module_init(gtp_init); ++module_exit(gtp_exit); ++ ++MODULE_DESCRIPTION("GT9 serials touch controller Driver"); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx.h b/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx.h +new file mode 100644 +index 000000000..2e1c66587 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx.h +@@ -0,0 +1,384 @@ ++/* ++ * Goodix GT9xx touchscreen driver ++ * ++ * Copyright (C) 2016 - 2017 Goodix. Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be a reference ++ * to you, when you are integrating the GOODiX's CTP IC into your system, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * Version: 2.8.0.2 ++ * Release Date: 2017/12/14 ++ */ ++ ++#ifndef _GOODIX_GT9XX_H_ ++#define _GOODIX_GT9XX_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_OF ++#include ++#endif ++#ifdef CONFIG_FB ++#include ++#include ++#endif ++#ifdef CONFIG_HAS_EARLYSUSPEND ++#include ++#endif ++#include ++#include ++ ++#define GTP_TOOL_PEN 1 ++#define GTP_TOOL_FINGER 2 ++ ++#define MAX_KEY_NUMS 4 ++#define GTP_CONFIG_MAX_LENGTH 240 ++#define GTP_ADDR_LENGTH 2 ++ ++/***************************PART1:ON/OFF define*******************************/ ++#define GTP_DEBUG_ON 1 ++#define GTP_DEBUG_ARRAY_ON 0 ++#define GTP_DEBUG_FUNC_ON 0 ++ ++struct goodix_point_t { ++ int id; ++ int x; ++ int y; ++ int w; ++ int p; ++ int tool_type; ++}; ++ ++struct goodix_config_data { ++ int length; ++ u8 data[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]; ++}; ++ ++struct goodix_ts_platform_data { ++ int irq_gpio; ++ int rst_gpio; ++ u32 irq_flags; ++ u32 abs_size_x; ++ u32 abs_size_y; ++ u32 max_touch_id; ++ u32 max_touch_width; ++ u32 max_touch_pressure; ++ u32 key_map[MAX_KEY_NUMS]; ++ u32 key_nums; ++ u32 int_sync; ++ u32 driver_send_cfg; ++ u32 swap_x2y; ++ u32 slide_wakeup; ++ u32 auto_update; ++ u32 auto_update_cfg; ++ u32 esd_protect; ++ u32 type_a_report; ++ u32 power_off_sleep; ++ u32 resume_in_workqueue; ++ u32 pen_suppress_finger; ++ struct goodix_config_data config; ++}; ++ ++struct goodix_ts_esd { ++ struct delayed_work delayed_work; ++ struct mutex mutex; ++ bool esd_on; ++}; ++ ++enum { ++ WORK_THREAD_ENABLED = 0, ++ HRTIMER_USED, ++ FW_ERROR, ++ ++ DOZE_MODE, ++ SLEEP_MODE, ++ POWER_OFF_MODE, ++ RAW_DATA_MODE, ++ ++ FW_UPDATE_RUNNING, ++ PANEL_RESETTING ++}; ++ ++struct goodix_pinctrl { ++ struct pinctrl *pinctrl; ++ struct pinctrl_state *default_sta; ++ struct pinctrl_state *int_out_high; ++ struct pinctrl_state *int_out_low; ++ struct pinctrl_state *int_input; ++}; ++ ++struct goodix_fw_info { ++ u8 pid[6]; ++ u16 version; ++ u8 sensor_id; ++}; ++ ++struct goodix_ts_data { ++ unsigned long flags; /* This member record the device status */ ++ ++ struct goodix_ts_esd ts_esd; ++ struct i2c_client *client; ++ struct input_dev *input_dev; ++ struct input_dev *pen_dev; ++ struct goodix_ts_platform_data *pdata; ++ /* use pinctrl control int-pin output low or high */ ++ struct goodix_pinctrl pinctrl; ++ struct hrtimer timer; ++ struct mutex lock; ++ struct notifier_block ps_notif; ++ struct regulator *vdd_ana; ++ struct regulator *vcc_i2c; ++#if defined(CONFIG_FB) ++ struct notifier_block notifier; ++ struct work_struct fb_notify_work; ++#elif defined(CONFIG_HAS_EARLYSUSPEND) ++ struct early_suspend early_suspend; ++#endif ++ struct goodix_fw_info fw_info; ++ bool force_update; ++ bool init_done; ++}; ++ ++/************************* PART2:TODO define *******************************/ ++/* STEP_1(REQUIRED): Define Configuration Information Group(s) ++ Sensor_ID Map: ++ sensor_opt1 sensor_opt2 Sensor_ID ++ GND GND 0 ++ VDDIO GND 1 ++ NC GND 2 ++ GND NC/300K 3 ++ VDDIO NC/300K 4 ++ NC NC/300K 5 ++*/ ++/* TODO: define your own default or for Sensor_ID == 0 config here. ++ The predefined one is just a sample config, ++ which is not suitable for your tp in most cases. */ ++#define CTP_CFG_GROUP0 {\ ++ 0x41, 0xD0, 0x02, 0x00, 0x05, 0x0A, 0x34, \ ++ 0x00, 0x01, 0x08, 0x28, 0x05, 0x50, 0x32, \ ++ 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x17, 0x19, 0x1E, 0x14, 0x8C, \ ++ 0x2D, 0x0E, 0x3C, 0x3E, 0x82, 0x0A, 0x82, \ ++ 0x0A, 0x00, 0x99, 0x33, 0x1D, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x2B, 0x19, 0x64, 0x94, 0xC0, 0x02, \ ++ 0x08, 0x00, 0x00, 0x04, 0xF2, 0x1C, 0x00, \ ++ 0xB9, 0x26, 0x00, 0x93, 0x32, 0x00, 0x77, \ ++ 0x42, 0x00, 0x62, 0x57, 0x00, 0x62, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0xFF, 0x65, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x19, 0x46, 0x00, 0x00, 0x00, 0x00, 0x32, \ ++ 0x1C, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, \ ++ 0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x08, \ ++ 0x0A, 0x0C, 0x0F, 0x10, 0x12, 0x13, 0x14, \ ++ 0x18, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, \ ++ 0x22, 0x24, 0x26, 0x28, 0x29, 0x2A, 0xFF, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0xB8, 0x01\ ++} ++ ++/* TODO: define your config for Sensor_ID == 1 here, if needed */ ++#define CTP_CFG_GROUP1 {\ ++} ++ ++/* TODO: define your config for Sensor_ID == 2 here, if needed */ ++#define CTP_CFG_GROUP2 {\ ++} ++ ++/* TODO: define your config for Sensor_ID == 3 here, if needed */ ++#define CTP_CFG_GROUP3 {\ ++} ++/* TODO: define your config for Sensor_ID == 4 here, if needed */ ++#define CTP_CFG_GROUP4 {\ ++ 0x53,0xD0,0x02,0x00,0x05,0x05,0xF5,0xD5,0x21,0x48,0x2D,0x0F,\ ++ 0x5A,0x41,0x0E,0x05,0x00,0x00,0x32,0x32,0x20,0x00,0x05,0x14,\ ++ 0x14,0x1A,0x14,0x8B,0x2B,0x0C,0xB5,0xB7,0xEB,0x04,0xFF,0xFE,\ ++ 0x00,0x22,0x33,0x10,0x3C,0x80,0x00,0x00,0x00,0x1E,0x12,0x41,\ ++ 0x23,0x12,0x5A,0xAA,0xBE,0x4A,0x55,0x04,0x00,0x14,0x19,0x04,\ ++ 0x80,0xAB,0x00,0x7F,0xAF,0x64,0x7E,0xB3,0x00,0x7E,0xB7,0x00,\ ++ 0x7B,0xBB,0x3C,0x7B,0x08,0x30,0x00,0x00,0xF8,0x70,0x50,0xFF,\ ++ 0xFF,0x17,0x00,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,\ ++ 0x08,0x46,0x80,0x08,0x0A,0x00,0xA0,0x00,0x3C,0x28,0x19,0x19,\ ++ 0x80,0x11,0x00,0x00,0x18,0x16,0x14,0x12,0x10,0x0E,0x0C,0x0A,\ ++ 0x08,0x06,0x04,0x02,0xFF,0xFF,0x28,0x00,0x32,0x20,0x00,0x06,\ ++ 0x00,0x00,0x0A,0x06,0x10,0x08,0x0A,0x22,0xEB,0x04,0x26,0x24,\ ++ 0x22,0x21,0x20,0x1F,0x1E,0x1D,0x1C,0x18,0x16,0x12,0x10,0x0F,\ ++ 0x0C,0x0A,0x08,0x06,0x04,0x02,0x00,0x13,0xFF,0xFF,0xFF,0xFF,\ ++ 0x00,0x00,0x00,0x02,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,\ ++ 0x00,0x00,0x00,0x00,0x28,0x0B,0x0B,0x00,0x00,0x00,0x00,0x00,\ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE6,0x10,0xEF,0x01\ ++} ++ ++/* TODO: define your config for Sensor_ID == 5 here, if needed */ ++#define CTP_CFG_GROUP5 {\ ++} ++ ++/* STEP_2(REQUIRED): Customize your I/O ports & I/O operations */ ++#define GTP_RST_PORT 64 /* EXYNOS4_GPX2(0) */ ++#define GTP_INT_PORT 65 /* EXYNOS4_GPX2(1) */ ++ ++#define GTP_GPIO_AS_INPUT(pin) (gpio_direction_input(pin)) ++#define GTP_GPIO_AS_INT(pin) (GTP_GPIO_AS_INPUT(pin)) ++#define GTP_GPIO_GET_VALUE(pin) gpio_get_value(pin) ++#define GTP_GPIO_OUTPUT(pin, level) gpio_direction_output(pin, level) ++#define GTP_GPIO_REQUEST(pin, label) gpio_request(pin, label) ++#define GTP_GPIO_FREE(pin) gpio_free(pin) ++ ++/* STEP_3(optional): Specify your special config info if needed */ ++#define GTP_DEFAULT_MAX_X 720 /* default coordinate max values */ ++#define GTP_DEFAULT_MAX_Y 1080 ++#define GTP_DEFAULT_MAX_WIDTH 1024 ++#define GTP_DEFAULT_MAX_PRESSURE 1024 ++#define GTP_DEFAULT_INT_TRIGGER 1 /* 1 rising, 2 falling */ ++#define GTP_MAX_TOUCH_ID 16 ++ ++/* STEP_4(optional): If keys are available and reported as keys, ++config your key info here */ ++#define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK, KEY_HOMEPAGE, \ ++ KEY_F1, KEY_F2, KEY_F3} ++ ++/**************************PART3:OTHER define*******************************/ ++#define GTP_DRIVER_VERSION "V2.8.0.2<2017/12/14>" ++#define GTP_I2C_NAME "goodix-ts" ++#define GT91XX_CONFIG_PROC_FILE "gt9xx_config" ++#define GTP_POLL_TIME 10 ++#define GTP_CONFIG_MIN_LENGTH 186 ++#define GTP_ESD_CHECK_VALUE 0xAA ++#define RETRY_MAX_TIMES 5 ++#define PEN_TRACK_ID 9 ++#define MASK_BIT_8 0x80 ++#define FAIL 0 ++#define SUCCESS 1 ++ ++/* Registers define */ ++#define GTP_REG_COMMAND 0x8040 ++#define GTP_REG_ESD_CHECK 0x8041 ++#define GTP_REG_COMMAND_CHECK 0x8046 ++#define GTP_REG_CONFIG_DATA 0x8047 ++#define GTP_REG_VERSION 0x8140 ++#define GTP_REG_SENSOR_ID 0x814A ++#define GTP_REG_DOZE_BUF 0x814B ++#define GTP_READ_COOR_ADDR 0x814E ++ ++/* Sleep time define */ ++#define GTP_1_DLY_MS 1 ++#define GTP_2_DLY_MS 2 ++#define GTP_10_DLY_MS 10 ++#define GTP_20_DLY_MS 20 ++#define GTP_50_DLY_MS 50 ++#define GTP_58_DLY_MS 58 ++#define GTP_100_DLY_MS 100 ++#define GTP_500_DLY_MS 500 ++#define GTP_1000_DLY_MS 1000 ++#define GTP_3000_DLY_MS 3000 ++ ++#define RESOLUTION_LOC 3 ++#define TRIGGER_LOC 8 ++ ++#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) ++/* Log define */ ++#define GTP_DEBUG(fmt, arg...) \ ++do { \ ++ if (GTP_DEBUG_ON) {\ ++ pr_info("<<-GTP-DEBUG->> [%d]"fmt"\n", __LINE__, ##arg);\ ++ } \ ++} while (0) ++#define GTP_DEBUG_ARRAY(array, num) \ ++do { \ ++ s32 i;\ ++ u8 *a = array;\ ++ if (GTP_DEBUG_ARRAY_ON) {\ ++ pr_warn("<<-GTP-DEBUG-ARRAY->>\n");\ ++ for (i = 0; i < (num); i++) {\ ++ pr_warn("%02x ", (a)[i]);\ ++ if ((i + 1) % 10 == 0) {\ ++ pr_warn("\n");\ ++ } \ ++ } \ ++ pr_warn("\n");\ ++ } \ ++} while (0) ++#define GTP_DEBUG_FUNC() \ ++do {\ ++ if (GTP_DEBUG_FUNC_ON) {\ ++ pr_warn("<<-GTP-FUNC->> Func:%s@Line:%d\n", \ ++ __func__, __LINE__);\ ++ } \ ++} while (0) ++#define GTP_SWAP(x, y) \ ++do {\ ++ typeof(x) z = x;\ ++ x = y;\ ++ y = z;\ ++} while (0) ++ ++/******************************End of Part III********************************/ ++#ifdef CONFIG_OF ++extern int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid); ++#endif ++ ++extern void gtp_reset_guitar(struct i2c_client *client, s32 ms); ++extern void gtp_int_sync(struct goodix_ts_data *ts, s32 ms); ++extern void gtp_esd_on(struct goodix_ts_data *ts); ++extern void gtp_esd_off(struct goodix_ts_data *ts); ++extern void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable); ++ ++#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE ++extern u16 show_len; ++extern u16 total_len; ++extern u8 gup_init_update_proc(struct goodix_ts_data *); ++extern s32 gup_update_proc(void *dir); ++extern s32 gup_enter_update_mode(struct i2c_client *client); ++extern void gup_leave_update_mode(struct i2c_client *client); ++#endif ++ ++#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL ++extern s32 init_wr_node(struct i2c_client *); ++extern void uninit_wr_node(void); ++#endif ++ ++/*********** For gt9xx_update Start *********/ ++extern struct i2c_client *i2c_connect_client; ++extern void gtp_reset_guitar(struct i2c_client *client, s32 ms); ++extern void gtp_int_output(struct goodix_ts_data *ts, int level); ++extern s32 gtp_send_cfg(struct i2c_client *client); ++extern s32 gtp_get_fw_info(struct i2c_client *, struct goodix_fw_info *fw_info); ++extern s32 gtp_i2c_read_dbl_check(struct i2c_client *, u16, u8 *, int); ++extern int gtp_i2c_read(struct i2c_client *, u8 *, int); ++extern int gtp_i2c_write(struct i2c_client *, u8 *, int); ++extern s32 gtp_fw_startup(struct i2c_client *client); ++extern int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf); ++/*********** For gt9xx_update End *********/ ++ ++#endif /* _GOODIX_GT9XX_H_ */ +diff --git a/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx_firmware.h b/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx_firmware.h +new file mode 100644 +index 000000000..d8ac62f4f +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx_firmware.h +@@ -0,0 +1,2338 @@ ++/* Copyright Statement: ++*This firmware are protected under relevant copyright laws,this information contained ++*herein is confidential and proprietary to Goodix. ++* ++* Copyright (C) 2010 - 2014 Goodix. Ltd. ++* ++*WARNING:The GTP_COMPATIBLE_MODE part of this file was generated by the specialized tools, ++*please do not modify it manually! ++* ++*/ ++ ++#ifndef _GT9XX_FIRMWARE_H_ ++#define _GT9XX_FIRMWARE_H_ ++ ++#if GTP_HEADER_FW_UPDATE ++unsigned char gtp_default_FW[] = ++{ ++ //TODO:Puts your update firmware data here! ++}; ++#endif ++ ++/* ++*[HW INFO]00900600 ++*[PID]910 ++*[VID]1010 ++*[GENERATED]2013/08/27 20:59:13 ++*/ ++#if GTP_COMPATIBLE_MODE ++unsigned char gtp_default_FW_fl[] = { ++/* 0x00,0x90,0x06,0x00,0x39,0x31,0x30,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x80,0x00, ++ 0x55,0x40,0xf8,0x86,0x98,0x71,0x69,0xf0,0x0c,0xc1,0x78,0x1e,0xd2,0x48,0x88,0x58, ++ 0xa3,0x41,0xd2,0xeb,0xb2,0x63,0x32,0xe0,0x1d,0xc9,0xf8,0x75,0x15,0x6e,0x01,0x8d, ++ 0x05,0x02,0xf9,0x87,0x18,0x7a,0x12,0x6b,0x4d,0x21,0x17,0xd5,0x94,0x6d,0x09,0x0d, ++ 0x87,0x03,0x4f,0xc2,0x13,0x0b,0x09,0x7b,0x4d,0x4b,0xf9,0x74,0x99,0xe8,0x38,0xa8, ++ 0x3d,0xc9,0xa2,0x4d,0x13,0x74,0xab,0x47,0xe3,0xe5,0xee,0x49,0xdf,0xd2,0x00,0x54, ++ 0x8b,0xfb,0x48,0x94,0x1f,0x67,0x8b,0x8e,0xbe,0xe4,0xce,0x59,0x55,0x46,0xbe,0x86, ++ 0x40,0x06,0x98,0xb8,0x77,0xa0,0x85,0x9e,0x2b,0x05,0x99,0xfd,0xb1,0xd4,0xf6,0xb9, ++ 0x40,0x9c,0x50,0x1d,0x4e,0x1a,0x0d,0x82,0xe9,0x9a,0x5d,0x17,0xba,0x86,0x47,0xac, ++ 0x2c,0x48,0x26,0x6e,0x59,0x38,0x10,0xda,0x0f,0x4c,0x15,0xce,0xda,0x40,0x9a,0x3c, ++ 0x2f,0x49,0xd0,0x18,0xba,0x2f,0x20,0x3a,0x55,0x69,0xea,0x5c,0x4f,0x62,0x98,0xcc, ++ 0x0f,0x7a,0xfb,0x8f,0x99,0x52,0x17,0x7d,0x2f,0xb4,0x91,0xcf,0xde,0x32,0x48,0x6c, ++ 0xaf,0x48,0x83,0x51,0xdb,0x24,0x9b,0x29,0xd9,0x49,0xda,0xc2,0x2e,0x29,0xa5,0xcc, ++ 0x28,0x7a,0x6d,0x4e,0x1e,0xd7,0x04,0xc8,0xa1,0x4f,0x8a,0x74,0x39,0x55,0xf0,0xa7, ++ 0xb2,0x61,0xcf,0x1d,0x5d,0xa0,0x5c,0x41,0xa2,0xfc,0x2f,0x1e,0x1b,0x62,0x79,0xa2, ++ 0xb9,0xf5,0x44,0xc9,0xf3,0x59,0x55,0x44,0x82,0x7f,0xc5,0x40,0xdc,0x6d,0xac,0x19, ++ 0x8f,0x26,0xb6,0xb5,0xa4,0xe2,0x03,0xd6,0x83,0xde,0xfb,0x6d,0x93,0x1e,0x04,0x80, ++ 0x78,0xf8,0x88,0x83,0x91,0xba,0x2c,0xc0,0xd0,0x58,0x9c,0xb7,0x63,0x58,0xde,0xb0, ++ 0x26,0xe9,0x6a,0x64,0x85,0x3e,0xe5,0xc2,0xef,0x34,0x5c,0x69,0x02,0xaa,0x4f,0x28, ++ 0x82,0x11,0x7b,0x67,0x32,0x38,0x64,0xd3,0x6e,0x37,0x48,0x25,0xc7,0x77,0x02,0x1d, ++ 0x24,0xe6,0x65,0xb8,0xb7,0x22,0x64,0xc3,0x6f,0x36,0xa8,0x48,0xc1,0x06,0x22,0x10, ++ 0x21,0x5d,0x8e,0x84,0x36,0x1d,0x74,0xa0,0x61,0x4f,0xe4,0x60,0x50,0x10,0x34,0xe2, ++ 0xd7,0x1a,0x06,0x36,0xd3,0xca,0x5c,0xb0,0x79,0xf8,0x4f,0xe7,0x5d,0x84,0x7b,0xe9, ++ 0x6a,0xdc,0xfc,0xb6,0x82,0x92,0x8b,0x97,0x6d,0xd0,0xdd,0xf1,0x3a,0x35,0x16,0xd1, ++ 0xcb,0x3d,0x7e,0x37,0x5a,0x1d,0xca,0xc0,0x42,0xa8,0xe3,0x50,0x9b,0x54,0xc6,0x69, ++ 0x14,0xb3,0x86,0xca,0xc4,0x3e,0x3f,0xfb,0xec,0x44,0xdf,0x82,0x37,0xc3,0x79,0x69, ++ 0x44,0x1c,0x3a,0x8c,0x9a,0x7b,0x66,0x9f,0xf8,0xf5,0x43,0x0c,0x12,0xea,0x37,0x37, ++ 0xc3,0xd3,0x0f,0x21,0x59,0x35,0xbe,0xfa,0x64,0x06,0x68,0x29,0xc1,0x20,0x51,0xfc, ++ 0xcc,0xb0,0x14,0x4a,0x65,0x72,0xbf,0xf3,0x7c,0xf7,0x0c,0x86,0xea,0xee,0x38,0xf1, ++ 0xdb,0xcf,0x1f,0xcc,0x46,0x93,0x68,0xd4,0x44,0x83,0xa8,0x4d,0x93,0x3f,0x5b,0xab, ++ 0x13,0x73,0xdd,0xcf,0x30,0x0c,0xbc,0x70,0x8e,0xd4,0xd8,0xd5,0x33,0xcc,0x39,0xf1, ++ 0x62,0x34,0xd0,0xa3,0xcc,0x91,0xfb,0x96,0xd9,0xd5,0x81,0x4d,0x11,0x7d,0x29,0x1d, ++ 0xa8,0x57,0xf1,0xf4,0x34,0x99,0x7f,0x13,0x1e,0xd6,0xe1,0xc4,0xd8,0x3f,0x20,0x02, ++ 0x04,0xc0,0xff,0x26,0x67,0xa0,0x20,0x62,0xc4,0xc6,0x2f,0xd9,0xb5,0x1f,0x28,0x12, ++ 0x05,0xc1,0x68,0xdf,0xca,0x5c,0x3c,0xb5,0x64,0x56,0x82,0xc9,0xa2,0xa3,0x79,0xfa, ++ 0x84,0x82,0x7e,0x07,0xe3,0xae,0xac,0xd1,0x25,0x19,0x4a,0xa3,0xa1,0x01,0x29,0x8f, ++ 0x85,0x83,0x22,0x77,0xcd,0xa5,0x8d,0xcc,0x86,0x30,0xa7,0x31,0x34,0x5c,0xa5,0xb2, ++ 0x3d,0xb5,0x1f,0x2d,0x9b,0x52,0x50,0xd5,0x0e,0xd5,0xd0,0xb8,0xbf,0x95,0x10,0x39, ++ 0x6f,0x88,0xb6,0xb4,0x57,0x98,0xc2,0x8d,0xc8,0x68,0xbf,0x4f,0x51,0xc6,0xa1,0xe3, ++ 0x39,0x0b,0xe9,0x43,0x1e,0x58,0x7d,0xda,0xf5,0x1d,0xee,0x87,0xd4,0x6d,0x7f,0x31, ++ 0xe7,0x78,0xdb,0x67,0x54,0x08,0xee,0xec,0xa4,0xc3,0x7d,0x04,0xbb,0xe8,0x22,0x0a, ++ 0x0c,0xc8,0xae,0x79,0x7f,0x37,0x62,0x59,0x54,0x42,0x4d,0xd0,0x5a,0x01,0x2a,0x1a, ++ 0x0d,0xc9,0xe7,0x19,0x9d,0xe7,0x8e,0x5a,0x45,0x19,0x65,0x62,0x2e,0xee,0x23,0x96, ++ 0x8c,0x8a,0xdb,0xf2,0x90,0xe8,0xf4,0xd5,0x2d,0xac,0x02,0x0b,0xab,0x5f,0xb6,0xda, ++ 0x8d,0x8b,0x6b,0xfe,0xa1,0xad,0x94,0xeb,0x4c,0x6a,0xe4,0x0b,0x15,0x01,0x1c,0x4c, ++ 0xef,0x0f,0x42,0x3d,0xbd,0x2f,0x0b,0x1b,0x3a,0xda,0x32,0xce,0xec,0x67,0x14,0x77, ++ 0xc7,0xe7,0x95,0x4d,0x10,0xbc,0x2e,0xe8,0x4f,0x60,0xae,0xda,0x3c,0xef,0x93,0xcf, ++ 0xac,0x14,0x04,0xcb,0xbc,0x34,0x7b,0xb2,0x41,0x63,0xf7,0x8d,0x86,0xac,0x7a,0x28, ++ 0xbf,0xe1,0xd5,0x77,0x10,0x09,0x2b,0x0b,0x4f,0x49,0x6c,0x8c,0x5b,0x64,0x01,0x82, ++ 0x4f,0xb4,0xc4,0x84,0x6a,0x1d,0x90,0xec,0xbb,0xed,0x7a,0x5b,0x76,0x2b,0xac,0x92, ++ 0x94,0x1c,0x82,0x12,0x1e,0x43,0x94,0x9f,0x1e,0xc9,0xe5,0x57,0x90,0x0e,0xda,0x87, ++ 0xa4,0xf7,0x3d,0x65,0xb2,0x99,0xde,0xd4,0x64,0x05,0x85,0x23,0xd9,0xd7,0xc9,0xb4, ++ 0x16,0x1e,0x72,0x3a,0xb3,0x98,0xe2,0xb2,0xe3,0x9a,0x51,0xc4,0x9f,0x05,0xa4,0x63, ++ 0x00,0x1f,0x2c,0x86,0x32,0x9d,0x54,0x68,0x67,0x57,0xf2,0xde,0x5f,0x6e,0x36,0xe9, ++ 0x21,0x96,0xfb,0x25,0xb3,0x3e,0x26,0x64,0x75,0x18,0x10,0x85,0x0b,0x73,0xee,0xfe, ++ 0x4d,0xd2,0xdf,0x37,0x86,0x17,0x99,0x90,0x9a,0xcd,0xf3,0xcf,0xdf,0x65,0xc9,0x93, ++ 0xe3,0x33,0xd8,0x66,0xc7,0x18,0x67,0xf1,0x54,0x7a,0x02,0x84,0x83,0x7e,0xc2,0xad, ++ 0x2d,0xf8,0x4b,0x7f,0x8e,0x28,0x20,0xd8,0xee,0xdc,0xec,0xac,0xcf,0x51,0x2f,0x45, ++ 0xce,0x9d,0x56,0x6e,0x35,0xb6,0xb2,0x4a,0x92,0xd6,0xe7,0x47,0x1a,0xf8,0xdd,0x89, ++ 0xa4,0xd5,0x4f,0xa5,0x3e,0xb2,0x3b,0x49,0x6e,0xde,0xe5,0x25,0xfd,0x7a,0x3a,0xe9, ++ 0x23,0xfe,0x07,0xa1,0x3a,0xce,0x05,0x9c,0x4e,0xbe,0x85,0x3d,0x1f,0xe0,0xb6,0xf6, ++ 0xe6,0xff,0x42,0xac,0xd5,0x5d,0xe5,0x9a,0xee,0xca,0xd6,0x7c,0xfe,0xf4,0x10,0xdc, ++ 0x4c,0x98,0xd0,0xeb,0xdc,0xb4,0xcc,0xc6,0x7f,0x18,0xde,0xfb,0xb7,0x0c,0xf0,0x3b, ++ 0xac,0x6f,0xfd,0xd2,0x9f,0xb7,0x7f,0xfe,0xdd,0xb5,0xf1,0x1e,0xc6,0x01,0xbc,0x28, ++ 0x23,0x92,0x3e,0xad,0x54,0xce,0xe8,0x88,0xd3,0xb1,0xea,0x84,0x70,0x79,0x00,0x40, ++ 0x3f,0x8d,0xda,0x06,0xa3,0xb9,0xaa,0xdf,0xa9,0x71,0xa8,0x20,0xd5,0xb2,0x58,0xba, ++ 0xa0,0xfe,0x9a,0x15,0x17,0x22,0x08,0xbd,0x4a,0x5a,0xd9,0xd4,0x59,0xa3,0x7f,0x2c, ++ 0xda,0x40,0xe0,0x45,0xa2,0xdf,0xfd,0xbe,0xc3,0xc0,0xc8,0xcc,0x35,0xa0,0xe5,0x82, ++ 0xbd,0x0b,0x98,0xd5,0xdb,0x38,0x45,0x47,0xbd,0xbc,0xc0,0xdc,0x34,0x71,0xfa,0xbf, ++ 0x8d,0x82,0xd6,0x26,0xa9,0x99,0xe8,0x80,0x46,0x69,0x77,0xa5,0xbb,0x4e,0x11,0xbd, ++ 0x66,0x0c,0x08,0xf4,0x19,0xd8,0x85,0x06,0xbc,0xd8,0x5c,0x06,0xb8,0x4f,0x41,0x01, ++ 0xde,0xfb,0x6d,0xce,0x91,0x56,0x2c,0x13,0x31,0x5d,0x3d,0xf7,0x84,0x6e,0x4c,0xb9, ++ 0xa4,0xca,0xb1,0x4c,0x13,0x48,0xf5,0xee,0xc2,0x07,0x19,0xd5,0x92,0x25,0x00,0x17, ++ 0x34,0xbc,0x5f,0x7a,0x79,0x08,0x28,0x8d,0xbf,0x0a,0x18,0xcc,0x3e,0x6e,0x34,0x31, ++ 0x86,0x12,0x18,0x9e,0x99,0x22,0x4a,0x04,0x48,0x41,0x5e,0xb9,0x1a,0x9a,0x95,0x72, ++ 0xab,0xd7,0xdb,0x24,0xb8,0x98,0x43,0xc1,0x69,0x08,0xb3,0x74,0x79,0xb5,0xd0,0x8f, ++ 0x88,0x6b,0xb3,0x98,0x97,0xa1,0x21,0xd1,0xa2,0x84,0x5f,0xbb,0x97,0x96,0x20,0x4d, ++ 0x09,0x4c,0xc1,0x0f,0xd6,0x37,0x6e,0xed,0xbb,0xed,0x82,0x16,0xd5,0xc1,0x92,0xae, ++ 0x38,0xb6,0x4a,0x3f,0xa0,0x36,0x48,0x72,0x4d,0x4e,0xd2,0x6c,0xa7,0x27,0xc1,0x6d, ++ 0x6b,0x15,0x1e,0x3b,0xeb,0x25,0x6b,0x58,0x6b,0xf1,0x1b,0xe9,0xf8,0x9f,0xf1,0xa6, ++ 0x06,0x89,0x16,0xc9,0x7a,0xb0,0x4b,0x1b,0x34,0x0d,0xfb,0x6c,0xdd,0x6c,0x7a,0xa8, ++ 0xdd,0x19,0xdd,0x86,0xd7,0x31,0xd4,0x00,0x53,0x5d,0x1f,0x2e,0x71,0xd0,0x34,0x63, ++ 0x11,0x17,0xd7,0x26,0x06,0xc7,0x14,0xb4,0xbd,0x60,0xf6,0x36,0x93,0x6a,0x06,0x05, ++ 0x8a,0x62,0x40,0x04,0x83,0x26,0xea,0x66,0x2a,0x63,0xaf,0x5a,0xf6,0x59,0x7f,0x79, ++ 0x00,0x91,0xd0,0x47,0xc6,0x33,0x7d,0x03,0xd2,0x5e,0xa5,0x4a,0xd2,0xd3,0x34,0x39, ++ 0x46,0x61,0xf8,0x32,0x34,0x37,0x66,0x1f,0x51,0x9f,0xee,0x17,0x7d,0x36,0xd0,0x0f, ++ 0xc2,0x0e,0xf2,0x10,0xbe,0xc3,0xb9,0x00,0xe3,0x4a,0xe7,0x33,0x9a,0xff,0x0c,0xef, ++ 0xed,0x54,0x82,0xa7,0xf0,0xc9,0xed,0x0e,0x6f,0xab,0x85,0x4d,0xf4,0x75,0x12,0x27, ++ 0x90,0xbc,0x85,0xd1,0x1a,0xf8,0x43,0x13,0x71,0x5f,0x1d,0x55,0x8f,0x7f,0x7e,0x0c, ++ 0x0a,0x03,0x59,0x34,0x3e,0x1b,0xe9,0x98,0x3c,0x1a,0xcf,0x5d,0x3c,0x7c,0x1b,0xd8, ++ 0x2d,0xed,0x50,0xea,0xb6,0xbf,0x66,0x3c,0x10,0x34,0x64,0x54,0x52,0xb4,0x3f,0x76, ++ 0x27,0xbc,0x41,0xce,0xfe,0x21,0x47,0x44,0x01,0x6b,0x95,0xdf,0xcb,0xd1,0x1a,0x69, ++ 0xfd,0xba,0x8f,0xdd,0xb5,0xf9,0x1a,0xd8,0xb3,0x5d,0xe0,0x7a,0x10,0xd8,0xfc,0x0f, ++ 0xe8,0x95,0x06,0x6c,0x08,0x7e,0x81,0x6c,0x48,0xee,0xd4,0xd3,0x39,0x78,0xb1,0x5c, ++ 0x00,0x93,0x02,0x58,0x19,0xcc,0xb2,0x6a,0x3d,0x55,0xdc,0x03,0xa7,0xf7,0x4f,0xc4, ++ 0x4b,0xd1,0x97,0xb7,0x35,0x93,0x6f,0x79,0x01,0x74,0xd1,0x69,0xd8,0x6d,0x6f,0xdc, ++ 0x98,0xa4,0xc7,0xd9,0x12,0xf0,0xdb,0x8b,0x00,0x75,0x86,0x10,0xbd,0xb2,0x06,0x2b, ++ 0x38,0x0b,0x77,0x26,0xb5,0xd2,0x0e,0x0b,0x2f,0xcf,0x74,0xa0,0x02,0xe6,0x7c,0x17, ++ 0xa4,0x2e,0x44,0x84,0x19,0xa9,0x6e,0x41,0x27,0x48,0x43,0xd4,0xd0,0x93,0x66,0x32, ++ 0xe8,0xc0,0xf8,0x05,0xd0,0x6f,0xb1,0x11,0x49,0x64,0x91,0x76,0x75,0x68,0xbf,0x23, ++ 0xbe,0xc1,0x6b,0xff,0xa6,0x68,0x19,0xd9,0x2c,0xcc,0x11,0xbe,0x57,0x64,0x70,0x82, ++ 0x1e,0x79,0xb9,0xab,0xf3,0x5b,0x20,0x32,0xcb,0x32,0xfa,0x76,0xa9,0x10,0x3e,0xf2, ++ 0x1d,0xc6,0x68,0x15,0xdf,0x38,0x30,0x8d,0x41,0xc6,0xba,0x89,0xbe,0x8f,0xcd,0xd1, ++ 0x96,0x8e,0xda,0x00,0x48,0xae,0x73,0x88,0xc0,0xc5,0x39,0xe3,0xf4,0xec,0x09,0xe1, ++ 0xb4,0x8a,0xff,0x35,0xff,0xaa,0x28,0x34,0x19,0x47,0x55,0xe8,0xd4,0x07,0x72,0xe5, ++ 0xad,0x77,0x27,0x06,0x7b,0xbf,0x28,0x28,0xde,0xc2,0xeb,0x4c,0x7f,0x4a,0x62,0x1e, ++ 0x85,0x17,0xa4,0x7c,0x5c,0x89,0x63,0xdb,0x8b,0xc3,0x56,0x4d,0x00,0x1f,0x1d,0x26, ++ 0x03,0x7c,0x4b,0x82,0x1e,0xae,0xb6,0x58,0xf4,0xa6,0xea,0xd3,0x39,0x15,0x4b,0xa9, ++ 0xbe,0x86,0xd3,0x1d,0xdd,0x26,0xbf,0x1b,0xd3,0x59,0xe1,0x3d,0x6e,0x42,0x3b,0xb7, ++ 0xe9,0x41,0x9d,0x7e,0x86,0xee,0x8d,0x01,0xc3,0x4a,0x41,0xab,0x83,0x31,0xaa,0xfa, ++ 0x91,0x56,0xd1,0x2d,0x14,0xef,0xd6,0xe8,0x5f,0xc7,0x36,0x0d,0x50,0x83,0x3a,0xb4, ++ 0xfd,0xc9,0xb3,0x1a,0x98,0xad,0x72,0xab,0xd8,0x33,0x5c,0x6d,0xde,0x1a,0x5c,0xa6, ++ 0xda,0x14,0xbb,0x63,0x9e,0xef,0x39,0x10,0x13,0xc0,0x99,0x53,0xde,0x8f,0x35,0x06, ++ 0x06,0xeb,0x84,0x92,0xd5,0xab,0x46,0x4a,0xc5,0x2f,0xd3,0x56,0xf4,0xef,0x3d,0x16, ++ 0x5c,0xfc,0x96,0x7e,0x3a,0xfe,0xdb,0x41,0x51,0xca,0x3f,0xc9,0x15,0xb1,0x1b,0xaa, ++ 0x07,0x67,0x79,0x71,0xa4,0x7d,0x99,0x4b,0xdb,0x1f,0xab,0x17,0x66,0xfa,0x77,0x7a, ++ 0xcd,0x72,0xcd,0x95,0xe0,0xbe,0xe1,0xd5,0x16,0xc3,0x7d,0x17,0xc5,0xfb,0xe6,0x2a, ++ 0x55,0x59,0x24,0x66,0x35,0x36,0xb4,0x42,0x27,0x54,0xe2,0x84,0x1e,0xf9,0x68,0x46, ++ 0x03,0x8e,0x0b,0x16,0x33,0x98,0x34,0x62,0x8c,0xbf,0xb4,0xfe,0x71,0xf6,0x89,0x51, ++ 0xa6,0x9e,0x1a,0xb4,0xf5,0xda,0x0b,0x27,0xe0,0xd5,0x88,0x9c,0x7b,0xc0,0xcb,0xb5, ++ 0x28,0x11,0x17,0x53,0x95,0x05,0x91,0x61,0xd3,0xdf,0xb9,0x88,0x54,0x47,0xe6,0x2a, ++ 0x93,0x35,0x8c,0x5e,0x60,0xb9,0x8e,0x51,0xe1,0x55,0x34,0x68,0x66,0xe3,0xab,0xe9, ++ 0x1d,0x96,0xce,0x9c,0x1e,0xb4,0x45,0x52,0x1a,0x14,0xcc,0x56,0xdc,0xe2,0xb2,0x69, ++ 0xaa,0xb9,0x9f,0x8b,0x39,0x58,0x50,0x50,0x0d,0x4c,0x69,0x5b,0xbe,0xfc,0x0f,0x47, ++ 0x9e,0x40,0x50,0xd8,0xb3,0xba,0xc2,0x7c,0x14,0xad,0x62,0x49,0xce,0x30,0x66,0x8a, ++ 0x32,0xd1,0xde,0x5e,0xc1,0x11,0xf2,0x98,0x85,0xb6,0xd6,0x09,0x9f,0x63,0xd4,0x3a, ++ 0x23,0x86,0x68,0xe0,0x34,0x41,0x00,0x2a,0x5c,0xa6,0xee,0xda,0x4c,0xef,0x25,0x2d, ++ 0x9d,0xe5,0xab,0x88,0x60,0xb4,0xb7,0x4b,0xdc,0x5e,0xcb,0xcf,0xae,0xd3,0xc9,0x3d, ++ 0x9c,0xf5,0x54,0x80,0x3f,0xbf,0xc5,0x6b,0x87,0xd2,0x47,0xef,0x58,0xbe,0xa8,0x38, ++ 0xe1,0x1b,0xcd,0x44,0x92,0x24,0x5a,0xbd,0x4e,0x06,0xd6,0x03,0xf1,0x25,0xe0,0x0d, ++ 0x13,0x4e,0xa2,0x91,0x1f,0xab,0x20,0xe0,0x1d,0x5a,0x3e,0xc0,0x59,0x7a,0xa3,0xe7, ++ 0x05,0xb0,0xc9,0x67,0xd3,0x2e,0xd6,0xa3,0x40,0xda,0xaf,0xa3,0x88,0x79,0xa1,0x81, ++ 0x04,0xa3,0x0d,0xfd,0x15,0x6c,0x39,0xd7,0x64,0x2d,0x5a,0x53,0x2e,0x6a,0x02,0xa6, ++ 0x31,0xd6,0x98,0x5d,0xb3,0x46,0xa8,0xe2,0xc2,0x9e,0x2f,0x5a,0x3e,0x26,0x36,0x84, ++ 0x05,0xed,0x4a,0x36,0x9e,0x47,0x20,0xf2,0xc3,0xbf,0xdd,0x07,0x6b,0x6a,0xf9,0xa9, ++ 0x1a,0xc7,0x21,0xd5,0xb0,0xa4,0x69,0xe3,0x2c,0x0b,0xca,0x5e,0x50,0x65,0x5a,0x23, ++ 0x7c,0x45,0x0d,0xd3,0xd7,0x21,0x61,0xf3,0x2d,0x2a,0x89,0x6c,0x8b,0x61,0xaa,0x1c, ++ 0x8d,0x28,0xe2,0x0e,0x43,0x25,0x70,0x39,0x49,0x28,0x16,0xc4,0x94,0xa8,0xf5,0xf5, ++ 0x01,0x52,0x72,0x7a,0x94,0xaf,0x3a,0x65,0xe8,0xc3,0x8e,0x5a,0xae,0x72,0xf8,0xf4, ++ 0x9f,0xb1,0xc9,0x10,0xab,0x3e,0x49,0x38,0x6f,0x4c,0x83,0x34,0x80,0x71,0x79,0xf0, ++ 0x06,0x49,0x89,0xdd,0x95,0xa0,0x9c,0xd1,0xa6,0x04,0x8b,0x5b,0xad,0x24,0xdc,0xbc, ++ 0xe3,0xa6,0xe2,0xe8,0xbb,0x83,0x2a,0xea,0xca,0x45,0x82,0x71,0xb3,0x3d,0x6c,0xba, ++ 0x44,0xa2,0x5b,0xde,0x9b,0x76,0x22,0xfa,0xcb,0x64,0xe0,0x9e,0xdb,0x5d,0x65,0x9d, ++ 0x29,0x8b,0xd6,0x6a,0x3b,0x81,0x6b,0xeb,0x24,0xc3,0xab,0xef,0xf8,0xde,0x02,0x2a, ++ 0xc0,0xae,0xf3,0xb5,0x5b,0xe0,0x63,0xfb,0x25,0x60,0xfd,0x54,0xef,0x69,0x64,0x82, ++ 0x39,0x1d,0xa4,0x6d,0xfb,0xef,0xb0,0xd2,0xc3,0xdb,0xac,0x21,0x7e,0xfa,0x6c,0x92, ++ 0x34,0x1c,0x4a,0x7c,0x41,0xaa,0x26,0x00,0xcf,0xfe,0xda,0x25,0x42,0x50,0x65,0x82, ++ 0xed,0x1d,0x5a,0xcd,0xb6,0x11,0xfd,0x9d,0x0b,0x16,0x52,0x56,0x99,0x73,0x6d,0x92, ++ 0xb0,0x1c,0x7e,0x6c,0x46,0x48,0xb9,0x41,0x1e,0x5c,0x25,0x4a,0xc2,0x72,0x24,0xc2, ++ 0x63,0x19,0x23,0x84,0x7a,0x76,0x50,0x06,0x83,0x4f,0x92,0x96,0x5c,0xfc,0x86,0x3a, ++ 0xc2,0x2e,0x0c,0xb1,0x1e,0x3f,0x24,0x4d,0x83,0xaa,0x64,0xa6,0x5d,0x16,0x4f,0xc9, ++ 0x01,0xbb,0x9d,0x12,0x32,0xd6,0x95,0x07,0x1f,0xfd,0xf5,0x1a,0xc1,0xe4,0x94,0x36, ++ 0x12,0xb6,0x4d,0x13,0xc3,0x31,0xee,0x13,0xe5,0x8e,0x97,0xb7,0xae,0x88,0x66,0x8a, ++ 0x35,0x15,0x82,0x60,0xb8,0x03,0x4c,0xd8,0x14,0x47,0x2e,0x52,0xf7,0x8e,0xd5,0x98, ++ 0x56,0x92,0x9e,0x18,0x61,0xbd,0x1c,0x84,0x9e,0x5d,0x31,0xbe,0x79,0x8d,0x67,0x8a, ++ 0xb1,0x15,0x71,0x71,0xb8,0xc1,0x2d,0x4f,0xb4,0xd1,0x9f,0xbc,0x25,0xa7,0x50,0x99, ++ 0x96,0x3b,0xef,0x9f,0x9c,0x36,0xb2,0x51,0x61,0xd0,0x81,0xbf,0xed,0xd6,0x7e,0x41, ++ 0x85,0xb1,0xe6,0xa4,0x9b,0xe3,0x73,0x6a,0x6b,0xbb,0xe8,0x88,0x12,0x71,0x15,0x3f, ++ 0x9a,0xbc,0xb1,0xa2,0xd0,0xdc,0x56,0x57,0x8a,0x52,0xe4,0x59,0x8c,0xf1,0x09,0x23, ++ 0x4b,0x25,0xa7,0xcf,0xd7,0x33,0x0d,0xe8,0x49,0x58,0x58,0x12,0x5e,0x6e,0x77,0x50, ++ 0x04,0x19,0xf0,0x2e,0x8b,0x3e,0xf7,0xd7,0x69,0x5c,0x0b,0x2d,0x5a,0x87,0x60,0x38, ++ 0xe5,0x9b,0xa2,0xe0,0x96,0xa4,0x88,0xc2,0x40,0x40,0x8a,0xce,0x7c,0xaf,0x56,0x4b, ++ 0x36,0xb5,0x50,0x94,0x95,0x2b,0x87,0x75,0x87,0x31,0xe1,0x3d,0xb0,0x3e,0x85,0xe5, ++ 0x94,0xcd,0xed,0x65,0xa7,0x69,0xc9,0x51,0x3b,0x1d,0xe8,0x29,0xb3,0xc2,0xd1,0xfb, ++ 0xb2,0x4c,0x91,0xff,0xe2,0x6c,0x71,0x0e,0xa6,0xd7,0x55,0xa8,0xd4,0x43,0xaa,0xaa, ++ 0x71,0xcb,0x54,0x24,0x25,0x60,0x08,0x24,0xba,0x88,0xa0,0x7f,0x35,0xc4,0x56,0x9a, ++ 0x4e,0x6f,0x17,0x25,0x2f,0xc9,0x42,0x9a,0x55,0x8a,0xed,0x90,0x64,0x27,0x5b,0xe6, ++ 0x94,0xc9,0x1b,0xaf,0x56,0x6b,0xb3,0xe7,0xd5,0xda,0x89,0x8f,0x9c,0x4b,0x71,0x5e, ++ 0x08,0x2a,0x0e,0x17,0xd5,0x0a,0x20,0x63,0x60,0xdc,0xc7,0x5b,0x70,0xa5,0x7b,0x0a, ++ 0xab,0x93,0xc2,0x0c,0x13,0xa5,0xa1,0xae,0x6e,0xc9,0x1d,0x50,0x81,0xec,0x4a,0x18, ++ 0x1c,0x84,0xf3,0x09,0xba,0xb2,0x10,0x07,0xa6,0x8d,0x45,0xd6,0x0d,0x14,0x36,0xfb, ++ 0x80,0xc5,0xfa,0xee,0x7b,0x27,0x69,0xd4,0x6f,0x41,0xb1,0xc7,0x8a,0xa7,0x4b,0x18, ++ 0xc8,0x84,0x32,0xe7,0x73,0xf0,0x01,0x8b,0x2f,0x64,0x43,0xbd,0x5d,0x32,0x2b,0xd8, ++ 0x0e,0x21,0x73,0xd1,0x1f,0x5c,0xd3,0x8c,0xcc,0xc8,0x3c,0xc4,0x58,0xe4,0xec,0xa7, ++ 0x03,0xcf,0xd4,0x77,0x90,0x5b,0x68,0x6b,0x7c,0xbf,0x3a,0xa7,0x38,0xf6,0xad,0xd9, ++ 0x82,0x86,0xba,0x59,0x7b,0x51,0xb9,0x09,0x8d,0x3e,0xf3,0xeb,0xac,0x61,0x26,0x5c, ++ 0x87,0x9c,0xa3,0x4e,0x76,0xfe,0x83,0x1d,0x30,0xd4,0xf8,0x19,0x24,0xaa,0xfd,0x81, ++ 0x1f,0x08,0xee,0x1b,0x07,0xb1,0xb4,0x44,0x57,0x3b,0xaa,0x61,0xb6,0x80,0x74,0xbc, ++ 0xa7,0x95,0x6b,0x7e,0x1d,0xfe,0x44,0x5a,0x62,0x9e,0x39,0x5e,0x55,0xbc,0xe5,0x03, ++ 0x54,0xd0,0x5d,0xa0,0x15,0x38,0x8d,0xb3,0x25,0x58,0xbd,0xa2,0x9f,0x5b,0x22,0xf1, ++ 0xab,0xf1,0x19,0xf5,0xf6,0x43,0x5d,0xb1,0xe6,0xde,0x42,0x86,0x9c,0x71,0x44,0x8b, ++ 0x87,0x4b,0xf7,0xdf,0x30,0xbf,0xf0,0x00,0xe4,0xd0,0x8a,0xaa,0x49,0xd4,0x13,0xac, ++ 0x14,0x0d,0xd4,0x25,0x0f,0xd0,0xfc,0x34,0x2f,0xd3,0x26,0x1e,0xef,0x38,0x05,0xc1, ++ 0xb7,0x9b,0x0b,0x45,0x36,0x1f,0x2a,0x81,0xc4,0x1b,0x42,0x96,0xf0,0xaf,0x95,0xa8, ++ 0xb7,0xd8,0xd5,0x24,0x83,0x4c,0x5d,0x0a,0x46,0xb4,0x00,0x1f,0xa1,0xba,0x6c,0x37, ++ 0x22,0xde,0xff,0x85,0xdb,0xb5,0x7c,0x17,0x87,0xe2,0x90,0xdf,0xdf,0x7c,0x16,0x1f, ++ 0xab,0x4b,0x6d,0x78,0xbf,0xbd,0x40,0x73,0xe2,0x5f,0xaa,0xd8,0x8a,0x04,0xe1,0x09, ++ 0x2c,0x91,0x8d,0x5f,0xe0,0xa1,0x21,0xc9,0x84,0xd7,0xee,0xa9,0x1b,0xe1,0x17,0x1e, ++ 0xa3,0xf9,0x37,0xfd,0x93,0xfd,0x37,0xfb,0xe1,0x70,0x2c,0x4c,0xb6,0xe0,0x06,0xc8, ++ 0x33,0x91,0xfc,0x32,0x3e,0xfe,0x96,0xe3,0x4c,0xec,0xe6,0xf7,0x3a,0x53,0x56,0x21, ++ 0xda,0x86,0x01,0xad,0x53,0xf2,0x46,0x08,0x90,0xdb,0xfc,0x0d,0x6a,0x48,0x9c,0x49, ++ 0x2e,0xc6,0x7c,0x71,0xb8,0xbd,0xbe,0x69,0x6e,0x2f,0x7e,0x9d,0x05,0xfa,0x27,0x3d, ++ 0x56,0x8f,0xee,0xac,0x8f,0xf0,0x5f,0xc7,0x4e,0x26,0xe1,0xc0,0x96,0xbd,0x99,0x8c, ++ 0x82,0x03,0x6f,0xea,0x90,0xb8,0x70,0x96,0x15,0x4d,0x7f,0xcf,0xd0,0xfc,0xc8,0xf0, ++ 0x1e,0x02,0xa8,0x42,0x91,0xaf,0x45,0xad,0xee,0xcc,0x9c,0x28,0x04,0x68,0x85,0xf1, ++ 0x88,0x0d,0xa1,0xc3,0x10,0x7d,0xbd,0xc9,0x00,0x84,0xb0,0xc7,0x2d,0x6b,0x0c,0xe8, ++ 0x03,0x07,0xa9,0x7c,0x11,0x6c,0xe6,0xb5,0xea,0xa0,0x35,0x3f,0x72,0xde,0x7a,0x1e, ++ 0xf9,0x45,0xbf,0x2f,0xce,0x2b,0x81,0x93,0xce,0x49,0x6b,0xc1,0xa5,0xd9,0xf3,0x42, ++ 0x23,0x4b,0xb0,0xae,0xae,0xf1,0xc8,0xb0,0x5b,0x78,0xa3,0x1b,0x7d,0x1a,0x7e,0xab, ++ 0x69,0x09,0xf3,0x7d,0x4b,0x85,0x2f,0x83,0x6e,0x4b,0x05,0x9e,0x23,0x05,0x0a,0xaf, ++ 0x7b,0x08,0xb1,0x67,0x64,0x12,0x4f,0x77,0x70,0x83,0x99,0xa2,0xdf,0x51,0x59,0x6a, ++ 0xc9,0x6a,0xa2,0xa9,0x98,0x2a,0x28,0xc0,0x37,0x87,0x80,0x28,0xba,0xe8,0xcc,0xfe, ++ 0x3a,0xed,0xaa,0x92,0x99,0x3c,0xe0,0xd0,0x22,0x86,0x3a,0x53,0x39,0x29,0xc7,0xd9, ++ 0x84,0x11,0xa3,0x3b,0x18,0x77,0x4a,0xc1,0x2f,0x5a,0x93,0xed,0x62,0xc5,0xb1,0xde, ++ 0x4b,0x2b,0xab,0xd3,0x19,0x66,0x1a,0xcf,0xfa,0xf0,0xe9,0x2d,0xd9,0x61,0x1c,0xaa, ++ 0x1a,0xf1,0xba,0x23,0xc6,0x23,0x2a,0x60,0xaf,0x0d,0xda,0x7c,0xe7,0x5a,0x35,0x18, ++ 0x47,0x1b,0x59,0x07,0x21,0xf2,0x4c,0x7e,0xf8,0x00,0xe0,0x97,0xec,0x2c,0xd4,0xb6, ++ 0x73,0x6d,0xf1,0x12,0x53,0x21,0xa6,0x97,0xde,0x73,0x2e,0x70,0x49,0xc3,0x03,0x4d, ++ 0x40,0x00,0xf1,0xe5,0x68,0x72,0x25,0x9b,0xdb,0x02,0x82,0xf5,0x26,0x9e,0x24,0x79, ++ 0x81,0x9a,0xb9,0x5a,0xdd,0x34,0xfb,0x4e,0xe0,0x83,0xae,0x23,0x54,0x8d,0xb8,0xf2, ++ 0xde,0x9d,0x28,0xe6,0xbf,0x54,0xa2,0xb9,0xc2,0x34,0xe4,0xeb,0xa1,0x7e,0x82,0x69, ++ 0x90,0x5d,0x82,0x8e,0x34,0x66,0x34,0xa7,0x30,0x36,0xb2,0x47,0x10,0x67,0x47,0x8c, ++ 0x92,0x71,0x77,0x9d,0x6e,0x0c,0xf2,0x5f,0x61,0x10,0xaf,0x9d,0x24,0xc7,0xe8,0x5f, ++ 0xdd,0x99,0x64,0x4b,0xcb,0x62,0xe0,0x02,0x46,0x5e,0x2d,0x96,0xa3,0x0b,0x22,0x97, ++ 0xc2,0xa3,0xad,0x94,0x63,0x9a,0x75,0x06,0x73,0x90,0x63,0xc9,0x8c,0xa8,0xa6,0x3f, ++ 0xa4,0xa6,0xfe,0x4e,0x5b,0x72,0x50,0x8a,0x8a,0x12,0x45,0x14,0x51,0x74,0x32,0xa3, ++ 0x71,0x88,0x6d,0xab,0x2d,0xe8,0x25,0xd5,0x5d,0x88,0x09,0x0b,0x0a,0x14,0xfe,0xee, ++ 0xa5,0x9e,0xbd,0x62,0x80,0x37,0xaa,0xa1,0x8f,0x48,0xee,0x9e,0x0c,0xa7,0x08,0x7e, ++ 0xab,0x1d,0x2e,0x92,0xb5,0xa4,0xa2,0xb1,0xce,0x49,0x6d,0xbc,0x41,0x84,0x01,0x49, ++ 0xa4,0x91,0xb8,0x62,0x9c,0x0e,0xf8,0x47,0x68,0x41,0x07,0x17,0xf8,0x0a,0xd4,0xfb, ++ 0xea,0xeb,0x76,0xff,0x15,0x27,0xf0,0x57,0x69,0x50,0xb8,0x5f,0x39,0x84,0x66,0xcd, ++ 0x2c,0xac,0xf9,0x42,0xc1,0xa1,0x53,0x83,0x02,0x18,0xa9,0xb6,0x54,0xe0,0xe2,0xaa, ++ 0xf5,0xe2,0xb6,0x0a,0xda,0xe1,0x5f,0x1e,0x4f,0x40,0x30,0xe9,0xe5,0xe0,0x29,0x69, ++ 0x61,0xfe,0xa2,0x37,0xe6,0x90,0x7e,0x0f,0x03,0x51,0xfe,0x48,0x6b,0x7c,0x75,0x47, ++ 0x5c,0x5e,0x32,0xaf,0x62,0x60,0xf8,0x1b,0x0b,0xc3,0x3e,0x97,0x61,0x77,0x28,0x17, ++ 0x37,0x62,0x80,0x48,0x94,0xc3,0xca,0x64,0x5e,0x8c,0x07,0x03,0x78,0x48,0xd0,0x90, ++ 0x85,0x1a,0x93,0xf8,0xf4,0xc7,0x8f,0xb6,0x6e,0x28,0xba,0xd3,0xeb,0xc1,0x99,0xfc, ++ 0x21,0x73,0x84,0x01,0x00,0xc6,0xf4,0x65,0xc0,0x8c,0x11,0x02,0x56,0x52,0x11,0xc3, ++ 0xfb,0x98,0x1d,0x5d,0x5c,0xe7,0x60,0x2f,0x30,0x8c,0x3b,0x3c,0x51,0xb7,0x98,0x66, ++ 0x8b,0x92,0xd2,0x7f,0xc3,0x07,0xe0,0x11,0xca,0x95,0x0f,0x18,0x78,0x3b,0xd1,0x76, ++ 0x82,0x2b,0x93,0x72,0x7c,0xaa,0x06,0x90,0xeb,0xf8,0x2c,0x8c,0xce,0x86,0x1e,0x5e, ++ 0x4d,0x89,0x99,0xbc,0x77,0x35,0x0f,0x64,0x7f,0xa0,0xce,0xc2,0x2d,0x7b,0x52,0xf3, ++ 0x6a,0xb7,0xe8,0xa6,0x13,0xa7,0x9d,0x57,0x74,0xb0,0xd4,0xf7,0x18,0x47,0xb7,0xec, ++ 0xa9,0x23,0x8b,0x54,0xd5,0xcc,0x33,0x55,0xeb,0x89,0x16,0x4c,0x78,0xe2,0x52,0x0b, ++ 0xcd,0x8f,0x84,0x18,0x8c,0x35,0xd5,0xd4,0xcd,0x01,0x41,0x3a,0xf0,0xa8,0x5b,0x0e, ++ 0x6c,0x21,0x88,0xed,0x30,0xb6,0x8d,0x22,0x2b,0xda,0x33,0x58,0xf8,0x9d,0xd9,0xdb, ++ 0x2e,0x8d,0x85,0x18,0x4c,0x55,0x85,0x32,0x6a,0xdb,0x9e,0x39,0x49,0x8f,0x92,0x99, ++ 0xef,0xe0,0x5d,0x73,0xe1,0x71,0x76,0xeb,0xa7,0x88,0x17,0x05,0xc8,0xe4,0x11,0x24, ++ 0x2d,0x60,0xc5,0x04,0x31,0x31,0xde,0xd6,0xa4,0xa9,0xc7,0xf0,0xe4,0x1d,0x04,0xb0, ++ 0x6f,0x18,0x37,0xb1,0x47,0xcd,0x66,0x98,0x4a,0x63,0x75,0x15,0x40,0x71,0x2d,0xfd, ++ 0x44,0x02,0xc5,0x59,0xb1,0x03,0x42,0x99,0x26,0xc0,0x92,0x1d,0x3e,0xd3,0x32,0xe0, ++ 0x4c,0x9d,0x8a,0x80,0xa5,0x2c,0x15,0xa4,0xb4,0xb4,0x83,0x44,0x50,0x7d,0x14,0x7a, ++ 0x33,0xde,0x18,0xdc,0xfc,0xf5,0xd3,0x5c,0xe5,0x58,0xbd,0xc9,0x09,0x0e,0x7c,0xaf, ++ 0x03,0xf7,0x8b,0x80,0x65,0xbd,0x89,0xaa,0x47,0xb7,0x9e,0x4d,0x9f,0xfd,0xed,0xff, ++ 0x26,0xd1,0x84,0xcd,0x7c,0xd7,0x18,0xb5,0x71,0xb7,0x06,0x12,0x02,0x6e,0x4a,0x20, ++ 0x95,0xf1,0xde,0x9c,0x8d,0xa1,0xd1,0x00,0x86,0x45,0x75,0x9d,0xe8,0x4b,0x14,0x38, ++ 0xce,0xd1,0xc0,0x7d,0x37,0x8f,0x4e,0xca,0x94,0x81,0x99,0x1c,0x2b,0x5b,0x5d,0xeb, ++ 0x05,0x3a,0x45,0xe3,0x04,0xb6,0x0e,0x88,0x32,0xd9,0xce,0x69,0x05,0xeb,0x2b,0xd5, ++ 0x84,0xd7,0x1c,0xd7,0xcf,0x2a,0x05,0x88,0x07,0x46,0x85,0x39,0x16,0x4b,0xe4,0xa7, ++ 0x2a,0xb3,0x8d,0x51,0x89,0x66,0x0e,0x8d,0x8b,0xc8,0x62,0x54,0x89,0x4e,0x77,0x07, ++ 0x4e,0x66,0x0e,0x90,0xb1,0x34,0x1b,0xbc,0xf9,0xbd,0xc5,0xc0,0xa7,0x26,0xa8,0x0f, ++ 0xef,0xa6,0x9e,0x8d,0x23,0x8e,0xd8,0x45,0x6c,0xc0,0x8c,0x25,0xfd,0x5a,0xd7,0x3b, ++ 0xe5,0xeb,0x4b,0xb8,0x1a,0xab,0x07,0x9c,0x4a,0xcb,0x38,0x6c,0x5e,0xc6,0x20,0xcd, ++ 0x8f,0x8f,0x43,0x2c,0xfe,0x40,0x0d,0x84,0xba,0xd3,0x0b,0x9c,0xaf,0xa3,0x2e,0xa9, ++ 0xab,0xac,0x96,0x91,0x84,0xa6,0xdb,0x18,0x8f,0x6c,0x43,0x61,0x94,0xf2,0x1f,0xef, ++ 0x10,0xbe,0x4c,0x94,0x4d,0x13,0x45,0xb0,0x5e,0xd1,0xcd,0xa5,0x45,0xbf,0x11,0xdd, ++ 0x46,0xfb,0xae,0xa0,0xc3,0x40,0x54,0x53,0x87,0xd0,0x46,0x61,0xfa,0xf0,0x3d,0x9b, ++ 0x05,0x0f,0x27,0xa0,0xe4,0xa3,0xb2,0xa4,0x42,0x84,0x90,0x64,0x54,0x48,0x98,0x7a, ++ 0x20,0xf1,0xa7,0xec,0x11,0x63,0xac,0x63,0xcd,0xed,0x8e,0x56,0x7e,0x40,0x38,0x9b, ++ 0xc9,0x0d,0x36,0xb4,0x49,0x5f,0x2b,0xc4,0x21,0x24,0xea,0xa7,0xda,0x16,0x32,0x56, ++ 0x8f,0x9c,0x0a,0x39,0x49,0x00,0x61,0x62,0x4d,0x5f,0x7c,0x14,0x2f,0x42,0x4c,0xba, ++ 0xeb,0xa7,0xda,0x45,0x31,0x64,0xfc,0xff,0x41,0xd6,0x10,0xe1,0x84,0x91,0x76,0xe0, ++ 0xc1,0x05,0x8b,0x14,0x4f,0x3e,0x66,0xd4,0xce,0xb3,0xc3,0x0f,0xd3,0xd5,0x27,0x95, ++ 0x69,0xe5,0xdd,0xce,0x94,0xac,0x6f,0xb0,0x80,0xb9,0x87,0x5b,0xb0,0x24,0x37,0xe5, ++ 0x8a,0x98,0x90,0x33,0x6c,0x8a,0x11,0xf5,0xc5,0xcd,0xe7,0xd5,0x5c,0xc1,0x3d,0x8d, ++ 0xf3,0xd5,0xd2,0x85,0x0e,0x33,0x3c,0x2e,0xd9,0x47,0xaf,0x6d,0x5e,0x40,0xf5,0xd2, ++ 0xa2,0x48,0x0a,0xdc,0x1f,0x92,0x62,0x6b,0xc5,0x55,0x2a,0x7d,0xc8,0x2b,0xc7,0xf7, ++ 0x75,0x68,0x5c,0x7b,0x15,0xac,0xa7,0x7a,0x44,0xe6,0xc5,0x6c,0xff,0x42,0x32,0x79, ++ 0xd5,0xf6,0x09,0x99,0xda,0xf8,0x35,0x3f,0x58,0x0a,0xd1,0x3d,0x30,0xc1,0x44,0x75, ++ 0xe3,0xc6,0x92,0x8b,0xc4,0x24,0xd5,0x2f,0xa3,0xef,0x41,0x2c,0x1e,0x2e,0x18,0xa7, ++ 0xfc,0x4f,0xd6,0xb1,0xf2,0x2e,0x64,0xc8,0x89,0x4d,0x39,0x6d,0x27,0x4c,0x51,0xb6, ++ 0x75,0x83,0x47,0x3e,0xb8,0x61,0x35,0xbd,0x21,0x7d,0x1f,0x1e,0xdc,0x0c,0x01,0x49, ++ 0x62,0x2c,0x27,0xce,0xef,0x27,0x25,0xd1,0xe2,0x8c,0xc4,0x59,0xb8,0x4f,0xb0,0xe2, ++ 0xd7,0x75,0x84,0x00,0x68,0x5c,0xff,0x4e,0x44,0x64,0x5e,0x94,0x8f,0x8f,0xe8,0x6a, ++ 0x42,0x31,0x1d,0x8b,0x49,0x2a,0x19,0x6f,0x92,0x64,0x50,0x53,0x77,0xfb,0x3d,0x7e, ++ 0x84,0x9f,0xda,0x8d,0xb6,0xe2,0x6d,0x61,0xac,0xbd,0xaf,0x15,0x0f,0x30,0xe9,0x6a, ++ 0xc2,0x53,0x2b,0xf3,0x3e,0xb5,0x65,0x95,0x5f,0x8c,0xd1,0xf2,0x2f,0x79,0x0e,0x5d, ++ 0xdd,0x78,0x53,0x34,0x02,0x95,0x43,0x13,0x58,0xc9,0x46,0xe1,0x50,0x15,0x5f,0x54, ++ 0x60,0x15,0x7e,0x65,0x01,0x9a,0x06,0x0e,0x0b,0xf6,0x70,0x1c,0xd9,0x38,0x7b,0xf9, ++ 0x7c,0xb9,0x90,0x36,0x36,0xbd,0x75,0x41,0xaa,0xa7,0x56,0x96,0xce,0xc9,0x73,0x70, ++ 0x2c,0x91,0x69,0xb7,0x44,0x9a,0x23,0x40,0x80,0xa8,0xba,0x13,0xe1,0x3a,0xe2,0x76, ++ 0x4b,0x78,0x86,0x4c,0x20,0x23,0x6d,0x4f,0x70,0xa6,0x54,0xdf,0x3f,0xf9,0xf4,0x90, ++ 0xd0,0xd6,0xc6,0x03,0x38,0xf9,0x20,0x74,0xe6,0xdf,0x32,0x23,0x78,0x39,0xe3,0x76, ++ 0x8c,0x87,0x5d,0xeb,0x47,0x97,0x6c,0x82,0x4b,0x1b,0x6c,0x52,0x11,0x59,0x0e,0xe7, ++ 0x4e,0x0b,0xb1,0xa4,0x34,0x59,0x1f,0x79,0xed,0x72,0x93,0x47,0xff,0xf1,0x46,0x88, ++ 0x70,0xb1,0x12,0x0b,0xe4,0x34,0x00,0x58,0x81,0xdf,0xb4,0xec,0xdd,0x67,0x9e,0x43, ++ 0x28,0x9f,0x2d,0x9c,0x4d,0xe0,0x5e,0x38,0x6f,0x74,0x60,0x7c,0x59,0xbc,0x09,0x59, ++ 0x51,0xb3,0xcd,0xbe,0x94,0x50,0x69,0x48,0x65,0xd8,0xa7,0x8b,0xea,0x7d,0x8f,0x09, ++ 0xb2,0xbc,0x0b,0x23,0x46,0x53,0x3a,0x8a,0xcd,0x31,0x5f,0x3b,0x93,0x31,0x8c,0xa7, ++ 0xfb,0x5d,0xff,0x0e,0x12,0x70,0x02,0x13,0xc0,0x6f,0xf2,0xdd,0xbd,0xa3,0x57,0x68, ++ 0x2b,0x1e,0xa8,0xef,0x19,0xa5,0x9c,0xc1,0xc9,0x80,0x86,0xe7,0x35,0x3e,0xf5,0xfd, ++ 0x7d,0xe1,0x30,0x18,0xe4,0x39,0x91,0x50,0x67,0x61,0x1d,0xbc,0xd7,0x40,0x40,0xf0, ++ 0xa1,0x4e,0x2e,0xee,0xd9,0xe1,0x86,0x6f,0xe4,0x81,0xc6,0x44,0xf3,0x8f,0x8c,0xd0, ++ 0x06,0x8c,0xb9,0x35,0x78,0x2b,0x76,0x5f,0xaf,0x0e,0x88,0x59,0x3c,0x31,0x0a,0x53, ++ 0x04,0xc5,0x92,0x36,0x0f,0xe7,0x40,0x8d,0xb6,0x87,0x68,0x04,0xbc,0x94,0xe2,0x30, ++ 0xac,0xe8,0xb9,0x42,0x7f,0x65,0x0e,0x9b,0xc6,0x67,0xa3,0xe3,0xff,0x1c,0x65,0xa9, ++ 0x81,0x0d,0xa3,0x6a,0x7e,0xa4,0xb5,0x95,0x2e,0x84,0x06,0x9f,0xa0,0x2a,0x59,0x02, ++ 0xe9,0x37,0xe8,0xb2,0x44,0xea,0x8d,0x4a,0x44,0x18,0xd5,0x6e,0x58,0xc0,0x90,0xe5, ++ 0x29,0x84,0xf1,0x1e,0x66,0x09,0x1f,0x3c,0xd9,0xad,0xc4,0x8b,0xa8,0xed,0x22,0x7d, ++ 0x7b,0x9a,0x20,0x23,0x40,0x3b,0x0c,0x84,0xc4,0xba,0xc8,0x5c,0xb6,0x1b,0x50,0x3c, ++ 0x2c,0x34,0x04,0x70,0x40,0x70,0x43,0x1c,0x12,0x54,0xa9,0x2e,0xa1,0x46,0xe5,0x0b, ++ 0xfd,0x2c,0x0e,0xd1,0x1f,0x05,0x9e,0xf8,0x4e,0xc4,0x09,0x29,0x50,0x43,0xae,0xa9, ++ 0x7b,0x20,0xd4,0x3c,0x7e,0x8d,0x9d,0xba,0x53,0x8f,0xe2,0x6f,0x34,0x9c,0xf4,0x38, ++ 0xfe,0xe2,0xff,0xc8,0x98,0xc4,0x37,0xef,0x8d,0xe4,0xe0,0x87,0x4a,0xa3,0x78,0xde, ++ 0x81,0xed,0xf3,0x92,0x99,0x25,0x31,0x66,0x26,0x6c,0xff,0x82,0xdb,0xec,0x9b,0x74, ++ 0x00,0x0d,0xda,0xbf,0xdd,0x21,0x53,0x26,0x19,0xf1,0xb9,0x17,0x16,0x5f,0x98,0xec, ++ 0x86,0xf4,0xd2,0xaa,0xd4,0x1e,0x66,0x9a,0x19,0x7e,0x2b,0xc5,0x32,0x70,0x5d,0xa4, ++ 0x5d,0x9d,0x61,0x02,0xf7,0x41,0x96,0x13,0x38,0x71,0x67,0xe6,0x07,0x52,0x92,0x71, ++ 0x81,0x86,0x3a,0xe4,0xc9,0xdf,0x9d,0x43,0x01,0x00,0xb9,0x48,0x14,0xb1,0x36,0x31, ++ 0x40,0xf8,0x20,0xfa,0xdd,0xb7,0x16,0xe2,0x65,0x94,0x66,0x0e,0xd4,0x7f,0x39,0xa1, ++ 0x45,0x43,0xbc,0x52,0x74,0x27,0x71,0x43,0x05,0x7a,0xef,0x10,0x57,0xe4,0x5b,0x72, ++ 0x78,0x39,0x09,0x54,0xce,0xbe,0x69,0x68,0xe0,0x5c,0xf1,0x01,0xe6,0x7d,0x13,0x7b, ++ 0x8e,0x54,0xe5,0x4b,0x84,0xac,0xaf,0x0f,0xe7,0x7a,0x37,0x1f,0xa2,0xba,0x86,0x99, ++ 0xa0,0x97,0xc4,0x86,0x3d,0xf8,0x48,0xad,0xcd,0x77,0x7a,0x48,0x95,0xbb,0xee,0x1a, ++ 0xe9,0xdb,0xd0,0x2a,0xd6,0x5a,0xe7,0xba,0x96,0x42,0x78,0xcd,0x5b,0x97,0x4f,0x8c, ++ 0x2f,0xde,0xa3,0x45,0xdf,0x45,0xe3,0xd8,0xab,0xa5,0x5b,0x3d,0xfc,0xf2,0x6f,0x8d, ++ 0xab,0x99,0x91,0xa2,0x5f,0xab,0x3f,0x3f,0xb9,0x8a,0xdd,0xbe,0xfe,0xbb,0x60,0xf7, ++ 0x4d,0xdc,0x5e,0x31,0xd7,0xbf,0x20,0xdb,0x29,0x73,0x0d,0x1f,0xdd,0x5c,0x54,0x6b, ++ 0x4d,0x32,0xd0,0x7e,0x98,0x1d,0x00,0x52,0xef,0x8e,0xa7,0x2e,0xda,0x62,0x71,0x7a, ++ 0x45,0x3d,0x0b,0x50,0xbf,0xde,0x22,0x95,0x84,0x5d,0xc5,0xdf,0xb6,0x41,0x3d,0x5f, ++ 0xec,0xb5,0xa7,0x5b,0xb0,0x12,0xbf,0x3e,0x06,0xd2,0x13,0x64,0xfe,0x6f,0x59,0xb7, ++ 0xa5,0x6e,0x6b,0x44,0x1c,0x21,0xa8,0xde,0x50,0x0d,0xc9,0xd8,0xb5,0x9f,0x52,0x11, ++ 0x81,0xc3,0xab,0x62,0xdb,0x50,0x9e,0x77,0xa0,0xb7,0x58,0x88,0x4f,0x6b,0x63,0x00, ++ 0x83,0x43,0x17,0xd0,0x1d,0x39,0xee,0x5f,0xe2,0xaf,0xee,0xdd,0xd0,0x0c,0x32,0xe0, ++ 0x22,0xa3,0x73,0xf5,0x95,0x6d,0xe6,0x43,0x17,0x9c,0x9f,0xb1,0xab,0xbd,0xfa,0xa0, ++ 0x42,0x14,0x99,0xdd,0xb7,0xdb,0x28,0xe2,0x60,0x74,0x90,0xfc,0xd1,0x69,0x93,0x26, ++ 0x8e,0x47,0xea,0xa7,0x31,0x88,0xf0,0x60,0xa2,0x5e,0x65,0x29,0xac,0x38,0x9b,0x45, ++ 0xa6,0x1d,0xff,0x91,0x4e,0x29,0x69,0x89,0x4e,0x89,0xac,0xa7,0x73,0x79,0x9a,0xd8, ++ 0x80,0xc5,0x03,0x4a,0x30,0xa3,0x4f,0x97,0xe1,0xf7,0x52,0x8b,0x6a,0xdf,0x30,0x38, ++ 0x40,0xb7,0x13,0xac,0x2c,0x21,0xbe,0x57,0x82,0xb0,0xda,0x25,0x6b,0xfc,0x4f,0xf0, ++ 0xe7,0x44,0xfb,0x7a,0xea,0x39,0x5e,0xf8,0x09,0x9c,0xfc,0x11,0xbe,0x72,0xb8,0xce, ++ 0x52,0x02,0x43,0xb4,0x77,0x31,0x2d,0x75,0xce,0x99,0x29,0x4d,0x98,0x06,0x11,0x18, ++ 0xa8,0x5b,0x33,0xe6,0x14,0xd6,0x90,0x06,0x94,0x50,0xb8,0x4b,0xfa,0x2b,0x82,0xf1, ++ 0xdd,0x06,0xfc,0xae,0x3b,0x6c,0x46,0xea,0x68,0xbc,0xad,0x06,0x0b,0xf3,0x5c,0x75, ++ 0xac,0x40,0xdc,0xfc,0x59,0x89,0xb8,0x91,0x2f,0x22,0x1a,0xfc,0x76,0xcd,0x07,0xa1, ++ 0x3c,0x43,0xc5,0xed,0x73,0xe4,0x6b,0x2e,0xf9,0x2a,0xbb,0x6b,0x59,0x0a,0xe7,0xcb, ++ 0xc3,0x07,0x9b,0xbf,0x5b,0x34,0x02,0x4d,0x6e,0xb0,0x8f,0x6c,0xa7,0x6b,0x5d,0x36, ++ 0x87,0x0b,0x97,0x00,0x46,0x20,0xc7,0x92,0x53,0x3c,0x54,0x1d,0xcb,0x1e,0x8d,0xd0, ++ 0x61,0x5f,0xf9,0xf2,0xfb,0xa0,0xa4,0x77,0xa3,0x01,0x99,0x30,0x07,0x79,0xf7,0xe7, ++ 0x2f,0x94,0xcd,0x05,0x3d,0x29,0xad,0x90,0xdc,0x1d,0x55,0x19,0xa4,0x7a,0x1c,0xe3, ++ 0x06,0x10,0x75,0x1d,0x14,0xb5,0x15,0x30,0x00,0x1c,0xc4,0xaf,0x96,0xb5,0xd2,0x26, ++ 0xaf,0x2f,0x3b,0xb7,0x18,0x5a,0xea,0x08,0xa2,0x92,0xd5,0x86,0xf0,0xe1,0xae,0x23, ++ 0x57,0x13,0x98,0xa6,0xd8,0xc4,0x64,0x0e,0x9e,0x81,0x9a,0x96,0x8c,0x73,0xe7,0xb6, ++ 0x91,0x92,0x22,0x85,0xb6,0xc2,0xaa,0x63,0xc0,0x46,0x8f,0x07,0xf4,0x5c,0xbf,0xc7, ++ 0xa5,0x3d,0xf3,0xe8,0x3e,0x91,0x25,0xe3,0x08,0x86,0x2f,0x78,0x52,0xa8,0x17,0x14, ++ 0x1b,0xdf,0x86,0x6a,0x0b,0xac,0x46,0x89,0x38,0x1a,0xb6,0x94,0xf7,0x85,0x57,0x74, ++ 0xcc,0x10,0x34,0x7c,0x23,0x15,0x47,0xa3,0x0e,0xd9,0xe7,0xc0,0xeb,0x71,0xbf,0xb8, ++ 0x94,0x55,0x5d,0x11,0x8b,0xae,0xc7,0x74,0xeb,0xba,0xf1,0x95,0x9b,0x7e,0x0d,0xeb, ++ 0x9a,0xdc,0x0b,0x19,0xc3,0xd4,0xb7,0x09,0xcd,0x58,0x9a,0x39,0x8f,0x73,0x5e,0xdb, ++ 0x89,0x1f,0x96,0x0c,0x6f,0x7e,0x36,0x5e,0x38,0x1e,0x69,0xd0,0xf8,0xe9,0xc9,0x3a, ++ 0xc2,0x1e,0xe6,0xda,0x9a,0x22,0x9b,0x8b,0xc8,0x52,0xfa,0xbc,0x18,0x4e,0x27,0x7a, ++ 0x36,0x95,0x8b,0xe8,0x3b,0x5a,0x1b,0x89,0x68,0x99,0x89,0x0f,0xde,0x78,0x57,0xcc, ++ 0x08,0x19,0x7b,0xbf,0x00,0x5a,0x9f,0x90,0x56,0x59,0xa7,0xda,0x98,0x5c,0x7a,0x06, ++ 0xa3,0x92,0xc7,0xf9,0xe1,0x36,0x43,0xa6,0x3e,0xdd,0x58,0x0a,0x76,0xb1,0x08,0x9b, ++ 0xe4,0x9a,0xa8,0xd1,0xe8,0x17,0x39,0x4d,0xe2,0xc2,0xe0,0xb2,0x66,0x8b,0x99,0x32, ++ 0xb8,0xcd,0x5a,0x3c,0xe4,0x39,0x79,0xa7,0x31,0x8d,0x29,0xcf,0xe3,0x2f,0xdf,0xf5, ++ 0x97,0xcc,0xf3,0x15,0x26,0x7a,0x2d,0x3f,0xc3,0x80,0x01,0xd7,0x8d,0xf8,0x65,0xaa, ++ 0xde,0x4f,0xa7,0xa0,0xf7,0x0b,0x20,0x15,0x5e,0x4b,0x45,0x77,0x22,0xc9,0x99,0xb4, ++ 0x23,0x9e,0xaf,0x30,0xe8,0x08,0xdc,0x84,0xc0,0x45,0x98,0x4c,0x74,0xea,0xe5,0x67, ++ 0x67,0x9d,0xb5,0xb4,0xe2,0xbd,0x73,0x85,0x67,0xdd,0x67,0x8f,0x16,0x2b,0x99,0xab, ++ 0x69,0x3c,0x7a,0x10,0x49,0xad,0x20,0x47,0x62,0xdc,0xa0,0x61,0x32,0x82,0x02,0x8b, ++ 0x3f,0x4f,0xc3,0x4e,0x08,0xb3,0xfd,0xea,0x04,0x8a,0xee,0x58,0xa3,0x84,0x22,0x0b, ++ 0xf8,0x7f,0xeb,0x78,0x6f,0xad,0x63,0x7d,0x2e,0xb9,0x69,0xa2,0x5c,0xa9,0x9b,0xf5, ++ 0x03,0x7c,0xd6,0x69,0xe4,0xe5,0xe0,0x19,0x4c,0xcb,0x8d,0x72,0x02,0xa8,0xd3,0x19, ++ 0xcd,0x06,0xe9,0x58,0x7c,0x0d,0xc3,0x39,0xed,0x89,0x9b,0x87,0xee,0xfc,0x66,0xa7, ++ 0x06,0xd7,0xb8,0xca,0x15,0xcd,0x64,0x8c,0xaf,0xca,0x8a,0x86,0x4a,0xa1,0x6a,0xa7, ++ 0x2f,0xcf,0xea,0x5e,0x1f,0xc1,0x3f,0x9c,0x49,0xc6,0xc1,0x59,0xfc,0x88,0x43,0xa2, ++ 0x60,0x55,0x23,0xcf,0xe3,0xae,0x05,0x21,0x6d,0xd5,0x88,0x67,0x7b,0x51,0x6c,0x49, ++ 0x6e,0x94,0xd5,0x8b,0x55,0xac,0xb6,0x3c,0xf4,0xab,0xc4,0x9d,0x5d,0xec,0xdc,0x6a, ++ 0xc2,0xdd,0xfd,0x98,0xd1,0xdc,0x26,0xa6,0xcc,0x5b,0xed,0xbc,0x13,0x22,0xaa,0xe0, ++ 0x82,0x8a,0xcb,0x66,0xb5,0xae,0x90,0xc1,0x38,0x27,0x7c,0x0f,0xce,0xea,0xc9,0x11, ++ 0xb4,0x9a,0x61,0x7c,0x39,0x4f,0x6c,0x42,0x01,0x2d,0x95,0x2f,0xc7,0xe5,0x0a,0x67, ++ 0xad,0xd2,0x36,0x1d,0xb6,0x33,0xfd,0x0f,0xb3,0xd9,0x66,0xc1,0x0e,0x9f,0x96,0xd4, ++ 0x87,0x14,0xdc,0x28,0x9a,0xb9,0x86,0x6b,0x9b,0xdb,0x8c,0xc1,0x34,0xfb,0x54,0x15, ++ 0xe5,0xc5,0xd1,0x94,0x96,0x38,0x04,0x70,0xe7,0x91,0xa6,0x76,0xd4,0x90,0x1d,0x41, ++ 0x40,0x52,0x18,0xad,0x37,0xbb,0x4f,0x61,0x00,0xfc,0xcf,0xc0,0x55,0x93,0x65,0xda, ++ 0xc4,0xc7,0x32,0xd6,0x40,0x08,0x45,0x1b,0xbd,0x98,0x85,0x1f,0xf7,0x6c,0x36,0xba, ++ 0x20,0x9b,0xff,0x94,0x5b,0x7e,0x2d,0x42,0xb8,0x15,0x8c,0x35,0x7a,0x2b,0xd0,0x72, ++ 0x1a,0x54,0x3f,0xd9,0x0e,0x2d,0xd2,0x3e,0x1b,0xeb,0x6d,0xfe,0x4e,0x6d,0x32,0xe2, ++ 0xaa,0xe2,0xb7,0xbf,0xb8,0x96,0xf3,0x2e,0xaf,0x29,0xb6,0x6f,0xb0,0xb8,0x77,0xda, ++ 0x9e,0xf0,0x15,0x0c,0x81,0x74,0x77,0xb3,0xeb,0x68,0x65,0xb3,0xce,0x6f,0x1e,0x48, ++ 0xc4,0xe8,0x9d,0x3e,0x98,0x1d,0xce,0x0a,0x6a,0x5c,0xd6,0x17,0x76,0x87,0x3e,0xd2, ++ 0x4c,0xbd,0xbc,0x69,0xd4,0xd9,0x92,0x68,0x33,0xd5,0x86,0x02,0x7f,0x06,0x3d,0xd6, ++ 0x0d,0x98,0xb3,0x3c,0x3a,0x33,0x8f,0x03,0xb4,0x93,0x08,0x03,0x8b,0xc5,0x17,0x59, ++ 0x8d,0x4f,0xd7,0x34,0x0c,0xfd,0xfb,0x0b,0xb3,0x90,0xef,0xfb,0xa7,0x7b,0x5e,0xa5, ++ 0xe4,0xab,0xb1,0x28,0x00,0x24,0xcf,0xf2,0x37,0xb6,0x93,0x65,0x50,0xc4,0x9e,0x63, ++ 0x6d,0x6d,0x4c,0x4a,0x1f,0x3f,0x90,0xdc,0x41,0xcc,0x48,0x75,0x51,0xec,0x53,0x29, ++ 0x61,0xad,0x03,0x5b,0x34,0xcf,0xd1,0x44,0xa0,0x39,0x06,0x84,0x18,0x61,0x6f,0xc0, ++ 0x80,0x43,0xf0,0xea,0x1c,0xa5,0x66,0xcc,0xc3,0x98,0xe7,0x94,0x3a,0x20,0x80,0xf0, ++ 0x21,0xb1,0x3f,0xac,0x65,0xe9,0x0b,0x42,0x39,0x64,0xb0,0x46,0x91,0x69,0x89,0x95, ++ 0xea,0xcf,0x08,0xe4,0x9b,0x2d,0x05,0xa2,0x45,0xf5,0x74,0x0b,0x89,0x9a,0x91,0x7b, ++ 0xa8,0x44,0x6d,0xc0,0x69,0x48,0x8c,0x60,0xf5,0xb0,0xaa,0x42,0x73,0xd9,0x17,0xb3, ++ 0x87,0x82,0x49,0x44,0xeb,0x87,0x7b,0x99,0xb4,0x8a,0x62,0xef,0x24,0xca,0x0e,0x95, ++ 0xe1,0xc2,0x8a,0x4c,0x1c,0xd3,0x22,0xac,0x71,0x12,0xec,0x04,0xb1,0x79,0x9f,0xe9, ++ 0x7b,0xb8,0x1b,0xe3,0x45,0x94,0x0b,0x7f,0x83,0x83,0x1c,0xb8,0x77,0x9e,0x7c,0xf1, ++ 0x88,0x71,0x54,0x7f,0x6f,0x81,0x29,0xda,0xf8,0xe7,0x3f,0xbe,0x9f,0x60,0xbc,0xa9, ++ 0x7d,0x68,0x89,0xee,0xa9,0x86,0x53,0x25,0xcf,0xc8,0x9d,0x15,0x59,0x24,0xf1,0xaa, ++ 0x62,0x8f,0x54,0x0d,0xa2,0x37,0xad,0x93,0xc7,0xe1,0x9c,0x5c,0xad,0xd3,0x9e,0xab, ++ 0x25,0xad,0x96,0x2a,0xa4,0x76,0x23,0x09,0x1e,0x5b,0x1a,0x60,0x6f,0xe0,0x3d,0xf9, ++ 0x7f,0xad,0x18,0x3b,0x65,0x35,0xdc,0xf2,0xa9,0x4a,0xe9,0xdd,0x25,0xf1,0xdd,0x58, ++ 0x93,0x09,0xcb,0x60,0x70,0xbe,0x13,0x71,0x36,0x23,0xa5,0x50,0x30,0xfe,0x5f,0x80, ++ 0x5b,0x18,0xba,0xac,0x72,0x9f,0xef,0x87,0xc1,0xaf,0xf2,0x04,0xf2,0x97,0x0e,0x63, ++ 0x19,0x9c,0x66,0xe6,0xda,0x12,0x22,0x11,0x17,0xfe,0xd4,0x14,0x77,0xf2,0xc5,0x9d, ++ 0x94,0xef,0x14,0x94,0x80,0x36,0x03,0x05,0x0b,0xc3,0x6c,0xc7,0x3a,0x83,0x73,0xbd, ++ 0x69,0x22,0xf3,0x31,0x5a,0x02,0x88,0xf6,0x08,0x10,0x91,0x5d,0x86,0xbe,0xfb,0x45, ++ 0xdd,0x12,0x7b,0xe9,0xcd,0xe9,0x6c,0x1b,0x9f,0x16,0x14,0x54,0xee,0xc2,0xf8,0xaf, ++ 0x80,0x98,0xac,0x67,0xff,0x38,0xf9,0x6b,0x92,0xdc,0xa2,0xdd,0x75,0xf6,0xb3,0x3b, ++ 0x57,0x19,0x14,0x3b,0x53,0x89,0x81,0xf3,0xe4,0xd5,0xab,0xc9,0x47,0xe0,0x2d,0x66, ++ 0x14,0x18,0xb4,0xf2,0x12,0x08,0x7d,0x1b,0x56,0xde,0x93,0x71,0xdd,0x23,0x17,0xfb, ++ 0x18,0x76,0xf8,0xa4,0xd1,0x29,0xf1,0x5b,0x1c,0xf5,0x3a,0x29,0x83,0x14,0x30,0xb0, ++ 0x27,0xb6,0xcd,0x18,0x5b,0xd8,0x4e,0xcf,0x21,0xd4,0xe7,0xc0,0xeb,0x73,0x65,0x89, ++ 0xa9,0x2a,0x2b,0x1e,0xff,0x30,0x43,0x37,0x03,0xeb,0x28,0x36,0x9b,0x7e,0x1e,0x88, ++ 0x9d,0x1f,0x70,0xda,0x73,0x6a,0x61,0x80,0x02,0x8a,0xd8,0xce,0x85,0x74,0xf2,0x2a, ++ 0x0e,0x69,0x72,0x48,0x58,0x48,0x76,0x62,0x69,0x1d,0xee,0x16,0xd6,0x71,0x1c,0xe6, ++ 0x05,0x5f,0x8e,0x34,0x34,0x70,0x0c,0xa1,0x6d,0x3e,0xe5,0x72,0xcc,0x11,0x15,0xe7, ++ 0x84,0xeb,0x07,0xd0,0x09,0x34,0x97,0x4c,0x6e,0x1c,0xa8,0xaa,0x64,0x01,0xd7,0xea, ++ 0x8f,0x92,0x97,0xd0,0x39,0x98,0xff,0x97,0x48,0x3a,0xe1,0xd1,0x25,0xd2,0xe0,0x67, ++ 0xac,0x0b,0xb1,0xc1,0xca,0xaa,0xa6,0x12,0x4e,0x82,0x87,0xf2,0x52,0x63,0x88,0x60, ++ 0x67,0xb7,0x7c,0xd9,0xee,0x2a,0x3e,0x1a,0xc5,0xbc,0x9e,0x92,0x77,0x4c,0x79,0x32, ++ 0xe8,0x2d,0xb3,0xf7,0x96,0xe0,0xe5,0xf8,0x84,0xcd,0xb2,0x34,0xfe,0x13,0x57,0x14, ++ 0x24,0x88,0x2e,0x93,0xbb,0xdd,0x95,0x41,0x0f,0x12,0x2e,0x97,0x38,0x93,0x96,0xa9, ++ 0xa7,0xea,0x59,0xe3,0xfd,0xd5,0xb4,0x93,0x3f,0xc4,0xae,0x53,0x5e,0x49,0x52,0xb0, ++ 0x85,0x62,0xed,0xbe,0x18,0xe8,0xee,0x01,0x2b,0xa9,0x6e,0x31,0x8d,0xef,0x03,0x09, ++ 0x87,0xd7,0xb8,0xab,0x73,0xad,0x0f,0x1f,0x27,0x69,0xbf,0xf7,0x2d,0x4b,0x12,0x31, ++ 0x70,0xe2,0xb1,0x47,0x12,0x44,0x1f,0xa2,0xc4,0xae,0xb2,0x86,0x74,0xa7,0xa2,0x2b, ++ 0x90,0xca,0xb5,0xf5,0x7f,0x8a,0x4c,0x8e,0xad,0x6e,0x1e,0x5c,0x96,0xeb,0x19,0x23, ++ 0x0b,0xdb,0xd4,0x37,0x92,0x7f,0xad,0x29,0x6b,0xca,0x2d,0xcd,0x21,0x85,0x71,0xeb, ++ 0x74,0x5b,0x63,0xaa,0x03,0x1b,0x24,0xd8,0xe6,0x65,0xcd,0x8f,0x3d,0x4c,0xe7,0x9f, ++ 0xef,0xa3,0xa3,0x0a,0x69,0x9a,0x5b,0x8c,0x3e,0xc6,0xdb,0x88,0x62,0xe6,0x5a,0xb5, ++ 0x8c,0x6b,0xc2,0x76,0x3e,0x4f,0x4c,0x5f,0x0e,0x33,0xcc,0x5b,0xbe,0x6d,0x0a,0xed, ++ 0xb8,0x80,0xf9,0xa6,0x1f,0x16,0x32,0xc7,0x49,0xae,0xc2,0x84,0xf3,0xe0,0x9e,0x29, ++ 0xf2,0x71,0xb1,0x71,0xa2,0x5b,0xcc,0x2c,0x04,0x64,0x1b,0xeb,0xf0,0xba,0xb8,0x1c, ++ 0x81,0x50,0xed,0xdb,0xc7,0xc3,0xdb,0x19,0x3c,0xaa,0x84,0xfb,0xf1,0xab,0x5c,0x06, ++ 0x0a,0x5d,0xac,0x9b,0xdd,0xe1,0x0a,0x8f,0x46,0x3d,0x00,0xd5,0x56,0xff,0x9f,0x37, ++ 0x23,0xf8,0x40,0x08,0x36,0x11,0x42,0x8a,0x8c,0x00,0x84,0x25,0x57,0xf7,0x7e,0x1c, ++ 0x58,0x11,0xb7,0x83,0x43,0x4f,0x33,0xd1,0x0f,0xa3,0x19,0x25,0x1a,0x4d,0xc2,0xe0, ++ 0xe2,0xec,0x6d,0x32,0x4b,0x13,0x8e,0x8a,0x55,0x82,0x4b,0x4d,0x54,0x55,0x1a,0xea, ++ 0xcd,0x25,0x42,0x42,0x34,0x4d,0xc9,0x00,0x0d,0xdb,0xe1,0x78,0x75,0xd5,0xa6,0xa0, ++ 0xcc,0x4d,0x7c,0x54,0xdd,0x51,0xda,0x81,0x5b,0xda,0x1f,0xb6,0x61,0xb7,0x75,0x5f, ++ 0xa2,0xb2,0xe5,0xc7,0xb6,0xb6,0xf5,0x9c,0xe0,0xb5,0x59,0x88,0x28,0xab,0x13,0x8e, ++ 0xd8,0x86,0x2d,0x57,0xca,0xb7,0xc9,0x80,0x97,0xd8,0x29,0xf1,0xf1,0x74,0xff,0x8a, ++ 0xd4,0xc9,0xb3,0x9f,0x0c,0xbc,0x37,0xa8,0x28,0x04,0x21,0x6e,0x30,0x55,0xee,0xeb, ++ 0x75,0xdb,0xcc,0x9e,0x3c,0x59,0xfa,0x70,0xde,0x66,0xee,0x5c,0xff,0x1e,0xf8,0x59, ++ 0xdb,0x6c,0xc8,0xfc,0x84,0xd4,0x87,0xdc,0xe2,0x06,0x20,0x4d,0x50,0x57,0xfb,0xed, ++ 0xde,0x6d,0x98,0xb6,0xbb,0x38,0x01,0x83,0x19,0xaa,0xc2,0xdd,0xbd,0xf4,0xbd,0xfc, ++ 0x28,0xcf,0xe6,0xce,0x3e,0x11,0x48,0xdf,0x4d,0x9c,0xf9,0x06,0x09,0x31,0x16,0xde, ++ 0xcf,0x62,0x2e,0x7b,0xab,0xb0,0x0c,0x7e,0x41,0x99,0xb6,0xe3,0x79,0x7e,0x9c,0xb8, ++ 0xe5,0x35,0xa9,0x4b,0xdc,0x87,0xd0,0xc3,0xb2,0xf6,0x5b,0x6b,0x9c,0x24,0xdc,0x39, ++ 0x9c,0x11,0x14,0xf8,0x1e,0x40,0x47,0x05,0x43,0xd2,0xb1,0x7b,0xd1,0xab,0xc0,0xb0, ++ 0x59,0x04,0x19,0x88,0x23,0xf2,0x24,0xde,0xa9,0xc9,0xb0,0x21,0x3b,0xa8,0xbc,0xd7, ++ 0xe8,0x90,0x32,0xfb,0x6d,0x9e,0x2c,0x49,0x72,0xd3,0x67,0x12,0x1d,0x06,0x03,0x10, ++ 0xec,0x2b,0x39,0xfa,0xa3,0x16,0x0b,0x20,0xe1,0x02,0x95,0x56,0xb1,0xe0,0x6f,0x6d, ++ 0x68,0x72,0xb3,0xb0,0x62,0x38,0xa1,0xd1,0xd3,0x58,0x79,0x08,0x75,0x33,0x9b,0xa8, ++ 0x4c,0x49,0xd0,0xc4,0xb3,0xa6,0xe8,0x24,0x7a,0x40,0xc0,0x21,0xaf,0x6b,0xe4,0xcf, ++ 0x00,0xc4,0xd9,0xd0,0x33,0x27,0x62,0x8f,0xc3,0x27,0x18,0x54,0x51,0xee,0xbe,0xa9, ++ 0xee,0x4b,0xb9,0xb5,0x35,0x87,0x90,0x90,0xfa,0x66,0x8b,0x83,0xba,0x77,0x10,0x46, ++ 0x66,0x81,0xf1,0x45,0x30,0x92,0x67,0x58,0x80,0x48,0xdd,0x97,0xb8,0x68,0x64,0x71, ++ 0x09,0x2a,0xa6,0x7a,0xaf,0x85,0x02,0x4e,0xb7,0x0a,0x72,0x8c,0x6b,0xa8,0xf5,0x6b, ++ 0x35,0xaa,0x75,0x22,0xba,0x6b,0xa5,0xde,0x7a,0x68,0x22,0xcf,0x4c,0x72,0x3d,0x31, ++ 0xe0,0xd3,0x9d,0x03,0x3b,0xaf,0xd4,0x5b,0xfb,0x2a,0x2b,0xde,0xc1,0x7a,0x14,0x5e, ++ 0x87,0xa4,0x8c,0x5a,0xaa,0xeb,0xa3,0xc6,0xcf,0xf2,0x9a,0x5b,0x32,0x13,0x46,0x08, ++ 0x0e,0x4b,0x54,0x73,0x2a,0x6e,0x4a,0x71,0xab,0xe3,0x52,0x1f,0x36,0x2e,0x1a,0xd9, ++ 0x43,0x09,0xca,0xd8,0x3b,0x45,0x4c,0x4d,0x4d,0x4c,0xcb,0xf8,0x7b,0xcb,0xc2,0xe9, ++ 0x9e,0xae,0x59,0x3d,0x9c,0x2f,0x46,0x96,0xa9,0xc2,0xc3,0x49,0x25,0xc3,0x4a,0xf9, ++ 0x81,0xaf,0x74,0xbf,0xf8,0xa3,0x56,0x0b,0x68,0xc4,0x85,0x9f,0xdf,0xc2,0xe7,0x04, ++ 0x72,0xfa,0x84,0x00,0x68,0x5c,0x4d,0xb8,0xc5,0xef,0xb2,0xb0,0xf7,0x32,0x42,0x50, ++ 0x39,0xe4,0xb7,0x28,0xc2,0x6c,0x16,0xb2,0x9e,0x4a,0x22,0xf3,0x42,0x95,0x3b,0xb4, ++ 0x2d,0xb4,0x3a,0xb4,0xf9,0x8d,0xa5,0x30,0x01,0x31,0x7d,0xa1,0xcb,0xd6,0x9b,0x15, ++ 0x8b,0x80,0x9b,0xf7,0x79,0x9a,0x5e,0xd7,0x20,0x30,0x7f,0xf5,0x8c,0x3f,0x2c,0xc6, ++ 0xa1,0x70,0x6b,0x40,0x5f,0xea,0x94,0xc0,0x32,0x59,0xc2,0xcc,0xc1,0x69,0x9c,0xa2, ++ 0xc8,0xf4,0x5a,0x50,0x68,0xb9,0x9c,0xd0,0x1b,0x58,0x85,0x30,0xd6,0xaa,0x2d,0x23, ++ 0x21,0x1b,0xea,0xae,0x6b,0xc3,0x0d,0xe5,0x4b,0xa8,0xfd,0x87,0x57,0x89,0x17,0x83, ++ 0xcb,0xf6,0x0d,0xf5,0xe3,0x3a,0x20,0x03,0xc0,0x17,0x62,0xa9,0x0c,0x79,0x00,0xbd, ++ 0xa8,0x17,0xfe,0xbe,0xc7,0x54,0xc2,0x78,0xe9,0xa0,0x17,0x44,0xb0,0xb3,0xf5,0xbf, ++ 0x88,0xe6,0xe8,0x7e,0xce,0x22,0x26,0xe5,0x96,0x1c,0xc3,0xbf,0x94,0x62,0xef,0x3c, ++ 0x8c,0x17,0xb8,0x12,0x47,0xa7,0xe8,0xda,0xcd,0xfb,0x97,0x45,0x70,0xba,0x50,0x4b, ++ 0xda,0x3e,0x4c,0xfb,0x85,0x84,0x1e,0xcb,0xc7,0x84,0x3f,0x2b,0xf8,0xa1,0x86,0xe8, ++ 0x33,0x11,0x39,0x3c,0xfb,0x0d,0x6a,0x8c,0x09,0xd5,0xee,0x06,0x87,0x33,0x82,0x28, ++ 0x8c,0x5f,0xb6,0x2c,0x5a,0x0c,0x4b,0x10,0xeb,0x10,0xe0,0xd4,0xf6,0xfb,0xab,0x5b, ++ 0xaa,0x16,0x07,0xed,0xa3,0xc3,0x42,0x03,0x4f,0xf1,0xf7,0xe4,0xb2,0x6f,0x5f,0xc5, ++ 0x0a,0x14,0xb6,0xae,0x83,0x70,0xa0,0x92,0x66,0xa9,0x58,0xbd,0x35,0xdf,0x3f,0x7d, ++ 0x0a,0x2f,0x1b,0xe0,0x04,0x5d,0x27,0xca,0x0c,0x3d,0xb1,0x40,0xbf,0x78,0xe8,0xb7, ++ 0xd3,0xc3,0xf0,0x06,0x26,0xa0,0x2c,0x54,0xba,0x83,0x84,0xb2,0x68,0x44,0xba,0x87, ++ 0xaa,0x5f,0x59,0xef,0xc6,0xef,0xc9,0x21,0x82,0xd9,0x86,0x73,0xd2,0x98,0x6a,0xc6, ++ 0x6c,0x62,0x89,0x13,0xa6,0x82,0xfe,0x41,0xf6,0x63,0x87,0x47,0x5a,0x45,0xa0,0xa3, ++ 0x71,0x80,0xf5,0xc2,0x36,0x9c,0x6a,0x53,0x2a,0xdb,0x66,0xe4,0xf6,0x9e,0xa8,0x86, ++ 0x4d,0x9e,0x6a,0xd2,0x37,0x14,0x68,0x97,0xba,0xca,0xc6,0x5e,0x51,0xe4,0xe5,0xc7, ++ 0xad,0xed,0xdb,0xa5,0xa5,0xfd,0x4f,0x4a,0x61,0x84,0x31,0x47,0xbe,0x19,0xff,0x35, ++ 0xc7,0xc8,0xb3,0xa8,0x34,0x8a,0x7f,0x46,0x2e,0x26,0x8d,0xf3,0xf7,0xe2,0x3a,0x03, ++ 0x46,0x69,0x1a,0xfd,0x55,0xb3,0x8d,0xcc,0x7f,0xc9,0xac,0xee,0x58,0xc4,0x79,0x18, ++ 0xa2,0xcb,0x55,0x6c,0x7f,0x56,0x2d,0xd2,0x41,0x34,0xe6,0x8b,0x36,0x60,0x94,0x3e, ++ 0x8a,0xa9,0x03,0x79,0xfc,0x55,0x8b,0xd4,0xca,0x73,0x60,0x5d,0x23,0xa8,0xff,0x65, ++ 0x8b,0xe8,0x50,0x24,0xf4,0x30,0xc3,0xbf,0xbf,0x44,0xbb,0x99,0xc9,0xf0,0x42,0x43, ++ 0x3d,0x6d,0x0d,0x5f,0x2e,0x80,0x68,0x77,0x6d,0xda,0xa8,0x87,0x58,0xed,0xaa,0x32, ++ 0xc9,0xcf,0x6d,0x3e,0x13,0xc7,0xec,0x3d,0x85,0x75,0x5f,0x4f,0x6f,0xf2,0x59,0xad, ++ 0x09,0xce,0x5a,0x3c,0xa6,0x24,0x49,0x98,0xa2,0x63,0x64,0x0d,0x21,0x65,0xe4,0x2f, ++ 0x0c,0x81,0xfe,0xbd,0x42,0x92,0x73,0x7f,0x66,0xa2,0x44,0x99,0xbc,0x66,0xe4,0xe7, ++ 0xfb,0x34,0x9e,0x23,0xc7,0xf2,0x1e,0x07,0x27,0xdd,0xed,0xa5,0x13,0xf0,0x14,0xd0, ++ 0x86,0x9d,0x17,0x70,0x25,0x4c,0x38,0x8d,0x0c,0x93,0xb9,0x66,0x4e,0xe5,0x34,0xb6, ++ 0x80,0x9e,0xa2,0xc0,0x87,0xa2,0xba,0x50,0xf1,0xa9,0xec,0xad,0xb0,0xf1,0x89,0xd1, ++ 0x21,0x9f,0x55,0xe4,0xd4,0x34,0xa4,0x47,0xd6,0xb3,0x03,0x5f,0x61,0x35,0xe9,0x32, ++ 0x47,0x35,0xd8,0x19,0x30,0xb5,0x7c,0x27,0x8f,0xe5,0x62,0xa5,0x98,0xb5,0x79,0x56, ++ 0x07,0xfe,0x36,0x52,0x17,0x25,0x02,0xda,0x54,0xd1,0xc2,0x87,0xa3,0xfa,0xf3,0x29, ++ 0x03,0x39,0xf2,0xa5,0x55,0xbd,0x3f,0x01,0xc5,0x6e,0xac,0xe4,0x13,0x29,0x55,0x2c, ++ 0x4e,0xa6,0xd5,0x10,0x84,0x9c,0xc5,0x0c,0x0e,0xc6,0x3d,0xaa,0x0e,0xff,0x4e,0x7b, ++ 0xaf,0x9a,0xa2,0x9f,0x57,0x70,0x8e,0x55,0x5f,0x78,0xbe,0xf6,0x4f,0x19,0xaa,0xd9, ++ 0x5b,0x82,0xb4,0xef,0x54,0xb2,0x84,0x55,0x5e,0x0b,0x3e,0x3a,0x00,0x22,0x37,0x83, ++ 0xec,0xd4,0xa7,0x8d,0xe8,0x17,0x8f,0x50,0xdf,0xee,0xed,0xae,0x5b,0xb6,0xb9,0xfd, ++ 0x8c,0xdb,0xa9,0x6e,0xf8,0xdb,0x87,0x48,0xf8,0x99,0x9f,0xff,0xfb,0x02,0x3e,0x46, ++ 0x1d,0x18,0x04,0x8e,0x4f,0x31,0xda,0x75,0x6f,0x9c,0x72,0xd1,0x17,0xbd,0xd6,0xba, ++ 0x23,0x60,0xe0,0xbc,0x1c,0xe7,0x70,0x98,0x4c,0x7e,0xfc,0x81,0xa9,0x02,0xdf,0x2b, ++ 0xaa,0x8c,0x99,0xe7,0xb8,0xbf,0x4b,0x34,0xe8,0xdf,0x48,0xa8,0x28,0xf6,0x77,0xce, ++ 0x9c,0xbb,0x2f,0xff,0xbf,0xfd,0x25,0x1d,0xd7,0x9d,0x6f,0x02,0xff,0xbe,0x37,0x28, ++ 0xfc,0xe1,0xb0,0x66,0xeb,0x62,0x49,0x0d,0xab,0x04,0x64,0xd7,0xdc,0x21,0x19,0x94, ++ 0x6c,0xdf,0xf0,0x26,0x35,0x8c,0xbc,0x14,0x22,0xa5,0xa2,0x84,0xff,0xce,0xc1,0xd8, ++ 0x41,0xf7,0xdd,0x00,0x6d,0x8d,0x2b,0x91,0x6e,0xed,0x83,0xe9,0x3b,0x26,0x53,0x76, ++ 0xe9,0xe2,0x1a,0x25,0x95,0xdc,0x8c,0xc2,0x45,0xce,0x3d,0x11,0xba,0x52,0x20,0x42, ++ 0x79,0x09,0xc8,0x55,0xf3,0x6b,0xa8,0x1e,0x29,0x4b,0x5e,0xec,0xaa,0xb5,0xdc,0x58, ++ 0x05,0x2e,0x17,0x50,0x15,0x0e,0xaa,0xfd,0xe2,0xb4,0xf8,0xe1,0xea,0xc4,0x51,0x32, ++ 0x8e,0x44,0x01,0x34,0x71,0x67,0xd6,0x53,0x3d,0x40,0xe2,0x5c,0xa5,0x46,0xc6,0xd5, ++ 0xea,0x88,0xa3,0xa8,0x97,0x65,0xa6,0xf5,0xf2,0x47,0xe1,0x9e,0x1b,0x16,0x7c,0x0e, ++ 0xe9,0x8b,0x42,0x75,0xe7,0xd5,0x40,0x8f,0xa3,0x2c,0x6d,0xae,0xbe,0x5a,0x21,0x63, ++ 0xd8,0x75,0xb0,0xac,0xb7,0x86,0x28,0x08,0x82,0xe6,0xc5,0xbd,0x5f,0x71,0xe4,0xfa, ++ 0x04,0x4b,0x2f,0x29,0x73,0x6e,0x83,0xd8,0x6b,0x8a,0xab,0xd2,0xe7,0x5b,0xb4,0x56, ++ 0x34,0xa0,0x2f,0x39,0x72,0x6f,0xbb,0x4b,0xab,0xcc,0x9b,0x22,0xe9,0x6d,0x78,0xa0, ++ 0x10,0x43,0x9e,0xea,0x3e,0x37,0xe9,0x9b,0x26,0x57,0x44,0x7f,0x2a,0x7d,0x3c,0x12, ++ 0xa8,0x16,0xaa,0xeb,0x22,0x20,0xa5,0x0b,0x27,0x23,0x1a,0x29,0x49,0xf8,0x63,0x58, ++ 0x6b,0x08,0x1a,0x3b,0xbb,0x1e,0xc2,0x0f,0xa2,0x7f,0x6a,0xe9,0x9f,0x0a,0xde,0x3f, ++ 0x74,0x14,0xd9,0x51,0x38,0x2b,0xbc,0x39,0xff,0x54,0x4c,0x46,0xf9,0xe2,0x84,0x00, ++ 0x80,0x1d,0xfa,0x82,0xd1,0xb3,0x6a,0xa6,0x81,0xd3,0x73,0x64,0x74,0x84,0x1d,0x63, ++ 0xa5,0x9c,0x1c,0x64,0xa5,0xc0,0x62,0xb7,0x0a,0x5e,0xe4,0xa4,0x91,0x8e,0xfa,0x71, ++ 0x61,0xb3,0xf7,0x76,0x3c,0x3f,0xe3,0x52,0x6c,0x13,0x80,0xd6,0xc8,0xd9,0x5f,0x23, ++ 0x4a,0x77,0xf3,0x93,0x50,0xb0,0x9d,0xc2,0xd9,0x11,0x71,0xc6,0xcd,0x85,0x45,0x42, ++ 0xc4,0x46,0x86,0xa4,0x62,0xb5,0x44,0x93,0x6e,0x16,0xd4,0xe6,0x68,0x89,0xb3,0xaf, ++ 0xac,0x93,0x17,0xd6,0x6b,0xce,0xd3,0x72,0x89,0x49,0xcf,0x07,0xf7,0xd8,0x7d,0x86, ++ 0x68,0x07,0x45,0x25,0xe2,0xcd,0xc1,0xe9,0xe4,0x7d,0x8b,0xe2,0xf2,0xd7,0xcd,0x91, ++ 0xbb,0xea,0x04,0xd7,0xab,0xcc,0x65,0x11,0xf9,0x4c,0x79,0x44,0xcf,0x35,0x96,0xe7, ++ 0x43,0x17,0xf4,0x7f,0xb4,0x35,0x56,0x8a,0xc9,0xc7,0xa8,0x80,0xb2,0x77,0x9e,0x68, ++ 0xb9,0xe8,0xf0,0x9a,0xd8,0xba,0x08,0xda,0x4d,0xa6,0x24,0x43,0x4a,0xbd,0x87,0x0b, ++ 0x08,0x60,0x17,0x7d,0x24,0xcb,0xa3,0xcb,0x13,0xa7,0x9f,0xed,0xcb,0xfe,0x71,0x9f, ++ 0x48,0x98,0xfd,0x6e,0x35,0x36,0x46,0xbe,0x4c,0x83,0x25,0x22,0x0e,0x60,0x24,0x36, ++ 0x29,0x9c,0x14,0xce,0x72,0x91,0x16,0x8e,0x49,0xde,0x58,0xf0,0x79,0xac,0x2e,0x6e, ++ 0x3d,0xb0,0xae,0x6b,0x02,0x30,0xc8,0x7a,0x8d,0x6f,0xcd,0x8e,0x11,0x0c,0x7d,0x21, ++ 0xa8,0x51,0x8a,0x8a,0xb4,0xc1,0x97,0x80,0x57,0xaa,0x68,0xdc,0x8a,0xd1,0x5e,0x3b, ++ 0xc0,0x10,0x63,0x4f,0x88,0x35,0x67,0x88,0x87,0x56,0xa1,0xd0,0x62,0xf7,0x58,0x06, ++ 0x86,0x85,0x9a,0xb6,0xba,0x0f,0x4e,0x25,0xb1,0xcf,0x42,0xbe,0xf5,0x1f,0x10,0xec, ++ 0xa9,0x8c,0xd6,0xf4,0xf5,0x10,0x40,0x49,0x2e,0xce,0xb8,0x29,0x65,0xe7,0x76,0x87, ++ 0x86,0x87,0x05,0x23,0x64,0xad,0x85,0x5c,0x67,0x83,0x8b,0xdc,0xd2,0xfa,0xb9,0xe3, ++ 0xdb,0x22,0x56,0x64,0x36,0x30,0xb9,0xb1,0x65,0xb9,0x4b,0xba,0x74,0xa1,0x25,0x24, ++ 0x46,0xcb,0xe6,0x34,0x94,0x43,0x30,0x04,0x65,0xa4,0x0b,0x19,0x2e,0x4b,0x64,0x19, ++ 0xe6,0xca,0x29,0xa6,0x5c,0xf4,0x38,0x14,0x07,0x8a,0x5c,0xb1,0xbe,0x74,0x8d,0xdc, ++ 0x85,0xc6,0xfc,0xa5,0xa1,0x56,0xc9,0x73,0x61,0xdd,0x51,0x15,0xa4,0x49,0xa9,0x8b, ++ 0x4f,0x53,0x90,0x31,0xb4,0xe7,0xd5,0xe1,0x87,0xcf,0x9f,0x71,0x3e,0x96,0xb4,0xf9, ++ 0x88,0x05,0x59,0x2a,0x67,0x88,0xa2,0xdb,0xef,0x08,0xfe,0x27,0xfd,0x47,0xba,0x65, ++ 0x66,0x86,0x75,0x03,0x19,0x19,0x9a,0x48,0x2f,0x6e,0x2f,0xd6,0x53,0xa4,0x71,0x29, ++ 0x67,0xee,0x7e,0x0e,0xeb,0xaa,0x01,0x1b,0xb0,0x65,0x22,0x08,0x7d,0x45,0xab,0x99, ++ 0x2d,0xab,0x89,0xef,0x05,0x5a,0xab,0xcb,0x42,0xfa,0x44,0x4c,0xe5,0x87,0xf3,0x55, ++ 0x32,0x28,0xc6,0x51,0xe2,0x96,0x33,0x18,0xe9,0x61,0x94,0x69,0x5f,0x1c,0x14,0x72, ++ 0xee,0x72,0xb2,0x73,0x2c,0xe9,0x85,0xfe,0x48,0x56,0xe9,0xed,0xdb,0x42,0xf6,0x62, ++ 0x67,0xdf,0x23,0x1b,0x01,0xa3,0x62,0x83,0x0e,0x0f,0x4c,0x9c,0x5a,0x43,0x32,0xdb, ++ 0x2a,0x86,0x53,0xcf,0xbe,0xdf,0x1b,0x79,0xb4,0xc2,0xe8,0x0c,0xe3,0x69,0x56,0x71, ++ 0xa8,0xd1,0x34,0x02,0x23,0x5d,0xcc,0xaa,0xc1,0x28,0xa2,0xc0,0x8f,0x9c,0x71,0x74, ++ 0x52,0x91,0x17,0x04,0x35,0xf0,0x04,0x48,0xc9,0xdc,0x82,0x9e,0xf8,0x57,0x7a,0x83, ++ 0x93,0x64,0x09,0xf8,0x76,0xba,0xcd,0x87,0x0f,0xb6,0x0e,0x3c,0x1f,0x13,0xf2,0x8e, ++ 0x9a,0xb3,0x82,0xe8,0x6c,0x2f,0x42,0x37,0x9c,0x6f,0x2b,0x77,0x85,0xf5,0xe3,0xd0, ++ 0xcd,0x75,0xe6,0x36,0x47,0x45,0xf2,0x91,0x0a,0xdb,0xf0,0xad,0x83,0x7d,0x97,0xa3, ++ 0x4b,0x9c,0xd4,0x25,0x4f,0xd0,0x25,0x1e,0x82,0xdc,0x76,0x39,0xd6,0xcd,0x05,0x75, ++ 0xf4,0x9b,0x1a,0x43,0xf3,0xa3,0x4f,0x0b,0xe2,0x99,0xf1,0x87,0x5a,0xb4,0x2f,0x51, ++ 0x41,0xa5,0xd5,0x24,0xc3,0xf5,0x78,0x1b,0x73,0x9a,0x85,0xe4,0xcb,0xc6,0xa6,0x0a, ++ 0xdc,0x13,0x1d,0xd4,0x18,0x13,0xda,0xd5,0xae,0xd8,0xc0,0xe4,0xdd,0x78,0x8e,0xe8, ++ 0x4f,0xfe,0x63,0xba,0x5d,0x2a,0x60,0x58,0x69,0xdf,0x2e,0xcd,0x4d,0x08,0x8b,0xba, ++ 0xc0,0x35,0xdf,0x8b,0x3e,0xbf,0x8c,0x39,0xe8,0x9b,0xcf,0x3d,0xf4,0xf2,0x51,0x9c, ++ 0x89,0x10,0xd1,0x99,0x5c,0x38,0x0f,0x02,0xe9,0xd9,0x40,0x3b,0xfa,0x60,0x5e,0xbb, ++ 0x42,0x95,0x6c,0x7d,0x9f,0x13,0x89,0x02,0x6a,0x91,0xd0,0xd6,0x4a,0xc1,0x6a,0x3c, ++ 0xc6,0x7c,0xbe,0xac,0x84,0xe0,0x36,0x98,0x90,0xc6,0x68,0xed,0x0b,0xec,0x64,0x23, ++ 0xac,0x15,0x70,0xe8,0x1f,0x11,0xe0,0x0d,0x6c,0x19,0xaf,0xf3,0x36,0x4f,0x17,0xa9, ++ 0x9c,0xdf,0x2f,0x8b,0xd8,0xfd,0xff,0x9d,0x62,0x29,0xd9,0xc2,0xc7,0x5b,0x50,0x2c, ++ 0x80,0xd1,0xd6,0x28,0x16,0xaa,0xbc,0xa5,0xff,0x02,0xae,0xf4,0x9a,0x0a,0x51,0x1a, ++ 0xa4,0x7e,0x75,0x67,0x5a,0xa3,0x64,0xc0,0xdd,0x10,0x40,0x73,0xb8,0x2b,0x3c,0x21, ++ 0x21,0x60,0x60,0xc5,0x94,0x07,0x8b,0xf3,0xc6,0x8a,0x7d,0xb7,0x90,0x68,0x3e,0xb1, ++ 0x71,0xf2,0x97,0x20,0xb0,0x01,0x60,0x4e,0x66,0x1e,0xff,0xf4,0x2e,0x0d,0xd5,0x20, ++ 0x06,0x20,0x99,0x4f,0xb7,0xdb,0x6e,0x4d,0x2a,0x49,0x40,0x16,0xb9,0x85,0xe6,0x41, ++ 0x6f,0x21,0x80,0xa0,0x5b,0x94,0x98,0x51,0x1f,0xc3,0xd7,0xb4,0x30,0xee,0xef,0x50, ++ 0xb6,0x22,0xff,0x1c,0x1d,0xd0,0x47,0x03,0x29,0x97,0xef,0x50,0x5f,0xc0,0x79,0x75, ++ 0x5f,0x76,0xe5,0x88,0xdb,0xb6,0x5f,0xb1,0x8f,0x05,0x65,0x44,0xbf,0x25,0xb5,0x24, ++ 0xfc,0x39,0xbc,0xd8,0x6b,0x28,0x0a,0x2c,0x61,0x59,0xf0,0x3c,0x59,0xa8,0x1f,0x07, ++ 0x3d,0x34,0xdc,0x30,0x1f,0xa3,0x43,0xd5,0xae,0x52,0x82,0x5d,0xd4,0xc4,0xc3,0x7d, ++ 0x4b,0xde,0x95,0x20,0x63,0xb7,0x83,0x5b,0x23,0x7b,0xad,0xfd,0xb1,0x00,0x1b,0x7a, ++ 0x87,0x10,0xef,0xdd,0x9d,0x0e,0xd7,0xdf,0x22,0xaa,0xd1,0xae,0xd6,0xeb,0xaa,0x70, ++ 0x69,0x85,0xee,0x10,0x38,0xbd,0x46,0x65,0x88,0xec,0xc2,0xec,0xfb,0x65,0x32,0x9f, ++ 0xc9,0x0f,0x35,0x2f,0x67,0xa2,0x38,0x3a,0xba,0xcb,0x4c,0xf8,0x7b,0x4e,0xd4,0xa3, ++ 0x2f,0x84,0x03,0x3e,0xb8,0xa1,0x5b,0x70,0x47,0xf3,0x49,0x9d,0x84,0xcf,0x43,0x5d, ++ 0x22,0x0b,0x30,0xb5,0x17,0x62,0x5b,0xb9,0x97,0x03,0xe3,0x8f,0xf8,0x15,0xc4,0xd4, ++ 0xac,0xbf,0xe3,0x7f,0xd9,0x61,0x6c,0x8c,0x8b,0x21,0xcd,0x5c,0xb6,0x78,0xb8,0xe3, ++ 0x15,0x1e,0xe8,0x54,0x35,0x14,0x0d,0xf7,0xab,0x9b,0xc5,0xd2,0x8e,0x6a,0xa1,0xf2, ++ 0x98,0x1d,0xe7,0x85,0xb6,0xb8,0x2f,0x52,0xd0,0xff,0x15,0x93,0xf3,0x69,0xcd,0xc5, ++ 0x11,0xbe,0x70,0x11,0xf2,0xa4,0x15,0xb5,0x68,0x63,0x40,0xc3,0x91,0xa3,0x14,0x30, ++ 0x85,0xb5,0xd3,0x3f,0xce,0xe5,0x40,0xed,0xa0,0xd4,0x9c,0x55,0x8a,0x95,0x74,0x23, ++ 0x09,0x98,0x70,0xe5,0x4b,0x77,0x3e,0x21,0x92,0xd3,0x69,0x04,0xde,0xd4,0xd0,0x45, ++ 0x82,0x14,0x05,0x78,0x0e,0xbd,0x5d,0x61,0x6d,0xeb,0x62,0xcd,0xf4,0x85,0x33,0xe9, ++ 0x4a,0x34,0xdd,0x55,0x52,0x38,0x5d,0xb1,0xdd,0xfa,0x4b,0x71,0xd3,0x75,0x90,0x6a, ++ 0x84,0xb5,0xdc,0x8d,0x9b,0x9c,0xd6,0x78,0x9a,0x55,0xe8,0xaa,0x99,0xfb,0x78,0xeb, ++ 0x11,0x16,0x46,0x8f,0x55,0x53,0x44,0x90,0x01,0x28,0xe6,0x54,0x72,0x3b,0x16,0x6b, ++ 0xae,0xd2,0x96,0x4c,0x70,0x2b,0x0f,0xad,0x40,0x25,0xe5,0x5e,0x74,0x87,0xbb,0xea, ++ 0x9d,0x14,0xa9,0xa8,0xfa,0x94,0x61,0xbf,0x8a,0x9e,0xdf,0x80,0x9a,0x6f,0x04,0x37, ++ 0xc3,0x8d,0x9c,0x51,0x52,0x8d,0x06,0xb9,0x16,0x57,0xec,0x0e,0x86,0x6d,0x72,0x5c, ++ 0xc2,0x8c,0x31,0x3e,0x58,0x72,0x3c,0xb8,0x9a,0xdb,0x19,0xcd,0x4b,0x3f,0xeb,0x56, ++ 0xab,0x5e,0x07,0xed,0x90,0xb5,0x01,0xcd,0x65,0xe3,0x17,0x81,0x45,0xf5,0x4d,0x2a, ++ 0xd3,0xb2,0xd9,0xf0,0xbd,0x3e,0x5f,0xb9,0xd7,0xf2,0xcf,0x5c,0x5a,0x80,0x01,0x64, ++ 0xbb,0x35,0x5d,0x75,0x24,0xa9,0x0e,0x17,0xc9,0x66,0x4b,0x59,0x14,0x34,0x39,0x2c, ++ 0x69,0xc3,0x3d,0xe5,0x91,0x2a,0x3f,0xc2,0x66,0x60,0x62,0x50,0xae,0x8d,0xb2,0x39, ++ 0xfc,0x77,0xe5,0xf7,0xf8,0x03,0x7f,0x63,0xc0,0xee,0xc9,0x15,0x2b,0xf9,0xb3,0xc1, ++ 0x51,0x62,0x1b,0xa6,0xa1,0xe1,0xaf,0xc0,0x41,0x4e,0x06,0xac,0x34,0x65,0xd7,0x6f, ++ 0x00,0x5e,0x2b,0xa0,0x06,0xe9,0x63,0x60,0x5a,0xa8,0x8e,0x4e,0xbf,0xf5,0x68,0x78, ++ 0x3b,0x95,0x0f,0x84,0xb6,0x0a,0x1a,0x72,0x44,0x85,0x30,0x05,0x3b,0x4c,0x54,0xb3, ++ 0x8e,0x5d,0x2e,0xa1,0xb2,0xa0,0x4e,0xf1,0xe5,0x5b,0x5d,0xf4,0x8f,0xec,0x49,0x42, ++ 0x0a,0xe4,0x7a,0xa6,0xe7,0x87,0xd1,0x4b,0x2e,0xe4,0xe8,0x17,0xc6,0x6c,0x85,0x22, ++ 0xb9,0xca,0xe8,0x80,0x1f,0xe8,0x60,0xa1,0xa7,0xac,0xb2,0x6e,0x48,0xf3,0x14,0x2f, ++ 0xae,0xec,0xb2,0x9b,0xf4,0x63,0x3f,0x49,0x21,0x6d,0xe3,0x29,0x3e,0x6b,0xa9,0xff, ++ 0x67,0xee,0x97,0xe0,0x75,0x4b,0x0b,0xcb,0xc8,0xe6,0x7f,0xdf,0xd4,0xa5,0x15,0x33, ++ 0x2e,0xd6,0xd4,0x58,0x74,0xda,0xf1,0xd9,0x2d,0x6f,0x43,0x4c,0xde,0x85,0xc9,0xef, ++ 0xdb,0x92,0xdc,0x76,0x93,0x0a,0x68,0x6e,0x6d,0x8f,0x4e,0x5f,0x6e,0xae,0xd2,0x86, ++ 0xe4,0x7c,0x80,0x6f,0x6f,0xef,0x85,0x05,0xc2,0x4b,0x29,0x45,0x6f,0x18,0x1e,0xb4, ++ 0xbd,0xea,0xb7,0x8f,0xb4,0x25,0xc4,0x57,0xc8,0x77,0xe3,0xef,0x7f,0xe7,0x6a,0x3d, ++ 0xd0,0x20,0xfb,0xdf,0x3e,0x00,0x79,0x3b,0x81,0x8d,0x6d,0xfb,0xf7,0xc6,0x7e,0x8d, ++ 0x10,0x8f,0xec,0x6e,0x07,0x4d,0x62,0x8e,0x8f,0xb4,0xa2,0x8f,0x9f,0xb4,0x76,0x43, ++ 0x11,0x8e,0x1b,0xbb,0xc1,0xe0,0x86,0x4c,0x98,0xbd,0x18,0x32,0x77,0x98,0x9d,0xc4, ++ 0xaa,0x6d,0x5d,0xf5,0x5f,0xe8,0x0d,0x5c,0xd7,0x09,0x8f,0x17,0x16,0x5d,0x95,0xd4, ++ 0xab,0x62,0x6d,0xef,0x4c,0xf1,0xde,0x73,0xe1,0xf6,0xe7,0xa7,0x9d,0xc2,0x73,0x85, ++ 0xec,0xb7,0xa4,0xa4,0x74,0xbb,0x24,0xb3,0x1a,0xdf,0x8e,0x86,0x34,0x7f,0x36,0x00, ++ 0x4f,0x04,0x5b,0xea,0x31,0xec,0x1e,0xf0,0x96,0x53,0x43,0xbc,0x67,0xf1,0x6d,0xc7, ++ 0x0f,0x46,0xe3,0xff,0x36,0xaa,0x63,0xc7,0x69,0x6b,0xf1,0x1b,0xf6,0xea,0xad,0xf3, ++ 0xa5,0x9a,0x10,0x27,0xbf,0x6c,0x7d,0xb3,0xf7,0x7a,0xfb,0xb0,0xd9,0x2b,0xd9,0x0e, ++ 0x69,0xb7,0xe6,0x44,0x0f,0xa3,0xcb,0xd9,0x2b,0x5a,0xc8,0x87,0x4f,0x83,0xbf,0x70, ++ 0x88,0x26,0x53,0xed,0x3a,0x10,0x64,0x93,0x05,0xa8,0x39,0x7e,0x7b,0x59,0xfc,0x8b, ++ 0xcf,0xee,0x1f,0x6f,0xb8,0x9f,0x29,0x83,0xcd,0xf8,0x35,0xd9,0x71,0x7c,0x74,0x9b, ++ 0x44,0xa1,0xe3,0x7f,0xa9,0xd7,0x41,0xbd,0x8e,0x1e,0xae,0xae,0xc1,0x56,0x99,0x3a, ++ 0xed,0x3d,0xe6,0xe4,0x02,0xac,0x26,0xbb,0x12,0xd7,0x22,0xb0,0xed,0xc3,0x56,0x21, ++ 0x29,0xc7,0x45,0x7b,0xea,0xa3,0x41,0x68,0x6f,0x40,0xef,0xfc,0x93,0x5d,0x70,0x4f, ++ 0x8e,0x9c,0xc7,0xde,0x33,0xdd,0xf7,0x88,0x6e,0xb0,0x37,0xcf,0x61,0x5e,0xd1,0x5f, ++ 0x87,0x06,0x92,0x5b,0x9f,0xc1,0x1d,0xfa,0xee,0x8f,0x69,0x9c,0x3f,0xbe,0x60,0x44, ++ 0x71,0x8d,0x8a,0x00,0xb3,0x26,0x4a,0x21,0xe3,0x46,0x6f,0x24,0xaf,0x9f,0x70,0x92, ++ 0x04,0x6b,0x73,0xf6,0xb0,0xa9,0x67,0xd2,0xc3,0x42,0x67,0xcb,0x51,0x41,0x79,0x83, ++ 0x85,0x3b,0x09,0x1c,0x31,0xa8,0x1d,0x27,0x61,0xc8,0x6a,0xda,0xd8,0x62,0x31,0xc1, ++ 0x76,0x0c,0x09,0xf7,0xee,0xaa,0xac,0x53,0x80,0xc3,0x66,0xcb,0x2e,0x43,0x40,0xbf, ++ 0x02,0xfb,0x62,0x22,0x31,0x06,0x50,0x60,0x42,0x75,0xa8,0x94,0x19,0xc5,0x4c,0xaf, ++ 0xfc,0xfa,0x4c,0x50,0x30,0x70,0x06,0x59,0xcf,0x74,0xd8,0x0b,0xf0,0xc5,0xbe,0xbe, ++ 0x7d,0x26,0x98,0x6c,0x37,0x2d,0x4f,0x48,0xff,0x77,0x47,0x8f,0xd4,0x65,0xb6,0x50, ++ 0x7c,0x27,0x21,0xdd,0xa0,0x16,0x3f,0x58,0x7f,0x76,0xc8,0x64,0xe3,0x25,0x3a,0xd8, ++ 0xf3,0x07,0x42,0x71,0xda,0x2e,0x6a,0x4a,0x09,0x40,0x92,0xd3,0xa7,0x68,0x40,0xe3, ++ 0xaa,0x0f,0xa0,0x99,0x17,0xa3,0x62,0xba,0x4c,0xad,0x65,0x3c,0xa6,0x96,0x63,0x4d, ++ 0x00,0x07,0x0b,0x98,0x39,0xd5,0x6b,0x4b,0x8b,0x35,0x97,0x2d,0x27,0x95,0x5b,0x36, ++ 0x28,0x81,0x0f,0xbd,0x38,0x5b,0x41,0x38,0x6a,0x4d,0x9b,0xc2,0xd9,0x6b,0xbd,0x49, ++ 0x02,0x2c,0x7a,0xdc,0xbd,0x28,0x7c,0x41,0xe7,0x1d,0x82,0x2b,0xfb,0xf3,0xb5,0xa7, ++ 0x03,0x2d,0x4e,0xba,0x70,0x3c,0x14,0x78,0x4b,0x4d,0x4f,0x42,0x6f,0x2f,0x47,0xb6, ++ 0x75,0x2e,0xc5,0xa5,0xa2,0xa5,0x55,0x45,0xf6,0x1f,0x67,0x0f,0x21,0x9b,0xb4,0xa6, ++ 0x74,0xf0,0x4c,0x2f,0x70,0x1e,0x5d,0x79,0xcb,0x4f,0xc4,0x26,0x59,0x6b,0x7c,0x02, ++ 0x21,0x52,0xe4,0xc0,0x76,0x3d,0xef,0x42,0xc1,0xda,0x94,0xa4,0x8f,0x70,0x34,0x40, ++ 0xda,0x1e,0xec,0xd0,0x29,0x3c,0x9c,0xd2,0x22,0xee,0x9c,0xb4,0x8e,0x71,0x3d,0x51, ++ 0x1f,0x1d,0x7a,0x25,0x11,0x42,0x6a,0x43,0x62,0x1a,0x95,0x5a,0x0f,0x72,0xb9,0xf3, ++ 0xe2,0xe4,0xc7,0x6e,0x12,0x3e,0x65,0x33,0xe4,0x93,0x9d,0x4a,0x0e,0x73,0x44,0xc0, ++ 0x22,0x14,0x55,0xdb,0x0e,0x8f,0x1c,0xe0,0x55,0xc8,0x6b,0x7f,0x87,0xf2,0x4c,0xd1, ++ 0x23,0x15,0x9e,0x52,0xe7,0xa4,0x64,0x90,0x67,0x71,0x9d,0x70,0x51,0x19,0x41,0xc1, ++ 0xaa,0x16,0xc1,0xfa,0xde,0x74,0x65,0x63,0x6a,0x8e,0xd5,0xa5,0xb4,0x38,0x49,0xd0, ++ 0xa3,0x17,0x6a,0xec,0xd0,0x9d,0x5f,0x51,0xed,0xc7,0xe3,0xd9,0x50,0x12,0x7e,0xea, ++ 0x6b,0xe6,0x8c,0x8d,0x9b,0xc5,0x2e,0x78,0x93,0x57,0x69,0xac,0x87,0x87,0x36,0x48, ++ 0xde,0x16,0x0b,0x1e,0x3c,0x89,0x54,0x43,0xca,0x5f,0x9e,0x43,0x79,0x79,0x7f,0x0b, ++ 0xa9,0x58,0x2b,0x08,0x9a,0x37,0x77,0xed,0xfc,0x57,0x68,0x52,0xf8,0x7a,0xbb,0xfb, ++ 0xea,0x64,0xb7,0x4d,0x42,0x34,0x97,0xa5,0x48,0xd1,0x60,0x42,0xf9,0x84,0x42,0xc8, ++ 0x22,0x3c,0xd0,0xf9,0x89,0x71,0x36,0xea,0x67,0xd7,0xe8,0xc1,0xd9,0x3e,0xb1,0x27, ++ 0x2b,0xe2,0xc8,0xf5,0xc7,0x2c,0xb6,0x70,0xe3,0xdd,0xa6,0xdb,0x92,0xcc,0x47,0x36, ++ 0x55,0xe1,0x9f,0xc9,0x93,0x80,0xd7,0x0b,0x6f,0x3c,0x87,0x2e,0x13,0xef,0x4f,0x26, ++ 0x54,0x1f,0xc9,0xf5,0xd8,0x37,0xf7,0x71,0xd8,0x04,0xa7,0xec,0x97,0x56,0xd7,0xe0, ++ 0x86,0xc8,0xc0,0x42,0x1c,0xad,0x60,0x33,0xa5,0xcf,0xb0,0xd9,0xab,0x1f,0x9c,0xe2, ++ 0x09,0x8e,0xa2,0x17,0xb6,0x5c,0x58,0x92,0x1f,0xce,0x47,0x36,0x55,0x1e,0x39,0xf3, ++ 0x85,0x8d,0xeb,0xfc,0x37,0xaf,0x51,0x83,0xfe,0xcd,0xb1,0xd8,0x2b,0xe2,0x49,0x57, ++ 0x92,0x0e,0x83,0x92,0x9b,0xc1,0x59,0x93,0xd9,0xcc,0x46,0xc8,0x2a,0xe3,0x64,0xbd, ++ 0x0e,0x7b,0x9e,0x73,0x25,0xa0,0x36,0x62,0x46,0xc4,0x3e,0x04,0xad,0x88,0x97,0xad, ++ 0x0f,0x85,0x44,0xc9,0x16,0xe5,0x61,0x72,0x47,0x05,0xf8,0xb6,0x05,0xa7,0x65,0x42, ++ 0x8e,0xa6,0x59,0xb8,0x7f,0x47,0x62,0x63,0xc6,0xe6,0x4e,0xfc,0x23,0x60,0x69,0x53, ++ 0x87,0xa7,0xf5,0x34,0xf4,0x0d,0x1d,0x73,0xc7,0x95,0xa9,0xb4,0x76,0x78,0x5a,0x88, ++ 0x09,0x42,0xe8,0x0f,0x3e,0xa5,0x52,0x8a,0x20,0xc7,0xb2,0xd1,0x5c,0xe8,0x12,0xca, ++ 0x72,0x86,0x92,0xce,0xe6,0xa6,0x70,0xc1,0xee,0xcf,0x45,0xc1,0xa2,0x16,0x5b,0x89, ++ 0x89,0x8e,0x26,0x8d,0x99,0x0a,0x53,0x6a,0x79,0xc7,0xb3,0xd0,0xdc,0xea,0x9f,0x79, ++ 0xce,0x54,0x93,0x4f,0x95,0xa4,0x37,0x50,0x6c,0x41,0xbb,0x3f,0x22,0xeb,0x62,0x4b, ++ 0x0e,0x8c,0xf4,0x7b,0xad,0xe1,0x02,0x6a,0x4e,0x4e,0x46,0x0c,0xa5,0x19,0x6e,0x5a, ++ 0x0f,0xad,0xd0,0xa5,0xe3,0x4c,0x43,0x7a,0x0f,0x62,0xe5,0x25,0xdd,0xe9,0x67,0x4b, ++ 0x8e,0xae,0xbb,0x4b,0xb7,0x10,0x18,0x6b,0xce,0x54,0xe4,0x51,0xae,0xac,0x6b,0x5a, ++ 0x87,0x8f,0x2b,0xef,0x19,0x7b,0x78,0x7b,0x93,0xa4,0xb2,0x1d,0x24,0x83,0x5c,0xe0, ++ 0x67,0x2f,0x9c,0xd6,0x3c,0xbf,0x4b,0x40,0xe6,0x98,0xb4,0x59,0x8b,0xf0,0x16,0x70, ++ 0x89,0x9e,0xa8,0x96,0x3d,0x91,0x44,0xd0,0x24,0x91,0xbc,0xb6,0x75,0x0e,0x5d,0x01, ++ 0xa1,0x13,0x35,0x86,0xb4,0x92,0x31,0xc1,0xa7,0x0d,0x4a,0x58,0xf4,0x0d,0x4d,0xd3, ++ 0x09,0x13,0xad,0x97,0xb5,0x93,0x45,0x31,0xe0,0x73,0x42,0xb7,0xf5,0xf3,0x64,0x3d, ++ 0xd9,0x94,0x73,0x42,0x14,0x84,0xce,0x1d,0xe4,0x93,0x64,0x0e,0xb2,0xb6,0x6c,0xd2, ++ 0x27,0x6a,0xbc,0xd2,0xde,0xc4,0xfc,0xf0,0x7b,0xce,0xc2,0xdf,0x36,0xf1,0x65,0x3c, ++ 0xa6,0x69,0xdb,0xf2,0x15,0xf4,0x8e,0x81,0x9b,0xdf,0xa5,0xe7,0x0b,0xf9,0x92,0x2c, ++ 0x58,0x68,0x95,0xa4,0x83,0xf5,0xdf,0x95,0x18,0xd1,0x83,0xc2,0x0a,0xfe,0x5e,0x08, ++ 0x29,0xc1,0xa2,0x8e,0x3c,0xb8,0x0e,0x7a,0x9b,0xd7,0x49,0xae,0x83,0x07,0x8e,0xf8, ++ 0x6c,0xd9,0xae,0x61,0x3d,0x46,0x5e,0xfe,0x75,0xd4,0x41,0xbe,0x7d,0xf9,0x1d,0x69, ++ 0x2e,0xb2,0xa3,0x70,0x43,0xba,0x0f,0xfb,0xe8,0xd5,0xb7,0x50,0x03,0xfa,0x57,0x19, ++ 0xac,0xf8,0x50,0x60,0xbd,0xbb,0x75,0x45,0x4e,0xd6,0x40,0x40,0xfd,0xfb,0x66,0x35, ++ 0x2e,0x63,0xb6,0xcf,0xc3,0xb3,0x82,0x47,0xcf,0x25,0x72,0xab,0x12,0xfe,0x91,0xda, ++ 0x2f,0x62,0xf9,0x3c,0xd6,0x2c,0x96,0x72,0x5c,0x86,0xda,0xa2,0x96,0x1c,0x98,0xcb, ++ 0xae,0x61,0x27,0x6f,0xba,0x13,0x6f,0xfb,0x13,0xd1,0xa7,0x67,0xee,0xf8,0x6f,0x24, ++ 0xaf,0x9f,0x2f,0x7f,0xb7,0x42,0xc5,0x1b,0xa9,0xc4,0x87,0xfd,0xb7,0x72,0x60,0x03, ++ 0x55,0x0f,0x15,0x35,0x64,0x8f,0xcf,0xde,0x64,0x5b,0x0f,0x24,0x50,0x60,0x49,0x0d, ++ 0x32,0x5a,0xf6,0x2d,0xe0,0xa1,0xe0,0xb4,0x18,0x29,0x58,0xb4,0x2c,0x61,0x51,0x1c, ++ 0x8c,0x03,0x12,0x77,0xfa,0x93,0xf2,0x47,0xf3,0x27,0x91,0xa7,0x3e,0xdf,0xb3,0xf1, ++ 0xd9,0x18,0xf4,0x66,0xad,0x17,0xa0,0xd3,0x6d,0x3e,0x99,0x35,0xd1,0x65,0x0a,0x80, ++ 0x3a,0xa9,0xc0,0x84,0x16,0x09,0x1a,0x19,0xc0,0xe3,0xc3,0xa3,0x90,0xe5,0x03,0xbd, ++ 0xfc,0x88,0x52,0x6c,0x9c,0x88,0x62,0x8d,0xe2,0x9e,0xe6,0x4c,0xdc,0xe3,0x0d,0x21, ++ 0x9e,0xa9,0xf7,0x7a,0xaa,0x64,0xf7,0xe5,0xc0,0x2f,0xd9,0xf8,0x52,0x86,0x36,0xac, ++ 0x7c,0x45,0x5c,0xc7,0x30,0x8a,0xde,0x8a,0x30,0x05,0xb9,0x35,0x95,0xec,0xa0,0x6e, ++ 0x2b,0x18,0xfa,0x3e,0xec,0x27,0x6a,0xc0,0xac,0x05,0x64,0x5f,0x5e,0x6a,0x8e,0x9c, ++ 0x2a,0x15,0x31,0xad,0x65,0x86,0x28,0xc7,0x6d,0x52,0x9a,0x2f,0x56,0x13,0x5a,0x20, ++ 0x2d,0x03,0x95,0xad,0x73,0x29,0x11,0xd8,0x6b,0x5a,0x0c,0x2d,0xd8,0x6a,0x9b,0xf1, ++ 0x1f,0x46,0x1c,0x05,0x19,0xe5,0xa9,0x5f,0x36,0x30,0xa5,0xf0,0x56,0xcd,0x5e,0x3a, ++ 0xe3,0xc6,0x53,0xde,0x1a,0x26,0x18,0xb4,0xc7,0x0e,0x2a,0x5d,0x62,0x2e,0xe6,0xc7, ++ 0x08,0x9d,0x71,0xce,0x1b,0x25,0x04,0xa1,0xb4,0x0c,0xa2,0x8c,0x05,0xcc,0x01,0xb6, ++ 0x63,0x44,0xc2,0x32,0x58,0x21,0xd4,0x83,0xcb,0xce,0xc3,0xed,0x7b,0xec,0x6d,0x9d, ++ 0xd8,0x74,0x4b,0x9b,0x8d,0x82,0x9b,0xa9,0xb2,0x54,0x4d,0xf9,0xfb,0x4c,0x1f,0x0a, ++ 0x23,0x00,0xbc,0x7b,0xb3,0x3d,0x2e,0x5a,0x91,0x3c,0x59,0xa6,0xeb,0xd4,0x88,0x6d, ++ 0xde,0x50,0x2f,0xa9,0xed,0x32,0xdc,0xe9,0x5d,0x13,0x70,0x27,0x76,0x7b,0x5c,0xba, ++ 0x05,0x19,0x7e,0x01,0xec,0xfb,0x73,0x99,0xe3,0x82,0xd9,0x7d,0x19,0xe8,0x1d,0x34, ++ 0xf0,0x08,0xd4,0x0b,0x14,0xcc,0x12,0xec,0xe0,0x33,0x8e,0xc6,0xfe,0x7a,0x1c,0x44, ++ 0x7e,0xdd,0xa6,0xa4,0xdb,0x65,0x84,0x92,0x89,0xb5,0xee,0x17,0x1e,0xff,0xf7,0x60, ++ 0x2b,0xba,0xec,0x85,0xbe,0xc8,0x53,0xb0,0x67,0x78,0xcc,0x55,0xd2,0x7c,0x7f,0xfc, ++ 0x49,0xec,0xa7,0xcc,0xb3,0x76,0x6b,0xd4,0x6f,0xf0,0xf4,0xd4,0x9e,0x34,0x86,0x53, ++ 0x4d,0xaa,0xaf,0xf7,0x46,0xb1,0x75,0x01,0xbd,0xf6,0x9f,0x05,0x54,0xd6,0x32,0xee, ++ 0x6b,0xe8,0xdf,0xab,0x9f,0x28,0xc9,0x56,0x4c,0xc8,0x15,0x5f,0x67,0xd5,0x3c,0xfe, ++ 0x9e,0x09,0xf1,0xe3,0x3f,0x81,0x25,0x7f,0xb3,0x51,0xa4,0x53,0x02,0x86,0xf8,0x75, ++ 0xa8,0x01,0x3f,0x77,0xa8,0x77,0x37,0xd3,0x9b,0xea,0x5d,0x5f,0xb8,0x85,0xb7,0x76, ++ 0x52,0x87,0x03,0xe7,0x1a,0x5e,0x9c,0x3d,0xb0,0x2a,0x5f,0xdc,0x18,0xd6,0x86,0x18, ++ 0x09,0x07,0xc6,0x0c,0x6a,0x91,0xc0,0x6c,0x4a,0x7f,0x40,0x68,0x5a,0x7e,0x8e,0x08, ++ 0x38,0x1b,0x5f,0x4e,0x37,0x35,0x06,0xfc,0xc2,0xca,0x32,0xcd,0x17,0x3f,0x42,0x4d, ++ 0xa8,0x8c,0x52,0x5f,0x3b,0x93,0x6f,0x1a,0xd2,0xd1,0xef,0x0d,0xee,0xf5,0xb9,0xa2, ++ 0xad,0x95,0x4f,0xdf,0x99,0x51,0x05,0x89,0x83,0x6e,0xcf,0xbf,0x98,0x5f,0xdf,0xea, ++ 0xe4,0xcd,0x13,0x3b,0xe8,0xa3,0xcf,0x50,0xbf,0x82,0xfa,0xe6,0x74,0x44,0x84,0x8d, ++ 0x66,0x85,0x2c,0x92,0x17,0x33,0x80,0xcd,0x7a,0xe1,0x54,0xa5,0x52,0xeb,0x5a,0x0b, ++ 0x21,0x3d,0x9b,0xfd,0x6f,0xb9,0xf9,0xd0,0x18,0x53,0xfd,0xff,0x3d,0x78,0x50,0x69, ++ 0xe4,0x87,0x12,0x55,0x34,0x5e,0x66,0x2a,0xc3,0x89,0x79,0x0c,0x86,0x16,0x64,0x30, ++ 0xfd,0x7f,0xf1,0x96,0xb5,0x1b,0x72,0xe6,0x44,0xf4,0xaa,0x99,0xf5,0xe0,0x6e,0x9f, ++ 0x87,0x8b,0x50,0x66,0xb6,0x3a,0xe8,0xd2,0x59,0x95,0xa0,0xf2,0xe8,0x50,0x65,0xc7, ++ 0xaf,0x0b,0xf9,0xd2,0xa5,0xec,0xd6,0xba,0x8e,0x7c,0x37,0x0c,0x95,0x76,0x09,0xe4, ++ 0x3e,0xc5,0xd6,0x10,0x45,0xaf,0x20,0x8b,0x22,0xa9,0xec,0x48,0xbb,0xa5,0x43,0xca, ++ 0x00,0x73,0x8a,0x6c,0xe8,0x19,0x4c,0x71,0xb1,0x74,0x7f,0xaa,0x77,0x92,0x92,0xe5, ++ 0x80,0x34,0x07,0x50,0xe8,0xf5,0xd6,0xa8,0x41,0xc1,0x7a,0xf3,0x89,0x49,0xdc,0x2f, ++ 0xbf,0x3c,0x14,0x33,0x01,0x57,0x9f,0x50,0x06,0x5b,0x73,0xff,0x78,0x15,0xcc,0xeb, ++ 0x0d,0x94,0x91,0xf4,0x2e,0xa5,0xbf,0xc6,0x3a,0x8a,0xf0,0x3d,0x30,0x4b,0x28,0xaa, ++ 0x3d,0xbc,0xe1,0x31,0xdc,0x3e,0x10,0x63,0x4f,0x8c,0xfc,0xd0,0x5f,0xfc,0x9c,0x31, ++ 0x09,0x07,0xe8,0xa2,0x1f,0x56,0x21,0x58,0x78,0x3b,0x6c,0xfa,0x16,0x3a,0xa3,0xcb, ++ 0xdc,0x88,0x58,0xdd,0x9e,0xa4,0x4f,0x01,0xfd,0xda,0x76,0x54,0xe6,0x1b,0xa6,0x7c, ++ 0x89,0x05,0xa8,0x98,0x76,0xde,0x26,0x9d,0xc9,0xee,0xfd,0x4a,0x56,0x63,0x9d,0xd8, ++ 0x22,0x20,0x9b,0x64,0xc8,0xb3,0xf4,0xfb,0x39,0xd8,0xfa,0x36,0x8b,0x5d,0x66,0x70, ++ 0xb4,0x6c,0xba,0xf4,0x55,0xa5,0x7f,0xb0,0x9c,0x5c,0xbf,0xa5,0x36,0x8b,0x89,0xfd, ++ 0x65,0x8d,0x35,0xf8,0xdc,0xbf,0xb1,0x5e,0x13,0x93,0xff,0xe0,0x2a,0xf8,0x07,0x43, ++ 0xf9,0x8b,0xd3,0x91,0x54,0x30,0x43,0x8a,0x0e,0x02,0x87,0x58,0x8e,0xd3,0x3c,0x46, ++ 0x7a,0x5d,0xda,0xeb,0xe8,0x19,0x0d,0x84,0x8d,0xc5,0x8c,0xf7,0x1a,0x59,0xd7,0x62, ++ 0x2f,0x3a,0x2c,0xf7,0x46,0x40,0xbc,0xd2,0x08,0xd8,0x6c,0x07,0x22,0xf1,0x5f,0xfe, ++ 0x4d,0xbf,0x74,0x59,0xb7,0x86,0x2f,0xa4,0x8e,0xe7,0x63,0x55,0xaa,0x88,0x75,0x57, ++ 0x86,0x2f,0x78,0xe9,0x83,0xb3,0x00,0xc8,0xdf,0x22,0xa3,0xaa,0xf7,0xec,0x58,0xa7, ++ 0x1f,0x7d,0xd4,0x7d,0xb0,0xfa,0x48,0x97,0x87,0xdb,0x01,0x7a,0x7a,0xd1,0xbb,0x5a, ++ 0x65,0xdb,0x6e,0x1e,0x72,0xbf,0x59,0x7a,0x05,0x9b,0x91,0xad,0x72,0x83,0x9f,0x74, ++ 0x23,0x3c,0xed,0x6f,0x8f,0x90,0x04,0x93,0x1d,0xb4,0x8d,0xbe,0xaf,0xfe,0x20,0x5a, ++ 0xac,0xfb,0x59,0xf4,0xbb,0xb9,0x30,0x96,0x4c,0x74,0x81,0x72,0x72,0x5d,0xa6,0x1a, ++ 0x57,0x9a,0xe4,0xf5,0x02,0x29,0xe0,0x6e,0x07,0xc4,0x2a,0x1e,0x01,0xb3,0x72,0x9d, ++ 0x29,0x6d,0x49,0xe6,0x86,0x37,0xd2,0x89,0x53,0x5b,0xc4,0x16,0x3c,0xb2,0x11,0xdc, ++ 0xa8,0x14,0x76,0x4b,0xf3,0x60,0xd4,0xc7,0x32,0xaf,0xf6,0x1f,0x01,0xb1,0x16,0x1b, ++ 0xb7,0xdd,0xec,0x3f,0xa7,0x12,0x77,0x88,0xdb,0x59,0xa6,0xa3,0x58,0xbe,0xb8,0xff, ++ 0xf4,0x11,0xfe,0x03,0x34,0x8f,0x6e,0x27,0x64,0x93,0x93,0xa0,0x7e,0x86,0x9b,0xe3, ++ 0x85,0x8c,0xf6,0x13,0x35,0xaa,0xc8,0x17,0xe0,0xee,0xa0,0xc7,0x77,0x65,0x07,0x29, ++ 0xe3,0x0a,0x21,0x77,0xf2,0xa5,0x6f,0x26,0x61,0xed,0xa9,0xd6,0xfa,0x07,0x5b,0x12, ++ 0x6a,0x67,0x6b,0x24,0xfd,0x8c,0xcd,0xf6,0x0b,0xb2,0xcf,0xb1,0xff,0x85,0xa4,0x22, ++ 0xf5,0x61,0x57,0x37,0x30,0x87,0x28,0x64,0xa2,0xc5,0x7c,0x40,0xbb,0x85,0x48,0x2e, ++ 0x62,0x01,0xe8,0xd2,0x15,0xf6,0x20,0xc0,0xd9,0xb0,0xca,0xa6,0xb8,0x21,0x79,0xbe, ++ 0x0d,0x80,0x52,0xb6,0xe6,0x16,0x39,0x92,0x46,0xeb,0x8f,0x87,0xd6,0xe3,0x2b,0x53, ++ 0x82,0x65,0x19,0x37,0x60,0x42,0xf9,0x82,0xe5,0xb3,0xe7,0x97,0xb1,0x62,0x92,0xf8, ++ 0xd8,0xb9,0x22,0x7e,0x7a,0x4f,0x2c,0x14,0x29,0x4c,0xaa,0xd2,0xf4,0x65,0x78,0xeb, ++ 0x85,0x04,0x8e,0xf1,0x11,0x69,0x3a,0xb2,0x6d,0xe2,0x29,0x45,0xa5,0xb0,0x7d,0x0f, ++ 0x69,0x89,0xfd,0x0a,0xbc,0x91,0x6a,0x5a,0xee,0xc3,0x6e,0xa9,0xba,0x81,0xf4,0xe9, ++ 0x19,0xba,0x8c,0x0f,0x72,0x4f,0x63,0x29,0x29,0xb4,0x20,0x98,0x13,0x66,0x1b,0xa9, ++ 0xef,0xb3,0xfa,0xb7,0xeb,0x40,0x86,0x94,0x94,0xb7,0xac,0x6b,0x7e,0xb7,0xcb,0x27, ++ 0x63,0x8e,0x35,0x1b,0xf2,0xdc,0xc4,0x74,0xaa,0x72,0x49,0x83,0xae,0xce,0x83,0xf9, ++ 0x02,0x04,0x07,0xb3,0x63,0x4c,0x39,0x52,0xb2,0x0c,0xd3,0x1e,0xbc,0xcf,0x35,0xe9, ++ 0x7e,0xac,0x2c,0x2e,0xef,0xf9,0x65,0xad,0xab,0x90,0x8d,0x83,0x26,0xce,0x7a,0x87, ++ 0x81,0x51,0xfa,0x21,0xdb,0xb3,0x6a,0xa7,0x44,0xfd,0x33,0x00,0x76,0x13,0xac,0xe2, ++ 0x43,0x96,0xbe,0x87,0x92,0x92,0x0f,0x43,0xe5,0xdc,0x3c,0xd6,0xc6,0x14,0x5f,0x8a, ++ 0xd8,0xbd,0xba,0x96,0xf7,0x3d,0x83,0x90,0x41,0xd3,0x71,0xe7,0x7c,0x7e,0x73,0x96, ++ 0x00,0x52,0xf3,0x21,0xda,0x3c,0x4f,0x03,0x0a,0x37,0xa5,0x5a,0x9a,0x7c,0x44,0x44, ++ 0x76,0x45,0xbd,0xb7,0x10,0xbd,0xf4,0x93,0xc1,0xd7,0x86,0xe2,0xba,0x17,0x8c,0x60, ++ 0x41,0x6a,0x0c,0x68,0x15,0x38,0x27,0xd7,0xc2,0xea,0xe2,0xdc,0x75,0x77,0xe6,0x64, ++ 0x7e,0x95,0xe5,0x4f,0xb3,0xa4,0xb2,0x12,0x6e,0x5b,0x71,0x14,0x51,0x36,0xf6,0x61, ++ 0x47,0x48,0x36,0xf2,0x12,0x2c,0x03,0x13,0xe7,0x6a,0xed,0x97,0x04,0x12,0x5c,0x86, ++ 0x50,0xb7,0x06,0xf7,0x3e,0x5b,0x86,0xdb,0x04,0xf9,0x16,0xdf,0x0c,0xfd,0x70,0x9f, ++ 0x88,0x58,0x3a,0xfe,0xd2,0x3a,0xbe,0xca,0x0b,0xde,0xa0,0x5e,0x1b,0x5c,0xa7,0xfb, ++ 0xca,0x9d,0x73,0xef,0x53,0xcb,0x2f,0x99,0xfd,0xf5,0x85,0x7f,0x13,0x3e,0x71,0x9e, ++ 0x08,0x84,0x4f,0x2d,0xdb,0xc4,0x61,0xbe,0xcd,0x5d,0xe1,0xba,0x58,0xa4,0xe9,0xa7, ++ 0xf7,0xc3,0x46,0x92,0xb7,0x5e,0x64,0xd8,0xf9,0xf3,0xee,0xdd,0x5c,0xd3,0x1c,0xe2, ++ 0x05,0x5f,0x31,0x1b,0xd2,0x1e,0xb9,0x0b,0xe7,0x50,0xa0,0x5d,0x5f,0xdc,0x87,0x79, ++ 0x89,0xab,0x6c,0x48,0x29,0x01,0xf7,0x9a,0x49,0xdd,0x07,0x93,0x90,0x5d,0xd7,0xea, ++ 0x8f,0x53,0x28,0xae,0x99,0xe9,0xa6,0xde,0x4a,0x33,0xce,0x0e,0x7f,0xf2,0x5e,0x04, ++ 0xe5,0x03,0x98,0xf5,0x32,0xc5,0x83,0xc0,0x3f,0xe0,0xcf,0xdc,0x52,0x30,0xd7,0x60, ++ 0x2b,0x5e,0x05,0x69,0x88,0xfd,0x65,0x38,0x41,0x71,0x07,0x74,0xf4,0x34,0x53,0xf0, ++ 0x08,0xc3,0x99,0xf4,0xba,0xe3,0xec,0x22,0xf3,0x45,0x5c,0x59,0x55,0xef,0x17,0x3f, ++ 0x0a,0x75,0x12,0x59,0x74,0x9c,0x1b,0xcf,0x45,0x38,0x2e,0x08,0xf7,0x9f,0xb4,0xb1, ++ 0x28,0x24,0xa8,0x42,0x91,0x15,0x8f,0x09,0xcb,0x32,0xc8,0x99,0xa3,0x87,0xa8,0xf7, ++ 0xfc,0x8f,0x96,0xf7,0xe6,0x03,0xd8,0x61,0x61,0xa1,0x86,0x70,0x34,0x20,0xf2,0x62, ++ 0xfb,0xe8,0x4d,0x3c,0x5c,0x57,0x39,0x13,0x0e,0xa5,0x0a,0x97,0xe6,0x17,0x6a,0xd7, ++ 0xa9,0x4a,0x7a,0xa4,0xb5,0xbc,0x27,0x91,0xc3,0xfa,0x2a,0x84,0x5b,0xa6,0x99,0x7a, ++ 0x8c,0x97,0xdb,0x2a,0xf5,0x19,0xbc,0xd3,0xe1,0x8a,0x0d,0x61,0x5a,0x6b,0x70,0x15, ++ 0x75,0x26,0xb9,0xbb,0xea,0xe8,0x60,0x53,0x35,0x66,0xd2,0x5c,0xaa,0xab,0x79,0x09, ++ 0x1e,0xcb,0xb5,0x6d,0x63,0x07,0xac,0xf8,0x31,0x8b,0x6d,0xed,0x7d,0x15,0x8b,0x69, ++ 0xef,0x0c,0x84,0x60,0x44,0x26,0x9b,0x49,0xaf,0x4c,0xa7,0xb2,0x09,0xc8,0x39,0x69, ++ 0x71,0x02,0x39,0x38,0xe5,0x07,0xb2,0xea,0xee,0xc1,0xac,0x8c,0x5a,0x69,0x85,0x64, ++ 0x21,0x78,0x06,0x2d,0x35,0x5b,0x24,0x98,0x4b,0xf0,0xc4,0x9c,0x3d,0x1b,0xb8,0x6d, ++ 0x8a,0xe7,0x9b,0x4b,0x7e,0x51,0x88,0x4c,0x6f,0x31,0xe1,0xbd,0x35,0xaa,0x39,0x60, ++ 0xc8,0x14,0xd5,0xbd,0xfe,0xab,0x49,0x4b,0x0c,0x60,0x85,0x78,0xfb,0x4b,0x90,0xe0, ++ 0xdf,0xf5,0x1f,0x36,0xd0,0x6f,0x14,0xdb,0xc5,0x5a,0x00,0xc4,0x1c,0xb3,0xd3,0x7a, ++ 0x2e,0xd3,0x1c,0x12,0x18,0x4f,0x44,0x5a,0x71,0x90,0x47,0x4e,0x75,0x4a,0x1d,0x7d, ++ 0x08,0x9f,0x65,0x22,0x51,0x29,0xb2,0x21,0xc6,0xa0,0x4a,0xd4,0xde,0x21,0x6d,0x46, ++ 0x44,0x3c,0x97,0x64,0xc1,0x1e,0x2f,0xb2,0x1a,0x5e,0x3d,0x33,0xa1,0xa2,0x73,0x2a, ++ 0x59,0xd9,0xec,0xc2,0xb1,0x05,0x13,0x19,0xd3,0x42,0xa6,0xc4,0x9d,0x90,0x94,0xa1, ++ 0x5f,0xf9,0x13,0x3e,0x99,0xf8,0x28,0x89,0xb1,0x7a,0x01,0x1a,0x77,0x4e,0x1b,0xfa, ++ 0xc5,0x69,0xb5,0xfe,0xac,0x0b,0x5a,0xa4,0x38,0x79,0xcd,0xc3,0x1f,0x3c,0x0b,0x02, ++ 0xa6,0xb7,0x7a,0x28,0xa5,0xfa,0x2d,0x53,0x0a,0xa7,0x97,0xd3,0x0b,0xe6,0xb5,0x79, ++ 0x50,0x37,0x35,0xc9,0xf6,0x72,0xe2,0x54,0x48,0xde,0x1a,0xc1,0xa2,0x07,0x74,0x86, ++ 0x15,0x36,0x6e,0x3b,0xc6,0x62,0xba,0x45,0x49,0x76,0xd6,0xb9,0xde,0x9c,0x77,0x78, ++ 0x86,0xdb,0xaf,0x8b,0xb5,0x5b,0x17,0xf2,0x4d,0x50,0x0e,0x31,0x7f,0xbe,0x8f,0xe9, ++ 0xcf,0x1c,0xaf,0xec,0xdb,0xb1,0x9f,0xc9,0x8f,0x5c,0x00,0x5d,0xfb,0x98,0xf6,0xb8, ++ 0xc5,0x4d,0xb4,0xce,0xc9,0xd2,0xda,0x98,0xa4,0xff,0x2d,0xee,0x97,0x36,0x7c,0x24, ++ 0x94,0x39,0xaf,0xb8,0xe9,0xb5,0x2e,0x09,0x4d,0x70,0xa5,0xfe,0x7b,0x4d,0x19,0xf6, ++ 0x47,0x54,0xbe,0x7c,0x1b,0x48,0x09,0x4a,0x0f,0x78,0x0a,0x03,0xfe,0x41,0x78,0x39, ++ 0x4f,0x34,0xeb,0xfb,0x30,0xfe,0x2b,0xca,0x93,0x70,0x53,0x8c,0xdd,0x59,0x9b,0x73, ++ 0x79,0x89,0xbe,0xb5,0xda,0x03,0x80,0x5f,0x9a,0xcb,0x42,0x1b,0x3e,0xff,0x12,0x12, ++ 0x93,0x40,0xee,0xb4,0xfa,0xa2,0x38,0xba,0x65,0x4c,0x23,0x76,0xf0,0x9c,0x21,0xeb, ++ 0x69,0xf3,0xff,0xb4,0x79,0xa1,0x31,0xcb,0x35,0xcb,0xee,0xa1,0x84,0x1c,0xba,0xb0, ++ 0x7d,0x40,0xb7,0xb0,0xf1,0x3f,0xe0,0x16,0x60,0x3c,0xb1,0x57,0x25,0xe0,0xc8,0x2c, ++ 0x61,0x24,0x16,0xd3,0x30,0x29,0xa7,0x82,0xc0,0x0c,0xc8,0x71,0xd0,0x4c,0x70,0x00, ++ 0x07,0x0a,0xe2,0xd1,0x50,0xc5,0x20,0x12,0x02,0x65,0xa0,0x07,0x63,0xe2,0x39,0xc3, ++ 0x83,0x64,0x41,0x54,0xe2,0xdb,0x9d,0x03,0x83,0x06,0xae,0x07,0x93,0x26,0x71,0x01, ++ 0xc3,0x08,0x99,0x37,0x97,0x87,0x21,0xf3,0xc6,0x7e,0x26,0x70,0xac,0x98,0x59,0x08, ++ 0x0e,0xd8,0x7d,0x7e,0x72,0x6b,0xbe,0x0c,0x99,0xb5,0x25,0x9d,0x5e,0x4b,0xda,0x3c, ++ 0xa8,0x96,0x1d,0x62,0xd3,0xf8,0x43,0xf8,0xec,0xe6,0xf2,0x5e,0xae,0x2b,0x92,0x17, ++ 0xa2,0xfe,0x78,0x4a,0x65,0x8c,0x38,0x52,0xe9,0x9a,0x82,0xef,0x79,0x95,0xbf,0x7b, ++ 0x06,0x8d,0x83,0x99,0x70,0x88,0xc9,0x31,0x6c,0xe4,0x1c,0x49,0xfd,0x6d,0x22,0x08, ++ 0x0c,0x01,0xd5,0x9f,0x76,0x51,0x08,0x69,0xe9,0x4a,0x42,0x1f,0x62,0xcd,0x72,0x08, ++ 0x2b,0x02,0x80,0xa2,0xb8,0x2b,0x56,0xef,0x0b,0x42,0xc0,0xf8,0x26,0xeb,0x49,0x48, ++ 0x29,0x6b,0xa3,0x0c,0x21,0x23,0xdb,0x11,0x69,0x48,0xc2,0x92,0xfe,0x95,0x73,0x09, ++ 0x8a,0x00,0xc7,0xa6,0x3a,0xa5,0x3b,0x3d,0xf7,0xcd,0xbb,0x39,0x95,0x62,0x94,0xc7, ++ 0xc9,0x81,0x87,0xf7,0x5a,0xb1,0x29,0x70,0x3c,0xfb,0xf4,0xe5,0x89,0x7d,0x99,0x03, ++ 0x59,0xce,0xde,0x24,0xce,0x9e,0x64,0x10,0x8a,0x72,0x96,0xb0,0xd2,0x77,0x63,0xbd, ++ 0x5f,0xbf,0x7a,0x76,0x9e,0x9f,0x6d,0x81,0x00,0xf6,0xdf,0x5b,0x53,0x7f,0x9d,0xf3, ++ 0x4a,0x62,0x5d,0xd2,0x58,0x50,0x7d,0xb3,0xb8,0x5e,0x91,0x56,0x50,0xf9,0xb4,0xa2, ++ 0x61,0xe4,0xfa,0xfc,0xbf,0xb2,0x34,0xa1,0x95,0x59,0xea,0x99,0xd1,0x11,0x44,0x72, ++ 0xd2,0x1a,0xdd,0xd5,0xb3,0x55,0x50,0x0b,0xc2,0xdd,0xb9,0x09,0xf0,0xd8,0x4f,0xe1, ++ 0x01,0x10,0xc4,0x85,0xfa,0x9d,0x1f,0x1a,0x41,0x50,0xeb,0x05,0x51,0xad,0xf9,0xaa, ++ 0x00,0x11,0x93,0xfd,0x4c,0x9a,0xdd,0x13,0x88,0xb6,0x4e,0xc5,0xfb,0xc8,0xb2,0xea, ++ 0xc3,0x89,0xe0,0xb1,0xd1,0x7b,0xd2,0x2d,0x66,0xd2,0x6d,0x4e,0xd9,0xf2,0x76,0x9c, ++ 0xc9,0x98,0xa8,0xa0,0x1f,0x9d,0x25,0x89,0xc8,0xd8,0xe0,0xde,0x3a,0xa6,0x97,0xfa, ++ 0xc4,0xb1,0xe1,0xb1,0xbb,0xfa,0x13,0xd0,0xc9,0x78,0xe8,0x4f,0x7a,0x52,0xe5,0xbd, ++ 0x16,0xa6,0x18,0x38,0x34,0x96,0xd6,0x4a,0x6d,0xd6,0xe7,0xdf,0xba,0xc4,0x4e,0x5d, ++ 0xd7,0x13,0x53,0x8b,0xf8,0x2c,0xd7,0x6c,0x04,0xba,0xec,0x5d,0x02,0xe3,0x36,0x5a, ++ 0x2e,0x39,0xac,0xd4,0x3a,0x9d,0xcf,0x87,0xaa,0x3f,0x84,0xfd,0xa5,0xc2,0x27,0x8d, ++ 0xf5,0x93,0xcf,0x4d,0x53,0x8f,0x47,0x8b,0xee,0xfe,0x17,0x98,0xfb,0x12,0x77,0x89, ++ 0xa3,0x10,0x91,0xf4,0xb7,0x3b,0x15,0xec,0xcb,0x52,0xe5,0x63,0x08,0xd2,0x21,0x78, ++ 0x65,0x84,0xb2,0x4c,0xeb,0x2d,0xe6,0xa0,0xc4,0xba,0x38,0x31,0xb5,0xef,0x42,0x23, ++ 0x35,0x2e,0x96,0xb3,0xcb,0x0c,0x80,0xc1,0x23,0xd1,0xf2,0xcd,0xf6,0xe7,0x43,0x01, ++ 0xa0,0x09,0xf7,0xb7,0x63,0xcc,0x11,0x3b,0xf7,0x5a,0xd1,0x66,0x21,0xef,0x89,0x61, ++ 0xe7,0x75,0x79,0x89,0x94,0x63,0x81,0xc0,0xab,0xc5,0xb5,0xd1,0x74,0x69,0x00,0x02, ++ 0x00,0x89,0x1b,0xa4,0xff,0xf5,0x08,0x46,0xa7,0x6b,0x0f,0x34,0x15,0x14,0x62,0x42, ++ 0xa4,0x83,0x6d,0x25,0x67,0x23,0x6b,0x81,0x3f,0xc3,0x86,0x4f,0x47,0xa8,0x6b,0x47, ++ 0x25,0x8b,0x4d,0xd5,0x86,0xae,0xe0,0x90,0xfa,0x69,0x61,0x8f,0x17,0xab,0xe1,0x63, ++ 0xe4,0xa7,0xe8,0x17,0xdf,0x0c,0xf1,0x36,0x66,0x4d,0x87,0x4b,0x9f,0xec,0x5c,0x0d, ++ 0xad,0xc9,0xf8,0xdf,0x6c,0xb7,0x12,0xf2,0xed,0xf7,0xcd,0xcc,0xde,0xc0,0xd5,0x69, ++ 0x67,0xea,0x7e,0x8d,0x77,0x04,0x42,0x1a,0xad,0x6d,0xc2,0xbc,0x54,0x36,0x1d,0xbf, ++ 0xe4,0x87,0x99,0xe9,0x11,0x07,0x19,0xfb,0x90,0x61,0x49,0x4d,0x9f,0x55,0xd0,0x64, ++ 0xed,0x9a,0x7b,0x8c,0xff,0xa3,0x43,0x07,0x26,0x3a,0x83,0xef,0x26,0xe4,0x1a,0xc8, ++ 0x0f,0xe1,0xf3,0x4a,0x9e,0xde,0x89,0x88,0xcc,0xe4,0xcc,0x8e,0x7d,0xac,0x50,0xb8, ++ 0x8d,0x85,0xeb,0x1e,0x57,0x20,0x02,0xf8,0x46,0xf2,0xec,0x1c,0xa0,0x40,0x1b,0xc9, ++ 0x8f,0xeb,0xdd,0x63,0x13,0x28,0x8a,0x09,0x8d,0x71,0xf5,0x12,0x37,0x3f,0x9f,0xb9, ++ 0x0d,0x87,0x95,0x77,0x1f,0x5f,0x43,0x2b,0xcb,0xc0,0xec,0xfb,0xa9,0x4e,0xc1,0x72, ++ 0xa4,0x8f,0x70,0x15,0x48,0x1f,0x66,0x05,0x62,0xf3,0xcc,0x24,0x7d,0x4f,0xbc,0x63, ++ 0x86,0xd1,0x3f,0x65,0x13,0xdd,0xbb,0xc8,0x0d,0xdc,0x84,0x66,0x8e,0xfe,0x1e,0xf3, ++ 0x24,0x84,0x71,0xf4,0x92,0x14,0xf6,0x4b,0xdb,0xd6,0x8d,0x77,0x03,0xfd,0x1f,0xa3, ++ 0x22,0xd2,0x93,0x26,0x7f,0x42,0x2f,0x0b,0x0e,0x97,0xdd,0xf6,0x71,0xfe,0x04,0x86, ++ 0xa6,0x99,0x61,0xb4,0xdd,0x85,0xf4,0xf3,0x5a,0x7a,0x67,0xd7,0xd7,0x0b,0xe4,0x06, ++ 0x44,0xf5,0x13,0x27,0x0f,0x4a,0x01,0x90,0x24,0x6a,0xa6,0x30,0x0b,0x5a,0x6f,0xc1, ++ 0x05,0x90,0xc5,0xd3,0xdd,0xa7,0xe3,0x8c,0x64,0xfe,0xcb,0xde,0xd8,0x29,0x15,0x51, ++ 0xa2,0xcd,0xd3,0xff,0xd6,0xf7,0x05,0x91,0xa6,0xf7,0x5d,0x07,0x6d,0x24,0x78,0x33, ++ 0x2c,0x3c,0xd8,0x3f,0xd5,0x3b,0x0c,0x1a,0xc2,0x9a,0xbc,0xaa,0xdf,0xfe,0x95,0xd4, ++ 0x98,0xfa,0x1d,0x3a,0xc1,0xda,0x86,0x49,0x0f,0xc9,0xde,0xff,0xf9,0xf4,0xed,0x37, ++ 0x88,0xc6,0xc1,0xb3,0x57,0x39,0x63,0x37,0xdf,0xe1,0xbf,0x0a,0x1d,0xf5,0x49,0xf9, ++ 0x16,0x84,0x6f,0x3e,0x8d,0x6e,0x87,0x48,0x87,0xb7,0xf5,0x44,0x5e,0xfd,0x1e,0x48, ++ 0x2b,0x95,0xfe,0xde,0xd7,0xad,0x0e,0x68,0x67,0x63,0x88,0xe9,0x8f,0xf3,0x34,0x25, ++ 0x8c,0x9b,0x93,0xbc,0x7e,0xfd,0x46,0xaa,0x67,0xd2,0xde,0xae,0xde,0x75,0x3d,0x36, ++ 0x0d,0xfb,0xbf,0xda,0x3c,0x96,0x4f,0x3b,0x15,0xd1,0x43,0x94,0x5d,0xf8,0x3f,0xf4, ++ 0x0e,0x15,0x97,0xac,0x87,0x30,0x21,0xce,0xfb,0x9d,0xdf,0x1d,0xdb,0xff,0xa8,0x38, ++ 0x33,0x12,0x6c,0x84,0xec,0x00,0x12,0x46,0x3c,0x0f,0x37,0xbb,0xbb,0xd6,0xc8,0x76, ++ 0x20,0xeb,0x59,0x0b,0x2f,0x95,0x41,0x20,0xe4,0x2f,0x2a,0x2b,0xbd,0xce,0xb9,0xe1, ++ 0xa9,0x19,0x2d,0x47,0x13,0xf6,0x2b,0xc9,0xd2,0x0d,0xcf,0xbf,0xd4,0xb6,0x59,0x11, ++ 0xc2,0x02,0x29,0x0f,0x1d,0xae,0x7b,0x41,0xc0,0xd1,0xaf,0xc4,0x31,0x23,0xe7,0x6d, ++ 0xda,0x95,0x67,0x79,0xf3,0x8b,0x31,0x20,0x52,0xd0,0x43,0x63,0xf3,0xfb,0xdb,0xa3, ++ 0x7f,0xaa,0xae,0x85,0x12,0x65,0xbb,0x1b,0xe4,0x29,0x8c,0x0e,0x25,0xca,0x7b,0xb2, ++ 0xfa,0xa9,0x93,0x36,0xf0,0x4a,0x46,0x7a,0xb6,0x5d,0x65,0x07,0xae,0xc9,0x19,0xd5, ++ 0xda,0xce,0xd5,0xba,0x7a,0xed,0x66,0xe2,0xe1,0xea,0x89,0x9d,0xa4,0xaa,0x11,0xc9, ++ 0x8f,0x99,0xfc,0x9a,0xf3,0xce,0xaa,0x18,0x9a,0x07,0x3a,0xa6,0xcc,0xfc,0x0e,0xe4, ++ 0x81,0xf2,0xe8,0x02,0xcf,0xdd,0xe2,0xd0,0x49,0x04,0x1e,0xfa,0xcb,0x6a,0xc3,0x69, ++ 0x98,0x44,0xdd,0x9e,0x88,0x85,0x4a,0x27,0xab,0x6a,0x36,0x36,0xb3,0x1e,0x23,0xf5, ++ 0x6d,0x70,0x6c,0xee,0x43,0x80,0x19,0xdf,0xe9,0x9b,0x78,0xc6,0x11,0x9c,0x3c,0xec, ++ 0xff,0x8f,0xbd,0xb4,0x1a,0x57,0xc5,0x18,0xca,0x53,0x2d,0x97,0xd5,0xc1,0x62,0x65, ++ 0xe0,0x49,0x94,0xf1,0x1f,0xd8,0x12,0x70,0x9b,0xbc,0xa3,0x0d,0x79,0x7b,0xe5,0xba, ++ 0xa0,0x85,0x13,0xbc,0xac,0x2d,0x68,0x19,0x4a,0x58,0x87,0xf6,0xb9,0x6a,0x11,0x5a, ++ 0xfd,0xfa,0x5c,0x63,0xef,0x6d,0x7c,0xd9,0xf8,0xd9,0xd3,0x6d,0xe8,0xe5,0x1a,0xdc, ++ 0xb2,0x1a,0x66,0x97,0x0e,0xd6,0x44,0x39,0x6a,0xdd,0x14,0x55,0xa2,0x30,0xd3,0xa5, ++ 0x5a,0x20,0xee,0x90,0xcd,0x75,0x8c,0xd6,0x9a,0xaa,0xc2,0x87,0x75,0xda,0x91,0x21, ++ 0xca,0x60,0xbf,0x76,0x7a,0x99,0x4c,0xa1,0x47,0x49,0x36,0x93,0x2c,0x97,0xcd,0x3d, ++ 0xa1,0x08,0x3e,0x92,0x65,0xe5,0x19,0x35,0xc4,0xf2,0xaf,0xb1,0x74,0x65,0xab,0xd3, ++ 0x04,0x50,0xfa,0x64,0x53,0x30,0x2d,0x1b,0xb3,0x89,0x00,0x77,0x2f,0xd9,0x34,0xd4, ++ 0x96,0x57,0x9c,0x70,0xfb,0x16,0x5e,0x82,0xdc,0x51,0xe2,0x50,0x12,0x71,0x63,0x60, ++ 0x2e,0xbd,0xa4,0x85,0xf6,0x92,0x7e,0x9b,0xc0,0xbb,0x5e,0x95,0x72,0x69,0x0d,0xf3, ++ 0x02,0xc8,0x19,0x3d,0x98,0xfa,0x9d,0x36,0x1a,0xd1,0xbc,0xb5,0xef,0xd3,0xe7,0xee, ++ 0xd7,0x76,0x21,0x13,0x53,0x8e,0x2c,0x57,0xe8,0x79,0x37,0xb6,0xe4,0xcc,0x2e,0x72, ++ 0x40,0xf8,0x2d,0xaa,0xe5,0xdc,0xd9,0x3a,0xe9,0xf3,0xff,0x1c,0xaf,0xc6,0x39,0xa1, ++ 0x76,0x91,0x07,0x7c,0x6a,0x7a,0x4e,0x2d,0x4d,0x51,0xc9,0xa2,0xbe,0x34,0x6e,0xd9, ++ 0xe9,0x55,0xd1,0xae,0xbd,0x90,0x27,0x69,0xb5,0xf0,0xa1,0x00,0x91,0x8c,0xf2,0xaa, ++ 0xd5,0xb8,0x39,0x8b,0xd3,0x5f,0xa9,0x92,0x0b,0x58,0x06,0xb0,0xb2,0x1f,0xea,0x29, ++ 0x88,0x5d,0xd0,0x78,0xa9,0x37,0x83,0x07,0xeb,0x3d,0x8c,0x1a,0x92,0xfe,0x15,0xcf, ++ 0x62,0x7d,0x20,0x3d,0x3a,0x21,0x35,0xeb,0xeb,0xde,0x58,0x05,0x85,0xd3,0xf6,0x5d, ++ 0xa9,0x1a,0xd3,0xae,0xfc,0xbe,0xf2,0x82,0x76,0xf2,0x1f,0x58,0x59,0xd2,0x31,0x11, ++ 0x4b,0x88,0xc3,0x02,0xe8,0xe4,0xb7,0x50,0xbb,0x82,0x67,0x35,0xa2,0x33,0x00,0xea, ++ 0xc9,0xc3,0x0f,0x21,0x7e,0x04,0xd0,0xb7,0xc5,0x41,0xcb,0x8e,0x9d,0xb2,0x07,0xcb, ++ 0x8d,0x39,0x12,0x00,0x40,0x67,0xa9,0x52,0xc5,0xd2,0x97,0x9c,0xae,0x46,0xe6,0xeb, ++ 0xf2,0x46,0x29,0xe6,0x75,0xe3,0x03,0xdb,0x51,0x8c,0x5b,0x24,0xeb,0x05,0xc0,0xb1, ++ 0x28,0x70,0x2a,0x29,0x9b,0x09,0x4d,0x84,0x66,0xa7,0xd0,0xef,0xdb,0x69,0xd1,0x0d, ++ 0x01,0x7f,0xc8,0x96,0x33,0xc9,0x06,0x74,0xa6,0x46,0xf8,0x88,0xda,0x48,0x33,0x31, ++ 0x31,0x7a,0xb1,0x37,0x16,0x20,0x61,0x93,0x51,0xf7,0x16,0x98,0x37,0x60,0xbb,0x18, ++ 0x7a,0xbb,0xd3,0xc4,0xbd,0x08,0x8b,0x80,0x4b,0xca,0xad,0xe8,0x22,0x6e,0xfd,0x22, ++ 0x0a,0xdb,0x0a,0x84,0x88,0x3c,0x6b,0xd6,0xa9,0x37,0x88,0xdd,0x96,0x43,0xd5,0xdd, ++ 0xe4,0x71,0xee,0xd8,0x8f,0xaa,0x60,0x38,0xfe,0x60,0x09,0x39,0x89,0x3f,0xd8,0xe3, ++ 0xfb,0x47,0x06,0x14,0xf7,0xde,0xdf,0x58,0x91,0x3c,0xd1,0x2b,0x20,0xae,0xcc,0xeb, ++ 0x0d,0x94,0x48,0xe4,0x55,0xf8,0xb0,0xb1,0xce,0xab,0x1c,0xa0,0xb6,0x5d,0x5f,0x8d, ++ 0xcc,0xec,0xb6,0x3c,0xd4,0xaf,0x8d,0x96,0x4e,0x8e,0xd2,0x84,0xb7,0xef,0xaa,0x03, ++ 0x69,0x00,0xbe,0xcd,0x31,0x00,0x78,0x24,0xeb,0x20,0xfc,0x96,0x0a,0xa0,0x6b,0x46, ++ 0x6f,0xf1,0x9d,0xef,0x11,0x03,0x74,0x2c,0x33,0xd5,0xe9,0x6d,0x4c,0xe4,0x13,0x7c, ++ 0x2c,0xa7,0x3b,0x2f,0x1f,0xb0,0xbf,0x25,0xc1,0xd1,0xf9,0x99,0x50,0x42,0x63,0x80, ++ 0x6c,0xd2,0x96,0x82,0xb1,0xa6,0x4c,0xae,0x84,0x2f,0xca,0x1b,0x9d,0x23,0x75,0x16, ++ 0x80,0x9a,0xf2,0x99,0x7b,0xff,0xdb,0xc1,0xc6,0x58,0x82,0x0f,0x1f,0x46,0x7d,0xcf, ++ 0x24,0xc4,0x04,0x9d,0x28,0x06,0x6c,0xa3,0x41,0xbc,0xe3,0x19,0x1f,0x21,0xaf,0x7b, ++ 0xbb,0xde,0xcc,0x37,0x63,0x0c,0x1d,0x59,0x86,0xd7,0xc3,0x0e,0x1c,0x60,0x5c,0x38, ++ 0x8a,0x99,0x1b,0x39,0xd7,0x37,0x6f,0xce,0x60,0x6c,0x24,0x04,0xda,0x59,0x8f,0x89, ++ 0xda,0x29,0xd4,0x29,0xc2,0xd6,0xc5,0x82,0x33,0xdc,0xa2,0x14,0x73,0x70,0xc9,0x5c, ++ 0x59,0x0b,0x1a,0x39,0x4b,0x17,0xe6,0x8c,0x45,0x86,0x21,0x05,0x1f,0x3c,0x16,0x57, ++ 0xfe,0x54,0x16,0xa4,0xcb,0x46,0xfd,0xb2,0x8b,0xc2,0x4e,0x15,0x9f,0x06,0xd9,0x88, ++ 0x28,0x63,0x9c,0x7d,0xfa,0x17,0x57,0xea,0x24,0x23,0xe0,0x14,0x97,0x6b,0x89,0x78, ++ 0xcd,0x66,0xd0,0x0c,0xc1,0xfd,0x2e,0xa7,0x2d,0x54,0x89,0x07,0x8e,0xf7,0x36,0x63, ++ 0xbe,0xd7,0x41,0x7e,0x76,0xaa,0x33,0x2f,0xdd,0x73,0x00,0x12,0x08,0x29,0x76,0x9a, ++ 0x0a,0x80,0x1c,0x98,0x69,0x6d,0x66,0xbb,0x4a,0x9a,0xd7,0x39,0x01,0xba,0x5d,0x28, ++ 0x82,0x21,0x98,0xc8,0xd7,0x6d,0xe3,0xdc,0x16,0xcc,0x88,0xd3,0x8b,0x5f,0x50,0xe3, ++ 0x4e,0x99,0x15,0xf9,0x9e,0x42,0xcc,0xc7,0x7f,0x18,0xac,0x9f,0x37,0xbc,0x1f,0x0c, ++ 0x64,0x4f,0x34,0x3c,0x32,0xb3,0xc5,0xd7,0x5e,0x4f,0x64,0x1c,0x8a,0x5e,0x16,0xa1, ++ 0xce,0x9b,0xc9,0xe2,0x3b,0x1b,0x2f,0xdf,0x3b,0x0e,0x58,0xd2,0x7a,0x6e,0x59,0x9f, ++ 0xa5,0x0b,0xe3,0xc4,0x14,0xb4,0x06,0x18,0x46,0xf8,0xee,0x22,0xdd,0xdd,0xf7,0x98, ++ 0xa4,0xbe,0x9b,0x72,0xea,0x20,0x5e,0x0b,0x7d,0x03,0xe1,0x4c,0xc3,0x6b,0x52,0xe9, ++ 0x2c,0x4f,0x0f,0xc3,0x9a,0x39,0x36,0x43,0x3f,0x4b,0xf7,0x23,0xb3,0x66,0x96,0xf1, ++ 0xa7,0x05,0xb1,0x11,0x14,0x01,0x45,0x34,0xf2,0x35,0x5a,0xc5,0xed,0x52,0xcf,0xdf, ++ 0xfd,0xa9,0xf8,0x14,0x1a,0x2b,0x06,0x1d,0xa9,0xbd,0xe8,0xb4,0xed,0x6b,0x37,0x22, ++ 0xc1,0x05,0xc2,0x14,0xb0,0x23,0x60,0x20,0x63,0x4a,0xe0,0x24,0x57,0x6a,0xca,0xdf, ++ 0x75,0x47,0xa1,0xe5,0x2e,0x2b,0xc1,0xe3,0x42,0xce,0xe9,0x35,0xda,0x69,0x32,0x16, ++ 0x7e,0xb1,0x99,0x44,0x32,0xaf,0xc9,0x0e,0xcd,0x25,0x06,0x9b,0xd5,0x9e,0x22,0xcc, ++ 0xa9,0x82,0xdb,0x1b,0xfd,0x46,0xaa,0xd6,0xb5,0x26,0xeb,0x4a,0xa7,0xe3,0x38,0xe7, ++ 0xf0,0x4b,0xbe,0x22,0x39,0x0b,0x09,0x28,0xa2,0xf8,0xca,0xbd,0x11,0xe2,0x84,0xf8, ++ 0x2b,0x4a,0xe1,0x0c,0x9b,0x6a,0xf0,0xe9,0x84,0xe7,0x84,0xa9,0xdb,0x11,0x04,0x8a, ++ 0x28,0x94,0x0c,0x66,0x97,0x2d,0x3b,0x30,0x81,0xda,0xd3,0x10,0x59,0xab,0x79,0x38, ++ 0x8a,0x13,0xc3,0xae,0xb6,0xa7,0x18,0xd5,0xb5,0x20,0xb0,0xe8,0x71,0xba,0xda,0xa7, ++ 0xf0,0xa0,0x4f,0x3e,0x58,0x22,0xca,0xdd,0xbc,0xb0,0x8a,0x58,0xba,0x62,0xf8,0x39, ++ 0x0a,0x18,0x44,0xaf,0x18,0x2d,0x0a,0xd7,0x6f,0xb8,0x13,0x8c,0x42,0x68,0xc4,0xc2, ++ 0xe8,0x0b,0xb3,0xdf,0xb9,0x0d,0x49,0xab,0x34,0x92,0xbb,0x3d,0xca,0xef,0x17,0x68, ++ 0xfe,0x5d,0xe1,0x44,0x91,0xb8,0x1c,0xb0,0x81,0x42,0xce,0x89,0x4c,0x6f,0x8e,0xb0, ++ 0x51,0x71,0x31,0xd3,0xfb,0xd9,0x1a,0x58,0x99,0xfc,0x09,0x5e,0xd4,0x1d,0x5d,0x84, ++ 0x82,0x83,0x8d,0x67,0x8f,0x12,0xed,0x85,0x1d,0x59,0x2d,0x5a,0x93,0xe3,0xcd,0xe8, ++ 0x35,0xbe,0x85,0x91,0x19,0x8d,0x0a,0x57,0xd2,0xe6,0x7a,0x4b,0x55,0x9e,0x1d,0x6a, ++ 0xcb,0xcc,0xfc,0x14,0xff,0xbc,0xad,0x93,0x58,0x36,0x78,0x7a,0x71,0x64,0xb4,0xf4, ++ 0x54,0x23,0xb5,0x36,0xb1,0xd6,0x98,0x92,0x20,0xea,0xcc,0x74,0x86,0x7a,0xbd,0xc9, ++ 0x4b,0xee,0xc4,0x27,0x13,0xbc,0xa8,0xc5,0x60,0x5e,0x8f,0x82,0x8e,0x34,0x92,0x13, ++ 0x90,0xbb,0x19,0xb7,0xf0,0xc9,0x25,0x93,0xa0,0x28,0x62,0xc4,0x52,0xd6,0x93,0x3a, ++ 0xd7,0x08,0x3b,0xbd,0x99,0x07,0xae,0xd9,0x10,0x51,0x52,0x53,0x1b,0x72,0xbb,0x7e, ++ 0xa9,0x61,0x4d,0x6c,0x0d,0x08,0x1f,0x48,0x2d,0x16,0x21,0x5e,0x65,0x7d,0x3d,0x7a, ++ 0xd0,0x01,0x2b,0x1e,0xff,0x30,0x16,0xdb,0xfa,0x15,0x02,0x29,0xfb,0x0b,0x31,0xb4, ++ 0x4b,0xc4,0xf6,0xfb,0x46,0xb0,0x8f,0x51,0x19,0x16,0xf4,0x99,0x74,0xf6,0xfe,0xf8, ++ 0x2e,0xa3,0xbe,0x4e,0x3f,0x35,0x2e,0x6a,0x48,0x29,0xee,0x13,0x83,0xdd,0x35,0xfc, ++ 0xc2,0xd7,0xae,0x98,0x6c,0xbd,0x66,0x28,0xd4,0x52,0x05,0xec,0x18,0x69,0x06,0xaf, ++ 0xc8,0x1e,0xfd,0x2f,0x16,0x31,0x6f,0xb9,0xaa,0x51,0xef,0xdc,0x5b,0xc1,0x11,0x3b, ++ 0xaf,0x9a,0xb7,0xfa,0x1a,0xb7,0x3f,0x59,0xe9,0xd4,0xc8,0x79,0xdb,0xe5,0x94,0x60, ++ 0x89,0x76,0xc5,0xc6,0xb7,0xbb,0x0e,0x1a,0xc9,0x46,0xe9,0x2d,0xb1,0x91,0xd3,0x96, ++ 0x26,0x92,0x97,0xf4,0x95,0xc3,0x2f,0x52,0x0d,0xaf,0x2d,0x48,0xf6,0x91,0xde,0x79, ++ 0x4e,0x8d,0xb6,0x83,0x97,0xe3,0x33,0x63,0x0b,0x6f,0xa3,0xe7,0xd2,0xe8,0x70,0x34, ++ 0x20,0xc1,0xf0,0x2f,0x93,0xa9,0x5b,0x23,0xc4,0xf3,0x99,0xb9,0xe6,0x72,0x19,0x33, ++ 0x53,0x92,0xba,0xdf,0xb5,0xa2,0x22,0xfd,0xb1,0x85,0x88,0x14,0xa9,0xa6,0x00,0x6f, ++ 0xec,0xc1,0x13,0xb4,0xb6,0x2f,0x79,0x94,0x63,0xb9,0x78,0x97,0x5a,0xe3,0xf1,0xe6, ++ 0x71,0x0d,0x69,0x82,0x37,0x2c,0x4b,0x8b,0x78,0x89,0xad,0xd2,0x37,0x19,0x33,0xd8, ++ 0xf1,0x28,0x96,0xb5,0x15,0xef,0xc6,0x3c,0x52,0x1a,0x0f,0xb1,0x76,0x65,0x2d,0x4f, ++ 0xad,0x17,0x32,0x75,0xbf,0xb3,0x08,0xc2,0xbc,0x87,0x0a,0x69,0x52,0xee,0x11,0x84, ++ 0x0e,0x29,0xca,0x95,0x1e,0xa6,0xaa,0xd2,0xb5,0x84,0xbe,0x51,0xd0,0xf2,0x97,0x69, ++ 0x01,0x7c,0xb4,0x69,0x11,0xc8,0x32,0x58,0xb4,0x85,0xd6,0xef,0x7f,0x91,0xeb,0x62, ++ 0x19,0xc5,0xa1,0x1d,0x3e,0xad,0xc4,0xfc,0x0f,0x4b,0x9e,0xa9,0xde,0x59,0xc6,0x6e, ++ 0xe7,0x3d,0x28,0x3c,0xbd,0xaa,0xdb,0x4e,0xc3,0x61,0x8a,0x9e,0xf3,0x5d,0x14,0x5c, ++ 0xee,0x0e,0x62,0xab,0x7c,0xdc,0xe5,0xe8,0x4f,0x8c,0x01,0x8e,0xf2,0x1c,0x75,0x29, ++ 0xee,0x88,0x6b,0x83,0x3d,0xa8,0x2b,0xf9,0x86,0x63,0x33,0x4f,0xdc,0xe3,0x0e,0xa8, ++ 0x03,0xce,0x93,0xdd,0xbe,0x5e,0x45,0xd3,0x42,0xad,0x3b,0x5f,0xdd,0xe2,0xe2,0x73, ++ 0x5c,0x30,0xb7,0x02,0x37,0xcb,0x24,0xd5,0x68,0x9d,0x53,0x59,0x95,0x76,0xff,0x16, ++ 0x7c,0x24,0xe4,0xbb,0xb5,0x71,0x84,0x4d,0xea,0x57,0x10,0xd0,0xab,0x2c,0x7c,0x1c, ++ 0x01,0x99,0xb5,0x06,0xfc,0x39,0x37,0x45,0xd7,0x47,0xb5,0x59,0xc7,0x79,0x95,0xd4, ++ 0x67,0x11,0xf4,0x9c,0x50,0xc2,0xbd,0xf3,0xa5,0x2e,0xa7,0xb5,0x1e,0xfc,0xd7,0x20, ++ 0x02,0xda,0x64,0x24,0xb4,0xfc,0xf3,0x00,0xe4,0xd7,0xcc,0x1c,0x70,0xf5,0x35,0xdd, ++ 0xc0,0xd4,0x8c,0x92,0x0c,0xba,0x76,0xe7,0xc4,0xd3,0xf4,0xe6,0x48,0xd5,0x71,0x05, ++ 0xca,0x1b,0x3c,0x37,0xbe,0xb9,0xc4,0x81,0xa5,0xd9,0xb8,0x85,0x79,0x60,0xd6,0x35, ++ 0xb7,0x6a,0x8d,0x93,0xc8,0x3a,0x2d,0x62,0x84,0xf7,0xdd,0xf3,0xc8,0xf7,0x2e,0x3b, ++ 0xa9,0x1b,0xb4,0x4e,0x3a,0xb2,0x3c,0xa8,0xcb,0x99,0xf7,0xc8,0x1d,0xfc,0x70,0xa3, ++ 0x69,0x14,0xbc,0x9f,0xc6,0x34,0x40,0xef,0x5e,0x0b,0x62,0xd8,0x8a,0xe9,0x1d,0x6d, ++ 0x2c,0x6b,0x32,0xf1,0x1f,0x87,0x6e,0xa0,0x09,0x65,0xd1,0x4d,0xd8,0xe1,0x51,0xa3, ++ 0xce,0xc9,0x7b,0x65,0x54,0x71,0x87,0x41,0x14,0xb7,0x07,0x40,0x70,0x56,0x9e,0x22, ++ 0x88,0x41,0x9e,0x4c,0x3b,0x67,0x0e,0x68,0x4c,0xbe,0x4d,0x3e,0x76,0x85,0xfe,0xa8, ++ 0x47,0x96,0xce,0xbc,0x7c,0x43,0x2e,0xe2,0x0c,0xbd,0xb3,0x84,0xdc,0x0d,0x9f,0xc3, ++ 0x53,0xd1,0xe5,0x2d,0x3c,0xf6,0x2d,0xfe,0x4d,0xd8,0xef,0xfe,0xf8,0xff,0x11,0x3b, ++ 0xcc,0xbf,0x97,0x5d,0xd1,0xdc,0x07,0x79,0xea,0x25,0xf8,0x21,0x60,0xbe,0x3a,0xe8, ++ 0x52,0x4f,0xf3,0x42,0x16,0x1b,0xc9,0x96,0x7b,0xf2,0xe8,0xa6,0x51,0xe7,0xfe,0x7c, ++ 0xa0,0x6d,0x29,0x82,0x12,0x61,0x1f,0x89,0xa0,0xee,0x34,0xab,0xae,0xfc,0x51,0x18, ++ 0xd0,0x04,0xa0,0x72,0x1d,0x39,0xd1,0xa1,0x30,0x41,0xa9,0xdf,0x7c,0x6f,0x6b,0x80, ++ 0x80,0x63,0x9d,0xb7,0xb3,0x13,0x8e,0xd9,0x83,0x0e,0x7a,0xcb,0x2c,0x78,0x11,0x33, ++ 0x2c,0x85,0xb8,0x02,0x72,0x66,0xfc,0x13,0x28,0xe2,0xae,0xc5,0xb9,0x27,0x98,0xaa, ++ 0x68,0x0d,0xd8,0x61,0x1c,0x26,0x8a,0xb0,0x07,0xce,0x82,0x26,0x6b,0x27,0xc1,0xba, ++ 0x63,0xa5,0x12,0xe3,0x93,0x6c,0x87,0x12,0xa0,0xe0,0xaf,0xc0,0x33,0x59,0x49,0x42, ++ 0xf7,0x2f,0x5b,0x71,0xa0,0xf3,0xa6,0x82,0xa1,0xe8,0xc9,0x3c,0x72,0x6e,0x58,0x09, ++ 0xaf,0x0b,0xc6,0x88,0x18,0xea,0xed,0x5b,0x34,0x24,0x12,0x72,0xd5,0x0a,0x18,0xe3, ++ 0xf6,0x65,0xda,0x15,0xba,0x32,0x52,0x9d,0xb6,0x25,0x65,0xbe,0x58,0xee,0x45,0xd5, ++ 0x61,0xa3,0xda,0x9c,0x3d,0x2c,0xf4,0xe9,0xd5,0x08,0x38,0xa8,0x4b,0x55,0xcf,0x28, ++ 0x28,0xaa,0x49,0x7b,0x1b,0x28,0x79,0xa8,0xca,0x8b,0x20,0xdf,0x75,0x96,0xf7,0xe9, ++ 0xbe,0x0f,0x78,0xbd,0xb9,0x4c,0x04,0x56,0x28,0xb9,0x85,0xe8,0x7a,0xdb,0x8a,0x85, ++ 0x78,0xa0,0x26,0x33,0xc5,0xa6,0xf2,0x5d,0xce,0x7c,0x22,0x55,0x5d,0x6c,0xf4,0xec, ++ 0x7e,0x4d,0xf1,0x0a,0x94,0xd1,0x05,0x4d,0x4f,0x6f,0xeb,0x8d,0xb4,0xe5,0xd8,0xdd, ++ 0xfd,0x95,0xeb,0xb7,0xae,0x39,0xb3,0x49,0x49,0x4b,0x9b,0x1f,0xf8,0xbe,0x97,0x50, ++ 0x28,0xef,0x48,0xe6,0x71,0x10,0xb0,0xdf,0xc3,0xf0,0xaa,0x70,0x32,0xdf,0x47,0xa1, ++ 0x5d,0x53,0xb4,0xc4,0x33,0x3e,0x62,0x8d,0x52,0xd3,0xe2,0x89,0x98,0xbb,0xba,0x91, ++ 0x1f,0x99,0xfd,0x07,0xb9,0x56,0x82,0xa3,0x25,0xdf,0x06,0xd6,0xbb,0xf0,0x45,0x74, ++ 0x1c,0x1c,0xed,0xd5,0xbf,0x3e,0xa5,0x4e,0x08,0xa2,0xc3,0x57,0xf5,0xf6,0x3c,0x68, ++ 0xc9,0x27,0x83,0x40,0x44,0x80,0xd0,0x64,0x37,0x5e,0x6b,0x77,0x5c,0xa9,0x8c,0x6c, ++ 0xd1,0xee,0x77,0x14,0x3d,0x59,0x58,0x83,0x1e,0xd3,0x7f,0x50,0xaf,0x16,0x1e,0xfa, ++ 0xd9,0xce,0x9f,0xc7,0xb4,0x85,0xb9,0x92,0xc1,0xd0,0xb3,0x41,0xf1,0xb6,0x27,0x2d, ++ 0x7d,0x55,0xf3,0xa8,0x71,0x17,0x5d,0x31,0xe7,0x7e,0xf8,0xc8,0xeb,0x40,0x38,0xb5, ++ 0x40,0xb1,0x8c,0x88,0x9b,0x35,0xba,0x37,0x6b,0x88,0x03,0x57,0x91,0x77,0xd2,0xf7, ++ 0x8a,0xec,0x84,0xbc,0x9a,0x34,0x56,0x7d,0x82,0x3d,0xb8,0x68,0xda,0xfc,0x15,0x51, ++ 0xae,0x10,0x8d,0x9d,0x1b,0x37,0xd7,0x69,0xc6,0x18,0x46,0x57,0x11,0x8b,0x9c,0xa7, ++ 0xd1,0xae,0x85,0xdd,0x1a,0x3d,0xa0,0x5b,0xa1,0xaa,0xb9,0x5f,0xf8,0xd4,0x13,0xc8, ++ 0xfe,0x9f,0xce,0xd4,0x3c,0xef,0x9d,0x2e,0x42,0x47,0x51,0x5a,0x93,0x5f,0x9c,0xcb, ++ 0x41,0xfe,0xee,0xcc,0x08,0x49,0x07,0xbb,0xce,0x02,0x8e,0x0e,0x5a,0xb4,0xe0,0x78, ++ 0x62,0x9d,0x5b,0x49,0xcc,0x9a,0xf4,0x9f,0x15,0xe1,0xad,0x0d,0xf6,0xd3,0x8f,0x65, ++ 0x59,0xbe,0x15,0xdc,0x36,0x92,0x5e,0x9f,0x54,0xe9,0x33,0x8e,0xd1,0xf9,0x18,0x32, ++ 0x9e,0x2f,0x27,0xe4,0x93,0xa0,0x8f,0xa6,0x47,0xaa,0xc8,0xa4,0x55,0x07,0x56,0x15, ++ 0x03,0x83,0xec,0xf0,0x97,0xe9,0xec,0xcd,0xc8,0x47,0xc7,0xc9,0x53,0xa8,0x81,0x71, ++ 0xe6,0xd3,0x09,0x03,0x75,0xb9,0x11,0xaa,0xc2,0xc8,0xeb,0x26,0x77,0x6f,0xa7,0x0c, ++ 0xf1,0x57,0x63,0xe7,0x99,0xac,0xac,0xf3,0x87,0x3e,0xaf,0x71,0x93,0xa2,0x76,0xe3, ++ 0xed,0xa7,0xe8,0x42,0x96,0x67,0x7a,0x00,0x05,0x33,0xdf,0x0d,0x8f,0x11,0x38,0xd6, ++ 0x71,0xdf,0x8a,0x52,0x14,0xe6,0x64,0x0a,0x41,0x9f,0x54,0x09,0x9d,0xc6,0xda,0xf2, ++ 0xa4,0x29,0xb8,0x48,0x73,0xca,0x09,0x43,0x92,0x86,0xe2,0xe3,0x9d,0xd5,0x7f,0xf6, ++ 0x6c,0xe4,0x33,0x53,0x17,0x76,0x99,0xf7,0x8e,0xe7,0x42,0xe4,0xf5,0xed,0x35,0x11, ++ 0x7c,0x1c,0xc2,0x4a,0x0b,0xa7,0x28,0x2f,0xb3,0x1d,0x8c,0x5e,0x7f,0x88,0x14,0x27, ++ 0x80,0x2f,0x75,0xfc,0xb1,0x22,0xee,0x06,0xa6,0x8d,0x27,0x0d,0xd8,0xa9,0xb6,0x79, ++ 0x67,0x7b,0xc3,0x4b,0xbd,0x21,0x67,0x3a,0xe6,0x41,0x73,0x47,0x11,0xa8,0x35,0xdb, ++ 0xe7,0x26,0x54,0xfd,0x1f,0xe3,0x01,0x8b,0x2b,0x64,0x2b,0xbb,0xab,0x9e,0xd9,0xfb, ++ 0x28,0x23,0xbb,0x50,0xfb,0x53,0x2b,0x71,0xab,0xa0,0x70,0x70,0x7c,0x18,0x40,0x29, ++ 0x7b,0x29,0x57,0xc5,0x7c,0xa9,0x2a,0x4b,0x57,0xcc,0xc7,0x25,0xa3,0x5c,0xb3,0xda, ++ 0xf6,0x8a,0x4f,0xca,0x65,0xc2,0x11,0x6e,0xcd,0x5e,0xa7,0x64,0xaa,0x52,0xfc,0xb9, ++ 0x6f,0x2b,0x92,0x33,0x0d,0xa5,0xed,0x6f,0xef,0x0f,0x3b,0xae,0xe5,0x83,0x37,0xb8, ++ 0x18,0x8b,0x2c,0x85,0x95,0x38,0x14,0xc8,0x40,0xd1,0xb8,0xf9,0xc9,0x0c,0x8b,0xae, ++ 0xf1,0x20,0x8c,0xf4,0x74,0xb5,0x65,0x87,0xc0,0xd8,0xd6,0x5a,0xab,0xb3,0x21,0x07, ++ 0xa6,0xa2,0xa1,0x65,0x36,0xfa,0xb5,0xa7,0xcc,0x45,0x1e,0xc9,0x21,0x89,0x0a,0xab, ++ 0x75,0xe2,0xd5,0x7f,0xb3,0xfe,0xbd,0x92,0x17,0xd0,0x72,0x4f,0x9e,0xf0,0x5c,0x3d, ++ 0x93,0xd6,0x7b,0x54,0x3e,0xbc,0x2e,0xe0,0xd5,0x89,0xe4,0x95,0x54,0x72,0x33,0x8e, ++ 0xaa,0x38,0xf4,0xd2,0xb0,0xd4,0xbd,0x8d,0xea,0xb7,0x28,0x64,0x57,0x58,0xb6,0x48, ++ 0xd5,0x23,0xe3,0x2f,0x2a,0x7b,0x6f,0xe1,0x74,0xdc,0xf1,0x27,0xe9,0x5b,0x38,0x5c, ++ 0x18,0x3a,0x7d,0xc8,0x8b,0xf5,0x82,0x34,0x5a,0x21,0x2d,0x65,0xff,0xfd,0x20,0xb7, ++ 0xac,0x14,0xbc,0x8f,0x1f,0x8b,0xf6,0x2b,0xee,0x24,0x51,0x5f,0x56,0x76,0x7a,0x64, ++ 0x52,0x08,0x55,0xb9,0x9c,0x46,0xba,0x7d,0xed,0xf9,0x6a,0x6c,0xb5,0x08,0x1d,0x78, ++ 0x8e,0x35,0xc7,0xcf,0x3d,0xb7,0x4f,0xc9,0x0e,0xba,0xe9,0x0b,0x22,0x51,0x70,0x64, ++ 0x92,0xbb,0xcf,0xdf,0x53,0x36,0x93,0xfb,0xe9,0xfa,0xa8,0xcc,0x85,0xf2,0x37,0x44, ++ 0x99,0xde,0x2d,0xe5,0xbc,0x4a,0xcf,0x9a,0xee,0xca,0xba,0x1f,0xdd,0xbc,0x38,0x29, ++ 0x45,0x40,0x5a,0xbc,0xd4,0x0c,0x5e,0xef,0xed,0xd9,0xfa,0x7a,0x5f,0x5c,0x32,0xcb, ++ 0x53,0x3f,0x8d,0xad,0x55,0x2f,0x7f,0xfb,0x69,0xef,0xc9,0xd6,0x7c,0xfb,0x39,0x6b, ++ 0x44,0x1c,0xb5,0x20,0x54,0xbc,0x75,0x99,0xae,0xd7,0xe9,0x5e,0x00,0x52,0x50,0xbc, ++ 0xf7,0xab,0x10,0x76,0xfb,0x91,0xe8,0x23,0xf3,0x02,0xae,0x84,0xf7,0xcd,0xc8,0x30, ++ 0x7b,0x0c,0x70,0x1c,0xb6,0xfa,0x70,0xc3,0xcd,0x4c,0x0b,0x46,0x3b,0xd0,0x79,0x05, ++ 0x69,0x93,0xff,0x39,0xa3,0x0e,0x9b,0x3e,0xc6,0x8a,0x82,0x14,0xa4,0xcd,0x72,0x36, ++ 0x20,0xa2,0xec,0xe8,0x13,0x58,0x67,0x19,0x6d,0x4e,0xe7,0x0c,0x99,0x12,0x1a,0xf2, ++ 0x7a,0xab,0xf8,0xbe,0xbe,0x29,0x22,0x44,0xfb,0xef,0x6f,0x34,0x73,0x2b,0x36,0x57, ++ 0xa2,0x5a,0x73,0xb6,0xbf,0xd8,0x4f,0x83,0xc7,0xc8,0xb8,0xc2,0xc4,0x27,0xe1,0x33, ++ 0xe0,0x61,0xbe,0x61,0x79,0x42,0x29,0x75,0x22,0xc7,0xb1,0x67,0x44,0x6b,0x72,0x61, ++ 0x8f,0xf8,0xb1,0x71,0x78,0x43,0x0b,0xc2,0xe7,0x7a,0xd6,0xbc,0x51,0x63,0xd6,0xf3, ++ 0xe1,0x4b,0x8a,0xe2,0xe3,0x6a,0x6c,0x01,0x90,0x0c,0xb2,0x1f,0x2f,0x5e,0xed,0x62, ++ 0xdf,0x01,0xd5,0xde,0x2a,0xa5,0xae,0x5a,0xaa,0x42,0xc1,0x3c,0x5f,0x80,0x50,0xf3, ++ 0x07,0xb7,0x9e,0xc1,0xeb,0x1c,0x30,0x2e,0x69,0x15,0x4c,0xaf,0x20,0xc0,0x0c,0x0a, ++ 0xf1,0x18,0x33,0xee,0x98,0x3b,0x9b,0x57,0x2a,0x40,0x93,0x22,0xbb,0xbf,0x7f,0x8f, ++ 0xd4,0x04,0x6e,0x3f,0x9e,0x9a,0x44,0x0a,0x2a,0xdf,0x37,0x0e,0xd8,0xab,0xb1,0x22, ++ 0x84,0xdb,0xb4,0x5b,0xba,0x82,0xae,0x8b,0xc7,0x40,0xe0,0x83,0xa6,0xf6,0x46,0x27, ++ 0xea,0x6e,0xfd,0x4a,0x48,0x6f,0x2d,0x6f,0x2b,0xcd,0xb8,0xe9,0x83,0x54,0x03,0x45, ++ 0x32,0x8e,0x5e,0x7a,0x3a,0x80,0xa0,0x5e,0x6a,0xb0,0xdb,0x90,0xd3,0xee,0x00,0x62, ++ 0x04,0x9d,0x92,0xe6,0xcf,0x9d,0x4e,0x71,0x58,0x4f,0x29,0x44,0x5c,0xdb,0x3b,0x96, ++ 0xd2,0x53,0xb2,0xac,0x8e,0x6a,0x09,0x5a,0x98,0x1e,0x8c,0x90,0x42,0x91,0x78,0x05, ++ 0xe5,0xb9,0x92,0x01,0xc6,0x04,0xad,0x5a,0x83,0x26,0xed,0xa1,0x0d,0x30,0x87,0x97, ++ 0x5d,0x57,0x8d,0x6c,0x41,0xa8,0x47,0x2d,0xd9,0x11,0x36,0xf2,0xff,0xaf,0xe8,0x45, ++ 0xb1,0x8b,0x14,0xb6,0x01,0x31,0xf0,0xc4,0x28,0xb5,0xc4,0x41,0x32,0xf9,0x5c,0xa6, ++ 0x67,0xe9,0xac,0xd6,0x66,0x38,0x02,0x12,0x67,0xf8,0x92,0x87,0x38,0xd1,0xba,0x61, ++ 0xd2,0xe6,0x3d,0x41,0x91,0xb4,0x72,0xe7,0x32,0x32,0x8c,0x6a,0x55,0xd4,0x47,0x91, ++ 0x7e,0x13,0x09,0x53,0xd9,0x36,0xcb,0xf5,0xe1,0x52,0x17,0x17,0x13,0xf6,0x78,0xa4, ++ 0xf4,0x69,0xb3,0x08,0x02,0x38,0x9c,0x76,0x89,0x57,0x52,0x66,0xc3,0x47,0xb6,0x78, ++ 0x19,0xad,0xdc,0xe2,0x9a,0x5c,0xa5,0x5a,0xc5,0xa4,0x8e,0xba,0xd8,0xe6,0x5d,0x58, ++ 0x90,0x05,0xb9,0xa0,0xbe,0xe9,0x2a,0x2d,0xad,0x6f,0xcd,0x45,0x80,0x38,0xaf,0x83, ++ 0x25,0x16,0x30,0x7f,0x50,0xaa,0x67,0xd2,0xef,0x93,0xc5,0x8e,0x81,0xd4,0xc7,0x97, ++ 0x6b,0x9c,0x90,0xc8,0x93,0x82,0x6b,0xd9,0xcb,0xdd,0xc7,0x1f,0xfe,0xf7,0x04,0x67, ++ 0xf6,0xc1,0x97,0x47,0x9c,0x58,0x0c,0x5f,0x4f,0xd6,0x7e,0x0f,0x46,0x89,0xe8,0xcb, ++ 0xea,0xe2,0xa7,0xcf,0x28,0x33,0x9e,0x1a,0x6e,0xd3,0xe2,0x5c,0x59,0x8b,0xf2,0x87, ++ 0x56,0x03,0xf7,0x35,0x2d,0x70,0x9c,0xd5,0x00,0x1b,0xc4,0xd9,0x06,0xa7,0x95,0x3e, ++ 0xfc,0xa3,0x18,0xf5,0x1d,0xdb,0x3d,0xd3,0x28,0xa0,0x64,0x3d,0x72,0x74,0x08,0x1f, ++ 0xcd,0x10,0xc2,0xea,0xcb,0xe3,0x40,0x15,0xb8,0xce,0xf1,0xb2,0x23,0x94,0x12,0xa3, ++ 0x78,0x13,0xcb,0xeb,0x4a,0x59,0xf1,0x77,0x41,0x1f,0xe5,0x19,0x9b,0x17,0x78,0x3c, ++ 0xf9,0x36,0x66,0xef,0x7c,0x69,0x1f,0x1e,0x41,0x67,0x83,0xdc,0x66,0x16,0xe4,0xbc, ++ 0xf7,0xea,0xf3,0x62,0xb7,0x3b,0xe0,0x71,0x3a,0x80,0x14,0x8d,0xa7,0x67,0x84,0xcd, ++ 0x06,0x05,0xd3,0xea,0xe0,0xe4,0xc1,0x43,0xe6,0x44,0x49,0x8d,0x14,0x05,0x82,0x03, ++ 0x9e,0xdb,0x55,0x25,0xea,0x59,0x57,0x5f,0x4a,0x87,0xd1,0x89,0xd0,0x56,0x81,0x6b, ++ 0x07,0xc7,0x32,0x57,0xe8,0x37,0x6e,0x80,0x43,0x4a,0xe1,0x63,0x2e,0x68,0xf6,0x30, ++ 0x2a,0x7d,0xb0,0xf0,0xf7,0x39,0xa3,0x2d,0x4a,0x00,0xe0,0x10,0x72,0xaa,0x70,0xfc, ++ 0x65,0xf8,0x3f,0x59,0xd7,0x03,0x8e,0x49,0x75,0xc6,0x01,0xd8,0x4d,0x14,0x34,0x8f, ++ 0xc3,0xc0,0x99,0xfc,0xa0,0x07,0x1a,0x58,0xfc,0xc5,0x34,0x5b,0xef,0x5d,0xeb,0x3b, ++ 0x8f,0x00,0xe3,0xcf,0x74,0x7a,0x05,0x0e,0xee,0x46,0x43,0x1b,0x01,0x5a,0xca,0x72, ++ 0x6d,0xe0,0xbd,0x4e,0x21,0x73,0x20,0xdd,0xa5,0xa8,0xea,0x6a,0xd9,0x8f,0x52,0xa5, ++ 0x9e,0xf0,0x2a,0xde,0xef,0xe1,0x68,0x37,0xa4,0x89,0xf5,0x65,0xa6,0xe2,0x74,0xcf, ++ 0xae,0x65,0x3a,0xf1,0xa5,0x2b,0xe3,0x05,0xa6,0xc3,0xa9,0xe3,0xa2,0xac,0x42,0x53, ++ 0x0f,0xcf,0xb9,0x19,0xb1,0xe3,0x41,0xcb,0x21,0x60,0x7c,0xc0,0x9f,0xb1,0xdf,0xa5, ++ 0x85,0x1f,0xdb,0x7e,0x34,0xcb,0xc6,0xd1,0x54,0xdf,0x14,0xd4,0x16,0x97,0x74,0x96, ++ 0xad,0x8e,0x73,0xac,0x42,0x84,0x1c,0xae,0x63,0xe9,0x7c,0x97,0x5a,0xb3,0x7d,0x87, ++ 0x51,0x1d,0x32,0x76,0xc6,0x11,0x81,0xd0,0xdc,0xdd,0x95,0x83,0x1d,0x43,0x73,0xa6, ++ 0xa9,0xd1,0x6d,0xf2,0x1d,0xdf,0x76,0x88,0xd9,0x46,0xad,0x86,0xc6,0x13,0xdf,0x88, ++ 0x36,0x90,0x84,0xc4,0xf8,0xb9,0x4e,0x52,0x88,0x7b,0xac,0xf7,0x2a,0x03,0x17,0x2d, ++ 0x44,0xf9,0xd4,0x84,0x74,0x45,0xdd,0xf5,0xcb,0xb0,0xf7,0x16,0x3f,0x45,0xe5,0x84, ++ 0x88,0x88,0xaf,0xda,0xa6,0xf9,0xd1,0xc7,0x7a,0x92,0xf5,0xe6,0xa2,0x4b,0x7a,0x57, ++ 0x87,0x7c,0xb3,0x35,0xa3,0x32,0x45,0x0d,0x4b,0xda,0x8a,0xf7,0xff,0x67,0xac,0xcc, ++ 0x4f,0x67,0xff,0xc8,0x99,0x1e,0xa7,0x95,0x54,0x0d,0x1d,0xe9,0x72,0x24,0xb8,0x7a, ++ 0xce,0x12,0xf9,0xe4,0x3e,0x59,0x3b,0xd1,0x0c,0x29,0xe4,0xa9,0x05,0xbb,0x5f,0xac, ++ 0x0f,0x37,0xf7,0xfc,0xc0,0xf8,0x26,0x2f,0xf5,0x40,0x73,0x65,0x47,0xc5,0x8a,0xb2, ++ 0x1e,0x16,0x91,0xa2,0x1a,0xab,0x27,0xbf,0x65,0x73,0xaf,0xa4,0x5c,0x64,0xd9,0x28, ++ 0x8a,0x0d,0xbf,0x51,0x99,0xba,0xe6,0x1a,0x25,0x8d,0x36,0xf7,0xb5,0x92,0xec,0xe8, ++ 0x4f,0xf3,0xda,0x38,0x9a,0x42,0x30,0xd6,0xdc,0x90,0x9c,0xfe,0x7e,0x9d,0xf7,0xa0, ++ 0xc5,0x91,0xc7,0x55,0x1f,0xa5,0x0e,0x94,0x49,0x55,0x48,0x7d,0x01,0x23,0x11,0xdd, ++ 0x4e,0x1c,0xa5,0x3d,0x9c,0x3f,0x80,0xdf,0x43,0xba,0x20,0x00,0xdb,0xbe,0xa7,0x38, ++ 0xd8,0xb1,0xbf,0x5b,0xc5,0xbd,0x68,0xa4,0x4b,0x23,0xd8,0xbd,0x56,0xa8,0x44,0x9d, ++ 0xa0,0xae,0x46,0x90,0x3c,0xa0,0x31,0x46,0xb6,0xbc,0xa0,0xcb,0xdc,0xc7,0x5b,0x1d, ++ 0xfc,0x40,0x2a,0x2a,0x83,0x77,0x29,0xde,0x51,0x3f,0xa5,0x47,0x27,0x07,0x5d,0xe0, ++ 0xfd,0xf3,0x99,0x08,0x9d,0x61,0xb5,0xaf,0xc2,0xe3,0x8e,0x4b,0x1b,0xf2,0xca,0x63, ++ 0xf7,0x0b,0x68,0x49,0x97,0x24,0x28,0x1d,0x61,0x55,0xc0,0x91,0xb3,0x6b,0xef,0x78, ++ 0x60,0x4a,0x37,0xb6,0x91,0xa2,0x66,0x58,0x45,0x44,0x92,0x96,0x72,0x8f,0xf5,0x3e, ++ 0x21,0x47,0xa1,0xf7,0xa3,0xad,0x91,0x41,0x94,0xb9,0xcd,0x02,0x3b,0x77,0xde,0xd5, ++ 0xa3,0x05,0xd0,0x37,0x71,0xd8,0x3f,0xf5,0xe3,0x6d,0x6e,0x40,0xd5,0xbd,0x62,0xbe, ++ 0xcc,0x05,0x99,0x4c,0x6f,0x1d,0xb8,0x57,0x8d,0x1c,0xda,0x31,0x5e,0xa0,0x88,0x9a, ++ 0xe3,0x7d,0x3b,0xc9,0xf8,0x96,0x1e,0x11,0x4f,0x63,0x36,0x43,0x83,0xb4,0x41,0x78, ++ 0xf8,0x01,0x5c,0x25,0x24,0x30,0x43,0x38,0xbc,0x1a,0xa7,0xa9,0x9d,0xb5,0x33,0xea, ++ 0xf5,0x67,0x4b,0x74,0x8e,0x69,0xc8,0x5b,0x36,0x57,0xf8,0xfd,0xdd,0x6f,0x7a,0xbb, ++ 0x32,0x4e,0x43,0xc8,0x7c,0x69,0x92,0x48,0x22,0xb3,0xe7,0x23,0xa7,0x10,0xe7,0x2a, ++ 0xbc,0x50,0xb2,0x5e,0xe6,0x2b,0x2e,0xfc,0x6b,0x48,0xca,0xdd,0x38,0x92,0x88,0x62, ++ 0x17,0xf3,0xa3,0xff,0xab,0xd3,0x6d,0x41,0xcc,0x4f,0x89,0xf0,0xe6,0x2c,0xe7,0xca, ++ 0xb3,0x05,0xb9,0x35,0x3a,0x29,0x01,0x90,0xf7,0x0d,0xa3,0x8d,0x78,0xce,0xbd,0xc7, ++ 0xfa,0x18,0xdd,0x70,0xd7,0x72,0xcf,0xa3,0x1f,0x5c,0x45,0x5a,0x8d,0x01,0x55,0xbc, ++ 0x84,0xe0,0xaa,0x10,0x70,0x59,0x3a,0x65,0x60,0xf5,0xe2,0x14,0x77,0xb9,0x80,0xa1, ++ 0xe2,0x02,0x07,0xe8,0xb6,0x38,0xcc,0x97,0xdf,0x43,0xeb,0x04,0x05,0x21,0xf2,0xe3, ++ 0xd7,0xcc,0x4d,0xb0,0xbf,0x71,0x54,0xf0,0x9a,0x5f,0xa9,0xd7,0x02,0x16,0x64,0x0b, ++ 0xc3,0x4b,0x7c,0x83,0xf0,0x64,0x6c,0x30,0x99,0x5b,0x14,0xc4,0x1a,0x8b,0x04,0xa1, ++ 0x40,0x9b,0xae,0x50,0x10,0x9a,0x56,0xf4,0xc0,0xae,0xa8,0x70,0x53,0xb8,0xfc,0x86, ++ 0x68,0x27,0xcd,0x23,0xb4,0x1d,0x35,0xa0,0x1b,0x5b,0xeb,0xd0,0xf4,0x77,0xdc,0x55, ++ 0x83,0x15,0x0d,0x34,0x41,0x75,0x8d,0x75,0x9e,0xd1,0xd5,0xed,0x88,0x57,0x2d,0xf7, ++ 0xf9,0xc5,0x9c,0x1a,0x3e,0x71,0x4d,0xbf,0x6e,0xa2,0xae,0x57,0x7e,0x81,0xb7,0xdf, ++ 0xf3,0x13,0x4e,0xe4,0x2f,0x78,0xde,0xc4,0x77,0x1b,0x33,0xc3,0xe4,0xec,0x1f,0x8d, ++ 0xdb,0xe5,0xb9,0x09,0x93,0x2f,0x4c,0x09,0xb4,0x3a,0xdb,0xe3,0x0d,0x26,0xcb,0x71, ++ 0x69,0xd6,0x2c,0xa5,0x65,0x8a,0xd3,0xc5,0x96,0x1b,0x8c,0x86,0x81,0x8e,0x7e,0x39, ++ 0x89,0x5c,0xc6,0xd8,0x3c,0x2f,0x36,0xac,0x24,0x51,0x61,0xd9,0x7c,0xf5,0x5e,0xe9, ++ 0xd4,0xb6,0xb0,0xe9,0x58,0xb4,0x66,0x70,0xe9,0x75,0xfe,0xf5,0x18,0x8f,0x27,0xeb, ++ 0xa2,0x5c,0xc7,0xcf,0x13,0xb3,0xa8,0xae,0xe4,0x5d,0x90,0x05,0xcd,0xbe,0x37,0xdd, ++ 0x16,0x5d,0xd9,0xe8,0x08,0x72,0xe4,0x9b,0xa8,0xe0,0x4a,0x79,0xdb,0x5c,0x1e,0xa3, ++ 0x37,0x04,0xb2,0x95,0x96,0xa4,0x8d,0x68,0xa1,0x1f,0xbb,0x55,0x28,0x61,0xbb,0x61, ++ 0x71,0xed,0x6c,0x93,0x56,0x53,0xf8,0xf3,0x33,0x1c,0xee,0x0a,0x53,0x29,0xc3,0xed, ++ 0x65,0x2d,0x2a,0x65,0x6b,0xc0,0xdd,0xbc,0xc5,0x62,0xb3,0xd4,0x50,0x6f,0x4f,0x2e, ++ 0x86,0xda,0xb9,0x75,0xd7,0xe1,0x41,0x0c,0xe7,0x82,0xdc,0xb3,0x90,0xc6,0x74,0xb2, ++ 0xc5,0xd5,0xc4,0x0a,0xb5,0xa2,0x60,0xc3,0xe7,0x3b,0xe1,0x95,0x66,0x6e,0x97,0x3f, ++ 0x26,0xe7,0xec,0xb4,0x11,0xfc,0x01,0x0d,0xe0,0x84,0xe8,0xea,0xa8,0x48,0xa1,0x63, ++ 0x84,0x8b,0xc1,0x17,0x37,0x2e,0x2b,0x6c,0xae,0xd7,0x89,0x87,0xa4,0xa4,0x33,0xce, ++ 0xfb,0xc5,0x5d,0xd3,0xc0,0xa8,0xf8,0x32,0x86,0x86,0x6f,0x86,0x74,0x27,0x1c,0x33, ++ 0x64,0x59,0xa6,0xb8,0x2f,0xe3,0x22,0x2b,0x40,0x8a,0x72,0x7a,0xab,0x84,0xd1,0x3d, ++ 0xac,0x76,0xa2,0x1b,0x3d,0x59,0xe5,0x3b,0x4b,0x20,0x17,0x41,0xc0,0xb6,0xe3,0xca, ++ 0x94,0x87,0x19,0xc8,0x5e,0xaa,0x2b,0x23,0x49,0xea,0x54,0xd0,0x2d,0x3c,0x72,0x86, ++ 0x28,0x34,0x68,0xf7,0xa2,0x66,0xe1,0xbf,0xac,0x91,0x84,0x12,0x22,0x76,0x72,0xeb, ++ 0x6d,0x73,0x3d,0x4f,0x18,0xe5,0xad,0x6a,0x39,0x4c,0xc0,0x5e,0x95,0x43,0x7b,0xde, ++ 0x2f,0x8f,0xfa,0x5e,0x03,0xef,0x72,0xdd,0x2c,0xed,0x3a,0x5e,0xba,0xe7,0x1b,0xbb, ++ 0x29,0x2f,0xfd,0xcb,0xeb,0xdc,0xb3,0x17,0xbb,0xc8,0x53,0x1d,0xbc,0x69,0x53,0xcb, ++ 0x2c,0xdf,0xb3,0x13,0xac,0xbd,0x03,0xf9,0xc6,0x12,0xbf,0xfb,0xff,0xc5,0x07,0x60, ++ 0xc4,0x6f,0x87,0xba,0xec,0x41,0xf4,0xd7,0x03,0x92,0xe0,0x98,0x56,0xb2,0x77,0x92, ++ 0x23,0x21,0x57,0xb1,0x94,0x4e,0x8d,0x36,0x46,0xe6,0x5b,0xd8,0xa3,0xf9,0x96,0x61, ++ 0x5c,0xb1,0x65,0xd3,0x1c,0xbf,0xf4,0x7e,0xe2,0x2b,0x2a,0x66,0x79,0x8f,0x43,0xc9, ++ 0x58,0x0f,0x41,0x04,0xcd,0x6e,0xe6,0x85,0x9a,0xc2,0x7c,0x33,0xb0,0xd6,0x74,0x7b, ++ 0x87,0x0b,0x9a,0xee,0x75,0x44,0x0c,0x60,0x6f,0x69,0xca,0xd3,0xd5,0x7f,0x73,0x89, ++ 0xaa,0x68,0xd2,0xfe,0x74,0x45,0xa3,0x56,0x61,0x2c,0xc2,0xde,0xd0,0x55,0xd1,0xa1, ++ 0x5d,0xd4,0xfd,0xe7,0xfc,0xa7,0x4d,0xb3,0xe2,0xd9,0xef,0xd6,0x9a,0xe9,0x0f,0xfb, ++ 0x52,0x11,0xf5,0xc7,0x56,0x08,0x1f,0x77,0xcc,0x51,0x6b,0x84,0x9b,0x9b,0x20,0x2b, ++ 0x2a,0xb2,0xc0,0xb6,0x3d,0x68,0x6d,0x91,0x17,0x00,0x76,0xfa,0xc9,0x59,0xc2,0x05, ++ 0x2c,0x39,0x6e,0xca,0xca,0xd7,0xfe,0xdf,0xb2,0x42,0x6d,0xf9,0x73,0x26,0xf3,0xe9, ++ 0x53,0x07,0x80,0x89,0x6c,0xde,0x82,0x63,0x58,0x30,0xa0,0x50,0x15,0x6b,0xef,0x5a, ++ 0x83,0x06,0x10,0x04,0x48,0x2d,0x8d,0x42,0xdd,0x27,0x00,0x3a,0x02,0xb9,0x66,0x0a, ++ 0x14,0x17,0xfa,0x0c,0x5d,0x30,0x56,0x34,0xec,0xf4,0x94,0xf3,0x7d,0xbc,0xd6,0x0a, ++ 0x8c,0x62,0xe3,0xac,0x9c,0x36,0x06,0x78,0xef,0x55,0x19,0x03,0xbc,0xbf,0x7d,0xfa, ++ 0x9e,0x81,0xf1,0xfa,0xb8,0xbf,0x48,0x89,0xad,0x61,0xeb,0x23,0xda,0x25,0x36,0x1f, ++ 0x0a,0x1e,0x43,0xee,0xd3,0xfd,0x47,0xab,0xeb,0xd0,0x64,0xcd,0x88,0x09,0xdf,0xd2, ++ 0x06,0x28,0x16,0x80,0x30,0x22,0xef,0x07,0xe1,0xbc,0x2f,0x15,0xf1,0xe1,0xf0,0x18, ++ 0xfc,0x4e,0x80,0x05,0xed,0xc0,0xd8,0xe8,0x6f,0x4b,0xca,0x82,0xba,0x05,0x76,0xe9, ++ 0x62,0xdf,0xb9,0xc2,0x52,0x02,0xe9,0x29,0x3d,0x0d,0x7a,0xd6,0x54,0xef,0x69,0xa6, ++ 0x62,0x0e,0x49,0x21,0xc5,0xa8,0x9b,0xd9,0x19,0x88,0x09,0xc6,0x55,0xee,0xd3,0x7f, ++ 0x7a,0x46,0x55,0xa2,0xb7,0x4a,0xf0,0x13,0x7e,0x97,0x10,0xa5,0x23,0xe5,0x5e,0x6c, ++ 0x05,0x04,0x60,0xe4,0x20,0xb3,0xe6,0xf5,0xf4,0x20,0x8a,0xfe,0x55,0x9d,0x96,0x6e, ++ 0xe1,0x6b,0xa3,0x54,0x93,0x9c,0x2f,0x66,0x63,0x03,0x81,0x96,0x56,0xeb,0x09,0x23, ++ 0x20,0x8c,0x71,0xbd,0x37,0x68,0x61,0xf4,0x7c,0xfa,0x61,0xf1,0xd8,0x87,0xae,0x9a, ++ 0x0a,0x02,0x7a,0x3d,0x74,0x6a,0x90,0x6e,0x2a,0x09,0xc0,0x9b,0xb3,0x0c,0xbe,0x7a, ++ 0xba,0x6c,0x0a,0x0d,0xe5,0xc8,0xe2,0x09,0x25,0x0b,0x39,0xcf,0xdd,0xe4,0x57,0x6b, ++ 0xc8,0x05,0x93,0x8d,0x39,0xad,0x29,0xda,0xa4,0xc1,0x03,0x1c,0x79,0xeb,0x33,0xf2, ++ 0x25,0x06,0x4b,0x58,0xe0,0x8b,0x0b,0xb9,0x68,0x25,0xc9,0x8b,0x32,0x0f,0x85,0x79, ++ 0x7e,0x4e,0x02,0x15,0xd0,0xb1,0x44,0x0a,0xb5,0xd1,0xea,0x96,0xf6,0x61,0x32,0x67, ++ 0x73,0x4f,0x5a,0x37,0x15,0x4f,0xff,0x9a,0x4d,0x9d,0x92,0x74,0x5d,0x47,0x53,0xe8, ++ 0xe9,0xf1,0xbb,0x6a,0x63,0x21,0x93,0xd5,0xa2,0x13,0x7f,0xf2,0x2b,0xb8,0xd2,0xb6, ++ 0x62,0xbe,0x81,0xe0,0x24,0x74,0x43,0x02,0x9a,0x44,0x5d,0x03,0x78,0x0a,0x64,0x37, ++ 0xcb,0x50,0xfa,0x83,0x14,0x91,0x72,0xf9,0x63,0x63,0x04,0xbb,0x4c,0xc4,0x72,0xf2, ++ 0xd2,0x74,0x2c,0xe6,0x53,0xf6,0x0c,0x11,0xc0,0xf8,0xa2,0xed,0x33,0x8e,0x45,0xe4, ++ 0x22,0xf5,0xbd,0xb5,0x76,0x9d,0x4f,0x3c,0x9c,0x10,0x86,0xd7,0x1b,0xc3,0x35,0x6a, ++ 0x0d,0x1e,0xf3,0x92,0x95,0x3e,0x8b,0x51,0xdd,0x11,0xa3,0x8c,0x7c,0x85,0xd1,0x44, ++ 0x02,0x16,0x28,0x56,0x64,0x3c,0x0d,0xef,0x87,0x38,0x14,0x25,0x41,0x36,0xdf,0xf3, ++ 0x8e,0xb5,0x60,0xab,0xe9,0xca,0xde,0xf2,0x61,0x17,0x63,0x6f,0x86,0xd3,0x7d,0x51, ++ 0x01,0xb6,0xd5,0x83,0xd0,0x77,0x37,0xe4,0xe1,0x36,0x56,0x11,0x09,0x18,0x5a,0xf2, ++ 0x32,0x56,0x76,0x4f,0x44,0x2c,0x8e,0x94,0x6e,0xfa,0xa5,0xb5,0xeb,0x35,0xfd,0xaf, ++ 0x89,0xe7,0x79,0x64,0xe2,0x75,0x06,0x01,0xc9,0xc7,0xde,0x55,0x1b,0x8a,0x0b,0x1a, ++ 0xc7,0x56,0x1e,0x67,0xf8,0xb3,0x8f,0x88,0xe8,0x26,0xca,0xde,0x10,0x08,0x5e,0x99, ++ 0xae,0x18,0x7c,0xf2,0x35,0xec,0xa3,0xcb,0x13,0xf7,0x81,0x94,0xfe,0x7b,0xb4,0x7b, ++ 0x1e,0x7e,0x08,0x8d,0x1a,0x86,0x25,0x08,0xd1,0x04,0xc7,0xc4,0x10,0xca,0x18,0xe5, ++ 0xf4,0xb7,0x27,0xaa,0xb7,0x5e,0xc9,0x7a,0x62,0x56,0x9a,0x04,0x8f,0x88,0x70,0x38, ++ 0x62,0xe4,0x94,0xde,0x88,0xe4,0x9e,0x44,0xa3,0x1d,0xd8,0xa9,0x92,0x95,0x54,0x1b, ++ 0x2f,0xbf,0xb8,0x8a,0x47,0x88,0xd3,0x6d,0x9c,0x65,0xaf,0x69,0xae,0xab,0x17,0xd1, ++ 0xad,0x45,0xae,0x1d,0xff,0xb2,0x89,0xca,0xd8,0xea,0x73,0x6f,0xa7,0x77,0xd9,0x25, ++ 0xa5,0xff,0x36,0x75,0x78,0xcc,0x52,0x23,0x45,0xbb,0x20,0x55,0x25,0x51,0x5a,0x74, ++ 0xf2,0x91,0x8c,0x81,0x31,0x0c,0x0d,0x2d,0x75,0x83,0xeb,0xc5,0xd9,0xec,0x18,0x41, ++ 0x25,0x99,0xc3,0x1a,0x97,0xe2,0x86,0x16,0xc2,0x18,0xcf,0x21,0x3d,0x9b,0x91,0xec, ++ 0x64,0x1c,0xb2,0x2f,0x7e,0xe7,0x29,0x9a,0x64,0x6c,0x29,0xdf,0x41,0xae,0x7e,0x7a, ++ 0x27,0x44,0xe0,0x81,0xeb,0xd2,0xdf,0xe6,0x30,0x83,0x4f,0x84,0xbf,0xfc,0x30,0xd7, ++ 0x64,0xa5,0x89,0x96,0x0b,0xd8,0xc2,0x8d,0x49,0x7a,0x86,0x70,0xb6,0x66,0x5f,0x7f, ++ 0xef,0x17,0xbb,0x45,0x25,0x7f,0x79,0xd2,0xf5,0x12,0xe7,0x05,0xb6,0xec,0xb2,0x53, ++ 0x37,0xf6,0xfe,0x39,0xe5,0xcb,0xd5,0x9b,0x42,0x8a,0x98,0xf3,0xdc,0x7e,0x5d,0xc8, ++ 0xad,0x97,0x98,0xbf,0x21,0x07,0x27,0x0d,0xed,0x67,0x4d,0xc6,0xe0,0xa5,0xf9,0xe4, ++ 0xf4,0xba,0x92,0x2e,0xcb,0x06,0xac,0xbe,0x14,0xe5,0x81,0x4e,0xdd,0xf6,0x9e,0x36, ++ 0x73,0xd7,0x07,0x2b,0x29,0x0b,0xa2,0x10,0xfc,0x3f,0x24,0xc9,0xf8,0x5c,0x54,0x61, ++ 0xbf,0x14,0x0b,0x6d,0xff,0x6c,0x01,0xc4,0x30,0xa7,0x02,0x4f,0x5d,0xfd,0x63,0x48, ++ 0x46,0xe0,0xf8,0x4c,0xdc,0xa8,0x15,0x9a,0xce,0x8e,0xe0,0x8e,0xb5,0xa8,0x03,0xb1, ++ 0x09,0x8c,0x52,0xb1,0x2c,0x58,0xba,0xc6,0x97,0x8f,0x75,0x18,0x60,0xcd,0xb7,0x15, ++ 0xa0,0x52,0xab,0xcb,0xad,0xfa,0x24,0x15,0xcd,0xaf,0xc9,0xdf,0x4c,0xac,0x86,0xab, ++ 0x28,0x2e,0x53,0x72,0x38,0xe2,0x2c,0x99,0xcc,0xbd,0x22,0xcc,0xe4,0x92,0x9b,0x60, ++ 0x9b,0x96,0xee,0x9b,0x74,0xd5,0xd8,0xd9,0xfa,0x4d,0xb6,0x55,0x00,0x5d,0xb3,0x92, ++ 0x25,0x91,0xba,0xf4,0xca,0x1c,0xfb,0x8f,0x63,0xd0,0xf4,0xd7,0x16,0x03,0xd3,0x70, ++ 0xa2,0x90,0xdd,0xa3,0x5d,0xa8,0xd4,0xe3,0xea,0x59,0x26,0xe0,0x3e,0x4a,0x2d,0xe1, ++ 0x27,0x74,0x63,0x32,0x42,0x4e,0x69,0x43,0x1a,0xdc,0xab,0x8b,0xf3,0xf2,0x84,0x46, ++ 0x05,0x55,0xbd,0xf8,0x91,0xa4,0xcc,0x82,0x62,0xf9,0xd5,0xc2,0x9d,0x90,0xd4,0x2c, ++ 0x37,0xd8,0x62,0xc5,0x7a,0xad,0x24,0x1f,0x54,0xbf,0x83,0x72,0x24,0x3b,0x49,0x0c, ++ 0x95,0x1a,0x1d,0xe3,0x57,0x19,0x6b,0x0b,0xd1,0x1b,0xcd,0x1d,0x5a,0xfb,0x12,0x89, ++ 0x52,0x0b,0xbd,0xc2,0xf3,0x3c,0xc5,0x13,0x80,0xcc,0x6d,0xc5,0x00,0x56,0x5c,0x68, ++ 0xa3,0x83,0xb4,0xcc,0x18,0xc5,0x6c,0x4c,0x04,0x39,0xe2,0xcc,0x15,0x89,0x96,0x14, ++ 0x2c,0x09,0xd5,0xe1,0x45,0x06,0x7c,0x58,0x31,0xdd,0x09,0x87,0x7b,0xd8,0x0f,0xed, ++ 0x32,0x88,0xd8,0x2a,0x76,0xb7,0xf7,0x8b,0xee,0xd7,0xef,0x6e,0x04,0x2b,0x4f,0x2c, ++ 0x0a,0x96,0x95,0x27,0x4e,0xfa,0x13,0x4b,0x4a,0x7a,0xa3,0x7f,0xec,0x4e,0x59,0x53, ++ 0x0d,0xbc,0xee,0xff,0x2f,0x13,0x97,0x8c,0xd5,0x6d,0xe8,0x15,0x9f,0x9f,0x91,0xa0, ++ 0x01,0x42,0xd6,0xee,0x3d,0x12,0x6e,0x12,0xfb,0x90,0xc5,0x8e,0xff,0xe2,0x24,0xb0, ++ 0xc6,0x93,0xee,0xbc,0xaf,0x1f,0x4d,0x53,0xcc,0x33,0x8c,0x90,0x73,0x48,0x51,0xe3, ++ 0xd3,0x30,0x4f,0xad,0xdd,0xa9,0x82,0x13,0x1b,0x92,0xa5,0xfd,0x6d,0xbe,0x12,0xff, ++ 0xfb,0x8d,0x76,0xc2,0xb1,0x3b,0xa0,0x57,0x4e,0x9f,0xb6,0xc6,0xdc,0x21,0x1f,0xe3, ++ 0x85,0xdc,0x06,0x25,0xb0,0xa0,0x66,0x69,0xc3,0xa6,0x67,0xd8,0xf1,0x5a,0x53,0xfe, ++ 0x73,0xff,0xa4,0xe3,0xb4,0x8f,0x81,0xc9,0xff,0x8f,0x51,0x05,0xb1,0xd9,0x5a,0xe2, ++ 0x0d,0x0e,0xa4,0xe6,0x15,0xae,0xf1,0xd3,0xb6,0x43,0x5e,0xb1,0xf1,0x3a,0x9b,0xcb, ++ 0x7d,0x0f,0xfe,0x3c,0x6e,0x66,0x0a,0x29,0x3e,0x06,0x89,0xba,0x21,0xa3,0x48,0x22, ++ 0xf8,0x47,0x0c,0xd1,0x1d,0xaf,0x66,0x48,0xce,0x93,0x01,0xc2,0x68,0xb3,0x7f,0x90, ++ 0x3d,0x5d,0xce,0x79,0x33,0x19,0x1d,0xa9,0x63,0x99,0x8e,0x64,0xed,0x46,0x54,0x9d, ++ 0x62,0xf8,0x0e,0xa6,0xb5,0x4b,0x51,0x61,0x9f,0xb0,0x22,0x88,0x81,0x25,0x7d,0xad, ++ 0xc2,0x05,0xd0,0xbf,0xf3,0x4c,0xcd,0x35,0x33,0x48,0xa8,0xdf,0x34,0xc5,0x31,0xa8, ++ 0x2f,0xbd,0xb2,0x2c,0x4d,0x86,0x47,0xe9,0x4f,0x4b,0xd2,0x4d,0x3a,0x04,0x78,0x7b, ++ 0xf0,0xb5,0x13,0x8f,0x7e,0xb8,0xce,0xd7,0xff,0x9d,0x05,0x6a,0x12,0xd2,0xab,0xea, ++ 0x05,0x86,0x2b,0x6f,0xfb,0xec,0x28,0x4a,0x90,0x40,0x8d,0x08,0xdf,0x6a,0xfd,0x0f, ++ 0xc0,0xa6,0xff,0xdf,0x3c,0x83,0xd0,0x16,0x29,0xa8,0xd5,0x7e,0xdd,0x2f,0x9e,0xfa, ++ 0xaa,0x92,0x1d,0xaf,0x35,0x6f,0x62,0xfa,0xad,0xfd,0xea,0x1a,0x1b,0x22,0x0b,0x38, ++ 0x77,0x4c,0x13,0xc8,0x94,0xa4,0xc4,0xed,0xc1,0xf6,0x13,0x8d,0x98,0x75,0xff,0x3b, ++ 0x70,0x14,0xc4,0xb8,0x9d,0x97,0x23,0xd9,0x93,0x0d,0x63,0xcf,0x9b,0x8f,0x64,0xc4, ++ 0x5b,0x9b,0x92,0xbc,0xdb,0x74,0x49,0xbc,0x66,0x71,0x23,0x91,0x76,0xda,0xac,0xe2, ++ 0x82,0x17,0x28,0xb0,0x52,0xd5,0xdc,0x71,0xa1,0x13,0x0d,0xca,0xbb,0x40,0x85,0x63, ++ 0x22,0x5a,0xbf,0x35,0x56,0x9d,0xc5,0x25,0xc9,0x17,0xc0,0xe2,0x0d,0xd4,0xdd,0xd5, ++ 0x02,0x76,0x9a,0x66,0x35,0xbe,0x16,0x23,0xe7,0x49,0xd5,0xa1,0x25,0x42,0x59,0x44, ++ 0x0c,0xd3,0xcb,0x21,0x8f,0x9b,0x6a,0xd9,0xc5,0x52,0xe7,0x82,0x8d,0xf5,0x4b,0x20, ++ 0x5e,0xe4,0xb2,0xd3,0xca,0x94,0xdd,0x96,0x94,0x45,0x8c,0x83,0x69,0x6e,0x85,0x71, ++ 0xb4,0x1e,0x65,0x60,0x78,0x3b,0x05,0xfc,0x41,0x4d,0x2a,0x63,0xa8,0x8b,0x33,0xd7, ++ 0x42,0x94,0x6d,0x2e,0x42,0x94,0xe5,0x0e,0xe5,0xce,0x11,0x93,0xd0,0xf5,0x7e,0xaf, ++ 0x0c,0x91,0xd4,0x3a,0xd3,0x5c,0x8c,0x2c,0x1c,0x6d,0x31,0x80,0xe0,0x69,0x08,0x38, ++ 0x4a,0xab,0xf0,0x9a,0xd8,0xba,0x88,0xbb,0xe9,0x39,0xa0,0x94,0x9a,0x70,0x83,0x76, ++ 0x5c,0x19,0x17,0x7d,0xa1,0x8b,0xd7,0xd0,0xd5,0x18,0x92,0x06,0xa4,0xb4,0x9c,0x6a, ++ 0x2d,0x96,0x7d,0x6e,0x35,0x7a,0xdf,0x99,0x88,0xd6,0x0f,0x4d,0xa7,0xda,0x23,0x3b, ++ 0xa6,0x97,0x62,0x36,0x3c,0x84,0x61,0x6c,0x2c,0x2d,0x8f,0xd7,0xdf,0xfe,0x0c,0x26, ++ 0xd6,0x71,0x2d,0x9c,0x3d,0x39,0x5f,0x9e,0xe9,0x59,0x61,0xb6,0x6b,0x79,0x43,0x2b, ++ 0x43,0xb4,0xf3,0x33,0x03,0x50,0x0e,0xe5,0x4f,0xa1,0x28,0x1d,0xf2,0x62,0xac,0x19, ++ 0xb1,0xe2,0x4d,0xb6,0x34,0x99,0x0f,0xa6,0x48,0x3a,0x5f,0xba,0xd5,0x61,0x58,0x26, ++ 0xa1,0xec,0xde,0x01,0x30,0x0d,0x74,0xca,0x73,0x0d,0xf0,0x44,0x75,0x0a,0x92,0x22, ++ 0x06,0x2e,0x90,0x26,0xc5,0x0e,0x80,0xd2,0x09,0xda,0xc6,0x1a,0xbe,0xf0,0xe5,0xf8, ++ 0xb7,0xb6,0x32,0x36,0x35,0x03,0x69,0x3b,0xf7,0xf6,0xeb,0xd8,0x3f,0xd3,0x89,0x61, ++ 0xe7,0xb5,0x09,0x65,0xf7,0x04,0x9d,0xd5,0xd5,0x8c,0x83,0xdc,0xb6,0x6f,0xbb,0x34, ++ 0x8b,0xe6,0xd4,0xad,0x9b,0x02,0x29,0x56,0xe3,0x65,0x30,0xaa,0x6c,0x69,0x60,0x0e, ++ 0x64,0x8e,0xfb,0x42,0xea,0xc9,0x7a,0x7f,0xbb,0x54,0x69,0x4c,0x6f,0x10,0x8d,0xc7, ++ 0xe4,0x5c,0x31,0x87,0x9f,0xa5,0x62,0x90,0xbe,0xc5,0xa8,0x45,0x71,0x53,0xfe,0xa0, ++ 0x03,0x0a,0x8b,0x53,0x94,0x97,0x07,0x4b,0x1b,0x76,0xe8,0x49,0xbb,0xa5,0x5c,0x0d, ++ 0x28,0x03,0xdc,0x09,0x38,0x23,0x9a,0xb2,0xad,0xd3,0xa7,0xaa,0x7c,0xd0,0x8a,0x68, ++ 0x6f,0x6e,0x90,0xae,0xed,0x06,0x22,0x1e,0x7e,0xa4,0xaa,0x85,0xfc,0xe2,0xba,0x3a, ++ 0xf0,0x25,0x79,0x23,0x77,0xee,0xea,0xdd,0x25,0x72,0x8b,0x4f,0x86,0xa8,0x55,0x1c, ++ 0x2c,0xca,0x0f,0x3b,0xfe,0xe1,0x60,0xa4,0xfa,0x4c,0x7d,0x64,0x64,0x57,0x30,0xc1, ++ 0xe5,0xe8,0xf2,0x76,0x2a,0x51,0x52,0x6f,0x86,0x5d,0x79,0xb0,0x58,0x96,0x86,0xc8, ++ 0x0f,0x85,0xf8,0x35,0x90,0x0b,0x69,0x9c,0xcd,0xce,0x3a,0xd3,0xac,0x60,0x39,0x4a, ++ 0x2d,0x73,0x0f,0xdd,0x82,0xa4,0x64,0x83,0x84,0x63,0x26,0xeb,0xae,0x5c,0x2e,0x24, ++ 0x89,0x0c,0x3f,0x1f,0xeb,0xed,0x7e,0x99,0xfc,0x0d,0xa2,0x69,0x78,0xf4,0x76,0x34, ++ 0x00,0x2f,0xfa,0x64,0x68,0x34,0xcb,0x52,0xa5,0x21,0x22,0x22,0x54,0xd3,0x13,0xe2, ++ 0x29,0x3e,0xd4,0x8b,0xf5,0xf0,0x64,0xba,0x06,0xbf,0x44,0x32,0x55,0xf3,0x1f,0x33, ++ 0x82,0x0d,0xdd,0xf4,0xc0,0x19,0xf5,0x83,0xfd,0xdf,0x8b,0x8f,0x57,0x73,0x8d,0x89, ++ 0x29,0x6e,0xd3,0x90,0x14,0x6c,0xaa,0x37,0xc5,0xdf,0x85,0xa7,0x56,0x5e,0xa4,0x72, ++ 0x69,0xd6,0x30,0x86,0x22,0xc9,0xcb,0x00,0xca,0x79,0x8f,0x0e,0xb2,0xbb,0xad,0x92, ++ 0x7f,0x1e,0x51,0xeb,0xc8,0x9d,0x6b,0x10,0x61,0xec,0xaa,0x05,0xf3,0x7e,0xb1,0x75, ++ 0xa0,0x15,0x72,0x38,0x36,0x16,0x66,0x01,0x4a,0x7b,0x65,0x17,0xc6,0x57,0x31,0xee, ++ 0x4c,0xd3,0x10,0xf3,0x95,0x14,0x68,0x77,0x9a,0x8a,0xc8,0x46,0x95,0x58,0x5e,0x96, ++ 0x08,0x37,0x12,0xec,0xc3,0x15,0x0c,0x48,0x30,0x2f,0x20,0x2a,0x5c,0xab,0x50,0x9d, ++ 0x09,0xa8,0xf0,0x7c,0x39,0x14,0x33,0x3e,0x70,0x33,0x80,0x92,0xde,0x59,0x87,0xf9, ++ 0xce,0x5d,0xae,0xbe,0x1d,0xfb,0xb0,0xc4,0xea,0x08,0x89,0x86,0x5f,0x9f,0x56,0xfd, ++ 0x20,0x6d,0x21,0xad,0x56,0xff,0xff,0xc3,0x34,0xdd,0x29,0x9e,0x73,0xba,0x5c,0x7a, ++ 0xb4,0x33,0x3a,0x33,0x52,0x07,0x3e,0xee,0xeb,0x3d,0x52,0xca,0x50,0x23,0xe9,0x9b, ++ 0x2d,0xdc,0xb7,0x41,0x9a,0xb6,0xaa,0x7c,0x1f,0x20,0x80,0x4f,0x96,0x7e,0xc3,0x3b, ++ 0xa6,0x91,0xf2,0x4b,0x88,0xbe,0xe7,0xf0,0xc4,0xa3,0x5b,0x9c,0x94,0x08,0xc8,0xe3, ++ 0xd0,0xbf,0x7e,0xff,0x99,0x5d,0x61,0x5a,0xce,0x66,0x1c,0x0c,0x9d,0xbe,0xb7,0xd4, ++ 0x77,0x00,0xfe,0x03,0xb1,0x5f,0x2a,0xda,0xbb,0x3d,0x6f,0x5e,0x26,0xbf,0x5e,0x6e, ++ 0x6b,0x82,0x48,0xd5,0x5a,0xbc,0x60,0xce,0xb8,0x72,0x87,0x62,0x57,0x40,0xbe,0x30, ++ 0xea,0xad,0x2d,0x7f,0x0e,0xbd,0x86,0xde,0x75,0xe1,0x51,0x05,0x44,0x20,0x77,0xa1, ++ 0xa5,0xae,0xf1,0x0c,0xf2,0x43,0x66,0x4b,0xf3,0xdc,0x82,0xb1,0x89,0x0f,0x0a,0xbb, ++ 0xa1,0x02,0xd6,0xf0,0xed,0x89,0xf3,0xc5,0x9e,0xc7,0xf8,0x17,0xde,0xe2,0xb3,0xb2, ++ 0xa2,0x8f,0x2a,0x4b,0xdd,0xa8,0x62,0x41,0x25,0xea,0x1f,0x45,0x61,0x27,0x61,0x7d, ++ 0x23,0x8c,0xb9,0xf4,0xf8,0x89,0x72,0xd0,0x1a,0x85,0xd1,0xa5,0xc0,0xed,0x36,0xb3, ++ 0x22,0x88,0xb7,0xc6,0xf8,0xa1,0x08,0x02,0xa9,0xc4,0xc9,0xd4,0xb0,0x98,0x54,0x38, ++ 0xf7,0xa7,0x15,0xf3,0xf9,0xfb,0x82,0xd2,0x2b,0x59,0x3b,0x52,0xcd,0x14,0xf5,0xeb, ++ 0x6f,0x48,0x28,0x6a,0x9b,0xee,0xa8,0x80,0xa2,0x2d,0xad,0x8d,0xad,0xea,0xd5,0x7a, ++ 0xea,0x89,0x78,0x0f,0x51,0x31,0x04,0xda,0x4c,0xc1,0x2c,0x62,0x28,0xe9,0x51,0x31, ++ 0xe1,0xa8,0x04,0xff,0xe2,0x0b,0x23,0xc7,0x34,0x27,0x2c,0x8c,0xdf,0xdb,0x22,0x4a, ++ 0x76,0x03,0x42,0x5f,0x70,0xfa,0x29,0x9b,0x24,0x20,0xaa,0x9d,0xf9,0x2c,0x72,0xda, ++ 0x29,0x3d,0xad,0xad,0xc9,0x6d,0x12,0xe1,0xc6,0xc0,0x8d,0x8c,0xa4,0x62,0xd3,0xcd, ++ 0x81,0xac,0xe5,0xf9,0x44,0x81,0x6d,0xcc,0x08,0xce,0xed,0xc5,0xdc,0x6f,0x33,0xdb, ++ 0x6d,0x3d,0xb5,0x6b,0x70,0xca,0x3d,0xc9,0x34,0xc4,0x6f,0x9f,0xff,0xe4,0xf9,0x78, ++ 0x20,0xef,0x44,0xa4,0x6e,0x2b,0x6a,0xa6,0x03,0x65,0x7a,0x87,0xe7,0x55,0xa0,0xe3, ++ 0x4b,0x90,0x27,0x11,0xa2,0x0e,0x8c,0x4c,0xe1,0xaa,0x1b,0x90,0xf4,0x81,0xde,0x81, ++ 0xa4,0xa2,0x03,0xdb,0x3d,0x50,0x43,0x8d,0x0b,0x36,0x29,0x86,0x47,0x3c,0x09,0x62, ++ 0xcf,0x9e,0x72,0x65,0x59,0x42,0xbd,0x33,0x07,0xb7,0x0d,0xc7,0x0e,0x31,0x1d,0x59, ++ 0x87,0xcb,0xb6,0xcc,0xd6,0x93,0x5c,0xc8,0x8b,0xd7,0x73,0xe2,0xa6,0x10,0x6e,0x2b, ++ 0xca,0xdf,0xcd,0xe2,0xcb,0xce,0x88,0x63,0x0d,0x8a,0x18,0x24,0x7f,0x73,0x7b,0x15, ++ 0x76,0x19,0xf4,0x69,0x56,0xa3,0x33,0x49,0x1d,0xfb,0xed,0x0a,0xfc,0x14,0xee,0x33, ++ 0x63,0xba,0xcd,0x17,0x30,0x71,0x9d,0x39,0xe3,0xfa,0x55,0x38,0x50,0x0a,0x96,0xfb, ++ 0x6f,0x9a,0x46,0xad,0x7e,0x35,0x4c,0xaa,0xcb,0x43,0xca,0x7e,0x99,0x87,0x6e,0x2f, ++ 0xd0,0x5b,0xb5,0x20,0xce,0x7b,0x13,0x5a,0x12,0x79,0x85,0xc8,0x02,0x79,0xf8,0xfa, ++ 0x82,0x5b,0xdc,0x8d,0xc4,0xc5,0x35,0xdf,0x6a,0x9d,0x17,0x4c,0x5e,0x3a,0x4f,0xfc, ++ 0x2b,0xfc,0x9f,0x60,0xbf,0x82,0x20,0xfe,0x2b,0xbb,0xc4,0xdd,0x86,0x5b,0x3e,0xa8, ++ 0x22,0xac,0x71,0xe8,0x51,0x33,0x07,0xd5,0x95,0xf1,0x9c,0xf9,0xf8,0x7f,0x2e,0x6e, ++ 0x20,0x12,0xde,0x65,0x9a,0x22,0xe1,0x6b,0x0d,0x80,0x92,0x0c,0x77,0x72,0xf8,0xd2, ++ 0x09,0x9a,0x47,0xbe,0x88,0x7c,0x81,0x55,0x1d,0x32,0x94,0x0f,0x78,0x36,0x16,0x40, ++ 0x0e,0xe0,0x7b,0xbf,0x50,0x7b,0x39,0x48,0xea,0x0f,0xf8,0xfb,0x2b,0x1b,0x5e,0x04, ++ 0x67,0x45,0x60,0xc7,0x5f,0xad,0xd3,0x06,0x27,0xd1,0x1c,0x59,0x68,0x1f,0x10,0xe1, ++ 0x27,0xef,0x04,0x89,0x14,0x21,0x8a,0x8e,0xae,0xa5,0xd8,0x34,0x54,0xec,0x77,0xb3, ++ 0x6f,0xe6,0x5e,0xef,0x18,0x6f,0xa6,0xd0,0x40,0x49,0x0a,0x8b,0x23,0xa3,0x4f,0x2b, ++ 0xa1,0x08,0xae,0xac,0xd1,0xac,0x01,0x17,0x32,0xce,0xcb,0x3f,0xd5,0xe9,0xa0,0x83, ++ 0x14,0x89,0xbe,0x75,0x06,0x0b,0x72,0xf1,0x68,0x1b,0x37,0x5b,0x50,0xe5,0x08,0x50, ++ 0x7e,0x88,0xd6,0xfe,0xdd,0xd6,0x42,0xed,0xb8,0x4e,0x00,0xf2,0x77,0xe7,0x01,0xe3, ++ 0xda,0x89,0xd3,0x01,0x04,0xca,0xb1,0xab,0xc6,0xaa,0xa5,0x08,0x75,0x67,0x7b,0x57, ++ 0x05,0x84,0x97,0x4c,0x7e,0x44,0x7b,0xed,0x30,0xc4,0xa3,0x76,0x74,0xa5,0x33,0x3b, ++ 0x62,0x27,0x62,0xcf,0x09,0xa5,0x4d,0xd2,0x4c,0x8a,0x2e,0xac,0x17,0x0f,0xf8,0xe9, ++ 0x81,0x84,0x3a,0x51,0xe4,0xd5,0x46,0x58,0xb6,0x88,0x14,0x1d,0xc8,0xcc,0x83,0xfb, ++ 0x68,0x29,0xc3,0xb9,0xc4,0xa5,0x34,0x6c,0x4e,0x2d,0xa5,0x4d,0xf3,0xcf,0xd4,0x3f, ++ 0x64,0xe8,0x02,0x60,0x08,0xf6,0x61,0x13,0xa5,0xba,0x12,0x1c,0x04,0xce,0xa7,0xa8, ++ 0x8c,0x4b,0x80,0x4e,0xf5,0x38,0xcc,0xc2,0xaf,0x13,0xe2,0xc7,0xaf,0xe3,0x0a,0xec, ++ 0x1d,0x80,0x8b,0xfe,0xc9,0x12,0x44,0xca,0x85,0xde,0x21,0x7c,0x20,0x94,0x2f,0x29, ++ 0xce,0x81,0xbd,0x40,0x92,0xe0,0x8c,0x69,0xe0,0xa0,0x47,0x14,0x7d,0xaf,0x94,0xa9, ++ 0xae,0x1d,0xc2,0x30,0x0e,0x6a,0x45,0xde,0x05,0x2c,0xa0,0x7d,0xa4,0x76,0x1a,0xe0, ++ 0x97,0xf5,0x0e,0x98,0x56,0x44,0x7c,0x13,0xb8,0x94,0x34,0x17,0xaa,0xbe,0xd5,0xb5, ++ 0x84,0xee,0x64,0x12,0x15,0x10,0x47,0x36,0x6e,0x89,0x9c,0xe7,0xd4,0x79,0x1d,0x68, ++ 0x08,0x9f,0xf3,0xe9,0xb2,0xb3,0x96,0xa4,0x48,0xdf,0xf7,0x61,0xb0,0xf4,0xbd,0x11, ++ 0x4b,0x3e,0xf4,0x82,0x60,0xdf,0x06,0x51,0x39,0x97,0x3d,0x55,0x77,0xf7,0x04,0x74, ++ 0x2d,0x99,0xc5,0xc1,0xbb,0x32,0x4a,0x56,0x06,0x2b,0xcc,0x19,0xb7,0x96,0x14,0x56, ++ 0x2c,0x34,0xec,0x96,0x55,0x08,0x83,0x0c,0x43,0xbb,0x9c,0xb2,0x24,0xfa,0xc2,0x21, ++ 0x66,0x3b,0x85,0xb4,0x3a,0x30,0x8a,0x90,0x8c,0x55,0x31,0x62,0xb5,0xd6,0x55,0x29, ++ 0x0b,0x9a,0x8f,0x55,0x46,0x31,0x3d,0xcc,0xef,0xbb,0x42,0xa5,0xf9,0x7d,0x1e,0x70, ++ 0x80,0x95,0x62,0xd0,0x32,0xa6,0x95,0xad,0xc0,0xbd,0x25,0xcc,0x3d,0xd8,0x9a,0xf8, ++ 0xd2,0xd8,0x3b,0x1a,0x15,0x6b,0x64,0xf2,0x15,0x76,0x9e,0x3b,0xf8,0x7b,0x58,0xac, ++ 0x0d,0x45,0xda,0x70,0xdf,0x3d,0x0f,0x9a,0x4d,0x45,0xcf,0xcd,0xbd,0xba,0x11,0x2f, ++ 0x4d,0x64,0x97,0x67,0xbd,0x4a,0x9f,0xc9,0x8f,0x1c,0xdf,0xbd,0xb4,0xf6,0x19,0xed, ++ 0x8f,0x43,0xe6,0x8e,0x4e,0xfe,0x5e,0x28,0xba,0x7f,0x72,0xc9,0xdd,0x48,0xbe,0x8a, ++ 0x29,0x9f,0x5a,0xbc,0xd4,0xf9,0x59,0x52,0x86,0xae,0xb4,0xeb,0xfd,0xb5,0xd3,0xa9, ++ 0x51,0x98,0xf7,0x66,0x1f,0xa1,0xd0,0x5f,0x3e,0x3d,0x57,0xf5,0x72,0xf3,0xf3,0xdf, ++ 0x8c,0x0b,0xce,0xd8,0x30,0x39,0x21,0x19,0xeb,0x5a,0x67,0x1d,0xdb,0xff,0x2f,0x7f, ++ 0xd9,0x9c,0x08,0x06,0xb1,0xaa,0x06,0x15,0x46,0x41,0x27,0x08,0x74,0x94,0xf1,0xd7, ++ 0xf8,0x87,0xc2,0xea,0xb2,0x27,0xd8,0x10,0x5a,0x4c,0xa0,0x64,0x53,0x6e,0xba,0x5b, ++ 0x61,0x7d,0x5e,0xe7,0x3c,0x2f,0x51,0x43,0xe1,0x31,0x82,0xa7,0x50,0xca,0x09,0x6b, ++ 0x43,0x43,0x81,0x90,0x30,0xa9,0x01,0x25,0xc7,0x42,0xa3,0xb7,0x59,0xbb,0xc1,0xb3, ++ 0xe2,0x48,0x6b,0xc1,0x81,0x1b,0xa6,0xa0,0x52,0x06,0xd8,0x71,0x61,0x81,0xe3,0xb8, ++ 0x47,0x69,0x08,0xb5,0x1f,0x19,0xec,0x0b,0xe0,0xb5,0x20,0x69,0xad,0xb5,0x20,0x3a, ++ 0x57,0x9b,0xbe,0x1a,0x27,0xda,0x5e,0x63,0x33,0x49,0xee,0x83,0xc2,0x9b,0x9d,0x0f, ++ 0xad,0xdb,0x76,0x1e,0x95,0x26,0xe6,0x01,0x97,0x4c,0x2c,0x51,0x0f,0xa4,0x0a,0x81, ++ 0xe9,0xb9,0x75,0xee,0xb9,0xa2,0x5f,0x4a,0x0a,0x47,0xea,0xae,0xd8,0x00,0x6a,0xaf, ++ 0xe8,0x4b,0x77,0xfe,0xb8,0xa3,0xda,0x19,0x33,0x25,0xa3,0xc0,0x55,0x2b,0xfc,0x73, ++ 0xea,0xd5,0x6c,0xef,0x39,0xa0,0x2d,0xfd,0x8a,0x95,0xad,0x15,0x7b,0x91,0x41,0x27, ++ 0x8f,0xbb,0xf4,0xff,0x1b,0x03,0xf8,0xf9,0x81,0x09,0x06,0x66,0xdf,0x92,0x2b,0xa3, ++ 0xe1,0xb8,0x8e,0xc8,0x3a,0x8d,0xe3,0x4c,0x21,0xfd,0x8c,0xd9,0x52,0x6a,0xca,0x9e, ++ 0x99,0x0e,0x0e,0x02,0x15,0x33,0x04,0x45,0x95,0xe6,0x5d,0x83,0xb2,0xae,0xe0,0x53, ++ 0xe1,0x7a,0x9a,0x58,0x4f,0x42,0x77,0x98,0xbe,0x42,0xf3,0xa9,0x7b,0xe4,0xa8,0xa2, ++ 0x62,0xa8,0xb6,0xb2,0x6a,0x6d,0x0b,0xab,0x22,0x85,0x77,0xe2,0xd8,0xcf,0xc4,0x99, ++ 0xeb,0xed,0xbe,0x28,0xdb,0x54,0x94,0xcc,0xdf,0xf0,0xb4,0xe1,0xd1,0x79,0xf5,0x68, ++ 0x29,0xaa,0x8c,0x6d,0x3d,0x73,0x0c,0x24,0x76,0x1f,0x18,0x30,0x4c,0xcd,0x90,0x6e, ++ 0x55,0x41,0x45,0xd0,0x94,0xa9,0x83,0xa0,0xc3,0x13,0x10,0x58,0x41,0xa9,0x0d,0x13, ++ 0x4f,0x5e,0x8a,0x46,0x65,0x02,0xdf,0x59,0xe7,0x1e,0x9b,0x8c,0x71,0x6e,0x3f,0xe7, ++ 0x83,0xab,0x3c,0xcc,0x95,0x24,0xc3,0xdb,0x16,0xc1,0xe9,0x60,0x70,0x1d,0xb1,0x3c, ++ 0x23,0xa8,0xf2,0xac,0x4f,0x77,0x62,0x54,0x65,0x86,0x96,0x95,0xbb,0x0f,0x1c,0x4f, ++ 0x07,0xc9,0x3d,0xcd,0x15,0xc9,0x42,0x65,0xbd,0xcd,0xb5,0x52,0x0b,0x34,0xd8,0x2a, ++ 0x16,0x84,0xc2,0xe9,0x12,0x88,0x16,0xc0,0xc1,0xf8,0xa5,0x71,0xb0,0xec,0x3e,0x77, ++ 0x5f,0x18,0x21,0xa0,0x3e,0xf0,0x64,0xa9,0x2e,0x43,0xf6,0xae,0x75,0xf3,0x0e,0x1c, ++ 0x71,0xb7,0x8c,0x6f,0xbd,0xb4,0x1a,0x3c,0x4c,0xf8,0x90,0xde,0x3a,0x84,0xc7,0x59, ++ 0x06,0x81,0x3d,0x72,0x05,0xbb,0x87,0xcf,0x13,0xa1,0x68,0x4f,0x7a,0x7e,0xb0,0xb4, ++ 0x16,0xc6,0x5e,0x19,0xf4,0xfb,0xc0,0x73,0x9e,0x6b,0xe7,0x7a,0xdd,0x15,0x3d,0x4c, ++ 0x73,0x18,0x9d,0xcc,0xb7,0x27,0x06,0x96,0x00,0xad,0x16,0x3c,0x69,0xd1,0xb3,0x1f, ++ 0x2d,0xa5,0xee,0x2f,0x98,0x2f,0x97,0xc9,0x1f,0xf2,0x1e,0x2c,0x0c,0x7b,0x7f,0x27, ++ 0x06,0x13,0xf1,0xab,0x60,0xb5,0x29,0xd4,0xec,0x8d,0x05,0xfe,0x94,0x71,0xb9,0x99, ++ 0xe9,0xc2,0x77,0xad,0x3b,0x99,0xcc,0x87,0x81,0xee,0x29,0x8e,0xff,0x7d,0x4e,0x6d, ++ 0x78,0xff,0x04,0x64,0x57,0x5d,0x24,0x9b,0x04,0xcf,0xb5,0xdb,0xe5,0x3b,0xa8,0xeb, ++ 0x05,0xef,0x0f,0x3e,0x88,0x1c,0x3e,0xb6,0x6d,0xf9,0x78,0xd6,0xcb,0xa3,0x98,0xbf, ++ 0x33,0x19,0xd9,0x23,0x40,0x43,0xf1,0x02,0xdd,0xcb,0x35,0xa3,0xe9,0x5e,0x16,0x81, ++ 0x85,0x1e,0x04,0x59,0x64,0xff,0x7b,0xd1,0x2c,0x69,0xe5,0xa5,0x3c,0x72,0x6e,0xf0, ++ 0x25,0x44,0xf0,0x68,0x10,0xa5,0x62,0x9c,0xad,0x87,0xca,0x95,0x30,0xe0,0x48,0x42, ++ 0xb3,0x52,0x44,0xd3,0xc2,0xc7,0x2c,0x35,0x8d,0x6f,0xc0,0xa6,0x0b,0x1a,0x3b,0x19, ++ 0x31,0xf9,0xf7,0xaf,0xda,0x7a,0x4b,0x90,0xec,0x6b,0xf6,0xe5,0x56,0xac,0xdc,0xec, ++ 0x5a,0xfa,0x80,0xbc,0x6c,0x5b,0x31,0xdb,0x2e,0x16,0x55,0x04,0xb1,0x11,0x40,0x0b, ++ 0x0d,0xba,0x62,0x5a,0xf9,0x57,0x70,0xd4,0x4a,0xe9,0xc0,0x2a,0x58,0x84,0x78,0xe5, ++ 0x8f,0x6e,0x6a,0x4b,0x39,0xd4,0x3c,0xbe,0x65,0x63,0x84,0x07,0xd0,0x6f,0x19,0x32, ++ 0x73,0x17,0x06,0x09,0x08,0xce,0x7d,0x6c,0x1a,0xc0,0x23,0x5d,0x37,0x5b,0x97,0x9f, ++ 0xce,0x5e,0xb9,0x0f,0x76,0xef,0x39,0xd9,0x31,0x2a,0xf9,0xff,0x5a,0xed,0xcd,0x14, ++ 0xbb,0x50,0x5f,0x11,0x18,0x8d,0x60,0x7a,0xb1,0x41,0x8c,0xda,0xdc,0x0b,0xfa,0x28, ++ 0xf0,0x70,0xfe,0x6a,0x3b,0x20,0x72,0x7a,0x87,0x8e,0xdc,0xa6,0xfc,0xaf,0x0b,0x89, ++ 0x08,0x7b,0x67,0xb4,0x27,0xec,0x25,0x52,0x39,0x65,0xce,0xeb,0x9d,0xc7,0xab,0x02, ++ 0xe1,0x82,0xb2,0x6d,0x38,0xbf,0x77,0x54,0xed,0x9a,0xb1,0x87,0x5d,0x08,0xf5,0x7c, ++ 0xf9,0xed,0x01,0x80,0xa0,0xd4,0xf4,0xde,0xfc,0xd6,0xf4,0x99,0x7c,0x9c,0xc4,0xf0, ++ 0x44,0xb1,0x09,0x90,0xa1,0xd5,0x44,0x30,0x60,0xbb,0x1b,0x21,0x1e,0x57,0x8a,0xa7, ++ 0x26,0x75,0x9d,0x78,0x18,0xbf,0x3d,0x14,0x87,0xf2,0x9d,0x65,0x20,0x34,0x75,0x5a, ++ 0x4e,0x72,0x19,0xb0,0x68,0xbc,0x05,0x63,0x12,0xdc,0x3d,0x46,0x37,0xb3,0x1b,0x05, ++ 0x9b,0x22,0x9c,0x06,0x3c,0xa4,0x0a,0xdb,0x2e,0xf7,0x68,0x64,0xab,0xfb,0x76,0xd0, ++ 0xb5,0x9d,0xad,0xb0,0x04,0xa0,0x6c,0x7a,0x54,0x35,0x53,0x04,0x14,0x6b,0x3f,0xc1, ++ 0x15,0xcb,0x5d,0x2f,0x5a,0xf9,0x55,0xa0,0xc2,0x94,0xaf,0xe6,0x55,0xf0,0xae,0x95, ++ 0xc5,0xdb,0x15,0x3f,0x57,0x2a,0xd6,0xb4,0xe9,0x0b,0x85,0x75,0x2a,0x88,0x18,0xbf, ++ 0xa1,0x3e,0x12,0xf1,0x9f,0xcc,0x56,0xee,0x4d,0x55,0x8c,0x5d,0xaa,0x57,0xb8,0xab, ++ 0x8c,0x38,0x38,0x7c,0x91,0x14,0xb6,0x76,0xce,0xdf,0xc0,0x24,0x96,0x3c,0x28,0x4b, ++ 0xaf,0x37,0x07,0x81,0x30,0x17,0x4f,0x8c,0x4f,0xdc,0x50,0x5e,0x26,0xea,0x17,0x64, ++ 0xce,0xf6,0xbe,0x7d,0x49,0x8a,0xb7,0x6f,0x4e,0xdd,0xc1,0x88,0x96,0x5e,0xb6,0xc8, ++ 0x3c,0x61,0x1e,0xc6,0xbe,0xbe,0xb2,0x20,0xd5,0x83,0x49,0x0c,0xda,0x0d,0x15,0xfd, ++ 0x8e,0x22,0x02,0xa5,0xa1,0x36,0xbe,0xda,0x4b,0xc6,0x2a,0x2e,0xfe,0x45,0xa7,0x92, ++ 0xc0,0x93,0xbe,0xf8,0x1b,0xc1,0x29,0x09,0xea,0x43,0xcd,0x4a,0x3f,0x9d,0xc3,0xb4, ++ 0xa9,0x27,0xcf,0x35,0xce,0xa9,0xf9,0xa5,0x62,0xbd,0x00,0xd9,0xdd,0x72,0xd4,0x52, ++ 0x2e,0x8a,0xd0,0xfa,0x1c,0x8b,0x90,0xe7,0x64,0x2c,0xee,0x22,0xb1,0xe3,0xf1,0xf2, ++ 0x83,0xfd,0x48,0xe5,0xae,0x83,0x42,0xcf,0xaa,0x90,0x7c,0xca,0x32,0x41,0x39,0x5c, ++ 0x02,0xfe,0x7c,0x15,0xfb,0x5d,0x81,0xd0,0xb8,0x62,0x00,0xd6,0x5c,0xef,0x74,0x62, ++ 0x98,0x0c,0xd7,0xfa,0xc5,0x20,0x67,0x0c,0x43,0x84,0x7d,0x2b,0xed,0xcc,0x95,0x2f, ++ 0x6a,0x09,0xbe,0x42,0xf3,0xa7,0xd0,0xbc,0x44,0x5f,0x7c,0x26,0xd1,0xb0,0x36,0x56, ++ 0xe2,0x86,0x57,0xb4,0x73,0xd8,0x42,0x37,0x9d,0x4f,0xa6,0xe7,0x38,0xe3,0x57,0x23, ++ 0xe2,0x48,0xe1,0xb6,0x1e,0x2b,0x41,0x07,0x3d,0xeb,0x33,0x7a,0x1c,0xeb,0xbd,0xa2, ++ 0x0f,0x47,0x5a,0xab,0xcb,0x90,0xdf,0x8d,0x25,0xbc,0x59,0x2b,0x22,0xbb,0x62,0x57, ++ 0xbb,0xa5,0xfb,0xf7,0x73,0x57,0xb0,0x4a,0x23,0x47,0x81,0x5e,0xa3,0xc5,0xf0,0x6b, ++ 0x14,0x06,0xd4,0xf3,0x3b,0x2a,0x6c,0x37,0xe8,0xb8,0xa8,0xc3,0xa0,0x05,0x8a,0xeb, ++ 0x0a,0xf6,0xc0,0xfc,0x27,0x4a,0x94,0x1b,0x37,0x4c,0x8d,0xdc,0x7b,0x2a,0xbf,0x6a, ++ 0xd8,0x04,0xf2,0xe6,0x6d,0xf4,0x09,0xdb,0x22,0xda,0x7c,0x4e,0x7a,0xe2,0x02,0x2d, ++ 0xde,0xe4,0xc4,0x23,0x98,0x28,0x15,0xec,0x7b,0x2f,0x7d,0x17,0x87,0xb8,0x4c,0xb0, ++ 0x83,0xc0,0x08,0x23,0x96,0xab,0x4e,0x1e,0xb4,0xe0,0xbd,0x8d,0x89,0x2d,0xe4,0x01, ++ 0xaa,0xff,0xd5,0x2f,0xee,0x25,0x03,0x70,0xc0,0x55,0x30,0x72,0x04,0xc1,0x6b,0x51, ++ 0xb8,0x4b,0x1b,0x1d,0x99,0xd2,0x41,0x3e,0x15,0x45,0x70,0x13,0x0e,0x93,0x3c,0x7f, ++ 0xad,0xa6,0xf3,0x6c,0xd2,0x72,0x72,0x9c,0x63,0x90,0x93,0xa6,0xf3,0x31,0xcc,0xe9, ++ 0xf8,0x7f,0xc8,0x10,0x47,0x69,0x39,0x89,0x79,0x55,0x23,0xef,0x1a,0x7e,0xbe,0x1b, ++ 0xa3,0x30,0x56,0xfd,0x92,0xe2,0xb6,0x9d,0x3c,0xa3,0x38,0xde,0x6d,0xce,0xb2,0x03, ++ 0xb2,0xce,0x4d,0xe0,0xb0,0xce,0xa5,0xc2,0x99,0xcc,0x1d,0xce,0xf7,0x72,0x3e,0xa0, ++ 0x3c,0x9f,0xdc,0x60,0xbf,0xb2,0x44,0x41,0xc3,0x6d,0x63,0xc0,0xfd,0x76,0x90,0xb2, ++ 0xd4,0x28,0xcc,0xd6,0x73,0x88,0x5a,0x40,0x00,0xdb,0xb4,0xea,0xb5,0x81,0x0e,0xfc, ++ 0xa4,0x1c,0xc7,0x05,0xf2,0xad,0x0d,0xc4,0x5e,0xd5,0x62,0xe4,0x7f,0x7a,0x5f,0xd1, ++ 0x1c,0x9a,0xdf,0x2f,0x40,0xaa,0xc8,0x75,0xc3,0x55,0x3b,0x04,0x39,0x37,0x64,0x8c, ++ 0x29,0xb8,0x9c,0x8d,0x6d,0x31,0x28,0x94,0x97,0xc5,0x06,0x44,0x34,0xa4,0x9e,0x70, ++ 0xd7,0x54,0xc3,0x9b,0x3f,0x71,0xa9,0xb9,0xe4,0x55,0xf7,0x57,0x86,0x3b,0x17,0x04, ++ 0xac,0x74,0x81,0x70,0xb4,0x78,0xec,0x8d,0x67,0x58,0x3b,0x28,0x2d,0x18,0xf4,0x91, ++ 0x0c,0xe4,0x6d,0x19,0xc4,0x08,0x77,0xa7,0x1e,0xaf,0x8f,0x40,0x04,0x39,0x14,0x6c, ++ 0xb6,0x58,0x02,0x49,0x34,0xb6,0x6d,0x0a,0x6c,0x5d,0x88,0x7e,0x7e,0x80,0x08,0x91, ++ 0x73,0xed,0x08,0x26,0xb6,0xbb,0x66,0x17,0xe6,0xab,0xde,0xe3,0xa5,0xd6,0x39,0xce, ++ 0x5f,0x11,0x00,0x36,0x98,0x5d,0x86,0x8b,0x5d,0x3b,0xe8,0xb2,0x91,0xa8,0x6f,0x1f, ++ 0x8f,0x1c,0xc8,0x1d,0xb3,0xaf,0xe6,0x67,0xe8,0x6f,0xb8,0xf0,0x1a,0xd0,0x40,0x42, ++ 0xb9,0x0b,0x17,0xf9,0x97,0xae,0x60,0x3b,0x50,0xdb,0x90,0xcc,0x37,0xe4,0x57,0x90, ++ 0x04,0x7e,0x8f,0x60,0x34,0x99,0x06,0x0a,0x9b,0x6e,0xab,0x0f,0xbe,0xa5,0x25,0xe1, ++ 0xa6,0x7d,0x41,0x38,0xb0,0xb9,0x27,0x45,0x3b,0xae,0xd0,0xe7,0x86,0x4f,0x11,0x33, ++ 0x24,0xbc,0x45,0x85,0xd9,0xab,0x2a,0xda,0xcd,0xfe,0x83,0x86,0xe9,0x4c,0xda,0x05, ++ 0x35,0xa0,0x0c,0xd4,0x25,0xae,0xf6,0x9e,0xa0,0x3f,0x4d,0x39,0x82,0x21,0x10,0x60, ++ 0xfc,0x70,0x10,0xad,0x68,0x85,0xe8,0x39,0xba,0xf9,0xa6,0x44,0x53,0xa9,0x83,0xd3, ++ 0x4e,0x2f,0x60,0xaf,0xb2,0x5b,0xa5,0xe7,0xf7,0xa5,0x56,0x50,0x3d,0x43,0x73,0x40, ++ 0xee,0xbf,0x69,0x33,0xff,0x5c,0x23,0x8c,0x38,0x18,0x98,0x64,0xd6,0x73,0xfd,0x0a, ++ 0x28,0x93,0x22,0x9a,0x38,0x73,0x9e,0xb9,0x3c,0xc2,0x16,0x5c,0xd2,0x17,0x92,0xe1, ++ 0x8f,0x6e,0x31,0x2c,0x6a,0x8d,0xfa,0x52,0x4d,0xa5,0x1a,0x4c,0x3f,0xdf,0xd3,0x6d, ++ 0x7f,0x9a,0x87,0xf2,0x1d,0xe8,0x72,0x74,0x75,0x36,0xe9,0xaf,0xa4,0x45,0xd3,0x79, ++ 0x7a,0xee,0x74,0x5d,0x9b,0x83,0x84,0xa8,0xb1,0x16,0xc5,0x38,0x20,0xe4,0x5c,0x03, ++ 0x2f,0xdd,0xe0,0xca,0x05,0xc8,0x45,0x33,0xaf,0x53,0xd4,0x2f,0x86,0x47,0xca,0x28, ++ 0x65,0x65,0xb0,0xd2,0x6b,0xef,0x1c,0x23,0x4c,0xce,0xaa,0xe0,0xa4,0x16,0x5d,0x03, ++ 0xf6,0x21,0xc3,0xf0,0x7f,0x71,0x0d,0xdb,0x3f,0xa2,0x56,0x6a,0x59,0xf8,0x15,0x5c, ++ 0x2e,0xb0,0xe4,0x44,0x3e,0x10,0x21,0xe6,0xbf,0x8d,0xfb,0xbd,0x5c,0xa9,0x44,0x35, ++ 0x83,0x9d,0xf4,0xa7,0x36,0xb1,0xcb,0x53,0xdb,0xe3,0xa4,0x8c,0x72,0xf1,0xec,0xeb, ++ 0xfc,0xfd,0x2a,0x7e,0x06,0x7a,0xc1,0xa2,0x0e,0xae,0x10,0x33,0xa0,0x93,0x5e,0xa4, ++ 0x05,0x2d,0xb7,0x9e,0x96,0xc0,0x65,0x5d,0xe8,0x79,0xa3,0x4f,0xb8,0x2e,0x92,0x01, ++ 0xd5,0x4e,0xad,0x9f,0xd2,0x93,0xfd,0x42,0x5a,0x71,0xd4,0x5c,0x0a,0xb1,0x22,0xe3, ++ 0x51,0x53,0xdb,0xa6,0x3e,0x06,0xdf,0x8c,0xb3,0x28,0x97,0xb8,0xc3,0x28,0xd4,0xe2, ++ 0xd8,0xd3,0x69,0xa9,0xb8,0x23,0x53,0xea,0xe7,0x89,0x4e,0xe9,0x9b,0x5e,0xba,0x5a, ++ 0x95,0x04,0x5a,0x80,0x6c,0xbe,0xc8,0xbc,0x3f,0x4b,0x5a,0x88,0x2b,0x22,0xfa,0x57, ++ 0xf0,0xd5,0xa5,0xc3,0x37,0xa7,0xd2,0x88,0x3a,0x96,0xcb,0xf5,0x9c,0x72,0x44,0x8b, ++ 0x2f,0x68,0x0e,0xae,0x18,0xf6,0x68,0x45,0x3c,0xdb,0xa6,0xa0,0x81,0xf7,0x2a,0x5a, ++ 0x69,0x82,0xbc,0x65,0xb0,0xdb,0xff,0xa0,0x9a,0x6d,0x86,0x8e,0xed,0xbb,0x7e,0x67, ++ 0x49,0x1c,0xb7,0xab,0x55,0x13,0x4e,0x50,0x87,0xa5,0x88,0x9e,0x5d,0x5b,0xe3,0xfd, ++ 0x4f,0xbb,0xb9,0xfd,0xdd,0xdf,0xc0,0x4a,0x52,0xe8,0xaf,0x67,0xfb,0xf9,0x36,0xd3, ++ 0x44,0x47,0x59,0xb7,0x1f,0x3c,0x2f,0xce,0x0d,0xc4,0xf4,0xa8,0xec,0x58,0x2d,0xbc, ++ 0x4e,0xbd,0x41,0xa0,0xe2,0xfc,0x46,0x05,0x98,0x66,0xd9,0x0f,0xe3,0x3d,0x95,0x36, ++ 0x80,0x85,0x64,0x71,0xfe,0xb2,0x8f,0x69,0x6e,0xdf,0x27,0xf5,0x36,0x9d,0x7d,0x24, ++ 0x29,0x6e,0x03,0x5f,0x43,0x9f,0x7b,0x0b,0xcf,0x6e,0x17,0x75,0xdd,0x29,0x7f,0xfd, ++ 0x00,0x0e,0xe0,0x40,0x2d,0x2f,0xcd,0x46,0xb3,0x50,0x5a,0xdf,0x23,0x60,0x58,0x19, ++ 0x08,0x07,0x77,0x53,0xd3,0x11,0xab,0x50,0x47,0x8b,0x25,0x6b,0x57,0xd1,0x69,0x87, ++ 0x7c,0x43,0xe1,0x07,0x58,0x2f,0xa9,0xda,0x3c,0x6b,0x3a,0x4b,0x05,0x9e,0xfb,0x08, ++ 0x20,0xbc,0x81,0x01,0x6c,0x4d,0x39,0x2f,0xe0,0xb7,0xf7,0x6a,0x28,0x9f,0xbf,0x2e, ++ 0x74,0xdb,0x0c,0x22,0x33,0xa4,0xfc,0x44,0xc5,0x94,0x70,0x16,0x30,0x60,0xe4,0xcb, ++ 0xd6,0x0f,0x91,0x77,0xb6,0xa9,0x60,0x8f,0x59,0x28,0xc0,0x70,0xde,0x24,0x81,0x91, ++ 0x26,0xf9,0xfb,0xad,0x2a,0x69,0x0c,0x32,0x6f,0xe7,0xaf,0x62,0x73,0xbf,0x4b,0x2e, ++ 0x56,0x03,0x83,0x48,0x6c,0x3c,0x99,0xcd,0xab,0x4a,0x66,0x95,0x72,0xbc,0x1a,0xa4, ++ 0x3b,0x8a,0xe0,0xe6,0x19,0xe8,0x0e,0x0c,0xc7,0x4a,0x2d,0xeb,0x92,0x22,0xad,0xfa, ++ 0xe9,0xad,0x1d,0xfe,0x3d,0x65,0x72,0x47,0x29,0x09,0x0a,0x43,0xd4,0xcf,0xbb,0xf6, ++ 0x61,0xc0,0xe3,0x49,0xa5,0x27,0xa4,0x28,0x45,0x46,0x9b,0x28,0x04,0x20,0x73,0x34, ++ 0x62,0x9a,0xe5,0x77,0xbb,0xc6,0x65,0xae,0x28,0x98,0xd7,0xfd,0xdd,0x9f,0xc2,0x33, ++ 0xdf,0xf0,0xf7,0x2a,0x97,0xda,0x2c,0x15,0xe6,0x41,0xf2,0x91,0x78,0xd7,0x5c,0x95, ++ 0xe0,0x77,0x72,0xa3,0x28,0x18,0xd6,0x88,0xb4,0x42,0xd2,0x03,0x0e,0x64,0xf8,0x16, ++ 0x63,0x8d,0x8b,0x54,0xa9,0x7a,0x2d,0x89,0x48,0x4a,0xd1,0x97,0xdc,0x87,0x75,0xe8, ++ 0xe3,0x95,0x73,0x60,0x3c,0xa2,0x3b,0x7b,0x82,0x42,0x5b,0x3a,0xff,0x01,0x6e,0xaf, ++ 0x50,0x45,0xbe,0x0a,0x87,0xbd,0x26,0xa4,0xe5,0x46,0xea,0xa2,0x91,0xf3,0xaa,0x14, ++ 0x00,0x57,0xf5,0x96,0x3d,0x73,0x42,0xbf,0x65,0x1f,0x84,0xa5,0x8d,0x90,0x90,0x78, ++ 0x21,0x89,0xe0,0x6e,0x51,0x24,0xb4,0xbb,0x7c,0xe6,0x72,0x56,0x7c,0x7f,0x9d,0x13, ++ 0x21,0xab,0x0a,0xe1,0x93,0x9d,0x7c,0x11,0x37,0xec,0x5d,0xd9,0x4e,0xd3,0x40,0x22, ++ 0xa0,0x5c,0x6f,0x9b,0xcb,0xc8,0xed,0xbe,0xbf,0x29,0xf3,0x15,0xee,0x66,0xc4,0xb9, ++ 0x80,0x70,0x92,0xe7,0x3f,0x9e,0xea,0x03,0x8b,0xfe,0xa3,0xbe,0xce,0x69,0x5e,0xb3, ++ 0x01,0x10,0x66,0xf3,0x6e,0xd3,0xfa,0xff,0x06,0xa2,0x3d,0x6f,0xd0,0xa0,0x35,0x53, ++ 0xa6,0x7d,0xff,0xd4,0x36,0x21,0x6f,0xf5,0x66,0x41,0x6f,0x47,0xe3,0xb2,0x3e,0xda, ++ 0x6b,0x78,0x81,0xfe,0xb5,0xce,0xc9,0xa8,0xeb,0x56,0x00,0xae,0xd1,0x7e,0x4c,0x1a, ++ 0xc7,0x54,0xb4,0x07,0xc2,0xb4,0xa1,0xe3,0x90,0xd3,0xe6,0x54,0x46,0xb4,0xeb,0x1b, ++ 0xac,0x10,0x78,0xff,0x6e,0xe5,0xf7,0x96,0xcc,0xe6,0x65,0x25,0x9b,0x85,0x55,0x0c, ++ 0x0a,0x7e,0xec,0x67,0x9d,0x47,0x9b,0x48,0x4a,0x59,0x87,0xac,0x10,0xa1,0x7e,0x18, ++ 0xdd,0x13,0x67,0xd6,0xa6,0x88,0x70,0x51,0xba,0xf8,0xa0,0xc6,0x08,0xb9,0xe1,0xa6, ++ 0xf6,0x5f,0xaf,0x7c,0xed,0x82,0xda,0x3e,0xf9,0x5e,0x01,0xfc,0xf8,0x73,0x7f,0x19, ++ 0x51,0x11,0x99,0xc2,0xbe,0x70,0x84,0xf2,0x81,0x2a,0xe4,0xe5,0x1e,0xcb,0x57,0x0e, ++ 0x29,0x17,0x10,0xdd,0x38,0x31,0xbc,0x02,0x94,0x5f,0x3f,0xc2,0xdf,0x11,0xf9,0x9d, ++ 0x3b,0x0e,0x27,0xa0,0xdf,0x2d,0x4e,0xb4,0x2f,0x66,0xfc,0x02,0x23,0xe0,0xfc,0xef, ++ 0x84,0x5a,0x49,0xf8,0xf4,0x97,0x02,0xc1,0x93,0x6e,0x65,0x37,0x62,0xe4,0x07,0x2e, ++ 0xa2,0x2d,0x0d,0x88,0x2b,0x2f,0xb1,0xd2,0x06,0x42,0x6e,0x3a,0xaf,0xe2,0x8f,0x97, ++ 0xda,0xcf,0xd4,0x65,0x07,0xbc,0xde,0xc2,0x1f,0xd3,0xe4,0xde,0xd3,0xe1,0x1e,0x9a, ++ 0x02,0xfe,0xb9,0x7c,0xb1,0xe5,0x3a,0x1d,0xe5,0xaa,0x60,0xa1,0x54,0x11,0xd7,0xc2, ++ 0x26,0xb5,0x44,0x14,0x94,0x71,0x7c,0x35,0xc6,0xcb,0x5b,0xe0,0x8b,0x03,0xc2,0x1d, ++ 0x7f,0x5a,0x0d,0xc7,0x6a,0x86,0xe1,0xa4,0xc4,0x33,0xf5,0x20,0x57,0xe8,0x6b,0xb3, ++ 0xed,0x81,0x0b,0x48,0x59,0x2a,0xda,0xe5,0x1b,0x21,0xc3,0x84,0x1d,0x4c,0xf9,0x95, ++ 0x73,0x06,0x99,0xae,0xf1,0x4a,0x4c,0xb0,0x99,0x55,0x81,0x5c,0xb7,0x09,0x75,0x0f, ++ 0x0b,0xb0,0xe6,0x9a,0x41,0x60,0x99,0x0c,0x91,0x2c,0x67,0xa8,0x5e,0x0b,0x96,0x33, ++ 0x38,0xfb,0x53,0xdc,0x9a,0x83,0x98,0x74,0x35,0x36,0x8d,0x1a,0x51,0xf1,0x8e,0xe7, ++ 0x53,0x70,0x91,0x58,0x03,0xd4,0x65,0x08,0xc9,0x60,0xe1,0x58,0xb5,0x0a,0x6a,0xef, ++ 0xef,0x83,0x9c,0xdd,0x75,0x2a,0x48,0x99,0x84,0x67,0x90,0x6a,0xb5,0x29,0x52,0x8a, ++ 0xd0,0x82,0x0d,0xaf,0xc5,0xbd,0x5d,0xe5,0x24,0x7b,0xfb,0x8d,0xbf,0xa1,0xf3,0xc9, ++ 0x8b,0xe4,0x63,0xbc,0x48,0x01,0x11,0x6f,0x1e,0x18,0x8d,0x58,0xb5,0x4b,0x0b,0x1f, ++ 0xa0,0x04,0x95,0xc5,0x4a,0x32,0x7a,0x88,0x1d,0x13,0x9a,0x65,0x0f,0x5b,0x7e,0x0b, ++ 0x87,0xf5,0x1b,0xc9,0xa1,0x6d,0x06,0x5d,0xe6,0x98,0x18,0x23,0xd7,0xb1,0xda,0x71, ++ 0x46,0x13,0xf7,0x96,0x33,0x01,0x04,0x62,0xb8,0xae,0x19,0x07,0x8d,0x6b,0x7f,0x1b, ++ 0x07,0x94,0x0c,0xf4,0xf3,0x0d,0x15,0xc1,0x53,0xb7,0x12,0x02,0x2c,0x71,0x55,0x7b, ++ 0x9e,0xde,0xc3,0xe8,0x3a,0x15,0x84,0xe2,0x46,0x0c,0x0a,0x7a,0xf3,0xd8,0xb0,0x32, ++ 0x2e,0x9b,0x04,0xf9,0x12,0xb2,0x1c,0x20,0xe0,0x21,0xb4,0xd9,0x7e,0x98,0x30,0x89, ++ 0xda,0x1c,0x5d,0xb6,0x33,0xd9,0x25,0xe4,0xc2,0xdc,0x5b,0x61,0x96,0x5a,0xf5,0xdc, ++ 0x9a,0xd4,0xc5,0x77,0x17,0x3f,0xe5,0x43,0x8c,0xa5,0xdd,0x25,0x22,0x30,0x69,0x8f, ++ 0x86,0xd5,0x7d,0x2a,0xa7,0x45,0xfb,0x1b,0x8c,0x9a,0x9b,0x06,0x35,0xb7,0x5d,0x82, ++ 0x89,0x27,0xec,0xce,0x7c,0x4c,0x8b,0xf7,0x93,0xde,0x7b,0x2a,0x3f,0xbd,0xee,0x4e, ++ 0xad,0x4d,0x02,0x0d,0x32,0xb3,0x8a,0xc5,0xce,0x64,0x6a,0x51,0x53,0x5f,0x90,0x56, ++ 0x58,0x40,0xed,0x8d,0xac,0x47,0xbf,0xa9,0x19,0xd5,0x1b,0x2a,0x07,0x57,0xe4,0x84, ++ 0xf2,0x80,0x2f,0x80,0xb2,0x16,0xfb,0x3e,0xae,0x28,0x87,0x51,0x40,0x0a,0x58,0xe7, ++ 0x0f,0x3c,0xbc,0x66,0x42,0x13,0x7c,0xee,0xc9,0x9d,0x88,0x70,0x95,0x0a,0xca,0x9c, ++ 0x7b,0x10,0x90,0xd9,0x9e,0x62,0x01,0x1c,0x5c,0x86,0x9d,0xa0,0x8e,0x21,0xb8,0xcf, ++ 0xa8,0xa4,0x47,0xbd,0xdc,0xba,0x2e,0x1a,0x4b,0x54,0xa9,0x74,0xee,0x51,0x11,0xa6, ++ 0x44,0x94,0xb5,0x7f,0xc3,0x10,0xc5,0x1b,0xa7,0xc4,0x50,0x84,0x22,0x2b,0xb2,0x1f, ++ 0xec,0xaf,0xbf,0x81,0xeb,0xbd,0xcb,0x20,0x3f,0xd2,0x02,0x00,0xdf,0x62,0xa0,0x9a, ++ 0x95,0x95,0x18,0x4b,0xe8,0xdd,0xa9,0x56,0xa3,0x51,0xf0,0x2a,0x68,0x95,0x37,0xf0, ++ 0x60,0x42,0x99,0x00,0xef,0xdd,0xd1,0x38,0x00,0x59,0x26,0x24,0x5d,0x6e,0xac,0x0a, ++ 0xea,0x77,0x19,0xd2,0x93,0xd6,0x9d,0xf7,0xa3,0x02,0x00,0xb1,0xa8,0xfb,0x38,0x59, ++ 0xf8,0x54,0x3b,0x46,0x56,0xf8,0x68,0x8f,0xbf,0xe5,0x92,0x04,0x7a,0xe5,0x92,0x69, ++ 0x05,0x2f,0x67,0x70,0xc7,0xa6,0xe1,0x92,0xef,0x38,0x42,0xee,0xd3,0x17,0x3d,0x33, ++ 0x79,0x8d,0xfa,0x1b,0x4f,0x9b,0x69,0xe5,0xea,0xc2,0xd3,0x85,0xf2,0x24,0x9b,0x33, ++ 0x70,0xac,0x6e,0xe4,0x7a,0xed,0x21,0x81,0xf8,0xf6,0xc9,0x51,0xc1,0x25,0x82,0xce, ++ 0x9a,0x0b,0x86,0x4b,0x99,0x26,0x4b,0x06,0xed,0xc8,0x2d,0x4c,0xef,0xcc,0x62,0xda, ++ 0x8f,0xfc,0xac,0x1b,0xdf,0x8d,0x40,0xe9,0x71,0x56,0x3e,0x5e,0x7a,0x09,0xe0,0xf2, ++ 0xf7,0x0a,0x24,0x0b,0x4c,0x4e,0xeb,0x0d,0x29,0x75,0x0a,0x2b,0x10,0x53,0x9b,0x02, ++ 0xb1,0xf6,0x2b,0x8a,0x60,0xa7,0xa3,0x59,0xbd,0x09,0x77,0x3f,0xd1,0x07,0x3a,0x5d, ++ 0xea,0xd9,0xe5,0xae,0xfa,0x8d,0x92,0x48,0x60,0x41,0xcd,0x46,0xda,0x0e,0xe6,0xdd, ++ 0xde,0x6f,0x1e,0xa2,0xe6,0xac,0x23,0x06,0xec,0x0c,0x1e,0x57,0x5d,0xd7,0x3b,0xa1, ++ 0x86,0xd2,0xfb,0xb2,0x73,0x21,0xa8,0x99,0x81,0xbf,0x83,0x49,0xd8,0x2c,0x22,0xb2, ++ 0x74,0x84,0xda,0xae,0xf5,0xf2,0xf3,0x5d,0x4e,0xae,0x4d,0x7f,0xcb,0x2d,0x56,0x33, ++ 0x26,0x11,0xfb,0x79,0x30,0x3e,0xb4,0x9b,0xe4,0xcf,0xaf,0x63,0xba,0xfa,0x37,0x72, ++ 0x8d,0xac,0x4c,0xb4,0x23,0x2a,0x96,0x72,0x67,0xb9,0x56,0x56,0x91,0x2a,0x2c,0x05, ++ 0x88,0x96,0xed,0x03,0x4c,0x73,0xd5,0x68,0x84,0x10,0xdd,0x9c,0x01,0xd6,0x75,0x61, ++ 0x3d,0xe2,0x0b,0xcb,0x3c,0x51,0x9f,0xb8,0x5b,0xa3,0x9d,0x84,0xfa,0x8c,0x18,0xc5, ++ 0xf3,0xe9,0x28,0x44,0xce,0x14,0x6a,0x34,0x02,0x8b,0xe2,0xec,0x99,0xf1,0x8c,0xf1, ++ 0x75,0x18,0x2e,0xcb,0xfd,0x9e,0x24,0xc2,0x9c,0x4e,0x73,0x07,0xa3,0x81,0x6e,0x31, ++ 0x40,0xc7,0x69,0x87,0x31,0xe2,0xaa,0x92,0xa9,0xa2,0x7d,0x6f,0x2f,0xcb,0xb2,0x21, ++ 0x6f,0xc6,0xab,0xd1,0xd8,0xb1,0x77,0x82,0x40,0x18,0xfa,0x04,0x6f,0x65,0x7f,0xee, ++ 0xdf,0x93,0x2d,0x09,0xab,0x07,0xb8,0x8c,0x1f,0x58,0x2f,0x1d,0xdb,0xa7,0xf6,0xbc, ++ 0x0b,0xba,0x4e,0xbc,0xbd,0x34,0xa5,0x08,0x99,0x86,0xf8,0x78,0x7a,0xfb,0x49,0xb4, ++ 0x1b,0xc7,0x78,0x7d,0x8b,0xab,0x4d,0x58,0x94,0xa5,0x22,0x6c,0x45,0x14,0x5e,0xb9, ++ 0xcb,0xb8,0xf0,0x19,0x92,0x5b,0xb8,0xbf,0x02,0x3f,0xc5,0x95,0x85,0xd4,0x86,0xe8, ++ 0xf2,0x5e,0x46,0xbe,0xd1,0xf9,0x57,0x97,0xcd,0x1d,0x3e,0x66,0x58,0xaa,0x36,0xa2, ++ 0xc0,0x12,0x4f,0x2f,0xdb,0x71,0x64,0x40,0x80,0x39,0x29,0x3e,0xf8,0x3b,0x53,0xc8, ++ 0x15,0x4b,0xb9,0xfa,0xd1,0x9b,0xea,0xd0,0x01,0x1a,0xa8,0xd3,0x0c,0x8b,0x7d,0xf4, ++ 0x54,0xb2,0xae,0xc7,0x6b,0x8b,0xb3,0x86,0x21,0x1b,0x68,0xd9,0x98,0x64,0x7e,0xe0, ++ 0x40,0x05,0xea,0xe4,0x55,0xe0,0xba,0x3d,0x42,0x08,0x50,0x92,0x76,0x23,0x12,0xa2, ++ 0xe7,0xc3,0x28,0x08,0xf1,0x55,0xf8,0xfb,0x21,0xfc,0x9e,0x5f,0xd9,0x6a,0x33,0xc4, ++ 0x6f,0xc6,0xdf,0x94,0xff,0x24,0x6f,0x18,0x40,0x5d,0xb4,0x34,0xe1,0xa6,0x39,0x59, ++ 0x83,0xa2,0x1f,0xe6,0x7d,0xe3,0x2f,0x51,0xa5,0x50,0xbd,0xd5,0xd3,0xc8,0xba,0x7b, ++ 0x00,0xae,0xb2,0x70,0xfd,0x67,0xd8,0x56,0xc3,0x65,0xeb,0x12,0xd6,0x84,0x1f,0xc4, ++ 0xd4,0xc4,0x48,0xa6,0x9f,0x76,0xd2,0x94,0x74,0xc2,0xf8,0x52,0xd8,0xe7,0xb3,0x3c, ++ 0x25,0x36,0xbb,0x05,0xea,0x09,0xb1,0xdf,0x26,0xdd,0x31,0x87,0xa7,0x1d,0xc2,0x2c, ++ 0x52,0x0c,0x5e,0x51,0x60,0x0c,0x23,0x77,0x60,0xd7,0x4e,0x76,0x5a,0xeb,0xfb,0x70, ++ 0xaf,0xed,0xfc,0x3c,0x18,0xe4,0x4c,0x2c,0xad,0x4b,0x8e,0x08,0x3a,0x65,0x52,0x0e, ++ 0xed,0x08,0x8d,0xef,0x81,0xbb,0xfa,0x6e,0xce,0x8b,0x5a,0x01,0x79,0x55,0x1c,0xe9, ++ 0x71,0x21,0xc2,0x01,0x4c,0xde,0xc7,0xaf,0x81,0x0a,0x67,0xd0,0x5f,0xe4,0x3c,0xe8, ++ 0x09,0x06,0x43,0x95,0xbf,0x7d,0xb1,0xb0,0xcb,0x03,0x04,0x64,0x2d,0x81,0x54,0x76, ++ 0x08,0xad,0xea,0x4e,0xd6,0x66,0x28,0xa2,0xe9,0x41,0x9a,0x70,0x98,0x18,0x33,0x66, ++ 0x09,0x8c,0xb8,0x65,0x71,0x38,0xa1,0x0c,0x7c,0x19,0xa4,0xec,0x1f,0x42,0xa1,0x29, ++ 0x71,0x05,0xef,0x60,0xf4,0xfb,0x2a,0x64,0x29,0xd5,0x15,0x1d,0x35,0x48,0xcb,0x39, ++ 0x74,0xcd,0x39,0x5b,0xc0,0x34,0x81,0xff,0xb2,0xfc,0x49,0x8c,0x33,0x44,0xe4,0xdb, ++ 0x41,0x2f,0x0d,0xf9,0xa1,0xf2,0x0c,0xe5,0x6a,0x6f,0x14,0x56,0xcc,0x23,0x01,0xe9, ++ 0xbc,0xea,0xba,0x7e,0x79,0x6d,0x06,0x17,0x96,0x25,0x39,0xab,0x8b,0xf1,0x9e,0x33, ++ 0x68,0xcd,0xb5,0x46,0xb2,0xb3,0x81,0xc1,0x9c,0x6d,0xcb,0xa0,0x0d,0xfd,0x29,0xf8, ++ 0x24,0x9e,0x01,0x12,0x60,0xd1,0x9d,0xad,0x69,0xb6,0xb9,0xab,0x75,0x3e,0x1c,0x6e, ++ 0xd1,0xd5,0xc3,0x37,0xaa,0xa6,0xcf,0x71,0xea,0xdc,0x63,0x62,0x56,0xb0,0x54,0x3c, ++ 0x8b,0x98,0x93,0xe9,0xc9,0x60,0x1b,0x0d,0x92,0x53,0x6b,0x72,0x5f,0x37,0x5a,0x47, ++ 0x86,0x89,0x0d,0x4d,0x94,0x60,0xf0,0x8c,0x1d,0x2b,0xcd,0x19,0x95,0x53,0x90,0xac, ++ 0xcf,0x9a,0x1e,0xec,0x4d,0x22,0x7d,0x0d,0x67,0xe5,0x46,0x15,0x94,0x13,0x7c,0xc8, ++ 0x50,0xa7,0xcf,0x65,0xc3,0x33,0x82,0xc8,0xe1,0xba,0xb5,0xac,0xa5,0xb9,0x13,0xd0, ++ 0xde,0x22,0x89,0x1a,0x15,0x99,0x85,0x02,0xb4,0x24,0xa9,0x3a,0x76,0xb1,0x7d,0x88, ++ 0xda,0x86,0x01,0xb7,0xba,0xbb,0xec,0xab,0x94,0x25,0x8d,0x54,0x9f,0xb0,0x2b,0x59, ++ 0x0c,0xa4,0xd0,0xf1,0xbb,0x9a,0x10,0xfc,0xe3,0x44,0x87,0x40,0x70,0x99,0xa6,0xeb, ++ 0x19,0xc1,0x95,0x0c,0xbd,0xfa,0xcb,0xd7,0x85,0x98,0x61,0x6a,0x5e,0x48,0x7e,0xf0, ++ 0x29,0x9f,0xf6,0x5a,0x7d,0xb4,0xfd,0x3a,0x7f,0xa0,0x69,0x7a,0x57,0x2f,0x1f,0xec, ++ 0x13,0xdc,0x50,0xeb,0x43,0x3c,0x4d,0x57,0xe8,0x36,0xcf,0x11,0x9d,0x79,0x5f,0xb9, ++ 0x18,0xfa,0x29,0x4f,0x9e,0x4d,0xe8,0x04,0x0e,0x0c,0x44,0x1d,0xdb,0xff,0xad,0x7f, ++ 0x9d,0x42,0xce,0x2e,0x92,0x24,0x62,0x21,0x18,0xbb,0xf1,0x84,0x86,0xdf,0xa1,0x7e, ++ 0x6a,0x22,0x90,0x11,0x72,0xde,0x83,0x3b,0xc3,0x49,0x78,0x0b,0x75,0x0f,0x1b,0xc7, ++ 0x15,0xff,0x89,0x67,0xf1,0x77,0x31,0xdd,0xc4,0x00,0x4e,0x25,0x53,0x6c,0x09,0xe2, ++ 0xa3,0x00,0xf1,0x97,0x19,0x72,0xef,0xc1,0xc9,0x4c,0xd9,0x0a,0xd9,0x0f,0x80,0xb0, ++ 0x05,0xb5,0xfe,0xe0,0x14,0x25,0x30,0x3f,0xf5,0xf9,0xcb,0xec,0xf7,0xe2,0x33,0x17, ++ 0xdd,0x0f,0x7c,0x27,0x4c,0x2a,0xe5,0x92,0xc1,0xb9,0x18,0x95,0x8a,0x98,0x81,0x80, ++ 0x87,0x0b,0xb8,0x36,0xc5,0x29,0x29,0xe3,0x1f,0x79,0xd5,0x25,0xda,0x27,0xcb,0x0e, ++ 0x72,0xfb,0xf7,0xf1,0x95,0x06,0x20,0x02,0xd6,0x48,0xc3,0x74,0x86,0x6e,0x05,0x90, ++ 0x3b,0xa9,0xba,0xbe,0x10,0xaa,0x4b,0xac,0xa1,0x39,0xba,0xee,0xa1,0xe4,0x10,0xde, ++ 0xd0,0xf4,0xf2,0x98,0x3b,0x9c,0xdd,0x5a,0x0a,0x96,0xe4,0xaf,0x32,0xdf,0xbb,0x24, ++ 0x77,0x48,0xb9,0x8f,0x10,0x7b,0xeb,0x0d,0x4a,0x49,0xd9,0xcf,0x99,0x7a,0x24,0x77, ++ 0x06,0xbd,0xd3,0x18,0x9d,0x3b,0x63,0xbb,0xcc,0x81,0x9a,0x23,0x3d,0x9f,0xe9,0x33, ++ 0xdf,0xbc,0x1e,0xc8,0x18,0x29,0x32,0x28,0xf7,0xc7,0x52,0x2b,0x7e,0x2e,0xe5,0x7c, ++ 0x89,0xf1,0xf4,0x3d,0xb8,0xa6,0x25,0xfa,0x4a,0xb2,0x62,0x01,0x78,0x0d,0x63,0x87, ++ 0x57,0xd3,0xfd,0x2d,0x39,0x4b,0x57,0x8b,0xe8,0xb1,0x8f,0x18,0xe9,0x9e,0x31,0xa9, ++ 0x83,0x00,0x96,0x6c,0xbd,0x6d,0x63,0x59,0x6a,0x70,0x9a,0x1b,0xae,0x66,0xa0,0x82, ++ 0x74,0xbd,0xe4,0x86,0x56,0x3f,0x54,0xdd,0x2a,0xfa,0x9e,0xa0,0xd3,0x76,0xb3,0xa1, ++ 0x40,0xbe,0xac,0x7d,0x13,0x4a,0x1d,0x32,0x64,0xab,0xe4,0x36,0x53,0x83,0x1f,0x05, ++ 0xa3,0x12,0x31,0xfa,0x13,0x69,0x5b,0x70,0xc4,0x1c,0xc5,0x3c,0x93,0x52,0xad,0xe3, ++ 0xd7,0xbc,0x89,0x7d,0x83,0xa8,0x47,0xb4,0x42,0x11,0xa5,0xe5,0xf9,0x7c,0xbb,0xa2, ++ 0x02,0x19,0xbc,0x46,0xdc,0x9b,0x55,0x92,0xe0,0x70,0x88,0x01,0x74,0xae,0x1c,0x5d, ++ 0x17,0xb8,0xcc,0xd4,0x33,0xb8,0x5c,0x0d,0x6b,0x17,0x2c,0xe1,0x3b,0xfc,0x38,0x3c, ++ 0xa2,0x57,0x05,0x45,0xcf,0x36,0xc4,0x03,0xe6,0x46,0x1a,0x61,0xd1,0xe2,0x01,0x16, ++ 0x61,0x17,0xad,0x62,0x50,0x38,0x10,0xf6,0x63,0x69,0x4d,0xae,0x0e,0xcb,0xa2,0xea, ++ 0xd7,0x7b,0xa6,0x75,0x30,0xe3,0x46,0x77,0xcd,0x87,0xf6,0x0c,0x2e,0xf5,0x99,0x67, ++ 0xdc,0x9a,0x89,0x8e,0xb6,0x3b,0x05,0x83,0x5a,0xfb,0xc4,0xb9,0xda,0xf4,0x61,0xeb, ++ 0x5f,0x97,0x87,0x70,0xa8,0x7a,0x16,0xcf,0x17,0x18,0xef,0x2f,0xfd,0xb0,0xdf,0x86, ++ 0x2d,0xb4,0x38,0x9c,0x34,0x37,0xa7,0x3b,0xcb,0x6b,0x60,0x39,0xd2,0x98,0x4e,0xcc, ++ 0x60,0x36,0x56,0x8e,0x9b,0x30,0x0f,0xfa,0x8f,0xa3,0xfd,0x92,0xab,0x3e,0x70,0x1c, ++ 0xa6,0xeb,0x6e,0x9e,0xb8,0x96,0xcd,0x7c,0x60,0x2f,0x73,0xb2,0x8e,0x21,0x79,0x1d, ++ 0xe8,0xe1,0xbf,0x8f,0x36,0x32,0x6d,0x17,0x89,0x8e,0x48,0xaf,0x67,0x83,0x07,0xdd, ++ 0xe3,0x55,0xa7,0x55,0xbd,0x3f,0xe0,0x1b,0x88,0x15,0x1f,0x80,0x7a,0x13,0x28,0x07, ++ 0xb1,0x84,0xa0,0xfb,0x1c,0xe2,0x0a,0xc0,0xc6,0xc3,0x06,0xd7,0xbc,0xa4,0x07,0xe1, ++ 0x27,0x3c,0x38,0x94,0x95,0x22,0x40,0xb0,0x67,0x73,0xd9,0x38,0x85,0x95,0x23,0x78, ++ 0x5d,0xdf,0xec,0x00,0x14,0x3f,0xf6,0x41,0x87,0x7d,0xef,0x15,0x94,0xae,0x57,0xb2, ++ 0x71,0x80,0xf3,0x39,0x36,0x78,0x03,0xd1,0x47,0xc7,0x9e,0xc6,0x49,0x71,0x00,0x1d, ++ 0xb9,0x79,0xf0,0xe7,0xff,0x1e,0xaf,0x62,0x62,0xc2,0x70,0x21,0x72,0x8a,0x57,0xb0, ++ 0x85,0x79,0x37,0x14,0x11,0x8d,0x00,0xf6,0x65,0x70,0x9e,0x07,0x54,0x37,0x19,0xc1, ++ 0x5b,0xd9,0x99,0x63,0xe1,0x82,0x51,0x23,0xa5,0x39,0x61,0x14,0xb7,0x8a,0x14,0x3c, ++ 0x24,0x81,0x9e,0xbf,0x75,0x7a,0x21,0xfe,0x45,0xc3,0x39,0x0a,0xe6,0xe4,0x95,0xab, ++ 0x28,0x25,0x82,0xf3,0x3e,0x13,0x2d,0x48,0xce,0xcb,0x5a,0xa4,0x7e,0x3e,0x3a,0x7c, ++ 0x0b,0x83,0x34,0x5e,0x90,0x24,0x65,0xca,0x49,0xc6,0xd2,0xb8,0xa1,0xa8,0x39,0xeb, ++ 0xdc,0x91,0x27,0xf7,0x9c,0xe8,0xf6,0xc9,0x4e,0x82,0xcc,0xd2,0xdc,0xe4,0x2b,0x04, ++ 0x09,0x5f,0x4c,0xe0,0x7c,0x7d,0x5b,0x9f,0x8c,0x89,0xdb,0x9f,0x83,0xe6,0xcd,0xa0, ++ 0xe7,0xd4,0x1a,0x46,0xe3,0xe3,0x6c,0x08,0x6f,0x6e,0x73,0x7f,0x7c,0xce,0x30,0x5b, ++ 0xac,0x8e,0xf1,0xdc,0xf1,0xe2,0x60,0x7b,0x6e,0x6d,0xbe,0x6f,0x59,0xc6,0x1b,0xc9, ++ 0x8f,0xf3,0xba,0xf0,0x98,0x7d,0x13,0x68,0xfa,0xc3,0xf5,0x6d,0xce,0xed,0x94,0xa0, ++ 0x0d,0x87,0x50,0xbd,0x33,0x52,0xbb,0x16,0xf0,0xc5,0x20,0x7d,0xd3,0xad,0x80,0x72, ++ 0x20,0x9f,0xcc,0x77,0xf2,0xb0,0x4c,0x20,0x46,0x60,0x6b,0xf6,0xf6,0x57,0xec,0xf4, ++ 0x4c,0xe0,0x29,0xe4,0xde,0x37,0x44,0xb0,0x69,0x5a,0x53,0x4c,0x51,0x0a,0xb5,0x9c, ++ 0x98,0x89,0x82,0x10,0xdf,0x14,0x65,0xba,0xa4,0x5f,0x98,0xd5,0x57,0x97,0x35,0xa6, ++ 0x4c,0xe2,0x0e,0xa1,0x69,0x56,0x39,0x51,0xe3,0x39,0x42,0xc5,0x02,0x4c,0x5a,0x07, ++ 0xa9,0x12,0x24,0x42,0x1d,0x32,0xe7,0x66,0x6d,0x9c,0x4b,0x69,0x89,0x29,0xa0,0xa1, ++ 0x6c,0x17,0x94,0x54,0x3e,0xd1,0xeb,0x0d,0x33,0x02,0x9b,0x88,0xa5,0xfd,0x65,0x83, ++ 0xa2,0x34,0x85,0x87,0x18,0x3b,0x4f,0x01,0x85,0x26,0x14,0x19,0x7b,0x0b,0x92,0xa0, ++ 0xe4,0xfb,0xd5,0x87,0xbf,0xb8,0xfc,0x99,0x90,0x42,0x79,0x30,0x77,0xd7,0x7e,0x92, ++ 0x1f,0xea,0xf8,0xbd,0x30,0x13,0x47,0x28,0x69,0xbc,0xd6,0x18,0xb8,0xf5,0x1c,0x65, ++ 0xd9,0x96,0x0f,0x84,0xa1,0x0d,0x5e,0xb8,0x6c,0xd4,0xf6,0x26,0xff,0x3e,0x9f,0x7a, ++ 0x0f,0x69,0x95,0x8e,0x39,0xac,0x6d,0xbb,0x4f,0x9b,0xcc,0xd4,0x71,0x6c,0x0f,0x92, ++ 0x44,0xea,0xf1,0x90,0xaf,0xf5,0x45,0xdb,0xb9,0x99,0xfc,0xdd,0x84,0xf2,0x81,0x0a, ++ 0x2a,0x3c,0x8e,0x0c,0xbd,0xf8,0xa9,0x1e,0x51,0x1a,0x5a,0x2e,0xc7,0xbd,0x14,0xa8, ++ 0x8c,0x9b,0x86,0xbc,0x19,0xd3,0xfe,0x93,0x78,0x29,0xd2,0x7b,0xf6,0x9d,0x2d,0xef, ++ 0x2c,0x62,0x8f,0xc8,0x3d,0xb1,0xae,0xeb,0x0f,0x61,0xdb,0xfa,0x77,0xae,0xc0,0x34, ++ 0x52,0x90,0xb6,0x8c,0x1a,0x39,0xaf,0x7f,0x97,0x76,0xd3,0xe7,0x77,0xdd,0x00,0x43, ++ 0x04,0x24,0x20,0x77,0xb3,0xa3,0xd0,0x9c,0x88,0xc8,0x96,0x11,0xb9,0x81,0x08,0x54, ++ 0xef,0x9e,0xf0,0x33,0xec,0x2e,0x60,0x14,0xc3,0x65,0xa6,0x10,0x57,0xd9,0x5f,0x01, ++ 0x08,0x68,0xb7,0xf6,0x1c,0xff,0x19,0xc3,0x81,0x46,0x3d,0xb7,0x8c,0x6a,0x09,0x11, ++ 0x84,0xe4,0x19,0xe9,0x75,0xd8,0x92,0x53,0x80,0x47,0xae,0xdd,0x0f,0x2e,0xa8,0x7d, ++ 0xe9,0x40,0x95,0xe5,0x30,0xde,0x30,0x20,0xe0,0x99,0xc9,0xc2,0x1e,0xc9,0xec,0x32, ++ 0xf4,0x8e,0xc8,0xd6,0x1a,0x98,0xc8,0xf2,0x42,0xa2,0xc2,0x8b,0x55,0x5c,0x7b,0xf1, ++ 0x2c,0xa9,0x95,0xe5,0xb8,0x25,0x29,0x46,0x3f,0x49,0xcb,0x85,0x82,0xcd,0xa5,0x6c, ++ 0x68,0x43,0xf1,0x85,0x64,0x28,0x63,0x93,0x41,0x4f,0xaa,0xf1,0xf8,0x0c,0xfb,0x08, ++ 0x08,0x20,0x93,0xe1,0x74,0x83,0x6a,0xac,0x6b,0x54,0x6d,0xcc,0x4c,0x73,0xdc,0x18, ++ 0x0f,0x0a,0xb9,0xc9,0x1f,0x40,0xf6,0xaa,0x49,0x41,0xd8,0x7c,0x09,0x6d,0xf5,0xe2, ++ 0x88,0x26,0xd0,0x24,0x60,0x30,0x73,0x2a,0x9d,0x47,0x26,0x4b,0x55,0xec,0x3c,0x79, ++ 0xdb,0x10,0xbf,0x0e,0xf5,0xf3,0x1c,0xd1,0xdb,0x06,0x1d,0xd5,0x65,0x26,0x78,0xf8, ++ 0xa4,0xa3,0x76,0x2e,0x59,0xf3,0xa0,0x0a,0x09,0x93,0x12,0xb8,0x10,0x2d,0x48,0xa7, ++ 0x2f,0x4f,0xb2,0xde,0x12,0xf0,0x50,0x38,0xe8,0x4b,0x21,0xfe,0x5a,0x88,0xe7,0x2b, ++ 0x07,0xd8,0xbb,0x6a,0xf9,0xde,0x2b,0x0b,0x89,0xbe,0xb3,0x2d,0x36,0x63,0x02,0x13, ++ 0x6a,0xa0,0xf3,0x0d,0x9f,0x20,0x53,0xcb,0x3e,0x40,0xe3,0x3a,0x0d,0x03,0x54,0x31, ++ 0x04,0x45,0x3b,0xc3,0xe6,0x38,0x14,0x24,0x49,0x22,0x54,0xc9,0x14,0x3e,0x08,0xfb, ++ 0xa0,0x1c,0x1c,0x69,0x31,0x70,0x64,0x97,0x9c,0x5e,0xa4,0x4f,0x90,0x12,0x98,0xaa, ++ 0xd1,0x69,0x87,0xfa,0x66,0xcd,0x75,0x01,0xa6,0xdf,0x05,0x81,0x51,0xd3,0x57,0xb9, ++ 0xc9,0x09,0x61,0x15,0x4d,0x13,0x8d,0xc3,0x12,0xce,0xe6,0x72,0x0c,0xc5,0xc0,0xa0, ++ 0x3e,0x9f,0x6c,0xec,0x22,0x7b,0xa1,0x92,0xc1,0x52,0x38,0x64,0x8e,0x54,0x9f,0x2e, ++ 0xfe,0x9f,0xcd,0x32,0xb6,0x64,0xa7,0x12,0xc2,0xdf,0xe4,0x07,0x07,0xd1,0xc1,0xfc, ++ 0x5d,0x9b,0xc4,0x23,0xa2,0x79,0x5d,0x4f,0x43,0xdc,0x79,0x67,0xf3,0xb3,0x36,0x8e, ++ 0x20,0x19,0x94,0xcf,0xd4,0xf1,0xda,0x13,0x61,0x5f,0x32,0xc8,0x75,0x82,0x7b,0x78, ++ 0xcc,0xbb,0x2a,0xce,0xbb,0x3e,0xba,0x3b,0x31,0x52,0x2d,0x36,0x79,0x98,0x75,0x61, ++ 0x21,0x17,0xf6,0x1e,0x38,0x86,0xde,0x98,0x43,0x54,0xfd,0x42,0x5d,0x15,0xc9,0xc3, ++ 0x11,0x06,0x8f,0x52,0xdb,0xaa,0xd1,0x59,0xb6,0xcb,0x28,0x36,0x07,0xa7,0x37,0x72, ++ 0xde,0x1b,0xb7,0x2f,0xe9,0xbb,0xe0,0x4b,0xc8,0x6b,0xa0,0x22,0x06,0xe6,0xa6,0xf7, ++ 0x0e,0x10,0x56,0x8b,0xc7,0x8a,0x27,0x96,0xc9,0x39,0x65,0xd0,0x86,0x8d,0xea,0x9a, ++ 0xaf,0x11,0x62,0xac,0xbb,0xbb,0x52,0x9f,0xca,0xd5,0x61,0xc5,0x90,0x39,0x7f,0x8b, ++ 0x09,0x12,0x38,0xb3,0x68,0xe1,0xe8,0x0b,0xce,0x58,0x47,0x9f,0x09,0xcc,0x27,0x28, ++ 0x28,0x1d,0xef,0x1d,0xab,0x53,0x5b,0x1b,0x94,0xd6,0xe5,0x41,0x10,0x1b,0x81,0x64, ++ 0xfb,0x9b,0x86,0x2e,0x49,0xbb,0xdc,0xb0,0x25,0xca,0x1c,0xb9,0x55,0x80,0x90,0xd5, ++ 0xc7,0x03,0xa9,0x65,0x21,0xee,0x18,0x5c,0x41,0x18,0xe1,0x60,0xf0,0x61,0x07,0x65, ++ 0xf8,0xcd,0x7d,0x74,0xac,0xed,0x37,0xa7,0xef,0x44,0x71,0xc6,0xde,0xa3,0x21,0x92, ++ 0xfa,0xe3,0x39,0x50,0xae,0xe7,0xfc,0x41,0x36,0x7c,0x41,0xb3,0xf6,0x2e,0x7a,0xaa, ++ 0xce,0x4b,0x70,0xd7,0x01,0x0f,0xc4,0x1d,0xe5,0x85,0x17,0x26,0x5a,0x8a,0x92,0x14, ++ 0x4b,0xc9,0xda,0x66,0xd4,0x0a,0x6f,0x71,0x2c,0x14,0x80,0x52,0x51,0x14,0xc9,0x4f, ++ 0xb5,0xa2,0x99,0x43,0x7f,0xfc,0xb1,0xdf,0x7a,0x6d,0xd1,0x66,0x5b,0xec,0xa9,0xbb, ++ 0x17,0x48,0x49,0x24,0x34,0x24,0x51,0x8a,0xf7,0x5c,0xc4,0x8a,0xe7,0x3c,0xe2,0xc3, ++ 0x80,0x8e,0x1c,0xe6,0x94,0x6e,0xef,0xaa,0x7b,0x29,0xeb,0x78,0xf9,0x86,0x2e,0xf8, ++ 0x29,0x04,0x6a,0x43,0xe4,0xa1,0xd7,0xd7,0x35,0x92,0x65,0x3f,0x5b,0xa0,0x2f,0x0c, ++ 0x2d,0x02,0xe1,0x1c,0xf5,0xa5,0x4e,0xc1,0xca,0x1a,0xd1,0x27,0xdd,0x5a,0x72,0x08, ++ 0x2a,0xca,0x2f,0x20,0xf4,0xea,0xce,0xd2,0xdd,0xd0,0xa5,0xbb,0xd8,0x2d,0xca,0x52, ++ 0x8b,0x8c,0xd4,0xbd,0x92,0xa1,0xc0,0x79,0x01,0xc4,0x40,0xea,0x68,0x33,0x2a,0x65, ++ 0x07,0xe1,0x7a,0x2c,0x2c,0x19,0xe9,0x44,0x37,0x8d,0x3c,0x7b,0x59,0xff,0x8b,0x4f, ++ 0xaa,0xe0,0x18,0x68,0x3f,0x51,0x55,0xa3,0xc7,0x3b,0x33,0xab,0xde,0xed,0x43,0x99, ++ 0x72,0x05,0x11,0xb7,0x79,0xe0,0xb4,0x83,0x4d,0xc7,0xfb,0x7b,0xa6,0x5f,0xfb,0x9e, ++ 0x22,0x20,0x7b,0x87,0xb4,0xf0,0x1b,0xd8,0xbd,0x92,0x57,0x58,0x50,0x8c,0xb3,0x00, ++ 0x2d,0x9b,0x4c,0xa9,0x11,0x3c,0xbe,0xaa,0xe5,0xbc,0x7c,0x36,0x09,0x8c,0x07,0xa7, ++ 0x29,0x3f,0x7a,0x87,0x37,0xbc,0xaf,0xd3,0xd7,0x89,0x0a,0xe8,0xc7,0xd8,0xa9,0x17, ++ 0xd3,0xa8,0xd3,0xa2,0xd6,0xfc,0xad,0xc0,0xf2,0xbf,0xab,0xd5,0x9d,0xfe,0xa4,0x82, ++ 0x8b,0x9a,0xde,0x59,0xc9,0x39,0xb4,0x9f,0xa4,0xd2,0xcc,0xde,0x85,0x49,0xc8,0x10, ++ 0x84,0x9b,0x8c,0x76,0x25,0xb6,0x1c,0xb3,0xca,0xd8,0x53,0xd2,0x57,0x34,0x0d,0x01, ++ 0x22,0x98,0x06,0x39,0x92,0xf7,0x7d,0x36,0x47,0x29,0xad,0x04,0x2b,0x6b,0x55,0x77, ++ 0x25,0x9f,0x6b,0xdf,0xd4,0xa1,0x37,0x0d,0x44,0x96,0xbd,0x30,0xc4,0xd0,0x8e,0xba, ++ 0xa9,0xf9,0xb0,0xbb,0x3a,0xb9,0x54,0x36,0x6f,0xca,0xa4,0xa4,0x7a,0xfb,0xe7,0x1c, ++ 0x2b,0x92,0xaa,0xde,0x75,0x4c,0x60,0x58,0x69,0x64,0xde,0x0c,0x4e,0xf4,0xe7,0x37, ++ 0x81,0xd8,0xe7,0xed,0x33,0x3c,0x00,0x67,0xa4,0x80,0xa7,0x2b,0xfe,0x93,0xbd,0x1f, ++ 0xc3,0x3e,0x39,0x1b,0xa8,0xab,0x0d,0x8b,0x2e,0x74,0xbd,0x5d,0xd9,0x70,0x92,0xb8, ++ 0x8d,0x9a,0x9e,0xe9,0x5d,0xba,0xf8,0x3a,0x54,0xdf,0x4e,0x7c,0x0e,0xee,0x6a,0x38, ++ 0x8e,0x17,0x96,0xf9,0x5c,0xbf,0x72,0x3f,0x7e,0x45,0xda,0xbe,0x7b,0x93,0x6f,0x6d, ++ 0x0f,0x16,0x9f,0xeb,0xdd,0xa8,0x27,0x36,0xab,0x46,0x4f,0x9f,0x7e,0x78,0xe8,0x8b, ++ 0x0f,0x90,0x97,0xfb,0xb9,0x46,0x71,0x3e,0xe0,0x25,0x6f,0xb8,0xdb,0x91,0x40,0x3f, ++ 0x08,0x6c,0x7f,0xe6,0x34,0xdd,0x78,0xd1,0xc3,0x50,0x98,0xa0,0x52,0x99,0x30,0x01, ++ 0x5d,0xf6,0x37,0x8f,0xee,0x60,0x70,0xf2,0xe0,0x02,0x08,0xb6,0x3f,0xa0,0x29,0xc3, ++ 0x7d,0x01,0x6d,0x9e,0x91,0xa2,0xd1,0x34,0x77,0x4c,0x00,0x0b,0x64,0x37,0x09,0x10, ++ 0xd5,0x0d,0x25,0x6e,0x4f,0xdc,0x79,0x91,0xcd,0xce,0xc3,0x20,0x72,0x06,0xbf,0xbf, ++ 0xfd,0xfb,0x3f,0xbb,0xed,0xdb,0xaf,0x9f,0xbd,0xbb,0x2f,0x9b,0xad,0x9b,0xb7,0xaf, ++ 0xfc,0xfa,0x37,0xab,0xec,0xda,0xa7,0x8f,0xbc,0xba,0x27,0x8b,0xac,0x9a,0xbe,0xbe, ++ 0x7d,0xf9,0x3e,0xba,0x6d,0xd9,0xae,0x9e,0x3d,0xb9,0x2e,0x9a,0x2d,0x99,0xb6,0xae, ++ 0x7c,0xf8,0x36,0xaa,0x6c,0xd8,0xa6,0x8e,0x3c,0xb8,0x26,0x8a,0x2c,0x98,0x6a,0x8e, ++ 0xf4,0x49,0x12,0x7e,0x2b,0xbd,0x6a,0x88,0xb7,0xf7,0xc8,0xd3,0xfb,0x29,0xf2,0x6a, ++ 0x3a,0xdf,0x3f,0xfa,0x9c,0xaa,0x1e,0xda,0x6d,0x4f,0x65,0x4e,0xfa,0x94,0x5a,0x93, ++ 0xeb,0xf5,0x7b,0x05,0x3f,0x31,0x73,0x89,0xc4,0xc1,0xf3,0x6d,0x76,0x67,0xf3,0xf1, ++ 0x2d,0x80,0x0b,0xfd,0xdb,0x65,0x17,0x47,0x68,0xc1,0xe3,0x19,0x5b,0x88,0xbd,0xb7, ++ 0xf5,0xf3,0x3d,0xb3,0xe5,0xd3,0xad,0x97,0xb5,0xb3,0x2d,0x93,0xa5,0x93,0xb5,0xa7, ++ 0xf4,0xf2,0x35,0xa3,0xe4,0xd2,0xa5,0x87,0xb4,0xb2,0x25,0x83,0xa4,0x92,0xbc,0xb6, ++ 0x75,0xf1,0x3c,0xb2,0x65,0xd1,0xac,0x96,0x35,0xb1,0x2c,0x92,0x25,0x91,0xb4,0xa6, ++ 0x74,0xf0,0x34,0xa2,0x64,0xd0,0xa4,0x86,0x34,0xb0,0x24,0x82,0x24,0x90,0x24,0x95, ++ 0xad,0x9d,0x11,0x73,0x14,0xbd,0x11,0x1f,0x68,0x30,0x11,0x20,0x58,0xa4,0xf7,0xb4, ++ 0xae,0x13,0x4c,0x54,0x1c,0xe6,0xdc,0x10,0xce,0x58,0xa4,0xe4,0x31,0x7e,0xe2,0x7e, ++ 0x41,0xc4,0x7e,0xfb,0xd0,0xa3,0xd5,0x41,0x7e,0x13,0x05,0x27,0x70,0xfa,0xba,0x90, ++ 0x2c,0x1f,0xcd,0x62,0x95,0xbe,0x99,0x0e,0xed,0x33,0x0d,0x31,0x87,0x2b,0xbb,0x3f, ++ 0xdd,0xeb,0x3b,0x3b,0xcd,0xcb,0xab,0x1f,0x9d,0xab,0x2b,0x1b,0x8d,0x8b,0xb3,0x2f, ++ 0xdc,0xea,0x33,0x2b,0xcc,0xca,0xa3,0x0f,0x9c,0xaa,0x23,0x0b,0x8c,0x8a,0xba,0x3e, ++ 0x5d,0xe9,0x3a,0x3a,0x4d,0xc9,0xaa,0x1e,0x1d,0xa9,0x2a,0x1a,0x0d,0x89,0xb2,0x2e, ++ 0x5c,0xe8,0x32,0x2a,0x4c,0xc8,0xa2,0x0e,0x1c,0xa8,0x22,0x0a,0x0c,0x88,0x6e,0x88, ++ 0x43,0xfc,0xdf,0x0c,0x9f,0x3e,0x96,0x48,0xf6,0x1a,0x56,0xd9,0x79,0x39,0xee,0xa7, ++ 0x0d,0x57,0xcb,0x7a,0x1d,0xc4,0x1e,0x45,0x79,0xe2,0xb9,0x4a,0x5d,0x7f,0x03,0x89, ++ 0x2b,0x14,0xf1,0xc7,0x1b,0x21,0x88,0xa0,0xcc,0x81,0x28,0x9d,0xb4,0x61,0x4f,0xeb, ++ 0x42,0x92,0xa9,0x49,0x1a,0xbe,0x51,0x55,0x69,0x60,0x97,0xda,0x04,0x74,0xb9,0x37, ++ 0xd5,0xe3,0x39,0x33,0xc5,0xc3,0xa9,0x17,0x95,0xa3,0x29,0x13,0x85,0x83,0xb1,0x27, ++ 0xd4,0xe2,0x31,0x23,0xc4,0xc2,0xa1,0x07,0x94,0xa2,0x21,0x03,0x84,0x82,0xb8,0x36, ++ 0x55,0xe1,0x38,0x32,0x45,0xc1,0xa8,0x16,0x15,0xa1,0x28,0x12,0x05,0x81,0xb0,0x26, ++ 0x54,0xe0,0x30,0x22,0x44,0xc0,0xa0,0x06,0x14,0xa0,0x20,0x02,0x04,0x80,0xdf,0xe4, ++ 0xe5,0x90,0xa1,0x82,0x62,0x6c,0x4f,0xc0,0xc6,0xe8,0xa2,0x54,0xf7,0x85,0x77,0xd0, ++ 0x36,0x0d,0x28,0x6a,0xe3,0xa7,0x40,0x16,0x43,0xc2,0x78,0x1a,0x9c,0xe0,0xd9,0x27, ++ 0xf7,0xb4,0x7e,0xf3,0xe3,0xe2,0x0e,0x41,0x85,0xe2,0xeb,0xd8,0x77,0xa3,0x91,0xfd, ++ 0x95,0xce,0xa1,0x5a,0xf6,0xc3,0xc5,0x53,0xc9,0x34,0x3e,0x32,0xd3,0x7a,0x9f,0xbd, ++ 0xf9,0x7b,0x1f,0xb9,0xe9,0x5b,0x8f,0x9d,0xb9,0x3b,0x0f,0x99,0xa9,0x1b,0x97,0xad, ++ 0xf8,0x7a,0x17,0xa9,0xe8,0x5a,0x87,0x8d,0xb8,0x3a,0x07,0x89,0xa8,0x1a,0x9e,0xbc, ++ 0x79,0x79,0x1e,0xb8,0x69,0x59,0x8e,0x9c,0x39,0x39,0x0e,0x98,0x29,0x19,0x96,0xac, ++ 0x78,0x78,0x16,0xa8,0x68,0x58,0x86,0x8c,0x38,0x38,0x06,0x88,0x28,0x18,0xdf,0xf7, ++ 0xcf,0x53,0xda,0x8c,0x1d,0xf0,0xb6,0x2f,0x48,0x31,0x13,0x0a,0xd9,0x6b,0x86,0x64, ++ 0x6c,0x8d,0x51,0x60,0x7d,0xa9,0xaa,0xbe,0x6f,0xa6,0xe3,0x10,0xfa,0xa8,0xc4,0x0f, ++ 0xa1,0x74,0x99,0xed,0xb8,0x27,0x36,0xaf,0xef,0xbc,0x1f,0xdf,0xcc,0x1c,0x49,0x19, ++ 0x8c,0xcb,0x6b,0xdf,0xb0,0x7c,0x63,0x3e,0xc9,0x32,0xeb,0x32,0x95,0xa7,0x9d,0xb5, ++ 0xf1,0x73,0x1d,0xb1,0xe1,0x53,0x8d,0x95,0xb1,0x33,0x0d,0x91,0xa1,0x13,0x95,0xa5, ++ 0xf0,0x72,0x15,0xa1,0xe0,0x52,0x85,0x85,0xb0,0x32,0x05,0x81,0xa0,0x12,0x9c,0xb4, ++ 0x71,0x71,0x1c,0xb0,0x61,0x51,0x8c,0x94,0x31,0x31,0x0c,0x90,0x21,0x11,0x94,0xa4, ++ 0x70,0x70,0x14,0xa0,0x60,0x50,0x84,0x84,0x30,0x30,0x04,0x80,0x20,0x10,0x7d,0x81, ++ 0xc3,0x96,0xb3,0x79,0xd5,0x13,0x64,0x4f,0x6c,0x90,0x24,0x24,0x75,0x0e,0x54,0x54, ++ 0x91,0xd0,0x8c,0x6b,0x24,0x0a,0x63,0xf0,0xd9,0xcb,0x43,0x49,0x8a,0x0e,0x2d,0x2c, ++ 0x07,0x12,0xdd,0x79,0x90,0x69,0x75,0x99,0x97,0xf6,0x8f,0x45,0xd0,0x0d,0x17,0x60, ++ 0xd8,0x3c,0xf8,0x6f,0xb5,0xf1,0x8c,0x66,0x9a,0xdf,0x42,0x48,0x0a,0x0c,0x9b,0x3d, ++ 0xd9,0x6b,0x1b,0x39,0xc9,0x4b,0x8b,0x1d,0x99,0x2b,0x0b,0x19,0x89,0x0b,0x93,0x2d, ++ 0xd8,0x6a,0x13,0x29,0xc8,0x4a,0x83,0x0d,0x98,0x2a,0x03,0x09,0x88,0x0a,0x9a,0x3c, ++ 0x59,0x69,0x1a,0x38,0x49,0x49,0x8a,0x1c,0x19,0x29,0x0a,0x18,0x09,0x09,0x92,0x2c, ++ 0x58,0x68,0x12,0x28,0x48,0x48,0x82,0x0c,0x18,0x28,0x02,0x08,0x08,0x08,0x7e,0xcc, ++ 0x04,0xd4,0x38,0xce,0x18,0xfa,0xed,0xbd,0x68,0xb1,0x49,0x51,0x83,0x07,0x16,0xca, ++ 0xad,0x96,0x31,0x0f,0x76,0x13,0x5e,0xb8,0x6c,0xd4,0x41,0x41,0x82,0x06,0xb1,0x09, ++ 0x2c,0x12,0xef,0xcf,0xba,0xb8,0xd8,0x2f,0xdd,0xc5,0x48,0x50,0x03,0x05,0xbf,0xd9, ++ 0x0c,0x97,0xe1,0xbb,0xbb,0xb1,0x4d,0x95,0xe1,0x50,0x40,0x40,0x02,0x04,0x99,0x35, ++ 0xd1,0x63,0x19,0x31,0xc1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03,0x91,0x25, ++ 0xd0,0x62,0x11,0x21,0xc0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02,0x98,0x34, ++ 0x51,0x61,0x18,0x30,0x41,0x41,0x88,0x14,0x11,0x21,0x08,0x10,0x01,0x01,0x90,0x24, ++ 0x50,0x60,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00,0x00,0x00,0xff,0xff, ++ 0xff,0xff,0x7f,0xfb,0xef,0xdf,0xef,0xdf,0xbf,0xbf,0x6f,0xdb,0xaf,0x9f,0xf7,0xef, ++ 0xfe,0xfe,0x77,0xeb,0xee,0xde,0xe7,0xcf,0xbe,0xbe,0x67,0xcb,0xae,0x9e,0xfe,0xfe, ++ 0x7f,0xfd,0x7e,0xfa,0x6f,0xdd,0xee,0xde,0x3f,0xbd,0x6e,0xda,0x2f,0x9d,0xf6,0xee, ++ 0x7e,0xfc,0x76,0xea,0x6e,0xdc,0xe6,0xce,0x3e,0xbc,0x66,0xca,0x2e,0x9c,0xbf,0xbf, ++ 0xfd,0xfb,0x3f,0xbb,0xed,0xdb,0xaf,0x9f,0xbd,0xbb,0x2f,0x9b,0xad,0x9b,0xb7,0xaf, ++ 0xfc,0xfa,0x37,0xab,0xec,0xda,0xa7,0x8f,0xbc,0xba,0x27,0x8b,0xac,0x9a,0xbe,0xbe, ++ 0x7d,0xf9,0x3e,0xba,0x6d,0xd9,0xae,0x9e,0x3d,0xb9,0x2e,0x9a,0x2d,0x99,0xb6,0xae, ++ 0x7c,0xf8,0x36,0xaa,0x6c,0xd8,0xa6,0x8e,0x3c,0xb8,0x26,0x8a,0x2c,0x98,0xfd,0xf7, ++ 0xf7,0xf7,0x7d,0xf3,0xe7,0xd7,0xed,0xd7,0xb7,0xb7,0x6d,0xd3,0xa7,0x97,0xf5,0xe7, ++ 0xf6,0xf6,0x75,0xe3,0xe6,0xd6,0xe5,0xc7,0xb6,0xb6,0x65,0xc3,0xa6,0x96,0xfc,0xf6, ++ 0x77,0xf5,0x7c,0xf2,0x67,0xd5,0xec,0xd6,0x37,0xb5,0x6c,0xd2,0x27,0x95,0xf4,0xe6, ++ 0x76,0xf4,0x74,0xe2,0x66,0xd4,0xe4,0xc6,0x36,0xb4,0x64,0xc2,0x26,0x94,0xbd,0xb7, ++ 0xf5,0xf3,0x3d,0xb3,0xe5,0xd3,0xad,0x97,0xb5,0xb3,0x2d,0x93,0xa5,0x93,0xb5,0xa7, ++ 0xf4,0xf2,0x35,0xa3,0xe4,0xd2,0xa5,0x87,0xb4,0xb2,0x25,0x83,0xa4,0x92,0xbc,0xb6, ++ 0x75,0xf1,0x3c,0xb2,0x65,0xd1,0xac,0x96,0x35,0xb1,0x2c,0x92,0x25,0x91,0xb4,0xa6, ++ 0x74,0xf0,0x34,0xa2,0x64,0xd0,0xa4,0x86,0x34,0xb0,0x24,0x82,0x24,0x90,0xfb,0x7f, ++ 0xdf,0xef,0x7b,0x7b,0xcf,0xcf,0xeb,0x5f,0x9f,0xaf,0x6b,0x5b,0x8f,0x8f,0xf3,0x6f, ++ 0xde,0xee,0x73,0x6b,0xce,0xce,0xe3,0x4f,0x9e,0xae,0x63,0x4b,0x8e,0x8e,0xfa,0x7e, ++ 0x5f,0xed,0x7a,0x7a,0x4f,0xcd,0xea,0x5e,0x1f,0xad,0x6a,0x5a,0x0f,0x8d,0xf2,0x6e, ++ 0x5e,0xec,0x72,0x6a,0x4e,0xcc,0xe2,0x4e,0x1e,0xac,0x62,0x4a,0x0e,0x8c,0xbb,0x3f, ++ 0xdd,0xeb,0x3b,0x3b,0xcd,0xcb,0xab,0x1f,0x9d,0xab,0x2b,0x1b,0x8d,0x8b,0xb3,0x2f, ++ 0xdc,0xea,0x33,0x2b,0xcc,0xca,0xa3,0x0f,0x9c,0xaa,0x23,0x0b,0x8c,0x8a,0xba,0x3e, ++ 0x5d,0xe9,0x3a,0x3a,0x4d,0xc9,0xaa,0x1e,0x1d,0xa9,0x2a,0x1a,0x0d,0x89,0xb2,0x2e, ++ 0x5c,0xe8,0x32,0x2a,0x4c,0xc8,0xa2,0x0e,0x1c,0xa8,0x22,0x0a,0x0c,0x88,0xf9,0x77, ++ 0xd7,0xe7,0x79,0x73,0xc7,0xc7,0xe9,0x57,0x97,0xa7,0x69,0x53,0x87,0x87,0xf1,0x67, ++ 0xd6,0xe6,0x71,0x63,0xc6,0xc6,0xe1,0x47,0x96,0xa6,0x61,0x43,0x86,0x86,0xf8,0x76, ++ 0x57,0xe5,0x78,0x72,0x47,0xc5,0xe8,0x56,0x17,0xa5,0x68,0x52,0x07,0x85,0xf0,0x66, ++ 0x56,0xe4,0x70,0x62,0x46,0xc4,0xe0,0x46,0x16,0xa4,0x60,0x42,0x06,0x84,0xb9,0x37, ++ 0xd5,0xe3,0x39,0x33,0xc5,0xc3,0xa9,0x17,0x95,0xa3,0x29,0x13,0x85,0x83,0xb1,0x27, ++ 0xd4,0xe2,0x31,0x23,0xc4,0xc2,0xa1,0x07,0x94,0xa2,0x21,0x03,0x84,0x82,0xb8,0x36, ++ 0x55,0xe1,0x38,0x32,0x45,0xc1,0xa8,0x16,0x15,0xa1,0x28,0x12,0x05,0x81,0xb0,0x26, ++ 0x54,0xe0,0x30,0x22,0x44,0xc0,0xa0,0x06,0x14,0xa0,0x20,0x02,0x04,0x80,0xdf,0xfd, ++ 0xfb,0x7f,0x5f,0xf9,0xeb,0x5f,0xcf,0xdd,0xbb,0x3f,0x4f,0xd9,0xab,0x1f,0xd7,0xed, ++ 0xfa,0x7e,0x57,0xe9,0xea,0x5e,0xc7,0xcd,0xba,0x3e,0x47,0xc9,0xaa,0x1e,0xde,0xfc, ++ 0x7b,0x7d,0x5e,0xf8,0x6b,0x5d,0xce,0xdc,0x3b,0x3d,0x4e,0xd8,0x2b,0x1d,0xd6,0xec, ++ 0x7a,0x7c,0x56,0xe8,0x6a,0x5c,0xc6,0xcc,0x3a,0x3c,0x46,0xc8,0x2a,0x1c,0x9f,0xbd, ++ 0xf9,0x7b,0x1f,0xb9,0xe9,0x5b,0x8f,0x9d,0xb9,0x3b,0x0f,0x99,0xa9,0x1b,0x97,0xad, ++ 0xf8,0x7a,0x17,0xa9,0xe8,0x5a,0x87,0x8d,0xb8,0x3a,0x07,0x89,0xa8,0x1a,0x9e,0xbc, ++ 0x79,0x79,0x1e,0xb8,0x69,0x59,0x8e,0x9c,0x39,0x39,0x0e,0x98,0x29,0x19,0x96,0xac, ++ 0x78,0x78,0x16,0xa8,0x68,0x58,0x86,0x8c,0x38,0x38,0x06,0x88,0x28,0x18,0xdd,0xf5, ++ 0xf3,0x77,0x5d,0xf1,0xe3,0x57,0xcd,0xd5,0xb3,0x37,0x4d,0xd1,0xa3,0x17,0xd5,0xe5, ++ 0xf2,0x76,0x55,0xe1,0xe2,0x56,0xc5,0xc5,0xb2,0x36,0x45,0xc1,0xa2,0x16,0xdc,0xf4, ++ 0x73,0x75,0x5c,0xf0,0x63,0x55,0xcc,0xd4,0x33,0x35,0x4c,0xd0,0x23,0x15,0xd4,0xe4, ++ 0x72,0x74,0x54,0xe0,0x62,0x54,0xc4,0xc4,0x32,0x34,0x44,0xc0,0x22,0x14,0x9d,0xb5, ++ 0xf1,0x73,0x1d,0xb1,0xe1,0x53,0x8d,0x95,0xb1,0x33,0x0d,0x91,0xa1,0x13,0x95,0xa5, ++ 0xf0,0x72,0x15,0xa1,0xe0,0x52,0x85,0x85,0xb0,0x32,0x05,0x81,0xa0,0x12,0x9c,0xb4, ++ 0x71,0x71,0x1c,0xb0,0x61,0x51,0x8c,0x94,0x31,0x31,0x0c,0x90,0x21,0x11,0x94,0xa4, ++ 0x70,0x70,0x14,0xa0,0x60,0x50,0x84,0x84,0x30,0x30,0x04,0x80,0x20,0x10,0xdb,0x7d, ++ 0xdb,0x6f,0x5b,0x79,0xcb,0x4f,0xcb,0x5d,0x9b,0x2f,0x4b,0x59,0x8b,0x0f,0xd3,0x6d, ++ 0xda,0x6e,0x53,0x69,0xca,0x4e,0xc3,0x4d,0x9a,0x2e,0x43,0x49,0x8a,0x0e,0xda,0x7c, ++ 0x5b,0x6d,0x5a,0x78,0x4b,0x4d,0xca,0x5c,0x1b,0x2d,0x4a,0x58,0x0b,0x0d,0xd2,0x6c, ++ 0x5a,0x6c,0x52,0x68,0x4a,0x4c,0xc2,0x4c,0x1a,0x2c,0x42,0x48,0x0a,0x0c,0x9b,0x3d, ++ 0xd9,0x6b,0x1b,0x39,0xc9,0x4b,0x8b,0x1d,0x99,0x2b,0x0b,0x19,0x89,0x0b,0x93,0x2d, ++ 0xd8,0x6a,0x13,0x29,0xc8,0x4a,0x83,0x0d,0x98,0x2a,0x03,0x09,0x88,0x0a,0x9a,0x3c, ++ 0x59,0x69,0x1a,0x38,0x49,0x49,0x8a,0x1c,0x19,0x29,0x0a,0x18,0x09,0x09,0x92,0x2c, ++ 0x58,0x68,0x12,0x28,0x48,0x48,0x82,0x0c,0x18,0x28,0x02,0x08,0x08,0x08,0xd9,0x75, ++ 0xd3,0x67,0x59,0x71,0xc3,0x47,0xc9,0x55,0x93,0x27,0x49,0x51,0x83,0x07,0xd1,0x65, ++ 0xd2,0x66,0x51,0x61,0xc2,0x46,0xc1,0x45,0x92,0x26,0x41,0x41,0x82,0x06,0xd8,0x74, ++ 0x53,0x65,0x58,0x70,0x43,0x45,0xc8,0x54,0x13,0x25,0x48,0x50,0x03,0x05,0xd0,0x64, ++ 0x52,0x64,0x50,0x60,0x42,0x44,0xc0,0x44,0x12,0x24,0x40,0x40,0x02,0x04,0x99,0x35, ++ 0xd1,0x63,0x19,0x31,0xc1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03,0x91,0x25, ++ 0xd0,0x62,0x11,0x21,0xc0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02,0x98,0x34, ++ 0x51,0x61,0x18,0x30,0x41,0x41,0x88,0x14,0x11,0x21,0x08,0x10,0x01,0x01,0x90,0x24, ++ 0x50,0x60,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00,0x00,0x00,0xff,0xff, ++ 0xff,0xff,0x7f,0xfb,0xef,0xdf,0xef,0xdf,0xbf,0xbf,0x6f,0xdb,0xaf,0x9f,0xf7,0xef, ++ 0xfe,0xfe,0x77,0xeb,0xee,0xde,0xe7,0xcf,0xbe,0xbe,0x67,0xcb,0xae,0x9e,0xfe,0xfe, ++ 0x7f,0xfd,0x7e,0xfa,0x6f,0xdd,0xee,0xde,0x3f,0xbd,0x6e,0xda,0x2f,0x9d,0xf6,0xee, ++ 0x7e,0xfc,0x76,0xea,0x6e,0xdc,0xe6,0xce,0x3e,0xbc,0x66,0xca,0x2e,0x9c,0xbf,0xbf, ++ 0xfd,0xfb,0x3f,0xbb,0xed,0xdb,0xaf,0x9f,0xbd,0xbb,0x2f,0x9b,0xad,0x9b,0xb7,0xaf, ++ 0xfc,0xfa,0x37,0xab,0xec,0xda,0xa7,0x8f,0xbc,0xba,0x27,0x8b,0xac,0x9a,0xbe,0xbe, ++ 0x7d,0xf9,0x3e,0xba,0x6d,0xd9,0xae,0x9e,0x3d,0xb9,0x2e,0x9a,0x2d,0x99,0xb6,0xae, ++ 0x7c,0xf8,0x36,0xaa,0x6c,0xd8,0xa6,0x8e,0x3c,0xb8,0x26,0x8a,0x2c,0x98,0xfd,0xf7, ++ 0xf7,0xf7,0x7d,0xf3,0xe7,0xd7,0xed,0xd7,0xb7,0xb7,0x6d,0xd3,0xa7,0x97,0xf5,0xe7, ++ 0xf6,0xf6,0x75,0xe3,0xe6,0xd6,0xe5,0xc7,0xb6,0xb6,0x65,0xc3,0xa6,0x96,0xfc,0xf6, ++ 0x77,0xf5,0x7c,0xf2,0x67,0xd5,0xec,0xd6,0x37,0xb5,0x6c,0xd2,0x27,0x95,0xf4,0xe6, ++ 0x76,0xf4,0x74,0xe2,0x66,0xd4,0xe4,0xc6,0x36,0xb4,0x64,0xc2,0x26,0x94,0xbd,0xb7, ++ 0xf5,0xf3,0x3d,0xb3,0xe5,0xd3,0xad,0x97,0xb5,0xb3,0x2d,0x93,0xa5,0x93,0xb5,0xa7, ++ 0xf4,0xf2,0x35,0xa3,0xe4,0xd2,0xa5,0x87,0xb4,0xb2,0x25,0x83,0xa4,0x92,0xbc,0xb6, ++ 0x75,0xf1,0x3c,0xb2,0x65,0xd1,0xac,0x96,0x35,0xb1,0x2c,0x92,0x25,0x91,0xb4,0xa6, ++ 0x74,0xf0,0x34,0xa2,0x64,0xd0,0xa4,0x86,0x34,0xb0,0x24,0x82,0x24,0x90,0xfb,0x7f, ++ 0xdf,0xef,0x7b,0x7b,0xcf,0xcf,0xeb,0x5f,0x9f,0xaf,0x6b,0x5b,0x8f,0x8f,0xf3,0x6f, ++ 0xde,0xee,0x73,0x6b,0xce,0xce,0xe3,0x4f,0x9e,0xae,0x63,0x4b,0x8e,0x8e,0xfa,0x7e, ++ 0x5f,0xed,0x7a,0x7a,0x4f,0xcd,0xea,0x5e,0x1f,0xad,0x6a,0x5a,0x0f,0x8d,0xf2,0x6e, ++ 0x5e,0xec,0x72,0x6a,0x4e,0xcc,0xe2,0x4e,0x1e,0xac,0x62,0x4a,0x0e,0x8c,0xbb,0x3f, ++ 0xdd,0xeb,0x3b,0x3b,0xcd,0xcb,0xab,0x1f,0x9d,0xab,0x2b,0x1b,0x8d,0x8b,0xb3,0x2f, ++ 0xdc,0xea,0x33,0x2b,0xcc,0xca,0xa3,0x0f,0x9c,0xaa,0x23,0x0b,0x8c,0x8a,0xba,0x3e, ++ 0x5d,0xe9,0x3a,0x3a,0x4d,0xc9,0xaa,0x1e,0x1d,0xa9,0x2a,0x1a,0x0d,0x89,0xb2,0x2e, ++ 0x5c,0xe8,0x32,0x2a,0x4c,0xc8,0xa2,0x0e,0x1c,0xa8,0x22,0x0a,0x0c,0x88,0xf9,0x77, ++ 0xd7,0xe7,0x79,0x73,0xc7,0xc7,0xe9,0x57,0x97,0xa7,0x69,0x53,0x87,0x87,0xf1,0x67, ++ 0xd6,0xe6,0x71,0x63,0xc6,0xc6,0xe1,0x47,0x96,0xa6,0x61,0x43,0x86,0x86,0xf8,0x76, ++ 0x57,0xe5,0x78,0x72,0x47,0xc5,0xe8,0x56,0x17,0xa5,0x68,0x52,0x07,0x85,0xf0,0x66, ++ 0x56,0xe4,0x70,0x62,0x46,0xc4,0xe0,0x46,0x16,0xa4,0x60,0x42,0x06,0x84,0xb9,0x37, ++ 0xd5,0xe3,0x39,0x33,0xc5,0xc3,0xa9,0x17,0x95,0xa3,0x29,0x13,0x85,0x83,0xb1,0x27, ++ 0xd4,0xe2,0x31,0x23,0xc4,0xc2,0xa1,0x07,0x94,0xa2,0x21,0x03,0x84,0x82,0xb8,0x36, ++ 0x55,0xe1,0x38,0x32,0x45,0xc1,0xa8,0x16,0x15,0xa1,0x28,0x12,0x05,0x81,0xb0,0x26, ++ 0x54,0xe0,0x30,0x22,0x44,0xc0,0xa0,0x06,0x14,0xa0,0x20,0x02,0x04,0x80,0xdf,0xfd, ++ 0xfb,0x7f,0x5f,0xf9,0xeb,0x5f,0xcf,0xdd,0xbb,0x3f,0x4f,0xd9,0xab,0x1f,0xd7,0xed, ++ 0xfa,0x7e,0x57,0xe9,0xea,0x5e,0xc7,0xcd,0xba,0x3e,0x47,0xc9,0xaa,0x1e,0xde,0xfc, ++ 0x7b,0x7d,0x5e,0xf8,0x6b,0x5d,0xce,0xdc,0x3b,0x3d,0x4e,0xd8,0x2b,0x1d,0xd6,0xec, ++ 0x7a,0x7c,0x56,0xe8,0x6a,0x5c,0xc6,0xcc,0x3a,0x3c,0x46,0xc8,0x2a,0x1c,0x9f,0xbd, ++ 0xf9,0x7b,0x1f,0xb9,0xe9,0x5b,0x8f,0x9d,0xb9,0x3b,0x0f,0x99,0xa9,0x1b,0x97,0xad, ++ 0xf8,0x7a,0x17,0xa9,0xe8,0x5a,0x87,0x8d,0xb8,0x3a,0x07,0x89,0xa8,0x1a,0x9e,0xbc, ++ 0x79,0x79,0x1e,0xb8,0x69,0x59,0x8e,0x9c,0x39,0x39,0x0e,0x98,0x29,0x19,0x96,0xac, ++ 0x78,0x78,0x16,0xa8,0x68,0x58,0x86,0x8c,0x38,0x38,0x06,0x88,0x28,0x18,0xdd,0xf5, ++ 0xf3,0x77,0x5d,0xf1,0xe3,0x57,0xcd,0xd5,0xb3,0x37,0x4d,0xd1,0xa3,0x17,0xd5,0xe5, ++ 0xf2,0x76,0x55,0xe1,0xe2,0x56,0xc5,0xc5,0xb2,0x36,0x45,0xc1,0xa2,0x16,0xdc,0xf4, ++ 0x73,0x75,0x5c,0xf0,0x63,0x55,0xcc,0xd4,0x33,0x35,0x4c,0xd0,0x23,0x15,0xd4,0xe4, ++ 0x72,0x74,0x54,0xe0,0x62,0x54,0xc4,0xc4,0x32,0x34,0x44,0xc0,0x22,0x14,0x9d,0xb5, ++ 0xf1,0x73,0x1d,0xb1,0xe1,0x53,0x8d,0x95,0xb1,0x33,0x0d,0x91,0xa1,0x13,0x95,0xa5, ++ 0xf0,0x72,0x15,0xa1,0xe0,0x52,0x85,0x85,0xb0,0x32,0x05,0x81,0xa0,0x12,0x9c,0xb4, ++ 0x71,0x71,0x1c,0xb0,0x61,0x51,0x8c,0x94,0x31,0x31,0x0c,0x90,0x21,0x11,0x94,0xa4, ++ 0x70,0x70,0x14,0xa0,0x60,0x50,0x84,0x84,0x30,0x30,0x04,0x80,0x20,0x10,0xdb,0x7d, ++ 0xdb,0x6f,0x5b,0x79,0xcb,0x4f,0xcb,0x5d,0x9b,0x2f,0x4b,0x59,0x8b,0x0f,0xd3,0x6d, ++ 0xda,0x6e,0x53,0x69,0xca,0x4e,0xc3,0x4d,0x9a,0x2e,0x43,0x49,0x8a,0x0e,0xda,0x7c, ++ 0x5b,0x6d,0x5a,0x78,0x4b,0x4d,0xca,0x5c,0x1b,0x2d,0x4a,0x58,0x0b,0x0d,0xd2,0x6c, ++ 0x5a,0x6c,0x52,0x68,0x4a,0x4c,0xc2,0x4c,0x1a,0x2c,0x42,0x48,0x0a,0x0c,0x9b,0x3d, ++ 0xd9,0x6b,0x1b,0x39,0xc9,0x4b,0x8b,0x1d,0x99,0x2b,0x0b,0x19,0x89,0x0b,0x93,0x2d, ++ 0xd8,0x6a,0x13,0x29,0xc8,0x4a,0x83,0x0d,0x98,0x2a,0x03,0x09,0x88,0x0a,0x9a,0x3c, ++ 0x59,0x69,0x1a,0x38,0x49,0x49,0x8a,0x1c,0x19,0x29,0x0a,0x18,0x09,0x09,0x92,0x2c, ++ 0x58,0x68,0x12,0x28,0x48,0x48,0x82,0x0c,0x18,0x28,0x02,0x08,0x08,0x08,0xd9,0x75, ++ 0xd3,0x67,0x59,0x71,0xc3,0x47,0xc9,0x55,0x93,0x27,0x49,0x51,0x83,0x07,0xd1,0x65, ++ 0xd2,0x66,0x51,0x61,0xc2,0x46,0xc1,0x45,0x92,0x26,0x41,0x41,0x82,0x06,0xd8,0x74, ++ 0x53,0x65,0x58,0x70,0x43,0x45,0xc8,0x54,0x13,0x25,0x48,0x50,0x03,0x05,0xd0,0x64, ++ 0x52,0x64,0x50,0x60,0x42,0x44,0xc0,0x44,0x12,0x24,0x40,0x40,0x02,0x04,0x99,0x35, ++ 0xd1,0x63,0x19,0x31,0xc1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03,0x91,0x25, ++ 0xd0,0x62,0x11,0x21,0xc0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02,0x98,0x34, ++ 0x51,0x61,0x18,0x30,0x41,0x41,0x88,0x14,0x11,0x21,0x08,0x10,0x01,0x01,0x90,0x24, ++ 0x50,0x60,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00,0x00,0x00,0xff,0xff, ++ 0xff,0xff,0x7f,0xfb,0xef,0xdf,0xef,0xdf,0xbf,0xbf,0x6f,0xdb,0xaf,0x9f,0xf7,0xef, ++ 0xfe,0xfe,0x77,0xeb,0xee,0xde,0xe7,0xcf,0xbe,0xbe,0x67,0xcb,0xae,0x9e,0xfe,0xfe, ++ 0x7f,0xfd,0x7e,0xfa,0x6f,0xdd,0xee,0xde,0x3f,0xbd,0x6e,0xda,0x2f,0x9d,0xf6,0xee, ++ 0x7e,0xfc,0x76,0xea,0x6e,0xdc,0xe6,0xce,0x3e,0xbc,0x66,0xca,0x2e,0x9c,0xbf,0xbf, ++ 0xfd,0xfb,0x3f,0xbb,0xed,0xdb,0xaf,0x9f,0xbd,0xbb,0x2f,0x9b,0xad,0x9b,0xb7,0xaf, ++ 0xfc,0xfa,0x37,0xab,0xec,0xda,0xa7,0x8f,0xbc,0xba,0x27,0x8b,0xac,0x9a,0xbe,0xbe, ++ 0x7d,0xf9,0x3e,0xba,0x6d,0xd9,0xae,0x9e,0x3d,0xb9,0x2e,0x9a,0x2d,0x99,0xb6,0xae, ++ 0x7c,0xf8,0x36,0xaa,0x6c,0xd8,0xa6,0x8e,0x3c,0xb8,0x26,0x8a,0x2c,0x98,0xfd,0xf7, ++ 0xf7,0xf7,0x7d,0xf3,0xe7,0xd7,0xed,0xd7,0xb7,0xb7,0x6d,0xd3,0xa7,0x97,0xf5,0xe7, ++ 0xf6,0xf6,0x75,0xe3,0xe6,0xd6,0xe5,0xc7,0xb6,0xb6,0x65,0xc3,0xa6,0x96,0xfc,0xf6, ++ 0x77,0xf5,0x7c,0xf2,0x67,0xd5,0xec,0xd6,0x37,0xb5,0x6c,0xd2,0x27,0x95,0xf4,0xe6, ++ 0x76,0xf4,0x74,0xe2,0x66,0xd4,0xe4,0xc6,0x36,0xb4,0x64,0xc2,0x26,0x94,0xbd,0xb7, ++ 0xf5,0xf3,0x3d,0xb3,0xe5,0xd3,0xad,0x97,0xb5,0xb3,0x2d,0x93,0xa5,0x93,0xb5,0xa7, ++ 0xf4,0xf2,0x35,0xa3,0xe4,0xd2,0xa5,0x87,0xb4,0xb2,0x25,0x83,0xa4,0x92,0xbc,0xb6, ++ 0x75,0xf1,0x3c,0xb2,0x65,0xd1,0xac,0x96,0x35,0xb1,0x2c,0x92,0x25,0x91,0xb4,0xa6, ++ 0x74,0xf0,0x34,0xa2,0x64,0xd0,0xa4,0x86,0x34,0xb0,0x24,0x82,0x24,0x90,0xfb,0x7f, ++ 0xdf,0xef,0x7b,0x7b,0xcf,0xcf,0xeb,0x5f,0x9f,0xaf,0x6b,0x5b,0x8f,0x8f,0xf3,0x6f, ++ 0xde,0xee,0x73,0x6b,0xce,0xce,0xe3,0x4f,0x9e,0xae,0x63,0x4b,0x8e,0x8e,0xfa,0x7e, ++ 0x5f,0xed,0x7a,0x7a,0x4f,0xcd,0xea,0x5e,0x1f,0xad,0x6a,0x5a,0x0f,0x8d,0xf2,0x6e, ++ 0x5e,0xec,0x72,0x6a,0x4e,0xcc,0xe2,0x4e,0x1e,0xac,0x62,0x4a,0x0e,0x8c,0xbb,0x3f, ++ 0xdd,0xeb,0x3b,0x3b,0xcd,0xcb,0xab,0x1f,0x9d,0xab,0x2b,0x1b,0x8d,0x8b,0xb3,0x2f, ++ 0xdc,0xea,0x33,0x2b,0xcc,0xca,0xa3,0x0f,0x9c,0xaa,0x23,0x0b,0x8c,0x8a,0xba,0x3e, ++ 0x5d,0xe9,0x3a,0x3a,0x4d,0xc9,0xaa,0x1e,0x1d,0xa9,0x2a,0x1a,0x0d,0x89,0xb2,0x2e, ++ 0x5c,0xe8,0x32,0x2a,0x4c,0xc8,0xa2,0x0e,0x1c,0xa8,0x22,0x0a,0x0c,0x88,0xf9,0x77, ++ 0xd7,0xe7,0x79,0x73,0xc7,0xc7,0xe9,0x57,0x97,0xa7,0x69,0x53,0x87,0x87,0xf1,0x67, ++ 0xd6,0xe6,0x71,0x63,0xc6,0xc6,0xe1,0x47,0x96,0xa6,0x61,0x43,0x86,0x86,0xf8,0x76, ++ 0x57,0xe5,0x78,0x72,0x47,0xc5,0xe8,0x56,0x17,0xa5,0x68,0x52,0x07,0x85,0xf0,0x66, ++ 0x56,0xe4,0x70,0x62,0x46,0xc4,0xe0,0x46,0x16,0xa4,0x60,0x42,0x06,0x84,0xb9,0x37, ++ 0xd5,0xe3,0x39,0x33,0xc5,0xc3,0xa9,0x17,0x95,0xa3,0x29,0x13,0x85,0x83,0xb1,0x27, ++ 0xd4,0xe2,0x31,0x23,0xc4,0xc2,0xa1,0x07,0x94,0xa2,0x21,0x03,0x84,0x82,0xb8,0x36, ++ 0x55,0xe1,0x38,0x32,0x45,0xc1,0xa8,0x16,0x15,0xa1,0x28,0x12,0x05,0x81,0xb0,0x26, ++ 0x54,0xe0,0x30,0x22,0x44,0xc0,0xa0,0x06,0x14,0xa0,0x20,0x02,0x04,0x80,0xdf,0xfd, ++ 0xfb,0x7f,0x5f,0xf9,0xeb,0x5f,0xcf,0xdd,0xbb,0x3f,0x4f,0xd9,0xab,0x1f,0xd7,0xed, ++ 0xfa,0x7e,0x57,0xe9,0xea,0x5e,0xc7,0xcd,0xba,0x3e,0x47,0xc9,0xaa,0x1e,0xde,0xfc, ++ 0x7b,0x7d,0x5e,0xf8,0x6b,0x5d,0xce,0xdc,0x3b,0x3d,0x4e,0xd8,0x2b,0x1d,0xd6,0xec, ++ 0x7a,0x7c,0x56,0xe8,0x6a,0x5c,0xc6,0xcc,0x3a,0x3c,0x46,0xc8,0x2a,0x1c,0x9f,0xbd, ++ 0xf9,0x7b,0x1f,0xb9,0xe9,0x5b,0x8f,0x9d,0xb9,0x3b,0x0f,0x99,0xa9,0x1b,0x97,0xad, ++ 0xf8,0x7a,0x17,0xa9,0xe8,0x5a,0x87,0x8d,0xb8,0x3a,0x07,0x89,0xa8,0x1a,0x9e,0xbc, ++ 0x79,0x79,0x1e,0xb8,0x69,0x59,0x8e,0x9c,0x39,0x39,0x0e,0x98,0x29,0x19,0x96,0xac, ++ 0x78,0x78,0x16,0xa8,0x68,0x58,0x86,0x8c,0x38,0x38,0x06,0x88,0x28,0x18,0xdd,0xf5, ++ 0xf3,0x77,0x5d,0xf1,0xe3,0x57,0xcd,0xd5,0xb3,0x37,0x4d,0xd1,0xa3,0x17,0xd5,0xe5, ++ 0xf2,0x76,0x55,0xe1,0xe2,0x56,0xc5,0xc5,0xb2,0x36,0x45,0xc1,0xa2,0x16,0xdc,0xf4, ++ 0x73,0x75,0x5c,0xf0,0x63,0x55,0xcc,0xd4,0x33,0x35,0x4c,0xd0,0x23,0x15,0xd4,0xe4, ++ 0x72,0x74,0x54,0xe0,0x62,0x54,0xc4,0xc4,0x32,0x34,0x44,0xc0,0x22,0x14,0x9d,0xb5, ++ 0xf1,0x73,0x1d,0xb1,0xe1,0x53,0x8d,0x95,0xb1,0x33,0x0d,0x91,0xa1,0x13,0x95,0xa5, ++ 0xf0,0x72,0x15,0xa1,0xe0,0x52,0x85,0x85,0xb0,0x32,0x05,0x81,0xa0,0x12,0x9c,0xb4, ++ 0x71,0x71,0x1c,0xb0,0x61,0x51,0x8c,0x94,0x31,0x31,0x0c,0x90,0x21,0x11,0x94,0xa4, ++ 0x70,0x70,0x14,0xa0,0x60,0x50,0x84,0x84,0x30,0x30,0x04,0x80,0x20,0x10,0xdb,0x7d, ++ 0xdb,0x6f,0x5b,0x79,0xcb,0x4f,0xcb,0x5d,0x9b,0x2f,0x4b,0x59,0x8b,0x0f,0xd3,0x6d, ++ 0xda,0x6e,0x53,0x69,0xca,0x4e,0xc3,0x4d,0x9a,0x2e,0x43,0x49,0x8a,0x0e,0xda,0x7c, ++ 0x5b,0x6d,0x5a,0x78,0x4b,0x4d,0xca,0x5c,0x1b,0x2d,0x4a,0x58,0x0b,0x0d,0xd2,0x6c, ++ 0x5a,0x6c,0x52,0x68,0x4a,0x4c,0xc2,0x4c,0x1a,0x2c,0x42,0x48,0x0a,0x0c,0x9b,0x3d, ++ 0xd9,0x6b,0x1b,0x39,0xc9,0x4b,0x8b,0x1d,0x99,0x2b,0x0b,0x19,0x89,0x0b,0x93,0x2d, ++ 0xd8,0x6a,0x13,0x29,0xc8,0x4a,0x83,0x0d,0x98,0x2a,0x03,0x09,0x88,0x0a,0x9a,0x3c, ++ 0x59,0x69,0x1a,0x38,0x49,0x49,0x8a,0x1c,0x19,0x29,0x0a,0x18,0x09,0x09,0x92,0x2c, ++ 0x58,0x68,0x12,0x28,0x48,0x48,0x82,0x0c,0x18,0x28,0x02,0x08,0x08,0x08,0xd9,0x75, ++ 0xd3,0x67,0x59,0x71,0xc3,0x47,0xc9,0x55,0x93,0x27,0x49,0x51,0x83,0x07,0xd1,0x65, ++ 0xd2,0x66,0x51,0x61,0xc2,0x46,0xc1,0x45,0x92,0x26,0x41,0x41,0x82,0x06,0xd8,0x74, ++ 0x53,0x65,0x58,0x70,0x43,0x45,0xc8,0x54,0x13,0x25,0x48,0x50,0x03,0x05,0xd0,0x64, ++ 0x52,0x64,0x50,0x60,0x42,0x44,0xc0,0x44,0x12,0x24,0x40,0x40,0x02,0x04,0x99,0x35, ++ 0xd1,0x63,0x19,0x31,0xc1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03,0x91,0x25, ++ 0xd0,0x62,0x11,0x21,0xc0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02,0x98,0x34, ++ 0x51,0x61,0x18,0x30,0x41,0x41,0x88,0x14,0x11,0x21,0x08,0x10,0x01,0x01,0x90,0x24, ++ 0x50,0x60,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00,0x68,0xf7,0x80,0x0c, ++ 0xcc,0x40,0x3b,0xa1,0xe7,0xdd,0x4e,0xb6,0x98,0xeb,0xa8,0xdb,0xa5,0x03,0xbf,0x11, ++ 0x8c,0x0d,0x33,0xa5,0x1f,0x8e,0x7e,0xc1,0x83,0xc1,0xe6,0xa4,0xa4,0xc2,0x04,0x19, ++ 0x0f,0x00,0x97,0x95,0x7b,0xa0,0xf7,0x67,0x21,0xed,0x6a,0x5a,0xb8,0xe0,0x61,0x6e, ++ 0xc2,0x63,0x4d,0x17,0x9f,0x8e,0x67,0xaf,0x2a,0xb5,0x5d,0xc6,0xdf,0x67,0x1e,0x4f, ++ 0x46,0x4a,0x6c,0x06,0x91,0xd0,0x76,0x4c,0x0c,0xe9,0xe8,0x9b,0xa7,0x07,0x6e,0xef, ++ 0xfc,0xa1,0x17,0x54,0x93,0x65,0x6a,0x4e,0xe0,0xe4,0xa6,0xf9,0xa6,0xe6,0x20,0xe1, ++ 0x54,0xb9,0x81,0xe5,0x82,0xa6,0x43,0x90,0x61,0x06,0x2a,0x1a,0xb2,0x6a,0xba,0xaf, ++ 0x4b,0xb0,0x16,0x54,0x4f,0x45,0x1b,0x82,0x81,0x9a,0x7f,0x86,0xc5,0x63,0x1a,0x05, ++ 0x6b,0x68,0xd4,0x3d,0xb9,0xd7,0x4c,0xb3,0x58,0xe7,0x56,0x5f,0x32,0xc9,0xf1,0x47, ++ 0x4a,0x96,0x35,0x2d,0x5b,0x86,0x44,0x0f,0xc8,0xe6,0x4e,0xc2,0xa4,0xc8,0x94,0xf6, ++ 0x69,0xd9,0xbd,0xbd,0xb6,0xf5,0x70,0xd8,0x2c,0xfe,0xab,0xd2,0x31,0xe9,0xa4,0xdb, ++ 0x0a,0x4d,0xc9,0x63,0xf3,0x49,0x2d,0xc8,0x29,0x0b,0xd9,0xce,0x9b,0xb6,0x3d,0x5b, ++ 0xf8,0x93,0x92,0x40,0x5a,0xd7,0x04,0xed,0xa1,0x2e,0x91,0x53,0x58,0xb7,0x28,0x58, ++ 0x08,0x6d,0xce,0x43,0x59,0x86,0x3c,0x1a,0xbc,0xb0,0xda,0xf8,0x47,0xee,0x76,0xc1, ++ 0x33,0x60,0x43,0x4f,0x9e,0xd5,0xe4,0xe5,0x37,0x2d,0xd3,0x56,0xba,0xf5,0xcb,0x5d, ++ 0x16,0x5a,0x0b,0x59,0x72,0x6d,0x4d,0x1b,0x34,0x92,0x64,0x4c,0x7a,0x90,0x12,0x78, ++ 0x20,0x52,0x84,0xbf,0x58,0xab,0xcb,0xa1,0xbc,0x52,0x2b,0x01,0xba,0x7d,0x34,0x6f, ++ 0xd4,0x72,0x33,0x7c,0x35,0x5d,0x7a,0x39,0x62,0x31,0x63,0xca,0x5f,0xae,0x80,0x31, ++ 0x5d,0xb3,0x85,0x01,0xac,0xb1,0xc8,0xa5,0x5d,0x3c,0x6e,0xda,0x98,0x7f,0x22,0xee, ++ 0x78,0x8c,0x59,0xcb,0x9f,0xef,0x9d,0xb5,0x0e,0xfe,0x22,0x84,0xf7,0xdc,0x7a,0x55, ++ 0xad,0x92,0xa2,0xf9,0x33,0x54,0x0a,0x0f,0x70,0x06,0x6f,0x55,0x64,0xdb,0xdc,0xb0, ++ 0x21,0xb1,0x98,0x74,0x92,0x17,0xdc,0xf4,0x25,0xf8,0xe2,0x74,0xfe,0xd3,0x45,0x81, ++ 0xc0,0xbb,0x45,0xd4,0xd8,0x9b,0xd5,0xe5,0xca,0x64,0x14,0xe1,0xb2,0x7c,0x8d,0xd7, ++ 0x6b,0x35,0x93,0x44,0x21,0x9c,0x9b,0x36,0x21,0x57,0x8d,0xb5,0xff,0x37,0x56,0x80, ++ 0x64,0xa5,0xef,0x67,0x50,0xfa,0xc6,0x08,0xc9,0xf8,0x56,0xd2,0x12,0x5a,0xda,0x62, ++ 0xc0,0xa8,0xc8,0x6f,0x73,0x9d,0x9a,0xca,0x82,0x0b,0x58,0x82,0x33,0x8c,0x11,0xeb, ++ 0x53,0x87,0xf9,0x19,0x4d,0x99,0x49,0x25,0xe0,0x5e,0xe9,0x2c,0x30,0x2b,0x25,0x49, ++ 0x0a,0x93,0xdf,0x15,0x9b,0x4b,0xa2,0xc9,0xed,0x50,0x5d,0xa3,0x3f,0x8f,0xe2,0xbb, ++ 0xdf,0xb8,0x04,0x4e,0x51,0xde,0x5e,0xc9,0x83,0x1d,0xd0,0x40,0x93,0x5f,0xc4,0xda, ++ 0x73,0xb9,0x90,0x55,0x99,0x39,0xfe,0xeb,0x61,0x39,0x98,0x76,0x10,0xbf,0xf8,0x2b, ++ 0xac,0x6e,0xc3,0x3c,0xa8,0x28,0x4f,0x69,0x22,0x1c,0x87,0x8f,0xf0,0xd5,0x8f,0xdf, ++ 0x63,0x3d,0x48,0x2c,0xf1,0x29,0x61,0x87,0x23,0xa2,0xb7,0x0c,0xb5,0x5f,0x97,0x26, ++ 0x22,0xc0,0xde,0x83,0xfd,0x43,0x98,0xa8,0x94,0x54,0xe6,0xa3,0xbf,0x82,0x9f,0x13, ++ 0x88,0x8d,0x7a,0xb3,0xe2,0x5c,0xb8,0xf4,0xd7,0xc2,0x47,0x45,0x33,0x82,0x21,0x27, ++ 0x0b,0x80,0xb7,0x65,0x6b,0x0f,0x16,0x38,0xaf,0xb6,0x8f,0x92,0xbc,0xef,0x41,0xe2, ++ 0x8f,0x67,0xbf,0x87,0x7e,0x21,0xda,0xc8,0xe7,0xd3,0x42,0x48,0xbd,0x61,0x76,0x2c, ++ 0x89,0x02,0x0c,0xd5,0x18,0xae,0xa4,0x9c,0xbb,0x65,0x4b,0xc3,0xa1,0x19,0xe8,0x05, ++ 0x6c,0xfa,0xd6,0xf2,0x36,0x05,0x2e,0xf7,0xac,0xe7,0x43,0xc6,0x9b,0x4a,0x61,0x83, ++ 0x8a,0xc6,0x65,0x43,0xde,0xf5,0x33,0x90,0xc0,0x1b,0xe3,0x25,0x3d,0x94,0xed,0xa2, ++ 0x38,0x84,0xb7,0xcf,0x9f,0xa3,0x91,0x6e,0xe5,0x11,0x38,0x48,0x85,0x1a,0x7c,0x8e, ++ 0x8d,0x23,0x19,0xbf,0x12,0x07,0x30,0xd7,0x4c,0xcc,0xcc,0xbe,0xa9,0x4b,0x02,0x5c, ++ 0x51,0x7c,0xe8,0x9a,0x19,0x89,0x7f,0x9a,0x59,0x49,0xfe,0x2d,0x1f,0xab,0xe7,0x1c, ++ 0xe7,0x08,0x67,0xfc,0x96,0x0e,0xb3,0xd6,0xc4,0x3e,0x77,0xdc,0xd2,0x45,0xbd,0xe7, ++ 0x8d,0x3e,0x58,0x20,0xf1,0x70,0xe4,0x3f,0x4d,0x8b,0x13,0x22,0x21,0xb9,0xca,0xc0, ++ 0x65,0x18,0x66,0x3c,0xf5,0x3e,0x0d,0xca,0xfd,0x73,0x26,0xfd,0xff,0x33,0x34,0x55, ++ 0x4b,0xc3,0xf2,0x5b,0x1b,0xcd,0x89,0x04,0x87,0x7a,0x41,0xdb,0xa8,0x10,0x63,0xba, ++ 0x56,0xce,0xdd,0xcb,0xff,0xee,0x55,0xd4,0x33,0x6a,0x4c,0x5e,0x7f,0x11,0x0a,0xfb, ++ 0xd3,0x16,0xc2,0x2c,0x9d,0xc3,0x44,0x68,0x3d,0x52,0xed,0xf2,0x34,0x9d,0x25,0x71, ++ 0xee,0x3b,0xa5,0x77,0x3a,0x54,0x7f,0x53,0x2e,0x64,0x52,0xd4,0x9f,0x56,0x0b,0x63, ++ 0xc9,0x9d,0x79,0x67,0x3b,0x55,0xab,0x3a,0x47,0xa1,0x5f,0xa9,0xab,0x5e,0x42,0x8b, ++ 0xcf,0x57,0xfb,0x17,0x35,0xb6,0x6b,0x37,0x65,0x76,0xeb,0x35,0xf0,0x26,0x73,0xa0, ++ 0x25,0x38,0xf3,0x07,0x34,0x1e,0x6b,0xc0,0x8f,0x7b,0xda,0x46,0x27,0xb3,0xc0,0xb1, ++ 0xd3,0x9b,0xba,0x52,0x34,0x1f,0x0c,0x66,0x7a,0x1c,0xaa,0x6e,0xe4,0x5f,0x2a,0x47, ++ 0xce,0x97,0x8d,0x27,0x2d,0xb6,0xdc,0xe1,0x6d,0xb1,0xa2,0x67,0xe5,0x5e,0xd1,0xb0, ++ 0x5b,0x99,0x23,0xc6,0xdd,0xa4,0x55,0xfa,0x2e,0x94,0xb0,0x05,0x76,0x06,0x33,0x31, ++ 0xa3,0x12,0xbd,0xda,0x93,0x1a,0x43,0x8d,0x44,0xb2,0x3f,0x37,0x9c,0x15,0x14,0x9a, ++ 0xa9,0x8e,0xf0,0xdf,0x5e,0xb3,0x64,0x4a,0x3e,0x2d,0xc8,0x98,0x97,0x1d,0x70,0x95, ++ 0x7f,0xd7,0x99,0xa3,0xce,0xfb,0x45,0x3e,0x71,0x5a,0x8c,0xf8,0xef,0x56,0x04,0x91, ++ 0x74,0x2e,0xe4,0xb0,0xdc,0x65,0x25,0x55,0x14,0xd9,0xe9,0x9c,0xec,0x55,0x4e,0x3b, ++ 0x7b,0x24,0x2a,0x2f,0x40,0x1a,0x80,0x8a,0x4c,0x24,0x9c,0x4e,0x25,0xbb,0xd5,0x28, ++ 0x46,0xde,0xa6,0xff,0x1c,0x43,0x48,0x95,0xcd,0xae,0xf2,0x1f,0x6c,0xea,0x2a,0x29, ++ 0x25,0xc0,0xfc,0x26,0x3f,0xff,0x16,0x7c,0x93,0x9c,0x7b,0x62,0x83,0xff,0x19,0x4f, ++ 0x5b,0x3d,0xdd,0x6a,0x49,0x0b,0xf7,0xeb,0x2b,0xd0,0xa9,0x66,0xdd,0xfd,0x71,0xea, ++ 0x8c,0x0e,0x6a,0x6f,0x42,0x1e,0x93,0x7b,0x13,0xff,0x24,0xff,0x07,0x7e,0x5b,0x00, ++ 0x06,0x70,0x7f,0xa1,0xda,0x2d,0x75,0xce,0xd9,0xbd,0x55,0x57,0x7a,0x63,0xf7,0x6e, ++ 0x2f,0xde,0x77,0x6a,0x3f,0xfe,0x9a,0xdd,0x49,0x1a,0x47,0xb6,0xd1,0xe1,0x53,0x7e, ++ 0xe8,0x0f,0x7a,0x7a,0xf8,0x2f,0x3c,0xcc,0xc8,0x46,0xa9,0x31,0xa7,0x74,0xb6,0x21, ++ 0x00,0xac,0x36,0x24,0xd7,0x8c,0x7c,0xd8,0xc2,0x37,0x42,0xbf,0xae,0x61,0xc0,0x07, ++ 0x2c,0xd8,0x82,0xb7,0x50,0xaf,0x94,0x5a,0x2a,0xd9,0x11,0x7e,0x39,0x06,0x5a,0x02, ++ 0xe8,0xe7,0x0e,0x26,0x79,0xe7,0xdc,0x74,0x0f,0x04,0x18,0x68,0x38,0x57,0x95,0x1f, ++ 0x11,0x39,0xc0,0x74,0xdc,0x89,0xbd,0xf3,0xc2,0x4c,0xd5,0x67,0xe2,0xcd,0xf2,0xe1, ++ 0x5b,0xa8,0xb7,0xc1,0x5b,0x85,0x7f,0xf9,0x05,0xe3,0xea,0x84,0xc5,0x32,0xc7,0x76, ++ 0x6a,0xec,0x40,0x72,0x72,0x8a,0x55,0x26,0x1e,0x7c,0x31,0xbc,0x84,0xca,0x34,0x98, ++ 0x61,0xf8,0xcf,0xef,0x03,0xf4,0xd9,0x13,0x17,0x0b,0x5c,0x7e,0xd9,0xc2,0x7d,0x85, ++ 0x08,0x0b,0xfd,0x9c,0x65,0x8b,0xd4,0x06,0x92,0x1f,0xcd,0xb9,0x00,0xc1,0xf4,0x6b, ++ 0xa7,0xd4,0xdd,0x95,0x72,0x39,0x9e,0xb4,0x36,0x28,0xec,0x38,0xc7,0xc6,0x80,0x3b, ++ 0x2c,0x0f,0x62,0x5f,0x58,0x48,0x17,0xff,0x21,0xea,0x8c,0xe9,0x52,0x68,0x4b,0xb5, ++ 0x03,0x56,0xf2,0xaf,0x15,0x2e,0x7c,0xfc,0x9d,0xe9,0x84,0xf5,0xab,0xc6,0x7b,0x68, ++ 0xa8,0x9e,0xfb,0xbe,0x9c,0x4b,0x57,0x98,0x08,0x6e,0x12,0x9c,0xdc,0x9e,0x2e,0xb0, ++ 0x88,0x0b,0x28,0xa6,0xc9,0x6f,0x9f,0xe6,0xa0,0xf9,0x1a,0x2b,0xb0,0x0d,0x12,0xe2, ++ 0xdf,0xcd,0xc4,0xbb,0x38,0x5c,0x50,0xd3,0x6a,0x3e,0xac,0xb0,0x07,0x66,0xc9,0x63, ++ 0x3f,0xcc,0xab,0x15,0xcc,0xb0,0x3a,0x24,0xe5,0xf5,0x47,0x3e,0x0e,0x7b,0xd1,0x7f, ++ 0x5d,0xb3,0xad,0x47,0x6c,0x30,0x77,0xa1,0xe1,0xeb,0x4a,0x67,0x70,0xf2,0x5b,0x1d, ++ 0x4a,0x41,0xcd,0x66,0xab,0xbe,0x5b,0xb6,0x40,0x8c,0x3e,0x25,0x2d,0xd1,0x16,0x4b, ++ 0x95,0x28,0x06,0xc5,0x59,0xd6,0x0a,0xfa,0x62,0xf0,0x2f,0xc3,0xd3,0x8b,0x6c,0xc4, ++ 0x1c,0x35,0xec,0xc9,0x58,0xb7,0xde,0x36,0xf1,0x51,0xe9,0x7c,0x75,0x05,0xfa,0x8a, ++ 0x9d,0x36,0xa4,0x34,0xa0,0x31,0xc3,0xfa,0x89,0x22,0x60,0x71,0x46,0x94,0x94,0x5a, ++ 0x98,0x1d,0xac,0x24,0xf9,0x35,0x5a,0xb7,0x71,0xfc,0x96,0x0e,0x03,0x78,0x38,0x2c, ++ 0x0a,0x15,0xd4,0x07,0xd3,0x2a,0xa2,0xca,0x97,0x2d,0xa8,0x34,0x8c,0x0a,0xd3,0x99, ++ 0x1e,0x2f,0x8e,0x9e,0x3d,0xc2,0x5b,0x3c,0x75,0xc3,0x35,0x19,0xac,0x67,0x13,0x29, ++ 0xf8,0x0a,0xd7,0x85,0xf8,0xc1,0xd1,0x87,0xfa,0x6f,0xce,0xa9,0x75,0x19,0x52,0x59, ++ 0x29,0xcb,0x0f,0x82,0xaf,0xce,0x60,0x83,0x4a,0x19,0xe2,0x8d,0x78,0xd4,0xe3,0x51, ++ 0xbe,0xce,0x98,0x58,0x32,0x97,0x75,0xe8,0xa2,0xbd,0x16,0xf4,0x29,0xd8,0xff,0x44, ++ 0x93,0xef,0x9e,0xaf,0x39,0xbf,0xb6,0x72,0x08,0x7d,0x7a,0x82,0xd8,0x18,0x62,0x54, ++ 0x16,0xac,0x01,0x47,0xd1,0x2c,0x70,0x18,0x76,0xbe,0x16,0xeb,0x32,0x4c,0x8f,0xd4, ++ 0xb5,0xe0,0xd7,0x50,0xf9,0x36,0x49,0x64,0x00,0xad,0x60,0x1f,0x98,0x3f,0x17,0x32, ++ 0x77,0x80,0x9e,0x96,0x7f,0xaf,0x56,0x40,0xb3,0x3d,0xe4,0x86,0xf5,0x20,0x3e,0x70, ++ 0xfa,0x5c,0xbe,0x9b,0xfe,0xd3,0xec,0xcc,0xb8,0x60,0x98,0x26,0x22,0xf7,0xe1,0x0e, ++ 0xe6,0x7f,0x21,0x35,0x60,0xad,0x27,0x41,0x3b,0x1f,0x6a,0xad,0xab,0xe5,0xfd,0xed, ++ 0x78,0x02,0x12,0xa6,0x83,0x0c,0xfb,0xc0,0x83,0x1e,0x66,0x97,0x01,0x61,0xe3,0x31, ++ 0x3a,0x05,0x62,0x41,0x4c,0xe4,0x71,0x10,0xad,0x52,0x70,0x64,0x06,0x4f,0x0d,0xbc, ++ 0x9e,0x78,0x08,0x69,0x33,0xcb,0xbe,0x45,0x2c,0x60,0xcb,0x87,0x41,0xf9,0x29,0xbc, ++ 0x67,0x05,0xe7,0xb6,0x15,0xa8,0x57,0xf7,0x22,0x62,0x31,0x7a,0xbd,0xd4,0x44,0xbe, ++ 0x8f,0xf3,0xa9,0x68,0x9f,0xcb,0x59,0x00,0xaf,0x6c,0xa7,0xf2,0xd3,0x6a,0x0a,0xf9, ++ 0x12,0x55,0x63,0x9f,0x16,0xac,0x64,0xbb,0xa7,0x6a,0x15,0xbf,0x37,0x2a,0x9d,0x82, ++ 0xf0,0xea,0x2e,0x82,0x9e,0xa7,0x7f,0x44,0x27,0xdb,0x9a,0xeb,0xa7,0xa9,0x71,0x1c, ++ 0x67,0xd8,0x80,0x9e,0x9a,0xea,0x8c,0x1a,0xd6,0x65,0x94,0xde,0x92,0x66,0x4d,0x79, ++ 0x7a,0x76,0x4b,0x20,0xb9,0xc5,0x45,0xb3,0x05,0x9a,0x2e,0x4c,0xf7,0xe8,0x25,0x44, ++ 0x58,0xb8,0xca,0x8c,0xc2,0xae,0x0a,0x62,0xae,0x63,0x8c,0xef,0xb7,0xce,0x69,0xda, ++ 0xe6,0xfc,0xae,0xaf,0x5d,0xbb,0x38,0x09,0x45,0xcc,0xb2,0x6d,0x15,0xa9,0xa4,0x49, ++ 0xd0,0x8d,0xdd,0xee,0xbc,0xa3,0x41,0x18,0xcc,0xc5,0x5f,0xfc,0xd8,0xe4,0x79,0x9b, ++ 0x70,0x02,0xb5,0xce,0x1d,0x04,0x43,0x66,0x4a,0xd9,0xdd,0xef,0x53,0xe2,0x1a,0xaf, ++ 0x44,0x9a,0x32,0x7a,0x34,0x05,0x37,0x7a,0xac,0xa2,0x72,0xd8,0x16,0x44,0xd5,0xd9, ++ 0xd8,0xad,0x29,0x26,0xc8,0x10,0x87,0x50,0xc9,0x2c,0x82,0x17,0x57,0xfc,0xda,0xf1, ++ 0xc6,0xa4,0xb3,0x7f,0xb4,0xf0,0x95,0xb0,0xf2,0xb6,0xcb,0x33,0x74,0xc3,0xf0,0x92, ++ 0x39,0x21,0x95,0x64,0xe7,0x6e,0x45,0x43,0xed,0x72,0x3f,0x4b,0x67,0x08,0xb0,0x51, ++ 0x87,0x4b,0x76,0x56,0x17,0x97,0x4e,0x53,0x30,0x7b,0xe2,0x77,0x9d,0x56,0xd7,0x77, ++ 0xd0,0x68,0xee,0x36,0x76,0x1e,0x49,0x6f,0x61,0xa5,0xbe,0x06,0x73,0x54,0xda,0xf2, ++ 0x07,0x69,0xa7,0xa7,0xc4,0x37,0xb6,0xcc,0xbc,0x89,0xcf,0x56,0xb4,0x59,0x7b,0x42, ++ 0x4c,0x35,0x2d,0xcb,0xdc,0x85,0xb8,0x0c,0xc9,0x71,0xbc,0x04,0xe5,0x7a,0x87,0x16, ++ 0xb4,0x6a,0x72,0x7d,0x22,0x03,0xf1,0x59,0x32,0x55,0xce,0xac,0x3c,0x23,0x6e,0xe9, ++ 0x11,0x18,0x6f,0x5e,0x31,0xf9,0x8b,0x23,0xda,0xec,0xfc,0xa1,0x37,0x54,0x07,0x16, ++ 0x8e,0x0a,0xa5,0xf4,0x33,0x1c,0x61,0x37,0x07,0x08,0xd6,0x52,0xdf,0x2e,0x67,0x64, ++ 0x4c,0x18,0x29,0xab,0x47,0x3b,0xf8,0x3f,0xf1,0xa9,0xfc,0x81,0xe3,0xe0,0xdd,0x7b, ++ 0x6c,0x33,0xd5,0x3f,0x28,0xb7,0x4e,0x14,0x93,0x7d,0xa0,0x7b,0x95,0x1e,0x10,0xdd, ++ 0x8e,0x32,0x3c,0x2f,0x39,0x4d,0x85,0x85,0x07,0x7f,0x7e,0xcc,0x8b,0xf2,0x25,0xd8, ++ 0xe4,0xda,0xb9,0x4a,0xb6,0xba,0x4f,0x14,0x1b,0xbd,0xc9,0x6a,0x95,0xf1,0xaf,0xfc, ++ 0x0e,0x30,0xb1,0x56,0x4f,0x14,0x01,0x6a,0x1a,0x7c,0xe9,0x73,0x14,0xad,0xbb,0xb1, ++ 0x1a,0xaf,0x9a,0x00,0x31,0x40,0x06,0xb8,0xab,0xd2,0x38,0x3c,0xd2,0x56,0x3d,0x63, ++ 0x03,0x88,0xe0,0x92,0xed,0x60,0xdd,0x43,0x7d,0xe0,0x9a,0xf2,0x45,0x65,0x44,0x10, ++ 0x8a,0x06,0x01,0x0d,0x9e,0x2c,0xaa,0x90,0xde,0xed,0xd9,0x47,0xf2,0xaf,0x0b,0x71, ++ 0x8d,0x43,0xa1,0x77,0x10,0x2c,0x0a,0xc2,0xc7,0xce,0x19,0x73,0xc5,0x65,0x10,0x5f, ++ 0x6e,0x1f,0xfa,0xc3,0xbe,0x38,0x38,0x67,0xc1,0x4b,0x34,0x97,0xf1,0xef,0xd1,0xb8, ++ 0xbc,0x48,0xe6,0x53,0x86,0x2a,0xef,0x98,0xbc,0xc8,0x3f,0x87,0xf0,0x38,0x39,0x33, ++ 0x25,0x02,0xef,0x43,0x03,0x7a,0x39,0x03,0xe4,0x0a,0xd5,0xe2,0xf6,0x1b,0x37,0xf4, ++ 0x91,0x4a,0x7d,0x1f,0x5a,0x63,0xa3,0xbb,0x38,0xec,0x3a,0x31,0x70,0x5a,0x07,0x1d, ++ 0xf3,0xb5,0xaa,0x0b,0x99,0x6c,0x6c,0xa9,0xa1,0x6a,0xf7,0xec,0xf9,0xe2,0x39,0xe9, ++ 0x5f,0x18,0x8b,0x9e,0x18,0xd6,0x04,0x4b,0x6d,0x42,0x41,0x28,0x22,0x6f,0x5b,0x45, ++ 0xe3,0xb8,0xab,0xcf,0xf3,0x24,0xbf,0xba,0xce,0x40,0x44,0xcf,0xa7,0x6a,0x55,0x94, ++ 0x79,0xa0,0xb3,0x3d,0x38,0x4b,0xdd,0x2a,0x9b,0x0f,0xc0,0x3d,0x5b,0x23,0xbd,0xe8, ++ 0xe7,0x8c,0xeb,0x02,0xd3,0x48,0x62,0x37,0x21,0x78,0xb5,0x28,0xf9,0x71,0x91,0x58, ++ 0xdf,0x4c,0x74,0x5e,0xed,0x5a,0xda,0x74,0x8c,0x0d,0x36,0xfc,0xa7,0x4d,0x98,0x48, ++ 0x0a,0x4e,0x6a,0x92,0x23,0xf0,0x53,0x98,0x42,0xb1,0xb0,0x3c,0x79,0x2f,0xf4,0xf9, ++ 0x6e,0x8f,0xcf,0x49,0x03,0x6b,0x58,0x78,0x2a,0x29,0x77,0x3f,0x58,0xbb,0x41,0x1f, ++ 0x4b,0x42,0x3c,0x77,0x58,0x22,0xd5,0xa6,0xa8,0x62,0x84,0xc6,0xc3,0x15,0x34,0x6f, ++ 0xc8,0xd2,0x34,0x6b,0x3f,0x77,0xdc,0xbd,0x24,0xf1,0x65,0x93,0xd0,0x0e,0x6f,0xf2, ++ 0xce,0xb3,0x3d,0x76,0xc8,0x20,0xb1,0xdf,0x3c,0x5d,0xad,0x4e,0x5c,0x7f,0xd9,0x6f, ++ 0x5c,0xb2,0x8a,0xea,0x93,0xde,0xde,0xc2,0xb7,0x58,0x31,0x31,0xed,0x97,0x96,0x48, ++ 0x87,0xbb,0xe3,0x26,0xd2,0xe5,0x7d,0xe7,0x63,0xd4,0x5b,0x60,0x2a,0x66,0x32,0x60, ++ 0x33,0x58,0xb5,0xf3,0x92,0x24,0xd6,0x06,0xbc,0xd8,0x9d,0xcb,0x45,0x37,0x93,0x29, ++ 0x45,0x5b,0x3e,0xe1,0x7b,0x39,0x2f,0x35,0x62,0x76,0x62,0x4c,0xf4,0xc6,0x33,0x60, ++ 0x81,0x07,0xb5,0x86,0x10,0x28,0x7d,0xfc,0xeb,0x17,0xda,0x7d,0x0f,0xe4,0xc7,0x7b, ++ 0x3e,0xc5,0x02,0x4b,0xb8,0x18,0x96,0xb9,0x32,0xf7,0xce,0x0d,0x13,0x49,0x30,0xa5, ++ 0x41,0x1a,0xde,0xea,0x35,0x57,0x26,0x47,0x47,0xff,0x63,0xda,0x92,0x88,0x51,0x00, ++ 0x43,0x28,0x2b,0x0b,0xa8,0xc7,0xb7,0xba,0xb2,0x3e,0x93,0xaf,0x88,0x61,0x71,0x1d, ++ 0x29,0xea,0xaf,0x9c,0x34,0x7d,0x27,0x47,0x14,0xfa,0xde,0xdb,0x12,0x78,0x87,0xbb, ++ 0x0c,0x1f,0xf8,0xca,0x70,0x78,0x54,0xe0,0x68,0x5d,0xf6,0x65,0x86,0x0f,0xdd,0x78, ++ 0x7b,0x0d,0xf6,0x74,0x98,0x7c,0x32,0x8a,0x1c,0x7d,0x18,0xd3,0x2a,0xdd,0x7f,0xc1, ++ 0x62,0x1d,0x9f,0xc9,0xf0,0x5a,0x5f,0xeb,0x68,0xee,0x91,0x40,0x07,0x77,0x6f,0x59, ++ 0x63,0xee,0x3a,0xdc,0xaf,0x0b,0xbb,0x99,0x19,0x3a,0x54,0x8e,0xae,0x2a,0x63,0xe2, ++ 0xcc,0x52,0x20,0x0a,0x67,0xbb,0x16,0xaf,0xc8,0xcd,0xa0,0x44,0xe7,0x85,0x10,0xed, ++ 0x2b,0x27,0x2c,0x12,0x0d,0x4f,0xf9,0x34,0x8d,0xf3,0x41,0x11,0xf4,0x9e,0x81,0x10, ++ 0xde,0xe6,0xdb,0x61,0xd6,0xa9,0xce,0x04,0x65,0x66,0x89,0xcc,0x78,0xef,0x11,0xed, ++ 0x78,0x22,0xbb,0x26,0xb6,0xc3,0x9d,0x6c,0x66,0xa6,0x15,0xb3,0xc9,0x07,0xbf,0x43, ++ 0x86,0xc4,0x41,0x41,0xb7,0xe5,0xc4,0x88,0xa7,0xa2,0xa5,0x79,0x60,0x50,0x31,0xbc, ++ 0xa2,0x7a,0x1d,0xa8,0x13,0xc8,0x58,0x73,0xe0,0xd5,0xf3,0x76,0x3c,0x5d,0xbe,0x43, ++ 0x5a,0xa5,0xa9,0x43,0x7b,0xe7,0xc5,0x23,0xca,0x09,0x24,0x68,0xa4,0x4d,0x39,0x20, ++ 0xc7,0x5c,0x79,0x5c,0x13,0xf3,0x96,0x81,0x47,0xf6,0xf9,0x86,0x82,0x54,0x1a,0xf5, ++ 0xf9,0xeb,0x22,0x02,0x04,0x29,0x8d,0xc8,0xcc,0x2a,0xea,0x3e,0xb7,0xd9,0x54,0x82, ++ 0xf8,0x2a,0x2b,0xfb,0x2e,0xd6,0xff,0x3d,0xec,0x16,0x61,0x2a,0x26,0xef,0xd8,0x74, ++ 0xe4,0x18,0xc8,0x6f,0x90,0xea,0x15,0xb3,0x48,0x6e,0x93,0x76,0xa3,0xca,0xee,0xe8, ++ 0x93,0x20,0x13,0xec,0xad,0xb9,0x8f,0x59,0x32,0x6f,0xe0,0x3f,0x5f,0xa3,0x66,0x48, ++ 0x0a,0x57,0x46,0x3c,0x90,0xed,0x48,0xed,0xe2,0xd3,0x2d,0x90,0x29,0x1b,0x20,0xc7, ++ 0xe4,0x9e,0xdb,0xbc,0xc2,0x39,0x53,0x3d,0x61,0x41,0xe2,0x88,0xb6,0x9e,0x63,0x55, ++ 0xa8,0x73,0x5c,0x54,0x3d,0x2b,0x39,0x7e,0xae,0x5e,0x33,0x77,0x26,0x13,0x32,0xb0, ++ 0x2a,0x20,0x93,0x6d,0xaf,0x73,0x31,0x66,0x8e,0xce,0xe9,0x18,0x20,0x40,0x7a,0x1b, ++ 0xd4,0x3b,0x21,0x6e,0x87,0xfd,0x0c,0x5d,0x91,0xb3,0xf5,0xc0,0x9f,0x81,0x1f,0x63, ++ 0x77,0x5d,0x40,0x94,0x3d,0xdd,0x42,0x2a,0x90,0x72,0x82,0x8b,0x1d,0xf2,0xe6,0x47, ++ 0xcf,0xe0,0x5a,0x27,0x5d,0xd2,0xce,0xdc,0x8c,0x40,0xf4,0xc1,0x1f,0x63,0x0b,0x0f, ++ 0x21,0x37,0x4d,0x9e,0x48,0x39,0xf8,0x40,0xfb,0x58,0xc3,0x83,0x1c,0x82,0xf7,0x62, ++ 0x76,0x34,0x44,0xc8,0xba,0xb9,0x8b,0x32,0x18,0xd7,0xfb,0x06,0x72,0x54,0x6d,0xd0, ++ 0x2b,0x31,0x7c,0x16,0x73,0x51,0x87,0x80,0xe9,0xb0,0x79,0x7b,0x88,0xb7,0x43,0xfb, ++ 0x92,0x92,0x9b,0x25,0x1a,0xbb,0x4b,0xea,0xa5,0x24,0xfa,0x77,0x4d,0xb4,0xfa,0xef, ++ 0x6f,0xe6,0x95,0xde,0x5a,0x85,0x65,0xf2,0xb3,0x2b,0xfa,0x7f,0x77,0xba,0x61,0x8d, ++ 0x8d,0x67,0x65,0xc9,0x32,0x17,0xb6,0x9b,0x7a,0x77,0xa0,0x96,0x97,0x79,0x91,0xab, ++ 0x8c,0x66,0x96,0x3e,0xd0,0x39,0x40,0x33,0x25,0xfb,0xee,0xfe,0x3d,0x0c,0xf3,0x18, ++ 0x0d,0x45,0x33,0x0d,0x26,0xb0,0xf6,0xd9,0x86,0xe8,0x89,0x92,0x73,0x5c,0x94,0x3e, ++ 0x5a,0x66,0x47,0x87,0x3d,0xfb,0x1f,0x29,0xb5,0x66,0x28,0xbd,0xf9,0x0e,0xf7,0x0c, ++ 0x2e,0x9a,0x76,0x61,0xc9,0x5c,0x3c,0xa8,0x06,0xd1,0xc8,0xb3,0x9d,0x03,0x16,0x7a, ++ 0xd0,0x22,0x52,0x57,0x1b,0x89,0x44,0x7d,0xc3,0x82,0x09,0x00,0x9e,0xf2,0x6f,0xa5, ++ 0xcd,0xbe,0x5b,0x3c,0x1d,0x8e,0x6f,0xc1,0xef,0xc9,0x37,0xf6,0xec,0xf8,0x07,0x19, ++ 0x2c,0xdb,0x4f,0xd1,0x33,0x32,0x45,0x7c,0x43,0xc0,0x97,0x3d,0x79,0x0a,0x90,0x46, ++ 0xfc,0xab,0xc4,0x80,0x10,0xe1,0xeb,0x3b,0xbf,0xeb,0x26,0x46,0xa7,0x66,0xf4,0xe0, ++ 0x09,0x0e,0x48,0x10,0xe2,0x25,0x9c,0xc1,0xfe,0xc1,0x7b,0x73,0x8f,0x69,0x70,0x00, ++ 0x02,0x0a,0xa1,0x1d,0x6c,0x41,0xec,0x88,0xe2,0x9d,0x99,0x12,0x71,0x0e,0xe1,0x3b, ++ 0x06,0xf6,0x8f,0x2a,0xbf,0x61,0x47,0xde,0xc7,0xe8,0x1d,0xf2,0x51,0x43,0x40,0x40, ++ 0x02,0x04,0xc0,0x44,0x12,0x24,0x50,0x60,0x42,0x44,0xd0,0x64,0x52,0x64,0x48,0x50, ++ 0x03,0x05,0xc8,0x54,0x13,0x25,0x58,0x70,0x43,0x45,0xd8,0x74,0x53,0x65,0x41,0x41, ++ 0x82,0x06,0xc1,0x45,0x92,0x26,0x51,0x61,0xc2,0x46,0xd1,0x65,0xd2,0x66,0x49,0x51, ++ 0x83,0x07,0xc9,0x55,0x93,0x27,0x59,0x71,0xc3,0x47,0xd9,0x75,0xd3,0x67,0x62,0x4c, ++ 0x04,0x83,0x04,0x21,0x2b,0x27,0xef,0xb9,0x23,0x37,0x3e,0xec,0xfb,0x29,0x8a,0x7a, ++ 0x48,0x49,0xea,0x7c,0x53,0x24,0x44,0xd7,0x1b,0xe2,0x36,0x7e,0xda,0xc4,0x84,0xeb, ++ 0x0a,0x42,0xd9,0x08,0x3f,0x6b,0x90,0x89,0x7b,0xf5,0x7f,0xad,0x24,0x4a,0x73,0x7b, ++ 0xca,0xd4,0x27,0x8f,0x98,0x21,0xe6,0x3c,0xa2,0x34,0x8b,0xdd,0x91,0x6b,0x42,0x48, ++ 0x0a,0x0c,0xc2,0x4c,0x1a,0x2c,0x52,0x68,0x4a,0x4c,0xd2,0x6c,0x5a,0x6c,0x4a,0x58, ++ 0x0b,0x0d,0xca,0x5c,0x1b,0x2d,0x5a,0x78,0x4b,0x4d,0xda,0x7c,0x5b,0x6d,0x43,0x49, ++ 0x8a,0x0e,0xc3,0x4d,0x9a,0x2e,0x53,0x69,0xca,0x4e,0xd3,0x6d,0xda,0x6e,0x4b,0x59, ++ 0x8b,0x0f,0xcb,0x5d,0x9b,0x2f,0x5b,0x79,0xcb,0x4f,0xdb,0x7d,0xdb,0x6f,0xdf,0xf2, ++ 0x9f,0xaf,0x68,0x04,0xcc,0x10,0xb4,0xb3,0x63,0x34,0xf6,0x24,0x70,0x30,0x6d,0xe2, ++ 0xde,0xce,0xb4,0x67,0x33,0x95,0x3c,0xb1,0xec,0x17,0x26,0xb6,0xde,0x77,0xfa,0x7f, ++ 0xa6,0x62,0x29,0x07,0xb1,0x27,0x2d,0x41,0xec,0x3c,0xb5,0x4f,0xf6,0xe2,0xcd,0x89, ++ 0x59,0x9e,0xe2,0x14,0x79,0xed,0x9e,0x11,0xb5,0x63,0x95,0x6a,0x10,0x7c,0x44,0xc0, ++ 0x22,0x14,0xc4,0xc4,0x32,0x34,0x54,0xe0,0x62,0x54,0xd4,0xe4,0x72,0x74,0x4c,0xd0, ++ 0x23,0x15,0xcc,0xd4,0x33,0x35,0x5c,0xf0,0x63,0x55,0xdc,0xf4,0x73,0x75,0x45,0xc1, ++ 0xa2,0x16,0xc5,0xc5,0xb2,0x36,0x55,0xe1,0xe2,0x56,0xd5,0xe5,0xf2,0x76,0x4d,0xd1, ++ 0xa3,0x17,0xcd,0xd5,0xb3,0x37,0x5d,0xf1,0xe3,0x57,0xdd,0xf5,0xf3,0x77,0xf9,0x76, ++ 0x2e,0xa8,0x46,0x9f,0xe7,0x5a,0x30,0x69,0xec,0xfc,0x06,0xad,0x58,0x78,0xce,0x98, ++ 0x6d,0x58,0x3d,0x18,0xc1,0x1b,0x66,0x3c,0x31,0x25,0x9e,0xbc,0x79,0x79,0x32,0xfb, ++ 0x57,0xc5,0x67,0xb2,0x44,0x58,0x5f,0xae,0x8b,0x7a,0x97,0xad,0xf8,0x7a,0xe3,0x19, ++ 0x55,0x3b,0xbc,0x1d,0x9d,0x55,0xaf,0xa5,0x08,0x38,0x9f,0xbd,0xf9,0x7b,0x46,0xc8, ++ 0x2a,0x1c,0xc6,0xcc,0x3a,0x3c,0x56,0xe8,0x6a,0x5c,0xd6,0xec,0x7a,0x7c,0x4e,0xd8, ++ 0x2b,0x1d,0xce,0xdc,0x3b,0x3d,0x5e,0xf8,0x6b,0x5d,0xde,0xfc,0x7b,0x7d,0x47,0xc9, ++ 0xaa,0x1e,0xc7,0xcd,0xba,0x3e,0x57,0xe9,0xea,0x5e,0xd7,0xed,0xfa,0x7e,0x4f,0xd9, ++ 0xab,0x1f,0xcf,0xdd,0xbb,0x3f,0x5f,0xf9,0xeb,0x5f,0xdf,0xfd,0xfb,0x7f,0x58,0x80, ++ 0x01,0x60,0x5e,0x84,0xea,0x1f,0x60,0x82,0xf7,0x7f,0xee,0x31,0x5c,0xe0,0xa0,0x06, ++ 0xa4,0x09,0xd6,0x10,0xf4,0x22,0x50,0xf0,0xc3,0x34,0x28,0xf1,0x57,0x14,0x7b,0x1e, ++ 0x27,0x84,0x99,0xf9,0xf4,0xae,0x82,0xdd,0x38,0x3d,0xd9,0xe5,0x52,0x17,0xa9,0xf1, ++ 0x24,0x09,0xde,0xe4,0x19,0x5e,0xa9,0xf4,0xc7,0x36,0xbd,0x70,0x54,0xed,0x60,0x42, ++ 0x06,0x84,0xe0,0x46,0x16,0xa4,0x70,0x62,0x46,0xc4,0xf0,0x66,0x56,0xe4,0x68,0x52, ++ 0x07,0x85,0xe8,0x56,0x17,0xa5,0x78,0x72,0x47,0xc5,0xf8,0x76,0x57,0xe5,0x61,0x43, ++ 0x86,0x86,0xe1,0x47,0x96,0xa6,0x71,0x63,0xc6,0xc6,0xf1,0x67,0xd6,0xe6,0x69,0x53, ++ 0x87,0x87,0xe9,0x57,0x97,0xa7,0x79,0x73,0xc7,0xc7,0xf9,0x77,0xd7,0xe7,0xd9,0xe8, ++ 0x0a,0x38,0xda,0x70,0x5c,0x22,0x36,0x6d,0xcd,0xc6,0x0d,0x8e,0xfd,0x48,0xba,0x9e, ++ 0x55,0x81,0xd2,0x9c,0x3c,0xdb,0xfa,0x23,0x12,0x34,0x39,0xfc,0xde,0xaf,0xd0,0x6b, ++ 0xec,0x81,0x74,0x8d,0x62,0x15,0x90,0xeb,0x10,0xe0,0x34,0x90,0xdc,0xca,0xf4,0x17, ++ 0x8b,0x3b,0xf1,0x1e,0x3e,0xea,0x23,0xd5,0x05,0xe1,0x0c,0x1b,0xdb,0x5b,0x62,0x4a, ++ 0x0e,0x8c,0xe2,0x4e,0x1e,0xac,0x72,0x6a,0x4e,0xcc,0xf2,0x6e,0x5e,0xec,0x6a,0x5a, ++ 0x0f,0x8d,0xea,0x5e,0x1f,0xad,0x7a,0x7a,0x4f,0xcd,0xfa,0x7e,0x5f,0xed,0x63,0x4b, ++ 0x8e,0x8e,0xe3,0x4f,0x9e,0xae,0x73,0x6b,0xce,0xce,0xf3,0x6f,0xde,0xee,0x6b,0x5b, ++ 0x8f,0x8f,0xeb,0x5f,0x9f,0xaf,0x7b,0x7b,0xcf,0xcf,0xfb,0x7f,0xdf,0xef,0x88,0xc0, ++ 0xa7,0x44,0xe4,0xb9,0x3c,0xdc,0xcb,0x60,0xe7,0x96,0xb4,0xa6,0x74,0xf0,0xd1,0x3b, ++ 0x07,0x4e,0x43,0x66,0x6d,0xbe,0x2e,0x12,0x3d,0x83,0xbc,0xb6,0x75,0xf1,0xde,0x9c, ++ 0x5b,0x39,0x8d,0x45,0x36,0xba,0x82,0x87,0xc6,0xe2,0xb5,0xa7,0xf4,0xf2,0xa9,0x62, ++ 0x1a,0x13,0xcd,0xd7,0x4e,0xbe,0x0a,0x1b,0x19,0xb0,0xbd,0xb7,0xf5,0xf3,0x64,0xc2, ++ 0x26,0x94,0xe4,0xc6,0x36,0xb4,0x74,0xe2,0x66,0xd4,0xf4,0xe6,0x76,0xf4,0x6c,0xd2, ++ 0x27,0x95,0xec,0xd6,0x37,0xb5,0x7c,0xf2,0x67,0xd5,0xfc,0xf6,0x77,0xf5,0x65,0xc3, ++ 0xa6,0x96,0xe5,0xc7,0xb6,0xb6,0x75,0xe3,0xe6,0xd6,0xf5,0xe7,0xf6,0xf6,0x6d,0xd3, ++ 0xa7,0x97,0xed,0xd7,0xb7,0xb7,0x7d,0xf3,0xe7,0xd7,0xfd,0xf7,0xf7,0xf7,0x78,0x65, ++ 0x2a,0x33,0xd4,0x97,0x7c,0x43,0xf6,0xbb,0x12,0x75,0xb6,0xae,0x7c,0xf8,0x2d,0x3a, ++ 0x9e,0x26,0xae,0x5c,0xbe,0xff,0x66,0x32,0x84,0xca,0xbe,0xbe,0x7d,0xf9,0xda,0x1a, ++ 0xc7,0xe5,0xa3,0x8d,0xb8,0x41,0x26,0x3b,0x85,0xb9,0xb7,0xaf,0xfc,0xfa,0x71,0x74, ++ 0xbb,0x0f,0x18,0xbb,0x3f,0xb3,0x93,0x29,0xe9,0xd3,0xbf,0xbf,0xfd,0xfb,0x66,0xca, ++ 0x2e,0x9c,0xe6,0xce,0x3e,0xbc,0x76,0xea,0x6e,0xdc,0xf6,0xee,0x7e,0xfc,0x6e,0xda, ++ 0x2f,0x9d,0xee,0xde,0x3f,0xbd,0x7e,0xfa,0x6f,0xdd,0xfe,0xfe,0x7f,0xfd,0x67,0xcb, ++ 0xae,0x9e,0xe7,0xcf,0xbe,0xbe,0x77,0xeb,0xee,0xde,0xf7,0xef,0xfe,0xfe,0x6f,0xdb, ++ 0xaf,0x9f,0xef,0xdf,0xbf,0xbf,0x7f,0xfb,0xef,0xdf,0xff,0xff,0x88,0x9f,*/ ++}; ++#endif ++ ++#endif +\ No newline at end of file +diff --git a/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx_update.c b/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx_update.c +new file mode 100644 +index 000000000..499599af3 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/gt9xx_touch/gt9xx_update.c +@@ -0,0 +1,2092 @@ ++/* ++ * Goodix GT9xx touchscreen driver ++ * ++ * Copyright (C) 2016 - 2017 Goodix. Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be a reference ++ * to you, when you are integrating the GOODiX's CTP IC into your system, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * Version: 2.8.0.1 ++ * Release Date: 2017/11/24 ++ */ ++ ++#include ++#include "gt9xx.h" ++ ++#include ++#include ++#include ++#include ++ ++#define GUP_REG_HW_INFO 0x4220 ++#define GUP_REG_FW_MSG 0x41E4 ++#define GUP_REG_PID_VID 0x8140 ++ ++#define FIRMWARE_NAME_LEN_MAX 256 ++#define GOODIX_FIRMWARE_FILE_NAME "goodix_firmware.bin" ++#define GOODIX_CONFIG_FILE_NAME "goodix_config.cfg" ++ ++#define FW_HEAD_LENGTH 14 ++#define FW_SECTION_LENGTH 0x2000 /* 8K */ ++#define FW_DSP_ISP_LENGTH 0x1000 /* 4K */ ++#define FW_DSP_LENGTH 0x1000 /* 4K */ ++#define FW_BOOT_LENGTH 0x800 /* 2K */ ++#define FW_SS51_LENGTH (4 * FW_SECTION_LENGTH) /* 32K */ ++#define FW_BOOT_ISP_LENGTH 0x800 /* 2k */ ++#define FW_GLINK_LENGTH 0x3000 /* 12k */ ++#define FW_GWAKE_LENGTH (4 * FW_SECTION_LENGTH) /* 32k */ ++ ++#define PACK_SIZE 256 ++#define MAX_FRAME_CHECK_TIME 5 ++ ++ ++#define _bRW_MISCTL__SRAM_BANK 0x4048 ++#define _bRW_MISCTL__MEM_CD_EN 0x4049 ++#define _bRW_MISCTL__CACHE_EN 0x404B ++#define _bRW_MISCTL__TMR0_EN 0x40B0 ++#define _rRW_MISCTL__SWRST_B0_ 0x4180 ++#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184 ++#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190 ++#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218 ++#define _rRW_MISCTL__BOOT_CTL_ 0x5094 ++ ++#pragma pack(1) ++struct st_fw_head { ++ u8 hw_info[4]; /* hardware info */ ++ u8 pid[8]; /* product id */ ++ u16 vid; /* version id */ ++}; ++#pragma pack() ++ ++struct st_update_msg { ++ u8 fw_damaged; ++ u8 fw_flag; ++ const u8 *fw_data; ++ struct file *cfg_file; ++ struct st_fw_head ic_fw_msg; ++ u32 fw_total_len; ++ u32 fw_burned_len; ++ const struct firmware *fw; ++} update_msg; ++ ++struct st_update_msg update_msg; ++ ++u16 show_len; ++u16 total_len; ++ ++static u8 gup_burn_fw_gwake_section(struct i2c_client *client, ++ u8 *fw_section, u16 start_addr, ++ u32 len, u8 bank_cmd); ++ ++static s32 gup_init_panel(struct goodix_ts_data *ts) ++{ ++ s32 ret = 0; ++ u8 opr_buf[16]; ++ u8 sensor_id = 0; ++ u8 drv_cfg_version; ++ u8 flash_cfg_version; ++ struct goodix_config_data *cfg = &ts->pdata->config; ++ ++ if (cfg->length < GTP_CONFIG_MIN_LENGTH) { ++ dev_err(&ts->client->dev, ++ "No valid config with sensor_ID(%d) ", ++ sensor_id); ++ ++ return -EPERM; ++ } ++ ++ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, ++ &opr_buf[0], 1); ++ if (ret == SUCCESS) { ++ dev_dbg(&ts->client->dev, ++ "CFG_GROUP%d Config Version: %d, IC Config Version: %d", ++ sensor_id, cfg->data[GTP_ADDR_LENGTH], opr_buf[0]); ++ ++ flash_cfg_version = opr_buf[0]; ++ drv_cfg_version = cfg->data[GTP_ADDR_LENGTH]; ++ ++ if (flash_cfg_version < 90 && ++ flash_cfg_version > drv_cfg_version) ++ cfg->data[GTP_ADDR_LENGTH] = 0x00; ++ } else { ++ dev_err(&ts->client->dev, ++ "Failed to get ic config version!No config sent!"); ++ return -EPERM; ++ } ++ ++ ret = gtp_send_cfg(ts->client); ++ if (ret < 0) ++ dev_err(&ts->client->dev, "Send config error."); ++ else ++ usleep_range(10000, 11000); ++ ++ /* restore config vrsion */ ++ cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version; ++ ++ return 0; ++} ++ ++ ++static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len) ++{ ++ s32 i = 0; ++ ++ msg[0] = (addr >> 8) & 0xff; ++ msg[1] = addr & 0xff; ++ ++ for (i = 0; i < 5; i++) { ++ if (gtp_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0) ++ break; ++ } ++ ++ if (i >= 5) { ++ dev_err(&client->dev, ++ "Read data from 0x%02x%02x failed!", ++ msg[0], msg[1]); ++ return FAIL; ++ } ++ ++ return SUCCESS; ++} ++ ++static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val) ++{ ++ s32 i = 0; ++ u8 msg[3]; ++ ++ msg[0] = (addr >> 8) & 0xff; ++ msg[1] = addr & 0xff; ++ msg[2] = val; ++ ++ for (i = 0; i < 5; i++) { ++ if (gtp_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0) ++ break; ++ } ++ ++ if (i >= 5) { ++ dev_err(&client->dev, ++ "Set data to 0x%02x%02x failed!", msg[0], msg[1]); ++ return FAIL; ++ } ++ ++ return SUCCESS; ++} ++ ++static u8 gup_get_ic_fw_msg(struct i2c_client *client) ++{ ++ s32 ret = -1; ++ u8 retry = 0; ++ u8 buf[16]; ++ u8 i; ++ ++ /* step1:get hardware info */ ++ ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, ++ &buf[GTP_ADDR_LENGTH], 4); ++ if (FAIL == ret) { ++ dev_err(&client->dev, "[get_ic_fw_msg]get hw_info failed,exit"); ++ return FAIL; ++ } ++ ++ /* buf[2~5]: 00 06 90 00 ++ * hw_info: 00 90 06 00 ++ */ ++ for (i = 0; i < 4; i++) ++ update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i]; ++ dev_dbg(&client->dev, ++ "IC Hardware info:%02x%02x%02x%02x", ++ update_msg.ic_fw_msg.hw_info[0], ++ update_msg.ic_fw_msg.hw_info[1], ++ update_msg.ic_fw_msg.hw_info[2], ++ update_msg.ic_fw_msg.hw_info[3]); ++ /* step2:get firmware message */ ++ for (retry = 0; retry < 2; retry++) { ++ ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1); ++ if (FAIL == ret) { ++ dev_err(&client->dev, "Read firmware message fail."); ++ return ret; ++ } ++ ++ update_msg.fw_damaged = buf[GTP_ADDR_LENGTH]; ++ if ((0xBE != update_msg.fw_damaged) && (!retry)) { ++ dev_info(&client->dev, "The check sum in ic is error."); ++ dev_info(&client->dev, "The IC will be updated by force."); ++ continue; ++ } ++ break; ++ } ++ dev_dbg(&client->dev, ++ "IC force update flag:0x%x", update_msg.fw_damaged); ++ ++ /* step3:get pid & vid */ ++ ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, ++ &buf[GTP_ADDR_LENGTH], 6); ++ if (FAIL == ret) { ++ dev_err(&client->dev, "[get_ic_fw_msg]get pid & vid failed,exit"); ++ return FAIL; ++ } ++ ++ memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid)); ++ memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4); ++ dev_dbg(&client->dev, "IC Product id:%s", update_msg.ic_fw_msg.pid); ++ ++ /* GT9XX PID MAPPING */ ++ /*|-----FLASH-----RAM-----| ++ *|------918------918-----| ++ *|------968------968-----| ++ *|------913------913-----| ++ *|------913P-----913P----| ++ *|------927------927-----| ++ *|------927P-----927P----| ++ *|------9110-----9110----| ++ *|------9110P----9111----|*/ ++ if (update_msg.ic_fw_msg.pid[0] != 0) { ++ if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) { ++ dev_dbg(&client->dev, "IC Mapping Product id:%s", ++ update_msg.ic_fw_msg.pid); ++ memcpy(update_msg.ic_fw_msg.pid, "9110P", 5); ++ } ++ } ++ ++ update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] + ++ (buf[GTP_ADDR_LENGTH + 5] << 8); ++ dev_dbg(&client->dev, "IC version id:%04x", update_msg.ic_fw_msg.vid); ++ ++ return SUCCESS; ++} ++ ++s32 gup_enter_update_mode(struct i2c_client *client) ++{ ++ s32 ret = -1; ++ s32 retry = 0; ++ u8 rd_buf[3]; ++ ++ struct goodix_ts_data *ts = i2c_get_clientdata(client); ++ ++ /* step1:RST output low last at least 2ms */ ++ if (!gpio_is_valid(ts->pdata->rst_gpio)) { ++ dev_err(&ts->client->dev, "update failed, no rst pin\n"); ++ return FAIL; ++ } ++ gpio_direction_output(ts->pdata->rst_gpio, 0); ++ usleep_range(2000, 3000); ++ ++ /* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */ ++ gtp_int_output(ts, client->addr == 0x14); ++ usleep_range(2000, 3000); ++ ++ /* step3:RST output high reset guitar */ ++ gpio_direction_output(ts->pdata->rst_gpio, 1); ++ ++ /* 20121211 modify start */ ++ usleep_range(5000, 6000); ++ while (retry++ < 200) { ++ /* step4:Hold ss51 & dsp */ ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); ++ if (ret <= 0) { ++ dev_dbg(&client->dev, ++ "Hold ss51 & dsp I2C error,retry:%d", ++ retry); ++ continue; ++ } ++ ++ /* step5:Confirm hold */ ++ ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1); ++ if (ret <= 0) { ++ dev_dbg(&client->dev, ++ "Hold ss51 & dsp I2C error,retry:%d", ++ retry); ++ continue; ++ } ++ if (0x0C == rd_buf[GTP_ADDR_LENGTH]) { ++ dev_dbg(&client->dev, "Hold ss51 & dsp confirm SUCCESS"); ++ break; ++ } ++ dev_dbg(&client->dev, ++ "Hold ss51 & dsp confirm 0x4180 failed,value:%d", ++ rd_buf[GTP_ADDR_LENGTH]); ++ } ++ if (retry >= 200) { ++ dev_err(&client->dev, "Enter update Hold ss51 failed."); ++ return FAIL; ++ } ++ ++ /* step6:DSP_CK and DSP_ALU_CK PowerOn */ ++ ret = gup_set_ic_msg(client, 0x4010, 0x00); ++ ++ /* 20121211 modify end */ ++ return ret; ++} ++ ++void gup_leave_update_mode(struct i2c_client *client) ++{ ++ struct goodix_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (ts->pdata->int_sync && ts->pinctrl.pinctrl) ++ pinctrl_select_state(ts->pinctrl.pinctrl, ++ ts->pinctrl.int_input); ++ else if (ts->pdata->int_sync && gpio_is_valid(ts->pdata->irq_gpio)) ++ gpio_direction_input(ts->pdata->irq_gpio); ++ dev_dbg(&client->dev, "[leave_update_mode]reset chip."); ++ gtp_reset_guitar(i2c_connect_client, 20); ++} ++ ++static u8 gup_enter_update_judge(struct i2c_client *client, ++ struct st_fw_head *fw_head) ++{ ++ u16 u16_tmp; ++ s32 i = 0; ++ u32 fw_len = 0; ++ s32 pid_cmp_len = 0; ++ ++ u16_tmp = fw_head->vid; ++ fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8); ++ ++ dev_info(&client->dev, "FILE HARDWARE INFO:%*ph\n", 4, ++ &fw_head->hw_info[0]); ++ dev_info(&client->dev, "FILE PID:%s\n", fw_head->pid); ++ dev_info(&client->dev, "FILE VID:%04x\n", fw_head->vid); ++ ++ dev_info(&client->dev, "IC HARDWARE INFO:%*ph\n", 4, ++ &update_msg.ic_fw_msg.hw_info[0]); ++ dev_info(&client->dev, "IC PID:%s\n", update_msg.ic_fw_msg.pid); ++ dev_info(&client->dev, "IC VID:%04x\n", update_msg.ic_fw_msg.vid); ++ ++ if (!memcmp(fw_head->pid, "9158", 4) && ++ !memcmp(update_msg.ic_fw_msg.pid, "915S", 4)) { ++ dev_info(&client->dev, "Update GT915S to GT9158 directly!"); ++ return SUCCESS; ++ } ++ /* First two conditions */ ++ if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, ++ sizeof(update_msg.ic_fw_msg.hw_info))) { ++ fw_len = 42 * 1024; ++ } else { ++ fw_len = fw_head->hw_info[3]; ++ fw_len += (((u32)fw_head->hw_info[2]) << 8); ++ fw_len += (((u32)fw_head->hw_info[1]) << 16); ++ fw_len += (((u32)fw_head->hw_info[0]) << 24); ++ } ++ if (update_msg.fw_total_len != fw_len) { ++ dev_err(&client->dev, ++ "Inconsistent firmware size, Update aborted!"); ++ dev_err(&client->dev, ++ " Default size: %d(%dK), actual size: %d(%dK)", ++ fw_len, fw_len/1024, update_msg.fw_total_len, ++ update_msg.fw_total_len/1024); ++ return FAIL; ++ } ++ dev_info(&client->dev, "Firmware length:%d(%dK)", ++ update_msg.fw_total_len, ++ update_msg.fw_total_len/1024); ++ ++ if (update_msg.fw_damaged != 0xBE) { ++ dev_info(&client->dev, "FW chksum error,need enter update."); ++ return SUCCESS; ++ } ++ ++ /* 20130523 start */ ++ if (strlen(update_msg.ic_fw_msg.pid) < 3) { ++ dev_info(&client->dev, "Illegal IC pid, need enter update"); ++ return SUCCESS; ++ } ++ ++ /* check pid legality */ ++ for (i = 0; i < 3; i++) { ++ if (!isdigit(update_msg.ic_fw_msg.pid[i])) { ++ dev_info(&client->dev, ++ "Illegal IC pid, need enter update"); ++ return SUCCESS; ++ } ++ } ++ /* 20130523 end */ ++ ++ pid_cmp_len = strlen(fw_head->pid); ++ if (pid_cmp_len < strlen(update_msg.ic_fw_msg.pid)) ++ pid_cmp_len = strlen(update_msg.ic_fw_msg.pid); ++ ++ if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, pid_cmp_len)) || ++ (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) || ++ (!memcmp(fw_head->pid, "91XX", 4))) { ++ if (!memcmp(fw_head->pid, "91XX", 4)) ++ dev_dbg(&client->dev, ++ "Force none same pid update mode."); ++ else ++ dev_dbg(&client->dev, "Get the same pid."); ++ ++ /* The third condition */ ++ if (fw_head->vid != update_msg.ic_fw_msg.vid) { ++ dev_info(&client->dev, "Need enter update."); ++ return SUCCESS; ++ } ++ dev_err(&client->dev, "File VID == Ic VID, update aborted!"); ++ } else { ++ dev_err(&client->dev, "File PID != Ic PID, update aborted!"); ++ } ++ ++ return FAIL; ++} ++ ++static int gup_update_config(struct i2c_client *client) ++{ ++ s32 ret = 0; ++ s32 i = 0; ++ s32 file_cfg_len = 0; ++ u8 *file_config; ++ const struct firmware *fw_cfg; ++ ++ struct goodix_ts_data *ts = i2c_get_clientdata(client); ++ ++ ret = request_firmware(&fw_cfg, GOODIX_CONFIG_FILE_NAME, ++ &client->dev); ++ if (ret < 0) { ++ dev_err(&client->dev, ++ "Cannot get config file - %s (%d)\n", ++ GOODIX_CONFIG_FILE_NAME, ret); ++ return -EFAULT; ++ } ++ if (!fw_cfg || !fw_cfg->data || fw_cfg->size > PAGE_SIZE) { ++ dev_err(&client->dev, "config file illegal"); ++ ret = -EFAULT; ++ goto cfg_fw_err; ++ } ++ ++ dev_dbg(&client->dev, "config firmware file len:%zu", fw_cfg->size); ++ ++ file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, ++ GFP_KERNEL); ++ if (!file_config) { ++ dev_err(&ts->client->dev, "failed alloc memory"); ++ ret = -ENOMEM; ++ goto cfg_fw_err; ++ } ++ file_config[0] = GTP_REG_CONFIG_DATA >> 8; ++ file_config[1] = GTP_REG_CONFIG_DATA & 0xff; ++ file_cfg_len = gtp_ascii_to_array(fw_cfg->data, fw_cfg->size, ++ &file_config[GTP_ADDR_LENGTH]); ++ if (file_cfg_len < 0) { ++ dev_err(&client->dev, "failed covert ascii to hex"); ++ ret = -EFAULT; ++ goto update_cfg_file_failed; ++ } ++ ++ GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len); ++ ++ i = 0; ++ while (i++ < 5) { ++ ret = gtp_i2c_write(client, file_config, file_cfg_len + 2); ++ if (ret > 0) { ++ dev_info(&client->dev, "Send config SUCCESS."); ++ msleep(500); ++ break; ++ } ++ dev_err(&ts->client->dev, "Send config i2c error."); ++ } ++ ++update_cfg_file_failed: ++ kfree(file_config); ++cfg_fw_err: ++ release_firmware(fw_cfg); ++ return ret; ++} ++ ++static u8 gup_check_firmware_name(struct i2c_client *client, ++ u8 **path_p) ++{ ++ u8 len; ++ u8 *fname; ++ ++ if (!(*path_p)) { ++ *path_p = GOODIX_FIRMWARE_FILE_NAME; ++ return 0; ++ } ++ ++ len = strnlen(*path_p, FIRMWARE_NAME_LEN_MAX); ++ if (len >= FIRMWARE_NAME_LEN_MAX) { ++ dev_err(&client->dev, "firmware name too long!"); ++ return -EINVAL; ++ } ++ ++ fname = strrchr(*path_p, '/'); ++ if (fname) { ++ fname = fname + 1; ++ *path_p = fname; ++ } ++ ++ return 0; ++} ++ ++static u8 gup_get_update_file(struct i2c_client *client, ++ struct st_fw_head *fw_head, u8 *path) ++{ ++ s32 ret = 0; ++ s32 i = 0; ++ s32 fw_checksum = 0; ++ struct goodix_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (ts->pdata->auto_update_cfg) { ++ ret = gup_update_config(client); ++ if (ret <= 0) ++ dev_err(&client->dev, "Update config failed."); ++ } ++ ++ ret = gup_check_firmware_name(client, &path); ++ if (ret < 0) ++ return FAIL; ++ ++ ret = request_firmware(&update_msg.fw, path, &client->dev); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed get firmware:%d\n", ret); ++ return FAIL; ++ } ++ ++ dev_info(&client->dev, "FW File: %s size=%zu", ++ path, update_msg.fw->size); ++ update_msg.fw_data = update_msg.fw->data; ++ update_msg.fw_total_len = update_msg.fw->size; ++ ++ if (update_msg.fw_total_len < ++ FW_HEAD_LENGTH + FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH + ++ FW_DSP_LENGTH + FW_BOOT_LENGTH) { ++ dev_err(&client->dev, ++ "INVALID bin file(size: %d), update aborted.", ++ update_msg.fw_total_len); ++ goto invalied_fw; ++ } ++ ++ update_msg.fw_total_len -= FW_HEAD_LENGTH; ++ ++ dev_dbg(&client->dev, "Bin firmware actual size: %d(%dK)", ++ update_msg.fw_total_len, update_msg.fw_total_len/1024); ++ ++ memcpy(fw_head, update_msg.fw_data, FW_HEAD_LENGTH); ++ ++ /* check firmware legality */ ++ fw_checksum = 0; ++ for (i = 0; i < update_msg.fw_total_len; i += 2) { ++ u16 temp; ++ ++ temp = (update_msg.fw_data[FW_HEAD_LENGTH + i] << 8) + ++ update_msg.fw_data[FW_HEAD_LENGTH + i + 1]; ++ fw_checksum += temp; ++ } ++ ++ dev_dbg(&client->dev, "firmware checksum:%x", fw_checksum&0xFFFF); ++ if (fw_checksum & 0xFFFF) { ++ dev_err(&client->dev, "Illegal firmware file."); ++ goto invalied_fw; ++ } ++ ++ return SUCCESS; ++ ++invalied_fw: ++ update_msg.fw_data = NULL; ++ update_msg.fw_total_len = 0; ++ release_firmware(update_msg.fw); ++ return FAIL; ++} ++ ++static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, ++ u16 start_addr, u16 total_length) ++{ ++ s32 ret = 0; ++ u16 burn_addr = start_addr; ++ u16 frame_length = 0; ++ u16 burn_length = 0; ++ u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH]; ++ u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; ++ u8 retry = 0; ++ ++ dev_dbg(&client->dev, "Begin burn %dk data to addr 0x%x", ++ total_length / 1024, start_addr); ++ while (burn_length < total_length) { ++ dev_dbg(&client->dev, ++ "B/T:%04d/%04d", burn_length, total_length); ++ frame_length = ((total_length - burn_length) ++ > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length); ++ wr_buf[0] = (u8)(burn_addr>>8); ++ rd_buf[0] = wr_buf[0]; ++ wr_buf[1] = (u8)burn_addr; ++ rd_buf[1] = wr_buf[1]; ++ memcpy(&wr_buf[GTP_ADDR_LENGTH], ++ &burn_buf[burn_length], frame_length); ++ ++ for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) { ++ ret = gtp_i2c_write(client, ++ wr_buf, GTP_ADDR_LENGTH + frame_length); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "Write frame data i2c error."); ++ continue; ++ } ++ ret = gtp_i2c_read(client, rd_buf, ++ GTP_ADDR_LENGTH + frame_length); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "Read back frame data i2c error."); ++ continue; ++ } ++ if (memcmp(&wr_buf[GTP_ADDR_LENGTH], ++ &rd_buf[GTP_ADDR_LENGTH], frame_length)) { ++ dev_err(&client->dev, ++ "Check frame data fail,not equal."); ++ dev_dbg(&client->dev, "write array:"); ++ GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], ++ frame_length); ++ dev_dbg(&client->dev, "read array:"); ++ GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], ++ frame_length); ++ continue; ++ } else { ++ /* dev_dbg(&client->dev, ++ * "Check frame data success."); ++ */ ++ break; ++ } ++ } ++ if (retry >= MAX_FRAME_CHECK_TIME) { ++ dev_err(&client->dev, ++ "Burn frame data time out,exit."); ++ return FAIL; ++ } ++ burn_length += frame_length; ++ burn_addr += frame_length; ++ } ++ ++ return SUCCESS; ++} ++ ++static u8 gup_load_section_file(u8 *buf, u32 offset, u16 length, u8 set_or_end) ++{ ++ if (!update_msg.fw_data || ++ update_msg.fw_total_len < offset + length) { ++ dev_err(&i2c_connect_client->dev, ++ "cannot load section data. fw_len=%d read end=%d\n", ++ update_msg.fw_total_len, ++ FW_HEAD_LENGTH + offset + length); ++ return FAIL; ++ } ++ ++ if (SEEK_SET == set_or_end) { ++ memcpy(buf, &update_msg.fw_data[FW_HEAD_LENGTH + offset], ++ length); ++ } else { ++ /* seek end */ ++ memcpy(buf, &update_msg.fw_data[update_msg.fw_total_len + ++ FW_HEAD_LENGTH - offset], length); ++ } ++ ++ return SUCCESS; ++} ++ ++static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src, ++ u16 start_rd_addr, u16 chk_length) ++{ ++ u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; ++ s32 ret = 0; ++ u16 recall_addr = start_rd_addr; ++ u16 recall_length = 0; ++ u16 frame_length = 0; ++ ++ while (recall_length < chk_length) { ++ frame_length = ((chk_length - recall_length) ++ > PACK_SIZE) ? PACK_SIZE : ++ (chk_length - recall_length); ++ ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length); ++ if (ret <= 0) { ++ dev_err(&client->dev, "recall i2c error,exit"); ++ return FAIL; ++ } ++ ++ if (memcmp(&rd_buf[GTP_ADDR_LENGTH], ++ &chk_src[recall_length], frame_length)) { ++ dev_err(&client->dev, "Recall frame data fail,not equal."); ++ dev_dbg(&client->dev, "chk_src array:"); ++ GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length); ++ dev_dbg(&client->dev, "recall array:"); ++ GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length); ++ return FAIL; ++ } ++ ++ recall_length += frame_length; ++ recall_addr += frame_length; ++ } ++ dev_dbg(&client->dev, ++ "Recall check %dk firmware success.", ++ (chk_length/1024)); ++ ++ return SUCCESS; ++} ++ ++static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, ++ u16 start_addr, u8 bank_cmd) ++{ ++ s32 ret = 0; ++ u8 rd_buf[5]; ++ ++ /* step1:hold ss51 & dsp */ ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_section]hold ss51 & dsp fail."); ++ return FAIL; ++ } ++ ++ /* step2:set scramble */ ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_section]set scramble fail."); ++ return FAIL; ++ } ++ ++ /* step3:select bank */ ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, ++ (bank_cmd >> 4)&0x0F); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_section]select bank %d fail.", ++ (bank_cmd >> 4)&0x0F); ++ return FAIL; ++ } ++ ++ /* step4:enable accessing code */ ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_section]enable accessing code fail."); ++ return FAIL; ++ } ++ ++ /* step5:burn 8k fw section */ ++ ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_section]burn fw_section fail."); ++ return FAIL; ++ } ++ ++ /* step6:hold ss51 & release dsp */ ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_section]hold ss51 & release dsp fail."); ++ return FAIL; ++ } ++ /* must delay */ ++ usleep_range(1000, 2000); ++ ++ /* step7:send burn cmd to move data to flash from sram */ ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_section]send burn cmd fail."); ++ return FAIL; ++ } ++ dev_dbg(&client->dev, ++ "[burn_fw_section]Wait for the burn is complete......"); ++ do { ++ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_section]Get burn state fail"); ++ return FAIL; ++ } ++ usleep_range(10000, 11000); ++ /* dev_dbg(&client->dev, "[burn_fw_section]Get burn state:%d.", ++ * rd_buf[GTP_ADDR_LENGTH]); ++ */ ++ } while (rd_buf[GTP_ADDR_LENGTH]); ++ ++ /* step8:select bank */ ++ ret = gup_set_ic_msg(client, ++ _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4) & 0x0F); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_section]select bank %d fail.", ++ (bank_cmd >> 4)&0x0F); ++ return FAIL; ++ } ++ ++ /* step9:enable accessing code */ ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_section]enable accessing code fail."); ++ return FAIL; ++ } ++ ++ /* step10:recall 8k fw section */ ++ ret = gup_recall_check(client, ++ fw_section, start_addr, FW_SECTION_LENGTH); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_section]recall check %dk firmware fail.", ++ FW_SECTION_LENGTH / 1024); ++ return FAIL; ++ } ++ ++ /* step11:disable accessing code */ ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_section]disable accessing code fail."); ++ return FAIL; ++ } ++ ++ return SUCCESS; ++} ++ ++static u8 gup_burn_dsp_isp(struct i2c_client *client) ++{ ++ s32 ret = 0; ++ u8 *fw_dsp_isp = NULL; ++ u8 retry = 0; ++ ++ dev_info(&client->dev, "[burn_dsp_isp]Begin burn dsp isp---->>"); ++ ++ /* step1:alloc memory */ ++ dev_dbg(&client->dev, "[burn_dsp_isp]step1:alloc memory"); ++ while (retry++ < 5) { ++ fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL); ++ if (fw_dsp_isp == NULL) { ++ continue; ++ } else { ++ dev_info(&client->dev, ++ "[burn_dsp_isp]Alloc %dk byte memory success.", ++ FW_DSP_ISP_LENGTH / 1024); ++ break; ++ } ++ } ++ if (retry >= 5) { ++ dev_err(&client->dev, "[burn_dsp_isp]Alloc memory fail,exit."); ++ return FAIL; ++ } ++ ++ /* step2:load dsp isp file data */ ++ dev_dbg(&client->dev, "[burn_dsp_isp]step2:load dsp isp file data"); ++ ret = gup_load_section_file(fw_dsp_isp, FW_DSP_ISP_LENGTH, ++ FW_DSP_ISP_LENGTH, SEEK_END); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_dsp_isp]load firmware dsp_isp fail."); ++ goto exit_burn_dsp_isp; ++ } ++ ++ /* step3:disable wdt,clear cache enable */ ++ dev_dbg(&client->dev, ++ "[burn_dsp_isp]step3:disable wdt,clear cache enable"); ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_dsp_isp]disable wdt fail."); ++ ret = FAIL; ++ goto exit_burn_dsp_isp; ++ } ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_dsp_isp]clear cache enable fail."); ++ ret = FAIL; ++ goto exit_burn_dsp_isp; ++ } ++ ++ /* step4:hold ss51 & dsp */ ++ dev_dbg(&client->dev, "[burn_dsp_isp]step4:hold ss51 & dsp"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_dsp_isp]hold ss51 & dsp fail."); ++ ret = FAIL; ++ goto exit_burn_dsp_isp; ++ } ++ ++ /* step5:set boot from sram */ ++ dev_dbg(&client->dev, "[burn_dsp_isp]step5:set boot from sram"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_dsp_isp]set boot from sram fail"); ++ ret = FAIL; ++ goto exit_burn_dsp_isp; ++ } ++ ++ /* step6:software reboot */ ++ dev_dbg(&client->dev, "[burn_dsp_isp]step6:software reboot"); ++ ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_dsp_isp]software reboot fail."); ++ ret = FAIL; ++ goto exit_burn_dsp_isp; ++ } ++ ++ /* step7:select bank2 */ ++ dev_dbg(&client->dev, "[burn_dsp_isp]step7:select bank2"); ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_dsp_isp]select bank2 fail"); ++ ret = FAIL; ++ goto exit_burn_dsp_isp; ++ } ++ ++ /* step8:enable accessing code */ ++ dev_dbg(&client->dev, "[burn_dsp_isp]step8:enable accessing code"); ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_dsp_isp]enable accessing code fail."); ++ ret = FAIL; ++ goto exit_burn_dsp_isp; ++ } ++ ++ /* step9:burn 4k dsp_isp */ ++ dev_dbg(&client->dev, "[burn_dsp_isp]step9:burn 4k dsp_isp"); ++ ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH); ++ if (FAIL == ret) { ++ dev_err(&client->dev, "[burn_dsp_isp]burn dsp_isp fail."); ++ goto exit_burn_dsp_isp; ++ } ++ ++ /* step10:set scramble */ ++ dev_dbg(&client->dev, "[burn_dsp_isp]step10:set scramble"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_dsp_isp]set scramble fail."); ++ ret = FAIL; ++ goto exit_burn_dsp_isp; ++ } ++ update_msg.fw_burned_len += FW_DSP_ISP_LENGTH; ++ dev_dbg(&client->dev, "[burn_dsp_isp]Burned length:%d", ++ update_msg.fw_burned_len); ++ ret = SUCCESS; ++ ++exit_burn_dsp_isp: ++ kfree(fw_dsp_isp); ++ ++ return ret; ++} ++ ++static u8 gup_burn_fw_ss51(struct i2c_client *client) ++{ ++ u8 *fw_ss51 = NULL; ++ u8 retry = 0; ++ s32 ret = 0; ++ ++ dev_info(&client->dev, "[burn_fw_ss51]Begin burn ss51 firmware---->>"); ++ ++ /* step1:alloc memory */ ++ dev_dbg(&client->dev, "[burn_fw_ss51]step1:alloc memory"); ++ while (retry++ < 5) { ++ fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); ++ if (fw_ss51 == NULL) { ++ continue; ++ } else { ++ dev_dbg(&client->dev, ++ "[burn_fw_ss51]Alloc %dk byte memory success.", ++ (FW_SECTION_LENGTH / 1024)); ++ break; ++ } ++ } ++ if (retry >= 5) { ++ dev_err(&client->dev, "[burn_fw_ss51]Alloc memory fail,exit."); ++ return FAIL; ++ } ++ ++ dev_info(&client->dev, "[burn_fw_ss51]Reset first 8K of ss51 to 0xFF."); ++ dev_dbg(&client->dev, "[burn_fw_ss51]step2: reset bank0 0xC000~0xD000"); ++ memset(fw_ss51, 0xFF, FW_SECTION_LENGTH); ++ ++ /* step3:clear control flag */ ++ dev_dbg(&client->dev, "[burn_fw_ss51]step3:clear control flag"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_ss51]clear control flag fail."); ++ ret = FAIL; ++ goto exit_burn_fw_ss51; ++ } ++ ++ /* step4:burn ss51 firmware section 1 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_ss51]step4:burn ss51 firmware section 1"); ++ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_ss51]burn ss51 firmware section 1 fail."); ++ goto exit_burn_fw_ss51; ++ } ++ ++ /* step5:load ss51 firmware section 2 file data */ ++ dev_dbg(&client->dev, ++ "[burn_fw_ss51]step5:load ss51 firmware section 2 file data"); ++ ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, ++ FW_SECTION_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_ss51]load ss51 firmware section 2 fail."); ++ goto exit_burn_fw_ss51; ++ } ++ ++ /* step6:burn ss51 firmware section 2 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_ss51]step6:burn ss51 firmware section 2"); ++ ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_ss51]burn ss51 firmware section 2 fail."); ++ goto exit_burn_fw_ss51; ++ } ++ ++ /* step7:load ss51 firmware section 3 file data */ ++ dev_dbg(&client->dev, ++ "[burn_fw_ss51]step7:load ss51 firmware section 3 file data"); ++ ret = gup_load_section_file(fw_ss51, 2 * FW_SECTION_LENGTH, ++ FW_SECTION_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_ss51]load ss51 firmware section 3 fail."); ++ goto exit_burn_fw_ss51; ++ } ++ ++ /* step8:burn ss51 firmware section 3 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_ss51]step8:burn ss51 firmware section 3"); ++ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_ss51]burn ss51 firmware section 3 fail."); ++ goto exit_burn_fw_ss51; ++ } ++ ++ /* step9:load ss51 firmware section 4 file data */ ++ dev_dbg(&client->dev, ++ "[burn_fw_ss51]step9:load ss51 firmware section 4 file data"); ++ ret = gup_load_section_file(fw_ss51, 3 * FW_SECTION_LENGTH, ++ FW_SECTION_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_ss51]load ss51 firmware section 4 fail."); ++ goto exit_burn_fw_ss51; ++ } ++ ++ /* step10:burn ss51 firmware section 4 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_ss51]step10:burn ss51 firmware section 4"); ++ ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_ss51]burn ss51 firmware section 4 fail."); ++ goto exit_burn_fw_ss51; ++ } ++ ++ update_msg.fw_burned_len += (FW_SECTION_LENGTH*4); ++ dev_dbg(&client->dev, "[burn_fw_ss51]Burned length:%d", ++ update_msg.fw_burned_len); ++ ret = SUCCESS; ++ ++exit_burn_fw_ss51: ++ kfree(fw_ss51); ++ return ret; ++} ++ ++static u8 gup_burn_fw_dsp(struct i2c_client *client) ++{ ++ s32 ret = 0; ++ u8 *fw_dsp = NULL; ++ u8 retry = 0; ++ u8 rd_buf[5]; ++ ++ dev_info(&client->dev, "[burn_fw_dsp]Begin burn dsp firmware---->>"); ++ /* step1:alloc memory */ ++ dev_dbg(&client->dev, "[burn_fw_dsp]step1:alloc memory"); ++ while (retry++ < 5) { ++ fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL); ++ if (fw_dsp == NULL) { ++ continue; ++ } else { ++ dev_dbg(&client->dev, ++ "[burn_fw_dsp]Alloc %dk byte memory success.", ++ FW_SECTION_LENGTH / 1024); ++ break; ++ } ++ } ++ if (retry >= 5) { ++ dev_err(&client->dev, "[burn_fw_dsp]Alloc memory fail,exit."); ++ return FAIL; ++ } ++ ++ /* step2:load firmware dsp */ ++ dev_dbg(&client->dev, "[burn_fw_dsp]step2:load firmware dsp"); ++ ret = gup_load_section_file(fw_dsp, 4 * FW_SECTION_LENGTH, ++ FW_DSP_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, "[burn_fw_dsp]load firmware dsp fail."); ++ goto exit_burn_fw_dsp; ++ } ++ ++ /* step3:select bank3 */ ++ dev_dbg(&client->dev, "[burn_fw_dsp]step3:select bank3"); ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_dsp]select bank3 fail."); ++ ret = FAIL; ++ goto exit_burn_fw_dsp; ++ } ++ ++ /* step4:hold ss51 & dsp */ ++ dev_dbg(&client->dev, "[burn_fw_dsp]step4:hold ss51 & dsp"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_dsp]hold ss51 & dsp fail."); ++ ret = FAIL; ++ goto exit_burn_fw_dsp; ++ } ++ ++ /* step5:set scramble */ ++ dev_dbg(&client->dev, "[burn_fw_dsp]step5:set scramble"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_dsp]set scramble fail."); ++ ret = FAIL; ++ goto exit_burn_fw_dsp; ++ } ++ ++ /* step6:release ss51 & dsp */ ++ dev_dbg(&client->dev, "[burn_fw_dsp]step6:release ss51 & dsp"); ++ ret = gup_set_ic_msg( ++ client, _rRW_MISCTL__SWRST_B0_, 0x04);/* 20121211 */ ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_dsp]release ss51 & dsp fail."); ++ ret = FAIL; ++ goto exit_burn_fw_dsp; ++ } ++ /* must delay */ ++ usleep_range(1000, 1100); ++ ++ /* step7:burn 4k dsp firmware */ ++ dev_dbg(&client->dev, "[burn_fw_dsp]step7:burn 4k dsp firmware"); ++ ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH); ++ if (FAIL == ret) { ++ dev_err(&client->dev, "[burn_fw_dsp]burn fw_section fail."); ++ goto exit_burn_fw_dsp; ++ } ++ ++ /* step8:send burn cmd to move data to flash from sram */ ++ dev_dbg(&client->dev, ++ "[burn_fw_dsp]step8:send burn cmd to move data to flash from sram"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_dsp]send burn cmd fail."); ++ goto exit_burn_fw_dsp; ++ } ++ dev_dbg(&client->dev, "[burn_fw_dsp]Wait for the burn is complete......"); ++ do { ++ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_dsp]Get burn state fail"); ++ goto exit_burn_fw_dsp; ++ } ++ usleep_range(10000, 11000); ++ /* dev_dbg(&client->dev, "[burn_fw_dsp]Get burn state:%d.", ++ rd_buf[GTP_ADDR_LENGTH]); */ ++ } while (rd_buf[GTP_ADDR_LENGTH]); ++ ++ /* step9:recall check 4k dsp firmware */ ++ dev_dbg(&client->dev, ++ "[burn_fw_dsp]step9:recall check 4k dsp firmware"); ++ ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_dsp]recall check 4k dsp firmware fail."); ++ goto exit_burn_fw_dsp; ++ } ++ ++ update_msg.fw_burned_len += FW_DSP_LENGTH; ++ dev_dbg(&client->dev, "[burn_fw_dsp]Burned length:%d", ++ update_msg.fw_burned_len); ++ ret = SUCCESS; ++ ++exit_burn_fw_dsp: ++ kfree(fw_dsp); ++ ++ return ret; ++} ++ ++static u8 gup_burn_fw_boot(struct i2c_client *client) ++{ ++ s32 ret = 0; ++ u8 *fw_boot = NULL; ++ u8 retry = 0; ++ u8 rd_buf[5]; ++ ++ dev_info(&client->dev, ++ "[burn_fw_boot]Begin burn bootloader firmware---->>"); ++ ++ /* step1:Alloc memory */ ++ dev_dbg(&client->dev, "[burn_fw_boot]step1:Alloc memory"); ++ while (retry++ < 5) { ++ fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL); ++ if (fw_boot == NULL) { ++ continue; ++ } else { ++ dev_dbg(&client->dev, ++ "[burn_fw_boot]Alloc %dk byte memory success.", ++ FW_BOOT_LENGTH / 1024); ++ break; ++ } ++ } ++ if (retry >= 5) { ++ dev_err(&client->dev, "[burn_fw_boot]Alloc memory fail,exit."); ++ return FAIL; ++ } ++ ++ /* step2:load firmware bootloader */ ++ dev_dbg(&client->dev, "[burn_fw_boot]step2:load firmware bootloader"); ++ ret = gup_load_section_file(fw_boot, ++ 4 * FW_SECTION_LENGTH + FW_DSP_LENGTH, ++ FW_BOOT_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_boot]load firmware bootcode fail."); ++ goto exit_burn_fw_boot; ++ } ++ ++ /* step3:hold ss51 & dsp */ ++ dev_dbg(&client->dev, "[burn_fw_boot]step3:hold ss51 & dsp"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_boot]hold ss51 & dsp fail."); ++ ret = FAIL; ++ goto exit_burn_fw_boot; ++ } ++ ++ /* step4:set scramble */ ++ dev_dbg(&client->dev, "[burn_fw_boot]step4:set scramble"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_boot]set scramble fail."); ++ ret = FAIL; ++ goto exit_burn_fw_boot; ++ } ++ ++ /* step5:hold ss51 & release dsp */ ++ dev_dbg(&client->dev, "[burn_fw_boot]step5:hold ss51 & release dsp"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); ++ /* 20121211 */ ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_boot]release ss51 & dsp fail"); ++ ret = FAIL; ++ goto exit_burn_fw_boot; ++ } ++ /* must delay */ ++ usleep_range(1000, 1100); ++ ++ /* step6:select bank3 */ ++ dev_dbg(&client->dev, "[burn_fw_boot]step6:select bank3"); ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_boot]select bank3 fail."); ++ ret = FAIL; ++ goto exit_burn_fw_boot; ++ } ++ ++ /* step6:burn 2k bootloader firmware */ ++ dev_dbg(&client->dev, ++ "[burn_fw_boot]step6:burn 2k bootloader firmware"); ++ ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH); ++ if (FAIL == ret) { ++ dev_err(&client->dev, "[burn_fw_boot]burn fw_boot fail."); ++ goto exit_burn_fw_boot; ++ } ++ ++ /* step7:send burn cmd to move data to flash from sram */ ++ dev_dbg(&client->dev, ++ "[burn_fw_boot]step7:send burn cmd to move data to flash from sram"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_boot]send burn cmd fail."); ++ goto exit_burn_fw_boot; ++ } ++ dev_dbg(&client->dev, ++ "[burn_fw_boot]Wait for the burn is complete......"); ++ do { ++ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_boot]Get burn state fail"); ++ goto exit_burn_fw_boot; ++ } ++ usleep_range(10000, 11000); ++ /* dev_dbg(&client->dev, "[burn_fw_boot]Get burn state:%d.", ++ * rd_buf[GTP_ADDR_LENGTH]); ++ */ ++ } while (rd_buf[GTP_ADDR_LENGTH]); ++ ++ /* step8:recall check 2k bootloader firmware */ ++ dev_dbg(&client->dev, ++ "[burn_fw_boot]step8:recall check 2k bootloader firmware"); ++ ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_boot]recall check 2k bootcode firmware fail"); ++ goto exit_burn_fw_boot; ++ } ++ ++ update_msg.fw_burned_len += FW_BOOT_LENGTH; ++ dev_dbg(&client->dev, "[burn_fw_boot]Burned length:%d", ++ update_msg.fw_burned_len); ++ ret = SUCCESS; ++ ++exit_burn_fw_boot: ++ kfree(fw_boot); ++ ++ return ret; ++} ++static u8 gup_burn_fw_boot_isp(struct i2c_client *client) ++{ ++ s32 ret = 0; ++ u8 *fw_boot_isp = NULL; ++ u8 retry = 0; ++ u8 rd_buf[5]; ++ ++ if (update_msg.fw_burned_len >= update_msg.fw_total_len) { ++ dev_dbg(&client->dev, "No need to upgrade the boot_isp code!"); ++ return SUCCESS; ++ } ++ dev_info(&client->dev, ++ "[burn_fw_boot_isp]Begin burn boot_isp firmware---->>"); ++ ++ /* step1:Alloc memory */ ++ dev_dbg(&client->dev, "[burn_fw_boot_isp]step1:Alloc memory"); ++ while (retry++ < 5) { ++ fw_boot_isp = kzalloc(FW_BOOT_ISP_LENGTH, GFP_KERNEL); ++ if (fw_boot_isp == NULL) { ++ continue; ++ } else { ++ dev_dbg(&client->dev, ++ "[burn_fw_boot_isp]Alloc %dk byte memory success.", ++ (FW_BOOT_ISP_LENGTH/1024)); ++ break; ++ } ++ } ++ if (retry >= 5) { ++ dev_err(&client->dev, ++ "[burn_fw_boot_isp]Alloc memory fail,exit."); ++ return FAIL; ++ } ++ ++ /* step2:load firmware bootloader */ ++ dev_dbg(&client->dev, ++ "[burn_fw_boot_isp]step2:load firmware bootloader isp"); ++ /* ret = gup_load_section_file(fw_boot_isp, ++ * (4*FW_SECTION_LENGTH+FW_DSP_LENGTH + ++ * FW_BOOT_LENGTH+FW_DSP_ISP_LENGTH), FW_BOOT_ISP_LENGTH, SEEK_SET); ++ */ ++ ret = gup_load_section_file(fw_boot_isp, (update_msg.fw_burned_len - FW_DSP_ISP_LENGTH), ++ FW_BOOT_ISP_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_boot_isp]load firmware boot_isp fail."); ++ goto exit_burn_fw_boot_isp; ++ } ++ ++ /* step3:hold ss51 & dsp */ ++ dev_dbg(&client->dev, "[burn_fw_boot_isp]step3:hold ss51 & dsp"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_boot_isp]hold ss51 & dsp fail"); ++ ret = FAIL; ++ goto exit_burn_fw_boot_isp; ++ } ++ ++ /* step4:set scramble */ ++ dev_dbg(&client->dev, "[burn_fw_boot_isp]step4:set scramble"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_boot_isp]set scramble fail."); ++ ret = FAIL; ++ goto exit_burn_fw_boot_isp; ++ } ++ ++ ++ /* step5:hold ss51 & release dsp */ ++ dev_dbg(&client->dev, ++ "[burn_fw_boot_isp]step5:hold ss51 & release dsp"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); ++ /* 20121211 */ ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_boot_isp]release ss51 & dsp fail."); ++ ret = FAIL; ++ goto exit_burn_fw_boot_isp; ++ } ++ /* must delay */ ++ usleep_range(1000, 2000); ++ ++ /* step6:select bank3 */ ++ dev_dbg(&client->dev, "[burn_fw_boot_isp]step6:select bank3"); ++ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_boot_isp]select bank3 fail."); ++ ret = FAIL; ++ goto exit_burn_fw_boot_isp; ++ } ++ ++ /* step7:burn 2k bootload_isp firmware */ ++ dev_dbg(&client->dev, ++ "[burn_fw_boot_isp]step7:burn 2k bootloader firmware"); ++ ret = gup_burn_proc(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_boot_isp]burn fw_section fail."); ++ goto exit_burn_fw_boot_isp; ++ } ++ ++ /* step7:send burn cmd to move data to flash from sram */ ++ dev_dbg(&client->dev, ++ "[burn_fw_boot_isp]step8:send burn cmd to move data to flash from sram"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x07); ++ if (ret <= 0) { ++ dev_err(&client->dev, "[burn_fw_boot_isp]send burn cmd fail."); ++ goto exit_burn_fw_boot_isp; ++ } ++ dev_dbg(&client->dev, ++ "[burn_fw_boot_isp]Wait for the burn is complete......"); ++ do { ++ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_boot_isp]Get burn state fail"); ++ goto exit_burn_fw_boot_isp; ++ } ++ usleep_range(10000, 11000); ++ /* dev_dbg(&client->dev, "[burn_fw_boot_isp]Get ++ * burn state:%d.", rd_buf[GTP_ADDR_LENGTH]); ++ */ ++ } while (rd_buf[GTP_ADDR_LENGTH]); ++ ++ /* step8:recall check 2k bootload_isp firmware */ ++ dev_dbg(&client->dev, ++ "[burn_fw_boot_isp]step9:recall check 2k bootloader firmware"); ++ ret = gup_recall_check(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_boot_isp]recall check 2k bootcode_isp firmware fail."); ++ goto exit_burn_fw_boot_isp; ++ } ++ ++ update_msg.fw_burned_len += FW_BOOT_ISP_LENGTH; ++ dev_dbg(&client->dev, ++ "[burn_fw_boot_isp]Burned length:%d", update_msg.fw_burned_len); ++ ret = SUCCESS; ++ ++exit_burn_fw_boot_isp: ++ kfree(fw_boot_isp); ++ ++ return ret; ++} ++ ++static u8 gup_burn_fw_link(struct i2c_client *client) ++{ ++ u8 *fw_link = NULL; ++ u8 retry = 0; ++ s32 ret = 0; ++ u32 offset; ++ ++ if (update_msg.fw_burned_len >= update_msg.fw_total_len) { ++ dev_dbg(&client->dev, "No need to upgrade the link code!"); ++ return SUCCESS; ++ } ++ dev_info(&client->dev, "[burn_fw_link]Begin burn link firmware---->>"); ++ ++ /* step1:Alloc memory */ ++ dev_dbg(&client->dev, "[burn_fw_link]step1:Alloc memory"); ++ while (retry++ < 5) { ++ fw_link = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); ++ if (fw_link == NULL) { ++ continue; ++ } else { ++ dev_dbg(&client->dev, ++ "[burn_fw_link]Alloc %dk byte memory success.", ++ (FW_SECTION_LENGTH/1024)); ++ break; ++ } ++ } ++ if (retry >= 5) { ++ dev_err(&client->dev, "[burn_fw_link]Alloc memory fail,exit."); ++ return FAIL; ++ } ++ ++ /* step2:load firmware link section 1 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_link]step2:load firmware link section 1"); ++ offset = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH; ++ ret = gup_load_section_file(fw_link, offset, FW_SECTION_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_link]load firmware link section 1 fail."); ++ goto exit_burn_fw_link; ++ } ++ ++ /* step3:burn link firmware section 1 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_link]step3:burn link firmware section 1"); ++ ret = gup_burn_fw_gwake_section( ++ client, fw_link, 0x9000, FW_SECTION_LENGTH, 0x38); ++ ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_link]burn link firmware section 1 fail."); ++ goto exit_burn_fw_link; ++ } ++ ++ /* step4:load link firmware section 2 file data */ ++ dev_dbg(&client->dev, ++ "[burn_fw_link]step4:load link firmware section 2 file data"); ++ offset += FW_SECTION_LENGTH; ++ ret = gup_load_section_file(fw_link, offset, ++ FW_GLINK_LENGTH - FW_SECTION_LENGTH, SEEK_SET); ++ ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_link]load link firmware section 2 fail."); ++ goto exit_burn_fw_link; ++ } ++ ++ /* step5:burn link firmware section 2 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_link]step4:burn link firmware section 2"); ++ ret = gup_burn_fw_gwake_section(client, ++ fw_link, 0x9000, FW_GLINK_LENGTH - FW_SECTION_LENGTH, 0x39); ++ ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_link]burn link firmware section 2 fail."); ++ goto exit_burn_fw_link; ++ } ++ ++ update_msg.fw_burned_len += FW_GLINK_LENGTH; ++ dev_dbg(&client->dev, ++ "[burn_fw_link]Burned length:%d", update_msg.fw_burned_len); ++ ret = SUCCESS; ++ ++exit_burn_fw_link: ++ kfree(fw_link); ++ ++ return ret; ++} ++ ++static u8 gup_burn_fw_gwake_section(struct i2c_client *client, ++ u8 *fw_section, u16 start_addr, u32 len, u8 bank_cmd) ++{ ++ s32 ret = 0; ++ u8 rd_buf[5]; ++ ++ /* step1:hold ss51 & dsp */ ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_app_section]hold ss51 & dsp fail."); ++ return FAIL; ++ } ++ ++ /* step2:set scramble */ ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_app_section]set scramble fail."); ++ return FAIL; ++ } ++ ++ /* step3:hold ss51 & release dsp */ ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_app_section]hold ss51 & release dsp fail."); ++ return FAIL; ++ } ++ /* must delay */ ++ usleep_range(1000, 2000); ++ ++ /* step4:select bank */ ++ ret = gup_set_ic_msg( ++ client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_section]select bank %d fail.", ++ (bank_cmd >> 4)&0x0F); ++ return FAIL; ++ } ++ ++ /* step5:burn fw section */ ++ ret = gup_burn_proc(client, fw_section, start_addr, len); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_app_section]burn fw_section fail."); ++ return FAIL; ++ } ++ ++ /* step6:send burn cmd to move data to flash from sram */ ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0F); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_app_section]send burn cmd fail."); ++ return FAIL; ++ } ++ dev_dbg(&client->dev, ++ "[burn_fw_section]Wait for the burn is complete......"); ++ do { ++ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_app_section]Get burn state fail"); ++ return FAIL; ++ } ++ usleep_range(10000, 11000); ++ /* dev_dbg(&client->dev, "[burn_fw_app_section]Get burn state:%d." ++ * rd_buf[GTP_ADDR_LENGTH]); ++ */ ++ } while (rd_buf[GTP_ADDR_LENGTH]); ++ ++ /* step7:recall fw section */ ++ ret = gup_recall_check(client, fw_section, start_addr, len); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_app_section]recall check %dk firmware fail.", ++ len/1024); ++ return FAIL; ++ } ++ ++ return SUCCESS; ++} ++ ++static u8 gup_burn_fw_gwake(struct i2c_client *client) ++{ ++ u8 *fw_gwake = NULL; ++ u8 retry = 0; ++ s32 ret = 0; ++ u16 start_index = 4*FW_SECTION_LENGTH + ++ FW_DSP_LENGTH + FW_BOOT_LENGTH + ++ FW_BOOT_ISP_LENGTH + FW_GLINK_LENGTH;/* 32 + 4 + 2 + 4 = 42K */ ++ /* u16 start_index; */ ++ ++ if (start_index >= update_msg.fw_total_len) { ++ dev_dbg(&client->dev, "No need to upgrade the gwake code!"); ++ return SUCCESS; ++ } ++ /* start_index = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH; */ ++ dev_info(&client->dev, ++ "[burn_fw_gwake]Begin burn gwake firmware---->>"); ++ ++ /* step1:alloc memory */ ++ dev_dbg(&client->dev, "[burn_fw_gwake]step1:alloc memory"); ++ while (retry++ < 5) { ++ fw_gwake = ++ kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); ++ if (fw_gwake == NULL) { ++ continue; ++ } else { ++ dev_dbg(&client->dev, ++ "[burn_fw_gwake]Alloc %dk byte memory success.", ++ (FW_SECTION_LENGTH/1024)); ++ break; ++ } ++ } ++ if (retry >= 5) { ++ dev_err(&client->dev, "[burn_fw_gwake]Alloc memory fail,exit."); ++ return FAIL; ++ } ++ ++ /* clear control flag */ ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_finish]clear control flag fail."); ++ goto exit_burn_fw_gwake; ++ } ++ ++ /* step2:load app_code firmware section 1 file data */ ++ dev_dbg(&client->dev, ++ "[burn_fw_gwake]step2:load app_code firmware section 1 file data"); ++ ret = gup_load_section_file(fw_gwake, start_index, ++ FW_SECTION_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_gwake]load app_code firmware section 1 fail."); ++ goto exit_burn_fw_gwake; ++ } ++ ++ /* step3:burn app_code firmware section 1 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_gwake]step3:burn app_code firmware section 1"); ++ ret = gup_burn_fw_gwake_section(client, ++ fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3A); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_gwake]burn app_code firmware section 1 fail."); ++ goto exit_burn_fw_gwake; ++ } ++ ++ /* step5:load app_code firmware section 2 file data */ ++ dev_dbg(&client->dev, ++ "[burn_fw_gwake]step5:load app_code firmware section 2 file data"); ++ ret = gup_load_section_file(fw_gwake, start_index+FW_SECTION_LENGTH, ++ FW_SECTION_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_gwake]load app_code firmware section 2 fail."); ++ goto exit_burn_fw_gwake; ++ } ++ ++ /* step6:burn app_code firmware section 2 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_gwake]step6:burn app_code firmware section 2"); ++ ret = gup_burn_fw_gwake_section(client, ++ fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3B); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_gwake]burn app_code firmware section 2 fail."); ++ goto exit_burn_fw_gwake; ++ } ++ ++ /* step7:load app_code firmware section 3 file data */ ++ dev_dbg(&client->dev, ++ "[burn_fw_gwake]step7:load app_code firmware section 3 file data"); ++ ret = gup_load_section_file(fw_gwake, ++ start_index + 2 * FW_SECTION_LENGTH, ++ FW_SECTION_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_gwake]load app_code firmware section 3 fail."); ++ goto exit_burn_fw_gwake; ++ } ++ ++ /* step8:burn app_code firmware section 3 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_gwake]step8:burn app_code firmware section 3"); ++ ret = gup_burn_fw_gwake_section( ++ client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3C); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_gwake]burn app_code firmware section 3 fail."); ++ goto exit_burn_fw_gwake; ++ } ++ ++ /* step9:load app_code firmware section 4 file data */ ++ dev_dbg(&client->dev, ++ "[burn_fw_gwake]step9:load app_code firmware section 4 file data"); ++ ret = gup_load_section_file(fw_gwake, ++ start_index + 3 * FW_SECTION_LENGTH, ++ FW_SECTION_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_gwake]load app_code firmware section 4 fail."); ++ goto exit_burn_fw_gwake; ++ } ++ ++ /* step10:burn app_code firmware section 4 */ ++ dev_dbg(&client->dev, ++ "[burn_fw_gwake]step10:burn app_code firmware section 4"); ++ ret = gup_burn_fw_gwake_section( ++ client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3D); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_gwake]burn app_code firmware section 4 fail."); ++ goto exit_burn_fw_gwake; ++ } ++ ++ /* update_msg.fw_burned_len += FW_GWAKE_LENGTH; */ ++ dev_dbg(&client->dev, ++ "[burn_fw_gwake]Burned length:%d", update_msg.fw_burned_len); ++ ret = SUCCESS; ++ ++exit_burn_fw_gwake: ++ kfree(fw_gwake); ++ ++ return ret; ++} ++ ++static u8 gup_burn_fw_finish(struct i2c_client *client) ++{ ++ u8 *fw_ss51 = NULL; ++ u8 retry = 0; ++ s32 ret = 0; ++ ++ dev_info(&client->dev, ++ "[burn_fw_finish]burn first 8K of ss51 and finish update."); ++ /* step1:alloc memory */ ++ dev_dbg(&client->dev, "[burn_fw_finish]step1:alloc memory"); ++ while (retry++ < 5) { ++ fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); ++ if (fw_ss51 == NULL) { ++ continue; ++ } else { ++ dev_dbg(&client->dev, ++ "[burn_fw_finish]Alloc %dk byte memory success.", ++ (FW_SECTION_LENGTH/1024)); ++ break; ++ } ++ } ++ if (retry >= 5) { ++ dev_err(&client->dev, ++ "[burn_fw_finish]Alloc memory fail,exit."); ++ return FAIL; ++ } ++ ++ dev_dbg(&client->dev, "[burn_fw_finish]step2: burn ss51 first 8K."); ++ ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH, SEEK_SET); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_finish]load ss51 firmware section 1 fail."); ++ goto exit_burn_fw_finish; ++ } ++ ++ dev_dbg(&client->dev, "[burn_fw_finish]step3:clear control flag"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_finish]clear control flag fail."); ++ goto exit_burn_fw_finish; ++ } ++ ++ dev_dbg(&client->dev, ++ "[burn_fw_finish]step4:burn ss51 firmware section 1"); ++ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); ++ if (FAIL == ret) { ++ dev_err(&client->dev, ++ "[burn_fw_finish]burn ss51 firmware section 1 fail."); ++ goto exit_burn_fw_finish; ++ } ++ ++ /* step11:enable download DSP code */ ++ dev_dbg(&client->dev, ++ "[burn_fw_finish]step5:enable download DSP code "); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_finish]enable download DSP code fail."); ++ goto exit_burn_fw_finish; ++ } ++ ++ /* step12:release ss51 & hold dsp */ ++ dev_dbg(&client->dev, "[burn_fw_finish]step6:release ss51 & hold dsp"); ++ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08); ++ if (ret <= 0) { ++ dev_err(&client->dev, ++ "[burn_fw_finish]release ss51 & hold dsp fail."); ++ goto exit_burn_fw_finish; ++ } ++ ++ if (fw_ss51 != NULL) ++ kfree(fw_ss51); ++ return SUCCESS; ++ ++exit_burn_fw_finish: ++ if (fw_ss51 != NULL) ++ kfree(fw_ss51); ++ ++ return FAIL; ++} ++ ++/* return 0 can update, else no update condition */ ++static int gup_update_condition_check(struct goodix_ts_data *ts) ++{ ++ if (test_bit(SLEEP_MODE, &ts->flags)) { ++ dev_info(&ts->client->dev, "Update abort, tp in sleep mode\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++s32 gup_update_proc(void *dir) ++{ ++ s32 ret = 0; ++ s32 update_ret = FAIL; ++ u8 retry = 0; ++ struct st_fw_head fw_head; ++ struct goodix_ts_data *ts = NULL; ++ ++ ts = i2c_get_clientdata(i2c_connect_client); ++ ++ dev_dbg(&ts->client->dev, "[update_proc]Begin update ......\n"); ++ ++ show_len = 1; ++ total_len = 100; ++ ++ ret = gup_update_condition_check(ts); ++ if (ret) { ++ dev_warn(&ts->client->dev, "Update start failed\n"); ++ return FAIL; ++ } ++ ++ if (test_and_set_bit(FW_UPDATE_RUNNING, &ts->flags)) { ++ dev_warn(&ts->client->dev, "FW update may already running\n"); ++ return FAIL; ++ } ++ ++ ret = gup_get_update_file(i2c_connect_client, &fw_head, (u8 *)dir); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "Failed get valied firmware data\n"); ++ clear_bit(FW_UPDATE_RUNNING, &ts->flags); ++ return FAIL; ++ } ++ ++ gtp_work_control_enable(ts, false); ++ gtp_esd_off(ts); ++ ++ ret = gup_get_ic_fw_msg(i2c_connect_client); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, "[update_proc]get ic message fail."); ++ goto file_fail; ++ } ++ ++ if (ts->force_update || dir) { ++ dev_dbg(&ts->client->dev, "Enter force update."); ++ } else { ++ ret = gup_enter_update_judge(i2c_connect_client, &fw_head); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "[update_proc]Doesn't meet update condition\n"); ++ goto file_fail; ++ } ++ } ++ ++ ret = gup_enter_update_mode(ts->client); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "[update_proc]enter update mode fail."); ++ goto update_fail; ++ } ++ ++ while (retry++ < 5) { ++ show_len = 10; ++ total_len = 100; ++ update_msg.fw_burned_len = 0; ++ ret = gup_burn_dsp_isp(i2c_connect_client); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "[update_proc]burn dsp isp fail."); ++ continue; ++ } ++ ++ show_len = 20; ++ ret = gup_burn_fw_gwake(i2c_connect_client); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "[update_proc]burn app_code firmware fail."); ++ continue; ++ } ++ ++ show_len = 30; ++ ret = gup_burn_fw_ss51(i2c_connect_client); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "[update_proc]burn ss51 firmware fail."); ++ continue; ++ } ++ ++ show_len = 40; ++ ret = gup_burn_fw_dsp(i2c_connect_client); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "[update_proc]burn dsp firmware fail."); ++ continue; ++ } ++ ++ show_len = 50; ++ ret = gup_burn_fw_boot(i2c_connect_client); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "[update_proc]burn bootloader firmware fail."); ++ continue; ++ } ++ show_len = 60; ++ ++ ret = gup_burn_fw_boot_isp(i2c_connect_client); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "[update_proc]burn boot_isp firmware fail."); ++ continue; ++ } ++ ++ show_len = 70; ++ ret = gup_burn_fw_link(i2c_connect_client); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "[update_proc]burn link firmware fail."); ++ continue; ++ } ++ ++ show_len = 80; ++ ret = gup_burn_fw_finish(i2c_connect_client); ++ if (FAIL == ret) { ++ dev_err(&ts->client->dev, ++ "[update_proc]burn finish fail."); ++ continue; ++ } ++ show_len = 90; ++ dev_info(&ts->client->dev, "[update_proc]UPDATE SUCCESS."); ++ retry = 0; ++ break; ++ } ++ ++ if (retry >= 5) { ++ dev_err(&ts->client->dev, ++ "[update_proc]retry timeout,UPDATE FAIL."); ++ update_ret = FAIL; ++ } else { ++ update_ret = SUCCESS; ++ } ++ ++update_fail: ++ dev_dbg(&ts->client->dev, "[update_proc]leave update mode."); ++ gup_leave_update_mode(i2c_connect_client); ++ ++ msleep(GTP_100_DLY_MS); ++ ++ if (SUCCESS == update_ret) { ++ dev_info(&ts->client->dev, ++ "firmware error auto update, resent config!\n"); ++ gup_init_panel(ts); ++ } ++ gtp_get_fw_info(ts->client, &ts->fw_info); ++ ++file_fail: ++ ++ update_msg.fw_data = NULL; ++ update_msg.fw_total_len = 0; ++ release_firmware(update_msg.fw); ++ ++ clear_bit(FW_UPDATE_RUNNING, &ts->flags); ++ gtp_work_control_enable(ts, true); ++ gtp_esd_on(ts); ++ total_len = 100; ++ ts->force_update = false; ++ if (SUCCESS == update_ret) { ++ show_len = 100; ++ clear_bit(FW_ERROR, &ts->flags); ++ return SUCCESS; ++ } else { ++ show_len = 200; ++ return FAIL; ++ } ++} ++ ++u8 gup_init_update_proc(struct goodix_ts_data *ts) ++{ ++ struct task_struct *thread = NULL; ++ ++ dev_info(&ts->client->dev, "Ready to run update thread."); ++ ++ thread = kthread_run(gup_update_proc, ++ (void *)NULL, "guitar_update"); ++ ++ if (IS_ERR(thread)) { ++ dev_err(&ts->client->dev, ++ "Failed to create update thread.\n"); ++ return -EPERM; ++ } ++ ++ return 0; ++} +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update1/hyn_cst3xx_0729_update1ok.c b/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update1/hyn_cst3xx_0729_update1ok.c +new file mode 100644 +index 000000000..84b31238f +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update1/hyn_cst3xx_0729_update1ok.c +@@ -0,0 +1,1602 @@ ++/* ++ * cst3xx Touchscreen Controller Driver ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "hyn_cst3xx.h" ++#include "hyn_cst3xx_RS659_fw.h" ++#include ++ ++#define HYN_DEBUG_EN 1 ++ ++struct st1615_ts_finger { ++ u16 x; ++ u16 y; ++ u8 t; ++ bool is_valid; ++}; ++ ++ ++static int cst3xx_into_program_mode(struct i2c_client * client); ++static int cst3xx_erase_program_area(struct i2c_client * client); ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms); ++static int cst3xx_write_program_data(struct i2c_client * client,const unsigned char *pdata); ++ ++static int cst3xx_check_checksum(struct i2c_client * client); ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client); ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata); ++ ++static int cst3xx_firmware_info(struct i2c_client * client); ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict); ++ ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata); ++ ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_test(struct i2c_client *client); ++static void cst3xx_reset(struct cst3xx_ts_data *ts) ; ++extern void close_vcc3v3Power(void); ++extern void open_vcc3v3Power(void); ++ ++static unsigned char *pcst3xx_update_firmware = (unsigned char *)cst3_fw ; //the updating firmware ++static unsigned int g_cst3xx_ic_version = 0; ++static unsigned int g_cst3xx_ic_checksum = 0; ++static unsigned int g_cst3xx_ic_checkcode =0; ++static unsigned int g_cst3xx_ic_project_id = 0; ++static unsigned int g_cst3xx_ic_type = 0; ++ ++static unsigned char report_flag = 0; ++static unsigned int x_temp_pos = 0; ++static unsigned int y_temp_pos = 0; ++ ++#define HYN_DRAW_POINT ++ ++//#define USE_ANALOG_I2C 1 //i2c analog -->defconfig i2c. ++#define USE_HIGHEST_I2CA 1// x1000 highest i2c ++//#define USE_LOWEST_I2CA 1 // x1000 lowest i2c ++#define HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++//#define HYN_UPDATE_FIRMWARE_ENABLE ++ ++#pragma pack(1) ++typedef struct ++{ ++ u16 pid; //product id // ++ u16 vid; //version id // ++} st_tpd_info; ++#pragma pack() ++ ++st_tpd_info tpd_info; ++ ++#define CST3XX_BIN_SIZE (24*1024 + 24) ++//#define CST3XX_MAX_X 340 ++#define CST3XX_MAX_X 480 ++#define CST3XX_MAX_Y 800 ++#define ERROR_TOUCH 1 ++ ++static void cst3xx_ts_power(struct cst3xx_ts_data *ts, bool poweron) ++{ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) ++ gpio_direction_output(ts->pdata->reset_gpio, poweron); ++} ++ ++static int cst3xx_into_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x01; ++ buf[2] = 0xAA; //set cmd to enter program mode ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(2); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; //check whether into program mode ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++static int cst3xx_erase_program_area(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; ++ buf[2] = 0x00; //set cmd to erase main area ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(5); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x03; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++ ++ ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms) ++{ ++ ++ unsigned char buf[4]; ++ buf[0] = 0xD1; ++ buf[1] = 0x0E; ++ cst3xx_i2c_write(ts->client, buf, 2); ++/* ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(2); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++*/ ++ mdelay(ms); ++} ++ ++ ++static int cst3xx_write_program_data(struct i2c_client * client, ++ const unsigned char *pdata) ++{ ++ int i, ret; ++ unsigned char *i2c_buf; ++ unsigned short eep_addr; ++ int total_kbyte; ++ ++ unsigned char temp_buf[8]; ++ unsigned short iic_addr; ++ int j; ++ ++ ++ i2c_buf = kmalloc(sizeof(unsigned char)*(1024 + 2), GFP_KERNEL); ++ if (i2c_buf == NULL) ++ return -1; ++ ++ //make sure fwbin len is N*1K ++ //total_kbyte = len / 1024; ++ total_kbyte = 24; ++ for (i=0; i>8; ++ ret = cst3xx_i2c_write(client, i2c_buf, 4); ++ if (ret < 0) ++ goto error_out; ++ ++ memcpy(i2c_buf, pdata + eep_addr, 1024); ++ for(j=0; j<256; j++) { ++ iic_addr = (j<<2); ++ temp_buf[0] = (iic_addr+0xA018)>>8; ++ temp_buf[1] = (iic_addr+0xA018)&0xFF; ++ temp_buf[2] = i2c_buf[iic_addr+0]; ++ temp_buf[3] = i2c_buf[iic_addr+1]; ++ temp_buf[4] = i2c_buf[iic_addr+2]; ++ temp_buf[5] = i2c_buf[iic_addr+3]; ++ ret = cst3xx_i2c_write(client, temp_buf, 6); ++ if (ret < 0) ++ goto error_out; ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x04; ++ i2c_buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(60); ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x05; ++ ret = cst3xx_i2c_read_register(client, i2c_buf, 1); ++ if (ret < 0) ++ goto error_out; ++ ++ if (i2c_buf[0] != 0x55) ++ goto error_out; ++ ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x03; ++ i2c_buf[2] = 0x00; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(8); ++ ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ ++ return 0; ++ ++error_out: ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ return -1; ++} ++ ++ ++static int cst3xx_check_checksum(struct i2c_client * client) ++{ ++ int ret; ++ int i; ++ unsigned int checksum; ++ unsigned int bin_checksum; ++ unsigned char buf[4]; ++ const unsigned char *pData; ++ ++ for(i=0; i<5; i++) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if(ret < 0) ++ { ++ mdelay(2); ++ continue; ++ } ++ ++ if(buf[0]!=0) ++ break; ++ else ++ mdelay(2); ++ } ++ mdelay(2); ++ ++ ++ if(buf[0]==0x01) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ ++ if(ret < 0) return -1; ++ ++ // read chip checksum ++ checksum = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); ++ ++ pData=(unsigned char *)pcst3xx_update_firmware +24*1024+16; //7*1024 +512 ++ bin_checksum = pData[0] + (pData[1]<<8) + (pData[2]<<16) + (pData[3]<<24); ++ ++ printk(" hyn the updated ic checksum is :0x%x. the updating firmware checksum is:0x%x------\n", checksum, bin_checksum); ++ ++ if(checksum!=bin_checksum) ++ { ++ printk(" cst3xx hyn check sum error.\n"); ++ return -1; ++ ++ } ++ ++ } ++ else ++ { ++ printk(" cst3xx hyn No checksum.\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x06; ++ buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) ++ return -1; ++ ++ mdelay(10); //wait for restart ++ ++ ++ return 0; ++} ++ ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ ++ printk(" cst3xx----------upgrade cst3xx begain------------\n"); ++ disable_irq(ts->irq); ++ mdelay(20); ++START_FLOW: ++ ++#ifdef HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++ close_vcc3v3Power(); ++ mdelay(20); ++ open_vcc3v3Power(); ++ mdelay(5+retry); ++#else ++ cst3xx_reset_ic(ts,5+retry); ++#endif ++ ret = cst3xx_into_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]into program mode failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_erase_program_area(ts->client); ++ if (ret) { ++ printk(" cst3xx[cst3xx]erase main area failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_write_program_data(ts->client, pdata); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]write program data into cstxxx failed.\n"); ++ goto err_out; ++ } ++ ++ ret =cst3xx_check_checksum(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] after write program cst3xx_check_checksum failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_exit_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]exit program mode failed.\n"); ++ goto err_out; ++ } ++ ++ cst3xx_reset_ic(ts,20); ++ ++ printk(" cst3xx hyn----------cst3xx_update_firmware end------------\n"); ++ ++ enable_irq(ts->irq); ++ ++ return 0; ++ ++err_out: ++ if (retry < 30) { ++ retry++; ++ mdelay(20); ++ goto START_FLOW; ++ } ++ else { ++ enable_irq(ts->irq); ++ return -1; ++ } ++} ++ ++ ++ ++ ++/******************************************************* ++Function: ++ get firmware version, ic type... ++Input: ++ client: i2c client ++Output: ++ success: 0 ++ fail: -1 ++*******************************************************/ ++static int cst3xx_firmware_info(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[28]; ++// unsigned short ic_type, project_id; ++ ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x01; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ ++ mdelay(40); ++ ++ buf[0] = 0xD1; ++ buf[1] = 0xFC; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ ++ //0xCACA0000 ++ g_cst3xx_ic_checkcode = buf[3]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[2]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[1]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip g_cst3xx_ic_checkcode:0x%x.\r\n",g_cst3xx_ic_checkcode); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x04; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ g_cst3xx_ic_type = buf[3]; ++ g_cst3xx_ic_type <<= 8; ++ g_cst3xx_ic_type |= buf[2]; ++ ++ ++ g_cst3xx_ic_project_id = buf[1]; ++ g_cst3xx_ic_project_id <<= 8; ++ g_cst3xx_ic_project_id |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip ic g_cst3xx_ic_type :0x%x, g_cst3xx_ic_project_id:0x%x\r\n", ++ g_cst3xx_ic_type, g_cst3xx_ic_project_id); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 8); ++ if (ret < 0) return -1; ++ ++ g_cst3xx_ic_version = buf[3]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[2]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[1]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[0]; ++ ++ g_cst3xx_ic_checksum = buf[7]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[6]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[5]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[4]; ++ ++ tpd_info.vid = g_cst3xx_ic_version; ++ tpd_info.pid = 0x00; ++ ++ ++ printk(" cst3xx [cst3xx] the chip ic version:0x%x, checksum:0x%x\r\n", ++ g_cst3xx_ic_version, g_cst3xx_ic_checksum); ++ ++ if(g_cst3xx_ic_version==0xA5A5A5A5) ++ { ++ printk(" cst3xx [cst3xx] the chip ic don't have firmware. \n"); ++ return -1; ++ } ++ if((g_cst3xx_ic_checkcode&0xffff0000)!=0xCACA0000){ ++ printk("linc cst3xx [cst3xx] cst3xx_firmware_info read error .\r\n"); ++ return -1; ++ } ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x09; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ mdelay(5); ++ ++ ++ return 0; ++} ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict) ++{ ++ unsigned short ic_type, project_id; ++ unsigned int fw_checksum, fw_version; ++ const unsigned int *p; ++ int i; ++ unsigned char *pBuf; ++ ++ fw_checksum = 0x55; ++ p = (const unsigned int *)pdata; ++ for (i=0; i<(CST3XX_BIN_SIZE-4); i+=4) { ++ fw_checksum += (*p); ++ p++; ++ } ++ ++ if (fw_checksum != (*p)) { ++ printk(" cst3xx[cst3xx]calculated checksum error:0x%x not equal 0x%x.\n", fw_checksum, *p); ++ return -1; //bad fw, so do not update ++ } ++ ++ pBuf = &pdata[CST3XX_BIN_SIZE-16]; ++ ++ project_id = pBuf[1]; ++ project_id <<= 8; ++ project_id |= pBuf[0]; ++ ++ ic_type = pBuf[3]; ++ ic_type <<= 8; ++ ic_type |= pBuf[2]; ++ ++ fw_version = pBuf[7]; ++ fw_version <<= 8; ++ fw_version |= pBuf[6]; ++ fw_version <<= 8; ++ fw_version |= pBuf[5]; ++ fw_version <<= 8; ++ fw_version |= pBuf[4]; ++ ++ fw_checksum = pBuf[11]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[10]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[9]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[8]; ++ ++ printk(" cst3xx[cst3xx]the updating firmware:project_id:0x%04x,ic type:0x%04x,version:0x%x,checksum:0x%x\n", ++ project_id, ic_type, fw_version, fw_checksum); ++ ++ if (strict > 0) { ++ ++ if (g_cst3xx_ic_checksum != fw_checksum){ ++ if (g_cst3xx_ic_version >fw_version){ ++ printk("[cst3xx]fw version(0x%x), ic version(0x%x).\n",fw_version, g_cst3xx_ic_version); ++ return -1; ++ } ++ }else{ ++ printk("[cst3xx]fw checksum(0x%x), ic checksum(0x%x).\n",fw_checksum, g_cst3xx_ic_checksum); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ int flag = 0; ++ ++ while (retry++ < 3) { ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret == 0) { ++ flag = 1; ++ break; ++ } ++ } ++ ++ if (flag == 1) { ++ ret = cst3xx_update_judge(pdata, 1); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] no need to update firmware.\n"); ++ return 0; ++ } ++ } ++ ++ ret = cst3xx_update_firmware(ts, pdata); ++ if (ret < 0){ ++ printk(" cst3xx [cst3xx] update firmware failed.\n"); ++ return -1; ++ } ++ ++ mdelay(50); ++ ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx [cst3xx] after update read version and checksum fail.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++/*******************************Chose which I2C interface ********************************************/ ++ ++#if USE_ANALOG_I2C ++ ++#define I2CSDA GPIO_PB(23) ++#define I2CSCL GPIO_PB(22) ++ ++#define I2CSDA_HIGH gpio_direction_output(I2CSDA,1) ++#define I2CSDA_LOW gpio_direction_output(I2CSDA,0) ++ ++#define I2CSCL_HIGH gpio_direction_output(I2CSCL,1) ++#define I2CSCL_LOW gpio_direction_output(I2CSCL,0) ++ ++#define delay_data 2 ++static void iicstart(void) ++{ ++ I2CSDA_HIGH; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_LOW; ++ __udelay(2); ++ I2CSCL_LOW; ++ __udelay(2); ++} ++static void iicstop(void) ++{ ++ I2CSDA_LOW; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_HIGH; ++ __udelay(2); ++ ++} ++static unsigned char waitack(void) ++{ ++ u8 ucErrTime=0; ++ ++// gpio_direction_input(GPIO_PC(27)); ++ gpio_direction_input(GPIO_PB(23)); ++ // __udelay(2); ++ ++ // I2CSDA_HIGH; ++ // __udelay(2); ++ I2CSCL_HIGH; ++ __udelay(2); ++ ++// while(__gpio_get_value(GPIO_PC(27))) ++ while(__gpio_get_value(GPIO_PB(23))) ++ { ++ ucErrTime++; ++ // printk("time out ++ \n"); ++ if(ucErrTime>250) ++ { ++ iicstop(); ++ return 1; ++ } ++ } ++ I2CSCL_LOW; ++ __udelay(2); ++ return 0; ++} ++static void sendack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_LOW; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ ++} ++static void sendnotack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_HIGH; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++} ++static void iicsendbyte(unsigned char ch) ++{ ++ unsigned char i; ++ I2CSCL_LOW; ++ for(i = 0;i<8;i++) ++ { ++ if(ch&0x80) ++ { ++ I2CSDA_HIGH; ++ } ++ else ++ { ++ I2CSDA_LOW; ++ } ++ __udelay(delay_data); ++ ch<<=1; ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ } ++} ++static unsigned char iicreceivebyte(unsigned char ack) ++{ ++ unsigned char i=8; ++ unsigned char ddata=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ __udelay(delay_data); ++ ++ for(i = 0;i<8;i++) ++ { ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ ++ ddata<<=1; ++ if(gpio_get_value(GPIO_PC(27))) ddata++; ++ } ++ ++ if(!ack) ++ sendnotack(); ++ else ++ sendack(); ++ ++ return ddata; ++} ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int count = len; ++ iicstart(); ++ __udelay(delay_data); ++ ++/* ++ iicsendbyte( (0x1a<<1) | 0); ++ __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ ++ iicsendbyte(buf[0]); ++ __udelay(delay_data); ++ waitack(); ++ __udelay(delay_data); ++*/ ++ iicstart(); ++ __udelay(delay_data); ++ ++ iicsendbyte((0x1a << 1 ) | 1); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ ++ while(count) ++ { ++ if(count == 1) *buf = iicreceivebyte(0); ++ else *buf = iicreceivebyte(1); ++ count --; ++ buf++; ++ } ++ iicstop(); ++ __udelay(delay_data); ++ return 0; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int count = len; ++ iicstart(); ++ // __udelay(delay_data); ++ ++ iicsendbyte((0x1A << 1) | 0); ++// __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write send address wait ack timeoue \n"); ++ return 1; ++ } ++ ++ while(count--) ++ { ++ iicsendbyte(*(buf++)); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ } ++ ++ iicstop(); ++ __udelay(delay_data); ++ ++ return 0; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if(ret) printk("failed to write cst3xx\n"); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ if(ret) printk("failed to write cst3xx\n"); ++ return ret; ++} ++ ++#elif USE_LOWEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_recv(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_send(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ ++ return ret; ++} ++ ++#elif USE_HIGHEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags |= I2C_M_RD; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++/******************************************************* ++Function: ++ read data from register. ++Input: ++ buf: first two byte is register addr, then read data store into buf ++ len: length of data that to read ++Output: ++ success: number of messages ++ fail: negative errno ++*******************************************************/ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++// printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ struct i2c_msg msgs[2]; ++ int ret = -1; ++ int retries = 0; ++ ++ msgs[0].flags = 0; ++ msgs[0].addr = client->addr; ++ msgs[0].len = 2; ++ msgs[0].buf = buf; ++ ++ msgs[1].flags |= I2C_M_RD; ++ msgs[1].addr = client->addr; ++ msgs[1].len = len; ++ msgs[1].buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if(ret == 2) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++// printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags = 0; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++#else ++#endif ++/*********************************i2c end********************************/ ++ ++ ++static int cst3xx_i2c_test(struct i2c_client *client) ++{ ++ int retry = 0; ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ while (retry++ < 5) { ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret == 0) ++ return ret; ++ ++ mdelay(2); ++ } ++ ++ if(retry==5) printk(" cst3xx hyn I2C TEST error.ret:%d;\n", ret); ++ ++ return ret; ++} ++ ++ ++static void cst3xx_reset(struct cst3xx_ts_data *ts) { ++ if(gpio_is_valid(ts->pdata->reset_gpio)) { ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(100); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++ mdelay(100); ++ } ++} ++/**************************** basic communication end*******************************/ ++ ++ ++static void cst3xx_touch_report(struct cst3xx_ts_data *ts) ++{ ++ unsigned char buf[30]; ++ unsigned char i2c_buf[8]; ++ unsigned char key_status, key_id = 0, finger_id, sw; ++ unsigned int input_x = 0; ++ unsigned int input_y = 0; ++ unsigned int input_w = 0; ++ unsigned int input_x_delta = 0; ++ unsigned int input_y_delta = 0; ++ unsigned char cnt_up, cnt_down; ++ int i, ret, idx; ++ int cnt, i2c_len; ++ ++ int len_1, len_2; ++ ++ key_status = 0; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(ts->client, buf, 7); ++ if(ret < 0) { ++ printk(" iic read touch point data failed.\n"); ++ goto OUT_PROCESS; ++ } ++ // printk(" read buf : buf[0]: %x ,buf[1]: %x ,buf[2]: %x, buf[3]: %x,buf[4]: %x ,buf[5]: %x ,buf[6]: %x, buf[7]: %x,\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); ++ ++ if(buf[6] != 0xAB) { ++ printk(KERN_INFO " data is not valid..\r\n"); ++ goto OUT_PROCESS; ++ } ++ ++ cnt = buf[5] & 0x7F; ++ if(cnt > 1) goto OUT_PROCESS; ++ else if(cnt==0) goto CLR_POINT; ++ ++ if(cnt == 0x01) { ++ goto FINGER_PROCESS; ++ } ++ ++FINGER_PROCESS: ++ ++ /* ++ * sw: buf[0] low 4 bit ++ * x pos: buf[1] low 4 bit | buf[3] high 4 bit ++ * y pos: buf[2] low 4 bit | buf[3] low 4 bit ++ * z press : buf[4] ++ * finger_id:buf[0] high 4 bit ++ */ ++ i2c_buf[0] = 0xD0; ++ i2c_buf[1] = 0x00; ++ i2c_buf[2] = 0xAB; ++ ++ ret = cst3xx_i2c_write(ts->client, i2c_buf, 3); ++ if(ret < 0) { ++ printk(" cst3xx hyn send read touch info ending failed.\r\n"); ++ cst3xx_reset_ic(ts,20); ++ goto END; ++ } ++ ++ idx = 0; ++ cnt_up = 0; ++ cnt_down = 0; ++ input_x = (unsigned int)((buf[idx + 1] << 4) | ((buf[idx + 3] >> 4) & 0x0F)); ++ input_y = (unsigned int)((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0F)); ++ input_w = (unsigned int)(buf[idx + 4]); ++ sw = (buf[idx] & 0x0F) >> 1; ++ finger_id = (buf[idx] >> 4) & 0x0F; ++ ++ printk(" no handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n", input_x, input_y, input_w,finger_id, sw); ++ ++// input_x=input_x*CST3XX_MAX_X/268; //update 0729 no handle == handle ++// input_x=input_x*CST3XX_MAX_X/360; //update 0729 no handle == handle ++// input_y=input_y*CST3XX_MAX_Y/800; ++ ++// if(input_x >= CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++// if(input_y >= CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ ++// input_x = CST3XX_MAX_X-input_x; ++// input_y = CST3XX_MAX_Y-input_y; ++ ++#ifdef HYN_DRAW_POINT ++ if(input_x > 300){ ++ input_x_delta = input_x - (CST3XX_MAX_X/2); ++ input_x = input_x + input_x_delta/((CST3XX_MAX_X/2)/20); ++ if(input_x > CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++ } ++ if(input_x < 40){ ++ input_x_delta = (CST3XX_MAX_X/2) - input_x; ++ input_x = input_x - input_x_delta/((CST3XX_MAX_X/2)/12); ++ if(input_x < 0) input_x = 0; ++ } ++ if(input_y > 760){ ++ input_y_delta = input_y - (CST3XX_MAX_Y/2); ++ input_y = input_y + input_y_delta/((CST3XX_MAX_Y/2)/12); ++ if(input_y > CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ } ++ if(input_y < 40){ ++ input_y_delta = (CST3XX_MAX_Y/2) - input_y; ++ input_y = input_y - input_y_delta/((CST3XX_MAX_Y/2)/25); ++ if(input_y < 0) input_y = 0; ++ } ++#endif ++ ++ printk(" handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n\n", input_x, input_y, input_w,finger_id, sw); ++ ++ if (sw == 0x03 ) { ++ if((input_x > x_temp_pos + ERROR_TOUCH) || (input_x < x_temp_pos -ERROR_TOUCH) || (input_y > y_temp_pos + ERROR_TOUCH) || (input_y < y_temp_pos -ERROR_TOUCH)) ++ { ++ // printk(" REPORT TOUCH DOWM Handle \n"); ++ x_temp_pos = input_x; ++ y_temp_pos = input_y; ++ input_report_key(ts->input_dev, BTN_TOUCH, 1); ++ input_report_abs(ts->input_dev, ABS_X, input_x); ++ input_report_abs(ts->input_dev, ABS_Y, input_y); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 1); ++ input_sync(ts->input_dev); ++ } ++ cnt_down++; ++ } ++ else if(sw == 0) { ++ cnt_up++; ++ } ++ ++ if((cnt_up>0) && (cnt_down==0) ){ ++ // printk(" REPORT TOUCH UP Handle \n"); ++ x_temp_pos = 0; ++ y_temp_pos = 0; ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 0); ++ input_mt_sync(ts->input_dev); ++ } ++ input_sync(ts->input_dev); ++ goto END; ++CLR_POINT: ++ ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_mt_sync(ts->input_dev); ++ input_sync(ts->input_dev); ++ ++OUT_PROCESS: ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ buf[2] = 0xAB; ++ ret = cst3xx_i2c_write(ts->client, buf, 3); ++ if (ret < 0) { ++ printk(" send read touch info ending failed.\n"); ++ cst3xx_reset_ic(ts,20); ++ } ++END: ++ return; ++} ++ ++ ++/******************************* irq handle begin************************************/ ++static void cst3xx_work_handler(struct work_struct *work) ++{ ++ struct cst3xx_ts_data *cst3xx_ts = container_of(work, struct cst3xx_ts_data, work); ++ int ret = 0; ++ /******************here handle touch *******************/ ++ // printk(KERN_INFO "-----------enter cst3xx_work_handler------------\n"); ++ cst3xx_touch_report(cst3xx_ts); ++ enable_irq(cst3xx_ts->irq); ++} ++ ++static irqreturn_t cst3xx_ts_irq_handler(int irq, void *dev_id) ++{ ++ struct cst3xx_ts_data *ts = dev_id; ++ ++ // printk( KERN_INFO "-----------enter cst3xx_ts_irq_handler------------\n"); ++ ++ disable_irq_nosync(ts->irq);//use in interrupt,disable_irq will make dead lock. ++ ++ if (!work_pending(&ts->work)) { ++ queue_work(ts->workqueue, &ts->work); ++ // queue_delayed_work(ts->workqueue,&ts->dwork,1);//10ms * x ++ } else { ++ enable_irq(ts->irq); ++ } ++ ++ return IRQ_HANDLED; ++} ++/******************************* irq handle end************************************/ ++static int cst3xx_parse_dt(struct device *dev, struct cst3xx_platform_data *pdata) ++{ ++ int ret = 0; ++ struct device_node *np = dev->of_node; ++ u32 temp_val = 0; ++ ++ HYN_FUNC_ENTER(); ++ ++ /* reset, irq gpio info */ ++ pdata->reset_gpio = of_get_named_gpio_flags(np, "hyn,reset-gpio", ++ 0, &pdata->reset_gpio_flags); ++ if (pdata->reset_gpio < 0) ++ HYN_ERROR("Unable to get reset_gpio"); ++ ++ pdata->int_gpio = of_get_named_gpio_flags(np, "hyn,irq-gpio", ++ 0, &pdata->irqflags); ++ if (pdata->int_gpio < 0) ++ HYN_ERROR("Unable to get irq_gpio"); ++ ++ HYN_INFO(" irq gpio:%d, reset gpio:%d", ++ pdata->int_gpio, pdata->reset_gpio); ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++} ++static int cst3xx_gpio_configure(struct cst3xx_ts_data *data) ++{ ++ int ret = 0; ++ ++ HYN_FUNC_ENTER(); ++ /* request irq gpio */ ++ if (gpio_is_valid(data->pdata->int_gpio)) { ++ ret = gpio_request(data->pdata->int_gpio, "cst3xx_irq_gpio"); ++ if (ret) { ++ HYN_ERROR("[GPIO]irq gpio request failed"); ++ goto err_irq_gpio_req; ++ } ++ ++ ret = gpio_direction_input(data->pdata->int_gpio); ++ if (ret) { ++ HYN_ERROR("[GPIO]set_direction for irq gpio failed"); ++ goto err_irq_gpio_dir; ++ } ++ } ++ ++ /* request reset gpio */ ++ if (gpio_is_valid(data->pdata->reset_gpio)) { ++ ret = gpio_request(data->pdata->reset_gpio, "cst3xx_reset_gpio"); ++ if (ret) { ++ HYN_ERROR("[GPIO]reset gpio request failed"); ++ goto err_irq_gpio_dir; ++ } ++ ++// ret = gpio_direction_output(data->pdata->reset_gpio, 1); ++// if (ret) { ++// HYN_ERROR("[GPIO]set_direction for reset gpio failed"); ++// goto err_reset_gpio_dir; ++// } ++ } ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++ ++err_reset_gpio_dir: ++ if (gpio_is_valid(data->pdata->reset_gpio)) ++ gpio_free(data->pdata->reset_gpio); ++err_irq_gpio_dir: ++ if (gpio_is_valid(data->pdata->int_gpio)) ++ gpio_free(data->pdata->int_gpio); ++err_irq_gpio_req: ++ HYN_FUNC_EXIT(); ++ return ret; ++} ++ ++static int cst3xx_input_init(struct cst3xx_ts_data *ts_data) ++{ ++ int ret = 0; ++ int key_num = 0; ++ struct cst3xx_platform_data *pdata = ts_data->pdata; ++ struct input_dev *input_dev; ++ ++ HYN_FUNC_ENTER(); ++ input_dev = input_allocate_device(); ++ if (!input_dev) { ++ HYN_ERROR("Failed to allocate memory for input device"); ++ return -ENOMEM; ++ } ++ ++ /* Init and register Input device */ ++ input_dev->name = CST3XX_NAME; ++ ++ input_dev->id.bustype = BUS_I2C; ++ input_dev->dev.parent = ts_data->dev; ++ ++ input_set_drvdata(input_dev, ts_data); ++ ++ __set_bit(EV_SYN, input_dev->evbit); ++ __set_bit(EV_ABS, input_dev->evbit); ++ __set_bit(EV_KEY, input_dev->evbit); ++ __set_bit(BTN_TOUCH, input_dev->keybit); ++// __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); ++ set_bit(ABS_X, input_dev->absbit); //add from hyn ++ set_bit(ABS_Y, input_dev->absbit); ++ set_bit(ABS_PRESSURE, input_dev->absbit); ++ ++/*---add from hyn*/ ++ input_set_abs_params(input_dev, ABS_X, ts_data->pdata->x_min, ts_data->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, ts_data->pdata->y_min, ts_data->pdata->y_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0 , 0); ++/*add from hyn---*/ ++ ++ ret = input_register_device(input_dev); ++ if (ret) { ++ HYN_ERROR("Input device registration failed"); ++ input_set_drvdata(input_dev, NULL); ++ input_free_device(input_dev); ++ input_dev = NULL; ++ return ret; ++ } ++ ++ ts_data->input_dev = input_dev; ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++} ++ ++static int cst3xx_irq_registration(struct cst3xx_ts_data *ts_data) ++{ ++ int ret = 0; ++ struct cst3xx_platform_data *pdata = ts_data->pdata; ++ ++ ts_data->irq = gpio_to_irq(pdata->int_gpio); ++ pdata->irqflags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; ++ HYN_INFO("irq:%d, flag:%x", ts_data->irq, pdata->irqflags); ++ ret = request_threaded_irq(ts_data->irq, NULL, cst3xx_ts_irq_handler, ++ pdata->irqflags, ++ CST3XX_NAME, ts_data); ++ ++ return ret; ++} ++ ++static int cst3xx_ts_probe_entry(struct cst3xx_ts_data *ts_data) ++{ ++ int ret = 0; ++ int pdata_size = sizeof(struct cst3xx_platform_data); ++ ++ HYN_FUNC_ENTER(); ++ ts_data->pdata = kzalloc(pdata_size, GFP_KERNEL); ++ if (!ts_data->pdata) { ++ HYN_ERROR("allocate memory for platform_data fail"); ++ return -ENOMEM; ++ } ++ ++ if (ts_data->dev->of_node) { ++ ret = cst3xx_parse_dt(ts_data->dev, ts_data->pdata); ++ if (ret) ++ HYN_ERROR("device-tree parse fail"); ++ } else { ++ if (ts_data->dev->platform_data) { ++ memcpy(ts_data->pdata, ts_data->dev->platform_data, pdata_size); ++ } else { ++ HYN_ERROR("platform_data is null"); ++ return -ENODEV; ++ } ++ } ++ //init work for cst3xx.. ++ ++ INIT_WORK(&ts_data->work, cst3xx_work_handler); ++ ++ ts_data->workqueue = create_singlethread_workqueue("cst3xx_wq"); ++ if (!ts_data->workqueue) { ++ HYN_ERROR("create cst3xx workqueue fail"); ++ } ++ ++// spin_lock_init(&ts_data->irq_lock); ++// mutex_init(&ts_data->report_mutex); ++// mutex_init(&ts_data->bus_lock); ++ ++ /* Init communication interface */ ++ ret = cst3xx_bus_init(ts_data); ++ if (ret) { ++ HYN_ERROR("bus initialize fail"); ++ goto err_bus_init; ++ } ++#if USE_ANALOG_I2C ++ if (gpio_is_valid(I2CSDA) ++ { ++ gpio_free(I2CSDA); ++ ret = gpio_request(GPIO_PB(23),"I2C2-SDA"); ++ if(ret < 0){ ++ printk("I2C2-SDA gpio request failed\n"); ++ return ret; ++ } ++ } ++ if (gpio_is_valid(I2CSCL)) ++ { ++ gpio_free(I2CSCL); ++ ret = gpio_request(GPIO_PB(22),"I2C2-SCL"); ++ if(ret < 0){ ++ printk("I2C2-SCL gpio request failed\n"); ++ return ret; ++ } ++ } ++#endif ++ ret = cst3xx_i2c_test(ts_data->client); ++ if(ret>=0){ ++ ++ mdelay(100); ++ ++ printk( KERN_INFO "cst3xx test OK -------------------\n"); ++#ifdef HYN_UPDATE_FIRMWARE_ENABLE ++ ret = cst3xx_boot_update_fw(ts_data,pcst3xx_update_firmware);// ++ if(ret < 0){ ++ printk(" cst3xx hyn_boot_update_fw failed.\n"); ++ return -1; ++ } ++#endif ++ ++ }else{ ++ printk( KERN_INFO "cst3xx hyn i2c communication failed.---------------\n"); ++ return -1; ++ } ++ ++ ret = cst3xx_input_init(ts_data); ++ if (ret) { ++ HYN_ERROR("input initialize fail"); ++ goto err_input_init; ++ } ++ ++ ret = cst3xx_gpio_configure(ts_data); ++ if (ret) { ++ HYN_ERROR("configure the gpios fail"); ++ goto err_gpio_config; ++ } ++ printk( KERN_INFO "cst3xx reset ----before---------------\n"); ++ cst3xx_reset(ts_data); ++ printk( KERN_INFO "cst3xx reset ----after--------------\n"); ++ ++ ret = cst3xx_irq_registration(ts_data); ++ if (ret) { ++ HYN_ERROR("request irq failed"); ++ goto err_irq_req; ++ } ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++ ++err_irq_req: ++ if (gpio_is_valid(ts_data->pdata->reset_gpio)) ++ gpio_free(ts_data->pdata->reset_gpio); ++ if (gpio_is_valid(ts_data->pdata->int_gpio)) ++ gpio_free(ts_data->pdata->int_gpio); ++err_gpio_config: ++ kfree_safe(ts_data->point_buf); ++ kfree_safe(ts_data->events); ++err_input_init: ++ if (ts_data->workqueue) ++ destroy_workqueue(ts_data->workqueue); ++err_bus_init: ++ kfree_safe(ts_data->bus_tx_buf); ++ kfree_safe(ts_data->bus_rx_buf); ++ kfree_safe(ts_data->pdata); ++ ++ HYN_FUNC_EXIT(); ++ return ret; ++} ++static int cst3xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ int ret = 0; ++ struct cst3xx_ts_data *ts_data = NULL; ++ struct input_dev *input_dev; ++ ++ struct cst3xx_platform_data *pdata = (struct cst3xx_platform_data*)client->dev.platform_data; ++ ++ HYN_INFO("Touch Screen(I2C BUS) driver prboe..."); ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ HYN_ERROR("I2C not supported"); ++ return -ENODEV; ++ } ++ ++ /* malloc memory for global struct variable */ ++ ts_data = (struct cst3xx_ts_data *)kzalloc(sizeof(*ts_data), GFP_KERNEL); ++ if (!ts_data) { ++ HYN_ERROR("allocate memory for cst3xx_data fail"); ++ return -ENOMEM; ++ } ++ ts_data->client = client; ++ ts_data->dev = &client->dev; ++ ts_data->pdata = pdata; ++ i2c_set_clientdata(client, ts_data); ++ ++ ret = cst3xx_ts_probe_entry(ts_data); ++ if (ret) { ++ HYN_ERROR("Touch Screen(I2C BUS) driver probe fail"); ++ kfree_safe(ts_data); ++ return ret; ++ } ++ if(client->addr != 0x1A) //check address ++ { ++ client->addr = 0x1A; ++ printk(">>>>>>>>>>>>>1>>>xtang:i2c_client_HYN->addr=%d.\n",client->addr); ++ ++ }else ++ printk(">>>>>>>>>>>>2>>>>xtang:i2c_client_HYN->addr=%d.\n",client->addr); ++ ++ ++ HYN_INFO("Touch Screen(I2C BUS) driver prboe successfully"); ++ return 0; ++} ++ ++ ++static int cst3xx_ts_remove(struct i2c_client *client) ++{ ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ free_irq(ts->irq,ts); ++ devm_free_irq(&ts->client->dev, ts->client->irq,ts); ++ destroy_workqueue(ts->workqueue); ++ input_unregister_device(ts->input_dev); ++ devm_gpio_free(&ts->client->dev, ts->pdata->reset_gpio); ++ gpio_free(ts->pdata->int_gpio); ++ ++#if USE_ANALOG_I2C ++ gpio_free(I2CSDA); ++ gpio_free(I2CSCL); ++#endif ++//i2c bus init. ++ cst3xx_bus_exit(ts); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int cst3xx_ts_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ enable_irq_wake(client->irq); ++ } else { ++ disable_irq(client->irq); ++ cst3xx_ts_power(ts, false);//reset ++ } ++ ++ return 0; ++} ++ ++static int cst3xx_ts_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ disable_irq_wake(client->irq); ++ } else { ++ cst3xx_ts_power(ts, true); ++ enable_irq(client->irq); ++ } ++ return 0; ++} ++ ++#endif ++ ++static SIMPLE_DEV_PM_OPS(cst3xx_ts_pm_ops, ++ cst3xx_ts_suspend, cst3xx_ts_resume); ++ ++static const struct i2c_device_id cst3xx_ts_id[] = { ++ { CST3XX_NAME, 0 }, ++ { } ++}; ++static const struct of_device_id cst3xx_dt_match[] = { ++ {.compatible = "hyn,cst3xx", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, cst3xx_dt_match); ++ ++static struct i2c_driver cst3xx_ts_driver = { ++ .probe = cst3xx_ts_probe, ++ .remove = cst3xx_ts_remove, ++ .driver = { ++ .name = CST3XX_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(cst3xx_dt_match), ++ .pm = &cst3xx_ts_pm_ops, ++ }, ++ .id_table = cst3xx_ts_id, ++}; ++ ++static int __init cst3xx_ts_init(void) ++{ ++ int ret = 0; ++ ++ HYN_FUNC_ENTER(); ++ ret = i2c_add_driver(&cst3xx_ts_driver); ++ if ( ret != 0 ) { ++ HYN_ERROR("hyn touch screen driver init failed!"); ++ } ++ HYN_FUNC_EXIT(); ++ return ret; ++} ++ ++static void __exit cst3xx_ts_exit(void) ++{ ++ i2c_del_driver(&cst3xx_ts_driver); ++} ++module_init(cst3xx_ts_init); ++module_exit(cst3xx_ts_exit); ++ ++MODULE_AUTHOR("HYN Driver Team"); ++MODULE_DESCRIPTION("HYN Touchscreen Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update1/hyn_cst3xx_RS659_fw.h b/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update1/hyn_cst3xx_RS659_fw.h +new file mode 100644 +index 000000000..006c36c81 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update1/hyn_cst3xx_RS659_fw.h +@@ -0,0 +1,1553 @@ ++ ++#ifndef __CST3xx_FW_H__ ++#define __CST3xx_FW_H__ ++ ++ unsigned char cst3_fw[] ={ ++ 0x98,0xE0,0x07,0x01,0xB0,0x88,0x01,0x00,0x00,0x00,0x00,0x00,0xB0,0x48,0x01,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x80,0x68,0x06,0x00,0x80,0x68,0x07,0x00,0x00,0x00,0x00,0x00, ++ 0x88,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0xD8,0x00,0x00,0x80,0x07,0xC0,0x17, ++ 0x82,0x07,0xC0,0x07,0x01,0x65,0x40,0x86,0xC1,0x41,0xC0,0x20,0xC5,0x68,0x31,0x12, ++ 0xF5,0x38,0x33,0x5A,0x32,0xA2,0x32,0xEA,0x10,0x62,0x8D,0x0E,0x81,0x07,0xC0,0x97, ++ 0x30,0xF2,0xF3,0x79,0x65,0x7E,0x30,0xB2,0x31,0x09,0x10,0x9A,0x87,0x06,0xD0,0xD8, ++ 0x35,0x12,0x35,0x5A,0x18,0x9A,0x39,0xC2,0xE0,0xE2,0x03,0x00,0xE0,0xE2,0x04,0x00, ++ 0xD0,0x81,0x98,0x16,0x43,0xC6,0x0B,0xC6,0xC2,0xD6,0x3F,0x90,0x99,0x0E,0x40,0x86, ++ 0x08,0x86,0xA9,0x0E,0x40,0x23,0x00,0x63,0x38,0x82,0x03,0x00,0x18,0x01,0x20,0x01, ++ 0x28,0x01,0x30,0x01,0xD0,0x81,0x98,0x0E,0x0F,0xC6,0xC3,0xDE,0x38,0x90,0x9A,0x06, ++ 0x08,0x86,0xA9,0x06,0x03,0x5B,0x38,0x82,0xAE,0xFD,0x30,0x02,0x30,0x02,0xEE,0xFD, ++ 0xA8,0x85,0xE8,0x85,0x86,0x2F,0xE0,0x1F,0x37,0x8A,0xB8,0xFF,0xF8,0xAF,0x87,0x0F, ++ 0xC0,0xCF,0x85,0x2F,0xE7,0xDF,0xBE,0xFF,0xF8,0x9F,0x87,0x2F,0xE0,0x0F,0x07,0x00, ++ 0xAF,0x85,0x6F,0xD2,0xE1,0x43,0x31,0x4A,0xCA,0x01,0x3E,0x30,0x34,0x42,0x80,0x01, ++ 0xF6,0x1B,0xF4,0x23,0xF3,0x53,0xC2,0x01,0x70,0x01,0xD8,0x16,0xE7,0x6B,0x4D,0x68, ++ 0x80,0x4E,0x28,0x01,0x10,0x6C,0xAE,0x6B,0xA4,0x2B,0x12,0xD2,0x8A,0x16,0xB0,0x63, ++ 0x00,0x09,0xB0,0x43,0xE8,0x85,0x37,0x72,0xEA,0x4B,0xE0,0x48,0x91,0x4D,0xAE,0x8B, ++ 0x57,0xAC,0x7F,0x5A,0x10,0xEA,0x95,0x0E,0xE7,0x68,0x13,0xAC,0x48,0xF9,0x8F,0x0E, ++ 0x10,0x12,0x85,0x16,0xE0,0x0B,0x4A,0x09,0x8B,0x26,0xB0,0x9B,0x09,0x01,0xA8,0x8B, ++ 0xA7,0x0B,0xEA,0x85,0x4F,0x09,0x8C,0xE6,0x0A,0x09,0xA0,0x0B,0xE8,0x85,0xAF,0x85, ++ 0x66,0xF2,0xE6,0x01,0x00,0x0F,0x80,0x0F,0xE1,0xAF,0xF7,0x03,0x47,0x01,0x80,0xD6, ++ 0xEB,0x85,0xA8,0x85,0x70,0xDA,0x2E,0x09,0x1E,0xAB,0x65,0xC2,0xE7,0x03,0x09,0x79, ++ 0x01,0x42,0xA0,0x03,0x00,0x0F,0x80,0x0F,0xE1,0x2F,0xE7,0x03,0x37,0x00,0xAE,0xD6, ++ 0x05,0x01,0x18,0x83,0xE1,0x03,0x19,0x42,0xA3,0x03,0xE9,0x85,0x42,0x7A,0xC6,0x01, ++ 0xE6,0x0B,0x44,0x8A,0x48,0x01,0x80,0x3E,0x4A,0x82,0x06,0x0B,0x0E,0xF9,0x57,0x72, ++ 0x8A,0x89,0x97,0x01,0x10,0x8B,0x00,0x17,0x48,0x62,0xCE,0xE1,0x07,0x0B,0x0A,0xF9, ++ 0x8E,0x21,0x01,0x0B,0x08,0x09,0x08,0x0B,0x08,0x0B,0x0C,0x31,0x08,0x0B,0x0A,0x59, ++ 0x18,0x0B,0x0C,0x81,0x18,0x0B,0x0A,0x01,0x1B,0x0B,0x38,0x82,0xAD,0x85,0x40,0xFA, ++ 0xE6,0x03,0x38,0x00,0x81,0x8E,0x00,0xE1,0x83,0x0F,0xC8,0x0F,0x40,0xDA,0x0D,0x01, ++ 0xC4,0x01,0xA9,0x0B,0xBE,0xFF,0xFF,0x97,0x4D,0xC2,0x55,0xEA,0xCD,0x01,0x46,0xEA, ++ 0x84,0x1F,0xD8,0xCF,0x00,0x01,0x80,0x0F,0xC8,0x77,0xE9,0x85,0xAD,0x85,0x40,0x9A, ++ 0xC6,0x01,0xE9,0x03,0x40,0x01,0x88,0x36,0x46,0x82,0xC5,0x01,0xE0,0x03,0x44,0x29, ++ 0xCF,0x0E,0xB8,0xFF,0xFD,0xE7,0x64,0x6A,0xE0,0x03,0x39,0x00,0xAF,0x0E,0xB8,0xFF, ++ 0xFB,0x07,0xE5,0x03,0x38,0x00,0xAC,0x2E,0x42,0x5A,0xC5,0x01,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0xE7,0x03,0x0B,0xE9,0x03,0x42,0xA0,0x03,0x40,0x52,0xC5,0x03, ++ 0x40,0x01,0x80,0x16,0x83,0x0F,0xE0,0xF7,0x38,0xE7,0xEF,0x85,0xAD,0x85,0x48,0x3A, ++ 0x04,0x01,0x00,0x43,0x4E,0xEA,0xCC,0x01,0xB2,0x43,0xF0,0x43,0x80,0x0F,0xC8,0xFF, ++ 0xEB,0x85,0xA8,0x85,0x30,0x2A,0x20,0x49,0x18,0x22,0x4F,0x01,0x80,0x46,0x68,0x01, ++ 0x80,0x16,0x30,0x82,0xC0,0x61,0x00,0x4F,0x30,0x82,0x80,0x61,0x20,0x51,0x00,0x2F, ++ 0x68,0x01,0x80,0x0E,0xF0,0x80,0x04,0x0F,0xE0,0x80,0x24,0x51,0x0A,0x01,0xF0,0x0A, ++ 0x48,0x01,0xD0,0x06,0x16,0x4A,0x0A,0x40,0x0A,0x01,0xF0,0x8A,0x81,0x2F,0xD8,0xA7, ++ 0x40,0xF9,0xEB,0x06,0x00,0xF9,0x6B,0x01,0x87,0x16,0x08,0xF9,0x88,0x09,0xD0,0x40, ++ 0xCB,0x00,0xE8,0x85,0xAC,0x85,0x6B,0x2A,0xED,0x01,0xE4,0x43,0x41,0x01,0x80,0x26, ++ 0x32,0x62,0xA1,0x01,0x40,0x03,0x41,0x01,0x81,0xFE,0x30,0x0A,0xCC,0x01,0x44,0x2A, ++ 0x81,0x17,0xC8,0x3F,0x0F,0x01,0x40,0xF9,0x8D,0xC6,0xF0,0x03,0xE3,0x01,0xB4,0x03, ++ 0x11,0x11,0x30,0x02,0x82,0x01,0xA1,0x13,0xA8,0x0B,0x01,0x01,0x12,0x79,0x28,0x29, ++ 0x5B,0xE2,0x0B,0x68,0xF8,0x23,0x03,0x37,0x0A,0x21,0x19,0x0A,0xC2,0x48,0xCE,0x48, ++ 0x92,0x53,0xE0,0x00,0x94,0x05,0x16,0x22,0xC3,0xB6,0xEF,0x85,0x47,0xF1,0x87,0xE6, ++ 0x47,0x01,0x80,0xD6,0xF0,0x00,0x12,0x09,0x44,0x1B,0x01,0x12,0x17,0x9A,0x80,0xA6, ++ 0xA3,0x4B,0xED,0x85,0xAB,0x85,0x51,0x92,0x28,0x01,0x20,0x01,0x08,0x01,0x00,0x01, ++ 0xC4,0x9B,0x10,0x5A,0xC8,0x06,0x30,0xCA,0x58,0xD1,0x9F,0x0E,0x28,0x09,0x00,0x27, ++ 0xE2,0x90,0xE2,0x00,0x90,0x05,0x46,0x31,0x99,0x96,0x4F,0xE1,0x92,0x5E,0x40,0xFA, ++ 0xC4,0x01,0xE6,0x03,0x40,0x29,0xC8,0x36,0x41,0x12,0x0B,0x81,0xF3,0x0A,0x4A,0xC1, ++ 0xD8,0x0E,0x28,0x09,0x03,0x1F,0xE0,0x20,0x90,0x25,0x67,0x71,0x98,0xF6,0x16,0x01, ++ 0x48,0x02,0x6B,0x01,0x82,0x7E,0x40,0x44,0xE4,0x00,0x92,0x05,0x00,0x44,0x42,0xA1, ++ 0xCC,0x46,0x40,0x44,0xE4,0x00,0x02,0x44,0x02,0x54,0x42,0x82,0x10,0x09,0xE0,0x0B, ++ 0x18,0x8A,0xA0,0x0B,0xEA,0x85,0x01,0x54,0xEF,0x85,0xA9,0x85,0x80,0x3D,0x04,0x01, ++ 0x80,0x14,0x80,0x1C,0x00,0x01,0x08,0x01,0x10,0x01,0x90,0x0C,0xD2,0x1C,0x58,0x6A, ++ 0x06,0x90,0x32,0x09,0xC5,0x90,0x06,0xB0,0xC9,0xA0,0x34,0x2A,0x18,0x01,0x10,0x01, ++ 0xF0,0x12,0xC5,0x80,0x92,0x05,0xE0,0x48,0x90,0x4D,0xF8,0x0C,0x10,0xD2,0xED,0x06, ++ 0x90,0x0C,0xA0,0x61,0xE6,0xD8,0x92,0xDD,0x5F,0x71,0x98,0x86,0x84,0x2F,0xD0,0xA7, ++ 0x90,0x25,0xC0,0x14,0x10,0x02,0xD5,0x06,0xA0,0x14,0x38,0x01,0x60,0x01,0xE8,0xAE, ++ 0x35,0x01,0xF8,0x72,0x10,0x32,0xDD,0x66,0xC6,0x0C,0x78,0x08,0xC2,0x40,0x80,0x00, ++ 0x10,0x32,0xD4,0x8E,0x09,0x19,0x30,0x82,0x83,0x2F,0xD0,0xF7,0xD1,0x80,0x01,0x44, ++ 0x00,0x57,0x70,0x01,0xE8,0x46,0x00,0x09,0x00,0x44,0x01,0x2F,0x01,0x01,0xF0,0x42, ++ 0x10,0x02,0xE5,0x0E,0xD9,0x00,0x00,0x44,0xAB,0x61,0xE0,0xF8,0x90,0xFD,0x7F,0x71, ++ 0x98,0xE6,0xC6,0x1C,0xE6,0x00,0x92,0x05,0x80,0x1C,0xC0,0x1C,0x45,0x31,0x98,0x8E, ++ 0x00,0x01,0x80,0x24,0x00,0x01,0x08,0x01,0x38,0x01,0xD0,0x24,0x1A,0x61,0x18,0xD2, ++ 0x5E,0x22,0xC1,0x98,0x14,0x09,0x06,0x90,0xC0,0xD0,0x34,0xA2,0x18,0x01,0x30,0x01, ++ 0xF9,0xB2,0xC4,0x80,0x92,0x05,0xE0,0x48,0x95,0x4D,0x10,0xF2,0xE9,0x06,0x30,0xBA, ++ 0xE2,0x90,0xE4,0xD8,0x90,0xDD,0x5E,0x31,0x98,0x8E,0x87,0x2F,0xD0,0x2F,0x92,0x2D, ++ 0xC5,0x14,0x10,0x42,0xD0,0x06,0xA8,0x14,0x30,0x01,0x68,0x01,0xE8,0xA6,0x01,0x01, ++ 0xF0,0x02,0x81,0x34,0x10,0x42,0xDD,0x9E,0x09,0x19,0x30,0x42,0x81,0x2F,0xD0,0xA7, ++ 0xC8,0x34,0xD0,0x40,0x91,0x05,0x00,0x04,0x83,0x2C,0xD8,0xC0,0x41,0x41,0xD1,0x4E, ++ 0x00,0x40,0x0B,0x19,0x81,0x2F,0xD0,0x47,0xC8,0x2C,0xD0,0x40,0x01,0x04,0x01,0x0F, ++ 0xC0,0x34,0x40,0x01,0xE8,0xF6,0x00,0x09,0x00,0x04,0x01,0xDF,0x00,0xC0,0x06,0x01, ++ 0x50,0x07,0x03,0x00,0x18,0x00,0x02,0x42,0x00,0x01,0x00,0x42,0x80,0x60,0x05,0x00, ++ 0x58,0xC0,0x02,0x01,0x00,0xA0,0x07,0x01,0x00,0x80,0x00,0x01,0x10,0x00,0x00,0x42, ++ 0x10,0xC0,0x00,0x01,0x00,0x00,0x00,0x01,0x01,0x01,0xF0,0x02,0x10,0x42,0xE5,0x0E, ++ 0xD9,0x00,0x02,0x04,0xE3,0x20,0xE5,0xB0,0x90,0xB5,0x77,0x31,0x98,0xEE,0xC5,0x24, ++ 0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x44,0x71,0x98,0x9E,0xC5,0x14,0x50,0xD2, ++ 0x40,0xE1,0xD1,0x26,0x7A,0x40,0xCF,0x00,0x82,0x00,0x82,0x83,0x00,0x0F,0x00,0xF1, ++ 0x82,0x83,0xC2,0x8B,0x40,0xAA,0x4D,0x01,0x82,0x4E,0xF0,0x48,0x81,0x8B,0x8A,0x41, ++ 0x32,0x12,0xD0,0x01,0x88,0x8B,0x08,0x31,0x98,0x0B,0x86,0x3D,0xE8,0x85,0x0F,0x11, ++ 0x9F,0x0B,0x3E,0xD7,0xAD,0x85,0x47,0x6A,0x72,0x6A,0xC5,0x01,0xF1,0x2B,0x04,0x09, ++ 0x09,0x00,0xC4,0xA0,0x69,0x09,0xC8,0x66,0x1F,0x01,0x10,0xF9,0x02,0x01,0x38,0x19, ++ 0x08,0xF8,0x03,0x57,0x0A,0x31,0x18,0x0A,0xCE,0x48,0xCC,0x48,0x54,0x4C,0x10,0xCA, ++ 0xC8,0x0E,0x30,0x5A,0x32,0x12,0xE0,0x00,0x94,0x05,0x16,0x2A,0xC7,0x96,0x57,0xF9, ++ 0x82,0xBE,0x00,0x80,0xC9,0x08,0x04,0x09,0x08,0x00,0xC4,0x40,0xF1,0x0B,0xB0,0x0B, ++ 0xF3,0x03,0xB2,0x03,0x02,0x31,0x18,0x12,0xCE,0x80,0xCC,0x00,0x4C,0xCA,0x4C,0x14, ++ 0x0E,0x54,0x4C,0x14,0x08,0x54,0x56,0x04,0x14,0x44,0x48,0xA2,0x02,0x09,0xC8,0x01, ++ 0xB4,0x43,0x44,0x92,0x3A,0x01,0xC0,0x01,0xF4,0x03,0x6C,0x7A,0x41,0x01,0x80,0x8E, ++ 0xF3,0x03,0xF1,0x13,0x48,0x5C,0x0B,0x61,0x19,0xCA,0x4A,0x64,0xCB,0x48,0x04,0x30, ++ 0xC8,0x48,0x34,0x19,0x14,0xB0,0xC9,0x70,0x0B,0x21,0xF0,0x8A,0x48,0x81,0xDA,0x06, ++ 0x00,0x7C,0x47,0x01,0x80,0x0E,0x40,0x29,0x8D,0xCE,0x10,0x02,0x8C,0xBE,0x10,0xD2, ++ 0x88,0xAE,0x18,0x61,0xF6,0x5A,0xD7,0x58,0x98,0x49,0x58,0x91,0xC7,0x7E,0x40,0x5C, ++ 0x65,0x0A,0x14,0x1A,0x92,0x0E,0xE0,0xD8,0x07,0x5C,0x47,0x5C,0x58,0x41,0xCE,0x36, ++ 0x03,0x7C,0x5F,0xD2,0x34,0x09,0x98,0x01,0xE1,0xE3,0x18,0xA2,0xA1,0xE3,0x08,0x44, ++ 0x0D,0x54,0x0B,0x4C,0x42,0xAA,0xC3,0x01,0x51,0x04,0x46,0x91,0xCF,0x06,0x00,0x7C, ++ 0xEF,0x85,0xAF,0x85,0x80,0x3D,0x2C,0x01,0x20,0x01,0x00,0x61,0x4B,0x82,0x1B,0x42, ++ 0xC0,0x00,0x82,0x34,0x30,0x01,0x38,0x01,0x00,0x01,0x80,0x1C,0x80,0x14,0xC0,0x34, ++ 0x00,0x08,0x13,0x19,0xC0,0x00,0x12,0x90,0xC0,0x10,0x04,0x21,0x90,0x2C,0xF0,0x82, ++ 0x80,0x24,0x60,0x01,0x83,0x46,0xF0,0x10,0xDA,0x34,0x00,0x90,0xC0,0xD0,0x1C,0x19, ++ 0x16,0xD8,0xC0,0x90,0x34,0x21,0xF8,0xB2,0x68,0x01,0x80,0x56,0xF0,0x50,0x1B,0x61, ++ 0x1A,0xD2,0x5A,0xFA,0xC0,0x90,0x1E,0x19,0xC0,0x90,0x12,0xD8,0xC0,0x90,0x3E,0x21, ++ 0xF8,0xBA,0x66,0x29,0x83,0x4E,0xE0,0x18,0xD2,0x34,0x00,0xD8,0xC0,0x90,0x1E,0x19, ++ 0x16,0xD8,0xC0,0x90,0x1E,0x21,0xF0,0x9A,0x98,0x1C,0x68,0x69,0x83,0x5E,0xE0,0x50, ++ 0x1A,0x61,0x18,0xD2,0x5E,0x92,0xC2,0x90,0xC0,0x88,0x12,0x19,0x14,0x90,0xC0,0x50, ++ 0x0A,0x21,0xF0,0x8A,0x88,0x14,0x08,0x09,0x89,0x0C,0x70,0x41,0xD1,0x3E,0x78,0x41, ++ 0xD0,0x2E,0xC8,0x1C,0x48,0x41,0xD1,0x16,0xC9,0x14,0x48,0x41,0xD8,0x0E,0x08,0x01, ++ 0x88,0x0C,0x08,0x19,0x80,0x2F,0xC8,0x47,0x10,0x82,0xED,0x3E,0x10,0xC2,0xED,0x2E, ++ 0xCC,0x1C,0x10,0x42,0xE8,0x16,0xC8,0x14,0x10,0x42,0xE4,0x0E,0x00,0x01,0x80,0x0C, ++ 0xC0,0x0C,0x40,0x01,0x80,0x36,0xC0,0x24,0x78,0x08,0xC6,0x48,0x82,0x48,0xD2,0x00, ++ 0xCC,0x2C,0x00,0x44,0xE7,0x20,0x93,0x25,0x64,0x31,0x98,0x9E,0xE7,0x68,0x93,0x6D, ++ 0x6C,0x71,0x98,0x4E,0x3B,0x4F,0xA8,0x85,0x48,0x9A,0x01,0x01,0x06,0x44,0x04,0x44, ++ 0x82,0x43,0x80,0x43,0x40,0x8A,0x29,0x09,0x80,0x01,0xE4,0x0B,0x18,0x4A,0xA1,0x0B, ++ 0x31,0x22,0xE0,0x01,0x07,0x9F,0xBA,0xFF,0xE9,0xCF,0x43,0x82,0xC0,0x03,0x40,0x01, ++ 0x81,0x1E,0x48,0x52,0x02,0xC1,0xC8,0x01,0xB1,0x43,0x40,0x42,0x51,0x62,0x49,0x42, ++ 0xC0,0x01,0x82,0x1F,0xF7,0x0F,0xBD,0xFF,0xE9,0x4F,0x49,0x22,0x52,0x42,0xC9,0x01, ++ 0x40,0x1A,0x81,0x27,0xC1,0x17,0x4C,0x0A,0x52,0x2A,0xC9,0x01,0x40,0x02,0x81,0x27, ++ 0xFF,0x0F,0xBC,0xFF,0xEF,0x3F,0xEE,0x03,0x40,0x01,0x80,0x16,0xE8,0x03,0x47,0x11, ++ 0x89,0x1E,0x40,0x02,0x41,0x0B,0x18,0x4A,0x00,0x0B,0x40,0xC2,0x0E,0x11,0x98,0x0B, ++ 0x32,0x0A,0xC8,0x01,0x40,0xB2,0x80,0x27,0xE8,0xC7,0x4D,0xA2,0x42,0xA2,0xC8,0x01, ++ 0x86,0x27,0xE0,0x7F,0xBF,0xFF,0xEF,0x4F,0xB9,0xFF,0xFF,0xDF,0x48,0x7A,0x40,0x82, ++ 0xC8,0x01,0x82,0x27,0xE0,0xF7,0x4A,0x6A,0x12,0x01,0xC8,0x01,0x40,0x62,0x58,0x92, ++ 0x85,0x17,0xE8,0x57,0xBD,0xFF,0xF7,0xB7,0xBB,0xFF,0xE7,0xD7,0x48,0x3A,0x40,0x42, ++ 0xC8,0x01,0x82,0x0F,0xF0,0x6F,0x80,0x07,0xDF,0x47,0xB8,0xFF,0xE7,0xFF,0xEF,0x03, ++ 0x45,0x31,0x88,0x46,0xE8,0x85,0x03,0x00,0x00,0x00,0x00,0x01,0x00,0xC0,0x02,0x01, ++ 0x00,0xA0,0x07,0x01,0x48,0xA0,0x02,0x01,0x38,0x81,0x00,0x00,0x00,0x80,0x00,0x01, ++ 0x58,0xC0,0x02,0x01,0xF8,0x00,0x06,0x42,0x18,0xD8,0x05,0x00,0xA8,0x85,0x33,0x22, ++ 0xF0,0x03,0x83,0x07,0xF1,0xA7,0x41,0x9A,0x2C,0x01,0x00,0x2B,0xB5,0x2B,0x01,0xB1, ++ 0xAF,0x2A,0xB8,0xFF,0xE4,0x1F,0xA5,0x01,0xFA,0x03,0x31,0x08,0x42,0x72,0x71,0x48, ++ 0x1C,0x0B,0x5C,0x0B,0x02,0x48,0x1A,0x0B,0x09,0x2B,0xFE,0x0B,0x30,0x48,0xA8,0x16, ++ 0x0E,0x09,0x04,0x0B,0x1B,0x2B,0xE8,0x85,0xAD,0x85,0x87,0x9D,0x42,0x32,0xC1,0x01, ++ 0x42,0x0B,0x40,0x48,0x00,0x48,0x02,0x0B,0x51,0x22,0x49,0x2A,0x40,0x2A,0x81,0x0F, ++ 0xC1,0x97,0x67,0x1A,0x35,0x2A,0xA9,0x01,0x01,0xBF,0x41,0x0A,0xBE,0xFF,0xFF,0x77, ++ 0x52,0x03,0x81,0x01,0xE7,0x03,0x40,0x79,0x80,0x0E,0x51,0xEA,0x48,0xEA,0x00,0x01, ++ 0x58,0xD2,0x80,0x07,0xF8,0x2F,0x51,0xD2,0x48,0xD2,0x00,0x09,0x58,0xBA,0x80,0x07, ++ 0xF9,0xFF,0x50,0x03,0x80,0x01,0xE2,0x03,0x40,0x59,0x8D,0x86,0x40,0xB2,0x48,0xAA, ++ 0x88,0xA1,0x11,0x01,0xD5,0x3B,0xD7,0x1B,0x18,0xFA,0x42,0x5C,0x44,0x34,0xD8,0xD8, ++ 0x04,0x1C,0xE0,0x00,0xE2,0x48,0xE4,0x90,0x95,0x95,0x14,0xD2,0x99,0xAE,0x57,0x03, ++ 0x80,0x01,0xE2,0x03,0x40,0x59,0x85,0x2E,0x50,0x42,0x48,0x4A,0x40,0x4A,0x58,0x0D, ++ 0x80,0x0F,0xC0,0xBF,0x40,0x0D,0x80,0x07,0xDF,0xFF,0xE9,0x43,0x46,0x31,0x80,0x26, ++ 0x87,0x9D,0xE9,0x85,0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x58,0xC0,0x02,0x01, ++ 0x00,0xC0,0x00,0x01,0x00,0xA0,0x07,0x01,0x18,0xC0,0x07,0x01,0x4C,0xFA,0x6F,0x54, ++ 0x82,0x13,0x68,0x54,0x80,0x13,0x32,0x52,0x92,0x01,0xF5,0x93,0x80,0x13,0xCC,0x4B, ++ 0x83,0x0B,0x3E,0x82,0xA8,0x85,0xF3,0x24,0x63,0xC2,0xFF,0x23,0x11,0x22,0xCC,0x56, ++ 0x23,0x21,0x19,0x02,0x60,0xB2,0xCF,0x00,0x23,0x29,0x0A,0x20,0xCE,0x00,0x50,0x24, ++ 0x58,0x2C,0x48,0x09,0x8E,0x26,0x50,0x0C,0x23,0xF9,0xA7,0x49,0xD4,0x08,0x93,0x65, ++ 0x50,0x09,0x88,0x26,0x58,0x0C,0x10,0xC9,0x0A,0x90,0xD2,0x88,0x90,0x6D,0xD4,0x0B, ++ 0xD0,0x13,0x0A,0x48,0x00,0x90,0x1A,0x8A,0x81,0xCB,0x48,0x08,0x81,0xCB,0x4A,0x48, ++ 0x81,0xCB,0x0C,0x08,0x38,0x50,0x79,0x90,0x1E,0x8A,0x80,0xCB,0x58,0x04,0x8A,0xC3, ++ 0xC2,0x83,0xE9,0x00,0x83,0x83,0xE9,0x85,0xAC,0x85,0x87,0x2D,0x0F,0x01,0x00,0x0D, ++ 0x40,0x2E,0x90,0x24,0x86,0x1C,0x40,0xEA,0xFA,0x2B,0xF8,0x1B,0x06,0x01,0x60,0xFA, ++ 0x51,0xFA,0xC6,0x33,0x70,0x59,0x85,0x1E,0xE4,0x00,0x92,0x05,0x17,0x82,0x9C,0xC6, ++ 0x50,0xE2,0x46,0x83,0x31,0x09,0x18,0x82,0x07,0x83,0x00,0xF9,0x80,0x03,0x69,0x01, ++ 0x80,0xBE,0x08,0x01,0x50,0x1D,0x00,0x01,0x2E,0x29,0x62,0x8A,0x08,0x68,0x03,0x77, ++ 0x32,0x21,0x19,0x32,0xCB,0xB0,0xC9,0xB0,0xD0,0xB3,0x75,0x09,0x88,0x2E,0x80,0x83, ++ 0xE6,0x48,0x92,0x4D,0xE0,0x90,0x4A,0x29,0x82,0x1E,0xE0,0x00,0x94,0x05,0x16,0xC2, ++ 0x98,0x76,0x8F,0x0C,0x60,0x4A,0x6E,0x1D,0x36,0x01,0x78,0x22,0xB9,0x01,0x06,0x0F, ++ 0x70,0x01,0x88,0x9E,0x50,0x15,0x90,0x04,0x11,0x01,0xC0,0x43,0x30,0x1A,0x31,0x8A, ++ 0xBC,0xFF,0xFF,0x47,0xE5,0x68,0xE3,0xC3,0xCE,0x0C,0x48,0x00,0x08,0x00,0x1E,0x42, ++ 0x8D,0x03,0x03,0x59,0x8D,0x03,0xED,0x20,0xE0,0x20,0x03,0x4F,0x50,0x15,0x90,0x04, ++ 0x11,0x01,0xC0,0x43,0x30,0x1A,0x31,0x8A,0xBB,0xFF,0xFF,0xA7,0xE3,0x68,0xEB,0x20, ++ 0xE7,0xB0,0x93,0xB5,0xC4,0x0C,0x10,0x32,0x9D,0xD6,0xE6,0xC3,0x1E,0x01,0x4C,0x08, ++ 0x48,0x01,0x80,0x96,0xC8,0x0C,0x48,0x01,0x81,0x36,0x80,0x03,0xEB,0xC3,0x81,0x03, ++ 0x05,0x59,0x85,0x03,0xE0,0x20,0x05,0x37,0x81,0x03,0xE9,0xC3,0x83,0x03,0x8B,0x1B, ++ 0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x2F,0xC0,0x0C,0x40,0x09,0xC8,0x16, ++ 0x01,0x59,0x85,0x03,0xE1,0x20,0x33,0x02,0xBA,0xFF,0xFF,0x07,0x4A,0x32,0x45,0x43, ++ 0x10,0x01,0x1A,0x82,0x05,0x43,0x4A,0x2A,0x40,0x43,0x1A,0xC2,0x03,0x43,0xE2,0xC3, ++ 0x08,0x11,0x18,0x42,0xA0,0xC3,0x83,0x2D,0xEF,0x85,0xAF,0xFD,0x80,0x0D,0xFC,0x54, ++ 0x30,0x32,0x30,0x62,0x6E,0xAA,0xAC,0x01,0x50,0x09,0x88,0x4E,0x00,0x0F,0x80,0x0F, ++ 0xC1,0xCF,0xE1,0x43,0x37,0x00,0xAA,0xD6,0xE5,0x43,0x09,0xF9,0x01,0x42,0xA0,0x43, ++ 0x04,0x09,0x30,0x22,0x51,0xAA,0x04,0x8F,0x60,0x01,0xC1,0x2E,0xF7,0x00,0x0B,0x01, ++ 0x1A,0x42,0x08,0x83,0x30,0x0A,0x01,0x17,0x02,0xF9,0x0F,0x83,0x08,0x01,0x19,0x01, ++ 0x08,0x9B,0x04,0x01,0x00,0x4F,0x78,0x01,0x88,0x16,0x18,0x01,0x00,0x9B,0x06,0x17, ++ 0xC6,0x9B,0x01,0x9B,0xCA,0xB0,0xE7,0x00,0x94,0x05,0x14,0x42,0x9B,0x9E,0x37,0x02, ++ 0x40,0x01,0x80,0x26,0x04,0xA1,0x00,0x83,0x04,0x01,0x30,0x22,0x00,0x0F,0x00,0x21, ++ 0x03,0x83,0xD4,0x00,0x92,0x25,0x44,0x83,0x08,0x01,0x1C,0x42,0x01,0x83,0xE2,0x43, ++ 0x37,0x00,0xAA,0xE6,0xE5,0x43,0x09,0xF9,0x01,0x42,0xA0,0x43,0x66,0x01,0x88,0x5E, ++ 0xC0,0x24,0x40,0x09,0x88,0x7E,0x05,0x01,0x02,0x83,0x44,0x83,0x08,0x01,0x1C,0x42, ++ 0x05,0x83,0x3A,0x47,0xAC,0x9D,0x87,0x1D,0x20,0x01,0x00,0x01,0x80,0x0C,0x70,0x15, ++ 0x40,0x52,0xF3,0x03,0xEE,0x00,0x92,0x3D,0x6E,0x42,0xAB,0x01,0x00,0xAF,0x81,0x07, ++ 0xF9,0x0F,0xE7,0x43,0x30,0x00,0xA2,0x1E,0x40,0x22,0xF3,0x03,0x17,0xC2,0x9D,0xB6, ++ 0x40,0x12,0xF3,0x03,0x10,0xC2,0x9D,0x06,0x21,0x11,0xE0,0x43,0x08,0xF9,0x05,0x42, ++ 0xA3,0x43,0x41,0x32,0x46,0x0B,0x14,0x79,0x00,0x8A,0x48,0x09,0x88,0x9E,0x08,0x01, ++ 0x0E,0x0B,0x44,0x0B,0x83,0x8B,0xE1,0xB0,0xE7,0x20,0x93,0x25,0x60,0x11,0x88,0x56, ++ 0x30,0x5A,0xD3,0xCB,0xD4,0x1C,0x10,0x8A,0x8A,0x2E,0xD0,0xCB,0xD4,0x24,0x10,0x8A, ++ 0x88,0x0E,0x08,0x09,0x8F,0x0C,0x08,0x01,0x08,0x0B,0x0A,0x01,0x08,0x0B,0x0C,0x81, ++ 0x02,0x0B,0x44,0x0B,0x10,0x01,0x1C,0x8A,0x00,0x0B,0x62,0x11,0x88,0x4E,0xC6,0x0C, ++ 0x3A,0x0F,0x4B,0x52,0x58,0x54,0x86,0x13,0x12,0x01,0x80,0x13,0xE4,0x4B,0x82,0x0B, ++ 0x4A,0x62,0x8A,0x01,0x5E,0x53,0x84,0x13,0x58,0x53,0x8A,0x13,0x12,0x91,0x88,0x13, ++ 0x14,0x19,0x88,0x13,0x4E,0x53,0x8E,0x13,0x48,0x53,0x94,0x13,0x4A,0x4B,0x92,0x0B, ++ 0x0C,0x09,0x90,0x0B,0x3F,0x82,0xAB,0x85,0x80,0x4D,0x34,0x22,0x30,0x01,0x00,0x01, ++ 0x80,0x2C,0x38,0x01,0x4C,0xCA,0xD1,0x43,0xD2,0x4B,0x1E,0x42,0x81,0x14,0x40,0xC2, ++ 0x80,0x61,0x80,0x24,0xC0,0x61,0x80,0x1C,0x60,0x09,0x80,0x0E,0x60,0x29,0x88,0x76, ++ 0x60,0x09,0x88,0x1E,0x70,0xD2,0xB1,0x2C,0x78,0xD2,0x01,0x27,0x73,0xD2,0xE1,0x80, ++ 0x81,0x2C,0x78,0xC2,0xF8,0x81,0x41,0x35,0xBA,0xFF,0xF7,0xC7,0x00,0x3F,0x60,0x21, ++ 0x89,0x2E,0x70,0xB2,0x47,0x35,0xB8,0xFF,0xF9,0xE7,0x7D,0x92,0xB9,0xA1,0x6A,0x3A, ++ 0xA9,0x01,0xE6,0x43,0x08,0xF9,0x05,0x42,0xA1,0x43,0xE1,0x43,0x08,0x01,0x19,0x42, ++ 0xA1,0x43,0x41,0x4A,0x42,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x4A,0x3A,0x41,0x43, ++ 0x10,0x01,0x1C,0x82,0x01,0x43,0x4A,0x1A,0x40,0x43,0x10,0x09,0x18,0x82,0x00,0x43, ++ 0x0C,0x09,0x00,0x01,0xBA,0xFF,0xFF,0xB7,0x42,0x09,0x88,0x66,0x62,0x21,0x88,0x5E, ++ 0x10,0x09,0x90,0x04,0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF,0xF0,0xB7,0x17,0x09, ++ 0x90,0x04,0x10,0x01,0x08,0x59,0x40,0x35,0x37,0x9A,0xB8,0xFF,0xF0,0x77,0x17,0x09, ++ 0x90,0x04,0x10,0x01,0x09,0x31,0x30,0xC2,0x37,0x9A,0xB8,0xFF,0xF0,0x37,0x17,0x09, ++ 0x90,0x04,0x40,0xA2,0x10,0x01,0x08,0x71,0xC0,0x21,0x32,0x9A,0xBE,0xFF,0xF7,0xEF, ++ 0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x30,0x9A,0xC0,0x24,0xBE,0xFF,0xF7,0xAF, ++ 0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x18,0x09,0x00,0xCF,0x00,0xC0,0x00,0x01, ++ 0x00,0xA0,0x07,0x01,0xFF,0xFF,0xFF,0xFF,0x00,0xF8,0x07,0x00,0x58,0x20,0x00,0x01, ++ 0x90,0xE4,0x03,0x00,0xF8,0x00,0x06,0x42,0x00,0x00,0x06,0x42,0x80,0x01,0x06,0x42, ++ 0x10,0xC0,0x00,0x01,0x40,0x60,0x07,0x01,0x18,0xC0,0x07,0x01,0x38,0xC0,0x05,0x01, ++ 0xC7,0x1C,0xB8,0xFF,0xF2,0x97,0x05,0x27,0x60,0x09,0x80,0x0E,0x62,0x29,0x88,0x06, ++ 0x60,0x09,0x88,0x76,0x10,0x09,0x90,0x04,0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF, ++ 0xF0,0x27,0x15,0x01,0x90,0x04,0x30,0x9A,0xC8,0x14,0xC0,0x2C,0xBC,0xFF,0xF7,0xEF, ++ 0x00,0x7F,0x10,0x11,0x90,0x04,0x10,0x09,0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF, ++ 0xF0,0xA7,0x14,0x11,0x90,0x04,0x10,0x01,0x30,0x9A,0xC8,0x14,0xC7,0x2C,0xB8,0xFF, ++ 0xF0,0x67,0x14,0x09,0x90,0x04,0x10,0x01,0x08,0x21,0x40,0x35,0x37,0x9A,0xB8,0xFF, ++ 0xF0,0x27,0x14,0x09,0x90,0x04,0x10,0x01,0x09,0x41,0x31,0xC2,0x37,0x9A,0xB8,0xFF, ++ 0xF0,0xE7,0x13,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x30,0x9A,0xC7,0x24,0xB8,0xFF, ++ 0xF0,0xA7,0x13,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x18,0x09,0xC7,0x1C,0xB8,0xFF, ++ 0xF1,0x67,0xE3,0x43,0x08,0xF9,0x06,0x42,0xA5,0x43,0x41,0x32,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x47,0x22,0x0D,0x01,0x08,0x0B,0x0A,0x01,0x02,0x0B,0x44,0x0B, ++ 0x10,0x01,0x1C,0x8A,0x00,0x0B,0x82,0x4D,0xEB,0x85,0xAF,0x85,0x67,0xFA,0xEC,0x03, ++ 0x28,0x01,0x40,0x09,0x87,0x16,0xE8,0x03,0x40,0x29,0x88,0x5E,0x71,0xE2,0xC4,0x83, ++ 0x40,0x11,0x98,0x26,0xEF,0x03,0xBF,0xFF,0xF1,0xF7,0x87,0xAB,0xEA,0x85,0xE3,0x00, ++ 0x83,0x83,0xE9,0x85,0xE8,0x03,0x47,0x21,0x8F,0x26,0xB8,0xFF,0xF0,0xA7,0x07,0x19, ++ 0xAB,0x03,0xEF,0x85,0xE8,0x03,0x47,0x19,0x87,0xDE,0xEF,0x03,0x47,0x31,0x80,0xC6, ++ 0x4D,0x72,0xCC,0x01,0xF8,0x43,0x40,0x01,0x88,0x3E,0x30,0x42,0x80,0x01,0xF6,0x13, ++ 0x50,0x31,0x98,0x3E,0xE0,0x03,0x34,0x00,0xAC,0x26,0x40,0x42,0xC4,0x01,0xE3,0x03, ++ 0x40,0x01,0x80,0xA6,0xE8,0x03,0x47,0x01,0x8E,0x1E,0x57,0x44,0x47,0x31,0x88,0x06, ++ 0x45,0x22,0x0C,0x59,0x82,0x0B,0x80,0x2B,0x86,0x2B,0x84,0x2B,0x8A,0x2B,0x88,0x2B, ++ 0x8B,0x0B,0x44,0xE2,0x42,0x0B,0x40,0x48,0x00,0x48,0x02,0x0B,0xEF,0x85,0xBB,0xFF, ++ 0xEB,0xDF,0xEB,0x85,0xA8,0xC5,0x27,0x01,0x30,0x1A,0x00,0x09,0x4B,0xBA,0x6B,0xD2, ++ 0x30,0x01,0x59,0x51,0x80,0xE6,0xE1,0x4E,0x79,0xC2,0xE3,0xD3,0x87,0x27,0xE8,0xDF, ++ 0x61,0x52,0x20,0x09,0x39,0x61,0x62,0x52,0x71,0x61,0x62,0x92,0x40,0x7A,0x13,0x31, ++ 0xC0,0x01,0x55,0x03,0x80,0x01,0x5A,0xC9,0x80,0xAE,0xE1,0x4E,0x59,0x59,0x80,0x56, ++ 0x59,0x61,0x80,0x66,0x59,0x69,0x88,0xBE,0x06,0x29,0xA8,0x43,0x21,0x09,0x00,0x9F, ++ 0x59,0xD1,0x80,0x6E,0x59,0x01,0x89,0x7E,0xA8,0x53,0x26,0x09,0x08,0x59,0xA5,0x0B, ++ 0x00,0x57,0x01,0x39,0xA9,0x43,0x06,0x3F,0x86,0x07,0xE8,0xF7,0x00,0x27,0x19,0x12, ++ 0xA1,0xD3,0x01,0x0F,0x00,0x41,0x18,0x12,0xA0,0xD3,0x01,0xEF,0x06,0x11,0xA8,0x43, ++ 0x20,0x09,0x00,0xCF,0x06,0x01,0xA8,0x43,0x41,0x43,0x19,0x82,0x00,0x43,0x01,0x9F, ++ 0xA8,0x43,0x26,0x09,0x00,0x87,0x00,0x19,0xA8,0x43,0x26,0x09,0x00,0x67,0x00,0x21, ++ 0xA8,0x43,0x26,0x09,0x06,0x47,0xA8,0x53,0x26,0x09,0x08,0x69,0xA0,0x0B,0x00,0x1F, ++ 0xA8,0x53,0x26,0x09,0x08,0x79,0xA7,0x0B,0x60,0x01,0x80,0x66,0x40,0x82,0x42,0x0B, ++ 0x30,0x48,0xA8,0x2E,0x08,0x81,0x06,0x0B,0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B, ++ 0x45,0x43,0x19,0x82,0x07,0x43,0xE9,0xC5,0xAC,0x8D,0x87,0x25,0x40,0x4A,0x82,0x14, ++ 0x45,0x12,0xC2,0x01,0xD6,0x2B,0xD4,0x33,0x08,0x01,0xB0,0x0B,0x61,0x1A,0xE2,0x0B, ++ 0x10,0xF9,0x05,0x8A,0xA1,0x0B,0xE1,0x0B,0x10,0x01,0x19,0x8A,0xA2,0x0B,0x51,0x02, ++ 0x92,0x01,0x46,0x8B,0x18,0x01,0x1A,0xCA,0x01,0x8B,0x52,0xBA,0x44,0x8B,0x1A,0x01, ++ 0x1A,0xCA,0x00,0x8B,0x79,0x9A,0x41,0xCB,0x10,0x09,0x18,0x8A,0x00,0xCB,0x51,0x03, ++ 0x80,0x01,0xE2,0x0B,0x49,0x79,0x87,0xDE,0xE6,0x03,0x40,0x69,0x88,0x46,0x09,0xA9, ++ 0x07,0x91,0xB8,0xFF,0xE8,0x3F,0x46,0x09,0x89,0x0E,0x32,0x42,0x1A,0x82,0x03,0x08, ++ 0x10,0x09,0x88,0x1C,0x94,0x04,0x90,0x4D,0x18,0x01,0xC0,0x14,0xBB,0xFF,0xEF,0x2F, ++ 0x42,0xC3,0x41,0x00,0x01,0x00,0x02,0xC3,0x40,0x5A,0x11,0x09,0x90,0x04,0xC8,0x1C, ++ 0x14,0x01,0x90,0x4D,0x37,0x9A,0xB8,0xFF,0xE8,0xC7,0xC2,0x24,0x15,0x09,0xC8,0x48, ++ 0xE8,0x48,0x90,0x04,0x00,0x48,0x12,0x01,0x1F,0x09,0xB8,0xFF,0xE8,0x77,0x02,0xF7, ++ 0x08,0xA1,0x00,0x91,0xBC,0xFF,0xEF,0xF7,0x40,0x09,0x88,0xC6,0x18,0xAA,0x13,0x09, ++ 0x20,0x40,0x63,0x08,0x90,0x04,0x30,0x9A,0xC7,0x14,0xB8,0xFF,0xE8,0xF7,0x01,0x77, ++ 0x08,0xB1,0x00,0x91,0xBC,0xFF,0xEF,0x77,0x40,0x09,0x88,0x46,0xC0,0x24,0x10,0x09, ++ 0xC8,0x48,0xED,0x48,0x00,0x48,0x32,0x9A,0x97,0x04,0xB8,0xFF,0xE9,0x77,0xE1,0x03, ++ 0x08,0xF9,0x06,0x42,0xA1,0x03,0x41,0xC3,0x42,0x00,0x02,0x00,0x00,0xC3,0x41,0x32, ++ 0x0A,0x01,0x0F,0x0B,0x0C,0x01,0x00,0x0B,0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B, ++ 0x28,0xCF,0x00,0x00,0xF8,0x00,0x06,0x42,0x80,0x01,0x06,0x42,0x00,0xC0,0x05,0x01, ++ 0x00,0x70,0x00,0x01,0x58,0x20,0x00,0x01,0x10,0x00,0x00,0x42,0x00,0xC0,0x06,0x01, ++ 0x00,0x00,0x00,0x42,0x18,0xC0,0x07,0x01,0x08,0x40,0x01,0x01,0x52,0xCA,0x42,0x83, ++ 0x02,0x83,0x42,0xCA,0xF7,0x0B,0x48,0xF9,0x90,0x16,0xF0,0x0B,0xE0,0x48,0xB2,0x0B, ++ 0xF0,0x03,0x40,0xC1,0x90,0x0E,0x00,0x01,0x03,0x83,0x3C,0x82,0x4C,0x9A,0x4A,0x53, ++ 0x58,0x8A,0xE2,0xC3,0x1C,0x12,0x0C,0x53,0x10,0x43,0x02,0x09,0xB3,0xC3,0x38,0x82, ++ 0xAA,0x85,0x40,0x72,0x84,0x01,0x42,0x0B,0x10,0x01,0x1C,0x8A,0x02,0x0B,0x54,0x62, ++ 0x4A,0x4A,0x42,0x62,0x85,0x27,0xC0,0xAF,0xEF,0x85,0xA8,0xC5,0x46,0x32,0x82,0x01, ++ 0xE2,0x0B,0x78,0x4A,0x30,0x48,0xAC,0x46,0xE2,0x0B,0x10,0x01,0x18,0x8A,0xA0,0x0B, ++ 0x44,0xC3,0x0B,0x01,0x1B,0x42,0x04,0xC3,0xE8,0xC5,0x17,0x01,0x0D,0xD3,0x45,0xCB, ++ 0x6E,0xEA,0x01,0x79,0x01,0x0A,0x30,0x72,0x59,0x02,0xB2,0x01,0x61,0x44,0x57,0x63, ++ 0x48,0x09,0x80,0xDE,0x48,0x29,0x80,0x46,0x4B,0x41,0x88,0x46,0x8F,0x93,0x43,0xCB, ++ 0x38,0x48,0x8E,0x16,0x05,0x81,0x00,0xC3,0xED,0xC5,0x0F,0xD3,0x10,0xC2,0x8C,0x16, ++ 0x07,0x29,0x05,0xC3,0x01,0x3F,0xE0,0x0A,0x02,0xCB,0xE7,0x00,0x97,0x05,0x24,0x44, ++ 0x40,0x89,0x9A,0x06,0x20,0x5C,0x07,0xA1,0x07,0xC3,0xED,0xC5,0xC8,0x8B,0x4B,0x11, ++ 0x91,0xE6,0x61,0x7A,0x48,0x01,0x88,0x2E,0x43,0xC3,0x07,0x04,0x41,0x6A,0x11,0x43, ++ 0x21,0x54,0x07,0xF7,0x43,0xC3,0x47,0x0C,0x10,0x48,0xC0,0x40,0x96,0x25,0x04,0x89, ++ 0x11,0x00,0xD0,0x00,0x40,0x01,0xC1,0x76,0x97,0x05,0xBF,0xFF,0xF1,0x1F,0x44,0x32, ++ 0x11,0x22,0x8C,0x76,0x00,0x09,0x80,0x07,0xC8,0xD7,0x03,0xC1,0xB1,0x43,0x49,0x02, ++ 0x00,0x09,0x80,0x43,0x00,0x2F,0x41,0xC2,0x86,0x01,0xED,0x03,0x08,0x69,0x18,0x48, ++ 0x40,0x01,0x88,0x36,0xD2,0x00,0x43,0x81,0xC7,0x0E,0x20,0x44,0x07,0xCF,0x20,0x5C, ++ 0x00,0xBF,0x40,0xD2,0xC1,0x00,0x41,0x19,0xC7,0x1E,0x20,0x44,0x41,0xC2,0x10,0x43, ++ 0x03,0x7F,0xD0,0x00,0x40,0xB1,0xC1,0x66,0x20,0x44,0x07,0x57,0x10,0xC2,0x84,0x46, ++ 0x41,0xCB,0xA7,0x0A,0x62,0x44,0xE7,0x00,0x97,0x05,0x24,0x44,0x40,0x89,0x9A,0x06, ++ 0x23,0x5C,0xCF,0x83,0xE3,0x00,0x8A,0x83,0x05,0x81,0x00,0xC3,0xED,0xC5,0x07,0xD3, ++ 0xE8,0xC5,0x07,0x00,0x10,0x00,0x00,0x42,0x00,0xC0,0x00,0x01,0xF8,0x00,0x06,0x42, ++ 0x58,0xC0,0x02,0x01,0x00,0xA0,0x07,0x01,0x80,0x01,0x06,0x42,0xF8,0xFF,0x07,0x00, ++ 0x00,0x80,0x00,0x01,0x58,0x20,0x00,0x01,0x88,0x76,0x00,0x00,0x77,0x81,0xF8,0xFF, ++ 0xF8,0x02,0x07,0x00,0xA8,0x85,0x80,0x07,0xC8,0x77,0x65,0x32,0xE8,0x03,0x47,0x01, ++ 0x80,0x26,0x40,0x31,0x8F,0xD6,0xBF,0xFF,0xDF,0x3F,0x38,0xBF,0xBB,0xFF,0xD7,0x5F, ++ 0x38,0xA7,0x07,0x00,0x00,0xC0,0x05,0x01,0xAE,0xC5,0x6F,0xDA,0x03,0x41,0x83,0x43, ++ 0x01,0x09,0x80,0x43,0x0F,0x01,0x81,0x4B,0x15,0x19,0x80,0x53,0x13,0x41,0x89,0x53, ++ 0x17,0x69,0x89,0x53,0x15,0x69,0x88,0x53,0x11,0x92,0x32,0x7A,0xBD,0x01,0x15,0xD4, ++ 0x17,0xA1,0x1D,0x54,0x32,0x62,0xA1,0x01,0x8D,0x03,0x8B,0x03,0x07,0x41,0x88,0x03, ++ 0x11,0x51,0x90,0x13,0x13,0xA1,0x90,0x13,0x90,0x0B,0x0F,0x81,0x9B,0x0B,0x99,0x03, ++ 0x0F,0x01,0x98,0x4B,0x0D,0x71,0x90,0x4B,0x17,0x31,0x90,0x53,0x98,0x4B,0x0B,0x31, ++ 0x98,0x4B,0x09,0x01,0x99,0x4B,0xA5,0x43,0x03,0x81,0xA1,0x43,0x03,0x51,0x80,0x03, ++ 0x05,0xB1,0x87,0x03,0x07,0x51,0x80,0x03,0x01,0xB1,0x8F,0x03,0x05,0x29,0x94,0x03, ++ 0x01,0x51,0x28,0x44,0x03,0xF9,0x87,0x49,0x34,0x32,0xB1,0x01,0x00,0x84,0x01,0xC9, ++ 0x0B,0x00,0x02,0x84,0x04,0x79,0x10,0x00,0x05,0x83,0x43,0xC2,0x00,0x83,0x05,0x01, ++ 0x99,0x83,0x31,0x02,0x0C,0x51,0x80,0x91,0x87,0x27,0xD0,0x87,0x05,0xB1,0xB7,0xC3, ++ 0x07,0xA1,0xB0,0xC3,0x07,0x01,0xA8,0xC3,0x09,0x01,0x30,0x02,0x80,0x01,0xA2,0x0B, ++ 0xA0,0x0B,0x0E,0xC1,0xA8,0x0B,0x08,0x51,0xAE,0x0B,0x0A,0x41,0x1F,0x0C,0x0E,0xF9, ++ 0x89,0x21,0x00,0xCC,0x0E,0x99,0x18,0x4A,0xA8,0x0B,0x14,0xA1,0xA8,0x13,0xB6,0x0B, ++ 0x0A,0xA1,0xB0,0x0B,0x0A,0x51,0x88,0x0B,0x14,0xF1,0x88,0x13,0x0E,0x21,0x8B,0x0B, ++ 0x0A,0x59,0x0D,0x0C,0x08,0xE1,0x90,0x0B,0x08,0xC9,0x99,0x0B,0x0A,0x31,0x98,0x0B, ++ 0x08,0xF9,0x8F,0x09,0x08,0x0C,0x0E,0x51,0xB8,0x4B,0x0B,0x01,0x32,0x4C,0xA3,0x0B, ++ 0x0D,0x21,0xB0,0x8B,0x0B,0x31,0xB0,0x8B,0x09,0x19,0x0D,0x4C,0x0C,0xA1,0xB0,0x0B, ++ 0x0E,0x51,0xB0,0x0B,0x0C,0x01,0xA0,0x0B,0x08,0x19,0xBC,0x0B,0x09,0x31,0x80,0x0B, ++ 0x18,0x01,0x30,0x0A,0xCE,0x01,0x9B,0x5B,0xA2,0x5B,0x88,0x01,0xB2,0x53,0xB0,0x53, ++ 0x14,0xE1,0xB1,0x53,0x16,0x41,0xB0,0x53,0x10,0x11,0xB8,0x53,0x12,0xB1,0xB8,0x53, ++ 0x14,0x19,0xB8,0x53,0x48,0x52,0x04,0x0B,0x8C,0x1B,0x48,0x52,0xC6,0x01,0x34,0x0B, ++ 0x88,0x91,0x38,0x0B,0x8A,0xE1,0x3E,0x0B,0x0C,0xC1,0x40,0x3A,0x84,0x27,0xD0,0x77, ++ 0x40,0x2A,0x0C,0xC1,0xC0,0x81,0x81,0x27,0xD4,0x4F,0x4C,0x12,0x43,0x1A,0xCC,0x31, ++ 0x00,0x0B,0xCE,0x71,0x00,0x0B,0x8C,0xA1,0x08,0x0B,0x88,0xC1,0x0A,0x0B,0xCA,0x21, ++ 0x01,0x0B,0xCA,0xC1,0x05,0x0B,0x88,0xA1,0x0D,0x0B,0xCC,0xC1,0x10,0x0B,0xFA,0x48, ++ 0x10,0x0B,0xF8,0x48,0x0F,0x0B,0xEE,0xC5,0xA8,0x85,0x09,0x01,0x63,0x92,0x43,0x92, ++ 0xA2,0xE1,0xFE,0x1B,0x01,0x77,0x00,0x21,0x18,0x42,0xCA,0x28,0x00,0x29,0x12,0x79, ++ 0x09,0x00,0xC2,0x40,0x90,0x13,0x10,0x01,0x94,0x13,0x92,0x13,0x10,0x14,0x1E,0x14, ++ 0xE6,0x48,0x92,0x4D,0x17,0x5A,0xC4,0x76,0x07,0x01,0x10,0xF9,0x2D,0x09,0x09,0x68, ++ 0x02,0x37,0x00,0x08,0xCA,0x48,0xC8,0x48,0xB2,0x53,0xB0,0x53,0xE6,0x00,0x92,0x05, ++ 0x17,0x1A,0xC4,0xB6,0xE9,0x85,0xA1,0x85,0x56,0xFA,0x92,0x01,0x08,0x01,0x10,0x8C, ++ 0xD4,0x01,0xB6,0x8B,0xB8,0x8B,0x30,0x9A,0x98,0x01,0xB5,0xCB,0x1C,0xCC,0xBC,0xCB, ++ 0xB0,0xCB,0x22,0x09,0xB0,0xA3,0xA8,0x8B,0xDE,0x01,0xF1,0xDB,0xB0,0x9B,0x32,0x9A, ++ 0x9A,0x01,0xA1,0xCB,0x9A,0x01,0xA1,0xE3,0xA4,0xCB,0xA0,0xA3,0x20,0x41,0x89,0xA3, ++ 0x40,0x09,0x88,0x16,0xA1,0xCB,0xE4,0x85,0x39,0xB7,0xE5,0x85,0x3A,0x82,0x0B,0x08, ++ 0x40,0x9A,0x42,0x13,0x18,0x01,0x01,0xD2,0x90,0x41,0x04,0x13,0x10,0xD0,0x1C,0x8A, ++ 0x0A,0x0B,0x42,0x0B,0x40,0x0B,0x10,0x41,0x18,0x8A,0x04,0x0B,0x0C,0x01,0x00,0x0B, ++ 0x38,0x82,0xAB,0x85,0x40,0x5A,0x42,0x0B,0x30,0x48,0xA8,0x2E,0x08,0x81,0x06,0x0B, ++ 0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B,0x4E,0x32,0x8A,0x01,0x40,0x53,0x3C,0x90, ++ 0x7C,0x90,0x00,0x53,0x41,0x53,0x1C,0x81,0x1C,0xD2,0x00,0x53,0x5E,0x12,0x12,0x09, ++ 0x01,0xD3,0x12,0x91,0x02,0x13,0x46,0x0A,0x40,0x23,0x14,0x61,0x1C,0xA2,0x00,0x23, ++ 0x40,0x23,0x1A,0xA2,0x02,0x23,0x4A,0x23,0x1A,0xA2,0x08,0x23,0x48,0x23,0x18,0xA2, ++ 0x0E,0x23,0x40,0x23,0x1E,0xA2,0x00,0x23,0x42,0x43,0x12,0x01,0x1A,0x82,0x00,0x43, ++ 0x00,0xD1,0x04,0xC3,0x02,0x01,0x0F,0xC3,0xE9,0x85,0x40,0xA2,0x40,0x13,0x08,0x09, ++ 0x18,0x52,0x00,0x13,0x4C,0x13,0x18,0x52,0x0A,0x13,0x48,0x13,0x1A,0x52,0x0C,0x13, ++ 0x40,0x13,0x1E,0x52,0x03,0x13,0x3E,0x82,0x40,0x6A,0x59,0x0B,0x10,0x21,0x18,0x8A, ++ 0x18,0x0B,0x58,0x0B,0x10,0x01,0x1A,0x8A,0x18,0x0B,0x58,0x13,0x08,0x01,0x1C,0x52, ++ 0x19,0x13,0x40,0x22,0x16,0x01,0x80,0x01,0x02,0x13,0x40,0x13,0x1A,0x52,0x00,0x13, ++ 0x48,0xFA,0x40,0x43,0x10,0x01,0x19,0x82,0x03,0x43,0x38,0x82,0xA8,0x85,0x08,0x09, ++ 0x00,0x31,0x80,0x07,0xD0,0x3F,0x0D,0x11,0x00,0x21,0x80,0x07,0xD0,0x1F,0x05,0x09, ++ 0x85,0x07,0xD0,0xFF,0x00,0x31,0x80,0x07,0xD0,0xE7,0x05,0x21,0x85,0x07,0xD0,0xCF, ++ 0x86,0x07,0xD0,0x77,0xE8,0x85,0xA8,0x85,0x40,0x82,0x48,0x5A,0xC0,0xA1,0x12,0x43, ++ 0xBA,0xFF,0xF7,0xD7,0x07,0x09,0xB8,0xFF,0xF8,0x77,0x02,0xA1,0xBB,0xFF,0xFF,0x7F, ++ 0xBB,0xFF,0xFF,0xFF,0xBE,0xFF,0xFF,0x07,0xBD,0xFF,0xFF,0x7F,0xBE,0xFF,0xFF,0xB7, ++ 0x48,0x62,0x00,0x01,0x80,0x43,0xE8,0x85,0x00,0xC0,0x00,0x01,0xC8,0x21,0x01,0x00, ++ 0xF8,0xFF,0x07,0x04,0xD8,0x02,0x06,0x00,0x40,0x60,0x07,0x01,0x58,0xC0,0x02,0x01, ++ 0x10,0x00,0x00,0x42,0x00,0x00,0x00,0x42,0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42, ++ 0x18,0x00,0x02,0x42,0x00,0x80,0x00,0x01,0xA8,0x85,0x80,0x07,0xD0,0xEF,0xEA,0x85, ++ 0xAF,0x85,0xB8,0xFF,0xF0,0xBF,0xE8,0x85,0xA8,0x7D,0x80,0x04,0x88,0x0C,0xC0,0x0C, ++ 0x80,0x14,0xC0,0x04,0x83,0x1C,0x30,0x42,0x40,0x7E,0x80,0x25,0xE8,0x05,0x00,0x00, ++ 0xAC,0xFD,0x87,0x1D,0x30,0x32,0x00,0x01,0x82,0x14,0x00,0x9F,0x44,0xFA,0x0F,0x01, ++ 0x0C,0x0B,0x26,0x01,0xC2,0x14,0x00,0x28,0x7F,0xE2,0x4F,0xC3,0x1F,0x02,0x09,0xC3, ++ 0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x86,0x1F,0xD8,0x37, ++ 0xF8,0x82,0x33,0x0A,0xCF,0x99,0x49,0xC9,0x99,0x3E,0x40,0x91,0xE7,0x16,0x48,0xC3, ++ 0x1F,0x02,0x0D,0xC3,0x40,0x20,0x63,0x01,0x88,0x36,0xD7,0x6C,0x90,0x04,0x10,0x09, ++ 0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x1F,0xDB,0x8F,0xFD,0xA2,0xD0,0x6C,0x90,0x04, ++ 0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x85,0x1F,0xD8,0x47,0xF8,0xBA,0xD3,0x6C, ++ 0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x1F,0xDD,0xFF,0x14,0x3A, ++ 0xE9,0x16,0x30,0x02,0x30,0xE2,0x31,0x3A,0xFD,0x82,0x13,0xC2,0xE3,0x0E,0x98,0xBA, ++ 0x05,0x17,0x10,0x02,0xDB,0x06,0x98,0xA2,0x46,0xE2,0x4E,0x03,0xDE,0x8A,0x0B,0x00, ++ 0xC0,0x00,0xCA,0x24,0x00,0x44,0xC0,0x24,0xE0,0x00,0x84,0x24,0xC2,0x14,0xE0,0x00, ++ 0x90,0x05,0x86,0x14,0xC8,0x2C,0xC0,0x14,0x15,0x42,0x9C,0x3E,0x87,0x3D,0xE8,0x85, ++ 0xAC,0xFD,0x87,0x7D,0x30,0xA2,0x30,0xEA,0xD8,0x0B,0x8B,0x6C,0xD0,0x0B,0x8F,0x64, ++ 0x40,0x01,0x80,0x6E,0x48,0x72,0x06,0x99,0x07,0x43,0x12,0xF9,0x58,0x5A,0x96,0x81, ++ 0x10,0xD3,0x06,0x43,0x00,0xC1,0x83,0x1F,0xF8,0x77,0xFF,0x84,0xB8,0xA1,0x01,0xD7, ++ 0x40,0x3A,0x0E,0x19,0x04,0x0B,0x0A,0x19,0x06,0x0B,0x08,0x09,0xC4,0x84,0x00,0x48, ++ 0xC0,0x38,0x12,0x01,0x30,0x5A,0x31,0x8A,0x00,0x09,0x80,0x17,0xD0,0xE7,0x31,0x01, ++ 0x30,0x1A,0x11,0x09,0x08,0x01,0x44,0x1D,0xA8,0x04,0x80,0x1F,0xDB,0x7F,0xE2,0xB0, ++ 0x91,0xB5,0x77,0x91,0x9D,0xA6,0x47,0xD2,0x40,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B, ++ 0x00,0xE1,0xEC,0x02,0x33,0x00,0xA8,0xE6,0x40,0xB2,0x0D,0x01,0x81,0x0B,0x30,0x12, ++ 0x30,0x4A,0x01,0x11,0x84,0x17,0xC8,0x27,0x30,0x1A,0xA9,0x04,0x08,0x01,0x00,0x11, ++ 0xD0,0x84,0x80,0x17,0xD0,0x77,0x33,0x01,0xC2,0x64,0x00,0x00,0x80,0x74,0x00,0xBF, ++ 0x31,0x5A,0x31,0x92,0x08,0x01,0x00,0x09,0x80,0x17,0xD0,0x6F,0xA8,0x0C,0xA0,0x04, ++ 0x30,0xCA,0x41,0x1D,0xD8,0x84,0xD0,0x64,0xBA,0xFF,0xFF,0x17,0xC6,0x74,0xC8,0x38, ++ 0x09,0x09,0x30,0x5A,0x30,0x92,0x31,0x42,0x87,0x17,0xC8,0xEF,0xE7,0xB0,0x93,0xB5, ++ 0xC4,0x6C,0x10,0x32,0x99,0x26,0x37,0x1A,0xA8,0x04,0x08,0x01,0x00,0x19,0xD0,0x84, ++ 0x82,0x17,0xD0,0x3F,0x31,0x12,0x31,0x4A,0x00,0x01,0x80,0x17,0xCD,0x8F,0xDA,0x03, ++ 0x41,0x01,0x80,0xF6,0x40,0xBA,0x0C,0x09,0x81,0x0B,0x30,0x12,0x30,0x4A,0x01,0x11, ++ 0x82,0x17,0xC8,0x37,0x30,0x5A,0x09,0x01,0x00,0x09,0xD0,0x6C,0x86,0x17,0xC8,0xDF, ++ 0x30,0x1A,0xA9,0x04,0x00,0x11,0xD0,0x84,0xC8,0x6C,0x80,0x17,0xD0,0x57,0xA9,0x0C, ++ 0xA5,0x04,0xD8,0x13,0x30,0xCA,0x41,0x1D,0xDF,0x84,0xB8,0xFF,0xFD,0x4F,0xD8,0x03, ++ 0x06,0x00,0xCA,0x30,0x30,0x1A,0xA9,0x04,0x00,0x19,0xD0,0x84,0xC8,0x6C,0x80,0x17, ++ 0xD0,0xC7,0x08,0x09,0x30,0x5A,0x31,0x42,0xD0,0x6C,0x80,0x17,0xC9,0xE7,0x35,0x12, ++ 0x30,0x4A,0x01,0x01,0x80,0x17,0xC8,0xE7,0x40,0xF2,0x0B,0x01,0x85,0x0B,0xD8,0x03, ++ 0x00,0x27,0x00,0x37,0x05,0x8C,0xE1,0xB0,0xE6,0x00,0x92,0x05,0xD4,0x64,0x10,0x82, ++ 0x9B,0xC6,0x57,0xBA,0x40,0x83,0x08,0x11,0x18,0x42,0x04,0x83,0x87,0x9D,0xE8,0x85, ++ 0xAC,0xFD,0x87,0x1D,0x30,0x7A,0x50,0x01,0x80,0x16,0x00,0x01,0x80,0x0C,0x00,0x0F, ++ 0x00,0x09,0x80,0x0C,0x2A,0x01,0x00,0x47,0xCD,0x64,0x00,0x40,0xC1,0x30,0x32,0x52, ++ 0x08,0x19,0xD8,0x6C,0xC0,0x0C,0x80,0x17,0xC9,0x77,0x04,0x41,0x81,0x1F,0xF8,0x5F, ++ 0x20,0x09,0xC0,0x34,0x80,0x01,0x84,0x14,0x60,0x81,0x99,0x36,0x0B,0xF9,0x47,0x1A, ++ 0x88,0x11,0x18,0x0B,0x42,0x08,0x1B,0x0B,0x03,0x0F,0x40,0x02,0x1F,0x23,0x02,0xF9, ++ 0x4F,0xF2,0x82,0x89,0x88,0x01,0x12,0x43,0x00,0x11,0x80,0x1F,0xF8,0xA7,0xC0,0x14, ++ 0xE0,0x03,0x44,0x01,0x80,0x3E,0x00,0x51,0x80,0x1F,0xF8,0x6F,0x40,0x83,0x41,0x03, ++ 0x30,0x00,0xA8,0x86,0x07,0x5F,0x00,0xF9,0x4C,0xA2,0x82,0x89,0x88,0x01,0x12,0x43, ++ 0x00,0x09,0x80,0x1F,0xF9,0x07,0x40,0x83,0x40,0x03,0x30,0x00,0xA3,0x1E,0xE0,0x20, ++ 0x93,0x25,0x67,0xF9,0xC9,0x86,0x06,0xE4,0xE1,0xF8,0x35,0x52,0x08,0x09,0xD8,0x6C, ++ 0xC0,0x0C,0x80,0x17,0xCB,0x87,0xE2,0x68,0x90,0x6D,0xC7,0x1C,0x15,0x2A,0x9C,0x9E, ++ 0x37,0x27,0xAF,0x85,0x80,0x4D,0x34,0x6A,0x34,0xA2,0x00,0x91,0xEF,0x02,0x0A,0xF9, ++ 0x88,0x09,0x40,0x01,0x80,0x0E,0x30,0x7A,0x00,0x0F,0x38,0x19,0x17,0xF8,0xD1,0x43, ++ 0x85,0x44,0xD0,0x53,0x90,0x3C,0x98,0x24,0xC2,0x44,0x00,0x00,0xC0,0x00,0x86,0x2C, ++ 0xD2,0x3C,0x00,0x90,0xC0,0x00,0x84,0x1C,0x45,0xC2,0x11,0x81,0x00,0x13,0x1A,0x0B, ++ 0x30,0x01,0x00,0x67,0x4D,0x03,0x01,0x88,0xC0,0x00,0x42,0x03,0x01,0x3B,0x30,0x1A, ++ 0x30,0x92,0x09,0x09,0x00,0x01,0x80,0x17,0xCB,0xF7,0xE0,0xB0,0x90,0xB5,0xC7,0x44, ++ 0x17,0x32,0x9C,0x7E,0x30,0x01,0x00,0x67,0x4D,0x03,0x03,0x88,0xC0,0x00,0x42,0x03, ++ 0x00,0x3B,0x08,0x09,0x31,0x1A,0x31,0x92,0x30,0x42,0x80,0x17,0xCB,0x67,0xE0,0xB0, ++ 0x90,0xB5,0xC7,0x3C,0x17,0x32,0x9C,0x7E,0xD8,0x43,0x45,0x01,0x81,0x16,0x41,0x1A, ++ 0x44,0x0B,0x96,0x4D,0x89,0x14,0x48,0x4C,0x01,0x0B,0x4E,0x12,0x00,0x09,0x80,0x43, ++ 0xD8,0x43,0x85,0x34,0x30,0x01,0x00,0x67,0x55,0x03,0x01,0x88,0xC0,0x00,0x42,0x03, ++ 0x01,0x3B,0x30,0x1A,0x30,0x92,0x09,0x09,0x00,0x01,0x80,0x17,0xC3,0x67,0xE7,0xB0, ++ 0x90,0xB5,0xC7,0x34,0x17,0x32,0x9C,0x7E,0x48,0xB2,0x00,0x01,0x80,0x43,0x40,0x9A, ++ 0xCE,0x14,0x00,0x0B,0x48,0x0B,0x89,0x04,0x30,0x5A,0x11,0x09,0xA0,0x0C,0xC8,0x24, ++ 0xC7,0x44,0xB8,0xFF,0xFB,0xAF,0x49,0x0B,0x89,0x04,0x30,0x5A,0x10,0x01,0xA0,0x0C, ++ 0xC8,0x2C,0xC0,0x3C,0xB9,0xFF,0xFF,0x67,0xD8,0x43,0x45,0x01,0x80,0xDE,0x70,0x3A, ++ 0x44,0x83,0x97,0x3D,0x4F,0x44,0x01,0x83,0x40,0x32,0x08,0x09,0x85,0x0B,0xD8,0x43, ++ 0x51,0x0B,0x31,0x5A,0x10,0x09,0xA0,0x0C,0x88,0x04,0x00,0x2F,0x00,0x01,0x00,0x42, ++ 0x18,0x00,0x04,0x42,0x00,0xB0,0x00,0x01,0xCF,0x1C,0xB8,0xFF,0xF8,0x8F,0x40,0xDA, ++ 0x08,0x01,0x80,0x0B,0x00,0xBB,0x4F,0xD2,0x00,0x01,0x10,0x43,0x4A,0xC2,0xC8,0x01, ++ 0x18,0x43,0x80,0x4D,0xEF,0x85,0xAF,0xC5,0x30,0x1A,0x30,0x42,0x34,0xBA,0xD0,0x23, ++ 0xD0,0x2B,0x4E,0xA2,0xC0,0xC8,0x8A,0x04,0x30,0xD2,0x31,0xCA,0x80,0x17,0xE8,0xE7, ++ 0x30,0x01,0x00,0x3F,0x09,0x09,0x30,0xDA,0x30,0x92,0x31,0x42,0x84,0x17,0xC0,0x9F, ++ 0xE7,0xB0,0x93,0xB5,0x17,0x32,0x9D,0xAE,0xC8,0x04,0x10,0x01,0x18,0x01,0x00,0x4F, ++ 0x00,0x01,0x00,0x1F,0x82,0x5B,0xE0,0x48,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE, ++ 0xE6,0x90,0x92,0x95,0x17,0x12,0x9D,0x9E,0xE8,0xC5,0x07,0x00,0x00,0xB0,0x00,0x01, ++ 0x00,0x01,0x02,0x42,0x30,0x20,0x06,0x00,0x49,0x32,0x41,0x2A,0x05,0x43,0x9E,0xFF, ++ 0x7F,0x04,0x3A,0xF7,0x94,0x15,0x3A,0x00,0x77,0x18,0x06,0xF9,0x04,0xC2,0x3C,0x48, ++ 0x74,0x48,0x00,0xCA,0x50,0x01,0xD0,0x5E,0x38,0x90,0x78,0x90,0xD4,0x41,0x40,0x98, ++ 0x54,0xE2,0x00,0xD8,0xC6,0xD0,0x4C,0x9B,0x18,0x1A,0x1C,0x5A,0x0B,0x9B,0x3E,0x82, ++ 0x40,0x98,0x54,0xCA,0x04,0xD8,0xC4,0xD0,0x44,0x9B,0x18,0x1A,0x18,0x5A,0x00,0x9B, ++ 0x3A,0x82,0x93,0x05,0x36,0x10,0x76,0x90,0x0C,0x09,0x00,0x8A,0x48,0x00,0x52,0x9A, ++ 0x04,0x00,0xC4,0x00,0x03,0x0B,0x38,0x82,0x96,0x05,0x32,0x10,0x70,0x90,0x0E,0x09, ++ 0x00,0x8A,0x54,0x72,0x4C,0x00,0x02,0x00,0x94,0x01,0xC4,0x00,0x03,0x0B,0x38,0x82, ++ 0xB3,0x15,0x3B,0x82,0xFB,0x85,0x39,0x82,0x40,0x32,0x48,0x0B,0x10,0x21,0x18,0x8A, ++ 0x0B,0x0B,0x38,0x82,0x48,0x1A,0x48,0x43,0x14,0x21,0x18,0x82,0x0B,0x43,0x38,0x82, ++ 0x07,0x20,0x28,0xD0,0x68,0x07,0x00,0x07,0x20,0x07,0x00,0x07,0x08,0x07,0x00,0x07, ++ 0xAC,0xFD,0x87,0x4D,0xD0,0x94,0x30,0x22,0xF0,0x43,0x84,0x0C,0xF8,0x6B,0xC2,0x64, ++ 0x08,0x01,0x80,0x0B,0x00,0x01,0x00,0x8F,0x0A,0x21,0x19,0x0A,0x18,0x29,0xCA,0x48, ++ 0x0E,0xD8,0xC2,0x48,0xD0,0x4B,0x48,0x79,0x80,0x36,0x80,0x83,0xE0,0x90,0xCA,0x64, ++ 0xD8,0x64,0xC0,0x4B,0xE0,0x48,0x82,0xCB,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0x5E, ++ 0xC0,0x64,0xC0,0x03,0x80,0x44,0x40,0x01,0x88,0x0E,0x80,0x6D,0xE8,0x85,0xC7,0x44, ++ 0x40,0x09,0x88,0x1E,0xC0,0x0C,0x40,0x09,0x8F,0x06,0x38,0xB7,0x00,0x01,0x80,0x34, ++ 0x80,0x2C,0xC8,0x44,0xC4,0x0C,0x10,0x0A,0x88,0x8E,0x02,0x01,0x30,0x01,0x08,0x01, ++ 0x88,0x1C,0x88,0x14,0x1A,0x19,0x0A,0xD8,0x00,0x4F,0x10,0x31,0x18,0x52,0xCA,0x90, ++ 0xC4,0x90,0x4E,0xBC,0xC6,0xC0,0x49,0x94,0xCA,0xB0,0xE4,0x48,0x90,0x4D,0xD6,0x0C, ++ 0x17,0x8A,0x9C,0x96,0xC8,0x0C,0x80,0x1F,0xF0,0xFF,0x83,0x24,0x30,0x82,0xC9,0x0C, ++ 0x83,0x1F,0xF0,0xD7,0x30,0x32,0x08,0x01,0x00,0x01,0x00,0xFF,0x1A,0x29,0x0A,0xD8, ++ 0x02,0x0F,0xE0,0x48,0x91,0x4D,0x16,0x21,0x18,0x52,0xCA,0x90,0xC0,0x90,0xD6,0x93, ++ 0x57,0x79,0x80,0xB6,0x12,0x21,0x19,0x52,0x18,0x19,0xC9,0x90,0x0E,0xD8,0xC4,0x90, ++ 0x1E,0x01,0xF0,0x9A,0xFE,0x1C,0xC8,0xD8,0x98,0x1C,0x18,0x11,0xF0,0x9A,0xD6,0x14, ++ 0xC0,0xD0,0x94,0x14,0xE6,0x48,0x92,0x4D,0xE6,0x00,0x92,0x05,0xD4,0x44,0x10,0x12, ++ 0xC0,0xE6,0xCE,0x44,0xC0,0x1C,0x80,0x1F,0xF0,0x7F,0x32,0x3A,0xC8,0x44,0xC0,0x14, ++ 0x82,0x1F,0xF0,0x57,0xCE,0x24,0xD8,0x48,0x89,0x34,0xD0,0x80,0x80,0x2C,0x08,0x01, ++ 0x10,0x01,0x00,0x77,0x00,0x01,0x30,0x5A,0x18,0x5A,0xF3,0x5C,0x04,0xD8,0xCA,0xD8, ++ 0x02,0x1F,0x00,0x30,0x9A,0xD2,0xE4,0x00,0x95,0x05,0x16,0x42,0x9A,0xCE,0xE7,0x48, ++ 0x95,0x4D,0x16,0x4A,0x98,0x76,0x0F,0x01,0x11,0x01,0x00,0xF7,0x1A,0x29,0x0A,0xD8, ++ 0x02,0x0F,0xE0,0x48,0x91,0x4D,0x06,0x21,0x18,0x42,0xCA,0x00,0x86,0x3C,0xC0,0x00, ++ 0xD0,0x03,0x40,0x79,0x80,0xAE,0x07,0x01,0x01,0x47,0x19,0x19,0xF4,0x3C,0x08,0xD8, ++ 0xC0,0x98,0x37,0x01,0x34,0xE2,0xFC,0xF2,0xDA,0x34,0x38,0x19,0xC0,0x98,0x37,0x31, ++ 0x19,0x32,0xCA,0xB0,0x0F,0xF8,0xCB,0xB0,0x35,0xB2,0x4D,0xB4,0xD8,0xD8,0xAC,0x06, ++ 0x14,0xDA,0x92,0xDD,0x30,0x32,0x3B,0x11,0xF8,0xBA,0xF7,0x2C,0xCB,0xF0,0x35,0xBA, ++ 0x4F,0xFC,0xDF,0xB0,0xAB,0x06,0x10,0xB2,0xC8,0xD8,0x34,0xB2,0x18,0x72,0xFB,0x5C, ++ 0x07,0xB0,0xCB,0xB0,0x07,0x38,0x9A,0x9A,0xE6,0x00,0x92,0x05,0xDC,0x0C,0x10,0xC2, ++ 0x9A,0x9E,0xE6,0x48,0x92,0x4D,0xE6,0x90,0x90,0x95,0xC6,0x64,0xC4,0x03,0x10,0x82, ++ 0xC0,0xE6,0xC5,0x64,0xC8,0x0C,0xC0,0x03,0x10,0x42,0xCC,0x06,0x38,0xEF,0xC1,0x0C, ++ 0x3F,0xDF,0xA9,0x85,0x80,0x4D,0x34,0x22,0x04,0x71,0xD4,0x1A,0x01,0xC1,0xF0,0x02, ++ 0x28,0x71,0x80,0x44,0xF8,0x2A,0xAB,0x3C,0xD8,0x00,0x92,0x05,0x2B,0xD1,0xF8,0x2A, ++ 0x30,0x81,0xA8,0x34,0xF8,0x32,0xB5,0x2C,0xD9,0x68,0x95,0x6D,0xC0,0x33,0x77,0x09, ++ 0x8D,0x16,0x10,0x04,0x10,0x2C,0x07,0x7F,0x55,0x3C,0x05,0xF0,0x31,0xE2,0xC5,0xB0, ++ 0x54,0x04,0x07,0x38,0xCB,0xE8,0x33,0x3A,0xD9,0xB0,0x97,0xB5,0xD0,0x40,0x91,0x2D, ++ 0x85,0x80,0x85,0x68,0x17,0x04,0x15,0x2C,0xF1,0x3C,0xC0,0x80,0x04,0x30,0xCA,0x00, ++ 0xF4,0x44,0xC8,0x00,0x80,0x00,0x94,0x05,0xF3,0x2C,0xC8,0xA8,0x05,0x70,0xCB,0x68, ++ 0xF5,0x34,0xC8,0x68,0x81,0x68,0x95,0x75,0x90,0x01,0x46,0x01,0xD0,0x0E,0x00,0x01, ++ 0x00,0x27,0x40,0xAC,0x10,0x2A,0xD4,0x0E,0x00,0x01,0xF0,0x82,0x70,0x01,0xD0,0x0E, ++ 0x30,0x01,0x00,0x27,0x45,0xAC,0x12,0xAA,0xD0,0x0E,0x30,0x11,0xF8,0xB2,0x4C,0x41, ++ 0x80,0x0E,0x48,0x49,0x88,0xBE,0xD0,0x3C,0xD0,0x90,0xA8,0x06,0x14,0x92,0x92,0xAD, ++ 0xD4,0x2C,0xD8,0x90,0xAA,0x06,0x10,0x92,0xCC,0x90,0x92,0xAD,0x10,0xEA,0xCC,0x06, ++ 0x30,0xEA,0x48,0x49,0x8B,0x16,0x20,0x48,0x60,0x68,0x00,0x37,0x4D,0xC8,0x10,0x4A, ++ 0xC8,0x1E,0x30,0x6A,0x00,0x0F,0x30,0xEA,0x00,0x6A,0xD6,0x3C,0xD8,0xC8,0x8A,0x24, ++ 0x1C,0x8A,0x02,0x50,0xC4,0x48,0x34,0x62,0xC8,0x24,0x10,0x51,0x05,0x78,0xF2,0x12, ++ 0xCA,0x48,0x1E,0x52,0x20,0x12,0x8B,0x1C,0x43,0xC8,0x1A,0x42,0xC6,0x00,0x02,0x00, ++ 0xC0,0x00,0x8C,0x14,0x00,0xC8,0x8E,0x0C,0x82,0x1F,0xE8,0xA7,0x30,0x3A,0xC0,0x2C, ++ 0xCA,0x24,0x18,0x0A,0x00,0x40,0xC4,0x40,0x15,0x61,0xF0,0x12,0xCA,0x1C,0x18,0x52, ++ 0xC0,0x80,0xC8,0x14,0x1B,0x72,0xC3,0x88,0x00,0x48,0xC6,0x40,0xC8,0x0C,0x80,0x1F, ++ 0xE8,0x0F,0xCA,0x3C,0x08,0x0C,0xCB,0x2C,0x08,0x0C,0xCD,0x44,0xD0,0xC8,0xAB,0x06, ++ 0x10,0x4A,0x92,0x55,0xCA,0x34,0xD0,0x08,0xAA,0x06,0x10,0x4A,0x90,0x4D,0x50,0x19, ++ 0xD8,0x46,0xD0,0x44,0x10,0xD2,0xCD,0x0E,0xE0,0xF8,0x03,0x1F,0xD5,0x44,0x10,0xD2, ++ 0x93,0x06,0xF0,0xF8,0x48,0x19,0xD8,0x46,0xCC,0x34,0x10,0x0A,0xCA,0x0E,0xE0,0x00, ++ 0x00,0x1F,0xC8,0x34,0x10,0x0A,0x94,0x06,0xF7,0x00,0x0A,0x3C,0x10,0x04,0x81,0x4D, ++ 0xEF,0x85,0xAF,0xF5,0x30,0xB2,0xD0,0x44,0x60,0xCA,0xCF,0xE0,0x2F,0x31,0x78,0xC2, ++ 0x1F,0xAA,0xC3,0x68,0xFF,0xE1,0xC9,0x68,0x07,0xB0,0xC3,0x98,0x72,0xA2,0xF7,0x81, ++ 0xCA,0xF0,0xFC,0x9B,0x36,0xBA,0xB8,0x01,0x32,0xE2,0xFD,0x01,0xBA,0x0C,0xF8,0x01, ++ 0xB8,0x04,0x40,0x09,0x88,0x36,0x01,0x01,0x01,0xFF,0xC0,0x0B,0x48,0x79,0x88,0xCE, ++ 0x47,0x4C,0x09,0x0C,0x41,0x7C,0x13,0x3C,0xC1,0x93,0x89,0x13,0xC3,0x93,0x8B,0x13, ++ 0x1F,0x0C,0x1D,0x3C,0x23,0x0C,0x21,0x3C,0x0D,0x0C,0x0B,0x3C,0x41,0x4C,0x19,0x0C, ++ 0x43,0x4C,0x1B,0x0C,0x80,0x03,0x09,0x09,0x85,0x0B,0x8F,0x0B,0x30,0x0A,0xDB,0x4B, ++ 0x90,0x0B,0x01,0x27,0xA2,0x21,0xE1,0x00,0x94,0x05,0x16,0xC2,0x9C,0xEE,0x16,0xC2, ++ 0x92,0x9E,0x03,0x87,0x02,0x21,0x19,0x0A,0xC8,0x60,0x08,0x41,0x41,0x44,0x19,0x04, ++ 0x01,0x11,0xF0,0x42,0x1D,0x04,0xCB,0x1B,0x58,0x09,0x88,0xA6,0x18,0xC1,0x38,0xE1, ++ 0xF7,0x1A,0xFF,0x3A,0xD8,0xD8,0xAE,0x06,0x14,0xDA,0x92,0xFD,0x1F,0xF1,0xF0,0x1A, ++ 0xD0,0x00,0xAE,0x06,0x14,0x02,0x92,0x05,0xD9,0x0C,0xC0,0xC0,0xDC,0xDB,0x10,0xC2, ++ 0xC8,0x0E,0x00,0x01,0x88,0x03,0x05,0xC1,0x19,0x01,0xF1,0x02,0xF6,0x1A,0xD7,0x00, ++ 0xAA,0x06,0x10,0x02,0x90,0x3D,0x04,0xD1,0x19,0x11,0xF1,0x02,0xF6,0x1A,0xD7,0x00, ++ 0xAA,0x06,0x10,0x02,0xCC,0x00,0x96,0x05,0xD4,0x1B,0x11,0x1A,0xC8,0x2E,0xD8,0x04, ++ 0xC6,0x03,0xDF,0xDB,0xE4,0xD8,0x12,0xC2,0xC0,0x86,0xD8,0x04,0xC6,0x03,0xDF,0xDB, ++ 0xE4,0xD8,0x12,0xC2,0xCB,0x1E,0x30,0x02,0xD8,0x03,0x48,0x00,0x91,0x03,0x59,0x04, ++ 0x23,0x04,0x59,0x04,0x21,0x04,0x33,0x02,0xBD,0xFF,0xF7,0x9F,0xC3,0x03,0x47,0xF9, ++ 0x92,0x0E,0xE0,0x00,0x85,0x03,0x47,0x44,0x10,0x04,0x03,0x19,0x80,0x03,0xC3,0x0C, ++ 0xDC,0x03,0x82,0x01,0x89,0x03,0xCF,0x03,0xC2,0x8B,0xD1,0x00,0xE0,0x00,0x42,0x11, ++ 0xC3,0x2E,0xC8,0x03,0xC2,0x8B,0xD3,0x00,0xE0,0x00,0x42,0x11,0xCF,0x4E,0xC0,0x03, ++ 0x40,0x11,0x98,0x36,0xCC,0x04,0xD8,0x4B,0x10,0x42,0xC4,0x16,0x07,0x01,0x80,0x03, ++ 0x89,0x03,0xC7,0x83,0x8B,0x03,0xC1,0x83,0x8F,0x03,0xEB,0xF5,0xAF,0x85,0x47,0xF9, ++ 0x88,0x0E,0x00,0x01,0xE9,0x85,0x27,0x21,0x1C,0x02,0x63,0xEA,0xC0,0x00,0xCC,0x00, ++ 0x23,0x31,0x18,0x0A,0xC4,0x48,0x54,0xD2,0xD4,0xE1,0xC1,0x50,0x0A,0xA1,0xF0,0x0A, ++ 0x48,0x01,0xD0,0x06,0x10,0x4A,0x22,0xB1,0xF8,0x22,0x60,0x01,0xD3,0x06,0x10,0x22, ++ 0xCC,0x48,0x60,0xA2,0x10,0x0A,0x9D,0x06,0x08,0x01,0x28,0x71,0x42,0xA4,0xF8,0x2A, ++ 0xD8,0x20,0xAB,0x06,0x10,0x22,0x2B,0x81,0x42,0x94,0xFA,0x2A,0xD8,0x90,0xAA,0x06, ++ 0x15,0x92,0xC2,0x28,0x34,0xE2,0xA0,0x01,0x4C,0x14,0x33,0xA2,0x10,0x52,0xC5,0xF6, ++ 0xC8,0x13,0x54,0x09,0x8B,0x26,0xD8,0x3B,0xCB,0x33,0xF6,0xF8,0x10,0xF2,0xDD,0xA6, ++ 0x50,0x09,0x88,0x3E,0xD4,0x23,0x11,0x62,0x9E,0x26,0xC0,0x03,0x40,0xF1,0xC0,0x0E, ++ 0x40,0x29,0x90,0x56,0x50,0x09,0x88,0x16,0x51,0xC4,0x46,0x81,0x98,0x2E,0x50,0x09, ++ 0x8B,0x2E,0x30,0x02,0x05,0x00,0x12,0x42,0xC0,0x0E,0x00,0x01,0xE8,0x85,0x07,0x09, ++ 0xEF,0x85,0xAF,0xFD,0x84,0x65,0x34,0xB2,0x08,0x01,0x28,0x01,0x00,0x01,0x80,0x1C, ++ 0xC2,0xAC,0xF8,0x23,0x04,0x01,0x30,0x22,0x80,0x3C,0x00,0x27,0xD7,0x6C,0x00,0xF9, ++ 0xA2,0x82,0xE2,0x48,0x95,0x4D,0x16,0x0A,0x98,0xC6,0xD7,0x7C,0x28,0x92,0xC3,0x26, ++ 0xC0,0x7C,0x80,0x2C,0x30,0x82,0x83,0x24,0x03,0x1F,0x30,0x82,0x80,0x2C,0xC0,0x7C, ++ 0x80,0x24,0x00,0x01,0x82,0x34,0x00,0xD7,0x1A,0x01,0x00,0xB7,0x36,0x02,0x03,0xC2, ++ 0x3A,0x00,0x8E,0x86,0x40,0x1A,0x83,0x44,0x00,0x01,0xD0,0xAC,0xF4,0x64,0xF0,0x93, ++ 0x90,0x5C,0x30,0xD2,0x1A,0x12,0x03,0xB8,0xC8,0xD0,0x95,0x54,0x00,0x6F,0xF0,0x3C, ++ 0x07,0x32,0x3E,0x90,0x88,0x3E,0xF0,0x54,0x07,0x38,0xDA,0xB2,0xFD,0x44,0x10,0xF2, ++ 0x90,0x0E,0xB0,0x44,0x32,0x0A,0xE0,0x00,0x90,0x05,0xD6,0x5C,0x17,0x12,0xC4,0x76, ++ 0x70,0xA2,0x02,0x01,0x00,0x78,0xBA,0x4C,0x03,0x87,0x30,0x3A,0x07,0x3A,0x3E,0xF8, ++ 0x88,0x56,0x30,0x3A,0x18,0x3A,0xD3,0x64,0x05,0xF8,0xC3,0xF8,0xD5,0x4C,0xD0,0xFA, ++ 0x10,0xBA,0xC5,0x0E,0x30,0xF2,0x31,0x2A,0xE6,0x00,0x92,0x05,0x2F,0x82,0x9B,0x66, ++ 0x10,0xEA,0x8C,0xA6,0xC4,0x1C,0xC8,0x00,0x80,0x1C,0xC0,0x34,0xE6,0x00,0x92,0x05, ++ 0x80,0x34,0xC0,0x6C,0xA0,0x2A,0x32,0x09,0x30,0x82,0xD1,0x3C,0x00,0x42,0x1C,0x82, ++ 0x90,0x05,0x84,0x3C,0x03,0x72,0x35,0x02,0x1D,0x32,0x90,0x85,0x30,0x22,0xD4,0x2C, ++ 0xC4,0x34,0x10,0x82,0x82,0x1E,0xE0,0xD8,0x93,0xDD,0x2E,0x9A,0x98,0x36,0xD5,0x2C, ++ 0xC4,0x34,0x10,0x82,0x98,0x06,0xC5,0x1C,0x80,0x44,0x10,0x01,0x00,0x01,0x08,0x01, ++ 0x30,0x5A,0x83,0xCB,0x18,0x01,0x08,0x01,0x33,0x62,0x34,0x4A,0xE0,0x4A,0x00,0x0F, ++ 0xE6,0x48,0x92,0x4D,0x36,0xEA,0x00,0x6A,0x3F,0x68,0x8F,0xCE,0xED,0x24,0x10,0x4A, ++ 0x98,0xD6,0x40,0x01,0x8F,0x8E,0x08,0xF9,0x00,0x5F,0xD0,0x6C,0xE3,0x9A,0x28,0x9A, ++ 0x90,0x1E,0xD0,0xAC,0xF4,0x93,0x14,0x12,0xC0,0x0E,0xD0,0x6C,0xA2,0x8A,0xE0,0x00, ++ 0x95,0x05,0x16,0x02,0x98,0x8E,0x87,0x85,0xEA,0x85,0xF7,0x00,0x93,0x05,0x36,0x4A, ++ 0xE0,0x4A,0x28,0x09,0x31,0x62,0x05,0x47,0x33,0x6A,0x18,0x2A,0xFB,0x64,0x00,0x70, ++ 0xCA,0xB0,0x07,0x38,0xDD,0xAA,0xC7,0x50,0x2C,0x09,0x00,0x6A,0x1D,0xEA,0x90,0x5D, ++ 0x31,0x72,0xA3,0x8A,0xED,0x44,0x10,0x52,0x98,0x16,0x28,0x11,0x30,0x62,0x05,0xA7, ++ 0xFA,0x7C,0xE0,0x28,0x10,0xEA,0x9D,0x6E,0x90,0x44,0x08,0x01,0x00,0x27,0xF8,0x6C, ++ 0xE3,0xAA,0xA3,0xEA,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xC6,0xE0,0x8A,0x29,0x09, ++ 0x30,0x62,0x05,0x17,0x90,0x45,0x2F,0x01,0xA3,0xAA,0x31,0x2A,0x6D,0x01,0x80,0x56, ++ 0x33,0x6A,0x18,0x2A,0xFB,0x64,0x00,0x70,0xCA,0xB0,0x07,0x38,0xDA,0xAA,0xDF,0x90, ++ 0x2C,0x09,0x00,0x6A,0x1B,0x5A,0x35,0x6A,0xE2,0x4A,0xE1,0x48,0xA4,0x4A,0x39,0xD7, ++ 0x40,0x40,0x05,0x00,0xF8,0xFF,0x07,0x00,0xAC,0x85,0x87,0x2D,0x33,0x72,0xF8,0x8B, ++ 0x8C,0x14,0x50,0xCA,0xC0,0x20,0xA4,0x24,0xC9,0x14,0x18,0x21,0x31,0xBA,0x31,0xAA, ++ 0x1A,0xCA,0xBA,0x01,0xA8,0x01,0xC6,0x40,0xC0,0x00,0x84,0x1C,0x01,0x67,0xC2,0x03, ++ 0x42,0x79,0x80,0x46,0xC8,0x03,0x37,0x08,0xA0,0xA6,0x41,0x21,0x88,0x16,0x01,0x71, ++ 0xF0,0x02,0x81,0x0C,0x01,0x81,0xF0,0x02,0x81,0x04,0x30,0x92,0x09,0x49,0x30,0x02, ++ 0xB8,0xFF,0xEF,0xFF,0x0B,0x71,0xF0,0x0A,0xC0,0x0C,0xD0,0x40,0xAA,0x06,0x10,0x02, ++ 0x90,0x0D,0x00,0x81,0xF0,0x02,0xD1,0x04,0xD0,0x00,0xAC,0x06,0x12,0x02,0xC2,0x00, ++ 0x91,0x05,0xD8,0x4B,0x44,0x48,0x14,0x0A,0xE8,0x5E,0xC0,0x0C,0x08,0x04,0xC7,0x04, ++ 0x10,0x04,0x01,0x37,0x40,0x21,0x90,0x26,0xF8,0x83,0x41,0x11,0x91,0x0E,0x00,0x01, ++ 0x87,0x03,0x05,0xF9,0x8B,0x03,0x89,0x03,0xC7,0x03,0xDF,0xCB,0x10,0x42,0xC4,0x0E, ++ 0x07,0x01,0x88,0x03,0xCA,0x03,0x37,0x00,0x77,0x00,0x8A,0x03,0x40,0x01,0x80,0x0E, ++ 0xF7,0x00,0x8A,0x03,0xC8,0x03,0x47,0x01,0x8B,0x2E,0xC0,0x03,0x44,0x00,0x04,0x00, ++ 0x80,0x03,0x03,0x01,0x81,0x03,0xA5,0x21,0xC5,0x1C,0x10,0x02,0xC0,0x7E,0x0D,0x01, ++ 0x11,0x01,0xB8,0x93,0xC0,0x24,0x00,0x87,0xC0,0x1B,0xE0,0x14,0x10,0x1A,0x95,0x56, ++ 0xC7,0x1B,0xDE,0xE3,0x32,0xD8,0x72,0xD8,0x10,0x1A,0xCD,0x26,0xC1,0x1B,0x5C,0x01, ++ 0x80,0x0E,0x08,0x09,0x04,0x27,0x80,0x13,0x80,0x21,0xD9,0x1C,0x17,0x1A,0xC4,0x5E, ++ 0x49,0x01,0x80,0x5E,0xC1,0x24,0x00,0x37,0x80,0x13,0xC4,0x0B,0xDC,0x14,0x10,0xCA, ++ 0x96,0x06,0xC1,0x0B,0xDA,0xDB,0x37,0x48,0x74,0x48,0x12,0xCA,0xC8,0xD6,0x08,0x09, ++ 0x81,0x0B,0xFC,0x8B,0xE1,0x48,0xBA,0x8B,0x0A,0x71,0xF0,0x0A,0x48,0x01,0xD0,0x0E, ++ 0x08,0x14,0x06,0x27,0x44,0x5C,0x11,0xCA,0xE9,0x0E,0x40,0x4C,0x08,0x0C,0x0E,0x81, ++ 0xF0,0x0A,0x4A,0x01,0xD0,0x0E,0x10,0x14,0x03,0x27,0x40,0x5C,0x10,0xCA,0xEC,0x0E, ++ 0x40,0x4C,0x13,0x0C,0x80,0x21,0xC9,0x1C,0x16,0x0A,0xC4,0xAE,0x87,0x2D,0xE8,0x85, ++ 0xAC,0x85,0x87,0x3D,0x30,0x2A,0x30,0x62,0x41,0x1A,0xC2,0x40,0x08,0xB9,0xED,0x4A, ++ 0x4B,0x29,0x80,0xE6,0x0C,0x09,0x06,0x48,0xC2,0x70,0x4B,0x02,0xC0,0x48,0x8B,0x1C, ++ 0x0E,0x19,0x03,0x48,0xC0,0x48,0x8B,0x14,0x0F,0x01,0x10,0xF9,0x18,0x79,0x00,0x3F, ++ 0xA6,0x92,0xCB,0x3B,0x78,0x01,0x88,0x06,0x82,0x1B,0xE0,0x48,0x91,0x4D,0x86,0x21, ++ 0xFC,0x3B,0x13,0x7A,0xC0,0xA6,0x07,0x01,0x85,0x34,0xF0,0x03,0x42,0x01,0x80,0xCE, ++ 0xB1,0x04,0x30,0x0A,0x30,0x42,0x59,0x2D,0xD7,0x14,0xB8,0xFF,0xD8,0x0F,0x84,0x34, ++ 0xC0,0x34,0x40,0x01,0x88,0x76,0x30,0x01,0x01,0x47,0x30,0x5A,0x37,0x92,0x09,0xF9, ++ 0x00,0x09,0xA0,0x04,0xB8,0xFF,0xEF,0xEF,0xE7,0xB0,0x93,0xB5,0xF5,0x03,0x15,0x82, ++ 0xC1,0x9E,0x07,0xFF,0xC0,0x34,0x40,0x09,0x89,0x96,0xC0,0xB3,0x31,0x1A,0x31,0x52, ++ 0x09,0x01,0x30,0x82,0xBE,0xFF,0xEF,0x17,0x40,0x01,0x80,0x0E,0x00,0x01,0x00,0x07, ++ 0x01,0x09,0x30,0x5A,0x11,0x01,0x30,0x8A,0xA7,0x04,0xB8,0xFF,0xE9,0x17,0x00,0x4F, ++ 0xA5,0x04,0xF0,0x3B,0x30,0x5A,0xEB,0xD3,0x30,0xDA,0xC9,0x1C,0xC7,0x14,0xB8,0xFF, ++ 0xF0,0x07,0x38,0x01,0x00,0xDF,0xC0,0x1C,0xEF,0x02,0x46,0xF9,0x81,0x16,0xE0,0x82, ++ 0x80,0x24,0x00,0x0F,0x00,0xF9,0x87,0x24,0x31,0x1A,0x31,0x52,0x30,0xCA,0xC1,0x24, ++ 0xBC,0xFF,0xEF,0xE7,0x40,0x01,0x80,0x0E,0x00,0x01,0x00,0x07,0x01,0x09,0x30,0x5A, ++ 0x30,0xD2,0xA1,0x04,0xCF,0x24,0xB8,0xFF,0xE3,0xE7,0xE6,0xF8,0x95,0xFD,0xF7,0x03, ++ 0x17,0xC2,0xC5,0x06,0x31,0x0A,0x31,0x42,0xD7,0x34,0xB8,0xFF,0xF0,0x6F,0x86,0x3D, ++ 0xE8,0x85,0x07,0x01,0x38,0x82,0x03,0x00,0x40,0x40,0x05,0x00,0x18,0x70,0x00,0x00, ++ 0xAE,0xFD,0x87,0x5D,0xC2,0xAC,0xDA,0x03,0x82,0xD4,0xC1,0xAC,0xD9,0x03,0x80,0xCC, ++ 0x01,0x09,0x58,0x45,0x89,0xC3,0xC0,0xCC,0xE2,0x00,0x8A,0xC3,0xC4,0xCC,0x89,0xC3, ++ 0xC2,0xCC,0xF1,0x00,0x8A,0xC3,0xC6,0xAC,0x82,0x01,0x86,0x54,0xE0,0x0B,0x00,0x21, ++ 0x1A,0x0A,0xC0,0x54,0xA2,0x0B,0xC0,0xAC,0xCA,0x03,0x42,0x00,0x80,0xDC,0x09,0x01, ++ 0x40,0xBD,0x31,0x52,0x00,0x36,0x00,0x01,0x82,0xFC,0xC0,0xAC,0xCD,0xB4,0x82,0x01, ++ 0x82,0x4C,0xC2,0xAC,0x82,0x01,0x84,0x44,0xC0,0x74,0x4A,0x11,0x92,0x05,0x82,0x3C, ++ 0xC2,0x6C,0x92,0x05,0x83,0x34,0x82,0xBE,0x10,0x01,0x00,0x01,0x4C,0x4D,0xB1,0x4A, ++ 0x8F,0x2C,0x4A,0xF2,0xB2,0x4A,0x8C,0x24,0x48,0xE2,0xEF,0x48,0xB2,0x4A,0x8C,0x1C, ++ 0x04,0x08,0xC4,0x48,0x91,0x4D,0x66,0xA5,0xDB,0x74,0xA2,0x1A,0x62,0x8D,0xD9,0x6C, ++ 0xA2,0x1A,0xDB,0x24,0x9A,0x3C,0xD9,0x1C,0x9A,0x34,0xD9,0x2C,0x98,0x2C,0x41,0x09, ++ 0x89,0x5E,0xD8,0x3C,0x12,0xDA,0x92,0xDD,0x99,0x3C,0xD9,0x34,0x12,0xDA,0x92,0xDD, ++ 0x99,0x34,0xD9,0x2C,0x12,0xDA,0x92,0xDD,0x9A,0x2C,0xD9,0x5C,0x32,0xE2,0xDC,0x64, ++ 0x9A,0x64,0xD9,0x34,0xE1,0x3C,0xEA,0x34,0xCA,0xD8,0x92,0xDD,0xEB,0x3C,0xC9,0x20, ++ 0x91,0x25,0xF3,0x2C,0xED,0x64,0xC9,0x68,0xA8,0x64,0x59,0x01,0xD9,0x86,0xEB,0xD4, ++ 0x13,0x5A,0xD5,0x6E,0x63,0x01,0xD8,0x5E,0xED,0xCC,0x11,0x62,0xD1,0x46,0xEB,0x64, ++ 0xC5,0x6B,0x49,0x68,0x8B,0x06,0x32,0x2A,0x3F,0x01,0xF8,0x7A,0xEB,0x2C,0x01,0x68, ++ 0x23,0x62,0x35,0x32,0x2B,0x01,0xF8,0xAA,0xF5,0xDC,0x11,0xAA,0xEA,0xC6,0xF2,0xB4, ++ 0x71,0x09,0x88,0x16,0xD9,0xF0,0x93,0xB5,0xB2,0x9C,0xF8,0x5C,0x35,0x01,0xF8,0xF2, ++ 0x10,0x72,0xDD,0x06,0x35,0xAA,0x81,0x68,0x01,0x68,0x33,0x7A,0xF3,0x9C,0x10,0x6A, ++ 0x12,0xAA,0xE5,0x2E,0x6B,0xA5,0xA1,0x62,0x6B,0x8D,0xA1,0x5A,0x01,0xA8,0x72,0xBD, ++ 0xC9,0x68,0xE5,0x72,0xE1,0xB0,0xA3,0x72,0xEB,0xFC,0xE0,0x68,0x90,0x6D,0xAF,0xFC, ++ 0xF5,0x9C,0x10,0xBA,0xD1,0xBE,0x05,0x9F,0x09,0xEF,0x6A,0xA5,0xA1,0x62,0x6B,0x8D, ++ 0xA2,0x5A,0x03,0xB0,0x6B,0xBD,0xC9,0xA8,0xE3,0x72,0xE1,0xB0,0xA0,0x72,0xE9,0xFC, ++ 0xE7,0x68,0x93,0x6D,0xAD,0xFC,0x38,0x37,0xE9,0x64,0xC1,0x6B,0x48,0x68,0x6D,0x19, ++ 0x8A,0x6E,0x00,0xB0,0x7F,0xBD,0xC9,0xB0,0xE0,0xB2,0x71,0x09,0xC2,0x3E,0xC0,0x64, ++ 0x08,0x01,0xC6,0x03,0x1A,0x42,0xC8,0x64,0x82,0x43,0x80,0x7D,0xE8,0x85,0x6F,0x11, ++ 0x89,0x56,0x68,0xA5,0xA1,0x62,0x63,0x8D,0xA2,0x1A,0x03,0x98,0x4A,0xBD,0xC1,0xC8, ++ 0xE2,0x5A,0xE0,0xD8,0xA0,0x5A,0x00,0x1F,0xCA,0x4C,0xF2,0x4B,0x4F,0x51,0x90,0x66, ++ 0xE6,0x00,0x92,0x05,0x40,0x11,0x90,0x06,0x3A,0xD7,0xE2,0x90,0x90,0x95,0x56,0x21, ++ 0x92,0x06,0x38,0x57,0x01,0x01,0x80,0x6C,0xC0,0xB4,0x42,0x09,0x88,0xF6,0x03,0x01, ++ 0x80,0x84,0x01,0x01,0x81,0x7C,0xC9,0x84,0x42,0xBD,0x01,0x48,0xC2,0x40,0x80,0x14, ++ 0xC1,0x7C,0xC9,0x84,0x02,0x00,0xC4,0x00,0x91,0x05,0x86,0x54,0xCA,0x7C,0xC1,0x14, ++ 0xE0,0x2A,0x6A,0x09,0xC1,0x26,0xC0,0x6C,0xE6,0x00,0x92,0x05,0x87,0x6C,0x01,0x8F, ++ 0xC0,0x7C,0x41,0x09,0x89,0x16,0xC0,0x84,0x47,0x01,0x88,0xC6,0x08,0x81,0x41,0x45, ++ 0x86,0x1F,0xC0,0x77,0xC0,0x6C,0x82,0x3C,0xC0,0x74,0x82,0x34,0xC0,0x5C,0x82,0x0C, ++ 0xC0,0x64,0x82,0x04,0xC4,0x84,0xE1,0x00,0x3C,0x00,0x7C,0x00,0x50,0x5A,0xB4,0xA2, ++ 0xE8,0x98,0xB0,0xCA,0x31,0x62,0x74,0x4D,0xB1,0x8A,0xC1,0x84,0xB0,0x82,0x80,0x24, ++ 0xC0,0x84,0xB1,0xC2,0x81,0x1C,0xD0,0x84,0xB0,0x82,0x85,0x14,0xC0,0x7C,0x41,0x09, ++ 0x88,0x5E,0xC0,0x24,0x12,0x02,0x92,0x05,0x80,0x24,0xC0,0x1C,0x12,0x02,0x92,0x05, ++ 0x80,0x1C,0xC0,0x14,0x12,0x02,0x92,0x05,0x80,0x14,0x00,0x01,0x83,0x2C,0xE0,0x68, ++ 0xAD,0xF4,0x01,0x9F,0x40,0x61,0x98,0x66,0xC8,0x24,0xC0,0x34,0xD2,0x54,0xD1,0x00, ++ 0x4C,0xA5,0xA1,0x42,0xC8,0x1C,0xC0,0x3C,0xD2,0x54,0xD1,0x00,0x4C,0x8D,0xA1,0x42, ++ 0x00,0x47,0x15,0x01,0xDC,0x0C,0x00,0x28,0xF0,0xD2,0x5C,0x45,0x88,0xD2,0x12,0x01, ++ 0x90,0x74,0xD1,0x3C,0x92,0x95,0x92,0x0C,0xD2,0x34,0x90,0x95,0x91,0x04,0xD2,0x74, ++ 0x50,0x09,0x88,0x3E,0x12,0x12,0x93,0xA5,0x32,0x12,0x13,0x92,0x94,0x95,0x32,0xA2, ++ 0x12,0x4A,0x92,0x4D,0xD2,0x0C,0xDA,0x04,0xF0,0x0C,0x00,0x07,0x01,0xEF,0xB4,0x24, ++ 0xF1,0x04,0xB0,0x64,0x01,0x70,0xB2,0xFC,0x22,0x12,0x93,0x95,0xCA,0xD8,0x90,0xDD, ++ 0xF9,0x24,0xF1,0xFC,0xC9,0xB0,0xB7,0x24,0xF3,0x64,0xC1,0xB0,0xB0,0x64,0x51,0x01, ++ 0xD9,0xBE,0xF0,0xD4,0x10,0x92,0xD5,0xA6,0x58,0x01,0xD8,0x96,0xF5,0xCC,0x11,0x9A, ++ 0xD1,0x7E,0xF8,0x24,0x35,0x01,0xF8,0xF2,0xF9,0x64,0xC1,0xFB,0x48,0xF8,0x8D,0x46, ++ 0xFD,0xDC,0x11,0xF2,0xE8,0x2E,0x78,0x45,0xCD,0xFA,0xCB,0xF0,0x7B,0x45,0x88,0xF2, ++ 0x39,0xD7,0xD6,0x74,0xE6,0x90,0x92,0x95,0x91,0x74,0xD1,0x74,0x55,0x11,0x98,0xF6, ++ 0x41,0x01,0x80,0xF6,0xF2,0x10,0xF2,0x44,0x00,0x90,0x5C,0x45,0xC7,0xD2,0xCC,0xB3, ++ 0xCC,0xDA,0xCA,0xB0,0x11,0xF2,0x94,0x86,0xD0,0x2C,0x50,0x09,0x88,0x8E,0xD1,0x24, ++ 0xC1,0x34,0xD8,0x54,0xD1,0x00,0x54,0xA5,0xA0,0x82,0xDE,0x1C,0xD1,0x3C,0xE8,0x54, ++ 0xD1,0x90,0x5E,0x8D,0xA8,0xD2,0xEA,0x14,0xDA,0x04,0xD8,0xE8,0x36,0x1A,0xD3,0x90, ++ 0x90,0x95,0xDA,0x00,0x93,0x1D,0xD2,0x40,0x2C,0x01,0x30,0x01,0x50,0x01,0xD8,0x56, ++ 0xFD,0xD4,0x11,0xD2,0xD0,0x3E,0x58,0x01,0xD9,0x2E,0xF8,0xCC,0x10,0xDA,0xD5,0x16, ++ 0xC1,0x3B,0x18,0xBA,0x83,0x3B,0x20,0x12,0x90,0x95,0xCA,0xD8,0x92,0xDD,0xC2,0x00, ++ 0xE7,0x68,0x93,0x6D,0x6F,0x11,0xC8,0x4E,0x04,0xE7,0x10,0x9A,0x90,0x0E,0x10,0x09, ++ 0x90,0x2C,0xD8,0x24,0xD6,0x34,0xC0,0x90,0x90,0x95,0x96,0x34,0xD8,0x1C,0xD0,0x3C, ++ 0xC6,0x90,0x96,0x95,0x90,0x3C,0xD0,0x14,0xDA,0x0C,0x00,0x90,0xC0,0x90,0x96,0x0C, ++ 0xD8,0x14,0xD0,0x04,0xC0,0x90,0x96,0x04,0xE6,0x00,0x92,0x05,0xD4,0xF4,0x11,0x82, ++ 0x92,0x06,0x38,0x3F,0xC2,0x7C,0xE1,0x00,0x91,0x05,0x86,0x7C,0xC0,0x7C,0x41,0x11, ++ 0x97,0x06,0x30,0xAF,0xC2,0x84,0xE1,0x00,0x91,0x05,0x86,0x84,0xC0,0x84,0x41,0x21, ++ 0x97,0x06,0x30,0x37,0x00,0x0F,0x00,0x41,0x81,0x6C,0xC1,0x6C,0x41,0x41,0x88,0xD6, ++ 0x10,0x01,0x00,0x01,0x58,0x8A,0xE8,0xC8,0xB4,0xF2,0xB4,0x7A,0x31,0x8A,0x31,0xDA, ++ 0x40,0x09,0x88,0x1E,0x12,0x4A,0x92,0x4D,0x12,0xDA,0x92,0xDD,0xE7,0x6C,0xC2,0x18, ++ 0x92,0xDD,0xE2,0x74,0xC2,0x08,0x93,0x65,0x04,0x08,0xC4,0x48,0x90,0x4D,0x5E,0x01, ++ 0xD9,0x76,0xE8,0xD4,0x10,0x5A,0xD5,0x5E,0x60,0x01,0xD8,0x4E,0xED,0xCC,0x11,0x62, ++ 0xD1,0x36,0x68,0xA5,0xA1,0x62,0x63,0x8D,0xA0,0x1A,0x03,0x3F,0xE8,0x62,0x00,0x00, ++ 0x62,0xA5,0xD9,0x74,0xA1,0x1A,0x63,0x8D,0xDB,0x6C,0xA2,0x1A,0xE6,0x00,0x92,0x05, ++ 0x46,0x11,0x98,0x9E,0xE6,0x90,0x92,0x95,0x56,0x21,0x98,0x56,0x58,0x85,0xE1,0xC3, ++ 0xB0,0xC3,0xC8,0xC3,0x98,0xC3,0x00,0x01,0x81,0x04,0x59,0x85,0xE0,0xC3,0xB0,0xC3, ++ 0xC8,0xC3,0x98,0xC3,0x00,0x01,0x80,0xE4,0x80,0xEC,0x80,0xF4,0xC4,0xAC,0xCA,0x03, ++ 0x80,0xDC,0x01,0x01,0x08,0x01,0x78,0xA5,0x06,0x18,0xCE,0xD0,0x32,0xA2,0x04,0x20, ++ 0xC6,0x10,0x93,0x95,0x6D,0xA5,0xE1,0x72,0x33,0x2A,0xA3,0x72,0x6D,0x8D,0xE1,0x6A, ++ 0x32,0x12,0xC3,0x90,0x8A,0xAB,0xE0,0x48,0x90,0x4D,0x4E,0x19,0x98,0x86,0x47,0x09, ++ 0x80,0x0E,0x40,0x19,0x8F,0x66,0xE0,0xCA,0x33,0xE2,0x31,0x12,0xCB,0x93,0x30,0x2A, ++ 0xC7,0x6B,0xA5,0x2A,0x34,0x1A,0xCB,0xE3,0x8C,0xE3,0x80,0xCB,0x34,0x0A,0x8B,0x53, ++ 0x09,0x09,0x88,0x14,0x09,0x01,0x88,0x7C,0xD3,0x7C,0x31,0x0A,0xE1,0x4A,0xDC,0x7C, ++ 0x36,0x12,0xC3,0x90,0xCA,0x9B,0xC0,0xAB,0xC9,0x93,0x92,0x1C,0xD0,0x7C,0x51,0x01, ++ 0x88,0x16,0x41,0x01,0x80,0x0E,0x40,0x19,0x8D,0x5E,0x10,0x4A,0x98,0x4E,0x10,0x09, ++ 0x90,0x0C,0x41,0x01,0x8A,0x16,0xF0,0x10,0x90,0x14,0x01,0xF7,0x11,0x09,0x90,0x14, ++ 0x00,0xDF,0x40,0x09,0x80,0x0E,0x40,0x11,0x8D,0x5E,0x10,0x4A,0xC0,0x4E,0x10,0x09, ++ 0x90,0x0C,0x41,0x09,0x8C,0x16,0xF0,0x10,0x90,0x14,0x01,0x77,0x11,0x09,0x90,0x14, ++ 0x00,0x5F,0x10,0x01,0x90,0x0C,0x01,0x47,0x11,0x09,0x90,0x0C,0x40,0x11,0x90,0x16, ++ 0xF1,0x90,0x94,0x14,0x00,0x0F,0x10,0x09,0x90,0x14,0x41,0x01,0x80,0x0E,0x40,0x19, ++ 0x8D,0x0E,0x10,0x4A,0x90,0x2E,0x40,0x09,0x80,0x0E,0x40,0x11,0x8D,0x26,0x10,0x4A, ++ 0xC0,0x16,0x10,0x09,0x94,0x5C,0x01,0x8F,0x11,0x01,0x90,0x5C,0x01,0x77,0xD4,0xCC, ++ 0x32,0x3A,0x19,0xBA,0xD1,0xA4,0xF2,0xEC,0xC4,0xD0,0xCD,0x90,0x91,0x64,0xD1,0x64, ++ 0xC1,0x93,0x90,0xE4,0x31,0x90,0xA2,0xD6,0xF3,0xA4,0x02,0xD0,0xC9,0x90,0xF4,0x44, ++ 0x04,0xB0,0xCB,0x90,0x31,0x19,0x10,0xB0,0xC8,0xB0,0x14,0x21,0xF1,0x92,0xF5,0xDC, ++ 0x10,0x92,0xD5,0x26,0xF0,0x6C,0x71,0x41,0x88,0xC6,0x50,0x01,0xD9,0xB6,0xF0,0xE4, ++ 0x48,0xB0,0x87,0x06,0x80,0x90,0xF2,0xE4,0xC0,0xB0,0xB5,0xE4,0xF0,0x44,0xF9,0xF4, ++ 0x1F,0xB2,0xCA,0xB0,0xB0,0xF4,0xF0,0xEC,0x1C,0x12,0xCB,0x90,0x91,0xEC,0xD0,0x04, ++ 0xE4,0x90,0x92,0x95,0x91,0x04,0xD1,0xE4,0x48,0x90,0x8E,0xEE,0xD0,0x44,0xF2,0xFC, ++ 0xCD,0x93,0x12,0x92,0xC1,0x2E,0xD0,0xE4,0x31,0x01,0x1E,0x92,0xF1,0x64,0x81,0x93, ++ 0x01,0x47,0xD0,0xE4,0x31,0x01,0x1A,0x92,0xF1,0x64,0x81,0x93,0x01,0x17,0xD0,0x0C, ++ 0x50,0x09,0x80,0x4E,0xD0,0x0C,0x51,0x09,0x8A,0x36,0xD0,0x6C,0x10,0xA2,0x84,0x1E, ++ 0xD5,0x14,0xC1,0x10,0x95,0xA5,0x3A,0x57,0x10,0x4A,0x8D,0xDE,0xD4,0x1C,0x11,0x9A, ++ 0x89,0xC6,0xC8,0x7C,0xE6,0x48,0x92,0x4D,0x89,0x7C,0xC9,0x7C,0x48,0x11,0x90,0x06, ++ 0x3A,0x97,0xE2,0x00,0x90,0x05,0x46,0x21,0x91,0x06,0x38,0x1F,0xC2,0x4C,0xF2,0x03, ++ 0x42,0x01,0x88,0x5E,0xC9,0xAC,0x8A,0x01,0xD8,0x43,0x36,0x10,0xAA,0x36,0x31,0x00, ++ 0x71,0x00,0x04,0x27,0xD0,0x5C,0x51,0x01,0x8D,0x5E,0x10,0x4A,0xCA,0x16,0xF0,0x48, ++ 0x90,0x4D,0x06,0x1F,0x10,0x4A,0x95,0x0E,0xE6,0x48,0x92,0x4D,0x11,0x09,0x90,0x5C, ++ 0x01,0x67,0xD0,0x1C,0x10,0x9A,0xCC,0x16,0xF6,0xD8,0x92,0xDD,0x01,0x27,0xD0,0x1C, ++ 0x10,0x9A,0x94,0x0E,0xE6,0xD8,0x92,0xDD,0x11,0x01,0x90,0x5C,0x91,0x55,0x92,0x44, ++ 0x97,0xE5,0x72,0xFA,0xD4,0x44,0xC9,0x90,0x93,0xEC,0x39,0x47,0x02,0x01,0xD0,0xAC, ++ 0x6C,0x94,0x12,0x12,0x9A,0xD6,0xC0,0xAC,0xE4,0x4B,0x68,0x04,0x10,0x42,0x9C,0x26, ++ 0xC4,0x44,0xCA,0x03,0xF6,0x00,0x94,0x05,0x02,0x1F,0xC0,0x44,0xCC,0x03,0xE4,0x00, ++ 0x91,0x05,0xCE,0x04,0x10,0x0A,0x9C,0x4E,0xC0,0xAC,0x0A,0x01,0xB2,0x0B,0xC4,0x54, ++ 0x08,0xD9,0xE7,0x03,0x02,0x42,0xC8,0x54,0xA2,0x43,0x28,0x37,0x27,0x01,0x30,0xF9, ++ 0xB0,0x09,0x60,0x01,0x8A,0x4E,0xC0,0x3C,0xC8,0xCC,0xF9,0xF4,0xD2,0x54,0x42,0x93, ++ 0x97,0x9C,0x50,0x42,0xDE,0x74,0xB2,0xAA,0x02,0x47,0xC0,0x34,0xC8,0xD4,0xF9,0xEC, ++ 0xD4,0x54,0x42,0x93,0x97,0x9C,0x50,0x22,0xDE,0x6C,0xB2,0xAA,0x40,0x01,0x80,0x16, ++ 0xF4,0x48,0x12,0x42,0x8A,0x8E,0xD0,0x74,0x96,0x04,0x90,0x05,0x32,0x0A,0xD9,0x6C, ++ 0xD7,0x5C,0xBA,0xEF,0xD1,0x77,0x37,0x8A,0x10,0x82,0xED,0x0E,0x30,0x42,0x00,0x17, ++ 0x40,0x01,0xD0,0x06,0x02,0x01,0xC8,0x28,0x04,0x07,0xA8,0x01,0x10,0xC0,0xC9,0xE4, ++ 0x81,0x17,0xF0,0x47,0xCA,0x9C,0xC8,0x00,0x18,0x42,0x42,0x01,0xD0,0x06,0x00,0x01, ++ 0xA0,0x00,0x60,0x01,0x8A,0x7E,0xC8,0x54,0x44,0x4C,0x10,0x0A,0xD0,0x06,0x30,0x42, ++ 0xC8,0xAC,0x12,0x31,0xF2,0x4B,0x1C,0x8A,0xD4,0xA4,0xC2,0x48,0x12,0x19,0x0A,0x90, ++ 0xC4,0x48,0x0C,0x44,0x02,0x77,0xC8,0x54,0x44,0x4C,0x12,0x0A,0xD0,0x06,0x30,0x42, ++ 0xC8,0xAC,0x12,0x31,0xF2,0x4B,0x1C,0x8A,0xD4,0xA4,0xC2,0x48,0x12,0x19,0x0A,0x90, ++ 0xC6,0x48,0x0C,0x44,0xE7,0x20,0x93,0x25,0x65,0x09,0xC8,0x16,0xC0,0xAC,0x12,0x31, ++ 0xD8,0x0B,0xC6,0xE4,0x02,0x42,0xCE,0xAC,0xF2,0x4B,0x1C,0x8A,0xD4,0xA4,0xC2,0x48, ++ 0x12,0x19,0x0A,0x90,0xC0,0x48,0x14,0x44,0xC2,0xAC,0xCA,0x74,0xF2,0x03,0x04,0x10, ++ 0xC0,0xA4,0xC2,0x90,0x04,0x09,0x09,0x00,0xC0,0x90,0xB0,0x8B,0xCA,0xAC,0xD2,0x6C, ++ 0xF2,0x4B,0x04,0x58,0xCA,0xA4,0xC2,0xC8,0xC2,0x40,0xB0,0x13,0xC2,0xAC,0xCA,0xAC, ++ 0xF2,0x03,0xE4,0x00,0xB6,0x43,0x24,0x07,0xAC,0xFD,0x87,0xDD,0xF4,0x24,0x31,0xB2, ++ 0x33,0xFA,0xD8,0x83,0x81,0x94,0xD8,0x83,0x81,0x8C,0xC8,0x83,0x80,0x84,0x00,0x01, ++ 0x85,0x6C,0x40,0x32,0x41,0x0B,0x32,0x82,0x80,0x01,0x85,0xD4,0x48,0x01,0x80,0x1E, ++ 0xC2,0x84,0x40,0x00,0x80,0x74,0x00,0x67,0xC2,0xD4,0xF0,0x03,0x40,0x51,0x98,0x26, ++ 0xC8,0xD4,0x00,0xD9,0xB0,0x42,0x80,0x74,0x00,0x1F,0xC8,0xD4,0x00,0xD1,0xB0,0x42, ++ 0x86,0x74,0x08,0x09,0x03,0x48,0xC4,0xC8,0xC0,0xDC,0x88,0xCC,0x41,0x01,0x80,0xEE, ++ 0x04,0x29,0x04,0x00,0xC1,0xD8,0x31,0xCA,0x89,0xF9,0x8F,0x29,0xE0,0xCC,0xC0,0x84, ++ 0x42,0x00,0x12,0x02,0x90,0x05,0x82,0x6C,0x04,0x01,0x30,0x22,0x00,0x8F,0x00,0x01, ++ 0x00,0x47,0xC0,0xEB,0xC5,0x53,0xD0,0x68,0x05,0x2C,0xE1,0x20,0xE2,0xD8,0xE2,0x48, ++ 0xE6,0x00,0x92,0x05,0xED,0x8C,0x10,0x42,0x9B,0x9E,0x37,0x02,0xE6,0x00,0x92,0x05, ++ 0x30,0x22,0xC4,0x94,0x2F,0x22,0x9C,0x56,0x30,0x82,0x43,0x01,0x84,0x06,0x38,0x02, ++ 0x06,0xC9,0x07,0x00,0xC7,0xD8,0x01,0xF9,0x01,0x00,0xC6,0xC0,0x4B,0x02,0xC4,0xC8, ++ 0x10,0x01,0x00,0x47,0x40,0x24,0x40,0x6C,0xD8,0x20,0x03,0xE4,0xE4,0xD8,0xE4,0x00, ++ 0xE2,0x48,0xE4,0x90,0x90,0x95,0xE6,0x8C,0x17,0x12,0x9D,0x9E,0x41,0xA2,0xC3,0xC0, ++ 0x80,0x64,0xE8,0xCC,0x00,0x01,0x80,0x9C,0x34,0x82,0x81,0x01,0x83,0xC4,0xC0,0x01, ++ 0x85,0xBC,0x80,0x01,0x85,0xB4,0x08,0x8F,0x25,0x01,0x08,0x3F,0xC0,0x64,0xC0,0x03, ++ 0x4B,0x00,0x8C,0xF6,0xF0,0x42,0xC9,0x84,0x13,0x42,0xDC,0xD6,0xC3,0x8C,0x30,0x5A, ++ 0x01,0x00,0xD2,0x48,0x31,0x52,0xD0,0x01,0x5C,0x94,0x1E,0xD4,0x46,0x54,0x18,0xD4, ++ 0x40,0x4C,0x22,0xCC,0x31,0x4A,0xC9,0x01,0x5A,0x4C,0x26,0xCC,0x44,0x4C,0x21,0xCC, ++ 0x46,0x4C,0x23,0xCC,0xC8,0x08,0x32,0x52,0xD6,0x01,0x59,0x94,0x29,0xD4,0xD0,0x42, ++ 0x2A,0xC4,0x42,0x44,0x28,0xC4,0x44,0x3D,0x60,0x01,0x88,0x66,0x0C,0x01,0x18,0xCC, ++ 0x20,0xCC,0x2A,0xCC,0x10,0xCC,0x0C,0xF9,0x0B,0x48,0xC4,0xC8,0x4E,0x54,0x10,0xD4, ++ 0x48,0x4C,0x1A,0xCC,0x00,0x87,0xC9,0x8C,0xF4,0x48,0x12,0x62,0x88,0xC6,0x10,0x01, ++ 0x30,0x5A,0x23,0xD4,0x24,0xD4,0x2E,0xD4,0xD0,0x8C,0x18,0xF9,0xF2,0x90,0x04,0x90, ++ 0xCC,0x90,0x0E,0xD8,0xC0,0x90,0x4E,0x94,0x34,0x5A,0x13,0xD4,0x06,0x48,0xCA,0x50, ++ 0x0C,0xF9,0x08,0x48,0xC0,0x88,0x4A,0x4C,0x10,0xCC,0x0E,0x01,0x18,0xCC,0x00,0x9F, ++ 0xF2,0x08,0x03,0x48,0xC8,0x50,0x0E,0xF9,0x0A,0x48,0xC4,0x90,0x4B,0x94,0x30,0x5A, ++ 0x13,0xD4,0x04,0x10,0xCA,0x90,0xC6,0x90,0x4E,0x94,0x10,0xD4,0xE2,0x10,0x03,0x90, ++ 0xCA,0x90,0xC6,0x88,0x48,0x4C,0x18,0xCC,0xC8,0x9C,0x48,0x01,0x8B,0x26,0x30,0x5A, ++ 0x1E,0xCC,0x1C,0xCC,0x20,0xCC,0x00,0x4F,0xC8,0x94,0xD0,0x9C,0xF4,0x48,0x12,0x52, ++ 0x88,0x26,0x08,0x01,0x30,0x5A,0x2B,0xCC,0x2C,0xCC,0x2A,0xCC,0x0B,0x01,0xF0,0x4A, ++ 0x33,0x62,0x34,0x5A,0x14,0xE1,0xF0,0xD2,0x10,0x52,0xE4,0x16,0x14,0xF1,0xF0,0xD2, ++ 0x04,0x07,0x00,0x07,0x13,0x52,0xD4,0xF6,0x14,0x01,0xF1,0xD2,0x17,0x52,0xD4,0xD6, ++ 0x14,0x11,0xF1,0xD2,0x17,0x52,0xE4,0x86,0x14,0x31,0xF1,0xD2,0x17,0x52,0xD4,0x96, ++ 0x14,0x41,0xF1,0xD2,0x17,0x52,0xD4,0x76,0x14,0x51,0xF1,0xD2,0x17,0x52,0xE4,0x26, ++ 0x14,0x61,0xF1,0xD2,0x17,0x52,0xE4,0x06,0xCA,0xC4,0xE0,0x4B,0x4B,0x01,0x80,0xCE, ++ 0x0C,0x01,0x30,0x72,0x88,0x14,0x88,0x1C,0x88,0x7C,0x10,0x01,0xC8,0xDC,0x48,0x01, ++ 0x88,0x96,0x8B,0x24,0x1E,0x01,0xF0,0x1A,0xE8,0xC8,0xD2,0x36,0xC0,0xC8,0x94,0x55, ++ 0xCA,0x1C,0xE0,0x48,0x90,0x4D,0x8E,0x1C,0x00,0x2F,0x58,0x51,0xE8,0x1E,0xC8,0x14, ++ 0xE6,0x48,0x92,0x4D,0x8C,0x14,0xE0,0x00,0xCA,0x24,0xE0,0x48,0x90,0x4D,0x8E,0x24, ++ 0xC8,0x24,0x48,0x49,0x9B,0x36,0x37,0x02,0xC0,0x00,0x94,0x05,0xD5,0xBC,0x68,0x8C, ++ 0xE4,0x93,0x10,0x8A,0x98,0x0E,0xC9,0x74,0x10,0x42,0xD4,0xF6,0xC8,0x14,0x48,0x39, ++ 0x98,0x8E,0xC8,0x74,0x84,0x48,0x12,0x0A,0xD8,0xBE,0xC0,0x1C,0x40,0x01,0x00,0x4F, ++ 0x30,0x20,0x06,0x00,0xE0,0xD2,0x07,0x00,0xE0,0xD2,0x06,0x00,0x58,0x80,0x04,0x01, ++ 0x40,0x40,0x01,0x00,0x88,0x4E,0xC0,0xD4,0xF0,0x03,0x42,0x11,0x98,0x0E,0x00,0x09, ++ 0x37,0x32,0x4C,0xFA,0xC2,0x43,0xE2,0x00,0x80,0x43,0xC2,0xC4,0xE0,0x03,0x40,0x01, ++ 0x83,0xFE,0x30,0x82,0x40,0x01,0x88,0xE6,0xC2,0xD4,0xF0,0x03,0x40,0x51,0x98,0xC6, ++ 0x30,0x5A,0x03,0xB1,0x08,0x91,0xF1,0xC2,0xF4,0x8A,0x13,0x42,0xD8,0x5E,0x08,0xA1, ++ 0xF2,0xCA,0x82,0x48,0x04,0x07,0x00,0xDF,0x10,0x42,0xDC,0x26,0x0A,0xC1,0xF0,0xCA, ++ 0x84,0x48,0x12,0x42,0xD0,0x2E,0x00,0x09,0x37,0x32,0x4C,0x6A,0xC2,0x43,0xE2,0x00, ++ 0x87,0x43,0x52,0x5A,0xC0,0x83,0x40,0x81,0x97,0x16,0x4A,0x52,0xA2,0x62,0xE0,0x00, ++ 0x81,0x83,0x00,0xEF,0x07,0x57,0x3A,0xFF,0x30,0x1A,0x9B,0x04,0x83,0xC8,0x24,0x0A, ++ 0x90,0x4D,0x88,0x0C,0x08,0x01,0x88,0x24,0xCA,0x6C,0x80,0x48,0x88,0xAC,0x18,0x01, ++ 0xF0,0x1A,0xCE,0xAC,0x9C,0xA4,0x10,0x5A,0xD0,0x6E,0xD8,0xA4,0xCA,0x04,0xC0,0xC8, ++ 0x90,0x4D,0x88,0x04,0xD8,0xA4,0xC8,0x6C,0x10,0x5A,0xD4,0x26,0x32,0x1A,0x83,0xC8, ++ 0x20,0x0A,0x93,0x4D,0x88,0x0C,0xC8,0xA4,0xC0,0x48,0x94,0x55,0xE0,0x00,0xCC,0x24, ++ 0xE6,0x48,0x92,0x4D,0x88,0x24,0xC8,0x24,0x4F,0x49,0x98,0x06,0xC4,0x0C,0x10,0x12, ++ 0xD8,0x66,0xC8,0x74,0xC4,0x04,0x10,0x42,0xD8,0x46,0xC0,0xC4,0xE0,0x03,0x40,0x01, ++ 0x83,0x36,0x30,0x5A,0x00,0xB1,0xF0,0xC2,0x40,0x01,0xD0,0x0E,0x04,0x09,0x30,0x32, ++ 0xC2,0xD4,0xF0,0x03,0x40,0x51,0x98,0x16,0xC0,0xDC,0x40,0x01,0x80,0x46,0x00,0x09, ++ 0x30,0x8A,0x4B,0x01,0x80,0x06,0x00,0x01,0x80,0x7C,0x00,0x0F,0x00,0x09,0x80,0x7C, ++ 0xC0,0x7C,0x40,0x01,0x80,0xA6,0x01,0x09,0xB5,0x83,0x47,0xFA,0x40,0x03,0x42,0x01, ++ 0x88,0x5E,0xC0,0xD4,0xF0,0x03,0x42,0x51,0x90,0x3E,0xC0,0xBC,0x6E,0x8C,0xDB,0x03, ++ 0x32,0x00,0x72,0x00,0x84,0x51,0x10,0x0A,0xC8,0x0E,0x10,0x01,0x00,0x07,0x10,0x09, ++ 0xC0,0xE4,0x40,0x01,0x80,0x06,0x10,0x11,0x91,0x14,0x30,0x1A,0xB8,0x04,0xB0,0x0C, ++ 0x30,0x42,0xD1,0x9C,0xCF,0x64,0xB8,0xFF,0xC8,0x5F,0xC7,0xB4,0xE2,0x03,0x38,0x00, ++ 0xAD,0x1E,0xF0,0x83,0xFC,0x8B,0x13,0x42,0x98,0x56,0xC0,0xB4,0xE2,0x03,0x38,0x00, ++ 0xA7,0x26,0x00,0xF1,0xA8,0x83,0xC9,0xB4,0x04,0x01,0xA0,0x43,0x87,0xFD,0xE8,0x85, ++ 0xE0,0x68,0xC5,0x64,0xE0,0x00,0x82,0x64,0xE7,0x20,0x93,0x25,0xC4,0x8C,0x10,0x22, ++ 0x92,0x06,0x30,0x9F,0xC2,0x9C,0xE0,0x00,0x90,0x05,0x86,0x9C,0xC8,0x94,0xC0,0x9C, ++ 0x10,0x42,0x94,0x06,0x37,0x47,0x3A,0x4F,0xAC,0x9D,0x87,0x3D,0x30,0x3A,0xC0,0x44, ++ 0xD0,0x03,0x84,0x24,0xC6,0x44,0xD0,0x23,0x41,0xC2,0xC4,0xE8,0x06,0xF9,0x07,0x00, ++ 0xC0,0xF0,0xC1,0x44,0x08,0xF1,0xE8,0x03,0x84,0x17,0xD8,0xA7,0x04,0x29,0x04,0x00, ++ 0xC4,0xD0,0x41,0x9A,0x37,0xDA,0x99,0xF9,0xC1,0xC0,0x99,0x29,0x80,0x34,0x48,0xE9, ++ 0x88,0xDE,0x08,0x01,0x00,0x5F,0x00,0x01,0x00,0x2F,0xC0,0xFB,0x82,0xBB,0xE0,0x90, ++ 0xE2,0xD8,0xE2,0x00,0x95,0x05,0x16,0x02,0x9A,0xBE,0xE7,0x48,0x90,0x4D,0xC6,0x24, ++ 0x17,0x0A,0x9C,0x86,0x00,0x01,0x00,0x2F,0x41,0x8C,0x01,0x4C,0xE5,0x68,0xE5,0xB0, ++ 0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0xBE,0x00,0xCF,0xC3,0x44,0x82,0x01,0xF5,0x03, ++ 0x43,0x51,0x98,0xA6,0xC4,0x44,0xF0,0x03,0x80,0x2C,0x40,0x01,0x80,0x7E,0x9B,0x1C, ++ 0xF3,0x34,0x08,0x21,0x1B,0x01,0x00,0x21,0x30,0x32,0x04,0x01,0x30,0x22,0x84,0x14, ++ 0x29,0x01,0x00,0x1F,0x00,0x01,0x80,0x0C,0x01,0x97,0xC0,0xBB,0x48,0xF8,0x85,0x66, ++ 0x10,0x0A,0xCC,0x0E,0x30,0x0A,0x00,0x17,0x10,0x1A,0x94,0x06,0x30,0x1A,0xF8,0x14, ++ 0xE7,0xF8,0x93,0xFD,0xB8,0x14,0x38,0x09,0xBB,0x0C,0xE0,0xB0,0xE6,0x00,0x92,0x05, ++ 0x17,0x02,0x9D,0x56,0xC0,0x0C,0x40,0x01,0x85,0x36,0x28,0x72,0xCD,0x0E,0x30,0x72, ++ 0x05,0x17,0x28,0x62,0x95,0x06,0x30,0x62,0xE7,0x68,0x93,0x6D,0xC4,0x24,0x10,0x2A, ++ 0x98,0xC6,0xC6,0x2C,0x2B,0x51,0x18,0x42,0xED,0x14,0x10,0x42,0xC8,0xB6,0x48,0x01, ++ 0x82,0x0E,0xF0,0x48,0x93,0x4D,0xF6,0x00,0x10,0x1A,0xD4,0x0E,0xE6,0xD8,0x92,0xDD, ++ 0x30,0x82,0x43,0x01,0x82,0x16,0xF0,0x00,0x94,0x05,0x36,0x32,0xEB,0x24,0xF0,0x68, ++ 0x28,0x62,0xD5,0x1E,0x32,0x02,0xE3,0x00,0x94,0x05,0x36,0x22,0x28,0x01,0x00,0xDF, ++ 0x00,0x01,0x00,0xAF,0x10,0x42,0x9C,0x2E,0x28,0xAA,0x9B,0x1E,0x10,0xC2,0xC4,0x0E, ++ 0x28,0x2A,0xCB,0x3E,0xC1,0xB3,0x08,0xB8,0xD8,0xF8,0xF5,0x1C,0xC7,0xB3,0xC9,0xB0, ++ 0x48,0xB0,0x81,0xB3,0xE0,0x90,0xF2,0x1C,0xE0,0xB0,0xB3,0x1C,0xE6,0x00,0x92,0x05, ++ 0x17,0x02,0x9D,0x3E,0xE7,0x68,0x93,0x6D,0xC4,0x24,0x10,0x2A,0x98,0x06,0xC7,0x34, ++ 0x10,0x01,0x00,0x67,0x08,0x01,0x00,0x37,0xC4,0x1B,0x30,0xD8,0x70,0xD8,0x84,0x1B, ++ 0xE2,0x00,0xE2,0x48,0x95,0x4D,0x16,0x0A,0x9A,0xB6,0xE7,0x90,0x90,0x95,0xCE,0x24, ++ 0x17,0x52,0x9C,0x7E,0x87,0x4D,0xE8,0x85,0xAC,0xFD,0x87,0x1D,0x30,0x2A,0x30,0x62, ++ 0x05,0x01,0xB0,0x03,0xB1,0x03,0x37,0x02,0x80,0x01,0xE6,0x0B,0x10,0xE9,0x07,0x52, ++ 0x3E,0x48,0x7A,0x48,0x00,0x48,0x1A,0x52,0xA0,0x13,0xE0,0x0B,0x10,0xD9,0x07,0x8A, ++ 0xA1,0x0B,0x30,0x02,0x80,0x01,0x84,0x14,0xE1,0x03,0x7A,0x4A,0x40,0x01,0x80,0x56, ++ 0x01,0x01,0x50,0x42,0x08,0xF9,0xA7,0x8A,0xE6,0x00,0x92,0x05,0x47,0x81,0x98,0xD6, ++ 0x01,0x01,0x80,0xC3,0x80,0xC3,0xA3,0x04,0x30,0x5A,0x01,0x01,0xD0,0x34,0xC8,0x2C, ++ 0xBE,0xFF,0xE7,0xD7,0x35,0x32,0xB1,0x01,0xF0,0x83,0x43,0x51,0x98,0x36,0xA0,0x04, ++ 0x30,0x5A,0x01,0x09,0xD0,0x34,0xC8,0x2C,0xBE,0xFF,0xE7,0x77,0xC2,0x14,0xE0,0x03, ++ 0x43,0x01,0x80,0xF6,0x45,0xB2,0xF0,0x0B,0xC2,0x03,0x02,0x00,0x10,0x0A,0xCC,0x1E, ++ 0x48,0x9A,0x00,0x01,0x81,0x43,0x02,0xDF,0x48,0x8A,0xC0,0x43,0x30,0x22,0x44,0x21, ++ 0xC0,0xB6,0x01,0x01,0x00,0x8F,0x59,0x7A,0xE7,0xCA,0x48,0xF9,0x80,0x5E,0x11,0x01, ++ 0xE6,0x08,0x92,0x4D,0x00,0x97,0x78,0x5A,0xE3,0xDA,0xE1,0xFA,0xDA,0xD8,0xE6,0xD8, ++ 0x58,0x11,0xC0,0x4E,0x5A,0x32,0xC0,0xD3,0x50,0x01,0x80,0x0E,0xF2,0x90,0x82,0xD3, ++ 0x5F,0x22,0x10,0xF9,0xA0,0xD2,0x10,0x09,0xE6,0x48,0x92,0x4D,0x28,0x0A,0x03,0x4F, ++ 0x00,0xA0,0x00,0x01,0x58,0x00,0x04,0x01,0x58,0x80,0x04,0x01,0x40,0x40,0x01,0x00, ++ 0x30,0x20,0x06,0x00,0x98,0xFE,0x56,0x09,0x8B,0x2E,0x50,0x42,0xC0,0x8B,0x4A,0x01, ++ 0x82,0x0E,0xF0,0x48,0x82,0x8B,0xE2,0x00,0x93,0x05,0x7E,0x22,0x2E,0x02,0x9B,0x56, ++ 0x08,0x01,0xC0,0x14,0xE1,0x1B,0x32,0x02,0x80,0x01,0x59,0x09,0x8A,0x2E,0x50,0xFA, ++ 0xC0,0x93,0x52,0x01,0x80,0x9E,0x08,0x09,0x02,0x8F,0x50,0xE2,0xC0,0x93,0x52,0x01, ++ 0x8E,0x46,0xD8,0x3B,0x6B,0x14,0x33,0xF8,0x75,0xF8,0x13,0xD2,0x9F,0x3E,0xF0,0x13, ++ 0x50,0x01,0x88,0x26,0x68,0x14,0xE5,0x3B,0x10,0xD2,0x9D,0x06,0x08,0x09,0x48,0x01, ++ 0x83,0x2E,0xF0,0x8B,0x48,0x01,0x95,0x3E,0xE3,0x48,0xB2,0x8B,0x03,0x27,0xF0,0x8B, ++ 0x48,0x51,0x90,0x0E,0x0B,0x01,0xB0,0x8B,0xF0,0x8B,0x4B,0x51,0x9A,0x0E,0x51,0x5A, ++ 0xC0,0x93,0x52,0x01,0x8D,0x8E,0xF0,0x3B,0x78,0x01,0x88,0x76,0x58,0x09,0x88,0x26, ++ 0x00,0x07,0x00,0xB7,0xF3,0x48,0xB2,0x8B,0x06,0x3F,0xD8,0x03,0x6A,0x1C,0x33,0x00, ++ 0x74,0x00,0x14,0x1A,0x92,0x0E,0xF0,0x48,0xB0,0x8B,0x53,0x11,0x9D,0x16,0x00,0x01, ++ 0xB0,0x83,0x03,0x37,0x50,0x09,0x88,0x26,0xF2,0x83,0x43,0x81,0x93,0x0E,0x00,0x21, ++ 0xB5,0x83,0xF3,0x0B,0x4B,0x09,0xC8,0x5E,0x07,0x01,0xD0,0x13,0x90,0x04,0x10,0x01, ++ 0x02,0xA7,0x00,0x98,0xC9,0xF0,0x1A,0x09,0x0F,0xD8,0xC4,0x98,0xF0,0xF3,0xF2,0xDB, ++ 0xFA,0x04,0x00,0xD8,0x1B,0xF2,0x03,0xB0,0xCF,0xB0,0xC3,0x98,0x31,0x19,0x10,0xB0, ++ 0xCC,0xD8,0x44,0xDC,0xC4,0xC0,0x90,0x05,0xE6,0x90,0x92,0x95,0x17,0x8A,0xC4,0x46, ++ 0x87,0x17,0xC8,0x47,0x40,0x00,0x82,0x0C,0xC8,0x0B,0xC1,0x0C,0x12,0x0A,0x94,0x3E, ++ 0x0A,0x01,0x00,0x17,0x02,0x40,0xCA,0x10,0x04,0x09,0x09,0x00,0xC2,0x80,0xF0,0x13, ++ 0xF0,0x03,0xD8,0x04,0x02,0x00,0x1A,0xD2,0x02,0x90,0xCA,0x90,0xC0,0x80,0x10,0x19, ++ 0x14,0x90,0xC0,0x10,0x00,0x21,0xF0,0x82,0xD4,0x0C,0x10,0x82,0xD0,0x5E,0x31,0x42, ++ 0x02,0x17,0xE1,0x10,0x36,0xA2,0x94,0x95,0x01,0x98,0x3A,0x09,0xCD,0xD8,0x0A,0xF8, ++ 0xCA,0xD8,0x06,0x30,0x33,0xF2,0xCC,0xB0,0xF7,0xDB,0xC8,0xB0,0xB3,0x9B,0x31,0x9A, ++ 0xF3,0xDB,0xB2,0x9B,0x1A,0x31,0x18,0xD2,0x3A,0x19,0xCA,0x90,0x08,0xF8,0x33,0x31, ++ 0xCB,0x90,0x1E,0x82,0xCC,0x00,0x4A,0x9C,0xCC,0x00,0x0E,0x1C,0x4E,0x9C,0x0E,0x1C, ++ 0x50,0x94,0x10,0x14,0x36,0x12,0x93,0x85,0xF2,0x13,0xF5,0x90,0x16,0x12,0xE4,0xC6, ++ 0xF2,0x03,0xF5,0x00,0xB2,0x03,0xE5,0x48,0x95,0x4D,0xF6,0x03,0x15,0x42,0xC4,0xCE, ++ 0x31,0x0A,0x31,0x42,0xBF,0xFF,0xEF,0x87,0x87,0x3D,0xE8,0x85,0x00,0xA0,0x00,0x01, ++ 0xAC,0xFD,0x87,0x2D,0xE0,0x74,0x00,0x01,0x80,0x1C,0xC0,0x3C,0xD0,0x33,0xC6,0x3C, ++ 0x58,0x04,0x86,0x0C,0xC3,0x34,0x18,0x82,0x50,0xFA,0xCF,0x2C,0xC2,0x48,0xC4,0x08, ++ 0x8F,0x24,0x40,0xF2,0xC0,0x03,0x40,0x09,0x88,0x0E,0xC0,0x3C,0xD8,0x33,0x04,0x01, ++ 0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0x17,0x82,0x9D,0xCE, ++ 0x08,0x01,0x00,0x09,0xD8,0x44,0xD0,0x34,0x86,0x07,0xD0,0x6F,0x28,0x01,0x60,0x01, ++ 0x8B,0x0E,0xE0,0x68,0x90,0x6D,0xFF,0x24,0x08,0x01,0x00,0x5F,0xC1,0xC3,0x19,0x02, ++ 0x91,0x05,0x86,0xC3,0xD4,0x7C,0x10,0x82,0xCD,0x0E,0x18,0x02,0x83,0xC3,0xE1,0xF8, ++ 0xE6,0x48,0x92,0x4D,0x17,0x8A,0x9D,0x8E,0x08,0x09,0xC6,0x2C,0x02,0x48,0xC4,0x00, ++ 0x80,0x14,0xD0,0x44,0x90,0x04,0x00,0x11,0xD8,0x3C,0xD0,0x2C,0xC8,0x34,0x80,0x07, ++ 0xD8,0x07,0xD0,0x44,0xC0,0x3C,0x90,0x04,0x82,0x01,0xCA,0x0B,0x00,0x01,0x1C,0x0A, ++ 0x10,0x01,0xD8,0x3C,0xC0,0x14,0x80,0x0F,0xDD,0xCF,0xDD,0xC0,0x09,0x01,0x00,0x3F, ++ 0xD0,0x14,0x18,0x01,0xF0,0x9A,0xD6,0x0C,0xD0,0xD0,0x94,0x95,0x68,0x01,0x88,0x2E, ++ 0x50,0xC1,0xE8,0xBE,0xC5,0x13,0x18,0x12,0x80,0x13,0x00,0x9F,0x50,0x99,0xE8,0x2E, ++ 0xC0,0x13,0x50,0x01,0x82,0x16,0xF0,0x90,0x80,0x13,0x00,0x5F,0x68,0x29,0x88,0x4E, ++ 0x58,0xE1,0xEE,0x3E,0xC0,0x13,0x50,0x01,0x88,0x26,0xD0,0x1C,0x50,0x01,0x88,0x0E, ++ 0x10,0x09,0x90,0x1C,0xD4,0x14,0xE0,0x90,0x92,0x14,0xE0,0x00,0xE6,0x48,0x92,0x4D, ++ 0x16,0x8A,0x9D,0xAE,0x40,0x20,0x6B,0x21,0xC8,0x0E,0xD5,0x44,0x90,0x04,0x08,0x01, ++ 0x00,0x19,0xD8,0x3C,0xD0,0x2C,0x80,0x07,0xD0,0xE7,0x0D,0x09,0x30,0x42,0xD8,0x44, ++ 0xD0,0x34,0x80,0x07,0xD0,0x07,0xC3,0x1C,0x87,0x4D,0xE8,0x85,0xAC,0xFD,0x87,0x1D, ++ 0xF0,0x64,0x30,0x7A,0x37,0xEA,0xD0,0xC3,0x86,0x14,0x08,0x09,0xC4,0x1C,0x00,0x48, ++ 0xC5,0x20,0x42,0xB2,0xC0,0x03,0x40,0x09,0x8D,0x0E,0xD8,0xC3,0x80,0x14,0x08,0x01, ++ 0x00,0x09,0xD8,0x2C,0xD0,0x6C,0x80,0x07,0xD0,0x37,0xD2,0x2C,0x91,0x04,0x30,0xDA, ++ 0x00,0x11,0xD0,0x1C,0xC8,0x6C,0x80,0x07,0xD0,0xA7,0xD4,0x2C,0x92,0x04,0x00,0x29, ++ 0xEC,0x0A,0x06,0x01,0x19,0x0A,0x30,0xDA,0x11,0x01,0x30,0x02,0x82,0x0F,0xD8,0x77, ++ 0xD0,0x2C,0x90,0x04,0x30,0xDA,0x09,0x01,0x00,0x19,0xD0,0x1C,0x84,0x07,0xD0,0x0F, ++ 0x08,0x09,0x30,0x42,0xD8,0x2C,0xD0,0x6C,0x81,0x07,0xD0,0x2F,0x41,0x02,0x05,0x44, ++ 0x01,0x01,0x00,0x84,0x08,0x01,0x00,0x77,0x01,0x01,0xF0,0x02,0x15,0x01,0xF0,0x52, ++ 0x10,0x12,0xEC,0x06,0x00,0x44,0x11,0x01,0xF4,0x92,0x15,0x12,0xD1,0x06,0x00,0x84, ++ 0xE2,0x20,0xE5,0x48,0x90,0x4D,0xC6,0x14,0x17,0x0A,0x9C,0x6E,0x87,0x3D,0xE8,0x85, ++ 0xAC,0xBD,0x87,0x45,0xC2,0x4C,0xD8,0x03,0x80,0x1C,0xC8,0x4C,0xD0,0x4B,0x8E,0x14, ++ 0x50,0x6A,0xCC,0x44,0xC0,0x48,0x8C,0x3C,0x48,0x62,0xC4,0x4B,0x48,0x09,0x88,0x46, ++ 0xCA,0x1C,0xE0,0x48,0x90,0x4D,0x8E,0x1C,0x80,0x34,0xC0,0x4C,0xD8,0x03,0x84,0x14, ++ 0x00,0x0F,0x00,0x01,0x80,0x34,0xF8,0x34,0x04,0x3F,0x4B,0x32,0x04,0x01,0x00,0x43, ++ 0xC0,0x4C,0xC8,0x3C,0xD3,0x03,0x1E,0xC2,0xC0,0x08,0x02,0x01,0x10,0xF9,0x01,0x1F, ++ 0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0xDC,0x14,0x10,0xC2,0x9C,0xC6,0x27,0x01, ++ 0x31,0x2A,0x31,0x32,0x03,0xC7,0x40,0xE2,0x08,0x23,0x4E,0x25,0xB8,0x0C,0x88,0x04, ++ 0x40,0x45,0x40,0x3E,0x5F,0x2D,0xB8,0xFF,0xFB,0x8F,0x33,0x5A,0x00,0xA1,0xF0,0xC2, ++ 0x40,0xE1,0xD1,0x1E,0x68,0x41,0x80,0x4E,0x18,0x62,0x05,0x1F,0x70,0x01,0x8C,0x0E, ++ 0x30,0x72,0x01,0x1F,0x41,0x68,0x1B,0x62,0x6F,0x01,0x88,0x26,0xC0,0x4C,0xC8,0x3C, ++ 0xD3,0x03,0x1E,0xC2,0xC0,0x08,0x02,0x01,0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48, ++ 0xE6,0x00,0x92,0x05,0xDC,0x14,0x10,0xC2,0x99,0xC6,0x37,0xAA,0x20,0x01,0x00,0x0F, ++ 0x1B,0xA2,0x41,0xB0,0x77,0x01,0x88,0xDE,0xC6,0x4C,0x58,0x04,0xC0,0x41,0x91,0x35, ++ 0x05,0x8F,0x18,0x62,0x46,0x02,0x0B,0x23,0x48,0x25,0xB8,0x0C,0x88,0x04,0x40,0x45, ++ 0x40,0x3E,0x58,0x2D,0xB9,0xFF,0xFF,0xD7,0x30,0x5A,0x03,0x81,0xF5,0xC2,0x10,0x82, ++ 0xE9,0x06,0x18,0x62,0x40,0x68,0x6B,0x01,0x88,0x5E,0xC7,0x44,0x0E,0xE9,0xC9,0x00, ++ 0x0A,0x48,0xC2,0x00,0xAB,0x23,0xE0,0xF8,0x90,0xFD,0xC7,0x1C,0x14,0x3A,0x9C,0xA6, ++ 0xF1,0x34,0x00,0x9F,0xC1,0x44,0x08,0xE9,0xCA,0x00,0x0C,0x48,0xC1,0x38,0xEA,0xC3, ++ 0x40,0x01,0x88,0x0E,0x01,0x09,0xA8,0xC3,0xE8,0xE3,0x29,0x01,0x01,0x01,0x00,0x07, ++ 0xE7,0x68,0x93,0x6D,0x40,0x09,0x88,0x1E,0x60,0xF9,0x97,0x0E,0xE5,0x20,0x93,0x25, ++ 0x48,0x22,0x02,0x01,0x00,0x43,0xAC,0x48,0x46,0x1A,0x0A,0x23,0x20,0x00,0x67,0x10, ++ 0x02,0x07,0x40,0x48,0x30,0x82,0x10,0x42,0x81,0xDE,0x4F,0x01,0xC9,0x06,0x08,0x01, ++ 0x88,0x04,0x90,0x0C,0x40,0x45,0x40,0x6E,0x37,0x8A,0xB9,0xFF,0xF0,0x0F,0x43,0x01, ++ 0x80,0x0E,0x68,0x29,0x99,0xE6,0xAE,0xE3,0xE7,0xB0,0x93,0xB5,0xC4,0x1C,0x10,0x32, ++ 0x98,0x46,0x86,0x5D,0xEF,0x85,0xAF,0xBD,0x80,0x15,0x34,0x62,0x31,0xB2,0x48,0x7A, ++ 0x00,0x01,0x80,0x43,0x40,0x8A,0x41,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B,0x28,0x01, ++ 0x00,0x3F,0x08,0x09,0x31,0x9A,0x31,0x52,0x30,0x42,0x80,0x07,0xCB,0xA7,0xE1,0x68, ++ 0x95,0x6D,0xD7,0x03,0x17,0x42,0xC5,0xA6,0x31,0x12,0x31,0x8A,0x00,0x11,0x80,0x07, ++ 0xC1,0x7F,0x34,0x92,0x30,0x0A,0xC1,0x14,0xB8,0xFF,0xFF,0xD7,0x31,0x12,0x31,0x8A, ++ 0x00,0x01,0x80,0x07,0xC5,0x2F,0xDC,0x03,0x41,0x01,0x80,0x46,0x6F,0xF2,0x40,0x43, ++ 0x91,0x3D,0x4C,0x04,0x00,0x43,0x47,0xCA,0x08,0x09,0x80,0x0B,0x31,0x12,0x31,0x8A, ++ 0x00,0x11,0x80,0x07,0xC1,0xAF,0x33,0x1A,0xB0,0x04,0x08,0x01,0x00,0x09,0xD0,0x14, ++ 0x82,0x07,0xC8,0xFF,0xB3,0x04,0xD8,0x0B,0x30,0x1A,0x01,0x11,0xD0,0x14,0x80,0x07, ++ 0xC9,0xC7,0x32,0x92,0x30,0x0A,0xC1,0x14,0xBF,0xFF,0xF7,0x97,0x31,0x12,0x31,0x8A, ++ 0x00,0x01,0x80,0x07,0xC0,0xEF,0x42,0x4A,0x08,0x01,0x80,0x0B,0x01,0x7B,0x37,0x1A, ++ 0xB0,0x04,0x08,0x01,0x00,0x11,0xD0,0x14,0x82,0x07,0xC8,0x1F,0x31,0x12,0x31,0x8A, ++ 0x00,0x11,0x80,0x07,0xC0,0x6F,0x02,0x5F,0x30,0x20,0x06,0x00,0x00,0xB0,0x00,0x01, ++ 0xF8,0xFB,0x07,0x00,0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42, ++ 0x50,0x1A,0x40,0x83,0x0C,0x11,0x18,0x42,0x00,0x83,0x80,0x2D,0xE8,0x85,0x07,0x00, ++ 0x18,0x00,0x04,0x42,0xA8,0x85,0x31,0x12,0x90,0x01,0xE6,0x9B,0x32,0xD8,0x72,0xD8, ++ 0xA7,0x9B,0x58,0xCA,0x41,0xE3,0x30,0x20,0xA2,0x16,0x40,0xE3,0x3F,0x20,0xAB,0xE6, ++ 0x58,0xB2,0x27,0x41,0x00,0xE3,0x44,0xE3,0x28,0xF9,0xAF,0x19,0x18,0x62,0x01,0xE3, ++ 0x20,0x81,0x48,0x01,0x83,0x76,0x00,0xE9,0x08,0x00,0xE4,0x8B,0x48,0x48,0x8E,0x1E, ++ 0xF0,0x00,0x22,0x00,0x67,0x00,0x88,0xC6,0x40,0x01,0x88,0x16,0x41,0xC3,0x18,0x02, ++ 0x01,0xC3,0xE8,0x85,0x80,0x01,0xE5,0x8B,0x48,0x48,0x8E,0x16,0xE8,0x0B,0x4E,0x31, ++ 0x8E,0xCE,0xEF,0x03,0x47,0x31,0x88,0xA6,0x41,0xC3,0x18,0x02,0x01,0xC3,0xE8,0x85, ++ 0xAA,0x85,0x47,0x63,0x46,0x5B,0xD6,0xAB,0x71,0x0A,0xC7,0xB3,0x70,0x09,0x88,0x16, ++ 0x4A,0x63,0x56,0x5B,0xD8,0xAB,0x44,0x01,0x88,0x0E,0x11,0x01,0x01,0xE7,0x40,0x03, ++ 0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08,0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB, ++ 0x1C,0xF2,0x19,0x33,0x58,0x33,0xC6,0xFB,0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83, ++ 0xC5,0xF3,0x18,0x82,0x31,0x32,0x03,0x83,0x40,0x73,0xC0,0xC3,0x18,0x32,0x04,0x73, ++ 0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95,0x17,0x52,0x9D,0x06,0xE8,0x85,0x47,0x09, ++ 0x88,0x0E,0x11,0x01,0x01,0xE7,0x40,0x03,0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08, ++ 0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB,0x1C,0xF2,0x1D,0x33,0x58,0x33,0xC6,0xFB, ++ 0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83,0xC5,0xF3,0x18,0x82,0x31,0x32,0x03,0x83, ++ 0x40,0x73,0xC0,0xC3,0x18,0x32,0x00,0x73,0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95, ++ 0x17,0x52,0x9D,0x06,0xE8,0x85,0x47,0x11,0x88,0x0E,0x11,0x01,0x01,0xE7,0x40,0x03, ++ 0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08,0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB, ++ 0x1C,0xF2,0x1D,0x33,0x58,0x33,0xC6,0xFB,0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83, ++ 0xC1,0xF3,0x18,0x82,0x31,0x32,0x03,0x83,0x40,0x73,0xC0,0xC3,0x18,0x32,0x04,0x73, ++ 0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95,0x17,0x52,0x9D,0x06,0xE8,0x85,0x47,0x19, ++ 0x88,0xE6,0x17,0x01,0x01,0xE7,0x40,0x03,0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08, ++ 0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB,0x1C,0xF2,0x1D,0x33,0x58,0x33,0xC6,0xFB, ++ 0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83,0xC1,0xF3,0x18,0x82,0x31,0x32,0x03,0x83, ++ 0x40,0x73,0xC0,0xC3,0x18,0x32,0x00,0x73,0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95, ++ 0x17,0x52,0x9D,0x06,0xEF,0x85,0xAF,0x85,0x44,0xE3,0x02,0xB0,0xCE,0x20,0x45,0xEB, ++ 0xC0,0x68,0x45,0x09,0x88,0x26,0x40,0xE3,0xCC,0x20,0x45,0xDB,0xC0,0xE8,0x04,0x3F, ++ 0x79,0x7A,0xC4,0xFB,0x78,0x09,0x88,0x1E,0x4D,0xE3,0xCE,0x20,0x54,0xDB,0xC2,0xE8, ++ 0x40,0x13,0xF9,0xA0,0xC0,0x5B,0x41,0x09,0x88,0x76,0x48,0x01,0x8A,0x66,0x40,0x83, ++ 0x1A,0xC2,0x04,0x83,0x44,0x83,0x1C,0xC2,0x01,0x83,0x44,0x03,0x19,0xC2,0x04,0x03, ++ 0x40,0x83,0x18,0xC2,0x07,0x83,0xE8,0x85,0x48,0x09,0x88,0x66,0x44,0x83,0x1A,0xC2, ++ 0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83,0x44,0x83,0x18,0xC2,0x01,0x83,0x40,0x03, ++ 0x19,0xC2,0x00,0x03,0xE8,0x85,0x4F,0x11,0x89,0x66,0x40,0x03,0x19,0xC2,0x04,0x03, ++ 0x44,0x83,0x18,0xC2,0x02,0x83,0x40,0x83,0x1A,0xC2,0x00,0x83,0x44,0x83,0x1C,0xC2, ++ 0x07,0x83,0xEC,0x85,0x4F,0x19,0x88,0xE6,0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83, ++ 0x18,0xC2,0x04,0x83,0x44,0x83,0x1A,0xC2,0x04,0x83,0x42,0x83,0x1C,0xC2,0x00,0x83, ++ 0xEF,0x85,0xAF,0xFD,0xF4,0x4C,0x30,0x62,0x29,0x01,0x48,0x93,0x4C,0x8B,0x35,0x72, ++ 0xD1,0xE3,0x36,0x3A,0x48,0x32,0xC3,0x4B,0x48,0x09,0x88,0x0E,0x54,0x93,0xD9,0xE3, ++ 0x41,0x19,0x80,0x96,0x33,0x79,0x48,0x0A,0x10,0xB0,0x41,0x11,0x8B,0xB6,0x30,0x02, ++ 0x1B,0x3A,0x5A,0x02,0xC6,0x14,0xC0,0x00,0xC3,0xC0,0x31,0x9A,0x32,0x2A,0xEB,0xDA, ++ 0x08,0x5B,0x0A,0x01,0x00,0x3F,0xC0,0x1B,0x18,0x9A,0x41,0xAB,0x00,0x5B,0xE9,0x90, ++ 0xE2,0x00,0xE2,0x48,0x95,0x4D,0x16,0x0A,0x9F,0xAE,0xEF,0xFD,0x40,0x01,0x88,0x8E, ++ 0x1E,0x01,0x10,0x5B,0x40,0x82,0x42,0x33,0x45,0xB0,0x05,0xB0,0x02,0x33,0x00,0x1B, ++ 0x00,0x5B,0x40,0x0B,0x1C,0x81,0x18,0xCA,0x00,0x0B,0x40,0x0B,0x18,0x01,0x1C,0xCA, ++ 0x00,0x0B,0x00,0x17,0x40,0x09,0x88,0x06,0x30,0xAA,0x01,0x01,0x00,0x27,0x40,0x8B, ++ 0x00,0x6B,0xE8,0x90,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0xC6,0xEF,0xFD,0xAF,0x85, ++ 0x30,0x72,0xCC,0x2C,0xD5,0x63,0x36,0x22,0x46,0xEB,0x42,0xE3,0x40,0x01,0x88,0x1E, ++ 0xDC,0x43,0x32,0x22,0x44,0xEB,0x40,0xE3,0x51,0x19,0x88,0x16,0x00,0x01,0x00,0xEF, ++ 0x3E,0x10,0x7E,0x90,0x28,0x92,0x8B,0xAE,0x40,0x53,0x31,0xB2,0xB0,0x41,0xE8,0x98, ++ 0x32,0xD2,0xD0,0x01,0x59,0xBB,0xC4,0x0B,0x1C,0x7A,0x1C,0xBB,0x59,0xBB,0xC6,0x0B, ++ 0x1E,0x7A,0x1C,0xBB,0x41,0x93,0xC1,0x3B,0x19,0xD2,0x01,0x93,0x41,0xCB,0xC0,0x13, ++ 0x18,0x8A,0x00,0xCB,0xEB,0x68,0xE1,0x20,0xE6,0x00,0x92,0x05,0x2E,0x02,0x9B,0xFE, ++ 0xE8,0x85,0x57,0x29,0x88,0xE6,0x07,0x01,0x06,0xEF,0x38,0x10,0x7B,0x90,0x2E,0x92, ++ 0x89,0xAE,0x40,0x53,0x30,0xB2,0xB0,0x41,0xE8,0x98,0x30,0xD2,0xD4,0x01,0x5A,0xBB, ++ 0xC0,0x0B,0x19,0x7A,0x1E,0xBB,0x5C,0xBB,0xC4,0x0B,0x19,0x7A,0x19,0xBB,0x46,0x93, ++ 0xC5,0x3B,0x19,0xD2,0x00,0x93,0x41,0xCB,0xC4,0x13,0x19,0x8A,0x01,0xCB,0xE8,0x68, ++ 0xE2,0x20,0xE3,0x00,0x93,0x05,0x2E,0x02,0x9F,0xFE,0xEE,0x85,0xA8,0x85,0xF7,0x2C, ++ 0x37,0x22,0xD4,0xAB,0xC4,0x34,0x00,0xB8,0x4E,0x03,0xC8,0x20,0x44,0xB2,0xC0,0xD8, ++ 0xC3,0xC0,0x30,0x1A,0x58,0x01,0x88,0x1E,0xD8,0xAB,0xDB,0x34,0x4E,0xDB,0xCA,0xE0, ++ 0x48,0x11,0x88,0xA6,0xB5,0x01,0xE4,0x8B,0x48,0x01,0x80,0x16,0x18,0x69,0x10,0xD8, ++ 0x00,0x57,0x18,0x79,0x10,0xD8,0x00,0x3F,0xC0,0x0B,0x18,0xCA,0x41,0x33,0x01,0x8B, ++ 0xA4,0x41,0xE0,0x00,0xE6,0x90,0x94,0x95,0x17,0x52,0x9D,0xAE,0xE8,0x85,0x4F,0x19, ++ 0x8F,0xE6,0x07,0xF9,0x18,0x02,0x06,0x77,0x18,0x00,0x04,0x42,0x00,0x01,0x00,0x42, ++ 0x00,0xB0,0x00,0x01,0x30,0x20,0x06,0x00,0x40,0x60,0x02,0x00,0x40,0x0B,0x01,0x43, ++ 0xA4,0x41,0xE0,0x90,0x95,0x95,0x16,0x52,0x9F,0xC6,0xEF,0x85,0xAC,0xFD,0x87,0x25, ++ 0x30,0x6A,0x30,0xB2,0x31,0xE2,0x48,0x3B,0x06,0xC9,0x07,0x00,0xC0,0x40,0x81,0x1C, ++ 0xD0,0x83,0x87,0x14,0xC0,0x24,0x40,0x01,0x8B,0x16,0xD8,0x83,0x83,0x14,0x48,0x3B, ++ 0x30,0x1A,0x11,0x19,0x08,0x01,0xB0,0x04,0xC7,0x24,0xB8,0xFF,0xF9,0x87,0x32,0x1A, ++ 0x10,0x19,0x08,0x09,0xB0,0x04,0xC0,0x24,0xBA,0xFF,0xFF,0x4F,0x30,0x5A,0x11,0x01, ++ 0x08,0x11,0xB0,0x04,0xA0,0x0C,0xC0,0x24,0xBC,0xFF,0xFF,0xC7,0x30,0x5A,0x11,0x09, ++ 0x08,0x11,0xB0,0x04,0xA0,0x0C,0xC0,0x24,0xBC,0xFF,0xFF,0x87,0x36,0x82,0x81,0x01, ++ 0xE2,0x0B,0x30,0x48,0x70,0x48,0xA2,0x0B,0x57,0xFA,0x0F,0xC1,0x00,0x8B,0x44,0x8B, ++ 0x18,0xF9,0x9F,0x19,0x18,0xCA,0x00,0x8B,0x35,0x8A,0x89,0x01,0x01,0x07,0xF8,0x85, ++ 0xE6,0x1B,0x48,0xD8,0x8E,0x16,0xE8,0x5B,0x5F,0x31,0x88,0xC6,0xE8,0x43,0x46,0x31, ++ 0x88,0x1E,0x40,0x83,0x08,0x81,0x18,0x42,0x00,0x83,0x00,0x01,0x04,0x3F,0x00,0x08, ++ 0xC2,0xCA,0x43,0x4B,0xDA,0x1C,0x00,0x10,0x92,0xCA,0xE4,0x00,0x90,0x05,0xCE,0x14, ++ 0x17,0x42,0x9C,0xA6,0x30,0x5A,0x11,0x01,0x08,0x19,0xB0,0x04,0xA0,0x0C,0xC0,0x24, ++ 0xBA,0xFF,0xFF,0xE7,0x30,0x5A,0x11,0x09,0x08,0x19,0xB0,0x04,0xA0,0x0C,0xC0,0x24, ++ 0xBA,0xFF,0xFF,0xA7,0x30,0x1A,0x11,0x29,0x08,0x09,0xB0,0x04,0xC7,0x24,0xB8,0xFF, ++ 0xF1,0xB7,0x37,0x1A,0x10,0x29,0x08,0x01,0xB0,0x04,0xC0,0x24,0xBF,0xFF,0xF7,0x7F, ++ 0x87,0x45,0xE8,0x85,0xAC,0xFD,0x87,0x35,0x08,0xC9,0xC7,0x3C,0x02,0x48,0xC6,0x28, ++ 0x48,0xD2,0xC6,0x3C,0xC0,0x20,0xC2,0x44,0xD0,0x33,0xC6,0x34,0x40,0x01,0x88,0x0E, ++ 0xC2,0x44,0xD8,0x33,0xC4,0x44,0x80,0x01,0x86,0x2C,0xE0,0x03,0x43,0x01,0x88,0xE6, ++ 0x08,0xF9,0x01,0x17,0xA2,0x0A,0xE1,0x00,0x95,0x05,0x14,0x82,0x9C,0xD6,0x3F,0x01, ++ 0xB8,0x24,0xB8,0x14,0x06,0x57,0x49,0x62,0xC6,0x24,0x08,0x43,0x40,0x35,0x40,0x7E, ++ 0xBA,0xFF,0xFF,0xE7,0x48,0x52,0x1E,0x01,0x00,0x01,0x00,0x67,0x04,0x10,0x32,0xA2, ++ 0xF4,0x52,0x15,0xD2,0xEB,0x0E,0x30,0x1A,0xD4,0x5A,0x17,0x52,0xD3,0x0E,0x30,0x0A, ++ 0xD2,0x4A,0xE3,0x00,0x95,0x05,0x14,0x82,0x9A,0x86,0x4F,0x81,0x90,0x2E,0x78,0x41, ++ 0x80,0x76,0xC0,0x24,0x18,0xC2,0x85,0x24,0x00,0x27,0xC0,0x14,0x40,0x01,0x8C,0x0E, ++ 0xB8,0x14,0x00,0x2F,0x40,0xF8,0xC3,0x24,0x18,0xC2,0x81,0x24,0x7E,0x01,0x88,0x96, ++ 0x00,0x01,0x08,0x01,0x01,0x17,0xA0,0x0A,0xE4,0x00,0x92,0x05,0x17,0x82,0x9D,0xD6, ++ 0xC0,0x14,0x80,0x1C,0x38,0x01,0x00,0x27,0xC0,0x14,0x18,0x3A,0xC2,0x14,0x40,0x00, ++ 0x80,0x14,0xC0,0x14,0x47,0x01,0x88,0xBE,0xC6,0x2C,0x58,0x04,0xC0,0x41,0x91,0x05, ++ 0x81,0x0C,0x00,0x17,0xC4,0x1C,0x18,0x3A,0x46,0x3A,0x0D,0x3B,0x40,0x35,0x40,0x7E, ++ 0xB8,0xFF,0xFF,0xA7,0x58,0x32,0x0D,0x01,0x00,0x01,0x00,0x67,0x04,0x10,0x32,0xA2, ++ 0xF4,0x52,0x15,0x52,0xEB,0x0E,0x30,0x0A,0xD4,0x4A,0x13,0xD2,0xD3,0x0E,0x30,0x12, ++ 0xD2,0x5A,0xE5,0x00,0x95,0x05,0x14,0x82,0x98,0x86,0xC7,0x0C,0x10,0x0A,0xEC,0x0E, ++ 0xC0,0x1C,0x18,0x3A,0xC2,0x1C,0x40,0x00,0x80,0x1C,0xC0,0x1C,0x46,0x01,0x88,0xCE, ++ 0x78,0x01,0x88,0x06,0x38,0x09,0xC0,0x2C,0xA0,0x3B,0xC6,0x2C,0xE4,0x0B,0x46,0x92, ++ 0x08,0x0B,0xC6,0x2C,0xE0,0x03,0x3E,0x09,0x16,0xF8,0x07,0x00,0x80,0x24,0x00,0x07, ++ 0x40,0xF8,0xC3,0x24,0x17,0xC2,0x81,0xDE,0x78,0x01,0xC9,0x06,0x38,0x01,0x01,0x01, ++ 0x08,0x01,0x00,0x17,0xA2,0x0A,0xE1,0x00,0x95,0x05,0x14,0x82,0x98,0xD6,0x07,0x01, ++ 0x80,0x04,0x78,0x01,0x88,0x1E,0xC0,0x04,0xE6,0x00,0x92,0x05,0x80,0x04,0x00,0x01, ++ 0x01,0x57,0xE0,0x0A,0x1E,0xCA,0x91,0x4D,0xA0,0x0A,0xD1,0x24,0x10,0x8A,0xCC,0x0E, ++ 0x19,0xCA,0xA5,0x0A,0xE4,0x00,0x92,0x05,0x17,0x82,0x9D,0x96,0x40,0x35,0x40,0x7E, ++ 0xBD,0xFF,0xF7,0xE7,0x01,0x01,0x00,0x0F,0xD2,0x2C,0x00,0x08,0xD6,0x4A,0x5B,0x94, ++ 0xD0,0x48,0x94,0x4D,0xD0,0x04,0x50,0x01,0x8B,0x2E,0x48,0x21,0xE9,0xA6,0xE0,0x0A, ++ 0x19,0xCA,0xA5,0x0A,0x01,0x87,0x48,0x91,0xE9,0x2E,0xE0,0x12,0x50,0x01,0x80,0x16, ++ 0xF1,0x90,0xA2,0x12,0x01,0x47,0x10,0x89,0x1C,0x92,0x16,0x8A,0xD1,0x26,0xE0,0x0A, ++ 0x48,0xF9,0x91,0x0E,0xE1,0x48,0xA2,0x0A,0xE4,0x00,0x92,0x05,0x16,0x82,0x9D,0xDE, ++ 0x40,0xF8,0xC3,0x04,0x45,0x21,0xC8,0xE6,0x87,0x55,0xE8,0x85,0xAC,0xBD,0x87,0x75, ++ 0xCE,0x84,0xD0,0x6B,0x10,0xC9,0xCF,0x7C,0x04,0x90,0xC6,0x48,0x18,0xF9,0xD1,0x7C, ++ 0x0E,0xD8,0xC2,0x90,0x20,0xF9,0xDF,0x7C,0x00,0x20,0xCF,0xE0,0x30,0x09,0xDC,0x7C, ++ 0x0C,0xB0,0xC9,0xD8,0x99,0x14,0x30,0x09,0xDD,0x7C,0x08,0xB0,0xC8,0xD8,0x9C,0x0C, ++ 0x78,0x1D,0x40,0x01,0x88,0x0E,0xC0,0x84,0xD8,0x2B,0xC2,0x84,0xE0,0x03,0x44,0x29, ++ 0xC0,0x56,0x00,0x01,0x02,0x37,0x00,0x18,0xD6,0x72,0x96,0xB2,0xD7,0x72,0x96,0x32, ++ 0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xB6,0x04,0x01,0x30,0x22,0x18,0x01,0x00,0xCF, ++ 0x01,0xC0,0xD2,0x32,0x30,0x32,0xB4,0x6C,0x30,0x01,0x00,0x01,0xF8,0xB2,0xF4,0x42, ++ 0xC3,0xB0,0x81,0xB0,0x31,0x82,0x93,0x32,0x40,0x74,0x00,0xB4,0xD0,0x02,0xF1,0x6C, ++ 0xD9,0x00,0x04,0xC4,0x20,0x02,0x93,0x05,0x34,0x22,0xE4,0x90,0xE5,0x48,0xE4,0xF8, ++ 0xE6,0xD8,0x92,0xDD,0x17,0x5A,0x9D,0x1E,0x71,0x1D,0x30,0x4A,0x30,0x02,0x83,0x0F, ++ 0xD8,0x5F,0x95,0x0D,0x10,0x01,0x00,0xCF,0x01,0x01,0xF0,0x82,0xE0,0xB0,0x45,0x01, ++ 0xE8,0x2E,0x48,0x01,0xEC,0x1E,0x10,0x42,0xE8,0x56,0x30,0x42,0x00,0x47,0x40,0x01, ++ 0xD0,0x2E,0x48,0x01,0xD4,0x1E,0x10,0x42,0xD0,0x16,0x30,0x42,0x00,0x07,0x00,0x01, ++ 0x07,0x98,0xD2,0x3A,0xD7,0xC0,0x91,0x02,0xE6,0x90,0x92,0x95,0x17,0x52,0x9D,0x1E, ++ 0xC4,0x84,0xE0,0x03,0x40,0x29,0xC0,0xEE,0x00,0x01,0x10,0x01,0x02,0x3F,0x00,0x08, ++ 0xF3,0x14,0xD0,0x1A,0x90,0x9A,0xCB,0x0C,0xA2,0x52,0xE0,0x00,0x95,0x05,0x16,0x42, ++ 0x98,0xAE,0x07,0x01,0x12,0xF9,0x09,0x90,0x1A,0x09,0x0A,0xD8,0x00,0x47,0xE0,0x7C, ++ 0x00,0x08,0xCA,0x48,0xC1,0x60,0x5C,0x24,0xC0,0x48,0x0E,0x64,0xE6,0x00,0x92,0x05, ++ 0x17,0x42,0x9D,0xA6,0x87,0x8D,0xE8,0x85,0xAE,0xE5,0xD7,0x9B,0x9F,0x0C,0x18,0xF9, ++ 0x06,0xD8,0xC6,0x58,0x34,0xF2,0x1C,0x09,0x0E,0xD8,0xC0,0x68,0x1C,0x09,0x09,0xD8, ++ 0xC4,0x58,0x36,0xE2,0x1E,0xC9,0x07,0xD8,0xC0,0x48,0x8E,0x04,0x40,0x01,0x88,0x0E, ++ 0xD8,0x83,0x82,0x0C,0x00,0x01,0x30,0x9A,0x9A,0x01,0x14,0xC3,0x11,0xC3,0x04,0xCF, ++ 0x03,0x20,0x32,0x8A,0xD9,0x4A,0xD8,0x72,0xD8,0x48,0x94,0x75,0xC8,0x04,0x98,0x72, ++ 0x08,0x01,0x38,0xB1,0xBD,0xFA,0x16,0xBA,0xE8,0x66,0x08,0x09,0x3A,0x09,0x50,0xF3, ++ 0x01,0x3A,0x1C,0xF2,0x10,0xF3,0x02,0x77,0x00,0x01,0x00,0x42,0x40,0x60,0x02,0x00, ++ 0xF8,0xFF,0x07,0x00,0xED,0xFB,0x16,0xBA,0xD0,0x2E,0x08,0x09,0x3C,0x09,0x50,0xF3, ++ 0x01,0x3A,0x1C,0xF2,0x10,0xF3,0x4C,0x01,0x8D,0x96,0x08,0xC1,0xE0,0x4A,0x4C,0x01, ++ 0x89,0x76,0xF8,0x7A,0x13,0xF0,0x31,0x0A,0xE4,0x4A,0xC8,0x70,0x30,0x8A,0xFB,0x4A, ++ 0x04,0x48,0xCC,0x70,0x03,0xC8,0xD5,0x88,0x91,0x70,0x98,0x72,0x31,0x22,0xA3,0x0A, ++ 0xE6,0x00,0x92,0x05,0xCC,0x0C,0x10,0x42,0x9F,0x16,0xEE,0xE5,0xAC,0xBD,0x87,0x65, ++ 0x30,0x62,0x30,0xB2,0x40,0xFA,0x47,0x03,0x90,0x05,0x84,0x5C,0x40,0xF2,0x47,0x0B, ++ 0x90,0x4D,0x8C,0x54,0x44,0x0B,0x92,0x4D,0x8E,0x4C,0x40,0x0B,0x90,0x4D,0x8C,0x44, ++ 0x4C,0x0B,0x90,0x4D,0x8A,0x3C,0x48,0x0B,0x90,0x4D,0x8C,0x34,0x4C,0x0B,0x94,0x4D, ++ 0x8E,0x2C,0x50,0x0B,0x90,0x4D,0x8C,0x24,0x4C,0x0B,0x96,0x4D,0x8A,0x1C,0x58,0x0B, ++ 0x90,0x4D,0x8C,0x14,0x5C,0x0B,0x94,0x4D,0x88,0x0C,0x08,0x21,0x0C,0x0B,0x08,0x0B, ++ 0xE7,0x0B,0x53,0x72,0x1E,0x8A,0x10,0x0B,0x08,0x01,0xDD,0x4A,0x01,0x0B,0x36,0x2A, ++ 0xA9,0x01,0xEC,0x4B,0x1B,0x0B,0xEA,0x4B,0x1F,0x0B,0xE4,0x4B,0x0D,0x0B,0xE6,0x43, ++ 0x40,0x01,0x80,0x3E,0x47,0x22,0x4F,0x32,0x00,0x0B,0x0A,0xC9,0x00,0x0B,0x08,0x09, ++ 0x08,0x0B,0x02,0x3F,0x4F,0x12,0x47,0x02,0xCA,0xE1,0x00,0x0B,0x08,0x89,0x00,0x0B, ++ 0x0A,0x41,0x08,0x0B,0xE0,0x03,0x45,0x09,0x8B,0xB6,0xD8,0x03,0x80,0x04,0x38,0x01, ++ 0x00,0x3F,0x08,0x09,0x31,0x9A,0x31,0xD2,0x37,0x42,0xB8,0xFF,0xE3,0x67,0xE0,0xF8, ++ 0x90,0xFD,0xC7,0x04,0x17,0x3A,0x9C,0xA6,0x31,0x9A,0x31,0x12,0x00,0x09,0xC8,0x64, ++ 0xBD,0xFF,0xEF,0xC7,0xF3,0x43,0xB7,0x03,0x31,0x9A,0x31,0x12,0x00,0x09,0xC8,0x64, ++ 0xB9,0xFF,0xEF,0xA7,0x30,0x12,0x01,0x09,0xCF,0x64,0xB8,0xFF,0xF1,0xFF,0x34,0x12, ++ 0x00,0x09,0xC8,0x64,0xB9,0xFF,0xFF,0x87,0x48,0x32,0xC6,0x5C,0x06,0x43,0x40,0x32, ++ 0xC8,0x54,0x00,0x0B,0xCA,0x4C,0x00,0x0B,0xCE,0x44,0x00,0x0B,0xC8,0x3C,0x08,0x0B, ++ 0xCA,0x34,0x08,0x0B,0xCC,0x2C,0x08,0x0B,0xCE,0x24,0x10,0x0B,0xCE,0x1C,0x08,0x0B, ++ 0xCA,0x14,0x18,0x0B,0xCC,0x0C,0x18,0x0B,0xE6,0x43,0x31,0x00,0xAB,0x66,0xF1,0x03, ++ 0xF4,0x4B,0x15,0x42,0x89,0x46,0x31,0x02,0x82,0x01,0xE1,0x13,0x50,0x11,0x88,0x46, ++ 0xE8,0x13,0x51,0x51,0x88,0x16,0x10,0x01,0xA0,0x13,0x02,0x9F,0xE1,0x90,0xAA,0x13, ++ 0x05,0x87,0x50,0x53,0x50,0x01,0x88,0x2E,0x50,0x53,0x53,0x01,0x89,0x16,0xE8,0x13, ++ 0x50,0x01,0x89,0x2E,0xF3,0x53,0xB7,0x13,0x11,0x09,0xB0,0x13,0xA0,0x13,0x02,0x0F, ++ 0xE1,0x90,0xAA,0x13,0xF4,0x03,0x13,0x42,0x88,0x36,0x08,0x01,0x30,0x1A,0xB1,0x04, ++ 0x30,0x42,0xD0,0x64,0xBF,0xFF,0xDF,0xEF,0x31,0x12,0x31,0x8A,0x07,0x11,0xB8,0xFF, ++ 0xD8,0x3F,0x80,0x7D,0xEF,0x85,0xAF,0x85,0x4E,0xA3,0xD0,0xEB,0x33,0x70,0x72,0xB0, ++ 0x4F,0x78,0x0E,0xF8,0x48,0xFA,0xC4,0x4B,0x48,0x09,0x88,0x0E,0x54,0xA3,0xD8,0xEB, ++ 0x0F,0x01,0x18,0xF9,0x01,0x6F,0x40,0x13,0x47,0x93,0x02,0x92,0x90,0x95,0x00,0x14, ++ 0x78,0x01,0x88,0x16,0x50,0xF9,0xEF,0x06,0x01,0x1C,0xE8,0x20,0xE2,0x00,0xE4,0x48, ++ 0x95,0x4D,0x16,0x4A,0x9F,0x7E,0xEF,0x85,0xA8,0xC5,0x33,0x2A,0x34,0xB2,0x60,0x6A, ++ 0x44,0x03,0x11,0x01,0x19,0x82,0x04,0x03,0x40,0x03,0x11,0x81,0x19,0x82,0x00,0x03, ++ 0x40,0x03,0x11,0x09,0x19,0x82,0x00,0x03,0xE7,0x53,0x03,0xF9,0x80,0x81,0x18,0x12, ++ 0x46,0x2A,0x14,0x13,0x13,0x99,0x00,0x13,0x14,0x41,0x00,0x13,0x12,0x91,0xEC,0x92, ++ 0x50,0x01,0x80,0x16,0x10,0xC9,0x00,0x13,0x00,0x0F,0x10,0x89,0x00,0x13,0x30,0x52, ++ 0x30,0x5A,0x09,0x01,0x00,0x09,0xB0,0x04,0xBD,0xFF,0xDF,0x5F,0x31,0x52,0x31,0x8A, ++ 0x07,0x11,0xB8,0xFF,0xD3,0xAF,0x45,0x03,0x3F,0x00,0xAA,0xE6,0xEF,0xC5,0xAB,0x9D, ++ 0x80,0x8D,0xCC,0x94,0xC8,0x4B,0x8A,0x84,0xE2,0x94,0xA0,0x01,0xD3,0x1B,0xD1,0x0B, ++ 0x88,0x0C,0xC8,0x94,0xD0,0x6B,0x36,0x0A,0x8C,0x61,0x30,0x62,0xC8,0x94,0x30,0x01, ++ 0xE0,0x4B,0x4C,0x09,0x88,0x56,0x08,0x01,0x02,0x27,0xC0,0x38,0x9A,0xF3,0xA1,0x32, ++ 0xE2,0x48,0x92,0x4D,0xD6,0x94,0xD0,0x93,0x17,0x52,0xE4,0xB6,0x52,0x52,0x03,0xB3, ++ 0x06,0xB3,0x04,0xB3,0x0E,0x01,0x18,0x4A,0x00,0x8B,0xC8,0x94,0xD0,0x4B,0xB6,0x8B, ++ 0x0B,0x01,0x50,0x2A,0x34,0x01,0x00,0x78,0xC1,0xF8,0x0D,0xF3,0xC2,0x90,0xB2,0xB3, ++ 0xE2,0x48,0x92,0x4D,0x4F,0x11,0xD8,0xA6,0xCC,0x94,0xE0,0x4B,0x4B,0x29,0xC8,0xA6, ++ 0x00,0x48,0xC5,0x48,0x04,0x50,0xC3,0x70,0x14,0x09,0x06,0x90,0xC0,0xB0,0xB5,0x1C, ++ 0xC0,0x48,0x8C,0x14,0x30,0x12,0x33,0x32,0xB0,0xC1,0x08,0x01,0x8A,0x3C,0x48,0xBA, ++ 0x88,0x6C,0x88,0x64,0x30,0x32,0x04,0x01,0x32,0x22,0x04,0x27,0xC8,0x1C,0x00,0x01, ++ 0xF0,0x42,0xF8,0x14,0x0B,0x01,0xF0,0xCA,0x32,0x7A,0xD0,0x08,0x97,0x4D,0x48,0xF9, ++ 0xEF,0x06,0x08,0xF9,0xCB,0x38,0x86,0xF8,0x78,0xF9,0xEF,0x06,0x3B,0xF9,0x37,0x82, ++ 0x82,0x3B,0xE0,0x00,0x30,0x32,0xC4,0xBB,0x10,0xFA,0x9C,0x46,0x10,0xCA,0xDC,0x36, ++ 0x46,0x84,0xD9,0x48,0xC0,0x00,0x92,0x05,0x04,0x84,0x81,0x08,0x04,0x37,0x10,0xCA, ++ 0xDC,0x16,0x00,0x78,0x00,0xBC,0x01,0x0F,0x39,0x01,0x00,0xBC,0x10,0xCA,0xDC,0x0E, ++ 0x38,0x09,0xB8,0x3C,0x43,0x78,0x2B,0x3A,0xE8,0x26,0xF8,0x6C,0x10,0x7A,0xEC,0x2E, ++ 0x88,0x6C,0x00,0x1F,0xFC,0x64,0x10,0x7A,0xE8,0x06,0x88,0x64,0x82,0x8B,0xE0,0x90, ++ 0xE0,0xB0,0xC5,0x1C,0xE0,0x00,0x84,0x1C,0xC4,0x14,0xE0,0x00,0x83,0x14,0x30,0x02, ++ 0xE2,0x00,0x92,0x05,0x35,0x22,0x2C,0x62,0xD8,0xC6,0xC5,0x3C,0x40,0x01,0x80,0xA6, ++ 0x08,0x01,0x00,0x01,0x80,0x5C,0xC0,0x0C,0xC2,0x00,0x46,0x00,0x80,0x7C,0xC0,0x0C, ++ 0x30,0x00,0x72,0x00,0x80,0x74,0x00,0x01,0x30,0x22,0x84,0x34,0x80,0x2C,0x80,0x24, ++ 0xF3,0x90,0xF2,0x40,0x94,0x05,0x32,0x32,0x05,0x7F,0x02,0x77,0x32,0x02,0x03,0x00, ++ 0x30,0x22,0xC4,0x34,0x00,0x00,0x82,0x34,0xC2,0x2C,0x00,0x00,0x80,0x2C,0xC0,0x24, ++ 0x00,0x00,0x82,0x24,0x43,0x40,0x2B,0x82,0xE8,0x26,0xC0,0x83,0xF4,0x6C,0xD8,0x00, ++ 0x80,0x83,0x00,0x1F,0xC0,0x83,0xF0,0x64,0xD8,0x00,0x84,0x83,0xC0,0x83,0x70,0x45, ++ 0x37,0xBA,0xAB,0x82,0xC4,0x83,0x10,0xC2,0xDA,0xDE,0xE0,0x48,0x90,0x4D,0xF2,0x5C, ++ 0xC1,0xB0,0x91,0xB5,0xB3,0x5C,0x30,0x32,0x39,0x09,0x18,0xF2,0x30,0xA2,0xF5,0x7C, ++ 0x10,0x82,0xDD,0x76,0xF1,0x34,0x18,0xF2,0xB0,0x34,0xF0,0x0C,0x10,0x82,0xDD,0x46, ++ 0xF1,0x2C,0x18,0xF2,0xB0,0x2C,0xF0,0x74,0x10,0x82,0xDD,0x16,0xC1,0x24,0x18,0xC2, ++ 0x80,0x24,0x00,0x6F,0x18,0x00,0x04,0x42,0x00,0x01,0x00,0x42,0x10,0x78,0x00,0x00, ++ 0x88,0x60,0x05,0x00,0x00,0xB0,0x00,0x01,0x58,0x80,0x04,0x01,0x78,0xF8,0x07,0x00, ++ 0xF3,0x90,0x32,0x82,0xF2,0x00,0x92,0x05,0x33,0x32,0x34,0x82,0x45,0x01,0xD0,0x6E, ++ 0x42,0xFA,0xB7,0x0B,0xD0,0x50,0xB3,0x13,0x36,0x12,0x1B,0x92,0x03,0x13,0x30,0x12, ++ 0x08,0x13,0xD0,0x34,0x00,0x13,0xD2,0x2C,0x00,0x13,0xD4,0x24,0x00,0x13,0x36,0x01, ++ 0x00,0xA7,0xC1,0x5C,0x87,0x0F,0xC0,0x07,0x90,0x05,0x80,0x5C,0x4D,0xA2,0x07,0x80, ++ 0xC0,0x00,0x4A,0x13,0x40,0x45,0x08,0x01,0x1C,0x01,0x30,0xF2,0x30,0xE2,0x04,0xCF, ++ 0x38,0x98,0x86,0x7E,0xC0,0x1B,0xF8,0x5C,0xD8,0xD8,0x96,0xDD,0x58,0x01,0xE8,0x36, ++ 0x83,0x1B,0x20,0x9A,0x94,0xDD,0x36,0xF2,0xE2,0x48,0x92,0x4D,0x00,0x27,0x18,0x01, ++ 0x80,0x1B,0x00,0x0F,0x18,0x01,0x80,0x1B,0x42,0x90,0xE2,0x00,0x32,0x1A,0xE3,0xD8, ++ 0x94,0xDD,0x32,0xE2,0x2F,0x62,0xDD,0x1E,0xE3,0xB0,0x93,0xB5,0x30,0x82,0x83,0x5C, ++ 0x45,0xFA,0x06,0x98,0xC0,0xD8,0x08,0xD3,0xCA,0x00,0xB4,0x0B,0x48,0x21,0xD8,0x0E, ++ 0x76,0x09,0xD8,0x36,0x06,0x01,0x50,0xD2,0x04,0x08,0xC4,0x58,0xE4,0x08,0x02,0x70, ++ 0xC0,0xB0,0x4D,0xEB,0x4D,0xB3,0x19,0xAA,0x08,0xEB,0xC0,0x80,0xF4,0x1B,0xF2,0x2B, ++ 0xDA,0xD8,0xB2,0x1B,0x90,0x45,0x42,0x09,0xD8,0x76,0x07,0x09,0x9E,0x03,0x45,0x82, ++ 0x0E,0x19,0x40,0x13,0x50,0x01,0x80,0x16,0x05,0x29,0x98,0x0B,0x04,0xF7,0x40,0x13, ++ 0x50,0x01,0x80,0x16,0x05,0x21,0x98,0x0B,0x02,0xC7,0x40,0x0B,0x48,0x01,0x80,0x1E, ++ 0x00,0x19,0x08,0x11,0x98,0x0B,0x05,0x8F,0x48,0x03,0x40,0x01,0x88,0x26,0xC0,0x94, ++ 0x82,0x01,0xF5,0x03,0x40,0x51,0x98,0x0E,0x00,0x11,0x00,0x3F,0xC1,0x94,0x80,0x01, ++ 0xD8,0x03,0x44,0x01,0x80,0x0E,0x00,0x11,0x00,0x07,0x00,0x09,0xDC,0x0B,0xE5,0x50, ++ 0x9D,0x13,0xD7,0x13,0x38,0x90,0xA2,0x0E,0xF5,0x48,0x9A,0x0B,0xE0,0x0B,0x13,0x29, ++ 0x10,0x0A,0x94,0x0E,0xA0,0x13,0x01,0xEF,0x10,0x0A,0xCC,0x46,0x40,0x09,0x88,0x16, ++ 0x09,0x81,0xA7,0x0B,0x00,0xB7,0xD0,0x48,0x01,0x52,0xA4,0x13,0x00,0x97,0x40,0x19, ++ 0xC8,0x0E,0x08,0x19,0x02,0x07,0x90,0x0D,0xE0,0x13,0x51,0x01,0x82,0x16,0xF0,0x90, ++ 0xA0,0x13,0x01,0x3F,0xD2,0x94,0xF0,0x48,0xCA,0x93,0x1C,0x52,0xCA,0x84,0xC0,0x88, ++ 0xD0,0x94,0x88,0x8B,0xA0,0x03,0x83,0x9D,0xEF,0x85,0xAF,0xBD,0x80,0x6D,0x34,0x6A, ++ 0xD1,0x63,0x37,0x42,0x80,0x01,0x82,0x64,0xC8,0x03,0x86,0x3C,0xC4,0x64,0xD0,0x03, ++ 0x30,0x00,0xA8,0x1E,0x02,0x91,0xEC,0x02,0x40,0x01,0x80,0xAE,0xC5,0x6C,0x00,0x08, ++ 0xC3,0x40,0x00,0x08,0x12,0x09,0xC6,0x08,0x04,0x90,0xC4,0x48,0xC0,0x10,0x04,0x01, ++ 0x18,0x01,0x00,0x2F,0x00,0x5C,0x00,0x9C,0xE4,0x48,0xE4,0x90,0xE2,0x00,0x92,0x05, ++ 0x17,0x02,0xDD,0xBE,0x87,0x85,0xE8,0x85,0x00,0xE9,0xC9,0x6C,0x08,0x00,0xC2,0x40, ++ 0x70,0x82,0xEC,0x03,0x08,0x83,0xD7,0x7C,0x91,0x04,0x30,0x5A,0x08,0x01,0x00,0x11, ++ 0xD7,0x6C,0xB8,0xFF,0xCC,0xB7,0x45,0x5A,0x80,0x01,0x42,0x0B,0x34,0x5A,0x0B,0xCC, ++ 0x5E,0x8B,0x09,0xCC,0x58,0x8B,0x13,0xCC,0x5A,0x8B,0x15,0xCC,0x44,0x8B,0x17,0xCC, ++ 0x48,0x2A,0x44,0x53,0x17,0xD4,0x4E,0x93,0x18,0xD4,0x10,0x89,0x00,0x93,0x17,0x19, ++ 0x18,0x93,0x43,0x53,0x1C,0x11,0x18,0xD2,0x00,0x53,0x40,0x0B,0x18,0xCA,0x00,0x0B, ++ 0x35,0x42,0xE1,0x4B,0x80,0x01,0x81,0x5C,0x4A,0x09,0x88,0x66,0x68,0x44,0x81,0x14, ++ 0x34,0x8A,0x59,0x43,0x90,0x35,0xB6,0x0C,0x00,0x01,0x80,0x04,0xD6,0x6C,0x08,0x09, ++ 0x04,0x00,0x07,0x48,0xC2,0x00,0xC4,0x00,0x83,0x54,0x40,0x92,0x18,0x33,0x0A,0x01, ++ 0x37,0x42,0xB9,0xFF,0xC0,0xBF,0xFA,0x54,0xC1,0x64,0x30,0x5A,0xC9,0x0B,0x34,0xC2, ++ 0xD7,0x7C,0xB8,0xFF,0xEB,0x07,0x4C,0x6A,0x10,0x01,0x00,0x01,0x02,0x67,0x00,0x18, ++ 0x37,0xE2,0xF4,0xDA,0x10,0x5A,0xD4,0x0E,0x33,0x0A,0xD3,0xCA,0x10,0x9A,0xEC,0x0E, ++ 0x35,0x12,0xD3,0xD2,0xE2,0x00,0x92,0x05,0x17,0x02,0xDD,0x86,0xC4,0x14,0xE0,0x00, ++ 0x10,0x0A,0x9C,0x36,0xC0,0x04,0x40,0x01,0x8B,0x9E,0x40,0x80,0x40,0x08,0xC2,0x70, ++ 0x00,0x3F,0xC0,0x14,0xF4,0x00,0x14,0x12,0xE0,0x5E,0x00,0x09,0x83,0x04,0xE0,0xB0, ++ 0x90,0xB5,0x77,0x01,0x80,0x16,0xC0,0x0C,0x16,0x32,0x9C,0x36,0x70,0x01,0x88,0x06, ++ 0x30,0x09,0xC0,0x5C,0x88,0x33,0xC0,0x5C,0xCA,0x0B,0x40,0x92,0x18,0x0B,0x32,0x01, ++ 0x35,0x42,0x81,0x01,0x81,0x4C,0x80,0x01,0x83,0x44,0x00,0x4F,0xC4,0x3C,0x10,0x32, ++ 0xD0,0x6E,0xC0,0x44,0xE0,0x03,0xC8,0x44,0x32,0x00,0x72,0x00,0xA2,0x43,0x40,0x4A, ++ 0x0C,0x41,0x00,0x0B,0x47,0x0B,0x10,0xF9,0x90,0x21,0x18,0x8A,0x00,0x0B,0xC8,0x6C, ++ 0x02,0x00,0xC5,0x08,0x06,0x00,0x13,0x09,0xC4,0x40,0x00,0x90,0xC4,0x00,0xC4,0x48, ++ 0x70,0x01,0x88,0x66,0x12,0x01,0x78,0x0A,0x00,0x37,0x18,0x01,0x00,0x1C,0x00,0x7C, ++ 0xE4,0x00,0xE4,0x48,0xE2,0x90,0x92,0x95,0x17,0x12,0xDD,0xB6,0x00,0x0F,0xD9,0x6C, ++ 0x06,0x10,0xC7,0x90,0x1C,0x09,0x06,0xD8,0xC4,0x90,0x36,0xA2,0x18,0x01,0x00,0x9F, ++ 0x30,0x3A,0x13,0x01,0xF0,0xD2,0x3D,0x01,0xFC,0x3A,0x16,0xBA,0xD0,0x06,0x00,0x14, ++ 0x3E,0x01,0xF8,0x7A,0x10,0xBA,0xEC,0x06,0x04,0x54,0xE0,0x00,0xE3,0x48,0x34,0x12, ++ 0xE4,0x90,0x34,0xA2,0xE2,0xD8,0x92,0xDD,0x17,0x1A,0xDD,0x4E,0xC4,0x3C,0x10,0x32, ++ 0x80,0x0E,0xC1,0x44,0xE6,0x03,0x48,0x00,0x88,0x1E,0xC0,0x4C,0xE8,0x03,0x46,0x31, ++ 0x88,0xBE,0xC7,0x4C,0xE8,0x03,0x46,0x31,0x89,0x26,0x40,0x12,0x40,0x0B,0x10,0x81, ++ 0x18,0x8A,0x00,0x0B,0xCF,0x6C,0x00,0x00,0xC6,0x00,0x0A,0x09,0x02,0x48,0xC4,0x00, ++ 0xC9,0x64,0x30,0x5A,0xC8,0x4B,0xD4,0x7C,0xBE,0xFF,0xE7,0xEF,0xE3,0xB0,0x93,0xB5, ++ 0xC4,0x3C,0x10,0x32,0xE8,0x96,0x44,0xBA,0x34,0x5A,0x4B,0xCC,0x80,0x01,0x02,0x0B, ++ 0x46,0xA2,0x48,0xCC,0x18,0x0B,0x50,0xCC,0x1A,0x0B,0x52,0xCC,0x1C,0x0B,0x54,0xCC, ++ 0x00,0x0B,0x4E,0x8A,0x50,0xD4,0x06,0x53,0x5E,0xCC,0x08,0x0B,0x37,0x97,0xAF,0xFD, ++ 0x81,0xED,0xE4,0x3C,0x30,0xAA,0x00,0x01,0x80,0x7C,0x80,0x74,0xC6,0x34,0xD1,0x03, ++ 0x81,0x6C,0xC0,0x34,0xDA,0x03,0xF2,0x00,0x90,0x05,0x86,0x64,0x00,0x01,0x80,0x5C, ++ 0x80,0x54,0x80,0x4C,0xC4,0x34,0xC9,0x03,0x00,0x00,0x82,0xBC,0x08,0xA1,0x05,0x3F, ++ 0x58,0x80,0x04,0x01,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0xF8,0xFB,0x07,0x00, ++ 0xC2,0x34,0xF1,0x0A,0x80,0x40,0x82,0xB4,0xC1,0x34,0xD9,0x04,0xE7,0x03,0x9C,0xF9, ++ 0x98,0x29,0x41,0x09,0x88,0x76,0xC0,0x6C,0x1E,0x42,0xC3,0x08,0xD0,0xEC,0x00,0x01, ++ 0x00,0x2F,0x40,0xB4,0x82,0x73,0xE0,0x48,0xE2,0x90,0xE4,0x00,0x90,0x05,0xF2,0x6C, ++ 0x17,0x82,0xDD,0xB6,0x00,0x01,0x80,0x9C,0x80,0xA4,0x80,0xAC,0xC4,0xEC,0x30,0x32, ++ 0x70,0x1D,0xC8,0x6C,0x32,0x42,0x19,0x42,0x86,0xE4,0xC0,0x00,0x30,0x22,0x84,0xDC, ++ 0x40,0xAA,0x47,0x13,0x48,0x1B,0x08,0x01,0x03,0x1F,0x31,0x82,0x30,0x3A,0x43,0x04, ++ 0xC6,0xFB,0xD9,0x00,0x91,0x05,0x00,0x84,0x38,0xB8,0x86,0x26,0xFE,0xAC,0xC8,0x00, ++ 0x90,0x05,0x80,0xAC,0x06,0x57,0x38,0xF8,0x80,0x26,0xF8,0xA4,0xC8,0x00,0x96,0x05, ++ 0x80,0xA4,0x00,0x1F,0xFE,0x9C,0xC8,0x00,0x90,0x05,0x80,0x9C,0xE3,0xB0,0x35,0x82, ++ 0xE4,0x00,0x34,0x32,0x32,0x02,0xE3,0x00,0x32,0x22,0x44,0x90,0x42,0xD8,0xE2,0x48, ++ 0x90,0x4D,0xC2,0x6C,0x16,0x0A,0xDC,0xC6,0x79,0xFA,0xF6,0xCB,0x48,0x01,0xE8,0x26, ++ 0xC0,0xAC,0x80,0x07,0xF0,0x8F,0x94,0x05,0x83,0xAC,0xF0,0xCB,0x48,0x01,0xE8,0x56, ++ 0x48,0x09,0x88,0x1E,0xC2,0xA4,0x80,0x00,0x80,0xA4,0x00,0x27,0xC0,0xA4,0x80,0x07, ++ 0xF0,0x1F,0x94,0x05,0x85,0xA4,0xF0,0xCB,0x48,0x01,0xE8,0x56,0x48,0x09,0x88,0x1E, ++ 0xC2,0x9C,0x80,0x00,0x80,0x9C,0x00,0x27,0xC0,0x9C,0x80,0x07,0xF0,0xAF,0x93,0x05, ++ 0x80,0x9C,0xF0,0xEC,0x40,0x1D,0x80,0x04,0xC0,0xDC,0x80,0x14,0x40,0xC3,0x81,0x94, ++ 0x48,0xC3,0x81,0x8C,0xC2,0x34,0x81,0x01,0x84,0xD4,0xD0,0x03,0x38,0x00,0x86,0x7E, ++ 0x40,0xC3,0x83,0x84,0x40,0xC3,0x85,0x7C,0x40,0xC3,0x87,0x74,0xC6,0xD4,0xD0,0x03, ++ 0x80,0x5C,0xC0,0xD4,0xD8,0x03,0x80,0x54,0xC2,0xD4,0xD8,0x03,0x80,0x4C,0x00,0x0F, ++ 0x00,0x01,0x80,0x84,0xC0,0x04,0xC9,0xE4,0x80,0xA1,0xC1,0x40,0x80,0x0C,0xC0,0xE4, ++ 0xCA,0x04,0x01,0x00,0xC5,0x00,0x4A,0xCA,0xC0,0x38,0x02,0x01,0x80,0xC4,0x00,0x09, ++ 0x00,0x42,0x85,0xCC,0x00,0x5F,0xC5,0x94,0x38,0x00,0x86,0x0E,0xC0,0xAC,0x00,0x2F, ++ 0xC6,0x8C,0x38,0x00,0x80,0x0E,0xC0,0xA4,0x00,0x07,0xC0,0x9C,0x40,0x01,0xE8,0x66, ++ 0xD0,0x04,0x08,0x01,0xF0,0x8A,0x4A,0x01,0xEC,0x3E,0x10,0x0A,0xD0,0x06,0x30,0x42, ++ 0x40,0x8C,0xD1,0x40,0x91,0x15,0x00,0x94,0x00,0x97,0xD1,0x04,0x0A,0x01,0xF0,0x8A, ++ 0x49,0x01,0xD0,0x5E,0x40,0x01,0xD0,0x2E,0x10,0x0A,0xEC,0x06,0x31,0x42,0x40,0x8C, ++ 0xD1,0x40,0x00,0x84,0x15,0x01,0xF0,0x92,0xC6,0x84,0x38,0x00,0x80,0x06,0xC1,0x14, ++ 0xC4,0x0B,0xD0,0x40,0x90,0x05,0xD8,0x74,0x38,0xD8,0x86,0x36,0xDC,0x4C,0x10,0xC2, ++ 0xE8,0xB6,0xC0,0x4C,0xD1,0x40,0x00,0x84,0x00,0x97,0xD8,0x7C,0x38,0xD8,0x86,0x36, ++ 0xDC,0x54,0x10,0xC2,0xE8,0x66,0xC0,0x54,0xD1,0x40,0x00,0x84,0x00,0x47,0xD8,0x5C, ++ 0x10,0xC2,0xEC,0x2E,0xC0,0x5C,0xD0,0x40,0x00,0x84,0x01,0x0F,0x15,0x01,0xF0,0x92, ++ 0xC0,0x0C,0xC0,0x03,0xD0,0x00,0x94,0x05,0xC8,0xF4,0x48,0x01,0x88,0x06,0xC9,0xBC, ++ 0x10,0x42,0xDC,0xAE,0x40,0x03,0xC9,0xCC,0x18,0x09,0x18,0x42,0x00,0x03,0x69,0x01, ++ 0x83,0x26,0xF0,0x48,0x34,0xD2,0x00,0x52,0x19,0x82,0x00,0x03,0xC4,0x64,0x10,0x2A, ++ 0x93,0x0E,0xE1,0x40,0x31,0xD2,0x40,0x0B,0x00,0x12,0x1C,0x8A,0x00,0x0B,0x01,0xD7, ++ 0xCC,0xB4,0x10,0x42,0xE1,0xBE,0x40,0x03,0xC8,0xCC,0x18,0x42,0x00,0x03,0x01,0x97, ++ 0xC0,0xF4,0x40,0x09,0x89,0x16,0x40,0x84,0x00,0xC4,0x01,0x67,0x41,0xC4,0x41,0x8C, ++ 0xC4,0x00,0x92,0x05,0x00,0xC4,0xC9,0xD4,0xD0,0xF4,0xC0,0x4B,0x10,0x8A,0x8C,0x16, ++ 0x85,0x07,0xE8,0x87,0x00,0x84,0xC9,0x14,0x40,0x84,0x81,0x43,0xE0,0xF8,0xC5,0x0C, ++ 0xE0,0x00,0x82,0x0C,0xE0,0xB0,0xC5,0x14,0xE0,0x00,0x82,0x14,0xC4,0x04,0xE0,0x00, ++ 0x80,0x04,0xC0,0x94,0x40,0x00,0x82,0x94,0xC2,0x8C,0x40,0x00,0x80,0x8C,0xC0,0x84, ++ 0x40,0x01,0x80,0x46,0xC2,0x84,0x40,0x00,0x80,0x84,0xC0,0x7C,0x40,0x00,0x82,0x7C, ++ 0xC2,0x74,0x40,0x00,0x80,0x74,0xC0,0xC4,0xE2,0x00,0x92,0x05,0x80,0xC4,0xC8,0x6C, ++ 0xC4,0xC4,0x10,0x42,0xD2,0x06,0x38,0x77,0x87,0x0D,0xE9,0x85,0xA8,0x85,0x37,0x6A, ++ 0xF0,0x2C,0x30,0x22,0x30,0x8A,0x30,0xFA,0x37,0xC2,0xB9,0xF7,0xF1,0x5F,0x30,0xDA, ++ 0x31,0x92,0x31,0x4A,0x37,0x02,0xB9,0xFF,0xDF,0xB7,0xE9,0x85,0xAC,0xBD,0x87,0x45, ++ 0x33,0x6A,0xD8,0x43,0x87,0x24,0xD0,0x43,0x85,0x1C,0xE0,0x43,0x40,0x29,0x90,0x2E, ++ 0x06,0x01,0x18,0x02,0x18,0x43,0x03,0x01,0x18,0x43,0x05,0x6F,0x02,0x89,0xEE,0x02, ++ 0x38,0x00,0xAA,0x26,0x4D,0x52,0x5A,0x43,0x1B,0x42,0x18,0x43,0x02,0x27,0x48,0x42, ++ 0x5E,0x43,0x1D,0x4A,0x1B,0x42,0x18,0x43,0x39,0x01,0x30,0x42,0x80,0x01,0x85,0x3C, ++ 0xC0,0x01,0x83,0x34,0x00,0xD7,0x03,0x01,0x1B,0x43,0x5F,0x73,0x20,0x01,0x00,0x17, ++ 0x43,0xB0,0xE3,0x20,0x97,0x25,0x3F,0x80,0x88,0x16,0xC0,0x24,0x17,0x22,0x9C,0xBE, ++ 0xC4,0x24,0x10,0x22,0x87,0xDE,0xA3,0x63,0xC1,0x44,0x08,0xE9,0xCA,0x00,0x08,0x48, ++ 0xC1,0x00,0x4A,0xC2,0xEE,0x03,0x08,0x43,0x30,0x12,0x09,0x01,0x00,0x09,0xD8,0x54, ++ 0xBC,0xF7,0xF7,0x8F,0xD0,0x54,0x90,0x04,0x31,0x5A,0x31,0x0A,0x00,0x11,0xD0,0x44, ++ 0xBE,0xF7,0xF7,0xFF,0x42,0x82,0x41,0x0B,0x3F,0x48,0xAA,0xE6,0x40,0x0B,0x10,0x11, ++ 0x18,0x8A,0x00,0x0B,0x40,0x5A,0x09,0x41,0x00,0x0B,0x44,0x0B,0x10,0xF9,0x97,0x19, ++ 0x18,0x8A,0x00,0x0B,0x78,0x01,0x88,0x2E,0x30,0x4A,0xC1,0x44,0xB9,0xFF,0xDF,0x3F, ++ 0x00,0x01,0x80,0x14,0xC3,0x1C,0x18,0x02,0x00,0x08,0xC2,0x44,0xC6,0x40,0x08,0x09, ++ 0x02,0x48,0xC4,0x00,0x81,0x2C,0x00,0x47,0xC6,0x3C,0xE8,0x03,0x40,0x31,0x88,0x36, ++ 0x48,0xE2,0x40,0x43,0x10,0x81,0x18,0x82,0x00,0x43,0x38,0x31,0x07,0x07,0x39,0x80, ++ 0x80,0x9E,0x08,0x09,0x00,0x0A,0x05,0x07,0xFF,0x85,0x59,0x43,0x10,0x42,0x88,0x1E, ++ 0xC6,0x3C,0xE8,0x03,0x47,0x31,0x88,0xBE,0x50,0x15,0xA8,0x04,0x91,0x0C,0x30,0x12, ++ 0x30,0xCA,0xD9,0x44,0xC7,0x2C,0xB8,0xFF,0xE8,0x17,0xC7,0x1C,0xCA,0x2C,0x00,0x00, ++ 0xC0,0x00,0x82,0x2C,0x43,0xB0,0xE3,0x20,0x90,0x25,0xC7,0x24,0x16,0x22,0x9C,0x9E, ++ 0x78,0x01,0x88,0x0E,0xC3,0x14,0x18,0x43,0xE7,0xF8,0x93,0xFD,0xC0,0x34,0xC0,0x03, ++ 0xE5,0x00,0x12,0xC2,0xCB,0x5E,0x38,0xF7,0x58,0x80,0x04,0x01,0x20,0x20,0x07,0x00, ++ 0xAA,0xAA,0xAA,0xAA,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x39,0xFF,0x37,0x52, ++ 0x00,0x01,0xC8,0x54,0xBC,0xF7,0xEF,0x27,0x87,0x5D,0xE8,0x85,0xAC,0xBD,0x87,0x2D, ++ 0x33,0x62,0xD8,0x03,0x87,0x14,0xD0,0x0B,0x88,0x0C,0xC8,0x0C,0xC2,0x14,0x18,0x42, ++ 0xCA,0x2C,0x00,0x10,0xC6,0x90,0x0A,0x09,0x02,0x48,0xC4,0xA8,0xA8,0x24,0xC8,0x2C, ++ 0x8A,0xA1,0xC1,0x30,0xCF,0x2C,0x88,0xF9,0x8A,0x29,0xC1,0x38,0xB8,0x1C,0xC8,0x2C, ++ 0xC0,0x14,0xC0,0x40,0x0A,0xE9,0x09,0x48,0xC0,0x00,0xEA,0x03,0x4E,0xFA,0x0F,0x43, ++ 0xD0,0x3C,0x90,0x04,0x30,0x1A,0x09,0x01,0x00,0x09,0xD0,0x2C,0xBA,0xF7,0xF7,0x4F, ++ 0x30,0x12,0x01,0x11,0xCF,0x3C,0xB8,0xF7,0xE8,0x9F,0x0A,0x01,0x00,0x09,0xD8,0x3C, ++ 0xD7,0x14,0xB8,0xF7,0xE8,0x47,0xD7,0x3C,0x91,0x04,0x30,0x1A,0x00,0x11,0xD0,0x2C, ++ 0xCF,0x14,0xB8,0xF7,0xF0,0xB7,0xD1,0x3C,0x92,0x04,0x00,0x29,0xE9,0x0A,0x30,0x1A, ++ 0x11,0x01,0x30,0x42,0xBF,0xFF,0xF7,0x97,0x08,0x09,0x30,0x42,0xD8,0x3C,0xD0,0x14, ++ 0xBE,0xF7,0xEF,0x8F,0xD0,0x3C,0x90,0x04,0x30,0x1A,0x01,0x19,0xD0,0x2C,0xC8,0x14, ++ 0xB8,0xF7,0xF7,0xFF,0x30,0x12,0x01,0x01,0xCF,0x3C,0xB8,0xF7,0xE8,0x4F,0xD1,0x3C, ++ 0x90,0x04,0x08,0x01,0x30,0x1A,0x31,0x42,0xD7,0x2C,0xB8,0xF7,0xF5,0x97,0xE0,0x03, ++ 0x40,0x29,0xC0,0x96,0x00,0x01,0x08,0x01,0x05,0x67,0xD8,0x13,0x10,0x12,0xC4,0x06, ++ 0x01,0x4C,0x41,0x54,0x81,0x93,0x41,0x54,0x83,0xD3,0xE1,0xF8,0xE5,0xB0,0xE3,0x68, ++ 0xE6,0x00,0x92,0x05,0xD4,0x0C,0x10,0x82,0x98,0x7E,0xCF,0x1C,0xC0,0x24,0x10,0x01, ++ 0x00,0x57,0x40,0x1C,0xC2,0x6B,0xC8,0xD8,0x92,0xDD,0x80,0xD8,0x00,0x1C,0x80,0x5B, ++ 0xE4,0x48,0xE2,0x00,0xE6,0x90,0x92,0x95,0xDC,0x1B,0x15,0x9A,0xC0,0x8E,0x87,0x45, ++ 0xEB,0x85,0xAF,0x85,0x35,0x42,0x80,0xC1,0x34,0x6A,0xA8,0x01,0x5F,0x53,0x51,0x73, ++ 0x53,0x5B,0x55,0x63,0xE0,0x6B,0x69,0x01,0x81,0xD6,0x32,0x2A,0x19,0xEA,0x18,0xAA, ++ 0x18,0xAA,0x80,0x0E,0x28,0x19,0x80,0x2B,0xC0,0x2B,0x68,0x01,0x83,0x0E,0xF0,0x68, ++ 0x81,0x2B,0x30,0x2A,0x10,0xAA,0x80,0x26,0x30,0xEA,0x10,0xAA,0x88,0x0E,0x10,0x09, ++ 0x01,0x97,0x30,0x2A,0x10,0xAA,0x81,0x26,0x30,0xEA,0x10,0xAA,0x88,0x0E,0x10,0x11, ++ 0x00,0x57,0x60,0x01,0x80,0x1E,0x10,0x9A,0x88,0x0E,0x10,0x79,0x01,0x27,0x10,0x9A, ++ 0x80,0x0E,0x10,0x21,0x00,0x07,0x10,0x01,0xC8,0x1B,0x24,0x01,0x10,0x9A,0x8C,0x0E, ++ 0x50,0x01,0x88,0x0E,0x01,0x24,0x04,0x57,0x40,0x1C,0x2C,0xC9,0x0D,0x68,0x13,0x5A, ++ 0x92,0x0E,0xE0,0xD8,0x00,0x1C,0x34,0x5A,0x2D,0x09,0x98,0x01,0x50,0x11,0x80,0x26, ++ 0xE0,0x8E,0x50,0x01,0x80,0xDE,0x50,0x09,0x8C,0xCE,0x40,0x34,0x70,0xE1,0xC9,0xB6, ++ 0xF0,0xDB,0x5A,0x51,0x90,0x9E,0x30,0x5A,0x98,0x01,0xE6,0xF3,0x18,0x72,0xA1,0xF3, ++ 0xA4,0x6B,0x04,0x24,0x00,0x5F,0x50,0x21,0x80,0x4E,0x50,0x79,0x8C,0x3E,0x40,0x34, ++ 0x70,0xE1,0xC9,0x26,0xF0,0xDB,0x5A,0x51,0x94,0x0E,0xA0,0x6B,0x04,0x24,0x8C,0x13, ++ 0xEF,0x85,0xAB,0x9D,0x80,0x4D,0x34,0x32,0xC4,0x54,0xD0,0x03,0x80,0x3C,0xC0,0x54, ++ 0xD0,0x03,0x86,0x34,0xC0,0x54,0xE8,0x03,0x43,0xF1,0x98,0x8E,0xC5,0x54,0x80,0x01, ++ 0xF0,0x03,0x40,0x01,0x88,0x66,0xC3,0x54,0xCA,0x03,0x34,0x00,0x70,0x00,0x80,0x2C, ++ 0x04,0x09,0x06,0x00,0xC1,0xB8,0x31,0xA2,0xA1,0xA1,0x01,0x81,0xF7,0x82,0x41,0x81, ++ 0xDF,0x26,0xC0,0x81,0x30,0x84,0x01,0x09,0x80,0x24,0x00,0x0F,0x00,0x01,0x80,0x24, ++ 0x01,0x91,0xF1,0x82,0x0E,0x79,0x1F,0x4A,0x10,0x42,0xE4,0x26,0x83,0x81,0x37,0x84, ++ 0x00,0x09,0x80,0x1C,0x00,0x0F,0x00,0x01,0x83,0x1C,0x40,0xEA,0x82,0x14,0x10,0x02, ++ 0x80,0x0C,0x00,0x01,0x81,0x44,0x00,0xBF,0x29,0x01,0x00,0x77,0x01,0x01,0xF0,0xC2, ++ 0xCC,0x2C,0x10,0x42,0xD0,0xCE,0x40,0x01,0xE8,0x56,0xC8,0x14,0x10,0x42,0xEC,0x06, ++ 0x80,0x14,0xC0,0x24,0x40,0x01,0x80,0xE6,0xC2,0x03,0xF1,0x00,0x80,0x03,0x01,0xC7, ++ 0x40,0x01,0xD0,0xB6,0xCC,0x0C,0x10,0x42,0xD0,0x06,0x80,0x0C,0xC0,0x1C,0x40,0x01, ++ 0x81,0x7E,0xC0,0x03,0xE1,0x00,0x82,0x03,0x00,0x5F,0xC0,0x54,0x08,0x21,0xEB,0x03, ++ 0x83,0x07,0xD8,0x47,0x48,0x19,0x8B,0x26,0xC9,0x2C,0xC0,0x03,0x42,0x48,0xD2,0x00, ++ 0x85,0x03,0xE1,0xF8,0xE3,0x20,0xE3,0x68,0x90,0x6D,0xC7,0x34,0x16,0x2A,0x9C,0x6E, ++ 0xC2,0x44,0xE0,0x00,0x90,0x05,0x86,0x44,0xC8,0x3C,0xC0,0x44,0x16,0x42,0x9C,0x1E, ++ 0x70,0x8C,0xC1,0x14,0xC1,0x40,0x30,0x84,0x70,0x8C,0xC3,0x0C,0xC3,0x40,0x30,0x84, ++ 0x37,0x57,0xAC,0xBD,0x80,0x15,0x34,0x62,0x37,0xBA,0xE0,0x2B,0xDF,0x33,0xD3,0x03, ++ 0x1A,0x42,0x03,0x08,0xC0,0x14,0xC0,0x40,0x0C,0x09,0x06,0x48,0xC0,0x00,0x82,0x0C, ++ 0x36,0x02,0x81,0x01,0xE4,0x0B,0x10,0x01,0x18,0x8A,0xA0,0x0B,0x00,0xB1,0xED,0x02, ++ 0x42,0x01,0x80,0x46,0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42,0xBC,0xF7,0xE7,0x5F, ++ 0x30,0x1A,0xB9,0x04,0x08,0x01,0x00,0x19,0xD7,0x14,0xB8,0xF7,0xE2,0xD7,0x06,0x29, ++ 0xE9,0x0A,0x30,0x1A,0x30,0xD2,0xC1,0x0C,0xBE,0xFF,0xC7,0xEF,0x58,0x03,0x17,0x09, ++ 0x35,0x8A,0x00,0x4A,0x1F,0x42,0x18,0x03,0xE7,0x68,0x93,0x6D,0x58,0x0B,0x03,0x0F, ++ 0xE7,0x68,0x93,0x6D,0x35,0x82,0x00,0x42,0x10,0x0A,0x88,0x0E,0x17,0xAA,0x9D,0xBE, ++ 0x11,0xAA,0x85,0x06,0xA1,0x2B,0x37,0xDA,0x30,0x52,0x09,0x01,0x07,0x09,0xB8,0xF7, ++ 0xE1,0x17,0x33,0x1A,0xB9,0x04,0x30,0x4A,0x00,0x11,0xD0,0x14,0xBD,0xF7,0xE7,0x8F, ++ 0xC1,0x14,0x08,0xE9,0xCA,0x00,0x0A,0x48,0xC1,0x00,0x52,0x62,0xEE,0x03,0x08,0x83, ++ 0x42,0x62,0x41,0x0B,0x3F,0x48,0xAA,0xE6,0x04,0x41,0x00,0x83,0x47,0x83,0x08,0xF9, ++ 0x88,0x19,0x18,0x42,0x00,0x83,0x80,0x2D,0xEF,0x85,0xAF,0x85,0x84,0xBD,0x34,0x22, ++ 0x37,0x6A,0xD0,0x7B,0xD0,0x43,0x85,0x6C,0x31,0x1A,0x9B,0xA1,0x9C,0xB4,0x08,0x29, ++ 0x34,0x02,0x03,0x48,0xC6,0x20,0x0A,0x09,0x03,0x48,0x24,0x0A,0x8B,0xAC,0xC8,0x43, ++ 0x02,0x00,0x92,0x05,0x80,0x2C,0x00,0x01,0x80,0x24,0x00,0x09,0x81,0x14,0x30,0x42, ++ 0x80,0x01,0x86,0xA4,0xE3,0x03,0x5A,0x73,0x32,0x32,0x3C,0x10,0x58,0x43,0x1D,0x32, ++ 0x50,0x01,0xD0,0x46,0x40,0xA2,0x18,0x32,0xB3,0x1C,0x30,0x82,0x10,0xD9,0x07,0x82, ++ 0xD2,0xA4,0xA0,0x83,0x00,0x47,0x40,0x82,0x18,0x02,0x1E,0x32,0xB3,0x1C,0x30,0x82, ++ 0x10,0x21,0x18,0x82,0xD2,0xA4,0xA0,0x83,0x35,0x01,0x18,0x73,0xD8,0x43,0x45,0x01, ++ 0x80,0x36,0xD0,0x6C,0xC2,0x14,0xF0,0x90,0x00,0x82,0xD4,0x1C,0x18,0x82,0x80,0x1C, ++ 0x34,0x52,0x91,0x01,0x92,0x9C,0xF0,0x83,0x80,0x8C,0x00,0x3F,0x00,0x01,0x00,0x42, ++ 0xC7,0x87,0xF9,0xFF,0x18,0x00,0x04,0x42,0xAA,0xAA,0xAA,0xAA,0xC0,0x9C,0x10,0xC1, ++ 0xB0,0x12,0x94,0x84,0xD0,0x9C,0x00,0x01,0x18,0x83,0x80,0x7C,0xD6,0x9C,0x10,0x83, ++ 0x80,0x74,0x10,0x01,0x97,0x64,0x50,0xFA,0x90,0x5C,0x10,0x01,0x91,0x54,0x30,0x72, ++ 0xB5,0x01,0x99,0x83,0xCA,0x43,0x45,0x00,0x85,0x4C,0x10,0xA1,0xFA,0x82,0x82,0x00, ++ 0x85,0x44,0xE0,0x43,0x40,0x29,0xC0,0xCE,0x03,0x01,0x30,0x12,0x32,0x84,0x30,0x84, ++ 0x30,0x22,0x04,0x87,0x10,0x01,0x00,0x47,0x41,0x44,0x80,0x03,0x40,0x44,0x80,0xC3, ++ 0xE4,0xD8,0xE2,0x48,0xE2,0x20,0xE3,0x90,0x95,0x95,0x12,0xD2,0xDB,0xA6,0x37,0x02, ++ 0xE2,0x00,0x92,0x05,0x30,0x22,0xC4,0x6C,0x2F,0x22,0xDC,0x5E,0xC0,0xB4,0x80,0x3C, ++ 0xE0,0xAC,0x00,0x01,0x85,0x94,0x00,0xBF,0x00,0x01,0x80,0x34,0x30,0x32,0xCC,0x94, ++ 0xC4,0x14,0x00,0x42,0xC8,0x1C,0x10,0x42,0x80,0x86,0x03,0x01,0x32,0x22,0x04,0xEF, ++ 0xC1,0x3C,0x40,0x0C,0xC2,0x03,0xD0,0x00,0x91,0x05,0x00,0x04,0xCA,0x9C,0xE0,0x4B, ++ 0x48,0x11,0x98,0xA6,0xCC,0x84,0x10,0x42,0xD5,0x8E,0xD8,0x8B,0xE5,0x48,0x9A,0x8B, ++ 0xC8,0x64,0xC0,0x48,0x88,0x64,0xD8,0x5C,0x34,0x12,0x10,0x1A,0xD8,0x06,0xD0,0x5C, ++ 0x90,0x5C,0xD8,0x54,0x34,0x12,0x10,0x1A,0xE0,0x06,0xD0,0x54,0x90,0x54,0xC8,0x2C, ++ 0x10,0x42,0xD4,0x3E,0x32,0x8A,0xE3,0x48,0x94,0x4D,0x36,0x72,0xC8,0x34,0xC0,0x48, ++ 0x90,0x4D,0x88,0x34,0xCC,0x4C,0x10,0x42,0xEB,0xBE,0xC8,0x4B,0x10,0x0A,0xE4,0x2E, ++ 0xDD,0x94,0x58,0x53,0x0C,0x09,0x00,0xCA,0x1D,0x52,0x18,0x53,0xE0,0x8B,0x4B,0x09, ++ 0x8C,0x0E,0x08,0x09,0xA0,0x8B,0xCB,0x8C,0x10,0x42,0xEC,0xBE,0x30,0x02,0x0B,0x09, ++ 0x00,0x0A,0xC4,0x7C,0x18,0x0A,0x88,0x7C,0x00,0x87,0xC8,0x44,0x10,0x42,0xD4,0x6E, ++ 0xE0,0x8B,0x4B,0x09,0x8C,0x0E,0x08,0x09,0xA0,0x8B,0xCB,0x84,0x10,0x42,0xD4,0x2E, ++ 0x30,0x02,0x0B,0x09,0x00,0x0A,0xC4,0x74,0x18,0x0A,0x88,0x74,0xE0,0x20,0xC5,0x3C, ++ 0xE0,0x00,0x82,0x3C,0x32,0x02,0xE3,0x00,0x94,0x05,0x32,0x22,0x2C,0xE2,0xDD,0xFE, ++ 0x30,0x82,0x43,0x11,0xCB,0x2E,0x30,0x8A,0xC0,0x34,0x80,0x07,0xC8,0x6F,0x97,0x05, ++ 0x00,0x07,0x00,0x01,0x03,0xC8,0xD3,0x20,0x11,0x01,0x00,0x57,0x00,0x67,0x41,0x01, ++ 0xE8,0x7E,0x08,0x01,0xF0,0x0A,0xDB,0x2C,0x10,0xCA,0xD4,0xB6,0xE4,0x18,0x12,0xCA, ++ 0xE8,0x16,0xD0,0x48,0x00,0x0C,0x01,0x87,0x48,0x01,0xE8,0x76,0x09,0x09,0x00,0x0C, ++ 0x00,0x5F,0x08,0x01,0xF4,0x0A,0x13,0x0A,0xD0,0x16,0xD0,0x48,0x00,0x0C,0x01,0x27, ++ 0x48,0x01,0xD0,0x16,0x0E,0x01,0x18,0x4A,0x00,0x0C,0x09,0x01,0xF0,0x0A,0xDB,0x44, ++ 0x10,0xCA,0xD4,0x1E,0xCA,0x24,0xE0,0x48,0x90,0x4D,0x8E,0x24,0xE2,0x20,0xE5,0x90, ++ 0x95,0x95,0x12,0xD2,0xD8,0x9E,0x06,0x5F,0x00,0x01,0x08,0x01,0x01,0x37,0x00,0x0C, ++ 0xE0,0x20,0xD5,0x3C,0xE0,0x90,0x92,0x3C,0xE2,0x00,0x92,0x05,0x17,0xC2,0xDD,0xB6, ++ 0xC2,0x94,0xE0,0x00,0x90,0x05,0x82,0x94,0xC8,0x6C,0xC0,0x94,0x10,0x42,0xD4,0x06, ++ 0x39,0x17,0xCA,0x43,0x40,0x71,0xC9,0x0E,0x01,0x71,0x89,0x43,0xC9,0x24,0xC8,0x43, ++ 0x42,0x48,0xC4,0x00,0x91,0x05,0x8E,0x43,0x40,0x81,0xCA,0x0E,0x01,0x81,0x8A,0x43, ++ 0xC2,0x9C,0xE0,0x03,0x42,0x11,0x98,0x56,0xD8,0x83,0x45,0x11,0xCC,0x3E,0xF2,0x00, ++ 0x90,0x05,0x86,0x04,0xC8,0x54,0xC0,0x5C,0xC0,0x08,0xC2,0x64,0xD0,0x00,0xCA,0x04, ++ 0x84,0x07,0xC8,0x17,0x90,0x05,0x80,0x0C,0x05,0x01,0x28,0x44,0x08,0xE9,0x0B,0x48, ++ 0x10,0x01,0xE0,0xAC,0x31,0x22,0x04,0x0F,0x18,0x01,0x00,0xCF,0x01,0x01,0xF0,0x02, ++ 0xF5,0x84,0x10,0x82,0xD0,0x8E,0xF0,0x0C,0xD8,0x00,0xAC,0x06,0x10,0x02,0x92,0x05, ++ 0x34,0x32,0x10,0x0A,0xE0,0x06,0x30,0x72,0x30,0x8A,0x31,0x32,0x10,0x12,0xDC,0x06, ++ 0x31,0xB2,0x30,0x92,0x69,0x74,0xC5,0x80,0x2D,0x44,0xE5,0x20,0xE2,0xD8,0x92,0xDD, ++ 0x17,0xDA,0xDD,0x1E,0x32,0x02,0xE3,0x00,0x94,0x05,0x32,0x22,0xDC,0x6C,0x28,0xE2, ++ 0xDD,0xD6,0x6E,0x44,0xC2,0x48,0xD4,0x00,0x90,0x05,0xCC,0x04,0x82,0x07,0xC8,0x17, ++ 0x28,0x44,0xC5,0x0C,0x40,0x01,0xD0,0x06,0x13,0x02,0x2A,0x44,0x00,0x17,0x00,0x01, ++ 0x2D,0x44,0x2B,0x44,0xC8,0x9C,0xC0,0x7C,0x18,0x43,0xC8,0x9C,0xC6,0x74,0x10,0x43, ++ 0x87,0xBD,0xE8,0x85,0xAC,0xBD,0x87,0x15,0x32,0x62,0x70,0x9A,0x29,0x01,0x80,0xAB, ++ 0x09,0x11,0x30,0x02,0x80,0x01,0x35,0x3A,0xA9,0x0B,0x34,0x0A,0xD0,0x24,0xC0,0x14, ++ 0xBD,0xFF,0xDF,0x67,0xAD,0xEB,0xDD,0x03,0x40,0x01,0x80,0x76,0x6F,0x5A,0x42,0x43, ++ 0x91,0x3D,0x4C,0x04,0x00,0x43,0x07,0x09,0x81,0x83,0x31,0x0A,0xD0,0x24,0xC0,0x14, ++ 0xBA,0xFF,0xE7,0xA7,0x01,0x01,0x80,0x83,0x00,0x7B,0xD7,0x24,0x90,0x04,0x08,0x01, ++ 0x30,0x1A,0x31,0x42,0xD7,0x14,0xB8,0xF7,0xD5,0xE7,0xE5,0x03,0x40,0x41,0x96,0x0E, ++ 0xE5,0x00,0xA2,0x03,0x30,0xBF,0x10,0x01,0x00,0x37,0x08,0x01,0xE4,0x48,0x92,0x4D, ++ 0x4F,0xA1,0xC8,0xDE,0xE4,0x90,0x92,0x95,0x17,0x12,0xCC,0xB6,0x38,0x82,0x3B,0x18, ++ 0x78,0xD8,0x10,0x09,0x06,0xD2,0x94,0x95,0x18,0xF9,0x0F,0xD8,0x01,0xC2,0x58,0xA2, ++ 0xC0,0x00,0x4E,0x09,0x88,0x66,0x40,0x0B,0x18,0x8A,0x04,0x0B,0x44,0x0B,0x1A,0x8A, ++ 0x04,0x0B,0x42,0x0B,0x1C,0x8A,0x04,0x0B,0x44,0x0B,0x1E,0x8A,0x03,0x0B,0x3E,0x82, ++ 0x48,0x01,0x88,0x66,0x44,0x0B,0x1A,0x8A,0x04,0x0B,0x42,0x0B,0x1C,0x8A,0x04,0x0B, ++ 0x44,0x0B,0x1E,0x8A,0x00,0x0B,0x46,0x0B,0x18,0x8A,0x00,0x0B,0x38,0x82,0x4B,0x11, ++ 0x88,0x66,0x40,0x0B,0x18,0x8A,0x04,0x0B,0x44,0x0B,0x1A,0x8A,0x04,0x0B,0x42,0x0B, ++ 0x1C,0x8A,0x04,0x0B,0x40,0x0B,0x1E,0x8A,0x03,0x0B,0x3E,0x82,0x4F,0x19,0x88,0xE6, ++ 0x44,0x0B,0x18,0x8A,0x04,0x0B,0x40,0x0B,0x1C,0x8A,0x04,0x0B,0x44,0x0B,0x1E,0x8A, ++ 0x02,0x0B,0x46,0x0B,0x1A,0x8A,0x00,0x0B,0x3F,0x82,0xAB,0x8D,0x80,0x3D,0xC4,0x3C, ++ 0xC8,0x3C,0x48,0x00,0x02,0x00,0xC4,0x00,0x38,0x00,0x48,0x92,0x72,0x00,0xC2,0x28, ++ 0x40,0x72,0x40,0x0B,0x90,0x4D,0x8C,0x34,0x5C,0x0B,0x90,0x4D,0x8A,0x2C,0x58,0x0B, ++ 0x90,0x4D,0x8C,0x24,0x5C,0x0B,0x94,0x4D,0x8E,0x1C,0x50,0x0B,0x90,0x75,0x4C,0x52, ++ 0x44,0x53,0x92,0x95,0x90,0x14,0x40,0x53,0x92,0xBD,0x44,0x13,0x90,0x95,0x94,0x0C, ++ 0x58,0x12,0x00,0x5F,0xE7,0xC7,0xF8,0xFF,0x00,0xB0,0x00,0x01,0x00,0x01,0x00,0x42, ++ 0x80,0x00,0x00,0x42,0x08,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x98,0x01,0x52,0xD3, ++ 0x90,0x95,0x94,0x04,0x10,0x09,0x00,0x13,0xA8,0x10,0x1C,0x13,0x12,0x81,0x18,0x13, ++ 0x18,0x13,0x14,0x79,0x11,0x13,0x16,0x01,0x00,0x53,0x12,0x89,0x02,0x53,0x40,0x0B, ++ 0x10,0x81,0x19,0x8A,0x07,0x0B,0x02,0xF9,0x80,0x89,0x17,0xC3,0x07,0x09,0xB8,0xFF, ++ 0xFF,0x17,0x03,0xF9,0x80,0x89,0x14,0xC3,0x07,0x09,0xB8,0xFF,0xF8,0xE7,0x02,0x19, ++ 0x11,0x00,0x00,0x43,0x07,0x09,0xB8,0xFF,0xF8,0xB7,0x0A,0x11,0xC7,0x3C,0xB8,0xFF, ++ 0xF8,0xF7,0x22,0xA1,0x01,0x01,0x40,0x4B,0x30,0x48,0xA8,0x16,0xE7,0x20,0x93,0x25, ++ 0x03,0x0F,0xF0,0x20,0x92,0x25,0xE7,0x00,0x90,0x05,0x46,0x51,0x98,0x9E,0x0F,0x09, ++ 0xC7,0x3C,0xB8,0xFF,0xF8,0x67,0x42,0x6A,0xC8,0x34,0x00,0x0B,0xC8,0x2C,0x18,0x0B, ++ 0xCA,0x24,0x18,0x0B,0xCC,0x1C,0x18,0x0B,0x10,0x33,0x4E,0x4A,0xD2,0x14,0x00,0x53, ++ 0x00,0x7B,0xC8,0x0C,0x00,0x0B,0x4A,0x2A,0xC2,0x04,0x88,0x01,0x10,0x43,0x60,0xA1, ++ 0xC8,0x16,0x00,0x09,0x87,0x45,0xE8,0x85,0x07,0x01,0x38,0xDF,0x00,0x01,0x00,0x42, ++ 0x18,0x00,0x04,0x42,0x00,0x0F,0x00,0x26,0xF8,0x48,0x48,0x21,0x94,0xDE,0x3F,0x58, ++ 0xA8,0x0E,0x00,0x14,0xE6,0x00,0x3C,0x48,0x80,0x06,0x80,0x13,0x38,0x82,0x4B,0x01, ++ 0x86,0x5E,0x38,0x18,0x80,0x16,0x80,0x13,0xE2,0x00,0xF2,0x48,0x48,0x11,0x98,0x26, ++ 0x38,0x18,0xAC,0x16,0x04,0x14,0xE0,0x00,0xF7,0x48,0x3C,0x1F,0x17,0x01,0x38,0x77, ++ 0x16,0x01,0x38,0xFF,0x10,0x01,0x48,0x18,0x11,0x5A,0x9C,0x66,0x54,0x18,0x10,0x5A, ++ 0x98,0x8E,0x18,0x01,0x32,0xE2,0x04,0x77,0x30,0x1A,0x18,0x5A,0xA0,0xE6,0x11,0x01, ++ 0x44,0x18,0x12,0x5A,0x98,0x8E,0x49,0x18,0x10,0x5A,0x9C,0xE6,0x54,0x18,0x10,0x5A, ++ 0x9C,0x0E,0x30,0xA2,0x06,0xFF,0x49,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD6,0x00, ++ 0x0C,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD4,0x00,0x0A,0x92,0x4A,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD2,0x00,0x08,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x0E,0x58,0xD0,0x00,0x0E,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD6,0x00, ++ 0x0C,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD4,0x00,0x0A,0x92,0x42,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A, ++ 0x08,0x92,0x32,0x82,0x3A,0x82,0x03,0xEF,0x78,0x50,0x86,0x06,0x10,0x4A,0x82,0x18, ++ 0x9A,0x06,0x10,0x02,0x00,0x9A,0x12,0x01,0x30,0xE2,0x4C,0x18,0x11,0x5A,0x9C,0x6E, ++ 0x54,0x18,0x10,0x5A,0x9F,0x96,0x10,0xE1,0x08,0x48,0xD4,0x95,0x54,0x18,0x10,0x5A, ++ 0x9C,0x66,0x08,0x48,0x8C,0x90,0x14,0x5A,0x9C,0x46,0x08,0x48,0x8C,0x90,0x14,0x5A, ++ 0x9C,0x26,0x08,0x48,0x84,0xD6,0x89,0x90,0x04,0x07,0x48,0x48,0x4C,0x18,0x16,0x5A, ++ 0x9E,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x14,0x5A,0x9C,0x0E,0x08,0x58, ++ 0xD2,0x00,0x0E,0x92,0x4C,0x18,0x12,0x5A,0x9A,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92, ++ 0x4C,0x18,0x10,0x5A,0x98,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x44,0x18,0x16,0x5A, ++ 0x9E,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92,0x44,0x18,0x14,0x5A,0x9C,0x0E,0x00,0x58, ++ 0xD2,0x00,0x0E,0x92,0x92,0xCE,0x46,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00, ++ 0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A,0x32,0x1A,0x0B,0x92,0x80,0xD8,0x32,0x82, ++ 0x9A,0x0E,0x10,0x02,0x58,0x01,0xA8,0x06,0x13,0x4A,0x3A,0x82,0x32,0x1A,0x83,0xD8, ++ 0x9A,0x06,0x10,0x02,0xA8,0x0D,0x00,0x01,0x36,0x02,0x36,0x02,0xEB,0x15,0x30,0xAA, ++ 0x81,0x07,0xC0,0x17,0x30,0x72,0x05,0x28,0x32,0x4A,0x33,0x9A,0x46,0x00,0x06,0x00, ++ 0x30,0x2A,0x84,0xC5,0xAF,0x05,0xB9,0xDF,0xEB,0xBF,0xE6,0x05,0x3A,0x01,0x40,0x48, ++ 0x30,0xB2,0x35,0x01,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06, ++ 0x2E,0x06,0x2E,0x06,0xEA,0x01,0x02,0x48,0x33,0x6A,0x3C,0x82,0x36,0x22,0x30,0x02, ++ 0x31,0x02,0x36,0x02,0xB8,0xD7,0xDF,0xFF,0x43,0x02,0x38,0x82,0x58,0x60,0x05,0x01, ++ 0x40,0x12,0x48,0x1A,0xF3,0x5D,0x3D,0x82,0x00,0x68,0x00,0x00,0x00,0xC0,0x00,0x00, ++ 0x00,0x30,0x01,0x10,0x39,0x82,0xA3,0x85,0x33,0xA2,0xF3,0x20,0xC3,0x2B,0xE1,0x20, ++ 0x10,0x5A,0x95,0x06,0x33,0xEA,0xE8,0x1A,0x07,0xD8,0xC2,0x18,0xE0,0x85,0x39,0xC2, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x20,0x01,0x42, ++ 0x80,0x20,0x01,0x42,0x80,0x20,0x01,0x42,0x80,0x20,0x01,0x42,0x80,0x20,0x03,0x42, ++ 0x80,0xA0,0x00,0x42,0x80,0x20,0x03,0x42,0x80,0xA0,0x00,0x42,0x80,0x20,0x03,0x42, ++ 0x80,0xA0,0x00,0x42,0x80,0x20,0x03,0x42,0x80,0xA0,0x00,0x42,0x80,0xA0,0x03,0x42, ++ 0x80,0x20,0x00,0x42,0x80,0xA0,0x03,0x42,0x80,0xA0,0x03,0x42,0x80,0x20,0x04,0x42, ++ 0x80,0x20,0x04,0x42,0x80,0x20,0x04,0x42,0x80,0xA0,0x04,0x42,0x10,0x20,0x08,0x40, ++ 0x40,0x08,0x20,0x10,0x10,0x20,0x08,0x40,0x20,0x08,0x40,0x20,0x20,0x10,0x08,0x40, ++ 0x08,0x81,0x03,0x42,0x08,0xC1,0x03,0x42,0x08,0x41,0x00,0x42,0x08,0x81,0x00,0x42, ++ 0x08,0xC1,0x00,0x42,0x08,0x01,0x01,0x42,0x08,0x81,0x02,0x42,0x08,0x41,0x02,0x42, ++ 0x08,0xC1,0x02,0x42,0x08,0x01,0x02,0x42,0x08,0x01,0x02,0x42,0x08,0xC1,0x01,0x42, ++ 0x08,0x41,0x02,0x42,0x08,0x81,0x01,0x42,0x08,0x81,0x02,0x42,0x08,0x41,0x01,0x42, ++ 0x08,0xC1,0x02,0x42,0x08,0x01,0x01,0x42,0x08,0x01,0x03,0x42,0x08,0x81,0x00,0x42, ++ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00, ++ 0x00,0x08,0xF8,0x0F,0xFF,0x07,0xF8,0xFF,0x07,0xF8,0x0F,0xF8,0x08,0x00,0x08,0x08, ++ 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x28,0xB5,0x39,0xC5,0x08,0x1D, ++ 0x1B,0x2B,0x3A,0x28,0x53,0xB5,0x0A,0xC5,0x00,0x08,0x01,0x00,0x01,0x00,0x50,0x0D, ++ 0x52,0x1D,0x52,0xB5,0x39,0x0D,0x04,0x08,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95, ++ 0x51,0x3D,0x54,0x95,0x51,0x3D,0x54,0x95,0x0B,0x3D,0x34,0x88,0x51,0x3D,0x54,0x1D, ++ 0x51,0x3D,0x54,0x95,0x04,0x00,0x50,0x3D,0x50,0x1D,0x01,0x00,0x00,0x00,0x00,0x00, ++ 0x54,0x2D,0x53,0x3D,0x32,0x8D,0x32,0x38,0x01,0x28,0x0A,0x45,0x50,0xB5,0x53,0x95, ++ 0x00,0x00,0x00,0x00,0x52,0xA5,0x51,0xB5,0x09,0xC5,0x03,0x08,0x03,0x00,0x50,0x3D, ++ 0x55,0x1D,0x51,0x0D,0x51,0x3D,0x54,0x95,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95, ++ 0x51,0x0D,0x55,0x0D,0x54,0xB5,0x3A,0x0D,0x00,0x08,0x01,0x00,0x53,0xA5,0x51,0x2D, ++ 0x52,0x3D,0x34,0x8A,0x1D,0x38,0x52,0x45,0x52,0x0D,0x51,0x1D,0x54,0xB5,0x3A,0x0D, ++ 0x53,0xA5,0x29,0xB5,0x39,0xC5,0x08,0x1D,0x19,0x2D,0x22,0x1D,0x44,0x0D,0x31,0x3D, ++ 0x23,0x95,0x09,0xC1,0x29,0xB5,0x0B,0x1D,0x1B,0x2B,0x3A,0x28,0x00,0x00,0x00,0x08, ++ 0xFF,0x07,0x00,0xF8,0x08,0x00,0x10,0x10,0x08,0x10,0x10,0x10,0x08,0x08,0x10,0x08, ++ 0x10,0x08,0x10,0x08,0x10,0x10,0x08,0x08,0x10,0x10,0x08,0x08,0x08,0x08,0x10,0x10, ++ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xF8,0x07, ++ 0x08,0x00,0x08,0x08,0xE8,0xA2,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0xC0,0x00,0x00, ++ 0x00,0x00,0x05,0x00,0xE8,0x62,0x02,0x00,0x00,0xC0,0x00,0x01,0x58,0xA0,0x07,0x00, ++ 0x00,0xE0,0x05,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,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0x00,0x70,0x00,0x30,0x09,0x40,0x1B,0x00,0x06,0x78,0x50,0x56, ++ 0xFF,0xFF,0xFF,0xFF,0x3C,0x50,0x00,0x10,0x00,0x20,0x18,0x00,0x1E,0xAC,0xE4,0x09, ++ 0x0F,0x00,0xCA,0xCA,0xFF,0xFF,0xFF,0xFF,0x0A,0x07,0x82,0x00,0x04,0x00,0x00,0x03, ++ 0x95,0x83,0xC1,0x3C,0xC8,0xB2,0xB5,0x47 ++}; ++ ++ ++ ++#define FW_INFO_SIZE (0x18) ++#define FW_REAL_SIZE (sizeof(fwbin)) ++#define FW_BIN_SIZE (24*1024+24) //24K byte ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_0729_update3_firmware.c b/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_0729_update3_firmware.c +new file mode 100644 +index 000000000..7d1b08664 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_0729_update3_firmware.c +@@ -0,0 +1,1626 @@ ++/* ++ * cst3xx Touchscreen Controller Driver ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "hyn_cst3xx.h" ++#include "hyn_cst3xx_RS659_fw.h" ++//#include "hyn_cst3xx_RS659_fw_0729_update2.h" ++//#include "hyn_cst3xx_RS659_fw_0729_update3.h" ++#include ++ ++ ++#define HYN_DEBUG_EN 1 ++ ++struct st1615_ts_finger { ++ u16 x; ++ u16 y; ++ u8 t; ++ bool is_valid; ++}; ++ ++ ++static int cst3xx_into_program_mode(struct i2c_client * client); ++static int cst3xx_erase_program_area(struct i2c_client * client); ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms); ++static int cst3xx_write_program_data(struct i2c_client * client,const unsigned char *pdata); ++ ++static int cst3xx_check_checksum(struct i2c_client * client); ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client); ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata); ++ ++static int cst3xx_firmware_info(struct i2c_client * client); ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict); ++ ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata); ++ ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_test(struct i2c_client *client); ++static void cst3xx_reset(struct cst3xx_ts_data *ts) ; ++extern void close_vcc3v3Power(void); ++extern void open_vcc3v3Power(void); ++ ++static unsigned char *pcst3xx_update_firmware = (unsigned char *)cst3_fw ; //the updating firmware ++static unsigned int g_cst3xx_ic_version = 0; ++static unsigned int g_cst3xx_ic_checksum = 0; ++static unsigned int g_cst3xx_ic_checkcode =0; ++static unsigned int g_cst3xx_ic_project_id = 0; ++static unsigned int g_cst3xx_ic_type = 0; ++ ++static unsigned char report_flag = 0; ++static unsigned int x_temp_pos = 0; ++static unsigned int y_temp_pos = 0; ++ ++#define HYN_DRAW_POINT ++ ++//#define USE_ANALOG_I2C 1 //i2c analog -->defconfig i2c. ++#define USE_HIGHEST_I2CA 1// x1000 highest i2c ++//#define USE_LOWEST_I2CA 1 // x1000 lowest i2c ++//#define HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++#define HYN_UPDATE_FIRMWARE_ENABLE ++ ++#pragma pack(1) ++typedef struct ++{ ++ u16 pid; //product id // ++ u16 vid; //version id // ++} st_tpd_info; ++#pragma pack() ++ ++st_tpd_info tpd_info; ++ ++#define CST3XX_BIN_SIZE (24*1024 + 24) ++//#define CST3XX_MAX_X 340 ++#define CST3XX_MAX_X 480 ++#define CST3XX_MAX_Y 800 ++#define ERROR_TOUCH 1 ++ ++static void cst3xx_ts_power(struct cst3xx_ts_data *ts, bool poweron) ++{ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) ++ gpio_direction_output(ts->pdata->reset_gpio, poweron); ++} ++ ++static int cst3xx_into_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x01; ++ buf[2] = 0xAA; //set cmd to enter program mode ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(2); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; //check whether into program mode ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++static int cst3xx_erase_program_area(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; ++ buf[2] = 0x00; //set cmd to erase main area ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(5); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x03; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++ ++ ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms) ++{ ++ ++ unsigned char buf[4]; ++ buf[0] = 0xD1; ++ buf[1] = 0x0E; ++ cst3xx_i2c_write(ts->client, buf, 2); ++/* ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(2); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++*/ ++ mdelay(ms); ++} ++ ++ ++static int cst3xx_write_program_data(struct i2c_client * client, ++ const unsigned char *pdata) ++{ ++ int i, ret; ++ unsigned char *i2c_buf; ++ unsigned short eep_addr; ++ int total_kbyte; ++ ++ unsigned char temp_buf[8]; ++ unsigned short iic_addr; ++ int j; ++ ++ ++ i2c_buf = kmalloc(sizeof(unsigned char)*(1024 + 2), GFP_KERNEL); ++ if (i2c_buf == NULL) ++ return -1; ++ ++ //make sure fwbin len is N*1K ++ //total_kbyte = len / 1024; ++ total_kbyte = 24; ++ for (i=0; i>8; ++ ret = cst3xx_i2c_write(client, i2c_buf, 4); ++ if (ret < 0) ++ goto error_out; ++ ++ memcpy(i2c_buf, pdata + eep_addr, 1024); ++ for(j=0; j<256; j++) { ++ iic_addr = (j<<2); ++ temp_buf[0] = (iic_addr+0xA018)>>8; ++ temp_buf[1] = (iic_addr+0xA018)&0xFF; ++ temp_buf[2] = i2c_buf[iic_addr+0]; ++ temp_buf[3] = i2c_buf[iic_addr+1]; ++ temp_buf[4] = i2c_buf[iic_addr+2]; ++ temp_buf[5] = i2c_buf[iic_addr+3]; ++ ret = cst3xx_i2c_write(client, temp_buf, 6); ++ if (ret < 0) ++ goto error_out; ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x04; ++ i2c_buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(60); ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x05; ++ ret = cst3xx_i2c_read_register(client, i2c_buf, 1); ++ if (ret < 0) ++ goto error_out; ++ ++ if (i2c_buf[0] != 0x55) ++ goto error_out; ++ ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x03; ++ i2c_buf[2] = 0x00; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(8); ++ ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ ++ return 0; ++ ++error_out: ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ return -1; ++} ++ ++ ++static int cst3xx_check_checksum(struct i2c_client * client) ++{ ++ int ret; ++ int i; ++ unsigned int checksum; ++ unsigned int bin_checksum; ++ unsigned char buf[4]; ++ const unsigned char *pData; ++ ++ for(i=0; i<5; i++) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if(ret < 0) ++ { ++ mdelay(2); ++ continue; ++ } ++ ++ if(buf[0]!=0) ++ break; ++ else ++ mdelay(2); ++ } ++ mdelay(2); ++ ++ ++ if(buf[0]==0x01) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ ++ if(ret < 0) return -1; ++ ++ // read chip checksum ++ checksum = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); ++ ++ pData=(unsigned char *)pcst3xx_update_firmware +24*1024+16; //7*1024 +512 ++ bin_checksum = pData[0] + (pData[1]<<8) + (pData[2]<<16) + (pData[3]<<24); ++ ++ printk(" hyn the updated ic checksum is :0x%x. the updating firmware checksum is:0x%x------\n", checksum, bin_checksum); ++ ++ if(checksum!=bin_checksum) ++ { ++ printk(" cst3xx hyn check sum error.\n"); ++ return -1; ++ ++ } ++ ++ } ++ else ++ { ++ printk(" cst3xx hyn No checksum.\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x06; ++ buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) ++ return -1; ++ ++ mdelay(10); //wait for restart ++ ++ ++ return 0; ++} ++ ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ ++ printk(" cst3xx----------upgrade cst3xx begain------------\n"); ++ disable_irq(ts->irq); ++ mdelay(20); ++START_FLOW: ++ ++#ifdef HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++ close_vcc3v3Power(); ++ mdelay(20); ++ open_vcc3v3Power(); ++ mdelay(5+retry); ++#else ++ cst3xx_reset_ic(ts,5+retry); ++#endif ++ ret = cst3xx_into_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]into program mode failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_erase_program_area(ts->client); ++ if (ret) { ++ printk(" cst3xx[cst3xx]erase main area failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_write_program_data(ts->client, pdata); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]write program data into cstxxx failed.\n"); ++ goto err_out; ++ } ++ ++ ret =cst3xx_check_checksum(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] after write program cst3xx_check_checksum failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_exit_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]exit program mode failed.\n"); ++ goto err_out; ++ } ++ ++ cst3xx_reset_ic(ts,20); ++ ++ printk(" cst3xx hyn----------cst3xx_update_firmware end------------\n"); ++ ++ enable_irq(ts->irq); ++ ++ return 0; ++ ++err_out: ++ if (retry < 30) { ++ retry++; ++ mdelay(20); ++ goto START_FLOW; ++ } ++ else { ++ enable_irq(ts->irq); ++ return -1; ++ } ++} ++ ++ ++ ++ ++/******************************************************* ++Function: ++ get firmware version, ic type... ++Input: ++ client: i2c client ++Output: ++ success: 0 ++ fail: -1 ++*******************************************************/ ++static int cst3xx_firmware_info(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[28]; ++// unsigned short ic_type, project_id; ++ ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x01; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ ++ mdelay(40); ++ ++ buf[0] = 0xD1; ++ buf[1] = 0xFC; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ ++ //0xCACA0000 ++ g_cst3xx_ic_checkcode = buf[3]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[2]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[1]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip g_cst3xx_ic_checkcode:0x%x.\r\n",g_cst3xx_ic_checkcode); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x04; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ g_cst3xx_ic_type = buf[3]; ++ g_cst3xx_ic_type <<= 8; ++ g_cst3xx_ic_type |= buf[2]; ++ ++ ++ g_cst3xx_ic_project_id = buf[1]; ++ g_cst3xx_ic_project_id <<= 8; ++ g_cst3xx_ic_project_id |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip ic g_cst3xx_ic_type :0x%x, g_cst3xx_ic_project_id:0x%x\r\n", ++ g_cst3xx_ic_type, g_cst3xx_ic_project_id); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 8); ++ if (ret < 0) return -1; ++ ++ g_cst3xx_ic_version = buf[3]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[2]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[1]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[0]; ++ ++ g_cst3xx_ic_checksum = buf[7]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[6]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[5]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[4]; ++ ++ tpd_info.vid = g_cst3xx_ic_version; ++ tpd_info.pid = 0x00; ++ ++ ++ printk(" cst3xx [cst3xx] the chip ic version:0x%x, checksum:0x%x\r\n", ++ g_cst3xx_ic_version, g_cst3xx_ic_checksum); ++ ++ if(g_cst3xx_ic_version==0xA5A5A5A5) ++ { ++ printk(" cst3xx [cst3xx] the chip ic don't have firmware. \n"); ++ return -1; ++ } ++ if((g_cst3xx_ic_checkcode&0xffff0000)!=0xCACA0000){ ++ printk("linc cst3xx [cst3xx] cst3xx_firmware_info read error .\r\n"); ++ return -1; ++ } ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x09; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ mdelay(5); ++ ++ ++ return 0; ++} ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict) ++{ ++ unsigned short ic_type, project_id; ++ unsigned int fw_checksum, fw_version; ++ const unsigned int *p; ++ int i; ++ unsigned char *pBuf; ++ ++ fw_checksum = 0x55; ++ p = (const unsigned int *)pdata; ++ for (i=0; i<(CST3XX_BIN_SIZE-4); i+=4) { ++ fw_checksum += (*p); ++ p++; ++ } ++ ++ if (fw_checksum != (*p)) { ++ printk(" cst3xx[cst3xx]calculated checksum error:0x%x not equal 0x%x.\n", fw_checksum, *p); ++ return -1; //bad fw, so do not update ++ } ++ ++ pBuf = &pdata[CST3XX_BIN_SIZE-16]; ++ ++ project_id = pBuf[1]; ++ project_id <<= 8; ++ project_id |= pBuf[0]; ++ ++ ic_type = pBuf[3]; ++ ic_type <<= 8; ++ ic_type |= pBuf[2]; ++ ++ fw_version = pBuf[7]; ++ fw_version <<= 8; ++ fw_version |= pBuf[6]; ++ fw_version <<= 8; ++ fw_version |= pBuf[5]; ++ fw_version <<= 8; ++ fw_version |= pBuf[4]; ++ ++ fw_checksum = pBuf[11]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[10]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[9]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[8]; ++ ++ printk(" cst3xx[cst3xx]the updating firmware:project_id:0x%04x,ic type:0x%04x,version:0x%x,checksum:0x%x\n", ++ project_id, ic_type, fw_version, fw_checksum); ++ ++ if (strict > 0) { ++ ++ if (g_cst3xx_ic_checksum != fw_checksum){ ++ if (g_cst3xx_ic_version >fw_version){ ++ printk("[cst3xx]fw version(0x%x), ic version(0x%x).\n",fw_version, g_cst3xx_ic_version); ++ // return -1; ++ } ++ }else{ ++ printk("[cst3xx]fw checksum(0x%x), ic checksum(0x%x).\n",fw_checksum, g_cst3xx_ic_checksum); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ int flag = 0; ++ ++ while (retry++ < 3) { ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret == 0) { ++ flag = 1; ++ break; ++ } ++ } ++ ++ if (flag == 1) { ++ ret = cst3xx_update_judge(pdata, 1); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] no need to update firmware.\n"); ++ return 0; ++ } ++ } ++ ++ ret = cst3xx_update_firmware(ts, pdata); ++ if (ret < 0){ ++ printk(" cst3xx [cst3xx] update firmware failed.\n"); ++ return -1; ++ } ++ ++ mdelay(50); ++ ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx [cst3xx] after update read version and checksum fail.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++static int hyn_boot_update_fw(struct i2c_client * ts) ++{ ++ unsigned char *ptr_fw; ++ int ret; ++ ptr_fw = pcst3xx_update_firmware; ++ ret = cst3xx_boot_update_fw(ts, ptr_fw); ++ return ret; ++ ++} ++ ++ ++/*******************************Chose which I2C interface ********************************************/ ++ ++#if USE_ANALOG_I2C ++ ++#define I2CSDA GPIO_PB(23) ++#define I2CSCL GPIO_PB(22) ++ ++#define I2CSDA_HIGH gpio_direction_output(I2CSDA,1) ++#define I2CSDA_LOW gpio_direction_output(I2CSDA,0) ++ ++#define I2CSCL_HIGH gpio_direction_output(I2CSCL,1) ++#define I2CSCL_LOW gpio_direction_output(I2CSCL,0) ++ ++#define delay_data 2 ++static void iicstart(void) ++{ ++ I2CSDA_HIGH; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_LOW; ++ __udelay(2); ++ I2CSCL_LOW; ++ __udelay(2); ++} ++static void iicstop(void) ++{ ++ I2CSDA_LOW; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_HIGH; ++ __udelay(2); ++ ++} ++static unsigned char waitack(void) ++{ ++ u8 ucErrTime=0; ++ ++// gpio_direction_input(GPIO_PC(27)); ++ gpio_direction_input(GPIO_PB(23)); ++ // __udelay(2); ++ ++ // I2CSDA_HIGH; ++ // __udelay(2); ++ I2CSCL_HIGH; ++ __udelay(2); ++ ++// while(__gpio_get_value(GPIO_PC(27))) ++ while(__gpio_get_value(GPIO_PB(23))) ++ { ++ ucErrTime++; ++ // printk("time out ++ \n"); ++ if(ucErrTime>250) ++ { ++ iicstop(); ++ return 1; ++ } ++ } ++ I2CSCL_LOW; ++ __udelay(2); ++ return 0; ++} ++static void sendack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_LOW; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ ++} ++static void sendnotack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_HIGH; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++} ++static void iicsendbyte(unsigned char ch) ++{ ++ unsigned char i; ++ I2CSCL_LOW; ++ for(i = 0;i<8;i++) ++ { ++ if(ch&0x80) ++ { ++ I2CSDA_HIGH; ++ } ++ else ++ { ++ I2CSDA_LOW; ++ } ++ __udelay(delay_data); ++ ch<<=1; ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ } ++} ++static unsigned char iicreceivebyte(unsigned char ack) ++{ ++ unsigned char i=8; ++ unsigned char ddata=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ __udelay(delay_data); ++ ++ for(i = 0;i<8;i++) ++ { ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ ++ ddata<<=1; ++ if(gpio_get_value(GPIO_PC(27))) ddata++; ++ } ++ ++ if(!ack) ++ sendnotack(); ++ else ++ sendack(); ++ ++ return ddata; ++} ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int count = len; ++ iicstart(); ++ __udelay(delay_data); ++ ++/* ++ iicsendbyte( (0x1a<<1) | 0); ++ __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ ++ iicsendbyte(buf[0]); ++ __udelay(delay_data); ++ waitack(); ++ __udelay(delay_data); ++*/ ++ iicstart(); ++ __udelay(delay_data); ++ ++ iicsendbyte((0x1a << 1 ) | 1); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ ++ while(count) ++ { ++ if(count == 1) *buf = iicreceivebyte(0); ++ else *buf = iicreceivebyte(1); ++ count --; ++ buf++; ++ } ++ iicstop(); ++ __udelay(delay_data); ++ return 0; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int count = len; ++ iicstart(); ++ // __udelay(delay_data); ++ ++ iicsendbyte((0x1A << 1) | 0); ++// __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write send address wait ack timeoue \n"); ++ return 1; ++ } ++ ++ while(count--) ++ { ++ iicsendbyte(*(buf++)); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ } ++ ++ iicstop(); ++ __udelay(delay_data); ++ ++ return 0; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if(ret) printk("failed to write cst3xx\n"); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ if(ret) printk("failed to write cst3xx\n"); ++ return ret; ++} ++ ++#elif USE_LOWEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_recv(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_send(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ ++ return ret; ++} ++ ++#elif USE_HIGHEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags |= I2C_M_RD; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++/******************************************************* ++Function: ++ read data from register. ++Input: ++ buf: first two byte is register addr, then read data store into buf ++ len: length of data that to read ++Output: ++ success: number of messages ++ fail: negative errno ++*******************************************************/ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++// printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ struct i2c_msg msgs[2]; ++ int ret = -1; ++ int retries = 0; ++ ++ msgs[0].flags = 0; ++ msgs[0].addr = client->addr; ++ msgs[0].len = 2; ++ msgs[0].buf = buf; ++ ++ msgs[1].flags |= I2C_M_RD; ++ msgs[1].addr = client->addr; ++ msgs[1].len = len; ++ msgs[1].buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if(ret == 2) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++// printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags = 0; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++#else ++#endif ++/*********************************i2c end********************************/ ++ ++ ++static int cst3xx_i2c_test(struct i2c_client *client) ++{ ++ int retry = 0; ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ while (retry++ < 5) { ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret == 0) ++ return ret; ++ ++ mdelay(2); ++ } ++ ++ if(retry==5) printk(" cst3xx hyn I2C TEST error.ret:%d;\n", ret); ++ ++ return ret; ++} ++ ++ ++static void cst3xx_reset(struct cst3xx_ts_data *ts) { ++ if(gpio_is_valid(ts->pdata->reset_gpio)) { ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(100); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++ mdelay(100); ++ } ++} ++/**************************** basic communication end*******************************/ ++ ++ ++static void cst3xx_touch_report(struct cst3xx_ts_data *ts) ++{ ++ unsigned char buf[30]; ++ unsigned char i2c_buf[8]; ++ unsigned char key_status, key_id = 0, finger_id, sw; ++ unsigned int input_x = 0; ++ unsigned int input_y = 0; ++ unsigned int input_w = 0; ++ unsigned int input_x_delta = 0; ++ unsigned int input_y_delta = 0; ++ unsigned char cnt_up, cnt_down; ++ int i, ret, idx; ++ int cnt, i2c_len; ++ ++ int len_1, len_2; ++ ++ key_status = 0; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(ts->client, buf, 7); ++ if(ret < 0) { ++ printk(" iic read touch point data failed.\n"); ++ goto OUT_PROCESS; ++ } ++ // printk(" read buf : buf[0]: %x ,buf[1]: %x ,buf[2]: %x, buf[3]: %x,buf[4]: %x ,buf[5]: %x ,buf[6]: %x, buf[7]: %x,\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); ++ ++ if(buf[6] != 0xAB) { ++ printk(KERN_INFO " data is not valid..\r\n"); ++ goto OUT_PROCESS; ++ } ++ ++ cnt = buf[5] & 0x7F; ++ if(cnt > 1) goto OUT_PROCESS; ++ else if(cnt==0) goto CLR_POINT; ++ ++ if(cnt == 0x01) { ++ goto FINGER_PROCESS; ++ } ++ ++FINGER_PROCESS: ++ ++ /* ++ * sw: buf[0] low 4 bit ++ * x pos: buf[1] low 4 bit | buf[3] high 4 bit ++ * y pos: buf[2] low 4 bit | buf[3] low 4 bit ++ * z press : buf[4] ++ * finger_id:buf[0] high 4 bit ++ */ ++ i2c_buf[0] = 0xD0; ++ i2c_buf[1] = 0x00; ++ i2c_buf[2] = 0xAB; ++ ++ ret = cst3xx_i2c_write(ts->client, i2c_buf, 3); ++ if(ret < 0) { ++ printk(" cst3xx hyn send read touch info ending failed.\r\n"); ++ cst3xx_reset_ic(ts,20); ++ goto END; ++ } ++ ++ idx = 0; ++ cnt_up = 0; ++ cnt_down = 0; ++ input_x = (unsigned int)((buf[idx + 1] << 4) | ((buf[idx + 3] >> 4) & 0x0F)); ++ input_y = (unsigned int)((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0F)); ++ input_w = (unsigned int)(buf[idx + 4]); ++ sw = (buf[idx] & 0x0F) >> 1; ++ finger_id = (buf[idx] >> 4) & 0x0F; ++ ++ printk(" no handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n", input_x, input_y, input_w,finger_id, sw); ++ ++ input_x=input_x*CST3XX_MAX_X/CST3XX_MAX_X; //update 0729 no handle == handle ++// input_x=input_x*CST3XX_MAX_X/268; //update 0729 no handle == handle ++// input_x=input_x*CST3XX_MAX_X/360; //update 0729 no handle == handle ++// input_y=input_y*CST3XX_MAX_Y/800; ++ ++// if(input_x >= CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++// if(input_y >= CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ ++// input_x = CST3XX_MAX_X-input_x; ++// input_y = CST3XX_MAX_Y-input_y; ++ ++#ifdef HYN_DRAW_POINT ++ if(input_x > 300){ ++ input_x_delta = input_x - (CST3XX_MAX_X/2); ++ input_x = input_x + input_x_delta/((CST3XX_MAX_X/2)/20); ++ if(input_x > CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++ } ++ if(input_x < 40){ ++ input_x_delta = (CST3XX_MAX_X/2) - input_x; ++ input_x = input_x - input_x_delta/((CST3XX_MAX_X/2)/12); ++ if(input_x < 0) input_x = 0; ++ } ++ if(input_y > 760){ ++ input_y_delta = input_y - (CST3XX_MAX_Y/2); ++ input_y = input_y + input_y_delta/((CST3XX_MAX_Y/2)/12); ++ if(input_y > CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ } ++ if(input_y < 40){ ++ input_y_delta = (CST3XX_MAX_Y/2) - input_y; ++ input_y = input_y - input_y_delta/((CST3XX_MAX_Y/2)/25); ++ if(input_y < 0) input_y = 0; ++ } ++#endif ++ ++ printk(" handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n\n", input_x, input_y, input_w,finger_id, sw); ++ ++ if (sw == 0x03 ) { ++ if((input_x > x_temp_pos + ERROR_TOUCH) || (input_x < x_temp_pos -ERROR_TOUCH) || (input_y > y_temp_pos + ERROR_TOUCH) || (input_y < y_temp_pos -ERROR_TOUCH)) ++ { ++ // printk(" REPORT TOUCH DOWM Handle \n"); ++ x_temp_pos = input_x; ++ y_temp_pos = input_y; ++ input_report_key(ts->input_dev, BTN_TOUCH, 1); ++ input_report_abs(ts->input_dev, ABS_X, input_x); ++ input_report_abs(ts->input_dev, ABS_Y, input_y); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 1); ++ input_sync(ts->input_dev); ++ } ++ cnt_down++; ++ } ++ else if(sw == 0) { ++ cnt_up++; ++ } ++ ++ if((cnt_up>0) && (cnt_down==0) ){ ++ // printk(" REPORT TOUCH UP Handle \n"); ++ x_temp_pos = 0; ++ y_temp_pos = 0; ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 0); ++ input_mt_sync(ts->input_dev); ++ } ++ input_sync(ts->input_dev); ++ goto END; ++CLR_POINT: ++ ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_mt_sync(ts->input_dev); ++ input_sync(ts->input_dev); ++ ++OUT_PROCESS: ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ buf[2] = 0xAB; ++ ret = cst3xx_i2c_write(ts->client, buf, 3); ++ if (ret < 0) { ++ printk(" send read touch info ending failed.\n"); ++ cst3xx_reset_ic(ts,20); ++ } ++END: ++ return; ++} ++ ++ ++/******************************* irq handle begin************************************/ ++static void cst3xx_work_handler(struct work_struct *work) ++{ ++ struct cst3xx_ts_data *cst3xx_ts = container_of(work, struct cst3xx_ts_data, work); ++ int ret = 0; ++ /******************here handle touch *******************/ ++ // printk(KERN_INFO "-----------enter cst3xx_work_handler------------\n"); ++ cst3xx_touch_report(cst3xx_ts); ++ enable_irq(cst3xx_ts->irq); ++} ++ ++static irqreturn_t cst3xx_ts_irq_handler(int irq, void *dev_id) ++{ ++ struct cst3xx_ts_data *ts = dev_id; ++ ++ // printk( KERN_INFO "-----------enter cst3xx_ts_irq_handler------------\n"); ++ ++ disable_irq_nosync(ts->irq);//use in interrupt,disable_irq will make dead lock. ++ ++ if (!work_pending(&ts->work)) { ++ queue_work(ts->workqueue, &ts->work); ++ // queue_delayed_work(ts->workqueue,&ts->dwork,1);//10ms * x ++ } else { ++ enable_irq(ts->irq); ++ } ++ ++ return IRQ_HANDLED; ++} ++/******************************* irq handle end************************************/ ++static int cst3xx_parse_dt(struct device *dev, struct cst3xx_platform_data *pdata) ++{ ++ int ret = 0; ++ struct device_node *np = dev->of_node; ++ u32 temp_val = 0; ++ ++ HYN_FUNC_ENTER(); ++ ++ /* reset, irq gpio info */ ++ pdata->reset_gpio = of_get_named_gpio_flags(np, "hyn,reset-gpio", ++ 0, &pdata->reset_gpio_flags); ++ if (pdata->reset_gpio < 0) ++ HYN_ERROR("Unable to get reset_gpio"); ++ ++ pdata->int_gpio = of_get_named_gpio_flags(np, "hyn,irq-gpio", ++ 0, &pdata->irqflags); ++ if (pdata->int_gpio < 0) ++ HYN_ERROR("Unable to get irq_gpio"); ++ ++ HYN_INFO(" irq gpio:%d, reset gpio:%d", ++ pdata->int_gpio, pdata->reset_gpio); ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++} ++static int cst3xx_gpio_configure(struct cst3xx_ts_data *data) ++{ ++ int ret = 0; ++ ++ HYN_FUNC_ENTER(); ++ /* request irq gpio */ ++ if (gpio_is_valid(data->pdata->int_gpio)) { ++ ret = gpio_request(data->pdata->int_gpio, "cst3xx_irq_gpio"); ++ if (ret) { ++ HYN_ERROR("[GPIO]irq gpio request failed"); ++ goto err_irq_gpio_req; ++ } ++ ++ ret = gpio_direction_input(data->pdata->int_gpio); ++ if (ret) { ++ HYN_ERROR("[GPIO]set_direction for irq gpio failed"); ++ goto err_irq_gpio_dir; ++ } ++ } ++ ++ /* request reset gpio */ ++ if (gpio_is_valid(data->pdata->reset_gpio)) { ++ ret = gpio_request(data->pdata->reset_gpio, "cst3xx_reset_gpio"); ++ if (ret) { ++ HYN_ERROR("[GPIO]reset gpio request failed"); ++ goto err_irq_gpio_dir; ++ } ++ ++// ret = gpio_direction_output(data->pdata->reset_gpio, 1); ++// if (ret) { ++// HYN_ERROR("[GPIO]set_direction for reset gpio failed"); ++// goto err_reset_gpio_dir; ++// } ++ } ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++ ++err_reset_gpio_dir: ++ if (gpio_is_valid(data->pdata->reset_gpio)) ++ gpio_free(data->pdata->reset_gpio); ++err_irq_gpio_dir: ++ if (gpio_is_valid(data->pdata->int_gpio)) ++ gpio_free(data->pdata->int_gpio); ++err_irq_gpio_req: ++ HYN_FUNC_EXIT(); ++ return ret; ++} ++ ++static int cst3xx_input_init(struct cst3xx_ts_data *ts_data) ++{ ++ int ret = 0; ++ int key_num = 0; ++ struct cst3xx_platform_data *pdata = ts_data->pdata; ++ struct input_dev *input_dev; ++ ++ HYN_FUNC_ENTER(); ++ input_dev = input_allocate_device(); ++ if (!input_dev) { ++ HYN_ERROR("Failed to allocate memory for input device"); ++ return -ENOMEM; ++ } ++ ++ /* Init and register Input device */ ++ input_dev->name = CST3XX_NAME; ++ ++ input_dev->id.bustype = BUS_I2C; ++ input_dev->dev.parent = ts_data->dev; ++ ++ input_set_drvdata(input_dev, ts_data); ++ ++ __set_bit(EV_SYN, input_dev->evbit); ++ __set_bit(EV_ABS, input_dev->evbit); ++ __set_bit(EV_KEY, input_dev->evbit); ++ __set_bit(BTN_TOUCH, input_dev->keybit); ++// __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); ++ set_bit(ABS_X, input_dev->absbit); //add from hyn ++ set_bit(ABS_Y, input_dev->absbit); ++ set_bit(ABS_PRESSURE, input_dev->absbit); ++ ++/*---add from hyn*/ ++ input_set_abs_params(input_dev, ABS_X, ts_data->pdata->x_min, ts_data->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, ts_data->pdata->y_min, ts_data->pdata->y_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0 , 0); ++/*add from hyn---*/ ++ ++ ret = input_register_device(input_dev); ++ if (ret) { ++ HYN_ERROR("Input device registration failed"); ++ input_set_drvdata(input_dev, NULL); ++ input_free_device(input_dev); ++ input_dev = NULL; ++ return ret; ++ } ++ ++ ts_data->input_dev = input_dev; ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++} ++ ++static int cst3xx_irq_registration(struct cst3xx_ts_data *ts_data) ++{ ++ int ret = 0; ++ struct cst3xx_platform_data *pdata = ts_data->pdata; ++ ++ ts_data->irq = gpio_to_irq(pdata->int_gpio); ++ pdata->irqflags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; ++ HYN_INFO("irq:%d, flag:%x", ts_data->irq, pdata->irqflags); ++ ret = request_threaded_irq(ts_data->irq, NULL, cst3xx_ts_irq_handler, ++ pdata->irqflags, ++ CST3XX_NAME, ts_data); ++ ++ return ret; ++} ++ ++static int cst3xx_ts_probe_entry(struct cst3xx_ts_data *ts_data) ++{ ++ int ret = 0; ++ int rc=-1; ++ int pdata_size = sizeof(struct cst3xx_platform_data); ++ ++ HYN_FUNC_ENTER(); ++ ts_data->pdata = kzalloc(pdata_size, GFP_KERNEL); ++ if (!ts_data->pdata) { ++ HYN_ERROR("allocate memory for platform_data fail"); ++ return -ENOMEM; ++ } ++ ++ if (ts_data->dev->of_node) { ++ ret = cst3xx_parse_dt(ts_data->dev, ts_data->pdata); ++ if (ret) ++ HYN_ERROR("device-tree parse fail"); ++ } else { ++ if (ts_data->dev->platform_data) { ++ memcpy(ts_data->pdata, ts_data->dev->platform_data, pdata_size); ++ } else { ++ HYN_ERROR("platform_data is null"); ++ return -ENODEV; ++ } ++ } ++ //init work for cst3xx.. ++ ++ INIT_WORK(&ts_data->work, cst3xx_work_handler); ++ ++ ts_data->workqueue = create_singlethread_workqueue("cst3xx_wq"); ++ if (!ts_data->workqueue) { ++ HYN_ERROR("create cst3xx workqueue fail"); ++ } ++ ++// spin_lock_init(&ts_data->irq_lock); ++// mutex_init(&ts_data->report_mutex); ++// mutex_init(&ts_data->bus_lock); ++ ++ /* Init communication interface */ ++ ret = cst3xx_bus_init(ts_data); ++ if (ret) { ++ HYN_ERROR("bus initialize fail"); ++ goto err_bus_init; ++ } ++#if USE_ANALOG_I2C ++ if (gpio_is_valid(I2CSDA) ++ { ++ gpio_free(I2CSDA); ++ ret = gpio_request(GPIO_PB(23),"I2C2-SDA"); ++ if(ret < 0){ ++ printk("I2C2-SDA gpio request failed\n"); ++ return ret; ++ } ++ } ++ if (gpio_is_valid(I2CSCL)) ++ { ++ gpio_free(I2CSCL); ++ ret = gpio_request(GPIO_PB(22),"I2C2-SCL"); ++ if(ret < 0){ ++ printk("I2C2-SCL gpio request failed\n"); ++ return ret; ++ } ++ } ++#endif ++ ret = cst3xx_i2c_test(ts_data->client); ++ // if(ret>=0){ ++ if(ret<0){ ++ ++ ++ mdelay(100); ++ ++ printk( KERN_INFO "cst3xx test OK -------------------\n"); ++#ifdef HYN_UPDATE_FIRMWARE_ENABLE ++ ret = cst3xx_boot_update_fw(ts_data,pcst3xx_update_firmware);// ++ if(ret < 0){ ++ printk(" cst3xx hyn_boot_update_fw failed.\n"); ++ return -1; ++ } ++#endif ++ ++ }else{ ++ // printk( KERN_INFO "cst3xx hyn i2c communication failed.---------------\n"); ++ //return -1; ++ ++ mdelay(20); ++// rc = hyn_boot_update_fw(ts); ++ rc = hyn_boot_update_fw(ts_data); ++ if(rc < 0){ ++ printk(" cst3xx hyn_boot_update_fw failed.\n"); ++ //return -1; ++ } ++ } ++ ++ ret = cst3xx_input_init(ts_data); ++ if (ret) { ++ HYN_ERROR("input initialize fail"); ++ goto err_input_init; ++ } ++ ++ ret = cst3xx_gpio_configure(ts_data); ++ if (ret) { ++ HYN_ERROR("configure the gpios fail"); ++ goto err_gpio_config; ++ } ++ printk( KERN_INFO "cst3xx reset ----before---------------\n"); ++ cst3xx_reset(ts_data); ++ printk( KERN_INFO "cst3xx reset ----after--------------\n"); ++ ++ ret = cst3xx_irq_registration(ts_data); ++ if (ret) { ++ HYN_ERROR("request irq failed"); ++ goto err_irq_req; ++ } ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++ ++err_irq_req: ++ if (gpio_is_valid(ts_data->pdata->reset_gpio)) ++ gpio_free(ts_data->pdata->reset_gpio); ++ if (gpio_is_valid(ts_data->pdata->int_gpio)) ++ gpio_free(ts_data->pdata->int_gpio); ++err_gpio_config: ++ kfree_safe(ts_data->point_buf); ++ kfree_safe(ts_data->events); ++err_input_init: ++ if (ts_data->workqueue) ++ destroy_workqueue(ts_data->workqueue); ++err_bus_init: ++ kfree_safe(ts_data->bus_tx_buf); ++ kfree_safe(ts_data->bus_rx_buf); ++ kfree_safe(ts_data->pdata); ++ ++ HYN_FUNC_EXIT(); ++ return ret; ++} ++static int cst3xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ int ret = 0; ++ struct cst3xx_ts_data *ts_data = NULL; ++ struct input_dev *input_dev; ++ ++ struct cst3xx_platform_data *pdata = (struct cst3xx_platform_data*)client->dev.platform_data; ++ ++ HYN_INFO("Touch Screen(I2C BUS) driver prboe..."); ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ HYN_ERROR("I2C not supported"); ++ return -ENODEV; ++ } ++ ++ /* malloc memory for global struct variable */ ++ ts_data = (struct cst3xx_ts_data *)kzalloc(sizeof(*ts_data), GFP_KERNEL); ++ if (!ts_data) { ++ HYN_ERROR("allocate memory for cst3xx_data fail"); ++ return -ENOMEM; ++ } ++ ts_data->client = client; ++ ts_data->dev = &client->dev; ++ ts_data->pdata = pdata; ++ i2c_set_clientdata(client, ts_data); ++ ++ ret = cst3xx_ts_probe_entry(ts_data); ++ if (ret) { ++ HYN_ERROR("Touch Screen(I2C BUS) driver probe fail"); ++ kfree_safe(ts_data); ++ return ret; ++ } ++ if(client->addr != 0x1A) //check address ++ { ++ client->addr = 0x1A; ++ printk(">>>>>>>>>>>>>1>>>xtang:i2c_client_HYN->addr=%d.\n",client->addr); ++ ++ }else ++ printk(">>>>>>>>>>>>2>>>>xtang:i2c_client_HYN->addr=%d.\n",client->addr); ++ ++ ++ HYN_INFO("Touch Screen(I2C BUS) driver prboe successfully"); ++ return 0; ++} ++ ++ ++static int cst3xx_ts_remove(struct i2c_client *client) ++{ ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ free_irq(ts->irq,ts); ++ devm_free_irq(&ts->client->dev, ts->client->irq,ts); ++ destroy_workqueue(ts->workqueue); ++ input_unregister_device(ts->input_dev); ++ devm_gpio_free(&ts->client->dev, ts->pdata->reset_gpio); ++ gpio_free(ts->pdata->int_gpio); ++ ++#if USE_ANALOG_I2C ++ gpio_free(I2CSDA); ++ gpio_free(I2CSCL); ++#endif ++//i2c bus init. ++ cst3xx_bus_exit(ts); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int cst3xx_ts_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ enable_irq_wake(client->irq); ++ } else { ++ disable_irq(client->irq); ++ cst3xx_ts_power(ts, false);//reset ++ } ++ ++ return 0; ++} ++ ++static int cst3xx_ts_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ disable_irq_wake(client->irq); ++ } else { ++ cst3xx_ts_power(ts, true); ++ enable_irq(client->irq); ++ } ++ return 0; ++} ++ ++#endif ++ ++static SIMPLE_DEV_PM_OPS(cst3xx_ts_pm_ops, ++ cst3xx_ts_suspend, cst3xx_ts_resume); ++ ++static const struct i2c_device_id cst3xx_ts_id[] = { ++ { CST3XX_NAME, 0 }, ++ { } ++}; ++static const struct of_device_id cst3xx_dt_match[] = { ++ {.compatible = "hyn,cst3xx", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, cst3xx_dt_match); ++ ++static struct i2c_driver cst3xx_ts_driver = { ++ .probe = cst3xx_ts_probe, ++ .remove = cst3xx_ts_remove, ++ .driver = { ++ .name = CST3XX_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(cst3xx_dt_match), ++ .pm = &cst3xx_ts_pm_ops, ++ }, ++ .id_table = cst3xx_ts_id, ++}; ++ ++static int __init cst3xx_ts_init(void) ++{ ++ int ret = 0; ++ ++ HYN_FUNC_ENTER(); ++ ret = i2c_add_driver(&cst3xx_ts_driver); ++ if ( ret != 0 ) { ++ HYN_ERROR("hyn touch screen driver init failed!"); ++ } ++ HYN_FUNC_EXIT(); ++ return ret; ++} ++ ++static void __exit cst3xx_ts_exit(void) ++{ ++ i2c_del_driver(&cst3xx_ts_driver); ++} ++module_init(cst3xx_ts_init); ++module_exit(cst3xx_ts_exit); ++ ++MODULE_AUTHOR("HYN Driver Team"); ++MODULE_DESCRIPTION("HYN Touchscreen Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw_0729_update2.h b/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw_0729_update2.h +new file mode 100644 +index 000000000..24cfbcfed +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw_0729_update2.h +@@ -0,0 +1,1552 @@ ++ ++#ifndef __CST3xx_FW_H__ ++#define __CST3xx_FW_H__ ++ ++ unsigned char cst3_fw[] ={ ++ 0x98,0xE0,0x07,0x01,0xC8,0x28,0x02,0x00,0x00,0x00,0x00,0x00,0xC8,0xE8,0x01,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x90,0x08,0x07,0x00,0x98,0x08,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x98,0xA8,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x78,0x01,0x00,0x80,0x07,0xC0,0x17, ++ 0x82,0x07,0xC0,0x07,0x01,0x65,0x40,0x86,0xC1,0x41,0xC0,0x20,0xC5,0x68,0x31,0x12, ++ 0xF5,0x38,0x33,0x5A,0x32,0xA2,0x32,0xEA,0x10,0x62,0x8D,0x0E,0x81,0x07,0xC0,0x97, ++ 0x30,0xF2,0xF3,0x79,0x65,0x7E,0x30,0xB2,0x31,0x09,0x10,0x9A,0x87,0x06,0xD0,0xD8, ++ 0x35,0x12,0x35,0x5A,0x18,0x9A,0x39,0xC2,0x70,0x82,0x02,0x00,0x70,0x82,0x03,0x00, ++ 0xD0,0x81,0x98,0x16,0x43,0xC6,0x0B,0xC6,0xC2,0xD6,0x3F,0x90,0x99,0x0E,0x40,0x86, ++ 0x08,0x86,0xA9,0x0E,0x40,0x23,0x00,0x63,0x38,0x82,0x03,0x00,0x18,0x01,0x20,0x01, ++ 0x28,0x01,0x30,0x01,0xD0,0x81,0x98,0x0E,0x0F,0xC6,0xC3,0xDE,0x38,0x90,0x9A,0x06, ++ 0x08,0x86,0xA9,0x06,0x03,0x5B,0x38,0x82,0xAE,0xFD,0x30,0x02,0x30,0x02,0xEE,0xFD, ++ 0xA8,0x85,0xE8,0x85,0x84,0x27,0xE8,0xBF,0x37,0x8A,0xB8,0xFF,0xF8,0xAF,0x87,0x0F, ++ 0xD0,0xFF,0x80,0x27,0xEF,0x7F,0xBD,0xFF,0xF8,0x9F,0x87,0x27,0xE8,0xAF,0x05,0x00, ++ 0xAF,0x85,0x6F,0xFA,0x39,0x01,0xC0,0x43,0x37,0x4A,0xC9,0x01,0x38,0x30,0x32,0x42, ++ 0x86,0x01,0xC5,0x1B,0xCE,0x23,0xF0,0x53,0xC0,0x01,0x74,0x01,0xDD,0x16,0xC0,0x6B, ++ 0x48,0x68,0x87,0x3E,0xAA,0x7B,0xAC,0x3B,0x10,0xD2,0x8C,0x16,0xB0,0x63,0x06,0x09, ++ 0xB7,0x43,0xEC,0x85,0x34,0x6A,0xE8,0x4B,0xE6,0x48,0x92,0x4D,0xAF,0x4B,0x4D,0xF9, ++ 0x8D,0x0E,0x10,0x12,0x82,0x16,0xE8,0x0B,0x48,0x09,0x88,0x1E,0xB5,0x5B,0xAF,0x7B, ++ 0xAF,0x3B,0xEA,0x85,0x4F,0x09,0x8C,0xE6,0x0A,0x09,0xA8,0x0B,0xE8,0x85,0xAF,0x85, ++ 0x67,0x3A,0xE7,0x01,0x00,0x0F,0x80,0x0F,0xF5,0x1F,0xF0,0x03,0x47,0x01,0x80,0xD6, ++ 0xEF,0x85,0xA8,0xC5,0x00,0x21,0x80,0x0F,0xE8,0x6F,0x07,0x09,0x87,0x0F,0xE8,0x57, ++ 0x79,0x02,0x47,0xC3,0x0C,0x01,0x19,0x42,0x00,0xC3,0x01,0x11,0x86,0x0F,0xE8,0xBF, ++ 0x61,0xEA,0x56,0x03,0x29,0x41,0x18,0x42,0x17,0x03,0x49,0x03,0x1F,0x42,0x09,0x03, ++ 0x15,0x2B,0x4B,0x03,0x1D,0x42,0x09,0x03,0x4D,0x03,0x1B,0x42,0x0B,0x03,0x4B,0x03, ++ 0x35,0x21,0x18,0x82,0x0B,0x03,0x4B,0x03,0x42,0x00,0x02,0x00,0x09,0x03,0x4B,0x03, ++ 0x19,0x42,0x09,0x03,0x49,0x03,0x19,0x82,0x09,0x03,0x49,0x03,0x08,0x09,0x18,0x42, ++ 0x0F,0x03,0x41,0x03,0x1F,0x42,0x05,0x03,0x45,0x03,0x1F,0x82,0x07,0x03,0x47,0x03, ++ 0x1F,0x42,0x04,0x03,0x45,0x03,0x1D,0x42,0x05,0x03,0x45,0x03,0x1D,0x82,0x05,0x03, ++ 0x45,0x03,0x1B,0x42,0x03,0x03,0x43,0x03,0x1B,0x82,0x05,0x03,0x44,0x03,0x1D,0x42, ++ 0x03,0x03,0x45,0x03,0x1B,0x42,0x04,0x03,0x0E,0x81,0x42,0x02,0x82,0x27,0xE0,0x97, ++ 0x85,0x0F,0xE8,0x87,0x85,0x0F,0xE8,0x67,0x85,0x0F,0xE8,0x97,0x48,0xE2,0x05,0x01, ++ 0x1D,0x43,0x4C,0x03,0x1D,0x42,0x0D,0x03,0x10,0x2B,0x03,0x11,0x84,0x0F,0xE8,0x97, ++ 0x41,0xC3,0x09,0x01,0x19,0x42,0x00,0xC3,0x00,0x21,0x80,0x0F,0xE8,0x07,0x04,0x09, ++ 0x83,0x0F,0xE8,0xEF,0x42,0x03,0x41,0x00,0x01,0x00,0x02,0x03,0x40,0x03,0x0F,0x09, ++ 0x1F,0x42,0x00,0x03,0x4C,0x03,0x1B,0x42,0x09,0x03,0x4B,0x03,0x19,0x42,0x0C,0x03, ++ 0x41,0x03,0x1D,0x42,0x05,0x03,0x45,0x03,0x1D,0x82,0x01,0x03,0x41,0x03,0x1B,0x42, ++ 0x03,0x03,0x43,0x03,0x1B,0x82,0x01,0x03,0x48,0x0B,0x03,0x61,0x1B,0x0A,0x08,0x0B, ++ 0x48,0x0B,0x19,0x0A,0x0F,0x0B,0x41,0x0B,0x1F,0x0A,0x00,0x0B,0x48,0xE2,0x04,0x09, ++ 0xC8,0x01,0xAF,0x43,0x82,0x0F,0xD0,0xD7,0xEC,0xC5,0x47,0xCA,0xC6,0x01,0xF3,0x0B, ++ 0x42,0xCA,0x84,0x01,0x48,0x01,0x80,0x3E,0x4A,0xD2,0x04,0x0B,0x0C,0xF9,0x57,0xB2, ++ 0x8C,0x89,0x97,0x01,0x10,0x8B,0x00,0x17,0x48,0xB2,0xCC,0xE1,0x07,0x0B,0x12,0xF9, ++ 0x96,0xA1,0x02,0x13,0x08,0x31,0x08,0x0B,0x0C,0x11,0x08,0x0B,0x0A,0x51,0x08,0x0B, ++ 0x0C,0x49,0x18,0x0B,0x18,0x0B,0x0A,0x01,0x1C,0x0B,0x40,0x4A,0xC2,0x01,0x0F,0x14, ++ 0x3F,0x82,0xAB,0x85,0x70,0x62,0x0C,0x01,0x2C,0x01,0x60,0x62,0x50,0x62,0x04,0x01, ++ 0xA4,0x82,0x02,0x40,0x50,0x5A,0xC4,0x40,0xC4,0x00,0x54,0x5A,0xC0,0x10,0x1C,0x01, ++ 0xC6,0x83,0x01,0x38,0xC1,0x83,0xD0,0xC0,0x94,0x05,0x14,0x2A,0x90,0x06,0x30,0x2A, ++ 0x10,0x22,0xCC,0x06,0x32,0x22,0xE0,0x90,0xE6,0xD8,0x92,0xDD,0x5F,0x29,0x98,0x8E, ++ 0x59,0xFA,0xDB,0x40,0xA3,0xC2,0xE2,0xB0,0xE6,0x48,0x92,0x4D,0x4E,0x71,0x98,0xDE, ++ 0x48,0xD2,0x03,0x01,0xE4,0xD2,0x10,0x52,0x90,0x06,0x30,0x8A,0xE6,0x00,0x92,0x05, ++ 0x47,0x71,0x98,0xBE,0x50,0xCA,0x03,0x01,0x00,0x84,0xE0,0xE2,0x43,0xAC,0xD0,0x20, ++ 0xC8,0x20,0x03,0xA4,0xE6,0x00,0x92,0x05,0x47,0x71,0x98,0xB6,0x47,0x84,0x40,0xF9, ++ 0xCF,0x0E,0x00,0xF9,0x03,0x84,0x48,0x92,0x40,0x84,0x80,0x43,0xE8,0x85,0xAF,0x85, ++ 0x40,0x1A,0xC3,0x03,0x38,0x00,0x86,0xAE,0x00,0x01,0x85,0x0F,0xD3,0x7F,0x60,0x02, ++ 0x01,0x01,0xE0,0x01,0x8F,0x03,0xB9,0xFF,0xF9,0x47,0x34,0x0A,0x56,0x4A,0xCB,0x01, ++ 0x40,0x22,0x83,0x1F,0xD0,0x3F,0x04,0x11,0x88,0x03,0x01,0x01,0x86,0x0F,0xC8,0xB7, ++ 0xBC,0xFF,0xFF,0xFF,0xE8,0x85,0xA8,0x85,0x41,0xAA,0xC2,0x01,0xC8,0x03,0x42,0x01, ++ 0x8A,0x36,0x40,0x9A,0xC0,0x01,0xEF,0x03,0x40,0x29,0xC8,0x0E,0xBE,0xFF,0xF7,0x7F, ++ 0x61,0x7A,0xC2,0x03,0x38,0x00,0xA8,0x0E,0xBE,0xFF,0xF7,0x9F,0xC3,0x03,0xC3,0x03, ++ 0x08,0xE9,0x07,0x42,0x82,0x03,0x43,0xC2,0xC0,0x03,0x40,0x01,0x80,0x16,0x80,0x0F, ++ 0xE7,0x3F,0x3E,0xE7,0xE8,0x85,0xA8,0x85,0x48,0x32,0x02,0x01,0x02,0x43,0x4C,0x22, ++ 0xCC,0x01,0xB7,0x43,0xF0,0x43,0x86,0x0F,0xC8,0x8F,0xEE,0x85,0xA8,0x85,0x33,0x2A, ++ 0x48,0x01,0x80,0x4E,0x68,0x01,0x80,0x1E,0x30,0x82,0xC0,0x51,0x20,0x01,0x00,0x5F, ++ 0x30,0x82,0x80,0x51,0x20,0x01,0x00,0x3F,0x68,0x01,0x80,0x1E,0xF0,0x80,0x24,0x49, ++ 0x18,0x22,0x07,0x0F,0xE0,0x80,0x24,0x51,0x0A,0x01,0xF0,0x0A,0x48,0x01,0xD0,0x06, ++ 0x16,0x4A,0x0A,0x40,0x0A,0x01,0xF0,0x8A,0x82,0x27,0xD8,0x57,0x40,0xF9,0xEB,0x06, ++ 0x00,0xF9,0x6B,0x01,0x87,0x16,0x08,0xF9,0x88,0x09,0xD0,0x40,0xCB,0x00,0xE8,0x85, ++ 0xAC,0x85,0x87,0x3D,0x28,0x01,0x20,0x01,0x01,0x51,0x48,0x92,0x1A,0x42,0xC3,0x00, ++ 0x80,0x34,0xC0,0x34,0x01,0x08,0x13,0x39,0xC4,0x00,0x0A,0x90,0xC0,0x10,0x04,0xE1, ++ 0x90,0x2C,0xF0,0x82,0x80,0x24,0x30,0x01,0x38,0x01,0x10,0x01,0x90,0x1C,0x90,0x14, ++ 0x60,0x01,0x80,0x46,0xF0,0x10,0xDB,0x34,0x04,0x90,0xC2,0xD0,0x1C,0x39,0x09,0xD8, ++ 0xC0,0x90,0x36,0xE1,0xF8,0xB2,0x6C,0x01,0x83,0x56,0xF0,0x50,0x1A,0x51,0x18,0xD2, ++ 0x5E,0x02,0xC1,0x90,0x1A,0x39,0xC1,0x90,0x0E,0xD8,0xC4,0x90,0x3E,0xE1,0xF8,0xBA, ++ 0x60,0x21,0x80,0x4E,0xE0,0x18,0xD3,0x34,0x06,0xD8,0xC2,0x90,0x1C,0x39,0x09,0xD8, ++ 0xC0,0x90,0x1E,0xE1,0xF0,0x9A,0x9E,0x1C,0x68,0x69,0x80,0x5E,0xE0,0x50,0x1B,0x51, ++ 0x18,0xD2,0x5A,0xA2,0xC2,0x90,0xC6,0x88,0x14,0x39,0x09,0x90,0xC0,0x50,0x0C,0xE1, ++ 0xF0,0x8A,0x8A,0x14,0x08,0x09,0x88,0x0C,0x70,0x41,0xD1,0x3E,0x78,0x41,0xD1,0x2E, ++ 0xC9,0x1C,0x48,0x41,0xD0,0x16,0xC8,0x14,0x49,0x41,0xD9,0x06,0x08,0x01,0x00,0xEF, ++ 0x00,0xE0,0x07,0x01,0x10,0x00,0x00,0x42,0xF8,0x00,0x06,0x42,0x80,0x30,0x02,0x01, ++ 0x18,0x00,0x02,0x42,0x80,0x60,0x05,0x00,0x70,0x00,0x04,0x01,0xF8,0xFF,0x07,0x00, ++ 0x80,0x50,0x06,0x01,0x08,0x40,0x00,0x01,0x60,0x20,0x02,0x00,0x00,0x60,0x00,0x01, ++ 0x00,0x28,0x00,0x01,0x80,0xC0,0x04,0x01,0x00,0x20,0x00,0x01,0x88,0x0C,0x08,0x19, ++ 0x86,0x27,0xD0,0x37,0x10,0x82,0xED,0x3E,0x10,0xC2,0xED,0x2E,0xCC,0x1C,0x10,0x42, ++ 0xE8,0x16,0xC8,0x14,0x10,0x42,0xE4,0x0E,0x00,0x01,0x80,0x0C,0xC0,0x0C,0x40,0x01, ++ 0x80,0x86,0xC8,0x24,0xD6,0x2C,0x78,0x40,0xC2,0x00,0x82,0x00,0xD0,0x48,0x90,0x4D, ++ 0x1F,0x8C,0x54,0xFA,0x58,0xFA,0xC7,0x93,0xC0,0xDB,0x18,0xD2,0x80,0x16,0xD0,0x40, ++ 0xCC,0x2C,0x18,0x44,0xE7,0x20,0x93,0x25,0x60,0x29,0x90,0x06,0x3B,0x4F,0xE3,0x68, ++ 0x90,0x6D,0x6F,0x71,0x92,0x06,0x38,0xF7,0x87,0x3D,0xE8,0x85,0xA8,0xC5,0x2F,0x01, ++ 0x40,0xAA,0xFF,0x03,0x81,0x04,0x00,0x5F,0x07,0x31,0x48,0xA2,0x1A,0x42,0xC3,0x00, ++ 0x0C,0xC9,0x09,0x48,0xC0,0x30,0x3A,0x11,0xF8,0xBA,0x07,0x21,0xF0,0x82,0x41,0x51, ++ 0xD0,0x0E,0x20,0x51,0x00,0x0F,0xC0,0x51,0x96,0x25,0x00,0x19,0x04,0x00,0x14,0x22, ++ 0xE8,0x06,0x30,0x22,0x37,0x02,0xC1,0xF9,0xC0,0x89,0x0C,0xF1,0x1F,0x42,0x0A,0xF9, ++ 0x88,0x89,0x84,0x27,0xD0,0xAF,0xCB,0x00,0x90,0x05,0x40,0x51,0xD0,0x06,0x00,0x51, ++ 0x4C,0x1A,0x17,0x42,0xE8,0x06,0x30,0x42,0x05,0xBC,0x03,0x84,0xE7,0x68,0x93,0x6D, ++ 0xC5,0x04,0x10,0x42,0xC7,0x86,0xEE,0xC5,0xAC,0x85,0x87,0x3D,0x00,0xF9,0x87,0x0C, ++ 0x00,0x01,0x80,0x04,0x81,0x14,0x18,0x39,0x09,0xD8,0x24,0x39,0x57,0xBA,0x1E,0x22, ++ 0x04,0x08,0xC2,0x48,0xC0,0x68,0x0E,0xE1,0xF2,0x4A,0xE3,0x00,0x92,0x05,0x40,0x31, ++ 0xD8,0xB6,0x07,0x01,0x80,0x24,0x00,0x01,0x38,0x01,0x28,0x01,0x30,0xF9,0xCF,0x24, ++ 0x12,0x51,0x18,0x8A,0x54,0x6A,0xC6,0x48,0x54,0x72,0xC6,0x50,0x90,0x34,0x08,0x01, ++ 0x20,0x01,0xF8,0xA2,0x60,0xA1,0xE8,0x0E,0xE1,0xF8,0x93,0xFD,0xC0,0x00,0x91,0x05, ++ 0x10,0x62,0xED,0x06,0x35,0x2A,0x11,0xA2,0xD1,0x06,0x30,0x32,0xE2,0x90,0xE4,0x48, ++ 0x90,0x4D,0x4E,0x29,0x99,0x66,0x6F,0xE1,0xED,0x16,0x50,0xFA,0x0C,0x01,0xA8,0x8B, ++ 0x08,0x29,0x80,0x27,0xD0,0x2F,0x91,0x0D,0xD0,0x40,0x83,0x71,0x40,0xE1,0xC0,0x6E, ++ 0xD0,0x80,0x83,0x71,0x40,0xE1,0xC0,0x4E,0x68,0xE1,0xE9,0x3E,0x78,0x21,0xE8,0x2E, ++ 0x50,0xA2,0x05,0x01,0x85,0x83,0x40,0x92,0x10,0xD1,0x87,0x13,0xC4,0x14,0x10,0x42, ++ 0xD0,0x06,0x88,0x14,0xC5,0x0C,0x10,0x82,0xE8,0x06,0xB0,0x0C,0xC5,0x04,0x10,0x42, ++ 0xD0,0x06,0xA8,0x04,0x6D,0x6A,0x75,0x7A,0xC0,0x34,0x18,0x01,0x48,0x01,0xE8,0xBE, ++ 0x14,0x01,0xF0,0x12,0x10,0x52,0xDC,0x76,0x61,0x2A,0xC5,0x23,0x60,0x01,0x80,0x16, ++ 0xD0,0x90,0x02,0x14,0x01,0xC7,0x50,0xE1,0xD6,0xB6,0x78,0x60,0xC3,0x20,0x83,0x20, ++ 0xD8,0x90,0x00,0x14,0x00,0x87,0x50,0x01,0xE8,0x76,0x10,0x09,0x00,0x14,0x00,0x5F, ++ 0x14,0x01,0xF0,0x12,0x10,0x52,0xE4,0x16,0xD0,0x90,0x02,0x14,0x00,0x27,0x50,0x01, ++ 0xD0,0x16,0x10,0x01,0x18,0x92,0x06,0x14,0xE2,0x00,0xE4,0xD8,0x90,0xDD,0x5E,0x29, ++ 0x98,0xA6,0xC6,0x24,0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x44,0x71,0x98,0x16, ++ 0x20,0x01,0x00,0x01,0x08,0x01,0x10,0x01,0x94,0x1C,0x50,0x82,0x04,0x18,0xC3,0xD0, ++ 0x5E,0x82,0xC4,0xA8,0x30,0x72,0x19,0x01,0x15,0x01,0xF0,0x52,0xC0,0x80,0x90,0x05, ++ 0xE0,0x48,0x92,0x4D,0xFD,0x1C,0x10,0xD2,0xE8,0x06,0x90,0x1C,0xAA,0x51,0xE0,0xD8, ++ 0x90,0xDD,0x5E,0x71,0x98,0x86,0x87,0x27,0xC8,0x9F,0x95,0x2D,0xC5,0x14,0x10,0x42, ++ 0xD0,0x06,0xA8,0x14,0x00,0x01,0x80,0x24,0x68,0x01,0xE8,0xDE,0x3F,0x01,0xF8,0xBA, ++ 0x10,0x7A,0xDD,0x96,0x60,0x01,0x80,0x0E,0x60,0x21,0x88,0x16,0xD9,0xC0,0x03,0x84, ++ 0x00,0xB7,0x08,0x19,0xC0,0x1C,0x80,0x27,0xCD,0xDF,0x14,0x42,0xD7,0x86,0x78,0x40, ++ 0xCA,0x00,0x82,0x00,0xD1,0xC0,0x01,0x84,0x00,0x57,0x78,0x01,0xE8,0x46,0x00,0x09, ++ 0x00,0x84,0x01,0x2F,0x01,0x01,0xF0,0x82,0x10,0x42,0xE5,0x0E,0xD9,0x00,0x02,0x84, ++ 0xB0,0x51,0xC0,0x24,0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x46,0x71,0x98,0x9E, ++ 0xE7,0x20,0x93,0x25,0x65,0x29,0x98,0x66,0x43,0x2A,0x4B,0x32,0xC0,0x03,0xC0,0x4B, ++ 0x33,0x22,0x58,0x4A,0x50,0x4A,0x1B,0x62,0x88,0xB6,0x01,0x01,0x4A,0x1A,0x03,0x20, ++ 0xC3,0x08,0x63,0x22,0xCB,0x60,0x68,0x1A,0xAA,0x51,0xC8,0x68,0x31,0xF9,0x0C,0xB0, ++ 0xC8,0x78,0x34,0x01,0xF8,0xF2,0x3D,0x01,0xFD,0x7A,0x17,0xF2,0xD0,0x3E,0x28,0x01, ++ 0xF8,0x2A,0x6B,0xA1,0xE8,0x1E,0x78,0x79,0xEB,0x0E,0x00,0x68,0x02,0x2C,0x61,0xD2, ++ 0xA0,0x51,0xC8,0x60,0xC4,0x70,0xC6,0x68,0x0B,0x01,0xF0,0x4A,0x2B,0x01,0xF8,0xAA, ++ 0x10,0x4A,0xD5,0x66,0x0B,0x01,0xF0,0x0A,0x48,0xA1,0xE8,0x46,0x68,0x79,0xE8,0x36, ++ 0x7B,0x70,0xC6,0xA8,0x83,0x68,0x03,0x70,0xCB,0x68,0xC5,0x48,0x02,0x0C,0xE1,0x00, ++ 0x90,0x05,0x46,0x29,0x9C,0x56,0x36,0xFF,0x47,0x01,0x80,0xE6,0x22,0x01,0x40,0x3A, ++ 0x00,0x08,0xC3,0x68,0x41,0x3A,0xC2,0x70,0x40,0x32,0x82,0x51,0xC4,0x40,0x09,0xF9, ++ 0x0B,0x48,0xC0,0x78,0x10,0x01,0x08,0x01,0xF2,0xD2,0xF5,0x0A,0x10,0x52,0xD4,0x6E, ++ 0x01,0x01,0xF0,0x82,0x81,0x2C,0x40,0x41,0xE8,0x46,0x48,0x79,0xEC,0x36,0x00,0x00, ++ 0x08,0x29,0x80,0x27,0xC8,0xEF,0xC8,0x2C,0xC1,0x00,0x02,0x84,0x40,0xD2,0x81,0x51, ++ 0xC1,0x40,0x49,0xD2,0xC0,0x48,0x1B,0x01,0x17,0x01,0xF0,0xDA,0xF4,0x52,0x14,0x9A, ++ 0xD0,0x3E,0x08,0x01,0xF1,0x0A,0x4A,0x41,0xE8,0x1E,0x50,0x79,0xEA,0x0E,0x00,0x48, ++ 0x03,0x0C,0xE0,0x20,0x90,0x25,0x67,0x29,0x9B,0x4E,0x36,0x2F,0xA9,0xC5,0x47,0x52, ++ 0x17,0x09,0x80,0x01,0xC0,0x0B,0x18,0x8A,0x81,0x0B,0x68,0x3A,0x79,0x22,0x31,0x62, ++ 0xA4,0x01,0x06,0x27,0xBB,0xFF,0xEF,0xFF,0x48,0x4A,0x41,0x43,0xE0,0x00,0x02,0x43, ++ 0x40,0x42,0xC1,0x03,0x40,0x01,0x80,0x0E,0x05,0xC1,0xB0,0x43,0x40,0xF2,0x80,0x1F, ++ 0xE9,0xE7,0x50,0x2A,0x48,0xEA,0x40,0xE2,0x86,0x1F,0xC8,0x3F,0xB9,0xFF,0xEF,0x7F, ++ 0x01,0x11,0x88,0x03,0x50,0x02,0x49,0xC2,0x40,0xC2,0x80,0x1F,0xD8,0x37,0x55,0xF2, ++ 0x48,0xAA,0x40,0xB2,0x85,0x1F,0xF8,0xE7,0xC8,0x03,0x43,0x01,0x83,0x16,0xC8,0x03, ++ 0x40,0x11,0x88,0x26,0x48,0xCA,0x40,0x43,0x10,0x09,0x18,0x82,0x00,0x43,0x48,0x72, ++ 0x40,0x72,0x80,0x1F,0xF0,0x47,0x73,0x5A,0xC1,0xCB,0xC1,0x83,0x18,0x42,0x80,0x0E, ++ 0x05,0x01,0xA8,0x43,0xBA,0xFF,0xF7,0xC7,0x41,0x8A,0xC0,0x8B,0x09,0x0C,0xC6,0xCB, ++ 0x11,0x0C,0xC8,0x4B,0x10,0x0C,0x72,0x22,0xB5,0x01,0xE2,0x8B,0x10,0x0C,0x04,0xCF, ++ 0x00,0x48,0x00,0x01,0x00,0x40,0x00,0x01,0x00,0xE0,0x00,0x01,0x08,0x40,0x00,0x01, ++ 0x18,0x10,0x00,0x00,0x48,0xE0,0x06,0x00,0x50,0xA0,0x02,0x00,0x50,0x50,0x02,0x00, ++ 0x00,0xA0,0x00,0x01,0x00,0x20,0x00,0x01,0x80,0xC0,0x04,0x01,0xF8,0x00,0x06,0x42, ++ 0x70,0x40,0x04,0x01,0x48,0xA2,0x40,0x4C,0x10,0x0C,0x4E,0xA2,0x40,0x4B,0x18,0x0C, ++ 0xA2,0x48,0x18,0x0C,0xEC,0x4B,0x1D,0x0C,0xBA,0xFF,0xEF,0x57,0x05,0x11,0xA0,0x83, ++ 0x32,0x8A,0xC9,0x01,0x40,0x72,0x80,0x1F,0xE9,0x9F,0x31,0x8A,0x12,0x09,0xC8,0x01, ++ 0x40,0x5A,0x58,0x62,0x80,0x17,0xE8,0xD7,0xBC,0xFF,0xDF,0x97,0x32,0x8A,0xC9,0x01, ++ 0x40,0x3A,0x80,0x0F,0xF0,0xDF,0x82,0x07,0xDF,0x0F,0xBA,0xFF,0xE3,0xE7,0xCE,0x03, ++ 0x40,0x31,0x80,0x06,0x3F,0xB7,0xEB,0xC5,0x00,0x60,0x00,0x01,0x00,0xA0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x30,0x48,0x00,0x00,0xA8,0x85,0x33,0x22,0xF0,0x03,0x87,0x07, ++ 0xF2,0x2F,0x46,0x7A,0x2C,0x01,0x00,0x2B,0xB6,0x2B,0x05,0x21,0xAF,0x2A,0xB8,0xFF, ++ 0xE5,0xE7,0xA1,0x01,0xCA,0x03,0x33,0x08,0x42,0x52,0x72,0x48,0x1C,0x0B,0x5C,0x0B, ++ 0x02,0x48,0x1A,0x0B,0x0B,0x2B,0xCE,0x0B,0x30,0x48,0xA8,0x16,0x0E,0x09,0x04,0x0B, ++ 0x1B,0x2B,0xE8,0x85,0xAD,0x85,0x87,0xAD,0x42,0x12,0xC2,0x01,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x52,0x02,0x4A,0x0A,0x40,0x0A,0x82,0x0F,0xCA,0xB7,0x40,0x0A, ++ 0x71,0xFA,0xC1,0x80,0x81,0xA4,0x41,0xEA,0xB6,0xE1,0x81,0x01,0x83,0x9C,0x01,0x47, ++ 0x47,0xD2,0xB9,0xFF,0xF9,0x4F,0x66,0xCA,0x52,0x03,0x83,0x01,0xE7,0x03,0x40,0x79, ++ 0x81,0x06,0x31,0x12,0x48,0xB2,0x01,0x01,0x58,0x9A,0x81,0x07,0xF9,0x5F,0x36,0x12, ++ 0x48,0x9A,0x01,0x09,0x58,0x82,0x81,0x07,0xFB,0x2F,0x56,0x03,0x80,0x01,0xE2,0x03, ++ 0x40,0x59,0x8D,0x7E,0xC1,0xA4,0x31,0x8A,0x13,0x01,0xD8,0x1B,0xDB,0x2B,0x19,0x5A, ++ 0x40,0x6C,0x40,0x3C,0xD8,0x68,0x07,0x2C,0xE4,0x00,0xE4,0x48,0xE4,0x90,0x92,0x95, ++ 0x17,0xD2,0x9C,0xAE,0x52,0x03,0x83,0x01,0xE5,0x03,0x40,0x59,0x81,0x2E,0x50,0x12, ++ 0x49,0x12,0x41,0x1A,0x58,0x0D,0x80,0x0F,0xC1,0x07,0xEC,0xA4,0x30,0xA2,0x39,0x01, ++ 0x01,0x01,0xF0,0x42,0x0A,0x99,0x18,0x42,0x08,0x51,0x80,0x1F,0xF9,0x8F,0x07,0x44, ++ 0x01,0x01,0xF0,0x02,0x0A,0x99,0x18,0x42,0x08,0x51,0x80,0x1F,0xF9,0x4F,0x07,0x04, ++ 0xE5,0x68,0xE5,0x20,0xE7,0xF8,0x93,0xFD,0x7F,0x29,0x98,0x4E,0x68,0xB2,0x60,0xA2, ++ 0xA0,0xF1,0x3D,0x01,0x01,0x01,0xF0,0x42,0x08,0x51,0x08,0x00,0x86,0x1F,0xF8,0xC7, ++ 0x00,0x44,0x01,0x01,0xF0,0x02,0x09,0x51,0x08,0x00,0x80,0x1F,0xF9,0x8F,0x06,0x04, ++ 0xE5,0x68,0xE5,0x20,0xE7,0xF8,0x93,0xFD,0x7F,0x29,0x98,0x5E,0x40,0x0D,0x80,0x07, ++ 0xD9,0xDF,0xC1,0x9C,0xC8,0x03,0x42,0x31,0x81,0x96,0x84,0xAD,0xE8,0x85,0x07,0x00, ++ 0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x80,0xC0,0x04,0x01,0x00,0xE0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x48,0xE0,0x06,0x00,0x58,0x30,0x03,0x01,0x48,0xFA,0xFF,0x53, ++ 0x84,0x13,0xF8,0x53,0x80,0x13,0x32,0x52,0x96,0x01,0xCE,0x93,0x80,0x13,0xCC,0x4B, ++ 0x83,0x0B,0x3E,0x82,0xA8,0xC5,0xF7,0x34,0x37,0x22,0x40,0xC2,0xFD,0x03,0x16,0x02, ++ 0xC9,0xFE,0x01,0x21,0x6B,0xB2,0x1F,0x02,0xCB,0x28,0x02,0x99,0x09,0x00,0xC2,0x40, ++ 0x2A,0xA1,0xF8,0x2A,0x3E,0xB1,0xF8,0x3A,0x48,0x09,0x88,0x1E,0x0F,0xF9,0x8F,0x09, ++ 0xD8,0x48,0x92,0x6D,0x50,0x09,0x88,0x1E,0x0A,0xC9,0x08,0x48,0xD8,0x48,0x96,0x7D, ++ 0xCE,0x0B,0xCC,0x13,0x0A,0x48,0x00,0x90,0x18,0x8A,0x80,0xCB,0x8A,0x48,0x81,0xCB, ++ 0x8C,0xC8,0x81,0xCB,0x39,0xD0,0x09,0x48,0x78,0x90,0x18,0x8A,0x86,0xCB,0xE6,0xD8, ++ 0xE0,0xE8,0x5A,0x04,0x08,0xA1,0x80,0x1F,0xF8,0x4F,0x83,0x51,0x97,0x05,0x46,0xF9, ++ 0x97,0x56,0x58,0x02,0xE8,0xCA,0x30,0x52,0x94,0x51,0x10,0x12,0x91,0x16,0x80,0x43, ++ 0xA8,0xC2,0x00,0x1F,0x80,0x4B,0x01,0x0F,0x01,0xF9,0x87,0x43,0xC2,0x83,0xE9,0x00, ++ 0x87,0x83,0xE9,0xC5,0xAC,0x85,0x87,0x2D,0x36,0x01,0x00,0xBD,0x40,0x03,0x80,0x14, ++ 0x44,0x92,0xFE,0x1B,0x10,0x09,0x00,0x01,0x4E,0xA2,0x66,0xAA,0xC5,0x6B,0x68,0x59, ++ 0x82,0x16,0xE0,0x00,0x17,0x02,0x9D,0xCE,0x00,0xF9,0x87,0x43,0x58,0x01,0x80,0xBE, ++ 0x30,0x01,0x48,0x15,0x03,0x01,0x20,0x99,0x5B,0x4A,0x0E,0x20,0x01,0x77,0x28,0x21, ++ 0x1F,0x2A,0xC2,0x68,0xC9,0x68,0xD1,0x6B,0x68,0x09,0x88,0x2E,0x83,0x43,0xE0,0xB0, ++ 0x92,0xB5,0xE7,0x48,0x70,0x09,0x80,0x1E,0xE6,0x00,0x92,0x05,0x17,0x82,0x9C,0x76, ++ 0x73,0x01,0x80,0x16,0x60,0x0A,0x6E,0x15,0x3D,0x01,0x40,0xE2,0x80,0x01,0x87,0x1C, ++ 0x00,0x0F,0x79,0x01,0x88,0x9E,0x50,0x0D,0x90,0x04,0x10,0x01,0xC1,0x43,0x31,0x1A, ++ 0x37,0x8A,0xB8,0xFF,0xFB,0xBF,0xE3,0x68,0xC4,0x1C,0xC0,0x03,0x4E,0x00,0x0E,0x00, ++ 0x1B,0x82,0x89,0x03,0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x4F,0x50,0x0D, ++ 0x90,0x04,0x10,0x01,0xC1,0x43,0x31,0x1A,0x37,0x8A,0xB8,0xFF,0xFB,0x1F,0xE3,0x68, ++ 0xEB,0x20,0xE3,0xF8,0x95,0xFD,0x17,0xBA,0x98,0xDE,0xC6,0x1C,0x1C,0x01,0xC4,0x03, ++ 0x48,0x08,0x4E,0x01,0x80,0x9E,0x70,0x01,0x81,0x3E,0x80,0x03,0xC0,0x1C,0xC8,0x03, ++ 0x85,0x03,0x03,0x59,0x85,0x03,0xE5,0x20,0x01,0x3F,0x80,0x03,0xC0,0x1C,0xC8,0x03, ++ 0x83,0x03,0x8B,0x1B,0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x27,0x70,0x09, ++ 0xCD,0x16,0x00,0x59,0x83,0x03,0xE1,0x20,0x37,0x02,0xB9,0xFF,0xFC,0x7F,0x41,0xEA, ++ 0x42,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x4A,0xDA,0x44,0x43,0x1A,0xC2,0x00,0x43, ++ 0x61,0xD2,0x44,0x03,0x42,0x00,0x02,0x00,0x07,0x03,0x01,0xF9,0x80,0x89,0x84,0x1F, ++ 0xE9,0x6F,0x46,0x03,0x08,0x09,0x18,0x42,0x00,0x03,0x81,0x2D,0xEF,0x85,0xAF,0xFD, ++ 0x80,0x0D,0xFC,0x54,0x30,0x32,0x30,0x62,0x6F,0x42,0xAC,0x01,0x50,0x09,0x88,0x4E, ++ 0x00,0x0F,0x80,0x0F,0xC1,0x6F,0xC0,0x43,0x37,0x00,0xAA,0xD6,0xC5,0x43,0x09,0xF9, ++ 0x01,0x42,0x80,0x43,0x04,0x09,0x30,0x22,0x51,0x3A,0x04,0x8F,0x60,0x01,0xC1,0x2E, ++ 0xF7,0x00,0x0B,0x01,0x1A,0x42,0x08,0x83,0x30,0x0A,0x01,0x17,0x02,0xF9,0x0F,0x83, ++ 0x08,0x01,0x19,0x01,0x08,0x9B,0x04,0x01,0x00,0x4F,0x78,0x01,0x88,0x16,0x18,0x01, ++ 0x00,0x9B,0x06,0x17,0xC6,0x9B,0x01,0x9B,0xCA,0xB0,0xE7,0x00,0x94,0x05,0x14,0x42, ++ 0x9B,0x9E,0x37,0x02,0x40,0x01,0x80,0x26,0x04,0xA1,0x00,0x83,0x04,0x01,0x30,0x22, ++ 0x00,0x0F,0x00,0x21,0x03,0x83,0xD4,0x00,0x92,0x25,0x44,0x83,0x08,0x01,0x1C,0x42, ++ 0x01,0x83,0xC2,0x43,0x37,0x00,0xAA,0xE6,0xC5,0x43,0x09,0xF9,0x01,0x42,0x80,0x43, ++ 0x66,0x01,0x88,0x5E,0xC0,0x24,0x40,0x09,0x88,0x7E,0x05,0x01,0x02,0x83,0x44,0x83, ++ 0x08,0x01,0x1C,0x42,0x05,0x83,0x3A,0x47,0xAC,0x9D,0x87,0x1D,0x20,0x01,0x00,0x01, ++ 0x80,0x0C,0x70,0x15,0x44,0xEA,0xF2,0x03,0xEE,0x00,0x92,0x3D,0x6F,0xDA,0xAA,0x01, ++ 0x00,0xAF,0x81,0x07,0xF9,0xAF,0xC5,0x43,0x30,0x00,0xA2,0x1E,0x44,0xBA,0xF2,0x03, ++ 0x17,0xC2,0x9D,0xB6,0x44,0xAA,0xF2,0x03,0x10,0xC2,0x9D,0x06,0x21,0x11,0xC0,0x43, ++ 0x08,0xF9,0x05,0x42,0x82,0x43,0x41,0xC2,0x46,0x0B,0x14,0x79,0x00,0x8A,0x48,0x09, ++ 0x88,0x9E,0x08,0x01,0x0E,0x0B,0x44,0x0B,0x83,0x8B,0xE1,0xB0,0xE7,0x20,0x93,0x25, ++ 0x60,0x11,0x88,0x56,0x30,0x5A,0xD3,0xCB,0xD4,0x1C,0x10,0x8A,0x8A,0x2E,0xD0,0xCB, ++ 0xD4,0x24,0x10,0x8A,0x88,0x0E,0x08,0x09,0x8F,0x0C,0x08,0x01,0x08,0x0B,0x0A,0x01, ++ 0x08,0x0B,0x0C,0x81,0x02,0x0B,0x44,0x0B,0x10,0x01,0x1C,0x8A,0x00,0x0B,0x62,0x11, ++ 0x88,0x4E,0xC6,0x0C,0x39,0x0F,0x4B,0xEA,0x60,0x54,0x80,0x13,0x12,0x01,0x80,0x13, ++ 0xE4,0x4B,0x86,0x0B,0x4A,0x0A,0x8A,0x01,0x5E,0x53,0x84,0x13,0x58,0x53,0x8A,0x13, ++ 0x12,0xA9,0x88,0x13,0x14,0x19,0x88,0x13,0x4E,0x53,0x8E,0x13,0x48,0x53,0x94,0x13, ++ 0x4A,0x4B,0x92,0x0B,0x0C,0x31,0x90,0x0B,0x3F,0x82,0xAB,0x85,0x80,0x4D,0x34,0x22, ++ 0x30,0x01,0x00,0x01,0x80,0x2C,0x38,0x01,0x48,0x62,0xD9,0x43,0xDA,0x4B,0x1A,0x42, ++ 0x81,0x14,0x40,0x5A,0x80,0x71,0x80,0x24,0xC0,0x71,0x80,0x1C,0x60,0x09,0x80,0x0E, ++ 0x60,0x29,0x88,0x7E,0x60,0x09,0x88,0x26,0x73,0x6A,0xE1,0x80,0x81,0x2C,0x78,0x6A, ++ 0x01,0x27,0x70,0x6A,0xE0,0x80,0x83,0x2C,0x79,0x52,0xF9,0xC1,0x47,0x35,0xB8,0xFF, ++ 0xF0,0xEF,0x01,0x3F,0x60,0x21,0x88,0x2E,0x70,0x42,0x41,0x35,0xBD,0xFF,0xFF,0xDF, ++ 0x7B,0x22,0xB9,0x11,0x6F,0xCA,0xA8,0x01,0xC5,0x43,0x09,0xF9,0x01,0x42,0x80,0x43, ++ 0xC1,0x43,0x09,0x01,0x19,0x42,0x80,0x43,0x42,0xD2,0x40,0x0B,0x10,0x01,0x1A,0x8A, ++ 0x00,0x0B,0x42,0xCA,0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x48,0xBA,0x40,0x43, ++ 0x10,0x09,0x18,0x82,0x00,0x43,0x08,0x09,0x07,0x01,0xBC,0xFF,0xF8,0xAF,0x42,0x09, ++ 0x88,0x5E,0x62,0x21,0x88,0x56,0x12,0x09,0x91,0x04,0x30,0x82,0x18,0x01,0xC8,0x14, ++ 0xBF,0xFF,0xF7,0xAF,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x59,0x40,0x35,0x30,0x9A, ++ 0xBF,0xFF,0xF7,0x6F,0x10,0x09,0x90,0x04,0x10,0x01,0x00,0xCF,0x00,0xE0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x80,0x00,0x06,0x01,0x00,0xF8,0x07,0x00,0x80,0x30,0x02,0x01, ++ 0x30,0x04,0x05,0x08,0x00,0x00,0x06,0x42,0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42, ++ 0x18,0x60,0x05,0x01,0x70,0x70,0x06,0x01,0x50,0x20,0x07,0x01,0x68,0x60,0x02,0x01, ++ 0x09,0x29,0x30,0xC2,0x37,0x9A,0xB8,0xFF,0xF0,0x57,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x0E,0x71,0x40,0x0A,0x37,0x9A,0xB8,0xFF,0xF0,0x17,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x29,0x30,0x9A,0xC7,0x24,0xB8,0xFF,0xF0,0xD7,0x15,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x29,0x18,0x09,0xC7,0x1C,0xB8,0xFF,0xF1,0x97,0x05,0x9F,0x60,0x09,0x80,0x0E, ++ 0x61,0x29,0x88,0x7E,0x10,0x11,0x90,0x04,0x11,0x09,0x30,0x82,0x18,0x01,0xC8,0x14, ++ 0xBD,0xFF,0xF7,0x2F,0x10,0x11,0x90,0x04,0x10,0x01,0x30,0x9A,0xC8,0x14,0xC0,0x2C, ++ 0xBC,0xFF,0xF7,0xEF,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x21,0x40,0x35,0x30,0x9A, ++ 0xBC,0xFF,0xF7,0xAF,0x10,0x09,0x90,0x04,0x11,0x01,0x08,0x31,0x30,0xC2,0x31,0x9A, ++ 0xBC,0xFF,0xF7,0x6F,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x29,0x30,0x9A,0xC0,0x24, ++ 0xBC,0xFF,0xF7,0x2F,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x29,0x18,0x09,0xC0,0x1C, ++ 0xBB,0xFF,0xF7,0xEF,0xC6,0x43,0x09,0xF9,0x01,0x42,0x80,0x43,0x40,0xDA,0x44,0x0B, ++ 0x42,0x48,0x02,0x48,0x04,0x0B,0x40,0xD2,0x0A,0x01,0x0F,0x0B,0x0C,0x01,0x00,0x0B, ++ 0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x87,0x4D,0xE8,0x85,0xAC,0x85,0x63,0xAA, ++ 0xC8,0x03,0x43,0x09,0x83,0x16,0xC8,0x03,0x40,0x29,0x88,0x86,0x46,0x8A,0xC4,0x01, ++ 0x82,0x1F,0xC8,0xDF,0x69,0x82,0xC4,0x43,0x40,0x11,0x98,0x2E,0xCF,0x03,0xBB,0xFF, ++ 0xF8,0x67,0x00,0x01,0x83,0x43,0xE9,0x85,0xE1,0x00,0x82,0x43,0xEB,0x85,0xCB,0x03, ++ 0x40,0x21,0x88,0x26,0xB8,0xFF,0xFF,0x0F,0x03,0x19,0x88,0x03,0xEB,0x85,0xCB,0x03, ++ 0x47,0x19,0x80,0xDE,0xC8,0x03,0x43,0x31,0x84,0xC6,0x47,0x12,0xC4,0x01,0xFE,0x03, ++ 0x40,0x01,0x88,0x3E,0x41,0xFA,0x83,0x01,0xD0,0x0B,0x48,0x31,0x9C,0x76,0xC7,0x03, ++ 0x37,0x00,0xA8,0x5E,0x44,0xDA,0xC3,0x01,0xE8,0x03,0x44,0x01,0x8F,0x36,0xBF,0xFF, ++ 0xEB,0xCF,0xEC,0x85,0xA8,0xC5,0x27,0x01,0x30,0x1A,0x00,0x09,0x4B,0xAA,0x6B,0xBA, ++ 0x30,0x01,0x59,0x51,0x80,0xE6,0xE1,0x4E,0x79,0xAA,0xC3,0xD3,0x85,0x1F,0xE8,0xFF, ++ 0x61,0x52,0x20,0x09,0x39,0x61,0x62,0x52,0x71,0x61,0x62,0x92,0x40,0x6A,0x13,0x31, ++ 0xC2,0x01,0x56,0x03,0x80,0x01,0x5A,0xC9,0x80,0xAE,0xE1,0x4E,0x59,0x59,0x80,0x56, ++ 0x59,0x61,0x80,0x66,0x59,0x69,0x88,0xBE,0x02,0x29,0x88,0x43,0x21,0x09,0x00,0x9F, ++ 0x59,0xD1,0x80,0x6E,0x59,0x01,0x89,0x7E,0x88,0x53,0x22,0x09,0x08,0x59,0xA5,0x0B, ++ 0x00,0x57,0x01,0x39,0x89,0x43,0x02,0x3F,0x86,0x07,0xE8,0xA7,0x00,0x27,0x19,0x12, ++ 0x81,0xD3,0x01,0x0F,0x00,0x41,0x18,0x12,0x80,0xD3,0x01,0xEF,0x02,0x11,0x88,0x43, ++ 0x20,0x09,0x00,0xCF,0x02,0x01,0x88,0x43,0x41,0x43,0x19,0x82,0x00,0x43,0x01,0x9F, ++ 0x88,0x43,0x22,0x09,0x00,0x87,0x00,0x19,0x88,0x43,0x22,0x09,0x00,0x67,0x00,0x21, ++ 0x88,0x43,0x22,0x09,0x02,0x47,0x88,0x53,0x26,0x09,0x08,0x69,0xA0,0x0B,0x00,0x1F, ++ 0x88,0x53,0x22,0x09,0x08,0x79,0xA7,0x0B,0x60,0x01,0x80,0x66,0x40,0x6A,0x42,0x0B, ++ 0x30,0x48,0xA8,0x2E,0x08,0x81,0x06,0x0B,0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B, ++ 0x45,0x43,0x19,0x82,0x07,0x43,0xE9,0xC5,0xAC,0x8D,0x87,0x15,0x40,0x32,0x82,0x0C, ++ 0x46,0x02,0xC2,0x01,0xDA,0x2B,0xD8,0x33,0x0C,0x01,0xB0,0x0B,0x61,0x02,0xC2,0x0B, ++ 0x10,0xF9,0x05,0x8A,0x81,0x0B,0xC1,0x0B,0x10,0x01,0x19,0x8A,0x81,0x0B,0x49,0xEA, ++ 0x8A,0x01,0x46,0x53,0x18,0x01,0x1A,0xD2,0x01,0x53,0x52,0xAA,0x44,0x8B,0x1A,0x01, ++ 0x1A,0xCA,0x00,0x8B,0x48,0x8A,0x41,0x53,0x18,0x09,0x18,0xD2,0x02,0x53,0x50,0x03, ++ 0x80,0x01,0xE2,0x0B,0x49,0x79,0x87,0xAE,0xE6,0x03,0x40,0x69,0x88,0x16,0x09,0xA9, ++ 0x07,0x91,0xB8,0xFF,0xE8,0x4F,0x47,0x09,0x89,0xDE,0x31,0x42,0x1A,0x82,0x03,0x38, ++ 0x15,0x09,0x90,0xCD,0x90,0x04,0x18,0x01,0xC7,0x0C,0xB8,0xFF,0xE9,0x47,0x44,0x5A, ++ 0x10,0x09,0x90,0x04,0x15,0x01,0x90,0xCD,0x37,0x9A,0xB8,0xFF,0xE8,0x07,0xC4,0x14, ++ 0x15,0x09,0xC8,0x48,0xE8,0x48,0x90,0x04,0x00,0x48,0x12,0x01,0x1F,0x09,0xB8,0xFF, ++ 0xE8,0xB7,0x03,0xF7,0x08,0xA1,0x00,0x91,0xBE,0xFF,0xEF,0x37,0x40,0x09,0x88,0xC6, ++ 0x18,0xAA,0x13,0x09,0x20,0x40,0x63,0x08,0x90,0x04,0x30,0x9A,0xC7,0x0C,0xB8,0xFF, ++ 0xE8,0x37,0x03,0x77,0x08,0xB1,0x00,0x91,0xBD,0xFF,0xEF,0xB7,0x40,0x09,0x88,0x46, ++ 0xC0,0x14,0x10,0x09,0xC8,0x48,0xED,0x48,0x00,0x48,0x32,0x9A,0x97,0x04,0xB8,0xFF, ++ 0xE9,0xB7,0xC2,0x03,0x08,0xF9,0x06,0x42,0x80,0x03,0x41,0x42,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x47,0x32,0x08,0x01,0x08,0x0B,0x0A,0x01,0x02,0x0B,0x44,0x0B, ++ 0x10,0x01,0x1C,0x8A,0x07,0x0B,0xEA,0xF5,0x70,0x00,0x04,0x01,0xF8,0x00,0x06,0x42, ++ 0x80,0x01,0x06,0x42,0x00,0xE0,0x06,0x01,0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x42, ++ 0x00,0xE0,0x07,0x01,0x00,0x00,0x00,0x42,0x50,0x20,0x07,0x01,0x08,0x20,0x02,0x01, ++ 0x52,0x2A,0x44,0x83,0x04,0x83,0x42,0x2A,0xF7,0x0B,0x4C,0xF9,0x94,0x16,0xF0,0x0B, ++ 0xE4,0x48,0xB2,0x0B,0xF0,0x03,0x44,0xC1,0x90,0x0E,0x00,0x01,0x03,0x83,0x3C,0x82, ++ 0x4C,0xFA,0x4B,0x53,0x5C,0xEA,0xE3,0xC3,0x1C,0x12,0x0C,0x53,0x10,0x43,0x02,0x09, ++ 0xB3,0xC3,0x3C,0x82,0xAB,0x85,0x40,0xD2,0x84,0x01,0x42,0x0B,0x10,0x01,0x1C,0x8A, ++ 0x03,0x0B,0x54,0xC2,0x4B,0xAA,0x43,0xC2,0x87,0x1F,0xC0,0x27,0xEF,0x85,0xA8,0xC5, ++ 0x47,0x92,0x83,0x01,0xC3,0x0B,0x70,0xAA,0x30,0x48,0xAC,0x46,0xC2,0x0B,0x10,0x01, ++ 0x18,0x8A,0x80,0x0B,0x44,0x83,0x0B,0x01,0x1B,0x42,0x04,0x83,0xE8,0xC5,0x0F,0x01, ++ 0x0D,0x8B,0x45,0x9B,0x66,0x4A,0x03,0x79,0x01,0x1A,0x30,0x2A,0xAB,0x01,0x69,0x04, ++ 0x50,0x13,0x5B,0x09,0x80,0x6E,0x59,0x29,0x80,0x46,0x58,0x41,0x8B,0xDE,0x93,0x4B, ++ 0x46,0x9B,0x3F,0xD8,0x88,0x16,0x00,0x81,0x07,0x83,0xED,0xC5,0x0B,0x8B,0x4D,0x22, ++ 0x10,0x42,0x8C,0x16,0x07,0x29,0x05,0x83,0x00,0x3F,0xE0,0x92,0x02,0x93,0xE7,0x00, ++ 0x93,0x05,0x2C,0x04,0x40,0x89,0x9A,0x06,0x2A,0x0C,0x43,0xCA,0x40,0x13,0x08,0x41, ++ 0x18,0x52,0x04,0x13,0x44,0x13,0x1C,0x52,0x00,0x13,0x14,0xA1,0x04,0x93,0x45,0x13, ++ 0x1C,0x52,0x04,0x13,0x44,0x13,0x1C,0x52,0x04,0x13,0x44,0x13,0x1C,0x52,0x00,0x13, ++ 0xEA,0xC5,0x5F,0xA2,0xD0,0x7B,0x43,0xDC,0x7B,0x11,0x90,0x56,0x78,0x01,0x88,0x36, ++ 0x42,0x83,0x57,0x82,0x02,0x84,0x40,0x82,0x13,0x03,0x2B,0x0C,0x07,0x1F,0x44,0x83, ++ 0x12,0xD0,0x48,0x62,0xC4,0x80,0x90,0x3D,0x06,0x7C,0x00,0x89,0x11,0x00,0xD0,0xC0, ++ 0x40,0x01,0xC1,0x96,0x97,0xC5,0xBF,0xFF,0xF2,0xAF,0x43,0x42,0x13,0x3A,0x84,0x96, ++ 0x40,0x32,0x82,0x41,0x13,0x3A,0x8C,0x76,0x00,0x09,0x80,0x07,0xC8,0x3F,0x06,0xC1, ++ 0xB2,0x03,0x4D,0x1A,0x00,0x09,0x80,0x43,0x01,0x2F,0x43,0xC2,0x82,0x01,0xCE,0x03, ++ 0x41,0x01,0x88,0x2E,0x46,0xEA,0xC1,0x31,0x10,0x3A,0x8C,0xAE,0x40,0xEA,0x41,0x0B, ++ 0x40,0xCA,0x71,0x50,0x80,0x01,0x82,0x13,0x62,0x50,0x80,0x13,0x54,0x50,0x80,0x13, ++ 0x80,0x0B,0xC6,0x0B,0xC4,0x13,0xC2,0x48,0xC6,0x13,0xC4,0x1B,0xC4,0x90,0xC6,0x48, ++ 0x88,0x29,0x55,0x50,0x8A,0x13,0x88,0x0B,0x00,0x69,0x18,0x00,0xD2,0xC0,0x41,0x81, ++ 0xC3,0x16,0x28,0x04,0x02,0xFF,0x01,0x27,0x06,0x01,0x18,0x02,0x29,0x04,0x03,0xD7, ++ 0x41,0x6A,0xC1,0xC0,0x40,0x19,0xC1,0x1E,0x29,0x04,0x43,0x62,0x11,0x03,0x03,0x97, ++ 0x41,0x4A,0xC1,0x81,0xC1,0xC0,0x41,0x01,0xC3,0x26,0x28,0x04,0x41,0x3A,0xC1,0x01, ++ 0x11,0x03,0x03,0x47,0x00,0x69,0x18,0x00,0xD1,0xC0,0x41,0xB1,0xC3,0x1E,0x29,0x04, ++ 0x00,0x0F,0x79,0xDA,0x10,0xC2,0x85,0xF6,0x40,0xBB,0xA7,0xBA,0x45,0xDA,0xC0,0xD1, ++ 0x10,0x1A,0x8C,0x7E,0x6A,0x04,0x43,0x61,0x8B,0x66,0x50,0x1B,0xE0,0xFA,0x50,0x7A, ++ 0x94,0x01,0x7A,0x01,0x88,0x16,0x00,0x09,0xA8,0x83,0x04,0x1F,0xE0,0xC2,0x40,0x01, ++ 0x8C,0x06,0xA8,0x8B,0x6A,0x04,0xE3,0x00,0x93,0x05,0x2C,0x04,0x40,0x89,0x9A,0x16, ++ 0x06,0x01,0x18,0x02,0x2B,0x04,0xD3,0x43,0xE3,0x00,0x92,0x43,0x05,0x81,0x00,0x83, ++ 0xED,0xC5,0x07,0x8B,0xE8,0xC5,0x07,0x00,0x10,0x00,0x00,0x42,0x00,0xE0,0x00,0x01, ++ 0xF8,0x00,0x06,0x42,0x80,0xC0,0x04,0x01,0x08,0x40,0x00,0x01,0x80,0x01,0x06,0x42, ++ 0xF8,0xFF,0x07,0x00,0x00,0x10,0x00,0x01,0x80,0x30,0x02,0x01,0x88,0x36,0x00,0x00, ++ 0x00,0x20,0x00,0x01,0x00,0xA0,0x00,0x01,0x77,0x81,0xF8,0xFF,0xF8,0x02,0x07,0x00, ++ 0xA8,0x85,0x80,0x07,0xC8,0xBF,0x65,0x32,0xC8,0x03,0x43,0x01,0x80,0x26,0x40,0x31, ++ 0x8F,0xD6,0xBF,0xFF,0xD7,0xFF,0x3B,0xBF,0xBE,0xFF,0xCF,0x07,0x38,0xA7,0x07,0x00, ++ 0x00,0xE0,0x06,0x01,0xAF,0xC5,0x77,0x62,0x03,0x01,0x87,0x83,0x01,0x09,0x80,0x83, ++ 0x0F,0x01,0x81,0x8B,0x05,0x19,0x80,0x83,0x03,0x41,0x89,0x83,0x07,0x69,0x89,0x83, ++ 0x05,0x69,0x88,0x83,0x11,0x02,0x32,0xAA,0xA9,0x01,0x06,0x44,0x04,0xF9,0x87,0x89, ++ 0x20,0x84,0x01,0x09,0x34,0x62,0xE1,0x01,0x93,0x03,0x91,0x03,0x05,0x41,0x90,0x03, ++ 0x17,0x51,0x90,0x13,0x11,0xA1,0x98,0x13,0x98,0x0B,0x0D,0x81,0x99,0x0B,0xA7,0x03, ++ 0x3B,0x01,0xA0,0xBB,0x09,0x71,0x98,0x8B,0x0B,0x29,0x98,0x8B,0x17,0x71,0x98,0x93, ++ 0x99,0x8B,0xA5,0xBB,0xA1,0x83,0x05,0x81,0xA0,0x83,0x07,0x51,0x8F,0x03,0x01,0xB1, ++ 0x8D,0x03,0x8B,0x3B,0x8B,0x3B,0x9F,0x0B,0x05,0x99,0x28,0x84,0x07,0xF9,0x87,0x09, ++ 0x10,0x44,0x01,0xC9,0x0B,0x00,0x12,0x44,0x02,0x19,0x18,0x00,0x0E,0x43,0x43,0x5A, ++ 0x0A,0x43,0x05,0x01,0xB9,0x43,0x31,0x02,0x0D,0x51,0x80,0x11,0x83,0x1F,0xD0,0x17, ++ 0x01,0xB1,0x97,0x43,0x1B,0xF1,0x90,0x5B,0x89,0x7B,0x33,0x02,0x82,0x01,0xB2,0x3B, ++ 0xB8,0x3B,0x08,0xC1,0xB8,0x0B,0x0A,0x51,0xBE,0x0B,0x14,0x41,0x31,0x0A,0x88,0x01, ++ 0x0F,0x54,0x12,0xF9,0x94,0x99,0x0A,0x54,0x16,0xC1,0xBE,0x13,0x10,0x41,0x81,0x53, ++ 0x12,0x11,0x87,0x53,0x80,0x5B,0x14,0x51,0x91,0x13,0x12,0x41,0x93,0x13,0x14,0x21, ++ 0x92,0x13,0x16,0xA9,0x08,0x14,0x16,0x71,0x9A,0x13,0x10,0x69,0xA0,0x13,0x10,0x21, ++ 0xA6,0x13,0x12,0x41,0x10,0x14,0x12,0x31,0xBF,0x93,0x37,0xBC,0xB0,0x3B,0x1C,0x21, ++ 0x33,0x12,0x90,0x01,0x90,0x9B,0x1C,0x31,0x96,0x9B,0x12,0x99,0x08,0x94,0x11,0xA1, ++ 0x80,0x53,0x16,0x51,0x8E,0x53,0xB0,0x3B,0x12,0x21,0x8C,0x53,0x53,0x42,0x05,0x54, ++ 0x14,0x09,0x88,0x53,0x10,0x51,0x90,0x53,0x17,0x11,0xA0,0x13,0x08,0x21,0xA8,0x0B, ++ 0x0A,0xC1,0xAB,0x0B,0xA8,0x0B,0x1C,0x01,0x33,0x0A,0xC8,0x01,0xA0,0x5B,0xAE,0x5B, ++ 0x22,0xF1,0x88,0x01,0xBA,0x63,0xB8,0x63,0x24,0xE1,0xB9,0x63,0x26,0x41,0xB8,0x63, ++ 0x80,0x13,0x08,0xB1,0x80,0x0B,0x0A,0x19,0x84,0x0B,0x4C,0xD2,0x00,0x0B,0x92,0x1B, ++ 0x4C,0xCA,0xC4,0x01,0x38,0x0B,0x88,0x91,0x3E,0x0B,0x8A,0xE1,0x38,0x0B,0x0C,0xE1, ++ 0x40,0xB2,0x84,0x1F,0xCC,0xBF,0x47,0xAA,0x09,0xE1,0xC0,0xC1,0x87,0x1F,0xC8,0x97, ++ 0x4C,0x8A,0x44,0x9A,0xCE,0x11,0x03,0x0B,0xCC,0x71,0x00,0x0B,0x88,0xA1,0x08,0x0B, ++ 0x8A,0xA1,0x08,0x0B,0xCA,0xE1,0x01,0x0B,0xC8,0xC1,0x01,0x0B,0x8C,0x61,0x0D,0x0B, ++ 0xCA,0x81,0x15,0x0B,0xF8,0x48,0x10,0x0B,0xFE,0x48,0x08,0x0B,0xE9,0xC5,0xAF,0x85, ++ 0x0C,0x01,0x60,0x0A,0x47,0x02,0xA4,0x61,0xF8,0x1B,0x06,0x77,0x02,0x21,0x19,0x42, ++ 0xCB,0x28,0x00,0x99,0x12,0x79,0x08,0x00,0xC4,0x40,0x89,0x13,0x16,0x01,0x88,0x13, ++ 0x94,0x13,0x10,0x14,0x12,0x14,0xE6,0x48,0x94,0x4D,0x16,0x5A,0xC0,0x76,0x07,0x01, ++ 0x13,0xF9,0x2F,0x89,0x08,0x68,0x03,0x37,0x00,0x08,0xCA,0x48,0xCC,0x48,0xAA,0x53, ++ 0xAA,0x53,0xE6,0x00,0x94,0x05,0x16,0x1A,0xC1,0xB6,0xEF,0x85,0xA3,0x85,0x51,0x72, ++ 0x90,0x01,0x0E,0x01,0x26,0x8C,0xD0,0x01,0xBC,0x8B,0xB8,0x8B,0x36,0x9A,0x98,0x01, ++ 0x8A,0xCB,0x0C,0xCC,0x9E,0xCB,0x88,0xCB,0x2C,0x09,0xB0,0xAB,0xA8,0x8B,0x34,0xA2, ++ 0xA1,0x01,0xCD,0x1B,0xB0,0x9B,0x36,0x9A,0x9A,0x01,0xA9,0xCB,0x9A,0x01,0xA9,0xEB, ++ 0xA8,0xCB,0xA8,0xAB,0x28,0x41,0x89,0xAB,0x8B,0x0B,0x57,0x32,0x88,0x8B,0x46,0x09, ++ 0x8C,0x16,0xA8,0xCB,0xE5,0x85,0x39,0x97,0xE3,0x85,0x39,0x82,0x0B,0x08,0x42,0x12, ++ 0x41,0x13,0x18,0x01,0x04,0xD2,0x90,0x41,0x04,0x13,0x10,0xD0,0x1A,0x8A,0x08,0x0B, ++ 0x40,0x0B,0x42,0x0B,0x14,0x41,0x18,0x8A,0x00,0x0B,0x08,0x01,0x03,0x0B,0x3C,0x82, ++ 0xAA,0x85,0x40,0xD2,0x40,0x0B,0x30,0x48,0xAE,0x2E,0x08,0x81,0x02,0x0B,0x08,0x81, ++ 0x00,0x0B,0x08,0x81,0x02,0x0B,0x48,0xAA,0x8C,0x01,0x46,0x53,0x38,0x90,0x78,0x90, ++ 0x04,0x53,0x44,0x53,0x18,0x81,0x19,0xD2,0x02,0x53,0x5C,0x8A,0x12,0x09,0x06,0xD3, ++ 0x16,0x91,0x01,0x13,0x44,0x7A,0x42,0x23,0x10,0x61,0x18,0xA2,0x02,0x23,0x44,0x23, ++ 0x1A,0xA2,0x00,0x23,0x4C,0x23,0x1A,0xA2,0x08,0x23,0x4A,0x23,0x18,0xA2,0x08,0x23, ++ 0x40,0x23,0x1E,0xA2,0x02,0x23,0x46,0x43,0x10,0x01,0x1A,0x82,0x04,0x43,0x02,0xD1, ++ 0x07,0xC3,0x00,0x01,0x08,0xC3,0xEA,0x85,0x40,0x12,0x42,0x13,0x08,0x09,0x18,0x52, ++ 0x00,0x13,0x48,0x13,0x18,0x52,0x0C,0x13,0x4C,0x13,0x1A,0x52,0x0E,0x13,0x42,0x13, ++ 0x1E,0x52,0x00,0x13,0x39,0x82,0x43,0xE2,0x58,0x0B,0x10,0x21,0x18,0x8A,0x18,0x0B, ++ 0x5A,0x0B,0x10,0x01,0x18,0x8A,0x18,0x0B,0x5C,0x13,0x08,0x01,0x18,0x52,0x18,0x13, ++ 0x40,0x92,0x11,0x01,0x80,0x01,0x06,0x13,0x40,0x13,0x1A,0x52,0x01,0x13,0x4A,0x72, ++ 0x41,0x43,0x10,0x01,0x18,0x82,0x00,0x43,0x38,0x82,0xAB,0x85,0x08,0x09,0x00,0x31, ++ 0x81,0x07,0xD0,0xF7,0x08,0x11,0x00,0x21,0x81,0x07,0xD0,0xD7,0x00,0x09,0x80,0x07, ++ 0xD0,0xB7,0x02,0x31,0x82,0x07,0xD0,0x9F,0x00,0x21,0x80,0x07,0xD0,0x87,0x82,0x07, ++ 0xD0,0x2F,0xEB,0x85,0xA8,0x85,0x43,0xF2,0x4A,0xBA,0xC0,0x91,0x11,0x43,0x0A,0x91, ++ 0x80,0x1F,0xC8,0x07,0x40,0xD2,0x08,0x51,0x80,0x41,0x81,0x1F,0xC7,0xEF,0xBF,0xFF, ++ 0xF0,0x4F,0x02,0x09,0xBA,0xFF,0xFF,0x17,0x07,0xA1,0xB8,0xFF,0xFF,0x3F,0xBB,0xFF, ++ 0xFF,0xBF,0xBB,0xFF,0xFF,0xC7,0xBD,0xFF,0xFF,0x3F,0xBD,0xFF,0xF8,0x77,0x66,0x8A, ++ 0x29,0x01,0x80,0x2B,0x08,0x2B,0x41,0x72,0x09,0x71,0x80,0x91,0x87,0x1F,0xC0,0x17, ++ 0x0B,0x2C,0x81,0x2B,0x87,0x2B,0x85,0x2B,0x8B,0x2B,0x89,0x2B,0x05,0x51,0x88,0x03, ++ 0x0F,0x2C,0x8B,0x2B,0x0B,0x2C,0xED,0x85,0x00,0xE0,0x00,0x01,0xC8,0x21,0x01,0x00, ++ 0x70,0x02,0x01,0x00,0xF8,0xFF,0x07,0x04,0x68,0x02,0x03,0x00,0x70,0x70,0x06,0x01, ++ 0x80,0xC0,0x04,0x01,0x00,0x20,0x00,0x01,0x10,0x00,0x00,0x42,0x00,0x00,0x00,0x42, ++ 0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42,0x18,0x00,0x02,0x42,0xA8,0x85,0x80,0x07, ++ 0xC8,0xCF,0xEE,0x85,0xAF,0x85,0xB8,0xFF,0xE8,0x9F,0xEF,0x85,0xA8,0x7D,0x80,0x04, ++ 0x88,0x0C,0xC0,0x0C,0x80,0x14,0xC0,0x04,0x83,0x1C,0x30,0x42,0x40,0x7E,0x80,0x25, ++ 0xE8,0x05,0x00,0x00,0xAC,0xFD,0x87,0x1D,0x30,0x32,0x00,0x01,0x82,0x14,0x00,0x9F, ++ 0x44,0xDA,0x0E,0x01,0x0C,0x0B,0x26,0x01,0xC2,0x14,0x00,0x28,0x7F,0xC2,0x4E,0xC3, ++ 0x1F,0x02,0x09,0xC3,0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64, ++ 0x86,0x17,0xE0,0x1F,0xF8,0x82,0x33,0x0A,0xCF,0x99,0x49,0xC9,0x99,0x3E,0x40,0x91, ++ 0xE7,0x16,0x48,0xC3,0x1F,0x02,0x0D,0xC3,0x40,0x20,0x63,0x01,0x88,0x36,0xD7,0x6C, ++ 0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x17,0xE3,0x77,0xFD,0xA2, ++ 0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x85,0x17,0xE0,0x2F, ++ 0xF8,0xBA,0xD3,0x6C,0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x17, ++ 0xE5,0xE7,0x14,0x3A,0xE9,0x16,0x30,0x02,0x30,0xE2,0x31,0x3A,0xFD,0x82,0x13,0xC2, ++ 0xE3,0x0E,0x98,0xBA,0x05,0x17,0x10,0x02,0xDB,0x06,0x98,0xA2,0x46,0xC2,0x4D,0x03, ++ 0xDE,0x8A,0x0B,0x00,0xC0,0x00,0xCA,0x24,0x00,0x44,0xC0,0x24,0xE0,0x00,0x84,0x24, ++ 0xC2,0x14,0xE0,0x00,0x90,0x05,0x86,0x14,0xC8,0x2C,0xC0,0x14,0x15,0x42,0x9C,0x3E, ++ 0x87,0x3D,0xE8,0x85,0xAC,0xFD,0x87,0x7D,0x30,0xA2,0x30,0xFA,0xD8,0x0B,0x8F,0x6C, ++ 0xD8,0x0B,0x8B,0x64,0x40,0x01,0x80,0x6E,0x48,0x52,0x05,0x99,0x07,0x43,0x12,0xF9, ++ 0x58,0x3A,0x95,0x81,0x10,0xD3,0x06,0x43,0x00,0xC1,0x83,0x17,0xF8,0xFF,0xF1,0x84, ++ 0xB0,0xE1,0x01,0xCF,0x40,0x1A,0x0D,0x19,0x04,0x0B,0x0A,0x19,0x05,0x0B,0x48,0x12, ++ 0xC2,0x84,0xC0,0x30,0x11,0x01,0x30,0xDA,0x30,0x8A,0x00,0x09,0x82,0x17,0xC0,0xC7, ++ 0x29,0x01,0x30,0x1A,0x14,0x09,0x08,0x01,0x40,0x1D,0xB8,0x04,0x82,0x17,0xE0,0x6F, ++ 0xE7,0x68,0x93,0x6D,0x6F,0x91,0x99,0xA6,0x48,0xB2,0x44,0x43,0x10,0x11,0x18,0x82, ++ 0x01,0x43,0x30,0x02,0x80,0x01,0x35,0x2A,0xC8,0x03,0x32,0x00,0xAC,0xEE,0x49,0x9A, ++ 0x00,0x01,0x80,0x43,0x31,0x12,0x31,0xCA,0x00,0x11,0x80,0x0F,0xF9,0xF7,0x34,0x1A, ++ 0xB8,0x04,0x08,0x01,0x00,0x11,0xD0,0x84,0x84,0x17,0xC0,0x47,0x49,0x42,0xD4,0x43, ++ 0x08,0x43,0x2A,0x01,0xC2,0x64,0x00,0x00,0x80,0x74,0x00,0xBF,0x31,0xDA,0x31,0x52, ++ 0x08,0x01,0x00,0x09,0x81,0x17,0xC0,0x27,0xB8,0x0C,0xA0,0x04,0x30,0x8A,0x41,0x1D, ++ 0xD8,0x84,0xD0,0x64,0xB9,0xFF,0xFF,0xF7,0xC4,0x74,0xC8,0x30,0x09,0x09,0x30,0xDA, ++ 0x30,0x52,0x31,0x42,0x80,0x17,0xC0,0xA7,0xE7,0x68,0x93,0x6D,0xC4,0x6C,0x10,0x2A, ++ 0x99,0x26,0x37,0x1A,0xB8,0x04,0x08,0x01,0x00,0x19,0xD0,0x84,0x82,0x17,0xC0,0xF7, ++ 0x31,0x12,0x31,0xCA,0x00,0x01,0x80,0x0F,0xFB,0x47,0x4B,0x92,0x40,0x43,0x10,0x11, ++ 0x18,0x82,0x04,0x43,0x87,0x9D,0xE8,0x85,0xAC,0xFD,0x87,0x1D,0x30,0x7A,0x50,0x01, ++ 0x80,0x16,0x00,0x01,0x80,0x0C,0x00,0x0F,0x00,0x09,0x80,0x0C,0x2A,0x01,0x00,0x47, ++ 0xCD,0x64,0x00,0x40,0xC1,0x30,0x32,0x52,0x08,0x19,0xD8,0x6C,0xC0,0x0C,0x80,0x0F, ++ 0xF9,0x3F,0x07,0x41,0x85,0x17,0xF0,0xD7,0x20,0x09,0xC0,0x34,0x80,0x01,0x84,0x14, ++ 0x60,0x81,0x99,0x36,0x0A,0xF9,0x47,0xF2,0x88,0x11,0x18,0x0B,0x42,0x08,0x1B,0x0B, ++ 0x02,0x0F,0x40,0xDA,0x1F,0x23,0x02,0xF9,0x4F,0xCA,0x82,0x89,0x88,0x01,0x12,0x43, ++ 0x00,0x11,0x80,0x17,0xF0,0x1F,0xC5,0x14,0xF0,0x03,0x46,0x01,0x80,0x3E,0x00,0x51, ++ 0x84,0x17,0xF0,0xE7,0x40,0x83,0x41,0x03,0x30,0x00,0xA8,0x86,0x07,0x5F,0x00,0xF9, ++ 0x4C,0x7A,0x82,0x89,0x88,0x01,0x12,0x43,0x00,0x09,0x80,0x17,0xF1,0x7F,0x44,0x83, ++ 0x40,0x03,0x30,0x00,0xA3,0x1E,0xE0,0x20,0x93,0x25,0x67,0xF9,0xC9,0x86,0x06,0xE4, ++ 0xE1,0xF8,0x35,0x52,0x08,0x09,0xD8,0x6C,0xC0,0x0C,0x80,0x0F,0xFB,0x4F,0xE5,0x68, ++ 0x90,0x6D,0xC7,0x1C,0x15,0x2A,0x9C,0x9E,0x3F,0x17,0xA9,0x85,0x80,0x3D,0x34,0x7A, ++ 0x34,0xA2,0x00,0xD9,0xEF,0x02,0x0E,0xF9,0x88,0x09,0x40,0x01,0x80,0x0E,0x30,0x72, ++ 0x00,0x0F,0x30,0x19,0x13,0xB0,0xD9,0xC3,0x81,0x34,0xD8,0xC3,0x80,0x2C,0x98,0x1C, ++ 0xC2,0x34,0x00,0x00,0xC0,0x00,0x86,0x24,0x45,0xAA,0x11,0x81,0x00,0x13,0x1A,0x0B, ++ 0x28,0x01,0x00,0x67,0x4D,0x03,0x01,0x48,0xC0,0x00,0x42,0x03,0x01,0x33,0x30,0x1A, ++ 0x30,0x52,0x09,0x09,0x00,0x01,0x80,0x0F,0xFB,0xDF,0xE3,0x68,0x90,0x6D,0xC7,0x34, ++ 0x17,0x2A,0x9C,0x7E,0x28,0x01,0x00,0x67,0x4D,0x03,0x03,0x48,0xC0,0x00,0x42,0x03, ++ 0x00,0x33,0x08,0x09,0x31,0x1A,0x31,0x52,0x30,0x42,0x80,0x0F,0xFB,0x4F,0xE3,0x68, ++ 0x90,0x6D,0xC7,0x2C,0x17,0x2A,0x9C,0x7E,0x48,0x0B,0xA1,0x0C,0x89,0x04,0x30,0xDA, ++ 0x10,0x09,0xC8,0x1C,0xC7,0x34,0xB8,0xFF,0xFB,0xFF,0x4A,0x0B,0x89,0x04,0x30,0xDA, ++ 0x10,0x01,0xA0,0x0C,0xC8,0x24,0xC0,0x2C,0xBA,0xFF,0xFF,0xB7,0x48,0xC2,0x00,0x01, ++ 0x88,0x01,0x12,0x43,0x48,0xB2,0x18,0x43,0x37,0x57,0xAE,0xC5,0x30,0x1A,0x30,0x42, ++ 0x30,0xBA,0xD8,0x23,0xD8,0x2B,0x4A,0xB2,0xC0,0xC8,0x8A,0x04,0x30,0xD2,0x31,0xCA, ++ 0x87,0x0F,0xF8,0xDF,0x30,0x01,0x00,0x3F,0x09,0x09,0x30,0xDA,0x30,0x92,0x31,0x42, ++ 0x81,0x0F,0xF8,0xB7,0xE7,0xB0,0x93,0xB5,0x17,0x32,0x9D,0xAE,0xC8,0x04,0x10,0x01, ++ 0x18,0x01,0x00,0x4F,0x00,0x01,0x00,0x1F,0x82,0x5B,0xE0,0x48,0xE6,0x00,0x92,0x05, ++ 0x17,0x42,0x9D,0xCE,0xE6,0x90,0x92,0x95,0x17,0x12,0x9D,0x9E,0xE8,0xC5,0x07,0x00, ++ 0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x48,0xE0,0x06,0x00,0x00,0xD0,0x00,0x01, ++ 0x60,0x20,0x02,0x00,0x49,0x32,0x41,0x2A,0x05,0x43,0x9E,0xFF,0x7F,0x04,0x3A,0xF7, ++ 0x94,0x15,0x3A,0x00,0x77,0x18,0x06,0xF9,0x04,0xC2,0x3C,0x48,0x74,0x48,0x00,0xCA, ++ 0x50,0x01,0xD0,0x5E,0x38,0x90,0x78,0x90,0xD4,0x41,0x40,0x98,0x54,0xE2,0x00,0xD8, ++ 0xC6,0xD0,0x4C,0x9B,0x18,0x1A,0x1C,0x5A,0x0B,0x9B,0x3E,0x82,0x40,0x98,0x54,0xCA, ++ 0x04,0xD8,0xC4,0xD0,0x44,0x9B,0x18,0x1A,0x18,0x5A,0x00,0x9B,0x3A,0x82,0x93,0x05, ++ 0x36,0x10,0x76,0x90,0x0C,0x09,0x00,0x8A,0x48,0x00,0x52,0x9A,0x04,0x00,0xC4,0x00, ++ 0x03,0x0B,0x38,0x82,0x96,0x05,0x32,0x10,0x70,0x90,0x0E,0x09,0x00,0x8A,0x54,0x72, ++ 0x4C,0x00,0x02,0x00,0x94,0x01,0xC4,0x00,0x03,0x0B,0x38,0x82,0xB3,0x15,0x3B,0x82, ++ 0xFB,0x85,0x39,0x82,0x40,0x32,0x48,0x0B,0x10,0x21,0x18,0x8A,0x0B,0x0B,0x38,0x82, ++ 0x48,0x1A,0x48,0x43,0x14,0x21,0x18,0x82,0x0B,0x43,0x38,0x82,0x07,0x20,0x28,0xD0, ++ 0x68,0x07,0x00,0x07,0x20,0x07,0x00,0x07,0x08,0x07,0x00,0x07,0xAC,0xFD,0x87,0x4D, ++ 0xD0,0x94,0x30,0x22,0xF8,0x43,0x80,0x0C,0xF8,0x6B,0xC6,0x64,0x08,0x01,0x80,0x0B, ++ 0x00,0x01,0x00,0x8F,0x0A,0x21,0x19,0x0A,0x18,0x99,0xCB,0x48,0x0E,0xD8,0xC2,0x48, ++ 0xC8,0x4B,0x4C,0x79,0x80,0x36,0x80,0x83,0xE0,0x90,0xCA,0x64,0xD8,0x64,0xC0,0x4B, ++ 0xE0,0x48,0x82,0xCB,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0x5E,0xC0,0x64,0xC0,0x03, ++ 0x80,0x44,0x40,0x01,0x88,0x0E,0x80,0x6D,0xE8,0x85,0xC7,0x44,0x40,0x09,0x88,0x1E, ++ 0xC0,0x0C,0x40,0x09,0x8F,0x06,0x38,0xB7,0x00,0x01,0x80,0x34,0x80,0x2C,0xC8,0x44, ++ 0xC4,0x0C,0x10,0x0A,0x88,0x96,0x02,0x01,0x30,0x01,0x08,0x01,0x88,0x1C,0x88,0x14, ++ 0x1C,0xC9,0x09,0xD8,0x00,0x4F,0x10,0x31,0x18,0x52,0xCA,0x90,0xC2,0x90,0x46,0xBC, ++ 0xC4,0xC0,0x41,0x94,0xCA,0xB0,0xE4,0x48,0x90,0x4D,0xD6,0x0C,0x17,0x8A,0x9C,0x96, ++ 0xC8,0x0C,0x80,0x17,0xF0,0x6F,0x82,0x24,0x30,0x82,0xC9,0x0C,0x82,0x17,0xF0,0x47, ++ 0x30,0x32,0x08,0x01,0x01,0x01,0x00,0x07,0x1A,0x99,0x0B,0xD8,0x02,0x0F,0xE0,0x48, ++ 0x91,0x4D,0x16,0x21,0x18,0x52,0xCA,0x90,0xC4,0x90,0xCE,0x93,0x57,0x79,0x80,0xB6, ++ 0x12,0x21,0x19,0x52,0xCE,0x90,0xC0,0x98,0x3E,0xF1,0xF8,0xFA,0xDF,0x1C,0xC0,0xD8, ++ 0x98,0x1C,0x18,0xE9,0x0E,0xD8,0xC6,0x98,0x14,0x01,0xF0,0xD2,0xDE,0x14,0xC0,0x90, ++ 0x92,0x14,0xE0,0x48,0x92,0x4D,0xE6,0x00,0x90,0x05,0xD6,0x44,0x16,0x12,0xC4,0xDE, ++ 0xC8,0x44,0xC0,0x1C,0x80,0x17,0xF0,0xE7,0x30,0x3A,0xC8,0x44,0xC0,0x14,0x80,0x17, ++ 0xF0,0xBF,0xC8,0x24,0xD8,0x48,0x8E,0x34,0xD0,0x80,0x81,0x2C,0x08,0x01,0x10,0x01, ++ 0x00,0x77,0x00,0x01,0x33,0x5A,0x18,0x5A,0xF2,0x5C,0x00,0xD8,0xC8,0xD8,0x04,0x1F, ++ 0x04,0x30,0x9A,0xD2,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE,0xE6,0x48,0x92,0x4D, ++ 0x17,0x4A,0x9D,0x76,0x08,0x01,0x10,0x01,0x03,0xE7,0x19,0x99,0x08,0xD8,0x02,0x0F, ++ 0xE6,0x48,0x92,0x4D,0x02,0x21,0x19,0x42,0xCC,0x00,0x30,0x22,0xC0,0x00,0x86,0x3C, ++ 0xC8,0x03,0x44,0x79,0x80,0xA6,0x07,0x01,0x00,0x2F,0xD9,0x3C,0x34,0xF1,0xF8,0xF2, ++ 0xD9,0x34,0x38,0xC9,0xC0,0xB0,0x1F,0x31,0x18,0x1A,0xCA,0xD8,0x0E,0xF8,0xCD,0xD8, ++ 0x47,0xFC,0xDA,0xB0,0xAB,0x06,0x10,0xB2,0x95,0xB5,0x35,0xB2,0x37,0xE9,0x08,0xB0, ++ 0x20,0x32,0x3B,0x01,0xF8,0xBA,0xF7,0x2C,0x45,0xDC,0xCC,0xF0,0xD0,0x98,0xAF,0x06, ++ 0x10,0xDA,0x32,0xB2,0x18,0x72,0xFB,0x5C,0x07,0xB0,0xCB,0xB0,0x22,0x9A,0x03,0x38, ++ 0x9A,0x9A,0xE7,0x00,0x90,0x05,0xDE,0x0C,0x16,0xC2,0x9C,0xB6,0xE6,0x48,0x92,0x4D, ++ 0xE6,0x90,0x92,0x95,0xC0,0x64,0xC0,0x03,0x15,0x82,0xC4,0xF6,0xC0,0x64,0xC8,0x0C, ++ 0xC4,0x03,0x10,0x42,0xC9,0x06,0x38,0xF7,0xC1,0x0C,0x38,0xE7,0xAC,0x85,0x87,0x3D, ++ 0x34,0x22,0x00,0x91,0xD4,0x02,0x34,0x22,0x01,0xC1,0xF0,0x02,0x18,0x71,0x80,0x34, ++ 0xF0,0x1A,0x9F,0x2C,0xD0,0x00,0x96,0x05,0x1F,0xD1,0xF0,0x1A,0x2B,0x81,0xF8,0x2A, ++ 0x32,0xF2,0xDC,0xD8,0x90,0xDD,0xA8,0x24,0xC0,0x2B,0x6F,0x09,0x8D,0x16,0x10,0x04, ++ 0x10,0x1C,0x07,0x6F,0x55,0x3C,0x05,0xE8,0xC7,0x68,0x51,0x04,0x07,0x30,0xC4,0x98, ++ 0xD9,0x68,0x97,0x6D,0xD0,0xC0,0x90,0x1D,0x84,0x40,0x85,0xD8,0x17,0x04,0x15,0x1C, ++ 0x4B,0x81,0x80,0xF6,0xE9,0x2C,0xC0,0x40,0x02,0x28,0xCA,0x00,0xEA,0x34,0xC8,0x00, ++ 0x80,0x00,0x94,0x05,0xEF,0x24,0xC0,0x58,0x02,0xE8,0xCA,0xE8,0x37,0x9A,0xC3,0x58, ++ 0x80,0xD8,0x94,0xED,0x90,0x01,0x46,0x01,0xD0,0x0E,0x00,0x01,0x00,0x27,0x50,0x9C, ++ 0x10,0x1A,0xD4,0x0E,0x00,0x81,0xF0,0x82,0x68,0x01,0xD0,0x0E,0x28,0x01,0x00,0x27, ++ 0x55,0x9C,0x12,0x5A,0xD0,0x0E,0x28,0x91,0xF8,0xAA,0xD2,0x2C,0xD0,0x90,0xF0,0xB0, ++ 0xD2,0x06,0x10,0x92,0x06,0x98,0xC2,0xB8,0xD2,0x24,0xD8,0x90,0xF0,0x98,0xD0,0x06, ++ 0x15,0x92,0xC2,0xF8,0x7E,0xD0,0xCF,0x90,0x18,0x90,0x66,0x90,0x58,0x01,0xD0,0x06, ++ 0x12,0xDA,0x02,0xF8,0xC8,0xD8,0x76,0x01,0xD3,0x06,0x10,0xB2,0xCE,0xD8,0x7C,0xF0, ++ 0xC6,0x98,0x1F,0xD8,0x60,0xF0,0x48,0x41,0x80,0x0E,0x48,0x49,0x88,0x2E,0x48,0x49, ++ 0x8A,0x1E,0x20,0x88,0x63,0x50,0x20,0x88,0x63,0x70,0x30,0x0A,0x8B,0x0C,0x28,0x12, ++ 0xCB,0x06,0x30,0x12,0xCC,0x0C,0x10,0x72,0xC8,0x06,0xF0,0x0C,0xDB,0x2C,0x30,0x0A, ++ 0xD0,0x48,0x34,0x7A,0x1C,0xCA,0x02,0x58,0xC4,0x48,0x36,0x72,0x19,0x51,0x30,0xCA, ++ 0xF3,0x1A,0x07,0xF8,0xCA,0x48,0x1E,0x5A,0x32,0x8A,0xC3,0xC8,0x1B,0x82,0x32,0x12, ++ 0x46,0xB8,0xCA,0x00,0x02,0x00,0xC6,0x00,0x36,0x0A,0x03,0x48,0x88,0x1C,0x80,0x17, ++ 0xE8,0xBF,0x80,0x14,0xD0,0x24,0xC0,0x0C,0xD8,0x00,0x34,0x0A,0x1C,0x82,0x02,0x10, ++ 0xC0,0x00,0x14,0x61,0xF2,0x12,0x05,0x58,0xC2,0x48,0x1E,0x52,0xC3,0x80,0x18,0xAA, ++ 0x00,0x07,0x00,0x67,0xCE,0x48,0x07,0x48,0xC0,0x40,0xC8,0x1C,0x80,0x17,0xE8,0x07, ++ 0xCB,0x2C,0x08,0x0C,0xCD,0x24,0x08,0x0C,0xCF,0x14,0x08,0x0C,0x10,0x04,0x81,0x3D, ++ 0xEF,0x85,0xAF,0xF5,0x30,0x3A,0xC0,0x44,0x60,0xD2,0xCF,0xE0,0x2F,0x31,0x70,0xCA, ++ 0x1F,0xAA,0xC2,0x68,0xF5,0x21,0xC9,0x68,0x06,0x90,0xC2,0x90,0x59,0xAA,0xDF,0x81, ++ 0xC6,0xB0,0xFE,0x13,0x31,0xB2,0x34,0xDA,0x32,0x3A,0xB8,0x01,0x30,0x12,0xB8,0x0C, ++ 0x92,0x01,0xBE,0x01,0x59,0x09,0x88,0x4E,0x01,0x01,0x00,0x17,0xC0,0x0B,0x49,0x79, ++ 0x89,0xE6,0x40,0x4C,0x0B,0x0C,0x47,0x5C,0x14,0x1C,0x31,0xE2,0xC1,0x9B,0x89,0x1B, ++ 0xC3,0x9B,0x8B,0x1B,0x1B,0x0C,0x35,0x1A,0x19,0x1C,0x27,0x0C,0x23,0x1C,0x0B,0x0C, ++ 0x09,0x1C,0x45,0x4C,0x1B,0x0C,0x41,0x4C,0x19,0x0C,0x83,0x03,0x0F,0x09,0x80,0x0B, ++ 0x88,0x0B,0xFD,0x8B,0x90,0x0B,0x09,0x01,0x90,0x0B,0x03,0x27,0xA2,0x21,0xE1,0x00, ++ 0x93,0x05,0x2E,0x82,0x9B,0xD6,0x2E,0x82,0x94,0xF6,0x03,0x2F,0x1A,0x21,0x19,0xCA, ++ 0xC8,0x60,0x08,0x41,0x89,0x04,0x40,0x4C,0x18,0x0C,0x09,0x11,0xF3,0x4A,0x1B,0x0C, ++ 0x35,0x62,0xCC,0x0B,0x48,0x09,0x88,0xAE,0x08,0xC1,0x18,0xE1,0xF7,0x0A,0xF3,0x1A, ++ 0xD0,0x48,0xAE,0x06,0x14,0x4A,0x92,0x4D,0x30,0x72,0x1C,0xF1,0xF3,0x1A,0x37,0x0A, ++ 0xD0,0x48,0xAE,0x06,0x14,0x4A,0x92,0x4D,0xE3,0xDB,0x21,0x8A,0x10,0xCA,0xCC,0x0E, ++ 0x0D,0x01,0x88,0x0B,0x09,0xC1,0x18,0x01,0xF7,0x0A,0xF3,0x1A,0xD0,0x48,0xAE,0x06, ++ 0x14,0x4A,0x92,0x4D,0x30,0x62,0x0C,0xD1,0x1B,0x11,0xF1,0x0A,0xF6,0x1A,0xD7,0x48, ++ 0xAA,0x06,0x10,0x4A,0x24,0x0A,0x93,0x4D,0x30,0x62,0xDC,0x0C,0xC4,0x0B,0xE7,0xDB, ++ 0xE4,0xD8,0x12,0xCA,0xC8,0x7E,0xF8,0x8B,0xEE,0xDB,0x01,0xCA,0x28,0x0A,0xCB,0x56, ++ 0xD6,0x0B,0x4B,0x41,0x92,0x0E,0xE0,0x48,0x91,0x0B,0xD3,0x0B,0xFC,0x9B,0x10,0xCA, ++ 0x92,0x0E,0xE0,0x48,0x91,0x0B,0xD1,0x0B,0x28,0x0A,0xCB,0xA6,0xDF,0x0C,0xC0,0x0B, ++ 0xE2,0xDB,0xE4,0xD8,0x10,0xCA,0xCC,0x76,0xCA,0x0B,0x37,0x50,0xE2,0xCB,0x73,0x90, ++ 0xF4,0x48,0x12,0x52,0x89,0x0E,0x08,0x01,0x80,0x0B,0x35,0x12,0x09,0x81,0x30,0x02, ++ 0xBC,0xFF,0xF7,0xE7,0x00,0xDF,0xD8,0x0C,0xC4,0x0B,0xE7,0xDB,0xE4,0xD8,0x12,0xCA, ++ 0xC8,0x1E,0xF8,0x8B,0xEE,0xD3,0x01,0x8A,0x91,0x0B,0x59,0x0C,0x23,0x0C,0x59,0x0C, ++ 0x20,0x0C,0x33,0x12,0x30,0x02,0xC9,0x04,0xBC,0xFF,0xF7,0x47,0x03,0x01,0x90,0x03, ++ 0xD0,0x03,0x41,0x01,0x80,0x1E,0x00,0x07,0x02,0x3F,0xF1,0x00,0x97,0x03,0xC1,0x03, ++ 0x40,0xF9,0x93,0x0E,0xE7,0x00,0x82,0x03,0x43,0x44,0x15,0x04,0x03,0x19,0x80,0x03, ++ 0xE4,0xC3,0x83,0x01,0x89,0x03,0xCF,0x03,0xC2,0x8B,0xD1,0x00,0xE0,0x00,0x42,0x11, ++ 0xC3,0x2E,0xC8,0x03,0xC2,0x8B,0xD3,0x00,0xE0,0x00,0x42,0x11,0xCF,0x4E,0xC0,0x03, ++ 0x40,0x11,0x98,0x36,0xCA,0x0C,0xE0,0x4B,0x10,0x42,0xC4,0x16,0x07,0x01,0x80,0x03, ++ 0x89,0x03,0xC7,0x83,0x8B,0x03,0xC1,0x83,0x8F,0x03,0xEB,0xF5,0xAC,0x85,0x37,0xE2, ++ 0x34,0x2A,0xAB,0x01,0x4A,0x5C,0x27,0xD8,0x67,0xE0,0x40,0xF9,0x88,0x0E,0x00,0x01, ++ 0xE9,0x85,0x1F,0x21,0x1B,0xC2,0x5A,0xFA,0xC6,0x00,0xC4,0x00,0x1A,0x31,0x18,0xCA, ++ 0xC3,0x48,0x54,0xE2,0xD4,0x21,0xC1,0x50,0x0A,0xA1,0xF0,0x0A,0x48,0x01,0xD0,0x06, ++ 0x10,0x4A,0x1A,0xB1,0xF0,0x1A,0x5E,0x01,0xD2,0x06,0x10,0xDA,0xC3,0x48,0x5E,0xB2, ++ 0x10,0xCA,0x9C,0x06,0x08,0x01,0x30,0x71,0x44,0x9C,0xF8,0x32,0xD8,0xD8,0xAC,0x06, ++ 0x10,0xDA,0x32,0x81,0x44,0x94,0xFA,0x32,0xD8,0x90,0xAC,0x06,0x14,0x92,0xC2,0xD0, ++ 0x11,0x12,0x9D,0x0E,0xC8,0x33,0x74,0x09,0x8B,0x26,0xE0,0x5B,0xCA,0x3B,0xF6,0xD8, ++ 0x10,0xFA,0xDC,0xBE,0x70,0x09,0x88,0x3E,0xDC,0x5B,0x11,0x5A,0x9E,0x26,0xC0,0x03, ++ 0x40,0xF1,0xC0,0x0E,0x40,0x51,0x90,0x6E,0x70,0x09,0x88,0x1E,0x30,0x02,0x5B,0x04, ++ 0x40,0xC1,0x98,0x3E,0x70,0x09,0x88,0x16,0x04,0x00,0x13,0x82,0xCD,0x16,0x00,0x00, ++ 0x10,0x82,0xC4,0x0E,0x07,0x01,0xE8,0x85,0x07,0x09,0xE8,0x85,0xAC,0xFD,0x87,0x5D, ++ 0x30,0xB2,0x0C,0x01,0x28,0x01,0x00,0x01,0x80,0x14,0xC0,0xA4,0xF8,0x23,0x06,0x01, ++ 0x30,0x22,0x84,0x34,0x00,0x27,0xD0,0x64,0x02,0xF9,0xA7,0x82,0xE6,0x48,0x92,0x4D, ++ 0x17,0x0A,0x9D,0xC6,0xD3,0x74,0x28,0x92,0xC0,0x26,0xC0,0x74,0x83,0x24,0x30,0x82, ++ 0x80,0x1C,0x00,0x1F,0x30,0x82,0x83,0x24,0xC0,0x74,0x80,0x1C,0x00,0x01,0x80,0x2C, ++ 0x00,0xD7,0x1A,0x01,0x03,0xB7,0x32,0x02,0x06,0xC2,0x3E,0x00,0x8A,0x86,0x42,0x32, ++ 0x80,0x3C,0x00,0x01,0xD0,0xA4,0xF0,0x5C,0xF8,0x93,0x90,0x54,0x33,0xD2,0x18,0x12, ++ 0x05,0xB8,0xCA,0xD0,0x90,0x4C,0x00,0x6F,0xF6,0x34,0x00,0x32,0x38,0x90,0x8F,0x3E, ++ 0xF2,0x4C,0x00,0x38,0xD8,0xB2,0xFF,0x3C,0x10,0xF2,0x95,0x0E,0xB0,0x3C,0x30,0x0A, ++ 0xE6,0x00,0x92,0x05,0xD4,0x54,0x10,0x12,0xC1,0x76,0x77,0xBA,0x02,0x01,0x00,0x78, ++ 0xB8,0x44,0x00,0x87,0x36,0x3A,0x03,0x3A,0x38,0xF8,0x8F,0x56,0x33,0x3A,0x18,0x3A, ++ 0xD3,0x5C,0x00,0xF8,0xC0,0xF8,0xD5,0x44,0xD5,0xFA,0x15,0xBA,0xC1,0x0E,0x30,0xF2, ++ 0x32,0x2A,0xE0,0x00,0x93,0x05,0x2E,0x82,0x9C,0x66,0x17,0xEA,0x88,0xA6,0xC0,0x14, ++ 0xC8,0x00,0x84,0x14,0xC2,0x2C,0xE0,0x00,0x90,0x05,0x86,0x2C,0xC2,0x64,0xA0,0x2A, ++ 0x31,0x09,0x30,0x82,0xD4,0x34,0x00,0x42,0x1C,0x82,0x90,0x05,0x85,0x34,0x00,0x72, ++ 0x30,0x02,0x1B,0x32,0x94,0x85,0x35,0x22,0xD0,0x24,0xC0,0x2C,0x10,0x82,0x84,0x1E, ++ 0xE6,0xD8,0x92,0xDD,0x2D,0x9A,0x9B,0x36,0xD0,0x24,0xC0,0x2C,0x15,0x82,0x9C,0x06, ++ 0xC0,0x14,0x80,0x3C,0x10,0x01,0x00,0x01,0x0B,0x01,0x30,0x5A,0x80,0xCB,0x18,0x01, ++ 0x0C,0x01,0x30,0x62,0x30,0x4A,0xE3,0x4A,0x02,0x0F,0xE0,0x48,0x90,0x4D,0x36,0xEA, ++ 0x07,0x6A,0x3E,0x68,0x88,0xCE,0xEF,0x1C,0x10,0x4A,0x9D,0xFE,0x40,0x01,0x88,0x8E, ++ 0x08,0xF9,0x07,0x5F,0xD0,0x64,0xE0,0x9A,0x28,0x9A,0x93,0x1E,0xD0,0xA4,0xF8,0x93, ++ 0x10,0x12,0xC4,0x0E,0xD0,0x64,0xA0,0x8A,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0x8E, ++ 0x87,0x7D,0xE8,0x85,0xF6,0x00,0x92,0x05,0x30,0x4A,0xE3,0x4A,0x2D,0x09,0x30,0x62, ++ 0x00,0x6F,0x01,0x00,0x70,0x30,0x03,0x00,0xF8,0xFF,0x07,0x00,0x33,0x6A,0x18,0x2A, ++ 0xFB,0x5C,0x00,0x70,0xCA,0xB0,0x07,0x38,0xDD,0xAA,0xC7,0x50,0x2C,0x09,0x00,0x6A, ++ 0x1D,0xEA,0x90,0x5D,0x31,0x72,0xA3,0x8A,0xED,0x3C,0x10,0x52,0x98,0x16,0x28,0x11, ++ 0x30,0x62,0x05,0xA7,0xFA,0x74,0xE0,0x28,0x10,0xEA,0x9D,0x6E,0x90,0x3C,0x08,0x01, ++ 0x00,0x27,0xF8,0x64,0xE3,0xAA,0xA3,0xEA,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xC6, ++ 0xE0,0x8A,0x29,0x09,0x30,0x62,0x05,0x17,0x90,0x45,0x2F,0x01,0xA3,0xAA,0x31,0x2A, ++ 0x6D,0x01,0x80,0x2E,0x33,0x6A,0x18,0x2A,0xFB,0x5C,0x00,0x70,0xCA,0xB0,0x07,0x38, ++ 0xDA,0xAA,0xDF,0x90,0x2C,0x09,0x00,0x6A,0x1B,0x5A,0x35,0x6A,0xE2,0x4A,0xE1,0x48, ++ 0xA4,0x4A,0x39,0xAF,0xAC,0xC5,0x37,0x22,0xFC,0x73,0x5E,0xAA,0x36,0x02,0xC3,0x00, ++ 0x31,0x32,0x34,0xAA,0x38,0x21,0x31,0x62,0x1A,0xEA,0xA3,0x01,0x13,0x01,0x20,0x2A, ++ 0xC0,0x68,0x07,0xF7,0xC0,0x1B,0x58,0x79,0x86,0xD6,0xC8,0x1B,0x30,0xD8,0xA0,0x3E, ++ 0x18,0xF9,0x8F,0x1B,0x8E,0x1B,0xC2,0x1B,0xE5,0x3B,0x15,0xDA,0xC6,0x06,0x88,0x13, ++ 0xCA,0x1B,0x36,0xD8,0x76,0xD8,0x8A,0x1B,0x58,0x01,0x80,0x0E,0xF6,0xD8,0x8A,0x1B, ++ 0xC8,0x1B,0x5E,0x01,0x8A,0x26,0xC0,0x1B,0x44,0xD8,0x04,0xD8,0x84,0x1B,0x82,0x13, ++ 0x84,0x21,0x11,0x2A,0xC0,0xF6,0x06,0x01,0x84,0x04,0xB8,0x53,0x30,0x82,0x03,0x8F, ++ 0xC5,0x13,0x10,0x92,0x96,0x5E,0xC0,0x13,0xE2,0x3B,0x35,0x98,0x75,0xD8,0x12,0xDA, ++ 0xCC,0x2E,0xC0,0x13,0x50,0x01,0x81,0x16,0x00,0x09,0x80,0x04,0x00,0x27,0x10,0x01, ++ 0x81,0x13,0x84,0x21,0x17,0x2A,0xC4,0x5E,0xC0,0x04,0x40,0x01,0x83,0x76,0x31,0x92, ++ 0x36,0x5A,0x98,0x01,0x00,0x47,0x01,0x01,0x80,0x83,0xC4,0x83,0x11,0x82,0x95,0x16, ++ 0xC2,0x83,0x36,0x38,0xE3,0x03,0x75,0xF8,0x10,0x3A,0xCC,0xE6,0x04,0x09,0x80,0x83, ++ 0xFA,0x43,0xE4,0x00,0xB8,0x43,0x3C,0x71,0xF8,0xBA,0x7E,0x01,0xD0,0x16,0x00,0x01, ++ 0x08,0x84,0x06,0x27,0x54,0xC4,0x10,0x3A,0xE8,0x0E,0x50,0xC4,0x08,0x84,0x3E,0x81, ++ 0xF8,0xBA,0x7E,0x01,0xD0,0x16,0x00,0x01,0x10,0x84,0x00,0x27,0x54,0xC4,0x12,0x3A, ++ 0xEA,0x0E,0x50,0xC4,0x11,0x84,0x90,0x21,0x16,0xAA,0xC4,0xA6,0xF8,0x43,0x40,0x01, ++ 0x88,0x36,0x58,0x44,0x16,0xE9,0x03,0x90,0x10,0x82,0x94,0x0E,0xE0,0x00,0x1A,0x44, ++ 0xF8,0x43,0x44,0x01,0x80,0xCE,0x10,0x01,0x03,0x01,0x28,0x99,0x0E,0x68,0xFB,0x63, ++ 0x01,0x6F,0x18,0x21,0x1B,0x1A,0x22,0x1A,0xC8,0xD8,0xD2,0xF3,0x70,0x09,0x88,0x26, ++ 0xC8,0xDB,0x5E,0x19,0x8A,0x0E,0xE0,0x90,0x92,0x95,0xE6,0x00,0x94,0x05,0x16,0x22, ++ 0xC0,0x7E,0x57,0x01,0x88,0x0E,0x00,0x01,0x1F,0x44,0xE8,0xC5,0xAC,0x85,0x87,0x3D, ++ 0x30,0x2A,0x30,0x62,0x41,0x12,0xC2,0x40,0x08,0x29,0xEE,0x4A,0x4B,0x29,0x80,0xDE, ++ 0x4B,0x02,0xC2,0x70,0xEB,0x48,0xC4,0x48,0x89,0x1C,0x48,0xF2,0x8B,0x61,0xC0,0x48, ++ 0x88,0x14,0x08,0x01,0x10,0xF9,0x1F,0x79,0x03,0x3F,0xA0,0x92,0xC8,0x3B,0x7E,0x01, ++ 0x88,0x06,0x80,0x1B,0xE6,0x48,0x92,0x4D,0x87,0x21,0xF9,0x3B,0x17,0x7A,0xC4,0xA6, ++ 0x00,0x01,0x80,0x34,0xF8,0x03,0x41,0x01,0x80,0xCE,0xB2,0x04,0x31,0x0A,0x31,0x42, ++ 0x58,0x2D,0xD0,0x14,0xBA,0xFF,0xDF,0x97,0x80,0x34,0xC0,0x34,0x40,0x01,0x88,0x76, ++ 0x30,0x01,0x00,0x47,0x31,0x5A,0x31,0x92,0x08,0xF9,0x07,0x09,0xA7,0x04,0xB8,0xFF, ++ 0xE3,0x47,0xE7,0xB0,0x91,0xB5,0xFF,0x03,0x17,0x82,0xC5,0x9E,0x00,0xFF,0xC1,0x34, ++ 0x40,0x09,0x88,0x96,0xC1,0xB3,0x31,0x1A,0x30,0x52,0x09,0x01,0x37,0x82,0xB9,0xFF, ++ 0xE8,0x2F,0x46,0x01,0x80,0x0E,0x00,0x01,0x00,0x07,0x00,0x09,0x30,0x5A,0x11,0x01, ++ 0x30,0x8A,0xA1,0x04,0xBE,0xFF,0xE7,0x6F,0x00,0x4F,0xA1,0x04,0xFB,0x3B,0x31,0x5A, ++ 0xE9,0xD3,0x30,0xDA,0xC8,0x1C,0xC0,0x14,0xB8,0xFF,0xF7,0x47,0x38,0x01,0x00,0xDF, ++ 0xC6,0x1C,0xE8,0x02,0x40,0xF9,0x87,0x16,0xE0,0x82,0x81,0x24,0x07,0x0F,0x00,0xF9, ++ 0x81,0x24,0x30,0x1A,0x31,0x52,0x31,0xCA,0xC7,0x24,0xB8,0xFF,0xE8,0xFF,0x44,0x01, ++ 0x80,0x0E,0x00,0x01,0x00,0x07,0x00,0x09,0x31,0x5A,0x31,0xD2,0xA0,0x04,0xC8,0x24, ++ 0xBD,0xFF,0xE7,0x3F,0xE7,0xF8,0x93,0xFD,0xFD,0x03,0x11,0xC2,0xC1,0x06,0x37,0x0A, ++ 0x30,0x42,0xD1,0x34,0xBE,0xFF,0xF7,0xB7,0x20,0xCF,0x04,0x01,0x38,0x82,0x03,0x00, ++ 0x70,0x30,0x03,0x00,0x48,0xE0,0x06,0x00,0xAE,0xFD,0x87,0x5D,0xC6,0xAC,0xDA,0x03, ++ 0x82,0xCC,0xC1,0xAC,0xD9,0x03,0x84,0xC4,0x01,0x09,0x58,0x45,0x81,0xC3,0xC0,0xC4, ++ 0xE2,0x00,0x82,0xC3,0xC4,0xC4,0x81,0xC3,0xC2,0xC4,0xF1,0x00,0x82,0xC3,0xC6,0xAC, ++ 0x82,0x01,0x87,0x54,0xC0,0x0B,0x00,0x21,0x1A,0x0A,0xC0,0x54,0x82,0x0B,0xC0,0xAC, ++ 0xCA,0x03,0x42,0x00,0x80,0xD4,0x09,0x01,0x40,0xB5,0x31,0x52,0x00,0x36,0x00,0x01, ++ 0x82,0xF4,0xC0,0xAC,0xCC,0xB4,0x82,0x01,0x82,0x4C,0xC2,0x74,0x92,0x05,0x82,0x44, ++ 0xC2,0x6C,0x92,0x05,0x82,0x3C,0xC2,0xAC,0x82,0x01,0x86,0x34,0x4B,0x11,0x80,0xBE, ++ 0x10,0x01,0x00,0x01,0x4C,0x45,0xB1,0x4A,0x8F,0x2C,0x4A,0xF2,0xB2,0x4A,0x8C,0x24, ++ 0x48,0xE2,0xEF,0x48,0xB2,0x4A,0x8C,0x1C,0x04,0x08,0xC4,0x48,0x91,0x4D,0x66,0x9D, ++ 0xDB,0x74,0xA2,0x1A,0x62,0x85,0xD9,0x6C,0xA2,0x1A,0xDB,0x24,0x9A,0x34,0xD9,0x1C, ++ 0x9A,0x2C,0xD9,0x2C,0x98,0x24,0x41,0x09,0x89,0x5E,0xD8,0x34,0x12,0xDA,0x92,0xDD, ++ 0x99,0x34,0xD9,0x2C,0x12,0xDA,0x92,0xDD,0x99,0x2C,0xD9,0x24,0x12,0xDA,0x92,0xDD, ++ 0x9A,0x24,0xD9,0x5C,0x32,0xE2,0xDC,0x64,0x9A,0x5C,0xD9,0x3C,0xE1,0x44,0xEA,0x2C, ++ 0xCA,0xD8,0x92,0xDD,0xEB,0x34,0xC9,0x20,0x91,0x25,0xF3,0x24,0xED,0x5C,0xC9,0x68, ++ 0xA8,0x5C,0x59,0x01,0xD9,0x86,0xEB,0xCC,0x13,0x5A,0xD5,0x6E,0x63,0x01,0xD8,0x5E, ++ 0xED,0xC4,0x11,0x62,0xD1,0x46,0xEB,0x5C,0xC5,0x6B,0x49,0x68,0x8B,0x06,0x32,0x2A, ++ 0x3F,0x01,0xF8,0x7A,0xEB,0x24,0x01,0x68,0x23,0x62,0x35,0x32,0x2B,0x01,0xF8,0xAA, ++ 0xF5,0xD4,0x11,0xAA,0xEA,0xC6,0xF2,0xB4,0x71,0x09,0x88,0x16,0xD9,0xF0,0x93,0xB5, ++ 0xB2,0x9C,0xF8,0x5C,0x35,0x01,0xF8,0xF2,0x10,0x72,0xDD,0x06,0x37,0xAA,0x81,0x68, ++ 0x01,0x68,0x33,0x7A,0xF3,0x9C,0x10,0x6A,0x12,0xAA,0xE5,0x2E,0x6B,0x9D,0xA1,0x62, ++ 0x6B,0x85,0xA1,0x5A,0x01,0xA8,0x72,0xB5,0xC9,0x68,0xE5,0x72,0xE1,0xB0,0xA3,0x72, ++ 0xEB,0xF4,0xE0,0x68,0x90,0x6D,0xAF,0xF4,0xF5,0x9C,0x10,0xBA,0xD1,0xBE,0x05,0x9F, ++ 0x09,0xEF,0x6A,0x9D,0xA1,0x62,0x6B,0x85,0xA2,0x5A,0x03,0xA8,0x75,0xB5,0xC9,0x68, ++ 0xE3,0x72,0xE1,0xB0,0xA0,0x72,0xE9,0xF4,0xE7,0x68,0x93,0x6D,0xAD,0xF4,0x38,0x37, ++ 0xE9,0x5C,0xC1,0x6B,0x48,0x68,0x6D,0x19,0x8A,0x6E,0x00,0xB0,0x7F,0xB5,0xC9,0xB0, ++ 0xE0,0xB2,0x71,0x09,0xC2,0x3E,0xC0,0x64,0x08,0x01,0xC6,0x03,0x1A,0x42,0xC8,0x64, ++ 0x82,0x43,0x80,0x7D,0xE8,0x85,0x6F,0x11,0x89,0x56,0x68,0x9D,0xA1,0x62,0x63,0x85, ++ 0xA2,0x1A,0x03,0x98,0x4A,0xB5,0xC1,0xC8,0xE2,0x5A,0xE0,0xD8,0xA0,0x5A,0x00,0x1F, ++ 0xCE,0x34,0xCA,0x4B,0x4F,0x51,0x90,0x66,0xE6,0x00,0x92,0x05,0x40,0x11,0x90,0x06, ++ 0x3A,0xD7,0xE2,0x90,0x90,0x95,0x56,0x21,0x92,0x06,0x38,0x57,0x01,0x01,0x80,0x64, ++ 0xC0,0xB4,0x42,0x09,0x88,0xF6,0x03,0x01,0x80,0x7C,0x01,0x01,0x81,0x74,0xC9,0x7C, ++ 0x42,0xB5,0x01,0x48,0xC2,0x40,0x80,0x14,0xC1,0x74,0xC9,0x7C,0x02,0x00,0xC4,0x00, ++ 0x91,0x05,0x86,0x4C,0xCA,0x74,0xC1,0x14,0xE0,0x2A,0x6A,0x09,0xC1,0x26,0xC0,0x64, ++ 0xE6,0x00,0x92,0x05,0x87,0x64,0x01,0x8F,0xC0,0x74,0x41,0x09,0x89,0x16,0xC0,0x7C, ++ 0x47,0x01,0x88,0xC6,0x08,0x81,0x41,0x45,0x83,0x17,0xC0,0x77,0xC0,0x6C,0x82,0x3C, ++ 0xC0,0x74,0x82,0x34,0xC0,0x5C,0x82,0x0C,0xC0,0x64,0x82,0x04,0xC4,0x7C,0xE1,0x00, ++ 0x3C,0x00,0x7C,0x00,0x50,0x5A,0xB4,0xA2,0xE8,0x98,0xB0,0xCA,0x31,0x62,0x74,0x45, ++ 0xB1,0x8A,0xC1,0x7C,0xB0,0x82,0x80,0x24,0xC0,0x7C,0xB1,0xC2,0x81,0x1C,0xD0,0x7C, ++ 0xB0,0x82,0x85,0x14,0xC0,0x74,0x41,0x09,0x88,0x5E,0xC0,0x24,0x12,0x02,0x92,0x05, ++ 0x80,0x24,0xC0,0x1C,0x12,0x02,0x92,0x05,0x80,0x1C,0xC0,0x14,0x12,0x02,0x92,0x05, ++ 0x80,0x14,0x00,0x01,0x83,0x2C,0xE0,0x68,0xAD,0xF4,0x01,0x9F,0x40,0x61,0x98,0x66, ++ 0xC8,0x24,0xC0,0x34,0xD2,0x4C,0xD1,0x00,0x4C,0x9D,0xA1,0x42,0xC8,0x1C,0xC0,0x3C, ++ 0xD2,0x4C,0xD1,0x00,0x4C,0x85,0xA1,0x42,0x00,0x47,0x15,0x01,0xDC,0x0C,0x00,0x28, ++ 0xF0,0xD2,0x5C,0x45,0x88,0xD2,0x12,0x01,0x90,0x6C,0xD1,0x3C,0x92,0x95,0x92,0x0C, ++ 0xD2,0x34,0x90,0x95,0x91,0x04,0xD2,0x6C,0x50,0x09,0x88,0x3E,0x12,0x12,0x93,0xA5, ++ 0x32,0x12,0x13,0x92,0x94,0x95,0x32,0xA2,0x12,0x4A,0x92,0x4D,0xD2,0x0C,0xDA,0x04, ++ 0xF0,0x0C,0x00,0x07,0x01,0xEF,0xB4,0x1C,0xF1,0x04,0xB0,0x5C,0x01,0x70,0xB2,0xFC, ++ 0x22,0x12,0x93,0x95,0xCA,0xD8,0x90,0xDD,0xF9,0x1C,0xF1,0xFC,0xC9,0xB0,0xB7,0x1C, ++ 0xF3,0x5C,0xC1,0xB0,0xB0,0x5C,0x51,0x01,0xD9,0xBE,0xF0,0xCC,0x10,0x92,0xD5,0xA6, ++ 0x58,0x01,0xD8,0x96,0xF5,0xC4,0x11,0x9A,0xD1,0x7E,0xF8,0x1C,0x35,0x01,0xF8,0xF2, ++ 0xF9,0x5C,0xC1,0xFB,0x48,0xF8,0x8D,0x46,0xFD,0xD4,0x11,0xF2,0xE8,0x2E,0x78,0x45, ++ 0xCD,0xFA,0xCB,0xF0,0x7B,0x45,0x88,0xF2,0x39,0xD7,0xD6,0x6C,0xE6,0x90,0x92,0x95, ++ 0x91,0x6C,0xD1,0x6C,0x55,0x11,0x98,0xF6,0x41,0x01,0x80,0xF6,0xF2,0x10,0xF2,0x4C, ++ 0x00,0x90,0x5C,0x45,0xC7,0xD2,0xD4,0xB3,0xCC,0xDA,0xCA,0xB0,0x11,0xF2,0x94,0x86, ++ 0xD0,0x2C,0x50,0x09,0x88,0x8E,0xD1,0x24,0xC1,0x34,0xD8,0x4C,0xD1,0x00,0x54,0x9D, ++ 0xA0,0x82,0xDE,0x1C,0xD1,0x3C,0xE8,0x4C,0xD1,0x90,0x5E,0x85,0xA8,0xD2,0xEA,0x14, ++ 0xDA,0x04,0xD8,0xE8,0x36,0x1A,0xD3,0x90,0x90,0x95,0xDA,0x00,0x93,0x1D,0xD2,0x40, ++ 0x2C,0x01,0x38,0x01,0x50,0x01,0xD8,0x56,0xF5,0xCC,0x11,0x92,0xD0,0x3E,0x58,0x01, ++ 0xD9,0x2E,0xF0,0xC4,0x10,0x9A,0xD5,0x16,0xC1,0x33,0x18,0xF2,0x83,0x33,0x20,0x12, ++ 0x90,0x95,0xCA,0xD8,0x92,0xDD,0xC2,0x00,0xE7,0x68,0x93,0x6D,0x6F,0x11,0xC8,0x4E, ++ 0x04,0xE7,0x10,0x9A,0x90,0x0E,0x10,0x09,0x90,0x2C,0xD8,0x24,0xD6,0x34,0xC0,0x90, ++ 0x90,0x95,0x96,0x34,0xD8,0x1C,0xD0,0x3C,0xC6,0x90,0x96,0x95,0x90,0x3C,0xD0,0x14, ++ 0xDA,0x0C,0x00,0x90,0xC0,0x90,0x96,0x0C,0xD8,0x14,0xD0,0x04,0xC0,0x90,0x96,0x04, ++ 0xE6,0x00,0x92,0x05,0xD4,0xF4,0x11,0x82,0x92,0x06,0x38,0x3F,0xC2,0x74,0xE1,0x00, ++ 0x91,0x05,0x86,0x74,0xC0,0x74,0x41,0x11,0x97,0x06,0x30,0xAF,0xC2,0x7C,0xE1,0x00, ++ 0x91,0x05,0x86,0x7C,0xC0,0x7C,0x41,0x21,0x97,0x06,0x30,0x37,0x00,0x0F,0x00,0x41, ++ 0x81,0x64,0xC1,0x64,0x41,0x41,0x88,0xD6,0x10,0x01,0x00,0x01,0x58,0x8A,0xE8,0xC8, ++ 0xB4,0xF2,0xB4,0x7A,0x31,0x8A,0x31,0xDA,0x40,0x09,0x88,0x1E,0x12,0x4A,0x92,0x4D, ++ 0x12,0xDA,0x92,0xDD,0xE7,0x6C,0xC2,0x18,0x92,0xDD,0xE2,0x74,0xC2,0x08,0x93,0x65, ++ 0x04,0x08,0xC4,0x48,0x90,0x4D,0x5E,0x01,0xD9,0x76,0xE8,0xCC,0x10,0x5A,0xD5,0x5E, ++ 0x60,0x01,0xD8,0x4E,0xED,0xC4,0x11,0x62,0xD1,0x36,0x68,0x9D,0xA1,0x62,0x63,0x85, ++ 0xA0,0x1A,0x03,0x3F,0x70,0xF2,0x06,0x00,0x62,0x9D,0xD9,0x74,0xA1,0x1A,0x63,0x85, ++ 0xDB,0x6C,0xA2,0x1A,0xE6,0x00,0x92,0x05,0x46,0x11,0x98,0x9E,0xE6,0x90,0x92,0x95, ++ 0x56,0x21,0x98,0x56,0x58,0x85,0xD9,0xC3,0xA8,0xC3,0xC0,0xC3,0x90,0xC3,0x00,0x01, ++ 0x81,0xFC,0x58,0x85,0xD8,0xC3,0xA8,0xC3,0xC0,0xC3,0x90,0xC3,0x00,0x01,0x80,0xE4, ++ 0x30,0x3A,0x80,0xEC,0xC4,0xAC,0xCA,0x03,0x80,0xD4,0x01,0x01,0x0E,0x01,0x00,0x18, ++ 0x54,0xA5,0xC0,0xD0,0x32,0xA2,0x04,0x20,0xC6,0x10,0x93,0x95,0x6D,0x9D,0xE1,0x72, ++ 0x33,0x2A,0xA3,0x72,0x6D,0x85,0xE1,0x6A,0x32,0x12,0xC3,0x90,0x8A,0xAB,0xE0,0x48, ++ 0x90,0x4D,0x4E,0x19,0x98,0x86,0x47,0x09,0x80,0x0E,0x40,0x19,0x88,0x66,0x60,0xA5, ++ 0xE3,0x0A,0x37,0x12,0xCB,0x93,0x30,0x2A,0xC7,0x6B,0xA5,0x2A,0x34,0x1A,0xCB,0xE3, ++ 0x8C,0xE3,0x80,0xCB,0x34,0x0A,0x8B,0x53,0x09,0x09,0x88,0x0C,0x09,0x01,0x88,0x74, ++ 0xD3,0x74,0x31,0x0A,0xE1,0x4A,0xDC,0x74,0x36,0x12,0xC3,0x90,0xCA,0x9B,0xC0,0xAB, ++ 0xC9,0x93,0x92,0x14,0xD0,0x74,0x51,0x01,0x88,0x16,0x41,0x01,0x80,0x0E,0x40,0x19, ++ 0x8D,0x5E,0x10,0x4A,0x98,0x4E,0x10,0x09,0x90,0x04,0x41,0x01,0x8A,0x16,0xF0,0x10, ++ 0x90,0x0C,0x01,0xF7,0x11,0x09,0x90,0x0C,0x00,0xDF,0x40,0x09,0x80,0x0E,0x40,0x11, ++ 0x8D,0x5E,0x10,0x4A,0xC0,0x4E,0x10,0x09,0x90,0x04,0x41,0x09,0x8C,0x16,0xF0,0x10, ++ 0x90,0x0C,0x01,0x77,0x11,0x09,0x90,0x0C,0x00,0x5F,0x10,0x01,0x90,0x04,0x01,0x47, ++ 0x11,0x09,0x90,0x04,0x40,0x11,0x90,0x16,0xF1,0x90,0x94,0x0C,0x00,0x0F,0x10,0x09, ++ 0x90,0x0C,0x41,0x01,0x80,0x0E,0x40,0x19,0x8D,0x0E,0x10,0x4A,0x90,0x2E,0x40,0x09, ++ 0x80,0x0E,0x40,0x11,0x8D,0x26,0x10,0x4A,0xC0,0x16,0x10,0x09,0x94,0x54,0x01,0x8F, ++ 0x11,0x01,0x90,0x54,0x01,0x77,0xF4,0xC4,0x33,0x12,0x19,0x92,0xF1,0xA4,0x92,0xE4, ++ 0xC9,0x90,0xF4,0xEC,0xC9,0x90,0x94,0x5C,0xD0,0x5C,0xC1,0x93,0x92,0xDC,0x31,0x90, ++ 0xA1,0xCE,0xD1,0xE4,0xF2,0xA4,0x02,0x90,0xC9,0x90,0xF4,0x3C,0x04,0xB0,0xCB,0x90, ++ 0x35,0x39,0x09,0xB0,0xC8,0xB0,0x14,0xE1,0xF1,0x92,0xF5,0xD4,0x10,0x92,0xD5,0x26, ++ 0xF0,0x64,0x71,0x41,0x88,0xB6,0x50,0x01,0xD9,0xA6,0xF0,0xDC,0x48,0xB0,0x87,0x06, ++ 0x80,0x90,0xF2,0xE4,0xC0,0xB0,0xB5,0xE4,0xF2,0x3C,0x19,0xB2,0xC8,0xB8,0xF7,0xEC, ++ 0x1C,0x12,0xCB,0x90,0x90,0xEC,0xD0,0xFC,0xE4,0x90,0x92,0x95,0x91,0xFC,0xD0,0xDC, ++ 0x48,0x90,0x8E,0xEE,0xD0,0x4C,0xF2,0xF4,0xD5,0x93,0x12,0x92,0xC1,0x2E,0xD0,0xDC, ++ 0x31,0x01,0x1E,0x92,0xF1,0x5C,0x81,0x93,0x01,0x47,0xD0,0xDC,0x31,0x01,0x1A,0x92, ++ 0xF1,0x5C,0x81,0x93,0x01,0x17,0xD0,0x04,0x50,0x09,0x80,0x4E,0xD0,0x04,0x51,0x09, ++ 0x8A,0x36,0xD0,0x6C,0x10,0xA2,0x84,0x1E,0xD5,0x0C,0xC1,0x10,0x95,0xA5,0x3A,0x57, ++ 0x10,0x4A,0x8D,0xDE,0xD4,0x14,0x11,0x9A,0x89,0xC6,0xC8,0x74,0xE6,0x48,0x92,0x4D, ++ 0x89,0x74,0xC9,0x74,0x48,0x11,0x90,0x06,0x3A,0x97,0xE2,0x00,0x90,0x05,0x46,0x21, ++ 0x91,0x06,0x38,0x1F,0xC6,0x34,0xCA,0x03,0x42,0x01,0x88,0x5E,0xC9,0xAC,0x8A,0x01, ++ 0xE0,0x43,0x36,0x10,0xAA,0x36,0x31,0x00,0x71,0x00,0x04,0x27,0xD0,0x54,0x51,0x01, ++ 0x8D,0x5E,0x10,0x4A,0xCA,0x16,0xF0,0x48,0x90,0x4D,0x06,0x1F,0x10,0x4A,0x95,0x0E, ++ 0xE6,0x48,0x92,0x4D,0x11,0x09,0x90,0x54,0x01,0x67,0xD0,0x14,0x10,0x9A,0xCC,0x16, ++ 0xF6,0xD8,0x92,0xDD,0x01,0x27,0xD0,0x14,0x10,0x9A,0x94,0x0E,0xE6,0xD8,0x92,0xDD, ++ 0x11,0x01,0x90,0x54,0x91,0x55,0x92,0x3C,0x97,0xE5,0x72,0xFA,0xD4,0x3C,0xC9,0x90, ++ 0x93,0xEC,0x39,0x47,0x02,0x01,0xD0,0xAC,0x6C,0x94,0x16,0x12,0x9A,0xD6,0xC0,0xAC, ++ 0xE8,0x4B,0x70,0x04,0x10,0x42,0x9C,0x26,0xC4,0x4C,0xD2,0x03,0xF6,0x00,0x94,0x05, ++ 0x02,0x1F,0xC0,0x4C,0xD4,0x03,0xE4,0x00,0x90,0x05,0xCE,0xFC,0x10,0x0A,0x9C,0x4E, ++ 0xC0,0xAC,0x0A,0x01,0xBA,0x0B,0xC0,0x54,0x08,0xD9,0xC7,0x03,0x02,0x42,0xC8,0x54, ++ 0x82,0x43,0x28,0x37,0x27,0x01,0x28,0xF9,0xA8,0x09,0x60,0x01,0x8A,0x56,0xC0,0x44, ++ 0xC8,0xC4,0xB9,0x9C,0xD2,0x34,0x4A,0x93,0x92,0x94,0xD0,0x74,0x5A,0x3A,0x07,0x90, ++ 0xF0,0xF2,0x04,0x57,0xC1,0x3C,0xCA,0xCC,0xD0,0xEC,0x90,0x9C,0xD4,0x34,0x4A,0x93, ++ 0x92,0x94,0xD0,0x6C,0x5A,0x12,0x07,0x90,0xF0,0xF2,0x44,0x01,0x82,0x16,0xF0,0x48, ++ 0x10,0x42,0x8C,0x8E,0xD0,0x74,0x92,0x04,0x91,0x05,0x36,0x0A,0xDA,0x6C,0xD2,0x5C, ++ 0xBB,0xEF,0xD7,0xA7,0x35,0x4A,0x11,0x42,0xE8,0x0E,0x30,0x42,0x00,0x17,0x40,0x01, ++ 0xD0,0x06,0x00,0x01,0xC8,0x30,0x04,0x07,0xB0,0x01,0xC4,0x9C,0xC8,0xE4,0x10,0x00, ++ 0x86,0x0F,0xE8,0x27,0xCC,0x94,0xC8,0x00,0x18,0x42,0x42,0x01,0xD0,0x06,0x00,0x01, ++ 0xA0,0x00,0x60,0x01,0x8A,0x7E,0xC8,0x34,0x54,0x4C,0x10,0x0A,0xD0,0x06,0x30,0x42, ++ 0xC8,0xAC,0x12,0x31,0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90, ++ 0xC2,0x48,0x04,0x44,0x02,0x77,0xC8,0x34,0x54,0x4C,0x12,0x0A,0xD0,0x06,0x30,0x42, ++ 0xC8,0xAC,0x12,0x31,0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90, ++ 0xC4,0x48,0x04,0x44,0xE7,0x20,0x93,0x25,0x64,0x09,0xC8,0xF6,0xC0,0xAC,0x12,0x31, ++ 0xE0,0x0B,0xC2,0xE4,0x02,0x42,0xCE,0xAC,0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48, ++ 0x14,0xC9,0x09,0x90,0xC6,0x48,0x04,0x44,0xC2,0xAC,0xCA,0x74,0xFA,0x03,0x00,0x10, ++ 0xC0,0xA4,0xC2,0x90,0x02,0x89,0x0B,0x00,0xC4,0x90,0xA8,0x8B,0xCA,0xAC,0xD2,0x6C, ++ 0xFA,0x4B,0x00,0x58,0xCA,0xA4,0xC2,0xC8,0xC6,0x40,0xA8,0x13,0xC2,0xAC,0xCA,0xAC, ++ 0xFA,0x03,0xE0,0x00,0xBD,0x43,0x20,0xE7,0xAC,0xFD,0x87,0xBD,0xEC,0x04,0x31,0xA2, ++ 0xD8,0x43,0x87,0x84,0xD8,0x43,0x85,0x7C,0xC8,0x43,0x81,0x74,0x00,0x01,0x80,0x54, ++ 0x42,0x22,0x45,0x0B,0x36,0x42,0x81,0x01,0x80,0xB4,0x48,0x01,0x80,0x1E,0xC0,0x74, ++ 0x40,0x00,0x82,0x5C,0x00,0x67,0xC0,0xB4,0xC8,0x03,0x46,0x51,0x98,0x26,0xC8,0xB4, ++ 0x00,0x49,0xB0,0x42,0x80,0x5C,0x00,0x1F,0xC0,0xB4,0x08,0x41,0xB0,0x0A,0x8A,0x5C, ++ 0x40,0xCA,0xD4,0xD4,0xC8,0xBC,0xC0,0x80,0x80,0xAC,0x48,0x01,0x84,0xF6,0x49,0xBA, ++ 0xC2,0xD4,0xC0,0x08,0x10,0x49,0xC5,0xD4,0x04,0x90,0xC4,0x18,0xE0,0xAC,0xC0,0x74, ++ 0x42,0x00,0x12,0x02,0x90,0x05,0x82,0x54,0x30,0x01,0x00,0x7F,0x00,0x01,0x00,0x47, ++ 0x40,0x7C,0x40,0xD4,0xD1,0xD0,0x05,0x14,0xE4,0x20,0xE5,0x48,0xE2,0xD8,0xE4,0x00, ++ 0x90,0x05,0xD6,0x7C,0x17,0x82,0x9C,0x9E,0xE7,0xB0,0x93,0xB5,0xC4,0x84,0x10,0x32, ++ 0x9B,0x66,0x37,0x02,0x40,0x01,0x80,0x06,0x3C,0x02,0x4C,0x2A,0xC2,0xD4,0xC0,0x18, ++ 0x48,0x1A,0xC4,0xD4,0x8A,0xC1,0xC1,0x00,0x50,0x0A,0xCC,0xD4,0x94,0x81,0xC3,0x48, ++ 0x10,0x01,0x00,0x47,0x40,0x24,0x40,0x74,0xD8,0x20,0x05,0xE4,0xE4,0xD8,0xE4,0x00, ++ 0xE2,0x48,0xE4,0x90,0x90,0x95,0xE6,0x7C,0x17,0x12,0x9D,0x9E,0x48,0x92,0xC3,0xD4, ++ 0xC0,0x00,0x82,0x4C,0xE0,0xAC,0x00,0x01,0x81,0x8C,0x30,0x42,0x80,0x01,0x81,0xA4, ++ 0x80,0x01,0x86,0x9C,0x08,0x97,0x32,0x01,0x08,0x47,0xC2,0x4C,0xC4,0x03,0x48,0x00, ++ 0x89,0xF6,0xF3,0x02,0xCC,0x74,0x10,0x42,0xD8,0xD6,0xC3,0x7C,0x32,0x5A,0x03,0x00, ++ 0xD0,0x08,0x31,0x52,0xD6,0x01,0x59,0x94,0x10,0xD4,0x40,0x54,0x12,0xD4,0x42,0x4C, ++ 0x11,0xCC,0x34,0x0A,0xCE,0x01,0x59,0x4C,0x11,0xCC,0x46,0x0C,0x1B,0xCC,0x40,0x0C, ++ 0x18,0xCC,0xCA,0x08,0x31,0x52,0xD0,0x01,0x5C,0x94,0x1E,0xD4,0xD6,0x02,0x19,0xC4, ++ 0x40,0x44,0x22,0xC4,0x40,0x25,0x70,0x01,0x88,0x26,0x08,0x01,0x16,0xCC,0x10,0xCC, ++ 0x18,0xCC,0x04,0x47,0xCA,0x7C,0xF0,0x48,0x10,0x72,0x8C,0x26,0x0B,0x01,0x30,0x5A, ++ 0x12,0xCC,0x1C,0xCC,0x20,0xCC,0xC8,0x8C,0x48,0x01,0x88,0x26,0x30,0x5A,0x13,0xCC, ++ 0x14,0xCC,0x12,0xCC,0x00,0x4F,0xC8,0x84,0xD2,0x8C,0xF0,0x48,0x10,0x52,0x8C,0x26, ++ 0x0B,0x01,0x30,0x5A,0x1E,0xCC,0x1C,0xCC,0x20,0xCC,0x10,0x01,0xF3,0x12,0x35,0x5A, ++ 0x0A,0x81,0xF0,0xCA,0x11,0x8A,0xD4,0x9E,0x0A,0x91,0xF0,0xCA,0x17,0x8A,0xD4,0xD6, ++ 0x0A,0xA1,0xF0,0xCA,0x17,0x8A,0xD4,0xB6,0x0A,0xB1,0xF0,0xCA,0x17,0x8A,0xD4,0x96, ++ 0x0A,0xD1,0xF0,0xCA,0x11,0x8A,0xE4,0x1E,0x0A,0xE1,0xF0,0xCA,0x17,0x8A,0xE4,0xD6, ++ 0x0A,0xF1,0xF0,0xCA,0x17,0x8A,0xE4,0xB6,0x0A,0x01,0xF1,0xCA,0x17,0x8A,0xE4,0x96, ++ 0x0A,0xD1,0xEC,0x4A,0x4B,0x01,0x80,0xCE,0x08,0x01,0x88,0x6C,0x30,0x72,0x8C,0x1C, ++ 0x88,0x64,0xD8,0xBC,0x5A,0x01,0x88,0x1E,0x32,0xE2,0xFC,0x78,0x1E,0x01,0xF0,0x1A, ++ 0x10,0xDA,0xD5,0x46,0xC0,0xC8,0x92,0x4D,0xDA,0x1C,0xE0,0xD8,0x90,0xDD,0x06,0x07, ++ 0x00,0xF7,0x9D,0x1C,0x00,0x2F,0x58,0x51,0xEB,0x1E,0x30,0x9A,0xE6,0xD8,0x92,0xDD, ++ 0x34,0xF2,0xE4,0x00,0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x36,0xE2,0x30,0x1A,0x5B,0x49, ++ 0x9A,0x26,0xC7,0x80,0x90,0x05,0xD0,0xA4,0x70,0x4C,0xE9,0x93,0x10,0x8A,0x9C,0xB6, ++ 0xCC,0x5C,0x10,0x42,0xD3,0x9E,0x30,0x8A,0x48,0x39,0x98,0x36,0xCA,0x5C,0x80,0x48, ++ 0x10,0x0A,0xDC,0x66,0xC0,0x1C,0x40,0x01,0x88,0x4E,0xC0,0xB4,0xC8,0x03,0x46,0x11, ++ 0x98,0x0E,0x00,0x09,0x80,0x6C,0x48,0xDA,0xC2,0x43,0xE2,0x00,0x80,0x43,0x4A,0xCA, ++ 0xC0,0x43,0x40,0x81,0x90,0x26,0x52,0xC2,0xA2,0xB2,0xE0,0x00,0x81,0x43,0x00,0xFF, ++ 0x34,0xB2,0x84,0x98,0xC0,0x98,0x96,0xDD,0x98,0x14,0x18,0x01,0x30,0xE2,0xDC,0x54, ++ 0x80,0xD8,0x9A,0x94,0x1E,0x01,0xF0,0x1A,0xFD,0x94,0x10,0xDA,0xD3,0x56,0x30,0xBA, ++ 0xC9,0xF8,0x96,0xFD,0x30,0xF2,0xFD,0x54,0x10,0xDA,0xD5,0x1E,0x86,0xB8,0xCA,0xB8, ++ 0x90,0xFD,0xB9,0x14,0xC0,0xC8,0x02,0x97,0x60,0x20,0x02,0x00,0x70,0xD2,0x05,0x00, ++ 0x70,0xD2,0x03,0x00,0x80,0x40,0x07,0x01,0x48,0xE0,0x06,0x00,0x28,0x60,0x00,0x00, ++ 0x68,0x70,0x04,0x00,0x00,0xC0,0x00,0x01,0x80,0xC0,0x06,0x01,0x00,0xF7,0x90,0x4D, ++ 0xE3,0x00,0x34,0x1A,0xE6,0xD8,0x92,0xDD,0x33,0xE2,0x34,0x1A,0x5E,0x49,0x98,0x8E, ++ 0xC4,0x14,0x10,0x0A,0xD8,0x16,0xC8,0x5C,0x28,0x72,0xD4,0x0E,0x00,0x09,0x80,0x6C, ++ 0xC6,0xB4,0xC8,0x03,0x40,0x51,0x98,0x16,0xC0,0xBC,0x40,0x01,0x80,0x46,0xC8,0x6C, ++ 0x00,0x09,0x48,0x01,0x80,0x06,0x00,0x01,0x80,0x64,0x00,0x0F,0x00,0x09,0x80,0x64, ++ 0xC0,0x64,0x40,0x01,0x80,0xA6,0x01,0x09,0xBC,0x43,0x43,0x3A,0x40,0x03,0x42,0x01, ++ 0x88,0x5E,0xC0,0xB4,0xC8,0x03,0x46,0x51,0x90,0x3E,0xC0,0xA4,0x6E,0x4C,0xE7,0x03, ++ 0x32,0x00,0x72,0x00,0x84,0x51,0x10,0x0A,0xC8,0x0E,0x10,0x01,0x00,0x07,0x10,0x09, ++ 0xC0,0xC4,0x40,0x01,0x80,0x06,0x10,0x11,0xC0,0xD4,0x90,0x14,0x81,0x04,0x30,0x9A, ++ 0xA9,0x0C,0x30,0x02,0xD0,0x8C,0xC8,0x4C,0xBA,0xFF,0xD7,0x37,0xC0,0x9C,0xC0,0x03, ++ 0x38,0x00,0xAA,0x1E,0xFF,0x43,0xF9,0x4B,0x10,0x42,0x9C,0x4E,0xC0,0x9C,0xC0,0x03, ++ 0x38,0x00,0xA2,0x1E,0x05,0x01,0xA8,0x43,0xCC,0x9C,0x80,0x43,0x87,0xDD,0xE8,0x85, ++ 0xE0,0x20,0xC5,0x4C,0xE0,0x00,0x82,0x4C,0xE7,0xB0,0x93,0xB5,0xC4,0x7C,0x10,0x32, ++ 0x95,0x06,0x30,0x97,0xC2,0x8C,0xE0,0x00,0x90,0x05,0x86,0x8C,0xC8,0x84,0xC0,0x8C, ++ 0x10,0x42,0x94,0x06,0x37,0x3F,0x3D,0x4F,0xAC,0x9D,0x87,0x0D,0xD8,0x43,0x80,0x04, ++ 0xDB,0x63,0x52,0x12,0xC4,0x0C,0xC0,0x28,0x50,0x02,0xC3,0x0C,0xD4,0xC1,0xC1,0x30, ++ 0xE8,0x43,0x0C,0xF1,0x84,0x0F,0xD8,0x97,0x49,0xE9,0x88,0x0E,0x48,0xE2,0xC2,0x0C, ++ 0xC5,0x10,0x0A,0x49,0xC4,0x0C,0x00,0x48,0xC0,0x08,0x1A,0x01,0x00,0x5F,0x00,0x01, ++ 0x00,0x2F,0x40,0x7C,0x04,0xBC,0xE0,0x90,0xE2,0x48,0xE4,0x00,0x95,0x05,0x16,0x02, ++ 0x9A,0xBE,0xE7,0xD8,0x90,0xDD,0xC6,0x04,0x17,0x1A,0x9C,0x86,0x00,0x01,0x00,0x2F, ++ 0x41,0x8C,0x01,0x4C,0xE5,0x68,0xE5,0xB0,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0xBE, ++ 0x48,0x62,0xC2,0x0C,0xC0,0x00,0x12,0x01,0x00,0x67,0x08,0x01,0x00,0x37,0xC0,0x1B, ++ 0x34,0xD8,0x74,0xD8,0x82,0x1B,0xE0,0x00,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xB6, ++ 0xE6,0x90,0x92,0x95,0xCC,0x04,0x10,0x52,0x9F,0x7E,0xEF,0xF5,0xAC,0xFD,0x87,0x1D, ++ 0x30,0x6A,0x30,0x01,0xBB,0x73,0xB9,0x73,0x37,0x42,0x81,0x01,0xC7,0x0B,0x10,0xE9, ++ 0x02,0x52,0x38,0x48,0x7A,0x48,0x06,0x48,0x18,0x52,0x80,0x13,0xC7,0x0B,0x10,0xD9, ++ 0x00,0x8A,0x80,0x0B,0x34,0x42,0x81,0x01,0x84,0x14,0xF0,0x03,0x78,0xB2,0x41,0x01, ++ 0x80,0x4E,0x00,0x01,0x57,0xAA,0x09,0xF9,0xA2,0x8A,0xE0,0x00,0x90,0x05,0x46,0x81, ++ 0x99,0xD6,0x87,0xF3,0x80,0xF3,0xAB,0x04,0x00,0x01,0xD8,0x1C,0xD0,0x34,0xC8,0x2C, ++ 0xBD,0xFF,0xEF,0xD7,0x36,0x62,0xA1,0x01,0xC8,0x03,0x47,0x51,0x98,0x36,0xA8,0x04, ++ 0x00,0x09,0xD8,0x1C,0xD0,0x34,0xC8,0x2C,0xBD,0xFF,0xEF,0x77,0xC4,0x14,0xF0,0x0B, ++ 0x49,0x01,0x80,0xD6,0x00,0x01,0x48,0x09,0x8B,0x5E,0xC0,0xD3,0x50,0x01,0x80,0x46, ++ 0x50,0x1A,0xC1,0x93,0x50,0x01,0x88,0x26,0x50,0x12,0xC1,0x93,0x50,0x01,0x88,0x06, ++ 0x00,0x09,0x40,0x01,0x87,0x2E,0xC8,0x13,0x50,0x01,0x95,0x36,0xE7,0x90,0x8A,0x13, ++ 0x07,0x1F,0xC8,0x13,0x50,0x51,0x90,0x06,0x8F,0x33,0xCF,0x13,0x50,0x51,0x98,0xE6, ++ 0x40,0x01,0x88,0x6E,0x48,0x09,0x88,0x16,0xF7,0x90,0x8A,0x13,0x01,0x47,0x00,0x99, ++ 0xEF,0x02,0x6A,0x4C,0x34,0x00,0x72,0x00,0x10,0x0A,0x94,0x0E,0xF7,0x90,0x8A,0x13, ++ 0xC0,0xC3,0x43,0x11,0x9D,0x16,0x00,0x01,0x88,0x03,0x07,0x37,0x40,0x09,0x88,0x26, ++ 0xCA,0x03,0x47,0x81,0x93,0x0E,0x00,0x21,0x89,0x03,0x37,0x4A,0xC7,0x1C,0xB8,0xFF, ++ 0xF8,0xDF,0x81,0x3D,0xE8,0x85,0x07,0x00,0x80,0x40,0x07,0x01,0x68,0xF0,0x07,0x00, ++ 0x28,0x60,0x00,0x00,0x60,0x20,0x02,0x00,0x00,0xC0,0x00,0x01,0x80,0xC0,0x06,0x01, ++ 0x00,0x40,0x00,0x01,0x00,0x48,0x00,0x01,0xAC,0xFD,0x87,0x3D,0xE0,0x84,0x30,0xB2, ++ 0x00,0x01,0x80,0x2C,0xD8,0x83,0x83,0x1C,0x60,0x8C,0x89,0x14,0xCA,0x44,0x18,0x0A, ++ 0x50,0xFA,0xC7,0x3C,0xC0,0x00,0xC4,0x48,0x8F,0x34,0x40,0xF2,0xC0,0x03,0x40,0x09, ++ 0x89,0x0E,0xE0,0x83,0x80,0x1C,0x00,0x01,0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48, ++ 0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2,0x98,0xC6,0x0F,0x01,0x00,0x09,0xD8,0x54, ++ 0xD0,0x44,0x80,0x07,0xD0,0xAF,0x2E,0x01,0x60,0x01,0x88,0x0E,0xE7,0x68,0x93,0x6D, ++ 0xF8,0x34,0x08,0x01,0x01,0x5F,0xC0,0xC3,0x1E,0x02,0x91,0x05,0x80,0xC3,0xD1,0x8C, ++ 0x10,0x82,0xCC,0x0E,0x19,0x02,0x85,0xC3,0xE2,0xF8,0xE3,0x48,0x90,0x4D,0xC6,0x1C, ++ 0x17,0x0A,0x9C,0x86,0x48,0x42,0xC7,0x3C,0xC0,0x00,0x82,0x24,0xD0,0x54,0x90,0x04, ++ 0x30,0x9A,0x01,0x11,0xD0,0x3C,0xC8,0x44,0x80,0x07,0xD8,0x47,0xD0,0x54,0x90,0x04, ++ 0x04,0x41,0xEA,0x0A,0x00,0x01,0x1C,0x0A,0x30,0x9A,0x11,0x01,0xC0,0x24,0x80,0x07, ++ 0xF6,0x27,0x05,0x29,0xE8,0x02,0x44,0x31,0x88,0x16,0x00,0x01,0x87,0x5D,0xE8,0x85, ++ 0xC1,0x1C,0xD0,0xC0,0x09,0x01,0x00,0x3F,0xD0,0x24,0x18,0x01,0xF0,0x9A,0xD6,0x14, ++ 0xD0,0xD0,0x94,0x95,0x68,0x01,0x88,0x2E,0x50,0xC1,0xE8,0xBE,0xC5,0x13,0x18,0x12, ++ 0x80,0x13,0x00,0x9F,0x50,0x99,0xE8,0x2E,0xC0,0x13,0x50,0x01,0x82,0x16,0xF0,0x90, ++ 0x80,0x13,0x00,0x5F,0x68,0x29,0x88,0x4E,0x58,0xE1,0xEE,0x3E,0xC0,0x13,0x50,0x01, ++ 0x88,0x26,0xD0,0x2C,0x50,0x01,0x88,0x0E,0x10,0x09,0x90,0x2C,0xD4,0x24,0xE0,0x90, ++ 0x92,0x24,0xE0,0x00,0xE6,0x48,0x92,0x4D,0xD4,0x1C,0x10,0x8A,0x9B,0xA6,0x46,0x20, ++ 0x6C,0x21,0xC8,0xCE,0xD0,0x54,0x90,0x04,0x30,0x9A,0x09,0x01,0x00,0x19,0xD0,0x3C, ++ 0x85,0x07,0xD0,0xE7,0x08,0x09,0x30,0x42,0xD8,0x54,0xD0,0x44,0x83,0x07,0xD0,0x07, ++ 0xC5,0x2C,0x38,0xDF,0xAC,0xFD,0x87,0x1D,0xF0,0x64,0x30,0x7A,0x33,0xEA,0xD8,0xC3, ++ 0x85,0x14,0x48,0xAA,0xC2,0x1C,0xC0,0x20,0x40,0x92,0xC5,0x03,0x40,0x09,0x88,0x0E, ++ 0xE0,0xC3,0x81,0x14,0x08,0x01,0x00,0x09,0xD8,0x2C,0xD0,0x6C,0x82,0x07,0xD0,0x47, ++ 0xD0,0x2C,0x90,0x04,0x30,0xDA,0x01,0x11,0xD0,0x1C,0xC8,0x6C,0x84,0x07,0xD0,0xB7, ++ 0xD0,0x2C,0x90,0x04,0x06,0x41,0xEA,0x0A,0x00,0x01,0x1C,0x0A,0x30,0xDA,0x11,0x01, ++ 0x30,0x02,0x81,0x07,0xF0,0x97,0xD1,0x2C,0x91,0x04,0x30,0xDA,0x08,0x01,0x00,0x19, ++ 0xD0,0x1C,0x80,0x07,0xD0,0x1F,0x0C,0x09,0x30,0x42,0xD8,0x2C,0xD0,0x6C,0x80,0x07, ++ 0xD4,0x3F,0x41,0xF2,0x00,0x44,0x01,0x01,0x00,0x84,0x09,0x01,0x00,0x77,0x00,0x01, ++ 0xF0,0x02,0x11,0x01,0xF4,0x52,0x15,0x12,0xE9,0x06,0x00,0x44,0x15,0x01,0xF0,0x92, ++ 0x10,0x12,0xD4,0x06,0x05,0x84,0xE1,0x20,0xE6,0x48,0x92,0x4D,0xC4,0x14,0x10,0x0A, ++ 0x98,0x6E,0x87,0x3D,0xEF,0x85,0xAF,0xBD,0x80,0x55,0xC4,0x5C,0xD8,0x03,0x86,0x24, ++ 0xCA,0x5C,0xD8,0x4B,0x8C,0x1C,0x50,0x52,0xCC,0x54,0xC0,0x48,0x8C,0x4C,0x48,0x4A, ++ 0xC0,0x4B,0x48,0x09,0x88,0x46,0xC8,0x24,0xE6,0x48,0x92,0x4D,0x88,0x24,0x80,0x3C, ++ 0xC0,0x5C,0xE0,0x03,0x80,0x1C,0x00,0x0F,0x00,0x01,0x80,0x3C,0xF8,0x3C,0xC0,0x5C, ++ 0x80,0x01,0x86,0x44,0x04,0x7F,0x4B,0x12,0x04,0x01,0x00,0x43,0xC0,0x5C,0xC8,0x4C, ++ 0xDB,0x03,0x1A,0xC2,0xC0,0x08,0x02,0x01,0x10,0xF9,0x01,0x1F,0x82,0x53,0xE0,0x48, ++ 0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2,0x9C,0xC6,0x27,0x01,0x31,0x2A,0x31,0x32, ++ 0x03,0xE7,0x40,0xC2,0x08,0x23,0x4E,0x2D,0xB8,0x0C,0x88,0x04,0x40,0x55,0x40,0x3E, ++ 0x5F,0x35,0xB8,0xFF,0xF8,0x7F,0xC3,0x44,0xC8,0x03,0x42,0x31,0x83,0x7E,0x33,0x5A, ++ 0x00,0xC1,0xF0,0xC2,0x40,0xE1,0xD1,0x1E,0x68,0x41,0x80,0x4E,0x18,0x62,0x05,0x1F, ++ 0x70,0x01,0x8C,0x0E,0x30,0x72,0x01,0x1F,0x41,0x68,0x1B,0x62,0x6F,0x01,0x88,0x06, ++ 0xC0,0x5C,0xC8,0x4C,0xDB,0x03,0x1A,0xC2,0xC0,0x08,0x02,0x01,0x10,0x01,0x00,0x1F, ++ 0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2,0x99,0xC6,0x37,0xAA, ++ 0x20,0x01,0x00,0x0F,0x1B,0xA2,0x41,0xB0,0x77,0x01,0x88,0xDE,0xC0,0x5C,0x60,0x04, ++ 0xC0,0x41,0x91,0x35,0x05,0xAF,0x18,0x62,0x46,0xD2,0x0A,0x23,0x48,0x2D,0xB8,0x0C, ++ 0x88,0x04,0x40,0x55,0x40,0x3E,0x58,0x35,0xB9,0xFF,0xFF,0xA7,0xC2,0x44,0xC8,0x03, ++ 0x42,0x31,0x80,0x6E,0x30,0x5A,0x03,0xA1,0xF5,0xC2,0x10,0x82,0xE9,0x06,0x18,0x62, ++ 0x40,0x68,0x6B,0x01,0x88,0x3E,0xC7,0x54,0x0E,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00, ++ 0xB3,0x23,0xE0,0xF8,0x90,0xFD,0xC7,0x24,0x14,0x3A,0x9C,0x66,0xF1,0x3C,0x00,0xA7, ++ 0xC3,0x54,0x08,0x59,0xCA,0x00,0x0C,0x48,0xC1,0x38,0xF2,0xC3,0x40,0x01,0x88,0x0E, ++ 0x01,0x09,0xB0,0xC3,0xF0,0xE3,0x29,0x01,0x01,0x01,0x00,0x0F,0xE7,0x68,0x93,0x6D, ++ 0x40,0x09,0x88,0x1E,0x60,0xF9,0x97,0x0E,0xE5,0x20,0x93,0x25,0x48,0xE2,0x01,0x01, ++ 0x00,0x43,0xAC,0x48,0x46,0xDA,0x09,0x23,0x20,0x00,0x67,0x10,0x00,0x0F,0x00,0xBF, ++ 0x40,0x48,0x32,0x82,0x17,0x42,0x80,0xDE,0x48,0x01,0xC9,0x06,0x08,0x01,0x89,0x04, ++ 0x90,0x0C,0x40,0x55,0x41,0x6E,0x30,0x8A,0xBA,0xFF,0xF7,0x77,0x40,0x01,0x80,0x0E, ++ 0x6E,0x29,0x98,0xDE,0xB3,0xE3,0xE1,0xB0,0x90,0xB5,0xC7,0x24,0x16,0x32,0x9C,0x3E, ++ 0x87,0x6D,0xE8,0x85,0xAC,0xBD,0x87,0x15,0x30,0x62,0x30,0xB2,0x48,0x2A,0x01,0x01, ++ 0x81,0x43,0x40,0x4A,0x40,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B,0x28,0x01,0x00,0x3F, ++ 0x09,0x09,0x30,0x9A,0x30,0x52,0x31,0x42,0x81,0x07,0xC8,0x57,0xE7,0x68,0x93,0x6D, ++ 0xDD,0x03,0x11,0x42,0xC1,0xA6,0x37,0x12,0x30,0x8A,0x01,0x11,0x84,0x07,0xC0,0x2F, ++ 0x31,0x92,0x31,0x0A,0xC7,0x14,0xB8,0xFF,0xF9,0x77,0x30,0x12,0x30,0x8A,0x01,0x01, ++ 0x83,0x07,0xC0,0xDF,0xE0,0x03,0x41,0x01,0x80,0xBE,0x69,0xB2,0x44,0x43,0x97,0x3D, ++ 0x4F,0x04,0x01,0x43,0x40,0x7A,0x08,0x09,0x81,0x0B,0x30,0x12,0x30,0x8A,0x01,0x11, ++ 0x83,0x07,0xC0,0x5F,0x30,0x1A,0xB1,0x04,0x08,0x01,0x00,0x09,0xD0,0x14,0x80,0x07, ++ 0xC8,0xAF,0xB2,0x04,0xD9,0x0B,0x37,0x1A,0x00,0x11,0xD0,0x14,0x82,0x07,0xC8,0x77, ++ 0x31,0x92,0x31,0x0A,0xC7,0x14,0xB8,0xFF,0xF1,0x37,0x37,0x12,0x30,0x8A,0x01,0x6F, ++ 0x60,0x20,0x02,0x00,0x00,0xD0,0x00,0x01,0x48,0xE0,0x06,0x00,0xF8,0xFB,0x07,0x00, ++ 0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x00,0x01,0x80,0x07, ++ 0xC0,0x27,0x42,0x5A,0x08,0x01,0x80,0x0B,0x01,0x7B,0x37,0x1A,0xB0,0x04,0x08,0x01, ++ 0x00,0x11,0xD0,0x14,0x81,0x07,0xC8,0x57,0x31,0x12,0x31,0x8A,0x00,0x11,0x80,0x07, ++ 0xC0,0xA7,0x51,0x22,0x40,0x83,0x08,0x11,0x18,0x42,0x04,0x83,0x87,0x2D,0xE8,0x85, ++ 0x00,0xD0,0x00,0x01,0x18,0x00,0x04,0x42,0xA8,0x85,0x31,0x12,0x92,0x01,0x46,0x8C, ++ 0x80,0x01,0xC7,0x1B,0x32,0xD8,0x72,0xD8,0x87,0x1B,0x58,0xE2,0x41,0xE3,0x30,0x20, ++ 0xA2,0x16,0x40,0xE3,0x3F,0x20,0xAB,0xE6,0x58,0xCA,0x27,0x41,0x00,0xE3,0x44,0xE3, ++ 0x28,0xF9,0xAF,0x19,0x18,0x62,0x01,0xE3,0xC7,0x23,0x48,0x20,0x8A,0x1E,0xF0,0x48, ++ 0x20,0x48,0x60,0x48,0x88,0xC6,0x4F,0x01,0x88,0x36,0x40,0xC3,0x08,0x81,0x18,0x42, ++ 0x07,0xC3,0x00,0xF9,0x82,0x89,0x04,0x84,0xEF,0x85,0xA9,0x85,0x46,0x63,0x42,0x5B, ++ 0xDF,0xAB,0x72,0x62,0xC0,0xB3,0x71,0x09,0x8E,0x16,0x48,0x63,0x50,0x5B,0xE2,0xAB, ++ 0x41,0x01,0x88,0x0E,0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2, ++ 0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33,0xC1,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33, ++ 0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3,0x1B,0x82,0x35,0x32, ++ 0x00,0x83,0x41,0x73,0xC4,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90, ++ 0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85,0x41,0x09,0x88,0x0E,0x10,0x01,0x00,0xE7, ++ 0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33, ++ 0xC5,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32, ++ 0x40,0x83,0xC1,0xF3,0x1B,0x82,0x35,0x32,0x00,0x83,0x41,0x73,0xC0,0xC3,0x18,0x32, ++ 0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85, ++ 0x41,0x11,0x88,0x0E,0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2, ++ 0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33, ++ 0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3,0x1B,0x82,0x31,0x32, ++ 0x00,0x83,0x41,0x73,0xC4,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90, ++ 0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85,0x47,0x19,0x88,0xE6,0x10,0x01,0x00,0xE7, ++ 0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33, ++ 0xC5,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32, ++ 0x40,0x83,0xC1,0xF3,0x1B,0x82,0x31,0x32,0x00,0x83,0x41,0x73,0xC0,0xC3,0x18,0x32, ++ 0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85, ++ 0xAA,0x85,0x47,0xE3,0x05,0xB0,0xCC,0x20,0x45,0xEB,0xC6,0x68,0x40,0x09,0x88,0x26, ++ 0x45,0xE3,0xC8,0x20,0x44,0xDB,0xC4,0xE8,0x04,0x3F,0x78,0xD2,0xC0,0xFB,0x79,0x09, ++ 0x8E,0x1E,0x48,0xE3,0xCA,0x20,0x55,0xDB,0xC1,0xE8,0x44,0x13,0xF9,0xA0,0xC0,0x5B, ++ 0x40,0x09,0x88,0x76,0x48,0x01,0x88,0x66,0x44,0x83,0x1A,0xC2,0x04,0x83,0x42,0x83, ++ 0x1C,0xC2,0x04,0x83,0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83,0x18,0xC2,0x00,0x83, ++ 0xE8,0x85,0x4F,0x09,0x8A,0x66,0x40,0x83,0x1A,0xC2,0x04,0x83,0x44,0x83,0x1C,0xC2, ++ 0x00,0x83,0x44,0x83,0x18,0xC2,0x04,0x83,0x40,0x03,0x19,0xC2,0x07,0x03,0xE9,0x85, ++ 0x48,0x11,0x88,0x66,0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83,0x18,0xC2,0x04,0x83, ++ 0x40,0x83,0x1A,0xC2,0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83,0xE8,0x85,0x4F,0x19, ++ 0x89,0xE6,0x47,0x03,0x19,0xC2,0x04,0x03,0x44,0x83,0x18,0xC2,0x02,0x83,0x40,0x83, ++ 0x1A,0xC2,0x04,0x83,0x40,0x83,0x1C,0xC2,0x07,0x83,0xEC,0x85,0xA8,0xFD,0xF7,0x4C, ++ 0x30,0x62,0x2C,0x01,0x4D,0x93,0x49,0x8B,0x32,0x72,0xDC,0xE3,0x33,0x3A,0x49,0x8A, ++ 0xC0,0x4B,0x48,0x09,0x89,0x0E,0x50,0x93,0xE0,0xE3,0x40,0x19,0x80,0x96,0x31,0x79, ++ 0x49,0x5A,0x13,0xB0,0x40,0x11,0x88,0xB6,0x32,0x02,0x1B,0x3A,0x58,0x52,0xC3,0x14, ++ 0xC1,0x00,0xC6,0xC0,0x33,0x9A,0x33,0x2A,0xEA,0xDA,0x0A,0x5B,0x08,0x01,0x00,0x3F, ++ 0xC1,0x1B,0x18,0x9A,0x41,0xAB,0x00,0x5B,0xEA,0x90,0xE0,0x00,0xE6,0x48,0x92,0x4D, ++ 0x17,0x0A,0x9D,0xAE,0xE8,0xFD,0x47,0x01,0x88,0x8E,0x18,0x01,0x12,0x5B,0x46,0xDA, ++ 0x45,0x33,0x40,0xB0,0x00,0xB0,0x05,0x33,0x00,0x1B,0x02,0x5B,0x40,0x0B,0x18,0x81, ++ 0x18,0xCA,0x04,0x0B,0x44,0x0B,0x18,0x01,0x18,0xCA,0x00,0x0B,0x00,0x17,0x40,0x09, ++ 0x89,0x06,0x30,0xAA,0x00,0x01,0x00,0x27,0x40,0x8B,0x00,0x6B,0xEA,0x90,0xE0,0x00, ++ 0x95,0x05,0x16,0x02,0x9F,0xC6,0xEF,0xFD,0x3B,0x82,0xAB,0x85,0x4A,0xA3,0xD8,0xEB, ++ 0x33,0x70,0x72,0xB0,0x48,0x5A,0xC2,0x4B,0x48,0x09,0x88,0x0E,0x50,0xA3,0xE0,0xEB, ++ 0x08,0x01,0x00,0x3F,0x42,0x13,0x41,0x93,0x00,0x92,0x07,0x14,0xEC,0x20,0xE1,0x00, ++ 0xE6,0x48,0x92,0x4D,0x17,0x4A,0x9D,0xAE,0xEB,0x85,0xAB,0xC5,0x30,0x2A,0x30,0xB2, ++ 0x61,0xF2,0x41,0x03,0x14,0x01,0x1C,0x82,0x01,0x03,0x41,0x03,0x10,0x81,0x18,0x82, ++ 0x01,0x03,0x41,0x03,0x10,0x09,0x18,0x82,0x07,0x03,0xE1,0x53,0x00,0xF9,0x87,0x81, ++ 0x19,0x12,0x40,0xBA,0x10,0x13,0x16,0x99,0x00,0x13,0x13,0x41,0x04,0x13,0x14,0xD9, ++ 0xE8,0x92,0x52,0x01,0x80,0x16,0x10,0xC9,0x00,0x13,0x00,0x0F,0x10,0x89,0x00,0x13, ++ 0x31,0x52,0x30,0x5A,0x08,0x01,0x00,0x09,0xB7,0x04,0xB8,0xFF,0xF9,0x7F,0x33,0x52, ++ 0x30,0x8A,0x01,0x11,0xBB,0xFF,0xF7,0xCF,0x42,0x03,0x3B,0x00,0xAB,0xE6,0xEF,0xC5, ++ 0xAC,0x9D,0x87,0x8D,0xCA,0x94,0xC8,0x4B,0x88,0x84,0xE0,0x94,0xA7,0x01,0xD2,0x1B, ++ 0xD8,0x0B,0x89,0x04,0xCA,0x94,0xD8,0x6B,0x30,0x0A,0x88,0x71,0x30,0x62,0xCC,0x94, ++ 0x30,0x01,0xE8,0x4B,0x48,0x09,0x88,0x56,0x08,0x01,0x00,0x27,0xC5,0x38,0x9A,0xF3, ++ 0xA2,0x32,0xE2,0x48,0x90,0x4D,0xD2,0x94,0xDC,0x93,0x12,0x52,0xE0,0xB6,0x57,0xDA, ++ 0x04,0xB3,0x02,0xB3,0x00,0xB3,0x0E,0x01,0x18,0x4A,0x06,0x8B,0xCA,0x94,0xD8,0x4B, ++ 0xB0,0x8B,0x08,0x01,0x50,0xAA,0x30,0x01,0x05,0x78,0xC4,0xF8,0x0A,0xF3,0xC1,0x90, ++ 0xB2,0xB3,0xE2,0x48,0x90,0x4D,0x4A,0x11,0xD8,0xA6,0xCF,0x94,0xE8,0x4B,0x48,0x29, ++ 0xCD,0xF6,0x03,0x48,0xC3,0x48,0x00,0x50,0xC0,0x70,0x54,0x6A,0xC0,0xB0,0xB5,0x14, ++ 0xC0,0x48,0x8C,0x0C,0x30,0x12,0x33,0x32,0xB0,0xE1,0x08,0x01,0x88,0x34,0x48,0x4A, ++ 0x88,0x6C,0x88,0x64,0x30,0x32,0x04,0x01,0x32,0x22,0x04,0x97,0x18,0x00,0x04,0x42, ++ 0x00,0x01,0x00,0x42,0x00,0xD0,0x00,0x01,0x60,0x20,0x02,0x00,0x80,0x40,0x07,0x01, ++ 0x48,0xE0,0x06,0x00,0x78,0xF8,0x07,0x00,0xC8,0x14,0x00,0x01,0xF0,0x42,0xF8,0x0C, ++ 0x0B,0x01,0xF0,0xCA,0x32,0x7A,0xD0,0x08,0x97,0x4D,0x48,0xF9,0xEF,0x06,0x08,0xF9, ++ 0xCB,0x38,0x86,0xF8,0x78,0xF9,0xEF,0x06,0x3B,0xF9,0x37,0x82,0x82,0x3B,0xE0,0x00, ++ 0x30,0x32,0xC4,0xBB,0x10,0xFA,0x9C,0x46,0x10,0xCA,0xDC,0x36,0x46,0x84,0xD9,0x48, ++ 0xC0,0x00,0x92,0x05,0x04,0x84,0x81,0x08,0x04,0x37,0x10,0xCA,0xDC,0x16,0x00,0x78, ++ 0x00,0xBC,0x01,0x0F,0x39,0x01,0x00,0xBC,0x10,0xCA,0xDC,0x0E,0x38,0x09,0xB8,0x34, ++ 0x43,0x78,0x2B,0x3A,0xE8,0x26,0xF8,0x6C,0x10,0x7A,0xEC,0x2E,0x88,0x6C,0x00,0x1F, ++ 0xFC,0x64,0x10,0x7A,0xE8,0x06,0x88,0x64,0x82,0x8B,0xE0,0x90,0xE0,0xB0,0xC5,0x14, ++ 0xE0,0x00,0x84,0x14,0xC4,0x0C,0xE0,0x00,0x83,0x0C,0x30,0x02,0xE2,0x00,0x92,0x05, ++ 0x35,0x22,0x2C,0x62,0xD8,0xC6,0xC5,0x34,0x40,0x01,0x80,0x8E,0x08,0x01,0x00,0x01, ++ 0x80,0x5C,0xC0,0x04,0xC2,0x00,0x46,0x00,0x80,0x7C,0xC0,0x04,0x30,0x00,0x72,0x00, ++ 0x80,0x74,0x00,0x01,0x30,0x22,0x84,0x2C,0x80,0x24,0x80,0x1C,0xF0,0x90,0x02,0x07, ++ 0x03,0x1F,0xF5,0x40,0x94,0x05,0x32,0x32,0x03,0xFF,0x31,0x02,0x04,0x00,0x32,0x22, ++ 0xC2,0x2C,0x00,0x00,0x80,0x2C,0xC0,0x24,0x00,0x00,0x82,0x24,0xC2,0x1C,0x00,0x00, ++ 0x83,0x1C,0x40,0x40,0x28,0x82,0xEB,0x26,0xC0,0x83,0xF0,0x6C,0xD8,0x00,0x84,0x83, ++ 0x00,0x1F,0xC0,0x83,0xF4,0x64,0xD8,0x00,0x80,0x83,0xC0,0x83,0x73,0x3D,0x30,0xBA, ++ 0xA8,0x82,0xC7,0x83,0x10,0xC2,0xDC,0xDE,0xE2,0x48,0x92,0x4D,0xF1,0x5C,0xC0,0xB0, ++ 0x90,0xB5,0xB1,0x5C,0x30,0x32,0x3B,0x09,0x1D,0xF2,0x31,0xA2,0xF5,0x7C,0x10,0x82, ++ 0xD8,0x76,0xF0,0x2C,0x18,0xF2,0xB1,0x2C,0xF5,0x04,0x10,0x82,0xD8,0x46,0xF0,0x24, ++ 0x18,0xF2,0xB1,0x24,0xF5,0x74,0x10,0x82,0xD8,0x16,0xC0,0x1C,0x18,0xC2,0x81,0x1C, ++ 0xF3,0x90,0x32,0x82,0xF2,0x00,0x92,0x05,0x33,0x32,0x34,0x82,0x45,0x01,0xD0,0xE6, ++ 0x42,0xE2,0xB7,0x0B,0xD0,0x50,0xB3,0x13,0x36,0x12,0x1B,0x92,0x03,0x13,0x30,0x12, ++ 0x08,0x13,0xD0,0x2C,0x00,0x13,0xD2,0x24,0x00,0x13,0xD4,0x1C,0x00,0x13,0x36,0x01, ++ 0x00,0xA7,0xC1,0x5C,0x86,0x07,0xE8,0xA7,0x90,0x05,0x80,0x5C,0x4D,0x8A,0x07,0x80, ++ 0xC0,0x00,0x4A,0x13,0x40,0x3D,0x08,0x01,0x1C,0x01,0x30,0xF2,0x30,0xE2,0x04,0xCF, ++ 0x38,0x98,0x86,0x7E,0xC0,0x1B,0xF8,0x5C,0xD8,0xD8,0x96,0xDD,0x58,0x01,0xE8,0x36, ++ 0x83,0x1B,0x20,0x9A,0x94,0xDD,0x36,0xF2,0xE2,0x48,0x92,0x4D,0x00,0x27,0x18,0x01, ++ 0x80,0x1B,0x00,0x0F,0x18,0x01,0x80,0x1B,0x42,0x90,0xE2,0x00,0x32,0x1A,0xE3,0xD8, ++ 0x94,0xDD,0x32,0xE2,0x2F,0x62,0xDD,0x1E,0xE3,0xB0,0x93,0xB5,0x30,0x82,0x83,0x5C, ++ 0x45,0xE2,0x06,0x98,0xC0,0xD8,0x08,0xD3,0xCA,0x00,0xB4,0x0B,0x48,0x21,0xD8,0x0E, ++ 0x76,0x09,0xD8,0x36,0x06,0x01,0x50,0xBA,0x04,0x08,0xC4,0x58,0xE4,0x08,0x02,0x70, ++ 0xC0,0xB0,0x4D,0xEB,0x4D,0xB3,0x19,0xAA,0x08,0xEB,0xC0,0x80,0xF4,0x1B,0xF2,0x2B, ++ 0xDA,0xD8,0xB2,0x1B,0x90,0x45,0x42,0x09,0xD8,0x76,0x07,0x09,0xA6,0x03,0x43,0x6A, ++ 0x0E,0x19,0x40,0x13,0x50,0x01,0x80,0x16,0x03,0x29,0xA0,0x0B,0x04,0xF7,0x40,0x13, ++ 0x50,0x01,0x80,0x16,0x03,0x21,0xA0,0x0B,0x02,0xC7,0x40,0x0B,0x48,0x01,0x80,0x1E, ++ 0x00,0x19,0x08,0x11,0xA0,0x0B,0x03,0x8F,0x48,0x03,0x40,0x01,0x88,0x26,0xC0,0x94, ++ 0x86,0x01,0xCE,0x03,0x40,0x51,0x98,0x0E,0x00,0x11,0x00,0x3F,0xC1,0x94,0x80,0x01, ++ 0xE0,0x03,0x44,0x01,0x80,0x0E,0x00,0x11,0x00,0x07,0x00,0x09,0xE4,0x0B,0xE3,0x50, ++ 0xA3,0x13,0xDD,0x13,0x38,0x90,0xA2,0x0E,0xF3,0x48,0xA2,0x0B,0xE8,0x0B,0x13,0x29, ++ 0x10,0x0A,0x94,0x0E,0xA8,0x13,0x01,0xEF,0x10,0x0A,0xCC,0x46,0x40,0x09,0x88,0x16, ++ 0x09,0x81,0xAF,0x0B,0x00,0xB7,0xD0,0x48,0x01,0x52,0xAC,0x13,0x00,0x97,0x40,0x19, ++ 0xC8,0x0E,0x08,0x19,0x02,0x07,0x90,0x0D,0xE8,0x13,0x51,0x01,0x82,0x16,0xF0,0x90, ++ 0xA8,0x13,0x01,0x3F,0xD2,0x94,0xF0,0x48,0xCA,0x93,0x1C,0x52,0xCA,0x84,0xC0,0x88, ++ 0xD0,0x94,0x88,0x8B,0xA8,0x03,0x83,0x9D,0xEF,0x85,0xAF,0xBD,0x80,0x6D,0x34,0x6A, ++ 0xD9,0x63,0x33,0x42,0x80,0x01,0x82,0x64,0xD0,0x03,0x84,0x3C,0xC2,0x64,0xD8,0x03, ++ 0x30,0x00,0xA8,0x1E,0x02,0xD9,0xEC,0x02,0x40,0x01,0x80,0xA6,0xC5,0x6C,0x00,0x08, ++ 0xC3,0x40,0x00,0x08,0x52,0xC2,0xC4,0x08,0xC4,0x48,0xC4,0x10,0x00,0x01,0x18,0x01, ++ 0x00,0x2F,0x00,0x5C,0x04,0x9C,0xE0,0x48,0xE2,0x90,0xE4,0x00,0x95,0x05,0x12,0x02, ++ 0xD8,0xBE,0x87,0x85,0xEB,0x85,0x07,0x59,0xCA,0x6C,0x08,0x00,0xC4,0x40,0x70,0x7A, ++ 0xF7,0x03,0x08,0x83,0xD0,0x7C,0x90,0x04,0x30,0x5A,0x09,0x01,0x00,0x11,0xD0,0x6C, ++ 0xBB,0xFF,0xEF,0xE7,0x42,0x4A,0x84,0x01,0x43,0x0B,0x30,0x5A,0x09,0xCC,0x5C,0x8B, ++ 0x0B,0xCC,0x5E,0x8B,0x15,0xCC,0x58,0x8B,0x17,0xCC,0x42,0x8B,0x14,0xCC,0x4C,0x22, ++ 0x46,0x53,0x10,0xD4,0x48,0x93,0x1F,0xD4,0x17,0x89,0x00,0x93,0x13,0x19,0x18,0x93, ++ 0x40,0x53,0x18,0x11,0x18,0xD2,0x04,0x53,0x40,0x0B,0x18,0xCA,0x01,0x0B,0x30,0x42, ++ 0xE9,0x4B,0x81,0x01,0x80,0x5C,0x48,0x09,0x8D,0x5E,0x6A,0x44,0x81,0x14,0x30,0x8A, ++ 0x5E,0x43,0x94,0x35,0xB0,0x0C,0x00,0x01,0x80,0x04,0xD0,0x6C,0x4F,0x92,0x03,0x00, ++ 0xC2,0x00,0xC4,0x00,0x83,0x54,0x40,0x8A,0x18,0x33,0x0A,0x01,0x37,0x42,0xB9,0xFF, ++ 0xE0,0x5F,0xF9,0x54,0xC1,0x64,0x30,0x5A,0xD1,0x0B,0x32,0xC2,0xD7,0x7C,0xB8,0xFF, ++ 0xEB,0x67,0x4C,0x62,0x10,0x01,0x00,0x01,0x02,0x67,0x00,0x18,0x37,0xE2,0xF4,0xDA, ++ 0x10,0x5A,0xD4,0x0E,0x33,0x0A,0xD3,0xCA,0x10,0x9A,0xEC,0x0E,0x35,0x12,0xD3,0xD2, ++ 0xE2,0x00,0x92,0x05,0x17,0x02,0xDD,0x86,0xC4,0x14,0xE0,0x00,0x10,0x0A,0x9C,0x36, ++ 0xC0,0x04,0x40,0x01,0x8B,0x9E,0x40,0x80,0x40,0x08,0xC2,0x70,0x00,0x3F,0xC0,0x14, ++ 0xF4,0x00,0x14,0x12,0xE0,0x5E,0x00,0x09,0x83,0x04,0xE0,0xB0,0x90,0xB5,0x77,0x01, ++ 0x80,0x16,0xC0,0x0C,0x16,0x32,0x9C,0x36,0x70,0x01,0x88,0x06,0x30,0x09,0xC0,0x5C, ++ 0x90,0x33,0xC0,0x5C,0xD2,0x0B,0x40,0x8A,0x18,0x0B,0x32,0x01,0x36,0x42,0x81,0x01, ++ 0x81,0x4C,0x80,0x01,0x83,0x44,0x00,0x37,0xC4,0x3C,0x10,0x32,0xD0,0x6E,0xC0,0x44, ++ 0xC0,0x03,0xC8,0x44,0x32,0x00,0x72,0x00,0x82,0x43,0x40,0x42,0x0C,0x41,0x00,0x0B, ++ 0x47,0x0B,0x10,0xF9,0x90,0x21,0x18,0x8A,0x00,0x0B,0xC8,0x6C,0x02,0x00,0xC5,0x08, ++ 0x02,0x00,0x53,0x0A,0xC4,0x40,0xC0,0x00,0xC0,0x48,0x74,0x01,0x88,0x66,0x10,0x01, ++ 0x78,0x02,0x02,0x37,0x18,0x01,0x00,0x1C,0x04,0x7C,0xE0,0x00,0xE2,0x48,0xE4,0x90, ++ 0x95,0x95,0x12,0x12,0xD9,0xB6,0x07,0x07,0xDF,0x6C,0x00,0x10,0xC1,0x90,0x5E,0xB2, ++ 0xC4,0x90,0x36,0xA2,0x18,0x01,0x00,0x9F,0x30,0x3A,0x13,0x01,0xF0,0xD2,0x3D,0x01, ++ 0xFC,0x3A,0x16,0xBA,0xD0,0x06,0x00,0x14,0x3E,0x01,0xF8,0x7A,0x10,0xBA,0xEC,0x06, ++ 0x04,0x54,0xE0,0x00,0xE3,0x48,0x34,0x12,0xE4,0x90,0x34,0xA2,0xE2,0xD8,0x92,0xDD, ++ 0x17,0x1A,0xDD,0x4E,0xC4,0x3C,0x10,0x32,0x80,0x06,0xC1,0x44,0xC6,0x03,0x48,0x00, ++ 0x88,0x1E,0xC0,0x4C,0xC8,0x03,0x42,0x31,0x88,0xBE,0xC7,0x4C,0xC8,0x03,0x42,0x31, ++ 0x89,0x26,0x40,0x12,0x40,0x0B,0x10,0x81,0x18,0x8A,0x00,0x0B,0xCF,0x6C,0x00,0x00, ++ 0xC0,0x00,0x4A,0xEA,0xC0,0x00,0xCA,0x64,0x32,0x5A,0xD1,0x4B,0xD7,0x7C,0xB8,0xFF, ++ 0xE3,0x67,0xE7,0xB0,0x90,0xB5,0xC3,0x3C,0x14,0x32,0xEC,0xAE,0x43,0xBA,0x30,0x5A, ++ 0x4A,0xCC,0x84,0x01,0x00,0x0B,0x40,0xAA,0x48,0xCC,0x1E,0x0B,0x52,0xCC,0x18,0x0B, ++ 0x54,0xCC,0x1A,0x0B,0x56,0xCC,0x04,0x0B,0x4E,0x8A,0x50,0xD4,0x00,0x53,0x58,0xCC, ++ 0x0F,0x0B,0x36,0xB7,0xAA,0x85,0xD8,0xE3,0x1A,0x0A,0x03,0x48,0xC5,0x50,0x0C,0x49, ++ 0x02,0x48,0xC4,0x88,0xE8,0xD3,0x50,0x11,0xC0,0x4E,0x10,0x01,0x00,0x2F,0x40,0x1C, ++ 0x04,0x5C,0xE0,0x48,0xE2,0x00,0xE4,0x90,0x95,0x95,0x12,0x12,0xD8,0xBE,0x17,0x01, ++ 0x00,0x87,0x00,0x00,0x80,0x40,0x07,0x01,0x48,0xE0,0x06,0x00,0x00,0x01,0x00,0x42, ++ 0x18,0x00,0x04,0x42,0xF8,0xFB,0x07,0x00,0x40,0x1C,0x00,0x5C,0xE4,0x00,0xE4,0x48, ++ 0xE2,0x90,0x92,0x95,0x17,0x12,0xDD,0xBE,0xEF,0x85,0xA8,0x85,0x30,0x6A,0xF0,0x2C, ++ 0x30,0x22,0x30,0x8A,0x31,0xFA,0x30,0xC2,0xB9,0xFF,0xDF,0xB7,0x31,0xDA,0x31,0x92, ++ 0x31,0x4A,0x31,0x02,0xBC,0xFF,0xE7,0xCF,0xE8,0x85,0x37,0x0A,0x8D,0x01,0x86,0x01, ++ 0x02,0x5F,0xC8,0x5B,0x58,0x31,0x88,0x46,0x40,0xFA,0x47,0x0B,0x10,0x81,0x18,0x8A, ++ 0x00,0x0B,0x40,0x0B,0x18,0x8A,0x00,0x0B,0x3E,0x82,0xCB,0x1B,0x5F,0x01,0x88,0x86, ++ 0x38,0x82,0xAB,0x85,0xDA,0x5B,0xD8,0x4B,0x1F,0x5A,0x4A,0xC2,0xC7,0x08,0x52,0xC2, ++ 0xC0,0x00,0x14,0x01,0x00,0x27,0x40,0x24,0x04,0x64,0xE0,0x00,0xE2,0x48,0xE4,0x90, ++ 0x17,0xD2,0x9C,0xC6,0xEF,0x85,0xA8,0xBD,0x80,0x15,0x34,0x62,0x37,0xBA,0xD8,0x33, ++ 0xE8,0x03,0x09,0x01,0x18,0x4A,0x2E,0x01,0x40,0x29,0x90,0x16,0x1F,0x0B,0x1D,0x2B, ++ 0x07,0x6F,0x00,0x09,0xEA,0x02,0x38,0x00,0xAF,0x26,0x50,0x52,0x58,0x03,0x1F,0x82, ++ 0x18,0x03,0x05,0x27,0x57,0x3A,0x5F,0x03,0x18,0x92,0x1E,0x82,0x1D,0x03,0x1D,0x0B, ++ 0x30,0x0A,0xC1,0x14,0xBC,0xFF,0xE7,0xE7,0x25,0x2B,0x59,0x03,0x28,0x01,0x00,0x17, ++ 0x43,0x00,0xE2,0x68,0x96,0x6D,0x3F,0x08,0x8D,0x0E,0x10,0xAA,0x9B,0xC6,0xAF,0x2B, ++ 0x73,0xCA,0x4E,0x04,0x00,0x83,0xC7,0x14,0x0A,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00, ++ 0xF7,0x03,0x08,0x83,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBC,0xFF,0xDF,0x87, ++ 0x30,0x1A,0xB9,0x04,0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD8,0xFF,0x06,0x09, ++ 0xA7,0x01,0x8D,0x03,0x48,0x82,0x46,0x43,0x10,0x11,0x18,0x82,0x00,0x43,0x00,0x41, ++ 0x01,0x83,0x45,0x83,0x08,0xF9,0x8F,0x19,0x19,0x42,0x00,0x83,0x87,0x2D,0xE8,0x85, ++ 0x3F,0x82,0xAB,0xC5,0xD8,0x53,0x90,0x04,0xDC,0x53,0x32,0xB2,0xE9,0x53,0x54,0x91, ++ 0x9E,0xBE,0x12,0x31,0xE0,0x92,0x52,0x01,0x8E,0x9E,0x52,0x02,0xC0,0x28,0x34,0x12, ++ 0x91,0xE1,0x19,0xC1,0x8E,0x01,0xF4,0x1A,0xE8,0x63,0x3A,0x11,0x10,0x1A,0xDD,0x16, ++ 0xD8,0xD8,0x38,0x1C,0xA9,0x7B,0x1E,0xD1,0xEE,0x63,0xF4,0x1A,0x15,0x32,0x13,0x9A, ++ 0xE0,0x16,0xC8,0xD8,0x38,0x1C,0xB2,0x7B,0x30,0x01,0x38,0x01,0x1C,0x01,0x30,0xE2, ++ 0x00,0x27,0x21,0x01,0x00,0xE7,0x18,0x01,0xF0,0x5A,0x5F,0x01,0xED,0x4E,0x10,0x9A, ++ 0xE8,0x06,0x30,0xF2,0xE8,0x5B,0x5E,0x01,0x80,0x76,0x40,0x9C,0xF0,0xD8,0x02,0x9C, ++ 0x00,0x57,0x58,0x01,0xD5,0x46,0x10,0xDA,0xD0,0x06,0x30,0xFA,0xF0,0x5B,0x58,0x01, ++ 0x80,0x16,0x40,0x9C,0xE0,0xD8,0x02,0x9C,0xE4,0x68,0xE5,0x90,0xE7,0x20,0x93,0x25, ++ 0x2F,0xA2,0x9B,0x06,0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x36,0xE2,0xE5,0x04,0x28,0x22, ++ 0x98,0xBE,0x7E,0x14,0xC8,0x90,0x3C,0x14,0x7E,0x14,0xCA,0x90,0x3E,0x14,0xEA,0x43, ++ 0x40,0x01,0x80,0x0E,0xF6,0x00,0xAA,0x43,0xF0,0x43,0x40,0x01,0x82,0x0E,0xF0,0x00, ++ 0xB7,0x43,0xE8,0xC5,0xAC,0xBD,0x87,0x15,0x30,0x62,0x30,0xBA,0xEF,0x2B,0xDB,0x33, ++ 0xDB,0x03,0x1B,0x42,0x00,0x08,0xC2,0x14,0xC4,0x40,0x48,0x8A,0xC0,0x00,0x82,0x0C, ++ 0x37,0x02,0x81,0x01,0xC4,0x0B,0x10,0x01,0x18,0x8A,0x80,0x0B,0x00,0x21,0xEE,0x02, ++ 0x44,0x01,0x80,0x1E,0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42,0xBF,0xFF,0xD7,0xC7, ++ 0x30,0x1A,0xB9,0x04,0x08,0x01,0x00,0x19,0xD7,0x14,0xB8,0xFF,0xDA,0x3F,0x02,0x41, ++ 0xE9,0x0A,0x30,0x1A,0x30,0xD2,0xC1,0x0C,0xBC,0xFF,0xDF,0x7F,0x31,0x1A,0x31,0x4A, ++ 0xD0,0x14,0xC0,0x0C,0xBD,0xFF,0xF7,0xB7,0x50,0x02,0x1C,0x09,0xC0,0x83,0x40,0x01, ++ 0x8B,0x5E,0xE0,0x68,0x95,0x6D,0x5F,0x0B,0x03,0x0F,0xE0,0x68,0x90,0x6D,0x37,0xC2, ++ 0x00,0x42,0x15,0x0A,0x8D,0x0E,0x10,0xAA,0x99,0xBE,0x37,0x82,0x74,0x92,0x13,0x2A, ++ 0x93,0xE6,0xA8,0x2B,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBE,0xFF,0xD7,0x47, ++ 0x30,0x1A,0xB9,0x04,0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD8,0xBF,0xC0,0x14, ++ 0x0A,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00,0xF7,0x03,0x08,0x83,0x05,0x41,0x00,0x83, ++ 0x47,0x83,0x09,0xF9,0x88,0x19,0x18,0x42,0x01,0x83,0x39,0xBF,0xE1,0x0B,0x31,0x02, ++ 0x80,0x01,0x4D,0x01,0x86,0x1E,0xC9,0x0B,0x49,0x09,0x88,0x06,0x0E,0x11,0x88,0x0B, ++ 0xA8,0x2B,0x83,0x9B,0x4F,0x04,0x01,0x83,0x50,0x0A,0xCB,0x14,0xDC,0x03,0xC1,0x48, ++ 0xE7,0x02,0x0A,0x83,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBC,0xFF,0xD7,0xC7, ++ 0x30,0x1A,0xB9,0x04,0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD0,0x3F,0x07,0x41, ++ 0x01,0x83,0x45,0x83,0x08,0xF9,0x8F,0x19,0x19,0x42,0x00,0x83,0x38,0x77,0x08,0x01, ++ 0x88,0x0B,0x86,0x8B,0x3F,0x57,0xA8,0x85,0x84,0x9D,0x34,0x22,0x33,0x6A,0xD8,0x73, ++ 0xD8,0x43,0x81,0x34,0x31,0x12,0x93,0xE1,0x92,0x94,0x48,0x72,0x32,0x02,0xC3,0x18, ++ 0x4B,0x32,0x22,0x0A,0x8B,0x8C,0xC8,0x43,0x00,0x00,0x82,0x1C,0x00,0x01,0x80,0x14, ++ 0x37,0x42,0x81,0x01,0x82,0x84,0xC0,0x03,0x5C,0x7B,0x35,0x32,0x3F,0x20,0x5A,0x43, ++ 0x18,0x3A,0x60,0x01,0xD1,0x46,0x40,0xFA,0x18,0x3A,0xB8,0x0C,0x37,0x82,0x23,0xD9, ++ 0x00,0x02,0xE1,0x84,0x80,0x03,0x03,0x47,0x46,0xD2,0x19,0x02,0x18,0x3A,0xB8,0x0C, ++ 0x30,0x82,0x23,0x21,0x18,0x02,0xE1,0x84,0x80,0x03,0x3B,0x01,0x19,0x7B,0x37,0x42, ++ 0x80,0x01,0x85,0x7C,0xC0,0x03,0x84,0x54,0xC0,0x7C,0x20,0x09,0xB8,0x22,0xA0,0x4C, ++ 0x34,0x42,0x81,0x01,0x86,0x74,0x18,0x3B,0xB8,0x44,0xC0,0x74,0x18,0x3B,0xBC,0x3C, ++ 0x31,0x42,0x81,0x01,0x84,0x6C,0xA0,0x3B,0xCA,0x43,0x45,0x00,0x86,0x2C,0x00,0x01, ++ 0xFB,0x22,0x82,0x00,0x81,0x24,0xE8,0x43,0x40,0x29,0xC0,0xBE,0x03,0x01,0x30,0x22, ++ 0x3B,0x04,0x39,0x04,0x20,0x01,0x00,0x77,0x00,0x01,0x00,0x47,0x40,0x7C,0x00,0xFC, ++ 0x40,0x7C,0x00,0xBC,0xE4,0x90,0xE4,0x48,0xE2,0xD8,0xE4,0x00,0x95,0x05,0x12,0x82, ++ 0xDB,0xA6,0xE7,0x20,0x90,0x25,0xC3,0x34,0x17,0x22,0xDC,0x6E,0xF8,0x94,0xE0,0x8C, ++ 0x00,0x01,0x80,0x5C,0x00,0xAF,0x05,0x01,0x34,0x32,0x34,0x22,0xC8,0x5C,0x00,0x09, ++ 0x00,0x42,0xCC,0x0C,0x80,0x64,0x10,0x42,0x81,0x7E,0xE3,0x53,0x50,0x01,0x80,0x2E, ++ 0xC8,0x34,0xC0,0x5C,0xF4,0x48,0x12,0x42,0x88,0x06,0x30,0xB2,0x1A,0x01,0x00,0x87, ++ 0x41,0xCC,0x41,0x14,0xD0,0x40,0x94,0x15,0x00,0x14,0xC9,0x1C,0x10,0x52,0xD4,0x3E, ++ 0x32,0x02,0xE3,0x00,0x94,0x05,0x36,0x22,0x34,0x82,0xC3,0x00,0x94,0x05,0x30,0x32, ++ 0xCC,0x2C,0x10,0x52,0xE8,0x3E,0x01,0x7F,0x00,0x01,0x00,0x42,0x48,0xE0,0x06,0x00, ++ 0x38,0xA0,0x03,0x00,0xAA,0xAA,0xAA,0xAA,0x18,0x00,0x04,0x42,0x00,0xD0,0x00,0x01, ++ 0x68,0xB8,0x03,0x00,0x28,0x60,0x00,0x00,0xCC,0x4B,0x13,0x8A,0xE7,0x1E,0x58,0x43, ++ 0xC8,0x64,0x18,0x0A,0x18,0x4B,0xCF,0x6C,0xE8,0x4B,0x4A,0x09,0x88,0x16,0xC8,0x6C, ++ 0x02,0x09,0xAC,0x43,0xCC,0x54,0x10,0x52,0xE8,0xBE,0x08,0x09,0xD4,0x44,0x00,0xCA, ++ 0x18,0x8A,0x88,0x44,0x00,0x8F,0xC8,0x24,0x10,0x52,0xD4,0x76,0xCA,0x6C,0xE8,0x4B, ++ 0x48,0x09,0x88,0x16,0xCC,0x6C,0x00,0x09,0xA8,0x43,0xCA,0x4C,0x10,0x52,0xD4,0x26, ++ 0x08,0x09,0xD0,0x3C,0x00,0xCA,0x1C,0x8A,0x8D,0x3C,0xE0,0x20,0xE2,0xF8,0xE5,0xD8, ++ 0x95,0xDD,0x12,0x9A,0xD8,0x66,0xC5,0x7C,0xC8,0x03,0x44,0x01,0x83,0x2E,0x32,0x02, ++ 0x40,0x11,0xC8,0x2E,0x33,0x0A,0x33,0x82,0x83,0x07,0xC8,0xD7,0x90,0x05,0x00,0x07, ++ 0x03,0x01,0x00,0x88,0xD0,0x20,0x13,0x01,0x01,0x57,0x01,0x67,0x40,0x01,0xE8,0x7E, ++ 0x0B,0x01,0xF0,0x0A,0xDC,0x1C,0x10,0xCA,0xD2,0xB6,0xE0,0x18,0x10,0xCA,0xEC,0x16, ++ 0xD1,0x48,0x00,0x0C,0x00,0x87,0x48,0x01,0xE8,0x76,0x08,0x09,0x00,0x0C,0x01,0x5F, ++ 0x0B,0x01,0xF0,0x0A,0x10,0x0A,0xD4,0x16,0xD1,0x48,0x00,0x0C,0x00,0x27,0x48,0x01, ++ 0xD0,0x16,0x08,0x01,0x19,0x4A,0x06,0x0C,0x0B,0x01,0xF0,0x0A,0xDC,0x24,0x10,0xCA, ++ 0xD0,0x1E,0xC8,0x14,0xE6,0x48,0x92,0x4D,0x8D,0x14,0xE0,0x20,0xE2,0x90,0x92,0x95, ++ 0x16,0x92,0xDD,0x9E,0x00,0x4F,0x00,0x01,0x08,0x01,0x00,0x27,0x05,0x0C,0xE1,0x20, ++ 0xE2,0xF8,0xE5,0x00,0x95,0x05,0x12,0x82,0xD8,0xC6,0xC7,0x5C,0xE2,0x00,0x92,0x05, ++ 0x80,0x5C,0xC8,0x34,0xC4,0x5C,0x10,0x42,0xD2,0x06,0x38,0x27,0xC9,0x43,0x41,0x71, ++ 0xC9,0x0E,0x00,0x71,0x88,0x43,0xC1,0x14,0xCC,0x4B,0x41,0x00,0xC6,0x40,0x90,0x05, ++ 0x8A,0x43,0x41,0x81,0xCA,0x0E,0x00,0x81,0x88,0x43,0x01,0x01,0x29,0x44,0x37,0x44, ++ 0xC0,0x74,0xC8,0x44,0x18,0x0B,0xCE,0x74,0xC4,0x3C,0x18,0x43,0x87,0x9D,0xE8,0x85, ++ 0xA8,0x85,0x33,0x2A,0x30,0x62,0x30,0xB2,0x31,0x0A,0x31,0x42,0xBA,0xFF,0xEF,0xCF, ++ 0x48,0x6A,0x03,0x01,0x81,0x43,0x30,0x92,0x31,0x0A,0x31,0x42,0xBB,0xFF,0xEF,0x1F, ++ 0xEE,0x03,0x41,0x41,0x92,0x0E,0xE0,0x00,0xAB,0x03,0xE9,0x85,0x10,0x01,0x00,0x37, ++ 0x0A,0x01,0xE0,0x48,0x90,0x4D,0x4C,0xA1,0xCA,0xDE,0xE7,0x90,0x94,0x95,0x14,0x12, ++ 0xCB,0xB6,0x3F,0x82,0x38,0x18,0x78,0xD8,0x14,0x09,0x00,0xD2,0x97,0x95,0x1E,0xF9, ++ 0x08,0xD8,0x00,0xC2,0x5E,0xEA,0xC2,0x00,0x48,0x09,0x88,0x66,0x44,0x0B,0x18,0x8A, ++ 0x02,0x0B,0x40,0x0B,0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B, ++ 0x1E,0x8A,0x04,0x0B,0x38,0x82,0x4B,0x01,0x8A,0x66,0x40,0x0B,0x1A,0x8A,0x04,0x0B, ++ 0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B,0x40,0x0B,0x18,0x8A, ++ 0x03,0x0B,0x38,0x82,0x48,0x11,0x88,0x66,0x44,0x0B,0x18,0x8A,0x02,0x0B,0x40,0x0B, ++ 0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x00,0x0B, ++ 0x38,0x82,0x4B,0x19,0x88,0xE6,0x47,0x0B,0x18,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A, ++ 0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B,0x40,0x0B,0x1A,0x8A,0x03,0x0B,0x3A,0x82, ++ 0xAC,0x8D,0x87,0x3D,0xC0,0x3C,0xC8,0x3C,0x4C,0x00,0x00,0x00,0xC0,0x00,0x3A,0x00, ++ 0x4A,0xDA,0x71,0x00,0xC1,0x28,0x42,0xDA,0x44,0x0B,0x90,0x4D,0x88,0x34,0x58,0x0B, ++ 0x90,0x4D,0x8C,0x2C,0x5C,0x0B,0x92,0x4D,0x8C,0x24,0x58,0x0B,0x90,0x4D,0x8C,0x1C, ++ 0x54,0x0B,0x96,0x75,0x4A,0xA2,0x41,0x53,0x90,0x95,0x94,0x14,0x44,0x53,0x90,0xBD, ++ 0x44,0x13,0x92,0x95,0x91,0x0C,0x58,0x7A,0x98,0x01,0x52,0xD3,0x90,0x95,0x94,0x04, ++ 0x10,0x09,0x00,0x13,0xA8,0x10,0x1C,0x13,0x12,0x81,0x18,0x13,0x18,0x13,0x14,0x79, ++ 0x11,0x13,0x16,0x01,0x00,0x53,0x12,0x89,0x02,0x53,0x40,0x0B,0x10,0x81,0x19,0x8A, ++ 0x07,0x0B,0x02,0xF9,0x80,0x89,0x17,0xC3,0x07,0x09,0xB8,0xFF,0xFF,0x7F,0x03,0xF9, ++ 0x80,0x89,0x14,0xC3,0x07,0x09,0xB8,0xFF,0xF8,0x4F,0x03,0x19,0x11,0x00,0x00,0x43, ++ 0x07,0x09,0xB8,0xFF,0xF8,0x1F,0x0B,0x11,0xC7,0x3C,0xB8,0xFF,0xF8,0x5F,0x23,0xA1, ++ 0x01,0x01,0x40,0x4B,0x30,0x48,0xA8,0x16,0xE7,0x20,0x93,0x25,0x03,0x0F,0xF0,0x20, ++ 0x92,0x25,0xE7,0x00,0x90,0x05,0x46,0x51,0x98,0x9E,0x0F,0x09,0xC7,0x3C,0xB8,0xFF, ++ 0xF8,0xCF,0x42,0x82,0xC8,0x34,0x00,0x0B,0xC8,0x2C,0x18,0x0B,0xCA,0x24,0x18,0x0B, ++ 0xCC,0x1C,0x18,0x0B,0x10,0x33,0x4E,0x62,0xD2,0x14,0x00,0x53,0x00,0x7B,0xC8,0x0C, ++ 0x00,0x0B,0x4A,0x42,0xC2,0x04,0x88,0x01,0x10,0x43,0x60,0xA1,0xC8,0x16,0x00,0x09, ++ 0x87,0x45,0xE8,0x85,0x07,0x01,0x38,0xDF,0x00,0xD0,0x00,0x01,0x80,0x00,0x00,0x42, ++ 0x08,0x01,0x00,0x42,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x00,0x0F,0x00,0x26, ++ 0xF8,0x48,0x48,0x21,0x94,0xDE,0x3F,0x58,0xA8,0x0E,0x00,0x14,0xE6,0x00,0x3C,0x48, ++ 0x80,0x06,0x80,0x13,0x38,0x82,0x4B,0x01,0x86,0x5E,0x38,0x18,0x80,0x16,0x80,0x13, ++ 0xE2,0x00,0xF2,0x48,0x48,0x11,0x98,0x26,0x38,0x18,0xAC,0x16,0x04,0x14,0xE0,0x00, ++ 0xF7,0x48,0x3C,0x1F,0x17,0x01,0x38,0x77,0x16,0x01,0x38,0xFF,0x10,0x01,0x48,0x18, ++ 0x11,0x5A,0x9C,0x66,0x54,0x18,0x10,0x5A,0x98,0x8E,0x18,0x01,0x32,0xE2,0x04,0x77, ++ 0x30,0x1A,0x18,0x5A,0xA0,0xE6,0x11,0x01,0x44,0x18,0x12,0x5A,0x98,0x8E,0x49,0x18, ++ 0x10,0x5A,0x9C,0xE6,0x54,0x18,0x10,0x5A,0x9C,0x0E,0x30,0xA2,0x06,0xFF,0x49,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD6,0x00,0x0C,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x0E,0x58,0xD4,0x00,0x0A,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD2,0x00, ++ 0x08,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD0,0x00,0x0E,0x92,0x42,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD6,0x00,0x0C,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x06,0x58,0xD4,0x00,0x0A,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00, ++ 0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A,0x08,0x92,0x32,0x82,0x3A,0x82,0x03,0xEF, ++ 0x78,0x50,0x86,0x06,0x10,0x4A,0x82,0x18,0x9A,0x06,0x10,0x02,0x00,0x9A,0x12,0x01, ++ 0x30,0xE2,0x4C,0x18,0x11,0x5A,0x9C,0x6E,0x54,0x18,0x10,0x5A,0x9F,0x96,0x10,0xE1, ++ 0x08,0x48,0xD4,0x95,0x54,0x18,0x10,0x5A,0x9C,0x66,0x08,0x48,0x8C,0x90,0x14,0x5A, ++ 0x9C,0x46,0x08,0x48,0x8C,0x90,0x14,0x5A,0x9C,0x26,0x08,0x48,0x84,0xD6,0x89,0x90, ++ 0x04,0x07,0x48,0x48,0x4C,0x18,0x16,0x5A,0x9E,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92, ++ 0x4C,0x18,0x14,0x5A,0x9C,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x12,0x5A, ++ 0x9A,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x10,0x5A,0x98,0x0E,0x08,0x58, ++ 0xD2,0x00,0x0E,0x92,0x44,0x18,0x16,0x5A,0x9E,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92, ++ 0x44,0x18,0x14,0x5A,0x9C,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92,0x92,0xCE,0x46,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A, ++ 0x32,0x1A,0x0B,0x92,0x80,0xD8,0x32,0x82,0x9A,0x0E,0x10,0x02,0x58,0x01,0xA8,0x06, ++ 0x13,0x4A,0x3A,0x82,0x32,0x1A,0x83,0xD8,0x9A,0x06,0x10,0x02,0xA8,0x0D,0x00,0x01, ++ 0x36,0x02,0x36,0x02,0xEB,0x15,0x30,0xAA,0x81,0x07,0xC0,0x17,0x30,0x72,0x05,0x28, ++ 0x32,0x4A,0x33,0x9A,0x46,0x00,0x06,0x00,0x30,0x2A,0x84,0xC5,0xAF,0x05,0xB9,0xE7, ++ 0xF3,0x6F,0xE4,0x05,0x3A,0x01,0x40,0x48,0x30,0xB2,0x35,0x01,0x2E,0x06,0x2E,0x06, ++ 0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0xEA,0x01,0x02,0x48, ++ 0x33,0x6A,0x3C,0x82,0x36,0x22,0x30,0x02,0x31,0x02,0x36,0x02,0xBA,0xDF,0xD7,0x5F, ++ 0x43,0x02,0x38,0x82,0x88,0x20,0x00,0x01,0x40,0x12,0x48,0x1A,0xF3,0x5D,0x3D,0x82, ++ 0x00,0x68,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x30,0x01,0x10,0x39,0x82,0xA3,0x85, ++ 0x33,0xA2,0xF3,0x20,0xC3,0x2B,0xE1,0x20,0x10,0x5A,0x95,0x06,0x33,0xEA,0xE8,0x1A, ++ 0x07,0xD8,0xC2,0x18,0xE0,0x85,0x39,0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x80,0x20,0x03,0x42,0x80,0x20,0x03,0x42,0x80,0x20,0x04,0x42, ++ 0x80,0x20,0x03,0x42,0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42,0x80,0xA0,0x04,0x42, ++ 0x80,0xA0,0x02,0x42,0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42,0x80,0x20,0x05,0x42, ++ 0x80,0xA0,0x02,0x42,0x80,0xA0,0x05,0x42,0x80,0x20,0x02,0x42,0x80,0x20,0x01,0x42, ++ 0x80,0x20,0x01,0x42,0x80,0xA0,0x01,0x42,0x80,0xA0,0x01,0x42,0x80,0xA0,0x01,0x42, ++ 0x10,0x20,0x08,0x40,0x40,0x08,0x20,0x10,0x10,0x20,0x08,0x40,0x40,0x08,0x20,0x40, ++ 0x10,0x20,0x00,0x08,0x08,0xC1,0x02,0x42,0x08,0x81,0x02,0x42,0x08,0x81,0x03,0x42, ++ 0x08,0x41,0x03,0x42,0x08,0x01,0x03,0x42,0x08,0x81,0x02,0x42,0x08,0x41,0x02,0x42, ++ 0x08,0xC1,0x00,0x42,0x08,0x01,0x02,0x42,0x08,0x01,0x01,0x42,0x08,0xC1,0x01,0x42, ++ 0x08,0x41,0x01,0x42,0x08,0x81,0x01,0x42,0x08,0x81,0x01,0x42,0x08,0x41,0x01,0x42, ++ 0x08,0xC1,0x02,0x42,0x08,0x01,0x01,0x42,0x08,0x01,0x03,0x42,0x08,0xC1,0x00,0x42, ++ 0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x00,0x00, ++ 0x00,0x08,0xF8,0x0F,0xFF,0x07,0xF8,0xFF,0x07,0xF8,0x0F,0xF8,0x08,0x00,0x08,0x08, ++ 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x28,0xB5,0x39,0xC5,0x08,0x1D, ++ 0x1B,0x2B,0x3A,0x28,0x53,0xB5,0x0A,0xC5,0x00,0x08,0x01,0x00,0x01,0x00,0x50,0x0D, ++ 0x52,0x1D,0x52,0xB5,0x39,0x0D,0x04,0x08,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95, ++ 0x51,0x3D,0x54,0x95,0x51,0x3D,0x54,0x95,0x0B,0x3D,0x34,0x88,0x51,0x3D,0x54,0x1D, ++ 0x51,0x3D,0x54,0x95,0x04,0x00,0x50,0x3D,0x50,0x1D,0x01,0x00,0x00,0x00,0x00,0x00, ++ 0x54,0x2D,0x53,0x3D,0x32,0x8D,0x32,0x38,0x01,0x28,0x0A,0x45,0x50,0xB5,0x53,0x95, ++ 0x00,0x00,0x00,0x00,0x52,0xA5,0x51,0xB5,0x09,0xC5,0x03,0x08,0x03,0x00,0x50,0x3D, ++ 0x55,0x1D,0x51,0x0D,0x51,0x3D,0x54,0x95,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95, ++ 0x51,0x0D,0x55,0x0D,0x54,0xB5,0x3A,0x0D,0x00,0x08,0x01,0x00,0x53,0xA5,0x51,0x2D, ++ 0x52,0x3D,0x34,0x8A,0x1D,0x38,0x52,0x45,0x52,0x0D,0x51,0x1D,0x54,0xB5,0x3A,0x0D, ++ 0x53,0xA5,0x29,0xB5,0x39,0xC5,0x08,0x1D,0x19,0x2D,0x22,0x1D,0x44,0x0D,0x31,0x3D, ++ 0x23,0x95,0x09,0xC1,0x29,0xB5,0x0B,0x1D,0x1B,0x2B,0x3A,0x28,0x00,0x00,0x00,0x08, ++ 0xFF,0x07,0x00,0xF8,0x08,0x00,0x10,0x10,0x08,0x10,0x10,0x10,0x08,0x08,0x10,0x08, ++ 0x10,0x08,0x10,0x08,0x10,0x10,0x08,0x08,0x10,0x10,0x08,0x08,0x08,0x08,0x10,0x10, ++ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08, ++ 0xF8,0x07,0x08,0x00,0x08,0x08,0x00,0x00,0x78,0x42,0x00,0x00,0x00,0x00,0x00,0x01, ++ 0x00,0xE0,0x00,0x00,0x00,0x00,0x05,0x00,0x78,0x22,0x01,0x00,0x00,0xE0,0x00,0x01, ++ 0x88,0x40,0x02,0x00,0x00,0xE0,0x05,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,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xD1,0xDA,0xAA,0xA9,0x2E,0x2D,0x55,0x56,0xBB,0x43,0xAC,0x32, ++ 0x99,0x21,0x8A,0x10,0x00,0x70,0x00,0x28,0x09,0x00,0x1F,0x00,0x06,0x78,0x50,0x56, ++ 0xFF,0xFF,0xFF,0xFF,0xB2,0x30,0x08,0x40,0x00,0x40,0x20,0x00,0x03,0x13,0x2A,0xC7, ++ 0x0F,0x00,0xCA,0xCA,0xFF,0xFF,0xFF,0xFF,0x06,0x16,0x48,0x01,0x08,0x00,0x00,0x04, ++ 0x42,0x60,0x78,0xE5,0xD8,0xB9,0xCC,0x04 ++}; ++ ++ ++#define FW_INFO_SIZE (0x18) ++#define FW_REAL_SIZE (sizeof(fwbin)) ++#define FW_BIN_SIZE (24*1024+24) //24K byte ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw_0729_update3.h b/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw_0729_update3.h +new file mode 100644 +index 000000000..636d31078 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Debug_driver/ref_cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw_0729_update3.h +@@ -0,0 +1,1552 @@ ++ ++#ifndef __CST3xx_FW_H__ ++#define __CST3xx_FW_H__ ++ ++ unsigned char cst3_fw[] ={ ++ 0x98,0xE0,0x07,0x01,0xC8,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0xC8,0xC8,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x90,0x08,0x07,0x00,0x98,0x08,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x98,0xA8,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x78,0x01,0x00,0x80,0x07,0xC0,0x17, ++ 0x82,0x07,0xC0,0x07,0x01,0x65,0x40,0x86,0xC1,0x41,0xC0,0x20,0xC5,0x68,0x31,0x12, ++ 0xF5,0x38,0x33,0x5A,0x32,0xA2,0x32,0xEA,0x10,0x62,0x8D,0x0E,0x81,0x07,0xC0,0x97, ++ 0x30,0xF2,0xF3,0x79,0x65,0x7E,0x30,0xB2,0x31,0x09,0x10,0x9A,0x87,0x06,0xD0,0xD8, ++ 0x35,0x12,0x35,0x5A,0x18,0x9A,0x39,0xC2,0x70,0x62,0x01,0x00,0x70,0x62,0x02,0x00, ++ 0xD0,0x81,0x98,0x16,0x43,0xC6,0x0B,0xC6,0xC2,0xD6,0x3F,0x90,0x99,0x0E,0x40,0x86, ++ 0x08,0x86,0xA9,0x0E,0x40,0x23,0x00,0x63,0x38,0x82,0x03,0x00,0x18,0x01,0x20,0x01, ++ 0x28,0x01,0x30,0x01,0xD0,0x81,0x98,0x0E,0x0F,0xC6,0xC3,0xDE,0x38,0x90,0x9A,0x06, ++ 0x08,0x86,0xA9,0x06,0x03,0x5B,0x38,0x82,0xAE,0xFD,0x30,0x02,0x30,0x02,0xEE,0xFD, ++ 0xA8,0x85,0xE8,0x85,0x84,0x27,0xE8,0x2F,0x37,0x8A,0xB8,0xFF,0xF8,0xAF,0x87,0x0F, ++ 0xD0,0x6F,0x80,0x27,0xEF,0xEF,0xBC,0xFF,0xF8,0x9F,0x87,0x27,0xE8,0x1F,0x05,0x00, ++ 0xAF,0x85,0x6F,0xFA,0x39,0x01,0xC0,0x43,0x37,0x4A,0xC9,0x01,0x38,0x30,0x32,0x42, ++ 0x86,0x01,0xC5,0x1B,0xCE,0x23,0xF0,0x53,0xC0,0x01,0x74,0x01,0xDD,0x16,0xC0,0x6B, ++ 0x48,0x68,0x87,0x3E,0xAA,0x7B,0xAC,0x3B,0x10,0xD2,0x8C,0x16,0xB0,0x63,0x06,0x09, ++ 0xB7,0x43,0xEC,0x85,0x34,0x6A,0xE8,0x4B,0xE6,0x48,0x92,0x4D,0xAF,0x4B,0x4D,0xF9, ++ 0x8D,0x0E,0x10,0x12,0x82,0x16,0xE8,0x0B,0x48,0x09,0x88,0x1E,0xB5,0x5B,0xAF,0x7B, ++ 0xAF,0x3B,0xEA,0x85,0x4F,0x09,0x8C,0xE6,0x0A,0x09,0xA8,0x0B,0xE8,0x85,0xAF,0x85, ++ 0x67,0x3A,0xE7,0x01,0x00,0x0F,0x80,0x0F,0xED,0x8F,0xF7,0x03,0x47,0x01,0x80,0xD6, ++ 0xEF,0x85,0xA8,0xC5,0x00,0x21,0x80,0x0F,0xE8,0xDF,0x06,0x09,0x86,0x0F,0xE8,0xC7, ++ 0x79,0x02,0x47,0xC3,0x0C,0x01,0x19,0x42,0x00,0xC3,0x01,0x11,0x86,0x0F,0xE8,0x2F, ++ 0x61,0xEA,0x56,0x03,0x29,0x41,0x18,0x42,0x17,0x03,0x49,0x03,0x1F,0x42,0x09,0x03, ++ 0x15,0x2B,0x4B,0x03,0x1D,0x42,0x09,0x03,0x4D,0x03,0x1B,0x42,0x0B,0x03,0x4B,0x03, ++ 0x35,0x21,0x18,0x82,0x0B,0x03,0x4B,0x03,0x42,0x00,0x02,0x00,0x09,0x03,0x4B,0x03, ++ 0x19,0x42,0x09,0x03,0x49,0x03,0x19,0x82,0x09,0x03,0x49,0x03,0x08,0x09,0x18,0x42, ++ 0x0F,0x03,0x41,0x03,0x1F,0x42,0x05,0x03,0x45,0x03,0x1F,0x82,0x07,0x03,0x47,0x03, ++ 0x1F,0x42,0x04,0x03,0x45,0x03,0x1D,0x42,0x05,0x03,0x45,0x03,0x1D,0x82,0x05,0x03, ++ 0x45,0x03,0x1B,0x42,0x03,0x03,0x43,0x03,0x1B,0x82,0x05,0x03,0x44,0x03,0x1D,0x42, ++ 0x03,0x03,0x45,0x03,0x1B,0x42,0x04,0x03,0x0E,0x81,0x42,0x02,0x82,0x27,0xE0,0x07, ++ 0x84,0x0F,0xE8,0xF7,0x84,0x0F,0xE8,0xD7,0x85,0x0F,0xE8,0x07,0x48,0xE2,0x05,0x01, ++ 0x1D,0x43,0x4C,0x03,0x1D,0x42,0x0D,0x03,0x10,0x2B,0x03,0x11,0x84,0x0F,0xE8,0x07, ++ 0x41,0xC3,0x09,0x01,0x19,0x42,0x00,0xC3,0x00,0x21,0x80,0x0F,0xE8,0x77,0x03,0x09, ++ 0x83,0x0F,0xE8,0x5F,0x42,0x03,0x41,0x00,0x01,0x00,0x02,0x03,0x40,0x03,0x0F,0x09, ++ 0x1F,0x42,0x00,0x03,0x4C,0x03,0x1B,0x42,0x09,0x03,0x4B,0x03,0x19,0x42,0x0C,0x03, ++ 0x41,0x03,0x1D,0x42,0x05,0x03,0x45,0x03,0x1D,0x82,0x01,0x03,0x41,0x03,0x1B,0x42, ++ 0x03,0x03,0x43,0x03,0x1B,0x82,0x01,0x03,0x48,0x0B,0x03,0x61,0x1B,0x0A,0x08,0x0B, ++ 0x48,0x0B,0x19,0x0A,0x0F,0x0B,0x41,0x0B,0x1F,0x0A,0x00,0x0B,0x48,0xE2,0x04,0x09, ++ 0xC8,0x01,0xAF,0x43,0x82,0x0F,0xD0,0x47,0xEC,0xC5,0x47,0xCA,0xC6,0x01,0xF3,0x0B, ++ 0x42,0xCA,0x84,0x01,0x48,0x01,0x80,0x3E,0x4A,0xD2,0x04,0x0B,0x0C,0xF9,0x57,0xB2, ++ 0x8C,0x89,0x97,0x01,0x10,0x8B,0x00,0x17,0x48,0xB2,0xCC,0xE1,0x07,0x0B,0x12,0xF9, ++ 0x96,0xA1,0x02,0x13,0x08,0x31,0x08,0x0B,0x0C,0x11,0x08,0x0B,0x0A,0x51,0x08,0x0B, ++ 0x0C,0x49,0x18,0x0B,0x18,0x0B,0x0A,0x01,0x1C,0x0B,0x40,0x4A,0xC2,0x01,0x0F,0x14, ++ 0x3F,0x82,0xAB,0x85,0x70,0x62,0x0C,0x01,0x2C,0x01,0x60,0x62,0x50,0x62,0x04,0x01, ++ 0xA4,0x82,0x02,0x40,0x50,0x5A,0xC4,0x40,0xC4,0x00,0x54,0x5A,0xC0,0x10,0x1C,0x01, ++ 0xC6,0x83,0x01,0x38,0xC1,0x83,0xD0,0xC0,0x94,0x05,0x14,0x2A,0x90,0x06,0x30,0x2A, ++ 0x10,0x22,0xCC,0x06,0x32,0x22,0xE0,0x90,0xE6,0xD8,0x92,0xDD,0x5F,0x29,0x98,0x8E, ++ 0x59,0xFA,0xDB,0x40,0xA3,0xC2,0xE2,0xB0,0xE6,0x48,0x92,0x4D,0x4E,0x71,0x98,0xDE, ++ 0x48,0xD2,0x03,0x01,0xE4,0xD2,0x10,0x52,0x90,0x06,0x30,0x8A,0xE6,0x00,0x92,0x05, ++ 0x47,0x71,0x98,0xBE,0x50,0xCA,0x03,0x01,0x00,0x84,0xE0,0xE2,0x43,0xAC,0xD0,0x20, ++ 0xC8,0x20,0x03,0xA4,0xE6,0x00,0x92,0x05,0x47,0x71,0x98,0xB6,0x47,0x84,0x40,0xF9, ++ 0xCF,0x0E,0x00,0xF9,0x03,0x84,0x48,0x92,0x40,0x84,0x80,0x43,0xE8,0x85,0xAF,0x85, ++ 0x40,0x1A,0xC3,0x03,0x38,0x00,0x86,0xAE,0x00,0x01,0x85,0x0F,0xCB,0xEF,0x67,0x02, ++ 0x01,0x01,0xE0,0x01,0x8F,0x03,0xB9,0xFF,0xF9,0x47,0x34,0x0A,0x56,0x4A,0xCB,0x01, ++ 0x40,0x22,0x83,0x1F,0xD0,0xAF,0x03,0x11,0x88,0x03,0x01,0x01,0x86,0x0F,0xC8,0x27, ++ 0xBC,0xFF,0xFF,0xFF,0xE8,0x85,0xA8,0x85,0x41,0xAA,0xC2,0x01,0xC8,0x03,0x42,0x01, ++ 0x8A,0x36,0x40,0x9A,0xC0,0x01,0xEF,0x03,0x40,0x29,0xC8,0x0E,0xBE,0xFF,0xF7,0x7F, ++ 0x61,0x7A,0xC2,0x03,0x38,0x00,0xA8,0x0E,0xBE,0xFF,0xF7,0x9F,0xC3,0x03,0xC3,0x03, ++ 0x08,0xE9,0x07,0x42,0x82,0x03,0x43,0xC2,0xC0,0x03,0x40,0x01,0x80,0x16,0x80,0x0F, ++ 0xE7,0xAF,0x3D,0xE7,0xE8,0x85,0xA8,0x85,0x48,0x32,0x02,0x01,0x02,0x43,0x4C,0x22, ++ 0xCC,0x01,0xB7,0x43,0xF0,0x43,0x86,0x0F,0xC8,0xFF,0xED,0x85,0xA8,0x85,0x33,0x2A, ++ 0x48,0x01,0x80,0x4E,0x68,0x01,0x80,0x1E,0x30,0x82,0xC0,0x51,0x20,0x01,0x00,0x5F, ++ 0x30,0x82,0x80,0x51,0x20,0x01,0x00,0x3F,0x68,0x01,0x80,0x1E,0xF0,0x80,0x24,0x49, ++ 0x18,0x22,0x07,0x0F,0xE0,0x80,0x24,0x51,0x0A,0x01,0xF0,0x0A,0x48,0x01,0xD0,0x06, ++ 0x16,0x4A,0x0A,0x40,0x0A,0x01,0xF0,0x8A,0x81,0x27,0xD8,0xC7,0x40,0xF9,0xEB,0x06, ++ 0x00,0xF9,0x6B,0x01,0x87,0x16,0x08,0xF9,0x88,0x09,0xD0,0x40,0xCB,0x00,0xE8,0x85, ++ 0xAC,0x85,0x87,0x3D,0x28,0x01,0x20,0x01,0x01,0x51,0x48,0x92,0x1A,0x42,0xC3,0x00, ++ 0x80,0x34,0xC0,0x34,0x01,0x08,0x13,0x39,0xC4,0x00,0x0A,0x90,0xC0,0x10,0x04,0xE1, ++ 0x90,0x2C,0xF0,0x82,0x80,0x24,0x30,0x01,0x38,0x01,0x10,0x01,0x90,0x1C,0x90,0x14, ++ 0x60,0x01,0x80,0x46,0xF0,0x10,0xDB,0x34,0x04,0x90,0xC2,0xD0,0x1C,0x39,0x09,0xD8, ++ 0xC0,0x90,0x36,0xE1,0xF8,0xB2,0x6C,0x01,0x83,0x56,0xF0,0x50,0x1A,0x51,0x18,0xD2, ++ 0x5E,0x02,0xC1,0x90,0x1A,0x39,0xC1,0x90,0x0E,0xD8,0xC4,0x90,0x3E,0xE1,0xF8,0xBA, ++ 0x60,0x21,0x80,0x4E,0xE0,0x18,0xD3,0x34,0x06,0xD8,0xC2,0x90,0x1C,0x39,0x09,0xD8, ++ 0xC0,0x90,0x1E,0xE1,0xF0,0x9A,0x9E,0x1C,0x68,0x69,0x80,0x5E,0xE0,0x50,0x1B,0x51, ++ 0x18,0xD2,0x5A,0xA2,0xC2,0x90,0xC6,0x88,0x14,0x39,0x09,0x90,0xC0,0x50,0x0C,0xE1, ++ 0xF0,0x8A,0x8A,0x14,0x08,0x09,0x88,0x0C,0x70,0x41,0xD1,0x3E,0x78,0x41,0xD1,0x2E, ++ 0xC9,0x1C,0x48,0x41,0xD0,0x16,0xC8,0x14,0x49,0x41,0xD9,0x06,0x08,0x01,0x00,0xEF, ++ 0x00,0xE0,0x07,0x01,0x10,0x00,0x00,0x42,0xF8,0x00,0x06,0x42,0x80,0x30,0x02,0x01, ++ 0x18,0x00,0x02,0x42,0x80,0x60,0x05,0x00,0x70,0x00,0x04,0x01,0xF8,0xFF,0x07,0x00, ++ 0x80,0x50,0x06,0x01,0x08,0x40,0x00,0x01,0x60,0x20,0x02,0x00,0x00,0x60,0x00,0x01, ++ 0x00,0x28,0x00,0x01,0x80,0xC0,0x04,0x01,0x00,0x20,0x00,0x01,0x88,0x0C,0x08,0x19, ++ 0x85,0x27,0xD0,0xA7,0x10,0x82,0xED,0x3E,0x10,0xC2,0xED,0x2E,0xCC,0x1C,0x10,0x42, ++ 0xE8,0x16,0xC8,0x14,0x10,0x42,0xE4,0x0E,0x00,0x01,0x80,0x0C,0xC0,0x0C,0x40,0x01, ++ 0x80,0x86,0xC8,0x24,0xD6,0x2C,0x78,0x40,0xC2,0x00,0x82,0x00,0xD0,0x48,0x90,0x4D, ++ 0x1F,0x8C,0x54,0xFA,0x58,0xFA,0xC7,0x93,0xC0,0xDB,0x18,0xD2,0x80,0x16,0xD0,0x40, ++ 0xCC,0x2C,0x18,0x44,0xE7,0x20,0x93,0x25,0x60,0x29,0x90,0x06,0x3B,0x4F,0xE3,0x68, ++ 0x90,0x6D,0x6F,0x71,0x92,0x06,0x38,0xF7,0x87,0x3D,0xE8,0x85,0xA8,0xC5,0x2F,0x01, ++ 0x40,0xAA,0xFF,0x03,0x81,0x04,0x00,0x5F,0x07,0x31,0x48,0xA2,0x1A,0x42,0xC3,0x00, ++ 0x0C,0xC9,0x09,0x48,0xC0,0x30,0x3A,0x11,0xF8,0xBA,0x07,0x21,0xF0,0x82,0x41,0x51, ++ 0xD0,0x0E,0x20,0x51,0x00,0x0F,0xC0,0x51,0x96,0x25,0x00,0x19,0x04,0x00,0x14,0x22, ++ 0xE8,0x06,0x30,0x22,0x37,0x02,0xC1,0xF9,0xC0,0x89,0x0C,0xF1,0x1F,0x42,0x0A,0xF9, ++ 0x88,0x89,0x84,0x27,0xD0,0x1F,0xCB,0x00,0x90,0x05,0x40,0x51,0xD0,0x06,0x00,0x51, ++ 0x4C,0x1A,0x17,0x42,0xE8,0x06,0x30,0x42,0x05,0xBC,0x03,0x84,0xE7,0x68,0x93,0x6D, ++ 0xC5,0x04,0x10,0x42,0xC7,0x86,0xEE,0xC5,0xAC,0x85,0x87,0x3D,0x00,0xF9,0x87,0x0C, ++ 0x00,0x01,0x80,0x04,0x81,0x14,0x18,0x39,0x09,0xD8,0x24,0x39,0x57,0xBA,0x1E,0x22, ++ 0x04,0x08,0xC2,0x48,0xC0,0x68,0x0E,0xE1,0xF2,0x4A,0xE3,0x00,0x92,0x05,0x40,0x31, ++ 0xD8,0xB6,0x07,0x01,0x80,0x24,0x00,0x01,0x38,0x01,0x28,0x01,0x30,0xF9,0xCF,0x24, ++ 0x12,0x51,0x18,0x8A,0x54,0x6A,0xC6,0x48,0x54,0x72,0xC6,0x50,0x90,0x34,0x08,0x01, ++ 0x20,0x01,0xF8,0xA2,0x60,0xA1,0xE8,0x0E,0xE1,0xF8,0x93,0xFD,0xC0,0x00,0x91,0x05, ++ 0x10,0x62,0xED,0x06,0x35,0x2A,0x11,0xA2,0xD1,0x06,0x30,0x32,0xE2,0x90,0xE4,0x48, ++ 0x90,0x4D,0x4E,0x29,0x99,0x66,0x6F,0xE1,0xED,0x16,0x50,0xFA,0x0C,0x01,0xA8,0x8B, ++ 0x08,0x29,0x80,0x27,0xD0,0x9F,0x90,0x0D,0xD0,0x40,0x83,0x71,0x40,0xE1,0xC0,0x6E, ++ 0xD0,0x80,0x83,0x71,0x40,0xE1,0xC0,0x4E,0x68,0xE1,0xE9,0x3E,0x78,0x21,0xE8,0x2E, ++ 0x50,0xA2,0x05,0x01,0x85,0x83,0x40,0x92,0x10,0xD1,0x87,0x13,0xC4,0x14,0x10,0x42, ++ 0xD0,0x06,0x88,0x14,0xC5,0x0C,0x10,0x82,0xE8,0x06,0xB0,0x0C,0xC5,0x04,0x10,0x42, ++ 0xD0,0x06,0xA8,0x04,0x6D,0x6A,0x75,0x7A,0xC0,0x34,0x18,0x01,0x48,0x01,0xE8,0xBE, ++ 0x14,0x01,0xF0,0x12,0x10,0x52,0xDC,0x76,0x61,0x2A,0xC5,0x23,0x60,0x01,0x80,0x16, ++ 0xD0,0x90,0x02,0x14,0x01,0xC7,0x50,0xE1,0xD6,0xB6,0x78,0x60,0xC3,0x20,0x83,0x20, ++ 0xD8,0x90,0x00,0x14,0x00,0x87,0x50,0x01,0xE8,0x76,0x10,0x09,0x00,0x14,0x00,0x5F, ++ 0x14,0x01,0xF0,0x12,0x10,0x52,0xE4,0x16,0xD0,0x90,0x02,0x14,0x00,0x27,0x50,0x01, ++ 0xD0,0x16,0x10,0x01,0x18,0x92,0x06,0x14,0xE2,0x00,0xE4,0xD8,0x90,0xDD,0x5E,0x29, ++ 0x98,0xA6,0xC6,0x24,0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x44,0x71,0x98,0x16, ++ 0x20,0x01,0x00,0x01,0x08,0x01,0x10,0x01,0x94,0x1C,0x50,0x82,0x04,0x18,0xC3,0xD0, ++ 0x5E,0x82,0xC4,0xA8,0x30,0x72,0x19,0x01,0x15,0x01,0xF0,0x52,0xC0,0x80,0x90,0x05, ++ 0xE0,0x48,0x92,0x4D,0xFD,0x1C,0x10,0xD2,0xE8,0x06,0x90,0x1C,0xAA,0x51,0xE0,0xD8, ++ 0x90,0xDD,0x5E,0x71,0x98,0x86,0x87,0x27,0xC8,0x0F,0x95,0x2D,0xC5,0x14,0x10,0x42, ++ 0xD0,0x06,0xA8,0x14,0x00,0x01,0x80,0x24,0x68,0x01,0xE8,0xDE,0x3F,0x01,0xF8,0xBA, ++ 0x10,0x7A,0xDD,0x96,0x60,0x01,0x80,0x0E,0x60,0x21,0x88,0x16,0xD9,0xC0,0x03,0x84, ++ 0x00,0xB7,0x08,0x19,0xC0,0x1C,0x80,0x27,0xCD,0x4F,0x14,0x42,0xD7,0x86,0x78,0x40, ++ 0xCA,0x00,0x82,0x00,0xD1,0xC0,0x01,0x84,0x00,0x57,0x78,0x01,0xE8,0x46,0x00,0x09, ++ 0x00,0x84,0x01,0x2F,0x01,0x01,0xF0,0x82,0x10,0x42,0xE5,0x0E,0xD9,0x00,0x02,0x84, ++ 0xB0,0x51,0xC0,0x24,0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x46,0x71,0x98,0x9E, ++ 0xE7,0x20,0x93,0x25,0x65,0x29,0x98,0x66,0x43,0x2A,0x4B,0x32,0xC0,0x03,0xC0,0x4B, ++ 0x33,0x22,0x58,0x4A,0x50,0x4A,0x1B,0x62,0x88,0xB6,0x01,0x01,0x4A,0x1A,0x03,0x20, ++ 0xC3,0x08,0x63,0x22,0xCB,0x60,0x68,0x1A,0xAA,0x51,0xC8,0x68,0x31,0xF9,0x0C,0xB0, ++ 0xC8,0x78,0x34,0x01,0xF8,0xF2,0x3D,0x01,0xFD,0x7A,0x17,0xF2,0xD0,0x3E,0x28,0x01, ++ 0xF8,0x2A,0x6B,0xA1,0xE8,0x1E,0x78,0x79,0xEB,0x0E,0x00,0x68,0x02,0x2C,0x61,0xD2, ++ 0xA0,0x51,0xC8,0x60,0xC4,0x70,0xC6,0x68,0x0B,0x01,0xF0,0x4A,0x2B,0x01,0xF8,0xAA, ++ 0x10,0x4A,0xD5,0x66,0x0B,0x01,0xF0,0x0A,0x48,0xA1,0xE8,0x46,0x68,0x79,0xE8,0x36, ++ 0x7B,0x70,0xC6,0xA8,0x83,0x68,0x03,0x70,0xCB,0x68,0xC5,0x48,0x02,0x0C,0xE1,0x00, ++ 0x90,0x05,0x46,0x29,0x9C,0x56,0x36,0xFF,0x47,0x01,0x80,0xE6,0x22,0x01,0x40,0x3A, ++ 0x00,0x08,0xC3,0x68,0x41,0x3A,0xC2,0x70,0x40,0x32,0x82,0x51,0xC4,0x40,0x09,0xF9, ++ 0x0B,0x48,0xC0,0x78,0x10,0x01,0x08,0x01,0xF2,0xD2,0xF5,0x0A,0x10,0x52,0xD4,0x6E, ++ 0x01,0x01,0xF0,0x82,0x81,0x2C,0x40,0x41,0xE8,0x46,0x48,0x79,0xEC,0x36,0x00,0x00, ++ 0x08,0x29,0x80,0x27,0xC8,0x5F,0xC8,0x2C,0xC1,0x00,0x02,0x84,0x40,0xD2,0x81,0x51, ++ 0xC1,0x40,0x49,0xD2,0xC0,0x48,0x1B,0x01,0x17,0x01,0xF0,0xDA,0xF4,0x52,0x14,0x9A, ++ 0xD0,0x3E,0x08,0x01,0xF1,0x0A,0x4A,0x41,0xE8,0x1E,0x50,0x79,0xEA,0x0E,0x00,0x48, ++ 0x03,0x0C,0xE0,0x20,0x90,0x25,0x67,0x29,0x9B,0x4E,0x36,0x2F,0xA9,0xC5,0x47,0x52, ++ 0x17,0x09,0x80,0x01,0xC0,0x0B,0x18,0x8A,0x81,0x0B,0x68,0x3A,0x79,0x22,0x31,0x62, ++ 0xA4,0x01,0x06,0x27,0xBB,0xFF,0xEF,0xFF,0x48,0x4A,0x41,0x43,0xE0,0x00,0x02,0x43, ++ 0x40,0x42,0xC1,0x03,0x40,0x01,0x80,0x0E,0x05,0xC1,0xB0,0x43,0x40,0xF2,0x80,0x1F, ++ 0xE9,0x57,0x50,0x2A,0x48,0xEA,0x40,0xE2,0x85,0x1F,0xC8,0xAF,0xB9,0xFF,0xEF,0x7F, ++ 0x01,0x11,0x88,0x03,0x50,0x02,0x49,0xC2,0x40,0xC2,0x80,0x1F,0xD8,0xA7,0x54,0xF2, ++ 0x48,0xAA,0x40,0xB2,0x85,0x1F,0xF8,0x57,0xC8,0x03,0x43,0x01,0x83,0x16,0xC8,0x03, ++ 0x40,0x11,0x88,0x26,0x48,0xCA,0x40,0x43,0x10,0x09,0x18,0x82,0x00,0x43,0x48,0x72, ++ 0x40,0x72,0x80,0x1F,0xF0,0xB7,0x72,0x5A,0xC1,0xCB,0xC1,0x83,0x18,0x42,0x80,0x0E, ++ 0x05,0x01,0xA8,0x43,0xBA,0xFF,0xF7,0xC7,0x41,0x8A,0xC0,0x8B,0x09,0x0C,0xC6,0xCB, ++ 0x11,0x0C,0xC8,0x4B,0x10,0x0C,0x72,0x22,0xB5,0x01,0xE2,0x8B,0x10,0x0C,0x04,0xCF, ++ 0x00,0x48,0x00,0x01,0x00,0x40,0x00,0x01,0x00,0xE0,0x00,0x01,0x08,0x40,0x00,0x01, ++ 0x18,0x10,0x00,0x00,0x48,0xE0,0x06,0x00,0x50,0xA0,0x02,0x00,0x50,0x50,0x02,0x00, ++ 0x00,0xA0,0x00,0x01,0x00,0x20,0x00,0x01,0x80,0xC0,0x04,0x01,0xF8,0x00,0x06,0x42, ++ 0x70,0x40,0x04,0x01,0x48,0xA2,0x40,0x4C,0x10,0x0C,0x4E,0xA2,0x40,0x4B,0x18,0x0C, ++ 0xA2,0x48,0x18,0x0C,0xEC,0x4B,0x1D,0x0C,0xBA,0xFF,0xEF,0x57,0x05,0x11,0xA0,0x83, ++ 0x32,0x8A,0xC9,0x01,0x40,0x72,0x80,0x1F,0xE9,0x0F,0x31,0x8A,0x12,0x09,0xC8,0x01, ++ 0x40,0x5A,0x58,0x62,0x80,0x17,0xE8,0x47,0xBC,0xFF,0xDF,0x97,0x32,0x8A,0xC9,0x01, ++ 0x40,0x3A,0x80,0x0F,0xF0,0x4F,0x82,0x07,0xDF,0x0F,0xBA,0xFF,0xE3,0xE7,0xCE,0x03, ++ 0x40,0x31,0x80,0x06,0x3F,0xB7,0xEB,0xC5,0x00,0x60,0x00,0x01,0x00,0xA0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x30,0x48,0x00,0x00,0xA8,0x85,0x33,0x22,0xF0,0x03,0x87,0x07, ++ 0xF2,0x9F,0x45,0x7A,0x2C,0x01,0x00,0x2B,0xB6,0x2B,0x05,0x21,0xAF,0x2A,0xB8,0xFF, ++ 0xE5,0xE7,0xA1,0x01,0xCA,0x03,0x33,0x08,0x42,0x52,0x72,0x48,0x1C,0x0B,0x5C,0x0B, ++ 0x02,0x48,0x1A,0x0B,0x0B,0x2B,0xCE,0x0B,0x30,0x48,0xA8,0x16,0x0E,0x09,0x04,0x0B, ++ 0x1B,0x2B,0xE8,0x85,0xAD,0x85,0x87,0xAD,0x42,0x12,0xC2,0x01,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x52,0x02,0x4A,0x0A,0x40,0x0A,0x82,0x0F,0xCA,0x27,0x40,0x0A, ++ 0x71,0xFA,0xC1,0x80,0x81,0xA4,0x41,0xEA,0xB6,0xE1,0x81,0x01,0x83,0x9C,0x01,0x47, ++ 0x47,0xD2,0xB9,0xFF,0xF9,0x4F,0x66,0xCA,0x52,0x03,0x83,0x01,0xE7,0x03,0x40,0x79, ++ 0x81,0x06,0x31,0x12,0x48,0xB2,0x01,0x01,0x58,0x9A,0x81,0x07,0xF9,0xCF,0x35,0x12, ++ 0x48,0x9A,0x01,0x09,0x58,0x82,0x81,0x07,0xFB,0x9F,0x55,0x03,0x80,0x01,0xE2,0x03, ++ 0x40,0x59,0x8D,0x7E,0xC1,0xA4,0x31,0x8A,0x13,0x01,0xD8,0x1B,0xDB,0x2B,0x19,0x5A, ++ 0x40,0x6C,0x40,0x3C,0xD8,0x68,0x07,0x2C,0xE4,0x00,0xE4,0x48,0xE4,0x90,0x92,0x95, ++ 0x17,0xD2,0x9C,0xAE,0x52,0x03,0x83,0x01,0xE5,0x03,0x40,0x59,0x81,0x2E,0x50,0x12, ++ 0x49,0x12,0x41,0x1A,0x58,0x0D,0x80,0x0F,0xC1,0x77,0xEB,0xA4,0x30,0xA2,0x39,0x01, ++ 0x01,0x01,0xF0,0x42,0x0A,0x99,0x18,0x42,0x08,0x51,0x80,0x1F,0xF9,0xFF,0x06,0x44, ++ 0x01,0x01,0xF0,0x02,0x0A,0x99,0x18,0x42,0x08,0x51,0x80,0x1F,0xF9,0xBF,0x06,0x04, ++ 0xE5,0x68,0xE5,0x20,0xE7,0xF8,0x93,0xFD,0x7F,0x29,0x98,0x4E,0x68,0xB2,0x60,0xA2, ++ 0xA0,0xF1,0x3D,0x01,0x01,0x01,0xF0,0x42,0x08,0x51,0x08,0x00,0x86,0x1F,0xF8,0x37, ++ 0x00,0x44,0x01,0x01,0xF0,0x02,0x09,0x51,0x08,0x00,0x80,0x1F,0xF9,0xFF,0x05,0x04, ++ 0xE5,0x68,0xE5,0x20,0xE7,0xF8,0x93,0xFD,0x7F,0x29,0x98,0x5E,0x40,0x0D,0x80,0x07, ++ 0xD9,0xDF,0xC1,0x9C,0xC8,0x03,0x42,0x31,0x81,0x96,0x84,0xAD,0xE8,0x85,0x07,0x00, ++ 0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x80,0xC0,0x04,0x01,0x00,0xE0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x48,0xE0,0x06,0x00,0x58,0x30,0x03,0x01,0x48,0xFA,0xFF,0x53, ++ 0x84,0x13,0xF8,0x53,0x80,0x13,0x32,0x52,0x96,0x01,0xCE,0x93,0x80,0x13,0xCC,0x4B, ++ 0x83,0x0B,0x3E,0x82,0xA8,0xC5,0xF7,0x34,0x37,0x22,0x40,0xC2,0xFD,0x03,0x16,0x02, ++ 0xC9,0xFE,0x01,0x21,0x6B,0xB2,0x1F,0x02,0xCB,0x28,0x02,0x99,0x09,0x00,0xC2,0x40, ++ 0x2A,0xA1,0xF8,0x2A,0x3E,0xB1,0xF8,0x3A,0x48,0x09,0x88,0x1E,0x0F,0xF9,0x8F,0x09, ++ 0xD8,0x48,0x92,0x6D,0x50,0x09,0x88,0x1E,0x0A,0xC9,0x08,0x48,0xD8,0x48,0x96,0x7D, ++ 0xCE,0x0B,0xCC,0x13,0x0A,0x48,0x00,0x90,0x18,0x8A,0x80,0xCB,0x8A,0x48,0x81,0xCB, ++ 0x8C,0xC8,0x81,0xCB,0x39,0xD0,0x09,0x48,0x78,0x90,0x18,0x8A,0x86,0xCB,0xE6,0xD8, ++ 0xE0,0xE8,0x5A,0x04,0x08,0xA1,0x80,0x1F,0xF8,0xBF,0x82,0x51,0x97,0x05,0x46,0xF9, ++ 0x97,0x56,0x58,0x02,0xE8,0xCA,0x30,0x52,0x94,0x51,0x10,0x12,0x91,0x16,0x80,0x43, ++ 0xA8,0xC2,0x00,0x1F,0x80,0x4B,0x01,0x0F,0x01,0xF9,0x87,0x43,0xC2,0x83,0xE9,0x00, ++ 0x87,0x83,0xE9,0xC5,0xAC,0x85,0x87,0x2D,0x36,0x01,0x00,0xBD,0x40,0x03,0x80,0x14, ++ 0x44,0x92,0xFE,0x1B,0x10,0x09,0x00,0x01,0x4E,0xA2,0x66,0xAA,0xC5,0x6B,0x68,0x59, ++ 0x82,0x16,0xE0,0x00,0x17,0x02,0x9D,0xCE,0x00,0xF9,0x87,0x43,0x58,0x01,0x80,0xBE, ++ 0x30,0x01,0x48,0x15,0x03,0x01,0x20,0x99,0x5B,0x4A,0x0E,0x20,0x01,0x77,0x28,0x21, ++ 0x1F,0x2A,0xC2,0x68,0xC9,0x68,0xD1,0x6B,0x68,0x09,0x88,0x2E,0x83,0x43,0xE0,0xB0, ++ 0x92,0xB5,0xE7,0x48,0x70,0x09,0x80,0x1E,0xE6,0x00,0x92,0x05,0x17,0x82,0x9C,0x76, ++ 0x73,0x01,0x80,0x16,0x60,0x0A,0x6E,0x15,0x3D,0x01,0x40,0xE2,0x80,0x01,0x87,0x1C, ++ 0x00,0x0F,0x79,0x01,0x88,0x9E,0x50,0x0D,0x90,0x04,0x10,0x01,0xC1,0x43,0x31,0x1A, ++ 0x37,0x8A,0xB8,0xFF,0xFB,0xBF,0xE3,0x68,0xC4,0x1C,0xC0,0x03,0x4E,0x00,0x0E,0x00, ++ 0x1B,0x82,0x89,0x03,0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x4F,0x50,0x0D, ++ 0x90,0x04,0x10,0x01,0xC1,0x43,0x31,0x1A,0x37,0x8A,0xB8,0xFF,0xFB,0x1F,0xE3,0x68, ++ 0xEB,0x20,0xE3,0xF8,0x95,0xFD,0x17,0xBA,0x98,0xDE,0xC6,0x1C,0x1C,0x01,0xC4,0x03, ++ 0x48,0x08,0x4E,0x01,0x80,0x9E,0x70,0x01,0x81,0x3E,0x80,0x03,0xC0,0x1C,0xC8,0x03, ++ 0x85,0x03,0x03,0x59,0x85,0x03,0xE5,0x20,0x01,0x3F,0x80,0x03,0xC0,0x1C,0xC8,0x03, ++ 0x83,0x03,0x8B,0x1B,0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x27,0x70,0x09, ++ 0xCD,0x16,0x00,0x59,0x83,0x03,0xE1,0x20,0x37,0x02,0xB9,0xFF,0xFC,0x7F,0x41,0xEA, ++ 0x42,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x4A,0xDA,0x44,0x43,0x1A,0xC2,0x00,0x43, ++ 0x61,0xD2,0x44,0x03,0x42,0x00,0x02,0x00,0x07,0x03,0x01,0xF9,0x80,0x89,0x84,0x1F, ++ 0xE9,0xDF,0x45,0x03,0x08,0x09,0x18,0x42,0x00,0x03,0x81,0x2D,0xEF,0x85,0xAF,0xFD, ++ 0x80,0x0D,0xFC,0x54,0x30,0x32,0x30,0x62,0x6F,0x42,0xAC,0x01,0x50,0x09,0x88,0x4E, ++ 0x00,0x0F,0x80,0x07,0xF9,0xDF,0xC7,0x43,0x37,0x00,0xAA,0xD6,0xC5,0x43,0x09,0xF9, ++ 0x01,0x42,0x80,0x43,0x04,0x09,0x30,0x22,0x51,0x3A,0x04,0x8F,0x60,0x01,0xC1,0x2E, ++ 0xF7,0x00,0x0B,0x01,0x1A,0x42,0x08,0x83,0x30,0x0A,0x01,0x17,0x02,0xF9,0x0F,0x83, ++ 0x08,0x01,0x19,0x01,0x08,0x9B,0x04,0x01,0x00,0x4F,0x78,0x01,0x88,0x16,0x18,0x01, ++ 0x00,0x9B,0x06,0x17,0xC6,0x9B,0x01,0x9B,0xCA,0xB0,0xE7,0x00,0x94,0x05,0x14,0x42, ++ 0x9B,0x9E,0x37,0x02,0x40,0x01,0x80,0x26,0x04,0xA1,0x00,0x83,0x04,0x01,0x30,0x22, ++ 0x00,0x0F,0x00,0x21,0x03,0x83,0xD4,0x00,0x92,0x25,0x44,0x83,0x08,0x01,0x1C,0x42, ++ 0x01,0x83,0xC2,0x43,0x37,0x00,0xAA,0xE6,0xC5,0x43,0x09,0xF9,0x01,0x42,0x80,0x43, ++ 0x66,0x01,0x88,0x5E,0xC0,0x24,0x40,0x09,0x88,0x7E,0x05,0x01,0x02,0x83,0x44,0x83, ++ 0x08,0x01,0x1C,0x42,0x05,0x83,0x3A,0x47,0xAC,0x9D,0x87,0x1D,0x20,0x01,0x00,0x01, ++ 0x80,0x0C,0x70,0x15,0x44,0xEA,0xF2,0x03,0xEE,0x00,0x92,0x3D,0x6F,0xDA,0xAA,0x01, ++ 0x00,0xAF,0x81,0x07,0xF9,0x1F,0xC5,0x43,0x30,0x00,0xA2,0x1E,0x44,0xBA,0xF2,0x03, ++ 0x17,0xC2,0x9D,0xB6,0x44,0xAA,0xF2,0x03,0x10,0xC2,0x9D,0x06,0x21,0x11,0xC0,0x43, ++ 0x08,0xF9,0x05,0x42,0x82,0x43,0x41,0xC2,0x46,0x0B,0x14,0x79,0x00,0x8A,0x48,0x09, ++ 0x88,0x9E,0x08,0x01,0x0E,0x0B,0x44,0x0B,0x83,0x8B,0xE1,0xB0,0xE7,0x20,0x93,0x25, ++ 0x60,0x11,0x88,0x56,0x30,0x5A,0xD3,0xCB,0xD4,0x1C,0x10,0x8A,0x8A,0x2E,0xD0,0xCB, ++ 0xD4,0x24,0x10,0x8A,0x88,0x0E,0x08,0x09,0x8F,0x0C,0x08,0x01,0x08,0x0B,0x0A,0x01, ++ 0x08,0x0B,0x0C,0x81,0x02,0x0B,0x44,0x0B,0x10,0x01,0x1C,0x8A,0x00,0x0B,0x62,0x11, ++ 0x88,0x4E,0xC6,0x0C,0x39,0x0F,0x4B,0xEA,0x60,0x54,0x80,0x13,0x12,0x01,0x80,0x13, ++ 0xE4,0x4B,0x86,0x0B,0x4A,0x0A,0x8A,0x01,0x5E,0x53,0x84,0x13,0x58,0x53,0x8A,0x13, ++ 0x12,0xA9,0x88,0x13,0x14,0x19,0x88,0x13,0x4E,0x53,0x8E,0x13,0x48,0x53,0x94,0x13, ++ 0x4A,0x4B,0x92,0x0B,0x0C,0x31,0x90,0x0B,0x3F,0x82,0xAB,0x85,0x80,0x4D,0x34,0x22, ++ 0x30,0x01,0x00,0x01,0x80,0x2C,0x38,0x01,0x48,0x62,0xD9,0x43,0xDA,0x4B,0x1A,0x42, ++ 0x81,0x14,0x40,0x5A,0x80,0x71,0x80,0x24,0xC0,0x71,0x80,0x1C,0x60,0x09,0x80,0x0E, ++ 0x60,0x29,0x88,0x7E,0x60,0x09,0x88,0x26,0x73,0x6A,0xE1,0x80,0x81,0x2C,0x78,0x6A, ++ 0x01,0x27,0x70,0x6A,0xE0,0x80,0x83,0x2C,0x79,0x52,0xF9,0xC1,0x47,0x35,0xB8,0xFF, ++ 0xF0,0xEF,0x01,0x3F,0x60,0x21,0x88,0x2E,0x70,0x42,0x41,0x35,0xBD,0xFF,0xFF,0xDF, ++ 0x7B,0x22,0xB9,0x11,0x6F,0xCA,0xA8,0x01,0xC5,0x43,0x09,0xF9,0x01,0x42,0x80,0x43, ++ 0xC1,0x43,0x09,0x01,0x19,0x42,0x80,0x43,0x42,0xD2,0x40,0x0B,0x10,0x01,0x1A,0x8A, ++ 0x00,0x0B,0x42,0xCA,0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x48,0xBA,0x40,0x43, ++ 0x10,0x09,0x18,0x82,0x00,0x43,0x08,0x09,0x07,0x01,0xBC,0xFF,0xF8,0xAF,0x42,0x09, ++ 0x88,0x5E,0x62,0x21,0x88,0x56,0x12,0x09,0x91,0x04,0x30,0x82,0x18,0x01,0xC8,0x14, ++ 0xBF,0xFF,0xF7,0xAF,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x59,0x40,0x35,0x30,0x9A, ++ 0xBF,0xFF,0xF7,0x6F,0x10,0x09,0x90,0x04,0x10,0x01,0x00,0xCF,0x00,0xE0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x80,0x00,0x06,0x01,0x00,0xF8,0x07,0x00,0x80,0x30,0x02,0x01, ++ 0x30,0x04,0x05,0x08,0x00,0x00,0x06,0x42,0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42, ++ 0x18,0x60,0x05,0x01,0x70,0x70,0x06,0x01,0x50,0x20,0x07,0x01,0x68,0x60,0x02,0x01, ++ 0x09,0x29,0x30,0xC2,0x37,0x9A,0xB8,0xFF,0xF0,0x57,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x0E,0x71,0x40,0x0A,0x37,0x9A,0xB8,0xFF,0xF0,0x17,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x29,0x30,0x9A,0xC7,0x24,0xB8,0xFF,0xF0,0xD7,0x15,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x29,0x18,0x09,0xC7,0x1C,0xB8,0xFF,0xF1,0x97,0x05,0x9F,0x60,0x09,0x80,0x0E, ++ 0x61,0x29,0x88,0x7E,0x10,0x11,0x90,0x04,0x11,0x09,0x30,0x82,0x18,0x01,0xC8,0x14, ++ 0xBD,0xFF,0xF7,0x2F,0x10,0x11,0x90,0x04,0x10,0x01,0x30,0x9A,0xC8,0x14,0xC0,0x2C, ++ 0xBC,0xFF,0xF7,0xEF,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x21,0x40,0x35,0x30,0x9A, ++ 0xBC,0xFF,0xF7,0xAF,0x10,0x09,0x90,0x04,0x11,0x01,0x08,0x31,0x30,0xC2,0x31,0x9A, ++ 0xBC,0xFF,0xF7,0x6F,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x29,0x30,0x9A,0xC0,0x24, ++ 0xBC,0xFF,0xF7,0x2F,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x29,0x18,0x09,0xC0,0x1C, ++ 0xBB,0xFF,0xF7,0xEF,0xC6,0x43,0x09,0xF9,0x01,0x42,0x80,0x43,0x40,0xDA,0x44,0x0B, ++ 0x42,0x48,0x02,0x48,0x04,0x0B,0x40,0xD2,0x0A,0x01,0x0F,0x0B,0x0C,0x01,0x00,0x0B, ++ 0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x87,0x4D,0xE8,0x85,0xAC,0x85,0x63,0xAA, ++ 0xC8,0x03,0x43,0x09,0x83,0x16,0xC8,0x03,0x40,0x29,0x88,0x86,0x46,0x8A,0xC4,0x01, ++ 0x82,0x1F,0xC8,0x4F,0x69,0x82,0xC4,0x43,0x40,0x11,0x98,0x2E,0xCF,0x03,0xBB,0xFF, ++ 0xF8,0x67,0x00,0x01,0x83,0x43,0xE9,0x85,0xE1,0x00,0x82,0x43,0xEB,0x85,0xCB,0x03, ++ 0x40,0x21,0x88,0x26,0xB8,0xFF,0xFF,0x0F,0x03,0x19,0x88,0x03,0xEB,0x85,0xCB,0x03, ++ 0x47,0x19,0x80,0xDE,0xC8,0x03,0x43,0x31,0x84,0xC6,0x47,0x12,0xC4,0x01,0xFE,0x03, ++ 0x40,0x01,0x88,0x3E,0x41,0xFA,0x83,0x01,0xD0,0x0B,0x48,0x31,0x9C,0x76,0xC7,0x03, ++ 0x37,0x00,0xA8,0x5E,0x44,0xDA,0xC3,0x01,0xE8,0x03,0x44,0x01,0x8F,0x36,0xBF,0xFF, ++ 0xEB,0xCF,0xEC,0x85,0xA8,0xC5,0x27,0x01,0x30,0x1A,0x00,0x09,0x4B,0xAA,0x6B,0xBA, ++ 0x30,0x01,0x59,0x51,0x80,0xE6,0xE1,0x4E,0x79,0xAA,0xC3,0xD3,0x85,0x1F,0xE8,0x6F, ++ 0x61,0x52,0x20,0x09,0x39,0x61,0x62,0x52,0x71,0x61,0x62,0x92,0x40,0x6A,0x13,0x31, ++ 0xC2,0x01,0x56,0x03,0x80,0x01,0x5A,0xC9,0x80,0xAE,0xE1,0x4E,0x59,0x59,0x80,0x56, ++ 0x59,0x61,0x80,0x66,0x59,0x69,0x88,0xBE,0x02,0x29,0x88,0x43,0x21,0x09,0x00,0x9F, ++ 0x59,0xD1,0x80,0x6E,0x59,0x01,0x89,0x7E,0x88,0x53,0x22,0x09,0x08,0x59,0xA5,0x0B, ++ 0x00,0x57,0x01,0x39,0x89,0x43,0x02,0x3F,0x86,0x07,0xE8,0x17,0x00,0x27,0x19,0x12, ++ 0x81,0xD3,0x01,0x0F,0x00,0x41,0x18,0x12,0x80,0xD3,0x01,0xEF,0x02,0x11,0x88,0x43, ++ 0x20,0x09,0x00,0xCF,0x02,0x01,0x88,0x43,0x41,0x43,0x19,0x82,0x00,0x43,0x01,0x9F, ++ 0x88,0x43,0x22,0x09,0x00,0x87,0x00,0x19,0x88,0x43,0x22,0x09,0x00,0x67,0x00,0x21, ++ 0x88,0x43,0x22,0x09,0x02,0x47,0x88,0x53,0x26,0x09,0x08,0x69,0xA0,0x0B,0x00,0x1F, ++ 0x88,0x53,0x22,0x09,0x08,0x79,0xA7,0x0B,0x60,0x01,0x80,0x66,0x40,0x6A,0x42,0x0B, ++ 0x30,0x48,0xA8,0x2E,0x08,0x81,0x06,0x0B,0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B, ++ 0x45,0x43,0x19,0x82,0x07,0x43,0xE9,0xC5,0xAC,0x8D,0x87,0x15,0x40,0x32,0x82,0x0C, ++ 0x46,0x02,0xC2,0x01,0xDA,0x2B,0xD8,0x33,0x0C,0x01,0xB0,0x0B,0x61,0x02,0xC2,0x0B, ++ 0x10,0xF9,0x05,0x8A,0x81,0x0B,0xC1,0x0B,0x10,0x01,0x19,0x8A,0x81,0x0B,0x49,0xEA, ++ 0x8A,0x01,0x46,0x53,0x18,0x01,0x1A,0xD2,0x01,0x53,0x52,0xAA,0x44,0x8B,0x1A,0x01, ++ 0x1A,0xCA,0x00,0x8B,0x48,0x8A,0x41,0x53,0x18,0x09,0x18,0xD2,0x02,0x53,0x50,0x03, ++ 0x80,0x01,0xE2,0x0B,0x49,0x79,0x87,0xAE,0xE6,0x03,0x40,0x69,0x88,0x16,0x09,0xA9, ++ 0x07,0x91,0xB8,0xFF,0xE8,0x4F,0x47,0x09,0x89,0xDE,0x31,0x42,0x1A,0x82,0x03,0x38, ++ 0x15,0x09,0x90,0xCD,0x90,0x04,0x18,0x01,0xC7,0x0C,0xB8,0xFF,0xE9,0x47,0x44,0x5A, ++ 0x10,0x09,0x90,0x04,0x15,0x01,0x90,0xCD,0x37,0x9A,0xB8,0xFF,0xE8,0x07,0xC4,0x14, ++ 0x15,0x09,0xC8,0x48,0xE8,0x48,0x90,0x04,0x00,0x48,0x12,0x01,0x1F,0x09,0xB8,0xFF, ++ 0xE8,0xB7,0x03,0xF7,0x08,0xA1,0x00,0x91,0xBE,0xFF,0xEF,0x37,0x40,0x09,0x88,0xC6, ++ 0x18,0xAA,0x13,0x09,0x20,0x40,0x63,0x08,0x90,0x04,0x30,0x9A,0xC7,0x0C,0xB8,0xFF, ++ 0xE8,0x37,0x03,0x77,0x08,0xB1,0x00,0x91,0xBD,0xFF,0xEF,0xB7,0x40,0x09,0x88,0x46, ++ 0xC0,0x14,0x10,0x09,0xC8,0x48,0xED,0x48,0x00,0x48,0x32,0x9A,0x97,0x04,0xB8,0xFF, ++ 0xE9,0xB7,0xC2,0x03,0x08,0xF9,0x06,0x42,0x80,0x03,0x41,0x42,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x47,0x32,0x08,0x01,0x08,0x0B,0x0A,0x01,0x02,0x0B,0x44,0x0B, ++ 0x10,0x01,0x1C,0x8A,0x07,0x0B,0xEA,0xF5,0x70,0x00,0x04,0x01,0xF8,0x00,0x06,0x42, ++ 0x80,0x01,0x06,0x42,0x00,0xE0,0x06,0x01,0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x42, ++ 0x00,0xE0,0x07,0x01,0x00,0x00,0x00,0x42,0x50,0x20,0x07,0x01,0x08,0x20,0x02,0x01, ++ 0x52,0xE2,0x43,0x83,0x03,0x83,0x42,0xE2,0xF7,0x0B,0x4C,0xF9,0x94,0x16,0xF0,0x0B, ++ 0xE4,0x48,0xB2,0x0B,0xF0,0x03,0x44,0xC1,0x90,0x0E,0x00,0x01,0x03,0x83,0x3C,0x82, ++ 0x4C,0xB2,0x4B,0x53,0x5C,0xA2,0xE3,0xC3,0x1C,0x12,0x0C,0x53,0x10,0x43,0x02,0x09, ++ 0xB3,0xC3,0x3C,0x82,0xAB,0x85,0x40,0x8A,0x84,0x01,0x42,0x0B,0x10,0x01,0x1C,0x8A, ++ 0x03,0x0B,0x54,0x7A,0x4B,0x62,0x43,0x7A,0x86,0x1F,0xC0,0x97,0xEF,0x85,0xA8,0xC5, ++ 0x47,0x4A,0x83,0x01,0xC3,0x0B,0x70,0x62,0x30,0x48,0xAC,0x46,0xC2,0x0B,0x10,0x01, ++ 0x18,0x8A,0x80,0x0B,0x44,0x83,0x0B,0x01,0x1B,0x42,0x04,0x83,0xE8,0xC5,0x0F,0x01, ++ 0x0D,0x8B,0x45,0x9B,0x66,0x02,0x03,0x79,0x01,0x1A,0x30,0x2A,0xAB,0x01,0x69,0x04, ++ 0x50,0x13,0x5B,0x09,0x80,0xE6,0x58,0x29,0x80,0x46,0x58,0x41,0x8B,0xB6,0x93,0x4B, ++ 0x46,0x9B,0x3F,0xD8,0x88,0x16,0x00,0x81,0x07,0x83,0xED,0xC5,0x0A,0x8B,0x4D,0xDA, ++ 0x10,0x42,0x8C,0x16,0x07,0x29,0x05,0x83,0x00,0x3F,0xE0,0x92,0x02,0x93,0xE7,0x00, ++ 0x93,0x05,0x2C,0x04,0x40,0x89,0x9A,0x06,0x28,0x0C,0x03,0xA1,0x07,0x83,0xED,0xC5, ++ 0x5B,0x9A,0xD2,0x7B,0x40,0xDC,0x78,0x11,0x90,0x56,0x7B,0x01,0x8F,0x36,0x40,0x83, ++ 0x50,0x7A,0x02,0x84,0x43,0x7A,0x12,0x03,0x2C,0x0C,0x03,0x1F,0x40,0x83,0x17,0xD0, ++ 0x48,0x5A,0xC2,0x80,0x90,0x3D,0x04,0x7C,0x00,0x89,0x16,0x00,0xD1,0xC0,0x41,0x01, ++ 0xC7,0x96,0x90,0xC5,0xBC,0xFF,0xF7,0x37,0x44,0x3A,0x12,0x3A,0x82,0x96,0x43,0x32, ++ 0x84,0x41,0x10,0x3A,0x88,0x76,0x03,0x09,0x86,0x07,0xC8,0x37,0x05,0xC1,0xB0,0x03, ++ 0x40,0x12,0x0A,0x09,0x83,0x0B,0x00,0x2F,0x46,0xBA,0x81,0x01,0xC8,0x03,0x42,0x01, ++ 0x89,0x26,0x41,0xEA,0xC4,0x31,0x16,0x3A,0x89,0xAE,0x40,0xEA,0x41,0x0B,0x40,0xCA, ++ 0x72,0x50,0x80,0x01,0x80,0x13,0x60,0x50,0x80,0x13,0x52,0x50,0x86,0x13,0x84,0x0B, ++ 0xC2,0x0B,0xC0,0x13,0xC4,0x48,0xC4,0x13,0xC6,0x1B,0xC6,0x90,0xC5,0x48,0x8C,0x29, ++ 0x50,0x50,0x88,0x13,0x88,0x0B,0x02,0x69,0x19,0x00,0xD0,0xC0,0x40,0x81,0xC2,0x0E, ++ 0x29,0x04,0x03,0xFF,0x06,0x01,0x18,0x02,0x29,0x04,0x03,0xDF,0x41,0x6A,0xC1,0xC0, ++ 0x40,0x19,0xC1,0x26,0x29,0x04,0x43,0x62,0x11,0x03,0x03,0x9F,0x01,0xC7,0x41,0x4A, ++ 0xC1,0x81,0xC1,0xC0,0x40,0x01,0xC1,0x26,0x29,0x04,0x43,0x3A,0xC3,0x01,0x11,0x03, ++ 0x00,0x47,0x01,0x69,0x19,0x00,0xD0,0xC0,0x41,0xB1,0xC1,0x1E,0x29,0x04,0x03,0x0F, ++ 0x7D,0xD2,0x10,0xC2,0x87,0xF6,0x40,0xBB,0xA0,0xBA,0x40,0xDA,0xC4,0xD1,0x15,0x1A, ++ 0x8B,0x7E,0x68,0x04,0x40,0x61,0x8A,0x66,0x50,0x1B,0xE3,0xFA,0x52,0x72,0x90,0x01, ++ 0x78,0x01,0x8C,0x16,0x04,0x09,0xA8,0x83,0x00,0x1F,0xE0,0xC2,0x40,0x01,0x88,0x06, ++ 0xAB,0x8B,0x6C,0x04,0xE4,0x00,0x92,0x05,0x2A,0x04,0x43,0x89,0x98,0x16,0x00,0x01, ++ 0x1B,0x02,0x2E,0x04,0xD2,0x43,0xE3,0x00,0x90,0x43,0x03,0x81,0x07,0x83,0xED,0xC5, ++ 0x07,0x8B,0xED,0xC5,0x10,0x00,0x00,0x42,0x00,0xE0,0x00,0x01,0xF8,0x00,0x06,0x42, ++ 0x80,0xC0,0x04,0x01,0x08,0x40,0x00,0x01,0x80,0x01,0x06,0x42,0xF8,0xFF,0x07,0x00, ++ 0x00,0x10,0x00,0x01,0x80,0x30,0x02,0x01,0x88,0x36,0x00,0x00,0x00,0x20,0x00,0x01, ++ 0x00,0xA0,0x00,0x01,0x77,0x81,0xF8,0xFF,0xF8,0x02,0x07,0x00,0xA8,0x85,0x80,0x07, ++ 0xC8,0xBF,0x65,0x32,0xC8,0x03,0x43,0x01,0x80,0x26,0x40,0x31,0x8F,0xD6,0xBF,0xFF, ++ 0xD7,0x8F,0x3C,0xBF,0xBE,0xFF,0xCF,0x97,0x38,0xA7,0x07,0x00,0x00,0xE0,0x06,0x01, ++ 0xAF,0xC5,0x77,0x62,0x03,0x01,0x87,0x83,0x01,0x09,0x80,0x83,0x0F,0x01,0x81,0x8B, ++ 0x05,0x19,0x80,0x83,0x03,0x41,0x89,0x83,0x07,0x69,0x89,0x83,0x05,0x69,0x88,0x83, ++ 0x11,0x02,0x32,0xAA,0xA9,0x01,0x06,0x44,0x04,0xF9,0x87,0x89,0x20,0x84,0x01,0x09, ++ 0x34,0x62,0xE1,0x01,0x93,0x03,0x91,0x03,0x05,0x41,0x90,0x03,0x17,0x51,0x90,0x13, ++ 0x11,0xA1,0x98,0x13,0x98,0x0B,0x0D,0x81,0x99,0x0B,0xA7,0x03,0x3B,0x01,0xA0,0xBB, ++ 0x09,0x71,0x98,0x8B,0x0B,0x29,0x98,0x8B,0x17,0x71,0x98,0x93,0x99,0x8B,0xA5,0xBB, ++ 0xA1,0x83,0x05,0x81,0xA0,0x83,0x07,0x51,0x8F,0x03,0x01,0xB1,0x8D,0x03,0x8B,0x3B, ++ 0x8B,0x3B,0x9F,0x0B,0x05,0x99,0x28,0x84,0x07,0xF9,0x87,0x09,0x10,0x44,0x01,0xC9, ++ 0x0B,0x00,0x12,0x44,0x02,0x19,0x18,0x00,0x0E,0x43,0x43,0x5A,0x0A,0x43,0x05,0x01, ++ 0xB9,0x43,0x31,0x02,0x0D,0x51,0x80,0x11,0x83,0x1F,0xD0,0x17,0x01,0xB1,0x97,0x43, ++ 0x1B,0xF1,0x90,0x5B,0x89,0x7B,0x33,0x02,0x82,0x01,0xB2,0x3B,0xB8,0x3B,0x08,0xC1, ++ 0xB8,0x0B,0x0A,0x51,0xBE,0x0B,0x14,0x41,0x31,0x0A,0x88,0x01,0x0F,0x54,0x12,0xF9, ++ 0x94,0x99,0x0A,0x54,0x16,0xC1,0xBE,0x13,0x10,0x41,0x81,0x53,0x12,0x11,0x87,0x53, ++ 0x80,0x5B,0x14,0x51,0x91,0x13,0x12,0x41,0x93,0x13,0x14,0x21,0x92,0x13,0x16,0xA9, ++ 0x08,0x14,0x16,0x71,0x9A,0x13,0x10,0x69,0xA0,0x13,0x10,0x21,0xA6,0x13,0x12,0x41, ++ 0x10,0x14,0x12,0x31,0xBF,0x93,0x37,0xBC,0xB0,0x3B,0x1C,0x21,0x33,0x12,0x90,0x01, ++ 0x90,0x9B,0x1C,0x31,0x96,0x9B,0x12,0x99,0x08,0x94,0x11,0xA1,0x80,0x53,0x16,0x51, ++ 0x8E,0x53,0xB0,0x3B,0x12,0x21,0x8C,0x53,0x53,0x42,0x05,0x54,0x14,0x09,0x88,0x53, ++ 0x10,0x51,0x90,0x53,0x17,0x11,0xA0,0x13,0x08,0x21,0xA8,0x0B,0x0A,0xC1,0xAB,0x0B, ++ 0xA8,0x0B,0x1C,0x01,0x33,0x0A,0xC8,0x01,0xA0,0x5B,0xAE,0x5B,0x22,0xF1,0x88,0x01, ++ 0xBA,0x63,0xB8,0x63,0x24,0xE1,0xB9,0x63,0x26,0x41,0xB8,0x63,0x80,0x13,0x08,0xB1, ++ 0x80,0x0B,0x0A,0x19,0x84,0x0B,0x4C,0xD2,0x00,0x0B,0x92,0x1B,0x4C,0xCA,0xC4,0x01, ++ 0x38,0x0B,0x88,0x91,0x3E,0x0B,0x8A,0xE1,0x38,0x0B,0x0C,0xE1,0x40,0xB2,0x84,0x1F, ++ 0xCC,0xBF,0x47,0xAA,0x09,0xE1,0xC0,0xC1,0x87,0x1F,0xC8,0x97,0x4C,0x8A,0x44,0x9A, ++ 0xCE,0x11,0x03,0x0B,0xCC,0x71,0x00,0x0B,0x88,0xA1,0x08,0x0B,0x8A,0xA1,0x08,0x0B, ++ 0xCA,0xE1,0x01,0x0B,0xC8,0xC1,0x01,0x0B,0x8C,0x61,0x0D,0x0B,0xCA,0x81,0x15,0x0B, ++ 0xF8,0x48,0x10,0x0B,0xFE,0x48,0x08,0x0B,0xE9,0xC5,0xAF,0x85,0x0C,0x01,0x60,0x0A, ++ 0x47,0x02,0xA4,0x61,0xF8,0x1B,0x06,0x77,0x02,0x21,0x19,0x42,0xCB,0x28,0x00,0x99, ++ 0x12,0x79,0x08,0x00,0xC4,0x40,0x89,0x13,0x16,0x01,0x88,0x13,0x94,0x13,0x10,0x14, ++ 0x12,0x14,0xE6,0x48,0x94,0x4D,0x16,0x5A,0xC0,0x76,0x07,0x01,0x13,0xF9,0x2F,0x89, ++ 0x08,0x68,0x03,0x37,0x00,0x08,0xCA,0x48,0xCC,0x48,0xAA,0x53,0xAA,0x53,0xE6,0x00, ++ 0x94,0x05,0x16,0x1A,0xC1,0xB6,0xEF,0x85,0xA3,0x85,0x51,0x72,0x90,0x01,0x0E,0x01, ++ 0x26,0x8C,0xD0,0x01,0xBC,0x8B,0xB8,0x8B,0x36,0x9A,0x98,0x01,0x8A,0xCB,0x0C,0xCC, ++ 0x9E,0xCB,0x88,0xCB,0x2C,0x09,0xB0,0xAB,0xA8,0x8B,0x34,0xA2,0xA1,0x01,0xCD,0x1B, ++ 0xB0,0x9B,0x36,0x9A,0x9A,0x01,0xA9,0xCB,0x9A,0x01,0xA9,0xEB,0xA8,0xCB,0xA8,0xAB, ++ 0x28,0x41,0x89,0xAB,0x8B,0x0B,0x57,0x32,0x88,0x8B,0x46,0x09,0x8C,0x16,0xA8,0xCB, ++ 0xE5,0x85,0x39,0x97,0xE3,0x85,0x39,0x82,0x0B,0x08,0x42,0x12,0x41,0x13,0x18,0x01, ++ 0x04,0xD2,0x90,0x41,0x04,0x13,0x10,0xD0,0x1A,0x8A,0x08,0x0B,0x40,0x0B,0x42,0x0B, ++ 0x14,0x41,0x18,0x8A,0x00,0x0B,0x08,0x01,0x03,0x0B,0x3C,0x82,0xAA,0x85,0x40,0xD2, ++ 0x40,0x0B,0x30,0x48,0xAE,0x2E,0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B,0x08,0x81, ++ 0x02,0x0B,0x48,0xAA,0x8C,0x01,0x46,0x53,0x38,0x90,0x78,0x90,0x04,0x53,0x44,0x53, ++ 0x18,0x81,0x19,0xD2,0x02,0x53,0x5C,0x8A,0x12,0x09,0x06,0xD3,0x16,0x91,0x01,0x13, ++ 0x44,0x7A,0x42,0x23,0x10,0x61,0x18,0xA2,0x02,0x23,0x44,0x23,0x1A,0xA2,0x00,0x23, ++ 0x4C,0x23,0x1A,0xA2,0x08,0x23,0x4A,0x23,0x18,0xA2,0x08,0x23,0x40,0x23,0x1E,0xA2, ++ 0x02,0x23,0x46,0x43,0x10,0x01,0x1A,0x82,0x04,0x43,0x02,0xD1,0x07,0xC3,0x00,0x01, ++ 0x08,0xC3,0xEA,0x85,0x40,0x12,0x42,0x13,0x08,0x09,0x18,0x52,0x00,0x13,0x48,0x13, ++ 0x18,0x52,0x0C,0x13,0x4C,0x13,0x1A,0x52,0x0E,0x13,0x42,0x13,0x1E,0x52,0x00,0x13, ++ 0x39,0x82,0x43,0xE2,0x58,0x0B,0x10,0x21,0x18,0x8A,0x18,0x0B,0x5A,0x0B,0x10,0x01, ++ 0x18,0x8A,0x18,0x0B,0x5C,0x13,0x08,0x01,0x18,0x52,0x18,0x13,0x40,0x92,0x11,0x01, ++ 0x80,0x01,0x06,0x13,0x40,0x13,0x1A,0x52,0x01,0x13,0x4A,0x72,0x41,0x43,0x10,0x01, ++ 0x18,0x82,0x00,0x43,0x38,0x82,0xAB,0x85,0x08,0x09,0x00,0x31,0x81,0x07,0xD0,0xF7, ++ 0x08,0x11,0x00,0x21,0x81,0x07,0xD0,0xD7,0x00,0x09,0x80,0x07,0xD0,0xB7,0x02,0x31, ++ 0x82,0x07,0xD0,0x9F,0x00,0x21,0x80,0x07,0xD0,0x87,0x82,0x07,0xD0,0x2F,0xEB,0x85, ++ 0xA8,0x85,0x43,0xF2,0x4A,0xBA,0xC0,0x91,0x11,0x43,0x0A,0x91,0x80,0x1F,0xC8,0x07, ++ 0x40,0xD2,0x08,0x51,0x80,0x41,0x81,0x1F,0xC7,0xEF,0xBF,0xFF,0xF0,0x4F,0x02,0x09, ++ 0xBA,0xFF,0xFF,0x17,0x07,0xA1,0xB8,0xFF,0xFF,0x3F,0xBB,0xFF,0xFF,0xBF,0xBB,0xFF, ++ 0xFF,0xC7,0xBD,0xFF,0xFF,0x3F,0xBD,0xFF,0xF8,0x77,0x66,0x8A,0x29,0x01,0x80,0x2B, ++ 0x08,0x2B,0x41,0x72,0x09,0x71,0x80,0x91,0x87,0x1F,0xC0,0x17,0x0B,0x2C,0x81,0x2B, ++ 0x87,0x2B,0x85,0x2B,0x8B,0x2B,0x89,0x2B,0x05,0x51,0x88,0x03,0x0F,0x2C,0x8B,0x2B, ++ 0x0B,0x2C,0xED,0x85,0x00,0xE0,0x00,0x01,0xC8,0x21,0x01,0x00,0x70,0x02,0x01,0x00, ++ 0xF8,0xFF,0x07,0x04,0x68,0xE2,0x01,0x00,0x70,0x70,0x06,0x01,0x80,0xC0,0x04,0x01, ++ 0x00,0x20,0x00,0x01,0x10,0x00,0x00,0x42,0x00,0x00,0x00,0x42,0x80,0x01,0x06,0x42, ++ 0xF8,0x00,0x06,0x42,0x18,0x00,0x02,0x42,0xA8,0x85,0x80,0x07,0xC8,0xCF,0xEE,0x85, ++ 0xAF,0x85,0xB8,0xFF,0xE8,0x9F,0xEF,0x85,0xA8,0x7D,0x80,0x04,0x88,0x0C,0xC0,0x0C, ++ 0x80,0x14,0xC0,0x04,0x83,0x1C,0x30,0x42,0x40,0x7E,0x80,0x25,0xE8,0x05,0x00,0x00, ++ 0xAC,0xFD,0x87,0x1D,0x30,0x32,0x00,0x01,0x82,0x14,0x00,0x9F,0x44,0xDA,0x0E,0x01, ++ 0x0C,0x0B,0x26,0x01,0xC2,0x14,0x00,0x28,0x7F,0xC2,0x4E,0xC3,0x1F,0x02,0x09,0xC3, ++ 0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x86,0x17,0xE0,0x1F, ++ 0xF8,0x82,0x33,0x0A,0xCF,0x99,0x49,0xC9,0x99,0x3E,0x40,0x91,0xE7,0x16,0x48,0xC3, ++ 0x1F,0x02,0x0D,0xC3,0x40,0x20,0x63,0x01,0x88,0x36,0xD7,0x6C,0x90,0x04,0x10,0x09, ++ 0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x17,0xE3,0x77,0xFD,0xA2,0xD0,0x6C,0x90,0x04, ++ 0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x85,0x17,0xE0,0x2F,0xF8,0xBA,0xD3,0x6C, ++ 0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x17,0xE5,0xE7,0x14,0x3A, ++ 0xE9,0x16,0x30,0x02,0x30,0xE2,0x31,0x3A,0xFD,0x82,0x13,0xC2,0xE3,0x0E,0x98,0xBA, ++ 0x05,0x17,0x10,0x02,0xDB,0x06,0x98,0xA2,0x46,0xC2,0x4D,0x03,0xDE,0x8A,0x0B,0x00, ++ 0xC0,0x00,0xCA,0x24,0x00,0x44,0xC0,0x24,0xE0,0x00,0x84,0x24,0xC2,0x14,0xE0,0x00, ++ 0x90,0x05,0x86,0x14,0xC8,0x2C,0xC0,0x14,0x15,0x42,0x9C,0x3E,0x87,0x3D,0xE8,0x85, ++ 0xAC,0xFD,0x87,0x7D,0x30,0xA2,0x30,0xFA,0xD8,0x0B,0x8F,0x6C,0xD8,0x0B,0x8B,0x64, ++ 0x40,0x01,0x80,0x6E,0x48,0x52,0x05,0x99,0x07,0x43,0x12,0xF9,0x58,0x3A,0x95,0x81, ++ 0x10,0xD3,0x06,0x43,0x00,0xC1,0x83,0x17,0xF8,0xFF,0xF1,0x84,0xB0,0xE1,0x01,0xCF, ++ 0x40,0x1A,0x0D,0x19,0x04,0x0B,0x0A,0x19,0x05,0x0B,0x48,0x12,0xC2,0x84,0xC0,0x30, ++ 0x11,0x01,0x30,0xDA,0x30,0x8A,0x00,0x09,0x82,0x17,0xC0,0xC7,0x29,0x01,0x30,0x1A, ++ 0x14,0x09,0x08,0x01,0x40,0x1D,0xB8,0x04,0x82,0x17,0xE0,0x6F,0xE7,0x68,0x93,0x6D, ++ 0x6F,0x91,0x99,0xA6,0x48,0xB2,0x44,0x43,0x10,0x11,0x18,0x82,0x01,0x43,0x30,0x02, ++ 0x80,0x01,0x35,0x2A,0xC8,0x03,0x32,0x00,0xAC,0xEE,0x49,0x9A,0x00,0x01,0x80,0x43, ++ 0x31,0x12,0x31,0xCA,0x00,0x11,0x80,0x0F,0xF9,0xF7,0x34,0x1A,0xB8,0x04,0x08,0x01, ++ 0x00,0x11,0xD0,0x84,0x84,0x17,0xC0,0x47,0x49,0x42,0xD4,0x43,0x08,0x43,0x2A,0x01, ++ 0xC2,0x64,0x00,0x00,0x80,0x74,0x00,0xBF,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09, ++ 0x81,0x17,0xC0,0x27,0xB8,0x0C,0xA0,0x04,0x30,0x8A,0x41,0x1D,0xD8,0x84,0xD0,0x64, ++ 0xB9,0xFF,0xFF,0xF7,0xC4,0x74,0xC8,0x30,0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42, ++ 0x80,0x17,0xC0,0xA7,0xE7,0x68,0x93,0x6D,0xC4,0x6C,0x10,0x2A,0x99,0x26,0x37,0x1A, ++ 0xB8,0x04,0x08,0x01,0x00,0x19,0xD0,0x84,0x82,0x17,0xC0,0xF7,0x31,0x12,0x31,0xCA, ++ 0x00,0x01,0x80,0x0F,0xFB,0x47,0x4B,0x92,0x40,0x43,0x10,0x11,0x18,0x82,0x04,0x43, ++ 0x87,0x9D,0xE8,0x85,0xAC,0xFD,0x87,0x1D,0x30,0x7A,0x50,0x01,0x80,0x16,0x00,0x01, ++ 0x80,0x0C,0x00,0x0F,0x00,0x09,0x80,0x0C,0x2A,0x01,0x00,0x47,0xCD,0x64,0x00,0x40, ++ 0xC1,0x30,0x32,0x52,0x08,0x19,0xD8,0x6C,0xC0,0x0C,0x80,0x0F,0xF9,0x3F,0x07,0x41, ++ 0x85,0x17,0xF0,0xD7,0x20,0x09,0xC0,0x34,0x80,0x01,0x84,0x14,0x60,0x81,0x99,0x36, ++ 0x0A,0xF9,0x47,0xF2,0x88,0x11,0x18,0x0B,0x42,0x08,0x1B,0x0B,0x02,0x0F,0x40,0xDA, ++ 0x1F,0x23,0x02,0xF9,0x4F,0xCA,0x82,0x89,0x88,0x01,0x12,0x43,0x00,0x11,0x80,0x17, ++ 0xF0,0x1F,0xC5,0x14,0xF0,0x03,0x46,0x01,0x80,0x3E,0x00,0x51,0x84,0x17,0xF0,0xE7, ++ 0x40,0x83,0x41,0x03,0x30,0x00,0xA8,0x86,0x07,0x5F,0x00,0xF9,0x4C,0x7A,0x82,0x89, ++ 0x88,0x01,0x12,0x43,0x00,0x09,0x80,0x17,0xF1,0x7F,0x44,0x83,0x40,0x03,0x30,0x00, ++ 0xA3,0x1E,0xE0,0x20,0x93,0x25,0x67,0xF9,0xC9,0x86,0x06,0xE4,0xE1,0xF8,0x35,0x52, ++ 0x08,0x09,0xD8,0x6C,0xC0,0x0C,0x80,0x0F,0xFB,0x4F,0xE5,0x68,0x90,0x6D,0xC7,0x1C, ++ 0x15,0x2A,0x9C,0x9E,0x3F,0x17,0xA9,0x85,0x80,0x3D,0x34,0x7A,0x34,0xA2,0x00,0xD9, ++ 0xEF,0x02,0x0E,0xF9,0x88,0x09,0x40,0x01,0x80,0x0E,0x30,0x72,0x00,0x0F,0x30,0x19, ++ 0x13,0xB0,0xD9,0xC3,0x81,0x34,0xD8,0xC3,0x80,0x2C,0x98,0x1C,0xC2,0x34,0x00,0x00, ++ 0xC0,0x00,0x86,0x24,0x45,0xAA,0x11,0x81,0x00,0x13,0x1A,0x0B,0x28,0x01,0x00,0x67, ++ 0x4D,0x03,0x01,0x48,0xC0,0x00,0x42,0x03,0x01,0x33,0x30,0x1A,0x30,0x52,0x09,0x09, ++ 0x00,0x01,0x80,0x0F,0xFB,0xDF,0xE3,0x68,0x90,0x6D,0xC7,0x34,0x17,0x2A,0x9C,0x7E, ++ 0x28,0x01,0x00,0x67,0x4D,0x03,0x03,0x48,0xC0,0x00,0x42,0x03,0x00,0x33,0x08,0x09, ++ 0x31,0x1A,0x31,0x52,0x30,0x42,0x80,0x0F,0xFB,0x4F,0xE3,0x68,0x90,0x6D,0xC7,0x2C, ++ 0x17,0x2A,0x9C,0x7E,0x48,0x0B,0xA1,0x0C,0x89,0x04,0x30,0xDA,0x10,0x09,0xC8,0x1C, ++ 0xC7,0x34,0xB8,0xFF,0xFB,0xFF,0x4A,0x0B,0x89,0x04,0x30,0xDA,0x10,0x01,0xA0,0x0C, ++ 0xC8,0x24,0xC0,0x2C,0xBA,0xFF,0xFF,0xB7,0x48,0xC2,0x00,0x01,0x88,0x01,0x12,0x43, ++ 0x48,0xB2,0x18,0x43,0x37,0x57,0xAE,0xC5,0x30,0x1A,0x30,0x42,0x30,0xBA,0xD8,0x23, ++ 0xD8,0x2B,0x4A,0xB2,0xC0,0xC8,0x8A,0x04,0x30,0xD2,0x31,0xCA,0x87,0x0F,0xF8,0xDF, ++ 0x30,0x01,0x00,0x3F,0x09,0x09,0x30,0xDA,0x30,0x92,0x31,0x42,0x81,0x0F,0xF8,0xB7, ++ 0xE7,0xB0,0x93,0xB5,0x17,0x32,0x9D,0xAE,0xC8,0x04,0x10,0x01,0x18,0x01,0x00,0x4F, ++ 0x00,0x01,0x00,0x1F,0x82,0x5B,0xE0,0x48,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE, ++ 0xE6,0x90,0x92,0x95,0x17,0x12,0x9D,0x9E,0xE8,0xC5,0x07,0x00,0x00,0x01,0x00,0x42, ++ 0x18,0x00,0x04,0x42,0x48,0xE0,0x06,0x00,0x00,0xD0,0x00,0x01,0x60,0x20,0x02,0x00, ++ 0x49,0x32,0x41,0x2A,0x05,0x43,0x9E,0xFF,0x7F,0x04,0x3A,0xF7,0x94,0x15,0x3A,0x00, ++ 0x77,0x18,0x06,0xF9,0x04,0xC2,0x3C,0x48,0x74,0x48,0x00,0xCA,0x50,0x01,0xD0,0x5E, ++ 0x38,0x90,0x78,0x90,0xD4,0x41,0x40,0x98,0x54,0xE2,0x00,0xD8,0xC6,0xD0,0x4C,0x9B, ++ 0x18,0x1A,0x1C,0x5A,0x0B,0x9B,0x3E,0x82,0x40,0x98,0x54,0xCA,0x04,0xD8,0xC4,0xD0, ++ 0x44,0x9B,0x18,0x1A,0x18,0x5A,0x00,0x9B,0x3A,0x82,0x93,0x05,0x36,0x10,0x76,0x90, ++ 0x0C,0x09,0x00,0x8A,0x48,0x00,0x52,0x9A,0x04,0x00,0xC4,0x00,0x03,0x0B,0x38,0x82, ++ 0x96,0x05,0x32,0x10,0x70,0x90,0x0E,0x09,0x00,0x8A,0x54,0x72,0x4C,0x00,0x02,0x00, ++ 0x94,0x01,0xC4,0x00,0x03,0x0B,0x38,0x82,0xB3,0x15,0x3B,0x82,0xFB,0x85,0x39,0x82, ++ 0x40,0x32,0x48,0x0B,0x10,0x21,0x18,0x8A,0x0B,0x0B,0x38,0x82,0x48,0x1A,0x48,0x43, ++ 0x14,0x21,0x18,0x82,0x0B,0x43,0x38,0x82,0x07,0x20,0x28,0xD0,0x68,0x07,0x00,0x07, ++ 0x20,0x07,0x00,0x07,0x08,0x07,0x00,0x07,0xAC,0xFD,0x87,0x4D,0xD0,0x94,0x30,0x22, ++ 0xF8,0x43,0x80,0x0C,0xF8,0x6B,0xC6,0x64,0x08,0x01,0x80,0x0B,0x00,0x01,0x00,0x8F, ++ 0x0A,0x21,0x19,0x0A,0x18,0x99,0xCB,0x48,0x0E,0xD8,0xC2,0x48,0xC8,0x4B,0x4C,0x79, ++ 0x80,0x36,0x80,0x83,0xE0,0x90,0xCA,0x64,0xD8,0x64,0xC0,0x4B,0xE0,0x48,0x82,0xCB, ++ 0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0x5E,0xC0,0x64,0xC0,0x03,0x80,0x44,0x40,0x01, ++ 0x88,0x0E,0x80,0x6D,0xE8,0x85,0xC7,0x44,0x40,0x09,0x88,0x1E,0xC0,0x0C,0x40,0x09, ++ 0x8F,0x06,0x38,0xB7,0x00,0x01,0x80,0x34,0x80,0x2C,0xC8,0x44,0xC4,0x0C,0x10,0x0A, ++ 0x88,0x96,0x02,0x01,0x30,0x01,0x08,0x01,0x88,0x1C,0x88,0x14,0x1C,0xC9,0x09,0xD8, ++ 0x00,0x4F,0x10,0x31,0x18,0x52,0xCA,0x90,0xC2,0x90,0x46,0xBC,0xC4,0xC0,0x41,0x94, ++ 0xCA,0xB0,0xE4,0x48,0x90,0x4D,0xD6,0x0C,0x17,0x8A,0x9C,0x96,0xC8,0x0C,0x80,0x17, ++ 0xF0,0x6F,0x82,0x24,0x30,0x82,0xC9,0x0C,0x82,0x17,0xF0,0x47,0x30,0x32,0x08,0x01, ++ 0x01,0x01,0x00,0x07,0x1A,0x99,0x0B,0xD8,0x02,0x0F,0xE0,0x48,0x91,0x4D,0x16,0x21, ++ 0x18,0x52,0xCA,0x90,0xC4,0x90,0xCE,0x93,0x57,0x79,0x80,0xB6,0x12,0x21,0x19,0x52, ++ 0xCE,0x90,0xC0,0x98,0x3E,0xF1,0xF8,0xFA,0xDF,0x1C,0xC0,0xD8,0x98,0x1C,0x18,0xE9, ++ 0x0E,0xD8,0xC6,0x98,0x14,0x01,0xF0,0xD2,0xDE,0x14,0xC0,0x90,0x92,0x14,0xE0,0x48, ++ 0x92,0x4D,0xE6,0x00,0x90,0x05,0xD6,0x44,0x16,0x12,0xC4,0xDE,0xC8,0x44,0xC0,0x1C, ++ 0x80,0x17,0xF0,0xE7,0x30,0x3A,0xC8,0x44,0xC0,0x14,0x80,0x17,0xF0,0xBF,0xC8,0x24, ++ 0xD8,0x48,0x8E,0x34,0xD0,0x80,0x81,0x2C,0x08,0x01,0x10,0x01,0x00,0x77,0x00,0x01, ++ 0x33,0x5A,0x18,0x5A,0xF2,0x5C,0x00,0xD8,0xC8,0xD8,0x04,0x1F,0x04,0x30,0x9A,0xD2, ++ 0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE,0xE6,0x48,0x92,0x4D,0x17,0x4A,0x9D,0x76, ++ 0x08,0x01,0x10,0x01,0x03,0xE7,0x19,0x99,0x08,0xD8,0x02,0x0F,0xE6,0x48,0x92,0x4D, ++ 0x02,0x21,0x19,0x42,0xCC,0x00,0x30,0x22,0xC0,0x00,0x86,0x3C,0xC8,0x03,0x44,0x79, ++ 0x80,0xA6,0x07,0x01,0x00,0x2F,0xD9,0x3C,0x34,0xF1,0xF8,0xF2,0xD9,0x34,0x38,0xC9, ++ 0xC0,0xB0,0x1F,0x31,0x18,0x1A,0xCA,0xD8,0x0E,0xF8,0xCD,0xD8,0x47,0xFC,0xDA,0xB0, ++ 0xAB,0x06,0x10,0xB2,0x95,0xB5,0x35,0xB2,0x37,0xE9,0x08,0xB0,0x20,0x32,0x3B,0x01, ++ 0xF8,0xBA,0xF7,0x2C,0x45,0xDC,0xCC,0xF0,0xD0,0x98,0xAF,0x06,0x10,0xDA,0x32,0xB2, ++ 0x18,0x72,0xFB,0x5C,0x07,0xB0,0xCB,0xB0,0x22,0x9A,0x03,0x38,0x9A,0x9A,0xE7,0x00, ++ 0x90,0x05,0xDE,0x0C,0x16,0xC2,0x9C,0xB6,0xE6,0x48,0x92,0x4D,0xE6,0x90,0x92,0x95, ++ 0xC0,0x64,0xC0,0x03,0x15,0x82,0xC4,0xF6,0xC0,0x64,0xC8,0x0C,0xC4,0x03,0x10,0x42, ++ 0xC9,0x06,0x38,0xF7,0xC1,0x0C,0x38,0xE7,0xAC,0x85,0x87,0x3D,0x34,0x22,0x00,0x91, ++ 0xD4,0x02,0x34,0x22,0x01,0xC1,0xF0,0x02,0x18,0x71,0x80,0x34,0xF0,0x1A,0x9F,0x2C, ++ 0xD0,0x00,0x96,0x05,0x1F,0xD1,0xF0,0x1A,0x2B,0x81,0xF8,0x2A,0x32,0xF2,0xDC,0xD8, ++ 0x90,0xDD,0xA8,0x24,0xC0,0x2B,0x6F,0x09,0x8D,0x16,0x10,0x04,0x10,0x1C,0x07,0x6F, ++ 0x55,0x3C,0x05,0xE8,0xC7,0x68,0x51,0x04,0x07,0x30,0xC4,0x98,0xD9,0x68,0x97,0x6D, ++ 0xD0,0xC0,0x90,0x1D,0x84,0x40,0x85,0xD8,0x17,0x04,0x15,0x1C,0x4B,0x81,0x80,0xF6, ++ 0xE9,0x2C,0xC0,0x40,0x02,0x28,0xCA,0x00,0xEA,0x34,0xC8,0x00,0x80,0x00,0x94,0x05, ++ 0xEF,0x24,0xC0,0x58,0x02,0xE8,0xCA,0xE8,0x37,0x9A,0xC3,0x58,0x80,0xD8,0x94,0xED, ++ 0x90,0x01,0x46,0x01,0xD0,0x0E,0x00,0x01,0x00,0x27,0x50,0x9C,0x10,0x1A,0xD4,0x0E, ++ 0x00,0x81,0xF0,0x82,0x68,0x01,0xD0,0x0E,0x28,0x01,0x00,0x27,0x55,0x9C,0x12,0x5A, ++ 0xD0,0x0E,0x28,0x91,0xF8,0xAA,0xD2,0x2C,0xD0,0x90,0xF0,0xB0,0xD2,0x06,0x10,0x92, ++ 0x06,0x98,0xC2,0xB8,0xD2,0x24,0xD8,0x90,0xF0,0x98,0xD0,0x06,0x15,0x92,0xC2,0xF8, ++ 0x7E,0xD0,0xCF,0x90,0x18,0x90,0x66,0x90,0x58,0x01,0xD0,0x06,0x12,0xDA,0x02,0xF8, ++ 0xC8,0xD8,0x76,0x01,0xD3,0x06,0x10,0xB2,0xCE,0xD8,0x7C,0xF0,0xC6,0x98,0x1F,0xD8, ++ 0x60,0xF0,0x48,0x41,0x80,0x0E,0x48,0x49,0x88,0x2E,0x48,0x49,0x8A,0x1E,0x20,0x88, ++ 0x63,0x50,0x20,0x88,0x63,0x70,0x30,0x0A,0x8B,0x0C,0x28,0x12,0xCB,0x06,0x30,0x12, ++ 0xCC,0x0C,0x10,0x72,0xC8,0x06,0xF0,0x0C,0xDB,0x2C,0x30,0x0A,0xD0,0x48,0x34,0x7A, ++ 0x1C,0xCA,0x02,0x58,0xC4,0x48,0x36,0x72,0x19,0x51,0x30,0xCA,0xF3,0x1A,0x07,0xF8, ++ 0xCA,0x48,0x1E,0x5A,0x32,0x8A,0xC3,0xC8,0x1B,0x82,0x32,0x12,0x46,0xB8,0xCA,0x00, ++ 0x02,0x00,0xC6,0x00,0x36,0x0A,0x03,0x48,0x88,0x1C,0x80,0x17,0xE8,0xBF,0x80,0x14, ++ 0xD0,0x24,0xC0,0x0C,0xD8,0x00,0x34,0x0A,0x1C,0x82,0x02,0x10,0xC0,0x00,0x14,0x61, ++ 0xF2,0x12,0x05,0x58,0xC2,0x48,0x1E,0x52,0xC3,0x80,0x18,0xAA,0x00,0x07,0x00,0x67, ++ 0xCE,0x48,0x07,0x48,0xC0,0x40,0xC8,0x1C,0x80,0x17,0xE8,0x07,0xCB,0x2C,0x08,0x0C, ++ 0xCD,0x24,0x08,0x0C,0xCF,0x14,0x08,0x0C,0x10,0x04,0x81,0x3D,0xEF,0x85,0xAF,0xF5, ++ 0x30,0x3A,0xC0,0x44,0x60,0xD2,0xCF,0xE0,0x2F,0x31,0x70,0xCA,0x1F,0xAA,0xC2,0x68, ++ 0xF5,0x21,0xC9,0x68,0x06,0x90,0xC2,0x90,0x59,0xAA,0xDF,0x81,0xC6,0xB0,0xFE,0x13, ++ 0x31,0xB2,0x34,0xDA,0x32,0x3A,0xB8,0x01,0x30,0x12,0xB8,0x0C,0x92,0x01,0xBE,0x01, ++ 0x59,0x09,0x88,0x4E,0x01,0x01,0x00,0x17,0xC0,0x0B,0x49,0x79,0x89,0xE6,0x40,0x4C, ++ 0x0B,0x0C,0x47,0x5C,0x14,0x1C,0x31,0xE2,0xC1,0x9B,0x89,0x1B,0xC3,0x9B,0x8B,0x1B, ++ 0x1B,0x0C,0x35,0x1A,0x19,0x1C,0x27,0x0C,0x23,0x1C,0x0B,0x0C,0x09,0x1C,0x45,0x4C, ++ 0x1B,0x0C,0x41,0x4C,0x19,0x0C,0x83,0x03,0x0F,0x09,0x80,0x0B,0x88,0x0B,0xFD,0x8B, ++ 0x90,0x0B,0x09,0x01,0x90,0x0B,0x03,0x27,0xA2,0x21,0xE1,0x00,0x93,0x05,0x2E,0x82, ++ 0x9B,0xD6,0x2E,0x82,0x94,0xF6,0x03,0x2F,0x1A,0x21,0x19,0xCA,0xC8,0x60,0x08,0x41, ++ 0x89,0x04,0x40,0x4C,0x18,0x0C,0x09,0x11,0xF3,0x4A,0x1B,0x0C,0x35,0x62,0xCC,0x0B, ++ 0x48,0x09,0x88,0xAE,0x08,0xC1,0x18,0xE1,0xF7,0x0A,0xF3,0x1A,0xD0,0x48,0xAE,0x06, ++ 0x14,0x4A,0x92,0x4D,0x30,0x72,0x1C,0xF1,0xF3,0x1A,0x37,0x0A,0xD0,0x48,0xAE,0x06, ++ 0x14,0x4A,0x92,0x4D,0xE3,0xDB,0x21,0x8A,0x10,0xCA,0xCC,0x0E,0x0D,0x01,0x88,0x0B, ++ 0x09,0xC1,0x18,0x01,0xF7,0x0A,0xF3,0x1A,0xD0,0x48,0xAE,0x06,0x14,0x4A,0x92,0x4D, ++ 0x30,0x62,0x0C,0xD1,0x1B,0x11,0xF1,0x0A,0xF6,0x1A,0xD7,0x48,0xAA,0x06,0x10,0x4A, ++ 0x24,0x0A,0x93,0x4D,0x30,0x62,0xDC,0x0C,0xC4,0x0B,0xE7,0xDB,0xE4,0xD8,0x12,0xCA, ++ 0xC8,0x7E,0xF8,0x8B,0xEE,0xDB,0x01,0xCA,0x28,0x0A,0xCB,0x56,0xD6,0x0B,0x4B,0x41, ++ 0x92,0x0E,0xE0,0x48,0x91,0x0B,0xD3,0x0B,0xFC,0x9B,0x10,0xCA,0x92,0x0E,0xE0,0x48, ++ 0x91,0x0B,0xD1,0x0B,0x28,0x0A,0xCB,0xA6,0xDF,0x0C,0xC0,0x0B,0xE2,0xDB,0xE4,0xD8, ++ 0x10,0xCA,0xCC,0x76,0xCA,0x0B,0x37,0x50,0xE2,0xCB,0x73,0x90,0xF4,0x48,0x12,0x52, ++ 0x89,0x0E,0x08,0x01,0x80,0x0B,0x35,0x12,0x09,0x81,0x30,0x02,0xBC,0xFF,0xF7,0xE7, ++ 0x00,0xDF,0xD8,0x0C,0xC4,0x0B,0xE7,0xDB,0xE4,0xD8,0x12,0xCA,0xC8,0x1E,0xF8,0x8B, ++ 0xEE,0xD3,0x01,0x8A,0x91,0x0B,0x59,0x0C,0x23,0x0C,0x59,0x0C,0x20,0x0C,0x33,0x12, ++ 0x30,0x02,0xC9,0x04,0xBC,0xFF,0xF7,0x47,0x03,0x01,0x90,0x03,0xD0,0x03,0x41,0x01, ++ 0x80,0x1E,0x00,0x07,0x02,0x3F,0xF1,0x00,0x97,0x03,0xC1,0x03,0x40,0xF9,0x93,0x0E, ++ 0xE7,0x00,0x82,0x03,0x43,0x44,0x15,0x04,0x03,0x19,0x80,0x03,0xE4,0xC3,0x83,0x01, ++ 0x89,0x03,0xCF,0x03,0xC2,0x8B,0xD1,0x00,0xE0,0x00,0x42,0x11,0xC3,0x2E,0xC8,0x03, ++ 0xC2,0x8B,0xD3,0x00,0xE0,0x00,0x42,0x11,0xCF,0x4E,0xC0,0x03,0x40,0x11,0x98,0x36, ++ 0xCA,0x0C,0xE0,0x4B,0x10,0x42,0xC4,0x16,0x07,0x01,0x80,0x03,0x89,0x03,0xC7,0x83, ++ 0x8B,0x03,0xC1,0x83,0x8F,0x03,0xEB,0xF5,0xAC,0x85,0x37,0xE2,0x34,0x2A,0xAB,0x01, ++ 0x4A,0x5C,0x27,0xD8,0x67,0xE0,0x40,0xF9,0x88,0x0E,0x00,0x01,0xE9,0x85,0x1F,0x21, ++ 0x1B,0xC2,0x5A,0xFA,0xC6,0x00,0xC4,0x00,0x1A,0x31,0x18,0xCA,0xC3,0x48,0x54,0xE2, ++ 0xD4,0x21,0xC1,0x50,0x0A,0xA1,0xF0,0x0A,0x48,0x01,0xD0,0x06,0x10,0x4A,0x1A,0xB1, ++ 0xF0,0x1A,0x5E,0x01,0xD2,0x06,0x10,0xDA,0xC3,0x48,0x5E,0xB2,0x10,0xCA,0x9C,0x06, ++ 0x08,0x01,0x30,0x71,0x44,0x9C,0xF8,0x32,0xD8,0xD8,0xAC,0x06,0x10,0xDA,0x32,0x81, ++ 0x44,0x94,0xFA,0x32,0xD8,0x90,0xAC,0x06,0x14,0x92,0xC2,0xD0,0x11,0x12,0x9D,0x0E, ++ 0xC8,0x33,0x74,0x09,0x8B,0x26,0xE0,0x5B,0xCA,0x3B,0xF6,0xD8,0x10,0xFA,0xDC,0xBE, ++ 0x70,0x09,0x88,0x3E,0xDC,0x5B,0x11,0x5A,0x9E,0x26,0xC0,0x03,0x40,0xF1,0xC0,0x0E, ++ 0x40,0x51,0x90,0x6E,0x70,0x09,0x88,0x1E,0x30,0x02,0x5B,0x04,0x40,0xC1,0x98,0x3E, ++ 0x70,0x09,0x88,0x16,0x04,0x00,0x13,0x82,0xCD,0x16,0x00,0x00,0x10,0x82,0xC4,0x0E, ++ 0x07,0x01,0xE8,0x85,0x07,0x09,0xE8,0x85,0xAC,0xFD,0x87,0x5D,0x30,0xB2,0x0C,0x01, ++ 0x28,0x01,0x00,0x01,0x80,0x14,0xC0,0xA4,0xF8,0x23,0x06,0x01,0x30,0x22,0x84,0x34, ++ 0x00,0x27,0xD0,0x64,0x02,0xF9,0xA7,0x82,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xC6, ++ 0xD3,0x74,0x28,0x92,0xC0,0x26,0xC0,0x74,0x83,0x24,0x30,0x82,0x80,0x1C,0x00,0x1F, ++ 0x30,0x82,0x83,0x24,0xC0,0x74,0x80,0x1C,0x00,0x01,0x80,0x2C,0x00,0xD7,0x1A,0x01, ++ 0x03,0xB7,0x32,0x02,0x06,0xC2,0x3E,0x00,0x8A,0x86,0x42,0x32,0x80,0x3C,0x00,0x01, ++ 0xD0,0xA4,0xF0,0x5C,0xF8,0x93,0x90,0x54,0x33,0xD2,0x18,0x12,0x05,0xB8,0xCA,0xD0, ++ 0x90,0x4C,0x00,0x6F,0xF6,0x34,0x00,0x32,0x38,0x90,0x8F,0x3E,0xF2,0x4C,0x00,0x38, ++ 0xD8,0xB2,0xFF,0x3C,0x10,0xF2,0x95,0x0E,0xB0,0x3C,0x30,0x0A,0xE6,0x00,0x92,0x05, ++ 0xD4,0x54,0x10,0x12,0xC1,0x76,0x77,0xBA,0x02,0x01,0x00,0x78,0xB8,0x44,0x00,0x87, ++ 0x36,0x3A,0x03,0x3A,0x38,0xF8,0x8F,0x56,0x33,0x3A,0x18,0x3A,0xD3,0x5C,0x00,0xF8, ++ 0xC0,0xF8,0xD5,0x44,0xD5,0xFA,0x15,0xBA,0xC1,0x0E,0x30,0xF2,0x32,0x2A,0xE0,0x00, ++ 0x93,0x05,0x2E,0x82,0x9C,0x66,0x17,0xEA,0x88,0xA6,0xC0,0x14,0xC8,0x00,0x84,0x14, ++ 0xC2,0x2C,0xE0,0x00,0x90,0x05,0x86,0x2C,0xC2,0x64,0xA0,0x2A,0x31,0x09,0x30,0x82, ++ 0xD4,0x34,0x00,0x42,0x1C,0x82,0x90,0x05,0x85,0x34,0x00,0x72,0x30,0x02,0x1B,0x32, ++ 0x94,0x85,0x35,0x22,0xD0,0x24,0xC0,0x2C,0x10,0x82,0x84,0x1E,0xE6,0xD8,0x92,0xDD, ++ 0x2D,0x9A,0x9B,0x36,0xD0,0x24,0xC0,0x2C,0x15,0x82,0x9C,0x06,0xC0,0x14,0x80,0x3C, ++ 0x10,0x01,0x00,0x01,0x0B,0x01,0x30,0x5A,0x80,0xCB,0x18,0x01,0x0C,0x01,0x30,0x62, ++ 0x30,0x4A,0xE3,0x4A,0x02,0x0F,0xE0,0x48,0x90,0x4D,0x36,0xEA,0x07,0x6A,0x3E,0x68, ++ 0x88,0xCE,0xEF,0x1C,0x10,0x4A,0x9D,0xFE,0x40,0x01,0x88,0x8E,0x08,0xF9,0x07,0x5F, ++ 0xD0,0x64,0xE0,0x9A,0x28,0x9A,0x93,0x1E,0xD0,0xA4,0xF8,0x93,0x10,0x12,0xC4,0x0E, ++ 0xD0,0x64,0xA0,0x8A,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0x8E,0x87,0x7D,0xE8,0x85, ++ 0xF6,0x00,0x92,0x05,0x30,0x4A,0xE3,0x4A,0x2D,0x09,0x30,0x62,0x00,0x6F,0x01,0x00, ++ 0x70,0x30,0x03,0x00,0xF8,0xFF,0x07,0x00,0x33,0x6A,0x18,0x2A,0xFB,0x5C,0x00,0x70, ++ 0xCA,0xB0,0x07,0x38,0xDD,0xAA,0xC7,0x50,0x2C,0x09,0x00,0x6A,0x1D,0xEA,0x90,0x5D, ++ 0x31,0x72,0xA3,0x8A,0xED,0x3C,0x10,0x52,0x98,0x16,0x28,0x11,0x30,0x62,0x05,0xA7, ++ 0xFA,0x74,0xE0,0x28,0x10,0xEA,0x9D,0x6E,0x90,0x3C,0x08,0x01,0x00,0x27,0xF8,0x64, ++ 0xE3,0xAA,0xA3,0xEA,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xC6,0xE0,0x8A,0x29,0x09, ++ 0x30,0x62,0x05,0x17,0x90,0x45,0x2F,0x01,0xA3,0xAA,0x31,0x2A,0x6D,0x01,0x80,0x2E, ++ 0x33,0x6A,0x18,0x2A,0xFB,0x5C,0x00,0x70,0xCA,0xB0,0x07,0x38,0xDA,0xAA,0xDF,0x90, ++ 0x2C,0x09,0x00,0x6A,0x1B,0x5A,0x35,0x6A,0xE2,0x4A,0xE1,0x48,0xA4,0x4A,0x39,0xAF, ++ 0xAC,0xC5,0x37,0x22,0xFC,0x73,0x5E,0xAA,0x36,0x02,0xC3,0x00,0x31,0x32,0x34,0xAA, ++ 0x38,0x21,0x31,0x62,0x1A,0xEA,0xA3,0x01,0x13,0x01,0x20,0x2A,0xC0,0x68,0x07,0xF7, ++ 0xC0,0x1B,0x58,0x79,0x86,0xD6,0xC8,0x1B,0x30,0xD8,0xA0,0x3E,0x18,0xF9,0x8F,0x1B, ++ 0x8E,0x1B,0xC2,0x1B,0xE5,0x3B,0x15,0xDA,0xC6,0x06,0x88,0x13,0xCA,0x1B,0x36,0xD8, ++ 0x76,0xD8,0x8A,0x1B,0x58,0x01,0x80,0x0E,0xF6,0xD8,0x8A,0x1B,0xC8,0x1B,0x5E,0x01, ++ 0x8A,0x26,0xC0,0x1B,0x44,0xD8,0x04,0xD8,0x84,0x1B,0x82,0x13,0x84,0x21,0x11,0x2A, ++ 0xC0,0xF6,0x06,0x01,0x84,0x04,0xB8,0x53,0x30,0x82,0x03,0x8F,0xC5,0x13,0x10,0x92, ++ 0x96,0x5E,0xC0,0x13,0xE2,0x3B,0x35,0x98,0x75,0xD8,0x12,0xDA,0xCC,0x2E,0xC0,0x13, ++ 0x50,0x01,0x81,0x16,0x00,0x09,0x80,0x04,0x00,0x27,0x10,0x01,0x81,0x13,0x84,0x21, ++ 0x17,0x2A,0xC4,0x5E,0xC0,0x04,0x40,0x01,0x83,0x76,0x31,0x92,0x36,0x5A,0x98,0x01, ++ 0x00,0x47,0x01,0x01,0x80,0x83,0xC4,0x83,0x11,0x82,0x95,0x16,0xC2,0x83,0x36,0x38, ++ 0xE3,0x03,0x75,0xF8,0x10,0x3A,0xCC,0xE6,0x04,0x09,0x80,0x83,0xFA,0x43,0xE4,0x00, ++ 0xB8,0x43,0x3C,0x71,0xF8,0xBA,0x7E,0x01,0xD0,0x16,0x00,0x01,0x08,0x84,0x06,0x27, ++ 0x54,0xC4,0x10,0x3A,0xE8,0x0E,0x50,0xC4,0x08,0x84,0x3E,0x81,0xF8,0xBA,0x7E,0x01, ++ 0xD0,0x16,0x00,0x01,0x10,0x84,0x00,0x27,0x54,0xC4,0x12,0x3A,0xEA,0x0E,0x50,0xC4, ++ 0x11,0x84,0x90,0x21,0x16,0xAA,0xC4,0xA6,0xF8,0x43,0x40,0x01,0x88,0x36,0x58,0x44, ++ 0x16,0xE9,0x03,0x90,0x10,0x82,0x94,0x0E,0xE0,0x00,0x1A,0x44,0xF8,0x43,0x44,0x01, ++ 0x80,0xCE,0x10,0x01,0x03,0x01,0x28,0x99,0x0E,0x68,0xFB,0x63,0x01,0x6F,0x18,0x21, ++ 0x1B,0x1A,0x22,0x1A,0xC8,0xD8,0xD2,0xF3,0x70,0x09,0x88,0x26,0xC8,0xDB,0x5E,0x19, ++ 0x8A,0x0E,0xE0,0x90,0x92,0x95,0xE6,0x00,0x94,0x05,0x16,0x22,0xC0,0x7E,0x57,0x01, ++ 0x88,0x0E,0x00,0x01,0x1F,0x44,0xE8,0xC5,0xAC,0x85,0x87,0x3D,0x30,0x2A,0x30,0x62, ++ 0x41,0x12,0xC2,0x40,0x08,0x29,0xEE,0x4A,0x4B,0x29,0x80,0xDE,0x4B,0x02,0xC2,0x70, ++ 0xEB,0x48,0xC4,0x48,0x89,0x1C,0x48,0xF2,0x8B,0x61,0xC0,0x48,0x88,0x14,0x08,0x01, ++ 0x10,0xF9,0x1F,0x79,0x03,0x3F,0xA0,0x92,0xC8,0x3B,0x7E,0x01,0x88,0x06,0x80,0x1B, ++ 0xE6,0x48,0x92,0x4D,0x87,0x21,0xF9,0x3B,0x17,0x7A,0xC4,0xA6,0x00,0x01,0x80,0x34, ++ 0xF8,0x03,0x41,0x01,0x80,0xCE,0xB2,0x04,0x31,0x0A,0x31,0x42,0x58,0x2D,0xD0,0x14, ++ 0xBA,0xFF,0xDF,0x97,0x80,0x34,0xC0,0x34,0x40,0x01,0x88,0x76,0x30,0x01,0x00,0x47, ++ 0x31,0x5A,0x31,0x92,0x08,0xF9,0x07,0x09,0xA7,0x04,0xB8,0xFF,0xE3,0x47,0xE7,0xB0, ++ 0x91,0xB5,0xFF,0x03,0x17,0x82,0xC5,0x9E,0x00,0xFF,0xC1,0x34,0x40,0x09,0x88,0x96, ++ 0xC1,0xB3,0x31,0x1A,0x30,0x52,0x09,0x01,0x37,0x82,0xB9,0xFF,0xE8,0x2F,0x46,0x01, ++ 0x80,0x0E,0x00,0x01,0x00,0x07,0x00,0x09,0x30,0x5A,0x11,0x01,0x30,0x8A,0xA1,0x04, ++ 0xBE,0xFF,0xE7,0x6F,0x00,0x4F,0xA1,0x04,0xFB,0x3B,0x31,0x5A,0xE9,0xD3,0x30,0xDA, ++ 0xC8,0x1C,0xC0,0x14,0xB8,0xFF,0xF7,0x47,0x38,0x01,0x00,0xDF,0xC6,0x1C,0xE8,0x02, ++ 0x40,0xF9,0x87,0x16,0xE0,0x82,0x81,0x24,0x07,0x0F,0x00,0xF9,0x81,0x24,0x30,0x1A, ++ 0x31,0x52,0x31,0xCA,0xC7,0x24,0xB8,0xFF,0xE8,0xFF,0x44,0x01,0x80,0x0E,0x00,0x01, ++ 0x00,0x07,0x00,0x09,0x31,0x5A,0x31,0xD2,0xA0,0x04,0xC8,0x24,0xBD,0xFF,0xE7,0x3F, ++ 0xE7,0xF8,0x93,0xFD,0xFD,0x03,0x11,0xC2,0xC1,0x06,0x37,0x0A,0x30,0x42,0xD1,0x34, ++ 0xBE,0xFF,0xF7,0xB7,0x20,0xCF,0x04,0x01,0x38,0x82,0x03,0x00,0x70,0x30,0x03,0x00, ++ 0x48,0xE0,0x06,0x00,0xAE,0xFD,0x87,0x5D,0xC6,0xAC,0xDA,0x03,0x82,0xCC,0xC1,0xAC, ++ 0xD9,0x03,0x84,0xC4,0x01,0x09,0x58,0x45,0x81,0xC3,0xC0,0xC4,0xE2,0x00,0x82,0xC3, ++ 0xC4,0xC4,0x81,0xC3,0xC2,0xC4,0xF1,0x00,0x82,0xC3,0xC6,0xAC,0x82,0x01,0x87,0x54, ++ 0xC0,0x0B,0x00,0x21,0x1A,0x0A,0xC0,0x54,0x82,0x0B,0xC0,0xAC,0xCA,0x03,0x42,0x00, ++ 0x80,0xD4,0x09,0x01,0x40,0xB5,0x31,0x52,0x00,0x36,0x00,0x01,0x82,0xF4,0xC0,0xAC, ++ 0xCC,0xB4,0x82,0x01,0x82,0x4C,0xC2,0x74,0x92,0x05,0x82,0x44,0xC2,0x6C,0x92,0x05, ++ 0x82,0x3C,0xC2,0xAC,0x82,0x01,0x86,0x34,0x4B,0x11,0x80,0xBE,0x10,0x01,0x00,0x01, ++ 0x4C,0x45,0xB1,0x4A,0x8F,0x2C,0x4A,0xF2,0xB2,0x4A,0x8C,0x24,0x48,0xE2,0xEF,0x48, ++ 0xB2,0x4A,0x8C,0x1C,0x04,0x08,0xC4,0x48,0x91,0x4D,0x66,0x9D,0xDB,0x74,0xA2,0x1A, ++ 0x62,0x85,0xD9,0x6C,0xA2,0x1A,0xDB,0x24,0x9A,0x34,0xD9,0x1C,0x9A,0x2C,0xD9,0x2C, ++ 0x98,0x24,0x41,0x09,0x89,0x5E,0xD8,0x34,0x12,0xDA,0x92,0xDD,0x99,0x34,0xD9,0x2C, ++ 0x12,0xDA,0x92,0xDD,0x99,0x2C,0xD9,0x24,0x12,0xDA,0x92,0xDD,0x9A,0x24,0xD9,0x5C, ++ 0x32,0xE2,0xDC,0x64,0x9A,0x5C,0xD9,0x3C,0xE1,0x44,0xEA,0x2C,0xCA,0xD8,0x92,0xDD, ++ 0xEB,0x34,0xC9,0x20,0x91,0x25,0xF3,0x24,0xED,0x5C,0xC9,0x68,0xA8,0x5C,0x59,0x01, ++ 0xD9,0x86,0xEB,0xCC,0x13,0x5A,0xD5,0x6E,0x63,0x01,0xD8,0x5E,0xED,0xC4,0x11,0x62, ++ 0xD1,0x46,0xEB,0x5C,0xC5,0x6B,0x49,0x68,0x8B,0x06,0x32,0x2A,0x3F,0x01,0xF8,0x7A, ++ 0xEB,0x24,0x01,0x68,0x23,0x62,0x35,0x32,0x2B,0x01,0xF8,0xAA,0xF5,0xD4,0x11,0xAA, ++ 0xEA,0xC6,0xF2,0xB4,0x71,0x09,0x88,0x16,0xD9,0xF0,0x93,0xB5,0xB2,0x9C,0xF8,0x5C, ++ 0x35,0x01,0xF8,0xF2,0x10,0x72,0xDD,0x06,0x37,0xAA,0x81,0x68,0x01,0x68,0x33,0x7A, ++ 0xF3,0x9C,0x10,0x6A,0x12,0xAA,0xE5,0x2E,0x6B,0x9D,0xA1,0x62,0x6B,0x85,0xA1,0x5A, ++ 0x01,0xA8,0x72,0xB5,0xC9,0x68,0xE5,0x72,0xE1,0xB0,0xA3,0x72,0xEB,0xF4,0xE0,0x68, ++ 0x90,0x6D,0xAF,0xF4,0xF5,0x9C,0x10,0xBA,0xD1,0xBE,0x05,0x9F,0x09,0xEF,0x6A,0x9D, ++ 0xA1,0x62,0x6B,0x85,0xA2,0x5A,0x03,0xA8,0x75,0xB5,0xC9,0x68,0xE3,0x72,0xE1,0xB0, ++ 0xA0,0x72,0xE9,0xF4,0xE7,0x68,0x93,0x6D,0xAD,0xF4,0x38,0x37,0xE9,0x5C,0xC1,0x6B, ++ 0x48,0x68,0x6D,0x19,0x8A,0x6E,0x00,0xB0,0x7F,0xB5,0xC9,0xB0,0xE0,0xB2,0x71,0x09, ++ 0xC2,0x3E,0xC0,0x64,0x08,0x01,0xC6,0x03,0x1A,0x42,0xC8,0x64,0x82,0x43,0x80,0x7D, ++ 0xE8,0x85,0x6F,0x11,0x89,0x56,0x68,0x9D,0xA1,0x62,0x63,0x85,0xA2,0x1A,0x03,0x98, ++ 0x4A,0xB5,0xC1,0xC8,0xE2,0x5A,0xE0,0xD8,0xA0,0x5A,0x00,0x1F,0xCE,0x34,0xCA,0x4B, ++ 0x4F,0x51,0x90,0x66,0xE6,0x00,0x92,0x05,0x40,0x11,0x90,0x06,0x3A,0xD7,0xE2,0x90, ++ 0x90,0x95,0x56,0x21,0x92,0x06,0x38,0x57,0x01,0x01,0x80,0x64,0xC0,0xB4,0x42,0x09, ++ 0x88,0xF6,0x03,0x01,0x80,0x7C,0x01,0x01,0x81,0x74,0xC9,0x7C,0x42,0xB5,0x01,0x48, ++ 0xC2,0x40,0x80,0x14,0xC1,0x74,0xC9,0x7C,0x02,0x00,0xC4,0x00,0x91,0x05,0x86,0x4C, ++ 0xCA,0x74,0xC1,0x14,0xE0,0x2A,0x6A,0x09,0xC1,0x26,0xC0,0x64,0xE6,0x00,0x92,0x05, ++ 0x87,0x64,0x01,0x8F,0xC0,0x74,0x41,0x09,0x89,0x16,0xC0,0x7C,0x47,0x01,0x88,0xC6, ++ 0x08,0x81,0x41,0x45,0x83,0x17,0xC0,0x77,0xC0,0x6C,0x82,0x3C,0xC0,0x74,0x82,0x34, ++ 0xC0,0x5C,0x82,0x0C,0xC0,0x64,0x82,0x04,0xC4,0x7C,0xE1,0x00,0x3C,0x00,0x7C,0x00, ++ 0x50,0x5A,0xB4,0xA2,0xE8,0x98,0xB0,0xCA,0x31,0x62,0x74,0x45,0xB1,0x8A,0xC1,0x7C, ++ 0xB0,0x82,0x80,0x24,0xC0,0x7C,0xB1,0xC2,0x81,0x1C,0xD0,0x7C,0xB0,0x82,0x85,0x14, ++ 0xC0,0x74,0x41,0x09,0x88,0x5E,0xC0,0x24,0x12,0x02,0x92,0x05,0x80,0x24,0xC0,0x1C, ++ 0x12,0x02,0x92,0x05,0x80,0x1C,0xC0,0x14,0x12,0x02,0x92,0x05,0x80,0x14,0x00,0x01, ++ 0x83,0x2C,0xE0,0x68,0xAD,0xF4,0x01,0x9F,0x40,0x61,0x98,0x66,0xC8,0x24,0xC0,0x34, ++ 0xD2,0x4C,0xD1,0x00,0x4C,0x9D,0xA1,0x42,0xC8,0x1C,0xC0,0x3C,0xD2,0x4C,0xD1,0x00, ++ 0x4C,0x85,0xA1,0x42,0x00,0x47,0x15,0x01,0xDC,0x0C,0x00,0x28,0xF0,0xD2,0x5C,0x45, ++ 0x88,0xD2,0x12,0x01,0x90,0x6C,0xD1,0x3C,0x92,0x95,0x92,0x0C,0xD2,0x34,0x90,0x95, ++ 0x91,0x04,0xD2,0x6C,0x50,0x09,0x88,0x3E,0x12,0x12,0x93,0xA5,0x32,0x12,0x13,0x92, ++ 0x94,0x95,0x32,0xA2,0x12,0x4A,0x92,0x4D,0xD2,0x0C,0xDA,0x04,0xF0,0x0C,0x00,0x07, ++ 0x01,0xEF,0xB4,0x1C,0xF1,0x04,0xB0,0x5C,0x01,0x70,0xB2,0xFC,0x22,0x12,0x93,0x95, ++ 0xCA,0xD8,0x90,0xDD,0xF9,0x1C,0xF1,0xFC,0xC9,0xB0,0xB7,0x1C,0xF3,0x5C,0xC1,0xB0, ++ 0xB0,0x5C,0x51,0x01,0xD9,0xBE,0xF0,0xCC,0x10,0x92,0xD5,0xA6,0x58,0x01,0xD8,0x96, ++ 0xF5,0xC4,0x11,0x9A,0xD1,0x7E,0xF8,0x1C,0x35,0x01,0xF8,0xF2,0xF9,0x5C,0xC1,0xFB, ++ 0x48,0xF8,0x8D,0x46,0xFD,0xD4,0x11,0xF2,0xE8,0x2E,0x78,0x45,0xCD,0xFA,0xCB,0xF0, ++ 0x7B,0x45,0x88,0xF2,0x39,0xD7,0xD6,0x6C,0xE6,0x90,0x92,0x95,0x91,0x6C,0xD1,0x6C, ++ 0x55,0x11,0x98,0xF6,0x41,0x01,0x80,0xF6,0xF2,0x10,0xF2,0x4C,0x00,0x90,0x5C,0x45, ++ 0xC7,0xD2,0xD4,0xB3,0xCC,0xDA,0xCA,0xB0,0x11,0xF2,0x94,0x86,0xD0,0x2C,0x50,0x09, ++ 0x88,0x8E,0xD1,0x24,0xC1,0x34,0xD8,0x4C,0xD1,0x00,0x54,0x9D,0xA0,0x82,0xDE,0x1C, ++ 0xD1,0x3C,0xE8,0x4C,0xD1,0x90,0x5E,0x85,0xA8,0xD2,0xEA,0x14,0xDA,0x04,0xD8,0xE8, ++ 0x36,0x1A,0xD3,0x90,0x90,0x95,0xDA,0x00,0x93,0x1D,0xD2,0x40,0x2C,0x01,0x38,0x01, ++ 0x50,0x01,0xD8,0x56,0xF5,0xCC,0x11,0x92,0xD0,0x3E,0x58,0x01,0xD9,0x2E,0xF0,0xC4, ++ 0x10,0x9A,0xD5,0x16,0xC1,0x33,0x18,0xF2,0x83,0x33,0x20,0x12,0x90,0x95,0xCA,0xD8, ++ 0x92,0xDD,0xC2,0x00,0xE7,0x68,0x93,0x6D,0x6F,0x11,0xC8,0x4E,0x04,0xE7,0x10,0x9A, ++ 0x90,0x0E,0x10,0x09,0x90,0x2C,0xD8,0x24,0xD6,0x34,0xC0,0x90,0x90,0x95,0x96,0x34, ++ 0xD8,0x1C,0xD0,0x3C,0xC6,0x90,0x96,0x95,0x90,0x3C,0xD0,0x14,0xDA,0x0C,0x00,0x90, ++ 0xC0,0x90,0x96,0x0C,0xD8,0x14,0xD0,0x04,0xC0,0x90,0x96,0x04,0xE6,0x00,0x92,0x05, ++ 0xD4,0xF4,0x11,0x82,0x92,0x06,0x38,0x3F,0xC2,0x74,0xE1,0x00,0x91,0x05,0x86,0x74, ++ 0xC0,0x74,0x41,0x11,0x97,0x06,0x30,0xAF,0xC2,0x7C,0xE1,0x00,0x91,0x05,0x86,0x7C, ++ 0xC0,0x7C,0x41,0x21,0x97,0x06,0x30,0x37,0x00,0x0F,0x00,0x41,0x81,0x64,0xC1,0x64, ++ 0x41,0x41,0x88,0xD6,0x10,0x01,0x00,0x01,0x58,0x8A,0xE8,0xC8,0xB4,0xF2,0xB4,0x7A, ++ 0x31,0x8A,0x31,0xDA,0x40,0x09,0x88,0x1E,0x12,0x4A,0x92,0x4D,0x12,0xDA,0x92,0xDD, ++ 0xE7,0x6C,0xC2,0x18,0x92,0xDD,0xE2,0x74,0xC2,0x08,0x93,0x65,0x04,0x08,0xC4,0x48, ++ 0x90,0x4D,0x5E,0x01,0xD9,0x76,0xE8,0xCC,0x10,0x5A,0xD5,0x5E,0x60,0x01,0xD8,0x4E, ++ 0xED,0xC4,0x11,0x62,0xD1,0x36,0x68,0x9D,0xA1,0x62,0x63,0x85,0xA0,0x1A,0x03,0x3F, ++ 0x70,0xD2,0x05,0x00,0x62,0x9D,0xD9,0x74,0xA1,0x1A,0x63,0x85,0xDB,0x6C,0xA2,0x1A, ++ 0xE6,0x00,0x92,0x05,0x46,0x11,0x98,0x9E,0xE6,0x90,0x92,0x95,0x56,0x21,0x98,0x56, ++ 0x58,0x85,0xD9,0xC3,0xA8,0xC3,0xC0,0xC3,0x90,0xC3,0x00,0x01,0x81,0xFC,0x58,0x85, ++ 0xD8,0xC3,0xA8,0xC3,0xC0,0xC3,0x90,0xC3,0x00,0x01,0x80,0xE4,0x30,0x3A,0x80,0xEC, ++ 0xC4,0xAC,0xCA,0x03,0x80,0xD4,0x01,0x01,0x0E,0x01,0x00,0x18,0x54,0xA5,0xC0,0xD0, ++ 0x32,0xA2,0x04,0x20,0xC6,0x10,0x93,0x95,0x6D,0x9D,0xE1,0x72,0x33,0x2A,0xA3,0x72, ++ 0x6D,0x85,0xE1,0x6A,0x32,0x12,0xC3,0x90,0x8A,0xAB,0xE0,0x48,0x90,0x4D,0x4E,0x19, ++ 0x98,0x86,0x47,0x09,0x80,0x0E,0x40,0x19,0x88,0x66,0x60,0xA5,0xE3,0x0A,0x37,0x12, ++ 0xCB,0x93,0x30,0x2A,0xC7,0x6B,0xA5,0x2A,0x34,0x1A,0xCB,0xE3,0x8C,0xE3,0x80,0xCB, ++ 0x34,0x0A,0x8B,0x53,0x09,0x09,0x88,0x0C,0x09,0x01,0x88,0x74,0xD3,0x74,0x31,0x0A, ++ 0xE1,0x4A,0xDC,0x74,0x36,0x12,0xC3,0x90,0xCA,0x9B,0xC0,0xAB,0xC9,0x93,0x92,0x14, ++ 0xD0,0x74,0x51,0x01,0x88,0x16,0x41,0x01,0x80,0x0E,0x40,0x19,0x8D,0x5E,0x10,0x4A, ++ 0x98,0x4E,0x10,0x09,0x90,0x04,0x41,0x01,0x8A,0x16,0xF0,0x10,0x90,0x0C,0x01,0xF7, ++ 0x11,0x09,0x90,0x0C,0x00,0xDF,0x40,0x09,0x80,0x0E,0x40,0x11,0x8D,0x5E,0x10,0x4A, ++ 0xC0,0x4E,0x10,0x09,0x90,0x04,0x41,0x09,0x8C,0x16,0xF0,0x10,0x90,0x0C,0x01,0x77, ++ 0x11,0x09,0x90,0x0C,0x00,0x5F,0x10,0x01,0x90,0x04,0x01,0x47,0x11,0x09,0x90,0x04, ++ 0x40,0x11,0x90,0x16,0xF1,0x90,0x94,0x0C,0x00,0x0F,0x10,0x09,0x90,0x0C,0x41,0x01, ++ 0x80,0x0E,0x40,0x19,0x8D,0x0E,0x10,0x4A,0x90,0x2E,0x40,0x09,0x80,0x0E,0x40,0x11, ++ 0x8D,0x26,0x10,0x4A,0xC0,0x16,0x10,0x09,0x94,0x54,0x01,0x8F,0x11,0x01,0x90,0x54, ++ 0x01,0x77,0xF4,0xC4,0x33,0x12,0x19,0x92,0xF1,0xA4,0x92,0xE4,0xC9,0x90,0xF4,0xEC, ++ 0xC9,0x90,0x94,0x5C,0xD0,0x5C,0xC1,0x93,0x92,0xDC,0x31,0x90,0xA1,0xCE,0xD1,0xE4, ++ 0xF2,0xA4,0x02,0x90,0xC9,0x90,0xF4,0x3C,0x04,0xB0,0xCB,0x90,0x35,0x39,0x09,0xB0, ++ 0xC8,0xB0,0x14,0xE1,0xF1,0x92,0xF5,0xD4,0x10,0x92,0xD5,0x26,0xF0,0x64,0x71,0x41, ++ 0x88,0xB6,0x50,0x01,0xD9,0xA6,0xF0,0xDC,0x48,0xB0,0x87,0x06,0x80,0x90,0xF2,0xE4, ++ 0xC0,0xB0,0xB5,0xE4,0xF2,0x3C,0x19,0xB2,0xC8,0xB8,0xF7,0xEC,0x1C,0x12,0xCB,0x90, ++ 0x90,0xEC,0xD0,0xFC,0xE4,0x90,0x92,0x95,0x91,0xFC,0xD0,0xDC,0x48,0x90,0x8E,0xEE, ++ 0xD0,0x4C,0xF2,0xF4,0xD5,0x93,0x12,0x92,0xC1,0x2E,0xD0,0xDC,0x31,0x01,0x1E,0x92, ++ 0xF1,0x5C,0x81,0x93,0x01,0x47,0xD0,0xDC,0x31,0x01,0x1A,0x92,0xF1,0x5C,0x81,0x93, ++ 0x01,0x17,0xD0,0x04,0x50,0x09,0x80,0x4E,0xD0,0x04,0x51,0x09,0x8A,0x36,0xD0,0x6C, ++ 0x10,0xA2,0x84,0x1E,0xD5,0x0C,0xC1,0x10,0x95,0xA5,0x3A,0x57,0x10,0x4A,0x8D,0xDE, ++ 0xD4,0x14,0x11,0x9A,0x89,0xC6,0xC8,0x74,0xE6,0x48,0x92,0x4D,0x89,0x74,0xC9,0x74, ++ 0x48,0x11,0x90,0x06,0x3A,0x97,0xE2,0x00,0x90,0x05,0x46,0x21,0x91,0x06,0x38,0x1F, ++ 0xC6,0x34,0xCA,0x03,0x42,0x01,0x88,0x5E,0xC9,0xAC,0x8A,0x01,0xE0,0x43,0x36,0x10, ++ 0xAA,0x36,0x31,0x00,0x71,0x00,0x04,0x27,0xD0,0x54,0x51,0x01,0x8D,0x5E,0x10,0x4A, ++ 0xCA,0x16,0xF0,0x48,0x90,0x4D,0x06,0x1F,0x10,0x4A,0x95,0x0E,0xE6,0x48,0x92,0x4D, ++ 0x11,0x09,0x90,0x54,0x01,0x67,0xD0,0x14,0x10,0x9A,0xCC,0x16,0xF6,0xD8,0x92,0xDD, ++ 0x01,0x27,0xD0,0x14,0x10,0x9A,0x94,0x0E,0xE6,0xD8,0x92,0xDD,0x11,0x01,0x90,0x54, ++ 0x91,0x55,0x92,0x3C,0x97,0xE5,0x72,0xFA,0xD4,0x3C,0xC9,0x90,0x93,0xEC,0x39,0x47, ++ 0x02,0x01,0xD0,0xAC,0x6C,0x94,0x16,0x12,0x9A,0xD6,0xC0,0xAC,0xE8,0x4B,0x70,0x04, ++ 0x10,0x42,0x9C,0x26,0xC4,0x4C,0xD2,0x03,0xF6,0x00,0x94,0x05,0x02,0x1F,0xC0,0x4C, ++ 0xD4,0x03,0xE4,0x00,0x90,0x05,0xCE,0xFC,0x10,0x0A,0x9C,0x4E,0xC0,0xAC,0x0A,0x01, ++ 0xBA,0x0B,0xC0,0x54,0x08,0xD9,0xC7,0x03,0x02,0x42,0xC8,0x54,0x82,0x43,0x28,0x37, ++ 0x27,0x01,0x28,0xF9,0xA8,0x09,0x60,0x01,0x8A,0x56,0xC0,0x44,0xC8,0xC4,0xB9,0x9C, ++ 0xD2,0x34,0x4A,0x93,0x92,0x94,0xD0,0x74,0x5A,0x3A,0x07,0x90,0xF0,0xF2,0x04,0x57, ++ 0xC1,0x3C,0xCA,0xCC,0xD0,0xEC,0x90,0x9C,0xD4,0x34,0x4A,0x93,0x92,0x94,0xD0,0x6C, ++ 0x5A,0x12,0x07,0x90,0xF0,0xF2,0x44,0x01,0x82,0x16,0xF0,0x48,0x10,0x42,0x8C,0x8E, ++ 0xD0,0x74,0x92,0x04,0x91,0x05,0x36,0x0A,0xDA,0x6C,0xD2,0x5C,0xBC,0xEF,0xD7,0x37, ++ 0x35,0x4A,0x11,0x42,0xE8,0x0E,0x30,0x42,0x00,0x17,0x40,0x01,0xD0,0x06,0x00,0x01, ++ 0xC8,0x30,0x04,0x07,0xB0,0x01,0xC4,0x9C,0xC8,0xE4,0x10,0x00,0x86,0x0F,0xE8,0x27, ++ 0xCC,0x94,0xC8,0x00,0x18,0x42,0x42,0x01,0xD0,0x06,0x00,0x01,0xA0,0x00,0x60,0x01, ++ 0x8A,0x7E,0xC8,0x34,0x54,0x4C,0x10,0x0A,0xD0,0x06,0x30,0x42,0xC8,0xAC,0x12,0x31, ++ 0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90,0xC2,0x48,0x04,0x44, ++ 0x02,0x77,0xC8,0x34,0x54,0x4C,0x12,0x0A,0xD0,0x06,0x30,0x42,0xC8,0xAC,0x12,0x31, ++ 0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90,0xC4,0x48,0x04,0x44, ++ 0xE7,0x20,0x93,0x25,0x64,0x09,0xC8,0xF6,0xC0,0xAC,0x12,0x31,0xE0,0x0B,0xC2,0xE4, ++ 0x02,0x42,0xCE,0xAC,0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90, ++ 0xC6,0x48,0x04,0x44,0xC2,0xAC,0xCA,0x74,0xFA,0x03,0x00,0x10,0xC0,0xA4,0xC2,0x90, ++ 0x02,0x89,0x0B,0x00,0xC4,0x90,0xA8,0x8B,0xCA,0xAC,0xD2,0x6C,0xFA,0x4B,0x00,0x58, ++ 0xCA,0xA4,0xC2,0xC8,0xC6,0x40,0xA8,0x13,0xC2,0xAC,0xCA,0xAC,0xFA,0x03,0xE0,0x00, ++ 0xBD,0x43,0x20,0xE7,0xAC,0xFD,0x87,0xBD,0xEC,0x04,0x31,0xA2,0xD8,0x43,0x87,0x84, ++ 0xD8,0x43,0x85,0x7C,0xC8,0x43,0x81,0x74,0x00,0x01,0x80,0x54,0x42,0x22,0x45,0x0B, ++ 0x36,0x42,0x81,0x01,0x80,0xB4,0x48,0x01,0x80,0x1E,0xC0,0x74,0x40,0x00,0x82,0x5C, ++ 0x00,0x67,0xC0,0xB4,0xC8,0x03,0x46,0x51,0x98,0x26,0xC8,0xB4,0x00,0x49,0xB0,0x42, ++ 0x80,0x5C,0x00,0x1F,0xC0,0xB4,0x08,0x41,0xB0,0x0A,0x8A,0x5C,0x40,0xCA,0xD4,0xD4, ++ 0xC8,0xBC,0xC0,0x80,0x80,0xAC,0x48,0x01,0x84,0xF6,0x49,0xBA,0xC2,0xD4,0xC0,0x08, ++ 0x10,0x49,0xC5,0xD4,0x04,0x90,0xC4,0x18,0xE0,0xAC,0xC0,0x74,0x42,0x00,0x12,0x02, ++ 0x90,0x05,0x82,0x54,0x30,0x01,0x00,0x7F,0x00,0x01,0x00,0x47,0x40,0x7C,0x40,0xD4, ++ 0xD1,0xD0,0x05,0x14,0xE4,0x20,0xE5,0x48,0xE2,0xD8,0xE4,0x00,0x90,0x05,0xD6,0x7C, ++ 0x17,0x82,0x9C,0x9E,0xE7,0xB0,0x93,0xB5,0xC4,0x84,0x10,0x32,0x9B,0x66,0x37,0x02, ++ 0x40,0x01,0x80,0x06,0x3C,0x02,0x4C,0x2A,0xC2,0xD4,0xC0,0x18,0x48,0x1A,0xC4,0xD4, ++ 0x8A,0xC1,0xC1,0x00,0x50,0x0A,0xCC,0xD4,0x94,0x81,0xC3,0x48,0x10,0x01,0x00,0x47, ++ 0x40,0x24,0x40,0x74,0xD8,0x20,0x05,0xE4,0xE4,0xD8,0xE4,0x00,0xE2,0x48,0xE4,0x90, ++ 0x90,0x95,0xE6,0x7C,0x17,0x12,0x9D,0x9E,0x48,0x92,0xC3,0xD4,0xC0,0x00,0x82,0x4C, ++ 0xE0,0xAC,0x00,0x01,0x81,0x8C,0x30,0x42,0x80,0x01,0x81,0xA4,0x80,0x01,0x86,0x9C, ++ 0x08,0x97,0x32,0x01,0x08,0x47,0xC2,0x4C,0xC4,0x03,0x48,0x00,0x89,0xF6,0xF3,0x02, ++ 0xCC,0x74,0x10,0x42,0xD8,0xD6,0xC3,0x7C,0x32,0x5A,0x03,0x00,0xD0,0x08,0x31,0x52, ++ 0xD6,0x01,0x59,0x94,0x10,0xD4,0x40,0x54,0x12,0xD4,0x42,0x4C,0x11,0xCC,0x34,0x0A, ++ 0xCE,0x01,0x59,0x4C,0x11,0xCC,0x46,0x0C,0x1B,0xCC,0x40,0x0C,0x18,0xCC,0xCA,0x08, ++ 0x31,0x52,0xD0,0x01,0x5C,0x94,0x1E,0xD4,0xD6,0x02,0x19,0xC4,0x40,0x44,0x22,0xC4, ++ 0x40,0x25,0x70,0x01,0x88,0x26,0x08,0x01,0x16,0xCC,0x10,0xCC,0x18,0xCC,0x04,0x47, ++ 0xCA,0x7C,0xF0,0x48,0x10,0x72,0x8C,0x26,0x0B,0x01,0x30,0x5A,0x12,0xCC,0x1C,0xCC, ++ 0x20,0xCC,0xC8,0x8C,0x48,0x01,0x88,0x26,0x30,0x5A,0x13,0xCC,0x14,0xCC,0x12,0xCC, ++ 0x00,0x4F,0xC8,0x84,0xD2,0x8C,0xF0,0x48,0x10,0x52,0x8C,0x26,0x0B,0x01,0x30,0x5A, ++ 0x1E,0xCC,0x1C,0xCC,0x20,0xCC,0x10,0x01,0xF3,0x12,0x35,0x5A,0x0A,0x81,0xF0,0xCA, ++ 0x11,0x8A,0xD4,0x9E,0x0A,0x91,0xF0,0xCA,0x17,0x8A,0xD4,0xD6,0x0A,0xA1,0xF0,0xCA, ++ 0x17,0x8A,0xD4,0xB6,0x0A,0xB1,0xF0,0xCA,0x17,0x8A,0xD4,0x96,0x0A,0xD1,0xF0,0xCA, ++ 0x11,0x8A,0xE4,0x1E,0x0A,0xE1,0xF0,0xCA,0x17,0x8A,0xE4,0xD6,0x0A,0xF1,0xF0,0xCA, ++ 0x17,0x8A,0xE4,0xB6,0x0A,0x01,0xF1,0xCA,0x17,0x8A,0xE4,0x96,0x0A,0xD1,0xEC,0x4A, ++ 0x4B,0x01,0x80,0xCE,0x08,0x01,0x88,0x6C,0x30,0x72,0x8C,0x1C,0x88,0x64,0xD8,0xBC, ++ 0x5A,0x01,0x88,0x1E,0x32,0xE2,0xFC,0x78,0x1E,0x01,0xF0,0x1A,0x10,0xDA,0xD5,0x46, ++ 0xC0,0xC8,0x92,0x4D,0xDA,0x1C,0xE0,0xD8,0x90,0xDD,0x06,0x07,0x00,0xF7,0x9D,0x1C, ++ 0x00,0x2F,0x58,0x51,0xEB,0x1E,0x30,0x9A,0xE6,0xD8,0x92,0xDD,0x34,0xF2,0xE4,0x00, ++ 0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x36,0xE2,0x30,0x1A,0x5B,0x49,0x9A,0x26,0xC7,0x80, ++ 0x90,0x05,0xD0,0xA4,0x70,0x4C,0xE9,0x93,0x10,0x8A,0x9C,0xB6,0xCC,0x5C,0x10,0x42, ++ 0xD3,0x9E,0x30,0x8A,0x48,0x39,0x98,0x36,0xCA,0x5C,0x80,0x48,0x10,0x0A,0xDC,0x66, ++ 0xC0,0x1C,0x40,0x01,0x88,0x4E,0xC0,0xB4,0xC8,0x03,0x46,0x11,0x98,0x0E,0x00,0x09, ++ 0x80,0x6C,0x48,0xDA,0xC2,0x43,0xE2,0x00,0x80,0x43,0x4A,0xCA,0xC0,0x43,0x40,0x81, ++ 0x90,0x26,0x52,0xC2,0xA2,0xB2,0xE0,0x00,0x81,0x43,0x00,0xFF,0x34,0xB2,0x84,0x98, ++ 0xC0,0x98,0x96,0xDD,0x98,0x14,0x18,0x01,0x30,0xE2,0xDC,0x54,0x80,0xD8,0x9A,0x94, ++ 0x1E,0x01,0xF0,0x1A,0xFD,0x94,0x10,0xDA,0xD3,0x56,0x30,0xBA,0xC9,0xF8,0x96,0xFD, ++ 0x30,0xF2,0xFD,0x54,0x10,0xDA,0xD5,0x1E,0x86,0xB8,0xCA,0xB8,0x90,0xFD,0xB9,0x14, ++ 0xC0,0xC8,0x02,0x97,0x60,0x20,0x02,0x00,0x70,0xB2,0x04,0x00,0x70,0xB2,0x02,0x00, ++ 0x80,0x40,0x07,0x01,0x48,0xE0,0x06,0x00,0x28,0x60,0x00,0x00,0x68,0x70,0x04,0x00, ++ 0x00,0xC0,0x00,0x01,0x80,0xC0,0x06,0x01,0x00,0xF7,0x90,0x4D,0xE3,0x00,0x34,0x1A, ++ 0xE6,0xD8,0x92,0xDD,0x33,0xE2,0x34,0x1A,0x5E,0x49,0x98,0x8E,0xC4,0x14,0x10,0x0A, ++ 0xD8,0x16,0xC8,0x5C,0x28,0x72,0xD4,0x0E,0x00,0x09,0x80,0x6C,0xC6,0xB4,0xC8,0x03, ++ 0x40,0x51,0x98,0x16,0xC0,0xBC,0x40,0x01,0x80,0x46,0xC8,0x6C,0x00,0x09,0x48,0x01, ++ 0x80,0x06,0x00,0x01,0x80,0x64,0x00,0x0F,0x00,0x09,0x80,0x64,0xC0,0x64,0x40,0x01, ++ 0x80,0xA6,0x01,0x09,0xBC,0x43,0x43,0x3A,0x40,0x03,0x42,0x01,0x88,0x5E,0xC0,0xB4, ++ 0xC8,0x03,0x46,0x51,0x90,0x3E,0xC0,0xA4,0x6E,0x4C,0xE7,0x03,0x32,0x00,0x72,0x00, ++ 0x84,0x51,0x10,0x0A,0xC8,0x0E,0x10,0x01,0x00,0x07,0x10,0x09,0xC0,0xC4,0x40,0x01, ++ 0x80,0x06,0x10,0x11,0xC0,0xD4,0x90,0x14,0x81,0x04,0x30,0x9A,0xA9,0x0C,0x30,0x02, ++ 0xD0,0x8C,0xC8,0x4C,0xBA,0xFF,0xD7,0x37,0xC0,0x9C,0xC0,0x03,0x38,0x00,0xAA,0x1E, ++ 0xFF,0x43,0xF9,0x4B,0x10,0x42,0x9C,0x4E,0xC0,0x9C,0xC0,0x03,0x38,0x00,0xA2,0x1E, ++ 0x05,0x01,0xA8,0x43,0xCC,0x9C,0x80,0x43,0x87,0xDD,0xE8,0x85,0xE0,0x20,0xC5,0x4C, ++ 0xE0,0x00,0x82,0x4C,0xE7,0xB0,0x93,0xB5,0xC4,0x7C,0x10,0x32,0x95,0x06,0x30,0x97, ++ 0xC2,0x8C,0xE0,0x00,0x90,0x05,0x86,0x8C,0xC8,0x84,0xC0,0x8C,0x10,0x42,0x94,0x06, ++ 0x37,0x3F,0x3D,0x4F,0xAC,0x9D,0x87,0x0D,0xD8,0x43,0x80,0x04,0xDB,0x63,0x52,0x12, ++ 0xC4,0x0C,0xC0,0x28,0x50,0x02,0xC3,0x0C,0xD4,0xC1,0xC1,0x30,0xE8,0x43,0x0C,0xF1, ++ 0x84,0x0F,0xD8,0x97,0x49,0xE9,0x88,0x0E,0x48,0xE2,0xC2,0x0C,0xC5,0x10,0x0A,0x49, ++ 0xC4,0x0C,0x00,0x48,0xC0,0x08,0x1A,0x01,0x00,0x5F,0x00,0x01,0x00,0x2F,0x40,0x7C, ++ 0x04,0xBC,0xE0,0x90,0xE2,0x48,0xE4,0x00,0x95,0x05,0x16,0x02,0x9A,0xBE,0xE7,0xD8, ++ 0x90,0xDD,0xC6,0x04,0x17,0x1A,0x9C,0x86,0x00,0x01,0x00,0x2F,0x41,0x8C,0x01,0x4C, ++ 0xE5,0x68,0xE5,0xB0,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0xBE,0x48,0x62,0xC2,0x0C, ++ 0xC0,0x00,0x12,0x01,0x00,0x67,0x08,0x01,0x00,0x37,0xC0,0x1B,0x34,0xD8,0x74,0xD8, ++ 0x82,0x1B,0xE0,0x00,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xB6,0xE6,0x90,0x92,0x95, ++ 0xCC,0x04,0x10,0x52,0x9F,0x7E,0xEF,0xF5,0xAC,0xFD,0x87,0x1D,0x30,0x6A,0x30,0x01, ++ 0xBB,0x73,0xB9,0x73,0x37,0x42,0x81,0x01,0xC7,0x0B,0x10,0xE9,0x02,0x52,0x38,0x48, ++ 0x7A,0x48,0x06,0x48,0x18,0x52,0x80,0x13,0xC7,0x0B,0x10,0xD9,0x00,0x8A,0x80,0x0B, ++ 0x34,0x42,0x81,0x01,0x84,0x14,0xF0,0x03,0x78,0xB2,0x41,0x01,0x80,0x4E,0x00,0x01, ++ 0x57,0xAA,0x09,0xF9,0xA2,0x8A,0xE0,0x00,0x90,0x05,0x46,0x81,0x99,0xD6,0x87,0xF3, ++ 0x80,0xF3,0xAB,0x04,0x00,0x01,0xD8,0x1C,0xD0,0x34,0xC8,0x2C,0xBD,0xFF,0xEF,0xD7, ++ 0x36,0x62,0xA1,0x01,0xC8,0x03,0x47,0x51,0x98,0x36,0xA8,0x04,0x00,0x09,0xD8,0x1C, ++ 0xD0,0x34,0xC8,0x2C,0xBD,0xFF,0xEF,0x77,0xC4,0x14,0xF0,0x0B,0x49,0x01,0x80,0xD6, ++ 0x00,0x01,0x48,0x09,0x8B,0x5E,0xC0,0xD3,0x50,0x01,0x80,0x46,0x50,0x1A,0xC1,0x93, ++ 0x50,0x01,0x88,0x26,0x50,0x12,0xC1,0x93,0x50,0x01,0x88,0x06,0x00,0x09,0x40,0x01, ++ 0x87,0x2E,0xC8,0x13,0x50,0x01,0x95,0x36,0xE7,0x90,0x8A,0x13,0x07,0x1F,0xC8,0x13, ++ 0x50,0x51,0x90,0x06,0x8F,0x33,0xCF,0x13,0x50,0x51,0x98,0xE6,0x40,0x01,0x88,0x6E, ++ 0x48,0x09,0x88,0x16,0xF7,0x90,0x8A,0x13,0x01,0x47,0x00,0x99,0xEF,0x02,0x6A,0x4C, ++ 0x34,0x00,0x72,0x00,0x10,0x0A,0x94,0x0E,0xF7,0x90,0x8A,0x13,0xC0,0xC3,0x43,0x11, ++ 0x9D,0x16,0x00,0x01,0x88,0x03,0x07,0x37,0x40,0x09,0x88,0x26,0xCA,0x03,0x47,0x81, ++ 0x93,0x0E,0x00,0x21,0x89,0x03,0x37,0x4A,0xC7,0x1C,0xB8,0xFF,0xF8,0xDF,0x81,0x3D, ++ 0xE8,0x85,0x07,0x00,0x80,0x40,0x07,0x01,0x68,0xF0,0x07,0x00,0x28,0x60,0x00,0x00, ++ 0x60,0x20,0x02,0x00,0x00,0xC0,0x00,0x01,0x80,0xC0,0x06,0x01,0x00,0x40,0x00,0x01, ++ 0x00,0x48,0x00,0x01,0xAC,0xFD,0x87,0x3D,0xE0,0x84,0x30,0xB2,0x00,0x01,0x80,0x2C, ++ 0xD8,0x83,0x83,0x1C,0x60,0x8C,0x89,0x14,0xCA,0x44,0x18,0x0A,0x50,0xFA,0xC7,0x3C, ++ 0xC0,0x00,0xC4,0x48,0x8F,0x34,0x40,0xF2,0xC0,0x03,0x40,0x09,0x89,0x0E,0xE0,0x83, ++ 0x80,0x1C,0x00,0x01,0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05, ++ 0xDC,0x1C,0x10,0xC2,0x98,0xC6,0x0F,0x01,0x00,0x09,0xD8,0x54,0xD0,0x44,0x80,0x07, ++ 0xD0,0xAF,0x2E,0x01,0x60,0x01,0x88,0x0E,0xE7,0x68,0x93,0x6D,0xF8,0x34,0x08,0x01, ++ 0x01,0x5F,0xC0,0xC3,0x1E,0x02,0x91,0x05,0x80,0xC3,0xD1,0x8C,0x10,0x82,0xCC,0x0E, ++ 0x19,0x02,0x85,0xC3,0xE2,0xF8,0xE3,0x48,0x90,0x4D,0xC6,0x1C,0x17,0x0A,0x9C,0x86, ++ 0x48,0x42,0xC7,0x3C,0xC0,0x00,0x82,0x24,0xD0,0x54,0x90,0x04,0x30,0x9A,0x01,0x11, ++ 0xD0,0x3C,0xC8,0x44,0x80,0x07,0xD8,0x47,0xD0,0x54,0x90,0x04,0x04,0x41,0xEA,0x0A, ++ 0x00,0x01,0x1C,0x0A,0x30,0x9A,0x11,0x01,0xC0,0x24,0x80,0x07,0xF6,0x27,0x05,0x29, ++ 0xE8,0x02,0x44,0x31,0x88,0x16,0x00,0x01,0x87,0x5D,0xE8,0x85,0xC1,0x1C,0xD0,0xC0, ++ 0x09,0x01,0x00,0x3F,0xD0,0x24,0x18,0x01,0xF0,0x9A,0xD6,0x14,0xD0,0xD0,0x94,0x95, ++ 0x68,0x01,0x88,0x2E,0x50,0xC1,0xE8,0xBE,0xC5,0x13,0x18,0x12,0x80,0x13,0x00,0x9F, ++ 0x50,0x99,0xE8,0x2E,0xC0,0x13,0x50,0x01,0x82,0x16,0xF0,0x90,0x80,0x13,0x00,0x5F, ++ 0x68,0x29,0x88,0x4E,0x58,0xE1,0xEE,0x3E,0xC0,0x13,0x50,0x01,0x88,0x26,0xD0,0x2C, ++ 0x50,0x01,0x88,0x0E,0x10,0x09,0x90,0x2C,0xD4,0x24,0xE0,0x90,0x92,0x24,0xE0,0x00, ++ 0xE6,0x48,0x92,0x4D,0xD4,0x1C,0x10,0x8A,0x9B,0xA6,0x46,0x20,0x6C,0x21,0xC8,0xCE, ++ 0xD0,0x54,0x90,0x04,0x30,0x9A,0x09,0x01,0x00,0x19,0xD0,0x3C,0x85,0x07,0xD0,0xE7, ++ 0x08,0x09,0x30,0x42,0xD8,0x54,0xD0,0x44,0x83,0x07,0xD0,0x07,0xC5,0x2C,0x38,0xDF, ++ 0xAC,0xFD,0x87,0x1D,0xF0,0x64,0x30,0x7A,0x33,0xEA,0xD8,0xC3,0x85,0x14,0x48,0xAA, ++ 0xC2,0x1C,0xC0,0x20,0x40,0x92,0xC5,0x03,0x40,0x09,0x88,0x0E,0xE0,0xC3,0x81,0x14, ++ 0x08,0x01,0x00,0x09,0xD8,0x2C,0xD0,0x6C,0x82,0x07,0xD0,0x47,0xD0,0x2C,0x90,0x04, ++ 0x30,0xDA,0x01,0x11,0xD0,0x1C,0xC8,0x6C,0x84,0x07,0xD0,0xB7,0xD0,0x2C,0x90,0x04, ++ 0x06,0x41,0xEA,0x0A,0x00,0x01,0x1C,0x0A,0x30,0xDA,0x11,0x01,0x30,0x02,0x81,0x07, ++ 0xF0,0x97,0xD1,0x2C,0x91,0x04,0x30,0xDA,0x08,0x01,0x00,0x19,0xD0,0x1C,0x80,0x07, ++ 0xD0,0x1F,0x0C,0x09,0x30,0x42,0xD8,0x2C,0xD0,0x6C,0x80,0x07,0xD4,0x3F,0x41,0xF2, ++ 0x00,0x44,0x01,0x01,0x00,0x84,0x09,0x01,0x00,0x77,0x00,0x01,0xF0,0x02,0x11,0x01, ++ 0xF4,0x52,0x15,0x12,0xE9,0x06,0x00,0x44,0x15,0x01,0xF0,0x92,0x10,0x12,0xD4,0x06, ++ 0x05,0x84,0xE1,0x20,0xE6,0x48,0x92,0x4D,0xC4,0x14,0x10,0x0A,0x98,0x6E,0x87,0x3D, ++ 0xEF,0x85,0xAF,0xBD,0x80,0x55,0xC4,0x5C,0xD8,0x03,0x86,0x24,0xCA,0x5C,0xD8,0x4B, ++ 0x8C,0x1C,0x50,0x52,0xCC,0x54,0xC0,0x48,0x8C,0x4C,0x48,0x4A,0xC0,0x4B,0x48,0x09, ++ 0x88,0x46,0xC8,0x24,0xE6,0x48,0x92,0x4D,0x88,0x24,0x80,0x3C,0xC0,0x5C,0xE0,0x03, ++ 0x80,0x1C,0x00,0x0F,0x00,0x01,0x80,0x3C,0xF8,0x3C,0xC0,0x5C,0x80,0x01,0x86,0x44, ++ 0x04,0x7F,0x4B,0x12,0x04,0x01,0x00,0x43,0xC0,0x5C,0xC8,0x4C,0xDB,0x03,0x1A,0xC2, ++ 0xC0,0x08,0x02,0x01,0x10,0xF9,0x01,0x1F,0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05, ++ 0xDC,0x1C,0x10,0xC2,0x9C,0xC6,0x27,0x01,0x31,0x2A,0x31,0x32,0x03,0xE7,0x40,0xC2, ++ 0x08,0x23,0x4E,0x2D,0xB8,0x0C,0x88,0x04,0x40,0x55,0x40,0x3E,0x5F,0x35,0xB8,0xFF, ++ 0xF8,0x7F,0xC3,0x44,0xC8,0x03,0x42,0x31,0x83,0x7E,0x33,0x5A,0x00,0xC1,0xF0,0xC2, ++ 0x40,0xE1,0xD1,0x1E,0x68,0x41,0x80,0x4E,0x18,0x62,0x05,0x1F,0x70,0x01,0x8C,0x0E, ++ 0x30,0x72,0x01,0x1F,0x41,0x68,0x1B,0x62,0x6F,0x01,0x88,0x06,0xC0,0x5C,0xC8,0x4C, ++ 0xDB,0x03,0x1A,0xC2,0xC0,0x08,0x02,0x01,0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48, ++ 0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2,0x99,0xC6,0x37,0xAA,0x20,0x01,0x00,0x0F, ++ 0x1B,0xA2,0x41,0xB0,0x77,0x01,0x88,0xDE,0xC0,0x5C,0x60,0x04,0xC0,0x41,0x91,0x35, ++ 0x05,0xAF,0x18,0x62,0x46,0xD2,0x0A,0x23,0x48,0x2D,0xB8,0x0C,0x88,0x04,0x40,0x55, ++ 0x40,0x3E,0x58,0x35,0xB9,0xFF,0xFF,0xA7,0xC2,0x44,0xC8,0x03,0x42,0x31,0x80,0x6E, ++ 0x30,0x5A,0x03,0xA1,0xF5,0xC2,0x10,0x82,0xE9,0x06,0x18,0x62,0x40,0x68,0x6B,0x01, ++ 0x88,0x3E,0xC7,0x54,0x0E,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00,0xB3,0x23,0xE0,0xF8, ++ 0x90,0xFD,0xC7,0x24,0x14,0x3A,0x9C,0x66,0xF1,0x3C,0x00,0xA7,0xC3,0x54,0x08,0x59, ++ 0xCA,0x00,0x0C,0x48,0xC1,0x38,0xF2,0xC3,0x40,0x01,0x88,0x0E,0x01,0x09,0xB0,0xC3, ++ 0xF0,0xE3,0x29,0x01,0x01,0x01,0x00,0x0F,0xE7,0x68,0x93,0x6D,0x40,0x09,0x88,0x1E, ++ 0x60,0xF9,0x97,0x0E,0xE5,0x20,0x93,0x25,0x48,0xE2,0x01,0x01,0x00,0x43,0xAC,0x48, ++ 0x46,0xDA,0x09,0x23,0x20,0x00,0x67,0x10,0x00,0x0F,0x00,0xBF,0x40,0x48,0x32,0x82, ++ 0x17,0x42,0x80,0xDE,0x48,0x01,0xC9,0x06,0x08,0x01,0x89,0x04,0x90,0x0C,0x40,0x55, ++ 0x41,0x6E,0x30,0x8A,0xBA,0xFF,0xF7,0x77,0x40,0x01,0x80,0x0E,0x6E,0x29,0x98,0xDE, ++ 0xB3,0xE3,0xE1,0xB0,0x90,0xB5,0xC7,0x24,0x16,0x32,0x9C,0x3E,0x87,0x6D,0xE8,0x85, ++ 0xAC,0xBD,0x87,0x15,0x30,0x62,0x30,0xB2,0x48,0x2A,0x01,0x01,0x81,0x43,0x40,0x4A, ++ 0x40,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B,0x28,0x01,0x00,0x3F,0x09,0x09,0x30,0x9A, ++ 0x30,0x52,0x31,0x42,0x81,0x07,0xC8,0x57,0xE7,0x68,0x93,0x6D,0xDD,0x03,0x11,0x42, ++ 0xC1,0xA6,0x37,0x12,0x30,0x8A,0x01,0x11,0x84,0x07,0xC0,0x2F,0x31,0x92,0x31,0x0A, ++ 0xC7,0x14,0xB8,0xFF,0xF9,0x77,0x30,0x12,0x30,0x8A,0x01,0x01,0x83,0x07,0xC0,0xDF, ++ 0xE0,0x03,0x41,0x01,0x80,0xBE,0x69,0xB2,0x44,0x43,0x97,0x3D,0x4F,0x04,0x01,0x43, ++ 0x40,0x7A,0x08,0x09,0x81,0x0B,0x30,0x12,0x30,0x8A,0x01,0x11,0x83,0x07,0xC0,0x5F, ++ 0x30,0x1A,0xB1,0x04,0x08,0x01,0x00,0x09,0xD0,0x14,0x80,0x07,0xC8,0xAF,0xB2,0x04, ++ 0xD9,0x0B,0x37,0x1A,0x00,0x11,0xD0,0x14,0x82,0x07,0xC8,0x77,0x31,0x92,0x31,0x0A, ++ 0xC7,0x14,0xB8,0xFF,0xF1,0x37,0x37,0x12,0x30,0x8A,0x01,0x6F,0x60,0x20,0x02,0x00, ++ 0x00,0xD0,0x00,0x01,0x48,0xE0,0x06,0x00,0xF8,0xFB,0x07,0x00,0x10,0x00,0x00,0x42, ++ 0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x00,0x01,0x80,0x07,0xC0,0x27,0x42,0x5A, ++ 0x08,0x01,0x80,0x0B,0x01,0x7B,0x37,0x1A,0xB0,0x04,0x08,0x01,0x00,0x11,0xD0,0x14, ++ 0x81,0x07,0xC8,0x57,0x31,0x12,0x31,0x8A,0x00,0x11,0x80,0x07,0xC0,0xA7,0x51,0x22, ++ 0x40,0x83,0x08,0x11,0x18,0x42,0x04,0x83,0x87,0x2D,0xE8,0x85,0x00,0xD0,0x00,0x01, ++ 0x18,0x00,0x04,0x42,0xA8,0x85,0x31,0x12,0x92,0x01,0x46,0x8C,0x80,0x01,0xC7,0x1B, ++ 0x32,0xD8,0x72,0xD8,0x87,0x1B,0x58,0xE2,0x41,0xE3,0x30,0x20,0xA2,0x16,0x40,0xE3, ++ 0x3F,0x20,0xAB,0xE6,0x58,0xCA,0x27,0x41,0x00,0xE3,0x44,0xE3,0x28,0xF9,0xAF,0x19, ++ 0x18,0x62,0x01,0xE3,0xC7,0x23,0x48,0x20,0x8A,0x1E,0xF0,0x48,0x20,0x48,0x60,0x48, ++ 0x88,0xC6,0x4F,0x01,0x88,0x36,0x40,0xC3,0x08,0x81,0x18,0x42,0x07,0xC3,0x00,0xF9, ++ 0x82,0x89,0x04,0x84,0xEF,0x85,0xA9,0x85,0x46,0x63,0x42,0x5B,0xDF,0xAB,0x72,0x62, ++ 0xC0,0xB3,0x71,0x09,0x8E,0x16,0x48,0x63,0x50,0x5B,0xE2,0xAB,0x41,0x01,0x88,0x0E, ++ 0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42, ++ 0xC4,0x01,0x5A,0x33,0xC1,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3,0x1B,0x82,0x35,0x32,0x00,0x83,0x41,0x73, ++ 0xC4,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52, ++ 0x9F,0x06,0xEF,0x85,0x41,0x09,0x88,0x0E,0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32, ++ 0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3, ++ 0x1B,0x82,0x35,0x32,0x00,0x83,0x41,0x73,0xC0,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20, ++ 0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85,0x41,0x11,0x88,0x0E, ++ 0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42, ++ 0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3,0x1B,0x82,0x31,0x32,0x00,0x83,0x41,0x73, ++ 0xC4,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52, ++ 0x9F,0x06,0xEF,0x85,0x47,0x19,0x88,0xE6,0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32, ++ 0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3, ++ 0x1B,0x82,0x31,0x32,0x00,0x83,0x41,0x73,0xC0,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20, ++ 0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85,0xAA,0x85,0x47,0xE3, ++ 0x05,0xB0,0xCC,0x20,0x45,0xEB,0xC6,0x68,0x40,0x09,0x88,0x26,0x45,0xE3,0xC8,0x20, ++ 0x44,0xDB,0xC4,0xE8,0x04,0x3F,0x78,0xD2,0xC0,0xFB,0x79,0x09,0x8E,0x1E,0x48,0xE3, ++ 0xCA,0x20,0x55,0xDB,0xC1,0xE8,0x44,0x13,0xF9,0xA0,0xC0,0x5B,0x40,0x09,0x88,0x76, ++ 0x48,0x01,0x88,0x66,0x44,0x83,0x1A,0xC2,0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83, ++ 0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83,0x18,0xC2,0x00,0x83,0xE8,0x85,0x4F,0x09, ++ 0x8A,0x66,0x40,0x83,0x1A,0xC2,0x04,0x83,0x44,0x83,0x1C,0xC2,0x00,0x83,0x44,0x83, ++ 0x18,0xC2,0x04,0x83,0x40,0x03,0x19,0xC2,0x07,0x03,0xE9,0x85,0x48,0x11,0x88,0x66, ++ 0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83,0x18,0xC2,0x04,0x83,0x40,0x83,0x1A,0xC2, ++ 0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83,0xE8,0x85,0x4F,0x19,0x89,0xE6,0x47,0x03, ++ 0x19,0xC2,0x04,0x03,0x44,0x83,0x18,0xC2,0x02,0x83,0x40,0x83,0x1A,0xC2,0x04,0x83, ++ 0x40,0x83,0x1C,0xC2,0x07,0x83,0xEC,0x85,0xA8,0xFD,0xF7,0x4C,0x30,0x62,0x2C,0x01, ++ 0x4D,0x93,0x49,0x8B,0x32,0x72,0xDC,0xE3,0x33,0x3A,0x49,0x8A,0xC0,0x4B,0x48,0x09, ++ 0x89,0x0E,0x50,0x93,0xE0,0xE3,0x40,0x19,0x80,0x96,0x31,0x79,0x49,0x5A,0x13,0xB0, ++ 0x40,0x11,0x88,0xB6,0x32,0x02,0x1B,0x3A,0x58,0x52,0xC3,0x14,0xC1,0x00,0xC6,0xC0, ++ 0x33,0x9A,0x33,0x2A,0xEA,0xDA,0x0A,0x5B,0x08,0x01,0x00,0x3F,0xC1,0x1B,0x18,0x9A, ++ 0x41,0xAB,0x00,0x5B,0xEA,0x90,0xE0,0x00,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xAE, ++ 0xE8,0xFD,0x47,0x01,0x88,0x8E,0x18,0x01,0x12,0x5B,0x46,0xDA,0x45,0x33,0x40,0xB0, ++ 0x00,0xB0,0x05,0x33,0x00,0x1B,0x02,0x5B,0x40,0x0B,0x18,0x81,0x18,0xCA,0x04,0x0B, ++ 0x44,0x0B,0x18,0x01,0x18,0xCA,0x00,0x0B,0x00,0x17,0x40,0x09,0x89,0x06,0x30,0xAA, ++ 0x00,0x01,0x00,0x27,0x40,0x8B,0x00,0x6B,0xEA,0x90,0xE0,0x00,0x95,0x05,0x16,0x02, ++ 0x9F,0xC6,0xEF,0xFD,0x3B,0x82,0xAB,0x85,0x4A,0xA3,0xD8,0xEB,0x33,0x70,0x72,0xB0, ++ 0x48,0x5A,0xC2,0x4B,0x48,0x09,0x88,0x0E,0x50,0xA3,0xE0,0xEB,0x08,0x01,0x00,0x3F, ++ 0x42,0x13,0x41,0x93,0x00,0x92,0x07,0x14,0xEC,0x20,0xE1,0x00,0xE6,0x48,0x92,0x4D, ++ 0x17,0x4A,0x9D,0xAE,0xEB,0x85,0xAB,0xC5,0x30,0x2A,0x30,0xB2,0x61,0xF2,0x41,0x03, ++ 0x14,0x01,0x1C,0x82,0x01,0x03,0x41,0x03,0x10,0x81,0x18,0x82,0x01,0x03,0x41,0x03, ++ 0x10,0x09,0x18,0x82,0x07,0x03,0xE1,0x53,0x00,0xF9,0x87,0x81,0x19,0x12,0x40,0xBA, ++ 0x10,0x13,0x16,0x99,0x00,0x13,0x13,0x41,0x04,0x13,0x14,0xD9,0xE8,0x92,0x52,0x01, ++ 0x80,0x16,0x10,0xC9,0x00,0x13,0x00,0x0F,0x10,0x89,0x00,0x13,0x31,0x52,0x30,0x5A, ++ 0x08,0x01,0x00,0x09,0xB7,0x04,0xB8,0xFF,0xF9,0x7F,0x33,0x52,0x30,0x8A,0x01,0x11, ++ 0xBB,0xFF,0xF7,0xCF,0x42,0x03,0x3B,0x00,0xAB,0xE6,0xEF,0xC5,0xAC,0x9D,0x87,0x8D, ++ 0xCA,0x94,0xC8,0x4B,0x88,0x84,0xE0,0x94,0xA7,0x01,0xD2,0x1B,0xD8,0x0B,0x89,0x04, ++ 0xCA,0x94,0xD8,0x6B,0x30,0x0A,0x88,0x71,0x30,0x62,0xCC,0x94,0x30,0x01,0xE8,0x4B, ++ 0x48,0x09,0x88,0x56,0x08,0x01,0x00,0x27,0xC5,0x38,0x9A,0xF3,0xA2,0x32,0xE2,0x48, ++ 0x90,0x4D,0xD2,0x94,0xDC,0x93,0x12,0x52,0xE0,0xB6,0x57,0xDA,0x04,0xB3,0x02,0xB3, ++ 0x00,0xB3,0x0E,0x01,0x18,0x4A,0x06,0x8B,0xCA,0x94,0xD8,0x4B,0xB0,0x8B,0x08,0x01, ++ 0x50,0xAA,0x30,0x01,0x05,0x78,0xC4,0xF8,0x0A,0xF3,0xC1,0x90,0xB2,0xB3,0xE2,0x48, ++ 0x90,0x4D,0x4A,0x11,0xD8,0xA6,0xCF,0x94,0xE8,0x4B,0x48,0x29,0xCD,0xF6,0x03,0x48, ++ 0xC3,0x48,0x00,0x50,0xC0,0x70,0x54,0x6A,0xC0,0xB0,0xB5,0x14,0xC0,0x48,0x8C,0x0C, ++ 0x30,0x12,0x33,0x32,0xB0,0xE1,0x08,0x01,0x88,0x34,0x48,0x4A,0x88,0x6C,0x88,0x64, ++ 0x30,0x32,0x04,0x01,0x32,0x22,0x04,0x97,0x18,0x00,0x04,0x42,0x00,0x01,0x00,0x42, ++ 0x00,0xD0,0x00,0x01,0x60,0x20,0x02,0x00,0x80,0x40,0x07,0x01,0x48,0xE0,0x06,0x00, ++ 0x78,0xF8,0x07,0x00,0xC8,0x14,0x00,0x01,0xF0,0x42,0xF8,0x0C,0x0B,0x01,0xF0,0xCA, ++ 0x32,0x7A,0xD0,0x08,0x97,0x4D,0x48,0xF9,0xEF,0x06,0x08,0xF9,0xCB,0x38,0x86,0xF8, ++ 0x78,0xF9,0xEF,0x06,0x3B,0xF9,0x37,0x82,0x82,0x3B,0xE0,0x00,0x30,0x32,0xC4,0xBB, ++ 0x10,0xFA,0x9C,0x46,0x10,0xCA,0xDC,0x36,0x46,0x84,0xD9,0x48,0xC0,0x00,0x92,0x05, ++ 0x04,0x84,0x81,0x08,0x04,0x37,0x10,0xCA,0xDC,0x16,0x00,0x78,0x00,0xBC,0x01,0x0F, ++ 0x39,0x01,0x00,0xBC,0x10,0xCA,0xDC,0x0E,0x38,0x09,0xB8,0x34,0x43,0x78,0x2B,0x3A, ++ 0xE8,0x26,0xF8,0x6C,0x10,0x7A,0xEC,0x2E,0x88,0x6C,0x00,0x1F,0xFC,0x64,0x10,0x7A, ++ 0xE8,0x06,0x88,0x64,0x82,0x8B,0xE0,0x90,0xE0,0xB0,0xC5,0x14,0xE0,0x00,0x84,0x14, ++ 0xC4,0x0C,0xE0,0x00,0x83,0x0C,0x30,0x02,0xE2,0x00,0x92,0x05,0x35,0x22,0x2C,0x62, ++ 0xD8,0xC6,0xC5,0x34,0x40,0x01,0x80,0x8E,0x08,0x01,0x00,0x01,0x80,0x5C,0xC0,0x04, ++ 0xC2,0x00,0x46,0x00,0x80,0x7C,0xC0,0x04,0x30,0x00,0x72,0x00,0x80,0x74,0x00,0x01, ++ 0x30,0x22,0x84,0x2C,0x80,0x24,0x80,0x1C,0xF0,0x90,0x02,0x07,0x03,0x1F,0xF5,0x40, ++ 0x94,0x05,0x32,0x32,0x03,0xFF,0x31,0x02,0x04,0x00,0x32,0x22,0xC2,0x2C,0x00,0x00, ++ 0x80,0x2C,0xC0,0x24,0x00,0x00,0x82,0x24,0xC2,0x1C,0x00,0x00,0x83,0x1C,0x40,0x40, ++ 0x28,0x82,0xEB,0x26,0xC0,0x83,0xF0,0x6C,0xD8,0x00,0x84,0x83,0x00,0x1F,0xC0,0x83, ++ 0xF4,0x64,0xD8,0x00,0x80,0x83,0xC0,0x83,0x73,0x3D,0x30,0xBA,0xA8,0x82,0xC7,0x83, ++ 0x10,0xC2,0xDC,0xDE,0xE2,0x48,0x92,0x4D,0xF1,0x5C,0xC0,0xB0,0x90,0xB5,0xB1,0x5C, ++ 0x30,0x32,0x3B,0x09,0x1D,0xF2,0x31,0xA2,0xF5,0x7C,0x10,0x82,0xD8,0x76,0xF0,0x2C, ++ 0x18,0xF2,0xB1,0x2C,0xF5,0x04,0x10,0x82,0xD8,0x46,0xF0,0x24,0x18,0xF2,0xB1,0x24, ++ 0xF5,0x74,0x10,0x82,0xD8,0x16,0xC0,0x1C,0x18,0xC2,0x81,0x1C,0xF3,0x90,0x32,0x82, ++ 0xF2,0x00,0x92,0x05,0x33,0x32,0x34,0x82,0x45,0x01,0xD0,0xE6,0x42,0xE2,0xB7,0x0B, ++ 0xD0,0x50,0xB3,0x13,0x36,0x12,0x1B,0x92,0x03,0x13,0x30,0x12,0x08,0x13,0xD0,0x2C, ++ 0x00,0x13,0xD2,0x24,0x00,0x13,0xD4,0x1C,0x00,0x13,0x36,0x01,0x00,0xA7,0xC1,0x5C, ++ 0x86,0x07,0xE8,0xA7,0x90,0x05,0x80,0x5C,0x4D,0x8A,0x07,0x80,0xC0,0x00,0x4A,0x13, ++ 0x40,0x3D,0x08,0x01,0x1C,0x01,0x30,0xF2,0x30,0xE2,0x04,0xCF,0x38,0x98,0x86,0x7E, ++ 0xC0,0x1B,0xF8,0x5C,0xD8,0xD8,0x96,0xDD,0x58,0x01,0xE8,0x36,0x83,0x1B,0x20,0x9A, ++ 0x94,0xDD,0x36,0xF2,0xE2,0x48,0x92,0x4D,0x00,0x27,0x18,0x01,0x80,0x1B,0x00,0x0F, ++ 0x18,0x01,0x80,0x1B,0x42,0x90,0xE2,0x00,0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x32,0xE2, ++ 0x2F,0x62,0xDD,0x1E,0xE3,0xB0,0x93,0xB5,0x30,0x82,0x83,0x5C,0x45,0xE2,0x06,0x98, ++ 0xC0,0xD8,0x08,0xD3,0xCA,0x00,0xB4,0x0B,0x48,0x21,0xD8,0x0E,0x76,0x09,0xD8,0x36, ++ 0x06,0x01,0x50,0xBA,0x04,0x08,0xC4,0x58,0xE4,0x08,0x02,0x70,0xC0,0xB0,0x4D,0xEB, ++ 0x4D,0xB3,0x19,0xAA,0x08,0xEB,0xC0,0x80,0xF4,0x1B,0xF2,0x2B,0xDA,0xD8,0xB2,0x1B, ++ 0x90,0x45,0x42,0x09,0xD8,0x76,0x07,0x09,0xA6,0x03,0x43,0x6A,0x0E,0x19,0x40,0x13, ++ 0x50,0x01,0x80,0x16,0x03,0x29,0xA0,0x0B,0x04,0xF7,0x40,0x13,0x50,0x01,0x80,0x16, ++ 0x03,0x21,0xA0,0x0B,0x02,0xC7,0x40,0x0B,0x48,0x01,0x80,0x1E,0x00,0x19,0x08,0x11, ++ 0xA0,0x0B,0x03,0x8F,0x48,0x03,0x40,0x01,0x88,0x26,0xC0,0x94,0x86,0x01,0xCE,0x03, ++ 0x40,0x51,0x98,0x0E,0x00,0x11,0x00,0x3F,0xC1,0x94,0x80,0x01,0xE0,0x03,0x44,0x01, ++ 0x80,0x0E,0x00,0x11,0x00,0x07,0x00,0x09,0xE4,0x0B,0xE3,0x50,0xA3,0x13,0xDD,0x13, ++ 0x38,0x90,0xA2,0x0E,0xF3,0x48,0xA2,0x0B,0xE8,0x0B,0x13,0x29,0x10,0x0A,0x94,0x0E, ++ 0xA8,0x13,0x01,0xEF,0x10,0x0A,0xCC,0x46,0x40,0x09,0x88,0x16,0x09,0x81,0xAF,0x0B, ++ 0x00,0xB7,0xD0,0x48,0x01,0x52,0xAC,0x13,0x00,0x97,0x40,0x19,0xC8,0x0E,0x08,0x19, ++ 0x02,0x07,0x90,0x0D,0xE8,0x13,0x51,0x01,0x82,0x16,0xF0,0x90,0xA8,0x13,0x01,0x3F, ++ 0xD2,0x94,0xF0,0x48,0xCA,0x93,0x1C,0x52,0xCA,0x84,0xC0,0x88,0xD0,0x94,0x88,0x8B, ++ 0xA8,0x03,0x83,0x9D,0xEF,0x85,0xAF,0xBD,0x80,0x6D,0x34,0x6A,0xD9,0x63,0x33,0x42, ++ 0x80,0x01,0x82,0x64,0xD0,0x03,0x84,0x3C,0xC2,0x64,0xD8,0x03,0x30,0x00,0xA8,0x1E, ++ 0x02,0xD9,0xEC,0x02,0x40,0x01,0x80,0xA6,0xC5,0x6C,0x00,0x08,0xC3,0x40,0x00,0x08, ++ 0x52,0xC2,0xC4,0x08,0xC4,0x48,0xC4,0x10,0x00,0x01,0x18,0x01,0x00,0x2F,0x00,0x5C, ++ 0x04,0x9C,0xE0,0x48,0xE2,0x90,0xE4,0x00,0x95,0x05,0x12,0x02,0xD8,0xBE,0x87,0x85, ++ 0xEB,0x85,0x07,0x59,0xCA,0x6C,0x08,0x00,0xC4,0x40,0x70,0x7A,0xF7,0x03,0x08,0x83, ++ 0xD0,0x7C,0x90,0x04,0x30,0x5A,0x09,0x01,0x00,0x11,0xD0,0x6C,0xBB,0xFF,0xEF,0xE7, ++ 0x42,0x4A,0x84,0x01,0x43,0x0B,0x30,0x5A,0x09,0xCC,0x5C,0x8B,0x0B,0xCC,0x5E,0x8B, ++ 0x15,0xCC,0x58,0x8B,0x17,0xCC,0x42,0x8B,0x14,0xCC,0x4C,0x22,0x46,0x53,0x10,0xD4, ++ 0x48,0x93,0x1F,0xD4,0x17,0x89,0x00,0x93,0x13,0x19,0x18,0x93,0x40,0x53,0x18,0x11, ++ 0x18,0xD2,0x04,0x53,0x40,0x0B,0x18,0xCA,0x01,0x0B,0x30,0x42,0xE9,0x4B,0x81,0x01, ++ 0x80,0x5C,0x48,0x09,0x8D,0x5E,0x6A,0x44,0x81,0x14,0x30,0x8A,0x5E,0x43,0x94,0x35, ++ 0xB0,0x0C,0x00,0x01,0x80,0x04,0xD0,0x6C,0x4F,0x92,0x03,0x00,0xC2,0x00,0xC4,0x00, ++ 0x83,0x54,0x40,0x8A,0x18,0x33,0x0A,0x01,0x37,0x42,0xB9,0xFF,0xE0,0x5F,0xF9,0x54, ++ 0xC1,0x64,0x30,0x5A,0xD1,0x0B,0x32,0xC2,0xD7,0x7C,0xB8,0xFF,0xEB,0x67,0x4C,0x62, ++ 0x10,0x01,0x00,0x01,0x02,0x67,0x00,0x18,0x37,0xE2,0xF4,0xDA,0x10,0x5A,0xD4,0x0E, ++ 0x33,0x0A,0xD3,0xCA,0x10,0x9A,0xEC,0x0E,0x35,0x12,0xD3,0xD2,0xE2,0x00,0x92,0x05, ++ 0x17,0x02,0xDD,0x86,0xC4,0x14,0xE0,0x00,0x10,0x0A,0x9C,0x36,0xC0,0x04,0x40,0x01, ++ 0x8B,0x9E,0x40,0x80,0x40,0x08,0xC2,0x70,0x00,0x3F,0xC0,0x14,0xF4,0x00,0x14,0x12, ++ 0xE0,0x5E,0x00,0x09,0x83,0x04,0xE0,0xB0,0x90,0xB5,0x77,0x01,0x80,0x16,0xC0,0x0C, ++ 0x16,0x32,0x9C,0x36,0x70,0x01,0x88,0x06,0x30,0x09,0xC0,0x5C,0x90,0x33,0xC0,0x5C, ++ 0xD2,0x0B,0x40,0x8A,0x18,0x0B,0x32,0x01,0x36,0x42,0x81,0x01,0x81,0x4C,0x80,0x01, ++ 0x83,0x44,0x00,0x37,0xC4,0x3C,0x10,0x32,0xD0,0x6E,0xC0,0x44,0xC0,0x03,0xC8,0x44, ++ 0x32,0x00,0x72,0x00,0x82,0x43,0x40,0x42,0x0C,0x41,0x00,0x0B,0x47,0x0B,0x10,0xF9, ++ 0x90,0x21,0x18,0x8A,0x00,0x0B,0xC8,0x6C,0x02,0x00,0xC5,0x08,0x02,0x00,0x53,0x0A, ++ 0xC4,0x40,0xC0,0x00,0xC0,0x48,0x74,0x01,0x88,0x66,0x10,0x01,0x78,0x02,0x02,0x37, ++ 0x18,0x01,0x00,0x1C,0x04,0x7C,0xE0,0x00,0xE2,0x48,0xE4,0x90,0x95,0x95,0x12,0x12, ++ 0xD9,0xB6,0x07,0x07,0xDF,0x6C,0x00,0x10,0xC1,0x90,0x5E,0xB2,0xC4,0x90,0x36,0xA2, ++ 0x18,0x01,0x00,0x9F,0x30,0x3A,0x13,0x01,0xF0,0xD2,0x3D,0x01,0xFC,0x3A,0x16,0xBA, ++ 0xD0,0x06,0x00,0x14,0x3E,0x01,0xF8,0x7A,0x10,0xBA,0xEC,0x06,0x04,0x54,0xE0,0x00, ++ 0xE3,0x48,0x34,0x12,0xE4,0x90,0x34,0xA2,0xE2,0xD8,0x92,0xDD,0x17,0x1A,0xDD,0x4E, ++ 0xC4,0x3C,0x10,0x32,0x80,0x06,0xC1,0x44,0xC6,0x03,0x48,0x00,0x88,0x1E,0xC0,0x4C, ++ 0xC8,0x03,0x42,0x31,0x88,0xBE,0xC7,0x4C,0xC8,0x03,0x42,0x31,0x89,0x26,0x40,0x12, ++ 0x40,0x0B,0x10,0x81,0x18,0x8A,0x00,0x0B,0xCF,0x6C,0x00,0x00,0xC0,0x00,0x4A,0xEA, ++ 0xC0,0x00,0xCA,0x64,0x32,0x5A,0xD1,0x4B,0xD7,0x7C,0xB8,0xFF,0xE3,0x67,0xE7,0xB0, ++ 0x90,0xB5,0xC3,0x3C,0x14,0x32,0xEC,0xAE,0x43,0xBA,0x30,0x5A,0x4A,0xCC,0x84,0x01, ++ 0x00,0x0B,0x40,0xAA,0x48,0xCC,0x1E,0x0B,0x52,0xCC,0x18,0x0B,0x54,0xCC,0x1A,0x0B, ++ 0x56,0xCC,0x04,0x0B,0x4E,0x8A,0x50,0xD4,0x00,0x53,0x58,0xCC,0x0F,0x0B,0x36,0xB7, ++ 0xAA,0x85,0xD8,0xE3,0x1A,0x0A,0x03,0x48,0xC5,0x50,0x0C,0x49,0x02,0x48,0xC4,0x88, ++ 0xE8,0xD3,0x50,0x11,0xC0,0x4E,0x10,0x01,0x00,0x2F,0x40,0x1C,0x04,0x5C,0xE0,0x48, ++ 0xE2,0x00,0xE4,0x90,0x95,0x95,0x12,0x12,0xD8,0xBE,0x17,0x01,0x00,0x87,0x00,0x00, ++ 0x80,0x40,0x07,0x01,0x48,0xE0,0x06,0x00,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42, ++ 0xF8,0xFB,0x07,0x00,0x40,0x1C,0x00,0x5C,0xE4,0x00,0xE4,0x48,0xE2,0x90,0x92,0x95, ++ 0x17,0x12,0xDD,0xBE,0xEF,0x85,0xA8,0x85,0x30,0x6A,0xF0,0x2C,0x30,0x22,0x30,0x8A, ++ 0x31,0xFA,0x30,0xC2,0xB9,0xFF,0xDF,0xB7,0x31,0xDA,0x31,0x92,0x31,0x4A,0x31,0x02, ++ 0xBC,0xFF,0xE7,0xCF,0xE8,0x85,0x37,0x0A,0x8D,0x01,0x86,0x01,0x02,0x5F,0xC8,0x5B, ++ 0x58,0x31,0x88,0x46,0x40,0xFA,0x47,0x0B,0x10,0x81,0x18,0x8A,0x00,0x0B,0x40,0x0B, ++ 0x18,0x8A,0x00,0x0B,0x3E,0x82,0xCB,0x1B,0x5F,0x01,0x88,0x86,0x38,0x82,0xAB,0x85, ++ 0xDA,0x5B,0xD8,0x4B,0x1F,0x5A,0x4A,0xC2,0xC7,0x08,0x52,0xC2,0xC0,0x00,0x14,0x01, ++ 0x00,0x27,0x40,0x24,0x04,0x64,0xE0,0x00,0xE2,0x48,0xE4,0x90,0x17,0xD2,0x9C,0xC6, ++ 0xEF,0x85,0xA8,0xBD,0x80,0x15,0x34,0x62,0x37,0xBA,0xD8,0x33,0xE8,0x03,0x09,0x01, ++ 0x18,0x4A,0x2E,0x01,0x40,0x29,0x90,0x16,0x1F,0x0B,0x1D,0x2B,0x07,0x6F,0x00,0x09, ++ 0xEA,0x02,0x38,0x00,0xAF,0x26,0x50,0x52,0x58,0x03,0x1F,0x82,0x18,0x03,0x05,0x27, ++ 0x57,0x3A,0x5F,0x03,0x18,0x92,0x1E,0x82,0x1D,0x03,0x1D,0x0B,0x30,0x0A,0xC1,0x14, ++ 0xBC,0xFF,0xE7,0xE7,0x25,0x2B,0x59,0x03,0x28,0x01,0x00,0x17,0x43,0x00,0xE2,0x68, ++ 0x96,0x6D,0x3F,0x08,0x8D,0x0E,0x10,0xAA,0x9B,0xC6,0xAF,0x2B,0x73,0xCA,0x4E,0x04, ++ 0x00,0x83,0xC7,0x14,0x0A,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00,0xF7,0x03,0x08,0x83, ++ 0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBC,0xFF,0xDF,0x87,0x30,0x1A,0xB9,0x04, ++ 0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD8,0xFF,0x06,0x09,0xA7,0x01,0x8D,0x03, ++ 0x48,0x82,0x46,0x43,0x10,0x11,0x18,0x82,0x00,0x43,0x00,0x41,0x01,0x83,0x45,0x83, ++ 0x08,0xF9,0x8F,0x19,0x19,0x42,0x00,0x83,0x87,0x2D,0xE8,0x85,0x3F,0x82,0xAB,0xC5, ++ 0xD8,0x53,0x90,0x04,0xDC,0x53,0x32,0xB2,0xE9,0x53,0x54,0x91,0x9E,0xBE,0x12,0x31, ++ 0xE0,0x92,0x52,0x01,0x8E,0x9E,0x52,0x02,0xC0,0x28,0x34,0x12,0x91,0xE1,0x19,0xC1, ++ 0x8E,0x01,0xF4,0x1A,0xE8,0x63,0x3A,0x11,0x10,0x1A,0xDD,0x16,0xD8,0xD8,0x38,0x1C, ++ 0xA9,0x7B,0x1E,0xD1,0xEE,0x63,0xF4,0x1A,0x15,0x32,0x13,0x9A,0xE0,0x16,0xC8,0xD8, ++ 0x38,0x1C,0xB2,0x7B,0x30,0x01,0x38,0x01,0x1C,0x01,0x30,0xE2,0x00,0x27,0x21,0x01, ++ 0x00,0xE7,0x18,0x01,0xF0,0x5A,0x5F,0x01,0xED,0x4E,0x10,0x9A,0xE8,0x06,0x30,0xF2, ++ 0xE8,0x5B,0x5E,0x01,0x80,0x76,0x40,0x9C,0xF0,0xD8,0x02,0x9C,0x00,0x57,0x58,0x01, ++ 0xD5,0x46,0x10,0xDA,0xD0,0x06,0x30,0xFA,0xF0,0x5B,0x58,0x01,0x80,0x16,0x40,0x9C, ++ 0xE0,0xD8,0x02,0x9C,0xE4,0x68,0xE5,0x90,0xE7,0x20,0x93,0x25,0x2F,0xA2,0x9B,0x06, ++ 0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x36,0xE2,0xE5,0x04,0x28,0x22,0x98,0xBE,0x7E,0x14, ++ 0xC8,0x90,0x3C,0x14,0x7E,0x14,0xCA,0x90,0x3E,0x14,0xEA,0x43,0x40,0x01,0x80,0x0E, ++ 0xF6,0x00,0xAA,0x43,0xF0,0x43,0x40,0x01,0x82,0x0E,0xF0,0x00,0xB7,0x43,0xE8,0xC5, ++ 0xAC,0xBD,0x87,0x15,0x30,0x62,0x30,0xBA,0xEF,0x2B,0xDB,0x33,0xDB,0x03,0x1B,0x42, ++ 0x00,0x08,0xC2,0x14,0xC4,0x40,0x48,0x8A,0xC0,0x00,0x82,0x0C,0x37,0x02,0x81,0x01, ++ 0xC4,0x0B,0x10,0x01,0x18,0x8A,0x80,0x0B,0x00,0x21,0xEE,0x02,0x44,0x01,0x80,0x1E, ++ 0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42,0xBF,0xFF,0xD7,0xC7,0x30,0x1A,0xB9,0x04, ++ 0x08,0x01,0x00,0x19,0xD7,0x14,0xB8,0xFF,0xDA,0x3F,0x02,0x41,0xE9,0x0A,0x30,0x1A, ++ 0x30,0xD2,0xC1,0x0C,0xBC,0xFF,0xDF,0x7F,0x31,0x1A,0x31,0x4A,0xD0,0x14,0xC0,0x0C, ++ 0xBD,0xFF,0xF7,0xB7,0x50,0x02,0x1C,0x09,0xC0,0x83,0x40,0x01,0x8B,0x5E,0xE0,0x68, ++ 0x95,0x6D,0x5F,0x0B,0x03,0x0F,0xE0,0x68,0x90,0x6D,0x37,0xC2,0x00,0x42,0x15,0x0A, ++ 0x8D,0x0E,0x10,0xAA,0x99,0xBE,0x37,0x82,0x74,0x92,0x13,0x2A,0x93,0xE6,0xA8,0x2B, ++ 0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBE,0xFF,0xD7,0x47,0x30,0x1A,0xB9,0x04, ++ 0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD8,0xBF,0xC0,0x14,0x0A,0x59,0xCB,0x00, ++ 0x0A,0x48,0xC2,0x00,0xF7,0x03,0x08,0x83,0x05,0x41,0x00,0x83,0x47,0x83,0x09,0xF9, ++ 0x88,0x19,0x18,0x42,0x01,0x83,0x39,0xBF,0xE1,0x0B,0x31,0x02,0x80,0x01,0x4D,0x01, ++ 0x86,0x1E,0xC9,0x0B,0x49,0x09,0x88,0x06,0x0E,0x11,0x88,0x0B,0xA8,0x2B,0x83,0x9B, ++ 0x4F,0x04,0x01,0x83,0x50,0x0A,0xCB,0x14,0xDC,0x03,0xC1,0x48,0xE7,0x02,0x0A,0x83, ++ 0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBC,0xFF,0xD7,0xC7,0x30,0x1A,0xB9,0x04, ++ 0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD0,0x3F,0x07,0x41,0x01,0x83,0x45,0x83, ++ 0x08,0xF9,0x8F,0x19,0x19,0x42,0x00,0x83,0x38,0x77,0x08,0x01,0x88,0x0B,0x86,0x8B, ++ 0x3F,0x57,0xA8,0x85,0x84,0x9D,0x34,0x22,0x33,0x6A,0xD8,0x73,0xD8,0x43,0x81,0x34, ++ 0x31,0x12,0x93,0xE1,0x92,0x94,0x48,0x72,0x32,0x02,0xC3,0x18,0x4B,0x32,0x22,0x0A, ++ 0x8B,0x8C,0xC8,0x43,0x00,0x00,0x82,0x1C,0x00,0x01,0x80,0x14,0x37,0x42,0x81,0x01, ++ 0x82,0x84,0xC0,0x03,0x5C,0x7B,0x35,0x32,0x3F,0x20,0x5A,0x43,0x18,0x3A,0x60,0x01, ++ 0xD1,0x46,0x40,0xFA,0x18,0x3A,0xB8,0x0C,0x37,0x82,0x23,0xD9,0x00,0x02,0xE1,0x84, ++ 0x80,0x03,0x03,0x47,0x46,0xD2,0x19,0x02,0x18,0x3A,0xB8,0x0C,0x30,0x82,0x23,0x21, ++ 0x18,0x02,0xE1,0x84,0x80,0x03,0x3B,0x01,0x19,0x7B,0x37,0x42,0x80,0x01,0x85,0x7C, ++ 0xC0,0x03,0x84,0x54,0xC0,0x7C,0x20,0x09,0xB8,0x22,0xA0,0x4C,0x34,0x42,0x81,0x01, ++ 0x86,0x74,0x18,0x3B,0xB8,0x44,0xC0,0x74,0x18,0x3B,0xBC,0x3C,0x31,0x42,0x81,0x01, ++ 0x84,0x6C,0xA0,0x3B,0xCA,0x43,0x45,0x00,0x86,0x2C,0x00,0x01,0xFB,0x22,0x82,0x00, ++ 0x81,0x24,0xE8,0x43,0x40,0x29,0xC0,0xBE,0x03,0x01,0x30,0x22,0x3B,0x04,0x39,0x04, ++ 0x20,0x01,0x00,0x77,0x00,0x01,0x00,0x47,0x40,0x7C,0x00,0xFC,0x40,0x7C,0x00,0xBC, ++ 0xE4,0x90,0xE4,0x48,0xE2,0xD8,0xE4,0x00,0x95,0x05,0x12,0x82,0xDB,0xA6,0xE7,0x20, ++ 0x90,0x25,0xC3,0x34,0x17,0x22,0xDC,0x6E,0xF8,0x94,0xE0,0x8C,0x00,0x01,0x80,0x5C, ++ 0x00,0xAF,0x05,0x01,0x34,0x32,0x34,0x22,0xC8,0x5C,0x00,0x09,0x00,0x42,0xCC,0x0C, ++ 0x80,0x64,0x10,0x42,0x81,0x7E,0xE3,0x53,0x50,0x01,0x80,0x2E,0xC8,0x34,0xC0,0x5C, ++ 0xF4,0x48,0x12,0x42,0x88,0x06,0x30,0xB2,0x1A,0x01,0x00,0x87,0x41,0xCC,0x41,0x14, ++ 0xD0,0x40,0x94,0x15,0x00,0x14,0xC9,0x1C,0x10,0x52,0xD4,0x3E,0x32,0x02,0xE3,0x00, ++ 0x94,0x05,0x36,0x22,0x34,0x82,0xC3,0x00,0x94,0x05,0x30,0x32,0xCC,0x2C,0x10,0x52, ++ 0xE8,0x3E,0x01,0x7F,0x00,0x01,0x00,0x42,0x48,0xE0,0x06,0x00,0x38,0xA0,0x03,0x00, ++ 0xAA,0xAA,0xAA,0xAA,0x18,0x00,0x04,0x42,0x00,0xD0,0x00,0x01,0x68,0xB8,0x03,0x00, ++ 0x28,0x60,0x00,0x00,0xCC,0x4B,0x13,0x8A,0xE7,0x1E,0x58,0x43,0xC8,0x64,0x18,0x0A, ++ 0x18,0x4B,0xCF,0x6C,0xE8,0x4B,0x4A,0x09,0x88,0x16,0xC8,0x6C,0x02,0x09,0xAC,0x43, ++ 0xCC,0x54,0x10,0x52,0xE8,0xBE,0x08,0x09,0xD4,0x44,0x00,0xCA,0x18,0x8A,0x88,0x44, ++ 0x00,0x8F,0xC8,0x24,0x10,0x52,0xD4,0x76,0xCA,0x6C,0xE8,0x4B,0x48,0x09,0x88,0x16, ++ 0xCC,0x6C,0x00,0x09,0xA8,0x43,0xCA,0x4C,0x10,0x52,0xD4,0x26,0x08,0x09,0xD0,0x3C, ++ 0x00,0xCA,0x1C,0x8A,0x8D,0x3C,0xE0,0x20,0xE2,0xF8,0xE5,0xD8,0x95,0xDD,0x12,0x9A, ++ 0xD8,0x66,0xC5,0x7C,0xC8,0x03,0x44,0x01,0x83,0x2E,0x32,0x02,0x40,0x11,0xC8,0x2E, ++ 0x33,0x0A,0x33,0x82,0x83,0x07,0xC8,0xD7,0x90,0x05,0x00,0x07,0x03,0x01,0x00,0x88, ++ 0xD0,0x20,0x13,0x01,0x01,0x57,0x01,0x67,0x40,0x01,0xE8,0x7E,0x0B,0x01,0xF0,0x0A, ++ 0xDC,0x1C,0x10,0xCA,0xD2,0xB6,0xE0,0x18,0x10,0xCA,0xEC,0x16,0xD1,0x48,0x00,0x0C, ++ 0x00,0x87,0x48,0x01,0xE8,0x76,0x08,0x09,0x00,0x0C,0x01,0x5F,0x0B,0x01,0xF0,0x0A, ++ 0x10,0x0A,0xD4,0x16,0xD1,0x48,0x00,0x0C,0x00,0x27,0x48,0x01,0xD0,0x16,0x08,0x01, ++ 0x19,0x4A,0x06,0x0C,0x0B,0x01,0xF0,0x0A,0xDC,0x24,0x10,0xCA,0xD0,0x1E,0xC8,0x14, ++ 0xE6,0x48,0x92,0x4D,0x8D,0x14,0xE0,0x20,0xE2,0x90,0x92,0x95,0x16,0x92,0xDD,0x9E, ++ 0x00,0x4F,0x00,0x01,0x08,0x01,0x00,0x27,0x05,0x0C,0xE1,0x20,0xE2,0xF8,0xE5,0x00, ++ 0x95,0x05,0x12,0x82,0xD8,0xC6,0xC7,0x5C,0xE2,0x00,0x92,0x05,0x80,0x5C,0xC8,0x34, ++ 0xC4,0x5C,0x10,0x42,0xD2,0x06,0x38,0x27,0xC9,0x43,0x41,0x71,0xC9,0x0E,0x00,0x71, ++ 0x88,0x43,0xC1,0x14,0xCC,0x4B,0x41,0x00,0xC6,0x40,0x90,0x05,0x8A,0x43,0x41,0x81, ++ 0xCA,0x0E,0x00,0x81,0x88,0x43,0x01,0x01,0x29,0x44,0x37,0x44,0xC0,0x74,0xC8,0x44, ++ 0x18,0x0B,0xCE,0x74,0xC4,0x3C,0x18,0x43,0x87,0x9D,0xE8,0x85,0xA8,0x85,0x33,0x2A, ++ 0x30,0x62,0x30,0xB2,0x31,0x0A,0x31,0x42,0xBA,0xFF,0xEF,0xCF,0x48,0x6A,0x03,0x01, ++ 0x81,0x43,0x30,0x92,0x31,0x0A,0x31,0x42,0xBB,0xFF,0xEF,0x1F,0xEE,0x03,0x41,0x41, ++ 0x92,0x0E,0xE0,0x00,0xAB,0x03,0xE9,0x85,0x10,0x01,0x00,0x37,0x0A,0x01,0xE0,0x48, ++ 0x90,0x4D,0x4C,0xA1,0xCA,0xDE,0xE7,0x90,0x94,0x95,0x14,0x12,0xCB,0xB6,0x3F,0x82, ++ 0x38,0x18,0x78,0xD8,0x14,0x09,0x00,0xD2,0x97,0x95,0x1E,0xF9,0x08,0xD8,0x00,0xC2, ++ 0x5E,0xEA,0xC2,0x00,0x48,0x09,0x88,0x66,0x44,0x0B,0x18,0x8A,0x02,0x0B,0x40,0x0B, ++ 0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B, ++ 0x38,0x82,0x4B,0x01,0x8A,0x66,0x40,0x0B,0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A, ++ 0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B,0x40,0x0B,0x18,0x8A,0x03,0x0B,0x38,0x82, ++ 0x48,0x11,0x88,0x66,0x44,0x0B,0x18,0x8A,0x02,0x0B,0x40,0x0B,0x1A,0x8A,0x04,0x0B, ++ 0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x00,0x0B,0x38,0x82,0x4B,0x19, ++ 0x88,0xE6,0x47,0x0B,0x18,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B, ++ 0x1E,0x8A,0x04,0x0B,0x40,0x0B,0x1A,0x8A,0x03,0x0B,0x3A,0x82,0xAC,0x8D,0x87,0x3D, ++ 0xC0,0x3C,0xC8,0x3C,0x4C,0x00,0x00,0x00,0xC0,0x00,0x3A,0x00,0x4A,0xDA,0x71,0x00, ++ 0xC1,0x28,0x42,0xDA,0x44,0x0B,0x90,0x4D,0x88,0x34,0x58,0x0B,0x90,0x4D,0x8C,0x2C, ++ 0x5C,0x0B,0x92,0x4D,0x8C,0x24,0x58,0x0B,0x90,0x4D,0x8C,0x1C,0x54,0x0B,0x96,0x75, ++ 0x4A,0xA2,0x41,0x53,0x90,0x95,0x94,0x14,0x44,0x53,0x90,0xBD,0x44,0x13,0x92,0x95, ++ 0x91,0x0C,0x58,0x7A,0x98,0x01,0x52,0xD3,0x90,0x95,0x94,0x04,0x10,0x09,0x00,0x13, ++ 0xA8,0x10,0x1C,0x13,0x12,0x81,0x18,0x13,0x18,0x13,0x14,0x79,0x11,0x13,0x16,0x01, ++ 0x00,0x53,0x12,0x89,0x02,0x53,0x40,0x0B,0x10,0x81,0x19,0x8A,0x07,0x0B,0x02,0xF9, ++ 0x80,0x89,0x17,0xC3,0x07,0x09,0xB8,0xFF,0xFF,0x7F,0x03,0xF9,0x80,0x89,0x14,0xC3, ++ 0x07,0x09,0xB8,0xFF,0xF8,0x4F,0x03,0x19,0x11,0x00,0x00,0x43,0x07,0x09,0xB8,0xFF, ++ 0xF8,0x1F,0x0B,0x11,0xC7,0x3C,0xB8,0xFF,0xF8,0x5F,0x23,0xA1,0x01,0x01,0x40,0x4B, ++ 0x30,0x48,0xA8,0x16,0xE7,0x20,0x93,0x25,0x03,0x0F,0xF0,0x20,0x92,0x25,0xE7,0x00, ++ 0x90,0x05,0x46,0x51,0x98,0x9E,0x0F,0x09,0xC7,0x3C,0xB8,0xFF,0xF8,0xCF,0x42,0x82, ++ 0xC8,0x34,0x00,0x0B,0xC8,0x2C,0x18,0x0B,0xCA,0x24,0x18,0x0B,0xCC,0x1C,0x18,0x0B, ++ 0x10,0x33,0x4E,0x62,0xD2,0x14,0x00,0x53,0x00,0x7B,0xC8,0x0C,0x00,0x0B,0x4A,0x42, ++ 0xC2,0x04,0x88,0x01,0x10,0x43,0x60,0xA1,0xC8,0x16,0x00,0x09,0x87,0x45,0xE8,0x85, ++ 0x07,0x01,0x38,0xDF,0x00,0xD0,0x00,0x01,0x80,0x00,0x00,0x42,0x08,0x01,0x00,0x42, ++ 0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x00,0x0F,0x00,0x26,0xF8,0x48,0x48,0x21, ++ 0x94,0xDE,0x3F,0x58,0xA8,0x0E,0x00,0x14,0xE6,0x00,0x3C,0x48,0x80,0x06,0x80,0x13, ++ 0x38,0x82,0x4B,0x01,0x86,0x5E,0x38,0x18,0x80,0x16,0x80,0x13,0xE2,0x00,0xF2,0x48, ++ 0x48,0x11,0x98,0x26,0x38,0x18,0xAC,0x16,0x04,0x14,0xE0,0x00,0xF7,0x48,0x3C,0x1F, ++ 0x17,0x01,0x38,0x77,0x16,0x01,0x38,0xFF,0x10,0x01,0x48,0x18,0x11,0x5A,0x9C,0x66, ++ 0x54,0x18,0x10,0x5A,0x98,0x8E,0x18,0x01,0x32,0xE2,0x04,0x77,0x30,0x1A,0x18,0x5A, ++ 0xA0,0xE6,0x11,0x01,0x44,0x18,0x12,0x5A,0x98,0x8E,0x49,0x18,0x10,0x5A,0x9C,0xE6, ++ 0x54,0x18,0x10,0x5A,0x9C,0x0E,0x30,0xA2,0x06,0xFF,0x49,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x0E,0x58,0xD6,0x00,0x0C,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD4,0x00, ++ 0x0A,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD2,0x00,0x08,0x92,0x4A,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD0,0x00,0x0E,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x06,0x58,0xD6,0x00,0x0C,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD4,0x00, ++ 0x0A,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08, ++ 0x90,0x06,0x30,0x0A,0x08,0x92,0x32,0x82,0x3A,0x82,0x03,0xEF,0x78,0x50,0x86,0x06, ++ 0x10,0x4A,0x82,0x18,0x9A,0x06,0x10,0x02,0x00,0x9A,0x12,0x01,0x30,0xE2,0x4C,0x18, ++ 0x11,0x5A,0x9C,0x6E,0x54,0x18,0x10,0x5A,0x9F,0x96,0x10,0xE1,0x08,0x48,0xD4,0x95, ++ 0x54,0x18,0x10,0x5A,0x9C,0x66,0x08,0x48,0x8C,0x90,0x14,0x5A,0x9C,0x46,0x08,0x48, ++ 0x8C,0x90,0x14,0x5A,0x9C,0x26,0x08,0x48,0x84,0xD6,0x89,0x90,0x04,0x07,0x48,0x48, ++ 0x4C,0x18,0x16,0x5A,0x9E,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x14,0x5A, ++ 0x9C,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x12,0x5A,0x9A,0x0E,0x08,0x58, ++ 0xD2,0x00,0x0E,0x92,0x4C,0x18,0x10,0x5A,0x98,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92, ++ 0x44,0x18,0x16,0x5A,0x9E,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92,0x44,0x18,0x14,0x5A, ++ 0x9C,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92,0x92,0xCE,0x46,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A,0x32,0x1A,0x0B,0x92, ++ 0x80,0xD8,0x32,0x82,0x9A,0x0E,0x10,0x02,0x58,0x01,0xA8,0x06,0x13,0x4A,0x3A,0x82, ++ 0x32,0x1A,0x83,0xD8,0x9A,0x06,0x10,0x02,0xA8,0x0D,0x00,0x01,0x36,0x02,0x36,0x02, ++ 0xEB,0x15,0x30,0xAA,0x81,0x07,0xC0,0x17,0x30,0x72,0x05,0x28,0x32,0x4A,0x33,0x9A, ++ 0x46,0x00,0x06,0x00,0x30,0x2A,0x84,0xC5,0xAF,0x05,0xB9,0xE7,0xF3,0x6F,0xE4,0x05, ++ 0x3A,0x01,0x40,0x48,0x30,0xB2,0x35,0x01,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06, ++ 0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0xEA,0x01,0x02,0x48,0x33,0x6A,0x3C,0x82, ++ 0x36,0x22,0x30,0x02,0x31,0x02,0x36,0x02,0xBA,0xDF,0xD7,0xEF,0x43,0x02,0x38,0x82, ++ 0x88,0x20,0x00,0x01,0x40,0x12,0x48,0x1A,0xF3,0x5D,0x3D,0x82,0x00,0x68,0x00,0x00, ++ 0x00,0xC0,0x00,0x00,0x00,0x30,0x01,0x10,0x39,0x82,0xA3,0x85,0x33,0xA2,0xF3,0x20, ++ 0xC3,0x2B,0xE1,0x20,0x10,0x5A,0x95,0x06,0x33,0xEA,0xE8,0x1A,0x07,0xD8,0xC2,0x18, ++ 0xE0,0x85,0x39,0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x80,0x20,0x03,0x42,0x80,0x20,0x03,0x42,0x80,0x20,0x04,0x42,0x80,0x20,0x03,0x42, ++ 0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42,0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42, ++ 0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42,0x80,0x20,0x05,0x42,0x80,0xA0,0x02,0x42, ++ 0x80,0xA0,0x05,0x42,0x80,0x20,0x02,0x42,0x80,0x20,0x01,0x42,0x80,0x20,0x01,0x42, ++ 0x80,0xA0,0x01,0x42,0x80,0xA0,0x01,0x42,0x80,0xA0,0x01,0x42,0x10,0x20,0x08,0x40, ++ 0x40,0x08,0x20,0x10,0x10,0x20,0x08,0x40,0x40,0x08,0x20,0x40,0x10,0x20,0x00,0x08, ++ 0x08,0xC1,0x02,0x42,0x08,0x81,0x02,0x42,0x08,0x81,0x03,0x42,0x08,0x41,0x03,0x42, ++ 0x08,0x01,0x03,0x42,0x08,0x81,0x02,0x42,0x08,0x41,0x02,0x42,0x08,0xC1,0x00,0x42, ++ 0x08,0x01,0x02,0x42,0x08,0x01,0x01,0x42,0x08,0xC1,0x01,0x42,0x08,0x41,0x01,0x42, ++ 0x08,0x81,0x01,0x42,0x08,0x81,0x01,0x42,0x08,0x41,0x01,0x42,0x08,0xC1,0x02,0x42, ++ 0x08,0x01,0x01,0x42,0x08,0x01,0x03,0x42,0x08,0xC1,0x00,0x42,0x50,0x50,0x50,0x50, ++ 0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x00,0x00,0x00,0x08,0xF8,0x0F, ++ 0xFF,0x07,0xF8,0xFF,0x07,0xF8,0x0F,0xF8,0x08,0x00,0x08,0x08,0x00,0x00,0x00,0x08, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x03,0x00,0x28,0xB5,0x39,0xC5,0x08,0x1D,0x1B,0x2B,0x3A,0x28, ++ 0x53,0xB5,0x0A,0xC5,0x00,0x08,0x01,0x00,0x01,0x00,0x50,0x0D,0x52,0x1D,0x52,0xB5, ++ 0x39,0x0D,0x04,0x08,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95,0x51,0x3D,0x54,0x95, ++ 0x51,0x3D,0x54,0x95,0x0B,0x3D,0x34,0x88,0x51,0x3D,0x54,0x1D,0x51,0x3D,0x54,0x95, ++ 0x04,0x00,0x50,0x3D,0x50,0x1D,0x01,0x00,0x00,0x00,0x00,0x00,0x54,0x2D,0x53,0x3D, ++ 0x32,0x8D,0x32,0x38,0x01,0x28,0x0A,0x45,0x50,0xB5,0x53,0x95,0x00,0x00,0x00,0x00, ++ 0x52,0xA5,0x51,0xB5,0x09,0xC5,0x03,0x08,0x03,0x00,0x50,0x3D,0x55,0x1D,0x51,0x0D, ++ 0x51,0x3D,0x54,0x95,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95,0x51,0x0D,0x55,0x0D, ++ 0x54,0xB5,0x3A,0x0D,0x00,0x08,0x01,0x00,0x53,0xA5,0x51,0x2D,0x52,0x3D,0x34,0x8A, ++ 0x1D,0x38,0x52,0x45,0x52,0x0D,0x51,0x1D,0x54,0xB5,0x3A,0x0D,0x53,0xA5,0x29,0xB5, ++ 0x39,0xC5,0x08,0x1D,0x19,0x2D,0x22,0x1D,0x44,0x0D,0x31,0x3D,0x23,0x95,0x09,0xC1, ++ 0x29,0xB5,0x0B,0x1D,0x1B,0x2B,0x3A,0x28,0x00,0x00,0x00,0x08,0xFF,0x07,0x00,0xF8, ++ 0x08,0x00,0x10,0x10,0x08,0x10,0x10,0x10,0x08,0x08,0x10,0x08,0x10,0x08,0x10,0x08, ++ 0x10,0x10,0x08,0x08,0x10,0x10,0x08,0x08,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10, ++ 0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xF8,0x07,0x08,0x00, ++ 0x08,0x08,0x00,0x00,0x70,0x22,0x07,0x00,0x00,0x00,0x00,0x01,0x00,0xE0,0x00,0x00, ++ 0x00,0x00,0x05,0x00,0x78,0x02,0x00,0x00,0x00,0xE0,0x00,0x01,0x88,0x40,0x02,0x00, ++ 0x00,0xE0,0x05,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, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xD1,0xDA,0xAA,0xA9,0x2E,0x2D,0x55,0x56,0xBB,0x43,0xAC,0x32, ++ 0x99,0x21,0x8A,0x10,0x00,0x70,0x00,0x28,0x09,0x00,0x1F,0x00,0x06,0x78,0x50,0x56, ++ 0xFF,0xFF,0xFF,0xFF,0xB2,0x30,0x08,0x40,0x00,0x48,0x20,0x00,0xE7,0xF5,0x15,0x0F, ++ 0x0F,0x00,0xCA,0xCA,0xFF,0xFF,0xFF,0xFF,0x06,0x16,0x48,0x01,0x09,0x00,0x00,0x04, ++ 0xBE,0xBC,0xE1,0xE2,0x30,0x14,0xF6,0x81 ++}; ++ ++ ++#define FW_INFO_SIZE (0x18) ++#define FW_REAL_SIZE (sizeof(fwbin)) ++#define FW_BIN_SIZE (24*1024+24) //24K byte ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Kconfig b/module_drivers/drivers/input/touchscreen/hyn_touch/Kconfig +new file mode 100644 +index 000000000..10a4e4717 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Kconfig +@@ -0,0 +1,16 @@ ++# ++# Focaltech Touchscreen driver configuration ++# ++ ++config TOUCHSCREEN_HYN ++ bool "hyn Touchscreen" ++ default n ++ help ++ Say Y here if you have Focaltech touch panel. ++ If unsure, say N. ++ ++config TOUCHSCREEN_HYN_DIRECTORY ++ string "hyn ts directory name" ++ default "hyn_touch" ++ depends on TOUCHSCREEN_HYN ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Makefile b/module_drivers/drivers/input/touchscreen/hyn_touch/Makefile +new file mode 100644 +index 000000000..f4c046d58 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Makefile +@@ -0,0 +1,4 @@ ++# Makefile for the focaltech touchscreen drivers. ++ ++obj-$(CONFIG_TOUCHSCREEN_HYN) += hyn_cst3xx.o ++obj-$(CONFIG_TOUCHSCREEN_HYN) += hyn_i2c.o +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/cst3xx.c b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/cst3xx.c +new file mode 100644 +index 000000000..f1e637caf +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/cst3xx.c +@@ -0,0 +1,1422 @@ ++/* ++ * cst3xx Touchscreen Controller Driver ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../../video/jz_fb_v13/jz_fb.h" ++ ++struct st1615_ts_finger { ++ u16 x; ++ u16 y; ++ u8 t; ++ bool is_valid; ++}; ++ ++struct cst3xx_ts_data { ++ struct i2c_client *client; ++ struct input_dev *input_dev; ++ struct cst3xx_platform_data *pdata; ++ struct work_struct work; ++ struct delayed_work dwork; ++ struct workqueue_struct *workqueue; ++ int irq; ++}; ++ ++static int cst3xx_into_program_mode(struct i2c_client * client); ++static int cst3xx_erase_program_area(struct i2c_client * client); ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms); ++static int cst3xx_write_program_data(struct i2c_client * client,const unsigned char *pdata); ++ ++static int cst3xx_check_checksum(struct i2c_client * client); ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client); ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata); ++ ++static int cst3xx_firmware_info(struct i2c_client * client); ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict); ++ ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata); ++ ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_test(struct i2c_client *client); ++static void cst3xx_reset(struct cst3xx_ts_data *ts) ; ++extern void close_vcc3v3Power(void); ++extern void open_vcc3v3Power(void); ++ ++static unsigned char *pcst3xx_update_firmware = (unsigned char *)cst3_fw ; //the updating firmware ++static unsigned int g_cst3xx_ic_version = 0; ++static unsigned int g_cst3xx_ic_checksum = 0; ++static unsigned int g_cst3xx_ic_checkcode =0; ++static unsigned int g_cst3xx_ic_project_id = 0; ++static unsigned int g_cst3xx_ic_type = 0; ++ ++static unsigned char report_flag = 0; ++static unsigned int x_temp_pos = 0; ++static unsigned int y_temp_pos = 0; ++ ++#define HYN_DRAW_POINT ++ ++#define USE_ANALOG_I2C 1 //i2c analog ++//#define USE_HIGHEST_I2CA 1// x1000 highest i2c ++//#define USE_LOWEST_I2CA 1 // x1000 lowest i2c ++#define HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++//#define HYN_UPDATE_FIRMWARE_ENABLE ++ ++#pragma pack(1) ++typedef struct ++{ ++ u16 pid; //product id // ++ u16 vid; //version id // ++} st_tpd_info; ++#pragma pack() ++ ++st_tpd_info tpd_info; ++ ++#define CST3XX_BIN_SIZE (24*1024 + 24) ++#define CST3XX_MAX_X 340 ++#define CST3XX_MAX_Y 800 ++#define ERROR_TOUCH 1 ++ ++static void cst3xx_ts_power(struct cst3xx_ts_data *ts, bool poweron) ++{ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) ++ gpio_direction_output(ts->pdata->reset_gpio, poweron); ++} ++ ++static int cst3xx_into_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x01; ++ buf[2] = 0xAA; //set cmd to enter program mode ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(2); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; //check whether into program mode ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++static int cst3xx_erase_program_area(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; ++ buf[2] = 0x00; //set cmd to erase main area ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(5); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x03; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++ ++ ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms) ++{ ++ ++ unsigned char buf[4]; ++ buf[0] = 0xD1; ++ buf[1] = 0x0E; ++ cst3xx_i2c_write(ts->client, buf, 2); ++/* ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(2); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++*/ ++ mdelay(ms); ++} ++ ++ ++static int cst3xx_write_program_data(struct i2c_client * client, ++ const unsigned char *pdata) ++{ ++ int i, ret; ++ unsigned char *i2c_buf; ++ unsigned short eep_addr; ++ int total_kbyte; ++ ++ unsigned char temp_buf[8]; ++ unsigned short iic_addr; ++ int j; ++ ++ ++ i2c_buf = kmalloc(sizeof(unsigned char)*(1024 + 2), GFP_KERNEL); ++ if (i2c_buf == NULL) ++ return -1; ++ ++ //make sure fwbin len is N*1K ++ //total_kbyte = len / 1024; ++ total_kbyte = 24; ++ for (i=0; i>8; ++ ret = cst3xx_i2c_write(client, i2c_buf, 4); ++ if (ret < 0) ++ goto error_out; ++ ++ memcpy(i2c_buf, pdata + eep_addr, 1024); ++ for(j=0; j<256; j++) { ++ iic_addr = (j<<2); ++ temp_buf[0] = (iic_addr+0xA018)>>8; ++ temp_buf[1] = (iic_addr+0xA018)&0xFF; ++ temp_buf[2] = i2c_buf[iic_addr+0]; ++ temp_buf[3] = i2c_buf[iic_addr+1]; ++ temp_buf[4] = i2c_buf[iic_addr+2]; ++ temp_buf[5] = i2c_buf[iic_addr+3]; ++ ret = cst3xx_i2c_write(client, temp_buf, 6); ++ if (ret < 0) ++ goto error_out; ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x04; ++ i2c_buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(60); ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x05; ++ ret = cst3xx_i2c_read_register(client, i2c_buf, 1); ++ if (ret < 0) ++ goto error_out; ++ ++ if (i2c_buf[0] != 0x55) ++ goto error_out; ++ ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x03; ++ i2c_buf[2] = 0x00; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(8); ++ ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ ++ return 0; ++ ++error_out: ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ return -1; ++} ++ ++ ++static int cst3xx_check_checksum(struct i2c_client * client) ++{ ++ int ret; ++ int i; ++ unsigned int checksum; ++ unsigned int bin_checksum; ++ unsigned char buf[4]; ++ const unsigned char *pData; ++ ++ for(i=0; i<5; i++) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if(ret < 0) ++ { ++ mdelay(2); ++ continue; ++ } ++ ++ if(buf[0]!=0) ++ break; ++ else ++ mdelay(2); ++ } ++ mdelay(2); ++ ++ ++ if(buf[0]==0x01) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ ++ if(ret < 0) return -1; ++ ++ // read chip checksum ++ checksum = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); ++ ++ pData=(unsigned char *)pcst3xx_update_firmware +24*1024+16; //7*1024 +512 ++ bin_checksum = pData[0] + (pData[1]<<8) + (pData[2]<<16) + (pData[3]<<24); ++ ++ printk(" hyn the updated ic checksum is :0x%x. the updating firmware checksum is:0x%x------\n", checksum, bin_checksum); ++ ++ if(checksum!=bin_checksum) ++ { ++ printk(" cst3xx hyn check sum error.\n"); ++ return -1; ++ ++ } ++ ++ } ++ else ++ { ++ printk(" cst3xx hyn No checksum.\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x06; ++ buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) ++ return -1; ++ ++ mdelay(10); //wait for restart ++ ++ ++ return 0; ++} ++ ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ ++ printk(" cst3xx----------upgrade cst3xx begain------------\n"); ++ disable_irq(ts->irq); ++ mdelay(20); ++START_FLOW: ++ ++#ifdef HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++ close_vcc3v3Power(); ++ mdelay(20); ++ open_vcc3v3Power(); ++ mdelay(5+retry); ++#else ++ cst3xx_reset_ic(ts,5+retry); ++#endif ++ ret = cst3xx_into_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]into program mode failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_erase_program_area(ts->client); ++ if (ret) { ++ printk(" cst3xx[cst3xx]erase main area failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_write_program_data(ts->client, pdata); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]write program data into cstxxx failed.\n"); ++ goto err_out; ++ } ++ ++ ret =cst3xx_check_checksum(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] after write program cst3xx_check_checksum failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_exit_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]exit program mode failed.\n"); ++ goto err_out; ++ } ++ ++ cst3xx_reset_ic(ts,20); ++ ++ printk(" cst3xx hyn----------cst3xx_update_firmware end------------\n"); ++ ++ enable_irq(ts->irq); ++ ++ return 0; ++ ++err_out: ++ if (retry < 30) { ++ retry++; ++ mdelay(20); ++ goto START_FLOW; ++ } ++ else { ++ enable_irq(ts->irq); ++ return -1; ++ } ++} ++ ++ ++ ++ ++/******************************************************* ++Function: ++ get firmware version, ic type... ++Input: ++ client: i2c client ++Output: ++ success: 0 ++ fail: -1 ++*******************************************************/ ++static int cst3xx_firmware_info(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[28]; ++// unsigned short ic_type, project_id; ++ ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x01; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ ++ mdelay(40); ++ ++ buf[0] = 0xD1; ++ buf[1] = 0xFC; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ ++ //0xCACA0000 ++ g_cst3xx_ic_checkcode = buf[3]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[2]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[1]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip g_cst3xx_ic_checkcode:0x%x.\r\n",g_cst3xx_ic_checkcode); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x04; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ g_cst3xx_ic_type = buf[3]; ++ g_cst3xx_ic_type <<= 8; ++ g_cst3xx_ic_type |= buf[2]; ++ ++ ++ g_cst3xx_ic_project_id = buf[1]; ++ g_cst3xx_ic_project_id <<= 8; ++ g_cst3xx_ic_project_id |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip ic g_cst3xx_ic_type :0x%x, g_cst3xx_ic_project_id:0x%x\r\n", ++ g_cst3xx_ic_type, g_cst3xx_ic_project_id); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 8); ++ if (ret < 0) return -1; ++ ++ g_cst3xx_ic_version = buf[3]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[2]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[1]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[0]; ++ ++ g_cst3xx_ic_checksum = buf[7]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[6]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[5]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[4]; ++ ++ tpd_info.vid = g_cst3xx_ic_version; ++ tpd_info.pid = 0x00; ++ ++ ++ printk(" cst3xx [cst3xx] the chip ic version:0x%x, checksum:0x%x\r\n", ++ g_cst3xx_ic_version, g_cst3xx_ic_checksum); ++ ++ if(g_cst3xx_ic_version==0xA5A5A5A5) ++ { ++ printk(" cst3xx [cst3xx] the chip ic don't have firmware. \n"); ++ return -1; ++ } ++ if((g_cst3xx_ic_checkcode&0xffff0000)!=0xCACA0000){ ++ printk("linc cst3xx [cst3xx] cst3xx_firmware_info read error .\r\n"); ++ return -1; ++ } ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x09; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ mdelay(5); ++ ++ ++ return 0; ++} ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict) ++{ ++ unsigned short ic_type, project_id; ++ unsigned int fw_checksum, fw_version; ++ const unsigned int *p; ++ int i; ++ unsigned char *pBuf; ++ ++ fw_checksum = 0x55; ++ p = (const unsigned int *)pdata; ++ for (i=0; i<(CST3XX_BIN_SIZE-4); i+=4) { ++ fw_checksum += (*p); ++ p++; ++ } ++ ++ if (fw_checksum != (*p)) { ++ printk(" cst3xx[cst3xx]calculated checksum error:0x%x not equal 0x%x.\n", fw_checksum, *p); ++ return -1; //bad fw, so do not update ++ } ++ ++ pBuf = &pdata[CST3XX_BIN_SIZE-16]; ++ ++ project_id = pBuf[1]; ++ project_id <<= 8; ++ project_id |= pBuf[0]; ++ ++ ic_type = pBuf[3]; ++ ic_type <<= 8; ++ ic_type |= pBuf[2]; ++ ++ fw_version = pBuf[7]; ++ fw_version <<= 8; ++ fw_version |= pBuf[6]; ++ fw_version <<= 8; ++ fw_version |= pBuf[5]; ++ fw_version <<= 8; ++ fw_version |= pBuf[4]; ++ ++ fw_checksum = pBuf[11]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[10]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[9]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[8]; ++ ++ printk(" cst3xx[cst3xx]the updating firmware:project_id:0x%04x,ic type:0x%04x,version:0x%x,checksum:0x%x\n", ++ project_id, ic_type, fw_version, fw_checksum); ++ ++ if (strict > 0) { ++ ++ if (g_cst3xx_ic_checksum != fw_checksum){ ++ if (g_cst3xx_ic_version >fw_version){ ++ printk("[cst3xx]fw version(0x%x), ic version(0x%x).\n",fw_version, g_cst3xx_ic_version); ++ return -1; ++ } ++ }else{ ++ printk("[cst3xx]fw checksum(0x%x), ic checksum(0x%x).\n",fw_checksum, g_cst3xx_ic_checksum); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ int flag = 0; ++ ++ while (retry++ < 3) { ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret == 0) { ++ flag = 1; ++ break; ++ } ++ } ++ ++ if (flag == 1) { ++ ret = cst3xx_update_judge(pdata, 1); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] no need to update firmware.\n"); ++ return 0; ++ } ++ } ++ ++ ret = cst3xx_update_firmware(ts, pdata); ++ if (ret < 0){ ++ printk(" cst3xx [cst3xx] update firmware failed.\n"); ++ return -1; ++ } ++ ++ mdelay(50); ++ ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx [cst3xx] after update read version and checksum fail.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++/*******************************Chose which I2C interface ********************************************/ ++ ++#if USE_ANALOG_I2C ++ ++#define I2CSDA GPIO_PC(27) ++#define I2CSCL GPIO_PC(26) ++ ++#define I2CSDA_HIGH gpio_direction_output(GPIO_PC(27),1) ++#define I2CSDA_LOW gpio_direction_output(GPIO_PC(27),0) ++ ++#define I2CSCL_HIGH gpio_direction_output(GPIO_PC(26),1) ++#define I2CSCL_LOW gpio_direction_output(GPIO_PC(26),0) ++ ++#define delay_data 2 ++static void iicstart(void) ++{ ++ I2CSDA_HIGH; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_LOW; ++ __udelay(2); ++ I2CSCL_LOW; ++ __udelay(2); ++} ++static void iicstop(void) ++{ ++ I2CSDA_LOW; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_HIGH; ++ __udelay(2); ++ ++} ++static unsigned char waitack(void) ++{ ++ u8 ucErrTime=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ // __udelay(2); ++ ++ // I2CSDA_HIGH; ++ // __udelay(2); ++ I2CSCL_HIGH; ++ __udelay(2); ++ ++ while(__gpio_get_value(GPIO_PC(27))) ++ { ++ ucErrTime++; ++ // printk("time out ++ \n"); ++ if(ucErrTime>250) ++ { ++ iicstop(); ++ return 1; ++ } ++ } ++ I2CSCL_LOW; ++ __udelay(2); ++ return 0; ++} ++static void sendack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_LOW; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ ++} ++static void sendnotack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_HIGH; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++} ++static void iicsendbyte(unsigned char ch) ++{ ++ unsigned char i; ++ I2CSCL_LOW; ++ for(i = 0;i<8;i++) ++ { ++ if(ch&0x80) ++ { ++ I2CSDA_HIGH; ++ } ++ else ++ { ++ I2CSDA_LOW; ++ } ++ __udelay(delay_data); ++ ch<<=1; ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ } ++} ++static unsigned char iicreceivebyte(unsigned char ack) ++{ ++ unsigned char i=8; ++ unsigned char ddata=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ __udelay(delay_data); ++ ++ for(i = 0;i<8;i++) ++ { ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ ++ ddata<<=1; ++ if(gpio_get_value(GPIO_PC(27))) ddata++; ++ } ++ ++ if(!ack) ++ sendnotack(); ++ else ++ sendack(); ++ ++ return ddata; ++} ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int count = len; ++ iicstart(); ++ __udelay(delay_data); ++ ++/* ++ iicsendbyte( (0x1a<<1) | 0); ++ __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ ++ iicsendbyte(buf[0]); ++ __udelay(delay_data); ++ waitack(); ++ __udelay(delay_data); ++*/ ++ iicstart(); ++ __udelay(delay_data); ++ ++ iicsendbyte((0x1a << 1 ) | 1); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ ++ while(count) ++ { ++ if(count == 1) *buf = iicreceivebyte(0); ++ else *buf = iicreceivebyte(1); ++ count --; ++ buf++; ++ } ++ iicstop(); ++ __udelay(delay_data); ++ return 0; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int count = len; ++ iicstart(); ++ // __udelay(delay_data); ++ ++ iicsendbyte((0x1A << 1) | 0); ++// __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write send address wait ack timeoue \n"); ++ return 1; ++ } ++ ++ while(count--) ++ { ++ iicsendbyte(*(buf++)); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ } ++ ++ iicstop(); ++ __udelay(delay_data); ++ ++ return 0; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if(ret) printk("failed to write cst3xx\n"); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ if(ret) printk("failed to write cst3xx\n"); ++ return ret; ++} ++ ++#elif USE_LOWEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_recv(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_send(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ ++ return ret; ++} ++ ++#elif USE_HIGHEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags |= I2C_M_RD; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++/******************************************************* ++Function: ++ read data from register. ++Input: ++ buf: first two byte is register addr, then read data store into buf ++ len: length of data that to read ++Output: ++ success: number of messages ++ fail: negative errno ++*******************************************************/ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msgs[2]; ++ int ret = -1; ++ int retries = 0; ++ ++ msgs[0].flags = 0; ++ msgs[0].addr = client->addr; ++ msgs[0].len = 2; ++ msgs[0].buf = buf; ++ ++ msgs[1].flags |= I2C_M_RD; ++ msgs[1].addr = client->addr; ++ msgs[1].len = len; ++ msgs[1].buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if(ret == 2) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags = 0; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++#else ++#endif ++/*********************************i2c end********************************/ ++ ++ ++static int cst3xx_i2c_test(struct i2c_client *client) ++{ ++ int retry = 0; ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ while (retry++ < 5) { ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret == 0) ++ return ret; ++ ++ mdelay(2); ++ } ++ ++ if(retry==5) printk(" cst3xx hyn I2C TEST error.ret:%d;\n", ret); ++ ++ return ret; ++} ++ ++ ++static void cst3xx_reset(struct cst3xx_ts_data *ts) { ++ if(gpio_is_valid(ts->pdata->reset_gpio)) { ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(100); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++ mdelay(100); ++ } ++} ++/**************************** basic communication end*******************************/ ++ ++ ++static void cst3xx_touch_report(struct cst3xx_ts_data *ts) ++{ ++ unsigned char buf[30]; ++ unsigned char i2c_buf[8]; ++ unsigned char key_status, key_id = 0, finger_id, sw; ++ unsigned int input_x = 0; ++ unsigned int input_y = 0; ++ unsigned int input_w = 0; ++ unsigned int input_x_delta = 0; ++ unsigned int input_y_delta = 0; ++ unsigned char cnt_up, cnt_down; ++ int i, ret, idx; ++ int cnt, i2c_len; ++ ++ int len_1, len_2; ++ ++ key_status = 0; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(ts->client, buf, 7); ++ if(ret < 0) { ++ printk(" iic read touch point data failed.\n"); ++ goto OUT_PROCESS; ++ } ++ // printk(" read buf : buf[0]: %x ,buf[1]: %x ,buf[2]: %x, buf[3]: %x,buf[4]: %x ,buf[5]: %x ,buf[6]: %x, buf[7]: %x,\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); ++ ++ if(buf[6] != 0xAB) { ++ printk(KERN_INFO " data is not valid..\r\n"); ++ goto OUT_PROCESS; ++ } ++ ++ cnt = buf[5] & 0x7F; ++ if(cnt > 1) goto OUT_PROCESS; ++ else if(cnt==0) goto CLR_POINT; ++ ++ if(cnt == 0x01) { ++ goto FINGER_PROCESS; ++ } ++ ++FINGER_PROCESS: ++ ++ /* ++ * sw: buf[0] low 4 bit ++ * x pos: buf[1] low 4 bit | buf[3] high 4 bit ++ * y pos: buf[2] low 4 bit | buf[3] low 4 bit ++ * z press : buf[4] ++ * finger_id:buf[0] high 4 bit ++ */ ++ i2c_buf[0] = 0xD0; ++ i2c_buf[1] = 0x00; ++ i2c_buf[2] = 0xAB; ++ ++ ret = cst3xx_i2c_write(ts->client, i2c_buf, 3); ++ if(ret < 0) { ++ printk(" cst3xx hyn send read touch info ending failed.\r\n"); ++ cst3xx_reset_ic(ts,20); ++ goto END; ++ } ++ ++ idx = 0; ++ cnt_up = 0; ++ cnt_down = 0; ++ input_x = (unsigned int)((buf[idx + 1] << 4) | ((buf[idx + 3] >> 4) & 0x0F)); ++ input_y = (unsigned int)((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0F)); ++ input_w = (unsigned int)(buf[idx + 4]); ++ sw = (buf[idx] & 0x0F) >> 1; ++ finger_id = (buf[idx] >> 4) & 0x0F; ++ ++ printk(" no handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n", input_x, input_y, input_w,finger_id, sw); ++ ++ input_x=input_x*CST3XX_MAX_X/360; ++ input_y=input_y*CST3XX_MAX_Y/800; ++ ++ if(input_x >= CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++ if(input_y >= CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ ++ input_x = CST3XX_MAX_X-input_x; ++ input_y = CST3XX_MAX_Y-input_y; ++ ++#ifdef 0//HYN_DRAW_POINT ++ if(input_x > 300){ ++ input_x_delta = input_x - (CST3XX_MAX_X/2); ++ input_x = input_x + input_x_delta/((CST3XX_MAX_X/2)/20); ++ if(input_x > CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++ } ++ if(input_x < 40){ ++ input_x_delta = (CST3XX_MAX_X/2) - input_x; ++ input_x = input_x - input_x_delta/((CST3XX_MAX_X/2)/12); ++ if(input_x < 0) input_x = 0; ++ } ++ if(input_y > 760){ ++ input_y_delta = input_y - (CST3XX_MAX_Y/2); ++ input_y = input_y + input_y_delta/((CST3XX_MAX_Y/2)/12); ++ if(input_y > CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ } ++ if(input_y < 40){ ++ input_y_delta = (CST3XX_MAX_Y/2) - input_y; ++ input_y = input_y - input_y_delta/((CST3XX_MAX_Y/2)/25); ++ if(input_y < 0) input_y = 0; ++ } ++#endif ++ ++ printk(" handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n\n", input_x, input_y, input_w,finger_id, sw); ++ ++ if (sw == 0x03 ) { ++ if((input_x > x_temp_pos + ERROR_TOUCH) || (input_x < x_temp_pos -ERROR_TOUCH) || (input_y > y_temp_pos + ERROR_TOUCH) || (input_y < y_temp_pos -ERROR_TOUCH)) ++ { ++ // printk(" REPORT TOUCH DOWM Handle \n"); ++ x_temp_pos = input_x; ++ y_temp_pos = input_y; ++ input_report_key(ts->input_dev, BTN_TOUCH, 1); ++ input_report_abs(ts->input_dev, ABS_X, input_x); ++ input_report_abs(ts->input_dev, ABS_Y, input_y); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 1); ++ input_sync(ts->input_dev); ++ } ++ cnt_down++; ++ } ++ else if(sw == 0) { ++ cnt_up++; ++ } ++ ++ if((cnt_up>0) && (cnt_down==0) ){ ++ // printk(" REPORT TOUCH UP Handle \n"); ++ x_temp_pos = 0; ++ y_temp_pos = 0; ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 0); ++ input_mt_sync(ts->input_dev); ++ } ++ input_sync(ts->input_dev); ++ goto END; ++CLR_POINT: ++ ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_mt_sync(ts->input_dev); ++ input_sync(ts->input_dev); ++ ++OUT_PROCESS: ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ buf[2] = 0xAB; ++ ret = cst3xx_i2c_write(ts->client, buf, 3); ++ if (ret < 0) { ++ printk(" send read touch info ending failed.\n"); ++ cst3xx_reset_ic(ts,20); ++ } ++END: ++ return; ++} ++ ++ ++/******************************* irq handle begin************************************/ ++static void cst3xx_work_handler(struct work_struct *work) ++{ ++ struct cst3xx_ts_data *cst3xx_ts = container_of(work, struct cst3xx_ts_data, work); ++ int ret = 0; ++ /******************here handle touch *******************/ ++ // printk(KERN_INFO "-----------enter cst3xx_work_handler------------\n"); ++ cst3xx_touch_report(cst3xx_ts); ++ enable_irq(cst3xx_ts->irq); ++} ++ ++static irqreturn_t cst3xx_ts_irq_handler(int irq, void *dev_id) ++{ ++ struct cst3xx_ts_data *ts = dev_id; ++ ++ // printk( KERN_INFO "-----------enter cst3xx_ts_irq_handler------------\n"); ++ ++ disable_irq_nosync(ts->irq);//use in interrupt,disable_irq will make dead lock. ++ ++ if (!work_pending(&ts->work)) { ++ queue_work(ts->workqueue, &ts->work); ++ // queue_delayed_work(ts->workqueue,&ts->dwork,1);//10ms * x ++ } else { ++ enable_irq(ts->irq); ++ } ++ ++ return IRQ_HANDLED; ++} ++/******************************* irq handle end************************************/ ++ ++static int cst3xx_ts_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ printk( KERN_INFO "Enter cst3xx_ts_probe -------------------\n"); ++ ++ int ret; ++ struct cst3xx_ts_data *ts; ++ ++ struct cst3xx_platform_data *pdata = (struct cst3xx_platform_data*)client->dev.platform_data; ++ struct input_dev *input_dev; ++ int error; ++ ++#if USE_ANALOG_I2C ++ if (gpio_is_valid(I2CSDA)) ++ { ++ gpio_free(I2CSDA); ++ ret = gpio_request(GPIO_PC(27),"I2C1-SDA"); ++ if(ret < 0){ ++ printk("I2C1-SDA gpio request failed\n"); ++ return ret; ++ } ++ } ++ if (gpio_is_valid(I2CSCL)) ++ { ++ gpio_free(I2CSCL); ++ ret = gpio_request(GPIO_PC(26),"I2C1-SCL"); ++ if(ret < 0){ ++ printk("I2C1-SCL gpio request failed\n"); ++ return ret; ++ } ++ } ++#endif ++ ++ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); ++ if (!ts) ++ return -ENOMEM; ++ input_dev = input_allocate_device(); ++ if(!input_dev) ++ return -ENOMEM; ++ ++ ts->pdata = pdata; ++ ts->client = client; ++ ts->input_dev = input_dev; ++ ++ if(client->addr != 0x1A) //check address ++ { ++ client->addr = 0x1A; ++ printk("Crystal_shen:i2c_client_HYN->addr=%d.\n",client->addr); ++ ++ } ++ ++ if (gpio_is_valid(ts->pdata->int_gpio)) { ++ //error = gpio_request(pdata->int_gpio,"cst3xx gpio irq"); ++ error = gpio_request_one(pdata->int_gpio, GPIOF_IN, "cst3xx gpio irq"); ++ if (error < 0) { ++ dev_err(&client->dev, "Failed to request GPIO %d, error %d\n", ++ pdata->int_gpio, error); ++ return error; ++ } ++ ++ /* if (error < 0) { ++ dev_err(&client->dev, "%s:failed to set gpio irq.\n",__func__); ++ return error; ++ }*/ ++ ts->irq = gpio_to_irq(pdata->int_gpio); ++ printk(" cst3xx ts -> irq = %d.\n",ts->irq); ++ } ++ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) { ++ error = devm_gpio_request(&client->dev, ts->pdata->reset_gpio, NULL); ++ if (error) { ++ dev_err(&client->dev, ++ "Unable to request GPIO pin %d.\n", ++ ts->pdata->reset_gpio); ++ return error; ++ } ++ } ++ cst3xx_reset(ts); ++ printk( KERN_INFO "cst3xx reset -------------------\n"); ++ ret = cst3xx_i2c_test(ts->client); ++ if(ret>=0){ ++ ++ mdelay(100); ++ ++ printk( KERN_INFO "cst3xx test OK -------------------\n"); ++#ifdef HYN_UPDATE_FIRMWARE_ENABLE ++ ret = cst3xx_boot_update_fw(ts,pcst3xx_update_firmware);// ++ if(ret < 0){ ++ printk(" cst3xx hyn_boot_update_fw failed.\n"); ++ return -1; ++ } ++#endif ++ ++ }else{ ++ printk( KERN_INFO "cst3xx hyn i2c communication failed.---------------\n"); ++ return -1; ++ } ++ ++ input_dev->name = "cst3xxx -touchscreen"; ++ input_dev->id.bustype = BUS_I2C; ++ input_dev->dev.parent = &client->dev; ++ ++ set_bit(EV_KEY, input_dev->evbit); ++ set_bit(EV_ABS, input_dev->evbit); ++ set_bit(EV_SYN, input_dev->evbit); ++ set_bit(BTN_TOUCH, input_dev->keybit); ++ ++ set_bit(ABS_X, input_dev->absbit); ++ set_bit(ABS_Y, input_dev->absbit); ++ set_bit(ABS_PRESSURE, input_dev->absbit); ++ ++ ++ input_set_abs_params(input_dev, ABS_X, ts->pdata->x_min, ts->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, ts->pdata->y_min, ts->pdata->y_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0 , 0); ++ ++ /* input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, MAX_AREA, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_POSITION_X, ts->pdata->x_min, ts->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, ts->pdata->y_min, ts->pdata->y_max, 0, 0); ++*/ ++ error = input_register_device(input_dev); ++ if (error) { ++ dev_err(&client->dev, "Unable to register %s input device\n", ++ input_dev->name); ++ return error; ++ } ++ ++ // INIT_DELAYED_WORK(&ts->dwork, cst3xx_work_handler); ++ ++ INIT_WORK(&ts->work, cst3xx_work_handler); ++ ts->workqueue = create_singlethread_workqueue("cst3xx_wq"); ++ ++ error = devm_request_threaded_irq(&client->dev, client->irq, ++ NULL, ++ cst3xx_ts_irq_handler, ++ IRQF_ONESHOT, ++ client->name, ts); ++ if (error) { ++ dev_err(&client->dev, "Failed to register interrupt\n"); ++ return error; ++ } ++ error = request_irq(ts->irq, ++ cst3xx_ts_irq_handler, ++ ts->pdata->irqflags, ++ client->dev.driver->name, ++ ts); ++ if (error < 0) { ++ dev_err(&client->dev, "%s: request irq failed\n",__func__); ++ return error; ++ } ++ printk(KERN_INFO "-----------CST3XX probe end ------------\n"); ++ return 0; ++} ++ ++static int cst3xx_ts_remove(struct i2c_client *client) ++{ ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ free_irq(ts->irq,ts); ++ devm_free_irq(&ts->client->dev, ts->client->irq,ts); ++ destroy_workqueue(ts->workqueue); ++ input_unregister_device(ts->input_dev); ++ devm_gpio_free(&ts->client->dev, ts->pdata->reset_gpio); ++ gpio_free(ts->pdata->int_gpio); ++ ++#if USE_ANALOG_I2C ++ gpio_free(I2CSDA); ++ gpio_free(I2CSCL); ++#endif ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int cst3xx_ts_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ enable_irq_wake(client->irq); ++ } else { ++ disable_irq(client->irq); ++ cst3xx_ts_power(ts, false);//reset ++ } ++ ++ return 0; ++} ++ ++static int cst3xx_ts_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ disable_irq_wake(client->irq); ++ } else { ++ cst3xx_ts_power(ts, true); ++ enable_irq(client->irq); ++ } ++ return 0; ++} ++ ++#endif ++ ++static SIMPLE_DEV_PM_OPS(cst3xx_ts_pm_ops, ++ cst3xx_ts_suspend, cst3xx_ts_resume); ++ ++static const struct i2c_device_id cst3xx_ts_id[] = { ++ { CST3XX_NAME, 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, cst3xx_ts_id); ++ ++ ++#ifdef CONFIG_OF ++static const struct of_device_id cst3xx_ts_dt_ids[] = { ++ { .compatible = "xxxxx,cst3xx", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, cst3xx_ts_dt_ids); ++#endif ++ ++ ++static struct i2c_driver cst3xx_ts_driver = { ++ .probe = cst3xx_ts_probe, ++ .remove = cst3xx_ts_remove, ++ .id_table = cst3xx_ts_id, ++ .driver = { ++ .name = CST3XX_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(cst3xx_ts_dt_ids), ++ .pm = &cst3xx_ts_pm_ops, ++ }, ++}; ++ ++module_i2c_driver(cst3xx_ts_driver); ++ ++ ++MODULE_AUTHOR("Tiben"); ++MODULE_DESCRIPTION("SITRONIX CST3XX Touchscreen Controller Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/cst3xx.h b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/cst3xx.h +new file mode 100644 +index 000000000..68791e6af +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/cst3xx.h +@@ -0,0 +1,29 @@ ++#ifndef TOUCHSCREEN_CST3XX__H ++#define TOUCHSCREEN_CST3XX__H ++ ++ ++/* -- dirver configure -- */ ++#define CFG_MAX_TOUCH_POINTS 1 ++#define MAX_AREA 0xff ++ ++#define CST3XX_NAME "cst3xx" ++ ++/*register address*/ ++#define CST3XX_ADDRESS 0x1A ++ ++ ++/* The platform data for the Focaltech ft5x0x touchscreen driver */ ++struct cst3xx_platform_data { ++ unsigned int x_min; ++ unsigned int y_min; ++ unsigned int x_max; ++ unsigned int y_max; ++ unsigned long irqflags; ++ unsigned int int_gpio; ++ unsigned int reset_gpio; ++}; ++ ++ ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/hyn_cst3xx_RS659_fw.h b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/hyn_cst3xx_RS659_fw.h +new file mode 100644 +index 000000000..006c36c81 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver-ori/hyn_cst3xx_RS659_fw.h +@@ -0,0 +1,1553 @@ ++ ++#ifndef __CST3xx_FW_H__ ++#define __CST3xx_FW_H__ ++ ++ unsigned char cst3_fw[] ={ ++ 0x98,0xE0,0x07,0x01,0xB0,0x88,0x01,0x00,0x00,0x00,0x00,0x00,0xB0,0x48,0x01,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x80,0x68,0x06,0x00,0x80,0x68,0x07,0x00,0x00,0x00,0x00,0x00, ++ 0x88,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0xD8,0x00,0x00,0x80,0x07,0xC0,0x17, ++ 0x82,0x07,0xC0,0x07,0x01,0x65,0x40,0x86,0xC1,0x41,0xC0,0x20,0xC5,0x68,0x31,0x12, ++ 0xF5,0x38,0x33,0x5A,0x32,0xA2,0x32,0xEA,0x10,0x62,0x8D,0x0E,0x81,0x07,0xC0,0x97, ++ 0x30,0xF2,0xF3,0x79,0x65,0x7E,0x30,0xB2,0x31,0x09,0x10,0x9A,0x87,0x06,0xD0,0xD8, ++ 0x35,0x12,0x35,0x5A,0x18,0x9A,0x39,0xC2,0xE0,0xE2,0x03,0x00,0xE0,0xE2,0x04,0x00, ++ 0xD0,0x81,0x98,0x16,0x43,0xC6,0x0B,0xC6,0xC2,0xD6,0x3F,0x90,0x99,0x0E,0x40,0x86, ++ 0x08,0x86,0xA9,0x0E,0x40,0x23,0x00,0x63,0x38,0x82,0x03,0x00,0x18,0x01,0x20,0x01, ++ 0x28,0x01,0x30,0x01,0xD0,0x81,0x98,0x0E,0x0F,0xC6,0xC3,0xDE,0x38,0x90,0x9A,0x06, ++ 0x08,0x86,0xA9,0x06,0x03,0x5B,0x38,0x82,0xAE,0xFD,0x30,0x02,0x30,0x02,0xEE,0xFD, ++ 0xA8,0x85,0xE8,0x85,0x86,0x2F,0xE0,0x1F,0x37,0x8A,0xB8,0xFF,0xF8,0xAF,0x87,0x0F, ++ 0xC0,0xCF,0x85,0x2F,0xE7,0xDF,0xBE,0xFF,0xF8,0x9F,0x87,0x2F,0xE0,0x0F,0x07,0x00, ++ 0xAF,0x85,0x6F,0xD2,0xE1,0x43,0x31,0x4A,0xCA,0x01,0x3E,0x30,0x34,0x42,0x80,0x01, ++ 0xF6,0x1B,0xF4,0x23,0xF3,0x53,0xC2,0x01,0x70,0x01,0xD8,0x16,0xE7,0x6B,0x4D,0x68, ++ 0x80,0x4E,0x28,0x01,0x10,0x6C,0xAE,0x6B,0xA4,0x2B,0x12,0xD2,0x8A,0x16,0xB0,0x63, ++ 0x00,0x09,0xB0,0x43,0xE8,0x85,0x37,0x72,0xEA,0x4B,0xE0,0x48,0x91,0x4D,0xAE,0x8B, ++ 0x57,0xAC,0x7F,0x5A,0x10,0xEA,0x95,0x0E,0xE7,0x68,0x13,0xAC,0x48,0xF9,0x8F,0x0E, ++ 0x10,0x12,0x85,0x16,0xE0,0x0B,0x4A,0x09,0x8B,0x26,0xB0,0x9B,0x09,0x01,0xA8,0x8B, ++ 0xA7,0x0B,0xEA,0x85,0x4F,0x09,0x8C,0xE6,0x0A,0x09,0xA0,0x0B,0xE8,0x85,0xAF,0x85, ++ 0x66,0xF2,0xE6,0x01,0x00,0x0F,0x80,0x0F,0xE1,0xAF,0xF7,0x03,0x47,0x01,0x80,0xD6, ++ 0xEB,0x85,0xA8,0x85,0x70,0xDA,0x2E,0x09,0x1E,0xAB,0x65,0xC2,0xE7,0x03,0x09,0x79, ++ 0x01,0x42,0xA0,0x03,0x00,0x0F,0x80,0x0F,0xE1,0x2F,0xE7,0x03,0x37,0x00,0xAE,0xD6, ++ 0x05,0x01,0x18,0x83,0xE1,0x03,0x19,0x42,0xA3,0x03,0xE9,0x85,0x42,0x7A,0xC6,0x01, ++ 0xE6,0x0B,0x44,0x8A,0x48,0x01,0x80,0x3E,0x4A,0x82,0x06,0x0B,0x0E,0xF9,0x57,0x72, ++ 0x8A,0x89,0x97,0x01,0x10,0x8B,0x00,0x17,0x48,0x62,0xCE,0xE1,0x07,0x0B,0x0A,0xF9, ++ 0x8E,0x21,0x01,0x0B,0x08,0x09,0x08,0x0B,0x08,0x0B,0x0C,0x31,0x08,0x0B,0x0A,0x59, ++ 0x18,0x0B,0x0C,0x81,0x18,0x0B,0x0A,0x01,0x1B,0x0B,0x38,0x82,0xAD,0x85,0x40,0xFA, ++ 0xE6,0x03,0x38,0x00,0x81,0x8E,0x00,0xE1,0x83,0x0F,0xC8,0x0F,0x40,0xDA,0x0D,0x01, ++ 0xC4,0x01,0xA9,0x0B,0xBE,0xFF,0xFF,0x97,0x4D,0xC2,0x55,0xEA,0xCD,0x01,0x46,0xEA, ++ 0x84,0x1F,0xD8,0xCF,0x00,0x01,0x80,0x0F,0xC8,0x77,0xE9,0x85,0xAD,0x85,0x40,0x9A, ++ 0xC6,0x01,0xE9,0x03,0x40,0x01,0x88,0x36,0x46,0x82,0xC5,0x01,0xE0,0x03,0x44,0x29, ++ 0xCF,0x0E,0xB8,0xFF,0xFD,0xE7,0x64,0x6A,0xE0,0x03,0x39,0x00,0xAF,0x0E,0xB8,0xFF, ++ 0xFB,0x07,0xE5,0x03,0x38,0x00,0xAC,0x2E,0x42,0x5A,0xC5,0x01,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0xE7,0x03,0x0B,0xE9,0x03,0x42,0xA0,0x03,0x40,0x52,0xC5,0x03, ++ 0x40,0x01,0x80,0x16,0x83,0x0F,0xE0,0xF7,0x38,0xE7,0xEF,0x85,0xAD,0x85,0x48,0x3A, ++ 0x04,0x01,0x00,0x43,0x4E,0xEA,0xCC,0x01,0xB2,0x43,0xF0,0x43,0x80,0x0F,0xC8,0xFF, ++ 0xEB,0x85,0xA8,0x85,0x30,0x2A,0x20,0x49,0x18,0x22,0x4F,0x01,0x80,0x46,0x68,0x01, ++ 0x80,0x16,0x30,0x82,0xC0,0x61,0x00,0x4F,0x30,0x82,0x80,0x61,0x20,0x51,0x00,0x2F, ++ 0x68,0x01,0x80,0x0E,0xF0,0x80,0x04,0x0F,0xE0,0x80,0x24,0x51,0x0A,0x01,0xF0,0x0A, ++ 0x48,0x01,0xD0,0x06,0x16,0x4A,0x0A,0x40,0x0A,0x01,0xF0,0x8A,0x81,0x2F,0xD8,0xA7, ++ 0x40,0xF9,0xEB,0x06,0x00,0xF9,0x6B,0x01,0x87,0x16,0x08,0xF9,0x88,0x09,0xD0,0x40, ++ 0xCB,0x00,0xE8,0x85,0xAC,0x85,0x6B,0x2A,0xED,0x01,0xE4,0x43,0x41,0x01,0x80,0x26, ++ 0x32,0x62,0xA1,0x01,0x40,0x03,0x41,0x01,0x81,0xFE,0x30,0x0A,0xCC,0x01,0x44,0x2A, ++ 0x81,0x17,0xC8,0x3F,0x0F,0x01,0x40,0xF9,0x8D,0xC6,0xF0,0x03,0xE3,0x01,0xB4,0x03, ++ 0x11,0x11,0x30,0x02,0x82,0x01,0xA1,0x13,0xA8,0x0B,0x01,0x01,0x12,0x79,0x28,0x29, ++ 0x5B,0xE2,0x0B,0x68,0xF8,0x23,0x03,0x37,0x0A,0x21,0x19,0x0A,0xC2,0x48,0xCE,0x48, ++ 0x92,0x53,0xE0,0x00,0x94,0x05,0x16,0x22,0xC3,0xB6,0xEF,0x85,0x47,0xF1,0x87,0xE6, ++ 0x47,0x01,0x80,0xD6,0xF0,0x00,0x12,0x09,0x44,0x1B,0x01,0x12,0x17,0x9A,0x80,0xA6, ++ 0xA3,0x4B,0xED,0x85,0xAB,0x85,0x51,0x92,0x28,0x01,0x20,0x01,0x08,0x01,0x00,0x01, ++ 0xC4,0x9B,0x10,0x5A,0xC8,0x06,0x30,0xCA,0x58,0xD1,0x9F,0x0E,0x28,0x09,0x00,0x27, ++ 0xE2,0x90,0xE2,0x00,0x90,0x05,0x46,0x31,0x99,0x96,0x4F,0xE1,0x92,0x5E,0x40,0xFA, ++ 0xC4,0x01,0xE6,0x03,0x40,0x29,0xC8,0x36,0x41,0x12,0x0B,0x81,0xF3,0x0A,0x4A,0xC1, ++ 0xD8,0x0E,0x28,0x09,0x03,0x1F,0xE0,0x20,0x90,0x25,0x67,0x71,0x98,0xF6,0x16,0x01, ++ 0x48,0x02,0x6B,0x01,0x82,0x7E,0x40,0x44,0xE4,0x00,0x92,0x05,0x00,0x44,0x42,0xA1, ++ 0xCC,0x46,0x40,0x44,0xE4,0x00,0x02,0x44,0x02,0x54,0x42,0x82,0x10,0x09,0xE0,0x0B, ++ 0x18,0x8A,0xA0,0x0B,0xEA,0x85,0x01,0x54,0xEF,0x85,0xA9,0x85,0x80,0x3D,0x04,0x01, ++ 0x80,0x14,0x80,0x1C,0x00,0x01,0x08,0x01,0x10,0x01,0x90,0x0C,0xD2,0x1C,0x58,0x6A, ++ 0x06,0x90,0x32,0x09,0xC5,0x90,0x06,0xB0,0xC9,0xA0,0x34,0x2A,0x18,0x01,0x10,0x01, ++ 0xF0,0x12,0xC5,0x80,0x92,0x05,0xE0,0x48,0x90,0x4D,0xF8,0x0C,0x10,0xD2,0xED,0x06, ++ 0x90,0x0C,0xA0,0x61,0xE6,0xD8,0x92,0xDD,0x5F,0x71,0x98,0x86,0x84,0x2F,0xD0,0xA7, ++ 0x90,0x25,0xC0,0x14,0x10,0x02,0xD5,0x06,0xA0,0x14,0x38,0x01,0x60,0x01,0xE8,0xAE, ++ 0x35,0x01,0xF8,0x72,0x10,0x32,0xDD,0x66,0xC6,0x0C,0x78,0x08,0xC2,0x40,0x80,0x00, ++ 0x10,0x32,0xD4,0x8E,0x09,0x19,0x30,0x82,0x83,0x2F,0xD0,0xF7,0xD1,0x80,0x01,0x44, ++ 0x00,0x57,0x70,0x01,0xE8,0x46,0x00,0x09,0x00,0x44,0x01,0x2F,0x01,0x01,0xF0,0x42, ++ 0x10,0x02,0xE5,0x0E,0xD9,0x00,0x00,0x44,0xAB,0x61,0xE0,0xF8,0x90,0xFD,0x7F,0x71, ++ 0x98,0xE6,0xC6,0x1C,0xE6,0x00,0x92,0x05,0x80,0x1C,0xC0,0x1C,0x45,0x31,0x98,0x8E, ++ 0x00,0x01,0x80,0x24,0x00,0x01,0x08,0x01,0x38,0x01,0xD0,0x24,0x1A,0x61,0x18,0xD2, ++ 0x5E,0x22,0xC1,0x98,0x14,0x09,0x06,0x90,0xC0,0xD0,0x34,0xA2,0x18,0x01,0x30,0x01, ++ 0xF9,0xB2,0xC4,0x80,0x92,0x05,0xE0,0x48,0x95,0x4D,0x10,0xF2,0xE9,0x06,0x30,0xBA, ++ 0xE2,0x90,0xE4,0xD8,0x90,0xDD,0x5E,0x31,0x98,0x8E,0x87,0x2F,0xD0,0x2F,0x92,0x2D, ++ 0xC5,0x14,0x10,0x42,0xD0,0x06,0xA8,0x14,0x30,0x01,0x68,0x01,0xE8,0xA6,0x01,0x01, ++ 0xF0,0x02,0x81,0x34,0x10,0x42,0xDD,0x9E,0x09,0x19,0x30,0x42,0x81,0x2F,0xD0,0xA7, ++ 0xC8,0x34,0xD0,0x40,0x91,0x05,0x00,0x04,0x83,0x2C,0xD8,0xC0,0x41,0x41,0xD1,0x4E, ++ 0x00,0x40,0x0B,0x19,0x81,0x2F,0xD0,0x47,0xC8,0x2C,0xD0,0x40,0x01,0x04,0x01,0x0F, ++ 0xC0,0x34,0x40,0x01,0xE8,0xF6,0x00,0x09,0x00,0x04,0x01,0xDF,0x00,0xC0,0x06,0x01, ++ 0x50,0x07,0x03,0x00,0x18,0x00,0x02,0x42,0x00,0x01,0x00,0x42,0x80,0x60,0x05,0x00, ++ 0x58,0xC0,0x02,0x01,0x00,0xA0,0x07,0x01,0x00,0x80,0x00,0x01,0x10,0x00,0x00,0x42, ++ 0x10,0xC0,0x00,0x01,0x00,0x00,0x00,0x01,0x01,0x01,0xF0,0x02,0x10,0x42,0xE5,0x0E, ++ 0xD9,0x00,0x02,0x04,0xE3,0x20,0xE5,0xB0,0x90,0xB5,0x77,0x31,0x98,0xEE,0xC5,0x24, ++ 0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x44,0x71,0x98,0x9E,0xC5,0x14,0x50,0xD2, ++ 0x40,0xE1,0xD1,0x26,0x7A,0x40,0xCF,0x00,0x82,0x00,0x82,0x83,0x00,0x0F,0x00,0xF1, ++ 0x82,0x83,0xC2,0x8B,0x40,0xAA,0x4D,0x01,0x82,0x4E,0xF0,0x48,0x81,0x8B,0x8A,0x41, ++ 0x32,0x12,0xD0,0x01,0x88,0x8B,0x08,0x31,0x98,0x0B,0x86,0x3D,0xE8,0x85,0x0F,0x11, ++ 0x9F,0x0B,0x3E,0xD7,0xAD,0x85,0x47,0x6A,0x72,0x6A,0xC5,0x01,0xF1,0x2B,0x04,0x09, ++ 0x09,0x00,0xC4,0xA0,0x69,0x09,0xC8,0x66,0x1F,0x01,0x10,0xF9,0x02,0x01,0x38,0x19, ++ 0x08,0xF8,0x03,0x57,0x0A,0x31,0x18,0x0A,0xCE,0x48,0xCC,0x48,0x54,0x4C,0x10,0xCA, ++ 0xC8,0x0E,0x30,0x5A,0x32,0x12,0xE0,0x00,0x94,0x05,0x16,0x2A,0xC7,0x96,0x57,0xF9, ++ 0x82,0xBE,0x00,0x80,0xC9,0x08,0x04,0x09,0x08,0x00,0xC4,0x40,0xF1,0x0B,0xB0,0x0B, ++ 0xF3,0x03,0xB2,0x03,0x02,0x31,0x18,0x12,0xCE,0x80,0xCC,0x00,0x4C,0xCA,0x4C,0x14, ++ 0x0E,0x54,0x4C,0x14,0x08,0x54,0x56,0x04,0x14,0x44,0x48,0xA2,0x02,0x09,0xC8,0x01, ++ 0xB4,0x43,0x44,0x92,0x3A,0x01,0xC0,0x01,0xF4,0x03,0x6C,0x7A,0x41,0x01,0x80,0x8E, ++ 0xF3,0x03,0xF1,0x13,0x48,0x5C,0x0B,0x61,0x19,0xCA,0x4A,0x64,0xCB,0x48,0x04,0x30, ++ 0xC8,0x48,0x34,0x19,0x14,0xB0,0xC9,0x70,0x0B,0x21,0xF0,0x8A,0x48,0x81,0xDA,0x06, ++ 0x00,0x7C,0x47,0x01,0x80,0x0E,0x40,0x29,0x8D,0xCE,0x10,0x02,0x8C,0xBE,0x10,0xD2, ++ 0x88,0xAE,0x18,0x61,0xF6,0x5A,0xD7,0x58,0x98,0x49,0x58,0x91,0xC7,0x7E,0x40,0x5C, ++ 0x65,0x0A,0x14,0x1A,0x92,0x0E,0xE0,0xD8,0x07,0x5C,0x47,0x5C,0x58,0x41,0xCE,0x36, ++ 0x03,0x7C,0x5F,0xD2,0x34,0x09,0x98,0x01,0xE1,0xE3,0x18,0xA2,0xA1,0xE3,0x08,0x44, ++ 0x0D,0x54,0x0B,0x4C,0x42,0xAA,0xC3,0x01,0x51,0x04,0x46,0x91,0xCF,0x06,0x00,0x7C, ++ 0xEF,0x85,0xAF,0x85,0x80,0x3D,0x2C,0x01,0x20,0x01,0x00,0x61,0x4B,0x82,0x1B,0x42, ++ 0xC0,0x00,0x82,0x34,0x30,0x01,0x38,0x01,0x00,0x01,0x80,0x1C,0x80,0x14,0xC0,0x34, ++ 0x00,0x08,0x13,0x19,0xC0,0x00,0x12,0x90,0xC0,0x10,0x04,0x21,0x90,0x2C,0xF0,0x82, ++ 0x80,0x24,0x60,0x01,0x83,0x46,0xF0,0x10,0xDA,0x34,0x00,0x90,0xC0,0xD0,0x1C,0x19, ++ 0x16,0xD8,0xC0,0x90,0x34,0x21,0xF8,0xB2,0x68,0x01,0x80,0x56,0xF0,0x50,0x1B,0x61, ++ 0x1A,0xD2,0x5A,0xFA,0xC0,0x90,0x1E,0x19,0xC0,0x90,0x12,0xD8,0xC0,0x90,0x3E,0x21, ++ 0xF8,0xBA,0x66,0x29,0x83,0x4E,0xE0,0x18,0xD2,0x34,0x00,0xD8,0xC0,0x90,0x1E,0x19, ++ 0x16,0xD8,0xC0,0x90,0x1E,0x21,0xF0,0x9A,0x98,0x1C,0x68,0x69,0x83,0x5E,0xE0,0x50, ++ 0x1A,0x61,0x18,0xD2,0x5E,0x92,0xC2,0x90,0xC0,0x88,0x12,0x19,0x14,0x90,0xC0,0x50, ++ 0x0A,0x21,0xF0,0x8A,0x88,0x14,0x08,0x09,0x89,0x0C,0x70,0x41,0xD1,0x3E,0x78,0x41, ++ 0xD0,0x2E,0xC8,0x1C,0x48,0x41,0xD1,0x16,0xC9,0x14,0x48,0x41,0xD8,0x0E,0x08,0x01, ++ 0x88,0x0C,0x08,0x19,0x80,0x2F,0xC8,0x47,0x10,0x82,0xED,0x3E,0x10,0xC2,0xED,0x2E, ++ 0xCC,0x1C,0x10,0x42,0xE8,0x16,0xC8,0x14,0x10,0x42,0xE4,0x0E,0x00,0x01,0x80,0x0C, ++ 0xC0,0x0C,0x40,0x01,0x80,0x36,0xC0,0x24,0x78,0x08,0xC6,0x48,0x82,0x48,0xD2,0x00, ++ 0xCC,0x2C,0x00,0x44,0xE7,0x20,0x93,0x25,0x64,0x31,0x98,0x9E,0xE7,0x68,0x93,0x6D, ++ 0x6C,0x71,0x98,0x4E,0x3B,0x4F,0xA8,0x85,0x48,0x9A,0x01,0x01,0x06,0x44,0x04,0x44, ++ 0x82,0x43,0x80,0x43,0x40,0x8A,0x29,0x09,0x80,0x01,0xE4,0x0B,0x18,0x4A,0xA1,0x0B, ++ 0x31,0x22,0xE0,0x01,0x07,0x9F,0xBA,0xFF,0xE9,0xCF,0x43,0x82,0xC0,0x03,0x40,0x01, ++ 0x81,0x1E,0x48,0x52,0x02,0xC1,0xC8,0x01,0xB1,0x43,0x40,0x42,0x51,0x62,0x49,0x42, ++ 0xC0,0x01,0x82,0x1F,0xF7,0x0F,0xBD,0xFF,0xE9,0x4F,0x49,0x22,0x52,0x42,0xC9,0x01, ++ 0x40,0x1A,0x81,0x27,0xC1,0x17,0x4C,0x0A,0x52,0x2A,0xC9,0x01,0x40,0x02,0x81,0x27, ++ 0xFF,0x0F,0xBC,0xFF,0xEF,0x3F,0xEE,0x03,0x40,0x01,0x80,0x16,0xE8,0x03,0x47,0x11, ++ 0x89,0x1E,0x40,0x02,0x41,0x0B,0x18,0x4A,0x00,0x0B,0x40,0xC2,0x0E,0x11,0x98,0x0B, ++ 0x32,0x0A,0xC8,0x01,0x40,0xB2,0x80,0x27,0xE8,0xC7,0x4D,0xA2,0x42,0xA2,0xC8,0x01, ++ 0x86,0x27,0xE0,0x7F,0xBF,0xFF,0xEF,0x4F,0xB9,0xFF,0xFF,0xDF,0x48,0x7A,0x40,0x82, ++ 0xC8,0x01,0x82,0x27,0xE0,0xF7,0x4A,0x6A,0x12,0x01,0xC8,0x01,0x40,0x62,0x58,0x92, ++ 0x85,0x17,0xE8,0x57,0xBD,0xFF,0xF7,0xB7,0xBB,0xFF,0xE7,0xD7,0x48,0x3A,0x40,0x42, ++ 0xC8,0x01,0x82,0x0F,0xF0,0x6F,0x80,0x07,0xDF,0x47,0xB8,0xFF,0xE7,0xFF,0xEF,0x03, ++ 0x45,0x31,0x88,0x46,0xE8,0x85,0x03,0x00,0x00,0x00,0x00,0x01,0x00,0xC0,0x02,0x01, ++ 0x00,0xA0,0x07,0x01,0x48,0xA0,0x02,0x01,0x38,0x81,0x00,0x00,0x00,0x80,0x00,0x01, ++ 0x58,0xC0,0x02,0x01,0xF8,0x00,0x06,0x42,0x18,0xD8,0x05,0x00,0xA8,0x85,0x33,0x22, ++ 0xF0,0x03,0x83,0x07,0xF1,0xA7,0x41,0x9A,0x2C,0x01,0x00,0x2B,0xB5,0x2B,0x01,0xB1, ++ 0xAF,0x2A,0xB8,0xFF,0xE4,0x1F,0xA5,0x01,0xFA,0x03,0x31,0x08,0x42,0x72,0x71,0x48, ++ 0x1C,0x0B,0x5C,0x0B,0x02,0x48,0x1A,0x0B,0x09,0x2B,0xFE,0x0B,0x30,0x48,0xA8,0x16, ++ 0x0E,0x09,0x04,0x0B,0x1B,0x2B,0xE8,0x85,0xAD,0x85,0x87,0x9D,0x42,0x32,0xC1,0x01, ++ 0x42,0x0B,0x40,0x48,0x00,0x48,0x02,0x0B,0x51,0x22,0x49,0x2A,0x40,0x2A,0x81,0x0F, ++ 0xC1,0x97,0x67,0x1A,0x35,0x2A,0xA9,0x01,0x01,0xBF,0x41,0x0A,0xBE,0xFF,0xFF,0x77, ++ 0x52,0x03,0x81,0x01,0xE7,0x03,0x40,0x79,0x80,0x0E,0x51,0xEA,0x48,0xEA,0x00,0x01, ++ 0x58,0xD2,0x80,0x07,0xF8,0x2F,0x51,0xD2,0x48,0xD2,0x00,0x09,0x58,0xBA,0x80,0x07, ++ 0xF9,0xFF,0x50,0x03,0x80,0x01,0xE2,0x03,0x40,0x59,0x8D,0x86,0x40,0xB2,0x48,0xAA, ++ 0x88,0xA1,0x11,0x01,0xD5,0x3B,0xD7,0x1B,0x18,0xFA,0x42,0x5C,0x44,0x34,0xD8,0xD8, ++ 0x04,0x1C,0xE0,0x00,0xE2,0x48,0xE4,0x90,0x95,0x95,0x14,0xD2,0x99,0xAE,0x57,0x03, ++ 0x80,0x01,0xE2,0x03,0x40,0x59,0x85,0x2E,0x50,0x42,0x48,0x4A,0x40,0x4A,0x58,0x0D, ++ 0x80,0x0F,0xC0,0xBF,0x40,0x0D,0x80,0x07,0xDF,0xFF,0xE9,0x43,0x46,0x31,0x80,0x26, ++ 0x87,0x9D,0xE9,0x85,0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x58,0xC0,0x02,0x01, ++ 0x00,0xC0,0x00,0x01,0x00,0xA0,0x07,0x01,0x18,0xC0,0x07,0x01,0x4C,0xFA,0x6F,0x54, ++ 0x82,0x13,0x68,0x54,0x80,0x13,0x32,0x52,0x92,0x01,0xF5,0x93,0x80,0x13,0xCC,0x4B, ++ 0x83,0x0B,0x3E,0x82,0xA8,0x85,0xF3,0x24,0x63,0xC2,0xFF,0x23,0x11,0x22,0xCC,0x56, ++ 0x23,0x21,0x19,0x02,0x60,0xB2,0xCF,0x00,0x23,0x29,0x0A,0x20,0xCE,0x00,0x50,0x24, ++ 0x58,0x2C,0x48,0x09,0x8E,0x26,0x50,0x0C,0x23,0xF9,0xA7,0x49,0xD4,0x08,0x93,0x65, ++ 0x50,0x09,0x88,0x26,0x58,0x0C,0x10,0xC9,0x0A,0x90,0xD2,0x88,0x90,0x6D,0xD4,0x0B, ++ 0xD0,0x13,0x0A,0x48,0x00,0x90,0x1A,0x8A,0x81,0xCB,0x48,0x08,0x81,0xCB,0x4A,0x48, ++ 0x81,0xCB,0x0C,0x08,0x38,0x50,0x79,0x90,0x1E,0x8A,0x80,0xCB,0x58,0x04,0x8A,0xC3, ++ 0xC2,0x83,0xE9,0x00,0x83,0x83,0xE9,0x85,0xAC,0x85,0x87,0x2D,0x0F,0x01,0x00,0x0D, ++ 0x40,0x2E,0x90,0x24,0x86,0x1C,0x40,0xEA,0xFA,0x2B,0xF8,0x1B,0x06,0x01,0x60,0xFA, ++ 0x51,0xFA,0xC6,0x33,0x70,0x59,0x85,0x1E,0xE4,0x00,0x92,0x05,0x17,0x82,0x9C,0xC6, ++ 0x50,0xE2,0x46,0x83,0x31,0x09,0x18,0x82,0x07,0x83,0x00,0xF9,0x80,0x03,0x69,0x01, ++ 0x80,0xBE,0x08,0x01,0x50,0x1D,0x00,0x01,0x2E,0x29,0x62,0x8A,0x08,0x68,0x03,0x77, ++ 0x32,0x21,0x19,0x32,0xCB,0xB0,0xC9,0xB0,0xD0,0xB3,0x75,0x09,0x88,0x2E,0x80,0x83, ++ 0xE6,0x48,0x92,0x4D,0xE0,0x90,0x4A,0x29,0x82,0x1E,0xE0,0x00,0x94,0x05,0x16,0xC2, ++ 0x98,0x76,0x8F,0x0C,0x60,0x4A,0x6E,0x1D,0x36,0x01,0x78,0x22,0xB9,0x01,0x06,0x0F, ++ 0x70,0x01,0x88,0x9E,0x50,0x15,0x90,0x04,0x11,0x01,0xC0,0x43,0x30,0x1A,0x31,0x8A, ++ 0xBC,0xFF,0xFF,0x47,0xE5,0x68,0xE3,0xC3,0xCE,0x0C,0x48,0x00,0x08,0x00,0x1E,0x42, ++ 0x8D,0x03,0x03,0x59,0x8D,0x03,0xED,0x20,0xE0,0x20,0x03,0x4F,0x50,0x15,0x90,0x04, ++ 0x11,0x01,0xC0,0x43,0x30,0x1A,0x31,0x8A,0xBB,0xFF,0xFF,0xA7,0xE3,0x68,0xEB,0x20, ++ 0xE7,0xB0,0x93,0xB5,0xC4,0x0C,0x10,0x32,0x9D,0xD6,0xE6,0xC3,0x1E,0x01,0x4C,0x08, ++ 0x48,0x01,0x80,0x96,0xC8,0x0C,0x48,0x01,0x81,0x36,0x80,0x03,0xEB,0xC3,0x81,0x03, ++ 0x05,0x59,0x85,0x03,0xE0,0x20,0x05,0x37,0x81,0x03,0xE9,0xC3,0x83,0x03,0x8B,0x1B, ++ 0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x2F,0xC0,0x0C,0x40,0x09,0xC8,0x16, ++ 0x01,0x59,0x85,0x03,0xE1,0x20,0x33,0x02,0xBA,0xFF,0xFF,0x07,0x4A,0x32,0x45,0x43, ++ 0x10,0x01,0x1A,0x82,0x05,0x43,0x4A,0x2A,0x40,0x43,0x1A,0xC2,0x03,0x43,0xE2,0xC3, ++ 0x08,0x11,0x18,0x42,0xA0,0xC3,0x83,0x2D,0xEF,0x85,0xAF,0xFD,0x80,0x0D,0xFC,0x54, ++ 0x30,0x32,0x30,0x62,0x6E,0xAA,0xAC,0x01,0x50,0x09,0x88,0x4E,0x00,0x0F,0x80,0x0F, ++ 0xC1,0xCF,0xE1,0x43,0x37,0x00,0xAA,0xD6,0xE5,0x43,0x09,0xF9,0x01,0x42,0xA0,0x43, ++ 0x04,0x09,0x30,0x22,0x51,0xAA,0x04,0x8F,0x60,0x01,0xC1,0x2E,0xF7,0x00,0x0B,0x01, ++ 0x1A,0x42,0x08,0x83,0x30,0x0A,0x01,0x17,0x02,0xF9,0x0F,0x83,0x08,0x01,0x19,0x01, ++ 0x08,0x9B,0x04,0x01,0x00,0x4F,0x78,0x01,0x88,0x16,0x18,0x01,0x00,0x9B,0x06,0x17, ++ 0xC6,0x9B,0x01,0x9B,0xCA,0xB0,0xE7,0x00,0x94,0x05,0x14,0x42,0x9B,0x9E,0x37,0x02, ++ 0x40,0x01,0x80,0x26,0x04,0xA1,0x00,0x83,0x04,0x01,0x30,0x22,0x00,0x0F,0x00,0x21, ++ 0x03,0x83,0xD4,0x00,0x92,0x25,0x44,0x83,0x08,0x01,0x1C,0x42,0x01,0x83,0xE2,0x43, ++ 0x37,0x00,0xAA,0xE6,0xE5,0x43,0x09,0xF9,0x01,0x42,0xA0,0x43,0x66,0x01,0x88,0x5E, ++ 0xC0,0x24,0x40,0x09,0x88,0x7E,0x05,0x01,0x02,0x83,0x44,0x83,0x08,0x01,0x1C,0x42, ++ 0x05,0x83,0x3A,0x47,0xAC,0x9D,0x87,0x1D,0x20,0x01,0x00,0x01,0x80,0x0C,0x70,0x15, ++ 0x40,0x52,0xF3,0x03,0xEE,0x00,0x92,0x3D,0x6E,0x42,0xAB,0x01,0x00,0xAF,0x81,0x07, ++ 0xF9,0x0F,0xE7,0x43,0x30,0x00,0xA2,0x1E,0x40,0x22,0xF3,0x03,0x17,0xC2,0x9D,0xB6, ++ 0x40,0x12,0xF3,0x03,0x10,0xC2,0x9D,0x06,0x21,0x11,0xE0,0x43,0x08,0xF9,0x05,0x42, ++ 0xA3,0x43,0x41,0x32,0x46,0x0B,0x14,0x79,0x00,0x8A,0x48,0x09,0x88,0x9E,0x08,0x01, ++ 0x0E,0x0B,0x44,0x0B,0x83,0x8B,0xE1,0xB0,0xE7,0x20,0x93,0x25,0x60,0x11,0x88,0x56, ++ 0x30,0x5A,0xD3,0xCB,0xD4,0x1C,0x10,0x8A,0x8A,0x2E,0xD0,0xCB,0xD4,0x24,0x10,0x8A, ++ 0x88,0x0E,0x08,0x09,0x8F,0x0C,0x08,0x01,0x08,0x0B,0x0A,0x01,0x08,0x0B,0x0C,0x81, ++ 0x02,0x0B,0x44,0x0B,0x10,0x01,0x1C,0x8A,0x00,0x0B,0x62,0x11,0x88,0x4E,0xC6,0x0C, ++ 0x3A,0x0F,0x4B,0x52,0x58,0x54,0x86,0x13,0x12,0x01,0x80,0x13,0xE4,0x4B,0x82,0x0B, ++ 0x4A,0x62,0x8A,0x01,0x5E,0x53,0x84,0x13,0x58,0x53,0x8A,0x13,0x12,0x91,0x88,0x13, ++ 0x14,0x19,0x88,0x13,0x4E,0x53,0x8E,0x13,0x48,0x53,0x94,0x13,0x4A,0x4B,0x92,0x0B, ++ 0x0C,0x09,0x90,0x0B,0x3F,0x82,0xAB,0x85,0x80,0x4D,0x34,0x22,0x30,0x01,0x00,0x01, ++ 0x80,0x2C,0x38,0x01,0x4C,0xCA,0xD1,0x43,0xD2,0x4B,0x1E,0x42,0x81,0x14,0x40,0xC2, ++ 0x80,0x61,0x80,0x24,0xC0,0x61,0x80,0x1C,0x60,0x09,0x80,0x0E,0x60,0x29,0x88,0x76, ++ 0x60,0x09,0x88,0x1E,0x70,0xD2,0xB1,0x2C,0x78,0xD2,0x01,0x27,0x73,0xD2,0xE1,0x80, ++ 0x81,0x2C,0x78,0xC2,0xF8,0x81,0x41,0x35,0xBA,0xFF,0xF7,0xC7,0x00,0x3F,0x60,0x21, ++ 0x89,0x2E,0x70,0xB2,0x47,0x35,0xB8,0xFF,0xF9,0xE7,0x7D,0x92,0xB9,0xA1,0x6A,0x3A, ++ 0xA9,0x01,0xE6,0x43,0x08,0xF9,0x05,0x42,0xA1,0x43,0xE1,0x43,0x08,0x01,0x19,0x42, ++ 0xA1,0x43,0x41,0x4A,0x42,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x4A,0x3A,0x41,0x43, ++ 0x10,0x01,0x1C,0x82,0x01,0x43,0x4A,0x1A,0x40,0x43,0x10,0x09,0x18,0x82,0x00,0x43, ++ 0x0C,0x09,0x00,0x01,0xBA,0xFF,0xFF,0xB7,0x42,0x09,0x88,0x66,0x62,0x21,0x88,0x5E, ++ 0x10,0x09,0x90,0x04,0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF,0xF0,0xB7,0x17,0x09, ++ 0x90,0x04,0x10,0x01,0x08,0x59,0x40,0x35,0x37,0x9A,0xB8,0xFF,0xF0,0x77,0x17,0x09, ++ 0x90,0x04,0x10,0x01,0x09,0x31,0x30,0xC2,0x37,0x9A,0xB8,0xFF,0xF0,0x37,0x17,0x09, ++ 0x90,0x04,0x40,0xA2,0x10,0x01,0x08,0x71,0xC0,0x21,0x32,0x9A,0xBE,0xFF,0xF7,0xEF, ++ 0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x30,0x9A,0xC0,0x24,0xBE,0xFF,0xF7,0xAF, ++ 0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x18,0x09,0x00,0xCF,0x00,0xC0,0x00,0x01, ++ 0x00,0xA0,0x07,0x01,0xFF,0xFF,0xFF,0xFF,0x00,0xF8,0x07,0x00,0x58,0x20,0x00,0x01, ++ 0x90,0xE4,0x03,0x00,0xF8,0x00,0x06,0x42,0x00,0x00,0x06,0x42,0x80,0x01,0x06,0x42, ++ 0x10,0xC0,0x00,0x01,0x40,0x60,0x07,0x01,0x18,0xC0,0x07,0x01,0x38,0xC0,0x05,0x01, ++ 0xC7,0x1C,0xB8,0xFF,0xF2,0x97,0x05,0x27,0x60,0x09,0x80,0x0E,0x62,0x29,0x88,0x06, ++ 0x60,0x09,0x88,0x76,0x10,0x09,0x90,0x04,0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF, ++ 0xF0,0x27,0x15,0x01,0x90,0x04,0x30,0x9A,0xC8,0x14,0xC0,0x2C,0xBC,0xFF,0xF7,0xEF, ++ 0x00,0x7F,0x10,0x11,0x90,0x04,0x10,0x09,0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF, ++ 0xF0,0xA7,0x14,0x11,0x90,0x04,0x10,0x01,0x30,0x9A,0xC8,0x14,0xC7,0x2C,0xB8,0xFF, ++ 0xF0,0x67,0x14,0x09,0x90,0x04,0x10,0x01,0x08,0x21,0x40,0x35,0x37,0x9A,0xB8,0xFF, ++ 0xF0,0x27,0x14,0x09,0x90,0x04,0x10,0x01,0x09,0x41,0x31,0xC2,0x37,0x9A,0xB8,0xFF, ++ 0xF0,0xE7,0x13,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x30,0x9A,0xC7,0x24,0xB8,0xFF, ++ 0xF0,0xA7,0x13,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x18,0x09,0xC7,0x1C,0xB8,0xFF, ++ 0xF1,0x67,0xE3,0x43,0x08,0xF9,0x06,0x42,0xA5,0x43,0x41,0x32,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x47,0x22,0x0D,0x01,0x08,0x0B,0x0A,0x01,0x02,0x0B,0x44,0x0B, ++ 0x10,0x01,0x1C,0x8A,0x00,0x0B,0x82,0x4D,0xEB,0x85,0xAF,0x85,0x67,0xFA,0xEC,0x03, ++ 0x28,0x01,0x40,0x09,0x87,0x16,0xE8,0x03,0x40,0x29,0x88,0x5E,0x71,0xE2,0xC4,0x83, ++ 0x40,0x11,0x98,0x26,0xEF,0x03,0xBF,0xFF,0xF1,0xF7,0x87,0xAB,0xEA,0x85,0xE3,0x00, ++ 0x83,0x83,0xE9,0x85,0xE8,0x03,0x47,0x21,0x8F,0x26,0xB8,0xFF,0xF0,0xA7,0x07,0x19, ++ 0xAB,0x03,0xEF,0x85,0xE8,0x03,0x47,0x19,0x87,0xDE,0xEF,0x03,0x47,0x31,0x80,0xC6, ++ 0x4D,0x72,0xCC,0x01,0xF8,0x43,0x40,0x01,0x88,0x3E,0x30,0x42,0x80,0x01,0xF6,0x13, ++ 0x50,0x31,0x98,0x3E,0xE0,0x03,0x34,0x00,0xAC,0x26,0x40,0x42,0xC4,0x01,0xE3,0x03, ++ 0x40,0x01,0x80,0xA6,0xE8,0x03,0x47,0x01,0x8E,0x1E,0x57,0x44,0x47,0x31,0x88,0x06, ++ 0x45,0x22,0x0C,0x59,0x82,0x0B,0x80,0x2B,0x86,0x2B,0x84,0x2B,0x8A,0x2B,0x88,0x2B, ++ 0x8B,0x0B,0x44,0xE2,0x42,0x0B,0x40,0x48,0x00,0x48,0x02,0x0B,0xEF,0x85,0xBB,0xFF, ++ 0xEB,0xDF,0xEB,0x85,0xA8,0xC5,0x27,0x01,0x30,0x1A,0x00,0x09,0x4B,0xBA,0x6B,0xD2, ++ 0x30,0x01,0x59,0x51,0x80,0xE6,0xE1,0x4E,0x79,0xC2,0xE3,0xD3,0x87,0x27,0xE8,0xDF, ++ 0x61,0x52,0x20,0x09,0x39,0x61,0x62,0x52,0x71,0x61,0x62,0x92,0x40,0x7A,0x13,0x31, ++ 0xC0,0x01,0x55,0x03,0x80,0x01,0x5A,0xC9,0x80,0xAE,0xE1,0x4E,0x59,0x59,0x80,0x56, ++ 0x59,0x61,0x80,0x66,0x59,0x69,0x88,0xBE,0x06,0x29,0xA8,0x43,0x21,0x09,0x00,0x9F, ++ 0x59,0xD1,0x80,0x6E,0x59,0x01,0x89,0x7E,0xA8,0x53,0x26,0x09,0x08,0x59,0xA5,0x0B, ++ 0x00,0x57,0x01,0x39,0xA9,0x43,0x06,0x3F,0x86,0x07,0xE8,0xF7,0x00,0x27,0x19,0x12, ++ 0xA1,0xD3,0x01,0x0F,0x00,0x41,0x18,0x12,0xA0,0xD3,0x01,0xEF,0x06,0x11,0xA8,0x43, ++ 0x20,0x09,0x00,0xCF,0x06,0x01,0xA8,0x43,0x41,0x43,0x19,0x82,0x00,0x43,0x01,0x9F, ++ 0xA8,0x43,0x26,0x09,0x00,0x87,0x00,0x19,0xA8,0x43,0x26,0x09,0x00,0x67,0x00,0x21, ++ 0xA8,0x43,0x26,0x09,0x06,0x47,0xA8,0x53,0x26,0x09,0x08,0x69,0xA0,0x0B,0x00,0x1F, ++ 0xA8,0x53,0x26,0x09,0x08,0x79,0xA7,0x0B,0x60,0x01,0x80,0x66,0x40,0x82,0x42,0x0B, ++ 0x30,0x48,0xA8,0x2E,0x08,0x81,0x06,0x0B,0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B, ++ 0x45,0x43,0x19,0x82,0x07,0x43,0xE9,0xC5,0xAC,0x8D,0x87,0x25,0x40,0x4A,0x82,0x14, ++ 0x45,0x12,0xC2,0x01,0xD6,0x2B,0xD4,0x33,0x08,0x01,0xB0,0x0B,0x61,0x1A,0xE2,0x0B, ++ 0x10,0xF9,0x05,0x8A,0xA1,0x0B,0xE1,0x0B,0x10,0x01,0x19,0x8A,0xA2,0x0B,0x51,0x02, ++ 0x92,0x01,0x46,0x8B,0x18,0x01,0x1A,0xCA,0x01,0x8B,0x52,0xBA,0x44,0x8B,0x1A,0x01, ++ 0x1A,0xCA,0x00,0x8B,0x79,0x9A,0x41,0xCB,0x10,0x09,0x18,0x8A,0x00,0xCB,0x51,0x03, ++ 0x80,0x01,0xE2,0x0B,0x49,0x79,0x87,0xDE,0xE6,0x03,0x40,0x69,0x88,0x46,0x09,0xA9, ++ 0x07,0x91,0xB8,0xFF,0xE8,0x3F,0x46,0x09,0x89,0x0E,0x32,0x42,0x1A,0x82,0x03,0x08, ++ 0x10,0x09,0x88,0x1C,0x94,0x04,0x90,0x4D,0x18,0x01,0xC0,0x14,0xBB,0xFF,0xEF,0x2F, ++ 0x42,0xC3,0x41,0x00,0x01,0x00,0x02,0xC3,0x40,0x5A,0x11,0x09,0x90,0x04,0xC8,0x1C, ++ 0x14,0x01,0x90,0x4D,0x37,0x9A,0xB8,0xFF,0xE8,0xC7,0xC2,0x24,0x15,0x09,0xC8,0x48, ++ 0xE8,0x48,0x90,0x04,0x00,0x48,0x12,0x01,0x1F,0x09,0xB8,0xFF,0xE8,0x77,0x02,0xF7, ++ 0x08,0xA1,0x00,0x91,0xBC,0xFF,0xEF,0xF7,0x40,0x09,0x88,0xC6,0x18,0xAA,0x13,0x09, ++ 0x20,0x40,0x63,0x08,0x90,0x04,0x30,0x9A,0xC7,0x14,0xB8,0xFF,0xE8,0xF7,0x01,0x77, ++ 0x08,0xB1,0x00,0x91,0xBC,0xFF,0xEF,0x77,0x40,0x09,0x88,0x46,0xC0,0x24,0x10,0x09, ++ 0xC8,0x48,0xED,0x48,0x00,0x48,0x32,0x9A,0x97,0x04,0xB8,0xFF,0xE9,0x77,0xE1,0x03, ++ 0x08,0xF9,0x06,0x42,0xA1,0x03,0x41,0xC3,0x42,0x00,0x02,0x00,0x00,0xC3,0x41,0x32, ++ 0x0A,0x01,0x0F,0x0B,0x0C,0x01,0x00,0x0B,0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B, ++ 0x28,0xCF,0x00,0x00,0xF8,0x00,0x06,0x42,0x80,0x01,0x06,0x42,0x00,0xC0,0x05,0x01, ++ 0x00,0x70,0x00,0x01,0x58,0x20,0x00,0x01,0x10,0x00,0x00,0x42,0x00,0xC0,0x06,0x01, ++ 0x00,0x00,0x00,0x42,0x18,0xC0,0x07,0x01,0x08,0x40,0x01,0x01,0x52,0xCA,0x42,0x83, ++ 0x02,0x83,0x42,0xCA,0xF7,0x0B,0x48,0xF9,0x90,0x16,0xF0,0x0B,0xE0,0x48,0xB2,0x0B, ++ 0xF0,0x03,0x40,0xC1,0x90,0x0E,0x00,0x01,0x03,0x83,0x3C,0x82,0x4C,0x9A,0x4A,0x53, ++ 0x58,0x8A,0xE2,0xC3,0x1C,0x12,0x0C,0x53,0x10,0x43,0x02,0x09,0xB3,0xC3,0x38,0x82, ++ 0xAA,0x85,0x40,0x72,0x84,0x01,0x42,0x0B,0x10,0x01,0x1C,0x8A,0x02,0x0B,0x54,0x62, ++ 0x4A,0x4A,0x42,0x62,0x85,0x27,0xC0,0xAF,0xEF,0x85,0xA8,0xC5,0x46,0x32,0x82,0x01, ++ 0xE2,0x0B,0x78,0x4A,0x30,0x48,0xAC,0x46,0xE2,0x0B,0x10,0x01,0x18,0x8A,0xA0,0x0B, ++ 0x44,0xC3,0x0B,0x01,0x1B,0x42,0x04,0xC3,0xE8,0xC5,0x17,0x01,0x0D,0xD3,0x45,0xCB, ++ 0x6E,0xEA,0x01,0x79,0x01,0x0A,0x30,0x72,0x59,0x02,0xB2,0x01,0x61,0x44,0x57,0x63, ++ 0x48,0x09,0x80,0xDE,0x48,0x29,0x80,0x46,0x4B,0x41,0x88,0x46,0x8F,0x93,0x43,0xCB, ++ 0x38,0x48,0x8E,0x16,0x05,0x81,0x00,0xC3,0xED,0xC5,0x0F,0xD3,0x10,0xC2,0x8C,0x16, ++ 0x07,0x29,0x05,0xC3,0x01,0x3F,0xE0,0x0A,0x02,0xCB,0xE7,0x00,0x97,0x05,0x24,0x44, ++ 0x40,0x89,0x9A,0x06,0x20,0x5C,0x07,0xA1,0x07,0xC3,0xED,0xC5,0xC8,0x8B,0x4B,0x11, ++ 0x91,0xE6,0x61,0x7A,0x48,0x01,0x88,0x2E,0x43,0xC3,0x07,0x04,0x41,0x6A,0x11,0x43, ++ 0x21,0x54,0x07,0xF7,0x43,0xC3,0x47,0x0C,0x10,0x48,0xC0,0x40,0x96,0x25,0x04,0x89, ++ 0x11,0x00,0xD0,0x00,0x40,0x01,0xC1,0x76,0x97,0x05,0xBF,0xFF,0xF1,0x1F,0x44,0x32, ++ 0x11,0x22,0x8C,0x76,0x00,0x09,0x80,0x07,0xC8,0xD7,0x03,0xC1,0xB1,0x43,0x49,0x02, ++ 0x00,0x09,0x80,0x43,0x00,0x2F,0x41,0xC2,0x86,0x01,0xED,0x03,0x08,0x69,0x18,0x48, ++ 0x40,0x01,0x88,0x36,0xD2,0x00,0x43,0x81,0xC7,0x0E,0x20,0x44,0x07,0xCF,0x20,0x5C, ++ 0x00,0xBF,0x40,0xD2,0xC1,0x00,0x41,0x19,0xC7,0x1E,0x20,0x44,0x41,0xC2,0x10,0x43, ++ 0x03,0x7F,0xD0,0x00,0x40,0xB1,0xC1,0x66,0x20,0x44,0x07,0x57,0x10,0xC2,0x84,0x46, ++ 0x41,0xCB,0xA7,0x0A,0x62,0x44,0xE7,0x00,0x97,0x05,0x24,0x44,0x40,0x89,0x9A,0x06, ++ 0x23,0x5C,0xCF,0x83,0xE3,0x00,0x8A,0x83,0x05,0x81,0x00,0xC3,0xED,0xC5,0x07,0xD3, ++ 0xE8,0xC5,0x07,0x00,0x10,0x00,0x00,0x42,0x00,0xC0,0x00,0x01,0xF8,0x00,0x06,0x42, ++ 0x58,0xC0,0x02,0x01,0x00,0xA0,0x07,0x01,0x80,0x01,0x06,0x42,0xF8,0xFF,0x07,0x00, ++ 0x00,0x80,0x00,0x01,0x58,0x20,0x00,0x01,0x88,0x76,0x00,0x00,0x77,0x81,0xF8,0xFF, ++ 0xF8,0x02,0x07,0x00,0xA8,0x85,0x80,0x07,0xC8,0x77,0x65,0x32,0xE8,0x03,0x47,0x01, ++ 0x80,0x26,0x40,0x31,0x8F,0xD6,0xBF,0xFF,0xDF,0x3F,0x38,0xBF,0xBB,0xFF,0xD7,0x5F, ++ 0x38,0xA7,0x07,0x00,0x00,0xC0,0x05,0x01,0xAE,0xC5,0x6F,0xDA,0x03,0x41,0x83,0x43, ++ 0x01,0x09,0x80,0x43,0x0F,0x01,0x81,0x4B,0x15,0x19,0x80,0x53,0x13,0x41,0x89,0x53, ++ 0x17,0x69,0x89,0x53,0x15,0x69,0x88,0x53,0x11,0x92,0x32,0x7A,0xBD,0x01,0x15,0xD4, ++ 0x17,0xA1,0x1D,0x54,0x32,0x62,0xA1,0x01,0x8D,0x03,0x8B,0x03,0x07,0x41,0x88,0x03, ++ 0x11,0x51,0x90,0x13,0x13,0xA1,0x90,0x13,0x90,0x0B,0x0F,0x81,0x9B,0x0B,0x99,0x03, ++ 0x0F,0x01,0x98,0x4B,0x0D,0x71,0x90,0x4B,0x17,0x31,0x90,0x53,0x98,0x4B,0x0B,0x31, ++ 0x98,0x4B,0x09,0x01,0x99,0x4B,0xA5,0x43,0x03,0x81,0xA1,0x43,0x03,0x51,0x80,0x03, ++ 0x05,0xB1,0x87,0x03,0x07,0x51,0x80,0x03,0x01,0xB1,0x8F,0x03,0x05,0x29,0x94,0x03, ++ 0x01,0x51,0x28,0x44,0x03,0xF9,0x87,0x49,0x34,0x32,0xB1,0x01,0x00,0x84,0x01,0xC9, ++ 0x0B,0x00,0x02,0x84,0x04,0x79,0x10,0x00,0x05,0x83,0x43,0xC2,0x00,0x83,0x05,0x01, ++ 0x99,0x83,0x31,0x02,0x0C,0x51,0x80,0x91,0x87,0x27,0xD0,0x87,0x05,0xB1,0xB7,0xC3, ++ 0x07,0xA1,0xB0,0xC3,0x07,0x01,0xA8,0xC3,0x09,0x01,0x30,0x02,0x80,0x01,0xA2,0x0B, ++ 0xA0,0x0B,0x0E,0xC1,0xA8,0x0B,0x08,0x51,0xAE,0x0B,0x0A,0x41,0x1F,0x0C,0x0E,0xF9, ++ 0x89,0x21,0x00,0xCC,0x0E,0x99,0x18,0x4A,0xA8,0x0B,0x14,0xA1,0xA8,0x13,0xB6,0x0B, ++ 0x0A,0xA1,0xB0,0x0B,0x0A,0x51,0x88,0x0B,0x14,0xF1,0x88,0x13,0x0E,0x21,0x8B,0x0B, ++ 0x0A,0x59,0x0D,0x0C,0x08,0xE1,0x90,0x0B,0x08,0xC9,0x99,0x0B,0x0A,0x31,0x98,0x0B, ++ 0x08,0xF9,0x8F,0x09,0x08,0x0C,0x0E,0x51,0xB8,0x4B,0x0B,0x01,0x32,0x4C,0xA3,0x0B, ++ 0x0D,0x21,0xB0,0x8B,0x0B,0x31,0xB0,0x8B,0x09,0x19,0x0D,0x4C,0x0C,0xA1,0xB0,0x0B, ++ 0x0E,0x51,0xB0,0x0B,0x0C,0x01,0xA0,0x0B,0x08,0x19,0xBC,0x0B,0x09,0x31,0x80,0x0B, ++ 0x18,0x01,0x30,0x0A,0xCE,0x01,0x9B,0x5B,0xA2,0x5B,0x88,0x01,0xB2,0x53,0xB0,0x53, ++ 0x14,0xE1,0xB1,0x53,0x16,0x41,0xB0,0x53,0x10,0x11,0xB8,0x53,0x12,0xB1,0xB8,0x53, ++ 0x14,0x19,0xB8,0x53,0x48,0x52,0x04,0x0B,0x8C,0x1B,0x48,0x52,0xC6,0x01,0x34,0x0B, ++ 0x88,0x91,0x38,0x0B,0x8A,0xE1,0x3E,0x0B,0x0C,0xC1,0x40,0x3A,0x84,0x27,0xD0,0x77, ++ 0x40,0x2A,0x0C,0xC1,0xC0,0x81,0x81,0x27,0xD4,0x4F,0x4C,0x12,0x43,0x1A,0xCC,0x31, ++ 0x00,0x0B,0xCE,0x71,0x00,0x0B,0x8C,0xA1,0x08,0x0B,0x88,0xC1,0x0A,0x0B,0xCA,0x21, ++ 0x01,0x0B,0xCA,0xC1,0x05,0x0B,0x88,0xA1,0x0D,0x0B,0xCC,0xC1,0x10,0x0B,0xFA,0x48, ++ 0x10,0x0B,0xF8,0x48,0x0F,0x0B,0xEE,0xC5,0xA8,0x85,0x09,0x01,0x63,0x92,0x43,0x92, ++ 0xA2,0xE1,0xFE,0x1B,0x01,0x77,0x00,0x21,0x18,0x42,0xCA,0x28,0x00,0x29,0x12,0x79, ++ 0x09,0x00,0xC2,0x40,0x90,0x13,0x10,0x01,0x94,0x13,0x92,0x13,0x10,0x14,0x1E,0x14, ++ 0xE6,0x48,0x92,0x4D,0x17,0x5A,0xC4,0x76,0x07,0x01,0x10,0xF9,0x2D,0x09,0x09,0x68, ++ 0x02,0x37,0x00,0x08,0xCA,0x48,0xC8,0x48,0xB2,0x53,0xB0,0x53,0xE6,0x00,0x92,0x05, ++ 0x17,0x1A,0xC4,0xB6,0xE9,0x85,0xA1,0x85,0x56,0xFA,0x92,0x01,0x08,0x01,0x10,0x8C, ++ 0xD4,0x01,0xB6,0x8B,0xB8,0x8B,0x30,0x9A,0x98,0x01,0xB5,0xCB,0x1C,0xCC,0xBC,0xCB, ++ 0xB0,0xCB,0x22,0x09,0xB0,0xA3,0xA8,0x8B,0xDE,0x01,0xF1,0xDB,0xB0,0x9B,0x32,0x9A, ++ 0x9A,0x01,0xA1,0xCB,0x9A,0x01,0xA1,0xE3,0xA4,0xCB,0xA0,0xA3,0x20,0x41,0x89,0xA3, ++ 0x40,0x09,0x88,0x16,0xA1,0xCB,0xE4,0x85,0x39,0xB7,0xE5,0x85,0x3A,0x82,0x0B,0x08, ++ 0x40,0x9A,0x42,0x13,0x18,0x01,0x01,0xD2,0x90,0x41,0x04,0x13,0x10,0xD0,0x1C,0x8A, ++ 0x0A,0x0B,0x42,0x0B,0x40,0x0B,0x10,0x41,0x18,0x8A,0x04,0x0B,0x0C,0x01,0x00,0x0B, ++ 0x38,0x82,0xAB,0x85,0x40,0x5A,0x42,0x0B,0x30,0x48,0xA8,0x2E,0x08,0x81,0x06,0x0B, ++ 0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B,0x4E,0x32,0x8A,0x01,0x40,0x53,0x3C,0x90, ++ 0x7C,0x90,0x00,0x53,0x41,0x53,0x1C,0x81,0x1C,0xD2,0x00,0x53,0x5E,0x12,0x12,0x09, ++ 0x01,0xD3,0x12,0x91,0x02,0x13,0x46,0x0A,0x40,0x23,0x14,0x61,0x1C,0xA2,0x00,0x23, ++ 0x40,0x23,0x1A,0xA2,0x02,0x23,0x4A,0x23,0x1A,0xA2,0x08,0x23,0x48,0x23,0x18,0xA2, ++ 0x0E,0x23,0x40,0x23,0x1E,0xA2,0x00,0x23,0x42,0x43,0x12,0x01,0x1A,0x82,0x00,0x43, ++ 0x00,0xD1,0x04,0xC3,0x02,0x01,0x0F,0xC3,0xE9,0x85,0x40,0xA2,0x40,0x13,0x08,0x09, ++ 0x18,0x52,0x00,0x13,0x4C,0x13,0x18,0x52,0x0A,0x13,0x48,0x13,0x1A,0x52,0x0C,0x13, ++ 0x40,0x13,0x1E,0x52,0x03,0x13,0x3E,0x82,0x40,0x6A,0x59,0x0B,0x10,0x21,0x18,0x8A, ++ 0x18,0x0B,0x58,0x0B,0x10,0x01,0x1A,0x8A,0x18,0x0B,0x58,0x13,0x08,0x01,0x1C,0x52, ++ 0x19,0x13,0x40,0x22,0x16,0x01,0x80,0x01,0x02,0x13,0x40,0x13,0x1A,0x52,0x00,0x13, ++ 0x48,0xFA,0x40,0x43,0x10,0x01,0x19,0x82,0x03,0x43,0x38,0x82,0xA8,0x85,0x08,0x09, ++ 0x00,0x31,0x80,0x07,0xD0,0x3F,0x0D,0x11,0x00,0x21,0x80,0x07,0xD0,0x1F,0x05,0x09, ++ 0x85,0x07,0xD0,0xFF,0x00,0x31,0x80,0x07,0xD0,0xE7,0x05,0x21,0x85,0x07,0xD0,0xCF, ++ 0x86,0x07,0xD0,0x77,0xE8,0x85,0xA8,0x85,0x40,0x82,0x48,0x5A,0xC0,0xA1,0x12,0x43, ++ 0xBA,0xFF,0xF7,0xD7,0x07,0x09,0xB8,0xFF,0xF8,0x77,0x02,0xA1,0xBB,0xFF,0xFF,0x7F, ++ 0xBB,0xFF,0xFF,0xFF,0xBE,0xFF,0xFF,0x07,0xBD,0xFF,0xFF,0x7F,0xBE,0xFF,0xFF,0xB7, ++ 0x48,0x62,0x00,0x01,0x80,0x43,0xE8,0x85,0x00,0xC0,0x00,0x01,0xC8,0x21,0x01,0x00, ++ 0xF8,0xFF,0x07,0x04,0xD8,0x02,0x06,0x00,0x40,0x60,0x07,0x01,0x58,0xC0,0x02,0x01, ++ 0x10,0x00,0x00,0x42,0x00,0x00,0x00,0x42,0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42, ++ 0x18,0x00,0x02,0x42,0x00,0x80,0x00,0x01,0xA8,0x85,0x80,0x07,0xD0,0xEF,0xEA,0x85, ++ 0xAF,0x85,0xB8,0xFF,0xF0,0xBF,0xE8,0x85,0xA8,0x7D,0x80,0x04,0x88,0x0C,0xC0,0x0C, ++ 0x80,0x14,0xC0,0x04,0x83,0x1C,0x30,0x42,0x40,0x7E,0x80,0x25,0xE8,0x05,0x00,0x00, ++ 0xAC,0xFD,0x87,0x1D,0x30,0x32,0x00,0x01,0x82,0x14,0x00,0x9F,0x44,0xFA,0x0F,0x01, ++ 0x0C,0x0B,0x26,0x01,0xC2,0x14,0x00,0x28,0x7F,0xE2,0x4F,0xC3,0x1F,0x02,0x09,0xC3, ++ 0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x86,0x1F,0xD8,0x37, ++ 0xF8,0x82,0x33,0x0A,0xCF,0x99,0x49,0xC9,0x99,0x3E,0x40,0x91,0xE7,0x16,0x48,0xC3, ++ 0x1F,0x02,0x0D,0xC3,0x40,0x20,0x63,0x01,0x88,0x36,0xD7,0x6C,0x90,0x04,0x10,0x09, ++ 0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x1F,0xDB,0x8F,0xFD,0xA2,0xD0,0x6C,0x90,0x04, ++ 0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x85,0x1F,0xD8,0x47,0xF8,0xBA,0xD3,0x6C, ++ 0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x1F,0xDD,0xFF,0x14,0x3A, ++ 0xE9,0x16,0x30,0x02,0x30,0xE2,0x31,0x3A,0xFD,0x82,0x13,0xC2,0xE3,0x0E,0x98,0xBA, ++ 0x05,0x17,0x10,0x02,0xDB,0x06,0x98,0xA2,0x46,0xE2,0x4E,0x03,0xDE,0x8A,0x0B,0x00, ++ 0xC0,0x00,0xCA,0x24,0x00,0x44,0xC0,0x24,0xE0,0x00,0x84,0x24,0xC2,0x14,0xE0,0x00, ++ 0x90,0x05,0x86,0x14,0xC8,0x2C,0xC0,0x14,0x15,0x42,0x9C,0x3E,0x87,0x3D,0xE8,0x85, ++ 0xAC,0xFD,0x87,0x7D,0x30,0xA2,0x30,0xEA,0xD8,0x0B,0x8B,0x6C,0xD0,0x0B,0x8F,0x64, ++ 0x40,0x01,0x80,0x6E,0x48,0x72,0x06,0x99,0x07,0x43,0x12,0xF9,0x58,0x5A,0x96,0x81, ++ 0x10,0xD3,0x06,0x43,0x00,0xC1,0x83,0x1F,0xF8,0x77,0xFF,0x84,0xB8,0xA1,0x01,0xD7, ++ 0x40,0x3A,0x0E,0x19,0x04,0x0B,0x0A,0x19,0x06,0x0B,0x08,0x09,0xC4,0x84,0x00,0x48, ++ 0xC0,0x38,0x12,0x01,0x30,0x5A,0x31,0x8A,0x00,0x09,0x80,0x17,0xD0,0xE7,0x31,0x01, ++ 0x30,0x1A,0x11,0x09,0x08,0x01,0x44,0x1D,0xA8,0x04,0x80,0x1F,0xDB,0x7F,0xE2,0xB0, ++ 0x91,0xB5,0x77,0x91,0x9D,0xA6,0x47,0xD2,0x40,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B, ++ 0x00,0xE1,0xEC,0x02,0x33,0x00,0xA8,0xE6,0x40,0xB2,0x0D,0x01,0x81,0x0B,0x30,0x12, ++ 0x30,0x4A,0x01,0x11,0x84,0x17,0xC8,0x27,0x30,0x1A,0xA9,0x04,0x08,0x01,0x00,0x11, ++ 0xD0,0x84,0x80,0x17,0xD0,0x77,0x33,0x01,0xC2,0x64,0x00,0x00,0x80,0x74,0x00,0xBF, ++ 0x31,0x5A,0x31,0x92,0x08,0x01,0x00,0x09,0x80,0x17,0xD0,0x6F,0xA8,0x0C,0xA0,0x04, ++ 0x30,0xCA,0x41,0x1D,0xD8,0x84,0xD0,0x64,0xBA,0xFF,0xFF,0x17,0xC6,0x74,0xC8,0x38, ++ 0x09,0x09,0x30,0x5A,0x30,0x92,0x31,0x42,0x87,0x17,0xC8,0xEF,0xE7,0xB0,0x93,0xB5, ++ 0xC4,0x6C,0x10,0x32,0x99,0x26,0x37,0x1A,0xA8,0x04,0x08,0x01,0x00,0x19,0xD0,0x84, ++ 0x82,0x17,0xD0,0x3F,0x31,0x12,0x31,0x4A,0x00,0x01,0x80,0x17,0xCD,0x8F,0xDA,0x03, ++ 0x41,0x01,0x80,0xF6,0x40,0xBA,0x0C,0x09,0x81,0x0B,0x30,0x12,0x30,0x4A,0x01,0x11, ++ 0x82,0x17,0xC8,0x37,0x30,0x5A,0x09,0x01,0x00,0x09,0xD0,0x6C,0x86,0x17,0xC8,0xDF, ++ 0x30,0x1A,0xA9,0x04,0x00,0x11,0xD0,0x84,0xC8,0x6C,0x80,0x17,0xD0,0x57,0xA9,0x0C, ++ 0xA5,0x04,0xD8,0x13,0x30,0xCA,0x41,0x1D,0xDF,0x84,0xB8,0xFF,0xFD,0x4F,0xD8,0x03, ++ 0x06,0x00,0xCA,0x30,0x30,0x1A,0xA9,0x04,0x00,0x19,0xD0,0x84,0xC8,0x6C,0x80,0x17, ++ 0xD0,0xC7,0x08,0x09,0x30,0x5A,0x31,0x42,0xD0,0x6C,0x80,0x17,0xC9,0xE7,0x35,0x12, ++ 0x30,0x4A,0x01,0x01,0x80,0x17,0xC8,0xE7,0x40,0xF2,0x0B,0x01,0x85,0x0B,0xD8,0x03, ++ 0x00,0x27,0x00,0x37,0x05,0x8C,0xE1,0xB0,0xE6,0x00,0x92,0x05,0xD4,0x64,0x10,0x82, ++ 0x9B,0xC6,0x57,0xBA,0x40,0x83,0x08,0x11,0x18,0x42,0x04,0x83,0x87,0x9D,0xE8,0x85, ++ 0xAC,0xFD,0x87,0x1D,0x30,0x7A,0x50,0x01,0x80,0x16,0x00,0x01,0x80,0x0C,0x00,0x0F, ++ 0x00,0x09,0x80,0x0C,0x2A,0x01,0x00,0x47,0xCD,0x64,0x00,0x40,0xC1,0x30,0x32,0x52, ++ 0x08,0x19,0xD8,0x6C,0xC0,0x0C,0x80,0x17,0xC9,0x77,0x04,0x41,0x81,0x1F,0xF8,0x5F, ++ 0x20,0x09,0xC0,0x34,0x80,0x01,0x84,0x14,0x60,0x81,0x99,0x36,0x0B,0xF9,0x47,0x1A, ++ 0x88,0x11,0x18,0x0B,0x42,0x08,0x1B,0x0B,0x03,0x0F,0x40,0x02,0x1F,0x23,0x02,0xF9, ++ 0x4F,0xF2,0x82,0x89,0x88,0x01,0x12,0x43,0x00,0x11,0x80,0x1F,0xF8,0xA7,0xC0,0x14, ++ 0xE0,0x03,0x44,0x01,0x80,0x3E,0x00,0x51,0x80,0x1F,0xF8,0x6F,0x40,0x83,0x41,0x03, ++ 0x30,0x00,0xA8,0x86,0x07,0x5F,0x00,0xF9,0x4C,0xA2,0x82,0x89,0x88,0x01,0x12,0x43, ++ 0x00,0x09,0x80,0x1F,0xF9,0x07,0x40,0x83,0x40,0x03,0x30,0x00,0xA3,0x1E,0xE0,0x20, ++ 0x93,0x25,0x67,0xF9,0xC9,0x86,0x06,0xE4,0xE1,0xF8,0x35,0x52,0x08,0x09,0xD8,0x6C, ++ 0xC0,0x0C,0x80,0x17,0xCB,0x87,0xE2,0x68,0x90,0x6D,0xC7,0x1C,0x15,0x2A,0x9C,0x9E, ++ 0x37,0x27,0xAF,0x85,0x80,0x4D,0x34,0x6A,0x34,0xA2,0x00,0x91,0xEF,0x02,0x0A,0xF9, ++ 0x88,0x09,0x40,0x01,0x80,0x0E,0x30,0x7A,0x00,0x0F,0x38,0x19,0x17,0xF8,0xD1,0x43, ++ 0x85,0x44,0xD0,0x53,0x90,0x3C,0x98,0x24,0xC2,0x44,0x00,0x00,0xC0,0x00,0x86,0x2C, ++ 0xD2,0x3C,0x00,0x90,0xC0,0x00,0x84,0x1C,0x45,0xC2,0x11,0x81,0x00,0x13,0x1A,0x0B, ++ 0x30,0x01,0x00,0x67,0x4D,0x03,0x01,0x88,0xC0,0x00,0x42,0x03,0x01,0x3B,0x30,0x1A, ++ 0x30,0x92,0x09,0x09,0x00,0x01,0x80,0x17,0xCB,0xF7,0xE0,0xB0,0x90,0xB5,0xC7,0x44, ++ 0x17,0x32,0x9C,0x7E,0x30,0x01,0x00,0x67,0x4D,0x03,0x03,0x88,0xC0,0x00,0x42,0x03, ++ 0x00,0x3B,0x08,0x09,0x31,0x1A,0x31,0x92,0x30,0x42,0x80,0x17,0xCB,0x67,0xE0,0xB0, ++ 0x90,0xB5,0xC7,0x3C,0x17,0x32,0x9C,0x7E,0xD8,0x43,0x45,0x01,0x81,0x16,0x41,0x1A, ++ 0x44,0x0B,0x96,0x4D,0x89,0x14,0x48,0x4C,0x01,0x0B,0x4E,0x12,0x00,0x09,0x80,0x43, ++ 0xD8,0x43,0x85,0x34,0x30,0x01,0x00,0x67,0x55,0x03,0x01,0x88,0xC0,0x00,0x42,0x03, ++ 0x01,0x3B,0x30,0x1A,0x30,0x92,0x09,0x09,0x00,0x01,0x80,0x17,0xC3,0x67,0xE7,0xB0, ++ 0x90,0xB5,0xC7,0x34,0x17,0x32,0x9C,0x7E,0x48,0xB2,0x00,0x01,0x80,0x43,0x40,0x9A, ++ 0xCE,0x14,0x00,0x0B,0x48,0x0B,0x89,0x04,0x30,0x5A,0x11,0x09,0xA0,0x0C,0xC8,0x24, ++ 0xC7,0x44,0xB8,0xFF,0xFB,0xAF,0x49,0x0B,0x89,0x04,0x30,0x5A,0x10,0x01,0xA0,0x0C, ++ 0xC8,0x2C,0xC0,0x3C,0xB9,0xFF,0xFF,0x67,0xD8,0x43,0x45,0x01,0x80,0xDE,0x70,0x3A, ++ 0x44,0x83,0x97,0x3D,0x4F,0x44,0x01,0x83,0x40,0x32,0x08,0x09,0x85,0x0B,0xD8,0x43, ++ 0x51,0x0B,0x31,0x5A,0x10,0x09,0xA0,0x0C,0x88,0x04,0x00,0x2F,0x00,0x01,0x00,0x42, ++ 0x18,0x00,0x04,0x42,0x00,0xB0,0x00,0x01,0xCF,0x1C,0xB8,0xFF,0xF8,0x8F,0x40,0xDA, ++ 0x08,0x01,0x80,0x0B,0x00,0xBB,0x4F,0xD2,0x00,0x01,0x10,0x43,0x4A,0xC2,0xC8,0x01, ++ 0x18,0x43,0x80,0x4D,0xEF,0x85,0xAF,0xC5,0x30,0x1A,0x30,0x42,0x34,0xBA,0xD0,0x23, ++ 0xD0,0x2B,0x4E,0xA2,0xC0,0xC8,0x8A,0x04,0x30,0xD2,0x31,0xCA,0x80,0x17,0xE8,0xE7, ++ 0x30,0x01,0x00,0x3F,0x09,0x09,0x30,0xDA,0x30,0x92,0x31,0x42,0x84,0x17,0xC0,0x9F, ++ 0xE7,0xB0,0x93,0xB5,0x17,0x32,0x9D,0xAE,0xC8,0x04,0x10,0x01,0x18,0x01,0x00,0x4F, ++ 0x00,0x01,0x00,0x1F,0x82,0x5B,0xE0,0x48,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE, ++ 0xE6,0x90,0x92,0x95,0x17,0x12,0x9D,0x9E,0xE8,0xC5,0x07,0x00,0x00,0xB0,0x00,0x01, ++ 0x00,0x01,0x02,0x42,0x30,0x20,0x06,0x00,0x49,0x32,0x41,0x2A,0x05,0x43,0x9E,0xFF, ++ 0x7F,0x04,0x3A,0xF7,0x94,0x15,0x3A,0x00,0x77,0x18,0x06,0xF9,0x04,0xC2,0x3C,0x48, ++ 0x74,0x48,0x00,0xCA,0x50,0x01,0xD0,0x5E,0x38,0x90,0x78,0x90,0xD4,0x41,0x40,0x98, ++ 0x54,0xE2,0x00,0xD8,0xC6,0xD0,0x4C,0x9B,0x18,0x1A,0x1C,0x5A,0x0B,0x9B,0x3E,0x82, ++ 0x40,0x98,0x54,0xCA,0x04,0xD8,0xC4,0xD0,0x44,0x9B,0x18,0x1A,0x18,0x5A,0x00,0x9B, ++ 0x3A,0x82,0x93,0x05,0x36,0x10,0x76,0x90,0x0C,0x09,0x00,0x8A,0x48,0x00,0x52,0x9A, ++ 0x04,0x00,0xC4,0x00,0x03,0x0B,0x38,0x82,0x96,0x05,0x32,0x10,0x70,0x90,0x0E,0x09, ++ 0x00,0x8A,0x54,0x72,0x4C,0x00,0x02,0x00,0x94,0x01,0xC4,0x00,0x03,0x0B,0x38,0x82, ++ 0xB3,0x15,0x3B,0x82,0xFB,0x85,0x39,0x82,0x40,0x32,0x48,0x0B,0x10,0x21,0x18,0x8A, ++ 0x0B,0x0B,0x38,0x82,0x48,0x1A,0x48,0x43,0x14,0x21,0x18,0x82,0x0B,0x43,0x38,0x82, ++ 0x07,0x20,0x28,0xD0,0x68,0x07,0x00,0x07,0x20,0x07,0x00,0x07,0x08,0x07,0x00,0x07, ++ 0xAC,0xFD,0x87,0x4D,0xD0,0x94,0x30,0x22,0xF0,0x43,0x84,0x0C,0xF8,0x6B,0xC2,0x64, ++ 0x08,0x01,0x80,0x0B,0x00,0x01,0x00,0x8F,0x0A,0x21,0x19,0x0A,0x18,0x29,0xCA,0x48, ++ 0x0E,0xD8,0xC2,0x48,0xD0,0x4B,0x48,0x79,0x80,0x36,0x80,0x83,0xE0,0x90,0xCA,0x64, ++ 0xD8,0x64,0xC0,0x4B,0xE0,0x48,0x82,0xCB,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0x5E, ++ 0xC0,0x64,0xC0,0x03,0x80,0x44,0x40,0x01,0x88,0x0E,0x80,0x6D,0xE8,0x85,0xC7,0x44, ++ 0x40,0x09,0x88,0x1E,0xC0,0x0C,0x40,0x09,0x8F,0x06,0x38,0xB7,0x00,0x01,0x80,0x34, ++ 0x80,0x2C,0xC8,0x44,0xC4,0x0C,0x10,0x0A,0x88,0x8E,0x02,0x01,0x30,0x01,0x08,0x01, ++ 0x88,0x1C,0x88,0x14,0x1A,0x19,0x0A,0xD8,0x00,0x4F,0x10,0x31,0x18,0x52,0xCA,0x90, ++ 0xC4,0x90,0x4E,0xBC,0xC6,0xC0,0x49,0x94,0xCA,0xB0,0xE4,0x48,0x90,0x4D,0xD6,0x0C, ++ 0x17,0x8A,0x9C,0x96,0xC8,0x0C,0x80,0x1F,0xF0,0xFF,0x83,0x24,0x30,0x82,0xC9,0x0C, ++ 0x83,0x1F,0xF0,0xD7,0x30,0x32,0x08,0x01,0x00,0x01,0x00,0xFF,0x1A,0x29,0x0A,0xD8, ++ 0x02,0x0F,0xE0,0x48,0x91,0x4D,0x16,0x21,0x18,0x52,0xCA,0x90,0xC0,0x90,0xD6,0x93, ++ 0x57,0x79,0x80,0xB6,0x12,0x21,0x19,0x52,0x18,0x19,0xC9,0x90,0x0E,0xD8,0xC4,0x90, ++ 0x1E,0x01,0xF0,0x9A,0xFE,0x1C,0xC8,0xD8,0x98,0x1C,0x18,0x11,0xF0,0x9A,0xD6,0x14, ++ 0xC0,0xD0,0x94,0x14,0xE6,0x48,0x92,0x4D,0xE6,0x00,0x92,0x05,0xD4,0x44,0x10,0x12, ++ 0xC0,0xE6,0xCE,0x44,0xC0,0x1C,0x80,0x1F,0xF0,0x7F,0x32,0x3A,0xC8,0x44,0xC0,0x14, ++ 0x82,0x1F,0xF0,0x57,0xCE,0x24,0xD8,0x48,0x89,0x34,0xD0,0x80,0x80,0x2C,0x08,0x01, ++ 0x10,0x01,0x00,0x77,0x00,0x01,0x30,0x5A,0x18,0x5A,0xF3,0x5C,0x04,0xD8,0xCA,0xD8, ++ 0x02,0x1F,0x00,0x30,0x9A,0xD2,0xE4,0x00,0x95,0x05,0x16,0x42,0x9A,0xCE,0xE7,0x48, ++ 0x95,0x4D,0x16,0x4A,0x98,0x76,0x0F,0x01,0x11,0x01,0x00,0xF7,0x1A,0x29,0x0A,0xD8, ++ 0x02,0x0F,0xE0,0x48,0x91,0x4D,0x06,0x21,0x18,0x42,0xCA,0x00,0x86,0x3C,0xC0,0x00, ++ 0xD0,0x03,0x40,0x79,0x80,0xAE,0x07,0x01,0x01,0x47,0x19,0x19,0xF4,0x3C,0x08,0xD8, ++ 0xC0,0x98,0x37,0x01,0x34,0xE2,0xFC,0xF2,0xDA,0x34,0x38,0x19,0xC0,0x98,0x37,0x31, ++ 0x19,0x32,0xCA,0xB0,0x0F,0xF8,0xCB,0xB0,0x35,0xB2,0x4D,0xB4,0xD8,0xD8,0xAC,0x06, ++ 0x14,0xDA,0x92,0xDD,0x30,0x32,0x3B,0x11,0xF8,0xBA,0xF7,0x2C,0xCB,0xF0,0x35,0xBA, ++ 0x4F,0xFC,0xDF,0xB0,0xAB,0x06,0x10,0xB2,0xC8,0xD8,0x34,0xB2,0x18,0x72,0xFB,0x5C, ++ 0x07,0xB0,0xCB,0xB0,0x07,0x38,0x9A,0x9A,0xE6,0x00,0x92,0x05,0xDC,0x0C,0x10,0xC2, ++ 0x9A,0x9E,0xE6,0x48,0x92,0x4D,0xE6,0x90,0x90,0x95,0xC6,0x64,0xC4,0x03,0x10,0x82, ++ 0xC0,0xE6,0xC5,0x64,0xC8,0x0C,0xC0,0x03,0x10,0x42,0xCC,0x06,0x38,0xEF,0xC1,0x0C, ++ 0x3F,0xDF,0xA9,0x85,0x80,0x4D,0x34,0x22,0x04,0x71,0xD4,0x1A,0x01,0xC1,0xF0,0x02, ++ 0x28,0x71,0x80,0x44,0xF8,0x2A,0xAB,0x3C,0xD8,0x00,0x92,0x05,0x2B,0xD1,0xF8,0x2A, ++ 0x30,0x81,0xA8,0x34,0xF8,0x32,0xB5,0x2C,0xD9,0x68,0x95,0x6D,0xC0,0x33,0x77,0x09, ++ 0x8D,0x16,0x10,0x04,0x10,0x2C,0x07,0x7F,0x55,0x3C,0x05,0xF0,0x31,0xE2,0xC5,0xB0, ++ 0x54,0x04,0x07,0x38,0xCB,0xE8,0x33,0x3A,0xD9,0xB0,0x97,0xB5,0xD0,0x40,0x91,0x2D, ++ 0x85,0x80,0x85,0x68,0x17,0x04,0x15,0x2C,0xF1,0x3C,0xC0,0x80,0x04,0x30,0xCA,0x00, ++ 0xF4,0x44,0xC8,0x00,0x80,0x00,0x94,0x05,0xF3,0x2C,0xC8,0xA8,0x05,0x70,0xCB,0x68, ++ 0xF5,0x34,0xC8,0x68,0x81,0x68,0x95,0x75,0x90,0x01,0x46,0x01,0xD0,0x0E,0x00,0x01, ++ 0x00,0x27,0x40,0xAC,0x10,0x2A,0xD4,0x0E,0x00,0x01,0xF0,0x82,0x70,0x01,0xD0,0x0E, ++ 0x30,0x01,0x00,0x27,0x45,0xAC,0x12,0xAA,0xD0,0x0E,0x30,0x11,0xF8,0xB2,0x4C,0x41, ++ 0x80,0x0E,0x48,0x49,0x88,0xBE,0xD0,0x3C,0xD0,0x90,0xA8,0x06,0x14,0x92,0x92,0xAD, ++ 0xD4,0x2C,0xD8,0x90,0xAA,0x06,0x10,0x92,0xCC,0x90,0x92,0xAD,0x10,0xEA,0xCC,0x06, ++ 0x30,0xEA,0x48,0x49,0x8B,0x16,0x20,0x48,0x60,0x68,0x00,0x37,0x4D,0xC8,0x10,0x4A, ++ 0xC8,0x1E,0x30,0x6A,0x00,0x0F,0x30,0xEA,0x00,0x6A,0xD6,0x3C,0xD8,0xC8,0x8A,0x24, ++ 0x1C,0x8A,0x02,0x50,0xC4,0x48,0x34,0x62,0xC8,0x24,0x10,0x51,0x05,0x78,0xF2,0x12, ++ 0xCA,0x48,0x1E,0x52,0x20,0x12,0x8B,0x1C,0x43,0xC8,0x1A,0x42,0xC6,0x00,0x02,0x00, ++ 0xC0,0x00,0x8C,0x14,0x00,0xC8,0x8E,0x0C,0x82,0x1F,0xE8,0xA7,0x30,0x3A,0xC0,0x2C, ++ 0xCA,0x24,0x18,0x0A,0x00,0x40,0xC4,0x40,0x15,0x61,0xF0,0x12,0xCA,0x1C,0x18,0x52, ++ 0xC0,0x80,0xC8,0x14,0x1B,0x72,0xC3,0x88,0x00,0x48,0xC6,0x40,0xC8,0x0C,0x80,0x1F, ++ 0xE8,0x0F,0xCA,0x3C,0x08,0x0C,0xCB,0x2C,0x08,0x0C,0xCD,0x44,0xD0,0xC8,0xAB,0x06, ++ 0x10,0x4A,0x92,0x55,0xCA,0x34,0xD0,0x08,0xAA,0x06,0x10,0x4A,0x90,0x4D,0x50,0x19, ++ 0xD8,0x46,0xD0,0x44,0x10,0xD2,0xCD,0x0E,0xE0,0xF8,0x03,0x1F,0xD5,0x44,0x10,0xD2, ++ 0x93,0x06,0xF0,0xF8,0x48,0x19,0xD8,0x46,0xCC,0x34,0x10,0x0A,0xCA,0x0E,0xE0,0x00, ++ 0x00,0x1F,0xC8,0x34,0x10,0x0A,0x94,0x06,0xF7,0x00,0x0A,0x3C,0x10,0x04,0x81,0x4D, ++ 0xEF,0x85,0xAF,0xF5,0x30,0xB2,0xD0,0x44,0x60,0xCA,0xCF,0xE0,0x2F,0x31,0x78,0xC2, ++ 0x1F,0xAA,0xC3,0x68,0xFF,0xE1,0xC9,0x68,0x07,0xB0,0xC3,0x98,0x72,0xA2,0xF7,0x81, ++ 0xCA,0xF0,0xFC,0x9B,0x36,0xBA,0xB8,0x01,0x32,0xE2,0xFD,0x01,0xBA,0x0C,0xF8,0x01, ++ 0xB8,0x04,0x40,0x09,0x88,0x36,0x01,0x01,0x01,0xFF,0xC0,0x0B,0x48,0x79,0x88,0xCE, ++ 0x47,0x4C,0x09,0x0C,0x41,0x7C,0x13,0x3C,0xC1,0x93,0x89,0x13,0xC3,0x93,0x8B,0x13, ++ 0x1F,0x0C,0x1D,0x3C,0x23,0x0C,0x21,0x3C,0x0D,0x0C,0x0B,0x3C,0x41,0x4C,0x19,0x0C, ++ 0x43,0x4C,0x1B,0x0C,0x80,0x03,0x09,0x09,0x85,0x0B,0x8F,0x0B,0x30,0x0A,0xDB,0x4B, ++ 0x90,0x0B,0x01,0x27,0xA2,0x21,0xE1,0x00,0x94,0x05,0x16,0xC2,0x9C,0xEE,0x16,0xC2, ++ 0x92,0x9E,0x03,0x87,0x02,0x21,0x19,0x0A,0xC8,0x60,0x08,0x41,0x41,0x44,0x19,0x04, ++ 0x01,0x11,0xF0,0x42,0x1D,0x04,0xCB,0x1B,0x58,0x09,0x88,0xA6,0x18,0xC1,0x38,0xE1, ++ 0xF7,0x1A,0xFF,0x3A,0xD8,0xD8,0xAE,0x06,0x14,0xDA,0x92,0xFD,0x1F,0xF1,0xF0,0x1A, ++ 0xD0,0x00,0xAE,0x06,0x14,0x02,0x92,0x05,0xD9,0x0C,0xC0,0xC0,0xDC,0xDB,0x10,0xC2, ++ 0xC8,0x0E,0x00,0x01,0x88,0x03,0x05,0xC1,0x19,0x01,0xF1,0x02,0xF6,0x1A,0xD7,0x00, ++ 0xAA,0x06,0x10,0x02,0x90,0x3D,0x04,0xD1,0x19,0x11,0xF1,0x02,0xF6,0x1A,0xD7,0x00, ++ 0xAA,0x06,0x10,0x02,0xCC,0x00,0x96,0x05,0xD4,0x1B,0x11,0x1A,0xC8,0x2E,0xD8,0x04, ++ 0xC6,0x03,0xDF,0xDB,0xE4,0xD8,0x12,0xC2,0xC0,0x86,0xD8,0x04,0xC6,0x03,0xDF,0xDB, ++ 0xE4,0xD8,0x12,0xC2,0xCB,0x1E,0x30,0x02,0xD8,0x03,0x48,0x00,0x91,0x03,0x59,0x04, ++ 0x23,0x04,0x59,0x04,0x21,0x04,0x33,0x02,0xBD,0xFF,0xF7,0x9F,0xC3,0x03,0x47,0xF9, ++ 0x92,0x0E,0xE0,0x00,0x85,0x03,0x47,0x44,0x10,0x04,0x03,0x19,0x80,0x03,0xC3,0x0C, ++ 0xDC,0x03,0x82,0x01,0x89,0x03,0xCF,0x03,0xC2,0x8B,0xD1,0x00,0xE0,0x00,0x42,0x11, ++ 0xC3,0x2E,0xC8,0x03,0xC2,0x8B,0xD3,0x00,0xE0,0x00,0x42,0x11,0xCF,0x4E,0xC0,0x03, ++ 0x40,0x11,0x98,0x36,0xCC,0x04,0xD8,0x4B,0x10,0x42,0xC4,0x16,0x07,0x01,0x80,0x03, ++ 0x89,0x03,0xC7,0x83,0x8B,0x03,0xC1,0x83,0x8F,0x03,0xEB,0xF5,0xAF,0x85,0x47,0xF9, ++ 0x88,0x0E,0x00,0x01,0xE9,0x85,0x27,0x21,0x1C,0x02,0x63,0xEA,0xC0,0x00,0xCC,0x00, ++ 0x23,0x31,0x18,0x0A,0xC4,0x48,0x54,0xD2,0xD4,0xE1,0xC1,0x50,0x0A,0xA1,0xF0,0x0A, ++ 0x48,0x01,0xD0,0x06,0x10,0x4A,0x22,0xB1,0xF8,0x22,0x60,0x01,0xD3,0x06,0x10,0x22, ++ 0xCC,0x48,0x60,0xA2,0x10,0x0A,0x9D,0x06,0x08,0x01,0x28,0x71,0x42,0xA4,0xF8,0x2A, ++ 0xD8,0x20,0xAB,0x06,0x10,0x22,0x2B,0x81,0x42,0x94,0xFA,0x2A,0xD8,0x90,0xAA,0x06, ++ 0x15,0x92,0xC2,0x28,0x34,0xE2,0xA0,0x01,0x4C,0x14,0x33,0xA2,0x10,0x52,0xC5,0xF6, ++ 0xC8,0x13,0x54,0x09,0x8B,0x26,0xD8,0x3B,0xCB,0x33,0xF6,0xF8,0x10,0xF2,0xDD,0xA6, ++ 0x50,0x09,0x88,0x3E,0xD4,0x23,0x11,0x62,0x9E,0x26,0xC0,0x03,0x40,0xF1,0xC0,0x0E, ++ 0x40,0x29,0x90,0x56,0x50,0x09,0x88,0x16,0x51,0xC4,0x46,0x81,0x98,0x2E,0x50,0x09, ++ 0x8B,0x2E,0x30,0x02,0x05,0x00,0x12,0x42,0xC0,0x0E,0x00,0x01,0xE8,0x85,0x07,0x09, ++ 0xEF,0x85,0xAF,0xFD,0x84,0x65,0x34,0xB2,0x08,0x01,0x28,0x01,0x00,0x01,0x80,0x1C, ++ 0xC2,0xAC,0xF8,0x23,0x04,0x01,0x30,0x22,0x80,0x3C,0x00,0x27,0xD7,0x6C,0x00,0xF9, ++ 0xA2,0x82,0xE2,0x48,0x95,0x4D,0x16,0x0A,0x98,0xC6,0xD7,0x7C,0x28,0x92,0xC3,0x26, ++ 0xC0,0x7C,0x80,0x2C,0x30,0x82,0x83,0x24,0x03,0x1F,0x30,0x82,0x80,0x2C,0xC0,0x7C, ++ 0x80,0x24,0x00,0x01,0x82,0x34,0x00,0xD7,0x1A,0x01,0x00,0xB7,0x36,0x02,0x03,0xC2, ++ 0x3A,0x00,0x8E,0x86,0x40,0x1A,0x83,0x44,0x00,0x01,0xD0,0xAC,0xF4,0x64,0xF0,0x93, ++ 0x90,0x5C,0x30,0xD2,0x1A,0x12,0x03,0xB8,0xC8,0xD0,0x95,0x54,0x00,0x6F,0xF0,0x3C, ++ 0x07,0x32,0x3E,0x90,0x88,0x3E,0xF0,0x54,0x07,0x38,0xDA,0xB2,0xFD,0x44,0x10,0xF2, ++ 0x90,0x0E,0xB0,0x44,0x32,0x0A,0xE0,0x00,0x90,0x05,0xD6,0x5C,0x17,0x12,0xC4,0x76, ++ 0x70,0xA2,0x02,0x01,0x00,0x78,0xBA,0x4C,0x03,0x87,0x30,0x3A,0x07,0x3A,0x3E,0xF8, ++ 0x88,0x56,0x30,0x3A,0x18,0x3A,0xD3,0x64,0x05,0xF8,0xC3,0xF8,0xD5,0x4C,0xD0,0xFA, ++ 0x10,0xBA,0xC5,0x0E,0x30,0xF2,0x31,0x2A,0xE6,0x00,0x92,0x05,0x2F,0x82,0x9B,0x66, ++ 0x10,0xEA,0x8C,0xA6,0xC4,0x1C,0xC8,0x00,0x80,0x1C,0xC0,0x34,0xE6,0x00,0x92,0x05, ++ 0x80,0x34,0xC0,0x6C,0xA0,0x2A,0x32,0x09,0x30,0x82,0xD1,0x3C,0x00,0x42,0x1C,0x82, ++ 0x90,0x05,0x84,0x3C,0x03,0x72,0x35,0x02,0x1D,0x32,0x90,0x85,0x30,0x22,0xD4,0x2C, ++ 0xC4,0x34,0x10,0x82,0x82,0x1E,0xE0,0xD8,0x93,0xDD,0x2E,0x9A,0x98,0x36,0xD5,0x2C, ++ 0xC4,0x34,0x10,0x82,0x98,0x06,0xC5,0x1C,0x80,0x44,0x10,0x01,0x00,0x01,0x08,0x01, ++ 0x30,0x5A,0x83,0xCB,0x18,0x01,0x08,0x01,0x33,0x62,0x34,0x4A,0xE0,0x4A,0x00,0x0F, ++ 0xE6,0x48,0x92,0x4D,0x36,0xEA,0x00,0x6A,0x3F,0x68,0x8F,0xCE,0xED,0x24,0x10,0x4A, ++ 0x98,0xD6,0x40,0x01,0x8F,0x8E,0x08,0xF9,0x00,0x5F,0xD0,0x6C,0xE3,0x9A,0x28,0x9A, ++ 0x90,0x1E,0xD0,0xAC,0xF4,0x93,0x14,0x12,0xC0,0x0E,0xD0,0x6C,0xA2,0x8A,0xE0,0x00, ++ 0x95,0x05,0x16,0x02,0x98,0x8E,0x87,0x85,0xEA,0x85,0xF7,0x00,0x93,0x05,0x36,0x4A, ++ 0xE0,0x4A,0x28,0x09,0x31,0x62,0x05,0x47,0x33,0x6A,0x18,0x2A,0xFB,0x64,0x00,0x70, ++ 0xCA,0xB0,0x07,0x38,0xDD,0xAA,0xC7,0x50,0x2C,0x09,0x00,0x6A,0x1D,0xEA,0x90,0x5D, ++ 0x31,0x72,0xA3,0x8A,0xED,0x44,0x10,0x52,0x98,0x16,0x28,0x11,0x30,0x62,0x05,0xA7, ++ 0xFA,0x7C,0xE0,0x28,0x10,0xEA,0x9D,0x6E,0x90,0x44,0x08,0x01,0x00,0x27,0xF8,0x6C, ++ 0xE3,0xAA,0xA3,0xEA,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xC6,0xE0,0x8A,0x29,0x09, ++ 0x30,0x62,0x05,0x17,0x90,0x45,0x2F,0x01,0xA3,0xAA,0x31,0x2A,0x6D,0x01,0x80,0x56, ++ 0x33,0x6A,0x18,0x2A,0xFB,0x64,0x00,0x70,0xCA,0xB0,0x07,0x38,0xDA,0xAA,0xDF,0x90, ++ 0x2C,0x09,0x00,0x6A,0x1B,0x5A,0x35,0x6A,0xE2,0x4A,0xE1,0x48,0xA4,0x4A,0x39,0xD7, ++ 0x40,0x40,0x05,0x00,0xF8,0xFF,0x07,0x00,0xAC,0x85,0x87,0x2D,0x33,0x72,0xF8,0x8B, ++ 0x8C,0x14,0x50,0xCA,0xC0,0x20,0xA4,0x24,0xC9,0x14,0x18,0x21,0x31,0xBA,0x31,0xAA, ++ 0x1A,0xCA,0xBA,0x01,0xA8,0x01,0xC6,0x40,0xC0,0x00,0x84,0x1C,0x01,0x67,0xC2,0x03, ++ 0x42,0x79,0x80,0x46,0xC8,0x03,0x37,0x08,0xA0,0xA6,0x41,0x21,0x88,0x16,0x01,0x71, ++ 0xF0,0x02,0x81,0x0C,0x01,0x81,0xF0,0x02,0x81,0x04,0x30,0x92,0x09,0x49,0x30,0x02, ++ 0xB8,0xFF,0xEF,0xFF,0x0B,0x71,0xF0,0x0A,0xC0,0x0C,0xD0,0x40,0xAA,0x06,0x10,0x02, ++ 0x90,0x0D,0x00,0x81,0xF0,0x02,0xD1,0x04,0xD0,0x00,0xAC,0x06,0x12,0x02,0xC2,0x00, ++ 0x91,0x05,0xD8,0x4B,0x44,0x48,0x14,0x0A,0xE8,0x5E,0xC0,0x0C,0x08,0x04,0xC7,0x04, ++ 0x10,0x04,0x01,0x37,0x40,0x21,0x90,0x26,0xF8,0x83,0x41,0x11,0x91,0x0E,0x00,0x01, ++ 0x87,0x03,0x05,0xF9,0x8B,0x03,0x89,0x03,0xC7,0x03,0xDF,0xCB,0x10,0x42,0xC4,0x0E, ++ 0x07,0x01,0x88,0x03,0xCA,0x03,0x37,0x00,0x77,0x00,0x8A,0x03,0x40,0x01,0x80,0x0E, ++ 0xF7,0x00,0x8A,0x03,0xC8,0x03,0x47,0x01,0x8B,0x2E,0xC0,0x03,0x44,0x00,0x04,0x00, ++ 0x80,0x03,0x03,0x01,0x81,0x03,0xA5,0x21,0xC5,0x1C,0x10,0x02,0xC0,0x7E,0x0D,0x01, ++ 0x11,0x01,0xB8,0x93,0xC0,0x24,0x00,0x87,0xC0,0x1B,0xE0,0x14,0x10,0x1A,0x95,0x56, ++ 0xC7,0x1B,0xDE,0xE3,0x32,0xD8,0x72,0xD8,0x10,0x1A,0xCD,0x26,0xC1,0x1B,0x5C,0x01, ++ 0x80,0x0E,0x08,0x09,0x04,0x27,0x80,0x13,0x80,0x21,0xD9,0x1C,0x17,0x1A,0xC4,0x5E, ++ 0x49,0x01,0x80,0x5E,0xC1,0x24,0x00,0x37,0x80,0x13,0xC4,0x0B,0xDC,0x14,0x10,0xCA, ++ 0x96,0x06,0xC1,0x0B,0xDA,0xDB,0x37,0x48,0x74,0x48,0x12,0xCA,0xC8,0xD6,0x08,0x09, ++ 0x81,0x0B,0xFC,0x8B,0xE1,0x48,0xBA,0x8B,0x0A,0x71,0xF0,0x0A,0x48,0x01,0xD0,0x0E, ++ 0x08,0x14,0x06,0x27,0x44,0x5C,0x11,0xCA,0xE9,0x0E,0x40,0x4C,0x08,0x0C,0x0E,0x81, ++ 0xF0,0x0A,0x4A,0x01,0xD0,0x0E,0x10,0x14,0x03,0x27,0x40,0x5C,0x10,0xCA,0xEC,0x0E, ++ 0x40,0x4C,0x13,0x0C,0x80,0x21,0xC9,0x1C,0x16,0x0A,0xC4,0xAE,0x87,0x2D,0xE8,0x85, ++ 0xAC,0x85,0x87,0x3D,0x30,0x2A,0x30,0x62,0x41,0x1A,0xC2,0x40,0x08,0xB9,0xED,0x4A, ++ 0x4B,0x29,0x80,0xE6,0x0C,0x09,0x06,0x48,0xC2,0x70,0x4B,0x02,0xC0,0x48,0x8B,0x1C, ++ 0x0E,0x19,0x03,0x48,0xC0,0x48,0x8B,0x14,0x0F,0x01,0x10,0xF9,0x18,0x79,0x00,0x3F, ++ 0xA6,0x92,0xCB,0x3B,0x78,0x01,0x88,0x06,0x82,0x1B,0xE0,0x48,0x91,0x4D,0x86,0x21, ++ 0xFC,0x3B,0x13,0x7A,0xC0,0xA6,0x07,0x01,0x85,0x34,0xF0,0x03,0x42,0x01,0x80,0xCE, ++ 0xB1,0x04,0x30,0x0A,0x30,0x42,0x59,0x2D,0xD7,0x14,0xB8,0xFF,0xD8,0x0F,0x84,0x34, ++ 0xC0,0x34,0x40,0x01,0x88,0x76,0x30,0x01,0x01,0x47,0x30,0x5A,0x37,0x92,0x09,0xF9, ++ 0x00,0x09,0xA0,0x04,0xB8,0xFF,0xEF,0xEF,0xE7,0xB0,0x93,0xB5,0xF5,0x03,0x15,0x82, ++ 0xC1,0x9E,0x07,0xFF,0xC0,0x34,0x40,0x09,0x89,0x96,0xC0,0xB3,0x31,0x1A,0x31,0x52, ++ 0x09,0x01,0x30,0x82,0xBE,0xFF,0xEF,0x17,0x40,0x01,0x80,0x0E,0x00,0x01,0x00,0x07, ++ 0x01,0x09,0x30,0x5A,0x11,0x01,0x30,0x8A,0xA7,0x04,0xB8,0xFF,0xE9,0x17,0x00,0x4F, ++ 0xA5,0x04,0xF0,0x3B,0x30,0x5A,0xEB,0xD3,0x30,0xDA,0xC9,0x1C,0xC7,0x14,0xB8,0xFF, ++ 0xF0,0x07,0x38,0x01,0x00,0xDF,0xC0,0x1C,0xEF,0x02,0x46,0xF9,0x81,0x16,0xE0,0x82, ++ 0x80,0x24,0x00,0x0F,0x00,0xF9,0x87,0x24,0x31,0x1A,0x31,0x52,0x30,0xCA,0xC1,0x24, ++ 0xBC,0xFF,0xEF,0xE7,0x40,0x01,0x80,0x0E,0x00,0x01,0x00,0x07,0x01,0x09,0x30,0x5A, ++ 0x30,0xD2,0xA1,0x04,0xCF,0x24,0xB8,0xFF,0xE3,0xE7,0xE6,0xF8,0x95,0xFD,0xF7,0x03, ++ 0x17,0xC2,0xC5,0x06,0x31,0x0A,0x31,0x42,0xD7,0x34,0xB8,0xFF,0xF0,0x6F,0x86,0x3D, ++ 0xE8,0x85,0x07,0x01,0x38,0x82,0x03,0x00,0x40,0x40,0x05,0x00,0x18,0x70,0x00,0x00, ++ 0xAE,0xFD,0x87,0x5D,0xC2,0xAC,0xDA,0x03,0x82,0xD4,0xC1,0xAC,0xD9,0x03,0x80,0xCC, ++ 0x01,0x09,0x58,0x45,0x89,0xC3,0xC0,0xCC,0xE2,0x00,0x8A,0xC3,0xC4,0xCC,0x89,0xC3, ++ 0xC2,0xCC,0xF1,0x00,0x8A,0xC3,0xC6,0xAC,0x82,0x01,0x86,0x54,0xE0,0x0B,0x00,0x21, ++ 0x1A,0x0A,0xC0,0x54,0xA2,0x0B,0xC0,0xAC,0xCA,0x03,0x42,0x00,0x80,0xDC,0x09,0x01, ++ 0x40,0xBD,0x31,0x52,0x00,0x36,0x00,0x01,0x82,0xFC,0xC0,0xAC,0xCD,0xB4,0x82,0x01, ++ 0x82,0x4C,0xC2,0xAC,0x82,0x01,0x84,0x44,0xC0,0x74,0x4A,0x11,0x92,0x05,0x82,0x3C, ++ 0xC2,0x6C,0x92,0x05,0x83,0x34,0x82,0xBE,0x10,0x01,0x00,0x01,0x4C,0x4D,0xB1,0x4A, ++ 0x8F,0x2C,0x4A,0xF2,0xB2,0x4A,0x8C,0x24,0x48,0xE2,0xEF,0x48,0xB2,0x4A,0x8C,0x1C, ++ 0x04,0x08,0xC4,0x48,0x91,0x4D,0x66,0xA5,0xDB,0x74,0xA2,0x1A,0x62,0x8D,0xD9,0x6C, ++ 0xA2,0x1A,0xDB,0x24,0x9A,0x3C,0xD9,0x1C,0x9A,0x34,0xD9,0x2C,0x98,0x2C,0x41,0x09, ++ 0x89,0x5E,0xD8,0x3C,0x12,0xDA,0x92,0xDD,0x99,0x3C,0xD9,0x34,0x12,0xDA,0x92,0xDD, ++ 0x99,0x34,0xD9,0x2C,0x12,0xDA,0x92,0xDD,0x9A,0x2C,0xD9,0x5C,0x32,0xE2,0xDC,0x64, ++ 0x9A,0x64,0xD9,0x34,0xE1,0x3C,0xEA,0x34,0xCA,0xD8,0x92,0xDD,0xEB,0x3C,0xC9,0x20, ++ 0x91,0x25,0xF3,0x2C,0xED,0x64,0xC9,0x68,0xA8,0x64,0x59,0x01,0xD9,0x86,0xEB,0xD4, ++ 0x13,0x5A,0xD5,0x6E,0x63,0x01,0xD8,0x5E,0xED,0xCC,0x11,0x62,0xD1,0x46,0xEB,0x64, ++ 0xC5,0x6B,0x49,0x68,0x8B,0x06,0x32,0x2A,0x3F,0x01,0xF8,0x7A,0xEB,0x2C,0x01,0x68, ++ 0x23,0x62,0x35,0x32,0x2B,0x01,0xF8,0xAA,0xF5,0xDC,0x11,0xAA,0xEA,0xC6,0xF2,0xB4, ++ 0x71,0x09,0x88,0x16,0xD9,0xF0,0x93,0xB5,0xB2,0x9C,0xF8,0x5C,0x35,0x01,0xF8,0xF2, ++ 0x10,0x72,0xDD,0x06,0x35,0xAA,0x81,0x68,0x01,0x68,0x33,0x7A,0xF3,0x9C,0x10,0x6A, ++ 0x12,0xAA,0xE5,0x2E,0x6B,0xA5,0xA1,0x62,0x6B,0x8D,0xA1,0x5A,0x01,0xA8,0x72,0xBD, ++ 0xC9,0x68,0xE5,0x72,0xE1,0xB0,0xA3,0x72,0xEB,0xFC,0xE0,0x68,0x90,0x6D,0xAF,0xFC, ++ 0xF5,0x9C,0x10,0xBA,0xD1,0xBE,0x05,0x9F,0x09,0xEF,0x6A,0xA5,0xA1,0x62,0x6B,0x8D, ++ 0xA2,0x5A,0x03,0xB0,0x6B,0xBD,0xC9,0xA8,0xE3,0x72,0xE1,0xB0,0xA0,0x72,0xE9,0xFC, ++ 0xE7,0x68,0x93,0x6D,0xAD,0xFC,0x38,0x37,0xE9,0x64,0xC1,0x6B,0x48,0x68,0x6D,0x19, ++ 0x8A,0x6E,0x00,0xB0,0x7F,0xBD,0xC9,0xB0,0xE0,0xB2,0x71,0x09,0xC2,0x3E,0xC0,0x64, ++ 0x08,0x01,0xC6,0x03,0x1A,0x42,0xC8,0x64,0x82,0x43,0x80,0x7D,0xE8,0x85,0x6F,0x11, ++ 0x89,0x56,0x68,0xA5,0xA1,0x62,0x63,0x8D,0xA2,0x1A,0x03,0x98,0x4A,0xBD,0xC1,0xC8, ++ 0xE2,0x5A,0xE0,0xD8,0xA0,0x5A,0x00,0x1F,0xCA,0x4C,0xF2,0x4B,0x4F,0x51,0x90,0x66, ++ 0xE6,0x00,0x92,0x05,0x40,0x11,0x90,0x06,0x3A,0xD7,0xE2,0x90,0x90,0x95,0x56,0x21, ++ 0x92,0x06,0x38,0x57,0x01,0x01,0x80,0x6C,0xC0,0xB4,0x42,0x09,0x88,0xF6,0x03,0x01, ++ 0x80,0x84,0x01,0x01,0x81,0x7C,0xC9,0x84,0x42,0xBD,0x01,0x48,0xC2,0x40,0x80,0x14, ++ 0xC1,0x7C,0xC9,0x84,0x02,0x00,0xC4,0x00,0x91,0x05,0x86,0x54,0xCA,0x7C,0xC1,0x14, ++ 0xE0,0x2A,0x6A,0x09,0xC1,0x26,0xC0,0x6C,0xE6,0x00,0x92,0x05,0x87,0x6C,0x01,0x8F, ++ 0xC0,0x7C,0x41,0x09,0x89,0x16,0xC0,0x84,0x47,0x01,0x88,0xC6,0x08,0x81,0x41,0x45, ++ 0x86,0x1F,0xC0,0x77,0xC0,0x6C,0x82,0x3C,0xC0,0x74,0x82,0x34,0xC0,0x5C,0x82,0x0C, ++ 0xC0,0x64,0x82,0x04,0xC4,0x84,0xE1,0x00,0x3C,0x00,0x7C,0x00,0x50,0x5A,0xB4,0xA2, ++ 0xE8,0x98,0xB0,0xCA,0x31,0x62,0x74,0x4D,0xB1,0x8A,0xC1,0x84,0xB0,0x82,0x80,0x24, ++ 0xC0,0x84,0xB1,0xC2,0x81,0x1C,0xD0,0x84,0xB0,0x82,0x85,0x14,0xC0,0x7C,0x41,0x09, ++ 0x88,0x5E,0xC0,0x24,0x12,0x02,0x92,0x05,0x80,0x24,0xC0,0x1C,0x12,0x02,0x92,0x05, ++ 0x80,0x1C,0xC0,0x14,0x12,0x02,0x92,0x05,0x80,0x14,0x00,0x01,0x83,0x2C,0xE0,0x68, ++ 0xAD,0xF4,0x01,0x9F,0x40,0x61,0x98,0x66,0xC8,0x24,0xC0,0x34,0xD2,0x54,0xD1,0x00, ++ 0x4C,0xA5,0xA1,0x42,0xC8,0x1C,0xC0,0x3C,0xD2,0x54,0xD1,0x00,0x4C,0x8D,0xA1,0x42, ++ 0x00,0x47,0x15,0x01,0xDC,0x0C,0x00,0x28,0xF0,0xD2,0x5C,0x45,0x88,0xD2,0x12,0x01, ++ 0x90,0x74,0xD1,0x3C,0x92,0x95,0x92,0x0C,0xD2,0x34,0x90,0x95,0x91,0x04,0xD2,0x74, ++ 0x50,0x09,0x88,0x3E,0x12,0x12,0x93,0xA5,0x32,0x12,0x13,0x92,0x94,0x95,0x32,0xA2, ++ 0x12,0x4A,0x92,0x4D,0xD2,0x0C,0xDA,0x04,0xF0,0x0C,0x00,0x07,0x01,0xEF,0xB4,0x24, ++ 0xF1,0x04,0xB0,0x64,0x01,0x70,0xB2,0xFC,0x22,0x12,0x93,0x95,0xCA,0xD8,0x90,0xDD, ++ 0xF9,0x24,0xF1,0xFC,0xC9,0xB0,0xB7,0x24,0xF3,0x64,0xC1,0xB0,0xB0,0x64,0x51,0x01, ++ 0xD9,0xBE,0xF0,0xD4,0x10,0x92,0xD5,0xA6,0x58,0x01,0xD8,0x96,0xF5,0xCC,0x11,0x9A, ++ 0xD1,0x7E,0xF8,0x24,0x35,0x01,0xF8,0xF2,0xF9,0x64,0xC1,0xFB,0x48,0xF8,0x8D,0x46, ++ 0xFD,0xDC,0x11,0xF2,0xE8,0x2E,0x78,0x45,0xCD,0xFA,0xCB,0xF0,0x7B,0x45,0x88,0xF2, ++ 0x39,0xD7,0xD6,0x74,0xE6,0x90,0x92,0x95,0x91,0x74,0xD1,0x74,0x55,0x11,0x98,0xF6, ++ 0x41,0x01,0x80,0xF6,0xF2,0x10,0xF2,0x44,0x00,0x90,0x5C,0x45,0xC7,0xD2,0xCC,0xB3, ++ 0xCC,0xDA,0xCA,0xB0,0x11,0xF2,0x94,0x86,0xD0,0x2C,0x50,0x09,0x88,0x8E,0xD1,0x24, ++ 0xC1,0x34,0xD8,0x54,0xD1,0x00,0x54,0xA5,0xA0,0x82,0xDE,0x1C,0xD1,0x3C,0xE8,0x54, ++ 0xD1,0x90,0x5E,0x8D,0xA8,0xD2,0xEA,0x14,0xDA,0x04,0xD8,0xE8,0x36,0x1A,0xD3,0x90, ++ 0x90,0x95,0xDA,0x00,0x93,0x1D,0xD2,0x40,0x2C,0x01,0x30,0x01,0x50,0x01,0xD8,0x56, ++ 0xFD,0xD4,0x11,0xD2,0xD0,0x3E,0x58,0x01,0xD9,0x2E,0xF8,0xCC,0x10,0xDA,0xD5,0x16, ++ 0xC1,0x3B,0x18,0xBA,0x83,0x3B,0x20,0x12,0x90,0x95,0xCA,0xD8,0x92,0xDD,0xC2,0x00, ++ 0xE7,0x68,0x93,0x6D,0x6F,0x11,0xC8,0x4E,0x04,0xE7,0x10,0x9A,0x90,0x0E,0x10,0x09, ++ 0x90,0x2C,0xD8,0x24,0xD6,0x34,0xC0,0x90,0x90,0x95,0x96,0x34,0xD8,0x1C,0xD0,0x3C, ++ 0xC6,0x90,0x96,0x95,0x90,0x3C,0xD0,0x14,0xDA,0x0C,0x00,0x90,0xC0,0x90,0x96,0x0C, ++ 0xD8,0x14,0xD0,0x04,0xC0,0x90,0x96,0x04,0xE6,0x00,0x92,0x05,0xD4,0xF4,0x11,0x82, ++ 0x92,0x06,0x38,0x3F,0xC2,0x7C,0xE1,0x00,0x91,0x05,0x86,0x7C,0xC0,0x7C,0x41,0x11, ++ 0x97,0x06,0x30,0xAF,0xC2,0x84,0xE1,0x00,0x91,0x05,0x86,0x84,0xC0,0x84,0x41,0x21, ++ 0x97,0x06,0x30,0x37,0x00,0x0F,0x00,0x41,0x81,0x6C,0xC1,0x6C,0x41,0x41,0x88,0xD6, ++ 0x10,0x01,0x00,0x01,0x58,0x8A,0xE8,0xC8,0xB4,0xF2,0xB4,0x7A,0x31,0x8A,0x31,0xDA, ++ 0x40,0x09,0x88,0x1E,0x12,0x4A,0x92,0x4D,0x12,0xDA,0x92,0xDD,0xE7,0x6C,0xC2,0x18, ++ 0x92,0xDD,0xE2,0x74,0xC2,0x08,0x93,0x65,0x04,0x08,0xC4,0x48,0x90,0x4D,0x5E,0x01, ++ 0xD9,0x76,0xE8,0xD4,0x10,0x5A,0xD5,0x5E,0x60,0x01,0xD8,0x4E,0xED,0xCC,0x11,0x62, ++ 0xD1,0x36,0x68,0xA5,0xA1,0x62,0x63,0x8D,0xA0,0x1A,0x03,0x3F,0xE8,0x62,0x00,0x00, ++ 0x62,0xA5,0xD9,0x74,0xA1,0x1A,0x63,0x8D,0xDB,0x6C,0xA2,0x1A,0xE6,0x00,0x92,0x05, ++ 0x46,0x11,0x98,0x9E,0xE6,0x90,0x92,0x95,0x56,0x21,0x98,0x56,0x58,0x85,0xE1,0xC3, ++ 0xB0,0xC3,0xC8,0xC3,0x98,0xC3,0x00,0x01,0x81,0x04,0x59,0x85,0xE0,0xC3,0xB0,0xC3, ++ 0xC8,0xC3,0x98,0xC3,0x00,0x01,0x80,0xE4,0x80,0xEC,0x80,0xF4,0xC4,0xAC,0xCA,0x03, ++ 0x80,0xDC,0x01,0x01,0x08,0x01,0x78,0xA5,0x06,0x18,0xCE,0xD0,0x32,0xA2,0x04,0x20, ++ 0xC6,0x10,0x93,0x95,0x6D,0xA5,0xE1,0x72,0x33,0x2A,0xA3,0x72,0x6D,0x8D,0xE1,0x6A, ++ 0x32,0x12,0xC3,0x90,0x8A,0xAB,0xE0,0x48,0x90,0x4D,0x4E,0x19,0x98,0x86,0x47,0x09, ++ 0x80,0x0E,0x40,0x19,0x8F,0x66,0xE0,0xCA,0x33,0xE2,0x31,0x12,0xCB,0x93,0x30,0x2A, ++ 0xC7,0x6B,0xA5,0x2A,0x34,0x1A,0xCB,0xE3,0x8C,0xE3,0x80,0xCB,0x34,0x0A,0x8B,0x53, ++ 0x09,0x09,0x88,0x14,0x09,0x01,0x88,0x7C,0xD3,0x7C,0x31,0x0A,0xE1,0x4A,0xDC,0x7C, ++ 0x36,0x12,0xC3,0x90,0xCA,0x9B,0xC0,0xAB,0xC9,0x93,0x92,0x1C,0xD0,0x7C,0x51,0x01, ++ 0x88,0x16,0x41,0x01,0x80,0x0E,0x40,0x19,0x8D,0x5E,0x10,0x4A,0x98,0x4E,0x10,0x09, ++ 0x90,0x0C,0x41,0x01,0x8A,0x16,0xF0,0x10,0x90,0x14,0x01,0xF7,0x11,0x09,0x90,0x14, ++ 0x00,0xDF,0x40,0x09,0x80,0x0E,0x40,0x11,0x8D,0x5E,0x10,0x4A,0xC0,0x4E,0x10,0x09, ++ 0x90,0x0C,0x41,0x09,0x8C,0x16,0xF0,0x10,0x90,0x14,0x01,0x77,0x11,0x09,0x90,0x14, ++ 0x00,0x5F,0x10,0x01,0x90,0x0C,0x01,0x47,0x11,0x09,0x90,0x0C,0x40,0x11,0x90,0x16, ++ 0xF1,0x90,0x94,0x14,0x00,0x0F,0x10,0x09,0x90,0x14,0x41,0x01,0x80,0x0E,0x40,0x19, ++ 0x8D,0x0E,0x10,0x4A,0x90,0x2E,0x40,0x09,0x80,0x0E,0x40,0x11,0x8D,0x26,0x10,0x4A, ++ 0xC0,0x16,0x10,0x09,0x94,0x5C,0x01,0x8F,0x11,0x01,0x90,0x5C,0x01,0x77,0xD4,0xCC, ++ 0x32,0x3A,0x19,0xBA,0xD1,0xA4,0xF2,0xEC,0xC4,0xD0,0xCD,0x90,0x91,0x64,0xD1,0x64, ++ 0xC1,0x93,0x90,0xE4,0x31,0x90,0xA2,0xD6,0xF3,0xA4,0x02,0xD0,0xC9,0x90,0xF4,0x44, ++ 0x04,0xB0,0xCB,0x90,0x31,0x19,0x10,0xB0,0xC8,0xB0,0x14,0x21,0xF1,0x92,0xF5,0xDC, ++ 0x10,0x92,0xD5,0x26,0xF0,0x6C,0x71,0x41,0x88,0xC6,0x50,0x01,0xD9,0xB6,0xF0,0xE4, ++ 0x48,0xB0,0x87,0x06,0x80,0x90,0xF2,0xE4,0xC0,0xB0,0xB5,0xE4,0xF0,0x44,0xF9,0xF4, ++ 0x1F,0xB2,0xCA,0xB0,0xB0,0xF4,0xF0,0xEC,0x1C,0x12,0xCB,0x90,0x91,0xEC,0xD0,0x04, ++ 0xE4,0x90,0x92,0x95,0x91,0x04,0xD1,0xE4,0x48,0x90,0x8E,0xEE,0xD0,0x44,0xF2,0xFC, ++ 0xCD,0x93,0x12,0x92,0xC1,0x2E,0xD0,0xE4,0x31,0x01,0x1E,0x92,0xF1,0x64,0x81,0x93, ++ 0x01,0x47,0xD0,0xE4,0x31,0x01,0x1A,0x92,0xF1,0x64,0x81,0x93,0x01,0x17,0xD0,0x0C, ++ 0x50,0x09,0x80,0x4E,0xD0,0x0C,0x51,0x09,0x8A,0x36,0xD0,0x6C,0x10,0xA2,0x84,0x1E, ++ 0xD5,0x14,0xC1,0x10,0x95,0xA5,0x3A,0x57,0x10,0x4A,0x8D,0xDE,0xD4,0x1C,0x11,0x9A, ++ 0x89,0xC6,0xC8,0x7C,0xE6,0x48,0x92,0x4D,0x89,0x7C,0xC9,0x7C,0x48,0x11,0x90,0x06, ++ 0x3A,0x97,0xE2,0x00,0x90,0x05,0x46,0x21,0x91,0x06,0x38,0x1F,0xC2,0x4C,0xF2,0x03, ++ 0x42,0x01,0x88,0x5E,0xC9,0xAC,0x8A,0x01,0xD8,0x43,0x36,0x10,0xAA,0x36,0x31,0x00, ++ 0x71,0x00,0x04,0x27,0xD0,0x5C,0x51,0x01,0x8D,0x5E,0x10,0x4A,0xCA,0x16,0xF0,0x48, ++ 0x90,0x4D,0x06,0x1F,0x10,0x4A,0x95,0x0E,0xE6,0x48,0x92,0x4D,0x11,0x09,0x90,0x5C, ++ 0x01,0x67,0xD0,0x1C,0x10,0x9A,0xCC,0x16,0xF6,0xD8,0x92,0xDD,0x01,0x27,0xD0,0x1C, ++ 0x10,0x9A,0x94,0x0E,0xE6,0xD8,0x92,0xDD,0x11,0x01,0x90,0x5C,0x91,0x55,0x92,0x44, ++ 0x97,0xE5,0x72,0xFA,0xD4,0x44,0xC9,0x90,0x93,0xEC,0x39,0x47,0x02,0x01,0xD0,0xAC, ++ 0x6C,0x94,0x12,0x12,0x9A,0xD6,0xC0,0xAC,0xE4,0x4B,0x68,0x04,0x10,0x42,0x9C,0x26, ++ 0xC4,0x44,0xCA,0x03,0xF6,0x00,0x94,0x05,0x02,0x1F,0xC0,0x44,0xCC,0x03,0xE4,0x00, ++ 0x91,0x05,0xCE,0x04,0x10,0x0A,0x9C,0x4E,0xC0,0xAC,0x0A,0x01,0xB2,0x0B,0xC4,0x54, ++ 0x08,0xD9,0xE7,0x03,0x02,0x42,0xC8,0x54,0xA2,0x43,0x28,0x37,0x27,0x01,0x30,0xF9, ++ 0xB0,0x09,0x60,0x01,0x8A,0x4E,0xC0,0x3C,0xC8,0xCC,0xF9,0xF4,0xD2,0x54,0x42,0x93, ++ 0x97,0x9C,0x50,0x42,0xDE,0x74,0xB2,0xAA,0x02,0x47,0xC0,0x34,0xC8,0xD4,0xF9,0xEC, ++ 0xD4,0x54,0x42,0x93,0x97,0x9C,0x50,0x22,0xDE,0x6C,0xB2,0xAA,0x40,0x01,0x80,0x16, ++ 0xF4,0x48,0x12,0x42,0x8A,0x8E,0xD0,0x74,0x96,0x04,0x90,0x05,0x32,0x0A,0xD9,0x6C, ++ 0xD7,0x5C,0xBA,0xEF,0xD1,0x77,0x37,0x8A,0x10,0x82,0xED,0x0E,0x30,0x42,0x00,0x17, ++ 0x40,0x01,0xD0,0x06,0x02,0x01,0xC8,0x28,0x04,0x07,0xA8,0x01,0x10,0xC0,0xC9,0xE4, ++ 0x81,0x17,0xF0,0x47,0xCA,0x9C,0xC8,0x00,0x18,0x42,0x42,0x01,0xD0,0x06,0x00,0x01, ++ 0xA0,0x00,0x60,0x01,0x8A,0x7E,0xC8,0x54,0x44,0x4C,0x10,0x0A,0xD0,0x06,0x30,0x42, ++ 0xC8,0xAC,0x12,0x31,0xF2,0x4B,0x1C,0x8A,0xD4,0xA4,0xC2,0x48,0x12,0x19,0x0A,0x90, ++ 0xC4,0x48,0x0C,0x44,0x02,0x77,0xC8,0x54,0x44,0x4C,0x12,0x0A,0xD0,0x06,0x30,0x42, ++ 0xC8,0xAC,0x12,0x31,0xF2,0x4B,0x1C,0x8A,0xD4,0xA4,0xC2,0x48,0x12,0x19,0x0A,0x90, ++ 0xC6,0x48,0x0C,0x44,0xE7,0x20,0x93,0x25,0x65,0x09,0xC8,0x16,0xC0,0xAC,0x12,0x31, ++ 0xD8,0x0B,0xC6,0xE4,0x02,0x42,0xCE,0xAC,0xF2,0x4B,0x1C,0x8A,0xD4,0xA4,0xC2,0x48, ++ 0x12,0x19,0x0A,0x90,0xC0,0x48,0x14,0x44,0xC2,0xAC,0xCA,0x74,0xF2,0x03,0x04,0x10, ++ 0xC0,0xA4,0xC2,0x90,0x04,0x09,0x09,0x00,0xC0,0x90,0xB0,0x8B,0xCA,0xAC,0xD2,0x6C, ++ 0xF2,0x4B,0x04,0x58,0xCA,0xA4,0xC2,0xC8,0xC2,0x40,0xB0,0x13,0xC2,0xAC,0xCA,0xAC, ++ 0xF2,0x03,0xE4,0x00,0xB6,0x43,0x24,0x07,0xAC,0xFD,0x87,0xDD,0xF4,0x24,0x31,0xB2, ++ 0x33,0xFA,0xD8,0x83,0x81,0x94,0xD8,0x83,0x81,0x8C,0xC8,0x83,0x80,0x84,0x00,0x01, ++ 0x85,0x6C,0x40,0x32,0x41,0x0B,0x32,0x82,0x80,0x01,0x85,0xD4,0x48,0x01,0x80,0x1E, ++ 0xC2,0x84,0x40,0x00,0x80,0x74,0x00,0x67,0xC2,0xD4,0xF0,0x03,0x40,0x51,0x98,0x26, ++ 0xC8,0xD4,0x00,0xD9,0xB0,0x42,0x80,0x74,0x00,0x1F,0xC8,0xD4,0x00,0xD1,0xB0,0x42, ++ 0x86,0x74,0x08,0x09,0x03,0x48,0xC4,0xC8,0xC0,0xDC,0x88,0xCC,0x41,0x01,0x80,0xEE, ++ 0x04,0x29,0x04,0x00,0xC1,0xD8,0x31,0xCA,0x89,0xF9,0x8F,0x29,0xE0,0xCC,0xC0,0x84, ++ 0x42,0x00,0x12,0x02,0x90,0x05,0x82,0x6C,0x04,0x01,0x30,0x22,0x00,0x8F,0x00,0x01, ++ 0x00,0x47,0xC0,0xEB,0xC5,0x53,0xD0,0x68,0x05,0x2C,0xE1,0x20,0xE2,0xD8,0xE2,0x48, ++ 0xE6,0x00,0x92,0x05,0xED,0x8C,0x10,0x42,0x9B,0x9E,0x37,0x02,0xE6,0x00,0x92,0x05, ++ 0x30,0x22,0xC4,0x94,0x2F,0x22,0x9C,0x56,0x30,0x82,0x43,0x01,0x84,0x06,0x38,0x02, ++ 0x06,0xC9,0x07,0x00,0xC7,0xD8,0x01,0xF9,0x01,0x00,0xC6,0xC0,0x4B,0x02,0xC4,0xC8, ++ 0x10,0x01,0x00,0x47,0x40,0x24,0x40,0x6C,0xD8,0x20,0x03,0xE4,0xE4,0xD8,0xE4,0x00, ++ 0xE2,0x48,0xE4,0x90,0x90,0x95,0xE6,0x8C,0x17,0x12,0x9D,0x9E,0x41,0xA2,0xC3,0xC0, ++ 0x80,0x64,0xE8,0xCC,0x00,0x01,0x80,0x9C,0x34,0x82,0x81,0x01,0x83,0xC4,0xC0,0x01, ++ 0x85,0xBC,0x80,0x01,0x85,0xB4,0x08,0x8F,0x25,0x01,0x08,0x3F,0xC0,0x64,0xC0,0x03, ++ 0x4B,0x00,0x8C,0xF6,0xF0,0x42,0xC9,0x84,0x13,0x42,0xDC,0xD6,0xC3,0x8C,0x30,0x5A, ++ 0x01,0x00,0xD2,0x48,0x31,0x52,0xD0,0x01,0x5C,0x94,0x1E,0xD4,0x46,0x54,0x18,0xD4, ++ 0x40,0x4C,0x22,0xCC,0x31,0x4A,0xC9,0x01,0x5A,0x4C,0x26,0xCC,0x44,0x4C,0x21,0xCC, ++ 0x46,0x4C,0x23,0xCC,0xC8,0x08,0x32,0x52,0xD6,0x01,0x59,0x94,0x29,0xD4,0xD0,0x42, ++ 0x2A,0xC4,0x42,0x44,0x28,0xC4,0x44,0x3D,0x60,0x01,0x88,0x66,0x0C,0x01,0x18,0xCC, ++ 0x20,0xCC,0x2A,0xCC,0x10,0xCC,0x0C,0xF9,0x0B,0x48,0xC4,0xC8,0x4E,0x54,0x10,0xD4, ++ 0x48,0x4C,0x1A,0xCC,0x00,0x87,0xC9,0x8C,0xF4,0x48,0x12,0x62,0x88,0xC6,0x10,0x01, ++ 0x30,0x5A,0x23,0xD4,0x24,0xD4,0x2E,0xD4,0xD0,0x8C,0x18,0xF9,0xF2,0x90,0x04,0x90, ++ 0xCC,0x90,0x0E,0xD8,0xC0,0x90,0x4E,0x94,0x34,0x5A,0x13,0xD4,0x06,0x48,0xCA,0x50, ++ 0x0C,0xF9,0x08,0x48,0xC0,0x88,0x4A,0x4C,0x10,0xCC,0x0E,0x01,0x18,0xCC,0x00,0x9F, ++ 0xF2,0x08,0x03,0x48,0xC8,0x50,0x0E,0xF9,0x0A,0x48,0xC4,0x90,0x4B,0x94,0x30,0x5A, ++ 0x13,0xD4,0x04,0x10,0xCA,0x90,0xC6,0x90,0x4E,0x94,0x10,0xD4,0xE2,0x10,0x03,0x90, ++ 0xCA,0x90,0xC6,0x88,0x48,0x4C,0x18,0xCC,0xC8,0x9C,0x48,0x01,0x8B,0x26,0x30,0x5A, ++ 0x1E,0xCC,0x1C,0xCC,0x20,0xCC,0x00,0x4F,0xC8,0x94,0xD0,0x9C,0xF4,0x48,0x12,0x52, ++ 0x88,0x26,0x08,0x01,0x30,0x5A,0x2B,0xCC,0x2C,0xCC,0x2A,0xCC,0x0B,0x01,0xF0,0x4A, ++ 0x33,0x62,0x34,0x5A,0x14,0xE1,0xF0,0xD2,0x10,0x52,0xE4,0x16,0x14,0xF1,0xF0,0xD2, ++ 0x04,0x07,0x00,0x07,0x13,0x52,0xD4,0xF6,0x14,0x01,0xF1,0xD2,0x17,0x52,0xD4,0xD6, ++ 0x14,0x11,0xF1,0xD2,0x17,0x52,0xE4,0x86,0x14,0x31,0xF1,0xD2,0x17,0x52,0xD4,0x96, ++ 0x14,0x41,0xF1,0xD2,0x17,0x52,0xD4,0x76,0x14,0x51,0xF1,0xD2,0x17,0x52,0xE4,0x26, ++ 0x14,0x61,0xF1,0xD2,0x17,0x52,0xE4,0x06,0xCA,0xC4,0xE0,0x4B,0x4B,0x01,0x80,0xCE, ++ 0x0C,0x01,0x30,0x72,0x88,0x14,0x88,0x1C,0x88,0x7C,0x10,0x01,0xC8,0xDC,0x48,0x01, ++ 0x88,0x96,0x8B,0x24,0x1E,0x01,0xF0,0x1A,0xE8,0xC8,0xD2,0x36,0xC0,0xC8,0x94,0x55, ++ 0xCA,0x1C,0xE0,0x48,0x90,0x4D,0x8E,0x1C,0x00,0x2F,0x58,0x51,0xE8,0x1E,0xC8,0x14, ++ 0xE6,0x48,0x92,0x4D,0x8C,0x14,0xE0,0x00,0xCA,0x24,0xE0,0x48,0x90,0x4D,0x8E,0x24, ++ 0xC8,0x24,0x48,0x49,0x9B,0x36,0x37,0x02,0xC0,0x00,0x94,0x05,0xD5,0xBC,0x68,0x8C, ++ 0xE4,0x93,0x10,0x8A,0x98,0x0E,0xC9,0x74,0x10,0x42,0xD4,0xF6,0xC8,0x14,0x48,0x39, ++ 0x98,0x8E,0xC8,0x74,0x84,0x48,0x12,0x0A,0xD8,0xBE,0xC0,0x1C,0x40,0x01,0x00,0x4F, ++ 0x30,0x20,0x06,0x00,0xE0,0xD2,0x07,0x00,0xE0,0xD2,0x06,0x00,0x58,0x80,0x04,0x01, ++ 0x40,0x40,0x01,0x00,0x88,0x4E,0xC0,0xD4,0xF0,0x03,0x42,0x11,0x98,0x0E,0x00,0x09, ++ 0x37,0x32,0x4C,0xFA,0xC2,0x43,0xE2,0x00,0x80,0x43,0xC2,0xC4,0xE0,0x03,0x40,0x01, ++ 0x83,0xFE,0x30,0x82,0x40,0x01,0x88,0xE6,0xC2,0xD4,0xF0,0x03,0x40,0x51,0x98,0xC6, ++ 0x30,0x5A,0x03,0xB1,0x08,0x91,0xF1,0xC2,0xF4,0x8A,0x13,0x42,0xD8,0x5E,0x08,0xA1, ++ 0xF2,0xCA,0x82,0x48,0x04,0x07,0x00,0xDF,0x10,0x42,0xDC,0x26,0x0A,0xC1,0xF0,0xCA, ++ 0x84,0x48,0x12,0x42,0xD0,0x2E,0x00,0x09,0x37,0x32,0x4C,0x6A,0xC2,0x43,0xE2,0x00, ++ 0x87,0x43,0x52,0x5A,0xC0,0x83,0x40,0x81,0x97,0x16,0x4A,0x52,0xA2,0x62,0xE0,0x00, ++ 0x81,0x83,0x00,0xEF,0x07,0x57,0x3A,0xFF,0x30,0x1A,0x9B,0x04,0x83,0xC8,0x24,0x0A, ++ 0x90,0x4D,0x88,0x0C,0x08,0x01,0x88,0x24,0xCA,0x6C,0x80,0x48,0x88,0xAC,0x18,0x01, ++ 0xF0,0x1A,0xCE,0xAC,0x9C,0xA4,0x10,0x5A,0xD0,0x6E,0xD8,0xA4,0xCA,0x04,0xC0,0xC8, ++ 0x90,0x4D,0x88,0x04,0xD8,0xA4,0xC8,0x6C,0x10,0x5A,0xD4,0x26,0x32,0x1A,0x83,0xC8, ++ 0x20,0x0A,0x93,0x4D,0x88,0x0C,0xC8,0xA4,0xC0,0x48,0x94,0x55,0xE0,0x00,0xCC,0x24, ++ 0xE6,0x48,0x92,0x4D,0x88,0x24,0xC8,0x24,0x4F,0x49,0x98,0x06,0xC4,0x0C,0x10,0x12, ++ 0xD8,0x66,0xC8,0x74,0xC4,0x04,0x10,0x42,0xD8,0x46,0xC0,0xC4,0xE0,0x03,0x40,0x01, ++ 0x83,0x36,0x30,0x5A,0x00,0xB1,0xF0,0xC2,0x40,0x01,0xD0,0x0E,0x04,0x09,0x30,0x32, ++ 0xC2,0xD4,0xF0,0x03,0x40,0x51,0x98,0x16,0xC0,0xDC,0x40,0x01,0x80,0x46,0x00,0x09, ++ 0x30,0x8A,0x4B,0x01,0x80,0x06,0x00,0x01,0x80,0x7C,0x00,0x0F,0x00,0x09,0x80,0x7C, ++ 0xC0,0x7C,0x40,0x01,0x80,0xA6,0x01,0x09,0xB5,0x83,0x47,0xFA,0x40,0x03,0x42,0x01, ++ 0x88,0x5E,0xC0,0xD4,0xF0,0x03,0x42,0x51,0x90,0x3E,0xC0,0xBC,0x6E,0x8C,0xDB,0x03, ++ 0x32,0x00,0x72,0x00,0x84,0x51,0x10,0x0A,0xC8,0x0E,0x10,0x01,0x00,0x07,0x10,0x09, ++ 0xC0,0xE4,0x40,0x01,0x80,0x06,0x10,0x11,0x91,0x14,0x30,0x1A,0xB8,0x04,0xB0,0x0C, ++ 0x30,0x42,0xD1,0x9C,0xCF,0x64,0xB8,0xFF,0xC8,0x5F,0xC7,0xB4,0xE2,0x03,0x38,0x00, ++ 0xAD,0x1E,0xF0,0x83,0xFC,0x8B,0x13,0x42,0x98,0x56,0xC0,0xB4,0xE2,0x03,0x38,0x00, ++ 0xA7,0x26,0x00,0xF1,0xA8,0x83,0xC9,0xB4,0x04,0x01,0xA0,0x43,0x87,0xFD,0xE8,0x85, ++ 0xE0,0x68,0xC5,0x64,0xE0,0x00,0x82,0x64,0xE7,0x20,0x93,0x25,0xC4,0x8C,0x10,0x22, ++ 0x92,0x06,0x30,0x9F,0xC2,0x9C,0xE0,0x00,0x90,0x05,0x86,0x9C,0xC8,0x94,0xC0,0x9C, ++ 0x10,0x42,0x94,0x06,0x37,0x47,0x3A,0x4F,0xAC,0x9D,0x87,0x3D,0x30,0x3A,0xC0,0x44, ++ 0xD0,0x03,0x84,0x24,0xC6,0x44,0xD0,0x23,0x41,0xC2,0xC4,0xE8,0x06,0xF9,0x07,0x00, ++ 0xC0,0xF0,0xC1,0x44,0x08,0xF1,0xE8,0x03,0x84,0x17,0xD8,0xA7,0x04,0x29,0x04,0x00, ++ 0xC4,0xD0,0x41,0x9A,0x37,0xDA,0x99,0xF9,0xC1,0xC0,0x99,0x29,0x80,0x34,0x48,0xE9, ++ 0x88,0xDE,0x08,0x01,0x00,0x5F,0x00,0x01,0x00,0x2F,0xC0,0xFB,0x82,0xBB,0xE0,0x90, ++ 0xE2,0xD8,0xE2,0x00,0x95,0x05,0x16,0x02,0x9A,0xBE,0xE7,0x48,0x90,0x4D,0xC6,0x24, ++ 0x17,0x0A,0x9C,0x86,0x00,0x01,0x00,0x2F,0x41,0x8C,0x01,0x4C,0xE5,0x68,0xE5,0xB0, ++ 0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0xBE,0x00,0xCF,0xC3,0x44,0x82,0x01,0xF5,0x03, ++ 0x43,0x51,0x98,0xA6,0xC4,0x44,0xF0,0x03,0x80,0x2C,0x40,0x01,0x80,0x7E,0x9B,0x1C, ++ 0xF3,0x34,0x08,0x21,0x1B,0x01,0x00,0x21,0x30,0x32,0x04,0x01,0x30,0x22,0x84,0x14, ++ 0x29,0x01,0x00,0x1F,0x00,0x01,0x80,0x0C,0x01,0x97,0xC0,0xBB,0x48,0xF8,0x85,0x66, ++ 0x10,0x0A,0xCC,0x0E,0x30,0x0A,0x00,0x17,0x10,0x1A,0x94,0x06,0x30,0x1A,0xF8,0x14, ++ 0xE7,0xF8,0x93,0xFD,0xB8,0x14,0x38,0x09,0xBB,0x0C,0xE0,0xB0,0xE6,0x00,0x92,0x05, ++ 0x17,0x02,0x9D,0x56,0xC0,0x0C,0x40,0x01,0x85,0x36,0x28,0x72,0xCD,0x0E,0x30,0x72, ++ 0x05,0x17,0x28,0x62,0x95,0x06,0x30,0x62,0xE7,0x68,0x93,0x6D,0xC4,0x24,0x10,0x2A, ++ 0x98,0xC6,0xC6,0x2C,0x2B,0x51,0x18,0x42,0xED,0x14,0x10,0x42,0xC8,0xB6,0x48,0x01, ++ 0x82,0x0E,0xF0,0x48,0x93,0x4D,0xF6,0x00,0x10,0x1A,0xD4,0x0E,0xE6,0xD8,0x92,0xDD, ++ 0x30,0x82,0x43,0x01,0x82,0x16,0xF0,0x00,0x94,0x05,0x36,0x32,0xEB,0x24,0xF0,0x68, ++ 0x28,0x62,0xD5,0x1E,0x32,0x02,0xE3,0x00,0x94,0x05,0x36,0x22,0x28,0x01,0x00,0xDF, ++ 0x00,0x01,0x00,0xAF,0x10,0x42,0x9C,0x2E,0x28,0xAA,0x9B,0x1E,0x10,0xC2,0xC4,0x0E, ++ 0x28,0x2A,0xCB,0x3E,0xC1,0xB3,0x08,0xB8,0xD8,0xF8,0xF5,0x1C,0xC7,0xB3,0xC9,0xB0, ++ 0x48,0xB0,0x81,0xB3,0xE0,0x90,0xF2,0x1C,0xE0,0xB0,0xB3,0x1C,0xE6,0x00,0x92,0x05, ++ 0x17,0x02,0x9D,0x3E,0xE7,0x68,0x93,0x6D,0xC4,0x24,0x10,0x2A,0x98,0x06,0xC7,0x34, ++ 0x10,0x01,0x00,0x67,0x08,0x01,0x00,0x37,0xC4,0x1B,0x30,0xD8,0x70,0xD8,0x84,0x1B, ++ 0xE2,0x00,0xE2,0x48,0x95,0x4D,0x16,0x0A,0x9A,0xB6,0xE7,0x90,0x90,0x95,0xCE,0x24, ++ 0x17,0x52,0x9C,0x7E,0x87,0x4D,0xE8,0x85,0xAC,0xFD,0x87,0x1D,0x30,0x2A,0x30,0x62, ++ 0x05,0x01,0xB0,0x03,0xB1,0x03,0x37,0x02,0x80,0x01,0xE6,0x0B,0x10,0xE9,0x07,0x52, ++ 0x3E,0x48,0x7A,0x48,0x00,0x48,0x1A,0x52,0xA0,0x13,0xE0,0x0B,0x10,0xD9,0x07,0x8A, ++ 0xA1,0x0B,0x30,0x02,0x80,0x01,0x84,0x14,0xE1,0x03,0x7A,0x4A,0x40,0x01,0x80,0x56, ++ 0x01,0x01,0x50,0x42,0x08,0xF9,0xA7,0x8A,0xE6,0x00,0x92,0x05,0x47,0x81,0x98,0xD6, ++ 0x01,0x01,0x80,0xC3,0x80,0xC3,0xA3,0x04,0x30,0x5A,0x01,0x01,0xD0,0x34,0xC8,0x2C, ++ 0xBE,0xFF,0xE7,0xD7,0x35,0x32,0xB1,0x01,0xF0,0x83,0x43,0x51,0x98,0x36,0xA0,0x04, ++ 0x30,0x5A,0x01,0x09,0xD0,0x34,0xC8,0x2C,0xBE,0xFF,0xE7,0x77,0xC2,0x14,0xE0,0x03, ++ 0x43,0x01,0x80,0xF6,0x45,0xB2,0xF0,0x0B,0xC2,0x03,0x02,0x00,0x10,0x0A,0xCC,0x1E, ++ 0x48,0x9A,0x00,0x01,0x81,0x43,0x02,0xDF,0x48,0x8A,0xC0,0x43,0x30,0x22,0x44,0x21, ++ 0xC0,0xB6,0x01,0x01,0x00,0x8F,0x59,0x7A,0xE7,0xCA,0x48,0xF9,0x80,0x5E,0x11,0x01, ++ 0xE6,0x08,0x92,0x4D,0x00,0x97,0x78,0x5A,0xE3,0xDA,0xE1,0xFA,0xDA,0xD8,0xE6,0xD8, ++ 0x58,0x11,0xC0,0x4E,0x5A,0x32,0xC0,0xD3,0x50,0x01,0x80,0x0E,0xF2,0x90,0x82,0xD3, ++ 0x5F,0x22,0x10,0xF9,0xA0,0xD2,0x10,0x09,0xE6,0x48,0x92,0x4D,0x28,0x0A,0x03,0x4F, ++ 0x00,0xA0,0x00,0x01,0x58,0x00,0x04,0x01,0x58,0x80,0x04,0x01,0x40,0x40,0x01,0x00, ++ 0x30,0x20,0x06,0x00,0x98,0xFE,0x56,0x09,0x8B,0x2E,0x50,0x42,0xC0,0x8B,0x4A,0x01, ++ 0x82,0x0E,0xF0,0x48,0x82,0x8B,0xE2,0x00,0x93,0x05,0x7E,0x22,0x2E,0x02,0x9B,0x56, ++ 0x08,0x01,0xC0,0x14,0xE1,0x1B,0x32,0x02,0x80,0x01,0x59,0x09,0x8A,0x2E,0x50,0xFA, ++ 0xC0,0x93,0x52,0x01,0x80,0x9E,0x08,0x09,0x02,0x8F,0x50,0xE2,0xC0,0x93,0x52,0x01, ++ 0x8E,0x46,0xD8,0x3B,0x6B,0x14,0x33,0xF8,0x75,0xF8,0x13,0xD2,0x9F,0x3E,0xF0,0x13, ++ 0x50,0x01,0x88,0x26,0x68,0x14,0xE5,0x3B,0x10,0xD2,0x9D,0x06,0x08,0x09,0x48,0x01, ++ 0x83,0x2E,0xF0,0x8B,0x48,0x01,0x95,0x3E,0xE3,0x48,0xB2,0x8B,0x03,0x27,0xF0,0x8B, ++ 0x48,0x51,0x90,0x0E,0x0B,0x01,0xB0,0x8B,0xF0,0x8B,0x4B,0x51,0x9A,0x0E,0x51,0x5A, ++ 0xC0,0x93,0x52,0x01,0x8D,0x8E,0xF0,0x3B,0x78,0x01,0x88,0x76,0x58,0x09,0x88,0x26, ++ 0x00,0x07,0x00,0xB7,0xF3,0x48,0xB2,0x8B,0x06,0x3F,0xD8,0x03,0x6A,0x1C,0x33,0x00, ++ 0x74,0x00,0x14,0x1A,0x92,0x0E,0xF0,0x48,0xB0,0x8B,0x53,0x11,0x9D,0x16,0x00,0x01, ++ 0xB0,0x83,0x03,0x37,0x50,0x09,0x88,0x26,0xF2,0x83,0x43,0x81,0x93,0x0E,0x00,0x21, ++ 0xB5,0x83,0xF3,0x0B,0x4B,0x09,0xC8,0x5E,0x07,0x01,0xD0,0x13,0x90,0x04,0x10,0x01, ++ 0x02,0xA7,0x00,0x98,0xC9,0xF0,0x1A,0x09,0x0F,0xD8,0xC4,0x98,0xF0,0xF3,0xF2,0xDB, ++ 0xFA,0x04,0x00,0xD8,0x1B,0xF2,0x03,0xB0,0xCF,0xB0,0xC3,0x98,0x31,0x19,0x10,0xB0, ++ 0xCC,0xD8,0x44,0xDC,0xC4,0xC0,0x90,0x05,0xE6,0x90,0x92,0x95,0x17,0x8A,0xC4,0x46, ++ 0x87,0x17,0xC8,0x47,0x40,0x00,0x82,0x0C,0xC8,0x0B,0xC1,0x0C,0x12,0x0A,0x94,0x3E, ++ 0x0A,0x01,0x00,0x17,0x02,0x40,0xCA,0x10,0x04,0x09,0x09,0x00,0xC2,0x80,0xF0,0x13, ++ 0xF0,0x03,0xD8,0x04,0x02,0x00,0x1A,0xD2,0x02,0x90,0xCA,0x90,0xC0,0x80,0x10,0x19, ++ 0x14,0x90,0xC0,0x10,0x00,0x21,0xF0,0x82,0xD4,0x0C,0x10,0x82,0xD0,0x5E,0x31,0x42, ++ 0x02,0x17,0xE1,0x10,0x36,0xA2,0x94,0x95,0x01,0x98,0x3A,0x09,0xCD,0xD8,0x0A,0xF8, ++ 0xCA,0xD8,0x06,0x30,0x33,0xF2,0xCC,0xB0,0xF7,0xDB,0xC8,0xB0,0xB3,0x9B,0x31,0x9A, ++ 0xF3,0xDB,0xB2,0x9B,0x1A,0x31,0x18,0xD2,0x3A,0x19,0xCA,0x90,0x08,0xF8,0x33,0x31, ++ 0xCB,0x90,0x1E,0x82,0xCC,0x00,0x4A,0x9C,0xCC,0x00,0x0E,0x1C,0x4E,0x9C,0x0E,0x1C, ++ 0x50,0x94,0x10,0x14,0x36,0x12,0x93,0x85,0xF2,0x13,0xF5,0x90,0x16,0x12,0xE4,0xC6, ++ 0xF2,0x03,0xF5,0x00,0xB2,0x03,0xE5,0x48,0x95,0x4D,0xF6,0x03,0x15,0x42,0xC4,0xCE, ++ 0x31,0x0A,0x31,0x42,0xBF,0xFF,0xEF,0x87,0x87,0x3D,0xE8,0x85,0x00,0xA0,0x00,0x01, ++ 0xAC,0xFD,0x87,0x2D,0xE0,0x74,0x00,0x01,0x80,0x1C,0xC0,0x3C,0xD0,0x33,0xC6,0x3C, ++ 0x58,0x04,0x86,0x0C,0xC3,0x34,0x18,0x82,0x50,0xFA,0xCF,0x2C,0xC2,0x48,0xC4,0x08, ++ 0x8F,0x24,0x40,0xF2,0xC0,0x03,0x40,0x09,0x88,0x0E,0xC0,0x3C,0xD8,0x33,0x04,0x01, ++ 0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0x17,0x82,0x9D,0xCE, ++ 0x08,0x01,0x00,0x09,0xD8,0x44,0xD0,0x34,0x86,0x07,0xD0,0x6F,0x28,0x01,0x60,0x01, ++ 0x8B,0x0E,0xE0,0x68,0x90,0x6D,0xFF,0x24,0x08,0x01,0x00,0x5F,0xC1,0xC3,0x19,0x02, ++ 0x91,0x05,0x86,0xC3,0xD4,0x7C,0x10,0x82,0xCD,0x0E,0x18,0x02,0x83,0xC3,0xE1,0xF8, ++ 0xE6,0x48,0x92,0x4D,0x17,0x8A,0x9D,0x8E,0x08,0x09,0xC6,0x2C,0x02,0x48,0xC4,0x00, ++ 0x80,0x14,0xD0,0x44,0x90,0x04,0x00,0x11,0xD8,0x3C,0xD0,0x2C,0xC8,0x34,0x80,0x07, ++ 0xD8,0x07,0xD0,0x44,0xC0,0x3C,0x90,0x04,0x82,0x01,0xCA,0x0B,0x00,0x01,0x1C,0x0A, ++ 0x10,0x01,0xD8,0x3C,0xC0,0x14,0x80,0x0F,0xDD,0xCF,0xDD,0xC0,0x09,0x01,0x00,0x3F, ++ 0xD0,0x14,0x18,0x01,0xF0,0x9A,0xD6,0x0C,0xD0,0xD0,0x94,0x95,0x68,0x01,0x88,0x2E, ++ 0x50,0xC1,0xE8,0xBE,0xC5,0x13,0x18,0x12,0x80,0x13,0x00,0x9F,0x50,0x99,0xE8,0x2E, ++ 0xC0,0x13,0x50,0x01,0x82,0x16,0xF0,0x90,0x80,0x13,0x00,0x5F,0x68,0x29,0x88,0x4E, ++ 0x58,0xE1,0xEE,0x3E,0xC0,0x13,0x50,0x01,0x88,0x26,0xD0,0x1C,0x50,0x01,0x88,0x0E, ++ 0x10,0x09,0x90,0x1C,0xD4,0x14,0xE0,0x90,0x92,0x14,0xE0,0x00,0xE6,0x48,0x92,0x4D, ++ 0x16,0x8A,0x9D,0xAE,0x40,0x20,0x6B,0x21,0xC8,0x0E,0xD5,0x44,0x90,0x04,0x08,0x01, ++ 0x00,0x19,0xD8,0x3C,0xD0,0x2C,0x80,0x07,0xD0,0xE7,0x0D,0x09,0x30,0x42,0xD8,0x44, ++ 0xD0,0x34,0x80,0x07,0xD0,0x07,0xC3,0x1C,0x87,0x4D,0xE8,0x85,0xAC,0xFD,0x87,0x1D, ++ 0xF0,0x64,0x30,0x7A,0x37,0xEA,0xD0,0xC3,0x86,0x14,0x08,0x09,0xC4,0x1C,0x00,0x48, ++ 0xC5,0x20,0x42,0xB2,0xC0,0x03,0x40,0x09,0x8D,0x0E,0xD8,0xC3,0x80,0x14,0x08,0x01, ++ 0x00,0x09,0xD8,0x2C,0xD0,0x6C,0x80,0x07,0xD0,0x37,0xD2,0x2C,0x91,0x04,0x30,0xDA, ++ 0x00,0x11,0xD0,0x1C,0xC8,0x6C,0x80,0x07,0xD0,0xA7,0xD4,0x2C,0x92,0x04,0x00,0x29, ++ 0xEC,0x0A,0x06,0x01,0x19,0x0A,0x30,0xDA,0x11,0x01,0x30,0x02,0x82,0x0F,0xD8,0x77, ++ 0xD0,0x2C,0x90,0x04,0x30,0xDA,0x09,0x01,0x00,0x19,0xD0,0x1C,0x84,0x07,0xD0,0x0F, ++ 0x08,0x09,0x30,0x42,0xD8,0x2C,0xD0,0x6C,0x81,0x07,0xD0,0x2F,0x41,0x02,0x05,0x44, ++ 0x01,0x01,0x00,0x84,0x08,0x01,0x00,0x77,0x01,0x01,0xF0,0x02,0x15,0x01,0xF0,0x52, ++ 0x10,0x12,0xEC,0x06,0x00,0x44,0x11,0x01,0xF4,0x92,0x15,0x12,0xD1,0x06,0x00,0x84, ++ 0xE2,0x20,0xE5,0x48,0x90,0x4D,0xC6,0x14,0x17,0x0A,0x9C,0x6E,0x87,0x3D,0xE8,0x85, ++ 0xAC,0xBD,0x87,0x45,0xC2,0x4C,0xD8,0x03,0x80,0x1C,0xC8,0x4C,0xD0,0x4B,0x8E,0x14, ++ 0x50,0x6A,0xCC,0x44,0xC0,0x48,0x8C,0x3C,0x48,0x62,0xC4,0x4B,0x48,0x09,0x88,0x46, ++ 0xCA,0x1C,0xE0,0x48,0x90,0x4D,0x8E,0x1C,0x80,0x34,0xC0,0x4C,0xD8,0x03,0x84,0x14, ++ 0x00,0x0F,0x00,0x01,0x80,0x34,0xF8,0x34,0x04,0x3F,0x4B,0x32,0x04,0x01,0x00,0x43, ++ 0xC0,0x4C,0xC8,0x3C,0xD3,0x03,0x1E,0xC2,0xC0,0x08,0x02,0x01,0x10,0xF9,0x01,0x1F, ++ 0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0xDC,0x14,0x10,0xC2,0x9C,0xC6,0x27,0x01, ++ 0x31,0x2A,0x31,0x32,0x03,0xC7,0x40,0xE2,0x08,0x23,0x4E,0x25,0xB8,0x0C,0x88,0x04, ++ 0x40,0x45,0x40,0x3E,0x5F,0x2D,0xB8,0xFF,0xFB,0x8F,0x33,0x5A,0x00,0xA1,0xF0,0xC2, ++ 0x40,0xE1,0xD1,0x1E,0x68,0x41,0x80,0x4E,0x18,0x62,0x05,0x1F,0x70,0x01,0x8C,0x0E, ++ 0x30,0x72,0x01,0x1F,0x41,0x68,0x1B,0x62,0x6F,0x01,0x88,0x26,0xC0,0x4C,0xC8,0x3C, ++ 0xD3,0x03,0x1E,0xC2,0xC0,0x08,0x02,0x01,0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48, ++ 0xE6,0x00,0x92,0x05,0xDC,0x14,0x10,0xC2,0x99,0xC6,0x37,0xAA,0x20,0x01,0x00,0x0F, ++ 0x1B,0xA2,0x41,0xB0,0x77,0x01,0x88,0xDE,0xC6,0x4C,0x58,0x04,0xC0,0x41,0x91,0x35, ++ 0x05,0x8F,0x18,0x62,0x46,0x02,0x0B,0x23,0x48,0x25,0xB8,0x0C,0x88,0x04,0x40,0x45, ++ 0x40,0x3E,0x58,0x2D,0xB9,0xFF,0xFF,0xD7,0x30,0x5A,0x03,0x81,0xF5,0xC2,0x10,0x82, ++ 0xE9,0x06,0x18,0x62,0x40,0x68,0x6B,0x01,0x88,0x5E,0xC7,0x44,0x0E,0xE9,0xC9,0x00, ++ 0x0A,0x48,0xC2,0x00,0xAB,0x23,0xE0,0xF8,0x90,0xFD,0xC7,0x1C,0x14,0x3A,0x9C,0xA6, ++ 0xF1,0x34,0x00,0x9F,0xC1,0x44,0x08,0xE9,0xCA,0x00,0x0C,0x48,0xC1,0x38,0xEA,0xC3, ++ 0x40,0x01,0x88,0x0E,0x01,0x09,0xA8,0xC3,0xE8,0xE3,0x29,0x01,0x01,0x01,0x00,0x07, ++ 0xE7,0x68,0x93,0x6D,0x40,0x09,0x88,0x1E,0x60,0xF9,0x97,0x0E,0xE5,0x20,0x93,0x25, ++ 0x48,0x22,0x02,0x01,0x00,0x43,0xAC,0x48,0x46,0x1A,0x0A,0x23,0x20,0x00,0x67,0x10, ++ 0x02,0x07,0x40,0x48,0x30,0x82,0x10,0x42,0x81,0xDE,0x4F,0x01,0xC9,0x06,0x08,0x01, ++ 0x88,0x04,0x90,0x0C,0x40,0x45,0x40,0x6E,0x37,0x8A,0xB9,0xFF,0xF0,0x0F,0x43,0x01, ++ 0x80,0x0E,0x68,0x29,0x99,0xE6,0xAE,0xE3,0xE7,0xB0,0x93,0xB5,0xC4,0x1C,0x10,0x32, ++ 0x98,0x46,0x86,0x5D,0xEF,0x85,0xAF,0xBD,0x80,0x15,0x34,0x62,0x31,0xB2,0x48,0x7A, ++ 0x00,0x01,0x80,0x43,0x40,0x8A,0x41,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B,0x28,0x01, ++ 0x00,0x3F,0x08,0x09,0x31,0x9A,0x31,0x52,0x30,0x42,0x80,0x07,0xCB,0xA7,0xE1,0x68, ++ 0x95,0x6D,0xD7,0x03,0x17,0x42,0xC5,0xA6,0x31,0x12,0x31,0x8A,0x00,0x11,0x80,0x07, ++ 0xC1,0x7F,0x34,0x92,0x30,0x0A,0xC1,0x14,0xB8,0xFF,0xFF,0xD7,0x31,0x12,0x31,0x8A, ++ 0x00,0x01,0x80,0x07,0xC5,0x2F,0xDC,0x03,0x41,0x01,0x80,0x46,0x6F,0xF2,0x40,0x43, ++ 0x91,0x3D,0x4C,0x04,0x00,0x43,0x47,0xCA,0x08,0x09,0x80,0x0B,0x31,0x12,0x31,0x8A, ++ 0x00,0x11,0x80,0x07,0xC1,0xAF,0x33,0x1A,0xB0,0x04,0x08,0x01,0x00,0x09,0xD0,0x14, ++ 0x82,0x07,0xC8,0xFF,0xB3,0x04,0xD8,0x0B,0x30,0x1A,0x01,0x11,0xD0,0x14,0x80,0x07, ++ 0xC9,0xC7,0x32,0x92,0x30,0x0A,0xC1,0x14,0xBF,0xFF,0xF7,0x97,0x31,0x12,0x31,0x8A, ++ 0x00,0x01,0x80,0x07,0xC0,0xEF,0x42,0x4A,0x08,0x01,0x80,0x0B,0x01,0x7B,0x37,0x1A, ++ 0xB0,0x04,0x08,0x01,0x00,0x11,0xD0,0x14,0x82,0x07,0xC8,0x1F,0x31,0x12,0x31,0x8A, ++ 0x00,0x11,0x80,0x07,0xC0,0x6F,0x02,0x5F,0x30,0x20,0x06,0x00,0x00,0xB0,0x00,0x01, ++ 0xF8,0xFB,0x07,0x00,0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42, ++ 0x50,0x1A,0x40,0x83,0x0C,0x11,0x18,0x42,0x00,0x83,0x80,0x2D,0xE8,0x85,0x07,0x00, ++ 0x18,0x00,0x04,0x42,0xA8,0x85,0x31,0x12,0x90,0x01,0xE6,0x9B,0x32,0xD8,0x72,0xD8, ++ 0xA7,0x9B,0x58,0xCA,0x41,0xE3,0x30,0x20,0xA2,0x16,0x40,0xE3,0x3F,0x20,0xAB,0xE6, ++ 0x58,0xB2,0x27,0x41,0x00,0xE3,0x44,0xE3,0x28,0xF9,0xAF,0x19,0x18,0x62,0x01,0xE3, ++ 0x20,0x81,0x48,0x01,0x83,0x76,0x00,0xE9,0x08,0x00,0xE4,0x8B,0x48,0x48,0x8E,0x1E, ++ 0xF0,0x00,0x22,0x00,0x67,0x00,0x88,0xC6,0x40,0x01,0x88,0x16,0x41,0xC3,0x18,0x02, ++ 0x01,0xC3,0xE8,0x85,0x80,0x01,0xE5,0x8B,0x48,0x48,0x8E,0x16,0xE8,0x0B,0x4E,0x31, ++ 0x8E,0xCE,0xEF,0x03,0x47,0x31,0x88,0xA6,0x41,0xC3,0x18,0x02,0x01,0xC3,0xE8,0x85, ++ 0xAA,0x85,0x47,0x63,0x46,0x5B,0xD6,0xAB,0x71,0x0A,0xC7,0xB3,0x70,0x09,0x88,0x16, ++ 0x4A,0x63,0x56,0x5B,0xD8,0xAB,0x44,0x01,0x88,0x0E,0x11,0x01,0x01,0xE7,0x40,0x03, ++ 0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08,0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB, ++ 0x1C,0xF2,0x19,0x33,0x58,0x33,0xC6,0xFB,0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83, ++ 0xC5,0xF3,0x18,0x82,0x31,0x32,0x03,0x83,0x40,0x73,0xC0,0xC3,0x18,0x32,0x04,0x73, ++ 0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95,0x17,0x52,0x9D,0x06,0xE8,0x85,0x47,0x09, ++ 0x88,0x0E,0x11,0x01,0x01,0xE7,0x40,0x03,0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08, ++ 0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB,0x1C,0xF2,0x1D,0x33,0x58,0x33,0xC6,0xFB, ++ 0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83,0xC5,0xF3,0x18,0x82,0x31,0x32,0x03,0x83, ++ 0x40,0x73,0xC0,0xC3,0x18,0x32,0x00,0x73,0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95, ++ 0x17,0x52,0x9D,0x06,0xE8,0x85,0x47,0x11,0x88,0x0E,0x11,0x01,0x01,0xE7,0x40,0x03, ++ 0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08,0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB, ++ 0x1C,0xF2,0x1D,0x33,0x58,0x33,0xC6,0xFB,0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83, ++ 0xC1,0xF3,0x18,0x82,0x31,0x32,0x03,0x83,0x40,0x73,0xC0,0xC3,0x18,0x32,0x04,0x73, ++ 0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95,0x17,0x52,0x9D,0x06,0xE8,0x85,0x47,0x19, ++ 0x88,0xE6,0x17,0x01,0x01,0xE7,0x40,0x03,0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08, ++ 0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB,0x1C,0xF2,0x1D,0x33,0x58,0x33,0xC6,0xFB, ++ 0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83,0xC1,0xF3,0x18,0x82,0x31,0x32,0x03,0x83, ++ 0x40,0x73,0xC0,0xC3,0x18,0x32,0x00,0x73,0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95, ++ 0x17,0x52,0x9D,0x06,0xEF,0x85,0xAF,0x85,0x44,0xE3,0x02,0xB0,0xCE,0x20,0x45,0xEB, ++ 0xC0,0x68,0x45,0x09,0x88,0x26,0x40,0xE3,0xCC,0x20,0x45,0xDB,0xC0,0xE8,0x04,0x3F, ++ 0x79,0x7A,0xC4,0xFB,0x78,0x09,0x88,0x1E,0x4D,0xE3,0xCE,0x20,0x54,0xDB,0xC2,0xE8, ++ 0x40,0x13,0xF9,0xA0,0xC0,0x5B,0x41,0x09,0x88,0x76,0x48,0x01,0x8A,0x66,0x40,0x83, ++ 0x1A,0xC2,0x04,0x83,0x44,0x83,0x1C,0xC2,0x01,0x83,0x44,0x03,0x19,0xC2,0x04,0x03, ++ 0x40,0x83,0x18,0xC2,0x07,0x83,0xE8,0x85,0x48,0x09,0x88,0x66,0x44,0x83,0x1A,0xC2, ++ 0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83,0x44,0x83,0x18,0xC2,0x01,0x83,0x40,0x03, ++ 0x19,0xC2,0x00,0x03,0xE8,0x85,0x4F,0x11,0x89,0x66,0x40,0x03,0x19,0xC2,0x04,0x03, ++ 0x44,0x83,0x18,0xC2,0x02,0x83,0x40,0x83,0x1A,0xC2,0x00,0x83,0x44,0x83,0x1C,0xC2, ++ 0x07,0x83,0xEC,0x85,0x4F,0x19,0x88,0xE6,0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83, ++ 0x18,0xC2,0x04,0x83,0x44,0x83,0x1A,0xC2,0x04,0x83,0x42,0x83,0x1C,0xC2,0x00,0x83, ++ 0xEF,0x85,0xAF,0xFD,0xF4,0x4C,0x30,0x62,0x29,0x01,0x48,0x93,0x4C,0x8B,0x35,0x72, ++ 0xD1,0xE3,0x36,0x3A,0x48,0x32,0xC3,0x4B,0x48,0x09,0x88,0x0E,0x54,0x93,0xD9,0xE3, ++ 0x41,0x19,0x80,0x96,0x33,0x79,0x48,0x0A,0x10,0xB0,0x41,0x11,0x8B,0xB6,0x30,0x02, ++ 0x1B,0x3A,0x5A,0x02,0xC6,0x14,0xC0,0x00,0xC3,0xC0,0x31,0x9A,0x32,0x2A,0xEB,0xDA, ++ 0x08,0x5B,0x0A,0x01,0x00,0x3F,0xC0,0x1B,0x18,0x9A,0x41,0xAB,0x00,0x5B,0xE9,0x90, ++ 0xE2,0x00,0xE2,0x48,0x95,0x4D,0x16,0x0A,0x9F,0xAE,0xEF,0xFD,0x40,0x01,0x88,0x8E, ++ 0x1E,0x01,0x10,0x5B,0x40,0x82,0x42,0x33,0x45,0xB0,0x05,0xB0,0x02,0x33,0x00,0x1B, ++ 0x00,0x5B,0x40,0x0B,0x1C,0x81,0x18,0xCA,0x00,0x0B,0x40,0x0B,0x18,0x01,0x1C,0xCA, ++ 0x00,0x0B,0x00,0x17,0x40,0x09,0x88,0x06,0x30,0xAA,0x01,0x01,0x00,0x27,0x40,0x8B, ++ 0x00,0x6B,0xE8,0x90,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0xC6,0xEF,0xFD,0xAF,0x85, ++ 0x30,0x72,0xCC,0x2C,0xD5,0x63,0x36,0x22,0x46,0xEB,0x42,0xE3,0x40,0x01,0x88,0x1E, ++ 0xDC,0x43,0x32,0x22,0x44,0xEB,0x40,0xE3,0x51,0x19,0x88,0x16,0x00,0x01,0x00,0xEF, ++ 0x3E,0x10,0x7E,0x90,0x28,0x92,0x8B,0xAE,0x40,0x53,0x31,0xB2,0xB0,0x41,0xE8,0x98, ++ 0x32,0xD2,0xD0,0x01,0x59,0xBB,0xC4,0x0B,0x1C,0x7A,0x1C,0xBB,0x59,0xBB,0xC6,0x0B, ++ 0x1E,0x7A,0x1C,0xBB,0x41,0x93,0xC1,0x3B,0x19,0xD2,0x01,0x93,0x41,0xCB,0xC0,0x13, ++ 0x18,0x8A,0x00,0xCB,0xEB,0x68,0xE1,0x20,0xE6,0x00,0x92,0x05,0x2E,0x02,0x9B,0xFE, ++ 0xE8,0x85,0x57,0x29,0x88,0xE6,0x07,0x01,0x06,0xEF,0x38,0x10,0x7B,0x90,0x2E,0x92, ++ 0x89,0xAE,0x40,0x53,0x30,0xB2,0xB0,0x41,0xE8,0x98,0x30,0xD2,0xD4,0x01,0x5A,0xBB, ++ 0xC0,0x0B,0x19,0x7A,0x1E,0xBB,0x5C,0xBB,0xC4,0x0B,0x19,0x7A,0x19,0xBB,0x46,0x93, ++ 0xC5,0x3B,0x19,0xD2,0x00,0x93,0x41,0xCB,0xC4,0x13,0x19,0x8A,0x01,0xCB,0xE8,0x68, ++ 0xE2,0x20,0xE3,0x00,0x93,0x05,0x2E,0x02,0x9F,0xFE,0xEE,0x85,0xA8,0x85,0xF7,0x2C, ++ 0x37,0x22,0xD4,0xAB,0xC4,0x34,0x00,0xB8,0x4E,0x03,0xC8,0x20,0x44,0xB2,0xC0,0xD8, ++ 0xC3,0xC0,0x30,0x1A,0x58,0x01,0x88,0x1E,0xD8,0xAB,0xDB,0x34,0x4E,0xDB,0xCA,0xE0, ++ 0x48,0x11,0x88,0xA6,0xB5,0x01,0xE4,0x8B,0x48,0x01,0x80,0x16,0x18,0x69,0x10,0xD8, ++ 0x00,0x57,0x18,0x79,0x10,0xD8,0x00,0x3F,0xC0,0x0B,0x18,0xCA,0x41,0x33,0x01,0x8B, ++ 0xA4,0x41,0xE0,0x00,0xE6,0x90,0x94,0x95,0x17,0x52,0x9D,0xAE,0xE8,0x85,0x4F,0x19, ++ 0x8F,0xE6,0x07,0xF9,0x18,0x02,0x06,0x77,0x18,0x00,0x04,0x42,0x00,0x01,0x00,0x42, ++ 0x00,0xB0,0x00,0x01,0x30,0x20,0x06,0x00,0x40,0x60,0x02,0x00,0x40,0x0B,0x01,0x43, ++ 0xA4,0x41,0xE0,0x90,0x95,0x95,0x16,0x52,0x9F,0xC6,0xEF,0x85,0xAC,0xFD,0x87,0x25, ++ 0x30,0x6A,0x30,0xB2,0x31,0xE2,0x48,0x3B,0x06,0xC9,0x07,0x00,0xC0,0x40,0x81,0x1C, ++ 0xD0,0x83,0x87,0x14,0xC0,0x24,0x40,0x01,0x8B,0x16,0xD8,0x83,0x83,0x14,0x48,0x3B, ++ 0x30,0x1A,0x11,0x19,0x08,0x01,0xB0,0x04,0xC7,0x24,0xB8,0xFF,0xF9,0x87,0x32,0x1A, ++ 0x10,0x19,0x08,0x09,0xB0,0x04,0xC0,0x24,0xBA,0xFF,0xFF,0x4F,0x30,0x5A,0x11,0x01, ++ 0x08,0x11,0xB0,0x04,0xA0,0x0C,0xC0,0x24,0xBC,0xFF,0xFF,0xC7,0x30,0x5A,0x11,0x09, ++ 0x08,0x11,0xB0,0x04,0xA0,0x0C,0xC0,0x24,0xBC,0xFF,0xFF,0x87,0x36,0x82,0x81,0x01, ++ 0xE2,0x0B,0x30,0x48,0x70,0x48,0xA2,0x0B,0x57,0xFA,0x0F,0xC1,0x00,0x8B,0x44,0x8B, ++ 0x18,0xF9,0x9F,0x19,0x18,0xCA,0x00,0x8B,0x35,0x8A,0x89,0x01,0x01,0x07,0xF8,0x85, ++ 0xE6,0x1B,0x48,0xD8,0x8E,0x16,0xE8,0x5B,0x5F,0x31,0x88,0xC6,0xE8,0x43,0x46,0x31, ++ 0x88,0x1E,0x40,0x83,0x08,0x81,0x18,0x42,0x00,0x83,0x00,0x01,0x04,0x3F,0x00,0x08, ++ 0xC2,0xCA,0x43,0x4B,0xDA,0x1C,0x00,0x10,0x92,0xCA,0xE4,0x00,0x90,0x05,0xCE,0x14, ++ 0x17,0x42,0x9C,0xA6,0x30,0x5A,0x11,0x01,0x08,0x19,0xB0,0x04,0xA0,0x0C,0xC0,0x24, ++ 0xBA,0xFF,0xFF,0xE7,0x30,0x5A,0x11,0x09,0x08,0x19,0xB0,0x04,0xA0,0x0C,0xC0,0x24, ++ 0xBA,0xFF,0xFF,0xA7,0x30,0x1A,0x11,0x29,0x08,0x09,0xB0,0x04,0xC7,0x24,0xB8,0xFF, ++ 0xF1,0xB7,0x37,0x1A,0x10,0x29,0x08,0x01,0xB0,0x04,0xC0,0x24,0xBF,0xFF,0xF7,0x7F, ++ 0x87,0x45,0xE8,0x85,0xAC,0xFD,0x87,0x35,0x08,0xC9,0xC7,0x3C,0x02,0x48,0xC6,0x28, ++ 0x48,0xD2,0xC6,0x3C,0xC0,0x20,0xC2,0x44,0xD0,0x33,0xC6,0x34,0x40,0x01,0x88,0x0E, ++ 0xC2,0x44,0xD8,0x33,0xC4,0x44,0x80,0x01,0x86,0x2C,0xE0,0x03,0x43,0x01,0x88,0xE6, ++ 0x08,0xF9,0x01,0x17,0xA2,0x0A,0xE1,0x00,0x95,0x05,0x14,0x82,0x9C,0xD6,0x3F,0x01, ++ 0xB8,0x24,0xB8,0x14,0x06,0x57,0x49,0x62,0xC6,0x24,0x08,0x43,0x40,0x35,0x40,0x7E, ++ 0xBA,0xFF,0xFF,0xE7,0x48,0x52,0x1E,0x01,0x00,0x01,0x00,0x67,0x04,0x10,0x32,0xA2, ++ 0xF4,0x52,0x15,0xD2,0xEB,0x0E,0x30,0x1A,0xD4,0x5A,0x17,0x52,0xD3,0x0E,0x30,0x0A, ++ 0xD2,0x4A,0xE3,0x00,0x95,0x05,0x14,0x82,0x9A,0x86,0x4F,0x81,0x90,0x2E,0x78,0x41, ++ 0x80,0x76,0xC0,0x24,0x18,0xC2,0x85,0x24,0x00,0x27,0xC0,0x14,0x40,0x01,0x8C,0x0E, ++ 0xB8,0x14,0x00,0x2F,0x40,0xF8,0xC3,0x24,0x18,0xC2,0x81,0x24,0x7E,0x01,0x88,0x96, ++ 0x00,0x01,0x08,0x01,0x01,0x17,0xA0,0x0A,0xE4,0x00,0x92,0x05,0x17,0x82,0x9D,0xD6, ++ 0xC0,0x14,0x80,0x1C,0x38,0x01,0x00,0x27,0xC0,0x14,0x18,0x3A,0xC2,0x14,0x40,0x00, ++ 0x80,0x14,0xC0,0x14,0x47,0x01,0x88,0xBE,0xC6,0x2C,0x58,0x04,0xC0,0x41,0x91,0x05, ++ 0x81,0x0C,0x00,0x17,0xC4,0x1C,0x18,0x3A,0x46,0x3A,0x0D,0x3B,0x40,0x35,0x40,0x7E, ++ 0xB8,0xFF,0xFF,0xA7,0x58,0x32,0x0D,0x01,0x00,0x01,0x00,0x67,0x04,0x10,0x32,0xA2, ++ 0xF4,0x52,0x15,0x52,0xEB,0x0E,0x30,0x0A,0xD4,0x4A,0x13,0xD2,0xD3,0x0E,0x30,0x12, ++ 0xD2,0x5A,0xE5,0x00,0x95,0x05,0x14,0x82,0x98,0x86,0xC7,0x0C,0x10,0x0A,0xEC,0x0E, ++ 0xC0,0x1C,0x18,0x3A,0xC2,0x1C,0x40,0x00,0x80,0x1C,0xC0,0x1C,0x46,0x01,0x88,0xCE, ++ 0x78,0x01,0x88,0x06,0x38,0x09,0xC0,0x2C,0xA0,0x3B,0xC6,0x2C,0xE4,0x0B,0x46,0x92, ++ 0x08,0x0B,0xC6,0x2C,0xE0,0x03,0x3E,0x09,0x16,0xF8,0x07,0x00,0x80,0x24,0x00,0x07, ++ 0x40,0xF8,0xC3,0x24,0x17,0xC2,0x81,0xDE,0x78,0x01,0xC9,0x06,0x38,0x01,0x01,0x01, ++ 0x08,0x01,0x00,0x17,0xA2,0x0A,0xE1,0x00,0x95,0x05,0x14,0x82,0x98,0xD6,0x07,0x01, ++ 0x80,0x04,0x78,0x01,0x88,0x1E,0xC0,0x04,0xE6,0x00,0x92,0x05,0x80,0x04,0x00,0x01, ++ 0x01,0x57,0xE0,0x0A,0x1E,0xCA,0x91,0x4D,0xA0,0x0A,0xD1,0x24,0x10,0x8A,0xCC,0x0E, ++ 0x19,0xCA,0xA5,0x0A,0xE4,0x00,0x92,0x05,0x17,0x82,0x9D,0x96,0x40,0x35,0x40,0x7E, ++ 0xBD,0xFF,0xF7,0xE7,0x01,0x01,0x00,0x0F,0xD2,0x2C,0x00,0x08,0xD6,0x4A,0x5B,0x94, ++ 0xD0,0x48,0x94,0x4D,0xD0,0x04,0x50,0x01,0x8B,0x2E,0x48,0x21,0xE9,0xA6,0xE0,0x0A, ++ 0x19,0xCA,0xA5,0x0A,0x01,0x87,0x48,0x91,0xE9,0x2E,0xE0,0x12,0x50,0x01,0x80,0x16, ++ 0xF1,0x90,0xA2,0x12,0x01,0x47,0x10,0x89,0x1C,0x92,0x16,0x8A,0xD1,0x26,0xE0,0x0A, ++ 0x48,0xF9,0x91,0x0E,0xE1,0x48,0xA2,0x0A,0xE4,0x00,0x92,0x05,0x16,0x82,0x9D,0xDE, ++ 0x40,0xF8,0xC3,0x04,0x45,0x21,0xC8,0xE6,0x87,0x55,0xE8,0x85,0xAC,0xBD,0x87,0x75, ++ 0xCE,0x84,0xD0,0x6B,0x10,0xC9,0xCF,0x7C,0x04,0x90,0xC6,0x48,0x18,0xF9,0xD1,0x7C, ++ 0x0E,0xD8,0xC2,0x90,0x20,0xF9,0xDF,0x7C,0x00,0x20,0xCF,0xE0,0x30,0x09,0xDC,0x7C, ++ 0x0C,0xB0,0xC9,0xD8,0x99,0x14,0x30,0x09,0xDD,0x7C,0x08,0xB0,0xC8,0xD8,0x9C,0x0C, ++ 0x78,0x1D,0x40,0x01,0x88,0x0E,0xC0,0x84,0xD8,0x2B,0xC2,0x84,0xE0,0x03,0x44,0x29, ++ 0xC0,0x56,0x00,0x01,0x02,0x37,0x00,0x18,0xD6,0x72,0x96,0xB2,0xD7,0x72,0x96,0x32, ++ 0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xB6,0x04,0x01,0x30,0x22,0x18,0x01,0x00,0xCF, ++ 0x01,0xC0,0xD2,0x32,0x30,0x32,0xB4,0x6C,0x30,0x01,0x00,0x01,0xF8,0xB2,0xF4,0x42, ++ 0xC3,0xB0,0x81,0xB0,0x31,0x82,0x93,0x32,0x40,0x74,0x00,0xB4,0xD0,0x02,0xF1,0x6C, ++ 0xD9,0x00,0x04,0xC4,0x20,0x02,0x93,0x05,0x34,0x22,0xE4,0x90,0xE5,0x48,0xE4,0xF8, ++ 0xE6,0xD8,0x92,0xDD,0x17,0x5A,0x9D,0x1E,0x71,0x1D,0x30,0x4A,0x30,0x02,0x83,0x0F, ++ 0xD8,0x5F,0x95,0x0D,0x10,0x01,0x00,0xCF,0x01,0x01,0xF0,0x82,0xE0,0xB0,0x45,0x01, ++ 0xE8,0x2E,0x48,0x01,0xEC,0x1E,0x10,0x42,0xE8,0x56,0x30,0x42,0x00,0x47,0x40,0x01, ++ 0xD0,0x2E,0x48,0x01,0xD4,0x1E,0x10,0x42,0xD0,0x16,0x30,0x42,0x00,0x07,0x00,0x01, ++ 0x07,0x98,0xD2,0x3A,0xD7,0xC0,0x91,0x02,0xE6,0x90,0x92,0x95,0x17,0x52,0x9D,0x1E, ++ 0xC4,0x84,0xE0,0x03,0x40,0x29,0xC0,0xEE,0x00,0x01,0x10,0x01,0x02,0x3F,0x00,0x08, ++ 0xF3,0x14,0xD0,0x1A,0x90,0x9A,0xCB,0x0C,0xA2,0x52,0xE0,0x00,0x95,0x05,0x16,0x42, ++ 0x98,0xAE,0x07,0x01,0x12,0xF9,0x09,0x90,0x1A,0x09,0x0A,0xD8,0x00,0x47,0xE0,0x7C, ++ 0x00,0x08,0xCA,0x48,0xC1,0x60,0x5C,0x24,0xC0,0x48,0x0E,0x64,0xE6,0x00,0x92,0x05, ++ 0x17,0x42,0x9D,0xA6,0x87,0x8D,0xE8,0x85,0xAE,0xE5,0xD7,0x9B,0x9F,0x0C,0x18,0xF9, ++ 0x06,0xD8,0xC6,0x58,0x34,0xF2,0x1C,0x09,0x0E,0xD8,0xC0,0x68,0x1C,0x09,0x09,0xD8, ++ 0xC4,0x58,0x36,0xE2,0x1E,0xC9,0x07,0xD8,0xC0,0x48,0x8E,0x04,0x40,0x01,0x88,0x0E, ++ 0xD8,0x83,0x82,0x0C,0x00,0x01,0x30,0x9A,0x9A,0x01,0x14,0xC3,0x11,0xC3,0x04,0xCF, ++ 0x03,0x20,0x32,0x8A,0xD9,0x4A,0xD8,0x72,0xD8,0x48,0x94,0x75,0xC8,0x04,0x98,0x72, ++ 0x08,0x01,0x38,0xB1,0xBD,0xFA,0x16,0xBA,0xE8,0x66,0x08,0x09,0x3A,0x09,0x50,0xF3, ++ 0x01,0x3A,0x1C,0xF2,0x10,0xF3,0x02,0x77,0x00,0x01,0x00,0x42,0x40,0x60,0x02,0x00, ++ 0xF8,0xFF,0x07,0x00,0xED,0xFB,0x16,0xBA,0xD0,0x2E,0x08,0x09,0x3C,0x09,0x50,0xF3, ++ 0x01,0x3A,0x1C,0xF2,0x10,0xF3,0x4C,0x01,0x8D,0x96,0x08,0xC1,0xE0,0x4A,0x4C,0x01, ++ 0x89,0x76,0xF8,0x7A,0x13,0xF0,0x31,0x0A,0xE4,0x4A,0xC8,0x70,0x30,0x8A,0xFB,0x4A, ++ 0x04,0x48,0xCC,0x70,0x03,0xC8,0xD5,0x88,0x91,0x70,0x98,0x72,0x31,0x22,0xA3,0x0A, ++ 0xE6,0x00,0x92,0x05,0xCC,0x0C,0x10,0x42,0x9F,0x16,0xEE,0xE5,0xAC,0xBD,0x87,0x65, ++ 0x30,0x62,0x30,0xB2,0x40,0xFA,0x47,0x03,0x90,0x05,0x84,0x5C,0x40,0xF2,0x47,0x0B, ++ 0x90,0x4D,0x8C,0x54,0x44,0x0B,0x92,0x4D,0x8E,0x4C,0x40,0x0B,0x90,0x4D,0x8C,0x44, ++ 0x4C,0x0B,0x90,0x4D,0x8A,0x3C,0x48,0x0B,0x90,0x4D,0x8C,0x34,0x4C,0x0B,0x94,0x4D, ++ 0x8E,0x2C,0x50,0x0B,0x90,0x4D,0x8C,0x24,0x4C,0x0B,0x96,0x4D,0x8A,0x1C,0x58,0x0B, ++ 0x90,0x4D,0x8C,0x14,0x5C,0x0B,0x94,0x4D,0x88,0x0C,0x08,0x21,0x0C,0x0B,0x08,0x0B, ++ 0xE7,0x0B,0x53,0x72,0x1E,0x8A,0x10,0x0B,0x08,0x01,0xDD,0x4A,0x01,0x0B,0x36,0x2A, ++ 0xA9,0x01,0xEC,0x4B,0x1B,0x0B,0xEA,0x4B,0x1F,0x0B,0xE4,0x4B,0x0D,0x0B,0xE6,0x43, ++ 0x40,0x01,0x80,0x3E,0x47,0x22,0x4F,0x32,0x00,0x0B,0x0A,0xC9,0x00,0x0B,0x08,0x09, ++ 0x08,0x0B,0x02,0x3F,0x4F,0x12,0x47,0x02,0xCA,0xE1,0x00,0x0B,0x08,0x89,0x00,0x0B, ++ 0x0A,0x41,0x08,0x0B,0xE0,0x03,0x45,0x09,0x8B,0xB6,0xD8,0x03,0x80,0x04,0x38,0x01, ++ 0x00,0x3F,0x08,0x09,0x31,0x9A,0x31,0xD2,0x37,0x42,0xB8,0xFF,0xE3,0x67,0xE0,0xF8, ++ 0x90,0xFD,0xC7,0x04,0x17,0x3A,0x9C,0xA6,0x31,0x9A,0x31,0x12,0x00,0x09,0xC8,0x64, ++ 0xBD,0xFF,0xEF,0xC7,0xF3,0x43,0xB7,0x03,0x31,0x9A,0x31,0x12,0x00,0x09,0xC8,0x64, ++ 0xB9,0xFF,0xEF,0xA7,0x30,0x12,0x01,0x09,0xCF,0x64,0xB8,0xFF,0xF1,0xFF,0x34,0x12, ++ 0x00,0x09,0xC8,0x64,0xB9,0xFF,0xFF,0x87,0x48,0x32,0xC6,0x5C,0x06,0x43,0x40,0x32, ++ 0xC8,0x54,0x00,0x0B,0xCA,0x4C,0x00,0x0B,0xCE,0x44,0x00,0x0B,0xC8,0x3C,0x08,0x0B, ++ 0xCA,0x34,0x08,0x0B,0xCC,0x2C,0x08,0x0B,0xCE,0x24,0x10,0x0B,0xCE,0x1C,0x08,0x0B, ++ 0xCA,0x14,0x18,0x0B,0xCC,0x0C,0x18,0x0B,0xE6,0x43,0x31,0x00,0xAB,0x66,0xF1,0x03, ++ 0xF4,0x4B,0x15,0x42,0x89,0x46,0x31,0x02,0x82,0x01,0xE1,0x13,0x50,0x11,0x88,0x46, ++ 0xE8,0x13,0x51,0x51,0x88,0x16,0x10,0x01,0xA0,0x13,0x02,0x9F,0xE1,0x90,0xAA,0x13, ++ 0x05,0x87,0x50,0x53,0x50,0x01,0x88,0x2E,0x50,0x53,0x53,0x01,0x89,0x16,0xE8,0x13, ++ 0x50,0x01,0x89,0x2E,0xF3,0x53,0xB7,0x13,0x11,0x09,0xB0,0x13,0xA0,0x13,0x02,0x0F, ++ 0xE1,0x90,0xAA,0x13,0xF4,0x03,0x13,0x42,0x88,0x36,0x08,0x01,0x30,0x1A,0xB1,0x04, ++ 0x30,0x42,0xD0,0x64,0xBF,0xFF,0xDF,0xEF,0x31,0x12,0x31,0x8A,0x07,0x11,0xB8,0xFF, ++ 0xD8,0x3F,0x80,0x7D,0xEF,0x85,0xAF,0x85,0x4E,0xA3,0xD0,0xEB,0x33,0x70,0x72,0xB0, ++ 0x4F,0x78,0x0E,0xF8,0x48,0xFA,0xC4,0x4B,0x48,0x09,0x88,0x0E,0x54,0xA3,0xD8,0xEB, ++ 0x0F,0x01,0x18,0xF9,0x01,0x6F,0x40,0x13,0x47,0x93,0x02,0x92,0x90,0x95,0x00,0x14, ++ 0x78,0x01,0x88,0x16,0x50,0xF9,0xEF,0x06,0x01,0x1C,0xE8,0x20,0xE2,0x00,0xE4,0x48, ++ 0x95,0x4D,0x16,0x4A,0x9F,0x7E,0xEF,0x85,0xA8,0xC5,0x33,0x2A,0x34,0xB2,0x60,0x6A, ++ 0x44,0x03,0x11,0x01,0x19,0x82,0x04,0x03,0x40,0x03,0x11,0x81,0x19,0x82,0x00,0x03, ++ 0x40,0x03,0x11,0x09,0x19,0x82,0x00,0x03,0xE7,0x53,0x03,0xF9,0x80,0x81,0x18,0x12, ++ 0x46,0x2A,0x14,0x13,0x13,0x99,0x00,0x13,0x14,0x41,0x00,0x13,0x12,0x91,0xEC,0x92, ++ 0x50,0x01,0x80,0x16,0x10,0xC9,0x00,0x13,0x00,0x0F,0x10,0x89,0x00,0x13,0x30,0x52, ++ 0x30,0x5A,0x09,0x01,0x00,0x09,0xB0,0x04,0xBD,0xFF,0xDF,0x5F,0x31,0x52,0x31,0x8A, ++ 0x07,0x11,0xB8,0xFF,0xD3,0xAF,0x45,0x03,0x3F,0x00,0xAA,0xE6,0xEF,0xC5,0xAB,0x9D, ++ 0x80,0x8D,0xCC,0x94,0xC8,0x4B,0x8A,0x84,0xE2,0x94,0xA0,0x01,0xD3,0x1B,0xD1,0x0B, ++ 0x88,0x0C,0xC8,0x94,0xD0,0x6B,0x36,0x0A,0x8C,0x61,0x30,0x62,0xC8,0x94,0x30,0x01, ++ 0xE0,0x4B,0x4C,0x09,0x88,0x56,0x08,0x01,0x02,0x27,0xC0,0x38,0x9A,0xF3,0xA1,0x32, ++ 0xE2,0x48,0x92,0x4D,0xD6,0x94,0xD0,0x93,0x17,0x52,0xE4,0xB6,0x52,0x52,0x03,0xB3, ++ 0x06,0xB3,0x04,0xB3,0x0E,0x01,0x18,0x4A,0x00,0x8B,0xC8,0x94,0xD0,0x4B,0xB6,0x8B, ++ 0x0B,0x01,0x50,0x2A,0x34,0x01,0x00,0x78,0xC1,0xF8,0x0D,0xF3,0xC2,0x90,0xB2,0xB3, ++ 0xE2,0x48,0x92,0x4D,0x4F,0x11,0xD8,0xA6,0xCC,0x94,0xE0,0x4B,0x4B,0x29,0xC8,0xA6, ++ 0x00,0x48,0xC5,0x48,0x04,0x50,0xC3,0x70,0x14,0x09,0x06,0x90,0xC0,0xB0,0xB5,0x1C, ++ 0xC0,0x48,0x8C,0x14,0x30,0x12,0x33,0x32,0xB0,0xC1,0x08,0x01,0x8A,0x3C,0x48,0xBA, ++ 0x88,0x6C,0x88,0x64,0x30,0x32,0x04,0x01,0x32,0x22,0x04,0x27,0xC8,0x1C,0x00,0x01, ++ 0xF0,0x42,0xF8,0x14,0x0B,0x01,0xF0,0xCA,0x32,0x7A,0xD0,0x08,0x97,0x4D,0x48,0xF9, ++ 0xEF,0x06,0x08,0xF9,0xCB,0x38,0x86,0xF8,0x78,0xF9,0xEF,0x06,0x3B,0xF9,0x37,0x82, ++ 0x82,0x3B,0xE0,0x00,0x30,0x32,0xC4,0xBB,0x10,0xFA,0x9C,0x46,0x10,0xCA,0xDC,0x36, ++ 0x46,0x84,0xD9,0x48,0xC0,0x00,0x92,0x05,0x04,0x84,0x81,0x08,0x04,0x37,0x10,0xCA, ++ 0xDC,0x16,0x00,0x78,0x00,0xBC,0x01,0x0F,0x39,0x01,0x00,0xBC,0x10,0xCA,0xDC,0x0E, ++ 0x38,0x09,0xB8,0x3C,0x43,0x78,0x2B,0x3A,0xE8,0x26,0xF8,0x6C,0x10,0x7A,0xEC,0x2E, ++ 0x88,0x6C,0x00,0x1F,0xFC,0x64,0x10,0x7A,0xE8,0x06,0x88,0x64,0x82,0x8B,0xE0,0x90, ++ 0xE0,0xB0,0xC5,0x1C,0xE0,0x00,0x84,0x1C,0xC4,0x14,0xE0,0x00,0x83,0x14,0x30,0x02, ++ 0xE2,0x00,0x92,0x05,0x35,0x22,0x2C,0x62,0xD8,0xC6,0xC5,0x3C,0x40,0x01,0x80,0xA6, ++ 0x08,0x01,0x00,0x01,0x80,0x5C,0xC0,0x0C,0xC2,0x00,0x46,0x00,0x80,0x7C,0xC0,0x0C, ++ 0x30,0x00,0x72,0x00,0x80,0x74,0x00,0x01,0x30,0x22,0x84,0x34,0x80,0x2C,0x80,0x24, ++ 0xF3,0x90,0xF2,0x40,0x94,0x05,0x32,0x32,0x05,0x7F,0x02,0x77,0x32,0x02,0x03,0x00, ++ 0x30,0x22,0xC4,0x34,0x00,0x00,0x82,0x34,0xC2,0x2C,0x00,0x00,0x80,0x2C,0xC0,0x24, ++ 0x00,0x00,0x82,0x24,0x43,0x40,0x2B,0x82,0xE8,0x26,0xC0,0x83,0xF4,0x6C,0xD8,0x00, ++ 0x80,0x83,0x00,0x1F,0xC0,0x83,0xF0,0x64,0xD8,0x00,0x84,0x83,0xC0,0x83,0x70,0x45, ++ 0x37,0xBA,0xAB,0x82,0xC4,0x83,0x10,0xC2,0xDA,0xDE,0xE0,0x48,0x90,0x4D,0xF2,0x5C, ++ 0xC1,0xB0,0x91,0xB5,0xB3,0x5C,0x30,0x32,0x39,0x09,0x18,0xF2,0x30,0xA2,0xF5,0x7C, ++ 0x10,0x82,0xDD,0x76,0xF1,0x34,0x18,0xF2,0xB0,0x34,0xF0,0x0C,0x10,0x82,0xDD,0x46, ++ 0xF1,0x2C,0x18,0xF2,0xB0,0x2C,0xF0,0x74,0x10,0x82,0xDD,0x16,0xC1,0x24,0x18,0xC2, ++ 0x80,0x24,0x00,0x6F,0x18,0x00,0x04,0x42,0x00,0x01,0x00,0x42,0x10,0x78,0x00,0x00, ++ 0x88,0x60,0x05,0x00,0x00,0xB0,0x00,0x01,0x58,0x80,0x04,0x01,0x78,0xF8,0x07,0x00, ++ 0xF3,0x90,0x32,0x82,0xF2,0x00,0x92,0x05,0x33,0x32,0x34,0x82,0x45,0x01,0xD0,0x6E, ++ 0x42,0xFA,0xB7,0x0B,0xD0,0x50,0xB3,0x13,0x36,0x12,0x1B,0x92,0x03,0x13,0x30,0x12, ++ 0x08,0x13,0xD0,0x34,0x00,0x13,0xD2,0x2C,0x00,0x13,0xD4,0x24,0x00,0x13,0x36,0x01, ++ 0x00,0xA7,0xC1,0x5C,0x87,0x0F,0xC0,0x07,0x90,0x05,0x80,0x5C,0x4D,0xA2,0x07,0x80, ++ 0xC0,0x00,0x4A,0x13,0x40,0x45,0x08,0x01,0x1C,0x01,0x30,0xF2,0x30,0xE2,0x04,0xCF, ++ 0x38,0x98,0x86,0x7E,0xC0,0x1B,0xF8,0x5C,0xD8,0xD8,0x96,0xDD,0x58,0x01,0xE8,0x36, ++ 0x83,0x1B,0x20,0x9A,0x94,0xDD,0x36,0xF2,0xE2,0x48,0x92,0x4D,0x00,0x27,0x18,0x01, ++ 0x80,0x1B,0x00,0x0F,0x18,0x01,0x80,0x1B,0x42,0x90,0xE2,0x00,0x32,0x1A,0xE3,0xD8, ++ 0x94,0xDD,0x32,0xE2,0x2F,0x62,0xDD,0x1E,0xE3,0xB0,0x93,0xB5,0x30,0x82,0x83,0x5C, ++ 0x45,0xFA,0x06,0x98,0xC0,0xD8,0x08,0xD3,0xCA,0x00,0xB4,0x0B,0x48,0x21,0xD8,0x0E, ++ 0x76,0x09,0xD8,0x36,0x06,0x01,0x50,0xD2,0x04,0x08,0xC4,0x58,0xE4,0x08,0x02,0x70, ++ 0xC0,0xB0,0x4D,0xEB,0x4D,0xB3,0x19,0xAA,0x08,0xEB,0xC0,0x80,0xF4,0x1B,0xF2,0x2B, ++ 0xDA,0xD8,0xB2,0x1B,0x90,0x45,0x42,0x09,0xD8,0x76,0x07,0x09,0x9E,0x03,0x45,0x82, ++ 0x0E,0x19,0x40,0x13,0x50,0x01,0x80,0x16,0x05,0x29,0x98,0x0B,0x04,0xF7,0x40,0x13, ++ 0x50,0x01,0x80,0x16,0x05,0x21,0x98,0x0B,0x02,0xC7,0x40,0x0B,0x48,0x01,0x80,0x1E, ++ 0x00,0x19,0x08,0x11,0x98,0x0B,0x05,0x8F,0x48,0x03,0x40,0x01,0x88,0x26,0xC0,0x94, ++ 0x82,0x01,0xF5,0x03,0x40,0x51,0x98,0x0E,0x00,0x11,0x00,0x3F,0xC1,0x94,0x80,0x01, ++ 0xD8,0x03,0x44,0x01,0x80,0x0E,0x00,0x11,0x00,0x07,0x00,0x09,0xDC,0x0B,0xE5,0x50, ++ 0x9D,0x13,0xD7,0x13,0x38,0x90,0xA2,0x0E,0xF5,0x48,0x9A,0x0B,0xE0,0x0B,0x13,0x29, ++ 0x10,0x0A,0x94,0x0E,0xA0,0x13,0x01,0xEF,0x10,0x0A,0xCC,0x46,0x40,0x09,0x88,0x16, ++ 0x09,0x81,0xA7,0x0B,0x00,0xB7,0xD0,0x48,0x01,0x52,0xA4,0x13,0x00,0x97,0x40,0x19, ++ 0xC8,0x0E,0x08,0x19,0x02,0x07,0x90,0x0D,0xE0,0x13,0x51,0x01,0x82,0x16,0xF0,0x90, ++ 0xA0,0x13,0x01,0x3F,0xD2,0x94,0xF0,0x48,0xCA,0x93,0x1C,0x52,0xCA,0x84,0xC0,0x88, ++ 0xD0,0x94,0x88,0x8B,0xA0,0x03,0x83,0x9D,0xEF,0x85,0xAF,0xBD,0x80,0x6D,0x34,0x6A, ++ 0xD1,0x63,0x37,0x42,0x80,0x01,0x82,0x64,0xC8,0x03,0x86,0x3C,0xC4,0x64,0xD0,0x03, ++ 0x30,0x00,0xA8,0x1E,0x02,0x91,0xEC,0x02,0x40,0x01,0x80,0xAE,0xC5,0x6C,0x00,0x08, ++ 0xC3,0x40,0x00,0x08,0x12,0x09,0xC6,0x08,0x04,0x90,0xC4,0x48,0xC0,0x10,0x04,0x01, ++ 0x18,0x01,0x00,0x2F,0x00,0x5C,0x00,0x9C,0xE4,0x48,0xE4,0x90,0xE2,0x00,0x92,0x05, ++ 0x17,0x02,0xDD,0xBE,0x87,0x85,0xE8,0x85,0x00,0xE9,0xC9,0x6C,0x08,0x00,0xC2,0x40, ++ 0x70,0x82,0xEC,0x03,0x08,0x83,0xD7,0x7C,0x91,0x04,0x30,0x5A,0x08,0x01,0x00,0x11, ++ 0xD7,0x6C,0xB8,0xFF,0xCC,0xB7,0x45,0x5A,0x80,0x01,0x42,0x0B,0x34,0x5A,0x0B,0xCC, ++ 0x5E,0x8B,0x09,0xCC,0x58,0x8B,0x13,0xCC,0x5A,0x8B,0x15,0xCC,0x44,0x8B,0x17,0xCC, ++ 0x48,0x2A,0x44,0x53,0x17,0xD4,0x4E,0x93,0x18,0xD4,0x10,0x89,0x00,0x93,0x17,0x19, ++ 0x18,0x93,0x43,0x53,0x1C,0x11,0x18,0xD2,0x00,0x53,0x40,0x0B,0x18,0xCA,0x00,0x0B, ++ 0x35,0x42,0xE1,0x4B,0x80,0x01,0x81,0x5C,0x4A,0x09,0x88,0x66,0x68,0x44,0x81,0x14, ++ 0x34,0x8A,0x59,0x43,0x90,0x35,0xB6,0x0C,0x00,0x01,0x80,0x04,0xD6,0x6C,0x08,0x09, ++ 0x04,0x00,0x07,0x48,0xC2,0x00,0xC4,0x00,0x83,0x54,0x40,0x92,0x18,0x33,0x0A,0x01, ++ 0x37,0x42,0xB9,0xFF,0xC0,0xBF,0xFA,0x54,0xC1,0x64,0x30,0x5A,0xC9,0x0B,0x34,0xC2, ++ 0xD7,0x7C,0xB8,0xFF,0xEB,0x07,0x4C,0x6A,0x10,0x01,0x00,0x01,0x02,0x67,0x00,0x18, ++ 0x37,0xE2,0xF4,0xDA,0x10,0x5A,0xD4,0x0E,0x33,0x0A,0xD3,0xCA,0x10,0x9A,0xEC,0x0E, ++ 0x35,0x12,0xD3,0xD2,0xE2,0x00,0x92,0x05,0x17,0x02,0xDD,0x86,0xC4,0x14,0xE0,0x00, ++ 0x10,0x0A,0x9C,0x36,0xC0,0x04,0x40,0x01,0x8B,0x9E,0x40,0x80,0x40,0x08,0xC2,0x70, ++ 0x00,0x3F,0xC0,0x14,0xF4,0x00,0x14,0x12,0xE0,0x5E,0x00,0x09,0x83,0x04,0xE0,0xB0, ++ 0x90,0xB5,0x77,0x01,0x80,0x16,0xC0,0x0C,0x16,0x32,0x9C,0x36,0x70,0x01,0x88,0x06, ++ 0x30,0x09,0xC0,0x5C,0x88,0x33,0xC0,0x5C,0xCA,0x0B,0x40,0x92,0x18,0x0B,0x32,0x01, ++ 0x35,0x42,0x81,0x01,0x81,0x4C,0x80,0x01,0x83,0x44,0x00,0x4F,0xC4,0x3C,0x10,0x32, ++ 0xD0,0x6E,0xC0,0x44,0xE0,0x03,0xC8,0x44,0x32,0x00,0x72,0x00,0xA2,0x43,0x40,0x4A, ++ 0x0C,0x41,0x00,0x0B,0x47,0x0B,0x10,0xF9,0x90,0x21,0x18,0x8A,0x00,0x0B,0xC8,0x6C, ++ 0x02,0x00,0xC5,0x08,0x06,0x00,0x13,0x09,0xC4,0x40,0x00,0x90,0xC4,0x00,0xC4,0x48, ++ 0x70,0x01,0x88,0x66,0x12,0x01,0x78,0x0A,0x00,0x37,0x18,0x01,0x00,0x1C,0x00,0x7C, ++ 0xE4,0x00,0xE4,0x48,0xE2,0x90,0x92,0x95,0x17,0x12,0xDD,0xB6,0x00,0x0F,0xD9,0x6C, ++ 0x06,0x10,0xC7,0x90,0x1C,0x09,0x06,0xD8,0xC4,0x90,0x36,0xA2,0x18,0x01,0x00,0x9F, ++ 0x30,0x3A,0x13,0x01,0xF0,0xD2,0x3D,0x01,0xFC,0x3A,0x16,0xBA,0xD0,0x06,0x00,0x14, ++ 0x3E,0x01,0xF8,0x7A,0x10,0xBA,0xEC,0x06,0x04,0x54,0xE0,0x00,0xE3,0x48,0x34,0x12, ++ 0xE4,0x90,0x34,0xA2,0xE2,0xD8,0x92,0xDD,0x17,0x1A,0xDD,0x4E,0xC4,0x3C,0x10,0x32, ++ 0x80,0x0E,0xC1,0x44,0xE6,0x03,0x48,0x00,0x88,0x1E,0xC0,0x4C,0xE8,0x03,0x46,0x31, ++ 0x88,0xBE,0xC7,0x4C,0xE8,0x03,0x46,0x31,0x89,0x26,0x40,0x12,0x40,0x0B,0x10,0x81, ++ 0x18,0x8A,0x00,0x0B,0xCF,0x6C,0x00,0x00,0xC6,0x00,0x0A,0x09,0x02,0x48,0xC4,0x00, ++ 0xC9,0x64,0x30,0x5A,0xC8,0x4B,0xD4,0x7C,0xBE,0xFF,0xE7,0xEF,0xE3,0xB0,0x93,0xB5, ++ 0xC4,0x3C,0x10,0x32,0xE8,0x96,0x44,0xBA,0x34,0x5A,0x4B,0xCC,0x80,0x01,0x02,0x0B, ++ 0x46,0xA2,0x48,0xCC,0x18,0x0B,0x50,0xCC,0x1A,0x0B,0x52,0xCC,0x1C,0x0B,0x54,0xCC, ++ 0x00,0x0B,0x4E,0x8A,0x50,0xD4,0x06,0x53,0x5E,0xCC,0x08,0x0B,0x37,0x97,0xAF,0xFD, ++ 0x81,0xED,0xE4,0x3C,0x30,0xAA,0x00,0x01,0x80,0x7C,0x80,0x74,0xC6,0x34,0xD1,0x03, ++ 0x81,0x6C,0xC0,0x34,0xDA,0x03,0xF2,0x00,0x90,0x05,0x86,0x64,0x00,0x01,0x80,0x5C, ++ 0x80,0x54,0x80,0x4C,0xC4,0x34,0xC9,0x03,0x00,0x00,0x82,0xBC,0x08,0xA1,0x05,0x3F, ++ 0x58,0x80,0x04,0x01,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0xF8,0xFB,0x07,0x00, ++ 0xC2,0x34,0xF1,0x0A,0x80,0x40,0x82,0xB4,0xC1,0x34,0xD9,0x04,0xE7,0x03,0x9C,0xF9, ++ 0x98,0x29,0x41,0x09,0x88,0x76,0xC0,0x6C,0x1E,0x42,0xC3,0x08,0xD0,0xEC,0x00,0x01, ++ 0x00,0x2F,0x40,0xB4,0x82,0x73,0xE0,0x48,0xE2,0x90,0xE4,0x00,0x90,0x05,0xF2,0x6C, ++ 0x17,0x82,0xDD,0xB6,0x00,0x01,0x80,0x9C,0x80,0xA4,0x80,0xAC,0xC4,0xEC,0x30,0x32, ++ 0x70,0x1D,0xC8,0x6C,0x32,0x42,0x19,0x42,0x86,0xE4,0xC0,0x00,0x30,0x22,0x84,0xDC, ++ 0x40,0xAA,0x47,0x13,0x48,0x1B,0x08,0x01,0x03,0x1F,0x31,0x82,0x30,0x3A,0x43,0x04, ++ 0xC6,0xFB,0xD9,0x00,0x91,0x05,0x00,0x84,0x38,0xB8,0x86,0x26,0xFE,0xAC,0xC8,0x00, ++ 0x90,0x05,0x80,0xAC,0x06,0x57,0x38,0xF8,0x80,0x26,0xF8,0xA4,0xC8,0x00,0x96,0x05, ++ 0x80,0xA4,0x00,0x1F,0xFE,0x9C,0xC8,0x00,0x90,0x05,0x80,0x9C,0xE3,0xB0,0x35,0x82, ++ 0xE4,0x00,0x34,0x32,0x32,0x02,0xE3,0x00,0x32,0x22,0x44,0x90,0x42,0xD8,0xE2,0x48, ++ 0x90,0x4D,0xC2,0x6C,0x16,0x0A,0xDC,0xC6,0x79,0xFA,0xF6,0xCB,0x48,0x01,0xE8,0x26, ++ 0xC0,0xAC,0x80,0x07,0xF0,0x8F,0x94,0x05,0x83,0xAC,0xF0,0xCB,0x48,0x01,0xE8,0x56, ++ 0x48,0x09,0x88,0x1E,0xC2,0xA4,0x80,0x00,0x80,0xA4,0x00,0x27,0xC0,0xA4,0x80,0x07, ++ 0xF0,0x1F,0x94,0x05,0x85,0xA4,0xF0,0xCB,0x48,0x01,0xE8,0x56,0x48,0x09,0x88,0x1E, ++ 0xC2,0x9C,0x80,0x00,0x80,0x9C,0x00,0x27,0xC0,0x9C,0x80,0x07,0xF0,0xAF,0x93,0x05, ++ 0x80,0x9C,0xF0,0xEC,0x40,0x1D,0x80,0x04,0xC0,0xDC,0x80,0x14,0x40,0xC3,0x81,0x94, ++ 0x48,0xC3,0x81,0x8C,0xC2,0x34,0x81,0x01,0x84,0xD4,0xD0,0x03,0x38,0x00,0x86,0x7E, ++ 0x40,0xC3,0x83,0x84,0x40,0xC3,0x85,0x7C,0x40,0xC3,0x87,0x74,0xC6,0xD4,0xD0,0x03, ++ 0x80,0x5C,0xC0,0xD4,0xD8,0x03,0x80,0x54,0xC2,0xD4,0xD8,0x03,0x80,0x4C,0x00,0x0F, ++ 0x00,0x01,0x80,0x84,0xC0,0x04,0xC9,0xE4,0x80,0xA1,0xC1,0x40,0x80,0x0C,0xC0,0xE4, ++ 0xCA,0x04,0x01,0x00,0xC5,0x00,0x4A,0xCA,0xC0,0x38,0x02,0x01,0x80,0xC4,0x00,0x09, ++ 0x00,0x42,0x85,0xCC,0x00,0x5F,0xC5,0x94,0x38,0x00,0x86,0x0E,0xC0,0xAC,0x00,0x2F, ++ 0xC6,0x8C,0x38,0x00,0x80,0x0E,0xC0,0xA4,0x00,0x07,0xC0,0x9C,0x40,0x01,0xE8,0x66, ++ 0xD0,0x04,0x08,0x01,0xF0,0x8A,0x4A,0x01,0xEC,0x3E,0x10,0x0A,0xD0,0x06,0x30,0x42, ++ 0x40,0x8C,0xD1,0x40,0x91,0x15,0x00,0x94,0x00,0x97,0xD1,0x04,0x0A,0x01,0xF0,0x8A, ++ 0x49,0x01,0xD0,0x5E,0x40,0x01,0xD0,0x2E,0x10,0x0A,0xEC,0x06,0x31,0x42,0x40,0x8C, ++ 0xD1,0x40,0x00,0x84,0x15,0x01,0xF0,0x92,0xC6,0x84,0x38,0x00,0x80,0x06,0xC1,0x14, ++ 0xC4,0x0B,0xD0,0x40,0x90,0x05,0xD8,0x74,0x38,0xD8,0x86,0x36,0xDC,0x4C,0x10,0xC2, ++ 0xE8,0xB6,0xC0,0x4C,0xD1,0x40,0x00,0x84,0x00,0x97,0xD8,0x7C,0x38,0xD8,0x86,0x36, ++ 0xDC,0x54,0x10,0xC2,0xE8,0x66,0xC0,0x54,0xD1,0x40,0x00,0x84,0x00,0x47,0xD8,0x5C, ++ 0x10,0xC2,0xEC,0x2E,0xC0,0x5C,0xD0,0x40,0x00,0x84,0x01,0x0F,0x15,0x01,0xF0,0x92, ++ 0xC0,0x0C,0xC0,0x03,0xD0,0x00,0x94,0x05,0xC8,0xF4,0x48,0x01,0x88,0x06,0xC9,0xBC, ++ 0x10,0x42,0xDC,0xAE,0x40,0x03,0xC9,0xCC,0x18,0x09,0x18,0x42,0x00,0x03,0x69,0x01, ++ 0x83,0x26,0xF0,0x48,0x34,0xD2,0x00,0x52,0x19,0x82,0x00,0x03,0xC4,0x64,0x10,0x2A, ++ 0x93,0x0E,0xE1,0x40,0x31,0xD2,0x40,0x0B,0x00,0x12,0x1C,0x8A,0x00,0x0B,0x01,0xD7, ++ 0xCC,0xB4,0x10,0x42,0xE1,0xBE,0x40,0x03,0xC8,0xCC,0x18,0x42,0x00,0x03,0x01,0x97, ++ 0xC0,0xF4,0x40,0x09,0x89,0x16,0x40,0x84,0x00,0xC4,0x01,0x67,0x41,0xC4,0x41,0x8C, ++ 0xC4,0x00,0x92,0x05,0x00,0xC4,0xC9,0xD4,0xD0,0xF4,0xC0,0x4B,0x10,0x8A,0x8C,0x16, ++ 0x85,0x07,0xE8,0x87,0x00,0x84,0xC9,0x14,0x40,0x84,0x81,0x43,0xE0,0xF8,0xC5,0x0C, ++ 0xE0,0x00,0x82,0x0C,0xE0,0xB0,0xC5,0x14,0xE0,0x00,0x82,0x14,0xC4,0x04,0xE0,0x00, ++ 0x80,0x04,0xC0,0x94,0x40,0x00,0x82,0x94,0xC2,0x8C,0x40,0x00,0x80,0x8C,0xC0,0x84, ++ 0x40,0x01,0x80,0x46,0xC2,0x84,0x40,0x00,0x80,0x84,0xC0,0x7C,0x40,0x00,0x82,0x7C, ++ 0xC2,0x74,0x40,0x00,0x80,0x74,0xC0,0xC4,0xE2,0x00,0x92,0x05,0x80,0xC4,0xC8,0x6C, ++ 0xC4,0xC4,0x10,0x42,0xD2,0x06,0x38,0x77,0x87,0x0D,0xE9,0x85,0xA8,0x85,0x37,0x6A, ++ 0xF0,0x2C,0x30,0x22,0x30,0x8A,0x30,0xFA,0x37,0xC2,0xB9,0xF7,0xF1,0x5F,0x30,0xDA, ++ 0x31,0x92,0x31,0x4A,0x37,0x02,0xB9,0xFF,0xDF,0xB7,0xE9,0x85,0xAC,0xBD,0x87,0x45, ++ 0x33,0x6A,0xD8,0x43,0x87,0x24,0xD0,0x43,0x85,0x1C,0xE0,0x43,0x40,0x29,0x90,0x2E, ++ 0x06,0x01,0x18,0x02,0x18,0x43,0x03,0x01,0x18,0x43,0x05,0x6F,0x02,0x89,0xEE,0x02, ++ 0x38,0x00,0xAA,0x26,0x4D,0x52,0x5A,0x43,0x1B,0x42,0x18,0x43,0x02,0x27,0x48,0x42, ++ 0x5E,0x43,0x1D,0x4A,0x1B,0x42,0x18,0x43,0x39,0x01,0x30,0x42,0x80,0x01,0x85,0x3C, ++ 0xC0,0x01,0x83,0x34,0x00,0xD7,0x03,0x01,0x1B,0x43,0x5F,0x73,0x20,0x01,0x00,0x17, ++ 0x43,0xB0,0xE3,0x20,0x97,0x25,0x3F,0x80,0x88,0x16,0xC0,0x24,0x17,0x22,0x9C,0xBE, ++ 0xC4,0x24,0x10,0x22,0x87,0xDE,0xA3,0x63,0xC1,0x44,0x08,0xE9,0xCA,0x00,0x08,0x48, ++ 0xC1,0x00,0x4A,0xC2,0xEE,0x03,0x08,0x43,0x30,0x12,0x09,0x01,0x00,0x09,0xD8,0x54, ++ 0xBC,0xF7,0xF7,0x8F,0xD0,0x54,0x90,0x04,0x31,0x5A,0x31,0x0A,0x00,0x11,0xD0,0x44, ++ 0xBE,0xF7,0xF7,0xFF,0x42,0x82,0x41,0x0B,0x3F,0x48,0xAA,0xE6,0x40,0x0B,0x10,0x11, ++ 0x18,0x8A,0x00,0x0B,0x40,0x5A,0x09,0x41,0x00,0x0B,0x44,0x0B,0x10,0xF9,0x97,0x19, ++ 0x18,0x8A,0x00,0x0B,0x78,0x01,0x88,0x2E,0x30,0x4A,0xC1,0x44,0xB9,0xFF,0xDF,0x3F, ++ 0x00,0x01,0x80,0x14,0xC3,0x1C,0x18,0x02,0x00,0x08,0xC2,0x44,0xC6,0x40,0x08,0x09, ++ 0x02,0x48,0xC4,0x00,0x81,0x2C,0x00,0x47,0xC6,0x3C,0xE8,0x03,0x40,0x31,0x88,0x36, ++ 0x48,0xE2,0x40,0x43,0x10,0x81,0x18,0x82,0x00,0x43,0x38,0x31,0x07,0x07,0x39,0x80, ++ 0x80,0x9E,0x08,0x09,0x00,0x0A,0x05,0x07,0xFF,0x85,0x59,0x43,0x10,0x42,0x88,0x1E, ++ 0xC6,0x3C,0xE8,0x03,0x47,0x31,0x88,0xBE,0x50,0x15,0xA8,0x04,0x91,0x0C,0x30,0x12, ++ 0x30,0xCA,0xD9,0x44,0xC7,0x2C,0xB8,0xFF,0xE8,0x17,0xC7,0x1C,0xCA,0x2C,0x00,0x00, ++ 0xC0,0x00,0x82,0x2C,0x43,0xB0,0xE3,0x20,0x90,0x25,0xC7,0x24,0x16,0x22,0x9C,0x9E, ++ 0x78,0x01,0x88,0x0E,0xC3,0x14,0x18,0x43,0xE7,0xF8,0x93,0xFD,0xC0,0x34,0xC0,0x03, ++ 0xE5,0x00,0x12,0xC2,0xCB,0x5E,0x38,0xF7,0x58,0x80,0x04,0x01,0x20,0x20,0x07,0x00, ++ 0xAA,0xAA,0xAA,0xAA,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x39,0xFF,0x37,0x52, ++ 0x00,0x01,0xC8,0x54,0xBC,0xF7,0xEF,0x27,0x87,0x5D,0xE8,0x85,0xAC,0xBD,0x87,0x2D, ++ 0x33,0x62,0xD8,0x03,0x87,0x14,0xD0,0x0B,0x88,0x0C,0xC8,0x0C,0xC2,0x14,0x18,0x42, ++ 0xCA,0x2C,0x00,0x10,0xC6,0x90,0x0A,0x09,0x02,0x48,0xC4,0xA8,0xA8,0x24,0xC8,0x2C, ++ 0x8A,0xA1,0xC1,0x30,0xCF,0x2C,0x88,0xF9,0x8A,0x29,0xC1,0x38,0xB8,0x1C,0xC8,0x2C, ++ 0xC0,0x14,0xC0,0x40,0x0A,0xE9,0x09,0x48,0xC0,0x00,0xEA,0x03,0x4E,0xFA,0x0F,0x43, ++ 0xD0,0x3C,0x90,0x04,0x30,0x1A,0x09,0x01,0x00,0x09,0xD0,0x2C,0xBA,0xF7,0xF7,0x4F, ++ 0x30,0x12,0x01,0x11,0xCF,0x3C,0xB8,0xF7,0xE8,0x9F,0x0A,0x01,0x00,0x09,0xD8,0x3C, ++ 0xD7,0x14,0xB8,0xF7,0xE8,0x47,0xD7,0x3C,0x91,0x04,0x30,0x1A,0x00,0x11,0xD0,0x2C, ++ 0xCF,0x14,0xB8,0xF7,0xF0,0xB7,0xD1,0x3C,0x92,0x04,0x00,0x29,0xE9,0x0A,0x30,0x1A, ++ 0x11,0x01,0x30,0x42,0xBF,0xFF,0xF7,0x97,0x08,0x09,0x30,0x42,0xD8,0x3C,0xD0,0x14, ++ 0xBE,0xF7,0xEF,0x8F,0xD0,0x3C,0x90,0x04,0x30,0x1A,0x01,0x19,0xD0,0x2C,0xC8,0x14, ++ 0xB8,0xF7,0xF7,0xFF,0x30,0x12,0x01,0x01,0xCF,0x3C,0xB8,0xF7,0xE8,0x4F,0xD1,0x3C, ++ 0x90,0x04,0x08,0x01,0x30,0x1A,0x31,0x42,0xD7,0x2C,0xB8,0xF7,0xF5,0x97,0xE0,0x03, ++ 0x40,0x29,0xC0,0x96,0x00,0x01,0x08,0x01,0x05,0x67,0xD8,0x13,0x10,0x12,0xC4,0x06, ++ 0x01,0x4C,0x41,0x54,0x81,0x93,0x41,0x54,0x83,0xD3,0xE1,0xF8,0xE5,0xB0,0xE3,0x68, ++ 0xE6,0x00,0x92,0x05,0xD4,0x0C,0x10,0x82,0x98,0x7E,0xCF,0x1C,0xC0,0x24,0x10,0x01, ++ 0x00,0x57,0x40,0x1C,0xC2,0x6B,0xC8,0xD8,0x92,0xDD,0x80,0xD8,0x00,0x1C,0x80,0x5B, ++ 0xE4,0x48,0xE2,0x00,0xE6,0x90,0x92,0x95,0xDC,0x1B,0x15,0x9A,0xC0,0x8E,0x87,0x45, ++ 0xEB,0x85,0xAF,0x85,0x35,0x42,0x80,0xC1,0x34,0x6A,0xA8,0x01,0x5F,0x53,0x51,0x73, ++ 0x53,0x5B,0x55,0x63,0xE0,0x6B,0x69,0x01,0x81,0xD6,0x32,0x2A,0x19,0xEA,0x18,0xAA, ++ 0x18,0xAA,0x80,0x0E,0x28,0x19,0x80,0x2B,0xC0,0x2B,0x68,0x01,0x83,0x0E,0xF0,0x68, ++ 0x81,0x2B,0x30,0x2A,0x10,0xAA,0x80,0x26,0x30,0xEA,0x10,0xAA,0x88,0x0E,0x10,0x09, ++ 0x01,0x97,0x30,0x2A,0x10,0xAA,0x81,0x26,0x30,0xEA,0x10,0xAA,0x88,0x0E,0x10,0x11, ++ 0x00,0x57,0x60,0x01,0x80,0x1E,0x10,0x9A,0x88,0x0E,0x10,0x79,0x01,0x27,0x10,0x9A, ++ 0x80,0x0E,0x10,0x21,0x00,0x07,0x10,0x01,0xC8,0x1B,0x24,0x01,0x10,0x9A,0x8C,0x0E, ++ 0x50,0x01,0x88,0x0E,0x01,0x24,0x04,0x57,0x40,0x1C,0x2C,0xC9,0x0D,0x68,0x13,0x5A, ++ 0x92,0x0E,0xE0,0xD8,0x00,0x1C,0x34,0x5A,0x2D,0x09,0x98,0x01,0x50,0x11,0x80,0x26, ++ 0xE0,0x8E,0x50,0x01,0x80,0xDE,0x50,0x09,0x8C,0xCE,0x40,0x34,0x70,0xE1,0xC9,0xB6, ++ 0xF0,0xDB,0x5A,0x51,0x90,0x9E,0x30,0x5A,0x98,0x01,0xE6,0xF3,0x18,0x72,0xA1,0xF3, ++ 0xA4,0x6B,0x04,0x24,0x00,0x5F,0x50,0x21,0x80,0x4E,0x50,0x79,0x8C,0x3E,0x40,0x34, ++ 0x70,0xE1,0xC9,0x26,0xF0,0xDB,0x5A,0x51,0x94,0x0E,0xA0,0x6B,0x04,0x24,0x8C,0x13, ++ 0xEF,0x85,0xAB,0x9D,0x80,0x4D,0x34,0x32,0xC4,0x54,0xD0,0x03,0x80,0x3C,0xC0,0x54, ++ 0xD0,0x03,0x86,0x34,0xC0,0x54,0xE8,0x03,0x43,0xF1,0x98,0x8E,0xC5,0x54,0x80,0x01, ++ 0xF0,0x03,0x40,0x01,0x88,0x66,0xC3,0x54,0xCA,0x03,0x34,0x00,0x70,0x00,0x80,0x2C, ++ 0x04,0x09,0x06,0x00,0xC1,0xB8,0x31,0xA2,0xA1,0xA1,0x01,0x81,0xF7,0x82,0x41,0x81, ++ 0xDF,0x26,0xC0,0x81,0x30,0x84,0x01,0x09,0x80,0x24,0x00,0x0F,0x00,0x01,0x80,0x24, ++ 0x01,0x91,0xF1,0x82,0x0E,0x79,0x1F,0x4A,0x10,0x42,0xE4,0x26,0x83,0x81,0x37,0x84, ++ 0x00,0x09,0x80,0x1C,0x00,0x0F,0x00,0x01,0x83,0x1C,0x40,0xEA,0x82,0x14,0x10,0x02, ++ 0x80,0x0C,0x00,0x01,0x81,0x44,0x00,0xBF,0x29,0x01,0x00,0x77,0x01,0x01,0xF0,0xC2, ++ 0xCC,0x2C,0x10,0x42,0xD0,0xCE,0x40,0x01,0xE8,0x56,0xC8,0x14,0x10,0x42,0xEC,0x06, ++ 0x80,0x14,0xC0,0x24,0x40,0x01,0x80,0xE6,0xC2,0x03,0xF1,0x00,0x80,0x03,0x01,0xC7, ++ 0x40,0x01,0xD0,0xB6,0xCC,0x0C,0x10,0x42,0xD0,0x06,0x80,0x0C,0xC0,0x1C,0x40,0x01, ++ 0x81,0x7E,0xC0,0x03,0xE1,0x00,0x82,0x03,0x00,0x5F,0xC0,0x54,0x08,0x21,0xEB,0x03, ++ 0x83,0x07,0xD8,0x47,0x48,0x19,0x8B,0x26,0xC9,0x2C,0xC0,0x03,0x42,0x48,0xD2,0x00, ++ 0x85,0x03,0xE1,0xF8,0xE3,0x20,0xE3,0x68,0x90,0x6D,0xC7,0x34,0x16,0x2A,0x9C,0x6E, ++ 0xC2,0x44,0xE0,0x00,0x90,0x05,0x86,0x44,0xC8,0x3C,0xC0,0x44,0x16,0x42,0x9C,0x1E, ++ 0x70,0x8C,0xC1,0x14,0xC1,0x40,0x30,0x84,0x70,0x8C,0xC3,0x0C,0xC3,0x40,0x30,0x84, ++ 0x37,0x57,0xAC,0xBD,0x80,0x15,0x34,0x62,0x37,0xBA,0xE0,0x2B,0xDF,0x33,0xD3,0x03, ++ 0x1A,0x42,0x03,0x08,0xC0,0x14,0xC0,0x40,0x0C,0x09,0x06,0x48,0xC0,0x00,0x82,0x0C, ++ 0x36,0x02,0x81,0x01,0xE4,0x0B,0x10,0x01,0x18,0x8A,0xA0,0x0B,0x00,0xB1,0xED,0x02, ++ 0x42,0x01,0x80,0x46,0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42,0xBC,0xF7,0xE7,0x5F, ++ 0x30,0x1A,0xB9,0x04,0x08,0x01,0x00,0x19,0xD7,0x14,0xB8,0xF7,0xE2,0xD7,0x06,0x29, ++ 0xE9,0x0A,0x30,0x1A,0x30,0xD2,0xC1,0x0C,0xBE,0xFF,0xC7,0xEF,0x58,0x03,0x17,0x09, ++ 0x35,0x8A,0x00,0x4A,0x1F,0x42,0x18,0x03,0xE7,0x68,0x93,0x6D,0x58,0x0B,0x03,0x0F, ++ 0xE7,0x68,0x93,0x6D,0x35,0x82,0x00,0x42,0x10,0x0A,0x88,0x0E,0x17,0xAA,0x9D,0xBE, ++ 0x11,0xAA,0x85,0x06,0xA1,0x2B,0x37,0xDA,0x30,0x52,0x09,0x01,0x07,0x09,0xB8,0xF7, ++ 0xE1,0x17,0x33,0x1A,0xB9,0x04,0x30,0x4A,0x00,0x11,0xD0,0x14,0xBD,0xF7,0xE7,0x8F, ++ 0xC1,0x14,0x08,0xE9,0xCA,0x00,0x0A,0x48,0xC1,0x00,0x52,0x62,0xEE,0x03,0x08,0x83, ++ 0x42,0x62,0x41,0x0B,0x3F,0x48,0xAA,0xE6,0x04,0x41,0x00,0x83,0x47,0x83,0x08,0xF9, ++ 0x88,0x19,0x18,0x42,0x00,0x83,0x80,0x2D,0xEF,0x85,0xAF,0x85,0x84,0xBD,0x34,0x22, ++ 0x37,0x6A,0xD0,0x7B,0xD0,0x43,0x85,0x6C,0x31,0x1A,0x9B,0xA1,0x9C,0xB4,0x08,0x29, ++ 0x34,0x02,0x03,0x48,0xC6,0x20,0x0A,0x09,0x03,0x48,0x24,0x0A,0x8B,0xAC,0xC8,0x43, ++ 0x02,0x00,0x92,0x05,0x80,0x2C,0x00,0x01,0x80,0x24,0x00,0x09,0x81,0x14,0x30,0x42, ++ 0x80,0x01,0x86,0xA4,0xE3,0x03,0x5A,0x73,0x32,0x32,0x3C,0x10,0x58,0x43,0x1D,0x32, ++ 0x50,0x01,0xD0,0x46,0x40,0xA2,0x18,0x32,0xB3,0x1C,0x30,0x82,0x10,0xD9,0x07,0x82, ++ 0xD2,0xA4,0xA0,0x83,0x00,0x47,0x40,0x82,0x18,0x02,0x1E,0x32,0xB3,0x1C,0x30,0x82, ++ 0x10,0x21,0x18,0x82,0xD2,0xA4,0xA0,0x83,0x35,0x01,0x18,0x73,0xD8,0x43,0x45,0x01, ++ 0x80,0x36,0xD0,0x6C,0xC2,0x14,0xF0,0x90,0x00,0x82,0xD4,0x1C,0x18,0x82,0x80,0x1C, ++ 0x34,0x52,0x91,0x01,0x92,0x9C,0xF0,0x83,0x80,0x8C,0x00,0x3F,0x00,0x01,0x00,0x42, ++ 0xC7,0x87,0xF9,0xFF,0x18,0x00,0x04,0x42,0xAA,0xAA,0xAA,0xAA,0xC0,0x9C,0x10,0xC1, ++ 0xB0,0x12,0x94,0x84,0xD0,0x9C,0x00,0x01,0x18,0x83,0x80,0x7C,0xD6,0x9C,0x10,0x83, ++ 0x80,0x74,0x10,0x01,0x97,0x64,0x50,0xFA,0x90,0x5C,0x10,0x01,0x91,0x54,0x30,0x72, ++ 0xB5,0x01,0x99,0x83,0xCA,0x43,0x45,0x00,0x85,0x4C,0x10,0xA1,0xFA,0x82,0x82,0x00, ++ 0x85,0x44,0xE0,0x43,0x40,0x29,0xC0,0xCE,0x03,0x01,0x30,0x12,0x32,0x84,0x30,0x84, ++ 0x30,0x22,0x04,0x87,0x10,0x01,0x00,0x47,0x41,0x44,0x80,0x03,0x40,0x44,0x80,0xC3, ++ 0xE4,0xD8,0xE2,0x48,0xE2,0x20,0xE3,0x90,0x95,0x95,0x12,0xD2,0xDB,0xA6,0x37,0x02, ++ 0xE2,0x00,0x92,0x05,0x30,0x22,0xC4,0x6C,0x2F,0x22,0xDC,0x5E,0xC0,0xB4,0x80,0x3C, ++ 0xE0,0xAC,0x00,0x01,0x85,0x94,0x00,0xBF,0x00,0x01,0x80,0x34,0x30,0x32,0xCC,0x94, ++ 0xC4,0x14,0x00,0x42,0xC8,0x1C,0x10,0x42,0x80,0x86,0x03,0x01,0x32,0x22,0x04,0xEF, ++ 0xC1,0x3C,0x40,0x0C,0xC2,0x03,0xD0,0x00,0x91,0x05,0x00,0x04,0xCA,0x9C,0xE0,0x4B, ++ 0x48,0x11,0x98,0xA6,0xCC,0x84,0x10,0x42,0xD5,0x8E,0xD8,0x8B,0xE5,0x48,0x9A,0x8B, ++ 0xC8,0x64,0xC0,0x48,0x88,0x64,0xD8,0x5C,0x34,0x12,0x10,0x1A,0xD8,0x06,0xD0,0x5C, ++ 0x90,0x5C,0xD8,0x54,0x34,0x12,0x10,0x1A,0xE0,0x06,0xD0,0x54,0x90,0x54,0xC8,0x2C, ++ 0x10,0x42,0xD4,0x3E,0x32,0x8A,0xE3,0x48,0x94,0x4D,0x36,0x72,0xC8,0x34,0xC0,0x48, ++ 0x90,0x4D,0x88,0x34,0xCC,0x4C,0x10,0x42,0xEB,0xBE,0xC8,0x4B,0x10,0x0A,0xE4,0x2E, ++ 0xDD,0x94,0x58,0x53,0x0C,0x09,0x00,0xCA,0x1D,0x52,0x18,0x53,0xE0,0x8B,0x4B,0x09, ++ 0x8C,0x0E,0x08,0x09,0xA0,0x8B,0xCB,0x8C,0x10,0x42,0xEC,0xBE,0x30,0x02,0x0B,0x09, ++ 0x00,0x0A,0xC4,0x7C,0x18,0x0A,0x88,0x7C,0x00,0x87,0xC8,0x44,0x10,0x42,0xD4,0x6E, ++ 0xE0,0x8B,0x4B,0x09,0x8C,0x0E,0x08,0x09,0xA0,0x8B,0xCB,0x84,0x10,0x42,0xD4,0x2E, ++ 0x30,0x02,0x0B,0x09,0x00,0x0A,0xC4,0x74,0x18,0x0A,0x88,0x74,0xE0,0x20,0xC5,0x3C, ++ 0xE0,0x00,0x82,0x3C,0x32,0x02,0xE3,0x00,0x94,0x05,0x32,0x22,0x2C,0xE2,0xDD,0xFE, ++ 0x30,0x82,0x43,0x11,0xCB,0x2E,0x30,0x8A,0xC0,0x34,0x80,0x07,0xC8,0x6F,0x97,0x05, ++ 0x00,0x07,0x00,0x01,0x03,0xC8,0xD3,0x20,0x11,0x01,0x00,0x57,0x00,0x67,0x41,0x01, ++ 0xE8,0x7E,0x08,0x01,0xF0,0x0A,0xDB,0x2C,0x10,0xCA,0xD4,0xB6,0xE4,0x18,0x12,0xCA, ++ 0xE8,0x16,0xD0,0x48,0x00,0x0C,0x01,0x87,0x48,0x01,0xE8,0x76,0x09,0x09,0x00,0x0C, ++ 0x00,0x5F,0x08,0x01,0xF4,0x0A,0x13,0x0A,0xD0,0x16,0xD0,0x48,0x00,0x0C,0x01,0x27, ++ 0x48,0x01,0xD0,0x16,0x0E,0x01,0x18,0x4A,0x00,0x0C,0x09,0x01,0xF0,0x0A,0xDB,0x44, ++ 0x10,0xCA,0xD4,0x1E,0xCA,0x24,0xE0,0x48,0x90,0x4D,0x8E,0x24,0xE2,0x20,0xE5,0x90, ++ 0x95,0x95,0x12,0xD2,0xD8,0x9E,0x06,0x5F,0x00,0x01,0x08,0x01,0x01,0x37,0x00,0x0C, ++ 0xE0,0x20,0xD5,0x3C,0xE0,0x90,0x92,0x3C,0xE2,0x00,0x92,0x05,0x17,0xC2,0xDD,0xB6, ++ 0xC2,0x94,0xE0,0x00,0x90,0x05,0x82,0x94,0xC8,0x6C,0xC0,0x94,0x10,0x42,0xD4,0x06, ++ 0x39,0x17,0xCA,0x43,0x40,0x71,0xC9,0x0E,0x01,0x71,0x89,0x43,0xC9,0x24,0xC8,0x43, ++ 0x42,0x48,0xC4,0x00,0x91,0x05,0x8E,0x43,0x40,0x81,0xCA,0x0E,0x01,0x81,0x8A,0x43, ++ 0xC2,0x9C,0xE0,0x03,0x42,0x11,0x98,0x56,0xD8,0x83,0x45,0x11,0xCC,0x3E,0xF2,0x00, ++ 0x90,0x05,0x86,0x04,0xC8,0x54,0xC0,0x5C,0xC0,0x08,0xC2,0x64,0xD0,0x00,0xCA,0x04, ++ 0x84,0x07,0xC8,0x17,0x90,0x05,0x80,0x0C,0x05,0x01,0x28,0x44,0x08,0xE9,0x0B,0x48, ++ 0x10,0x01,0xE0,0xAC,0x31,0x22,0x04,0x0F,0x18,0x01,0x00,0xCF,0x01,0x01,0xF0,0x02, ++ 0xF5,0x84,0x10,0x82,0xD0,0x8E,0xF0,0x0C,0xD8,0x00,0xAC,0x06,0x10,0x02,0x92,0x05, ++ 0x34,0x32,0x10,0x0A,0xE0,0x06,0x30,0x72,0x30,0x8A,0x31,0x32,0x10,0x12,0xDC,0x06, ++ 0x31,0xB2,0x30,0x92,0x69,0x74,0xC5,0x80,0x2D,0x44,0xE5,0x20,0xE2,0xD8,0x92,0xDD, ++ 0x17,0xDA,0xDD,0x1E,0x32,0x02,0xE3,0x00,0x94,0x05,0x32,0x22,0xDC,0x6C,0x28,0xE2, ++ 0xDD,0xD6,0x6E,0x44,0xC2,0x48,0xD4,0x00,0x90,0x05,0xCC,0x04,0x82,0x07,0xC8,0x17, ++ 0x28,0x44,0xC5,0x0C,0x40,0x01,0xD0,0x06,0x13,0x02,0x2A,0x44,0x00,0x17,0x00,0x01, ++ 0x2D,0x44,0x2B,0x44,0xC8,0x9C,0xC0,0x7C,0x18,0x43,0xC8,0x9C,0xC6,0x74,0x10,0x43, ++ 0x87,0xBD,0xE8,0x85,0xAC,0xBD,0x87,0x15,0x32,0x62,0x70,0x9A,0x29,0x01,0x80,0xAB, ++ 0x09,0x11,0x30,0x02,0x80,0x01,0x35,0x3A,0xA9,0x0B,0x34,0x0A,0xD0,0x24,0xC0,0x14, ++ 0xBD,0xFF,0xDF,0x67,0xAD,0xEB,0xDD,0x03,0x40,0x01,0x80,0x76,0x6F,0x5A,0x42,0x43, ++ 0x91,0x3D,0x4C,0x04,0x00,0x43,0x07,0x09,0x81,0x83,0x31,0x0A,0xD0,0x24,0xC0,0x14, ++ 0xBA,0xFF,0xE7,0xA7,0x01,0x01,0x80,0x83,0x00,0x7B,0xD7,0x24,0x90,0x04,0x08,0x01, ++ 0x30,0x1A,0x31,0x42,0xD7,0x14,0xB8,0xF7,0xD5,0xE7,0xE5,0x03,0x40,0x41,0x96,0x0E, ++ 0xE5,0x00,0xA2,0x03,0x30,0xBF,0x10,0x01,0x00,0x37,0x08,0x01,0xE4,0x48,0x92,0x4D, ++ 0x4F,0xA1,0xC8,0xDE,0xE4,0x90,0x92,0x95,0x17,0x12,0xCC,0xB6,0x38,0x82,0x3B,0x18, ++ 0x78,0xD8,0x10,0x09,0x06,0xD2,0x94,0x95,0x18,0xF9,0x0F,0xD8,0x01,0xC2,0x58,0xA2, ++ 0xC0,0x00,0x4E,0x09,0x88,0x66,0x40,0x0B,0x18,0x8A,0x04,0x0B,0x44,0x0B,0x1A,0x8A, ++ 0x04,0x0B,0x42,0x0B,0x1C,0x8A,0x04,0x0B,0x44,0x0B,0x1E,0x8A,0x03,0x0B,0x3E,0x82, ++ 0x48,0x01,0x88,0x66,0x44,0x0B,0x1A,0x8A,0x04,0x0B,0x42,0x0B,0x1C,0x8A,0x04,0x0B, ++ 0x44,0x0B,0x1E,0x8A,0x00,0x0B,0x46,0x0B,0x18,0x8A,0x00,0x0B,0x38,0x82,0x4B,0x11, ++ 0x88,0x66,0x40,0x0B,0x18,0x8A,0x04,0x0B,0x44,0x0B,0x1A,0x8A,0x04,0x0B,0x42,0x0B, ++ 0x1C,0x8A,0x04,0x0B,0x40,0x0B,0x1E,0x8A,0x03,0x0B,0x3E,0x82,0x4F,0x19,0x88,0xE6, ++ 0x44,0x0B,0x18,0x8A,0x04,0x0B,0x40,0x0B,0x1C,0x8A,0x04,0x0B,0x44,0x0B,0x1E,0x8A, ++ 0x02,0x0B,0x46,0x0B,0x1A,0x8A,0x00,0x0B,0x3F,0x82,0xAB,0x8D,0x80,0x3D,0xC4,0x3C, ++ 0xC8,0x3C,0x48,0x00,0x02,0x00,0xC4,0x00,0x38,0x00,0x48,0x92,0x72,0x00,0xC2,0x28, ++ 0x40,0x72,0x40,0x0B,0x90,0x4D,0x8C,0x34,0x5C,0x0B,0x90,0x4D,0x8A,0x2C,0x58,0x0B, ++ 0x90,0x4D,0x8C,0x24,0x5C,0x0B,0x94,0x4D,0x8E,0x1C,0x50,0x0B,0x90,0x75,0x4C,0x52, ++ 0x44,0x53,0x92,0x95,0x90,0x14,0x40,0x53,0x92,0xBD,0x44,0x13,0x90,0x95,0x94,0x0C, ++ 0x58,0x12,0x00,0x5F,0xE7,0xC7,0xF8,0xFF,0x00,0xB0,0x00,0x01,0x00,0x01,0x00,0x42, ++ 0x80,0x00,0x00,0x42,0x08,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x98,0x01,0x52,0xD3, ++ 0x90,0x95,0x94,0x04,0x10,0x09,0x00,0x13,0xA8,0x10,0x1C,0x13,0x12,0x81,0x18,0x13, ++ 0x18,0x13,0x14,0x79,0x11,0x13,0x16,0x01,0x00,0x53,0x12,0x89,0x02,0x53,0x40,0x0B, ++ 0x10,0x81,0x19,0x8A,0x07,0x0B,0x02,0xF9,0x80,0x89,0x17,0xC3,0x07,0x09,0xB8,0xFF, ++ 0xFF,0x17,0x03,0xF9,0x80,0x89,0x14,0xC3,0x07,0x09,0xB8,0xFF,0xF8,0xE7,0x02,0x19, ++ 0x11,0x00,0x00,0x43,0x07,0x09,0xB8,0xFF,0xF8,0xB7,0x0A,0x11,0xC7,0x3C,0xB8,0xFF, ++ 0xF8,0xF7,0x22,0xA1,0x01,0x01,0x40,0x4B,0x30,0x48,0xA8,0x16,0xE7,0x20,0x93,0x25, ++ 0x03,0x0F,0xF0,0x20,0x92,0x25,0xE7,0x00,0x90,0x05,0x46,0x51,0x98,0x9E,0x0F,0x09, ++ 0xC7,0x3C,0xB8,0xFF,0xF8,0x67,0x42,0x6A,0xC8,0x34,0x00,0x0B,0xC8,0x2C,0x18,0x0B, ++ 0xCA,0x24,0x18,0x0B,0xCC,0x1C,0x18,0x0B,0x10,0x33,0x4E,0x4A,0xD2,0x14,0x00,0x53, ++ 0x00,0x7B,0xC8,0x0C,0x00,0x0B,0x4A,0x2A,0xC2,0x04,0x88,0x01,0x10,0x43,0x60,0xA1, ++ 0xC8,0x16,0x00,0x09,0x87,0x45,0xE8,0x85,0x07,0x01,0x38,0xDF,0x00,0x01,0x00,0x42, ++ 0x18,0x00,0x04,0x42,0x00,0x0F,0x00,0x26,0xF8,0x48,0x48,0x21,0x94,0xDE,0x3F,0x58, ++ 0xA8,0x0E,0x00,0x14,0xE6,0x00,0x3C,0x48,0x80,0x06,0x80,0x13,0x38,0x82,0x4B,0x01, ++ 0x86,0x5E,0x38,0x18,0x80,0x16,0x80,0x13,0xE2,0x00,0xF2,0x48,0x48,0x11,0x98,0x26, ++ 0x38,0x18,0xAC,0x16,0x04,0x14,0xE0,0x00,0xF7,0x48,0x3C,0x1F,0x17,0x01,0x38,0x77, ++ 0x16,0x01,0x38,0xFF,0x10,0x01,0x48,0x18,0x11,0x5A,0x9C,0x66,0x54,0x18,0x10,0x5A, ++ 0x98,0x8E,0x18,0x01,0x32,0xE2,0x04,0x77,0x30,0x1A,0x18,0x5A,0xA0,0xE6,0x11,0x01, ++ 0x44,0x18,0x12,0x5A,0x98,0x8E,0x49,0x18,0x10,0x5A,0x9C,0xE6,0x54,0x18,0x10,0x5A, ++ 0x9C,0x0E,0x30,0xA2,0x06,0xFF,0x49,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD6,0x00, ++ 0x0C,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD4,0x00,0x0A,0x92,0x4A,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD2,0x00,0x08,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x0E,0x58,0xD0,0x00,0x0E,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD6,0x00, ++ 0x0C,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD4,0x00,0x0A,0x92,0x42,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A, ++ 0x08,0x92,0x32,0x82,0x3A,0x82,0x03,0xEF,0x78,0x50,0x86,0x06,0x10,0x4A,0x82,0x18, ++ 0x9A,0x06,0x10,0x02,0x00,0x9A,0x12,0x01,0x30,0xE2,0x4C,0x18,0x11,0x5A,0x9C,0x6E, ++ 0x54,0x18,0x10,0x5A,0x9F,0x96,0x10,0xE1,0x08,0x48,0xD4,0x95,0x54,0x18,0x10,0x5A, ++ 0x9C,0x66,0x08,0x48,0x8C,0x90,0x14,0x5A,0x9C,0x46,0x08,0x48,0x8C,0x90,0x14,0x5A, ++ 0x9C,0x26,0x08,0x48,0x84,0xD6,0x89,0x90,0x04,0x07,0x48,0x48,0x4C,0x18,0x16,0x5A, ++ 0x9E,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x14,0x5A,0x9C,0x0E,0x08,0x58, ++ 0xD2,0x00,0x0E,0x92,0x4C,0x18,0x12,0x5A,0x9A,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92, ++ 0x4C,0x18,0x10,0x5A,0x98,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x44,0x18,0x16,0x5A, ++ 0x9E,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92,0x44,0x18,0x14,0x5A,0x9C,0x0E,0x00,0x58, ++ 0xD2,0x00,0x0E,0x92,0x92,0xCE,0x46,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00, ++ 0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A,0x32,0x1A,0x0B,0x92,0x80,0xD8,0x32,0x82, ++ 0x9A,0x0E,0x10,0x02,0x58,0x01,0xA8,0x06,0x13,0x4A,0x3A,0x82,0x32,0x1A,0x83,0xD8, ++ 0x9A,0x06,0x10,0x02,0xA8,0x0D,0x00,0x01,0x36,0x02,0x36,0x02,0xEB,0x15,0x30,0xAA, ++ 0x81,0x07,0xC0,0x17,0x30,0x72,0x05,0x28,0x32,0x4A,0x33,0x9A,0x46,0x00,0x06,0x00, ++ 0x30,0x2A,0x84,0xC5,0xAF,0x05,0xB9,0xDF,0xEB,0xBF,0xE6,0x05,0x3A,0x01,0x40,0x48, ++ 0x30,0xB2,0x35,0x01,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06, ++ 0x2E,0x06,0x2E,0x06,0xEA,0x01,0x02,0x48,0x33,0x6A,0x3C,0x82,0x36,0x22,0x30,0x02, ++ 0x31,0x02,0x36,0x02,0xB8,0xD7,0xDF,0xFF,0x43,0x02,0x38,0x82,0x58,0x60,0x05,0x01, ++ 0x40,0x12,0x48,0x1A,0xF3,0x5D,0x3D,0x82,0x00,0x68,0x00,0x00,0x00,0xC0,0x00,0x00, ++ 0x00,0x30,0x01,0x10,0x39,0x82,0xA3,0x85,0x33,0xA2,0xF3,0x20,0xC3,0x2B,0xE1,0x20, ++ 0x10,0x5A,0x95,0x06,0x33,0xEA,0xE8,0x1A,0x07,0xD8,0xC2,0x18,0xE0,0x85,0x39,0xC2, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x20,0x01,0x42, ++ 0x80,0x20,0x01,0x42,0x80,0x20,0x01,0x42,0x80,0x20,0x01,0x42,0x80,0x20,0x03,0x42, ++ 0x80,0xA0,0x00,0x42,0x80,0x20,0x03,0x42,0x80,0xA0,0x00,0x42,0x80,0x20,0x03,0x42, ++ 0x80,0xA0,0x00,0x42,0x80,0x20,0x03,0x42,0x80,0xA0,0x00,0x42,0x80,0xA0,0x03,0x42, ++ 0x80,0x20,0x00,0x42,0x80,0xA0,0x03,0x42,0x80,0xA0,0x03,0x42,0x80,0x20,0x04,0x42, ++ 0x80,0x20,0x04,0x42,0x80,0x20,0x04,0x42,0x80,0xA0,0x04,0x42,0x10,0x20,0x08,0x40, ++ 0x40,0x08,0x20,0x10,0x10,0x20,0x08,0x40,0x20,0x08,0x40,0x20,0x20,0x10,0x08,0x40, ++ 0x08,0x81,0x03,0x42,0x08,0xC1,0x03,0x42,0x08,0x41,0x00,0x42,0x08,0x81,0x00,0x42, ++ 0x08,0xC1,0x00,0x42,0x08,0x01,0x01,0x42,0x08,0x81,0x02,0x42,0x08,0x41,0x02,0x42, ++ 0x08,0xC1,0x02,0x42,0x08,0x01,0x02,0x42,0x08,0x01,0x02,0x42,0x08,0xC1,0x01,0x42, ++ 0x08,0x41,0x02,0x42,0x08,0x81,0x01,0x42,0x08,0x81,0x02,0x42,0x08,0x41,0x01,0x42, ++ 0x08,0xC1,0x02,0x42,0x08,0x01,0x01,0x42,0x08,0x01,0x03,0x42,0x08,0x81,0x00,0x42, ++ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00, ++ 0x00,0x08,0xF8,0x0F,0xFF,0x07,0xF8,0xFF,0x07,0xF8,0x0F,0xF8,0x08,0x00,0x08,0x08, ++ 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x28,0xB5,0x39,0xC5,0x08,0x1D, ++ 0x1B,0x2B,0x3A,0x28,0x53,0xB5,0x0A,0xC5,0x00,0x08,0x01,0x00,0x01,0x00,0x50,0x0D, ++ 0x52,0x1D,0x52,0xB5,0x39,0x0D,0x04,0x08,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95, ++ 0x51,0x3D,0x54,0x95,0x51,0x3D,0x54,0x95,0x0B,0x3D,0x34,0x88,0x51,0x3D,0x54,0x1D, ++ 0x51,0x3D,0x54,0x95,0x04,0x00,0x50,0x3D,0x50,0x1D,0x01,0x00,0x00,0x00,0x00,0x00, ++ 0x54,0x2D,0x53,0x3D,0x32,0x8D,0x32,0x38,0x01,0x28,0x0A,0x45,0x50,0xB5,0x53,0x95, ++ 0x00,0x00,0x00,0x00,0x52,0xA5,0x51,0xB5,0x09,0xC5,0x03,0x08,0x03,0x00,0x50,0x3D, ++ 0x55,0x1D,0x51,0x0D,0x51,0x3D,0x54,0x95,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95, ++ 0x51,0x0D,0x55,0x0D,0x54,0xB5,0x3A,0x0D,0x00,0x08,0x01,0x00,0x53,0xA5,0x51,0x2D, ++ 0x52,0x3D,0x34,0x8A,0x1D,0x38,0x52,0x45,0x52,0x0D,0x51,0x1D,0x54,0xB5,0x3A,0x0D, ++ 0x53,0xA5,0x29,0xB5,0x39,0xC5,0x08,0x1D,0x19,0x2D,0x22,0x1D,0x44,0x0D,0x31,0x3D, ++ 0x23,0x95,0x09,0xC1,0x29,0xB5,0x0B,0x1D,0x1B,0x2B,0x3A,0x28,0x00,0x00,0x00,0x08, ++ 0xFF,0x07,0x00,0xF8,0x08,0x00,0x10,0x10,0x08,0x10,0x10,0x10,0x08,0x08,0x10,0x08, ++ 0x10,0x08,0x10,0x08,0x10,0x10,0x08,0x08,0x10,0x10,0x08,0x08,0x08,0x08,0x10,0x10, ++ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xF8,0x07, ++ 0x08,0x00,0x08,0x08,0xE8,0xA2,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0xC0,0x00,0x00, ++ 0x00,0x00,0x05,0x00,0xE8,0x62,0x02,0x00,0x00,0xC0,0x00,0x01,0x58,0xA0,0x07,0x00, ++ 0x00,0xE0,0x05,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,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0x00,0x70,0x00,0x30,0x09,0x40,0x1B,0x00,0x06,0x78,0x50,0x56, ++ 0xFF,0xFF,0xFF,0xFF,0x3C,0x50,0x00,0x10,0x00,0x20,0x18,0x00,0x1E,0xAC,0xE4,0x09, ++ 0x0F,0x00,0xCA,0xCA,0xFF,0xFF,0xFF,0xFF,0x0A,0x07,0x82,0x00,0x04,0x00,0x00,0x03, ++ 0x95,0x83,0xC1,0x3C,0xC8,0xB2,0xB5,0x47 ++}; ++ ++ ++ ++#define FW_INFO_SIZE (0x18) ++#define FW_REAL_SIZE (sizeof(fwbin)) ++#define FW_BIN_SIZE (24*1024+24) //24K byte ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx.h b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx.h +new file mode 100644 +index 000000000..68791e6af +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx.h +@@ -0,0 +1,29 @@ ++#ifndef TOUCHSCREEN_CST3XX__H ++#define TOUCHSCREEN_CST3XX__H ++ ++ ++/* -- dirver configure -- */ ++#define CFG_MAX_TOUCH_POINTS 1 ++#define MAX_AREA 0xff ++ ++#define CST3XX_NAME "cst3xx" ++ ++/*register address*/ ++#define CST3XX_ADDRESS 0x1A ++ ++ ++/* The platform data for the Focaltech ft5x0x touchscreen driver */ ++struct cst3xx_platform_data { ++ unsigned int x_min; ++ unsigned int y_min; ++ unsigned int x_max; ++ unsigned int y_max; ++ unsigned long irqflags; ++ unsigned int int_gpio; ++ unsigned int reset_gpio; ++}; ++ ++ ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx_1.c b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx_1.c +new file mode 100644 +index 000000000..0c7725e88 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx_1.c +@@ -0,0 +1,1422 @@ ++/* ++ * cst3xx Touchscreen Controller Driver ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../../video/jz_fb_v13/jz_fb.h" ++ ++struct st1615_ts_finger { ++ u16 x; ++ u16 y; ++ u8 t; ++ bool is_valid; ++}; ++ ++struct cst3xx_ts_data { ++ struct i2c_client *client; ++ struct input_dev *input_dev; ++ struct cst3xx_platform_data *pdata; ++ struct work_struct work; ++ struct delayed_work dwork; ++ struct workqueue_struct *workqueue; ++ int irq; ++}; ++ ++static int cst3xx_into_program_mode(struct i2c_client * client); ++static int cst3xx_erase_program_area(struct i2c_client * client); ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms); ++static int cst3xx_write_program_data(struct i2c_client * client,const unsigned char *pdata); ++ ++static int cst3xx_check_checksum(struct i2c_client * client); ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client); ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata); ++ ++static int cst3xx_firmware_info(struct i2c_client * client); ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict); ++ ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata); ++ ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_test(struct i2c_client *client); ++static void cst3xx_reset(struct cst3xx_ts_data *ts) ; ++extern void close_vcc3v3Power(void); ++extern void open_vcc3v3Power(void); ++ ++static unsigned char *pcst3xx_update_firmware = (unsigned char *)cst3_fw ; //the updating firmware ++static unsigned int g_cst3xx_ic_version = 0; ++static unsigned int g_cst3xx_ic_checksum = 0; ++static unsigned int g_cst3xx_ic_checkcode =0; ++static unsigned int g_cst3xx_ic_project_id = 0; ++static unsigned int g_cst3xx_ic_type = 0; ++ ++static unsigned char report_flag = 0; ++static unsigned int x_temp_pos = 0; ++static unsigned int y_temp_pos = 0; ++ ++#define HYN_DRAW_POINT ++ ++#define USE_ANALOG_I2C 1 //i2c analog ++//#define USE_HIGHEST_I2CA 1// x1000 highest i2c ++//#define USE_LOWEST_I2CA 1 // x1000 lowest i2c ++#define HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++//#define HYN_UPDATE_FIRMWARE_ENABLE ++ ++#pragma pack(1) ++typedef struct ++{ ++ u16 pid; //product id // ++ u16 vid; //version id // ++} st_tpd_info; ++#pragma pack() ++ ++st_tpd_info tpd_info; ++ ++#define CST3XX_BIN_SIZE (24*1024 + 24) ++#define CST3XX_MAX_X 340 ++#define CST3XX_MAX_Y 800 ++#define ERROR_TOUCH 1 ++ ++static void cst3xx_ts_power(struct cst3xx_ts_data *ts, bool poweron) ++{ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) ++ gpio_direction_output(ts->pdata->reset_gpio, poweron); ++} ++ ++static int cst3xx_into_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x01; ++ buf[2] = 0xAA; //set cmd to enter program mode ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(2); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; //check whether into program mode ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++static int cst3xx_erase_program_area(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; ++ buf[2] = 0x00; //set cmd to erase main area ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(5); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x03; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++ ++ ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms) ++{ ++ ++ unsigned char buf[4]; ++ buf[0] = 0xD1; ++ buf[1] = 0x0E; ++ cst3xx_i2c_write(ts->client, buf, 2); ++/* ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(2); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++*/ ++ mdelay(ms); ++} ++ ++ ++static int cst3xx_write_program_data(struct i2c_client * client, ++ const unsigned char *pdata) ++{ ++ int i, ret; ++ unsigned char *i2c_buf; ++ unsigned short eep_addr; ++ int total_kbyte; ++ ++ unsigned char temp_buf[8]; ++ unsigned short iic_addr; ++ int j; ++ ++ ++ i2c_buf = kmalloc(sizeof(unsigned char)*(1024 + 2), GFP_KERNEL); ++ if (i2c_buf == NULL) ++ return -1; ++ ++ //make sure fwbin len is N*1K ++ //total_kbyte = len / 1024; ++ total_kbyte = 24; ++ for (i=0; i>8; ++ ret = cst3xx_i2c_write(client, i2c_buf, 4); ++ if (ret < 0) ++ goto error_out; ++ ++ memcpy(i2c_buf, pdata + eep_addr, 1024); ++ for(j=0; j<256; j++) { ++ iic_addr = (j<<2); ++ temp_buf[0] = (iic_addr+0xA018)>>8; ++ temp_buf[1] = (iic_addr+0xA018)&0xFF; ++ temp_buf[2] = i2c_buf[iic_addr+0]; ++ temp_buf[3] = i2c_buf[iic_addr+1]; ++ temp_buf[4] = i2c_buf[iic_addr+2]; ++ temp_buf[5] = i2c_buf[iic_addr+3]; ++ ret = cst3xx_i2c_write(client, temp_buf, 6); ++ if (ret < 0) ++ goto error_out; ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x04; ++ i2c_buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(60); ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x05; ++ ret = cst3xx_i2c_read_register(client, i2c_buf, 1); ++ if (ret < 0) ++ goto error_out; ++ ++ if (i2c_buf[0] != 0x55) ++ goto error_out; ++ ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x03; ++ i2c_buf[2] = 0x00; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(8); ++ ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ ++ return 0; ++ ++error_out: ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ return -1; ++} ++ ++ ++static int cst3xx_check_checksum(struct i2c_client * client) ++{ ++ int ret; ++ int i; ++ unsigned int checksum; ++ unsigned int bin_checksum; ++ unsigned char buf[4]; ++ const unsigned char *pData; ++ ++ for(i=0; i<5; i++) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if(ret < 0) ++ { ++ mdelay(2); ++ continue; ++ } ++ ++ if(buf[0]!=0) ++ break; ++ else ++ mdelay(2); ++ } ++ mdelay(2); ++ ++ ++ if(buf[0]==0x01) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ ++ if(ret < 0) return -1; ++ ++ // read chip checksum ++ checksum = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); ++ ++ pData=(unsigned char *)pcst3xx_update_firmware +24*1024+16; //7*1024 +512 ++ bin_checksum = pData[0] + (pData[1]<<8) + (pData[2]<<16) + (pData[3]<<24); ++ ++ printk(" hyn the updated ic checksum is :0x%x. the updating firmware checksum is:0x%x------\n", checksum, bin_checksum); ++ ++ if(checksum!=bin_checksum) ++ { ++ printk(" cst3xx hyn check sum error.\n"); ++ return -1; ++ ++ } ++ ++ } ++ else ++ { ++ printk(" cst3xx hyn No checksum.\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x06; ++ buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) ++ return -1; ++ ++ mdelay(10); //wait for restart ++ ++ ++ return 0; ++} ++ ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ ++ printk(" cst3xx----------upgrade cst3xx begain------------\n"); ++ disable_irq(ts->irq); ++ mdelay(20); ++START_FLOW: ++ ++#ifdef HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++ close_vcc3v3Power(); ++ mdelay(20); ++ open_vcc3v3Power(); ++ mdelay(5+retry); ++#else ++ cst3xx_reset_ic(ts,5+retry); ++#endif ++ ret = cst3xx_into_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]into program mode failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_erase_program_area(ts->client); ++ if (ret) { ++ printk(" cst3xx[cst3xx]erase main area failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_write_program_data(ts->client, pdata); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]write program data into cstxxx failed.\n"); ++ goto err_out; ++ } ++ ++ ret =cst3xx_check_checksum(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] after write program cst3xx_check_checksum failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_exit_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]exit program mode failed.\n"); ++ goto err_out; ++ } ++ ++ cst3xx_reset_ic(ts,20); ++ ++ printk(" cst3xx hyn----------cst3xx_update_firmware end------------\n"); ++ ++ enable_irq(ts->irq); ++ ++ return 0; ++ ++err_out: ++ if (retry < 30) { ++ retry++; ++ mdelay(20); ++ goto START_FLOW; ++ } ++ else { ++ enable_irq(ts->irq); ++ return -1; ++ } ++} ++ ++ ++ ++ ++/******************************************************* ++Function: ++ get firmware version, ic type... ++Input: ++ client: i2c client ++Output: ++ success: 0 ++ fail: -1 ++*******************************************************/ ++static int cst3xx_firmware_info(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[28]; ++// unsigned short ic_type, project_id; ++ ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x01; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ ++ mdelay(40); ++ ++ buf[0] = 0xD1; ++ buf[1] = 0xFC; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ ++ //0xCACA0000 ++ g_cst3xx_ic_checkcode = buf[3]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[2]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[1]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip g_cst3xx_ic_checkcode:0x%x.\r\n",g_cst3xx_ic_checkcode); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x04; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ g_cst3xx_ic_type = buf[3]; ++ g_cst3xx_ic_type <<= 8; ++ g_cst3xx_ic_type |= buf[2]; ++ ++ ++ g_cst3xx_ic_project_id = buf[1]; ++ g_cst3xx_ic_project_id <<= 8; ++ g_cst3xx_ic_project_id |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip ic g_cst3xx_ic_type :0x%x, g_cst3xx_ic_project_id:0x%x\r\n", ++ g_cst3xx_ic_type, g_cst3xx_ic_project_id); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 8); ++ if (ret < 0) return -1; ++ ++ g_cst3xx_ic_version = buf[3]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[2]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[1]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[0]; ++ ++ g_cst3xx_ic_checksum = buf[7]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[6]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[5]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[4]; ++ ++ tpd_info.vid = g_cst3xx_ic_version; ++ tpd_info.pid = 0x00; ++ ++ ++ printk(" cst3xx [cst3xx] the chip ic version:0x%x, checksum:0x%x\r\n", ++ g_cst3xx_ic_version, g_cst3xx_ic_checksum); ++ ++ if(g_cst3xx_ic_version==0xA5A5A5A5) ++ { ++ printk(" cst3xx [cst3xx] the chip ic don't have firmware. \n"); ++ return -1; ++ } ++ if((g_cst3xx_ic_checkcode&0xffff0000)!=0xCACA0000){ ++ printk("linc cst3xx [cst3xx] cst3xx_firmware_info read error .\r\n"); ++ return -1; ++ } ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x09; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ mdelay(5); ++ ++ ++ return 0; ++} ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict) ++{ ++ unsigned short ic_type, project_id; ++ unsigned int fw_checksum, fw_version; ++ const unsigned int *p; ++ int i; ++ unsigned char *pBuf; ++ ++ fw_checksum = 0x55; ++ p = (const unsigned int *)pdata; ++ for (i=0; i<(CST3XX_BIN_SIZE-4); i+=4) { ++ fw_checksum += (*p); ++ p++; ++ } ++ ++ if (fw_checksum != (*p)) { ++ printk(" cst3xx[cst3xx]calculated checksum error:0x%x not equal 0x%x.\n", fw_checksum, *p); ++ return -1; //bad fw, so do not update ++ } ++ ++ pBuf = &pdata[CST3XX_BIN_SIZE-16]; ++ ++ project_id = pBuf[1]; ++ project_id <<= 8; ++ project_id |= pBuf[0]; ++ ++ ic_type = pBuf[3]; ++ ic_type <<= 8; ++ ic_type |= pBuf[2]; ++ ++ fw_version = pBuf[7]; ++ fw_version <<= 8; ++ fw_version |= pBuf[6]; ++ fw_version <<= 8; ++ fw_version |= pBuf[5]; ++ fw_version <<= 8; ++ fw_version |= pBuf[4]; ++ ++ fw_checksum = pBuf[11]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[10]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[9]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[8]; ++ ++ printk(" cst3xx[cst3xx]the updating firmware:project_id:0x%04x,ic type:0x%04x,version:0x%x,checksum:0x%x\n", ++ project_id, ic_type, fw_version, fw_checksum); ++ ++ if (strict > 0) { ++ ++ if (g_cst3xx_ic_checksum != fw_checksum){ ++ if (g_cst3xx_ic_version >fw_version){ ++ printk("[cst3xx]fw version(0x%x), ic version(0x%x).\n",fw_version, g_cst3xx_ic_version); ++ return -1; ++ } ++ }else{ ++ printk("[cst3xx]fw checksum(0x%x), ic checksum(0x%x).\n",fw_checksum, g_cst3xx_ic_checksum); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ int flag = 0; ++ ++ while (retry++ < 3) { ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret == 0) { ++ flag = 1; ++ break; ++ } ++ } ++ ++ if (flag == 1) { ++ ret = cst3xx_update_judge(pdata, 1); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] no need to update firmware.\n"); ++ return 0; ++ } ++ } ++ ++ ret = cst3xx_update_firmware(ts, pdata); ++ if (ret < 0){ ++ printk(" cst3xx [cst3xx] update firmware failed.\n"); ++ return -1; ++ } ++ ++ mdelay(50); ++ ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx [cst3xx] after update read version and checksum fail.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++/*******************************Chose which I2C interface ********************************************/ ++ ++#if USE_ANALOG_I2C ++ ++#define I2CSDA GPIO_PC(27) ++#define I2CSCL GPIO_PC(26) ++ ++#define I2CSDA_HIGH gpio_direction_output(GPIO_PC(27),1) ++#define I2CSDA_LOW gpio_direction_output(GPIO_PC(27),0) ++ ++#define I2CSCL_HIGH gpio_direction_output(GPIO_PC(26),1) ++#define I2CSCL_LOW gpio_direction_output(GPIO_PC(26),0) ++ ++#define delay_data 2 ++static void iicstart(void) ++{ ++ I2CSDA_HIGH; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_LOW; ++ __udelay(2); ++ I2CSCL_LOW; ++ __udelay(2); ++} ++static void iicstop(void) ++{ ++ I2CSDA_LOW; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_HIGH; ++ __udelay(2); ++ ++} ++static unsigned char waitack(void) ++{ ++ u8 ucErrTime=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ // __udelay(2); ++ ++ // I2CSDA_HIGH; ++ // __udelay(2); ++ I2CSCL_HIGH; ++ __udelay(2); ++ ++ while(__gpio_get_value(GPIO_PC(27))) ++ { ++ ucErrTime++; ++ // printk("time out ++ \n"); ++ if(ucErrTime>250) ++ { ++ iicstop(); ++ return 1; ++ } ++ } ++ I2CSCL_LOW; ++ __udelay(2); ++ return 0; ++} ++static void sendack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_LOW; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ ++} ++static void sendnotack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_HIGH; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++} ++static void iicsendbyte(unsigned char ch) ++{ ++ unsigned char i; ++ I2CSCL_LOW; ++ for(i = 0;i<8;i++) ++ { ++ if(ch&0x80) ++ { ++ I2CSDA_HIGH; ++ } ++ else ++ { ++ I2CSDA_LOW; ++ } ++ __udelay(delay_data); ++ ch<<=1; ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ } ++} ++static unsigned char iicreceivebyte(unsigned char ack) ++{ ++ unsigned char i=8; ++ unsigned char ddata=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ __udelay(delay_data); ++ ++ for(i = 0;i<8;i++) ++ { ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ ++ ddata<<=1; ++ if(gpio_get_value(GPIO_PC(27))) ddata++; ++ } ++ ++ if(!ack) ++ sendnotack(); ++ else ++ sendack(); ++ ++ return ddata; ++} ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int count = len; ++ iicstart(); ++ __udelay(delay_data); ++ ++/* ++ iicsendbyte( (0x1a<<1) | 0); ++ __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ ++ iicsendbyte(buf[0]); ++ __udelay(delay_data); ++ waitack(); ++ __udelay(delay_data); ++*/ ++ iicstart(); ++ __udelay(delay_data); ++ ++ iicsendbyte((0x1a << 1 ) | 1); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ ++ while(count) ++ { ++ if(count == 1) *buf = iicreceivebyte(0); ++ else *buf = iicreceivebyte(1); ++ count --; ++ buf++; ++ } ++ iicstop(); ++ __udelay(delay_data); ++ return 0; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int count = len; ++ iicstart(); ++ // __udelay(delay_data); ++ ++ iicsendbyte((0x1A << 1) | 0); ++// __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write send address wait ack timeoue \n"); ++ return 1; ++ } ++ ++ while(count--) ++ { ++ iicsendbyte(*(buf++)); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ } ++ ++ iicstop(); ++ __udelay(delay_data); ++ ++ return 0; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if(ret) printk("failed to write cst3xx\n"); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ if(ret) printk("failed to write cst3xx\n"); ++ return ret; ++} ++ ++#elif USE_LOWEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_recv(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_send(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ ++ return ret; ++} ++ ++#elif USE_HIGHEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags |= I2C_M_RD; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++/******************************************************* ++Function: ++ read data from register. ++Input: ++ buf: first two byte is register addr, then read data store into buf ++ len: length of data that to read ++Output: ++ success: number of messages ++ fail: negative errno ++*******************************************************/ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msgs[2]; ++ int ret = -1; ++ int retries = 0; ++ ++ msgs[0].flags = 0; ++ msgs[0].addr = client->addr; ++ msgs[0].len = 2; ++ msgs[0].buf = buf; ++ ++ msgs[1].flags |= I2C_M_RD; ++ msgs[1].addr = client->addr; ++ msgs[1].len = len; ++ msgs[1].buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if(ret == 2) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags = 0; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++#else ++#endif ++/*********************************i2c end********************************/ ++ ++ ++static int cst3xx_i2c_test(struct i2c_client *client) ++{ ++ int retry = 0; ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ while (retry++ < 5) { ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret == 0) ++ return ret; ++ ++ mdelay(2); ++ } ++ ++ if(retry==5) printk(" cst3xx hyn I2C TEST error.ret:%d;\n", ret); ++ ++ return ret; ++} ++ ++ ++static void cst3xx_reset(struct cst3xx_ts_data *ts) { ++ if(gpio_is_valid(ts->pdata->reset_gpio)) { ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(100); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++ mdelay(100); ++ } ++} ++/**************************** basic communication end*******************************/ ++ ++ ++static void cst3xx_touch_report(struct cst3xx_ts_data *ts) ++{ ++ unsigned char buf[30]; ++ unsigned char i2c_buf[8]; ++ unsigned char key_status, key_id = 0, finger_id, sw; ++ unsigned int input_x = 0; ++ unsigned int input_y = 0; ++ unsigned int input_w = 0; ++ unsigned int input_x_delta = 0; ++ unsigned int input_y_delta = 0; ++ unsigned char cnt_up, cnt_down; ++ int i, ret, idx; ++ int cnt, i2c_len; ++ ++ int len_1, len_2; ++ ++ key_status = 0; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(ts->client, buf, 7); ++ if(ret < 0) { ++ printk(" iic read touch point data failed.\n"); ++ goto OUT_PROCESS; ++ } ++ // printk(" read buf : buf[0]: %x ,buf[1]: %x ,buf[2]: %x, buf[3]: %x,buf[4]: %x ,buf[5]: %x ,buf[6]: %x, buf[7]: %x,\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); ++ ++ if(buf[6] != 0xAB) { ++ printk(KERN_INFO " data is not valid..\r\n"); ++ goto OUT_PROCESS; ++ } ++ ++ cnt = buf[5] & 0x7F; ++ if(cnt > 1) goto OUT_PROCESS; ++ else if(cnt==0) goto CLR_POINT; ++ ++ if(cnt == 0x01) { ++ goto FINGER_PROCESS; ++ } ++ ++FINGER_PROCESS: ++ ++ /* ++ * sw: buf[0] low 4 bit ++ * x pos: buf[1] low 4 bit | buf[3] high 4 bit ++ * y pos: buf[2] low 4 bit | buf[3] low 4 bit ++ * z press : buf[4] ++ * finger_id:buf[0] high 4 bit ++ */ ++ i2c_buf[0] = 0xD0; ++ i2c_buf[1] = 0x00; ++ i2c_buf[2] = 0xAB; ++ ++ ret = cst3xx_i2c_write(ts->client, i2c_buf, 3); ++ if(ret < 0) { ++ printk(" cst3xx hyn send read touch info ending failed.\r\n"); ++ cst3xx_reset_ic(ts,20); ++ goto END; ++ } ++ ++ idx = 0; ++ cnt_up = 0; ++ cnt_down = 0; ++ input_x = (unsigned int)((buf[idx + 1] << 4) | ((buf[idx + 3] >> 4) & 0x0F)); ++ input_y = (unsigned int)((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0F)); ++ input_w = (unsigned int)(buf[idx + 4]); ++ sw = (buf[idx] & 0x0F) >> 1; ++ finger_id = (buf[idx] >> 4) & 0x0F; ++ ++ printk(" no handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n", input_x, input_y, input_w,finger_id, sw); ++ ++ input_x=input_x*CST3XX_MAX_X/360; ++ input_y=input_y*CST3XX_MAX_Y/800; ++ ++ if(input_x >= CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++ if(input_y >= CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ ++// input_x = CST3XX_MAX_X-input_x; ++// input_y = CST3XX_MAX_Y-input_y; ++ ++#ifdef 0//HYN_DRAW_POINT ++ if(input_x > 300){ ++ input_x_delta = input_x - (CST3XX_MAX_X/2); ++ input_x = input_x + input_x_delta/((CST3XX_MAX_X/2)/20); ++ if(input_x > CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++ } ++ if(input_x < 40){ ++ input_x_delta = (CST3XX_MAX_X/2) - input_x; ++ input_x = input_x - input_x_delta/((CST3XX_MAX_X/2)/12); ++ if(input_x < 0) input_x = 0; ++ } ++ if(input_y > 760){ ++ input_y_delta = input_y - (CST3XX_MAX_Y/2); ++ input_y = input_y + input_y_delta/((CST3XX_MAX_Y/2)/12); ++ if(input_y > CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ } ++ if(input_y < 40){ ++ input_y_delta = (CST3XX_MAX_Y/2) - input_y; ++ input_y = input_y - input_y_delta/((CST3XX_MAX_Y/2)/25); ++ if(input_y < 0) input_y = 0; ++ } ++#endif ++ ++ printk(" handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n\n", input_x, input_y, input_w,finger_id, sw); ++ ++ if (sw == 0x03 ) { ++ if((input_x > x_temp_pos + ERROR_TOUCH) || (input_x < x_temp_pos -ERROR_TOUCH) || (input_y > y_temp_pos + ERROR_TOUCH) || (input_y < y_temp_pos -ERROR_TOUCH)) ++ { ++ // printk(" REPORT TOUCH DOWM Handle \n"); ++ x_temp_pos = input_x; ++ y_temp_pos = input_y; ++ input_report_key(ts->input_dev, BTN_TOUCH, 1); ++ input_report_abs(ts->input_dev, ABS_X, input_x); ++ input_report_abs(ts->input_dev, ABS_Y, input_y); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 1); ++ input_sync(ts->input_dev); ++ } ++ cnt_down++; ++ } ++ else if(sw == 0) { ++ cnt_up++; ++ } ++ ++ if((cnt_up>0) && (cnt_down==0) ){ ++ // printk(" REPORT TOUCH UP Handle \n"); ++ x_temp_pos = 0; ++ y_temp_pos = 0; ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 0); ++ input_mt_sync(ts->input_dev); ++ } ++ input_sync(ts->input_dev); ++ goto END; ++CLR_POINT: ++ ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_mt_sync(ts->input_dev); ++ input_sync(ts->input_dev); ++ ++OUT_PROCESS: ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ buf[2] = 0xAB; ++ ret = cst3xx_i2c_write(ts->client, buf, 3); ++ if (ret < 0) { ++ printk(" send read touch info ending failed.\n"); ++ cst3xx_reset_ic(ts,20); ++ } ++END: ++ return; ++} ++ ++ ++/******************************* irq handle begin************************************/ ++static void cst3xx_work_handler(struct work_struct *work) ++{ ++ struct cst3xx_ts_data *cst3xx_ts = container_of(work, struct cst3xx_ts_data, work); ++ int ret = 0; ++ /******************here handle touch *******************/ ++ // printk(KERN_INFO "-----------enter cst3xx_work_handler------------\n"); ++ cst3xx_touch_report(cst3xx_ts); ++ enable_irq(cst3xx_ts->irq); ++} ++ ++static irqreturn_t cst3xx_ts_irq_handler(int irq, void *dev_id) ++{ ++ struct cst3xx_ts_data *ts = dev_id; ++ ++ // printk( KERN_INFO "-----------enter cst3xx_ts_irq_handler------------\n"); ++ ++ disable_irq_nosync(ts->irq);//use in interrupt,disable_irq will make dead lock. ++ ++ if (!work_pending(&ts->work)) { ++ queue_work(ts->workqueue, &ts->work); ++ // queue_delayed_work(ts->workqueue,&ts->dwork,1);//10ms * x ++ } else { ++ enable_irq(ts->irq); ++ } ++ ++ return IRQ_HANDLED; ++} ++/******************************* irq handle end************************************/ ++ ++static int cst3xx_ts_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ printk( KERN_INFO "Enter cst3xx_ts_probe -------------------\n"); ++ ++ int ret; ++ struct cst3xx_ts_data *ts; ++ ++ struct cst3xx_platform_data *pdata = (struct cst3xx_platform_data*)client->dev.platform_data; ++ struct input_dev *input_dev; ++ int error; ++ ++#if USE_ANALOG_I2C ++ if (gpio_is_valid(I2CSDA)) ++ { ++ gpio_free(I2CSDA); ++ ret = gpio_request(GPIO_PC(27),"I2C1-SDA"); ++ if(ret < 0){ ++ printk("I2C1-SDA gpio request failed\n"); ++ return ret; ++ } ++ } ++ if (gpio_is_valid(I2CSCL)) ++ { ++ gpio_free(I2CSCL); ++ ret = gpio_request(GPIO_PC(26),"I2C1-SCL"); ++ if(ret < 0){ ++ printk("I2C1-SCL gpio request failed\n"); ++ return ret; ++ } ++ } ++#endif ++ ++ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); ++ if (!ts) ++ return -ENOMEM; ++ input_dev = input_allocate_device(); ++ if(!input_dev) ++ return -ENOMEM; ++ ++ ts->pdata = pdata; ++ ts->client = client; ++ ts->input_dev = input_dev; ++ ++ if(client->addr != 0x1A) //check address ++ { ++ client->addr = 0x1A; ++ printk("Crystal_shen:i2c_client_HYN->addr=%d.\n",client->addr); ++ ++ } ++ ++ if (gpio_is_valid(ts->pdata->int_gpio)) { ++ //error = gpio_request(pdata->int_gpio,"cst3xx gpio irq"); ++ error = gpio_request_one(pdata->int_gpio, GPIOF_IN, "cst3xx gpio irq"); ++ if (error < 0) { ++ dev_err(&client->dev, "Failed to request GPIO %d, error %d\n", ++ pdata->int_gpio, error); ++ return error; ++ } ++ ++ /* if (error < 0) { ++ dev_err(&client->dev, "%s:failed to set gpio irq.\n",__func__); ++ return error; ++ }*/ ++ ts->irq = gpio_to_irq(pdata->int_gpio); ++ printk(" cst3xx ts -> irq = %d.\n",ts->irq); ++ } ++ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) { ++ error = devm_gpio_request(&client->dev, ts->pdata->reset_gpio, NULL); ++ if (error) { ++ dev_err(&client->dev, ++ "Unable to request GPIO pin %d.\n", ++ ts->pdata->reset_gpio); ++ return error; ++ } ++ } ++ cst3xx_reset(ts); ++ printk( KERN_INFO "cst3xx reset -------------------\n"); ++ ret = cst3xx_i2c_test(ts->client); ++ if(ret>=0){ ++ ++ mdelay(100); ++ ++ printk( KERN_INFO "cst3xx test OK -------------------\n"); ++#ifdef HYN_UPDATE_FIRMWARE_ENABLE ++ ret = cst3xx_boot_update_fw(ts,pcst3xx_update_firmware);// ++ if(ret < 0){ ++ printk(" cst3xx hyn_boot_update_fw failed.\n"); ++ return -1; ++ } ++#endif ++ ++ }else{ ++ printk( KERN_INFO "cst3xx hyn i2c communication failed.---------------\n"); ++ return -1; ++ } ++ ++ input_dev->name = "cst3xxx -touchscreen"; ++ input_dev->id.bustype = BUS_I2C; ++ input_dev->dev.parent = &client->dev; ++ ++ set_bit(EV_KEY, input_dev->evbit); ++ set_bit(EV_ABS, input_dev->evbit); ++ set_bit(EV_SYN, input_dev->evbit); ++ set_bit(BTN_TOUCH, input_dev->keybit); ++ ++ set_bit(ABS_X, input_dev->absbit); ++ set_bit(ABS_Y, input_dev->absbit); ++ set_bit(ABS_PRESSURE, input_dev->absbit); ++ ++ ++ input_set_abs_params(input_dev, ABS_X, ts->pdata->x_min, ts->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, ts->pdata->y_min, ts->pdata->y_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0 , 0); ++ ++ /* input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, MAX_AREA, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_POSITION_X, ts->pdata->x_min, ts->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, ts->pdata->y_min, ts->pdata->y_max, 0, 0); ++*/ ++ error = input_register_device(input_dev); ++ if (error) { ++ dev_err(&client->dev, "Unable to register %s input device\n", ++ input_dev->name); ++ return error; ++ } ++ ++ // INIT_DELAYED_WORK(&ts->dwork, cst3xx_work_handler); ++ ++ INIT_WORK(&ts->work, cst3xx_work_handler); ++ ts->workqueue = create_singlethread_workqueue("cst3xx_wq"); ++ ++ error = devm_request_threaded_irq(&client->dev, client->irq, ++ NULL, ++ cst3xx_ts_irq_handler, ++ IRQF_ONESHOT, ++ client->name, ts); ++ if (error) { ++ dev_err(&client->dev, "Failed to register interrupt\n"); ++ return error; ++ } ++ error = request_irq(ts->irq, ++ cst3xx_ts_irq_handler, ++ ts->pdata->irqflags, ++ client->dev.driver->name, ++ ts); ++ if (error < 0) { ++ dev_err(&client->dev, "%s: request irq failed\n",__func__); ++ return error; ++ } ++ printk(KERN_INFO "-----------CST3XX probe end ------------\n"); ++ return 0; ++} ++ ++static int cst3xx_ts_remove(struct i2c_client *client) ++{ ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ free_irq(ts->irq,ts); ++ devm_free_irq(&ts->client->dev, ts->client->irq,ts); ++ destroy_workqueue(ts->workqueue); ++ input_unregister_device(ts->input_dev); ++ devm_gpio_free(&ts->client->dev, ts->pdata->reset_gpio); ++ gpio_free(ts->pdata->int_gpio); ++ ++#if USE_ANALOG_I2C ++ gpio_free(I2CSDA); ++ gpio_free(I2CSCL); ++#endif ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int cst3xx_ts_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ enable_irq_wake(client->irq); ++ } else { ++ disable_irq(client->irq); ++ cst3xx_ts_power(ts, false);//reset ++ } ++ ++ return 0; ++} ++ ++static int cst3xx_ts_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ disable_irq_wake(client->irq); ++ } else { ++ cst3xx_ts_power(ts, true); ++ enable_irq(client->irq); ++ } ++ return 0; ++} ++ ++#endif ++ ++static SIMPLE_DEV_PM_OPS(cst3xx_ts_pm_ops, ++ cst3xx_ts_suspend, cst3xx_ts_resume); ++ ++static const struct i2c_device_id cst3xx_ts_id[] = { ++ { CST3XX_NAME, 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, cst3xx_ts_id); ++ ++ ++#ifdef CONFIG_OF ++static const struct of_device_id cst3xx_ts_dt_ids[] = { ++ { .compatible = "xxxxx,cst3xx", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, cst3xx_ts_dt_ids); ++#endif ++ ++ ++static struct i2c_driver cst3xx_ts_driver = { ++ .probe = cst3xx_ts_probe, ++ .remove = cst3xx_ts_remove, ++ .id_table = cst3xx_ts_id, ++ .driver = { ++ .name = CST3XX_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(cst3xx_ts_dt_ids), ++ .pm = &cst3xx_ts_pm_ops, ++ }, ++}; ++ ++module_i2c_driver(cst3xx_ts_driver); ++ ++ ++MODULE_AUTHOR("Tiben"); ++MODULE_DESCRIPTION("SITRONIX CST3XX Touchscreen Controller Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx_2.c b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx_2.c +new file mode 100644 +index 000000000..50f7df826 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/cst3xx_2.c +@@ -0,0 +1,1422 @@ ++/* ++ * cst3xx Touchscreen Controller Driver ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../../video/jz_fb_v13/jz_fb.h" ++ ++struct st1615_ts_finger { ++ u16 x; ++ u16 y; ++ u8 t; ++ bool is_valid; ++}; ++ ++struct cst3xx_ts_data { ++ struct i2c_client *client; ++ struct input_dev *input_dev; ++ struct cst3xx_platform_data *pdata; ++ struct work_struct work; ++ struct delayed_work dwork; ++ struct workqueue_struct *workqueue; ++ int irq; ++}; ++ ++static int cst3xx_into_program_mode(struct i2c_client * client); ++static int cst3xx_erase_program_area(struct i2c_client * client); ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms); ++static int cst3xx_write_program_data(struct i2c_client * client,const unsigned char *pdata); ++ ++static int cst3xx_check_checksum(struct i2c_client * client); ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client); ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata); ++ ++static int cst3xx_firmware_info(struct i2c_client * client); ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict); ++ ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata); ++ ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_test(struct i2c_client *client); ++static void cst3xx_reset(struct cst3xx_ts_data *ts) ; ++extern void close_vcc3v3Power(void); ++extern void open_vcc3v3Power(void); ++ ++static unsigned char *pcst3xx_update_firmware = (unsigned char *)cst3_fw ; //the updating firmware ++static unsigned int g_cst3xx_ic_version = 0; ++static unsigned int g_cst3xx_ic_checksum = 0; ++static unsigned int g_cst3xx_ic_checkcode =0; ++static unsigned int g_cst3xx_ic_project_id = 0; ++static unsigned int g_cst3xx_ic_type = 0; ++ ++static unsigned char report_flag = 0; ++static unsigned int x_temp_pos = 0; ++static unsigned int y_temp_pos = 0; ++ ++#define HYN_DRAW_POINT ++ ++#define USE_ANALOG_I2C 1 //i2c analog ++//#define USE_HIGHEST_I2CA 1// x1000 highest i2c ++//#define USE_LOWEST_I2CA 1 // x1000 lowest i2c ++#define HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++//#define HYN_UPDATE_FIRMWARE_ENABLE ++ ++#pragma pack(1) ++typedef struct ++{ ++ u16 pid; //product id // ++ u16 vid; //version id // ++} st_tpd_info; ++#pragma pack() ++ ++st_tpd_info tpd_info; ++ ++#define CST3XX_BIN_SIZE (24*1024 + 24) ++#define CST3XX_MAX_X 480 ++#define CST3XX_MAX_Y 800 ++#define ERROR_TOUCH 1 ++ ++static void cst3xx_ts_power(struct cst3xx_ts_data *ts, bool poweron) ++{ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) ++ gpio_direction_output(ts->pdata->reset_gpio, poweron); ++} ++ ++static int cst3xx_into_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x01; ++ buf[2] = 0xAA; //set cmd to enter program mode ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(2); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; //check whether into program mode ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++static int cst3xx_erase_program_area(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; ++ buf[2] = 0x00; //set cmd to erase main area ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(5); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x03; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++ ++ ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms) ++{ ++ ++ unsigned char buf[4]; ++ buf[0] = 0xD1; ++ buf[1] = 0x0E; ++ cst3xx_i2c_write(ts->client, buf, 2); ++/* ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(2); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++*/ ++ mdelay(ms); ++} ++ ++ ++static int cst3xx_write_program_data(struct i2c_client * client, ++ const unsigned char *pdata) ++{ ++ int i, ret; ++ unsigned char *i2c_buf; ++ unsigned short eep_addr; ++ int total_kbyte; ++ ++ unsigned char temp_buf[8]; ++ unsigned short iic_addr; ++ int j; ++ ++ ++ i2c_buf = kmalloc(sizeof(unsigned char)*(1024 + 2), GFP_KERNEL); ++ if (i2c_buf == NULL) ++ return -1; ++ ++ //make sure fwbin len is N*1K ++ //total_kbyte = len / 1024; ++ total_kbyte = 24; ++ for (i=0; i>8; ++ ret = cst3xx_i2c_write(client, i2c_buf, 4); ++ if (ret < 0) ++ goto error_out; ++ ++ memcpy(i2c_buf, pdata + eep_addr, 1024); ++ for(j=0; j<256; j++) { ++ iic_addr = (j<<2); ++ temp_buf[0] = (iic_addr+0xA018)>>8; ++ temp_buf[1] = (iic_addr+0xA018)&0xFF; ++ temp_buf[2] = i2c_buf[iic_addr+0]; ++ temp_buf[3] = i2c_buf[iic_addr+1]; ++ temp_buf[4] = i2c_buf[iic_addr+2]; ++ temp_buf[5] = i2c_buf[iic_addr+3]; ++ ret = cst3xx_i2c_write(client, temp_buf, 6); ++ if (ret < 0) ++ goto error_out; ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x04; ++ i2c_buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(60); ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x05; ++ ret = cst3xx_i2c_read_register(client, i2c_buf, 1); ++ if (ret < 0) ++ goto error_out; ++ ++ if (i2c_buf[0] != 0x55) ++ goto error_out; ++ ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x03; ++ i2c_buf[2] = 0x00; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(8); ++ ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ ++ return 0; ++ ++error_out: ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ return -1; ++} ++ ++ ++static int cst3xx_check_checksum(struct i2c_client * client) ++{ ++ int ret; ++ int i; ++ unsigned int checksum; ++ unsigned int bin_checksum; ++ unsigned char buf[4]; ++ const unsigned char *pData; ++ ++ for(i=0; i<5; i++) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if(ret < 0) ++ { ++ mdelay(2); ++ continue; ++ } ++ ++ if(buf[0]!=0) ++ break; ++ else ++ mdelay(2); ++ } ++ mdelay(2); ++ ++ ++ if(buf[0]==0x01) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ ++ if(ret < 0) return -1; ++ ++ // read chip checksum ++ checksum = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); ++ ++ pData=(unsigned char *)pcst3xx_update_firmware +24*1024+16; //7*1024 +512 ++ bin_checksum = pData[0] + (pData[1]<<8) + (pData[2]<<16) + (pData[3]<<24); ++ ++ printk(" hyn the updated ic checksum is :0x%x. the updating firmware checksum is:0x%x------\n", checksum, bin_checksum); ++ ++ if(checksum!=bin_checksum) ++ { ++ printk(" cst3xx hyn check sum error.\n"); ++ return -1; ++ ++ } ++ ++ } ++ else ++ { ++ printk(" cst3xx hyn No checksum.\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x06; ++ buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) ++ return -1; ++ ++ mdelay(10); //wait for restart ++ ++ ++ return 0; ++} ++ ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ ++ printk(" cst3xx----------upgrade cst3xx begain------------\n"); ++ disable_irq(ts->irq); ++ mdelay(20); ++START_FLOW: ++ ++#ifdef HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++ close_vcc3v3Power(); ++ mdelay(20); ++ open_vcc3v3Power(); ++ mdelay(5+retry); ++#else ++ cst3xx_reset_ic(ts,5+retry); ++#endif ++ ret = cst3xx_into_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]into program mode failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_erase_program_area(ts->client); ++ if (ret) { ++ printk(" cst3xx[cst3xx]erase main area failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_write_program_data(ts->client, pdata); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]write program data into cstxxx failed.\n"); ++ goto err_out; ++ } ++ ++ ret =cst3xx_check_checksum(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] after write program cst3xx_check_checksum failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_exit_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]exit program mode failed.\n"); ++ goto err_out; ++ } ++ ++ cst3xx_reset_ic(ts,20); ++ ++ printk(" cst3xx hyn----------cst3xx_update_firmware end------------\n"); ++ ++ enable_irq(ts->irq); ++ ++ return 0; ++ ++err_out: ++ if (retry < 30) { ++ retry++; ++ mdelay(20); ++ goto START_FLOW; ++ } ++ else { ++ enable_irq(ts->irq); ++ return -1; ++ } ++} ++ ++ ++ ++ ++/******************************************************* ++Function: ++ get firmware version, ic type... ++Input: ++ client: i2c client ++Output: ++ success: 0 ++ fail: -1 ++*******************************************************/ ++static int cst3xx_firmware_info(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[28]; ++// unsigned short ic_type, project_id; ++ ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x01; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ ++ mdelay(40); ++ ++ buf[0] = 0xD1; ++ buf[1] = 0xFC; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ ++ //0xCACA0000 ++ g_cst3xx_ic_checkcode = buf[3]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[2]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[1]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip g_cst3xx_ic_checkcode:0x%x.\r\n",g_cst3xx_ic_checkcode); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x04; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ g_cst3xx_ic_type = buf[3]; ++ g_cst3xx_ic_type <<= 8; ++ g_cst3xx_ic_type |= buf[2]; ++ ++ ++ g_cst3xx_ic_project_id = buf[1]; ++ g_cst3xx_ic_project_id <<= 8; ++ g_cst3xx_ic_project_id |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip ic g_cst3xx_ic_type :0x%x, g_cst3xx_ic_project_id:0x%x\r\n", ++ g_cst3xx_ic_type, g_cst3xx_ic_project_id); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 8); ++ if (ret < 0) return -1; ++ ++ g_cst3xx_ic_version = buf[3]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[2]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[1]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[0]; ++ ++ g_cst3xx_ic_checksum = buf[7]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[6]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[5]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[4]; ++ ++ tpd_info.vid = g_cst3xx_ic_version; ++ tpd_info.pid = 0x00; ++ ++ ++ printk(" cst3xx [cst3xx] the chip ic version:0x%x, checksum:0x%x\r\n", ++ g_cst3xx_ic_version, g_cst3xx_ic_checksum); ++ ++ if(g_cst3xx_ic_version==0xA5A5A5A5) ++ { ++ printk(" cst3xx [cst3xx] the chip ic don't have firmware. \n"); ++ return -1; ++ } ++ if((g_cst3xx_ic_checkcode&0xffff0000)!=0xCACA0000){ ++ printk("linc cst3xx [cst3xx] cst3xx_firmware_info read error .\r\n"); ++ return -1; ++ } ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x09; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ mdelay(5); ++ ++ ++ return 0; ++} ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict) ++{ ++ unsigned short ic_type, project_id; ++ unsigned int fw_checksum, fw_version; ++ const unsigned int *p; ++ int i; ++ unsigned char *pBuf; ++ ++ fw_checksum = 0x55; ++ p = (const unsigned int *)pdata; ++ for (i=0; i<(CST3XX_BIN_SIZE-4); i+=4) { ++ fw_checksum += (*p); ++ p++; ++ } ++ ++ if (fw_checksum != (*p)) { ++ printk(" cst3xx[cst3xx]calculated checksum error:0x%x not equal 0x%x.\n", fw_checksum, *p); ++ return -1; //bad fw, so do not update ++ } ++ ++ pBuf = &pdata[CST3XX_BIN_SIZE-16]; ++ ++ project_id = pBuf[1]; ++ project_id <<= 8; ++ project_id |= pBuf[0]; ++ ++ ic_type = pBuf[3]; ++ ic_type <<= 8; ++ ic_type |= pBuf[2]; ++ ++ fw_version = pBuf[7]; ++ fw_version <<= 8; ++ fw_version |= pBuf[6]; ++ fw_version <<= 8; ++ fw_version |= pBuf[5]; ++ fw_version <<= 8; ++ fw_version |= pBuf[4]; ++ ++ fw_checksum = pBuf[11]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[10]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[9]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[8]; ++ ++ printk(" cst3xx[cst3xx]the updating firmware:project_id:0x%04x,ic type:0x%04x,version:0x%x,checksum:0x%x\n", ++ project_id, ic_type, fw_version, fw_checksum); ++ ++ if (strict > 0) { ++ ++ if (g_cst3xx_ic_checksum != fw_checksum){ ++ if (g_cst3xx_ic_version >fw_version){ ++ printk("[cst3xx]fw version(0x%x), ic version(0x%x).\n",fw_version, g_cst3xx_ic_version); ++ return -1; ++ } ++ }else{ ++ printk("[cst3xx]fw checksum(0x%x), ic checksum(0x%x).\n",fw_checksum, g_cst3xx_ic_checksum); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ int flag = 0; ++ ++ while (retry++ < 3) { ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret == 0) { ++ flag = 1; ++ break; ++ } ++ } ++ ++ if (flag == 1) { ++ ret = cst3xx_update_judge(pdata, 1); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] no need to update firmware.\n"); ++ return 0; ++ } ++ } ++ ++ ret = cst3xx_update_firmware(ts, pdata); ++ if (ret < 0){ ++ printk(" cst3xx [cst3xx] update firmware failed.\n"); ++ return -1; ++ } ++ ++ mdelay(50); ++ ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx [cst3xx] after update read version and checksum fail.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++/*******************************Chose which I2C interface ********************************************/ ++ ++#if USE_ANALOG_I2C ++ ++#define I2CSDA GPIO_PC(27) ++#define I2CSCL GPIO_PC(26) ++ ++#define I2CSDA_HIGH gpio_direction_output(GPIO_PC(27),1) ++#define I2CSDA_LOW gpio_direction_output(GPIO_PC(27),0) ++ ++#define I2CSCL_HIGH gpio_direction_output(GPIO_PC(26),1) ++#define I2CSCL_LOW gpio_direction_output(GPIO_PC(26),0) ++ ++#define delay_data 2 ++static void iicstart(void) ++{ ++ I2CSDA_HIGH; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_LOW; ++ __udelay(2); ++ I2CSCL_LOW; ++ __udelay(2); ++} ++static void iicstop(void) ++{ ++ I2CSDA_LOW; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_HIGH; ++ __udelay(2); ++ ++} ++static unsigned char waitack(void) ++{ ++ u8 ucErrTime=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ // __udelay(2); ++ ++ // I2CSDA_HIGH; ++ // __udelay(2); ++ I2CSCL_HIGH; ++ __udelay(2); ++ ++ while(__gpio_get_value(GPIO_PC(27))) ++ { ++ ucErrTime++; ++ // printk("time out ++ \n"); ++ if(ucErrTime>250) ++ { ++ iicstop(); ++ return 1; ++ } ++ } ++ I2CSCL_LOW; ++ __udelay(2); ++ return 0; ++} ++static void sendack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_LOW; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ ++} ++static void sendnotack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_HIGH; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++} ++static void iicsendbyte(unsigned char ch) ++{ ++ unsigned char i; ++ I2CSCL_LOW; ++ for(i = 0;i<8;i++) ++ { ++ if(ch&0x80) ++ { ++ I2CSDA_HIGH; ++ } ++ else ++ { ++ I2CSDA_LOW; ++ } ++ __udelay(delay_data); ++ ch<<=1; ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ } ++} ++static unsigned char iicreceivebyte(unsigned char ack) ++{ ++ unsigned char i=8; ++ unsigned char ddata=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ __udelay(delay_data); ++ ++ for(i = 0;i<8;i++) ++ { ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ ++ ddata<<=1; ++ if(gpio_get_value(GPIO_PC(27))) ddata++; ++ } ++ ++ if(!ack) ++ sendnotack(); ++ else ++ sendack(); ++ ++ return ddata; ++} ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int count = len; ++ iicstart(); ++ __udelay(delay_data); ++ ++/* ++ iicsendbyte( (0x1a<<1) | 0); ++ __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ ++ iicsendbyte(buf[0]); ++ __udelay(delay_data); ++ waitack(); ++ __udelay(delay_data); ++*/ ++ iicstart(); ++ __udelay(delay_data); ++ ++ iicsendbyte((0x1a << 1 ) | 1); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ ++ while(count) ++ { ++ if(count == 1) *buf = iicreceivebyte(0); ++ else *buf = iicreceivebyte(1); ++ count --; ++ buf++; ++ } ++ iicstop(); ++ __udelay(delay_data); ++ return 0; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int count = len; ++ iicstart(); ++ // __udelay(delay_data); ++ ++ iicsendbyte((0x1A << 1) | 0); ++// __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write send address wait ack timeoue \n"); ++ return 1; ++ } ++ ++ while(count--) ++ { ++ iicsendbyte(*(buf++)); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ } ++ ++ iicstop(); ++ __udelay(delay_data); ++ ++ return 0; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if(ret) printk("failed to write cst3xx\n"); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ if(ret) printk("failed to write cst3xx\n"); ++ return ret; ++} ++ ++#elif USE_LOWEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_recv(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_send(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ ++ return ret; ++} ++ ++#elif USE_HIGHEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags |= I2C_M_RD; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++/******************************************************* ++Function: ++ read data from register. ++Input: ++ buf: first two byte is register addr, then read data store into buf ++ len: length of data that to read ++Output: ++ success: number of messages ++ fail: negative errno ++*******************************************************/ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msgs[2]; ++ int ret = -1; ++ int retries = 0; ++ ++ msgs[0].flags = 0; ++ msgs[0].addr = client->addr; ++ msgs[0].len = 2; ++ msgs[0].buf = buf; ++ ++ msgs[1].flags |= I2C_M_RD; ++ msgs[1].addr = client->addr; ++ msgs[1].len = len; ++ msgs[1].buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if(ret == 2) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags = 0; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++#else ++#endif ++/*********************************i2c end********************************/ ++ ++ ++static int cst3xx_i2c_test(struct i2c_client *client) ++{ ++ int retry = 0; ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ while (retry++ < 5) { ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret == 0) ++ return ret; ++ ++ mdelay(2); ++ } ++ ++ if(retry==5) printk(" cst3xx hyn I2C TEST error.ret:%d;\n", ret); ++ ++ return ret; ++} ++ ++ ++static void cst3xx_reset(struct cst3xx_ts_data *ts) { ++ if(gpio_is_valid(ts->pdata->reset_gpio)) { ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(100); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++ mdelay(100); ++ } ++} ++/**************************** basic communication end*******************************/ ++ ++ ++static void cst3xx_touch_report(struct cst3xx_ts_data *ts) ++{ ++ unsigned char buf[30]; ++ unsigned char i2c_buf[8]; ++ unsigned char key_status, key_id = 0, finger_id, sw; ++ unsigned int input_x = 0; ++ unsigned int input_y = 0; ++ unsigned int input_w = 0; ++ unsigned int input_x_delta = 0; ++ unsigned int input_y_delta = 0; ++ unsigned char cnt_up, cnt_down; ++ int i, ret, idx; ++ int cnt, i2c_len; ++ ++ int len_1, len_2; ++ ++ key_status = 0; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(ts->client, buf, 7); ++ if(ret < 0) { ++ printk(" iic read touch point data failed.\n"); ++ goto OUT_PROCESS; ++ } ++ // printk(" read buf : buf[0]: %x ,buf[1]: %x ,buf[2]: %x, buf[3]: %x,buf[4]: %x ,buf[5]: %x ,buf[6]: %x, buf[7]: %x,\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); ++ ++ if(buf[6] != 0xAB) { ++ printk(KERN_INFO " data is not valid..\r\n"); ++ goto OUT_PROCESS; ++ } ++ ++ cnt = buf[5] & 0x7F; ++ if(cnt > 1) goto OUT_PROCESS; ++ else if(cnt==0) goto CLR_POINT; ++ ++ if(cnt == 0x01) { ++ goto FINGER_PROCESS; ++ } ++ ++FINGER_PROCESS: ++ ++ /* ++ * sw: buf[0] low 4 bit ++ * x pos: buf[1] low 4 bit | buf[3] high 4 bit ++ * y pos: buf[2] low 4 bit | buf[3] low 4 bit ++ * z press : buf[4] ++ * finger_id:buf[0] high 4 bit ++ */ ++ i2c_buf[0] = 0xD0; ++ i2c_buf[1] = 0x00; ++ i2c_buf[2] = 0xAB; ++ ++ ret = cst3xx_i2c_write(ts->client, i2c_buf, 3); ++ if(ret < 0) { ++ printk(" cst3xx hyn send read touch info ending failed.\r\n"); ++ cst3xx_reset_ic(ts,20); ++ goto END; ++ } ++ ++ idx = 0; ++ cnt_up = 0; ++ cnt_down = 0; ++ input_x = (unsigned int)((buf[idx + 1] << 4) | ((buf[idx + 3] >> 4) & 0x0F)); ++ input_y = (unsigned int)((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0F)); ++ input_w = (unsigned int)(buf[idx + 4]); ++ sw = (buf[idx] & 0x0F) >> 1; ++ finger_id = (buf[idx] >> 4) & 0x0F; ++ ++ printk(" no handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n", input_x, input_y, input_w,finger_id, sw); ++ ++// input_x=input_x*CST3XX_MAX_X/268; ++// input_y=input_y*CST3XX_MAX_Y/800; ++ ++// if(input_x >= CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++// if(input_y >= CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ ++// input_x = CST3XX_MAX_X-input_x; ++// input_y = CST3XX_MAX_Y-input_y; ++ ++#ifdef 0//HYN_DRAW_POINT ++ if(input_x > 300){ ++ input_x_delta = input_x - (CST3XX_MAX_X/2); ++ input_x = input_x + input_x_delta/((CST3XX_MAX_X/2)/20); ++ if(input_x > CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++ } ++ if(input_x < 40){ ++ input_x_delta = (CST3XX_MAX_X/2) - input_x; ++ input_x = input_x - input_x_delta/((CST3XX_MAX_X/2)/12); ++ if(input_x < 0) input_x = 0; ++ } ++ if(input_y > 760){ ++ input_y_delta = input_y - (CST3XX_MAX_Y/2); ++ input_y = input_y + input_y_delta/((CST3XX_MAX_Y/2)/12); ++ if(input_y > CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ } ++ if(input_y < 40){ ++ input_y_delta = (CST3XX_MAX_Y/2) - input_y; ++ input_y = input_y - input_y_delta/((CST3XX_MAX_Y/2)/25); ++ if(input_y < 0) input_y = 0; ++ } ++#endif ++ ++ printk(" handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n\n", input_x, input_y, input_w,finger_id, sw); ++ ++ if (sw == 0x03 ) { ++ if((input_x > x_temp_pos + ERROR_TOUCH) || (input_x < x_temp_pos -ERROR_TOUCH) || (input_y > y_temp_pos + ERROR_TOUCH) || (input_y < y_temp_pos -ERROR_TOUCH)) ++ { ++ // printk(" REPORT TOUCH DOWM Handle \n"); ++ x_temp_pos = input_x; ++ y_temp_pos = input_y; ++ input_report_key(ts->input_dev, BTN_TOUCH, 1); ++ input_report_abs(ts->input_dev, ABS_X, input_x); ++ input_report_abs(ts->input_dev, ABS_Y, input_y); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 1); ++ input_sync(ts->input_dev); ++ } ++ cnt_down++; ++ } ++ else if(sw == 0) { ++ cnt_up++; ++ } ++ ++ if((cnt_up>0) && (cnt_down==0) ){ ++ // printk(" REPORT TOUCH UP Handle \n"); ++ x_temp_pos = 0; ++ y_temp_pos = 0; ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 0); ++ input_mt_sync(ts->input_dev); ++ } ++ input_sync(ts->input_dev); ++ goto END; ++CLR_POINT: ++ ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_mt_sync(ts->input_dev); ++ input_sync(ts->input_dev); ++ ++OUT_PROCESS: ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ buf[2] = 0xAB; ++ ret = cst3xx_i2c_write(ts->client, buf, 3); ++ if (ret < 0) { ++ printk(" send read touch info ending failed.\n"); ++ cst3xx_reset_ic(ts,20); ++ } ++END: ++ return; ++} ++ ++ ++/******************************* irq handle begin************************************/ ++static void cst3xx_work_handler(struct work_struct *work) ++{ ++ struct cst3xx_ts_data *cst3xx_ts = container_of(work, struct cst3xx_ts_data, work); ++ int ret = 0; ++ /******************here handle touch *******************/ ++ // printk(KERN_INFO "-----------enter cst3xx_work_handler------------\n"); ++ cst3xx_touch_report(cst3xx_ts); ++ enable_irq(cst3xx_ts->irq); ++} ++ ++static irqreturn_t cst3xx_ts_irq_handler(int irq, void *dev_id) ++{ ++ struct cst3xx_ts_data *ts = dev_id; ++ ++ // printk( KERN_INFO "-----------enter cst3xx_ts_irq_handler------------\n"); ++ ++ disable_irq_nosync(ts->irq);//use in interrupt,disable_irq will make dead lock. ++ ++ if (!work_pending(&ts->work)) { ++ queue_work(ts->workqueue, &ts->work); ++ // queue_delayed_work(ts->workqueue,&ts->dwork,1);//10ms * x ++ } else { ++ enable_irq(ts->irq); ++ } ++ ++ return IRQ_HANDLED; ++} ++/******************************* irq handle end************************************/ ++ ++static int cst3xx_ts_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ printk( KERN_INFO "Enter cst3xx_ts_probe -------------------\n"); ++ ++ int ret; ++ struct cst3xx_ts_data *ts; ++ ++ struct cst3xx_platform_data *pdata = (struct cst3xx_platform_data*)client->dev.platform_data; ++ struct input_dev *input_dev; ++ int error; ++ ++#if USE_ANALOG_I2C ++ if (gpio_is_valid(I2CSDA)) ++ { ++ gpio_free(I2CSDA); ++ ret = gpio_request(GPIO_PC(27),"I2C1-SDA"); ++ if(ret < 0){ ++ printk("I2C1-SDA gpio request failed\n"); ++ return ret; ++ } ++ } ++ if (gpio_is_valid(I2CSCL)) ++ { ++ gpio_free(I2CSCL); ++ ret = gpio_request(GPIO_PC(26),"I2C1-SCL"); ++ if(ret < 0){ ++ printk("I2C1-SCL gpio request failed\n"); ++ return ret; ++ } ++ } ++#endif ++ ++ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); ++ if (!ts) ++ return -ENOMEM; ++ input_dev = input_allocate_device(); ++ if(!input_dev) ++ return -ENOMEM; ++ ++ ts->pdata = pdata; ++ ts->client = client; ++ ts->input_dev = input_dev; ++ ++ if(client->addr != 0x1A) //check address ++ { ++ client->addr = 0x1A; ++ printk("Crystal_shen:i2c_client_HYN->addr=%d.\n",client->addr); ++ ++ } ++ ++ if (gpio_is_valid(ts->pdata->int_gpio)) { ++ //error = gpio_request(pdata->int_gpio,"cst3xx gpio irq"); ++ error = gpio_request_one(pdata->int_gpio, GPIOF_IN, "cst3xx gpio irq"); ++ if (error < 0) { ++ dev_err(&client->dev, "Failed to request GPIO %d, error %d\n", ++ pdata->int_gpio, error); ++ return error; ++ } ++ ++ /* if (error < 0) { ++ dev_err(&client->dev, "%s:failed to set gpio irq.\n",__func__); ++ return error; ++ }*/ ++ ts->irq = gpio_to_irq(pdata->int_gpio); ++ printk(" cst3xx ts -> irq = %d.\n",ts->irq); ++ } ++ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) { ++ error = devm_gpio_request(&client->dev, ts->pdata->reset_gpio, NULL); ++ if (error) { ++ dev_err(&client->dev, ++ "Unable to request GPIO pin %d.\n", ++ ts->pdata->reset_gpio); ++ return error; ++ } ++ } ++ cst3xx_reset(ts); ++ printk( KERN_INFO "cst3xx reset -------------------\n"); ++ ret = cst3xx_i2c_test(ts->client); ++ if(ret>=0){ ++ ++ mdelay(100); ++ ++ printk( KERN_INFO "cst3xx test OK -------------------\n"); ++#ifdef HYN_UPDATE_FIRMWARE_ENABLE ++ ret = cst3xx_boot_update_fw(ts,pcst3xx_update_firmware);// ++ if(ret < 0){ ++ printk(" cst3xx hyn_boot_update_fw failed.\n"); ++ return -1; ++ } ++#endif ++ ++ }else{ ++ printk( KERN_INFO "cst3xx hyn i2c communication failed.---------------\n"); ++ return -1; ++ } ++ ++ input_dev->name = "cst3xxx -touchscreen"; ++ input_dev->id.bustype = BUS_I2C; ++ input_dev->dev.parent = &client->dev; ++ ++ set_bit(EV_KEY, input_dev->evbit); ++ set_bit(EV_ABS, input_dev->evbit); ++ set_bit(EV_SYN, input_dev->evbit); ++ set_bit(BTN_TOUCH, input_dev->keybit); ++ ++ set_bit(ABS_X, input_dev->absbit); ++ set_bit(ABS_Y, input_dev->absbit); ++ set_bit(ABS_PRESSURE, input_dev->absbit); ++ ++ ++ input_set_abs_params(input_dev, ABS_X, ts->pdata->x_min, ts->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, ts->pdata->y_min, ts->pdata->y_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0 , 0); ++ ++ /* input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, MAX_AREA, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_POSITION_X, ts->pdata->x_min, ts->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, ts->pdata->y_min, ts->pdata->y_max, 0, 0); ++*/ ++ error = input_register_device(input_dev); ++ if (error) { ++ dev_err(&client->dev, "Unable to register %s input device\n", ++ input_dev->name); ++ return error; ++ } ++ ++ // INIT_DELAYED_WORK(&ts->dwork, cst3xx_work_handler); ++ ++ INIT_WORK(&ts->work, cst3xx_work_handler); ++ ts->workqueue = create_singlethread_workqueue("cst3xx_wq"); ++ ++ error = devm_request_threaded_irq(&client->dev, client->irq, ++ NULL, ++ cst3xx_ts_irq_handler, ++ IRQF_ONESHOT, ++ client->name, ts); ++ if (error) { ++ dev_err(&client->dev, "Failed to register interrupt\n"); ++ return error; ++ } ++ error = request_irq(ts->irq, ++ cst3xx_ts_irq_handler, ++ ts->pdata->irqflags, ++ client->dev.driver->name, ++ ts); ++ if (error < 0) { ++ dev_err(&client->dev, "%s: request irq failed\n",__func__); ++ return error; ++ } ++ printk(KERN_INFO "-----------CST3XX probe end ------------\n"); ++ return 0; ++} ++ ++static int cst3xx_ts_remove(struct i2c_client *client) ++{ ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ free_irq(ts->irq,ts); ++ devm_free_irq(&ts->client->dev, ts->client->irq,ts); ++ destroy_workqueue(ts->workqueue); ++ input_unregister_device(ts->input_dev); ++ devm_gpio_free(&ts->client->dev, ts->pdata->reset_gpio); ++ gpio_free(ts->pdata->int_gpio); ++ ++#if USE_ANALOG_I2C ++ gpio_free(I2CSDA); ++ gpio_free(I2CSCL); ++#endif ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int cst3xx_ts_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ enable_irq_wake(client->irq); ++ } else { ++ disable_irq(client->irq); ++ cst3xx_ts_power(ts, false);//reset ++ } ++ ++ return 0; ++} ++ ++static int cst3xx_ts_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ disable_irq_wake(client->irq); ++ } else { ++ cst3xx_ts_power(ts, true); ++ enable_irq(client->irq); ++ } ++ return 0; ++} ++ ++#endif ++ ++static SIMPLE_DEV_PM_OPS(cst3xx_ts_pm_ops, ++ cst3xx_ts_suspend, cst3xx_ts_resume); ++ ++static const struct i2c_device_id cst3xx_ts_id[] = { ++ { CST3XX_NAME, 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, cst3xx_ts_id); ++ ++ ++#ifdef CONFIG_OF ++static const struct of_device_id cst3xx_ts_dt_ids[] = { ++ { .compatible = "xxxxx,cst3xx", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, cst3xx_ts_dt_ids); ++#endif ++ ++ ++static struct i2c_driver cst3xx_ts_driver = { ++ .probe = cst3xx_ts_probe, ++ .remove = cst3xx_ts_remove, ++ .id_table = cst3xx_ts_id, ++ .driver = { ++ .name = CST3XX_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(cst3xx_ts_dt_ids), ++ .pm = &cst3xx_ts_pm_ops, ++ }, ++}; ++ ++module_i2c_driver(cst3xx_ts_driver); ++ ++ ++MODULE_AUTHOR("Tiben"); ++MODULE_DESCRIPTION("SITRONIX CST3XX Touchscreen Controller Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/hyn_cst3xx_RS659_fw.h b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/hyn_cst3xx_RS659_fw.h +new file mode 100644 +index 000000000..006c36c81 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update1/hyn_cst3xx_RS659_fw.h +@@ -0,0 +1,1553 @@ ++ ++#ifndef __CST3xx_FW_H__ ++#define __CST3xx_FW_H__ ++ ++ unsigned char cst3_fw[] ={ ++ 0x98,0xE0,0x07,0x01,0xB0,0x88,0x01,0x00,0x00,0x00,0x00,0x00,0xB0,0x48,0x01,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x80,0x68,0x06,0x00,0x80,0x68,0x07,0x00,0x00,0x00,0x00,0x00, ++ 0x88,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0xD8,0x00,0x00,0x80,0x07,0xC0,0x17, ++ 0x82,0x07,0xC0,0x07,0x01,0x65,0x40,0x86,0xC1,0x41,0xC0,0x20,0xC5,0x68,0x31,0x12, ++ 0xF5,0x38,0x33,0x5A,0x32,0xA2,0x32,0xEA,0x10,0x62,0x8D,0x0E,0x81,0x07,0xC0,0x97, ++ 0x30,0xF2,0xF3,0x79,0x65,0x7E,0x30,0xB2,0x31,0x09,0x10,0x9A,0x87,0x06,0xD0,0xD8, ++ 0x35,0x12,0x35,0x5A,0x18,0x9A,0x39,0xC2,0xE0,0xE2,0x03,0x00,0xE0,0xE2,0x04,0x00, ++ 0xD0,0x81,0x98,0x16,0x43,0xC6,0x0B,0xC6,0xC2,0xD6,0x3F,0x90,0x99,0x0E,0x40,0x86, ++ 0x08,0x86,0xA9,0x0E,0x40,0x23,0x00,0x63,0x38,0x82,0x03,0x00,0x18,0x01,0x20,0x01, ++ 0x28,0x01,0x30,0x01,0xD0,0x81,0x98,0x0E,0x0F,0xC6,0xC3,0xDE,0x38,0x90,0x9A,0x06, ++ 0x08,0x86,0xA9,0x06,0x03,0x5B,0x38,0x82,0xAE,0xFD,0x30,0x02,0x30,0x02,0xEE,0xFD, ++ 0xA8,0x85,0xE8,0x85,0x86,0x2F,0xE0,0x1F,0x37,0x8A,0xB8,0xFF,0xF8,0xAF,0x87,0x0F, ++ 0xC0,0xCF,0x85,0x2F,0xE7,0xDF,0xBE,0xFF,0xF8,0x9F,0x87,0x2F,0xE0,0x0F,0x07,0x00, ++ 0xAF,0x85,0x6F,0xD2,0xE1,0x43,0x31,0x4A,0xCA,0x01,0x3E,0x30,0x34,0x42,0x80,0x01, ++ 0xF6,0x1B,0xF4,0x23,0xF3,0x53,0xC2,0x01,0x70,0x01,0xD8,0x16,0xE7,0x6B,0x4D,0x68, ++ 0x80,0x4E,0x28,0x01,0x10,0x6C,0xAE,0x6B,0xA4,0x2B,0x12,0xD2,0x8A,0x16,0xB0,0x63, ++ 0x00,0x09,0xB0,0x43,0xE8,0x85,0x37,0x72,0xEA,0x4B,0xE0,0x48,0x91,0x4D,0xAE,0x8B, ++ 0x57,0xAC,0x7F,0x5A,0x10,0xEA,0x95,0x0E,0xE7,0x68,0x13,0xAC,0x48,0xF9,0x8F,0x0E, ++ 0x10,0x12,0x85,0x16,0xE0,0x0B,0x4A,0x09,0x8B,0x26,0xB0,0x9B,0x09,0x01,0xA8,0x8B, ++ 0xA7,0x0B,0xEA,0x85,0x4F,0x09,0x8C,0xE6,0x0A,0x09,0xA0,0x0B,0xE8,0x85,0xAF,0x85, ++ 0x66,0xF2,0xE6,0x01,0x00,0x0F,0x80,0x0F,0xE1,0xAF,0xF7,0x03,0x47,0x01,0x80,0xD6, ++ 0xEB,0x85,0xA8,0x85,0x70,0xDA,0x2E,0x09,0x1E,0xAB,0x65,0xC2,0xE7,0x03,0x09,0x79, ++ 0x01,0x42,0xA0,0x03,0x00,0x0F,0x80,0x0F,0xE1,0x2F,0xE7,0x03,0x37,0x00,0xAE,0xD6, ++ 0x05,0x01,0x18,0x83,0xE1,0x03,0x19,0x42,0xA3,0x03,0xE9,0x85,0x42,0x7A,0xC6,0x01, ++ 0xE6,0x0B,0x44,0x8A,0x48,0x01,0x80,0x3E,0x4A,0x82,0x06,0x0B,0x0E,0xF9,0x57,0x72, ++ 0x8A,0x89,0x97,0x01,0x10,0x8B,0x00,0x17,0x48,0x62,0xCE,0xE1,0x07,0x0B,0x0A,0xF9, ++ 0x8E,0x21,0x01,0x0B,0x08,0x09,0x08,0x0B,0x08,0x0B,0x0C,0x31,0x08,0x0B,0x0A,0x59, ++ 0x18,0x0B,0x0C,0x81,0x18,0x0B,0x0A,0x01,0x1B,0x0B,0x38,0x82,0xAD,0x85,0x40,0xFA, ++ 0xE6,0x03,0x38,0x00,0x81,0x8E,0x00,0xE1,0x83,0x0F,0xC8,0x0F,0x40,0xDA,0x0D,0x01, ++ 0xC4,0x01,0xA9,0x0B,0xBE,0xFF,0xFF,0x97,0x4D,0xC2,0x55,0xEA,0xCD,0x01,0x46,0xEA, ++ 0x84,0x1F,0xD8,0xCF,0x00,0x01,0x80,0x0F,0xC8,0x77,0xE9,0x85,0xAD,0x85,0x40,0x9A, ++ 0xC6,0x01,0xE9,0x03,0x40,0x01,0x88,0x36,0x46,0x82,0xC5,0x01,0xE0,0x03,0x44,0x29, ++ 0xCF,0x0E,0xB8,0xFF,0xFD,0xE7,0x64,0x6A,0xE0,0x03,0x39,0x00,0xAF,0x0E,0xB8,0xFF, ++ 0xFB,0x07,0xE5,0x03,0x38,0x00,0xAC,0x2E,0x42,0x5A,0xC5,0x01,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0xE7,0x03,0x0B,0xE9,0x03,0x42,0xA0,0x03,0x40,0x52,0xC5,0x03, ++ 0x40,0x01,0x80,0x16,0x83,0x0F,0xE0,0xF7,0x38,0xE7,0xEF,0x85,0xAD,0x85,0x48,0x3A, ++ 0x04,0x01,0x00,0x43,0x4E,0xEA,0xCC,0x01,0xB2,0x43,0xF0,0x43,0x80,0x0F,0xC8,0xFF, ++ 0xEB,0x85,0xA8,0x85,0x30,0x2A,0x20,0x49,0x18,0x22,0x4F,0x01,0x80,0x46,0x68,0x01, ++ 0x80,0x16,0x30,0x82,0xC0,0x61,0x00,0x4F,0x30,0x82,0x80,0x61,0x20,0x51,0x00,0x2F, ++ 0x68,0x01,0x80,0x0E,0xF0,0x80,0x04,0x0F,0xE0,0x80,0x24,0x51,0x0A,0x01,0xF0,0x0A, ++ 0x48,0x01,0xD0,0x06,0x16,0x4A,0x0A,0x40,0x0A,0x01,0xF0,0x8A,0x81,0x2F,0xD8,0xA7, ++ 0x40,0xF9,0xEB,0x06,0x00,0xF9,0x6B,0x01,0x87,0x16,0x08,0xF9,0x88,0x09,0xD0,0x40, ++ 0xCB,0x00,0xE8,0x85,0xAC,0x85,0x6B,0x2A,0xED,0x01,0xE4,0x43,0x41,0x01,0x80,0x26, ++ 0x32,0x62,0xA1,0x01,0x40,0x03,0x41,0x01,0x81,0xFE,0x30,0x0A,0xCC,0x01,0x44,0x2A, ++ 0x81,0x17,0xC8,0x3F,0x0F,0x01,0x40,0xF9,0x8D,0xC6,0xF0,0x03,0xE3,0x01,0xB4,0x03, ++ 0x11,0x11,0x30,0x02,0x82,0x01,0xA1,0x13,0xA8,0x0B,0x01,0x01,0x12,0x79,0x28,0x29, ++ 0x5B,0xE2,0x0B,0x68,0xF8,0x23,0x03,0x37,0x0A,0x21,0x19,0x0A,0xC2,0x48,0xCE,0x48, ++ 0x92,0x53,0xE0,0x00,0x94,0x05,0x16,0x22,0xC3,0xB6,0xEF,0x85,0x47,0xF1,0x87,0xE6, ++ 0x47,0x01,0x80,0xD6,0xF0,0x00,0x12,0x09,0x44,0x1B,0x01,0x12,0x17,0x9A,0x80,0xA6, ++ 0xA3,0x4B,0xED,0x85,0xAB,0x85,0x51,0x92,0x28,0x01,0x20,0x01,0x08,0x01,0x00,0x01, ++ 0xC4,0x9B,0x10,0x5A,0xC8,0x06,0x30,0xCA,0x58,0xD1,0x9F,0x0E,0x28,0x09,0x00,0x27, ++ 0xE2,0x90,0xE2,0x00,0x90,0x05,0x46,0x31,0x99,0x96,0x4F,0xE1,0x92,0x5E,0x40,0xFA, ++ 0xC4,0x01,0xE6,0x03,0x40,0x29,0xC8,0x36,0x41,0x12,0x0B,0x81,0xF3,0x0A,0x4A,0xC1, ++ 0xD8,0x0E,0x28,0x09,0x03,0x1F,0xE0,0x20,0x90,0x25,0x67,0x71,0x98,0xF6,0x16,0x01, ++ 0x48,0x02,0x6B,0x01,0x82,0x7E,0x40,0x44,0xE4,0x00,0x92,0x05,0x00,0x44,0x42,0xA1, ++ 0xCC,0x46,0x40,0x44,0xE4,0x00,0x02,0x44,0x02,0x54,0x42,0x82,0x10,0x09,0xE0,0x0B, ++ 0x18,0x8A,0xA0,0x0B,0xEA,0x85,0x01,0x54,0xEF,0x85,0xA9,0x85,0x80,0x3D,0x04,0x01, ++ 0x80,0x14,0x80,0x1C,0x00,0x01,0x08,0x01,0x10,0x01,0x90,0x0C,0xD2,0x1C,0x58,0x6A, ++ 0x06,0x90,0x32,0x09,0xC5,0x90,0x06,0xB0,0xC9,0xA0,0x34,0x2A,0x18,0x01,0x10,0x01, ++ 0xF0,0x12,0xC5,0x80,0x92,0x05,0xE0,0x48,0x90,0x4D,0xF8,0x0C,0x10,0xD2,0xED,0x06, ++ 0x90,0x0C,0xA0,0x61,0xE6,0xD8,0x92,0xDD,0x5F,0x71,0x98,0x86,0x84,0x2F,0xD0,0xA7, ++ 0x90,0x25,0xC0,0x14,0x10,0x02,0xD5,0x06,0xA0,0x14,0x38,0x01,0x60,0x01,0xE8,0xAE, ++ 0x35,0x01,0xF8,0x72,0x10,0x32,0xDD,0x66,0xC6,0x0C,0x78,0x08,0xC2,0x40,0x80,0x00, ++ 0x10,0x32,0xD4,0x8E,0x09,0x19,0x30,0x82,0x83,0x2F,0xD0,0xF7,0xD1,0x80,0x01,0x44, ++ 0x00,0x57,0x70,0x01,0xE8,0x46,0x00,0x09,0x00,0x44,0x01,0x2F,0x01,0x01,0xF0,0x42, ++ 0x10,0x02,0xE5,0x0E,0xD9,0x00,0x00,0x44,0xAB,0x61,0xE0,0xF8,0x90,0xFD,0x7F,0x71, ++ 0x98,0xE6,0xC6,0x1C,0xE6,0x00,0x92,0x05,0x80,0x1C,0xC0,0x1C,0x45,0x31,0x98,0x8E, ++ 0x00,0x01,0x80,0x24,0x00,0x01,0x08,0x01,0x38,0x01,0xD0,0x24,0x1A,0x61,0x18,0xD2, ++ 0x5E,0x22,0xC1,0x98,0x14,0x09,0x06,0x90,0xC0,0xD0,0x34,0xA2,0x18,0x01,0x30,0x01, ++ 0xF9,0xB2,0xC4,0x80,0x92,0x05,0xE0,0x48,0x95,0x4D,0x10,0xF2,0xE9,0x06,0x30,0xBA, ++ 0xE2,0x90,0xE4,0xD8,0x90,0xDD,0x5E,0x31,0x98,0x8E,0x87,0x2F,0xD0,0x2F,0x92,0x2D, ++ 0xC5,0x14,0x10,0x42,0xD0,0x06,0xA8,0x14,0x30,0x01,0x68,0x01,0xE8,0xA6,0x01,0x01, ++ 0xF0,0x02,0x81,0x34,0x10,0x42,0xDD,0x9E,0x09,0x19,0x30,0x42,0x81,0x2F,0xD0,0xA7, ++ 0xC8,0x34,0xD0,0x40,0x91,0x05,0x00,0x04,0x83,0x2C,0xD8,0xC0,0x41,0x41,0xD1,0x4E, ++ 0x00,0x40,0x0B,0x19,0x81,0x2F,0xD0,0x47,0xC8,0x2C,0xD0,0x40,0x01,0x04,0x01,0x0F, ++ 0xC0,0x34,0x40,0x01,0xE8,0xF6,0x00,0x09,0x00,0x04,0x01,0xDF,0x00,0xC0,0x06,0x01, ++ 0x50,0x07,0x03,0x00,0x18,0x00,0x02,0x42,0x00,0x01,0x00,0x42,0x80,0x60,0x05,0x00, ++ 0x58,0xC0,0x02,0x01,0x00,0xA0,0x07,0x01,0x00,0x80,0x00,0x01,0x10,0x00,0x00,0x42, ++ 0x10,0xC0,0x00,0x01,0x00,0x00,0x00,0x01,0x01,0x01,0xF0,0x02,0x10,0x42,0xE5,0x0E, ++ 0xD9,0x00,0x02,0x04,0xE3,0x20,0xE5,0xB0,0x90,0xB5,0x77,0x31,0x98,0xEE,0xC5,0x24, ++ 0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x44,0x71,0x98,0x9E,0xC5,0x14,0x50,0xD2, ++ 0x40,0xE1,0xD1,0x26,0x7A,0x40,0xCF,0x00,0x82,0x00,0x82,0x83,0x00,0x0F,0x00,0xF1, ++ 0x82,0x83,0xC2,0x8B,0x40,0xAA,0x4D,0x01,0x82,0x4E,0xF0,0x48,0x81,0x8B,0x8A,0x41, ++ 0x32,0x12,0xD0,0x01,0x88,0x8B,0x08,0x31,0x98,0x0B,0x86,0x3D,0xE8,0x85,0x0F,0x11, ++ 0x9F,0x0B,0x3E,0xD7,0xAD,0x85,0x47,0x6A,0x72,0x6A,0xC5,0x01,0xF1,0x2B,0x04,0x09, ++ 0x09,0x00,0xC4,0xA0,0x69,0x09,0xC8,0x66,0x1F,0x01,0x10,0xF9,0x02,0x01,0x38,0x19, ++ 0x08,0xF8,0x03,0x57,0x0A,0x31,0x18,0x0A,0xCE,0x48,0xCC,0x48,0x54,0x4C,0x10,0xCA, ++ 0xC8,0x0E,0x30,0x5A,0x32,0x12,0xE0,0x00,0x94,0x05,0x16,0x2A,0xC7,0x96,0x57,0xF9, ++ 0x82,0xBE,0x00,0x80,0xC9,0x08,0x04,0x09,0x08,0x00,0xC4,0x40,0xF1,0x0B,0xB0,0x0B, ++ 0xF3,0x03,0xB2,0x03,0x02,0x31,0x18,0x12,0xCE,0x80,0xCC,0x00,0x4C,0xCA,0x4C,0x14, ++ 0x0E,0x54,0x4C,0x14,0x08,0x54,0x56,0x04,0x14,0x44,0x48,0xA2,0x02,0x09,0xC8,0x01, ++ 0xB4,0x43,0x44,0x92,0x3A,0x01,0xC0,0x01,0xF4,0x03,0x6C,0x7A,0x41,0x01,0x80,0x8E, ++ 0xF3,0x03,0xF1,0x13,0x48,0x5C,0x0B,0x61,0x19,0xCA,0x4A,0x64,0xCB,0x48,0x04,0x30, ++ 0xC8,0x48,0x34,0x19,0x14,0xB0,0xC9,0x70,0x0B,0x21,0xF0,0x8A,0x48,0x81,0xDA,0x06, ++ 0x00,0x7C,0x47,0x01,0x80,0x0E,0x40,0x29,0x8D,0xCE,0x10,0x02,0x8C,0xBE,0x10,0xD2, ++ 0x88,0xAE,0x18,0x61,0xF6,0x5A,0xD7,0x58,0x98,0x49,0x58,0x91,0xC7,0x7E,0x40,0x5C, ++ 0x65,0x0A,0x14,0x1A,0x92,0x0E,0xE0,0xD8,0x07,0x5C,0x47,0x5C,0x58,0x41,0xCE,0x36, ++ 0x03,0x7C,0x5F,0xD2,0x34,0x09,0x98,0x01,0xE1,0xE3,0x18,0xA2,0xA1,0xE3,0x08,0x44, ++ 0x0D,0x54,0x0B,0x4C,0x42,0xAA,0xC3,0x01,0x51,0x04,0x46,0x91,0xCF,0x06,0x00,0x7C, ++ 0xEF,0x85,0xAF,0x85,0x80,0x3D,0x2C,0x01,0x20,0x01,0x00,0x61,0x4B,0x82,0x1B,0x42, ++ 0xC0,0x00,0x82,0x34,0x30,0x01,0x38,0x01,0x00,0x01,0x80,0x1C,0x80,0x14,0xC0,0x34, ++ 0x00,0x08,0x13,0x19,0xC0,0x00,0x12,0x90,0xC0,0x10,0x04,0x21,0x90,0x2C,0xF0,0x82, ++ 0x80,0x24,0x60,0x01,0x83,0x46,0xF0,0x10,0xDA,0x34,0x00,0x90,0xC0,0xD0,0x1C,0x19, ++ 0x16,0xD8,0xC0,0x90,0x34,0x21,0xF8,0xB2,0x68,0x01,0x80,0x56,0xF0,0x50,0x1B,0x61, ++ 0x1A,0xD2,0x5A,0xFA,0xC0,0x90,0x1E,0x19,0xC0,0x90,0x12,0xD8,0xC0,0x90,0x3E,0x21, ++ 0xF8,0xBA,0x66,0x29,0x83,0x4E,0xE0,0x18,0xD2,0x34,0x00,0xD8,0xC0,0x90,0x1E,0x19, ++ 0x16,0xD8,0xC0,0x90,0x1E,0x21,0xF0,0x9A,0x98,0x1C,0x68,0x69,0x83,0x5E,0xE0,0x50, ++ 0x1A,0x61,0x18,0xD2,0x5E,0x92,0xC2,0x90,0xC0,0x88,0x12,0x19,0x14,0x90,0xC0,0x50, ++ 0x0A,0x21,0xF0,0x8A,0x88,0x14,0x08,0x09,0x89,0x0C,0x70,0x41,0xD1,0x3E,0x78,0x41, ++ 0xD0,0x2E,0xC8,0x1C,0x48,0x41,0xD1,0x16,0xC9,0x14,0x48,0x41,0xD8,0x0E,0x08,0x01, ++ 0x88,0x0C,0x08,0x19,0x80,0x2F,0xC8,0x47,0x10,0x82,0xED,0x3E,0x10,0xC2,0xED,0x2E, ++ 0xCC,0x1C,0x10,0x42,0xE8,0x16,0xC8,0x14,0x10,0x42,0xE4,0x0E,0x00,0x01,0x80,0x0C, ++ 0xC0,0x0C,0x40,0x01,0x80,0x36,0xC0,0x24,0x78,0x08,0xC6,0x48,0x82,0x48,0xD2,0x00, ++ 0xCC,0x2C,0x00,0x44,0xE7,0x20,0x93,0x25,0x64,0x31,0x98,0x9E,0xE7,0x68,0x93,0x6D, ++ 0x6C,0x71,0x98,0x4E,0x3B,0x4F,0xA8,0x85,0x48,0x9A,0x01,0x01,0x06,0x44,0x04,0x44, ++ 0x82,0x43,0x80,0x43,0x40,0x8A,0x29,0x09,0x80,0x01,0xE4,0x0B,0x18,0x4A,0xA1,0x0B, ++ 0x31,0x22,0xE0,0x01,0x07,0x9F,0xBA,0xFF,0xE9,0xCF,0x43,0x82,0xC0,0x03,0x40,0x01, ++ 0x81,0x1E,0x48,0x52,0x02,0xC1,0xC8,0x01,0xB1,0x43,0x40,0x42,0x51,0x62,0x49,0x42, ++ 0xC0,0x01,0x82,0x1F,0xF7,0x0F,0xBD,0xFF,0xE9,0x4F,0x49,0x22,0x52,0x42,0xC9,0x01, ++ 0x40,0x1A,0x81,0x27,0xC1,0x17,0x4C,0x0A,0x52,0x2A,0xC9,0x01,0x40,0x02,0x81,0x27, ++ 0xFF,0x0F,0xBC,0xFF,0xEF,0x3F,0xEE,0x03,0x40,0x01,0x80,0x16,0xE8,0x03,0x47,0x11, ++ 0x89,0x1E,0x40,0x02,0x41,0x0B,0x18,0x4A,0x00,0x0B,0x40,0xC2,0x0E,0x11,0x98,0x0B, ++ 0x32,0x0A,0xC8,0x01,0x40,0xB2,0x80,0x27,0xE8,0xC7,0x4D,0xA2,0x42,0xA2,0xC8,0x01, ++ 0x86,0x27,0xE0,0x7F,0xBF,0xFF,0xEF,0x4F,0xB9,0xFF,0xFF,0xDF,0x48,0x7A,0x40,0x82, ++ 0xC8,0x01,0x82,0x27,0xE0,0xF7,0x4A,0x6A,0x12,0x01,0xC8,0x01,0x40,0x62,0x58,0x92, ++ 0x85,0x17,0xE8,0x57,0xBD,0xFF,0xF7,0xB7,0xBB,0xFF,0xE7,0xD7,0x48,0x3A,0x40,0x42, ++ 0xC8,0x01,0x82,0x0F,0xF0,0x6F,0x80,0x07,0xDF,0x47,0xB8,0xFF,0xE7,0xFF,0xEF,0x03, ++ 0x45,0x31,0x88,0x46,0xE8,0x85,0x03,0x00,0x00,0x00,0x00,0x01,0x00,0xC0,0x02,0x01, ++ 0x00,0xA0,0x07,0x01,0x48,0xA0,0x02,0x01,0x38,0x81,0x00,0x00,0x00,0x80,0x00,0x01, ++ 0x58,0xC0,0x02,0x01,0xF8,0x00,0x06,0x42,0x18,0xD8,0x05,0x00,0xA8,0x85,0x33,0x22, ++ 0xF0,0x03,0x83,0x07,0xF1,0xA7,0x41,0x9A,0x2C,0x01,0x00,0x2B,0xB5,0x2B,0x01,0xB1, ++ 0xAF,0x2A,0xB8,0xFF,0xE4,0x1F,0xA5,0x01,0xFA,0x03,0x31,0x08,0x42,0x72,0x71,0x48, ++ 0x1C,0x0B,0x5C,0x0B,0x02,0x48,0x1A,0x0B,0x09,0x2B,0xFE,0x0B,0x30,0x48,0xA8,0x16, ++ 0x0E,0x09,0x04,0x0B,0x1B,0x2B,0xE8,0x85,0xAD,0x85,0x87,0x9D,0x42,0x32,0xC1,0x01, ++ 0x42,0x0B,0x40,0x48,0x00,0x48,0x02,0x0B,0x51,0x22,0x49,0x2A,0x40,0x2A,0x81,0x0F, ++ 0xC1,0x97,0x67,0x1A,0x35,0x2A,0xA9,0x01,0x01,0xBF,0x41,0x0A,0xBE,0xFF,0xFF,0x77, ++ 0x52,0x03,0x81,0x01,0xE7,0x03,0x40,0x79,0x80,0x0E,0x51,0xEA,0x48,0xEA,0x00,0x01, ++ 0x58,0xD2,0x80,0x07,0xF8,0x2F,0x51,0xD2,0x48,0xD2,0x00,0x09,0x58,0xBA,0x80,0x07, ++ 0xF9,0xFF,0x50,0x03,0x80,0x01,0xE2,0x03,0x40,0x59,0x8D,0x86,0x40,0xB2,0x48,0xAA, ++ 0x88,0xA1,0x11,0x01,0xD5,0x3B,0xD7,0x1B,0x18,0xFA,0x42,0x5C,0x44,0x34,0xD8,0xD8, ++ 0x04,0x1C,0xE0,0x00,0xE2,0x48,0xE4,0x90,0x95,0x95,0x14,0xD2,0x99,0xAE,0x57,0x03, ++ 0x80,0x01,0xE2,0x03,0x40,0x59,0x85,0x2E,0x50,0x42,0x48,0x4A,0x40,0x4A,0x58,0x0D, ++ 0x80,0x0F,0xC0,0xBF,0x40,0x0D,0x80,0x07,0xDF,0xFF,0xE9,0x43,0x46,0x31,0x80,0x26, ++ 0x87,0x9D,0xE9,0x85,0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x58,0xC0,0x02,0x01, ++ 0x00,0xC0,0x00,0x01,0x00,0xA0,0x07,0x01,0x18,0xC0,0x07,0x01,0x4C,0xFA,0x6F,0x54, ++ 0x82,0x13,0x68,0x54,0x80,0x13,0x32,0x52,0x92,0x01,0xF5,0x93,0x80,0x13,0xCC,0x4B, ++ 0x83,0x0B,0x3E,0x82,0xA8,0x85,0xF3,0x24,0x63,0xC2,0xFF,0x23,0x11,0x22,0xCC,0x56, ++ 0x23,0x21,0x19,0x02,0x60,0xB2,0xCF,0x00,0x23,0x29,0x0A,0x20,0xCE,0x00,0x50,0x24, ++ 0x58,0x2C,0x48,0x09,0x8E,0x26,0x50,0x0C,0x23,0xF9,0xA7,0x49,0xD4,0x08,0x93,0x65, ++ 0x50,0x09,0x88,0x26,0x58,0x0C,0x10,0xC9,0x0A,0x90,0xD2,0x88,0x90,0x6D,0xD4,0x0B, ++ 0xD0,0x13,0x0A,0x48,0x00,0x90,0x1A,0x8A,0x81,0xCB,0x48,0x08,0x81,0xCB,0x4A,0x48, ++ 0x81,0xCB,0x0C,0x08,0x38,0x50,0x79,0x90,0x1E,0x8A,0x80,0xCB,0x58,0x04,0x8A,0xC3, ++ 0xC2,0x83,0xE9,0x00,0x83,0x83,0xE9,0x85,0xAC,0x85,0x87,0x2D,0x0F,0x01,0x00,0x0D, ++ 0x40,0x2E,0x90,0x24,0x86,0x1C,0x40,0xEA,0xFA,0x2B,0xF8,0x1B,0x06,0x01,0x60,0xFA, ++ 0x51,0xFA,0xC6,0x33,0x70,0x59,0x85,0x1E,0xE4,0x00,0x92,0x05,0x17,0x82,0x9C,0xC6, ++ 0x50,0xE2,0x46,0x83,0x31,0x09,0x18,0x82,0x07,0x83,0x00,0xF9,0x80,0x03,0x69,0x01, ++ 0x80,0xBE,0x08,0x01,0x50,0x1D,0x00,0x01,0x2E,0x29,0x62,0x8A,0x08,0x68,0x03,0x77, ++ 0x32,0x21,0x19,0x32,0xCB,0xB0,0xC9,0xB0,0xD0,0xB3,0x75,0x09,0x88,0x2E,0x80,0x83, ++ 0xE6,0x48,0x92,0x4D,0xE0,0x90,0x4A,0x29,0x82,0x1E,0xE0,0x00,0x94,0x05,0x16,0xC2, ++ 0x98,0x76,0x8F,0x0C,0x60,0x4A,0x6E,0x1D,0x36,0x01,0x78,0x22,0xB9,0x01,0x06,0x0F, ++ 0x70,0x01,0x88,0x9E,0x50,0x15,0x90,0x04,0x11,0x01,0xC0,0x43,0x30,0x1A,0x31,0x8A, ++ 0xBC,0xFF,0xFF,0x47,0xE5,0x68,0xE3,0xC3,0xCE,0x0C,0x48,0x00,0x08,0x00,0x1E,0x42, ++ 0x8D,0x03,0x03,0x59,0x8D,0x03,0xED,0x20,0xE0,0x20,0x03,0x4F,0x50,0x15,0x90,0x04, ++ 0x11,0x01,0xC0,0x43,0x30,0x1A,0x31,0x8A,0xBB,0xFF,0xFF,0xA7,0xE3,0x68,0xEB,0x20, ++ 0xE7,0xB0,0x93,0xB5,0xC4,0x0C,0x10,0x32,0x9D,0xD6,0xE6,0xC3,0x1E,0x01,0x4C,0x08, ++ 0x48,0x01,0x80,0x96,0xC8,0x0C,0x48,0x01,0x81,0x36,0x80,0x03,0xEB,0xC3,0x81,0x03, ++ 0x05,0x59,0x85,0x03,0xE0,0x20,0x05,0x37,0x81,0x03,0xE9,0xC3,0x83,0x03,0x8B,0x1B, ++ 0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x2F,0xC0,0x0C,0x40,0x09,0xC8,0x16, ++ 0x01,0x59,0x85,0x03,0xE1,0x20,0x33,0x02,0xBA,0xFF,0xFF,0x07,0x4A,0x32,0x45,0x43, ++ 0x10,0x01,0x1A,0x82,0x05,0x43,0x4A,0x2A,0x40,0x43,0x1A,0xC2,0x03,0x43,0xE2,0xC3, ++ 0x08,0x11,0x18,0x42,0xA0,0xC3,0x83,0x2D,0xEF,0x85,0xAF,0xFD,0x80,0x0D,0xFC,0x54, ++ 0x30,0x32,0x30,0x62,0x6E,0xAA,0xAC,0x01,0x50,0x09,0x88,0x4E,0x00,0x0F,0x80,0x0F, ++ 0xC1,0xCF,0xE1,0x43,0x37,0x00,0xAA,0xD6,0xE5,0x43,0x09,0xF9,0x01,0x42,0xA0,0x43, ++ 0x04,0x09,0x30,0x22,0x51,0xAA,0x04,0x8F,0x60,0x01,0xC1,0x2E,0xF7,0x00,0x0B,0x01, ++ 0x1A,0x42,0x08,0x83,0x30,0x0A,0x01,0x17,0x02,0xF9,0x0F,0x83,0x08,0x01,0x19,0x01, ++ 0x08,0x9B,0x04,0x01,0x00,0x4F,0x78,0x01,0x88,0x16,0x18,0x01,0x00,0x9B,0x06,0x17, ++ 0xC6,0x9B,0x01,0x9B,0xCA,0xB0,0xE7,0x00,0x94,0x05,0x14,0x42,0x9B,0x9E,0x37,0x02, ++ 0x40,0x01,0x80,0x26,0x04,0xA1,0x00,0x83,0x04,0x01,0x30,0x22,0x00,0x0F,0x00,0x21, ++ 0x03,0x83,0xD4,0x00,0x92,0x25,0x44,0x83,0x08,0x01,0x1C,0x42,0x01,0x83,0xE2,0x43, ++ 0x37,0x00,0xAA,0xE6,0xE5,0x43,0x09,0xF9,0x01,0x42,0xA0,0x43,0x66,0x01,0x88,0x5E, ++ 0xC0,0x24,0x40,0x09,0x88,0x7E,0x05,0x01,0x02,0x83,0x44,0x83,0x08,0x01,0x1C,0x42, ++ 0x05,0x83,0x3A,0x47,0xAC,0x9D,0x87,0x1D,0x20,0x01,0x00,0x01,0x80,0x0C,0x70,0x15, ++ 0x40,0x52,0xF3,0x03,0xEE,0x00,0x92,0x3D,0x6E,0x42,0xAB,0x01,0x00,0xAF,0x81,0x07, ++ 0xF9,0x0F,0xE7,0x43,0x30,0x00,0xA2,0x1E,0x40,0x22,0xF3,0x03,0x17,0xC2,0x9D,0xB6, ++ 0x40,0x12,0xF3,0x03,0x10,0xC2,0x9D,0x06,0x21,0x11,0xE0,0x43,0x08,0xF9,0x05,0x42, ++ 0xA3,0x43,0x41,0x32,0x46,0x0B,0x14,0x79,0x00,0x8A,0x48,0x09,0x88,0x9E,0x08,0x01, ++ 0x0E,0x0B,0x44,0x0B,0x83,0x8B,0xE1,0xB0,0xE7,0x20,0x93,0x25,0x60,0x11,0x88,0x56, ++ 0x30,0x5A,0xD3,0xCB,0xD4,0x1C,0x10,0x8A,0x8A,0x2E,0xD0,0xCB,0xD4,0x24,0x10,0x8A, ++ 0x88,0x0E,0x08,0x09,0x8F,0x0C,0x08,0x01,0x08,0x0B,0x0A,0x01,0x08,0x0B,0x0C,0x81, ++ 0x02,0x0B,0x44,0x0B,0x10,0x01,0x1C,0x8A,0x00,0x0B,0x62,0x11,0x88,0x4E,0xC6,0x0C, ++ 0x3A,0x0F,0x4B,0x52,0x58,0x54,0x86,0x13,0x12,0x01,0x80,0x13,0xE4,0x4B,0x82,0x0B, ++ 0x4A,0x62,0x8A,0x01,0x5E,0x53,0x84,0x13,0x58,0x53,0x8A,0x13,0x12,0x91,0x88,0x13, ++ 0x14,0x19,0x88,0x13,0x4E,0x53,0x8E,0x13,0x48,0x53,0x94,0x13,0x4A,0x4B,0x92,0x0B, ++ 0x0C,0x09,0x90,0x0B,0x3F,0x82,0xAB,0x85,0x80,0x4D,0x34,0x22,0x30,0x01,0x00,0x01, ++ 0x80,0x2C,0x38,0x01,0x4C,0xCA,0xD1,0x43,0xD2,0x4B,0x1E,0x42,0x81,0x14,0x40,0xC2, ++ 0x80,0x61,0x80,0x24,0xC0,0x61,0x80,0x1C,0x60,0x09,0x80,0x0E,0x60,0x29,0x88,0x76, ++ 0x60,0x09,0x88,0x1E,0x70,0xD2,0xB1,0x2C,0x78,0xD2,0x01,0x27,0x73,0xD2,0xE1,0x80, ++ 0x81,0x2C,0x78,0xC2,0xF8,0x81,0x41,0x35,0xBA,0xFF,0xF7,0xC7,0x00,0x3F,0x60,0x21, ++ 0x89,0x2E,0x70,0xB2,0x47,0x35,0xB8,0xFF,0xF9,0xE7,0x7D,0x92,0xB9,0xA1,0x6A,0x3A, ++ 0xA9,0x01,0xE6,0x43,0x08,0xF9,0x05,0x42,0xA1,0x43,0xE1,0x43,0x08,0x01,0x19,0x42, ++ 0xA1,0x43,0x41,0x4A,0x42,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x4A,0x3A,0x41,0x43, ++ 0x10,0x01,0x1C,0x82,0x01,0x43,0x4A,0x1A,0x40,0x43,0x10,0x09,0x18,0x82,0x00,0x43, ++ 0x0C,0x09,0x00,0x01,0xBA,0xFF,0xFF,0xB7,0x42,0x09,0x88,0x66,0x62,0x21,0x88,0x5E, ++ 0x10,0x09,0x90,0x04,0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF,0xF0,0xB7,0x17,0x09, ++ 0x90,0x04,0x10,0x01,0x08,0x59,0x40,0x35,0x37,0x9A,0xB8,0xFF,0xF0,0x77,0x17,0x09, ++ 0x90,0x04,0x10,0x01,0x09,0x31,0x30,0xC2,0x37,0x9A,0xB8,0xFF,0xF0,0x37,0x17,0x09, ++ 0x90,0x04,0x40,0xA2,0x10,0x01,0x08,0x71,0xC0,0x21,0x32,0x9A,0xBE,0xFF,0xF7,0xEF, ++ 0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x30,0x9A,0xC0,0x24,0xBE,0xFF,0xF7,0xAF, ++ 0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x18,0x09,0x00,0xCF,0x00,0xC0,0x00,0x01, ++ 0x00,0xA0,0x07,0x01,0xFF,0xFF,0xFF,0xFF,0x00,0xF8,0x07,0x00,0x58,0x20,0x00,0x01, ++ 0x90,0xE4,0x03,0x00,0xF8,0x00,0x06,0x42,0x00,0x00,0x06,0x42,0x80,0x01,0x06,0x42, ++ 0x10,0xC0,0x00,0x01,0x40,0x60,0x07,0x01,0x18,0xC0,0x07,0x01,0x38,0xC0,0x05,0x01, ++ 0xC7,0x1C,0xB8,0xFF,0xF2,0x97,0x05,0x27,0x60,0x09,0x80,0x0E,0x62,0x29,0x88,0x06, ++ 0x60,0x09,0x88,0x76,0x10,0x09,0x90,0x04,0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF, ++ 0xF0,0x27,0x15,0x01,0x90,0x04,0x30,0x9A,0xC8,0x14,0xC0,0x2C,0xBC,0xFF,0xF7,0xEF, ++ 0x00,0x7F,0x10,0x11,0x90,0x04,0x10,0x09,0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF, ++ 0xF0,0xA7,0x14,0x11,0x90,0x04,0x10,0x01,0x30,0x9A,0xC8,0x14,0xC7,0x2C,0xB8,0xFF, ++ 0xF0,0x67,0x14,0x09,0x90,0x04,0x10,0x01,0x08,0x21,0x40,0x35,0x37,0x9A,0xB8,0xFF, ++ 0xF0,0x27,0x14,0x09,0x90,0x04,0x10,0x01,0x09,0x41,0x31,0xC2,0x37,0x9A,0xB8,0xFF, ++ 0xF0,0xE7,0x13,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x30,0x9A,0xC7,0x24,0xB8,0xFF, ++ 0xF0,0xA7,0x13,0x09,0x90,0x04,0x10,0x01,0x08,0x31,0x18,0x09,0xC7,0x1C,0xB8,0xFF, ++ 0xF1,0x67,0xE3,0x43,0x08,0xF9,0x06,0x42,0xA5,0x43,0x41,0x32,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x47,0x22,0x0D,0x01,0x08,0x0B,0x0A,0x01,0x02,0x0B,0x44,0x0B, ++ 0x10,0x01,0x1C,0x8A,0x00,0x0B,0x82,0x4D,0xEB,0x85,0xAF,0x85,0x67,0xFA,0xEC,0x03, ++ 0x28,0x01,0x40,0x09,0x87,0x16,0xE8,0x03,0x40,0x29,0x88,0x5E,0x71,0xE2,0xC4,0x83, ++ 0x40,0x11,0x98,0x26,0xEF,0x03,0xBF,0xFF,0xF1,0xF7,0x87,0xAB,0xEA,0x85,0xE3,0x00, ++ 0x83,0x83,0xE9,0x85,0xE8,0x03,0x47,0x21,0x8F,0x26,0xB8,0xFF,0xF0,0xA7,0x07,0x19, ++ 0xAB,0x03,0xEF,0x85,0xE8,0x03,0x47,0x19,0x87,0xDE,0xEF,0x03,0x47,0x31,0x80,0xC6, ++ 0x4D,0x72,0xCC,0x01,0xF8,0x43,0x40,0x01,0x88,0x3E,0x30,0x42,0x80,0x01,0xF6,0x13, ++ 0x50,0x31,0x98,0x3E,0xE0,0x03,0x34,0x00,0xAC,0x26,0x40,0x42,0xC4,0x01,0xE3,0x03, ++ 0x40,0x01,0x80,0xA6,0xE8,0x03,0x47,0x01,0x8E,0x1E,0x57,0x44,0x47,0x31,0x88,0x06, ++ 0x45,0x22,0x0C,0x59,0x82,0x0B,0x80,0x2B,0x86,0x2B,0x84,0x2B,0x8A,0x2B,0x88,0x2B, ++ 0x8B,0x0B,0x44,0xE2,0x42,0x0B,0x40,0x48,0x00,0x48,0x02,0x0B,0xEF,0x85,0xBB,0xFF, ++ 0xEB,0xDF,0xEB,0x85,0xA8,0xC5,0x27,0x01,0x30,0x1A,0x00,0x09,0x4B,0xBA,0x6B,0xD2, ++ 0x30,0x01,0x59,0x51,0x80,0xE6,0xE1,0x4E,0x79,0xC2,0xE3,0xD3,0x87,0x27,0xE8,0xDF, ++ 0x61,0x52,0x20,0x09,0x39,0x61,0x62,0x52,0x71,0x61,0x62,0x92,0x40,0x7A,0x13,0x31, ++ 0xC0,0x01,0x55,0x03,0x80,0x01,0x5A,0xC9,0x80,0xAE,0xE1,0x4E,0x59,0x59,0x80,0x56, ++ 0x59,0x61,0x80,0x66,0x59,0x69,0x88,0xBE,0x06,0x29,0xA8,0x43,0x21,0x09,0x00,0x9F, ++ 0x59,0xD1,0x80,0x6E,0x59,0x01,0x89,0x7E,0xA8,0x53,0x26,0x09,0x08,0x59,0xA5,0x0B, ++ 0x00,0x57,0x01,0x39,0xA9,0x43,0x06,0x3F,0x86,0x07,0xE8,0xF7,0x00,0x27,0x19,0x12, ++ 0xA1,0xD3,0x01,0x0F,0x00,0x41,0x18,0x12,0xA0,0xD3,0x01,0xEF,0x06,0x11,0xA8,0x43, ++ 0x20,0x09,0x00,0xCF,0x06,0x01,0xA8,0x43,0x41,0x43,0x19,0x82,0x00,0x43,0x01,0x9F, ++ 0xA8,0x43,0x26,0x09,0x00,0x87,0x00,0x19,0xA8,0x43,0x26,0x09,0x00,0x67,0x00,0x21, ++ 0xA8,0x43,0x26,0x09,0x06,0x47,0xA8,0x53,0x26,0x09,0x08,0x69,0xA0,0x0B,0x00,0x1F, ++ 0xA8,0x53,0x26,0x09,0x08,0x79,0xA7,0x0B,0x60,0x01,0x80,0x66,0x40,0x82,0x42,0x0B, ++ 0x30,0x48,0xA8,0x2E,0x08,0x81,0x06,0x0B,0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B, ++ 0x45,0x43,0x19,0x82,0x07,0x43,0xE9,0xC5,0xAC,0x8D,0x87,0x25,0x40,0x4A,0x82,0x14, ++ 0x45,0x12,0xC2,0x01,0xD6,0x2B,0xD4,0x33,0x08,0x01,0xB0,0x0B,0x61,0x1A,0xE2,0x0B, ++ 0x10,0xF9,0x05,0x8A,0xA1,0x0B,0xE1,0x0B,0x10,0x01,0x19,0x8A,0xA2,0x0B,0x51,0x02, ++ 0x92,0x01,0x46,0x8B,0x18,0x01,0x1A,0xCA,0x01,0x8B,0x52,0xBA,0x44,0x8B,0x1A,0x01, ++ 0x1A,0xCA,0x00,0x8B,0x79,0x9A,0x41,0xCB,0x10,0x09,0x18,0x8A,0x00,0xCB,0x51,0x03, ++ 0x80,0x01,0xE2,0x0B,0x49,0x79,0x87,0xDE,0xE6,0x03,0x40,0x69,0x88,0x46,0x09,0xA9, ++ 0x07,0x91,0xB8,0xFF,0xE8,0x3F,0x46,0x09,0x89,0x0E,0x32,0x42,0x1A,0x82,0x03,0x08, ++ 0x10,0x09,0x88,0x1C,0x94,0x04,0x90,0x4D,0x18,0x01,0xC0,0x14,0xBB,0xFF,0xEF,0x2F, ++ 0x42,0xC3,0x41,0x00,0x01,0x00,0x02,0xC3,0x40,0x5A,0x11,0x09,0x90,0x04,0xC8,0x1C, ++ 0x14,0x01,0x90,0x4D,0x37,0x9A,0xB8,0xFF,0xE8,0xC7,0xC2,0x24,0x15,0x09,0xC8,0x48, ++ 0xE8,0x48,0x90,0x04,0x00,0x48,0x12,0x01,0x1F,0x09,0xB8,0xFF,0xE8,0x77,0x02,0xF7, ++ 0x08,0xA1,0x00,0x91,0xBC,0xFF,0xEF,0xF7,0x40,0x09,0x88,0xC6,0x18,0xAA,0x13,0x09, ++ 0x20,0x40,0x63,0x08,0x90,0x04,0x30,0x9A,0xC7,0x14,0xB8,0xFF,0xE8,0xF7,0x01,0x77, ++ 0x08,0xB1,0x00,0x91,0xBC,0xFF,0xEF,0x77,0x40,0x09,0x88,0x46,0xC0,0x24,0x10,0x09, ++ 0xC8,0x48,0xED,0x48,0x00,0x48,0x32,0x9A,0x97,0x04,0xB8,0xFF,0xE9,0x77,0xE1,0x03, ++ 0x08,0xF9,0x06,0x42,0xA1,0x03,0x41,0xC3,0x42,0x00,0x02,0x00,0x00,0xC3,0x41,0x32, ++ 0x0A,0x01,0x0F,0x0B,0x0C,0x01,0x00,0x0B,0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B, ++ 0x28,0xCF,0x00,0x00,0xF8,0x00,0x06,0x42,0x80,0x01,0x06,0x42,0x00,0xC0,0x05,0x01, ++ 0x00,0x70,0x00,0x01,0x58,0x20,0x00,0x01,0x10,0x00,0x00,0x42,0x00,0xC0,0x06,0x01, ++ 0x00,0x00,0x00,0x42,0x18,0xC0,0x07,0x01,0x08,0x40,0x01,0x01,0x52,0xCA,0x42,0x83, ++ 0x02,0x83,0x42,0xCA,0xF7,0x0B,0x48,0xF9,0x90,0x16,0xF0,0x0B,0xE0,0x48,0xB2,0x0B, ++ 0xF0,0x03,0x40,0xC1,0x90,0x0E,0x00,0x01,0x03,0x83,0x3C,0x82,0x4C,0x9A,0x4A,0x53, ++ 0x58,0x8A,0xE2,0xC3,0x1C,0x12,0x0C,0x53,0x10,0x43,0x02,0x09,0xB3,0xC3,0x38,0x82, ++ 0xAA,0x85,0x40,0x72,0x84,0x01,0x42,0x0B,0x10,0x01,0x1C,0x8A,0x02,0x0B,0x54,0x62, ++ 0x4A,0x4A,0x42,0x62,0x85,0x27,0xC0,0xAF,0xEF,0x85,0xA8,0xC5,0x46,0x32,0x82,0x01, ++ 0xE2,0x0B,0x78,0x4A,0x30,0x48,0xAC,0x46,0xE2,0x0B,0x10,0x01,0x18,0x8A,0xA0,0x0B, ++ 0x44,0xC3,0x0B,0x01,0x1B,0x42,0x04,0xC3,0xE8,0xC5,0x17,0x01,0x0D,0xD3,0x45,0xCB, ++ 0x6E,0xEA,0x01,0x79,0x01,0x0A,0x30,0x72,0x59,0x02,0xB2,0x01,0x61,0x44,0x57,0x63, ++ 0x48,0x09,0x80,0xDE,0x48,0x29,0x80,0x46,0x4B,0x41,0x88,0x46,0x8F,0x93,0x43,0xCB, ++ 0x38,0x48,0x8E,0x16,0x05,0x81,0x00,0xC3,0xED,0xC5,0x0F,0xD3,0x10,0xC2,0x8C,0x16, ++ 0x07,0x29,0x05,0xC3,0x01,0x3F,0xE0,0x0A,0x02,0xCB,0xE7,0x00,0x97,0x05,0x24,0x44, ++ 0x40,0x89,0x9A,0x06,0x20,0x5C,0x07,0xA1,0x07,0xC3,0xED,0xC5,0xC8,0x8B,0x4B,0x11, ++ 0x91,0xE6,0x61,0x7A,0x48,0x01,0x88,0x2E,0x43,0xC3,0x07,0x04,0x41,0x6A,0x11,0x43, ++ 0x21,0x54,0x07,0xF7,0x43,0xC3,0x47,0x0C,0x10,0x48,0xC0,0x40,0x96,0x25,0x04,0x89, ++ 0x11,0x00,0xD0,0x00,0x40,0x01,0xC1,0x76,0x97,0x05,0xBF,0xFF,0xF1,0x1F,0x44,0x32, ++ 0x11,0x22,0x8C,0x76,0x00,0x09,0x80,0x07,0xC8,0xD7,0x03,0xC1,0xB1,0x43,0x49,0x02, ++ 0x00,0x09,0x80,0x43,0x00,0x2F,0x41,0xC2,0x86,0x01,0xED,0x03,0x08,0x69,0x18,0x48, ++ 0x40,0x01,0x88,0x36,0xD2,0x00,0x43,0x81,0xC7,0x0E,0x20,0x44,0x07,0xCF,0x20,0x5C, ++ 0x00,0xBF,0x40,0xD2,0xC1,0x00,0x41,0x19,0xC7,0x1E,0x20,0x44,0x41,0xC2,0x10,0x43, ++ 0x03,0x7F,0xD0,0x00,0x40,0xB1,0xC1,0x66,0x20,0x44,0x07,0x57,0x10,0xC2,0x84,0x46, ++ 0x41,0xCB,0xA7,0x0A,0x62,0x44,0xE7,0x00,0x97,0x05,0x24,0x44,0x40,0x89,0x9A,0x06, ++ 0x23,0x5C,0xCF,0x83,0xE3,0x00,0x8A,0x83,0x05,0x81,0x00,0xC3,0xED,0xC5,0x07,0xD3, ++ 0xE8,0xC5,0x07,0x00,0x10,0x00,0x00,0x42,0x00,0xC0,0x00,0x01,0xF8,0x00,0x06,0x42, ++ 0x58,0xC0,0x02,0x01,0x00,0xA0,0x07,0x01,0x80,0x01,0x06,0x42,0xF8,0xFF,0x07,0x00, ++ 0x00,0x80,0x00,0x01,0x58,0x20,0x00,0x01,0x88,0x76,0x00,0x00,0x77,0x81,0xF8,0xFF, ++ 0xF8,0x02,0x07,0x00,0xA8,0x85,0x80,0x07,0xC8,0x77,0x65,0x32,0xE8,0x03,0x47,0x01, ++ 0x80,0x26,0x40,0x31,0x8F,0xD6,0xBF,0xFF,0xDF,0x3F,0x38,0xBF,0xBB,0xFF,0xD7,0x5F, ++ 0x38,0xA7,0x07,0x00,0x00,0xC0,0x05,0x01,0xAE,0xC5,0x6F,0xDA,0x03,0x41,0x83,0x43, ++ 0x01,0x09,0x80,0x43,0x0F,0x01,0x81,0x4B,0x15,0x19,0x80,0x53,0x13,0x41,0x89,0x53, ++ 0x17,0x69,0x89,0x53,0x15,0x69,0x88,0x53,0x11,0x92,0x32,0x7A,0xBD,0x01,0x15,0xD4, ++ 0x17,0xA1,0x1D,0x54,0x32,0x62,0xA1,0x01,0x8D,0x03,0x8B,0x03,0x07,0x41,0x88,0x03, ++ 0x11,0x51,0x90,0x13,0x13,0xA1,0x90,0x13,0x90,0x0B,0x0F,0x81,0x9B,0x0B,0x99,0x03, ++ 0x0F,0x01,0x98,0x4B,0x0D,0x71,0x90,0x4B,0x17,0x31,0x90,0x53,0x98,0x4B,0x0B,0x31, ++ 0x98,0x4B,0x09,0x01,0x99,0x4B,0xA5,0x43,0x03,0x81,0xA1,0x43,0x03,0x51,0x80,0x03, ++ 0x05,0xB1,0x87,0x03,0x07,0x51,0x80,0x03,0x01,0xB1,0x8F,0x03,0x05,0x29,0x94,0x03, ++ 0x01,0x51,0x28,0x44,0x03,0xF9,0x87,0x49,0x34,0x32,0xB1,0x01,0x00,0x84,0x01,0xC9, ++ 0x0B,0x00,0x02,0x84,0x04,0x79,0x10,0x00,0x05,0x83,0x43,0xC2,0x00,0x83,0x05,0x01, ++ 0x99,0x83,0x31,0x02,0x0C,0x51,0x80,0x91,0x87,0x27,0xD0,0x87,0x05,0xB1,0xB7,0xC3, ++ 0x07,0xA1,0xB0,0xC3,0x07,0x01,0xA8,0xC3,0x09,0x01,0x30,0x02,0x80,0x01,0xA2,0x0B, ++ 0xA0,0x0B,0x0E,0xC1,0xA8,0x0B,0x08,0x51,0xAE,0x0B,0x0A,0x41,0x1F,0x0C,0x0E,0xF9, ++ 0x89,0x21,0x00,0xCC,0x0E,0x99,0x18,0x4A,0xA8,0x0B,0x14,0xA1,0xA8,0x13,0xB6,0x0B, ++ 0x0A,0xA1,0xB0,0x0B,0x0A,0x51,0x88,0x0B,0x14,0xF1,0x88,0x13,0x0E,0x21,0x8B,0x0B, ++ 0x0A,0x59,0x0D,0x0C,0x08,0xE1,0x90,0x0B,0x08,0xC9,0x99,0x0B,0x0A,0x31,0x98,0x0B, ++ 0x08,0xF9,0x8F,0x09,0x08,0x0C,0x0E,0x51,0xB8,0x4B,0x0B,0x01,0x32,0x4C,0xA3,0x0B, ++ 0x0D,0x21,0xB0,0x8B,0x0B,0x31,0xB0,0x8B,0x09,0x19,0x0D,0x4C,0x0C,0xA1,0xB0,0x0B, ++ 0x0E,0x51,0xB0,0x0B,0x0C,0x01,0xA0,0x0B,0x08,0x19,0xBC,0x0B,0x09,0x31,0x80,0x0B, ++ 0x18,0x01,0x30,0x0A,0xCE,0x01,0x9B,0x5B,0xA2,0x5B,0x88,0x01,0xB2,0x53,0xB0,0x53, ++ 0x14,0xE1,0xB1,0x53,0x16,0x41,0xB0,0x53,0x10,0x11,0xB8,0x53,0x12,0xB1,0xB8,0x53, ++ 0x14,0x19,0xB8,0x53,0x48,0x52,0x04,0x0B,0x8C,0x1B,0x48,0x52,0xC6,0x01,0x34,0x0B, ++ 0x88,0x91,0x38,0x0B,0x8A,0xE1,0x3E,0x0B,0x0C,0xC1,0x40,0x3A,0x84,0x27,0xD0,0x77, ++ 0x40,0x2A,0x0C,0xC1,0xC0,0x81,0x81,0x27,0xD4,0x4F,0x4C,0x12,0x43,0x1A,0xCC,0x31, ++ 0x00,0x0B,0xCE,0x71,0x00,0x0B,0x8C,0xA1,0x08,0x0B,0x88,0xC1,0x0A,0x0B,0xCA,0x21, ++ 0x01,0x0B,0xCA,0xC1,0x05,0x0B,0x88,0xA1,0x0D,0x0B,0xCC,0xC1,0x10,0x0B,0xFA,0x48, ++ 0x10,0x0B,0xF8,0x48,0x0F,0x0B,0xEE,0xC5,0xA8,0x85,0x09,0x01,0x63,0x92,0x43,0x92, ++ 0xA2,0xE1,0xFE,0x1B,0x01,0x77,0x00,0x21,0x18,0x42,0xCA,0x28,0x00,0x29,0x12,0x79, ++ 0x09,0x00,0xC2,0x40,0x90,0x13,0x10,0x01,0x94,0x13,0x92,0x13,0x10,0x14,0x1E,0x14, ++ 0xE6,0x48,0x92,0x4D,0x17,0x5A,0xC4,0x76,0x07,0x01,0x10,0xF9,0x2D,0x09,0x09,0x68, ++ 0x02,0x37,0x00,0x08,0xCA,0x48,0xC8,0x48,0xB2,0x53,0xB0,0x53,0xE6,0x00,0x92,0x05, ++ 0x17,0x1A,0xC4,0xB6,0xE9,0x85,0xA1,0x85,0x56,0xFA,0x92,0x01,0x08,0x01,0x10,0x8C, ++ 0xD4,0x01,0xB6,0x8B,0xB8,0x8B,0x30,0x9A,0x98,0x01,0xB5,0xCB,0x1C,0xCC,0xBC,0xCB, ++ 0xB0,0xCB,0x22,0x09,0xB0,0xA3,0xA8,0x8B,0xDE,0x01,0xF1,0xDB,0xB0,0x9B,0x32,0x9A, ++ 0x9A,0x01,0xA1,0xCB,0x9A,0x01,0xA1,0xE3,0xA4,0xCB,0xA0,0xA3,0x20,0x41,0x89,0xA3, ++ 0x40,0x09,0x88,0x16,0xA1,0xCB,0xE4,0x85,0x39,0xB7,0xE5,0x85,0x3A,0x82,0x0B,0x08, ++ 0x40,0x9A,0x42,0x13,0x18,0x01,0x01,0xD2,0x90,0x41,0x04,0x13,0x10,0xD0,0x1C,0x8A, ++ 0x0A,0x0B,0x42,0x0B,0x40,0x0B,0x10,0x41,0x18,0x8A,0x04,0x0B,0x0C,0x01,0x00,0x0B, ++ 0x38,0x82,0xAB,0x85,0x40,0x5A,0x42,0x0B,0x30,0x48,0xA8,0x2E,0x08,0x81,0x06,0x0B, ++ 0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B,0x4E,0x32,0x8A,0x01,0x40,0x53,0x3C,0x90, ++ 0x7C,0x90,0x00,0x53,0x41,0x53,0x1C,0x81,0x1C,0xD2,0x00,0x53,0x5E,0x12,0x12,0x09, ++ 0x01,0xD3,0x12,0x91,0x02,0x13,0x46,0x0A,0x40,0x23,0x14,0x61,0x1C,0xA2,0x00,0x23, ++ 0x40,0x23,0x1A,0xA2,0x02,0x23,0x4A,0x23,0x1A,0xA2,0x08,0x23,0x48,0x23,0x18,0xA2, ++ 0x0E,0x23,0x40,0x23,0x1E,0xA2,0x00,0x23,0x42,0x43,0x12,0x01,0x1A,0x82,0x00,0x43, ++ 0x00,0xD1,0x04,0xC3,0x02,0x01,0x0F,0xC3,0xE9,0x85,0x40,0xA2,0x40,0x13,0x08,0x09, ++ 0x18,0x52,0x00,0x13,0x4C,0x13,0x18,0x52,0x0A,0x13,0x48,0x13,0x1A,0x52,0x0C,0x13, ++ 0x40,0x13,0x1E,0x52,0x03,0x13,0x3E,0x82,0x40,0x6A,0x59,0x0B,0x10,0x21,0x18,0x8A, ++ 0x18,0x0B,0x58,0x0B,0x10,0x01,0x1A,0x8A,0x18,0x0B,0x58,0x13,0x08,0x01,0x1C,0x52, ++ 0x19,0x13,0x40,0x22,0x16,0x01,0x80,0x01,0x02,0x13,0x40,0x13,0x1A,0x52,0x00,0x13, ++ 0x48,0xFA,0x40,0x43,0x10,0x01,0x19,0x82,0x03,0x43,0x38,0x82,0xA8,0x85,0x08,0x09, ++ 0x00,0x31,0x80,0x07,0xD0,0x3F,0x0D,0x11,0x00,0x21,0x80,0x07,0xD0,0x1F,0x05,0x09, ++ 0x85,0x07,0xD0,0xFF,0x00,0x31,0x80,0x07,0xD0,0xE7,0x05,0x21,0x85,0x07,0xD0,0xCF, ++ 0x86,0x07,0xD0,0x77,0xE8,0x85,0xA8,0x85,0x40,0x82,0x48,0x5A,0xC0,0xA1,0x12,0x43, ++ 0xBA,0xFF,0xF7,0xD7,0x07,0x09,0xB8,0xFF,0xF8,0x77,0x02,0xA1,0xBB,0xFF,0xFF,0x7F, ++ 0xBB,0xFF,0xFF,0xFF,0xBE,0xFF,0xFF,0x07,0xBD,0xFF,0xFF,0x7F,0xBE,0xFF,0xFF,0xB7, ++ 0x48,0x62,0x00,0x01,0x80,0x43,0xE8,0x85,0x00,0xC0,0x00,0x01,0xC8,0x21,0x01,0x00, ++ 0xF8,0xFF,0x07,0x04,0xD8,0x02,0x06,0x00,0x40,0x60,0x07,0x01,0x58,0xC0,0x02,0x01, ++ 0x10,0x00,0x00,0x42,0x00,0x00,0x00,0x42,0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42, ++ 0x18,0x00,0x02,0x42,0x00,0x80,0x00,0x01,0xA8,0x85,0x80,0x07,0xD0,0xEF,0xEA,0x85, ++ 0xAF,0x85,0xB8,0xFF,0xF0,0xBF,0xE8,0x85,0xA8,0x7D,0x80,0x04,0x88,0x0C,0xC0,0x0C, ++ 0x80,0x14,0xC0,0x04,0x83,0x1C,0x30,0x42,0x40,0x7E,0x80,0x25,0xE8,0x05,0x00,0x00, ++ 0xAC,0xFD,0x87,0x1D,0x30,0x32,0x00,0x01,0x82,0x14,0x00,0x9F,0x44,0xFA,0x0F,0x01, ++ 0x0C,0x0B,0x26,0x01,0xC2,0x14,0x00,0x28,0x7F,0xE2,0x4F,0xC3,0x1F,0x02,0x09,0xC3, ++ 0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x86,0x1F,0xD8,0x37, ++ 0xF8,0x82,0x33,0x0A,0xCF,0x99,0x49,0xC9,0x99,0x3E,0x40,0x91,0xE7,0x16,0x48,0xC3, ++ 0x1F,0x02,0x0D,0xC3,0x40,0x20,0x63,0x01,0x88,0x36,0xD7,0x6C,0x90,0x04,0x10,0x09, ++ 0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x1F,0xDB,0x8F,0xFD,0xA2,0xD0,0x6C,0x90,0x04, ++ 0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x85,0x1F,0xD8,0x47,0xF8,0xBA,0xD3,0x6C, ++ 0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x1F,0xDD,0xFF,0x14,0x3A, ++ 0xE9,0x16,0x30,0x02,0x30,0xE2,0x31,0x3A,0xFD,0x82,0x13,0xC2,0xE3,0x0E,0x98,0xBA, ++ 0x05,0x17,0x10,0x02,0xDB,0x06,0x98,0xA2,0x46,0xE2,0x4E,0x03,0xDE,0x8A,0x0B,0x00, ++ 0xC0,0x00,0xCA,0x24,0x00,0x44,0xC0,0x24,0xE0,0x00,0x84,0x24,0xC2,0x14,0xE0,0x00, ++ 0x90,0x05,0x86,0x14,0xC8,0x2C,0xC0,0x14,0x15,0x42,0x9C,0x3E,0x87,0x3D,0xE8,0x85, ++ 0xAC,0xFD,0x87,0x7D,0x30,0xA2,0x30,0xEA,0xD8,0x0B,0x8B,0x6C,0xD0,0x0B,0x8F,0x64, ++ 0x40,0x01,0x80,0x6E,0x48,0x72,0x06,0x99,0x07,0x43,0x12,0xF9,0x58,0x5A,0x96,0x81, ++ 0x10,0xD3,0x06,0x43,0x00,0xC1,0x83,0x1F,0xF8,0x77,0xFF,0x84,0xB8,0xA1,0x01,0xD7, ++ 0x40,0x3A,0x0E,0x19,0x04,0x0B,0x0A,0x19,0x06,0x0B,0x08,0x09,0xC4,0x84,0x00,0x48, ++ 0xC0,0x38,0x12,0x01,0x30,0x5A,0x31,0x8A,0x00,0x09,0x80,0x17,0xD0,0xE7,0x31,0x01, ++ 0x30,0x1A,0x11,0x09,0x08,0x01,0x44,0x1D,0xA8,0x04,0x80,0x1F,0xDB,0x7F,0xE2,0xB0, ++ 0x91,0xB5,0x77,0x91,0x9D,0xA6,0x47,0xD2,0x40,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B, ++ 0x00,0xE1,0xEC,0x02,0x33,0x00,0xA8,0xE6,0x40,0xB2,0x0D,0x01,0x81,0x0B,0x30,0x12, ++ 0x30,0x4A,0x01,0x11,0x84,0x17,0xC8,0x27,0x30,0x1A,0xA9,0x04,0x08,0x01,0x00,0x11, ++ 0xD0,0x84,0x80,0x17,0xD0,0x77,0x33,0x01,0xC2,0x64,0x00,0x00,0x80,0x74,0x00,0xBF, ++ 0x31,0x5A,0x31,0x92,0x08,0x01,0x00,0x09,0x80,0x17,0xD0,0x6F,0xA8,0x0C,0xA0,0x04, ++ 0x30,0xCA,0x41,0x1D,0xD8,0x84,0xD0,0x64,0xBA,0xFF,0xFF,0x17,0xC6,0x74,0xC8,0x38, ++ 0x09,0x09,0x30,0x5A,0x30,0x92,0x31,0x42,0x87,0x17,0xC8,0xEF,0xE7,0xB0,0x93,0xB5, ++ 0xC4,0x6C,0x10,0x32,0x99,0x26,0x37,0x1A,0xA8,0x04,0x08,0x01,0x00,0x19,0xD0,0x84, ++ 0x82,0x17,0xD0,0x3F,0x31,0x12,0x31,0x4A,0x00,0x01,0x80,0x17,0xCD,0x8F,0xDA,0x03, ++ 0x41,0x01,0x80,0xF6,0x40,0xBA,0x0C,0x09,0x81,0x0B,0x30,0x12,0x30,0x4A,0x01,0x11, ++ 0x82,0x17,0xC8,0x37,0x30,0x5A,0x09,0x01,0x00,0x09,0xD0,0x6C,0x86,0x17,0xC8,0xDF, ++ 0x30,0x1A,0xA9,0x04,0x00,0x11,0xD0,0x84,0xC8,0x6C,0x80,0x17,0xD0,0x57,0xA9,0x0C, ++ 0xA5,0x04,0xD8,0x13,0x30,0xCA,0x41,0x1D,0xDF,0x84,0xB8,0xFF,0xFD,0x4F,0xD8,0x03, ++ 0x06,0x00,0xCA,0x30,0x30,0x1A,0xA9,0x04,0x00,0x19,0xD0,0x84,0xC8,0x6C,0x80,0x17, ++ 0xD0,0xC7,0x08,0x09,0x30,0x5A,0x31,0x42,0xD0,0x6C,0x80,0x17,0xC9,0xE7,0x35,0x12, ++ 0x30,0x4A,0x01,0x01,0x80,0x17,0xC8,0xE7,0x40,0xF2,0x0B,0x01,0x85,0x0B,0xD8,0x03, ++ 0x00,0x27,0x00,0x37,0x05,0x8C,0xE1,0xB0,0xE6,0x00,0x92,0x05,0xD4,0x64,0x10,0x82, ++ 0x9B,0xC6,0x57,0xBA,0x40,0x83,0x08,0x11,0x18,0x42,0x04,0x83,0x87,0x9D,0xE8,0x85, ++ 0xAC,0xFD,0x87,0x1D,0x30,0x7A,0x50,0x01,0x80,0x16,0x00,0x01,0x80,0x0C,0x00,0x0F, ++ 0x00,0x09,0x80,0x0C,0x2A,0x01,0x00,0x47,0xCD,0x64,0x00,0x40,0xC1,0x30,0x32,0x52, ++ 0x08,0x19,0xD8,0x6C,0xC0,0x0C,0x80,0x17,0xC9,0x77,0x04,0x41,0x81,0x1F,0xF8,0x5F, ++ 0x20,0x09,0xC0,0x34,0x80,0x01,0x84,0x14,0x60,0x81,0x99,0x36,0x0B,0xF9,0x47,0x1A, ++ 0x88,0x11,0x18,0x0B,0x42,0x08,0x1B,0x0B,0x03,0x0F,0x40,0x02,0x1F,0x23,0x02,0xF9, ++ 0x4F,0xF2,0x82,0x89,0x88,0x01,0x12,0x43,0x00,0x11,0x80,0x1F,0xF8,0xA7,0xC0,0x14, ++ 0xE0,0x03,0x44,0x01,0x80,0x3E,0x00,0x51,0x80,0x1F,0xF8,0x6F,0x40,0x83,0x41,0x03, ++ 0x30,0x00,0xA8,0x86,0x07,0x5F,0x00,0xF9,0x4C,0xA2,0x82,0x89,0x88,0x01,0x12,0x43, ++ 0x00,0x09,0x80,0x1F,0xF9,0x07,0x40,0x83,0x40,0x03,0x30,0x00,0xA3,0x1E,0xE0,0x20, ++ 0x93,0x25,0x67,0xF9,0xC9,0x86,0x06,0xE4,0xE1,0xF8,0x35,0x52,0x08,0x09,0xD8,0x6C, ++ 0xC0,0x0C,0x80,0x17,0xCB,0x87,0xE2,0x68,0x90,0x6D,0xC7,0x1C,0x15,0x2A,0x9C,0x9E, ++ 0x37,0x27,0xAF,0x85,0x80,0x4D,0x34,0x6A,0x34,0xA2,0x00,0x91,0xEF,0x02,0x0A,0xF9, ++ 0x88,0x09,0x40,0x01,0x80,0x0E,0x30,0x7A,0x00,0x0F,0x38,0x19,0x17,0xF8,0xD1,0x43, ++ 0x85,0x44,0xD0,0x53,0x90,0x3C,0x98,0x24,0xC2,0x44,0x00,0x00,0xC0,0x00,0x86,0x2C, ++ 0xD2,0x3C,0x00,0x90,0xC0,0x00,0x84,0x1C,0x45,0xC2,0x11,0x81,0x00,0x13,0x1A,0x0B, ++ 0x30,0x01,0x00,0x67,0x4D,0x03,0x01,0x88,0xC0,0x00,0x42,0x03,0x01,0x3B,0x30,0x1A, ++ 0x30,0x92,0x09,0x09,0x00,0x01,0x80,0x17,0xCB,0xF7,0xE0,0xB0,0x90,0xB5,0xC7,0x44, ++ 0x17,0x32,0x9C,0x7E,0x30,0x01,0x00,0x67,0x4D,0x03,0x03,0x88,0xC0,0x00,0x42,0x03, ++ 0x00,0x3B,0x08,0x09,0x31,0x1A,0x31,0x92,0x30,0x42,0x80,0x17,0xCB,0x67,0xE0,0xB0, ++ 0x90,0xB5,0xC7,0x3C,0x17,0x32,0x9C,0x7E,0xD8,0x43,0x45,0x01,0x81,0x16,0x41,0x1A, ++ 0x44,0x0B,0x96,0x4D,0x89,0x14,0x48,0x4C,0x01,0x0B,0x4E,0x12,0x00,0x09,0x80,0x43, ++ 0xD8,0x43,0x85,0x34,0x30,0x01,0x00,0x67,0x55,0x03,0x01,0x88,0xC0,0x00,0x42,0x03, ++ 0x01,0x3B,0x30,0x1A,0x30,0x92,0x09,0x09,0x00,0x01,0x80,0x17,0xC3,0x67,0xE7,0xB0, ++ 0x90,0xB5,0xC7,0x34,0x17,0x32,0x9C,0x7E,0x48,0xB2,0x00,0x01,0x80,0x43,0x40,0x9A, ++ 0xCE,0x14,0x00,0x0B,0x48,0x0B,0x89,0x04,0x30,0x5A,0x11,0x09,0xA0,0x0C,0xC8,0x24, ++ 0xC7,0x44,0xB8,0xFF,0xFB,0xAF,0x49,0x0B,0x89,0x04,0x30,0x5A,0x10,0x01,0xA0,0x0C, ++ 0xC8,0x2C,0xC0,0x3C,0xB9,0xFF,0xFF,0x67,0xD8,0x43,0x45,0x01,0x80,0xDE,0x70,0x3A, ++ 0x44,0x83,0x97,0x3D,0x4F,0x44,0x01,0x83,0x40,0x32,0x08,0x09,0x85,0x0B,0xD8,0x43, ++ 0x51,0x0B,0x31,0x5A,0x10,0x09,0xA0,0x0C,0x88,0x04,0x00,0x2F,0x00,0x01,0x00,0x42, ++ 0x18,0x00,0x04,0x42,0x00,0xB0,0x00,0x01,0xCF,0x1C,0xB8,0xFF,0xF8,0x8F,0x40,0xDA, ++ 0x08,0x01,0x80,0x0B,0x00,0xBB,0x4F,0xD2,0x00,0x01,0x10,0x43,0x4A,0xC2,0xC8,0x01, ++ 0x18,0x43,0x80,0x4D,0xEF,0x85,0xAF,0xC5,0x30,0x1A,0x30,0x42,0x34,0xBA,0xD0,0x23, ++ 0xD0,0x2B,0x4E,0xA2,0xC0,0xC8,0x8A,0x04,0x30,0xD2,0x31,0xCA,0x80,0x17,0xE8,0xE7, ++ 0x30,0x01,0x00,0x3F,0x09,0x09,0x30,0xDA,0x30,0x92,0x31,0x42,0x84,0x17,0xC0,0x9F, ++ 0xE7,0xB0,0x93,0xB5,0x17,0x32,0x9D,0xAE,0xC8,0x04,0x10,0x01,0x18,0x01,0x00,0x4F, ++ 0x00,0x01,0x00,0x1F,0x82,0x5B,0xE0,0x48,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE, ++ 0xE6,0x90,0x92,0x95,0x17,0x12,0x9D,0x9E,0xE8,0xC5,0x07,0x00,0x00,0xB0,0x00,0x01, ++ 0x00,0x01,0x02,0x42,0x30,0x20,0x06,0x00,0x49,0x32,0x41,0x2A,0x05,0x43,0x9E,0xFF, ++ 0x7F,0x04,0x3A,0xF7,0x94,0x15,0x3A,0x00,0x77,0x18,0x06,0xF9,0x04,0xC2,0x3C,0x48, ++ 0x74,0x48,0x00,0xCA,0x50,0x01,0xD0,0x5E,0x38,0x90,0x78,0x90,0xD4,0x41,0x40,0x98, ++ 0x54,0xE2,0x00,0xD8,0xC6,0xD0,0x4C,0x9B,0x18,0x1A,0x1C,0x5A,0x0B,0x9B,0x3E,0x82, ++ 0x40,0x98,0x54,0xCA,0x04,0xD8,0xC4,0xD0,0x44,0x9B,0x18,0x1A,0x18,0x5A,0x00,0x9B, ++ 0x3A,0x82,0x93,0x05,0x36,0x10,0x76,0x90,0x0C,0x09,0x00,0x8A,0x48,0x00,0x52,0x9A, ++ 0x04,0x00,0xC4,0x00,0x03,0x0B,0x38,0x82,0x96,0x05,0x32,0x10,0x70,0x90,0x0E,0x09, ++ 0x00,0x8A,0x54,0x72,0x4C,0x00,0x02,0x00,0x94,0x01,0xC4,0x00,0x03,0x0B,0x38,0x82, ++ 0xB3,0x15,0x3B,0x82,0xFB,0x85,0x39,0x82,0x40,0x32,0x48,0x0B,0x10,0x21,0x18,0x8A, ++ 0x0B,0x0B,0x38,0x82,0x48,0x1A,0x48,0x43,0x14,0x21,0x18,0x82,0x0B,0x43,0x38,0x82, ++ 0x07,0x20,0x28,0xD0,0x68,0x07,0x00,0x07,0x20,0x07,0x00,0x07,0x08,0x07,0x00,0x07, ++ 0xAC,0xFD,0x87,0x4D,0xD0,0x94,0x30,0x22,0xF0,0x43,0x84,0x0C,0xF8,0x6B,0xC2,0x64, ++ 0x08,0x01,0x80,0x0B,0x00,0x01,0x00,0x8F,0x0A,0x21,0x19,0x0A,0x18,0x29,0xCA,0x48, ++ 0x0E,0xD8,0xC2,0x48,0xD0,0x4B,0x48,0x79,0x80,0x36,0x80,0x83,0xE0,0x90,0xCA,0x64, ++ 0xD8,0x64,0xC0,0x4B,0xE0,0x48,0x82,0xCB,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0x5E, ++ 0xC0,0x64,0xC0,0x03,0x80,0x44,0x40,0x01,0x88,0x0E,0x80,0x6D,0xE8,0x85,0xC7,0x44, ++ 0x40,0x09,0x88,0x1E,0xC0,0x0C,0x40,0x09,0x8F,0x06,0x38,0xB7,0x00,0x01,0x80,0x34, ++ 0x80,0x2C,0xC8,0x44,0xC4,0x0C,0x10,0x0A,0x88,0x8E,0x02,0x01,0x30,0x01,0x08,0x01, ++ 0x88,0x1C,0x88,0x14,0x1A,0x19,0x0A,0xD8,0x00,0x4F,0x10,0x31,0x18,0x52,0xCA,0x90, ++ 0xC4,0x90,0x4E,0xBC,0xC6,0xC0,0x49,0x94,0xCA,0xB0,0xE4,0x48,0x90,0x4D,0xD6,0x0C, ++ 0x17,0x8A,0x9C,0x96,0xC8,0x0C,0x80,0x1F,0xF0,0xFF,0x83,0x24,0x30,0x82,0xC9,0x0C, ++ 0x83,0x1F,0xF0,0xD7,0x30,0x32,0x08,0x01,0x00,0x01,0x00,0xFF,0x1A,0x29,0x0A,0xD8, ++ 0x02,0x0F,0xE0,0x48,0x91,0x4D,0x16,0x21,0x18,0x52,0xCA,0x90,0xC0,0x90,0xD6,0x93, ++ 0x57,0x79,0x80,0xB6,0x12,0x21,0x19,0x52,0x18,0x19,0xC9,0x90,0x0E,0xD8,0xC4,0x90, ++ 0x1E,0x01,0xF0,0x9A,0xFE,0x1C,0xC8,0xD8,0x98,0x1C,0x18,0x11,0xF0,0x9A,0xD6,0x14, ++ 0xC0,0xD0,0x94,0x14,0xE6,0x48,0x92,0x4D,0xE6,0x00,0x92,0x05,0xD4,0x44,0x10,0x12, ++ 0xC0,0xE6,0xCE,0x44,0xC0,0x1C,0x80,0x1F,0xF0,0x7F,0x32,0x3A,0xC8,0x44,0xC0,0x14, ++ 0x82,0x1F,0xF0,0x57,0xCE,0x24,0xD8,0x48,0x89,0x34,0xD0,0x80,0x80,0x2C,0x08,0x01, ++ 0x10,0x01,0x00,0x77,0x00,0x01,0x30,0x5A,0x18,0x5A,0xF3,0x5C,0x04,0xD8,0xCA,0xD8, ++ 0x02,0x1F,0x00,0x30,0x9A,0xD2,0xE4,0x00,0x95,0x05,0x16,0x42,0x9A,0xCE,0xE7,0x48, ++ 0x95,0x4D,0x16,0x4A,0x98,0x76,0x0F,0x01,0x11,0x01,0x00,0xF7,0x1A,0x29,0x0A,0xD8, ++ 0x02,0x0F,0xE0,0x48,0x91,0x4D,0x06,0x21,0x18,0x42,0xCA,0x00,0x86,0x3C,0xC0,0x00, ++ 0xD0,0x03,0x40,0x79,0x80,0xAE,0x07,0x01,0x01,0x47,0x19,0x19,0xF4,0x3C,0x08,0xD8, ++ 0xC0,0x98,0x37,0x01,0x34,0xE2,0xFC,0xF2,0xDA,0x34,0x38,0x19,0xC0,0x98,0x37,0x31, ++ 0x19,0x32,0xCA,0xB0,0x0F,0xF8,0xCB,0xB0,0x35,0xB2,0x4D,0xB4,0xD8,0xD8,0xAC,0x06, ++ 0x14,0xDA,0x92,0xDD,0x30,0x32,0x3B,0x11,0xF8,0xBA,0xF7,0x2C,0xCB,0xF0,0x35,0xBA, ++ 0x4F,0xFC,0xDF,0xB0,0xAB,0x06,0x10,0xB2,0xC8,0xD8,0x34,0xB2,0x18,0x72,0xFB,0x5C, ++ 0x07,0xB0,0xCB,0xB0,0x07,0x38,0x9A,0x9A,0xE6,0x00,0x92,0x05,0xDC,0x0C,0x10,0xC2, ++ 0x9A,0x9E,0xE6,0x48,0x92,0x4D,0xE6,0x90,0x90,0x95,0xC6,0x64,0xC4,0x03,0x10,0x82, ++ 0xC0,0xE6,0xC5,0x64,0xC8,0x0C,0xC0,0x03,0x10,0x42,0xCC,0x06,0x38,0xEF,0xC1,0x0C, ++ 0x3F,0xDF,0xA9,0x85,0x80,0x4D,0x34,0x22,0x04,0x71,0xD4,0x1A,0x01,0xC1,0xF0,0x02, ++ 0x28,0x71,0x80,0x44,0xF8,0x2A,0xAB,0x3C,0xD8,0x00,0x92,0x05,0x2B,0xD1,0xF8,0x2A, ++ 0x30,0x81,0xA8,0x34,0xF8,0x32,0xB5,0x2C,0xD9,0x68,0x95,0x6D,0xC0,0x33,0x77,0x09, ++ 0x8D,0x16,0x10,0x04,0x10,0x2C,0x07,0x7F,0x55,0x3C,0x05,0xF0,0x31,0xE2,0xC5,0xB0, ++ 0x54,0x04,0x07,0x38,0xCB,0xE8,0x33,0x3A,0xD9,0xB0,0x97,0xB5,0xD0,0x40,0x91,0x2D, ++ 0x85,0x80,0x85,0x68,0x17,0x04,0x15,0x2C,0xF1,0x3C,0xC0,0x80,0x04,0x30,0xCA,0x00, ++ 0xF4,0x44,0xC8,0x00,0x80,0x00,0x94,0x05,0xF3,0x2C,0xC8,0xA8,0x05,0x70,0xCB,0x68, ++ 0xF5,0x34,0xC8,0x68,0x81,0x68,0x95,0x75,0x90,0x01,0x46,0x01,0xD0,0x0E,0x00,0x01, ++ 0x00,0x27,0x40,0xAC,0x10,0x2A,0xD4,0x0E,0x00,0x01,0xF0,0x82,0x70,0x01,0xD0,0x0E, ++ 0x30,0x01,0x00,0x27,0x45,0xAC,0x12,0xAA,0xD0,0x0E,0x30,0x11,0xF8,0xB2,0x4C,0x41, ++ 0x80,0x0E,0x48,0x49,0x88,0xBE,0xD0,0x3C,0xD0,0x90,0xA8,0x06,0x14,0x92,0x92,0xAD, ++ 0xD4,0x2C,0xD8,0x90,0xAA,0x06,0x10,0x92,0xCC,0x90,0x92,0xAD,0x10,0xEA,0xCC,0x06, ++ 0x30,0xEA,0x48,0x49,0x8B,0x16,0x20,0x48,0x60,0x68,0x00,0x37,0x4D,0xC8,0x10,0x4A, ++ 0xC8,0x1E,0x30,0x6A,0x00,0x0F,0x30,0xEA,0x00,0x6A,0xD6,0x3C,0xD8,0xC8,0x8A,0x24, ++ 0x1C,0x8A,0x02,0x50,0xC4,0x48,0x34,0x62,0xC8,0x24,0x10,0x51,0x05,0x78,0xF2,0x12, ++ 0xCA,0x48,0x1E,0x52,0x20,0x12,0x8B,0x1C,0x43,0xC8,0x1A,0x42,0xC6,0x00,0x02,0x00, ++ 0xC0,0x00,0x8C,0x14,0x00,0xC8,0x8E,0x0C,0x82,0x1F,0xE8,0xA7,0x30,0x3A,0xC0,0x2C, ++ 0xCA,0x24,0x18,0x0A,0x00,0x40,0xC4,0x40,0x15,0x61,0xF0,0x12,0xCA,0x1C,0x18,0x52, ++ 0xC0,0x80,0xC8,0x14,0x1B,0x72,0xC3,0x88,0x00,0x48,0xC6,0x40,0xC8,0x0C,0x80,0x1F, ++ 0xE8,0x0F,0xCA,0x3C,0x08,0x0C,0xCB,0x2C,0x08,0x0C,0xCD,0x44,0xD0,0xC8,0xAB,0x06, ++ 0x10,0x4A,0x92,0x55,0xCA,0x34,0xD0,0x08,0xAA,0x06,0x10,0x4A,0x90,0x4D,0x50,0x19, ++ 0xD8,0x46,0xD0,0x44,0x10,0xD2,0xCD,0x0E,0xE0,0xF8,0x03,0x1F,0xD5,0x44,0x10,0xD2, ++ 0x93,0x06,0xF0,0xF8,0x48,0x19,0xD8,0x46,0xCC,0x34,0x10,0x0A,0xCA,0x0E,0xE0,0x00, ++ 0x00,0x1F,0xC8,0x34,0x10,0x0A,0x94,0x06,0xF7,0x00,0x0A,0x3C,0x10,0x04,0x81,0x4D, ++ 0xEF,0x85,0xAF,0xF5,0x30,0xB2,0xD0,0x44,0x60,0xCA,0xCF,0xE0,0x2F,0x31,0x78,0xC2, ++ 0x1F,0xAA,0xC3,0x68,0xFF,0xE1,0xC9,0x68,0x07,0xB0,0xC3,0x98,0x72,0xA2,0xF7,0x81, ++ 0xCA,0xF0,0xFC,0x9B,0x36,0xBA,0xB8,0x01,0x32,0xE2,0xFD,0x01,0xBA,0x0C,0xF8,0x01, ++ 0xB8,0x04,0x40,0x09,0x88,0x36,0x01,0x01,0x01,0xFF,0xC0,0x0B,0x48,0x79,0x88,0xCE, ++ 0x47,0x4C,0x09,0x0C,0x41,0x7C,0x13,0x3C,0xC1,0x93,0x89,0x13,0xC3,0x93,0x8B,0x13, ++ 0x1F,0x0C,0x1D,0x3C,0x23,0x0C,0x21,0x3C,0x0D,0x0C,0x0B,0x3C,0x41,0x4C,0x19,0x0C, ++ 0x43,0x4C,0x1B,0x0C,0x80,0x03,0x09,0x09,0x85,0x0B,0x8F,0x0B,0x30,0x0A,0xDB,0x4B, ++ 0x90,0x0B,0x01,0x27,0xA2,0x21,0xE1,0x00,0x94,0x05,0x16,0xC2,0x9C,0xEE,0x16,0xC2, ++ 0x92,0x9E,0x03,0x87,0x02,0x21,0x19,0x0A,0xC8,0x60,0x08,0x41,0x41,0x44,0x19,0x04, ++ 0x01,0x11,0xF0,0x42,0x1D,0x04,0xCB,0x1B,0x58,0x09,0x88,0xA6,0x18,0xC1,0x38,0xE1, ++ 0xF7,0x1A,0xFF,0x3A,0xD8,0xD8,0xAE,0x06,0x14,0xDA,0x92,0xFD,0x1F,0xF1,0xF0,0x1A, ++ 0xD0,0x00,0xAE,0x06,0x14,0x02,0x92,0x05,0xD9,0x0C,0xC0,0xC0,0xDC,0xDB,0x10,0xC2, ++ 0xC8,0x0E,0x00,0x01,0x88,0x03,0x05,0xC1,0x19,0x01,0xF1,0x02,0xF6,0x1A,0xD7,0x00, ++ 0xAA,0x06,0x10,0x02,0x90,0x3D,0x04,0xD1,0x19,0x11,0xF1,0x02,0xF6,0x1A,0xD7,0x00, ++ 0xAA,0x06,0x10,0x02,0xCC,0x00,0x96,0x05,0xD4,0x1B,0x11,0x1A,0xC8,0x2E,0xD8,0x04, ++ 0xC6,0x03,0xDF,0xDB,0xE4,0xD8,0x12,0xC2,0xC0,0x86,0xD8,0x04,0xC6,0x03,0xDF,0xDB, ++ 0xE4,0xD8,0x12,0xC2,0xCB,0x1E,0x30,0x02,0xD8,0x03,0x48,0x00,0x91,0x03,0x59,0x04, ++ 0x23,0x04,0x59,0x04,0x21,0x04,0x33,0x02,0xBD,0xFF,0xF7,0x9F,0xC3,0x03,0x47,0xF9, ++ 0x92,0x0E,0xE0,0x00,0x85,0x03,0x47,0x44,0x10,0x04,0x03,0x19,0x80,0x03,0xC3,0x0C, ++ 0xDC,0x03,0x82,0x01,0x89,0x03,0xCF,0x03,0xC2,0x8B,0xD1,0x00,0xE0,0x00,0x42,0x11, ++ 0xC3,0x2E,0xC8,0x03,0xC2,0x8B,0xD3,0x00,0xE0,0x00,0x42,0x11,0xCF,0x4E,0xC0,0x03, ++ 0x40,0x11,0x98,0x36,0xCC,0x04,0xD8,0x4B,0x10,0x42,0xC4,0x16,0x07,0x01,0x80,0x03, ++ 0x89,0x03,0xC7,0x83,0x8B,0x03,0xC1,0x83,0x8F,0x03,0xEB,0xF5,0xAF,0x85,0x47,0xF9, ++ 0x88,0x0E,0x00,0x01,0xE9,0x85,0x27,0x21,0x1C,0x02,0x63,0xEA,0xC0,0x00,0xCC,0x00, ++ 0x23,0x31,0x18,0x0A,0xC4,0x48,0x54,0xD2,0xD4,0xE1,0xC1,0x50,0x0A,0xA1,0xF0,0x0A, ++ 0x48,0x01,0xD0,0x06,0x10,0x4A,0x22,0xB1,0xF8,0x22,0x60,0x01,0xD3,0x06,0x10,0x22, ++ 0xCC,0x48,0x60,0xA2,0x10,0x0A,0x9D,0x06,0x08,0x01,0x28,0x71,0x42,0xA4,0xF8,0x2A, ++ 0xD8,0x20,0xAB,0x06,0x10,0x22,0x2B,0x81,0x42,0x94,0xFA,0x2A,0xD8,0x90,0xAA,0x06, ++ 0x15,0x92,0xC2,0x28,0x34,0xE2,0xA0,0x01,0x4C,0x14,0x33,0xA2,0x10,0x52,0xC5,0xF6, ++ 0xC8,0x13,0x54,0x09,0x8B,0x26,0xD8,0x3B,0xCB,0x33,0xF6,0xF8,0x10,0xF2,0xDD,0xA6, ++ 0x50,0x09,0x88,0x3E,0xD4,0x23,0x11,0x62,0x9E,0x26,0xC0,0x03,0x40,0xF1,0xC0,0x0E, ++ 0x40,0x29,0x90,0x56,0x50,0x09,0x88,0x16,0x51,0xC4,0x46,0x81,0x98,0x2E,0x50,0x09, ++ 0x8B,0x2E,0x30,0x02,0x05,0x00,0x12,0x42,0xC0,0x0E,0x00,0x01,0xE8,0x85,0x07,0x09, ++ 0xEF,0x85,0xAF,0xFD,0x84,0x65,0x34,0xB2,0x08,0x01,0x28,0x01,0x00,0x01,0x80,0x1C, ++ 0xC2,0xAC,0xF8,0x23,0x04,0x01,0x30,0x22,0x80,0x3C,0x00,0x27,0xD7,0x6C,0x00,0xF9, ++ 0xA2,0x82,0xE2,0x48,0x95,0x4D,0x16,0x0A,0x98,0xC6,0xD7,0x7C,0x28,0x92,0xC3,0x26, ++ 0xC0,0x7C,0x80,0x2C,0x30,0x82,0x83,0x24,0x03,0x1F,0x30,0x82,0x80,0x2C,0xC0,0x7C, ++ 0x80,0x24,0x00,0x01,0x82,0x34,0x00,0xD7,0x1A,0x01,0x00,0xB7,0x36,0x02,0x03,0xC2, ++ 0x3A,0x00,0x8E,0x86,0x40,0x1A,0x83,0x44,0x00,0x01,0xD0,0xAC,0xF4,0x64,0xF0,0x93, ++ 0x90,0x5C,0x30,0xD2,0x1A,0x12,0x03,0xB8,0xC8,0xD0,0x95,0x54,0x00,0x6F,0xF0,0x3C, ++ 0x07,0x32,0x3E,0x90,0x88,0x3E,0xF0,0x54,0x07,0x38,0xDA,0xB2,0xFD,0x44,0x10,0xF2, ++ 0x90,0x0E,0xB0,0x44,0x32,0x0A,0xE0,0x00,0x90,0x05,0xD6,0x5C,0x17,0x12,0xC4,0x76, ++ 0x70,0xA2,0x02,0x01,0x00,0x78,0xBA,0x4C,0x03,0x87,0x30,0x3A,0x07,0x3A,0x3E,0xF8, ++ 0x88,0x56,0x30,0x3A,0x18,0x3A,0xD3,0x64,0x05,0xF8,0xC3,0xF8,0xD5,0x4C,0xD0,0xFA, ++ 0x10,0xBA,0xC5,0x0E,0x30,0xF2,0x31,0x2A,0xE6,0x00,0x92,0x05,0x2F,0x82,0x9B,0x66, ++ 0x10,0xEA,0x8C,0xA6,0xC4,0x1C,0xC8,0x00,0x80,0x1C,0xC0,0x34,0xE6,0x00,0x92,0x05, ++ 0x80,0x34,0xC0,0x6C,0xA0,0x2A,0x32,0x09,0x30,0x82,0xD1,0x3C,0x00,0x42,0x1C,0x82, ++ 0x90,0x05,0x84,0x3C,0x03,0x72,0x35,0x02,0x1D,0x32,0x90,0x85,0x30,0x22,0xD4,0x2C, ++ 0xC4,0x34,0x10,0x82,0x82,0x1E,0xE0,0xD8,0x93,0xDD,0x2E,0x9A,0x98,0x36,0xD5,0x2C, ++ 0xC4,0x34,0x10,0x82,0x98,0x06,0xC5,0x1C,0x80,0x44,0x10,0x01,0x00,0x01,0x08,0x01, ++ 0x30,0x5A,0x83,0xCB,0x18,0x01,0x08,0x01,0x33,0x62,0x34,0x4A,0xE0,0x4A,0x00,0x0F, ++ 0xE6,0x48,0x92,0x4D,0x36,0xEA,0x00,0x6A,0x3F,0x68,0x8F,0xCE,0xED,0x24,0x10,0x4A, ++ 0x98,0xD6,0x40,0x01,0x8F,0x8E,0x08,0xF9,0x00,0x5F,0xD0,0x6C,0xE3,0x9A,0x28,0x9A, ++ 0x90,0x1E,0xD0,0xAC,0xF4,0x93,0x14,0x12,0xC0,0x0E,0xD0,0x6C,0xA2,0x8A,0xE0,0x00, ++ 0x95,0x05,0x16,0x02,0x98,0x8E,0x87,0x85,0xEA,0x85,0xF7,0x00,0x93,0x05,0x36,0x4A, ++ 0xE0,0x4A,0x28,0x09,0x31,0x62,0x05,0x47,0x33,0x6A,0x18,0x2A,0xFB,0x64,0x00,0x70, ++ 0xCA,0xB0,0x07,0x38,0xDD,0xAA,0xC7,0x50,0x2C,0x09,0x00,0x6A,0x1D,0xEA,0x90,0x5D, ++ 0x31,0x72,0xA3,0x8A,0xED,0x44,0x10,0x52,0x98,0x16,0x28,0x11,0x30,0x62,0x05,0xA7, ++ 0xFA,0x7C,0xE0,0x28,0x10,0xEA,0x9D,0x6E,0x90,0x44,0x08,0x01,0x00,0x27,0xF8,0x6C, ++ 0xE3,0xAA,0xA3,0xEA,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xC6,0xE0,0x8A,0x29,0x09, ++ 0x30,0x62,0x05,0x17,0x90,0x45,0x2F,0x01,0xA3,0xAA,0x31,0x2A,0x6D,0x01,0x80,0x56, ++ 0x33,0x6A,0x18,0x2A,0xFB,0x64,0x00,0x70,0xCA,0xB0,0x07,0x38,0xDA,0xAA,0xDF,0x90, ++ 0x2C,0x09,0x00,0x6A,0x1B,0x5A,0x35,0x6A,0xE2,0x4A,0xE1,0x48,0xA4,0x4A,0x39,0xD7, ++ 0x40,0x40,0x05,0x00,0xF8,0xFF,0x07,0x00,0xAC,0x85,0x87,0x2D,0x33,0x72,0xF8,0x8B, ++ 0x8C,0x14,0x50,0xCA,0xC0,0x20,0xA4,0x24,0xC9,0x14,0x18,0x21,0x31,0xBA,0x31,0xAA, ++ 0x1A,0xCA,0xBA,0x01,0xA8,0x01,0xC6,0x40,0xC0,0x00,0x84,0x1C,0x01,0x67,0xC2,0x03, ++ 0x42,0x79,0x80,0x46,0xC8,0x03,0x37,0x08,0xA0,0xA6,0x41,0x21,0x88,0x16,0x01,0x71, ++ 0xF0,0x02,0x81,0x0C,0x01,0x81,0xF0,0x02,0x81,0x04,0x30,0x92,0x09,0x49,0x30,0x02, ++ 0xB8,0xFF,0xEF,0xFF,0x0B,0x71,0xF0,0x0A,0xC0,0x0C,0xD0,0x40,0xAA,0x06,0x10,0x02, ++ 0x90,0x0D,0x00,0x81,0xF0,0x02,0xD1,0x04,0xD0,0x00,0xAC,0x06,0x12,0x02,0xC2,0x00, ++ 0x91,0x05,0xD8,0x4B,0x44,0x48,0x14,0x0A,0xE8,0x5E,0xC0,0x0C,0x08,0x04,0xC7,0x04, ++ 0x10,0x04,0x01,0x37,0x40,0x21,0x90,0x26,0xF8,0x83,0x41,0x11,0x91,0x0E,0x00,0x01, ++ 0x87,0x03,0x05,0xF9,0x8B,0x03,0x89,0x03,0xC7,0x03,0xDF,0xCB,0x10,0x42,0xC4,0x0E, ++ 0x07,0x01,0x88,0x03,0xCA,0x03,0x37,0x00,0x77,0x00,0x8A,0x03,0x40,0x01,0x80,0x0E, ++ 0xF7,0x00,0x8A,0x03,0xC8,0x03,0x47,0x01,0x8B,0x2E,0xC0,0x03,0x44,0x00,0x04,0x00, ++ 0x80,0x03,0x03,0x01,0x81,0x03,0xA5,0x21,0xC5,0x1C,0x10,0x02,0xC0,0x7E,0x0D,0x01, ++ 0x11,0x01,0xB8,0x93,0xC0,0x24,0x00,0x87,0xC0,0x1B,0xE0,0x14,0x10,0x1A,0x95,0x56, ++ 0xC7,0x1B,0xDE,0xE3,0x32,0xD8,0x72,0xD8,0x10,0x1A,0xCD,0x26,0xC1,0x1B,0x5C,0x01, ++ 0x80,0x0E,0x08,0x09,0x04,0x27,0x80,0x13,0x80,0x21,0xD9,0x1C,0x17,0x1A,0xC4,0x5E, ++ 0x49,0x01,0x80,0x5E,0xC1,0x24,0x00,0x37,0x80,0x13,0xC4,0x0B,0xDC,0x14,0x10,0xCA, ++ 0x96,0x06,0xC1,0x0B,0xDA,0xDB,0x37,0x48,0x74,0x48,0x12,0xCA,0xC8,0xD6,0x08,0x09, ++ 0x81,0x0B,0xFC,0x8B,0xE1,0x48,0xBA,0x8B,0x0A,0x71,0xF0,0x0A,0x48,0x01,0xD0,0x0E, ++ 0x08,0x14,0x06,0x27,0x44,0x5C,0x11,0xCA,0xE9,0x0E,0x40,0x4C,0x08,0x0C,0x0E,0x81, ++ 0xF0,0x0A,0x4A,0x01,0xD0,0x0E,0x10,0x14,0x03,0x27,0x40,0x5C,0x10,0xCA,0xEC,0x0E, ++ 0x40,0x4C,0x13,0x0C,0x80,0x21,0xC9,0x1C,0x16,0x0A,0xC4,0xAE,0x87,0x2D,0xE8,0x85, ++ 0xAC,0x85,0x87,0x3D,0x30,0x2A,0x30,0x62,0x41,0x1A,0xC2,0x40,0x08,0xB9,0xED,0x4A, ++ 0x4B,0x29,0x80,0xE6,0x0C,0x09,0x06,0x48,0xC2,0x70,0x4B,0x02,0xC0,0x48,0x8B,0x1C, ++ 0x0E,0x19,0x03,0x48,0xC0,0x48,0x8B,0x14,0x0F,0x01,0x10,0xF9,0x18,0x79,0x00,0x3F, ++ 0xA6,0x92,0xCB,0x3B,0x78,0x01,0x88,0x06,0x82,0x1B,0xE0,0x48,0x91,0x4D,0x86,0x21, ++ 0xFC,0x3B,0x13,0x7A,0xC0,0xA6,0x07,0x01,0x85,0x34,0xF0,0x03,0x42,0x01,0x80,0xCE, ++ 0xB1,0x04,0x30,0x0A,0x30,0x42,0x59,0x2D,0xD7,0x14,0xB8,0xFF,0xD8,0x0F,0x84,0x34, ++ 0xC0,0x34,0x40,0x01,0x88,0x76,0x30,0x01,0x01,0x47,0x30,0x5A,0x37,0x92,0x09,0xF9, ++ 0x00,0x09,0xA0,0x04,0xB8,0xFF,0xEF,0xEF,0xE7,0xB0,0x93,0xB5,0xF5,0x03,0x15,0x82, ++ 0xC1,0x9E,0x07,0xFF,0xC0,0x34,0x40,0x09,0x89,0x96,0xC0,0xB3,0x31,0x1A,0x31,0x52, ++ 0x09,0x01,0x30,0x82,0xBE,0xFF,0xEF,0x17,0x40,0x01,0x80,0x0E,0x00,0x01,0x00,0x07, ++ 0x01,0x09,0x30,0x5A,0x11,0x01,0x30,0x8A,0xA7,0x04,0xB8,0xFF,0xE9,0x17,0x00,0x4F, ++ 0xA5,0x04,0xF0,0x3B,0x30,0x5A,0xEB,0xD3,0x30,0xDA,0xC9,0x1C,0xC7,0x14,0xB8,0xFF, ++ 0xF0,0x07,0x38,0x01,0x00,0xDF,0xC0,0x1C,0xEF,0x02,0x46,0xF9,0x81,0x16,0xE0,0x82, ++ 0x80,0x24,0x00,0x0F,0x00,0xF9,0x87,0x24,0x31,0x1A,0x31,0x52,0x30,0xCA,0xC1,0x24, ++ 0xBC,0xFF,0xEF,0xE7,0x40,0x01,0x80,0x0E,0x00,0x01,0x00,0x07,0x01,0x09,0x30,0x5A, ++ 0x30,0xD2,0xA1,0x04,0xCF,0x24,0xB8,0xFF,0xE3,0xE7,0xE6,0xF8,0x95,0xFD,0xF7,0x03, ++ 0x17,0xC2,0xC5,0x06,0x31,0x0A,0x31,0x42,0xD7,0x34,0xB8,0xFF,0xF0,0x6F,0x86,0x3D, ++ 0xE8,0x85,0x07,0x01,0x38,0x82,0x03,0x00,0x40,0x40,0x05,0x00,0x18,0x70,0x00,0x00, ++ 0xAE,0xFD,0x87,0x5D,0xC2,0xAC,0xDA,0x03,0x82,0xD4,0xC1,0xAC,0xD9,0x03,0x80,0xCC, ++ 0x01,0x09,0x58,0x45,0x89,0xC3,0xC0,0xCC,0xE2,0x00,0x8A,0xC3,0xC4,0xCC,0x89,0xC3, ++ 0xC2,0xCC,0xF1,0x00,0x8A,0xC3,0xC6,0xAC,0x82,0x01,0x86,0x54,0xE0,0x0B,0x00,0x21, ++ 0x1A,0x0A,0xC0,0x54,0xA2,0x0B,0xC0,0xAC,0xCA,0x03,0x42,0x00,0x80,0xDC,0x09,0x01, ++ 0x40,0xBD,0x31,0x52,0x00,0x36,0x00,0x01,0x82,0xFC,0xC0,0xAC,0xCD,0xB4,0x82,0x01, ++ 0x82,0x4C,0xC2,0xAC,0x82,0x01,0x84,0x44,0xC0,0x74,0x4A,0x11,0x92,0x05,0x82,0x3C, ++ 0xC2,0x6C,0x92,0x05,0x83,0x34,0x82,0xBE,0x10,0x01,0x00,0x01,0x4C,0x4D,0xB1,0x4A, ++ 0x8F,0x2C,0x4A,0xF2,0xB2,0x4A,0x8C,0x24,0x48,0xE2,0xEF,0x48,0xB2,0x4A,0x8C,0x1C, ++ 0x04,0x08,0xC4,0x48,0x91,0x4D,0x66,0xA5,0xDB,0x74,0xA2,0x1A,0x62,0x8D,0xD9,0x6C, ++ 0xA2,0x1A,0xDB,0x24,0x9A,0x3C,0xD9,0x1C,0x9A,0x34,0xD9,0x2C,0x98,0x2C,0x41,0x09, ++ 0x89,0x5E,0xD8,0x3C,0x12,0xDA,0x92,0xDD,0x99,0x3C,0xD9,0x34,0x12,0xDA,0x92,0xDD, ++ 0x99,0x34,0xD9,0x2C,0x12,0xDA,0x92,0xDD,0x9A,0x2C,0xD9,0x5C,0x32,0xE2,0xDC,0x64, ++ 0x9A,0x64,0xD9,0x34,0xE1,0x3C,0xEA,0x34,0xCA,0xD8,0x92,0xDD,0xEB,0x3C,0xC9,0x20, ++ 0x91,0x25,0xF3,0x2C,0xED,0x64,0xC9,0x68,0xA8,0x64,0x59,0x01,0xD9,0x86,0xEB,0xD4, ++ 0x13,0x5A,0xD5,0x6E,0x63,0x01,0xD8,0x5E,0xED,0xCC,0x11,0x62,0xD1,0x46,0xEB,0x64, ++ 0xC5,0x6B,0x49,0x68,0x8B,0x06,0x32,0x2A,0x3F,0x01,0xF8,0x7A,0xEB,0x2C,0x01,0x68, ++ 0x23,0x62,0x35,0x32,0x2B,0x01,0xF8,0xAA,0xF5,0xDC,0x11,0xAA,0xEA,0xC6,0xF2,0xB4, ++ 0x71,0x09,0x88,0x16,0xD9,0xF0,0x93,0xB5,0xB2,0x9C,0xF8,0x5C,0x35,0x01,0xF8,0xF2, ++ 0x10,0x72,0xDD,0x06,0x35,0xAA,0x81,0x68,0x01,0x68,0x33,0x7A,0xF3,0x9C,0x10,0x6A, ++ 0x12,0xAA,0xE5,0x2E,0x6B,0xA5,0xA1,0x62,0x6B,0x8D,0xA1,0x5A,0x01,0xA8,0x72,0xBD, ++ 0xC9,0x68,0xE5,0x72,0xE1,0xB0,0xA3,0x72,0xEB,0xFC,0xE0,0x68,0x90,0x6D,0xAF,0xFC, ++ 0xF5,0x9C,0x10,0xBA,0xD1,0xBE,0x05,0x9F,0x09,0xEF,0x6A,0xA5,0xA1,0x62,0x6B,0x8D, ++ 0xA2,0x5A,0x03,0xB0,0x6B,0xBD,0xC9,0xA8,0xE3,0x72,0xE1,0xB0,0xA0,0x72,0xE9,0xFC, ++ 0xE7,0x68,0x93,0x6D,0xAD,0xFC,0x38,0x37,0xE9,0x64,0xC1,0x6B,0x48,0x68,0x6D,0x19, ++ 0x8A,0x6E,0x00,0xB0,0x7F,0xBD,0xC9,0xB0,0xE0,0xB2,0x71,0x09,0xC2,0x3E,0xC0,0x64, ++ 0x08,0x01,0xC6,0x03,0x1A,0x42,0xC8,0x64,0x82,0x43,0x80,0x7D,0xE8,0x85,0x6F,0x11, ++ 0x89,0x56,0x68,0xA5,0xA1,0x62,0x63,0x8D,0xA2,0x1A,0x03,0x98,0x4A,0xBD,0xC1,0xC8, ++ 0xE2,0x5A,0xE0,0xD8,0xA0,0x5A,0x00,0x1F,0xCA,0x4C,0xF2,0x4B,0x4F,0x51,0x90,0x66, ++ 0xE6,0x00,0x92,0x05,0x40,0x11,0x90,0x06,0x3A,0xD7,0xE2,0x90,0x90,0x95,0x56,0x21, ++ 0x92,0x06,0x38,0x57,0x01,0x01,0x80,0x6C,0xC0,0xB4,0x42,0x09,0x88,0xF6,0x03,0x01, ++ 0x80,0x84,0x01,0x01,0x81,0x7C,0xC9,0x84,0x42,0xBD,0x01,0x48,0xC2,0x40,0x80,0x14, ++ 0xC1,0x7C,0xC9,0x84,0x02,0x00,0xC4,0x00,0x91,0x05,0x86,0x54,0xCA,0x7C,0xC1,0x14, ++ 0xE0,0x2A,0x6A,0x09,0xC1,0x26,0xC0,0x6C,0xE6,0x00,0x92,0x05,0x87,0x6C,0x01,0x8F, ++ 0xC0,0x7C,0x41,0x09,0x89,0x16,0xC0,0x84,0x47,0x01,0x88,0xC6,0x08,0x81,0x41,0x45, ++ 0x86,0x1F,0xC0,0x77,0xC0,0x6C,0x82,0x3C,0xC0,0x74,0x82,0x34,0xC0,0x5C,0x82,0x0C, ++ 0xC0,0x64,0x82,0x04,0xC4,0x84,0xE1,0x00,0x3C,0x00,0x7C,0x00,0x50,0x5A,0xB4,0xA2, ++ 0xE8,0x98,0xB0,0xCA,0x31,0x62,0x74,0x4D,0xB1,0x8A,0xC1,0x84,0xB0,0x82,0x80,0x24, ++ 0xC0,0x84,0xB1,0xC2,0x81,0x1C,0xD0,0x84,0xB0,0x82,0x85,0x14,0xC0,0x7C,0x41,0x09, ++ 0x88,0x5E,0xC0,0x24,0x12,0x02,0x92,0x05,0x80,0x24,0xC0,0x1C,0x12,0x02,0x92,0x05, ++ 0x80,0x1C,0xC0,0x14,0x12,0x02,0x92,0x05,0x80,0x14,0x00,0x01,0x83,0x2C,0xE0,0x68, ++ 0xAD,0xF4,0x01,0x9F,0x40,0x61,0x98,0x66,0xC8,0x24,0xC0,0x34,0xD2,0x54,0xD1,0x00, ++ 0x4C,0xA5,0xA1,0x42,0xC8,0x1C,0xC0,0x3C,0xD2,0x54,0xD1,0x00,0x4C,0x8D,0xA1,0x42, ++ 0x00,0x47,0x15,0x01,0xDC,0x0C,0x00,0x28,0xF0,0xD2,0x5C,0x45,0x88,0xD2,0x12,0x01, ++ 0x90,0x74,0xD1,0x3C,0x92,0x95,0x92,0x0C,0xD2,0x34,0x90,0x95,0x91,0x04,0xD2,0x74, ++ 0x50,0x09,0x88,0x3E,0x12,0x12,0x93,0xA5,0x32,0x12,0x13,0x92,0x94,0x95,0x32,0xA2, ++ 0x12,0x4A,0x92,0x4D,0xD2,0x0C,0xDA,0x04,0xF0,0x0C,0x00,0x07,0x01,0xEF,0xB4,0x24, ++ 0xF1,0x04,0xB0,0x64,0x01,0x70,0xB2,0xFC,0x22,0x12,0x93,0x95,0xCA,0xD8,0x90,0xDD, ++ 0xF9,0x24,0xF1,0xFC,0xC9,0xB0,0xB7,0x24,0xF3,0x64,0xC1,0xB0,0xB0,0x64,0x51,0x01, ++ 0xD9,0xBE,0xF0,0xD4,0x10,0x92,0xD5,0xA6,0x58,0x01,0xD8,0x96,0xF5,0xCC,0x11,0x9A, ++ 0xD1,0x7E,0xF8,0x24,0x35,0x01,0xF8,0xF2,0xF9,0x64,0xC1,0xFB,0x48,0xF8,0x8D,0x46, ++ 0xFD,0xDC,0x11,0xF2,0xE8,0x2E,0x78,0x45,0xCD,0xFA,0xCB,0xF0,0x7B,0x45,0x88,0xF2, ++ 0x39,0xD7,0xD6,0x74,0xE6,0x90,0x92,0x95,0x91,0x74,0xD1,0x74,0x55,0x11,0x98,0xF6, ++ 0x41,0x01,0x80,0xF6,0xF2,0x10,0xF2,0x44,0x00,0x90,0x5C,0x45,0xC7,0xD2,0xCC,0xB3, ++ 0xCC,0xDA,0xCA,0xB0,0x11,0xF2,0x94,0x86,0xD0,0x2C,0x50,0x09,0x88,0x8E,0xD1,0x24, ++ 0xC1,0x34,0xD8,0x54,0xD1,0x00,0x54,0xA5,0xA0,0x82,0xDE,0x1C,0xD1,0x3C,0xE8,0x54, ++ 0xD1,0x90,0x5E,0x8D,0xA8,0xD2,0xEA,0x14,0xDA,0x04,0xD8,0xE8,0x36,0x1A,0xD3,0x90, ++ 0x90,0x95,0xDA,0x00,0x93,0x1D,0xD2,0x40,0x2C,0x01,0x30,0x01,0x50,0x01,0xD8,0x56, ++ 0xFD,0xD4,0x11,0xD2,0xD0,0x3E,0x58,0x01,0xD9,0x2E,0xF8,0xCC,0x10,0xDA,0xD5,0x16, ++ 0xC1,0x3B,0x18,0xBA,0x83,0x3B,0x20,0x12,0x90,0x95,0xCA,0xD8,0x92,0xDD,0xC2,0x00, ++ 0xE7,0x68,0x93,0x6D,0x6F,0x11,0xC8,0x4E,0x04,0xE7,0x10,0x9A,0x90,0x0E,0x10,0x09, ++ 0x90,0x2C,0xD8,0x24,0xD6,0x34,0xC0,0x90,0x90,0x95,0x96,0x34,0xD8,0x1C,0xD0,0x3C, ++ 0xC6,0x90,0x96,0x95,0x90,0x3C,0xD0,0x14,0xDA,0x0C,0x00,0x90,0xC0,0x90,0x96,0x0C, ++ 0xD8,0x14,0xD0,0x04,0xC0,0x90,0x96,0x04,0xE6,0x00,0x92,0x05,0xD4,0xF4,0x11,0x82, ++ 0x92,0x06,0x38,0x3F,0xC2,0x7C,0xE1,0x00,0x91,0x05,0x86,0x7C,0xC0,0x7C,0x41,0x11, ++ 0x97,0x06,0x30,0xAF,0xC2,0x84,0xE1,0x00,0x91,0x05,0x86,0x84,0xC0,0x84,0x41,0x21, ++ 0x97,0x06,0x30,0x37,0x00,0x0F,0x00,0x41,0x81,0x6C,0xC1,0x6C,0x41,0x41,0x88,0xD6, ++ 0x10,0x01,0x00,0x01,0x58,0x8A,0xE8,0xC8,0xB4,0xF2,0xB4,0x7A,0x31,0x8A,0x31,0xDA, ++ 0x40,0x09,0x88,0x1E,0x12,0x4A,0x92,0x4D,0x12,0xDA,0x92,0xDD,0xE7,0x6C,0xC2,0x18, ++ 0x92,0xDD,0xE2,0x74,0xC2,0x08,0x93,0x65,0x04,0x08,0xC4,0x48,0x90,0x4D,0x5E,0x01, ++ 0xD9,0x76,0xE8,0xD4,0x10,0x5A,0xD5,0x5E,0x60,0x01,0xD8,0x4E,0xED,0xCC,0x11,0x62, ++ 0xD1,0x36,0x68,0xA5,0xA1,0x62,0x63,0x8D,0xA0,0x1A,0x03,0x3F,0xE8,0x62,0x00,0x00, ++ 0x62,0xA5,0xD9,0x74,0xA1,0x1A,0x63,0x8D,0xDB,0x6C,0xA2,0x1A,0xE6,0x00,0x92,0x05, ++ 0x46,0x11,0x98,0x9E,0xE6,0x90,0x92,0x95,0x56,0x21,0x98,0x56,0x58,0x85,0xE1,0xC3, ++ 0xB0,0xC3,0xC8,0xC3,0x98,0xC3,0x00,0x01,0x81,0x04,0x59,0x85,0xE0,0xC3,0xB0,0xC3, ++ 0xC8,0xC3,0x98,0xC3,0x00,0x01,0x80,0xE4,0x80,0xEC,0x80,0xF4,0xC4,0xAC,0xCA,0x03, ++ 0x80,0xDC,0x01,0x01,0x08,0x01,0x78,0xA5,0x06,0x18,0xCE,0xD0,0x32,0xA2,0x04,0x20, ++ 0xC6,0x10,0x93,0x95,0x6D,0xA5,0xE1,0x72,0x33,0x2A,0xA3,0x72,0x6D,0x8D,0xE1,0x6A, ++ 0x32,0x12,0xC3,0x90,0x8A,0xAB,0xE0,0x48,0x90,0x4D,0x4E,0x19,0x98,0x86,0x47,0x09, ++ 0x80,0x0E,0x40,0x19,0x8F,0x66,0xE0,0xCA,0x33,0xE2,0x31,0x12,0xCB,0x93,0x30,0x2A, ++ 0xC7,0x6B,0xA5,0x2A,0x34,0x1A,0xCB,0xE3,0x8C,0xE3,0x80,0xCB,0x34,0x0A,0x8B,0x53, ++ 0x09,0x09,0x88,0x14,0x09,0x01,0x88,0x7C,0xD3,0x7C,0x31,0x0A,0xE1,0x4A,0xDC,0x7C, ++ 0x36,0x12,0xC3,0x90,0xCA,0x9B,0xC0,0xAB,0xC9,0x93,0x92,0x1C,0xD0,0x7C,0x51,0x01, ++ 0x88,0x16,0x41,0x01,0x80,0x0E,0x40,0x19,0x8D,0x5E,0x10,0x4A,0x98,0x4E,0x10,0x09, ++ 0x90,0x0C,0x41,0x01,0x8A,0x16,0xF0,0x10,0x90,0x14,0x01,0xF7,0x11,0x09,0x90,0x14, ++ 0x00,0xDF,0x40,0x09,0x80,0x0E,0x40,0x11,0x8D,0x5E,0x10,0x4A,0xC0,0x4E,0x10,0x09, ++ 0x90,0x0C,0x41,0x09,0x8C,0x16,0xF0,0x10,0x90,0x14,0x01,0x77,0x11,0x09,0x90,0x14, ++ 0x00,0x5F,0x10,0x01,0x90,0x0C,0x01,0x47,0x11,0x09,0x90,0x0C,0x40,0x11,0x90,0x16, ++ 0xF1,0x90,0x94,0x14,0x00,0x0F,0x10,0x09,0x90,0x14,0x41,0x01,0x80,0x0E,0x40,0x19, ++ 0x8D,0x0E,0x10,0x4A,0x90,0x2E,0x40,0x09,0x80,0x0E,0x40,0x11,0x8D,0x26,0x10,0x4A, ++ 0xC0,0x16,0x10,0x09,0x94,0x5C,0x01,0x8F,0x11,0x01,0x90,0x5C,0x01,0x77,0xD4,0xCC, ++ 0x32,0x3A,0x19,0xBA,0xD1,0xA4,0xF2,0xEC,0xC4,0xD0,0xCD,0x90,0x91,0x64,0xD1,0x64, ++ 0xC1,0x93,0x90,0xE4,0x31,0x90,0xA2,0xD6,0xF3,0xA4,0x02,0xD0,0xC9,0x90,0xF4,0x44, ++ 0x04,0xB0,0xCB,0x90,0x31,0x19,0x10,0xB0,0xC8,0xB0,0x14,0x21,0xF1,0x92,0xF5,0xDC, ++ 0x10,0x92,0xD5,0x26,0xF0,0x6C,0x71,0x41,0x88,0xC6,0x50,0x01,0xD9,0xB6,0xF0,0xE4, ++ 0x48,0xB0,0x87,0x06,0x80,0x90,0xF2,0xE4,0xC0,0xB0,0xB5,0xE4,0xF0,0x44,0xF9,0xF4, ++ 0x1F,0xB2,0xCA,0xB0,0xB0,0xF4,0xF0,0xEC,0x1C,0x12,0xCB,0x90,0x91,0xEC,0xD0,0x04, ++ 0xE4,0x90,0x92,0x95,0x91,0x04,0xD1,0xE4,0x48,0x90,0x8E,0xEE,0xD0,0x44,0xF2,0xFC, ++ 0xCD,0x93,0x12,0x92,0xC1,0x2E,0xD0,0xE4,0x31,0x01,0x1E,0x92,0xF1,0x64,0x81,0x93, ++ 0x01,0x47,0xD0,0xE4,0x31,0x01,0x1A,0x92,0xF1,0x64,0x81,0x93,0x01,0x17,0xD0,0x0C, ++ 0x50,0x09,0x80,0x4E,0xD0,0x0C,0x51,0x09,0x8A,0x36,0xD0,0x6C,0x10,0xA2,0x84,0x1E, ++ 0xD5,0x14,0xC1,0x10,0x95,0xA5,0x3A,0x57,0x10,0x4A,0x8D,0xDE,0xD4,0x1C,0x11,0x9A, ++ 0x89,0xC6,0xC8,0x7C,0xE6,0x48,0x92,0x4D,0x89,0x7C,0xC9,0x7C,0x48,0x11,0x90,0x06, ++ 0x3A,0x97,0xE2,0x00,0x90,0x05,0x46,0x21,0x91,0x06,0x38,0x1F,0xC2,0x4C,0xF2,0x03, ++ 0x42,0x01,0x88,0x5E,0xC9,0xAC,0x8A,0x01,0xD8,0x43,0x36,0x10,0xAA,0x36,0x31,0x00, ++ 0x71,0x00,0x04,0x27,0xD0,0x5C,0x51,0x01,0x8D,0x5E,0x10,0x4A,0xCA,0x16,0xF0,0x48, ++ 0x90,0x4D,0x06,0x1F,0x10,0x4A,0x95,0x0E,0xE6,0x48,0x92,0x4D,0x11,0x09,0x90,0x5C, ++ 0x01,0x67,0xD0,0x1C,0x10,0x9A,0xCC,0x16,0xF6,0xD8,0x92,0xDD,0x01,0x27,0xD0,0x1C, ++ 0x10,0x9A,0x94,0x0E,0xE6,0xD8,0x92,0xDD,0x11,0x01,0x90,0x5C,0x91,0x55,0x92,0x44, ++ 0x97,0xE5,0x72,0xFA,0xD4,0x44,0xC9,0x90,0x93,0xEC,0x39,0x47,0x02,0x01,0xD0,0xAC, ++ 0x6C,0x94,0x12,0x12,0x9A,0xD6,0xC0,0xAC,0xE4,0x4B,0x68,0x04,0x10,0x42,0x9C,0x26, ++ 0xC4,0x44,0xCA,0x03,0xF6,0x00,0x94,0x05,0x02,0x1F,0xC0,0x44,0xCC,0x03,0xE4,0x00, ++ 0x91,0x05,0xCE,0x04,0x10,0x0A,0x9C,0x4E,0xC0,0xAC,0x0A,0x01,0xB2,0x0B,0xC4,0x54, ++ 0x08,0xD9,0xE7,0x03,0x02,0x42,0xC8,0x54,0xA2,0x43,0x28,0x37,0x27,0x01,0x30,0xF9, ++ 0xB0,0x09,0x60,0x01,0x8A,0x4E,0xC0,0x3C,0xC8,0xCC,0xF9,0xF4,0xD2,0x54,0x42,0x93, ++ 0x97,0x9C,0x50,0x42,0xDE,0x74,0xB2,0xAA,0x02,0x47,0xC0,0x34,0xC8,0xD4,0xF9,0xEC, ++ 0xD4,0x54,0x42,0x93,0x97,0x9C,0x50,0x22,0xDE,0x6C,0xB2,0xAA,0x40,0x01,0x80,0x16, ++ 0xF4,0x48,0x12,0x42,0x8A,0x8E,0xD0,0x74,0x96,0x04,0x90,0x05,0x32,0x0A,0xD9,0x6C, ++ 0xD7,0x5C,0xBA,0xEF,0xD1,0x77,0x37,0x8A,0x10,0x82,0xED,0x0E,0x30,0x42,0x00,0x17, ++ 0x40,0x01,0xD0,0x06,0x02,0x01,0xC8,0x28,0x04,0x07,0xA8,0x01,0x10,0xC0,0xC9,0xE4, ++ 0x81,0x17,0xF0,0x47,0xCA,0x9C,0xC8,0x00,0x18,0x42,0x42,0x01,0xD0,0x06,0x00,0x01, ++ 0xA0,0x00,0x60,0x01,0x8A,0x7E,0xC8,0x54,0x44,0x4C,0x10,0x0A,0xD0,0x06,0x30,0x42, ++ 0xC8,0xAC,0x12,0x31,0xF2,0x4B,0x1C,0x8A,0xD4,0xA4,0xC2,0x48,0x12,0x19,0x0A,0x90, ++ 0xC4,0x48,0x0C,0x44,0x02,0x77,0xC8,0x54,0x44,0x4C,0x12,0x0A,0xD0,0x06,0x30,0x42, ++ 0xC8,0xAC,0x12,0x31,0xF2,0x4B,0x1C,0x8A,0xD4,0xA4,0xC2,0x48,0x12,0x19,0x0A,0x90, ++ 0xC6,0x48,0x0C,0x44,0xE7,0x20,0x93,0x25,0x65,0x09,0xC8,0x16,0xC0,0xAC,0x12,0x31, ++ 0xD8,0x0B,0xC6,0xE4,0x02,0x42,0xCE,0xAC,0xF2,0x4B,0x1C,0x8A,0xD4,0xA4,0xC2,0x48, ++ 0x12,0x19,0x0A,0x90,0xC0,0x48,0x14,0x44,0xC2,0xAC,0xCA,0x74,0xF2,0x03,0x04,0x10, ++ 0xC0,0xA4,0xC2,0x90,0x04,0x09,0x09,0x00,0xC0,0x90,0xB0,0x8B,0xCA,0xAC,0xD2,0x6C, ++ 0xF2,0x4B,0x04,0x58,0xCA,0xA4,0xC2,0xC8,0xC2,0x40,0xB0,0x13,0xC2,0xAC,0xCA,0xAC, ++ 0xF2,0x03,0xE4,0x00,0xB6,0x43,0x24,0x07,0xAC,0xFD,0x87,0xDD,0xF4,0x24,0x31,0xB2, ++ 0x33,0xFA,0xD8,0x83,0x81,0x94,0xD8,0x83,0x81,0x8C,0xC8,0x83,0x80,0x84,0x00,0x01, ++ 0x85,0x6C,0x40,0x32,0x41,0x0B,0x32,0x82,0x80,0x01,0x85,0xD4,0x48,0x01,0x80,0x1E, ++ 0xC2,0x84,0x40,0x00,0x80,0x74,0x00,0x67,0xC2,0xD4,0xF0,0x03,0x40,0x51,0x98,0x26, ++ 0xC8,0xD4,0x00,0xD9,0xB0,0x42,0x80,0x74,0x00,0x1F,0xC8,0xD4,0x00,0xD1,0xB0,0x42, ++ 0x86,0x74,0x08,0x09,0x03,0x48,0xC4,0xC8,0xC0,0xDC,0x88,0xCC,0x41,0x01,0x80,0xEE, ++ 0x04,0x29,0x04,0x00,0xC1,0xD8,0x31,0xCA,0x89,0xF9,0x8F,0x29,0xE0,0xCC,0xC0,0x84, ++ 0x42,0x00,0x12,0x02,0x90,0x05,0x82,0x6C,0x04,0x01,0x30,0x22,0x00,0x8F,0x00,0x01, ++ 0x00,0x47,0xC0,0xEB,0xC5,0x53,0xD0,0x68,0x05,0x2C,0xE1,0x20,0xE2,0xD8,0xE2,0x48, ++ 0xE6,0x00,0x92,0x05,0xED,0x8C,0x10,0x42,0x9B,0x9E,0x37,0x02,0xE6,0x00,0x92,0x05, ++ 0x30,0x22,0xC4,0x94,0x2F,0x22,0x9C,0x56,0x30,0x82,0x43,0x01,0x84,0x06,0x38,0x02, ++ 0x06,0xC9,0x07,0x00,0xC7,0xD8,0x01,0xF9,0x01,0x00,0xC6,0xC0,0x4B,0x02,0xC4,0xC8, ++ 0x10,0x01,0x00,0x47,0x40,0x24,0x40,0x6C,0xD8,0x20,0x03,0xE4,0xE4,0xD8,0xE4,0x00, ++ 0xE2,0x48,0xE4,0x90,0x90,0x95,0xE6,0x8C,0x17,0x12,0x9D,0x9E,0x41,0xA2,0xC3,0xC0, ++ 0x80,0x64,0xE8,0xCC,0x00,0x01,0x80,0x9C,0x34,0x82,0x81,0x01,0x83,0xC4,0xC0,0x01, ++ 0x85,0xBC,0x80,0x01,0x85,0xB4,0x08,0x8F,0x25,0x01,0x08,0x3F,0xC0,0x64,0xC0,0x03, ++ 0x4B,0x00,0x8C,0xF6,0xF0,0x42,0xC9,0x84,0x13,0x42,0xDC,0xD6,0xC3,0x8C,0x30,0x5A, ++ 0x01,0x00,0xD2,0x48,0x31,0x52,0xD0,0x01,0x5C,0x94,0x1E,0xD4,0x46,0x54,0x18,0xD4, ++ 0x40,0x4C,0x22,0xCC,0x31,0x4A,0xC9,0x01,0x5A,0x4C,0x26,0xCC,0x44,0x4C,0x21,0xCC, ++ 0x46,0x4C,0x23,0xCC,0xC8,0x08,0x32,0x52,0xD6,0x01,0x59,0x94,0x29,0xD4,0xD0,0x42, ++ 0x2A,0xC4,0x42,0x44,0x28,0xC4,0x44,0x3D,0x60,0x01,0x88,0x66,0x0C,0x01,0x18,0xCC, ++ 0x20,0xCC,0x2A,0xCC,0x10,0xCC,0x0C,0xF9,0x0B,0x48,0xC4,0xC8,0x4E,0x54,0x10,0xD4, ++ 0x48,0x4C,0x1A,0xCC,0x00,0x87,0xC9,0x8C,0xF4,0x48,0x12,0x62,0x88,0xC6,0x10,0x01, ++ 0x30,0x5A,0x23,0xD4,0x24,0xD4,0x2E,0xD4,0xD0,0x8C,0x18,0xF9,0xF2,0x90,0x04,0x90, ++ 0xCC,0x90,0x0E,0xD8,0xC0,0x90,0x4E,0x94,0x34,0x5A,0x13,0xD4,0x06,0x48,0xCA,0x50, ++ 0x0C,0xF9,0x08,0x48,0xC0,0x88,0x4A,0x4C,0x10,0xCC,0x0E,0x01,0x18,0xCC,0x00,0x9F, ++ 0xF2,0x08,0x03,0x48,0xC8,0x50,0x0E,0xF9,0x0A,0x48,0xC4,0x90,0x4B,0x94,0x30,0x5A, ++ 0x13,0xD4,0x04,0x10,0xCA,0x90,0xC6,0x90,0x4E,0x94,0x10,0xD4,0xE2,0x10,0x03,0x90, ++ 0xCA,0x90,0xC6,0x88,0x48,0x4C,0x18,0xCC,0xC8,0x9C,0x48,0x01,0x8B,0x26,0x30,0x5A, ++ 0x1E,0xCC,0x1C,0xCC,0x20,0xCC,0x00,0x4F,0xC8,0x94,0xD0,0x9C,0xF4,0x48,0x12,0x52, ++ 0x88,0x26,0x08,0x01,0x30,0x5A,0x2B,0xCC,0x2C,0xCC,0x2A,0xCC,0x0B,0x01,0xF0,0x4A, ++ 0x33,0x62,0x34,0x5A,0x14,0xE1,0xF0,0xD2,0x10,0x52,0xE4,0x16,0x14,0xF1,0xF0,0xD2, ++ 0x04,0x07,0x00,0x07,0x13,0x52,0xD4,0xF6,0x14,0x01,0xF1,0xD2,0x17,0x52,0xD4,0xD6, ++ 0x14,0x11,0xF1,0xD2,0x17,0x52,0xE4,0x86,0x14,0x31,0xF1,0xD2,0x17,0x52,0xD4,0x96, ++ 0x14,0x41,0xF1,0xD2,0x17,0x52,0xD4,0x76,0x14,0x51,0xF1,0xD2,0x17,0x52,0xE4,0x26, ++ 0x14,0x61,0xF1,0xD2,0x17,0x52,0xE4,0x06,0xCA,0xC4,0xE0,0x4B,0x4B,0x01,0x80,0xCE, ++ 0x0C,0x01,0x30,0x72,0x88,0x14,0x88,0x1C,0x88,0x7C,0x10,0x01,0xC8,0xDC,0x48,0x01, ++ 0x88,0x96,0x8B,0x24,0x1E,0x01,0xF0,0x1A,0xE8,0xC8,0xD2,0x36,0xC0,0xC8,0x94,0x55, ++ 0xCA,0x1C,0xE0,0x48,0x90,0x4D,0x8E,0x1C,0x00,0x2F,0x58,0x51,0xE8,0x1E,0xC8,0x14, ++ 0xE6,0x48,0x92,0x4D,0x8C,0x14,0xE0,0x00,0xCA,0x24,0xE0,0x48,0x90,0x4D,0x8E,0x24, ++ 0xC8,0x24,0x48,0x49,0x9B,0x36,0x37,0x02,0xC0,0x00,0x94,0x05,0xD5,0xBC,0x68,0x8C, ++ 0xE4,0x93,0x10,0x8A,0x98,0x0E,0xC9,0x74,0x10,0x42,0xD4,0xF6,0xC8,0x14,0x48,0x39, ++ 0x98,0x8E,0xC8,0x74,0x84,0x48,0x12,0x0A,0xD8,0xBE,0xC0,0x1C,0x40,0x01,0x00,0x4F, ++ 0x30,0x20,0x06,0x00,0xE0,0xD2,0x07,0x00,0xE0,0xD2,0x06,0x00,0x58,0x80,0x04,0x01, ++ 0x40,0x40,0x01,0x00,0x88,0x4E,0xC0,0xD4,0xF0,0x03,0x42,0x11,0x98,0x0E,0x00,0x09, ++ 0x37,0x32,0x4C,0xFA,0xC2,0x43,0xE2,0x00,0x80,0x43,0xC2,0xC4,0xE0,0x03,0x40,0x01, ++ 0x83,0xFE,0x30,0x82,0x40,0x01,0x88,0xE6,0xC2,0xD4,0xF0,0x03,0x40,0x51,0x98,0xC6, ++ 0x30,0x5A,0x03,0xB1,0x08,0x91,0xF1,0xC2,0xF4,0x8A,0x13,0x42,0xD8,0x5E,0x08,0xA1, ++ 0xF2,0xCA,0x82,0x48,0x04,0x07,0x00,0xDF,0x10,0x42,0xDC,0x26,0x0A,0xC1,0xF0,0xCA, ++ 0x84,0x48,0x12,0x42,0xD0,0x2E,0x00,0x09,0x37,0x32,0x4C,0x6A,0xC2,0x43,0xE2,0x00, ++ 0x87,0x43,0x52,0x5A,0xC0,0x83,0x40,0x81,0x97,0x16,0x4A,0x52,0xA2,0x62,0xE0,0x00, ++ 0x81,0x83,0x00,0xEF,0x07,0x57,0x3A,0xFF,0x30,0x1A,0x9B,0x04,0x83,0xC8,0x24,0x0A, ++ 0x90,0x4D,0x88,0x0C,0x08,0x01,0x88,0x24,0xCA,0x6C,0x80,0x48,0x88,0xAC,0x18,0x01, ++ 0xF0,0x1A,0xCE,0xAC,0x9C,0xA4,0x10,0x5A,0xD0,0x6E,0xD8,0xA4,0xCA,0x04,0xC0,0xC8, ++ 0x90,0x4D,0x88,0x04,0xD8,0xA4,0xC8,0x6C,0x10,0x5A,0xD4,0x26,0x32,0x1A,0x83,0xC8, ++ 0x20,0x0A,0x93,0x4D,0x88,0x0C,0xC8,0xA4,0xC0,0x48,0x94,0x55,0xE0,0x00,0xCC,0x24, ++ 0xE6,0x48,0x92,0x4D,0x88,0x24,0xC8,0x24,0x4F,0x49,0x98,0x06,0xC4,0x0C,0x10,0x12, ++ 0xD8,0x66,0xC8,0x74,0xC4,0x04,0x10,0x42,0xD8,0x46,0xC0,0xC4,0xE0,0x03,0x40,0x01, ++ 0x83,0x36,0x30,0x5A,0x00,0xB1,0xF0,0xC2,0x40,0x01,0xD0,0x0E,0x04,0x09,0x30,0x32, ++ 0xC2,0xD4,0xF0,0x03,0x40,0x51,0x98,0x16,0xC0,0xDC,0x40,0x01,0x80,0x46,0x00,0x09, ++ 0x30,0x8A,0x4B,0x01,0x80,0x06,0x00,0x01,0x80,0x7C,0x00,0x0F,0x00,0x09,0x80,0x7C, ++ 0xC0,0x7C,0x40,0x01,0x80,0xA6,0x01,0x09,0xB5,0x83,0x47,0xFA,0x40,0x03,0x42,0x01, ++ 0x88,0x5E,0xC0,0xD4,0xF0,0x03,0x42,0x51,0x90,0x3E,0xC0,0xBC,0x6E,0x8C,0xDB,0x03, ++ 0x32,0x00,0x72,0x00,0x84,0x51,0x10,0x0A,0xC8,0x0E,0x10,0x01,0x00,0x07,0x10,0x09, ++ 0xC0,0xE4,0x40,0x01,0x80,0x06,0x10,0x11,0x91,0x14,0x30,0x1A,0xB8,0x04,0xB0,0x0C, ++ 0x30,0x42,0xD1,0x9C,0xCF,0x64,0xB8,0xFF,0xC8,0x5F,0xC7,0xB4,0xE2,0x03,0x38,0x00, ++ 0xAD,0x1E,0xF0,0x83,0xFC,0x8B,0x13,0x42,0x98,0x56,0xC0,0xB4,0xE2,0x03,0x38,0x00, ++ 0xA7,0x26,0x00,0xF1,0xA8,0x83,0xC9,0xB4,0x04,0x01,0xA0,0x43,0x87,0xFD,0xE8,0x85, ++ 0xE0,0x68,0xC5,0x64,0xE0,0x00,0x82,0x64,0xE7,0x20,0x93,0x25,0xC4,0x8C,0x10,0x22, ++ 0x92,0x06,0x30,0x9F,0xC2,0x9C,0xE0,0x00,0x90,0x05,0x86,0x9C,0xC8,0x94,0xC0,0x9C, ++ 0x10,0x42,0x94,0x06,0x37,0x47,0x3A,0x4F,0xAC,0x9D,0x87,0x3D,0x30,0x3A,0xC0,0x44, ++ 0xD0,0x03,0x84,0x24,0xC6,0x44,0xD0,0x23,0x41,0xC2,0xC4,0xE8,0x06,0xF9,0x07,0x00, ++ 0xC0,0xF0,0xC1,0x44,0x08,0xF1,0xE8,0x03,0x84,0x17,0xD8,0xA7,0x04,0x29,0x04,0x00, ++ 0xC4,0xD0,0x41,0x9A,0x37,0xDA,0x99,0xF9,0xC1,0xC0,0x99,0x29,0x80,0x34,0x48,0xE9, ++ 0x88,0xDE,0x08,0x01,0x00,0x5F,0x00,0x01,0x00,0x2F,0xC0,0xFB,0x82,0xBB,0xE0,0x90, ++ 0xE2,0xD8,0xE2,0x00,0x95,0x05,0x16,0x02,0x9A,0xBE,0xE7,0x48,0x90,0x4D,0xC6,0x24, ++ 0x17,0x0A,0x9C,0x86,0x00,0x01,0x00,0x2F,0x41,0x8C,0x01,0x4C,0xE5,0x68,0xE5,0xB0, ++ 0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0xBE,0x00,0xCF,0xC3,0x44,0x82,0x01,0xF5,0x03, ++ 0x43,0x51,0x98,0xA6,0xC4,0x44,0xF0,0x03,0x80,0x2C,0x40,0x01,0x80,0x7E,0x9B,0x1C, ++ 0xF3,0x34,0x08,0x21,0x1B,0x01,0x00,0x21,0x30,0x32,0x04,0x01,0x30,0x22,0x84,0x14, ++ 0x29,0x01,0x00,0x1F,0x00,0x01,0x80,0x0C,0x01,0x97,0xC0,0xBB,0x48,0xF8,0x85,0x66, ++ 0x10,0x0A,0xCC,0x0E,0x30,0x0A,0x00,0x17,0x10,0x1A,0x94,0x06,0x30,0x1A,0xF8,0x14, ++ 0xE7,0xF8,0x93,0xFD,0xB8,0x14,0x38,0x09,0xBB,0x0C,0xE0,0xB0,0xE6,0x00,0x92,0x05, ++ 0x17,0x02,0x9D,0x56,0xC0,0x0C,0x40,0x01,0x85,0x36,0x28,0x72,0xCD,0x0E,0x30,0x72, ++ 0x05,0x17,0x28,0x62,0x95,0x06,0x30,0x62,0xE7,0x68,0x93,0x6D,0xC4,0x24,0x10,0x2A, ++ 0x98,0xC6,0xC6,0x2C,0x2B,0x51,0x18,0x42,0xED,0x14,0x10,0x42,0xC8,0xB6,0x48,0x01, ++ 0x82,0x0E,0xF0,0x48,0x93,0x4D,0xF6,0x00,0x10,0x1A,0xD4,0x0E,0xE6,0xD8,0x92,0xDD, ++ 0x30,0x82,0x43,0x01,0x82,0x16,0xF0,0x00,0x94,0x05,0x36,0x32,0xEB,0x24,0xF0,0x68, ++ 0x28,0x62,0xD5,0x1E,0x32,0x02,0xE3,0x00,0x94,0x05,0x36,0x22,0x28,0x01,0x00,0xDF, ++ 0x00,0x01,0x00,0xAF,0x10,0x42,0x9C,0x2E,0x28,0xAA,0x9B,0x1E,0x10,0xC2,0xC4,0x0E, ++ 0x28,0x2A,0xCB,0x3E,0xC1,0xB3,0x08,0xB8,0xD8,0xF8,0xF5,0x1C,0xC7,0xB3,0xC9,0xB0, ++ 0x48,0xB0,0x81,0xB3,0xE0,0x90,0xF2,0x1C,0xE0,0xB0,0xB3,0x1C,0xE6,0x00,0x92,0x05, ++ 0x17,0x02,0x9D,0x3E,0xE7,0x68,0x93,0x6D,0xC4,0x24,0x10,0x2A,0x98,0x06,0xC7,0x34, ++ 0x10,0x01,0x00,0x67,0x08,0x01,0x00,0x37,0xC4,0x1B,0x30,0xD8,0x70,0xD8,0x84,0x1B, ++ 0xE2,0x00,0xE2,0x48,0x95,0x4D,0x16,0x0A,0x9A,0xB6,0xE7,0x90,0x90,0x95,0xCE,0x24, ++ 0x17,0x52,0x9C,0x7E,0x87,0x4D,0xE8,0x85,0xAC,0xFD,0x87,0x1D,0x30,0x2A,0x30,0x62, ++ 0x05,0x01,0xB0,0x03,0xB1,0x03,0x37,0x02,0x80,0x01,0xE6,0x0B,0x10,0xE9,0x07,0x52, ++ 0x3E,0x48,0x7A,0x48,0x00,0x48,0x1A,0x52,0xA0,0x13,0xE0,0x0B,0x10,0xD9,0x07,0x8A, ++ 0xA1,0x0B,0x30,0x02,0x80,0x01,0x84,0x14,0xE1,0x03,0x7A,0x4A,0x40,0x01,0x80,0x56, ++ 0x01,0x01,0x50,0x42,0x08,0xF9,0xA7,0x8A,0xE6,0x00,0x92,0x05,0x47,0x81,0x98,0xD6, ++ 0x01,0x01,0x80,0xC3,0x80,0xC3,0xA3,0x04,0x30,0x5A,0x01,0x01,0xD0,0x34,0xC8,0x2C, ++ 0xBE,0xFF,0xE7,0xD7,0x35,0x32,0xB1,0x01,0xF0,0x83,0x43,0x51,0x98,0x36,0xA0,0x04, ++ 0x30,0x5A,0x01,0x09,0xD0,0x34,0xC8,0x2C,0xBE,0xFF,0xE7,0x77,0xC2,0x14,0xE0,0x03, ++ 0x43,0x01,0x80,0xF6,0x45,0xB2,0xF0,0x0B,0xC2,0x03,0x02,0x00,0x10,0x0A,0xCC,0x1E, ++ 0x48,0x9A,0x00,0x01,0x81,0x43,0x02,0xDF,0x48,0x8A,0xC0,0x43,0x30,0x22,0x44,0x21, ++ 0xC0,0xB6,0x01,0x01,0x00,0x8F,0x59,0x7A,0xE7,0xCA,0x48,0xF9,0x80,0x5E,0x11,0x01, ++ 0xE6,0x08,0x92,0x4D,0x00,0x97,0x78,0x5A,0xE3,0xDA,0xE1,0xFA,0xDA,0xD8,0xE6,0xD8, ++ 0x58,0x11,0xC0,0x4E,0x5A,0x32,0xC0,0xD3,0x50,0x01,0x80,0x0E,0xF2,0x90,0x82,0xD3, ++ 0x5F,0x22,0x10,0xF9,0xA0,0xD2,0x10,0x09,0xE6,0x48,0x92,0x4D,0x28,0x0A,0x03,0x4F, ++ 0x00,0xA0,0x00,0x01,0x58,0x00,0x04,0x01,0x58,0x80,0x04,0x01,0x40,0x40,0x01,0x00, ++ 0x30,0x20,0x06,0x00,0x98,0xFE,0x56,0x09,0x8B,0x2E,0x50,0x42,0xC0,0x8B,0x4A,0x01, ++ 0x82,0x0E,0xF0,0x48,0x82,0x8B,0xE2,0x00,0x93,0x05,0x7E,0x22,0x2E,0x02,0x9B,0x56, ++ 0x08,0x01,0xC0,0x14,0xE1,0x1B,0x32,0x02,0x80,0x01,0x59,0x09,0x8A,0x2E,0x50,0xFA, ++ 0xC0,0x93,0x52,0x01,0x80,0x9E,0x08,0x09,0x02,0x8F,0x50,0xE2,0xC0,0x93,0x52,0x01, ++ 0x8E,0x46,0xD8,0x3B,0x6B,0x14,0x33,0xF8,0x75,0xF8,0x13,0xD2,0x9F,0x3E,0xF0,0x13, ++ 0x50,0x01,0x88,0x26,0x68,0x14,0xE5,0x3B,0x10,0xD2,0x9D,0x06,0x08,0x09,0x48,0x01, ++ 0x83,0x2E,0xF0,0x8B,0x48,0x01,0x95,0x3E,0xE3,0x48,0xB2,0x8B,0x03,0x27,0xF0,0x8B, ++ 0x48,0x51,0x90,0x0E,0x0B,0x01,0xB0,0x8B,0xF0,0x8B,0x4B,0x51,0x9A,0x0E,0x51,0x5A, ++ 0xC0,0x93,0x52,0x01,0x8D,0x8E,0xF0,0x3B,0x78,0x01,0x88,0x76,0x58,0x09,0x88,0x26, ++ 0x00,0x07,0x00,0xB7,0xF3,0x48,0xB2,0x8B,0x06,0x3F,0xD8,0x03,0x6A,0x1C,0x33,0x00, ++ 0x74,0x00,0x14,0x1A,0x92,0x0E,0xF0,0x48,0xB0,0x8B,0x53,0x11,0x9D,0x16,0x00,0x01, ++ 0xB0,0x83,0x03,0x37,0x50,0x09,0x88,0x26,0xF2,0x83,0x43,0x81,0x93,0x0E,0x00,0x21, ++ 0xB5,0x83,0xF3,0x0B,0x4B,0x09,0xC8,0x5E,0x07,0x01,0xD0,0x13,0x90,0x04,0x10,0x01, ++ 0x02,0xA7,0x00,0x98,0xC9,0xF0,0x1A,0x09,0x0F,0xD8,0xC4,0x98,0xF0,0xF3,0xF2,0xDB, ++ 0xFA,0x04,0x00,0xD8,0x1B,0xF2,0x03,0xB0,0xCF,0xB0,0xC3,0x98,0x31,0x19,0x10,0xB0, ++ 0xCC,0xD8,0x44,0xDC,0xC4,0xC0,0x90,0x05,0xE6,0x90,0x92,0x95,0x17,0x8A,0xC4,0x46, ++ 0x87,0x17,0xC8,0x47,0x40,0x00,0x82,0x0C,0xC8,0x0B,0xC1,0x0C,0x12,0x0A,0x94,0x3E, ++ 0x0A,0x01,0x00,0x17,0x02,0x40,0xCA,0x10,0x04,0x09,0x09,0x00,0xC2,0x80,0xF0,0x13, ++ 0xF0,0x03,0xD8,0x04,0x02,0x00,0x1A,0xD2,0x02,0x90,0xCA,0x90,0xC0,0x80,0x10,0x19, ++ 0x14,0x90,0xC0,0x10,0x00,0x21,0xF0,0x82,0xD4,0x0C,0x10,0x82,0xD0,0x5E,0x31,0x42, ++ 0x02,0x17,0xE1,0x10,0x36,0xA2,0x94,0x95,0x01,0x98,0x3A,0x09,0xCD,0xD8,0x0A,0xF8, ++ 0xCA,0xD8,0x06,0x30,0x33,0xF2,0xCC,0xB0,0xF7,0xDB,0xC8,0xB0,0xB3,0x9B,0x31,0x9A, ++ 0xF3,0xDB,0xB2,0x9B,0x1A,0x31,0x18,0xD2,0x3A,0x19,0xCA,0x90,0x08,0xF8,0x33,0x31, ++ 0xCB,0x90,0x1E,0x82,0xCC,0x00,0x4A,0x9C,0xCC,0x00,0x0E,0x1C,0x4E,0x9C,0x0E,0x1C, ++ 0x50,0x94,0x10,0x14,0x36,0x12,0x93,0x85,0xF2,0x13,0xF5,0x90,0x16,0x12,0xE4,0xC6, ++ 0xF2,0x03,0xF5,0x00,0xB2,0x03,0xE5,0x48,0x95,0x4D,0xF6,0x03,0x15,0x42,0xC4,0xCE, ++ 0x31,0x0A,0x31,0x42,0xBF,0xFF,0xEF,0x87,0x87,0x3D,0xE8,0x85,0x00,0xA0,0x00,0x01, ++ 0xAC,0xFD,0x87,0x2D,0xE0,0x74,0x00,0x01,0x80,0x1C,0xC0,0x3C,0xD0,0x33,0xC6,0x3C, ++ 0x58,0x04,0x86,0x0C,0xC3,0x34,0x18,0x82,0x50,0xFA,0xCF,0x2C,0xC2,0x48,0xC4,0x08, ++ 0x8F,0x24,0x40,0xF2,0xC0,0x03,0x40,0x09,0x88,0x0E,0xC0,0x3C,0xD8,0x33,0x04,0x01, ++ 0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0x17,0x82,0x9D,0xCE, ++ 0x08,0x01,0x00,0x09,0xD8,0x44,0xD0,0x34,0x86,0x07,0xD0,0x6F,0x28,0x01,0x60,0x01, ++ 0x8B,0x0E,0xE0,0x68,0x90,0x6D,0xFF,0x24,0x08,0x01,0x00,0x5F,0xC1,0xC3,0x19,0x02, ++ 0x91,0x05,0x86,0xC3,0xD4,0x7C,0x10,0x82,0xCD,0x0E,0x18,0x02,0x83,0xC3,0xE1,0xF8, ++ 0xE6,0x48,0x92,0x4D,0x17,0x8A,0x9D,0x8E,0x08,0x09,0xC6,0x2C,0x02,0x48,0xC4,0x00, ++ 0x80,0x14,0xD0,0x44,0x90,0x04,0x00,0x11,0xD8,0x3C,0xD0,0x2C,0xC8,0x34,0x80,0x07, ++ 0xD8,0x07,0xD0,0x44,0xC0,0x3C,0x90,0x04,0x82,0x01,0xCA,0x0B,0x00,0x01,0x1C,0x0A, ++ 0x10,0x01,0xD8,0x3C,0xC0,0x14,0x80,0x0F,0xDD,0xCF,0xDD,0xC0,0x09,0x01,0x00,0x3F, ++ 0xD0,0x14,0x18,0x01,0xF0,0x9A,0xD6,0x0C,0xD0,0xD0,0x94,0x95,0x68,0x01,0x88,0x2E, ++ 0x50,0xC1,0xE8,0xBE,0xC5,0x13,0x18,0x12,0x80,0x13,0x00,0x9F,0x50,0x99,0xE8,0x2E, ++ 0xC0,0x13,0x50,0x01,0x82,0x16,0xF0,0x90,0x80,0x13,0x00,0x5F,0x68,0x29,0x88,0x4E, ++ 0x58,0xE1,0xEE,0x3E,0xC0,0x13,0x50,0x01,0x88,0x26,0xD0,0x1C,0x50,0x01,0x88,0x0E, ++ 0x10,0x09,0x90,0x1C,0xD4,0x14,0xE0,0x90,0x92,0x14,0xE0,0x00,0xE6,0x48,0x92,0x4D, ++ 0x16,0x8A,0x9D,0xAE,0x40,0x20,0x6B,0x21,0xC8,0x0E,0xD5,0x44,0x90,0x04,0x08,0x01, ++ 0x00,0x19,0xD8,0x3C,0xD0,0x2C,0x80,0x07,0xD0,0xE7,0x0D,0x09,0x30,0x42,0xD8,0x44, ++ 0xD0,0x34,0x80,0x07,0xD0,0x07,0xC3,0x1C,0x87,0x4D,0xE8,0x85,0xAC,0xFD,0x87,0x1D, ++ 0xF0,0x64,0x30,0x7A,0x37,0xEA,0xD0,0xC3,0x86,0x14,0x08,0x09,0xC4,0x1C,0x00,0x48, ++ 0xC5,0x20,0x42,0xB2,0xC0,0x03,0x40,0x09,0x8D,0x0E,0xD8,0xC3,0x80,0x14,0x08,0x01, ++ 0x00,0x09,0xD8,0x2C,0xD0,0x6C,0x80,0x07,0xD0,0x37,0xD2,0x2C,0x91,0x04,0x30,0xDA, ++ 0x00,0x11,0xD0,0x1C,0xC8,0x6C,0x80,0x07,0xD0,0xA7,0xD4,0x2C,0x92,0x04,0x00,0x29, ++ 0xEC,0x0A,0x06,0x01,0x19,0x0A,0x30,0xDA,0x11,0x01,0x30,0x02,0x82,0x0F,0xD8,0x77, ++ 0xD0,0x2C,0x90,0x04,0x30,0xDA,0x09,0x01,0x00,0x19,0xD0,0x1C,0x84,0x07,0xD0,0x0F, ++ 0x08,0x09,0x30,0x42,0xD8,0x2C,0xD0,0x6C,0x81,0x07,0xD0,0x2F,0x41,0x02,0x05,0x44, ++ 0x01,0x01,0x00,0x84,0x08,0x01,0x00,0x77,0x01,0x01,0xF0,0x02,0x15,0x01,0xF0,0x52, ++ 0x10,0x12,0xEC,0x06,0x00,0x44,0x11,0x01,0xF4,0x92,0x15,0x12,0xD1,0x06,0x00,0x84, ++ 0xE2,0x20,0xE5,0x48,0x90,0x4D,0xC6,0x14,0x17,0x0A,0x9C,0x6E,0x87,0x3D,0xE8,0x85, ++ 0xAC,0xBD,0x87,0x45,0xC2,0x4C,0xD8,0x03,0x80,0x1C,0xC8,0x4C,0xD0,0x4B,0x8E,0x14, ++ 0x50,0x6A,0xCC,0x44,0xC0,0x48,0x8C,0x3C,0x48,0x62,0xC4,0x4B,0x48,0x09,0x88,0x46, ++ 0xCA,0x1C,0xE0,0x48,0x90,0x4D,0x8E,0x1C,0x80,0x34,0xC0,0x4C,0xD8,0x03,0x84,0x14, ++ 0x00,0x0F,0x00,0x01,0x80,0x34,0xF8,0x34,0x04,0x3F,0x4B,0x32,0x04,0x01,0x00,0x43, ++ 0xC0,0x4C,0xC8,0x3C,0xD3,0x03,0x1E,0xC2,0xC0,0x08,0x02,0x01,0x10,0xF9,0x01,0x1F, ++ 0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0xDC,0x14,0x10,0xC2,0x9C,0xC6,0x27,0x01, ++ 0x31,0x2A,0x31,0x32,0x03,0xC7,0x40,0xE2,0x08,0x23,0x4E,0x25,0xB8,0x0C,0x88,0x04, ++ 0x40,0x45,0x40,0x3E,0x5F,0x2D,0xB8,0xFF,0xFB,0x8F,0x33,0x5A,0x00,0xA1,0xF0,0xC2, ++ 0x40,0xE1,0xD1,0x1E,0x68,0x41,0x80,0x4E,0x18,0x62,0x05,0x1F,0x70,0x01,0x8C,0x0E, ++ 0x30,0x72,0x01,0x1F,0x41,0x68,0x1B,0x62,0x6F,0x01,0x88,0x26,0xC0,0x4C,0xC8,0x3C, ++ 0xD3,0x03,0x1E,0xC2,0xC0,0x08,0x02,0x01,0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48, ++ 0xE6,0x00,0x92,0x05,0xDC,0x14,0x10,0xC2,0x99,0xC6,0x37,0xAA,0x20,0x01,0x00,0x0F, ++ 0x1B,0xA2,0x41,0xB0,0x77,0x01,0x88,0xDE,0xC6,0x4C,0x58,0x04,0xC0,0x41,0x91,0x35, ++ 0x05,0x8F,0x18,0x62,0x46,0x02,0x0B,0x23,0x48,0x25,0xB8,0x0C,0x88,0x04,0x40,0x45, ++ 0x40,0x3E,0x58,0x2D,0xB9,0xFF,0xFF,0xD7,0x30,0x5A,0x03,0x81,0xF5,0xC2,0x10,0x82, ++ 0xE9,0x06,0x18,0x62,0x40,0x68,0x6B,0x01,0x88,0x5E,0xC7,0x44,0x0E,0xE9,0xC9,0x00, ++ 0x0A,0x48,0xC2,0x00,0xAB,0x23,0xE0,0xF8,0x90,0xFD,0xC7,0x1C,0x14,0x3A,0x9C,0xA6, ++ 0xF1,0x34,0x00,0x9F,0xC1,0x44,0x08,0xE9,0xCA,0x00,0x0C,0x48,0xC1,0x38,0xEA,0xC3, ++ 0x40,0x01,0x88,0x0E,0x01,0x09,0xA8,0xC3,0xE8,0xE3,0x29,0x01,0x01,0x01,0x00,0x07, ++ 0xE7,0x68,0x93,0x6D,0x40,0x09,0x88,0x1E,0x60,0xF9,0x97,0x0E,0xE5,0x20,0x93,0x25, ++ 0x48,0x22,0x02,0x01,0x00,0x43,0xAC,0x48,0x46,0x1A,0x0A,0x23,0x20,0x00,0x67,0x10, ++ 0x02,0x07,0x40,0x48,0x30,0x82,0x10,0x42,0x81,0xDE,0x4F,0x01,0xC9,0x06,0x08,0x01, ++ 0x88,0x04,0x90,0x0C,0x40,0x45,0x40,0x6E,0x37,0x8A,0xB9,0xFF,0xF0,0x0F,0x43,0x01, ++ 0x80,0x0E,0x68,0x29,0x99,0xE6,0xAE,0xE3,0xE7,0xB0,0x93,0xB5,0xC4,0x1C,0x10,0x32, ++ 0x98,0x46,0x86,0x5D,0xEF,0x85,0xAF,0xBD,0x80,0x15,0x34,0x62,0x31,0xB2,0x48,0x7A, ++ 0x00,0x01,0x80,0x43,0x40,0x8A,0x41,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B,0x28,0x01, ++ 0x00,0x3F,0x08,0x09,0x31,0x9A,0x31,0x52,0x30,0x42,0x80,0x07,0xCB,0xA7,0xE1,0x68, ++ 0x95,0x6D,0xD7,0x03,0x17,0x42,0xC5,0xA6,0x31,0x12,0x31,0x8A,0x00,0x11,0x80,0x07, ++ 0xC1,0x7F,0x34,0x92,0x30,0x0A,0xC1,0x14,0xB8,0xFF,0xFF,0xD7,0x31,0x12,0x31,0x8A, ++ 0x00,0x01,0x80,0x07,0xC5,0x2F,0xDC,0x03,0x41,0x01,0x80,0x46,0x6F,0xF2,0x40,0x43, ++ 0x91,0x3D,0x4C,0x04,0x00,0x43,0x47,0xCA,0x08,0x09,0x80,0x0B,0x31,0x12,0x31,0x8A, ++ 0x00,0x11,0x80,0x07,0xC1,0xAF,0x33,0x1A,0xB0,0x04,0x08,0x01,0x00,0x09,0xD0,0x14, ++ 0x82,0x07,0xC8,0xFF,0xB3,0x04,0xD8,0x0B,0x30,0x1A,0x01,0x11,0xD0,0x14,0x80,0x07, ++ 0xC9,0xC7,0x32,0x92,0x30,0x0A,0xC1,0x14,0xBF,0xFF,0xF7,0x97,0x31,0x12,0x31,0x8A, ++ 0x00,0x01,0x80,0x07,0xC0,0xEF,0x42,0x4A,0x08,0x01,0x80,0x0B,0x01,0x7B,0x37,0x1A, ++ 0xB0,0x04,0x08,0x01,0x00,0x11,0xD0,0x14,0x82,0x07,0xC8,0x1F,0x31,0x12,0x31,0x8A, ++ 0x00,0x11,0x80,0x07,0xC0,0x6F,0x02,0x5F,0x30,0x20,0x06,0x00,0x00,0xB0,0x00,0x01, ++ 0xF8,0xFB,0x07,0x00,0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42, ++ 0x50,0x1A,0x40,0x83,0x0C,0x11,0x18,0x42,0x00,0x83,0x80,0x2D,0xE8,0x85,0x07,0x00, ++ 0x18,0x00,0x04,0x42,0xA8,0x85,0x31,0x12,0x90,0x01,0xE6,0x9B,0x32,0xD8,0x72,0xD8, ++ 0xA7,0x9B,0x58,0xCA,0x41,0xE3,0x30,0x20,0xA2,0x16,0x40,0xE3,0x3F,0x20,0xAB,0xE6, ++ 0x58,0xB2,0x27,0x41,0x00,0xE3,0x44,0xE3,0x28,0xF9,0xAF,0x19,0x18,0x62,0x01,0xE3, ++ 0x20,0x81,0x48,0x01,0x83,0x76,0x00,0xE9,0x08,0x00,0xE4,0x8B,0x48,0x48,0x8E,0x1E, ++ 0xF0,0x00,0x22,0x00,0x67,0x00,0x88,0xC6,0x40,0x01,0x88,0x16,0x41,0xC3,0x18,0x02, ++ 0x01,0xC3,0xE8,0x85,0x80,0x01,0xE5,0x8B,0x48,0x48,0x8E,0x16,0xE8,0x0B,0x4E,0x31, ++ 0x8E,0xCE,0xEF,0x03,0x47,0x31,0x88,0xA6,0x41,0xC3,0x18,0x02,0x01,0xC3,0xE8,0x85, ++ 0xAA,0x85,0x47,0x63,0x46,0x5B,0xD6,0xAB,0x71,0x0A,0xC7,0xB3,0x70,0x09,0x88,0x16, ++ 0x4A,0x63,0x56,0x5B,0xD8,0xAB,0x44,0x01,0x88,0x0E,0x11,0x01,0x01,0xE7,0x40,0x03, ++ 0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08,0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB, ++ 0x1C,0xF2,0x19,0x33,0x58,0x33,0xC6,0xFB,0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83, ++ 0xC5,0xF3,0x18,0x82,0x31,0x32,0x03,0x83,0x40,0x73,0xC0,0xC3,0x18,0x32,0x04,0x73, ++ 0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95,0x17,0x52,0x9D,0x06,0xE8,0x85,0x47,0x09, ++ 0x88,0x0E,0x11,0x01,0x01,0xE7,0x40,0x03,0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08, ++ 0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB,0x1C,0xF2,0x1D,0x33,0x58,0x33,0xC6,0xFB, ++ 0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83,0xC5,0xF3,0x18,0x82,0x31,0x32,0x03,0x83, ++ 0x40,0x73,0xC0,0xC3,0x18,0x32,0x00,0x73,0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95, ++ 0x17,0x52,0x9D,0x06,0xE8,0x85,0x47,0x11,0x88,0x0E,0x11,0x01,0x01,0xE7,0x40,0x03, ++ 0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08,0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB, ++ 0x1C,0xF2,0x1D,0x33,0x58,0x33,0xC6,0xFB,0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83, ++ 0xC1,0xF3,0x18,0x82,0x31,0x32,0x03,0x83,0x40,0x73,0xC0,0xC3,0x18,0x32,0x04,0x73, ++ 0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95,0x17,0x52,0x9D,0x06,0xE8,0x85,0x47,0x19, ++ 0x88,0xE6,0x17,0x01,0x01,0xE7,0x40,0x03,0x30,0x32,0xB0,0x41,0x30,0xA2,0xED,0x08, ++ 0x32,0x42,0xC0,0x01,0x58,0x33,0xC4,0xFB,0x1C,0xF2,0x1D,0x33,0x58,0x33,0xC6,0xFB, ++ 0x1E,0xF2,0x1D,0x33,0x31,0x32,0x43,0x83,0xC1,0xF3,0x18,0x82,0x31,0x32,0x03,0x83, ++ 0x40,0x73,0xC0,0xC3,0x18,0x32,0x00,0x73,0xEA,0x20,0xE1,0xD8,0xE6,0x90,0x92,0x95, ++ 0x17,0x52,0x9D,0x06,0xEF,0x85,0xAF,0x85,0x44,0xE3,0x02,0xB0,0xCE,0x20,0x45,0xEB, ++ 0xC0,0x68,0x45,0x09,0x88,0x26,0x40,0xE3,0xCC,0x20,0x45,0xDB,0xC0,0xE8,0x04,0x3F, ++ 0x79,0x7A,0xC4,0xFB,0x78,0x09,0x88,0x1E,0x4D,0xE3,0xCE,0x20,0x54,0xDB,0xC2,0xE8, ++ 0x40,0x13,0xF9,0xA0,0xC0,0x5B,0x41,0x09,0x88,0x76,0x48,0x01,0x8A,0x66,0x40,0x83, ++ 0x1A,0xC2,0x04,0x83,0x44,0x83,0x1C,0xC2,0x01,0x83,0x44,0x03,0x19,0xC2,0x04,0x03, ++ 0x40,0x83,0x18,0xC2,0x07,0x83,0xE8,0x85,0x48,0x09,0x88,0x66,0x44,0x83,0x1A,0xC2, ++ 0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83,0x44,0x83,0x18,0xC2,0x01,0x83,0x40,0x03, ++ 0x19,0xC2,0x00,0x03,0xE8,0x85,0x4F,0x11,0x89,0x66,0x40,0x03,0x19,0xC2,0x04,0x03, ++ 0x44,0x83,0x18,0xC2,0x02,0x83,0x40,0x83,0x1A,0xC2,0x00,0x83,0x44,0x83,0x1C,0xC2, ++ 0x07,0x83,0xEC,0x85,0x4F,0x19,0x88,0xE6,0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83, ++ 0x18,0xC2,0x04,0x83,0x44,0x83,0x1A,0xC2,0x04,0x83,0x42,0x83,0x1C,0xC2,0x00,0x83, ++ 0xEF,0x85,0xAF,0xFD,0xF4,0x4C,0x30,0x62,0x29,0x01,0x48,0x93,0x4C,0x8B,0x35,0x72, ++ 0xD1,0xE3,0x36,0x3A,0x48,0x32,0xC3,0x4B,0x48,0x09,0x88,0x0E,0x54,0x93,0xD9,0xE3, ++ 0x41,0x19,0x80,0x96,0x33,0x79,0x48,0x0A,0x10,0xB0,0x41,0x11,0x8B,0xB6,0x30,0x02, ++ 0x1B,0x3A,0x5A,0x02,0xC6,0x14,0xC0,0x00,0xC3,0xC0,0x31,0x9A,0x32,0x2A,0xEB,0xDA, ++ 0x08,0x5B,0x0A,0x01,0x00,0x3F,0xC0,0x1B,0x18,0x9A,0x41,0xAB,0x00,0x5B,0xE9,0x90, ++ 0xE2,0x00,0xE2,0x48,0x95,0x4D,0x16,0x0A,0x9F,0xAE,0xEF,0xFD,0x40,0x01,0x88,0x8E, ++ 0x1E,0x01,0x10,0x5B,0x40,0x82,0x42,0x33,0x45,0xB0,0x05,0xB0,0x02,0x33,0x00,0x1B, ++ 0x00,0x5B,0x40,0x0B,0x1C,0x81,0x18,0xCA,0x00,0x0B,0x40,0x0B,0x18,0x01,0x1C,0xCA, ++ 0x00,0x0B,0x00,0x17,0x40,0x09,0x88,0x06,0x30,0xAA,0x01,0x01,0x00,0x27,0x40,0x8B, ++ 0x00,0x6B,0xE8,0x90,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0xC6,0xEF,0xFD,0xAF,0x85, ++ 0x30,0x72,0xCC,0x2C,0xD5,0x63,0x36,0x22,0x46,0xEB,0x42,0xE3,0x40,0x01,0x88,0x1E, ++ 0xDC,0x43,0x32,0x22,0x44,0xEB,0x40,0xE3,0x51,0x19,0x88,0x16,0x00,0x01,0x00,0xEF, ++ 0x3E,0x10,0x7E,0x90,0x28,0x92,0x8B,0xAE,0x40,0x53,0x31,0xB2,0xB0,0x41,0xE8,0x98, ++ 0x32,0xD2,0xD0,0x01,0x59,0xBB,0xC4,0x0B,0x1C,0x7A,0x1C,0xBB,0x59,0xBB,0xC6,0x0B, ++ 0x1E,0x7A,0x1C,0xBB,0x41,0x93,0xC1,0x3B,0x19,0xD2,0x01,0x93,0x41,0xCB,0xC0,0x13, ++ 0x18,0x8A,0x00,0xCB,0xEB,0x68,0xE1,0x20,0xE6,0x00,0x92,0x05,0x2E,0x02,0x9B,0xFE, ++ 0xE8,0x85,0x57,0x29,0x88,0xE6,0x07,0x01,0x06,0xEF,0x38,0x10,0x7B,0x90,0x2E,0x92, ++ 0x89,0xAE,0x40,0x53,0x30,0xB2,0xB0,0x41,0xE8,0x98,0x30,0xD2,0xD4,0x01,0x5A,0xBB, ++ 0xC0,0x0B,0x19,0x7A,0x1E,0xBB,0x5C,0xBB,0xC4,0x0B,0x19,0x7A,0x19,0xBB,0x46,0x93, ++ 0xC5,0x3B,0x19,0xD2,0x00,0x93,0x41,0xCB,0xC4,0x13,0x19,0x8A,0x01,0xCB,0xE8,0x68, ++ 0xE2,0x20,0xE3,0x00,0x93,0x05,0x2E,0x02,0x9F,0xFE,0xEE,0x85,0xA8,0x85,0xF7,0x2C, ++ 0x37,0x22,0xD4,0xAB,0xC4,0x34,0x00,0xB8,0x4E,0x03,0xC8,0x20,0x44,0xB2,0xC0,0xD8, ++ 0xC3,0xC0,0x30,0x1A,0x58,0x01,0x88,0x1E,0xD8,0xAB,0xDB,0x34,0x4E,0xDB,0xCA,0xE0, ++ 0x48,0x11,0x88,0xA6,0xB5,0x01,0xE4,0x8B,0x48,0x01,0x80,0x16,0x18,0x69,0x10,0xD8, ++ 0x00,0x57,0x18,0x79,0x10,0xD8,0x00,0x3F,0xC0,0x0B,0x18,0xCA,0x41,0x33,0x01,0x8B, ++ 0xA4,0x41,0xE0,0x00,0xE6,0x90,0x94,0x95,0x17,0x52,0x9D,0xAE,0xE8,0x85,0x4F,0x19, ++ 0x8F,0xE6,0x07,0xF9,0x18,0x02,0x06,0x77,0x18,0x00,0x04,0x42,0x00,0x01,0x00,0x42, ++ 0x00,0xB0,0x00,0x01,0x30,0x20,0x06,0x00,0x40,0x60,0x02,0x00,0x40,0x0B,0x01,0x43, ++ 0xA4,0x41,0xE0,0x90,0x95,0x95,0x16,0x52,0x9F,0xC6,0xEF,0x85,0xAC,0xFD,0x87,0x25, ++ 0x30,0x6A,0x30,0xB2,0x31,0xE2,0x48,0x3B,0x06,0xC9,0x07,0x00,0xC0,0x40,0x81,0x1C, ++ 0xD0,0x83,0x87,0x14,0xC0,0x24,0x40,0x01,0x8B,0x16,0xD8,0x83,0x83,0x14,0x48,0x3B, ++ 0x30,0x1A,0x11,0x19,0x08,0x01,0xB0,0x04,0xC7,0x24,0xB8,0xFF,0xF9,0x87,0x32,0x1A, ++ 0x10,0x19,0x08,0x09,0xB0,0x04,0xC0,0x24,0xBA,0xFF,0xFF,0x4F,0x30,0x5A,0x11,0x01, ++ 0x08,0x11,0xB0,0x04,0xA0,0x0C,0xC0,0x24,0xBC,0xFF,0xFF,0xC7,0x30,0x5A,0x11,0x09, ++ 0x08,0x11,0xB0,0x04,0xA0,0x0C,0xC0,0x24,0xBC,0xFF,0xFF,0x87,0x36,0x82,0x81,0x01, ++ 0xE2,0x0B,0x30,0x48,0x70,0x48,0xA2,0x0B,0x57,0xFA,0x0F,0xC1,0x00,0x8B,0x44,0x8B, ++ 0x18,0xF9,0x9F,0x19,0x18,0xCA,0x00,0x8B,0x35,0x8A,0x89,0x01,0x01,0x07,0xF8,0x85, ++ 0xE6,0x1B,0x48,0xD8,0x8E,0x16,0xE8,0x5B,0x5F,0x31,0x88,0xC6,0xE8,0x43,0x46,0x31, ++ 0x88,0x1E,0x40,0x83,0x08,0x81,0x18,0x42,0x00,0x83,0x00,0x01,0x04,0x3F,0x00,0x08, ++ 0xC2,0xCA,0x43,0x4B,0xDA,0x1C,0x00,0x10,0x92,0xCA,0xE4,0x00,0x90,0x05,0xCE,0x14, ++ 0x17,0x42,0x9C,0xA6,0x30,0x5A,0x11,0x01,0x08,0x19,0xB0,0x04,0xA0,0x0C,0xC0,0x24, ++ 0xBA,0xFF,0xFF,0xE7,0x30,0x5A,0x11,0x09,0x08,0x19,0xB0,0x04,0xA0,0x0C,0xC0,0x24, ++ 0xBA,0xFF,0xFF,0xA7,0x30,0x1A,0x11,0x29,0x08,0x09,0xB0,0x04,0xC7,0x24,0xB8,0xFF, ++ 0xF1,0xB7,0x37,0x1A,0x10,0x29,0x08,0x01,0xB0,0x04,0xC0,0x24,0xBF,0xFF,0xF7,0x7F, ++ 0x87,0x45,0xE8,0x85,0xAC,0xFD,0x87,0x35,0x08,0xC9,0xC7,0x3C,0x02,0x48,0xC6,0x28, ++ 0x48,0xD2,0xC6,0x3C,0xC0,0x20,0xC2,0x44,0xD0,0x33,0xC6,0x34,0x40,0x01,0x88,0x0E, ++ 0xC2,0x44,0xD8,0x33,0xC4,0x44,0x80,0x01,0x86,0x2C,0xE0,0x03,0x43,0x01,0x88,0xE6, ++ 0x08,0xF9,0x01,0x17,0xA2,0x0A,0xE1,0x00,0x95,0x05,0x14,0x82,0x9C,0xD6,0x3F,0x01, ++ 0xB8,0x24,0xB8,0x14,0x06,0x57,0x49,0x62,0xC6,0x24,0x08,0x43,0x40,0x35,0x40,0x7E, ++ 0xBA,0xFF,0xFF,0xE7,0x48,0x52,0x1E,0x01,0x00,0x01,0x00,0x67,0x04,0x10,0x32,0xA2, ++ 0xF4,0x52,0x15,0xD2,0xEB,0x0E,0x30,0x1A,0xD4,0x5A,0x17,0x52,0xD3,0x0E,0x30,0x0A, ++ 0xD2,0x4A,0xE3,0x00,0x95,0x05,0x14,0x82,0x9A,0x86,0x4F,0x81,0x90,0x2E,0x78,0x41, ++ 0x80,0x76,0xC0,0x24,0x18,0xC2,0x85,0x24,0x00,0x27,0xC0,0x14,0x40,0x01,0x8C,0x0E, ++ 0xB8,0x14,0x00,0x2F,0x40,0xF8,0xC3,0x24,0x18,0xC2,0x81,0x24,0x7E,0x01,0x88,0x96, ++ 0x00,0x01,0x08,0x01,0x01,0x17,0xA0,0x0A,0xE4,0x00,0x92,0x05,0x17,0x82,0x9D,0xD6, ++ 0xC0,0x14,0x80,0x1C,0x38,0x01,0x00,0x27,0xC0,0x14,0x18,0x3A,0xC2,0x14,0x40,0x00, ++ 0x80,0x14,0xC0,0x14,0x47,0x01,0x88,0xBE,0xC6,0x2C,0x58,0x04,0xC0,0x41,0x91,0x05, ++ 0x81,0x0C,0x00,0x17,0xC4,0x1C,0x18,0x3A,0x46,0x3A,0x0D,0x3B,0x40,0x35,0x40,0x7E, ++ 0xB8,0xFF,0xFF,0xA7,0x58,0x32,0x0D,0x01,0x00,0x01,0x00,0x67,0x04,0x10,0x32,0xA2, ++ 0xF4,0x52,0x15,0x52,0xEB,0x0E,0x30,0x0A,0xD4,0x4A,0x13,0xD2,0xD3,0x0E,0x30,0x12, ++ 0xD2,0x5A,0xE5,0x00,0x95,0x05,0x14,0x82,0x98,0x86,0xC7,0x0C,0x10,0x0A,0xEC,0x0E, ++ 0xC0,0x1C,0x18,0x3A,0xC2,0x1C,0x40,0x00,0x80,0x1C,0xC0,0x1C,0x46,0x01,0x88,0xCE, ++ 0x78,0x01,0x88,0x06,0x38,0x09,0xC0,0x2C,0xA0,0x3B,0xC6,0x2C,0xE4,0x0B,0x46,0x92, ++ 0x08,0x0B,0xC6,0x2C,0xE0,0x03,0x3E,0x09,0x16,0xF8,0x07,0x00,0x80,0x24,0x00,0x07, ++ 0x40,0xF8,0xC3,0x24,0x17,0xC2,0x81,0xDE,0x78,0x01,0xC9,0x06,0x38,0x01,0x01,0x01, ++ 0x08,0x01,0x00,0x17,0xA2,0x0A,0xE1,0x00,0x95,0x05,0x14,0x82,0x98,0xD6,0x07,0x01, ++ 0x80,0x04,0x78,0x01,0x88,0x1E,0xC0,0x04,0xE6,0x00,0x92,0x05,0x80,0x04,0x00,0x01, ++ 0x01,0x57,0xE0,0x0A,0x1E,0xCA,0x91,0x4D,0xA0,0x0A,0xD1,0x24,0x10,0x8A,0xCC,0x0E, ++ 0x19,0xCA,0xA5,0x0A,0xE4,0x00,0x92,0x05,0x17,0x82,0x9D,0x96,0x40,0x35,0x40,0x7E, ++ 0xBD,0xFF,0xF7,0xE7,0x01,0x01,0x00,0x0F,0xD2,0x2C,0x00,0x08,0xD6,0x4A,0x5B,0x94, ++ 0xD0,0x48,0x94,0x4D,0xD0,0x04,0x50,0x01,0x8B,0x2E,0x48,0x21,0xE9,0xA6,0xE0,0x0A, ++ 0x19,0xCA,0xA5,0x0A,0x01,0x87,0x48,0x91,0xE9,0x2E,0xE0,0x12,0x50,0x01,0x80,0x16, ++ 0xF1,0x90,0xA2,0x12,0x01,0x47,0x10,0x89,0x1C,0x92,0x16,0x8A,0xD1,0x26,0xE0,0x0A, ++ 0x48,0xF9,0x91,0x0E,0xE1,0x48,0xA2,0x0A,0xE4,0x00,0x92,0x05,0x16,0x82,0x9D,0xDE, ++ 0x40,0xF8,0xC3,0x04,0x45,0x21,0xC8,0xE6,0x87,0x55,0xE8,0x85,0xAC,0xBD,0x87,0x75, ++ 0xCE,0x84,0xD0,0x6B,0x10,0xC9,0xCF,0x7C,0x04,0x90,0xC6,0x48,0x18,0xF9,0xD1,0x7C, ++ 0x0E,0xD8,0xC2,0x90,0x20,0xF9,0xDF,0x7C,0x00,0x20,0xCF,0xE0,0x30,0x09,0xDC,0x7C, ++ 0x0C,0xB0,0xC9,0xD8,0x99,0x14,0x30,0x09,0xDD,0x7C,0x08,0xB0,0xC8,0xD8,0x9C,0x0C, ++ 0x78,0x1D,0x40,0x01,0x88,0x0E,0xC0,0x84,0xD8,0x2B,0xC2,0x84,0xE0,0x03,0x44,0x29, ++ 0xC0,0x56,0x00,0x01,0x02,0x37,0x00,0x18,0xD6,0x72,0x96,0xB2,0xD7,0x72,0x96,0x32, ++ 0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xB6,0x04,0x01,0x30,0x22,0x18,0x01,0x00,0xCF, ++ 0x01,0xC0,0xD2,0x32,0x30,0x32,0xB4,0x6C,0x30,0x01,0x00,0x01,0xF8,0xB2,0xF4,0x42, ++ 0xC3,0xB0,0x81,0xB0,0x31,0x82,0x93,0x32,0x40,0x74,0x00,0xB4,0xD0,0x02,0xF1,0x6C, ++ 0xD9,0x00,0x04,0xC4,0x20,0x02,0x93,0x05,0x34,0x22,0xE4,0x90,0xE5,0x48,0xE4,0xF8, ++ 0xE6,0xD8,0x92,0xDD,0x17,0x5A,0x9D,0x1E,0x71,0x1D,0x30,0x4A,0x30,0x02,0x83,0x0F, ++ 0xD8,0x5F,0x95,0x0D,0x10,0x01,0x00,0xCF,0x01,0x01,0xF0,0x82,0xE0,0xB0,0x45,0x01, ++ 0xE8,0x2E,0x48,0x01,0xEC,0x1E,0x10,0x42,0xE8,0x56,0x30,0x42,0x00,0x47,0x40,0x01, ++ 0xD0,0x2E,0x48,0x01,0xD4,0x1E,0x10,0x42,0xD0,0x16,0x30,0x42,0x00,0x07,0x00,0x01, ++ 0x07,0x98,0xD2,0x3A,0xD7,0xC0,0x91,0x02,0xE6,0x90,0x92,0x95,0x17,0x52,0x9D,0x1E, ++ 0xC4,0x84,0xE0,0x03,0x40,0x29,0xC0,0xEE,0x00,0x01,0x10,0x01,0x02,0x3F,0x00,0x08, ++ 0xF3,0x14,0xD0,0x1A,0x90,0x9A,0xCB,0x0C,0xA2,0x52,0xE0,0x00,0x95,0x05,0x16,0x42, ++ 0x98,0xAE,0x07,0x01,0x12,0xF9,0x09,0x90,0x1A,0x09,0x0A,0xD8,0x00,0x47,0xE0,0x7C, ++ 0x00,0x08,0xCA,0x48,0xC1,0x60,0x5C,0x24,0xC0,0x48,0x0E,0x64,0xE6,0x00,0x92,0x05, ++ 0x17,0x42,0x9D,0xA6,0x87,0x8D,0xE8,0x85,0xAE,0xE5,0xD7,0x9B,0x9F,0x0C,0x18,0xF9, ++ 0x06,0xD8,0xC6,0x58,0x34,0xF2,0x1C,0x09,0x0E,0xD8,0xC0,0x68,0x1C,0x09,0x09,0xD8, ++ 0xC4,0x58,0x36,0xE2,0x1E,0xC9,0x07,0xD8,0xC0,0x48,0x8E,0x04,0x40,0x01,0x88,0x0E, ++ 0xD8,0x83,0x82,0x0C,0x00,0x01,0x30,0x9A,0x9A,0x01,0x14,0xC3,0x11,0xC3,0x04,0xCF, ++ 0x03,0x20,0x32,0x8A,0xD9,0x4A,0xD8,0x72,0xD8,0x48,0x94,0x75,0xC8,0x04,0x98,0x72, ++ 0x08,0x01,0x38,0xB1,0xBD,0xFA,0x16,0xBA,0xE8,0x66,0x08,0x09,0x3A,0x09,0x50,0xF3, ++ 0x01,0x3A,0x1C,0xF2,0x10,0xF3,0x02,0x77,0x00,0x01,0x00,0x42,0x40,0x60,0x02,0x00, ++ 0xF8,0xFF,0x07,0x00,0xED,0xFB,0x16,0xBA,0xD0,0x2E,0x08,0x09,0x3C,0x09,0x50,0xF3, ++ 0x01,0x3A,0x1C,0xF2,0x10,0xF3,0x4C,0x01,0x8D,0x96,0x08,0xC1,0xE0,0x4A,0x4C,0x01, ++ 0x89,0x76,0xF8,0x7A,0x13,0xF0,0x31,0x0A,0xE4,0x4A,0xC8,0x70,0x30,0x8A,0xFB,0x4A, ++ 0x04,0x48,0xCC,0x70,0x03,0xC8,0xD5,0x88,0x91,0x70,0x98,0x72,0x31,0x22,0xA3,0x0A, ++ 0xE6,0x00,0x92,0x05,0xCC,0x0C,0x10,0x42,0x9F,0x16,0xEE,0xE5,0xAC,0xBD,0x87,0x65, ++ 0x30,0x62,0x30,0xB2,0x40,0xFA,0x47,0x03,0x90,0x05,0x84,0x5C,0x40,0xF2,0x47,0x0B, ++ 0x90,0x4D,0x8C,0x54,0x44,0x0B,0x92,0x4D,0x8E,0x4C,0x40,0x0B,0x90,0x4D,0x8C,0x44, ++ 0x4C,0x0B,0x90,0x4D,0x8A,0x3C,0x48,0x0B,0x90,0x4D,0x8C,0x34,0x4C,0x0B,0x94,0x4D, ++ 0x8E,0x2C,0x50,0x0B,0x90,0x4D,0x8C,0x24,0x4C,0x0B,0x96,0x4D,0x8A,0x1C,0x58,0x0B, ++ 0x90,0x4D,0x8C,0x14,0x5C,0x0B,0x94,0x4D,0x88,0x0C,0x08,0x21,0x0C,0x0B,0x08,0x0B, ++ 0xE7,0x0B,0x53,0x72,0x1E,0x8A,0x10,0x0B,0x08,0x01,0xDD,0x4A,0x01,0x0B,0x36,0x2A, ++ 0xA9,0x01,0xEC,0x4B,0x1B,0x0B,0xEA,0x4B,0x1F,0x0B,0xE4,0x4B,0x0D,0x0B,0xE6,0x43, ++ 0x40,0x01,0x80,0x3E,0x47,0x22,0x4F,0x32,0x00,0x0B,0x0A,0xC9,0x00,0x0B,0x08,0x09, ++ 0x08,0x0B,0x02,0x3F,0x4F,0x12,0x47,0x02,0xCA,0xE1,0x00,0x0B,0x08,0x89,0x00,0x0B, ++ 0x0A,0x41,0x08,0x0B,0xE0,0x03,0x45,0x09,0x8B,0xB6,0xD8,0x03,0x80,0x04,0x38,0x01, ++ 0x00,0x3F,0x08,0x09,0x31,0x9A,0x31,0xD2,0x37,0x42,0xB8,0xFF,0xE3,0x67,0xE0,0xF8, ++ 0x90,0xFD,0xC7,0x04,0x17,0x3A,0x9C,0xA6,0x31,0x9A,0x31,0x12,0x00,0x09,0xC8,0x64, ++ 0xBD,0xFF,0xEF,0xC7,0xF3,0x43,0xB7,0x03,0x31,0x9A,0x31,0x12,0x00,0x09,0xC8,0x64, ++ 0xB9,0xFF,0xEF,0xA7,0x30,0x12,0x01,0x09,0xCF,0x64,0xB8,0xFF,0xF1,0xFF,0x34,0x12, ++ 0x00,0x09,0xC8,0x64,0xB9,0xFF,0xFF,0x87,0x48,0x32,0xC6,0x5C,0x06,0x43,0x40,0x32, ++ 0xC8,0x54,0x00,0x0B,0xCA,0x4C,0x00,0x0B,0xCE,0x44,0x00,0x0B,0xC8,0x3C,0x08,0x0B, ++ 0xCA,0x34,0x08,0x0B,0xCC,0x2C,0x08,0x0B,0xCE,0x24,0x10,0x0B,0xCE,0x1C,0x08,0x0B, ++ 0xCA,0x14,0x18,0x0B,0xCC,0x0C,0x18,0x0B,0xE6,0x43,0x31,0x00,0xAB,0x66,0xF1,0x03, ++ 0xF4,0x4B,0x15,0x42,0x89,0x46,0x31,0x02,0x82,0x01,0xE1,0x13,0x50,0x11,0x88,0x46, ++ 0xE8,0x13,0x51,0x51,0x88,0x16,0x10,0x01,0xA0,0x13,0x02,0x9F,0xE1,0x90,0xAA,0x13, ++ 0x05,0x87,0x50,0x53,0x50,0x01,0x88,0x2E,0x50,0x53,0x53,0x01,0x89,0x16,0xE8,0x13, ++ 0x50,0x01,0x89,0x2E,0xF3,0x53,0xB7,0x13,0x11,0x09,0xB0,0x13,0xA0,0x13,0x02,0x0F, ++ 0xE1,0x90,0xAA,0x13,0xF4,0x03,0x13,0x42,0x88,0x36,0x08,0x01,0x30,0x1A,0xB1,0x04, ++ 0x30,0x42,0xD0,0x64,0xBF,0xFF,0xDF,0xEF,0x31,0x12,0x31,0x8A,0x07,0x11,0xB8,0xFF, ++ 0xD8,0x3F,0x80,0x7D,0xEF,0x85,0xAF,0x85,0x4E,0xA3,0xD0,0xEB,0x33,0x70,0x72,0xB0, ++ 0x4F,0x78,0x0E,0xF8,0x48,0xFA,0xC4,0x4B,0x48,0x09,0x88,0x0E,0x54,0xA3,0xD8,0xEB, ++ 0x0F,0x01,0x18,0xF9,0x01,0x6F,0x40,0x13,0x47,0x93,0x02,0x92,0x90,0x95,0x00,0x14, ++ 0x78,0x01,0x88,0x16,0x50,0xF9,0xEF,0x06,0x01,0x1C,0xE8,0x20,0xE2,0x00,0xE4,0x48, ++ 0x95,0x4D,0x16,0x4A,0x9F,0x7E,0xEF,0x85,0xA8,0xC5,0x33,0x2A,0x34,0xB2,0x60,0x6A, ++ 0x44,0x03,0x11,0x01,0x19,0x82,0x04,0x03,0x40,0x03,0x11,0x81,0x19,0x82,0x00,0x03, ++ 0x40,0x03,0x11,0x09,0x19,0x82,0x00,0x03,0xE7,0x53,0x03,0xF9,0x80,0x81,0x18,0x12, ++ 0x46,0x2A,0x14,0x13,0x13,0x99,0x00,0x13,0x14,0x41,0x00,0x13,0x12,0x91,0xEC,0x92, ++ 0x50,0x01,0x80,0x16,0x10,0xC9,0x00,0x13,0x00,0x0F,0x10,0x89,0x00,0x13,0x30,0x52, ++ 0x30,0x5A,0x09,0x01,0x00,0x09,0xB0,0x04,0xBD,0xFF,0xDF,0x5F,0x31,0x52,0x31,0x8A, ++ 0x07,0x11,0xB8,0xFF,0xD3,0xAF,0x45,0x03,0x3F,0x00,0xAA,0xE6,0xEF,0xC5,0xAB,0x9D, ++ 0x80,0x8D,0xCC,0x94,0xC8,0x4B,0x8A,0x84,0xE2,0x94,0xA0,0x01,0xD3,0x1B,0xD1,0x0B, ++ 0x88,0x0C,0xC8,0x94,0xD0,0x6B,0x36,0x0A,0x8C,0x61,0x30,0x62,0xC8,0x94,0x30,0x01, ++ 0xE0,0x4B,0x4C,0x09,0x88,0x56,0x08,0x01,0x02,0x27,0xC0,0x38,0x9A,0xF3,0xA1,0x32, ++ 0xE2,0x48,0x92,0x4D,0xD6,0x94,0xD0,0x93,0x17,0x52,0xE4,0xB6,0x52,0x52,0x03,0xB3, ++ 0x06,0xB3,0x04,0xB3,0x0E,0x01,0x18,0x4A,0x00,0x8B,0xC8,0x94,0xD0,0x4B,0xB6,0x8B, ++ 0x0B,0x01,0x50,0x2A,0x34,0x01,0x00,0x78,0xC1,0xF8,0x0D,0xF3,0xC2,0x90,0xB2,0xB3, ++ 0xE2,0x48,0x92,0x4D,0x4F,0x11,0xD8,0xA6,0xCC,0x94,0xE0,0x4B,0x4B,0x29,0xC8,0xA6, ++ 0x00,0x48,0xC5,0x48,0x04,0x50,0xC3,0x70,0x14,0x09,0x06,0x90,0xC0,0xB0,0xB5,0x1C, ++ 0xC0,0x48,0x8C,0x14,0x30,0x12,0x33,0x32,0xB0,0xC1,0x08,0x01,0x8A,0x3C,0x48,0xBA, ++ 0x88,0x6C,0x88,0x64,0x30,0x32,0x04,0x01,0x32,0x22,0x04,0x27,0xC8,0x1C,0x00,0x01, ++ 0xF0,0x42,0xF8,0x14,0x0B,0x01,0xF0,0xCA,0x32,0x7A,0xD0,0x08,0x97,0x4D,0x48,0xF9, ++ 0xEF,0x06,0x08,0xF9,0xCB,0x38,0x86,0xF8,0x78,0xF9,0xEF,0x06,0x3B,0xF9,0x37,0x82, ++ 0x82,0x3B,0xE0,0x00,0x30,0x32,0xC4,0xBB,0x10,0xFA,0x9C,0x46,0x10,0xCA,0xDC,0x36, ++ 0x46,0x84,0xD9,0x48,0xC0,0x00,0x92,0x05,0x04,0x84,0x81,0x08,0x04,0x37,0x10,0xCA, ++ 0xDC,0x16,0x00,0x78,0x00,0xBC,0x01,0x0F,0x39,0x01,0x00,0xBC,0x10,0xCA,0xDC,0x0E, ++ 0x38,0x09,0xB8,0x3C,0x43,0x78,0x2B,0x3A,0xE8,0x26,0xF8,0x6C,0x10,0x7A,0xEC,0x2E, ++ 0x88,0x6C,0x00,0x1F,0xFC,0x64,0x10,0x7A,0xE8,0x06,0x88,0x64,0x82,0x8B,0xE0,0x90, ++ 0xE0,0xB0,0xC5,0x1C,0xE0,0x00,0x84,0x1C,0xC4,0x14,0xE0,0x00,0x83,0x14,0x30,0x02, ++ 0xE2,0x00,0x92,0x05,0x35,0x22,0x2C,0x62,0xD8,0xC6,0xC5,0x3C,0x40,0x01,0x80,0xA6, ++ 0x08,0x01,0x00,0x01,0x80,0x5C,0xC0,0x0C,0xC2,0x00,0x46,0x00,0x80,0x7C,0xC0,0x0C, ++ 0x30,0x00,0x72,0x00,0x80,0x74,0x00,0x01,0x30,0x22,0x84,0x34,0x80,0x2C,0x80,0x24, ++ 0xF3,0x90,0xF2,0x40,0x94,0x05,0x32,0x32,0x05,0x7F,0x02,0x77,0x32,0x02,0x03,0x00, ++ 0x30,0x22,0xC4,0x34,0x00,0x00,0x82,0x34,0xC2,0x2C,0x00,0x00,0x80,0x2C,0xC0,0x24, ++ 0x00,0x00,0x82,0x24,0x43,0x40,0x2B,0x82,0xE8,0x26,0xC0,0x83,0xF4,0x6C,0xD8,0x00, ++ 0x80,0x83,0x00,0x1F,0xC0,0x83,0xF0,0x64,0xD8,0x00,0x84,0x83,0xC0,0x83,0x70,0x45, ++ 0x37,0xBA,0xAB,0x82,0xC4,0x83,0x10,0xC2,0xDA,0xDE,0xE0,0x48,0x90,0x4D,0xF2,0x5C, ++ 0xC1,0xB0,0x91,0xB5,0xB3,0x5C,0x30,0x32,0x39,0x09,0x18,0xF2,0x30,0xA2,0xF5,0x7C, ++ 0x10,0x82,0xDD,0x76,0xF1,0x34,0x18,0xF2,0xB0,0x34,0xF0,0x0C,0x10,0x82,0xDD,0x46, ++ 0xF1,0x2C,0x18,0xF2,0xB0,0x2C,0xF0,0x74,0x10,0x82,0xDD,0x16,0xC1,0x24,0x18,0xC2, ++ 0x80,0x24,0x00,0x6F,0x18,0x00,0x04,0x42,0x00,0x01,0x00,0x42,0x10,0x78,0x00,0x00, ++ 0x88,0x60,0x05,0x00,0x00,0xB0,0x00,0x01,0x58,0x80,0x04,0x01,0x78,0xF8,0x07,0x00, ++ 0xF3,0x90,0x32,0x82,0xF2,0x00,0x92,0x05,0x33,0x32,0x34,0x82,0x45,0x01,0xD0,0x6E, ++ 0x42,0xFA,0xB7,0x0B,0xD0,0x50,0xB3,0x13,0x36,0x12,0x1B,0x92,0x03,0x13,0x30,0x12, ++ 0x08,0x13,0xD0,0x34,0x00,0x13,0xD2,0x2C,0x00,0x13,0xD4,0x24,0x00,0x13,0x36,0x01, ++ 0x00,0xA7,0xC1,0x5C,0x87,0x0F,0xC0,0x07,0x90,0x05,0x80,0x5C,0x4D,0xA2,0x07,0x80, ++ 0xC0,0x00,0x4A,0x13,0x40,0x45,0x08,0x01,0x1C,0x01,0x30,0xF2,0x30,0xE2,0x04,0xCF, ++ 0x38,0x98,0x86,0x7E,0xC0,0x1B,0xF8,0x5C,0xD8,0xD8,0x96,0xDD,0x58,0x01,0xE8,0x36, ++ 0x83,0x1B,0x20,0x9A,0x94,0xDD,0x36,0xF2,0xE2,0x48,0x92,0x4D,0x00,0x27,0x18,0x01, ++ 0x80,0x1B,0x00,0x0F,0x18,0x01,0x80,0x1B,0x42,0x90,0xE2,0x00,0x32,0x1A,0xE3,0xD8, ++ 0x94,0xDD,0x32,0xE2,0x2F,0x62,0xDD,0x1E,0xE3,0xB0,0x93,0xB5,0x30,0x82,0x83,0x5C, ++ 0x45,0xFA,0x06,0x98,0xC0,0xD8,0x08,0xD3,0xCA,0x00,0xB4,0x0B,0x48,0x21,0xD8,0x0E, ++ 0x76,0x09,0xD8,0x36,0x06,0x01,0x50,0xD2,0x04,0x08,0xC4,0x58,0xE4,0x08,0x02,0x70, ++ 0xC0,0xB0,0x4D,0xEB,0x4D,0xB3,0x19,0xAA,0x08,0xEB,0xC0,0x80,0xF4,0x1B,0xF2,0x2B, ++ 0xDA,0xD8,0xB2,0x1B,0x90,0x45,0x42,0x09,0xD8,0x76,0x07,0x09,0x9E,0x03,0x45,0x82, ++ 0x0E,0x19,0x40,0x13,0x50,0x01,0x80,0x16,0x05,0x29,0x98,0x0B,0x04,0xF7,0x40,0x13, ++ 0x50,0x01,0x80,0x16,0x05,0x21,0x98,0x0B,0x02,0xC7,0x40,0x0B,0x48,0x01,0x80,0x1E, ++ 0x00,0x19,0x08,0x11,0x98,0x0B,0x05,0x8F,0x48,0x03,0x40,0x01,0x88,0x26,0xC0,0x94, ++ 0x82,0x01,0xF5,0x03,0x40,0x51,0x98,0x0E,0x00,0x11,0x00,0x3F,0xC1,0x94,0x80,0x01, ++ 0xD8,0x03,0x44,0x01,0x80,0x0E,0x00,0x11,0x00,0x07,0x00,0x09,0xDC,0x0B,0xE5,0x50, ++ 0x9D,0x13,0xD7,0x13,0x38,0x90,0xA2,0x0E,0xF5,0x48,0x9A,0x0B,0xE0,0x0B,0x13,0x29, ++ 0x10,0x0A,0x94,0x0E,0xA0,0x13,0x01,0xEF,0x10,0x0A,0xCC,0x46,0x40,0x09,0x88,0x16, ++ 0x09,0x81,0xA7,0x0B,0x00,0xB7,0xD0,0x48,0x01,0x52,0xA4,0x13,0x00,0x97,0x40,0x19, ++ 0xC8,0x0E,0x08,0x19,0x02,0x07,0x90,0x0D,0xE0,0x13,0x51,0x01,0x82,0x16,0xF0,0x90, ++ 0xA0,0x13,0x01,0x3F,0xD2,0x94,0xF0,0x48,0xCA,0x93,0x1C,0x52,0xCA,0x84,0xC0,0x88, ++ 0xD0,0x94,0x88,0x8B,0xA0,0x03,0x83,0x9D,0xEF,0x85,0xAF,0xBD,0x80,0x6D,0x34,0x6A, ++ 0xD1,0x63,0x37,0x42,0x80,0x01,0x82,0x64,0xC8,0x03,0x86,0x3C,0xC4,0x64,0xD0,0x03, ++ 0x30,0x00,0xA8,0x1E,0x02,0x91,0xEC,0x02,0x40,0x01,0x80,0xAE,0xC5,0x6C,0x00,0x08, ++ 0xC3,0x40,0x00,0x08,0x12,0x09,0xC6,0x08,0x04,0x90,0xC4,0x48,0xC0,0x10,0x04,0x01, ++ 0x18,0x01,0x00,0x2F,0x00,0x5C,0x00,0x9C,0xE4,0x48,0xE4,0x90,0xE2,0x00,0x92,0x05, ++ 0x17,0x02,0xDD,0xBE,0x87,0x85,0xE8,0x85,0x00,0xE9,0xC9,0x6C,0x08,0x00,0xC2,0x40, ++ 0x70,0x82,0xEC,0x03,0x08,0x83,0xD7,0x7C,0x91,0x04,0x30,0x5A,0x08,0x01,0x00,0x11, ++ 0xD7,0x6C,0xB8,0xFF,0xCC,0xB7,0x45,0x5A,0x80,0x01,0x42,0x0B,0x34,0x5A,0x0B,0xCC, ++ 0x5E,0x8B,0x09,0xCC,0x58,0x8B,0x13,0xCC,0x5A,0x8B,0x15,0xCC,0x44,0x8B,0x17,0xCC, ++ 0x48,0x2A,0x44,0x53,0x17,0xD4,0x4E,0x93,0x18,0xD4,0x10,0x89,0x00,0x93,0x17,0x19, ++ 0x18,0x93,0x43,0x53,0x1C,0x11,0x18,0xD2,0x00,0x53,0x40,0x0B,0x18,0xCA,0x00,0x0B, ++ 0x35,0x42,0xE1,0x4B,0x80,0x01,0x81,0x5C,0x4A,0x09,0x88,0x66,0x68,0x44,0x81,0x14, ++ 0x34,0x8A,0x59,0x43,0x90,0x35,0xB6,0x0C,0x00,0x01,0x80,0x04,0xD6,0x6C,0x08,0x09, ++ 0x04,0x00,0x07,0x48,0xC2,0x00,0xC4,0x00,0x83,0x54,0x40,0x92,0x18,0x33,0x0A,0x01, ++ 0x37,0x42,0xB9,0xFF,0xC0,0xBF,0xFA,0x54,0xC1,0x64,0x30,0x5A,0xC9,0x0B,0x34,0xC2, ++ 0xD7,0x7C,0xB8,0xFF,0xEB,0x07,0x4C,0x6A,0x10,0x01,0x00,0x01,0x02,0x67,0x00,0x18, ++ 0x37,0xE2,0xF4,0xDA,0x10,0x5A,0xD4,0x0E,0x33,0x0A,0xD3,0xCA,0x10,0x9A,0xEC,0x0E, ++ 0x35,0x12,0xD3,0xD2,0xE2,0x00,0x92,0x05,0x17,0x02,0xDD,0x86,0xC4,0x14,0xE0,0x00, ++ 0x10,0x0A,0x9C,0x36,0xC0,0x04,0x40,0x01,0x8B,0x9E,0x40,0x80,0x40,0x08,0xC2,0x70, ++ 0x00,0x3F,0xC0,0x14,0xF4,0x00,0x14,0x12,0xE0,0x5E,0x00,0x09,0x83,0x04,0xE0,0xB0, ++ 0x90,0xB5,0x77,0x01,0x80,0x16,0xC0,0x0C,0x16,0x32,0x9C,0x36,0x70,0x01,0x88,0x06, ++ 0x30,0x09,0xC0,0x5C,0x88,0x33,0xC0,0x5C,0xCA,0x0B,0x40,0x92,0x18,0x0B,0x32,0x01, ++ 0x35,0x42,0x81,0x01,0x81,0x4C,0x80,0x01,0x83,0x44,0x00,0x4F,0xC4,0x3C,0x10,0x32, ++ 0xD0,0x6E,0xC0,0x44,0xE0,0x03,0xC8,0x44,0x32,0x00,0x72,0x00,0xA2,0x43,0x40,0x4A, ++ 0x0C,0x41,0x00,0x0B,0x47,0x0B,0x10,0xF9,0x90,0x21,0x18,0x8A,0x00,0x0B,0xC8,0x6C, ++ 0x02,0x00,0xC5,0x08,0x06,0x00,0x13,0x09,0xC4,0x40,0x00,0x90,0xC4,0x00,0xC4,0x48, ++ 0x70,0x01,0x88,0x66,0x12,0x01,0x78,0x0A,0x00,0x37,0x18,0x01,0x00,0x1C,0x00,0x7C, ++ 0xE4,0x00,0xE4,0x48,0xE2,0x90,0x92,0x95,0x17,0x12,0xDD,0xB6,0x00,0x0F,0xD9,0x6C, ++ 0x06,0x10,0xC7,0x90,0x1C,0x09,0x06,0xD8,0xC4,0x90,0x36,0xA2,0x18,0x01,0x00,0x9F, ++ 0x30,0x3A,0x13,0x01,0xF0,0xD2,0x3D,0x01,0xFC,0x3A,0x16,0xBA,0xD0,0x06,0x00,0x14, ++ 0x3E,0x01,0xF8,0x7A,0x10,0xBA,0xEC,0x06,0x04,0x54,0xE0,0x00,0xE3,0x48,0x34,0x12, ++ 0xE4,0x90,0x34,0xA2,0xE2,0xD8,0x92,0xDD,0x17,0x1A,0xDD,0x4E,0xC4,0x3C,0x10,0x32, ++ 0x80,0x0E,0xC1,0x44,0xE6,0x03,0x48,0x00,0x88,0x1E,0xC0,0x4C,0xE8,0x03,0x46,0x31, ++ 0x88,0xBE,0xC7,0x4C,0xE8,0x03,0x46,0x31,0x89,0x26,0x40,0x12,0x40,0x0B,0x10,0x81, ++ 0x18,0x8A,0x00,0x0B,0xCF,0x6C,0x00,0x00,0xC6,0x00,0x0A,0x09,0x02,0x48,0xC4,0x00, ++ 0xC9,0x64,0x30,0x5A,0xC8,0x4B,0xD4,0x7C,0xBE,0xFF,0xE7,0xEF,0xE3,0xB0,0x93,0xB5, ++ 0xC4,0x3C,0x10,0x32,0xE8,0x96,0x44,0xBA,0x34,0x5A,0x4B,0xCC,0x80,0x01,0x02,0x0B, ++ 0x46,0xA2,0x48,0xCC,0x18,0x0B,0x50,0xCC,0x1A,0x0B,0x52,0xCC,0x1C,0x0B,0x54,0xCC, ++ 0x00,0x0B,0x4E,0x8A,0x50,0xD4,0x06,0x53,0x5E,0xCC,0x08,0x0B,0x37,0x97,0xAF,0xFD, ++ 0x81,0xED,0xE4,0x3C,0x30,0xAA,0x00,0x01,0x80,0x7C,0x80,0x74,0xC6,0x34,0xD1,0x03, ++ 0x81,0x6C,0xC0,0x34,0xDA,0x03,0xF2,0x00,0x90,0x05,0x86,0x64,0x00,0x01,0x80,0x5C, ++ 0x80,0x54,0x80,0x4C,0xC4,0x34,0xC9,0x03,0x00,0x00,0x82,0xBC,0x08,0xA1,0x05,0x3F, ++ 0x58,0x80,0x04,0x01,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0xF8,0xFB,0x07,0x00, ++ 0xC2,0x34,0xF1,0x0A,0x80,0x40,0x82,0xB4,0xC1,0x34,0xD9,0x04,0xE7,0x03,0x9C,0xF9, ++ 0x98,0x29,0x41,0x09,0x88,0x76,0xC0,0x6C,0x1E,0x42,0xC3,0x08,0xD0,0xEC,0x00,0x01, ++ 0x00,0x2F,0x40,0xB4,0x82,0x73,0xE0,0x48,0xE2,0x90,0xE4,0x00,0x90,0x05,0xF2,0x6C, ++ 0x17,0x82,0xDD,0xB6,0x00,0x01,0x80,0x9C,0x80,0xA4,0x80,0xAC,0xC4,0xEC,0x30,0x32, ++ 0x70,0x1D,0xC8,0x6C,0x32,0x42,0x19,0x42,0x86,0xE4,0xC0,0x00,0x30,0x22,0x84,0xDC, ++ 0x40,0xAA,0x47,0x13,0x48,0x1B,0x08,0x01,0x03,0x1F,0x31,0x82,0x30,0x3A,0x43,0x04, ++ 0xC6,0xFB,0xD9,0x00,0x91,0x05,0x00,0x84,0x38,0xB8,0x86,0x26,0xFE,0xAC,0xC8,0x00, ++ 0x90,0x05,0x80,0xAC,0x06,0x57,0x38,0xF8,0x80,0x26,0xF8,0xA4,0xC8,0x00,0x96,0x05, ++ 0x80,0xA4,0x00,0x1F,0xFE,0x9C,0xC8,0x00,0x90,0x05,0x80,0x9C,0xE3,0xB0,0x35,0x82, ++ 0xE4,0x00,0x34,0x32,0x32,0x02,0xE3,0x00,0x32,0x22,0x44,0x90,0x42,0xD8,0xE2,0x48, ++ 0x90,0x4D,0xC2,0x6C,0x16,0x0A,0xDC,0xC6,0x79,0xFA,0xF6,0xCB,0x48,0x01,0xE8,0x26, ++ 0xC0,0xAC,0x80,0x07,0xF0,0x8F,0x94,0x05,0x83,0xAC,0xF0,0xCB,0x48,0x01,0xE8,0x56, ++ 0x48,0x09,0x88,0x1E,0xC2,0xA4,0x80,0x00,0x80,0xA4,0x00,0x27,0xC0,0xA4,0x80,0x07, ++ 0xF0,0x1F,0x94,0x05,0x85,0xA4,0xF0,0xCB,0x48,0x01,0xE8,0x56,0x48,0x09,0x88,0x1E, ++ 0xC2,0x9C,0x80,0x00,0x80,0x9C,0x00,0x27,0xC0,0x9C,0x80,0x07,0xF0,0xAF,0x93,0x05, ++ 0x80,0x9C,0xF0,0xEC,0x40,0x1D,0x80,0x04,0xC0,0xDC,0x80,0x14,0x40,0xC3,0x81,0x94, ++ 0x48,0xC3,0x81,0x8C,0xC2,0x34,0x81,0x01,0x84,0xD4,0xD0,0x03,0x38,0x00,0x86,0x7E, ++ 0x40,0xC3,0x83,0x84,0x40,0xC3,0x85,0x7C,0x40,0xC3,0x87,0x74,0xC6,0xD4,0xD0,0x03, ++ 0x80,0x5C,0xC0,0xD4,0xD8,0x03,0x80,0x54,0xC2,0xD4,0xD8,0x03,0x80,0x4C,0x00,0x0F, ++ 0x00,0x01,0x80,0x84,0xC0,0x04,0xC9,0xE4,0x80,0xA1,0xC1,0x40,0x80,0x0C,0xC0,0xE4, ++ 0xCA,0x04,0x01,0x00,0xC5,0x00,0x4A,0xCA,0xC0,0x38,0x02,0x01,0x80,0xC4,0x00,0x09, ++ 0x00,0x42,0x85,0xCC,0x00,0x5F,0xC5,0x94,0x38,0x00,0x86,0x0E,0xC0,0xAC,0x00,0x2F, ++ 0xC6,0x8C,0x38,0x00,0x80,0x0E,0xC0,0xA4,0x00,0x07,0xC0,0x9C,0x40,0x01,0xE8,0x66, ++ 0xD0,0x04,0x08,0x01,0xF0,0x8A,0x4A,0x01,0xEC,0x3E,0x10,0x0A,0xD0,0x06,0x30,0x42, ++ 0x40,0x8C,0xD1,0x40,0x91,0x15,0x00,0x94,0x00,0x97,0xD1,0x04,0x0A,0x01,0xF0,0x8A, ++ 0x49,0x01,0xD0,0x5E,0x40,0x01,0xD0,0x2E,0x10,0x0A,0xEC,0x06,0x31,0x42,0x40,0x8C, ++ 0xD1,0x40,0x00,0x84,0x15,0x01,0xF0,0x92,0xC6,0x84,0x38,0x00,0x80,0x06,0xC1,0x14, ++ 0xC4,0x0B,0xD0,0x40,0x90,0x05,0xD8,0x74,0x38,0xD8,0x86,0x36,0xDC,0x4C,0x10,0xC2, ++ 0xE8,0xB6,0xC0,0x4C,0xD1,0x40,0x00,0x84,0x00,0x97,0xD8,0x7C,0x38,0xD8,0x86,0x36, ++ 0xDC,0x54,0x10,0xC2,0xE8,0x66,0xC0,0x54,0xD1,0x40,0x00,0x84,0x00,0x47,0xD8,0x5C, ++ 0x10,0xC2,0xEC,0x2E,0xC0,0x5C,0xD0,0x40,0x00,0x84,0x01,0x0F,0x15,0x01,0xF0,0x92, ++ 0xC0,0x0C,0xC0,0x03,0xD0,0x00,0x94,0x05,0xC8,0xF4,0x48,0x01,0x88,0x06,0xC9,0xBC, ++ 0x10,0x42,0xDC,0xAE,0x40,0x03,0xC9,0xCC,0x18,0x09,0x18,0x42,0x00,0x03,0x69,0x01, ++ 0x83,0x26,0xF0,0x48,0x34,0xD2,0x00,0x52,0x19,0x82,0x00,0x03,0xC4,0x64,0x10,0x2A, ++ 0x93,0x0E,0xE1,0x40,0x31,0xD2,0x40,0x0B,0x00,0x12,0x1C,0x8A,0x00,0x0B,0x01,0xD7, ++ 0xCC,0xB4,0x10,0x42,0xE1,0xBE,0x40,0x03,0xC8,0xCC,0x18,0x42,0x00,0x03,0x01,0x97, ++ 0xC0,0xF4,0x40,0x09,0x89,0x16,0x40,0x84,0x00,0xC4,0x01,0x67,0x41,0xC4,0x41,0x8C, ++ 0xC4,0x00,0x92,0x05,0x00,0xC4,0xC9,0xD4,0xD0,0xF4,0xC0,0x4B,0x10,0x8A,0x8C,0x16, ++ 0x85,0x07,0xE8,0x87,0x00,0x84,0xC9,0x14,0x40,0x84,0x81,0x43,0xE0,0xF8,0xC5,0x0C, ++ 0xE0,0x00,0x82,0x0C,0xE0,0xB0,0xC5,0x14,0xE0,0x00,0x82,0x14,0xC4,0x04,0xE0,0x00, ++ 0x80,0x04,0xC0,0x94,0x40,0x00,0x82,0x94,0xC2,0x8C,0x40,0x00,0x80,0x8C,0xC0,0x84, ++ 0x40,0x01,0x80,0x46,0xC2,0x84,0x40,0x00,0x80,0x84,0xC0,0x7C,0x40,0x00,0x82,0x7C, ++ 0xC2,0x74,0x40,0x00,0x80,0x74,0xC0,0xC4,0xE2,0x00,0x92,0x05,0x80,0xC4,0xC8,0x6C, ++ 0xC4,0xC4,0x10,0x42,0xD2,0x06,0x38,0x77,0x87,0x0D,0xE9,0x85,0xA8,0x85,0x37,0x6A, ++ 0xF0,0x2C,0x30,0x22,0x30,0x8A,0x30,0xFA,0x37,0xC2,0xB9,0xF7,0xF1,0x5F,0x30,0xDA, ++ 0x31,0x92,0x31,0x4A,0x37,0x02,0xB9,0xFF,0xDF,0xB7,0xE9,0x85,0xAC,0xBD,0x87,0x45, ++ 0x33,0x6A,0xD8,0x43,0x87,0x24,0xD0,0x43,0x85,0x1C,0xE0,0x43,0x40,0x29,0x90,0x2E, ++ 0x06,0x01,0x18,0x02,0x18,0x43,0x03,0x01,0x18,0x43,0x05,0x6F,0x02,0x89,0xEE,0x02, ++ 0x38,0x00,0xAA,0x26,0x4D,0x52,0x5A,0x43,0x1B,0x42,0x18,0x43,0x02,0x27,0x48,0x42, ++ 0x5E,0x43,0x1D,0x4A,0x1B,0x42,0x18,0x43,0x39,0x01,0x30,0x42,0x80,0x01,0x85,0x3C, ++ 0xC0,0x01,0x83,0x34,0x00,0xD7,0x03,0x01,0x1B,0x43,0x5F,0x73,0x20,0x01,0x00,0x17, ++ 0x43,0xB0,0xE3,0x20,0x97,0x25,0x3F,0x80,0x88,0x16,0xC0,0x24,0x17,0x22,0x9C,0xBE, ++ 0xC4,0x24,0x10,0x22,0x87,0xDE,0xA3,0x63,0xC1,0x44,0x08,0xE9,0xCA,0x00,0x08,0x48, ++ 0xC1,0x00,0x4A,0xC2,0xEE,0x03,0x08,0x43,0x30,0x12,0x09,0x01,0x00,0x09,0xD8,0x54, ++ 0xBC,0xF7,0xF7,0x8F,0xD0,0x54,0x90,0x04,0x31,0x5A,0x31,0x0A,0x00,0x11,0xD0,0x44, ++ 0xBE,0xF7,0xF7,0xFF,0x42,0x82,0x41,0x0B,0x3F,0x48,0xAA,0xE6,0x40,0x0B,0x10,0x11, ++ 0x18,0x8A,0x00,0x0B,0x40,0x5A,0x09,0x41,0x00,0x0B,0x44,0x0B,0x10,0xF9,0x97,0x19, ++ 0x18,0x8A,0x00,0x0B,0x78,0x01,0x88,0x2E,0x30,0x4A,0xC1,0x44,0xB9,0xFF,0xDF,0x3F, ++ 0x00,0x01,0x80,0x14,0xC3,0x1C,0x18,0x02,0x00,0x08,0xC2,0x44,0xC6,0x40,0x08,0x09, ++ 0x02,0x48,0xC4,0x00,0x81,0x2C,0x00,0x47,0xC6,0x3C,0xE8,0x03,0x40,0x31,0x88,0x36, ++ 0x48,0xE2,0x40,0x43,0x10,0x81,0x18,0x82,0x00,0x43,0x38,0x31,0x07,0x07,0x39,0x80, ++ 0x80,0x9E,0x08,0x09,0x00,0x0A,0x05,0x07,0xFF,0x85,0x59,0x43,0x10,0x42,0x88,0x1E, ++ 0xC6,0x3C,0xE8,0x03,0x47,0x31,0x88,0xBE,0x50,0x15,0xA8,0x04,0x91,0x0C,0x30,0x12, ++ 0x30,0xCA,0xD9,0x44,0xC7,0x2C,0xB8,0xFF,0xE8,0x17,0xC7,0x1C,0xCA,0x2C,0x00,0x00, ++ 0xC0,0x00,0x82,0x2C,0x43,0xB0,0xE3,0x20,0x90,0x25,0xC7,0x24,0x16,0x22,0x9C,0x9E, ++ 0x78,0x01,0x88,0x0E,0xC3,0x14,0x18,0x43,0xE7,0xF8,0x93,0xFD,0xC0,0x34,0xC0,0x03, ++ 0xE5,0x00,0x12,0xC2,0xCB,0x5E,0x38,0xF7,0x58,0x80,0x04,0x01,0x20,0x20,0x07,0x00, ++ 0xAA,0xAA,0xAA,0xAA,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x39,0xFF,0x37,0x52, ++ 0x00,0x01,0xC8,0x54,0xBC,0xF7,0xEF,0x27,0x87,0x5D,0xE8,0x85,0xAC,0xBD,0x87,0x2D, ++ 0x33,0x62,0xD8,0x03,0x87,0x14,0xD0,0x0B,0x88,0x0C,0xC8,0x0C,0xC2,0x14,0x18,0x42, ++ 0xCA,0x2C,0x00,0x10,0xC6,0x90,0x0A,0x09,0x02,0x48,0xC4,0xA8,0xA8,0x24,0xC8,0x2C, ++ 0x8A,0xA1,0xC1,0x30,0xCF,0x2C,0x88,0xF9,0x8A,0x29,0xC1,0x38,0xB8,0x1C,0xC8,0x2C, ++ 0xC0,0x14,0xC0,0x40,0x0A,0xE9,0x09,0x48,0xC0,0x00,0xEA,0x03,0x4E,0xFA,0x0F,0x43, ++ 0xD0,0x3C,0x90,0x04,0x30,0x1A,0x09,0x01,0x00,0x09,0xD0,0x2C,0xBA,0xF7,0xF7,0x4F, ++ 0x30,0x12,0x01,0x11,0xCF,0x3C,0xB8,0xF7,0xE8,0x9F,0x0A,0x01,0x00,0x09,0xD8,0x3C, ++ 0xD7,0x14,0xB8,0xF7,0xE8,0x47,0xD7,0x3C,0x91,0x04,0x30,0x1A,0x00,0x11,0xD0,0x2C, ++ 0xCF,0x14,0xB8,0xF7,0xF0,0xB7,0xD1,0x3C,0x92,0x04,0x00,0x29,0xE9,0x0A,0x30,0x1A, ++ 0x11,0x01,0x30,0x42,0xBF,0xFF,0xF7,0x97,0x08,0x09,0x30,0x42,0xD8,0x3C,0xD0,0x14, ++ 0xBE,0xF7,0xEF,0x8F,0xD0,0x3C,0x90,0x04,0x30,0x1A,0x01,0x19,0xD0,0x2C,0xC8,0x14, ++ 0xB8,0xF7,0xF7,0xFF,0x30,0x12,0x01,0x01,0xCF,0x3C,0xB8,0xF7,0xE8,0x4F,0xD1,0x3C, ++ 0x90,0x04,0x08,0x01,0x30,0x1A,0x31,0x42,0xD7,0x2C,0xB8,0xF7,0xF5,0x97,0xE0,0x03, ++ 0x40,0x29,0xC0,0x96,0x00,0x01,0x08,0x01,0x05,0x67,0xD8,0x13,0x10,0x12,0xC4,0x06, ++ 0x01,0x4C,0x41,0x54,0x81,0x93,0x41,0x54,0x83,0xD3,0xE1,0xF8,0xE5,0xB0,0xE3,0x68, ++ 0xE6,0x00,0x92,0x05,0xD4,0x0C,0x10,0x82,0x98,0x7E,0xCF,0x1C,0xC0,0x24,0x10,0x01, ++ 0x00,0x57,0x40,0x1C,0xC2,0x6B,0xC8,0xD8,0x92,0xDD,0x80,0xD8,0x00,0x1C,0x80,0x5B, ++ 0xE4,0x48,0xE2,0x00,0xE6,0x90,0x92,0x95,0xDC,0x1B,0x15,0x9A,0xC0,0x8E,0x87,0x45, ++ 0xEB,0x85,0xAF,0x85,0x35,0x42,0x80,0xC1,0x34,0x6A,0xA8,0x01,0x5F,0x53,0x51,0x73, ++ 0x53,0x5B,0x55,0x63,0xE0,0x6B,0x69,0x01,0x81,0xD6,0x32,0x2A,0x19,0xEA,0x18,0xAA, ++ 0x18,0xAA,0x80,0x0E,0x28,0x19,0x80,0x2B,0xC0,0x2B,0x68,0x01,0x83,0x0E,0xF0,0x68, ++ 0x81,0x2B,0x30,0x2A,0x10,0xAA,0x80,0x26,0x30,0xEA,0x10,0xAA,0x88,0x0E,0x10,0x09, ++ 0x01,0x97,0x30,0x2A,0x10,0xAA,0x81,0x26,0x30,0xEA,0x10,0xAA,0x88,0x0E,0x10,0x11, ++ 0x00,0x57,0x60,0x01,0x80,0x1E,0x10,0x9A,0x88,0x0E,0x10,0x79,0x01,0x27,0x10,0x9A, ++ 0x80,0x0E,0x10,0x21,0x00,0x07,0x10,0x01,0xC8,0x1B,0x24,0x01,0x10,0x9A,0x8C,0x0E, ++ 0x50,0x01,0x88,0x0E,0x01,0x24,0x04,0x57,0x40,0x1C,0x2C,0xC9,0x0D,0x68,0x13,0x5A, ++ 0x92,0x0E,0xE0,0xD8,0x00,0x1C,0x34,0x5A,0x2D,0x09,0x98,0x01,0x50,0x11,0x80,0x26, ++ 0xE0,0x8E,0x50,0x01,0x80,0xDE,0x50,0x09,0x8C,0xCE,0x40,0x34,0x70,0xE1,0xC9,0xB6, ++ 0xF0,0xDB,0x5A,0x51,0x90,0x9E,0x30,0x5A,0x98,0x01,0xE6,0xF3,0x18,0x72,0xA1,0xF3, ++ 0xA4,0x6B,0x04,0x24,0x00,0x5F,0x50,0x21,0x80,0x4E,0x50,0x79,0x8C,0x3E,0x40,0x34, ++ 0x70,0xE1,0xC9,0x26,0xF0,0xDB,0x5A,0x51,0x94,0x0E,0xA0,0x6B,0x04,0x24,0x8C,0x13, ++ 0xEF,0x85,0xAB,0x9D,0x80,0x4D,0x34,0x32,0xC4,0x54,0xD0,0x03,0x80,0x3C,0xC0,0x54, ++ 0xD0,0x03,0x86,0x34,0xC0,0x54,0xE8,0x03,0x43,0xF1,0x98,0x8E,0xC5,0x54,0x80,0x01, ++ 0xF0,0x03,0x40,0x01,0x88,0x66,0xC3,0x54,0xCA,0x03,0x34,0x00,0x70,0x00,0x80,0x2C, ++ 0x04,0x09,0x06,0x00,0xC1,0xB8,0x31,0xA2,0xA1,0xA1,0x01,0x81,0xF7,0x82,0x41,0x81, ++ 0xDF,0x26,0xC0,0x81,0x30,0x84,0x01,0x09,0x80,0x24,0x00,0x0F,0x00,0x01,0x80,0x24, ++ 0x01,0x91,0xF1,0x82,0x0E,0x79,0x1F,0x4A,0x10,0x42,0xE4,0x26,0x83,0x81,0x37,0x84, ++ 0x00,0x09,0x80,0x1C,0x00,0x0F,0x00,0x01,0x83,0x1C,0x40,0xEA,0x82,0x14,0x10,0x02, ++ 0x80,0x0C,0x00,0x01,0x81,0x44,0x00,0xBF,0x29,0x01,0x00,0x77,0x01,0x01,0xF0,0xC2, ++ 0xCC,0x2C,0x10,0x42,0xD0,0xCE,0x40,0x01,0xE8,0x56,0xC8,0x14,0x10,0x42,0xEC,0x06, ++ 0x80,0x14,0xC0,0x24,0x40,0x01,0x80,0xE6,0xC2,0x03,0xF1,0x00,0x80,0x03,0x01,0xC7, ++ 0x40,0x01,0xD0,0xB6,0xCC,0x0C,0x10,0x42,0xD0,0x06,0x80,0x0C,0xC0,0x1C,0x40,0x01, ++ 0x81,0x7E,0xC0,0x03,0xE1,0x00,0x82,0x03,0x00,0x5F,0xC0,0x54,0x08,0x21,0xEB,0x03, ++ 0x83,0x07,0xD8,0x47,0x48,0x19,0x8B,0x26,0xC9,0x2C,0xC0,0x03,0x42,0x48,0xD2,0x00, ++ 0x85,0x03,0xE1,0xF8,0xE3,0x20,0xE3,0x68,0x90,0x6D,0xC7,0x34,0x16,0x2A,0x9C,0x6E, ++ 0xC2,0x44,0xE0,0x00,0x90,0x05,0x86,0x44,0xC8,0x3C,0xC0,0x44,0x16,0x42,0x9C,0x1E, ++ 0x70,0x8C,0xC1,0x14,0xC1,0x40,0x30,0x84,0x70,0x8C,0xC3,0x0C,0xC3,0x40,0x30,0x84, ++ 0x37,0x57,0xAC,0xBD,0x80,0x15,0x34,0x62,0x37,0xBA,0xE0,0x2B,0xDF,0x33,0xD3,0x03, ++ 0x1A,0x42,0x03,0x08,0xC0,0x14,0xC0,0x40,0x0C,0x09,0x06,0x48,0xC0,0x00,0x82,0x0C, ++ 0x36,0x02,0x81,0x01,0xE4,0x0B,0x10,0x01,0x18,0x8A,0xA0,0x0B,0x00,0xB1,0xED,0x02, ++ 0x42,0x01,0x80,0x46,0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42,0xBC,0xF7,0xE7,0x5F, ++ 0x30,0x1A,0xB9,0x04,0x08,0x01,0x00,0x19,0xD7,0x14,0xB8,0xF7,0xE2,0xD7,0x06,0x29, ++ 0xE9,0x0A,0x30,0x1A,0x30,0xD2,0xC1,0x0C,0xBE,0xFF,0xC7,0xEF,0x58,0x03,0x17,0x09, ++ 0x35,0x8A,0x00,0x4A,0x1F,0x42,0x18,0x03,0xE7,0x68,0x93,0x6D,0x58,0x0B,0x03,0x0F, ++ 0xE7,0x68,0x93,0x6D,0x35,0x82,0x00,0x42,0x10,0x0A,0x88,0x0E,0x17,0xAA,0x9D,0xBE, ++ 0x11,0xAA,0x85,0x06,0xA1,0x2B,0x37,0xDA,0x30,0x52,0x09,0x01,0x07,0x09,0xB8,0xF7, ++ 0xE1,0x17,0x33,0x1A,0xB9,0x04,0x30,0x4A,0x00,0x11,0xD0,0x14,0xBD,0xF7,0xE7,0x8F, ++ 0xC1,0x14,0x08,0xE9,0xCA,0x00,0x0A,0x48,0xC1,0x00,0x52,0x62,0xEE,0x03,0x08,0x83, ++ 0x42,0x62,0x41,0x0B,0x3F,0x48,0xAA,0xE6,0x04,0x41,0x00,0x83,0x47,0x83,0x08,0xF9, ++ 0x88,0x19,0x18,0x42,0x00,0x83,0x80,0x2D,0xEF,0x85,0xAF,0x85,0x84,0xBD,0x34,0x22, ++ 0x37,0x6A,0xD0,0x7B,0xD0,0x43,0x85,0x6C,0x31,0x1A,0x9B,0xA1,0x9C,0xB4,0x08,0x29, ++ 0x34,0x02,0x03,0x48,0xC6,0x20,0x0A,0x09,0x03,0x48,0x24,0x0A,0x8B,0xAC,0xC8,0x43, ++ 0x02,0x00,0x92,0x05,0x80,0x2C,0x00,0x01,0x80,0x24,0x00,0x09,0x81,0x14,0x30,0x42, ++ 0x80,0x01,0x86,0xA4,0xE3,0x03,0x5A,0x73,0x32,0x32,0x3C,0x10,0x58,0x43,0x1D,0x32, ++ 0x50,0x01,0xD0,0x46,0x40,0xA2,0x18,0x32,0xB3,0x1C,0x30,0x82,0x10,0xD9,0x07,0x82, ++ 0xD2,0xA4,0xA0,0x83,0x00,0x47,0x40,0x82,0x18,0x02,0x1E,0x32,0xB3,0x1C,0x30,0x82, ++ 0x10,0x21,0x18,0x82,0xD2,0xA4,0xA0,0x83,0x35,0x01,0x18,0x73,0xD8,0x43,0x45,0x01, ++ 0x80,0x36,0xD0,0x6C,0xC2,0x14,0xF0,0x90,0x00,0x82,0xD4,0x1C,0x18,0x82,0x80,0x1C, ++ 0x34,0x52,0x91,0x01,0x92,0x9C,0xF0,0x83,0x80,0x8C,0x00,0x3F,0x00,0x01,0x00,0x42, ++ 0xC7,0x87,0xF9,0xFF,0x18,0x00,0x04,0x42,0xAA,0xAA,0xAA,0xAA,0xC0,0x9C,0x10,0xC1, ++ 0xB0,0x12,0x94,0x84,0xD0,0x9C,0x00,0x01,0x18,0x83,0x80,0x7C,0xD6,0x9C,0x10,0x83, ++ 0x80,0x74,0x10,0x01,0x97,0x64,0x50,0xFA,0x90,0x5C,0x10,0x01,0x91,0x54,0x30,0x72, ++ 0xB5,0x01,0x99,0x83,0xCA,0x43,0x45,0x00,0x85,0x4C,0x10,0xA1,0xFA,0x82,0x82,0x00, ++ 0x85,0x44,0xE0,0x43,0x40,0x29,0xC0,0xCE,0x03,0x01,0x30,0x12,0x32,0x84,0x30,0x84, ++ 0x30,0x22,0x04,0x87,0x10,0x01,0x00,0x47,0x41,0x44,0x80,0x03,0x40,0x44,0x80,0xC3, ++ 0xE4,0xD8,0xE2,0x48,0xE2,0x20,0xE3,0x90,0x95,0x95,0x12,0xD2,0xDB,0xA6,0x37,0x02, ++ 0xE2,0x00,0x92,0x05,0x30,0x22,0xC4,0x6C,0x2F,0x22,0xDC,0x5E,0xC0,0xB4,0x80,0x3C, ++ 0xE0,0xAC,0x00,0x01,0x85,0x94,0x00,0xBF,0x00,0x01,0x80,0x34,0x30,0x32,0xCC,0x94, ++ 0xC4,0x14,0x00,0x42,0xC8,0x1C,0x10,0x42,0x80,0x86,0x03,0x01,0x32,0x22,0x04,0xEF, ++ 0xC1,0x3C,0x40,0x0C,0xC2,0x03,0xD0,0x00,0x91,0x05,0x00,0x04,0xCA,0x9C,0xE0,0x4B, ++ 0x48,0x11,0x98,0xA6,0xCC,0x84,0x10,0x42,0xD5,0x8E,0xD8,0x8B,0xE5,0x48,0x9A,0x8B, ++ 0xC8,0x64,0xC0,0x48,0x88,0x64,0xD8,0x5C,0x34,0x12,0x10,0x1A,0xD8,0x06,0xD0,0x5C, ++ 0x90,0x5C,0xD8,0x54,0x34,0x12,0x10,0x1A,0xE0,0x06,0xD0,0x54,0x90,0x54,0xC8,0x2C, ++ 0x10,0x42,0xD4,0x3E,0x32,0x8A,0xE3,0x48,0x94,0x4D,0x36,0x72,0xC8,0x34,0xC0,0x48, ++ 0x90,0x4D,0x88,0x34,0xCC,0x4C,0x10,0x42,0xEB,0xBE,0xC8,0x4B,0x10,0x0A,0xE4,0x2E, ++ 0xDD,0x94,0x58,0x53,0x0C,0x09,0x00,0xCA,0x1D,0x52,0x18,0x53,0xE0,0x8B,0x4B,0x09, ++ 0x8C,0x0E,0x08,0x09,0xA0,0x8B,0xCB,0x8C,0x10,0x42,0xEC,0xBE,0x30,0x02,0x0B,0x09, ++ 0x00,0x0A,0xC4,0x7C,0x18,0x0A,0x88,0x7C,0x00,0x87,0xC8,0x44,0x10,0x42,0xD4,0x6E, ++ 0xE0,0x8B,0x4B,0x09,0x8C,0x0E,0x08,0x09,0xA0,0x8B,0xCB,0x84,0x10,0x42,0xD4,0x2E, ++ 0x30,0x02,0x0B,0x09,0x00,0x0A,0xC4,0x74,0x18,0x0A,0x88,0x74,0xE0,0x20,0xC5,0x3C, ++ 0xE0,0x00,0x82,0x3C,0x32,0x02,0xE3,0x00,0x94,0x05,0x32,0x22,0x2C,0xE2,0xDD,0xFE, ++ 0x30,0x82,0x43,0x11,0xCB,0x2E,0x30,0x8A,0xC0,0x34,0x80,0x07,0xC8,0x6F,0x97,0x05, ++ 0x00,0x07,0x00,0x01,0x03,0xC8,0xD3,0x20,0x11,0x01,0x00,0x57,0x00,0x67,0x41,0x01, ++ 0xE8,0x7E,0x08,0x01,0xF0,0x0A,0xDB,0x2C,0x10,0xCA,0xD4,0xB6,0xE4,0x18,0x12,0xCA, ++ 0xE8,0x16,0xD0,0x48,0x00,0x0C,0x01,0x87,0x48,0x01,0xE8,0x76,0x09,0x09,0x00,0x0C, ++ 0x00,0x5F,0x08,0x01,0xF4,0x0A,0x13,0x0A,0xD0,0x16,0xD0,0x48,0x00,0x0C,0x01,0x27, ++ 0x48,0x01,0xD0,0x16,0x0E,0x01,0x18,0x4A,0x00,0x0C,0x09,0x01,0xF0,0x0A,0xDB,0x44, ++ 0x10,0xCA,0xD4,0x1E,0xCA,0x24,0xE0,0x48,0x90,0x4D,0x8E,0x24,0xE2,0x20,0xE5,0x90, ++ 0x95,0x95,0x12,0xD2,0xD8,0x9E,0x06,0x5F,0x00,0x01,0x08,0x01,0x01,0x37,0x00,0x0C, ++ 0xE0,0x20,0xD5,0x3C,0xE0,0x90,0x92,0x3C,0xE2,0x00,0x92,0x05,0x17,0xC2,0xDD,0xB6, ++ 0xC2,0x94,0xE0,0x00,0x90,0x05,0x82,0x94,0xC8,0x6C,0xC0,0x94,0x10,0x42,0xD4,0x06, ++ 0x39,0x17,0xCA,0x43,0x40,0x71,0xC9,0x0E,0x01,0x71,0x89,0x43,0xC9,0x24,0xC8,0x43, ++ 0x42,0x48,0xC4,0x00,0x91,0x05,0x8E,0x43,0x40,0x81,0xCA,0x0E,0x01,0x81,0x8A,0x43, ++ 0xC2,0x9C,0xE0,0x03,0x42,0x11,0x98,0x56,0xD8,0x83,0x45,0x11,0xCC,0x3E,0xF2,0x00, ++ 0x90,0x05,0x86,0x04,0xC8,0x54,0xC0,0x5C,0xC0,0x08,0xC2,0x64,0xD0,0x00,0xCA,0x04, ++ 0x84,0x07,0xC8,0x17,0x90,0x05,0x80,0x0C,0x05,0x01,0x28,0x44,0x08,0xE9,0x0B,0x48, ++ 0x10,0x01,0xE0,0xAC,0x31,0x22,0x04,0x0F,0x18,0x01,0x00,0xCF,0x01,0x01,0xF0,0x02, ++ 0xF5,0x84,0x10,0x82,0xD0,0x8E,0xF0,0x0C,0xD8,0x00,0xAC,0x06,0x10,0x02,0x92,0x05, ++ 0x34,0x32,0x10,0x0A,0xE0,0x06,0x30,0x72,0x30,0x8A,0x31,0x32,0x10,0x12,0xDC,0x06, ++ 0x31,0xB2,0x30,0x92,0x69,0x74,0xC5,0x80,0x2D,0x44,0xE5,0x20,0xE2,0xD8,0x92,0xDD, ++ 0x17,0xDA,0xDD,0x1E,0x32,0x02,0xE3,0x00,0x94,0x05,0x32,0x22,0xDC,0x6C,0x28,0xE2, ++ 0xDD,0xD6,0x6E,0x44,0xC2,0x48,0xD4,0x00,0x90,0x05,0xCC,0x04,0x82,0x07,0xC8,0x17, ++ 0x28,0x44,0xC5,0x0C,0x40,0x01,0xD0,0x06,0x13,0x02,0x2A,0x44,0x00,0x17,0x00,0x01, ++ 0x2D,0x44,0x2B,0x44,0xC8,0x9C,0xC0,0x7C,0x18,0x43,0xC8,0x9C,0xC6,0x74,0x10,0x43, ++ 0x87,0xBD,0xE8,0x85,0xAC,0xBD,0x87,0x15,0x32,0x62,0x70,0x9A,0x29,0x01,0x80,0xAB, ++ 0x09,0x11,0x30,0x02,0x80,0x01,0x35,0x3A,0xA9,0x0B,0x34,0x0A,0xD0,0x24,0xC0,0x14, ++ 0xBD,0xFF,0xDF,0x67,0xAD,0xEB,0xDD,0x03,0x40,0x01,0x80,0x76,0x6F,0x5A,0x42,0x43, ++ 0x91,0x3D,0x4C,0x04,0x00,0x43,0x07,0x09,0x81,0x83,0x31,0x0A,0xD0,0x24,0xC0,0x14, ++ 0xBA,0xFF,0xE7,0xA7,0x01,0x01,0x80,0x83,0x00,0x7B,0xD7,0x24,0x90,0x04,0x08,0x01, ++ 0x30,0x1A,0x31,0x42,0xD7,0x14,0xB8,0xF7,0xD5,0xE7,0xE5,0x03,0x40,0x41,0x96,0x0E, ++ 0xE5,0x00,0xA2,0x03,0x30,0xBF,0x10,0x01,0x00,0x37,0x08,0x01,0xE4,0x48,0x92,0x4D, ++ 0x4F,0xA1,0xC8,0xDE,0xE4,0x90,0x92,0x95,0x17,0x12,0xCC,0xB6,0x38,0x82,0x3B,0x18, ++ 0x78,0xD8,0x10,0x09,0x06,0xD2,0x94,0x95,0x18,0xF9,0x0F,0xD8,0x01,0xC2,0x58,0xA2, ++ 0xC0,0x00,0x4E,0x09,0x88,0x66,0x40,0x0B,0x18,0x8A,0x04,0x0B,0x44,0x0B,0x1A,0x8A, ++ 0x04,0x0B,0x42,0x0B,0x1C,0x8A,0x04,0x0B,0x44,0x0B,0x1E,0x8A,0x03,0x0B,0x3E,0x82, ++ 0x48,0x01,0x88,0x66,0x44,0x0B,0x1A,0x8A,0x04,0x0B,0x42,0x0B,0x1C,0x8A,0x04,0x0B, ++ 0x44,0x0B,0x1E,0x8A,0x00,0x0B,0x46,0x0B,0x18,0x8A,0x00,0x0B,0x38,0x82,0x4B,0x11, ++ 0x88,0x66,0x40,0x0B,0x18,0x8A,0x04,0x0B,0x44,0x0B,0x1A,0x8A,0x04,0x0B,0x42,0x0B, ++ 0x1C,0x8A,0x04,0x0B,0x40,0x0B,0x1E,0x8A,0x03,0x0B,0x3E,0x82,0x4F,0x19,0x88,0xE6, ++ 0x44,0x0B,0x18,0x8A,0x04,0x0B,0x40,0x0B,0x1C,0x8A,0x04,0x0B,0x44,0x0B,0x1E,0x8A, ++ 0x02,0x0B,0x46,0x0B,0x1A,0x8A,0x00,0x0B,0x3F,0x82,0xAB,0x8D,0x80,0x3D,0xC4,0x3C, ++ 0xC8,0x3C,0x48,0x00,0x02,0x00,0xC4,0x00,0x38,0x00,0x48,0x92,0x72,0x00,0xC2,0x28, ++ 0x40,0x72,0x40,0x0B,0x90,0x4D,0x8C,0x34,0x5C,0x0B,0x90,0x4D,0x8A,0x2C,0x58,0x0B, ++ 0x90,0x4D,0x8C,0x24,0x5C,0x0B,0x94,0x4D,0x8E,0x1C,0x50,0x0B,0x90,0x75,0x4C,0x52, ++ 0x44,0x53,0x92,0x95,0x90,0x14,0x40,0x53,0x92,0xBD,0x44,0x13,0x90,0x95,0x94,0x0C, ++ 0x58,0x12,0x00,0x5F,0xE7,0xC7,0xF8,0xFF,0x00,0xB0,0x00,0x01,0x00,0x01,0x00,0x42, ++ 0x80,0x00,0x00,0x42,0x08,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x98,0x01,0x52,0xD3, ++ 0x90,0x95,0x94,0x04,0x10,0x09,0x00,0x13,0xA8,0x10,0x1C,0x13,0x12,0x81,0x18,0x13, ++ 0x18,0x13,0x14,0x79,0x11,0x13,0x16,0x01,0x00,0x53,0x12,0x89,0x02,0x53,0x40,0x0B, ++ 0x10,0x81,0x19,0x8A,0x07,0x0B,0x02,0xF9,0x80,0x89,0x17,0xC3,0x07,0x09,0xB8,0xFF, ++ 0xFF,0x17,0x03,0xF9,0x80,0x89,0x14,0xC3,0x07,0x09,0xB8,0xFF,0xF8,0xE7,0x02,0x19, ++ 0x11,0x00,0x00,0x43,0x07,0x09,0xB8,0xFF,0xF8,0xB7,0x0A,0x11,0xC7,0x3C,0xB8,0xFF, ++ 0xF8,0xF7,0x22,0xA1,0x01,0x01,0x40,0x4B,0x30,0x48,0xA8,0x16,0xE7,0x20,0x93,0x25, ++ 0x03,0x0F,0xF0,0x20,0x92,0x25,0xE7,0x00,0x90,0x05,0x46,0x51,0x98,0x9E,0x0F,0x09, ++ 0xC7,0x3C,0xB8,0xFF,0xF8,0x67,0x42,0x6A,0xC8,0x34,0x00,0x0B,0xC8,0x2C,0x18,0x0B, ++ 0xCA,0x24,0x18,0x0B,0xCC,0x1C,0x18,0x0B,0x10,0x33,0x4E,0x4A,0xD2,0x14,0x00,0x53, ++ 0x00,0x7B,0xC8,0x0C,0x00,0x0B,0x4A,0x2A,0xC2,0x04,0x88,0x01,0x10,0x43,0x60,0xA1, ++ 0xC8,0x16,0x00,0x09,0x87,0x45,0xE8,0x85,0x07,0x01,0x38,0xDF,0x00,0x01,0x00,0x42, ++ 0x18,0x00,0x04,0x42,0x00,0x0F,0x00,0x26,0xF8,0x48,0x48,0x21,0x94,0xDE,0x3F,0x58, ++ 0xA8,0x0E,0x00,0x14,0xE6,0x00,0x3C,0x48,0x80,0x06,0x80,0x13,0x38,0x82,0x4B,0x01, ++ 0x86,0x5E,0x38,0x18,0x80,0x16,0x80,0x13,0xE2,0x00,0xF2,0x48,0x48,0x11,0x98,0x26, ++ 0x38,0x18,0xAC,0x16,0x04,0x14,0xE0,0x00,0xF7,0x48,0x3C,0x1F,0x17,0x01,0x38,0x77, ++ 0x16,0x01,0x38,0xFF,0x10,0x01,0x48,0x18,0x11,0x5A,0x9C,0x66,0x54,0x18,0x10,0x5A, ++ 0x98,0x8E,0x18,0x01,0x32,0xE2,0x04,0x77,0x30,0x1A,0x18,0x5A,0xA0,0xE6,0x11,0x01, ++ 0x44,0x18,0x12,0x5A,0x98,0x8E,0x49,0x18,0x10,0x5A,0x9C,0xE6,0x54,0x18,0x10,0x5A, ++ 0x9C,0x0E,0x30,0xA2,0x06,0xFF,0x49,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD6,0x00, ++ 0x0C,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD4,0x00,0x0A,0x92,0x4A,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD2,0x00,0x08,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x0E,0x58,0xD0,0x00,0x0E,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD6,0x00, ++ 0x0C,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD4,0x00,0x0A,0x92,0x42,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A, ++ 0x08,0x92,0x32,0x82,0x3A,0x82,0x03,0xEF,0x78,0x50,0x86,0x06,0x10,0x4A,0x82,0x18, ++ 0x9A,0x06,0x10,0x02,0x00,0x9A,0x12,0x01,0x30,0xE2,0x4C,0x18,0x11,0x5A,0x9C,0x6E, ++ 0x54,0x18,0x10,0x5A,0x9F,0x96,0x10,0xE1,0x08,0x48,0xD4,0x95,0x54,0x18,0x10,0x5A, ++ 0x9C,0x66,0x08,0x48,0x8C,0x90,0x14,0x5A,0x9C,0x46,0x08,0x48,0x8C,0x90,0x14,0x5A, ++ 0x9C,0x26,0x08,0x48,0x84,0xD6,0x89,0x90,0x04,0x07,0x48,0x48,0x4C,0x18,0x16,0x5A, ++ 0x9E,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x14,0x5A,0x9C,0x0E,0x08,0x58, ++ 0xD2,0x00,0x0E,0x92,0x4C,0x18,0x12,0x5A,0x9A,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92, ++ 0x4C,0x18,0x10,0x5A,0x98,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x44,0x18,0x16,0x5A, ++ 0x9E,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92,0x44,0x18,0x14,0x5A,0x9C,0x0E,0x00,0x58, ++ 0xD2,0x00,0x0E,0x92,0x92,0xCE,0x46,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00, ++ 0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A,0x32,0x1A,0x0B,0x92,0x80,0xD8,0x32,0x82, ++ 0x9A,0x0E,0x10,0x02,0x58,0x01,0xA8,0x06,0x13,0x4A,0x3A,0x82,0x32,0x1A,0x83,0xD8, ++ 0x9A,0x06,0x10,0x02,0xA8,0x0D,0x00,0x01,0x36,0x02,0x36,0x02,0xEB,0x15,0x30,0xAA, ++ 0x81,0x07,0xC0,0x17,0x30,0x72,0x05,0x28,0x32,0x4A,0x33,0x9A,0x46,0x00,0x06,0x00, ++ 0x30,0x2A,0x84,0xC5,0xAF,0x05,0xB9,0xDF,0xEB,0xBF,0xE6,0x05,0x3A,0x01,0x40,0x48, ++ 0x30,0xB2,0x35,0x01,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06, ++ 0x2E,0x06,0x2E,0x06,0xEA,0x01,0x02,0x48,0x33,0x6A,0x3C,0x82,0x36,0x22,0x30,0x02, ++ 0x31,0x02,0x36,0x02,0xB8,0xD7,0xDF,0xFF,0x43,0x02,0x38,0x82,0x58,0x60,0x05,0x01, ++ 0x40,0x12,0x48,0x1A,0xF3,0x5D,0x3D,0x82,0x00,0x68,0x00,0x00,0x00,0xC0,0x00,0x00, ++ 0x00,0x30,0x01,0x10,0x39,0x82,0xA3,0x85,0x33,0xA2,0xF3,0x20,0xC3,0x2B,0xE1,0x20, ++ 0x10,0x5A,0x95,0x06,0x33,0xEA,0xE8,0x1A,0x07,0xD8,0xC2,0x18,0xE0,0x85,0x39,0xC2, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x20,0x01,0x42, ++ 0x80,0x20,0x01,0x42,0x80,0x20,0x01,0x42,0x80,0x20,0x01,0x42,0x80,0x20,0x03,0x42, ++ 0x80,0xA0,0x00,0x42,0x80,0x20,0x03,0x42,0x80,0xA0,0x00,0x42,0x80,0x20,0x03,0x42, ++ 0x80,0xA0,0x00,0x42,0x80,0x20,0x03,0x42,0x80,0xA0,0x00,0x42,0x80,0xA0,0x03,0x42, ++ 0x80,0x20,0x00,0x42,0x80,0xA0,0x03,0x42,0x80,0xA0,0x03,0x42,0x80,0x20,0x04,0x42, ++ 0x80,0x20,0x04,0x42,0x80,0x20,0x04,0x42,0x80,0xA0,0x04,0x42,0x10,0x20,0x08,0x40, ++ 0x40,0x08,0x20,0x10,0x10,0x20,0x08,0x40,0x20,0x08,0x40,0x20,0x20,0x10,0x08,0x40, ++ 0x08,0x81,0x03,0x42,0x08,0xC1,0x03,0x42,0x08,0x41,0x00,0x42,0x08,0x81,0x00,0x42, ++ 0x08,0xC1,0x00,0x42,0x08,0x01,0x01,0x42,0x08,0x81,0x02,0x42,0x08,0x41,0x02,0x42, ++ 0x08,0xC1,0x02,0x42,0x08,0x01,0x02,0x42,0x08,0x01,0x02,0x42,0x08,0xC1,0x01,0x42, ++ 0x08,0x41,0x02,0x42,0x08,0x81,0x01,0x42,0x08,0x81,0x02,0x42,0x08,0x41,0x01,0x42, ++ 0x08,0xC1,0x02,0x42,0x08,0x01,0x01,0x42,0x08,0x01,0x03,0x42,0x08,0x81,0x00,0x42, ++ 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00, ++ 0x00,0x08,0xF8,0x0F,0xFF,0x07,0xF8,0xFF,0x07,0xF8,0x0F,0xF8,0x08,0x00,0x08,0x08, ++ 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x28,0xB5,0x39,0xC5,0x08,0x1D, ++ 0x1B,0x2B,0x3A,0x28,0x53,0xB5,0x0A,0xC5,0x00,0x08,0x01,0x00,0x01,0x00,0x50,0x0D, ++ 0x52,0x1D,0x52,0xB5,0x39,0x0D,0x04,0x08,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95, ++ 0x51,0x3D,0x54,0x95,0x51,0x3D,0x54,0x95,0x0B,0x3D,0x34,0x88,0x51,0x3D,0x54,0x1D, ++ 0x51,0x3D,0x54,0x95,0x04,0x00,0x50,0x3D,0x50,0x1D,0x01,0x00,0x00,0x00,0x00,0x00, ++ 0x54,0x2D,0x53,0x3D,0x32,0x8D,0x32,0x38,0x01,0x28,0x0A,0x45,0x50,0xB5,0x53,0x95, ++ 0x00,0x00,0x00,0x00,0x52,0xA5,0x51,0xB5,0x09,0xC5,0x03,0x08,0x03,0x00,0x50,0x3D, ++ 0x55,0x1D,0x51,0x0D,0x51,0x3D,0x54,0x95,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95, ++ 0x51,0x0D,0x55,0x0D,0x54,0xB5,0x3A,0x0D,0x00,0x08,0x01,0x00,0x53,0xA5,0x51,0x2D, ++ 0x52,0x3D,0x34,0x8A,0x1D,0x38,0x52,0x45,0x52,0x0D,0x51,0x1D,0x54,0xB5,0x3A,0x0D, ++ 0x53,0xA5,0x29,0xB5,0x39,0xC5,0x08,0x1D,0x19,0x2D,0x22,0x1D,0x44,0x0D,0x31,0x3D, ++ 0x23,0x95,0x09,0xC1,0x29,0xB5,0x0B,0x1D,0x1B,0x2B,0x3A,0x28,0x00,0x00,0x00,0x08, ++ 0xFF,0x07,0x00,0xF8,0x08,0x00,0x10,0x10,0x08,0x10,0x10,0x10,0x08,0x08,0x10,0x08, ++ 0x10,0x08,0x10,0x08,0x10,0x10,0x08,0x08,0x10,0x10,0x08,0x08,0x08,0x08,0x10,0x10, ++ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xF8,0x07, ++ 0x08,0x00,0x08,0x08,0xE8,0xA2,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0xC0,0x00,0x00, ++ 0x00,0x00,0x05,0x00,0xE8,0x62,0x02,0x00,0x00,0xC0,0x00,0x01,0x58,0xA0,0x07,0x00, ++ 0x00,0xE0,0x05,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,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0x00,0x70,0x00,0x30,0x09,0x40,0x1B,0x00,0x06,0x78,0x50,0x56, ++ 0xFF,0xFF,0xFF,0xFF,0x3C,0x50,0x00,0x10,0x00,0x20,0x18,0x00,0x1E,0xAC,0xE4,0x09, ++ 0x0F,0x00,0xCA,0xCA,0xFF,0xFF,0xFF,0xFF,0x0A,0x07,0x82,0x00,0x04,0x00,0x00,0x03, ++ 0x95,0x83,0xC1,0x3C,0xC8,0xB2,0xB5,0x47 ++}; ++ ++ ++ ++#define FW_INFO_SIZE (0x18) ++#define FW_REAL_SIZE (sizeof(fwbin)) ++#define FW_BIN_SIZE (24*1024+24) //24K byte ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/cst3xx.c b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/cst3xx.c +new file mode 100644 +index 000000000..3120bafe3 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/cst3xx.c +@@ -0,0 +1,1437 @@ ++/* ++ * cst3xx Touchscreen Controller Driver ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../../video/jz_fb_v13/jz_fb.h" ++ ++struct st1615_ts_finger { ++ u16 x; ++ u16 y; ++ u8 t; ++ bool is_valid; ++}; ++ ++struct cst3xx_ts_data { ++ struct i2c_client *client; ++ struct input_dev *input_dev; ++ struct cst3xx_platform_data *pdata; ++ struct work_struct work; ++ struct delayed_work dwork; ++ struct workqueue_struct *workqueue; ++ int irq; ++}; ++ ++static int cst3xx_into_program_mode(struct i2c_client * client); ++static int cst3xx_erase_program_area(struct i2c_client * client); ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms); ++static int cst3xx_write_program_data(struct i2c_client * client,const unsigned char *pdata); ++ ++static int cst3xx_check_checksum(struct i2c_client * client); ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client); ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata); ++ ++static int cst3xx_firmware_info(struct i2c_client * client); ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict); ++ ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata); ++ ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_test(struct i2c_client *client); ++static void cst3xx_reset(struct cst3xx_ts_data *ts) ; ++extern void close_vcc3v3Power(void); ++extern void open_vcc3v3Power(void); ++ ++static unsigned char *pcst3xx_update_firmware = (unsigned char *)cst3_fw ; //the updating firmware ++static unsigned int g_cst3xx_ic_version = 0; ++static unsigned int g_cst3xx_ic_checksum = 0; ++static unsigned int g_cst3xx_ic_checkcode =0; ++static unsigned int g_cst3xx_ic_project_id = 0; ++static unsigned int g_cst3xx_ic_type = 0; ++ ++static unsigned char report_flag = 0; ++static unsigned int x_temp_pos = 0; ++static unsigned int y_temp_pos = 0; ++ ++#define HYN_DRAW_POINT ++ ++#define USE_ANALOG_I2C 1 //i2c analog ++//#define USE_HIGHEST_I2CA 1// x1000 highest i2c ++//#define USE_LOWEST_I2CA 1 // x1000 lowest i2c ++#define HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++#define HYN_UPDATE_FIRMWARE_ENABLE ++ ++#pragma pack(1) ++typedef struct ++{ ++ u16 pid; //product id // ++ u16 vid; //version id // ++} st_tpd_info; ++#pragma pack() ++ ++st_tpd_info tpd_info; ++ ++#define CST3XX_BIN_SIZE (24*1024 + 24) ++#define CST3XX_MAX_X 480 ++#define CST3XX_MAX_Y 800 ++#define ERROR_TOUCH 1 ++ ++static void cst3xx_ts_power(struct cst3xx_ts_data *ts, bool poweron) ++{ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) ++ gpio_direction_output(ts->pdata->reset_gpio, poweron); ++} ++ ++static int cst3xx_into_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x01; ++ buf[2] = 0xAA; //set cmd to enter program mode ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(2); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; //check whether into program mode ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++static int cst3xx_erase_program_area(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; ++ buf[2] = 0x00; //set cmd to erase main area ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(5); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x03; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++ ++ ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms) ++{ ++ ++ unsigned char buf[4]; ++ buf[0] = 0xD1; ++ buf[1] = 0x0E; ++ cst3xx_i2c_write(ts->client, buf, 2); ++/* ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(2); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++*/ ++ mdelay(ms); ++} ++ ++ ++static int cst3xx_write_program_data(struct i2c_client * client, ++ const unsigned char *pdata) ++{ ++ int i, ret; ++ unsigned char *i2c_buf; ++ unsigned short eep_addr; ++ int total_kbyte; ++ ++ unsigned char temp_buf[8]; ++ unsigned short iic_addr; ++ int j; ++ ++ ++ i2c_buf = kmalloc(sizeof(unsigned char)*(1024 + 2), GFP_KERNEL); ++ if (i2c_buf == NULL) ++ return -1; ++ ++ //make sure fwbin len is N*1K ++ //total_kbyte = len / 1024; ++ total_kbyte = 24; ++ for (i=0; i>8; ++ ret = cst3xx_i2c_write(client, i2c_buf, 4); ++ if (ret < 0) ++ goto error_out; ++ ++ memcpy(i2c_buf, pdata + eep_addr, 1024); ++ for(j=0; j<256; j++) { ++ iic_addr = (j<<2); ++ temp_buf[0] = (iic_addr+0xA018)>>8; ++ temp_buf[1] = (iic_addr+0xA018)&0xFF; ++ temp_buf[2] = i2c_buf[iic_addr+0]; ++ temp_buf[3] = i2c_buf[iic_addr+1]; ++ temp_buf[4] = i2c_buf[iic_addr+2]; ++ temp_buf[5] = i2c_buf[iic_addr+3]; ++ ret = cst3xx_i2c_write(client, temp_buf, 6); ++ if (ret < 0) ++ goto error_out; ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x04; ++ i2c_buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(60); ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x05; ++ ret = cst3xx_i2c_read_register(client, i2c_buf, 1); ++ if (ret < 0) ++ goto error_out; ++ ++ if (i2c_buf[0] != 0x55) ++ goto error_out; ++ ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x03; ++ i2c_buf[2] = 0x00; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(8); ++ ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ ++ return 0; ++ ++error_out: ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ return -1; ++} ++ ++ ++static int cst3xx_check_checksum(struct i2c_client * client) ++{ ++ int ret; ++ int i; ++ unsigned int checksum; ++ unsigned int bin_checksum; ++ unsigned char buf[4]; ++ const unsigned char *pData; ++ ++ for(i=0; i<5; i++) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if(ret < 0) ++ { ++ mdelay(2); ++ continue; ++ } ++ ++ if(buf[0]!=0) ++ break; ++ else ++ mdelay(2); ++ } ++ mdelay(2); ++ ++ ++ if(buf[0]==0x01) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ ++ if(ret < 0) return -1; ++ ++ // read chip checksum ++ checksum = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); ++ ++ pData=(unsigned char *)pcst3xx_update_firmware +24*1024+16; //7*1024 +512 ++ bin_checksum = pData[0] + (pData[1]<<8) + (pData[2]<<16) + (pData[3]<<24); ++ ++ printk(" hyn the updated ic checksum is :0x%x. the updating firmware checksum is:0x%x------\n", checksum, bin_checksum); ++ ++ if(checksum!=bin_checksum) ++ { ++ printk(" cst3xx hyn check sum error.\n"); ++ return -1; ++ ++ } ++ ++ } ++ else ++ { ++ printk(" cst3xx hyn No checksum.\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x06; ++ buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) ++ return -1; ++ ++ mdelay(10); //wait for restart ++ ++ ++ return 0; ++} ++ ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ ++ printk(" cst3xx----------upgrade cst3xx begain------------\n"); ++ disable_irq(ts->irq); ++ mdelay(20); ++START_FLOW: ++ ++#ifdef HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++ close_vcc3v3Power(); ++ mdelay(20); ++ open_vcc3v3Power(); ++ mdelay(5+retry); ++#else ++ cst3xx_reset_ic(ts,5+retry); ++#endif ++ ret = cst3xx_into_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]into program mode failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_erase_program_area(ts->client); ++ if (ret) { ++ printk(" cst3xx[cst3xx]erase main area failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_write_program_data(ts->client, pdata); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]write program data into cstxxx failed.\n"); ++ goto err_out; ++ } ++ ++ ret =cst3xx_check_checksum(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] after write program cst3xx_check_checksum failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_exit_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]exit program mode failed.\n"); ++ goto err_out; ++ } ++ ++ cst3xx_reset_ic(ts,20); ++ ++ printk(" cst3xx hyn----------cst3xx_update_firmware end------------\n"); ++ ++ enable_irq(ts->irq); ++ ++ return 0; ++ ++err_out: ++ if (retry < 30) { ++ retry++; ++ mdelay(20); ++ goto START_FLOW; ++ } ++ else { ++ enable_irq(ts->irq); ++ return -1; ++ } ++} ++ ++ ++ ++ ++/******************************************************* ++Function: ++ get firmware version, ic type... ++Input: ++ client: i2c client ++Output: ++ success: 0 ++ fail: -1 ++*******************************************************/ ++static int cst3xx_firmware_info(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[28]; ++// unsigned short ic_type, project_id; ++ ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x01; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ ++ mdelay(40); ++ ++ buf[0] = 0xD1; ++ buf[1] = 0xFC; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ ++ //0xCACA0000 ++ g_cst3xx_ic_checkcode = buf[3]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[2]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[1]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip g_cst3xx_ic_checkcode:0x%x.\r\n",g_cst3xx_ic_checkcode); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x04; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ g_cst3xx_ic_type = buf[3]; ++ g_cst3xx_ic_type <<= 8; ++ g_cst3xx_ic_type |= buf[2]; ++ ++ ++ g_cst3xx_ic_project_id = buf[1]; ++ g_cst3xx_ic_project_id <<= 8; ++ g_cst3xx_ic_project_id |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip ic g_cst3xx_ic_type :0x%x, g_cst3xx_ic_project_id:0x%x\r\n", ++ g_cst3xx_ic_type, g_cst3xx_ic_project_id); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 8); ++ if (ret < 0) return -1; ++ ++ g_cst3xx_ic_version = buf[3]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[2]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[1]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[0]; ++ ++ g_cst3xx_ic_checksum = buf[7]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[6]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[5]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[4]; ++ ++ tpd_info.vid = g_cst3xx_ic_version; ++ tpd_info.pid = 0x00; ++ ++ ++ printk(" cst3xx [cst3xx] the chip ic version:0x%x, checksum:0x%x\r\n", ++ g_cst3xx_ic_version, g_cst3xx_ic_checksum); ++ ++ if(g_cst3xx_ic_version==0xA5A5A5A5) ++ { ++ printk(" cst3xx [cst3xx] the chip ic don't have firmware. \n"); ++ return -1; ++ } ++ if((g_cst3xx_ic_checkcode&0xffff0000)!=0xCACA0000){ ++ printk("linc cst3xx [cst3xx] cst3xx_firmware_info read error .\r\n"); ++ return -1; ++ } ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x09; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ mdelay(5); ++ ++ ++ return 0; ++} ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict) ++{ ++ unsigned short ic_type, project_id; ++ unsigned int fw_checksum, fw_version; ++ const unsigned int *p; ++ int i; ++ unsigned char *pBuf; ++ ++ fw_checksum = 0x55; ++ p = (const unsigned int *)pdata; ++ for (i=0; i<(CST3XX_BIN_SIZE-4); i+=4) { ++ fw_checksum += (*p); ++ p++; ++ } ++ ++ if (fw_checksum != (*p)) { ++ printk(" cst3xx[cst3xx]calculated checksum error:0x%x not equal 0x%x.\n", fw_checksum, *p); ++ return -1; //bad fw, so do not update ++ } ++ ++ pBuf = &pdata[CST3XX_BIN_SIZE-16]; ++ ++ project_id = pBuf[1]; ++ project_id <<= 8; ++ project_id |= pBuf[0]; ++ ++ ic_type = pBuf[3]; ++ ic_type <<= 8; ++ ic_type |= pBuf[2]; ++ ++ fw_version = pBuf[7]; ++ fw_version <<= 8; ++ fw_version |= pBuf[6]; ++ fw_version <<= 8; ++ fw_version |= pBuf[5]; ++ fw_version <<= 8; ++ fw_version |= pBuf[4]; ++ ++ fw_checksum = pBuf[11]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[10]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[9]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[8]; ++ ++ printk(" cst3xx[cst3xx]the updating firmware:project_id:0x%04x,ic type:0x%04x,version:0x%x,checksum:0x%x\n", ++ project_id, ic_type, fw_version, fw_checksum); ++ ++ if (strict > 0) { ++ ++ if (g_cst3xx_ic_checksum != fw_checksum){ ++ if (g_cst3xx_ic_version >fw_version){ ++ printk("[cst3xx]fw version(0x%x), ic version(0x%x).\n",fw_version, g_cst3xx_ic_version); ++ // return -1; ++ } ++ }else{ ++ printk("[cst3xx]fw checksum(0x%x), ic checksum(0x%x).\n",fw_checksum, g_cst3xx_ic_checksum); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ int flag = 0; ++ ++ while (retry++ < 3) { ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret == 0) { ++ flag = 1; ++ break; ++ } ++ } ++ ++ if (flag == 1) { ++ ret = cst3xx_update_judge(pdata, 1); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] no need to update firmware.\n"); ++ return 0; ++ } ++ } ++ ++ ret = cst3xx_update_firmware(ts, pdata); ++ if (ret < 0){ ++ printk(" cst3xx [cst3xx] update firmware failed.\n"); ++ return -1; ++ } ++ ++ mdelay(50); ++ ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx [cst3xx] after update read version and checksum fail.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++static int hyn_boot_update_fw(struct i2c_client * ts) ++{ ++ unsigned char *ptr_fw; ++ int ret; ++ ptr_fw = pcst3xx_update_firmware; ++ ret = cst3xx_boot_update_fw(ts, ptr_fw); ++ return ret; ++ ++} ++ ++ ++/*******************************Chose which I2C interface ********************************************/ ++ ++#if USE_ANALOG_I2C ++ ++#define I2CSDA GPIO_PC(27) ++#define I2CSCL GPIO_PC(26) ++ ++#define I2CSDA_HIGH gpio_direction_output(GPIO_PC(27),1) ++#define I2CSDA_LOW gpio_direction_output(GPIO_PC(27),0) ++ ++#define I2CSCL_HIGH gpio_direction_output(GPIO_PC(26),1) ++#define I2CSCL_LOW gpio_direction_output(GPIO_PC(26),0) ++ ++#define delay_data 2 ++static void iicstart(void) ++{ ++ I2CSDA_HIGH; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_LOW; ++ __udelay(2); ++ I2CSCL_LOW; ++ __udelay(2); ++} ++static void iicstop(void) ++{ ++ I2CSDA_LOW; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_HIGH; ++ __udelay(2); ++ ++} ++static unsigned char waitack(void) ++{ ++ u8 ucErrTime=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ // __udelay(2); ++ ++ // I2CSDA_HIGH; ++ // __udelay(2); ++ I2CSCL_HIGH; ++ __udelay(2); ++ ++ while(__gpio_get_value(GPIO_PC(27))) ++ { ++ ucErrTime++; ++ // printk("time out ++ \n"); ++ if(ucErrTime>250) ++ { ++ iicstop(); ++ return 1; ++ } ++ } ++ I2CSCL_LOW; ++ __udelay(2); ++ return 0; ++} ++static void sendack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_LOW; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ ++} ++static void sendnotack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_HIGH; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++} ++static void iicsendbyte(unsigned char ch) ++{ ++ unsigned char i; ++ I2CSCL_LOW; ++ for(i = 0;i<8;i++) ++ { ++ if(ch&0x80) ++ { ++ I2CSDA_HIGH; ++ } ++ else ++ { ++ I2CSDA_LOW; ++ } ++ __udelay(delay_data); ++ ch<<=1; ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ } ++} ++static unsigned char iicreceivebyte(unsigned char ack) ++{ ++ unsigned char i=8; ++ unsigned char ddata=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ __udelay(delay_data); ++ ++ for(i = 0;i<8;i++) ++ { ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ ++ ddata<<=1; ++ if(gpio_get_value(GPIO_PC(27))) ddata++; ++ } ++ ++ if(!ack) ++ sendnotack(); ++ else ++ sendack(); ++ ++ return ddata; ++} ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int count = len; ++ iicstart(); ++ __udelay(delay_data); ++ ++/* ++ iicsendbyte( (0x1a<<1) | 0); ++ __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ ++ iicsendbyte(buf[0]); ++ __udelay(delay_data); ++ waitack(); ++ __udelay(delay_data); ++*/ ++ iicstart(); ++ __udelay(delay_data); ++ ++ iicsendbyte((0x1a << 1 ) | 1); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ ++ while(count) ++ { ++ if(count == 1) *buf = iicreceivebyte(0); ++ else *buf = iicreceivebyte(1); ++ count --; ++ buf++; ++ } ++ iicstop(); ++ __udelay(delay_data); ++ return 0; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int count = len; ++ iicstart(); ++ // __udelay(delay_data); ++ ++ iicsendbyte((0x1A << 1) | 0); ++// __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write send address wait ack timeoue \n"); ++ return 1; ++ } ++ ++ while(count--) ++ { ++ iicsendbyte(*(buf++)); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ } ++ ++ iicstop(); ++ __udelay(delay_data); ++ ++ return 0; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if(ret) printk("failed to write cst3xx\n"); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ if(ret) printk("failed to write cst3xx\n"); ++ return ret; ++} ++ ++#elif USE_LOWEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_recv(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_send(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ ++ return ret; ++} ++ ++#elif USE_HIGHEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags |= I2C_M_RD; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++/******************************************************* ++Function: ++ read data from register. ++Input: ++ buf: first two byte is register addr, then read data store into buf ++ len: length of data that to read ++Output: ++ success: number of messages ++ fail: negative errno ++*******************************************************/ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msgs[2]; ++ int ret = -1; ++ int retries = 0; ++ ++ msgs[0].flags = 0; ++ msgs[0].addr = client->addr; ++ msgs[0].len = 2; ++ msgs[0].buf = buf; ++ ++ msgs[1].flags |= I2C_M_RD; ++ msgs[1].addr = client->addr; ++ msgs[1].len = len; ++ msgs[1].buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if(ret == 2) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags = 0; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++#else ++#endif ++/*********************************i2c end********************************/ ++ ++ ++static int cst3xx_i2c_test(struct i2c_client *client) ++{ ++ int retry = 0; ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ while (retry++ < 5) { ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret == 0) ++ return ret; ++ ++ mdelay(2); ++ } ++ ++ if(retry==5) printk(" cst3xx hyn I2C TEST error.ret:%d;\n", ret); ++ ++ return ret; ++} ++ ++ ++static void cst3xx_reset(struct cst3xx_ts_data *ts) { ++ if(gpio_is_valid(ts->pdata->reset_gpio)) { ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(100); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++ mdelay(100); ++ } ++} ++/**************************** basic communication end*******************************/ ++ ++ ++static void cst3xx_touch_report(struct cst3xx_ts_data *ts) ++{ ++ unsigned char buf[30]; ++ unsigned char i2c_buf[8]; ++ unsigned char key_status, key_id = 0, finger_id, sw; ++ unsigned int input_x = 0; ++ unsigned int input_y = 0; ++ unsigned int input_w = 0; ++ unsigned int input_x_delta = 0; ++ unsigned int input_y_delta = 0; ++ unsigned char cnt_up, cnt_down; ++ int i, ret, idx; ++ int cnt, i2c_len; ++ ++ int len_1, len_2; ++ ++ key_status = 0; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(ts->client, buf, 7); ++ if(ret < 0) { ++ printk(" iic read touch point data failed.\n"); ++ goto OUT_PROCESS; ++ } ++ // printk(" read buf : buf[0]: %x ,buf[1]: %x ,buf[2]: %x, buf[3]: %x,buf[4]: %x ,buf[5]: %x ,buf[6]: %x, buf[7]: %x,\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); ++ ++ if(buf[6] != 0xAB) { ++ printk(KERN_INFO " data is not valid..\r\n"); ++ goto OUT_PROCESS; ++ } ++ ++ cnt = buf[5] & 0x7F; ++ if(cnt > 1) goto OUT_PROCESS; ++ else if(cnt==0) goto CLR_POINT; ++ ++ if(cnt == 0x01) { ++ goto FINGER_PROCESS; ++ } ++ ++FINGER_PROCESS: ++ ++ /* ++ * sw: buf[0] low 4 bit ++ * x pos: buf[1] low 4 bit | buf[3] high 4 bit ++ * y pos: buf[2] low 4 bit | buf[3] low 4 bit ++ * z press : buf[4] ++ * finger_id:buf[0] high 4 bit ++ */ ++ i2c_buf[0] = 0xD0; ++ i2c_buf[1] = 0x00; ++ i2c_buf[2] = 0xAB; ++ ++ ret = cst3xx_i2c_write(ts->client, i2c_buf, 3); ++ if(ret < 0) { ++ printk(" cst3xx hyn send read touch info ending failed.\r\n"); ++ cst3xx_reset_ic(ts,20); ++ goto END; ++ } ++ ++ idx = 0; ++ cnt_up = 0; ++ cnt_down = 0; ++ input_x = (unsigned int)((buf[idx + 1] << 4) | ((buf[idx + 3] >> 4) & 0x0F)); ++ input_y = (unsigned int)((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0F)); ++ input_w = (unsigned int)(buf[idx + 4]); ++ sw = (buf[idx] & 0x0F) >> 1; ++ finger_id = (buf[idx] >> 4) & 0x0F; ++ ++ printk(" no handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n", input_x, input_y, input_w,finger_id, sw); ++ ++ input_x=input_x*CST3XX_MAX_X/268; ++// input_y=input_y*CST3XX_MAX_Y/800; ++ ++// if(input_x >= CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++// if(input_y >= CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ ++// input_x = CST3XX_MAX_X-input_x; ++// input_y = CST3XX_MAX_Y-input_y; ++ ++#ifdef 0//HYN_DRAW_POINT ++ if(input_x > 300){ ++ input_x_delta = input_x - (CST3XX_MAX_X/2); ++ input_x = input_x + input_x_delta/((CST3XX_MAX_X/2)/20); ++ if(input_x > CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++ } ++ if(input_x < 40){ ++ input_x_delta = (CST3XX_MAX_X/2) - input_x; ++ input_x = input_x - input_x_delta/((CST3XX_MAX_X/2)/12); ++ if(input_x < 0) input_x = 0; ++ } ++ if(input_y > 760){ ++ input_y_delta = input_y - (CST3XX_MAX_Y/2); ++ input_y = input_y + input_y_delta/((CST3XX_MAX_Y/2)/12); ++ if(input_y > CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ } ++ if(input_y < 40){ ++ input_y_delta = (CST3XX_MAX_Y/2) - input_y; ++ input_y = input_y - input_y_delta/((CST3XX_MAX_Y/2)/25); ++ if(input_y < 0) input_y = 0; ++ } ++#endif ++ ++ printk(" handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n\n", input_x, input_y, input_w,finger_id, sw); ++ ++ if (sw == 0x03 ) { ++ if((input_x > x_temp_pos + ERROR_TOUCH) || (input_x < x_temp_pos -ERROR_TOUCH) || (input_y > y_temp_pos + ERROR_TOUCH) || (input_y < y_temp_pos -ERROR_TOUCH)) ++ { ++ // printk(" REPORT TOUCH DOWM Handle \n"); ++ x_temp_pos = input_x; ++ y_temp_pos = input_y; ++ input_report_key(ts->input_dev, BTN_TOUCH, 1); ++ input_report_abs(ts->input_dev, ABS_X, input_x); ++ input_report_abs(ts->input_dev, ABS_Y, input_y); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 1); ++ input_sync(ts->input_dev); ++ } ++ cnt_down++; ++ } ++ else if(sw == 0) { ++ cnt_up++; ++ } ++ ++ if((cnt_up>0) && (cnt_down==0) ){ ++ // printk(" REPORT TOUCH UP Handle \n"); ++ x_temp_pos = 0; ++ y_temp_pos = 0; ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 0); ++ input_mt_sync(ts->input_dev); ++ } ++ input_sync(ts->input_dev); ++ goto END; ++CLR_POINT: ++ ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_mt_sync(ts->input_dev); ++ input_sync(ts->input_dev); ++ ++OUT_PROCESS: ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ buf[2] = 0xAB; ++ ret = cst3xx_i2c_write(ts->client, buf, 3); ++ if (ret < 0) { ++ printk(" send read touch info ending failed.\n"); ++ cst3xx_reset_ic(ts,20); ++ } ++END: ++ return; ++} ++ ++ ++/******************************* irq handle begin************************************/ ++static void cst3xx_work_handler(struct work_struct *work) ++{ ++ struct cst3xx_ts_data *cst3xx_ts = container_of(work, struct cst3xx_ts_data, work); ++ int ret = 0; ++ /******************here handle touch *******************/ ++ // printk(KERN_INFO "-----------enter cst3xx_work_handler------------\n"); ++ cst3xx_touch_report(cst3xx_ts); ++ enable_irq(cst3xx_ts->irq); ++} ++ ++static irqreturn_t cst3xx_ts_irq_handler(int irq, void *dev_id) ++{ ++ struct cst3xx_ts_data *ts = dev_id; ++ ++ // printk( KERN_INFO "-----------enter cst3xx_ts_irq_handler------------\n"); ++ ++ disable_irq_nosync(ts->irq);//use in interrupt,disable_irq will make dead lock. ++ ++ if (!work_pending(&ts->work)) { ++ queue_work(ts->workqueue, &ts->work); ++ // queue_delayed_work(ts->workqueue,&ts->dwork,1);//10ms * x ++ } else { ++ enable_irq(ts->irq); ++ } ++ ++ return IRQ_HANDLED; ++} ++/******************************* irq handle end************************************/ ++ ++static int cst3xx_ts_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ printk( KERN_INFO "Enter cst3xx_ts_probe -------------------\n"); ++ ++ int ret; ++ int rc=-1; ++ struct cst3xx_ts_data *ts; ++ ++ struct cst3xx_platform_data *pdata = (struct cst3xx_platform_data*)client->dev.platform_data; ++ struct input_dev *input_dev; ++ int error; ++ ++#if USE_ANALOG_I2C ++ if (gpio_is_valid(I2CSDA)) ++ { ++ gpio_free(I2CSDA); ++ ret = gpio_request(GPIO_PC(27),"I2C1-SDA"); ++ if(ret < 0){ ++ printk("I2C1-SDA gpio request failed\n"); ++ return ret; ++ } ++ } ++ if (gpio_is_valid(I2CSCL)) ++ { ++ gpio_free(I2CSCL); ++ ret = gpio_request(GPIO_PC(26),"I2C1-SCL"); ++ if(ret < 0){ ++ printk("I2C1-SCL gpio request failed\n"); ++ return ret; ++ } ++ } ++#endif ++ ++ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); ++ if (!ts) ++ return -ENOMEM; ++ input_dev = input_allocate_device(); ++ if(!input_dev) ++ return -ENOMEM; ++ ++ ts->pdata = pdata; ++ ts->client = client; ++ ts->input_dev = input_dev; ++ ++ if(client->addr != 0x1A) //check address ++ { ++ client->addr = 0x1A; ++ printk("Crystal_shen:i2c_client_HYN->addr=%d.\n",client->addr); ++ ++ } ++ ++ if (gpio_is_valid(ts->pdata->int_gpio)) { ++ //error = gpio_request(pdata->int_gpio,"cst3xx gpio irq"); ++ error = gpio_request_one(pdata->int_gpio, GPIOF_IN, "cst3xx gpio irq"); ++ if (error < 0) { ++ dev_err(&client->dev, "Failed to request GPIO %d, error %d\n", ++ pdata->int_gpio, error); ++ return error; ++ } ++ ++ /* if (error < 0) { ++ dev_err(&client->dev, "%s:failed to set gpio irq.\n",__func__); ++ return error; ++ }*/ ++ ts->irq = gpio_to_irq(pdata->int_gpio); ++ printk(" cst3xx ts -> irq = %d.\n",ts->irq); ++ } ++ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) { ++ error = devm_gpio_request(&client->dev, ts->pdata->reset_gpio, NULL); ++ if (error) { ++ dev_err(&client->dev, ++ "Unable to request GPIO pin %d.\n", ++ ts->pdata->reset_gpio); ++ return error; ++ } ++ } ++ cst3xx_reset(ts); ++ printk( KERN_INFO "cst3xx reset -------------------\n"); ++ ret = cst3xx_i2c_test(ts->client); ++ if(ret<0){ ++ ++ mdelay(100); ++ ++ printk( KERN_INFO "cst3xx test OK -------------------\n"); ++#ifdef HYN_UPDATE_FIRMWARE_ENABLE ++ ret = cst3xx_boot_update_fw(ts,pcst3xx_update_firmware);// ++ if(ret < 0){ ++ printk(" cst3xx hyn_boot_update_fw failed.\n"); ++ return -1; ++ } ++#endif ++ ++ }else{ ++ ++ mdelay(20); ++ rc = hyn_boot_update_fw(ts); ++ if(rc < 0){ ++ printk(" cst3xx hyn_boot_update_fw failed.\n"); ++ //return -1; ++ } ++ } ++ ++ input_dev->name = "cst3xxx -touchscreen"; ++ input_dev->id.bustype = BUS_I2C; ++ input_dev->dev.parent = &client->dev; ++ ++ set_bit(EV_KEY, input_dev->evbit); ++ set_bit(EV_ABS, input_dev->evbit); ++ set_bit(EV_SYN, input_dev->evbit); ++ set_bit(BTN_TOUCH, input_dev->keybit); ++ ++ set_bit(ABS_X, input_dev->absbit); ++ set_bit(ABS_Y, input_dev->absbit); ++ set_bit(ABS_PRESSURE, input_dev->absbit); ++ ++ ++ input_set_abs_params(input_dev, ABS_X, ts->pdata->x_min, ts->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, ts->pdata->y_min, ts->pdata->y_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0 , 0); ++ ++ /* input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, MAX_AREA, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_POSITION_X, ts->pdata->x_min, ts->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, ts->pdata->y_min, ts->pdata->y_max, 0, 0); ++*/ ++ error = input_register_device(input_dev); ++ if (error) { ++ dev_err(&client->dev, "Unable to register %s input device\n", ++ input_dev->name); ++ return error; ++ } ++ ++ // INIT_DELAYED_WORK(&ts->dwork, cst3xx_work_handler); ++ ++ INIT_WORK(&ts->work, cst3xx_work_handler); ++ ts->workqueue = create_singlethread_workqueue("cst3xx_wq"); ++ ++ error = devm_request_threaded_irq(&client->dev, client->irq, ++ NULL, ++ cst3xx_ts_irq_handler, ++ IRQF_ONESHOT, ++ client->name, ts); ++ if (error) { ++ dev_err(&client->dev, "Failed to register interrupt\n"); ++ return error; ++ } ++ error = request_irq(ts->irq, ++ cst3xx_ts_irq_handler, ++ ts->pdata->irqflags, ++ client->dev.driver->name, ++ ts); ++ if (error < 0) { ++ dev_err(&client->dev, "%s: request irq failed\n",__func__); ++ return error; ++ } ++ printk(KERN_INFO "-----------CST3XX probe end ------------\n"); ++ return 0; ++} ++ ++static int cst3xx_ts_remove(struct i2c_client *client) ++{ ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ free_irq(ts->irq,ts); ++ devm_free_irq(&ts->client->dev, ts->client->irq,ts); ++ destroy_workqueue(ts->workqueue); ++ input_unregister_device(ts->input_dev); ++ devm_gpio_free(&ts->client->dev, ts->pdata->reset_gpio); ++ gpio_free(ts->pdata->int_gpio); ++ ++#if USE_ANALOG_I2C ++ gpio_free(I2CSDA); ++ gpio_free(I2CSCL); ++#endif ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int cst3xx_ts_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ enable_irq_wake(client->irq); ++ } else { ++ disable_irq(client->irq); ++ cst3xx_ts_power(ts, false);//reset ++ } ++ ++ return 0; ++} ++ ++static int cst3xx_ts_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ disable_irq_wake(client->irq); ++ } else { ++ cst3xx_ts_power(ts, true); ++ enable_irq(client->irq); ++ } ++ return 0; ++} ++ ++#endif ++ ++static SIMPLE_DEV_PM_OPS(cst3xx_ts_pm_ops, ++ cst3xx_ts_suspend, cst3xx_ts_resume); ++ ++static const struct i2c_device_id cst3xx_ts_id[] = { ++ { CST3XX_NAME, 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, cst3xx_ts_id); ++ ++ ++#ifdef CONFIG_OF ++static const struct of_device_id cst3xx_ts_dt_ids[] = { ++ { .compatible = "xxxxx,cst3xx", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, cst3xx_ts_dt_ids); ++#endif ++ ++ ++static struct i2c_driver cst3xx_ts_driver = { ++ .probe = cst3xx_ts_probe, ++ .remove = cst3xx_ts_remove, ++ .id_table = cst3xx_ts_id, ++ .driver = { ++ .name = CST3XX_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(cst3xx_ts_dt_ids), ++ .pm = &cst3xx_ts_pm_ops, ++ }, ++}; ++ ++module_i2c_driver(cst3xx_ts_driver); ++ ++ ++MODULE_AUTHOR("Tiben"); ++MODULE_DESCRIPTION("SITRONIX CST3XX Touchscreen Controller Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/cst3xx.h b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/cst3xx.h +new file mode 100644 +index 000000000..68791e6af +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/cst3xx.h +@@ -0,0 +1,29 @@ ++#ifndef TOUCHSCREEN_CST3XX__H ++#define TOUCHSCREEN_CST3XX__H ++ ++ ++/* -- dirver configure -- */ ++#define CFG_MAX_TOUCH_POINTS 1 ++#define MAX_AREA 0xff ++ ++#define CST3XX_NAME "cst3xx" ++ ++/*register address*/ ++#define CST3XX_ADDRESS 0x1A ++ ++ ++/* The platform data for the Focaltech ft5x0x touchscreen driver */ ++struct cst3xx_platform_data { ++ unsigned int x_min; ++ unsigned int y_min; ++ unsigned int x_max; ++ unsigned int y_max; ++ unsigned long irqflags; ++ unsigned int int_gpio; ++ unsigned int reset_gpio; ++}; ++ ++ ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw.h b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw.h +new file mode 100644 +index 000000000..24cfbcfed +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/cst3xx_MCU_driver_0729_update2/hyn_cst3xx_RS659_fw.h +@@ -0,0 +1,1552 @@ ++ ++#ifndef __CST3xx_FW_H__ ++#define __CST3xx_FW_H__ ++ ++ unsigned char cst3_fw[] ={ ++ 0x98,0xE0,0x07,0x01,0xC8,0x28,0x02,0x00,0x00,0x00,0x00,0x00,0xC8,0xE8,0x01,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x90,0x08,0x07,0x00,0x98,0x08,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x98,0xA8,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0x78,0x01,0x00,0x80,0x07,0xC0,0x17, ++ 0x82,0x07,0xC0,0x07,0x01,0x65,0x40,0x86,0xC1,0x41,0xC0,0x20,0xC5,0x68,0x31,0x12, ++ 0xF5,0x38,0x33,0x5A,0x32,0xA2,0x32,0xEA,0x10,0x62,0x8D,0x0E,0x81,0x07,0xC0,0x97, ++ 0x30,0xF2,0xF3,0x79,0x65,0x7E,0x30,0xB2,0x31,0x09,0x10,0x9A,0x87,0x06,0xD0,0xD8, ++ 0x35,0x12,0x35,0x5A,0x18,0x9A,0x39,0xC2,0x70,0x82,0x02,0x00,0x70,0x82,0x03,0x00, ++ 0xD0,0x81,0x98,0x16,0x43,0xC6,0x0B,0xC6,0xC2,0xD6,0x3F,0x90,0x99,0x0E,0x40,0x86, ++ 0x08,0x86,0xA9,0x0E,0x40,0x23,0x00,0x63,0x38,0x82,0x03,0x00,0x18,0x01,0x20,0x01, ++ 0x28,0x01,0x30,0x01,0xD0,0x81,0x98,0x0E,0x0F,0xC6,0xC3,0xDE,0x38,0x90,0x9A,0x06, ++ 0x08,0x86,0xA9,0x06,0x03,0x5B,0x38,0x82,0xAE,0xFD,0x30,0x02,0x30,0x02,0xEE,0xFD, ++ 0xA8,0x85,0xE8,0x85,0x84,0x27,0xE8,0xBF,0x37,0x8A,0xB8,0xFF,0xF8,0xAF,0x87,0x0F, ++ 0xD0,0xFF,0x80,0x27,0xEF,0x7F,0xBD,0xFF,0xF8,0x9F,0x87,0x27,0xE8,0xAF,0x05,0x00, ++ 0xAF,0x85,0x6F,0xFA,0x39,0x01,0xC0,0x43,0x37,0x4A,0xC9,0x01,0x38,0x30,0x32,0x42, ++ 0x86,0x01,0xC5,0x1B,0xCE,0x23,0xF0,0x53,0xC0,0x01,0x74,0x01,0xDD,0x16,0xC0,0x6B, ++ 0x48,0x68,0x87,0x3E,0xAA,0x7B,0xAC,0x3B,0x10,0xD2,0x8C,0x16,0xB0,0x63,0x06,0x09, ++ 0xB7,0x43,0xEC,0x85,0x34,0x6A,0xE8,0x4B,0xE6,0x48,0x92,0x4D,0xAF,0x4B,0x4D,0xF9, ++ 0x8D,0x0E,0x10,0x12,0x82,0x16,0xE8,0x0B,0x48,0x09,0x88,0x1E,0xB5,0x5B,0xAF,0x7B, ++ 0xAF,0x3B,0xEA,0x85,0x4F,0x09,0x8C,0xE6,0x0A,0x09,0xA8,0x0B,0xE8,0x85,0xAF,0x85, ++ 0x67,0x3A,0xE7,0x01,0x00,0x0F,0x80,0x0F,0xF5,0x1F,0xF0,0x03,0x47,0x01,0x80,0xD6, ++ 0xEF,0x85,0xA8,0xC5,0x00,0x21,0x80,0x0F,0xE8,0x6F,0x07,0x09,0x87,0x0F,0xE8,0x57, ++ 0x79,0x02,0x47,0xC3,0x0C,0x01,0x19,0x42,0x00,0xC3,0x01,0x11,0x86,0x0F,0xE8,0xBF, ++ 0x61,0xEA,0x56,0x03,0x29,0x41,0x18,0x42,0x17,0x03,0x49,0x03,0x1F,0x42,0x09,0x03, ++ 0x15,0x2B,0x4B,0x03,0x1D,0x42,0x09,0x03,0x4D,0x03,0x1B,0x42,0x0B,0x03,0x4B,0x03, ++ 0x35,0x21,0x18,0x82,0x0B,0x03,0x4B,0x03,0x42,0x00,0x02,0x00,0x09,0x03,0x4B,0x03, ++ 0x19,0x42,0x09,0x03,0x49,0x03,0x19,0x82,0x09,0x03,0x49,0x03,0x08,0x09,0x18,0x42, ++ 0x0F,0x03,0x41,0x03,0x1F,0x42,0x05,0x03,0x45,0x03,0x1F,0x82,0x07,0x03,0x47,0x03, ++ 0x1F,0x42,0x04,0x03,0x45,0x03,0x1D,0x42,0x05,0x03,0x45,0x03,0x1D,0x82,0x05,0x03, ++ 0x45,0x03,0x1B,0x42,0x03,0x03,0x43,0x03,0x1B,0x82,0x05,0x03,0x44,0x03,0x1D,0x42, ++ 0x03,0x03,0x45,0x03,0x1B,0x42,0x04,0x03,0x0E,0x81,0x42,0x02,0x82,0x27,0xE0,0x97, ++ 0x85,0x0F,0xE8,0x87,0x85,0x0F,0xE8,0x67,0x85,0x0F,0xE8,0x97,0x48,0xE2,0x05,0x01, ++ 0x1D,0x43,0x4C,0x03,0x1D,0x42,0x0D,0x03,0x10,0x2B,0x03,0x11,0x84,0x0F,0xE8,0x97, ++ 0x41,0xC3,0x09,0x01,0x19,0x42,0x00,0xC3,0x00,0x21,0x80,0x0F,0xE8,0x07,0x04,0x09, ++ 0x83,0x0F,0xE8,0xEF,0x42,0x03,0x41,0x00,0x01,0x00,0x02,0x03,0x40,0x03,0x0F,0x09, ++ 0x1F,0x42,0x00,0x03,0x4C,0x03,0x1B,0x42,0x09,0x03,0x4B,0x03,0x19,0x42,0x0C,0x03, ++ 0x41,0x03,0x1D,0x42,0x05,0x03,0x45,0x03,0x1D,0x82,0x01,0x03,0x41,0x03,0x1B,0x42, ++ 0x03,0x03,0x43,0x03,0x1B,0x82,0x01,0x03,0x48,0x0B,0x03,0x61,0x1B,0x0A,0x08,0x0B, ++ 0x48,0x0B,0x19,0x0A,0x0F,0x0B,0x41,0x0B,0x1F,0x0A,0x00,0x0B,0x48,0xE2,0x04,0x09, ++ 0xC8,0x01,0xAF,0x43,0x82,0x0F,0xD0,0xD7,0xEC,0xC5,0x47,0xCA,0xC6,0x01,0xF3,0x0B, ++ 0x42,0xCA,0x84,0x01,0x48,0x01,0x80,0x3E,0x4A,0xD2,0x04,0x0B,0x0C,0xF9,0x57,0xB2, ++ 0x8C,0x89,0x97,0x01,0x10,0x8B,0x00,0x17,0x48,0xB2,0xCC,0xE1,0x07,0x0B,0x12,0xF9, ++ 0x96,0xA1,0x02,0x13,0x08,0x31,0x08,0x0B,0x0C,0x11,0x08,0x0B,0x0A,0x51,0x08,0x0B, ++ 0x0C,0x49,0x18,0x0B,0x18,0x0B,0x0A,0x01,0x1C,0x0B,0x40,0x4A,0xC2,0x01,0x0F,0x14, ++ 0x3F,0x82,0xAB,0x85,0x70,0x62,0x0C,0x01,0x2C,0x01,0x60,0x62,0x50,0x62,0x04,0x01, ++ 0xA4,0x82,0x02,0x40,0x50,0x5A,0xC4,0x40,0xC4,0x00,0x54,0x5A,0xC0,0x10,0x1C,0x01, ++ 0xC6,0x83,0x01,0x38,0xC1,0x83,0xD0,0xC0,0x94,0x05,0x14,0x2A,0x90,0x06,0x30,0x2A, ++ 0x10,0x22,0xCC,0x06,0x32,0x22,0xE0,0x90,0xE6,0xD8,0x92,0xDD,0x5F,0x29,0x98,0x8E, ++ 0x59,0xFA,0xDB,0x40,0xA3,0xC2,0xE2,0xB0,0xE6,0x48,0x92,0x4D,0x4E,0x71,0x98,0xDE, ++ 0x48,0xD2,0x03,0x01,0xE4,0xD2,0x10,0x52,0x90,0x06,0x30,0x8A,0xE6,0x00,0x92,0x05, ++ 0x47,0x71,0x98,0xBE,0x50,0xCA,0x03,0x01,0x00,0x84,0xE0,0xE2,0x43,0xAC,0xD0,0x20, ++ 0xC8,0x20,0x03,0xA4,0xE6,0x00,0x92,0x05,0x47,0x71,0x98,0xB6,0x47,0x84,0x40,0xF9, ++ 0xCF,0x0E,0x00,0xF9,0x03,0x84,0x48,0x92,0x40,0x84,0x80,0x43,0xE8,0x85,0xAF,0x85, ++ 0x40,0x1A,0xC3,0x03,0x38,0x00,0x86,0xAE,0x00,0x01,0x85,0x0F,0xD3,0x7F,0x60,0x02, ++ 0x01,0x01,0xE0,0x01,0x8F,0x03,0xB9,0xFF,0xF9,0x47,0x34,0x0A,0x56,0x4A,0xCB,0x01, ++ 0x40,0x22,0x83,0x1F,0xD0,0x3F,0x04,0x11,0x88,0x03,0x01,0x01,0x86,0x0F,0xC8,0xB7, ++ 0xBC,0xFF,0xFF,0xFF,0xE8,0x85,0xA8,0x85,0x41,0xAA,0xC2,0x01,0xC8,0x03,0x42,0x01, ++ 0x8A,0x36,0x40,0x9A,0xC0,0x01,0xEF,0x03,0x40,0x29,0xC8,0x0E,0xBE,0xFF,0xF7,0x7F, ++ 0x61,0x7A,0xC2,0x03,0x38,0x00,0xA8,0x0E,0xBE,0xFF,0xF7,0x9F,0xC3,0x03,0xC3,0x03, ++ 0x08,0xE9,0x07,0x42,0x82,0x03,0x43,0xC2,0xC0,0x03,0x40,0x01,0x80,0x16,0x80,0x0F, ++ 0xE7,0x3F,0x3E,0xE7,0xE8,0x85,0xA8,0x85,0x48,0x32,0x02,0x01,0x02,0x43,0x4C,0x22, ++ 0xCC,0x01,0xB7,0x43,0xF0,0x43,0x86,0x0F,0xC8,0x8F,0xEE,0x85,0xA8,0x85,0x33,0x2A, ++ 0x48,0x01,0x80,0x4E,0x68,0x01,0x80,0x1E,0x30,0x82,0xC0,0x51,0x20,0x01,0x00,0x5F, ++ 0x30,0x82,0x80,0x51,0x20,0x01,0x00,0x3F,0x68,0x01,0x80,0x1E,0xF0,0x80,0x24,0x49, ++ 0x18,0x22,0x07,0x0F,0xE0,0x80,0x24,0x51,0x0A,0x01,0xF0,0x0A,0x48,0x01,0xD0,0x06, ++ 0x16,0x4A,0x0A,0x40,0x0A,0x01,0xF0,0x8A,0x82,0x27,0xD8,0x57,0x40,0xF9,0xEB,0x06, ++ 0x00,0xF9,0x6B,0x01,0x87,0x16,0x08,0xF9,0x88,0x09,0xD0,0x40,0xCB,0x00,0xE8,0x85, ++ 0xAC,0x85,0x87,0x3D,0x28,0x01,0x20,0x01,0x01,0x51,0x48,0x92,0x1A,0x42,0xC3,0x00, ++ 0x80,0x34,0xC0,0x34,0x01,0x08,0x13,0x39,0xC4,0x00,0x0A,0x90,0xC0,0x10,0x04,0xE1, ++ 0x90,0x2C,0xF0,0x82,0x80,0x24,0x30,0x01,0x38,0x01,0x10,0x01,0x90,0x1C,0x90,0x14, ++ 0x60,0x01,0x80,0x46,0xF0,0x10,0xDB,0x34,0x04,0x90,0xC2,0xD0,0x1C,0x39,0x09,0xD8, ++ 0xC0,0x90,0x36,0xE1,0xF8,0xB2,0x6C,0x01,0x83,0x56,0xF0,0x50,0x1A,0x51,0x18,0xD2, ++ 0x5E,0x02,0xC1,0x90,0x1A,0x39,0xC1,0x90,0x0E,0xD8,0xC4,0x90,0x3E,0xE1,0xF8,0xBA, ++ 0x60,0x21,0x80,0x4E,0xE0,0x18,0xD3,0x34,0x06,0xD8,0xC2,0x90,0x1C,0x39,0x09,0xD8, ++ 0xC0,0x90,0x1E,0xE1,0xF0,0x9A,0x9E,0x1C,0x68,0x69,0x80,0x5E,0xE0,0x50,0x1B,0x51, ++ 0x18,0xD2,0x5A,0xA2,0xC2,0x90,0xC6,0x88,0x14,0x39,0x09,0x90,0xC0,0x50,0x0C,0xE1, ++ 0xF0,0x8A,0x8A,0x14,0x08,0x09,0x88,0x0C,0x70,0x41,0xD1,0x3E,0x78,0x41,0xD1,0x2E, ++ 0xC9,0x1C,0x48,0x41,0xD0,0x16,0xC8,0x14,0x49,0x41,0xD9,0x06,0x08,0x01,0x00,0xEF, ++ 0x00,0xE0,0x07,0x01,0x10,0x00,0x00,0x42,0xF8,0x00,0x06,0x42,0x80,0x30,0x02,0x01, ++ 0x18,0x00,0x02,0x42,0x80,0x60,0x05,0x00,0x70,0x00,0x04,0x01,0xF8,0xFF,0x07,0x00, ++ 0x80,0x50,0x06,0x01,0x08,0x40,0x00,0x01,0x60,0x20,0x02,0x00,0x00,0x60,0x00,0x01, ++ 0x00,0x28,0x00,0x01,0x80,0xC0,0x04,0x01,0x00,0x20,0x00,0x01,0x88,0x0C,0x08,0x19, ++ 0x86,0x27,0xD0,0x37,0x10,0x82,0xED,0x3E,0x10,0xC2,0xED,0x2E,0xCC,0x1C,0x10,0x42, ++ 0xE8,0x16,0xC8,0x14,0x10,0x42,0xE4,0x0E,0x00,0x01,0x80,0x0C,0xC0,0x0C,0x40,0x01, ++ 0x80,0x86,0xC8,0x24,0xD6,0x2C,0x78,0x40,0xC2,0x00,0x82,0x00,0xD0,0x48,0x90,0x4D, ++ 0x1F,0x8C,0x54,0xFA,0x58,0xFA,0xC7,0x93,0xC0,0xDB,0x18,0xD2,0x80,0x16,0xD0,0x40, ++ 0xCC,0x2C,0x18,0x44,0xE7,0x20,0x93,0x25,0x60,0x29,0x90,0x06,0x3B,0x4F,0xE3,0x68, ++ 0x90,0x6D,0x6F,0x71,0x92,0x06,0x38,0xF7,0x87,0x3D,0xE8,0x85,0xA8,0xC5,0x2F,0x01, ++ 0x40,0xAA,0xFF,0x03,0x81,0x04,0x00,0x5F,0x07,0x31,0x48,0xA2,0x1A,0x42,0xC3,0x00, ++ 0x0C,0xC9,0x09,0x48,0xC0,0x30,0x3A,0x11,0xF8,0xBA,0x07,0x21,0xF0,0x82,0x41,0x51, ++ 0xD0,0x0E,0x20,0x51,0x00,0x0F,0xC0,0x51,0x96,0x25,0x00,0x19,0x04,0x00,0x14,0x22, ++ 0xE8,0x06,0x30,0x22,0x37,0x02,0xC1,0xF9,0xC0,0x89,0x0C,0xF1,0x1F,0x42,0x0A,0xF9, ++ 0x88,0x89,0x84,0x27,0xD0,0xAF,0xCB,0x00,0x90,0x05,0x40,0x51,0xD0,0x06,0x00,0x51, ++ 0x4C,0x1A,0x17,0x42,0xE8,0x06,0x30,0x42,0x05,0xBC,0x03,0x84,0xE7,0x68,0x93,0x6D, ++ 0xC5,0x04,0x10,0x42,0xC7,0x86,0xEE,0xC5,0xAC,0x85,0x87,0x3D,0x00,0xF9,0x87,0x0C, ++ 0x00,0x01,0x80,0x04,0x81,0x14,0x18,0x39,0x09,0xD8,0x24,0x39,0x57,0xBA,0x1E,0x22, ++ 0x04,0x08,0xC2,0x48,0xC0,0x68,0x0E,0xE1,0xF2,0x4A,0xE3,0x00,0x92,0x05,0x40,0x31, ++ 0xD8,0xB6,0x07,0x01,0x80,0x24,0x00,0x01,0x38,0x01,0x28,0x01,0x30,0xF9,0xCF,0x24, ++ 0x12,0x51,0x18,0x8A,0x54,0x6A,0xC6,0x48,0x54,0x72,0xC6,0x50,0x90,0x34,0x08,0x01, ++ 0x20,0x01,0xF8,0xA2,0x60,0xA1,0xE8,0x0E,0xE1,0xF8,0x93,0xFD,0xC0,0x00,0x91,0x05, ++ 0x10,0x62,0xED,0x06,0x35,0x2A,0x11,0xA2,0xD1,0x06,0x30,0x32,0xE2,0x90,0xE4,0x48, ++ 0x90,0x4D,0x4E,0x29,0x99,0x66,0x6F,0xE1,0xED,0x16,0x50,0xFA,0x0C,0x01,0xA8,0x8B, ++ 0x08,0x29,0x80,0x27,0xD0,0x2F,0x91,0x0D,0xD0,0x40,0x83,0x71,0x40,0xE1,0xC0,0x6E, ++ 0xD0,0x80,0x83,0x71,0x40,0xE1,0xC0,0x4E,0x68,0xE1,0xE9,0x3E,0x78,0x21,0xE8,0x2E, ++ 0x50,0xA2,0x05,0x01,0x85,0x83,0x40,0x92,0x10,0xD1,0x87,0x13,0xC4,0x14,0x10,0x42, ++ 0xD0,0x06,0x88,0x14,0xC5,0x0C,0x10,0x82,0xE8,0x06,0xB0,0x0C,0xC5,0x04,0x10,0x42, ++ 0xD0,0x06,0xA8,0x04,0x6D,0x6A,0x75,0x7A,0xC0,0x34,0x18,0x01,0x48,0x01,0xE8,0xBE, ++ 0x14,0x01,0xF0,0x12,0x10,0x52,0xDC,0x76,0x61,0x2A,0xC5,0x23,0x60,0x01,0x80,0x16, ++ 0xD0,0x90,0x02,0x14,0x01,0xC7,0x50,0xE1,0xD6,0xB6,0x78,0x60,0xC3,0x20,0x83,0x20, ++ 0xD8,0x90,0x00,0x14,0x00,0x87,0x50,0x01,0xE8,0x76,0x10,0x09,0x00,0x14,0x00,0x5F, ++ 0x14,0x01,0xF0,0x12,0x10,0x52,0xE4,0x16,0xD0,0x90,0x02,0x14,0x00,0x27,0x50,0x01, ++ 0xD0,0x16,0x10,0x01,0x18,0x92,0x06,0x14,0xE2,0x00,0xE4,0xD8,0x90,0xDD,0x5E,0x29, ++ 0x98,0xA6,0xC6,0x24,0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x44,0x71,0x98,0x16, ++ 0x20,0x01,0x00,0x01,0x08,0x01,0x10,0x01,0x94,0x1C,0x50,0x82,0x04,0x18,0xC3,0xD0, ++ 0x5E,0x82,0xC4,0xA8,0x30,0x72,0x19,0x01,0x15,0x01,0xF0,0x52,0xC0,0x80,0x90,0x05, ++ 0xE0,0x48,0x92,0x4D,0xFD,0x1C,0x10,0xD2,0xE8,0x06,0x90,0x1C,0xAA,0x51,0xE0,0xD8, ++ 0x90,0xDD,0x5E,0x71,0x98,0x86,0x87,0x27,0xC8,0x9F,0x95,0x2D,0xC5,0x14,0x10,0x42, ++ 0xD0,0x06,0xA8,0x14,0x00,0x01,0x80,0x24,0x68,0x01,0xE8,0xDE,0x3F,0x01,0xF8,0xBA, ++ 0x10,0x7A,0xDD,0x96,0x60,0x01,0x80,0x0E,0x60,0x21,0x88,0x16,0xD9,0xC0,0x03,0x84, ++ 0x00,0xB7,0x08,0x19,0xC0,0x1C,0x80,0x27,0xCD,0xDF,0x14,0x42,0xD7,0x86,0x78,0x40, ++ 0xCA,0x00,0x82,0x00,0xD1,0xC0,0x01,0x84,0x00,0x57,0x78,0x01,0xE8,0x46,0x00,0x09, ++ 0x00,0x84,0x01,0x2F,0x01,0x01,0xF0,0x82,0x10,0x42,0xE5,0x0E,0xD9,0x00,0x02,0x84, ++ 0xB0,0x51,0xC0,0x24,0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x46,0x71,0x98,0x9E, ++ 0xE7,0x20,0x93,0x25,0x65,0x29,0x98,0x66,0x43,0x2A,0x4B,0x32,0xC0,0x03,0xC0,0x4B, ++ 0x33,0x22,0x58,0x4A,0x50,0x4A,0x1B,0x62,0x88,0xB6,0x01,0x01,0x4A,0x1A,0x03,0x20, ++ 0xC3,0x08,0x63,0x22,0xCB,0x60,0x68,0x1A,0xAA,0x51,0xC8,0x68,0x31,0xF9,0x0C,0xB0, ++ 0xC8,0x78,0x34,0x01,0xF8,0xF2,0x3D,0x01,0xFD,0x7A,0x17,0xF2,0xD0,0x3E,0x28,0x01, ++ 0xF8,0x2A,0x6B,0xA1,0xE8,0x1E,0x78,0x79,0xEB,0x0E,0x00,0x68,0x02,0x2C,0x61,0xD2, ++ 0xA0,0x51,0xC8,0x60,0xC4,0x70,0xC6,0x68,0x0B,0x01,0xF0,0x4A,0x2B,0x01,0xF8,0xAA, ++ 0x10,0x4A,0xD5,0x66,0x0B,0x01,0xF0,0x0A,0x48,0xA1,0xE8,0x46,0x68,0x79,0xE8,0x36, ++ 0x7B,0x70,0xC6,0xA8,0x83,0x68,0x03,0x70,0xCB,0x68,0xC5,0x48,0x02,0x0C,0xE1,0x00, ++ 0x90,0x05,0x46,0x29,0x9C,0x56,0x36,0xFF,0x47,0x01,0x80,0xE6,0x22,0x01,0x40,0x3A, ++ 0x00,0x08,0xC3,0x68,0x41,0x3A,0xC2,0x70,0x40,0x32,0x82,0x51,0xC4,0x40,0x09,0xF9, ++ 0x0B,0x48,0xC0,0x78,0x10,0x01,0x08,0x01,0xF2,0xD2,0xF5,0x0A,0x10,0x52,0xD4,0x6E, ++ 0x01,0x01,0xF0,0x82,0x81,0x2C,0x40,0x41,0xE8,0x46,0x48,0x79,0xEC,0x36,0x00,0x00, ++ 0x08,0x29,0x80,0x27,0xC8,0xEF,0xC8,0x2C,0xC1,0x00,0x02,0x84,0x40,0xD2,0x81,0x51, ++ 0xC1,0x40,0x49,0xD2,0xC0,0x48,0x1B,0x01,0x17,0x01,0xF0,0xDA,0xF4,0x52,0x14,0x9A, ++ 0xD0,0x3E,0x08,0x01,0xF1,0x0A,0x4A,0x41,0xE8,0x1E,0x50,0x79,0xEA,0x0E,0x00,0x48, ++ 0x03,0x0C,0xE0,0x20,0x90,0x25,0x67,0x29,0x9B,0x4E,0x36,0x2F,0xA9,0xC5,0x47,0x52, ++ 0x17,0x09,0x80,0x01,0xC0,0x0B,0x18,0x8A,0x81,0x0B,0x68,0x3A,0x79,0x22,0x31,0x62, ++ 0xA4,0x01,0x06,0x27,0xBB,0xFF,0xEF,0xFF,0x48,0x4A,0x41,0x43,0xE0,0x00,0x02,0x43, ++ 0x40,0x42,0xC1,0x03,0x40,0x01,0x80,0x0E,0x05,0xC1,0xB0,0x43,0x40,0xF2,0x80,0x1F, ++ 0xE9,0xE7,0x50,0x2A,0x48,0xEA,0x40,0xE2,0x86,0x1F,0xC8,0x3F,0xB9,0xFF,0xEF,0x7F, ++ 0x01,0x11,0x88,0x03,0x50,0x02,0x49,0xC2,0x40,0xC2,0x80,0x1F,0xD8,0x37,0x55,0xF2, ++ 0x48,0xAA,0x40,0xB2,0x85,0x1F,0xF8,0xE7,0xC8,0x03,0x43,0x01,0x83,0x16,0xC8,0x03, ++ 0x40,0x11,0x88,0x26,0x48,0xCA,0x40,0x43,0x10,0x09,0x18,0x82,0x00,0x43,0x48,0x72, ++ 0x40,0x72,0x80,0x1F,0xF0,0x47,0x73,0x5A,0xC1,0xCB,0xC1,0x83,0x18,0x42,0x80,0x0E, ++ 0x05,0x01,0xA8,0x43,0xBA,0xFF,0xF7,0xC7,0x41,0x8A,0xC0,0x8B,0x09,0x0C,0xC6,0xCB, ++ 0x11,0x0C,0xC8,0x4B,0x10,0x0C,0x72,0x22,0xB5,0x01,0xE2,0x8B,0x10,0x0C,0x04,0xCF, ++ 0x00,0x48,0x00,0x01,0x00,0x40,0x00,0x01,0x00,0xE0,0x00,0x01,0x08,0x40,0x00,0x01, ++ 0x18,0x10,0x00,0x00,0x48,0xE0,0x06,0x00,0x50,0xA0,0x02,0x00,0x50,0x50,0x02,0x00, ++ 0x00,0xA0,0x00,0x01,0x00,0x20,0x00,0x01,0x80,0xC0,0x04,0x01,0xF8,0x00,0x06,0x42, ++ 0x70,0x40,0x04,0x01,0x48,0xA2,0x40,0x4C,0x10,0x0C,0x4E,0xA2,0x40,0x4B,0x18,0x0C, ++ 0xA2,0x48,0x18,0x0C,0xEC,0x4B,0x1D,0x0C,0xBA,0xFF,0xEF,0x57,0x05,0x11,0xA0,0x83, ++ 0x32,0x8A,0xC9,0x01,0x40,0x72,0x80,0x1F,0xE9,0x9F,0x31,0x8A,0x12,0x09,0xC8,0x01, ++ 0x40,0x5A,0x58,0x62,0x80,0x17,0xE8,0xD7,0xBC,0xFF,0xDF,0x97,0x32,0x8A,0xC9,0x01, ++ 0x40,0x3A,0x80,0x0F,0xF0,0xDF,0x82,0x07,0xDF,0x0F,0xBA,0xFF,0xE3,0xE7,0xCE,0x03, ++ 0x40,0x31,0x80,0x06,0x3F,0xB7,0xEB,0xC5,0x00,0x60,0x00,0x01,0x00,0xA0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x30,0x48,0x00,0x00,0xA8,0x85,0x33,0x22,0xF0,0x03,0x87,0x07, ++ 0xF2,0x2F,0x46,0x7A,0x2C,0x01,0x00,0x2B,0xB6,0x2B,0x05,0x21,0xAF,0x2A,0xB8,0xFF, ++ 0xE5,0xE7,0xA1,0x01,0xCA,0x03,0x33,0x08,0x42,0x52,0x72,0x48,0x1C,0x0B,0x5C,0x0B, ++ 0x02,0x48,0x1A,0x0B,0x0B,0x2B,0xCE,0x0B,0x30,0x48,0xA8,0x16,0x0E,0x09,0x04,0x0B, ++ 0x1B,0x2B,0xE8,0x85,0xAD,0x85,0x87,0xAD,0x42,0x12,0xC2,0x01,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x52,0x02,0x4A,0x0A,0x40,0x0A,0x82,0x0F,0xCA,0xB7,0x40,0x0A, ++ 0x71,0xFA,0xC1,0x80,0x81,0xA4,0x41,0xEA,0xB6,0xE1,0x81,0x01,0x83,0x9C,0x01,0x47, ++ 0x47,0xD2,0xB9,0xFF,0xF9,0x4F,0x66,0xCA,0x52,0x03,0x83,0x01,0xE7,0x03,0x40,0x79, ++ 0x81,0x06,0x31,0x12,0x48,0xB2,0x01,0x01,0x58,0x9A,0x81,0x07,0xF9,0x5F,0x36,0x12, ++ 0x48,0x9A,0x01,0x09,0x58,0x82,0x81,0x07,0xFB,0x2F,0x56,0x03,0x80,0x01,0xE2,0x03, ++ 0x40,0x59,0x8D,0x7E,0xC1,0xA4,0x31,0x8A,0x13,0x01,0xD8,0x1B,0xDB,0x2B,0x19,0x5A, ++ 0x40,0x6C,0x40,0x3C,0xD8,0x68,0x07,0x2C,0xE4,0x00,0xE4,0x48,0xE4,0x90,0x92,0x95, ++ 0x17,0xD2,0x9C,0xAE,0x52,0x03,0x83,0x01,0xE5,0x03,0x40,0x59,0x81,0x2E,0x50,0x12, ++ 0x49,0x12,0x41,0x1A,0x58,0x0D,0x80,0x0F,0xC1,0x07,0xEC,0xA4,0x30,0xA2,0x39,0x01, ++ 0x01,0x01,0xF0,0x42,0x0A,0x99,0x18,0x42,0x08,0x51,0x80,0x1F,0xF9,0x8F,0x07,0x44, ++ 0x01,0x01,0xF0,0x02,0x0A,0x99,0x18,0x42,0x08,0x51,0x80,0x1F,0xF9,0x4F,0x07,0x04, ++ 0xE5,0x68,0xE5,0x20,0xE7,0xF8,0x93,0xFD,0x7F,0x29,0x98,0x4E,0x68,0xB2,0x60,0xA2, ++ 0xA0,0xF1,0x3D,0x01,0x01,0x01,0xF0,0x42,0x08,0x51,0x08,0x00,0x86,0x1F,0xF8,0xC7, ++ 0x00,0x44,0x01,0x01,0xF0,0x02,0x09,0x51,0x08,0x00,0x80,0x1F,0xF9,0x8F,0x06,0x04, ++ 0xE5,0x68,0xE5,0x20,0xE7,0xF8,0x93,0xFD,0x7F,0x29,0x98,0x5E,0x40,0x0D,0x80,0x07, ++ 0xD9,0xDF,0xC1,0x9C,0xC8,0x03,0x42,0x31,0x81,0x96,0x84,0xAD,0xE8,0x85,0x07,0x00, ++ 0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x80,0xC0,0x04,0x01,0x00,0xE0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x48,0xE0,0x06,0x00,0x58,0x30,0x03,0x01,0x48,0xFA,0xFF,0x53, ++ 0x84,0x13,0xF8,0x53,0x80,0x13,0x32,0x52,0x96,0x01,0xCE,0x93,0x80,0x13,0xCC,0x4B, ++ 0x83,0x0B,0x3E,0x82,0xA8,0xC5,0xF7,0x34,0x37,0x22,0x40,0xC2,0xFD,0x03,0x16,0x02, ++ 0xC9,0xFE,0x01,0x21,0x6B,0xB2,0x1F,0x02,0xCB,0x28,0x02,0x99,0x09,0x00,0xC2,0x40, ++ 0x2A,0xA1,0xF8,0x2A,0x3E,0xB1,0xF8,0x3A,0x48,0x09,0x88,0x1E,0x0F,0xF9,0x8F,0x09, ++ 0xD8,0x48,0x92,0x6D,0x50,0x09,0x88,0x1E,0x0A,0xC9,0x08,0x48,0xD8,0x48,0x96,0x7D, ++ 0xCE,0x0B,0xCC,0x13,0x0A,0x48,0x00,0x90,0x18,0x8A,0x80,0xCB,0x8A,0x48,0x81,0xCB, ++ 0x8C,0xC8,0x81,0xCB,0x39,0xD0,0x09,0x48,0x78,0x90,0x18,0x8A,0x86,0xCB,0xE6,0xD8, ++ 0xE0,0xE8,0x5A,0x04,0x08,0xA1,0x80,0x1F,0xF8,0x4F,0x83,0x51,0x97,0x05,0x46,0xF9, ++ 0x97,0x56,0x58,0x02,0xE8,0xCA,0x30,0x52,0x94,0x51,0x10,0x12,0x91,0x16,0x80,0x43, ++ 0xA8,0xC2,0x00,0x1F,0x80,0x4B,0x01,0x0F,0x01,0xF9,0x87,0x43,0xC2,0x83,0xE9,0x00, ++ 0x87,0x83,0xE9,0xC5,0xAC,0x85,0x87,0x2D,0x36,0x01,0x00,0xBD,0x40,0x03,0x80,0x14, ++ 0x44,0x92,0xFE,0x1B,0x10,0x09,0x00,0x01,0x4E,0xA2,0x66,0xAA,0xC5,0x6B,0x68,0x59, ++ 0x82,0x16,0xE0,0x00,0x17,0x02,0x9D,0xCE,0x00,0xF9,0x87,0x43,0x58,0x01,0x80,0xBE, ++ 0x30,0x01,0x48,0x15,0x03,0x01,0x20,0x99,0x5B,0x4A,0x0E,0x20,0x01,0x77,0x28,0x21, ++ 0x1F,0x2A,0xC2,0x68,0xC9,0x68,0xD1,0x6B,0x68,0x09,0x88,0x2E,0x83,0x43,0xE0,0xB0, ++ 0x92,0xB5,0xE7,0x48,0x70,0x09,0x80,0x1E,0xE6,0x00,0x92,0x05,0x17,0x82,0x9C,0x76, ++ 0x73,0x01,0x80,0x16,0x60,0x0A,0x6E,0x15,0x3D,0x01,0x40,0xE2,0x80,0x01,0x87,0x1C, ++ 0x00,0x0F,0x79,0x01,0x88,0x9E,0x50,0x0D,0x90,0x04,0x10,0x01,0xC1,0x43,0x31,0x1A, ++ 0x37,0x8A,0xB8,0xFF,0xFB,0xBF,0xE3,0x68,0xC4,0x1C,0xC0,0x03,0x4E,0x00,0x0E,0x00, ++ 0x1B,0x82,0x89,0x03,0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x4F,0x50,0x0D, ++ 0x90,0x04,0x10,0x01,0xC1,0x43,0x31,0x1A,0x37,0x8A,0xB8,0xFF,0xFB,0x1F,0xE3,0x68, ++ 0xEB,0x20,0xE3,0xF8,0x95,0xFD,0x17,0xBA,0x98,0xDE,0xC6,0x1C,0x1C,0x01,0xC4,0x03, ++ 0x48,0x08,0x4E,0x01,0x80,0x9E,0x70,0x01,0x81,0x3E,0x80,0x03,0xC0,0x1C,0xC8,0x03, ++ 0x85,0x03,0x03,0x59,0x85,0x03,0xE5,0x20,0x01,0x3F,0x80,0x03,0xC0,0x1C,0xC8,0x03, ++ 0x83,0x03,0x8B,0x1B,0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x27,0x70,0x09, ++ 0xCD,0x16,0x00,0x59,0x83,0x03,0xE1,0x20,0x37,0x02,0xB9,0xFF,0xFC,0x7F,0x41,0xEA, ++ 0x42,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x4A,0xDA,0x44,0x43,0x1A,0xC2,0x00,0x43, ++ 0x61,0xD2,0x44,0x03,0x42,0x00,0x02,0x00,0x07,0x03,0x01,0xF9,0x80,0x89,0x84,0x1F, ++ 0xE9,0x6F,0x46,0x03,0x08,0x09,0x18,0x42,0x00,0x03,0x81,0x2D,0xEF,0x85,0xAF,0xFD, ++ 0x80,0x0D,0xFC,0x54,0x30,0x32,0x30,0x62,0x6F,0x42,0xAC,0x01,0x50,0x09,0x88,0x4E, ++ 0x00,0x0F,0x80,0x0F,0xC1,0x6F,0xC0,0x43,0x37,0x00,0xAA,0xD6,0xC5,0x43,0x09,0xF9, ++ 0x01,0x42,0x80,0x43,0x04,0x09,0x30,0x22,0x51,0x3A,0x04,0x8F,0x60,0x01,0xC1,0x2E, ++ 0xF7,0x00,0x0B,0x01,0x1A,0x42,0x08,0x83,0x30,0x0A,0x01,0x17,0x02,0xF9,0x0F,0x83, ++ 0x08,0x01,0x19,0x01,0x08,0x9B,0x04,0x01,0x00,0x4F,0x78,0x01,0x88,0x16,0x18,0x01, ++ 0x00,0x9B,0x06,0x17,0xC6,0x9B,0x01,0x9B,0xCA,0xB0,0xE7,0x00,0x94,0x05,0x14,0x42, ++ 0x9B,0x9E,0x37,0x02,0x40,0x01,0x80,0x26,0x04,0xA1,0x00,0x83,0x04,0x01,0x30,0x22, ++ 0x00,0x0F,0x00,0x21,0x03,0x83,0xD4,0x00,0x92,0x25,0x44,0x83,0x08,0x01,0x1C,0x42, ++ 0x01,0x83,0xC2,0x43,0x37,0x00,0xAA,0xE6,0xC5,0x43,0x09,0xF9,0x01,0x42,0x80,0x43, ++ 0x66,0x01,0x88,0x5E,0xC0,0x24,0x40,0x09,0x88,0x7E,0x05,0x01,0x02,0x83,0x44,0x83, ++ 0x08,0x01,0x1C,0x42,0x05,0x83,0x3A,0x47,0xAC,0x9D,0x87,0x1D,0x20,0x01,0x00,0x01, ++ 0x80,0x0C,0x70,0x15,0x44,0xEA,0xF2,0x03,0xEE,0x00,0x92,0x3D,0x6F,0xDA,0xAA,0x01, ++ 0x00,0xAF,0x81,0x07,0xF9,0xAF,0xC5,0x43,0x30,0x00,0xA2,0x1E,0x44,0xBA,0xF2,0x03, ++ 0x17,0xC2,0x9D,0xB6,0x44,0xAA,0xF2,0x03,0x10,0xC2,0x9D,0x06,0x21,0x11,0xC0,0x43, ++ 0x08,0xF9,0x05,0x42,0x82,0x43,0x41,0xC2,0x46,0x0B,0x14,0x79,0x00,0x8A,0x48,0x09, ++ 0x88,0x9E,0x08,0x01,0x0E,0x0B,0x44,0x0B,0x83,0x8B,0xE1,0xB0,0xE7,0x20,0x93,0x25, ++ 0x60,0x11,0x88,0x56,0x30,0x5A,0xD3,0xCB,0xD4,0x1C,0x10,0x8A,0x8A,0x2E,0xD0,0xCB, ++ 0xD4,0x24,0x10,0x8A,0x88,0x0E,0x08,0x09,0x8F,0x0C,0x08,0x01,0x08,0x0B,0x0A,0x01, ++ 0x08,0x0B,0x0C,0x81,0x02,0x0B,0x44,0x0B,0x10,0x01,0x1C,0x8A,0x00,0x0B,0x62,0x11, ++ 0x88,0x4E,0xC6,0x0C,0x39,0x0F,0x4B,0xEA,0x60,0x54,0x80,0x13,0x12,0x01,0x80,0x13, ++ 0xE4,0x4B,0x86,0x0B,0x4A,0x0A,0x8A,0x01,0x5E,0x53,0x84,0x13,0x58,0x53,0x8A,0x13, ++ 0x12,0xA9,0x88,0x13,0x14,0x19,0x88,0x13,0x4E,0x53,0x8E,0x13,0x48,0x53,0x94,0x13, ++ 0x4A,0x4B,0x92,0x0B,0x0C,0x31,0x90,0x0B,0x3F,0x82,0xAB,0x85,0x80,0x4D,0x34,0x22, ++ 0x30,0x01,0x00,0x01,0x80,0x2C,0x38,0x01,0x48,0x62,0xD9,0x43,0xDA,0x4B,0x1A,0x42, ++ 0x81,0x14,0x40,0x5A,0x80,0x71,0x80,0x24,0xC0,0x71,0x80,0x1C,0x60,0x09,0x80,0x0E, ++ 0x60,0x29,0x88,0x7E,0x60,0x09,0x88,0x26,0x73,0x6A,0xE1,0x80,0x81,0x2C,0x78,0x6A, ++ 0x01,0x27,0x70,0x6A,0xE0,0x80,0x83,0x2C,0x79,0x52,0xF9,0xC1,0x47,0x35,0xB8,0xFF, ++ 0xF0,0xEF,0x01,0x3F,0x60,0x21,0x88,0x2E,0x70,0x42,0x41,0x35,0xBD,0xFF,0xFF,0xDF, ++ 0x7B,0x22,0xB9,0x11,0x6F,0xCA,0xA8,0x01,0xC5,0x43,0x09,0xF9,0x01,0x42,0x80,0x43, ++ 0xC1,0x43,0x09,0x01,0x19,0x42,0x80,0x43,0x42,0xD2,0x40,0x0B,0x10,0x01,0x1A,0x8A, ++ 0x00,0x0B,0x42,0xCA,0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x48,0xBA,0x40,0x43, ++ 0x10,0x09,0x18,0x82,0x00,0x43,0x08,0x09,0x07,0x01,0xBC,0xFF,0xF8,0xAF,0x42,0x09, ++ 0x88,0x5E,0x62,0x21,0x88,0x56,0x12,0x09,0x91,0x04,0x30,0x82,0x18,0x01,0xC8,0x14, ++ 0xBF,0xFF,0xF7,0xAF,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x59,0x40,0x35,0x30,0x9A, ++ 0xBF,0xFF,0xF7,0x6F,0x10,0x09,0x90,0x04,0x10,0x01,0x00,0xCF,0x00,0xE0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x80,0x00,0x06,0x01,0x00,0xF8,0x07,0x00,0x80,0x30,0x02,0x01, ++ 0x30,0x04,0x05,0x08,0x00,0x00,0x06,0x42,0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42, ++ 0x18,0x60,0x05,0x01,0x70,0x70,0x06,0x01,0x50,0x20,0x07,0x01,0x68,0x60,0x02,0x01, ++ 0x09,0x29,0x30,0xC2,0x37,0x9A,0xB8,0xFF,0xF0,0x57,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x0E,0x71,0x40,0x0A,0x37,0x9A,0xB8,0xFF,0xF0,0x17,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x29,0x30,0x9A,0xC7,0x24,0xB8,0xFF,0xF0,0xD7,0x15,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x29,0x18,0x09,0xC7,0x1C,0xB8,0xFF,0xF1,0x97,0x05,0x9F,0x60,0x09,0x80,0x0E, ++ 0x61,0x29,0x88,0x7E,0x10,0x11,0x90,0x04,0x11,0x09,0x30,0x82,0x18,0x01,0xC8,0x14, ++ 0xBD,0xFF,0xF7,0x2F,0x10,0x11,0x90,0x04,0x10,0x01,0x30,0x9A,0xC8,0x14,0xC0,0x2C, ++ 0xBC,0xFF,0xF7,0xEF,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x21,0x40,0x35,0x30,0x9A, ++ 0xBC,0xFF,0xF7,0xAF,0x10,0x09,0x90,0x04,0x11,0x01,0x08,0x31,0x30,0xC2,0x31,0x9A, ++ 0xBC,0xFF,0xF7,0x6F,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x29,0x30,0x9A,0xC0,0x24, ++ 0xBC,0xFF,0xF7,0x2F,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x29,0x18,0x09,0xC0,0x1C, ++ 0xBB,0xFF,0xF7,0xEF,0xC6,0x43,0x09,0xF9,0x01,0x42,0x80,0x43,0x40,0xDA,0x44,0x0B, ++ 0x42,0x48,0x02,0x48,0x04,0x0B,0x40,0xD2,0x0A,0x01,0x0F,0x0B,0x0C,0x01,0x00,0x0B, ++ 0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x87,0x4D,0xE8,0x85,0xAC,0x85,0x63,0xAA, ++ 0xC8,0x03,0x43,0x09,0x83,0x16,0xC8,0x03,0x40,0x29,0x88,0x86,0x46,0x8A,0xC4,0x01, ++ 0x82,0x1F,0xC8,0xDF,0x69,0x82,0xC4,0x43,0x40,0x11,0x98,0x2E,0xCF,0x03,0xBB,0xFF, ++ 0xF8,0x67,0x00,0x01,0x83,0x43,0xE9,0x85,0xE1,0x00,0x82,0x43,0xEB,0x85,0xCB,0x03, ++ 0x40,0x21,0x88,0x26,0xB8,0xFF,0xFF,0x0F,0x03,0x19,0x88,0x03,0xEB,0x85,0xCB,0x03, ++ 0x47,0x19,0x80,0xDE,0xC8,0x03,0x43,0x31,0x84,0xC6,0x47,0x12,0xC4,0x01,0xFE,0x03, ++ 0x40,0x01,0x88,0x3E,0x41,0xFA,0x83,0x01,0xD0,0x0B,0x48,0x31,0x9C,0x76,0xC7,0x03, ++ 0x37,0x00,0xA8,0x5E,0x44,0xDA,0xC3,0x01,0xE8,0x03,0x44,0x01,0x8F,0x36,0xBF,0xFF, ++ 0xEB,0xCF,0xEC,0x85,0xA8,0xC5,0x27,0x01,0x30,0x1A,0x00,0x09,0x4B,0xAA,0x6B,0xBA, ++ 0x30,0x01,0x59,0x51,0x80,0xE6,0xE1,0x4E,0x79,0xAA,0xC3,0xD3,0x85,0x1F,0xE8,0xFF, ++ 0x61,0x52,0x20,0x09,0x39,0x61,0x62,0x52,0x71,0x61,0x62,0x92,0x40,0x6A,0x13,0x31, ++ 0xC2,0x01,0x56,0x03,0x80,0x01,0x5A,0xC9,0x80,0xAE,0xE1,0x4E,0x59,0x59,0x80,0x56, ++ 0x59,0x61,0x80,0x66,0x59,0x69,0x88,0xBE,0x02,0x29,0x88,0x43,0x21,0x09,0x00,0x9F, ++ 0x59,0xD1,0x80,0x6E,0x59,0x01,0x89,0x7E,0x88,0x53,0x22,0x09,0x08,0x59,0xA5,0x0B, ++ 0x00,0x57,0x01,0x39,0x89,0x43,0x02,0x3F,0x86,0x07,0xE8,0xA7,0x00,0x27,0x19,0x12, ++ 0x81,0xD3,0x01,0x0F,0x00,0x41,0x18,0x12,0x80,0xD3,0x01,0xEF,0x02,0x11,0x88,0x43, ++ 0x20,0x09,0x00,0xCF,0x02,0x01,0x88,0x43,0x41,0x43,0x19,0x82,0x00,0x43,0x01,0x9F, ++ 0x88,0x43,0x22,0x09,0x00,0x87,0x00,0x19,0x88,0x43,0x22,0x09,0x00,0x67,0x00,0x21, ++ 0x88,0x43,0x22,0x09,0x02,0x47,0x88,0x53,0x26,0x09,0x08,0x69,0xA0,0x0B,0x00,0x1F, ++ 0x88,0x53,0x22,0x09,0x08,0x79,0xA7,0x0B,0x60,0x01,0x80,0x66,0x40,0x6A,0x42,0x0B, ++ 0x30,0x48,0xA8,0x2E,0x08,0x81,0x06,0x0B,0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B, ++ 0x45,0x43,0x19,0x82,0x07,0x43,0xE9,0xC5,0xAC,0x8D,0x87,0x15,0x40,0x32,0x82,0x0C, ++ 0x46,0x02,0xC2,0x01,0xDA,0x2B,0xD8,0x33,0x0C,0x01,0xB0,0x0B,0x61,0x02,0xC2,0x0B, ++ 0x10,0xF9,0x05,0x8A,0x81,0x0B,0xC1,0x0B,0x10,0x01,0x19,0x8A,0x81,0x0B,0x49,0xEA, ++ 0x8A,0x01,0x46,0x53,0x18,0x01,0x1A,0xD2,0x01,0x53,0x52,0xAA,0x44,0x8B,0x1A,0x01, ++ 0x1A,0xCA,0x00,0x8B,0x48,0x8A,0x41,0x53,0x18,0x09,0x18,0xD2,0x02,0x53,0x50,0x03, ++ 0x80,0x01,0xE2,0x0B,0x49,0x79,0x87,0xAE,0xE6,0x03,0x40,0x69,0x88,0x16,0x09,0xA9, ++ 0x07,0x91,0xB8,0xFF,0xE8,0x4F,0x47,0x09,0x89,0xDE,0x31,0x42,0x1A,0x82,0x03,0x38, ++ 0x15,0x09,0x90,0xCD,0x90,0x04,0x18,0x01,0xC7,0x0C,0xB8,0xFF,0xE9,0x47,0x44,0x5A, ++ 0x10,0x09,0x90,0x04,0x15,0x01,0x90,0xCD,0x37,0x9A,0xB8,0xFF,0xE8,0x07,0xC4,0x14, ++ 0x15,0x09,0xC8,0x48,0xE8,0x48,0x90,0x04,0x00,0x48,0x12,0x01,0x1F,0x09,0xB8,0xFF, ++ 0xE8,0xB7,0x03,0xF7,0x08,0xA1,0x00,0x91,0xBE,0xFF,0xEF,0x37,0x40,0x09,0x88,0xC6, ++ 0x18,0xAA,0x13,0x09,0x20,0x40,0x63,0x08,0x90,0x04,0x30,0x9A,0xC7,0x0C,0xB8,0xFF, ++ 0xE8,0x37,0x03,0x77,0x08,0xB1,0x00,0x91,0xBD,0xFF,0xEF,0xB7,0x40,0x09,0x88,0x46, ++ 0xC0,0x14,0x10,0x09,0xC8,0x48,0xED,0x48,0x00,0x48,0x32,0x9A,0x97,0x04,0xB8,0xFF, ++ 0xE9,0xB7,0xC2,0x03,0x08,0xF9,0x06,0x42,0x80,0x03,0x41,0x42,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x47,0x32,0x08,0x01,0x08,0x0B,0x0A,0x01,0x02,0x0B,0x44,0x0B, ++ 0x10,0x01,0x1C,0x8A,0x07,0x0B,0xEA,0xF5,0x70,0x00,0x04,0x01,0xF8,0x00,0x06,0x42, ++ 0x80,0x01,0x06,0x42,0x00,0xE0,0x06,0x01,0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x42, ++ 0x00,0xE0,0x07,0x01,0x00,0x00,0x00,0x42,0x50,0x20,0x07,0x01,0x08,0x20,0x02,0x01, ++ 0x52,0x2A,0x44,0x83,0x04,0x83,0x42,0x2A,0xF7,0x0B,0x4C,0xF9,0x94,0x16,0xF0,0x0B, ++ 0xE4,0x48,0xB2,0x0B,0xF0,0x03,0x44,0xC1,0x90,0x0E,0x00,0x01,0x03,0x83,0x3C,0x82, ++ 0x4C,0xFA,0x4B,0x53,0x5C,0xEA,0xE3,0xC3,0x1C,0x12,0x0C,0x53,0x10,0x43,0x02,0x09, ++ 0xB3,0xC3,0x3C,0x82,0xAB,0x85,0x40,0xD2,0x84,0x01,0x42,0x0B,0x10,0x01,0x1C,0x8A, ++ 0x03,0x0B,0x54,0xC2,0x4B,0xAA,0x43,0xC2,0x87,0x1F,0xC0,0x27,0xEF,0x85,0xA8,0xC5, ++ 0x47,0x92,0x83,0x01,0xC3,0x0B,0x70,0xAA,0x30,0x48,0xAC,0x46,0xC2,0x0B,0x10,0x01, ++ 0x18,0x8A,0x80,0x0B,0x44,0x83,0x0B,0x01,0x1B,0x42,0x04,0x83,0xE8,0xC5,0x0F,0x01, ++ 0x0D,0x8B,0x45,0x9B,0x66,0x4A,0x03,0x79,0x01,0x1A,0x30,0x2A,0xAB,0x01,0x69,0x04, ++ 0x50,0x13,0x5B,0x09,0x80,0x6E,0x59,0x29,0x80,0x46,0x58,0x41,0x8B,0xDE,0x93,0x4B, ++ 0x46,0x9B,0x3F,0xD8,0x88,0x16,0x00,0x81,0x07,0x83,0xED,0xC5,0x0B,0x8B,0x4D,0x22, ++ 0x10,0x42,0x8C,0x16,0x07,0x29,0x05,0x83,0x00,0x3F,0xE0,0x92,0x02,0x93,0xE7,0x00, ++ 0x93,0x05,0x2C,0x04,0x40,0x89,0x9A,0x06,0x2A,0x0C,0x43,0xCA,0x40,0x13,0x08,0x41, ++ 0x18,0x52,0x04,0x13,0x44,0x13,0x1C,0x52,0x00,0x13,0x14,0xA1,0x04,0x93,0x45,0x13, ++ 0x1C,0x52,0x04,0x13,0x44,0x13,0x1C,0x52,0x04,0x13,0x44,0x13,0x1C,0x52,0x00,0x13, ++ 0xEA,0xC5,0x5F,0xA2,0xD0,0x7B,0x43,0xDC,0x7B,0x11,0x90,0x56,0x78,0x01,0x88,0x36, ++ 0x42,0x83,0x57,0x82,0x02,0x84,0x40,0x82,0x13,0x03,0x2B,0x0C,0x07,0x1F,0x44,0x83, ++ 0x12,0xD0,0x48,0x62,0xC4,0x80,0x90,0x3D,0x06,0x7C,0x00,0x89,0x11,0x00,0xD0,0xC0, ++ 0x40,0x01,0xC1,0x96,0x97,0xC5,0xBF,0xFF,0xF2,0xAF,0x43,0x42,0x13,0x3A,0x84,0x96, ++ 0x40,0x32,0x82,0x41,0x13,0x3A,0x8C,0x76,0x00,0x09,0x80,0x07,0xC8,0x3F,0x06,0xC1, ++ 0xB2,0x03,0x4D,0x1A,0x00,0x09,0x80,0x43,0x01,0x2F,0x43,0xC2,0x82,0x01,0xCE,0x03, ++ 0x41,0x01,0x88,0x2E,0x46,0xEA,0xC1,0x31,0x10,0x3A,0x8C,0xAE,0x40,0xEA,0x41,0x0B, ++ 0x40,0xCA,0x71,0x50,0x80,0x01,0x82,0x13,0x62,0x50,0x80,0x13,0x54,0x50,0x80,0x13, ++ 0x80,0x0B,0xC6,0x0B,0xC4,0x13,0xC2,0x48,0xC6,0x13,0xC4,0x1B,0xC4,0x90,0xC6,0x48, ++ 0x88,0x29,0x55,0x50,0x8A,0x13,0x88,0x0B,0x00,0x69,0x18,0x00,0xD2,0xC0,0x41,0x81, ++ 0xC3,0x16,0x28,0x04,0x02,0xFF,0x01,0x27,0x06,0x01,0x18,0x02,0x29,0x04,0x03,0xD7, ++ 0x41,0x6A,0xC1,0xC0,0x40,0x19,0xC1,0x1E,0x29,0x04,0x43,0x62,0x11,0x03,0x03,0x97, ++ 0x41,0x4A,0xC1,0x81,0xC1,0xC0,0x41,0x01,0xC3,0x26,0x28,0x04,0x41,0x3A,0xC1,0x01, ++ 0x11,0x03,0x03,0x47,0x00,0x69,0x18,0x00,0xD1,0xC0,0x41,0xB1,0xC3,0x1E,0x29,0x04, ++ 0x00,0x0F,0x79,0xDA,0x10,0xC2,0x85,0xF6,0x40,0xBB,0xA7,0xBA,0x45,0xDA,0xC0,0xD1, ++ 0x10,0x1A,0x8C,0x7E,0x6A,0x04,0x43,0x61,0x8B,0x66,0x50,0x1B,0xE0,0xFA,0x50,0x7A, ++ 0x94,0x01,0x7A,0x01,0x88,0x16,0x00,0x09,0xA8,0x83,0x04,0x1F,0xE0,0xC2,0x40,0x01, ++ 0x8C,0x06,0xA8,0x8B,0x6A,0x04,0xE3,0x00,0x93,0x05,0x2C,0x04,0x40,0x89,0x9A,0x16, ++ 0x06,0x01,0x18,0x02,0x2B,0x04,0xD3,0x43,0xE3,0x00,0x92,0x43,0x05,0x81,0x00,0x83, ++ 0xED,0xC5,0x07,0x8B,0xE8,0xC5,0x07,0x00,0x10,0x00,0x00,0x42,0x00,0xE0,0x00,0x01, ++ 0xF8,0x00,0x06,0x42,0x80,0xC0,0x04,0x01,0x08,0x40,0x00,0x01,0x80,0x01,0x06,0x42, ++ 0xF8,0xFF,0x07,0x00,0x00,0x10,0x00,0x01,0x80,0x30,0x02,0x01,0x88,0x36,0x00,0x00, ++ 0x00,0x20,0x00,0x01,0x00,0xA0,0x00,0x01,0x77,0x81,0xF8,0xFF,0xF8,0x02,0x07,0x00, ++ 0xA8,0x85,0x80,0x07,0xC8,0xBF,0x65,0x32,0xC8,0x03,0x43,0x01,0x80,0x26,0x40,0x31, ++ 0x8F,0xD6,0xBF,0xFF,0xD7,0xFF,0x3B,0xBF,0xBE,0xFF,0xCF,0x07,0x38,0xA7,0x07,0x00, ++ 0x00,0xE0,0x06,0x01,0xAF,0xC5,0x77,0x62,0x03,0x01,0x87,0x83,0x01,0x09,0x80,0x83, ++ 0x0F,0x01,0x81,0x8B,0x05,0x19,0x80,0x83,0x03,0x41,0x89,0x83,0x07,0x69,0x89,0x83, ++ 0x05,0x69,0x88,0x83,0x11,0x02,0x32,0xAA,0xA9,0x01,0x06,0x44,0x04,0xF9,0x87,0x89, ++ 0x20,0x84,0x01,0x09,0x34,0x62,0xE1,0x01,0x93,0x03,0x91,0x03,0x05,0x41,0x90,0x03, ++ 0x17,0x51,0x90,0x13,0x11,0xA1,0x98,0x13,0x98,0x0B,0x0D,0x81,0x99,0x0B,0xA7,0x03, ++ 0x3B,0x01,0xA0,0xBB,0x09,0x71,0x98,0x8B,0x0B,0x29,0x98,0x8B,0x17,0x71,0x98,0x93, ++ 0x99,0x8B,0xA5,0xBB,0xA1,0x83,0x05,0x81,0xA0,0x83,0x07,0x51,0x8F,0x03,0x01,0xB1, ++ 0x8D,0x03,0x8B,0x3B,0x8B,0x3B,0x9F,0x0B,0x05,0x99,0x28,0x84,0x07,0xF9,0x87,0x09, ++ 0x10,0x44,0x01,0xC9,0x0B,0x00,0x12,0x44,0x02,0x19,0x18,0x00,0x0E,0x43,0x43,0x5A, ++ 0x0A,0x43,0x05,0x01,0xB9,0x43,0x31,0x02,0x0D,0x51,0x80,0x11,0x83,0x1F,0xD0,0x17, ++ 0x01,0xB1,0x97,0x43,0x1B,0xF1,0x90,0x5B,0x89,0x7B,0x33,0x02,0x82,0x01,0xB2,0x3B, ++ 0xB8,0x3B,0x08,0xC1,0xB8,0x0B,0x0A,0x51,0xBE,0x0B,0x14,0x41,0x31,0x0A,0x88,0x01, ++ 0x0F,0x54,0x12,0xF9,0x94,0x99,0x0A,0x54,0x16,0xC1,0xBE,0x13,0x10,0x41,0x81,0x53, ++ 0x12,0x11,0x87,0x53,0x80,0x5B,0x14,0x51,0x91,0x13,0x12,0x41,0x93,0x13,0x14,0x21, ++ 0x92,0x13,0x16,0xA9,0x08,0x14,0x16,0x71,0x9A,0x13,0x10,0x69,0xA0,0x13,0x10,0x21, ++ 0xA6,0x13,0x12,0x41,0x10,0x14,0x12,0x31,0xBF,0x93,0x37,0xBC,0xB0,0x3B,0x1C,0x21, ++ 0x33,0x12,0x90,0x01,0x90,0x9B,0x1C,0x31,0x96,0x9B,0x12,0x99,0x08,0x94,0x11,0xA1, ++ 0x80,0x53,0x16,0x51,0x8E,0x53,0xB0,0x3B,0x12,0x21,0x8C,0x53,0x53,0x42,0x05,0x54, ++ 0x14,0x09,0x88,0x53,0x10,0x51,0x90,0x53,0x17,0x11,0xA0,0x13,0x08,0x21,0xA8,0x0B, ++ 0x0A,0xC1,0xAB,0x0B,0xA8,0x0B,0x1C,0x01,0x33,0x0A,0xC8,0x01,0xA0,0x5B,0xAE,0x5B, ++ 0x22,0xF1,0x88,0x01,0xBA,0x63,0xB8,0x63,0x24,0xE1,0xB9,0x63,0x26,0x41,0xB8,0x63, ++ 0x80,0x13,0x08,0xB1,0x80,0x0B,0x0A,0x19,0x84,0x0B,0x4C,0xD2,0x00,0x0B,0x92,0x1B, ++ 0x4C,0xCA,0xC4,0x01,0x38,0x0B,0x88,0x91,0x3E,0x0B,0x8A,0xE1,0x38,0x0B,0x0C,0xE1, ++ 0x40,0xB2,0x84,0x1F,0xCC,0xBF,0x47,0xAA,0x09,0xE1,0xC0,0xC1,0x87,0x1F,0xC8,0x97, ++ 0x4C,0x8A,0x44,0x9A,0xCE,0x11,0x03,0x0B,0xCC,0x71,0x00,0x0B,0x88,0xA1,0x08,0x0B, ++ 0x8A,0xA1,0x08,0x0B,0xCA,0xE1,0x01,0x0B,0xC8,0xC1,0x01,0x0B,0x8C,0x61,0x0D,0x0B, ++ 0xCA,0x81,0x15,0x0B,0xF8,0x48,0x10,0x0B,0xFE,0x48,0x08,0x0B,0xE9,0xC5,0xAF,0x85, ++ 0x0C,0x01,0x60,0x0A,0x47,0x02,0xA4,0x61,0xF8,0x1B,0x06,0x77,0x02,0x21,0x19,0x42, ++ 0xCB,0x28,0x00,0x99,0x12,0x79,0x08,0x00,0xC4,0x40,0x89,0x13,0x16,0x01,0x88,0x13, ++ 0x94,0x13,0x10,0x14,0x12,0x14,0xE6,0x48,0x94,0x4D,0x16,0x5A,0xC0,0x76,0x07,0x01, ++ 0x13,0xF9,0x2F,0x89,0x08,0x68,0x03,0x37,0x00,0x08,0xCA,0x48,0xCC,0x48,0xAA,0x53, ++ 0xAA,0x53,0xE6,0x00,0x94,0x05,0x16,0x1A,0xC1,0xB6,0xEF,0x85,0xA3,0x85,0x51,0x72, ++ 0x90,0x01,0x0E,0x01,0x26,0x8C,0xD0,0x01,0xBC,0x8B,0xB8,0x8B,0x36,0x9A,0x98,0x01, ++ 0x8A,0xCB,0x0C,0xCC,0x9E,0xCB,0x88,0xCB,0x2C,0x09,0xB0,0xAB,0xA8,0x8B,0x34,0xA2, ++ 0xA1,0x01,0xCD,0x1B,0xB0,0x9B,0x36,0x9A,0x9A,0x01,0xA9,0xCB,0x9A,0x01,0xA9,0xEB, ++ 0xA8,0xCB,0xA8,0xAB,0x28,0x41,0x89,0xAB,0x8B,0x0B,0x57,0x32,0x88,0x8B,0x46,0x09, ++ 0x8C,0x16,0xA8,0xCB,0xE5,0x85,0x39,0x97,0xE3,0x85,0x39,0x82,0x0B,0x08,0x42,0x12, ++ 0x41,0x13,0x18,0x01,0x04,0xD2,0x90,0x41,0x04,0x13,0x10,0xD0,0x1A,0x8A,0x08,0x0B, ++ 0x40,0x0B,0x42,0x0B,0x14,0x41,0x18,0x8A,0x00,0x0B,0x08,0x01,0x03,0x0B,0x3C,0x82, ++ 0xAA,0x85,0x40,0xD2,0x40,0x0B,0x30,0x48,0xAE,0x2E,0x08,0x81,0x02,0x0B,0x08,0x81, ++ 0x00,0x0B,0x08,0x81,0x02,0x0B,0x48,0xAA,0x8C,0x01,0x46,0x53,0x38,0x90,0x78,0x90, ++ 0x04,0x53,0x44,0x53,0x18,0x81,0x19,0xD2,0x02,0x53,0x5C,0x8A,0x12,0x09,0x06,0xD3, ++ 0x16,0x91,0x01,0x13,0x44,0x7A,0x42,0x23,0x10,0x61,0x18,0xA2,0x02,0x23,0x44,0x23, ++ 0x1A,0xA2,0x00,0x23,0x4C,0x23,0x1A,0xA2,0x08,0x23,0x4A,0x23,0x18,0xA2,0x08,0x23, ++ 0x40,0x23,0x1E,0xA2,0x02,0x23,0x46,0x43,0x10,0x01,0x1A,0x82,0x04,0x43,0x02,0xD1, ++ 0x07,0xC3,0x00,0x01,0x08,0xC3,0xEA,0x85,0x40,0x12,0x42,0x13,0x08,0x09,0x18,0x52, ++ 0x00,0x13,0x48,0x13,0x18,0x52,0x0C,0x13,0x4C,0x13,0x1A,0x52,0x0E,0x13,0x42,0x13, ++ 0x1E,0x52,0x00,0x13,0x39,0x82,0x43,0xE2,0x58,0x0B,0x10,0x21,0x18,0x8A,0x18,0x0B, ++ 0x5A,0x0B,0x10,0x01,0x18,0x8A,0x18,0x0B,0x5C,0x13,0x08,0x01,0x18,0x52,0x18,0x13, ++ 0x40,0x92,0x11,0x01,0x80,0x01,0x06,0x13,0x40,0x13,0x1A,0x52,0x01,0x13,0x4A,0x72, ++ 0x41,0x43,0x10,0x01,0x18,0x82,0x00,0x43,0x38,0x82,0xAB,0x85,0x08,0x09,0x00,0x31, ++ 0x81,0x07,0xD0,0xF7,0x08,0x11,0x00,0x21,0x81,0x07,0xD0,0xD7,0x00,0x09,0x80,0x07, ++ 0xD0,0xB7,0x02,0x31,0x82,0x07,0xD0,0x9F,0x00,0x21,0x80,0x07,0xD0,0x87,0x82,0x07, ++ 0xD0,0x2F,0xEB,0x85,0xA8,0x85,0x43,0xF2,0x4A,0xBA,0xC0,0x91,0x11,0x43,0x0A,0x91, ++ 0x80,0x1F,0xC8,0x07,0x40,0xD2,0x08,0x51,0x80,0x41,0x81,0x1F,0xC7,0xEF,0xBF,0xFF, ++ 0xF0,0x4F,0x02,0x09,0xBA,0xFF,0xFF,0x17,0x07,0xA1,0xB8,0xFF,0xFF,0x3F,0xBB,0xFF, ++ 0xFF,0xBF,0xBB,0xFF,0xFF,0xC7,0xBD,0xFF,0xFF,0x3F,0xBD,0xFF,0xF8,0x77,0x66,0x8A, ++ 0x29,0x01,0x80,0x2B,0x08,0x2B,0x41,0x72,0x09,0x71,0x80,0x91,0x87,0x1F,0xC0,0x17, ++ 0x0B,0x2C,0x81,0x2B,0x87,0x2B,0x85,0x2B,0x8B,0x2B,0x89,0x2B,0x05,0x51,0x88,0x03, ++ 0x0F,0x2C,0x8B,0x2B,0x0B,0x2C,0xED,0x85,0x00,0xE0,0x00,0x01,0xC8,0x21,0x01,0x00, ++ 0x70,0x02,0x01,0x00,0xF8,0xFF,0x07,0x04,0x68,0x02,0x03,0x00,0x70,0x70,0x06,0x01, ++ 0x80,0xC0,0x04,0x01,0x00,0x20,0x00,0x01,0x10,0x00,0x00,0x42,0x00,0x00,0x00,0x42, ++ 0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42,0x18,0x00,0x02,0x42,0xA8,0x85,0x80,0x07, ++ 0xC8,0xCF,0xEE,0x85,0xAF,0x85,0xB8,0xFF,0xE8,0x9F,0xEF,0x85,0xA8,0x7D,0x80,0x04, ++ 0x88,0x0C,0xC0,0x0C,0x80,0x14,0xC0,0x04,0x83,0x1C,0x30,0x42,0x40,0x7E,0x80,0x25, ++ 0xE8,0x05,0x00,0x00,0xAC,0xFD,0x87,0x1D,0x30,0x32,0x00,0x01,0x82,0x14,0x00,0x9F, ++ 0x44,0xDA,0x0E,0x01,0x0C,0x0B,0x26,0x01,0xC2,0x14,0x00,0x28,0x7F,0xC2,0x4E,0xC3, ++ 0x1F,0x02,0x09,0xC3,0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64, ++ 0x86,0x17,0xE0,0x1F,0xF8,0x82,0x33,0x0A,0xCF,0x99,0x49,0xC9,0x99,0x3E,0x40,0x91, ++ 0xE7,0x16,0x48,0xC3,0x1F,0x02,0x0D,0xC3,0x40,0x20,0x63,0x01,0x88,0x36,0xD7,0x6C, ++ 0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x17,0xE3,0x77,0xFD,0xA2, ++ 0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x85,0x17,0xE0,0x2F, ++ 0xF8,0xBA,0xD3,0x6C,0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x17, ++ 0xE5,0xE7,0x14,0x3A,0xE9,0x16,0x30,0x02,0x30,0xE2,0x31,0x3A,0xFD,0x82,0x13,0xC2, ++ 0xE3,0x0E,0x98,0xBA,0x05,0x17,0x10,0x02,0xDB,0x06,0x98,0xA2,0x46,0xC2,0x4D,0x03, ++ 0xDE,0x8A,0x0B,0x00,0xC0,0x00,0xCA,0x24,0x00,0x44,0xC0,0x24,0xE0,0x00,0x84,0x24, ++ 0xC2,0x14,0xE0,0x00,0x90,0x05,0x86,0x14,0xC8,0x2C,0xC0,0x14,0x15,0x42,0x9C,0x3E, ++ 0x87,0x3D,0xE8,0x85,0xAC,0xFD,0x87,0x7D,0x30,0xA2,0x30,0xFA,0xD8,0x0B,0x8F,0x6C, ++ 0xD8,0x0B,0x8B,0x64,0x40,0x01,0x80,0x6E,0x48,0x52,0x05,0x99,0x07,0x43,0x12,0xF9, ++ 0x58,0x3A,0x95,0x81,0x10,0xD3,0x06,0x43,0x00,0xC1,0x83,0x17,0xF8,0xFF,0xF1,0x84, ++ 0xB0,0xE1,0x01,0xCF,0x40,0x1A,0x0D,0x19,0x04,0x0B,0x0A,0x19,0x05,0x0B,0x48,0x12, ++ 0xC2,0x84,0xC0,0x30,0x11,0x01,0x30,0xDA,0x30,0x8A,0x00,0x09,0x82,0x17,0xC0,0xC7, ++ 0x29,0x01,0x30,0x1A,0x14,0x09,0x08,0x01,0x40,0x1D,0xB8,0x04,0x82,0x17,0xE0,0x6F, ++ 0xE7,0x68,0x93,0x6D,0x6F,0x91,0x99,0xA6,0x48,0xB2,0x44,0x43,0x10,0x11,0x18,0x82, ++ 0x01,0x43,0x30,0x02,0x80,0x01,0x35,0x2A,0xC8,0x03,0x32,0x00,0xAC,0xEE,0x49,0x9A, ++ 0x00,0x01,0x80,0x43,0x31,0x12,0x31,0xCA,0x00,0x11,0x80,0x0F,0xF9,0xF7,0x34,0x1A, ++ 0xB8,0x04,0x08,0x01,0x00,0x11,0xD0,0x84,0x84,0x17,0xC0,0x47,0x49,0x42,0xD4,0x43, ++ 0x08,0x43,0x2A,0x01,0xC2,0x64,0x00,0x00,0x80,0x74,0x00,0xBF,0x31,0xDA,0x31,0x52, ++ 0x08,0x01,0x00,0x09,0x81,0x17,0xC0,0x27,0xB8,0x0C,0xA0,0x04,0x30,0x8A,0x41,0x1D, ++ 0xD8,0x84,0xD0,0x64,0xB9,0xFF,0xFF,0xF7,0xC4,0x74,0xC8,0x30,0x09,0x09,0x30,0xDA, ++ 0x30,0x52,0x31,0x42,0x80,0x17,0xC0,0xA7,0xE7,0x68,0x93,0x6D,0xC4,0x6C,0x10,0x2A, ++ 0x99,0x26,0x37,0x1A,0xB8,0x04,0x08,0x01,0x00,0x19,0xD0,0x84,0x82,0x17,0xC0,0xF7, ++ 0x31,0x12,0x31,0xCA,0x00,0x01,0x80,0x0F,0xFB,0x47,0x4B,0x92,0x40,0x43,0x10,0x11, ++ 0x18,0x82,0x04,0x43,0x87,0x9D,0xE8,0x85,0xAC,0xFD,0x87,0x1D,0x30,0x7A,0x50,0x01, ++ 0x80,0x16,0x00,0x01,0x80,0x0C,0x00,0x0F,0x00,0x09,0x80,0x0C,0x2A,0x01,0x00,0x47, ++ 0xCD,0x64,0x00,0x40,0xC1,0x30,0x32,0x52,0x08,0x19,0xD8,0x6C,0xC0,0x0C,0x80,0x0F, ++ 0xF9,0x3F,0x07,0x41,0x85,0x17,0xF0,0xD7,0x20,0x09,0xC0,0x34,0x80,0x01,0x84,0x14, ++ 0x60,0x81,0x99,0x36,0x0A,0xF9,0x47,0xF2,0x88,0x11,0x18,0x0B,0x42,0x08,0x1B,0x0B, ++ 0x02,0x0F,0x40,0xDA,0x1F,0x23,0x02,0xF9,0x4F,0xCA,0x82,0x89,0x88,0x01,0x12,0x43, ++ 0x00,0x11,0x80,0x17,0xF0,0x1F,0xC5,0x14,0xF0,0x03,0x46,0x01,0x80,0x3E,0x00,0x51, ++ 0x84,0x17,0xF0,0xE7,0x40,0x83,0x41,0x03,0x30,0x00,0xA8,0x86,0x07,0x5F,0x00,0xF9, ++ 0x4C,0x7A,0x82,0x89,0x88,0x01,0x12,0x43,0x00,0x09,0x80,0x17,0xF1,0x7F,0x44,0x83, ++ 0x40,0x03,0x30,0x00,0xA3,0x1E,0xE0,0x20,0x93,0x25,0x67,0xF9,0xC9,0x86,0x06,0xE4, ++ 0xE1,0xF8,0x35,0x52,0x08,0x09,0xD8,0x6C,0xC0,0x0C,0x80,0x0F,0xFB,0x4F,0xE5,0x68, ++ 0x90,0x6D,0xC7,0x1C,0x15,0x2A,0x9C,0x9E,0x3F,0x17,0xA9,0x85,0x80,0x3D,0x34,0x7A, ++ 0x34,0xA2,0x00,0xD9,0xEF,0x02,0x0E,0xF9,0x88,0x09,0x40,0x01,0x80,0x0E,0x30,0x72, ++ 0x00,0x0F,0x30,0x19,0x13,0xB0,0xD9,0xC3,0x81,0x34,0xD8,0xC3,0x80,0x2C,0x98,0x1C, ++ 0xC2,0x34,0x00,0x00,0xC0,0x00,0x86,0x24,0x45,0xAA,0x11,0x81,0x00,0x13,0x1A,0x0B, ++ 0x28,0x01,0x00,0x67,0x4D,0x03,0x01,0x48,0xC0,0x00,0x42,0x03,0x01,0x33,0x30,0x1A, ++ 0x30,0x52,0x09,0x09,0x00,0x01,0x80,0x0F,0xFB,0xDF,0xE3,0x68,0x90,0x6D,0xC7,0x34, ++ 0x17,0x2A,0x9C,0x7E,0x28,0x01,0x00,0x67,0x4D,0x03,0x03,0x48,0xC0,0x00,0x42,0x03, ++ 0x00,0x33,0x08,0x09,0x31,0x1A,0x31,0x52,0x30,0x42,0x80,0x0F,0xFB,0x4F,0xE3,0x68, ++ 0x90,0x6D,0xC7,0x2C,0x17,0x2A,0x9C,0x7E,0x48,0x0B,0xA1,0x0C,0x89,0x04,0x30,0xDA, ++ 0x10,0x09,0xC8,0x1C,0xC7,0x34,0xB8,0xFF,0xFB,0xFF,0x4A,0x0B,0x89,0x04,0x30,0xDA, ++ 0x10,0x01,0xA0,0x0C,0xC8,0x24,0xC0,0x2C,0xBA,0xFF,0xFF,0xB7,0x48,0xC2,0x00,0x01, ++ 0x88,0x01,0x12,0x43,0x48,0xB2,0x18,0x43,0x37,0x57,0xAE,0xC5,0x30,0x1A,0x30,0x42, ++ 0x30,0xBA,0xD8,0x23,0xD8,0x2B,0x4A,0xB2,0xC0,0xC8,0x8A,0x04,0x30,0xD2,0x31,0xCA, ++ 0x87,0x0F,0xF8,0xDF,0x30,0x01,0x00,0x3F,0x09,0x09,0x30,0xDA,0x30,0x92,0x31,0x42, ++ 0x81,0x0F,0xF8,0xB7,0xE7,0xB0,0x93,0xB5,0x17,0x32,0x9D,0xAE,0xC8,0x04,0x10,0x01, ++ 0x18,0x01,0x00,0x4F,0x00,0x01,0x00,0x1F,0x82,0x5B,0xE0,0x48,0xE6,0x00,0x92,0x05, ++ 0x17,0x42,0x9D,0xCE,0xE6,0x90,0x92,0x95,0x17,0x12,0x9D,0x9E,0xE8,0xC5,0x07,0x00, ++ 0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x48,0xE0,0x06,0x00,0x00,0xD0,0x00,0x01, ++ 0x60,0x20,0x02,0x00,0x49,0x32,0x41,0x2A,0x05,0x43,0x9E,0xFF,0x7F,0x04,0x3A,0xF7, ++ 0x94,0x15,0x3A,0x00,0x77,0x18,0x06,0xF9,0x04,0xC2,0x3C,0x48,0x74,0x48,0x00,0xCA, ++ 0x50,0x01,0xD0,0x5E,0x38,0x90,0x78,0x90,0xD4,0x41,0x40,0x98,0x54,0xE2,0x00,0xD8, ++ 0xC6,0xD0,0x4C,0x9B,0x18,0x1A,0x1C,0x5A,0x0B,0x9B,0x3E,0x82,0x40,0x98,0x54,0xCA, ++ 0x04,0xD8,0xC4,0xD0,0x44,0x9B,0x18,0x1A,0x18,0x5A,0x00,0x9B,0x3A,0x82,0x93,0x05, ++ 0x36,0x10,0x76,0x90,0x0C,0x09,0x00,0x8A,0x48,0x00,0x52,0x9A,0x04,0x00,0xC4,0x00, ++ 0x03,0x0B,0x38,0x82,0x96,0x05,0x32,0x10,0x70,0x90,0x0E,0x09,0x00,0x8A,0x54,0x72, ++ 0x4C,0x00,0x02,0x00,0x94,0x01,0xC4,0x00,0x03,0x0B,0x38,0x82,0xB3,0x15,0x3B,0x82, ++ 0xFB,0x85,0x39,0x82,0x40,0x32,0x48,0x0B,0x10,0x21,0x18,0x8A,0x0B,0x0B,0x38,0x82, ++ 0x48,0x1A,0x48,0x43,0x14,0x21,0x18,0x82,0x0B,0x43,0x38,0x82,0x07,0x20,0x28,0xD0, ++ 0x68,0x07,0x00,0x07,0x20,0x07,0x00,0x07,0x08,0x07,0x00,0x07,0xAC,0xFD,0x87,0x4D, ++ 0xD0,0x94,0x30,0x22,0xF8,0x43,0x80,0x0C,0xF8,0x6B,0xC6,0x64,0x08,0x01,0x80,0x0B, ++ 0x00,0x01,0x00,0x8F,0x0A,0x21,0x19,0x0A,0x18,0x99,0xCB,0x48,0x0E,0xD8,0xC2,0x48, ++ 0xC8,0x4B,0x4C,0x79,0x80,0x36,0x80,0x83,0xE0,0x90,0xCA,0x64,0xD8,0x64,0xC0,0x4B, ++ 0xE0,0x48,0x82,0xCB,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0x5E,0xC0,0x64,0xC0,0x03, ++ 0x80,0x44,0x40,0x01,0x88,0x0E,0x80,0x6D,0xE8,0x85,0xC7,0x44,0x40,0x09,0x88,0x1E, ++ 0xC0,0x0C,0x40,0x09,0x8F,0x06,0x38,0xB7,0x00,0x01,0x80,0x34,0x80,0x2C,0xC8,0x44, ++ 0xC4,0x0C,0x10,0x0A,0x88,0x96,0x02,0x01,0x30,0x01,0x08,0x01,0x88,0x1C,0x88,0x14, ++ 0x1C,0xC9,0x09,0xD8,0x00,0x4F,0x10,0x31,0x18,0x52,0xCA,0x90,0xC2,0x90,0x46,0xBC, ++ 0xC4,0xC0,0x41,0x94,0xCA,0xB0,0xE4,0x48,0x90,0x4D,0xD6,0x0C,0x17,0x8A,0x9C,0x96, ++ 0xC8,0x0C,0x80,0x17,0xF0,0x6F,0x82,0x24,0x30,0x82,0xC9,0x0C,0x82,0x17,0xF0,0x47, ++ 0x30,0x32,0x08,0x01,0x01,0x01,0x00,0x07,0x1A,0x99,0x0B,0xD8,0x02,0x0F,0xE0,0x48, ++ 0x91,0x4D,0x16,0x21,0x18,0x52,0xCA,0x90,0xC4,0x90,0xCE,0x93,0x57,0x79,0x80,0xB6, ++ 0x12,0x21,0x19,0x52,0xCE,0x90,0xC0,0x98,0x3E,0xF1,0xF8,0xFA,0xDF,0x1C,0xC0,0xD8, ++ 0x98,0x1C,0x18,0xE9,0x0E,0xD8,0xC6,0x98,0x14,0x01,0xF0,0xD2,0xDE,0x14,0xC0,0x90, ++ 0x92,0x14,0xE0,0x48,0x92,0x4D,0xE6,0x00,0x90,0x05,0xD6,0x44,0x16,0x12,0xC4,0xDE, ++ 0xC8,0x44,0xC0,0x1C,0x80,0x17,0xF0,0xE7,0x30,0x3A,0xC8,0x44,0xC0,0x14,0x80,0x17, ++ 0xF0,0xBF,0xC8,0x24,0xD8,0x48,0x8E,0x34,0xD0,0x80,0x81,0x2C,0x08,0x01,0x10,0x01, ++ 0x00,0x77,0x00,0x01,0x33,0x5A,0x18,0x5A,0xF2,0x5C,0x00,0xD8,0xC8,0xD8,0x04,0x1F, ++ 0x04,0x30,0x9A,0xD2,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE,0xE6,0x48,0x92,0x4D, ++ 0x17,0x4A,0x9D,0x76,0x08,0x01,0x10,0x01,0x03,0xE7,0x19,0x99,0x08,0xD8,0x02,0x0F, ++ 0xE6,0x48,0x92,0x4D,0x02,0x21,0x19,0x42,0xCC,0x00,0x30,0x22,0xC0,0x00,0x86,0x3C, ++ 0xC8,0x03,0x44,0x79,0x80,0xA6,0x07,0x01,0x00,0x2F,0xD9,0x3C,0x34,0xF1,0xF8,0xF2, ++ 0xD9,0x34,0x38,0xC9,0xC0,0xB0,0x1F,0x31,0x18,0x1A,0xCA,0xD8,0x0E,0xF8,0xCD,0xD8, ++ 0x47,0xFC,0xDA,0xB0,0xAB,0x06,0x10,0xB2,0x95,0xB5,0x35,0xB2,0x37,0xE9,0x08,0xB0, ++ 0x20,0x32,0x3B,0x01,0xF8,0xBA,0xF7,0x2C,0x45,0xDC,0xCC,0xF0,0xD0,0x98,0xAF,0x06, ++ 0x10,0xDA,0x32,0xB2,0x18,0x72,0xFB,0x5C,0x07,0xB0,0xCB,0xB0,0x22,0x9A,0x03,0x38, ++ 0x9A,0x9A,0xE7,0x00,0x90,0x05,0xDE,0x0C,0x16,0xC2,0x9C,0xB6,0xE6,0x48,0x92,0x4D, ++ 0xE6,0x90,0x92,0x95,0xC0,0x64,0xC0,0x03,0x15,0x82,0xC4,0xF6,0xC0,0x64,0xC8,0x0C, ++ 0xC4,0x03,0x10,0x42,0xC9,0x06,0x38,0xF7,0xC1,0x0C,0x38,0xE7,0xAC,0x85,0x87,0x3D, ++ 0x34,0x22,0x00,0x91,0xD4,0x02,0x34,0x22,0x01,0xC1,0xF0,0x02,0x18,0x71,0x80,0x34, ++ 0xF0,0x1A,0x9F,0x2C,0xD0,0x00,0x96,0x05,0x1F,0xD1,0xF0,0x1A,0x2B,0x81,0xF8,0x2A, ++ 0x32,0xF2,0xDC,0xD8,0x90,0xDD,0xA8,0x24,0xC0,0x2B,0x6F,0x09,0x8D,0x16,0x10,0x04, ++ 0x10,0x1C,0x07,0x6F,0x55,0x3C,0x05,0xE8,0xC7,0x68,0x51,0x04,0x07,0x30,0xC4,0x98, ++ 0xD9,0x68,0x97,0x6D,0xD0,0xC0,0x90,0x1D,0x84,0x40,0x85,0xD8,0x17,0x04,0x15,0x1C, ++ 0x4B,0x81,0x80,0xF6,0xE9,0x2C,0xC0,0x40,0x02,0x28,0xCA,0x00,0xEA,0x34,0xC8,0x00, ++ 0x80,0x00,0x94,0x05,0xEF,0x24,0xC0,0x58,0x02,0xE8,0xCA,0xE8,0x37,0x9A,0xC3,0x58, ++ 0x80,0xD8,0x94,0xED,0x90,0x01,0x46,0x01,0xD0,0x0E,0x00,0x01,0x00,0x27,0x50,0x9C, ++ 0x10,0x1A,0xD4,0x0E,0x00,0x81,0xF0,0x82,0x68,0x01,0xD0,0x0E,0x28,0x01,0x00,0x27, ++ 0x55,0x9C,0x12,0x5A,0xD0,0x0E,0x28,0x91,0xF8,0xAA,0xD2,0x2C,0xD0,0x90,0xF0,0xB0, ++ 0xD2,0x06,0x10,0x92,0x06,0x98,0xC2,0xB8,0xD2,0x24,0xD8,0x90,0xF0,0x98,0xD0,0x06, ++ 0x15,0x92,0xC2,0xF8,0x7E,0xD0,0xCF,0x90,0x18,0x90,0x66,0x90,0x58,0x01,0xD0,0x06, ++ 0x12,0xDA,0x02,0xF8,0xC8,0xD8,0x76,0x01,0xD3,0x06,0x10,0xB2,0xCE,0xD8,0x7C,0xF0, ++ 0xC6,0x98,0x1F,0xD8,0x60,0xF0,0x48,0x41,0x80,0x0E,0x48,0x49,0x88,0x2E,0x48,0x49, ++ 0x8A,0x1E,0x20,0x88,0x63,0x50,0x20,0x88,0x63,0x70,0x30,0x0A,0x8B,0x0C,0x28,0x12, ++ 0xCB,0x06,0x30,0x12,0xCC,0x0C,0x10,0x72,0xC8,0x06,0xF0,0x0C,0xDB,0x2C,0x30,0x0A, ++ 0xD0,0x48,0x34,0x7A,0x1C,0xCA,0x02,0x58,0xC4,0x48,0x36,0x72,0x19,0x51,0x30,0xCA, ++ 0xF3,0x1A,0x07,0xF8,0xCA,0x48,0x1E,0x5A,0x32,0x8A,0xC3,0xC8,0x1B,0x82,0x32,0x12, ++ 0x46,0xB8,0xCA,0x00,0x02,0x00,0xC6,0x00,0x36,0x0A,0x03,0x48,0x88,0x1C,0x80,0x17, ++ 0xE8,0xBF,0x80,0x14,0xD0,0x24,0xC0,0x0C,0xD8,0x00,0x34,0x0A,0x1C,0x82,0x02,0x10, ++ 0xC0,0x00,0x14,0x61,0xF2,0x12,0x05,0x58,0xC2,0x48,0x1E,0x52,0xC3,0x80,0x18,0xAA, ++ 0x00,0x07,0x00,0x67,0xCE,0x48,0x07,0x48,0xC0,0x40,0xC8,0x1C,0x80,0x17,0xE8,0x07, ++ 0xCB,0x2C,0x08,0x0C,0xCD,0x24,0x08,0x0C,0xCF,0x14,0x08,0x0C,0x10,0x04,0x81,0x3D, ++ 0xEF,0x85,0xAF,0xF5,0x30,0x3A,0xC0,0x44,0x60,0xD2,0xCF,0xE0,0x2F,0x31,0x70,0xCA, ++ 0x1F,0xAA,0xC2,0x68,0xF5,0x21,0xC9,0x68,0x06,0x90,0xC2,0x90,0x59,0xAA,0xDF,0x81, ++ 0xC6,0xB0,0xFE,0x13,0x31,0xB2,0x34,0xDA,0x32,0x3A,0xB8,0x01,0x30,0x12,0xB8,0x0C, ++ 0x92,0x01,0xBE,0x01,0x59,0x09,0x88,0x4E,0x01,0x01,0x00,0x17,0xC0,0x0B,0x49,0x79, ++ 0x89,0xE6,0x40,0x4C,0x0B,0x0C,0x47,0x5C,0x14,0x1C,0x31,0xE2,0xC1,0x9B,0x89,0x1B, ++ 0xC3,0x9B,0x8B,0x1B,0x1B,0x0C,0x35,0x1A,0x19,0x1C,0x27,0x0C,0x23,0x1C,0x0B,0x0C, ++ 0x09,0x1C,0x45,0x4C,0x1B,0x0C,0x41,0x4C,0x19,0x0C,0x83,0x03,0x0F,0x09,0x80,0x0B, ++ 0x88,0x0B,0xFD,0x8B,0x90,0x0B,0x09,0x01,0x90,0x0B,0x03,0x27,0xA2,0x21,0xE1,0x00, ++ 0x93,0x05,0x2E,0x82,0x9B,0xD6,0x2E,0x82,0x94,0xF6,0x03,0x2F,0x1A,0x21,0x19,0xCA, ++ 0xC8,0x60,0x08,0x41,0x89,0x04,0x40,0x4C,0x18,0x0C,0x09,0x11,0xF3,0x4A,0x1B,0x0C, ++ 0x35,0x62,0xCC,0x0B,0x48,0x09,0x88,0xAE,0x08,0xC1,0x18,0xE1,0xF7,0x0A,0xF3,0x1A, ++ 0xD0,0x48,0xAE,0x06,0x14,0x4A,0x92,0x4D,0x30,0x72,0x1C,0xF1,0xF3,0x1A,0x37,0x0A, ++ 0xD0,0x48,0xAE,0x06,0x14,0x4A,0x92,0x4D,0xE3,0xDB,0x21,0x8A,0x10,0xCA,0xCC,0x0E, ++ 0x0D,0x01,0x88,0x0B,0x09,0xC1,0x18,0x01,0xF7,0x0A,0xF3,0x1A,0xD0,0x48,0xAE,0x06, ++ 0x14,0x4A,0x92,0x4D,0x30,0x62,0x0C,0xD1,0x1B,0x11,0xF1,0x0A,0xF6,0x1A,0xD7,0x48, ++ 0xAA,0x06,0x10,0x4A,0x24,0x0A,0x93,0x4D,0x30,0x62,0xDC,0x0C,0xC4,0x0B,0xE7,0xDB, ++ 0xE4,0xD8,0x12,0xCA,0xC8,0x7E,0xF8,0x8B,0xEE,0xDB,0x01,0xCA,0x28,0x0A,0xCB,0x56, ++ 0xD6,0x0B,0x4B,0x41,0x92,0x0E,0xE0,0x48,0x91,0x0B,0xD3,0x0B,0xFC,0x9B,0x10,0xCA, ++ 0x92,0x0E,0xE0,0x48,0x91,0x0B,0xD1,0x0B,0x28,0x0A,0xCB,0xA6,0xDF,0x0C,0xC0,0x0B, ++ 0xE2,0xDB,0xE4,0xD8,0x10,0xCA,0xCC,0x76,0xCA,0x0B,0x37,0x50,0xE2,0xCB,0x73,0x90, ++ 0xF4,0x48,0x12,0x52,0x89,0x0E,0x08,0x01,0x80,0x0B,0x35,0x12,0x09,0x81,0x30,0x02, ++ 0xBC,0xFF,0xF7,0xE7,0x00,0xDF,0xD8,0x0C,0xC4,0x0B,0xE7,0xDB,0xE4,0xD8,0x12,0xCA, ++ 0xC8,0x1E,0xF8,0x8B,0xEE,0xD3,0x01,0x8A,0x91,0x0B,0x59,0x0C,0x23,0x0C,0x59,0x0C, ++ 0x20,0x0C,0x33,0x12,0x30,0x02,0xC9,0x04,0xBC,0xFF,0xF7,0x47,0x03,0x01,0x90,0x03, ++ 0xD0,0x03,0x41,0x01,0x80,0x1E,0x00,0x07,0x02,0x3F,0xF1,0x00,0x97,0x03,0xC1,0x03, ++ 0x40,0xF9,0x93,0x0E,0xE7,0x00,0x82,0x03,0x43,0x44,0x15,0x04,0x03,0x19,0x80,0x03, ++ 0xE4,0xC3,0x83,0x01,0x89,0x03,0xCF,0x03,0xC2,0x8B,0xD1,0x00,0xE0,0x00,0x42,0x11, ++ 0xC3,0x2E,0xC8,0x03,0xC2,0x8B,0xD3,0x00,0xE0,0x00,0x42,0x11,0xCF,0x4E,0xC0,0x03, ++ 0x40,0x11,0x98,0x36,0xCA,0x0C,0xE0,0x4B,0x10,0x42,0xC4,0x16,0x07,0x01,0x80,0x03, ++ 0x89,0x03,0xC7,0x83,0x8B,0x03,0xC1,0x83,0x8F,0x03,0xEB,0xF5,0xAC,0x85,0x37,0xE2, ++ 0x34,0x2A,0xAB,0x01,0x4A,0x5C,0x27,0xD8,0x67,0xE0,0x40,0xF9,0x88,0x0E,0x00,0x01, ++ 0xE9,0x85,0x1F,0x21,0x1B,0xC2,0x5A,0xFA,0xC6,0x00,0xC4,0x00,0x1A,0x31,0x18,0xCA, ++ 0xC3,0x48,0x54,0xE2,0xD4,0x21,0xC1,0x50,0x0A,0xA1,0xF0,0x0A,0x48,0x01,0xD0,0x06, ++ 0x10,0x4A,0x1A,0xB1,0xF0,0x1A,0x5E,0x01,0xD2,0x06,0x10,0xDA,0xC3,0x48,0x5E,0xB2, ++ 0x10,0xCA,0x9C,0x06,0x08,0x01,0x30,0x71,0x44,0x9C,0xF8,0x32,0xD8,0xD8,0xAC,0x06, ++ 0x10,0xDA,0x32,0x81,0x44,0x94,0xFA,0x32,0xD8,0x90,0xAC,0x06,0x14,0x92,0xC2,0xD0, ++ 0x11,0x12,0x9D,0x0E,0xC8,0x33,0x74,0x09,0x8B,0x26,0xE0,0x5B,0xCA,0x3B,0xF6,0xD8, ++ 0x10,0xFA,0xDC,0xBE,0x70,0x09,0x88,0x3E,0xDC,0x5B,0x11,0x5A,0x9E,0x26,0xC0,0x03, ++ 0x40,0xF1,0xC0,0x0E,0x40,0x51,0x90,0x6E,0x70,0x09,0x88,0x1E,0x30,0x02,0x5B,0x04, ++ 0x40,0xC1,0x98,0x3E,0x70,0x09,0x88,0x16,0x04,0x00,0x13,0x82,0xCD,0x16,0x00,0x00, ++ 0x10,0x82,0xC4,0x0E,0x07,0x01,0xE8,0x85,0x07,0x09,0xE8,0x85,0xAC,0xFD,0x87,0x5D, ++ 0x30,0xB2,0x0C,0x01,0x28,0x01,0x00,0x01,0x80,0x14,0xC0,0xA4,0xF8,0x23,0x06,0x01, ++ 0x30,0x22,0x84,0x34,0x00,0x27,0xD0,0x64,0x02,0xF9,0xA7,0x82,0xE6,0x48,0x92,0x4D, ++ 0x17,0x0A,0x9D,0xC6,0xD3,0x74,0x28,0x92,0xC0,0x26,0xC0,0x74,0x83,0x24,0x30,0x82, ++ 0x80,0x1C,0x00,0x1F,0x30,0x82,0x83,0x24,0xC0,0x74,0x80,0x1C,0x00,0x01,0x80,0x2C, ++ 0x00,0xD7,0x1A,0x01,0x03,0xB7,0x32,0x02,0x06,0xC2,0x3E,0x00,0x8A,0x86,0x42,0x32, ++ 0x80,0x3C,0x00,0x01,0xD0,0xA4,0xF0,0x5C,0xF8,0x93,0x90,0x54,0x33,0xD2,0x18,0x12, ++ 0x05,0xB8,0xCA,0xD0,0x90,0x4C,0x00,0x6F,0xF6,0x34,0x00,0x32,0x38,0x90,0x8F,0x3E, ++ 0xF2,0x4C,0x00,0x38,0xD8,0xB2,0xFF,0x3C,0x10,0xF2,0x95,0x0E,0xB0,0x3C,0x30,0x0A, ++ 0xE6,0x00,0x92,0x05,0xD4,0x54,0x10,0x12,0xC1,0x76,0x77,0xBA,0x02,0x01,0x00,0x78, ++ 0xB8,0x44,0x00,0x87,0x36,0x3A,0x03,0x3A,0x38,0xF8,0x8F,0x56,0x33,0x3A,0x18,0x3A, ++ 0xD3,0x5C,0x00,0xF8,0xC0,0xF8,0xD5,0x44,0xD5,0xFA,0x15,0xBA,0xC1,0x0E,0x30,0xF2, ++ 0x32,0x2A,0xE0,0x00,0x93,0x05,0x2E,0x82,0x9C,0x66,0x17,0xEA,0x88,0xA6,0xC0,0x14, ++ 0xC8,0x00,0x84,0x14,0xC2,0x2C,0xE0,0x00,0x90,0x05,0x86,0x2C,0xC2,0x64,0xA0,0x2A, ++ 0x31,0x09,0x30,0x82,0xD4,0x34,0x00,0x42,0x1C,0x82,0x90,0x05,0x85,0x34,0x00,0x72, ++ 0x30,0x02,0x1B,0x32,0x94,0x85,0x35,0x22,0xD0,0x24,0xC0,0x2C,0x10,0x82,0x84,0x1E, ++ 0xE6,0xD8,0x92,0xDD,0x2D,0x9A,0x9B,0x36,0xD0,0x24,0xC0,0x2C,0x15,0x82,0x9C,0x06, ++ 0xC0,0x14,0x80,0x3C,0x10,0x01,0x00,0x01,0x0B,0x01,0x30,0x5A,0x80,0xCB,0x18,0x01, ++ 0x0C,0x01,0x30,0x62,0x30,0x4A,0xE3,0x4A,0x02,0x0F,0xE0,0x48,0x90,0x4D,0x36,0xEA, ++ 0x07,0x6A,0x3E,0x68,0x88,0xCE,0xEF,0x1C,0x10,0x4A,0x9D,0xFE,0x40,0x01,0x88,0x8E, ++ 0x08,0xF9,0x07,0x5F,0xD0,0x64,0xE0,0x9A,0x28,0x9A,0x93,0x1E,0xD0,0xA4,0xF8,0x93, ++ 0x10,0x12,0xC4,0x0E,0xD0,0x64,0xA0,0x8A,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0x8E, ++ 0x87,0x7D,0xE8,0x85,0xF6,0x00,0x92,0x05,0x30,0x4A,0xE3,0x4A,0x2D,0x09,0x30,0x62, ++ 0x00,0x6F,0x01,0x00,0x70,0x30,0x03,0x00,0xF8,0xFF,0x07,0x00,0x33,0x6A,0x18,0x2A, ++ 0xFB,0x5C,0x00,0x70,0xCA,0xB0,0x07,0x38,0xDD,0xAA,0xC7,0x50,0x2C,0x09,0x00,0x6A, ++ 0x1D,0xEA,0x90,0x5D,0x31,0x72,0xA3,0x8A,0xED,0x3C,0x10,0x52,0x98,0x16,0x28,0x11, ++ 0x30,0x62,0x05,0xA7,0xFA,0x74,0xE0,0x28,0x10,0xEA,0x9D,0x6E,0x90,0x3C,0x08,0x01, ++ 0x00,0x27,0xF8,0x64,0xE3,0xAA,0xA3,0xEA,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xC6, ++ 0xE0,0x8A,0x29,0x09,0x30,0x62,0x05,0x17,0x90,0x45,0x2F,0x01,0xA3,0xAA,0x31,0x2A, ++ 0x6D,0x01,0x80,0x2E,0x33,0x6A,0x18,0x2A,0xFB,0x5C,0x00,0x70,0xCA,0xB0,0x07,0x38, ++ 0xDA,0xAA,0xDF,0x90,0x2C,0x09,0x00,0x6A,0x1B,0x5A,0x35,0x6A,0xE2,0x4A,0xE1,0x48, ++ 0xA4,0x4A,0x39,0xAF,0xAC,0xC5,0x37,0x22,0xFC,0x73,0x5E,0xAA,0x36,0x02,0xC3,0x00, ++ 0x31,0x32,0x34,0xAA,0x38,0x21,0x31,0x62,0x1A,0xEA,0xA3,0x01,0x13,0x01,0x20,0x2A, ++ 0xC0,0x68,0x07,0xF7,0xC0,0x1B,0x58,0x79,0x86,0xD6,0xC8,0x1B,0x30,0xD8,0xA0,0x3E, ++ 0x18,0xF9,0x8F,0x1B,0x8E,0x1B,0xC2,0x1B,0xE5,0x3B,0x15,0xDA,0xC6,0x06,0x88,0x13, ++ 0xCA,0x1B,0x36,0xD8,0x76,0xD8,0x8A,0x1B,0x58,0x01,0x80,0x0E,0xF6,0xD8,0x8A,0x1B, ++ 0xC8,0x1B,0x5E,0x01,0x8A,0x26,0xC0,0x1B,0x44,0xD8,0x04,0xD8,0x84,0x1B,0x82,0x13, ++ 0x84,0x21,0x11,0x2A,0xC0,0xF6,0x06,0x01,0x84,0x04,0xB8,0x53,0x30,0x82,0x03,0x8F, ++ 0xC5,0x13,0x10,0x92,0x96,0x5E,0xC0,0x13,0xE2,0x3B,0x35,0x98,0x75,0xD8,0x12,0xDA, ++ 0xCC,0x2E,0xC0,0x13,0x50,0x01,0x81,0x16,0x00,0x09,0x80,0x04,0x00,0x27,0x10,0x01, ++ 0x81,0x13,0x84,0x21,0x17,0x2A,0xC4,0x5E,0xC0,0x04,0x40,0x01,0x83,0x76,0x31,0x92, ++ 0x36,0x5A,0x98,0x01,0x00,0x47,0x01,0x01,0x80,0x83,0xC4,0x83,0x11,0x82,0x95,0x16, ++ 0xC2,0x83,0x36,0x38,0xE3,0x03,0x75,0xF8,0x10,0x3A,0xCC,0xE6,0x04,0x09,0x80,0x83, ++ 0xFA,0x43,0xE4,0x00,0xB8,0x43,0x3C,0x71,0xF8,0xBA,0x7E,0x01,0xD0,0x16,0x00,0x01, ++ 0x08,0x84,0x06,0x27,0x54,0xC4,0x10,0x3A,0xE8,0x0E,0x50,0xC4,0x08,0x84,0x3E,0x81, ++ 0xF8,0xBA,0x7E,0x01,0xD0,0x16,0x00,0x01,0x10,0x84,0x00,0x27,0x54,0xC4,0x12,0x3A, ++ 0xEA,0x0E,0x50,0xC4,0x11,0x84,0x90,0x21,0x16,0xAA,0xC4,0xA6,0xF8,0x43,0x40,0x01, ++ 0x88,0x36,0x58,0x44,0x16,0xE9,0x03,0x90,0x10,0x82,0x94,0x0E,0xE0,0x00,0x1A,0x44, ++ 0xF8,0x43,0x44,0x01,0x80,0xCE,0x10,0x01,0x03,0x01,0x28,0x99,0x0E,0x68,0xFB,0x63, ++ 0x01,0x6F,0x18,0x21,0x1B,0x1A,0x22,0x1A,0xC8,0xD8,0xD2,0xF3,0x70,0x09,0x88,0x26, ++ 0xC8,0xDB,0x5E,0x19,0x8A,0x0E,0xE0,0x90,0x92,0x95,0xE6,0x00,0x94,0x05,0x16,0x22, ++ 0xC0,0x7E,0x57,0x01,0x88,0x0E,0x00,0x01,0x1F,0x44,0xE8,0xC5,0xAC,0x85,0x87,0x3D, ++ 0x30,0x2A,0x30,0x62,0x41,0x12,0xC2,0x40,0x08,0x29,0xEE,0x4A,0x4B,0x29,0x80,0xDE, ++ 0x4B,0x02,0xC2,0x70,0xEB,0x48,0xC4,0x48,0x89,0x1C,0x48,0xF2,0x8B,0x61,0xC0,0x48, ++ 0x88,0x14,0x08,0x01,0x10,0xF9,0x1F,0x79,0x03,0x3F,0xA0,0x92,0xC8,0x3B,0x7E,0x01, ++ 0x88,0x06,0x80,0x1B,0xE6,0x48,0x92,0x4D,0x87,0x21,0xF9,0x3B,0x17,0x7A,0xC4,0xA6, ++ 0x00,0x01,0x80,0x34,0xF8,0x03,0x41,0x01,0x80,0xCE,0xB2,0x04,0x31,0x0A,0x31,0x42, ++ 0x58,0x2D,0xD0,0x14,0xBA,0xFF,0xDF,0x97,0x80,0x34,0xC0,0x34,0x40,0x01,0x88,0x76, ++ 0x30,0x01,0x00,0x47,0x31,0x5A,0x31,0x92,0x08,0xF9,0x07,0x09,0xA7,0x04,0xB8,0xFF, ++ 0xE3,0x47,0xE7,0xB0,0x91,0xB5,0xFF,0x03,0x17,0x82,0xC5,0x9E,0x00,0xFF,0xC1,0x34, ++ 0x40,0x09,0x88,0x96,0xC1,0xB3,0x31,0x1A,0x30,0x52,0x09,0x01,0x37,0x82,0xB9,0xFF, ++ 0xE8,0x2F,0x46,0x01,0x80,0x0E,0x00,0x01,0x00,0x07,0x00,0x09,0x30,0x5A,0x11,0x01, ++ 0x30,0x8A,0xA1,0x04,0xBE,0xFF,0xE7,0x6F,0x00,0x4F,0xA1,0x04,0xFB,0x3B,0x31,0x5A, ++ 0xE9,0xD3,0x30,0xDA,0xC8,0x1C,0xC0,0x14,0xB8,0xFF,0xF7,0x47,0x38,0x01,0x00,0xDF, ++ 0xC6,0x1C,0xE8,0x02,0x40,0xF9,0x87,0x16,0xE0,0x82,0x81,0x24,0x07,0x0F,0x00,0xF9, ++ 0x81,0x24,0x30,0x1A,0x31,0x52,0x31,0xCA,0xC7,0x24,0xB8,0xFF,0xE8,0xFF,0x44,0x01, ++ 0x80,0x0E,0x00,0x01,0x00,0x07,0x00,0x09,0x31,0x5A,0x31,0xD2,0xA0,0x04,0xC8,0x24, ++ 0xBD,0xFF,0xE7,0x3F,0xE7,0xF8,0x93,0xFD,0xFD,0x03,0x11,0xC2,0xC1,0x06,0x37,0x0A, ++ 0x30,0x42,0xD1,0x34,0xBE,0xFF,0xF7,0xB7,0x20,0xCF,0x04,0x01,0x38,0x82,0x03,0x00, ++ 0x70,0x30,0x03,0x00,0x48,0xE0,0x06,0x00,0xAE,0xFD,0x87,0x5D,0xC6,0xAC,0xDA,0x03, ++ 0x82,0xCC,0xC1,0xAC,0xD9,0x03,0x84,0xC4,0x01,0x09,0x58,0x45,0x81,0xC3,0xC0,0xC4, ++ 0xE2,0x00,0x82,0xC3,0xC4,0xC4,0x81,0xC3,0xC2,0xC4,0xF1,0x00,0x82,0xC3,0xC6,0xAC, ++ 0x82,0x01,0x87,0x54,0xC0,0x0B,0x00,0x21,0x1A,0x0A,0xC0,0x54,0x82,0x0B,0xC0,0xAC, ++ 0xCA,0x03,0x42,0x00,0x80,0xD4,0x09,0x01,0x40,0xB5,0x31,0x52,0x00,0x36,0x00,0x01, ++ 0x82,0xF4,0xC0,0xAC,0xCC,0xB4,0x82,0x01,0x82,0x4C,0xC2,0x74,0x92,0x05,0x82,0x44, ++ 0xC2,0x6C,0x92,0x05,0x82,0x3C,0xC2,0xAC,0x82,0x01,0x86,0x34,0x4B,0x11,0x80,0xBE, ++ 0x10,0x01,0x00,0x01,0x4C,0x45,0xB1,0x4A,0x8F,0x2C,0x4A,0xF2,0xB2,0x4A,0x8C,0x24, ++ 0x48,0xE2,0xEF,0x48,0xB2,0x4A,0x8C,0x1C,0x04,0x08,0xC4,0x48,0x91,0x4D,0x66,0x9D, ++ 0xDB,0x74,0xA2,0x1A,0x62,0x85,0xD9,0x6C,0xA2,0x1A,0xDB,0x24,0x9A,0x34,0xD9,0x1C, ++ 0x9A,0x2C,0xD9,0x2C,0x98,0x24,0x41,0x09,0x89,0x5E,0xD8,0x34,0x12,0xDA,0x92,0xDD, ++ 0x99,0x34,0xD9,0x2C,0x12,0xDA,0x92,0xDD,0x99,0x2C,0xD9,0x24,0x12,0xDA,0x92,0xDD, ++ 0x9A,0x24,0xD9,0x5C,0x32,0xE2,0xDC,0x64,0x9A,0x5C,0xD9,0x3C,0xE1,0x44,0xEA,0x2C, ++ 0xCA,0xD8,0x92,0xDD,0xEB,0x34,0xC9,0x20,0x91,0x25,0xF3,0x24,0xED,0x5C,0xC9,0x68, ++ 0xA8,0x5C,0x59,0x01,0xD9,0x86,0xEB,0xCC,0x13,0x5A,0xD5,0x6E,0x63,0x01,0xD8,0x5E, ++ 0xED,0xC4,0x11,0x62,0xD1,0x46,0xEB,0x5C,0xC5,0x6B,0x49,0x68,0x8B,0x06,0x32,0x2A, ++ 0x3F,0x01,0xF8,0x7A,0xEB,0x24,0x01,0x68,0x23,0x62,0x35,0x32,0x2B,0x01,0xF8,0xAA, ++ 0xF5,0xD4,0x11,0xAA,0xEA,0xC6,0xF2,0xB4,0x71,0x09,0x88,0x16,0xD9,0xF0,0x93,0xB5, ++ 0xB2,0x9C,0xF8,0x5C,0x35,0x01,0xF8,0xF2,0x10,0x72,0xDD,0x06,0x37,0xAA,0x81,0x68, ++ 0x01,0x68,0x33,0x7A,0xF3,0x9C,0x10,0x6A,0x12,0xAA,0xE5,0x2E,0x6B,0x9D,0xA1,0x62, ++ 0x6B,0x85,0xA1,0x5A,0x01,0xA8,0x72,0xB5,0xC9,0x68,0xE5,0x72,0xE1,0xB0,0xA3,0x72, ++ 0xEB,0xF4,0xE0,0x68,0x90,0x6D,0xAF,0xF4,0xF5,0x9C,0x10,0xBA,0xD1,0xBE,0x05,0x9F, ++ 0x09,0xEF,0x6A,0x9D,0xA1,0x62,0x6B,0x85,0xA2,0x5A,0x03,0xA8,0x75,0xB5,0xC9,0x68, ++ 0xE3,0x72,0xE1,0xB0,0xA0,0x72,0xE9,0xF4,0xE7,0x68,0x93,0x6D,0xAD,0xF4,0x38,0x37, ++ 0xE9,0x5C,0xC1,0x6B,0x48,0x68,0x6D,0x19,0x8A,0x6E,0x00,0xB0,0x7F,0xB5,0xC9,0xB0, ++ 0xE0,0xB2,0x71,0x09,0xC2,0x3E,0xC0,0x64,0x08,0x01,0xC6,0x03,0x1A,0x42,0xC8,0x64, ++ 0x82,0x43,0x80,0x7D,0xE8,0x85,0x6F,0x11,0x89,0x56,0x68,0x9D,0xA1,0x62,0x63,0x85, ++ 0xA2,0x1A,0x03,0x98,0x4A,0xB5,0xC1,0xC8,0xE2,0x5A,0xE0,0xD8,0xA0,0x5A,0x00,0x1F, ++ 0xCE,0x34,0xCA,0x4B,0x4F,0x51,0x90,0x66,0xE6,0x00,0x92,0x05,0x40,0x11,0x90,0x06, ++ 0x3A,0xD7,0xE2,0x90,0x90,0x95,0x56,0x21,0x92,0x06,0x38,0x57,0x01,0x01,0x80,0x64, ++ 0xC0,0xB4,0x42,0x09,0x88,0xF6,0x03,0x01,0x80,0x7C,0x01,0x01,0x81,0x74,0xC9,0x7C, ++ 0x42,0xB5,0x01,0x48,0xC2,0x40,0x80,0x14,0xC1,0x74,0xC9,0x7C,0x02,0x00,0xC4,0x00, ++ 0x91,0x05,0x86,0x4C,0xCA,0x74,0xC1,0x14,0xE0,0x2A,0x6A,0x09,0xC1,0x26,0xC0,0x64, ++ 0xE6,0x00,0x92,0x05,0x87,0x64,0x01,0x8F,0xC0,0x74,0x41,0x09,0x89,0x16,0xC0,0x7C, ++ 0x47,0x01,0x88,0xC6,0x08,0x81,0x41,0x45,0x83,0x17,0xC0,0x77,0xC0,0x6C,0x82,0x3C, ++ 0xC0,0x74,0x82,0x34,0xC0,0x5C,0x82,0x0C,0xC0,0x64,0x82,0x04,0xC4,0x7C,0xE1,0x00, ++ 0x3C,0x00,0x7C,0x00,0x50,0x5A,0xB4,0xA2,0xE8,0x98,0xB0,0xCA,0x31,0x62,0x74,0x45, ++ 0xB1,0x8A,0xC1,0x7C,0xB0,0x82,0x80,0x24,0xC0,0x7C,0xB1,0xC2,0x81,0x1C,0xD0,0x7C, ++ 0xB0,0x82,0x85,0x14,0xC0,0x74,0x41,0x09,0x88,0x5E,0xC0,0x24,0x12,0x02,0x92,0x05, ++ 0x80,0x24,0xC0,0x1C,0x12,0x02,0x92,0x05,0x80,0x1C,0xC0,0x14,0x12,0x02,0x92,0x05, ++ 0x80,0x14,0x00,0x01,0x83,0x2C,0xE0,0x68,0xAD,0xF4,0x01,0x9F,0x40,0x61,0x98,0x66, ++ 0xC8,0x24,0xC0,0x34,0xD2,0x4C,0xD1,0x00,0x4C,0x9D,0xA1,0x42,0xC8,0x1C,0xC0,0x3C, ++ 0xD2,0x4C,0xD1,0x00,0x4C,0x85,0xA1,0x42,0x00,0x47,0x15,0x01,0xDC,0x0C,0x00,0x28, ++ 0xF0,0xD2,0x5C,0x45,0x88,0xD2,0x12,0x01,0x90,0x6C,0xD1,0x3C,0x92,0x95,0x92,0x0C, ++ 0xD2,0x34,0x90,0x95,0x91,0x04,0xD2,0x6C,0x50,0x09,0x88,0x3E,0x12,0x12,0x93,0xA5, ++ 0x32,0x12,0x13,0x92,0x94,0x95,0x32,0xA2,0x12,0x4A,0x92,0x4D,0xD2,0x0C,0xDA,0x04, ++ 0xF0,0x0C,0x00,0x07,0x01,0xEF,0xB4,0x1C,0xF1,0x04,0xB0,0x5C,0x01,0x70,0xB2,0xFC, ++ 0x22,0x12,0x93,0x95,0xCA,0xD8,0x90,0xDD,0xF9,0x1C,0xF1,0xFC,0xC9,0xB0,0xB7,0x1C, ++ 0xF3,0x5C,0xC1,0xB0,0xB0,0x5C,0x51,0x01,0xD9,0xBE,0xF0,0xCC,0x10,0x92,0xD5,0xA6, ++ 0x58,0x01,0xD8,0x96,0xF5,0xC4,0x11,0x9A,0xD1,0x7E,0xF8,0x1C,0x35,0x01,0xF8,0xF2, ++ 0xF9,0x5C,0xC1,0xFB,0x48,0xF8,0x8D,0x46,0xFD,0xD4,0x11,0xF2,0xE8,0x2E,0x78,0x45, ++ 0xCD,0xFA,0xCB,0xF0,0x7B,0x45,0x88,0xF2,0x39,0xD7,0xD6,0x6C,0xE6,0x90,0x92,0x95, ++ 0x91,0x6C,0xD1,0x6C,0x55,0x11,0x98,0xF6,0x41,0x01,0x80,0xF6,0xF2,0x10,0xF2,0x4C, ++ 0x00,0x90,0x5C,0x45,0xC7,0xD2,0xD4,0xB3,0xCC,0xDA,0xCA,0xB0,0x11,0xF2,0x94,0x86, ++ 0xD0,0x2C,0x50,0x09,0x88,0x8E,0xD1,0x24,0xC1,0x34,0xD8,0x4C,0xD1,0x00,0x54,0x9D, ++ 0xA0,0x82,0xDE,0x1C,0xD1,0x3C,0xE8,0x4C,0xD1,0x90,0x5E,0x85,0xA8,0xD2,0xEA,0x14, ++ 0xDA,0x04,0xD8,0xE8,0x36,0x1A,0xD3,0x90,0x90,0x95,0xDA,0x00,0x93,0x1D,0xD2,0x40, ++ 0x2C,0x01,0x38,0x01,0x50,0x01,0xD8,0x56,0xF5,0xCC,0x11,0x92,0xD0,0x3E,0x58,0x01, ++ 0xD9,0x2E,0xF0,0xC4,0x10,0x9A,0xD5,0x16,0xC1,0x33,0x18,0xF2,0x83,0x33,0x20,0x12, ++ 0x90,0x95,0xCA,0xD8,0x92,0xDD,0xC2,0x00,0xE7,0x68,0x93,0x6D,0x6F,0x11,0xC8,0x4E, ++ 0x04,0xE7,0x10,0x9A,0x90,0x0E,0x10,0x09,0x90,0x2C,0xD8,0x24,0xD6,0x34,0xC0,0x90, ++ 0x90,0x95,0x96,0x34,0xD8,0x1C,0xD0,0x3C,0xC6,0x90,0x96,0x95,0x90,0x3C,0xD0,0x14, ++ 0xDA,0x0C,0x00,0x90,0xC0,0x90,0x96,0x0C,0xD8,0x14,0xD0,0x04,0xC0,0x90,0x96,0x04, ++ 0xE6,0x00,0x92,0x05,0xD4,0xF4,0x11,0x82,0x92,0x06,0x38,0x3F,0xC2,0x74,0xE1,0x00, ++ 0x91,0x05,0x86,0x74,0xC0,0x74,0x41,0x11,0x97,0x06,0x30,0xAF,0xC2,0x7C,0xE1,0x00, ++ 0x91,0x05,0x86,0x7C,0xC0,0x7C,0x41,0x21,0x97,0x06,0x30,0x37,0x00,0x0F,0x00,0x41, ++ 0x81,0x64,0xC1,0x64,0x41,0x41,0x88,0xD6,0x10,0x01,0x00,0x01,0x58,0x8A,0xE8,0xC8, ++ 0xB4,0xF2,0xB4,0x7A,0x31,0x8A,0x31,0xDA,0x40,0x09,0x88,0x1E,0x12,0x4A,0x92,0x4D, ++ 0x12,0xDA,0x92,0xDD,0xE7,0x6C,0xC2,0x18,0x92,0xDD,0xE2,0x74,0xC2,0x08,0x93,0x65, ++ 0x04,0x08,0xC4,0x48,0x90,0x4D,0x5E,0x01,0xD9,0x76,0xE8,0xCC,0x10,0x5A,0xD5,0x5E, ++ 0x60,0x01,0xD8,0x4E,0xED,0xC4,0x11,0x62,0xD1,0x36,0x68,0x9D,0xA1,0x62,0x63,0x85, ++ 0xA0,0x1A,0x03,0x3F,0x70,0xF2,0x06,0x00,0x62,0x9D,0xD9,0x74,0xA1,0x1A,0x63,0x85, ++ 0xDB,0x6C,0xA2,0x1A,0xE6,0x00,0x92,0x05,0x46,0x11,0x98,0x9E,0xE6,0x90,0x92,0x95, ++ 0x56,0x21,0x98,0x56,0x58,0x85,0xD9,0xC3,0xA8,0xC3,0xC0,0xC3,0x90,0xC3,0x00,0x01, ++ 0x81,0xFC,0x58,0x85,0xD8,0xC3,0xA8,0xC3,0xC0,0xC3,0x90,0xC3,0x00,0x01,0x80,0xE4, ++ 0x30,0x3A,0x80,0xEC,0xC4,0xAC,0xCA,0x03,0x80,0xD4,0x01,0x01,0x0E,0x01,0x00,0x18, ++ 0x54,0xA5,0xC0,0xD0,0x32,0xA2,0x04,0x20,0xC6,0x10,0x93,0x95,0x6D,0x9D,0xE1,0x72, ++ 0x33,0x2A,0xA3,0x72,0x6D,0x85,0xE1,0x6A,0x32,0x12,0xC3,0x90,0x8A,0xAB,0xE0,0x48, ++ 0x90,0x4D,0x4E,0x19,0x98,0x86,0x47,0x09,0x80,0x0E,0x40,0x19,0x88,0x66,0x60,0xA5, ++ 0xE3,0x0A,0x37,0x12,0xCB,0x93,0x30,0x2A,0xC7,0x6B,0xA5,0x2A,0x34,0x1A,0xCB,0xE3, ++ 0x8C,0xE3,0x80,0xCB,0x34,0x0A,0x8B,0x53,0x09,0x09,0x88,0x0C,0x09,0x01,0x88,0x74, ++ 0xD3,0x74,0x31,0x0A,0xE1,0x4A,0xDC,0x74,0x36,0x12,0xC3,0x90,0xCA,0x9B,0xC0,0xAB, ++ 0xC9,0x93,0x92,0x14,0xD0,0x74,0x51,0x01,0x88,0x16,0x41,0x01,0x80,0x0E,0x40,0x19, ++ 0x8D,0x5E,0x10,0x4A,0x98,0x4E,0x10,0x09,0x90,0x04,0x41,0x01,0x8A,0x16,0xF0,0x10, ++ 0x90,0x0C,0x01,0xF7,0x11,0x09,0x90,0x0C,0x00,0xDF,0x40,0x09,0x80,0x0E,0x40,0x11, ++ 0x8D,0x5E,0x10,0x4A,0xC0,0x4E,0x10,0x09,0x90,0x04,0x41,0x09,0x8C,0x16,0xF0,0x10, ++ 0x90,0x0C,0x01,0x77,0x11,0x09,0x90,0x0C,0x00,0x5F,0x10,0x01,0x90,0x04,0x01,0x47, ++ 0x11,0x09,0x90,0x04,0x40,0x11,0x90,0x16,0xF1,0x90,0x94,0x0C,0x00,0x0F,0x10,0x09, ++ 0x90,0x0C,0x41,0x01,0x80,0x0E,0x40,0x19,0x8D,0x0E,0x10,0x4A,0x90,0x2E,0x40,0x09, ++ 0x80,0x0E,0x40,0x11,0x8D,0x26,0x10,0x4A,0xC0,0x16,0x10,0x09,0x94,0x54,0x01,0x8F, ++ 0x11,0x01,0x90,0x54,0x01,0x77,0xF4,0xC4,0x33,0x12,0x19,0x92,0xF1,0xA4,0x92,0xE4, ++ 0xC9,0x90,0xF4,0xEC,0xC9,0x90,0x94,0x5C,0xD0,0x5C,0xC1,0x93,0x92,0xDC,0x31,0x90, ++ 0xA1,0xCE,0xD1,0xE4,0xF2,0xA4,0x02,0x90,0xC9,0x90,0xF4,0x3C,0x04,0xB0,0xCB,0x90, ++ 0x35,0x39,0x09,0xB0,0xC8,0xB0,0x14,0xE1,0xF1,0x92,0xF5,0xD4,0x10,0x92,0xD5,0x26, ++ 0xF0,0x64,0x71,0x41,0x88,0xB6,0x50,0x01,0xD9,0xA6,0xF0,0xDC,0x48,0xB0,0x87,0x06, ++ 0x80,0x90,0xF2,0xE4,0xC0,0xB0,0xB5,0xE4,0xF2,0x3C,0x19,0xB2,0xC8,0xB8,0xF7,0xEC, ++ 0x1C,0x12,0xCB,0x90,0x90,0xEC,0xD0,0xFC,0xE4,0x90,0x92,0x95,0x91,0xFC,0xD0,0xDC, ++ 0x48,0x90,0x8E,0xEE,0xD0,0x4C,0xF2,0xF4,0xD5,0x93,0x12,0x92,0xC1,0x2E,0xD0,0xDC, ++ 0x31,0x01,0x1E,0x92,0xF1,0x5C,0x81,0x93,0x01,0x47,0xD0,0xDC,0x31,0x01,0x1A,0x92, ++ 0xF1,0x5C,0x81,0x93,0x01,0x17,0xD0,0x04,0x50,0x09,0x80,0x4E,0xD0,0x04,0x51,0x09, ++ 0x8A,0x36,0xD0,0x6C,0x10,0xA2,0x84,0x1E,0xD5,0x0C,0xC1,0x10,0x95,0xA5,0x3A,0x57, ++ 0x10,0x4A,0x8D,0xDE,0xD4,0x14,0x11,0x9A,0x89,0xC6,0xC8,0x74,0xE6,0x48,0x92,0x4D, ++ 0x89,0x74,0xC9,0x74,0x48,0x11,0x90,0x06,0x3A,0x97,0xE2,0x00,0x90,0x05,0x46,0x21, ++ 0x91,0x06,0x38,0x1F,0xC6,0x34,0xCA,0x03,0x42,0x01,0x88,0x5E,0xC9,0xAC,0x8A,0x01, ++ 0xE0,0x43,0x36,0x10,0xAA,0x36,0x31,0x00,0x71,0x00,0x04,0x27,0xD0,0x54,0x51,0x01, ++ 0x8D,0x5E,0x10,0x4A,0xCA,0x16,0xF0,0x48,0x90,0x4D,0x06,0x1F,0x10,0x4A,0x95,0x0E, ++ 0xE6,0x48,0x92,0x4D,0x11,0x09,0x90,0x54,0x01,0x67,0xD0,0x14,0x10,0x9A,0xCC,0x16, ++ 0xF6,0xD8,0x92,0xDD,0x01,0x27,0xD0,0x14,0x10,0x9A,0x94,0x0E,0xE6,0xD8,0x92,0xDD, ++ 0x11,0x01,0x90,0x54,0x91,0x55,0x92,0x3C,0x97,0xE5,0x72,0xFA,0xD4,0x3C,0xC9,0x90, ++ 0x93,0xEC,0x39,0x47,0x02,0x01,0xD0,0xAC,0x6C,0x94,0x16,0x12,0x9A,0xD6,0xC0,0xAC, ++ 0xE8,0x4B,0x70,0x04,0x10,0x42,0x9C,0x26,0xC4,0x4C,0xD2,0x03,0xF6,0x00,0x94,0x05, ++ 0x02,0x1F,0xC0,0x4C,0xD4,0x03,0xE4,0x00,0x90,0x05,0xCE,0xFC,0x10,0x0A,0x9C,0x4E, ++ 0xC0,0xAC,0x0A,0x01,0xBA,0x0B,0xC0,0x54,0x08,0xD9,0xC7,0x03,0x02,0x42,0xC8,0x54, ++ 0x82,0x43,0x28,0x37,0x27,0x01,0x28,0xF9,0xA8,0x09,0x60,0x01,0x8A,0x56,0xC0,0x44, ++ 0xC8,0xC4,0xB9,0x9C,0xD2,0x34,0x4A,0x93,0x92,0x94,0xD0,0x74,0x5A,0x3A,0x07,0x90, ++ 0xF0,0xF2,0x04,0x57,0xC1,0x3C,0xCA,0xCC,0xD0,0xEC,0x90,0x9C,0xD4,0x34,0x4A,0x93, ++ 0x92,0x94,0xD0,0x6C,0x5A,0x12,0x07,0x90,0xF0,0xF2,0x44,0x01,0x82,0x16,0xF0,0x48, ++ 0x10,0x42,0x8C,0x8E,0xD0,0x74,0x92,0x04,0x91,0x05,0x36,0x0A,0xDA,0x6C,0xD2,0x5C, ++ 0xBB,0xEF,0xD7,0xA7,0x35,0x4A,0x11,0x42,0xE8,0x0E,0x30,0x42,0x00,0x17,0x40,0x01, ++ 0xD0,0x06,0x00,0x01,0xC8,0x30,0x04,0x07,0xB0,0x01,0xC4,0x9C,0xC8,0xE4,0x10,0x00, ++ 0x86,0x0F,0xE8,0x27,0xCC,0x94,0xC8,0x00,0x18,0x42,0x42,0x01,0xD0,0x06,0x00,0x01, ++ 0xA0,0x00,0x60,0x01,0x8A,0x7E,0xC8,0x34,0x54,0x4C,0x10,0x0A,0xD0,0x06,0x30,0x42, ++ 0xC8,0xAC,0x12,0x31,0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90, ++ 0xC2,0x48,0x04,0x44,0x02,0x77,0xC8,0x34,0x54,0x4C,0x12,0x0A,0xD0,0x06,0x30,0x42, ++ 0xC8,0xAC,0x12,0x31,0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90, ++ 0xC4,0x48,0x04,0x44,0xE7,0x20,0x93,0x25,0x64,0x09,0xC8,0xF6,0xC0,0xAC,0x12,0x31, ++ 0xE0,0x0B,0xC2,0xE4,0x02,0x42,0xCE,0xAC,0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48, ++ 0x14,0xC9,0x09,0x90,0xC6,0x48,0x04,0x44,0xC2,0xAC,0xCA,0x74,0xFA,0x03,0x00,0x10, ++ 0xC0,0xA4,0xC2,0x90,0x02,0x89,0x0B,0x00,0xC4,0x90,0xA8,0x8B,0xCA,0xAC,0xD2,0x6C, ++ 0xFA,0x4B,0x00,0x58,0xCA,0xA4,0xC2,0xC8,0xC6,0x40,0xA8,0x13,0xC2,0xAC,0xCA,0xAC, ++ 0xFA,0x03,0xE0,0x00,0xBD,0x43,0x20,0xE7,0xAC,0xFD,0x87,0xBD,0xEC,0x04,0x31,0xA2, ++ 0xD8,0x43,0x87,0x84,0xD8,0x43,0x85,0x7C,0xC8,0x43,0x81,0x74,0x00,0x01,0x80,0x54, ++ 0x42,0x22,0x45,0x0B,0x36,0x42,0x81,0x01,0x80,0xB4,0x48,0x01,0x80,0x1E,0xC0,0x74, ++ 0x40,0x00,0x82,0x5C,0x00,0x67,0xC0,0xB4,0xC8,0x03,0x46,0x51,0x98,0x26,0xC8,0xB4, ++ 0x00,0x49,0xB0,0x42,0x80,0x5C,0x00,0x1F,0xC0,0xB4,0x08,0x41,0xB0,0x0A,0x8A,0x5C, ++ 0x40,0xCA,0xD4,0xD4,0xC8,0xBC,0xC0,0x80,0x80,0xAC,0x48,0x01,0x84,0xF6,0x49,0xBA, ++ 0xC2,0xD4,0xC0,0x08,0x10,0x49,0xC5,0xD4,0x04,0x90,0xC4,0x18,0xE0,0xAC,0xC0,0x74, ++ 0x42,0x00,0x12,0x02,0x90,0x05,0x82,0x54,0x30,0x01,0x00,0x7F,0x00,0x01,0x00,0x47, ++ 0x40,0x7C,0x40,0xD4,0xD1,0xD0,0x05,0x14,0xE4,0x20,0xE5,0x48,0xE2,0xD8,0xE4,0x00, ++ 0x90,0x05,0xD6,0x7C,0x17,0x82,0x9C,0x9E,0xE7,0xB0,0x93,0xB5,0xC4,0x84,0x10,0x32, ++ 0x9B,0x66,0x37,0x02,0x40,0x01,0x80,0x06,0x3C,0x02,0x4C,0x2A,0xC2,0xD4,0xC0,0x18, ++ 0x48,0x1A,0xC4,0xD4,0x8A,0xC1,0xC1,0x00,0x50,0x0A,0xCC,0xD4,0x94,0x81,0xC3,0x48, ++ 0x10,0x01,0x00,0x47,0x40,0x24,0x40,0x74,0xD8,0x20,0x05,0xE4,0xE4,0xD8,0xE4,0x00, ++ 0xE2,0x48,0xE4,0x90,0x90,0x95,0xE6,0x7C,0x17,0x12,0x9D,0x9E,0x48,0x92,0xC3,0xD4, ++ 0xC0,0x00,0x82,0x4C,0xE0,0xAC,0x00,0x01,0x81,0x8C,0x30,0x42,0x80,0x01,0x81,0xA4, ++ 0x80,0x01,0x86,0x9C,0x08,0x97,0x32,0x01,0x08,0x47,0xC2,0x4C,0xC4,0x03,0x48,0x00, ++ 0x89,0xF6,0xF3,0x02,0xCC,0x74,0x10,0x42,0xD8,0xD6,0xC3,0x7C,0x32,0x5A,0x03,0x00, ++ 0xD0,0x08,0x31,0x52,0xD6,0x01,0x59,0x94,0x10,0xD4,0x40,0x54,0x12,0xD4,0x42,0x4C, ++ 0x11,0xCC,0x34,0x0A,0xCE,0x01,0x59,0x4C,0x11,0xCC,0x46,0x0C,0x1B,0xCC,0x40,0x0C, ++ 0x18,0xCC,0xCA,0x08,0x31,0x52,0xD0,0x01,0x5C,0x94,0x1E,0xD4,0xD6,0x02,0x19,0xC4, ++ 0x40,0x44,0x22,0xC4,0x40,0x25,0x70,0x01,0x88,0x26,0x08,0x01,0x16,0xCC,0x10,0xCC, ++ 0x18,0xCC,0x04,0x47,0xCA,0x7C,0xF0,0x48,0x10,0x72,0x8C,0x26,0x0B,0x01,0x30,0x5A, ++ 0x12,0xCC,0x1C,0xCC,0x20,0xCC,0xC8,0x8C,0x48,0x01,0x88,0x26,0x30,0x5A,0x13,0xCC, ++ 0x14,0xCC,0x12,0xCC,0x00,0x4F,0xC8,0x84,0xD2,0x8C,0xF0,0x48,0x10,0x52,0x8C,0x26, ++ 0x0B,0x01,0x30,0x5A,0x1E,0xCC,0x1C,0xCC,0x20,0xCC,0x10,0x01,0xF3,0x12,0x35,0x5A, ++ 0x0A,0x81,0xF0,0xCA,0x11,0x8A,0xD4,0x9E,0x0A,0x91,0xF0,0xCA,0x17,0x8A,0xD4,0xD6, ++ 0x0A,0xA1,0xF0,0xCA,0x17,0x8A,0xD4,0xB6,0x0A,0xB1,0xF0,0xCA,0x17,0x8A,0xD4,0x96, ++ 0x0A,0xD1,0xF0,0xCA,0x11,0x8A,0xE4,0x1E,0x0A,0xE1,0xF0,0xCA,0x17,0x8A,0xE4,0xD6, ++ 0x0A,0xF1,0xF0,0xCA,0x17,0x8A,0xE4,0xB6,0x0A,0x01,0xF1,0xCA,0x17,0x8A,0xE4,0x96, ++ 0x0A,0xD1,0xEC,0x4A,0x4B,0x01,0x80,0xCE,0x08,0x01,0x88,0x6C,0x30,0x72,0x8C,0x1C, ++ 0x88,0x64,0xD8,0xBC,0x5A,0x01,0x88,0x1E,0x32,0xE2,0xFC,0x78,0x1E,0x01,0xF0,0x1A, ++ 0x10,0xDA,0xD5,0x46,0xC0,0xC8,0x92,0x4D,0xDA,0x1C,0xE0,0xD8,0x90,0xDD,0x06,0x07, ++ 0x00,0xF7,0x9D,0x1C,0x00,0x2F,0x58,0x51,0xEB,0x1E,0x30,0x9A,0xE6,0xD8,0x92,0xDD, ++ 0x34,0xF2,0xE4,0x00,0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x36,0xE2,0x30,0x1A,0x5B,0x49, ++ 0x9A,0x26,0xC7,0x80,0x90,0x05,0xD0,0xA4,0x70,0x4C,0xE9,0x93,0x10,0x8A,0x9C,0xB6, ++ 0xCC,0x5C,0x10,0x42,0xD3,0x9E,0x30,0x8A,0x48,0x39,0x98,0x36,0xCA,0x5C,0x80,0x48, ++ 0x10,0x0A,0xDC,0x66,0xC0,0x1C,0x40,0x01,0x88,0x4E,0xC0,0xB4,0xC8,0x03,0x46,0x11, ++ 0x98,0x0E,0x00,0x09,0x80,0x6C,0x48,0xDA,0xC2,0x43,0xE2,0x00,0x80,0x43,0x4A,0xCA, ++ 0xC0,0x43,0x40,0x81,0x90,0x26,0x52,0xC2,0xA2,0xB2,0xE0,0x00,0x81,0x43,0x00,0xFF, ++ 0x34,0xB2,0x84,0x98,0xC0,0x98,0x96,0xDD,0x98,0x14,0x18,0x01,0x30,0xE2,0xDC,0x54, ++ 0x80,0xD8,0x9A,0x94,0x1E,0x01,0xF0,0x1A,0xFD,0x94,0x10,0xDA,0xD3,0x56,0x30,0xBA, ++ 0xC9,0xF8,0x96,0xFD,0x30,0xF2,0xFD,0x54,0x10,0xDA,0xD5,0x1E,0x86,0xB8,0xCA,0xB8, ++ 0x90,0xFD,0xB9,0x14,0xC0,0xC8,0x02,0x97,0x60,0x20,0x02,0x00,0x70,0xD2,0x05,0x00, ++ 0x70,0xD2,0x03,0x00,0x80,0x40,0x07,0x01,0x48,0xE0,0x06,0x00,0x28,0x60,0x00,0x00, ++ 0x68,0x70,0x04,0x00,0x00,0xC0,0x00,0x01,0x80,0xC0,0x06,0x01,0x00,0xF7,0x90,0x4D, ++ 0xE3,0x00,0x34,0x1A,0xE6,0xD8,0x92,0xDD,0x33,0xE2,0x34,0x1A,0x5E,0x49,0x98,0x8E, ++ 0xC4,0x14,0x10,0x0A,0xD8,0x16,0xC8,0x5C,0x28,0x72,0xD4,0x0E,0x00,0x09,0x80,0x6C, ++ 0xC6,0xB4,0xC8,0x03,0x40,0x51,0x98,0x16,0xC0,0xBC,0x40,0x01,0x80,0x46,0xC8,0x6C, ++ 0x00,0x09,0x48,0x01,0x80,0x06,0x00,0x01,0x80,0x64,0x00,0x0F,0x00,0x09,0x80,0x64, ++ 0xC0,0x64,0x40,0x01,0x80,0xA6,0x01,0x09,0xBC,0x43,0x43,0x3A,0x40,0x03,0x42,0x01, ++ 0x88,0x5E,0xC0,0xB4,0xC8,0x03,0x46,0x51,0x90,0x3E,0xC0,0xA4,0x6E,0x4C,0xE7,0x03, ++ 0x32,0x00,0x72,0x00,0x84,0x51,0x10,0x0A,0xC8,0x0E,0x10,0x01,0x00,0x07,0x10,0x09, ++ 0xC0,0xC4,0x40,0x01,0x80,0x06,0x10,0x11,0xC0,0xD4,0x90,0x14,0x81,0x04,0x30,0x9A, ++ 0xA9,0x0C,0x30,0x02,0xD0,0x8C,0xC8,0x4C,0xBA,0xFF,0xD7,0x37,0xC0,0x9C,0xC0,0x03, ++ 0x38,0x00,0xAA,0x1E,0xFF,0x43,0xF9,0x4B,0x10,0x42,0x9C,0x4E,0xC0,0x9C,0xC0,0x03, ++ 0x38,0x00,0xA2,0x1E,0x05,0x01,0xA8,0x43,0xCC,0x9C,0x80,0x43,0x87,0xDD,0xE8,0x85, ++ 0xE0,0x20,0xC5,0x4C,0xE0,0x00,0x82,0x4C,0xE7,0xB0,0x93,0xB5,0xC4,0x7C,0x10,0x32, ++ 0x95,0x06,0x30,0x97,0xC2,0x8C,0xE0,0x00,0x90,0x05,0x86,0x8C,0xC8,0x84,0xC0,0x8C, ++ 0x10,0x42,0x94,0x06,0x37,0x3F,0x3D,0x4F,0xAC,0x9D,0x87,0x0D,0xD8,0x43,0x80,0x04, ++ 0xDB,0x63,0x52,0x12,0xC4,0x0C,0xC0,0x28,0x50,0x02,0xC3,0x0C,0xD4,0xC1,0xC1,0x30, ++ 0xE8,0x43,0x0C,0xF1,0x84,0x0F,0xD8,0x97,0x49,0xE9,0x88,0x0E,0x48,0xE2,0xC2,0x0C, ++ 0xC5,0x10,0x0A,0x49,0xC4,0x0C,0x00,0x48,0xC0,0x08,0x1A,0x01,0x00,0x5F,0x00,0x01, ++ 0x00,0x2F,0x40,0x7C,0x04,0xBC,0xE0,0x90,0xE2,0x48,0xE4,0x00,0x95,0x05,0x16,0x02, ++ 0x9A,0xBE,0xE7,0xD8,0x90,0xDD,0xC6,0x04,0x17,0x1A,0x9C,0x86,0x00,0x01,0x00,0x2F, ++ 0x41,0x8C,0x01,0x4C,0xE5,0x68,0xE5,0xB0,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0xBE, ++ 0x48,0x62,0xC2,0x0C,0xC0,0x00,0x12,0x01,0x00,0x67,0x08,0x01,0x00,0x37,0xC0,0x1B, ++ 0x34,0xD8,0x74,0xD8,0x82,0x1B,0xE0,0x00,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xB6, ++ 0xE6,0x90,0x92,0x95,0xCC,0x04,0x10,0x52,0x9F,0x7E,0xEF,0xF5,0xAC,0xFD,0x87,0x1D, ++ 0x30,0x6A,0x30,0x01,0xBB,0x73,0xB9,0x73,0x37,0x42,0x81,0x01,0xC7,0x0B,0x10,0xE9, ++ 0x02,0x52,0x38,0x48,0x7A,0x48,0x06,0x48,0x18,0x52,0x80,0x13,0xC7,0x0B,0x10,0xD9, ++ 0x00,0x8A,0x80,0x0B,0x34,0x42,0x81,0x01,0x84,0x14,0xF0,0x03,0x78,0xB2,0x41,0x01, ++ 0x80,0x4E,0x00,0x01,0x57,0xAA,0x09,0xF9,0xA2,0x8A,0xE0,0x00,0x90,0x05,0x46,0x81, ++ 0x99,0xD6,0x87,0xF3,0x80,0xF3,0xAB,0x04,0x00,0x01,0xD8,0x1C,0xD0,0x34,0xC8,0x2C, ++ 0xBD,0xFF,0xEF,0xD7,0x36,0x62,0xA1,0x01,0xC8,0x03,0x47,0x51,0x98,0x36,0xA8,0x04, ++ 0x00,0x09,0xD8,0x1C,0xD0,0x34,0xC8,0x2C,0xBD,0xFF,0xEF,0x77,0xC4,0x14,0xF0,0x0B, ++ 0x49,0x01,0x80,0xD6,0x00,0x01,0x48,0x09,0x8B,0x5E,0xC0,0xD3,0x50,0x01,0x80,0x46, ++ 0x50,0x1A,0xC1,0x93,0x50,0x01,0x88,0x26,0x50,0x12,0xC1,0x93,0x50,0x01,0x88,0x06, ++ 0x00,0x09,0x40,0x01,0x87,0x2E,0xC8,0x13,0x50,0x01,0x95,0x36,0xE7,0x90,0x8A,0x13, ++ 0x07,0x1F,0xC8,0x13,0x50,0x51,0x90,0x06,0x8F,0x33,0xCF,0x13,0x50,0x51,0x98,0xE6, ++ 0x40,0x01,0x88,0x6E,0x48,0x09,0x88,0x16,0xF7,0x90,0x8A,0x13,0x01,0x47,0x00,0x99, ++ 0xEF,0x02,0x6A,0x4C,0x34,0x00,0x72,0x00,0x10,0x0A,0x94,0x0E,0xF7,0x90,0x8A,0x13, ++ 0xC0,0xC3,0x43,0x11,0x9D,0x16,0x00,0x01,0x88,0x03,0x07,0x37,0x40,0x09,0x88,0x26, ++ 0xCA,0x03,0x47,0x81,0x93,0x0E,0x00,0x21,0x89,0x03,0x37,0x4A,0xC7,0x1C,0xB8,0xFF, ++ 0xF8,0xDF,0x81,0x3D,0xE8,0x85,0x07,0x00,0x80,0x40,0x07,0x01,0x68,0xF0,0x07,0x00, ++ 0x28,0x60,0x00,0x00,0x60,0x20,0x02,0x00,0x00,0xC0,0x00,0x01,0x80,0xC0,0x06,0x01, ++ 0x00,0x40,0x00,0x01,0x00,0x48,0x00,0x01,0xAC,0xFD,0x87,0x3D,0xE0,0x84,0x30,0xB2, ++ 0x00,0x01,0x80,0x2C,0xD8,0x83,0x83,0x1C,0x60,0x8C,0x89,0x14,0xCA,0x44,0x18,0x0A, ++ 0x50,0xFA,0xC7,0x3C,0xC0,0x00,0xC4,0x48,0x8F,0x34,0x40,0xF2,0xC0,0x03,0x40,0x09, ++ 0x89,0x0E,0xE0,0x83,0x80,0x1C,0x00,0x01,0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48, ++ 0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2,0x98,0xC6,0x0F,0x01,0x00,0x09,0xD8,0x54, ++ 0xD0,0x44,0x80,0x07,0xD0,0xAF,0x2E,0x01,0x60,0x01,0x88,0x0E,0xE7,0x68,0x93,0x6D, ++ 0xF8,0x34,0x08,0x01,0x01,0x5F,0xC0,0xC3,0x1E,0x02,0x91,0x05,0x80,0xC3,0xD1,0x8C, ++ 0x10,0x82,0xCC,0x0E,0x19,0x02,0x85,0xC3,0xE2,0xF8,0xE3,0x48,0x90,0x4D,0xC6,0x1C, ++ 0x17,0x0A,0x9C,0x86,0x48,0x42,0xC7,0x3C,0xC0,0x00,0x82,0x24,0xD0,0x54,0x90,0x04, ++ 0x30,0x9A,0x01,0x11,0xD0,0x3C,0xC8,0x44,0x80,0x07,0xD8,0x47,0xD0,0x54,0x90,0x04, ++ 0x04,0x41,0xEA,0x0A,0x00,0x01,0x1C,0x0A,0x30,0x9A,0x11,0x01,0xC0,0x24,0x80,0x07, ++ 0xF6,0x27,0x05,0x29,0xE8,0x02,0x44,0x31,0x88,0x16,0x00,0x01,0x87,0x5D,0xE8,0x85, ++ 0xC1,0x1C,0xD0,0xC0,0x09,0x01,0x00,0x3F,0xD0,0x24,0x18,0x01,0xF0,0x9A,0xD6,0x14, ++ 0xD0,0xD0,0x94,0x95,0x68,0x01,0x88,0x2E,0x50,0xC1,0xE8,0xBE,0xC5,0x13,0x18,0x12, ++ 0x80,0x13,0x00,0x9F,0x50,0x99,0xE8,0x2E,0xC0,0x13,0x50,0x01,0x82,0x16,0xF0,0x90, ++ 0x80,0x13,0x00,0x5F,0x68,0x29,0x88,0x4E,0x58,0xE1,0xEE,0x3E,0xC0,0x13,0x50,0x01, ++ 0x88,0x26,0xD0,0x2C,0x50,0x01,0x88,0x0E,0x10,0x09,0x90,0x2C,0xD4,0x24,0xE0,0x90, ++ 0x92,0x24,0xE0,0x00,0xE6,0x48,0x92,0x4D,0xD4,0x1C,0x10,0x8A,0x9B,0xA6,0x46,0x20, ++ 0x6C,0x21,0xC8,0xCE,0xD0,0x54,0x90,0x04,0x30,0x9A,0x09,0x01,0x00,0x19,0xD0,0x3C, ++ 0x85,0x07,0xD0,0xE7,0x08,0x09,0x30,0x42,0xD8,0x54,0xD0,0x44,0x83,0x07,0xD0,0x07, ++ 0xC5,0x2C,0x38,0xDF,0xAC,0xFD,0x87,0x1D,0xF0,0x64,0x30,0x7A,0x33,0xEA,0xD8,0xC3, ++ 0x85,0x14,0x48,0xAA,0xC2,0x1C,0xC0,0x20,0x40,0x92,0xC5,0x03,0x40,0x09,0x88,0x0E, ++ 0xE0,0xC3,0x81,0x14,0x08,0x01,0x00,0x09,0xD8,0x2C,0xD0,0x6C,0x82,0x07,0xD0,0x47, ++ 0xD0,0x2C,0x90,0x04,0x30,0xDA,0x01,0x11,0xD0,0x1C,0xC8,0x6C,0x84,0x07,0xD0,0xB7, ++ 0xD0,0x2C,0x90,0x04,0x06,0x41,0xEA,0x0A,0x00,0x01,0x1C,0x0A,0x30,0xDA,0x11,0x01, ++ 0x30,0x02,0x81,0x07,0xF0,0x97,0xD1,0x2C,0x91,0x04,0x30,0xDA,0x08,0x01,0x00,0x19, ++ 0xD0,0x1C,0x80,0x07,0xD0,0x1F,0x0C,0x09,0x30,0x42,0xD8,0x2C,0xD0,0x6C,0x80,0x07, ++ 0xD4,0x3F,0x41,0xF2,0x00,0x44,0x01,0x01,0x00,0x84,0x09,0x01,0x00,0x77,0x00,0x01, ++ 0xF0,0x02,0x11,0x01,0xF4,0x52,0x15,0x12,0xE9,0x06,0x00,0x44,0x15,0x01,0xF0,0x92, ++ 0x10,0x12,0xD4,0x06,0x05,0x84,0xE1,0x20,0xE6,0x48,0x92,0x4D,0xC4,0x14,0x10,0x0A, ++ 0x98,0x6E,0x87,0x3D,0xEF,0x85,0xAF,0xBD,0x80,0x55,0xC4,0x5C,0xD8,0x03,0x86,0x24, ++ 0xCA,0x5C,0xD8,0x4B,0x8C,0x1C,0x50,0x52,0xCC,0x54,0xC0,0x48,0x8C,0x4C,0x48,0x4A, ++ 0xC0,0x4B,0x48,0x09,0x88,0x46,0xC8,0x24,0xE6,0x48,0x92,0x4D,0x88,0x24,0x80,0x3C, ++ 0xC0,0x5C,0xE0,0x03,0x80,0x1C,0x00,0x0F,0x00,0x01,0x80,0x3C,0xF8,0x3C,0xC0,0x5C, ++ 0x80,0x01,0x86,0x44,0x04,0x7F,0x4B,0x12,0x04,0x01,0x00,0x43,0xC0,0x5C,0xC8,0x4C, ++ 0xDB,0x03,0x1A,0xC2,0xC0,0x08,0x02,0x01,0x10,0xF9,0x01,0x1F,0x82,0x53,0xE0,0x48, ++ 0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2,0x9C,0xC6,0x27,0x01,0x31,0x2A,0x31,0x32, ++ 0x03,0xE7,0x40,0xC2,0x08,0x23,0x4E,0x2D,0xB8,0x0C,0x88,0x04,0x40,0x55,0x40,0x3E, ++ 0x5F,0x35,0xB8,0xFF,0xF8,0x7F,0xC3,0x44,0xC8,0x03,0x42,0x31,0x83,0x7E,0x33,0x5A, ++ 0x00,0xC1,0xF0,0xC2,0x40,0xE1,0xD1,0x1E,0x68,0x41,0x80,0x4E,0x18,0x62,0x05,0x1F, ++ 0x70,0x01,0x8C,0x0E,0x30,0x72,0x01,0x1F,0x41,0x68,0x1B,0x62,0x6F,0x01,0x88,0x06, ++ 0xC0,0x5C,0xC8,0x4C,0xDB,0x03,0x1A,0xC2,0xC0,0x08,0x02,0x01,0x10,0x01,0x00,0x1F, ++ 0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2,0x99,0xC6,0x37,0xAA, ++ 0x20,0x01,0x00,0x0F,0x1B,0xA2,0x41,0xB0,0x77,0x01,0x88,0xDE,0xC0,0x5C,0x60,0x04, ++ 0xC0,0x41,0x91,0x35,0x05,0xAF,0x18,0x62,0x46,0xD2,0x0A,0x23,0x48,0x2D,0xB8,0x0C, ++ 0x88,0x04,0x40,0x55,0x40,0x3E,0x58,0x35,0xB9,0xFF,0xFF,0xA7,0xC2,0x44,0xC8,0x03, ++ 0x42,0x31,0x80,0x6E,0x30,0x5A,0x03,0xA1,0xF5,0xC2,0x10,0x82,0xE9,0x06,0x18,0x62, ++ 0x40,0x68,0x6B,0x01,0x88,0x3E,0xC7,0x54,0x0E,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00, ++ 0xB3,0x23,0xE0,0xF8,0x90,0xFD,0xC7,0x24,0x14,0x3A,0x9C,0x66,0xF1,0x3C,0x00,0xA7, ++ 0xC3,0x54,0x08,0x59,0xCA,0x00,0x0C,0x48,0xC1,0x38,0xF2,0xC3,0x40,0x01,0x88,0x0E, ++ 0x01,0x09,0xB0,0xC3,0xF0,0xE3,0x29,0x01,0x01,0x01,0x00,0x0F,0xE7,0x68,0x93,0x6D, ++ 0x40,0x09,0x88,0x1E,0x60,0xF9,0x97,0x0E,0xE5,0x20,0x93,0x25,0x48,0xE2,0x01,0x01, ++ 0x00,0x43,0xAC,0x48,0x46,0xDA,0x09,0x23,0x20,0x00,0x67,0x10,0x00,0x0F,0x00,0xBF, ++ 0x40,0x48,0x32,0x82,0x17,0x42,0x80,0xDE,0x48,0x01,0xC9,0x06,0x08,0x01,0x89,0x04, ++ 0x90,0x0C,0x40,0x55,0x41,0x6E,0x30,0x8A,0xBA,0xFF,0xF7,0x77,0x40,0x01,0x80,0x0E, ++ 0x6E,0x29,0x98,0xDE,0xB3,0xE3,0xE1,0xB0,0x90,0xB5,0xC7,0x24,0x16,0x32,0x9C,0x3E, ++ 0x87,0x6D,0xE8,0x85,0xAC,0xBD,0x87,0x15,0x30,0x62,0x30,0xB2,0x48,0x2A,0x01,0x01, ++ 0x81,0x43,0x40,0x4A,0x40,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B,0x28,0x01,0x00,0x3F, ++ 0x09,0x09,0x30,0x9A,0x30,0x52,0x31,0x42,0x81,0x07,0xC8,0x57,0xE7,0x68,0x93,0x6D, ++ 0xDD,0x03,0x11,0x42,0xC1,0xA6,0x37,0x12,0x30,0x8A,0x01,0x11,0x84,0x07,0xC0,0x2F, ++ 0x31,0x92,0x31,0x0A,0xC7,0x14,0xB8,0xFF,0xF9,0x77,0x30,0x12,0x30,0x8A,0x01,0x01, ++ 0x83,0x07,0xC0,0xDF,0xE0,0x03,0x41,0x01,0x80,0xBE,0x69,0xB2,0x44,0x43,0x97,0x3D, ++ 0x4F,0x04,0x01,0x43,0x40,0x7A,0x08,0x09,0x81,0x0B,0x30,0x12,0x30,0x8A,0x01,0x11, ++ 0x83,0x07,0xC0,0x5F,0x30,0x1A,0xB1,0x04,0x08,0x01,0x00,0x09,0xD0,0x14,0x80,0x07, ++ 0xC8,0xAF,0xB2,0x04,0xD9,0x0B,0x37,0x1A,0x00,0x11,0xD0,0x14,0x82,0x07,0xC8,0x77, ++ 0x31,0x92,0x31,0x0A,0xC7,0x14,0xB8,0xFF,0xF1,0x37,0x37,0x12,0x30,0x8A,0x01,0x6F, ++ 0x60,0x20,0x02,0x00,0x00,0xD0,0x00,0x01,0x48,0xE0,0x06,0x00,0xF8,0xFB,0x07,0x00, ++ 0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x00,0x01,0x80,0x07, ++ 0xC0,0x27,0x42,0x5A,0x08,0x01,0x80,0x0B,0x01,0x7B,0x37,0x1A,0xB0,0x04,0x08,0x01, ++ 0x00,0x11,0xD0,0x14,0x81,0x07,0xC8,0x57,0x31,0x12,0x31,0x8A,0x00,0x11,0x80,0x07, ++ 0xC0,0xA7,0x51,0x22,0x40,0x83,0x08,0x11,0x18,0x42,0x04,0x83,0x87,0x2D,0xE8,0x85, ++ 0x00,0xD0,0x00,0x01,0x18,0x00,0x04,0x42,0xA8,0x85,0x31,0x12,0x92,0x01,0x46,0x8C, ++ 0x80,0x01,0xC7,0x1B,0x32,0xD8,0x72,0xD8,0x87,0x1B,0x58,0xE2,0x41,0xE3,0x30,0x20, ++ 0xA2,0x16,0x40,0xE3,0x3F,0x20,0xAB,0xE6,0x58,0xCA,0x27,0x41,0x00,0xE3,0x44,0xE3, ++ 0x28,0xF9,0xAF,0x19,0x18,0x62,0x01,0xE3,0xC7,0x23,0x48,0x20,0x8A,0x1E,0xF0,0x48, ++ 0x20,0x48,0x60,0x48,0x88,0xC6,0x4F,0x01,0x88,0x36,0x40,0xC3,0x08,0x81,0x18,0x42, ++ 0x07,0xC3,0x00,0xF9,0x82,0x89,0x04,0x84,0xEF,0x85,0xA9,0x85,0x46,0x63,0x42,0x5B, ++ 0xDF,0xAB,0x72,0x62,0xC0,0xB3,0x71,0x09,0x8E,0x16,0x48,0x63,0x50,0x5B,0xE2,0xAB, ++ 0x41,0x01,0x88,0x0E,0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2, ++ 0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33,0xC1,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33, ++ 0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3,0x1B,0x82,0x35,0x32, ++ 0x00,0x83,0x41,0x73,0xC4,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90, ++ 0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85,0x41,0x09,0x88,0x0E,0x10,0x01,0x00,0xE7, ++ 0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33, ++ 0xC5,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32, ++ 0x40,0x83,0xC1,0xF3,0x1B,0x82,0x35,0x32,0x00,0x83,0x41,0x73,0xC0,0xC3,0x18,0x32, ++ 0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85, ++ 0x41,0x11,0x88,0x0E,0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2, ++ 0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33, ++ 0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3,0x1B,0x82,0x31,0x32, ++ 0x00,0x83,0x41,0x73,0xC4,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90, ++ 0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85,0x47,0x19,0x88,0xE6,0x10,0x01,0x00,0xE7, ++ 0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33, ++ 0xC5,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32, ++ 0x40,0x83,0xC1,0xF3,0x1B,0x82,0x31,0x32,0x00,0x83,0x41,0x73,0xC0,0xC3,0x18,0x32, ++ 0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85, ++ 0xAA,0x85,0x47,0xE3,0x05,0xB0,0xCC,0x20,0x45,0xEB,0xC6,0x68,0x40,0x09,0x88,0x26, ++ 0x45,0xE3,0xC8,0x20,0x44,0xDB,0xC4,0xE8,0x04,0x3F,0x78,0xD2,0xC0,0xFB,0x79,0x09, ++ 0x8E,0x1E,0x48,0xE3,0xCA,0x20,0x55,0xDB,0xC1,0xE8,0x44,0x13,0xF9,0xA0,0xC0,0x5B, ++ 0x40,0x09,0x88,0x76,0x48,0x01,0x88,0x66,0x44,0x83,0x1A,0xC2,0x04,0x83,0x42,0x83, ++ 0x1C,0xC2,0x04,0x83,0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83,0x18,0xC2,0x00,0x83, ++ 0xE8,0x85,0x4F,0x09,0x8A,0x66,0x40,0x83,0x1A,0xC2,0x04,0x83,0x44,0x83,0x1C,0xC2, ++ 0x00,0x83,0x44,0x83,0x18,0xC2,0x04,0x83,0x40,0x03,0x19,0xC2,0x07,0x03,0xE9,0x85, ++ 0x48,0x11,0x88,0x66,0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83,0x18,0xC2,0x04,0x83, ++ 0x40,0x83,0x1A,0xC2,0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83,0xE8,0x85,0x4F,0x19, ++ 0x89,0xE6,0x47,0x03,0x19,0xC2,0x04,0x03,0x44,0x83,0x18,0xC2,0x02,0x83,0x40,0x83, ++ 0x1A,0xC2,0x04,0x83,0x40,0x83,0x1C,0xC2,0x07,0x83,0xEC,0x85,0xA8,0xFD,0xF7,0x4C, ++ 0x30,0x62,0x2C,0x01,0x4D,0x93,0x49,0x8B,0x32,0x72,0xDC,0xE3,0x33,0x3A,0x49,0x8A, ++ 0xC0,0x4B,0x48,0x09,0x89,0x0E,0x50,0x93,0xE0,0xE3,0x40,0x19,0x80,0x96,0x31,0x79, ++ 0x49,0x5A,0x13,0xB0,0x40,0x11,0x88,0xB6,0x32,0x02,0x1B,0x3A,0x58,0x52,0xC3,0x14, ++ 0xC1,0x00,0xC6,0xC0,0x33,0x9A,0x33,0x2A,0xEA,0xDA,0x0A,0x5B,0x08,0x01,0x00,0x3F, ++ 0xC1,0x1B,0x18,0x9A,0x41,0xAB,0x00,0x5B,0xEA,0x90,0xE0,0x00,0xE6,0x48,0x92,0x4D, ++ 0x17,0x0A,0x9D,0xAE,0xE8,0xFD,0x47,0x01,0x88,0x8E,0x18,0x01,0x12,0x5B,0x46,0xDA, ++ 0x45,0x33,0x40,0xB0,0x00,0xB0,0x05,0x33,0x00,0x1B,0x02,0x5B,0x40,0x0B,0x18,0x81, ++ 0x18,0xCA,0x04,0x0B,0x44,0x0B,0x18,0x01,0x18,0xCA,0x00,0x0B,0x00,0x17,0x40,0x09, ++ 0x89,0x06,0x30,0xAA,0x00,0x01,0x00,0x27,0x40,0x8B,0x00,0x6B,0xEA,0x90,0xE0,0x00, ++ 0x95,0x05,0x16,0x02,0x9F,0xC6,0xEF,0xFD,0x3B,0x82,0xAB,0x85,0x4A,0xA3,0xD8,0xEB, ++ 0x33,0x70,0x72,0xB0,0x48,0x5A,0xC2,0x4B,0x48,0x09,0x88,0x0E,0x50,0xA3,0xE0,0xEB, ++ 0x08,0x01,0x00,0x3F,0x42,0x13,0x41,0x93,0x00,0x92,0x07,0x14,0xEC,0x20,0xE1,0x00, ++ 0xE6,0x48,0x92,0x4D,0x17,0x4A,0x9D,0xAE,0xEB,0x85,0xAB,0xC5,0x30,0x2A,0x30,0xB2, ++ 0x61,0xF2,0x41,0x03,0x14,0x01,0x1C,0x82,0x01,0x03,0x41,0x03,0x10,0x81,0x18,0x82, ++ 0x01,0x03,0x41,0x03,0x10,0x09,0x18,0x82,0x07,0x03,0xE1,0x53,0x00,0xF9,0x87,0x81, ++ 0x19,0x12,0x40,0xBA,0x10,0x13,0x16,0x99,0x00,0x13,0x13,0x41,0x04,0x13,0x14,0xD9, ++ 0xE8,0x92,0x52,0x01,0x80,0x16,0x10,0xC9,0x00,0x13,0x00,0x0F,0x10,0x89,0x00,0x13, ++ 0x31,0x52,0x30,0x5A,0x08,0x01,0x00,0x09,0xB7,0x04,0xB8,0xFF,0xF9,0x7F,0x33,0x52, ++ 0x30,0x8A,0x01,0x11,0xBB,0xFF,0xF7,0xCF,0x42,0x03,0x3B,0x00,0xAB,0xE6,0xEF,0xC5, ++ 0xAC,0x9D,0x87,0x8D,0xCA,0x94,0xC8,0x4B,0x88,0x84,0xE0,0x94,0xA7,0x01,0xD2,0x1B, ++ 0xD8,0x0B,0x89,0x04,0xCA,0x94,0xD8,0x6B,0x30,0x0A,0x88,0x71,0x30,0x62,0xCC,0x94, ++ 0x30,0x01,0xE8,0x4B,0x48,0x09,0x88,0x56,0x08,0x01,0x00,0x27,0xC5,0x38,0x9A,0xF3, ++ 0xA2,0x32,0xE2,0x48,0x90,0x4D,0xD2,0x94,0xDC,0x93,0x12,0x52,0xE0,0xB6,0x57,0xDA, ++ 0x04,0xB3,0x02,0xB3,0x00,0xB3,0x0E,0x01,0x18,0x4A,0x06,0x8B,0xCA,0x94,0xD8,0x4B, ++ 0xB0,0x8B,0x08,0x01,0x50,0xAA,0x30,0x01,0x05,0x78,0xC4,0xF8,0x0A,0xF3,0xC1,0x90, ++ 0xB2,0xB3,0xE2,0x48,0x90,0x4D,0x4A,0x11,0xD8,0xA6,0xCF,0x94,0xE8,0x4B,0x48,0x29, ++ 0xCD,0xF6,0x03,0x48,0xC3,0x48,0x00,0x50,0xC0,0x70,0x54,0x6A,0xC0,0xB0,0xB5,0x14, ++ 0xC0,0x48,0x8C,0x0C,0x30,0x12,0x33,0x32,0xB0,0xE1,0x08,0x01,0x88,0x34,0x48,0x4A, ++ 0x88,0x6C,0x88,0x64,0x30,0x32,0x04,0x01,0x32,0x22,0x04,0x97,0x18,0x00,0x04,0x42, ++ 0x00,0x01,0x00,0x42,0x00,0xD0,0x00,0x01,0x60,0x20,0x02,0x00,0x80,0x40,0x07,0x01, ++ 0x48,0xE0,0x06,0x00,0x78,0xF8,0x07,0x00,0xC8,0x14,0x00,0x01,0xF0,0x42,0xF8,0x0C, ++ 0x0B,0x01,0xF0,0xCA,0x32,0x7A,0xD0,0x08,0x97,0x4D,0x48,0xF9,0xEF,0x06,0x08,0xF9, ++ 0xCB,0x38,0x86,0xF8,0x78,0xF9,0xEF,0x06,0x3B,0xF9,0x37,0x82,0x82,0x3B,0xE0,0x00, ++ 0x30,0x32,0xC4,0xBB,0x10,0xFA,0x9C,0x46,0x10,0xCA,0xDC,0x36,0x46,0x84,0xD9,0x48, ++ 0xC0,0x00,0x92,0x05,0x04,0x84,0x81,0x08,0x04,0x37,0x10,0xCA,0xDC,0x16,0x00,0x78, ++ 0x00,0xBC,0x01,0x0F,0x39,0x01,0x00,0xBC,0x10,0xCA,0xDC,0x0E,0x38,0x09,0xB8,0x34, ++ 0x43,0x78,0x2B,0x3A,0xE8,0x26,0xF8,0x6C,0x10,0x7A,0xEC,0x2E,0x88,0x6C,0x00,0x1F, ++ 0xFC,0x64,0x10,0x7A,0xE8,0x06,0x88,0x64,0x82,0x8B,0xE0,0x90,0xE0,0xB0,0xC5,0x14, ++ 0xE0,0x00,0x84,0x14,0xC4,0x0C,0xE0,0x00,0x83,0x0C,0x30,0x02,0xE2,0x00,0x92,0x05, ++ 0x35,0x22,0x2C,0x62,0xD8,0xC6,0xC5,0x34,0x40,0x01,0x80,0x8E,0x08,0x01,0x00,0x01, ++ 0x80,0x5C,0xC0,0x04,0xC2,0x00,0x46,0x00,0x80,0x7C,0xC0,0x04,0x30,0x00,0x72,0x00, ++ 0x80,0x74,0x00,0x01,0x30,0x22,0x84,0x2C,0x80,0x24,0x80,0x1C,0xF0,0x90,0x02,0x07, ++ 0x03,0x1F,0xF5,0x40,0x94,0x05,0x32,0x32,0x03,0xFF,0x31,0x02,0x04,0x00,0x32,0x22, ++ 0xC2,0x2C,0x00,0x00,0x80,0x2C,0xC0,0x24,0x00,0x00,0x82,0x24,0xC2,0x1C,0x00,0x00, ++ 0x83,0x1C,0x40,0x40,0x28,0x82,0xEB,0x26,0xC0,0x83,0xF0,0x6C,0xD8,0x00,0x84,0x83, ++ 0x00,0x1F,0xC0,0x83,0xF4,0x64,0xD8,0x00,0x80,0x83,0xC0,0x83,0x73,0x3D,0x30,0xBA, ++ 0xA8,0x82,0xC7,0x83,0x10,0xC2,0xDC,0xDE,0xE2,0x48,0x92,0x4D,0xF1,0x5C,0xC0,0xB0, ++ 0x90,0xB5,0xB1,0x5C,0x30,0x32,0x3B,0x09,0x1D,0xF2,0x31,0xA2,0xF5,0x7C,0x10,0x82, ++ 0xD8,0x76,0xF0,0x2C,0x18,0xF2,0xB1,0x2C,0xF5,0x04,0x10,0x82,0xD8,0x46,0xF0,0x24, ++ 0x18,0xF2,0xB1,0x24,0xF5,0x74,0x10,0x82,0xD8,0x16,0xC0,0x1C,0x18,0xC2,0x81,0x1C, ++ 0xF3,0x90,0x32,0x82,0xF2,0x00,0x92,0x05,0x33,0x32,0x34,0x82,0x45,0x01,0xD0,0xE6, ++ 0x42,0xE2,0xB7,0x0B,0xD0,0x50,0xB3,0x13,0x36,0x12,0x1B,0x92,0x03,0x13,0x30,0x12, ++ 0x08,0x13,0xD0,0x2C,0x00,0x13,0xD2,0x24,0x00,0x13,0xD4,0x1C,0x00,0x13,0x36,0x01, ++ 0x00,0xA7,0xC1,0x5C,0x86,0x07,0xE8,0xA7,0x90,0x05,0x80,0x5C,0x4D,0x8A,0x07,0x80, ++ 0xC0,0x00,0x4A,0x13,0x40,0x3D,0x08,0x01,0x1C,0x01,0x30,0xF2,0x30,0xE2,0x04,0xCF, ++ 0x38,0x98,0x86,0x7E,0xC0,0x1B,0xF8,0x5C,0xD8,0xD8,0x96,0xDD,0x58,0x01,0xE8,0x36, ++ 0x83,0x1B,0x20,0x9A,0x94,0xDD,0x36,0xF2,0xE2,0x48,0x92,0x4D,0x00,0x27,0x18,0x01, ++ 0x80,0x1B,0x00,0x0F,0x18,0x01,0x80,0x1B,0x42,0x90,0xE2,0x00,0x32,0x1A,0xE3,0xD8, ++ 0x94,0xDD,0x32,0xE2,0x2F,0x62,0xDD,0x1E,0xE3,0xB0,0x93,0xB5,0x30,0x82,0x83,0x5C, ++ 0x45,0xE2,0x06,0x98,0xC0,0xD8,0x08,0xD3,0xCA,0x00,0xB4,0x0B,0x48,0x21,0xD8,0x0E, ++ 0x76,0x09,0xD8,0x36,0x06,0x01,0x50,0xBA,0x04,0x08,0xC4,0x58,0xE4,0x08,0x02,0x70, ++ 0xC0,0xB0,0x4D,0xEB,0x4D,0xB3,0x19,0xAA,0x08,0xEB,0xC0,0x80,0xF4,0x1B,0xF2,0x2B, ++ 0xDA,0xD8,0xB2,0x1B,0x90,0x45,0x42,0x09,0xD8,0x76,0x07,0x09,0xA6,0x03,0x43,0x6A, ++ 0x0E,0x19,0x40,0x13,0x50,0x01,0x80,0x16,0x03,0x29,0xA0,0x0B,0x04,0xF7,0x40,0x13, ++ 0x50,0x01,0x80,0x16,0x03,0x21,0xA0,0x0B,0x02,0xC7,0x40,0x0B,0x48,0x01,0x80,0x1E, ++ 0x00,0x19,0x08,0x11,0xA0,0x0B,0x03,0x8F,0x48,0x03,0x40,0x01,0x88,0x26,0xC0,0x94, ++ 0x86,0x01,0xCE,0x03,0x40,0x51,0x98,0x0E,0x00,0x11,0x00,0x3F,0xC1,0x94,0x80,0x01, ++ 0xE0,0x03,0x44,0x01,0x80,0x0E,0x00,0x11,0x00,0x07,0x00,0x09,0xE4,0x0B,0xE3,0x50, ++ 0xA3,0x13,0xDD,0x13,0x38,0x90,0xA2,0x0E,0xF3,0x48,0xA2,0x0B,0xE8,0x0B,0x13,0x29, ++ 0x10,0x0A,0x94,0x0E,0xA8,0x13,0x01,0xEF,0x10,0x0A,0xCC,0x46,0x40,0x09,0x88,0x16, ++ 0x09,0x81,0xAF,0x0B,0x00,0xB7,0xD0,0x48,0x01,0x52,0xAC,0x13,0x00,0x97,0x40,0x19, ++ 0xC8,0x0E,0x08,0x19,0x02,0x07,0x90,0x0D,0xE8,0x13,0x51,0x01,0x82,0x16,0xF0,0x90, ++ 0xA8,0x13,0x01,0x3F,0xD2,0x94,0xF0,0x48,0xCA,0x93,0x1C,0x52,0xCA,0x84,0xC0,0x88, ++ 0xD0,0x94,0x88,0x8B,0xA8,0x03,0x83,0x9D,0xEF,0x85,0xAF,0xBD,0x80,0x6D,0x34,0x6A, ++ 0xD9,0x63,0x33,0x42,0x80,0x01,0x82,0x64,0xD0,0x03,0x84,0x3C,0xC2,0x64,0xD8,0x03, ++ 0x30,0x00,0xA8,0x1E,0x02,0xD9,0xEC,0x02,0x40,0x01,0x80,0xA6,0xC5,0x6C,0x00,0x08, ++ 0xC3,0x40,0x00,0x08,0x52,0xC2,0xC4,0x08,0xC4,0x48,0xC4,0x10,0x00,0x01,0x18,0x01, ++ 0x00,0x2F,0x00,0x5C,0x04,0x9C,0xE0,0x48,0xE2,0x90,0xE4,0x00,0x95,0x05,0x12,0x02, ++ 0xD8,0xBE,0x87,0x85,0xEB,0x85,0x07,0x59,0xCA,0x6C,0x08,0x00,0xC4,0x40,0x70,0x7A, ++ 0xF7,0x03,0x08,0x83,0xD0,0x7C,0x90,0x04,0x30,0x5A,0x09,0x01,0x00,0x11,0xD0,0x6C, ++ 0xBB,0xFF,0xEF,0xE7,0x42,0x4A,0x84,0x01,0x43,0x0B,0x30,0x5A,0x09,0xCC,0x5C,0x8B, ++ 0x0B,0xCC,0x5E,0x8B,0x15,0xCC,0x58,0x8B,0x17,0xCC,0x42,0x8B,0x14,0xCC,0x4C,0x22, ++ 0x46,0x53,0x10,0xD4,0x48,0x93,0x1F,0xD4,0x17,0x89,0x00,0x93,0x13,0x19,0x18,0x93, ++ 0x40,0x53,0x18,0x11,0x18,0xD2,0x04,0x53,0x40,0x0B,0x18,0xCA,0x01,0x0B,0x30,0x42, ++ 0xE9,0x4B,0x81,0x01,0x80,0x5C,0x48,0x09,0x8D,0x5E,0x6A,0x44,0x81,0x14,0x30,0x8A, ++ 0x5E,0x43,0x94,0x35,0xB0,0x0C,0x00,0x01,0x80,0x04,0xD0,0x6C,0x4F,0x92,0x03,0x00, ++ 0xC2,0x00,0xC4,0x00,0x83,0x54,0x40,0x8A,0x18,0x33,0x0A,0x01,0x37,0x42,0xB9,0xFF, ++ 0xE0,0x5F,0xF9,0x54,0xC1,0x64,0x30,0x5A,0xD1,0x0B,0x32,0xC2,0xD7,0x7C,0xB8,0xFF, ++ 0xEB,0x67,0x4C,0x62,0x10,0x01,0x00,0x01,0x02,0x67,0x00,0x18,0x37,0xE2,0xF4,0xDA, ++ 0x10,0x5A,0xD4,0x0E,0x33,0x0A,0xD3,0xCA,0x10,0x9A,0xEC,0x0E,0x35,0x12,0xD3,0xD2, ++ 0xE2,0x00,0x92,0x05,0x17,0x02,0xDD,0x86,0xC4,0x14,0xE0,0x00,0x10,0x0A,0x9C,0x36, ++ 0xC0,0x04,0x40,0x01,0x8B,0x9E,0x40,0x80,0x40,0x08,0xC2,0x70,0x00,0x3F,0xC0,0x14, ++ 0xF4,0x00,0x14,0x12,0xE0,0x5E,0x00,0x09,0x83,0x04,0xE0,0xB0,0x90,0xB5,0x77,0x01, ++ 0x80,0x16,0xC0,0x0C,0x16,0x32,0x9C,0x36,0x70,0x01,0x88,0x06,0x30,0x09,0xC0,0x5C, ++ 0x90,0x33,0xC0,0x5C,0xD2,0x0B,0x40,0x8A,0x18,0x0B,0x32,0x01,0x36,0x42,0x81,0x01, ++ 0x81,0x4C,0x80,0x01,0x83,0x44,0x00,0x37,0xC4,0x3C,0x10,0x32,0xD0,0x6E,0xC0,0x44, ++ 0xC0,0x03,0xC8,0x44,0x32,0x00,0x72,0x00,0x82,0x43,0x40,0x42,0x0C,0x41,0x00,0x0B, ++ 0x47,0x0B,0x10,0xF9,0x90,0x21,0x18,0x8A,0x00,0x0B,0xC8,0x6C,0x02,0x00,0xC5,0x08, ++ 0x02,0x00,0x53,0x0A,0xC4,0x40,0xC0,0x00,0xC0,0x48,0x74,0x01,0x88,0x66,0x10,0x01, ++ 0x78,0x02,0x02,0x37,0x18,0x01,0x00,0x1C,0x04,0x7C,0xE0,0x00,0xE2,0x48,0xE4,0x90, ++ 0x95,0x95,0x12,0x12,0xD9,0xB6,0x07,0x07,0xDF,0x6C,0x00,0x10,0xC1,0x90,0x5E,0xB2, ++ 0xC4,0x90,0x36,0xA2,0x18,0x01,0x00,0x9F,0x30,0x3A,0x13,0x01,0xF0,0xD2,0x3D,0x01, ++ 0xFC,0x3A,0x16,0xBA,0xD0,0x06,0x00,0x14,0x3E,0x01,0xF8,0x7A,0x10,0xBA,0xEC,0x06, ++ 0x04,0x54,0xE0,0x00,0xE3,0x48,0x34,0x12,0xE4,0x90,0x34,0xA2,0xE2,0xD8,0x92,0xDD, ++ 0x17,0x1A,0xDD,0x4E,0xC4,0x3C,0x10,0x32,0x80,0x06,0xC1,0x44,0xC6,0x03,0x48,0x00, ++ 0x88,0x1E,0xC0,0x4C,0xC8,0x03,0x42,0x31,0x88,0xBE,0xC7,0x4C,0xC8,0x03,0x42,0x31, ++ 0x89,0x26,0x40,0x12,0x40,0x0B,0x10,0x81,0x18,0x8A,0x00,0x0B,0xCF,0x6C,0x00,0x00, ++ 0xC0,0x00,0x4A,0xEA,0xC0,0x00,0xCA,0x64,0x32,0x5A,0xD1,0x4B,0xD7,0x7C,0xB8,0xFF, ++ 0xE3,0x67,0xE7,0xB0,0x90,0xB5,0xC3,0x3C,0x14,0x32,0xEC,0xAE,0x43,0xBA,0x30,0x5A, ++ 0x4A,0xCC,0x84,0x01,0x00,0x0B,0x40,0xAA,0x48,0xCC,0x1E,0x0B,0x52,0xCC,0x18,0x0B, ++ 0x54,0xCC,0x1A,0x0B,0x56,0xCC,0x04,0x0B,0x4E,0x8A,0x50,0xD4,0x00,0x53,0x58,0xCC, ++ 0x0F,0x0B,0x36,0xB7,0xAA,0x85,0xD8,0xE3,0x1A,0x0A,0x03,0x48,0xC5,0x50,0x0C,0x49, ++ 0x02,0x48,0xC4,0x88,0xE8,0xD3,0x50,0x11,0xC0,0x4E,0x10,0x01,0x00,0x2F,0x40,0x1C, ++ 0x04,0x5C,0xE0,0x48,0xE2,0x00,0xE4,0x90,0x95,0x95,0x12,0x12,0xD8,0xBE,0x17,0x01, ++ 0x00,0x87,0x00,0x00,0x80,0x40,0x07,0x01,0x48,0xE0,0x06,0x00,0x00,0x01,0x00,0x42, ++ 0x18,0x00,0x04,0x42,0xF8,0xFB,0x07,0x00,0x40,0x1C,0x00,0x5C,0xE4,0x00,0xE4,0x48, ++ 0xE2,0x90,0x92,0x95,0x17,0x12,0xDD,0xBE,0xEF,0x85,0xA8,0x85,0x30,0x6A,0xF0,0x2C, ++ 0x30,0x22,0x30,0x8A,0x31,0xFA,0x30,0xC2,0xB9,0xFF,0xDF,0xB7,0x31,0xDA,0x31,0x92, ++ 0x31,0x4A,0x31,0x02,0xBC,0xFF,0xE7,0xCF,0xE8,0x85,0x37,0x0A,0x8D,0x01,0x86,0x01, ++ 0x02,0x5F,0xC8,0x5B,0x58,0x31,0x88,0x46,0x40,0xFA,0x47,0x0B,0x10,0x81,0x18,0x8A, ++ 0x00,0x0B,0x40,0x0B,0x18,0x8A,0x00,0x0B,0x3E,0x82,0xCB,0x1B,0x5F,0x01,0x88,0x86, ++ 0x38,0x82,0xAB,0x85,0xDA,0x5B,0xD8,0x4B,0x1F,0x5A,0x4A,0xC2,0xC7,0x08,0x52,0xC2, ++ 0xC0,0x00,0x14,0x01,0x00,0x27,0x40,0x24,0x04,0x64,0xE0,0x00,0xE2,0x48,0xE4,0x90, ++ 0x17,0xD2,0x9C,0xC6,0xEF,0x85,0xA8,0xBD,0x80,0x15,0x34,0x62,0x37,0xBA,0xD8,0x33, ++ 0xE8,0x03,0x09,0x01,0x18,0x4A,0x2E,0x01,0x40,0x29,0x90,0x16,0x1F,0x0B,0x1D,0x2B, ++ 0x07,0x6F,0x00,0x09,0xEA,0x02,0x38,0x00,0xAF,0x26,0x50,0x52,0x58,0x03,0x1F,0x82, ++ 0x18,0x03,0x05,0x27,0x57,0x3A,0x5F,0x03,0x18,0x92,0x1E,0x82,0x1D,0x03,0x1D,0x0B, ++ 0x30,0x0A,0xC1,0x14,0xBC,0xFF,0xE7,0xE7,0x25,0x2B,0x59,0x03,0x28,0x01,0x00,0x17, ++ 0x43,0x00,0xE2,0x68,0x96,0x6D,0x3F,0x08,0x8D,0x0E,0x10,0xAA,0x9B,0xC6,0xAF,0x2B, ++ 0x73,0xCA,0x4E,0x04,0x00,0x83,0xC7,0x14,0x0A,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00, ++ 0xF7,0x03,0x08,0x83,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBC,0xFF,0xDF,0x87, ++ 0x30,0x1A,0xB9,0x04,0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD8,0xFF,0x06,0x09, ++ 0xA7,0x01,0x8D,0x03,0x48,0x82,0x46,0x43,0x10,0x11,0x18,0x82,0x00,0x43,0x00,0x41, ++ 0x01,0x83,0x45,0x83,0x08,0xF9,0x8F,0x19,0x19,0x42,0x00,0x83,0x87,0x2D,0xE8,0x85, ++ 0x3F,0x82,0xAB,0xC5,0xD8,0x53,0x90,0x04,0xDC,0x53,0x32,0xB2,0xE9,0x53,0x54,0x91, ++ 0x9E,0xBE,0x12,0x31,0xE0,0x92,0x52,0x01,0x8E,0x9E,0x52,0x02,0xC0,0x28,0x34,0x12, ++ 0x91,0xE1,0x19,0xC1,0x8E,0x01,0xF4,0x1A,0xE8,0x63,0x3A,0x11,0x10,0x1A,0xDD,0x16, ++ 0xD8,0xD8,0x38,0x1C,0xA9,0x7B,0x1E,0xD1,0xEE,0x63,0xF4,0x1A,0x15,0x32,0x13,0x9A, ++ 0xE0,0x16,0xC8,0xD8,0x38,0x1C,0xB2,0x7B,0x30,0x01,0x38,0x01,0x1C,0x01,0x30,0xE2, ++ 0x00,0x27,0x21,0x01,0x00,0xE7,0x18,0x01,0xF0,0x5A,0x5F,0x01,0xED,0x4E,0x10,0x9A, ++ 0xE8,0x06,0x30,0xF2,0xE8,0x5B,0x5E,0x01,0x80,0x76,0x40,0x9C,0xF0,0xD8,0x02,0x9C, ++ 0x00,0x57,0x58,0x01,0xD5,0x46,0x10,0xDA,0xD0,0x06,0x30,0xFA,0xF0,0x5B,0x58,0x01, ++ 0x80,0x16,0x40,0x9C,0xE0,0xD8,0x02,0x9C,0xE4,0x68,0xE5,0x90,0xE7,0x20,0x93,0x25, ++ 0x2F,0xA2,0x9B,0x06,0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x36,0xE2,0xE5,0x04,0x28,0x22, ++ 0x98,0xBE,0x7E,0x14,0xC8,0x90,0x3C,0x14,0x7E,0x14,0xCA,0x90,0x3E,0x14,0xEA,0x43, ++ 0x40,0x01,0x80,0x0E,0xF6,0x00,0xAA,0x43,0xF0,0x43,0x40,0x01,0x82,0x0E,0xF0,0x00, ++ 0xB7,0x43,0xE8,0xC5,0xAC,0xBD,0x87,0x15,0x30,0x62,0x30,0xBA,0xEF,0x2B,0xDB,0x33, ++ 0xDB,0x03,0x1B,0x42,0x00,0x08,0xC2,0x14,0xC4,0x40,0x48,0x8A,0xC0,0x00,0x82,0x0C, ++ 0x37,0x02,0x81,0x01,0xC4,0x0B,0x10,0x01,0x18,0x8A,0x80,0x0B,0x00,0x21,0xEE,0x02, ++ 0x44,0x01,0x80,0x1E,0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42,0xBF,0xFF,0xD7,0xC7, ++ 0x30,0x1A,0xB9,0x04,0x08,0x01,0x00,0x19,0xD7,0x14,0xB8,0xFF,0xDA,0x3F,0x02,0x41, ++ 0xE9,0x0A,0x30,0x1A,0x30,0xD2,0xC1,0x0C,0xBC,0xFF,0xDF,0x7F,0x31,0x1A,0x31,0x4A, ++ 0xD0,0x14,0xC0,0x0C,0xBD,0xFF,0xF7,0xB7,0x50,0x02,0x1C,0x09,0xC0,0x83,0x40,0x01, ++ 0x8B,0x5E,0xE0,0x68,0x95,0x6D,0x5F,0x0B,0x03,0x0F,0xE0,0x68,0x90,0x6D,0x37,0xC2, ++ 0x00,0x42,0x15,0x0A,0x8D,0x0E,0x10,0xAA,0x99,0xBE,0x37,0x82,0x74,0x92,0x13,0x2A, ++ 0x93,0xE6,0xA8,0x2B,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBE,0xFF,0xD7,0x47, ++ 0x30,0x1A,0xB9,0x04,0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD8,0xBF,0xC0,0x14, ++ 0x0A,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00,0xF7,0x03,0x08,0x83,0x05,0x41,0x00,0x83, ++ 0x47,0x83,0x09,0xF9,0x88,0x19,0x18,0x42,0x01,0x83,0x39,0xBF,0xE1,0x0B,0x31,0x02, ++ 0x80,0x01,0x4D,0x01,0x86,0x1E,0xC9,0x0B,0x49,0x09,0x88,0x06,0x0E,0x11,0x88,0x0B, ++ 0xA8,0x2B,0x83,0x9B,0x4F,0x04,0x01,0x83,0x50,0x0A,0xCB,0x14,0xDC,0x03,0xC1,0x48, ++ 0xE7,0x02,0x0A,0x83,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBC,0xFF,0xD7,0xC7, ++ 0x30,0x1A,0xB9,0x04,0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD0,0x3F,0x07,0x41, ++ 0x01,0x83,0x45,0x83,0x08,0xF9,0x8F,0x19,0x19,0x42,0x00,0x83,0x38,0x77,0x08,0x01, ++ 0x88,0x0B,0x86,0x8B,0x3F,0x57,0xA8,0x85,0x84,0x9D,0x34,0x22,0x33,0x6A,0xD8,0x73, ++ 0xD8,0x43,0x81,0x34,0x31,0x12,0x93,0xE1,0x92,0x94,0x48,0x72,0x32,0x02,0xC3,0x18, ++ 0x4B,0x32,0x22,0x0A,0x8B,0x8C,0xC8,0x43,0x00,0x00,0x82,0x1C,0x00,0x01,0x80,0x14, ++ 0x37,0x42,0x81,0x01,0x82,0x84,0xC0,0x03,0x5C,0x7B,0x35,0x32,0x3F,0x20,0x5A,0x43, ++ 0x18,0x3A,0x60,0x01,0xD1,0x46,0x40,0xFA,0x18,0x3A,0xB8,0x0C,0x37,0x82,0x23,0xD9, ++ 0x00,0x02,0xE1,0x84,0x80,0x03,0x03,0x47,0x46,0xD2,0x19,0x02,0x18,0x3A,0xB8,0x0C, ++ 0x30,0x82,0x23,0x21,0x18,0x02,0xE1,0x84,0x80,0x03,0x3B,0x01,0x19,0x7B,0x37,0x42, ++ 0x80,0x01,0x85,0x7C,0xC0,0x03,0x84,0x54,0xC0,0x7C,0x20,0x09,0xB8,0x22,0xA0,0x4C, ++ 0x34,0x42,0x81,0x01,0x86,0x74,0x18,0x3B,0xB8,0x44,0xC0,0x74,0x18,0x3B,0xBC,0x3C, ++ 0x31,0x42,0x81,0x01,0x84,0x6C,0xA0,0x3B,0xCA,0x43,0x45,0x00,0x86,0x2C,0x00,0x01, ++ 0xFB,0x22,0x82,0x00,0x81,0x24,0xE8,0x43,0x40,0x29,0xC0,0xBE,0x03,0x01,0x30,0x22, ++ 0x3B,0x04,0x39,0x04,0x20,0x01,0x00,0x77,0x00,0x01,0x00,0x47,0x40,0x7C,0x00,0xFC, ++ 0x40,0x7C,0x00,0xBC,0xE4,0x90,0xE4,0x48,0xE2,0xD8,0xE4,0x00,0x95,0x05,0x12,0x82, ++ 0xDB,0xA6,0xE7,0x20,0x90,0x25,0xC3,0x34,0x17,0x22,0xDC,0x6E,0xF8,0x94,0xE0,0x8C, ++ 0x00,0x01,0x80,0x5C,0x00,0xAF,0x05,0x01,0x34,0x32,0x34,0x22,0xC8,0x5C,0x00,0x09, ++ 0x00,0x42,0xCC,0x0C,0x80,0x64,0x10,0x42,0x81,0x7E,0xE3,0x53,0x50,0x01,0x80,0x2E, ++ 0xC8,0x34,0xC0,0x5C,0xF4,0x48,0x12,0x42,0x88,0x06,0x30,0xB2,0x1A,0x01,0x00,0x87, ++ 0x41,0xCC,0x41,0x14,0xD0,0x40,0x94,0x15,0x00,0x14,0xC9,0x1C,0x10,0x52,0xD4,0x3E, ++ 0x32,0x02,0xE3,0x00,0x94,0x05,0x36,0x22,0x34,0x82,0xC3,0x00,0x94,0x05,0x30,0x32, ++ 0xCC,0x2C,0x10,0x52,0xE8,0x3E,0x01,0x7F,0x00,0x01,0x00,0x42,0x48,0xE0,0x06,0x00, ++ 0x38,0xA0,0x03,0x00,0xAA,0xAA,0xAA,0xAA,0x18,0x00,0x04,0x42,0x00,0xD0,0x00,0x01, ++ 0x68,0xB8,0x03,0x00,0x28,0x60,0x00,0x00,0xCC,0x4B,0x13,0x8A,0xE7,0x1E,0x58,0x43, ++ 0xC8,0x64,0x18,0x0A,0x18,0x4B,0xCF,0x6C,0xE8,0x4B,0x4A,0x09,0x88,0x16,0xC8,0x6C, ++ 0x02,0x09,0xAC,0x43,0xCC,0x54,0x10,0x52,0xE8,0xBE,0x08,0x09,0xD4,0x44,0x00,0xCA, ++ 0x18,0x8A,0x88,0x44,0x00,0x8F,0xC8,0x24,0x10,0x52,0xD4,0x76,0xCA,0x6C,0xE8,0x4B, ++ 0x48,0x09,0x88,0x16,0xCC,0x6C,0x00,0x09,0xA8,0x43,0xCA,0x4C,0x10,0x52,0xD4,0x26, ++ 0x08,0x09,0xD0,0x3C,0x00,0xCA,0x1C,0x8A,0x8D,0x3C,0xE0,0x20,0xE2,0xF8,0xE5,0xD8, ++ 0x95,0xDD,0x12,0x9A,0xD8,0x66,0xC5,0x7C,0xC8,0x03,0x44,0x01,0x83,0x2E,0x32,0x02, ++ 0x40,0x11,0xC8,0x2E,0x33,0x0A,0x33,0x82,0x83,0x07,0xC8,0xD7,0x90,0x05,0x00,0x07, ++ 0x03,0x01,0x00,0x88,0xD0,0x20,0x13,0x01,0x01,0x57,0x01,0x67,0x40,0x01,0xE8,0x7E, ++ 0x0B,0x01,0xF0,0x0A,0xDC,0x1C,0x10,0xCA,0xD2,0xB6,0xE0,0x18,0x10,0xCA,0xEC,0x16, ++ 0xD1,0x48,0x00,0x0C,0x00,0x87,0x48,0x01,0xE8,0x76,0x08,0x09,0x00,0x0C,0x01,0x5F, ++ 0x0B,0x01,0xF0,0x0A,0x10,0x0A,0xD4,0x16,0xD1,0x48,0x00,0x0C,0x00,0x27,0x48,0x01, ++ 0xD0,0x16,0x08,0x01,0x19,0x4A,0x06,0x0C,0x0B,0x01,0xF0,0x0A,0xDC,0x24,0x10,0xCA, ++ 0xD0,0x1E,0xC8,0x14,0xE6,0x48,0x92,0x4D,0x8D,0x14,0xE0,0x20,0xE2,0x90,0x92,0x95, ++ 0x16,0x92,0xDD,0x9E,0x00,0x4F,0x00,0x01,0x08,0x01,0x00,0x27,0x05,0x0C,0xE1,0x20, ++ 0xE2,0xF8,0xE5,0x00,0x95,0x05,0x12,0x82,0xD8,0xC6,0xC7,0x5C,0xE2,0x00,0x92,0x05, ++ 0x80,0x5C,0xC8,0x34,0xC4,0x5C,0x10,0x42,0xD2,0x06,0x38,0x27,0xC9,0x43,0x41,0x71, ++ 0xC9,0x0E,0x00,0x71,0x88,0x43,0xC1,0x14,0xCC,0x4B,0x41,0x00,0xC6,0x40,0x90,0x05, ++ 0x8A,0x43,0x41,0x81,0xCA,0x0E,0x00,0x81,0x88,0x43,0x01,0x01,0x29,0x44,0x37,0x44, ++ 0xC0,0x74,0xC8,0x44,0x18,0x0B,0xCE,0x74,0xC4,0x3C,0x18,0x43,0x87,0x9D,0xE8,0x85, ++ 0xA8,0x85,0x33,0x2A,0x30,0x62,0x30,0xB2,0x31,0x0A,0x31,0x42,0xBA,0xFF,0xEF,0xCF, ++ 0x48,0x6A,0x03,0x01,0x81,0x43,0x30,0x92,0x31,0x0A,0x31,0x42,0xBB,0xFF,0xEF,0x1F, ++ 0xEE,0x03,0x41,0x41,0x92,0x0E,0xE0,0x00,0xAB,0x03,0xE9,0x85,0x10,0x01,0x00,0x37, ++ 0x0A,0x01,0xE0,0x48,0x90,0x4D,0x4C,0xA1,0xCA,0xDE,0xE7,0x90,0x94,0x95,0x14,0x12, ++ 0xCB,0xB6,0x3F,0x82,0x38,0x18,0x78,0xD8,0x14,0x09,0x00,0xD2,0x97,0x95,0x1E,0xF9, ++ 0x08,0xD8,0x00,0xC2,0x5E,0xEA,0xC2,0x00,0x48,0x09,0x88,0x66,0x44,0x0B,0x18,0x8A, ++ 0x02,0x0B,0x40,0x0B,0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B, ++ 0x1E,0x8A,0x04,0x0B,0x38,0x82,0x4B,0x01,0x8A,0x66,0x40,0x0B,0x1A,0x8A,0x04,0x0B, ++ 0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B,0x40,0x0B,0x18,0x8A, ++ 0x03,0x0B,0x38,0x82,0x48,0x11,0x88,0x66,0x44,0x0B,0x18,0x8A,0x02,0x0B,0x40,0x0B, ++ 0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x00,0x0B, ++ 0x38,0x82,0x4B,0x19,0x88,0xE6,0x47,0x0B,0x18,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A, ++ 0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B,0x40,0x0B,0x1A,0x8A,0x03,0x0B,0x3A,0x82, ++ 0xAC,0x8D,0x87,0x3D,0xC0,0x3C,0xC8,0x3C,0x4C,0x00,0x00,0x00,0xC0,0x00,0x3A,0x00, ++ 0x4A,0xDA,0x71,0x00,0xC1,0x28,0x42,0xDA,0x44,0x0B,0x90,0x4D,0x88,0x34,0x58,0x0B, ++ 0x90,0x4D,0x8C,0x2C,0x5C,0x0B,0x92,0x4D,0x8C,0x24,0x58,0x0B,0x90,0x4D,0x8C,0x1C, ++ 0x54,0x0B,0x96,0x75,0x4A,0xA2,0x41,0x53,0x90,0x95,0x94,0x14,0x44,0x53,0x90,0xBD, ++ 0x44,0x13,0x92,0x95,0x91,0x0C,0x58,0x7A,0x98,0x01,0x52,0xD3,0x90,0x95,0x94,0x04, ++ 0x10,0x09,0x00,0x13,0xA8,0x10,0x1C,0x13,0x12,0x81,0x18,0x13,0x18,0x13,0x14,0x79, ++ 0x11,0x13,0x16,0x01,0x00,0x53,0x12,0x89,0x02,0x53,0x40,0x0B,0x10,0x81,0x19,0x8A, ++ 0x07,0x0B,0x02,0xF9,0x80,0x89,0x17,0xC3,0x07,0x09,0xB8,0xFF,0xFF,0x7F,0x03,0xF9, ++ 0x80,0x89,0x14,0xC3,0x07,0x09,0xB8,0xFF,0xF8,0x4F,0x03,0x19,0x11,0x00,0x00,0x43, ++ 0x07,0x09,0xB8,0xFF,0xF8,0x1F,0x0B,0x11,0xC7,0x3C,0xB8,0xFF,0xF8,0x5F,0x23,0xA1, ++ 0x01,0x01,0x40,0x4B,0x30,0x48,0xA8,0x16,0xE7,0x20,0x93,0x25,0x03,0x0F,0xF0,0x20, ++ 0x92,0x25,0xE7,0x00,0x90,0x05,0x46,0x51,0x98,0x9E,0x0F,0x09,0xC7,0x3C,0xB8,0xFF, ++ 0xF8,0xCF,0x42,0x82,0xC8,0x34,0x00,0x0B,0xC8,0x2C,0x18,0x0B,0xCA,0x24,0x18,0x0B, ++ 0xCC,0x1C,0x18,0x0B,0x10,0x33,0x4E,0x62,0xD2,0x14,0x00,0x53,0x00,0x7B,0xC8,0x0C, ++ 0x00,0x0B,0x4A,0x42,0xC2,0x04,0x88,0x01,0x10,0x43,0x60,0xA1,0xC8,0x16,0x00,0x09, ++ 0x87,0x45,0xE8,0x85,0x07,0x01,0x38,0xDF,0x00,0xD0,0x00,0x01,0x80,0x00,0x00,0x42, ++ 0x08,0x01,0x00,0x42,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x00,0x0F,0x00,0x26, ++ 0xF8,0x48,0x48,0x21,0x94,0xDE,0x3F,0x58,0xA8,0x0E,0x00,0x14,0xE6,0x00,0x3C,0x48, ++ 0x80,0x06,0x80,0x13,0x38,0x82,0x4B,0x01,0x86,0x5E,0x38,0x18,0x80,0x16,0x80,0x13, ++ 0xE2,0x00,0xF2,0x48,0x48,0x11,0x98,0x26,0x38,0x18,0xAC,0x16,0x04,0x14,0xE0,0x00, ++ 0xF7,0x48,0x3C,0x1F,0x17,0x01,0x38,0x77,0x16,0x01,0x38,0xFF,0x10,0x01,0x48,0x18, ++ 0x11,0x5A,0x9C,0x66,0x54,0x18,0x10,0x5A,0x98,0x8E,0x18,0x01,0x32,0xE2,0x04,0x77, ++ 0x30,0x1A,0x18,0x5A,0xA0,0xE6,0x11,0x01,0x44,0x18,0x12,0x5A,0x98,0x8E,0x49,0x18, ++ 0x10,0x5A,0x9C,0xE6,0x54,0x18,0x10,0x5A,0x9C,0x0E,0x30,0xA2,0x06,0xFF,0x49,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD6,0x00,0x0C,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x0E,0x58,0xD4,0x00,0x0A,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD2,0x00, ++ 0x08,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD0,0x00,0x0E,0x92,0x42,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD6,0x00,0x0C,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x06,0x58,0xD4,0x00,0x0A,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00, ++ 0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A,0x08,0x92,0x32,0x82,0x3A,0x82,0x03,0xEF, ++ 0x78,0x50,0x86,0x06,0x10,0x4A,0x82,0x18,0x9A,0x06,0x10,0x02,0x00,0x9A,0x12,0x01, ++ 0x30,0xE2,0x4C,0x18,0x11,0x5A,0x9C,0x6E,0x54,0x18,0x10,0x5A,0x9F,0x96,0x10,0xE1, ++ 0x08,0x48,0xD4,0x95,0x54,0x18,0x10,0x5A,0x9C,0x66,0x08,0x48,0x8C,0x90,0x14,0x5A, ++ 0x9C,0x46,0x08,0x48,0x8C,0x90,0x14,0x5A,0x9C,0x26,0x08,0x48,0x84,0xD6,0x89,0x90, ++ 0x04,0x07,0x48,0x48,0x4C,0x18,0x16,0x5A,0x9E,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92, ++ 0x4C,0x18,0x14,0x5A,0x9C,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x12,0x5A, ++ 0x9A,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x10,0x5A,0x98,0x0E,0x08,0x58, ++ 0xD2,0x00,0x0E,0x92,0x44,0x18,0x16,0x5A,0x9E,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92, ++ 0x44,0x18,0x14,0x5A,0x9C,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92,0x92,0xCE,0x46,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A, ++ 0x32,0x1A,0x0B,0x92,0x80,0xD8,0x32,0x82,0x9A,0x0E,0x10,0x02,0x58,0x01,0xA8,0x06, ++ 0x13,0x4A,0x3A,0x82,0x32,0x1A,0x83,0xD8,0x9A,0x06,0x10,0x02,0xA8,0x0D,0x00,0x01, ++ 0x36,0x02,0x36,0x02,0xEB,0x15,0x30,0xAA,0x81,0x07,0xC0,0x17,0x30,0x72,0x05,0x28, ++ 0x32,0x4A,0x33,0x9A,0x46,0x00,0x06,0x00,0x30,0x2A,0x84,0xC5,0xAF,0x05,0xB9,0xE7, ++ 0xF3,0x6F,0xE4,0x05,0x3A,0x01,0x40,0x48,0x30,0xB2,0x35,0x01,0x2E,0x06,0x2E,0x06, ++ 0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0xEA,0x01,0x02,0x48, ++ 0x33,0x6A,0x3C,0x82,0x36,0x22,0x30,0x02,0x31,0x02,0x36,0x02,0xBA,0xDF,0xD7,0x5F, ++ 0x43,0x02,0x38,0x82,0x88,0x20,0x00,0x01,0x40,0x12,0x48,0x1A,0xF3,0x5D,0x3D,0x82, ++ 0x00,0x68,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x30,0x01,0x10,0x39,0x82,0xA3,0x85, ++ 0x33,0xA2,0xF3,0x20,0xC3,0x2B,0xE1,0x20,0x10,0x5A,0x95,0x06,0x33,0xEA,0xE8,0x1A, ++ 0x07,0xD8,0xC2,0x18,0xE0,0x85,0x39,0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x80,0x20,0x03,0x42,0x80,0x20,0x03,0x42,0x80,0x20,0x04,0x42, ++ 0x80,0x20,0x03,0x42,0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42,0x80,0xA0,0x04,0x42, ++ 0x80,0xA0,0x02,0x42,0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42,0x80,0x20,0x05,0x42, ++ 0x80,0xA0,0x02,0x42,0x80,0xA0,0x05,0x42,0x80,0x20,0x02,0x42,0x80,0x20,0x01,0x42, ++ 0x80,0x20,0x01,0x42,0x80,0xA0,0x01,0x42,0x80,0xA0,0x01,0x42,0x80,0xA0,0x01,0x42, ++ 0x10,0x20,0x08,0x40,0x40,0x08,0x20,0x10,0x10,0x20,0x08,0x40,0x40,0x08,0x20,0x40, ++ 0x10,0x20,0x00,0x08,0x08,0xC1,0x02,0x42,0x08,0x81,0x02,0x42,0x08,0x81,0x03,0x42, ++ 0x08,0x41,0x03,0x42,0x08,0x01,0x03,0x42,0x08,0x81,0x02,0x42,0x08,0x41,0x02,0x42, ++ 0x08,0xC1,0x00,0x42,0x08,0x01,0x02,0x42,0x08,0x01,0x01,0x42,0x08,0xC1,0x01,0x42, ++ 0x08,0x41,0x01,0x42,0x08,0x81,0x01,0x42,0x08,0x81,0x01,0x42,0x08,0x41,0x01,0x42, ++ 0x08,0xC1,0x02,0x42,0x08,0x01,0x01,0x42,0x08,0x01,0x03,0x42,0x08,0xC1,0x00,0x42, ++ 0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x00,0x00, ++ 0x00,0x08,0xF8,0x0F,0xFF,0x07,0xF8,0xFF,0x07,0xF8,0x0F,0xF8,0x08,0x00,0x08,0x08, ++ 0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x28,0xB5,0x39,0xC5,0x08,0x1D, ++ 0x1B,0x2B,0x3A,0x28,0x53,0xB5,0x0A,0xC5,0x00,0x08,0x01,0x00,0x01,0x00,0x50,0x0D, ++ 0x52,0x1D,0x52,0xB5,0x39,0x0D,0x04,0x08,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95, ++ 0x51,0x3D,0x54,0x95,0x51,0x3D,0x54,0x95,0x0B,0x3D,0x34,0x88,0x51,0x3D,0x54,0x1D, ++ 0x51,0x3D,0x54,0x95,0x04,0x00,0x50,0x3D,0x50,0x1D,0x01,0x00,0x00,0x00,0x00,0x00, ++ 0x54,0x2D,0x53,0x3D,0x32,0x8D,0x32,0x38,0x01,0x28,0x0A,0x45,0x50,0xB5,0x53,0x95, ++ 0x00,0x00,0x00,0x00,0x52,0xA5,0x51,0xB5,0x09,0xC5,0x03,0x08,0x03,0x00,0x50,0x3D, ++ 0x55,0x1D,0x51,0x0D,0x51,0x3D,0x54,0x95,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95, ++ 0x51,0x0D,0x55,0x0D,0x54,0xB5,0x3A,0x0D,0x00,0x08,0x01,0x00,0x53,0xA5,0x51,0x2D, ++ 0x52,0x3D,0x34,0x8A,0x1D,0x38,0x52,0x45,0x52,0x0D,0x51,0x1D,0x54,0xB5,0x3A,0x0D, ++ 0x53,0xA5,0x29,0xB5,0x39,0xC5,0x08,0x1D,0x19,0x2D,0x22,0x1D,0x44,0x0D,0x31,0x3D, ++ 0x23,0x95,0x09,0xC1,0x29,0xB5,0x0B,0x1D,0x1B,0x2B,0x3A,0x28,0x00,0x00,0x00,0x08, ++ 0xFF,0x07,0x00,0xF8,0x08,0x00,0x10,0x10,0x08,0x10,0x10,0x10,0x08,0x08,0x10,0x08, ++ 0x10,0x08,0x10,0x08,0x10,0x10,0x08,0x08,0x10,0x10,0x08,0x08,0x08,0x08,0x10,0x10, ++ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08, ++ 0xF8,0x07,0x08,0x00,0x08,0x08,0x00,0x00,0x78,0x42,0x00,0x00,0x00,0x00,0x00,0x01, ++ 0x00,0xE0,0x00,0x00,0x00,0x00,0x05,0x00,0x78,0x22,0x01,0x00,0x00,0xE0,0x00,0x01, ++ 0x88,0x40,0x02,0x00,0x00,0xE0,0x05,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,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xD1,0xDA,0xAA,0xA9,0x2E,0x2D,0x55,0x56,0xBB,0x43,0xAC,0x32, ++ 0x99,0x21,0x8A,0x10,0x00,0x70,0x00,0x28,0x09,0x00,0x1F,0x00,0x06,0x78,0x50,0x56, ++ 0xFF,0xFF,0xFF,0xFF,0xB2,0x30,0x08,0x40,0x00,0x40,0x20,0x00,0x03,0x13,0x2A,0xC7, ++ 0x0F,0x00,0xCA,0xCA,0xFF,0xFF,0xFF,0xFF,0x06,0x16,0x48,0x01,0x08,0x00,0x00,0x04, ++ 0x42,0x60,0x78,0xE5,0xD8,0xB9,0xCC,0x04 ++}; ++ ++ ++#define FW_INFO_SIZE (0x18) ++#define FW_REAL_SIZE (sizeof(fwbin)) ++#define FW_BIN_SIZE (24*1024+24) //24K byte ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/hyn_cst3xx_RS659_fw_0730_268_800.h b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/hyn_cst3xx_RS659_fw_0730_268_800.h +new file mode 100644 +index 000000000..3bd6f0b32 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Original_driver/hyn_cst3xx_RS659_fw_0730_268_800.h +@@ -0,0 +1,1552 @@ ++ ++#ifndef __CST3xx_FW_H__ ++#define __CST3xx_FW_H__ ++ ++ unsigned char cst3_fw[] ={ ++ 0x98,0xE0,0x07,0x01,0xC8,0x88,0x02,0x00,0x00,0x00,0x00,0x00,0xC8,0x48,0x02,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x98,0x88,0x00,0x00,0x98,0x88,0x01,0x00,0x00,0x00,0x00,0x00, ++ 0x98,0x28,0x02,0x00,0x00,0x00,0x00,0x00,0x98,0xF8,0x02,0x00,0x80,0x07,0xC0,0x17, ++ 0x82,0x07,0xC0,0x07,0x01,0x65,0x40,0x86,0xC1,0x41,0xC0,0x20,0xC5,0x68,0x31,0x12, ++ 0xF5,0x38,0x33,0x5A,0x32,0xA2,0x32,0xEA,0x10,0x62,0x8D,0x0E,0x81,0x07,0xC0,0x97, ++ 0x30,0xF2,0xF3,0x79,0x65,0x7E,0x30,0xB2,0x31,0x09,0x10,0x9A,0x87,0x06,0xD0,0xD8, ++ 0x35,0x12,0x35,0x5A,0x18,0x9A,0x39,0xC2,0x70,0xE2,0x02,0x00,0x70,0xE2,0x03,0x00, ++ 0xD0,0x81,0x98,0x16,0x43,0xC6,0x0B,0xC6,0xC2,0xD6,0x3F,0x90,0x99,0x0E,0x40,0x86, ++ 0x08,0x86,0xA9,0x0E,0x40,0x23,0x00,0x63,0x38,0x82,0x03,0x00,0x18,0x01,0x20,0x01, ++ 0x28,0x01,0x30,0x01,0xD0,0x81,0x98,0x0E,0x0F,0xC6,0xC3,0xDE,0x38,0x90,0x9A,0x06, ++ 0x08,0x86,0xA9,0x06,0x03,0x5B,0x38,0x82,0xAE,0xFD,0x30,0x02,0x30,0x02,0xEE,0xFD, ++ 0xA8,0x85,0xE8,0x85,0x84,0x27,0xE8,0xEF,0x37,0x8A,0xB8,0xFF,0xF8,0xAF,0x87,0x0F, ++ 0xD0,0x2F,0x81,0x27,0xEF,0xAF,0xBD,0xFF,0xF8,0x9F,0x87,0x27,0xE8,0xDF,0x05,0x00, ++ 0xAF,0x85,0x6F,0xFA,0x39,0x01,0xC0,0x43,0x37,0x4A,0xC9,0x01,0x38,0x30,0x32,0x42, ++ 0x86,0x01,0xC5,0x1B,0xCE,0x23,0xF0,0x53,0xC0,0x01,0x74,0x01,0xDD,0x16,0xC0,0x6B, ++ 0x48,0x68,0x87,0x3E,0xAA,0x7B,0xAC,0x3B,0x10,0xD2,0x8C,0x16,0xB0,0x63,0x06,0x09, ++ 0xB7,0x43,0xEC,0x85,0x34,0x6A,0xE8,0x4B,0xE6,0x48,0x92,0x4D,0xAF,0x4B,0x4D,0xF9, ++ 0x8D,0x0E,0x10,0x12,0x82,0x16,0xE8,0x0B,0x48,0x09,0x88,0x1E,0xB5,0x5B,0xAF,0x7B, ++ 0xAF,0x3B,0xEA,0x85,0x4F,0x09,0x8C,0xE6,0x0A,0x09,0xA8,0x0B,0xE8,0x85,0xAF,0x85, ++ 0x67,0x3A,0xE7,0x01,0x00,0x0F,0x80,0x0F,0xF5,0x4F,0xF0,0x03,0x47,0x01,0x80,0xD6, ++ 0xEF,0x85,0xA8,0xC5,0x00,0x21,0x80,0x0F,0xE8,0x9F,0x07,0x09,0x87,0x0F,0xE8,0x87, ++ 0x79,0x02,0x47,0xC3,0x0C,0x01,0x19,0x42,0x00,0xC3,0x01,0x11,0x86,0x0F,0xE8,0xEF, ++ 0x61,0xEA,0x56,0x03,0x29,0x41,0x18,0x42,0x17,0x03,0x49,0x03,0x1F,0x42,0x09,0x03, ++ 0x15,0x2B,0x4B,0x03,0x1D,0x42,0x09,0x03,0x4D,0x03,0x1B,0x42,0x0B,0x03,0x4B,0x03, ++ 0x35,0x21,0x18,0x82,0x0B,0x03,0x4B,0x03,0x42,0x00,0x02,0x00,0x09,0x03,0x4B,0x03, ++ 0x19,0x42,0x09,0x03,0x49,0x03,0x19,0x82,0x09,0x03,0x49,0x03,0x08,0x09,0x18,0x42, ++ 0x0F,0x03,0x41,0x03,0x1F,0x42,0x05,0x03,0x45,0x03,0x1F,0x82,0x07,0x03,0x47,0x03, ++ 0x1F,0x42,0x04,0x03,0x45,0x03,0x1D,0x42,0x05,0x03,0x45,0x03,0x1D,0x82,0x05,0x03, ++ 0x45,0x03,0x1B,0x42,0x03,0x03,0x43,0x03,0x1B,0x82,0x05,0x03,0x44,0x03,0x1D,0x42, ++ 0x03,0x03,0x45,0x03,0x1B,0x42,0x04,0x03,0x0E,0x81,0x42,0x02,0x82,0x27,0xE0,0xC7, ++ 0x85,0x0F,0xE8,0xB7,0x85,0x0F,0xE8,0x97,0x85,0x0F,0xE8,0xC7,0x48,0xE2,0x05,0x01, ++ 0x1D,0x43,0x4C,0x03,0x1D,0x42,0x0D,0x03,0x10,0x2B,0x03,0x11,0x84,0x0F,0xE8,0xC7, ++ 0x41,0xC3,0x09,0x01,0x19,0x42,0x00,0xC3,0x00,0x21,0x80,0x0F,0xE8,0x37,0x04,0x09, ++ 0x84,0x0F,0xE8,0x1F,0x42,0x03,0x41,0x00,0x01,0x00,0x02,0x03,0x40,0x03,0x0F,0x09, ++ 0x1F,0x42,0x00,0x03,0x4C,0x03,0x1B,0x42,0x09,0x03,0x4B,0x03,0x19,0x42,0x0C,0x03, ++ 0x41,0x03,0x1D,0x42,0x05,0x03,0x45,0x03,0x1D,0x82,0x01,0x03,0x41,0x03,0x1B,0x42, ++ 0x03,0x03,0x43,0x03,0x1B,0x82,0x01,0x03,0x48,0x0B,0x03,0x61,0x1B,0x0A,0x08,0x0B, ++ 0x48,0x0B,0x19,0x0A,0x0F,0x0B,0x41,0x0B,0x1F,0x0A,0x00,0x0B,0x48,0xE2,0x04,0x09, ++ 0xC8,0x01,0xAF,0x43,0x83,0x0F,0xD0,0x07,0xEC,0xC5,0x47,0xCA,0xC6,0x01,0xF3,0x0B, ++ 0x42,0xCA,0x84,0x01,0x48,0x01,0x80,0x3E,0x4A,0xD2,0x04,0x0B,0x0C,0xF9,0x57,0xB2, ++ 0x8C,0x89,0x97,0x01,0x10,0x8B,0x00,0x17,0x48,0xB2,0xCC,0xE1,0x07,0x0B,0x12,0xF9, ++ 0x96,0xA1,0x02,0x13,0x08,0x31,0x08,0x0B,0x0C,0x11,0x08,0x0B,0x0A,0x51,0x08,0x0B, ++ 0x0C,0x49,0x18,0x0B,0x18,0x0B,0x0A,0x01,0x1C,0x0B,0x40,0x4A,0xC2,0x01,0x0F,0x14, ++ 0x3F,0x82,0xAB,0x85,0x70,0x62,0x0C,0x01,0x2C,0x01,0x60,0x62,0x50,0x62,0x04,0x01, ++ 0xA4,0x82,0x02,0x40,0x50,0x5A,0xC4,0x40,0xC4,0x00,0x54,0x5A,0xC0,0x10,0x1C,0x01, ++ 0xC6,0x83,0x01,0x38,0xC1,0x83,0xD0,0xC0,0x94,0x05,0x14,0x2A,0x90,0x06,0x30,0x2A, ++ 0x10,0x22,0xCC,0x06,0x32,0x22,0xE0,0x90,0xE6,0xD8,0x92,0xDD,0x5F,0x29,0x98,0x8E, ++ 0x59,0xFA,0xDB,0x40,0xA3,0xC2,0xE2,0xB0,0xE6,0x48,0x92,0x4D,0x4E,0x71,0x98,0xDE, ++ 0x48,0xD2,0x03,0x01,0xE4,0xD2,0x10,0x52,0x90,0x06,0x30,0x8A,0xE6,0x00,0x92,0x05, ++ 0x47,0x71,0x98,0xBE,0x50,0xCA,0x03,0x01,0x00,0x84,0xE0,0xE2,0x43,0xAC,0xD0,0x20, ++ 0xC8,0x20,0x03,0xA4,0xE6,0x00,0x92,0x05,0x47,0x71,0x98,0xB6,0x47,0x84,0x40,0xF9, ++ 0xCF,0x0E,0x00,0xF9,0x03,0x84,0x48,0x92,0x40,0x84,0x80,0x43,0xE8,0x85,0xAF,0x85, ++ 0x40,0x1A,0xC3,0x03,0x38,0x00,0x86,0xAE,0x00,0x01,0x85,0x0F,0xD3,0xAF,0x60,0x02, ++ 0x01,0x01,0xE0,0x01,0x8F,0x03,0xB9,0xFF,0xF9,0x47,0x34,0x0A,0x56,0x4A,0xCB,0x01, ++ 0x40,0x22,0x83,0x1F,0xD0,0x6F,0x04,0x11,0x88,0x03,0x01,0x01,0x86,0x0F,0xC8,0xE7, ++ 0xBC,0xFF,0xFF,0xFF,0xE8,0x85,0xA8,0x85,0x41,0xAA,0xC2,0x01,0xC8,0x03,0x42,0x01, ++ 0x8A,0x36,0x40,0x9A,0xC0,0x01,0xEF,0x03,0x40,0x29,0xC8,0x0E,0xBE,0xFF,0xF7,0x7F, ++ 0x61,0x7A,0xC2,0x03,0x38,0x00,0xA8,0x0E,0xBE,0xFF,0xF7,0x9F,0xC3,0x03,0xC3,0x03, ++ 0x08,0xE9,0x07,0x42,0x82,0x03,0x43,0xC2,0xC0,0x03,0x40,0x01,0x80,0x16,0x80,0x0F, ++ 0xE7,0x6F,0x3E,0xE7,0xE8,0x85,0xA8,0x85,0x48,0x32,0x02,0x01,0x02,0x43,0x4C,0x22, ++ 0xCC,0x01,0xB7,0x43,0xF0,0x43,0x86,0x0F,0xC8,0xBF,0xEE,0x85,0xA8,0x85,0x33,0x2A, ++ 0x48,0x01,0x80,0x4E,0x68,0x01,0x80,0x1E,0x30,0x82,0xC0,0x51,0x20,0x01,0x00,0x5F, ++ 0x30,0x82,0x80,0x51,0x20,0x01,0x00,0x3F,0x68,0x01,0x80,0x1E,0xF0,0x80,0x24,0x49, ++ 0x18,0x22,0x07,0x0F,0xE0,0x80,0x24,0x51,0x0A,0x01,0xF0,0x0A,0x48,0x01,0xD0,0x06, ++ 0x16,0x4A,0x0A,0x40,0x0A,0x01,0xF0,0x8A,0x82,0x27,0xD8,0x87,0x40,0xF9,0xEB,0x06, ++ 0x00,0xF9,0x6B,0x01,0x87,0x16,0x08,0xF9,0x88,0x09,0xD0,0x40,0xCB,0x00,0xE8,0x85, ++ 0xAC,0x85,0x87,0x3D,0x28,0x01,0x20,0x01,0x01,0x51,0x48,0x92,0x1A,0x42,0xC3,0x00, ++ 0x80,0x34,0xC0,0x34,0x01,0x08,0x13,0x39,0xC4,0x00,0x0A,0x90,0xC0,0x10,0x04,0xE1, ++ 0x90,0x2C,0xF0,0x82,0x80,0x24,0x30,0x01,0x38,0x01,0x10,0x01,0x90,0x1C,0x90,0x14, ++ 0x60,0x01,0x80,0x46,0xF0,0x10,0xDB,0x34,0x04,0x90,0xC2,0xD0,0x1C,0x39,0x09,0xD8, ++ 0xC0,0x90,0x36,0xE1,0xF8,0xB2,0x6C,0x01,0x83,0x56,0xF0,0x50,0x1A,0x51,0x18,0xD2, ++ 0x5E,0x02,0xC1,0x90,0x1A,0x39,0xC1,0x90,0x0E,0xD8,0xC4,0x90,0x3E,0xE1,0xF8,0xBA, ++ 0x60,0x21,0x80,0x4E,0xE0,0x18,0xD3,0x34,0x06,0xD8,0xC2,0x90,0x1C,0x39,0x09,0xD8, ++ 0xC0,0x90,0x1E,0xE1,0xF0,0x9A,0x9E,0x1C,0x68,0x69,0x80,0x5E,0xE0,0x50,0x1B,0x51, ++ 0x18,0xD2,0x5A,0xA2,0xC2,0x90,0xC6,0x88,0x14,0x39,0x09,0x90,0xC0,0x50,0x0C,0xE1, ++ 0xF0,0x8A,0x8A,0x14,0x08,0x09,0x88,0x0C,0x70,0x41,0xD1,0x3E,0x78,0x41,0xD1,0x2E, ++ 0xC9,0x1C,0x48,0x41,0xD0,0x16,0xC8,0x14,0x49,0x41,0xD9,0x06,0x08,0x01,0x00,0xEF, ++ 0x00,0xE0,0x07,0x01,0x10,0x00,0x00,0x42,0xF8,0x00,0x06,0x42,0x80,0x30,0x02,0x01, ++ 0x18,0x00,0x02,0x42,0x80,0x60,0x05,0x00,0x70,0x00,0x04,0x01,0xF8,0xFF,0x07,0x00, ++ 0x80,0x50,0x06,0x01,0x08,0x40,0x00,0x01,0x60,0x20,0x02,0x00,0x00,0x60,0x00,0x01, ++ 0x00,0x28,0x00,0x01,0x80,0xC0,0x04,0x01,0x00,0x20,0x00,0x01,0x88,0x0C,0x08,0x19, ++ 0x86,0x27,0xD0,0x67,0x10,0x82,0xED,0x3E,0x10,0xC2,0xED,0x2E,0xCC,0x1C,0x10,0x42, ++ 0xE8,0x16,0xC8,0x14,0x10,0x42,0xE4,0x0E,0x00,0x01,0x80,0x0C,0xC0,0x0C,0x40,0x01, ++ 0x80,0x86,0xC8,0x24,0xD6,0x2C,0x78,0x40,0xC2,0x00,0x82,0x00,0xD0,0x48,0x90,0x4D, ++ 0x1F,0x8C,0x54,0xFA,0x58,0xFA,0xC7,0x93,0xC0,0xDB,0x18,0xD2,0x80,0x16,0xD0,0x40, ++ 0xCC,0x2C,0x18,0x44,0xE7,0x20,0x93,0x25,0x60,0x29,0x90,0x06,0x3B,0x4F,0xE3,0x68, ++ 0x90,0x6D,0x6F,0x71,0x92,0x06,0x38,0xF7,0x87,0x3D,0xE8,0x85,0xA8,0xC5,0x2F,0x01, ++ 0x40,0xAA,0xFF,0x03,0x81,0x04,0x00,0x5F,0x07,0x31,0x48,0xA2,0x1A,0x42,0xC3,0x00, ++ 0x0C,0xC9,0x09,0x48,0xC0,0x30,0x3A,0x11,0xF8,0xBA,0x07,0x21,0xF0,0x82,0x41,0x51, ++ 0xD0,0x0E,0x20,0x51,0x00,0x0F,0xC0,0x51,0x96,0x25,0x00,0x19,0x04,0x00,0x14,0x22, ++ 0xE8,0x06,0x30,0x22,0x37,0x02,0xC1,0xF9,0xC0,0x89,0x0C,0xF1,0x1F,0x42,0x0A,0xF9, ++ 0x88,0x89,0x84,0x27,0xD0,0xDF,0xCB,0x00,0x90,0x05,0x40,0x51,0xD0,0x06,0x00,0x51, ++ 0x4C,0x1A,0x17,0x42,0xE8,0x06,0x30,0x42,0x05,0xBC,0x03,0x84,0xE7,0x68,0x93,0x6D, ++ 0xC5,0x04,0x10,0x42,0xC7,0x86,0xEE,0xC5,0xAC,0x85,0x87,0x3D,0x00,0xF9,0x87,0x0C, ++ 0x00,0x01,0x80,0x04,0x81,0x14,0x18,0x39,0x09,0xD8,0x24,0x39,0x57,0xBA,0x1E,0x22, ++ 0x04,0x08,0xC2,0x48,0xC0,0x68,0x0E,0xE1,0xF2,0x4A,0xE3,0x00,0x92,0x05,0x40,0x31, ++ 0xD8,0xB6,0x07,0x01,0x80,0x24,0x00,0x01,0x38,0x01,0x28,0x01,0x30,0xF9,0xCF,0x24, ++ 0x12,0x51,0x18,0x8A,0x54,0x6A,0xC6,0x48,0x54,0x72,0xC6,0x50,0x90,0x34,0x08,0x01, ++ 0x20,0x01,0xF8,0xA2,0x60,0xA1,0xE8,0x0E,0xE1,0xF8,0x93,0xFD,0xC0,0x00,0x91,0x05, ++ 0x10,0x62,0xED,0x06,0x35,0x2A,0x11,0xA2,0xD1,0x06,0x30,0x32,0xE2,0x90,0xE4,0x48, ++ 0x90,0x4D,0x4E,0x29,0x99,0x66,0x6F,0xE1,0xED,0x16,0x50,0xFA,0x0C,0x01,0xA8,0x8B, ++ 0x08,0x29,0x80,0x27,0xD0,0x5F,0x91,0x0D,0xD0,0x40,0x83,0x71,0x40,0xE1,0xC0,0x6E, ++ 0xD0,0x80,0x83,0x71,0x40,0xE1,0xC0,0x4E,0x68,0xE1,0xE9,0x3E,0x78,0x21,0xE8,0x2E, ++ 0x50,0xA2,0x05,0x01,0x85,0x83,0x40,0x92,0x10,0xD1,0x87,0x13,0xC4,0x14,0x10,0x42, ++ 0xD0,0x06,0x88,0x14,0xC5,0x0C,0x10,0x82,0xE8,0x06,0xB0,0x0C,0xC5,0x04,0x10,0x42, ++ 0xD0,0x06,0xA8,0x04,0x6D,0x6A,0x75,0x7A,0xC0,0x34,0x18,0x01,0x48,0x01,0xE8,0xBE, ++ 0x14,0x01,0xF0,0x12,0x10,0x52,0xDC,0x76,0x61,0x2A,0xC5,0x23,0x60,0x01,0x80,0x16, ++ 0xD0,0x90,0x02,0x14,0x01,0xC7,0x50,0xE1,0xD6,0xB6,0x78,0x60,0xC3,0x20,0x83,0x20, ++ 0xD8,0x90,0x00,0x14,0x00,0x87,0x50,0x01,0xE8,0x76,0x10,0x09,0x00,0x14,0x00,0x5F, ++ 0x14,0x01,0xF0,0x12,0x10,0x52,0xE4,0x16,0xD0,0x90,0x02,0x14,0x00,0x27,0x50,0x01, ++ 0xD0,0x16,0x10,0x01,0x18,0x92,0x06,0x14,0xE2,0x00,0xE4,0xD8,0x90,0xDD,0x5E,0x29, ++ 0x98,0xA6,0xC6,0x24,0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x44,0x71,0x98,0x16, ++ 0x20,0x01,0x00,0x01,0x08,0x01,0x10,0x01,0x94,0x1C,0x50,0x82,0x04,0x18,0xC3,0xD0, ++ 0x5E,0x82,0xC4,0xA8,0x30,0x72,0x19,0x01,0x15,0x01,0xF0,0x52,0xC0,0x80,0x90,0x05, ++ 0xE0,0x48,0x92,0x4D,0xFD,0x1C,0x10,0xD2,0xE8,0x06,0x90,0x1C,0xAA,0x51,0xE0,0xD8, ++ 0x90,0xDD,0x5E,0x71,0x98,0x86,0x87,0x27,0xC8,0xCF,0x95,0x2D,0xC5,0x14,0x10,0x42, ++ 0xD0,0x06,0xA8,0x14,0x00,0x01,0x80,0x24,0x68,0x01,0xE8,0xDE,0x3F,0x01,0xF8,0xBA, ++ 0x10,0x7A,0xDD,0x96,0x60,0x01,0x80,0x0E,0x60,0x21,0x88,0x16,0xD9,0xC0,0x03,0x84, ++ 0x00,0xB7,0x08,0x19,0xC0,0x1C,0x80,0x27,0xCD,0x0F,0x15,0x42,0xD7,0x86,0x78,0x40, ++ 0xCA,0x00,0x82,0x00,0xD1,0xC0,0x01,0x84,0x00,0x57,0x78,0x01,0xE8,0x46,0x00,0x09, ++ 0x00,0x84,0x01,0x2F,0x01,0x01,0xF0,0x82,0x10,0x42,0xE5,0x0E,0xD9,0x00,0x02,0x84, ++ 0xB0,0x51,0xC0,0x24,0xE6,0x00,0x92,0x05,0x80,0x24,0xC0,0x24,0x46,0x71,0x98,0x9E, ++ 0xE7,0x20,0x93,0x25,0x65,0x29,0x98,0x66,0x43,0x2A,0x4B,0x32,0xC0,0x03,0xC0,0x4B, ++ 0x33,0x22,0x58,0x4A,0x50,0x4A,0x1B,0x62,0x88,0xB6,0x01,0x01,0x4A,0x1A,0x03,0x20, ++ 0xC3,0x08,0x63,0x22,0xCB,0x60,0x68,0x1A,0xAA,0x51,0xC8,0x68,0x31,0xF9,0x0C,0xB0, ++ 0xC8,0x78,0x34,0x01,0xF8,0xF2,0x3D,0x01,0xFD,0x7A,0x17,0xF2,0xD0,0x3E,0x28,0x01, ++ 0xF8,0x2A,0x6B,0xA1,0xE8,0x1E,0x78,0x79,0xEB,0x0E,0x00,0x68,0x02,0x2C,0x61,0xD2, ++ 0xA0,0x51,0xC8,0x60,0xC4,0x70,0xC6,0x68,0x0B,0x01,0xF0,0x4A,0x2B,0x01,0xF8,0xAA, ++ 0x10,0x4A,0xD5,0x66,0x0B,0x01,0xF0,0x0A,0x48,0xA1,0xE8,0x46,0x68,0x79,0xE8,0x36, ++ 0x7B,0x70,0xC6,0xA8,0x83,0x68,0x03,0x70,0xCB,0x68,0xC5,0x48,0x02,0x0C,0xE1,0x00, ++ 0x90,0x05,0x46,0x29,0x9C,0x56,0x36,0xFF,0x47,0x01,0x80,0xE6,0x22,0x01,0x40,0x3A, ++ 0x00,0x08,0xC3,0x68,0x41,0x3A,0xC2,0x70,0x40,0x32,0x82,0x51,0xC4,0x40,0x09,0xF9, ++ 0x0B,0x48,0xC0,0x78,0x10,0x01,0x08,0x01,0xF2,0xD2,0xF5,0x0A,0x10,0x52,0xD4,0x6E, ++ 0x01,0x01,0xF0,0x82,0x81,0x2C,0x40,0x41,0xE8,0x46,0x48,0x79,0xEC,0x36,0x00,0x00, ++ 0x08,0x29,0x80,0x27,0xC8,0x1F,0xC9,0x2C,0xC1,0x00,0x02,0x84,0x40,0xD2,0x81,0x51, ++ 0xC1,0x40,0x49,0xD2,0xC0,0x48,0x1B,0x01,0x17,0x01,0xF0,0xDA,0xF4,0x52,0x14,0x9A, ++ 0xD0,0x3E,0x08,0x01,0xF1,0x0A,0x4A,0x41,0xE8,0x1E,0x50,0x79,0xEA,0x0E,0x00,0x48, ++ 0x03,0x0C,0xE0,0x20,0x90,0x25,0x67,0x29,0x9B,0x4E,0x36,0x2F,0xA9,0xC5,0x47,0x52, ++ 0x17,0x09,0x80,0x01,0xC0,0x0B,0x18,0x8A,0x81,0x0B,0x68,0x3A,0x79,0x22,0x31,0x62, ++ 0xA4,0x01,0x06,0x27,0xBB,0xFF,0xEF,0xFF,0x48,0x4A,0x41,0x43,0xE0,0x00,0x02,0x43, ++ 0x40,0x42,0xC1,0x03,0x40,0x01,0x80,0x0E,0x05,0xC1,0xB0,0x43,0x40,0xF2,0x80,0x1F, ++ 0xE9,0x17,0x51,0x2A,0x48,0xEA,0x40,0xE2,0x86,0x1F,0xC8,0x6F,0xB9,0xFF,0xEF,0x7F, ++ 0x01,0x11,0x88,0x03,0x50,0x02,0x49,0xC2,0x40,0xC2,0x80,0x1F,0xD8,0x67,0x55,0xF2, ++ 0x48,0xAA,0x40,0xB2,0x86,0x1F,0xF8,0x17,0xC8,0x03,0x43,0x01,0x83,0x16,0xC8,0x03, ++ 0x40,0x11,0x88,0x26,0x48,0xCA,0x40,0x43,0x10,0x09,0x18,0x82,0x00,0x43,0x48,0x72, ++ 0x40,0x72,0x80,0x1F,0xF0,0x77,0x73,0x5A,0xC1,0xCB,0xC1,0x83,0x18,0x42,0x80,0x0E, ++ 0x05,0x01,0xA8,0x43,0xBA,0xFF,0xF7,0xC7,0x41,0x8A,0xC0,0x8B,0x09,0x0C,0xC6,0xCB, ++ 0x11,0x0C,0xC8,0x4B,0x10,0x0C,0x72,0x22,0xB5,0x01,0xE2,0x8B,0x10,0x0C,0x04,0xCF, ++ 0x00,0x48,0x00,0x01,0x00,0x40,0x00,0x01,0x00,0xE0,0x00,0x01,0x08,0x40,0x00,0x01, ++ 0x18,0x10,0x00,0x00,0x48,0xE0,0x06,0x00,0x50,0xA0,0x02,0x00,0x50,0x50,0x02,0x00, ++ 0x00,0xA0,0x00,0x01,0x00,0x20,0x00,0x01,0x80,0xC0,0x04,0x01,0xF8,0x00,0x06,0x42, ++ 0x70,0x40,0x04,0x01,0x48,0xA2,0x40,0x4C,0x10,0x0C,0x4E,0xA2,0x40,0x4B,0x18,0x0C, ++ 0xA2,0x48,0x18,0x0C,0xEC,0x4B,0x1D,0x0C,0xBA,0xFF,0xEF,0x57,0x05,0x11,0xA0,0x83, ++ 0x32,0x8A,0xC9,0x01,0x40,0x72,0x80,0x1F,0xE9,0xCF,0x31,0x8A,0x12,0x09,0xC8,0x01, ++ 0x40,0x5A,0x58,0x62,0x81,0x17,0xE8,0x07,0xBC,0xFF,0xDF,0x97,0x32,0x8A,0xC9,0x01, ++ 0x40,0x3A,0x80,0x0F,0xF0,0x0F,0x83,0x07,0xDF,0xCF,0xBA,0xFF,0xE3,0xE7,0xCE,0x03, ++ 0x40,0x31,0x80,0x06,0x3F,0xB7,0xEB,0xC5,0x00,0x60,0x00,0x01,0x00,0xA0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x30,0x48,0x00,0x00,0xA8,0x85,0x33,0x22,0xF0,0x03,0x87,0x07, ++ 0xF2,0x5F,0x46,0x7A,0x2C,0x01,0x00,0x2B,0xB6,0x2B,0x05,0x21,0xAF,0x2A,0xB8,0xFF, ++ 0xE5,0xE7,0xA1,0x01,0xCA,0x03,0x33,0x08,0x42,0x52,0x72,0x48,0x1C,0x0B,0x5C,0x0B, ++ 0x02,0x48,0x1A,0x0B,0x0B,0x2B,0xCE,0x0B,0x30,0x48,0xA8,0x16,0x0E,0x09,0x04,0x0B, ++ 0x1B,0x2B,0xE8,0x85,0xAD,0x85,0x87,0xAD,0x42,0x12,0xC2,0x01,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x52,0x02,0x4A,0x0A,0x40,0x0A,0x82,0x0F,0xCA,0xE7,0x40,0x0A, ++ 0x71,0xFA,0xC1,0x80,0x81,0xA4,0x41,0xEA,0xB6,0xE1,0x81,0x01,0x83,0x9C,0x01,0x47, ++ 0x47,0xD2,0xB9,0xFF,0xF9,0x4F,0x66,0xCA,0x52,0x03,0x83,0x01,0xE7,0x03,0x40,0x79, ++ 0x81,0x06,0x31,0x12,0x48,0xB2,0x01,0x01,0x58,0x9A,0x81,0x07,0xF9,0x8F,0x36,0x12, ++ 0x48,0x9A,0x01,0x09,0x58,0x82,0x81,0x07,0xFB,0x5F,0x56,0x03,0x80,0x01,0xE2,0x03, ++ 0x40,0x59,0x8D,0x7E,0xC1,0xA4,0x31,0x8A,0x13,0x01,0xD8,0x1B,0xDB,0x2B,0x19,0x5A, ++ 0x40,0x6C,0x40,0x3C,0xD8,0x68,0x07,0x2C,0xE4,0x00,0xE4,0x48,0xE4,0x90,0x92,0x95, ++ 0x17,0xD2,0x9C,0xAE,0x52,0x03,0x83,0x01,0xE5,0x03,0x40,0x59,0x81,0x2E,0x50,0x12, ++ 0x49,0x12,0x41,0x1A,0x58,0x0D,0x80,0x0F,0xC1,0x37,0xEC,0xA4,0x30,0xA2,0x39,0x01, ++ 0x01,0x01,0xF0,0x42,0x0A,0x99,0x18,0x42,0x08,0x51,0x80,0x1F,0xF9,0xBF,0x07,0x44, ++ 0x01,0x01,0xF0,0x02,0x0A,0x99,0x18,0x42,0x08,0x51,0x80,0x1F,0xF9,0x7F,0x07,0x04, ++ 0xE5,0x68,0xE5,0x20,0xE7,0xF8,0x93,0xFD,0x7F,0x29,0x98,0x4E,0x68,0xB2,0x60,0xA2, ++ 0xA0,0xF1,0x3D,0x01,0x01,0x01,0xF0,0x42,0x08,0x51,0x08,0x00,0x86,0x1F,0xF8,0xF7, ++ 0x00,0x44,0x01,0x01,0xF0,0x02,0x09,0x51,0x08,0x00,0x80,0x1F,0xF9,0xBF,0x06,0x04, ++ 0xE5,0x68,0xE5,0x20,0xE7,0xF8,0x93,0xFD,0x7F,0x29,0x98,0x5E,0x40,0x0D,0x80,0x07, ++ 0xD9,0x9F,0xC2,0x9C,0xC8,0x03,0x42,0x31,0x81,0x96,0x84,0xAD,0xE8,0x85,0x07,0x00, ++ 0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x80,0xC0,0x04,0x01,0x00,0xE0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x48,0xE0,0x06,0x00,0x58,0x30,0x03,0x01,0x48,0xFA,0xFF,0x53, ++ 0x84,0x13,0xF8,0x53,0x80,0x13,0x32,0x52,0x96,0x01,0xCE,0x93,0x80,0x13,0xCC,0x4B, ++ 0x83,0x0B,0x3E,0x82,0xA8,0xF5,0x37,0x2A,0x46,0xC2,0xFF,0x03,0x12,0x42,0xCD,0xBE, ++ 0x07,0x21,0x61,0xBA,0x18,0x42,0xCB,0x20,0x02,0x99,0x0B,0x00,0xC0,0x20,0x39,0xA1, ++ 0xF8,0x3A,0x37,0xB1,0xF8,0x32,0x9D,0x0C,0x48,0x09,0x88,0x1E,0x07,0xF9,0x87,0x09, ++ 0xD8,0x00,0x96,0x3D,0x50,0x09,0x88,0x1E,0x02,0xC9,0x08,0x00,0xD8,0x00,0x94,0x35, ++ 0xC8,0x03,0x85,0x04,0x06,0x81,0xDF,0x00,0x0A,0xE1,0x19,0x42,0x08,0x81,0x87,0x1F, ++ 0xFE,0x2F,0xCC,0x00,0x93,0x05,0x40,0x71,0xD3,0x06,0x00,0x71,0x0B,0xF9,0x8F,0x99, ++ 0x10,0x42,0xEC,0x06,0x30,0x42,0xC8,0x04,0xC8,0x13,0x0F,0x48,0x00,0x90,0x1A,0x8A, ++ 0xD0,0x0C,0x80,0x8B,0xF8,0x0C,0x88,0x08,0x81,0xCB,0x8B,0x88,0x81,0xCB,0x3D,0x88, ++ 0x08,0x00,0x78,0x48,0x1F,0x42,0x80,0xC3,0xE3,0xF8,0xE7,0xF8,0x58,0x04,0x09,0xA1, ++ 0x82,0x1F,0xF8,0xD7,0x86,0x51,0x90,0x05,0x40,0xF9,0x97,0x56,0x5A,0xAA,0xEE,0xCA, ++ 0x30,0x52,0x90,0x51,0x10,0x12,0x94,0x16,0x82,0xC3,0xA9,0xC2,0x01,0x1F,0x80,0xCB, ++ 0x07,0x0F,0x00,0xF9,0x80,0xC3,0xC1,0x44,0xC8,0x44,0xC0,0x03,0xE8,0x00,0x82,0x43, ++ 0xEF,0xF5,0xAF,0x85,0x80,0x2D,0x34,0x01,0x00,0x5D,0x46,0x03,0x86,0x14,0x40,0x3A, ++ 0xF8,0x1B,0x14,0x09,0x06,0x01,0x48,0x4A,0x60,0x4A,0xC6,0x6B,0x68,0x59,0x85,0x16, ++ 0xE5,0x00,0x12,0x02,0x9F,0xCE,0x07,0xF9,0x80,0x43,0x58,0x01,0x80,0xBE,0x30,0x01, ++ 0x48,0x15,0x00,0x01,0x25,0x99,0x5B,0xF2,0x08,0x20,0x03,0x77,0x2A,0x21,0x19,0x2A, ++ 0xC1,0x68,0xCF,0x68,0xD0,0x6B,0x69,0x09,0x88,0x2E,0x80,0x43,0xE7,0xB0,0x93,0xB5, ++ 0xE0,0x48,0x72,0x09,0x82,0x1E,0xE0,0x00,0x94,0x05,0x16,0x82,0x98,0x76,0x77,0x01, ++ 0x85,0x16,0x63,0xB2,0x68,0x15,0x38,0x01,0x47,0x82,0x85,0x01,0x81,0x1C,0x00,0x0F, ++ 0x78,0x01,0x88,0x9E,0x50,0x0D,0x90,0x04,0x11,0x01,0xC0,0x43,0x30,0x1A,0x31,0x8A, ++ 0xBB,0xFF,0xFF,0x07,0xE0,0x68,0xC3,0x1C,0xC6,0x03,0x4C,0x00,0x09,0x00,0x1E,0x82, ++ 0x8D,0x03,0x03,0x59,0x8D,0x03,0xED,0x20,0xE0,0x20,0x03,0x4F,0x50,0x0D,0x90,0x04, ++ 0x11,0x01,0xC0,0x43,0x30,0x1A,0x31,0x8A,0xBA,0xFF,0xFF,0x67,0xE3,0x68,0xEB,0x20, ++ 0xE7,0xF8,0x93,0xFD,0x16,0xBA,0x9D,0xDE,0xC4,0x1C,0x18,0x01,0xC6,0x03,0x4C,0x08, ++ 0x48,0x01,0x80,0x9E,0x70,0x01,0x80,0x3E,0x80,0x03,0xC1,0x1C,0xCB,0x03,0x80,0x03, ++ 0x05,0x59,0x85,0x03,0xE0,0x20,0x05,0x3F,0x80,0x03,0xC1,0x1C,0xCB,0x03,0x80,0x03, ++ 0x8D,0x1B,0x03,0x59,0x8D,0x03,0xED,0x20,0xE0,0x20,0x03,0x27,0x70,0x09,0xC8,0x16, ++ 0x01,0x59,0x85,0x03,0xE1,0x20,0x33,0x02,0xB8,0xFF,0xFF,0xC7,0x42,0x8A,0x44,0x0B, ++ 0x10,0x01,0x1A,0x8A,0x04,0x0B,0x4A,0x82,0x40,0x43,0x1A,0xC2,0x04,0x43,0x62,0x7A, ++ 0x42,0x03,0x41,0x00,0x01,0x00,0x02,0x03,0x04,0xF9,0x87,0x89,0x85,0x1F,0xE8,0xE7, ++ 0x40,0x03,0x09,0x09,0x19,0x42,0x00,0x03,0x87,0x2D,0xE8,0x85,0xAC,0xFD,0x87,0x0D, ++ 0xF8,0x54,0x30,0x32,0x33,0x62,0x68,0xEA,0xA8,0x01,0x57,0x09,0x88,0x4E,0x00,0x0F, ++ 0x87,0x07,0xF8,0xE7,0xC2,0x43,0x31,0x00,0xA9,0xD6,0xC7,0x43,0x08,0xF9,0x05,0x42, ++ 0x80,0x43,0x01,0x09,0x33,0x22,0x54,0xE2,0x01,0x8F,0x61,0x01,0xC3,0x2E,0xF0,0x00, ++ 0x08,0x01,0x1F,0x42,0x09,0x83,0x32,0x0A,0x07,0x17,0x00,0xF9,0x09,0x83,0x0A,0x01, ++ 0x1C,0x01,0x08,0x9B,0x00,0x01,0x00,0x4F,0x78,0x01,0x88,0x16,0x1E,0x01,0x00,0x9B, ++ 0x01,0x17,0xC0,0x9B,0x07,0x9B,0xCE,0xB0,0xE4,0x00,0x92,0x05,0x17,0x42,0x9C,0x9E, ++ 0x30,0x02,0x43,0x01,0x80,0x26,0x00,0xA1,0x00,0x83,0x04,0x01,0x30,0x22,0x04,0x0F, ++ 0x04,0x21,0x00,0x83,0xD4,0x00,0x93,0x25,0x44,0x83,0x0A,0x01,0x1A,0x42,0x00,0x83, ++ 0xC2,0x43,0x31,0x00,0xA9,0xE6,0xC7,0x43,0x08,0xF9,0x05,0x42,0x80,0x43,0x61,0x01, ++ 0x88,0x5E,0xC6,0x24,0x45,0x09,0x88,0x7E,0x04,0x01,0x00,0x83,0x44,0x83,0x0A,0x01, ++ 0x1A,0x42,0x00,0x83,0x3F,0x47,0xAD,0x9D,0x80,0x1D,0x24,0x01,0x00,0x01,0x80,0x0C, ++ 0x72,0x15,0x40,0x92,0xF2,0x03,0xEC,0x00,0x92,0x3D,0x6E,0x82,0xA9,0x01,0x07,0xAF, ++ 0x85,0x07,0xF8,0x27,0xC2,0x43,0x31,0x00,0xA2,0x1E,0x40,0x62,0xF5,0x03,0x14,0xC2, ++ 0x9A,0xB6,0x47,0x52,0xF5,0x03,0x14,0xC2,0x98,0x06,0x20,0x11,0xC5,0x43,0x09,0xF9, ++ 0x01,0x42,0x80,0x43,0x44,0x62,0x42,0x0B,0x10,0x79,0x06,0x8A,0x48,0x09,0x88,0x9E, ++ 0x0C,0x01,0x08,0x0B,0x41,0x0B,0x86,0x8B,0xE3,0xB0,0xE3,0x20,0x90,0x25,0x67,0x11, ++ 0x8B,0x56,0x30,0x5A,0xD0,0xCB,0xD0,0x1C,0x10,0x8A,0x8C,0x2E,0xD0,0xCB,0xD2,0x24, ++ 0x10,0x8A,0x8C,0x0E,0x08,0x09,0x88,0x0C,0x0A,0x01,0x0F,0x0B,0x0C,0x01,0x08,0x0B, ++ 0x0C,0x81,0x00,0x0B,0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x66,0x11,0x88,0x4E, ++ 0xC3,0x0C,0x38,0x0F,0x48,0x8A,0x61,0x54,0x80,0x13,0x10,0x01,0x86,0x13,0xE2,0x4B, ++ 0x81,0x0B,0x4C,0xB2,0x8C,0x01,0x5A,0x53,0x82,0x13,0x5E,0x53,0x88,0x13,0x10,0xA9, ++ 0x88,0x13,0x12,0x19,0x8E,0x13,0x4C,0x53,0x8C,0x13,0x4E,0x53,0x92,0x13,0x48,0x4B, ++ 0x90,0x0B,0x0A,0x31,0x93,0x0B,0x3C,0x82,0xAC,0x85,0x87,0x4D,0x30,0x22,0x30,0x01, ++ 0x00,0x01,0x80,0x2C,0x39,0x01,0x48,0x0A,0xDA,0x43,0xD8,0x4B,0x18,0x42,0x82,0x14, ++ 0x40,0xFA,0x80,0x71,0x80,0x24,0xC0,0x71,0x80,0x1C,0x60,0x09,0x80,0x0E,0x60,0x29, ++ 0x88,0x7E,0x60,0x09,0x89,0x26,0x70,0x12,0xE0,0x80,0x83,0x2C,0x78,0x0A,0x01,0x27, ++ 0x73,0x0A,0xE1,0x80,0x80,0x2C,0x78,0xFA,0xF8,0xC1,0x41,0x35,0xB9,0xFF,0xF7,0x37, ++ 0x00,0x3F,0x60,0x21,0x88,0x2E,0x70,0xEA,0x47,0x35,0xB8,0xFF,0xF8,0xDF,0x7D,0xCA, ++ 0xB8,0x11,0x6B,0x72,0xA9,0x01,0xC7,0x43,0x08,0xF9,0x05,0x42,0x81,0x43,0xC1,0x43, ++ 0x08,0x01,0x19,0x42,0x80,0x43,0x41,0x7A,0x42,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B, ++ 0x42,0x6A,0x40,0x0B,0x10,0x01,0x1C,0x8A,0x00,0x0B,0x4A,0x62,0x40,0x43,0x10,0x09, ++ 0x18,0x82,0x00,0x43,0x0C,0x09,0x00,0x01,0x00,0xD7,0x00,0x00,0x00,0xE0,0x00,0x01, ++ 0x08,0x40,0x00,0x01,0x80,0x00,0x06,0x01,0x00,0xF8,0x07,0x00,0x80,0x30,0x02,0x01, ++ 0x30,0x04,0x05,0x08,0x00,0x00,0x06,0x42,0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42, ++ 0x18,0x60,0x05,0x01,0x70,0x70,0x06,0x01,0x50,0x20,0x07,0x01,0x68,0x60,0x02,0x01, ++ 0xB9,0xFF,0xFF,0xCF,0x43,0x09,0x88,0x2E,0x61,0x21,0x88,0x7E,0x10,0x09,0x90,0x04, ++ 0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF,0xF0,0xCF,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x59,0x40,0x35,0x37,0x9A,0xB8,0xFF,0xF0,0x8F,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x09,0x29,0x30,0xC2,0x37,0x9A,0xB8,0xFF,0xF0,0x4F,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x0E,0x71,0x40,0x0A,0x37,0x9A,0xB8,0xFF,0xF0,0x0F,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x29,0x30,0x9A,0xC7,0x24,0xB8,0xFF,0xF0,0xCF,0x15,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x29,0x18,0x09,0xC7,0x1C,0xB8,0xFF,0xF1,0x8F,0x05,0x9F,0x60,0x09,0x80,0x0E, ++ 0x61,0x29,0x88,0x7E,0x10,0x11,0x90,0x04,0x11,0x09,0x30,0x82,0x18,0x01,0xC8,0x14, ++ 0xBD,0xFF,0xF7,0x27,0x10,0x11,0x90,0x04,0x10,0x01,0x30,0x9A,0xC8,0x14,0xC0,0x2C, ++ 0xBC,0xFF,0xF7,0xE7,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x21,0x40,0x35,0x30,0x9A, ++ 0xBC,0xFF,0xF7,0xA7,0x10,0x09,0x90,0x04,0x11,0x01,0x08,0x31,0x30,0xC2,0x31,0x9A, ++ 0xBC,0xFF,0xF7,0x67,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x29,0x30,0x9A,0xC0,0x24, ++ 0xBC,0xFF,0xF7,0x27,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x29,0x18,0x09,0xC0,0x1C, ++ 0xBB,0xFF,0xF7,0xE7,0xC6,0x43,0x09,0xF9,0x01,0x42,0x80,0x43,0x40,0xDA,0x44,0x0B, ++ 0x42,0x48,0x02,0x48,0x04,0x0B,0x40,0xD2,0x0A,0x01,0x0F,0x0B,0x0C,0x01,0x00,0x0B, ++ 0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x87,0x4D,0xE8,0x85,0xAC,0x85,0x63,0xAA, ++ 0xC8,0x03,0x43,0x09,0x83,0x16,0xC8,0x03,0x40,0x29,0x88,0x86,0x46,0x8A,0xC4,0x01, ++ 0x82,0x1F,0xC8,0x4F,0x69,0x82,0xC4,0x43,0x40,0x11,0x98,0x2E,0xCF,0x03,0xBB,0xFF, ++ 0xF8,0x5F,0x00,0x01,0x83,0x43,0xE9,0x85,0xE1,0x00,0x82,0x43,0xEB,0x85,0xCB,0x03, ++ 0x40,0x21,0x88,0x26,0xB8,0xFF,0xFF,0x07,0x03,0x19,0x88,0x03,0xEB,0x85,0xCB,0x03, ++ 0x47,0x19,0x80,0xDE,0xC8,0x03,0x43,0x31,0x84,0xC6,0x47,0x12,0xC4,0x01,0xFE,0x03, ++ 0x40,0x01,0x88,0x3E,0x41,0xFA,0x83,0x01,0xD0,0x0B,0x48,0x31,0x9C,0x76,0xC7,0x03, ++ 0x37,0x00,0xA8,0x5E,0x44,0xDA,0xC3,0x01,0xE8,0x03,0x44,0x01,0x8F,0x36,0xBF,0xFF, ++ 0xEB,0xC7,0xEC,0x85,0xA8,0xC5,0x27,0x01,0x30,0x1A,0x00,0x09,0x4B,0xAA,0x6B,0xBA, ++ 0x30,0x01,0x59,0x51,0x80,0xE6,0xE1,0x4E,0x79,0xAA,0xC3,0xD3,0x85,0x1F,0xE8,0x6F, ++ 0x61,0x52,0x20,0x09,0x39,0x61,0x62,0x52,0x71,0x61,0x62,0x92,0x40,0x6A,0x13,0x31, ++ 0xC2,0x01,0x56,0x03,0x80,0x01,0x5A,0xC9,0x80,0xAE,0xE1,0x4E,0x59,0x59,0x80,0x56, ++ 0x59,0x61,0x80,0x66,0x59,0x69,0x88,0xBE,0x02,0x29,0x88,0x43,0x21,0x09,0x00,0x9F, ++ 0x59,0xD1,0x80,0x6E,0x59,0x01,0x89,0x7E,0x88,0x53,0x22,0x09,0x08,0x59,0xA5,0x0B, ++ 0x00,0x57,0x01,0x39,0x89,0x43,0x02,0x3F,0x86,0x07,0xE8,0x17,0x00,0x27,0x19,0x12, ++ 0x81,0xD3,0x01,0x0F,0x00,0x41,0x18,0x12,0x80,0xD3,0x01,0xEF,0x02,0x11,0x88,0x43, ++ 0x20,0x09,0x00,0xCF,0x02,0x01,0x88,0x43,0x41,0x43,0x19,0x82,0x00,0x43,0x01,0x9F, ++ 0x88,0x43,0x22,0x09,0x00,0x87,0x00,0x19,0x88,0x43,0x22,0x09,0x00,0x67,0x00,0x21, ++ 0x88,0x43,0x22,0x09,0x02,0x47,0x88,0x53,0x26,0x09,0x08,0x69,0xA0,0x0B,0x00,0x1F, ++ 0x88,0x53,0x22,0x09,0x08,0x79,0xA7,0x0B,0x60,0x01,0x80,0x66,0x40,0x6A,0x42,0x0B, ++ 0x30,0x48,0xA8,0x2E,0x08,0x81,0x06,0x0B,0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B, ++ 0x45,0x43,0x19,0x82,0x07,0x43,0xE9,0xC5,0xAC,0x8D,0x87,0x15,0x40,0x32,0x82,0x0C, ++ 0x46,0x02,0xC2,0x01,0xDA,0x2B,0xD8,0x33,0x0C,0x01,0xB0,0x0B,0x61,0x02,0xC2,0x0B, ++ 0x10,0xF9,0x05,0x8A,0x81,0x0B,0xC1,0x0B,0x10,0x01,0x19,0x8A,0x81,0x0B,0x49,0xEA, ++ 0x8A,0x01,0x46,0x53,0x18,0x01,0x1A,0xD2,0x01,0x53,0x52,0xAA,0x44,0x8B,0x1A,0x01, ++ 0x1A,0xCA,0x00,0x8B,0x48,0x8A,0x41,0x53,0x18,0x09,0x18,0xD2,0x02,0x53,0x50,0x03, ++ 0x80,0x01,0xE2,0x0B,0x49,0x79,0x87,0xAE,0xE6,0x03,0x40,0x69,0x88,0x16,0x09,0xA9, ++ 0x07,0x91,0xB8,0xFF,0xE8,0x47,0x47,0x09,0x89,0xDE,0x31,0x42,0x1A,0x82,0x03,0x38, ++ 0x15,0x09,0x90,0xCD,0x90,0x04,0x18,0x01,0xC7,0x0C,0xB8,0xFF,0xE9,0x3F,0x44,0x5A, ++ 0x10,0x09,0x90,0x04,0x15,0x01,0x90,0xCD,0x37,0x9A,0xB8,0xFF,0xE8,0xFF,0xC3,0x14, ++ 0x15,0x09,0xC8,0x48,0xE8,0x48,0x90,0x04,0x00,0x48,0x12,0x01,0x1F,0x09,0xB8,0xFF, ++ 0xE8,0xAF,0x03,0xF7,0x08,0xA1,0x00,0x91,0xBE,0xFF,0xEF,0x2F,0x40,0x09,0x88,0xC6, ++ 0x18,0xAA,0x13,0x09,0x20,0x40,0x63,0x08,0x90,0x04,0x30,0x9A,0xC7,0x0C,0xB8,0xFF, ++ 0xE8,0x2F,0x03,0x77,0x08,0xB1,0x00,0x91,0xBD,0xFF,0xEF,0xAF,0x40,0x09,0x88,0x46, ++ 0xC0,0x14,0x10,0x09,0xC8,0x48,0xED,0x48,0x00,0x48,0x32,0x9A,0x97,0x04,0xB8,0xFF, ++ 0xE9,0xAF,0xC2,0x03,0x08,0xF9,0x06,0x42,0x80,0x03,0x41,0x42,0x42,0x0B,0x40,0x48, ++ 0x00,0x48,0x02,0x0B,0x47,0x32,0x08,0x01,0x08,0x0B,0x0A,0x01,0x02,0x0B,0x44,0x0B, ++ 0x10,0x01,0x1C,0x8A,0x07,0x0B,0xEA,0xF5,0x70,0x00,0x04,0x01,0xF8,0x00,0x06,0x42, ++ 0x80,0x01,0x06,0x42,0x00,0xE0,0x06,0x01,0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x42, ++ 0x00,0xE0,0x07,0x01,0x00,0x00,0x00,0x42,0x50,0x20,0x07,0x01,0x08,0x20,0x02,0x01, ++ 0x52,0xE2,0x43,0x83,0x03,0x83,0x42,0xE2,0xF7,0x0B,0x4C,0xF9,0x94,0x16,0xF0,0x0B, ++ 0xE4,0x48,0xB2,0x0B,0xF0,0x03,0x44,0xC1,0x90,0x0E,0x00,0x01,0x03,0x83,0x3C,0x82, ++ 0x4C,0xB2,0x4B,0x53,0x5C,0xA2,0xE3,0xC3,0x1C,0x12,0x0C,0x53,0x10,0x43,0x02,0x09, ++ 0xB3,0xC3,0x3C,0x82,0xAB,0x85,0x40,0x8A,0x84,0x01,0x42,0x0B,0x10,0x01,0x1C,0x8A, ++ 0x03,0x0B,0x54,0x7A,0x4B,0x62,0x43,0x7A,0x86,0x1F,0xC0,0x97,0xEF,0x85,0xA8,0xC5, ++ 0x47,0x4A,0x83,0x01,0xC3,0x0B,0x70,0x62,0x30,0x48,0xAC,0x46,0xC2,0x0B,0x10,0x01, ++ 0x18,0x8A,0x80,0x0B,0x44,0x83,0x0B,0x01,0x1B,0x42,0x04,0x83,0xE8,0xC5,0x0F,0x01, ++ 0x0D,0x8B,0x45,0x9B,0x66,0x02,0x03,0x79,0x01,0x1A,0x30,0x2A,0xAB,0x01,0x69,0x04, ++ 0x50,0x13,0x5B,0x09,0x80,0xE6,0x58,0x29,0x80,0x46,0x58,0x41,0x8B,0xB6,0x93,0x4B, ++ 0x46,0x9B,0x3F,0xD8,0x88,0x16,0x00,0x81,0x07,0x83,0xED,0xC5,0x0A,0x8B,0x4D,0xDA, ++ 0x10,0x42,0x8C,0x16,0x07,0x29,0x05,0x83,0x00,0x3F,0xE0,0x92,0x02,0x93,0xE7,0x00, ++ 0x93,0x05,0x2C,0x04,0x40,0x89,0x9A,0x06,0x28,0x0C,0x03,0xA1,0x07,0x83,0xED,0xC5, ++ 0x5B,0x9A,0xD2,0x7B,0x40,0xDC,0x78,0x11,0x90,0x56,0x7B,0x01,0x8F,0x36,0x40,0x83, ++ 0x50,0x7A,0x02,0x84,0x43,0x7A,0x12,0x03,0x2C,0x0C,0x03,0x1F,0x40,0x83,0x17,0xD0, ++ 0x48,0x5A,0xC2,0x80,0x90,0x3D,0x04,0x7C,0x00,0x89,0x16,0x00,0xD1,0xC0,0x41,0x01, ++ 0xC7,0x96,0x90,0xC5,0xBC,0xFF,0xF7,0x37,0x44,0x3A,0x12,0x3A,0x82,0x96,0x43,0x32, ++ 0x84,0x41,0x10,0x3A,0x88,0x76,0x03,0x09,0x86,0x07,0xC8,0x37,0x05,0xC1,0xB0,0x03, ++ 0x40,0x12,0x0A,0x09,0x83,0x0B,0x00,0x2F,0x46,0xBA,0x81,0x01,0xC8,0x03,0x42,0x01, ++ 0x89,0x26,0x41,0xEA,0xC4,0x31,0x16,0x3A,0x89,0xAE,0x40,0xEA,0x41,0x0B,0x40,0xCA, ++ 0x72,0x50,0x80,0x01,0x80,0x13,0x60,0x50,0x80,0x13,0x52,0x50,0x86,0x13,0x84,0x0B, ++ 0xC2,0x0B,0xC0,0x13,0xC4,0x48,0xC4,0x13,0xC6,0x1B,0xC6,0x90,0xC5,0x48,0x8C,0x29, ++ 0x50,0x50,0x88,0x13,0x88,0x0B,0x02,0x69,0x19,0x00,0xD0,0xC0,0x40,0x81,0xC2,0x0E, ++ 0x29,0x04,0x03,0xFF,0x06,0x01,0x18,0x02,0x29,0x04,0x03,0xDF,0x41,0x6A,0xC1,0xC0, ++ 0x40,0x19,0xC1,0x26,0x29,0x04,0x43,0x62,0x11,0x03,0x03,0x9F,0x01,0xC7,0x41,0x4A, ++ 0xC1,0x81,0xC1,0xC0,0x40,0x01,0xC1,0x26,0x29,0x04,0x43,0x3A,0xC3,0x01,0x11,0x03, ++ 0x00,0x47,0x01,0x69,0x19,0x00,0xD0,0xC0,0x41,0xB1,0xC1,0x1E,0x29,0x04,0x03,0x0F, ++ 0x7D,0xD2,0x10,0xC2,0x87,0xF6,0x40,0xBB,0xA0,0xBA,0x40,0xDA,0xC4,0xD1,0x15,0x1A, ++ 0x8B,0x7E,0x68,0x04,0x40,0x61,0x8A,0x66,0x50,0x1B,0xE3,0xFA,0x52,0x72,0x90,0x01, ++ 0x78,0x01,0x8C,0x16,0x04,0x09,0xA8,0x83,0x00,0x1F,0xE0,0xC2,0x40,0x01,0x88,0x06, ++ 0xAB,0x8B,0x6C,0x04,0xE4,0x00,0x92,0x05,0x2A,0x04,0x43,0x89,0x98,0x16,0x00,0x01, ++ 0x1B,0x02,0x2E,0x04,0xD2,0x43,0xE3,0x00,0x90,0x43,0x03,0x81,0x07,0x83,0xED,0xC5, ++ 0x07,0x8B,0xED,0xC5,0x10,0x00,0x00,0x42,0x00,0xE0,0x00,0x01,0xF8,0x00,0x06,0x42, ++ 0x80,0xC0,0x04,0x01,0x08,0x40,0x00,0x01,0x80,0x01,0x06,0x42,0xF8,0xFF,0x07,0x00, ++ 0x00,0x10,0x00,0x01,0x80,0x30,0x02,0x01,0x88,0x36,0x00,0x00,0x00,0x20,0x00,0x01, ++ 0x00,0xA0,0x00,0x01,0x77,0x81,0xF8,0xFF,0xF8,0x02,0x07,0x00,0xA8,0x85,0x80,0x07, ++ 0xC8,0xBF,0x65,0x32,0xC8,0x03,0x43,0x01,0x80,0x26,0x40,0x31,0x8F,0xD6,0xBF,0xFF, ++ 0xD7,0xCF,0x3B,0xBF,0xBD,0xFF,0xCF,0xD7,0x38,0xA7,0x07,0x00,0x00,0xE0,0x06,0x01, ++ 0xAF,0xC5,0x77,0x62,0x03,0x01,0x87,0x83,0x01,0x09,0x80,0x83,0x0F,0x01,0x81,0x8B, ++ 0x05,0x19,0x80,0x83,0x03,0x41,0x89,0x83,0x07,0x69,0x89,0x83,0x05,0x69,0x88,0x83, ++ 0x11,0x02,0x32,0xAA,0xA9,0x01,0x06,0x44,0x04,0xF9,0x87,0x89,0x20,0x84,0x01,0x09, ++ 0x34,0x62,0xE1,0x01,0x93,0x03,0x91,0x03,0x05,0x41,0x90,0x03,0x17,0x51,0x90,0x13, ++ 0x11,0xA1,0x98,0x13,0x98,0x0B,0x0D,0x81,0x99,0x0B,0xA7,0x03,0x3B,0x01,0xA0,0xBB, ++ 0x09,0x71,0x98,0x8B,0x0B,0x29,0x98,0x8B,0x17,0x71,0x98,0x93,0x99,0x8B,0xA5,0xBB, ++ 0xA1,0x83,0x05,0x81,0xA0,0x83,0x07,0x51,0x8F,0x03,0x01,0xB1,0x8D,0x03,0x8B,0x3B, ++ 0x8B,0x3B,0x9F,0x0B,0x05,0x99,0x28,0x84,0x07,0xF9,0x87,0x09,0x10,0x44,0x01,0xC9, ++ 0x0B,0x00,0x12,0x44,0x02,0x19,0x18,0x00,0x0E,0x43,0x43,0x5A,0x0A,0x43,0x05,0x01, ++ 0xB9,0x43,0x31,0x02,0x0D,0x51,0x80,0x11,0x83,0x1F,0xD0,0x17,0x01,0xB1,0x97,0x43, ++ 0x1B,0xF1,0x90,0x5B,0x89,0x7B,0x33,0x02,0x82,0x01,0xB2,0x3B,0xB8,0x3B,0x08,0xC1, ++ 0xB8,0x0B,0x0A,0x51,0xBE,0x0B,0x14,0x41,0x31,0x0A,0x88,0x01,0x0F,0x54,0x12,0xF9, ++ 0x94,0x99,0x0A,0x54,0x16,0xC1,0xBE,0x13,0x10,0x41,0x81,0x53,0x12,0x11,0x87,0x53, ++ 0x80,0x5B,0x14,0x51,0x91,0x13,0x12,0x41,0x93,0x13,0x14,0x21,0x92,0x13,0x16,0xA9, ++ 0x08,0x14,0x16,0x71,0x9A,0x13,0x10,0x69,0xA0,0x13,0x10,0x21,0xA6,0x13,0x12,0x41, ++ 0x10,0x14,0x12,0x31,0xBF,0x93,0x37,0xBC,0xB0,0x3B,0x1C,0x21,0x33,0x12,0x90,0x01, ++ 0x90,0x9B,0x1C,0x31,0x96,0x9B,0x12,0x99,0x08,0x94,0x11,0xA1,0x80,0x53,0x16,0x51, ++ 0x8E,0x53,0xB0,0x3B,0x12,0x21,0x8C,0x53,0x53,0x42,0x05,0x54,0x14,0x09,0x88,0x53, ++ 0x10,0x51,0x90,0x53,0x17,0x11,0xA0,0x13,0x08,0x21,0xA8,0x0B,0x0A,0xC1,0xAB,0x0B, ++ 0xA8,0x0B,0x1C,0x01,0x33,0x0A,0xC8,0x01,0xA0,0x5B,0xAE,0x5B,0x22,0xF1,0x88,0x01, ++ 0xBA,0x63,0xB8,0x63,0x24,0xE1,0xB9,0x63,0x26,0x41,0xB8,0x63,0x80,0x13,0x08,0xB1, ++ 0x80,0x0B,0x0A,0x19,0x84,0x0B,0x4C,0xD2,0x00,0x0B,0x92,0x1B,0x4C,0xCA,0xC4,0x01, ++ 0x38,0x0B,0x88,0x91,0x3E,0x0B,0x8A,0xE1,0x38,0x0B,0x0C,0xE1,0x40,0xB2,0x84,0x1F, ++ 0xCC,0xBF,0x47,0xAA,0x09,0xE1,0xC0,0xC1,0x87,0x1F,0xC8,0x97,0x4C,0x8A,0x44,0x9A, ++ 0xCE,0x11,0x03,0x0B,0xCC,0x71,0x00,0x0B,0x88,0xA1,0x08,0x0B,0x8A,0xA1,0x08,0x0B, ++ 0xCA,0xE1,0x01,0x0B,0xC8,0xC1,0x01,0x0B,0x8C,0x61,0x0D,0x0B,0xCA,0x81,0x15,0x0B, ++ 0xF8,0x48,0x10,0x0B,0xFE,0x48,0x08,0x0B,0xE9,0xC5,0xAF,0x85,0x0C,0x01,0x60,0x0A, ++ 0x47,0x02,0xA4,0x61,0xF8,0x1B,0x06,0x77,0x02,0x21,0x19,0x42,0xCB,0x28,0x00,0x99, ++ 0x12,0x79,0x08,0x00,0xC4,0x40,0x89,0x13,0x16,0x01,0x88,0x13,0x94,0x13,0x10,0x14, ++ 0x12,0x14,0xE6,0x48,0x94,0x4D,0x16,0x5A,0xC0,0x76,0x07,0x01,0x13,0xF9,0x2F,0x89, ++ 0x08,0x68,0x03,0x37,0x00,0x08,0xCA,0x48,0xCC,0x48,0xAA,0x53,0xAA,0x53,0xE6,0x00, ++ 0x94,0x05,0x16,0x1A,0xC1,0xB6,0xEF,0x85,0xA3,0x85,0x51,0x72,0x90,0x01,0x0E,0x01, ++ 0x26,0x8C,0xD0,0x01,0xBC,0x8B,0xB8,0x8B,0x36,0x9A,0x98,0x01,0x8A,0xCB,0x0C,0xCC, ++ 0x9E,0xCB,0x88,0xCB,0x2C,0x09,0xB0,0xAB,0xA8,0x8B,0x34,0xA2,0xA1,0x01,0xCD,0x1B, ++ 0xB0,0x9B,0x36,0x9A,0x9A,0x01,0xA9,0xCB,0x9A,0x01,0xA9,0xEB,0xA8,0xCB,0xA8,0xAB, ++ 0x28,0x41,0x89,0xAB,0x8B,0x0B,0x57,0x32,0x88,0x8B,0x46,0x09,0x8C,0x16,0xA8,0xCB, ++ 0xE5,0x85,0x39,0x97,0xE3,0x85,0x39,0x82,0x0B,0x08,0x42,0x12,0x41,0x13,0x18,0x01, ++ 0x04,0xD2,0x90,0x41,0x04,0x13,0x10,0xD0,0x1A,0x8A,0x08,0x0B,0x40,0x0B,0x42,0x0B, ++ 0x14,0x41,0x18,0x8A,0x00,0x0B,0x08,0x01,0x03,0x0B,0x3C,0x82,0xAA,0x85,0x40,0xD2, ++ 0x40,0x0B,0x30,0x48,0xAE,0x2E,0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B,0x08,0x81, ++ 0x02,0x0B,0x48,0xAA,0x8C,0x01,0x46,0x53,0x38,0x90,0x78,0x90,0x04,0x53,0x44,0x53, ++ 0x18,0x81,0x19,0xD2,0x02,0x53,0x5C,0x8A,0x12,0x09,0x06,0xD3,0x16,0x91,0x01,0x13, ++ 0x44,0x7A,0x42,0x23,0x10,0x61,0x18,0xA2,0x02,0x23,0x44,0x23,0x1A,0xA2,0x00,0x23, ++ 0x48,0x23,0x1A,0xA2,0x08,0x23,0x4A,0x23,0x18,0xA2,0x08,0x23,0x40,0x23,0x1E,0xA2, ++ 0x02,0x23,0x46,0x43,0x10,0x01,0x1A,0x82,0x04,0x43,0x02,0xD1,0x07,0xC3,0x00,0x01, ++ 0x08,0xC3,0xEA,0x85,0x40,0x12,0x42,0x13,0x08,0x09,0x18,0x52,0x00,0x13,0x48,0x13, ++ 0x18,0x52,0x0C,0x13,0x4C,0x13,0x1A,0x52,0x0E,0x13,0x42,0x13,0x1E,0x52,0x00,0x13, ++ 0x39,0x82,0x43,0xE2,0x58,0x0B,0x10,0x21,0x18,0x8A,0x18,0x0B,0x5A,0x0B,0x10,0x01, ++ 0x18,0x8A,0x18,0x0B,0x5C,0x13,0x08,0x01,0x18,0x52,0x18,0x13,0x40,0x92,0x11,0x01, ++ 0x80,0x01,0x06,0x13,0x40,0x13,0x1A,0x52,0x01,0x13,0x4A,0x72,0x41,0x43,0x10,0x01, ++ 0x18,0x82,0x00,0x43,0x38,0x82,0xAB,0x85,0x08,0x09,0x00,0x31,0x81,0x07,0xD0,0xF7, ++ 0x08,0x11,0x00,0x21,0x81,0x07,0xD0,0xD7,0x00,0x09,0x80,0x07,0xD0,0xB7,0x02,0x31, ++ 0x82,0x07,0xD0,0x9F,0x00,0x21,0x80,0x07,0xD0,0x87,0x82,0x07,0xD0,0x2F,0xEB,0x85, ++ 0xA8,0x85,0x43,0xF2,0x4A,0xBA,0xC0,0x91,0x11,0x43,0x0A,0x91,0x80,0x1F,0xC8,0x07, ++ 0x40,0xD2,0x08,0x51,0x80,0x41,0x81,0x1F,0xC7,0xEF,0xBF,0xFF,0xF0,0x4F,0x02,0x09, ++ 0xBA,0xFF,0xFF,0x17,0x07,0xA1,0xB8,0xFF,0xFF,0x3F,0xBB,0xFF,0xFF,0xBF,0xBB,0xFF, ++ 0xFF,0xC7,0xBD,0xFF,0xFF,0x3F,0xBD,0xFF,0xF8,0x77,0x66,0x8A,0x29,0x01,0x80,0x2B, ++ 0x08,0x2B,0x41,0x72,0x09,0x71,0x80,0x91,0x87,0x1F,0xC0,0x17,0x0B,0x2C,0x81,0x2B, ++ 0x87,0x2B,0x85,0x2B,0x8B,0x2B,0x89,0x2B,0x05,0x51,0x88,0x03,0x0F,0x2C,0x8B,0x2B, ++ 0x0B,0x2C,0xED,0x85,0x00,0xE0,0x00,0x01,0xC8,0x21,0x01,0x00,0x70,0x02,0x01,0x00, ++ 0xF8,0xFF,0x07,0x04,0x68,0x62,0x03,0x00,0x70,0x70,0x06,0x01,0x80,0xC0,0x04,0x01, ++ 0x00,0x20,0x00,0x01,0x10,0x00,0x00,0x42,0x00,0x00,0x00,0x42,0x80,0x01,0x06,0x42, ++ 0xF8,0x00,0x06,0x42,0x18,0x00,0x02,0x42,0xA8,0x85,0x80,0x07,0xC8,0xCF,0xEE,0x85, ++ 0xAF,0x85,0xB8,0xFF,0xE8,0x9F,0xEF,0x85,0xA8,0x7D,0x80,0x04,0x88,0x0C,0xC0,0x0C, ++ 0x80,0x14,0xC0,0x04,0x83,0x1C,0x30,0x42,0x40,0x7E,0x80,0x25,0xE8,0x05,0x00,0x00, ++ 0xAC,0xFD,0x87,0x1D,0x30,0x32,0x00,0x01,0x82,0x14,0x00,0x9F,0x44,0xDA,0x0E,0x01, ++ 0x0C,0x0B,0x26,0x01,0xC2,0x14,0x00,0x28,0x7F,0xC2,0x4E,0xC3,0x1F,0x02,0x09,0xC3, ++ 0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x86,0x17,0xE0,0x1F, ++ 0xF8,0x82,0x33,0x0A,0xCF,0x99,0x49,0xC9,0x99,0x3E,0x40,0x91,0xE7,0x16,0x48,0xC3, ++ 0x1F,0x02,0x0D,0xC3,0x40,0x20,0x63,0x01,0x88,0x36,0xD7,0x6C,0x90,0x04,0x10,0x09, ++ 0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x17,0xE3,0x77,0xFD,0xA2,0xD0,0x6C,0x90,0x04, ++ 0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64,0x85,0x17,0xE0,0x2F,0xF8,0xBA,0xD3,0x6C, ++ 0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x17,0xE5,0xE7,0x14,0x3A, ++ 0xE9,0x16,0x30,0x02,0x30,0xE2,0x31,0x3A,0xFD,0x82,0x13,0xC2,0xE3,0x0E,0x98,0xBA, ++ 0x05,0x17,0x10,0x02,0xDB,0x06,0x98,0xA2,0x46,0xC2,0x4D,0x03,0xDE,0x8A,0x0B,0x00, ++ 0xC0,0x00,0xCA,0x24,0x00,0x44,0xC0,0x24,0xE0,0x00,0x84,0x24,0xC2,0x14,0xE0,0x00, ++ 0x90,0x05,0x86,0x14,0xC8,0x2C,0xC0,0x14,0x15,0x42,0x9C,0x3E,0x87,0x3D,0xE8,0x85, ++ 0xAC,0xFD,0x87,0x7D,0x30,0xA2,0x30,0xFA,0xD8,0x0B,0x8F,0x6C,0xD8,0x0B,0x8B,0x64, ++ 0x40,0x01,0x80,0x6E,0x48,0x52,0x05,0x99,0x07,0x43,0x12,0xF9,0x58,0x3A,0x95,0x81, ++ 0x10,0xD3,0x06,0x43,0x00,0xC1,0x83,0x17,0xF8,0xFF,0xF1,0x84,0xB0,0xE1,0x01,0xCF, ++ 0x40,0x1A,0x0D,0x19,0x04,0x0B,0x0A,0x19,0x05,0x0B,0x48,0x12,0xC2,0x84,0xC0,0x30, ++ 0x11,0x01,0x30,0xDA,0x30,0x8A,0x00,0x09,0x82,0x17,0xC0,0xC7,0x29,0x01,0x30,0x1A, ++ 0x14,0x09,0x08,0x01,0x40,0x1D,0xB8,0x04,0x82,0x17,0xE0,0x6F,0xE7,0x68,0x93,0x6D, ++ 0x6F,0x91,0x99,0xA6,0x48,0xB2,0x44,0x43,0x10,0x11,0x18,0x82,0x01,0x43,0x30,0x02, ++ 0x80,0x01,0x35,0x2A,0xC8,0x03,0x32,0x00,0xAC,0xEE,0x49,0x9A,0x00,0x01,0x80,0x43, ++ 0x31,0x12,0x31,0xCA,0x00,0x11,0x80,0x0F,0xF9,0xF7,0x34,0x1A,0xB8,0x04,0x08,0x01, ++ 0x00,0x11,0xD0,0x84,0x84,0x17,0xC0,0x47,0x49,0x42,0xD4,0x43,0x08,0x43,0x2A,0x01, ++ 0xC2,0x64,0x00,0x00,0x80,0x74,0x00,0xBF,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09, ++ 0x81,0x17,0xC0,0x27,0xB8,0x0C,0xA0,0x04,0x30,0x8A,0x41,0x1D,0xD8,0x84,0xD0,0x64, ++ 0xB9,0xFF,0xFF,0xF7,0xC4,0x74,0xC8,0x30,0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42, ++ 0x80,0x17,0xC0,0xA7,0xE7,0x68,0x93,0x6D,0xC4,0x6C,0x10,0x2A,0x99,0x26,0x37,0x1A, ++ 0xB8,0x04,0x08,0x01,0x00,0x19,0xD0,0x84,0x82,0x17,0xC0,0xF7,0x31,0x12,0x31,0xCA, ++ 0x00,0x01,0x80,0x0F,0xFB,0x47,0x4B,0x92,0x40,0x43,0x10,0x11,0x18,0x82,0x04,0x43, ++ 0x87,0x9D,0xE8,0x85,0xAC,0xFD,0x87,0x1D,0x30,0x7A,0x50,0x01,0x80,0x16,0x00,0x01, ++ 0x80,0x0C,0x00,0x0F,0x00,0x09,0x80,0x0C,0x2A,0x01,0x00,0x47,0xCD,0x64,0x00,0x40, ++ 0xC1,0x30,0x32,0x52,0x08,0x19,0xD8,0x6C,0xC0,0x0C,0x80,0x0F,0xF9,0x3F,0x07,0x41, ++ 0x85,0x17,0xF0,0xD7,0x20,0x09,0xC0,0x34,0x80,0x01,0x84,0x14,0x60,0x81,0x99,0x36, ++ 0x0A,0xF9,0x47,0xF2,0x88,0x11,0x18,0x0B,0x42,0x08,0x1B,0x0B,0x02,0x0F,0x40,0xDA, ++ 0x1F,0x23,0x02,0xF9,0x4F,0xCA,0x82,0x89,0x88,0x01,0x12,0x43,0x00,0x11,0x80,0x17, ++ 0xF0,0x1F,0xC5,0x14,0xF0,0x03,0x46,0x01,0x80,0x3E,0x00,0x51,0x84,0x17,0xF0,0xE7, ++ 0x40,0x83,0x41,0x03,0x30,0x00,0xA8,0x86,0x07,0x5F,0x00,0xF9,0x4C,0x7A,0x82,0x89, ++ 0x88,0x01,0x12,0x43,0x00,0x09,0x80,0x17,0xF1,0x7F,0x44,0x83,0x40,0x03,0x30,0x00, ++ 0xA3,0x1E,0xE0,0x20,0x93,0x25,0x67,0xF9,0xC9,0x86,0x06,0xE4,0xE1,0xF8,0x35,0x52, ++ 0x08,0x09,0xD8,0x6C,0xC0,0x0C,0x80,0x0F,0xFB,0x4F,0xE5,0x68,0x90,0x6D,0xC7,0x1C, ++ 0x15,0x2A,0x9C,0x9E,0x3F,0x17,0xA9,0x85,0x80,0x3D,0x34,0x7A,0x34,0xA2,0x00,0xD9, ++ 0xEF,0x02,0x0E,0xF9,0x88,0x09,0x40,0x01,0x80,0x0E,0x30,0x72,0x00,0x0F,0x30,0x19, ++ 0x13,0xB0,0xD9,0xC3,0x81,0x34,0xD8,0xC3,0x80,0x2C,0x98,0x1C,0xC2,0x34,0x00,0x00, ++ 0xC0,0x00,0x86,0x24,0x45,0xAA,0x11,0x81,0x00,0x13,0x1A,0x0B,0x28,0x01,0x00,0x67, ++ 0x4D,0x03,0x01,0x48,0xC0,0x00,0x42,0x03,0x01,0x33,0x30,0x1A,0x30,0x52,0x09,0x09, ++ 0x00,0x01,0x80,0x0F,0xFB,0xDF,0xE3,0x68,0x90,0x6D,0xC7,0x34,0x17,0x2A,0x9C,0x7E, ++ 0x28,0x01,0x00,0x67,0x4D,0x03,0x03,0x48,0xC0,0x00,0x42,0x03,0x00,0x33,0x08,0x09, ++ 0x31,0x1A,0x31,0x52,0x30,0x42,0x80,0x0F,0xFB,0x4F,0xE3,0x68,0x90,0x6D,0xC7,0x2C, ++ 0x17,0x2A,0x9C,0x7E,0x48,0x0B,0xA1,0x0C,0x89,0x04,0x30,0xDA,0x10,0x09,0xC8,0x1C, ++ 0xC7,0x34,0xB8,0xFF,0xFB,0xFF,0x4A,0x0B,0x89,0x04,0x30,0xDA,0x10,0x01,0xA0,0x0C, ++ 0xC8,0x24,0xC0,0x2C,0xBA,0xFF,0xFF,0xB7,0x48,0xC2,0x00,0x01,0x88,0x01,0x12,0x43, ++ 0x48,0xB2,0x18,0x43,0x37,0x57,0xAE,0xC5,0x30,0x1A,0x30,0x42,0x30,0xBA,0xD8,0x23, ++ 0xD8,0x2B,0x4A,0xB2,0xC0,0xC8,0x8A,0x04,0x30,0xD2,0x31,0xCA,0x87,0x0F,0xF8,0xDF, ++ 0x30,0x01,0x00,0x3F,0x09,0x09,0x30,0xDA,0x30,0x92,0x31,0x42,0x81,0x0F,0xF8,0xB7, ++ 0xE7,0xB0,0x93,0xB5,0x17,0x32,0x9D,0xAE,0xC8,0x04,0x10,0x01,0x18,0x01,0x00,0x4F, ++ 0x00,0x01,0x00,0x1F,0x82,0x5B,0xE0,0x48,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE, ++ 0xE6,0x90,0x92,0x95,0x17,0x12,0x9D,0x9E,0xE8,0xC5,0x07,0x00,0x00,0x01,0x00,0x42, ++ 0x18,0x00,0x04,0x42,0x48,0xE0,0x06,0x00,0x00,0xD0,0x00,0x01,0x60,0x20,0x02,0x00, ++ 0x49,0x32,0x41,0x2A,0x05,0x43,0x9E,0xFF,0x7F,0x04,0x3A,0xF7,0x94,0x15,0x3A,0x00, ++ 0x77,0x18,0x06,0xF9,0x04,0xC2,0x3C,0x48,0x74,0x48,0x00,0xCA,0x50,0x01,0xD0,0x5E, ++ 0x38,0x90,0x78,0x90,0xD4,0x41,0x40,0x98,0x54,0xE2,0x00,0xD8,0xC6,0xD0,0x4C,0x9B, ++ 0x18,0x1A,0x1C,0x5A,0x0B,0x9B,0x3E,0x82,0x40,0x98,0x54,0xCA,0x04,0xD8,0xC4,0xD0, ++ 0x44,0x9B,0x18,0x1A,0x18,0x5A,0x00,0x9B,0x3A,0x82,0x93,0x05,0x36,0x10,0x76,0x90, ++ 0x0C,0x09,0x00,0x8A,0x48,0x00,0x52,0x9A,0x04,0x00,0xC4,0x00,0x03,0x0B,0x38,0x82, ++ 0x96,0x05,0x32,0x10,0x70,0x90,0x0E,0x09,0x00,0x8A,0x54,0x72,0x4C,0x00,0x02,0x00, ++ 0x94,0x01,0xC4,0x00,0x03,0x0B,0x38,0x82,0xB3,0x15,0x3B,0x82,0xFB,0x85,0x39,0x82, ++ 0x40,0x32,0x48,0x0B,0x10,0x21,0x18,0x8A,0x0B,0x0B,0x38,0x82,0x48,0x1A,0x48,0x43, ++ 0x14,0x21,0x18,0x82,0x0B,0x43,0x38,0x82,0x07,0x20,0x28,0xD0,0x68,0x07,0x00,0x07, ++ 0x20,0x07,0x00,0x07,0x08,0x07,0x00,0x07,0xAC,0xFD,0x87,0x4D,0xD0,0x94,0x30,0x22, ++ 0xF8,0x43,0x80,0x0C,0xF8,0x6B,0xC6,0x64,0x08,0x01,0x80,0x0B,0x00,0x01,0x00,0x8F, ++ 0x0A,0x21,0x19,0x0A,0x18,0x99,0xCB,0x48,0x0E,0xD8,0xC2,0x48,0xC8,0x4B,0x4C,0x79, ++ 0x80,0x36,0x80,0x83,0xE0,0x90,0xCA,0x64,0xD8,0x64,0xC0,0x4B,0xE0,0x48,0x82,0xCB, ++ 0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0x5E,0xC0,0x64,0xC0,0x03,0x80,0x44,0x40,0x01, ++ 0x88,0x0E,0x80,0x6D,0xE8,0x85,0xC7,0x44,0x40,0x09,0x88,0x1E,0xC0,0x0C,0x40,0x09, ++ 0x8F,0x06,0x38,0xB7,0x00,0x01,0x80,0x34,0x80,0x2C,0xC8,0x44,0xC4,0x0C,0x10,0x0A, ++ 0x88,0x96,0x02,0x01,0x30,0x01,0x08,0x01,0x88,0x1C,0x88,0x14,0x1C,0xC9,0x09,0xD8, ++ 0x00,0x4F,0x10,0x31,0x18,0x52,0xCA,0x90,0xC2,0x90,0x46,0xBC,0xC4,0xC0,0x41,0x94, ++ 0xCA,0xB0,0xE4,0x48,0x90,0x4D,0xD6,0x0C,0x17,0x8A,0x9C,0x96,0xC8,0x0C,0x80,0x17, ++ 0xF0,0x6F,0x82,0x24,0x30,0x82,0xC9,0x0C,0x82,0x17,0xF0,0x47,0x30,0x32,0x08,0x01, ++ 0x01,0x01,0x00,0x07,0x1A,0x99,0x0B,0xD8,0x02,0x0F,0xE0,0x48,0x91,0x4D,0x16,0x21, ++ 0x18,0x52,0xCA,0x90,0xC4,0x90,0xCE,0x93,0x57,0x79,0x80,0xB6,0x12,0x21,0x19,0x52, ++ 0xCE,0x90,0xC0,0x98,0x3E,0xF1,0xF8,0xFA,0xDF,0x1C,0xC0,0xD8,0x98,0x1C,0x18,0xE9, ++ 0x0E,0xD8,0xC6,0x98,0x14,0x01,0xF0,0xD2,0xDE,0x14,0xC0,0x90,0x92,0x14,0xE0,0x48, ++ 0x92,0x4D,0xE6,0x00,0x90,0x05,0xD6,0x44,0x16,0x12,0xC4,0xDE,0xC8,0x44,0xC0,0x1C, ++ 0x80,0x17,0xF0,0xE7,0x30,0x3A,0xC8,0x44,0xC0,0x14,0x80,0x17,0xF0,0xBF,0xC8,0x24, ++ 0xD8,0x48,0x8E,0x34,0xD0,0x80,0x81,0x2C,0x08,0x01,0x10,0x01,0x00,0x77,0x00,0x01, ++ 0x33,0x5A,0x18,0x5A,0xF2,0x5C,0x00,0xD8,0xC8,0xD8,0x04,0x1F,0x04,0x30,0x9A,0xD2, ++ 0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE,0xE6,0x48,0x92,0x4D,0x17,0x4A,0x9D,0x76, ++ 0x08,0x01,0x10,0x01,0x03,0xE7,0x19,0x99,0x08,0xD8,0x02,0x0F,0xE6,0x48,0x92,0x4D, ++ 0x02,0x21,0x19,0x42,0xCC,0x00,0x30,0x22,0xC0,0x00,0x86,0x3C,0xC8,0x03,0x44,0x79, ++ 0x80,0xA6,0x07,0x01,0x00,0x2F,0xD9,0x3C,0x34,0xF1,0xF8,0xF2,0xD9,0x34,0x38,0xC9, ++ 0xC0,0xB0,0x1F,0x31,0x18,0x1A,0xCA,0xD8,0x0E,0xF8,0xCD,0xD8,0x47,0xFC,0xDA,0xB0, ++ 0xAB,0x06,0x10,0xB2,0x95,0xB5,0x35,0xB2,0x37,0xE9,0x08,0xB0,0x20,0x32,0x3B,0x01, ++ 0xF8,0xBA,0xF7,0x2C,0x45,0xDC,0xCC,0xF0,0xD0,0x98,0xAF,0x06,0x10,0xDA,0x32,0xB2, ++ 0x18,0x72,0xFB,0x5C,0x07,0xB0,0xCB,0xB0,0x22,0x9A,0x03,0x38,0x9A,0x9A,0xE7,0x00, ++ 0x90,0x05,0xDE,0x0C,0x16,0xC2,0x9C,0xB6,0xE6,0x48,0x92,0x4D,0xE6,0x90,0x92,0x95, ++ 0xC0,0x64,0xC0,0x03,0x15,0x82,0xC4,0xF6,0xC0,0x64,0xC8,0x0C,0xC4,0x03,0x10,0x42, ++ 0xC9,0x06,0x38,0xF7,0xC1,0x0C,0x38,0xE7,0xAC,0x85,0x87,0x3D,0x34,0x22,0x00,0x91, ++ 0xD4,0x02,0x34,0x22,0x01,0xC1,0xF0,0x02,0x18,0x71,0x80,0x34,0xF0,0x1A,0x9F,0x2C, ++ 0xD0,0x00,0x96,0x05,0x1F,0xD1,0xF0,0x1A,0x2B,0x81,0xF8,0x2A,0x32,0xF2,0xDC,0xD8, ++ 0x90,0xDD,0xA8,0x24,0xC0,0x2B,0x6F,0x09,0x8D,0x16,0x10,0x04,0x10,0x1C,0x07,0x6F, ++ 0x55,0x3C,0x05,0xE8,0xC7,0x68,0x51,0x04,0x07,0x30,0xC4,0x98,0xD9,0x68,0x97,0x6D, ++ 0xD0,0xC0,0x90,0x1D,0x84,0x40,0x85,0xD8,0x17,0x04,0x15,0x1C,0x4B,0x81,0x80,0xF6, ++ 0xE9,0x2C,0xC0,0x40,0x02,0x28,0xCA,0x00,0xEA,0x34,0xC8,0x00,0x80,0x00,0x94,0x05, ++ 0xEF,0x24,0xC0,0x58,0x02,0xE8,0xCA,0xE8,0x37,0x9A,0xC3,0x58,0x80,0xD8,0x94,0xED, ++ 0x90,0x01,0x46,0x01,0xD0,0x0E,0x00,0x01,0x00,0x27,0x50,0x9C,0x10,0x1A,0xD4,0x0E, ++ 0x00,0x81,0xF0,0x82,0x68,0x01,0xD0,0x0E,0x28,0x01,0x00,0x27,0x55,0x9C,0x12,0x5A, ++ 0xD0,0x0E,0x28,0x91,0xF8,0xAA,0xD2,0x2C,0xD0,0x90,0xF0,0xB0,0xD2,0x06,0x10,0x92, ++ 0x06,0x98,0xC2,0xB8,0xD2,0x24,0xD8,0x90,0xF0,0x98,0xD0,0x06,0x15,0x92,0xC2,0xF8, ++ 0x7E,0xD0,0xCF,0x90,0x18,0x90,0x66,0x90,0x58,0x01,0xD0,0x06,0x12,0xDA,0x02,0xF8, ++ 0xC8,0xD8,0x76,0x01,0xD3,0x06,0x10,0xB2,0xCE,0xD8,0x7C,0xF0,0xC6,0x98,0x1F,0xD8, ++ 0x60,0xF0,0x48,0x41,0x80,0x0E,0x48,0x49,0x88,0x2E,0x48,0x49,0x8A,0x1E,0x20,0x88, ++ 0x63,0x50,0x20,0x88,0x63,0x70,0x30,0x0A,0x8B,0x0C,0x28,0x12,0xCB,0x06,0x30,0x12, ++ 0xCC,0x0C,0x10,0x72,0xC8,0x06,0xF0,0x0C,0xDB,0x2C,0x30,0x0A,0xD0,0x48,0x34,0x7A, ++ 0x1C,0xCA,0x02,0x58,0xC4,0x48,0x36,0x72,0x19,0x51,0x30,0xCA,0xF3,0x1A,0x07,0xF8, ++ 0xCA,0x48,0x1E,0x5A,0x32,0x8A,0xC3,0xC8,0x1B,0x82,0x32,0x12,0x46,0xB8,0xCA,0x00, ++ 0x02,0x00,0xC6,0x00,0x36,0x0A,0x03,0x48,0x88,0x1C,0x80,0x17,0xE8,0xBF,0x80,0x14, ++ 0xD0,0x24,0xC0,0x0C,0xD8,0x00,0x34,0x0A,0x1C,0x82,0x02,0x10,0xC0,0x00,0x14,0x61, ++ 0xF2,0x12,0x05,0x58,0xC2,0x48,0x1E,0x52,0xC3,0x80,0x18,0xAA,0x00,0x07,0x00,0x67, ++ 0xCE,0x48,0x07,0x48,0xC0,0x40,0xC8,0x1C,0x80,0x17,0xE8,0x07,0xCB,0x2C,0x08,0x0C, ++ 0xCD,0x24,0x08,0x0C,0xCF,0x14,0x08,0x0C,0x10,0x04,0x81,0x3D,0xEF,0x85,0xAF,0xF5, ++ 0x30,0x3A,0xC0,0x44,0x60,0xD2,0xCF,0xE0,0x2F,0x31,0x70,0xCA,0x1F,0xAA,0xC2,0x68, ++ 0xF5,0x21,0xC9,0x68,0x06,0x90,0xC2,0x90,0x59,0xAA,0xDF,0x81,0xC6,0xB0,0xFE,0x13, ++ 0x31,0xB2,0x34,0xDA,0x32,0x3A,0xB8,0x01,0x30,0x12,0xB8,0x0C,0x92,0x01,0xBE,0x01, ++ 0x59,0x09,0x88,0x4E,0x01,0x01,0x00,0x17,0xC0,0x0B,0x49,0x79,0x89,0xE6,0x40,0x4C, ++ 0x0B,0x0C,0x47,0x5C,0x14,0x1C,0x31,0xE2,0xC1,0x9B,0x89,0x1B,0xC3,0x9B,0x8B,0x1B, ++ 0x1B,0x0C,0x35,0x1A,0x19,0x1C,0x27,0x0C,0x23,0x1C,0x0B,0x0C,0x09,0x1C,0x45,0x4C, ++ 0x1B,0x0C,0x41,0x4C,0x19,0x0C,0x83,0x03,0x0F,0x09,0x80,0x0B,0x88,0x0B,0xFD,0x8B, ++ 0x90,0x0B,0x09,0x01,0x90,0x0B,0x03,0x27,0xA2,0x21,0xE1,0x00,0x93,0x05,0x2E,0x82, ++ 0x9B,0xD6,0x2E,0x82,0x94,0xF6,0x03,0x2F,0x1A,0x21,0x19,0xCA,0xC8,0x60,0x08,0x41, ++ 0x89,0x04,0x40,0x4C,0x18,0x0C,0x09,0x11,0xF3,0x4A,0x1B,0x0C,0x35,0x62,0xCC,0x0B, ++ 0x48,0x09,0x88,0xAE,0x08,0xC1,0x18,0xE1,0xF7,0x0A,0xF3,0x1A,0xD0,0x48,0xAE,0x06, ++ 0x14,0x4A,0x92,0x4D,0x30,0x72,0x1C,0xF1,0xF3,0x1A,0x37,0x0A,0xD0,0x48,0xAE,0x06, ++ 0x14,0x4A,0x92,0x4D,0xE3,0xDB,0x21,0x8A,0x10,0xCA,0xCC,0x0E,0x0D,0x01,0x88,0x0B, ++ 0x09,0xC1,0x18,0x01,0xF7,0x0A,0xF3,0x1A,0xD0,0x48,0xAE,0x06,0x14,0x4A,0x92,0x4D, ++ 0x30,0x62,0x0C,0xD1,0x1B,0x11,0xF1,0x0A,0xF6,0x1A,0xD7,0x48,0xAA,0x06,0x10,0x4A, ++ 0x24,0x0A,0x93,0x4D,0x30,0x62,0xDC,0x0C,0xC4,0x0B,0xE7,0xDB,0xE4,0xD8,0x12,0xCA, ++ 0xC8,0x7E,0xF8,0x8B,0xEE,0xDB,0x01,0xCA,0x28,0x0A,0xCB,0x56,0xD6,0x0B,0x4B,0x41, ++ 0x92,0x0E,0xE0,0x48,0x91,0x0B,0xD3,0x0B,0xFC,0x9B,0x10,0xCA,0x92,0x0E,0xE0,0x48, ++ 0x91,0x0B,0xD1,0x0B,0x28,0x0A,0xCB,0xA6,0xDF,0x0C,0xC0,0x0B,0xE2,0xDB,0xE4,0xD8, ++ 0x10,0xCA,0xCC,0x76,0xCA,0x0B,0x37,0x50,0xE2,0xCB,0x73,0x90,0xF4,0x48,0x12,0x52, ++ 0x89,0x0E,0x08,0x01,0x80,0x0B,0x35,0x12,0x09,0x81,0x30,0x02,0xBC,0xFF,0xF7,0xE7, ++ 0x00,0xDF,0xD8,0x0C,0xC4,0x0B,0xE7,0xDB,0xE4,0xD8,0x12,0xCA,0xC8,0x1E,0xF8,0x8B, ++ 0xEE,0xD3,0x01,0x8A,0x91,0x0B,0x59,0x0C,0x23,0x0C,0x59,0x0C,0x20,0x0C,0x33,0x12, ++ 0x30,0x02,0xC9,0x04,0xBC,0xFF,0xF7,0x47,0x03,0x01,0x90,0x03,0xD0,0x03,0x41,0x01, ++ 0x80,0x1E,0x00,0x07,0x02,0x3F,0xF1,0x00,0x97,0x03,0xC1,0x03,0x40,0xF9,0x93,0x0E, ++ 0xE7,0x00,0x82,0x03,0x43,0x44,0x15,0x04,0x03,0x19,0x80,0x03,0xE4,0xC3,0x83,0x01, ++ 0x89,0x03,0xCF,0x03,0xC2,0x8B,0xD1,0x00,0xE0,0x00,0x42,0x11,0xC3,0x2E,0xC8,0x03, ++ 0xC2,0x8B,0xD3,0x00,0xE0,0x00,0x42,0x11,0xCF,0x4E,0xC0,0x03,0x40,0x11,0x98,0x36, ++ 0xCA,0x0C,0xE0,0x4B,0x10,0x42,0xC4,0x16,0x07,0x01,0x80,0x03,0x89,0x03,0xC7,0x83, ++ 0x8B,0x03,0xC1,0x83,0x8F,0x03,0xEB,0xF5,0xAC,0x85,0x37,0xE2,0x34,0x2A,0xAB,0x01, ++ 0x4A,0x5C,0x27,0xD8,0x67,0xE0,0x40,0xF9,0x88,0x0E,0x00,0x01,0xE9,0x85,0x1F,0x21, ++ 0x1B,0xC2,0x5A,0xFA,0xC6,0x00,0xC4,0x00,0x1A,0x31,0x18,0xCA,0xC3,0x48,0x54,0xE2, ++ 0xD4,0x21,0xC1,0x50,0x0A,0xA1,0xF0,0x0A,0x48,0x01,0xD0,0x06,0x10,0x4A,0x1A,0xB1, ++ 0xF0,0x1A,0x5E,0x01,0xD2,0x06,0x10,0xDA,0xC3,0x48,0x5E,0xB2,0x10,0xCA,0x9C,0x06, ++ 0x08,0x01,0x30,0x71,0x44,0x9C,0xF8,0x32,0xD8,0xD8,0xAC,0x06,0x10,0xDA,0x32,0x81, ++ 0x44,0x94,0xFA,0x32,0xD8,0x90,0xAC,0x06,0x14,0x92,0xC2,0xD0,0x11,0x12,0x9D,0x0E, ++ 0xC8,0x33,0x74,0x09,0x8B,0x26,0xE0,0x5B,0xCA,0x3B,0xF6,0xD8,0x10,0xFA,0xDC,0xBE, ++ 0x70,0x09,0x88,0x3E,0xDC,0x5B,0x11,0x5A,0x9E,0x26,0xC0,0x03,0x40,0xF1,0xC0,0x0E, ++ 0x40,0x51,0x90,0x6E,0x70,0x09,0x88,0x1E,0x30,0x02,0x5B,0x04,0x40,0xC1,0x98,0x3E, ++ 0x70,0x09,0x88,0x16,0x04,0x00,0x13,0x82,0xCD,0x16,0x00,0x00,0x10,0x82,0xC4,0x0E, ++ 0x07,0x01,0xE8,0x85,0x07,0x09,0xE8,0x85,0xAC,0xFD,0x87,0x5D,0x30,0xB2,0x0C,0x01, ++ 0x28,0x01,0x00,0x01,0x80,0x14,0xC0,0xA4,0xF8,0x23,0x06,0x01,0x30,0x22,0x84,0x34, ++ 0x00,0x27,0xD0,0x64,0x02,0xF9,0xA7,0x82,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xC6, ++ 0xD3,0x74,0x28,0x92,0xC0,0x26,0xC0,0x74,0x83,0x24,0x30,0x82,0x80,0x1C,0x00,0x1F, ++ 0x30,0x82,0x83,0x24,0xC0,0x74,0x80,0x1C,0x00,0x01,0x80,0x2C,0x00,0xD7,0x1A,0x01, ++ 0x03,0xB7,0x32,0x02,0x06,0xC2,0x3E,0x00,0x8A,0x86,0x42,0x32,0x80,0x3C,0x00,0x01, ++ 0xD0,0xA4,0xF0,0x5C,0xF8,0x93,0x90,0x54,0x33,0xD2,0x18,0x12,0x05,0xB8,0xCA,0xD0, ++ 0x90,0x4C,0x00,0x6F,0xF6,0x34,0x00,0x32,0x38,0x90,0x8F,0x3E,0xF2,0x4C,0x00,0x38, ++ 0xD8,0xB2,0xFF,0x3C,0x10,0xF2,0x95,0x0E,0xB0,0x3C,0x30,0x0A,0xE6,0x00,0x92,0x05, ++ 0xD4,0x54,0x10,0x12,0xC1,0x76,0x77,0xBA,0x02,0x01,0x00,0x78,0xB8,0x44,0x00,0x87, ++ 0x36,0x3A,0x03,0x3A,0x38,0xF8,0x8F,0x56,0x33,0x3A,0x18,0x3A,0xD3,0x5C,0x00,0xF8, ++ 0xC0,0xF8,0xD5,0x44,0xD5,0xFA,0x15,0xBA,0xC1,0x0E,0x30,0xF2,0x32,0x2A,0xE0,0x00, ++ 0x93,0x05,0x2E,0x82,0x9C,0x66,0x17,0xEA,0x88,0xA6,0xC0,0x14,0xC8,0x00,0x84,0x14, ++ 0xC2,0x2C,0xE0,0x00,0x90,0x05,0x86,0x2C,0xC2,0x64,0xA0,0x2A,0x31,0x09,0x30,0x82, ++ 0xD4,0x34,0x00,0x42,0x1C,0x82,0x90,0x05,0x85,0x34,0x00,0x72,0x30,0x02,0x1B,0x32, ++ 0x94,0x85,0x35,0x22,0xD0,0x24,0xC0,0x2C,0x10,0x82,0x84,0x1E,0xE6,0xD8,0x92,0xDD, ++ 0x2D,0x9A,0x9B,0x36,0xD0,0x24,0xC0,0x2C,0x15,0x82,0x9C,0x06,0xC0,0x14,0x80,0x3C, ++ 0x10,0x01,0x00,0x01,0x0B,0x01,0x30,0x5A,0x80,0xCB,0x18,0x01,0x0C,0x01,0x30,0x62, ++ 0x30,0x4A,0xE3,0x4A,0x02,0x0F,0xE0,0x48,0x90,0x4D,0x36,0xEA,0x07,0x6A,0x3E,0x68, ++ 0x88,0xCE,0xEF,0x1C,0x10,0x4A,0x9D,0xFE,0x40,0x01,0x88,0x8E,0x08,0xF9,0x07,0x5F, ++ 0xD0,0x64,0xE0,0x9A,0x28,0x9A,0x93,0x1E,0xD0,0xA4,0xF8,0x93,0x10,0x12,0xC4,0x0E, ++ 0xD0,0x64,0xA0,0x8A,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0x8E,0x87,0x7D,0xE8,0x85, ++ 0xF6,0x00,0x92,0x05,0x30,0x4A,0xE3,0x4A,0x2D,0x09,0x30,0x62,0x00,0x6F,0x01,0x00, ++ 0x70,0x30,0x03,0x00,0xF8,0xFF,0x07,0x00,0x33,0x6A,0x18,0x2A,0xFB,0x5C,0x00,0x70, ++ 0xCA,0xB0,0x07,0x38,0xDD,0xAA,0xC7,0x50,0x2C,0x09,0x00,0x6A,0x1D,0xEA,0x90,0x5D, ++ 0x31,0x72,0xA3,0x8A,0xED,0x3C,0x10,0x52,0x98,0x16,0x28,0x11,0x30,0x62,0x05,0xA7, ++ 0xFA,0x74,0xE0,0x28,0x10,0xEA,0x9D,0x6E,0x90,0x3C,0x08,0x01,0x00,0x27,0xF8,0x64, ++ 0xE3,0xAA,0xA3,0xEA,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xC6,0xE0,0x8A,0x29,0x09, ++ 0x30,0x62,0x05,0x17,0x90,0x45,0x2F,0x01,0xA3,0xAA,0x31,0x2A,0x6D,0x01,0x80,0x2E, ++ 0x33,0x6A,0x18,0x2A,0xFB,0x5C,0x00,0x70,0xCA,0xB0,0x07,0x38,0xDA,0xAA,0xDF,0x90, ++ 0x2C,0x09,0x00,0x6A,0x1B,0x5A,0x35,0x6A,0xE2,0x4A,0xE1,0x48,0xA4,0x4A,0x39,0xAF, ++ 0xAC,0xC5,0x37,0x22,0xFC,0x73,0x5E,0xAA,0x36,0x02,0xC3,0x00,0x31,0x32,0x34,0xAA, ++ 0x38,0x21,0x31,0x62,0x1A,0xEA,0xA3,0x01,0x13,0x01,0x20,0x2A,0xC0,0x68,0x07,0xF7, ++ 0xC0,0x1B,0x58,0x79,0x86,0xD6,0xC8,0x1B,0x30,0xD8,0xA0,0x3E,0x18,0xF9,0x8F,0x1B, ++ 0x8E,0x1B,0xC2,0x1B,0xE5,0x3B,0x15,0xDA,0xC6,0x06,0x88,0x13,0xCA,0x1B,0x36,0xD8, ++ 0x76,0xD8,0x8A,0x1B,0x58,0x01,0x80,0x0E,0xF6,0xD8,0x8A,0x1B,0xC8,0x1B,0x5E,0x01, ++ 0x8A,0x26,0xC0,0x1B,0x44,0xD8,0x04,0xD8,0x84,0x1B,0x82,0x13,0x84,0x21,0x11,0x2A, ++ 0xC0,0xF6,0x06,0x01,0x84,0x04,0xB8,0x53,0x30,0x82,0x03,0x8F,0xC5,0x13,0x10,0x92, ++ 0x96,0x5E,0xC0,0x13,0xE2,0x3B,0x35,0x98,0x75,0xD8,0x12,0xDA,0xCC,0x2E,0xC0,0x13, ++ 0x50,0x01,0x81,0x16,0x00,0x09,0x80,0x04,0x00,0x27,0x10,0x01,0x81,0x13,0x84,0x21, ++ 0x17,0x2A,0xC4,0x5E,0xC0,0x04,0x40,0x01,0x83,0x76,0x31,0x92,0x36,0x5A,0x98,0x01, ++ 0x00,0x47,0x01,0x01,0x80,0x83,0xC4,0x83,0x11,0x82,0x95,0x16,0xC2,0x83,0x36,0x38, ++ 0xE3,0x03,0x75,0xF8,0x10,0x3A,0xCC,0xE6,0x04,0x09,0x80,0x83,0xFA,0x43,0xE4,0x00, ++ 0xB8,0x43,0x3C,0x71,0xF8,0xBA,0x7E,0x01,0xD0,0x16,0x00,0x01,0x08,0x84,0x06,0x27, ++ 0x54,0xC4,0x10,0x3A,0xE8,0x0E,0x50,0xC4,0x08,0x84,0x3E,0x81,0xF8,0xBA,0x7E,0x01, ++ 0xD0,0x16,0x00,0x01,0x10,0x84,0x00,0x27,0x54,0xC4,0x12,0x3A,0xEA,0x0E,0x50,0xC4, ++ 0x11,0x84,0x90,0x21,0x16,0xAA,0xC4,0xA6,0xF8,0x43,0x40,0x01,0x88,0x36,0x58,0x44, ++ 0x16,0xE9,0x03,0x90,0x10,0x82,0x94,0x0E,0xE0,0x00,0x1A,0x44,0xF8,0x43,0x44,0x01, ++ 0x80,0xCE,0x10,0x01,0x03,0x01,0x28,0x99,0x0E,0x68,0xFB,0x63,0x01,0x6F,0x18,0x21, ++ 0x1B,0x1A,0x22,0x1A,0xC8,0xD8,0xD2,0xF3,0x70,0x09,0x88,0x26,0xC8,0xDB,0x5E,0x19, ++ 0x8A,0x0E,0xE0,0x90,0x92,0x95,0xE6,0x00,0x94,0x05,0x16,0x22,0xC0,0x7E,0x57,0x01, ++ 0x88,0x0E,0x00,0x01,0x1F,0x44,0xE8,0xC5,0xAC,0x85,0x87,0x3D,0x30,0x2A,0x30,0x62, ++ 0x41,0x12,0xC2,0x40,0x08,0x29,0xEE,0x4A,0x4B,0x29,0x80,0xDE,0x4B,0x02,0xC2,0x70, ++ 0xEB,0x48,0xC4,0x48,0x89,0x1C,0x48,0xF2,0x8B,0x61,0xC0,0x48,0x88,0x14,0x08,0x01, ++ 0x10,0xF9,0x1F,0x79,0x03,0x3F,0xA0,0x92,0xC8,0x3B,0x7E,0x01,0x88,0x06,0x80,0x1B, ++ 0xE6,0x48,0x92,0x4D,0x87,0x21,0xF9,0x3B,0x17,0x7A,0xC4,0xA6,0x00,0x01,0x80,0x34, ++ 0xF8,0x03,0x41,0x01,0x80,0xCE,0xB2,0x04,0x31,0x0A,0x31,0x42,0x58,0x2D,0xD0,0x14, ++ 0xBA,0xFF,0xDF,0x97,0x80,0x34,0xC0,0x34,0x40,0x01,0x88,0x76,0x30,0x01,0x00,0x47, ++ 0x31,0x5A,0x31,0x92,0x08,0xF9,0x07,0x09,0xA7,0x04,0xB8,0xFF,0xE3,0x47,0xE7,0xB0, ++ 0x91,0xB5,0xFF,0x03,0x17,0x82,0xC5,0x9E,0x00,0xFF,0xC1,0x34,0x40,0x09,0x88,0x96, ++ 0xC1,0xB3,0x31,0x1A,0x30,0x52,0x09,0x01,0x37,0x82,0xB9,0xFF,0xE8,0x2F,0x46,0x01, ++ 0x80,0x0E,0x00,0x01,0x00,0x07,0x00,0x09,0x30,0x5A,0x11,0x01,0x30,0x8A,0xA1,0x04, ++ 0xBE,0xFF,0xE7,0x6F,0x00,0x4F,0xA1,0x04,0xFB,0x3B,0x31,0x5A,0xE9,0xD3,0x30,0xDA, ++ 0xC8,0x1C,0xC0,0x14,0xB8,0xFF,0xF7,0x47,0x38,0x01,0x00,0xDF,0xC6,0x1C,0xE8,0x02, ++ 0x40,0xF9,0x87,0x16,0xE0,0x82,0x81,0x24,0x07,0x0F,0x00,0xF9,0x81,0x24,0x30,0x1A, ++ 0x31,0x52,0x31,0xCA,0xC7,0x24,0xB8,0xFF,0xE8,0xFF,0x44,0x01,0x80,0x0E,0x00,0x01, ++ 0x00,0x07,0x00,0x09,0x31,0x5A,0x31,0xD2,0xA0,0x04,0xC8,0x24,0xBD,0xFF,0xE7,0x3F, ++ 0xE7,0xF8,0x93,0xFD,0xFD,0x03,0x11,0xC2,0xC1,0x06,0x37,0x0A,0x30,0x42,0xD1,0x34, ++ 0xBE,0xFF,0xF7,0xB7,0x20,0xCF,0x04,0x01,0x38,0x82,0x03,0x00,0x70,0x30,0x03,0x00, ++ 0x48,0xE0,0x06,0x00,0xAE,0xFD,0x87,0x5D,0xC6,0xAC,0xDA,0x03,0x82,0xCC,0xC1,0xAC, ++ 0xD9,0x03,0x84,0xC4,0x01,0x09,0x58,0x45,0x81,0xC3,0xC0,0xC4,0xE2,0x00,0x82,0xC3, ++ 0xC4,0xC4,0x81,0xC3,0xC2,0xC4,0xF1,0x00,0x82,0xC3,0xC6,0xAC,0x82,0x01,0x87,0x54, ++ 0xC0,0x0B,0x00,0x21,0x1A,0x0A,0xC0,0x54,0x82,0x0B,0xC0,0xAC,0xCA,0x03,0x42,0x00, ++ 0x80,0xD4,0x09,0x01,0x40,0xB5,0x31,0x52,0x00,0x36,0x00,0x01,0x82,0xF4,0xC0,0xAC, ++ 0xCC,0xB4,0x82,0x01,0x82,0x4C,0xC2,0x74,0x92,0x05,0x82,0x44,0xC2,0x6C,0x92,0x05, ++ 0x82,0x3C,0xC2,0xAC,0x82,0x01,0x86,0x34,0x4B,0x11,0x80,0xBE,0x10,0x01,0x00,0x01, ++ 0x4C,0x45,0xB1,0x4A,0x8F,0x2C,0x4A,0xF2,0xB2,0x4A,0x8C,0x24,0x48,0xE2,0xEF,0x48, ++ 0xB2,0x4A,0x8C,0x1C,0x04,0x08,0xC4,0x48,0x91,0x4D,0x66,0x9D,0xDB,0x74,0xA2,0x1A, ++ 0x62,0x85,0xD9,0x6C,0xA2,0x1A,0xDB,0x24,0x9A,0x34,0xD9,0x1C,0x9A,0x2C,0xD9,0x2C, ++ 0x98,0x24,0x41,0x09,0x89,0x5E,0xD8,0x34,0x12,0xDA,0x92,0xDD,0x99,0x34,0xD9,0x2C, ++ 0x12,0xDA,0x92,0xDD,0x99,0x2C,0xD9,0x24,0x12,0xDA,0x92,0xDD,0x9A,0x24,0xD9,0x5C, ++ 0x32,0xE2,0xDC,0x64,0x9A,0x5C,0xD9,0x3C,0xE1,0x44,0xEA,0x2C,0xCA,0xD8,0x92,0xDD, ++ 0xEB,0x34,0xC9,0x20,0x91,0x25,0xF3,0x24,0xED,0x5C,0xC9,0x68,0xA8,0x5C,0x59,0x01, ++ 0xD9,0x86,0xEB,0xCC,0x13,0x5A,0xD5,0x6E,0x63,0x01,0xD8,0x5E,0xED,0xC4,0x11,0x62, ++ 0xD1,0x46,0xEB,0x5C,0xC5,0x6B,0x49,0x68,0x8B,0x06,0x32,0x2A,0x3F,0x01,0xF8,0x7A, ++ 0xEB,0x24,0x01,0x68,0x23,0x62,0x35,0x32,0x2B,0x01,0xF8,0xAA,0xF5,0xD4,0x11,0xAA, ++ 0xEA,0xC6,0xF2,0xB4,0x71,0x09,0x88,0x16,0xD9,0xF0,0x93,0xB5,0xB2,0x9C,0xF8,0x5C, ++ 0x35,0x01,0xF8,0xF2,0x10,0x72,0xDD,0x06,0x37,0xAA,0x81,0x68,0x01,0x68,0x33,0x7A, ++ 0xF3,0x9C,0x10,0x6A,0x12,0xAA,0xE5,0x2E,0x6B,0x9D,0xA1,0x62,0x6B,0x85,0xA1,0x5A, ++ 0x01,0xA8,0x72,0xB5,0xC9,0x68,0xE5,0x72,0xE1,0xB0,0xA3,0x72,0xEB,0xF4,0xE0,0x68, ++ 0x90,0x6D,0xAF,0xF4,0xF5,0x9C,0x10,0xBA,0xD1,0xBE,0x05,0x9F,0x09,0xEF,0x6A,0x9D, ++ 0xA1,0x62,0x6B,0x85,0xA2,0x5A,0x03,0xA8,0x75,0xB5,0xC9,0x68,0xE3,0x72,0xE1,0xB0, ++ 0xA0,0x72,0xE9,0xF4,0xE7,0x68,0x93,0x6D,0xAD,0xF4,0x38,0x37,0xE9,0x5C,0xC1,0x6B, ++ 0x48,0x68,0x6D,0x19,0x8A,0x6E,0x00,0xB0,0x7F,0xB5,0xC9,0xB0,0xE0,0xB2,0x71,0x09, ++ 0xC2,0x3E,0xC0,0x64,0x08,0x01,0xC6,0x03,0x1A,0x42,0xC8,0x64,0x82,0x43,0x80,0x7D, ++ 0xE8,0x85,0x6F,0x11,0x89,0x56,0x68,0x9D,0xA1,0x62,0x63,0x85,0xA2,0x1A,0x03,0x98, ++ 0x4A,0xB5,0xC1,0xC8,0xE2,0x5A,0xE0,0xD8,0xA0,0x5A,0x00,0x1F,0xCE,0x34,0xCA,0x4B, ++ 0x4F,0x51,0x90,0x66,0xE6,0x00,0x92,0x05,0x40,0x11,0x90,0x06,0x3A,0xD7,0xE2,0x90, ++ 0x90,0x95,0x56,0x21,0x92,0x06,0x38,0x57,0x01,0x01,0x80,0x64,0xC0,0xB4,0x42,0x09, ++ 0x88,0xF6,0x03,0x01,0x80,0x7C,0x01,0x01,0x81,0x74,0xC9,0x7C,0x42,0xB5,0x01,0x48, ++ 0xC2,0x40,0x80,0x14,0xC1,0x74,0xC9,0x7C,0x02,0x00,0xC4,0x00,0x91,0x05,0x86,0x4C, ++ 0xCA,0x74,0xC1,0x14,0xE0,0x2A,0x6A,0x09,0xC1,0x26,0xC0,0x64,0xE6,0x00,0x92,0x05, ++ 0x87,0x64,0x01,0x8F,0xC0,0x74,0x41,0x09,0x89,0x16,0xC0,0x7C,0x47,0x01,0x88,0xC6, ++ 0x08,0x81,0x41,0x45,0x83,0x17,0xC0,0x77,0xC0,0x6C,0x82,0x3C,0xC0,0x74,0x82,0x34, ++ 0xC0,0x5C,0x82,0x0C,0xC0,0x64,0x82,0x04,0xC4,0x7C,0xE1,0x00,0x3C,0x00,0x7C,0x00, ++ 0x50,0x5A,0xB4,0xA2,0xE8,0x98,0xB0,0xCA,0x31,0x62,0x74,0x45,0xB1,0x8A,0xC1,0x7C, ++ 0xB0,0x82,0x80,0x24,0xC0,0x7C,0xB1,0xC2,0x81,0x1C,0xD0,0x7C,0xB0,0x82,0x85,0x14, ++ 0xC0,0x74,0x41,0x09,0x88,0x5E,0xC0,0x24,0x12,0x02,0x92,0x05,0x80,0x24,0xC0,0x1C, ++ 0x12,0x02,0x92,0x05,0x80,0x1C,0xC0,0x14,0x12,0x02,0x92,0x05,0x80,0x14,0x00,0x01, ++ 0x83,0x2C,0xE0,0x68,0xAD,0xF4,0x01,0x9F,0x40,0x61,0x98,0x66,0xC8,0x24,0xC0,0x34, ++ 0xD2,0x4C,0xD1,0x00,0x4C,0x9D,0xA1,0x42,0xC8,0x1C,0xC0,0x3C,0xD2,0x4C,0xD1,0x00, ++ 0x4C,0x85,0xA1,0x42,0x00,0x47,0x15,0x01,0xDC,0x0C,0x00,0x28,0xF0,0xD2,0x5C,0x45, ++ 0x88,0xD2,0x12,0x01,0x90,0x6C,0xD1,0x3C,0x92,0x95,0x92,0x0C,0xD2,0x34,0x90,0x95, ++ 0x91,0x04,0xD2,0x6C,0x50,0x09,0x88,0x3E,0x12,0x12,0x93,0xA5,0x32,0x12,0x13,0x92, ++ 0x94,0x95,0x32,0xA2,0x12,0x4A,0x92,0x4D,0xD2,0x0C,0xDA,0x04,0xF0,0x0C,0x00,0x07, ++ 0x01,0xEF,0xB4,0x1C,0xF1,0x04,0xB0,0x5C,0x01,0x70,0xB2,0xFC,0x22,0x12,0x93,0x95, ++ 0xCA,0xD8,0x90,0xDD,0xF9,0x1C,0xF1,0xFC,0xC9,0xB0,0xB7,0x1C,0xF3,0x5C,0xC1,0xB0, ++ 0xB0,0x5C,0x51,0x01,0xD9,0xBE,0xF0,0xCC,0x10,0x92,0xD5,0xA6,0x58,0x01,0xD8,0x96, ++ 0xF5,0xC4,0x11,0x9A,0xD1,0x7E,0xF8,0x1C,0x35,0x01,0xF8,0xF2,0xF9,0x5C,0xC1,0xFB, ++ 0x48,0xF8,0x8D,0x46,0xFD,0xD4,0x11,0xF2,0xE8,0x2E,0x78,0x45,0xCD,0xFA,0xCB,0xF0, ++ 0x7B,0x45,0x88,0xF2,0x39,0xD7,0xD6,0x6C,0xE6,0x90,0x92,0x95,0x91,0x6C,0xD1,0x6C, ++ 0x55,0x11,0x98,0xF6,0x41,0x01,0x80,0xF6,0xF2,0x10,0xF2,0x4C,0x00,0x90,0x5C,0x45, ++ 0xC7,0xD2,0xD4,0xB3,0xCC,0xDA,0xCA,0xB0,0x11,0xF2,0x94,0x86,0xD0,0x2C,0x50,0x09, ++ 0x88,0x8E,0xD1,0x24,0xC1,0x34,0xD8,0x4C,0xD1,0x00,0x54,0x9D,0xA0,0x82,0xDE,0x1C, ++ 0xD1,0x3C,0xE8,0x4C,0xD1,0x90,0x5E,0x85,0xA8,0xD2,0xEA,0x14,0xDA,0x04,0xD8,0xE8, ++ 0x36,0x1A,0xD3,0x90,0x90,0x95,0xDA,0x00,0x93,0x1D,0xD2,0x40,0x2C,0x01,0x38,0x01, ++ 0x50,0x01,0xD8,0x56,0xF5,0xCC,0x11,0x92,0xD0,0x3E,0x58,0x01,0xD9,0x2E,0xF0,0xC4, ++ 0x10,0x9A,0xD5,0x16,0xC1,0x33,0x18,0xF2,0x83,0x33,0x20,0x12,0x90,0x95,0xCA,0xD8, ++ 0x92,0xDD,0xC2,0x00,0xE7,0x68,0x93,0x6D,0x6F,0x11,0xC8,0x4E,0x04,0xE7,0x10,0x9A, ++ 0x90,0x0E,0x10,0x09,0x90,0x2C,0xD8,0x24,0xD6,0x34,0xC0,0x90,0x90,0x95,0x96,0x34, ++ 0xD8,0x1C,0xD0,0x3C,0xC6,0x90,0x96,0x95,0x90,0x3C,0xD0,0x14,0xDA,0x0C,0x00,0x90, ++ 0xC0,0x90,0x96,0x0C,0xD8,0x14,0xD0,0x04,0xC0,0x90,0x96,0x04,0xE6,0x00,0x92,0x05, ++ 0xD4,0xF4,0x11,0x82,0x92,0x06,0x38,0x3F,0xC2,0x74,0xE1,0x00,0x91,0x05,0x86,0x74, ++ 0xC0,0x74,0x41,0x11,0x97,0x06,0x30,0xAF,0xC2,0x7C,0xE1,0x00,0x91,0x05,0x86,0x7C, ++ 0xC0,0x7C,0x41,0x21,0x97,0x06,0x30,0x37,0x00,0x0F,0x00,0x41,0x81,0x64,0xC1,0x64, ++ 0x41,0x41,0x88,0xD6,0x10,0x01,0x00,0x01,0x58,0x8A,0xE8,0xC8,0xB4,0xF2,0xB4,0x7A, ++ 0x31,0x8A,0x31,0xDA,0x40,0x09,0x88,0x1E,0x12,0x4A,0x92,0x4D,0x12,0xDA,0x92,0xDD, ++ 0xE7,0x6C,0xC2,0x18,0x92,0xDD,0xE2,0x74,0xC2,0x08,0x93,0x65,0x04,0x08,0xC4,0x48, ++ 0x90,0x4D,0x5E,0x01,0xD9,0x76,0xE8,0xCC,0x10,0x5A,0xD5,0x5E,0x60,0x01,0xD8,0x4E, ++ 0xED,0xC4,0x11,0x62,0xD1,0x36,0x68,0x9D,0xA1,0x62,0x63,0x85,0xA0,0x1A,0x03,0x3F, ++ 0x70,0x52,0x07,0x00,0x62,0x9D,0xD9,0x74,0xA1,0x1A,0x63,0x85,0xDB,0x6C,0xA2,0x1A, ++ 0xE6,0x00,0x92,0x05,0x46,0x11,0x98,0x9E,0xE6,0x90,0x92,0x95,0x56,0x21,0x98,0x56, ++ 0x58,0x85,0xD9,0xC3,0xA8,0xC3,0xC0,0xC3,0x90,0xC3,0x00,0x01,0x81,0xFC,0x58,0x85, ++ 0xD8,0xC3,0xA8,0xC3,0xC0,0xC3,0x90,0xC3,0x00,0x01,0x80,0xE4,0x30,0x3A,0x80,0xEC, ++ 0xC4,0xAC,0xCA,0x03,0x80,0xD4,0x01,0x01,0x0E,0x01,0x00,0x18,0x54,0xA5,0xC0,0xD0, ++ 0x32,0xA2,0x04,0x20,0xC6,0x10,0x93,0x95,0x6D,0x9D,0xE1,0x72,0x33,0x2A,0xA3,0x72, ++ 0x6D,0x85,0xE1,0x6A,0x32,0x12,0xC3,0x90,0x8A,0xAB,0xE0,0x48,0x90,0x4D,0x4E,0x19, ++ 0x98,0x86,0x47,0x09,0x80,0x0E,0x40,0x19,0x88,0x66,0x60,0xA5,0xE3,0x0A,0x37,0x12, ++ 0xCB,0x93,0x30,0x2A,0xC7,0x6B,0xA5,0x2A,0x34,0x1A,0xCB,0xE3,0x8C,0xE3,0x80,0xCB, ++ 0x34,0x0A,0x8B,0x53,0x09,0x09,0x88,0x0C,0x09,0x01,0x88,0x74,0xD3,0x74,0x31,0x0A, ++ 0xE1,0x4A,0xDC,0x74,0x36,0x12,0xC3,0x90,0xCA,0x9B,0xC0,0xAB,0xC9,0x93,0x92,0x14, ++ 0xD0,0x74,0x51,0x01,0x88,0x16,0x41,0x01,0x80,0x0E,0x40,0x19,0x8D,0x5E,0x10,0x4A, ++ 0x98,0x4E,0x10,0x09,0x90,0x04,0x41,0x01,0x8A,0x16,0xF0,0x10,0x90,0x0C,0x01,0xF7, ++ 0x11,0x09,0x90,0x0C,0x00,0xDF,0x40,0x09,0x80,0x0E,0x40,0x11,0x8D,0x5E,0x10,0x4A, ++ 0xC0,0x4E,0x10,0x09,0x90,0x04,0x41,0x09,0x8C,0x16,0xF0,0x10,0x90,0x0C,0x01,0x77, ++ 0x11,0x09,0x90,0x0C,0x00,0x5F,0x10,0x01,0x90,0x04,0x01,0x47,0x11,0x09,0x90,0x04, ++ 0x40,0x11,0x90,0x16,0xF1,0x90,0x94,0x0C,0x00,0x0F,0x10,0x09,0x90,0x0C,0x41,0x01, ++ 0x80,0x0E,0x40,0x19,0x8D,0x0E,0x10,0x4A,0x90,0x2E,0x40,0x09,0x80,0x0E,0x40,0x11, ++ 0x8D,0x26,0x10,0x4A,0xC0,0x16,0x10,0x09,0x94,0x54,0x01,0x8F,0x11,0x01,0x90,0x54, ++ 0x01,0x77,0xF4,0xC4,0x33,0x12,0x19,0x92,0xF1,0xA4,0x92,0xE4,0xC9,0x90,0xF4,0xEC, ++ 0xC9,0x90,0x94,0x5C,0xD0,0x5C,0xC1,0x93,0x92,0xDC,0x31,0x90,0xA1,0xCE,0xD1,0xE4, ++ 0xF2,0xA4,0x02,0x90,0xC9,0x90,0xF4,0x3C,0x04,0xB0,0xCB,0x90,0x35,0x39,0x09,0xB0, ++ 0xC8,0xB0,0x14,0xE1,0xF1,0x92,0xF5,0xD4,0x10,0x92,0xD5,0x26,0xF0,0x64,0x71,0x41, ++ 0x88,0xB6,0x50,0x01,0xD9,0xA6,0xF0,0xDC,0x48,0xB0,0x87,0x06,0x80,0x90,0xF2,0xE4, ++ 0xC0,0xB0,0xB5,0xE4,0xF2,0x3C,0x19,0xB2,0xC8,0xB8,0xF7,0xEC,0x1C,0x12,0xCB,0x90, ++ 0x90,0xEC,0xD0,0xFC,0xE4,0x90,0x92,0x95,0x91,0xFC,0xD0,0xDC,0x48,0x90,0x8E,0xEE, ++ 0xD0,0x4C,0xF2,0xF4,0xD5,0x93,0x12,0x92,0xC1,0x2E,0xD0,0xDC,0x31,0x01,0x1E,0x92, ++ 0xF1,0x5C,0x81,0x93,0x01,0x47,0xD0,0xDC,0x31,0x01,0x1A,0x92,0xF1,0x5C,0x81,0x93, ++ 0x01,0x17,0xD0,0x04,0x50,0x09,0x80,0x4E,0xD0,0x04,0x51,0x09,0x8A,0x36,0xD0,0x6C, ++ 0x10,0xA2,0x84,0x1E,0xD5,0x0C,0xC1,0x10,0x95,0xA5,0x3A,0x57,0x10,0x4A,0x8D,0xDE, ++ 0xD4,0x14,0x11,0x9A,0x89,0xC6,0xC8,0x74,0xE6,0x48,0x92,0x4D,0x89,0x74,0xC9,0x74, ++ 0x48,0x11,0x90,0x06,0x3A,0x97,0xE2,0x00,0x90,0x05,0x46,0x21,0x91,0x06,0x38,0x1F, ++ 0xC6,0x34,0xCA,0x03,0x42,0x01,0x88,0x5E,0xC9,0xAC,0x8A,0x01,0xE0,0x43,0x36,0x10, ++ 0xAA,0x36,0x31,0x00,0x71,0x00,0x04,0x27,0xD0,0x54,0x51,0x01,0x8D,0x5E,0x10,0x4A, ++ 0xCA,0x16,0xF0,0x48,0x90,0x4D,0x06,0x1F,0x10,0x4A,0x95,0x0E,0xE6,0x48,0x92,0x4D, ++ 0x11,0x09,0x90,0x54,0x01,0x67,0xD0,0x14,0x10,0x9A,0xCC,0x16,0xF6,0xD8,0x92,0xDD, ++ 0x01,0x27,0xD0,0x14,0x10,0x9A,0x94,0x0E,0xE6,0xD8,0x92,0xDD,0x11,0x01,0x90,0x54, ++ 0x91,0x55,0x92,0x3C,0x97,0xE5,0x72,0xFA,0xD4,0x3C,0xC9,0x90,0x93,0xEC,0x39,0x47, ++ 0x02,0x01,0xD0,0xAC,0x6C,0x94,0x16,0x12,0x9A,0xD6,0xC0,0xAC,0xE8,0x4B,0x70,0x04, ++ 0x10,0x42,0x9C,0x26,0xC4,0x4C,0xD2,0x03,0xF6,0x00,0x94,0x05,0x02,0x1F,0xC0,0x4C, ++ 0xD4,0x03,0xE4,0x00,0x90,0x05,0xCE,0xFC,0x10,0x0A,0x9C,0x4E,0xC0,0xAC,0x0A,0x01, ++ 0xBA,0x0B,0xC0,0x54,0x08,0xD9,0xC7,0x03,0x02,0x42,0xC8,0x54,0x82,0x43,0x28,0x37, ++ 0x27,0x01,0x28,0xF9,0xA8,0x09,0x60,0x01,0x8A,0x56,0xC0,0x44,0xC8,0xC4,0xB9,0x9C, ++ 0xD2,0x34,0x4A,0x93,0x92,0x94,0xD0,0x74,0x5A,0x3A,0x07,0x90,0xF0,0xF2,0x04,0x57, ++ 0xC1,0x3C,0xCA,0xCC,0xD0,0xEC,0x90,0x9C,0xD4,0x34,0x4A,0x93,0x92,0x94,0xD0,0x6C, ++ 0x5A,0x12,0x07,0x90,0xF0,0xF2,0x44,0x01,0x82,0x16,0xF0,0x48,0x10,0x42,0x8C,0x8E, ++ 0xD0,0x74,0x92,0x04,0x91,0x05,0x36,0x0A,0xDA,0x6C,0xD2,0x5C,0xBB,0xEF,0xD7,0x77, ++ 0x35,0x4A,0x11,0x42,0xE8,0x0E,0x30,0x42,0x00,0x17,0x40,0x01,0xD0,0x06,0x00,0x01, ++ 0xC8,0x30,0x04,0x07,0xB0,0x01,0xC4,0x9C,0xC8,0xE4,0x10,0x00,0x86,0x0F,0xE8,0x27, ++ 0xCC,0x94,0xC8,0x00,0x18,0x42,0x42,0x01,0xD0,0x06,0x00,0x01,0xA0,0x00,0x60,0x01, ++ 0x8A,0x7E,0xC8,0x34,0x54,0x4C,0x10,0x0A,0xD0,0x06,0x30,0x42,0xC8,0xAC,0x12,0x31, ++ 0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90,0xC2,0x48,0x04,0x44, ++ 0x02,0x77,0xC8,0x34,0x54,0x4C,0x12,0x0A,0xD0,0x06,0x30,0x42,0xC8,0xAC,0x12,0x31, ++ 0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90,0xC4,0x48,0x04,0x44, ++ 0xE7,0x20,0x93,0x25,0x64,0x09,0xC8,0xF6,0xC0,0xAC,0x12,0x31,0xE0,0x0B,0xC2,0xE4, ++ 0x02,0x42,0xCE,0xAC,0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90, ++ 0xC6,0x48,0x04,0x44,0xC2,0xAC,0xCA,0x74,0xFA,0x03,0x00,0x10,0xC0,0xA4,0xC2,0x90, ++ 0x02,0x89,0x0B,0x00,0xC4,0x90,0xA8,0x8B,0xCA,0xAC,0xD2,0x6C,0xFA,0x4B,0x00,0x58, ++ 0xCA,0xA4,0xC2,0xC8,0xC6,0x40,0xA8,0x13,0xC2,0xAC,0xCA,0xAC,0xFA,0x03,0xE0,0x00, ++ 0xBD,0x43,0x20,0xE7,0xAC,0xFD,0x87,0xBD,0xEC,0x04,0x31,0xA2,0xD8,0x43,0x87,0x84, ++ 0xD8,0x43,0x85,0x7C,0xC8,0x43,0x81,0x74,0x00,0x01,0x80,0x54,0x42,0x22,0x45,0x0B, ++ 0x36,0x42,0x81,0x01,0x80,0xB4,0x48,0x01,0x80,0x1E,0xC0,0x74,0x40,0x00,0x82,0x5C, ++ 0x00,0x67,0xC0,0xB4,0xC8,0x03,0x46,0x51,0x98,0x26,0xC8,0xB4,0x00,0x49,0xB0,0x42, ++ 0x80,0x5C,0x00,0x1F,0xC0,0xB4,0x08,0x41,0xB0,0x0A,0x8A,0x5C,0x40,0xCA,0xD4,0xD4, ++ 0xC8,0xBC,0xC0,0x80,0x80,0xAC,0x48,0x01,0x84,0xF6,0x49,0xBA,0xC2,0xD4,0xC0,0x08, ++ 0x10,0x49,0xC5,0xD4,0x04,0x90,0xC4,0x18,0xE0,0xAC,0xC0,0x74,0x42,0x00,0x12,0x02, ++ 0x90,0x05,0x82,0x54,0x30,0x01,0x00,0x7F,0x00,0x01,0x00,0x47,0x40,0x7C,0x40,0xD4, ++ 0xD1,0xD0,0x05,0x14,0xE4,0x20,0xE5,0x48,0xE2,0xD8,0xE4,0x00,0x90,0x05,0xD6,0x7C, ++ 0x17,0x82,0x9C,0x9E,0xE7,0xB0,0x93,0xB5,0xC4,0x84,0x10,0x32,0x9B,0x66,0x37,0x02, ++ 0x40,0x01,0x80,0x06,0x3C,0x02,0x4C,0x2A,0xC2,0xD4,0xC0,0x18,0x48,0x1A,0xC4,0xD4, ++ 0x8A,0xC1,0xC1,0x00,0x50,0x0A,0xCC,0xD4,0x94,0x81,0xC3,0x48,0x10,0x01,0x00,0x47, ++ 0x40,0x24,0x40,0x74,0xD8,0x20,0x05,0xE4,0xE4,0xD8,0xE4,0x00,0xE2,0x48,0xE4,0x90, ++ 0x90,0x95,0xE6,0x7C,0x17,0x12,0x9D,0x9E,0x48,0x92,0xC3,0xD4,0xC0,0x00,0x82,0x4C, ++ 0xE0,0xAC,0x00,0x01,0x81,0x8C,0x30,0x42,0x80,0x01,0x81,0xA4,0x80,0x01,0x86,0x9C, ++ 0x08,0x97,0x32,0x01,0x08,0x47,0xC2,0x4C,0xC4,0x03,0x48,0x00,0x89,0xF6,0xF3,0x02, ++ 0xCC,0x74,0x10,0x42,0xD8,0xD6,0xC3,0x7C,0x32,0x5A,0x03,0x00,0xD0,0x08,0x31,0x52, ++ 0xD6,0x01,0x59,0x94,0x10,0xD4,0x40,0x54,0x12,0xD4,0x42,0x4C,0x11,0xCC,0x34,0x0A, ++ 0xCE,0x01,0x59,0x4C,0x11,0xCC,0x46,0x0C,0x1B,0xCC,0x40,0x0C,0x18,0xCC,0xCA,0x08, ++ 0x31,0x52,0xD0,0x01,0x5C,0x94,0x1E,0xD4,0xD6,0x02,0x19,0xC4,0x40,0x44,0x22,0xC4, ++ 0x40,0x25,0x70,0x01,0x88,0x26,0x08,0x01,0x16,0xCC,0x10,0xCC,0x18,0xCC,0x04,0x47, ++ 0xCA,0x7C,0xF0,0x48,0x10,0x72,0x8C,0x26,0x0B,0x01,0x30,0x5A,0x12,0xCC,0x1C,0xCC, ++ 0x20,0xCC,0xC8,0x8C,0x48,0x01,0x88,0x26,0x30,0x5A,0x13,0xCC,0x14,0xCC,0x12,0xCC, ++ 0x00,0x4F,0xC8,0x84,0xD2,0x8C,0xF0,0x48,0x10,0x52,0x8C,0x26,0x0B,0x01,0x30,0x5A, ++ 0x1E,0xCC,0x1C,0xCC,0x20,0xCC,0x10,0x01,0xF3,0x12,0x35,0x5A,0x0A,0x81,0xF0,0xCA, ++ 0x11,0x8A,0xD4,0x9E,0x0A,0x91,0xF0,0xCA,0x17,0x8A,0xD4,0xD6,0x0A,0xA1,0xF0,0xCA, ++ 0x17,0x8A,0xD4,0xB6,0x0A,0xB1,0xF0,0xCA,0x17,0x8A,0xD4,0x96,0x0A,0xD1,0xF0,0xCA, ++ 0x11,0x8A,0xE4,0x1E,0x0A,0xE1,0xF0,0xCA,0x17,0x8A,0xE4,0xD6,0x0A,0xF1,0xF0,0xCA, ++ 0x17,0x8A,0xE4,0xB6,0x0A,0x01,0xF1,0xCA,0x17,0x8A,0xE4,0x96,0x0A,0xD1,0xEC,0x4A, ++ 0x4B,0x01,0x80,0xCE,0x08,0x01,0x88,0x6C,0x30,0x72,0x8C,0x1C,0x88,0x64,0xD8,0xBC, ++ 0x5A,0x01,0x88,0x1E,0x32,0xE2,0xFC,0x78,0x1E,0x01,0xF0,0x1A,0x10,0xDA,0xD5,0x46, ++ 0xC0,0xC8,0x92,0x4D,0xDA,0x1C,0xE0,0xD8,0x90,0xDD,0x06,0x07,0x00,0xF7,0x9D,0x1C, ++ 0x00,0x2F,0x58,0x51,0xEB,0x1E,0x30,0x9A,0xE6,0xD8,0x92,0xDD,0x34,0xF2,0xE4,0x00, ++ 0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x36,0xE2,0x30,0x1A,0x5B,0x49,0x9A,0x26,0xC7,0x80, ++ 0x90,0x05,0xD0,0xA4,0x70,0x4C,0xE9,0x93,0x10,0x8A,0x9C,0xB6,0xCC,0x5C,0x10,0x42, ++ 0xD3,0x9E,0x30,0x8A,0x48,0x39,0x98,0x36,0xCA,0x5C,0x80,0x48,0x10,0x0A,0xDC,0x66, ++ 0xC0,0x1C,0x40,0x01,0x88,0x4E,0xC0,0xB4,0xC8,0x03,0x46,0x11,0x98,0x0E,0x00,0x09, ++ 0x80,0x6C,0x48,0xDA,0xC2,0x43,0xE2,0x00,0x80,0x43,0x4A,0xCA,0xC0,0x43,0x40,0x81, ++ 0x90,0x26,0x52,0xC2,0xA2,0xB2,0xE0,0x00,0x81,0x43,0x00,0xFF,0x34,0xB2,0x84,0x98, ++ 0xC0,0x98,0x96,0xDD,0x98,0x14,0x18,0x01,0x30,0xE2,0xDC,0x54,0x80,0xD8,0x9A,0x94, ++ 0x1E,0x01,0xF0,0x1A,0xFD,0x94,0x10,0xDA,0xD3,0x56,0x30,0xBA,0xC9,0xF8,0x96,0xFD, ++ 0x30,0xF2,0xFD,0x54,0x10,0xDA,0xD5,0x1E,0x86,0xB8,0xCA,0xB8,0x90,0xFD,0xB9,0x14, ++ 0xC0,0xC8,0x02,0x97,0x60,0x20,0x02,0x00,0x70,0x32,0x06,0x00,0x70,0x32,0x04,0x00, ++ 0x80,0x40,0x07,0x01,0x48,0xE0,0x06,0x00,0x28,0x60,0x00,0x00,0x68,0x70,0x04,0x00, ++ 0x00,0xC0,0x00,0x01,0x80,0xC0,0x06,0x01,0x00,0xF7,0x90,0x4D,0xE3,0x00,0x34,0x1A, ++ 0xE6,0xD8,0x92,0xDD,0x33,0xE2,0x34,0x1A,0x5E,0x49,0x98,0x8E,0xC4,0x14,0x10,0x0A, ++ 0xD8,0x16,0xC8,0x5C,0x28,0x72,0xD4,0x0E,0x00,0x09,0x80,0x6C,0xC6,0xB4,0xC8,0x03, ++ 0x40,0x51,0x98,0x16,0xC0,0xBC,0x40,0x01,0x80,0x46,0xC8,0x6C,0x00,0x09,0x48,0x01, ++ 0x80,0x06,0x00,0x01,0x80,0x64,0x00,0x0F,0x00,0x09,0x80,0x64,0xC0,0x64,0x40,0x01, ++ 0x80,0xA6,0x01,0x09,0xBC,0x43,0x43,0x3A,0x40,0x03,0x42,0x01,0x88,0x5E,0xC0,0xB4, ++ 0xC8,0x03,0x46,0x51,0x90,0x3E,0xC0,0xA4,0x6E,0x4C,0xE7,0x03,0x32,0x00,0x72,0x00, ++ 0x84,0x51,0x10,0x0A,0xC8,0x0E,0x10,0x01,0x00,0x07,0x10,0x09,0xC0,0xC4,0x40,0x01, ++ 0x80,0x06,0x10,0x11,0xC0,0xD4,0x90,0x14,0x81,0x04,0x30,0x9A,0xA9,0x0C,0x30,0x02, ++ 0xD0,0x8C,0xC8,0x4C,0xBA,0xFF,0xD7,0x37,0xC0,0x9C,0xC0,0x03,0x38,0x00,0xAA,0x1E, ++ 0xFF,0x43,0xF9,0x4B,0x10,0x42,0x9C,0x4E,0xC0,0x9C,0xC0,0x03,0x38,0x00,0xA2,0x1E, ++ 0x05,0x01,0xA8,0x43,0xCC,0x9C,0x80,0x43,0x87,0xDD,0xE8,0x85,0xE0,0x20,0xC5,0x4C, ++ 0xE0,0x00,0x82,0x4C,0xE7,0xB0,0x93,0xB5,0xC4,0x7C,0x10,0x32,0x95,0x06,0x30,0x97, ++ 0xC2,0x8C,0xE0,0x00,0x90,0x05,0x86,0x8C,0xC8,0x84,0xC0,0x8C,0x10,0x42,0x94,0x06, ++ 0x37,0x3F,0x3D,0x4F,0xAC,0x9D,0x87,0x0D,0xD8,0x43,0x80,0x04,0xDB,0x63,0x52,0x12, ++ 0xC4,0x0C,0xC0,0x28,0x50,0x02,0xC3,0x0C,0xD4,0xC1,0xC1,0x30,0xE8,0x43,0x0C,0xF1, ++ 0x84,0x0F,0xD8,0x97,0x49,0xE9,0x88,0x0E,0x48,0xE2,0xC2,0x0C,0xC5,0x10,0x0A,0x49, ++ 0xC4,0x0C,0x00,0x48,0xC0,0x08,0x1A,0x01,0x00,0x5F,0x00,0x01,0x00,0x2F,0x40,0x7C, ++ 0x04,0xBC,0xE0,0x90,0xE2,0x48,0xE4,0x00,0x95,0x05,0x16,0x02,0x9A,0xBE,0xE7,0xD8, ++ 0x90,0xDD,0xC6,0x04,0x17,0x1A,0x9C,0x86,0x00,0x01,0x00,0x2F,0x41,0x8C,0x01,0x4C, ++ 0xE5,0x68,0xE5,0xB0,0xE6,0x00,0x92,0x05,0x17,0x02,0x9D,0xBE,0x48,0x62,0xC2,0x0C, ++ 0xC0,0x00,0x12,0x01,0x00,0x67,0x08,0x01,0x00,0x37,0xC0,0x1B,0x34,0xD8,0x74,0xD8, ++ 0x82,0x1B,0xE0,0x00,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xB6,0xE6,0x90,0x92,0x95, ++ 0xCC,0x04,0x10,0x52,0x9F,0x7E,0xEF,0xF5,0xAC,0xFD,0x87,0x1D,0x30,0x6A,0x30,0x01, ++ 0xBB,0x73,0xB9,0x73,0x37,0x42,0x81,0x01,0xC7,0x0B,0x10,0xE9,0x02,0x52,0x38,0x48, ++ 0x7A,0x48,0x06,0x48,0x18,0x52,0x80,0x13,0xC7,0x0B,0x10,0xD9,0x00,0x8A,0x80,0x0B, ++ 0x34,0x42,0x81,0x01,0x84,0x14,0xF0,0x03,0x78,0xB2,0x41,0x01,0x80,0x4E,0x00,0x01, ++ 0x57,0xAA,0x09,0xF9,0xA2,0x8A,0xE0,0x00,0x90,0x05,0x46,0x81,0x99,0xD6,0x87,0xF3, ++ 0x80,0xF3,0xAB,0x04,0x00,0x01,0xD8,0x1C,0xD0,0x34,0xC8,0x2C,0xBD,0xFF,0xEF,0xD7, ++ 0x36,0x62,0xA1,0x01,0xC8,0x03,0x47,0x51,0x98,0x36,0xA8,0x04,0x00,0x09,0xD8,0x1C, ++ 0xD0,0x34,0xC8,0x2C,0xBD,0xFF,0xEF,0x77,0xC4,0x14,0xF0,0x0B,0x49,0x01,0x80,0xD6, ++ 0x00,0x01,0x48,0x09,0x8B,0x5E,0xC0,0xD3,0x50,0x01,0x80,0x46,0x50,0x1A,0xC1,0x93, ++ 0x50,0x01,0x88,0x26,0x50,0x12,0xC1,0x93,0x50,0x01,0x88,0x06,0x00,0x09,0x40,0x01, ++ 0x87,0x2E,0xC8,0x13,0x50,0x01,0x95,0x36,0xE7,0x90,0x8A,0x13,0x07,0x1F,0xC8,0x13, ++ 0x50,0x51,0x90,0x06,0x8F,0x33,0xCF,0x13,0x50,0x51,0x98,0xE6,0x40,0x01,0x88,0x6E, ++ 0x48,0x09,0x88,0x16,0xF7,0x90,0x8A,0x13,0x01,0x47,0x00,0x99,0xEF,0x02,0x6A,0x4C, ++ 0x34,0x00,0x72,0x00,0x10,0x0A,0x94,0x0E,0xF7,0x90,0x8A,0x13,0xC0,0xC3,0x43,0x11, ++ 0x9D,0x16,0x00,0x01,0x88,0x03,0x07,0x37,0x40,0x09,0x88,0x26,0xCA,0x03,0x47,0x81, ++ 0x93,0x0E,0x00,0x21,0x89,0x03,0x37,0x4A,0xC7,0x1C,0xB8,0xFF,0xF8,0xDF,0x81,0x3D, ++ 0xE8,0x85,0x07,0x00,0x80,0x40,0x07,0x01,0x68,0xF0,0x07,0x00,0x28,0x60,0x00,0x00, ++ 0x60,0x20,0x02,0x00,0x00,0xC0,0x00,0x01,0x80,0xC0,0x06,0x01,0x00,0x40,0x00,0x01, ++ 0x00,0x48,0x00,0x01,0xAC,0xFD,0x87,0x3D,0xE0,0x84,0x30,0xB2,0x00,0x01,0x80,0x2C, ++ 0xD8,0x83,0x83,0x1C,0x60,0x8C,0x89,0x14,0xCA,0x44,0x18,0x0A,0x50,0xFA,0xC7,0x3C, ++ 0xC0,0x00,0xC4,0x48,0x8F,0x34,0x40,0xF2,0xC0,0x03,0x40,0x09,0x89,0x0E,0xE0,0x83, ++ 0x80,0x1C,0x00,0x01,0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05, ++ 0xDC,0x1C,0x10,0xC2,0x98,0xC6,0x0F,0x01,0x00,0x09,0xD8,0x54,0xD0,0x44,0x80,0x07, ++ 0xD0,0xAF,0x2E,0x01,0x60,0x01,0x88,0x0E,0xE7,0x68,0x93,0x6D,0xF8,0x34,0x08,0x01, ++ 0x01,0x5F,0xC0,0xC3,0x1E,0x02,0x91,0x05,0x80,0xC3,0xD1,0x8C,0x10,0x82,0xCC,0x0E, ++ 0x19,0x02,0x85,0xC3,0xE2,0xF8,0xE3,0x48,0x90,0x4D,0xC6,0x1C,0x17,0x0A,0x9C,0x86, ++ 0x48,0x42,0xC7,0x3C,0xC0,0x00,0x82,0x24,0xD0,0x54,0x90,0x04,0x30,0x9A,0x01,0x11, ++ 0xD0,0x3C,0xC8,0x44,0x80,0x07,0xD8,0x47,0xD0,0x54,0x90,0x04,0x04,0x41,0xEA,0x0A, ++ 0x00,0x01,0x1C,0x0A,0x30,0x9A,0x11,0x01,0xC0,0x24,0x80,0x07,0xF6,0x27,0x05,0x29, ++ 0xE8,0x02,0x44,0x31,0x88,0x16,0x00,0x01,0x87,0x5D,0xE8,0x85,0xC1,0x1C,0xD0,0xC0, ++ 0x09,0x01,0x00,0x3F,0xD0,0x24,0x18,0x01,0xF0,0x9A,0xD6,0x14,0xD0,0xD0,0x94,0x95, ++ 0x68,0x01,0x88,0x2E,0x50,0xC1,0xE8,0xBE,0xC5,0x13,0x18,0x12,0x80,0x13,0x00,0x9F, ++ 0x50,0x99,0xE8,0x2E,0xC0,0x13,0x50,0x01,0x82,0x16,0xF0,0x90,0x80,0x13,0x00,0x5F, ++ 0x68,0x29,0x88,0x4E,0x58,0xE1,0xEE,0x3E,0xC0,0x13,0x50,0x01,0x88,0x26,0xD0,0x2C, ++ 0x50,0x01,0x88,0x0E,0x10,0x09,0x90,0x2C,0xD4,0x24,0xE0,0x90,0x92,0x24,0xE0,0x00, ++ 0xE6,0x48,0x92,0x4D,0xD4,0x1C,0x10,0x8A,0x9B,0xA6,0x46,0x20,0x6C,0x21,0xC8,0xCE, ++ 0xD0,0x54,0x90,0x04,0x30,0x9A,0x09,0x01,0x00,0x19,0xD0,0x3C,0x85,0x07,0xD0,0xE7, ++ 0x08,0x09,0x30,0x42,0xD8,0x54,0xD0,0x44,0x83,0x07,0xD0,0x07,0xC5,0x2C,0x38,0xDF, ++ 0xAC,0xFD,0x87,0x1D,0xF0,0x64,0x30,0x7A,0x33,0xEA,0xD8,0xC3,0x85,0x14,0x48,0xAA, ++ 0xC2,0x1C,0xC0,0x20,0x40,0x92,0xC5,0x03,0x40,0x09,0x88,0x0E,0xE0,0xC3,0x81,0x14, ++ 0x08,0x01,0x00,0x09,0xD8,0x2C,0xD0,0x6C,0x82,0x07,0xD0,0x47,0xD0,0x2C,0x90,0x04, ++ 0x30,0xDA,0x01,0x11,0xD0,0x1C,0xC8,0x6C,0x84,0x07,0xD0,0xB7,0xD0,0x2C,0x90,0x04, ++ 0x06,0x41,0xEA,0x0A,0x00,0x01,0x1C,0x0A,0x30,0xDA,0x11,0x01,0x30,0x02,0x81,0x07, ++ 0xF0,0x97,0xD1,0x2C,0x91,0x04,0x30,0xDA,0x08,0x01,0x00,0x19,0xD0,0x1C,0x80,0x07, ++ 0xD0,0x1F,0x0C,0x09,0x30,0x42,0xD8,0x2C,0xD0,0x6C,0x80,0x07,0xD4,0x3F,0x41,0xF2, ++ 0x00,0x44,0x01,0x01,0x00,0x84,0x09,0x01,0x00,0x77,0x00,0x01,0xF0,0x02,0x11,0x01, ++ 0xF4,0x52,0x15,0x12,0xE9,0x06,0x00,0x44,0x15,0x01,0xF0,0x92,0x10,0x12,0xD4,0x06, ++ 0x05,0x84,0xE1,0x20,0xE6,0x48,0x92,0x4D,0xC4,0x14,0x10,0x0A,0x98,0x6E,0x87,0x3D, ++ 0xEF,0x85,0xAF,0xBD,0x80,0x55,0xC4,0x5C,0xD8,0x03,0x86,0x24,0xCA,0x5C,0xD8,0x4B, ++ 0x8C,0x1C,0x50,0x52,0xCC,0x54,0xC0,0x48,0x8C,0x4C,0x48,0x4A,0xC0,0x4B,0x48,0x09, ++ 0x88,0x46,0xC8,0x24,0xE6,0x48,0x92,0x4D,0x88,0x24,0x80,0x3C,0xC0,0x5C,0xE0,0x03, ++ 0x80,0x1C,0x00,0x0F,0x00,0x01,0x80,0x3C,0xF8,0x3C,0xC0,0x5C,0x80,0x01,0x86,0x44, ++ 0x04,0x7F,0x4B,0x12,0x04,0x01,0x00,0x43,0xC0,0x5C,0xC8,0x4C,0xDB,0x03,0x1A,0xC2, ++ 0xC0,0x08,0x02,0x01,0x10,0xF9,0x01,0x1F,0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05, ++ 0xDC,0x1C,0x10,0xC2,0x9C,0xC6,0x27,0x01,0x31,0x2A,0x31,0x32,0x03,0xE7,0x40,0xC2, ++ 0x08,0x23,0x4E,0x2D,0xB8,0x0C,0x88,0x04,0x40,0x55,0x40,0x3E,0x5F,0x35,0xB8,0xFF, ++ 0xF8,0x7F,0xC3,0x44,0xC8,0x03,0x42,0x31,0x83,0x7E,0x33,0x5A,0x00,0xC1,0xF0,0xC2, ++ 0x40,0xE1,0xD1,0x1E,0x68,0x41,0x80,0x4E,0x18,0x62,0x05,0x1F,0x70,0x01,0x8C,0x0E, ++ 0x30,0x72,0x01,0x1F,0x41,0x68,0x1B,0x62,0x6F,0x01,0x88,0x06,0xC0,0x5C,0xC8,0x4C, ++ 0xDB,0x03,0x1A,0xC2,0xC0,0x08,0x02,0x01,0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48, ++ 0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2,0x99,0xC6,0x37,0xAA,0x20,0x01,0x00,0x0F, ++ 0x1B,0xA2,0x41,0xB0,0x77,0x01,0x88,0xDE,0xC0,0x5C,0x60,0x04,0xC0,0x41,0x91,0x35, ++ 0x05,0xAF,0x18,0x62,0x46,0xD2,0x0A,0x23,0x48,0x2D,0xB8,0x0C,0x88,0x04,0x40,0x55, ++ 0x40,0x3E,0x58,0x35,0xB9,0xFF,0xFF,0xA7,0xC2,0x44,0xC8,0x03,0x42,0x31,0x80,0x6E, ++ 0x30,0x5A,0x03,0xA1,0xF5,0xC2,0x10,0x82,0xE9,0x06,0x18,0x62,0x40,0x68,0x6B,0x01, ++ 0x88,0x3E,0xC7,0x54,0x0E,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00,0xB3,0x23,0xE0,0xF8, ++ 0x90,0xFD,0xC7,0x24,0x14,0x3A,0x9C,0x66,0xF1,0x3C,0x00,0xA7,0xC3,0x54,0x08,0x59, ++ 0xCA,0x00,0x0C,0x48,0xC1,0x38,0xF2,0xC3,0x40,0x01,0x88,0x0E,0x01,0x09,0xB0,0xC3, ++ 0xF0,0xE3,0x29,0x01,0x01,0x01,0x00,0x0F,0xE7,0x68,0x93,0x6D,0x40,0x09,0x88,0x1E, ++ 0x60,0xF9,0x97,0x0E,0xE5,0x20,0x93,0x25,0x48,0xE2,0x01,0x01,0x00,0x43,0xAC,0x48, ++ 0x46,0xDA,0x09,0x23,0x20,0x00,0x67,0x10,0x00,0x0F,0x00,0xBF,0x40,0x48,0x32,0x82, ++ 0x17,0x42,0x80,0xDE,0x48,0x01,0xC9,0x06,0x08,0x01,0x89,0x04,0x90,0x0C,0x40,0x55, ++ 0x41,0x6E,0x30,0x8A,0xBA,0xFF,0xF7,0x77,0x40,0x01,0x80,0x0E,0x6E,0x29,0x98,0xDE, ++ 0xB3,0xE3,0xE1,0xB0,0x90,0xB5,0xC7,0x24,0x16,0x32,0x9C,0x3E,0x87,0x6D,0xE8,0x85, ++ 0xAC,0xBD,0x87,0x15,0x30,0x62,0x30,0xB2,0x48,0x2A,0x01,0x01,0x81,0x43,0x40,0x4A, ++ 0x40,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B,0x28,0x01,0x00,0x3F,0x09,0x09,0x30,0x9A, ++ 0x30,0x52,0x31,0x42,0x81,0x07,0xC8,0x57,0xE7,0x68,0x93,0x6D,0xDD,0x03,0x11,0x42, ++ 0xC1,0xA6,0x37,0x12,0x30,0x8A,0x01,0x11,0x84,0x07,0xC0,0x2F,0x31,0x92,0x31,0x0A, ++ 0xC7,0x14,0xB8,0xFF,0xF9,0x77,0x30,0x12,0x30,0x8A,0x01,0x01,0x83,0x07,0xC0,0xDF, ++ 0xE0,0x03,0x41,0x01,0x80,0xBE,0x69,0xB2,0x44,0x43,0x97,0x3D,0x4F,0x04,0x01,0x43, ++ 0x40,0x7A,0x08,0x09,0x81,0x0B,0x30,0x12,0x30,0x8A,0x01,0x11,0x83,0x07,0xC0,0x5F, ++ 0x30,0x1A,0xB1,0x04,0x08,0x01,0x00,0x09,0xD0,0x14,0x80,0x07,0xC8,0xAF,0xB2,0x04, ++ 0xD9,0x0B,0x37,0x1A,0x00,0x11,0xD0,0x14,0x82,0x07,0xC8,0x77,0x31,0x92,0x31,0x0A, ++ 0xC7,0x14,0xB8,0xFF,0xF1,0x37,0x37,0x12,0x30,0x8A,0x01,0x6F,0x60,0x20,0x02,0x00, ++ 0x00,0xD0,0x00,0x01,0x48,0xE0,0x06,0x00,0xF8,0xFB,0x07,0x00,0x10,0x00,0x00,0x42, ++ 0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x00,0x01,0x80,0x07,0xC0,0x27,0x42,0x5A, ++ 0x08,0x01,0x80,0x0B,0x01,0x7B,0x37,0x1A,0xB0,0x04,0x08,0x01,0x00,0x11,0xD0,0x14, ++ 0x81,0x07,0xC8,0x57,0x31,0x12,0x31,0x8A,0x00,0x11,0x80,0x07,0xC0,0xA7,0x51,0x22, ++ 0x40,0x83,0x08,0x11,0x18,0x42,0x04,0x83,0x87,0x2D,0xE8,0x85,0x00,0xD0,0x00,0x01, ++ 0x18,0x00,0x04,0x42,0xA8,0x85,0x31,0x12,0x92,0x01,0x46,0x8C,0x80,0x01,0xC7,0x1B, ++ 0x32,0xD8,0x72,0xD8,0x87,0x1B,0x58,0xE2,0x41,0xE3,0x30,0x20,0xA2,0x16,0x40,0xE3, ++ 0x3F,0x20,0xAB,0xE6,0x58,0xCA,0x27,0x41,0x00,0xE3,0x44,0xE3,0x28,0xF9,0xAF,0x19, ++ 0x18,0x62,0x01,0xE3,0xC7,0x23,0x48,0x20,0x8A,0x1E,0xF0,0x48,0x20,0x48,0x60,0x48, ++ 0x88,0xC6,0x4F,0x01,0x88,0x36,0x40,0xC3,0x08,0x81,0x18,0x42,0x07,0xC3,0x00,0xF9, ++ 0x82,0x89,0x04,0x84,0xEF,0x85,0xA9,0x85,0x46,0x63,0x42,0x5B,0xDF,0xAB,0x72,0x62, ++ 0xC0,0xB3,0x71,0x09,0x8E,0x16,0x48,0x63,0x50,0x5B,0xE2,0xAB,0x41,0x01,0x88,0x0E, ++ 0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42, ++ 0xC4,0x01,0x5A,0x33,0xC1,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3,0x1B,0x82,0x35,0x32,0x00,0x83,0x41,0x73, ++ 0xC4,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52, ++ 0x9F,0x06,0xEF,0x85,0x41,0x09,0x88,0x0E,0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32, ++ 0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3, ++ 0x1B,0x82,0x35,0x32,0x00,0x83,0x41,0x73,0xC0,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20, ++ 0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85,0x41,0x11,0x88,0x0E, ++ 0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42, ++ 0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3,0x1B,0x82,0x31,0x32,0x00,0x83,0x41,0x73, ++ 0xC4,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52, ++ 0x9F,0x06,0xEF,0x85,0x47,0x19,0x88,0xE6,0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32, ++ 0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3, ++ 0x1B,0x82,0x31,0x32,0x00,0x83,0x41,0x73,0xC0,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20, ++ 0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85,0xAA,0x85,0x47,0xE3, ++ 0x05,0xB0,0xCC,0x20,0x45,0xEB,0xC6,0x68,0x40,0x09,0x88,0x26,0x45,0xE3,0xC8,0x20, ++ 0x44,0xDB,0xC4,0xE8,0x04,0x3F,0x78,0xD2,0xC0,0xFB,0x79,0x09,0x8E,0x1E,0x48,0xE3, ++ 0xCA,0x20,0x55,0xDB,0xC1,0xE8,0x44,0x13,0xF9,0xA0,0xC0,0x5B,0x40,0x09,0x88,0x76, ++ 0x48,0x01,0x88,0x66,0x44,0x83,0x1A,0xC2,0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83, ++ 0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83,0x18,0xC2,0x00,0x83,0xE8,0x85,0x4F,0x09, ++ 0x8A,0x66,0x40,0x83,0x1A,0xC2,0x04,0x83,0x44,0x83,0x1C,0xC2,0x00,0x83,0x44,0x83, ++ 0x18,0xC2,0x04,0x83,0x40,0x03,0x19,0xC2,0x07,0x03,0xE9,0x85,0x48,0x11,0x88,0x66, ++ 0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83,0x18,0xC2,0x04,0x83,0x40,0x83,0x1A,0xC2, ++ 0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83,0xE8,0x85,0x4F,0x19,0x89,0xE6,0x47,0x03, ++ 0x19,0xC2,0x04,0x03,0x44,0x83,0x18,0xC2,0x02,0x83,0x40,0x83,0x1A,0xC2,0x04,0x83, ++ 0x40,0x83,0x1C,0xC2,0x07,0x83,0xEC,0x85,0xA8,0xFD,0xF7,0x4C,0x30,0x62,0x2C,0x01, ++ 0x4D,0x93,0x49,0x8B,0x32,0x72,0xDC,0xE3,0x33,0x3A,0x49,0x8A,0xC0,0x4B,0x48,0x09, ++ 0x89,0x0E,0x50,0x93,0xE0,0xE3,0x40,0x19,0x80,0x96,0x31,0x79,0x49,0x5A,0x13,0xB0, ++ 0x40,0x11,0x88,0xB6,0x32,0x02,0x1B,0x3A,0x58,0x52,0xC3,0x14,0xC1,0x00,0xC6,0xC0, ++ 0x33,0x9A,0x33,0x2A,0xEA,0xDA,0x0A,0x5B,0x08,0x01,0x00,0x3F,0xC1,0x1B,0x18,0x9A, ++ 0x41,0xAB,0x00,0x5B,0xEA,0x90,0xE0,0x00,0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xAE, ++ 0xE8,0xFD,0x47,0x01,0x88,0x8E,0x18,0x01,0x12,0x5B,0x46,0xDA,0x45,0x33,0x40,0xB0, ++ 0x00,0xB0,0x05,0x33,0x00,0x1B,0x02,0x5B,0x40,0x0B,0x18,0x81,0x18,0xCA,0x04,0x0B, ++ 0x44,0x0B,0x18,0x01,0x18,0xCA,0x00,0x0B,0x00,0x17,0x40,0x09,0x89,0x06,0x30,0xAA, ++ 0x00,0x01,0x00,0x27,0x40,0x8B,0x00,0x6B,0xEA,0x90,0xE0,0x00,0x95,0x05,0x16,0x02, ++ 0x9F,0xC6,0xEF,0xFD,0x3B,0x82,0xAB,0x85,0x4A,0xA3,0xD8,0xEB,0x33,0x70,0x72,0xB0, ++ 0x48,0x5A,0xC2,0x4B,0x48,0x09,0x88,0x0E,0x50,0xA3,0xE0,0xEB,0x08,0x01,0x00,0x3F, ++ 0x42,0x13,0x41,0x93,0x00,0x92,0x07,0x14,0xEC,0x20,0xE1,0x00,0xE6,0x48,0x92,0x4D, ++ 0x17,0x4A,0x9D,0xAE,0xEB,0x85,0xAB,0xC5,0x30,0x2A,0x30,0xB2,0x61,0xF2,0x41,0x03, ++ 0x14,0x01,0x1C,0x82,0x01,0x03,0x41,0x03,0x10,0x81,0x18,0x82,0x01,0x03,0x41,0x03, ++ 0x10,0x09,0x18,0x82,0x07,0x03,0xE1,0x53,0x00,0xF9,0x87,0x81,0x19,0x12,0x40,0xBA, ++ 0x10,0x13,0x16,0x99,0x00,0x13,0x13,0x41,0x04,0x13,0x14,0xD9,0xE8,0x92,0x52,0x01, ++ 0x80,0x16,0x10,0xC9,0x00,0x13,0x00,0x0F,0x10,0x89,0x00,0x13,0x31,0x52,0x30,0x5A, ++ 0x08,0x01,0x00,0x09,0xB7,0x04,0xB8,0xFF,0xF9,0x7F,0x33,0x52,0x30,0x8A,0x01,0x11, ++ 0xBB,0xFF,0xF7,0xCF,0x42,0x03,0x3B,0x00,0xAB,0xE6,0xEF,0xC5,0xAC,0x9D,0x87,0x8D, ++ 0xCA,0x94,0xC8,0x4B,0x88,0x84,0xE0,0x94,0xA7,0x01,0xD2,0x1B,0xD8,0x0B,0x89,0x04, ++ 0xCA,0x94,0xD8,0x6B,0x30,0x0A,0x88,0x71,0x30,0x62,0xCC,0x94,0x30,0x01,0xE8,0x4B, ++ 0x48,0x09,0x88,0x56,0x08,0x01,0x00,0x27,0xC5,0x38,0x9A,0xF3,0xA2,0x32,0xE2,0x48, ++ 0x90,0x4D,0xD2,0x94,0xDC,0x93,0x12,0x52,0xE0,0xB6,0x57,0xDA,0x04,0xB3,0x02,0xB3, ++ 0x00,0xB3,0x0E,0x01,0x18,0x4A,0x06,0x8B,0xCA,0x94,0xD8,0x4B,0xB0,0x8B,0x08,0x01, ++ 0x50,0xAA,0x30,0x01,0x05,0x78,0xC4,0xF8,0x0A,0xF3,0xC1,0x90,0xB2,0xB3,0xE2,0x48, ++ 0x90,0x4D,0x4A,0x11,0xD8,0xA6,0xCF,0x94,0xE8,0x4B,0x48,0x29,0xCD,0xF6,0x03,0x48, ++ 0xC3,0x48,0x00,0x50,0xC0,0x70,0x54,0x6A,0xC0,0xB0,0xB5,0x14,0xC0,0x48,0x8C,0x0C, ++ 0x30,0x12,0x33,0x32,0xB0,0xE1,0x08,0x01,0x88,0x34,0x48,0x4A,0x88,0x6C,0x88,0x64, ++ 0x30,0x32,0x04,0x01,0x32,0x22,0x04,0x97,0x18,0x00,0x04,0x42,0x00,0x01,0x00,0x42, ++ 0x00,0xD0,0x00,0x01,0x60,0x20,0x02,0x00,0x80,0x40,0x07,0x01,0x48,0xE0,0x06,0x00, ++ 0x78,0xF8,0x07,0x00,0xC8,0x14,0x00,0x01,0xF0,0x42,0xF8,0x0C,0x0B,0x01,0xF0,0xCA, ++ 0x32,0x7A,0xD0,0x08,0x97,0x4D,0x48,0xF9,0xEF,0x06,0x08,0xF9,0xCB,0x38,0x86,0xF8, ++ 0x78,0xF9,0xEF,0x06,0x3B,0xF9,0x37,0x82,0x82,0x3B,0xE0,0x00,0x30,0x32,0xC4,0xBB, ++ 0x10,0xFA,0x9C,0x46,0x10,0xCA,0xDC,0x36,0x46,0x84,0xD9,0x48,0xC0,0x00,0x92,0x05, ++ 0x04,0x84,0x81,0x08,0x04,0x37,0x10,0xCA,0xDC,0x16,0x00,0x78,0x00,0xBC,0x01,0x0F, ++ 0x39,0x01,0x00,0xBC,0x10,0xCA,0xDC,0x0E,0x38,0x09,0xB8,0x34,0x43,0x78,0x2B,0x3A, ++ 0xE8,0x26,0xF8,0x6C,0x10,0x7A,0xEC,0x2E,0x88,0x6C,0x00,0x1F,0xFC,0x64,0x10,0x7A, ++ 0xE8,0x06,0x88,0x64,0x82,0x8B,0xE0,0x90,0xE0,0xB0,0xC5,0x14,0xE0,0x00,0x84,0x14, ++ 0xC4,0x0C,0xE0,0x00,0x83,0x0C,0x30,0x02,0xE2,0x00,0x92,0x05,0x35,0x22,0x2C,0x62, ++ 0xD8,0xC6,0xC5,0x34,0x40,0x01,0x80,0x8E,0x08,0x01,0x00,0x01,0x80,0x5C,0xC0,0x04, ++ 0xC2,0x00,0x46,0x00,0x80,0x7C,0xC0,0x04,0x30,0x00,0x72,0x00,0x80,0x74,0x00,0x01, ++ 0x30,0x22,0x84,0x2C,0x80,0x24,0x80,0x1C,0xF0,0x90,0x02,0x07,0x03,0x1F,0xF5,0x40, ++ 0x94,0x05,0x32,0x32,0x03,0xFF,0x31,0x02,0x04,0x00,0x32,0x22,0xC2,0x2C,0x00,0x00, ++ 0x80,0x2C,0xC0,0x24,0x00,0x00,0x82,0x24,0xC2,0x1C,0x00,0x00,0x83,0x1C,0x40,0x40, ++ 0x28,0x82,0xEB,0x26,0xC0,0x83,0xF0,0x6C,0xD8,0x00,0x84,0x83,0x00,0x1F,0xC0,0x83, ++ 0xF4,0x64,0xD8,0x00,0x80,0x83,0xC0,0x83,0x73,0x3D,0x30,0xBA,0xA8,0x82,0xC7,0x83, ++ 0x10,0xC2,0xDC,0xDE,0xE2,0x48,0x92,0x4D,0xF1,0x5C,0xC0,0xB0,0x90,0xB5,0xB1,0x5C, ++ 0x30,0x32,0x3B,0x09,0x1D,0xF2,0x31,0xA2,0xF5,0x7C,0x10,0x82,0xD8,0x76,0xF0,0x2C, ++ 0x18,0xF2,0xB1,0x2C,0xF5,0x04,0x10,0x82,0xD8,0x46,0xF0,0x24,0x18,0xF2,0xB1,0x24, ++ 0xF5,0x74,0x10,0x82,0xD8,0x16,0xC0,0x1C,0x18,0xC2,0x81,0x1C,0xF3,0x90,0x32,0x82, ++ 0xF2,0x00,0x92,0x05,0x33,0x32,0x34,0x82,0x45,0x01,0xD0,0xE6,0x42,0xE2,0xB7,0x0B, ++ 0xD0,0x50,0xB3,0x13,0x36,0x12,0x1B,0x92,0x03,0x13,0x30,0x12,0x08,0x13,0xD0,0x2C, ++ 0x00,0x13,0xD2,0x24,0x00,0x13,0xD4,0x1C,0x00,0x13,0x36,0x01,0x00,0xA7,0xC1,0x5C, ++ 0x86,0x07,0xE8,0xA7,0x90,0x05,0x80,0x5C,0x4D,0x8A,0x07,0x80,0xC0,0x00,0x4A,0x13, ++ 0x40,0x3D,0x08,0x01,0x1C,0x01,0x30,0xF2,0x30,0xE2,0x04,0xCF,0x38,0x98,0x86,0x7E, ++ 0xC0,0x1B,0xF8,0x5C,0xD8,0xD8,0x96,0xDD,0x58,0x01,0xE8,0x36,0x83,0x1B,0x20,0x9A, ++ 0x94,0xDD,0x36,0xF2,0xE2,0x48,0x92,0x4D,0x00,0x27,0x18,0x01,0x80,0x1B,0x00,0x0F, ++ 0x18,0x01,0x80,0x1B,0x42,0x90,0xE2,0x00,0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x32,0xE2, ++ 0x2F,0x62,0xDD,0x1E,0xE3,0xB0,0x93,0xB5,0x30,0x82,0x83,0x5C,0x45,0xE2,0x06,0x98, ++ 0xC0,0xD8,0x08,0xD3,0xCA,0x00,0xB4,0x0B,0x48,0x21,0xD8,0x0E,0x76,0x09,0xD8,0x36, ++ 0x06,0x01,0x50,0xBA,0x04,0x08,0xC4,0x58,0xE4,0x08,0x02,0x70,0xC0,0xB0,0x4D,0xEB, ++ 0x4D,0xB3,0x19,0xAA,0x08,0xEB,0xC0,0x80,0xF4,0x1B,0xF2,0x2B,0xDA,0xD8,0xB2,0x1B, ++ 0x90,0x45,0x42,0x09,0xD8,0x76,0x07,0x09,0xA6,0x03,0x43,0x6A,0x0E,0x19,0x40,0x13, ++ 0x50,0x01,0x80,0x16,0x03,0x29,0xA0,0x0B,0x04,0xF7,0x40,0x13,0x50,0x01,0x80,0x16, ++ 0x03,0x21,0xA0,0x0B,0x02,0xC7,0x40,0x0B,0x48,0x01,0x80,0x1E,0x00,0x19,0x08,0x11, ++ 0xA0,0x0B,0x03,0x8F,0x48,0x03,0x40,0x01,0x88,0x26,0xC0,0x94,0x86,0x01,0xCE,0x03, ++ 0x40,0x51,0x98,0x0E,0x00,0x11,0x00,0x3F,0xC1,0x94,0x80,0x01,0xE0,0x03,0x44,0x01, ++ 0x80,0x0E,0x00,0x11,0x00,0x07,0x00,0x09,0xE4,0x0B,0xE3,0x50,0xA3,0x13,0xDD,0x13, ++ 0x38,0x90,0xA2,0x0E,0xF3,0x48,0xA2,0x0B,0xE8,0x0B,0x13,0x29,0x10,0x0A,0x94,0x0E, ++ 0xA8,0x13,0x01,0xEF,0x10,0x0A,0xCC,0x46,0x40,0x09,0x88,0x16,0x09,0x81,0xAF,0x0B, ++ 0x00,0xB7,0xD0,0x48,0x01,0x52,0xAC,0x13,0x00,0x97,0x40,0x19,0xC8,0x0E,0x08,0x19, ++ 0x02,0x07,0x90,0x0D,0xE8,0x13,0x51,0x01,0x82,0x16,0xF0,0x90,0xA8,0x13,0x01,0x3F, ++ 0xD2,0x94,0xF0,0x48,0xCA,0x93,0x1C,0x52,0xCA,0x84,0xC0,0x88,0xD0,0x94,0x88,0x8B, ++ 0xA8,0x03,0x83,0x9D,0xEF,0x85,0xAF,0xBD,0x80,0x6D,0x34,0x6A,0xD9,0x63,0x33,0x42, ++ 0x80,0x01,0x82,0x64,0xD0,0x03,0x84,0x3C,0xC2,0x64,0xD8,0x03,0x30,0x00,0xA8,0x1E, ++ 0x02,0xD9,0xEC,0x02,0x40,0x01,0x80,0xA6,0xC5,0x6C,0x00,0x08,0xC3,0x40,0x00,0x08, ++ 0x52,0xC2,0xC4,0x08,0xC4,0x48,0xC4,0x10,0x00,0x01,0x18,0x01,0x00,0x2F,0x00,0x5C, ++ 0x04,0x9C,0xE0,0x48,0xE2,0x90,0xE4,0x00,0x95,0x05,0x12,0x02,0xD8,0xBE,0x87,0x85, ++ 0xEB,0x85,0x07,0x59,0xCA,0x6C,0x08,0x00,0xC4,0x40,0x70,0x7A,0xF7,0x03,0x08,0x83, ++ 0xD0,0x7C,0x90,0x04,0x30,0x5A,0x09,0x01,0x00,0x11,0xD0,0x6C,0xBB,0xFF,0xEF,0xE7, ++ 0x42,0x4A,0x84,0x01,0x43,0x0B,0x30,0x5A,0x09,0xCC,0x5C,0x8B,0x0B,0xCC,0x5E,0x8B, ++ 0x15,0xCC,0x58,0x8B,0x17,0xCC,0x42,0x8B,0x14,0xCC,0x4C,0x22,0x46,0x53,0x10,0xD4, ++ 0x48,0x93,0x1F,0xD4,0x17,0x89,0x00,0x93,0x13,0x19,0x18,0x93,0x40,0x53,0x18,0x11, ++ 0x18,0xD2,0x04,0x53,0x40,0x0B,0x18,0xCA,0x01,0x0B,0x30,0x42,0xE9,0x4B,0x81,0x01, ++ 0x80,0x5C,0x48,0x09,0x8D,0x5E,0x6A,0x44,0x81,0x14,0x30,0x8A,0x5E,0x43,0x94,0x35, ++ 0xB0,0x0C,0x00,0x01,0x80,0x04,0xD0,0x6C,0x4F,0x92,0x03,0x00,0xC2,0x00,0xC4,0x00, ++ 0x83,0x54,0x40,0x8A,0x18,0x33,0x0A,0x01,0x37,0x42,0xB9,0xFF,0xE0,0x5F,0xF9,0x54, ++ 0xC1,0x64,0x30,0x5A,0xD1,0x0B,0x32,0xC2,0xD7,0x7C,0xB8,0xFF,0xEB,0x67,0x4C,0x62, ++ 0x10,0x01,0x00,0x01,0x02,0x67,0x00,0x18,0x37,0xE2,0xF4,0xDA,0x10,0x5A,0xD4,0x0E, ++ 0x33,0x0A,0xD3,0xCA,0x10,0x9A,0xEC,0x0E,0x35,0x12,0xD3,0xD2,0xE2,0x00,0x92,0x05, ++ 0x17,0x02,0xDD,0x86,0xC4,0x14,0xE0,0x00,0x10,0x0A,0x9C,0x36,0xC0,0x04,0x40,0x01, ++ 0x8B,0x9E,0x40,0x80,0x40,0x08,0xC2,0x70,0x00,0x3F,0xC0,0x14,0xF4,0x00,0x14,0x12, ++ 0xE0,0x5E,0x00,0x09,0x83,0x04,0xE0,0xB0,0x90,0xB5,0x77,0x01,0x80,0x16,0xC0,0x0C, ++ 0x16,0x32,0x9C,0x36,0x70,0x01,0x88,0x06,0x30,0x09,0xC0,0x5C,0x90,0x33,0xC0,0x5C, ++ 0xD2,0x0B,0x40,0x8A,0x18,0x0B,0x32,0x01,0x36,0x42,0x81,0x01,0x81,0x4C,0x80,0x01, ++ 0x83,0x44,0x00,0x37,0xC4,0x3C,0x10,0x32,0xD0,0x6E,0xC0,0x44,0xC0,0x03,0xC8,0x44, ++ 0x32,0x00,0x72,0x00,0x82,0x43,0x40,0x42,0x0C,0x41,0x00,0x0B,0x47,0x0B,0x10,0xF9, ++ 0x90,0x21,0x18,0x8A,0x00,0x0B,0xC8,0x6C,0x02,0x00,0xC5,0x08,0x02,0x00,0x53,0x0A, ++ 0xC4,0x40,0xC0,0x00,0xC0,0x48,0x74,0x01,0x88,0x66,0x10,0x01,0x78,0x02,0x02,0x37, ++ 0x18,0x01,0x00,0x1C,0x04,0x7C,0xE0,0x00,0xE2,0x48,0xE4,0x90,0x95,0x95,0x12,0x12, ++ 0xD9,0xB6,0x07,0x07,0xDF,0x6C,0x00,0x10,0xC1,0x90,0x5E,0xB2,0xC4,0x90,0x36,0xA2, ++ 0x18,0x01,0x00,0x9F,0x30,0x3A,0x13,0x01,0xF0,0xD2,0x3D,0x01,0xFC,0x3A,0x16,0xBA, ++ 0xD0,0x06,0x00,0x14,0x3E,0x01,0xF8,0x7A,0x10,0xBA,0xEC,0x06,0x04,0x54,0xE0,0x00, ++ 0xE3,0x48,0x34,0x12,0xE4,0x90,0x34,0xA2,0xE2,0xD8,0x92,0xDD,0x17,0x1A,0xDD,0x4E, ++ 0xC4,0x3C,0x10,0x32,0x80,0x06,0xC1,0x44,0xC6,0x03,0x48,0x00,0x88,0x1E,0xC0,0x4C, ++ 0xC8,0x03,0x42,0x31,0x88,0xBE,0xC7,0x4C,0xC8,0x03,0x42,0x31,0x89,0x26,0x40,0x12, ++ 0x40,0x0B,0x10,0x81,0x18,0x8A,0x00,0x0B,0xCF,0x6C,0x00,0x00,0xC0,0x00,0x4A,0xEA, ++ 0xC0,0x00,0xCA,0x64,0x32,0x5A,0xD1,0x4B,0xD7,0x7C,0xB8,0xFF,0xE3,0x67,0xE7,0xB0, ++ 0x90,0xB5,0xC3,0x3C,0x14,0x32,0xEC,0xAE,0x43,0xBA,0x30,0x5A,0x4A,0xCC,0x84,0x01, ++ 0x00,0x0B,0x40,0xAA,0x48,0xCC,0x1E,0x0B,0x52,0xCC,0x18,0x0B,0x54,0xCC,0x1A,0x0B, ++ 0x56,0xCC,0x04,0x0B,0x4E,0x8A,0x50,0xD4,0x00,0x53,0x58,0xCC,0x0F,0x0B,0x36,0xB7, ++ 0xAA,0x85,0xD8,0xE3,0x1A,0x0A,0x03,0x48,0xC5,0x50,0x0C,0x49,0x02,0x48,0xC4,0x88, ++ 0xE8,0xD3,0x50,0x11,0xC0,0x4E,0x10,0x01,0x00,0x2F,0x40,0x1C,0x04,0x5C,0xE0,0x48, ++ 0xE2,0x00,0xE4,0x90,0x95,0x95,0x12,0x12,0xD8,0xBE,0x17,0x01,0x00,0x87,0x00,0x00, ++ 0x80,0x40,0x07,0x01,0x48,0xE0,0x06,0x00,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42, ++ 0xF8,0xFB,0x07,0x00,0x40,0x1C,0x00,0x5C,0xE4,0x00,0xE4,0x48,0xE2,0x90,0x92,0x95, ++ 0x17,0x12,0xDD,0xBE,0xEF,0x85,0xA8,0x85,0x30,0x6A,0xF0,0x2C,0x30,0x22,0x30,0x8A, ++ 0x31,0xFA,0x30,0xC2,0xB9,0xFF,0xDF,0xB7,0x31,0xDA,0x31,0x92,0x31,0x4A,0x31,0x02, ++ 0xBC,0xFF,0xE7,0xCF,0xE8,0x85,0x37,0x0A,0x8D,0x01,0x86,0x01,0x02,0x5F,0xC8,0x5B, ++ 0x58,0x31,0x88,0x46,0x40,0xFA,0x47,0x0B,0x10,0x81,0x18,0x8A,0x00,0x0B,0x40,0x0B, ++ 0x18,0x8A,0x00,0x0B,0x3E,0x82,0xCB,0x1B,0x5F,0x01,0x88,0x86,0x38,0x82,0xAB,0x85, ++ 0xDA,0x5B,0xD8,0x4B,0x1F,0x5A,0x4A,0xC2,0xC7,0x08,0x52,0xC2,0xC0,0x00,0x14,0x01, ++ 0x00,0x27,0x40,0x24,0x04,0x64,0xE0,0x00,0xE2,0x48,0xE4,0x90,0x17,0xD2,0x9C,0xC6, ++ 0xEF,0x85,0xA8,0xBD,0x80,0x15,0x34,0x62,0x37,0xBA,0xD8,0x33,0xE8,0x03,0x09,0x01, ++ 0x18,0x4A,0x2E,0x01,0x40,0x29,0x90,0x16,0x1F,0x0B,0x1D,0x2B,0x07,0x6F,0x00,0x09, ++ 0xEA,0x02,0x38,0x00,0xAF,0x26,0x50,0x52,0x58,0x03,0x1F,0x82,0x18,0x03,0x05,0x27, ++ 0x57,0x3A,0x5F,0x03,0x18,0x92,0x1E,0x82,0x1D,0x03,0x1D,0x0B,0x30,0x0A,0xC1,0x14, ++ 0xBC,0xFF,0xE7,0xE7,0x25,0x2B,0x59,0x03,0x28,0x01,0x00,0x17,0x43,0x00,0xE2,0x68, ++ 0x96,0x6D,0x3F,0x08,0x8D,0x0E,0x10,0xAA,0x9B,0xC6,0xAF,0x2B,0x73,0xCA,0x4E,0x04, ++ 0x00,0x83,0xC7,0x14,0x0A,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00,0xF7,0x03,0x08,0x83, ++ 0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBC,0xFF,0xDF,0x87,0x30,0x1A,0xB9,0x04, ++ 0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD8,0xFF,0x06,0x09,0xA7,0x01,0x8D,0x03, ++ 0x48,0x82,0x46,0x43,0x10,0x11,0x18,0x82,0x00,0x43,0x00,0x41,0x01,0x83,0x45,0x83, ++ 0x08,0xF9,0x8F,0x19,0x19,0x42,0x00,0x83,0x87,0x2D,0xE8,0x85,0x3F,0x82,0xAB,0xC5, ++ 0xD8,0x53,0x90,0x04,0xDC,0x53,0x32,0xB2,0xE9,0x53,0x54,0x91,0x9E,0xBE,0x12,0x31, ++ 0xE0,0x92,0x52,0x01,0x8E,0x9E,0x52,0x02,0xC0,0x28,0x34,0x12,0x91,0xE1,0x19,0xC1, ++ 0x8E,0x01,0xF4,0x1A,0xE8,0x63,0x3A,0x11,0x10,0x1A,0xDD,0x16,0xD8,0xD8,0x38,0x1C, ++ 0xA9,0x7B,0x1E,0xD1,0xEE,0x63,0xF4,0x1A,0x15,0x32,0x13,0x9A,0xE0,0x16,0xC8,0xD8, ++ 0x38,0x1C,0xB2,0x7B,0x30,0x01,0x38,0x01,0x1C,0x01,0x30,0xE2,0x00,0x27,0x21,0x01, ++ 0x00,0xE7,0x18,0x01,0xF0,0x5A,0x5F,0x01,0xED,0x4E,0x10,0x9A,0xE8,0x06,0x30,0xF2, ++ 0xE8,0x5B,0x5E,0x01,0x80,0x76,0x40,0x9C,0xF0,0xD8,0x02,0x9C,0x00,0x57,0x58,0x01, ++ 0xD5,0x46,0x10,0xDA,0xD0,0x06,0x30,0xFA,0xF0,0x5B,0x58,0x01,0x80,0x16,0x40,0x9C, ++ 0xE0,0xD8,0x02,0x9C,0xE4,0x68,0xE5,0x90,0xE7,0x20,0x93,0x25,0x2F,0xA2,0x9B,0x06, ++ 0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x36,0xE2,0xE5,0x04,0x28,0x22,0x98,0xBE,0x7E,0x14, ++ 0xC8,0x90,0x3C,0x14,0x7E,0x14,0xCA,0x90,0x3E,0x14,0xEA,0x43,0x40,0x01,0x80,0x0E, ++ 0xF6,0x00,0xAA,0x43,0xF0,0x43,0x40,0x01,0x82,0x0E,0xF0,0x00,0xB7,0x43,0xE8,0xC5, ++ 0xAC,0xBD,0x87,0x15,0x30,0x62,0x30,0xBA,0xEF,0x2B,0xDB,0x33,0xDB,0x03,0x1B,0x42, ++ 0x00,0x08,0xC2,0x14,0xC4,0x40,0x48,0x8A,0xC0,0x00,0x82,0x0C,0x37,0x02,0x81,0x01, ++ 0xC4,0x0B,0x10,0x01,0x18,0x8A,0x80,0x0B,0x00,0x21,0xEE,0x02,0x44,0x01,0x80,0x1E, ++ 0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42,0xBF,0xFF,0xD7,0xC7,0x30,0x1A,0xB9,0x04, ++ 0x08,0x01,0x00,0x19,0xD7,0x14,0xB8,0xFF,0xDA,0x3F,0x02,0x41,0xE9,0x0A,0x30,0x1A, ++ 0x30,0xD2,0xC1,0x0C,0xBC,0xFF,0xDF,0x7F,0x31,0x1A,0x31,0x4A,0xD0,0x14,0xC0,0x0C, ++ 0xBD,0xFF,0xF7,0xB7,0x50,0x02,0x1C,0x09,0xC0,0x83,0x40,0x01,0x8B,0x5E,0xE0,0x68, ++ 0x95,0x6D,0x5F,0x0B,0x03,0x0F,0xE0,0x68,0x90,0x6D,0x37,0xC2,0x00,0x42,0x15,0x0A, ++ 0x8D,0x0E,0x10,0xAA,0x99,0xBE,0x37,0x82,0x74,0x92,0x13,0x2A,0x93,0xE6,0xA8,0x2B, ++ 0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBE,0xFF,0xD7,0x47,0x30,0x1A,0xB9,0x04, ++ 0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD8,0xBF,0xC0,0x14,0x0A,0x59,0xCB,0x00, ++ 0x0A,0x48,0xC2,0x00,0xF7,0x03,0x08,0x83,0x05,0x41,0x00,0x83,0x47,0x83,0x09,0xF9, ++ 0x88,0x19,0x18,0x42,0x01,0x83,0x39,0xBF,0xE1,0x0B,0x31,0x02,0x80,0x01,0x4D,0x01, ++ 0x86,0x1E,0xC9,0x0B,0x49,0x09,0x88,0x06,0x0E,0x11,0x88,0x0B,0xA8,0x2B,0x83,0x9B, ++ 0x4F,0x04,0x01,0x83,0x50,0x0A,0xCB,0x14,0xDC,0x03,0xC1,0x48,0xE7,0x02,0x0A,0x83, ++ 0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0xBC,0xFF,0xD7,0xC7,0x30,0x1A,0xB9,0x04, ++ 0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF,0xD0,0x3F,0x07,0x41,0x01,0x83,0x45,0x83, ++ 0x08,0xF9,0x8F,0x19,0x19,0x42,0x00,0x83,0x38,0x77,0x08,0x01,0x88,0x0B,0x86,0x8B, ++ 0x3F,0x57,0xA8,0x85,0x84,0x9D,0x34,0x22,0x33,0x6A,0xD8,0x73,0xD8,0x43,0x81,0x34, ++ 0x31,0x12,0x93,0xE1,0x92,0x94,0x48,0x72,0x32,0x02,0xC3,0x18,0x4B,0x32,0x22,0x0A, ++ 0x8B,0x8C,0xC8,0x43,0x00,0x00,0x82,0x1C,0x00,0x01,0x80,0x14,0x37,0x42,0x81,0x01, ++ 0x82,0x84,0xC0,0x03,0x5C,0x7B,0x35,0x32,0x3F,0x20,0x5A,0x43,0x18,0x3A,0x60,0x01, ++ 0xD1,0x46,0x40,0xFA,0x18,0x3A,0xB8,0x0C,0x37,0x82,0x23,0xD9,0x00,0x02,0xE1,0x84, ++ 0x80,0x03,0x03,0x47,0x46,0xD2,0x19,0x02,0x18,0x3A,0xB8,0x0C,0x30,0x82,0x23,0x21, ++ 0x18,0x02,0xE1,0x84,0x80,0x03,0x3B,0x01,0x19,0x7B,0x37,0x42,0x80,0x01,0x85,0x7C, ++ 0xC0,0x03,0x84,0x54,0xC0,0x7C,0x20,0x09,0xB8,0x22,0xA0,0x4C,0x34,0x42,0x81,0x01, ++ 0x86,0x74,0x18,0x3B,0xB8,0x44,0xC0,0x74,0x18,0x3B,0xBC,0x3C,0x31,0x42,0x81,0x01, ++ 0x84,0x6C,0xA0,0x3B,0xCA,0x43,0x45,0x00,0x86,0x2C,0x00,0x01,0xFB,0x22,0x82,0x00, ++ 0x81,0x24,0xE8,0x43,0x40,0x29,0xC0,0xBE,0x03,0x01,0x30,0x22,0x3B,0x04,0x39,0x04, ++ 0x20,0x01,0x00,0x77,0x00,0x01,0x00,0x47,0x40,0x7C,0x00,0xFC,0x40,0x7C,0x00,0xBC, ++ 0xE4,0x90,0xE4,0x48,0xE2,0xD8,0xE4,0x00,0x95,0x05,0x12,0x82,0xDB,0xA6,0xE7,0x20, ++ 0x90,0x25,0xC3,0x34,0x17,0x22,0xDC,0x6E,0xF8,0x94,0xE0,0x8C,0x00,0x01,0x80,0x5C, ++ 0x00,0xAF,0x05,0x01,0x34,0x32,0x34,0x22,0xC8,0x5C,0x00,0x09,0x00,0x42,0xCC,0x0C, ++ 0x80,0x64,0x10,0x42,0x81,0x7E,0xE3,0x53,0x50,0x01,0x80,0x2E,0xC8,0x34,0xC0,0x5C, ++ 0xF4,0x48,0x12,0x42,0x88,0x06,0x30,0xB2,0x1A,0x01,0x00,0x87,0x41,0xCC,0x41,0x14, ++ 0xD0,0x40,0x94,0x15,0x00,0x14,0xC9,0x1C,0x10,0x52,0xD4,0x3E,0x32,0x02,0xE3,0x00, ++ 0x94,0x05,0x36,0x22,0x34,0x82,0xC3,0x00,0x94,0x05,0x30,0x32,0xCC,0x2C,0x10,0x52, ++ 0xE8,0x3E,0x01,0x7F,0x00,0x01,0x00,0x42,0x48,0xE0,0x06,0x00,0x38,0xA0,0x03,0x00, ++ 0xAA,0xAA,0xAA,0xAA,0x18,0x00,0x04,0x42,0x00,0xD0,0x00,0x01,0x68,0xB8,0x03,0x00, ++ 0x28,0x60,0x00,0x00,0xCC,0x4B,0x13,0x8A,0xE7,0x1E,0x58,0x43,0xC8,0x64,0x18,0x0A, ++ 0x18,0x4B,0xCF,0x6C,0xE8,0x4B,0x4A,0x09,0x88,0x16,0xC8,0x6C,0x02,0x09,0xAC,0x43, ++ 0xCC,0x54,0x10,0x52,0xE8,0xBE,0x08,0x09,0xD4,0x44,0x00,0xCA,0x18,0x8A,0x88,0x44, ++ 0x00,0x8F,0xC8,0x24,0x10,0x52,0xD4,0x76,0xCA,0x6C,0xE8,0x4B,0x48,0x09,0x88,0x16, ++ 0xCC,0x6C,0x00,0x09,0xA8,0x43,0xCA,0x4C,0x10,0x52,0xD4,0x26,0x08,0x09,0xD0,0x3C, ++ 0x00,0xCA,0x1C,0x8A,0x8D,0x3C,0xE0,0x20,0xE2,0xF8,0xE5,0xD8,0x95,0xDD,0x12,0x9A, ++ 0xD8,0x66,0xC5,0x7C,0xC8,0x03,0x44,0x01,0x83,0x2E,0x32,0x02,0x40,0x11,0xC8,0x2E, ++ 0x33,0x0A,0x33,0x82,0x83,0x07,0xC8,0xD7,0x90,0x05,0x00,0x07,0x03,0x01,0x00,0x88, ++ 0xD0,0x20,0x13,0x01,0x01,0x57,0x01,0x67,0x40,0x01,0xE8,0x7E,0x0B,0x01,0xF0,0x0A, ++ 0xDC,0x1C,0x10,0xCA,0xD2,0xB6,0xE0,0x18,0x10,0xCA,0xEC,0x16,0xD1,0x48,0x00,0x0C, ++ 0x00,0x87,0x48,0x01,0xE8,0x76,0x08,0x09,0x00,0x0C,0x01,0x5F,0x0B,0x01,0xF0,0x0A, ++ 0x10,0x0A,0xD4,0x16,0xD1,0x48,0x00,0x0C,0x00,0x27,0x48,0x01,0xD0,0x16,0x08,0x01, ++ 0x19,0x4A,0x06,0x0C,0x0B,0x01,0xF0,0x0A,0xDC,0x24,0x10,0xCA,0xD0,0x1E,0xC8,0x14, ++ 0xE6,0x48,0x92,0x4D,0x8D,0x14,0xE0,0x20,0xE2,0x90,0x92,0x95,0x16,0x92,0xDD,0x9E, ++ 0x00,0x4F,0x00,0x01,0x08,0x01,0x00,0x27,0x05,0x0C,0xE1,0x20,0xE2,0xF8,0xE5,0x00, ++ 0x95,0x05,0x12,0x82,0xD8,0xC6,0xC7,0x5C,0xE2,0x00,0x92,0x05,0x80,0x5C,0xC8,0x34, ++ 0xC4,0x5C,0x10,0x42,0xD2,0x06,0x38,0x27,0xC9,0x43,0x41,0x71,0xC9,0x0E,0x00,0x71, ++ 0x88,0x43,0xC1,0x14,0xCC,0x4B,0x41,0x00,0xC6,0x40,0x90,0x05,0x8A,0x43,0x41,0x81, ++ 0xCA,0x0E,0x00,0x81,0x88,0x43,0x01,0x01,0x29,0x44,0x37,0x44,0xC0,0x74,0xC8,0x44, ++ 0x18,0x0B,0xCE,0x74,0xC4,0x3C,0x18,0x43,0x87,0x9D,0xE8,0x85,0xA8,0x85,0x33,0x2A, ++ 0x30,0x62,0x30,0xB2,0x31,0x0A,0x31,0x42,0xBA,0xFF,0xEF,0xCF,0x48,0x6A,0x03,0x01, ++ 0x81,0x43,0x30,0x92,0x31,0x0A,0x31,0x42,0xBB,0xFF,0xEF,0x1F,0xEE,0x03,0x41,0x41, ++ 0x92,0x0E,0xE0,0x00,0xAB,0x03,0xE9,0x85,0x10,0x01,0x00,0x37,0x0A,0x01,0xE0,0x48, ++ 0x90,0x4D,0x4C,0xA1,0xCA,0xDE,0xE7,0x90,0x94,0x95,0x14,0x12,0xCB,0xB6,0x3F,0x82, ++ 0x38,0x18,0x78,0xD8,0x14,0x09,0x00,0xD2,0x97,0x95,0x1E,0xF9,0x08,0xD8,0x00,0xC2, ++ 0x5E,0xEA,0xC2,0x00,0x48,0x09,0x88,0x66,0x44,0x0B,0x18,0x8A,0x02,0x0B,0x40,0x0B, ++ 0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B, ++ 0x38,0x82,0x4B,0x01,0x8A,0x66,0x40,0x0B,0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A, ++ 0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B,0x40,0x0B,0x18,0x8A,0x03,0x0B,0x38,0x82, ++ 0x48,0x11,0x88,0x66,0x44,0x0B,0x18,0x8A,0x02,0x0B,0x40,0x0B,0x1A,0x8A,0x04,0x0B, ++ 0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x00,0x0B,0x38,0x82,0x4B,0x19, ++ 0x88,0xE6,0x47,0x0B,0x18,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B, ++ 0x1E,0x8A,0x04,0x0B,0x40,0x0B,0x1A,0x8A,0x03,0x0B,0x3A,0x82,0xAC,0x8D,0x87,0x3D, ++ 0xC0,0x3C,0xC8,0x3C,0x4C,0x00,0x00,0x00,0xC0,0x00,0x3A,0x00,0x4A,0xDA,0x71,0x00, ++ 0xC1,0x28,0x42,0xDA,0x44,0x0B,0x90,0x4D,0x88,0x34,0x58,0x0B,0x90,0x4D,0x8C,0x2C, ++ 0x5C,0x0B,0x92,0x4D,0x8C,0x24,0x58,0x0B,0x90,0x4D,0x8C,0x1C,0x54,0x0B,0x96,0x75, ++ 0x4A,0xA2,0x41,0x53,0x90,0x95,0x94,0x14,0x44,0x53,0x90,0xBD,0x44,0x13,0x92,0x95, ++ 0x91,0x0C,0x58,0x7A,0x98,0x01,0x52,0xD3,0x90,0x95,0x94,0x04,0x10,0x09,0x00,0x13, ++ 0xA8,0x10,0x1C,0x13,0x12,0x81,0x18,0x13,0x18,0x13,0x14,0x79,0x11,0x13,0x16,0x01, ++ 0x00,0x53,0x12,0x89,0x02,0x53,0x40,0x0B,0x10,0x81,0x19,0x8A,0x07,0x0B,0x02,0xF9, ++ 0x80,0x89,0x17,0xC3,0x07,0x09,0xB8,0xFF,0xFF,0x7F,0x03,0xF9,0x80,0x89,0x14,0xC3, ++ 0x07,0x09,0xB8,0xFF,0xF8,0x4F,0x03,0x19,0x11,0x00,0x00,0x43,0x07,0x09,0xB8,0xFF, ++ 0xF8,0x1F,0x0B,0x11,0xC7,0x3C,0xB8,0xFF,0xF8,0x5F,0x23,0xA1,0x01,0x01,0x40,0x4B, ++ 0x30,0x48,0xA8,0x16,0xE7,0x20,0x93,0x25,0x03,0x0F,0xF0,0x20,0x92,0x25,0xE7,0x00, ++ 0x90,0x05,0x46,0x51,0x98,0x9E,0x0F,0x09,0xC7,0x3C,0xB8,0xFF,0xF8,0xCF,0x42,0x82, ++ 0xC8,0x34,0x00,0x0B,0xC8,0x2C,0x18,0x0B,0xCA,0x24,0x18,0x0B,0xCC,0x1C,0x18,0x0B, ++ 0x10,0x33,0x4E,0x62,0xD2,0x14,0x00,0x53,0x00,0x7B,0xC8,0x0C,0x00,0x0B,0x4A,0x42, ++ 0xC2,0x04,0x88,0x01,0x10,0x43,0x60,0xA1,0xC8,0x16,0x00,0x09,0x87,0x45,0xE8,0x85, ++ 0x07,0x01,0x38,0xDF,0x00,0xD0,0x00,0x01,0x80,0x00,0x00,0x42,0x08,0x01,0x00,0x42, ++ 0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x00,0x0F,0x00,0x26,0xF8,0x48,0x48,0x21, ++ 0x94,0xDE,0x3F,0x58,0xA8,0x0E,0x00,0x14,0xE6,0x00,0x3C,0x48,0x80,0x06,0x80,0x13, ++ 0x38,0x82,0x4B,0x01,0x86,0x5E,0x38,0x18,0x80,0x16,0x80,0x13,0xE2,0x00,0xF2,0x48, ++ 0x48,0x11,0x98,0x26,0x38,0x18,0xAC,0x16,0x04,0x14,0xE0,0x00,0xF7,0x48,0x3C,0x1F, ++ 0x17,0x01,0x38,0x77,0x16,0x01,0x38,0xFF,0x10,0x01,0x48,0x18,0x11,0x5A,0x9C,0x66, ++ 0x54,0x18,0x10,0x5A,0x98,0x8E,0x18,0x01,0x32,0xE2,0x04,0x77,0x30,0x1A,0x18,0x5A, ++ 0xA0,0xE6,0x11,0x01,0x44,0x18,0x12,0x5A,0x98,0x8E,0x49,0x18,0x10,0x5A,0x9C,0xE6, ++ 0x54,0x18,0x10,0x5A,0x9C,0x0E,0x30,0xA2,0x06,0xFF,0x49,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x0E,0x58,0xD6,0x00,0x0C,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD4,0x00, ++ 0x0A,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD2,0x00,0x08,0x92,0x4A,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD0,0x00,0x0E,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x06,0x58,0xD6,0x00,0x0C,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD4,0x00, ++ 0x0A,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08, ++ 0x90,0x06,0x30,0x0A,0x08,0x92,0x32,0x82,0x3A,0x82,0x03,0xEF,0x78,0x50,0x86,0x06, ++ 0x10,0x4A,0x82,0x18,0x9A,0x06,0x10,0x02,0x00,0x9A,0x12,0x01,0x30,0xE2,0x4C,0x18, ++ 0x11,0x5A,0x9C,0x6E,0x54,0x18,0x10,0x5A,0x9F,0x96,0x10,0xE1,0x08,0x48,0xD4,0x95, ++ 0x54,0x18,0x10,0x5A,0x9C,0x66,0x08,0x48,0x8C,0x90,0x14,0x5A,0x9C,0x46,0x08,0x48, ++ 0x8C,0x90,0x14,0x5A,0x9C,0x26,0x08,0x48,0x84,0xD6,0x89,0x90,0x04,0x07,0x48,0x48, ++ 0x4C,0x18,0x16,0x5A,0x9E,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x14,0x5A, ++ 0x9C,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x12,0x5A,0x9A,0x0E,0x08,0x58, ++ 0xD2,0x00,0x0E,0x92,0x4C,0x18,0x10,0x5A,0x98,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92, ++ 0x44,0x18,0x16,0x5A,0x9E,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92,0x44,0x18,0x14,0x5A, ++ 0x9C,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92,0x92,0xCE,0x46,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A,0x32,0x1A,0x0B,0x92, ++ 0x80,0xD8,0x32,0x82,0x9A,0x0E,0x10,0x02,0x58,0x01,0xA8,0x06,0x13,0x4A,0x3A,0x82, ++ 0x32,0x1A,0x83,0xD8,0x9A,0x06,0x10,0x02,0xA8,0x0D,0x00,0x01,0x36,0x02,0x36,0x02, ++ 0xEB,0x15,0x30,0xAA,0x81,0x07,0xC0,0x17,0x30,0x72,0x05,0x28,0x32,0x4A,0x33,0x9A, ++ 0x46,0x00,0x06,0x00,0x30,0x2A,0x84,0xC5,0xAF,0x05,0xB9,0xE7,0xF3,0x6F,0xE4,0x05, ++ 0x3A,0x01,0x40,0x48,0x30,0xB2,0x35,0x01,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06, ++ 0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0xEA,0x01,0x02,0x48,0x33,0x6A,0x3C,0x82, ++ 0x36,0x22,0x30,0x02,0x31,0x02,0x36,0x02,0xBA,0xDF,0xD7,0x2F,0x43,0x02,0x38,0x82, ++ 0x88,0x20,0x00,0x01,0x40,0x12,0x48,0x1A,0xF3,0x5D,0x3D,0x82,0x00,0x68,0x00,0x00, ++ 0x00,0xC0,0x00,0x00,0x00,0x30,0x01,0x10,0x39,0x82,0xA3,0x85,0x33,0xA2,0xF3,0x20, ++ 0xC3,0x2B,0xE1,0x20,0x10,0x5A,0x95,0x06,0x33,0xEA,0xE8,0x1A,0x07,0xD8,0xC2,0x18, ++ 0xE0,0x85,0x39,0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x80,0x20,0x03,0x42,0x80,0x20,0x03,0x42,0x80,0x20,0x04,0x42,0x80,0x20,0x03,0x42, ++ 0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42,0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42, ++ 0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42,0x80,0x20,0x05,0x42,0x80,0xA0,0x02,0x42, ++ 0x80,0xA0,0x05,0x42,0x80,0x20,0x02,0x42,0x80,0x20,0x01,0x42,0x80,0x20,0x01,0x42, ++ 0x80,0xA0,0x01,0x42,0x80,0xA0,0x01,0x42,0x80,0xA0,0x01,0x42,0x10,0x20,0x08,0x40, ++ 0x40,0x08,0x20,0x10,0x10,0x20,0x08,0x40,0x40,0x08,0x20,0x40,0x10,0x20,0x00,0x08, ++ 0x08,0xC1,0x02,0x42,0x08,0x81,0x02,0x42,0x08,0x81,0x03,0x42,0x08,0x41,0x03,0x42, ++ 0x08,0x01,0x03,0x42,0x08,0x81,0x02,0x42,0x08,0x41,0x02,0x42,0x08,0xC1,0x00,0x42, ++ 0x08,0x01,0x02,0x42,0x08,0x01,0x01,0x42,0x08,0xC1,0x01,0x42,0x08,0x41,0x01,0x42, ++ 0x08,0x81,0x01,0x42,0x08,0x81,0x01,0x42,0x08,0x41,0x01,0x42,0x08,0xC1,0x02,0x42, ++ 0x08,0x01,0x01,0x42,0x08,0x01,0x03,0x42,0x08,0xC1,0x00,0x42,0x50,0x50,0x50,0x50, ++ 0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x00,0x00,0x00,0x08,0xF8,0x0F, ++ 0xFF,0x07,0xF8,0xFF,0x07,0xF8,0x0F,0xF8,0x08,0x00,0x08,0x08,0x00,0x00,0x00,0x08, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x03,0x00,0x28,0xB5,0x39,0xC5,0x08,0x1D,0x1B,0x2B,0x3A,0x28, ++ 0x53,0xB5,0x0A,0xC5,0x00,0x08,0x01,0x00,0x01,0x00,0x50,0x0D,0x52,0x1D,0x52,0xB5, ++ 0x39,0x0D,0x04,0x08,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95,0x51,0x3D,0x54,0x95, ++ 0x51,0x3D,0x54,0x95,0x0B,0x3D,0x34,0x88,0x51,0x3D,0x54,0x1D,0x51,0x3D,0x54,0x95, ++ 0x04,0x00,0x50,0x3D,0x50,0x1D,0x01,0x00,0x00,0x00,0x00,0x00,0x54,0x2D,0x53,0x3D, ++ 0x32,0x8D,0x32,0x38,0x01,0x28,0x0A,0x45,0x50,0xB5,0x53,0x95,0x00,0x00,0x00,0x00, ++ 0x52,0xA5,0x51,0xB5,0x09,0xC5,0x03,0x08,0x03,0x00,0x50,0x3D,0x55,0x1D,0x51,0x0D, ++ 0x51,0x3D,0x54,0x95,0x51,0x3D,0x53,0x1D,0x51,0x3D,0x54,0x95,0x51,0x0D,0x55,0x0D, ++ 0x54,0xB5,0x3A,0x0D,0x00,0x08,0x01,0x00,0x53,0xA5,0x51,0x2D,0x52,0x3D,0x34,0x8A, ++ 0x1D,0x38,0x52,0x45,0x52,0x0D,0x51,0x1D,0x54,0xB5,0x3A,0x0D,0x53,0xA5,0x29,0xB5, ++ 0x39,0xC5,0x08,0x1D,0x19,0x2D,0x22,0x1D,0x44,0x0D,0x31,0x3D,0x23,0x95,0x09,0xC1, ++ 0x29,0xB5,0x0B,0x1D,0x1B,0x2B,0x3A,0x28,0x00,0x00,0x00,0x08,0xFF,0x07,0x00,0xF8, ++ 0x08,0x00,0x10,0x10,0x08,0x10,0x10,0x10,0x08,0x08,0x10,0x08,0x10,0x08,0x10,0x08, ++ 0x10,0x10,0x08,0x08,0x10,0x10,0x08,0x08,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10, ++ 0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0xF8,0x07,0x08,0x00, ++ 0x08,0x08,0x00,0x00,0x78,0xA2,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0xE0,0x00,0x00, ++ 0x00,0x00,0x05,0x00,0x78,0x82,0x01,0x00,0x00,0xE0,0x00,0x01,0x88,0x40,0x02,0x00, ++ 0x00,0xE0,0x05,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, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xD1,0xDA,0xAA,0xA9,0x2E,0x2D,0x55,0x56,0xBB,0x43,0xAC,0x32, ++ 0x99,0x21,0x8A,0x10,0x00,0x70,0x00,0x28,0x09,0x00,0x1F,0x00,0x06,0x78,0x50,0x56, ++ 0xFF,0xFF,0xFF,0xFF,0xBA,0xB0,0x09,0x40,0x00,0x40,0x28,0x00,0x0B,0x1C,0x29,0xF0, ++ 0x0F,0x00,0xCA,0xCA,0xFF,0xFF,0xFF,0xFF,0x36,0x17,0x48,0x01,0x08,0x00,0x00,0x05, ++ 0x23,0x81,0x7E,0x05,0x5F,0x0D,0x69,0x30 ++}; ++ ++ ++#define FW_INFO_SIZE (0x18) ++#define FW_REAL_SIZE (sizeof(fwbin)) ++#define FW_BIN_SIZE (24*1024+24) //24K byte ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/Readme b/module_drivers/drivers/input/touchscreen/hyn_touch/Readme +new file mode 100644 +index 000000000..262f3cad4 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/Readme +@@ -0,0 +1,6 @@ ++1.Original_driver: ++ Provided by the original factory. ++2.Debug_driver: ++ Reference Original_driver to match out platform. ++ ++3.Def driver------>Original_driver/cst3xx_MCU_driver-ori [Version 1] +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx.c b/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx.c +new file mode 100755 +index 000000000..b917cdd0d +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx.c +@@ -0,0 +1,1645 @@ ++/* ++ * cst3xx Touchscreen Controller Driver ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "hyn_cst3xx.h" ++#include "hyn_cst3xx_RS659_fw.h" ++#include ++ ++ ++#define HYN_DEBUG_EN 1 ++ ++struct st1615_ts_finger { ++ u16 x; ++ u16 y; ++ u8 t; ++ bool is_valid; ++}; ++ ++ ++static int cst3xx_into_program_mode(struct i2c_client * client); ++static int cst3xx_erase_program_area(struct i2c_client * client); ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms); ++static int cst3xx_write_program_data(struct i2c_client * client,const unsigned char *pdata); ++ ++static int cst3xx_check_checksum(struct i2c_client * client); ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client); ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata); ++ ++static int cst3xx_firmware_info(struct i2c_client * client); ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict); ++ ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata); ++ ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len); ++static int cst3xx_i2c_test(struct i2c_client *client); ++static void cst3xx_reset(struct cst3xx_ts_data *ts) ; ++extern void close_vcc3v3Power(void); ++extern void open_vcc3v3Power(void); ++ ++static unsigned char *pcst3xx_update_firmware = (unsigned char *)cst3_fw ; //the updating firmware ++static unsigned int g_cst3xx_ic_version = 0; ++static unsigned int g_cst3xx_ic_checksum = 0; ++static unsigned int g_cst3xx_ic_checkcode =0; ++static unsigned int g_cst3xx_ic_project_id = 0; ++static unsigned int g_cst3xx_ic_type = 0; ++ ++static unsigned char report_flag = 0; ++static unsigned int x_temp_pos = 0; ++static unsigned int y_temp_pos = 0; ++ ++#define HYN_DRAW_POINT ++ ++//#define USE_ANALOG_I2C 1 //i2c analog -->defconfig i2c. ++//#define USE_HIGHEST_I2CA 1// x1000 highest i2c ++#define USE_LOWEST_I2CA 1 // x1000 lowest i2c ++//#define HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++#define HYN_UPDATE_FIRMWARE_ENABLE ++ ++#pragma pack(1) ++typedef struct ++{ ++ u16 pid; //product id // ++ u16 vid; //version id // ++} st_tpd_info; ++#pragma pack() ++ ++st_tpd_info tpd_info; ++ ++#define CST3XX_BIN_SIZE (24*1024 + 24) ++//#define CST3XX_MAX_X 340 ++#define CST3XX_MAX_X 480 ++#define CST3XX_REL_X 268 ++#define CST3XX_MAX_Y 800 ++#define ERROR_TOUCH 1 ++ ++static void cst3xx_ts_power(struct cst3xx_ts_data *ts, bool poweron) ++{ ++ if (gpio_is_valid(ts->pdata->reset_gpio)) ++ gpio_direction_output(ts->pdata->reset_gpio, poweron); ++} ++ ++static int cst3xx_into_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x01; ++ buf[2] = 0xAA; //set cmd to enter program mode ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(2); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; //check whether into program mode ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++static int cst3xx_erase_program_area(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x02; ++ buf[2] = 0x00; //set cmd to erase main area ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) return -1; ++ ++ mdelay(5); ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x03; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if (ret < 0) return -1; ++ ++ if (buf[0] != 0x55) return -1; ++ ++ return 0; ++} ++ ++ ++static void cst3xx_reset_ic(struct cst3xx_ts_data *ts,unsigned int ms) ++{ ++ ++ unsigned char buf[4]; ++ buf[0] = 0xD1; ++ buf[1] = 0x0E; ++ cst3xx_i2c_write(ts->client, buf, 2); ++/* ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(2); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++*/ ++ mdelay(ms); ++} ++ ++ ++static int cst3xx_write_program_data(struct i2c_client * client, ++ const unsigned char *pdata) ++{ ++ int i, ret; ++ unsigned char *i2c_buf; ++ unsigned short eep_addr; ++ int total_kbyte; ++ ++ unsigned char temp_buf[8]; ++ unsigned short iic_addr; ++ int j; ++ ++ ++ i2c_buf = kmalloc(sizeof(unsigned char)*(1024 + 2), GFP_KERNEL); ++ if (i2c_buf == NULL) ++ return -1; ++ ++ //make sure fwbin len is N*1K ++ //total_kbyte = len / 1024; ++ total_kbyte = 24; ++ for (i=0; i>8; ++ ret = cst3xx_i2c_write(client, i2c_buf, 4); ++ if (ret < 0) ++ goto error_out; ++ ++ memcpy(i2c_buf, pdata + eep_addr, 1024); ++ for(j=0; j<256; j++) { ++ iic_addr = (j<<2); ++ temp_buf[0] = (iic_addr+0xA018)>>8; ++ temp_buf[1] = (iic_addr+0xA018)&0xFF; ++ temp_buf[2] = i2c_buf[iic_addr+0]; ++ temp_buf[3] = i2c_buf[iic_addr+1]; ++ temp_buf[4] = i2c_buf[iic_addr+2]; ++ temp_buf[5] = i2c_buf[iic_addr+3]; ++ ret = cst3xx_i2c_write(client, temp_buf, 6); ++ if (ret < 0) ++ goto error_out; ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x04; ++ i2c_buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(60); ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x05; ++ ret = cst3xx_i2c_read_register(client, i2c_buf, 1); ++ if (ret < 0) ++ goto error_out; ++ ++ if (i2c_buf[0] != 0x55) ++ goto error_out; ++ ++ } ++ ++ i2c_buf[0] = 0xA0; ++ i2c_buf[1] = 0x03; ++ i2c_buf[2] = 0x00; ++ ret = cst3xx_i2c_write(client, i2c_buf, 3); ++ if (ret < 0) ++ goto error_out; ++ ++ mdelay(8); ++ ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ ++ return 0; ++ ++error_out: ++ if (i2c_buf != NULL) { ++ kfree(i2c_buf); ++ i2c_buf = NULL; ++ } ++ return -1; ++} ++ ++ ++static int cst3xx_check_checksum(struct i2c_client * client) ++{ ++ int ret; ++ int i; ++ unsigned int checksum; ++ unsigned int bin_checksum; ++ unsigned char buf[4]; ++ const unsigned char *pData; ++ ++ for(i=0; i<5; i++) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(client, buf, 1); ++ if(ret < 0) ++ { ++ mdelay(2); ++ continue; ++ } ++ ++ if(buf[0]!=0) ++ break; ++ else ++ mdelay(2); ++ } ++ mdelay(2); ++ ++ ++ if(buf[0]==0x01) ++ { ++ buf[0] = 0xA0; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ ++ if(ret < 0) return -1; ++ ++ // read chip checksum ++ checksum = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); ++ ++ pData=(unsigned char *)pcst3xx_update_firmware +24*1024+16; //7*1024 +512 ++ bin_checksum = pData[0] + (pData[1]<<8) + (pData[2]<<16) + (pData[3]<<24); ++ ++ printk(" hyn the updated ic checksum is :0x%x. the updating firmware checksum is:0x%x------\n", checksum, bin_checksum); ++ ++ if(checksum!=bin_checksum) ++ { ++ printk(" cst3xx hyn check sum error.\n"); ++ return -1; ++ ++ } ++ ++ } ++ else ++ { ++ printk(" cst3xx hyn No checksum.\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int cst3xx_exit_program_mode(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[3]; ++ ++ buf[0] = 0xA0; ++ buf[1] = 0x06; ++ buf[2] = 0xEE; ++ ret = cst3xx_i2c_write(client, buf, 3); ++ if (ret < 0) ++ return -1; ++ ++ mdelay(10); //wait for restart ++ ++ ++ return 0; ++} ++ ++ ++static int cst3xx_update_firmware(struct cst3xx_ts_data *ts, const unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ ++ printk(" cst3xx----------upgrade cst3xx begain------------\n"); ++ disable_irq(ts->irq); ++ mdelay(20); ++START_FLOW: ++ ++#ifdef HYN_UPDATE_FIRMWARE_POWERON_ENABLE ++ close_vcc3v3Power(); ++ mdelay(20); ++ open_vcc3v3Power(); ++ mdelay(5+retry); ++#else ++ cst3xx_reset_ic(ts,5+retry); ++#endif ++ ret = cst3xx_into_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]into program mode failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_erase_program_area(ts->client); ++ if (ret) { ++ printk(" cst3xx[cst3xx]erase main area failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_write_program_data(ts->client, pdata); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]write program data into cstxxx failed.\n"); ++ goto err_out; ++ } ++ ++ ret =cst3xx_check_checksum(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] after write program cst3xx_check_checksum failed.\n"); ++ goto err_out; ++ } ++ ++ ret = cst3xx_exit_program_mode(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx]exit program mode failed.\n"); ++ goto err_out; ++ } ++ ++ cst3xx_reset_ic(ts,20); ++ ++ printk(" cst3xx hyn----------cst3xx_update_firmware end------------\n"); ++ ++ enable_irq(ts->irq); ++ ++ return 0; ++ ++err_out: ++ if (retry < 30) { ++ retry++; ++ mdelay(20); ++ goto START_FLOW; ++ } ++ else { ++ enable_irq(ts->irq); ++ return -1; ++ } ++} ++ ++ ++ ++ ++/******************************************************* ++Function: ++ get firmware version, ic type... ++Input: ++ client: i2c client ++Output: ++ success: 0 ++ fail: -1 ++*******************************************************/ ++static int cst3xx_firmware_info(struct i2c_client * client) ++{ ++ int ret; ++ unsigned char buf[28]; ++// unsigned short ic_type, project_id; ++ ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x01; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ ++ mdelay(40); ++ ++ buf[0] = 0xD1; ++ buf[1] = 0xFC; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ ++ //0xCACA0000 ++ g_cst3xx_ic_checkcode = buf[3]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[2]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[1]; ++ g_cst3xx_ic_checkcode <<= 8; ++ g_cst3xx_ic_checkcode |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip g_cst3xx_ic_checkcode:0x%x.\r\n",g_cst3xx_ic_checkcode); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x04; ++ ret = cst3xx_i2c_read_register(client, buf, 4); ++ if (ret < 0) return -1; ++ g_cst3xx_ic_type = buf[3]; ++ g_cst3xx_ic_type <<= 8; ++ g_cst3xx_ic_type |= buf[2]; ++ ++ ++ g_cst3xx_ic_project_id = buf[1]; ++ g_cst3xx_ic_project_id <<= 8; ++ g_cst3xx_ic_project_id |= buf[0]; ++ ++ printk("linc cst3xx [cst3xx] the chip ic g_cst3xx_ic_type :0x%x, g_cst3xx_ic_project_id:0x%x\r\n", ++ g_cst3xx_ic_type, g_cst3xx_ic_project_id); ++ ++ mdelay(2); ++ ++ buf[0] = 0xD2; ++ buf[1] = 0x08; ++ ret = cst3xx_i2c_read_register(client, buf, 8); ++ if (ret < 0) return -1; ++ ++ g_cst3xx_ic_version = buf[3]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[2]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[1]; ++ g_cst3xx_ic_version <<= 8; ++ g_cst3xx_ic_version |= buf[0]; ++ ++ g_cst3xx_ic_checksum = buf[7]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[6]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[5]; ++ g_cst3xx_ic_checksum <<= 8; ++ g_cst3xx_ic_checksum |= buf[4]; ++ ++ tpd_info.vid = g_cst3xx_ic_version; ++ tpd_info.pid = 0x00; ++ ++ ++ printk(" cst3xx [cst3xx] the chip ic version:0x%x, checksum:0x%x\r\n", ++ g_cst3xx_ic_version, g_cst3xx_ic_checksum); ++ ++ if(g_cst3xx_ic_version==0xA5A5A5A5) ++ { ++ printk(" cst3xx [cst3xx] the chip ic don't have firmware. \n"); ++ return -1; ++ } ++ if((g_cst3xx_ic_checkcode&0xffff0000)!=0xCACA0000){ ++ printk("linc cst3xx [cst3xx] cst3xx_firmware_info read error .\r\n"); ++ return -1; ++ } ++ ++ buf[0] = 0xD1; ++ buf[1] = 0x09; ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret < 0) return -1; ++ mdelay(5); ++ ++ ++ return 0; ++} ++ ++static int cst3xx_update_judge( unsigned char *pdata, int strict) ++{ ++ unsigned short ic_type, project_id; ++ unsigned int fw_checksum, fw_version; ++ const unsigned int *p; ++ int i; ++ unsigned char *pBuf; ++ ++ fw_checksum = 0x55; ++ p = (const unsigned int *)pdata; ++ for (i=0; i<(CST3XX_BIN_SIZE-4); i+=4) { ++ fw_checksum += (*p); ++ p++; ++ } ++ ++ if (fw_checksum != (*p)) { ++ printk(" cst3xx[cst3xx]calculated checksum error:0x%x not equal 0x%x.\n", fw_checksum, *p); ++ return -1; //bad fw, so do not update ++ } ++ ++ pBuf = &pdata[CST3XX_BIN_SIZE-16]; ++ ++ project_id = pBuf[1]; ++ project_id <<= 8; ++ project_id |= pBuf[0]; ++ ++ ic_type = pBuf[3]; ++ ic_type <<= 8; ++ ic_type |= pBuf[2]; ++ ++ fw_version = pBuf[7]; ++ fw_version <<= 8; ++ fw_version |= pBuf[6]; ++ fw_version <<= 8; ++ fw_version |= pBuf[5]; ++ fw_version <<= 8; ++ fw_version |= pBuf[4]; ++ ++ fw_checksum = pBuf[11]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[10]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[9]; ++ fw_checksum <<= 8; ++ fw_checksum |= pBuf[8]; ++ ++ printk(" cst3xx[cst3xx]the updating firmware:project_id:0x%04x,ic type:0x%04x,version:0x%x,checksum:0x%x\n", ++ project_id, ic_type, fw_version, fw_checksum); ++ ++ if (strict > 0) { ++ ++ if (g_cst3xx_ic_checksum != fw_checksum){ ++ if (g_cst3xx_ic_version >fw_version){ ++ printk("[cst3xx]fw version(0x%x), ic version(0x%x).\n",fw_version, g_cst3xx_ic_version); ++ // return -1; ++ } ++ }else{ ++ printk("[cst3xx]fw checksum(0x%x), ic checksum(0x%x).\n",fw_checksum, g_cst3xx_ic_checksum); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++static int cst3xx_boot_update_fw(struct cst3xx_ts_data *ts, unsigned char *pdata) ++{ ++ int ret; ++ int retry = 0; ++ int flag = 0; ++ ++ while (retry++ < 3) { ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret == 0) { ++ flag = 1; ++ break; ++ } ++ } ++ ++ if (flag == 1) { ++ ret = cst3xx_update_judge(pdata, 1); ++ if (ret < 0) { ++ printk(" cst3xx[cst3xx] no need to update firmware.\n"); ++ return 0; ++ } ++ } ++ ++ ret = cst3xx_update_firmware(ts, pdata); ++ if (ret < 0){ ++ printk(" cst3xx [cst3xx] update firmware failed.\n"); ++ return -1; ++ } ++ ++ mdelay(50); ++ ++ ret = cst3xx_firmware_info(ts->client); ++ if (ret < 0) { ++ printk(" cst3xx [cst3xx] after update read version and checksum fail.\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++static int hyn_boot_update_fw(struct cst3xx_ts_data * ts) ++{ ++ unsigned char *ptr_fw; ++ int ret; ++ ptr_fw = pcst3xx_update_firmware; ++ ret = cst3xx_boot_update_fw(ts, ptr_fw); ++ return ret; ++ ++} ++ ++ ++/*******************************Chose which I2C interface ********************************************/ ++ ++#if USE_ANALOG_I2C ++ ++#define I2CSDA GPIO_PB(23) ++#define I2CSCL GPIO_PB(22) ++ ++#define I2CSDA_HIGH gpio_direction_output(I2CSDA,1) ++#define I2CSDA_LOW gpio_direction_output(I2CSDA,0) ++ ++#define I2CSCL_HIGH gpio_direction_output(I2CSCL,1) ++#define I2CSCL_LOW gpio_direction_output(I2CSCL,0) ++ ++#define delay_data 2 ++static void iicstart(void) ++{ ++ I2CSDA_HIGH; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_LOW; ++ __udelay(2); ++ I2CSCL_LOW; ++ __udelay(2); ++} ++static void iicstop(void) ++{ ++ I2CSDA_LOW; ++ I2CSCL_HIGH; ++ __udelay(2); ++ I2CSDA_HIGH; ++ __udelay(2); ++ ++} ++static unsigned char waitack(void) ++{ ++ u8 ucErrTime=0; ++ ++ gpio_direction_input(GPIO_PB(23)); ++ // __udelay(2); ++ ++ // I2CSDA_HIGH; ++ // __udelay(2); ++ I2CSCL_HIGH; ++ __udelay(2); ++ ++ while(__gpio_get_value(GPIO_PB(23))) ++ { ++ ucErrTime++; ++ // printk("time out ++ \n"); ++ if(ucErrTime>250) ++ { ++ iicstop(); ++ return 1; ++ } ++ } ++ I2CSCL_LOW; ++ __udelay(2); ++ return 0; ++} ++static void sendack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_LOW; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ ++} ++static void sendnotack(void) ++{ ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSDA_HIGH; ++ __udelay(delay_data); ++ ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++} ++static void iicsendbyte(unsigned char ch) ++{ ++ unsigned char i; ++ I2CSCL_LOW; ++ for(i = 0;i<8;i++) ++ { ++ if(ch&0x80) ++ { ++ I2CSDA_HIGH; ++ } ++ else ++ { ++ I2CSDA_LOW; ++ } ++ __udelay(delay_data); ++ ch<<=1; ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ } ++} ++static unsigned char iicreceivebyte(unsigned char ack) ++{ ++ unsigned char i=8; ++ unsigned char ddata=0; ++ ++ gpio_direction_input(GPIO_PC(27)); ++ __udelay(delay_data); ++ ++ for(i = 0;i<8;i++) ++ { ++ I2CSCL_LOW; ++ __udelay(delay_data); ++ I2CSCL_HIGH; ++ __udelay(delay_data); ++ ++ ddata<<=1; ++ if(gpio_get_value(GPIO_PC(27))) ddata++; ++ } ++ ++ if(!ack) ++ sendnotack(); ++ else ++ sendack(); ++ ++ return ddata; ++} ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int count = len; ++ iicstart(); ++ __udelay(delay_data); ++ ++/* ++ iicsendbyte( (0x1a<<1) | 0); ++ __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ ++ iicsendbyte(buf[0]); ++ __udelay(delay_data); ++ waitack(); ++ __udelay(delay_data); ++*/ ++ iicstart(); ++ __udelay(delay_data); ++ ++ iicsendbyte((0x1a << 1 ) | 1); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_read wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ ++ while(count) ++ { ++ if(count == 1) *buf = iicreceivebyte(0); ++ else *buf = iicreceivebyte(1); ++ count --; ++ buf++; ++ } ++ iicstop(); ++ __udelay(delay_data); ++ return 0; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int count = len; ++ iicstart(); ++ // __udelay(delay_data); ++ ++ iicsendbyte((0x1A << 1) | 0); ++// __udelay(delay_data); ++ ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write send address wait ack timeoue \n"); ++ return 1; ++ } ++ ++ while(count--) ++ { ++ iicsendbyte(*(buf++)); ++ __udelay(delay_data); ++ if(waitack()) ++ { ++ iicstop(); ++ printk(" cst3xx_i2c_write wait ack timeoue \n"); ++ return 1; ++ } ++ __udelay(delay_data); ++ } ++ ++ iicstop(); ++ __udelay(delay_data); ++ ++ return 0; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ printk(">>>>>>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if(ret) printk("failed to write cst3xx\n"); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ if(ret) printk("failed to write cst3xx\n"); ++ return ret; ++} ++ ++#elif USE_LOWEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++// printk(">>>>>>>low speed>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_recv(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++// printk(">>>>>>low speed>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ int retries = 0; ++ ++ while (retries < 2) { ++ ret = i2c_master_send(client, buf, len); ++ if(ret<=0) ++ retries++; ++ else ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++// printk(">>>>>low speed>>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ int ret = -1; ++ ++ ret = cst3xx_i2c_write(client, buf, 2); ++ ++ ret = cst3xx_i2c_read(client, buf, len); ++ ++ return ret; ++} ++ ++#elif USE_HIGHEST_I2CA ++static int cst3xx_i2c_read(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>high speed>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags |= I2C_M_RD; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++/******************************************************* ++Function: ++ read data from register. ++Input: ++ buf: first two byte is register addr, then read data store into buf ++ len: length of data that to read ++Output: ++ success: number of messages ++ fail: negative errno ++*******************************************************/ ++static int cst3xx_i2c_read_register(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>high speed>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ struct i2c_msg msgs[2]; ++ int ret = -1; ++ int retries = 0; ++ ++ msgs[0].flags = 0; ++ msgs[0].addr = client->addr; ++ msgs[0].len = 2; ++ msgs[0].buf = buf; ++ ++ msgs[1].flags |= I2C_M_RD; ++ msgs[1].addr = client->addr; ++ msgs[1].len = len; ++ msgs[1].buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if(ret == 2) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++ ++static int cst3xx_i2c_write(struct i2c_client *client, unsigned char *buf, int len) ++{ ++ HYN_FUNC_ENTER(); ++ printk(">>>>>>high speed>>>>>>>>>>>func=%s,line=%d\n\n",__func__,__LINE__); ++ struct i2c_msg msg; ++ int ret = -1; ++ int retries = 0; ++ ++ msg.flags = 0; ++ msg.addr = client->addr; ++ msg.len = len; ++ msg.buf = buf; ++ ++ while (retries < 2) { ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == 1) ++ break; ++ retries++; ++ } ++ ++ return ret; ++} ++#else ++#endif ++/*********************************i2c end********************************/ ++ ++ ++static int cst3xx_i2c_test(struct i2c_client *client) ++{ ++ int retry = 0; ++ int ret; ++ unsigned char buf[4]; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ while (retry++ < 5) { ++ ret = cst3xx_i2c_write(client, buf, 2); ++ if (ret == 0) ++ return ret; ++ ++ mdelay(2); ++ } ++ ++ if(retry==5) printk(" cst3xx hyn I2C TEST error.ret:%d;\n", ret); ++ ++ return ret; ++} ++ ++ ++static void cst3xx_reset(struct cst3xx_ts_data *ts) { ++ if(gpio_is_valid(ts->pdata->reset_gpio)) { ++ gpio_direction_output(ts->pdata->reset_gpio,0); ++ mdelay(100); ++ gpio_direction_output(ts->pdata->reset_gpio,1); ++ mdelay(100); ++ } ++} ++/**************************** basic communication end*******************************/ ++ ++ ++static void cst3xx_touch_report(struct cst3xx_ts_data *ts) ++{ ++ unsigned char buf[30]; ++ unsigned char i2c_buf[8]; ++ unsigned char key_status, key_id = 0, finger_id, sw; ++ unsigned int input_x = 0,bx; ++ unsigned int input_y = 0,by; ++ unsigned int input_w = 0; ++ unsigned int input_x_delta = 0; ++ unsigned int input_y_delta = 0; ++ unsigned char cnt_up, cnt_down; ++ int i, ret, idx; ++ int cnt, i2c_len; ++ ++ int len_1, len_2; ++ ++ key_status = 0; ++ ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ ret = cst3xx_i2c_read_register(ts->client, buf, 7); ++ if(ret < 0) { ++ printk(" iic read touch point data failed.\n"); ++ goto OUT_PROCESS; ++ } ++ // printk(" read buf : buf[0]: %x ,buf[1]: %x ,buf[2]: %x, buf[3]: %x,buf[4]: %x ,buf[5]: %x ,buf[6]: %x, buf[7]: %x,\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); ++ ++ if(buf[6] != 0xAB) { ++ printk(KERN_INFO " data is not valid..\r\n"); ++ goto OUT_PROCESS; ++ } ++ ++ cnt = buf[5] & 0x7F; ++ if(cnt > 1) goto OUT_PROCESS; ++ else if(cnt==0) goto CLR_POINT; ++ ++ if(cnt == 0x01) { ++ goto FINGER_PROCESS; ++ } ++ ++FINGER_PROCESS: ++ ++ /* ++ * sw: buf[0] low 4 bit ++ * x pos: buf[1] low 4 bit | buf[3] high 4 bit ++ * y pos: buf[2] low 4 bit | buf[3] low 4 bit ++ * z press : buf[4] ++ * finger_id:buf[0] high 4 bit ++ */ ++ i2c_buf[0] = 0xD0; ++ i2c_buf[1] = 0x00; ++ i2c_buf[2] = 0xAB; ++ ++ ret = cst3xx_i2c_write(ts->client, i2c_buf, 3); ++ if(ret < 0) { ++ printk(" cst3xx hyn send read touch info ending failed.\r\n"); ++ cst3xx_reset_ic(ts,20); ++ goto END; ++ } ++ ++ idx = 0; ++ cnt_up = 0; ++ cnt_down = 0; ++ input_x = (unsigned int)((buf[idx + 1] << 4) | ((buf[idx + 3] >> 4) & 0x0F)); ++ input_y = (unsigned int)((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0F)); ++ input_w = (unsigned int)(buf[idx + 4]); ++ sw = (buf[idx] & 0x0F) >> 1; ++ finger_id = (buf[idx] >> 4) & 0x0F; ++ ++ //printk(KERN_DEBUG " no handle : cst3xxPoint x:%d, y:%3d, w:%3d, id:%d, sw:%d. \n", input_x, input_y, input_w,finger_id, sw); ++ bx = input_x; ++ by = input_y; ++ ++// input_x=input_x*CST3XX_MAX_X/268; //update 0729: no handle == handle ++// input_x=input_x*CST3XX_MAX_X/360; // ++// input_y=input_y*CST3XX_MAX_Y/800; ++ ++// if(input_x >= CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++// if(input_y >= CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ ++// input_x = CST3XX_MAX_X-input_x; ++// input_y = CST3XX_MAX_Y-input_y; ++#if 1 // clivia ++ #define TP_START_X 106 ++ #define TP_WIDTH 268 ++ #define TP_MAX_X (TP_START_X+TP_WIDTH-1) ++ #define TP_START_Y 0 ++ #define TP_HEIGHT 800 ++ #define TP_MAX_Y (TP_START_Y+TP_HEIGHT-1) ++ if(input_x < 106) ++ input_x = 106; ++ else if(input_x > TP_MAX_X) ++ input_x = TP_MAX_X; ++ else ++ input_x = input_x - 106; ++ if(input_y > TP_MAX_Y) ++ input_y = TP_MAX_Y; ++ ++#else ++ if(input_x > CST3XX_MAX_X-1) ++ input_x = CST3XX_MAX_X-1; ++ if(input_y > CST3XX_MAX_Y-1) ++ input_y = CST3XX_MAX_Y-1; ++#ifdef HYN_DRAW_POINT ++ if(input_x > 300){ ++ input_x_delta = input_x - (CST3XX_MAX_X/2); ++ input_x = input_x + input_x_delta/((CST3XX_MAX_X/2)/20); ++ if(input_x > CST3XX_MAX_X) input_x = CST3XX_MAX_X; ++ } ++ if(input_x < 40){ ++ input_x_delta = (CST3XX_MAX_X/2) - input_x; ++ input_x = input_x - input_x_delta/((CST3XX_MAX_X/2)/12); ++ if(input_x < 0) input_x = 0; ++ } ++ if(input_y > 760){ ++ input_y_delta = input_y - (CST3XX_MAX_Y/2); ++ input_y = input_y + input_y_delta/((CST3XX_MAX_Y/2)/12); ++ if(input_y > CST3XX_MAX_Y) input_y = CST3XX_MAX_Y; ++ } ++ if(input_y < 40){ ++ input_y_delta = (CST3XX_MAX_Y/2) - input_y; ++ input_y = input_y - input_y_delta/((CST3XX_MAX_Y/2)/25); ++ if(input_y < 0) input_y = 0; ++ } ++ input_x -= (CST3XX_MAX_X - CST3XX_REL_X)/2; ++#endif ++#endif ++ ++// printk(KERN_DEBUG " handle : cst3xxPoint x:%d, y:%d, w:%d, id:%d, sw:%d. \n\n", input_x, input_y, input_w,finger_id, sw); ++ //clivia printk(KERN_DEBUG "cst3xxPoint bx:%3d, by=%3d, x:%3d, y:%3d, w:%3d, id:%d, sw:%d. \n", bx, by, input_x, input_y, input_w,finger_id, sw); ++ if (sw == 0x03 ) { ++ if((input_x > x_temp_pos + ERROR_TOUCH) || (input_x < x_temp_pos -ERROR_TOUCH) || (input_y > y_temp_pos + ERROR_TOUCH) || (input_y < y_temp_pos -ERROR_TOUCH)) ++ { ++ // printk(" REPORT TOUCH DOWM Handle \n"); ++ x_temp_pos = input_x; ++ y_temp_pos = input_y; ++ input_report_key(ts->input_dev, BTN_TOUCH, 1); ++ input_report_abs(ts->input_dev, ABS_X, input_x); ++ input_report_abs(ts->input_dev, ABS_Y, input_y); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 1); ++ input_sync(ts->input_dev); ++ } ++ cnt_down++; ++ } ++ else if(sw == 0) { ++ cnt_up++; ++ } ++ ++ if((cnt_up>0) && (cnt_down==0) ){ ++ // printk(" REPORT TOUCH UP Handle \n"); ++ x_temp_pos = 0; ++ y_temp_pos = 0; ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_report_abs(ts->input_dev, ABS_PRESSURE, 0); ++ input_mt_sync(ts->input_dev); ++ } ++ input_sync(ts->input_dev); ++ goto END; ++CLR_POINT: ++ ++ input_report_key(ts->input_dev, BTN_TOUCH, 0); ++ input_mt_sync(ts->input_dev); ++ input_sync(ts->input_dev); ++ ++OUT_PROCESS: ++ buf[0] = 0xD0; ++ buf[1] = 0x00; ++ buf[2] = 0xAB; ++ ret = cst3xx_i2c_write(ts->client, buf, 3); ++ if (ret < 0) { ++ printk(" send read touch info ending failed.\n"); ++ cst3xx_reset_ic(ts,20); ++ } ++END: ++ return; ++} ++ ++ ++/******************************* irq handle begin************************************/ ++static void cst3xx_work_handler(struct work_struct *work) ++{ ++ struct cst3xx_ts_data *cst3xx_ts = container_of(work, struct cst3xx_ts_data, work); ++ int ret = 0; ++ /******************here handle touch *******************/ ++ // printk(KERN_INFO "-----------enter cst3xx_work_handler------------\n"); ++ cst3xx_touch_report(cst3xx_ts); ++ enable_irq(cst3xx_ts->irq); ++} ++ ++static irqreturn_t cst3xx_ts_irq_handler(int irq, void *dev_id) ++{ ++ struct cst3xx_ts_data *ts = dev_id; ++ ++ // printk( KERN_INFO "-----------enter cst3xx_ts_irq_handler------------\n"); ++ ++ disable_irq_nosync(ts->irq);//use in interrupt,disable_irq will make dead lock. ++ ++ if (!work_pending(&ts->work)) { ++ queue_work(ts->workqueue, &ts->work); ++ // queue_delayed_work(ts->workqueue,&ts->dwork,1);//10ms * x ++ } else { ++ enable_irq(ts->irq); ++ } ++ ++ return IRQ_HANDLED; ++} ++/******************************* irq handle end************************************/ ++static int cst3xx_parse_dt(struct device *dev, struct cst3xx_platform_data *pdata) ++{ ++ int ret = 0; ++ struct device_node *np = dev->of_node; ++ u32 temp_val = 0; ++ ++ HYN_FUNC_ENTER(); ++ ++ /* reset, irq gpio info */ ++ pdata->reset_gpio = of_get_named_gpio_flags(np, "hyn,reset-gpio", ++ 0, &pdata->reset_gpio_flags); ++ if (pdata->reset_gpio < 0) ++ HYN_ERROR("Unable to get reset_gpio"); ++ ++ pdata->int_gpio = of_get_named_gpio_flags(np, "hyn,irq-gpio", ++ 0, pdata->irqflags); ++ if (pdata->int_gpio < 0) ++ HYN_ERROR("Unable to get irq_gpio"); ++ ++ HYN_INFO(" irq gpio:%d, reset gpio:%d", ++ pdata->int_gpio, pdata->reset_gpio); ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++} ++static int cst3xx_gpio_configure(struct cst3xx_ts_data *data) ++{ ++ int ret = 0; ++ ++ HYN_FUNC_ENTER(); ++ /* request irq gpio */ ++ if (gpio_is_valid(data->pdata->int_gpio)) { ++ ret = gpio_request(data->pdata->int_gpio, "cst3xx_irq_gpio"); ++ if (ret) { ++ HYN_ERROR("[GPIO]irq gpio request failed"); ++ goto err_irq_gpio_req; ++ } ++ ++ ret = gpio_direction_input(data->pdata->int_gpio); ++ if (ret) { ++ HYN_ERROR("[GPIO]set_direction for irq gpio failed"); ++ goto err_irq_gpio_dir; ++ } ++ } ++ ++ /* request reset gpio */ ++ if (gpio_is_valid(data->pdata->reset_gpio)) { ++ ret = gpio_request(data->pdata->reset_gpio, "cst3xx_reset_gpio"); ++ if (ret) { ++ HYN_ERROR("[GPIO]reset gpio request failed"); ++ goto err_irq_gpio_dir; ++ } ++ ++// ret = gpio_direction_output(data->pdata->reset_gpio, 1); ++// if (ret) { ++// HYN_ERROR("[GPIO]set_direction for reset gpio failed"); ++// goto err_reset_gpio_dir; ++// } ++ } ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++ ++err_reset_gpio_dir: ++ if (gpio_is_valid(data->pdata->reset_gpio)) ++ gpio_free(data->pdata->reset_gpio); ++err_irq_gpio_dir: ++ if (gpio_is_valid(data->pdata->int_gpio)) ++ gpio_free(data->pdata->int_gpio); ++err_irq_gpio_req: ++ HYN_FUNC_EXIT(); ++ return ret; ++} ++ ++static int cst3xx_input_init(struct cst3xx_ts_data *ts_data) ++{ ++ int ret = 0; ++ int key_num = 0; ++ struct cst3xx_platform_data *pdata = ts_data->pdata; ++ struct input_dev *input_dev; ++ ++ HYN_FUNC_ENTER(); ++ input_dev = input_allocate_device(); ++ if (!input_dev) { ++ HYN_ERROR("Failed to allocate memory for input device"); ++ return -ENOMEM; ++ } ++ ++ /* Init and register Input device */ ++ input_dev->name = CST3XX_NAME; ++ ++ input_dev->id.bustype = BUS_I2C; ++ input_dev->dev.parent = ts_data->dev; ++ ++ input_set_drvdata(input_dev, ts_data); ++ ++ __set_bit(EV_SYN, input_dev->evbit); ++ __set_bit(EV_ABS, input_dev->evbit); ++ __set_bit(EV_KEY, input_dev->evbit); ++ __set_bit(BTN_TOUCH, input_dev->keybit); ++// __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); ++ set_bit(ABS_X, input_dev->absbit); //add from hyn ++ set_bit(ABS_Y, input_dev->absbit); ++ set_bit(ABS_PRESSURE, input_dev->absbit); ++ ++/*---add from hyn*/ ++ input_set_abs_params(input_dev, ABS_X, ts_data->pdata->x_min, ts_data->pdata->x_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, ts_data->pdata->y_min, ts_data->pdata->y_max, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0 , 0); ++/*add from hyn---*/ ++ ++ ret = input_register_device(input_dev); ++ if (ret) { ++ HYN_ERROR("Input device registration failed"); ++ input_set_drvdata(input_dev, NULL); ++ input_free_device(input_dev); ++ input_dev = NULL; ++ return ret; ++ } ++ ++ ts_data->input_dev = input_dev; ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++} ++ ++static int cst3xx_irq_registration(struct cst3xx_ts_data *ts_data) ++{ ++ int ret = 0; ++ struct cst3xx_platform_data *pdata = ts_data->pdata; ++ ++ ts_data->irq = gpio_to_irq(pdata->int_gpio); ++ pdata->irqflags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; ++ HYN_INFO("irq:%d, flag:%x", ts_data->irq, pdata->irqflags); ++ ret = request_threaded_irq(ts_data->irq, NULL, cst3xx_ts_irq_handler, ++ pdata->irqflags, ++ CST3XX_NAME, ts_data); ++ ++ return ret; ++} ++ ++static int cst3xx_ts_probe_entry(struct cst3xx_ts_data *ts_data) ++{ ++ int ret = 0; ++ int rc=-1; ++ int pdata_size = sizeof(struct cst3xx_platform_data); ++ ++ HYN_FUNC_ENTER(); ++ ts_data->pdata = kzalloc(pdata_size, GFP_KERNEL); ++ if (!ts_data->pdata) { ++ HYN_ERROR("allocate memory for platform_data fail"); ++ return -ENOMEM; ++ } ++ ++ if (ts_data->dev->of_node) { ++ ret = cst3xx_parse_dt(ts_data->dev, ts_data->pdata); ++ if (ret) ++ HYN_ERROR("device-tree parse fail"); ++ } else { ++ if (ts_data->dev->platform_data) { ++ memcpy(ts_data->pdata, ts_data->dev->platform_data, pdata_size); ++ } else { ++ HYN_ERROR("platform_data is null"); ++ return -ENODEV; ++ } ++ } ++ //init work for cst3xx.. ++ ++ INIT_WORK(&ts_data->work, cst3xx_work_handler); ++ ++ ts_data->workqueue = create_singlethread_workqueue("cst3xx_wq"); ++ if (!ts_data->workqueue) { ++ HYN_ERROR("create cst3xx workqueue fail"); ++ } ++ ++// spin_lock_init(&ts_data->irq_lock); ++// mutex_init(&ts_data->report_mutex); ++// mutex_init(&ts_data->bus_lock); ++ ++ /* Init communication interface */ ++ ret = cst3xx_bus_init(ts_data); ++ if (ret) { ++ HYN_ERROR("bus initialize fail"); ++ goto err_bus_init; ++ } ++#if USE_ANALOG_I2C ++ if (gpio_is_valid(I2CSDA) ++ { ++ gpio_free(I2CSDA); ++ ret = gpio_request(GPIO_PB(23),"I2C2-SDA"); ++ if(ret < 0){ ++ printk("I2C2-SDA gpio request failed\n"); ++ return ret; ++ } ++ } ++ if (gpio_is_valid(I2CSCL)) ++ { ++ gpio_free(I2CSCL); ++ ret = gpio_request(GPIO_PB(22),"I2C2-SCL"); ++ if(ret < 0){ ++ printk("I2C2-SCL gpio request failed\n"); ++ return ret; ++ } ++ } ++#endif ++ ret = cst3xx_i2c_test(ts_data->client); ++ // if(ret>=0){ ++ if(ret<0){ ++ ++ ++ mdelay(100); ++ ++ printk( KERN_INFO "cst3xx test OK -------------------\n"); ++#ifdef HYN_UPDATE_FIRMWARE_ENABLE ++ ret = cst3xx_boot_update_fw(ts_data,pcst3xx_update_firmware);// ++ if(ret < 0){ ++ printk(" cst3xx hyn_boot_update_fw failed.\n"); ++ return -1; ++ } ++#endif ++ ++ }else{ ++ // printk( KERN_INFO "cst3xx hyn i2c communication failed.---------------\n"); ++ mdelay(20); ++ rc = hyn_boot_update_fw(ts_data); ++ if(rc < 0){ ++ printk(" cst3xx hyn_boot_update_fw failed.\n"); ++ //return -1; ++ } ++ } ++ ++ ret = cst3xx_input_init(ts_data); ++ if (ret) { ++ HYN_ERROR("input initialize fail"); ++ goto err_input_init; ++ } ++ ++ ret = cst3xx_gpio_configure(ts_data); ++ if (ret) { ++ HYN_ERROR("configure the gpios fail"); ++ goto err_gpio_config; ++ } ++ printk( KERN_INFO "cst3xx reset ----before---------------\n"); ++ cst3xx_reset(ts_data); ++ printk( KERN_INFO "cst3xx reset ----after--------------\n"); ++ ++ ret = cst3xx_irq_registration(ts_data); ++ if (ret) { ++ HYN_ERROR("request irq failed"); ++ goto err_irq_req; ++ } ++ ++ HYN_FUNC_EXIT(); ++ return 0; ++ ++err_irq_req: ++ if (gpio_is_valid(ts_data->pdata->reset_gpio)) ++ gpio_free(ts_data->pdata->reset_gpio); ++ if (gpio_is_valid(ts_data->pdata->int_gpio)) ++ gpio_free(ts_data->pdata->int_gpio); ++err_gpio_config: ++ kfree_safe(ts_data->point_buf); ++ kfree_safe(ts_data->events); ++err_input_init: ++ if (ts_data->workqueue) ++ destroy_workqueue(ts_data->workqueue); ++err_bus_init: ++ kfree_safe(ts_data->bus_tx_buf); ++ kfree_safe(ts_data->bus_rx_buf); ++ kfree_safe(ts_data->pdata); ++ ++ HYN_FUNC_EXIT(); ++ return ret; ++} ++static int cst3xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ int ret = 0; ++ struct cst3xx_ts_data *ts_data = NULL; ++ struct input_dev *input_dev; ++ ++ struct cst3xx_platform_data *pdata = (struct cst3xx_platform_data*)client->dev.platform_data; ++ ++ HYN_INFO("Touch Screen(I2C BUS) driver prboe..."); ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ HYN_ERROR("I2C not supported"); ++ return -ENODEV; ++ } ++ ++ /* malloc memory for global struct variable */ ++ ts_data = (struct cst3xx_ts_data *)kzalloc(sizeof(*ts_data), GFP_KERNEL); ++ if (!ts_data) { ++ HYN_ERROR("allocate memory for cst3xx_data fail"); ++ return -ENOMEM; ++ } ++ ts_data->client = client; ++ ts_data->dev = &client->dev; ++ ts_data->pdata = pdata; ++ i2c_set_clientdata(client, ts_data); ++ ++ ret = cst3xx_ts_probe_entry(ts_data); ++ if (ret) { ++ HYN_ERROR("Touch Screen(I2C BUS) driver probe fail"); ++ kfree_safe(ts_data); ++ return ret; ++ } ++ if(client->addr != 0x1A) //check address ++ { ++ client->addr = 0x1A; ++ printk(">>>>>>>>>>>>>1>>>xtang:i2c_client_HYN->addr=%d.\n",client->addr); ++ ++ }else ++ printk(">>>>>>>>>>>>2>>>>xtang:i2c_client_HYN->addr=%d.\n",client->addr); ++ ++ ++ HYN_INFO("Touch Screen(I2C BUS) driver prboe successfully"); ++ return 0; ++} ++ ++ ++static int cst3xx_ts_remove(struct i2c_client *client) ++{ ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ free_irq(ts->irq,ts); ++ devm_free_irq(&ts->client->dev, ts->client->irq,ts); ++ destroy_workqueue(ts->workqueue); ++ input_unregister_device(ts->input_dev); ++ devm_gpio_free(&ts->client->dev, ts->pdata->reset_gpio); ++ gpio_free(ts->pdata->int_gpio); ++ ++#if USE_ANALOG_I2C ++ gpio_free(I2CSDA); ++ gpio_free(I2CSCL); ++#endif ++//i2c bus init. ++ cst3xx_bus_exit(ts); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int cst3xx_ts_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ enable_irq_wake(client->irq); ++ } else { ++ disable_irq(client->irq); ++ cst3xx_ts_power(ts, false);//reset ++ } ++ ++ return 0; ++} ++ ++static int cst3xx_ts_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct cst3xx_ts_data *ts = i2c_get_clientdata(client); ++ ++ if (device_may_wakeup(&client->dev)) { ++ disable_irq_wake(client->irq); ++ } else { ++ cst3xx_ts_power(ts, true); ++ enable_irq(client->irq); ++ } ++ return 0; ++} ++ ++#endif ++ ++static SIMPLE_DEV_PM_OPS(cst3xx_ts_pm_ops, ++ cst3xx_ts_suspend, cst3xx_ts_resume); ++ ++static const struct i2c_device_id cst3xx_ts_id[] = { ++ { CST3XX_NAME, 0 }, ++ { } ++}; ++static const struct of_device_id cst3xx_dt_match[] = { ++ {.compatible = "hyn,cst3xx", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, cst3xx_dt_match); ++ ++static struct i2c_driver cst3xx_ts_driver = { ++ .probe = cst3xx_ts_probe, ++ .remove = cst3xx_ts_remove, ++ .driver = { ++ .name = CST3XX_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(cst3xx_dt_match), ++ .pm = &cst3xx_ts_pm_ops, ++ }, ++ .id_table = cst3xx_ts_id, ++}; ++ ++static int __init cst3xx_ts_init(void) ++{ ++ int ret = 0; ++ ++ HYN_FUNC_ENTER(); ++ ret = i2c_add_driver(&cst3xx_ts_driver); ++ if ( ret != 0 ) { ++ HYN_ERROR("hyn touch screen driver init failed!"); ++ } ++ HYN_FUNC_EXIT(); ++ return ret; ++} ++ ++static void __exit cst3xx_ts_exit(void) ++{ ++ i2c_del_driver(&cst3xx_ts_driver); ++} ++//module_init(cst3xx_ts_init); ++late_initcall(cst3xx_ts_init); ++module_exit(cst3xx_ts_exit); ++ ++MODULE_AUTHOR("HYN Driver Team"); ++MODULE_DESCRIPTION("HYN Touchscreen Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx.h b/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx.h +new file mode 100644 +index 000000000..16f9978d1 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx.h +@@ -0,0 +1,136 @@ ++#ifndef TOUCHSCREEN_CST3XX__H ++#define TOUCHSCREEN_CST3XX__H ++ ++/***************************************************************************** ++* Included header files ++*****************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/***************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++ ++/* -- dirver configure -- */ ++#define CFG_MAX_TOUCH_POINTS 1 ++#define MAX_AREA 0xff ++ ++#define CST3XX_NAME "cst3xx" ++ ++/*register address*/ ++#define CST3XX_ADDRESS 0x1A ++ ++/***************************************************************************** ++* Private enumerations, structures and unions using typedef ++*****************************************************************************/ ++struct cst3xx_ts_data { ++ struct i2c_client *client; ++ struct input_dev *input_dev; ++ struct device *dev; ++ struct cst3xx_platform_data *pdata; ++ struct work_struct work; ++ struct delayed_work dwork; ++ struct workqueue_struct *workqueue; ++ int irq; ++ ++ struct ts_event *events; ++ u8 *bus_tx_buf; ++ u8 *bus_rx_buf; ++ u8 *point_buf; ++ ++}; ++ ++extern struct cst3xx_ts_data *cst3xx_data; ++/* The platform data for the Focaltech ft5x0x touchscreen driver */ ++struct cst3xx_platform_data { ++ unsigned int x_min; ++ unsigned int y_min; ++ unsigned int x_max; ++ unsigned int y_max; ++ unsigned long irqflags; ++ unsigned int int_gpio; ++ unsigned int reset_gpio; ++ ++ unsigned int reset_gpio_flags; ++ spinlock_t irq_lock; ++ struct mutex report_mutex; ++ struct mutex bus_lock; ++ u8 *bus_tx_buf; ++ u8 *bus_rx_buf; ++}; ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++ ++int cst3xx_bus_init(struct cst3xx_ts_data *ts_data); ++int cst3xx_bus_exit(struct cst3xx_ts_data *ts_data); ++ ++#define kfree_safe(pbuf) do {\ ++ if (pbuf) {\ ++ kfree(pbuf);\ ++ pbuf = NULL;\ ++ }\ ++} while(0) ++ ++/***************************************************************************** ++* Debug interface. ++*****************************************************************************/ ++ ++#if HYN_DEBUG_EN ++ ++#define HYN_DEBUG(fmt, args...) do { \ ++ printk("[HYN_TS]%s:"fmt"\n", __func__, ##args); \ ++} while (0) ++ ++#define HYN_FUNC_ENTER() do { \ ++ printk("[HYN_TS]%s: Enter(%d)\n", __func__,__LINE__); \ ++} while (0) ++ ++#define HYN_FUNC_EXIT() do { \ ++ printk("[HYN_TS]%s: Exit(%d)\n", __func__, __LINE__); \ ++} while (0) ++#else /* #if HYN_DEBUG_EN*/ ++#define HYN_DEBUG(fmt, args...) ++#define HYN_FUNC_ENTER() ++#define HYN_FUNC_EXIT() ++#endif ++ ++#define HYN_INFO(fmt, args...) do { \ ++ printk(KERN_INFO "[HYN_TS/I]%s:"fmt"\n", __func__, ##args); \ ++} while (0) ++ ++#define HYN_ERROR(fmt, args...) do { \ ++ printk(KERN_ERR "[HYN_TS/E]%s:"fmt"\n", __func__, ##args); \ ++} while (0) ++ ++#endif /* TOUCHSCREEN_CST3XX__H */ ++ ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx_RS659_fw.h b/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx_RS659_fw.h +new file mode 100644 +index 000000000..efb7139f2 +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_cst3xx_RS659_fw.h +@@ -0,0 +1,1550 @@ ++ ++#ifndef __CST3xx_FW_H__ ++#define __CST3xx_FW_H__ ++ ++ unsigned char cst3_fw[] ={ ++ 0x98,0xE0,0x07,0x01,0xC8,0xC8,0x02,0x00,0x00,0x00,0x00,0x00,0xC8,0x88,0x02,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x98,0x68,0x00,0x00,0x98,0x68,0x01,0x00,0x00,0x00,0x00,0x00, ++ 0x98,0x08,0x02,0x00,0x00,0x00,0x00,0x00,0x98,0xD8,0x02,0x00,0x80,0x07,0xC0,0x17, ++ 0x82,0x07,0xC0,0x07,0x01,0x65,0x40,0x86,0xC1,0x41,0xC0,0x20,0xC5,0x68,0x31,0x12, ++ 0xF5,0x38,0x33,0x5A,0x32,0xA2,0x32,0xEA,0x10,0x62,0x8D,0x0E,0x81,0x07,0xC0,0x97, ++ 0x30,0xF2,0xF3,0x79,0x65,0x7E,0x30,0xB2,0x31,0x09,0x10,0x9A,0x87,0x06,0xD0,0xD8, ++ 0x35,0x12,0x35,0x5A,0x18,0x9A,0x39,0xC2,0x70,0x22,0x03,0x00,0x70,0x22,0x04,0x00, ++ 0xD0,0x81,0x98,0x16,0x43,0xC6,0x0B,0xC6,0xC2,0xD6,0x3F,0x90,0x99,0x0E,0x40,0x86, ++ 0x08,0x86,0xA9,0x0E,0x40,0x23,0x00,0x63,0x38,0x82,0x03,0x00,0x18,0x01,0x20,0x01, ++ 0x28,0x01,0x30,0x01,0xD0,0x81,0x98,0x0E,0x0F,0xC6,0xC3,0xDE,0x38,0x90,0x9A,0x06, ++ 0x08,0x86,0xA9,0x06,0x03,0x5B,0x38,0x82,0xAE,0xFD,0x30,0x02,0x30,0x02,0xEE,0xFD, ++ 0xA8,0x85,0xE8,0x85,0x85,0x27,0xE8,0x0F,0x37,0x8A,0xB8,0xFF,0xF8,0xAF,0x87,0x0F, ++ 0xD0,0x1F,0x81,0x27,0xEF,0xCF,0xBD,0xFF,0xF8,0x9F,0x87,0x27,0xE8,0xFF,0x05,0x00, ++ 0xAF,0x85,0x6F,0xFA,0x39,0x01,0xC0,0x43,0x37,0x4A,0xC9,0x01,0x38,0x30,0x32,0x42, ++ 0x86,0x01,0xC5,0x1B,0xCE,0x23,0xF0,0x53,0xC0,0x01,0x74,0x01,0xDD,0x16,0xC0,0x6B, ++ 0x48,0x68,0x87,0x3E,0xAA,0x7B,0xAC,0x3B,0x10,0xD2,0x8C,0x16,0xB0,0x63,0x06,0x09, ++ 0xB7,0x43,0xEC,0x85,0x34,0x6A,0xE8,0x4B,0xE6,0x48,0x92,0x4D,0xAF,0x4B,0x4D,0xF9, ++ 0x8D,0x0E,0x10,0x12,0x82,0x16,0xE8,0x0B,0x48,0x09,0x88,0x1E,0xB5,0x5B,0xAF,0x7B, ++ 0xAF,0x3B,0xEA,0x85,0x4F,0x09,0x8C,0xE6,0x0A,0x09,0xA8,0x0B,0xE8,0x85,0xAF,0x85, ++ 0x67,0x3A,0xE7,0x01,0x00,0x0F,0x80,0x0F,0xF5,0x6F,0xF0,0x03,0x47,0x01,0x80,0xD6, ++ 0xEF,0x85,0xA8,0xC5,0x00,0x21,0x80,0x0F,0xE8,0xBF,0x07,0x09,0x87,0x0F,0xE8,0xA7, ++ 0x79,0x02,0x47,0xC3,0x0C,0x01,0x19,0x42,0x00,0xC3,0x01,0x11,0x87,0x0F,0xE8,0x0F, ++ 0x61,0xEA,0x56,0x03,0x29,0x41,0x18,0x42,0x17,0x03,0x49,0x03,0x1F,0x42,0x09,0x03, ++ 0x15,0x2B,0x4B,0x03,0x1D,0x42,0x09,0x03,0x4D,0x03,0x1B,0x42,0x0B,0x03,0x4B,0x03, ++ 0x35,0x21,0x18,0x82,0x0B,0x03,0x4B,0x03,0x42,0x00,0x02,0x00,0x09,0x03,0x4B,0x03, ++ 0x19,0x42,0x09,0x03,0x49,0x03,0x19,0x82,0x09,0x03,0x49,0x03,0x08,0x09,0x18,0x42, ++ 0x0F,0x03,0x41,0x03,0x1F,0x42,0x05,0x03,0x45,0x03,0x1F,0x82,0x07,0x03,0x47,0x03, ++ 0x1F,0x42,0x04,0x03,0x45,0x03,0x1D,0x42,0x05,0x03,0x45,0x03,0x1D,0x82,0x05,0x03, ++ 0x45,0x03,0x1B,0x42,0x03,0x03,0x43,0x03,0x1B,0x82,0x05,0x03,0x44,0x03,0x1D,0x42, ++ 0x03,0x03,0x45,0x03,0x1B,0x42,0x04,0x03,0x0E,0x81,0x42,0x02,0x82,0x27,0xE0,0xE7, ++ 0x85,0x0F,0xE8,0xD7,0x85,0x0F,0xE8,0xB7,0x85,0x0F,0xE8,0xE7,0x48,0xE2,0x05,0x01, ++ 0x1D,0x43,0x4C,0x03,0x1D,0x42,0x0D,0x03,0x10,0x2B,0x03,0x11,0x84,0x0F,0xE8,0xE7, ++ 0x41,0xC3,0x09,0x01,0x19,0x42,0x00,0xC3,0x00,0x21,0x80,0x0F,0xE8,0x57,0x04,0x09, ++ 0x84,0x0F,0xE8,0x3F,0x42,0x03,0x41,0x00,0x01,0x00,0x02,0x03,0x40,0x03,0x0F,0x09, ++ 0x1F,0x42,0x00,0x03,0x4C,0x03,0x1B,0x42,0x09,0x03,0x4B,0x03,0x19,0x42,0x0C,0x03, ++ 0x41,0x03,0x1D,0x42,0x05,0x03,0x45,0x03,0x1D,0x82,0x01,0x03,0x41,0x03,0x1B,0x42, ++ 0x03,0x03,0x43,0x03,0x1B,0x82,0x01,0x03,0x48,0x0B,0x03,0x61,0x1B,0x0A,0x08,0x0B, ++ 0x48,0x0B,0x19,0x0A,0x0F,0x0B,0x41,0x0B,0x1F,0x0A,0x00,0x0B,0x48,0xE2,0x04,0x09, ++ 0xC8,0x01,0xAF,0x43,0x83,0x0F,0xD0,0x07,0xEC,0xC5,0x47,0xCA,0xC6,0x01,0xF3,0x0B, ++ 0x42,0xCA,0x84,0x01,0x48,0x01,0x80,0x3E,0x4A,0xD2,0x04,0x0B,0x0C,0xF9,0x57,0xB2, ++ 0x8C,0x89,0x97,0x01,0x10,0x8B,0x00,0x17,0x48,0xB2,0xCC,0xE1,0x04,0x0B,0x52,0xB2, ++ 0x00,0x13,0x0E,0x31,0x08,0x0B,0x08,0x11,0x08,0x0B,0x0C,0x51,0x0C,0x0B,0x1A,0x0B, ++ 0x18,0x0B,0x0A,0x01,0x1C,0x0B,0x40,0x52,0xC2,0x01,0x0F,0x14,0x3F,0x82,0xAB,0x85, ++ 0x70,0x72,0x0C,0x01,0x2C,0x01,0x60,0x72,0x50,0x72,0x04,0x01,0xA4,0x82,0x02,0x40, ++ 0x50,0x6A,0xC4,0x40,0xC4,0x00,0x54,0x6A,0xC0,0x10,0x1C,0x01,0xC6,0x83,0x01,0x38, ++ 0xC1,0x83,0xD0,0xC0,0x94,0x05,0x14,0x2A,0x90,0x06,0x30,0x2A,0x10,0x22,0xCC,0x06, ++ 0x32,0x22,0xE0,0x90,0xE6,0xD8,0x92,0xDD,0x5F,0x29,0x98,0x8E,0x59,0x0A,0xDC,0x40, ++ 0xA3,0xC2,0xE2,0xB0,0xE6,0x48,0x92,0x4D,0x4E,0x71,0x98,0xDE,0x48,0xE2,0x03,0x01, ++ 0xE4,0xD2,0x10,0x52,0x90,0x06,0x30,0x8A,0xE6,0x00,0x92,0x05,0x47,0x71,0x98,0xBE, ++ 0x50,0xDA,0x03,0x01,0x00,0x84,0xE0,0xE2,0x43,0xAC,0xD0,0x20,0xC8,0x20,0x03,0xA4, ++ 0xE6,0x00,0x92,0x05,0x47,0x71,0x98,0xB6,0x47,0x84,0x40,0xF9,0xCF,0x0E,0x00,0xF9, ++ 0x03,0x84,0x48,0xA2,0x40,0x84,0x80,0x43,0xE8,0x85,0xAF,0x85,0x40,0x22,0xC3,0x03, ++ 0x38,0x00,0x86,0xAE,0x00,0x01,0x85,0x0F,0xD3,0xBF,0x60,0x0A,0x01,0x01,0xE0,0x01, ++ 0x8F,0x03,0xB9,0xFF,0xF9,0x57,0x34,0x0A,0x56,0x5A,0xCB,0x01,0x40,0x32,0x83,0x1F, ++ 0xD0,0x9F,0x04,0x11,0x88,0x03,0x01,0x01,0x86,0x0F,0xC8,0xF7,0xBC,0xFF,0xFF,0xFF, ++ 0xE8,0x85,0xA8,0x85,0x41,0xB2,0xC2,0x01,0xC8,0x03,0x42,0x01,0x8A,0x36,0x40,0xA2, ++ 0xC0,0x01,0xEF,0x03,0x40,0x29,0xC8,0x0E,0xBE,0xFF,0xF7,0x8F,0x61,0x82,0xC2,0x03, ++ 0x38,0x00,0xA8,0x0E,0xBE,0xFF,0xF7,0xAF,0xC3,0x03,0xC3,0x03,0x08,0xE9,0x07,0x42, ++ 0x82,0x03,0x43,0xD2,0xC0,0x03,0x40,0x01,0x80,0x16,0x80,0x0F,0xE7,0x9F,0x3E,0xE7, ++ 0xE8,0x85,0xA8,0x85,0x48,0x3A,0x02,0x01,0x02,0x43,0x4C,0x2A,0xCC,0x01,0xB7,0x43, ++ 0xF0,0x43,0x86,0x0F,0xC8,0xCF,0xEE,0x85,0xA8,0x85,0x33,0x2A,0x48,0x01,0x80,0x56, ++ 0x68,0x01,0x80,0x1E,0x30,0x82,0xC0,0x51,0x20,0xF1,0x00,0x67,0x30,0x82,0x80,0x51, ++ 0x27,0xE9,0x18,0x22,0x00,0x3F,0x68,0x01,0x84,0x1E,0xF0,0x80,0x27,0x89,0x18,0x22, ++ 0x04,0x0F,0xE0,0x80,0x20,0x61,0x08,0x01,0xF0,0x0A,0x4A,0x01,0xD2,0x06,0x10,0x4A, ++ 0x08,0x40,0x0E,0x01,0xF0,0x8A,0x82,0x27,0xDB,0xAF,0x42,0xF9,0xEB,0x06,0x00,0xF9, ++ 0x68,0x01,0x80,0x16,0x08,0xF9,0x8F,0x09,0xD0,0x40,0xC8,0x00,0xEF,0x85,0xAB,0x85, ++ 0x80,0x3D,0x2C,0x01,0x20,0x01,0x00,0x51,0x4B,0x9A,0x19,0x42,0xC0,0x00,0x82,0x34, ++ 0xC3,0x34,0x00,0x08,0x12,0x39,0xC1,0x00,0x0C,0x90,0xC4,0x10,0x00,0xE1,0x90,0x2C, ++ 0xF0,0x82,0x80,0x24,0x30,0x01,0x38,0x01,0x10,0x01,0x90,0x1C,0x90,0x14,0x60,0x01, ++ 0x83,0x46,0xF0,0x10,0xDA,0x34,0x00,0x90,0xC1,0xD0,0x1C,0x39,0x0E,0xD8,0xC4,0x90, ++ 0x34,0xE1,0xF8,0xB2,0x68,0x01,0x80,0x56,0xF0,0x50,0x1B,0x51,0x19,0xD2,0x5A,0x12, ++ 0xC1,0x90,0x1E,0x39,0xC4,0x90,0x0A,0xD8,0xC0,0x90,0x3E,0xE1,0xF8,0xBA,0x66,0x21, ++ 0x83,0x4E,0xE0,0x18,0xD2,0x34,0x00,0xD8,0xC1,0x90,0x1E,0x39,0x0E,0xD8,0xC4,0x90, ++ 0x1E,0xE1,0xF0,0x9A,0x98,0x1C,0x68,0x69,0x83,0x5E,0xE0,0x50,0x1A,0x51,0x18,0xD2, ++ 0x5E,0xAA,0xC0,0x90,0xC1,0x88,0x12,0x39,0x0C,0x90,0xC4,0x50,0x0A,0xE1,0xF0,0x8A, ++ 0x88,0x14,0x08,0x09,0x89,0x0C,0x70,0x29,0xD1,0x3E,0x78,0x29,0xD0,0x2E,0xC8,0x1C, ++ 0x48,0x29,0xD1,0x16,0xC9,0x14,0x48,0x29,0xD8,0x0E,0x08,0x01,0x88,0x0C,0x00,0xFF, ++ 0x08,0x00,0x00,0x01,0x10,0x00,0x00,0x42,0xF8,0x00,0x06,0x42,0x80,0x50,0x02,0x01, ++ 0x18,0x00,0x02,0x42,0x80,0x60,0x05,0x00,0x10,0x18,0x02,0x00,0x70,0x20,0x04,0x01, ++ 0xF8,0xFF,0x07,0x00,0x80,0x70,0x06,0x01,0x08,0x60,0x00,0x01,0x60,0x20,0x02,0x00, ++ 0x00,0x70,0x00,0x01,0x00,0x28,0x00,0x01,0x80,0xE0,0x04,0x01,0x00,0x20,0x00,0x01, ++ 0x08,0x19,0x80,0x27,0xD5,0x7F,0x16,0x82,0xED,0x3E,0x10,0xC2,0xE8,0x2E,0xC8,0x1C, ++ 0x10,0x42,0xEC,0x16,0xCC,0x14,0x10,0x42,0xE0,0x0E,0x00,0x01,0x80,0x0C,0xC0,0x0C, ++ 0x40,0x01,0x80,0x86,0xC8,0x24,0xD0,0x2C,0x7A,0x40,0xC6,0x00,0x80,0x00,0xD2,0x48, ++ 0x94,0x4D,0x18,0x8C,0x50,0xFA,0xC7,0x93,0x58,0xFA,0xC7,0xDB,0x18,0xD2,0x80,0x16, ++ 0xD0,0x40,0xC8,0x2C,0x1B,0x44,0xE4,0x20,0x90,0x25,0x67,0x29,0x93,0x06,0x38,0x3F, ++ 0xE7,0x68,0x93,0x6D,0x68,0x71,0x90,0x06,0x38,0xE7,0x82,0x3D,0xEF,0x85,0xAF,0xC5, ++ 0x2F,0x01,0x40,0xB2,0xF8,0x03,0x80,0x04,0x00,0x5F,0x01,0x31,0x4B,0xA2,0x1F,0x42, ++ 0xC1,0x00,0x0A,0xC9,0x0A,0x48,0xC4,0x30,0x3F,0x11,0xF8,0xBA,0x01,0x21,0xF0,0x82, ++ 0x40,0x51,0xD0,0x0E,0x20,0x51,0x00,0x0F,0xC0,0x51,0x90,0x25,0x04,0x19,0x06,0x00, ++ 0x10,0x22,0xEC,0x06,0x31,0x22,0x30,0x02,0xC4,0xF9,0xC7,0x89,0x0A,0xF1,0x18,0x42, ++ 0x0C,0xF9,0x8F,0x89,0x83,0x27,0xD0,0xF7,0xC8,0x00,0x90,0x05,0x40,0x51,0xD0,0x06, ++ 0x07,0x51,0x48,0x22,0x10,0x42,0xEC,0x06,0x33,0x42,0x00,0xBC,0x03,0x84,0xE5,0x68, ++ 0x90,0x6D,0xC7,0x04,0x16,0x42,0xC5,0x86,0xEF,0xC5,0xAF,0x85,0x87,0x2D,0x04,0xF9, ++ 0x80,0x0C,0x00,0x01,0x80,0x04,0x80,0x14,0x52,0xCA,0x06,0x08,0x1C,0x39,0xC1,0x48, ++ 0x0E,0xD8,0xC4,0x68,0x0B,0xE1,0xF0,0x4A,0x27,0x39,0x19,0x22,0xE0,0x00,0x92,0x05, ++ 0x47,0x31,0xDA,0x96,0x38,0x01,0x00,0x01,0x30,0x01,0x20,0x01,0x29,0xF9,0x37,0xCA, ++ 0x12,0x51,0x18,0x8A,0x54,0x72,0xC6,0x48,0x54,0x7A,0xC6,0x58,0x98,0x24,0x10,0x01, ++ 0x0A,0x01,0xF0,0xCA,0x48,0xA1,0xE8,0x0E,0xE1,0xB0,0x93,0xB5,0xC0,0x40,0x90,0x05, ++ 0x10,0x0A,0xED,0x06,0x35,0x62,0x10,0x4A,0xD0,0x06,0x30,0x6A,0xE2,0xD8,0xE4,0x90, ++ 0x90,0x95,0x56,0x29,0x99,0x66,0x67,0xE1,0xEE,0x16,0x50,0x02,0x0C,0x01,0xA8,0x8B, ++ 0x08,0x29,0x80,0x27,0xD0,0x7F,0x91,0x0D,0xD0,0x00,0x83,0x71,0x40,0xE1,0xC0,0x6E, ++ 0xD0,0x40,0x83,0x71,0x40,0xE1,0xC0,0x4E,0x60,0xE1,0xE9,0x3E,0x70,0x21,0xE8,0x2E, ++ 0x50,0xAA,0x05,0x01,0x85,0x83,0x50,0x9A,0x00,0xD1,0x87,0x83,0xC4,0x14,0x10,0x42, ++ 0xD0,0x06,0x88,0x14,0xC5,0x0C,0x10,0x42,0xE8,0x06,0xA8,0x0C,0xC5,0x04,0x10,0x02, ++ 0xD0,0x06,0xA0,0x04,0x68,0x82,0xC5,0x24,0x18,0x01,0x48,0x01,0xE8,0xDE,0x10,0x01, ++ 0xF4,0x12,0x14,0x52,0xDD,0x96,0x60,0x3A,0xC0,0x23,0x61,0x01,0x86,0x2E,0x78,0x60, ++ 0xC3,0x20,0x83,0x20,0xD8,0x90,0x00,0x14,0x01,0xCF,0x50,0xE1,0xD6,0xBE,0xB8,0x60, ++ 0x7B,0x20,0xC5,0x20,0x80,0x20,0xDD,0x90,0x00,0x14,0x00,0x87,0x50,0x01,0xE8,0x76, ++ 0x10,0x09,0x00,0x14,0x00,0x5F,0x10,0x01,0xF4,0x12,0x14,0x52,0xE2,0x16,0xD0,0x90, ++ 0x00,0x14,0x00,0x27,0x50,0x01,0xD0,0x16,0x16,0x01,0x18,0x92,0x04,0x14,0xE0,0x00, ++ 0xE6,0xD8,0x92,0xDD,0x5E,0x29,0x98,0x86,0xE6,0xC0,0x93,0x3D,0x7C,0x71,0x98,0x16, ++ 0x44,0x82,0x4C,0x8A,0xC0,0x03,0xC0,0x4B,0x34,0x22,0x78,0xA2,0x19,0x62,0x88,0xCE, ++ 0x01,0x01,0x30,0xDA,0x7A,0x72,0x04,0x10,0xCC,0x88,0x56,0x7A,0xC4,0x50,0x64,0x72, ++ 0xA0,0x51,0xC8,0x68,0x21,0xF9,0x0C,0x20,0xC8,0x60,0x30,0x01,0xF8,0x32,0x25,0x01, ++ 0xFD,0x62,0x11,0x32,0xD0,0x3E,0x28,0x01,0xF8,0xAA,0x6A,0xA1,0xE8,0x1E,0x60,0x79, ++ 0xEB,0x0E,0x00,0x60,0x04,0xA4,0x50,0x2A,0x94,0x51,0xC0,0x50,0xC4,0x68,0x66,0x1A, ++ 0xE0,0x51,0xC8,0x48,0x30,0x01,0x20,0x01,0xF9,0x72,0xFC,0x62,0x10,0x32,0xD5,0x66, ++ 0x0A,0x01,0xF0,0x8A,0x48,0xA1,0xE8,0x46,0x60,0x79,0xE8,0x36,0x7B,0x68,0xC6,0x60, ++ 0x83,0x20,0x03,0x28,0xCB,0x20,0xC3,0x08,0x02,0x8C,0xE0,0x00,0x90,0x05,0x46,0x29, ++ 0x99,0x4E,0x06,0xCF,0x41,0x01,0x80,0xBE,0x23,0x01,0x40,0x8A,0x00,0x08,0xC3,0x68, ++ 0x41,0x8A,0xC3,0x70,0x40,0x82,0x83,0x51,0xC4,0x40,0x09,0xF9,0x0B,0x48,0xC0,0x78, ++ 0x10,0x01,0x08,0x01,0xF2,0xD2,0xF5,0x0A,0x10,0x52,0xD4,0x6E,0x01,0x01,0xF0,0x82, ++ 0x81,0x1C,0x40,0x41,0xE8,0x46,0x48,0x79,0xEC,0x36,0x00,0x00,0x08,0x29,0x80,0x27, ++ 0xC8,0xCF,0xCB,0x1C,0xC1,0x00,0x02,0x84,0x40,0x22,0x83,0x51,0xC3,0x40,0x49,0x1A, ++ 0xCB,0x51,0xC0,0x50,0x18,0x01,0x08,0x01,0xF2,0xDA,0xF7,0x8A,0x10,0x5A,0xD4,0x3E, ++ 0x14,0x01,0xF0,0x12,0x50,0x41,0xE9,0x1E,0x48,0x79,0xE8,0x0E,0x00,0x88,0x02,0x0C, ++ 0xE7,0x20,0x93,0x25,0x66,0x29,0x98,0x46,0x00,0x01,0x08,0x01,0x2A,0x99,0x60,0xA2, ++ 0x1A,0x6A,0x5F,0xBA,0x02,0x70,0x03,0x50,0x38,0x39,0xC9,0x90,0x0E,0xF8,0xCD,0xB8, ++ 0x15,0xE1,0xF0,0xD2,0x10,0x52,0xD5,0x2E,0xE4,0x00,0x92,0x05,0x10,0x92,0xD5,0x0E, ++ 0xE4,0x00,0x96,0x05,0x50,0x81,0xEA,0x2E,0x08,0x01,0x80,0xCB,0x02,0x01,0x50,0x6A, ++ 0x00,0x8C,0x00,0x1F,0xE0,0x48,0x92,0x4D,0x4F,0x31,0xDA,0x26,0x4F,0x1A,0x8A,0x01, ++ 0x40,0x29,0xC8,0x6E,0xC0,0xC3,0x40,0xF1,0x92,0x1E,0xE0,0x00,0x80,0xC3,0x80,0x2D, ++ 0xE8,0x85,0xC7,0x43,0x10,0x09,0x18,0x82,0x80,0x43,0x00,0x01,0x87,0xC3,0x38,0xB7, ++ 0xC0,0xC3,0x40,0x01,0x82,0x0E,0xF0,0x00,0x81,0xC3,0x50,0xF2,0x40,0x84,0x40,0xF1, ++ 0xC8,0x6E,0xC7,0x43,0x18,0x09,0x18,0xC2,0x80,0x43,0x00,0x01,0x07,0x84,0x38,0x37, ++ 0xA9,0xC5,0x47,0x92,0x17,0x09,0x80,0x01,0xC0,0x0B,0x18,0x8A,0x81,0x0B,0x68,0x7A, ++ 0x79,0x62,0x31,0x62,0xA4,0x01,0x06,0x3F,0xBC,0xFF,0xEF,0x5F,0x48,0x92,0x41,0x43, ++ 0xE0,0x00,0x02,0x43,0x40,0x8A,0xC1,0x03,0x40,0x01,0x80,0x0E,0x05,0xC1,0xB0,0x43, ++ 0x40,0x32,0x81,0x1F,0xE9,0xA7,0x51,0x72,0x49,0x2A,0x41,0x22,0x86,0x1F,0xC8,0xFF, ++ 0xB9,0xFF,0xEF,0xDF,0x01,0x11,0x88,0x03,0x51,0x4A,0x49,0x02,0x40,0x02,0x81,0x1F, ++ 0xD9,0xF7,0x55,0x3A,0x48,0xEA,0x40,0xF2,0x86,0x1F,0xF8,0xA7,0xC8,0x03,0x43,0x01, ++ 0x83,0x16,0xC8,0x03,0x40,0x11,0x88,0x26,0x48,0x12,0x41,0x43,0x10,0x09,0x18,0x82, ++ 0x00,0x43,0x48,0xB2,0x40,0xB2,0x80,0x1F,0xF0,0x07,0x74,0x9A,0xC1,0xCB,0xC1,0x83, ++ 0x18,0x42,0x80,0x0E,0x05,0x01,0xA8,0x43,0xBB,0xFF,0xF7,0x3F,0x41,0xD2,0xC0,0x8B, ++ 0x09,0x0C,0xC6,0xCB,0x11,0x0C,0xC8,0x4B,0x10,0x0C,0x72,0x62,0xB5,0x01,0xE2,0x8B, ++ 0x10,0x0C,0x4C,0xB2,0x46,0x4C,0x10,0x0C,0x48,0x7A,0x40,0x4B,0x18,0x0C,0xA0,0x48, ++ 0x1D,0x0C,0xEA,0x4B,0x1F,0x0C,0xBC,0xFF,0xE8,0x97,0x03,0x11,0xA0,0x83,0x4D,0x1A, ++ 0x40,0x1A,0x00,0xEF,0x00,0x48,0x00,0x01,0x00,0x40,0x00,0x01,0x00,0x00,0x01,0x01, ++ 0x08,0x60,0x00,0x01,0x18,0x10,0x00,0x00,0x48,0xE0,0x06,0x00,0x50,0xA0,0x02,0x00, ++ 0x00,0x58,0x00,0x01,0x00,0x80,0x00,0x01,0x00,0xC0,0x00,0x01,0x00,0x20,0x00,0x01, ++ 0x80,0xE0,0x04,0x01,0xF8,0x00,0x06,0x42,0x70,0x60,0x04,0x01,0x00,0x70,0x00,0x01, ++ 0x82,0x1F,0xE8,0x47,0x30,0x8A,0x11,0x09,0xC8,0x01,0x42,0x52,0x58,0x52,0x80,0x17, ++ 0xEF,0x7F,0xB9,0xFF,0xD9,0xEF,0x34,0x8A,0xC8,0x01,0x42,0x32,0x83,0x0F,0xF0,0x87, ++ 0x82,0x07,0xD8,0xE7,0xBF,0xFF,0xE7,0x2F,0xC8,0x03,0x43,0x31,0x83,0x06,0x38,0x9F, ++ 0xE8,0xC5,0x07,0x00,0x08,0x60,0x00,0x01,0x30,0x58,0x00,0x00,0xA8,0x85,0x33,0x22, ++ 0xF0,0x03,0x87,0x07,0xF2,0xCF,0x46,0x7A,0x2C,0x01,0x00,0x2B,0xB6,0x2B,0x05,0x21, ++ 0xAF,0x2A,0xB8,0xFF,0xE5,0x57,0xA2,0x01,0xCA,0x03,0x33,0x08,0x42,0x52,0x72,0x48, ++ 0x1C,0x0B,0x5C,0x0B,0x02,0x48,0x1A,0x0B,0x0B,0x2B,0xCE,0x0B,0x30,0x48,0xA8,0x16, ++ 0x0E,0x09,0x04,0x0B,0x1B,0x2B,0xE8,0x85,0xAD,0x85,0x87,0xAD,0x42,0x12,0xC2,0x01, ++ 0x42,0x0B,0x40,0x48,0x00,0x48,0x02,0x0B,0x52,0x02,0x4A,0x0A,0x40,0x0A,0x82,0x0F, ++ 0xCA,0x77,0x41,0x0A,0x71,0xFA,0xC1,0x80,0x81,0xA4,0x41,0xEA,0xB6,0xE1,0x81,0x01, ++ 0x83,0x9C,0x01,0x47,0x47,0xD2,0xB9,0xFF,0xF9,0x4F,0x66,0xCA,0x52,0x03,0x83,0x01, ++ 0xE7,0x03,0x40,0x79,0x81,0x06,0x31,0x12,0x48,0xB2,0x01,0x01,0x58,0x9A,0x81,0x07, ++ 0xF9,0x1F,0x37,0x12,0x48,0x9A,0x01,0x09,0x58,0x82,0x81,0x07,0xFB,0xEF,0x56,0x03, ++ 0x80,0x01,0xE2,0x03,0x40,0x59,0x8D,0x7E,0xC1,0xA4,0x31,0x8A,0x13,0x01,0xD8,0x1B, ++ 0xDB,0x2B,0x19,0x5A,0x40,0x6C,0x40,0x3C,0xD8,0x68,0x07,0x2C,0xE4,0x00,0xE4,0x48, ++ 0xE4,0x90,0x92,0x95,0x17,0xD2,0x9C,0xAE,0x52,0x03,0x83,0x01,0xE5,0x03,0x40,0x59, ++ 0x81,0x2E,0x50,0x12,0x49,0x12,0x41,0x1A,0x58,0x0D,0x80,0x0F,0xC1,0xC7,0xEC,0xA4, ++ 0x30,0xA2,0x39,0x01,0x01,0x01,0xF0,0x42,0x0A,0x99,0x18,0x42,0x08,0x51,0x80,0x27, ++ 0xC1,0x4F,0x00,0x44,0x01,0x01,0xF0,0x02,0x0A,0x99,0x18,0x42,0x08,0x51,0x80,0x27, ++ 0xC1,0x0F,0x00,0x04,0xE5,0x68,0xE5,0x20,0xE7,0xF8,0x93,0xFD,0x7F,0x29,0x98,0x4E, ++ 0x68,0xB2,0x60,0xA2,0xA0,0xF1,0x3D,0x01,0x01,0x01,0xF0,0x42,0x08,0x51,0x08,0x00, ++ 0x87,0x1F,0xF8,0x87,0x00,0x44,0x01,0x01,0xF0,0x02,0x09,0x51,0x08,0x00,0x80,0x1F, ++ 0xF9,0x4F,0x07,0x04,0xE5,0x68,0xE5,0x20,0xE7,0xF8,0x93,0xFD,0x7F,0x29,0x98,0x5E, ++ 0x40,0x0D,0x80,0x07,0xD9,0xE7,0xC2,0x9C,0xC8,0x03,0x42,0x31,0x81,0x96,0x84,0xAD, ++ 0xE8,0x85,0x07,0x00,0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x80,0xE0,0x04,0x01, ++ 0x00,0x00,0x01,0x01,0x08,0x60,0x00,0x01,0x48,0xE0,0x06,0x00,0x58,0x50,0x03,0x01, ++ 0x48,0xFA,0xFF,0x53,0x84,0x13,0xF8,0x53,0x80,0x13,0x32,0x52,0x96,0x01,0xCE,0x93, ++ 0x80,0x13,0xCC,0x4B,0x83,0x0B,0x3E,0x82,0xA8,0xF5,0x37,0x2A,0x46,0xC2,0xFF,0x03, ++ 0x12,0x42,0xCD,0xBE,0x07,0x21,0x61,0xBA,0x18,0x42,0xCB,0x20,0x02,0x99,0x0B,0x00, ++ 0xC0,0x20,0x39,0xA1,0xF8,0x3A,0x37,0xB1,0xF8,0x32,0x9D,0x0C,0x48,0x09,0x88,0x1E, ++ 0x07,0xF9,0x87,0x09,0xD8,0x00,0x96,0x3D,0x50,0x09,0x88,0x1E,0x02,0xC9,0x08,0x00, ++ 0xD8,0x00,0x94,0x35,0xC8,0x03,0x85,0x04,0x06,0x81,0xDF,0x00,0x0A,0x51,0x1B,0x42, ++ 0x08,0x81,0x87,0x1F,0xFE,0xBF,0xCC,0x00,0x93,0x05,0x40,0x51,0xD3,0x06,0x00,0x51, ++ 0x0B,0xF9,0x8F,0xB9,0x10,0x42,0xEC,0x06,0x30,0x42,0xC8,0x04,0xC8,0x13,0x0F,0x48, ++ 0x00,0x90,0x1A,0x8A,0xD0,0x0C,0x80,0x8B,0xF8,0x0C,0x88,0x08,0x81,0xCB,0x8B,0x88, ++ 0x81,0xCB,0x3D,0x88,0x08,0x00,0x78,0x48,0x1F,0x42,0x80,0xC3,0xE3,0xF8,0xE7,0xF8, ++ 0x58,0x04,0x09,0xA1,0x83,0x1F,0xF8,0x67,0x86,0x51,0x90,0x05,0x40,0xF9,0x97,0x56, ++ 0x5A,0xAA,0xEE,0xCA,0x30,0x52,0x90,0x51,0x10,0x12,0x94,0x16,0x82,0xC3,0xA9,0xC2, ++ 0x01,0x1F,0x80,0xCB,0x07,0x0F,0x00,0xF9,0x80,0xC3,0xC1,0x44,0xC8,0x44,0xC0,0x03, ++ 0xE8,0x00,0x82,0x43,0xEF,0xF5,0xAF,0x85,0x80,0x2D,0x34,0x01,0x00,0x5D,0x46,0x03, ++ 0x86,0x14,0x40,0x3A,0xF8,0x1B,0x14,0x09,0x06,0x01,0x48,0x4A,0x60,0x4A,0xC6,0x6B, ++ 0x68,0x59,0x85,0x16,0xE5,0x00,0x12,0x02,0x9F,0xCE,0x07,0xF9,0x80,0x43,0x58,0x01, ++ 0x80,0xBE,0x30,0x01,0x48,0x15,0x00,0x01,0x25,0x99,0x5B,0xF2,0x08,0x20,0x03,0x77, ++ 0x2A,0x21,0x19,0x2A,0xC1,0x68,0xCF,0x68,0xD0,0x6B,0x69,0x09,0x88,0x2E,0x80,0x43, ++ 0xE7,0xB0,0x93,0xB5,0xE0,0x48,0x72,0x09,0x82,0x1E,0xE0,0x00,0x94,0x05,0x16,0x82, ++ 0x98,0x76,0x77,0x01,0x80,0x3E,0x73,0x09,0xCD,0x16,0x48,0xBA,0x00,0x09,0x80,0x43, ++ 0x60,0x9A,0x6D,0x15,0x3D,0x01,0x40,0x72,0x80,0x01,0x87,0x1C,0x00,0x0F,0x79,0x01, ++ 0x88,0x9E,0x50,0x0D,0x90,0x04,0x10,0x01,0xC1,0x43,0x31,0x1A,0x37,0x8A,0xB8,0xFF, ++ 0xFB,0xDF,0xE2,0x68,0xC4,0x1C,0xC0,0x03,0x4E,0x00,0x0E,0x00,0x1B,0x82,0x89,0x03, ++ 0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x4F,0x50,0x0D,0x90,0x04,0x10,0x01, ++ 0xC1,0x43,0x31,0x1A,0x37,0x8A,0xB8,0xFF,0xFB,0x3F,0xE2,0x68,0xEB,0x20,0xE3,0xF8, ++ 0x95,0xFD,0x17,0xBA,0x98,0xDE,0xC6,0x1C,0x1C,0x01,0xC4,0x03,0x48,0x08,0x4E,0x01, ++ 0x80,0x9E,0x70,0x01,0x81,0x3E,0x80,0x03,0xC0,0x1C,0xC8,0x03,0x85,0x03,0x03,0x59, ++ 0x85,0x03,0xE5,0x20,0x01,0x3F,0x80,0x03,0xC0,0x1C,0xC8,0x03,0x83,0x03,0x8B,0x1B, ++ 0x05,0x59,0x8D,0x03,0xEB,0x20,0xE5,0x20,0x00,0x27,0x70,0x09,0xCD,0x16,0x00,0x59, ++ 0x83,0x03,0xE1,0x20,0x37,0x02,0xB9,0xFF,0xFC,0x9F,0x40,0x82,0x42,0x0B,0x12,0x01, ++ 0x1A,0x8A,0x00,0x0B,0x42,0x72,0x44,0x0B,0x1A,0xCA,0x00,0x0B,0x61,0x6A,0x44,0x03, ++ 0x42,0x00,0x02,0x00,0x07,0x03,0x01,0xF9,0x80,0x89,0x84,0x1F,0xE9,0x4F,0x46,0x03, ++ 0x08,0x09,0x18,0x42,0x00,0x03,0x81,0x2D,0xEF,0x85,0xAF,0xFD,0x80,0x0D,0xFC,0x54, ++ 0x30,0x32,0x30,0x62,0x6F,0xD2,0xAB,0x01,0x50,0x09,0x88,0x4E,0x00,0x0F,0x80,0x0F, ++ 0xC1,0x4F,0xC0,0x43,0x37,0x00,0xAA,0xD6,0xC5,0x43,0x09,0xF9,0x01,0x42,0x80,0x43, ++ 0x04,0x09,0x30,0x22,0x51,0xD2,0x03,0x8F,0x60,0x01,0xC1,0x2E,0xF7,0x00,0x0B,0x01, ++ 0x1A,0x42,0x08,0x83,0x30,0x0A,0x01,0x17,0x02,0xF9,0x0F,0x83,0x08,0x01,0x19,0x01, ++ 0x08,0x9B,0x04,0x01,0x00,0x4F,0x78,0x01,0x88,0x16,0x18,0x01,0x00,0x9B,0x06,0x17, ++ 0xC6,0x9B,0x01,0x9B,0xCA,0xB0,0xE7,0x00,0x94,0x05,0x14,0x42,0x9B,0x9E,0x37,0x02, ++ 0x40,0x01,0x80,0x26,0x04,0xA1,0x00,0x83,0x04,0x01,0x30,0x22,0x00,0x0F,0x00,0x21, ++ 0x03,0x83,0xD4,0x00,0x92,0x25,0x44,0x83,0x08,0x01,0x1C,0x42,0x01,0x83,0xC2,0x43, ++ 0x37,0x00,0xAA,0xE6,0xC5,0x43,0x09,0xF9,0x01,0x42,0x80,0x43,0x66,0x01,0x88,0x5E, ++ 0xC0,0x24,0x40,0x09,0x88,0x7E,0x05,0x01,0x02,0x83,0x44,0x83,0x08,0x01,0x1C,0x42, ++ 0x05,0x83,0x3A,0x47,0xAC,0x9D,0x87,0x1D,0x20,0x01,0x00,0x01,0x80,0x0C,0x70,0x15, ++ 0x44,0x7A,0xF2,0x03,0xEE,0x00,0x92,0x3D,0x6F,0x6A,0xAA,0x01,0x00,0xAF,0x81,0x07, ++ 0xF9,0x8F,0xC5,0x43,0x30,0x00,0xA2,0x1E,0x44,0x4A,0xF2,0x03,0x17,0xC2,0x9D,0xB6, ++ 0x44,0x3A,0xF2,0x03,0x10,0xC2,0x9D,0x06,0x21,0x11,0xC0,0x43,0x08,0xF9,0x05,0x42, ++ 0x82,0x43,0x41,0x5A,0x46,0x0B,0x14,0x79,0x00,0x8A,0x48,0x09,0x88,0x9E,0x08,0x01, ++ 0x0E,0x0B,0x44,0x0B,0x83,0x8B,0xE1,0xB0,0xE7,0x20,0x93,0x25,0x60,0x11,0x88,0x56, ++ 0x30,0x5A,0xD3,0xCB,0xD4,0x1C,0x10,0x8A,0x8A,0x2E,0xD0,0xCB,0xD4,0x24,0x10,0x8A, ++ 0x88,0x0E,0x08,0x09,0x8F,0x0C,0x08,0x01,0x08,0x0B,0x0A,0x01,0x08,0x0B,0x0C,0x81, ++ 0x02,0x0B,0x44,0x0B,0x10,0x01,0x1C,0x8A,0x00,0x0B,0x62,0x11,0x88,0x4E,0xC6,0x0C, ++ 0x39,0x0F,0x4B,0x7A,0x60,0x54,0x80,0x13,0x12,0x01,0x80,0x13,0xE4,0x4B,0x86,0x0B, ++ 0x4A,0xA2,0x89,0x01,0x5E,0x53,0x84,0x13,0x58,0x53,0x8A,0x13,0x12,0x21,0x89,0x13, ++ 0x14,0x19,0x88,0x13,0x4E,0x53,0x8E,0x13,0x48,0x53,0x94,0x13,0x4A,0x4B,0x92,0x0B, ++ 0x0C,0x31,0x90,0x0B,0x3F,0x82,0xAB,0x85,0x80,0x4D,0x34,0x22,0x30,0x01,0x00,0x01, ++ 0x80,0x2C,0x38,0x01,0x48,0xF2,0xD8,0x43,0xDA,0x4B,0x1A,0x42,0x80,0x14,0x40,0xEA, ++ 0x80,0x71,0x80,0x24,0xC0,0x71,0x80,0x1C,0x60,0x09,0x80,0x0E,0x60,0x29,0x88,0x7E, ++ 0x60,0x09,0x88,0x26,0x73,0x02,0xE1,0x80,0x81,0x2C,0x78,0x02,0x01,0x27,0x70,0x02, ++ 0xE0,0x80,0x83,0x2C,0x79,0xEA,0xF8,0xC1,0x47,0x35,0xB8,0xFF,0xF0,0x0F,0x01,0x3F, ++ 0x60,0x21,0x88,0x2E,0x70,0xDA,0x40,0x35,0xBD,0xFF,0xFF,0xDF,0x7B,0xBA,0xB8,0x11, ++ 0x6F,0x5A,0xA8,0x01,0xC5,0x43,0x09,0xF9,0x01,0x42,0x80,0x43,0xC1,0x43,0x09,0x01, ++ 0x19,0x42,0x80,0x43,0x42,0x6A,0x40,0x0B,0x10,0x01,0x1A,0x8A,0x00,0x0B,0x42,0x62, ++ 0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x48,0x52,0x40,0x43,0x10,0x09,0x00,0xDF, ++ 0x00,0x00,0x01,0x01,0x08,0x60,0x00,0x01,0x80,0x20,0x06,0x01,0x00,0xF8,0x07,0x00, ++ 0x80,0x50,0x02,0x01,0x30,0x04,0x05,0x08,0x00,0x60,0x00,0x01,0x00,0x00,0x06,0x42, ++ 0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42,0x18,0x80,0x05,0x01,0x70,0x90,0x06,0x01, ++ 0x50,0x40,0x07,0x01,0x68,0x80,0x02,0x01,0x18,0x82,0x00,0x43,0x0C,0x09,0x00,0x01, ++ 0xB9,0xFF,0xFF,0xC7,0x43,0x09,0x88,0x2E,0x61,0x21,0x88,0x7E,0x10,0x09,0x90,0x04, ++ 0x30,0x82,0x19,0x01,0xCF,0x14,0xB8,0xFF,0xF0,0xC7,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x59,0x40,0x35,0x37,0x9A,0xB8,0xFF,0xF0,0x87,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x09,0x29,0x30,0xC2,0x37,0x9A,0xB8,0xFF,0xF0,0x47,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x0E,0x71,0x40,0x1A,0x37,0x9A,0xB8,0xFF,0xF0,0x07,0x16,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x29,0x30,0x9A,0xC7,0x24,0xB8,0xFF,0xF0,0xC7,0x15,0x09,0x90,0x04,0x10,0x01, ++ 0x08,0x29,0x18,0x09,0xC7,0x1C,0xB8,0xFF,0xF1,0x87,0x05,0x9F,0x60,0x09,0x80,0x0E, ++ 0x61,0x29,0x88,0x7E,0x10,0x11,0x90,0x04,0x11,0x09,0x30,0x82,0x18,0x01,0xC8,0x14, ++ 0xBD,0xFF,0xF7,0x1F,0x10,0x11,0x90,0x04,0x10,0x01,0x30,0x9A,0xC8,0x14,0xC0,0x2C, ++ 0xBC,0xFF,0xF7,0xDF,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x21,0x40,0x35,0x30,0x9A, ++ 0xBC,0xFF,0xF7,0x9F,0x10,0x09,0x90,0x04,0x11,0x01,0x08,0x31,0x30,0xC2,0x31,0x9A, ++ 0xBC,0xFF,0xF7,0x5F,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x29,0x30,0x9A,0xC0,0x24, ++ 0xBC,0xFF,0xF7,0x1F,0x10,0x09,0x90,0x04,0x10,0x01,0x08,0x29,0x18,0x09,0xC0,0x1C, ++ 0xBB,0xFF,0xF7,0xDF,0xC6,0x43,0x09,0xF9,0x01,0x42,0x80,0x43,0x40,0xEA,0x44,0x0B, ++ 0x42,0x48,0x02,0x48,0x04,0x0B,0x40,0xE2,0x0A,0x01,0x0F,0x0B,0x0C,0x01,0x00,0x0B, ++ 0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0x87,0x4D,0xE8,0x85,0xAC,0x85,0x63,0xBA, ++ 0xC8,0x03,0x2B,0x01,0x40,0x09,0x80,0x16,0xC8,0x03,0x43,0x29,0x8C,0x7E,0x40,0x9A, ++ 0xC0,0x01,0x86,0x1F,0xCC,0xA7,0x72,0x92,0xC0,0x83,0x41,0x11,0x9B,0x26,0xC8,0x03, ++ 0xB8,0xFF,0xFF,0x4F,0x83,0xAB,0xE9,0x85,0xE1,0x00,0x82,0x83,0xEB,0x85,0xCB,0x03, ++ 0x40,0x21,0x88,0x26,0xBF,0xFF,0xF7,0xFF,0x03,0x19,0x88,0x03,0xEB,0x85,0xCB,0x03, ++ 0x47,0x19,0x80,0xDE,0xC8,0x03,0x43,0x31,0x84,0xC6,0x47,0x22,0xC4,0x01,0xFE,0x03, ++ 0x40,0x01,0x88,0x3E,0x41,0x0A,0x84,0x01,0xD0,0x0B,0x48,0x31,0x9C,0x3E,0xC0,0x03, ++ 0x30,0x00,0xA8,0x26,0x44,0xEA,0xC3,0x01,0xE8,0x03,0x44,0x01,0x83,0x16,0x40,0xEA, ++ 0x83,0x2B,0xE8,0x85,0xBC,0xFF,0xEF,0x7F,0xEF,0x85,0xAB,0xC5,0x20,0x01,0x30,0x1A, ++ 0x03,0x09,0x48,0xB2,0x69,0xC2,0x33,0x01,0x59,0x51,0x80,0xE6,0xE3,0x4E,0x78,0xBA, ++ 0xC0,0xD3,0x81,0x1F,0xE8,0xB7,0x65,0x52,0x22,0x09,0x39,0x61,0x62,0x52,0x71,0x61, ++ 0x63,0x92,0x41,0x72,0x16,0x31,0xC0,0x01,0x52,0x03,0x82,0x01,0x59,0xC9,0x80,0xAE, ++ 0xE0,0x4E,0x58,0x59,0x80,0x56,0x59,0x61,0x80,0x66,0x59,0x69,0x88,0xBE,0x01,0x29, ++ 0x88,0x43,0x22,0x09,0x00,0x9F,0x59,0xD1,0x81,0x6E,0x59,0x01,0x8A,0x7E,0x89,0x53, ++ 0x25,0x09,0x08,0x59,0xA1,0x0B,0x00,0x57,0x02,0x39,0x88,0x43,0x00,0x3F,0x81,0x07, ++ 0xE9,0x5F,0x06,0x27,0x19,0x12,0x80,0xD3,0x00,0x0F,0x01,0x41,0x19,0x12,0x80,0xD3, ++ 0x00,0xEF,0x00,0x11,0x88,0x43,0x22,0x09,0x00,0xCF,0x00,0x01,0x89,0x43,0x42,0x43, ++ 0x19,0x82,0x01,0x43,0x02,0x9F,0x88,0x43,0x20,0x09,0x00,0x87,0x02,0x19,0x88,0x43, ++ 0x20,0x09,0x00,0x67,0x02,0x21,0x88,0x43,0x20,0x09,0x00,0x47,0x88,0x53,0x22,0x09, ++ 0x08,0x69,0xA6,0x0B,0x02,0x1F,0x88,0x53,0x27,0x09,0x08,0x79,0xA0,0x0B,0x60,0x01, ++ 0x82,0x66,0x40,0x7A,0x40,0x0B,0x30,0x48,0xAE,0x2E,0x08,0x81,0x02,0x0B,0x08,0x81, ++ 0x00,0x0B,0x08,0x81,0x01,0x0B,0x40,0x43,0x19,0x82,0x05,0x43,0xEF,0xC5,0xAF,0x8D, ++ 0x82,0x15,0x44,0x42,0x82,0x0C,0x40,0x0A,0xC0,0x01,0xDE,0x2B,0xD8,0x33,0x0A,0x01, ++ 0xB2,0x0B,0x64,0x12,0xC5,0x0B,0x11,0xF9,0x01,0x8A,0x80,0x0B,0xC1,0x0B,0x11,0x01, ++ 0x19,0x8A,0x80,0x0B,0x4E,0xF2,0x89,0x01,0x42,0x53,0x1A,0x01,0x1A,0xD2,0x00,0x53, ++ 0x52,0xAA,0x41,0x8B,0x18,0x01,0x1C,0xCA,0x01,0x8B,0x4A,0x92,0x40,0x53,0x18,0x09, ++ 0x18,0xD2,0x00,0x53,0x52,0x03,0x82,0x01,0xE7,0x0B,0x48,0x79,0x80,0xAE,0xE1,0x03, ++ 0x41,0x69,0x8E,0x16,0x08,0xA9,0x00,0x91,0xBF,0xFF,0xEF,0x27,0x41,0x09,0x88,0xDE, ++ 0x33,0x42,0x19,0x82,0x00,0x38,0x12,0x09,0x90,0xCD,0x95,0x04,0x18,0x01,0xC0,0x0C, ++ 0xBC,0xFF,0xEF,0x1F,0x40,0x62,0x11,0x09,0x90,0x04,0x10,0x01,0x90,0xCD,0x35,0x9A, ++ 0xBB,0xFF,0xEF,0xDF,0xC0,0x14,0x10,0x09,0xC8,0x48,0xED,0x48,0x92,0x04,0x00,0x48, ++ 0x10,0x01,0x18,0x09,0xBB,0xFF,0xEF,0x8F,0x00,0xF7,0x08,0xA1,0x07,0x91,0xB8,0xFF, ++ 0xE8,0x0F,0x46,0x09,0x8B,0xC6,0x18,0xAA,0x13,0x09,0x20,0x40,0x60,0x08,0x90,0x04, ++ 0x30,0x9A,0xC0,0x0C,0xBB,0xFF,0xEF,0x0F,0x00,0x77,0x08,0xB1,0x07,0x91,0xB8,0xFF, ++ 0xE8,0x8F,0x45,0x09,0x88,0x46,0xC0,0x14,0x15,0x09,0xC8,0x48,0xEA,0x48,0x00,0x48, ++ 0x30,0x9A,0x90,0x04,0xBA,0xFF,0xEF,0x8F,0xC6,0x03,0x09,0xF9,0x01,0x42,0x80,0x03, ++ 0x40,0x42,0x40,0x0B,0x42,0x48,0x02,0x48,0x00,0x0B,0x40,0x3A,0x0A,0x01,0x0F,0x0B, ++ 0x0C,0x01,0x00,0x0B,0x44,0x0B,0x12,0x01,0x1A,0x8A,0x00,0x0B,0xE8,0xF5,0x07,0x00, ++ 0x70,0x20,0x04,0x01,0xF8,0x00,0x06,0x42,0x80,0x01,0x06,0x42,0x00,0x00,0x07,0x01, ++ 0x00,0x00,0x00,0x01,0x00,0x60,0x00,0x01,0x10,0x00,0x00,0x42,0x08,0x00,0x00,0x01, ++ 0x00,0x00,0x00,0x42,0x50,0x40,0x07,0x01,0x08,0x40,0x02,0x01,0x52,0xE2,0x43,0x83, ++ 0x03,0x83,0x42,0xE2,0xF7,0x0B,0x4C,0xF9,0x94,0x16,0xF0,0x0B,0xE4,0x48,0xB2,0x0B, ++ 0xF0,0x03,0x44,0xC1,0x90,0x0E,0x00,0x01,0x03,0x83,0x3C,0x82,0x4C,0xB2,0x4B,0x53, ++ 0x5C,0xA2,0xE3,0xC3,0x1C,0x12,0x0C,0x53,0x10,0x43,0x02,0x09,0xB3,0xC3,0x3C,0x82, ++ 0xAB,0x85,0x40,0x8A,0x84,0x01,0x42,0x0B,0x10,0x01,0x1C,0x8A,0x03,0x0B,0x54,0x7A, ++ 0x4B,0x62,0x43,0x7A,0x86,0x1F,0xC0,0xC7,0xEF,0x85,0xA8,0xC5,0x47,0x4A,0x83,0x01, ++ 0xC3,0x0B,0x70,0x62,0x30,0x48,0xAC,0x46,0xC2,0x0B,0x10,0x01,0x18,0x8A,0x80,0x0B, ++ 0x44,0x83,0x0B,0x01,0x1B,0x42,0x04,0x83,0xE8,0xC5,0x0F,0x01,0x0D,0x8B,0x45,0x9B, ++ 0x66,0x02,0x03,0x79,0x01,0x1A,0x30,0x2A,0xAB,0x01,0x69,0x04,0x50,0x13,0x5B,0x09, ++ 0x80,0xE6,0x58,0x29,0x80,0x46,0x58,0x41,0x8B,0xB6,0x93,0x4B,0x46,0x9B,0x3F,0xD8, ++ 0x88,0x16,0x00,0x81,0x07,0x83,0xED,0xC5,0x0A,0x8B,0x4D,0xDA,0x10,0x42,0x8C,0x16, ++ 0x07,0x29,0x05,0x83,0x00,0x3F,0xE0,0x92,0x02,0x93,0xE7,0x00,0x93,0x05,0x2C,0x04, ++ 0x40,0x89,0x9A,0x06,0x28,0x0C,0x03,0xA1,0x07,0x83,0xED,0xC5,0x5B,0x9A,0xD2,0x7B, ++ 0x40,0xDC,0x78,0x11,0x90,0x56,0x7B,0x01,0x8F,0x36,0x40,0x83,0x50,0x7A,0x02,0x84, ++ 0x43,0x7A,0x12,0x03,0x2C,0x0C,0x03,0x1F,0x40,0x83,0x17,0xD0,0x48,0x5A,0xC2,0x80, ++ 0x90,0x3D,0x04,0x7C,0x00,0x89,0x16,0x00,0xD1,0xC0,0x41,0x01,0xC7,0x96,0x90,0xC5, ++ 0xBC,0xFF,0xF7,0x1F,0x44,0x3A,0x12,0x3A,0x82,0x96,0x43,0x32,0x84,0x41,0x10,0x3A, ++ 0x88,0x76,0x03,0x09,0x86,0x07,0xC8,0x47,0x05,0xC1,0xB0,0x03,0x40,0x12,0x0A,0x09, ++ 0x83,0x0B,0x00,0x2F,0x46,0xBA,0x81,0x01,0xC8,0x03,0x42,0x01,0x89,0x26,0x41,0xEA, ++ 0xC4,0x31,0x16,0x3A,0x89,0xAE,0x40,0xEA,0x41,0x0B,0x40,0xCA,0x72,0x50,0x80,0x01, ++ 0x80,0x13,0x60,0x50,0x80,0x13,0x52,0x50,0x86,0x13,0x84,0x0B,0xC2,0x0B,0xC0,0x13, ++ 0xC4,0x48,0xC4,0x13,0xC6,0x1B,0xC6,0x90,0xC5,0x48,0x8C,0x29,0x50,0x50,0x88,0x13, ++ 0x88,0x0B,0x02,0x69,0x19,0x00,0xD0,0xC0,0x40,0x81,0xC2,0x0E,0x29,0x04,0x03,0xFF, ++ 0x06,0x01,0x18,0x02,0x29,0x04,0x03,0xDF,0x41,0x6A,0xC1,0xC0,0x40,0x19,0xC1,0x26, ++ 0x29,0x04,0x43,0x62,0x11,0x03,0x03,0x9F,0x01,0xC7,0x41,0x4A,0xC1,0x81,0xC1,0xC0, ++ 0x40,0x01,0xC1,0x26,0x29,0x04,0x43,0x3A,0xC3,0x01,0x11,0x03,0x00,0x47,0x01,0x69, ++ 0x19,0x00,0xD0,0xC0,0x41,0xB1,0xC1,0x1E,0x29,0x04,0x03,0x0F,0x7D,0xD2,0x10,0xC2, ++ 0x87,0xF6,0x40,0xBB,0xA0,0xBA,0x40,0xDA,0xC4,0xD1,0x15,0x1A,0x8B,0x7E,0x68,0x04, ++ 0x40,0x61,0x8A,0x66,0x50,0x1B,0xE3,0xFA,0x52,0x72,0x90,0x01,0x78,0x01,0x8C,0x16, ++ 0x04,0x09,0xA8,0x83,0x00,0x1F,0xE0,0xC2,0x40,0x01,0x88,0x06,0xAB,0x8B,0x6C,0x04, ++ 0xE4,0x00,0x92,0x05,0x2A,0x04,0x43,0x89,0x98,0x16,0x00,0x01,0x1B,0x02,0x2E,0x04, ++ 0xD2,0x43,0xE3,0x00,0x90,0x43,0x03,0x81,0x07,0x83,0xED,0xC5,0x07,0x8B,0xED,0xC5, ++ 0x10,0x00,0x00,0x42,0x00,0x00,0x01,0x01,0xF8,0x00,0x06,0x42,0x80,0xE0,0x04,0x01, ++ 0x08,0x60,0x00,0x01,0x80,0x01,0x06,0x42,0xF8,0xFF,0x07,0x00,0x00,0x10,0x00,0x01, ++ 0x80,0x50,0x02,0x01,0x88,0x36,0x00,0x00,0x00,0x20,0x00,0x01,0x00,0xC0,0x00,0x01, ++ 0x77,0x81,0xF8,0xFF,0xF8,0x02,0x07,0x00,0xA8,0x85,0x80,0x07,0xC8,0xCF,0x65,0x32, ++ 0xC8,0x03,0x43,0x01,0x80,0x26,0x40,0x31,0x8F,0xD6,0xBF,0xFF,0xD7,0x6F,0x3B,0xBF, ++ 0xBD,0xFF,0xCF,0x77,0x38,0xA7,0x07,0x00,0x00,0x00,0x07,0x01,0xAF,0xC5,0x77,0x7A, ++ 0x03,0x01,0x87,0x83,0x01,0x09,0x80,0x83,0x07,0x01,0x81,0x83,0x05,0x19,0x80,0x83, ++ 0x03,0x29,0x89,0x83,0x07,0x69,0x89,0x83,0x05,0x61,0x88,0x83,0x11,0x02,0x32,0xAA, ++ 0xA9,0x01,0x06,0x44,0x04,0xF9,0x87,0x89,0x20,0x84,0x01,0x09,0x34,0x62,0xE1,0x01, ++ 0x93,0x03,0x91,0x03,0x05,0x41,0x90,0x03,0x07,0x51,0x90,0x03,0x01,0xA1,0x98,0x03, ++ 0x05,0xE9,0x98,0x03,0x07,0x71,0x98,0x03,0x01,0x39,0xA0,0x03,0x3B,0x01,0xA0,0xBB, ++ 0x01,0x71,0x98,0x83,0x03,0x29,0x98,0x83,0x0F,0x71,0x98,0x8B,0x99,0x83,0xA5,0xBB, ++ 0x0D,0x41,0xA0,0x8B,0x0F,0x81,0xA1,0x8B,0x09,0x61,0x88,0x0B,0x0B,0x71,0x8F,0x0B, ++ 0x0D,0x11,0x8F,0x0B,0x0F,0xF1,0x88,0x0B,0x98,0x03,0x03,0x59,0x28,0x84,0x0D,0x40, ++ 0x10,0x44,0x01,0xC9,0x0B,0x00,0x12,0x44,0x02,0x19,0x18,0x00,0x0E,0x43,0x43,0x62, ++ 0x09,0x43,0xBD,0x7B,0x30,0x02,0x09,0x51,0x80,0x11,0x85,0x1F,0xD7,0x2F,0x03,0xB1, ++ 0x90,0x43,0x01,0xF1,0x93,0x43,0x8B,0x7B,0x32,0x02,0x81,0x01,0xB0,0x3B,0xBA,0x3B, ++ 0x0A,0xC1,0xB8,0x0B,0x0C,0x51,0xB8,0x0B,0x10,0x41,0x36,0x0A,0x8A,0x01,0x09,0x54, ++ 0x12,0xF9,0x97,0x99,0x0E,0x54,0x14,0xC1,0xB9,0x13,0x1E,0x41,0x87,0x5B,0x10,0x11, ++ 0x80,0x53,0x12,0xF1,0x80,0x53,0x14,0x51,0x94,0x13,0x92,0x1B,0x16,0x21,0x93,0x13, ++ 0x16,0xA9,0x0A,0x14,0x10,0x71,0x98,0x13,0x10,0x69,0xA2,0x13,0x12,0x21,0xA0,0x13, ++ 0x12,0x41,0x16,0x14,0x17,0x31,0xB8,0x93,0x34,0xBC,0xB7,0x3B,0x18,0x21,0x30,0x12, ++ 0x94,0x01,0x93,0x9B,0x1A,0x31,0x90,0x9B,0x11,0x99,0x0E,0x94,0x16,0xA1,0x80,0x53, ++ 0x10,0x51,0x88,0x53,0xB4,0x3B,0x16,0x21,0x8D,0x53,0x52,0x52,0x00,0x54,0x13,0x09, ++ 0x88,0x53,0x14,0x51,0x90,0x53,0x10,0x11,0xA0,0x13,0x0F,0x21,0xAB,0x0B,0x08,0xC1, ++ 0xAC,0x0B,0xAA,0x0B,0x33,0x0A,0xC8,0x01,0xA0,0x7B,0xAE,0x7B,0x1A,0xF1,0x88,0x01, ++ 0xBA,0x5B,0xB8,0x5B,0x1C,0xE1,0xB9,0x5B,0x1E,0x41,0xB8,0x5B,0x80,0x13,0x08,0xB1, ++ 0x80,0x0B,0x0A,0x19,0x84,0x0B,0x4C,0xE2,0x00,0x0B,0x92,0x3B,0x4C,0xDA,0xC4,0x01, ++ 0x38,0x0B,0x88,0x91,0x3E,0x0B,0x8A,0xE1,0x38,0x0B,0x0C,0xE1,0x40,0xC2,0x84,0x1F, ++ 0xCC,0xDF,0x47,0xBA,0x09,0xE1,0xC0,0xC1,0x87,0x1F,0xC8,0xB7,0x4C,0x9A,0x44,0xAA, ++ 0xCE,0x11,0x03,0x0B,0xCC,0x71,0x00,0x0B,0x88,0xA1,0x08,0x0B,0x8A,0xA1,0x08,0x0B, ++ 0xCA,0xE1,0x01,0x0B,0xC8,0xC1,0x01,0x0B,0x8C,0x61,0x0D,0x0B,0xCA,0x81,0x15,0x0B, ++ 0xF8,0x48,0x10,0x0B,0xFE,0x48,0x08,0x0B,0xE9,0xC5,0xAF,0x85,0x0C,0x01,0x60,0x1A, ++ 0x47,0x12,0xA4,0x61,0xF8,0x1B,0x06,0x77,0x02,0x21,0x19,0x42,0xCB,0x28,0x00,0x99, ++ 0x12,0x79,0x08,0x00,0xC4,0x40,0x89,0x13,0x16,0x01,0x88,0x13,0x94,0x13,0x10,0x14, ++ 0x12,0x14,0xE6,0x48,0x94,0x4D,0x16,0x5A,0xC0,0x76,0x07,0x01,0x13,0xF9,0x2F,0x89, ++ 0x08,0x68,0x03,0x37,0x00,0x08,0xCA,0x48,0xCC,0x48,0xAA,0x53,0xAA,0x53,0xE6,0x00, ++ 0x94,0x05,0x16,0x1A,0xC1,0xB6,0xEF,0x85,0xA3,0x85,0x51,0x82,0x90,0x01,0x0E,0x01, ++ 0x26,0x8C,0xD0,0x01,0xBC,0x8B,0xB8,0x8B,0x36,0x9A,0x98,0x01,0x8A,0xCB,0x0C,0xCC, ++ 0x9E,0xCB,0x88,0xCB,0x2C,0x09,0xB0,0xAB,0xA8,0x8B,0x34,0xA2,0xA1,0x01,0xCD,0x1B, ++ 0xB0,0x9B,0x36,0x9A,0x9A,0x01,0xA9,0xCB,0x9A,0x01,0xA9,0xEB,0xA8,0xCB,0xA8,0xAB, ++ 0x28,0x29,0x89,0xAB,0x8B,0x0B,0x57,0x42,0x88,0x8B,0x46,0x09,0x8C,0x16,0xA8,0xCB, ++ 0xE5,0x85,0x39,0x97,0xE3,0x85,0x39,0x82,0x0B,0x08,0x42,0x22,0x41,0x13,0x18,0x01, ++ 0x04,0xD2,0x90,0x41,0x04,0x13,0x10,0xD0,0x1A,0x8A,0x08,0x0B,0x40,0x0B,0x42,0x0B, ++ 0x14,0x41,0x18,0x8A,0x00,0x0B,0x08,0x01,0x03,0x0B,0x3C,0x82,0xAA,0x85,0x40,0xE2, ++ 0x40,0x0B,0x30,0x48,0xAE,0x2E,0x08,0x81,0x02,0x0B,0x08,0x81,0x00,0x0B,0x08,0x81, ++ 0x02,0x0B,0x48,0xBA,0x8C,0x01,0x46,0x53,0x38,0x90,0x78,0x90,0x04,0x53,0x44,0x53, ++ 0x18,0x81,0x19,0xD2,0x02,0x53,0x5C,0x9A,0x12,0x09,0x06,0xD3,0x16,0x91,0x01,0x13, ++ 0x44,0x8A,0x42,0x23,0x10,0x61,0x18,0xA2,0x02,0x23,0x44,0x23,0x1A,0xA2,0x00,0x23, ++ 0x4C,0x23,0x1A,0xA2,0x08,0x23,0x4A,0x23,0x18,0xA2,0x08,0x23,0x40,0x23,0x1E,0xA2, ++ 0x02,0x23,0x46,0x43,0x10,0x01,0x1A,0x82,0x04,0x43,0x02,0xD1,0x07,0xC3,0x00,0x01, ++ 0x08,0xC3,0xEA,0x85,0x40,0x22,0x42,0x13,0x08,0x09,0x18,0x52,0x00,0x13,0x48,0x13, ++ 0x18,0x52,0x0C,0x13,0x4C,0x13,0x1A,0x52,0x0E,0x13,0x42,0x13,0x1E,0x52,0x00,0x13, ++ 0x39,0x82,0x43,0xF2,0x58,0x0B,0x10,0x21,0x18,0x8A,0x18,0x0B,0x5A,0x0B,0x10,0x01, ++ 0x18,0x8A,0x18,0x0B,0x5C,0x13,0x08,0x01,0x18,0x52,0x18,0x13,0x40,0xA2,0x11,0x01, ++ 0x80,0x01,0x06,0x13,0x40,0x13,0x1A,0x52,0x01,0x13,0x4A,0x82,0x41,0x43,0x10,0x01, ++ 0x18,0x82,0x00,0x43,0x38,0x82,0xAB,0x85,0x08,0x09,0x00,0x31,0x82,0x07,0xD0,0x17, ++ 0x08,0x11,0x00,0x21,0x81,0x07,0xD0,0xF7,0x00,0x09,0x80,0x07,0xD0,0xD7,0x02,0x31, ++ 0x82,0x07,0xD0,0xBF,0x00,0x21,0x80,0x07,0xD0,0xA7,0x82,0x07,0xD0,0x4F,0xEB,0x85, ++ 0xA9,0x85,0x43,0x02,0x4A,0xCA,0xC0,0x91,0x11,0x43,0x0A,0x91,0x80,0x1F,0xC8,0x27, ++ 0x40,0xE2,0x08,0x51,0x80,0x41,0x81,0x1F,0xC8,0x0F,0x60,0xDA,0x29,0x01,0x90,0x2B, ++ 0xBA,0xFF,0xF7,0x27,0x07,0x09,0xB8,0xFF,0xF8,0xFF,0x01,0xA1,0xBB,0xFF,0xFF,0x27, ++ 0xBB,0xFF,0xFF,0xA7,0xBD,0xFF,0xFF,0xAF,0xBD,0xFF,0xFF,0x27,0xBE,0xFF,0xFF,0x5F, ++ 0x83,0x2B,0x09,0x2B,0x40,0x7A,0x08,0x71,0x80,0x91,0x81,0x1F,0xC3,0x2F,0x0F,0x2C, ++ 0x85,0x2B,0x83,0x2B,0x81,0x2B,0x8F,0x2B,0x88,0x2B,0x03,0x51,0x8D,0x03,0x0D,0x2C, ++ 0x8F,0x2B,0x0F,0x2C,0x13,0x2C,0x11,0x2C,0xE8,0x85,0x03,0x00,0x00,0x00,0x01,0x01, ++ 0xC8,0x21,0x01,0x00,0x70,0x02,0x01,0x00,0xF8,0xFF,0x07,0x04,0x68,0xA2,0x03,0x00, ++ 0x70,0x90,0x06,0x01,0x80,0xE0,0x04,0x01,0x00,0x20,0x00,0x01,0x10,0x00,0x00,0x42, ++ 0x00,0x00,0x00,0x42,0x80,0x01,0x06,0x42,0xF8,0x00,0x06,0x42,0x18,0x00,0x02,0x42, ++ 0xA8,0x85,0x80,0x07,0xC8,0xCF,0xEE,0x85,0xAF,0x85,0xB8,0xFF,0xE8,0x6F,0xEF,0x85, ++ 0xA8,0x7D,0x80,0x04,0x88,0x0C,0xC0,0x0C,0x80,0x14,0xC0,0x04,0x83,0x1C,0x30,0x42, ++ 0x40,0x7E,0x80,0x25,0xE8,0x05,0x00,0x00,0xAC,0xFD,0x87,0x1D,0x30,0x32,0x00,0x01, ++ 0x82,0x14,0x00,0x9F,0x44,0xDA,0x0E,0x01,0x0C,0x0B,0x26,0x01,0xC2,0x14,0x00,0x28, ++ 0x7F,0xC2,0x4E,0xC3,0x1F,0x02,0x09,0xC3,0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01, ++ 0x30,0x82,0xD9,0x64,0x86,0x17,0xE0,0x1F,0xF8,0x82,0x33,0x0A,0xCF,0x99,0x49,0xC9, ++ 0x99,0x3E,0x40,0x91,0xE7,0x16,0x48,0xC3,0x1F,0x02,0x0D,0xC3,0x40,0x20,0x63,0x01, ++ 0x88,0x36,0xD7,0x6C,0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82,0xD8,0x64,0x80,0x17, ++ 0xE3,0x77,0xFD,0xA2,0xD0,0x6C,0x90,0x04,0x14,0x09,0x08,0x01,0x30,0x82,0xD9,0x64, ++ 0x85,0x17,0xE0,0x2F,0xF8,0xBA,0xD3,0x6C,0x90,0x04,0x10,0x09,0x09,0x01,0x34,0x82, ++ 0xD8,0x64,0x80,0x17,0xE5,0xE7,0x14,0x3A,0xE9,0x16,0x30,0x02,0x30,0xE2,0x31,0x3A, ++ 0xFD,0x82,0x13,0xC2,0xE3,0x0E,0x98,0xBA,0x05,0x17,0x10,0x02,0xDB,0x06,0x98,0xA2, ++ 0x46,0xC2,0x4D,0x03,0xDE,0x8A,0x0B,0x00,0xC0,0x00,0xCA,0x24,0x00,0x44,0xC0,0x24, ++ 0xE0,0x00,0x84,0x24,0xC2,0x14,0xE0,0x00,0x90,0x05,0x86,0x14,0xC8,0x2C,0xC0,0x14, ++ 0x15,0x42,0x9C,0x3E,0x87,0x3D,0xE8,0x85,0xAC,0xFD,0x87,0x7D,0x30,0xA2,0x30,0xFA, ++ 0xD8,0x0B,0x8F,0x6C,0xD8,0x0B,0x8B,0x64,0x40,0x01,0x80,0x6E,0x48,0x52,0x05,0x99, ++ 0x07,0x43,0x12,0xF9,0x58,0x3A,0x95,0x81,0x10,0xD3,0x06,0x43,0x00,0xC1,0x83,0x17, ++ 0xF8,0xFF,0xF1,0x84,0xB0,0xE1,0x01,0xCF,0x40,0x1A,0x0D,0x19,0x04,0x0B,0x0A,0x19, ++ 0x05,0x0B,0x48,0x12,0xC2,0x84,0xC0,0x30,0x11,0x01,0x30,0xDA,0x30,0x8A,0x00,0x09, ++ 0x82,0x17,0xC0,0xC7,0x29,0x01,0x30,0x1A,0x14,0x09,0x08,0x01,0x40,0x1D,0xB8,0x04, ++ 0x82,0x17,0xE0,0x6F,0xE7,0x68,0x93,0x6D,0x6F,0x91,0x99,0xA6,0x48,0xB2,0x44,0x43, ++ 0x10,0x11,0x18,0x82,0x01,0x43,0x30,0x02,0x80,0x01,0x35,0x2A,0xC8,0x03,0x32,0x00, ++ 0xAC,0xEE,0x49,0x9A,0x00,0x01,0x80,0x43,0x31,0x12,0x31,0xCA,0x00,0x11,0x80,0x0F, ++ 0xF9,0xF7,0x34,0x1A,0xB8,0x04,0x08,0x01,0x00,0x11,0xD0,0x84,0x84,0x17,0xC0,0x47, ++ 0x49,0x42,0xD4,0x43,0x08,0x43,0x2A,0x01,0xC2,0x64,0x00,0x00,0x80,0x74,0x00,0xBF, ++ 0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09,0x81,0x17,0xC0,0x27,0xB8,0x0C,0xA0,0x04, ++ 0x30,0x8A,0x41,0x1D,0xD8,0x84,0xD0,0x64,0xB9,0xFF,0xFF,0xF7,0xC4,0x74,0xC8,0x30, ++ 0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42,0x80,0x17,0xC0,0xA7,0xE7,0x68,0x93,0x6D, ++ 0xC4,0x6C,0x10,0x2A,0x99,0x26,0x37,0x1A,0xB8,0x04,0x08,0x01,0x00,0x19,0xD0,0x84, ++ 0x82,0x17,0xC0,0xF7,0x31,0x12,0x31,0xCA,0x00,0x01,0x80,0x0F,0xFB,0x47,0x4B,0x92, ++ 0x40,0x43,0x10,0x11,0x18,0x82,0x04,0x43,0x87,0x9D,0xE8,0x85,0xAC,0xFD,0x87,0x1D, ++ 0x30,0x7A,0x50,0x01,0x80,0x16,0x00,0x01,0x80,0x0C,0x00,0x0F,0x00,0x09,0x80,0x0C, ++ 0x2A,0x01,0x00,0x47,0xCD,0x64,0x00,0x40,0xC1,0x30,0x32,0x52,0x08,0x19,0xD8,0x6C, ++ 0xC0,0x0C,0x80,0x0F,0xF9,0x3F,0x07,0x41,0x85,0x17,0xF0,0xD7,0x20,0x09,0xC0,0x34, ++ 0x80,0x01,0x84,0x14,0x60,0x81,0x99,0x36,0x0A,0xF9,0x47,0xF2,0x88,0x11,0x18,0x0B, ++ 0x42,0x08,0x1B,0x0B,0x02,0x0F,0x40,0xDA,0x1F,0x23,0x02,0xF9,0x4F,0xCA,0x82,0x89, ++ 0x88,0x01,0x12,0x43,0x00,0x11,0x80,0x17,0xF0,0x1F,0xC5,0x14,0xF0,0x03,0x46,0x01, ++ 0x80,0x3E,0x00,0x51,0x84,0x17,0xF0,0xE7,0x40,0x83,0x41,0x03,0x30,0x00,0xA8,0x86, ++ 0x07,0x5F,0x00,0xF9,0x4C,0x7A,0x82,0x89,0x88,0x01,0x12,0x43,0x00,0x09,0x80,0x17, ++ 0xF1,0x7F,0x44,0x83,0x40,0x03,0x30,0x00,0xA3,0x1E,0xE0,0x20,0x93,0x25,0x67,0xF9, ++ 0xC9,0x86,0x06,0xE4,0xE1,0xF8,0x35,0x52,0x08,0x09,0xD8,0x6C,0xC0,0x0C,0x80,0x0F, ++ 0xFB,0x4F,0xE5,0x68,0x90,0x6D,0xC7,0x1C,0x15,0x2A,0x9C,0x9E,0x3F,0x17,0xA9,0x85, ++ 0x80,0x3D,0x34,0x7A,0x34,0xA2,0x00,0xD9,0xEF,0x02,0x0E,0xF9,0x88,0x09,0x40,0x01, ++ 0x80,0x0E,0x30,0x72,0x00,0x0F,0x30,0x19,0x13,0xB0,0xD9,0xC3,0x81,0x34,0xD8,0xC3, ++ 0x80,0x2C,0x98,0x1C,0xC2,0x34,0x00,0x00,0xC0,0x00,0x86,0x24,0x45,0xAA,0x11,0x81, ++ 0x00,0x13,0x1A,0x0B,0x28,0x01,0x00,0x67,0x4D,0x03,0x01,0x48,0xC0,0x00,0x42,0x03, ++ 0x01,0x33,0x30,0x1A,0x30,0x52,0x09,0x09,0x00,0x01,0x80,0x0F,0xFB,0xDF,0xE3,0x68, ++ 0x90,0x6D,0xC7,0x34,0x17,0x2A,0x9C,0x7E,0x28,0x01,0x00,0x67,0x4D,0x03,0x03,0x48, ++ 0xC0,0x00,0x42,0x03,0x00,0x33,0x08,0x09,0x31,0x1A,0x31,0x52,0x30,0x42,0x80,0x0F, ++ 0xFB,0x4F,0xE3,0x68,0x90,0x6D,0xC7,0x2C,0x17,0x2A,0x9C,0x7E,0x48,0x0B,0xA1,0x0C, ++ 0x89,0x04,0x30,0xDA,0x10,0x09,0xC8,0x1C,0xC7,0x34,0xB8,0xFF,0xFB,0xFF,0x4A,0x0B, ++ 0x89,0x04,0x30,0xDA,0x10,0x01,0xA0,0x0C,0xC8,0x24,0xC0,0x2C,0xBA,0xFF,0xFF,0xB7, ++ 0x48,0xC2,0x00,0x01,0x88,0x01,0x12,0x43,0x48,0xB2,0x18,0x43,0x37,0x57,0xAE,0xC5, ++ 0x30,0x1A,0x30,0x42,0x30,0xBA,0xD8,0x23,0xD8,0x2B,0x4A,0xB2,0xC0,0xC8,0x8A,0x04, ++ 0x30,0xD2,0x31,0xCA,0x87,0x0F,0xF8,0xDF,0x30,0x01,0x00,0x3F,0x09,0x09,0x30,0xDA, ++ 0x30,0x92,0x31,0x42,0x81,0x0F,0xF8,0xB7,0xE7,0xB0,0x93,0xB5,0x17,0x32,0x9D,0xAE, ++ 0xC8,0x04,0x10,0x01,0x18,0x01,0x00,0x4F,0x00,0x01,0x00,0x1F,0x82,0x5B,0xE0,0x48, ++ 0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE,0xE6,0x90,0x92,0x95,0x17,0x12,0x9D,0x9E, ++ 0xE8,0xC5,0x07,0x00,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0x48,0xE0,0x06,0x00, ++ 0x00,0xF0,0x00,0x01,0x60,0x20,0x02,0x00,0x49,0x32,0x41,0x2A,0x05,0x43,0x9E,0xFF, ++ 0x7F,0x04,0x3A,0xF7,0x94,0x15,0x3A,0x00,0x77,0x18,0x06,0xF9,0x04,0xC2,0x3C,0x48, ++ 0x74,0x48,0x00,0xCA,0x50,0x01,0xD0,0x5E,0x38,0x90,0x78,0x90,0xD4,0x41,0x40,0x98, ++ 0x54,0xE2,0x00,0xD8,0xC6,0xD0,0x4C,0x9B,0x18,0x1A,0x1C,0x5A,0x0B,0x9B,0x3E,0x82, ++ 0x40,0x98,0x54,0xCA,0x04,0xD8,0xC4,0xD0,0x44,0x9B,0x18,0x1A,0x18,0x5A,0x00,0x9B, ++ 0x3A,0x82,0x93,0x05,0x36,0x10,0x76,0x90,0x0C,0x09,0x00,0x8A,0x48,0x00,0x52,0x9A, ++ 0x04,0x00,0xC4,0x00,0x03,0x0B,0x38,0x82,0x96,0x05,0x32,0x10,0x70,0x90,0x0E,0x09, ++ 0x00,0x8A,0x54,0x72,0x4C,0x00,0x02,0x00,0x94,0x01,0xC4,0x00,0x03,0x0B,0x38,0x82, ++ 0xB3,0x15,0x3B,0x82,0xFB,0x85,0x39,0x82,0x40,0x32,0x48,0x0B,0x10,0x21,0x18,0x8A, ++ 0x0B,0x0B,0x38,0x82,0x48,0x1A,0x48,0x43,0x14,0x21,0x18,0x82,0x0B,0x43,0x38,0x82, ++ 0x07,0x20,0x28,0xD0,0x68,0x07,0x00,0x07,0x20,0x07,0x00,0x07,0x08,0x07,0x00,0x07, ++ 0xAC,0xFD,0x87,0x4D,0xD0,0x94,0x30,0x22,0xF8,0x43,0x80,0x0C,0xF8,0x6B,0xC6,0x64, ++ 0x08,0x01,0x80,0x0B,0x00,0x01,0x00,0x8F,0x0A,0x21,0x19,0x0A,0x18,0x99,0xCB,0x48, ++ 0x0E,0xD8,0xC2,0x48,0xC8,0x4B,0x4C,0x79,0x80,0x36,0x80,0x83,0xE0,0x90,0xCA,0x64, ++ 0xD8,0x64,0xC0,0x4B,0xE0,0x48,0x82,0xCB,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0x5E, ++ 0xC0,0x64,0xC0,0x03,0x80,0x44,0x40,0x01,0x88,0x0E,0x80,0x6D,0xE8,0x85,0xC7,0x44, ++ 0x40,0x09,0x88,0x1E,0xC0,0x0C,0x40,0x09,0x8F,0x06,0x38,0xB7,0x00,0x01,0x80,0x34, ++ 0x80,0x2C,0xC8,0x44,0xC4,0x0C,0x10,0x0A,0x88,0x96,0x02,0x01,0x30,0x01,0x08,0x01, ++ 0x88,0x1C,0x88,0x14,0x1C,0xC9,0x09,0xD8,0x00,0x4F,0x10,0x31,0x18,0x52,0xCA,0x90, ++ 0xC2,0x90,0x46,0xBC,0xC4,0xC0,0x41,0x94,0xCA,0xB0,0xE4,0x48,0x90,0x4D,0xD6,0x0C, ++ 0x17,0x8A,0x9C,0x96,0xC8,0x0C,0x80,0x17,0xF0,0x6F,0x82,0x24,0x30,0x82,0xC9,0x0C, ++ 0x82,0x17,0xF0,0x47,0x30,0x32,0x08,0x01,0x01,0x01,0x00,0x07,0x1A,0x99,0x0B,0xD8, ++ 0x02,0x0F,0xE0,0x48,0x91,0x4D,0x16,0x21,0x18,0x52,0xCA,0x90,0xC4,0x90,0xCE,0x93, ++ 0x57,0x79,0x80,0xB6,0x12,0x21,0x19,0x52,0xCE,0x90,0xC0,0x98,0x3E,0xF1,0xF8,0xFA, ++ 0xDF,0x1C,0xC0,0xD8,0x98,0x1C,0x18,0xE9,0x0E,0xD8,0xC6,0x98,0x14,0x01,0xF0,0xD2, ++ 0xDE,0x14,0xC0,0x90,0x92,0x14,0xE0,0x48,0x92,0x4D,0xE6,0x00,0x90,0x05,0xD6,0x44, ++ 0x16,0x12,0xC4,0xDE,0xC8,0x44,0xC0,0x1C,0x80,0x17,0xF0,0xE7,0x30,0x3A,0xC8,0x44, ++ 0xC0,0x14,0x80,0x17,0xF0,0xBF,0xC8,0x24,0xD8,0x48,0x8E,0x34,0xD0,0x80,0x81,0x2C, ++ 0x08,0x01,0x10,0x01,0x00,0x77,0x00,0x01,0x33,0x5A,0x18,0x5A,0xF2,0x5C,0x00,0xD8, ++ 0xC8,0xD8,0x04,0x1F,0x04,0x30,0x9A,0xD2,0xE6,0x00,0x92,0x05,0x17,0x42,0x9D,0xCE, ++ 0xE6,0x48,0x92,0x4D,0x17,0x4A,0x9D,0x76,0x08,0x01,0x10,0x01,0x03,0xE7,0x19,0x99, ++ 0x08,0xD8,0x02,0x0F,0xE6,0x48,0x92,0x4D,0x02,0x21,0x19,0x42,0xCC,0x00,0x30,0x22, ++ 0xC0,0x00,0x86,0x3C,0xC8,0x03,0x44,0x79,0x80,0xA6,0x07,0x01,0x00,0x2F,0xD9,0x3C, ++ 0x34,0xF1,0xF8,0xF2,0xD9,0x34,0x38,0xC9,0xC0,0xB0,0x1F,0x31,0x18,0x1A,0xCA,0xD8, ++ 0x0E,0xF8,0xCD,0xD8,0x47,0xFC,0xDA,0xB0,0xAB,0x06,0x10,0xB2,0x95,0xB5,0x35,0xB2, ++ 0x37,0xE9,0x08,0xB0,0x20,0x32,0x3B,0x01,0xF8,0xBA,0xF7,0x2C,0x45,0xDC,0xCC,0xF0, ++ 0xD0,0x98,0xAF,0x06,0x10,0xDA,0x32,0xB2,0x18,0x72,0xFB,0x5C,0x07,0xB0,0xCB,0xB0, ++ 0x22,0x9A,0x03,0x38,0x9A,0x9A,0xE7,0x00,0x90,0x05,0xDE,0x0C,0x16,0xC2,0x9C,0xB6, ++ 0xE6,0x48,0x92,0x4D,0xE6,0x90,0x92,0x95,0xC0,0x64,0xC0,0x03,0x15,0x82,0xC4,0xF6, ++ 0xC0,0x64,0xC8,0x0C,0xC4,0x03,0x10,0x42,0xC9,0x06,0x38,0xF7,0xC1,0x0C,0x38,0xE7, ++ 0xAC,0x85,0x87,0x3D,0x34,0x22,0x00,0x91,0xD4,0x02,0x34,0x22,0x01,0xC1,0xF0,0x02, ++ 0x18,0x71,0x80,0x34,0xF0,0x1A,0x9F,0x2C,0xD0,0x00,0x96,0x05,0x1F,0xD1,0xF0,0x1A, ++ 0x2B,0x81,0xF8,0x2A,0x32,0xF2,0xDC,0xD8,0x90,0xDD,0xA8,0x24,0xC0,0x2B,0x6F,0x09, ++ 0x8D,0x16,0x10,0x04,0x10,0x1C,0x07,0x6F,0x55,0x3C,0x05,0xE8,0xC7,0x68,0x51,0x04, ++ 0x07,0x30,0xC4,0x98,0xD9,0x68,0x97,0x6D,0xD0,0xC0,0x90,0x1D,0x84,0x40,0x85,0xD8, ++ 0x17,0x04,0x15,0x1C,0x4B,0x81,0x80,0xF6,0xE9,0x2C,0xC0,0x40,0x02,0x28,0xCA,0x00, ++ 0xEA,0x34,0xC8,0x00,0x80,0x00,0x94,0x05,0xEF,0x24,0xC0,0x58,0x02,0xE8,0xCA,0xE8, ++ 0x37,0x9A,0xC3,0x58,0x80,0xD8,0x94,0xED,0x90,0x01,0x46,0x01,0xD0,0x0E,0x00,0x01, ++ 0x00,0x27,0x50,0x9C,0x10,0x1A,0xD4,0x0E,0x00,0x81,0xF0,0x82,0x68,0x01,0xD0,0x0E, ++ 0x28,0x01,0x00,0x27,0x55,0x9C,0x12,0x5A,0xD0,0x0E,0x28,0x91,0xF8,0xAA,0xD2,0x2C, ++ 0xD0,0x90,0xF0,0xB0,0xD2,0x06,0x10,0x92,0x06,0x98,0xC2,0xB8,0xD2,0x24,0xD8,0x90, ++ 0xF0,0x98,0xD0,0x06,0x15,0x92,0xC2,0xF8,0x7E,0xD0,0xCF,0x90,0x18,0x90,0x66,0x90, ++ 0x58,0x01,0xD0,0x06,0x12,0xDA,0x02,0xF8,0xC8,0xD8,0x76,0x01,0xD3,0x06,0x10,0xB2, ++ 0xCE,0xD8,0x7C,0xF0,0xC6,0x98,0x1F,0xD8,0x60,0xF0,0x48,0x41,0x80,0x0E,0x48,0x49, ++ 0x88,0x2E,0x48,0x49,0x8A,0x1E,0x20,0x88,0x63,0x50,0x20,0x88,0x63,0x70,0x30,0x0A, ++ 0x8B,0x0C,0x28,0x12,0xCB,0x06,0x30,0x12,0xCC,0x0C,0x10,0x72,0xC8,0x06,0xF0,0x0C, ++ 0xDB,0x2C,0x30,0x0A,0xD0,0x48,0x34,0x7A,0x1C,0xCA,0x02,0x58,0xC4,0x48,0x36,0x72, ++ 0x19,0x51,0x30,0xCA,0xF3,0x1A,0x07,0xF8,0xCA,0x48,0x1E,0x5A,0x32,0x8A,0xC3,0xC8, ++ 0x1B,0x82,0x32,0x12,0x46,0xB8,0xCA,0x00,0x02,0x00,0xC6,0x00,0x36,0x0A,0x03,0x48, ++ 0x88,0x1C,0x80,0x17,0xE8,0xBF,0x80,0x14,0xD0,0x24,0xC0,0x0C,0xD8,0x00,0x34,0x0A, ++ 0x1C,0x82,0x02,0x10,0xC0,0x00,0x14,0x61,0xF2,0x12,0x05,0x58,0xC2,0x48,0x1E,0x52, ++ 0xC3,0x80,0x18,0xAA,0x00,0x07,0x00,0x67,0xCE,0x48,0x07,0x48,0xC0,0x40,0xC8,0x1C, ++ 0x80,0x17,0xE8,0x07,0xCB,0x2C,0x08,0x0C,0xCD,0x24,0x08,0x0C,0xCF,0x14,0x08,0x0C, ++ 0x10,0x04,0x81,0x3D,0xEF,0x85,0xAF,0xF5,0x30,0x3A,0xC0,0x44,0x60,0xD2,0xCF,0xE0, ++ 0x2F,0x31,0x70,0xCA,0x1F,0xAA,0xC2,0x68,0xF5,0x21,0xC9,0x68,0x06,0x90,0xC2,0x90, ++ 0x59,0xAA,0xDF,0x81,0xC6,0xB0,0xFE,0x13,0x31,0xB2,0x34,0xDA,0x32,0x3A,0xB8,0x01, ++ 0x30,0x12,0xB8,0x0C,0x92,0x01,0xBE,0x01,0x59,0x09,0x88,0x4E,0x01,0x01,0x00,0x17, ++ 0xC0,0x0B,0x49,0x79,0x89,0xE6,0x40,0x4C,0x0B,0x0C,0x47,0x5C,0x14,0x1C,0x31,0xE2, ++ 0xC1,0x9B,0x89,0x1B,0xC3,0x9B,0x8B,0x1B,0x1B,0x0C,0x35,0x1A,0x19,0x1C,0x27,0x0C, ++ 0x23,0x1C,0x0B,0x0C,0x09,0x1C,0x45,0x4C,0x1B,0x0C,0x41,0x4C,0x19,0x0C,0x83,0x03, ++ 0x0F,0x09,0x80,0x0B,0x88,0x0B,0xFD,0x8B,0x90,0x0B,0x09,0x01,0x90,0x0B,0x03,0x27, ++ 0xA2,0x21,0xE1,0x00,0x93,0x05,0x2E,0x82,0x9B,0xD6,0x2E,0x82,0x94,0xF6,0x03,0x2F, ++ 0x1A,0x21,0x19,0xCA,0xC8,0x60,0x08,0x41,0x89,0x04,0x40,0x4C,0x18,0x0C,0x09,0x11, ++ 0xF3,0x4A,0x1B,0x0C,0x35,0x62,0xCC,0x0B,0x48,0x09,0x88,0xAE,0x08,0xC1,0x18,0xE1, ++ 0xF7,0x0A,0xF3,0x1A,0xD0,0x48,0xAE,0x06,0x14,0x4A,0x92,0x4D,0x30,0x72,0x1C,0xF1, ++ 0xF3,0x1A,0x37,0x0A,0xD0,0x48,0xAE,0x06,0x14,0x4A,0x92,0x4D,0xE3,0xDB,0x21,0x8A, ++ 0x10,0xCA,0xCC,0x0E,0x0D,0x01,0x88,0x0B,0x09,0xC1,0x18,0x01,0xF7,0x0A,0xF3,0x1A, ++ 0xD0,0x48,0xAE,0x06,0x14,0x4A,0x92,0x4D,0x30,0x62,0x0C,0xD1,0x1B,0x11,0xF1,0x0A, ++ 0xF6,0x1A,0xD7,0x48,0xAA,0x06,0x10,0x4A,0x24,0x0A,0x93,0x4D,0x30,0x62,0xDC,0x0C, ++ 0xC4,0x0B,0xE7,0xDB,0xE4,0xD8,0x12,0xCA,0xC8,0x7E,0xF8,0x8B,0xEE,0xDB,0x01,0xCA, ++ 0x28,0x0A,0xCB,0x56,0xD6,0x0B,0x4B,0x41,0x92,0x0E,0xE0,0x48,0x91,0x0B,0xD3,0x0B, ++ 0xFC,0x9B,0x10,0xCA,0x92,0x0E,0xE0,0x48,0x91,0x0B,0xD1,0x0B,0x28,0x0A,0xCB,0xA6, ++ 0xDF,0x0C,0xC0,0x0B,0xE2,0xDB,0xE4,0xD8,0x10,0xCA,0xCC,0x76,0xCA,0x0B,0x37,0x50, ++ 0xE2,0xCB,0x73,0x90,0xF4,0x48,0x12,0x52,0x89,0x0E,0x08,0x01,0x80,0x0B,0x35,0x12, ++ 0x09,0x81,0x30,0x02,0xBC,0xFF,0xF7,0xE7,0x00,0xDF,0xD8,0x0C,0xC4,0x0B,0xE7,0xDB, ++ 0xE4,0xD8,0x12,0xCA,0xC8,0x1E,0xF8,0x8B,0xEE,0xD3,0x01,0x8A,0x91,0x0B,0x59,0x0C, ++ 0x23,0x0C,0x59,0x0C,0x20,0x0C,0x33,0x12,0x30,0x02,0xC9,0x04,0xBC,0xFF,0xF7,0x47, ++ 0x03,0x01,0x90,0x03,0xD0,0x03,0x41,0x01,0x80,0x1E,0x00,0x07,0x02,0x3F,0xF1,0x00, ++ 0x97,0x03,0xC1,0x03,0x40,0xF9,0x93,0x0E,0xE7,0x00,0x82,0x03,0x43,0x44,0x15,0x04, ++ 0x03,0x19,0x80,0x03,0xE4,0xC3,0x83,0x01,0x89,0x03,0xCF,0x03,0xC2,0x8B,0xD1,0x00, ++ 0xE0,0x00,0x42,0x11,0xC3,0x2E,0xC8,0x03,0xC2,0x8B,0xD3,0x00,0xE0,0x00,0x42,0x11, ++ 0xCF,0x4E,0xC0,0x03,0x40,0x11,0x98,0x36,0xCA,0x0C,0xE0,0x4B,0x10,0x42,0xC4,0x16, ++ 0x07,0x01,0x80,0x03,0x89,0x03,0xC7,0x83,0x8B,0x03,0xC1,0x83,0x8F,0x03,0xEB,0xF5, ++ 0xAC,0x85,0x37,0xE2,0x34,0x2A,0xAB,0x01,0x4A,0x5C,0x27,0xD8,0x67,0xE0,0x40,0xF9, ++ 0x88,0x0E,0x00,0x01,0xE9,0x85,0x1F,0x21,0x1B,0xC2,0x5A,0xFA,0xC6,0x00,0xC4,0x00, ++ 0x1A,0x31,0x18,0xCA,0xC3,0x48,0x54,0xE2,0xD4,0x21,0xC1,0x50,0x0A,0xA1,0xF0,0x0A, ++ 0x48,0x01,0xD0,0x06,0x10,0x4A,0x1A,0xB1,0xF0,0x1A,0x5E,0x01,0xD2,0x06,0x10,0xDA, ++ 0xC3,0x48,0x5E,0xB2,0x10,0xCA,0x9C,0x06,0x08,0x01,0x30,0x71,0x44,0x9C,0xF8,0x32, ++ 0xD8,0xD8,0xAC,0x06,0x10,0xDA,0x32,0x81,0x44,0x94,0xFA,0x32,0xD8,0x90,0xAC,0x06, ++ 0x14,0x92,0xC2,0xD0,0x11,0x12,0x9D,0x0E,0xC8,0x33,0x74,0x09,0x8B,0x26,0xE0,0x5B, ++ 0xCA,0x3B,0xF6,0xD8,0x10,0xFA,0xDC,0xBE,0x70,0x09,0x88,0x3E,0xDC,0x5B,0x11,0x5A, ++ 0x9E,0x26,0xC0,0x03,0x40,0xF1,0xC0,0x0E,0x40,0x51,0x90,0x6E,0x70,0x09,0x88,0x1E, ++ 0x30,0x02,0x5B,0x04,0x40,0xC1,0x98,0x3E,0x70,0x09,0x88,0x16,0x04,0x00,0x13,0x82, ++ 0xCD,0x16,0x00,0x00,0x10,0x82,0xC4,0x0E,0x07,0x01,0xE8,0x85,0x07,0x09,0xE8,0x85, ++ 0xAC,0xFD,0x87,0x5D,0x30,0xB2,0x0C,0x01,0x28,0x01,0x00,0x01,0x80,0x14,0xC0,0xA4, ++ 0xF8,0x23,0x06,0x01,0x30,0x22,0x84,0x34,0x00,0x27,0xD0,0x64,0x02,0xF9,0xA7,0x82, ++ 0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xC6,0xD3,0x74,0x28,0x92,0xC0,0x26,0xC0,0x74, ++ 0x83,0x24,0x30,0x82,0x80,0x1C,0x00,0x1F,0x30,0x82,0x83,0x24,0xC0,0x74,0x80,0x1C, ++ 0x00,0x01,0x80,0x2C,0x00,0xD7,0x1A,0x01,0x03,0xB7,0x32,0x02,0x06,0xC2,0x3E,0x00, ++ 0x8A,0x86,0x42,0x32,0x80,0x3C,0x00,0x01,0xD0,0xA4,0xF0,0x5C,0xF8,0x93,0x90,0x54, ++ 0x33,0xD2,0x18,0x12,0x05,0xB8,0xCA,0xD0,0x90,0x4C,0x00,0x6F,0xF6,0x34,0x00,0x32, ++ 0x38,0x90,0x8F,0x3E,0xF2,0x4C,0x00,0x38,0xD8,0xB2,0xFF,0x3C,0x10,0xF2,0x95,0x0E, ++ 0xB0,0x3C,0x30,0x0A,0xE6,0x00,0x92,0x05,0xD4,0x54,0x10,0x12,0xC1,0x76,0x77,0xBA, ++ 0x02,0x01,0x00,0x78,0xB8,0x44,0x00,0x87,0x36,0x3A,0x03,0x3A,0x38,0xF8,0x8F,0x56, ++ 0x33,0x3A,0x18,0x3A,0xD3,0x5C,0x00,0xF8,0xC0,0xF8,0xD5,0x44,0xD5,0xFA,0x15,0xBA, ++ 0xC1,0x0E,0x30,0xF2,0x32,0x2A,0xE0,0x00,0x93,0x05,0x2E,0x82,0x9C,0x66,0x17,0xEA, ++ 0x88,0xA6,0xC0,0x14,0xC8,0x00,0x84,0x14,0xC2,0x2C,0xE0,0x00,0x90,0x05,0x86,0x2C, ++ 0xC2,0x64,0xA0,0x2A,0x31,0x09,0x30,0x82,0xD4,0x34,0x00,0x42,0x1C,0x82,0x90,0x05, ++ 0x85,0x34,0x00,0x72,0x30,0x02,0x1B,0x32,0x94,0x85,0x35,0x22,0xD0,0x24,0xC0,0x2C, ++ 0x10,0x82,0x84,0x1E,0xE6,0xD8,0x92,0xDD,0x2D,0x9A,0x9B,0x36,0xD0,0x24,0xC0,0x2C, ++ 0x15,0x82,0x9C,0x06,0xC0,0x14,0x80,0x3C,0x10,0x01,0x00,0x01,0x0B,0x01,0x30,0x5A, ++ 0x80,0xCB,0x18,0x01,0x0C,0x01,0x30,0x62,0x30,0x4A,0xE3,0x4A,0x02,0x0F,0xE0,0x48, ++ 0x90,0x4D,0x36,0xEA,0x07,0x6A,0x3E,0x68,0x88,0xCE,0xEF,0x1C,0x10,0x4A,0x9D,0xFE, ++ 0x40,0x01,0x88,0x8E,0x08,0xF9,0x07,0x5F,0xD0,0x64,0xE0,0x9A,0x28,0x9A,0x93,0x1E, ++ 0xD0,0xA4,0xF8,0x93,0x10,0x12,0xC4,0x0E,0xD0,0x64,0xA0,0x8A,0xE6,0x00,0x92,0x05, ++ 0x17,0x02,0x9D,0x8E,0x87,0x7D,0xE8,0x85,0xF6,0x00,0x92,0x05,0x30,0x4A,0xE3,0x4A, ++ 0x2D,0x09,0x30,0x62,0x00,0x6F,0x01,0x00,0x70,0x30,0x03,0x00,0xF8,0xFF,0x07,0x00, ++ 0x33,0x6A,0x18,0x2A,0xFB,0x5C,0x00,0x70,0xCA,0xB0,0x07,0x38,0xDD,0xAA,0xC7,0x50, ++ 0x2C,0x09,0x00,0x6A,0x1D,0xEA,0x90,0x5D,0x31,0x72,0xA3,0x8A,0xED,0x3C,0x10,0x52, ++ 0x98,0x16,0x28,0x11,0x30,0x62,0x05,0xA7,0xFA,0x74,0xE0,0x28,0x10,0xEA,0x9D,0x6E, ++ 0x90,0x3C,0x08,0x01,0x00,0x27,0xF8,0x64,0xE3,0xAA,0xA3,0xEA,0xE6,0x48,0x92,0x4D, ++ 0x17,0x0A,0x9D,0xC6,0xE0,0x8A,0x29,0x09,0x30,0x62,0x05,0x17,0x90,0x45,0x2F,0x01, ++ 0xA3,0xAA,0x31,0x2A,0x6D,0x01,0x80,0x2E,0x33,0x6A,0x18,0x2A,0xFB,0x5C,0x00,0x70, ++ 0xCA,0xB0,0x07,0x38,0xDA,0xAA,0xDF,0x90,0x2C,0x09,0x00,0x6A,0x1B,0x5A,0x35,0x6A, ++ 0xE2,0x4A,0xE1,0x48,0xA4,0x4A,0x39,0xAF,0xAC,0xC5,0x37,0x22,0xFC,0x73,0x5E,0xAA, ++ 0x36,0x02,0xC3,0x00,0x31,0x32,0x34,0xAA,0x38,0x21,0x31,0x62,0x1A,0xEA,0xA3,0x01, ++ 0x13,0x01,0x20,0x2A,0xC0,0x68,0x07,0xF7,0xC0,0x1B,0x58,0x79,0x86,0xD6,0xC8,0x1B, ++ 0x30,0xD8,0xA0,0x3E,0x18,0xF9,0x8F,0x1B,0x8E,0x1B,0xC2,0x1B,0xE5,0x3B,0x15,0xDA, ++ 0xC6,0x06,0x88,0x13,0xCA,0x1B,0x36,0xD8,0x76,0xD8,0x8A,0x1B,0x58,0x01,0x80,0x0E, ++ 0xF6,0xD8,0x8A,0x1B,0xC8,0x1B,0x5E,0x01,0x8A,0x26,0xC0,0x1B,0x44,0xD8,0x04,0xD8, ++ 0x84,0x1B,0x82,0x13,0x84,0x21,0x11,0x2A,0xC0,0xF6,0x06,0x01,0x84,0x04,0xB8,0x53, ++ 0x30,0x82,0x03,0x8F,0xC5,0x13,0x10,0x92,0x96,0x5E,0xC0,0x13,0xE2,0x3B,0x35,0x98, ++ 0x75,0xD8,0x12,0xDA,0xCC,0x2E,0xC0,0x13,0x50,0x01,0x81,0x16,0x00,0x09,0x80,0x04, ++ 0x00,0x27,0x10,0x01,0x81,0x13,0x84,0x21,0x17,0x2A,0xC4,0x5E,0xC0,0x04,0x40,0x01, ++ 0x83,0x76,0x31,0x92,0x36,0x5A,0x98,0x01,0x00,0x47,0x01,0x01,0x80,0x83,0xC4,0x83, ++ 0x11,0x82,0x95,0x16,0xC2,0x83,0x36,0x38,0xE3,0x03,0x75,0xF8,0x10,0x3A,0xCC,0xE6, ++ 0x04,0x09,0x80,0x83,0xFA,0x43,0xE4,0x00,0xB8,0x43,0x3C,0x71,0xF8,0xBA,0x7E,0x01, ++ 0xD0,0x16,0x00,0x01,0x08,0x84,0x06,0x27,0x54,0xC4,0x10,0x3A,0xE8,0x0E,0x50,0xC4, ++ 0x08,0x84,0x3E,0x81,0xF8,0xBA,0x7E,0x01,0xD0,0x16,0x00,0x01,0x10,0x84,0x00,0x27, ++ 0x54,0xC4,0x12,0x3A,0xEA,0x0E,0x50,0xC4,0x11,0x84,0x90,0x21,0x16,0xAA,0xC4,0xA6, ++ 0xF8,0x43,0x40,0x01,0x88,0x36,0x58,0x44,0x16,0xE9,0x03,0x90,0x10,0x82,0x94,0x0E, ++ 0xE0,0x00,0x1A,0x44,0xF8,0x43,0x44,0x01,0x80,0xCE,0x10,0x01,0x03,0x01,0x28,0x99, ++ 0x0E,0x68,0xFB,0x63,0x01,0x6F,0x18,0x21,0x1B,0x1A,0x22,0x1A,0xC8,0xD8,0xD2,0xF3, ++ 0x70,0x09,0x88,0x26,0xC8,0xDB,0x5E,0x19,0x8A,0x0E,0xE0,0x90,0x92,0x95,0xE6,0x00, ++ 0x94,0x05,0x16,0x22,0xC0,0x7E,0x57,0x01,0x88,0x0E,0x00,0x01,0x1F,0x44,0xE8,0xC5, ++ 0xAC,0x85,0x87,0x3D,0x30,0x2A,0x30,0x62,0x41,0x12,0xC2,0x40,0x08,0x29,0xEE,0x4A, ++ 0x4B,0x29,0x80,0xDE,0x4B,0x02,0xC2,0x70,0xEB,0x48,0xC4,0x48,0x89,0x1C,0x48,0xF2, ++ 0x8B,0x61,0xC0,0x48,0x88,0x14,0x08,0x01,0x10,0xF9,0x1F,0x79,0x03,0x3F,0xA0,0x92, ++ 0xC8,0x3B,0x7E,0x01,0x88,0x06,0x80,0x1B,0xE6,0x48,0x92,0x4D,0x87,0x21,0xF9,0x3B, ++ 0x17,0x7A,0xC4,0xA6,0x00,0x01,0x80,0x34,0xF8,0x03,0x41,0x01,0x80,0xCE,0xB2,0x04, ++ 0x31,0x0A,0x31,0x42,0x58,0x2D,0xD0,0x14,0xBA,0xFF,0xDF,0x97,0x80,0x34,0xC0,0x34, ++ 0x40,0x01,0x88,0x76,0x30,0x01,0x00,0x47,0x31,0x5A,0x31,0x92,0x08,0xF9,0x07,0x09, ++ 0xA7,0x04,0xB8,0xFF,0xE3,0x47,0xE7,0xB0,0x91,0xB5,0xFF,0x03,0x17,0x82,0xC5,0x9E, ++ 0x00,0xFF,0xC1,0x34,0x40,0x09,0x88,0x96,0xC1,0xB3,0x31,0x1A,0x30,0x52,0x09,0x01, ++ 0x37,0x82,0xB9,0xFF,0xE8,0x2F,0x46,0x01,0x80,0x0E,0x00,0x01,0x00,0x07,0x00,0x09, ++ 0x30,0x5A,0x11,0x01,0x30,0x8A,0xA1,0x04,0xBE,0xFF,0xE7,0x6F,0x00,0x4F,0xA1,0x04, ++ 0xFB,0x3B,0x31,0x5A,0xE9,0xD3,0x30,0xDA,0xC8,0x1C,0xC0,0x14,0xB8,0xFF,0xF7,0x47, ++ 0x38,0x01,0x00,0xDF,0xC6,0x1C,0xE8,0x02,0x40,0xF9,0x87,0x16,0xE0,0x82,0x81,0x24, ++ 0x07,0x0F,0x00,0xF9,0x81,0x24,0x30,0x1A,0x31,0x52,0x31,0xCA,0xC7,0x24,0xB8,0xFF, ++ 0xE8,0xFF,0x44,0x01,0x80,0x0E,0x00,0x01,0x00,0x07,0x00,0x09,0x31,0x5A,0x31,0xD2, ++ 0xA0,0x04,0xC8,0x24,0xBD,0xFF,0xE7,0x3F,0xE7,0xF8,0x93,0xFD,0xFD,0x03,0x11,0xC2, ++ 0xC1,0x06,0x37,0x0A,0x30,0x42,0xD1,0x34,0xBE,0xFF,0xF7,0xB7,0x20,0xCF,0x04,0x01, ++ 0x38,0x82,0x03,0x00,0x70,0x30,0x03,0x00,0x48,0xE0,0x06,0x00,0xAE,0xFD,0x87,0x5D, ++ 0xC6,0xAC,0xDA,0x03,0x82,0xCC,0xC1,0xAC,0xD9,0x03,0x84,0xC4,0x01,0x09,0x58,0x45, ++ 0x81,0xC3,0xC0,0xC4,0xE2,0x00,0x82,0xC3,0xC4,0xC4,0x81,0xC3,0xC2,0xC4,0xF1,0x00, ++ 0x82,0xC3,0xC6,0xAC,0x82,0x01,0x87,0x54,0xC0,0x0B,0x00,0x21,0x1A,0x0A,0xC0,0x54, ++ 0x82,0x0B,0xC0,0xAC,0xCA,0x03,0x42,0x00,0x80,0xD4,0x09,0x01,0x40,0xB5,0x31,0x52, ++ 0x00,0x36,0x00,0x01,0x82,0xF4,0xC0,0xAC,0xCC,0xB4,0x82,0x01,0x82,0x4C,0xC2,0x74, ++ 0x92,0x05,0x82,0x44,0xC2,0x6C,0x92,0x05,0x82,0x3C,0xC2,0xAC,0x82,0x01,0x86,0x34, ++ 0x4B,0x11,0x80,0xBE,0x10,0x01,0x00,0x01,0x4C,0x45,0xB1,0x4A,0x8F,0x2C,0x4A,0xF2, ++ 0xB2,0x4A,0x8C,0x24,0x48,0xE2,0xEF,0x48,0xB2,0x4A,0x8C,0x1C,0x04,0x08,0xC4,0x48, ++ 0x91,0x4D,0x66,0x9D,0xDB,0x74,0xA2,0x1A,0x62,0x85,0xD9,0x6C,0xA2,0x1A,0xDB,0x24, ++ 0x9A,0x34,0xD9,0x1C,0x9A,0x2C,0xD9,0x2C,0x98,0x24,0x41,0x09,0x89,0x5E,0xD8,0x34, ++ 0x12,0xDA,0x92,0xDD,0x99,0x34,0xD9,0x2C,0x12,0xDA,0x92,0xDD,0x99,0x2C,0xD9,0x24, ++ 0x12,0xDA,0x92,0xDD,0x9A,0x24,0xD9,0x5C,0x32,0xE2,0xDC,0x64,0x9A,0x5C,0xD9,0x3C, ++ 0xE1,0x44,0xEA,0x2C,0xCA,0xD8,0x92,0xDD,0xEB,0x34,0xC9,0x20,0x91,0x25,0xF3,0x24, ++ 0xED,0x5C,0xC9,0x68,0xA8,0x5C,0x59,0x01,0xD9,0x86,0xEB,0xCC,0x13,0x5A,0xD5,0x6E, ++ 0x63,0x01,0xD8,0x5E,0xED,0xC4,0x11,0x62,0xD1,0x46,0xEB,0x5C,0xC5,0x6B,0x49,0x68, ++ 0x8B,0x06,0x32,0x2A,0x3F,0x01,0xF8,0x7A,0xEB,0x24,0x01,0x68,0x23,0x62,0x35,0x32, ++ 0x2B,0x01,0xF8,0xAA,0xF5,0xD4,0x11,0xAA,0xEA,0xC6,0xF2,0xB4,0x71,0x09,0x88,0x16, ++ 0xD9,0xF0,0x93,0xB5,0xB2,0x9C,0xF8,0x5C,0x35,0x01,0xF8,0xF2,0x10,0x72,0xDD,0x06, ++ 0x37,0xAA,0x81,0x68,0x01,0x68,0x33,0x7A,0xF3,0x9C,0x10,0x6A,0x12,0xAA,0xE5,0x2E, ++ 0x6B,0x9D,0xA1,0x62,0x6B,0x85,0xA1,0x5A,0x01,0xA8,0x72,0xB5,0xC9,0x68,0xE5,0x72, ++ 0xE1,0xB0,0xA3,0x72,0xEB,0xF4,0xE0,0x68,0x90,0x6D,0xAF,0xF4,0xF5,0x9C,0x10,0xBA, ++ 0xD1,0xBE,0x05,0x9F,0x09,0xEF,0x6A,0x9D,0xA1,0x62,0x6B,0x85,0xA2,0x5A,0x03,0xA8, ++ 0x75,0xB5,0xC9,0x68,0xE3,0x72,0xE1,0xB0,0xA0,0x72,0xE9,0xF4,0xE7,0x68,0x93,0x6D, ++ 0xAD,0xF4,0x38,0x37,0xE9,0x5C,0xC1,0x6B,0x48,0x68,0x6D,0x19,0x8A,0x6E,0x00,0xB0, ++ 0x7F,0xB5,0xC9,0xB0,0xE0,0xB2,0x71,0x09,0xC2,0x3E,0xC0,0x64,0x08,0x01,0xC6,0x03, ++ 0x1A,0x42,0xC8,0x64,0x82,0x43,0x80,0x7D,0xE8,0x85,0x6F,0x11,0x89,0x56,0x68,0x9D, ++ 0xA1,0x62,0x63,0x85,0xA2,0x1A,0x03,0x98,0x4A,0xB5,0xC1,0xC8,0xE2,0x5A,0xE0,0xD8, ++ 0xA0,0x5A,0x00,0x1F,0xCE,0x34,0xCA,0x4B,0x4F,0x51,0x90,0x66,0xE6,0x00,0x92,0x05, ++ 0x40,0x11,0x90,0x06,0x3A,0xD7,0xE2,0x90,0x90,0x95,0x56,0x21,0x92,0x06,0x38,0x57, ++ 0x01,0x01,0x80,0x64,0xC0,0xB4,0x42,0x09,0x88,0xF6,0x03,0x01,0x80,0x7C,0x01,0x01, ++ 0x81,0x74,0xC9,0x7C,0x42,0xB5,0x01,0x48,0xC2,0x40,0x80,0x14,0xC1,0x74,0xC9,0x7C, ++ 0x02,0x00,0xC4,0x00,0x91,0x05,0x86,0x4C,0xCA,0x74,0xC1,0x14,0xE0,0x2A,0x6A,0x09, ++ 0xC1,0x26,0xC0,0x64,0xE6,0x00,0x92,0x05,0x87,0x64,0x01,0x8F,0xC0,0x74,0x41,0x09, ++ 0x89,0x16,0xC0,0x7C,0x47,0x01,0x88,0xC6,0x08,0x81,0x41,0x45,0x83,0x17,0xC0,0x77, ++ 0xC0,0x6C,0x82,0x3C,0xC0,0x74,0x82,0x34,0xC0,0x5C,0x82,0x0C,0xC0,0x64,0x82,0x04, ++ 0xC4,0x7C,0xE1,0x00,0x3C,0x00,0x7C,0x00,0x50,0x5A,0xB4,0xA2,0xE8,0x98,0xB0,0xCA, ++ 0x31,0x62,0x74,0x45,0xB1,0x8A,0xC1,0x7C,0xB0,0x82,0x80,0x24,0xC0,0x7C,0xB1,0xC2, ++ 0x81,0x1C,0xD0,0x7C,0xB0,0x82,0x85,0x14,0xC0,0x74,0x41,0x09,0x88,0x5E,0xC0,0x24, ++ 0x12,0x02,0x92,0x05,0x80,0x24,0xC0,0x1C,0x12,0x02,0x92,0x05,0x80,0x1C,0xC0,0x14, ++ 0x12,0x02,0x92,0x05,0x80,0x14,0x00,0x01,0x83,0x2C,0xE0,0x68,0xAD,0xF4,0x01,0x9F, ++ 0x40,0x61,0x98,0x66,0xC8,0x24,0xC0,0x34,0xD2,0x4C,0xD1,0x00,0x4C,0x9D,0xA1,0x42, ++ 0xC8,0x1C,0xC0,0x3C,0xD2,0x4C,0xD1,0x00,0x4C,0x85,0xA1,0x42,0x00,0x47,0x15,0x01, ++ 0xDC,0x0C,0x00,0x28,0xF0,0xD2,0x5C,0x45,0x88,0xD2,0x12,0x01,0x90,0x6C,0xD1,0x3C, ++ 0x92,0x95,0x92,0x0C,0xD2,0x34,0x90,0x95,0x91,0x04,0xD2,0x6C,0x50,0x09,0x88,0x3E, ++ 0x12,0x12,0x93,0xA5,0x32,0x12,0x13,0x92,0x94,0x95,0x32,0xA2,0x12,0x4A,0x92,0x4D, ++ 0xD2,0x0C,0xDA,0x04,0xF0,0x0C,0x00,0x07,0x01,0xEF,0xB4,0x1C,0xF1,0x04,0xB0,0x5C, ++ 0x01,0x70,0xB2,0xFC,0x22,0x12,0x93,0x95,0xCA,0xD8,0x90,0xDD,0xF9,0x1C,0xF1,0xFC, ++ 0xC9,0xB0,0xB7,0x1C,0xF3,0x5C,0xC1,0xB0,0xB0,0x5C,0x51,0x01,0xD9,0xBE,0xF0,0xCC, ++ 0x10,0x92,0xD5,0xA6,0x58,0x01,0xD8,0x96,0xF5,0xC4,0x11,0x9A,0xD1,0x7E,0xF8,0x1C, ++ 0x35,0x01,0xF8,0xF2,0xF9,0x5C,0xC1,0xFB,0x48,0xF8,0x8D,0x46,0xFD,0xD4,0x11,0xF2, ++ 0xE8,0x2E,0x78,0x45,0xCD,0xFA,0xCB,0xF0,0x7B,0x45,0x88,0xF2,0x39,0xD7,0xD6,0x6C, ++ 0xE6,0x90,0x92,0x95,0x91,0x6C,0xD1,0x6C,0x55,0x11,0x98,0xF6,0x41,0x01,0x80,0xF6, ++ 0xF2,0x10,0xF2,0x4C,0x00,0x90,0x5C,0x45,0xC7,0xD2,0xD4,0xB3,0xCC,0xDA,0xCA,0xB0, ++ 0x11,0xF2,0x94,0x86,0xD0,0x2C,0x50,0x09,0x88,0x8E,0xD1,0x24,0xC1,0x34,0xD8,0x4C, ++ 0xD1,0x00,0x54,0x9D,0xA0,0x82,0xDE,0x1C,0xD1,0x3C,0xE8,0x4C,0xD1,0x90,0x5E,0x85, ++ 0xA8,0xD2,0xEA,0x14,0xDA,0x04,0xD8,0xE8,0x36,0x1A,0xD3,0x90,0x90,0x95,0xDA,0x00, ++ 0x93,0x1D,0xD2,0x40,0x2C,0x01,0x38,0x01,0x50,0x01,0xD8,0x56,0xF5,0xCC,0x11,0x92, ++ 0xD0,0x3E,0x58,0x01,0xD9,0x2E,0xF0,0xC4,0x10,0x9A,0xD5,0x16,0xC1,0x33,0x18,0xF2, ++ 0x83,0x33,0x20,0x12,0x90,0x95,0xCA,0xD8,0x92,0xDD,0xC2,0x00,0xE7,0x68,0x93,0x6D, ++ 0x6F,0x11,0xC8,0x4E,0x04,0xE7,0x10,0x9A,0x90,0x0E,0x10,0x09,0x90,0x2C,0xD8,0x24, ++ 0xD6,0x34,0xC0,0x90,0x90,0x95,0x96,0x34,0xD8,0x1C,0xD0,0x3C,0xC6,0x90,0x96,0x95, ++ 0x90,0x3C,0xD0,0x14,0xDA,0x0C,0x00,0x90,0xC0,0x90,0x96,0x0C,0xD8,0x14,0xD0,0x04, ++ 0xC0,0x90,0x96,0x04,0xE6,0x00,0x92,0x05,0xD4,0xF4,0x11,0x82,0x92,0x06,0x38,0x3F, ++ 0xC2,0x74,0xE1,0x00,0x91,0x05,0x86,0x74,0xC0,0x74,0x41,0x11,0x97,0x06,0x30,0xAF, ++ 0xC2,0x7C,0xE1,0x00,0x91,0x05,0x86,0x7C,0xC0,0x7C,0x41,0x21,0x97,0x06,0x30,0x37, ++ 0x00,0x0F,0x00,0x41,0x81,0x64,0xC1,0x64,0x41,0x41,0x88,0xD6,0x10,0x01,0x00,0x01, ++ 0x58,0x8A,0xE8,0xC8,0xB4,0xF2,0xB4,0x7A,0x31,0x8A,0x31,0xDA,0x40,0x09,0x88,0x1E, ++ 0x12,0x4A,0x92,0x4D,0x12,0xDA,0x92,0xDD,0xE7,0x6C,0xC2,0x18,0x92,0xDD,0xE2,0x74, ++ 0xC2,0x08,0x93,0x65,0x04,0x08,0xC4,0x48,0x90,0x4D,0x5E,0x01,0xD9,0x76,0xE8,0xCC, ++ 0x10,0x5A,0xD5,0x5E,0x60,0x01,0xD8,0x4E,0xED,0xC4,0x11,0x62,0xD1,0x36,0x68,0x9D, ++ 0xA1,0x62,0x63,0x85,0xA0,0x1A,0x03,0x3F,0x70,0x92,0x07,0x00,0x62,0x9D,0xD9,0x74, ++ 0xA1,0x1A,0x63,0x85,0xDB,0x6C,0xA2,0x1A,0xE6,0x00,0x92,0x05,0x46,0x11,0x98,0x9E, ++ 0xE6,0x90,0x92,0x95,0x56,0x21,0x98,0x56,0x58,0x85,0xD9,0xC3,0xA8,0xC3,0xC0,0xC3, ++ 0x90,0xC3,0x00,0x01,0x81,0xFC,0x58,0x85,0xD8,0xC3,0xA8,0xC3,0xC0,0xC3,0x90,0xC3, ++ 0x00,0x01,0x80,0xE4,0x30,0x3A,0x80,0xEC,0xC4,0xAC,0xCA,0x03,0x80,0xD4,0x01,0x01, ++ 0x0E,0x01,0x00,0x18,0x54,0xA5,0xC0,0xD0,0x32,0xA2,0x04,0x20,0xC6,0x10,0x93,0x95, ++ 0x6D,0x9D,0xE1,0x72,0x33,0x2A,0xA3,0x72,0x6D,0x85,0xE1,0x6A,0x32,0x12,0xC3,0x90, ++ 0x8A,0xAB,0xE0,0x48,0x90,0x4D,0x4E,0x19,0x98,0x86,0x47,0x09,0x80,0x0E,0x40,0x19, ++ 0x88,0x66,0x60,0xA5,0xE3,0x0A,0x37,0x12,0xCB,0x93,0x30,0x2A,0xC7,0x6B,0xA5,0x2A, ++ 0x34,0x1A,0xCB,0xE3,0x8C,0xE3,0x80,0xCB,0x34,0x0A,0x8B,0x53,0x09,0x09,0x88,0x0C, ++ 0x09,0x01,0x88,0x74,0xD3,0x74,0x31,0x0A,0xE1,0x4A,0xDC,0x74,0x36,0x12,0xC3,0x90, ++ 0xCA,0x9B,0xC0,0xAB,0xC9,0x93,0x92,0x14,0xD0,0x74,0x51,0x01,0x88,0x16,0x41,0x01, ++ 0x80,0x0E,0x40,0x19,0x8D,0x5E,0x10,0x4A,0x98,0x4E,0x10,0x09,0x90,0x04,0x41,0x01, ++ 0x8A,0x16,0xF0,0x10,0x90,0x0C,0x01,0xF7,0x11,0x09,0x90,0x0C,0x00,0xDF,0x40,0x09, ++ 0x80,0x0E,0x40,0x11,0x8D,0x5E,0x10,0x4A,0xC0,0x4E,0x10,0x09,0x90,0x04,0x41,0x09, ++ 0x8C,0x16,0xF0,0x10,0x90,0x0C,0x01,0x77,0x11,0x09,0x90,0x0C,0x00,0x5F,0x10,0x01, ++ 0x90,0x04,0x01,0x47,0x11,0x09,0x90,0x04,0x40,0x11,0x90,0x16,0xF1,0x90,0x94,0x0C, ++ 0x00,0x0F,0x10,0x09,0x90,0x0C,0x41,0x01,0x80,0x0E,0x40,0x19,0x8D,0x0E,0x10,0x4A, ++ 0x90,0x2E,0x40,0x09,0x80,0x0E,0x40,0x11,0x8D,0x26,0x10,0x4A,0xC0,0x16,0x10,0x09, ++ 0x94,0x54,0x01,0x8F,0x11,0x01,0x90,0x54,0x01,0x77,0xF4,0xC4,0x33,0x12,0x19,0x92, ++ 0xF1,0xA4,0x92,0xE4,0xC9,0x90,0xF4,0xEC,0xC9,0x90,0x94,0x5C,0xD0,0x5C,0xC1,0x93, ++ 0x92,0xDC,0x31,0x90,0xA1,0xCE,0xD1,0xE4,0xF2,0xA4,0x02,0x90,0xC9,0x90,0xF4,0x3C, ++ 0x04,0xB0,0xCB,0x90,0x35,0x39,0x09,0xB0,0xC8,0xB0,0x14,0xE1,0xF1,0x92,0xF5,0xD4, ++ 0x10,0x92,0xD5,0x26,0xF0,0x64,0x71,0x41,0x88,0xB6,0x50,0x01,0xD9,0xA6,0xF0,0xDC, ++ 0x48,0xB0,0x87,0x06,0x80,0x90,0xF2,0xE4,0xC0,0xB0,0xB5,0xE4,0xF2,0x3C,0x19,0xB2, ++ 0xC8,0xB8,0xF7,0xEC,0x1C,0x12,0xCB,0x90,0x90,0xEC,0xD0,0xFC,0xE4,0x90,0x92,0x95, ++ 0x91,0xFC,0xD0,0xDC,0x48,0x90,0x8E,0xEE,0xD0,0x4C,0xF2,0xF4,0xD5,0x93,0x12,0x92, ++ 0xC1,0x2E,0xD0,0xDC,0x31,0x01,0x1E,0x92,0xF1,0x5C,0x81,0x93,0x01,0x47,0xD0,0xDC, ++ 0x31,0x01,0x1A,0x92,0xF1,0x5C,0x81,0x93,0x01,0x17,0xD0,0x04,0x50,0x09,0x80,0x4E, ++ 0xD0,0x04,0x51,0x09,0x8A,0x36,0xD0,0x6C,0x10,0xA2,0x84,0x1E,0xD5,0x0C,0xC1,0x10, ++ 0x95,0xA5,0x3A,0x57,0x10,0x4A,0x8D,0xDE,0xD4,0x14,0x11,0x9A,0x89,0xC6,0xC8,0x74, ++ 0xE6,0x48,0x92,0x4D,0x89,0x74,0xC9,0x74,0x48,0x11,0x90,0x06,0x3A,0x97,0xE2,0x00, ++ 0x90,0x05,0x46,0x21,0x91,0x06,0x38,0x1F,0xC6,0x34,0xCA,0x03,0x42,0x01,0x88,0x5E, ++ 0xC9,0xAC,0x8A,0x01,0xE0,0x43,0x36,0x10,0xAA,0x36,0x31,0x00,0x71,0x00,0x04,0x27, ++ 0xD0,0x54,0x51,0x01,0x8D,0x5E,0x10,0x4A,0xCA,0x16,0xF0,0x48,0x90,0x4D,0x06,0x1F, ++ 0x10,0x4A,0x95,0x0E,0xE6,0x48,0x92,0x4D,0x11,0x09,0x90,0x54,0x01,0x67,0xD0,0x14, ++ 0x10,0x9A,0xCC,0x16,0xF6,0xD8,0x92,0xDD,0x01,0x27,0xD0,0x14,0x10,0x9A,0x94,0x0E, ++ 0xE6,0xD8,0x92,0xDD,0x11,0x01,0x90,0x54,0x91,0x55,0x92,0x3C,0x97,0xE5,0x72,0xFA, ++ 0xD4,0x3C,0xC9,0x90,0x93,0xEC,0x39,0x47,0x02,0x01,0xD0,0xAC,0x6C,0x94,0x16,0x12, ++ 0x9A,0xD6,0xC0,0xAC,0xE8,0x4B,0x70,0x04,0x10,0x42,0x9C,0x26,0xC4,0x4C,0xD2,0x03, ++ 0xF6,0x00,0x94,0x05,0x02,0x1F,0xC0,0x4C,0xD4,0x03,0xE4,0x00,0x90,0x05,0xCE,0xFC, ++ 0x10,0x0A,0x9C,0x4E,0xC0,0xAC,0x0A,0x01,0xBA,0x0B,0xC0,0x54,0x08,0xD9,0xC7,0x03, ++ 0x02,0x42,0xC8,0x54,0x82,0x43,0x28,0x37,0x27,0x01,0x28,0xF9,0xA8,0x09,0x60,0x01, ++ 0x8A,0x56,0xC0,0x44,0xC8,0xC4,0xB9,0x9C,0xD2,0x34,0x4A,0x93,0x92,0x94,0xD0,0x74, ++ 0x5A,0x3A,0x07,0x90,0xF0,0xF2,0x04,0x57,0xC1,0x3C,0xCA,0xCC,0xD0,0xEC,0x90,0x9C, ++ 0xD4,0x34,0x4A,0x93,0x92,0x94,0xD0,0x6C,0x5A,0x12,0x07,0x90,0xF0,0xF2,0x44,0x01, ++ 0x82,0x16,0xF0,0x48,0x10,0x42,0x8C,0x8E,0xD0,0x74,0x92,0x04,0x91,0x05,0x36,0x0A, ++ 0xDA,0x6C,0xD2,0x5C,0xBB,0xEF,0xD7,0x47,0x35,0x4A,0x11,0x42,0xE8,0x0E,0x30,0x42, ++ 0x00,0x17,0x40,0x01,0xD0,0x06,0x00,0x01,0xC8,0x30,0x04,0x07,0xB0,0x01,0xC4,0x9C, ++ 0xC8,0xE4,0x10,0x00,0x86,0x0F,0xE8,0x27,0xCC,0x94,0xC8,0x00,0x18,0x42,0x42,0x01, ++ 0xD0,0x06,0x00,0x01,0xA0,0x00,0x60,0x01,0x8A,0x7E,0xC8,0x34,0x54,0x4C,0x10,0x0A, ++ 0xD0,0x06,0x30,0x42,0xC8,0xAC,0x12,0x31,0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48, ++ 0x14,0xC9,0x09,0x90,0xC2,0x48,0x04,0x44,0x02,0x77,0xC8,0x34,0x54,0x4C,0x12,0x0A, ++ 0xD0,0x06,0x30,0x42,0xC8,0xAC,0x12,0x31,0xFA,0x4B,0x18,0x8A,0xD4,0xA4,0xC2,0x48, ++ 0x14,0xC9,0x09,0x90,0xC4,0x48,0x04,0x44,0xE7,0x20,0x93,0x25,0x64,0x09,0xC8,0xF6, ++ 0xC0,0xAC,0x12,0x31,0xE0,0x0B,0xC2,0xE4,0x02,0x42,0xCE,0xAC,0xFA,0x4B,0x18,0x8A, ++ 0xD4,0xA4,0xC2,0x48,0x14,0xC9,0x09,0x90,0xC6,0x48,0x04,0x44,0xC2,0xAC,0xCA,0x74, ++ 0xFA,0x03,0x00,0x10,0xC0,0xA4,0xC2,0x90,0x02,0x89,0x0B,0x00,0xC4,0x90,0xA8,0x8B, ++ 0xCA,0xAC,0xD2,0x6C,0xFA,0x4B,0x00,0x58,0xCA,0xA4,0xC2,0xC8,0xC6,0x40,0xA8,0x13, ++ 0xC2,0xAC,0xCA,0xAC,0xFA,0x03,0xE0,0x00,0xBD,0x43,0x20,0xE7,0xAC,0xFD,0x87,0xBD, ++ 0xEC,0x04,0x31,0xA2,0xD8,0x43,0x87,0x84,0xD8,0x43,0x85,0x7C,0xC8,0x43,0x81,0x74, ++ 0x00,0x01,0x80,0x54,0x42,0x22,0x45,0x0B,0x36,0x42,0x81,0x01,0x80,0xB4,0x48,0x01, ++ 0x80,0x1E,0xC0,0x74,0x40,0x00,0x82,0x5C,0x00,0x67,0xC0,0xB4,0xC8,0x03,0x46,0x51, ++ 0x98,0x26,0xC8,0xB4,0x00,0x49,0xB0,0x42,0x80,0x5C,0x00,0x1F,0xC0,0xB4,0x08,0x41, ++ 0xB0,0x0A,0x8A,0x5C,0x40,0xCA,0xD4,0xD4,0xC8,0xBC,0xC0,0x80,0x80,0xAC,0x48,0x01, ++ 0x84,0xF6,0x49,0xBA,0xC2,0xD4,0xC0,0x08,0x10,0x49,0xC5,0xD4,0x04,0x90,0xC4,0x18, ++ 0xE0,0xAC,0xC0,0x74,0x42,0x00,0x12,0x02,0x90,0x05,0x82,0x54,0x30,0x01,0x00,0x7F, ++ 0x00,0x01,0x00,0x47,0x40,0x7C,0x40,0xD4,0xD1,0xD0,0x05,0x14,0xE4,0x20,0xE5,0x48, ++ 0xE2,0xD8,0xE4,0x00,0x90,0x05,0xD6,0x7C,0x17,0x82,0x9C,0x9E,0xE7,0xB0,0x93,0xB5, ++ 0xC4,0x84,0x10,0x32,0x9B,0x66,0x37,0x02,0x40,0x01,0x80,0x06,0x3C,0x02,0x4C,0x2A, ++ 0xC2,0xD4,0xC0,0x18,0x48,0x1A,0xC4,0xD4,0x8A,0xC1,0xC1,0x00,0x50,0x0A,0xCC,0xD4, ++ 0x94,0x81,0xC3,0x48,0x10,0x01,0x00,0x47,0x40,0x24,0x40,0x74,0xD8,0x20,0x05,0xE4, ++ 0xE4,0xD8,0xE4,0x00,0xE2,0x48,0xE4,0x90,0x90,0x95,0xE6,0x7C,0x17,0x12,0x9D,0x9E, ++ 0x48,0x92,0xC3,0xD4,0xC0,0x00,0x82,0x4C,0xE0,0xAC,0x00,0x01,0x81,0x8C,0x30,0x42, ++ 0x80,0x01,0x81,0xA4,0x80,0x01,0x86,0x9C,0x08,0x97,0x32,0x01,0x08,0x47,0xC2,0x4C, ++ 0xC4,0x03,0x48,0x00,0x89,0xF6,0xF3,0x02,0xCC,0x74,0x10,0x42,0xD8,0xD6,0xC3,0x7C, ++ 0x32,0x5A,0x03,0x00,0xD0,0x08,0x31,0x52,0xD6,0x01,0x59,0x94,0x10,0xD4,0x40,0x54, ++ 0x12,0xD4,0x42,0x4C,0x11,0xCC,0x34,0x0A,0xCE,0x01,0x59,0x4C,0x11,0xCC,0x46,0x0C, ++ 0x1B,0xCC,0x40,0x0C,0x18,0xCC,0xCA,0x08,0x31,0x52,0xD0,0x01,0x5C,0x94,0x1E,0xD4, ++ 0xD6,0x02,0x19,0xC4,0x40,0x44,0x22,0xC4,0x40,0x25,0x70,0x01,0x88,0x26,0x08,0x01, ++ 0x16,0xCC,0x10,0xCC,0x18,0xCC,0x04,0x47,0xCA,0x7C,0xF0,0x48,0x10,0x72,0x8C,0x26, ++ 0x0B,0x01,0x30,0x5A,0x12,0xCC,0x1C,0xCC,0x20,0xCC,0xC8,0x8C,0x48,0x01,0x88,0x26, ++ 0x30,0x5A,0x13,0xCC,0x14,0xCC,0x12,0xCC,0x00,0x4F,0xC8,0x84,0xD2,0x8C,0xF0,0x48, ++ 0x10,0x52,0x8C,0x26,0x0B,0x01,0x30,0x5A,0x1E,0xCC,0x1C,0xCC,0x20,0xCC,0x10,0x01, ++ 0xF3,0x12,0x35,0x5A,0x0A,0x81,0xF0,0xCA,0x11,0x8A,0xD4,0x9E,0x0A,0x91,0xF0,0xCA, ++ 0x17,0x8A,0xD4,0xD6,0x0A,0xA1,0xF0,0xCA,0x17,0x8A,0xD4,0xB6,0x0A,0xB1,0xF0,0xCA, ++ 0x17,0x8A,0xD4,0x96,0x0A,0xD1,0xF0,0xCA,0x11,0x8A,0xE4,0x1E,0x0A,0xE1,0xF0,0xCA, ++ 0x17,0x8A,0xE4,0xD6,0x0A,0xF1,0xF0,0xCA,0x17,0x8A,0xE4,0xB6,0x0A,0x01,0xF1,0xCA, ++ 0x17,0x8A,0xE4,0x96,0x0A,0xD1,0xEC,0x4A,0x4B,0x01,0x80,0xCE,0x08,0x01,0x88,0x6C, ++ 0x30,0x72,0x8C,0x1C,0x88,0x64,0xD8,0xBC,0x5A,0x01,0x88,0x1E,0x32,0xE2,0xFC,0x78, ++ 0x1E,0x01,0xF0,0x1A,0x10,0xDA,0xD5,0x46,0xC0,0xC8,0x92,0x4D,0xDA,0x1C,0xE0,0xD8, ++ 0x90,0xDD,0x06,0x07,0x00,0xF7,0x9D,0x1C,0x00,0x2F,0x58,0x51,0xEB,0x1E,0x30,0x9A, ++ 0xE6,0xD8,0x92,0xDD,0x34,0xF2,0xE4,0x00,0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x36,0xE2, ++ 0x30,0x1A,0x5B,0x49,0x9A,0x26,0xC7,0x80,0x90,0x05,0xD0,0xA4,0x70,0x4C,0xE9,0x93, ++ 0x10,0x8A,0x9C,0xB6,0xCC,0x5C,0x10,0x42,0xD3,0x9E,0x30,0x8A,0x48,0x39,0x98,0x36, ++ 0xCA,0x5C,0x80,0x48,0x10,0x0A,0xDC,0x66,0xC0,0x1C,0x40,0x01,0x88,0x4E,0xC0,0xB4, ++ 0xC8,0x03,0x46,0x11,0x98,0x0E,0x00,0x09,0x80,0x6C,0x48,0xDA,0xC2,0x43,0xE2,0x00, ++ 0x80,0x43,0x4A,0xCA,0xC0,0x43,0x40,0x81,0x90,0x26,0x52,0xC2,0xA2,0xB2,0xE0,0x00, ++ 0x81,0x43,0x00,0xFF,0x34,0xB2,0x84,0x98,0xC0,0x98,0x96,0xDD,0x98,0x14,0x18,0x01, ++ 0x30,0xE2,0xDC,0x54,0x80,0xD8,0x9A,0x94,0x1E,0x01,0xF0,0x1A,0xFD,0x94,0x10,0xDA, ++ 0xD3,0x56,0x30,0xBA,0xC9,0xF8,0x96,0xFD,0x30,0xF2,0xFD,0x54,0x10,0xDA,0xD5,0x1E, ++ 0x86,0xB8,0xCA,0xB8,0x90,0xFD,0xB9,0x14,0xC0,0xC8,0x02,0x97,0x60,0x20,0x02,0x00, ++ 0x70,0x72,0x06,0x00,0x70,0x72,0x04,0x00,0x80,0x60,0x07,0x01,0x48,0xE0,0x06,0x00, ++ 0x28,0x60,0x00,0x00,0x68,0x70,0x04,0x00,0x00,0xE0,0x00,0x01,0x80,0xE0,0x06,0x01, ++ 0x00,0xF7,0x90,0x4D,0xE3,0x00,0x34,0x1A,0xE6,0xD8,0x92,0xDD,0x33,0xE2,0x34,0x1A, ++ 0x5E,0x49,0x98,0x8E,0xC4,0x14,0x10,0x0A,0xD8,0x16,0xC8,0x5C,0x28,0x72,0xD4,0x0E, ++ 0x00,0x09,0x80,0x6C,0xC6,0xB4,0xC8,0x03,0x40,0x51,0x98,0x16,0xC0,0xBC,0x40,0x01, ++ 0x80,0x46,0xC8,0x6C,0x00,0x09,0x48,0x01,0x80,0x06,0x00,0x01,0x80,0x64,0x00,0x0F, ++ 0x00,0x09,0x80,0x64,0xC0,0x64,0x40,0x01,0x80,0xA6,0x01,0x09,0xBC,0x43,0x43,0x3A, ++ 0x40,0x03,0x42,0x01,0x88,0x5E,0xC0,0xB4,0xC8,0x03,0x46,0x51,0x90,0x3E,0xC0,0xA4, ++ 0x6E,0x4C,0xE7,0x03,0x32,0x00,0x72,0x00,0x84,0x51,0x10,0x0A,0xC8,0x0E,0x10,0x01, ++ 0x00,0x07,0x10,0x09,0xC0,0xC4,0x40,0x01,0x80,0x06,0x10,0x11,0xC0,0xD4,0x90,0x14, ++ 0x81,0x04,0x30,0x9A,0xA9,0x0C,0x30,0x02,0xD0,0x8C,0xC8,0x4C,0xBA,0xFF,0xD7,0x37, ++ 0xC0,0x9C,0xC0,0x03,0x38,0x00,0xAA,0x1E,0xFF,0x43,0xF9,0x4B,0x10,0x42,0x9C,0x4E, ++ 0xC0,0x9C,0xC0,0x03,0x38,0x00,0xA2,0x1E,0x05,0x01,0xA8,0x43,0xCC,0x9C,0x80,0x43, ++ 0x87,0xDD,0xE8,0x85,0xE0,0x20,0xC5,0x4C,0xE0,0x00,0x82,0x4C,0xE7,0xB0,0x93,0xB5, ++ 0xC4,0x7C,0x10,0x32,0x95,0x06,0x30,0x97,0xC2,0x8C,0xE0,0x00,0x90,0x05,0x86,0x8C, ++ 0xC8,0x84,0xC0,0x8C,0x10,0x42,0x94,0x06,0x37,0x3F,0x3D,0x4F,0xAC,0x9D,0x87,0x0D, ++ 0xD8,0x43,0x80,0x04,0xDB,0x63,0x52,0x12,0xC4,0x0C,0xC0,0x28,0x50,0x02,0xC3,0x0C, ++ 0xD4,0xC1,0xC1,0x30,0xE8,0x43,0x0C,0xF1,0x84,0x0F,0xD8,0x97,0x49,0xE9,0x88,0x0E, ++ 0x48,0xE2,0xC2,0x0C,0xC5,0x10,0x0A,0x49,0xC4,0x0C,0x00,0x48,0xC0,0x08,0x1A,0x01, ++ 0x00,0x5F,0x00,0x01,0x00,0x2F,0x40,0x7C,0x04,0xBC,0xE0,0x90,0xE2,0x48,0xE4,0x00, ++ 0x95,0x05,0x16,0x02,0x9A,0xBE,0xE7,0xD8,0x90,0xDD,0xC6,0x04,0x17,0x1A,0x9C,0x86, ++ 0x00,0x01,0x00,0x2F,0x41,0x8C,0x01,0x4C,0xE5,0x68,0xE5,0xB0,0xE6,0x00,0x92,0x05, ++ 0x17,0x02,0x9D,0xBE,0x48,0x62,0xC2,0x0C,0xC0,0x00,0x12,0x01,0x00,0x67,0x08,0x01, ++ 0x00,0x37,0xC0,0x1B,0x34,0xD8,0x74,0xD8,0x82,0x1B,0xE0,0x00,0xE6,0x48,0x92,0x4D, ++ 0x17,0x0A,0x9D,0xB6,0xE6,0x90,0x92,0x95,0xCC,0x04,0x10,0x52,0x9F,0x7E,0xEF,0xF5, ++ 0xAC,0xFD,0x87,0x1D,0x30,0x6A,0x30,0x01,0xBB,0x73,0xB9,0x73,0x37,0x42,0x81,0x01, ++ 0xC7,0x0B,0x10,0xE9,0x02,0x52,0x38,0x48,0x7A,0x48,0x06,0x48,0x18,0x52,0x80,0x13, ++ 0xC7,0x0B,0x10,0xD9,0x00,0x8A,0x80,0x0B,0x34,0x42,0x81,0x01,0x84,0x14,0xF0,0x03, ++ 0x78,0xB2,0x41,0x01,0x80,0x4E,0x00,0x01,0x57,0xAA,0x09,0xF9,0xA2,0x8A,0xE0,0x00, ++ 0x90,0x05,0x46,0x81,0x99,0xD6,0x87,0xF3,0x80,0xF3,0xAB,0x04,0x00,0x01,0xD8,0x1C, ++ 0xD0,0x34,0xC8,0x2C,0xBD,0xFF,0xEF,0xD7,0x36,0x62,0xA1,0x01,0xC8,0x03,0x47,0x51, ++ 0x98,0x36,0xA8,0x04,0x00,0x09,0xD8,0x1C,0xD0,0x34,0xC8,0x2C,0xBD,0xFF,0xEF,0x77, ++ 0xC4,0x14,0xF0,0x0B,0x49,0x01,0x80,0xD6,0x00,0x01,0x48,0x09,0x8B,0x5E,0xC0,0xD3, ++ 0x50,0x01,0x80,0x46,0x50,0x1A,0xC1,0x93,0x50,0x01,0x88,0x26,0x50,0x12,0xC1,0x93, ++ 0x50,0x01,0x88,0x06,0x00,0x09,0x40,0x01,0x87,0x2E,0xC8,0x13,0x50,0x01,0x95,0x36, ++ 0xE7,0x90,0x8A,0x13,0x07,0x1F,0xC8,0x13,0x50,0x51,0x90,0x06,0x8F,0x33,0xCF,0x13, ++ 0x50,0x51,0x98,0xE6,0x40,0x01,0x88,0x6E,0x48,0x09,0x88,0x16,0xF7,0x90,0x8A,0x13, ++ 0x01,0x47,0x00,0x99,0xEF,0x02,0x6A,0x4C,0x34,0x00,0x72,0x00,0x10,0x0A,0x94,0x0E, ++ 0xF7,0x90,0x8A,0x13,0xC0,0xC3,0x43,0x11,0x9D,0x16,0x00,0x01,0x88,0x03,0x07,0x37, ++ 0x40,0x09,0x88,0x26,0xCA,0x03,0x47,0x81,0x93,0x0E,0x00,0x21,0x89,0x03,0x37,0x4A, ++ 0xC7,0x1C,0xB8,0xFF,0xF8,0xDF,0x81,0x3D,0xE8,0x85,0x07,0x00,0x80,0x60,0x07,0x01, ++ 0x68,0xF0,0x07,0x00,0x28,0x60,0x00,0x00,0x60,0x20,0x02,0x00,0x00,0xE0,0x00,0x01, ++ 0x80,0xE0,0x06,0x01,0x00,0x40,0x00,0x01,0x00,0x48,0x00,0x01,0xAC,0xFD,0x87,0x3D, ++ 0xE0,0x84,0x30,0xB2,0x00,0x01,0x80,0x2C,0xD8,0x83,0x83,0x1C,0x60,0x8C,0x89,0x14, ++ 0xCA,0x44,0x18,0x0A,0x50,0xFA,0xC7,0x3C,0xC0,0x00,0xC4,0x48,0x8F,0x34,0x40,0xF2, ++ 0xC0,0x03,0x40,0x09,0x89,0x0E,0xE0,0x83,0x80,0x1C,0x00,0x01,0x10,0x01,0x00,0x1F, ++ 0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2,0x98,0xC6,0x0F,0x01, ++ 0x00,0x09,0xD8,0x54,0xD0,0x44,0x80,0x07,0xD0,0xAF,0x2E,0x01,0x60,0x01,0x88,0x0E, ++ 0xE7,0x68,0x93,0x6D,0xF8,0x34,0x08,0x01,0x01,0x5F,0xC0,0xC3,0x1E,0x02,0x91,0x05, ++ 0x80,0xC3,0xD1,0x8C,0x10,0x82,0xCC,0x0E,0x19,0x02,0x85,0xC3,0xE2,0xF8,0xE3,0x48, ++ 0x90,0x4D,0xC6,0x1C,0x17,0x0A,0x9C,0x86,0x48,0x42,0xC7,0x3C,0xC0,0x00,0x82,0x24, ++ 0xD0,0x54,0x90,0x04,0x30,0x9A,0x01,0x11,0xD0,0x3C,0xC8,0x44,0x80,0x07,0xD8,0x47, ++ 0xD0,0x54,0x90,0x04,0x04,0x41,0xEA,0x0A,0x00,0x01,0x1C,0x0A,0x30,0x9A,0x11,0x01, ++ 0xC0,0x24,0x80,0x07,0xF6,0x27,0x05,0x29,0xE8,0x02,0x44,0x31,0x88,0x16,0x00,0x01, ++ 0x87,0x5D,0xE8,0x85,0xC1,0x1C,0xD0,0xC0,0x09,0x01,0x00,0x3F,0xD0,0x24,0x18,0x01, ++ 0xF0,0x9A,0xD6,0x14,0xD0,0xD0,0x94,0x95,0x68,0x01,0x88,0x2E,0x50,0xC1,0xE8,0xBE, ++ 0xC5,0x13,0x18,0x12,0x80,0x13,0x00,0x9F,0x50,0x99,0xE8,0x2E,0xC0,0x13,0x50,0x01, ++ 0x82,0x16,0xF0,0x90,0x80,0x13,0x00,0x5F,0x68,0x29,0x88,0x4E,0x58,0xE1,0xEE,0x3E, ++ 0xC0,0x13,0x50,0x01,0x88,0x26,0xD0,0x2C,0x50,0x01,0x88,0x0E,0x10,0x09,0x90,0x2C, ++ 0xD4,0x24,0xE0,0x90,0x92,0x24,0xE0,0x00,0xE6,0x48,0x92,0x4D,0xD4,0x1C,0x10,0x8A, ++ 0x9B,0xA6,0x46,0x20,0x6C,0x21,0xC8,0xCE,0xD0,0x54,0x90,0x04,0x30,0x9A,0x09,0x01, ++ 0x00,0x19,0xD0,0x3C,0x85,0x07,0xD0,0xE7,0x08,0x09,0x30,0x42,0xD8,0x54,0xD0,0x44, ++ 0x83,0x07,0xD0,0x07,0xC5,0x2C,0x38,0xDF,0xAC,0xFD,0x87,0x1D,0xF0,0x64,0x30,0x7A, ++ 0x33,0xEA,0xD8,0xC3,0x85,0x14,0x48,0xAA,0xC2,0x1C,0xC0,0x20,0x40,0x92,0xC5,0x03, ++ 0x40,0x09,0x88,0x0E,0xE0,0xC3,0x81,0x14,0x08,0x01,0x00,0x09,0xD8,0x2C,0xD0,0x6C, ++ 0x82,0x07,0xD0,0x47,0xD0,0x2C,0x90,0x04,0x30,0xDA,0x01,0x11,0xD0,0x1C,0xC8,0x6C, ++ 0x84,0x07,0xD0,0xB7,0xD0,0x2C,0x90,0x04,0x06,0x41,0xEA,0x0A,0x00,0x01,0x1C,0x0A, ++ 0x30,0xDA,0x11,0x01,0x30,0x02,0x81,0x07,0xF0,0x97,0xD1,0x2C,0x91,0x04,0x30,0xDA, ++ 0x08,0x01,0x00,0x19,0xD0,0x1C,0x80,0x07,0xD0,0x1F,0x0C,0x09,0x30,0x42,0xD8,0x2C, ++ 0xD0,0x6C,0x80,0x07,0xD4,0x3F,0x41,0xF2,0x00,0x44,0x01,0x01,0x00,0x84,0x09,0x01, ++ 0x00,0x77,0x00,0x01,0xF0,0x02,0x11,0x01,0xF4,0x52,0x15,0x12,0xE9,0x06,0x00,0x44, ++ 0x15,0x01,0xF0,0x92,0x10,0x12,0xD4,0x06,0x05,0x84,0xE1,0x20,0xE6,0x48,0x92,0x4D, ++ 0xC4,0x14,0x10,0x0A,0x98,0x6E,0x87,0x3D,0xEF,0x85,0xAF,0xBD,0x80,0x55,0xC4,0x5C, ++ 0xD8,0x03,0x86,0x24,0xCA,0x5C,0xD8,0x4B,0x8C,0x1C,0x50,0x52,0xCC,0x54,0xC0,0x48, ++ 0x8C,0x4C,0x48,0x4A,0xC0,0x4B,0x48,0x09,0x88,0x46,0xC8,0x24,0xE6,0x48,0x92,0x4D, ++ 0x88,0x24,0x80,0x3C,0xC0,0x5C,0xE0,0x03,0x80,0x1C,0x00,0x0F,0x00,0x01,0x80,0x3C, ++ 0xF8,0x3C,0xC0,0x5C,0x80,0x01,0x86,0x44,0x04,0x7F,0x4B,0x12,0x04,0x01,0x00,0x43, ++ 0xC0,0x5C,0xC8,0x4C,0xDB,0x03,0x1A,0xC2,0xC0,0x08,0x02,0x01,0x10,0xF9,0x01,0x1F, ++ 0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2,0x9C,0xC6,0x27,0x01, ++ 0x31,0x2A,0x31,0x32,0x03,0xE7,0x40,0xC2,0x08,0x23,0x4E,0x2D,0xB8,0x0C,0x88,0x04, ++ 0x40,0x55,0x40,0x3E,0x5F,0x35,0xB8,0xFF,0xF8,0x7F,0xC3,0x44,0xC8,0x03,0x42,0x31, ++ 0x83,0x7E,0x33,0x5A,0x00,0xC1,0xF0,0xC2,0x40,0xE1,0xD1,0x1E,0x68,0x41,0x80,0x4E, ++ 0x18,0x62,0x05,0x1F,0x70,0x01,0x8C,0x0E,0x30,0x72,0x01,0x1F,0x41,0x68,0x1B,0x62, ++ 0x6F,0x01,0x88,0x06,0xC0,0x5C,0xC8,0x4C,0xDB,0x03,0x1A,0xC2,0xC0,0x08,0x02,0x01, ++ 0x10,0x01,0x00,0x1F,0x82,0x53,0xE0,0x48,0xE6,0x00,0x92,0x05,0xDC,0x1C,0x10,0xC2, ++ 0x99,0xC6,0x37,0xAA,0x20,0x01,0x00,0x0F,0x1B,0xA2,0x41,0xB0,0x77,0x01,0x88,0xDE, ++ 0xC0,0x5C,0x60,0x04,0xC0,0x41,0x91,0x35,0x05,0xAF,0x18,0x62,0x46,0xD2,0x0A,0x23, ++ 0x48,0x2D,0xB8,0x0C,0x88,0x04,0x40,0x55,0x40,0x3E,0x58,0x35,0xB9,0xFF,0xFF,0xA7, ++ 0xC2,0x44,0xC8,0x03,0x42,0x31,0x80,0x6E,0x30,0x5A,0x03,0xA1,0xF5,0xC2,0x10,0x82, ++ 0xE9,0x06,0x18,0x62,0x40,0x68,0x6B,0x01,0x88,0x3E,0xC7,0x54,0x0E,0x59,0xCB,0x00, ++ 0x0A,0x48,0xC2,0x00,0xB3,0x23,0xE0,0xF8,0x90,0xFD,0xC7,0x24,0x14,0x3A,0x9C,0x66, ++ 0xF1,0x3C,0x00,0xA7,0xC3,0x54,0x08,0x59,0xCA,0x00,0x0C,0x48,0xC1,0x38,0xF2,0xC3, ++ 0x40,0x01,0x88,0x0E,0x01,0x09,0xB0,0xC3,0xF0,0xE3,0x29,0x01,0x01,0x01,0x00,0x0F, ++ 0xE7,0x68,0x93,0x6D,0x40,0x09,0x88,0x1E,0x60,0xF9,0x97,0x0E,0xE5,0x20,0x93,0x25, ++ 0x48,0xE2,0x01,0x01,0x00,0x43,0xAC,0x48,0x46,0xDA,0x09,0x23,0x20,0x00,0x67,0x10, ++ 0x00,0x0F,0x00,0xBF,0x40,0x48,0x32,0x82,0x17,0x42,0x80,0xDE,0x48,0x01,0xC9,0x06, ++ 0x08,0x01,0x89,0x04,0x90,0x0C,0x40,0x55,0x41,0x6E,0x30,0x8A,0xBA,0xFF,0xF7,0x77, ++ 0x40,0x01,0x80,0x0E,0x6E,0x29,0x98,0xDE,0xB3,0xE3,0xE1,0xB0,0x90,0xB5,0xC7,0x24, ++ 0x16,0x32,0x9C,0x3E,0x87,0x6D,0xE8,0x85,0xAC,0xBD,0x87,0x15,0x30,0x62,0x30,0xB2, ++ 0x48,0x2A,0x01,0x01,0x81,0x43,0x40,0x4A,0x40,0x0B,0x10,0x11,0x18,0x8A,0x00,0x0B, ++ 0x28,0x01,0x00,0x3F,0x09,0x09,0x30,0x9A,0x30,0x52,0x31,0x42,0x81,0x07,0xC8,0x57, ++ 0xE7,0x68,0x93,0x6D,0xDD,0x03,0x11,0x42,0xC1,0xA6,0x37,0x12,0x30,0x8A,0x01,0x11, ++ 0x84,0x07,0xC0,0x2F,0x31,0x92,0x31,0x0A,0xC7,0x14,0xB8,0xFF,0xF9,0x77,0x30,0x12, ++ 0x30,0x8A,0x01,0x01,0x83,0x07,0xC0,0xDF,0xE0,0x03,0x41,0x01,0x80,0xBE,0x69,0xB2, ++ 0x44,0x43,0x97,0x3D,0x4F,0x04,0x01,0x43,0x40,0x7A,0x08,0x09,0x81,0x0B,0x30,0x12, ++ 0x30,0x8A,0x01,0x11,0x83,0x07,0xC0,0x5F,0x30,0x1A,0xB1,0x04,0x08,0x01,0x00,0x09, ++ 0xD0,0x14,0x80,0x07,0xC8,0xAF,0xB2,0x04,0xD9,0x0B,0x37,0x1A,0x00,0x11,0xD0,0x14, ++ 0x82,0x07,0xC8,0x77,0x31,0x92,0x31,0x0A,0xC7,0x14,0xB8,0xFF,0xF1,0x37,0x37,0x12, ++ 0x30,0x8A,0x01,0x6F,0x60,0x20,0x02,0x00,0x00,0xF0,0x00,0x01,0x48,0xE0,0x06,0x00, ++ 0xF8,0xFB,0x07,0x00,0x10,0x00,0x00,0x42,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42, ++ 0x00,0x01,0x80,0x07,0xC0,0x27,0x42,0x5A,0x08,0x01,0x80,0x0B,0x01,0x7B,0x37,0x1A, ++ 0xB0,0x04,0x08,0x01,0x00,0x11,0xD0,0x14,0x81,0x07,0xC8,0x57,0x31,0x12,0x31,0x8A, ++ 0x00,0x11,0x80,0x07,0xC0,0xA7,0x51,0x22,0x40,0x83,0x08,0x11,0x18,0x42,0x04,0x83, ++ 0x87,0x2D,0xE8,0x85,0x00,0xF0,0x00,0x01,0x18,0x00,0x04,0x42,0xA8,0x85,0x31,0x12, ++ 0x92,0x01,0x46,0x8C,0x80,0x01,0xC7,0x1B,0x32,0xD8,0x72,0xD8,0x87,0x1B,0x58,0xE2, ++ 0x41,0xE3,0x30,0x20,0xA2,0x16,0x40,0xE3,0x3F,0x20,0xAB,0xE6,0x58,0xCA,0x27,0x41, ++ 0x00,0xE3,0x44,0xE3,0x28,0xF9,0xAF,0x19,0x18,0x62,0x01,0xE3,0xC7,0x23,0x48,0x20, ++ 0x8A,0x1E,0xF0,0x48,0x20,0x48,0x60,0x48,0x88,0xC6,0x4F,0x01,0x88,0x36,0x40,0xC3, ++ 0x08,0x81,0x18,0x42,0x07,0xC3,0x00,0xF9,0x82,0x89,0x04,0x84,0xEF,0x85,0xA9,0x85, ++ 0x46,0x63,0x42,0x5B,0xDF,0xAB,0x72,0x62,0xC0,0xB3,0x71,0x09,0x8E,0x16,0x48,0x63, ++ 0x50,0x5B,0xE2,0xAB,0x41,0x01,0x88,0x0E,0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32, ++ 0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33,0xC1,0xFB,0x18,0xF2, ++ 0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3, ++ 0x1B,0x82,0x35,0x32,0x00,0x83,0x41,0x73,0xC4,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20, ++ 0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85,0x41,0x09,0x88,0x0E, ++ 0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42, ++ 0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3,0x1B,0x82,0x35,0x32,0x00,0x83,0x41,0x73, ++ 0xC0,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52, ++ 0x9F,0x06,0xEF,0x85,0x41,0x11,0x88,0x0E,0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32, ++ 0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42,0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2,0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3, ++ 0x1B,0x82,0x31,0x32,0x00,0x83,0x41,0x73,0xC4,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20, ++ 0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52,0x9F,0x06,0xEF,0x85,0x47,0x19,0x88,0xE6, ++ 0x10,0x01,0x00,0xE7,0x40,0x03,0x31,0x32,0xB5,0x41,0x30,0xA2,0xE8,0x08,0x30,0x42, ++ 0xC4,0x01,0x5A,0x33,0xC5,0xFB,0x18,0xF2,0x1E,0x33,0x5C,0x33,0xC5,0xFB,0x18,0xF2, ++ 0x1B,0x33,0x36,0x32,0x40,0x83,0xC1,0xF3,0x1B,0x82,0x31,0x32,0x00,0x83,0x41,0x73, ++ 0xC0,0xC3,0x18,0x32,0x01,0x73,0xE8,0x20,0xE2,0xD8,0xE2,0x90,0x95,0x95,0x16,0x52, ++ 0x9F,0x06,0xEF,0x85,0xAA,0x85,0x47,0xE3,0x05,0xB0,0xCC,0x20,0x45,0xEB,0xC6,0x68, ++ 0x40,0x09,0x88,0x26,0x45,0xE3,0xC8,0x20,0x44,0xDB,0xC4,0xE8,0x04,0x3F,0x78,0xD2, ++ 0xC0,0xFB,0x79,0x09,0x8E,0x1E,0x48,0xE3,0xCA,0x20,0x55,0xDB,0xC1,0xE8,0x44,0x13, ++ 0xF9,0xA0,0xC0,0x5B,0x40,0x09,0x88,0x76,0x48,0x01,0x88,0x66,0x44,0x83,0x1A,0xC2, ++ 0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83,0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83, ++ 0x18,0xC2,0x00,0x83,0xE8,0x85,0x4F,0x09,0x8A,0x66,0x40,0x83,0x1A,0xC2,0x04,0x83, ++ 0x44,0x83,0x1C,0xC2,0x00,0x83,0x44,0x83,0x18,0xC2,0x04,0x83,0x40,0x03,0x19,0xC2, ++ 0x07,0x03,0xE9,0x85,0x48,0x11,0x88,0x66,0x44,0x03,0x19,0xC2,0x00,0x03,0x41,0x83, ++ 0x18,0xC2,0x04,0x83,0x40,0x83,0x1A,0xC2,0x04,0x83,0x42,0x83,0x1C,0xC2,0x04,0x83, ++ 0xE8,0x85,0x4F,0x19,0x89,0xE6,0x47,0x03,0x19,0xC2,0x04,0x03,0x44,0x83,0x18,0xC2, ++ 0x02,0x83,0x40,0x83,0x1A,0xC2,0x04,0x83,0x40,0x83,0x1C,0xC2,0x07,0x83,0xEC,0x85, ++ 0xA8,0xFD,0xF7,0x4C,0x30,0x62,0x2C,0x01,0x4D,0x93,0x49,0x8B,0x32,0x72,0xDC,0xE3, ++ 0x33,0x3A,0x49,0x8A,0xC0,0x4B,0x48,0x09,0x89,0x0E,0x50,0x93,0xE0,0xE3,0x40,0x19, ++ 0x80,0x96,0x31,0x79,0x49,0x5A,0x13,0xB0,0x40,0x11,0x88,0xB6,0x32,0x02,0x1B,0x3A, ++ 0x58,0x52,0xC3,0x14,0xC1,0x00,0xC6,0xC0,0x33,0x9A,0x33,0x2A,0xEA,0xDA,0x0A,0x5B, ++ 0x08,0x01,0x00,0x3F,0xC1,0x1B,0x18,0x9A,0x41,0xAB,0x00,0x5B,0xEA,0x90,0xE0,0x00, ++ 0xE6,0x48,0x92,0x4D,0x17,0x0A,0x9D,0xAE,0xE8,0xFD,0x47,0x01,0x88,0x8E,0x18,0x01, ++ 0x12,0x5B,0x46,0xDA,0x45,0x33,0x40,0xB0,0x00,0xB0,0x05,0x33,0x00,0x1B,0x02,0x5B, ++ 0x40,0x0B,0x18,0x81,0x18,0xCA,0x04,0x0B,0x44,0x0B,0x18,0x01,0x18,0xCA,0x00,0x0B, ++ 0x00,0x17,0x40,0x09,0x89,0x06,0x30,0xAA,0x00,0x01,0x00,0x27,0x40,0x8B,0x00,0x6B, ++ 0xEA,0x90,0xE0,0x00,0x95,0x05,0x16,0x02,0x9F,0xC6,0xEF,0xFD,0x3B,0x82,0xAB,0x85, ++ 0x4A,0xA3,0xD8,0xEB,0x33,0x70,0x72,0xB0,0x48,0x5A,0xC2,0x4B,0x48,0x09,0x88,0x0E, ++ 0x50,0xA3,0xE0,0xEB,0x08,0x01,0x00,0x3F,0x42,0x13,0x41,0x93,0x00,0x92,0x07,0x14, ++ 0xEC,0x20,0xE1,0x00,0xE6,0x48,0x92,0x4D,0x17,0x4A,0x9D,0xAE,0xEB,0x85,0xAB,0xC5, ++ 0x30,0x2A,0x30,0xB2,0x61,0xF2,0x41,0x03,0x14,0x01,0x1C,0x82,0x01,0x03,0x41,0x03, ++ 0x10,0x81,0x18,0x82,0x01,0x03,0x41,0x03,0x10,0x09,0x18,0x82,0x07,0x03,0xE1,0x53, ++ 0x00,0xF9,0x87,0x81,0x19,0x12,0x40,0xBA,0x10,0x13,0x16,0x99,0x00,0x13,0x13,0x41, ++ 0x04,0x13,0x14,0xD9,0xE8,0x92,0x52,0x01,0x80,0x16,0x10,0xC9,0x00,0x13,0x00,0x0F, ++ 0x10,0x89,0x00,0x13,0x31,0x52,0x30,0x5A,0x08,0x01,0x00,0x09,0xB7,0x04,0xB8,0xFF, ++ 0xF9,0x7F,0x33,0x52,0x30,0x8A,0x01,0x11,0xBB,0xFF,0xF7,0xCF,0x42,0x03,0x3B,0x00, ++ 0xAB,0xE6,0xEF,0xC5,0xAC,0x9D,0x87,0x8D,0xCA,0x94,0xC8,0x4B,0x88,0x84,0xE0,0x94, ++ 0xA7,0x01,0xD2,0x1B,0xD8,0x0B,0x89,0x04,0xCA,0x94,0xD8,0x6B,0x30,0x0A,0x88,0x71, ++ 0x30,0x62,0xCC,0x94,0x30,0x01,0xE8,0x4B,0x48,0x09,0x88,0x56,0x08,0x01,0x00,0x27, ++ 0xC5,0x38,0x9A,0xF3,0xA2,0x32,0xE2,0x48,0x90,0x4D,0xD2,0x94,0xDC,0x93,0x12,0x52, ++ 0xE0,0xB6,0x57,0xDA,0x04,0xB3,0x02,0xB3,0x00,0xB3,0x0E,0x01,0x18,0x4A,0x06,0x8B, ++ 0xCA,0x94,0xD8,0x4B,0xB0,0x8B,0x08,0x01,0x50,0xAA,0x30,0x01,0x05,0x78,0xC4,0xF8, ++ 0x0A,0xF3,0xC1,0x90,0xB2,0xB3,0xE2,0x48,0x90,0x4D,0x4A,0x11,0xD8,0xA6,0xCF,0x94, ++ 0xE8,0x4B,0x48,0x29,0xCD,0xF6,0x03,0x48,0xC3,0x48,0x00,0x50,0xC0,0x70,0x54,0x6A, ++ 0xC0,0xB0,0xB5,0x14,0xC0,0x48,0x8C,0x0C,0x30,0x12,0x33,0x32,0xB0,0xE1,0x08,0x01, ++ 0x88,0x34,0x48,0x4A,0x88,0x6C,0x88,0x64,0x30,0x32,0x04,0x01,0x32,0x22,0x04,0x97, ++ 0x18,0x00,0x04,0x42,0x00,0x01,0x00,0x42,0x00,0xF0,0x00,0x01,0x60,0x20,0x02,0x00, ++ 0x80,0x60,0x07,0x01,0x48,0xE0,0x06,0x00,0x78,0xF8,0x07,0x00,0xC8,0x14,0x00,0x01, ++ 0xF0,0x42,0xF8,0x0C,0x0B,0x01,0xF0,0xCA,0x32,0x7A,0xD0,0x08,0x97,0x4D,0x48,0xF9, ++ 0xEF,0x06,0x08,0xF9,0xCB,0x38,0x86,0xF8,0x78,0xF9,0xEF,0x06,0x3B,0xF9,0x37,0x82, ++ 0x82,0x3B,0xE0,0x00,0x30,0x32,0xC4,0xBB,0x10,0xFA,0x9C,0x46,0x10,0xCA,0xDC,0x36, ++ 0x46,0x84,0xD9,0x48,0xC0,0x00,0x92,0x05,0x04,0x84,0x81,0x08,0x04,0x37,0x10,0xCA, ++ 0xDC,0x16,0x00,0x78,0x00,0xBC,0x01,0x0F,0x39,0x01,0x00,0xBC,0x10,0xCA,0xDC,0x0E, ++ 0x38,0x09,0xB8,0x34,0x43,0x78,0x2B,0x3A,0xE8,0x26,0xF8,0x6C,0x10,0x7A,0xEC,0x2E, ++ 0x88,0x6C,0x00,0x1F,0xFC,0x64,0x10,0x7A,0xE8,0x06,0x88,0x64,0x82,0x8B,0xE0,0x90, ++ 0xE0,0xB0,0xC5,0x14,0xE0,0x00,0x84,0x14,0xC4,0x0C,0xE0,0x00,0x83,0x0C,0x30,0x02, ++ 0xE2,0x00,0x92,0x05,0x35,0x22,0x2C,0x62,0xD8,0xC6,0xC5,0x34,0x40,0x01,0x80,0x8E, ++ 0x08,0x01,0x00,0x01,0x80,0x5C,0xC0,0x04,0xC2,0x00,0x46,0x00,0x80,0x7C,0xC0,0x04, ++ 0x30,0x00,0x72,0x00,0x80,0x74,0x00,0x01,0x30,0x22,0x84,0x2C,0x80,0x24,0x80,0x1C, ++ 0xF0,0x90,0x02,0x07,0x03,0x1F,0xF5,0x40,0x94,0x05,0x32,0x32,0x03,0xFF,0x31,0x02, ++ 0x04,0x00,0x32,0x22,0xC2,0x2C,0x00,0x00,0x80,0x2C,0xC0,0x24,0x00,0x00,0x82,0x24, ++ 0xC2,0x1C,0x00,0x00,0x83,0x1C,0x40,0x40,0x28,0x82,0xEB,0x26,0xC0,0x83,0xF0,0x6C, ++ 0xD8,0x00,0x84,0x83,0x00,0x1F,0xC0,0x83,0xF4,0x64,0xD8,0x00,0x80,0x83,0xC0,0x83, ++ 0x73,0x3D,0x30,0xBA,0xA8,0x82,0xC7,0x83,0x10,0xC2,0xDC,0xDE,0xE2,0x48,0x92,0x4D, ++ 0xF1,0x5C,0xC0,0xB0,0x90,0xB5,0xB1,0x5C,0x30,0x32,0x3B,0x09,0x1D,0xF2,0x31,0xA2, ++ 0xF5,0x7C,0x10,0x82,0xD8,0x76,0xF0,0x2C,0x18,0xF2,0xB1,0x2C,0xF5,0x04,0x10,0x82, ++ 0xD8,0x46,0xF0,0x24,0x18,0xF2,0xB1,0x24,0xF5,0x74,0x10,0x82,0xD8,0x16,0xC0,0x1C, ++ 0x18,0xC2,0x81,0x1C,0xF3,0x90,0x32,0x82,0xF2,0x00,0x92,0x05,0x33,0x32,0x34,0x82, ++ 0x45,0x01,0xD0,0xE6,0x42,0xE2,0xB7,0x0B,0xD0,0x50,0xB3,0x13,0x36,0x12,0x1B,0x92, ++ 0x03,0x13,0x30,0x12,0x08,0x13,0xD0,0x2C,0x00,0x13,0xD2,0x24,0x00,0x13,0xD4,0x1C, ++ 0x00,0x13,0x36,0x01,0x00,0xA7,0xC1,0x5C,0x86,0x07,0xE8,0xA7,0x90,0x05,0x80,0x5C, ++ 0x4D,0x8A,0x07,0x80,0xC0,0x00,0x4A,0x13,0x40,0x3D,0x08,0x01,0x1C,0x01,0x30,0xF2, ++ 0x30,0xE2,0x04,0xCF,0x38,0x98,0x86,0x7E,0xC0,0x1B,0xF8,0x5C,0xD8,0xD8,0x96,0xDD, ++ 0x58,0x01,0xE8,0x36,0x83,0x1B,0x20,0x9A,0x94,0xDD,0x36,0xF2,0xE2,0x48,0x92,0x4D, ++ 0x00,0x27,0x18,0x01,0x80,0x1B,0x00,0x0F,0x18,0x01,0x80,0x1B,0x42,0x90,0xE2,0x00, ++ 0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x32,0xE2,0x2F,0x62,0xDD,0x1E,0xE3,0xB0,0x93,0xB5, ++ 0x30,0x82,0x83,0x5C,0x45,0xE2,0x06,0x98,0xC0,0xD8,0x08,0xD3,0xCA,0x00,0xB4,0x0B, ++ 0x48,0x21,0xD8,0x0E,0x76,0x09,0xD8,0x36,0x06,0x01,0x50,0xBA,0x04,0x08,0xC4,0x58, ++ 0xE4,0x08,0x02,0x70,0xC0,0xB0,0x4D,0xEB,0x4D,0xB3,0x19,0xAA,0x08,0xEB,0xC0,0x80, ++ 0xF4,0x1B,0xF2,0x2B,0xDA,0xD8,0xB2,0x1B,0x90,0x45,0x42,0x09,0xD8,0x76,0x07,0x09, ++ 0xA6,0x03,0x43,0x6A,0x0E,0x19,0x40,0x13,0x50,0x01,0x80,0x16,0x03,0x29,0xA0,0x0B, ++ 0x04,0xF7,0x40,0x13,0x50,0x01,0x80,0x16,0x03,0x21,0xA0,0x0B,0x02,0xC7,0x40,0x0B, ++ 0x48,0x01,0x80,0x1E,0x00,0x19,0x08,0x11,0xA0,0x0B,0x03,0x8F,0x48,0x03,0x40,0x01, ++ 0x88,0x26,0xC0,0x94,0x86,0x01,0xCE,0x03,0x40,0x51,0x98,0x0E,0x00,0x11,0x00,0x3F, ++ 0xC1,0x94,0x80,0x01,0xE0,0x03,0x44,0x01,0x80,0x0E,0x00,0x11,0x00,0x07,0x00,0x09, ++ 0xE4,0x0B,0xE3,0x50,0xA3,0x13,0xDD,0x13,0x38,0x90,0xA2,0x0E,0xF3,0x48,0xA2,0x0B, ++ 0xE8,0x0B,0x13,0x29,0x10,0x0A,0x94,0x0E,0xA8,0x13,0x01,0xEF,0x10,0x0A,0xCC,0x46, ++ 0x40,0x09,0x88,0x16,0x09,0x81,0xAF,0x0B,0x00,0xB7,0xD0,0x48,0x01,0x52,0xAC,0x13, ++ 0x00,0x97,0x40,0x19,0xC8,0x0E,0x08,0x19,0x02,0x07,0x90,0x0D,0xE8,0x13,0x51,0x01, ++ 0x82,0x16,0xF0,0x90,0xA8,0x13,0x01,0x3F,0xD2,0x94,0xF0,0x48,0xCA,0x93,0x1C,0x52, ++ 0xCA,0x84,0xC0,0x88,0xD0,0x94,0x88,0x8B,0xA8,0x03,0x83,0x9D,0xEF,0x85,0xAF,0xBD, ++ 0x80,0x6D,0x34,0x6A,0xD9,0x63,0x33,0x42,0x80,0x01,0x82,0x64,0xD0,0x03,0x84,0x3C, ++ 0xC2,0x64,0xD8,0x03,0x30,0x00,0xA8,0x1E,0x02,0xD9,0xEC,0x02,0x40,0x01,0x80,0xA6, ++ 0xC5,0x6C,0x00,0x08,0xC3,0x40,0x00,0x08,0x52,0xC2,0xC4,0x08,0xC4,0x48,0xC4,0x10, ++ 0x00,0x01,0x18,0x01,0x00,0x2F,0x00,0x5C,0x04,0x9C,0xE0,0x48,0xE2,0x90,0xE4,0x00, ++ 0x95,0x05,0x12,0x02,0xD8,0xBE,0x87,0x85,0xEB,0x85,0x07,0x59,0xCA,0x6C,0x08,0x00, ++ 0xC4,0x40,0x70,0x7A,0xF7,0x03,0x08,0x83,0xD0,0x7C,0x90,0x04,0x30,0x5A,0x09,0x01, ++ 0x00,0x11,0xD0,0x6C,0xBB,0xFF,0xEF,0xE7,0x42,0x4A,0x84,0x01,0x43,0x0B,0x30,0x5A, ++ 0x09,0xCC,0x5C,0x8B,0x0B,0xCC,0x5E,0x8B,0x15,0xCC,0x58,0x8B,0x17,0xCC,0x42,0x8B, ++ 0x14,0xCC,0x4C,0x22,0x46,0x53,0x10,0xD4,0x48,0x93,0x1F,0xD4,0x17,0x89,0x00,0x93, ++ 0x13,0x19,0x18,0x93,0x40,0x53,0x18,0x11,0x18,0xD2,0x04,0x53,0x40,0x0B,0x18,0xCA, ++ 0x01,0x0B,0x30,0x42,0xE9,0x4B,0x81,0x01,0x80,0x5C,0x48,0x09,0x8D,0x5E,0x6A,0x44, ++ 0x81,0x14,0x30,0x8A,0x5E,0x43,0x94,0x35,0xB0,0x0C,0x00,0x01,0x80,0x04,0xD0,0x6C, ++ 0x4F,0x92,0x03,0x00,0xC2,0x00,0xC4,0x00,0x83,0x54,0x40,0x8A,0x18,0x33,0x0A,0x01, ++ 0x37,0x42,0xB9,0xFF,0xE0,0x5F,0xF9,0x54,0xC1,0x64,0x30,0x5A,0xD1,0x0B,0x32,0xC2, ++ 0xD7,0x7C,0xB8,0xFF,0xEB,0x67,0x4C,0x62,0x10,0x01,0x00,0x01,0x02,0x67,0x00,0x18, ++ 0x37,0xE2,0xF4,0xDA,0x10,0x5A,0xD4,0x0E,0x33,0x0A,0xD3,0xCA,0x10,0x9A,0xEC,0x0E, ++ 0x35,0x12,0xD3,0xD2,0xE2,0x00,0x92,0x05,0x17,0x02,0xDD,0x86,0xC4,0x14,0xE0,0x00, ++ 0x10,0x0A,0x9C,0x36,0xC0,0x04,0x40,0x01,0x8B,0x9E,0x40,0x80,0x40,0x08,0xC2,0x70, ++ 0x00,0x3F,0xC0,0x14,0xF4,0x00,0x14,0x12,0xE0,0x5E,0x00,0x09,0x83,0x04,0xE0,0xB0, ++ 0x90,0xB5,0x77,0x01,0x80,0x16,0xC0,0x0C,0x16,0x32,0x9C,0x36,0x70,0x01,0x88,0x06, ++ 0x30,0x09,0xC0,0x5C,0x90,0x33,0xC0,0x5C,0xD2,0x0B,0x40,0x8A,0x18,0x0B,0x32,0x01, ++ 0x36,0x42,0x81,0x01,0x81,0x4C,0x80,0x01,0x83,0x44,0x00,0x37,0xC4,0x3C,0x10,0x32, ++ 0xD0,0x6E,0xC0,0x44,0xC0,0x03,0xC8,0x44,0x32,0x00,0x72,0x00,0x82,0x43,0x40,0x42, ++ 0x0C,0x41,0x00,0x0B,0x47,0x0B,0x10,0xF9,0x90,0x21,0x18,0x8A,0x00,0x0B,0xC8,0x6C, ++ 0x02,0x00,0xC5,0x08,0x02,0x00,0x53,0x0A,0xC4,0x40,0xC0,0x00,0xC0,0x48,0x74,0x01, ++ 0x88,0x66,0x10,0x01,0x78,0x02,0x02,0x37,0x18,0x01,0x00,0x1C,0x04,0x7C,0xE0,0x00, ++ 0xE2,0x48,0xE4,0x90,0x95,0x95,0x12,0x12,0xD9,0xB6,0x07,0x07,0xDF,0x6C,0x00,0x10, ++ 0xC1,0x90,0x5E,0xB2,0xC4,0x90,0x36,0xA2,0x18,0x01,0x00,0x9F,0x30,0x3A,0x13,0x01, ++ 0xF0,0xD2,0x3D,0x01,0xFC,0x3A,0x16,0xBA,0xD0,0x06,0x00,0x14,0x3E,0x01,0xF8,0x7A, ++ 0x10,0xBA,0xEC,0x06,0x04,0x54,0xE0,0x00,0xE3,0x48,0x34,0x12,0xE4,0x90,0x34,0xA2, ++ 0xE2,0xD8,0x92,0xDD,0x17,0x1A,0xDD,0x4E,0xC4,0x3C,0x10,0x32,0x80,0x06,0xC1,0x44, ++ 0xC6,0x03,0x48,0x00,0x88,0x1E,0xC0,0x4C,0xC8,0x03,0x42,0x31,0x88,0xBE,0xC7,0x4C, ++ 0xC8,0x03,0x42,0x31,0x89,0x26,0x40,0x12,0x40,0x0B,0x10,0x81,0x18,0x8A,0x00,0x0B, ++ 0xCF,0x6C,0x00,0x00,0xC0,0x00,0x4A,0xEA,0xC0,0x00,0xCA,0x64,0x32,0x5A,0xD1,0x4B, ++ 0xD7,0x7C,0xB8,0xFF,0xE3,0x67,0xE7,0xB0,0x90,0xB5,0xC3,0x3C,0x14,0x32,0xEC,0xAE, ++ 0x43,0xBA,0x30,0x5A,0x4A,0xCC,0x84,0x01,0x00,0x0B,0x40,0xAA,0x48,0xCC,0x1E,0x0B, ++ 0x52,0xCC,0x18,0x0B,0x54,0xCC,0x1A,0x0B,0x56,0xCC,0x04,0x0B,0x4E,0x8A,0x50,0xD4, ++ 0x00,0x53,0x58,0xCC,0x0F,0x0B,0x36,0xB7,0xAA,0x85,0xD8,0xE3,0x1A,0x0A,0x03,0x48, ++ 0xC5,0x50,0x0C,0x49,0x02,0x48,0xC4,0x88,0xE8,0xD3,0x50,0x11,0xC0,0x4E,0x10,0x01, ++ 0x00,0x2F,0x40,0x1C,0x04,0x5C,0xE0,0x48,0xE2,0x00,0xE4,0x90,0x95,0x95,0x12,0x12, ++ 0xD8,0xBE,0x17,0x01,0x00,0x87,0x00,0x00,0x80,0x60,0x07,0x01,0x48,0xE0,0x06,0x00, ++ 0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42,0xF8,0xFB,0x07,0x00,0x40,0x1C,0x00,0x5C, ++ 0xE4,0x00,0xE4,0x48,0xE2,0x90,0x92,0x95,0x17,0x12,0xDD,0xBE,0xEF,0x85,0xA8,0x85, ++ 0x30,0x6A,0xF0,0x2C,0x30,0x22,0x30,0x8A,0x31,0xFA,0x30,0xC2,0xB9,0xFF,0xDF,0xB7, ++ 0x31,0xDA,0x31,0x92,0x31,0x4A,0x31,0x02,0xBC,0xFF,0xE7,0xCF,0xE8,0x85,0x37,0x0A, ++ 0x8D,0x01,0x86,0x01,0x02,0x5F,0xC8,0x5B,0x58,0x31,0x88,0x46,0x40,0xFA,0x47,0x0B, ++ 0x10,0x81,0x18,0x8A,0x00,0x0B,0x40,0x0B,0x18,0x8A,0x00,0x0B,0x3E,0x82,0xCB,0x1B, ++ 0x5F,0x01,0x88,0x86,0x38,0x82,0xAB,0x85,0xDA,0x5B,0xD8,0x4B,0x1F,0x5A,0x4A,0xC2, ++ 0xC7,0x08,0x52,0xC2,0xC0,0x00,0x14,0x01,0x00,0x27,0x40,0x24,0x04,0x64,0xE0,0x00, ++ 0xE2,0x48,0xE4,0x90,0x17,0xD2,0x9C,0xC6,0xEF,0x85,0xA8,0xBD,0x80,0x15,0x34,0x62, ++ 0x37,0xBA,0xD8,0x33,0xE8,0x03,0x09,0x01,0x18,0x4A,0x2E,0x01,0x40,0x29,0x90,0x16, ++ 0x1F,0x0B,0x1D,0x2B,0x07,0x6F,0x00,0x09,0xEA,0x02,0x38,0x00,0xAF,0x26,0x50,0x52, ++ 0x58,0x03,0x1F,0x82,0x18,0x03,0x05,0x27,0x57,0x3A,0x5F,0x03,0x18,0x92,0x1E,0x82, ++ 0x1D,0x03,0x1D,0x0B,0x30,0x0A,0xC1,0x14,0xBC,0xFF,0xE7,0xE7,0x25,0x2B,0x59,0x03, ++ 0x28,0x01,0x00,0x17,0x43,0x00,0xE2,0x68,0x96,0x6D,0x3F,0x08,0x8D,0x0E,0x10,0xAA, ++ 0x9B,0xC6,0xAF,0x2B,0x73,0xCA,0x4E,0x04,0x00,0x83,0xC7,0x14,0x0A,0x59,0xCB,0x00, ++ 0x0A,0x48,0xC2,0x00,0xF7,0x03,0x08,0x83,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09, ++ 0xBC,0xFF,0xDF,0x87,0x30,0x1A,0xB9,0x04,0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF, ++ 0xD8,0xFF,0x06,0x09,0xA7,0x01,0x8D,0x03,0x48,0x82,0x46,0x43,0x10,0x11,0x18,0x82, ++ 0x00,0x43,0x00,0x41,0x01,0x83,0x45,0x83,0x08,0xF9,0x8F,0x19,0x19,0x42,0x00,0x83, ++ 0x87,0x2D,0xE8,0x85,0x3F,0x82,0xAB,0xC5,0xD8,0x53,0x90,0x04,0xDC,0x53,0x32,0xB2, ++ 0xE9,0x53,0x54,0x91,0x9E,0xBE,0x12,0x31,0xE0,0x92,0x52,0x01,0x8E,0x9E,0x52,0x02, ++ 0xC0,0x28,0x34,0x12,0x91,0xE1,0x19,0xC1,0x8E,0x01,0xF4,0x1A,0xE8,0x63,0x3A,0x11, ++ 0x10,0x1A,0xDD,0x16,0xD8,0xD8,0x38,0x1C,0xA9,0x7B,0x1E,0xD1,0xEE,0x63,0xF4,0x1A, ++ 0x15,0x32,0x13,0x9A,0xE0,0x16,0xC8,0xD8,0x38,0x1C,0xB2,0x7B,0x30,0x01,0x38,0x01, ++ 0x1C,0x01,0x30,0xE2,0x00,0x27,0x21,0x01,0x00,0xE7,0x18,0x01,0xF0,0x5A,0x5F,0x01, ++ 0xED,0x4E,0x10,0x9A,0xE8,0x06,0x30,0xF2,0xE8,0x5B,0x5E,0x01,0x80,0x76,0x40,0x9C, ++ 0xF0,0xD8,0x02,0x9C,0x00,0x57,0x58,0x01,0xD5,0x46,0x10,0xDA,0xD0,0x06,0x30,0xFA, ++ 0xF0,0x5B,0x58,0x01,0x80,0x16,0x40,0x9C,0xE0,0xD8,0x02,0x9C,0xE4,0x68,0xE5,0x90, ++ 0xE7,0x20,0x93,0x25,0x2F,0xA2,0x9B,0x06,0x32,0x1A,0xE3,0xD8,0x94,0xDD,0x36,0xE2, ++ 0xE5,0x04,0x28,0x22,0x98,0xBE,0x7E,0x14,0xC8,0x90,0x3C,0x14,0x7E,0x14,0xCA,0x90, ++ 0x3E,0x14,0xEA,0x43,0x40,0x01,0x80,0x0E,0xF6,0x00,0xAA,0x43,0xF0,0x43,0x40,0x01, ++ 0x82,0x0E,0xF0,0x00,0xB7,0x43,0xE8,0xC5,0xAC,0xBD,0x87,0x15,0x30,0x62,0x30,0xBA, ++ 0xEF,0x2B,0xDB,0x33,0xDB,0x03,0x1B,0x42,0x00,0x08,0xC2,0x14,0xC4,0x40,0x48,0x8A, ++ 0xC0,0x00,0x82,0x0C,0x37,0x02,0x81,0x01,0xC4,0x0B,0x10,0x01,0x18,0x8A,0x80,0x0B, ++ 0x00,0x21,0xEE,0x02,0x44,0x01,0x80,0x1E,0x09,0x09,0x30,0xDA,0x30,0x52,0x31,0x42, ++ 0xBF,0xFF,0xD7,0xC7,0x30,0x1A,0xB9,0x04,0x08,0x01,0x00,0x19,0xD7,0x14,0xB8,0xFF, ++ 0xDA,0x3F,0x02,0x41,0xE9,0x0A,0x30,0x1A,0x30,0xD2,0xC1,0x0C,0xBC,0xFF,0xDF,0x7F, ++ 0x31,0x1A,0x31,0x4A,0xD0,0x14,0xC0,0x0C,0xBD,0xFF,0xF7,0xB7,0x50,0x02,0x1C,0x09, ++ 0xC0,0x83,0x40,0x01,0x8B,0x5E,0xE0,0x68,0x95,0x6D,0x5F,0x0B,0x03,0x0F,0xE0,0x68, ++ 0x90,0x6D,0x37,0xC2,0x00,0x42,0x15,0x0A,0x8D,0x0E,0x10,0xAA,0x99,0xBE,0x37,0x82, ++ 0x74,0x92,0x13,0x2A,0x93,0xE6,0xA8,0x2B,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09, ++ 0xBE,0xFF,0xD7,0x47,0x30,0x1A,0xB9,0x04,0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF, ++ 0xD8,0xBF,0xC0,0x14,0x0A,0x59,0xCB,0x00,0x0A,0x48,0xC2,0x00,0xF7,0x03,0x08,0x83, ++ 0x05,0x41,0x00,0x83,0x47,0x83,0x09,0xF9,0x88,0x19,0x18,0x42,0x01,0x83,0x39,0xBF, ++ 0xE1,0x0B,0x31,0x02,0x80,0x01,0x4D,0x01,0x86,0x1E,0xC9,0x0B,0x49,0x09,0x88,0x06, ++ 0x0E,0x11,0x88,0x0B,0xA8,0x2B,0x83,0x9B,0x4F,0x04,0x01,0x83,0x50,0x0A,0xCB,0x14, ++ 0xDC,0x03,0xC1,0x48,0xE7,0x02,0x0A,0x83,0x31,0xDA,0x31,0x52,0x08,0x01,0x00,0x09, ++ 0xBC,0xFF,0xD7,0xC7,0x30,0x1A,0xB9,0x04,0x30,0x4A,0x01,0x11,0xD7,0x14,0xB8,0xFF, ++ 0xD0,0x3F,0x07,0x41,0x01,0x83,0x45,0x83,0x08,0xF9,0x8F,0x19,0x19,0x42,0x00,0x83, ++ 0x38,0x77,0x08,0x01,0x88,0x0B,0x86,0x8B,0x3F,0x57,0xA8,0x85,0x84,0x9D,0x34,0x22, ++ 0x33,0x6A,0xD8,0x73,0xD8,0x43,0x81,0x34,0x31,0x12,0x93,0xE1,0x92,0x94,0x48,0x72, ++ 0x32,0x02,0xC3,0x18,0x4B,0x32,0x22,0x0A,0x8B,0x8C,0xC8,0x43,0x00,0x00,0x82,0x1C, ++ 0x00,0x01,0x80,0x14,0x37,0x42,0x81,0x01,0x82,0x84,0xC0,0x03,0x5C,0x7B,0x35,0x32, ++ 0x3F,0x20,0x5A,0x43,0x18,0x3A,0x60,0x01,0xD1,0x46,0x40,0xFA,0x18,0x3A,0xB8,0x0C, ++ 0x37,0x82,0x23,0xD9,0x00,0x02,0xE1,0x84,0x80,0x03,0x03,0x47,0x46,0xD2,0x19,0x02, ++ 0x18,0x3A,0xB8,0x0C,0x30,0x82,0x23,0x21,0x18,0x02,0xE1,0x84,0x80,0x03,0x3B,0x01, ++ 0x19,0x7B,0x37,0x42,0x80,0x01,0x85,0x7C,0xC0,0x03,0x84,0x54,0xC0,0x7C,0x20,0x09, ++ 0xB8,0x22,0xA0,0x4C,0x34,0x42,0x81,0x01,0x86,0x74,0x18,0x3B,0xB8,0x44,0xC0,0x74, ++ 0x18,0x3B,0xBC,0x3C,0x31,0x42,0x81,0x01,0x84,0x6C,0xA0,0x3B,0xCA,0x43,0x45,0x00, ++ 0x86,0x2C,0x00,0x01,0xFB,0x22,0x82,0x00,0x81,0x24,0xE8,0x43,0x40,0x29,0xC0,0xBE, ++ 0x03,0x01,0x30,0x22,0x3B,0x04,0x39,0x04,0x20,0x01,0x00,0x77,0x00,0x01,0x00,0x47, ++ 0x40,0x7C,0x00,0xFC,0x40,0x7C,0x00,0xBC,0xE4,0x90,0xE4,0x48,0xE2,0xD8,0xE4,0x00, ++ 0x95,0x05,0x12,0x82,0xDB,0xA6,0xE7,0x20,0x90,0x25,0xC3,0x34,0x17,0x22,0xDC,0x6E, ++ 0xF8,0x94,0xE0,0x8C,0x00,0x01,0x80,0x5C,0x00,0xAF,0x05,0x01,0x34,0x32,0x34,0x22, ++ 0xC8,0x5C,0x00,0x09,0x00,0x42,0xCC,0x0C,0x80,0x64,0x10,0x42,0x81,0x7E,0xE3,0x53, ++ 0x50,0x01,0x80,0x2E,0xC8,0x34,0xC0,0x5C,0xF4,0x48,0x12,0x42,0x88,0x06,0x30,0xB2, ++ 0x1A,0x01,0x00,0x87,0x41,0xCC,0x41,0x14,0xD0,0x40,0x94,0x15,0x00,0x14,0xC9,0x1C, ++ 0x10,0x52,0xD4,0x3E,0x32,0x02,0xE3,0x00,0x94,0x05,0x36,0x22,0x34,0x82,0xC3,0x00, ++ 0x94,0x05,0x30,0x32,0xCC,0x2C,0x10,0x52,0xE8,0x3E,0x01,0x7F,0x00,0x01,0x00,0x42, ++ 0x48,0xE0,0x06,0x00,0x38,0xA0,0x03,0x00,0xAA,0xAA,0xAA,0xAA,0x18,0x00,0x04,0x42, ++ 0x00,0xF0,0x00,0x01,0x68,0xB8,0x03,0x00,0x28,0x60,0x00,0x00,0xCC,0x4B,0x13,0x8A, ++ 0xE7,0x1E,0x58,0x43,0xC8,0x64,0x18,0x0A,0x18,0x4B,0xCF,0x6C,0xE8,0x4B,0x4A,0x09, ++ 0x88,0x16,0xC8,0x6C,0x02,0x09,0xAC,0x43,0xCC,0x54,0x10,0x52,0xE8,0xBE,0x08,0x09, ++ 0xD4,0x44,0x00,0xCA,0x18,0x8A,0x88,0x44,0x00,0x8F,0xC8,0x24,0x10,0x52,0xD4,0x76, ++ 0xCA,0x6C,0xE8,0x4B,0x48,0x09,0x88,0x16,0xCC,0x6C,0x00,0x09,0xA8,0x43,0xCA,0x4C, ++ 0x10,0x52,0xD4,0x26,0x08,0x09,0xD0,0x3C,0x00,0xCA,0x1C,0x8A,0x8D,0x3C,0xE0,0x20, ++ 0xE2,0xF8,0xE5,0xD8,0x95,0xDD,0x12,0x9A,0xD8,0x66,0xC5,0x7C,0xC8,0x03,0x44,0x01, ++ 0x83,0x2E,0x32,0x02,0x40,0x11,0xC8,0x2E,0x33,0x0A,0x33,0x82,0x83,0x07,0xC8,0xD7, ++ 0x90,0x05,0x00,0x07,0x03,0x01,0x00,0x88,0xD0,0x20,0x13,0x01,0x01,0x57,0x01,0x67, ++ 0x40,0x01,0xE8,0x7E,0x0B,0x01,0xF0,0x0A,0xDC,0x1C,0x10,0xCA,0xD2,0xB6,0xE0,0x18, ++ 0x10,0xCA,0xEC,0x16,0xD1,0x48,0x00,0x0C,0x00,0x87,0x48,0x01,0xE8,0x76,0x08,0x09, ++ 0x00,0x0C,0x01,0x5F,0x0B,0x01,0xF0,0x0A,0x10,0x0A,0xD4,0x16,0xD1,0x48,0x00,0x0C, ++ 0x00,0x27,0x48,0x01,0xD0,0x16,0x08,0x01,0x19,0x4A,0x06,0x0C,0x0B,0x01,0xF0,0x0A, ++ 0xDC,0x24,0x10,0xCA,0xD0,0x1E,0xC8,0x14,0xE6,0x48,0x92,0x4D,0x8D,0x14,0xE0,0x20, ++ 0xE2,0x90,0x92,0x95,0x16,0x92,0xDD,0x9E,0x00,0x4F,0x00,0x01,0x08,0x01,0x00,0x27, ++ 0x05,0x0C,0xE1,0x20,0xE2,0xF8,0xE5,0x00,0x95,0x05,0x12,0x82,0xD8,0xC6,0xC7,0x5C, ++ 0xE2,0x00,0x92,0x05,0x80,0x5C,0xC8,0x34,0xC4,0x5C,0x10,0x42,0xD2,0x06,0x38,0x27, ++ 0xC9,0x43,0x41,0x71,0xC9,0x0E,0x00,0x71,0x88,0x43,0xC1,0x14,0xCC,0x4B,0x41,0x00, ++ 0xC6,0x40,0x90,0x05,0x8A,0x43,0x41,0x81,0xCA,0x0E,0x00,0x81,0x88,0x43,0x01,0x01, ++ 0x29,0x44,0x37,0x44,0xC0,0x74,0xC8,0x44,0x18,0x0B,0xCE,0x74,0xC4,0x3C,0x18,0x43, ++ 0x87,0x9D,0xE8,0x85,0xA8,0x85,0x33,0x2A,0x30,0x62,0x30,0xB2,0x31,0x0A,0x31,0x42, ++ 0xBA,0xFF,0xEF,0xCF,0x48,0x6A,0x03,0x01,0x81,0x43,0x30,0x92,0x31,0x0A,0x31,0x42, ++ 0xBB,0xFF,0xEF,0x1F,0xEE,0x03,0x41,0x41,0x92,0x0E,0xE0,0x00,0xAB,0x03,0xE9,0x85, ++ 0x10,0x01,0x00,0x37,0x0A,0x01,0xE0,0x48,0x90,0x4D,0x4C,0xA1,0xCA,0xDE,0xE7,0x90, ++ 0x94,0x95,0x14,0x12,0xCB,0xB6,0x3F,0x82,0x38,0x18,0x78,0xD8,0x14,0x09,0x00,0xD2, ++ 0x97,0x95,0x1E,0xF9,0x08,0xD8,0x00,0xC2,0x5E,0xEA,0xC2,0x00,0x48,0x09,0x88,0x66, ++ 0x44,0x0B,0x18,0x8A,0x02,0x0B,0x40,0x0B,0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A, ++ 0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B,0x38,0x82,0x4B,0x01,0x8A,0x66,0x40,0x0B, ++ 0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B, ++ 0x40,0x0B,0x18,0x8A,0x03,0x0B,0x38,0x82,0x48,0x11,0x88,0x66,0x44,0x0B,0x18,0x8A, ++ 0x02,0x0B,0x40,0x0B,0x1A,0x8A,0x04,0x0B,0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B, ++ 0x1E,0x8A,0x00,0x0B,0x38,0x82,0x4B,0x19,0x88,0xE6,0x47,0x0B,0x18,0x8A,0x04,0x0B, ++ 0x44,0x0B,0x1C,0x8A,0x06,0x0B,0x44,0x0B,0x1E,0x8A,0x04,0x0B,0x40,0x0B,0x1A,0x8A, ++ 0x03,0x0B,0x3A,0x82,0xAC,0x8D,0x87,0x3D,0xC0,0x3C,0xC8,0x3C,0x4C,0x00,0x00,0x00, ++ 0xC0,0x00,0x3A,0x00,0x4A,0xDA,0x71,0x00,0xC1,0x28,0x42,0xDA,0x44,0x0B,0x90,0x4D, ++ 0x88,0x34,0x58,0x0B,0x90,0x4D,0x8C,0x2C,0x5C,0x0B,0x92,0x4D,0x8C,0x24,0x58,0x0B, ++ 0x90,0x4D,0x8C,0x1C,0x54,0x0B,0x96,0x75,0x4A,0xA2,0x41,0x53,0x90,0x95,0x94,0x14, ++ 0x44,0x53,0x90,0xBD,0x44,0x13,0x92,0x95,0x91,0x0C,0x58,0x7A,0x98,0x01,0x52,0xD3, ++ 0x90,0x95,0x94,0x04,0x10,0x09,0x00,0x13,0xA8,0x10,0x1C,0x13,0x12,0x81,0x18,0x13, ++ 0x18,0x13,0x14,0x79,0x11,0x13,0x16,0x01,0x00,0x53,0x12,0x89,0x02,0x53,0x40,0x0B, ++ 0x10,0x81,0x19,0x8A,0x07,0x0B,0x02,0xF9,0x80,0x89,0x17,0xC3,0x07,0x09,0xB8,0xFF, ++ 0xFF,0x7F,0x03,0xF9,0x80,0x89,0x14,0xC3,0x07,0x09,0xB8,0xFF,0xF8,0x4F,0x03,0x19, ++ 0x11,0x00,0x00,0x43,0x07,0x09,0xB8,0xFF,0xF8,0x1F,0x0B,0x11,0xC7,0x3C,0xB8,0xFF, ++ 0xF8,0x5F,0x23,0xA1,0x01,0x01,0x40,0x4B,0x30,0x48,0xA8,0x16,0xE7,0x20,0x93,0x25, ++ 0x03,0x0F,0xF0,0x20,0x92,0x25,0xE7,0x00,0x90,0x05,0x46,0x51,0x98,0x9E,0x0F,0x09, ++ 0xC7,0x3C,0xB8,0xFF,0xF8,0xCF,0x42,0x82,0xC8,0x34,0x00,0x0B,0xC8,0x2C,0x18,0x0B, ++ 0xCA,0x24,0x18,0x0B,0xCC,0x1C,0x18,0x0B,0x10,0x33,0x4E,0x62,0xD2,0x14,0x00,0x53, ++ 0x00,0x7B,0xC8,0x0C,0x00,0x0B,0x4A,0x42,0xC2,0x04,0x88,0x01,0x10,0x43,0x60,0xA1, ++ 0xC8,0x16,0x00,0x09,0x87,0x45,0xE8,0x85,0x07,0x01,0x38,0xDF,0x00,0xF0,0x00,0x01, ++ 0x80,0x00,0x00,0x42,0x08,0x01,0x00,0x42,0x00,0x01,0x00,0x42,0x18,0x00,0x04,0x42, ++ 0x00,0x0F,0x00,0x26,0xF8,0x48,0x48,0x21,0x94,0xDE,0x3F,0x58,0xA8,0x0E,0x00,0x14, ++ 0xE6,0x00,0x3C,0x48,0x80,0x06,0x80,0x13,0x38,0x82,0x4B,0x01,0x86,0x5E,0x38,0x18, ++ 0x80,0x16,0x80,0x13,0xE2,0x00,0xF2,0x48,0x48,0x11,0x98,0x26,0x38,0x18,0xAC,0x16, ++ 0x04,0x14,0xE0,0x00,0xF7,0x48,0x3C,0x1F,0x17,0x01,0x38,0x77,0x16,0x01,0x38,0xFF, ++ 0x10,0x01,0x48,0x18,0x11,0x5A,0x9C,0x66,0x54,0x18,0x10,0x5A,0x98,0x8E,0x18,0x01, ++ 0x32,0xE2,0x04,0x77,0x30,0x1A,0x18,0x5A,0xA0,0xE6,0x11,0x01,0x44,0x18,0x12,0x5A, ++ 0x98,0x8E,0x49,0x18,0x10,0x5A,0x9C,0xE6,0x54,0x18,0x10,0x5A,0x9C,0x0E,0x30,0xA2, ++ 0x06,0xFF,0x49,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD6,0x00,0x0C,0x92,0x4A,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD4,0x00,0x0A,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x0E,0x58,0xD2,0x00,0x08,0x92,0x4A,0x18,0x10,0x5A,0x9C,0x0E,0x0E,0x58,0xD0,0x00, ++ 0x0E,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD6,0x00,0x0C,0x92,0x42,0x18, ++ 0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD4,0x00,0x0A,0x92,0x42,0x18,0x10,0x5A,0x9C,0x0E, ++ 0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08,0x90,0x06,0x30,0x0A,0x08,0x92,0x32,0x82, ++ 0x3A,0x82,0x03,0xEF,0x78,0x50,0x86,0x06,0x10,0x4A,0x82,0x18,0x9A,0x06,0x10,0x02, ++ 0x00,0x9A,0x12,0x01,0x30,0xE2,0x4C,0x18,0x11,0x5A,0x9C,0x6E,0x54,0x18,0x10,0x5A, ++ 0x9F,0x96,0x10,0xE1,0x08,0x48,0xD4,0x95,0x54,0x18,0x10,0x5A,0x9C,0x66,0x08,0x48, ++ 0x8C,0x90,0x14,0x5A,0x9C,0x46,0x08,0x48,0x8C,0x90,0x14,0x5A,0x9C,0x26,0x08,0x48, ++ 0x84,0xD6,0x89,0x90,0x04,0x07,0x48,0x48,0x4C,0x18,0x16,0x5A,0x9E,0x0E,0x08,0x58, ++ 0xD2,0x00,0x0E,0x92,0x4C,0x18,0x14,0x5A,0x9C,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92, ++ 0x4C,0x18,0x12,0x5A,0x9A,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x4C,0x18,0x10,0x5A, ++ 0x98,0x0E,0x08,0x58,0xD2,0x00,0x0E,0x92,0x44,0x18,0x16,0x5A,0x9E,0x0E,0x00,0x58, ++ 0xD2,0x00,0x0E,0x92,0x44,0x18,0x14,0x5A,0x9C,0x0E,0x00,0x58,0xD2,0x00,0x0E,0x92, ++ 0x92,0xCE,0x46,0x18,0x10,0x5A,0x9C,0x0E,0x06,0x58,0xD2,0x00,0x0A,0x92,0xD2,0x08, ++ 0x90,0x06,0x30,0x0A,0x32,0x1A,0x0B,0x92,0x80,0xD8,0x32,0x82,0x9A,0x0E,0x10,0x02, ++ 0x58,0x01,0xA8,0x06,0x13,0x4A,0x3A,0x82,0x32,0x1A,0x83,0xD8,0x9A,0x06,0x10,0x02, ++ 0xA8,0x0D,0x00,0x01,0x36,0x02,0x36,0x02,0xEB,0x15,0x30,0xAA,0x81,0x07,0xC0,0x17, ++ 0x30,0x72,0x05,0x28,0x32,0x4A,0x33,0x9A,0x46,0x00,0x06,0x00,0x30,0x2A,0x84,0xC5, ++ 0xAF,0x05,0xB9,0xE7,0xF3,0x6F,0xE4,0x05,0x3A,0x01,0x40,0x48,0x30,0xB2,0x35,0x01, ++ 0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06,0x2E,0x06, ++ 0xEA,0x01,0x02,0x48,0x33,0x6A,0x3C,0x82,0x36,0x22,0x30,0x02,0x31,0x02,0x36,0x02, ++ 0xBA,0xDF,0xD7,0x0F,0x43,0x02,0x38,0x82,0x88,0x40,0x00,0x01,0x40,0x12,0x48,0x1A, ++ 0xF3,0x5D,0x3D,0x82,0x00,0x68,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x30,0x01,0x10, ++ 0x39,0x82,0xA3,0x85,0x33,0xA2,0xF3,0x20,0xC3,0x2B,0xE1,0x20,0x10,0x5A,0x95,0x06, ++ 0x33,0xEA,0xE8,0x1A,0x07,0xD8,0xC2,0x18,0xE0,0x85,0x39,0xC2,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x20,0x03,0x42,0x80,0x20,0x03,0x42, ++ 0x80,0x20,0x04,0x42,0x80,0x20,0x03,0x42,0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42, ++ 0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42,0x80,0xA0,0x04,0x42,0x80,0xA0,0x02,0x42, ++ 0x80,0x20,0x05,0x42,0x80,0xA0,0x02,0x42,0x80,0xA0,0x05,0x42,0x80,0x20,0x02,0x42, ++ 0x80,0x20,0x01,0x42,0x80,0x20,0x01,0x42,0x80,0xA0,0x01,0x42,0x80,0xA0,0x01,0x42, ++ 0x80,0xA0,0x01,0x42,0x10,0x20,0x08,0x40,0x40,0x08,0x20,0x10,0x10,0x20,0x08,0x40, ++ 0x40,0x08,0x20,0x40,0x10,0x20,0x00,0x08,0x08,0xC1,0x02,0x42,0x08,0x81,0x02,0x42, ++ 0x08,0x81,0x03,0x42,0x08,0x41,0x03,0x42,0x08,0x01,0x03,0x42,0x08,0x81,0x02,0x42, ++ 0x08,0x41,0x02,0x42,0x08,0xC1,0x00,0x42,0x08,0x01,0x02,0x42,0x08,0x01,0x01,0x42, ++ 0x08,0xC1,0x01,0x42,0x08,0x41,0x01,0x42,0x08,0x81,0x01,0x42,0x08,0x81,0x01,0x42, ++ 0x08,0x41,0x01,0x42,0x08,0xC1,0x02,0x42,0x08,0x01,0x01,0x42,0x08,0x01,0x03,0x42, ++ 0x08,0xC1,0x00,0x42,0x68,0x68,0x50,0x60,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50, ++ 0x50,0x50,0x00,0x00,0x00,0x08,0xF8,0x0F,0xFF,0x07,0xF8,0xFF,0x07,0xF8,0x0F,0xF8, ++ 0x08,0x00,0x08,0x08,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x28,0xB5, ++ 0x39,0xC5,0x08,0x1D,0x1B,0x2B,0x3A,0x28,0x53,0xB5,0x0A,0xC5,0x00,0x08,0x01,0x00, ++ 0x01,0x00,0x50,0x0D,0x52,0x1D,0x52,0xB5,0x39,0x0D,0x04,0x08,0x51,0x3D,0x53,0x1D, ++ 0x51,0x3D,0x54,0x95,0x51,0x3D,0x54,0x95,0x51,0x3D,0x54,0x95,0x0B,0x3D,0x34,0x88, ++ 0x51,0x3D,0x54,0x1D,0x51,0x3D,0x54,0x95,0x04,0x00,0x50,0x3D,0x50,0x1D,0x01,0x00, ++ 0x00,0x00,0x00,0x00,0x54,0x2D,0x53,0x3D,0x32,0x8D,0x32,0x38,0x01,0x28,0x0A,0x45, ++ 0x50,0xB5,0x53,0x95,0x00,0x00,0x00,0x00,0x52,0xA5,0x51,0xB5,0x09,0xC5,0x03,0x08, ++ 0x03,0x00,0x50,0x3D,0x55,0x1D,0x51,0x0D,0x51,0x3D,0x54,0x95,0x51,0x3D,0x53,0x1D, ++ 0x51,0x3D,0x54,0x95,0x51,0x0D,0x55,0x0D,0x54,0xB5,0x3A,0x0D,0x00,0x08,0x01,0x00, ++ 0x53,0xA5,0x51,0x2D,0x52,0x3D,0x34,0x8A,0x1D,0x38,0x52,0x45,0x52,0x0D,0x51,0x1D, ++ 0x54,0xB5,0x3A,0x0D,0x53,0xA5,0x29,0xB5,0x39,0xC5,0x08,0x1D,0x19,0x2D,0x22,0x1D, ++ 0x44,0x0D,0x31,0x3D,0x23,0x95,0x09,0xC1,0x29,0xB5,0x0B,0x1D,0x1B,0x2B,0x3A,0x28, ++ 0x00,0x00,0x00,0x08,0xFF,0x07,0x00,0xF8,0x08,0x00,0x10,0x10,0x08,0x10,0x10,0x10, ++ 0x08,0x08,0x10,0x08,0x10,0x08,0x10,0x08,0x10,0x10,0x08,0x08,0x10,0x10,0x08,0x08, ++ 0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x13,0x10,0xF8,0xA7, ++ 0xFC,0x47,0xFC,0xE7,0xFE,0x27,0xFE,0xC7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x01,0x40,0x01,0xE0,0x03,0x20,0x03,0xC0,0x00,0x60,0x04,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90, ++ 0x00,0x78,0x00,0x00,0xFF,0x57,0xFF,0x17,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,0x08,0x08,0xF8,0x07,0x08,0x00,0x08,0x08,0x00,0x00,0x78,0xE2,0x00,0x00, ++ 0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x05,0x00,0x78,0xE2,0x01,0x00, ++ 0x00,0x00,0x01,0x01,0x88,0x40,0x02,0x00,0x00,0xE0,0x05,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,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, ++ 0xFF,0xFF,0xFF,0xFF,0xD1,0xDA,0xAA,0xA9,0x2E,0x2D,0x55,0x56,0xBB,0x43,0xAC,0x32, ++ 0x99,0x21,0x8A,0x10,0x00,0x70,0x00,0x28,0x09,0x00,0x1F,0x00,0x06,0x78,0x50,0x56, ++ 0xFF,0xFF,0xFF,0xFF,0xBA,0xB0,0x09,0x40,0x00,0x10,0x28,0x10,0xF1,0x7A,0x16,0x5D, ++ 0x0F,0x00,0xCA,0xCA,0xFF,0xFF,0xFF,0xFF,0x36,0x17,0x48,0x01,0x02,0x00,0x02,0x05, ++ 0xCF,0x5E,0x2B,0xA2,0x79,0xC9,0x5A,0x26 ++}; ++#define FW_INFO_SIZE (0x18) ++#define FW_REAL_SIZE (sizeof(fwbin)) ++#define FW_BIN_SIZE (24*1024+24) //24K byte ++ ++#endif ++ +diff --git a/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_i2c.c b/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_i2c.c +new file mode 100644 +index 000000000..576aa89dd +--- /dev/null ++++ b/module_drivers/drivers/input/touchscreen/hyn_touch/hyn_i2c.c +@@ -0,0 +1,99 @@ ++/* ++ * ++ * FocalTech TouchScreen driver. ++ * ++ * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. ++ * ++ */ ++ ++/************************************************************************ ++* ++* File Name: focaltech_i2c.c ++* ++* Author: Focaltech Driver Team ++* ++* Created: 2016-08-04 ++* ++* Abstract: i2c communication with TP ++* ++* Version: v1.0 ++* ++* Revision History: ++* ++************************************************************************/ ++ ++/***************************************************************************** ++* Included header files ++*****************************************************************************/ ++//#include "hyn_core.h" ++#include "hyn_cst3xx.h" ++ ++/***************************************************************************** ++* Private constant and macro definitions using #define ++*****************************************************************************/ ++#define I2C_RETRY_NUMBER 1 ++#define I2C_BUF_LENGTH 256 ++ ++/***************************************************************************** ++* Private enumerations, structures and unions using typedef ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Static variables ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Global variable or extern global variabls/functions ++*****************************************************************************/ ++ ++/***************************************************************************** ++* Static function prototypes ++*****************************************************************************/ ++ ++/***************************************************************************** ++* functions body ++*****************************************************************************/ ++extern struct cst3xx_ts_data *ts_data; ++ ++int cst3xx_bus_init(struct cst3xx_ts_data *ts_data) ++{ ++ HYN_FUNC_ENTER(); ++ ts_data->bus_tx_buf = kzalloc(I2C_BUF_LENGTH, GFP_KERNEL); ++ if (NULL == ts_data->bus_tx_buf) { ++ HYN_ERROR("failed to allocate memory for bus_tx_buf"); ++ return -ENOMEM; ++ } ++ ++ ts_data->bus_rx_buf = kzalloc(I2C_BUF_LENGTH, GFP_KERNEL); ++ if (NULL == ts_data->bus_rx_buf) { ++ HYN_ERROR("failed to allocate memory for bus_rx_buf"); ++ return -ENOMEM; ++ } ++ HYN_FUNC_EXIT(); ++ return 0; ++} ++ ++int cst3xx_bus_exit(struct cst3xx_ts_data *ts_data) ++{ ++ HYN_FUNC_ENTER(); ++ if (ts_data && ts_data->bus_tx_buf) { ++ kfree(ts_data->bus_tx_buf); ++ ts_data->bus_tx_buf = NULL; ++ } ++ ++ if (ts_data && ts_data->bus_rx_buf) { ++ kfree(ts_data->bus_rx_buf); ++ ts_data->bus_rx_buf = NULL; ++ } ++ HYN_FUNC_EXIT(); ++ return 0; ++} +diff --git a/module_drivers/drivers/irqchip/Kconfig b/module_drivers/drivers/irqchip/Kconfig +new file mode 100644 +index 000000000..8843b4045 +--- /dev/null ++++ b/module_drivers/drivers/irqchip/Kconfig +@@ -0,0 +1,20 @@ ++config INGENIC_INTC ++ bool "intc v1 interrupt " ++ depends on SOC_X1600 ++ select IRQ_DOMAIN ++ ++config IRQ_INGENIC_CPU ++ bool "cpu interrupt driver" ++ depends on SOC_X2000 || SOC_X2000_V12 || SOC_X2100 || SOC_X2500 || SOC_M300 ++ select IRQ_DOMAIN ++ help ++ Support for ingenic cpu core irq handler. ++ ++config INGENIC_INTC_CHIP ++ bool "intc v2 interrupt driver" ++ depends on IRQ_INGENIC_CPU ++ select IRQ_DOMAIN ++ help ++ Support for ingenic XBURST2 based SOCs, which intc is ++ near cpu core,and each logic cpu has an intc. ++ +diff --git a/module_drivers/drivers/irqchip/Makefile b/module_drivers/drivers/irqchip/Makefile +new file mode 100644 +index 000000000..035584462 +--- /dev/null ++++ b/module_drivers/drivers/irqchip/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_INGENIC_INTC) += irq-ingenic.o ++obj-$(CONFIG_IRQ_INGENIC_CPU) += irq-ingenic-cpu.o ++obj-$(CONFIG_INGENIC_INTC_CHIP) += irq-ingenic-chip.o +diff --git a/module_drivers/drivers/irqchip/irq-ingenic-chip.c b/module_drivers/drivers/irqchip/irq-ingenic-chip.c +new file mode 100644 +index 000000000..b58f2654c +--- /dev/null ++++ b/module_drivers/drivers/irqchip/irq-ingenic-chip.c +@@ -0,0 +1,560 @@ ++/* ++ * Copyright (C) 2017 Ingenic Semiconductor Co., Ltd. ++ * ++ * Author: dongsheng.qiu, dongsheng.qiu@ingenic.com bo.liu@ingenic.com ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define PART_OFF 0x20 ++#define ISR_OFF (0x00) ++#define IMR_OFF (0x04) ++#define IMSR_OFF (0x08) ++#define IMCR_OFF (0x0c) ++#define IPR_OFF (0x10) ++ ++ ++struct cpu_intc_map ++{ ++ unsigned int cpu_num; ++ unsigned int dev_base; ++}; ++static struct cpu_intc_map cpu_intc_map[NR_CPUS]; ++ ++struct core_irq_chip{ ++ void __iomem *iobase; ++ unsigned int next_irq_resp; ++}; ++struct irq_chip_data { ++ void __iomem *iobase[NR_CPUS]; ++ raw_spinlock_t lock; ++ struct cpumask irq_idle_mask; ++ unsigned int wake_up_flag[(INTC_NR_IRQS + 31) / 32]; /* Interrupts which can generate wakeup signal when cpu asleep. */ ++ unsigned char intc_num[INTC_NR_IRQS]; /* Which CPU/INTC does an interrupt current connect to, */ ++ struct cpumask affinity[INTC_NR_IRQS]; /* Which CPU does an interrupt src affinity to. */ ++}; ++struct core_irq_chips { ++ struct core_irq_chip *__percpu *percpu_irq_chip; ++ struct irq_chip_data chip_data; ++ int irq; ++ void __iomem *iobase; /* external intc iobase*/ ++ struct clk *intc_clk; ++}; ++ ++static struct core_irq_chip irq_chip_buf[NR_CPUS]; ++static struct core_irq_chips g_irq_chips; ++ ++ ++static void percpu_irq_init(struct core_irq_chips *irq_chips, unsigned int cpu_num) ++{ ++ unsigned int base = 0; ++ struct core_irq_chip *irq_chip; ++ int cpu = smp_processor_id(); ++ void __iomem * iobase; ++ int i; ++ ++ for(i = 0;i < NR_CPUS;i++) ++ { ++ if(cpu_intc_map[i].cpu_num == cpu_num) { ++ base = cpu_intc_map[i].dev_base; ++ irq_chip = &irq_chip_buf[i]; ++ break; ++ } ++ } ++ ++ if(base == 0){ ++ pr_err("Error: CPU[%d] don't finded intc base address\n",cpu_num); ++ return; ++ } ++ ++ iobase = (void *)base; ++ ++ irq_chip = &irq_chip_buf[cpu]; ++ ++ irq_chip->iobase = iobase; ++ irq_chip->next_irq_resp = 0; ++ irq_chips->chip_data.iobase[cpu] = iobase; ++ ++ *this_cpu_ptr(irq_chips->percpu_irq_chip) = irq_chip; ++ enable_percpu_irq(irq_chips->irq, IRQ_TYPE_NONE); ++ ++ pr_info("percpu irq inited.\n"); ++} ++int ingenic_percpu_irq_init(int cpu_num) ++{ ++ percpu_irq_init(&g_irq_chips, cpu_num); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_percpu_irq_init); ++ ++static void percpu_irq_deinit(struct core_irq_chips *irq_chips) ++{ ++ disable_percpu_irq(irq_chips->irq); ++} ++ ++void ingenic_percpu_irq_deinit(void) ++{ ++ percpu_irq_deinit(&g_irq_chips); ++} ++EXPORT_SYMBOL_GPL(ingenic_percpu_irq_deinit); ++ ++ ++#ifdef CONFIG_SMP ++static inline void irq_lock(struct irq_chip_data *chip) ++{ ++ raw_spin_lock(&chip->lock); ++} ++ ++static inline void irq_unlock(struct irq_chip_data *chip) ++{ ++ raw_spin_unlock(&chip->lock); ++} ++#else ++static inline void irq_lock(struct irq_chip_data *chip) { } ++static inline void irq_unlock(struct irq_chip_data *chip) { } ++#endif ++ ++ ++static void xburst2_irq_unmask(struct irq_data *data) ++{ ++ struct irq_chip_data *chip = (struct irq_chip_data *)irq_data_get_irq_chip_data(data); ++ void __iomem * iobase; ++ int hwirq = data->hwirq; ++ unsigned int group; ++ unsigned int bit; ++ int intc_num; ++ ++ group = hwirq / 32; ++ bit = 1 << ((hwirq) & 31); ++ irq_lock(chip); ++ intc_num = chip->intc_num[hwirq]; ++ iobase = chip->iobase[intc_num]; ++ writel(bit, iobase + group * PART_OFF + IMCR_OFF); ++ irq_unlock(chip); ++} ++ ++ ++static void xburst2_irq_mask(struct irq_data *data) ++{ ++ struct irq_chip_data *chip = (struct irq_chip_data *)irq_data_get_irq_chip_data(data); ++ void __iomem * iobase; ++ int hwirq = data->hwirq; ++ unsigned int group; ++ unsigned int bit; ++ int intc_num; ++ ++ group = hwirq / 32; ++ bit = 1 << ((hwirq) & 31); ++ irq_lock(chip); ++ intc_num = chip->intc_num[hwirq]; ++ iobase = chip->iobase[intc_num]; ++ writel(bit, iobase + group * PART_OFF + IMSR_OFF); ++ ++#ifdef CONFIG_SMP ++ ingenic_irq_migration(0); ++#endif ++ irq_unlock(chip); ++} ++ ++static int xburst2_irq_set_wake(struct irq_data *data, unsigned int on) ++{ ++ struct irq_chip_data *chip = (struct irq_chip_data *)irq_data_get_irq_chip_data(data); ++ unsigned int group = (data->irq - IRQ_INTC_BASE) / 32; ++ unsigned int bit = 1 << ((data->irq - IRQ_INTC_BASE) & 31); ++ ++ irq_lock(chip); ++ if(on) { ++ chip->wake_up_flag[group] |= bit; ++ }else { ++ chip->wake_up_flag[group] &= ~bit; ++ } ++ irq_unlock(chip); ++ return 0; ++} ++ ++#ifdef CONFIG_SMP ++static int xburst2_set_affinity(struct irq_data *data, const struct cpumask *dest, bool force) ++{ ++ struct irq_chip_data *chip = (struct irq_chip_data *)irq_data_get_irq_chip_data(data); ++ int hwirq = data->hwirq; ++ unsigned int cpu = cpumask_any_and(dest,cpu_online_mask); ++ void __iomem * prev_iobase; ++ void __iomem * iobase; ++ int prev_intc_num; ++ int group; ++ unsigned int bit; ++ ++// printk("########%s, %d, dest->bits %lx, cpu_online_mask->bits: %lx\n", __func__, __LINE__, dest->bits[0], cpu_online_mask->bits[0]); ++ ++ irq_lock(chip); ++ ++ cpumask_and(&chip->affinity[hwirq],dest,cpu_online_mask); ++ ++ prev_intc_num = chip->intc_num[hwirq]; ++ prev_iobase = chip->iobase[prev_intc_num]; ++ iobase = chip->iobase[cpu]; ++ group = hwirq / 32; ++ bit = 1 << ((hwirq) & 31); ++ ++ if(!(readl(prev_iobase + PART_OFF * group + IMR_OFF) & bit)){ ++ writel(bit,prev_iobase + PART_OFF * group + IMSR_OFF); ++ writel(bit,iobase + PART_OFF * group + IMCR_OFF); ++ } else { ++ writel(bit,prev_iobase + PART_OFF * group + IMSR_OFF); ++ } ++ chip->intc_num[hwirq] = cpu; ++ ++ irq_unlock(chip); ++ ++ return IRQ_SET_MASK_OK; ++} ++#endif ++ ++static struct irq_chip xburst2_irq_chip = { ++ .name = "XBurst2-irqchip", ++ .irq_mask = xburst2_irq_mask, ++ .irq_mask_ack = xburst2_irq_mask, ++ .irq_unmask = xburst2_irq_unmask, ++ .irq_ack = xburst2_irq_mask, ++ .irq_eoi = xburst2_irq_unmask, ++ .irq_set_wake = xburst2_irq_set_wake, ++#ifdef CONFIG_SMP ++ .irq_set_affinity = xburst2_set_affinity, ++#endif ++}; ++ ++ ++static irqreturn_t xburst2_irq_handler(int irq, void *data) ++{ ++ struct core_irq_chip *irq_chip = *(struct core_irq_chip **)data; ++ void __iomem * iobase = irq_chip->iobase; ++ unsigned int irq_num = 0xffffffff; ++ int n = 0,i; ++ unsigned int next_irq_resp = irq_chip->next_irq_resp; ++ unsigned int ipr = readl(iobase + (next_irq_resp / 32) * PART_OFF + IPR_OFF); ++ ++ do{ ++ if(irq) { ++ for(i = next_irq_resp & 31;i < 32;i++) ++ { ++ if(ipr & (1 << i)) ++ { ++ irq_num = (next_irq_resp & (~31)) + i; ++ break; ++ } ++ } ++ } ++ if(irq_num != 0xffffffff) ++ break; ++ next_irq_resp = (next_irq_resp & (~31)) + 32; ++ if(next_irq_resp >= INTC_NR_IRQS) ++ next_irq_resp = 0; ++ ipr = readl(iobase + (next_irq_resp / 32) * PART_OFF + IPR_OFF); ++ n++; ++ }while(n < ((INTC_NR_IRQS + 31) / 32 + 1)); ++ ++ if(irq_num != 0xffffffff) ++ { ++#ifdef CONFIG_SMP ++ irq_chip->next_irq_resp = irq_num; ++#else ++ irq_chip->next_irq_resp = irq_num + 1; ++ if(irq_chip->next_irq_resp >= INTC_NR_IRQS) ++ irq_chip->next_irq_resp = 0; ++#endif ++ do_IRQ(irq_num + IRQ_INTC_BASE); ++ }else{ ++ //pr_err("Error: Not Find any irq,check me %s %d.\n",__FILE__,__LINE__); ++ } ++ return IRQ_HANDLED; ++} ++ ++static void __init core_irq_setup(struct core_irq_chips *irq_chips) ++{ ++ struct irq_chip_data *chip = &irq_chips->chip_data; ++ int ret; ++ int i; ++ ++ irq_chips->percpu_irq_chip = alloc_percpu(struct core_irq_chip *); ++ if (!irq_chips->percpu_irq_chip) { ++ pr_err("ERROR:alloc cpu intc dev percpu fail!\n"); ++ return; ++ } ++ ++ ret = request_percpu_irq(irq_chips->irq, xburst2_irq_handler, "xburst2-intc", irq_chips->percpu_irq_chip); ++ if(ret) { ++ pr_err("ERROR:intc request error,ret: %d check %s %d\n", ret, __FILE__,__LINE__); ++ return; ++ } ++ ++ cpumask_clear(&chip->irq_idle_mask); ++ raw_spin_lock_init(&chip->lock); ++ ++ ++ for(i = 0;i < ARRAY_SIZE(chip->wake_up_flag);i++) ++ chip->wake_up_flag[i] = 0; ++ ++ for (i = 0; i < INTC_NR_IRQS; i++) { ++ cpumask_clear(&chip->affinity[i]); ++ chip->intc_num[i] = 0; ++ } ++ ++ pr_info("core irq setup finished\n"); ++} ++ ++static int ingenic_irq_domain_map(struct irq_domain *d, unsigned int irq, ++ irq_hw_number_t hw) ++{ ++ ++ irq_set_chip_data(irq, (void *)d->host_data); ++ irq_set_chip_and_handler(irq, &xburst2_irq_chip, handle_level_irq); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops ingenic_irq_domain_ops = { ++ .map = ingenic_irq_domain_map, ++ .xlate = irq_domain_xlate_onetwocell, ++}; ++ ++static int __init ingenic_intc_of_init(struct device_node *node) ++{ ++ struct core_irq_chips *irq_chips = &g_irq_chips; ++ void __iomem * iobase; ++ void __iomem * iobase_ex; ++ struct irq_domain *domain; ++ struct irq_chip_data *chip = &irq_chips->chip_data; ++ int irq; ++ struct property *prop; ++ const unsigned int *vp; ++ unsigned int pv; ++ int index = 0; ++ ++ if(WARN_ON(!node)) ++ return -ENODEV; ++ ++ iobase = of_iomap(node, 0); ++ WARN(!iobase, "Unable to map core intc iobase registers!\n"); ++ ++ iobase_ex = of_iomap(node, 1); ++ WARN(!iobase_ex, "Unable to map external intc iobase registers!\n"); ++ irq_chips->iobase = iobase_ex; ++ ++ irq = irq_of_parse_and_map(node, 0); ++ WARN(irq < 0, "Failed to get intc irq from DT!\n"); ++ ++ irq_chips->irq = irq; ++ ++ ++ of_property_for_each_u32(node, "cpu-intc-map", prop, vp, pv) { ++ if(index % 2) { ++ cpu_intc_map[index/2].dev_base = (unsigned int)iobase + pv; ++ } else { ++ cpu_intc_map[index/2].cpu_num = pv; ++ } ++ ++ index ++; ++ if(index > NR_CPUS * 2 - 1) { ++ printk("parse cpu-intc-iomap, intc define in dt is too large!\n"); ++ break; ++ } ++ } ++ ++ core_irq_setup(irq_chips); ++ ++ irq_chips->intc_clk = clk_get(NULL, "gate_intc"); ++ ++ domain = irq_domain_add_legacy(node, INTC_NR_IRQS, 8, 0, &ingenic_irq_domain_ops, chip); ++ WARN(!iobase, "Unable to register IRQ domain!\n"); ++ ++ percpu_irq_init(irq_chips, 0); ++ ++ return 0; ++} ++ ++ ++ ++static int __init ingenic_intc_init(struct device_node *node, ++ struct device_node *parent) ++{ ++ return ingenic_intc_of_init(node); ++} ++IRQCHIP_DECLARE(ingenic_intc, "ingenic,core-intc", ingenic_intc_init); ++ ++ ++asmlinkage void plat_irq_dispatch(void) ++{ ++ unsigned long status = read_c0_status(); ++ unsigned long cause = read_c0_cause(); ++ volatile unsigned long r = ((status & cause) >> 8) & 0xff; ++ ++ if(r) { ++ if (r & 8) { /* IPI */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 3); ++ } else if(r & 16) { /* OST */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 4); ++ } else if (r & 4) { /* INTC */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 2); ++ } else { /* Others */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + __ffs(r)); ++ } ++ ++ } else { ++ printk("IRQ Error, cpu: %d Cause:0x%08lx, Status:0x%08lx\n", smp_processor_id(), cause, status); ++ } ++} ++ ++void ingenic_irq_migration(int lock) ++{ ++ struct core_irq_chips *irq_chips = &g_irq_chips; ++ struct irq_chip_data *chip = &irq_chips->chip_data; ++ unsigned int cpu = smp_processor_id(); ++ void __iomem * iobase = NULL; ++ void __iomem * prev_iobase = NULL; ++ int i; ++ struct cpumask resp_mask; ++ unsigned int ipr = 0; ++ ++ if(lock){ ++ irq_lock(chip); ++ } ++ ++ prev_iobase = chip->iobase[cpu]; ++ for(i = 0;i < INTC_NR_IRQS;i++) ++ { ++ int group = i / 32; ++ int bitcount = i & 31; ++ unsigned int bit = 1 << bitcount; ++ int resp_cpu; ++ ++ if(bitcount == 0) { ++ ipr = readl(prev_iobase + group * PART_OFF + IPR_OFF); ++ } ++ ++ if(ipr == 0){ ++ i = (i & (~31)) + 31; ++ continue; ++ } ++ ++ if(ipr & bit){ ++ cpumask_and(&resp_mask,&chip->affinity[i],&chip->irq_idle_mask); ++ for_each_cpu(resp_cpu,&resp_mask){ ++ if(resp_cpu != cpu){ ++ //printk("migrate irq from cpu[%d] to cpu[%d], i: %d\n", cpu, resp_cpu, i); ++ iobase = chip->iobase[resp_cpu]; ++ if(!(readl(prev_iobase + PART_OFF * group + IMR_OFF) & bit)){ ++ writel(bit,prev_iobase + PART_OFF * group + IMSR_OFF); ++ writel(bit,iobase + PART_OFF * group + IMCR_OFF); ++ }else{ ++ writel(bit,iobase + PART_OFF * group + IMSR_OFF); ++ } ++ cpumask_clear_cpu(resp_cpu,&chip->irq_idle_mask); ++ chip->intc_num[i] = resp_cpu; ++ break; ++ } ++ } ++ } ++ } ++ if(lock){ ++ irq_unlock(chip); ++ } ++} ++EXPORT_SYMBOL_GPL(ingenic_irq_migration); ++ ++ ++void ingenic_irq_cpumask_idle(int idle) ++{ ++ struct core_irq_chips *irq_chips = &g_irq_chips; ++ struct irq_chip_data *chip = &irq_chips->chip_data; ++ int cpu = smp_processor_id(); ++ irq_lock(chip); ++ if(idle){ ++ cpumask_set_cpu(cpu,&chip->irq_idle_mask); ++ }else{ ++ cpumask_clear_cpu(cpu,&chip->irq_idle_mask); ++ } ++ irq_unlock(chip); ++} ++EXPORT_SYMBOL_GPL(ingenic_irq_cpumask_idle); ++ ++ ++ ++static unsigned long intc_saved[4]; ++extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); ++ ++void arch_suspend_disable_irqs(void) ++{ ++ struct irq_chip_data *chip_data = &g_irq_chips.chip_data; ++ struct core_irq_chip *irq_chip = *this_cpu_ptr(g_irq_chips.percpu_irq_chip); ++ struct core_irq_chips *irq_chips = &g_irq_chips; ++ ++ unsigned int *intc_wakeup = chip_data->wake_up_flag; ++ void __iomem * intc_base = irq_chip->iobase; ++ struct clk *intc_clk; ++ ++ ++ local_irq_disable(); ++ ++ intc_saved[0] = readl(intc_base + IMR_OFF); ++ intc_saved[1] = readl(intc_base + PART_OFF + IMR_OFF); ++ ++ /* Mask interrupts which are not wakeup src. */ ++ writel(0xffffffff & ~intc_wakeup[0], intc_base + IMSR_OFF); ++ writel(0xffffffff & ~intc_wakeup[1], intc_base + PART_OFF + IMSR_OFF); ++ if(IS_ERR(irq_chips->intc_clk)) ++ irq_chips->intc_clk = clk_get(NULL, "gate_intc"); ++ if (!IS_ERR(irq_chips->intc_clk)) ++ clk_prepare_enable(irq_chips->intc_clk); ++ ++ intc_saved[2] = readl(irq_chips->iobase + IMR_OFF); ++ intc_saved[3] = readl(irq_chips->iobase + PART_OFF + IMR_OFF); ++ ++ ++ writel(0xffffffff & ~intc_wakeup[0], irq_chips->iobase + IMR_OFF); ++ writel(0xffffffff & ~intc_wakeup[1], irq_chips->iobase + PART_OFF + IMR_OFF); ++ ++} ++ ++void arch_suspend_enable_irqs(void) ++{ ++ struct core_irq_chip *irq_chip = *this_cpu_ptr(g_irq_chips.percpu_irq_chip); ++ void __iomem * intc_base = irq_chip->iobase; ++ struct core_irq_chips *irq_chips = &g_irq_chips; ++ struct clk *intc_clk = irq_chips->intc_clk; ++ ++ writel(intc_saved[2],irq_chips->iobase + IMR_OFF); ++ writel(intc_saved[3],irq_chips->iobase + PART_OFF + IMR_OFF); ++ if (!IS_ERR(intc_clk)) ++ clk_disable_unprepare(intc_clk); ++ ++ writel(0xffffffff & ~intc_saved[0], intc_base + IMCR_OFF); ++ writel(0xffffffff & ~intc_saved[1], intc_base + PART_OFF + IMCR_OFF); ++ ++ local_irq_enable(); ++} +diff --git a/module_drivers/drivers/irqchip/irq-ingenic-cpu.c b/module_drivers/drivers/irqchip/irq-ingenic-cpu.c +new file mode 100644 +index 000000000..169bd7bd2 +--- /dev/null ++++ b/module_drivers/drivers/irqchip/irq-ingenic-cpu.c +@@ -0,0 +1,128 @@ ++/* ++ * Copyright (C) 2014 Ingenic Semiconductor Co., Ltd. ++ * ++ * Author: dongsheng.qiu, dongsheng.qiu@ingenic.com bo.liu@ingenic.com ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++static inline void unmask_ingenic_irq(struct irq_data *d) ++{ ++ set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); ++#ifdef CONFIG_SMP ++ ingenic_irq_cpumask_idle(1); ++#endif ++} ++ ++static inline void mask_ingenic_irq(struct irq_data *d) ++{ ++ clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); ++#ifdef CONFIG_SMP ++ ingenic_irq_cpumask_idle(0); ++ if(d->irq != CORE_INTC_IRQ){ ++ ingenic_irq_migration(1); ++ } ++#endif ++} ++ ++static struct irq_chip ingenic_cpu_irq_controller = { ++ .name = "XBurst2", ++ .irq_ack = mask_ingenic_irq, ++ .irq_mask = mask_ingenic_irq, ++ .irq_mask_ack = mask_ingenic_irq, ++ .irq_unmask = unmask_ingenic_irq, ++ .irq_eoi = unmask_ingenic_irq, ++ .irq_disable = mask_ingenic_irq, ++ .irq_enable = unmask_ingenic_irq, ++}; ++ ++asmlinkage void __weak plat_irq_dispatch(void) ++{ ++ unsigned int status = read_c0_status(); ++ unsigned int cause = read_c0_cause(); ++ ++ unsigned long pending = ((status & cause) >> 8) & 0xff; ++ int irq; ++ ++ if (!pending) { ++ spurious_interrupt(); ++ return; ++ } ++ ++ if(pending) { ++ if (pending & 8) { /* IPI */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 3); ++ } else if(pending & 16) { /* OST */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 4); ++ } else if (pending & 4) { /* INTC */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + 2); ++ } else { /* Others */ ++ do_IRQ(MIPS_CPU_IRQ_BASE + __ffs(pending)); ++ } ++ ++ } else { ++ //printk("IRQ Error, cpu: %d Cause:0x%08lx, Status:0x%08lx\n", smp_processor_id(), cause, status); ++ } ++} ++ ++static int ingenic_cpu_intc_map(struct irq_domain *d, unsigned int irq, ++ irq_hw_number_t hw) ++{ ++ static struct irq_chip *chip; ++ ++ chip = &ingenic_cpu_irq_controller; ++ ++ irq_set_percpu_devid(irq); ++ irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops ingenic_cpu_intc_irq_domain_ops = { ++ .map = ingenic_cpu_intc_map, ++ .xlate = irq_domain_xlate_onecell, ++}; ++ ++static void __init __ingenic_cpu_irq_init(struct device_node *of_node) ++{ ++ struct irq_domain *domain; ++ ++ /* Mask interrupts. */ ++ clear_c0_status(ST0_IM); ++ clear_c0_cause(CAUSEF_IP); ++ ++ domain = irq_domain_add_legacy(of_node, 8, MIPS_CPU_IRQ_BASE, 0, ++ &ingenic_cpu_intc_irq_domain_ops, NULL); ++ if (!domain) ++ panic("Failed to add irqdomain for MIPS CPU"); ++} ++ ++void __init ingenic_cpu_irq_init(void) ++{ ++ __ingenic_cpu_irq_init(NULL); ++} ++ ++int __init ingenic_cpu_irq_of_init(struct device_node *of_node, ++ struct device_node *parent) ++{ ++ __ingenic_cpu_irq_init(of_node); ++ return 0; ++} ++IRQCHIP_DECLARE(cpu_intc, "ingenic,cpu-interrupt-controller", ingenic_cpu_irq_of_init); +diff --git a/module_drivers/drivers/irqchip/irq-ingenic.c b/module_drivers/drivers/irqchip/irq-ingenic.c +new file mode 100644 +index 000000000..a9ea35037 +--- /dev/null ++++ b/module_drivers/drivers/irqchip/irq-ingenic.c +@@ -0,0 +1,266 @@ ++/* ++ * Copyright (C) 2009-2010, Lars-Peter Clausen ++ * ingenic platform IRQ support ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void __iomem *intc_base; ++static unsigned ingenic_num_chips; ++ ++#define TRACE_IRQ 1 ++#define PART_OFF 0x20 ++ ++#define ISR_OFF (0x00) ++#define IMR_OFF (0x04) ++#define IMSR_OFF (0x08) ++#define IMCR_OFF (0x0c) ++#define IPR_OFF (0x10) ++ ++#define DSR0_OFF (0x34) ++#define DMR0_OFF (0x38) ++#define DPR0_OFF (0x3c) ++#define DSR1_OFF (0x40) ++#define DMR1_OFF (0x44) ++#define DPR1_OFF (0x48) ++ ++static irqreturn_t ingenic_cascade(int irq, void *data) ++{ ++ uint32_t irq_reg; ++ unsigned i; ++ ++ for (i = 0; i < ingenic_num_chips; i++) { ++ irq_reg = readl(intc_base + (i * PART_OFF) + IPR_OFF); ++ if (!irq_reg) ++ continue; ++ generic_handle_irq(__fls(irq_reg) + (i * 32) + XBURST_SOC_IRQ_BASE); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void ingenic_irq_pm_set_mask(struct irq_chip_generic *gc, uint32_t unmask) ++{ ++ struct irq_chip_regs *regs = &gc->chip_types->regs; ++ ++ writel(unmask, gc->reg_base + regs->enable); ++ writel(~unmask, gc->reg_base + regs->disable); ++} ++ ++void ingenic_irq_suspend(struct irq_data *data) ++{ ++ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); ++ ingenic_irq_pm_set_mask(gc, gc->wake_active); ++} ++ ++void ingenic_irq_resume(struct irq_data *data) ++{ ++ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); ++ ingenic_irq_pm_set_mask(gc, gc->mask_cache); ++} ++ ++static int __init ingenic_intc_of_init(struct device_node *node, unsigned num_chips) ++{ ++ struct irq_chip_generic *gc; ++ struct irq_chip_type *ct; ++ struct irq_domain *domain; ++ struct resource res; ++ int ret, parent_irq; ++ unsigned i; ++ ++ parent_irq = irq_of_parse_and_map(node, 0); ++ if (!parent_irq) ++ return -EINVAL; ++ ++ ret = of_address_to_resource(node, 0, &res); ++ if (ret < 0) ++ return ret; ++ ++ ingenic_num_chips = num_chips; ++ intc_base = ioremap(res.start, ++ ((num_chips - 1) * PART_OFF) + 0x14); ++ ++ domain = irq_domain_add_legacy(node, num_chips * 32, XBURST_SOC_IRQ_BASE, 0, ++ &irq_domain_simple_ops, NULL); ++ if (!domain) ++ pr_warn("unable to register IRQ domain\n"); ++ ++ for (i = 0; i < num_chips; i++) { ++ /* Mask all irqs */ ++ writel(0xffffffff, intc_base + (i * PART_OFF) + IMSR_OFF); ++ ++ gc = irq_alloc_generic_chip("INTC", 1, XBURST_SOC_IRQ_BASE + (i * 32), ++ intc_base + (i * PART_OFF), ++ handle_level_irq); ++ gc->wake_enabled = IRQ_MSK(32); ++ ct = gc->chip_types; ++ ct->regs.enable = IMCR_OFF; ++ ct->regs.disable = IMSR_OFF; ++ ct->chip.irq_unmask = irq_gc_unmask_enable_reg; ++ ct->chip.irq_mask = irq_gc_mask_disable_reg; ++ ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; ++ ct->chip.irq_set_wake = irq_gc_set_wake; ++ ct->chip.irq_suspend = ingenic_irq_suspend; ++ ct->chip.irq_resume = ingenic_irq_resume; ++#ifdef CONFIG_SPARSE_IRQ ++ irq_alloc_descs(gc->irq_base, -1, gc->num_ct, of_node_to_nid(domain->of_node)); ++#endif ++ irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, IRQ_NOPROBE | IRQ_LEVEL); ++ } ++ ++ if (request_irq(parent_irq, ingenic_cascade, 0, "ingenic cascade interrupt", NULL)) ++ pr_err("Failed to register ingenic cascade interrupt\n"); ++ ++ /* enable cpu interrupt mask */ ++ set_c0_status(IE_IRQ0 | IE_IRQ1); ++ return 0; ++} ++ ++static int __init ingenic_intc_init(struct device_node *node, ++ struct device_node *parent) ++{ ++ return ingenic_intc_of_init(node, INTC_CHIP_NUM); ++} ++IRQCHIP_DECLARE(ingenic_intc, "ingenic,ingenic-intc", ingenic_intc_init); ++ ++#if 0 ++/************************************************************************* ++if nand was config: ++ After cpu was woke up,the mcu should be handler ++those interruptions of GPIO0,so that it was convenient to read/write nand, ++the process of GPIO's interruption as follows ++ |----------------------------------| ++ | GPIO | ++ | | | ++ | |--****--INTC---------->| | ++ | | MASK UNMASK | | ++ | CPU MCU | ++ | | | ++ | MAILEBOX | ++ | | <---------------------| | ++ | | | ++ | ingenicdma | ++ | | | ++ | soft intc | ++ | | | ++ | handler func of intc | ++ |__________________________________| ++ ++ On the contraty, when cpu will go to sleep, the cpu should be handler ++GPIO0's interruptions, it was convenient to the next step, which is that cpu was ++woke up. ++ GPIO ++ | ++ |---------INTC-------->| ++ | unmask mask | ++ CPU MCU ++ | ++ | ++ handler func of intc ++************************************************************************/ ++ ++#define IRQ_IS_GGPIO(irq) (irq >= IRQ_GPIO0 && irq <= IRQ_GPIO_END) ++extern void mcu_gpio_register(unsigned int ggpio, unsigned int reg); ++extern void mcu_gpio_unregister(unsigned int ggpio); ++ ++void ingenic_change_irq_destination(int irq, bool cpu_to_mcu, unsigned gpio_pending_reg) ++{ ++ int reg = 0; ++ if (WARN((irq < 0 || irq > 63), ++ "irq %d not support switch between cpu and mcu\n", ++ irq)) ++ return; ++ ++ if (cpu_to_mcu) { ++ if (irq < 32) { ++ writel((1 << irq), intc_base + IMSR_OFF); ++ if (IRQ_IS_GGPIO(irq)) ++ mcu_gpio_register((irq-IRQ_GPIO0), gpio_pending_reg); ++ reg = readl(intc_base + DMR0_OFF); ++ writel((reg & (~(1 << irq))), intc_base + DMR0_OFF); ++ } else { ++ writel((1 << (irq - 32)), intc_base + PART_OFF + IMSR_OFF); ++ reg = readl(intc_base + DMR1_OFF); ++ writel((reg & (~(1 << (irq - 32)))), intc_base + DMR1_OFF); ++ } ++ } else { ++ if (irq < 32) { ++ reg = readl(intc_base + DMR0_OFF); ++ writel((reg | (1 << irq)), intc_base + DMR0_OFF); ++ if (IRQ_IS_GGPIO(irq)) ++ mcu_gpio_unregister((irq-IRQ_GPIO0)); ++ writel((1 << irq), intc_base + IMCR_OFF); ++ } else { ++ reg = readl(intc_base + DMR1_OFF); ++ writel((reg | (1 << (irq - 32))), intc_base + DMR1_OFF); ++ writel((1 << (irq - 32)), intc_base + PART_OFF + IMCR_OFF); ++ } ++ } ++ return; ++} ++EXPORT_SYMBOL_GPL(ingenic_change_irq_destination); ++#endif ++#ifdef CONFIG_DEBUG_FS ++static inline void intc_seq_reg(struct seq_file *s, const char *name, ++ unsigned int reg) ++{ ++ seq_printf(s, "%s:\t\t%08x\n", name, readl(intc_base + reg)); ++} ++ ++static int intc_regs_show(struct seq_file *s, void *unused) ++{ ++ intc_seq_reg(s, "Status", ISR_OFF); ++ intc_seq_reg(s, "Mask", IMR_OFF); ++ intc_seq_reg(s, "Pending", IPR_OFF); ++ ++ return 0; ++} ++ ++static int intc_regs_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, intc_regs_show, NULL); ++} ++ ++static const struct file_operations intc_regs_operations = { ++ .open = intc_regs_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int __init intc_debugfs_init(void) ++{ ++ (void) debugfs_create_file("intc_regs", S_IFREG | S_IRUGO, ++ NULL, NULL, &intc_regs_operations); ++ return 0; ++} ++subsys_initcall(intc_debugfs_init); ++#endif +diff --git a/module_drivers/drivers/md_export/Makefile b/module_drivers/drivers/md_export/Makefile +new file mode 100644 +index 000000000..70928c85b +--- /dev/null ++++ b/module_drivers/drivers/md_export/Makefile +@@ -0,0 +1 @@ ++obj-y += md_export.o +\ No newline at end of file +diff --git a/module_drivers/drivers/md_export/md_export.c b/module_drivers/drivers/md_export/md_export.c +new file mode 100644 +index 000000000..c0da81f2f +--- /dev/null ++++ b/module_drivers/drivers/md_export/md_export.c +@@ -0,0 +1,3 @@ ++#include ++ ++EXPORT_SYMBOL_GPL(sched_setscheduler); +\ No newline at end of file +diff --git a/module_drivers/drivers/media/Makefile b/module_drivers/drivers/media/Makefile +new file mode 100644 +index 000000000..8c25d878f +--- /dev/null ++++ b/module_drivers/drivers/media/Makefile +@@ -0,0 +1,3 @@ ++obj-y += i2c/ ++obj-y += platform/ ++obj-y += v4l2-core/ +diff --git a/module_drivers/drivers/media/i2c/Kconfig b/module_drivers/drivers/media/i2c/Kconfig +new file mode 100644 +index 000000000..80dc8562e +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/Kconfig +@@ -0,0 +1,4 @@ ++ ++source "module_drivers/drivers/media/i2c/ingenic-isp/Kconfig" ++source "module_drivers/drivers/media/i2c/ingenic-isp-v2/Kconfig" ++source "module_drivers/drivers/media/i2c/ingenic-cim/Kconfig" +diff --git a/module_drivers/drivers/media/i2c/Makefile b/module_drivers/drivers/media/i2c/Makefile +new file mode 100644 +index 000000000..b162432c6 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_VIDEO_INGENIC_ISP) += ingenic-isp/ ++obj-$(CONFIG_VIDEO_INGENIC_ISP_V2) += ingenic-isp-v2/ ++obj-$(CONFIG_VIDEO_INGENIC_CIM) += ingenic-cim/ +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/Kconfig b/module_drivers/drivers/media/i2c/ingenic-cim/Kconfig +new file mode 100644 +index 000000000..7acc00919 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/Kconfig +@@ -0,0 +1,56 @@ ++comment "ingenic-cim camera sensor drivers" ++ ++config INGENIC_CIM_CAMERA_OV2735B ++ tristate "ov2735 camera DVP interface support" ++ depends on VIDEO_INGENIC_CIM && I2C ++ help ++ This is a ingenic-cim camera driver for the OmniVision OV2735 sensor DVP interface ++ ++config INGENIC_CIM_CAMERA_AR0144 ++ tristate "ar0144 camera mipi interface support" ++ depends on VIDEO_INGENIC_CIM && I2C ++ help ++ This is a ingenic-cim camera driver for the OmniVision AR0144 sensor MIPI interface ++ ++config INGENIC_CIM_CAMERA_OV5640 ++ tristate "ov5640 camera DVP interface support" ++ depends on VIDEO_INGENIC_CIM && I2C ++ help ++ This is a ingenic-cim camera driver for the OmniVision OV5640 sensor DVP interface ++ ++config INGENIC_CIM_CAMERA_SC031GS ++ tristate "sc031gs camera DVP interface support" ++ depends on VIDEO_INGENIC_CIM && I2C ++ help ++ This is a ingenic-cim camera driver for the OmniVision SC031GS sensor DVP interface ++ ++config INGENIC_CIM_CAMERA_MIPI_SC031GS ++ tristate "sc031gs camera mipi interface support" ++ depends on VIDEO_INGENIC_CIM && I2C ++ help ++ This is a ingenic-cim camera driver for the OmniVision SC031GS sensor MIPI interface ++ ++config INGENIC_CIM_CAMERA_OV5645 ++ tristate "ov5645 camera mipi interface support" ++ depends on VIDEO_INGENIC_CIM && I2C ++ help ++ This is a ingenic-cim camera driver for the OmniVision OV5645 sensor MIPI interface ++ ++config INGENIC_CIM_CAMERA_OV9281 ++ tristate "ov9281 camera mipi interface support" ++ depends on VIDEO_INGENIC_CIM && I2C ++ help ++ This is a ingenic-cim camera driver for the OmniVision OV9281 sensor MIPI interface ++ ++config INGENIC_CIM_CAMERA_OV9281_DVP_SNAPSHOT ++ tristate "ov9281 camera support cim snapshot" ++ depends on VIDEO_INGENIC_CIM && I2C ++ help ++ This is a ingenic-cim camera driver for the OmniVision OV9281 sensor DVP interface ++ ++config INGENIC_CIM_CAMERA_OV4689 ++ tristate "ov4689 camera mipi interface support" ++ depends on VIDEO_INGENIC_CIM && I2C ++ help ++ This is a ingenic-cim camera driver for the OmniVision OV4689 sensor MIPI interface ++ +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/Makefile b/module_drivers/drivers/media/i2c/ingenic-cim/Makefile +new file mode 100644 +index 000000000..a353d2a3c +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/Makefile +@@ -0,0 +1,12 @@ ++obj-$(CONFIG_INGENIC_CIM_CAMERA_OV2735B) += ov2735b.o ++obj-$(CONFIG_INGENIC_CIM_CAMERA_AR0144) += ar0144.o ++obj-$(CONFIG_INGENIC_CIM_CAMERA_OV5640) += ov5640.o ++obj-$(CONFIG_INGENIC_CIM_CAMERA_SC031GS) += sc031gs.o ++obj-$(CONFIG_INGENIC_CIM_CAMERA_MIPI_SC031GS) += sc031gs-mipi.o ++obj-$(CONFIG_INGENIC_CIM_CAMERA_OV5645) += ov5645.o ++obj-$(CONFIG_INGENIC_CIM_CAMERA_OV9281) += ov9281.o ++obj-$(CONFIG_INGENIC_CIM_CAMERA_OV9281_DVP_SNAPSHOT) += ov9281-dvp-snapshot.o ++obj-$(CONFIG_INGENIC_CIM_CAMERA_OV4689) += ov4689.o ++ ++ccflags-y += -I$(srctree)/module_drivers/drivers/media/platform/ingenic-cim/ ++ +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/ar0144.c b/module_drivers/drivers/media/i2c/ingenic-cim/ar0144.c +new file mode 100644 +index 000000000..49c1a7d03 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/ar0144.c +@@ -0,0 +1,935 @@ ++/* ++ * ar0144 Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++ ++#define AR0144_REG_END 0xffff ++#define AR0144_REG_DELAY 0xfffe ++#define AR0144_REG_CHIP_ID 0x3000 ++#define AR0144_CHIP_ID_HIGH 0x03 ++#define AR0144_CHIP_ID_LOW 0x56 ++ ++#define ar0144_DEFAULT_WIDTH 640 ++#define ar0144_DEFAULT_HEIGHT 480 ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++#define ar0144_FLIP_VAL ((unsigned char)0x04) ++#define ar0144_FLIP_MASK ((unsigned char)0x04) ++ ++/* whether sensor support high resolution (> vga) preview or not */ ++#define SUPPORT_HIGH_RESOLUTION_PRE 1 ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ u16 reg_num; ++ u16 value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++struct ar0144_win_size { ++ char *name; ++ int width; ++ int height; ++ const struct regval_list *regs; ++ unsigned int mbus_code; ++}; ++ ++ ++struct ar0144_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ar0144_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct ar0144_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++// struct soc_camera_subdev_desc ssdd_dt; ++ struct v4l2_subdev_platform_data *sd_pdata; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ int (*power)(struct i2c_client *client, int on); ++ int (*reset)(struct i2c_client *client); ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++unsigned short ar0144_read_reg(struct i2c_client *client, u16 reg, unsigned char *value) ++{ ++ int ret; ++ unsigned short r = cpu_to_be16(reg); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 2, ++ .buf = value, ++ } ++ }; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++int ar0144_write_reg(struct i2c_client *client, unsigned short reg, unsigned short value) ++{ ++ int ret; ++ uint8_t buf[4] = {reg >> 8, reg & 0xff, value >> 8, value & 0xff}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 4, ++ .buf = buf, ++ }; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static struct regval_list ar0144_720p_regs_mipi[] = { ++ //mipibps 444 ++ //pclk 74.00 ++ //hts:0x5D0 VTS 0x338 ++ //again default 0x3060 = 0x0010 ++ //expo 0x3012 = 0x01F3 ++ //[ar0144_720P_60FPS] ++// { AR0144_REG_DELAY, 200}, ++ { 0x301A, 0x00D9 }, // RESET_REGISTER ++ { AR0144_REG_DELAY, 200}, ++ { 0x301A, 0x3058 }, // RESET_REGISTER ++ { AR0144_REG_DELAY, 100}, ++ { 0x3F4C, 0x003F }, // PIX_DEF_1D_DDC_LO_DEF ++ { 0x3F4E, 0x0018 }, // PIX_DEF_1D_DDC_HI_DEF ++ { 0x3F50, 0x17DF }, // PIX_DEF_1D_DDC_EDGE ++ { 0x30B0, 0x0028 }, // DIGITAL_TEST ++ { AR0144_REG_DELAY, 200}, ++ { 0x3ED6, 0x3CB5 }, // DAC_LD_10_11 ++ { 0x3ED8, 0x8765 }, // DAC_LD_12_13 ++ { 0x3EDA, 0x8888 }, // DAC_LD_14_15 ++ { 0x3EDC, 0x97FF }, // DAC_LD_16_17 ++ { 0x3EF8, 0x6522 }, // DAC_LD_44_45 ++ { 0x3EFA, 0x2222 }, // DAC_LD_46_47 ++ { 0x3EFC, 0x6666 }, // DAC_LD_48_49 ++ { 0x3F00, 0xAA05 }, // DAC_LD_52_53 ++ { 0x3EE2, 0x180E }, // DAC_LD_22_23 ++ { 0x3EE4, 0x0808 }, // DAC_LD_24_25 ++ { 0x3EEA, 0x2A09 }, // DAC_LD_30_31 ++ { 0x3060, 0x003C }, // ANALOG_GAIN ++ { 0x30FE, 0x00A8 }, // NOISE_PEDESTAL ++ { 0x3092, 0x00CF }, // ROW_NOISE_CONTROL ++ { 0x3268, 0x0030 }, // SEQUENCER_CONTROL ++ { 0x3786, 0x0006 }, // DIGITAL_CTRL_1 ++ { 0x3F4A, 0x0F70 }, // DELTA_DK_PIX_THRES ++ { 0x306E, 0x4810 }, // DATAPATH_SELECT ++ { 0x3064, 0x1802 }, // SMIA_TEST ++ { 0x3EF6, 0x804D }, // DAC_LD_42_43 ++ { 0x3180, 0xC08F }, // DELTA_DK_CONTROL ++ { 0x30BA, 0x7623 }, // DIGITAL_CTRL ++ { 0x3176, 0x0480 }, // DELTA_DK_ADJUST_GREENR ++ { 0x3178, 0x0480 }, // DELTA_DK_ADJUST_RED ++ { 0x317A, 0x0480 }, // DELTA_DK_ADJUST_BLUE ++ { 0x317C, 0x0480 }, // DELTA_DK_ADJUST_GREENB ++ { 0x302A, 0x0006 }, // VT_PIX_CLK_DIV ++ { 0x302C, 0x0001 }, // VT_SYS_CLK_DIV ++ { 0x302E, 0x0004 }, // PRE_PLL_CLK_DIV ++ { 0x3030, 0x004A }, // PLL_MULTIPLIER ++ { 0x3036, 0x000C }, // OP_PIX_CLK_DIV ++ { 0x3038, 0x0001 }, // OP_SYS_CLK_DIV ++ { 0x30B0, 0x0028 }, // DIGITAL_TEST ++ { AR0144_REG_DELAY, 100}, ++ { 0x31AE, 0x0202 }, // SERIAL_FORMAT ++ { 0x31AC, 0x0C0C }, // DATA_FORMAT_BITS ++ { 0x31B0, 0x0042 }, // FRAME_PREAMBLE ++ { 0x31B2, 0x002E }, // LINE_PREAMBLE ++ { 0x31B4, 0x2633 }, // MIPI_TIMING_0 ++ { 0x31B6, 0x210E }, // MIPI_TIMING_1 ++ { 0x31B8, 0x20C7 }, // MIPI_TIMING_2 ++#if 0 ++ { 0x31BA, 0x0105 }, // MIPI_TIMING_3 ++ { 0x31BC, 0x0004 }, // MIPI_TIMING_4 ++#else ++ { 0x31BA, 0x01a5 }, // MIPI_TIMING_3 ++ { 0x31BC, 0x8004 }, // MIPI_TIMING_4 ++#endif ++ { 0x3002, 0x0028 }, // Y_ADDR_START ++ { 0x3004, 0x0004 }, // X_ADDR_START ++ { 0x3006, 0x02F7 }, // Y_ADDR_END ++ { 0x3008, 0x0503 }, // X_ADDR_END ++ { 0x300A, 0x0338 }, // FRAME_LENGTH_LINES ++ { 0x300C, 0x05D0 }, // LINE_LENGTH_PCK ++// { 0x3012, 0x0064 }, // COARSE_INTEGRATION_TIME ++ { 0x3012, 0x01F3 }, // COARSE_INTEGRATION_TIME ++ { 0x30A2, 0x0001 }, // X_ODD_INC ++ { 0x30A6, 0x0001 }, // Y_ODD_INC ++ { 0x3040, 0x0000 }, // READ_MODE ++ { 0x3064, 0x1882 }, // SMIA_TEST ++ { 0x3064, 0x1802 }, // SMIA_TEST ++ { 0x3028, 0x0010 }, // ROW_SPEED ++// { 0x301D, 0x0003 }, // FLIP ++#ifdef SNAPSHOT ++ { 0x301A, 0x0958 }, // RESET_REGISTER stream_off ++ { 0x30CE, 0x0120 }, ++#else ++#endif ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++ ++#if 0 ++ ++static const struct regval_list ar0144_wb_auto_regs[] = { ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ar0144_wb_incandescence_regs[] = { ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ar0144_wb_daylight_regs[] = { ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ar0144_wb_fluorescent_regs[] = { ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ar0144_wb_cloud_regs[] = { ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct mode_list ar0144_balance[] = { ++ {0, ar0144_wb_auto_regs}, {1, ar0144_wb_incandescence_regs}, ++ {2, ar0144_wb_daylight_regs}, {3, ar0144_wb_fluorescent_regs}, ++ {4, ar0144_wb_cloud_regs}, ++}; ++ ++ ++static const struct regval_list ar0144_effect_normal_regs[] = { ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ar0144_effect_grayscale_regs[] = { ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ar0144_effect_sepia_regs[] = { ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ar0144_effect_colorinv_regs[] = { ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ar0144_effect_sepiabluel_regs[] = { ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct mode_list ar0144_effect[] = { ++ {0, ar0144_effect_normal_regs}, {1, ar0144_effect_grayscale_regs}, ++ {2, ar0144_effect_sepia_regs}, {3, ar0144_effect_colorinv_regs}, ++ {4, ar0144_effect_sepiabluel_regs}, ++}; ++ ++#endif ++ ++static struct ar0144_win_size ar0144_supported_win_sizes[] = { ++ { ++ .name = "720P", ++ .width = 1920 , ++ .height = 720, ++ .regs = ar0144_720p_regs_mipi, ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ }, ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(ar0144_supported_win_sizes)) ++ ++/* ++ * General functions ++ */ ++ ++static struct ar0144_priv *to_ov2735b(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ar0144_priv, ++ subdev); ++} ++ ++static int ar0144_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != AR0144_REG_END) { ++ if (vals->reg_num == AR0144_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ar0144_write_reg(client, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++#if 0 ++static int ar0144_mask_set(struct i2c_client *client, ++ u16 reg, u16 mask, u16 set) ++{ ++ int ret = 0; ++ unsigned char value[2] = {0}; ++ ret = ar0144_read_reg(client, reg, value); ++ if (ret < 0) ++ return ret; ++ ++ val &= ~mask; ++ val |= set & mask; ++ ++ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); ++ ++ return ar0144_write_reg(client, reg, val); ++} ++#endif ++ ++/* ++ * soc_camera_ops functions ++ */ ++ ++ ++/*hw ops*/ ++static int ar0144_hw_power(struct i2c_client *client, int on) ++{ ++ struct ar0144_priv *priv = to_ov2735b(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int ar0144_reset(struct i2c_client *client) ++{ ++ struct ar0144_priv *priv = to_ov2735b(client); ++ ++ if(priv->resetb_gpio) { ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ msleep(10); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ msleep(10); ++ } ++ return 0; ++} ++ ++ ++ ++/*ctrl_ops*/ ++static int ar0144_g_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ar0144_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0144_priv *priv = to_ov2735b(client); ++ ++ switch (ctrl->id) { ++ ++ case V4L2_CID_VFLIP: ++ ctrl->val = priv->flag_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->val = priv->flag_hflip; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++ ++static int ar0144_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ int ret = 0; ++#if 0 ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ar0144_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0144_priv *priv = to_ov2735b(client); ++ int i = 0; ++ u16 value; ++ ++ int balance_count = ARRAY_SIZE(ar0144_balance); ++ int effect_count = ARRAY_SIZE(ar0144_effect); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VFLIP: ++ value = ctrl->val ? ar0144_FLIP_VAL : 0x00; ++ priv->flag_vflip = ctrl->val ? 1 : 0; ++// ret = ar0144_mask_set(client, 0x301D, ar0144_FLIP_MASK, value); ++ break; ++ ++ case V4L2_CID_HFLIP: ++ value = ctrl->val ? ar0144_FLIP_VAL : 0x00; ++ priv->flag_hflip = ctrl->val ? 1 : 0; ++// ret = ar0144_mask_set(client, 0x301D, ar0144_FLIP_MASK, value); ++ break; ++ ++ default: ++ dev_err(&client->dev, "no V4L2 CID: 0x%x ", ctrl->id); ++ return -EINVAL; ++ } ++ ++#endif ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ar0144_ctrl_ops = { ++ .s_ctrl = ar0144_s_ctrl, ++ .g_volatile_ctrl = ar0144_g_ctrl, ++}; ++ ++/*core_ops*/ ++static int ar0144_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0144_priv *priv = to_ov2735b(client); ++ ++ if(priv->sd_pdata) { ++ if(on) ++ return regulator_bulk_enable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ else ++ return regulator_bulk_disable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ } else if(priv->power){ ++ return priv->power(client, on); ++ } else { ++ dev_err(&client->dev, "ar0144_s_power failde"); ++ return -EINVAL; ++ } ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ar0144_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg > 0xff) ++ return -EINVAL; ++ ++ ret = ar0144_read_reg(client, reg->reg, reg->val); ++ ++ return 0; ++} ++ ++static int ar0144_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg > 0xff || ++ reg->val > 0xff) ++ return -EINVAL; ++ ++ return ar0144_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++static int ar0144_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!enable ) { ++ dev_info(&client->dev, "stream down\n"); ++#ifdef SNAPSHOT ++ ar0144_write_reg(client, 0x301A, 0x0958); ++#else ++ ar0144_write_reg(client, 0x301A, 0x0058); ++#endif ++ return 0; ++ } ++ ++ dev_info(&client->dev, "stream on\n"); ++#ifdef SNAPSHOT ++ ar0144_write_reg(client, 0x301A, 0x095C); ++#else ++ ar0144_write_reg(client, 0x301A, 0x005C); ++#endif ++ ++ return 0; ++} ++ ++/* Select the nearest higher resolution for capture */ ++static const struct ar0144_win_size *ar0144_select_win(u32 *code, u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(ar0144_supported_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(ar0144_supported_win_sizes); i++) { ++ if ((*width >= ar0144_supported_win_sizes[i].width) && ++ (*height >= ar0144_supported_win_sizes[i].height) && ++ (*code == ar0144_supported_win_sizes[i].mbus_code)) { ++ *width = ar0144_supported_win_sizes[i].width; ++ *height = ar0144_supported_win_sizes[i].height; ++ return &ar0144_supported_win_sizes[i]; ++ } ++ } ++ return NULL; ++} ++ ++static int ar0144_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0144_priv *priv = to_ov2735b(client); ++ ++ if(!priv->win) ++ return -EINVAL; ++ ++ sel->r.top = 0; ++ sel->r.left = 0; ++ sel->r.width = priv->win->width; ++ sel->r.height = priv->win->height; ++ ++ return 0; ++} ++ ++static int ar0144_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0144_priv *priv = to_ov2735b(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ if(priv->win){ ++ mf->width = priv->win->width; ++ mf->height = priv->win->height; ++ } else { ++ mf->width = ar0144_DEFAULT_WIDTH;//priv->win->width; ++ mf->height = ar0144_DEFAULT_HEIGHT;//priv->win->height; ++ } ++ mf->code = priv->cfmt_code; ++ ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ar0144_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code) ++{ ++ struct ar0144_priv *priv = to_ov2735b(client); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* reset hardware */ ++ ar0144_reset(client); ++ ++ /* initialize the sensor with default data */ ++#if 0 ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ret = ar0144_write_array(client, ov2735b_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = ar0144_write_array(client, ar0144_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = ar0144_write_array(client, ar0144_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++#endif ++ /* set size win */ ++ dev_dbg(&client->dev, "priv->win.width = %d\n", priv->win->width); ++ dev_dbg(&client->dev, "priv->win.height = %d\n", priv->win->height); ++ ++ ret = ar0144_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ ar0144_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int ar0144_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0144_priv *priv = to_ov2735b(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ priv->win = ar0144_select_win(&mf->code ,&mf->width, &mf->height); ++ if(!priv->win) ++ return -EINVAL; ++ ++ mf->field = V4L2_FIELD_NONE; ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ ar0144_set_params(client, &mf->width, ++ &mf->height, mf->code); ++ if(cfg) ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int ar0144_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= ARRAY_SIZE(ar0144_supported_win_sizes)) ++ return -EINVAL; ++ ++ code->code = ar0144_supported_win_sizes[code->index].mbus_code; ++ return 0; ++} ++ ++static int ar0144_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int i, j; ++ int num_valid = -1; ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++ fse->code = ar0144_supported_win_sizes[index].mbus_code; ++ fse->min_width = ar0144_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = ar0144_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++ ++} ++ ++static int ar0144_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++ /*in dts*/ ++ return 0; ++} ++ ++static struct v4l2_subdev_core_ops ar0144_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ar0144_g_register, ++ .s_register = ar0144_s_register, ++#endif ++ .s_power = ar0144_s_power, ++}; ++ ++static struct v4l2_subdev_video_ops ar0144_subdev_video_ops = { ++ .s_stream = ar0144_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops ar0144_subdev_pad_ops = { ++ .enum_mbus_code = ar0144_enum_mbus_code, ++ .enum_frame_size = ar0144_enum_frame_size, ++ .get_fmt = ar0144_get_fmt, ++ .set_fmt = ar0144_set_fmt, ++ .get_mbus_config = ar0144_g_mbus_config, ++ .get_selection = ar0144_get_selection, ++}; ++ ++static struct v4l2_subdev_ops ar0144_subdev_ops = { ++ .core = &ar0144_subdev_core_ops, ++ .video = &ar0144_subdev_video_ops, ++ .pad = &ar0144_subdev_pad_ops, ++}; ++ ++ ++static int ar0144_detect(struct i2c_client *client, unsigned int *ident) ++{ ++ unsigned char value[2] = {0}; ++ int ret; ++ ++ ret = ar0144_read_reg(client, AR0144_REG_CHIP_ID, value); ++ ++ if (ret < 0) ++ return ret; ++ ++ if (value[0] != AR0144_CHIP_ID_HIGH) ++ return -ENODEV; ++ ++ if (value[1] != AR0144_CHIP_ID_LOW) ++ return -ENODEV; ++ ++ return 0; ++} ++ ++ ++static int ar0144_probe_dt(struct i2c_client *client, ++ struct ar0144_priv *priv) ++{ ++ struct v4l2_subdev_platform_data *sd_pdata = priv->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies > 0) { ++ ++ sd_pdata = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev_platform_data), GFP_KERNEL); ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ devm_kfree(&client->dev,sd_pdata); ++ return -ENOMEM; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ devm_regulator_bulk_get(&client->dev, sd_pdata->num_regulators, sd_pdata->regulators); ++ ++ //if(!client->dev.platform_data) /*TODO*/ ++ // client->dev.platform_data = &priv->sd_pdata; ++ } else { ++ ++ ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power vcc-en GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Request the power resetb GPIO asserted */ ++ priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", ++ GPIOD_OUT_LOW); ++ if (!priv->resetb_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->resetb_gpio)) ++ return PTR_ERR(priv->resetb_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->power = ar0144_hw_power; ++ // priv->reset = ar0144_hw_reset; /*TODO*/ ++ } ++ return 0; ++} ++ ++static int ar0144_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ar0144_priv *priv; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "ar0144: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct ar0144_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++ ++ /*mclk gate close*/ ++// *(volatile unsigned int *)0xb0000024 &= ~(1 << 5); ++ ++ ret = ar0144_probe_dt(client, priv); ++ if (ret) ++ goto err_probe_dt; ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &ar0144_subdev_ops); ++ ++ /* add handler */ ++ v4l2_ctrl_handler_init(&priv->hdl, 2); ++ ++ v4l2_ctrl_new_std(&priv->hdl, &ar0144_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0144_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ ++ priv->subdev.ctrl_handler = &priv->hdl; ++ if (priv->hdl.error) { ++ ret = priv->hdl.error; ++ goto err_hdl; ++ } ++ ++#if 1 ++ ret = ar0144_detect(client, NULL); ++ if(ret < 0){ ++ v4l_err(client,"chip found @ 0x%x (%s) is not an ar0144 chip.\n", ++ client->addr << 1, client->adapter->name); ++ goto err_detect; ++ } ++#endif ++ ++ ret = v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_async_register_subdev; ++ ++ dev_info(&adapter->dev, "ar0144 Probed\n"); ++ ++ return 0; ++ ++err_async_register_subdev: ++err_detect: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_hdl: ++ v4l2_device_unregister_subdev(&priv->subdev); ++err_probe_dt: ++ v4l2_clk_put(priv->clk); ++ devm_kfree(&client->dev, priv); ++ return ret; ++} ++ ++static int ar0144_remove(struct i2c_client *client) ++{ ++ struct ar0144_priv *priv = to_ov2735b(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ devm_kfree(&client->dev, priv); ++ return 0; ++} ++ ++static const struct i2c_device_id ar0144_id[] = { ++ { "ar0144", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ar0144_id); ++static const struct of_device_id ar0144_of_match[] = { ++ {.compatible = "onsemi,ar0144", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ar0144_of_match); ++static struct i2c_driver ar0144_i2c_driver = { ++ .driver = { ++ .name = "ar0144", ++ .of_match_table = of_match_ptr(ar0144_of_match), ++ }, ++ .probe = ar0144_probe, ++ .remove = ar0144_remove, ++ .id_table = ar0144_id, ++}; ++module_i2c_driver(ar0144_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for onsemi ar0144 sensor"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/ov2735b.c b/module_drivers/drivers/media/i2c/ingenic-cim/ov2735b.c +new file mode 100644 +index 000000000..790c69e17 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/ov2735b.c +@@ -0,0 +1,999 @@ ++/* ++ * ov2735b Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++ ++#define OV2735B_CHIP_ID_H (0x27) ++#define OV2735B_CHIP_ID_L (0x35) ++#define OV2735B_REG_END 0xff ++#define OV2735B_REG_DELAY 0x00 ++#define OV2735B_PAGE_REG 0xfd ++ ++#define ov2735b_DEFAULT_WIDTH 640 ++#define ov2735b_DEFAULT_HEIGHT 480 ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++#define ov2735b_FLIP_VAL ((unsigned char)0x04) ++#define ov2735b_FLIP_MASK ((unsigned char)0x04) ++ ++/* whether sensor support high resolution (> vga) preview or not */ ++#define SUPPORT_HIGH_RESOLUTION_PRE 1 ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++struct ov2735b_win_size { ++ char *name; ++ int width; ++ int height; ++ const struct regval_list *regs; ++ unsigned int mbus_code; ++}; ++ ++ ++struct ov2735b_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov2735b_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct ov2735b_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++// struct soc_camera_subdev_desc ssdd_dt; ++ struct v4l2_subdev_platform_data *sd_pdata; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ int (*power)(struct i2c_client *client, int on); ++ int (*reset)(struct i2c_client *client); ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++unsigned short ov2735b_read_reg(struct i2c_client *client, unsigned char reg, unsigned char *value) ++{ ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 1, ++ .buf = ®, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++int ov2735b_write_reg(struct i2c_client *client, unsigned char reg, unsigned short value) ++{ ++ unsigned char buf[2] = {reg, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++ ++} ++ ++static struct regval_list ov2735b_1080p_regs[] = { ++ {0xfd, 0x00}, ++ {OV2735B_REG_DELAY, 0x05}, ++ {0xfd, 0x00}, ++ {0x2f, 0x10}, ++ {0x34, 0x00}, ++ {0x30, 0x15}, ++ {0x33, 0x01}, ++ {0x35, 0x20}, ++ {0x1d, 0xa5}, ++ {0xfd, 0x01}, ++ {0x0d, 0x00}, ++ {0x30, 0x00}, ++ {0x03, 0x01}, ++ {0x04, 0x8f}, ++ {0x01, 0x01}, ++ {0x09, 0x00}, ++ {0x0a, 0x20}, ++ {0x06, 0x0a}, ++ {0x24, 0x10}, ++ {0x01, 0x01}, ++ {0xfb, 0x73}, ++ {0x01, 0x01}, ++ {0xfd, 0x01}, ++ {0x1a, 0x6b}, ++ {0x1c, 0xea}, ++ {0x16, 0x0c}, ++ {0x21, 0x00}, ++ {0x11, 0x63}, ++ {0x19, 0xc3}, ++ {0x26, 0xda}, ++ {0x29, 0x01}, ++ {0x33, 0x6f}, ++ {0x2a, 0xd2}, ++ {0x2c, 0x40}, ++ {0xd0, 0x02}, ++ {0xd1, 0x01}, ++ {0xd2, 0x20}, ++ {0xd3, 0x04}, ++ {0xd4, 0x2a}, ++ {0x50, 0x00}, ++ {0x51, 0x2c}, ++ {0x52, 0x29}, ++ {0x53, 0x00}, ++ {0x55, 0x44}, ++ {0x58, 0x29}, ++ {0x5a, 0x00}, ++ {0x5b, 0x00}, ++ {0x5d, 0x00}, ++ {0x64, 0x2f}, ++ {0x66, 0x62}, ++ {0x68, 0x5b}, ++ {0x75, 0x46}, ++ {0x76, 0xf0}, ++ {0x77, 0x4f}, ++ {0x78, 0xef}, ++ {0x72, 0xcf}, ++ {0x73, 0x36}, ++ {0x7d, 0x0d}, ++ {0x7e, 0x0d}, ++ {0x8a, 0x77}, ++ {0x8b, 0x77}, ++ {0xfd, 0x01}, ++ {0xb1, 0x82}, ++ {0xb3, 0x0b}, ++ {0xb4, 0x14}, ++ {0x9d, 0x40}, ++ {0xa1, 0x05}, ++ {0x94, 0x44}, ++ {0x95, 0x33}, ++ {0x96, 0x1f}, ++ {0x98, 0x45}, ++ {0x9c, 0x10}, ++ {0xb5, 0x70}, ++ {0xa0, 0x00}, ++ {0x25, 0xe0}, ++ {0x20, 0x7b}, ++ {0x8f, 0x88}, ++ {0x91, 0x40}, ++ {0xfd, 0x01}, ++ {0xfd, 0x02}, ++ {0x5e, 0x03}, ++ {0xfd, 0x02}, ++ {0x60, 0xf0}, ++ {0xa1, 0x04}, ++ {0xa3, 0x40}, ++ {0xa5, 0x02}, ++ {0xa7, 0xc4}, ++ {0xfd, 0x01}, ++ {0x86, 0x77}, ++ {0x89, 0x77}, ++ {0x87, 0x74}, ++ {0x88, 0x74}, ++ {0xfc, 0xe0}, ++ {0xfe, 0xe0}, ++ {0xf0, 0x40}, ++ {0xf1, 0x40}, ++ {0xf2, 0x40}, ++ {0xf3, 0x40}, ++ {0xfd, 0x02}, ++ {0x36, 0x08}, ++ {0xa0, 0x00}, ++ {0xa1, 0x08}, ++ {0xa2, 0x04}, ++ {0xa3, 0x38}, ++ {0xa4, 0x00}, ++ {0xa5, 0x04}, ++ {0xa6, 0x03}, ++ {0xa7, 0xc0}, ++ {0xfd, 0x03}, ++ {0xc0, 0x01},//OTP transf ++ {0xfd, 0x04}, ++ {0x22, 0x14}, ++ {0x23, 0x14}, ++ {0xfd, 0x01}, ++ {0x06, 0xe0}, ++ {0x01, 0x01}, ++ {0xfd, 0x00}, ++ {0x1b, 0x00}, ++ {0xfd, 0x01}, ++ {0x0d, 0x10}, ++ {0x0e, 0x05}, ++ {0x0f, 0x2b}, ++ {0x01, 0x01}, ++ ++ {OV2735B_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++#if 0 ++ ++static const struct regval_list ov2735b_wb_auto_regs[] = { ++ {OV2735B_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ov2735b_wb_incandescence_regs[] = { ++ {OV2735B_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ov2735b_wb_daylight_regs[] = { ++ {OV2735B_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ov2735b_wb_fluorescent_regs[] = { ++ {OV2735B_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ov2735b_wb_cloud_regs[] = { ++ {OV2735B_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct mode_list ov2735b_balance[] = { ++ {0, ov2735b_wb_auto_regs}, {1, ar0144_wb_incandescence_regs}, ++ {2, ov2735b_wb_daylight_regs}, {3, ar0144_wb_fluorescent_regs}, ++ {4, ov2735b_wb_cloud_regs}, ++}; ++ ++ ++static const struct regval_list ov2735b_effect_normal_regs[] = { ++ {OV2735B_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ov2735b_effect_grayscale_regs[] = { ++ {OV2735B_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ov2735b_effect_sepia_regs[] = { ++ {OV2735B_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ov2735b_effect_colorinv_regs[] = { ++ {OV2735B_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct regval_list ov2735b_effect_sepiabluel_regs[] = { ++ {OV2735B_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static const struct mode_list ov2735b_effect[] = { ++ {0, ov2735b_effect_normal_regs}, {1, ar0144_effect_grayscale_regs}, ++ {2, ov2735b_effect_sepia_regs}, {3, ar0144_effect_colorinv_regs}, ++ {4, ov2735b_effect_sepiabluel_regs}, ++}; ++ ++#endif ++ ++static struct ov2735b_win_size ov2735b_supported_win_sizes[] = { ++ { ++ .name = "1080P", ++ .width = 1920, ++ .height = 1080, ++ .regs = ov2735b_1080p_regs, ++ //.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ }, ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(ov2735b_supported_win_sizes)) ++ ++/* ++ * General functions ++ */ ++ ++static struct ov2735b_priv *to_ov2735b(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov2735b_priv, ++ subdev); ++} ++ ++static int ov2735b_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while (vals->reg_num != OV2735B_REG_END) { ++ if (vals->reg_num == OV2735B_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov2735b_write_reg(client, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++#if 0 ++static int ov2735b_mask_set(struct i2c_client *client, ++ u16 reg, u16 mask, u16 set) ++{ ++ int ret = 0; ++ unsigned char value[2] = {0}; ++ ret = ov2735b_read_reg(client, reg, value); ++ if (ret < 0) ++ return ret; ++ ++ val &= ~mask; ++ val |= set & mask; ++ ++ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); ++ ++ return ov2735b_write_reg(client, reg, val); ++} ++#endif ++ ++/* ++ * soc_camera_ops functions ++ */ ++ ++ ++/*hw ops*/ ++static int ov2735b_hw_power(struct i2c_client *client, int on) ++{ ++ struct ov2735b_priv *priv = to_ov2735b(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int ov2735b_reset(struct i2c_client *client) ++{ ++ struct ov2735b_priv *priv = to_ov2735b(client); ++ ++ if(priv->resetb_gpio) { ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ msleep(10); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ msleep(10); ++ } ++ return 0; ++} ++ ++ ++ ++/*ctrl_ops*/ ++static int ov2735b_g_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov2735b_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2735b_priv *priv = to_ov2735b(client); ++ ++ switch (ctrl->id) { ++ ++ case V4L2_CID_VFLIP: ++ ctrl->val = priv->flag_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->val = priv->flag_hflip; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++ ++static int ov2735b_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ int ret = 0; ++#if 0 ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov2735b_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2735b_priv *priv = to_ov2735b(client); ++ int i = 0; ++ u16 value; ++ ++ int balance_count = ARRAY_SIZE(ov2735b_balance); ++ int effect_count = ARRAY_SIZE(ov2735b_effect); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VFLIP: ++ value = ctrl->val ? ov2735b_FLIP_VAL : 0x00; ++ priv->flag_vflip = ctrl->val ? 1 : 0; ++// ret = ov2735b_mask_set(client, 0x301D, ar0144_FLIP_MASK, value); ++ break; ++ ++ case V4L2_CID_HFLIP: ++ value = ctrl->val ? ov2735b_FLIP_VAL : 0x00; ++ priv->flag_hflip = ctrl->val ? 1 : 0; ++// ret = ov2735b_mask_set(client, 0x301D, ar0144_FLIP_MASK, value); ++ break; ++ ++ default: ++ dev_err(&client->dev, "no V4L2 CID: 0x%x ", ctrl->id); ++ return -EINVAL; ++ } ++ ++#endif ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ov2735b_ctrl_ops = { ++ .s_ctrl = ov2735b_s_ctrl, ++ .g_volatile_ctrl = ov2735b_g_ctrl, ++}; ++ ++/*core_ops*/ ++static int ov2735b_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2735b_priv *priv = to_ov2735b(client); ++ ++ if(priv->sd_pdata) { ++ if(on) ++ return regulator_bulk_enable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ else ++ return regulator_bulk_disable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ } else if(priv->power){ ++ return priv->power(client, on); ++ } else { ++ dev_err(&client->dev, "ov2735b_s_power failde"); ++ return -EINVAL; ++ } ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov2735b_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg > 0xff) ++ return -EINVAL; ++ ++ ret = ov2735b_read_reg(client, reg->reg, reg->val); ++ ++ return 0; ++} ++ ++static int ov2735b_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg > 0xff || ++ reg->val > 0xff) ++ return -EINVAL; ++ ++ return ov2735b_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++static struct regval_list ov2735b_stream_on[] = { ++ {0xfd, 0x00}, ++ {0x36, 0x00}, ++ {0x37, 0x00},//fake stream on ++ ++ {OV2735B_REG_END, 0x00}, ++}; ++ ++static struct regval_list ov2735b_stream_off[] = { ++ {0xfd, 0x00}, ++ {0x36, 0x01}, ++ {0x37, 0x01},//fake stream off ++ ++ {OV2735B_REG_END, 0x00}, ++}; ++ ++static int ov2735b_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!enable ) { ++ dev_info(&client->dev, "stream down\n"); ++ ov2735b_write_array(client, ov2735b_stream_off); ++ return 0; ++ } ++ ++ dev_info(&client->dev, "stream on\n"); ++ ov2735b_write_array(client, ov2735b_stream_on); ++ ++ return 0; ++} ++ ++/* Select the nearest higher resolution for capture */ ++static const struct ov2735b_win_size *ov2735b_select_win(u32 *code, u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(ov2735b_supported_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(ov2735b_supported_win_sizes); i++) { ++ if ((*width >= ov2735b_supported_win_sizes[i].width) && ++ (*height >= ov2735b_supported_win_sizes[i].height) && ++ (*code == ov2735b_supported_win_sizes[i].mbus_code)) { ++ *width = ov2735b_supported_win_sizes[i].width; ++ *height = ov2735b_supported_win_sizes[i].height; ++ return &ov2735b_supported_win_sizes[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int ov2735b_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2735b_priv *priv = to_ov2735b(client); ++ ++ if(!priv->win) ++ return -EINVAL; ++ ++ sel->r.top = 0; ++ sel->r.left = 0; ++ sel->r.width = priv->win->width; ++ sel->r.height = priv->win->height; ++ ++ return 0; ++} ++ ++static int ov2735b_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2735b_priv *priv = to_ov2735b(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ if(priv->win){ ++ mf->width = priv->win->width; ++ mf->height = priv->win->height; ++ } else { ++ mf->width = ov2735b_DEFAULT_WIDTH; ++ mf->height = ov2735b_DEFAULT_HEIGHT; ++ } ++ mf->code = priv->cfmt_code; ++ ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov2735b_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code) ++{ ++ struct ov2735b_priv *priv = to_ov2735b(client); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* reset hardware */ ++ ov2735b_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++#if 0 ++ ret = ov2735b_write_array(client, ov2735b_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = ov2735b_write_array(client, ar0144_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = ov2735b_write_array(client, ar0144_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++#endif ++ /* set size win */ ++ dev_dbg(&client->dev, "priv->win.width = %d\n", priv->win->width); ++ dev_dbg(&client->dev, "priv->win.height = %d\n", priv->win->height); ++ ++ ret = ov2735b_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ ov2735b_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int ov2735b_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov2735b_priv *priv = to_ov2735b(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ priv->win = ov2735b_select_win(&mf->code ,&mf->width, &mf->height); ++ if(!priv->win) ++ return -EINVAL; ++ ++ mf->field = V4L2_FIELD_NONE; ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ ov2735b_set_params(client, &mf->width, ++ &mf->height, mf->code); ++ if(cfg) ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int ov2735b_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= ARRAY_SIZE(ov2735b_supported_win_sizes)) ++ return -EINVAL; ++ ++ code->code = ov2735b_supported_win_sizes[code->index].mbus_code; ++ return 0; ++} ++ ++static int ov2735b_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int i, j; ++ int num_valid = -1; ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++ fse->code = ov2735b_supported_win_sizes[index].mbus_code; ++ fse->min_width = ov2735b_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = ov2735b_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++ ++} ++ ++static int ov2735b_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++ /*int dts*/ ++ return 0; ++} ++ ++static struct v4l2_subdev_core_ops ov2735b_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov2735b_g_register, ++ .s_register = ov2735b_s_register, ++#endif ++ .s_power = ov2735b_s_power, ++}; ++ ++static struct v4l2_subdev_video_ops ov2735b_subdev_video_ops = { ++ .s_stream = ov2735b_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov2735b_subdev_pad_ops = { ++ .enum_mbus_code = ov2735b_enum_mbus_code, ++ .enum_frame_size = ov2735b_enum_frame_size, ++ .get_fmt = ov2735b_get_fmt, ++ .set_fmt = ov2735b_set_fmt, ++ .get_mbus_config = ov2735b_g_mbus_config, ++ .get_selection = ov2735b_get_selection, ++}; ++ ++static struct v4l2_subdev_ops ov2735b_subdev_ops = { ++ .core = &ov2735b_subdev_core_ops, ++ .video = &ov2735b_subdev_video_ops, ++ .pad = &ov2735b_subdev_pad_ops, ++}; ++ ++ ++static int ov2735b_detect(struct i2c_client *client, unsigned int *ident) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ unsigned char v; ++ int ret; ++ ++ ov2735b_s_power(sd, 1); ++ ret = ov2735b_read_reg(client, 0x02, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV2735B_CHIP_ID_H) ++ return -ENODEV; ++ ++ ret = ov2735b_read_reg(client, 0x03, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV2735B_CHIP_ID_L) ++ return -ENODEV; ++ ++ ret = ov2735b_read_reg(client, 0x04, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != 0x05 && v != 0x06 && v != 0x07) ++ return -ENODEV; ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++// ov2735b_s_power(sd, 0); ++ return 0; ++ ++} ++ ++ ++static int ov2735b_probe_dt(struct i2c_client *client, ++ struct ov2735b_priv *priv) ++{ ++ struct v4l2_subdev_platform_data *sd_pdata = priv->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies > 0) { ++ ++ sd_pdata = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev_platform_data), GFP_KERNEL); ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ devm_kfree(&client->dev,sd_pdata); ++ return -ENOMEM; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ devm_regulator_bulk_get(&client->dev, sd_pdata->num_regulators, sd_pdata->regulators); ++ ++ //if(!client->dev.platform_data) /*TODO*/ ++ // client->dev.platform_data = &priv->sd_pdata; ++ } else { ++ ++ ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power vcc-en GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Request the power resetb GPIO asserted */ ++ priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", ++ GPIOD_OUT_LOW); ++ if (!priv->resetb_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->resetb_gpio)) ++ return PTR_ERR(priv->resetb_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->power = ov2735b_hw_power; ++ // priv->reset = ov2735b_hw_reset; /*TODO*/ ++ } ++ return 0; ++} ++ ++static int ov2735b_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov2735b_priv *priv; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "ov2735b: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct ov2735b_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++ ++ /*mclk gate close*/ ++// *(volatile unsigned int *)0xb0000024 &= ~(1 << 5); ++ ++ ret = ov2735b_probe_dt(client, priv); ++ if (ret) ++ goto err_probe_dt; ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &ov2735b_subdev_ops); ++ ++ /* add handler */ ++ v4l2_ctrl_handler_init(&priv->hdl, 2); ++ ++ v4l2_ctrl_new_std(&priv->hdl, &ov2735b_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov2735b_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ ++ priv->subdev.ctrl_handler = &priv->hdl; ++ if (priv->hdl.error) { ++ ret = priv->hdl.error; ++ goto err_hdl; ++ } ++ ++#if 0 ++ ret = ov2735b_detect(client, NULL); ++ if(ret < 0){ ++ v4l_err(client,"chip found @ 0x%x (%s) is not an ov2735b chip.\n", ++ client->addr << 1, client->adapter->name); ++ goto err_detect; ++ } ++#endif ++ ++ ret = v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_async_register_subdev; ++ ++ dev_info(&adapter->dev, "ov2735b Probed\n"); ++ ++ return 0; ++ ++err_async_register_subdev: ++err_detect: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_hdl: ++ v4l2_device_unregister_subdev(&priv->subdev); ++err_probe_dt: ++ v4l2_clk_put(priv->clk); ++ devm_kfree(&client->dev, priv); ++ return ret; ++} ++ ++static int ov2735b_remove(struct i2c_client *client) ++{ ++ struct ov2735b_priv *priv = to_ov2735b(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ devm_kfree(&client->dev, priv); ++ return 0; ++} ++ ++static const struct i2c_device_id ov2735b_id[] = { ++ { "ov2735b", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov2735b_id); ++static const struct of_device_id ov2735b_of_match[] = { ++ {.compatible = "ovit,ov2735b", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2735b_of_match); ++static struct i2c_driver ov2735b_i2c_driver = { ++ .driver = { ++ .name = "ov2735b", ++ .of_match_table = of_match_ptr(ov2735b_of_match), ++ }, ++ .probe = ov2735b_probe, ++ .remove = ov2735b_remove, ++ .id_table = ov2735b_id, ++}; ++module_i2c_driver(ov2735b_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for onsemi ov2735b sensor"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/ov4689.c b/module_drivers/drivers/media/i2c/ingenic-cim/ov4689.c +new file mode 100644 +index 000000000..b59e4a176 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/ov4689.c +@@ -0,0 +1,3115 @@ ++/* ++ * A V4L2 driver for OmniVision OV4689 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define OV4689_CHIP_ID_H (0x46) ++#define OV4689_CHIP_ID_L (0x88) ++#define OV4689_REG_END 0xffff ++#define OV4689_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ov4689_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ /* struct sensor_info sensor_info; */ ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ov4689_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov4689_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ov4689_win_size *win; ++ ++ struct gpio_desc *reset; ++ struct gpio_desc *ircutp; ++ struct gpio_desc *ircutn; ++ ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut ov4689_again_lut[] = { ++ ++ {0x80, 0}, ++ {0x88, 5731}, ++ {0x90, 11136}, ++ {0x98, 16248}, ++ {0xa0, 21097}, ++ {0xa8, 25710}, ++ {0xb0, 30109}, ++ {0xb8, 34312}, ++ {0xc0, 38336}, ++ {0xc8, 42195}, ++ {0xd0, 45904}, ++ {0xd8, 49472}, ++ {0xe0, 52910}, ++ {0xe8, 56228}, ++ {0xf0, 59433}, ++ {0xf8, 62534}, ++ {0x178, 65536}, ++ {0x17c, 68445}, ++ {0x180, 71267}, ++ {0x184, 74008}, ++ {0x188, 76672}, ++ {0x18c, 79262}, ++ {0x190, 81784}, ++ {0x194, 84240}, ++ {0x198, 86633}, ++ {0x19c, 88968}, ++ {0x1a0, 91246}, ++ {0x1a4, 93471}, ++ {0x1a8, 95645}, ++ {0x1ac, 97770}, ++ {0x1b0, 99848}, ++ {0x1b4, 101881}, ++ {0x1b8, 103872}, ++ {0x1bc, 105821}, ++ {0x1c0, 107731}, ++ {0x1c4, 109604}, ++ {0x1c8, 111440}, ++ {0x1cc, 113241}, ++ {0x1d0, 115008}, ++ {0x1d4, 116743}, ++ {0x1d8, 118446}, ++ {0x1dc, 120120}, ++ {0x1e0, 121764}, ++ {0x1e4, 123380}, ++ {0x1e8, 124969}, ++ {0x1ec, 126532}, ++ {0x1f0, 128070}, ++ {0x1f4, 129583}, ++ {0x374, 131072}, ++ {0x376, 132537}, ++ {0x378, 133981}, ++ {0x37a, 135403}, ++ {0x37c, 136803}, ++ {0x37e, 138184}, ++ {0x380, 139544}, ++ {0x382, 140885}, ++ {0x384, 142208}, ++ {0x386, 143512}, ++ {0x388, 144798}, ++ {0x38a, 146067}, ++ {0x38c, 147320}, ++ {0x38e, 148556}, ++ {0x390, 149776}, ++ {0x392, 150980}, ++ {0x394, 152169}, ++ {0x396, 153344}, ++ {0x398, 154504}, ++ {0x39a, 155650}, ++ {0x39c, 156782}, ++ {0x39e, 157901}, ++ {0x3a0, 159007}, ++ {0x3a2, 160100}, ++ {0x3a4, 161181}, ++ {0x3a6, 162249}, ++ {0x3a8, 163306}, ++ {0x3aa, 164350}, ++ {0x3ac, 165384}, ++ {0x3ae, 166406}, ++ {0x3b0, 167417}, ++ {0x3b2, 168418}, ++ {0x3b4, 169408}, ++ {0x3b6, 170387}, ++ {0x3b8, 171357}, ++ {0x3ba, 172317}, ++ {0x3bc, 173267}, ++ {0x3be, 174208}, ++ {0x3c0, 175140}, ++ {0x3c2, 176062}, ++ {0x3c4, 176976}, ++ {0x3c6, 177880}, ++ {0x3c8, 178777}, ++ {0x3ca, 179664}, ++ {0x3cc, 180544}, ++ {0x3ce, 181415}, ++ {0x3d0, 182279}, ++ {0x3d2, 183134}, ++ {0x3d4, 183982}, ++ {0x3d6, 184823}, ++ {0x3d8, 185656}, ++ {0x3da, 186482}, ++ {0x3dc, 187300}, ++ {0x3de, 188112}, ++ {0x3e0, 188916}, ++ {0x3e2, 189714}, ++ {0x3e4, 190505}, ++ {0x3e6, 191290}, ++ {0x3e8, 192068}, ++ {0x3ea, 192840}, ++ {0x3ec, 193606}, ++ {0x3ee, 194365}, ++ {0x3f0, 195119}, ++ {0x3f2, 195866}, ++ {0x778, 196608}, ++ {0x779, 197343}, ++ {0x77a, 198073}, ++ {0x77b, 198798}, ++ {0x77c, 199517}, ++ {0x77d, 200230}, ++ {0x77e, 200939}, ++ {0x77f, 201642}, ++ {0x780, 202339}, ++ {0x781, 203032}, ++ {0x782, 203720}, ++ {0x783, 204402}, ++ {0x784, 205080}, ++ {0x785, 205753}, ++ {0x786, 206421}, ++ {0x787, 207085}, ++ {0x788, 207744}, ++ {0x789, 208398}, ++ {0x78a, 209048}, ++ {0x78b, 209693}, ++ {0x78c, 210334}, ++ {0x78d, 210971}, ++ {0x78e, 211603}, ++ {0x78f, 212232}, ++ {0x790, 212856}, ++ {0x791, 213476}, ++ {0x792, 214092}, ++ {0x793, 214704}, ++ {0x794, 215312}, ++ {0x795, 215916}, ++ {0x796, 216516}, ++ {0x797, 217113}, ++ {0x798, 217705}, ++ {0x799, 218294}, ++ {0x79a, 218880}, ++ {0x79b, 219462}, ++ {0x79c, 220040}, ++ {0x79d, 220615}, ++ {0x79e, 221186}, ++ {0x79f, 221754}, ++ {0x7a0, 222318}, ++ {0x7a1, 222880}, ++ {0x7a2, 223437}, ++ {0x7a3, 223992}, ++ {0x7a4, 224543}, ++ {0x7a5, 225091}, ++ {0x7a6, 225636}, ++ {0x7a7, 226178}, ++ {0x7a8, 226717}, ++ {0x7a9, 227253}, ++ {0x7aa, 227785}, ++ {0x7ab, 228315}, ++ {0x7ac, 228842}, ++ {0x7ad, 229365}, ++ {0x7ae, 229886}, ++ {0x7af, 230404}, ++ {0x7b0, 230920}, ++ {0x7b1, 231432}, ++ {0x7b2, 231942}, ++ {0x7b3, 232449}, ++ {0x7b4, 232953}, ++ {0x7b5, 233455}, ++ {0x7b6, 233954}, ++ {0x7b7, 234450}, ++ {0x7b8, 234944}, ++ {0x7b9, 235435}, ++ {0x7ba, 235923}, ++ {0x7bb, 236410}, ++ {0x7bc, 236893}, ++ {0x7bd, 237374}, ++ {0x7be, 237853}, ++ {0x7bf, 238329}, ++ {0x7c0, 238803}, ++ {0x7c1, 239275}, ++ {0x7c2, 239744}, ++ {0x7c3, 240211}, ++ {0x7c4, 240676}, ++ {0x7c5, 241138}, ++ {0x7c6, 241598}, ++ {0x7c7, 242056}, ++ {0x7c8, 242512}, ++ {0x7c9, 242965}, ++ {0x7ca, 243416}, ++ {0x7cb, 243865}, ++ {0x7cc, 244313}, ++ {0x7cd, 244757}, ++ {0x7ce, 245200}, ++ {0x7cf, 245641}, ++ {0x7d0, 246080}, ++ {0x7d1, 246517}, ++ {0x7d2, 246951}, ++ {0x7d3, 247384}, ++ {0x7d4, 247815}, ++ {0x7d5, 248243}, ++ {0x7d6, 248670}, ++ {0x7d7, 249095}, ++ {0x7d8, 249518}, ++ {0x7d9, 249939}, ++ {0x7da, 250359}, ++ {0x7db, 250776}, ++ {0x7dc, 251192}, ++ {0x7dd, 251606}, ++ {0x7de, 252018}, ++ {0x7df, 252428}, ++ {0x7e0, 252836}, ++ {0x7e1, 253243}, ++ {0x7e2, 253648}, ++ {0x7e3, 254051}, ++ {0x7e4, 254452}, ++ {0x7e5, 254852}, ++ {0x7e6, 255250}, ++ {0x7e7, 255647}, ++ {0x7e8, 256041}, ++ {0x7e9, 256435}, ++ {0x7ea, 256826}, ++ {0x7eb, 257216}, ++ {0x7ec, 257604}, ++ {0x7ed, 257991}, ++ {0x7ee, 258376}, ++ {0x7ef, 258760}, ++ {0x7f0, 259142}, ++ {0x7f1, 259522}, ++ {0x7f2, 259901}, ++ {0x7f3, 260279}, ++ {0x7f4, 260655}, ++ {0x7f5, 261029}, ++ {0x7f6, 261402}, ++ {0x7f7, 261773}, ++}; ++ ++static inline struct ov4689_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ov4689_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov4689_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list ov4689_init_regs_1920_1080_120fps_mipi[] = { ++ // @@ 0 35 RES_1920x1080_120fps_1008Mbps ++ // 100 99 1920 1080 ++ //102 3601 2ee0 ++ ++ { 0x0103, 0x01 }, ++ { 0x3638, 0x00 }, ++ { 0x0300, 0x00 }, ++ { 0x0302, 0x2a }, ++ { 0x0303, 0x00 }, ++ { 0x0304, 0x03 }, ++ { 0x030b, 0x00 }, ++ { 0x030d, 0x1e }, ++ { 0x030e, 0x04 }, ++ { 0x030f, 0x01 }, ++ { 0x0312, 0x01 }, ++ { 0x031e, 0x00 }, ++ { 0x3000, 0x20 }, ++ { 0x3002, 0x00 }, ++ { 0x3018, 0x72 }, ++ { 0x3020, 0x93 }, ++ { 0x3021, 0x03 }, ++ { 0x3022, 0x01 }, ++ { 0x3031, 0x0a }, ++ { 0x303f, 0x0c }, ++ { 0x3305, 0xf1 }, ++ { 0x3307, 0x04 }, ++ { 0x3309, 0x29 }, ++ { 0x3500, 0x00 }, ++ { 0x3501, 0x4c }, ++ { 0x3502, 0x00 }, ++ { 0x3503, 0x04 }, ++ { 0x3504, 0x00 }, ++ { 0x3505, 0x00 }, ++ { 0x3506, 0x00 }, ++ { 0x3507, 0x00 }, ++ { 0x3508, 0x00 }, ++ { 0x3509, 0x80 }, ++ { 0x350a, 0x00 }, ++ { 0x350b, 0x00 }, ++ { 0x350c, 0x00 }, ++ { 0x350d, 0x00 }, ++ { 0x350e, 0x00 }, ++ { 0x350f, 0x80 }, ++ { 0x3510, 0x00 }, ++ { 0x3511, 0x00 }, ++ { 0x3512, 0x00 }, ++ { 0x3513, 0x00 }, ++ { 0x3514, 0x00 }, ++ { 0x3515, 0x80 }, ++ { 0x3516, 0x00 }, ++ { 0x3517, 0x00 }, ++ { 0x3518, 0x00 }, ++ { 0x3519, 0x00 }, ++ { 0x351a, 0x00 }, ++ { 0x351b, 0x80 }, ++ { 0x351c, 0x00 }, ++ { 0x351d, 0x00 }, ++ { 0x351e, 0x00 }, ++ { 0x351f, 0x00 }, ++ { 0x3520, 0x00 }, ++ { 0x3521, 0x80 }, ++ { 0x3522, 0x08 }, ++ { 0x3524, 0x08 }, ++ { 0x3526, 0x08 }, ++ { 0x3528, 0x08 }, ++ { 0x352a, 0x08 }, ++ { 0x3602, 0x00 }, ++ { 0x3603, 0x40 }, ++ { 0x3604, 0x02 }, ++ { 0x3605, 0x00 }, ++ { 0x3606, 0x00 }, ++ { 0x3607, 0x00 }, ++ { 0x3609, 0x12 }, ++ { 0x360a, 0x40 }, ++ { 0x360c, 0x08 }, ++ { 0x360f, 0xe5 }, ++ { 0x3608, 0x8f }, ++ { 0x3611, 0x00 }, ++ { 0x3613, 0xf7 }, ++ { 0x3616, 0x58 }, ++ { 0x3619, 0x99 }, ++ { 0x361b, 0x60 }, ++ { 0x361c, 0x7a }, ++ { 0x361e, 0x79 }, ++ { 0x361f, 0x02 }, ++ { 0x3632, 0x00 }, ++ { 0x3633, 0x10 }, ++ { 0x3634, 0x10 }, ++ { 0x3635, 0x10 }, ++ { 0x3636, 0x15 }, ++ { 0x3646, 0x86 }, ++ { 0x364a, 0x0b }, ++ { 0x3700, 0x17 }, ++ { 0x3701, 0x22 }, ++ { 0x3703, 0x10 }, ++ { 0x370a, 0x37 }, ++ { 0x3705, 0x00 }, ++ { 0x3706, 0x63 }, ++ { 0x3709, 0x3c }, ++ { 0x370b, 0x01 }, ++ { 0x370c, 0x30 }, ++ { 0x3710, 0x24 }, ++ { 0x3711, 0x0c }, ++ { 0x3716, 0x00 }, ++ { 0x3720, 0x28 }, ++ { 0x3729, 0x7b }, ++ { 0x372a, 0x84 }, ++ { 0x372b, 0xbd }, ++ { 0x372c, 0xbc }, ++ { 0x372e, 0x52 }, ++ { 0x373c, 0x0e }, ++ { 0x373e, 0x33 }, ++ { 0x3743, 0x10 }, ++ { 0x3744, 0x88 }, ++ { 0x3745, 0xc0 }, ++ { 0x374a, 0x43 }, ++ { 0x374c, 0x00 }, ++ { 0x374e, 0x23 }, ++ { 0x3751, 0x7b }, ++ { 0x3752, 0x84 }, ++ { 0x3753, 0xbd }, ++ { 0x3754, 0xbc }, ++ { 0x3756, 0x52 }, ++ { 0x375c, 0x00 }, ++ { 0x3760, 0x00 }, ++ { 0x3761, 0x00 }, ++ { 0x3762, 0x00 }, ++ { 0x3763, 0x00 }, ++ { 0x3764, 0x00 }, ++ { 0x3767, 0x04 }, ++ { 0x3768, 0x04 }, ++ { 0x3769, 0x08 }, ++ { 0x376a, 0x08 }, ++ { 0x376b, 0x20 }, ++ { 0x376c, 0x00 }, ++ { 0x376d, 0x00 }, ++ { 0x376e, 0x00 }, ++ { 0x3773, 0x00 }, ++ { 0x3774, 0x51 }, ++ { 0x3776, 0xbd }, ++ { 0x3777, 0xbd }, ++ { 0x3781, 0x18 }, ++ { 0x3783, 0x25 }, ++ { 0x3798, 0x1b }, ++ { 0x3800, 0x01 }, ++ { 0x3801, 0x88 }, ++ { 0x3802, 0x00 }, ++ { 0x3803, 0xe0 }, ++ { 0x3804, 0x09 }, ++ { 0x3805, 0x17 }, ++ { 0x3806, 0x05 }, ++ { 0x3807, 0x1f }, ++ { 0x3808, 0x07 }, ++ { 0x3809, 0x80 }, ++ { 0x380a, 0x04 }, ++ { 0x380b, 0x38 }, ++ { 0x380c, 0x03 }, ++ { 0x380d, 0x5c }, ++ { 0x380e, 0x04 }, ++ { 0x380f, 0x8A }, ++ { 0x3810, 0x00 }, ++ { 0x3811, 0x08 }, ++ { 0x3812, 0x00 }, ++ { 0x3813, 0x04 }, ++ { 0x3814, 0x01 }, ++ { 0x3815, 0x01 }, ++ { 0x3819, 0x01 }, ++ { 0x3820, 0x00 }, ++ { 0x3821, 0x06 }, ++ { 0x3829, 0x00 }, ++ { 0x382a, 0x01 }, ++ { 0x382b, 0x01 }, ++ { 0x382d, 0x7f }, ++ { 0x3830, 0x04 }, ++ { 0x3836, 0x01 }, ++ { 0x3837, 0x00 }, ++ { 0x3841, 0x02 }, ++ { 0x3846, 0x08 }, ++ { 0x3847, 0x07 }, ++ { 0x3d85, 0x36 }, ++ { 0x3d8c, 0x71 }, ++ { 0x3d8d, 0xcb }, ++ { 0x3f0a, 0x00 }, ++ { 0x4000, 0xf1 }, ++ { 0x4001, 0x40 }, ++ { 0x4002, 0x04 }, ++ { 0x4003, 0x14 }, ++ { 0x400e, 0x00 }, ++ { 0x4011, 0x00 }, ++ { 0x401a, 0x00 }, ++ { 0x401b, 0x00 }, ++ { 0x401c, 0x00 }, ++ { 0x401d, 0x00 }, ++ { 0x401f, 0x00 }, ++ { 0x4020, 0x00 }, ++ { 0x4021, 0x10 }, ++ { 0x4022, 0x06 }, ++ { 0x4023, 0x13 }, ++ { 0x4024, 0x07 }, ++ { 0x4025, 0x40 }, ++ { 0x4026, 0x07 }, ++ { 0x4027, 0x50 }, ++ { 0x4028, 0x00 }, ++ { 0x4029, 0x02 }, ++ { 0x402a, 0x06 }, ++ { 0x402b, 0x04 }, ++ { 0x402c, 0x02 }, ++ { 0x402d, 0x02 }, ++ { 0x402e, 0x0e }, ++ { 0x402f, 0x04 }, ++ { 0x4302, 0xff }, ++ { 0x4303, 0xff }, ++ { 0x4304, 0x00 }, ++ { 0x4305, 0x00 }, ++ { 0x4306, 0x00 }, ++ { 0x4308, 0x02 }, ++ { 0x4500, 0x6c }, ++ { 0x4501, 0xc4 }, ++ { 0x4502, 0x40 }, ++ { 0x4503, 0x01 }, ++ { 0x4601, 0x77 }, ++ { 0x4800, 0x04 }, ++ { 0x4813, 0x08 }, ++ { 0x481f, 0x40 }, ++ { 0x4829, 0x78 }, ++ { 0x4837, 0x10 }, ++ { 0x4b00, 0x2a }, ++ { 0x4b0d, 0x00 }, ++ { 0x4d00, 0x04 }, ++ { 0x4d01, 0x42 }, ++ { 0x4d02, 0xd1 }, ++ { 0x4d03, 0x93 }, ++ { 0x4d04, 0xf5 }, ++ { 0x4d05, 0xc1 }, ++ { 0x5000, 0xf3 }, ++ { 0x5001, 0x11 }, ++ { 0x5004, 0x00 }, ++ { 0x500a, 0x00 }, ++ { 0x500b, 0x00 }, ++ { 0x5032, 0x00 }, ++ { 0x5040, 0x00 }, ++ { 0x5050, 0x0c }, ++ { 0x5500, 0x00 }, ++ { 0x5501, 0x10 }, ++ { 0x5502, 0x01 }, ++ { 0x5503, 0x0f }, ++ { 0x8000, 0x00 }, ++ { 0x8001, 0x00 }, ++ { 0x8002, 0x00 }, ++ { 0x8003, 0x00 }, ++ { 0x8004, 0x00 }, ++ { 0x8005, 0x00 }, ++ { 0x8006, 0x00 }, ++ { 0x8007, 0x00 }, ++ { 0x8008, 0x00 }, ++ { 0x3638, 0x00 }, ++ { 0x0100, 0x00 }, ++ { 0x5040, 0x80 }, ++ {OV4689_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov4689_init_regs_1920_1080_30fps_mipi[] = { ++#if 0 //1080p@30fps 1 lane ok ++ /* @@ 0 35 RES_1920x1080_30fps_816Mbps 1Lane */ ++ /* ;SCLK = 80MHz MIPI CLK = 816Mbps/lane Mipi PCLK = 102MHz */ ++ /* ;HTS = 2294 VTS = 1162 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x22}, ++ {0x0303, 0x00}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x02}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++ {0x3018, 0x02}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x88}, ++ {0x3802, 0x00}, ++ {0x3803, 0xe0}, ++ {0x3804, 0x09}, ++ {0x3805, 0x17}, ++ {0x3806, 0x05}, ++ {0x3807, 0x1f}, ++ {0x3808, 0x07}, ++ {0x3809, 0x80}, ++ {0x380a, 0x04}, ++ {0x380b, 0x38}, ++ {0x380c, 0x08}, ++ {0x380d, 0xf6}, ++ {0x380e, 0x04}, ++ {0x380f, 0x8A}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x13}, ++ {0x4024, 0x07}, ++ {0x4025, 0x40}, ++ {0x4026, 0x07}, ++ {0x4027, 0x50}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x77}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x2d}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++#endif ++#if 1 ++ //1080p@30fps 2 or 4 lane ++ /* @@ 0 35 RES_1920x1080_30fps_816Mbps 2Lane */ ++ /* ;SCLK = 80MHz MIPI CLK = 816Mbps/lane Mipi PCLK = 102MHz */ ++ /* ;HTS = 2294 VTS = 1162 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x23}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x02}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++// {0x3018, 0x72}, //4lan ++ {0x3018, 0x32}, //2lan ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x88}, ++ {0x3802, 0x00}, ++ {0x3803, 0xe0}, ++ {0x3804, 0x09}, ++ {0x3805, 0x17}, ++ {0x3806, 0x05}, ++ {0x3807, 0x1f}, ++ {0x3808, 0x07}, ++ {0x3809, 0x80}, ++ {0x380a, 0x04}, ++ {0x380b, 0x38}, ++ {0x380c, 0x08}, ++ {0x380d, 0xf6}, ++ {0x380e, 0x04}, ++ {0x380f, 0x8A}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x13}, ++ {0x4024, 0x07}, ++ {0x4025, 0x40}, ++ {0x4026, 0x07}, ++ {0x4027, 0x50}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x77}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x14}, //for zebra/panda ++ /* {0x4837, 0x80}, //for halley5 */ ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++#endif ++#if 0 ++ /*support by ov , dosen't word in zebra & halley5*/ ++// @@ 0 35 RES_1920x1080_30fps_1008Mbps 4lane ++//100 99 1920 1080 ++//102 3601 2ee0 ++ { 0x0103, 0x01 }, ++ { 0x3638, 0x00 }, ++ { 0x0300, 0x00 }, ++ { 0x0302, 0x2a }, ++ { 0x0303, 0x00 }, ++ { 0x0304, 0x03 }, ++ { 0x030b, 0x00 }, ++ { 0x030d, 0x1e }, ++ { 0x030e, 0x04 }, ++ { 0x030f, 0x01 }, ++ { 0x0312, 0x01 }, ++ { 0x031e, 0x00 }, ++ { 0x3000, 0x20 }, ++ { 0x3002, 0x00 }, ++ { 0x3018, 0x72 }, ++// { 0x3018, 0x32 }, ++ { 0x3020, 0x93 }, ++ { 0x3021, 0x03 }, ++ { 0x3022, 0x01 }, ++ { 0x3031, 0x0a }, ++ { 0x303f, 0x0c }, ++ { 0x3305, 0xf1 }, ++ { 0x3307, 0x04 }, ++ { 0x3309, 0x29 }, ++ { 0x3500, 0x00 }, ++ { 0x3501, 0x4c }, ++ { 0x3502, 0x00 }, ++ { 0x3503, 0x04 }, ++ { 0x3504, 0x00 }, ++ { 0x3505, 0x00 }, ++ { 0x3506, 0x00 }, ++ { 0x3507, 0x00 }, ++ { 0x3508, 0x00 }, ++ { 0x3509, 0x80 }, ++ { 0x350a, 0x00 }, ++ { 0x350b, 0x00 }, ++ { 0x350c, 0x00 }, ++ { 0x350d, 0x00 }, ++ { 0x350e, 0x00 }, ++ { 0x350f, 0x80 }, ++ { 0x3510, 0x00 }, ++ { 0x3511, 0x00 }, ++ { 0x3512, 0x00 }, ++ { 0x3513, 0x00 }, ++ { 0x3514, 0x00 }, ++ { 0x3515, 0x80 }, ++ { 0x3516, 0x00 }, ++ { 0x3517, 0x00 }, ++ { 0x3518, 0x00 }, ++ { 0x3519, 0x00 }, ++ { 0x351a, 0x00 }, ++ { 0x351b, 0x80 }, ++ { 0x351c, 0x00 }, ++ { 0x351d, 0x00 }, ++ { 0x351e, 0x00 }, ++ { 0x351f, 0x00 }, ++ { 0x3520, 0x00 }, ++ { 0x3521, 0x80 }, ++ { 0x3522, 0x08 }, ++ { 0x3524, 0x08 }, ++ { 0x3526, 0x08 }, ++ { 0x3528, 0x08 }, ++ { 0x352a, 0x08 }, ++ { 0x3602, 0x00 }, ++ { 0x3603, 0x40 }, ++ { 0x3604, 0x02 }, ++ { 0x3605, 0x00 }, ++ { 0x3606, 0x00 }, ++ { 0x3607, 0x00 }, ++ { 0x3609, 0x12 }, ++ { 0x360a, 0x40 }, ++ { 0x360c, 0x08 }, ++ { 0x360f, 0xe5 }, ++ { 0x3608, 0x8f }, ++ { 0x3611, 0x00 }, ++ { 0x3613, 0xf7 }, ++ { 0x3616, 0x58 }, ++ { 0x3619, 0x99 }, ++ { 0x361b, 0x60 }, ++ { 0x361c, 0x7a }, ++ { 0x361e, 0x79 }, ++ { 0x361f, 0x02 }, ++ { 0x3632, 0x00 }, ++ { 0x3633, 0x10 }, ++ { 0x3634, 0x10 }, ++ { 0x3635, 0x10 }, ++ { 0x3636, 0x15 }, ++ { 0x3646, 0x86 }, ++ { 0x364a, 0x0b }, ++ { 0x3700, 0x17 }, ++ { 0x3701, 0x22 }, ++ { 0x3703, 0x10 }, ++ { 0x370a, 0x37 }, ++ { 0x3705, 0x00 }, ++ { 0x3706, 0x63 }, ++ { 0x3709, 0x3c }, ++ { 0x370b, 0x01 }, ++ { 0x370c, 0x30 }, ++ { 0x3710, 0x24 }, ++ { 0x3711, 0x0c }, ++ { 0x3716, 0x00 }, ++ { 0x3720, 0x28 }, ++ { 0x3729, 0x7b }, ++ { 0x372a, 0x84 }, ++ { 0x372b, 0xbd }, ++ { 0x372c, 0xbc }, ++ { 0x372e, 0x52 }, ++ { 0x373c, 0x0e }, ++ { 0x373e, 0x33 }, ++ { 0x3743, 0x10 }, ++ { 0x3744, 0x88 }, ++ { 0x3745, 0xc0 }, ++ { 0x374a, 0x43 }, ++ { 0x374c, 0x00 }, ++ { 0x374e, 0x23 }, ++ { 0x3751, 0x7b }, ++ { 0x3752, 0x84 }, ++ { 0x3753, 0xbd }, ++ { 0x3754, 0xbc }, ++ { 0x3756, 0x52 }, ++ { 0x375c, 0x00 }, ++ { 0x3760, 0x00 }, ++ { 0x3761, 0x00 }, ++ { 0x3762, 0x00 }, ++ { 0x3763, 0x00 }, ++ { 0x3764, 0x00 }, ++ { 0x3767, 0x04 }, ++ { 0x3768, 0x04 }, ++ { 0x3769, 0x08 }, ++ { 0x376a, 0x08 }, ++ { 0x376b, 0x20 }, ++ { 0x376c, 0x00 }, ++ { 0x376d, 0x00 }, ++ { 0x376e, 0x00 }, ++ { 0x3773, 0x00 }, ++ { 0x3774, 0x51 }, ++ { 0x3776, 0xbd }, ++ { 0x3777, 0xbd }, ++ { 0x3781, 0x18 }, ++ { 0x3783, 0x25 }, ++ { 0x3798, 0x1b }, ++ { 0x3800, 0x01 }, ++ { 0x3801, 0x88 }, ++ { 0x3802, 0x00 }, ++ { 0x3803, 0xe0 }, ++ { 0x3804, 0x09 }, ++ { 0x3805, 0x17 }, ++ { 0x3806, 0x05 }, ++ { 0x3807, 0x1f }, ++ { 0x3808, 0x07 }, ++ { 0x3809, 0x80 }, ++ { 0x380a, 0x04 }, ++ { 0x380b, 0x38 }, ++ { 0x380c, 0x06 }, ++ { 0x380d, 0xb8 }, ++ { 0x380e, 0x09 }, ++ { 0x380f, 0x14 }, ++ { 0x3810, 0x00 }, ++ { 0x3811, 0x08 }, ++ { 0x3812, 0x00 }, ++ { 0x3813, 0x04 }, ++ { 0x3814, 0x01 }, ++ { 0x3815, 0x01 }, ++ { 0x3819, 0x01 }, ++ { 0x3820, 0x00 }, ++ { 0x3821, 0x06 }, ++ { 0x3829, 0x00 }, ++ { 0x382a, 0x01 }, ++ { 0x382b, 0x01 }, ++ { 0x382d, 0x7f }, ++ { 0x3830, 0x04 }, ++ { 0x3836, 0x01 }, ++ { 0x3837, 0x00 }, ++ { 0x3841, 0x02 }, ++ { 0x3846, 0x08 }, ++ { 0x3847, 0x07 }, ++ { 0x3d85, 0x36 }, ++ { 0x3d8c, 0x71 }, ++ { 0x3d8d, 0xcb }, ++ { 0x3f0a, 0x00 }, ++ { 0x4000, 0xf1 }, ++ { 0x4001, 0x40 }, ++ { 0x4002, 0x04 }, ++ { 0x4003, 0x14 }, ++ { 0x400e, 0x00 }, ++ { 0x4011, 0x00 }, ++ { 0x401a, 0x00 }, ++ { 0x401b, 0x00 }, ++ { 0x401c, 0x00 }, ++ { 0x401d, 0x00 }, ++ { 0x401f, 0x00 }, ++ { 0x4020, 0x00 }, ++ { 0x4021, 0x10 }, ++ { 0x4022, 0x06 }, ++ { 0x4023, 0x13 }, ++ { 0x4024, 0x07 }, ++ { 0x4025, 0x40 }, ++ { 0x4026, 0x07 }, ++ { 0x4027, 0x50 }, ++ { 0x4028, 0x00 }, ++ { 0x4029, 0x02 }, ++ { 0x402a, 0x06 }, ++ { 0x402b, 0x04 }, ++ { 0x402c, 0x02 }, ++ { 0x402d, 0x02 }, ++ { 0x402e, 0x0e }, ++ { 0x402f, 0x04 }, ++ { 0x4302, 0xff }, ++ { 0x4303, 0xff }, ++ { 0x4304, 0x00 }, ++ { 0x4305, 0x00 }, ++ { 0x4306, 0x00 }, ++ { 0x4308, 0x02 }, ++ { 0x4500, 0x6c }, ++ { 0x4501, 0xc4 }, ++ { 0x4502, 0x40 }, ++ { 0x4503, 0x01 }, ++ { 0x4601, 0x77 }, ++ { 0x4800, 0x04 }, ++ { 0x4813, 0x08 }, ++ { 0x481f, 0x40 }, ++ { 0x4829, 0x78 }, ++ { 0x4837, 0x10 }, ++ { 0x4b00, 0x2a }, ++ { 0x4b0d, 0x00 }, ++ { 0x4d00, 0x04 }, ++ { 0x4d01, 0x42 }, ++ { 0x4d02, 0xd1 }, ++ { 0x4d03, 0x93 }, ++ { 0x4d04, 0xf5 }, ++ { 0x4d05, 0xc1 }, ++ { 0x5000, 0xf3 }, ++ { 0x5001, 0x11 }, ++ { 0x5004, 0x00 }, ++ { 0x500a, 0x00 }, ++ { 0x500b, 0x00 }, ++ { 0x5032, 0x00 }, ++ { 0x5040, 0x00 }, ++ { 0x5050, 0x0c }, ++ { 0x5500, 0x00 }, ++ { 0x5501, 0x10 }, ++ { 0x5502, 0x01 }, ++ { 0x5503, 0x0f }, ++ { 0x8000, 0x00 }, ++ { 0x8001, 0x00 }, ++ { 0x8002, 0x00 }, ++ { 0x8003, 0x00 }, ++ { 0x8004, 0x00 }, ++ { 0x8005, 0x00 }, ++ { 0x8006, 0x00 }, ++ { 0x8007, 0x00 }, ++ { 0x8008, 0x00 }, ++ { 0x3638, 0x00 }, ++#endif ++ {0x0100, 0x00}, ++// {0x5040, 0x80}, ++ {OV4689_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov4689_init_regs_2048_1520_30fps_mipi[] = { ++#if 0 ++ /* @@ 0 35 RES_2048x1520_23.37fps_408Mbps 2Lane */ ++ /* ;SCLK = 80MHz MIPI CLK = 408Mbps/lane Mipi PCLK = 51MHz */ ++ /* ;HTS = 2200 VTS = 1556 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x22}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x02}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++ {0x3018, 0x32}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x48}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x09}, ++ {0x3805, 0x57}, ++ {0x3806, 0x05}, ++ {0x3807, 0xFB}, ++ {0x3808, 0x08}, ++ {0x3809, 0x00}, ++ {0x380A, 0x05}, ++ {0x380B, 0xF0}, ++ {0x380C, 0x08}, ++ {0x380D, 0x98}, ++ {0x380E, 0x06}, ++ {0x380F, 0x14}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x93}, ++ {0x4024, 0x07}, ++ {0x4025, 0xC0}, ++ {0x4026, 0x07}, ++ {0x4027, 0xD0}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x7f}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x14}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++ {0x0100, 0x00}, ++#endif ++ ++#if 1 ++ /* @@ 0 35 RES_2048x1520_30fps_600Mbps 2Lane */ ++ /* ;SCLK = 120 MHz MIPI CLK = 600Mbps/lane Mipi PCLK = 75MHz */ ++ /* ;HTS = 2570 VTS = 1556 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x19}, ++ {0x0303, 0x00}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x01}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++ {0x3018, 0x32}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x48}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x09}, ++ {0x3805, 0x57}, ++ {0x3806, 0x05}, ++ {0x3807, 0xFB}, ++ {0x3808, 0x08}, ++ {0x3809, 0x00}, ++ {0x380A, 0x05}, ++ {0x380B, 0xF0}, ++ {0x380C, 0x0a}, ++ {0x380D, 0x0a}, ++ {0x380E, 0x06}, ++ {0x380F, 0x14}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x93}, ++ {0x4024, 0x07}, ++ {0x4025, 0xC0}, ++ {0x4026, 0x07}, ++ {0x4027, 0xD0}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x7f}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x2d}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++ {0x0100, 0x00}, ++#endif ++ ++#if 0 ++ /* @@ 0 35 RES_2048x1520_25fps_420Mbps 2Lane */ ++ /* ;SCLK = 82.7MHz MIPI CLK = 420Mbps/lane Mipi PCLK = 52.5MHz */ ++ /* ;HTS = 2125 VTS = 1556 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x23}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1f}, ++ {0x030e, 0x04}, ++ {0x030f, 0x02}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++#ifdef DRIVE_CAPABILITY_1 ++ {0x3011,0x00}, ++#elif defined(DRIVE_CAPABILITY_2) ++ {0x3011,0x20}, ++#elif defined(DRIVE_CAPABILITY_3) ++ {0x3011,0x40}, ++#elif defined(DRIVE_CAPABILITY_4) ++ {0x3011,0x60}, ++#endif ++ {0x3018, 0x32}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3037, 0x01}, ++// {0x303f, 0x0d}, ++// {0x3012, 0x22}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x48}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x09}, ++ {0x3805, 0x57}, ++ {0x3806, 0x05}, ++ {0x3807, 0xFB}, ++ {0x3808, 0x08}, ++ {0x3809, 0x00}, ++ {0x380A, 0x05}, ++ {0x380B, 0xF0}, ++ {0x380C, 0x08}, ++ {0x380D, 0x4d}, ++ {0x380E, 0x06}, ++ {0x380F, 0x14}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x93}, ++ {0x4024, 0x07}, ++ {0x4025, 0xC0}, ++ {0x4026, 0x07}, ++ {0x4027, 0xD0}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x7f}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x14}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++ //{0x5040, 0x80},//color bar ++ {0x0100, 0x00}, ++#endif ++ {OV4689_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov4689_init_regs_2592_1520_30fps_mipi[] = { ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x19}, //0x19 ++ {0x0303, 0x00}, ++ {0x0304, 0x03}, //0x03 ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x01}, ++ {0x0311, 0x00}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++ {0x3018, 0x32}, ++ {0x3019, 0x0c}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x60}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x00}, ++ {0x3801, 0x38}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x67}, ++ {0x3806, 0x05}, ++ {0x3807, 0xfb}, ++ {0x3808, 0x0a}, ++ {0x3809, 0x20}, ++ {0x380a, 0x05}, ++ {0x380b, 0xf0}, ++ {0x380c, 0x0A}, ++ {0x380d, 0x82},//0x18 ++ {0x380e, 0x06}, ++ {0x380f, 0xfb}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x08}, ++ {0x4023, 0xb3}, ++ {0x4024, 0x09}, ++ {0x4025, 0xe0}, ++ {0x4026, 0x09}, ++ {0x4027, 0xf0},// ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0xA1},// ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x10}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++ {0x0100, 0x00}, ++ {OV4689_REG_END, 0x00},/* END MARKER */ ++}; ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list ov4689_stream_on_mipi[] = { ++ {0x0100, 0x01}, ++ {OV4689_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov4689_stream_off_mipi[] = { ++ {0x0100, 0x00}, ++ {OV4689_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int ov4689_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != OV4689_REG_END) { ++ if (vals->reg_num == OV4689_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov4689_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int ov4689_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != OV4689_REG_END) { ++ if (vals->reg_num == OV4689_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov4689_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ov4689_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov4689_info *info = to_state(sd); ++ ++ if(val) { ++ gpiod_direction_output(info->reset, 1); ++ msleep(10); ++ gpiod_direction_output(info->reset, 0); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int ov4689_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov4689_info *info = to_state(sd); ++ ++ if(val) { ++ gpiod_direction_output(info->ircutp, 1); ++ gpiod_direction_output(info->ircutn, 1); ++ msleep(10); ++ gpiod_direction_output(info->ircutp, 0); ++ } else { ++ gpiod_direction_output(info->ircutp, 0); ++ gpiod_direction_output(info->ircutn, 0); ++ msleep(10); ++ gpiod_direction_output(info->ircutp, 1); ++ } ++ return 0; ++} ++ ++static int ov4689_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov4689_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov4689_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int ov4689_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ret = ov4689_read(sd, 0x300a, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV4689_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = ov4689_read(sd, 0x300b, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV4689_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++ ++static struct ov4689_win_size ov4689_win_sizes[] = { ++ { ++ .width = 1920, ++ .height = 1080, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++#ifdef CONFIG_OV4689_1080P_120FPS ++ .regs = ov4689_init_regs_1920_1080_120fps_mipi, ++#else ++ .regs = ov4689_init_regs_1920_1080_30fps_mipi, ++#endif ++ }, ++ { ++ .width = 2048, ++ .height = 1520, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov4689_init_regs_2048_1520_30fps_mipi, ++ }, ++ { ++ .width = 2592, ++ .height = 1520, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov4689_init_regs_2592_1520_30fps_mipi, ++ } ++}; ++ ++#define N_OV4689_FMTS ARRAY_SIZE(ov4689_win_sizes) ++ ++static int ov4689_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= N_OV4689_FMTS) ++ return -EINVAL; ++ ++ code->code = ov4689_win_sizes[code->index].mbus_code; ++ ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int ov4689_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ov4689_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov4689_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ /* *(unsigned int *)fmt->reserved = &info->win->sensor_info; */ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ov4689_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ov4689_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ov4689_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov4689_again_lut); i++) { ++ lut = &ov4689_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov4689_again_lut); i++) { ++ lut = &ov4689_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ov4689_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ret += ov4689_read(sd, 0x3509, &v); ++ ++ reg_val |= v; ++ ret += ov4689_read(sd, 0x3508, &v); ++ reg_val |= v << 8; ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ov4689_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct ov4689_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += ov4689_write(sd, 0x3509, (unsigned char)(reg_value & 0xff)); ++ ret += ov4689_write(sd, 0x3508, (unsigned char)((reg_value>>8) & 0xff)); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ov4689_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ ret += ov4689_write(sd, 0x3502, ((unsigned char)(value & 0xf)) << 4); ++ ret += ov4689_write(sd, 0x3501, (unsigned char)((value >> 4) & 0xff)); ++ ret += ov4689_write(sd, 0x3500, (unsigned char)((value >> 12) & 0xf)); ++ ++ return ret; ++} ++ ++static int ov4689_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov4689_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ov4689_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov4689_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ov4689_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov4689_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ov4689_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ov4689_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ov4689_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ov4689_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ov4689_s_gain turns off auto gain */ ++ return ov4689_s_gain(sd, info->gain->val); ++ } ++ return ov4689_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ov4689_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov4689_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ov4689_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ov4689_ctrl_ops = { ++ .s_ctrl = ov4689_s_ctrl, ++ .g_volatile_ctrl = ov4689_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov4689_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ov4689_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ov4689_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ov4689_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int ov4689_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ int ret = 0; ++ ++ if (enable) { ++ ret = ov4689_write_array(sd, ov4689_stream_on_mipi); ++ pr_debug("ov4689 stream on\n"); ++ ++ } ++ else { ++ ret = ov4689_write_array(sd, ov4689_stream_off_mipi); ++ pr_debug("ov4689 stream off\n"); ++ } ++ return ret; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ov4689_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov4689_g_register, ++ .s_register = ov4689_s_register, ++#endif ++// .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, ++// .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, ++// .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, ++// .g_ctrl = v4l2_subdev_g_ctrl, ++// .s_ctrl = v4l2_subdev_s_ctrl, ++// .queryctrl = v4l2_subdev_queryctrl, ++// .querymenu = v4l2_subdev_querymenu, ++}; ++ ++static int ov4689_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++ /*int dts*/ ++ return 0; ++} ++ ++static const struct v4l2_subdev_video_ops ov4689_video_ops = { ++ .s_stream = ov4689_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov4689_pad_ops = { ++ //.enum_frame_interval = ov4689_enum_frame_interval, ++ //.num_frame_size = ov4689_enum_frame_size, ++ .enum_mbus_code = ov4689_enum_mbus_code, ++ .set_fmt = ov4689_set_fmt, ++ .get_fmt = ov4689_get_fmt, ++ .get_mbus_config = ov4689_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_ops ov4689_ops = { ++ .core = &ov4689_core_ops, ++ .video = &ov4689_video_ops, ++ .pad = &ov4689_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int ov4689_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct ov4689_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ /* Request the reset GPIO deasserted */ ++ info->reset = devm_gpiod_get_optional(&client->dev, "reset", ++ GPIOD_OUT_LOW); ++ if (!info->reset) ++ dev_dbg(&client->dev, "reset gpio is not assigned!\n"); ++ else if (IS_ERR(info->reset)) ++ return PTR_ERR(info->reset); ++ ++ info->ircutp = devm_gpiod_get_optional(&client->dev, "ircutp", ++ GPIOD_OUT_LOW); ++ if (!info->ircutp) ++ dev_dbg(&client->dev, "ircutp gpio is not assigned!\n"); ++ else if (IS_ERR(info->ircutp)) ++ return PTR_ERR(info->ircutp); ++ ++ info->ircutn = devm_gpiod_get_optional(&client->dev, "ircutn", ++ GPIOD_OUT_LOW); ++ if (!info->ircutn) ++ dev_dbg(&client->dev, "ircutn gpio is not assigned!\n"); ++ else if (IS_ERR(info->ircutn)) ++ return PTR_ERR(info->ircutn); ++ ++ v4l2_i2c_subdev_init(sd, client, &ov4689_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ ov4689_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ov4689 */ ++ ret = ov4689_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ov4689 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ /*IRCUT ctl 0:off 1:on*/ ++ ov4689_ircut(sd, 0); ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 261773, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++#ifdef CONFIG_OV4689_2048X1520_30FPS ++ info->win = &ov4689_win_sizes[1]; ++#else ++ info->win = &ov4689_win_sizes[0]; ++#endif ++ ++ ov4689_init(sd, 1); ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ov4689 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ov4689_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov4689_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ devm_kfree(&client->dev, info); ++ return 0; ++} ++ ++static const struct i2c_device_id ov4689_id[] = { ++ { "ov4689", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov4689_id); ++ ++static const struct of_device_id ov4689_of_match[] = { ++ {.compatible = "ovti,ov4689", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++ ++static struct i2c_driver ov4689_driver = { ++ .driver = { ++ .name = "ov4689", ++ .of_match_table = of_match_ptr(ov4689_of_match), ++ }, ++ .probe = ov4689_probe, ++ .remove = ov4689_remove, ++ .id_table = ov4689_id, ++}; ++ ++module_i2c_driver(ov4689_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision ov4689 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/ov5640.c b/module_drivers/drivers/media/i2c/ingenic-cim/ov5640.c +new file mode 100644 +index 000000000..856edd0d3 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/ov5640.c +@@ -0,0 +1,1925 @@ ++/* ++ * ov5640 Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define REG_CHIP_ID_HIGH 0x300a ++#define REG_CHIP_ID_LOW 0x300b ++#define REG_CHIP_REVISION 0x302a ++#define CHIP_ID_HIGH 0x56 ++#define CHIP_ID_LOW 0x40 ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++/* In flip, the OV5640 does not need additional settings because the ISP block ++ * will auto-detect whether the pixel is in the red line or blue line and make ++ * the necessary adjustments. ++ */ ++#define REG_TC_VFLIP 0x3820 ++#define REG_TC_MIRROR 0x3821 ++#define OV5640_HFLIP 0x1 ++#define OV5640_VFLIP 0x2 ++#define OV5640_FLIP_VAL ((unsigned char)0x06) ++#define OV5640_FLIP_MASK ((unsigned char)0x06) ++ ++ /* whether sensor support high resolution (> vga) preview or not */ ++#define SUPPORT_HIGH_RESOLUTION_PRE 1 ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ u16 reg_num; ++ u16 value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++/* Supported resolutions */ ++enum ov5640_width { ++ W_QVGA = 320, ++ W_VGA = 640, ++ W_720P = 1280, ++ W_1080P = 1920, ++}; ++ ++enum ov5640_height { ++ H_QVGA = 240, ++ H_VGA = 480, ++ H_720P = 720, ++ H_1080P = 1080, ++}; ++ ++struct ov5640_format { ++ u32 code; ++ const struct regval_list *regs; ++}; ++ ++struct ov5640_win_size { ++ char *name; ++ enum ov5640_width width; ++ enum ov5640_height height; ++ const struct regval_list *regs; ++ unsigned int mbus_code; ++}; ++ ++struct ov5640_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct ov5640_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++ struct v4l2_subdev_platform_data *sd_pdata; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ ++ int (*power)(struct i2c_client *client, int on); ++ int (*reset)(struct i2c_client *client); ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++int cam_t_j = 0, cam_t_i = 0; ++unsigned long long cam_t0_buf[10]; ++unsigned long long cam_t1_buf[10]; ++ ++static inline int sensor_i2c_master_send(struct i2c_client *client, ++ const char *buf ,int count) ++{ ++ int ret; ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.len = count; ++ msg.buf = (char *)buf; ++#if 0 ++ { ++ if (cam_t_i < 10) ++ cam_t0_buf[cam_t_i] = cpu_clock(smp_processor_id()); ++ } ++#endif ++ ++ ret = i2c_transfer(adap, &msg, 1); ++ ++#if 0 ++ { ++ if (cam_t_i < 10) { ++ cam_t1_buf[cam_t_i] = cpu_clock(smp_processor_id()); ++ cam_t_i++; ++ } ++ if (cam_t_i == 10) { ++ cam_t_j = cam_t_i; ++ cam_t_i = 11; ++ while(--cam_t_j) ++ printk("cam%d : i2c1_time 0 = %lld, i2c1_time 1" ++ "= %lld, time = %lld\n", ++ cam_t_j, ++ cam_t0_buf[cam_t_j], ++ cam_t1_buf[cam_t_j], ++ cam_t1_buf[cam_t_j] ++ - cam_t0_buf[cam_t_j]); ++ } ++ } ++#endif ++ ++ /* If everything went ok (i.e. 1 msg transmitted), return #bytes ++ transmitted, else error code. */ ++ return (ret == 1) ? count : ret; ++} ++ ++static inline int sensor_i2c_master_recv(struct i2c_client *client, ++ char *buf ,int count) ++{ ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ int ret; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.flags |= I2C_M_RD; ++ msg.len = count; ++ msg.buf = buf; ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ /* If everything went ok (i.e. 1 msg transmitted), return #bytes ++ transmitted, else error code. */ ++ return (ret == 1) ? count : ret; ++} ++ ++static s32 ov5640_read_reg(struct i2c_client *client, u16 reg) ++{ ++ int ret; ++ u8 retval; ++ u16 r = cpu_to_be16(reg); ++ ++ ret = sensor_i2c_master_send(client,(u8 *)&r,2); ++ ++ if (ret < 0) ++ return ret; ++ if (ret != 2) ++ return -EIO; ++ ++ ret = sensor_i2c_master_recv(client, &retval, 1); ++ if (ret < 0) ++ return ret; ++ if (ret != 1) ++ return -EIO; ++ return retval; ++ ++} ++ ++static s32 ov5640_write_reg(struct i2c_client *client, u16 reg, u8 val) ++{ ++ unsigned char msg[3]; ++ int ret; ++ ++ ++ reg = cpu_to_be16(reg); ++ ++ memcpy(&msg[0], ®, 2); ++ memcpy(&msg[2], &val, 1); ++ ++ ret = sensor_i2c_master_send(client, msg, 3); ++ ++ if (ret < 0) ++ { ++ printk("RET<0\n"); ++ return ret; ++ } ++ if (ret < 3) ++ { ++ printk("RET<3\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Registers settings ++ */ ++ ++#define ENDMARKER { 0xff, 0xff } ++ ++static const struct regval_list ov5640_init_regs[] = { ++ {0x3103, 0x11}, ++ {0x3008, 0x82}, // sw reset ++ {0x3008, 0x42}, // sw powerdown ++ {0x3103, 0x03}, ++ {0x3017, 0xff}, ++ {0x3018, 0xff}, // i/o control ++ {0x3034, 0x18}, ++ {0x3035, 0x11}, ++ {0x3036, 0x46}, ++ {0x3037, 0x13}, ++ {0x3108, 0x01}, ++ {0x3630, 0x36}, //?? ++ {0x3631, 0x0e}, ++ {0x3632, 0xe2}, ++ {0x3633, 0x12}, ++ {0x3621, 0xe0}, ++ {0x3704, 0xa0}, //?? ++ {0x3703, 0x5a}, ++ {0x3715, 0x78}, ++ {0x3717, 0x01}, ++ {0x370b, 0x60}, ++ {0x3705, 0x1a}, ++ {0x3905, 0x02}, ++ {0x3906, 0x10}, ++ {0x3901, 0x0a}, ++ {0x3731, 0x12}, ++ {0x3600, 0x08}, ++ {0x3601, 0x33}, ++ {0x302d, 0x60}, ++ {0x3620, 0x52}, ++ {0x371b, 0x20}, ++ {0x471c, 0x50}, ++ {0x3a13, 0x43}, ++ {0x3a18, 0x00}, ++ {0x3a19, 0xf8}, ++ {0x3635, 0x13}, ++ {0x3636, 0x03}, ++ {0x3634, 0x40}, ++ {0x3622, 0x01}, ++ {0x3c01, 0x34}, ++ {0x3c04, 0x28}, ++ {0x3c05, 0x98}, ++ {0x3c06, 0x00}, ++ {0x3c07, 0x08}, ++ {0x3c08, 0x00}, ++ {0x3c09, 0x1c}, ++ {0x3c0a, 0x9c}, ++ {0x3c0b, 0x40}, ++ {0x3820, 0x41}, ++ {0x3821, 0x07}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x07}, ++ {0x3807, 0x9b}, ++ {0x3808, 0x02}, ++ {0x3809, 0x80}, ++ {0x380a, 0x01}, ++ {0x380b, 0xe0}, ++ {0x380c, 0x07}, ++ {0x380d, 0x68}, ++ {0x380e, 0x03}, ++ {0x380f, 0xd8}, ++ {0x3810, 0x00}, ++ {0x3811, 0x10}, ++ {0x3812, 0x00}, ++ {0x3813, 0x06}, ++ {0x3618, 0x00}, ++ {0x3612, 0x29}, ++ {0x3708, 0x62}, ++ {0x3709, 0x52}, ++ {0x370c, 0x03}, ++ {0x3a02, 0x03}, ++ {0x3a03, 0xd8}, ++ {0x3a08, 0x01}, ++ {0x3a09, 0x27}, ++ {0x3a0a, 0x00}, ++ {0x3a0b, 0xf6}, ++ {0x3a0e, 0x03}, ++ {0x3a0d, 0x04}, ++ {0x3a14, 0x03}, ++ {0x3a15, 0xd8}, ++ {0x4000, 0x81}, ++ {0x4001, 0x02}, ++ {0x4004, 0x02}, ++ {0x3000, 0x00}, ++ {0x3002, 0x1c}, ++ {0x3004, 0xff}, ++ {0x3006, 0xc3}, ++ {0x300e, 0x58}, //set output interface is DVP ++ {0x302e, 0x00}, ++ {0x4300, 0x30}, //YUV422, sequence YUYV ++ {0x4740, 0x00}, //pclk polarity HSYNC, VSYNC, PCLK, 0: active low, 1: active high. ++ {0x501f, 0x00}, ++ {0x4713, 0x03}, ++ {0x4407, 0x04}, ++ {0x440e, 0x00}, ++ {0x460b, 0x35}, ++ {0x460c, 0x22}, ++ {0x3824, 0x02}, ++ {0x5000, 0xa7}, ++ {0x5001, 0xa3}, ++ {0x5180, 0xff}, ++ {0x5181, 0xf2}, ++ {0x5182, 0x00}, ++ {0x5183, 0x14}, ++ {0x5184, 0x25}, ++ {0x5185, 0x24}, ++ {0x5186, 0x09}, ++ {0x5187, 0x09}, ++ {0x5188, 0x09}, ++ {0x5189, 0x75}, ++ {0x518a, 0x54}, ++ {0x518b, 0xe0}, ++ {0x518c, 0xb2}, ++ {0x518d, 0x42}, ++ {0x518e, 0x3d}, ++ {0x518f, 0x56}, ++ {0x5190, 0x46}, ++ {0x5191, 0xf8}, ++ {0x5192, 0x04}, ++ {0x5193, 0x70}, ++ {0x5194, 0xf0}, ++ {0x5195, 0xf0}, ++ {0x5196, 0x03}, ++ {0x5197, 0x01}, ++ {0x5198, 0x04}, ++ {0x5199, 0x12}, ++ {0x519a, 0x04}, ++ {0x519b, 0x00}, ++ {0x519c, 0x06}, ++ {0x519d, 0x82}, ++ {0x519e, 0x38}, ++ {0x5381, 0x1e}, ++ {0x5382, 0x5b}, ++ {0x5383, 0x08}, ++ {0x5384, 0x0a}, ++ {0x5385, 0x7e}, ++ {0x5386, 0x88}, ++ {0x5387, 0x7c}, ++ {0x5388, 0x6c}, ++ {0x5389, 0x10}, ++ {0x538a, 0x01}, ++ {0x538b, 0x98}, ++ {0x5300, 0x08}, ++ {0x5301, 0x30}, ++ {0x5302, 0x10}, ++ {0x5303, 0x00}, ++ {0x5304, 0x08}, ++ {0x5305, 0x30}, ++ {0x5306, 0x08}, ++ {0x5307, 0x16}, ++ {0x5309, 0x08}, ++ {0x530a, 0x30}, ++ {0x530b, 0x04}, ++ {0x530c, 0x06}, ++ {0x5480, 0x01}, ++ {0x5481, 0x08}, ++ {0x5482, 0x14}, ++ {0x5483, 0x28}, ++ {0x5484, 0x51}, ++ {0x5485, 0x65}, ++ {0x5486, 0x71}, ++ {0x5487, 0x7d}, ++ {0x5488, 0x87}, ++ {0x5489, 0x91}, ++ {0x548a, 0x9a}, ++ {0x548b, 0xaa}, ++ {0x548c, 0xb8}, ++ {0x548d, 0xcd}, ++ {0x548e, 0xdd}, ++ {0x548f, 0xea}, ++ {0x5490, 0x1d}, ++ {0x5580, 0x06}, ++ {0x5583, 0x40}, ++ {0x5584, 0x10}, ++ {0x5589, 0x10}, ++ {0x558a, 0x00}, ++ {0x558b, 0xf8}, ++ {0x5800, 0x23}, ++ {0x5801, 0x14}, ++ {0x5802, 0x0f}, ++ {0x5803, 0x0f}, ++ {0x5804, 0x12}, ++ {0x5805, 0x26}, ++ {0x5806, 0x0c}, ++ {0x5807, 0x08}, ++ {0x5808, 0x05}, ++ {0x5809, 0x05}, ++ {0x580a, 0x08}, ++ {0x580b, 0x0d}, ++ {0x580c, 0x08}, ++ {0x580d, 0x03}, ++ {0x580e, 0x00}, ++ {0x580f, 0x00}, ++ {0x5810, 0x03}, ++ {0x5811, 0x09}, ++ {0x5812, 0x07}, ++ {0x5813, 0x03}, ++ {0x5814, 0x00}, ++ {0x5815, 0x01}, ++ {0x5816, 0x03}, ++ {0x5817, 0x08}, ++ {0x5818, 0x0d}, ++ {0x5819, 0x08}, ++ {0x581a, 0x05}, ++ {0x581b, 0x06}, ++ {0x581c, 0x08}, ++ {0x581d, 0x0e}, ++ {0x581e, 0x29}, ++ {0x581f, 0x17}, ++ {0x5820, 0x11}, ++ {0x5821, 0x11}, ++ {0x5822, 0x15}, ++ {0x5823, 0x28}, ++ {0x5824, 0x46}, ++ {0x5825, 0x26}, ++ {0x5826, 0x08}, ++ {0x5827, 0x26}, ++ {0x5828, 0x64}, ++ {0x5829, 0x26}, ++ {0x582a, 0x24}, ++ {0x582b, 0x22}, ++ {0x582c, 0x24}, ++ {0x582d, 0x24}, ++ {0x582e, 0x06}, ++ {0x582f, 0x22}, ++ {0x5830, 0x40}, ++ {0x5831, 0x42}, ++ {0x5832, 0x24}, ++ {0x5833, 0x26}, ++ {0x5834, 0x24}, ++ {0x5835, 0x22}, ++ {0x5836, 0x22}, ++ {0x5837, 0x26}, ++ {0x5838, 0x44}, ++ {0x5839, 0x24}, ++ {0x583a, 0x26}, ++ {0x583b, 0x28}, ++ {0x583c, 0x42}, ++ {0x583d, 0xce}, ++ {0x5025, 0x00}, ++ {0x3a0f, 0x30}, ++ {0x3a10, 0x28}, ++ {0x3a1b, 0x30}, ++ {0x3a1e, 0x26}, ++ {0x3a11, 0x60}, ++ {0x3a1f, 0x14}, ++ {0x3008, 0x02}, ++ {0x3035, 0x21}, ++ /* {0x503d, 0x80}, // color bar */ ++ {0x4202, 0X0F}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_qvga_regs[] = { ++ {0x4202, 0x0f}, ++ ++ {0x3c07, 0x08}, ++ {0x5189, 0x72}, ++ ++ {0x3503, 0x00}, ++ {0x3a00, 0x3c}, ++ {0x3a02, 0x09}, ++ {0x3a03, 0x3a}, ++ {0x3a14, 0x09}, ++ {0x3a15, 0x3a}, ++ ++ {0x5302, 0x3f}, ++ {0x5303, 0x10}, ++ {0x5306, 0x04}, ++ {0x5307, 0x14}, ++ ++ {0x3820, 0x41}, ++ {0x3821, 0x07}, ++ ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x07}, ++ {0x3807, 0x9b}, ++ {0x3808, 0x01}, ++ {0x3809, 0x40}, ++ {0x380a, 0x00}, ++ {0x380b, 0xf0}, ++ {0x3810, 0x00}, ++ {0x3811, 0x10}, ++ {0x3812, 0x00}, ++ {0x3813, 0x06}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ ++ {0x3034, 0x1a}, ++ //{0x3035, 0x11}, ++ {0x3035, 0x21}, ++ ++ {0x3036, 0x46}, ++ {0x3037, 0x13}, ++ ++ {0x380c, 0x07}, ++ {0x380d, 0x68}, ++ {0x380e, 0x03}, ++ {0x380f, 0xd8}, ++ ++ {0x3a08, 0x01}, ++ {0x3a09, 0x27}, ++ {0x3a0e, 0x03}, ++ {0x3a0a, 0x00}, ++ {0x3a0b, 0xf6}, ++ {0x3a0d, 0x04}, ++ ++ {0x3618, 0x00}, ++ {0x3612, 0x29}, ++ {0x3709, 0x52}, ++ {0x370c, 0x03}, ++ ++ {0x4004, 0x02}, ++ {0x3002, 0x1c}, ++ {0x3006, 0xc3}, ++ {0x3824, 0x02}, ++ {0x5001, 0xa3}, ++ ++ {0x4713, 0x03}, ++ {0x4407, 0x04}, ++ {0x460b, 0x35}, ++ {0x460c, 0x22}, ++ {0x4837, 0x22}, ++ ++ {0x5586, 0x24}, ++ {0x5585, 0x10}, ++ {0x5587, 0x20}, ++ {0x5588, 0x01}, ++ ++ //{0x4202, 0x00}, ++ ++ {0x3023, 0x01}, ++ {0x3022, 0x04}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_vga_regs[] = { ++ {0x4202, 0x0f}, ++ ++ {0x3c07, 0x08}, ++ {0x5189, 0x72}, ++ ++ {0x3503, 0x00}, ++ {0x3a00, 0x3c}, ++ {0x3a02, 0x09}, ++ {0x3a03, 0x3a}, ++ {0x3a14, 0x09}, ++ {0x3a15, 0x3a}, ++ ++ {0x5302, 0x3f}, ++ {0x5303, 0x10}, ++ {0x5306, 0x04}, ++ {0x5307, 0x14}, ++ ++ {0x3820, 0x41}, ++ {0x3821, 0x07}, ++ ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x07}, ++ {0x3807, 0x9b}, ++ {0x3808, 0x02}, ++ {0x3809, 0x80}, ++ {0x380a, 0x01}, ++ {0x380b, 0xe0}, ++ {0x3810, 0x00}, ++ {0x3811, 0x10}, ++ {0x3812, 0x00}, ++ {0x3813, 0x06}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ ++ {0x3034, 0x1a}, ++ {0x3035, 0x11}, ++ {0x3036, 0x46}, ++ {0x3037, 0x13}, ++ ++ {0x380c, 0x07}, ++ {0x380d, 0x68}, ++ {0x380e, 0x03}, ++ {0x380f, 0xd8}, ++ ++ {0x3a08, 0x01}, ++ {0x3a09, 0x27}, ++ {0x3a0e, 0x03}, ++ {0x3a0a, 0x00}, ++ {0x3a0b, 0xf6}, ++ {0x3a0d, 0x04}, ++ ++ {0x3618, 0x00}, ++ {0x3612, 0x29}, ++ {0x3709, 0x52}, ++ {0x370c, 0x03}, ++ ++ {0x4004, 0x02}, ++ {0x3002, 0x1c}, ++ {0x3006, 0xc3}, ++ {0x3824, 0x02}, ++ {0x5001, 0xa3}, ++ ++ {0x4713, 0x03}, ++ {0x4407, 0x04}, ++ {0x460b, 0x35}, ++ {0x460c, 0x22}, ++ {0x4837, 0x22}, ++ ++ {0x5586, 0x24}, ++ {0x5585, 0x10}, ++ {0x5587, 0x20}, ++ {0x5588, 0x01}, ++ ++ //{0x4202, 0x00}, ++ ++ {0x3023, 0x01}, ++ {0x3022, 0x04}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_720p_regs[] = { ++ {0x4202, 0x0f}, ++ ++ {0x3c07, 0x07}, ++ {0x5189, 0x72}, ++ ++ {0x3503, 0x00}, ++ ++ {0x5302, 0x3f}, ++ {0x5303, 0x10}, ++ {0x5306, 0x04}, ++ {0x5307, 0x14}, ++ ++ {0x3820, 0x41}, ++ {0x3821, 0x07}, ++ ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0xfa}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x06}, ++ {0x3807, 0xa9}, ++ {0x3808, 0x05}, ++ {0x3809, 0x00}, ++ {0x380a, 0x02}, ++ {0x380b, 0xd0}, ++ {0x3813, 0x04}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ ++ {0x3034, 0x1a}, ++ {0x3035, 0x41}, //30fps ++ {0x3036, 0x69}, ++ {0x3037, 0x13}, ++ ++ {0x380c, 0x07}, ++ {0x380d, 0x64}, ++ {0x380e, 0x02}, ++ {0x380f, 0xe4}, ++ ++ {0x3a08, 0x00}, ++ {0x3a09, 0xde}, ++ {0x3a0e, 0x03}, ++ {0x3a0a, 0x00}, ++ {0x3a0b, 0xb9}, ++ {0x3a0d, 0x04}, ++ ++ {0x3a00, 0x38}, ++ {0x3a02, 0x02}, ++ {0x3a03, 0xe4}, ++ {0x3a14, 0x02}, ++ {0x3a15, 0xe4}, ++ ++ {0x3618, 0x00}, ++ {0x3612, 0x29}, ++ {0x3709, 0x52}, ++ {0x370c, 0x03}, ++ ++ {0x4004, 0x02}, ++ {0x3002, 0x1c}, ++ {0x3006, 0xc3}, ++ {0x3824, 0x04}, ++ {0x5001, 0x83}, ++ ++ {0x4713, 0x03}, ++ {0x4407, 0x04}, ++ {0x460b, 0x37}, ++ {0x460c, 0x20}, ++ {0x4837, 0x16}, ++ ++ {0x5586, 0x24}, ++ {0x5585, 0x10}, ++ {0x5587, 0x20}, ++ {0x5588, 0x01}, ++ ++// {0x4202, 0x00}, ++ ++ {0x3023, 0x01}, ++ {0x3022, 0x04}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_1080p_regs[] = { ++ {0x4202, 0x0f}, ++ ++ {0x3c07, 0x07}, ++ {0x5189, 0x72}, ++ ++ {0x3503, 0x00}, ++ ++ {0x5302, 0x3f}, ++ {0x5303, 0x10}, ++ {0x5306, 0x04}, ++ {0x5307, 0x14}, ++ ++ {0x3820, 0x40}, ++ {0x3821, 0x00}, ++ ++ {0x3800, 0x01}, ++ {0x3801, 0x50}, ++ {0x3802, 0x01}, ++ {0x3803, 0xb2}, ++ {0x3804, 0x08}, ++ {0x3805, 0xef}, ++ {0x3806, 0x05}, ++ {0x3807, 0xf1}, ++ {0x3808, 0x07}, ++ {0x3809, 0x80}, ++ {0x380a, 0x04}, ++ {0x380b, 0x38}, ++ {0x3813, 0x04}, ++ {0x3814, 0x11}, ++ {0x3815, 0x11}, ++ ++ {0x3034, 0x1a}, ++ {0x3035, 0x41}, //3.75fps ++ {0x3036, 0x69}, ++ {0x3037, 0x13}, ++ ++ {0x380c, 0x09}, ++ {0x380d, 0xc4}, ++ {0x380e, 0x04}, ++ {0x380f, 0x60}, ++ ++ {0x3a08, 0x01}, ++ {0x3a09, 0x50}, ++ {0x3a0e, 0x03}, ++ {0x3a0a, 0x01}, ++ {0x3a0b, 0x18}, ++ {0x3a0d, 0x04}, ++ ++ {0x3a00, 0x38}, ++ {0x3a02, 0x04}, ++ {0x3a03, 0x60}, ++ {0x3a14, 0x04}, ++ {0x3a15, 0x60}, ++ ++ {0x3618, 0x04}, ++ {0x3612, 0x2b}, ++ {0x3709, 0x12}, ++ {0x370c, 0x00}, ++ ++ {0x4004, 0x06}, ++ {0x3002, 0x1c}, ++ {0x3006, 0xc3}, ++ {0x3824, 0x04}, ++ {0x5001, 0x83}, ++ ++ {0x4713, 0x02}, ++ {0x4407, 0x04}, ++ {0x460b, 0x37}, ++ {0x460c, 0x20}, ++ {0x4837, 0x0a}, ++ ++ {0x5586, 0x24}, ++ {0x5585, 0x10}, ++ {0x5587, 0x20}, ++ {0x5588, 0x01}, ++ ++ //{0x4202, 0x00}, ++ ++ {0x3023, 0x01}, ++ {0x3022, 0x04}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_wb_auto_regs[] = { ++ {0x3406, 0x00}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_wb_incandescence_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x3406, 0x01}, ++ {0x3400, 0x05}, ++ {0x3401, 0x48}, ++ {0x3402, 0x04}, ++ {0x3403, 0x00}, ++ {0x3404, 0x07}, ++ {0x3405, 0xcf}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_wb_daylight_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x3406, 0x01}, ++ {0x3400, 0x06}, ++ {0x3401, 0x1c}, ++ {0x3402, 0x04}, ++ {0x3403, 0x00}, ++ {0x3404, 0x04}, ++ {0x3405, 0xf3}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_wb_fluorescent_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x3406, 0x01}, ++ {0x3400, 0x05}, ++ {0x3401, 0x8c}, ++ {0x3402, 0x04}, ++ {0x3403, 0x00}, ++ {0x3404, 0x06}, ++ {0x3405, 0xe8}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_wb_cloud_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x3406, 0x01}, ++ {0x3400, 0x06}, ++ {0x3401, 0x48}, ++ {0x3402, 0x04}, ++ {0x3403, 0x00}, ++ {0x3404, 0x04}, ++ {0x3405, 0xd3}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov5640_balance[] = { ++ {0, ov5640_wb_auto_regs}, {1, ov5640_wb_incandescence_regs}, ++ {2, ov5640_wb_daylight_regs}, {3, ov5640_wb_fluorescent_regs}, ++ {4, ov5640_wb_cloud_regs}, ++}; ++ ++static const struct regval_list ov5640_effect_normal_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x5580, 0x06}, ++ {0x5583, 0x40}, ++ {0x5584, 0x10}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_effect_grayscale_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x5580, 0x1e}, ++ {0x5583, 0x80}, ++ {0x5584, 0x80}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_effect_sepia_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x5580, 0x1e}, ++ {0x5583, 0x40}, ++ {0x5584, 0xa0}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_effect_colorinv_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x5580, 0x46}, ++ {0x5583, 0x40}, ++ {0x5584, 0x10}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_effect_sepiabluel_regs[] = { ++ {0x3212, 0x03}, ++ ++ {0x5580, 0x1e}, ++ {0x5583, 0xa0}, ++ {0x5584, 0x40}, ++ ++ {0x3212, 0x13}, ++ {0x3212, 0xa3}, ++ ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_BGR565_Setting[] = { ++ {0x4300, 0x60},//BGR565 ++ {0x501f, 0x01},//ISP RGB ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_RGB565_Setting[] = { ++ {0x4300, 0x61},//RGB565 ++ {0x501f, 0x01},//ISP RGB */ ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_GRB565_Setting[] = { ++ {0x4300, 0x62},//GRB565 ++ {0x501f, 0x01},//ISP RGB ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_BRG565_Setting[] = { ++ {0x4300, 0x63},//BRG565 ++ {0x501f, 0x01},//ISP RGB ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_GBR565_Setting[] = { ++ {0x4300, 0x64},//GBR565 ++ {0x501f, 0x01},//ISP RGB ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_RBG565_Setting[] = { ++ {0x4300, 0x65},//RBG565 ++ {0x501f, 0x01},//ISP RGB ++ ENDMARKER, ++}; ++ ++ ++struct regval_list ov5640_YUV422_YUYV_Setting[] = { ++ {0x4300, 0x30},//YUYV ++ {0x501f, 0x00},//ISP YUV ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_YUV422_YVYU_Setting[] = { ++ {0x4300, 0x31},//YVYU ++ {0x501f, 0x00},//ISP YUV ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_YUV422_UYVY_Setting[] = { ++ {0x4300, 0x32},//UYVY ++ {0x501f, 0x00},//ISP YUV ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_YUV422_VYUY_Setting[] = { ++ {0x4300, 0x33},//VYUY ++ {0x501f, 0x00},//ISP YUV ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_SBGGR8_Setting[] = { ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x10}, ++ {0x3813, 0x04}, ++ ENDMARKER, ++}; ++struct regval_list ov5640_SGBRG8_Setting[] = { ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x11}, ++ {0x3813, 0x04}, ++ ENDMARKER, ++}; ++struct regval_list ov5640_SGRBG8_Setting[] = { ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x10}, ++ {0x3813, 0x05}, ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_SRGGB8_Setting[] = { ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x11}, ++ {0x3813, 0x05}, ++ ENDMARKER, ++}; ++ ++struct regval_list ov5640_Y8_Setting[] = { ++ {0x4300, 0x10},//Y ++ ENDMARKER, ++}; ++ ++static struct ov5640_format ov5640_fmt[] = { ++ {MEDIA_BUS_FMT_RGB565_2X8_LE, ov5640_RGB565_Setting}, ++ {INGENIC_MEDIA_BUS_FMT_RBG565_2X8_LE, ov5640_RBG565_Setting}, ++ {MEDIA_BUS_FMT_BGR565_2X8_LE, ov5640_BGR565_Setting}, ++ {INGENIC_MEDIA_BUS_FMT_BRG565_2X8_LE, ov5640_BRG565_Setting}, ++ {INGENIC_MEDIA_BUS_FMT_GRB565_2X8_LE, ov5640_GRB565_Setting}, ++ {INGENIC_MEDIA_BUS_FMT_GBR565_2X8_LE, ov5640_GBR565_Setting}, ++ {MEDIA_BUS_FMT_YUYV8_2X8, ov5640_YUV422_YUYV_Setting}, ++ {MEDIA_BUS_FMT_YVYU8_2X8, ov5640_YUV422_YVYU_Setting}, ++ {MEDIA_BUS_FMT_UYVY8_2X8, ov5640_YUV422_UYVY_Setting}, ++ {MEDIA_BUS_FMT_VYUY8_2X8, ov5640_YUV422_VYUY_Setting}, ++ ++ {MEDIA_BUS_FMT_SBGGR8_1X8, ov5640_SBGGR8_Setting}, /*raw 8*/ ++ {MEDIA_BUS_FMT_SGBRG8_1X8, ov5640_SGBRG8_Setting}, /*raw 8*/ ++ {MEDIA_BUS_FMT_SGRBG8_1X8, ov5640_SGRBG8_Setting}, /*raw 8*/ ++ {MEDIA_BUS_FMT_SRGGB8_1X8, ov5640_SRGGB8_Setting}, /*raw 8*/ ++ {MEDIA_BUS_FMT_Y8_1X8, ov5640_Y8_Setting}, /*raw 8*/ ++}; ++ ++#define N_FMT_SIZES (ARRAY_SIZE(ov5640_fmt)) ++ ++static const struct mode_list ov5640_effect[] = { ++ {0, ov5640_effect_normal_regs}, {1, ov5640_effect_grayscale_regs}, ++ {2, ov5640_effect_sepia_regs}, {3, ov5640_effect_colorinv_regs}, ++ {4, ov5640_effect_sepiabluel_regs}, ++}; ++ ++#define OV5640_SIZE(n, w, h, r) \ ++ {.name = n, .width = w , .height = h, .regs = r} ++ ++static struct ov5640_win_size ov5640_supported_win_sizes[] = { ++ OV5640_SIZE("1080P", W_1080P, H_1080P, ov5640_1080p_regs), ++ OV5640_SIZE("720P", W_720P, H_720P, ov5640_720p_regs), ++ OV5640_SIZE("VGA", W_VGA, H_VGA, ov5640_vga_regs), ++ OV5640_SIZE("QVGA", W_QVGA, H_QVGA, ov5640_qvga_regs), ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(ov5640_supported_win_sizes)) ++ ++static const struct regval_list ov5640_yuv422_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5640_rgb565_regs[] = { ++ ENDMARKER, ++}; ++ ++/* ++ * Supported balance menus ++ */ ++static const struct v4l2_querymenu ov5640_balance_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 0, ++ .name = "auto", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 1, ++ .name = "incandescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 2, ++ .name = "fluorescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 3, ++ .name = "daylight", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 4, ++ .name = "cloudy-daylight", ++ }, ++ ++}; ++ ++/* ++ * Supported effect menus ++ */ ++static const struct v4l2_querymenu ov5640_effect_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 0, ++ .name = "none", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 1, ++ .name = "mono", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 2, ++ .name = "sepia", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 3, ++ .name = "negative", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 4, ++ .name = "aqua", ++ }, ++}; ++/* ++ * General functions ++ */ ++static struct ov5640_priv *to_ov5640(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov5640_priv, ++ subdev); ++} ++ ++static int ov5640_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while ((vals->reg_num != 0xff) || (vals->value != 0xff)) { ++ ret = ov5640_write_reg(client, vals->reg_num, vals->value); ++ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", ++ vals->reg_num, vals->value); ++ ++ if (ret < 0) ++ return ret; ++ vals++; ++ } ++ ++ return 0; ++} ++ ++static int ov5640_mask_set(struct i2c_client *client, ++ u16 reg, u16 mask, u16 set) ++{ ++ s32 val = ov5640_read_reg(client, reg); ++ if (val < 0) ++ return val; ++ ++ val &= ~mask; ++ val |= set & mask; ++ ++ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); ++ ++ return ov5640_write_reg(client, reg, val); ++} ++ ++/* ++ * soc_camera_ops functions ++ */ ++ ++/* OF probe functions */ ++static int ov5640_hw_power(struct i2c_client *client, int on) ++{ ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, !on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int ov5640_reset(struct i2c_client *client) ++{ ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ if(priv->resetb_gpio) { ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ msleep(10); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ msleep(10); ++ } ++ ++ return 0; ++} ++ ++static int ov5640_g_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov5640_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VFLIP: ++ ctrl->val = priv->flag_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->val = priv->flag_hflip; ++ break; ++ case V4L2_CID_PRIVATE_BALANCE: ++ ctrl->val = priv->balance_value; ++ break; ++ case V4L2_CID_PRIVATE_EFFECT: ++ ctrl->val = priv->effect_value; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov5640_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640_priv *priv = to_ov5640(client); ++ int ret = 0; ++ int i = 0; ++ u16 value; ++ ++ int balance_count = ARRAY_SIZE(ov5640_balance); ++ int effect_count = ARRAY_SIZE(ov5640_effect); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ if(ctrl->val > balance_count) ++ return -EINVAL; ++ ++ for(i = 0; i < balance_count; i++) { ++ if(ctrl->val == ov5640_balance[i].index) { ++ ret = ov5640_write_array(client, ++ ov5640_balance[ctrl->val].mode_regs); ++ priv->balance_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ if(ctrl->val > effect_count) ++ return -EINVAL; ++ ++ for(i = 0; i < effect_count; i++) { ++ if(ctrl->val == ov5640_effect[i].index) { ++ ret = ov5640_write_array(client, ++ ov5640_effect[ctrl->val].mode_regs); ++ priv->effect_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_VFLIP: ++ value = ctrl->val ? OV5640_FLIP_VAL : 0x00; ++ priv->flag_vflip = ctrl->val ? 1 : 0; ++ ret = ov5640_mask_set(client, REG_TC_VFLIP, OV5640_FLIP_MASK, value); ++ break; ++ ++ case V4L2_CID_HFLIP: ++ value = ctrl->val ? OV5640_FLIP_VAL : 0x00; ++ priv->flag_hflip = ctrl->val ? 1 : 0; ++ ret = ov5640_mask_set(client, REG_TC_MIRROR, OV5640_FLIP_MASK, value); ++ break; ++ ++ default: ++ dev_err(&client->dev, "no V4L2 CID: 0x%x ", ctrl->id); ++ return -EINVAL; ++ } ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { ++ .s_ctrl = ov5640_s_ctrl, ++ .g_volatile_ctrl = ov5640_g_ctrl, ++}; ++ ++static int ov5640_s_power(struct v4l2_subdev *sd, int on) ++ ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ if(priv->sd_pdata) { ++ if(on) ++ return regulator_bulk_enable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ else ++ return regulator_bulk_disable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ } else if(priv->power){ ++ return priv->power(client, on); ++ } else { ++ dev_err(&client->dev, "ov5640_s_power failde"); ++ return -EINVAL; ++ } ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov5640_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg == 0xff) ++ return -EINVAL; ++ ++ ret = ov5640_read_reg(client, reg->reg); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = ret; ++ ++ return 0; ++} ++ ++static int ov5640_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg == 0xff || ++ reg->val == 0xff) ++ return -EINVAL; ++ ++ return ov5640_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!enable ) { ++ dev_dbg(&client->dev, "stream down\n"); ++ ov5640_write_reg(client, 0x4202, 0x0f); ++ return 0; ++ } ++ ++ dev_dbg(&client->dev, "stream on\n"); ++ ov5640_write_reg(client, 0x4202, 0x00); ++ ++ return 0; ++} ++ ++/* Select the nearest higher resolution for capture */ ++static const struct ov5640_win_size *ov5640_select_win(u32 *width, u32 *height) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ov5640_supported_win_sizes); i++) { ++ if ((*width >= ov5640_supported_win_sizes[i].width) && ++ (*height >= ov5640_supported_win_sizes[i].height)) { ++ *width = ov5640_supported_win_sizes[i].width; ++ *height = ov5640_supported_win_sizes[i].height; ++ return &ov5640_supported_win_sizes[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int ov5640_set_params(struct i2c_client *client, u32 *width, u32 *height, ++ u32 code) ++{ ++ struct ov5640_priv *priv = to_ov5640(client); ++ int ret; ++ int i; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* select win */ ++ priv->win = ov5640_select_win(width, height); ++ ++ /* select format */ ++ priv->cfmt_code = 0; ++ ++ /* reset hardware */ ++ ov5640_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ret = ov5640_write_array(client, ov5640_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = ov5640_write_array(client, ov5640_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = ov5640_write_array(client, ov5640_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set size win */ ++ ret = ov5640_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ for (i = 0; i < N_FMT_SIZES; i++) { ++ if (ov5640_fmt[i].code == code) { ++ ret = ov5640_write_array(client, ov5640_fmt[i].regs); ++ if (ret < 0) ++ goto err; ++ } ++ } ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ ov5640_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int ov5640_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ if(!priv->win) ++ return -EINVAL; ++ ++ sel->r.top = 0; ++ sel->r.left = 0; ++ sel->r.width = priv->win->width; ++ sel->r.height = priv->win->height; ++ ++ return 0; ++} ++ ++static int ov5640_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ if (!priv->win) { ++ mf->width = W_VGA, ++ mf->height = H_VGA; ++ priv->win = ov5640_select_win(&mf->width, &mf->height); ++ priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; ++ } ++ ++ mf->width = priv->win->width; ++ mf->height = priv->win->height; ++ mf->code = priv->cfmt_code; ++ ++ switch (mf->code) { ++ case MEDIA_BUS_FMT_RGB565_2X8_BE: ++ case MEDIA_BUS_FMT_RGB565_2X8_LE: ++ case INGENIC_MEDIA_BUS_FMT_RBG565_2X8_LE: ++ case MEDIA_BUS_FMT_BGR565_2X8_LE: ++ case INGENIC_MEDIA_BUS_FMT_BRG565_2X8_LE: ++ case INGENIC_MEDIA_BUS_FMT_GBR565_2X8_LE: ++ case INGENIC_MEDIA_BUS_FMT_GRB565_2X8_LE: ++ mf->colorspace = V4L2_COLORSPACE_SRGB; ++ break; ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ case MEDIA_BUS_FMT_YVYU8_2X8: ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ case MEDIA_BUS_FMT_VYUY8_2X8: ++ default: ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ break; ++ } ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov5640_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ /* ++ * select suitable win, but don't store it ++ */ ++ priv->win = ov5640_select_win(&mf->width, &mf->height); ++ if(!priv->win) ++ return -EINVAL; ++ ++ mf->field = V4L2_FIELD_NONE; ++ ++ switch (mf->code) { ++ case MEDIA_BUS_FMT_RGB565_2X8_BE: ++ case MEDIA_BUS_FMT_RGB565_2X8_LE: ++ case INGENIC_MEDIA_BUS_FMT_RBG565_2X8_LE: ++ case MEDIA_BUS_FMT_BGR565_2X8_LE: ++ case INGENIC_MEDIA_BUS_FMT_BRG565_2X8_LE: ++ case INGENIC_MEDIA_BUS_FMT_GBR565_2X8_LE: ++ case INGENIC_MEDIA_BUS_FMT_GRB565_2X8_LE: ++ mf->colorspace = V4L2_COLORSPACE_SRGB; ++ break; ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ case MEDIA_BUS_FMT_YVYU8_2X8: ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ case MEDIA_BUS_FMT_VYUY8_2X8: ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ break; ++ default: ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ break; ++ } ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ ov5640_set_params(client, &mf->width, &mf->height, mf->code); ++ if(cfg) ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= N_FMT_SIZES) ++ return -EINVAL; ++ ++ code->code = ov5640_fmt[code->index].code; ++ ++ return 0; ++} ++ ++static int ov5640_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int i, j; ++ int num_valid = -1; ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++ j = N_FMT_SIZES; ++ while(--j) ++ if(fse->code == ov5640_fmt[j].code) ++ break; ++ for (i = 0; i < N_WIN_SIZES; i++) { ++ if (index == ++num_valid) { ++ fse->code = ov5640_fmt[j].code; ++ fse->min_width = ov5640_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = ov5640_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++ } ++ } ++ return -EINVAL; ++} ++ ++static int ov5640_hw_reset(struct i2c_client *client) ++{ ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ if (priv->resetb_gpio) { ++ /* Active the resetb pin to perform a reset pulse */ ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ usleep_range(3000, 5000); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ } ++ ++ return 0; ++} ++ ++static int ov5640_video_probe(struct i2c_client *client) ++{ ++ unsigned char retval = 0, retval_high = 0, retval_low = 0; ++ struct ov5640_priv *priv = to_ov5640(client); ++ int ret; ++ ++ ret = ov5640_s_power(&priv->subdev, 1); ++ if (ret < 0) ++ return ret; ++ /* ++ * check and show product ID and manufacturer ID ++ */ ++ ++ retval = ov5640_write_reg(client, 0x3008, 0x80); ++ if(retval) { ++ dev_err(&client->dev, "i2c write failed!\n"); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ retval_high = ov5640_read_reg(client, REG_CHIP_ID_HIGH); ++ if (retval_high != CHIP_ID_HIGH) { ++ dev_err(&client->dev, "read sensor %s chip_id high %x is error\n", ++ client->name, retval_high); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ ++ retval_low = ov5640_read_reg(client, REG_CHIP_ID_LOW); ++ if (retval_low != CHIP_ID_LOW) { ++ dev_err(&client->dev, "read sensor %s chip_id low %x is error\n", ++ client->name, retval_low); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ dev_info(&client->dev, "read sensor %s id high:0x%x,low:%x successed!\n", ++ client->name, retval_high, retval_low); ++done: ++ return ret; ++} ++ ++static int ov5640_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++ /*int dts*/ ++ return 0; ++} ++ ++static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov5640_g_register, ++ .s_register = ov5640_s_register, ++#endif ++ .s_power = ov5640_s_power, ++}; ++ ++static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = { ++ .s_stream = ov5640_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = { ++ .enum_mbus_code = ov5640_enum_mbus_code, ++ .enum_frame_size = ov5640_enum_frame_size, ++ .get_fmt = ov5640_get_fmt, ++ .set_fmt = ov5640_set_fmt, ++ .get_mbus_config = ov5640_g_mbus_config, ++ .get_selection = ov5640_get_selection, ++}; ++ ++static struct v4l2_subdev_ops ov5640_subdev_ops = { ++ .core = &ov5640_subdev_core_ops, ++ .video = &ov5640_subdev_video_ops, ++ .pad = &ov5640_subdev_pad_ops, ++}; ++ ++static int ov5640_probe_dt(struct i2c_client *client, ++ struct ov5640_priv *priv) ++{ ++ ++ struct v4l2_subdev_platform_data *sd_pdata = priv->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies > 0) { ++ sd_pdata = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev_platform_data), GFP_KERNEL); ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ devm_kfree(&client->dev,sd_pdata); ++ return -ENOMEM; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ devm_regulator_bulk_get(&client->dev, sd_pdata->num_regulators, sd_pdata->regulators); ++ } else { ++ /* Request the reset GPIO deasserted */ ++ priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", ++ GPIOD_OUT_LOW); ++ if (!priv->resetb_gpio) ++ dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); ++ else if (IS_ERR(priv->resetb_gpio)) ++ return PTR_ERR(priv->resetb_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->power = ov5640_hw_power; ++ priv->reset = ov5640_hw_reset; /* TODO */ ++ } ++ return 0; ++} ++ ++#include ++/* ++ * i2c_driver functions ++ */ ++static int ov5640_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov5640_priv *priv; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "OV5640: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct ov5640_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 25000000); ++ ++ ret = ov5640_probe_dt(client, priv); ++ if (ret) ++ goto err_probe_dt; ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &ov5640_subdev_ops); ++ ++ /* add handler */ ++ v4l2_ctrl_handler_init(&priv->hdl, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov5640_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov5640_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ priv->subdev.ctrl_handler = &priv->hdl; ++ if (priv->hdl.error) { ++ ret = priv->hdl.error; ++ goto err_hdl; ++ } ++ ++ ret = ov5640_video_probe(client); ++ if (ret < 0) ++ goto err_detect; ++ ++ ret = v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_async_register_subdev; ++ ++ dev_info(&adapter->dev, "OV5640 Probed\n"); ++ ++ return 0; ++ ++err_async_register_subdev: ++err_detect: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_hdl: ++ v4l2_device_unregister_subdev(&priv->subdev); ++err_probe_dt: ++ v4l2_clk_put(priv->clk); ++ devm_kfree(&client->dev, priv); ++ return ret; ++} ++ ++static int ov5640_remove(struct i2c_client *client) ++{ ++ struct ov5640_priv *priv = to_ov5640(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ devm_kfree(&client->dev, priv); ++ return 0; ++} ++ ++static const struct i2c_device_id ov5640_id[] = { ++ { "ov5640", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov5640_id); ++ ++static const struct of_device_id ov5640_of_match[] = { ++ {.compatible = "ovti,ov5640", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov5640_of_match); ++ ++static struct i2c_driver ov5640_i2c_driver = { ++ .driver = { ++ .name = "ov5640", ++ .of_match_table = of_match_ptr(ov5640_of_match), ++ }, ++ .probe = ov5640_probe, ++ .remove = ov5640_remove, ++ .id_table = ov5640_id, ++}; ++ ++module_i2c_driver(ov5640_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 5640 sensor"); ++MODULE_AUTHOR("Alberto Panizzo"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/ov5645.c b/module_drivers/drivers/media/i2c/ingenic-cim/ov5645.c +new file mode 100644 +index 000000000..84c43f3db +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/ov5645.c +@@ -0,0 +1,1629 @@ ++/* ++ * ov5645 Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define REG_CHIP_ID_HIGH 0x300a ++#define REG_CHIP_ID_LOW 0x300b ++#define CHIP_ID_HIGH 0x56 ++#define CHIP_ID_LOW 0x45 ++ ++#define OV5645_DEFAULT_WIDTH 640 ++#define OV5645_DEFAULT_HEIGHT 480 ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++#define REG_TC_VFLIP 0x3820 ++#define REG_TC_MIRROR 0x3821 ++#define OV5645_FLIP_VAL ((unsigned char)0x04) ++#define OV5645_FLIP_MASK ((unsigned char)0x04) ++ ++/* whether sensor support high resolution (> vga) preview or not */ ++#define SUPPORT_HIGH_RESOLUTION_PRE 1 ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ u16 reg_num; ++ u16 value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++/* Supported resolutions */ ++enum ov5645_width { ++ W_VGA = OV5645_DEFAULT_WIDTH, ++ W_720P = 1280, ++ W_1080P = 1920, ++}; ++ ++enum ov5645_height { ++ H_VGA = OV5645_DEFAULT_HEIGHT, ++ H_720P = 720, ++ H_1080P = 1080, ++}; ++ ++struct ov5645_format { ++ u32 code; ++ const struct regval_list *regs; ++}; ++ ++struct ov5645_win_size { ++ char *name; ++ enum ov5645_width width; ++ enum ov5645_height height; ++ const struct regval_list *regs; ++}; ++ ++struct ov5645_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov5645_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct ov5645_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++ struct v4l2_subdev_platform_data *sd_pdata; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ ++ int (*power)(struct i2c_client *client, int on); ++ int (*reset)(struct i2c_client *client); ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++static inline int sensor_i2c_master_send(struct i2c_client *client, ++ const char *buf ,int count) ++{ ++ int ret; ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.len = count; ++ msg.buf = (char *)buf; ++ ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++static inline int sensor_i2c_master_recv(struct i2c_client *client, ++ char *buf ,int count) ++{ ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ int ret; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.flags |= I2C_M_RD; ++ msg.len = count; ++ msg.buf = buf; ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++ ++unsigned char ov5645_read_reg(struct i2c_client *client, u16 reg) ++{ ++ int ret; ++ unsigned char retval; ++ unsigned short r = cpu_to_be16(reg); ++ ++ ret = sensor_i2c_master_send(client,(u8 *)&r,2); ++ ++ if (ret < 0) ++ return ret; ++ if (ret != 2) ++ return -EIO; ++ ++ ret = sensor_i2c_master_recv(client, &retval, 1); ++ if (ret < 0) ++ return ret; ++ if (ret != 1) ++ return -EIO; ++ return retval; ++} ++ ++int ov5645_write_reg(struct i2c_client *client, u16 reg, u8 val) ++{ ++ unsigned char msg[3]; ++ int ret; ++ ++ reg = cpu_to_be16(reg); ++ ++ memcpy(&msg[0], ®, 2); ++ memcpy(&msg[2], &val, 1); ++ ++ ret = sensor_i2c_master_send(client, msg, 3); ++ ++ if (ret < 0) ++ { ++ printk("RET<0\n"); ++ return ret; ++ } ++ if (ret < 3) ++ { ++ printk("RET<3\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Registers settings ++ */ ++ ++#define ENDMARKER { 0xffff, 0x00 } ++#define OV5645_REG_DELAY 0xfffe ++ ++static const struct regval_list ov5645_init_regs[] = { ++ {0x3103, 0x11}, // software standby ++ {0x3008, 0x82}, // software reset ++ //delay(5ms) ++ {OV5645_REG_DELAY, 3}, ++ {0x4202, 0x0f}, // analog control ++ {0x4202, 0x0f}, // analog control ++ ++ {0x3008, 0x42}, ++ {0x3103, 0x03}, ++ {0x3503, 0x07}, ++ {0x3002, 0x1c}, ++ {0x3006, 0xc3}, ++ {0x300e, 0x45}, ++ {0x3017, 0x40}, ++ {0x3018, 0x00}, ++ {0x302e, 0x0b}, ++ {0x3037, 0x13}, ++ {0x3108, 0x01}, ++ {0x3611, 0x06}, ++ {0x3612, 0xab}, ++ {0x3614, 0x50}, ++ {0x3618, 0x00}, ++ {0x3034, 0x18}, ++ {0x3035, 0x21}, ++ {0x3036, 0x70}, ++ {0x3500, 0x00}, ++ {0x3501, 0x01}, ++ {0x3502, 0x00}, ++ {0x350a, 0x00}, ++ {0x350b, 0x3f}, ++ {0x3600, 0x09}, ++ {0x3601, 0x43}, ++ {0x3620, 0x33}, ++ {0x3621, 0xe0}, ++ {0x3622, 0x01}, ++ {0x3630, 0x2d}, ++ {0x3631, 0x00}, ++ {0x3632, 0x32}, ++ {0x3633, 0x52}, ++ {0x3634, 0x70}, ++ {0x3635, 0x13}, ++ {0x3636, 0x03}, ++ {0x3702, 0x6e}, ++ {0x3703, 0x52}, ++ {0x3704, 0xa0}, ++ {0x3705, 0x33}, ++ {0x3708, 0x66}, ++ {0x3709, 0x12}, ++ {0x370b, 0x61}, ++ {0x370c, 0xc3}, ++ {0x370f, 0x10}, ++ {0x3715, 0x08}, ++ {0x3717, 0x01}, ++ {0x371b, 0x20}, ++ {0x3731, 0x22}, ++ {0x3739, 0x70}, ++ {0x3901, 0x0a}, ++ {0x3905, 0x02}, ++ {0x3906, 0x10}, ++ {0x3719, 0x86}, ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x06}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x3f}, ++ {0x3806, 0x07}, ++ {0x3807, 0x9d}, ++ {0x3808, 0x05}, ++ {0x3809, 0x00}, ++ {0x380a, 0x03}, ++ {0x380b, 0xc0}, ++ {0x380c, 0x07}, ++ {0x380d, 0x68}, ++ {0x380e, 0x03}, ++ {0x380f, 0xd8}, ++ {0x3810, 0x00}, ++ {0x3811, 0x10}, ++ {0x3812, 0x00}, ++ {0x3813, 0x06}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ {0x3820, 0x47}, ++ {0x3821, 0x07}, ++ {0x3824, 0x01}, ++ {0x3826, 0x03}, ++ {0x3828, 0x08}, ++ {0x3a02, 0x03}, ++ {0x3a03, 0xd8}, ++ {0x3a08, 0x01}, ++ {0x3a09, 0xf8}, ++ {0x3a0a, 0x01}, ++ {0x3a0b, 0xa4}, ++ {0x3a0e, 0x02}, ++ {0x3a0d, 0x02}, ++ {0x3a14, 0x03}, // 50Hz max exposure = 984 ++ {0x3a15, 0xd8}, // 50Hz max exposure ++ {0x3a18, 0x01}, // gain ceiling = 31.5x ++ {0x3a19, 0xf8}, // gain ceiling ++ // 50/0xauto, 0xde,tect ++ {0x3c01, 0x34}, ++ {0x3c04, 0x28}, ++ {0x3c05, 0x98}, ++ {0x3c07, 0x07}, ++ {0x3c09, 0xc2}, ++ {0x3c0a, 0x9c}, ++ {0x3c0b, 0x40}, ++ {0x3c01, 0x34}, ++ {0x4001, 0x02}, ++ {0x4004, 0x02}, ++ {0x4005, 0x18}, ++ {0x4300, 0x32}, /* YUYV */ ++ {0x4514, 0x00}, ++ {0x4520, 0xb0}, ++ {0x460b, 0x37}, ++ {0x460c, 0x20}, ++ // MIPI timing ++ {0x4818, 0x01}, ++ {0x481d, 0xf0}, ++ {0x481f, 0x50}, ++ {0x4823, 0x70}, ++ {0x4831, 0x14}, ++ {0x4837, 0x10}, ++ // BLC start line ++ // B0xline, 0xnu,mber ++ // BLC update by gain change ++ // YUV 422, YUYV ++ // global timing ++ {0x5000, 0xa7}, // Lenc on, raw gamma on, BPC on, WPC on, color interpolation on ++ {0x5001, 0x83}, // SDE on, scale off, UV adjust off, color matrix on, AWB on ++ {0x501d, 0x00}, ++ {0x501f, 0x00}, // select ISP YUV 422 ++ {0x503d, 0x00}, ++ {0x505c, 0x30}, ++ // AWB control ++ {0x5181, 0x59}, ++ {0x5183, 0x00}, ++ {0x5191, 0xf0}, ++ {0x5192, 0x03}, ++ // AVG control ++ {0x5684, 0x10}, ++ {0x5685, 0xa0}, ++ {0x5686, 0x0c}, ++ {0x5687, 0x78}, ++ {0x5a00, 0x08}, ++ {0x5a21, 0x00}, ++ {0x5a24, 0x00}, ++ {0x3008, 0x02}, // wake 0xfrom, 0xso,ftware standby ++ {0x3503, 0x00}, // AGC auto, AEC auto ++ // AWB control ++ {0x5180, 0xff}, ++ {0x5181, 0xf2}, ++ {0x5182, 0x00}, ++ {0x5183, 0x14}, ++ {0x5184, 0x25}, ++ {0x5185, 0x24}, ++ {0x5186, 0x09}, ++ {0x5187, 0x09}, ++ {0x5188, 0x0a}, ++ {0x5189, 0x75}, ++ {0x518a, 0x52}, ++ {0x518b, 0xea}, ++ {0x518c, 0xa8}, ++ {0x518d, 0x42}, ++ {0x518e, 0x38}, ++ {0x518f, 0x56}, ++ {0x5190, 0x42}, ++ {0x5191, 0xf8}, ++ {0x5192, 0x04}, ++ {0x5193, 0x70}, ++ {0x5194, 0xf0}, ++ {0x5195, 0xf0}, ++ {0x5196, 0x03}, ++ {0x5197, 0x01}, ++ {0x5198, 0x04}, ++ {0x5199, 0x12}, ++ {0x519a, 0x04}, ++ {0x519b, 0x00}, ++ {0x519c, 0x06}, ++ {0x519d, 0x82}, ++ {0x519e, 0x38}, ++ // matrix ++ {0x5381, 0x1e}, ++ {0x5382, 0x5b}, ++ {0x5383, 0x08}, ++ {0x5384, 0x0b}, ++ {0x5385, 0x84}, ++ {0x5386, 0x8f}, ++ {0x5387, 0x82}, ++ {0x5388, 0x71}, ++ {0x5389, 0x11}, ++ {0x538a, 0x01}, ++ {0x538b, 0x98}, ++ // CIP ++ {0x5300, 0x08}, ++ {0x5301, 0x30}, ++ {0x5302, 0x10}, ++ {0x5303, 0x00}, ++ {0x5304, 0x08}, ++ {0x5305, 0x30}, ++ {0x5306, 0x08}, ++ {0x5307, 0x16}, ++ {0x5309, 0x08}, ++ {0x530a, 0x30}, ++ {0x530b, 0x04}, ++ {0x530c, 0x06}, ++ // Gamma ++ {0x5480, 0x01}, ++ {0x5481, 0x0e}, ++ {0x5482, 0x18}, ++ {0x5483, 0x2b}, ++ {0x5484, 0x52}, ++ {0x5485, 0x65}, ++ {0x5486, 0x71}, ++ {0x5487, 0x7d}, ++ {0x5488, 0x87}, ++ {0x5489, 0x91}, ++ {0x548a, 0x9a}, ++ {0x548b, 0xaa}, ++ {0x548c, 0xb8}, ++ {0x548d, 0xcd}, ++ {0x548e, 0xdd}, ++ {0x548f, 0xea}, ++ {0x5490, 0x1d}, ++ {0x5580, 0x06}, ++ {0x5583, 0x40}, ++ {0x5584, 0x30}, ++ {0x5589, 0x10}, ++ {0x558a, 0x00}, ++ {0x558b, 0xf8}, ++ // LENC ++ {0x5800, 0x3f}, ++ {0x5801, 0x16}, ++ {0x5802, 0x0e}, ++ {0x5803, 0x0d}, ++ {0x5804, 0x17}, ++ {0x5805, 0x3f}, ++ {0x5806, 0x0b}, ++ {0x5807, 0x06}, ++ {0x5808, 0x04}, ++ {0x5809, 0x04}, ++ {0x580a, 0x06}, ++ {0x580b, 0x0b}, ++ {0x580c, 0x09}, ++ {0x580d, 0x03}, ++ {0x580e, 0x00}, ++ {0x580f, 0x00}, ++ {0x5810, 0x03}, ++ {0x5811, 0x08}, ++ {0x5812, 0x0a}, ++ {0x5813, 0x03}, ++ {0x5814, 0x00}, ++ {0x5815, 0x00}, ++ {0x5816, 0x04}, ++ {0x5817, 0x09}, ++ {0x5818, 0x0f}, ++ {0x5819, 0x08}, ++ {0x581a, 0x06}, ++ {0x581b, 0x06}, ++ {0x581c, 0x08}, ++ {0x581d, 0x0c}, ++ {0x581e, 0x3f}, ++ {0x581f, 0x1e}, ++ {0x5820, 0x12}, ++ {0x5821, 0x13}, ++ {0x5822, 0x21}, ++ {0x5823, 0x3f}, ++ {0x5824, 0x68}, ++ {0x5825, 0x28}, ++ {0x5826, 0x2c}, ++ {0x5827, 0x28}, ++ {0x5828, 0x08}, ++ {0x5829, 0x48}, ++ {0x582a, 0x64}, ++ {0x582b, 0x62}, ++ {0x582c, 0x64}, ++ {0x582d, 0x28}, ++ {0x582e, 0x46}, ++ {0x582f, 0x62}, ++ {0x5830, 0x60}, ++ {0x5831, 0x62}, ++ {0x5832, 0x26}, ++ {0x5833, 0x48}, ++ {0x5834, 0x66}, ++ {0x5835, 0x44}, ++ {0x5836, 0x64}, ++ {0x5837, 0x28}, ++ {0x5838, 0x66}, ++ {0x5839, 0x48}, ++ {0x583a, 0x2c}, ++ {0x583b, 0x28}, ++ {0x583c, 0x26}, ++ {0x583d, 0xae}, ++ {0x5025, 0x00}, // AEC in H ++ {0x3a0f, 0x38}, // AEC in L ++ {0x3a10, 0x30}, // AEC out H ++ {0x3a1b, 0x38}, // AEC out L ++ {0x3a1e, 0x30}, // control zone H ++ {0x3a11, 0x70}, // control zone L ++ {0x3a1f, 0x18}, // wake up from standby ++ {0x3008, 0x02}, ++ // DPC Setting // ++ {0x5780, 0xfc}, // default value ++ {0x5781, 0x13}, // default value ++ {0x5782, 0x03}, // default 8 ++ {0x5786, 0x20}, // default 10 -- add ++ {0x5787, 0x40}, // default 10 ++ {0x5788, 0x08}, ++ // white pixel threshold ++ {0x5789, 0x08}, // 1x ++ {0x578a, 0x02}, // 8x – set in 5783 ++ {0x578b, 0x01}, // 12x – set in 5784 ++ {0x578c, 0x01}, // 128x ++ // black pixel threshold ++ {0x578d, 0x0c}, // 1x ++ {0x578e, 0x02}, // 8x – set in 5783 ++ {0x578f, 0x01}, // 12x – set in 5784 ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_wb_auto_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_wb_incandescence_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_wb_daylight_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_wb_fluorescent_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_wb_cloud_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov5645_balance[] = { ++ {0, ov5645_wb_auto_regs}, {1, ov5645_wb_incandescence_regs}, ++ {2, ov5645_wb_daylight_regs}, {3, ov5645_wb_fluorescent_regs}, ++ {4, ov5645_wb_cloud_regs}, ++}; ++ ++ ++static const struct regval_list ov5645_effect_normal_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_effect_grayscale_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_effect_sepia_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_effect_colorinv_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_effect_sepiabluel_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov5645_effect[] = { ++ {0, ov5645_effect_normal_regs}, {1, ov5645_effect_grayscale_regs}, ++ {2, ov5645_effect_sepia_regs}, {3, ov5645_effect_colorinv_regs}, ++ {4, ov5645_effect_sepiabluel_regs}, ++}; ++ ++static const struct regval_list ov5645_vga_regs[] = { ++ //Sysclk = 42Mhz, MIPI 2 lane 168MBps ++ //0x3612, 0xa9, ++ {0x3618, 0x00}, ++ {0x3035, 0x21}, ++ {0x3036, 0x54}, ++ {0x3600, 0x09}, ++ {0x3601, 0x43}, ++ {0x3708, 0x66}, ++ {0x370c, 0xc3}, ++ {0x3803, 0xfa},// VS L ++ {0x3806, 0x06},// VH = 1705 ++ {0x3807, 0xa9},// VH ++ {0x3808, 0x02},// DVPHO = 640 ++ {0x3809, 0x80},// DVPHO ++ {0x380a, 0x01},// DVPVO = 480 ++ {0x380b, 0xe0},// DVPVO ++ {0x380c, 0x07},// HTS = 1892 ++ {0x380d, 0x64},// HTS ++ {0x380e, 0x02},// VTS = 740 ++ {0x380f, 0xe4},// VTS ++ {0x3814, 0x31},// X INC ++ {0x3815, 0x31},// X INC ++ {0x3820, 0x41},// flip off, V bin on ++ {0x3821, 0x07},// mirror on, H bin on ++ {0x4514, 0x00}, ++ ++ {0x3a02, 0x02},// night mode ceiling = 740 ++ {0x3a03, 0xe4},// night mode ceiling ++ {0x3a08, 0x00},// B50 = 222 ++ {0x3a09, 0xde},// B50 ++ {0x3a0a, 0x00},// B60 = 185 ++ {0x3a0b, 0xb9},// B60 ++ {0x3a0e, 0x03},// max 50 ++ {0x3a0d, 0x04},// max 60 ++ {0x3a14, 0x02},//max 50hz exposure = 3/100 ++ {0x3a15, 0x9a},// max 50hz exposure ++ {0x3a18, 0x01},// max gain = 31.5x ++ {0x3a19, 0xf8},// max gain ++ {0x4004, 0x02},// BLC line number ++ {0x4005, 0x18},// BLC update by gain change ++ {0x4837, 0x16},// MIPI global timing ++ {0x3503, 0x00},// AGC/AEC on ++ ++ {0x4300, 0x30},//YUYV ++ {0x501f, 0x00},//ISP YUV ++// {0x503d ,0x80}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_720p_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov5645_1080p_regs[] = { ++ {0x3618 ,0x04}, ++ {0x3035 ,0x61}, ++ {0x3036 ,0x30}, ++ {0x3600 ,0x08}, ++ {0x3601 ,0x33}, ++ {0x3708 ,0x63}, ++ {0x370c ,0xc0}, ++ {0x3800 ,0x01}, ++ {0x3801 ,0x50}, ++ {0x3802 ,0x01}, ++ {0x3803 ,0xb2}, ++ {0x3804 ,0x08}, ++ {0x3805 ,0xef}, ++ {0x3806 ,0x05}, ++ {0x3807 ,0xf1}, ++ {0x3808 ,0x07},//width[11:8]1920 ++ {0x3809 ,0x80},//width[7:0] ++ {0x380a ,0x04},//height[11:8]1080 ++ {0x380b ,0x38},//height[7:0] ++ {0x380c ,0x09}, ++ {0x380d ,0xc4}, ++ {0x380e ,0x04}, ++ {0x380f ,0x60}, ++ {0x3813 ,0x04}, ++ {0x3814 ,0x11}, ++ {0x3815 ,0x11}, ++ {0x3820 ,0x40}, ++ {0x3821 ,0x06}, ++ {0x3a02 ,0x04}, ++ {0x3a03 ,0x60}, ++ {0x3a09 ,0x50}, ++ {0x3a0b ,0x18}, ++ {0x3a0e ,0x03}, ++ {0x3a0d ,0x04}, ++ {0x3a14 ,0x04}, ++ {0x3a15 ,0x60}, ++ {0x3a18 ,0x00}, ++ {0x4004 ,0x06}, ++ {0x4050 ,0x6e}, ++ {0x4051 ,0x8f}, ++ {0x4300 ,0x30}, ++ {0x4837 ,0x0b}, ++ {0x5301 ,0x1e}, ++ {0x5305 ,0x1e}, ++ {0x530a ,0x1e}, ++ {0x5580 ,0x02}, ++ {0x5780 ,0xfc}, ++ {0x5781 ,0x13}, ++ {0x5782 ,0x03}, ++ {0x5786 ,0x20}, ++ {0x5787 ,0x40}, ++ {0x5788 ,0x08}, ++ {0x5789 ,0x08}, ++ {0x578a ,0x02}, ++ {0x578b ,0x01}, ++ {0x578c ,0x01}, ++ {0x578d ,0x0c}, ++ {0x578e ,0x02}, ++ {0x578f ,0x01}, ++ {0x5790 ,0x01}, ++ {0x3a11 ,0x70}, ++ {0x3a1b ,0x38}, ++ {0x3a1e ,0x30}, ++ {0x3a1f ,0x18}, ++ {0x4300 ,0x00}, ++ {0x501f ,0x03}, ++ {0x3008 ,0x02}, ++// {0x503d ,0x80}, ++ ++ ENDMARKER, ++}; ++ ++ ++#define OV5645_SIZE(n, w, h, r) \ ++ {.name = n, .width = w , .height = h, .regs = r } ++ ++static struct ov5645_win_size ov5645_supported_win_sizes[] = { ++ OV5645_SIZE("VGA", W_VGA, H_VGA, ov5645_vga_regs), ++ OV5645_SIZE("720P", W_720P, H_720P, ov5645_720p_regs), ++ OV5645_SIZE("1080P", W_1080P, H_1080P, ov5645_1080p_regs), ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(ov5645_supported_win_sizes)) ++ ++struct regval_list ov5645_BGR565_Setting[] = { ++ {0x4300, 0x60},//BGR565 ++ {0x501f, 0x01},//ISP RGB ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_RGB565_Setting[] = { ++ /* {0x4300, 0x61},//RGB565 */ ++ {0x4300, 0x6F},//RGB565 ++ {0x501f, 0x01},//ISP RGB */ ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_GRB565_Setting[] = { ++ {0x4300, 0x62},//GRB565 ++ {0x501f, 0x01},//ISP RGB ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_BRG565_Setting[] = { ++ {0x4300, 0x63},//BRG565 ++ {0x501f, 0x01},//ISP RGB ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_GBR565_Setting[] = { ++ {0x4300, 0x64},//GBR565 ++ {0x501f, 0x01},//ISP RGB ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_RBG565_Setting[] = { ++ {0x4300, 0x65},//GBR565 ++ {0x501f, 0x01},//ISP RGB ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_YUV422_YUYV_Setting[] = { ++ {0x4300, 0x30},//YUYV ++ {0x501f, 0x00},//ISP YUV ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_YUV422_YVYU_Setting[] = { ++ {0x4300, 0x31},//YVYU ++ {0x501f, 0x00},//ISP YUV ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_YUV422_UYVY_Setting[] = { ++ {0x4300, 0x32},//UYVY ++ {0x501f, 0x00},//ISP YUV ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_YUV422_VYUY_Setting[] = { ++ {0x4300, 0x33},//VYUY ++ {0x501f, 0x00},//ISP YUV ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_SBGGR8_Setting[] = { ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x10}, ++ {0x3813, 0x04}, ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_SGBRG8_Setting[] = { ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x11}, ++ {0x3813, 0x04}, ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_SGRBG8_Setting[] = { ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x10}, ++ {0x3813, 0x05}, ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_SRGGB8_Setting[] = { ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x11}, ++ {0x3813, 0x05}, ++ ENDMARKER, ++}; ++ ++ ++struct regval_list ov5645_SBGGR10_Setting[] = { ++ {0x3034, 0x1a}, ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x10}, ++ {0x3813, 0x04}, ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_SGBRG10_Setting[] = { ++ {0x3034, 0x1a}, ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x11}, ++ {0x3813, 0x04}, ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_SGRBG10_Setting[] = { ++ {0x3034, 0x1a}, ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x10}, ++ {0x3813, 0x05}, ++ ENDMARKER, ++}; ++ ++struct regval_list ov5645_SRGGB10_Setting[] = { ++ {0x3034, 0x1a}, ++ {0x4300, 0xf8},//raw ++ {0x501f, 0x03}, ++ {0x3811, 0x11}, ++ {0x3813, 0x05}, ++ ENDMARKER, ++}; ++ ++ ++struct ov5645_format ov5645_fmt[] = { ++ {MEDIA_BUS_FMT_RGB565_2X8_LE, ov5645_RGB565_Setting}, ++ {INGENIC_MEDIA_BUS_FMT_RBG565_2X8_LE, ov5645_RBG565_Setting}, ++ {MEDIA_BUS_FMT_BGR565_2X8_LE, ov5645_BGR565_Setting}, ++ {INGENIC_MEDIA_BUS_FMT_BRG565_2X8_LE, ov5645_BRG565_Setting}, ++ {INGENIC_MEDIA_BUS_FMT_GRB565_2X8_LE, ov5645_GRB565_Setting}, ++ {INGENIC_MEDIA_BUS_FMT_GBR565_2X8_LE, ov5645_GBR565_Setting}, ++ {MEDIA_BUS_FMT_YUYV8_2X8, ov5645_YUV422_YUYV_Setting}, ++ {MEDIA_BUS_FMT_YVYU8_2X8, ov5645_YUV422_YVYU_Setting}, ++ {MEDIA_BUS_FMT_UYVY8_2X8, ov5645_YUV422_UYVY_Setting}, ++ {MEDIA_BUS_FMT_VYUY8_2X8, ov5645_YUV422_VYUY_Setting}, ++ {MEDIA_BUS_FMT_SBGGR8_1X8, ov5645_SBGGR8_Setting}, ++ {MEDIA_BUS_FMT_SGBRG8_1X8, ov5645_SGBRG8_Setting}, ++ {MEDIA_BUS_FMT_SGRBG8_1X8, ov5645_SGRBG8_Setting}, ++ {MEDIA_BUS_FMT_SRGGB8_1X8, ov5645_SRGGB8_Setting}, ++ {MEDIA_BUS_FMT_SBGGR10_1X10, ov5645_SBGGR10_Setting}, ++ {MEDIA_BUS_FMT_SGBRG10_1X10, ov5645_SGBRG10_Setting}, ++ {MEDIA_BUS_FMT_SGRBG10_1X10, ov5645_SGRBG10_Setting}, ++ {MEDIA_BUS_FMT_SRGGB10_1X10, ov5645_SRGGB10_Setting}, ++}; ++ ++#define N_FMT_SIZES (ARRAY_SIZE(ov5645_fmt)) ++ ++/* ++ * Supported balance menus ++ */ ++static const struct v4l2_querymenu ov5645_balance_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 0, ++ .name = "auto", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 1, ++ .name = "incandescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 2, ++ .name = "fluorescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 3, ++ .name = "daylight", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 4, ++ .name = "cloudy-daylight", ++ }, ++ ++}; ++ ++/* ++ * Supported effect menus ++ */ ++static const struct v4l2_querymenu ov5645_effect_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 0, ++ .name = "none", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 1, ++ .name = "mono", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 2, ++ .name = "sepia", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 3, ++ .name = "negative", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 4, ++ .name = "aqua", ++ }, ++}; ++ ++ ++/* ++ * General functions ++ */ ++static struct ov5645_priv *to_ov5645(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov5645_priv, ++ subdev); ++} ++ ++static int ov5645_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while (vals->reg_num != 0xffff) { ++ ret = ov5645_write_reg(client, vals->reg_num, vals->value); ++ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", ++ vals->reg_num, vals->value); ++ ++ if (ret < 0) ++ return ret; ++ vals++; ++ } ++ return 0; ++} ++ ++static int ov5645_mask_set(struct i2c_client *client, ++ u16 reg, u16 mask, u16 set) ++{ ++ s32 val = ov5645_read_reg(client, reg); ++ if (val < 0) ++ return val; ++ ++ val &= ~mask; ++ val |= set & mask; ++ ++ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); ++ ++ return ov5645_write_reg(client, reg, val); ++} ++ ++ ++/* OF probe functions */ ++static int ov5645_hw_power(struct i2c_client *client, int on) ++{ ++ struct ov5645_priv *priv = to_ov5645(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, !on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int ov5645_reset(struct i2c_client *client) ++{ ++ struct ov5645_priv *priv = to_ov5645(client); ++ ++ if(priv->resetb_gpio) { ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ msleep(10); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ msleep(10); ++ } ++ ++ return 0; ++} ++ ++static int ov5645_g_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov5645_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5645_priv *priv = to_ov5645(client); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VFLIP: ++ ctrl->val = priv->flag_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->val = priv->flag_hflip; ++ break; ++ case V4L2_CID_PRIVATE_BALANCE: ++ ctrl->val = priv->balance_value; ++ break; ++ case V4L2_CID_PRIVATE_EFFECT: ++ ctrl->val = priv->effect_value; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov5645_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5645_priv *priv = to_ov5645(client); ++ int ret = 0; ++ int i = 0; ++ u16 value; ++ ++ int balance_count = ARRAY_SIZE(ov5645_balance); ++ int effect_count = ARRAY_SIZE(ov5645_effect); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ if(ctrl->val > balance_count) ++ return -EINVAL; ++ ++ for(i = 0; i < balance_count; i++) { ++ if(ctrl->val == ov5645_balance[i].index) { ++ ret = ov5645_write_array(client, ++ ov5645_balance[ctrl->val].mode_regs); ++ priv->balance_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ if(ctrl->val > effect_count) ++ return -EINVAL; ++ ++ for(i = 0; i < effect_count; i++) { ++ if(ctrl->val == ov5645_effect[i].index) { ++ ret = ov5645_write_array(client, ++ ov5645_effect[ctrl->val].mode_regs); ++ priv->effect_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_VFLIP: ++ value = ctrl->val ? OV5645_FLIP_VAL : 0x00; ++ priv->flag_vflip = ctrl->val ? 1 : 0; ++ ret = ov5645_mask_set(client, REG_TC_VFLIP, OV5645_FLIP_MASK, value); ++ break; ++ ++ case V4L2_CID_HFLIP: ++ value = ctrl->val ? OV5645_FLIP_VAL : 0x00; ++ priv->flag_hflip = ctrl->val ? 1 : 0; ++ ret = ov5645_mask_set(client, REG_TC_MIRROR, OV5645_FLIP_MASK, value); ++ break; ++ ++ default: ++ dev_err(&client->dev, "no V4L2 CID: 0x%x ", ctrl->id); ++ return -EINVAL; ++ } ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ov5645_ctrl_ops = { ++ .s_ctrl = ov5645_s_ctrl, ++ .g_volatile_ctrl = ov5645_g_ctrl, ++}; ++ ++static int ov5645_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5645_priv *priv = to_ov5645(client); ++ ++ if(priv->sd_pdata) { ++ if(on) ++ return regulator_bulk_enable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ else ++ return regulator_bulk_disable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ } else if(priv->power){ ++ return priv->power(client, on); ++ } else { ++ dev_err(&client->dev, "ov5640_s_power failde"); ++ return -EINVAL; ++ } ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov5645_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg > 0xff) ++ return -EINVAL; ++ ++ ret = ov5645_read_reg(client, reg->reg); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = ret; ++ ++ return 0; ++} ++ ++static int ov5645_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg > 0xff || ++ reg->val > 0xff) ++ return -EINVAL; ++ ++ return ov5645_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++/* ++ * soc_camera_ops functions ++ */ ++static int ov5645_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!enable ) { ++ dev_info(&client->dev, "stream down\n"); ++ ov5645_write_reg(client, 0x4202, 0x0f); ++ return 0; ++ } ++ ++ dev_info(&client->dev, "stream on\n"); ++ ov5645_write_reg(client, 0x4202, 0x00); ++ ++ return 0; ++} ++ ++/* Select the nearest higher resolution for capture */ ++static const struct ov5645_win_size *ov5645_select_win(u32 *width, u32 *height) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ov5645_supported_win_sizes); i++) { ++ if ((*width <= ov5645_supported_win_sizes[i].width) && ++ (*height <= ov5645_supported_win_sizes[i].height)) { ++ *width = ov5645_supported_win_sizes[i].width; ++ *height = ov5645_supported_win_sizes[i].height; ++ return &ov5645_supported_win_sizes[i]; ++ } ++ } ++ return NULL; ++} ++ ++static int ov5645_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5645_priv *priv = to_ov5645(client); ++ ++ if(!priv->win) ++ return -EINVAL; ++ ++ sel->r.top = 0; ++ sel->r.left = 0; ++ sel->r.width = priv->win->width; ++ sel->r.height = priv->win->height; ++ ++ return 0; ++} ++ ++static int ov5645_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5645_priv *priv = to_ov5645(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ if(priv->win) { ++ mf->width = priv->win->width; ++ mf->height = priv->win->height; ++ } else { ++ mf->width = OV5645_DEFAULT_WIDTH; ++ mf->height = OV5645_DEFAULT_HEIGHT; ++ } ++ ++ mf->code = priv->cfmt_code; ++ ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov5645_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code) ++{ ++ struct ov5645_priv *priv = to_ov5645(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ int i; ++ ++ /* select win */ ++ priv->win = ov5645_select_win(width, height); ++ ++ /* select format */ ++ priv->cfmt_code = 0; ++ ++ /* reset hardware */ ++ ov5645_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ret = ov5645_write_array(client, ov5645_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = ov5645_write_array(client, ov5645_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = ov5645_write_array(client, ov5645_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set size win */ ++ ret = ov5645_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ for (i = 0; i < N_FMT_SIZES; i++) { ++ if (ov5645_fmt[i].code == code) { ++ ret = ov5645_write_array(client, ov5645_fmt[i].regs); ++ if (ret < 0) ++ goto err; ++ } ++ } ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ ov5645_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int ov5645_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov5645_priv *priv = to_ov5645(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ /* ++ * select suitable win, but don't store it ++ */ ++ priv->win = ov5645_select_win(&mf->width, &mf->height); ++ if(!priv->win) ++ return -EINVAL; ++ ++ mf->field = V4L2_FIELD_NONE; ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ ov5645_set_params(client, &mf->width, ++ &mf->height, mf->code); ++ if(cfg) ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int ov5645_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= N_FMT_SIZES) ++ return -EINVAL; ++ ++ code->code = ov5645_fmt[code->index].code; ++ return 0; ++} ++ ++static int ov5645_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int i, j; ++ int num_valid = -1; ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++ j = N_FMT_SIZES; ++ while(--j) ++ if(fse->code == ov5645_fmt[j].code) ++ break; ++ ++ for (i = 0; i < N_WIN_SIZES; i++) { ++ if (index == ++num_valid) { ++ fse->code = ov5645_fmt[j].code; ++ fse->min_width = ov5645_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = ov5645_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int ov5645_hw_reset(struct i2c_client *client) ++{ ++ struct ov5645_priv *priv = to_ov5645(client); ++ ++ if(priv->resetb_gpio) { ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ usleep_range(3000, 5000); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ } ++ return 0; ++} ++ ++static int ov5645_video_probe(struct i2c_client *client) ++{ ++ unsigned char retval = 0, retval_high = 0, retval_low = 0; ++ struct ov5645_priv *priv = to_ov5645(client); ++ int ret; ++ ++ ret = ov5645_s_power(&priv->subdev, 1); ++ if (ret < 0) ++ return ret; ++ /* ++ * check and show product ID and manufacturer ID ++ */ ++ ++ retval = ov5645_write_reg(client, 0x3008, 0x82); ++ if(retval) { ++ dev_err(&client->dev, "i2c write failed!\n"); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ retval_high = ov5645_read_reg(client, REG_CHIP_ID_HIGH); ++ if (retval_high != CHIP_ID_HIGH) { ++ dev_err(&client->dev, "read sensor %s chip_id high %x is error\n", ++ client->name, retval_high); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ ++ retval_low = ov5645_read_reg(client, REG_CHIP_ID_LOW); ++ if (retval_low != CHIP_ID_LOW) { ++ dev_err(&client->dev, "read sensor %s chip_id low %x is error\n", ++ client->name, retval_low); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ dev_info(&client->dev, "read sensor %s id high:0x%x,low:%x successed!\n", ++ client->name, retval_high, retval_low); ++ ++done: ++ return ret; ++} ++ ++static int ov5645_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++ /*int dts*/ ++ return 0; ++} ++ ++static struct v4l2_subdev_core_ops ov5645_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov5645_g_register, ++ .s_register = ov5645_s_register, ++#endif ++ .s_power = ov5645_s_power, ++}; ++ ++static struct v4l2_subdev_video_ops ov5645_subdev_video_ops = { ++ .s_stream = ov5645_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov5645_subdev_pad_ops = { ++ .enum_mbus_code = ov5645_enum_mbus_code, ++ .enum_frame_size = ov5645_enum_frame_size, ++ .get_fmt = ov5645_get_fmt, ++ .set_fmt = ov5645_set_fmt, ++ .get_mbus_config = ov5645_g_mbus_config, ++ .get_selection = ov5645_get_selection, ++}; ++ ++static struct v4l2_subdev_ops ov5645_subdev_ops = { ++ .core = &ov5645_subdev_core_ops, ++ .video = &ov5645_subdev_video_ops, ++ .pad = &ov5645_subdev_pad_ops, ++}; ++ ++static int ov5645_probe_dt(struct i2c_client *client, ++ struct ov5645_priv *priv) ++{ ++ struct v4l2_subdev_platform_data *sd_pdata = priv->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies > 0) { ++ sd_pdata = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev_platform_data), GFP_KERNEL); ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ devm_kfree(&client->dev,sd_pdata); ++ return -ENOMEM; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ devm_regulator_bulk_get(&client->dev, sd_pdata->num_regulators, sd_pdata->regulators); ++ } else { ++ /* Request the reset GPIO deasserted */ ++ priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", ++ GPIOD_OUT_LOW); ++ if (!priv->resetb_gpio) ++ dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); ++ else if (IS_ERR(priv->resetb_gpio)) ++ return PTR_ERR(priv->resetb_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->power = ov5645_hw_power; ++ priv->reset = ov5645_hw_reset; ++ } ++ return 0; ++} ++ ++#include ++/* ++ * i2c_driver functions ++ */ ++static int ov5645_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov5645_priv *priv; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "ov5645: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct ov5645_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++ ++ /*mclk gate close*/ ++// *(volatile unsigned int *)0xb0000024 &= ~(1 << 5); ++ ++ ret = ov5645_probe_dt(client, priv); ++ if (ret) ++ goto err_probe_dt; ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &ov5645_subdev_ops); ++ ++ /* add handler */ ++ v4l2_ctrl_handler_init(&priv->hdl, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov5645_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov5645_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ priv->subdev.ctrl_handler = &priv->hdl; ++ if (priv->hdl.error) { ++ ret = priv->hdl.error; ++ goto err_hdl; ++ } ++ ++ ret = ov5645_video_probe(client); ++ if (ret < 0) ++ goto err_detect; ++ ++ ret = v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_async_register_subdev; ++ ++ dev_info(&adapter->dev, "ov5645 Probed\n"); ++ ++ return 0; ++ ++err_async_register_subdev: ++err_detect: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_hdl: ++ v4l2_device_unregister_subdev(&priv->subdev); ++err_probe_dt: ++ v4l2_clk_put(priv->clk); ++ devm_kfree(&client->dev, priv); ++ return ret; ++} ++ ++static int ov5645_remove(struct i2c_client *client) ++{ ++ struct ov5645_priv *priv = to_ov5645(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ devm_kfree(&client->dev, priv); ++ return 0; ++} ++ ++static const struct i2c_device_id ov5645_id[] = { ++ { "ov5645", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov5645_id); ++static const struct of_device_id ov5645_of_match[] = { ++ {.compatible = "ovti,ov5645", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov5645_of_match); ++static struct i2c_driver ov5645_i2c_driver = { ++ .driver = { ++ .name = "ov5645", ++ .of_match_table = of_match_ptr(ov5645_of_match), ++ }, ++ .probe = ov5645_probe, ++ .remove = ov5645_remove, ++ .id_table = ov5645_id, ++}; ++module_i2c_driver(ov5645_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for Omni Vision ov5645 sensor"); ++MODULE_AUTHOR("Alberto Panizzo"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/ov9281-dvp-snapshot.c b/module_drivers/drivers/media/i2c/ingenic-cim/ov9281-dvp-snapshot.c +new file mode 100644 +index 000000000..63335df05 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/ov9281-dvp-snapshot.c +@@ -0,0 +1,1223 @@ ++/* ++ * ov9281 Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define REG_CHIP_ID_HIGH 0x300a ++#define REG_CHIP_ID_LOW 0x300b ++#define CHIP_ID_HIGH 0x92 ++#define CHIP_ID_LOW 0x81 ++ ++#define OV9281_DEFAULT_WIDTH 1280 ++#define OV9281_DEFAULT_HEIGHT 720 ++/* #define OV9281_DEFAULT_WIDTH 640 */ ++/* #define OV9281_DEFAULT_HEIGHT 480 */ ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++#define REG_TC_VFLIP 0x3820 ++#define REG_TC_MIRROR 0x3821 ++#define OV9281_FLIP_VAL ((unsigned char)0x04) ++#define OV9281_FLIP_MASK ((unsigned char)0x04) ++ ++/* whether sensor support high resolution (> vga) preview or not */ ++#define SUPPORT_HIGH_RESOLUTION_PRE 1 ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ u16 reg_num; ++ u16 value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++/* Supported resolutions */ ++enum ov9281_width { ++ W_720P = OV9281_DEFAULT_WIDTH, ++ /* W_640 = OV9281_DEFAULT_WIDTH, */ ++}; ++ ++enum ov9281_height { ++ H_720P = OV9281_DEFAULT_HEIGHT, ++ /* H_480 = OV9281_DEFAULT_HEIGHT, */ ++}; ++ ++struct ov9281_win_size { ++ char *name; ++ enum ov9281_width width; ++ enum ov9281_height height; ++ const struct regval_list *regs; ++ unsigned int mbus_code; ++}; ++ ++struct ov9281_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct ov9281_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++ struct v4l2_subdev_platform_data *sd_pdata; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ ++ int (*power)(struct i2c_client *client, int on); ++ int (*reset)(struct i2c_client *client); ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++static inline int sensor_i2c_master_send(struct i2c_client *client, ++ const char *buf ,int count) ++{ ++ int ret; ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.len = count; ++ msg.buf = (char *)buf; ++ ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++static inline int sensor_i2c_master_recv(struct i2c_client *client, ++ char *buf ,int count) ++{ ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ int ret; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.flags |= I2C_M_RD; ++ msg.len = count; ++ msg.buf = buf; ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++ ++unsigned char ov9281_read_reg(struct i2c_client *client, u16 reg) ++{ ++ int ret; ++ unsigned char retval; ++ unsigned short r = cpu_to_be16(reg); ++ ++ ret = sensor_i2c_master_send(client,(u8 *)&r,2); ++ ++ if (ret < 0) ++ return ret; ++ if (ret != 2) ++ return -EIO; ++ ++ ret = sensor_i2c_master_recv(client, &retval, 1); ++ if (ret < 0) ++ return ret; ++ if (ret != 1) ++ return -EIO; ++ return retval; ++} ++ ++int ov9281_write_reg(struct i2c_client *client, u16 reg, u8 val) ++{ ++ unsigned char msg[3]; ++ int ret; ++ ++ reg = cpu_to_be16(reg); ++ ++ memcpy(&msg[0], ®, 2); ++ memcpy(&msg[2], &val, 1); ++ ++ ret = sensor_i2c_master_send(client, msg, 3); ++ ++ if (ret < 0) ++ { ++ printk("RET<0\n"); ++ return ret; ++ } ++ if (ret < 3) ++ { ++ printk("RET<3\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Registers settings ++ */ ++ ++#define ENDMARKER { 0xffff, 0xff } ++ ++static const struct regval_list ov9281_init_regs[] = { ++ { 0x0103, 0x01 }, ++ { 0x0302, 0x30 }, ++ { 0x030d, 0x60 }, ++ { 0x030e, 0x06 }, ++ { 0x3001, 0x62 }, ++ { 0x3004, 0x01 }, ++ { 0x3005, 0xff }, ++ ++ { 0x3667, 0xda }, //choose PWM pin for DVP vsync output ++ { 0x3006, 0xe6 }, //[2]1:enable output for PWM pin ; [1]0:enable input for FSIN pin ++ { 0x0100, 0x01 }, ++ ++ ++ { 0x3011, 0x0a }, ++ { 0x3013, 0x18 }, ++ { 0x3022, 0x07 }, ++ { 0x3030, 0x10 }, ++ { 0x3039, 0x2e }, ++ { 0x303a, 0xf0 }, ++ { 0x3500, 0x00 }, ++ { 0x3501, 0x2a }, ++ { 0x3502, 0x90 }, ++ { 0x3503, 0x08 }, ++ { 0x3505, 0x8c }, ++ { 0x3507, 0x03 }, ++ { 0x3508, 0x00 }, ++// { 0x3509, 0x40 }, ++ { 0x3509, 0x30 }, ++ { 0x3610, 0x80 }, ++ { 0x3611, 0xa0 }, ++ { 0x3620, 0x6f }, ++ { 0x3632, 0x56 }, ++ { 0x3633, 0x78 }, ++ { 0x3662, 0x03 }, ++ { 0x3666, 0x5a }, ++ { 0x366f, 0x7e }, ++ { 0x3680, 0x84 }, ++ { 0x3712, 0x80 }, ++ { 0x372d, 0x22 }, ++ { 0x3731, 0x80 }, ++ { 0x3732, 0x30 }, ++ { 0x3778, 0x00 }, ++ { 0x377d, 0x22 }, ++ { 0x3788, 0x02 }, ++ { 0x3789, 0xa4 }, ++ { 0x378a, 0x00 }, ++ { 0x378b, 0x4a }, ++ { 0x3799, 0x20 }, ++ { 0x3800, 0x00 }, ++ { 0x3801, 0x00 }, ++ { 0x3802, 0x00 }, ++ { 0x3803, 0x00 }, ++ { 0x3804, 0x05 }, ++ { 0x3805, 0x0f }, ++ { 0x3806, 0x03 }, ++ { 0x3807, 0x2f }, ++ { 0x3808, 0x05 }, ++ { 0x3809, 0x00 }, ++ { 0x380a, 0x02 }, ++ { 0x380b, 0xd0 }, ++ { 0x380c, 0x02 }, ++ { 0x380d, 0xd8 }, ++ { 0x380e, 0x03 }, ++ { 0x380f, 0x54 }, ++ { 0x3810, 0x00 }, ++ { 0x3811, 0x08 }, ++ { 0x3812, 0x00 }, ++ { 0x3813, 0x08 }, ++ { 0x3814, 0x11 }, ++ { 0x3815, 0x11 }, ++ { 0x3820, 0x40 }, ++ { 0x3821, 0x00 }, ++ { 0x3881, 0x42 }, ++ { 0x38b1, 0x00 }, ++ { 0x3920, 0xff }, ++ { 0x4003, 0x40 }, ++ { 0x4008, 0x04 }, ++ { 0x4009, 0x0b }, ++ { 0x400c, 0x00 }, ++ { 0x400d, 0x07 }, ++ { 0x4010, 0x40 }, ++ { 0x4043, 0x40 }, ++ { 0x4307, 0x30 }, ++ { 0x4317, 0x01 }, ++ { 0x4501, 0x00 }, ++ { 0x4507, 0x00 }, ++ { 0x4509, 0x00 }, ++ { 0x450a, 0x08 }, ++ { 0x4601, 0x04 }, ++ { 0x470f, 0xe0 }, ++ { 0x4f07, 0x00 }, ++ { 0x4800, 0x00 }, ++ { 0x5000, 0x9f }, ++ { 0x5001, 0x00 }, ++ { 0x5e00, 0x00 }, ++ { 0x5d00, 0x0b }, ++ { 0x5d01, 0x02 }, ++ ++ { 0x4f00, 0x01}, ++ { 0x0100, 0x00}, ++ ++ { 0x320c, 0x8f}, ++ { 0x302c, 0x00}, ++ { 0x302d, 0x00}, ++ { 0x302e, 0x00}, ++ { 0x302f, 0x02}, ++ { 0x303f, 0x01}, ++ { 0x3023, 0x07}, ++ { 0x4242, 0x00}, ++ ++// { 0x3030, 0x80}, ++// { 0x3030, 0x10}, ++// { 0x3030, 0x90}, ++ { 0x3030, 0x80}, ++ { 0x3030, 0x84}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_auto_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_incandescence_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_daylight_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_fluorescent_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_cloud_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov9281_balance[] = { ++ {0, ov9281_wb_auto_regs}, {1, ov9281_wb_incandescence_regs}, ++ {2, ov9281_wb_daylight_regs}, {3, ov9281_wb_fluorescent_regs}, ++ {4, ov9281_wb_cloud_regs}, ++}; ++ ++ ++static const struct regval_list ov9281_effect_normal_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_grayscale_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_sepia_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_colorinv_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_sepiabluel_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov9281_effect[] = { ++ {0, ov9281_effect_normal_regs}, {1, ov9281_effect_grayscale_regs}, ++ {2, ov9281_effect_sepia_regs}, {3, ov9281_effect_colorinv_regs}, ++ {4, ov9281_effect_sepiabluel_regs}, ++}; ++ ++static const struct regval_list ov9281_720p_regs[] = { ++ {0x4708, 0x0}, ++ {0x3808,0x05}, ++ {0x3809,0x00}, /* ISP Horizontal Output Width: 1280 */ ++ {0x380a,0x02}, ++ {0x380b,0xd0}, /* ISP Vertical Output Width : 720*/ ++ {0x380c,0x02}, ++ {0x380d,0xd8}, /* HTS: Horizontal Timing Size: 728 */ ++ {0x380e,0x03}, ++ {0x380f,0x8e}, /* VTS: Vertical Timing Size: 910 */ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_vga_regs[] = { ++ { 0x3808, 0x02 }, ++ { 0x3809, 0x80 }, ++ { 0x380a, 0x01 }, ++ { 0x380b, 0xe0 }, ++ { 0x380c, 0x02 }, ++ { 0x380d, 0xd8 }, ++ { 0x380e, 0x03 }, ++ { 0x380f, 0x54 }, ++ ENDMARKER, ++}; ++ ++#define OV9281_SIZE(n, w, h, r, c) \ ++ {.name = n, .width = w , .height = h, .regs = r, .mbus_code = c } ++ ++static struct ov9281_win_size ov9281_supported_win_sizes[] = { ++ OV9281_SIZE("720P", W_720P, H_720P, ov9281_720p_regs, MEDIA_BUS_FMT_Y8_1X8), ++ /* OV9281_SIZE("vga", W_640,H_480,ov9281_vga_regs), */ ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(ov9281_supported_win_sizes)) ++/* ++static u32 ov9281_codes[] = { ++ MEDIA_BUS_FMT_Y8_1X8, ++}; ++*/ ++/* ++ * Supported balance menus ++ */ ++static const struct v4l2_querymenu ov9281_balance_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 0, ++ .name = "auto", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 1, ++ .name = "incandescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 2, ++ .name = "fluorescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 3, ++ .name = "daylight", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 4, ++ .name = "cloudy-daylight", ++ }, ++ ++}; ++ ++/* ++ * Supported effect menus ++ */ ++static const struct v4l2_querymenu ov9281_effect_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 0, ++ .name = "none", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 1, ++ .name = "mono", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 2, ++ .name = "sepia", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 3, ++ .name = "negative", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 4, ++ .name = "aqua", ++ }, ++}; ++ ++ ++/* ++ * General functions ++ */ ++static struct ov9281_priv *to_ov9281(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov9281_priv, ++ subdev); ++} ++ ++static int ov9281_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while ((vals->reg_num != 0xffff) || (vals->value != 0xff)) { ++ ret = ov9281_write_reg(client, vals->reg_num, vals->value); ++ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", ++ vals->reg_num, vals->value); ++ ++ if (ret < 0) ++ return ret; ++ vals++; ++ } ++ return 0; ++} ++#if 1 ++static int ov9281_mask_set(struct i2c_client *client, ++ u16 reg, u16 mask, u16 set) ++{ ++ s32 val = ov9281_read_reg(client, reg); ++ if (val < 0) ++ return val; ++ ++ val &= ~mask; ++ val |= set & mask; ++ ++ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); ++ ++ return ov9281_write_reg(client, reg, val); ++} ++#endif ++ ++/* OF probe functions */ ++static int ov9281_hw_power(struct i2c_client *client, int on) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int ov9281_reset(struct i2c_client *client) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if(priv->resetb_gpio) { ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ msleep(10); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ msleep(10); ++ } ++ ++ return 0; ++} ++ ++static int ov9281_g_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov9281_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VFLIP: ++ ctrl->val = priv->flag_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->val = priv->flag_hflip; ++ break; ++ case V4L2_CID_PRIVATE_BALANCE: ++ ctrl->val = priv->balance_value; ++ break; ++ case V4L2_CID_PRIVATE_EFFECT: ++ ctrl->val = priv->effect_value; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int ov9281_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov9281_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ int ret = 0; ++ int i = 0; ++ u16 value; ++ ++ int balance_count = ARRAY_SIZE(ov9281_balance); ++ int effect_count = ARRAY_SIZE(ov9281_effect); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ if(ctrl->val > balance_count) ++ return -EINVAL; ++ ++ for(i = 0; i < balance_count; i++) { ++ if(ctrl->val == ov9281_balance[i].index) { ++ ret = ov9281_write_array(client, ++ ov9281_balance[ctrl->val].mode_regs); ++ priv->balance_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ if(ctrl->val > effect_count) ++ return -EINVAL; ++ ++ for(i = 0; i < effect_count; i++) { ++ if(ctrl->val == ov9281_effect[i].index) { ++ ret = ov9281_write_array(client, ++ ov9281_effect[ctrl->val].mode_regs); ++ priv->effect_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_VFLIP: ++ value = ctrl->val ? OV9281_FLIP_VAL : 0x00; ++ priv->flag_vflip = ctrl->val ? 1 : 0; ++ ret = ov9281_mask_set(client, REG_TC_VFLIP, OV9281_FLIP_MASK, value); ++ break; ++ ++ case V4L2_CID_HFLIP: ++ value = ctrl->val ? OV9281_FLIP_VAL : 0x00; ++ priv->flag_hflip = ctrl->val ? 1 : 0; ++ ret = ov9281_mask_set(client, REG_TC_MIRROR, OV9281_FLIP_MASK, value); ++ break; ++ ++ default: ++ dev_err(&client->dev, "no V4L2 CID: 0x%x ", ctrl->id); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ov9281_ctrl_ops = { ++ .s_ctrl = ov9281_s_ctrl, ++ .g_volatile_ctrl = ov9281_g_ctrl, ++}; ++#if 0 ++static int ov9281_querymenu(struct v4l2_subdev *sd, ++ struct v4l2_querymenu *qm) ++{ ++ switch (qm->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ memcpy(qm->name, ov9281_balance_menus[qm->index].name, ++ sizeof(qm->name)); ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ memcpy(qm->name, ov9281_effect_menus[qm->index].name, ++ sizeof(qm->name)); ++ break; ++ } ++ ++ return 0; ++} ++#endif ++ ++static int ov9281_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if(priv->sd_pdata) { ++ if(on) ++ return regulator_bulk_enable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ else ++ return regulator_bulk_disable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ } else if(priv->power) { ++ return priv->power(client, on); ++ } else { ++ dev_err(&client->dev, "ov9281_s_power failde"); ++ return -EINVAL; ++ } ++ ++// return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov9281_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg > 0xff) ++ return -EINVAL; ++ ++ ret = ov9281_read_reg(client, reg->reg); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = ret; ++ ++ return 0; ++} ++ ++static int ov9281_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg > 0xff || ++ reg->val > 0xff) ++ return -EINVAL; ++ ++ return ov9281_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++/* ++ * soc_camera_ops functions ++ */ ++static int ov9281_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!enable ) { ++ dev_info(&client->dev, "stream down\n"); ++ ov9281_write_reg(client, 0x0100, 0x00); ++ return 0; ++ } ++ ++ dev_info(&client->dev, "stream on\n"); ++ ov9281_write_reg(client, 0x0100, 0x01); ++ ++ return 0; ++} ++ ++/* Select the nearest higher resolution for capture */ ++static const struct ov9281_win_size *ov9281_select_win(u32 *code, u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(ov9281_supported_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(ov9281_supported_win_sizes); i++) { ++ if ((*width >= ov9281_supported_win_sizes[i].width) && ++ (*height >= ov9281_supported_win_sizes[i].height) && ++ (*code == ov9281_supported_win_sizes[i].mbus_code)) { ++ *width = ov9281_supported_win_sizes[i].width; ++ *height = ov9281_supported_win_sizes[i].height; ++ return &ov9281_supported_win_sizes[i]; ++ } ++ } ++ return NULL; ++} ++ ++static int ov9281_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if(!priv->win) ++ return -EINVAL; ++ ++ sel->r.top = 0; ++ sel->r.left = 0; ++ sel->r.width = priv->win->width; ++ sel->r.height = priv->win->height; ++ ++ return 0; ++} ++ ++static int ov9281_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ if(priv->win) { ++ mf->width = priv->win->width; ++ mf->height = priv->win->height; ++ } else { ++ mf->width = OV9281_DEFAULT_WIDTH; ++ mf->height = OV9281_DEFAULT_HEIGHT; ++ } ++ mf->code = priv->cfmt_code; ++ ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov9281_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* select win */ ++ priv->win = ov9281_select_win(&code, width, height); ++ ++ /* select format */ ++ priv->cfmt_code = 0; ++ ++ /* reset hardware */ ++ ov9281_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ret = ov9281_write_array(client, ov9281_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = ov9281_write_array(client, ov9281_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = ov9281_write_array(client, ov9281_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set size win */ ++ ret = ov9281_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ ov9281_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int ov9281_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ /* ++ * select suitable win, but don't store it ++ */ ++ priv->win = ov9281_select_win(&mf->code, &mf->width, &mf->height); ++ if(!priv->win) ++ return -EINVAL; ++ ++ mf->field = V4L2_FIELD_NONE; ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ ov9281_set_params(client, &mf->width, ++ &mf->height, mf->code); ++ if(cfg) ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int ov9281_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= ARRAY_SIZE(ov9281_supported_win_sizes)) ++ return -EINVAL; ++ ++ code->code = ov9281_supported_win_sizes[code->index].mbus_code; ++ return 0; ++} ++ ++static int ov9281_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int i, j; ++ int num_valid = -1; ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++#if 0 ++ j = ARRAY_SIZE(ov9281_codes); ++ while(--j) ++ if(fse->code == ov9281_codes[j]) ++ break; ++ for (i = 0; i < N_WIN_SIZES; i++) { ++ if (index == ++num_valid) { ++ fse->code = ov9281_codes[j]; ++ fse->min_width = ov9281_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = ov9281_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++#endif ++ fse->code = ov9281_supported_win_sizes[index].mbus_code; ++ fse->min_width = ov9281_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = ov9281_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++} ++#if 0 ++static int ov9281_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ++{ ++ a->c.left = 0; ++ a->c.top = 0; ++ a->c.width = OV9281_DEFAULT_WIDTH; ++ a->c.height = OV9281_DEFAULT_HEIGHT; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ++ return 0; ++} ++ ++static int ov9281_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) ++{ ++ a->bounds.left = 0; ++ a->bounds.top = 0; ++ a->bounds.width = OV9281_DEFAULT_WIDTH; ++ a->bounds.height = OV9281_DEFAULT_HEIGHT; ++ a->defrect = a->bounds; ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ a->pixelaspect.numerator = 1; ++ a->pixelaspect.denominator = 1; ++ ++ return 0; ++} ++#endif ++static int ov9281_video_probe(struct i2c_client *client) ++{ ++ unsigned char retval_high = 0, retval_low = 0; ++ struct ov9281_priv *priv = to_ov9281(client); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ int ret; ++ ++ ret = ov9281_s_power(&priv->subdev, 1); ++ if (ret < 0) ++ return ret; ++ /* ++ * check and show product ID and manufacturer ID ++ */ ++ ++ retval_high = ov9281_read_reg(client, REG_CHIP_ID_HIGH); ++ if (retval_high != CHIP_ID_HIGH) { ++ dev_err(&client->dev, "read sensor %s chip_id high %x is error\n", ++ client->name, retval_high); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ ++ retval_low = ov9281_read_reg(client, REG_CHIP_ID_LOW); ++ if (retval_low != CHIP_ID_LOW) { ++ dev_err(&client->dev, "read sensor %s chip_id low %x is error\n", ++ client->name, retval_low); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ dev_info(&client->dev, "read sensor %s id high:0x%x,low:%x successed!\n", ++ client->name, retval_high, retval_low); ++ ++ ret = v4l2_ctrl_handler_setup(&priv->hdl); ++ ++done: ++// ov9281_s_power(&priv->subdev, 0); ++ return ret; ++} ++ ++static int ov9281_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++/* ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); ++ ++ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | ++ V4L2_MBUS_VSYNC_ACTIVE_LOW | V4L2_MBUS_HSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_DATA_ACTIVE_HIGH; ++ cfg->type = V4L2_MBUS_PARALLEL; ++ ++ cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); ++*/ ++ /*int dts*/ ++ return 0; ++} ++ ++static struct v4l2_subdev_core_ops ov9281_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov9281_g_register, ++ .s_register = ov9281_s_register, ++#endif ++ .s_power = ov9281_s_power, ++ //.querymenu = ov9281_querymenu, ++}; ++ ++static struct v4l2_subdev_video_ops ov9281_subdev_video_ops = { ++ .s_stream = ov9281_s_stream, ++// .cropcap = ov9281_cropcap, ++// .g_crop = ov9281_g_crop, ++// .g_mbus_config = ov9281_g_mbus_config, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov9281_subdev_pad_ops = { ++ .enum_mbus_code = ov9281_enum_mbus_code, ++ .enum_frame_size = ov9281_enum_frame_size, ++ .get_fmt = ov9281_get_fmt, ++ .set_fmt = ov9281_set_fmt, ++ .get_mbus_config = ov9281_g_mbus_config, ++ .get_selection = ov9281_get_selection, ++}; ++ ++static struct v4l2_subdev_ops ov9281_subdev_ops = { ++ .core = &ov9281_subdev_core_ops, ++ .video = &ov9281_subdev_video_ops, ++ .pad = &ov9281_subdev_pad_ops, ++}; ++ ++static int ov9281_hw_reset(struct i2c_client *client) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if (priv->resetb_gpio) { ++ /* Active the resetb pin to perform a reset pulse */ ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ usleep_range(3000, 5000); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ } ++ ++ return 0; ++} ++ ++ ++static int ov9281_probe_dt(struct i2c_client *client, ++ struct ov9281_priv *priv) ++{ ++ struct v4l2_subdev_platform_data *sd_pdata = priv->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies > 0) { ++ sd_pdata = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev_platform_data), GFP_KERNEL); ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ devm_kfree(&client->dev,sd_pdata); ++ return -ENOMEM; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ devm_regulator_bulk_get(&client->dev, sd_pdata->num_regulators, sd_pdata->regulators); ++// soc_camera_power_init(&client->dev, ssdd_dt); ++ } else { ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->power = ov9281_hw_power; ++ priv->reset = ov9281_hw_reset; ++ } ++ return 0; ++} ++ ++#include ++/* ++ * i2c_driver functions ++ */ ++static int ov9281_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov9281_priv *priv; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "ov9281: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct ov9281_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++/** ++ if (!ssdd && !client->dev.of_node) { ++ dev_err(&client->dev, "Missing platform_data for driver\n"); ++ ret = -EINVAL; ++ goto err_videoprobe; ++ } ++ ++ if (!ssdd) { ++ ret = ov9281_probe_dt(client, priv); ++ if (ret) ++ goto err_clk; ++ } ++*/ ++ ret = ov9281_probe_dt(client, priv); ++ if (ret) ++ goto err_probe_dt; ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &ov9281_subdev_ops); ++ ++ /* add handler */ ++ v4l2_ctrl_handler_init(&priv->hdl, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov9281_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov9281_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ priv->subdev.ctrl_handler = &priv->hdl; ++ if (priv->hdl.error) { ++ ret = priv->hdl.error; ++ goto err_hdl; ++ } ++ ++ ret = ov9281_video_probe(client); ++ if (ret < 0) ++ goto err_detect; ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_async_register_subdev; ++ ++ dev_info(&adapter->dev, "ov9281 DVP snapshot Probed\n"); ++ ++ return 0; ++ ++err_async_register_subdev: ++err_detect: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_hdl: ++ v4l2_device_unregister_subdev(&priv->subdev); ++err_probe_dt: ++ v4l2_clk_put(priv->clk); ++ devm_kfree(&client->dev, priv); ++ return ret; ++} ++ ++static int ov9281_remove(struct i2c_client *client) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ devm_kfree(&client->dev, priv); ++ return 0; ++} ++ ++static const struct i2c_device_id ov9281_id[] = { ++ { "ov9281", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov9281_id); ++static const struct of_device_id ov9281_of_match[] = { ++ {.compatible = "ovti,ov9281", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov9281_of_match); ++static struct i2c_driver ov9281_i2c_driver = { ++ .driver = { ++ .name = "ov9281", ++ .of_match_table = of_match_ptr(ov9281_of_match), ++ }, ++ .probe = ov9281_probe, ++ .remove = ov9281_remove, ++ .id_table = ov9281_id, ++}; ++module_i2c_driver(ov9281_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for Omni Vision ov9281 sensor"); ++MODULE_AUTHOR("Alberto Panizzo"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/ov9281.c b/module_drivers/drivers/media/i2c/ingenic-cim/ov9281.c +new file mode 100644 +index 000000000..cf69ea8fa +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/ov9281.c +@@ -0,0 +1,1068 @@ ++/* ++ * ov9281 Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define REG_CHIP_ID_HIGH 0x300a ++#define REG_CHIP_ID_LOW 0x300b ++#define CHIP_ID_HIGH 0x92 ++#define CHIP_ID_LOW 0x81 ++ ++#define OV9281_DEFAULT_WIDTH 1280 ++#define OV9281_DEFAULT_HEIGHT 720 ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++#define REG_TC_VFLIP 0x3820 ++#define REG_TC_MIRROR 0x3821 ++#define OV9281_FLIP_VAL ((unsigned char)0x04) ++#define OV9281_FLIP_MASK ((unsigned char)0x04) ++ ++/* whether sensor support high resolution (> vga) preview or not */ ++#define SUPPORT_HIGH_RESOLUTION_PRE 1 ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ u16 reg_num; ++ u16 value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++/* Supported resolutions */ ++enum ov9281_width { ++ W_720P = OV9281_DEFAULT_WIDTH, ++}; ++ ++enum ov9281_height { ++ H_720P = OV9281_DEFAULT_HEIGHT, ++}; ++ ++struct ov9281_win_size { ++ char *name; ++ enum ov9281_width width; ++ enum ov9281_height height; ++ const struct regval_list *regs; ++ unsigned int mbus_code; ++}; ++ ++struct ov9281_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct ov9281_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++ struct v4l2_subdev_platform_data *sd_pdata; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ ++ int (*power)(struct i2c_client *client, int on); ++ int (*reset)(struct i2c_client *client); ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++static inline int sensor_i2c_master_send(struct i2c_client *client, ++ const char *buf ,int count) ++{ ++ int ret; ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.len = count; ++ msg.buf = (char *)buf; ++ ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++static inline int sensor_i2c_master_recv(struct i2c_client *client, ++ char *buf ,int count) ++{ ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ int ret; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.flags |= I2C_M_RD; ++ msg.len = count; ++ msg.buf = buf; ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++ ++unsigned char ov9281_read_reg(struct i2c_client *client, u16 reg) ++{ ++ int ret; ++ unsigned char retval; ++ unsigned short r = cpu_to_be16(reg); ++ ++ ret = sensor_i2c_master_send(client,(u8 *)&r,2); ++ ++ if (ret < 0) ++ return ret; ++ if (ret != 2) ++ return -EIO; ++ ++ ret = sensor_i2c_master_recv(client, &retval, 1); ++ if (ret < 0) ++ return ret; ++ if (ret != 1) ++ return -EIO; ++ return retval; ++} ++ ++int ov9281_write_reg(struct i2c_client *client, u16 reg, u8 val) ++{ ++ unsigned char msg[3]; ++ int ret; ++ ++ reg = cpu_to_be16(reg); ++ ++ memcpy(&msg[0], ®, 2); ++ memcpy(&msg[2], &val, 1); ++ ++ ret = sensor_i2c_master_send(client, msg, 3); ++ ++ if (ret < 0) ++ { ++ printk("RET<0\n"); ++ return ret; ++ } ++ if (ret < 3) ++ { ++ printk("RET<3\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Registers settings ++ */ ++ ++#define ENDMARKER { 0xffff, 0xff } ++ ++static const struct regval_list ov9281_init_regs[] = { ++ { 0x0103, 0x01}, ++ { 0x0302, 0x32}, ++ { 0x030d, 0x50}, ++ { 0x030e, 0x02}, ++ { 0x3001, 0x00}, ++ { 0x3004, 0x00}, ++ { 0x3005, 0x00}, ++ { 0x3006, 0x04}, ++ { 0x3011, 0x0a}, ++ { 0x3013, 0x18}, ++ { 0x3022, 0x01}, ++ { 0x3030, 0x10}, ++ { 0x3039, 0x32}, ++ { 0x303a, 0x00}, ++ { 0x3500, 0x00}, ++ { 0x3501, 0x2a}, ++ { 0x3502, 0x90}, ++ { 0x3503, 0x08}, ++ { 0x3505, 0x8c}, ++ { 0x3507, 0x03}, ++ { 0x3508, 0x00}, ++ { 0x3509, 0x10}, ++ { 0x3610, 0x80}, ++ { 0x3611, 0xa0}, ++ { 0x3620, 0x6f}, ++ { 0x3632, 0x56}, ++ { 0x3633, 0x78}, ++ { 0x3662, 0x03}, /* 1 lane raw8 */ ++ { 0x3666, 0x00}, ++ { 0x366f, 0x5a}, ++ { 0x3680, 0x84}, ++ { 0x3712, 0x80}, ++ { 0x372d, 0x22}, ++ { 0x3731, 0x80}, ++ { 0x3732, 0x30}, ++ { 0x3778, 0x00}, ++ { 0x377d, 0x22}, ++ { 0x3788, 0x02}, ++ { 0x3789, 0xa4}, ++ { 0x378a, 0x00}, ++ { 0x378b, 0x4a}, ++ { 0x3799, 0x20}, ++ { 0x3800, 0x00}, ++ { 0x3801, 0x00}, ++ { 0x3802, 0x00}, ++ { 0x3803, 0x00}, ++ { 0x3804, 0x05}, ++ { 0x3805, 0x0f}, ++ { 0x3806, 0x03}, ++ { 0x3807, 0x2f}, ++ { 0x3808, 0x05}, ++ { 0x3809, 0x00}, ++ { 0x380a, 0x02}, ++ { 0x380b, 0xd0}, ++#if 0 /* 30 fps */ ++ { 0x380c, 0x05}, /* hsync */ ++ { 0x380d, 0xd8}, ++ { 0x380e, 0x06}, /* vsync */ ++ { 0x380f, 0x8e}, ++#endif ++#if 1 /* 45 fps */ ++ { 0x380c, 0x05}, /* hsync */ ++ { 0x380d, 0xd8}, ++ { 0x380e, 0x04}, /* vsync */ ++ { 0x380f, 0x8e}, ++#endif ++#if 0 /* 60 fps */ ++ { 0x380c, 0x04}, /* hsync */ ++ { 0x380d, 0xd8}, ++ { 0x380e, 0x03}, /* vsync */ ++ { 0x380f, 0x8e}, ++#endif ++ { 0x3810, 0x00}, ++ { 0x3811, 0x08}, ++ { 0x3812, 0x00}, ++ { 0x3813, 0x08}, ++ { 0x3814, 0x11}, ++ { 0x3815, 0x11}, ++ { 0x3820, 0x40}, ++ { 0x3821, 0x00}, ++ { 0x3881, 0x42}, ++ { 0x38b1, 0x00}, ++ { 0x3920, 0xff}, ++ { 0x4003, 0x40}, ++ { 0x4008, 0x04}, ++ { 0x4009, 0x0b}, ++ { 0x400c, 0x00}, ++ { 0x400d, 0x07}, ++ { 0x4010, 0x40}, ++ { 0x4043, 0x40}, ++ { 0x4307, 0x30}, ++ { 0x4317, 0x00}, ++ { 0x4501, 0x00}, ++ { 0x4507, 0x00}, ++ { 0x4509, 0x00}, ++ { 0x450a, 0x08}, ++ { 0x4601, 0x04}, ++ { 0x470f, 0x00}, ++ { 0x4f07, 0x00}, ++ { 0x4800, 0x00}, ++ { 0x5000, 0x9f}, ++ { 0x5001, 0x00}, ++ { 0x5e00, 0x00}, ++ { 0x5d00, 0x07}, ++ { 0x5d01, 0x00}, ++// { 0x0100, 0x00}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_auto_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_incandescence_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_daylight_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_fluorescent_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_wb_cloud_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov9281_balance[] = { ++ {0, ov9281_wb_auto_regs}, {1, ov9281_wb_incandescence_regs}, ++ {2, ov9281_wb_daylight_regs}, {3, ov9281_wb_fluorescent_regs}, ++ {4, ov9281_wb_cloud_regs}, ++}; ++ ++ ++static const struct regval_list ov9281_effect_normal_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_grayscale_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_sepia_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_colorinv_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list ov9281_effect_sepiabluel_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list ov9281_effect[] = { ++ {0, ov9281_effect_normal_regs}, {1, ov9281_effect_grayscale_regs}, ++ {2, ov9281_effect_sepia_regs}, {3, ov9281_effect_colorinv_regs}, ++ {4, ov9281_effect_sepiabluel_regs}, ++}; ++ ++static const struct regval_list ov9281_720p_regs[] = { ++ ENDMARKER, ++}; ++ ++#define OV9281_SIZE(n, w, h, r, c) \ ++ {.name = n, .width = w , .height = h, .regs = r, .mbus_code = c } ++ ++static struct ov9281_win_size ov9281_supported_win_sizes[] = { ++ OV9281_SIZE("720P", W_720P, H_720P, ov9281_720p_regs, MEDIA_BUS_FMT_Y8_1X8), ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(ov9281_supported_win_sizes)) ++ ++/* ++ * Supported balance menus ++ */ ++static const struct v4l2_querymenu ov9281_balance_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 0, ++ .name = "auto", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 1, ++ .name = "incandescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 2, ++ .name = "fluorescent", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 3, ++ .name = "daylight", ++ }, { ++ .id = V4L2_CID_PRIVATE_BALANCE, ++ .index = 4, ++ .name = "cloudy-daylight", ++ }, ++ ++}; ++ ++/* ++ * Supported effect menus ++ */ ++static const struct v4l2_querymenu ov9281_effect_menus[] = { ++ { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 0, ++ .name = "none", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 1, ++ .name = "mono", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 2, ++ .name = "sepia", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 3, ++ .name = "negative", ++ }, { ++ .id = V4L2_CID_PRIVATE_EFFECT, ++ .index = 4, ++ .name = "aqua", ++ }, ++}; ++ ++ ++/* ++ * General functions ++ */ ++static struct ov9281_priv *to_ov9281(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov9281_priv, ++ subdev); ++} ++ ++static int ov9281_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while ((vals->reg_num != 0xffff) || (vals->value != 0xff)) { ++ ret = ov9281_write_reg(client, vals->reg_num, vals->value); ++ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", ++ vals->reg_num, vals->value); ++ ++ if (ret < 0) ++ return ret; ++ vals++; ++ } ++ return 0; ++} ++ ++static int ov9281_mask_set(struct i2c_client *client, ++ u16 reg, u16 mask, u16 set) ++{ ++ s32 val = ov9281_read_reg(client, reg); ++ if (val < 0) ++ return val; ++ ++ val &= ~mask; ++ val |= set & mask; ++ ++ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); ++ ++ return ov9281_write_reg(client, reg, val); ++} ++ ++/* OF probe functions */ ++static int ov9281_hw_power(struct i2c_client *client, int on) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int ov9281_reset(struct i2c_client *client) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if(priv->resetb_gpio) { ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ msleep(10); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ msleep(10); ++ } ++ ++ return 0; ++} ++ ++static int ov9281_g_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov9281_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_VFLIP: ++ ctrl->val = priv->flag_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->val = priv->flag_hflip; ++ break; ++ case V4L2_CID_PRIVATE_BALANCE: ++ ctrl->val = priv->balance_value; ++ break; ++ case V4L2_CID_PRIVATE_EFFECT: ++ ctrl->val = priv->effect_value; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static int ov9281_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = ++ &container_of(ctrl->handler, struct ov9281_priv, hdl)->subdev; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ int ret = 0; ++ int i = 0; ++ u16 value; ++ ++ int balance_count = ARRAY_SIZE(ov9281_balance); ++ int effect_count = ARRAY_SIZE(ov9281_effect); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_PRIVATE_BALANCE: ++ if(ctrl->val > balance_count) ++ return -EINVAL; ++ ++ for(i = 0; i < balance_count; i++) { ++ if(ctrl->val == ov9281_balance[i].index) { ++ ret = ov9281_write_array(client, ++ ov9281_balance[ctrl->val].mode_regs); ++ priv->balance_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_PRIVATE_EFFECT: ++ if(ctrl->val > effect_count) ++ return -EINVAL; ++ ++ for(i = 0; i < effect_count; i++) { ++ if(ctrl->val == ov9281_effect[i].index) { ++ ret = ov9281_write_array(client, ++ ov9281_effect[ctrl->val].mode_regs); ++ priv->effect_value = ctrl->val; ++ break; ++ } ++ } ++ break; ++ ++ case V4L2_CID_VFLIP: ++ value = ctrl->val ? OV9281_FLIP_VAL : 0x00; ++ priv->flag_vflip = ctrl->val ? 1 : 0; ++ ret = ov9281_mask_set(client, REG_TC_VFLIP, OV9281_FLIP_MASK, value); ++ break; ++ ++ case V4L2_CID_HFLIP: ++ value = ctrl->val ? OV9281_FLIP_VAL : 0x00; ++ priv->flag_hflip = ctrl->val ? 1 : 0; ++ ret = ov9281_mask_set(client, REG_TC_MIRROR, OV9281_FLIP_MASK, value); ++ break; ++ ++ default: ++ dev_err(&client->dev, "no V4L2 CID: 0x%x ", ctrl->id); ++ return -EINVAL; ++ } ++ return ret; ++} ++ ++static const struct v4l2_ctrl_ops ov9281_ctrl_ops = { ++ .s_ctrl = ov9281_s_ctrl, ++ .g_volatile_ctrl = ov9281_g_ctrl, ++}; ++ ++static int ov9281_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if(priv->sd_pdata) { ++ if(on) ++ return regulator_bulk_enable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ else ++ return regulator_bulk_disable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ } else if(priv->power){ ++ return priv->power(client, on); ++ } else { ++ dev_err(&client->dev, "ov9281_s_power failde"); ++ return -EINVAL; ++ } ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov9281_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg > 0xff) ++ return -EINVAL; ++ ++ ret = ov9281_read_reg(client, reg->reg); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = ret; ++ ++ return 0; ++} ++ ++static int ov9281_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg > 0xff || ++ reg->val > 0xff) ++ return -EINVAL; ++ ++ return ov9281_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++/* ++ * soc_camera_ops functions ++ */ ++static int ov9281_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!enable ) { ++ dev_info(&client->dev, "stream down\n"); ++ ov9281_write_reg(client, 0x0100, 0x00); ++ return 0; ++ } ++ ++ dev_info(&client->dev, "stream on\n"); ++ ov9281_write_reg(client, 0x0100, 0x01); ++ ++ return 0; ++} ++ ++/* Select the nearest higher resolution for capture */ ++static const struct ov9281_win_size *ov9281_select_win(u32 *code, u32 *width, u32 *height) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ov9281_supported_win_sizes); i++) { ++ if ((*width >= ov9281_supported_win_sizes[i].width) && ++ (*height >= ov9281_supported_win_sizes[i].height) && ++ (*code == ov9281_supported_win_sizes[i].mbus_code)) { ++ *width = ov9281_supported_win_sizes[i].width; ++ *height = ov9281_supported_win_sizes[i].height; ++ return &ov9281_supported_win_sizes[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int ov9281_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ if(priv->win) { ++ mf->width = priv->win->width; ++ mf->height = priv->win->height; ++ } else { ++ mf->width = OV9281_DEFAULT_WIDTH; ++ mf->height = OV9281_DEFAULT_HEIGHT; ++ } ++ mf->code = priv->cfmt_code; ++ ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int ov9281_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* select win */ ++ priv->win = ov9281_select_win(&code, width, height); ++ ++ /* select format */ ++ priv->cfmt_code = 0; ++ ++ /* reset hardware */ ++ ov9281_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ret = ov9281_write_array(client, ov9281_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = ov9281_write_array(client, ov9281_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = ov9281_write_array(client, ov9281_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set size win */ ++ ret = ov9281_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ ov9281_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int ov9281_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ /* ++ * select suitable win, but don't store it ++ */ ++ priv->win = ov9281_select_win(&mf->code, &mf->width, &mf->height); ++ if(!priv->win) ++ return -EINVAL; ++ ++ mf->field = V4L2_FIELD_NONE; ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ ov9281_set_params(client, &mf->width, ++ &mf->height, mf->code); ++ if(cfg) ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int ov9281_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= ARRAY_SIZE(ov9281_supported_win_sizes)) ++ return -EINVAL; ++ ++ code->code = ov9281_supported_win_sizes[code->index].mbus_code; ++ return 0; ++} ++ ++static int ov9281_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++ fse->code = ov9281_supported_win_sizes[index].mbus_code; ++ fse->min_width = ov9281_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = ov9281_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++ ++} ++ ++static int ov9281_video_probe(struct i2c_client *client) ++{ ++ unsigned char retval_high = 0, retval_low = 0; ++ struct ov9281_priv *priv = to_ov9281(client); ++ int ret; ++ ++ ret = ov9281_s_power(&priv->subdev, 1); ++ if (ret < 0) ++ return ret; ++ /* ++ * check and show product ID and manufacturer ID ++ */ ++ retval_high = ov9281_read_reg(client, REG_CHIP_ID_HIGH); ++ if (retval_high != CHIP_ID_HIGH) { ++ dev_err(&client->dev, "read sensor %s chip_id high %x is error\n", ++ client->name, retval_high); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ ++ retval_low = ov9281_read_reg(client, REG_CHIP_ID_LOW); ++ if (retval_low != CHIP_ID_LOW) { ++ dev_err(&client->dev, "read sensor %s chip_id low %x is error\n", ++ client->name, retval_low); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ dev_info(&client->dev, "read sensor %s id high:0x%x,low:%x successed!\n", ++ client->name, retval_high, retval_low); ++ ++done: ++ return ret; ++} ++ ++static int ov9281_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++ /*int dts*/ ++ return 0; ++} ++ ++static struct v4l2_subdev_core_ops ov9281_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov9281_g_register, ++ .s_register = ov9281_s_register, ++#endif ++ .s_power = ov9281_s_power, ++}; ++ ++static struct v4l2_subdev_video_ops ov9281_subdev_video_ops = { ++ .s_stream = ov9281_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov9281_subdev_pad_ops = { ++ .enum_mbus_code = ov9281_enum_mbus_code, ++ .enum_frame_size = ov9281_enum_frame_size, ++ .get_fmt = ov9281_get_fmt, ++ .set_fmt = ov9281_set_fmt, ++ .get_mbus_config = ov9281_g_mbus_config, ++}; ++ ++static struct v4l2_subdev_ops ov9281_subdev_ops = { ++ .core = &ov9281_subdev_core_ops, ++ .video = &ov9281_subdev_video_ops, ++ .pad = &ov9281_subdev_pad_ops, ++}; ++ ++static int ov9281_hw_reset(struct i2c_client *client) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ if (priv->resetb_gpio) { ++ /* Active the resetb pin to perform a reset pulse */ ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ usleep_range(3000, 5000); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ } ++ ++ return 0; ++} ++ ++static int ov9281_probe_dt(struct i2c_client *client, ++ struct ov9281_priv *priv) ++{ ++ ++ struct v4l2_subdev_platform_data *sd_pdata = priv->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies > 0) { ++ sd_pdata = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev_platform_data), GFP_KERNEL); ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ devm_kfree(&client->dev,sd_pdata); ++ return -ENOMEM; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ devm_regulator_bulk_get(&client->dev, sd_pdata->num_regulators, sd_pdata->regulators); ++ ++ } else { ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->power = ov9281_hw_power; ++ priv->reset = ov9281_hw_reset; ++ } ++ return 0; ++} ++ ++#include ++/* ++ * i2c_driver functions ++ */ ++static int ov9281_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov9281_priv *priv; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "ov9281: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct ov9281_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++ ++ ret = ov9281_probe_dt(client, priv); ++ if (ret) ++ goto err_probe_dt; ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &ov9281_subdev_ops); ++ ++ /* add handler */ ++ v4l2_ctrl_handler_init(&priv->hdl, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov9281_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov9281_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ priv->subdev.ctrl_handler = &priv->hdl; ++ if (priv->hdl.error) { ++ ret = priv->hdl.error; ++ goto err_hdl; ++ } ++ ++ ret = ov9281_video_probe(client); ++ if (ret < 0) ++ goto err_detect; ++ ++ ret = v4l2_ctrl_handler_setup(&priv->hdl); ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_async_register_subdev; ++ ++ dev_info(&adapter->dev, "ov9281 Probed\n"); ++ ++ return 0; ++ ++err_async_register_subdev: ++err_detect: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_hdl: ++ v4l2_device_unregister_subdev(&priv->subdev); ++err_probe_dt: ++ v4l2_clk_put(priv->clk); ++ devm_kfree(&client->dev, priv); ++ return ret; ++} ++ ++static int ov9281_remove(struct i2c_client *client) ++{ ++ struct ov9281_priv *priv = to_ov9281(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ devm_kfree(&client->dev, priv); ++ return 0; ++} ++ ++static const struct i2c_device_id ov9281_id[] = { ++ { "ov9281", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov9281_id); ++static const struct of_device_id ov9281_of_match[] = { ++ {.compatible = "ovti,ov9281", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov9281_of_match); ++static struct i2c_driver ov9281_i2c_driver = { ++ .driver = { ++ .name = "ov9281", ++ .of_match_table = of_match_ptr(ov9281_of_match), ++ }, ++ .probe = ov9281_probe, ++ .remove = ov9281_remove, ++ .id_table = ov9281_id, ++}; ++module_i2c_driver(ov9281_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for Omni Vision ov9281 sensor"); ++MODULE_AUTHOR("Alberto Panizzo"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/sc031gs-mipi.c b/module_drivers/drivers/media/i2c/ingenic-cim/sc031gs-mipi.c +new file mode 100644 +index 000000000..35cabb31f +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/sc031gs-mipi.c +@@ -0,0 +1,919 @@ ++/* ++ * sc031gs Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define REG_CHIP_ID_HIGH 0x3107 ++#define REG_CHIP_ID_LOW 0x3108 ++#define CHIP_ID_HIGH 0x00 ++#define CHIP_ID_LOW 0x31 ++#define SC031_REG_DELAY 0xfe ++ ++#define SC031GS_DEFAULT_WIDTH 640 ++#define SC031GS_DEFAULT_HEIGHT 480 ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ u16 reg_num; ++ u16 value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++/* Supported resolutions */ ++enum sc031gs_width { ++ W_VGA = SC031GS_DEFAULT_WIDTH, ++}; ++ ++enum sc031gs_height { ++ H_VGA = SC031GS_DEFAULT_HEIGHT, ++}; ++ ++struct sc031gs_win_size { ++ char *name; ++ enum sc031gs_width width; ++ enum sc031gs_height height; ++ const struct regval_list *regs; ++ unsigned int mbus_code; ++}; ++ ++struct sc031gs_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct sc031gs_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++ struct v4l2_subdev_platform_data *sd_pdata; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ ++ int (*power)(struct i2c_client *client, int on); ++ int (*reset)(struct i2c_client *client); ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++static inline int sensor_i2c_master_send(struct i2c_client *client, ++ const char *buf ,int count) ++{ ++ int ret; ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.len = count; ++ msg.buf = (char *)buf; ++ ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++static inline int sensor_i2c_master_recv(struct i2c_client *client, ++ char *buf ,int count) ++{ ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ int ret; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.flags |= I2C_M_RD; ++ msg.len = count; ++ msg.buf = buf; ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++ ++unsigned char sc031gs_read_reg(struct i2c_client *client, u16 reg) ++{ ++ int ret; ++ unsigned char retval; ++ unsigned short r = cpu_to_be16(reg); ++ ++ ret = sensor_i2c_master_send(client,(u8 *)&r,2); ++ ++ if (ret < 0) ++ return ret; ++ if (ret != 2) ++ return -EIO; ++ ++ ret = sensor_i2c_master_recv(client, &retval, 1); ++ if (ret < 0) ++ return ret; ++ if (ret != 1) ++ return -EIO; ++ return retval; ++} ++ ++int sc031gs_write_reg(struct i2c_client *client, u16 reg, u8 val) ++{ ++ unsigned char msg[3]; ++ int ret; ++ ++ reg = cpu_to_be16(reg); ++ ++ memcpy(&msg[0], ®, 2); ++ memcpy(&msg[2], &val, 1); ++ ++ ret = sensor_i2c_master_send(client, msg, 3); ++ ++ if (ret < 0) ++ { ++ printk("RET<0\n"); ++ return ret; ++ } ++ if (ret < 3) ++ { ++ printk("RET<3\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Registers settings ++ */ ++ ++#define ENDMARKER { 0xffff, 0xff } ++ ++static const struct regval_list sc031gs_init_regs[] = { ++ ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x36e9, 0x80}, ++ {0x36f9, 0x80}, ++ {0x3001, 0x00}, ++ {0x3000, 0x00}, ++ {0x300f, 0x0f}, ++ {0x3018, 0x33}, ++ {0x3019, 0xfc}, ++ {0x301c, 0x78}, ++ {0x301f, 0x0e}, ++ {0x3031, 0x0a}, ++ {0x3037, 0x20}, ++ {0x303f, 0x01}, ++ {0x320c, 0x04}, ++ {0x320d, 0xb0}, ++ {0x320e, 0x07}, ++ {0x320f, 0xd0}, ++ {0x3220, 0x10}, ++ {0x3250, 0xc0}, ++ {0x3251, 0x02}, ++ {0x3252, 0x02}, ++ {0x3253, 0xa6}, ++ {0x3254, 0x02}, ++ {0x3255, 0x07}, ++ {0x3304, 0x48}, ++ {0x3306, 0x38}, ++ {0x3309, 0x68}, ++ {0x330b, 0xe0}, ++ {0x330c, 0x18}, ++ {0x330f, 0x20}, ++ {0x3310, 0x10}, ++ {0x3314, 0x1e}, ++ {0x3315, 0x38}, ++ {0x3316, 0x40}, ++ {0x3317, 0x10}, ++ {0x3329, 0x34}, ++ {0x332d, 0x34}, ++ {0x332f, 0x38}, ++ {0x3335, 0x3c}, ++ {0x3344, 0x3c}, ++ {0x335b, 0x80}, ++ {0x335f, 0x80}, ++ {0x3366, 0x06}, ++ {0x3385, 0x31}, ++ {0x3387, 0x51}, ++ {0x3389, 0x01}, ++ {0x33b1, 0x03}, ++ {0x33b2, 0x06}, ++ {0x3621, 0xa4}, ++ {0x3622, 0x05}, ++ {0x3624, 0x47}, ++ {0x3630, 0x46}, ++ {0x3631, 0x48}, ++ {0x3633, 0x52}, ++ {0x3635, 0x18}, ++ {0x3636, 0x25}, ++ {0x3637, 0x89}, ++ {0x3638, 0x0f}, ++ {0x3639, 0x08}, ++ {0x363a, 0x00}, ++ {0x363b, 0x48}, ++ {0x363c, 0x06}, ++ {0x363d, 0x00}, ++ {0x363e, 0xf8}, ++ {0x3640, 0x00}, ++ {0x3641, 0x01}, ++ {0x36ea, 0x3b}, ++ {0x36eb, 0x0e}, ++ {0x36ec, 0x1e}, ++ {0x36ed, 0x33}, ++ {0x36fa, 0x3a}, ++ {0x36fc, 0x01}, ++ {0x3908, 0x91}, ++ {0x3d08, 0x01}, ++ {0x3e01, 0x70}, ++ {0x3e02, 0x00}, // 1800 ++ {0x3e06, 0x0c}, ++ {0x3e08, 0x01}, ++ {0x3e09, 0x1f}, //4x again ++ {0x4500, 0x59}, ++ {0x4501, 0xc4}, ++ {0x4603, 0x00}, ++ {0x4809, 0x01}, ++ {0x4837, 0x38}, ++ {0x5011, 0x00}, ++ {0x36e9, 0x00}, ++ {0x36f9, 0x00}, ++ //{0x0100, 0x01}, //stream on ++ ++ //Delay 10ms} ++ {0x4418, 0x08}, ++ {0x4419, 0x8e}, ++ ++ //[gain<2] ++ {0x3314, 0x1e},//0222 ++ {0x3317, 0x10}, ++ //[4>gain>=2] ++ {0x3314, 0x4f}, //0222 ++ {0x3317, 0x0f}, //0625 ++ //[gain>=4] ++ {0x3314, 0x4f}, //0222 ++ {0x3317, 0x0f}, //0625 ++ {SC031_REG_DELAY,10}, ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_qvga_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_vga_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_720p_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_1080p_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_wb_auto_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_wb_incandescence_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_wb_daylight_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_wb_fluorescent_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_wb_cloud_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list sc031gs_balance[] = { ++ {0, sc031gs_wb_auto_regs}, {1, sc031gs_wb_incandescence_regs}, ++ {2, sc031gs_wb_daylight_regs}, {3, sc031gs_wb_fluorescent_regs}, ++ {4, sc031gs_wb_cloud_regs}, ++}; ++ ++ ++static const struct regval_list sc031gs_effect_normal_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_effect_grayscale_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_effect_sepia_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_effect_colorinv_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_effect_sepiabluel_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list sc031gs_effect[] = { ++ {0, sc031gs_effect_normal_regs}, {1, sc031gs_effect_grayscale_regs}, ++ {2, sc031gs_effect_sepia_regs}, {3, sc031gs_effect_colorinv_regs}, ++ {4, sc031gs_effect_sepiabluel_regs}, ++}; ++ ++#define SC031GS_SIZE(n, w, h, r, c) \ ++ {.name = n, .width = w , .height = h, .regs = r, .mbus_code = c } ++ ++static struct sc031gs_win_size sc031gs_supported_win_sizes[] = { ++ SC031GS_SIZE("VGA", W_VGA, H_VGA, sc031gs_vga_regs, MEDIA_BUS_FMT_SBGGR10_1X10), ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(sc031gs_supported_win_sizes)) ++/* ++ * General functions ++ */ ++static struct sc031gs_priv *to_sc031gs(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct sc031gs_priv, ++ subdev); ++} ++ ++static int sc031gs_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while ((vals->reg_num != 0xffff) || (vals->value != 0xff)) { ++ ret = sc031gs_write_reg(client, vals->reg_num, vals->value); ++ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", ++ vals->reg_num, vals->value); ++ ++ if (ret < 0) ++ return ret; ++ vals++; ++ } ++ return 0; ++} ++ ++/* OF probe functions */ ++static int sc031gs_hw_power(struct i2c_client *client, int on) ++{ ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, on); ++ } ++ ++ msleep(3); ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int sc031gs_reset(struct i2c_client *client) ++{ ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if(priv->resetb_gpio) { ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ msleep(10); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ msleep(10); ++ } ++ ++ return 0; ++} ++ ++static int sc031gs_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if(priv->sd_pdata) { ++ if(on){ ++ return regulator_bulk_enable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ }else{ ++ return regulator_bulk_disable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ } ++ } else if(priv->power) { ++ return priv->power(client, on); ++ } else { ++ dev_err(&client->dev, "sc031gs_s_power failde"); ++ return -EINVAL; ++ } ++ ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int sc031gs_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg > 0xff) ++ return -EINVAL; ++ ++ ret = sc031gs_read_reg(client, reg->reg); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = ret; ++ ++ return 0; ++} ++ ++static int sc031gs_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg > 0xff || ++ reg->val > 0xff) ++ return -EINVAL; ++ ++ return sc031gs_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++/* ++ * soc_camera_ops functions ++ */ ++static int sc031gs_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!enable ) { ++ dev_info(&client->dev, "stream down\n"); ++ sc031gs_write_reg(client, 0x0100, 0x00); ++ return 0; ++ } ++ ++ dev_info(&client->dev, "stream on\n"); ++ sc031gs_write_reg(client, 0x0100, 0x01); ++ ++ return 0; ++} ++ ++/* Select the nearest higher resolution for capture */ ++static const struct sc031gs_win_size *sc031gs_select_win(u32 *code, u32 *width, u32 *height) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(sc031gs_supported_win_sizes); i++) { ++ if ((*width >= sc031gs_supported_win_sizes[i].width) && ++ (*height >= sc031gs_supported_win_sizes[i].height) && ++ (*code == sc031gs_supported_win_sizes[i].mbus_code)) { ++ *width = sc031gs_supported_win_sizes[i].width; ++ *height = sc031gs_supported_win_sizes[i].height; ++ return &sc031gs_supported_win_sizes[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int sc031gs_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if(!priv->win) ++ return -EINVAL; ++ ++ sel->r.top = 0; ++ sel->r.left = 0; ++ sel->r.width = priv->win->width; ++ sel->r.height = priv->win->height; ++ ++ return 0; ++} ++ ++static int sc031gs_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ if(priv->win) { ++ mf->width = priv->win->width; ++ mf->height = priv->win->height; ++ } else { ++ mf->width = SC031GS_DEFAULT_WIDTH; ++ mf->height = SC031GS_DEFAULT_HEIGHT; ++ } ++ mf->code = priv->cfmt_code; ++ ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int sc031gs_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code) ++{ ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* select win */ ++ priv->win = sc031gs_select_win(&code, width, height); ++ ++ /* select format */ ++ priv->cfmt_code = 0; ++ ++ /* reset hardware */ ++ sc031gs_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ++ ret = sc031gs_write_array(client, sc031gs_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = sc031gs_write_array(client, sc031gs_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = sc031gs_write_array(client, sc031gs_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set size win */ ++ ret = sc031gs_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ sc031gs_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int sc031gs_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ /* ++ * select suitable win, but don't store it ++ */ ++ priv->win = sc031gs_select_win(&mf->code, &mf->width, &mf->height); ++ if(!priv->win) ++ return -EINVAL; ++ ++ mf->field = V4L2_FIELD_NONE; ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ sc031gs_set_params(client, &mf->width, &mf->height, mf->code); ++ if(cfg) ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int sc031gs_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= ARRAY_SIZE(sc031gs_supported_win_sizes)) ++ return -EINVAL; ++ ++ code->code = sc031gs_supported_win_sizes[code->index].mbus_code; ++ return 0; ++} ++ ++static int sc031gs_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++ fse->code = sc031gs_supported_win_sizes[index].mbus_code; ++ fse->min_width = sc031gs_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = sc031gs_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++} ++ ++static int sc031gs_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++ /*int dts*/ ++ return 0; ++} ++ ++static struct v4l2_subdev_core_ops sc031gs_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = sc031gs_g_register, ++ .s_register = sc031gs_s_register, ++#endif ++ .s_power = sc031gs_s_power, ++}; ++ ++static struct v4l2_subdev_video_ops sc031gs_subdev_video_ops = { ++ .s_stream = sc031gs_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops sc031gs_subdev_pad_ops = { ++ .enum_mbus_code = sc031gs_enum_mbus_code, ++ .enum_frame_size = sc031gs_enum_frame_size, ++ .get_fmt = sc031gs_get_fmt, ++ .set_fmt = sc031gs_set_fmt, ++ .get_mbus_config = sc031gs_g_mbus_config, ++ .get_selection = sc031gs_get_selection, ++}; ++ ++static struct v4l2_subdev_ops sc031gs_subdev_ops = { ++ .core = &sc031gs_subdev_core_ops, ++ .video = &sc031gs_subdev_video_ops, ++ .pad = &sc031gs_subdev_pad_ops, ++}; ++ ++static int sc031gs_hw_reset(struct i2c_client *client) ++{ ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if (priv->resetb_gpio) { ++ /* Active the resetb pin to perform a reset pulse */ ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ usleep_range(3000, 5000); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ } ++ ++ return 0; ++} ++ ++static int sc031gs_video_probe(struct i2c_client *client) ++{ ++ unsigned char retval_high = 0, retval_low = 0; ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ int ret; ++ ++ ret = sc031gs_s_power(&priv->subdev, 1); ++ if (ret < 0) ++ return ret; ++ /* ++ * check and show product ID and manufacturer ID ++ */ ++ ++ retval_high = sc031gs_read_reg(client, REG_CHIP_ID_HIGH); ++ if (retval_high != CHIP_ID_HIGH) { ++ dev_err(&client->dev, "read sensor %s chip_id high %x is error\n", ++ client->name, retval_high); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ ++ retval_low = sc031gs_read_reg(client, REG_CHIP_ID_LOW); ++ if (retval_low != CHIP_ID_LOW) { ++ dev_err(&client->dev, "read sensor %s chip_id low %x is error\n", ++ client->name, retval_low); ++ ret = -EINVAL; ++ goto done; ++ } ++ dev_info(&client->dev, "read sensor %s id high:0x%x,low:%x successed!\n", ++ client->name, retval_high, retval_low); ++ ++done: ++// sc031gs_s_power(&priv->subdev, 0); ++ return ret; ++} ++ ++static int sc031gs_probe_dt(struct i2c_client *client, ++ struct sc031gs_priv *priv) ++{ ++ ++ struct v4l2_subdev_platform_data *sd_pdata = priv->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies > 0) { ++ sd_pdata = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev_platform_data), GFP_KERNEL); ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ devm_kfree(&client->dev,sd_pdata); ++ return -ENOMEM; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ devm_regulator_bulk_get(&client->dev, sd_pdata->num_regulators, sd_pdata->regulators); ++ } else { ++ /* Request the reset GPIO deasserted */ ++ priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", ++ GPIOD_OUT_LOW); ++ if (!priv->resetb_gpio) ++ dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); ++ else if (IS_ERR(priv->resetb_gpio)) ++ return PTR_ERR(priv->resetb_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_LOW); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_LOW); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->power = sc031gs_hw_power; ++ priv->reset = sc031gs_hw_reset; ++ } ++ return 0; ++} ++ ++#include ++/* ++ * i2c_driver functions ++ */ ++static int sc031gs_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct sc031gs_priv *priv; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "sc031gs: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct sc031gs_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++ ++ ret = sc031gs_probe_dt(client, priv); ++ if (ret) ++ goto err_probe_dt; ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &sc031gs_subdev_ops); ++ ++ ret = sc031gs_video_probe(client); ++ if (ret < 0) ++ goto err_detect; ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_async_register_subdev; ++ ++ dev_info(&adapter->dev, "sc031gs mipi Probed\n"); ++ ++ return 0; ++ ++err_async_register_subdev: ++err_detect: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_hdl: ++ v4l2_device_unregister_subdev(&priv->subdev); ++err_probe_dt: ++ v4l2_clk_put(priv->clk); ++ devm_kfree(&client->dev, priv); ++ return ret; ++} ++ ++static int sc031gs_remove(struct i2c_client *client) ++{ ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ devm_kfree(&client->dev, priv); ++ return 0; ++} ++ ++static const struct i2c_device_id sc031gs_id[] = { ++ { "sc031gs", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, sc031gs_id); ++static const struct of_device_id sc031gs_of_match[] = { ++ {.compatible = "sc031gs", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sc031gs_of_match); ++static struct i2c_driver sc031gs_i2c_driver = { ++ .driver = { ++ .name = "sc031gs", ++ .of_match_table = of_match_ptr(sc031gs_of_match), ++ }, ++ .probe = sc031gs_probe, ++ .remove = sc031gs_remove, ++ .id_table = sc031gs_id, ++}; ++ ++module_i2c_driver(sc031gs_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for smartsens SC031GS sensor"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-cim/sc031gs.c b/module_drivers/drivers/media/i2c/ingenic-cim/sc031gs.c +new file mode 100644 +index 000000000..535b1301d +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-cim/sc031gs.c +@@ -0,0 +1,985 @@ ++/* ++ * sc031gs Camera Driver ++ * ++ * Copyright (C) 2010 Alberto Panizzo ++ * ++ * Based on ov772x, ov9640 drivers and previous non merged implementations. ++ * ++ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006, OmniVision ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define REG_CHIP_ID_HIGH 0x3107 ++#define REG_CHIP_ID_LOW 0x3108 ++#define CHIP_ID_HIGH 0x00 ++#define CHIP_ID_LOW 0x31 ++ ++#define SC031GS_DEFAULT_WIDTH 640 ++#define SC031GS_DEFAULT_HEIGHT 480 ++ ++/* Private v4l2 controls */ ++#define V4L2_CID_PRIVATE_BALANCE (V4L2_CID_PRIVATE_BASE + 0) ++#define V4L2_CID_PRIVATE_EFFECT (V4L2_CID_PRIVATE_BASE + 1) ++ ++/* ++ * Struct ++ */ ++struct regval_list { ++ u16 reg_num; ++ u16 value; ++}; ++ ++struct mode_list { ++ u16 index; ++ const struct regval_list *mode_regs; ++}; ++ ++/* Supported resolutions */ ++enum sc031gs_width { ++ W_VGA = SC031GS_DEFAULT_WIDTH, ++}; ++ ++enum sc031gs_height { ++ H_VGA = SC031GS_DEFAULT_HEIGHT, ++}; ++ ++struct sc031gs_win_size { ++ char *name; ++ enum sc031gs_width width; ++ enum sc031gs_height height; ++ const struct regval_list *regs; ++ unsigned int mbus_code; ++}; ++ ++struct sc031gs_priv { ++ struct v4l2_subdev subdev; ++ struct v4l2_ctrl_handler hdl; ++ u32 cfmt_code; ++ struct v4l2_clk *clk; ++ const struct sc031gs_win_size *win; ++ ++ int model; ++ u16 balance_value; ++ u16 effect_value; ++ u16 flag_vflip:1; ++ u16 flag_hflip:1; ++ ++ struct v4l2_subdev_platform_data *sd_pdata; ++ struct gpio_desc *resetb_gpio; ++ struct gpio_desc *pwdn_gpio; ++ struct gpio_desc *vcc_en_gpio; ++ ++ int (*power)(struct i2c_client *client, int on); ++ int (*reset)(struct i2c_client *client); ++ ++ struct regulator *reg; ++ struct regulator *reg1; ++}; ++ ++static inline int sensor_i2c_master_send(struct i2c_client *client, ++ const char *buf ,int count) ++{ ++ int ret; ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.len = count; ++ msg.buf = (char *)buf; ++ ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++static inline int sensor_i2c_master_recv(struct i2c_client *client, ++ char *buf ,int count) ++{ ++ struct i2c_adapter *adap=client->adapter; ++ struct i2c_msg msg; ++ int ret; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags & I2C_M_TEN; ++ msg.flags |= I2C_M_RD; ++ msg.len = count; ++ msg.buf = buf; ++ ret = i2c_transfer(adap, &msg, 1); ++ ++ return (ret == 1) ? count : ret; ++} ++ ++ ++unsigned char sc031gs_read_reg(struct i2c_client *client, u16 reg) ++{ ++ int ret; ++ unsigned char retval; ++ unsigned short r = cpu_to_be16(reg); ++ ++ ret = sensor_i2c_master_send(client,(u8 *)&r,2); ++ ++ if (ret < 0) ++ return ret; ++ if (ret != 2) ++ return -EIO; ++ ++ ret = sensor_i2c_master_recv(client, &retval, 1); ++ if (ret < 0) ++ return ret; ++ if (ret != 1) ++ return -EIO; ++ return retval; ++} ++ ++int sc031gs_write_reg(struct i2c_client *client, u16 reg, u8 val) ++{ ++ unsigned char msg[3]; ++ int ret; ++ ++ reg = cpu_to_be16(reg); ++ ++ memcpy(&msg[0], ®, 2); ++ memcpy(&msg[2], &val, 1); ++ ++ ret = sensor_i2c_master_send(client, msg, 3); ++ ++ if (ret < 0) ++ { ++ printk("RET<0\n"); ++ return ret; ++ } ++ if (ret < 3) ++ { ++ printk("RET<3\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Registers settings ++ */ ++ ++#define ENDMARKER { 0xffff, 0xff } ++ ++static const struct regval_list sc031gs_init_regs[] = { ++ {0x0103,0x01}, ++ {0x0100,0x00}, ++ {0x3018,0x1f}, ++ {0x3019,0xff}, ++ {0x301c,0xb4}, ++ {0x363c,0x08}, ++ {0x3630,0x82}, ++ {0x3638,0x0f}, ++ {0x3639,0x08}, ++ {0x335b,0x80}, ++ {0x3636,0x25}, ++ {0x3640,0x02}, ++ {0x3306,0x38}, ++ {0x3304,0x48}, ++ {0x3389,0x01}, ++ {0x3385,0x31}, ++ {0x330c,0x18}, ++ {0x3315,0x38}, ++ {0x3306,0x28}, ++ {0x3309,0x68}, ++ {0x3387,0x51}, ++ {0x3306,0x48}, ++ {0x3366,0x04}, ++ {0x335f,0x80}, ++ {0x363a,0x00}, ++ {0x3622,0x01}, ++ {0x3633,0x62}, ++ {0x36f9,0x20}, ++ {0x3637,0x80}, ++ {0x363d,0x04}, ++ {0x3e06,0x00}, ++ {0x363c,0x48}, ++ {0x320c,0x03}, ++ {0x320e,0x0e}, ++ {0x320f,0xa8}, ++ {0x3306,0x38}, ++ {0x330b,0xb6}, ++ {0x36f9,0x24}, ++ {0x363b,0x4a}, ++ {0x3366,0x02}, ++ {0x3316,0x78}, ++ {0x3344,0x74}, ++ {0x3335,0x74}, ++ {0x332f,0x70}, ++ {0x332d,0x6c}, ++ {0x3329,0x6c}, ++ {0x363c,0x08}, ++ {0x3630,0x81}, ++ {0x3366,0x06}, ++ {0x3314,0x3a}, ++ {0x3317,0x28}, ++ {0x3622,0x05}, ++ {0x363d,0x00}, ++ {0x3637,0x86}, ++ {0x3e01,0x62}, ++ {0x3633,0x52}, ++ {0x3630,0x86}, ++ {0x3306,0x4c}, ++ {0x330b,0xa0}, ++ {0x3631,0x48}, ++ {0x33b1,0x03}, ++ {0x33b2,0x06}, ++ {0x320c,0x02}, ++ {0x320e,0x02}, ++ {0x320f,0x0d}, ++ {0x3e01,0x20}, ++ {0x3e02,0x20}, ++ {0x3316,0x68}, ++ {0x3344,0x64}, ++ {0x3335,0x64}, ++ {0x332f,0x60}, ++ {0x332d,0x5c}, ++ {0x3329,0x5c}, ++ {0x3310,0x10}, ++ {0x3637,0x87}, ++ {0x363e,0xf8}, ++ {0x3254,0x02}, ++ {0x3255,0x07}, ++ {0x3252,0x02}, ++ {0x3253,0xa6}, ++ {0x3250,0xf0}, ++ {0x3251,0x02}, ++ {0x330f,0x50}, ++ {0x3630,0x46}, ++ {0x3621,0xa2}, ++ {0x3621,0xa0}, ++ {0x4500,0x59}, ++ {0x3637,0x88}, ++ {0x3908,0x81}, ++ {0x3640,0x00}, ++ {0x3641,0x02}, ++ {0x363c,0x05}, ++ {0x363b,0x4c}, ++ {0x36e9,0x40}, ++ {0x36ea,0x36}, ++ {0x36ed,0x13}, ++ {0x36f9,0x04}, ++ {0x36fa,0x38}, ++ {0x330b,0x80}, ++ {0x3640,0x00}, ++ {0x3641,0x01}, ++ {0x3d08,0x00}, ++ {0x3306,0x48}, ++ {0x3621,0xa4}, ++ {0x300f,0x0f}, ++ {0x4837,0x1b}, ++ {0x4809,0x01}, ++ {0x363b,0x48}, ++ {0x363c,0x06}, ++ {0x36e9,0x00}, ++ {0x36ea,0x3b}, ++ {0x36eb,0x1A}, ++ {0x36ec,0x0A}, ++ {0x36ed,0x33}, ++ {0x36f9,0x00}, ++ {0x36fa,0x3a}, ++ {0x36fc,0x01}, ++ {0x320c,0x03}, ++ {0x320d,0x6e}, ++ {0x320e,0x02}, ++ {0x320f,0xab}, ++ {0x330b,0x80}, ++ {0x330f,0x50}, ++ {0x3637,0x89}, ++ {0x3641,0x01}, ++ {0x4501,0xc4}, ++ {0x5011,0x01}, ++ {0x3908,0x21}, ++ {0x3e01,0x40}, ++ {0x3e02,0x80}, ++ {0x3306,0x38}, ++ {0x330b,0xe0}, ++ {0x330f,0x20}, ++ {0x3d08,0x01}, ++ {0x3314,0x65}, ++ {0x5011,0x00}, ++ {0x3e06,0x0c}, ++ {0x3908,0x91}, ++ {0x3624,0x47}, ++ {0x3220,0x10}, ++ {0x3635,0x18}, ++ {0x3223,0x50}, ++ {0x301f,0x01}, ++ {0x3028,0x82}, ++ {0x0100,0x01}, ++ ++ //Delay 10ms ++ {0x4418,0x08}, ++ {0x4419,0x80}, ++ {0x363d,0x10}, ++ {0x3630,0x48}, ++ //[gain<2] ++ {0x3314,0x65}, ++ {0x3317,0x10}, ++ //[4>gain>=2] ++ {0x3314,0x65}, ++ {0x3317,0x10}, ++ //[gain>=4] ++ {0x3314,0x60}, ++ {0x3317,0x0e}, ++ ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_qvga_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_vga_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_720p_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_1080p_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_wb_auto_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_wb_incandescence_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_wb_daylight_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_wb_fluorescent_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_wb_cloud_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list sc031gs_balance[] = { ++ {0, sc031gs_wb_auto_regs}, {1, sc031gs_wb_incandescence_regs}, ++ {2, sc031gs_wb_daylight_regs}, {3, sc031gs_wb_fluorescent_regs}, ++ {4, sc031gs_wb_cloud_regs}, ++}; ++ ++ ++static const struct regval_list sc031gs_effect_normal_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_effect_grayscale_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_effect_sepia_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_effect_colorinv_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct regval_list sc031gs_effect_sepiabluel_regs[] = { ++ ENDMARKER, ++}; ++ ++static const struct mode_list sc031gs_effect[] = { ++ {0, sc031gs_effect_normal_regs}, {1, sc031gs_effect_grayscale_regs}, ++ {2, sc031gs_effect_sepia_regs}, {3, sc031gs_effect_colorinv_regs}, ++ {4, sc031gs_effect_sepiabluel_regs}, ++}; ++ ++#define SC031GS_SIZE(n, w, h, r, c) \ ++ {.name = n, .width = w , .height = h, .regs = r, .mbus_code = c } ++ ++static struct sc031gs_win_size sc031gs_supported_win_sizes[] = { ++ SC031GS_SIZE("VGA", W_VGA, H_VGA, sc031gs_vga_regs, MEDIA_BUS_FMT_Y8_1X8), ++}; ++ ++#define N_WIN_SIZES (ARRAY_SIZE(sc031gs_supported_win_sizes)) ++ ++/* ++ * General functions ++ */ ++static struct sc031gs_priv *to_sc031gs(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct sc031gs_priv, ++ subdev); ++} ++ ++static int sc031gs_write_array(struct i2c_client *client, ++ const struct regval_list *vals) ++{ ++ int ret; ++ ++ while ((vals->reg_num != 0xffff) || (vals->value != 0xff)) { ++ ret = sc031gs_write_reg(client, vals->reg_num, vals->value); ++ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", ++ vals->reg_num, vals->value); ++ ++ if (ret < 0) ++ return ret; ++ vals++; ++ } ++ return 0; ++} ++ ++/* OF probe functions */ ++static int sc031gs_hw_power(struct i2c_client *client, int on) ++{ ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ dev_dbg(&client->dev, "%s: %s the camera\n", ++ __func__, on ? "ENABLE" : "DISABLE"); ++ ++ /* thses gpio should be set according to the active level in dt defines */ ++ if(priv->vcc_en_gpio) { ++ gpiod_direction_output(priv->vcc_en_gpio, !on); ++ } ++ ++ msleep(3); ++ ++ if (priv->pwdn_gpio) { ++ gpiod_direction_output(priv->pwdn_gpio, on); ++ } ++ ++ msleep(10); ++ return 0; ++} ++ ++static int sc031gs_reset(struct i2c_client *client) ++{ ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if(priv->resetb_gpio) { ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ msleep(10); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ msleep(10); ++ } ++ ++ return 0; ++} ++ ++static int sc031gs_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if(priv->sd_pdata) { ++ if(on) ++ return regulator_bulk_enable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ else ++ return regulator_bulk_disable(priv->sd_pdata->num_regulators,priv->sd_pdata->regulators); ++ } else if(priv->power) { ++ return priv->power(client, on); ++ } else { ++ dev_err(&client->dev, "sc031gs_s_power failde"); ++ return -EINVAL; ++ } ++ ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int sc031gs_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ reg->size = 1; ++ if (reg->reg > 0xff) ++ return -EINVAL; ++ ++ ret = sc031gs_read_reg(client, reg->reg); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = ret; ++ ++ return 0; ++} ++ ++static int sc031gs_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (reg->reg > 0xff || ++ reg->val > 0xff) ++ return -EINVAL; ++ ++ return sc031gs_write_reg(client, reg->reg, reg->val); ++} ++#endif ++ ++/* ++ * soc_camera_ops functions ++ */ ++static int sc031gs_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ if (!enable ) { ++ dev_info(&client->dev, "stream down\n"); ++ sc031gs_write_reg(client, 0x0100, 0x00); ++ return 0; ++ } ++ ++ dev_info(&client->dev, "stream on\n"); ++ sc031gs_write_reg(client, 0x0100, 0x01); ++ ++ return 0; ++} ++ ++/* Select the nearest higher resolution for capture */ ++static const struct sc031gs_win_size *sc031gs_select_win(u32 code, u32 *width, u32 *height) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(sc031gs_supported_win_sizes); i++) { ++ if ((*width >= sc031gs_supported_win_sizes[i].width) && ++ (*height >= sc031gs_supported_win_sizes[i].height) && ++ (code == sc031gs_supported_win_sizes[i].mbus_code)) { ++ *width = sc031gs_supported_win_sizes[i].width; ++ *height = sc031gs_supported_win_sizes[i].height; ++ return &sc031gs_supported_win_sizes[i]; ++ } ++ } ++ return NULL; ++} ++ ++static int sc031gs_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if(!priv->win) ++ return -EINVAL; ++ ++ sel->r.top = 0; ++ sel->r.left = 0; ++ sel->r.width = priv->win->width; ++ sel->r.height = priv->win->height; ++ ++ return 0; ++} ++ ++static int sc031gs_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ if(priv->win) { ++ mf->width = priv->win->width; ++ mf->height = priv->win->height; ++ } else { ++ mf->width = SC031GS_DEFAULT_WIDTH; ++ mf->height = SC031GS_DEFAULT_HEIGHT; ++ } ++ mf->code = priv->cfmt_code; ++ ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int sc031gs_set_params(struct i2c_client *client, u32 *width, u32 *height, u32 code) ++{ ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ int ret; ++ ++ int bala_index = priv->balance_value; ++ int effe_index = priv->effect_value; ++ ++ /* select win */ ++ priv->win = sc031gs_select_win(code, width, height); ++ ++ /* select format */ ++ priv->cfmt_code = 0; ++ ++ /* reset hardware */ ++ sc031gs_reset(client); ++ ++ /* initialize the sensor with default data */ ++ dev_dbg(&client->dev, "%s: Init default", __func__); ++ ++ ret = sc031gs_write_array(client, sc031gs_init_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set balance */ ++ ret = sc031gs_write_array(client, sc031gs_balance[bala_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set effect */ ++ ret = sc031gs_write_array(client, sc031gs_effect[effe_index].mode_regs); ++ if (ret < 0) ++ goto err; ++ ++ /* set size win */ ++ ret = sc031gs_write_array(client, priv->win->regs); ++ if (ret < 0) ++ goto err; ++ ++ priv->cfmt_code = code; ++ *width = priv->win->width; ++ *height = priv->win->height; ++ ++ return 0; ++ ++err: ++ dev_err(&client->dev, "%s: Error %d", __func__, ret); ++ sc031gs_reset(client); ++ priv->win = NULL; ++ ++ return ret; ++} ++ ++static int sc031gs_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ /* ++ * select suitable win, but don't store it ++ */ ++ priv->win = sc031gs_select_win(mf->code, &mf->width, &mf->height); ++ if(!priv->win) ++ return -EINVAL; ++ ++ mf->field = V4L2_FIELD_NONE; ++ mf->colorspace = V4L2_COLORSPACE_JPEG; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) ++ sc031gs_set_params(client, &mf->width, &mf->height, mf->code); ++ if(cfg) ++ cfg->try_fmt = *mf; ++ return 0; ++} ++ ++static int sc031gs_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= ARRAY_SIZE(sc031gs_supported_win_sizes)) ++ return -EINVAL; ++ ++ code->code = sc031gs_supported_win_sizes[code->index].mbus_code; ++ return 0; ++} ++ ++static int sc031gs_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ __u32 index = fse->index; ++ ++ if(index >= N_WIN_SIZES) ++ return -EINVAL; ++ ++ fse->code = sc031gs_supported_win_sizes[index].mbus_code; ++ fse->min_width = sc031gs_supported_win_sizes[index].width; ++ fse->max_width = fse->min_width; ++ fse->min_height = sc031gs_supported_win_sizes[index].height; ++ fse->max_height = fse->min_height; ++ return 0; ++} ++ ++static int sc031gs_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, ++ struct v4l2_mbus_config *cfg) ++{ ++ /* int dts*/ ++ return 0; ++} ++ ++static struct v4l2_subdev_core_ops sc031gs_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = sc031gs_g_register, ++ .s_register = sc031gs_s_register, ++#endif ++ .s_power = sc031gs_s_power, ++}; ++ ++static struct v4l2_subdev_video_ops sc031gs_subdev_video_ops = { ++ .s_stream = sc031gs_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops sc031gs_subdev_pad_ops = { ++ .enum_mbus_code = sc031gs_enum_mbus_code, ++ .enum_frame_size = sc031gs_enum_frame_size, ++ .get_fmt = sc031gs_get_fmt, ++ .set_fmt = sc031gs_set_fmt, ++ .get_mbus_config = sc031gs_g_mbus_config, ++ .get_selection = sc031gs_get_selection, ++}; ++ ++static struct v4l2_subdev_ops sc031gs_subdev_ops = { ++ .core = &sc031gs_subdev_core_ops, ++ .video = &sc031gs_subdev_video_ops, ++ .pad = &sc031gs_subdev_pad_ops, ++}; ++ ++static int sc031gs_hw_reset(struct i2c_client *client) ++{ ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ if (priv->resetb_gpio) { ++ /* Active the resetb pin to perform a reset pulse */ ++ gpiod_direction_output(priv->resetb_gpio, 1); ++ usleep_range(3000, 5000); ++ gpiod_direction_output(priv->resetb_gpio, 0); ++ } ++ ++ return 0; ++} ++ ++static int sc031gs_video_probe(struct i2c_client *client) ++{ ++ unsigned char retval = 0, retval_high = 0, retval_low = 0; ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ int ret; ++ ++ ret = sc031gs_s_power(&priv->subdev, 1); ++ if (ret < 0) ++ return ret; ++ /* ++ * check and show product ID and manufacturer ID ++ */ ++ ++ retval = sc031gs_write_reg(client, 0x0103, 0x01); ++ if(retval) { ++ dev_err(&client->dev, "i2c write failed!\n"); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ retval_high = sc031gs_read_reg(client, REG_CHIP_ID_HIGH); ++ if (retval_high != CHIP_ID_HIGH) { ++ dev_err(&client->dev, "read sensor %s chip_id high %x is error\n", ++ client->name, retval_high); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ ++ retval_low = sc031gs_read_reg(client, REG_CHIP_ID_LOW); ++ if (retval_low != CHIP_ID_LOW) { ++ dev_err(&client->dev, "read sensor %s chip_id low %x is error\n", ++ client->name, retval_low); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ dev_info(&client->dev, "read sensor %s id high:0x%x,low:%x successed!\n", ++ client->name, retval_high, retval_low); ++ ++done: ++ return ret; ++} ++ ++static int sc031gs_probe_dt(struct i2c_client *client, ++ struct sc031gs_priv *priv) ++{ ++ struct v4l2_subdev_platform_data *sd_pdata = priv->sd_pdata; ++ struct device_node *np = client->dev.of_node; ++ int supplies = 0, index = 0; ++ ++ supplies = of_property_count_strings(np, "supplies-name"); ++ if(supplies > 0) { ++ sd_pdata = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev_platform_data), GFP_KERNEL); ++ sd_pdata->num_regulators = supplies; ++ sd_pdata->regulators = devm_kzalloc(&client->dev, supplies * sizeof(struct regulator_bulk_data), GFP_KERNEL); ++ if(!sd_pdata->regulators) { ++ dev_err(&client->dev, "Failed to allocate regulators.!\n"); ++ devm_kfree(&client->dev,sd_pdata); ++ return -ENOMEM; ++ } ++ ++ for(index = 0; index < sd_pdata->num_regulators; index ++) { ++ of_property_read_string_index(np, "supplies-name", index, ++ &(sd_pdata->regulators[index].supply)); ++ ++ dev_dbg(&client->dev, "sd_pdata->regulators[%d].supply: %s\n", ++ index, sd_pdata->regulators[index].supply); ++ } ++ ++ devm_regulator_bulk_get(&client->dev, sd_pdata->num_regulators, sd_pdata->regulators); ++ } else { ++ /* Request the reset GPIO deasserted */ ++ priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", ++ GPIOD_OUT_LOW); ++ if (!priv->resetb_gpio) ++ dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); ++ else if (IS_ERR(priv->resetb_gpio)) ++ return PTR_ERR(priv->resetb_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_LOW); ++ if (!priv->pwdn_gpio) ++ dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); ++ else if (IS_ERR(priv->pwdn_gpio)) ++ return PTR_ERR(priv->pwdn_gpio); ++ ++ /* Request the power down GPIO asserted */ ++ priv->vcc_en_gpio = devm_gpiod_get_optional(&client->dev, "vcc-en", ++ GPIOD_OUT_HIGH); ++ if (!priv->vcc_en_gpio) ++ dev_dbg(&client->dev, "vcc_en gpio is not assigned!\n"); ++ else if (IS_ERR(priv->vcc_en_gpio)) ++ return PTR_ERR(priv->vcc_en_gpio); ++ ++ /* Initialize the soc_camera_subdev_desc */ ++ priv->power = sc031gs_hw_power; ++ priv->reset = sc031gs_hw_reset; ++ } ++ return 0; ++} ++ ++#include ++/* ++ * i2c_driver functions ++ */ ++static int sc031gs_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct sc031gs_priv *priv; ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ int ret; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_err(&adapter->dev, ++ "sc031gs: I2C-Adapter doesn't support SMBUS\n"); ++ return -EIO; ++ } ++ ++ priv = devm_kzalloc(&client->dev, sizeof(struct sc031gs_priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&adapter->dev, ++ "Failed to allocate memory for private data!\n"); ++ return -ENOMEM; ++ } ++ ++ priv->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(priv->clk)) ++ return -EPROBE_DEFER; ++ ++ v4l2_clk_set_rate(priv->clk, 24000000); ++ ++ ret = sc031gs_probe_dt(client, priv); ++ if (ret) ++ goto err_probe_dt; ++ ++ v4l2_i2c_subdev_init(&priv->subdev, client, &sc031gs_subdev_ops); ++ ++ ret = sc031gs_video_probe(client); ++ if (ret < 0) ++ goto err_detect; ++ ++ ret = v4l2_async_register_subdev(&priv->subdev); ++ if (ret < 0) ++ goto err_async_register_subdev; ++ ++ dev_info(&adapter->dev, "sc031gs Probed\n"); ++ ++ return 0; ++ ++err_async_register_subdev: ++err_detect: ++ v4l2_ctrl_handler_free(&priv->hdl); ++err_hdl: ++ v4l2_device_unregister_subdev(&priv->subdev); ++err_probe_dt: ++ v4l2_clk_put(priv->clk); ++ devm_kfree(&client->dev, priv); ++ return ret; ++} ++ ++static int sc031gs_remove(struct i2c_client *client) ++{ ++ struct sc031gs_priv *priv = to_sc031gs(client); ++ ++ v4l2_async_unregister_subdev(&priv->subdev); ++ v4l2_clk_put(priv->clk); ++ v4l2_device_unregister_subdev(&priv->subdev); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ devm_kfree(&client->dev, priv); ++ return 0; ++} ++ ++static const struct i2c_device_id sc031gs_id[] = { ++ { "sc031gs", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, sc031gs_id); ++static const struct of_device_id sc031gs_of_match[] = { ++ {.compatible = "sc031gs", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sc031gs_of_match); ++static struct i2c_driver sc031gs_i2c_driver = { ++ .driver = { ++ .name = "sc031gs", ++ .of_match_table = of_match_ptr(sc031gs_of_match), ++ }, ++ .probe = sc031gs_probe, ++ .remove = sc031gs_remove, ++ .id_table = sc031gs_id, ++}; ++ ++module_i2c_driver(sc031gs_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for smartsens SC031GS sensor"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/Kconfig b/module_drivers/drivers/media/i2c/ingenic-isp-v2/Kconfig +new file mode 100644 +index 000000000..372adde35 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/Kconfig +@@ -0,0 +1,49 @@ ++comment "ingenic-isp-v2 camera sensor drivers" ++ ++config INGENIC_ISP_V2_CAMERA_IMX327 ++ tristate "imx327 sensor support" ++ depends on VIDEO_INGENIC_ISP_V2 && I2C ++ help ++ This is a ingenic-isp camera driver for IMX327 ++ ++config INGENIC_ISP_V2_CAMERA_GC2093 ++ tristate "gc2093 sensor support" ++ depends on VIDEO_INGENIC_ISP_V2 && I2C ++ help ++ This is a ingenic-isp camera driver for GC2093 ++ ++config INGENIC_ISP_V2_CAMERA_OV2735A ++ tristate "ov2735a sensor support" ++ depends on VIDEO_INGENIC_ISP_V2 && I2C ++ help ++ This is a ingenic-isp camera driver for ov2735a ++ ++config INGENIC_ISP_V2_CAMERA_SC2310 ++ tristate "sc2310 sensor support" ++ depends on VIDEO_INGENIC_ISP_V2 && I2C ++ help ++ This is a ingenic-isp camera driver for sc2310 ++ ++config INGENIC_ISP_V2_CAMERA_SC230AI ++ tristate "sc230ai sensor support" ++ depends on VIDEO_INGENIC_ISP_V2 && I2C ++ help ++ This is a ingenic-isp camera driver for sc230ai ++ ++config INGENIC_ISP_V2_CAMERA_GC2155 ++ tristate "gc2155 sensor support" ++ depends on VIDEO_INGENIC_ISP_V2 && I2C ++ help ++ This is a ingenic-isp camera driver for gc2155 ++ ++config INGENIC_ISP_V2_CAMERA_OV4689 ++ tristate "ov4689 sensor support" ++ depends on VIDEO_INGENIC_ISP_V2 && I2C ++ help ++ This is a ingenic-isp camera driver for ov4689 ++ ++config INGENIC_ISP_V2_CAMERA_OV7251 ++ tristate "ov7251 sensor support" ++ depends on VIDEO_INGENIC_ISP_V2 && I2C ++ help ++ This is a ingenic-isp camera driver for ov7251 +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/Makefile b/module_drivers/drivers/media/i2c/ingenic-isp-v2/Makefile +new file mode 100644 +index 000000000..8779e03bf +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/Makefile +@@ -0,0 +1,10 @@ ++obj-$(CONFIG_INGENIC_ISP_V2_CAMERA_IMX327) += imx327.o ++obj-$(CONFIG_INGENIC_ISP_V2_CAMERA_GC2093) += gc2093.o ++obj-$(CONFIG_INGENIC_ISP_V2_CAMERA_OV2735A) += ov2735a.o ++obj-$(CONFIG_INGENIC_ISP_V2_CAMERA_SC2310) += sc2310.o ++obj-$(CONFIG_INGENIC_ISP_V2_CAMERA_SC230AI) += sc230ai.o ++obj-$(CONFIG_INGENIC_ISP_V2_CAMERA_GC2155) += gc2155.o ++obj-$(CONFIG_INGENIC_ISP_V2_CAMERA_OV4689) += ov4689.o ++obj-$(CONFIG_INGENIC_ISP_V2_CAMERA_OV7251) += ov7251.o ++ ++ccflags-y += -I$(srctree)/module_drivers/drivers/media/platform/ingenic-isp-v2/ +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2053.c b/module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2053.c +new file mode 100755 +index 000000000..763cdbc69 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2053.c +@@ -0,0 +1,1001 @@ ++/* ++ * A V4L2 driver for OmniVision gc2053 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define GC2053_CHIP_ID_H (0x20) ++#define GC2053_CHIP_ID_L (0x53) ++#define GC2053_REG_END 0xff ++#define GC2053_REG_DELAY 0x00 ++ ++#define AGAIN_MAX_DB 0x64 ++#define DGAIN_MAX_DB 0x64 ++#define LOG2_GAIN_SHIFT 16 ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++ ++struct gc2053_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++}; ++ ++struct gc2053_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct gc2053_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ /* struct clk *sclka; */ ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct gc2053_win_size *win; ++ ++ struct gc2053_gpio reset; ++ struct gc2053_gpio pwdn; ++ struct gc2053_gpio pwen; ++}; ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ int index; ++ unsigned int regb4; ++ unsigned int regb3; ++ unsigned int regb2; ++ unsigned int dpc; ++ unsigned int blc; ++ unsigned int gain; ++}; ++ ++struct again_lut gc2053_again_lut[] = { ++ {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0}, ++ {0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 5776}, ++ {0x02, 0x00, 0x00, 0x20, 0x01, 0x00, 11553}, ++ {0x03, 0x00, 0x10, 0x00, 0x01, 0x0c, 17330}, ++ {0x04, 0x00, 0x10, 0x10, 0x01, 0x0c, 23450}, ++ {0x05, 0x00, 0x20, 0x00, 0x01, 0x1b, 29570}, ++ {0x06, 0x00, 0x20, 0x14, 0x01, 0x1b, 36240}, ++ {0x07, 0x00, 0x20, 0x28, 0x01, 0x1b, 42910}, ++ {0x08, 0x00, 0x30, 0x00, 0x01, 0x2c, 49580}, ++ {0x09, 0x00, 0x30, 0x14, 0x01, 0x2c, 57187}, ++ {0x0A, 0x00, 0x40, 0x00, 0x01, 0x3f, 64793}, ++ {0x0B, 0x00, 0x40, 0x14, 0x01, 0x3f, 72266}, ++ {0x0C, 0x00, 0x50, 0x00, 0x02, 0x16, 79739}, ++ {0x0D, 0x00, 0x50, 0x18, 0x02, 0x16, 88754}, ++ {0x0E, 0x00, 0x60, 0x00, 0x02, 0x35, 97768}, ++ {0x0F, 0x00, 0x60, 0x18, 0x02, 0x35, 106442}, ++ {0x10, 0x00, 0x70, 0x00, 0x03, 0x16, 115115}, ++ {0x11, 0x00, 0x70, 0x14, 0x03, 0x16, 122907}, ++ {0x12, 0x00, 0x80, 0x00, 0x04, 0x02, 130699}, ++ {0x13, 0x00, 0x80, 0x14, 0x04, 0x02, 138382}, ++ {0x14, 0x00, 0x90, 0x00, 0x04, 0x31, 146065}, ++ {0x15, 0x00, 0x90, 0x18, 0x04, 0x31, 154815}, ++ {0x16, 0x00, 0xa0, 0x00, 0x05, 0x32, 163565}, ++ {0x17, 0x00, 0xa0, 0x14, 0x05, 0x32, 171002}, ++ {0x18, 0x00, 0xb0, 0x00, 0x06, 0x35, 178439}, ++ {0x19, 0x00, 0xb0, 0x18, 0x06, 0x35, 186777}, ++ {0x1A, 0x00, 0xc0, 0x00, 0x08, 0x04, 195116}, ++ {0x1B, 0x00, 0xc0, 0x14, 0x08, 0x04, 202863}, ++ {0x1C, 0x00, 0x5a, 0x00, 0x09, 0x19, 210610}, ++ {0x1D, 0x00, 0x5a, 0x14, 0x09, 0x19, 216774}, ++ {0x1E, 0x00, 0x5a, 0x20, 0x09, 0x19, 222937}, ++ {0x1F, 0x00, 0x83, 0x00, 0x0b, 0x0f, 229100}, ++ {0x20, 0x00, 0x83, 0x14, 0x0b, 0x0f, 236816}, ++ {0x21, 0x00, 0x93, 0x00, 0x0d, 0x12, 244531}, ++ {0x22, 0x00, 0x93, 0x18, 0x0d, 0x12, 252603}, ++ {0x23, 0x00, 0x84, 0x00, 0x10, 0x00, 260674}, ++ {0x24, 0x00, 0x84, 0x14, 0x10, 0x00, 268190}, ++ {0x25, 0x00, 0x94, 0x00, 0x12, 0x3a, 275706}, ++ {0x26, 0x00, 0x94, 0x18, 0x12, 0x3a, 283977}, ++ {0x27, 0x01, 0x2c, 0x00, 0x1a, 0x02, 292248}, ++ {0x28, 0x01, 0x2c, 0x18, 0x1a, 0x02, 300872}, ++ {0x29, 0x01, 0x3c, 0x00, 0x1b, 0x20, 309495}, ++ {0x2A, 0x01, 0x3c, 0x18, 0x1b, 0x20, 317963}, ++ {0x2B, 0x00, 0x8c, 0x00, 0x20, 0x0f, 326431}, ++ {0x2C, 0x00, 0x8c, 0x18, 0x20, 0x0f, 334373}, ++ {0x2D, 0x00, 0x9c, 0x00, 0x26, 0x07, 342315}, ++ {0x2E, 0x00, 0x9c, 0x18, 0x26, 0x07, 350616}, ++ {0x2F, 0x02, 0x64, 0x00, 0x36, 0x21, 358918}, ++ {0x30, 0x02, 0x64, 0x18, 0x36, 0x21, 366834}, ++ {0x31, 0x02, 0x74, 0x00, 0x37, 0x3a, 374750}, ++ {0x32, 0x02, 0x74, 0x18, 0x37, 0x3a, 382687}, ++ {0x33, 0x00, 0xc6, 0x00, 0x3d, 0x02, 390624}, ++ {0x34, 0x00, 0xc6, 0x18, 0x3d, 0x02, 399464}, ++ {0x35, 0x00, 0xdc, 0x00, 0x3f, 0x3f, 408304}, ++ {0x36, 0x00, 0xdc, 0x18, 0x3f, 0x3f, 416945}, ++ {0x37, 0x02, 0x85, 0x00, 0x3f, 0x3f, 421145}, ++ {0x38, 0x02, 0x95, 0x00, 0x3f, 0x3f, 440355}, ++ {0x39, 0x00, 0xce, 0x00, 0x3f, 0x3f, 444858} ++}; ++ ++ ++static inline struct gc2053_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct gc2053_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct gc2053_info, hdl)->sd; ++} ++struct regval_list { ++ uint8_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list gc2053_init_regs_1920_1080_25fps_mipi[] = { ++ /*system*/ ++ {0xfe, 0x80}, ++ {0xfe, 0x80}, ++ {0xfe, 0x80}, ++ {0xfe, 0x00}, ++ {0xf2, 0x00}, ++ {0xf3, 0x00}, ++ {0xf4, 0x36}, ++ {0xf5, 0xc0}, ++ {0xf6, 0x44}, ++ {0xf7, 0x01}, ++ {0xf8, 0x63}, ++ {0xf9, 0x40}, ++ {0xfc, 0x8e}, ++ /*CISCTL & ANALOG*/ ++ {0xfe, 0x00}, ++ {0x87, 0x18}, ++ {0xee, 0x30}, ++ {0xd0, 0xb7}, ++ {0x03, 0x04}, ++ {0x04, 0x60}, ++ {0x05, 0x04}, ++ {0x06, 0x4c}, ++ {0x07, 0x00}, ++ {0x08, 0x11}, ++ {0x09, 0x00}, ++ {0x0a, 0x02}, ++ {0x0b, 0x00}, ++ {0x0c, 0x02}, ++ {0x0d, 0x04}, ++ {0x0e, 0x40}, ++ {0x12, 0xe2}, ++ {0x13, 0x16}, ++ {0x19, 0x0a}, ++ {0x21, 0x1c}, ++ {0x28, 0x0a}, ++ {0x29, 0x24}, ++ {0x2b, 0x04}, ++ {0x32, 0xf8}, ++ {0x37, 0x03}, ++ {0x39, 0x15}, ++ {0x43, 0x07}, ++ {0x44, 0x40}, ++ {0x46, 0x0b}, ++ {0x4b, 0x20}, ++ {0x4e, 0x08}, ++ {0x55, 0x20}, ++ {0x66, 0x05}, ++ {0x67, 0x05}, ++ {0x77, 0x01}, ++ {0x78, 0x00}, ++ {0x7c, 0x93}, ++ {0x8c, 0x12}, ++ {0x8d, 0x92}, ++ {0x90, 0x00},/*use frame length to change fps*/ ++ {0x41, 0x05}, ++ {0x42, 0x46},/*vts for 25fps mipi*/ ++ {0x9d, 0x10}, ++ {0xce, 0x7c}, ++ {0xd2, 0x41}, ++ {0xd3, 0xdc}, ++ {0xe6, 0x50}, ++ /*gain*/ ++ {0xb6, 0xc0}, ++ {0xb0, 0x70}, ++ {0xb1, 0x01}, ++ {0xb2, 0x00}, ++ {0xb3, 0x00}, ++ {0xb4, 0x00}, ++ {0xb8, 0x01}, ++ {0xb9, 0x00}, ++ /*blk*/ ++ {0x26, 0x30}, ++ {0xfe, 0x01}, ++ {0x40, 0x23}, ++ {0x55, 0x07}, ++ {0x60, 0x40}, ++ {0xfe, 0x04}, ++ {0x14, 0x78}, ++ {0x15, 0x78}, ++ {0x16, 0x78}, ++ {0x17, 0x78}, ++ /*window*/ ++ {0xfe, 0x01}, ++ {0x92, 0x00}, ++ {0x94, 0x03}, ++ {0x95, 0x04}, ++ {0x96, 0x38}, ++ {0x97, 0x07}, ++ {0x98, 0x80}, ++ /*ISP*/ ++ {0xfe, 0x01}, ++ {0x01, 0x05}, ++ {0x02, 0x89}, ++ {0x04, 0x01}, ++ {0x07, 0xa6}, ++ {0x08, 0xa9}, ++ {0x09, 0xa8}, ++ {0x0a, 0xa7}, ++ {0x0b, 0xff}, ++ {0x0c, 0xff}, ++ {0x0f, 0x00}, ++ {0x50, 0x1c}, ++ {0x89, 0x03}, ++ {0xfe, 0x04}, ++ {0x28, 0x86}, ++ {0x29, 0x86}, ++ {0x2a, 0x86}, ++ {0x2b, 0x68}, ++ {0x2c, 0x68}, ++ {0x2d, 0x68}, ++ {0x2e, 0x68}, ++ {0x2f, 0x68}, ++ {0x30, 0x4f}, ++ {0x31, 0x68}, ++ {0x32, 0x67}, ++ {0x33, 0x66}, ++ {0x34, 0x66}, ++ {0x35, 0x66}, ++ {0x36, 0x66}, ++ {0x37, 0x66}, ++ {0x38, 0x62}, ++ {0x39, 0x62}, ++ {0x3a, 0x62}, ++ {0x3b, 0x62}, ++ {0x3c, 0x62}, ++ {0x3d, 0x62}, ++ {0x3e, 0x62}, ++ {0x3f, 0x62}, ++ /****DVP & MIPI****/ ++ {0xfe, 0x01}, ++ {0x9a, 0x06}, ++ {0xfe, 0x00}, ++ {0x7b, 0x2a}, ++ {0x23, 0x2d}, ++ {0xfe, 0x03}, ++ {0x01, 0x27}, ++ {0x02, 0x56}, ++ {0x03, 0x8e},/*0xb6*/ ++ {0x12, 0x80}, ++ {0x13, 0x07}, ++ {0x15, 0x12}, ++ {0xfe, 0x00}, ++ {0x3e, 0x91}, ++ ++ {GC2053_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list gc2053_stream_on_mipi[] = { ++ {GC2053_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list gc2053_stream_off_mipi[] = { ++ {GC2053_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int gc2053_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct gc2053_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 1, ++ .buf = ®, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ printk("i2c device addr : 0x%x~~~~~~~~~~~~~\n",client->addr); ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc2053_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct gc2053_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {reg, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc2053_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != GC2053_REG_END) { ++ if (vals->reg_num == GC2053_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc2053_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int gc2053_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != GC2053_REG_END) { ++ if (vals->reg_num == GC2053_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc2053_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int gc2053_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ return 0; ++} ++ ++static int gc2053_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ return 0; ++} ++ ++static int gc2053_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2053_info *info = to_state(sd); ++ int ret = 0; ++ printk("%s:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",__func__); ++ ret = gc2053_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int gc2053_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ret = gc2053_read(sd, 0xf0, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC2053_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = gc2053_read(sd, 0xf1, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC2053_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++static struct gc2053_win_size gc2053_win_sizes[] = { ++ { ++ .mipi_cfg.clk = 600, //data rate = 600Mbps/lane, clk is about 600Mbps. ++ .mipi_cfg.twidth = 1920, ++ .mipi_cfg.theight = 1080, ++ .mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .mipi_cfg.mipi_vcomp_en = 0, ++ .mipi_cfg.mipi_hcomp_en = 0, ++ .mipi_cfg.mipi_crop_start0x = 0, ++ .mipi_cfg.mipi_crop_start0y = 0, ++ .mipi_cfg.mipi_crop_start1x = 0, ++ .mipi_cfg.mipi_crop_start1y = 0, ++ .mipi_cfg.mipi_crop_start2x = 0, ++ .mipi_cfg.mipi_crop_start2y = 0, ++ .mipi_cfg.mipi_crop_start3x = 0, ++ .mipi_cfg.mipi_crop_start3y = 0, ++ .mipi_cfg.hcrop_diff_en = 0, ++ .mipi_cfg.line_sync_mode = 0, ++ .mipi_cfg.work_start_flag = 0, ++ .mipi_cfg.data_type_en = 0, ++ .mipi_cfg.data_type_value = 0, ++ .mipi_cfg.del_start = 0, ++ .mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .mipi_cfg.sensor_fid_mode = 0, ++ .mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ ++ .width = 1920, ++ .height = 1080, ++ .fps = 25 << 16 | 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = gc2053_init_regs_1920_1080_25fps_mipi, ++ ++ }, ++}; ++ ++static int gc2053_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_gc2053_FMTS) ++ return -EINVAL; ++ ++ code->code = gc2053_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int gc2053_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc2053_format_struct *ovfmt; ++ struct gc2053_win_size *wsize; ++ struct gc2053_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int gc2053_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc2053_info *info = to_state(sd); ++ struct gc2053_win_size *wsize = info->win; ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = wsize->width; ++ fmt->height = wsize->height; ++ fmt->code = wsize->mbus_code; ++ fmt->colorspace = wsize->colorspace; ++ *(unsigned int *)fmt->reserved = &wsize->sensor_info; ++ ++ printk("----%s, %d, width: %d, height: %d, code: %x\n", ++ __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int gc2053_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2053_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2053_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2053_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int gc2053_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int gc2053_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(gc2093_again_lut); i++) { ++ lut = &gc2093_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->index; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->index; ++} ++static int gc2053_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ struct gc2053_info *info = to_state(sd); ++ unsigned char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int gc2053_s_again(struct v4l2_subdev *sd, int again) ++{ ++ struct gc2053_info *info = to_state(sd); ++ struct again_lut *val_lut = gc2053_again_lut; ++ unsigned int reg_value = 0; ++ int ret = 0; ++ if(again < info->again->minimum || again > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(again); ++ } ++ ++ ret = gc2053_write(sd, 0xfe, 0x00); ++ ret += gc2053_write(sd, 0xb4, val_lut[again].regb4); ++ ret += gc2053_write(sd, 0xb3, val_lut[again].regb3); ++ ret += gc2053_write(sd, 0xb2, val_lut[again].regb2); ++ ret += gc2053_write(sd, 0xb8, val_lut[again].dpc); ++ ret += gc2053_write(sd, 0xb9, val_lut[again].blc); ++ if(ret < 0){ ++ printk("%s : gc2053_write error %d~~~~\n",__func__,__LINE__); ++ return ret; ++ } ++ ++ return 0; ++ ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int gc2053_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2053_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct gc2053_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = gc2053_write(sd, 0x04, value&0xff); ++ ret += gc2053_write(sd, 0x03, (value&0x3f00)>>8); ++ ++ return ret; ++} ++ ++static int gc2053_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc2053_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return gc2053_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc2053_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int gc2053_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc2053_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return gc2053_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return gc2053_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return gc2053_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return gc2053_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* gc2053_s_gain turns off auto gain */ ++ return gc2053_s_gain(sd, info->gain->val); ++ } ++ return gc2053_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return gc2053_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc2053_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return gc2053_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops gc2053_ctrl_ops = { ++ .s_ctrl = gc2053_s_ctrl, ++ .g_volatile_ctrl = gc2053_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int gc2053_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = gc2053_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int gc2053_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ gc2053_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int gc2053_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct gc2053_info *info = to_state(sd); ++ int ret = 0; ++ printk("%s:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",__func__); ++ if (enable) { ++ ret = gc2053_write_array(sd, gc2053_stream_on_mipi); ++ printk("gc2053 stream on\n"); ++ ++ } ++ else { ++ ret = gc2053_write_array(sd, gc2053_stream_off_mipi); ++ printk("gc2053 stream off\n"); ++ } ++ return ret; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops gc2053_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = gc2053_g_register, ++ .s_register = gc2053_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops gc2053_video_ops = { ++ .s_stream = gc2053_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops gc2053_pad_ops = { ++ //.enum_frame_interval = gc2053_enum_frame_interval, ++ //.num_frame_size = gc2053_enum_frame_size, ++ //.enum_mbus_code = gc2053_enum_mbus_code, ++ .set_fmt = gc2053_set_fmt, ++ .get_fmt = gc2053_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops gc2053_ops = { ++ .core = &gc2053_core_ops, ++ .video = &gc2053_video_ops, ++ .pad = &gc2053_pad_ops, ++}; ++ ++void gc2053_power_init_seq(struct gc2053_info *info) ++{ ++ *(volatile unsigned int*)0xb0010100 = 0x1; ++ //gpio_direction_output(4,0); ++ udelay(50); ++ gpio_direction_output(info->pwen.pin,info->pwen.active_level); ++ udelay(50); ++ ++ gpio_direction_output(info->reset.pin,!info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin,info->reset.active_level); ++ msleep(20); ++ gpio_direction_output(info->reset.pin,!info->reset.active_level); ++ msleep(50); ++ ++ gpio_direction_output(info->pwdn.pin,info->pwdn.active_level); ++ msleep(10); ++ gpio_direction_output(info->pwdn.pin,!info->pwdn.active_level); ++ msleep(10); ++ gpio_direction_output(info->pwdn.pin,info->pwdn.active_level); ++ msleep(10); ++} ++/* ----------------------------------------------------------------------- */ ++ ++static int gc2053_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ printk("~~~%s:%d~~~=====================================\n", __func__, __LINE__); ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct gc2053_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned long rate; ++ unsigned char value; ++ int mclk_index = -1; ++ printk("~~~%s:%d~~~\n", __func__, __LINE__); ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwen-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwen.pin = gpio; ++ info->pwen.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwdn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwdn.pin = gpio; ++ info->pwdn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ printk("gpio set ok ~~~%s:%d~~~\n", __func__, __LINE__); ++ ++ gc2053_power_init_seq(info); ++ v4l2_i2c_subdev_init(sd, client, &gc2053_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++#if 1 ++ ++#if 1 ++ char id_div[9]; ++ char id_mux[9]; ++ printk("%s:%d\n", __func__, __LINE__); ++ of_property_read_u32(client->dev.of_node, "ingenic,mclk", &mclk_index); ++ if(mclk_index == 0) { ++ memcpy(id_div, "div_cim0", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim0", sizeof(id_mux)); ++ } else if(mclk_index == 1) { ++ memcpy(id_div, "div_cim1", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim1", sizeof(id_mux)); ++ } else if(mclk_index == 2) { ++ memcpy(id_div, "div_cim2", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim2", sizeof(id_mux)); ++ } else ++ printk("Unkonwn mclk index\n"); ++ ++ ++ info->clk = v4l2_clk_get(&client->dev, id_div); ++#endif ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ++ ret = v4l2_clk_set_rate(info->clk, 27000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++#endif ++ ++#if 1 ++ /* Make sure it's an gc2053 */ ++ ret = gc2053_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an gc2053 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++#if 1 ++ /*IRCUT ctl 0:off 1:on*/ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &gc2053_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &gc2053_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &gc2053_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &gc2053_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &gc2053_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &gc2053_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 444858, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &gc2053_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 1350 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &gc2053_win_sizes[0]; ++ ++ gc2053_init(sd, 1); ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ /* test image */ ++// gc2053_write(sd,0x018c,0x01); ++ dev_info(&client->dev, "gc2053 Probed\n"); ++ return 0; ++#endif ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int gc2053_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct gc2053_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id gc2053_id[] = { ++ { "gc2053", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, gc2053_id); ++ ++static const struct of_device_id gc2053_of_match[] = { ++ {.compatible = "gc2053", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, gc2053_of_match); ++ ++ ++static struct i2c_driver gc2053_driver = { ++ .driver = { ++ .name = "gc2053", ++ .of_match_table = of_match_ptr(gc2053_of_match), ++ }, ++ .probe = gc2053_probe, ++ .remove = gc2053_remove, ++ .id_table = gc2053_id, ++}; ++ ++module_i2c_driver(gc2053_driver); ++MODULE_DESCRIPTION("A low-level driver for gc2053 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2093.c b/module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2093.c +new file mode 100644 +index 000000000..6fee0e215 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2093.c +@@ -0,0 +1,1255 @@ ++/* ++ * A V4L2 driver for OmniVision gc2093 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define GC2093_CHIP_ID_H (0x20) ++#define GC2093_CHIP_ID_L (0x93) ++#define GC2093_REG_CHIP_ID_HIGH 0x03f0 ++#define GC2093_REG_CHIP_ID_LOW 0x03f1 ++ ++ ++#define GC2093_REG_END 0xffff ++#define GC2093_REG_DELAY 0x00 ++#define GC2093_PAGE_REG 0xfd ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++ ++struct gc2093_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++}; ++ ++struct gc2093_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct gc2093_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ struct v4l2_ctrl *again_short; ++ ++ struct v4l2_clk *clk; ++ /* struct clk *sclka; */ ++ ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *exposure_short; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct gc2093_win_size *win; ++ ++ struct gc2093_gpio reset; ++ struct gc2093_gpio pwdn; ++ struct gc2093_gpio pwen; ++}; ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int index; ++ unsigned char regb0; ++ unsigned char regb1; ++ unsigned int regb2; ++ unsigned char regb3; ++ unsigned char regb4; ++ unsigned char regb5; ++ unsigned char regb6; ++ unsigned char regb7; ++ ++ unsigned int gain; ++}; ++ ++struct again_lut gc2093_again_lut[] = { ++ {0x0,0x00,0x00,0x01,0x00,0x68,0x07,0x00,0xf8,0}, ++ {0x1,0x00,0x10,0x01,0x0c,0x68,0x07,0x00,0xf8,14997}, ++ {0x2,0x00,0x20,0x01,0x1b,0x6c,0x07,0x00,0xf8,32233}, ++ {0x3,0x00,0x30,0xf01,0x2c,0x6c,0x07,0x00,0xf8,46808}, ++ {0x4,0x00,0x40,0x01,0x3f,0x7c,0x07,0x00,0xf8,60995}, ++ {0x5,0x00,0x50,0x02,0x16,0x7c,0x07,0x00,0xf8,75348}, ++ {0x6,0x00,0x60,0x02,0x35,0x7c,0x08,0x00,0xf9,90681}, ++ {0x7,0x00,0x70,0x03,0x16,0x7c,0x0b,0x00,0xfc,104361}, ++ {0x8,0x00,0x80,0x04,0x02,0x7c,0x0d,0x00,0xfe,118021}, ++ {0x9,0x00,0x90,0x04,0x31,0x7c,0x0f,0x08,0x00,131438}, ++ {0xA,0x00,0xa0,0x05,0x32,0x7c,0x11,0x08,0x02,145749}, ++ {0xB,0x00,0xb0,0x06,0x35,0x7c,0x14,0x08,0x05,159553}, ++ {0xC,0x00,0xc0,0x08,0x04,0x7c,0x16,0x08,0x07,172553}, ++ {0xD,0x00,0x5a,0x09,0x19,0x7c,0x18,0x08,0x09,183132}, ++ {0xE,0x00,0x83,0x0b,0x0f,0x7c,0x1b,0x08,0x0c,198614}, ++ {0xF,0x00,0x93,0x0d,0x12,0x7c,0x1e,0x08,0x0f,212697}, ++ {0x10,0x00,0x84,0x10,0x00,0x7c,0x22,0x08,0x13,226175}, ++ {0x11,0x00,0x94,0x12,0x3a,0x7c,0x26,0x08,0x17,240788}, ++ {0x12,0x00,0x5d,0x1a,0x02,0x7c,0x30,0x08,0x21,271536}, ++ {0x13,0x00,0x9b,0x1b,0x20,0x7c,0x30,0x08,0x21,272451}, ++ {0x14,0x00,0x8c,0x20,0x0f,0x7c,0x35,0x08,0x26,287144}, ++ {0x15,0x00,0x9c,0x26,0x07,0x7c,0x3b,0x08,0x2c,302425}, ++ {0x16,0x00,0xB6,0x36,0x21,0x7c,0x43,0x08,0x34,334228}, ++ {0x17,0x00,0xad,0x37,0x3a,0x7c,0x43,0x08,0x34,351574}, ++ {0x18,0x00,0xbd,0x3d,0x02,0x7c,0x43,0x08,0x34,367506}, ++}; ++ ++ ++static inline struct gc2093_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct gc2093_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct gc2093_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list gc2093_init_regs_1920_1080_60fps_mipi[] = { ++ /****system****/ ++ {0x03fe, 0xf0}, ++ {0x03fe, 0xf0}, ++ {0x03fe, 0xf0}, ++ {0x03fe, 0x00}, ++ {0x03f2, 0x00}, ++ {0x03f3, 0x00}, ++ {0x03f4, 0x36}, ++ {0x03f5, 0xc0}, ++ {0x03f6, 0x0B}, ++ {0x03f7, 0x01}, ++ // {0x03f8, 0x58}, //24Mhz ++ {0x03f8, 0x58}, //27Mhz ++ {0x03f9, 0x40}, ++ {0x03fc, 0x8e}, ++ /****CISCTL & NALOG****/ ++ {0x0087, 0x18}, ++ {0x00ee, 0x30}, ++ {0x00d0, 0xbf}, ++ {0x01a0, 0x00}, ++ {0x01a4, 0x40}, ++ {0x01a5, 0x40}, ++ {0x01a6, 0x40}, ++ {0x01af, 0x09}, ++ {0x0001, 0x00}, ++ {0x0002, 0x02}, ++ {0x0003, 0x04}, ++ {0x0004, 0x02}, ++ {0x0005, 0x02}, ++ {0x0006, 0x94}, ++ {0x0007, 0x00}, ++ {0x0008, 0x11}, ++ {0x0009, 0x00}, ++ {0x000a, 0x02}, ++ {0x000b, 0x00}, ++ {0x000c, 0x04}, ++ {0x000d, 0x04}, ++ {0x000e, 0x40}, ++ {0x000f, 0x07}, ++ {0x0010, 0x8c}, ++ {0x0013, 0x15}, ++ {0x0019, 0x0c}, ++ {0x0041, 0x04}, ++ {0x0042, 0xE2}, //frame length 0x04e2=1250 ++ ++ // {0x0041, 0x05}, //or dorp ++ // {0x0042, 0xE6}, //frame length 0x05E6=1350 ++ ++ {0x0053, 0x60}, ++ {0x008d, 0x92}, ++ {0x0090, 0x00}, ++ {0x00c7, 0xe1}, ++ {0x001b, 0x73}, ++ {0x0028, 0x0d}, ++ {0x0029, 0x24}, ++ {0x002b, 0x04}, ++ {0x002e, 0x23}, ++ {0x0037, 0x03}, ++ {0x0043, 0x04}, ++ {0x0044, 0x28}, ++ {0x004a, 0x01}, ++ {0x004b, 0x20}, ++ {0x0055, 0x28}, ++ {0x0066, 0x3f}, ++ {0x0068, 0x3f}, ++ {0x006b, 0x44}, ++ {0x0077, 0x00}, ++ {0x0078, 0x20}, ++ {0x007c, 0xa1}, ++ {0x00ce, 0x7c}, ++ {0x00d3, 0xd4}, ++ {0x00e6, 0x50}, ++ /****gain****/ ++ {0x00b6, 0xc0}, ++ {0x00b0, 0x68}, //0x60 ++ ++ {0x00b3,0x00}, ++ {0x00b8,0x01}, ++ {0x00b9,0x00}, ++ {0x00b1,0x01}, ++ {0x00b2,0x00}, ++ ++ /*****isp****/ ++ //{0x0101, 0x0c}, ++ {0x0102, 0x89}, ++ {0x0104, 0x01}, ++ {0x010f, 0x00}, ++ {0x0158, 0x00}, ++ {/*dark sun*/}, ++ {0x0123, 0x08}, ++ {0x0123, 0x00}, ++ {0x0120, 0x01}, ++ {0x0121, 0x04}, ++ {0x0122, 0xd8}, ++ {0x0124, 0x03}, ++ {0x0125, 0xff}, ++ {0x001a, 0x8c}, ++ {0x00c6, 0xe0}, ++ /****blk****/ ++ {0x0026, 0x30}, ++ {0x0142, 0x00}, ++ {0x0149, 0x1e}, ++ {0x014a, 0x0f}, ++ {0x014b, 0x00}, ++ {0x0155, 0x07}, ++ {0x0414, 0x78}, ++ {0x0415, 0x78}, ++ {0x0416, 0x78}, ++ {0x0417, 0x78}, ++ {0x0454, 0x78}, ++ {0x0455, 0x78}, ++ {0x0456, 0x78}, ++ {0x0457, 0x78}, ++ {0x04e0, 0x18}, ++ /****window****/ ++ {0x0192, 0x02}, ++ {0x0194, 0x03}, ++ {0x0195, 0x04}, ++ {0x0196, 0x38}, ++ {0x0197, 0x07}, ++ {0x0198, 0x80}, ++ /****DVP & MIP*****/ ++ {0x019a, 0x06}, ++ {0x007b, 0x2a}, ++ {0x0023, 0x2d}, ++ {0x0201, 0x27}, ++ {0x0202, 0x56}, ++ //{0x0203, 0xb6}, //try 0xce or 0x8e or drop ++ {0x0203, 0x8e}, //try 0xce or 0x8e or drop ++ {0x0212, 0x80}, ++ {0x0213, 0x07}, ++ {0x0215, 0x10}, ++ {0x003e, 0x91}, ++ {GC2093_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++#if 1 ++static struct regval_list gc2093_init_regs_1920_1080_30fps_mipi_lin[] = { ++ {0x03fe, 0xf0}, ++ {0x03fe, 0xf0}, ++ {0x03fe, 0xf0}, ++ {0x03fe, 0x00}, ++ {0x03f2, 0x00}, ++ {0x03f3, 0x00}, ++ {0x03f4, 0x36}, ++ {0x03f5, 0xc0}, ++ {0x03f6, 0x0A}, ++ {0x03f7, 0x01}, ++ {0x03f8, 0x24}, ++ {0x03f9, 0x10}, ++ {0x03fc, 0x8e}, ++ /****CISCTL & ANALOG****/ ++ {0x0087, 0x18}, ++ {0x00ee, 0x30}, ++ {0x00d0, 0xbf}, ++ {0x01a0, 0x00}, ++ {0x01a4, 0x40}, ++ {0x01a5, 0x40}, ++ {0x01a6, 0x40}, ++ {0x01af, 0x09}, ++ {0x0001, 0x00}, ++ {0x0002, 0x02}, ++ {0x0003, 0x04}, ++ {0x0004, 0x00}, ++ {0x0005, 0x02}, ++ {0x0006, 0xd5}, ++ {0x0007, 0x00}, ++ {0x0008, 0x8e},//vb=142 ++ {0x0009, 0x00}, ++ {0x000a, 0x02}, ++ {0x000b, 0x00}, ++ {0x000c, 0x04}, ++ {0x000d, 0x04}, ++ {0x000e, 0x40}, ++ {0x000f, 0x07}, ++ {0x0010, 0x8c}, ++ {0x0013, 0x15}, ++ {0x0019, 0x0c}, ++// {0x0041, 0x04},//1250 ++// {0x0042, 0xe2},//1250 ++ {0x0041, 0x05},//1350 jz ++ {0x0042, 0x46},//1350 jz ++ {0x0053, 0x60}, ++ {0x008d, 0x92}, ++ {0x0090, 0x00}, ++ {0x00c7, 0xe1}, ++ {0x001b, 0x73}, ++ {0x0028, 0x0d}, ++ {0x0029, 0x24}, ++ {0x002b, 0x04}, ++ {0x002e, 0x23}, ++ {0x0037, 0x03}, ++ {0x0043, 0x04}, ++ {0x0044, 0x38}, ++ {0x004a, 0x01}, ++ {0x004b, 0x28}, ++ {0x0055, 0x38}, ++ {0x006b, 0x44}, ++ {0x0077, 0x00}, ++ {0x0078, 0x20}, ++ {0x007c, 0xa1}, ++ {0x00ce, 0x7c}, ++ {0x00d3, 0xd4}, ++ {0x00e6, 0x50}, ++ /*gain*/ ++ {0x00b6, 0xc0}, ++ {0x00b0, 0x60}, ++ {0x00b3, 0x00}, ++ {0x00b8, 0x01}, ++ {0x00b9, 0x00}, ++ {0x00b1, 0x01}, ++ {0x00b2, 0x00}, ++ /*isp*/ ++ {0x0102, 0x89}, ++ {0x0104, 0x01}, ++ {0x010e, 0x00},//jz wdr -> lin ++ {0x010f, 0x00}, ++ {0x0158, 0x00}, ++ /*dark sun*/ ++ {0x0123, 0x08}, ++ {0x0123, 0x00}, ++ {0x0120, 0x00}, ++ {0x0121, 0x00}, ++ {0x0122, 0x0f}, ++ {0x0124, 0x03}, ++ {0x0125, 0xff}, ++ {0x0126, 0x3c}, ++ {0x001a, 0x8c}, ++ {0x00c6, 0xe0}, ++ /*blk*/ ++ {0x0026, 0x30}, ++ {0x0142, 0x00}, ++ {0x0149, 0x1e}, ++ {0x014a, 0x07}, ++ {0x014b, 0x80}, ++ {0x0155, 0x00}, ++ {0x0414, 0x78}, ++ {0x0415, 0x78}, ++ {0x0416, 0x78}, ++ {0x0417, 0x78}, ++ {0x04e0, 0x18}, ++ /*window*/ ++ {0x0192, 0x02}, ++ {0x0194, 0x03}, ++ {0x0195, 0x04}, ++ {0x0196, 0x38}, ++ {0x0197, 0x07}, ++ {0x0198, 0x80}, ++ {0x01b0, 0x01}, ++ {0x01b1, 0x00}, ++ {0x01b2, 0x20}, ++ {0x01b3, 0x00}, ++ {0x01b4, 0xf0}, ++ {0x01b5, 0x80}, ++ {0x01b6, 0x05}, ++ {0x01b8, 0x01}, ++ {0x01b9, 0xe0}, ++ {0x01ba, 0x01}, ++ {0x01bb, 0x80}, ++ /****DVP & MIPI****/ ++ {0x019a, 0x06}, ++ {0x007b, 0x2a}, ++ {0x0023, 0x2d}, ++ {0x0201, 0x27}, ++ {0x0202, 0x56}, ++// {0x0203, 0xb6}, ++ {0x0203, 0x8e}, ++ {0x0212, 0x80}, ++ {0x0213, 0x07}, ++ {0x0215, 0x12}, ++ /****HDR EN****/ ++ {0x0027, 0x70},//jz ++ {0x0215, 0x12},//jz ++ {0x024d, 0x00},//jz ++ {0x003e, 0x91}, ++ {GC2093_REG_END, 0x00}, /* END MARKER */ ++}; ++#endif ++ ++static struct regval_list gc2093_init_regs_1920_1080_15fps_mipi_wdr[] = { ++ {0x03fe, 0xf0}, ++ {0x03fe, 0xf0}, ++ {0x03fe, 0xf0}, ++ {0x03fe, 0x00}, ++ {0x03f2, 0x00}, ++ {0x03f3, 0x00}, ++ {0x03f4, 0x36}, ++ {0x03f5, 0xc0}, ++ {0x03f6, 0x0A}, ++ {0x03f7, 0x01}, ++ {0x03f8, 0x24}, ++ {0x03f9, 0x10}, ++ {0x03fc, 0x8e}, ++ /****CISCTL & ANALOG****/ ++ {0x0087, 0x18}, ++ {0x00ee, 0x30}, ++ {0x00d0, 0xbf}, ++ {0x01a0, 0x00}, ++ {0x01a4, 0x40}, ++ {0x01a5, 0x40}, ++ {0x01a6, 0x40}, ++ {0x01af, 0x09}, ++ {0x0001, 0x00}, ++ {0x0002, 0x02}, ++ {0x0003, 0x04}, ++ {0x0004, 0x00}, ++ {0x0005, 0x02}, ++ {0x0006, 0xd5}, ++ {0x0007, 0x00}, ++ {0x0008, 0x8e},//vb=142 ++ {0x0009, 0x00}, ++ {0x000a, 0x02}, ++ {0x000b, 0x00}, ++ {0x000c, 0x04}, ++ {0x000d, 0x04}, ++ {0x000e, 0x40}, ++ {0x000f, 0x07}, ++ {0x0010, 0x8c}, ++ {0x0013, 0x15}, ++ {0x0019, 0x0c}, ++// {0x0041, 0x04},//1250 ++// {0x0042, 0xe2},//1250 ++ {0x0041, 0x05},//1350 jz ++ {0x0042, 0x46},//1350 jz ++ {0x0053, 0x60}, ++ {0x008d, 0x92}, ++ {0x0090, 0x00}, ++ {0x00c7, 0xe1}, ++ {0x001b, 0x73}, ++ {0x0028, 0x0d}, ++ {0x0029, 0x24}, ++ {0x002b, 0x04}, ++ {0x002e, 0x23}, ++ {0x0037, 0x03}, ++ {0x0043, 0x04}, ++ {0x0044, 0x38}, ++ {0x004a, 0x01}, ++ {0x004b, 0x28}, ++ {0x0055, 0x38}, ++ {0x006b, 0x44}, ++ {0x0077, 0x00}, ++ {0x0078, 0x20}, ++ {0x007c, 0xa1}, ++ {0x00ce, 0x7c}, ++ {0x00d3, 0xd4}, ++ {0x00e6, 0x50}, ++ /*gain*/ ++ {0x00b6, 0xc0}, ++ {0x00b0, 0x60}, ++ {0x00b3, 0x00}, ++ {0x00b8, 0x01}, ++ {0x00b9, 0x00}, ++ {0x00b1, 0x01}, ++ {0x00b2, 0x00}, ++ /*isp*/ ++ {0x0102, 0x89}, ++ {0x0104, 0x01}, ++ {0x010e, 0x01}, ++ {0x010f, 0x00}, ++ {0x0158, 0x00}, ++ /*dark sun*/ ++ {0x0123, 0x08}, ++ {0x0123, 0x00}, ++ {0x0120, 0x00}, ++ {0x0121, 0x00}, ++ {0x0122, 0x0f}, ++ {0x0124, 0x03}, ++ {0x0125, 0xff}, ++ {0x0126, 0x3c}, ++ {0x001a, 0x8c}, ++ {0x00c6, 0xe0}, ++ /*blk*/ ++ {0x0026, 0x30}, ++ {0x0142, 0x00}, ++ {0x0149, 0x1e}, ++ {0x014a, 0x07}, ++ {0x014b, 0x80}, ++ {0x0155, 0x00}, ++ {0x0414, 0x78}, ++ {0x0415, 0x78}, ++ {0x0416, 0x78}, ++ {0x0417, 0x78}, ++ {0x04e0, 0x18}, ++ /*window*/ ++ {0x0192, 0x02}, ++ {0x0194, 0x03}, ++ {0x0195, 0x04}, ++ {0x0196, 0x38}, ++ {0x0197, 0x07}, ++ {0x0198, 0x80}, ++ {0x01b0, 0x01}, ++ {0x01b1, 0x00}, ++ {0x01b2, 0x20}, ++ {0x01b3, 0x00}, ++ {0x01b4, 0xf0}, ++ {0x01b5, 0x80}, ++ {0x01b6, 0x05}, ++ {0x01b8, 0x01}, ++ {0x01b9, 0xe0}, ++ {0x01ba, 0x01}, ++ {0x01bb, 0x80}, ++ /****DVP & MIPI****/ ++ {0x019a, 0x06}, ++ {0x007b, 0x2a}, ++ {0x0023, 0x2d}, ++ {0x0201, 0x27}, ++ {0x0202, 0x56}, ++// {0x0203, 0xb6}, ++ {0x0203, 0x8e}, ++ {0x0212, 0x80}, ++ {0x0213, 0x07}, ++ {0x0215, 0x12}, ++ /****HDR EN****/ ++ {0x0027, 0x71}, ++ {0x0215, 0x92}, ++ {0x024d, 0x01}, ++ {0x003e, 0x91}, ++ {GC2093_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list gc2093_stream_on_mipi[] = { ++ {GC2093_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list gc2093_stream_off_mipi[] = { ++ {GC2093_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int gc2093_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct gc2093_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ printk("i2c device addr : 0x%x~~~~~~~~~~~~~\n",client->addr); ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct gc2093_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != GC2093_REG_END) { ++ if (vals->reg_num == GC2093_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc2093_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int gc2093_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != GC2093_REG_END) { ++ if (vals->reg_num == GC2093_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc2093_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int gc2093_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ return 0; ++} ++ ++static int gc2093_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ return 0; ++} ++ ++static int gc2093_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2093_info *info = to_state(sd); ++ int ret = 0; ++ printk("%s:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",__func__); ++ ret = gc2093_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int gc2093_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ret = gc2093_read(sd, 0x03f0, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC2093_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = gc2093_read(sd, 0x03f1, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC2093_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++static struct gc2093_win_size gc2093_win_sizes[] = { ++ { ++ .sensor_info.mipi_cfg.clk = 650, //data rate = 650Mbps/lane, clk is about 650Mbps. ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = 0, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .sensor_info.fps = 25 << 16 | 1, ++ .sensor_info.wdr_en = 0, ++ ++ .width = 1920, ++ .height = 1080, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ //.regs = gc2093_init_regs_1920_1080_30fps_mipi_lin, ++ ++ .regs = gc2093_init_regs_1920_1080_60fps_mipi, ++ }, ++#if 0 ++ { ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = 0, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_WDR_2_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_VC_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .sensor_info ++ .width = 1920, ++ .height = 1080, ++ .fps = 15 << 16 | 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = gc2093_init_regs_1920_1080_15fps_mipi_wdr, ++ }, ++#endif ++}; ++ ++static int gc2093_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_gc2093_FMTS) ++ return -EINVAL; ++ ++ code->code = gc2093_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int gc2093_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc2093_format_struct *ovfmt; ++ struct gc2093_win_size *wsize; ++ struct gc2093_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int gc2093_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc2093_info *info = to_state(sd); ++ struct gc2093_win_size *wsize = info->win; ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = wsize->width; ++ fmt->height = wsize->height; ++ fmt->code = wsize->mbus_code; ++ fmt->colorspace = wsize->colorspace; ++ *(unsigned int *)fmt->reserved = &wsize->sensor_info; ++ ++ printk("----%s, %d, width: %d, height: %d, code: %x\n", ++ __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int gc2093_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int gc2093_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int gc2093_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(gc2093_again_lut); i++) { ++ lut = &gc2093_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->index; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->index; ++} ++ ++static int gc2093_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ return 0; ++} ++ ++/*set analog gain db value, map value to sensor register.*/ ++static int gc2093_s_again(struct v4l2_subdev *sd, int again) ++{ ++ struct gc2093_info *info = to_state(sd); ++ struct again_lut *val_lut = gc2093_again_lut; ++ unsigned int reg_value = 0; ++ int ret = 0; ++ if(again < info->again->minimum || again > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(again); ++ } ++ ++ ret += gc2093_write(sd,0xb4,val_lut[reg_value].regb0); ++ ret += gc2093_write(sd,0xb3,val_lut[reg_value].regb1); ++ ret += gc2093_write(sd,0xb8,val_lut[reg_value].regb2); ++ ret += gc2093_write(sd,0xb9,val_lut[reg_value].regb3); ++ ret += gc2093_write(sd,0xce,val_lut[reg_value].regb4); ++ ret += gc2093_write(sd,0xc2,val_lut[reg_value].regb5); ++ ret += gc2093_write(sd,0xcf,val_lut[reg_value].regb6); ++ ret += gc2093_write(sd,0xd9,val_lut[reg_value].regb7); ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int gc2093_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct gc2093_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = gc2093_write(sd, 0x04, value & 0xff); ++ ret += gc2093_write(sd, 0x03, (value>>8)&0x3f); ++ ++ return ret; ++} ++ ++static int gc2093_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc2093_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return gc2093_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc2093_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int gc2093_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc2093_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return gc2093_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return gc2093_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return gc2093_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return gc2093_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* gc2093_s_gain turns off auto gain */ ++ return gc2093_s_gain(sd, info->gain->val); ++ } ++ return gc2093_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return gc2093_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc2093_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return gc2093_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops gc2093_ctrl_ops = { ++ .s_ctrl = gc2093_s_ctrl, ++ .g_volatile_ctrl = gc2093_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int gc2093_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = gc2093_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int gc2093_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ gc2093_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int gc2093_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct gc2093_info *info = to_state(sd); ++ int ret = 0; ++ printk("%s:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",__func__); ++ if (enable) { ++ ret = gc2093_write_array(sd, gc2093_stream_on_mipi); ++ printk("gc2093 stream on\n"); ++ ++ } ++ else { ++ ret = gc2093_write_array(sd, gc2093_stream_off_mipi); ++ printk("gc2093 stream off\n"); ++ } ++ return ret; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops gc2093_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = gc2093_g_register, ++ .s_register = gc2093_s_register, ++#endif ++}; ++ ++static const struct v4l2_subdev_video_ops gc2093_video_ops = { ++ .s_stream = gc2093_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops gc2093_pad_ops = { ++ //.enum_frame_interval = gc2093_enum_frame_interval, ++ //.num_frame_size = gc2093_enum_frame_size, ++ //.enum_mbus_code = gc2093_enum_mbus_code, ++ .set_fmt = gc2093_set_fmt, ++ .get_fmt = gc2093_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops gc2093_ops = { ++ .core = &gc2093_core_ops, ++ .video = &gc2093_video_ops, ++ .pad = &gc2093_pad_ops, ++}; ++ ++void gc2093_power_init_seq(struct gc2093_info *info) ++{ ++ *(volatile unsigned int*)0xb0010100 = 0x1; ++ gpio_direction_output(4,0); ++ udelay(50); ++ gpio_direction_output(info->pwen.pin,info->pwen.active_level); ++ udelay(50); ++ ++ gpio_direction_output(info->reset.pin,!info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin,info->reset.active_level); ++ msleep(20); ++ gpio_direction_output(info->reset.pin,!info->reset.active_level); ++ msleep(50); ++ ++ gpio_direction_output(info->pwdn.pin,info->pwdn.active_level); ++ msleep(10); ++ gpio_direction_output(info->pwdn.pin,!info->pwdn.active_level); ++ msleep(10); ++ gpio_direction_output(info->pwdn.pin,info->pwdn.active_level); ++ msleep(10); ++} ++/* ----------------------------------------------------------------------- */ ++ ++static int gc2093_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ printk("~~~%s:%d~~~=====================================\n", __func__, __LINE__); ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct gc2093_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned long rate; ++ unsigned char value; ++ printk("~~~%s:%d~~~\n", __func__, __LINE__); ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwen-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwen.pin = gpio; ++ info->pwen.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwdn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwdn.pin = gpio; ++ info->pwdn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ printk("gpio set ok ~~~%s:%d~~~\n", __func__, __LINE__); ++ ++ gc2093_power_init_seq(info); ++ v4l2_i2c_subdev_init(sd, client, &gc2093_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++#if 1 ++ info->clk = v4l2_clk_get(&client->dev, "div_cim0"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ++ ret = v4l2_clk_set_rate(info->clk, 27000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++#endif ++ ++#if 1 ++ /* Make sure it's an gc2093 */ ++ ret = gc2093_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an gc2093 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++#if 1 ++ /*IRCUT ctl 0:off 1:on*/ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 367506, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1350 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &gc2093_win_sizes[0]; ++ ++ gc2093_init(sd, 1); ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ /* test image */ ++// gc2093_write(sd,0x018c,0x01); ++ dev_info(&client->dev, "gc2093 Probed\n"); ++ return 0; ++#endif ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int gc2093_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct gc2093_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id gc2093_id[] = { ++ { "gc2093b", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, gc2093_id); ++ ++static const struct of_device_id gc2093_of_match[] = { ++ {.compatible = "gc2093b", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, gc2093_of_match); ++ ++ ++static struct i2c_driver gc2093_driver = { ++ .driver = { ++ .name = "gc2093b", ++ .of_match_table = of_match_ptr(gc2093_of_match), ++ }, ++ .probe = gc2093_probe, ++ .remove = gc2093_remove, ++ .id_table = gc2093_id, ++}; ++ ++module_i2c_driver(gc2093_driver); ++MODULE_DESCRIPTION("A low-level driver for gc2093 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2155.c b/module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2155.c +new file mode 100644 +index 000000000..ef7f2c8ad +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/gc2155.c +@@ -0,0 +1,1516 @@ ++/* ++ * A V4L2 driver for OmniVision GC2155 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define GC2155_CHIP_ID_H (0x21) ++#define GC2155_CHIP_ID_L (0x55) ++#define GC2155_REG_END 0xff ++#define GC2155_REG_DELAY 0x00 ++ ++#define AGAIN_MAX_DB 0x64 ++#define DGAIN_MAX_DB 0x64 ++#define LOG2_GAIN_SHIFT 16 ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++ ++struct gc2155_win_size { ++ unsigned int width; ++ unsigned int height; ++ struct sensor_info sensor_info; ++ unsigned int mbus_code; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++}; ++ ++struct gc2155_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct gc2155_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ struct v4l2_ctrl *again_short; ++ ++ struct v4l2_clk *clk; ++ struct clk *sclka; ++ ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *exposure_short; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct gc2155_win_size *win; ++ ++ struct gc2155_gpio pwdn; ++ struct gc2155_gpio reset; ++}; ++ ++ ++static inline struct gc2155_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct gc2155_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct gc2155_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++ ++static struct regval_list gc2155_init_regs[] = { ++ {0xfe,0xf0}, ++ {0xfe,0xf0}, ++ {0xfe,0xf0}, ++ {0xfc,0x06}, ++ {0xf6,0x00}, ++ {0xf7,0x1d}, ++ {0xf8,0x84}, ++ {0xfa,0x00}, ++ {0xf9,0xfe}, ++ {0xf2,0x00}, ++ {0xfe,0x00}, ++ {0x03,0x04}, ++ {0x04,0xe2}, ++ {0x09,0x00}, ++ {0x0a,0x00}, ++ {0x0b,0x00}, ++ {0x0c,0x00}, ++ {0x0d,0x04}, ++ {0x0e,0xc0}, ++ {0x0f,0x06}, ++ {0x10,0x50}, ++ {0x12,0x2e}, ++ {0x17,0x14}, // mirror ++ {0x18,0x02}, ++ {0x19,0x0e}, ++ {0x1a,0x01}, ++ {0x1b,0x4b}, ++ {0x1c,0x07}, ++ {0x1d,0x10}, ++ {0x1e,0x98}, ++ {0x1f,0x78}, ++ {0x20,0x05}, ++ {0x21,0x40}, ++ {0x22,0xf0}, ++ {0x24,0x16}, ++ {0x25,0x01}, ++ {0x26,0x10}, ++ {0x2d,0x40}, ++ {0x30,0x01}, ++ {0x31,0x90}, ++ {0x33,0x04}, ++ {0x34,0x01}, ++ {0xfe,0x00}, ++ {0x80,0xff}, ++ {0x81,0x2c}, ++ {0x82,0xfa}, ++ {0x83,0x00}, ++ {0x84,0x02}, //y u yv ++ {0x85,0x08}, ++ {0x86,0x02}, ++ {0x89,0x03}, ++ {0x8a,0x00}, ++ {0x8b,0x00}, ++ {0xb0,0x55}, ++ {0xc3,0x11}, //00 ++ {0xc4,0x20}, ++ {0xc5,0x30}, ++ {0xc6,0x38}, ++ {0xc7,0x40}, ++ {0xec,0x02}, ++ {0xed,0x04}, ++ {0xee,0x60}, ++ {0xef,0x90}, ++ {0xb6,0x01}, ++ {0x90,0x01}, ++ {0x91,0x00}, ++ {0x92,0x00}, ++ {0x93,0x00}, ++ {0x94,0x00}, ++ {0x95,0x04}, ++ {0x96,0xb0}, ++ {0x97,0x06}, ++ {0x98,0x40}, ++ {0xfe,0x00}, ++ {0x18,0x02}, ++ {0x40,0x42}, ++ {0x41,0x00}, ++ {0x43,0x5b},//0X54 ++ {0x5e,0x00}, ++ {0x5f,0x00}, ++ {0x60,0x00}, ++ {0x61,0x00}, ++ {0x62,0x00}, ++ {0x63,0x00}, ++ {0x64,0x00}, ++ {0x65,0x00}, ++ {0x66,0x20}, ++ {0x67,0x20}, ++ {0x68,0x20}, ++ {0x69,0x20}, ++ {0x6a,0x08}, ++ {0x6b,0x08}, ++ {0x6c,0x08}, ++ {0x6d,0x08}, ++ {0x6e,0x08}, ++ {0x6f,0x08}, ++ {0x70,0x08}, ++ {0x71,0x08}, ++ {0x72,0xf0}, ++ {0x7e,0x3c}, ++ {0x7f,0x00}, ++ {0xfe,0x00}, ++ {0xfe,0x01}, ++ {0x01,0x08}, ++ {0x02,0xc0}, ++ {0x03,0x04}, ++ {0x04,0x90}, ++ {0x05,0x30}, ++ {0x06,0x98}, ++ {0x07,0x28}, ++ {0x08,0x6c}, ++ {0x09,0x00}, ++ {0x0a,0xc2}, ++ {0x0b,0x11}, ++ {0x0c,0x10}, ++ {0x13,0x2d}, ++ {0x17,0x00}, ++ {0x1c,0x11}, ++ {0x1e,0x61}, ++ {0x1f,0x30}, ++ {0x20,0x40}, ++ {0x22,0x80}, ++ {0x23,0x20}, ++ {0x12,0x35}, ++ {0x15,0x50}, ++ {0x10,0x31}, ++ {0x3e,0x28}, ++ {0x3f,0xe0}, ++ {0x40,0xe0}, ++ {0x41,0x08}, ++ {0xfe,0x02}, ++ {0x0f,0x05}, ++ {0xfe,0x02}, ++ {0x90,0x6c}, ++ {0x91,0x03}, ++ {0x92,0xc4}, ++ {0x97,0x64}, ++ {0x98,0x88}, ++ {0x9d,0x08}, ++ {0xa2,0x11}, ++ {0xfe,0x00}, ++ {0xfe,0x02}, ++ {0x80,0xc1}, ++ {0x81,0x08}, ++ {0x82,0x05}, ++ {0x83,0x04}, ++ {0x86,0x80}, ++ {0x87,0x30}, ++ {0x88,0x15}, ++ {0x89,0x80}, ++ {0x8a,0x60}, ++ {0x8b,0x30}, ++ {0xfe,0x01}, ++ {0x21,0x14}, ++ {0xfe,0x02}, ++ {0x3c,0x06}, ++ {0x3d,0x40}, ++ {0x48,0x30}, ++ {0x49,0x06}, ++ {0x4b,0x08}, ++ {0x4c,0x20}, ++ {0xa3,0x50}, ++ {0xa4,0x30}, ++ {0xa5,0x40}, ++ {0xa6,0x80}, ++ {0xab,0x40}, ++ {0xae,0x0c}, ++ {0xb3,0x42}, ++ {0xb4,0x24}, ++ {0xb6,0x50}, ++ {0xb7,0x01}, ++ {0xb9,0x28}, ++ {0xfe,0x00}, ++ {0xfe,0x02}, ++ {0x10,0x0d}, ++ {0x11,0x12}, ++ {0x12,0x17}, ++ {0x13,0x1c}, ++ {0x14,0x27}, ++ {0x15,0x34}, ++ {0x16,0x44}, ++ {0x17,0x55}, ++ {0x18,0x6e}, ++ {0x19,0x81}, ++ {0x1a,0x91}, ++ {0x1b,0x9c}, ++ {0x1c,0xaa}, ++ {0x1d,0xbb}, ++ {0x1e,0xca}, ++ {0x1f,0xd5}, ++ {0x20,0xe0}, ++ {0x21,0xe7}, ++ {0x22,0xed}, ++ {0x23,0xf6}, ++ {0x24,0xfb}, ++ {0x25,0xff}, ++ {0xfe,0x02}, ++ {0x26,0x0d}, ++ {0x27,0x12}, ++ {0x28,0x17}, ++ {0x29,0x1c}, ++ {0x2a,0x27}, ++ {0x2b,0x34}, ++ {0x2c,0x44}, ++ {0x2d,0x55}, ++ {0x2e,0x6e}, ++ {0x2f,0x81}, ++ {0x30,0x91}, ++ {0x31,0x9c}, ++ {0x32,0xaa}, ++ {0x33,0xbb}, ++ {0x34,0xca}, ++ {0x35,0xd5}, ++ {0x36,0xe0}, ++ {0x37,0xe7}, ++ {0x38,0xed}, ++ {0x39,0xf6}, ++ {0x3a,0xfb}, ++ {0x3b,0xff}, ++ {0xfe,0x02}, ++ {0xd1,0x28}, ++ {0xd2,0x28}, ++ {0xdd,0x14}, ++ {0xde,0x88}, ++ {0xed,0x80}, ++ {0xfe,0x01}, ++ {0xc2,0x1f}, ++ {0xc3,0x13}, ++ {0xc4,0x0e}, ++ {0xc8,0x16}, ++ {0xc9,0x0f}, ++ {0xca,0x0c}, ++ {0xbc,0x52}, ++ {0xbd,0x2c}, ++ {0xbe,0x27}, ++ {0xb6,0x47}, ++ {0xb7,0x32}, ++ {0xb8,0x30}, ++ {0xc5,0x00}, ++ {0xc6,0x00}, ++ {0xc7,0x00}, ++ {0xcb,0x00}, ++ {0xcc,0x00}, ++ {0xcd,0x00}, ++ {0xbf,0x0e}, ++ {0xc0,0x00}, ++ {0xc1,0x00}, ++ {0xb9,0x08}, ++ {0xba,0x00}, ++ {0xbb,0x00}, ++ {0xaa,0x0a}, ++ {0xab,0x0c}, ++ {0xac,0x0d}, ++ {0xad,0x02}, ++ {0xae,0x06}, ++ {0xaf,0x05}, ++ {0xb0,0x00}, ++ {0xb1,0x05}, ++ {0xb2,0x02}, ++ {0xb3,0x04}, ++ {0xb4,0x04}, ++ {0xb5,0x05}, ++ {0xd0,0x00}, ++ {0xd1,0x00}, ++ {0xd2,0x00}, ++ {0xd6,0x02}, ++ {0xd7,0x00}, ++ {0xd8,0x00}, ++ {0xd9,0x00}, ++ {0xda,0x00}, ++ {0xdb,0x00}, ++ {0xd3,0x00}, ++ {0xd4,0x00}, ++ {0xd5,0x00}, ++ {0xa4,0x04}, ++ {0xa5,0x00}, ++ {0xa6,0x77}, ++ {0xa7,0x77}, ++ {0xa8,0x77}, ++ {0xa9,0x77}, ++ {0xa1,0x80}, ++ {0xa2,0x80}, ++ {0xfe,0x01}, ++ {0xdc,0x35}, ++ {0xdd,0x28}, ++ {0xdf,0x0d}, ++ {0xe0,0x70}, ++ {0xe1,0x78}, ++ {0xe2,0x70}, ++ {0xe3,0x78}, ++ {0xe6,0x90}, ++ {0xe7,0x70}, ++ {0xe8,0x90}, ++ {0xe9,0x70}, ++ {0xfe,0x00}, ++ {0xfe,0x01}, ++ {0x4f,0x00}, ++ {0x4f,0x00}, ++ {0x4b,0x01}, ++ {0x4f,0x00}, ++ {0x4c,0x01}, ++ {0x4d,0x71}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x91}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x50}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x70}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x90}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0xb0}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0xd0}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x4f}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x6f}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x8f}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0xaf}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0xcf}, ++ {0x4e,0x02}, ++ {0x4c,0x01}, ++ {0x4d,0x6e}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x8e}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xae}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xce}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x4d}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x6d}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x8d}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xad}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xcd}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x4c}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x6c}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x8c}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xac}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xcc}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xec}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x4b}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x6b}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x8b}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0xab}, ++ {0x4e,0x03}, ++ {0x4c,0x01}, ++ {0x4d,0x8a}, ++ {0x4e,0x04}, ++ {0x4c,0x01}, ++ {0x4d,0xaa}, ++ {0x4e,0x04}, ++ {0x4c,0x01}, ++ {0x4d,0xca}, ++ {0x4e,0x04}, ++ {0x4c,0x01}, ++ {0x4d,0xa9}, ++ {0x4e,0x04}, ++ {0x4c,0x01}, ++ {0x4d,0xc9}, ++ {0x4e,0x04}, ++ {0x4c,0x01}, ++ {0x4d,0xcb}, ++ {0x4e,0x05}, ++ {0x4c,0x01}, ++ {0x4d,0xeb}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x0b}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x2b}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x4b}, ++ {0x4e,0x05}, ++ {0x4c,0x01}, ++ {0x4d,0xea}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x0a}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x2a}, ++ {0x4e,0x05}, ++ {0x4c,0x02}, ++ {0x4d,0x6a}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x29}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x49}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x69}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x89}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0xa9}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0xc9}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x48}, ++ {0x4e,0x06}, ++ {0x4c,0x02}, ++ {0x4d,0x68}, ++ {0x4e,0x06}, ++ {0x4c,0x03}, ++ {0x4d,0x09}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xa8}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xc8}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xe8}, ++ {0x4e,0x07}, ++ {0x4c,0x03}, ++ {0x4d,0x08}, ++ {0x4e,0x07}, ++ {0x4c,0x03}, ++ {0x4d,0x28}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0x87}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xa7}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xc7}, ++ {0x4e,0x07}, ++ {0x4c,0x02}, ++ {0x4d,0xe7}, ++ {0x4e,0x07}, ++ {0x4c,0x03}, ++ {0x4d,0x07}, ++ {0x4e,0x07}, ++ {0x4f,0x01}, ++ {0xfe,0x01}, ++ {0x50,0x80}, ++ {0x51,0xa8}, ++ {0x52,0x57}, ++ {0x53,0x38}, ++ {0x54,0xc7}, ++ {0x56,0x0e}, ++ {0x58,0x08}, ++ {0x5b,0x00}, ++ {0x5c,0x74}, ++ {0x5d,0x8b}, ++ {0x61,0xd3}, ++ {0x62,0x90}, ++ {0x63,0xaa}, ++ {0x65,0x04}, ++ {0x67,0xb2}, ++ {0x68,0xac}, ++ {0x69,0x00}, ++ {0x6a,0xb2}, ++ {0x6b,0xac}, ++ {0x6c,0xdc}, ++ {0x6d,0xb0}, ++ {0x6e,0x30}, ++ {0x6f,0x40}, ++ {0x70,0x05}, ++ {0x71,0x80}, ++ {0x72,0x80}, ++ {0x73,0x30}, ++ {0x74,0x01}, ++ {0x75,0x01}, ++ {0x7f,0x08}, ++ {0x76,0x70}, ++ {0x77,0x48}, ++ {0x78,0xa0}, ++ {0xfe,0x00}, ++ {0xfe,0x02}, ++ {0xc0,0x01}, ++ {0xc1,0x4a}, ++ {0xc2,0xf3}, ++ {0xc3,0xfc}, ++ {0xc4,0xe4}, ++ {0xc5,0x48}, ++ {0xc6,0xec}, ++ {0xc7,0x45}, ++ {0xc8,0xf8}, ++ {0xc9,0x02}, ++ {0xca,0xfe}, ++ {0xcb,0x42}, ++ {0xcc,0x00}, ++ {0xcd,0x45}, ++ {0xce,0xf0}, ++ {0xcf,0x00}, ++ {0xe3,0xf0}, ++ {0xe4,0x45}, ++ {0xe5,0xe8}, ++ {0xfe,0x01}, ++ {0x9f,0x42}, ++ {0xfe,0x00}, ++ {0xfe,0x00}, ++ {0xf2,0x0f}, ++ {0xfe,0x00}, ++ {0x05,0x01}, ++ {0x06,0x56}, ++ {0x07,0x00}, ++ {0x08,0x32}, ++ {0xfe,0x01}, ++ {0x25,0x00}, ++ {0x26,0xfa}, ++ {0x27,0x04}, ++ {0x28,0xe2}, //20fps ++ {0x29,0x06}, ++ {0x2a,0xd6}, //16fps ++ {0x2b,0x07}, ++ {0x2c,0xd0}, //12fps ++ {0x2d,0x0b}, ++ {0x2e,0xb8}, //8fps ++ {0xfe,0x00}, ++ {0xfe,0x00}, ++ {0xfa,0x00}, ++ {0xfd,0x01}, ++ {0xfe,0x00}, ++ {0x90,0x01}, ++ {0x91,0x00}, ++ {0x92,0x00}, ++ {0x93,0x00}, ++ {0x95,0x04},// win_size 320 * 240 ++ {0x96,0xb0}, ++ {0x97,0x06}, ++ {0x98,0x40}, ++ ++ ++ {0x99,0x11}, ++ {0x9a,0x06}, ++ {0xfe,0x01}, ++ {0xec,0x01}, ++ {0xed,0x02}, ++ {0xee,0x30}, ++ {0xef,0x48}, ++ {0xfe,0x01}, ++ {0x74,0x00}, ++ {0xfe,0x01}, ++ {0x01,0x04}, ++ {0x02,0x60}, ++ {0x03,0x02}, ++ {0x04,0x48}, ++ {0x05,0x18}, ++ {0x06,0x4c}, ++ {0x07,0x14}, ++ {0x08,0x36}, ++ {0x0a,0xc0}, ++ {0x21,0x14}, ++ {0xfe,0x00}, ++ {0xfe,0x00}, ++ {0xc3,0x11}, ++ {0xc4,0x20}, ++ {0xc5,0x30}, ++ {0xfa,0x11},//pclk rate ++ {0x86,0x02},//pclk polar ++ {0xfe,0x00}, ++ ++#if 1 ++ // 720P init ++ {0xfe,0x00}, ++ {0xb6,0x01}, ++ {0xfd,0x00}, ++ ++ //subsample ++ {0xfe,0x00}, ++ {0x99,0x55}, ++ {0x9a,0x06}, ++ {0x9b,0x00}, ++ {0x9c,0x00}, ++ {0x9d,0x01}, ++ {0x9e,0x23}, ++ {0x9f,0x00}, ++ {0xa0,0x00}, ++ {0xa1,0x01}, ++ {0xa2,0x23}, ++ //crop window ++ {0x90,0x01}, ++ {0x91,0x00}, ++ {0x92,0x78}, ++ {0x93,0x00}, ++ {0x94,0x00}, ++ {0x95,0x02}, ++ {0x96,0xd0}, ++ {0x97,0x05}, ++ {0x98,0x00}, ++ // AWB ++ {0xfe,0x00}, ++ {0xec,0x02}, ++ {0xed,0x04}, ++ {0xee,0x60}, ++ {0xef,0x90}, ++ {0xfe,0x01}, ++ {0x74,0x01}, ++ // AEC ++ {0xfe,0x01}, ++ {0x01,0x08}, ++ {0x02,0xc0}, ++ {0x03,0x04}, ++ {0x04,0x90}, ++ {0x05,0x30}, ++ {0x06,0x98}, ++ {0x07,0x28}, ++ {0x08,0x6c}, ++ {0x0a,0xc2}, ++ {0x21,0x15}, ++ {0xfe,0x00}, ++#if 0 ++ //banding setting 20fps fixed/// ++ {0xfe,0x00}, ++ {0x03,0x03}, ++ {0x04,0xe8}, ++ {0x05,0x01}, ++ {0x06,0x56}, ++ {0x07,0x00}, ++ {0x08,0x32}, ++ {0xfe,0x01}, ++ {0x25,0x00}, ++ {0x26,0xfa}, ++ {0x27,0x04}, ++ {0x28,0xe2}, //20fps ++ {0x29,0x04}, ++ {0x2a,0xe2}, //16fps 5dc ++ {0x2b,0x04}, ++ {0x2c,0xe2}, //16fps 6d6 5dc ++ {0x2d,0x04}, ++ {0x2e,0xe2}, //8fps bb8 ++ {0x3c,0x00}, //8fps ++ {0xfe,0x00}, ++#endif ++#endif ++#if 0 ++ /*qvga*/ ++ {0xfe,0x00}, ++ {0xfd,0x01}, ++ // crop window ++ {0xfe,0x00}, ++ {0x90,0x01}, ++ {0x91,0x00}, ++ {0x92,0xb4}, ++ {0x93,0x00}, ++ {0x94,0xf0}, ++ {0x95,0x00}, ++ {0x96,0xf0}, ++ {0x97,0x01}, ++ {0x98,0x40}, ++ // AWB ++ {0xfe,0x00}, ++ {0xec,0x01}, ++ {0xed,0x02}, ++ {0xee,0x30}, ++ {0xef,0x48}, ++ {0xfe,0x01}, ++ {0x74,0x00}, ++ //// AEC ++ {0xfe,0x01}, ++ {0x01,0x04}, ++ {0x02,0x60}, ++ {0x03,0x02}, ++ {0x04,0x48}, ++ {0x05,0x18}, ++ {0x06,0x4c}, ++ {0x07,0x14}, ++ {0x08,0x36}, ++ {0x0a,0xc0}, ++ {0x21,0x14}, ++#if 0 ++ {0x25,0x01}, ++ {0x26,0x90}, ++ {0x27,0x03}, ++ {0x28,0x20}, //50fps ++ {0x29,0x03}, ++ {0x2a,0x20}, ++ {0x2b,0x03}, ++ {0x2c,0x20}, ++ {0x2d,0x03}, ++ {0x2e,0x20}, ++#endif ++ {0xfe,0x00}, ++ //// gamma ++ {0xfe,0x00}, ++ {0xc3,0x11}, ++ {0xc4,0x20}, ++ {0xc5,0x30}, ++ {0xfe,0x00}, ++#endif ++ ++ ++ {0xfe, 0x00}, ++ {0x8d, 0x08}, ++ ++ ++ {GC2155_REG_END, 0x00}, /* END MARKER */ ++ ++}; ++ ++ ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list gc2155_stream_on_mipi[] = { ++ /* ++ {0x3000, 0x00}, ++ */ ++ {GC2155_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list gc2155_stream_off_mipi[] = { ++ /* ++ {0x3000, 0x01}, ++ */ ++ {GC2155_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int gc2155_read(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 1, ++ .buf = ®, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc2155_write(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ unsigned char buf[2] = {reg, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc2155_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != GC2155_REG_END) { ++ if (vals->reg_num == GC2155_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc2155_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int gc2155_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != GC2155_REG_END) { ++ if (vals->reg_num == GC2155_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc2155_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++static int gc2155_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ret = gc2155_read(sd, 0xf0, &v); ++// pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC2155_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = gc2155_read(sd, 0xf1, &v); ++// pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC2155_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++static struct gc2155_win_size gc2155_win_sizes[] = { ++ { ++ .width = 1280, ++ .height = 720, ++ .sensor_info.fps = 25 << 16 | 1, ++ .sensor_info.total_width = 1280, ++ .sensor_info.total_height = 720, ++ .sensor_info.wdr_en = 0, ++ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = gc2155_init_regs, ++ }, ++}; ++ ++#if 0 ++static int gc2155_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= N_GC2155_FMTS) ++ return -EINVAL; ++ ++ code->code = gc2155_formats[code->index].mbus_code; ++ return 0; ++} ++#endif ++ ++/* ++ * Set a format. ++ */ ++static int gc2155_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int gc2155_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc2155_info *info = to_state(sd); ++ struct gc2155_win_size *wsize = info->win; ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = wsize->width; ++ fmt->height = wsize->height; ++ fmt->code = wsize->mbus_code; ++ fmt->colorspace = wsize->colorspace; ++ *(unsigned int *)fmt->reserved = (unsigned int)&wsize->sensor_info; ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int gc2155_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2155_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2155_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2155_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int gc2155_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int gc2155_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ unsigned int again=(gain*20)>>LOG2_GAIN_SHIFT; ++ // Limit Max gain ++ if(again>AGAIN_MAX_DB+DGAIN_MAX_DB) again=AGAIN_MAX_DB+DGAIN_MAX_DB; ++ return again; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ return (((int32_t)regval)<win->sensor_info.wdr_en) { ++ total_height *= 2; ++ shs = total_height - value - 1; ++ ret = gc2155_write(sd, 0x3024, (unsigned char)(shs & 0xff)); ++ ret += gc2155_write(sd, 0x3025, (unsigned char)((shs >> 8) & 0xff)); ++ ret += gc2155_write(sd, 0x3026, (unsigned char)((shs >> 16) & 0x3)); ++ } else { ++ shs = total_height - value - 1; ++ ret = gc2155_write(sd, 0x3020, (unsigned char)(shs & 0xff)); ++ ret += gc2155_write(sd, 0x3021, (unsigned char)((shs >> 8) & 0xff)); ++ ret += gc2155_write(sd, 0x3022, (unsigned char)((shs >> 16) & 0x3)); ++ } ++#endif ++ return ret; ++} ++ ++static int gc2155_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc2155_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return gc2155_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc2155_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int gc2155_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc2155_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return gc2155_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return gc2155_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return gc2155_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return gc2155_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* gc2155_s_gain turns off auto gain */ ++ return gc2155_s_gain(sd, info->gain->val); ++ } ++ return gc2155_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return gc2155_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc2155_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return gc2155_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops gc2155_ctrl_ops = { ++ .s_ctrl = gc2155_s_ctrl, ++ .g_volatile_ctrl = gc2155_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int gc2155_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = gc2155_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int gc2155_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ gc2155_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++static int gc2155_core_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2155_info *info = to_state(sd); ++ int ret = 0; ++ ret = gc2155_write_array(sd, info->win->regs); ++ return ret; ++} ++ ++static int gc2155_power(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2155_info *info = to_state(sd); ++ if(val) { ++ gpio_direction_output(info->pwdn.pin, info->reset.active_level); ++ msleep(10); ++ } ++ else{ ++ gpio_direction_output(info->pwdn.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int gc2155_core_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2155_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++ ++int gc2155_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ int ret = 0; ++ ++ if (enable) { ++ gc2155_core_reset(sd, 1); ++ gc2155_core_init(sd, 1); ++ ret = gc2155_write_array(sd, gc2155_stream_on_mipi); ++ pr_debug("gc2155 stream on\n"); ++ ++ } ++ else { ++ ret = gc2155_write_array(sd, gc2155_stream_off_mipi); ++ pr_debug("gc2155 stream off\n"); ++ } ++ return ret; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops gc2155_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = gc2155_g_register, ++ .s_register = gc2155_s_register, ++#endif ++ .init = gc2155_core_init, ++ .reset = gc2155_core_reset, ++ ++}; ++ ++static const struct v4l2_subdev_video_ops gc2155_video_ops = { ++ .s_stream = gc2155_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops gc2155_pad_ops = { ++ //.enum_frame_interval = gc2155_enum_frame_interval, ++ //.num_frame_size = gc2155_enum_frame_size, ++ //.enum_mbus_code = gc2155_enum_mbus_code, ++ .set_fmt = gc2155_set_fmt, ++ .get_fmt = gc2155_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops gc2155_ops = { ++ .core = &gc2155_core_ops, ++ .video = &gc2155_video_ops, ++ .pad = &gc2155_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int gc2155_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct gc2155_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned long rate; ++ int mclk_index = -1; ++ char id_div[9]; ++ char id_mux[9]; ++ ++ *(volatile unsigned int *)(0xb0010100) = 1; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwdn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwdn.pin = gpio; ++ info->pwdn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &gc2155_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++#if 1 ++ ++ of_property_read_u32(client->dev.of_node, "ingenic,mclk", &mclk_index); ++ if(mclk_index == 0) { ++ memcpy(id_div, "div_cim0", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim0", sizeof(id_mux)); ++ } else if(mclk_index == 1) { ++ memcpy(id_div, "div_cim1", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim1", sizeof(id_mux)); ++ } else if(mclk_index == 2) { ++ memcpy(id_div, "div_cim2", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim2", sizeof(id_mux)); ++ } else ++ printk("Unkonwn mclk index\n"); ++ ++ ++ info->clk = v4l2_clk_get(&client->dev, id_div); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ info->sclka = devm_clk_get(&client->dev, id_mux); ++ ++ rate = v4l2_clk_get_rate(info->clk); ++ if (((rate / 1000) % 24000) != 0) { ++ ret = clk_set_parent(info->sclka, clk_get(NULL, "epll")); ++ info->sclka = devm_clk_get(&client->dev, "epll"); ++ if (IS_ERR(info->sclka)) { ++ pr_err("get sclka failed\n"); ++ } else { ++ rate = clk_get_rate(info->sclka); ++ if (((rate / 1000) % 24000) != 0) { ++ clk_set_rate(info->sclka, 120000000); ++ } ++ } ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++#endif ++ ++ ++ gc2155_power(sd, 1); ++ gc2155_core_reset(sd, 1); ++#if 1 ++ /* Make sure it's an gc2155 */ ++ ret = gc2155_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an gc2155 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ info->win = &gc2155_win_sizes[0]; ++ ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 10); ++ v4l2_ctrl_new_std(&info->hdl, &gc2155_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &gc2155_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &gc2155_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &gc2155_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &gc2155_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &gc2155_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 589824, 1, 10000); ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &gc2155_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 1176, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "gc2155 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int gc2155_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct gc2155_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id gc2155_id[] = { ++ { "gc2155", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, gc2155_id); ++ ++static const struct of_device_id gc2155_of_match[] = { ++ {.compatible = "GalaxyCore,gc2155", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, gc2155_of_match); ++ ++ ++static struct i2c_driver gc2155_driver = { ++ .driver = { ++ .name = "gc2155", ++ .of_match_table = of_match_ptr(gc2155_of_match), ++ }, ++ .probe = gc2155_probe, ++ .remove = gc2155_remove, ++ .id_table = gc2155_id, ++}; ++ ++module_i2c_driver(gc2155_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision gc2155 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/imx327.c b/module_drivers/drivers/media/i2c/ingenic-isp-v2/imx327.c +new file mode 100644 +index 000000000..5772832ba +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/imx327.c +@@ -0,0 +1,1109 @@ ++/* ++ * A V4L2 driver for OmniVision IMX327 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define IMX327_CHIP_ID_H (0xb2) ++#define IMX327_CHIP_ID_L (0x01) ++#define IMX327_REG_END 0xffff ++#define IMX327_REG_DELAY 0xfffe ++ ++#define AGAIN_MAX_DB 0x64 ++#define DGAIN_MAX_DB 0x64 ++#define LOG2_GAIN_SHIFT 16 ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++ ++struct imx327_win_size { ++ unsigned int width; ++ unsigned int height; ++ struct sensor_info sensor_info; ++ unsigned int mbus_code; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++}; ++ ++struct imx327_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct imx327_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ struct v4l2_ctrl *again_short; ++ ++ struct v4l2_clk *clk; ++ struct clk *sclka; ++ ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *exposure_short; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct imx327_win_size *win; ++ ++ struct imx327_gpio reset; ++ struct imx327_gpio ircutp; ++ struct imx327_gpio ircutn; ++}; ++ ++ ++static inline struct imx327_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct imx327_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct imx327_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++ ++static struct regval_list imx327_init_regs_1920_1080_30fps_mipi[] = { ++ {0x3000, 0x01},//standy ++ {0x3001, 0x01}, ++ {0x3002, 0x01},//Master stop ++// {IMX327_REG_DELAY, 0x18}, ++ {0x3005, 0x01}, ++ {0x3007, 0x00}, ++ {0x3009, 0x02}, ++ {0x300A, 0xF0}, ++ {0x300B, 0x00}, ++ {0x3011, 0x0A}, ++ {0x3012, 0x64}, ++ {0x3014, 0x00}, ++ {0x3018, 0x65},// 1125 ++ {0x3019, 0x04}, ++ {0x301A, 0x00}, ++ {0x301C, 0xa0},//0x1130:30fps 0x14a0:25fps ++ {0x301D, 0x14}, ++ {0x3022, 0x00}, ++ {0x3046, 0x01}, ++ {0x3048, 0x00}, ++ {0x3049, 0x08}, ++ {0x304B, 0x0A}, ++ {0x305C, 0x18}, ++ {0x305D, 0x03}, ++ {0x305E, 0x20}, ++ {0x305F, 0x01}, ++ {0x309E, 0x4A}, ++ {0x309F, 0x4A}, ++ {0x30D2, 0x19}, ++ {0x30D7, 0x03}, ++ {0x3129, 0x00}, ++ {0x313B, 0x61}, ++ {0x315E, 0x1A}, ++ {0x3164, 0x1A}, ++ {0x317C, 0x00}, ++ {0x31EC, 0x0E}, ++ {0x3405, 0x10}, ++ {0x3407, 0x01}, ++ {0x3414, 0x0A}, ++ {0x3418, 0x49}, ++ {0x3419, 0x04}, ++ {0x3441, 0x0C}, ++ {0x3442, 0x0C}, ++ {0x3443, 0x01}, ++ {0x3444, 0x20}, ++ {0x3445, 0x25}, ++ {0x3446, 0x57}, ++ {0x3447, 0x00}, ++ {0x3448, 0x37}, ++ {0x3449, 0x00}, ++ {0x344A, 0x2F},//1f ++ {0x344B, 0x00}, ++ {0x344C, 0x1F}, ++ {0x344D, 0x00}, ++ {0x344E, 0x1F}, ++ {0x344F, 0x00}, ++ {0x3450, 0x77}, ++ {0x3451, 0x00}, ++ {0x3452, 0x1F}, ++ {0x3453, 0x00}, ++ {0x3454, 0x17}, ++ {0x3455, 0x00}, ++ {0x346a, 0x9c},//EBD ++ {0x346b, 0x07}, ++ {0x3472, 0x9C}, ++ {0x3473, 0x07}, ++ {0x3480, 0x49}, ++// {IMX327_REG_DELAY, 0x18}, ++ {0x3001, 0x00},//standy cancel ++ {0x3002, 0x00},//Master start ++ {0x3000, 0x01},//standy cancel ++ {IMX327_REG_END, 0x00},/* END MARKER */ ++}; ++ ++ ++static struct regval_list imx327_init_regs_1920_1080_30fps_mipi_2dol_lcg[] = { ++//add ++ {0x3000, 0x01},//standy ++ {0x3001, 0x01}, ++ {0x3002, 0x01},//Master stop ++// {IMX327_REG_DELAY, 0x18}, ++// {0x3002, 0x00}, ++ {0x3005, 0x01},//ADBIT 01:12bit ++ {0x3007, 0x40},//WINMODE[6:4] ++ {0x3009, 0x01},//FRSEL[1:0] ++ {0x300a, 0xf0}, ++ {0x300c, 0x11},//WDMODE[0] WDSEL[5:4] ++ {0x3010, 0x61},//FPGC gain for each gain ++ {0x30f0, 0x64},//FPGC1 gain for each gain ++ {0x3011, 0x02}, ++ {0x3018, 0x6E},//Vmax FSC=vmax*2 ++ {0x3019, 0x05},//0x486 ++ {0x301c, 0x58},//Hmax ++ {0x301d, 0x08}, ++#if 0 ++ {0x3018, 0x86},//Vmax FSC=vmax*2 ++ {0x3019, 0x04},//0x486 1158 60.04fps ++ {0x301c, 0x05},//Hmax 2136 0x858 ++ {0x301d, 0x0a}, ++#endif ++#if 1 ++ {0x3020, 0x02},//SHS1 S ++ {0x3021, 0x00}, ++#else ++// {0x3014, 0x70}, ++ {0x3020, 0x02},//SHS1 S ++ {0x3021, 0x00}, ++ {0x3022, 0x00}, ++#endif ++ {0x3024, 0x73},//SHS2 L ++ {0x3025, 0x04}, ++ {0x3028, 0x00},//SHS3 ++ {0x3029, 0x00}, ++ {0x302a, 0x00}, ++ {0x3030, 0x65},//RHS1 ++ {0x3031, 0x00}, ++ {0x3032, 0x00}, ++ {0x3034, 0x00},//RHS2 ++ {0x3035, 0x00}, ++ {0x3036, 0x00}, ++ {0x303c, 0x04},//WINPV[7:0] ++ {0x303d, 0x00},//WINPV[2:0] ++ {0x303e, 0x41},//WINWV[7:0] ++ {0x303f, 0x04},//WINWV[2:0] ++ {0x3045, 0x05}, ++ {0x3046, 0x01},//ODBIT[1:0] ++ {0x304b, 0x0a}, ++ {0x305c, 0x18}, ++ {0x305d, 0x03}, ++ {0x305e, 0x20}, ++ {0x305f, 0x01}, ++ {0x309e, 0x4a}, ++ {0x309f, 0x4a}, ++ {0x30d2, 0x19}, ++ {0x30d7, 0x03}, ++ {0x3106, 0x11}, ++ {0x3129, 0x00}, ++ {0x313b, 0x61}, ++ {0x315e, 0x1a}, ++ {0x3164, 0x1a}, ++#if 0 ++ {0x31a0, 0xbc}, ++ {0x31a1, 0x00}, ++ ++#endif ++ {0x317c, 0x00}, ++ {0x31ec, 0x0e}, ++ {0x3204, 0x4a}, ++ {0x3209, 0xf0}, ++ {0x320a, 0x22}, ++ {0x3344, 0x38}, ++ {0x3405, 0x00}, ++ {0x3407, 0x01}, ++ {0x3414, 0x00},//OPB_SIZE_V[5:0] ++ {0x3415, 0x00},//NULL0_SIZE_V[5:0] ++ {0x3418, 0x7a},//Y_OUT_SIZE[7:0] ++ {0x3419, 0x09},//Y_OUT_SIZE[4:0] ++ {0x3441, 0x0c}, ++ {0x3442, 0x0c}, ++ {0x3443, 0x01}, ++ {0x3444, 0x20}, ++ {0x3445, 0x25}, ++ {0x3446, 0x77}, ++ {0x3447, 0x00}, ++ {0x3448, 0x67}, ++ {0x3449, 0x00}, ++ {0x344a, 0x47}, ++ {0x344b, 0x00}, ++ {0x344c, 0x37}, ++ {0x344d, 0x00}, ++ {0x344e, 0x3f}, ++ {0x344f, 0x00}, ++ {0x3450, 0xff}, ++ {0x3451, 0x00}, ++ {0x3452, 0x3f}, ++ {0x3453, 0x00}, ++ {0x3454, 0x37}, ++ {0x3455, 0x00}, ++ {0x346a, 0x9c},//EBD ++ {0x346b, 0x07}, ++ {0x3472, 0xa0}, ++ {0x3473, 0x07}, ++ {0x347b, 0x23}, ++ {0x3480, 0x49}, ++// {IMX327_REG_DELAY, 0x18}, ++ {0x3001, 0x00},//standy cancel ++ {0x3002, 0x00},//Master start ++ {0x3000, 0x01},//standy cancel ++ {IMX327_REG_END, 0x00},/* END MARKER */ ++ ++}; ++ ++ ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list imx327_stream_on_mipi[] = { ++ {0x3000, 0x00}, ++ {IMX327_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list imx327_stream_off_mipi[] = { ++ {0x3000, 0x01}, ++ {IMX327_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int imx327_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct imx327_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int imx327_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct imx327_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int imx327_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != IMX327_REG_END) { ++ if (vals->reg_num == IMX327_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = imx327_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int imx327_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != IMX327_REG_END) { ++ if (vals->reg_num == IMX327_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = imx327_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++static int imx327_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct imx327_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int imx327_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ret = imx327_read(sd, 0x301e, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != IMX327_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = imx327_read(sd, 0x301f, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != IMX327_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++static struct imx327_win_size imx327_win_sizes[] = { ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 25 << 16 | 1, ++ .sensor_info.total_width = 2136, ++ .sensor_info.total_height = 2781, ++ .sensor_info.wdr_en = 1, ++ .sensor_info.mipi_cfg.clk = 891, ++ .sensor_info.mipi_cfg.twidth = 1952, ++ .sensor_info.mipi_cfg.theight = 1109, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_SONY_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 1, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 16, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 12, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 16, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 62, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW12, ++ .sensor_info.mipi_cfg.del_start = 1, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_WDR_2_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_NOT_VC_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW12, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = imx327_init_regs_1920_1080_30fps_mipi_2dol_lcg, ++ }, ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 25 << 16 | 1, ++ .sensor_info.total_width = 5280, ++ .sensor_info.total_height = 1125, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 445, ++ .sensor_info.mipi_cfg.twidth = 1948, ++ .sensor_info.mipi_cfg.theight = 1109, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_SONY_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 12, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 20, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW12, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW12, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = imx327_init_regs_1920_1080_30fps_mipi, ++ }, ++}; ++ ++static int imx327_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_IMX327_FMTS) ++ return -EINVAL; ++ ++ code->code = imx327_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int imx327_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct imx327_format_struct *ovfmt; ++ struct imx327_win_size *wsize; ++ struct imx327_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int imx327_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct imx327_info *info = to_state(sd); ++ struct imx327_win_size *wsize = info->win; ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = wsize->width; ++ fmt->height = wsize->height; ++ fmt->code = wsize->mbus_code; ++ fmt->colorspace = wsize->colorspace; ++ *(unsigned int *)fmt->reserved = &wsize->sensor_info; ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int imx327_s_wdr(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ struct imx327_info *info = to_state(sd); ++ printk("%s:%d\n", __func__, value); ++ if(value) ++ info->win = &imx327_win_sizes[0]; ++ else ++ info->win = &imx327_win_sizes[1]; ++ ++ return ret; ++} ++ ++static int imx327_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int imx327_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int imx327_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int imx327_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int imx327_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int imx327_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ unsigned int again=(gain*20)>>LOG2_GAIN_SHIFT; ++ // Limit Max gain ++ if(again>AGAIN_MAX_DB+DGAIN_MAX_DB) again=AGAIN_MAX_DB+DGAIN_MAX_DB; ++ return again; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ return (((int32_t)regval)<win->sensor_info.wdr_en) { ++ total_height *= 2; ++ shs = total_height - value - 1; ++ ret = imx327_write(sd, 0x3024, (unsigned char)(shs & 0xff)); ++ ret += imx327_write(sd, 0x3025, (unsigned char)((shs >> 8) & 0xff)); ++ ret += imx327_write(sd, 0x3026, (unsigned char)((shs >> 16) & 0x3)); ++ } else { ++ shs = total_height - value - 1; ++ ret = imx327_write(sd, 0x3020, (unsigned char)(shs & 0xff)); ++ ret += imx327_write(sd, 0x3021, (unsigned char)((shs >> 8) & 0xff)); ++ ret += imx327_write(sd, 0x3022, (unsigned char)((shs >> 16) & 0x3)); ++ } ++ ++ return ret; ++} ++ ++static int imx327_s_exp_short(struct v4l2_subdev *sd, int value) ++{ ++ struct imx327_info *info = to_state(sd); ++ int ret = 0; ++ ++ int shs = 101 - value - 1; ++ ret = imx327_write(sd, 0x3020, (unsigned char)(shs & 0xff)); ++ ret += imx327_write(sd, 0x3021, (unsigned char)((shs >> 8) & 0xff)); ++ ret += imx327_write(sd, 0x3022, (unsigned char)((shs >> 16) & 0x3)); ++ ++ ++ return ret; ++} ++ ++static int imx327_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct imx327_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return imx327_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return imx327_g_again(sd, &info->again->val); ++ case V4L2_CID_USER_ANALOG_GAIN_SHORT: ++ return imx327_g_again_short(sd, &info->again_short->val); ++ } ++ return -EINVAL; ++} ++ ++static int imx327_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct imx327_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return imx327_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return imx327_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return imx327_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return imx327_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* imx327_s_gain turns off auto gain */ ++ return imx327_s_gain(sd, info->gain->val); ++ } ++ return imx327_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return imx327_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return imx327_s_again(sd, ctrl->val); ++ case V4L2_CID_USER_ANALOG_GAIN_SHORT: ++ return imx327_s_again_short(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return imx327_s_exp(sd, ctrl->val); ++ case V4L2_CID_USER_EXPOSURE_SHORT: ++ return imx327_s_exp_short(sd, ctrl->val); ++ case V4L2_CID_WIDE_DYNAMIC_RANGE: ++ return imx327_s_wdr(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops imx327_ctrl_ops = { ++ .s_ctrl = imx327_s_ctrl, ++ .g_volatile_ctrl = imx327_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int imx327_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = imx327_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int imx327_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ imx327_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++static int imx327_core_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct imx327_info *info = to_state(sd); ++ int ret = 0; ++ ret = imx327_write_array(sd, info->win->regs); ++ return ret; ++} ++ ++static int imx327_core_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct imx327_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++ ++int imx327_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct imx327_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ret = imx327_write_array(sd, imx327_stream_on_mipi); ++ pr_debug("imx327 stream on\n"); ++ ++ } ++ else { ++ ret = imx327_write_array(sd, imx327_stream_off_mipi); ++ pr_debug("imx327 stream off\n"); ++ } ++ return ret; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops imx327_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = imx327_g_register, ++ .s_register = imx327_s_register, ++#endif ++ .init = imx327_core_init, ++ .reset = imx327_core_reset, ++ ++}; ++ ++static const struct v4l2_subdev_video_ops imx327_video_ops = { ++ .s_stream = imx327_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops imx327_pad_ops = { ++ //.enum_frame_interval = imx327_enum_frame_interval, ++ //.num_frame_size = imx327_enum_frame_size, ++ //.enum_mbus_code = imx327_enum_mbus_code, ++ .set_fmt = imx327_set_fmt, ++ .get_fmt = imx327_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops imx327_ops = { ++ .core = &imx327_core_ops, ++ .video = &imx327_video_ops, ++ .pad = &imx327_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int imx327_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct imx327_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned long rate; ++ struct v4l2_ctrl_config cfg = {0}; ++ int mclk_index = -1; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &imx327_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++#if 1 ++ ++ char id_div[9]; ++ char id_mux[9]; ++ printk("%s:%d\n", __func__, __LINE__); ++ of_property_read_u32(client->dev.of_node, "ingenic,mclk", &mclk_index); ++ if(mclk_index == 0) { ++ memcpy(id_div, "div_cim0", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim0", sizeof(id_mux)); ++ } else if(mclk_index == 1) { ++ memcpy(id_div, "div_cim1", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim1", sizeof(id_mux)); ++ } else if(mclk_index == 2) { ++ memcpy(id_div, "div_cim2", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim2", sizeof(id_mux)); ++ } else ++ printk("Unkonwn mclk index\n"); ++ ++ ++ info->clk = v4l2_clk_get(&client->dev, id_div); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ info->sclka = devm_clk_get(&client->dev, id_mux); ++ ++ printk("sclka is %s\n", info->sclka?"NOT NULL":"NULL"); ++ rate = v4l2_clk_get_rate(info->clk); ++ if (((rate / 1000) % 37125) != 0) { ++ ret = clk_set_parent(info->sclka, clk_get(NULL, "epll")); ++ info->sclka = devm_clk_get(&client->dev, "epll"); ++ if (IS_ERR(info->sclka)) { ++ pr_err("get sclka failed\n"); ++ } else { ++ rate = clk_get_rate(info->sclka); ++ if (((rate / 1000) % 37125) != 0) { ++ clk_set_rate(info->sclka, 891000000); ++ } ++ } ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 37125000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++#endif ++ ++ ++ imx327_core_reset(sd, 1); ++#if 1 ++ /* Make sure it's an imx327 */ ++ ret = imx327_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an imx327 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ /*IRCUT ctl 0:off 1:on*/ ++ imx327_ircut(sd, 0); ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 10); ++ v4l2_ctrl_new_std(&info->hdl, &imx327_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &imx327_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &imx327_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &imx327_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &imx327_ctrl_ops, ++ V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &imx327_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &imx327_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 589824, 1, 10000); ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &imx327_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 1176, 1, 1000); ++ ++ cfg.ops = &imx327_ctrl_ops; ++ cfg.id = V4L2_CID_USER_EXPOSURE_SHORT; ++ cfg.name = "expo short"; ++ cfg.type = V4L2_CTRL_TYPE_INTEGER; ++ cfg.min = 1; ++ cfg.max = 98; ++ cfg.step = 1; ++ cfg.def = 50; ++ info->exposure_short = v4l2_ctrl_new_custom(&info->hdl, &cfg, NULL); ++ ++ memset(&cfg, 0, sizeof(cfg)); ++ cfg.ops = &imx327_ctrl_ops; ++ cfg.id = V4L2_CID_USER_ANALOG_GAIN_SHORT; ++ cfg.name = "analog gain short"; ++ cfg.type = V4L2_CTRL_TYPE_INTEGER; ++ cfg.min = 0; ++ cfg.max = 589824; ++ cfg.step = 1; ++ cfg.def = 10000; ++ info->again_short = v4l2_ctrl_new_custom(&info->hdl, &cfg, NULL); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "imx327 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int imx327_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx327_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id imx327_id[] = { ++ { "imx327", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, imx327_id); ++ ++static const struct of_device_id imx327_of_match[] = { ++ {.compatible = "ovti,imx327", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, imx327_of_match); ++ ++ ++static struct i2c_driver imx327_driver = { ++ .driver = { ++ .name = "imx327", ++ .of_match_table = of_match_ptr(imx327_of_match), ++ }, ++ .probe = imx327_probe, ++ .remove = imx327_remove, ++ .id_table = imx327_id, ++}; ++ ++module_i2c_driver(imx327_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision imx327 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/ov2735a.c b/module_drivers/drivers/media/i2c/ingenic-isp-v2/ov2735a.c +new file mode 100644 +index 000000000..15e4d8e1c +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/ov2735a.c +@@ -0,0 +1,1132 @@ ++/* ++ * A V4L2 driver for OmniVision OV2735a cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define OV2735A_CHIP_ID_H (0x27) ++#define OV2735A_CHIP_ID_L (0x35) ++#define OV2735A_REG_END 0xff ++#define OV2735A_REG_DELAY 0x00 ++#define OV2735A_PAGE_REG 0xfd ++ ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ov2735a_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ov2735a_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov2735a_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ struct clk *sclka; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ov2735a_win_size *win; ++ ++ struct ov2735a_gpio reset; ++ struct ov2735a_gpio ircutp; ++ struct ov2735a_gpio ircutn; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++ ++struct again_lut ov2735a_again_lut[] = { ++ {0x10, 0}, ++ {0x11, 5731}, ++ {0x12, 11136}, ++ {0x13, 16248}, ++ {0x14, 21097}, ++ {0x15, 25710}, ++ {0x16, 30109}, ++ {0x17, 34312}, ++ {0x18, 38336}, ++ {0x19, 42195}, ++ {0x1a, 45904}, ++ {0x1b, 49472}, ++ {0x1c, 52910}, ++ {0x1d, 56228}, ++ {0x1e, 59433}, ++ {0x1f, 62534}, ++ {0x20, 65536}, ++ {0x22, 71267}, ++ {0x24, 76672}, ++ {0x26, 81784}, ++ {0x28, 86633}, ++ {0x2a, 91246}, ++ {0x2c, 95645}, ++ {0x2e, 99848}, ++ {0x30, 103872}, ++ {0x32, 107731}, ++ {0x34, 111440}, ++ {0x36, 115008}, ++ {0x38, 118446}, ++ {0x3a, 121764}, ++ {0x3c, 124969}, ++ {0x3e, 128070}, ++ {0x40, 131072}, ++ {0x44, 136803}, ++ {0x48, 142208}, ++ {0x4c, 147320}, ++ {0x50, 152169}, ++ {0x54, 156782}, ++ {0x58, 161181}, ++ {0x5c, 165384}, ++ {0x60, 169408}, ++ {0x64, 173267}, ++ {0x68, 176976}, ++ {0x6c, 180544}, ++ {0x70, 183982}, ++ {0x74, 187300}, ++ {0x78, 190505}, ++ {0x7c, 193606}, ++ {0x80, 196608}, ++ {0x88, 202339}, ++ {0x90, 207744}, ++ {0x98, 212856}, ++ {0xa0, 217705}, ++ {0xa8, 222318}, ++ {0xb0, 226717}, ++ {0xb8, 230920}, ++ {0xc0, 234944}, ++ {0xc8, 238803}, ++ {0xd0, 242512}, ++ {0xd8, 246080}, ++ {0xe0, 249518}, ++ {0xe8, 252836}, ++ {0xf0, 256041}, ++ {0xf8, 259142}, ++}; ++ ++static inline struct ov2735a_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ov2735a_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov2735a_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list ov2735a_init_regs_1920_1080_30fps_MIPI[] = { ++ {0xfd, 0x00}, ++ {OV2735A_REG_DELAY, 0x05}, ++ {0xfd, 0x00}, ++ {0x2f, 0x10}, ++ {0x34, 0x00}, ++ {0x30, 0x15}, ++ {0x33, 0x01}, ++ {0x35, 0x20}, ++ {0xfd, 0x01}, ++ {0x0d, 0x00}, ++ {0x30, 0x00}, ++ {0x03, 0x01}, ++ {0x04, 0x8f}, ++ {0x01, 0x01}, ++ {0x09, 0x00}, ++ {0x0a, 0x20}, ++ {0x06, 0x0a}, ++ {0x24, 0x10}, ++ {0x01, 0x01}, ++ {0xfb, 0x73}, ++ {0x01, 0x01}, ++ {0xfd, 0x01}, ++ {0x1a, 0x6b}, ++ {0x1c, 0xea}, ++ {0x16, 0x0c}, ++ {0x21, 0x00}, ++ {0x11, 0xe8},//;63 ;fr ++ {0x19, 0xc3}, ++ {0x26, 0xda}, ++ {0x29, 0x01}, ++ {0x33, 0x6f}, ++ {0x2a, 0xd2}, ++ {0x2c, 0x40}, ++ {0xd0, 0x02}, ++ {0xd1, 0x01}, ++ {0xd2, 0x20}, ++ {0xd3, 0x03},//;04 ; ++ {0xd4, 0xa4},//;2a ; ++ {0x50, 0x00}, ++ {0x51, 0x2c}, ++ {0x52, 0x29}, ++ {0x53, 0x00}, ++ {0x55, 0x44}, ++ {0x58, 0x29}, ++ {0x5a, 0x00}, ++ {0x5b, 0x00}, ++ {0x5d, 0x00}, ++ {0x64, 0x2f}, ++ {0x66, 0x62}, ++ {0x68, 0x5b}, ++ {0x75, 0x46}, ++ {0x76, 0xf0}, ++ {0x77, 0x4f}, ++ {0x78, 0xef}, ++ {0x72, 0xcf}, ++ {0x73, 0x36}, ++ {0x7d, 0x0d}, ++ {0x7e, 0x0d}, ++ {0x8a, 0x77}, ++ {0x8b, 0x77}, ++ {0xfd, 0x01}, ++ {0xb1, 0x83},//;DPHY enable 8b ++ ++// {0xb2, 0x40},//hs mode ++ ++ {0xb3, 0x0b},//;0b;09;1d ++ {0xb4, 0x14},//;MIPI PLL enable;14;35;36 ++ {0x9d, 0x40},//;mipi hs dc level 40/03/55 ++ {0xa1, 0x05},//;speed/03 ++ {0x94, 0x44},//;dphy time ++ {0x95, 0x33},//;dphy time ++ {0x96, 0x1f},//;dphy time ++ {0x98, 0x45},//;dphy time ++ {0x9c, 0x10},//;dphy time ++ {0xb5, 0x70},//;30 ++ {0xa0, 0x01},//;mipi enable ++ {0x25, 0xe0}, ++ {0x20, 0x7b}, ++ {0x8f, 0x88}, ++ {0x91, 0x40}, ++ ++ {0xfd, 0x02}, ++ {0x5e, 0x03}, ++ {0xa1, 0x04}, ++ {0xa3, 0x40}, ++ {0xa5, 0x02}, ++ {0xa7, 0xc4}, ++ {0xfd, 0x01}, ++ {0x86, 0x77}, ++ {0x89, 0x77}, ++ {0x87, 0x74}, ++ {0x88, 0x74}, ++ {0xfc, 0xe0}, ++ {0xfe, 0xe0}, ++ {0xf0, 0x40}, ++ {0xf1, 0x40}, ++ {0xf2, 0x40}, ++ {0xf3, 0x40}, ++ ++#if 1 ++ {0xfd, 0x02},//;;crop to 1920x1080 ++ {0xa0, 0x00},//;Image vertical start MSB3bits ++ {0xa1, 0x08},//;Image vertical start LSB8bits ++ {0xa2, 0x04},//;image vertical size MSB8bits ++ {0xa3, 0x38},//;image vertical size LSB8bits ++ {0xa4, 0x00}, ++ {0xa5, 0x04},//;H start 8Lsb, keep center ++ {0xa6, 0x03}, ++ {0xa7, 0xc0},//;Half H size Lsb8bits ++ {0xfd, 0x01}, ++ {0x8e, 0x07}, ++ {0x8f, 0x80},//;MIPI column number ++ {0x90, 0x04},//;MIPI row number ++ {0x91, 0x38}, ++ ++ {0xfd, 0x03}, ++ {0xc0, 0x01},//;enable transfer OTP BP information ++ {0xfd, 0x04}, ++ {0x21, 0x14}, ++ {0x22, 0x14}, ++ {0x23, 0x14},//;enhance normal and dummy BPC ++ ++ {0xfd, 0x01}, ++ {0x06, 0xe0},//;insert dummy line , the frame rate is 30.01. ++// {0x01, 0x01},//; ++// {0xa0, 0x01},//;MIPI enable, stream on ++#else ++ {0xfd, 0x02},//;;crop to 1920x1080 ++ {0xa0, 0x00},//;Image vertical start MSB3bits ++ {0xa1, 0x08},//;Image vertical start LSB8bits ++ {0xa2, 0x01},//;image vertical size MSB8bits ++ {0xa3, 0xe0},//;image vertical size LSB8bits ++ {0xa4, 0x00}, ++ {0xa5, 0x04},//;H start 8Lsb, keep center ++ {0xa6, 0x01}, ++ {0xa7, 0x40},//;Half H size Lsb8bits ++ {0xfd, 0x01}, ++ {0x8e, 0x02}, ++ {0x8f, 0x80},//;MIPI column number ++ {0x90, 0x01},//;MIPI row number ++ {0x91, 0xe0}, ++ ++ {0xfd, 0x03}, ++ {0xc0, 0x01},//;enable transfer OTP BP information ++ {0xfd, 0x04}, ++ {0x21, 0x14}, ++ {0x22, 0x14}, ++ {0x23, 0x14},//;enhance normal and dummy BPC ++ ++ {0xfd, 0x01}, ++ {0x06, 0xe0},//;insert dummy line , the frame rate is 30.01. ++ {0x01, 0x01},//; ++ {0xa0, 0x01},//;MIPI enable, stream on ++#endif ++ ++#if 0 ++ {0xfd, 0x01},//@@ 1 11 Mirror_On_Flip_Off ++ ++ {0x3f, 0x01},//03 ++ {0xf8, 0x00},//02 ++ {0x01, 0x01}, ++ {0xfd, 0x02}, ++ {0x62, 0x01},//;full size mode flip off row start for OTP BPC ++ {0x63, 0x00}, ++ {0xfd, 0x01}, ++ ++#endif ++#if 0 ++ {0xfd, 0x01},//@@ 1 12 Mirror_On_Flip_On ++ ++ {0x3f, 0x03},// 03 ++ ++ {0xf8, 0x02},//02 ++ ++ {0x01, 0x01}, ++ {0xfd, 0x02}, ++ {0x62, 0x48}, ++ {0x63, 0x04},//;full size flip, row start:1096(0x448) ++ {0xfd, 0x01}, ++#endif ++ ++#if 0 ++ {0xfd, 0x01},//@@ 1 13 Mirror_Off_Flip_Off ++ ++ {0x3f, 0x00},//03 ++ {0xf8, 0x00},// 02 ++ ++ {0x01, 0x01}, ++ {0xfd, 0x02}, ++ {0x62, 0x01},//;full size mode flip off row start for OTP BPC ++ {0x63, 0x00}, ++ {0xfd, 0x01}, ++#endif ++ ++#if 1 ++ {0xfd, 0x01},//@@ 1 14 Mirror_Off_Flip_On ++ ++ {0x3f, 0x02},//03 ++ {0xf8, 0x02},//02 ++ {0x01, 0x01}, ++ ++ {0xfd, 0x02}, ++ {0x62, 0x48}, ++ {0x63, 0x04},//;full size flip, row start:1096(0x448) ++ {0xfd, 0x01}, ++#endif ++ ++ {0x01, 0x01},//; ++ {0xa0, 0x01},//;MIPI enable, stream on ++ {OV2735A_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++ ++static struct regval_list ov2735a_stream_on[] = { ++ {0xfd, 0x00}, ++ {0x36, 0x00}, ++ {0x37, 0x00},//fake stream on ++ {OV2735A_REG_END, 0x00}, ++}; ++ ++static struct regval_list ov2735a_stream_off[] = { ++ {0xfd, 0x00}, ++ {0x36, 0x01}, ++ {0x37, 0x01},//fake stream off ++ {OV2735A_REG_END, 0x00}, ++}; ++ ++ ++int ov2735a_read(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 1, ++ .buf = ®, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_write(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ unsigned char buf[2] = {reg, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }; ++ int ret; ++ unsigned int timeout = 100; ++ while(timeout--){ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == -EAGAIN){ ++ msleep(100); ++ continue; ++ } ++ else ++ break; ++ } ++ if(ret > 0) ++ ret = 0; ++ return ret; ++} ++ ++static int ov2735a_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != OV2735A_REG_END) { ++ if (vals->reg_num == OV2735A_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov2735a_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ if (vals->reg_num == OV2735A_PAGE_REG){ ++ val &= 0xf8; ++ val |= (vals->value & 0x07); ++ ret = ov2735a_write(sd, vals->reg_num, val); ++ ret = ov2735a_read(sd, vals->reg_num, &val); ++ } ++ } ++ vals++; ++ } ++ return 0; ++} ++static int ov2735a_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != OV2735A_REG_END) { ++ if (vals->reg_num == OV2735A_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov2735a_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ov2735a_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int ov2735a_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int ov2735a_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov2735a_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int ov2735a_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ ret = ov2735a_read(sd, 0x02, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV2735A_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = ov2735a_read(sd, 0x03, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV2735A_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ ret = ov2735a_read(sd, 0x04, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != 0x05 && v != 0x06 && v != 0x07) ++ return -ENODEV; ++ ++ ++ return 0; ++ ++} ++ ++static struct ov2735a_win_size ov2735a_win_sizes[] = { ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 30 << 16 | 1, ++ .sensor_info.total_width = 1936, ++ .sensor_info.total_height = 1096, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 600, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW10, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov2735a_init_regs_1920_1080_30fps_MIPI, ++ }, ++}; ++ ++static int ov2735a_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_OV2735a_FMTS) ++ return -EINVAL; ++ ++ code->code = ov2735a_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int ov2735a_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov2735a_format_struct *ovfmt; ++ struct ov2735a_win_size *wsize; ++ struct ov2735a_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ov2735a_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ struct ov2735a_win_size *wsize = info->win; ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = wsize->width; ++ fmt->height = wsize->height; ++ fmt->code = wsize->mbus_code; ++ fmt->colorspace = wsize->colorspace; ++ *(unsigned int *)fmt->reserved = &wsize->sensor_info; /*reserved[0] reserved[1]*/ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ov2735a_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ov2735a_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ov2735a_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++// printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov2735a_again_lut); i++) { ++ lut = &ov2735a_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov2735a_again_lut); i++) { ++ lut = &ov2735a_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++ ++static int ov2735a_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret = ov2735a_read(sd, 0x23, &v); ++ reg_val |= v ; ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++ ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ov2735a_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret = ov2735a_write(sd, 0xfd, 0x01); ++ ret += ov2735a_write(sd, 0x24, (unsigned char)reg_value); ++ ret += ov2735a_write(sd, 0x01, 0x01); ++ if (ret < 0){ ++ printk("ov2735a_write error %d\n" ,__LINE__ ); ++ return ret; ++ } ++ return 0; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ov2735a_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov2735a_write(sd, 0xfd, 0x01); ++ ret += ov2735a_write(sd, 0x4, (unsigned char)(value & 0xff)); ++ ret += ov2735a_write(sd, 0x3, (unsigned char)((value & 0xff00) >> 8)); ++ ret += ov2735a_write(sd, 0x01, 0x01); ++ ++ if (ret < 0) { ++ printk("ov2735a_write error %d\n" ,__LINE__); ++ return ret; ++ } ++ return ret; ++} ++ ++static int ov2735a_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov2735a_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ov2735a_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov2735a_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ov2735a_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov2735a_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ov2735a_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ov2735a_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ov2735a_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ov2735a_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ov2735a_s_gain turns off auto gain */ ++ return ov2735a_s_gain(sd, info->gain->val); ++ } ++ return ov2735a_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ov2735a_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov2735a_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ov2735a_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ov2735a_ctrl_ops = { ++ .s_ctrl = ov2735a_s_ctrl, ++ .g_volatile_ctrl = ov2735a_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov2735a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ov2735a_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ov2735a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ov2735a_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int ov2735a_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ov2735a_reset(sd, 1); ++ ov2735a_write_array(sd, info->win->regs); ++ ret = ov2735a_write_array(sd, ov2735a_stream_on); ++ printk("ov2735a stream on\n"); ++ ++ } ++ else { ++ ret = ov2735a_write_array(sd, ov2735a_stream_off); ++ printk("ov2735a stream off\n"); ++ } ++ return ret; ++} ++ ++ ++int ov2735a_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ov2735a_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov2735a_g_register, ++ .s_register = ov2735a_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops ov2735a_video_ops = { ++ .s_stream = ov2735a_s_stream, ++ .g_frame_interval = ov2735a_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov2735a_pad_ops = { ++ //.enum_frame_interval = ov2735a_enum_frame_interval, ++ //.num_frame_size = ov2735a_enum_frame_size, ++ //.enum_mbus_code = ov2735a_enum_mbus_code, ++ .set_fmt = ov2735a_set_fmt, ++ .get_fmt = ov2735a_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops ov2735a_ops = { ++ .core = &ov2735a_core_ops, ++ .video = &ov2735a_video_ops, ++ .pad = &ov2735a_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int ov2735a_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct ov2735a_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned long rate; ++ struct v4l2_ctrl_config cfg = {0}; ++ int mclk_index = -1; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &ov2735a_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++#if 1 ++ ++ char id_div[9]; ++ char id_mux[9]; ++ printk("%s:%d\n", __func__, __LINE__); ++ of_property_read_u32(client->dev.of_node, "ingenic,mclk", &mclk_index); ++ if(mclk_index == 0) { ++ memcpy(id_div, "div_cim0", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim0", sizeof(id_mux)); ++ } else if(mclk_index == 1) { ++ memcpy(id_div, "div_cim1", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim1", sizeof(id_mux)); ++ } else if(mclk_index == 2) { ++ memcpy(id_div, "div_cim2", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim2", sizeof(id_mux)); ++ } else ++ printk("Unkonwn mclk index\n"); ++ ++ ++ info->clk = v4l2_clk_get(&client->dev, id_div); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ info->sclka = devm_clk_get(&client->dev, id_mux); ++ ++ printk("sclka is %s\n", info->sclka?"NOT NULL":"NULL"); ++ rate = v4l2_clk_get_rate(info->clk); ++ if (((rate / 1000) % 24000) != 0) { ++ ret = clk_set_parent(info->sclka, clk_get(NULL, "epll")); ++ info->sclka = devm_clk_get(&client->dev, "epll"); ++ if (IS_ERR(info->sclka)) { ++ pr_err("get sclka failed\n"); ++ } else { ++ rate = clk_get_rate(info->sclka); ++ if (((rate / 1000) % 24000) != 0) { ++ clk_set_rate(info->sclka, 120000000); ++ } ++ } ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++#endif ++ ++ info->win = &ov2735a_win_sizes[0]; ++ ov2735a_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ov2735a */ ++ ret = ov2735a_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ov2735a chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ /*IRCUT ctl 0:off 1:on*/ ++ ov2735a_ircut(sd, 0); ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 259142, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1899 - 4, 1, 1500); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ov2735a Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ov2735a_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov2735a_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id ov2735a_id[] = { ++ { "ov2735a", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov2735a_id); ++ ++static const struct of_device_id ov2735a_of_match[] = { ++ {.compatible = "ovti,ov2735a", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2735a_of_match); ++ ++ ++static struct i2c_driver ov2735a_driver = { ++ .driver = { ++ .name = "ov2735a", ++ .of_match_table = of_match_ptr(ov2735a_of_match), ++ }, ++ .probe = ov2735a_probe, ++ .remove = ov2735a_remove, ++ .id_table = ov2735a_id, ++}; ++ ++module_i2c_driver(ov2735a_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision ov2735a sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/ov4689.c b/module_drivers/drivers/media/i2c/ingenic-isp-v2/ov4689.c +new file mode 100644 +index 000000000..db5617af7 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/ov4689.c +@@ -0,0 +1,1629 @@ ++/* ++ * A V4L2 driver for OmniVision OV4689 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define OV4689_CHIP_ID_H (0x46) ++#define OV4689_CHIP_ID_L (0x88) ++#define OV4689_REG_END 0xffff ++#define OV4689_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ov4689_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ov4689_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov4689_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ struct clk *sclka; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ov4689_win_size *win; ++ ++ struct ov4689_gpio reset; ++ struct ov4689_gpio ircutp; ++ struct ov4689_gpio ircutn; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut ov4689_again_lut[] = { ++ ++ {0x80, 0}, ++ {0x88, 5731}, ++ {0x90, 11136}, ++ {0x98, 16248}, ++ {0xa0, 21097}, ++ {0xa8, 25710}, ++ {0xb0, 30109}, ++ {0xb8, 34312}, ++ {0xc0, 38336}, ++ {0xc8, 42195}, ++ {0xd0, 45904}, ++ {0xd8, 49472}, ++ {0xe0, 52910}, ++ {0xe8, 56228}, ++ {0xf0, 59433}, ++ {0xf8, 62534}, ++ {0x178, 65536}, ++ {0x17c, 68445}, ++ {0x180, 71267}, ++ {0x184, 74008}, ++ {0x188, 76672}, ++ {0x18c, 79262}, ++ {0x190, 81784}, ++ {0x194, 84240}, ++ {0x198, 86633}, ++ {0x19c, 88968}, ++ {0x1a0, 91246}, ++ {0x1a4, 93471}, ++ {0x1a8, 95645}, ++ {0x1ac, 97770}, ++ {0x1b0, 99848}, ++ {0x1b4, 101881}, ++ {0x1b8, 103872}, ++ {0x1bc, 105821}, ++ {0x1c0, 107731}, ++ {0x1c4, 109604}, ++ {0x1c8, 111440}, ++ {0x1cc, 113241}, ++ {0x1d0, 115008}, ++ {0x1d4, 116743}, ++ {0x1d8, 118446}, ++ {0x1dc, 120120}, ++ {0x1e0, 121764}, ++ {0x1e4, 123380}, ++ {0x1e8, 124969}, ++ {0x1ec, 126532}, ++ {0x1f0, 128070}, ++ {0x1f4, 129583}, ++ {0x374, 131072}, ++ {0x376, 132537}, ++ {0x378, 133981}, ++ {0x37a, 135403}, ++ {0x37c, 136803}, ++ {0x37e, 138184}, ++ {0x380, 139544}, ++ {0x382, 140885}, ++ {0x384, 142208}, ++ {0x386, 143512}, ++ {0x388, 144798}, ++ {0x38a, 146067}, ++ {0x38c, 147320}, ++ {0x38e, 148556}, ++ {0x390, 149776}, ++ {0x392, 150980}, ++ {0x394, 152169}, ++ {0x396, 153344}, ++ {0x398, 154504}, ++ {0x39a, 155650}, ++ {0x39c, 156782}, ++ {0x39e, 157901}, ++ {0x3a0, 159007}, ++ {0x3a2, 160100}, ++ {0x3a4, 161181}, ++ {0x3a6, 162249}, ++ {0x3a8, 163306}, ++ {0x3aa, 164350}, ++ {0x3ac, 165384}, ++ {0x3ae, 166406}, ++ {0x3b0, 167417}, ++ {0x3b2, 168418}, ++ {0x3b4, 169408}, ++ {0x3b6, 170387}, ++ {0x3b8, 171357}, ++ {0x3ba, 172317}, ++ {0x3bc, 173267}, ++ {0x3be, 174208}, ++ {0x3c0, 175140}, ++ {0x3c2, 176062}, ++ {0x3c4, 176976}, ++ {0x3c6, 177880}, ++ {0x3c8, 178777}, ++ {0x3ca, 179664}, ++ {0x3cc, 180544}, ++ {0x3ce, 181415}, ++ {0x3d0, 182279}, ++ {0x3d2, 183134}, ++ {0x3d4, 183982}, ++ {0x3d6, 184823}, ++ {0x3d8, 185656}, ++ {0x3da, 186482}, ++ {0x3dc, 187300}, ++ {0x3de, 188112}, ++ {0x3e0, 188916}, ++ {0x3e2, 189714}, ++ {0x3e4, 190505}, ++ {0x3e6, 191290}, ++ {0x3e8, 192068}, ++ {0x3ea, 192840}, ++ {0x3ec, 193606}, ++ {0x3ee, 194365}, ++ {0x3f0, 195119}, ++ {0x3f2, 195866}, ++ {0x778, 196608}, ++ {0x779, 197343}, ++ {0x77a, 198073}, ++ {0x77b, 198798}, ++ {0x77c, 199517}, ++ {0x77d, 200230}, ++ {0x77e, 200939}, ++ {0x77f, 201642}, ++ {0x780, 202339}, ++ {0x781, 203032}, ++ {0x782, 203720}, ++ {0x783, 204402}, ++ {0x784, 205080}, ++ {0x785, 205753}, ++ {0x786, 206421}, ++ {0x787, 207085}, ++ {0x788, 207744}, ++ {0x789, 208398}, ++ {0x78a, 209048}, ++ {0x78b, 209693}, ++ {0x78c, 210334}, ++ {0x78d, 210971}, ++ {0x78e, 211603}, ++ {0x78f, 212232}, ++ {0x790, 212856}, ++ {0x791, 213476}, ++ {0x792, 214092}, ++ {0x793, 214704}, ++ {0x794, 215312}, ++ {0x795, 215916}, ++ {0x796, 216516}, ++ {0x797, 217113}, ++ {0x798, 217705}, ++ {0x799, 218294}, ++ {0x79a, 218880}, ++ {0x79b, 219462}, ++ {0x79c, 220040}, ++ {0x79d, 220615}, ++ {0x79e, 221186}, ++ {0x79f, 221754}, ++ {0x7a0, 222318}, ++ {0x7a1, 222880}, ++ {0x7a2, 223437}, ++ {0x7a3, 223992}, ++ {0x7a4, 224543}, ++ {0x7a5, 225091}, ++ {0x7a6, 225636}, ++ {0x7a7, 226178}, ++ {0x7a8, 226717}, ++ {0x7a9, 227253}, ++ {0x7aa, 227785}, ++ {0x7ab, 228315}, ++ {0x7ac, 228842}, ++ {0x7ad, 229365}, ++ {0x7ae, 229886}, ++ {0x7af, 230404}, ++ {0x7b0, 230920}, ++ {0x7b1, 231432}, ++ {0x7b2, 231942}, ++ {0x7b3, 232449}, ++ {0x7b4, 232953}, ++ {0x7b5, 233455}, ++ {0x7b6, 233954}, ++ {0x7b7, 234450}, ++ {0x7b8, 234944}, ++ {0x7b9, 235435}, ++ {0x7ba, 235923}, ++ {0x7bb, 236410}, ++ {0x7bc, 236893}, ++ {0x7bd, 237374}, ++ {0x7be, 237853}, ++ {0x7bf, 238329}, ++ {0x7c0, 238803}, ++ {0x7c1, 239275}, ++ {0x7c2, 239744}, ++ {0x7c3, 240211}, ++ {0x7c4, 240676}, ++ {0x7c5, 241138}, ++ {0x7c6, 241598}, ++ {0x7c7, 242056}, ++ {0x7c8, 242512}, ++ {0x7c9, 242965}, ++ {0x7ca, 243416}, ++ {0x7cb, 243865}, ++ {0x7cc, 244313}, ++ {0x7cd, 244757}, ++ {0x7ce, 245200}, ++ {0x7cf, 245641}, ++ {0x7d0, 246080}, ++ {0x7d1, 246517}, ++ {0x7d2, 246951}, ++ {0x7d3, 247384}, ++ {0x7d4, 247815}, ++ {0x7d5, 248243}, ++ {0x7d6, 248670}, ++ {0x7d7, 249095}, ++ {0x7d8, 249518}, ++ {0x7d9, 249939}, ++ {0x7da, 250359}, ++ {0x7db, 250776}, ++ {0x7dc, 251192}, ++ {0x7dd, 251606}, ++ {0x7de, 252018}, ++ {0x7df, 252428}, ++ {0x7e0, 252836}, ++ {0x7e1, 253243}, ++ {0x7e2, 253648}, ++ {0x7e3, 254051}, ++ {0x7e4, 254452}, ++ {0x7e5, 254852}, ++ {0x7e6, 255250}, ++ {0x7e7, 255647}, ++ {0x7e8, 256041}, ++ {0x7e9, 256435}, ++ {0x7ea, 256826}, ++ {0x7eb, 257216}, ++ {0x7ec, 257604}, ++ {0x7ed, 257991}, ++ {0x7ee, 258376}, ++ {0x7ef, 258760}, ++ {0x7f0, 259142}, ++ {0x7f1, 259522}, ++ {0x7f2, 259901}, ++ {0x7f3, 260279}, ++ {0x7f4, 260655}, ++ {0x7f5, 261029}, ++ {0x7f6, 261402}, ++ {0x7f7, 261773}, ++}; ++ ++static inline struct ov4689_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ov4689_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov4689_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list ov4689_init_regs_1920_1080_30fps_mipi[] = { ++ //1080p@30fps 2 or 4 lane ++ /* @@ 0 35 RES_1920x1080_30fps_816Mbps 2Lane */ ++ /* ;SCLK = 80MHz MIPI CLK = 816Mbps/lane Mipi PCLK = 102MHz */ ++ /* ;HTS = 2294 VTS = 1162 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x23}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x02}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++// {0x3018, 0x72}, //4lan ++ {0x3018, 0x32}, //2lan ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x88}, ++ {0x3802, 0x00}, ++ {0x3803, 0xe0}, ++ {0x3804, 0x09}, ++ {0x3805, 0x17}, ++ {0x3806, 0x05}, ++ {0x3807, 0x1f}, ++ {0x3808, 0x07}, ++ {0x3809, 0x80}, ++ {0x380a, 0x04}, ++ {0x380b, 0x38}, ++ {0x380c, 0x08}, ++ {0x380d, 0xf6}, ++ {0x380e, 0x04}, ++ {0x380f, 0x8A}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x13}, ++ {0x4024, 0x07}, ++ {0x4025, 0x40}, ++ {0x4026, 0x07}, ++ {0x4027, 0x50}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x77}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++// {0x4837, 0x14}, //for zebra ++ {0x4837, 0x80}, //for halley5 ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++ {0x0100, 0x00}, ++ {OV4689_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov4689_init_regs_2592_1520_30fps_mipi[] = { ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x19}, //0x19 ++ {0x0303, 0x00}, ++ {0x0304, 0x03}, //0x03 ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x01}, ++ {0x0311, 0x00}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++ {0x3018, 0x32}, ++ {0x3019, 0x0c}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x60}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x00}, ++ {0x3801, 0x38}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x67}, ++ {0x3806, 0x05}, ++ {0x3807, 0xfb}, ++ {0x3808, 0x0a}, ++ {0x3809, 0x20}, ++ {0x380a, 0x05}, ++ {0x380b, 0xf0}, ++ {0x380c, 0x0A}, ++ {0x380d, 0x82},//0x18 ++ {0x380e, 0x06}, ++ {0x380f, 0xfb}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x08}, ++ {0x4023, 0xb3}, ++ {0x4024, 0x09}, ++ {0x4025, 0xe0}, ++ {0x4026, 0x09}, ++ {0x4027, 0xf0},// ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0xA1},// ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x10}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++ {0x0100, 0x00}, ++ {OV4689_REG_END, 0x00},/* END MARKER */ ++}; ++ ++ ++ ++ ++static struct regval_list ov4689_stream_on[] = { ++ {0x0100,0x01}, ++ {OV4689_REG_END, 0x00}, ++}; ++ ++static struct regval_list ov4689_stream_off[] = { ++ {0x0100,0x00}, ++ {OV4689_REG_END, 0x00}, ++}; ++ ++ ++int ov4689_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ unsigned int timeout = 100; ++ while(timeout--){ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == -EAGAIN){ ++ msleep(100); ++ continue; ++ } ++ else ++ break; ++ } ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != OV4689_REG_END) { ++ if (vals->reg_num == OV4689_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov4689_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int ov4689_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != OV4689_REG_END) { ++ if (vals->reg_num == OV4689_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov4689_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ov4689_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov4689_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int ov4689_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov4689_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++ ++static int ov4689_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ret = ov4689_read(sd, 0x300a, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV4689_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = ov4689_read(sd, 0x300b, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV4689_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ return 0; ++ ++} ++ ++static struct ov4689_win_size ov4689_win_sizes[] = { ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 30 << 16 | 1, ++ .sensor_info.total_width = 2294, ++ .sensor_info.total_height = 1162, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 80, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW10, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov4689_init_regs_1920_1080_30fps_mipi, ++ }, ++ { ++ .width = 2592, ++ .height = 1520, ++ .sensor_info.fps = 25 << 16 | 1, ++ .sensor_info.total_width = 2690, ++ .sensor_info.total_height = 1787, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 80, ++ .sensor_info.mipi_cfg.twidth = 2592, ++ .sensor_info.mipi_cfg.theight = 1520, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW10, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov4689_init_regs_2592_1520_30fps_mipi, ++ }, ++}; ++ ++ ++static int ov4689_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_OV4689_FMTS) ++ return -EINVAL; ++ ++ code->code = ov4689_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int ov4689_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov4689_format_struct *ovfmt; ++ struct ov4689_win_size *wsize; ++ struct ov4689_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ov4689_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov4689_info *info = to_state(sd); ++ struct ov4689_win_size *wsize = info->win; ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = wsize->width; ++ fmt->height = wsize->height; ++ fmt->code = wsize->mbus_code; ++ fmt->colorspace = wsize->colorspace; ++ *(unsigned int *)fmt->reserved = &wsize->sensor_info; /*reserved[0] reserved[1]*/ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ov4689_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ov4689_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ov4689_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++// printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov4689_again_lut); i++) { ++ lut = &ov4689_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov4689_again_lut); i++) { ++ lut = &ov4689_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ov4689_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ struct ov4689_info *info = to_state(sd); ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret += ov4689_read(sd, 0x3509, &v); ++ ++ reg_val |= v; ++ ret += ov4689_read(sd, 0x3508, &v); ++ reg_val |= v << 8; ++ ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ov4689_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct ov4689_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ int i; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += ov4689_write(sd, 0x3509, (unsigned char)(reg_value & 0xff)); ++ ret += ov4689_write(sd, 0x3508, (unsigned char)((reg_value>>8) & 0xff)); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ov4689_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct ov4689_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret += ov4689_write(sd, 0x3502, ((unsigned char)(value & 0xf)) << 4); ++ ret += ov4689_write(sd, 0x3501, (unsigned char)((value >> 4) & 0xff)); ++ ret += ov4689_write(sd, 0x3500, (unsigned char)((value >> 12) & 0xf)); ++ ++ return ret; ++} ++ ++static int ov4689_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov4689_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ov4689_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov4689_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ov4689_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov4689_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ov4689_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ov4689_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ov4689_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ov4689_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ov4689_s_gain turns off auto gain */ ++ return ov4689_s_gain(sd, info->gain->val); ++ } ++ return ov4689_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ov4689_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov4689_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ov4689_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ov4689_ctrl_ops = { ++ .s_ctrl = ov4689_s_ctrl, ++ .g_volatile_ctrl = ov4689_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov4689_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ov4689_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ov4689_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ov4689_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++static int ov4689_core_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov4689_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov4689_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++int ov4689_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ov4689_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ret = ov4689_write_array(sd, ov4689_stream_on); ++ printk("ov4689 stream on\n"); ++ ++ } ++ else { ++ ret = ov4689_write_array(sd, ov4689_stream_off); ++ printk("ov4689 stream off\n"); ++ } ++ return ret; ++} ++ ++ ++int ov4689_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct ov4689_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ov4689_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov4689_g_register, ++ .s_register = ov4689_s_register, ++#endif ++ .init = ov4689_core_init, ++}; ++ ++static const struct v4l2_subdev_video_ops ov4689_video_ops = { ++ .s_stream = ov4689_s_stream, ++ .g_frame_interval = ov4689_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov4689_pad_ops = { ++ //.enum_frame_interval = ov4689_enum_frame_interval, ++ //.num_frame_size = ov4689_enum_frame_size, ++ //.enum_mbus_code = ov4689_enum_mbus_code, ++ .set_fmt = ov4689_set_fmt, ++ .get_fmt = ov4689_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops ov4689_ops = { ++ .core = &ov4689_core_ops, ++ .video = &ov4689_video_ops, ++ .pad = &ov4689_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int ov4689_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct ov4689_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned long rate; ++ int mclk_index = -1; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &ov4689_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ char id_div[9]; ++ char id_mux[9]; ++ of_property_read_u32(client->dev.of_node, "ingenic,mclk", &mclk_index); ++ if(mclk_index == 0) { ++ memcpy(id_div, "div_cim0", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim0", sizeof(id_mux)); ++ } else if(mclk_index == 1) { ++ memcpy(id_div, "div_cim1", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim1", sizeof(id_mux)); ++ } else if(mclk_index == 2) { ++ memcpy(id_div, "div_cim2", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim2", sizeof(id_mux)); ++ } else ++ printk("Unkonwn mclk index\n"); ++ ++ ++ info->clk = v4l2_clk_get(&client->dev, id_div); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ info->sclka = devm_clk_get(&client->dev, id_mux); ++ ++ rate = v4l2_clk_get_rate(info->clk); ++ if (((rate / 1000) % 24000) != 0) { ++ ret = clk_set_parent(info->sclka, clk_get(NULL, "epll")); ++ info->sclka = devm_clk_get(&client->dev, "epll"); ++ if (IS_ERR(info->sclka)) { ++ pr_err("get sclka failed\n"); ++ } else { ++ rate = clk_get_rate(info->sclka); ++ if (((rate / 1000) % 27000) != 0) { ++ clk_set_rate(info->sclka, 891000000); ++ } ++ } ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ ov4689_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ov4689 */ ++ ret = ov4689_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ov4689 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ /*IRCUT ctl 0:off 1:on*/ ++ ov4689_ircut(sd, 0); ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 261773, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_EXPOSURE, 0, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &ov4689_win_sizes[1]; ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ov4689 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ov4689_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov4689_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id ov4689_id[] = { ++ { "ov4689", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov4689_id); ++ ++static const struct of_device_id ov4689_of_match[] = { ++ {.compatible = "ovit,ov4689", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov4689_of_match); ++ ++ ++static struct i2c_driver ov4689_driver = { ++ .driver = { ++ .name = "ov4689", ++ .of_match_table = of_match_ptr(ov4689_of_match), ++ }, ++ .probe = ov4689_probe, ++ .remove = ov4689_remove, ++ .id_table = ov4689_id, ++}; ++ ++module_i2c_driver(ov4689_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision ov4689 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/ov7251.c b/module_drivers/drivers/media/i2c/ingenic-isp-v2/ov7251.c +new file mode 100644 +index 000000000..ee083617b +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/ov7251.c +@@ -0,0 +1,1534 @@ ++/* ++ * A V4L2 driver for OmniVision OV7251 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define OV7251_CHIP_ID_H (0x77) ++#define OV7251_CHIP_ID_L (0x50) ++#define OV7251_REG_END 0xffff ++#define OV7251_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ov7251_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ov7251_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov7251_supply { ++ struct regulator *vdd2v8; /* Digital Core supply */ ++ struct regulator *vdd1v8; /* Digital I/O supply */ ++}; ++ ++struct ov7251_info { ++ struct ov7251_supply supply; ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ struct clk *sclka; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ov7251_win_size *win; ++ ++ struct ov7251_gpio reset; ++ struct ov7251_gpio ircutp; ++ struct ov7251_gpio ircutn; ++ struct ov7251_gpio pwr; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut ov7251_again_lut[] = { ++ ++ {0x80, 0}, ++ {0x88, 5731}, ++ {0x90, 11136}, ++ {0x98, 16248}, ++ {0xa0, 21097}, ++ {0xa8, 25710}, ++ {0xb0, 30109}, ++ {0xb8, 34312}, ++ {0xc0, 38336}, ++ {0xc8, 42195}, ++ {0xd0, 45904}, ++ {0xd8, 49472}, ++ {0xe0, 52910}, ++ {0xe8, 56228}, ++ {0xf0, 59433}, ++ {0xf8, 62534}, ++ {0x178, 65536}, ++ {0x17c, 68445}, ++ {0x180, 71267}, ++ {0x184, 74008}, ++ {0x188, 76672}, ++ {0x18c, 79262}, ++ {0x190, 81784}, ++ {0x194, 84240}, ++ {0x198, 86633}, ++ {0x19c, 88968}, ++ {0x1a0, 91246}, ++ {0x1a4, 93471}, ++ {0x1a8, 95645}, ++ {0x1ac, 97770}, ++ {0x1b0, 99848}, ++ {0x1b4, 101881}, ++ {0x1b8, 103872}, ++ {0x1bc, 105821}, ++ {0x1c0, 107731}, ++ {0x1c4, 109604}, ++ {0x1c8, 111440}, ++ {0x1cc, 113241}, ++ {0x1d0, 115008}, ++ {0x1d4, 116743}, ++ {0x1d8, 118446}, ++ {0x1dc, 120120}, ++ {0x1e0, 121764}, ++ {0x1e4, 123380}, ++ {0x1e8, 124969}, ++ {0x1ec, 126532}, ++ {0x1f0, 128070}, ++ {0x1f4, 129583}, ++ {0x374, 131072}, ++ {0x376, 132537}, ++ {0x378, 133981}, ++ {0x37a, 135403}, ++ {0x37c, 136803}, ++ {0x37e, 138184}, ++ {0x380, 139544}, ++ {0x382, 140885}, ++ {0x384, 142208}, ++ {0x386, 143512}, ++ {0x388, 144798}, ++ {0x38a, 146067}, ++ {0x38c, 147320}, ++ {0x38e, 148556}, ++ {0x390, 149776}, ++ {0x392, 150980}, ++ {0x394, 152169}, ++ {0x396, 153344}, ++ {0x398, 154504}, ++ {0x39a, 155650}, ++ {0x39c, 156782}, ++ {0x39e, 157901}, ++ {0x3a0, 159007}, ++ {0x3a2, 160100}, ++ {0x3a4, 161181}, ++ {0x3a6, 162249}, ++ {0x3a8, 163306}, ++ {0x3aa, 164350}, ++ {0x3ac, 165384}, ++ {0x3ae, 166406}, ++ {0x3b0, 167417}, ++ {0x3b2, 168418}, ++ {0x3b4, 169408}, ++ {0x3b6, 170387}, ++ {0x3b8, 171357}, ++ {0x3ba, 172317}, ++ {0x3bc, 173267}, ++ {0x3be, 174208}, ++ {0x3c0, 175140}, ++ {0x3c2, 176062}, ++ {0x3c4, 176976}, ++ {0x3c6, 177880}, ++ {0x3c8, 178777}, ++ {0x3ca, 179664}, ++ {0x3cc, 180544}, ++ {0x3ce, 181415}, ++ {0x3d0, 182279}, ++ {0x3d2, 183134}, ++ {0x3d4, 183982}, ++ {0x3d6, 184823}, ++ {0x3d8, 185656}, ++ {0x3da, 186482}, ++ {0x3dc, 187300}, ++ {0x3de, 188112}, ++ {0x3e0, 188916}, ++ {0x3e2, 189714}, ++ {0x3e4, 190505}, ++ {0x3e6, 191290}, ++ {0x3e8, 192068}, ++ {0x3ea, 192840}, ++ {0x3ec, 193606}, ++ {0x3ee, 194365}, ++ {0x3f0, 195119}, ++ {0x3f2, 195866}, ++ {0x778, 196608}, ++ {0x779, 197343}, ++ {0x77a, 198073}, ++ {0x77b, 198798}, ++ {0x77c, 199517}, ++ {0x77d, 200230}, ++ {0x77e, 200939}, ++ {0x77f, 201642}, ++ {0x780, 202339}, ++ {0x781, 203032}, ++ {0x782, 203720}, ++ {0x783, 204402}, ++ {0x784, 205080}, ++ {0x785, 205753}, ++ {0x786, 206421}, ++ {0x787, 207085}, ++ {0x788, 207744}, ++ {0x789, 208398}, ++ {0x78a, 209048}, ++ {0x78b, 209693}, ++ {0x78c, 210334}, ++ {0x78d, 210971}, ++ {0x78e, 211603}, ++ {0x78f, 212232}, ++ {0x790, 212856}, ++ {0x791, 213476}, ++ {0x792, 214092}, ++ {0x793, 214704}, ++ {0x794, 215312}, ++ {0x795, 215916}, ++ {0x796, 216516}, ++ {0x797, 217113}, ++ {0x798, 217705}, ++ {0x799, 218294}, ++ {0x79a, 218880}, ++ {0x79b, 219462}, ++ {0x79c, 220040}, ++ {0x79d, 220615}, ++ {0x79e, 221186}, ++ {0x79f, 221754}, ++ {0x7a0, 222318}, ++ {0x7a1, 222880}, ++ {0x7a2, 223437}, ++ {0x7a3, 223992}, ++ {0x7a4, 224543}, ++ {0x7a5, 225091}, ++ {0x7a6, 225636}, ++ {0x7a7, 226178}, ++ {0x7a8, 226717}, ++ {0x7a9, 227253}, ++ {0x7aa, 227785}, ++ {0x7ab, 228315}, ++ {0x7ac, 228842}, ++ {0x7ad, 229365}, ++ {0x7ae, 229886}, ++ {0x7af, 230404}, ++ {0x7b0, 230920}, ++ {0x7b1, 231432}, ++ {0x7b2, 231942}, ++ {0x7b3, 232449}, ++ {0x7b4, 232953}, ++ {0x7b5, 233455}, ++ {0x7b6, 233954}, ++ {0x7b7, 234450}, ++ {0x7b8, 234944}, ++ {0x7b9, 235435}, ++ {0x7ba, 235923}, ++ {0x7bb, 236410}, ++ {0x7bc, 236893}, ++ {0x7bd, 237374}, ++ {0x7be, 237853}, ++ {0x7bf, 238329}, ++ {0x7c0, 238803}, ++ {0x7c1, 239275}, ++ {0x7c2, 239744}, ++ {0x7c3, 240211}, ++ {0x7c4, 240676}, ++ {0x7c5, 241138}, ++ {0x7c6, 241598}, ++ {0x7c7, 242056}, ++ {0x7c8, 242512}, ++ {0x7c9, 242965}, ++ {0x7ca, 243416}, ++ {0x7cb, 243865}, ++ {0x7cc, 244313}, ++ {0x7cd, 244757}, ++ {0x7ce, 245200}, ++ {0x7cf, 245641}, ++ {0x7d0, 246080}, ++ {0x7d1, 246517}, ++ {0x7d2, 246951}, ++ {0x7d3, 247384}, ++ {0x7d4, 247815}, ++ {0x7d5, 248243}, ++ {0x7d6, 248670}, ++ {0x7d7, 249095}, ++ {0x7d8, 249518}, ++ {0x7d9, 249939}, ++ {0x7da, 250359}, ++ {0x7db, 250776}, ++ {0x7dc, 251192}, ++ {0x7dd, 251606}, ++ {0x7de, 252018}, ++ {0x7df, 252428}, ++ {0x7e0, 252836}, ++ {0x7e1, 253243}, ++ {0x7e2, 253648}, ++ {0x7e3, 254051}, ++ {0x7e4, 254452}, ++ {0x7e5, 254852}, ++ {0x7e6, 255250}, ++ {0x7e7, 255647}, ++ {0x7e8, 256041}, ++ {0x7e9, 256435}, ++ {0x7ea, 256826}, ++ {0x7eb, 257216}, ++ {0x7ec, 257604}, ++ {0x7ed, 257991}, ++ {0x7ee, 258376}, ++ {0x7ef, 258760}, ++ {0x7f0, 259142}, ++ {0x7f1, 259522}, ++ {0x7f2, 259901}, ++ {0x7f3, 260279}, ++ {0x7f4, 260655}, ++ {0x7f5, 261029}, ++ {0x7f6, 261402}, ++ {0x7f7, 261773}, ++}; ++ ++static inline struct ov7251_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ov7251_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov7251_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++ ++ ++static struct regval_list ov7251_init_regs_640_480_mipi[] = { ++ {0x3501, 0x00}, ++ {0x3502, 0x80}, ++ {0x3674, 0xef}, ++ {0x373c, 0x8e}, ++ {0x37a8, 0x01}, ++ {0x37a9, 0xc0}, ++ {0x3803, 0x04}, ++ {0x3807, 0xeb}, ++ {0x3808, 0x02}, ++ {0x3809, 0x80}, ++ {0x380a, 0x01}, ++ {0x380b, 0xe0}, ++ {0x380c, 0x05}, ++ {0x380d, 0x70}, ++ {0x380e, 0x02}, ++ {0x380f, 0x40}, ++ {0x3813, 0x05}, ++ {0x3814, 0x11}, ++ {0x3815, 0x11}, ++ {0x3820, 0x40}, ++ {0x3821, 0x00}, ++ {0x3c0c, 0x01}, ++ {0x3c0d, 0xd0}, ++ {0x3c0e, 0x02}, ++ {0x3c0f, 0x0a}, ++ {0x4001, 0x42}, ++ {0x4004, 0x04}, ++ {0x0100, 0x01}, ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov7251_init_regs_320_240_mipi[] = { ++ {0x3501, 0x00}, ++ {0x3502, 0x90}, ++ {0x3674, 0xef}, ++ {0x373c, 0xe8}, ++ {0x37a8, 0x02}, ++ {0x37a9, 0x14}, ++ {0x3803, 0x00}, ++ {0x3807, 0xef}, ++ {0x3808, 0x01}, ++ {0x3809, 0x40}, ++ {0x380a, 0x00}, ++ {0x380b, 0xf0}, ++ {0x380c, 0x05}, ++ {0x380d, 0x70}, ++ {0x380e, 0x02}, ++ {0x380f, 0x40}, ++ {0x3813, 0x05}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ {0x3820, 0x42}, ++ {0x3821, 0x01}, ++ {0x3c0e, 0x01}, ++ {0x3c0f, 0x30}, ++ {0x4001, 0x40}, ++ {0x4004, 0x02}, ++ {0x0100, 0x01}, ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov7251_init_regs_160_120_mipi[] = { ++ {0x3501, 0x02}, // ++ {0x3502, 0x80}, //expo ++// {0x3509, 0x18}, ++// {0x3504, 0x03}, ++// {0x3505, 0x00}, //mannual again ++ {0x3674, 0xff}, // ++ {0x373c, 0xe8}, // ++ {0x37a8, 0x02}, // ++ {0x37a9, 0x14}, // ++ {0x3803, 0x00}, // ++ {0x3807, 0xef}, // ++ {0x3808, 0x00}, //01 ++ {0x3809, 0xa0}, //40 ++ {0x380a, 0x00}, // ++ {0x380b, 0x78}, //f0 ++ {0x380c, 0x03}, // ++ {0x380d, 0xa0}, //HTS ++ {0x380e, 0x02}, // ++ {0x380f, 0x0a}, //VTS ++ {0x3811, 0x02}, ++ {0x3813, 0x03}, //05 ++ {0x3814, 0x44}, //31 ++ {0x3815, 0x44}, //31 ++ {0x3820, 0x42}, // ++ {0x3821, 0x01}, // ++ {0x3c0c, 0x01}, // ++ {0x3c0d, 0x82}, // ++ {0x3c0e, 0x01}, // ++ {0x3c0f, 0x30}, // ++ {0x4001, 0x40}, // ++ {0x4004, 0x02}, // ++ {0x0100, 0x01}, // ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov7251_common_init_regs_mipi[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x3005, 0x00}, ++ {0x3012, 0xc0}, ++ {0x3013, 0xd2}, ++ {0x3014, 0x04}, ++ {0x3016, 0x10}, ++ {0x3017, 0x00}, ++ {0x3018, 0x00}, ++ {0x301a, 0x00}, ++ {0x301b, 0x00}, ++ {0x301c, 0x00}, ++ {0x3023, 0x05}, ++ {0x3037, 0xf0}, ++ {0x3098, 0x04}, ++ {0x3099, 0x28}, ++ {0x309a, 0x05}, ++ {0x309b, 0x04}, ++ {0x30b0, 0x0a}, ++ {0x30b1, 0x01}, ++ {0x30b3, 0x64}, ++ {0x30b4, 0x03}, ++ {0x30b5, 0x05}, ++ {0x3106, 0xda}, ++ {0x3500, 0x00}, ++ {0x3503, 0x07}, ++ {0x3509, 0x10}, ++ {0x350b, 0x10}, ++ {0x3600, 0x1c}, ++ {0x3602, 0x62}, ++ {0x3620, 0xb7}, ++ {0x3622, 0x04}, ++ {0x3626, 0x21}, ++ {0x3627, 0x30}, ++ {0x3630, 0x44}, ++ {0x3631, 0x35}, ++ {0x3634, 0x60}, ++ {0x3636, 0x00}, ++ {0x3662, 0x01}, ++ {0x3663, 0x70}, ++ {0x3664, 0xf0}, ++ {0x3666, 0x0a}, ++ {0x3669, 0x1a}, ++ {0x366a, 0x00}, ++ {0x366b, 0x50}, ++ {0x3673, 0x01}, ++ {0x3675, 0x03}, ++ {0x3705, 0x41}, ++ {0x3709, 0x40}, ++ {0x3742, 0x00}, ++ {0x3757, 0xb3}, ++ {0x3788, 0x00}, ++ {0x3800, 0x00}, ++ {0x3801, 0x04}, ++ {0x3802, 0x00}, ++ {0x3804, 0x02}, ++ {0x3805, 0x8b}, ++ {0x3806, 0x01}, ++ {0x3810, 0x00}, ++ {0x3811, 0x04}, ++ {0x3812, 0x00}, ++ {0x382f, 0x0e}, ++ {0x3832, 0x00}, ++ {0x3833, 0x05}, ++ {0x3834, 0x00}, ++ {0x3835, 0x0c}, ++ {0x3837, 0x00}, ++ {0x3b80, 0x00}, ++ {0x3b81, 0xa5}, ++ {0x3b82, 0x10}, ++ {0x3b83, 0x00}, ++ {0x3b84, 0x08}, ++ {0x3b85, 0x00}, ++ {0x3b86, 0x01}, ++ {0x3b87, 0x00}, ++ {0x3b88, 0x00}, ++ {0x3b89, 0x00}, ++ {0x3b8a, 0x00}, ++ {0x3b8b, 0x05}, ++ {0x3b8c, 0x00}, ++ {0x3b8d, 0x00}, ++ {0x3b8e, 0x00}, ++ {0x3b8f, 0x1a}, ++ {0x3b94, 0x05}, ++ {0x3b95, 0xf2}, ++ {0x3b96, 0x40}, ++ {0x3c00, 0x89}, ++ {0x3c01, 0x63}, ++ {0x3c02, 0x01}, ++ {0x3c03, 0x00}, ++ {0x3c04, 0x00}, ++ {0x3c05, 0x03}, ++ {0x3c06, 0x00}, ++ {0x3c07, 0x06}, ++ {0x4005, 0x00}, ++ {0x404e, 0x01}, ++ {0x4300, 0xff}, ++ {0x4301, 0x00}, ++ {0x4501, 0x48}, ++ {0x4600, 0x00}, ++ {0x4601, 0x4e}, ++ {0x4801, 0x0f}, ++ {0x4806, 0x0f}, ++ {0x4819, 0xaa}, ++ {0x4823, 0x3e}, ++ {0x4837, 0x19}, ++ {0x4a0d, 0x00}, ++ {0x4a47, 0x7f}, ++ {0x4a49, 0xf0}, ++ {0x4a4b, 0x30}, ++ {0x5000, 0x85}, ++ {0x5001, 0x80}, ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list ov7251_stream_on_mipi[] = { ++ {0x0100, 0x01}, ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov7251_stream_off_mipi[] = { ++ {0x0100, 0x00}, ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int ov7251_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct ov7251_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct ov7251_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != OV7251_REG_END) { ++ if (vals->reg_num == OV7251_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov7251_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int ov7251_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != OV7251_REG_END) { ++ if (vals->reg_num == OV7251_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov7251_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ov7251_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov7251_info *info = to_state(sd); ++ printk("%s >>>>>>>>>>> %s >>>>\n",__func__,__func__); ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(20); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(20); ++ } ++ return 0; ++} ++ ++static int ov7251_pwr_set(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov7251_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->pwr.pin, info->pwr.active_level); ++ } else { ++ gpio_direction_output(info->pwr.pin, !info->pwr.active_level); ++ } ++ return 0; ++} ++ ++static int ov7251_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov7251_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int ov7251_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov7251_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov7251_write_array(sd, ov7251_common_init_regs_mipi); ++ ++ return ret; ++} ++ ++ ++ ++static int ov7251_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v = 0; ++ int ret; ++//while(1) ++ { ++ ret = ov7251_read(sd, 0x300a, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ } ++ if (ret < 0) ++ return ret; ++ if (v != OV7251_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = ov7251_read(sd, 0x300b, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ ++ if (ret < 0) ++ return ret; ++ if (v != OV7251_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++ ++static struct ov7251_win_size ov7251_win_sizes[] = { ++ /* { */ ++ /* .sensor_info.mipi_cfg.twidth = 640, */ ++ /* .sensor_info.mipi_cfg.theight = 480, */ ++ /* .sensor_info.mipi_cfg.mipi_crop_start0x = 0, */ ++ /* .sensor_info.mipi_cfg.mipi_crop_start0y = 0, */ ++ /* .sensor_info.fps = 60 << 16 | 1, */ ++ ++ /* .width = 640, */ ++ /* .height = 480, */ ++ /* .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, */ ++ /* .colorspace = V4L2_COLORSPACE_SRGB, */ ++ /* .regs = ov7251_init_regs_640_480_mipi, */ ++ /* }, */ ++ /* { */ ++ /* .sensor_info.mipi_cfg.twidth = 320, */ ++ /* .sensor_info.mipi_cfg.theight = 240, */ ++ /* .sensor_info.mipi_cfg.mipi_crop_start0x = 0, */ ++ /* .sensor_info.mipi_cfg.mipi_crop_start0y = 0, */ ++ /* .sensor_info.fps = 60 << 16 | 1, */ ++ ++ /* .width = 320, */ ++ /* .height = 240, */ ++ /* .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, */ ++ /* .colorspace = V4L2_COLORSPACE_SRGB, */ ++ /* .regs = ov7251_init_regs_320_240_mipi, */ ++ /* }, */ ++ /* { */ ++ /* .sensor_info.mipi_cfg.twidth = 160, */ ++ /* .sensor_info.mipi_cfg.theight = 120, */ ++ /* .sensor_info.mipi_cfg.mipi_crop_start0x = 0, */ ++ /* .sensor_info.mipi_cfg.mipi_crop_start0y = 0, */ ++ /* .sensor_info.fps = 75 << 16 | 1, */ ++ ++ /* .width = 160, */ ++ /* .height = 120, */ ++ /* .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, */ ++ /* .colorspace = V4L2_COLORSPACE_SRGB, */ ++ /* .regs = ov7251_init_regs_160_120_mipi, */ ++ /* }, */ ++ { ++ .width = 640, ++ .height = 480, ++ .sensor_info.fps = 60 << 16 | 1, ++// .sensor_info.total_width = 656, ++// .sensor_info.total_height = 496, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 600, ++ .sensor_info.mipi_cfg.twidth = 640, ++ .sensor_info.mipi_cfg.theight = 480, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW10, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov7251_init_regs_640_480_mipi, ++ }, ++ { ++ .width = 320, ++ .height = 240, ++ .sensor_info.fps = 60 << 16 | 1, ++// .sensor_info.total_width = 656, ++// .sensor_info.total_height = 496, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 600, ++ .sensor_info.mipi_cfg.twidth = 320, ++ .sensor_info.mipi_cfg.theight = 240, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW10, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov7251_init_regs_320_240_mipi, ++ }, ++ { ++ .width = 160, ++ .height = 120, ++ .sensor_info.fps = 100 << 16 | 1, ++ // .sensor_info.total_width = 656, ++ // .sensor_info.total_height = 496, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 600, ++ .sensor_info.mipi_cfg.twidth = 160, ++ .sensor_info.mipi_cfg.theight = 120, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW10, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov7251_init_regs_160_120_mipi, ++ }, ++}; ++ ++static const struct ov7251_win_size *ov7251_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(ov7251_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(ov7251_win_sizes); i++) { ++ if ((*width >= ov7251_win_sizes[i].width) && ++ (*height >= ov7251_win_sizes[i].height)) { ++ *width = ov7251_win_sizes[i].width; ++ *height = ov7251_win_sizes[i].height; ++ return &ov7251_win_sizes[i]; ++ } ++ } ++ ++ *width = ov7251_win_sizes[default_size].width; ++ *height = ov7251_win_sizes[default_size].height; ++ return &ov7251_win_sizes[default_size]; ++} ++ ++ ++static int ov7251_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_OV7251_FMTS) ++ return -EINVAL; ++ ++ code->code = ov7251_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int ov7251_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov7251_format_struct *ovfmt; ++ struct ov7251_win_size *wsize; ++ struct ov7251_info *info = to_state(sd); ++ int ret; ++ ++ info->win = ov7251_select_win(&format->format.width, &format->format.height); ++ ++ return 0; ++} ++ ++static int ov7251_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov7251_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ov7251_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ov7251_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ov7251_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++// printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov7251_again_lut); i++) { ++ lut = &ov7251_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov7251_again_lut); i++) { ++ lut = &ov7251_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++} ++ ++static int ov7251_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ /* ++ struct ov7251_info *info = to_state(sd); ++ char v = 0; ++ unsigned int reg_val = 0; ++ ++ ++ ret += ov7251_read(sd, 0x3509, &v); ++ ++ reg_val |= v; ++ ret += ov7251_read(sd, 0x3508, &v); ++ reg_val |= v << 8; ++ ++ ++ *value = regval_to_again(reg_val); ++ */ ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ov7251_s_again(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++#if 0 ++ struct ov7251_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int i; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += ov7251_write(sd, 0x3509, (unsigned char)(reg_value & 0xff)); ++ ret += ov7251_write(sd, 0x3508, (unsigned char)((reg_value>>8) & 0xff)); ++ if (ret < 0) ++ return ret; ++ ++#endif ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ov7251_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ /* ++ struct ov7251_info *info = to_state(sd); ++ ++ ret += ov7251_write(sd, 0x3502, ((unsigned char)(value & 0xf)) << 4); ++ ret += ov7251_write(sd, 0x3501, (unsigned char)((value >> 4) & 0xff)); ++ ret += ov7251_write(sd, 0x3500, (unsigned char)((value >> 12) & 0xf)); ++ ++ */ ++ return ret; ++} ++ ++static int ov7251_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov7251_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ov7251_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov7251_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov7251_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ov7251_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ov7251_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ov7251_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ov7251_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ov7251_s_gain turns off auto gain */ ++ return ov7251_s_gain(sd, info->gain->val); ++ } ++ return ov7251_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ov7251_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov7251_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ov7251_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ov7251_ctrl_ops = { ++ .s_ctrl = ov7251_s_ctrl, ++ .g_volatile_ctrl = ov7251_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov7251_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ov7251_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ov7251_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ov7251_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int ov7251_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ov7251_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ov7251_write_array(sd, info->win->regs); ++ ov7251_s_again(sd, 100000); ++ ret = ov7251_write_array(sd, ov7251_stream_on_mipi); ++ printk("ov7251 stream on\n"); ++ ++ } ++ else { ++ ret = ov7251_write_array(sd, ov7251_stream_off_mipi); ++ printk("ov7251 stream off\n"); ++ } ++ return ret; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ov7251_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov7251_g_register, ++ .s_register = ov7251_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops ov7251_video_ops = { ++ .s_stream = ov7251_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov7251_pad_ops = { ++ //.enum_frame_interval = ov7251_enum_frame_interval, ++ //.num_frame_size = ov7251_enum_frame_size, ++ //.enum_mbus_code = ov7251_enum_mbus_code, ++ .set_fmt = ov7251_set_fmt, ++ .get_fmt = ov7251_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops ov7251_ops = { ++ .core = &ov7251_core_ops, ++ .video = &ov7251_video_ops, ++ .pad = &ov7251_pad_ops, ++}; ++ ++#if 0 ++int ov7251_regulator_get_supply(struct device *dev) ++{ ++ int ret; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov7251_info *info = to_state(sd); ++ ++ info->supply.vdd2v8 = devm_regulator_get_optional(dev, "vdd2v8"); ++ info->supply.vdd1v8 = devm_regulator_get_optional(dev, "vdd1v8"); ++ ++ if (IS_ERR(info->supply.vdd2v8)) { ++ if (PTR_ERR(info->supply.vdd2v8) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ printk("No vdd2v8 regulator found\n"); ++ } ++ ++ if (IS_ERR(info->supply.vdd1v8)) { ++ if (PTR_ERR(info->supply.vdd1v8) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ printk("No vdd1v8 regulator found\n"); ++ } ++ if (!IS_ERR(info->supply.vdd2v8)) { ++ ret = regulator_enable(info->supply.vdd2v8); ++ if (ret) ++ dev_err(&client->dev, "ov7251 vdd2v8 supply enable failed\n"); ++ } ++ if (!IS_ERR(info->supply.vdd1v8)) { ++ ret = regulator_enable(info->supply.vdd1v8); ++ if (ret) ++ dev_err(&client->dev, "ov7251 vdd1v8 supply enable failed\n"); ++ } ++ ++ return 0; ++} ++#endif ++/* ----------------------------------------------------------------------- */ ++ ++static int ov7251_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct ov7251_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ int tmp; ++ int mclk_index; ++ unsigned long rate; ++ dev_info(&client->dev, "ov7251 probing\n"); ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwr-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwr.pin = gpio; ++ info->pwr.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ v4l2_i2c_subdev_init(sd, client, &ov7251_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /* ret = ov7251_regulator_get_supply(&client->dev); */ ++ /* if (ret) */ ++ /* dev_err(&client->dev, "get supply failed!\n"); */ ++ ++ *(volatile unsigned int *)(0xb0010100) = 1; // set gpio a work at 1.8v ++ ov7251_pwr_set(sd,1); ++ /*clk*/ ++ char id_div[9]; ++ char id_mux[9]; ++ printk("%s:%d\n", __func__, __LINE__); ++ of_property_read_u32(client->dev.of_node, "ingenic,mclk", &mclk_index); ++ if(mclk_index == 0) { ++ memcpy(id_div, "div_cim0", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim0", sizeof(id_mux)); ++ } else if(mclk_index == 1) { ++ memcpy(id_div, "div_cim1", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim1", sizeof(id_mux)); ++ } else if(mclk_index == 2) { ++ memcpy(id_div, "div_cim2", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim2", sizeof(id_mux)); ++ } else ++ printk("Unkonwn mclk index\n"); ++ ++ ++ info->clk = v4l2_clk_get(&client->dev, id_div); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ info->sclka = devm_clk_get(&client->dev, id_mux); ++ ++ printk("sclka is %s\n", info->sclka?"NOT NULL":"NULL"); ++ rate = v4l2_clk_get_rate(info->clk); ++ if (((rate / 1000) % 24000) != 0) { ++ ret = clk_set_parent(info->sclka, clk_get(NULL, "epll")); ++ info->sclka = devm_clk_get(&client->dev, "epll"); ++ if (IS_ERR(info->sclka)) { ++ pr_err("get sclka failed\n"); ++ } else { ++ rate = clk_get_rate(info->sclka); ++ if (((rate / 1000) % 24000) != 0) { ++ clk_set_rate(info->sclka, 120000000); ++ } ++ } ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ov7251_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ov7251 */ ++ ret = ov7251_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ov7251 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 261773, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ ov7251_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ov7251 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ov7251_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov7251_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id ov7251_id[] = { ++ { "ov7251", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov7251_id); ++ ++static const struct of_device_id ov7251_of_match[] = { ++ {.compatible = "ovti,ov7251", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++int ov7251_suspend(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov7251_info *info = to_state(sd); ++ int ret; ++ ++ /* if (!IS_ERR(info->supply.vdd2v8)) { */ ++ /* ret = regulator_disable(info->supply.vdd2v8); */ ++ /* if (ret) { */ ++ /* dev_err(dev, "ov7251 vdd2v8 supply disable failed\n"); */ ++ /* return ret; */ ++ /* } */ ++ /* } */ ++ /* if (!IS_ERR(info->supply.vdd1v8)) { */ ++ /* ret = regulator_disable(info->supply.vdd1v8); */ ++ /* if (ret) { */ ++ /* dev_err(dev, "ov7251 vdd1v8 supply disable failed\n"); */ ++ /* return ret; */ ++ /* } */ ++ /* } */ ++ ++ v4l2_clk_disable(info->clk); ++ return 0; ++} ++ ++int ov7251_resume(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov7251_info *info = to_state(sd); ++ int ret; ++ ++ /* if (!IS_ERR(info->supply.vdd2v8)) { */ ++ /* ret = regulator_enable(info->supply.vdd2v8); */ ++ /* if (ret) { */ ++ /* dev_err(dev, "ov7251 vdd2v8 supply enable failed\n"); */ ++ /* } */ ++ /* } */ ++ /* if (!IS_ERR(info->supply.vdd1v8)) { */ ++ /* ret = regulator_enable(info->supply.vdd1v8); */ ++ /* if (ret) { */ ++ /* dev_err(dev, "ov7251 vdd1v8 supply enable failed\n"); */ ++ /* } */ ++ /* } */ ++ ++ v4l2_clk_enable(info->clk); ++ ov7251_reset(sd, 1); ++ ov7251_init(sd, 1); ++ return 0; ++} ++ ++const struct dev_pm_ops ov7251_pm = ++{ ++ .suspend = ov7251_suspend, ++ .resume = ov7251_resume, ++}; ++ ++ ++ ++static struct i2c_driver ov7251_driver = { ++ .driver = { ++ .name = "ov7251", ++ .of_match_table = of_match_ptr(ov7251_of_match), ++ .pm = &ov7251_pm, ++ }, ++ .probe = ov7251_probe, ++ .remove = ov7251_remove, ++ .id_table = ov7251_id, ++}; ++ ++module_i2c_driver(ov7251_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision ov7251 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/sc230ai.c b/module_drivers/drivers/media/i2c/ingenic-isp-v2/sc230ai.c +new file mode 100644 +index 000000000..a63de3007 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/sc230ai.c +@@ -0,0 +1,1972 @@ ++/* ++ * A V4L2 driver for OmniVision OV2735a cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define SC230AI_CHIP_ID_H (0xcb) ++#define SC230AI_CHIP_ID_L (0x34) ++#define SC230AI_REG_END 0xff ++#define SC230AI_REG_DELAY 0x00 ++#define SC230AI_PAGE_REG 0xfd ++ ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct sc230ai_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct sc230ai_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct sc230ai_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ struct v4l2_ctrl *again_short; ++ ++ struct v4l2_clk *clk; ++ struct clk *sclka; ++ ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *exposure_short; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct sc230ai_win_size *win; ++ ++ struct sc230ai_gpio xshutdn; ++ struct sc230ai_gpio pwdn; ++ struct sc230ai_gpio efsync; ++ struct sc230ai_gpio led; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int fine_value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++ ++struct again_lut sc230ai_again_lut[] = { ++ /* ++ {0x00, 0}, ++ {0x01, 65536}, ++ {0x40, 115455}, ++ {0x48, 180991}, ++ {0x49, 246527}, ++ {0x4b, 312063}, ++ {0x4f, 377599}, ++ {0x5f, 443135}, ++ */ ++ ++ {0x00,0x80,0}, ++ {0x00,0x82,1501}, ++ {0x00,0x84,2886}, ++ {0x00,0x86,4343}, ++ {0x00,0x88,5776}, ++ {0x00,0x8a,7101}, ++ {0x00,0x8c,8494}, ++ {0x00,0x8e,9782}, ++ {0x00,0x90,11136}, ++ {0x00,0x92,12471}, ++ {0x00,0x94,13706}, ++ {0x00,0x96,15006}, ++ {0x00,0x98,16288}, ++ {0x00,0x9a,17474}, ++ {0x00,0x9c,18724}, ++ {0x00,0x9e,19880}, ++ {0x00,0xa0,21098}, ++ {0x00,0xa2,22300}, ++ {0x00,0xa4,23414}, ++ {0x00,0xa6,24588}, ++ {0x00,0xa8,25747}, ++ {0x00,0xaa,26821}, ++ {0x00,0xac,27953}, ++ {0x00,0xae,29003}, ++ {0x00,0xb0,30109}, ++ {0x00,0xb2,31203}, ++ {0x00,0xb4,32217}, ++ {0x00,0xb6,33287}, ++ {0x00,0xb8,34345}, ++ {0x00,0xba,35326}, ++ {0x00,0xbc,36362}, ++ {0x00,0xbe,37322}, ++ {0x00,0xc0,38336}, ++ {0x00,0xc2,39339}, ++ {0x00,0xc4,40270}, ++ {0x00,0xc6,41253}, ++ {0x00,0xc8,42226}, ++ {0x00,0xca,43129}, ++ {0x00,0xcc,44083}, ++ {0x00,0xce,44968}, ++ {0x00,0xd0,45904}, ++ {0x00,0xd2,46830}, ++ {0x00,0xd4,47691}, ++ {0x00,0xd6,48600}, ++ {0x00,0xd8,49500}, ++ {0x00,0xda,50337}, ++ {0x00,0xdc,51221}, ++ {0x00,0xdf,52042}, ++ {0x00,0xe0,52911}, ++ {0x00,0xe2,53771}, ++ {0x00,0xe4,54571}, ++ {0x00,0xe6,55417}, ++ {0x00,0xe8,56255}, ++ {0x00,0xea,57034}, ++ {0x00,0xec,57858}, ++ {0x00,0xee,58624}, ++ {0x00,0xf0,59434}, ++ {0x00,0xf2,60237}, ++ {0x00,0xf4,60984}, ++ {0x00,0xf6,61775}, ++ {0x00,0xf8,62559}, ++ {0x00,0xfa,63288}, ++ {0x00,0xfc,64059}, ++ {0x00,0xfe,64777}, ++ {0x01,0x80,65536}, ++ {0x01,0x82,66990}, ++ {0x01,0x84,68468}, ++ {0x01,0x86,69879}, ++ {0x01,0x88,71268}, ++ {0x01,0x8a,72637}, ++ {0x01,0x8c,74030}, ++ {0x01,0x8e,75360}, ++ {0x01,0x90,76672}, ++ {0x01,0x92,77966}, ++ {0x01,0x94,79283}, ++ {0x01,0x96,80542}, ++ {0x01,0x98,81784}, ++ {0x01,0x9a,83010}, ++ {0x01,0x9c,84260}, ++ {0x01,0x9e,85454}, ++ {0x01,0xa0,86634}, ++ {0x01,0xa2,87799}, ++ {0x01,0xa4,88987}, ++ {0x01,0xa6,90124}, ++ {0x01,0xa8,91247}, ++ {0x01,0xaa,92357}, ++ {0x01,0xac,93489}, ++ {0x01,0xae,94573}, ++ {0x01,0xb0,95645}, ++ {0x01,0xb2,96705}, ++ {0x01,0xb4,97787}, ++ {0x01,0xb6,98823}, ++ {0x01,0xb8,99848}, ++ {0x01,0xba,100862}, ++ {0x01,0xbc,101898}, ++ {0x01,0xbe,102890}, ++ {0x01,0xc0,103872}, ++ {0x01,0xc2,104844}, ++ {0x01,0xc4,105837}, ++ {0x01,0xc6,106789}, ++ {0x01,0xc8,107732}, ++ {0x01,0xca,108665}, ++ {0x01,0xcc,109619}, ++ {0x01,0xce,110534}, ++ {0x01,0xd0,111440}, ++ {0x01,0xd2,112338}, ++ {0x01,0xd4,113255}, ++ {0x01,0xd6,114136}, ++ {0x01,0xd8,115008}, ++ {0x40,0x80,115455}, ++ {0x40,0x82,116323}, ++ {0x40,0x84,117182}, ++ {0x40,0x86,118034}, ++ {0x40,0x88,118878}, ++ {0x40,0x8a,119715}, ++ {0x40,0x8c,120544}, ++ {0x40,0x8e,121366}, ++ {0x40,0x90,122181}, ++ {0x40,0x92,122989}, ++ {0x40,0x94,123790}, ++ {0x40,0x96,124585}, ++ {0x40,0x98,125373}, ++ {0x40,0x9a,126154}, ++ {0x40,0x9c,126929}, ++ {0x40,0x9e,127697}, ++ {0x40,0xa0,128460}, ++ {0x40,0xa2,129216}, ++ {0x40,0xa4,129966}, ++ {0x40,0xa6,130711}, ++ {0x40,0xa8,131449}, ++ {0x40,0xaa,132910}, ++ {0x40,0xac,134347}, ++ {0x40,0xae,135764}, ++ {0x40,0xb0,137159}, ++ {0x40,0xb2,138534}, ++ {0x40,0xb4,139890}, ++ {0x40,0xb6,141226}, ++ {0x40,0xb8,142544}, ++ {0x40,0xba,143843}, ++ {0x40,0xbc,145125}, ++ {0x40,0xbe,146390}, ++ {0x40,0xc0,147638}, ++ {0x40,0xc2,148870}, ++ {0x40,0xc4,150086}, ++ {0x40,0xc6,151286}, ++ {0x40,0xc8,152472}, ++ {0x40,0xca,153643}, ++ {0x40,0xcc,154799}, ++ {0x40,0xce,155942}, ++ {0x40,0xd0,157071}, ++ {0x40,0xd2,158186}, ++ {0x40,0xd4,159289}, ++ {0x40,0xd6,160379}, ++ {0x40,0xd8,161456}, ++ {0x40,0xda,162521}, ++ {0x40,0xdc,163575}, ++ {0x40,0xdf,164616}, ++ {0x40,0xe0,165647}, ++ {0x40,0xe2,166666}, ++ {0x40,0xe4,167675}, ++ {0x40,0xe6,168672}, ++ {0x40,0xe8,169660}, ++ {0x40,0xea,170637}, ++ {0x40,0xec,171604}, ++ {0x40,0xee,172562}, ++ {0x40,0xf0,173509}, ++ {0x40,0xf2,174448}, ++ {0x40,0xf4,175377}, ++ {0x40,0xf6,176297}, ++ {0x40,0xf8,177208}, ++ {0x40,0xfa,178111}, ++ {0x40,0xfc,179005}, ++ {0x40,0xfe,179891}, ++ {0x48,0x80,180991}, ++ {0x48,0x82,181859}, ++ {0x48,0x84,182718}, ++ {0x48,0x86,183570}, ++ {0x48,0x88,184414}, ++ {0x48,0x8a,185251}, ++ {0x48,0x8c,186080}, ++ {0x48,0x8e,186902}, ++ {0x48,0x90,187717}, ++ {0x48,0x92,188525}, ++ {0x48,0x94,189326}, ++ {0x48,0x96,190121}, ++ {0x48,0x98,190909}, ++ {0x48,0x9a,191690}, ++ {0x48,0x9c,192465}, ++ {0x48,0x9e,193233}, ++ {0x48,0xa0,193996}, ++ {0x48,0xa2,194752}, ++ {0x48,0xa4,195502}, ++ {0x48,0xa6,196247}, ++ {0x48,0xa8,197718}, ++ {0x48,0xaa,199167}, ++ {0x48,0xac,200594}, ++ {0x48,0xae,202000}, ++ {0x48,0xb0,203385}, ++ {0x48,0xb2,204751}, ++ {0x48,0xb4,206096}, ++ {0x48,0xb6,207423}, ++ {0x48,0xb8,208732}, ++ {0x48,0xba,210022}, ++ {0x48,0xbc,211296}, ++ {0x48,0xbe,212552}, ++ {0x48,0xc0,213792}, ++ {0x48,0xc2,215016}, ++ {0x48,0xc4,216224}, ++ {0x48,0xc6,217417}, ++ {0x48,0xc8,218595}, ++ {0x48,0xca,219759}, ++ {0x48,0xcc,220908}, ++ {0x48,0xce,222044}, ++ {0x48,0xd0,223166}, ++ {0x48,0xd2,224275}, ++ {0x48,0xd4,225371}, ++ {0x48,0xd6,226455}, ++ {0x48,0xd8,227526}, ++ {0x48,0xda,228585}, ++ {0x48,0xdc,229633}, ++ {0x48,0xdf,230669}, ++ {0x48,0xe0,231694}, ++ {0x48,0xe2,232708}, ++ {0x48,0xe4,233711}, ++ {0x48,0xe6,234703}, ++ {0x48,0xe8,235686}, ++ {0x48,0xea,236658}, ++ {0x48,0xec,237620}, ++ {0x48,0xee,238573}, ++ {0x48,0xf0,239516}, ++ {0x48,0xf2,240450}, ++ {0x48,0xf4,241374}, ++ {0x48,0xf6,242290}, ++ {0x48,0xf8,243197}, ++ {0x48,0xfa,244095}, ++ {0x48,0xfc,244985}, ++ {0x48,0xfe,245866}, ++ {0x49,0x80,246527}, ++ {0x49,0x82,247395}, ++ {0x49,0x84,248254}, ++ {0x49,0x86,249106}, ++ {0x49,0x88,249950}, ++ {0x49,0x8a,250787}, ++ {0x49,0x8c,251616}, ++ {0x49,0x8e,252438}, ++ {0x49,0x90,253253}, ++ {0x49,0x92,254061}, ++ {0x49,0x94,254862}, ++ {0x49,0x96,255657}, ++ {0x49,0x98,256445}, ++ {0x49,0x9a,257226}, ++ {0x49,0x9c,258001}, ++ {0x49,0x9e,258769}, ++ {0x49,0xa0,259532}, ++ {0x49,0xa2,260288}, ++ {0x49,0xa4,261038}, ++ {0x49,0xa6,261783}, ++ {0x49,0xa8,263254}, ++ {0x49,0xaa,264703}, ++ {0x49,0xac,266130}, ++ {0x49,0xae,267536}, ++ {0x49,0xb0,268921}, ++ {0x49,0xb2,270287}, ++ {0x49,0xb4,271632}, ++ {0x49,0xb6,272959}, ++ {0x49,0xb8,274268}, ++ {0x49,0xba,275558}, ++ {0x49,0xbc,276832}, ++ {0x49,0xbe,278088}, ++ {0x49,0xc0,279328}, ++ {0x49,0xc2,280552}, ++ {0x49,0xc4,281760}, ++ {0x49,0xc6,282953}, ++ {0x49,0xc8,284131}, ++ {0x49,0xca,285295}, ++ {0x49,0xcc,286444}, ++ {0x49,0xce,287580}, ++ {0x49,0xd0,288702}, ++ {0x49,0xd2,289811}, ++ {0x49,0xd4,290907}, ++ {0x49,0xd6,291991}, ++ {0x49,0xd8,293062}, ++ {0x49,0xda,294121}, ++ {0x49,0xdc,295169}, ++ {0x49,0xdf,296205}, ++ {0x49,0xe0,297230}, ++ {0x49,0xe2,298244}, ++ {0x49,0xe4,299247}, ++ {0x49,0xe6,300239}, ++ {0x49,0xe8,301222}, ++ {0x49,0xea,302194}, ++ {0x49,0xec,303156}, ++ {0x49,0xee,304109}, ++ {0x49,0xf0,305052}, ++ {0x49,0xf2,305986}, ++ {0x49,0xf4,306910}, ++ {0x49,0xf6,307826}, ++ {0x49,0xf8,308733}, ++ {0x49,0xfa,309631}, ++ {0x49,0xfc,310521}, ++ {0x49,0xfe,311402}, ++ {0x4b,0x80,312063}, ++ {0x4b,0x82,312931}, ++ {0x4b,0x84,313790}, ++ {0x4b,0x86,314642}, ++ {0x4b,0x88,315486}, ++ {0x4b,0x8a,316323}, ++ {0x4b,0x8c,317152}, ++ {0x4b,0x8e,317974}, ++ {0x4b,0x90,318789}, ++ {0x4b,0x92,319597}, ++ {0x4b,0x94,320398}, ++ {0x4b,0x96,321193}, ++ {0x4b,0x98,321981}, ++ {0x4b,0x9a,322762}, ++ {0x4b,0x9c,323537}, ++ {0x4b,0x9e,324305}, ++ {0x4b,0xa0,325068}, ++ {0x4b,0xa2,325824}, ++ {0x4b,0xa4,326574}, ++ {0x4b,0xa6,327319}, ++ {0x4b,0xa8,328057}, ++ {0x4b,0xaa,329518}, ++ {0x4b,0xac,330955}, ++ {0x4b,0xae,332372}, ++ {0x4b,0xb0,333767}, ++ {0x4b,0xb2,335142}, ++ {0x4b,0xb4,336498}, ++ {0x4b,0xb6,337834}, ++ {0x4b,0xb8,339152}, ++ {0x4b,0xba,340451}, ++ {0x4b,0xbc,341733}, ++ {0x4b,0xbe,342998}, ++ {0x4b,0xc0,344246}, ++ {0x4b,0xc2,345478}, ++ {0x4b,0xc4,346694}, ++ {0x4b,0xc6,347894}, ++ {0x4b,0xc8,349080}, ++ {0x4b,0xca,350251}, ++ {0x4b,0xcc,351407}, ++ {0x4b,0xce,352550}, ++ {0x4b,0xd0,353679}, ++ {0x4b,0xd2,354794}, ++ {0x4b,0xd4,355897}, ++ {0x4b,0xd6,356987}, ++ {0x4b,0xd8,358064}, ++ {0x4b,0xda,359129}, ++ {0x4b,0xdc,360183}, ++ {0x4b,0xdf,361224}, ++ {0x4b,0xe0,362255}, ++ {0x4b,0xe2,363274}, ++ {0x4b,0xe4,364283}, ++ {0x4b,0xe6,365280}, ++ {0x4b,0xe8,366268}, ++ {0x4b,0xea,367245}, ++ {0x4b,0xec,368212}, ++ {0x4b,0xee,369170}, ++ {0x4b,0xf0,370117}, ++ {0x4b,0xf2,371056}, ++ {0x4b,0xf4,371985}, ++ {0x4b,0xf6,372905}, ++ {0x4b,0xf8,373816}, ++ {0x4b,0xfa,374719}, ++ {0x4b,0xfc,375613}, ++ {0x4b,0xfe,376499}, ++ {0x4f,0x80,377599}, ++ {0x4f,0x82,378467}, ++ {0x4f,0x84,379326}, ++ {0x4f,0x86,380178}, ++ {0x4f,0x88,381022}, ++ {0x4f,0x8a,381859}, ++ {0x4f,0x8c,382688}, ++ {0x4f,0x8e,383510}, ++ {0x4f,0x90,384325}, ++ {0x4f,0x92,385133}, ++ {0x4f,0x94,385934}, ++ {0x4f,0x96,386729}, ++ {0x4f,0x98,387517}, ++ {0x4f,0x9a,388298}, ++ {0x4f,0x9c,389073}, ++ {0x4f,0x9e,389841}, ++ {0x4f,0xa0,390604}, ++ {0x4f,0xa2,391360}, ++ {0x4f,0xa4,392110}, ++ {0x4f,0xa6,392855}, ++ {0x4f,0xa8,393593}, ++ {0x4f,0xaa,395054}, ++ {0x4f,0xac,396491}, ++ {0x4f,0xae,397908}, ++ {0x4f,0xb0,399303}, ++ {0x4f,0xb2,400678}, ++ {0x4f,0xb4,402034}, ++ {0x4f,0xb6,403370}, ++ {0x4f,0xb8,404688}, ++ {0x4f,0xba,405987}, ++ {0x4f,0xbc,407269}, ++ {0x4f,0xbe,408534}, ++ {0x4f,0xc0,409782}, ++ {0x4f,0xc2,411014}, ++ {0x4f,0xc4,412230}, ++ {0x4f,0xc6,413430}, ++ {0x4f,0xc8,414616}, ++ {0x4f,0xca,415787}, ++ {0x4f,0xcc,416943}, ++ {0x4f,0xce,418086}, ++ {0x4f,0xd0,419215}, ++ {0x4f,0xd2,420330}, ++ {0x4f,0xd4,421433}, ++ {0x4f,0xd6,422523}, ++ {0x4f,0xd8,423600}, ++ {0x4f,0xda,424665}, ++ {0x4f,0xdc,425719}, ++ {0x4f,0xdf,426760}, ++ {0x4f,0xe0,427791}, ++ {0x4f,0xe2,428810}, ++ {0x4f,0xe4,429819}, ++ {0x4f,0xe6,430816}, ++ {0x4f,0xe8,431804}, ++ {0x4f,0xea,432781}, ++ {0x4f,0xec,433748}, ++ {0x4f,0xee,434706}, ++ {0x4f,0xf0,435653}, ++ {0x4f,0xf2,436592}, ++ {0x4f,0xf4,437521}, ++ {0x4f,0xf6,438441}, ++ {0x4f,0xf8,439352}, ++ {0x4f,0xfa,440255}, ++ {0x4f,0xfc,441149}, ++ {0x4f,0xfe,442035}, ++ {0x5f,0x80,443135}, ++}; ++ ++static inline struct sc230ai_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct sc230ai_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct sc230ai_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list sc230ai_init_regs_1920_1080_30fps_MIPI[] = { ++ {0x0103,0x01}, ++ {0x0100,0x00}, ++ {0x36e9,0x80}, ++ {0x37f9,0x80}, ++ {0x301f,0x01}, ++ {0x3221,0x06}, ++ {0x3301,0x07}, ++ {0x3304,0x50}, ++ {0x3306,0x70}, ++ {0x3308,0x18}, ++ {0x3309,0x68}, ++ {0x330a,0x01}, ++ {0x330b,0x20}, ++ {0x331e,0x41}, ++ {0x331f,0x59}, ++ {0x3333,0x10}, ++ {0x3334,0x40}, ++ {0x335d,0x60}, ++ {0x335e,0x06}, ++ {0x335f,0x08}, ++ {0x3364,0x5e}, ++ {0x337c,0x02}, ++ {0x337d,0x0a}, ++ {0x3390,0x01}, ++ {0x3391,0x0b}, ++ {0x3392,0x0f}, ++ {0x3393,0x09}, ++ {0x3394,0x0d}, ++ {0x3395,0x60}, ++ {0x3396,0x48}, ++ {0x3397,0x49}, ++ {0x3398,0x4b}, ++ {0x3399,0x06}, ++ {0x339a,0x0a}, ++ {0x339b,0x0d}, ++ {0x339c,0x60}, ++ {0x33a2,0x04}, ++ {0x33af,0x40}, ++ {0x33b1,0x80}, ++ {0x33b3,0x40}, ++ {0x33b9,0x0a}, ++ {0x33f9,0xa0}, ++ {0x33fb,0xbf}, ++ {0x33fc,0x5f}, ++ {0x33fd,0x7f}, ++ {0x349f,0x03}, ++ {0x34a6,0x4b}, ++ {0x34a7,0x5f}, ++ {0x34a8,0x30}, ++ {0x34a9,0x20}, ++ {0x34aa,0x01}, ++ {0x34ab,0x28}, ++ {0x34ac,0x01}, ++ {0x34ad,0x58}, ++ {0x34f8,0x7f}, ++ {0x34f9,0x10}, ++ {0x3630,0xc0}, ++ {0x3633,0x44}, ++ {0x363b,0x20}, ++ {0x3670,0x09}, ++ {0x3674,0xb0}, ++ {0x3675,0x80}, ++ {0x3676,0x88}, ++ {0x367c,0x40}, ++ {0x367d,0x49}, ++ {0x3690,0x44}, ++ {0x3691,0x33}, ++ {0x3692,0x43}, ++ {0x369c,0x49}, ++ {0x369d,0x4f}, ++ {0x36ae,0x4b}, ++ {0x36af,0x4f}, ++ {0x36b0,0x87}, ++ {0x36b1,0x94}, ++ {0x36b2,0xbc}, ++ {0x36d0,0x01}, ++ {0x3722,0x97}, ++ {0x3728,0x90}, ++ {0x3901,0x02}, ++ {0x3902,0xc5}, ++ {0x3904,0x04}, ++ {0x3907,0x00}, ++ {0x3908,0x41}, ++ {0x3909,0x00}, ++ {0x390a,0x00}, ++ {0x3933,0x84}, ++ {0x3934,0x10}, ++ {0x3940,0x78}, ++ {0x3942,0x04}, ++ {0x3943,0x11}, ++ {0x3e00,0x00}, ++ {0x3e01,0x8c}, ++ {0x3e02,0x20}, ++ {0x440e,0x02}, ++ {0x5010,0x01}, ++ {0x5787,0x08}, ++ {0x5788,0x03}, ++ {0x5789,0x00}, ++ {0x578a,0x10}, ++ {0x578b,0x08}, ++ {0x578c,0x00}, ++ {0x5790,0x08}, ++ {0x5791,0x04}, ++ {0x5792,0x00}, ++ {0x5793,0x10}, ++ {0x5794,0x08}, ++ {0x5795,0x00}, ++ {0x5799,0x06}, ++ {0x57ad,0x00}, ++ {0x5ae0,0xfe}, ++ {0x5ae1,0x40}, ++ {0x5ae2,0x3f}, ++ {0x5ae3,0x38}, ++ {0x5ae4,0x28}, ++ {0x5ae5,0x3f}, ++ {0x5ae6,0x38}, ++ {0x5ae7,0x28}, ++ {0x5ae8,0x3f}, ++ {0x5ae9,0x3c}, ++ {0x5aea,0x2c}, ++ {0x5aeb,0x3f}, ++ {0x5aec,0x3c}, ++ {0x5aed,0x2c}, ++ {0x5af4,0x3f}, ++ {0x5af5,0x38}, ++ {0x5af6,0x28}, ++ {0x5af7,0x3f}, ++ {0x5af8,0x38}, ++ {0x5af9,0x28}, ++ {0x5afa,0x3f}, ++ {0x5afb,0x3c}, ++ {0x5afc,0x2c}, ++ {0x5afd,0x3f}, ++ {0x5afe,0x3c}, ++ {0x5aff,0x2c}, ++ {0x36e9,0x20}, ++ {0x37f9,0x27}, ++ {SC230AI_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc230ai_init_regs_1920_1080_30fps_wdr_MIPI[] = { ++ {0x0103,0x01}, ++ {0x0100,0x00}, ++ {0x36e9,0x80}, ++ {0x37f9,0x80}, ++ {0x301f,0x06}, ++ {0x320e,0x08}, ++ {0x320f,0xca}, ++ {0x3221,0x06}, ++ {0x3250,0xff}, ++ {0x3281,0x01}, ++ {0x3301,0x09}, ++ {0x3304,0x50}, ++ {0x3306,0x48}, ++ {0x3308,0x18}, ++ {0x3309,0x68}, ++ {0x330a,0x00}, ++ {0x330b,0xc0}, ++ {0x331e,0x41}, ++ {0x331f,0x59}, ++ {0x3333,0x10}, ++ {0x3334,0x40}, ++ {0x335d,0x60}, ++ {0x335e,0x06}, ++ {0x335f,0x08}, ++ {0x3364,0x5e}, ++ {0x337c,0x02}, ++ {0x337d,0x0a}, ++ {0x3390,0x01}, ++ {0x3391,0x0b}, ++ {0x3392,0x0f}, ++ {0x3393,0x0c}, ++ {0x3394,0x0d}, ++ {0x3395,0x60}, ++ {0x3396,0x48}, ++ {0x3397,0x49}, ++ {0x3398,0x4f}, ++ {0x3399,0x0a}, ++ {0x339a,0x0f}, ++ {0x339b,0x14}, ++ {0x339c,0x60}, ++ {0x33a2,0x04}, ++ {0x33af,0x40}, ++ {0x33b1,0x80}, ++ {0x33b3,0x40}, ++ {0x33b9,0x0a}, ++ {0x33f9,0x70}, ++ {0x33fb,0x90}, ++ {0x33fc,0x4b}, ++ {0x33fd,0x5f}, ++ {0x349f,0x03}, ++ {0x34a6,0x4b}, ++ {0x34a7,0x4f}, ++ {0x34a8,0x30}, ++ {0x34a9,0x20}, ++ {0x34aa,0x00}, ++ {0x34ab,0xe0}, ++ {0x34ac,0x01}, ++ {0x34ad,0x00}, ++ {0x34f8,0x5f}, ++ {0x34f9,0x10}, ++ {0x3630,0xc0}, ++ {0x3633,0x44}, ++ {0x3637,0x29}, ++ {0x363b,0x20}, ++ {0x3670,0x09}, ++ {0x3674,0xb0}, ++ {0x3675,0x80}, ++ {0x3676,0x88}, ++ {0x367c,0x40}, ++ {0x367d,0x49}, ++ {0x3690,0x44}, ++ {0x3691,0x44}, ++ {0x3692,0x54}, ++ {0x369c,0x49}, ++ {0x369d,0x4f}, ++ {0x36ae,0x4b}, ++ {0x36af,0x4f}, ++ {0x36b0,0x87}, ++ {0x36b1,0x94}, ++ {0x36b2,0xbc}, ++ {0x36d0,0x01}, ++ {0x36ea,0x0b}, ++ {0x36eb,0x04}, ++ {0x36ec,0x0c}, ++ {0x36ed,0x24}, ++ {0x370f,0x01}, ++ {0x3722,0x17}, ++ {0x3728,0x90}, ++ {0x37b0,0x17}, ++ {0x37b1,0x17}, ++ {0x37b2,0x97}, ++ {0x37b3,0x4b}, ++ {0x37b4,0x4f}, ++ {0x37fa,0x0b}, ++ {0x37fb,0x24}, ++ {0x37fc,0x10}, ++ {0x37fd,0x22}, ++ {0x3901,0x02}, ++ {0x3902,0xc5}, ++ {0x3904,0x04}, ++ {0x3907,0x00}, ++ {0x3908,0x41}, ++ {0x3909,0x00}, ++ {0x390a,0x00}, ++ {0x391f,0x04}, ++ {0x3933,0x84}, ++ {0x3934,0x10}, ++ {0x3940,0x78}, ++ {0x3942,0x04}, ++ {0x3943,0x11}, ++ {0x3e00,0x01}, ++ {0x3e01,0x06}, ++ {0x3e02,0x00}, ++// {0x3e22,0x00}, //short exp ++ {0x3e04,0x10}, //short exp ++ {0x3e05,0x60}, //short exp ++ {0x3e06,0x00}, ++ {0x3e07,0x80}, ++ {0x3e08,0x03}, ++ {0x3e09,0x40}, ++ {0x3e10,0x00}, ++ {0x3e11,0x80}, ++ {0x3e12,0x03}, ++ {0x3e13,0x40}, ++ {0x3e23,0x00}, ++ {0x3e24,0x88}, ++ {0x440e,0x02}, ++ {0x4816,0x71}, //vc ++ {0x5010,0x00}, ++ {0x5787,0x08}, ++ {0x5788,0x03}, ++ {0x5789,0x00}, ++ {0x578a,0x10}, ++ {0x578b,0x08}, ++ {0x578c,0x00}, ++ {0x5790,0x08}, ++ {0x5791,0x04}, ++ {0x5792,0x00}, ++ {0x5793,0x10}, ++ {0x5794,0x08}, ++ {0x5795,0x00}, ++ {0x5799,0x06}, ++ {0x57ad,0x00}, ++ {0x5ae0,0xfe}, ++ {0x5ae1,0x40}, ++ {0x5ae2,0x3f}, ++ {0x5ae3,0x38}, ++ {0x5ae4,0x28}, ++ {0x5ae5,0x3f}, ++ {0x5ae6,0x38}, ++ {0x5ae7,0x28}, ++ {0x5ae8,0x3f}, ++ {0x5ae9,0x3c}, ++ {0x5aea,0x2c}, ++ {0x5aeb,0x3f}, ++ {0x5aec,0x3c}, ++ {0x5aed,0x2c}, ++ {0x5af4,0x3f}, ++ {0x5af5,0x38}, ++ {0x5af6,0x28}, ++ {0x5af7,0x3f}, ++ {0x5af8,0x38}, ++ {0x5af9,0x28}, ++ {0x5afa,0x3f}, ++ {0x5afb,0x3c}, ++ {0x5afc,0x2c}, ++ {0x5afd,0x3f}, ++ {0x5afe,0x3c}, ++ {0x5aff,0x2c}, ++ {0x36e9,0x20}, ++ {0x37f9,0x24}, ++ {SC230AI_REG_END, 0x00}, ++}; ++ ++ ++static struct regval_list sc230ai_init_regs_1920_1080_60fps_MIPI[] = { ++ {0x0103,0x01}, ++ {0x0100,0x00}, ++ {0x36e9,0x80}, ++ {0x37f9,0x80}, ++ {0x301f,0x02}, ++ {0x3221,0x06}, ++ {0x3301,0x09}, ++ {0x3304,0x50}, ++ {0x3306,0x48}, ++ {0x3308,0x18}, ++ {0x3309,0x68}, ++ {0x330a,0x00}, ++ {0x330b,0xc0}, ++ {0x331e,0x41}, ++ {0x331f,0x59}, ++ {0x3333,0x10}, ++ {0x3334,0x40}, ++ {0x335d,0x60}, ++ {0x335e,0x06}, ++ {0x335f,0x08}, ++ {0x3364,0x5e}, ++ {0x337c,0x02}, ++ {0x337d,0x0a}, ++ {0x3390,0x01}, ++ {0x3391,0x0b}, ++ {0x3392,0x0f}, ++ {0x3393,0x0c}, ++ {0x3394,0x0d}, ++ {0x3395,0x60}, ++ {0x3396,0x48}, ++ {0x3397,0x49}, ++ {0x3398,0x4f}, ++ {0x3399,0x0a}, ++ {0x339a,0x0f}, ++ {0x339b,0x14}, ++ {0x339c,0x60}, ++ {0x33a2,0x04}, ++ {0x33af,0x40}, ++ {0x33b1,0x80}, ++ {0x33b3,0x40}, ++ {0x33b9,0x0a}, ++ {0x33f9,0x70}, ++ {0x33fb,0x90}, ++ {0x33fc,0x4b}, ++ {0x33fd,0x5f}, ++ {0x349f,0x03}, ++ {0x34a6,0x4b}, ++ {0x34a7,0x4f}, ++ {0x34a8,0x30}, ++ {0x34a9,0x20}, ++ {0x34aa,0x00}, ++ {0x34ab,0xe0}, ++ {0x34ac,0x01}, ++ {0x34ad,0x00}, ++ {0x34f8,0x5f}, ++ {0x34f9,0x10}, ++ {0x3630,0xc0}, ++ {0x3633,0x44}, ++ {0x3637,0x29}, ++ {0x363b,0x20}, ++ {0x3670,0x09}, ++ {0x3674,0xb0}, ++ {0x3675,0x80}, ++ {0x3676,0x88}, ++ {0x367c,0x40}, ++ {0x367d,0x49}, ++ {0x3690,0x44}, ++ {0x3691,0x44}, ++ {0x3692,0x54}, ++ {0x369c,0x49}, ++ {0x369d,0x4f}, ++ {0x36ae,0x4b}, ++ {0x36af,0x4f}, ++ {0x36b0,0x87}, ++ {0x36b1,0x94}, ++ {0x36b2,0xbc}, ++ {0x36d0,0x01}, ++ {0x36ea,0x0b}, ++ {0x36eb,0x04}, ++ {0x36ec,0x0c}, ++ {0x36ed,0x24}, ++ {0x370f,0x01}, ++ {0x3722,0x17}, ++ {0x3728,0x90}, ++ {0x37b0,0x17}, ++ {0x37b1,0x17}, ++ {0x37b2,0x97}, ++ {0x37b3,0x4b}, ++ {0x37b4,0x4f}, ++ {0x37fa,0x0b}, ++ {0x37fb,0x24}, ++ {0x37fc,0x10}, ++ {0x37fd,0x22}, ++ {0x3901,0x02}, ++ {0x3902,0xc5}, ++ {0x3904,0x04}, ++ {0x3907,0x00}, ++ {0x3908,0x41}, ++ {0x3909,0x00}, ++ {0x390a,0x00}, ++ {0x391f,0x04}, ++ {0x3933,0x84}, ++ {0x3934,0x10}, ++ {0x3940,0x78}, ++ {0x3942,0x04}, ++ {0x3943,0x11}, ++ {0x3e00,0x00}, ++ {0x3e01,0x8c}, ++ {0x3e02,0x20}, ++ {0x440e,0x02}, ++ {0x5010,0x01}, ++ {0x5787,0x08}, ++ {0x5788,0x03}, ++ {0x5789,0x00}, ++ {0x578a,0x10}, ++ {0x578b,0x08}, ++ {0x578c,0x00}, ++ {0x5790,0x08}, ++ {0x5791,0x04}, ++ {0x5792,0x00}, ++ {0x5793,0x10}, ++ {0x5794,0x08}, ++ {0x5795,0x00}, ++ {0x5799,0x06}, ++ {0x57ad,0x00}, ++ {0x5ae0,0xfe}, ++ {0x5ae1,0x40}, ++ {0x5ae2,0x3f}, ++ {0x5ae3,0x38}, ++ {0x5ae4,0x28}, ++ {0x5ae5,0x3f}, ++ {0x5ae6,0x38}, ++ {0x5ae7,0x28}, ++ {0x5ae8,0x3f}, ++ {0x5ae9,0x3c}, ++ {0x5aea,0x2c}, ++ {0x5aeb,0x3f}, ++ {0x5aec,0x3c}, ++ {0x5aed,0x2c}, ++ {0x5af4,0x3f}, ++ {0x5af5,0x38}, ++ {0x5af6,0x28}, ++ {0x5af7,0x3f}, ++ {0x5af8,0x38}, ++ {0x5af9,0x28}, ++ {0x5afa,0x3f}, ++ {0x5afb,0x3c}, ++ {0x5afc,0x2c}, ++ {0x5afd,0x3f}, ++ {0x5afe,0x3c}, ++ {0x5aff,0x2c}, ++ {0x36e9,0x20}, ++ {0x37f9,0x24}, ++ {SC230AI_REG_END, 0x00}, ++}; ++ ++ ++static struct regval_list sc230ai_stream_on[] = { ++ {0x0100,0x01}, ++ {SC230AI_REG_END, 0x00}, ++}; ++ ++static struct regval_list sc230ai_stream_off[] = { ++ {0x0100,0x00}, ++ {SC230AI_REG_END, 0x00}, ++}; ++ ++ ++int sc230ai_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int sc230ai_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ unsigned int timeout = 100; ++ while(timeout--){ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == -EAGAIN){ ++ msleep(100); ++ continue; ++ } ++ else ++ break; ++ } ++ if (ret > 0) ++ ret = 0; ++ return ret; ++} ++ ++static int sc230ai_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != SC230AI_REG_END) { ++ if (vals->reg_num == SC230AI_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc230ai_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ if (vals->reg_num == SC230AI_PAGE_REG){ ++ val &= 0xf8; ++ val |= (vals->value & 0x07); ++ ret = sc230ai_write(sd, vals->reg_num, val); ++ ret = sc230ai_read(sd, vals->reg_num, &val); ++ } ++ } ++ vals++; ++ } ++ return 0; ++} ++static int sc230ai_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != SC230AI_REG_END) { ++ if (vals->reg_num == SC230AI_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc230ai_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int sc230ai_lightup(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->led.pin, info->led.active_level); ++ } else { ++ gpio_direction_output(info->led.pin, !info->led.active_level); ++ } ++ return 0; ++} ++ ++static int sc230ai_xshutdn(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->xshutdn.pin, info->xshutdn.active_level); ++ } else { ++ gpio_direction_output(info->xshutdn.pin, !info->xshutdn.active_level); ++ } ++ return 0; ++} ++ ++static int sc230ai_pwdn(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->pwdn.pin, info->pwdn.active_level); ++ msleep(10); ++ } else { ++ gpio_direction_output(info->pwdn.pin, !info->pwdn.active_level); ++ } ++ return 0; ++} ++ ++static int sc230ai_hw_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->xshutdn.pin, !info->xshutdn.active_level); ++ gpio_direction_output(info->xshutdn.pin, info->xshutdn.active_level); ++ } ++ return 0; ++} ++ ++static int sc230ai_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ ret = sc230ai_read(sd, 0x3107, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC230AI_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = sc230ai_read(sd, 0x3108, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC230AI_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ return 0; ++ ++} ++ ++static struct sc230ai_win_size sc230ai_win_sizes[] = { ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 30 << 16 | 1, ++ .sensor_info.total_width = 1928, ++ .sensor_info.total_height = 1152, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 600, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW10, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc230ai_init_regs_1920_1080_30fps_MIPI, ++ }, ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 60 << 16 | 1, ++ .sensor_info.total_width = 1928, ++ .sensor_info.total_height = 1152, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 600, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW10, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc230ai_init_regs_1920_1080_60fps_MIPI, ++ }, ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 30 << 16 | 1, ++ .sensor_info.total_width = 1928, ++ .sensor_info.total_height = 2250, ++ .sensor_info.wdr_en = 1, ++ .sensor_info.mipi_cfg.clk = 600, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW10, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_WDR_2_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_VC_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW10, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc230ai_init_regs_1920_1080_30fps_wdr_MIPI, ++ }, ++}; ++ ++#if 0 ++static int sc230ai_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= N_OV2735a_FMTS) ++ return -EINVAL; ++ ++ code->code = sc230ai_formats[code->index].mbus_code; ++ return 0; ++} ++#endif ++ ++/* ++ * Set a format. ++ */ ++static int sc230ai_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ ++ if (format->pad) ++ { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int sc230ai_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ struct sc230ai_win_size *wsize = info->win; ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = wsize->width; ++ fmt->height = wsize->height; ++ fmt->code = wsize->mbus_code; ++ fmt->colorspace = wsize->colorspace; ++ *(unsigned int *)fmt->reserved = (unsigned int)&wsize->sensor_info; /*reserved[0] reserved[1]*/ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int sc230ai_s_wdr(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ struct sc230ai_info *info = to_state(sd); ++// printk("%s:%d\n", __func__, value); ++ if(value) ++ info->win = &sc230ai_win_sizes[2]; ++ else ++ info->win = &sc230ai_win_sizes[0]; ++ return ret; ++} ++ ++static int sc230ai_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc230ai_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc230ai_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc230ai_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int sc230ai_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int sc230ai_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++// printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain, unsigned int *value, unsigned int *fine_value) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc230ai_again_lut); i++) { ++ lut = &sc230ai_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ *value = lut->value; ++ *fine_value = lut->fine_value; ++ return lut->value; ++ } ++ } ++ /*last value.*/ ++ *value = lut->value; ++ *fine_value = lut->fine_value; ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval, unsigned int fine_reg_val) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc230ai_again_lut); i++) { ++ lut = &sc230ai_again_lut[i]; ++ ++ if(regval == lut->value && fine_reg_val == lut->fine_value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++ ++static int sc230ai_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ char v = 0; ++ unsigned int reg_val = 0; ++ unsigned int fine_reg_val = 0; ++ int ret = 0; ++ ++ ++ ret = sc230ai_read(sd, 0x3e09, &v); ++ reg_val = v ; ++ ret = sc230ai_read(sd, 0x3e07, &v); ++ fine_reg_val = v ; ++ ++ *value = regval_to_again(reg_val, fine_reg_val); ++ ++ return ret; ++ ++} ++ ++static int sc230ai_g_again_short(struct v4l2_subdev *sd, __s32 *value) ++{ ++ char v = 0; ++ unsigned int reg_val = 0; ++ unsigned int fine_reg_val = 0; ++ int ret = 0; ++ ++ ++ ret = sc230ai_read(sd, 0x3e13, &v); ++ reg_val = v ; ++ ret = sc230ai_read(sd, 0x3e11, &v); ++ fine_reg_val = v ; ++ ++ *value = regval_to_again(reg_val, fine_reg_val); ++ ++ return ret; ++ ++} ++ ++/*set analog gain db value, map value to sensor register.*/ ++static int sc230ai_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ unsigned int reg_value; ++ unsigned int reg_fine_value; ++ int ret = 0; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ again_to_regval(info->again->default_value, ®_value, ®_fine_value); ++ } else { ++ again_to_regval(value, ®_value, ®_fine_value); ++ } ++ ++ ret += sc230ai_write(sd, 0x3e09, (unsigned char)(reg_value)); ++ ret += sc230ai_write(sd, 0x3e07, (unsigned char)(reg_fine_value)); ++ if (ret < 0){ ++ printk("sc230ai_write error %d\n" ,__LINE__ ); ++ return ret; ++ } ++ return 0; ++} ++ ++static int sc230ai_s_again_short(struct v4l2_subdev *sd, int value) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ unsigned int reg_value; ++ unsigned int reg_fine_value; ++ int ret = 0; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ again_to_regval(info->again->default_value, ®_value, ®_fine_value); ++ } else { ++ again_to_regval(value, ®_value, ®_fine_value); ++ } ++ ++ ret += sc230ai_write(sd, 0x3e13, (unsigned char)(reg_value)); ++ ret += sc230ai_write(sd, 0x3e11, (unsigned char)(reg_fine_value)); ++ if (ret < 0){ ++ printk("sc230ai_write error %d\n" ,__LINE__ ); ++ return ret; ++ } ++ return 0; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int sc230ai_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc230ai_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ value *= 2; /*unit in half line*/ ++ ret += sc230ai_write(sd, 0x3e00, (unsigned char)((value >> 12) & 0xf)); ++ ret += sc230ai_write(sd, 0x3e01, (unsigned char)((value >> 4) & 0xff)); ++ ret += sc230ai_write(sd, 0x3e02, (unsigned char)(value & 0xf) << 4); ++ ++ if (ret < 0) { ++ printk("sc230ai_write error %d\n" ,__LINE__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int sc230ai_s_exp_short(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ value *= 2; /*unit in half line*/ ++ ret += sc230ai_write(sd, 0x3e22, (unsigned char)((value >> 12) & 0xf)); ++ ret += sc230ai_write(sd, 0x3e04, (unsigned char)((value >> 4) & 0xff)); ++ ret += sc230ai_write(sd, 0x3e05, (unsigned char)(value & 0xf) << 4); ++ ++ if (ret < 0) { ++ printk("sc230ai_write error %d\n" ,__LINE__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++ ++static int sc230ai_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc230ai_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return sc230ai_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc230ai_g_again(sd, &info->again->val); ++ case V4L2_CID_USER_ANALOG_GAIN_SHORT: ++ return sc230ai_g_again_short(sd, &info->again_short->val); ++ } ++ return -EINVAL; ++} ++ ++static int sc230ai_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc230ai_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return sc230ai_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return sc230ai_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return sc230ai_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return sc230ai_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* sc230ai_s_gain turns off auto gain */ ++ return sc230ai_s_gain(sd, info->gain->val); ++ } ++ return sc230ai_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return sc230ai_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc230ai_s_again(sd, ctrl->val); ++ case V4L2_CID_USER_ANALOG_GAIN_SHORT: ++ return sc230ai_s_again_short(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return sc230ai_s_exp(sd, ctrl->val); ++ case V4L2_CID_USER_EXPOSURE_SHORT: ++ return sc230ai_s_exp_short(sd, ctrl->val); ++ case V4L2_CID_WIDE_DYNAMIC_RANGE: ++ return sc230ai_s_wdr(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops sc230ai_ctrl_ops = { ++ .s_ctrl = sc230ai_s_ctrl, ++ .g_volatile_ctrl = sc230ai_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int sc230ai_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = sc230ai_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int sc230ai_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ sc230ai_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++static int sc230ai_core_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ unsigned char v; ++ int ret; ++ ++ /*software reset*/ ++ ret = sc230ai_read(sd, 0x0103, &v); ++ ++ if(val) { ++ v |= 1; ++ ret += sc230ai_write(sd, 0x0103, v); ++ } ++ return 0; ++} ++ ++static int sc230ai_core_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = sc230ai_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++ ++int sc230ai_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ int ret = 0; ++ ++ if (enable) { ++ ret = sc230ai_write_array(sd, sc230ai_stream_on); ++ printk("sc230ai stream on\n"); ++ ++ } ++ else { ++ ret = sc230ai_write_array(sd, sc230ai_stream_off); ++ printk("sc230ai stream off\n"); ++ } ++ return ret; ++} ++ ++ ++int sc230ai_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops sc230ai_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = sc230ai_g_register, ++ .s_register = sc230ai_s_register, ++#endif ++ .init = sc230ai_core_init, ++ .reset = sc230ai_core_reset, ++ ++}; ++ ++static const struct v4l2_subdev_video_ops sc230ai_video_ops = { ++ .s_stream = sc230ai_s_stream, ++ .g_frame_interval = sc230ai_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops sc230ai_pad_ops = { ++ //.enum_frame_interval = sc230ai_enum_frame_interval, ++ //.num_frame_size = sc230ai_enum_frame_size, ++ //.enum_mbus_code = sc230ai_enum_mbus_code, ++ .set_fmt = sc230ai_set_fmt, ++ .get_fmt = sc230ai_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops sc230ai_ops = { ++ .core = &sc230ai_core_ops, ++ .video = &sc230ai_video_ops, ++ .pad = &sc230ai_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int sc230ai_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct sc230ai_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned long rate; ++ struct v4l2_ctrl_config cfg = {0}; ++ int mclk_index = -1; ++ char id_div[9]; ++ char id_mux[9]; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,xshutdn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->xshutdn.pin = gpio; ++ info->xshutdn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwdn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwdn.pin = gpio; ++ info->pwdn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,efsync-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->efsync.pin = gpio; ++ info->efsync.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,led-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->led.pin = gpio; ++ info->led.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ ++ v4l2_i2c_subdev_init(sd, client, &sc230ai_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ of_property_read_u32(client->dev.of_node, "ingenic,mclk", &mclk_index); ++ if(mclk_index == 0) { ++ memcpy(id_div, "div_cim0", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim0", sizeof(id_mux)); ++ } else if(mclk_index == 1) { ++ memcpy(id_div, "div_cim1", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim1", sizeof(id_mux)); ++ } else if(mclk_index == 2) { ++ memcpy(id_div, "div_cim2", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim2", sizeof(id_mux)); ++ } else ++ printk("Unkonwn mclk index\n"); ++ ++ ++ info->clk = v4l2_clk_get(&client->dev, id_div); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ info->sclka = devm_clk_get(&client->dev, id_mux); ++ ++ rate = v4l2_clk_get_rate(info->clk); ++ if (((rate / 1000) % 27000) != 0) { ++ ret = clk_set_parent(info->sclka, clk_get(NULL, "epll")); ++ info->sclka = devm_clk_get(&client->dev, "epll"); ++ if (IS_ERR(info->sclka)) { ++ pr_err("get sclka failed\n"); ++ } else { ++ rate = clk_get_rate(info->sclka); ++ if (((rate / 1000) % 27000) != 0) { ++ clk_set_rate(info->sclka, 891000000); ++ } ++ } ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 27000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ *(volatile unsigned int *)(0xb0010100) = 1; // set gpio a work at 1.8v ++ sc230ai_xshutdn(sd, 1); ++ sc230ai_pwdn(sd, 1); ++ sc230ai_lightup(sd, 1); ++#if 1 ++ /* Make sure it's an sc230ai */ ++ ret = sc230ai_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an sc230ai chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 443135, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 1152 - 4 , 4, 600); ++ ++ cfg.ops = &sc230ai_ctrl_ops; ++ cfg.id = V4L2_CID_USER_EXPOSURE_SHORT; ++ cfg.name = "expo short"; ++ cfg.type = V4L2_CTRL_TYPE_INTEGER; ++ cfg.min = 1; ++ cfg.max = 131; ++ cfg.step = 4; ++ cfg.def = 50; ++ info->exposure_short = v4l2_ctrl_new_custom(&info->hdl, &cfg, NULL); ++ ++ memset(&cfg, 0, sizeof(cfg)); ++ cfg.ops = &sc230ai_ctrl_ops; ++ cfg.id = V4L2_CID_USER_ANALOG_GAIN_SHORT; ++ cfg.name = "analog gain short"; ++ cfg.type = V4L2_CTRL_TYPE_INTEGER; ++ cfg.min = 0; ++ cfg.max = 589824; ++ cfg.step = 1; ++ cfg.def = 10000; ++ info->again_short = v4l2_ctrl_new_custom(&info->hdl, &cfg, NULL); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "sc230ai Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int sc230ai_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct sc230ai_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id sc230ai_id[] = { ++ { "sc230ai", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, sc230ai_id); ++ ++static const struct of_device_id sc230ai_of_match[] = { ++ {.compatible = "smartsens,sc230ai", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sc230ai_of_match); ++ ++ ++static struct i2c_driver sc230ai_driver = { ++ .driver = { ++ .name = "sc230ai", ++ .of_match_table = of_match_ptr(sc230ai_of_match), ++ }, ++ .probe = sc230ai_probe, ++ .remove = sc230ai_remove, ++ .id_table = sc230ai_id, ++}; ++ ++module_i2c_driver(sc230ai_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for SmartSens sc230ai sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp-v2/sc2310.c b/module_drivers/drivers/media/i2c/ingenic-isp-v2/sc2310.c +new file mode 100644 +index 000000000..03760e8bb +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp-v2/sc2310.c +@@ -0,0 +1,2461 @@ ++/* ++ * A V4L2 driver for SmartSens sc2310 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define SC2310_CHIP_ID_H (0x23) ++#define SC2310_CHIP_ID_L (0x11) ++#define SC2310_REG_END 0xffff ++#define SC2310_REG_DELAY 0xfffe ++ ++#define AGAIN_MAX_DB 0x64 ++#define DGAIN_MAX_DB 0x64 ++#define LOG2_GAIN_SHIFT 16 ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++//#define SC2310_WDR_EN ++ ++struct sc2310_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++}; ++ ++struct sc2310_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct sc2310_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ struct v4l2_ctrl *again_short; ++ ++ struct v4l2_clk *clk; ++ struct clk *sclka; ++ ++ struct v4l2_ctrl *exposure; ++ struct v4l2_ctrl *exposure_short; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct sc2310_win_size *win; ++ ++ struct sc2310_gpio reset; ++ struct sc2310_gpio ircutp; ++ struct sc2310_gpio ircutn; ++ struct sc2310_gpio pwen; ++ struct sc2310_gpio pwdn; ++}; ++ ++void sc2310_power_init_seq(struct sc2310_info *info); ++static inline struct sc2310_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct sc2310_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct sc2310_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; ++ unsigned int gain; ++}; ++ ++struct again_lut sc2310_again_lut[] = { ++ {0x340, 0}, ++ {0x342, 2886}, ++ {0x344, 5776}, ++ {0x346, 8494}, ++ {0x348, 11136}, ++ {0x34a, 13706}, ++ {0x34c, 16287}, ++ {0x34e, 18723}, ++ {0x350, 21097}, ++ {0x352, 23414}, ++ {0x354, 25746}, ++ {0x356, 27953}, ++ {0x358, 30109}, ++ {0x35a, 32217}, ++ {0x35c, 34345}, ++ {0x35e, 36361}, ++ {0x360, 38336}, ++ {0x362, 40270}, ++ {0x364, 42226}, ++ {0x366, 44082}, ++ {0x368, 45904}, ++ {0x36a, 47690}, ++ {0x36c, 49500}, ++ {0x36e, 51220}, ++ {0x370, 52910}, ++ {0x372, 54571}, ++ {0x374, 56254}, ++ {0x376, 57857}, ++ {0x378, 59433}, ++ {0x37a, 60984}, ++ {0x37c, 62558}, ++ {0x37e, 64059}, ++ {0x740, 65536}, ++ {0x742, 68468}, ++ {0x744, 71267}, ++ {0x746, 74030}, ++ {0x748, 76672}, ++ {0x74a, 79283}, ++ {0x74c, 81784}, ++ {0x74e, 84259}, ++ {0x750, 86633}, ++ {0x752, 88986}, ++ {0x754, 91246}, ++ {0x756, 93489}, ++ {0x2341, 96091}, ++ {0x2343, 98956}, ++ {0x2345, 101736}, ++ {0x2347, 104437}, ++ {0x2349, 107063}, ++ {0x234b, 109618}, ++ {0x234d, 112106}, ++ {0x234f, 114530}, ++ {0x2351, 116894}, ++ {0x2353, 119200}, ++ {0x2355, 121451}, ++ {0x2357, 123649}, ++ {0x2359, 125798}, ++ {0x235b, 127899}, ++ {0x235d, 129954}, ++ {0x235f, 131965}, ++ {0x2361, 133935}, ++ {0x2363, 135864}, ++ {0x2365, 137755}, ++ {0x2367, 139609}, ++ {0x2369, 141427}, ++ {0x236b, 143211}, ++ {0x236d, 144962}, ++ {0x236f, 146681}, ++ {0x2371, 148369}, ++ {0x2373, 150027}, ++ {0x2375, 151657}, ++ {0x2377, 153260}, ++ {0x2379, 154836}, ++ {0x237b, 156385}, ++ {0x237d, 157910}, ++ {0x237f, 159411}, ++ {0x2741, 161610}, ++ {0x2743, 164475}, ++ {0x2745, 167256}, ++ {0x2747, 169958}, ++ {0x2749, 172584}, ++ {0x274b, 175140}, ++ {0x274d, 177628}, ++ {0x274f, 180052}, ++ {0x2751, 182416}, ++ {0x2753, 184722}, ++ {0x2755, 186974}, ++ {0x2757, 189172}, ++ {0x2759, 191321}, ++ {0x275b, 193423}, ++ {0x275d, 195478}, ++ {0x275f, 197490}, ++ {0x2761, 199460}, ++ {0x2763, 201389}, ++ {0x2765, 203280}, ++ {0x2767, 205134}, ++ {0x2769, 206953}, ++ {0x276b, 208736}, ++ {0x276d, 210487}, ++ {0x276f, 212207}, ++ {0x2771, 213895}, ++ {0x2773, 215554}, ++ {0x2775, 217184}, ++ {0x2777, 218786}, ++ {0x2779, 220362}, ++ {0x277b, 221912}, ++ {0x277d, 223437}, ++ {0x277f, 224938}, ++ {0x2f41, 227146}, ++ {0x2f43, 230011}, ++ {0x2f45, 232792}, ++ {0x2f47, 235494}, ++ {0x2f49, 238120}, ++ {0x2f4b, 240676}, ++ {0x2f4d, 243164}, ++ {0x2f4f, 245588}, ++ {0x2f51, 247952}, ++ {0x2f53, 250258}, ++ {0x2f55, 252510}, ++ {0x2f57, 254708}, ++ {0x2f59, 256857}, ++ {0x2f5b, 258959}, ++ {0x2f5d, 261014}, ++ {0x2f5f, 263026}, ++ {0x2f61, 264996}, ++ {0x2f63, 266925}, ++ {0x2f65, 268816}, ++ {0x2f67, 270670}, ++ {0x2f69, 272489}, ++ {0x2f6b, 274273}, ++ {0x2f6d, 276023}, ++ {0x2f6f, 277743}, ++ {0x2f71, 279431}, ++ {0x2f73, 281090}, ++ {0x2f75, 282720}, ++ {0x2f77, 284322}, ++ {0x2f79, 285898}, ++ {0x2f7b, 287448}, ++ {0x2f7d, 288973}, ++ {0x2f7f, 290474}, ++ {0x3f41, 292682}, ++ {0x3f43, 295547}, ++ {0x3f45, 298328}, ++ {0x3f47, 301030}, ++ {0x3f49, 303656}, ++ {0x3f4b, 306212}, ++ {0x3f4d, 308700}, ++ {0x3f4f, 311124}, ++ {0x3f51, 313488}, ++ {0x3f53, 315794}, ++ {0x3f55, 318046}, ++ {0x3f57, 320244}, ++ {0x3f59, 322393}, ++ {0x3f5b, 324495}, ++ {0x3f5d, 326550}, ++ {0x3f5f, 328562}, ++ {0x3f61, 330532}, ++ {0x3f63, 332461}, ++ {0x3f65, 334352}, ++ {0x3f67, 336206}, ++ {0x3f69, 338025}, ++ {0x3f6b, 339809}, ++ {0x3f6d, 341559}, ++ {0x3f6f, 343279}, ++ {0x3f71, 344967}, ++ {0x3f73, 346626}, ++ {0x3f75, 348256}, ++ {0x3f77, 349858}, ++ {0x3f79, 351434}, ++ {0x3f7b, 352984}, ++ {0x3f7d, 354509}, ++ {0x3f7f, 356010}, ++}; ++ ++static struct regval_list sc2310_init_regs_1920_1080_25fps_mipi_dol[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x36e9, 0xa6}, ++ {0x36f9, 0x85}, ++ {0x3001, 0xfe}, ++ {0x3018, 0x33}, ++ {0x301c, 0x78}, ++ {0x3031, 0x0a}, ++ {0x3037, 0x24}, ++ {0x3038, 0x44}, ++ {0x303f, 0x01}, ++ {0x3200, 0x00}, ++ {0x3201, 0x04}, ++ {0x3202, 0x00}, ++ {0x3203, 0x00}, ++ {0x3204, 0x07}, ++ {0x3205, 0x8b}, ++ {0x3206, 0x04}, ++ {0x3207, 0x3f}, ++ {0x3208, 0x07}, ++ {0x3209, 0x80}, ++ {0x320a, 0x04}, ++ {0x320b, 0x38}, ++ {0x320c, 0x04}, ++ {0x320d, 0x4c}, ++ {0x320e, 0x08},//0x08 ++ {0x320f, 0xca}, ++ {0x3211, 0x04}, ++ {0x3213, 0x04}, ++ {0x3220, 0x51}, ++ {0x3222, 0x29}, ++ {0x3301, 0x10}, ++ {0x3302, 0x10}, ++ {0x3303, 0x30}, ++ {0x3306, 0x54}, ++ {0x3308, 0x10}, ++ {0x3309, 0x48}, ++ {0x330a, 0x00}, ++ {0x330b, 0xb4}, ++ {0x330e, 0x30}, ++ {0x3314, 0x04}, ++ {0x331b, 0x83}, ++ {0x331e, 0x21}, ++ {0x331f, 0x39}, ++ {0x3320, 0x01}, ++ {0x3324, 0x02}, ++ {0x3325, 0x02}, ++ {0x3326, 0x00}, ++ {0x3333, 0x30}, ++ {0x3334, 0x40}, ++ {0x333d, 0x08}, ++ {0x3341, 0x07}, ++ {0x3343, 0x03}, ++ {0x3364, 0x1d}, ++ {0x3366, 0xc0}, ++ {0x3367, 0x08}, ++ {0x3368, 0x04}, ++ {0x3369, 0x00}, ++ {0x336a, 0x00}, ++ {0x336b, 0x00}, ++ {0x336c, 0x42}, ++ {0x337f, 0x03}, ++ {0x3380, 0x1b}, ++ {0x33aa, 0x00}, ++ {0x33b6, 0x07}, ++ {0x33b7, 0x07}, ++ {0x33b8, 0x10}, ++ {0x33b9, 0x10}, ++ {0x33ba, 0x10}, ++ {0x33bb, 0x07}, ++ {0x33bc, 0x07}, ++ {0x33bd, 0x18}, ++ {0x33be, 0x18}, ++ {0x33bf, 0x18}, ++ {0x33c0, 0x05}, ++ {0x360f, 0x05}, ++ {0x3621, 0xac}, ++ {0x3622, 0xf6}, ++ {0x3623, 0x18}, ++ {0x3624, 0x47}, ++ {0x3625, 0x09}, ++ {0x3630, 0xc8}, ++ {0x3631, 0x88}, ++ {0x3632, 0x18}, ++ {0x3633, 0x22}, ++ {0x3634, 0x44}, ++ {0x3635, 0x20}, ++ {0x3636, 0x62}, ++ {0x3637, 0x0c}, ++ {0x3638, 0x24}, ++ {0x363a, 0x83}, ++ {0x363b, 0x08}, ++ {0x363c, 0x05}, ++ {0x363d, 0x05}, ++ {0x3640, 0x00}, ++ {0x366e, 0x04}, ++ {0x3670, 0x6a}, ++ {0x3671, 0xf6}, ++ {0x3672, 0x16}, ++ {0x3673, 0x16}, ++ {0x3674, 0xc8}, ++ {0x3675, 0x54}, ++ {0x3676, 0x18}, ++ {0x3677, 0x22}, ++ {0x3678, 0x53}, ++ {0x3679, 0x55}, ++ {0x367a, 0x40}, ++ {0x367b, 0x40}, ++ {0x367c, 0x40}, ++ {0x367d, 0x58}, ++ {0x367e, 0x40}, ++ {0x367f, 0x58}, ++ {0x3693, 0x20}, ++ {0x3694, 0x40}, ++ {0x3695, 0x40}, ++ {0x3696, 0x9f}, ++ {0x3697, 0x9f}, ++ {0x3698, 0x9f}, ++ {0x369e, 0x40}, ++ {0x369f, 0x40}, ++ {0x36a0, 0x58}, ++ {0x36a1, 0x78}, ++ {0x36ea, 0x35}, ++ {0x36eb, 0x0a}, ++ {0x36ec, 0x0e}, ++ {0x36fa, 0xa8}, ++ {0x3802, 0x00}, ++ {0x3901, 0x02}, ++ {0x3902, 0xc5}, ++ {0x3905, 0xd8}, ++ {0x3907, 0x01}, ++ {0x3908, 0x01}, ++ {0x391d, 0x21}, ++ {0x391e, 0x00}, ++ {0x391f, 0xc0}, ++ {0x3933, 0x28}, ++ {0x3934, 0x0a}, ++ {0x3940, 0x1b}, ++ {0x3941, 0x40}, ++ {0x3942, 0x08}, ++ {0x3943, 0x0e}, ++ {0x3e00, 0x01}, ++ {0x3e01, 0x07}, ++ {0x3e02, 0xa0}, ++ {0x3e03, 0x0b}, ++ {0x3e04, 0x10}, ++ {0x3e05, 0x80}, ++ {0x3e06, 0x00}, ++ {0x3e07, 0x80}, ++ {0x3e08, 0x03}, ++ {0x3e09, 0x40}, ++ {0x3e0e, 0x66}, ++ {0x3e14, 0xb0}, ++ {0x3e1e, 0x35}, ++ {0x3e23, 0x00}, ++ {0x3e24, 0x26}, ++ {0x3e25, 0x03}, ++ {0x3e26, 0x40}, ++ {0x3f00, 0x0d}, ++ {0x3f04, 0x02}, ++ {0x3f05, 0x1e}, ++ {0x3f08, 0x04}, ++ {0x4500, 0x59}, ++ {0x4501, 0xa4}, ++ {0x4509, 0x10}, ++ {0x4602, 0x0f}, ++ {0x4603, 0x00}, ++ {0x4809, 0x01}, ++ {0x4816, 0x51}, ++ {0x4837, 0x1a}, ++ {0x5000, 0x06}, ++ {0x5780, 0x7f}, ++ {0x5781, 0x06}, ++ {0x5782, 0x04}, ++ {0x5783, 0x02}, ++ {0x5784, 0x01}, ++ {0x5785, 0x16}, ++ {0x5786, 0x12}, ++ {0x5787, 0x08}, ++ {0x5788, 0x02}, ++ {0x57a0, 0x00}, ++ {0x57a1, 0x74}, ++ {0x57a2, 0x01}, ++ {0x57a3, 0xf4}, ++ {0x57a4, 0xf0}, ++ {0x6000, 0x06}, ++ {0x6002, 0x06}, ++ {0x36e9, 0x26}, ++ {0x36f9, 0x05}, ++ {0x0100, 0x01}, ++ ++ {SC2310_REG_DELAY, 10}, ++ {SC2310_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc2310_init_regs_1920_1080_15fps_mipi[] = { ++ /* {0x0103, 0x01}, */ ++ /* {0x0100, 0x00}, */ ++ /* {SC2310_REG_DELAY, 10}, */ ++ {0x36e9, 0xa3},//bypass pll1 20180830 ++ {0x36f9, 0x85},//bypass pll2 20180830 ++ {0x4509, 0x10}, ++ {0x4500, 0x39}, ++ {0x3907, 0x00}, ++ {0x3908, 0x44}, ++ {0x3633, 0x87}, ++ {0x3306, 0x7e}, ++ {0x330b, 0x00}, ++ {0x3635, 0x4c}, ++ {0x330e, 0x7a}, ++ {0x3302, 0x1f}, //3302 need be odd why???? 3366 3302 3621 ++ {0x3e01, 0x8c}, ++ {0x3e02, 0x80}, ++ {0x3e09, 0x1f}, ++ {0x3e08, 0x3f}, ++ {0x3e06, 0x03}, ++ {0x337f, 0x03}, //new auto precharge 330e in 3372 [7:6] 11: close div_rst 00:open div_rst ++ {0x3368, 0x04}, ++ {0x3369, 0x00}, ++ {0x336a, 0x00}, ++ {0x336b, 0x00}, ++ {0x3367, 0x08}, ++ {0x330e, 0x30}, ++ {0x3320, 0x06}, // New ramp offset timing ++ {0x3326, 0x00}, ++ {0x331e, 0x11}, ++ {0x331f, 0x21}, ++ {0x3303, 0x20}, ++ {0x3309, 0x30}, ++ {0x4501, 0xc4}, ++ {0x3e06, 0x00}, ++ {0x3e08, 0x03}, ++ {0x3e09, 0x10}, ++ {0x3366, 0x7c}, // div_rst gap ++ {0x3622, 0x02}, ++ {0x3633, 0x63}, ++ {0x3038, 0x88}, ++ {0x3635, 0x45}, ++ {0x363b, 0x04}, ++ {0x363c, 0x06}, ++ {0x363d, 0x05}, ++ {0x3633, 0x23}, ++ {0x3301, 0x10}, ++ {0x3306, 0x58}, ++ {0x3622, 0x06},//blksun ++ {0x3631, 0x88}, ++ {0x3630, 0x38}, ++ {0x3633, 0x22}, ++ {0x3018, 0x33},//[7:5] lane_num-1 ++ {0x3031, 0x0c},//[3:0] bitmode ++ {0x3037, 0x40},//[6:5] bitsel 40:12bit ++ {0x3001, 0xFE},//[0] c_y ++ {0x4603, 0x00},//[0] data_fifo mipi mode ++ {0x4837, 0x35},//[7:0] pclk period * 2 ++ {0x36e9, 0x83}, ++ {0x36eb, 0x0f}, ++ {0x36ec, 0x1f}, ++ {0x303f, 0x01}, ++ {0x330b, 0x20}, ++ {0x3640, 0x00}, ++ {0x3308, 0x10}, ++ {0x3637, 0x0a}, ++ {0x3e09, 0x20}, //3f for 2x fine gain ++ {0x363b, 0x08}, ++ {0x3637, 0x09}, // ADC range: 14.8k fullwell blc target : 0.9k output fullwell: 13.9k (5fps 27C linear fullwell is 14.5K) ++ {0x3638, 0x14}, ++ {0x3636, 0x65}, ++ {0x3907, 0x01}, ++ {0x3908, 0x01}, ++ {0x3320, 0x01}, //ramp ++ {0x331e, 0x15}, ++ {0x331f, 0x25}, ++ {0x3366, 0x80}, ++ {0x3634, 0x34}, ++ {0x57a4, 0xf0}, //default c0, ++ {0x3635, 0x41}, //fpn ++ {0x3e02, 0x30}, //minimum exp 3? debug ++ {0x3333, 0x30}, //col fpn G >br ? ++ {0x331b, 0x83}, ++ {0x3334, 0x40}, ++ {0x3306, 0x6c}, ++ {0x3638, 0x17}, ++ {0x330a, 0x01}, ++ {0x330b, 0x14}, ++ {0x3302, 0x10}, ++ {0x3308, 0x08}, ++ {0x3303, 0x18}, ++ {0x3309, 0x18}, ++ {0x331e, 0x11}, ++ {0x331f, 0x11}, ++ {0x3f00, 0x0d}, //[2] hts/2-4 ++ {0x3f04, 0x02}, ++ {0x3f05, 0x22}, ++ {0x3622, 0xe6}, ++ {0x3633, 0x22}, ++ {0x3630, 0xc8}, ++ {0x3301, 0x10}, ++ {0x36e9, 0xa3}, ++ {0x36eb, 0x0b}, ++ {0x36ec, 0x0f}, ++ {0x3638, 0x27}, ++ {0x33aa, 0x00}, //power save mode ++ {0x3624, 0x02}, ++ {0x3621, 0xac}, ++ {0x4509, 0x40}, ++ {0x391e, 0x00}, ++ {0x391f, 0xc0}, ++ {0x3635, 0x45}, ++ {0x336c, 0x40}, ++ {0x3621, 0xae}, ++ {0x3623, 0x08}, ++ {0x36fa, 0xad}, //charge pump ++ {0x3634, 0x44}, ++ {0x3621, 0xac}, //fifo delay ++ {0x4500, 0x59}, ++ {0x3623, 0x18}, //for more grp rdout setup margin ++ {0x3f08, 0x04}, ++ {0x3f00, 0x0d}, //[2] hts/2-4-{3f08} ++ {0x3f04, 0x02}, //0321 ++ {0x3f05, 0x1e}, //0321 ++ {0x336c, 0x42}, //recover read timing ++ {0x5000, 0x06},//dpc enable ++ {0x5780, 0x7f},//auto blc setting ++ {0x57a0, 0x00}, //gain0 = 2x 0x0710ÖÃ0x071f ++ {0x57a1, 0x71}, ++ {0x57a2, 0x01}, //gain1 = 8x 0x1f10ÖÃ0x1f1f ++ {0x57a3, 0xf1}, ++ {0x5781, 0x06}, //white 1x ++ {0x5782, 0x04}, //2x ++ {0x5783, 0x02}, //8x ++ {0x5784, 0x01}, //128x ++ {0x5785, 0x16}, //black 1x ++ {0x5786, 0x12}, //2x ++ {0x5787, 0x08}, //8x ++ {0x5788, 0x02}, //128x ++ {0x3933, 0x28}, ++ {0x3934, 0x0a}, ++ {0x3940, 0x1b}, ++ {0x3941, 0x40}, ++ {0x3942, 0x08}, ++ {0x3943, 0x0e}, ++ {0x3208, 0x07}, ++ {0x3209, 0x80}, ++ {0x320a, 0x04}, ++ {0x320b, 0x38}, ++ {0x3211, 0x08}, ++ {0x3213, 0x08}, ++ {0x36e9, 0xa3}, ++ {0x36ea, 0x77}, ++ {0x36eb, 0x0b}, ++ {0x36ec, 0x0f}, ++ {0x36ed, 0x03}, ++ {0x36f9, 0x85}, ++ {0x36fa, 0x2d}, ++ {0x36fb, 0x10}, ++ {0x320c, 0x04},//hts=1125*2=2250 ++ {0x320d, 0x65}, ++ {0x320e, 0x12},//vts=2400 ++ {0x320f, 0x60}, ++ {0x3235, 0x12},//vts*2-0x02 ++ {0x3236, 0xbe}, ++ {0x3f04, 0x02},//{0x320c,0x320d}/2-0x3f08-0x04 ++ {0x3f05, 0x2a}, ++ {0x3802, 0x00}, ++ {0x3624, 0x47}, ++ {0x3621, 0xac}, ++ {0x36fa, 0x2f}, ++ {0x3637, 0x08}, ++ {0x3638, 0x25}, ++ {0x3635, 0x40}, ++ {0x363b, 0x08}, ++ {0x363c, 0x05}, ++ {0x363d, 0x05}, ++ {0x3303, 0x1c}, ++ {0x3309, 0x1c}, ++ {0x3324, 0x02}, //falling edge: ramp_offset_en cover ramp_integ_en ++ {0x3325, 0x02}, ++ {0x333d, 0x08}, //count_div_rst_width ++ {0x3314, 0x04}, ++ {0x36fa, 0x28}, ++ {0x3205, 0x93}, ++ {0x3e14, 0xb0}, //[7]:1 ana fine gain double 20~3f ++ {0x3e1e, 0x35}, //[7]:1 open DCG function in 0x3e03=0x03 [6]:0 DCG >2 [2] 1: dig_fine_gain_en [1:0] max fine gain 01: 3f ++ {0x3e0e, 0x66}, //[7:3] fine gain to compsensate 2.4x DCGgain 5 : 2.3125x 6:2.375x [2]:1 DCG gain between sa1gain 2~4 [1]:1 dcg gain in 0x3e08[5] ++ {0x3364, 0x1d},//[4] fine gain op 1~20--3f 0~10--1f [4] ana dithring en ++ {0x33b6, 0x07},//gain0 when dcg off ++ {0x33b7, 0x07},//gain1 when dcg off ++ {0x33b8, 0x10},//sel0 when dcg off ++ {0x33b9, 0x10},//sel1 when dcg off ++ {0x33ba, 0x10},//sel2 when dcg off ++ {0x33bb, 0x07},//gain0 when dcg on ++ {0x33bc, 0x07},//gain1 when dcg on ++ {0x33bd, 0x14},//sel0 when dcg on ++ {0x33be, 0x14},//sel1 when dcg on ++ {0x33bf, 0x14},//sel2 when dcg on ++ {0x360f, 0x05},//[0] 3622 auto en ++ {0x367a, 0x40},//gain0 ++ {0x367b, 0x40},//gain1 ++ {0x3671, 0xf6},//sel0 ++ {0x3672, 0x16},//sel1 ++ {0x3673, 0x16},//sel2 ++ {0x366e, 0x04},//[2] fine gain op 1~20--3f 0~10--1f ++ {0x3670, 0x4a},//[1] 3630 auto en, [3] 3633 auto en, [6] 363a auto en ++ {0x367c, 0x40},//gain0 3e08[5:2] 1000 ++ {0x367d, 0x58},//gain1 3e08[5:2] 1011 ++ {0x3674, 0xc8},//sel0 ++ {0x3675, 0x54},//sel1 ++ {0x3676, 0x18},//sel2 ++ {0x367e, 0x40},//gain0 3e08[5:2] 1000 ++ {0x367f, 0x58},//gain1 3e08[5:2] 1011 ++ {0x3677, 0x22},//sel0 ++ {0x3678, 0x53},//sel1 ++ {0x3679, 0x55},//sel2 ++ {0x36a0, 0x58},//gain0 3e08[5:2] 1011 ++ {0x36a1, 0x78},//gain1 3e08[5:2] 1111 ++ {0x3696, 0x83},//sel0 ++ {0x3697, 0x87},//sel1 ++ {0x3698, 0x9f},//sel2 ++ {0x4837, 0x31}, ++ {0x6000, 0x00}, ++ {0x6002, 0x00}, ++ {0x301c, 0x78},//close dvp ++ {0x3037, 0x44},//[3:0] pump div range [10M,20M],sclk=81/2=40.5M,div=4-->sclk/4=10.125M,duty cycle-->even number ++ {0x3038, 0x44},//[7:4]ppump & [3:0]npump ++ {0x3632, 0x18},//[5:4]idac driver ++ {0x5785, 0x40},//black point 1x ++ {0x4809, 0x01},//mipi first frame, lp status ++ {0x3637, 0x10}, ++ {0x5000, 0x06},//dpc enable ++ {0x5780, 0x7f},//auto blc setting ++ {0x57a0, 0x00}, //gain0 = 2x 0x0740ÖÃ0x077f ++ {0x57a1, 0x74}, ++ {0x57a2, 0x01}, //gain1 = 8x 0x1f40ÖÃ0x1f7f ++ {0x57a3, 0xf4}, ++ {0x5781, 0x06}, //white 1x ++ {0x5782, 0x04}, //2x ++ {0x5783, 0x02}, //8x ++ {0x5784, 0x01}, //128x ++ {0x5785, 0x16}, //black 1x ++ {0x5786, 0x12}, //2x ++ {0x5787, 0x08}, //8x ++ {0x5788, 0x02}, //128x ++ {0x4501, 0xb4},//reduce bit ++ {0x3637, 0x20}, ++ {0x4509, 0x20},//blc quantification //20181206 ++ {0x3364, 0x1d},//[4] fine gain op 1~20--3f 0~10--1f [4] ana dithring en ++ {0x33b6, 0x07},//gain0 when dcg off gain=dcg ++ {0x33bc, 0x07},//gain1 when dcg on ++ {0x33bd, 0x20},//sel0 when dcg on ++ {0x33be, 0x20},//sel1 when dcg on ++ {0x33bf, 0x20},//sel2 when dcg on ++ {0x360f, 0x05},//[0] 3622 auto en ++ {0x367a, 0x40},//gain0 ++ {0x367b, 0x40},//gain1 ++ {0x3671, 0xf6},//sel0 ++ {0x3672, 0x16},//sel1 ++ {0x3673, 0x16},//sel2 ++ {0x366e, 0x04},//[2] fine gain op 1~20--3f 0~10--1f ++ {0x3670, 0x4a},//[1] 3630 auto en, [3] 3633 auto en, [6] 363a auto en ++ {0x367c, 0x40},//gain0 3e08[5:2] 1000 ++ {0x367d, 0x58},//gain1 3e08[5:2] 1011 ++ {0x3674, 0xc8},//sel0 ++ {0x3675, 0x54},//sel1 ++ {0x3676, 0x18},//sel2 ++ {0x367e, 0x40},//gain0 3e08[5:2] 1000 ++ {0x367f, 0x58},//gain1 3e08[5:2] 1011 ++ {0x3677, 0x22},//sel0 ++ {0x3678, 0x33},//sel1 ++ {0x3679, 0x44},//sel2 ++ {0x36a0, 0x58},//gain0 3e08[5:2] 1011 ++ {0x36a1, 0x78},//gain1 3e08[5:2] 1111 ++ {0x3696, 0x83},//sel0 ++ {0x3697, 0x87},//sel1 ++ {0x3698, 0x9f},//sel2 ++ {0x3637, 0x17},//fullwell 8.6k ++ {0x331e, 0x11}, ++ {0x331f, 0x21},//1d ++ {0x3303, 0x1c}, //[hl,to][1,1a,2e] ++ {0x3309, 0x3c}, //[hl,to][1,32,46] ++ {0x330a, 0x00}, ++ {0x330b, 0xc8}, //[bs,to][1,a8,ec] ++ {0x3306, 0x68}, //[hl,bs][1,46,88] ++ {0x3200, 0x00}, ++ {0x3201, 0x04}, ++ {0x3202, 0x00}, ++ {0x3203, 0x04}, ++ {0x3204, 0x07}, ++ {0x3205, 0x8b}, ++ {0x3206, 0x04}, ++ {0x3207, 0x43}, ++ {0x3208, 0x07}, ++ {0x3209, 0x80}, ++ {0x320a, 0x04}, ++ {0x320b, 0x38}, ++ {0x3211, 0x04}, ++ {0x3213, 0x04}, ++ {0x3380, 0x1b}, ++ {0x3341, 0x07},//3318[3:0] + 2 ++ {0x3343, 0x03},//3318[3:0] -2 ++ {0x3e25, 0x03},//blc dithering(analog fine gain) ++ {0x3e26, 0x40}, ++ {0x3366, 0x70},//[60,78] ++ {0x3e00, 0x00},//max_exposure = vts*2-6; min_exposure = 3; 20180712 ++ {0x3e01, 0x95}, ++ {0x3e02, 0xa0}, ++ {0x3e03, 0x0b},//gain map 0x0b mode gain=1x ++ {0x3e06, 0x00}, ++ {0x3e07, 0x80}, ++ {0x3e08, 0x03}, ++ {0x3e09, 0x40}, ++ {0x3905, 0xd8}, ++ {0x36e9, 0x23},//enable pll1 20180830 ++ {0x36f9, 0x05},//enable pll2 20180830 ++ {0x0100, 0x01}, ++ ++ {SC2310_REG_DELAY, 10}, ++ {SC2310_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc2310_init_regs_1920_1080_15fps_mipi_dol[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x36e9, 0xa3},//bypass pll1 20180830 ++ {0x36f9, 0x85},//bypass pll2 20180830 ++ {0x4509, 0x10}, ++ {0x4500, 0x39}, ++ {0x3907, 0x00}, ++ {0x3908, 0x44}, ++ {0x3633, 0x87}, ++ {0x3306, 0x7e}, ++ {0x330b, 0x00}, ++ {0x3635, 0x4c}, ++ {0x330e, 0x7a}, ++ {0x3302, 0x1f}, //3302 need be odd why???? 3366 3302 3621 ++ {0x3e01, 0x8c}, ++ {0x3e02, 0x80}, ++ {0x3e09, 0x1f}, ++ {0x3e08, 0x3f}, ++ {0x3e06, 0x03}, ++ {0x337f, 0x03}, //new auto precharge 330e in 3372 [7:6] 11: close div_rst 00:open div_rst ++ {0x3368, 0x04}, ++ {0x3369, 0x00}, ++ {0x336a, 0x00}, ++ {0x336b, 0x00}, ++ {0x3367, 0x08}, ++ {0x330e, 0x30}, ++ {0x3320, 0x06}, // New ramp offset timing ++ {0x3326, 0x00}, ++ {0x331e, 0x11}, ++ {0x331f, 0x21}, ++ {0x3303, 0x20}, ++ {0x3309, 0x30}, ++ {0x4501, 0xc4}, ++ {0x3e06, 0x00}, ++ {0x3e08, 0x03}, ++ {0x3e09, 0x10}, ++ {0x3366, 0x7c}, // div_rst gap ++ {0x3622, 0x02}, ++ {0x3633, 0x63}, ++ {0x3038, 0x88}, ++ {0x3635, 0x45}, ++ {0x363b, 0x04}, ++ {0x363c, 0x06}, ++ {0x363d, 0x05}, ++ {0x3633, 0x23}, ++ {0x3301, 0x10}, ++ {0x3306, 0x58}, ++ {0x3622, 0x06},//blksun ++ {0x3631, 0x88}, ++ {0x3630, 0x38}, ++ {0x3633, 0x22}, ++ {0x3018, 0x33},//[7:5] lane_num-1 ++ {0x3031, 0x0c},//[3:0] bitmode ++ {0x3037, 0x40},//[6:5] bitsel 40:12bit ++ {0x3001, 0xFE},//[0] c_y ++ {0x4603, 0x00},//[0] data_fifo mipi mode ++ {0x4837, 0x35},//[7:0] pclk period * 2 ++ {0x36e9, 0x83}, ++ {0x36eb, 0x0f}, ++ {0x36ec, 0x1f}, ++ {0x303f, 0x01}, ++ {0x330b, 0x20}, ++ {0x3640, 0x00}, ++ {0x3308, 0x10}, ++ {0x3637, 0x0a}, ++ {0x3e09, 0x20}, //3f for 2x fine gain ++ {0x363b, 0x08}, ++ {0x3637, 0x09}, // ADC range: 14.8k fullwell blc target : 0.9k output fullwell: 13.9k (5fps 27C linear fullwell is 14.5K) ++ {0x3638, 0x14}, ++ {0x3636, 0x65}, ++ {0x3907, 0x01}, ++ {0x3908, 0x01}, ++ {0x3320, 0x01}, //ramp ++ {0x331e, 0x15}, ++ {0x331f, 0x25}, ++ {0x3366, 0x80}, ++ {0x3634, 0x34}, ++ {0x57a4, 0xf0}, //default c0, ++ {0x3635, 0x41}, //fpn ++ {0x3e02, 0x30}, //minimum exp 3? debug ++ {0x3333, 0x30}, //col fpn G >br ? ++ {0x331b, 0x83}, ++ {0x3334, 0x40}, ++ {0x3306, 0x6c}, ++ {0x3638, 0x17}, ++ {0x330a, 0x01}, ++ {0x330b, 0x14}, ++ {0x3302, 0x10}, ++ {0x3308, 0x08}, ++ {0x3303, 0x18}, ++ {0x3309, 0x18}, ++ {0x331e, 0x11}, ++ {0x331f, 0x11}, ++ {0x3f00, 0x0d}, //[2] hts/2-4 ++ {0x3f04, 0x02}, ++ {0x3f05, 0x22}, ++ {0x3622, 0xe6}, ++ {0x3633, 0x22}, ++ {0x3630, 0xc8}, ++ {0x3301, 0x10}, ++ {0x36e9, 0xa3}, ++ {0x36eb, 0x0b}, ++ {0x36ec, 0x0f}, ++ {0x3638, 0x27}, ++ {0x33aa, 0x00}, //power save mode ++ {0x3624, 0x02}, ++ {0x3621, 0xac}, ++ {0x4509, 0x40}, ++ {0x391e, 0x00}, ++ {0x391f, 0xc0}, ++ {0x3635, 0x45}, ++ {0x336c, 0x40}, ++ {0x3621, 0xae}, ++ {0x3623, 0x08}, ++ {0x36fa, 0xad}, //charge pump ++ {0x3634, 0x44}, ++ {0x3621, 0xac}, //fifo delay ++ {0x4500, 0x59}, ++ {0x3623, 0x18}, //for more grp rdout setup margin ++ {0x3f08, 0x04}, ++ {0x3f00, 0x0d}, //[2] hts/2-4-{3f08} ++ {0x3f04, 0x02}, //0321 ++ {0x3f05, 0x1e}, //0321 ++ {0x336c, 0x42}, //recover read timing ++ {0x5000, 0x06},//dpc enable ++ {0x5780, 0x7f},//auto blc setting ++ {0x57a0, 0x00}, //gain0 = 2x 0x0710ÖÃ0x071f ++ {0x57a1, 0x71}, ++ {0x57a2, 0x01}, //gain1 = 8x 0x1f10ÖÃ0x1f1f ++ {0x57a3, 0xf1}, ++ {0x5781, 0x06}, //white 1x ++ {0x5782, 0x04}, //2x ++ {0x5783, 0x02}, //8x ++ {0x5784, 0x01}, //128x ++ {0x5785, 0x16}, //black 1x ++ {0x5786, 0x12}, //2x ++ {0x5787, 0x08}, //8x ++ {0x5788, 0x02}, //128x ++ {0x3933, 0x28}, ++ {0x3934, 0x0a}, ++ {0x3940, 0x1b}, ++ {0x3941, 0x40}, ++ {0x3942, 0x08}, ++ {0x3943, 0x0e}, ++ {0x3208, 0x07}, ++ {0x3209, 0x80}, ++ {0x320a, 0x04}, ++ {0x320b, 0x38}, ++ {0x3211, 0x08}, ++ {0x3213, 0x08}, ++ {0x36e9, 0xa3}, ++ {0x36ea, 0x77}, ++ {0x36eb, 0x0b}, ++ {0x36ec, 0x0f}, ++ {0x36ed, 0x03}, ++ {0x36f9, 0x85}, ++ {0x36fa, 0x2d}, ++ {0x36fb, 0x10}, ++ {0x320c, 0x04},//hts=1125*2=2250 ++ {0x320d, 0x65}, ++ {0x320e, 0x04},//vts=1200 ++ {0x320f, 0xb0}, ++ {0x3235, 0x12},//vts*2-0x02 ++ {0x3236, 0xbe}, ++ {0x3f04, 0x02},//{0x320c,0x320d}/2-0x3f08-0x04 ++ {0x3f05, 0x2a}, ++ {0x3802, 0x00}, ++ {0x3624, 0x47}, ++ {0x3621, 0xac}, ++ {0x36fa, 0x2f}, ++ {0x3637, 0x08}, ++ {0x3638, 0x25}, ++ {0x3635, 0x40}, ++ {0x363b, 0x08}, ++ {0x363c, 0x05}, ++ {0x363d, 0x05}, ++ {0x3303, 0x1c}, ++ {0x3309, 0x1c}, ++ {0x3324, 0x02}, //falling edge: ramp_offset_en cover ramp_integ_en ++ {0x3325, 0x02}, ++ {0x333d, 0x08}, //count_div_rst_width ++ {0x3314, 0x04}, ++ {0x36fa, 0x28}, ++ {0x3205, 0x93}, ++ {0x3e14, 0xb0}, //[7]:1 ana fine gain double 20~3f ++ {0x3e1e, 0x35}, //[7]:1 open DCG function in 0x3e03=0x03 [6]:0 DCG >2 [2] 1: dig_fine_gain_en [1:0] max fine gain 01: 3f ++ {0x3e0e, 0x66}, //[7:3] fine gain to compsensate 2.4x DCGgain 5 : 2.3125x 6:2.375x [2]:1 DCG gain between sa1gain 2~4 [1]:1 dcg gain in 0x3e08[5] ++ {0x3364, 0x1d},//[4] fine gain op 1~20--3f 0~10--1f [4] ana dithring en ++ {0x33b6, 0x07},//gain0 when dcg off ++ {0x33b7, 0x07},//gain1 when dcg off ++ {0x33b8, 0x10},//sel0 when dcg off ++ {0x33b9, 0x10},//sel1 when dcg off ++ {0x33ba, 0x10},//sel2 when dcg off ++ {0x33bb, 0x07},//gain0 when dcg on ++ {0x33bc, 0x07},//gain1 when dcg on ++ {0x33bd, 0x14},//sel0 when dcg on ++ {0x33be, 0x14},//sel1 when dcg on ++ {0x33bf, 0x14},//sel2 when dcg on ++ {0x360f, 0x05},//[0] 3622 auto en ++ {0x367a, 0x40},//gain0 ++ {0x367b, 0x40},//gain1 ++ {0x3671, 0xf6},//sel0 ++ {0x3672, 0x16},//sel1 ++ {0x3673, 0x16},//sel2 ++ {0x366e, 0x04},//[2] fine gain op 1~20--3f 0~10--1f ++ {0x3670, 0x4a},//[1] 3630 auto en, [3] 3633 auto en, [6] 363a auto en ++ {0x367c, 0x40},//gain0 3e08[5:2] 1000 ++ {0x367d, 0x58},//gain1 3e08[5:2] 1011 ++ {0x3674, 0xc8},//sel0 ++ {0x3675, 0x54},//sel1 ++ {0x3676, 0x18},//sel2 ++ {0x367e, 0x40},//gain0 3e08[5:2] 1000 ++ {0x367f, 0x58},//gain1 3e08[5:2] 1011 ++ {0x3677, 0x22},//sel0 ++ {0x3678, 0x53},//sel1 ++ {0x3679, 0x55},//sel2 ++ {0x36a0, 0x58},//gain0 3e08[5:2] 1011 ++ {0x36a1, 0x78},//gain1 3e08[5:2] 1111 ++ {0x3696, 0x83},//sel0 ++ {0x3697, 0x87},//sel1 ++ {0x3698, 0x9f},//sel2 ++ {0x4837, 0x31}, ++ {0x6000, 0x00}, ++ {0x6002, 0x00}, ++ {0x301c, 0x78},//close dvp ++ {0x3037, 0x44},//[3:0] pump div range [10M,20M],sclk=81/2=40.5M,div=4-->sclk/4=10.125M,duty cycle-->even number ++ {0x3038, 0x44},//[7:4]ppump & [3:0]npump ++ {0x3632, 0x18},//[5:4]idac driver ++ {0x5785, 0x40},//black point 1x ++ {0x4809, 0x01},//mipi first frame, lp status ++ {0x3637, 0x10}, ++ {0x5000, 0x06},//dpc enable ++ {0x5780, 0x7f},//auto blc setting ++ {0x57a0, 0x00}, //gain0 = 2x 0x0740ÖÃ0x077f ++ {0x57a1, 0x74}, ++ {0x57a2, 0x01}, //gain1 = 8x 0x1f40ÖÃ0x1f7f ++ {0x57a3, 0xf4}, ++ {0x5781, 0x06}, //white 1x ++ {0x5782, 0x04}, //2x ++ {0x5783, 0x02}, //8x ++ {0x5784, 0x01}, //128x ++ {0x5785, 0x16}, //black 1x ++ {0x5786, 0x12}, //2x ++ {0x5787, 0x08}, //8x ++ {0x5788, 0x02}, //128x ++ {0x4501, 0xb4},//reduce bit ++ {0x3637, 0x20}, ++ {0x4509, 0x20},//blc quantification //20181206 ++ {0x3364, 0x1d},//[4] fine gain op 1~20--3f 0~10--1f [4] ana dithring en ++ {0x33b6, 0x07},//gain0 when dcg off gain=dcg ++ {0x33bc, 0x07},//gain1 when dcg on ++ {0x33bd, 0x20},//sel0 when dcg on ++ {0x33be, 0x20},//sel1 when dcg on ++ {0x33bf, 0x20},//sel2 when dcg on ++ {0x360f, 0x05},//[0] 3622 auto en ++ {0x367a, 0x40},//gain0 ++ {0x367b, 0x40},//gain1 ++ {0x3671, 0xf6},//sel0 ++ {0x3672, 0x16},//sel1 ++ {0x3673, 0x16},//sel2 ++ {0x366e, 0x04},//[2] fine gain op 1~20--3f 0~10--1f ++ {0x3670, 0x4a},//[1] 3630 auto en, [3] 3633 auto en, [6] 363a auto en ++ {0x367c, 0x40},//gain0 3e08[5:2] 1000 ++ {0x367d, 0x58},//gain1 3e08[5:2] 1011 ++ {0x3674, 0xc8},//sel0 ++ {0x3675, 0x54},//sel1 ++ {0x3676, 0x18},//sel2 ++ {0x367e, 0x40},//gain0 3e08[5:2] 1000 ++ {0x367f, 0x58},//gain1 3e08[5:2] 1011 ++ {0x3677, 0x22},//sel0 ++ {0x3678, 0x33},//sel1 ++ {0x3679, 0x44},//sel2 ++ {0x36a0, 0x58},//gain0 3e08[5:2] 1011 ++ {0x36a1, 0x78},//gain1 3e08[5:2] 1111 ++ {0x3696, 0x9f},//sel0 ++ {0x3697, 0x9f},//sel1 ++ {0x3698, 0x9f},//sel2 ++ {0x3637, 0x17},//fullwell 8.6k ++ {0x331e, 0x11}, ++ {0x331f, 0x21},//1d ++ {0x3303, 0x1c}, //[hl,to][1,1a,2e] ++ {0x3309, 0x3c}, //[hl,to][1,32,46] ++ {0x330a, 0x00}, ++ {0x330b, 0xc8}, //[bs,to][1,a8,ec] ++ {0x3306, 0x68}, //[hl,bs][1,46,88] ++ {0x3200, 0x00}, ++ {0x3201, 0x04}, ++ {0x3202, 0x00}, ++ {0x3203, 0x04}, ++ {0x3204, 0x07}, ++ {0x3205, 0x8b}, ++ {0x3206, 0x04}, ++ {0x3207, 0x43}, ++ {0x3208, 0x07}, ++ {0x3209, 0x80}, ++ {0x320a, 0x04}, ++ {0x320b, 0x38}, ++ {0x3211, 0x04}, ++ {0x3213, 0x04}, ++ {0x3380, 0x1b}, ++ {0x3341, 0x07},//3318[3:0] + 2 ++ {0x3343, 0x03},//3318[3:0] -2 ++ {0x3e25, 0x03},//blc dithering(analog fine gain) ++ {0x3e26, 0x40}, ++ {0x3366, 0x70},//[60,78] ++ {0x4816, 0x51},//bit[4] ++ {0x3220, 0x51},//bit[6] ++ {0x4602, 0x0f},//bit[3:0] ++ {0x33c0, 0x05},//bit[2] ++ {0x6000, 0x06}, ++ {0x6002, 0x06}, ++ /* {0x320e, 0x1a},//double vts */ ++ /* {0x320f, 0x60}, */ ++ {0x320e, 0x12},//double vts ++ {0x320f, 0x60}, ++ {0x3202, 0x00},//x_start must be 0x00 ++ {0x3203, 0x00}, ++ {0x3206, 0x04},//1088 activeBoard=4 ++ {0x3207, 0x3f}, ++ {0x3e00, 0x01},//max long exposure = 0x103e ++ {0x3e01, 0x19}, ++ {0x3e02, 0xe0}, ++ {0x3e04, 0x11},//max short exposure = 0x104 ++ {0x3e05, 0x80}, ++ {0x3e23, 0x01},//max long exp : max short exp <= 16:1 ++ {0x3e24, 0x1a}, ++ {0x3e03, 0x0b},//gain map 0x0b mode gain=1x ++ {0x3e06, 0x00}, ++ {0x3e07, 0x80}, ++ {0x3e08, 0x03}, ++ {0x3e09, 0x40}, ++ {0x3905, 0xd8}, ++ {0x36e9, 0x23},//enable pll1 20180830 ++ {0x36f9, 0x05},//enable pll2 20180830 ++ {0x0100, 0x01}, ++ {SC2310_REG_DELAY, 10}, ++ {SC2310_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc2310_init_regs_1920_1080_25fps_mipi[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x36e9, 0xa3},//bypass pll1 ++ {0x36f9, 0x85},//bypass pll2 ++ {0x337f, 0x03}, ++ {0x3368, 0x04}, ++ {0x3369, 0x00}, ++ {0x336a, 0x00}, ++ {0x336b, 0x00}, ++ {0x3367, 0x08}, ++ {0x330e, 0x30}, ++ {0x3326, 0x00}, ++ {0x3631, 0x88}, ++ {0x3018, 0x33}, ++ {0x3031, 0x0c}, ++ {0x3001, 0xfe}, ++ {0x4603, 0x00}, ++ {0x303f, 0x01}, ++ {0x3640, 0x00}, ++ {0x3636, 0x65}, ++ {0x3907, 0x01}, ++ {0x3908, 0x01}, ++ {0x3320, 0x01}, ++ {0x3366, 0x70}, ++ {0x57a4, 0xf0}, ++ {0x3333, 0x30}, ++ {0x331b, 0x83}, ++ {0x3334, 0x40}, ++ {0x3302, 0x10}, ++ {0x3308, 0x08}, ++ {0x3622, 0xe6}, ++ {0x3633, 0x22}, ++ {0x3630, 0xc8}, ++ {0x3301, 0x10}, ++ {0x33aa, 0x00}, ++ {0x391e, 0x00}, ++ {0x391f, 0xc0}, ++ {0x3634, 0x44}, ++ {0x4500, 0x59}, ++ {0x3623, 0x18}, ++ {0x3f08, 0x04}, ++ {0x3f00, 0x0d}, ++ {0x336c, 0x42}, ++ {0x3933, 0x28}, ++ {0x3934, 0x0a}, ++ {0x3940, 0x1b}, ++ {0x3941, 0x40}, ++ {0x3942, 0x08}, ++ {0x3943, 0x0e}, ++ {0x36ea, 0x77}, ++ {0x36eb, 0x0b}, ++ {0x36ec, 0x0f}, ++ {0x36ed, 0x03}, ++ {0x36fb, 0x10}, ++ {0x320c, 0x04},//1125 ++ {0x320d, 0x65}, ++ {0x320e, 0x05},//1440 ++ {0x320f, 0xa0}, ++ {0x3235, 0x09}, ++ {0x3236, 0x5e}, ++ {0x3f04, 0x02}, ++ {0x3f05, 0x2a}, ++ {0x3802, 0x00}, ++ {0x3624, 0x47}, ++ {0x3621, 0xac}, ++ {0x3638, 0x25}, ++ {0x3635, 0x40}, ++ {0x363b, 0x08}, ++ {0x363c, 0x05}, ++ {0x363d, 0x05}, ++ {0x3324, 0x02}, ++ {0x3325, 0x02}, ++ {0x333d, 0x08}, ++ {0x3314, 0x04}, ++ {0x36fa, 0x28}, ++ {0x3e14, 0xb0}, ++ {0x3e1e, 0x35}, ++ {0x3e0e, 0x66}, ++ {0x4837, 0x31}, ++ {0x6000, 0x00}, ++ {0x6002, 0x00}, ++ {0x301c, 0x78}, ++ {0x3037, 0x44}, ++ {0x3038, 0x44}, ++ {0x3632, 0x18}, ++ {0x4809, 0x01}, ++ {0x5000, 0x06}, ++ {0x5780, 0x7f}, ++ {0x57a0, 0x00}, ++ {0x57a1, 0x74}, ++ {0x57a2, 0x01}, ++ {0x57a3, 0xf4}, ++ {0x5781, 0x06}, ++ {0x5782, 0x04}, ++ {0x5783, 0x02}, ++ {0x5784, 0x01}, ++ {0x5785, 0x16}, ++ {0x5786, 0x12}, ++ {0x5787, 0x08}, ++ {0x5788, 0x02}, ++ {0x4501, 0xb4}, ++ {0x4509, 0x20}, ++ {0x3364, 0x1d}, ++ {0x33b6, 0x07}, ++ {0x33b7, 0x07}, ++ {0x33b8, 0x10}, ++ {0x33b9, 0x10}, ++ {0x33ba, 0x10}, ++ {0x33bb, 0x07}, ++ {0x33bc, 0x07}, ++ {0x33bd, 0x20}, ++ {0x33be, 0x20}, ++ {0x33bf, 0x20}, ++ {0x360f, 0x05}, ++ {0x367a, 0x40}, ++ {0x367b, 0x40}, ++ {0x3671, 0xf6}, ++ {0x3672, 0x16}, ++ {0x3673, 0x16}, ++ {0x366e, 0x04}, ++ {0x3670, 0x4a}, ++ {0x367c, 0x40}, ++ {0x367d, 0x58}, ++ {0x3674, 0xc8}, ++ {0x3675, 0x54}, ++ {0x3676, 0x18}, ++ {0x367e, 0x40}, ++ {0x367f, 0x58}, ++ {0x3677, 0x22}, ++ {0x3678, 0x33}, ++ {0x3679, 0x44}, ++ {0x36a0, 0x58}, ++ {0x36a1, 0x78}, ++ {0x3696, 0x83}, ++ {0x3697, 0x87}, ++ {0x3698, 0x9f}, ++ {0x3637, 0x17}, ++ {0x331e, 0x11}, ++ {0x331f, 0x21}, ++ {0x3303, 0x1c}, ++ {0x3309, 0x3c}, ++ {0x330a, 0x00}, ++ {0x330b, 0xc8}, ++ {0x3306, 0x68}, ++ {0x3200, 0x00}, ++ {0x3201, 0x04}, ++ {0x3202, 0x00}, ++ {0x3203, 0x04}, ++ {0x3204, 0x07}, ++ {0x3205, 0x8b}, ++ {0x3206, 0x04}, ++ {0x3207, 0x43}, ++ {0x3208, 0x07}, ++ {0x3209, 0x80}, ++ {0x320a, 0x04}, ++ {0x320b, 0x38}, ++ {0x3211, 0x04}, ++ {0x3213, 0x04}, ++ {0x3380, 0x1b}, ++ {0x3341, 0x07}, ++ {0x3343, 0x03}, ++ {0x3e25, 0x03}, ++ {0x3e26, 0x40}, ++ {0x3e00, 0x00}, ++ {0x3e01, 0x95}, ++ {0x3e02, 0xa0}, ++ {0x3e03, 0x0b}, ++ {0x3e06, 0x00}, ++ {0x3e07, 0x80}, ++ {0x3e08, 0x03}, ++ {0x3e09, 0x40}, ++ {0x3905, 0xd8}, ++ {0x36e9, 0x23}, ++ {0x36f9, 0x05}, ++ {0x0100, 0x01}, ++ {SC2310_REG_DELAY, 10}, ++ {SC2310_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc2310_init_regs_1920_1080_25fps_dvp[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x36e9, 0xa3},//bypass pll1 ++ {0x36f9, 0x85},//bypass pll2 ++ {0x337f, 0x03}, ++ {0x3368, 0x04}, ++ {0x3369, 0x00}, ++ {0x336a, 0x00}, ++ {0x336b, 0x00}, ++ {0x3367, 0x08}, ++ {0x330e, 0x30}, ++ {0x3326, 0x00}, ++ {0x3631, 0x88}, ++ {0x3640, 0x00}, ++ {0x3636, 0x65}, ++ {0x3907, 0x01}, ++ {0x3908, 0x01}, ++ {0x3320, 0x01}, ++ {0x3366, 0x70}, ++ {0x57a4, 0xf0}, ++ {0x3333, 0x30}, ++ {0x331b, 0x83}, ++ {0x3334, 0x40}, ++ {0x3302, 0x10}, ++ {0x3308, 0x08}, ++ {0x3622, 0xe6}, ++ {0x3633, 0x22}, ++ {0x3630, 0xc8}, ++ {0x3301, 0x10}, ++ {0x33aa, 0x00}, ++ {0x391e, 0x00}, ++ {0x391f, 0xc0}, ++ {0x3634, 0x44}, ++ {0x4500, 0x59}, ++ {0x3623, 0x18}, ++ {0x3f08, 0x04}, ++ {0x3f00, 0x0d}, ++ {0x336c, 0x42}, ++ {0x3933, 0x28}, ++ {0x3934, 0x0a}, ++ {0x3940, 0x1b}, ++ {0x3941, 0x40}, ++ {0x3942, 0x08}, ++ {0x3943, 0x0e}, ++ {0x36ea, 0x77}, ++ {0x36eb, 0x0b}, ++ {0x36ec, 0x0f}, ++ {0x36ed, 0x03}, ++ {0x36fb, 0x10}, ++ {0x320c, 0x04}, ++ {0x320d, 0x65}, ++ {0x320e, 0x05}, ++ {0x320f, 0xa0}, ++ {0x3235, 0x09}, ++ {0x3236, 0x5e}, ++ {0x3f04, 0x02}, ++ {0x3f05, 0x2a}, ++ {0x3802, 0x00}, ++ {0x3624, 0x47}, ++ {0x3621, 0xac}, ++ {0x3019, 0xff}, ++ {0x301c, 0xb4}, ++ {0x3018, 0x1f}, ++ {0x3031, 0x0a}, ++ {0x3001, 0xff}, ++ {0x4603, 0x01}, ++ {0x4837, 0x36}, ++ {0x303f, 0x81}, ++ {0x3d08, 0x01}, ++ {0x3638, 0x25}, ++ {0x3635, 0x40}, ++ {0x363b, 0x08}, ++ {0x363c, 0x05}, ++ {0x363d, 0x05}, ++ {0x3641, 0x01}, ++ {0x3324, 0x02}, ++ {0x3325, 0x02}, ++ {0x333d, 0x08}, ++ {0x3314, 0x04}, ++ {0x36fa, 0x28}, ++ {0x3e14, 0xb0}, ++ {0x3e1e, 0x35}, ++ {0x3e0e, 0x66}, ++ {0x6000, 0x00}, ++ {0x6002, 0x00}, ++ {0x3037, 0x24}, ++ {0x3038, 0x44}, ++ {0x3632, 0x18}, ++ {0x4809, 0x01}, ++ {0x5000, 0x06}, ++ {0x5780, 0x7f}, ++ {0x57a0, 0x00}, ++ {0x57a1, 0x74}, ++ {0x57a2, 0x01}, ++ {0x57a3, 0xf4}, ++ {0x5781, 0x06}, ++ {0x5782, 0x04}, ++ {0x5783, 0x02}, ++ {0x5784, 0x01}, ++ {0x5785, 0x16}, ++ {0x5786, 0x12}, ++ {0x5787, 0x08}, ++ {0x5788, 0x02}, ++ {0x4501, 0xb4}, ++ {0x4509, 0x20}, ++ {0x3364, 0x1d}, ++ {0x33b6, 0x07}, ++ {0x33b7, 0x07}, ++ {0x33b8, 0x10}, ++ {0x33b9, 0x10}, ++ {0x33ba, 0x10}, ++ {0x33bb, 0x07}, ++ {0x33bc, 0x07}, ++ {0x33bd, 0x20}, ++ {0x33be, 0x20}, ++ {0x33bf, 0x20}, ++ {0x360f, 0x05}, ++ {0x367a, 0x40}, ++ {0x367b, 0x40}, ++ {0x3671, 0xf6}, ++ {0x3672, 0x16}, ++ {0x3673, 0x16}, ++ {0x366e, 0x04}, ++ {0x3670, 0x4a}, ++ {0x367c, 0x40}, ++ {0x367d, 0x58}, ++ {0x3674, 0xc8}, ++ {0x3675, 0x54}, ++ {0x3676, 0x18}, ++ {0x367e, 0x40}, ++ {0x367f, 0x58}, ++ {0x3677, 0x22}, ++ {0x3678, 0x33}, ++ {0x3679, 0x44}, ++ {0x36a0, 0x58}, ++ {0x36a1, 0x78}, ++ {0x3696, 0x83}, ++ {0x3697, 0x87}, ++ {0x3698, 0x9f}, ++ {0x3637, 0x17}, ++ {0x331e, 0x11}, ++ {0x331f, 0x21}, ++ {0x3303, 0x1c}, ++ {0x3309, 0x3c}, ++ {0x330a, 0x00}, ++ {0x330b, 0xc8}, ++ {0x3306, 0x68}, ++ {0x3200, 0x00}, ++ {0x3201, 0x04}, ++ {0x3202, 0x00}, ++ {0x3203, 0x04}, ++ {0x3204, 0x07}, ++ {0x3205, 0x8b}, ++ {0x3206, 0x04}, ++ {0x3207, 0x43}, ++ {0x3208, 0x07}, ++ {0x3209, 0x80}, ++ {0x320a, 0x04}, ++ {0x320b, 0x38}, ++ {0x3211, 0x04}, ++ {0x3213, 0x04}, ++ {0x3380, 0x1b}, ++ {0x3341, 0x07}, ++ {0x3343, 0x03}, ++ {0x3e25, 0x03}, ++ {0x3e26, 0x40}, ++ {0x3e00, 0x00}, ++ {0x3e01, 0x95}, ++ {0x3e02, 0xa0}, ++ {0x3e03, 0x0b}, ++ {0x3e06, 0x00}, ++ {0x3e07, 0x80}, ++ {0x3e08, 0x03}, ++ {0x3e09, 0x40}, ++ {0x3905, 0xd8}, ++ {0x36e9, 0x23}, ++ {0x36f9, 0x05}, ++ {0x0100, 0x01}, ++ {SC2310_REG_DELAY, 10}, ++ {SC2310_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++ ++ ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list sc2310_stream_on_dvp[] = { ++ {0x0100, 0x01}, ++ {SC2310_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc2310_stream_off_dvp[] = { ++ {0x0100, 0x00}, ++ {SC2310_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc2310_stream_on_mipi[] = { ++ {0x0100,0x01}, ++ {SC2310_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc2310_stream_off_mipi[] = { ++ {0x0100, 0x00}, ++ {SC2310_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int sc2310_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct sc2310_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ ++ int ret = 0; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int sc2310_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct sc2310_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++#if 0 ++static int sc2310_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != SC2310_REG_END) { ++ if (vals->reg_num == SC2310_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc2310_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++#endif ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int sc2310_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != SC2310_REG_END) { ++ if (vals->reg_num == SC2310_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc2310_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int sc2310_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc2310_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int sc2310_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc2310_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int sc2310_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc2310_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = sc2310_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int sc2310_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ret = sc2310_read(sd, 0x3107, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC2310_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = sc2310_read(sd, 0x3108, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC2310_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++static struct sc2310_win_size sc2310_win_sizes[] = { ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 15 << 16 | 1, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 400, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW12, ++ .sensor_info.mipi_cfg.del_start = 1, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_WDR_2_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW12, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc2310_init_regs_1920_1080_15fps_mipi, ++ },//[0] ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 25 << 16 | 1, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 400, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW12, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW12, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc2310_init_regs_1920_1080_25fps_mipi, ++ },//[1] ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 25 << 16 | 1, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 400, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW12, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW12, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc2310_init_regs_1920_1080_15fps_mipi_dol, ++ },//[2] ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 25 << 16 | 1, ++ .sensor_info.wdr_en = 0, ++ .sensor_info.mipi_cfg.clk = 400, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_mode = SENSOR_MIPI_OTHER_MODE, ++ .sensor_info.mipi_cfg.mipi_vcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_hcomp_en = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start1y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start2y = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start3y = 0, ++ .sensor_info.mipi_cfg.hcrop_diff_en = 0, ++ .sensor_info.mipi_cfg.line_sync_mode = 0, ++ .sensor_info.mipi_cfg.work_start_flag = 0, ++ .sensor_info.mipi_cfg.data_type_en = 0, ++ .sensor_info.mipi_cfg.data_type_value = RAW12, ++ .sensor_info.mipi_cfg.del_start = 0, ++ .sensor_info.mipi_cfg.sensor_frame_mode = TX_SENSOR_DEFAULT_FRAME_MODE, ++ .sensor_info.mipi_cfg.sensor_fid_mode = 0, ++ .sensor_info.mipi_cfg.sensor_mode = TX_SENSOR_DEFAULT_MODE, ++ .sensor_info.mipi_cfg.sensor_csi_fmt = TX_SENSOR_RAW12, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc2310_init_regs_1920_1080_25fps_mipi_dol, ++ },//[3] ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 25 << 16 | 1, ++ .sensor_info.wdr_en = 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc2310_init_regs_1920_1080_25fps_dvp, ++ },//[4] ++}; ++ ++static int sc2310_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int sc2310_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc2310_format_struct *ovfmt; ++ struct sc2310_win_size *wsize; ++ struct sc2310_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int sc2310_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc2310_info *info = to_state(sd); ++ struct sc2310_win_size *wsize = info->win; ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = wsize->width; ++ fmt->height = wsize->height; ++ fmt->code = wsize->mbus_code; ++ fmt->colorspace = wsize->colorspace; ++ *(unsigned int *)fmt->reserved = &wsize->sensor_info; ++ ++ printk("----%s, %d, width: %d, height: %d, code: %x\n", ++ __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int sc2310_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc2310_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc2310_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc2310_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int sc2310_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int sc2310_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc2310_again_lut); i++) { ++ lut = &sc2310_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc2310_again_lut); i++) { ++ lut = &sc2310_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++ ++static int sc2310_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ struct sc2310_info *info = to_state(sd); ++ unsigned char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ return ret; ++} ++ ++static int sc2310_g_again_short(struct v4l2_subdev *sd, __s32 *value) ++{ ++ struct sc2310_info *info = to_state(sd); ++ unsigned char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int sc2310_s_again(struct v4l2_subdev *sd, int again) ++{ ++ struct sc2310_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ if(again < info->again->minimum || again > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(again); ++ } ++ ++ ret = sc2310_write(sd, 0x3e09, (unsigned char)(reg_value & 0xff)); ++ ret += sc2310_write(sd, 0x3e08, (unsigned char)(reg_value >> 8 & 0x3f)); ++ ++ return ret; ++} ++ ++static int sc2310_s_again_short(struct v4l2_subdev *sd, int again) ++{ ++ struct sc2310_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ if(again < info->again->minimum || again > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(again); ++ } ++ ++ ret = sc2310_write(sd, 0x3e13, (unsigned char)(reg_value & 0xff)); ++ ret += sc2310_write(sd, 0x3e12, (unsigned char)(reg_value >> 8 & 0x3f)); ++ ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int sc2310_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc2310_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct sc2310_info *info = to_state(sd); ++ int ret = 0; ++ unsigned int expo = 0; ++#ifdef SC2310_WDR_EN ++ expo = value*4; ++ ret += sc2310_write(sd, 0x3e00, (unsigned char)((expo >> 12) & 0x0f)); ++ ret += sc2310_write(sd, 0x3e01, (unsigned char)((expo >> 4) & 0xff)); ++ ret += sc2310_write(sd, 0x3e02, (unsigned char)((expo & 0x0f) << 4)); ++ if (value < 0x50) { ++ ret += sc2310_write(sd, 0x3812, 0x00); ++ ret += sc2310_write(sd, 0x3314, 0x14); ++ ret += sc2310_write(sd, 0x3812, 0x30); ++ } else if(value > 0xa0){ ++ ret += sc2310_write(sd, 0x3812, 0x00); ++ ret += sc2310_write(sd, 0x3314, 0x04); ++ ret += sc2310_write(sd, 0x3812, 0x30); ++ } ++#else ++ expo = value*2; ++ ret += sc2310_write(sd, 0x3e00, (unsigned char)((expo >> 12) & 0x0f)); ++ ret += sc2310_write(sd, 0x3e01, (unsigned char)((expo >> 4) & 0xff)); ++ ret += sc2310_write(sd, 0x3e02, (unsigned char)((expo & 0x0f) << 4)); ++ if (value < 0x50) { ++ ret += sc2310_write(sd, 0x3812, 0x00); ++ ret += sc2310_write(sd, 0x3314, 0x14); ++ ret += sc2310_write(sd, 0x3812, 0x30); ++ } else if(value > 0xa0){ ++ ret += sc2310_write(sd, 0x3812, 0x00); ++ ret += sc2310_write(sd, 0x3314, 0x04); ++ ret += sc2310_write(sd, 0x3812, 0x30); ++ } ++#endif ++ ++ return ret; ++} ++ ++static int sc2310_s_exp_short(struct v4l2_subdev *sd, int value) ++{ ++ struct sc2310_info *info = to_state(sd); ++ int ret = 0; ++ unsigned int expo = 0; ++ ret += sc2310_write(sd, 0x3e04, (unsigned char)((expo >> 4) & 0xff)); ++ ret += sc2310_write(sd, 0x3e05, (unsigned char)((expo & 0x0f) << 4)); ++ if (value < 0x50) { ++ ret += sc2310_write(sd, 0x3812, 0x00); ++ ret += sc2310_write(sd, 0x3314, 0x14); ++ ret += sc2310_write(sd, 0x3812, 0x30); ++ } ++ else if(value > 0xa0){ ++ ret += sc2310_write(sd, 0x3812, 0x00); ++ ret += sc2310_write(sd, 0x3314, 0x04); ++ ret += sc2310_write(sd, 0x3812, 0x30); ++ } ++ ++ return ret; ++} ++ ++static int sc2310_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc2310_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return sc2310_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc2310_g_again(sd, &info->again->val); ++ case V4L2_CID_USER_ANALOG_GAIN_SHORT: ++ return sc2310_g_again_short(sd, &info->again_short->val); ++ } ++ return -EINVAL; ++} ++ ++static int sc2310_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc2310_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return sc2310_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return sc2310_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return sc2310_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return sc2310_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* sc2310_s_gain turns off auto gain */ ++ return sc2310_s_gain(sd, info->gain->val); ++ } ++ return sc2310_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return sc2310_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc2310_s_again(sd, ctrl->val); ++ case V4L2_CID_USER_ANALOG_GAIN_SHORT: ++ return sc2310_s_again_short(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return sc2310_s_exp(sd, ctrl->val); ++ case V4L2_CID_USER_EXPOSURE_SHORT: ++ return sc2310_s_exp_short(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops sc2310_ctrl_ops = { ++ .s_ctrl = sc2310_s_ctrl, ++ .g_volatile_ctrl = sc2310_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int sc2310_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = sc2310_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 2; ++ return ret; ++} ++ ++static int sc2310_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ sc2310_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int sc2310_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct sc2310_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ sc2310_power_init_seq(info); ++ sc2310_init(sd, 1); ++ ret = sc2310_write_array(sd, sc2310_stream_on_mipi); ++ printk("--------------------->>>>>sc2310 stream on\n"); ++ ++ } ++ else { ++ ret = sc2310_write_array(sd, sc2310_stream_off_mipi); ++ printk("--------------------->>>>>>>>sc2310 stream off\n"); ++ } ++ return ret; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops sc2310_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = sc2310_g_register, ++ .s_register = sc2310_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops sc2310_video_ops = { ++ .s_stream = sc2310_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops sc2310_pad_ops = { ++ //.enum_frame_interval = sc2310_enum_frame_interval, ++ //.num_frame_size = sc2310_enum_frame_size, ++ //.enum_mbus_code = sc2310_enum_mbus_code, ++ .set_fmt = sc2310_set_fmt, ++ .get_fmt = sc2310_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops sc2310_ops = { ++ .core = &sc2310_core_ops, ++ .video = &sc2310_video_ops, ++ .pad = &sc2310_pad_ops, ++}; ++ ++void sc2310_power_init_seq(struct sc2310_info *info) ++{ ++ *(volatile unsigned int*)0xb0010100 = 0x1; //set gpio power domain 1.8v ++ gpio_direction_output(4,0); ++ udelay(50); ++ if(info->pwen.pin == 3){ ++ gpio_direction_output(info->pwen.pin,info->pwen.active_level); ++ udelay(50); ++ } ++ gpio_direction_output(info->pwen.pin,info->pwen.active_level); ++ udelay(50); ++ ++ gpio_direction_output(info->reset.pin,!info->reset.active_level); ++ msleep(40); ++ gpio_direction_output(info->reset.pin,info->reset.active_level); ++ msleep(40); ++ gpio_direction_output(info->reset.pin,!info->reset.active_level); ++ msleep(40); ++ ++ gpio_direction_output(info->pwdn.pin,info->pwdn.active_level); ++ msleep(10); ++ gpio_direction_output(info->pwdn.pin,!info->pwdn.active_level); ++ msleep(10); ++ gpio_direction_output(info->pwdn.pin,info->pwdn.active_level); ++ msleep(10); ++} ++/* ----------------------------------------------------------------------- */ ++ ++static int sc2310_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct sc2310_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned long rate; ++ struct v4l2_ctrl_config cfg = {0}; ++ int mclk_index = -1; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwen-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwen.pin = gpio; ++ info->pwen.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwdn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwdn.pin = gpio; ++ info->pwdn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ sc2310_power_init_seq(info); ++ v4l2_i2c_subdev_init(sd, client, &sc2310_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++#if 1 ++ ++ char id_div[9]; ++ char id_mux[9]; ++ printk("%s:%d\n", __func__, __LINE__); ++ of_property_read_u32(client->dev.of_node, "ingenic,mclk", &mclk_index); ++ if(mclk_index == 0) { ++ memcpy(id_div, "div_cim0", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim0", sizeof(id_mux)); ++ } else if(mclk_index == 1) { ++ memcpy(id_div, "div_cim1", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim1", sizeof(id_mux)); ++ } else if(mclk_index == 2) { ++ memcpy(id_div, "div_cim2", sizeof(id_div)); ++ memcpy(id_mux, "mux_cim2", sizeof(id_mux)); ++ } else ++ printk("Unkonwn mclk index\n"); ++ ++ ++ info->clk = v4l2_clk_get(&client->dev, id_div); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++#endif ++ ++ ++ //sc2310_reset(sd, 1); ++#if 1 ++ /* Make sure it's an sc2310 */ ++ ret = sc2310_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an sc2310 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ /*IRCUT ctl 0:off 1:on*/ ++ //sc2310_ircut(sd, 0); ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &sc2310_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &sc2310_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &sc2310_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &sc2310_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &sc2310_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &sc2310_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 356010, 1, 10000); ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &sc2310_ctrl_ops, ++ V4L2_CID_EXPOSURE, 2, 0x5a0 - 3, 1, 1000); ++ ++#if 1 ++ cfg.ops = &sc2310_ctrl_ops; ++ cfg.id = V4L2_CID_USER_EXPOSURE_SHORT; ++ cfg.name = "expo short"; ++ cfg.type = V4L2_CTRL_TYPE_INTEGER; ++ cfg.min = 5; ++ cfg.max = 0x5a0 - 3; ++ cfg.step = 1; ++ cfg.def = 1000; ++ info->exposure_short = v4l2_ctrl_new_custom(&info->hdl, &cfg, NULL); ++ ++ memset(&cfg, 0, sizeof(cfg)); ++ cfg.ops = &sc2310_ctrl_ops; ++ cfg.id = V4L2_CID_USER_ANALOG_GAIN_SHORT; ++ cfg.name = "analog gain short"; ++ cfg.type = V4L2_CTRL_TYPE_INTEGER; ++ cfg.min = 0; ++ cfg.max = 356010; ++ cfg.step = 1; ++ cfg.def = 10000; ++ info->again_short = v4l2_ctrl_new_custom(&info->hdl, &cfg, NULL); ++#endif ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &sc2310_win_sizes[1]; ++ ++ sc2310_init(sd, 1); ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "sc2310 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int sc2310_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct sc2310_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id sc2310_id[] = { ++ { "sc2310", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, sc2310_id); ++ ++static const struct of_device_id sc2310_of_match[] = { ++ {.compatible = "smartsens,sc2310", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sc2310_of_match); ++ ++ ++static struct i2c_driver sc2310_driver = { ++ .driver = { ++ .name = "sc2310", ++ .of_match_table = of_match_ptr(sc2310_of_match), ++ }, ++ .probe = sc2310_probe, ++ .remove = sc2310_remove, ++ .id_table = sc2310_id, ++}; ++ ++module_i2c_driver(sc2310_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for SmartSens sc2310 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/Kconfig b/module_drivers/drivers/media/i2c/ingenic-isp/Kconfig +new file mode 100644 +index 000000000..50509b160 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/Kconfig +@@ -0,0 +1,92 @@ ++comment "ingenic-isp camera sensor drivers" ++ ++ ++config INGENIC_ISP_CAMERA_OV4689 ++ tristate "ov4689 camera support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the OmniVision OV4689 sensor ++ ++config INGENIC_ISP_CAMERA_SC2232H ++ tristate "sc2232h camera support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the OmniVision sc2232h sensor ++ ++config INGENIC_ISP_CAMERA_OV2735B ++ tristate "ov2735 camera DVP interface support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the OmniVision OV2735 sensor DVP interface ++ ++config INGENIC_ISP_CAMERA_OV2735A ++ tristate "ov2735 camera MIPI interface support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the OmniVision OV2735 sensor MIPI interface ++ ++config INGENIC_ISP_CAMERA_GC1054 ++ tristate "gc1054 camera MIPI interface support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the Galaxyc gc1054 sensor MIPI interface ++ ++config INGENIC_ISP_CAMERA_AR0144 ++ tristate "ar0144 camera support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the Onsemi ar0144 sensor ++ ++config INGENIC_ISP_CAMERA_AR0234 ++ tristate "ar0234 camera support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the Onsemi ar0234 sensor ++ ++config INGENIC_ISP_CAMERA_OV7251 ++ tristate "ov7251 camera MIPI interface support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the OmniVision OV7251 sensor MIPI interface ++ ++config INGENIC_ISP_CAMERA_SC031GS ++ tristate "sc031gs camera MIPI interface support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the SmartSens sc031gs sensor MIPI interface ++ ++config INGENIC_ISP_CAMERA_OV6710 ++ tristate "ov6710 camera MIPI interface support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the OmniVision OV6710 sensor MIPI interface ++ ++config INGENIC_ISP_CAMERA_CISADC ++ tristate "CIS ADC Simulator" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for CIS ADC ++ ++config INGENIC_ISP_CAMERA_GC2093 ++ tristate "gc2093 camera MIPI interface support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the OmniVision GC2093 sensor MIPI interface ++ ++config INGENIC_ISP_CAMERA_GM8914_GM8913_GC2093 ++ tristate "GM8914 GM8913 gc2093 camera support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for the zhenxin gm8914/gm8913 gc2093 sensor ++ ++config INGENIC_ISP_CAMERA_IMX335 ++ tristate "IMX335 camera MIPI interface support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for IMX335 sensor MIPI interface ++ ++config INGENIC_ISP_CAMERA_SC230AI ++ tristate "SC230AI camera MIPI interface support" ++ depends on VIDEO_INGENIC_ISP && I2C ++ help ++ This is a ingenic-isp camera driver for SC230AI sensor MIPI interface +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/Makefile b/module_drivers/drivers/media/i2c/ingenic-isp/Makefile +new file mode 100644 +index 000000000..edf286b57 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/Makefile +@@ -0,0 +1,17 @@ ++obj-$(CONFIG_INGENIC_ISP_CAMERA_OV4689) += ov4689.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_SC2232H) += sc2232h.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_OV2735B) += ov2735b.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_OV2735A) += ov2735a.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_GC1054) += gc1054.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_AR0144) += ar0144.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_AR0234) += ar0234.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_OV7251) += ov7251.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_SC031GS) += sc031gs.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_OV6710) += ov6710.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_CISADC) += cisadc.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_GC2093) += gc2093.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_GM8914_GM8913_GC2093) += gm8914_gm8913_gc2093.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_IMX335) += imx335.o ++obj-$(CONFIG_INGENIC_ISP_CAMERA_SC230AI) += sc230ai.o ++ ++ccflags-y += -I$(srctree)/module_drivers/drivers/media/platform/ingenic-isp/ +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/ar0144.c b/module_drivers/drivers/media/i2c/ingenic-isp/ar0144.c +new file mode 100644 +index 000000000..4294895bc +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/ar0144.c +@@ -0,0 +1,998 @@ ++/* ++ * A V4L2 driver for OmniVision AR0144 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define AR0144_CHIP_ID_H (0x03) ++#define AR0144_CHIP_ID_L (0x56) ++#define AR0144_CHIP_ID (0x0356) ++#define AR0144_CHIP_ID_REG (0x3000) ++ ++#define AR0144_REG_END 0xffff ++#define AR0144_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ar0144_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ar0144_gpio { ++ int pin; ++ int active_level; ++}; ++ ++ ++struct ar0144_supply{ ++ struct regulator *pwen; ++ struct regulator *avdd; ++ struct regulator *dvdd; ++ struct regulator *dovdd; ++}; ++ ++struct ar0144_info { ++ struct ar0144_supply supply; ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ar0144_win_size *win; ++ ++ struct ar0144_gpio reset; ++ struct ar0144_gpio expo; ++ struct ar0144_gpio oe; ++ struct ar0144_gpio pwen; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut ar0144_again_lut[] = { ++ { 0x0, 0 }, ++ { 0x1, 2794 }, ++ { 0x2, 6397 }, ++ { 0x3, 9011 }, ++ { 0x4, 12388 }, ++ { 0x5, 16447 }, ++ { 0x6, 19572 }, ++ { 0x7, 23340 }, ++ { 0x8, 26963 }, ++ { 0x9, 31135 }, ++ { 0xa, 35780 }, ++ { 0xb, 39588 }, ++ { 0xc, 44438 }, ++ { 0xd, 49051 }, ++ { 0xe, 54517 }, ++ { 0xf, 59685 }, ++ { 0x10, 65536 }, ++ { 0x12, 71490 }, ++ { 0x14, 78338 }, ++ { 0x16, 85108 }, ++ { 0x18, 92854 }, ++ { 0x1a, 100992 }, ++ { 0x1c, 109974 }, ++ { 0x1e, 120053 }, ++ { 0x20, 131072 }, ++ { 0x22, 137247 }, ++ { 0x24, 143667 }, ++ { 0x26, 150644 }, ++ { 0x28, 158212 }, ++ { 0x2a, 166528 }, ++ { 0x2c, 175510 }, ++ { 0x2e, 185457 }, ++ { 0x30, 196608 }, ++ { 0x32, 202783 }, ++ { 0x34, 209203 }, ++ { 0x36, 216276 }, ++ { 0x38, 223748 }, ++ { 0x3a, 232064 }, ++ { 0x3c, 241046 }, ++ { 0x3e, 250993 }, ++ { 0x40, 262144 }, ++}; ++ ++static inline struct ar0144_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ar0144_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ar0144_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned short value; ++}; ++ ++static struct regval_list ar0144_init_regs_720p_60fps_mipi[] = { ++ //mipibps 444 ++ //pclk 74.00 ++ //hts:0x5D0 VTS 0x338 ++ //again default 0x3060 = 0x0010 ++ //expo 0x3012 = 0x01F3 ++ //[ar0144_720P_60FPS] ++// { AR0144_REG_DELAY, 200}, ++ { 0x301A, 0x00D9 }, // RESET_REGISTER ++ { AR0144_REG_DELAY, 200}, ++ { 0x301A, 0x3058 }, // RESET_REGISTER ++ { AR0144_REG_DELAY, 100}, ++ { 0x3F4C, 0x003F }, // PIX_DEF_1D_DDC_LO_DEF ++ { 0x3F4E, 0x0018 }, // PIX_DEF_1D_DDC_HI_DEF ++ { 0x3F50, 0x17DF }, // PIX_DEF_1D_DDC_EDGE ++ { 0x30B0, 0x0028 }, // DIGITAL_TEST ++ { AR0144_REG_DELAY, 200}, ++ { 0x3ED6, 0x3CB5 }, // DAC_LD_10_11 ++ { 0x3ED8, 0x8765 }, // DAC_LD_12_13 ++ { 0x3EDA, 0x8888 }, // DAC_LD_14_15 ++ { 0x3EDC, 0x97FF }, // DAC_LD_16_17 ++ { 0x3EF8, 0x6522 }, // DAC_LD_44_45 ++ { 0x3EFA, 0x2222 }, // DAC_LD_46_47 ++ { 0x3EFC, 0x6666 }, // DAC_LD_48_49 ++ { 0x3F00, 0xAA05 }, // DAC_LD_52_53 ++ { 0x3EE2, 0x180E }, // DAC_LD_22_23 ++ { 0x3EE4, 0x0808 }, // DAC_LD_24_25 ++ { 0x3EEA, 0x2A09 }, // DAC_LD_30_31 ++ { 0x3060, 0x0010 }, // ANALOG_GAIN ++ { 0x30FE, 0x00A8 }, // NOISE_PEDESTAL ++ { 0x3092, 0x00CF }, // ROW_NOISE_CONTROL ++ { 0x3268, 0x0030 }, // SEQUENCER_CONTROL ++ { 0x3786, 0x0006 }, // DIGITAL_CTRL_1 ++ { 0x3F4A, 0x0F70 }, // DELTA_DK_PIX_THRES ++ { 0x306E, 0x4810 }, // DATAPATH_SELECT ++ { 0x3064, 0x1802 }, // SMIA_TEST ++ { 0x3EF6, 0x804D }, // DAC_LD_42_43 ++ { 0x3180, 0xC08F }, // DELTA_DK_CONTROL ++ { 0x30BA, 0x7623 }, // DIGITAL_CTRL ++ { 0x3176, 0x0480 }, // DELTA_DK_ADJUST_GREENR ++ { 0x3178, 0x0480 }, // DELTA_DK_ADJUST_RED ++ { 0x317A, 0x0480 }, // DELTA_DK_ADJUST_BLUE ++ { 0x317C, 0x0480 }, // DELTA_DK_ADJUST_GREENB ++ { 0x302A, 0x0006 }, // VT_PIX_CLK_DIV ++ { 0x302C, 0x0001 }, // VT_SYS_CLK_DIV ++ { 0x302E, 0x0004 }, // PRE_PLL_CLK_DIV ++ { 0x3030, 0x004A }, // PLL_MULTIPLIER ++ { 0x3036, 0x000C }, // OP_PIX_CLK_DIV ++ { 0x3038, 0x0001 }, // OP_SYS_CLK_DIV ++ { 0x30B0, 0x0028 }, // DIGITAL_TEST ++ { AR0144_REG_DELAY, 100}, ++ { 0x31AE, 0x0202 }, // SERIAL_FORMAT ++ { 0x31AC, 0x0C0C }, // DATA_FORMAT_BITS ++ { 0x31B0, 0x0042 }, // FRAME_PREAMBLE ++ { 0x31B2, 0x002E }, // LINE_PREAMBLE ++ { 0x31B4, 0x2633 }, // MIPI_TIMING_0 ++ { 0x31B6, 0x210E }, // MIPI_TIMING_1 ++ { 0x31B8, 0x20C7 }, // MIPI_TIMING_2 ++#if 0 ++ { 0x31BA, 0x0105 }, // MIPI_TIMING_3 ++ { 0x31BC, 0x0004 }, // MIPI_TIMING_4 ++#else ++ { 0x31BA, 0x01a5 }, // MIPI_TIMING_3 ++ { 0x31BC, 0x8004 }, // MIPI_TIMING_4 ++#endif ++ { 0x3002, 0x0028 }, // Y_ADDR_START ++ { 0x3004, 0x0004 }, // X_ADDR_START ++ { 0x3006, 0x02F8 }, // Y_ADDR_END ++ { 0x3008, 0x0503 }, // X_ADDR_END ++ { 0x300A, 0x0338 }, // FRAME_LENGTH_LINES ++ { 0x300C, 0x05D0 }, // LINE_LENGTH_PCK ++// { 0x3012, 0x0064 }, // COARSE_INTEGRATION_TIME ++ { 0x3012, 0x01F3 }, // COARSE_INTEGRATION_TIME ++ { 0x30A2, 0x0001 }, // X_ODD_INC ++ { 0x30A6, 0x0001 }, // Y_ODD_INC ++ { 0x3040, 0x0000 }, // READ_MODE ++ { 0x3064, 0x1882 }, // SMIA_TEST ++ { 0x3064, 0x1802 }, // SMIA_TEST ++ { 0x3028, 0x0010 }, // ROW_SPEED ++// { 0x301A, 0x005C }, // RESET_REGISTER stream_on ++ {AR0144_REG_END, 0x00},/* END MARKER */ ++}; ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list ar0144_stream_on[] = { ++// {0x301A, 0x19CC}, ++ {0x301A, 0x005C}, ++ {AR0144_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ar0144_stream_off[] = { ++// {0x301A, 0x19C8}, ++ {0x301A, 0x0058}, ++ {AR0144_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int ar0144_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct ar0144_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 2, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ar0144_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned short value) ++{ ++ struct ar0144_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[4] = {reg >> 8, reg & 0xff, value >> 8, value & 0xff}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 4, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ar0144_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val[2]; ++ uint16_t value; ++ while (vals->reg_num != AR0144_REG_END) { ++ if (vals->reg_num == AR0144_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ar0144_read(sd, vals->reg_num, val); ++ if (ret < 0) ++ return ret; ++ } ++ vals->value=(val[0]<<8)|val[1]; ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int ar0144_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != AR0144_REG_END) { ++ if (vals->reg_num == AR0144_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ar0144_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ar0144_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ar0144_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(20); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(20); ++ } ++ return 0; ++} ++ ++static int ar0144_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ar0144_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ar0144_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int ar0144_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v[2] = {0}; ++ int ret; ++ ret = ar0144_read(sd, 0x3000, v); ++ ++ if (ret < 0) ++ return ret; ++ ++ if (v[0] != AR0144_CHIP_ID_H) ++ return -ENODEV; ++ ++ if (v[1] != AR0144_CHIP_ID_L) ++ return -ENODEV; ++ ++ return 0; ++} ++ ++ ++static struct ar0144_win_size ar0144_win_sizes[] = { ++ { ++ .sensor_info.mipi_cfg.twidth = 1280, ++ .sensor_info.mipi_cfg.theight = 720, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 60 << 16 | 1, ++ ++ .width = 1280, ++ .height = 720, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ar0144_init_regs_720p_60fps_mipi, ++ }, ++}; ++ ++static int ar0144_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_AR0144_FMTS) ++ return -EINVAL; ++ ++ code->code = ar0144_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int ar0144_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ar0144_format_struct *ovfmt; ++ struct ar0144_win_size *wsize; ++ struct ar0144_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ar0144_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ar0144_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ar0144_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ar0144_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ar0144_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ar0144_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ar0144_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ar0144_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ar0144_again_lut); i++) { ++ lut = &ar0144_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ar0144_again_lut); i++) { ++ lut = &ar0144_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ar0144_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ struct ar0144_info *info = to_state(sd); ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret = ar0144_read(sd, 0x3509, ®_val); ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ar0144_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct ar0144_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ int i; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += ar0144_write(sd, 0x3060, reg_value); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ar0144_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ar0144_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct ar0144_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ar0144_write(sd, 0x3012, value); ++ ++ return ret; ++} ++ ++static int ar0144_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ar0144_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ar0144_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ar0144_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ar0144_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ar0144_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ar0144_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ar0144_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ar0144_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ar0144_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ar0144_s_gain turns off auto gain */ ++ return ar0144_s_gain(sd, info->gain->val); ++ } ++ return ar0144_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ar0144_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ar0144_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ar0144_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ar0144_ctrl_ops = { ++ .s_ctrl = ar0144_s_ctrl, ++ .g_volatile_ctrl = ar0144_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ar0144_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ar0144_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ar0144_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ar0144_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int ar0144_power_t(struct v4l2_subdev *sd, int on) ++{ ++ struct ar0144_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ info->supply.pwen = devm_regulator_get_optional(&client->dev, "pwen"); ++ if (IS_ERR(info->supply.pwen)){ ++ if ((PTR_ERR(info->supply.pwen) == -EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ printk("No ar0144 vdd regulator found\n"); ++ } ++ ++ if (!IS_ERR(info->supply.pwen)){ ++ if(on){ ++ ret = regulator_enable(info->supply.pwen); ++ if (ret) ++ dev_err(&client->dev, "ar0144 pwen supply disable failed\n"); ++ }else{ ++ ret = regulator_disable(info->supply.pwen); ++ if (ret) ++ dev_err(&client->dev, "ar0144 pwen supply disable failed\n"); ++ } ++ }else{ ++ dev_err(&client->dev, "ar0144 vdd supply IS_ERR failed\n"); ++ } ++ ++ return ret; ++} ++ ++int ar0144_power(struct v4l2_subdev *sd, int on) ++{ ++ struct ar0144_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ /*double sensor,eg halley5_camera v1.0*/ ++ ar0144_power_t(sd,on); ++ ++ info->supply.avdd = devm_regulator_get_optional(&client->dev, "avdd"); ++ info->supply.dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); ++ info->supply.dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); ++ ++ if (IS_ERR(info->supply.avdd)||IS_ERR(info->supply.dvdd) ++ ||IS_ERR(info->supply.dovdd)) { ++ if ((PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.avdd) == -EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ printk("No ar0144 vdd regulator found\n"); ++ } ++ ++ if ((!IS_ERR(info->supply.avdd))&&(!IS_ERR(info->supply.avdd)) ++ &&(!IS_ERR(info->supply.avdd))) { ++ if(on){ ++ ret = regulator_enable(info->supply.avdd); ++ ret = regulator_enable(info->supply.dvdd); ++ ret = regulator_enable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "ar0144 vdd supply disable failed\n"); ++ } ++ else{ ++ ret = regulator_disable(info->supply.avdd); ++ ret = regulator_disable(info->supply.dvdd); ++ ret = regulator_disable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "ar0144 vdd supply disable failed\n"); ++ } ++ }else{ ++ dev_err(&client->dev, "ar0144 vdd supply IS_ERR failed\n"); ++ } ++ ++ return ret; ++} ++ ++int ar0144_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ar0144_info *info = to_state(sd); ++ int ret = 0; ++ struct regval_list *vals; ++ ++ if (enable) { ++ ret = ar0144_write_array(sd, ar0144_stream_on); ++ pr_debug("ar0144 stream on\n"); ++ } ++ else { ++ ret = ar0144_write_array(sd, ar0144_stream_off); ++ pr_debug("ar0144 stream off\n"); ++ } ++ return ret; ++} ++ ++ ++int ar0144_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct ar0144_info *info = to_state(sd); ++ if(info->win->fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ar0144_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ar0144_g_register, ++ .s_register = ar0144_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops ar0144_video_ops = { ++ .s_stream = ar0144_s_stream, ++ .g_frame_interval = ar0144_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops ar0144_pad_ops = { ++ //.enum_frame_interval = ar0144_enum_frame_interval, ++ //.num_frame_size = ar0144_enum_frame_size, ++ //.enum_mbus_code = ar0144_enum_mbus_code, ++ .set_fmt = ar0144_set_fmt, ++ .get_fmt = ar0144_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops ar0144_ops = { ++ .core = &ar0144_core_ops, ++ .video = &ar0144_video_ops, ++ .pad = &ar0144_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int ar0144_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct ar0144_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,expo-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->expo.pin = gpio; ++ info->expo.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,oe-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->oe.pin = gpio; ++ info->oe.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwen-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwen.pin = gpio; ++ info->pwen.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ ++ v4l2_i2c_subdev_init(sd, client, &ar0144_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ ar0144_power(sd, 1); ++ msleep(30); ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ ar0144_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ar0144 */ ++ ret = ar0144_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ar0144 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ /*IRCUT ctl 0:off 1:on*/ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ar0144_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ar0144_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ar0144_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ar0144_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ar0144_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ar0144_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 1, 262144, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ar0144_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &ar0144_win_sizes[0]; ++ ++ ar0144_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ar0144 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ar0144_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ar0144_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id ar0144_id[] = { ++ { "ar0144", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ar0144_id); ++ ++static const struct of_device_id ar0144_of_match[] = { ++ {.compatible = "onsemi,ar0144", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++int ar0144_suspend(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ar0144_info *info = to_state(sd); ++ int ret=0; ++ ++ ar0144_power(sd, 0); ++ v4l2_clk_disable(info->clk); ++ return 0; ++} ++ ++int ar0144_resume(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ar0144_info *info = to_state(sd); ++ int ret=0; ++ ++ ar0144_power(sd, 1); ++ v4l2_clk_enable(info->clk); ++ ar0144_reset(sd, 1); ++ ar0144_init(sd, 1); ++ return 0; ++} ++ ++const struct dev_pm_ops ar0144_pm = ++{ ++ .suspend = ar0144_suspend, ++ .resume = ar0144_resume, ++}; ++ ++ ++static struct i2c_driver ar0144_driver = { ++ .driver = { ++ .name = "ar0144", ++ .of_match_table = of_match_ptr(ar0144_of_match), ++ .pm = &ar0144_pm, ++ }, ++ .probe = ar0144_probe, ++ .remove = ar0144_remove, ++ .id_table = ar0144_id, ++}; ++ ++module_i2c_driver(ar0144_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for onsemi ar0144 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/ar0234.c b/module_drivers/drivers/media/i2c/ingenic-isp/ar0234.c +new file mode 100644 +index 000000000..d061d266e +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/ar0234.c +@@ -0,0 +1,1183 @@ ++/* ++ * A V4L2 driver for OmniVision AR0234 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define AR0234_CHIP_ID_H (0x0a) ++#define AR0234_CHIP_ID_L (0x56) ++#define AR0234_CHIP_ID (0x0356) ++#define AR0234_CHIP_ID_REG (0x3000) ++ ++#define AR0234_REG_END 0xffff ++#define AR0234_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ar0234_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ar0234_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ar0234_supply{ ++ struct regulator *pwen; ++ struct regulator *shutdown; ++}; ++ ++struct ar0234_info { ++ struct ar0234_supply supply; ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ar0234_win_size *win; ++ ++ struct ar0234_gpio reset; ++ struct ar0234_gpio expo; ++ struct ar0234_gpio oe; ++ struct ar0234_gpio pwen; ++ struct ar0234_gpio shutdown; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut ar0234_again_lut[] = { ++ { 0x0, 0 }, ++ { 0x1, 2794 }, ++ { 0x2, 6397 }, ++ { 0x3, 9011 }, ++ { 0x4, 12388 }, ++ { 0x5, 16447 }, ++ { 0x6, 19572 }, ++ { 0x7, 23340 }, ++ { 0x8, 26963 }, ++ { 0x9, 31135 }, ++ { 0xa, 35780 }, ++ { 0xb, 39588 }, ++ { 0xc, 44438 }, ++ { 0xd, 49051 }, ++ { 0xe, 54517 }, ++ { 0xf, 59685 }, ++ { 0x10, 65536 }, ++ { 0x12, 71490 }, ++ { 0x14, 78338 }, ++ { 0x16, 85108 }, ++ { 0x18, 92854 }, ++ { 0x1a, 100992 }, ++ { 0x1c, 109974 }, ++ { 0x1e, 120053 }, ++ { 0x20, 131072 }, ++ { 0x22, 137247 }, ++ { 0x24, 143667 }, ++ { 0x26, 150644 }, ++ { 0x28, 158212 }, ++ { 0x2a, 166528 }, ++ { 0x2c, 175510 }, ++ { 0x2e, 185457 }, ++ { 0x30, 196608 }, ++ { 0x32, 202783 }, ++ { 0x34, 209203 }, ++ { 0x36, 216276 }, ++ { 0x38, 223748 }, ++ { 0x3a, 232064 }, ++ { 0x3c, 241046 }, ++ { 0x3e, 250993 }, ++ { 0x40, 262144 }, ++}; ++ ++static inline struct ar0234_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ar0234_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ar0234_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned short value; ++}; ++ ++static struct regval_list ar0234_init_regs_1080p_60fps_mipi[] = { ++ /* ++ [AR0234_MIPI_2Lane_1920x1080_10bits_24MCLK_891Mbps_60fps] ++ ;load = seq ++ load = PLL_settings ++ load = Timing_settings ++ [seq] ++ */ ++ { AR0234_REG_DELAY, 200}, ++ { 0x301A, 0x00D9}, // RESET_REGISTER ++ { AR0234_REG_DELAY, 200}, ++ { 0x3F4C, 0x121F}, // PIX_DEF_1D_DDC_LO_DEF ++ { 0x3F4E, 0x121F}, // PIX_DEF_1D_DDC_HI_DEF ++ { 0x3F50, 0x0B81}, // PIX_DEF_1D_DDC_EDGE ++ { 0x31E0, 0x0003}, // PIX_DEF_ID ++ { 0x31E0, 0x0003}, // PIX_DEF_ID ++ { 0x30B0, 0x0028}, // DIGITAL_TEST ++ { AR0234_REG_DELAY, 200}, ++ { 0x3088, 0x8000}, // SEQ_CTRL_PORT ++ { 0x3086, 0xC1AE}, // SEQ_DATA_PORT ++ { 0x3086, 0x327F}, // SEQ_DATA_PORT ++ { 0x3086, 0x5780}, // SEQ_DATA_PORT ++ { 0x3086, 0x272F}, // SEQ_DATA_PORT ++ { 0x3086, 0x7416}, // SEQ_DATA_PORT ++ { 0x3086, 0x7E13}, // SEQ_DATA_PORT ++ { 0x3086, 0x8000}, // SEQ_DATA_PORT ++ { 0x3086, 0x307E}, // SEQ_DATA_PORT ++ { 0x3086, 0xFF80}, // SEQ_DATA_PORT ++ { 0x3086, 0x20C3}, // SEQ_DATA_PORT ++ { 0x3086, 0xB00E}, // SEQ_DATA_PORT ++ { 0x3086, 0x8190}, // SEQ_DATA_PORT ++ { 0x3086, 0x1643}, // SEQ_DATA_PORT ++ { 0x3086, 0x1651}, // SEQ_DATA_PORT ++ { 0x3086, 0x9D3E}, // SEQ_DATA_PORT ++ { 0x3086, 0x9545}, // SEQ_DATA_PORT ++ { 0x3086, 0x2209}, // SEQ_DATA_PORT ++ { 0x3086, 0x3781}, // SEQ_DATA_PORT ++ { 0x3086, 0x9016}, // SEQ_DATA_PORT ++ { 0x3086, 0x4316}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F90}, // SEQ_DATA_PORT ++ { 0x3086, 0x8000}, // SEQ_DATA_PORT ++ { 0x3086, 0x387F}, // SEQ_DATA_PORT ++ { 0x3086, 0x1380}, // SEQ_DATA_PORT ++ { 0x3086, 0x233B}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F93}, // SEQ_DATA_PORT ++ { 0x3086, 0x4502}, // SEQ_DATA_PORT ++ { 0x3086, 0x8000}, // SEQ_DATA_PORT ++ { 0x3086, 0x7FB0}, // SEQ_DATA_PORT ++ { 0x3086, 0x8D66}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F90}, // SEQ_DATA_PORT ++ { 0x3086, 0x8192}, // SEQ_DATA_PORT ++ { 0x3086, 0x3C16}, // SEQ_DATA_PORT ++ { 0x3086, 0x357F}, // SEQ_DATA_PORT ++ { 0x3086, 0x9345}, // SEQ_DATA_PORT ++ { 0x3086, 0x0280}, // SEQ_DATA_PORT ++ { 0x3086, 0x007F}, // SEQ_DATA_PORT ++ { 0x3086, 0xB08D}, // SEQ_DATA_PORT ++ { 0x3086, 0x667F}, // SEQ_DATA_PORT ++ { 0x3086, 0x9081}, // SEQ_DATA_PORT ++ { 0x3086, 0x8237}, // SEQ_DATA_PORT ++ { 0x3086, 0x4502}, // SEQ_DATA_PORT ++ { 0x3086, 0x3681}, // SEQ_DATA_PORT ++ { 0x3086, 0x8044}, // SEQ_DATA_PORT ++ { 0x3086, 0x1631}, // SEQ_DATA_PORT ++ { 0x3086, 0x4374}, // SEQ_DATA_PORT ++ { 0x3086, 0x1678}, // SEQ_DATA_PORT ++ { 0x3086, 0x7B7D}, // SEQ_DATA_PORT ++ { 0x3086, 0x4502}, // SEQ_DATA_PORT ++ { 0x3086, 0x450A}, // SEQ_DATA_PORT ++ { 0x3086, 0x7E12}, // SEQ_DATA_PORT ++ { 0x3086, 0x8180}, // SEQ_DATA_PORT ++ { 0x3086, 0x377F}, // SEQ_DATA_PORT ++ { 0x3086, 0x1045}, // SEQ_DATA_PORT ++ { 0x3086, 0x0A0E}, // SEQ_DATA_PORT ++ { 0x3086, 0x7FD4}, // SEQ_DATA_PORT ++ { 0x3086, 0x8024}, // SEQ_DATA_PORT ++ { 0x3086, 0x0E82}, // SEQ_DATA_PORT ++ { 0x3086, 0x9CC2}, // SEQ_DATA_PORT ++ { 0x3086, 0xAFA8}, // SEQ_DATA_PORT ++ { 0x3086, 0xAA03}, // SEQ_DATA_PORT ++ { 0x3086, 0x430D}, // SEQ_DATA_PORT ++ { 0x3086, 0x2D46}, // SEQ_DATA_PORT ++ { 0x3086, 0x4316}, // SEQ_DATA_PORT ++ { 0x3086, 0x5F16}, // SEQ_DATA_PORT ++ { 0x3086, 0x530D}, // SEQ_DATA_PORT ++ { 0x3086, 0x1660}, // SEQ_DATA_PORT ++ { 0x3086, 0x401E}, // SEQ_DATA_PORT ++ { 0x3086, 0x2904}, // SEQ_DATA_PORT ++ { 0x3086, 0x2984}, // SEQ_DATA_PORT ++ { 0x3086, 0x81E7}, // SEQ_DATA_PORT ++ { 0x3086, 0x816F}, // SEQ_DATA_PORT ++ { 0x3086, 0x1706}, // SEQ_DATA_PORT ++ { 0x3086, 0x81E7}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F81}, // SEQ_DATA_PORT ++ { 0x3086, 0x5C0D}, // SEQ_DATA_PORT ++ { 0x3086, 0x5754}, // SEQ_DATA_PORT ++ { 0x3086, 0x495F}, // SEQ_DATA_PORT ++ { 0x3086, 0x5305}, // SEQ_DATA_PORT ++ { 0x3086, 0x5307}, // SEQ_DATA_PORT ++ { 0x3086, 0x4D2B}, // SEQ_DATA_PORT ++ { 0x3086, 0xF810}, // SEQ_DATA_PORT ++ { 0x3086, 0x164C}, // SEQ_DATA_PORT ++ { 0x3086, 0x0755}, // SEQ_DATA_PORT ++ { 0x3086, 0x562B}, // SEQ_DATA_PORT ++ { 0x3086, 0xB82B}, // SEQ_DATA_PORT ++ { 0x3086, 0x984E}, // SEQ_DATA_PORT ++ { 0x3086, 0x1129}, // SEQ_DATA_PORT ++ { 0x3086, 0x9460}, // SEQ_DATA_PORT ++ { 0x3086, 0x5C09}, // SEQ_DATA_PORT ++ { 0x3086, 0x5C1B}, // SEQ_DATA_PORT ++ { 0x3086, 0x4002}, // SEQ_DATA_PORT ++ { 0x3086, 0x4500}, // SEQ_DATA_PORT ++ { 0x3086, 0x4580}, // SEQ_DATA_PORT ++ { 0x3086, 0x29B6}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F80}, // SEQ_DATA_PORT ++ { 0x3086, 0x4004}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F88}, // SEQ_DATA_PORT ++ { 0x3086, 0x4109}, // SEQ_DATA_PORT ++ { 0x3086, 0x5C0B}, // SEQ_DATA_PORT ++ { 0x3086, 0x29B2}, // SEQ_DATA_PORT ++ { 0x3086, 0x4115}, // SEQ_DATA_PORT ++ { 0x3086, 0x5C03}, // SEQ_DATA_PORT ++ { 0x3086, 0x4105}, // SEQ_DATA_PORT ++ { 0x3086, 0x5F2B}, // SEQ_DATA_PORT ++ { 0x3086, 0x902B}, // SEQ_DATA_PORT ++ { 0x3086, 0x8081}, // SEQ_DATA_PORT ++ { 0x3086, 0x6F40}, // SEQ_DATA_PORT ++ { 0x3086, 0x1041}, // SEQ_DATA_PORT ++ { 0x3086, 0x0160}, // SEQ_DATA_PORT ++ { 0x3086, 0x29A2}, // SEQ_DATA_PORT ++ { 0x3086, 0x29A3}, // SEQ_DATA_PORT ++ { 0x3086, 0x5F4D}, // SEQ_DATA_PORT ++ { 0x3086, 0x1C17}, // SEQ_DATA_PORT ++ { 0x3086, 0x0281}, // SEQ_DATA_PORT ++ { 0x3086, 0xE729}, // SEQ_DATA_PORT ++ { 0x3086, 0x8345}, // SEQ_DATA_PORT ++ { 0x3086, 0x8840}, // SEQ_DATA_PORT ++ { 0x3086, 0x0F7F}, // SEQ_DATA_PORT ++ { 0x3086, 0x8A40}, // SEQ_DATA_PORT ++ { 0x3086, 0x2345}, // SEQ_DATA_PORT ++ { 0x3086, 0x8024}, // SEQ_DATA_PORT ++ { 0x3086, 0x4008}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F88}, // SEQ_DATA_PORT ++ { 0x3086, 0x5D29}, // SEQ_DATA_PORT ++ { 0x3086, 0x9288}, // SEQ_DATA_PORT ++ { 0x3086, 0x102B}, // SEQ_DATA_PORT ++ { 0x3086, 0x0489}, // SEQ_DATA_PORT ++ { 0x3086, 0x165C}, // SEQ_DATA_PORT ++ { 0x3086, 0x4386}, // SEQ_DATA_PORT ++ { 0x3086, 0x170B}, // SEQ_DATA_PORT ++ { 0x3086, 0x5C03}, // SEQ_DATA_PORT ++ { 0x3086, 0x8A48}, // SEQ_DATA_PORT ++ { 0x3086, 0x4D4E}, // SEQ_DATA_PORT ++ { 0x3086, 0x2B80}, // SEQ_DATA_PORT ++ { 0x3086, 0x4C09}, // SEQ_DATA_PORT ++ { 0x3086, 0x4119}, // SEQ_DATA_PORT ++ { 0x3086, 0x816F}, // SEQ_DATA_PORT ++ { 0x3086, 0x4110}, // SEQ_DATA_PORT ++ { 0x3086, 0x4001}, // SEQ_DATA_PORT ++ { 0x3086, 0x6029}, // SEQ_DATA_PORT ++ { 0x3086, 0x8229}, // SEQ_DATA_PORT ++ { 0x3086, 0x8329}, // SEQ_DATA_PORT ++ { 0x3086, 0x435C}, // SEQ_DATA_PORT ++ { 0x3086, 0x055F}, // SEQ_DATA_PORT ++ { 0x3086, 0x4D1C}, // SEQ_DATA_PORT ++ { 0x3086, 0x81E7}, // SEQ_DATA_PORT ++ { 0x3086, 0x4502}, // SEQ_DATA_PORT ++ { 0x3086, 0x8180}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F80}, // SEQ_DATA_PORT ++ { 0x3086, 0x410A}, // SEQ_DATA_PORT ++ { 0x3086, 0x9144}, // SEQ_DATA_PORT ++ { 0x3086, 0x1609}, // SEQ_DATA_PORT ++ { 0x3086, 0x2FC3}, // SEQ_DATA_PORT ++ { 0x3086, 0xB130}, // SEQ_DATA_PORT ++ { 0x3086, 0xC3B1}, // SEQ_DATA_PORT ++ { 0x3086, 0x0343}, // SEQ_DATA_PORT ++ { 0x3086, 0x164A}, // SEQ_DATA_PORT ++ { 0x3086, 0x0A43}, // SEQ_DATA_PORT ++ { 0x3086, 0x160B}, // SEQ_DATA_PORT ++ { 0x3086, 0x4316}, // SEQ_DATA_PORT ++ { 0x3086, 0x8F43}, // SEQ_DATA_PORT ++ { 0x3086, 0x1690}, // SEQ_DATA_PORT ++ { 0x3086, 0x4316}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F81}, // SEQ_DATA_PORT ++ { 0x3086, 0x450A}, // SEQ_DATA_PORT ++ { 0x3086, 0x410F}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F83}, // SEQ_DATA_PORT ++ { 0x3086, 0x5D29}, // SEQ_DATA_PORT ++ { 0x3086, 0x4488}, // SEQ_DATA_PORT ++ { 0x3086, 0x102B}, // SEQ_DATA_PORT ++ { 0x3086, 0x0453}, // SEQ_DATA_PORT ++ { 0x3086, 0x0D40}, // SEQ_DATA_PORT ++ { 0x3086, 0x2345}, // SEQ_DATA_PORT ++ { 0x3086, 0x0240}, // SEQ_DATA_PORT ++ { 0x3086, 0x087F}, // SEQ_DATA_PORT ++ { 0x3086, 0x8053}, // SEQ_DATA_PORT ++ { 0x3086, 0x0D89}, // SEQ_DATA_PORT ++ { 0x3086, 0x165C}, // SEQ_DATA_PORT ++ { 0x3086, 0x4586}, // SEQ_DATA_PORT ++ { 0x3086, 0x170B}, // SEQ_DATA_PORT ++ { 0x3086, 0x5C05}, // SEQ_DATA_PORT ++ { 0x3086, 0x8A60}, // SEQ_DATA_PORT ++ { 0x3086, 0x4B91}, // SEQ_DATA_PORT ++ { 0x3086, 0x4416}, // SEQ_DATA_PORT ++ { 0x3086, 0x09C1}, // SEQ_DATA_PORT ++ { 0x3086, 0x2CA9}, // SEQ_DATA_PORT ++ { 0x3086, 0xAB30}, // SEQ_DATA_PORT ++ { 0x3086, 0x51B3}, // SEQ_DATA_PORT ++ { 0x3086, 0x3D5A}, // SEQ_DATA_PORT ++ { 0x3086, 0x7E3D}, // SEQ_DATA_PORT ++ { 0x3086, 0x7E19}, // SEQ_DATA_PORT ++ { 0x3086, 0x8000}, // SEQ_DATA_PORT ++ { 0x3086, 0x8B1F}, // SEQ_DATA_PORT ++ { 0x3086, 0x2A1F}, // SEQ_DATA_PORT ++ { 0x3086, 0x83A2}, // SEQ_DATA_PORT ++ { 0x3086, 0x7516}, // SEQ_DATA_PORT ++ { 0x3086, 0xAD33}, // SEQ_DATA_PORT ++ { 0x3086, 0x450A}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F53}, // SEQ_DATA_PORT ++ { 0x3086, 0x8023}, // SEQ_DATA_PORT ++ { 0x3086, 0x8C66}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F13}, // SEQ_DATA_PORT ++ { 0x3086, 0x8184}, // SEQ_DATA_PORT ++ { 0x3086, 0x1481}, // SEQ_DATA_PORT ++ { 0x3086, 0x8031}, // SEQ_DATA_PORT ++ { 0x3086, 0x3D64}, // SEQ_DATA_PORT ++ { 0x3086, 0x452A}, // SEQ_DATA_PORT ++ { 0x3086, 0x9451}, // SEQ_DATA_PORT ++ { 0x3086, 0x9E96}, // SEQ_DATA_PORT ++ { 0x3086, 0x3D2B}, // SEQ_DATA_PORT ++ { 0x3086, 0x3D1B}, // SEQ_DATA_PORT ++ { 0x3086, 0x529F}, // SEQ_DATA_PORT ++ { 0x3086, 0x0E3D}, // SEQ_DATA_PORT ++ { 0x3086, 0x083D}, // SEQ_DATA_PORT ++ { 0x3086, 0x167E}, // SEQ_DATA_PORT ++ { 0x3086, 0x307E}, // SEQ_DATA_PORT ++ { 0x3086, 0x1175}, // SEQ_DATA_PORT ++ { 0x3086, 0x163E}, // SEQ_DATA_PORT ++ { 0x3086, 0x970E}, // SEQ_DATA_PORT ++ { 0x3086, 0x82B2}, // SEQ_DATA_PORT ++ { 0x3086, 0x3D7F}, // SEQ_DATA_PORT ++ { 0x3086, 0xAC3E}, // SEQ_DATA_PORT ++ { 0x3086, 0x4502}, // SEQ_DATA_PORT ++ { 0x3086, 0x7E11}, // SEQ_DATA_PORT ++ { 0x3086, 0x7FD0}, // SEQ_DATA_PORT ++ { 0x3086, 0x8000}, // SEQ_DATA_PORT ++ { 0x3086, 0x8C66}, // SEQ_DATA_PORT ++ { 0x3086, 0x7F90}, // SEQ_DATA_PORT ++ { 0x3086, 0x8194}, // SEQ_DATA_PORT ++ { 0x3086, 0x3F44}, // SEQ_DATA_PORT ++ { 0x3086, 0x1681}, // SEQ_DATA_PORT ++ { 0x3086, 0x8416}, // SEQ_DATA_PORT ++ { 0x3086, 0x2C2C}, // SEQ_DATA_PORT ++ { 0x3086, 0x2C2C}, // SEQ_DATA_PORT ++ // [PLL_settings] ++ { 0x302A, 0x0005}, //VT_PIX_CLK_DIV = 5 ++ { 0x302C, 0x0001}, //VT_SYS_CLK_DIV = 1 ++ { 0x302E, 0x0007}, //PRE_PLL_CLK_DIV = 7 ++ { 0x3030, 0x0082}, //PLL_MULTIPLIER = 130 ++ { 0x3036, 0x000A}, //OP_PIX_CLK_DIV = 10 ++ { 0x3038, 0x0001}, //OP_SYS_CLK_DIV = 1 ++ // BITFIELD = 0x30B0, 0x4000, 0x0000 //DIGITAL_TEST, bits 0x4000 = 0 ++ { 0x31B0, 0x0082}, //FRAME_PREAMBLE = 130 ++ { 0x31B2, 0x005C}, //LINE_PREAMBLE = 92 ++ { 0x31B4, 0x4248}, //MIPI_TIMING_0 = 16968 ++ { 0x31B6, 0x3258}, //MIPI_TIMING_1 = 12888 ++ { 0x31B8, 0x804B}, //MIPI_TIMING_2 = 32843 ++ { 0x31BA, 0x030B}, //MIPI_TIMING_3 = 779 ++ { 0x31BC, 0x8E09}, //MIPI_TIMING_4 = 36361 ++ { 0x3354, 0x002B}, //MIPI_CNTRL = 43 ++ ++ ++ // [Timing_settings] ++ { 0x301A, 0x2058}, //RESET_REGISTER = 8280 ++ { 0x31AE, 0x0202}, //SERIAL_FORMAT = 514 ++ { 0x3002, 0x0044}, //Y_ADDR_START = 68 ++ { 0x3004, 0x0008}, //X_ADDR_START = 8 ++ { 0x3006, 0x047B}, //Y_ADDR_END = 1147 ++ { 0x3008, 0x0787}, //X_ADDR_END = 1927 ++ { 0x300A, 0x04B8}, //FRAME_LENGTH_LINES = 1208 ++ { 0x300C, 0x0264}, //LINE_LENGTH_PCK = 612 ++ { 0x3012, 0x048D}, //COARSE_INTEGRATION_TIME = 1165 ++ { 0x31AC, 0x0A0A}, //DATA_FORMAT_BITS = 2570 ++ { 0x3354, 0x002B}, //MIPI DATATYPE 10BITS ++ { 0x306E, 0x9010}, //DATAPATH_SELECT = 36880 ++ { 0x30A2, 0x0001}, //X_ODD_INC = 1 ++ { 0x30A6, 0x0001}, //Y_ODD_INC = 1 ++ { 0x3082, 0x0003}, //OPERATION_MODE_CTRL = 3 ++ { 0x3040, 0x0000}, //READ_MODE = 0 ++ { 0x31D0, 0x0000}, //COMPANDING = 0 ++// { 0x301A, 0x205C}, //RESET_REGISTER = 8284 ++ {AR0234_REG_END, 0x00},/* END MARKER */ ++}; ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list ar0234_stream_on[] = { ++// {0x301A, 0x19CC}, ++ {0x301A, 0x205C}, ++ {AR0234_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ar0234_stream_off[] = { ++// {0x301A, 0x19C8}, ++ {0x301A, 0x2058}, ++ {AR0234_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int ar0234_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct ar0234_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 2, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ar0234_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned short value) ++{ ++ struct ar0234_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[4] = {reg >> 8, reg & 0xff, value >> 8, value & 0xff}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 4, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ar0234_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val[2]; ++ uint16_t value; ++ while (vals->reg_num != AR0234_REG_END) { ++ if (vals->reg_num == AR0234_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ar0234_read(sd, vals->reg_num, val); ++ if (ret < 0) ++ return ret; ++ } ++ vals->value=(val[0]<<8)|val[1]; ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int ar0234_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != AR0234_REG_END) { ++ if (vals->reg_num == AR0234_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ar0234_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ar0234_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ar0234_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int ar0234_shutdown(struct v4l2_subdev *sd, u32 on) ++{ ++ struct ar0234_info *info = to_state(sd); ++ int ret = 0; ++ ++ if(on) ++ ret = gpio_direction_output(info->shutdown.pin, info->shutdown.active_level); ++ else ++ ret = gpio_direction_output(info->shutdown.pin, !info->shutdown.active_level); ++ return ret; ++} ++ ++static int ar0234_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ar0234_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ar0234_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int ar0234_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v[2] = {0}; ++ int ret; ++ ret = ar0234_read(sd, 0x3000, v); ++ ++ if (ret < 0) ++ return ret; ++ ++ printk("%x %x \n", v[0], v[1]); ++ if (v[0] != AR0234_CHIP_ID_H) ++ return -ENODEV; ++ ++ if (v[1] != AR0234_CHIP_ID_L) ++ return -ENODEV; ++ ++ return 0; ++} ++ ++ ++static struct ar0234_win_size ar0234_win_sizes[] = { ++ { ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 60 << 16 | 1, ++ ++ .width = 1920, ++ .height = 1080, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ar0234_init_regs_1080p_60fps_mipi, ++ }, ++}; ++ ++static int ar0234_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_AR0234_FMTS) ++ return -EINVAL; ++ ++ code->code = ar0234_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int ar0234_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ar0234_format_struct *ovfmt; ++ struct ar0234_win_size *wsize; ++ struct ar0234_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ar0234_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ar0234_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ar0234_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ar0234_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ar0234_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ar0234_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ar0234_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ar0234_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ar0234_again_lut); i++) { ++ lut = &ar0234_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ar0234_again_lut); i++) { ++ lut = &ar0234_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ar0234_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ struct ar0234_info *info = to_state(sd); ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret = ar0234_read(sd, 0x3509, ®_val); ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ar0234_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct ar0234_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ int i; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += ar0234_write(sd, 0x3060, reg_value); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ar0234_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ar0234_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct ar0234_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ar0234_write(sd, 0x3012, value); ++ ++ return ret; ++} ++ ++static int ar0234_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ar0234_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ar0234_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ar0234_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ar0234_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ar0234_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ar0234_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ar0234_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ar0234_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ar0234_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ar0234_s_gain turns off auto gain */ ++ return ar0234_s_gain(sd, info->gain->val); ++ } ++ return ar0234_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ar0234_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ar0234_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ar0234_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ar0234_ctrl_ops = { ++ .s_ctrl = ar0234_s_ctrl, ++ .g_volatile_ctrl = ar0234_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ar0234_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ar0234_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ar0234_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ar0234_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++ ++int ar0234_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct ar0234_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ info->supply.pwen = devm_regulator_get_optional(&client->dev, "pwen"); ++ info->supply.shutdown = devm_regulator_get_optional(&client->dev, "shutdown"); ++ ++ if (IS_ERR(info->supply.pwen)||IS_ERR(info->supply.shutdown)) { ++ if ((PTR_ERR(info->supply.pwen) == -EPROBE_DEFER)||(PTR_ERR(info->supply.shutdown) == -EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ printk("No ar0234 vdd regulator found\n"); ++ } ++ ++ if ((!IS_ERR(info->supply.pwen))&&(!IS_ERR(info->supply.shutdown))){ ++ if(on){ ++ ret = regulator_enable(info->supply.pwen); ++ ret = regulator_enable(info->supply.shutdown); ++ if (ret) ++ dev_err(&client->dev, "ar0234 vdd supply disable failed\n"); ++ }else{ ++ ret = regulator_disable(info->supply.pwen); ++ ret = regulator_disable(info->supply.shutdown); ++ if (ret) ++ dev_err(&client->dev, "ar0234 vdd supply disable failed\n"); ++ } ++ }else{ ++ dev_err(&client->dev, "ar0234 vdd supply IS_ERR failed\n"); ++ } ++ return ret; ++} ++ ++int ar0234_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ar0234_info *info = to_state(sd); ++ int ret = 0; ++ struct regval_list *vals; ++ ++ if (enable) { ++ ret = ar0234_write_array(sd, ar0234_stream_on); ++ pr_debug("ar0234 stream on\n"); ++ } ++ else { ++ ret = ar0234_write_array(sd, ar0234_stream_off); ++ pr_debug("ar0234 stream off\n"); ++ } ++ return ret; ++} ++ ++ ++int ar0234_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct ar0234_info *info = to_state(sd); ++ if(info->win->fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ar0234_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ar0234_g_register, ++ .s_register = ar0234_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops ar0234_video_ops = { ++ .s_stream = ar0234_s_stream, ++ .g_frame_interval = ar0234_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops ar0234_pad_ops = { ++ //.enum_frame_interval = ar0234_enum_frame_interval, ++ //.num_frame_size = ar0234_enum_frame_size, ++ //.enum_mbus_code = ar0234_enum_mbus_code, ++ .set_fmt = ar0234_set_fmt, ++ .get_fmt = ar0234_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops ar0234_ops = { ++ .core = &ar0234_core_ops, ++ .video = &ar0234_video_ops, ++ .pad = &ar0234_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int ar0234_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct ar0234_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,expo-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->expo.pin = gpio; ++ info->expo.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,oe-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->oe.pin = gpio; ++ info->oe.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwen-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwen.pin = gpio; ++ info->pwen.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,shutdown-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->shutdown.pin = gpio; ++ info->shutdown.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ ++ v4l2_i2c_subdev_init(sd, client, &ar0234_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++// ar0234_shutdown(sd, 0); ++ ar0234_s_power(sd, 1); ++ ar0234_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ar0234 */ ++ ret = ar0234_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ar0234 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ /*IRCUT ctl 0:off 1:on*/ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ar0234_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ar0234_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ar0234_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ar0234_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ar0234_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ar0234_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 1, 262144, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ar0234_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &ar0234_win_sizes[0]; ++ ar0234_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ar0234 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ar0234_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ar0234_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ ar0234_s_power(sd, 0); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id ar0234_id[] = { ++ { "ar0234", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ar0234_id); ++ ++static const struct of_device_id ar0234_of_match[] = { ++ {.compatible = "onsemi,ar0234", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++static int ar0234_suspend(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ar0234_info *info = to_state(sd); ++ int ret=0; ++ ++ ar0234_s_power(sd,0); ++ v4l2_clk_disable(info->clk); ++ return 0; ++} ++ ++static int ar0234_resume(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ar0234_info *info = to_state(sd); ++ int ret=0; ++ ++ ar0234_s_power(sd,1); ++ v4l2_clk_enable(info->clk); ++ ar0234_reset(sd, 1); ++ ar0234_init(sd, 1); ++ return 0; ++} ++ ++const struct dev_pm_ops ar0234_pm = ++{ ++ .suspend = ar0234_suspend, ++ .resume = ar0234_resume, ++}; ++ ++ ++static struct i2c_driver ar0234_driver = { ++ .driver = { ++ .name = "ar0234", ++ .of_match_table = of_match_ptr(ar0234_of_match), ++ .pm = &ar0234_pm, ++ }, ++ .probe = ar0234_probe, ++ .remove = ar0234_remove, ++ .id_table = ar0234_id, ++}; ++ ++module_i2c_driver(ar0234_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for onsemi ar0234 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/cisadc.c b/module_drivers/drivers/media/i2c/ingenic-isp/cisadc.c +new file mode 100644 +index 000000000..2591db0cb +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/cisadc.c +@@ -0,0 +1,602 @@ ++ ++#define DEBUG ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct cisadc_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct cisadc_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct cisadc_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct cisadc_win_size *win; ++ ++ struct cisadc_gpio reset; ++ struct cisadc_gpio ircutp; ++ struct cisadc_gpio ircutn; ++}; ++ ++ ++/* scanner cis 300dpi/600dpi/1200dpi */ ++static struct cisadc_win_size cisadc_win_sizes[] = { ++ /* 300dpi */ ++ { ++ .width = 5376, // 300dpi, dma 32bytes aligned ++ .height = 1, ++ .sensor_info.fps = 30 << 16 | 1, ++ /* .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, */ ++ /* .colorspace = V4L2_COLORSPACE_SRGB, */ ++ /* .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, */ ++ /* .colorspace = V4L2_COLORSPACE_DEFAULT, */ ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ }, ++ /* 600dpi */ ++ { ++ .width = 10556, // 600dpi, dma 32bytes aligned ++ .height = 1, ++ .sensor_info.fps = 30 << 16 | 1, ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ }, ++ /* 1200dpi */ ++ { ++ .width = 20920, // 1200dpi, dma 32bytes aligned ++ .height = 1, ++ .sensor_info.fps = 30 << 16 | 1, ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ }, ++ /* user set xdpi, width/height */ ++ { ++ .width = 0, // 1200dpi, dma 32bytes aligned ++ .height = 0, ++ .sensor_info.fps = 30 << 16 | 1, ++ /* .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, */ ++ /* .colorspace = V4L2_COLORSPACE_SRGB, */ ++ /* .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, */ ++ /* .colorspace = V4L2_COLORSPACE_DEFAULT, */ ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ }, ++}; ++ ++static inline struct cisadc_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct cisadc_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct cisadc_info, hdl)->sd; ++} ++ ++#if 0 ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int cisadc_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct cisadc_info *info = to_state(sd); ++#if 0 ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++#endif ++ return 0; ++} ++ ++static int cisadc_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct cisadc_info *info = to_state(sd); ++#if 0 ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++#endif ++ return 0; ++} ++ ++static int cisadc_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct cisadc_info *info = to_state(sd); ++ int ret = 0; ++ ++ //ret = cisadc_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int cisadc_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x return 0;\n", __func__, __LINE__, ret,v); ++ ++ return 0; ++} ++#endif ++ ++static int cisadc_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_CISADC_FMTS) ++ return -EINVAL; ++ ++ code->code = cisadc_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++static const struct cisadc_win_size *cisadc_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size, win_size; ++ default_size = 0; ++ win_size = ARRAY_SIZE(cisadc_win_sizes); ++ //win_size -= 1; ++ for (i = 0; i < win_size; i++) { ++ if ((*width <= cisadc_win_sizes[i].width) && ++ (*height <= cisadc_win_sizes[i].height)) { ++ *width = cisadc_win_sizes[i].width; ++ *height = cisadc_win_sizes[i].height; ++ return &cisadc_win_sizes[i]; ++ } ++ } ++ ++ *width = cisadc_win_sizes[default_size].width; ++ *height = cisadc_win_sizes[default_size].height; ++ return &cisadc_win_sizes[default_size]; ++} ++ ++/* ++ * Set a format. ++ */ ++static int cisadc_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct cisadc_format_struct *ovfmt; ++ struct cisadc_win_size *wsize; ++ struct cisadc_info *info = to_state(sd); ++ int ret; ++ int win_size; ++ ++ win_size = ARRAY_SIZE(cisadc_win_sizes); ++ dev_info(sd->dev, "format width=%d, height=%d, code=0x%x, format->pad=%p, win_size=%d\n", format->format.width, format->format.height, format->format.code, format->pad, win_size); ++ ++ win_size--; ++ format->format.width = cisadc_win_sizes[win_size].width = format->format.width; ++ format->format.height = cisadc_win_sizes[win_size].height = format->format.height; ++ ++ info->win = &cisadc_win_sizes[win_size]; ++ //info->win = cisadc_select_win(&format->format.width, &format->format.height); ++ ++ return 0; ++} ++ ++static int cisadc_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct cisadc_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++ printk("----%s, %d, width: %d, height: %d, code: %x\n", ++ __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++#if 0 ++static int cisadc_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int cisadc_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int cisadc_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int cisadc_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int cisadc_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ return ret; ++ ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int cisadc_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct cisadc_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ ++ return 0; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int cisadc_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int cisadc_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct cisadc_info *info = to_state(sd); ++ int ret = 0; ++ if(info->exposure->val != value) { ++ ret = cisadc_write(sd, 0xfd, 0x01); ++ ret += cisadc_write(sd, 0x4, (unsigned char)(value & 0xff)); ++ ret += cisadc_write(sd, 0x3, (unsigned char)((value & 0xff00) >> 8)); ++ ret += cisadc_write(sd, 0x01, 0x01); ++ } ++ if (ret < 0) { ++ printk("cisadc_write error %d\n" ,__LINE__); ++ return ret; ++ } ++ return ret; ++} ++#endif ++ ++#if 0 ++static int cisadc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++#if 0 ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct cisadc_info *info = to_state(sd); ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return cisadc_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return cisadc_g_again(sd, &info->again->val); ++ } ++#endif ++ return -EINVAL; ++} ++ ++static int cisadc_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++#if 0 ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct cisadc_info *info = to_state(sd); ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return cisadc_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return cisadc_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return cisadc_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return cisadc_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* cisadc_s_gain turns off auto gain */ ++ return cisadc_s_gain(sd, info->gain->val); ++ } ++ return cisadc_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return cisadc_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return cisadc_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return cisadc_s_exp(sd, ctrl->val); ++ } ++#endif ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops cisadc_ctrl_ops = { ++ .s_ctrl = cisadc_s_ctrl, ++ .g_volatile_ctrl = cisadc_g_volatile_ctrl, ++}; ++#endif ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int cisadc_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ //ret = cisadc_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int cisadc_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ //cisadc_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int cisadc_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct cisadc_info *info = to_state(sd); ++ int ret = 0; ++ ++ return ret; ++} ++ ++int cisadc_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct cisadc_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops cisadc_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = cisadc_g_register, ++ .s_register = cisadc_s_register, ++#endif ++}; ++ ++static const struct v4l2_subdev_video_ops cisadc_video_ops = { ++ .s_stream = cisadc_s_stream, ++ .g_frame_interval = cisadc_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops cisadc_pad_ops = { ++ //.enum_frame_interval = cisadc_enum_frame_interval, ++ //.num_frame_size = cisadc_enum_frame_size, ++ //.enum_mbus_code = cisadc_enum_mbus_code, ++ .set_fmt = cisadc_set_fmt, ++ .get_fmt = cisadc_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops cisadc_ops = { ++ .core = &cisadc_core_ops, ++ .video = &cisadc_video_ops, ++ .pad = &cisadc_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++extern int isp_clk; ++ ++static int cisadc_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct cisadc_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned int ispcdr; ++ ++ /* ++ * after system boot up, #devmem 0x10000030 32 0x8000000f ++ * to set vic clock on. ++ */ ++ isp_clk = 4710000; /* isp clk = cis-clk/2 = 9.3MHz/2 = 4.7MHz */ ++ ispcdr = *(unsigned int*)0xB0000030; ++ v4l_info(client, "%s() isp_clk=%d, ispcdr=0x%08x\n", ++ __func__, isp_clk, ispcdr); ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ v4l2_i2c_subdev_init(sd, client, &cisadc_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++#if 0 ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ cisadc_reset(sd, 1); ++ ++ /* Make sure it's an cisadc */ ++ ret = cisadc_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an cisadc chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++ ++ /*IRCUT ctl 0:off 1:on*/ ++ cisadc_ircut(sd, 0); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &cisadc_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &cisadc_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &cisadc_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &cisadc_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &cisadc_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &cisadc_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 259142, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &cisadc_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1899 - 4, 1, 1500); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++#endif ++ info->win = &cisadc_win_sizes[0]; ++ //cisadc_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "cisadc Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int cisadc_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct cisadc_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id cisadc_id[] = { ++ { "cisadc", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, cisadc_id); ++ ++static const struct of_device_id cisadc_of_match[] = { ++ {.compatible = "ingenic,cisadc", }, ++ {}, ++}; ++ ++static struct i2c_driver cisadc_driver = { ++ .driver = { ++ .name = "cisadc", ++ .of_match_table = of_match_ptr(cisadc_of_match), ++ }, ++ .probe = cisadc_probe, ++ .remove = cisadc_remove, ++ .id_table = cisadc_id, ++}; ++ ++module_i2c_driver(cisadc_driver); ++MODULE_AUTHOR("Justin "); ++MODULE_DESCRIPTION("A low-level driver for CIS ADC"); ++MODULE_LICENSE("GPLv2"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/gc1054.c b/module_drivers/drivers/media/i2c/ingenic-isp/gc1054.c +new file mode 100644 +index 000000000..f4fb0bb58 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/gc1054.c +@@ -0,0 +1,1606 @@ ++/* ++ * A V4L2 driver for OmniVision gc1054 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#define DEBUG ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define GC1054_CHIP_ID_H (0x10) ++#define GC1054_CHIP_ID_L (0x54) ++#define GC1054_REG_CHIP_ID_HIGH 0xF0 ++#define GC1054_REG_CHIP_ID_LOW 0xF1 ++ ++ ++#define GC1054_REG_END 0xff ++#define GC1054_REG_DELAY 0x00 ++#define GC1054_PAGE_REG 0xfd ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct gc1054_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct gc1054_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct gc1054_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct gc1054_win_size *win; ++ ++ struct gc1054_gpio pwr; ++ ++ struct gc1054_gpio reset; ++ struct gc1054_gpio cimen; ++ struct gc1054_gpio ircutp; ++ struct gc1054_gpio ircutn; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++ ++struct again_lut gc1054_again_lut[] = { ++//gc1054_mipi.c add// ++ {0x00, 0}, ++ {0x01, 33220}, ++ {0x02, 64776}, ++ {0x03, 98789}, ++ {0x04, 131801}, ++ {0x05, 165630}, ++ {0x06, 197337}, ++ {0x07, 231174}, ++ {0x08, 262879}, ++ {0x09, 297665}, ++ { 0x0a, 329326}, ++ ++}; ++ ++static inline struct gc1054_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct gc1054_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct gc1054_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list gc1054_init_regs_1280_720_30fps_dvp[] = { ++//Mclk=24Mhz£¬PCLK=39Mhz ++//HD=1726,VD=750,row_time=HD/PCLK=44.25us ++//Actual_window_size=1280*720 ++ ///////////////////////////////////////////////////// ++ ////////////////////// SYS ////////////////////// ++ ///////////////////////////////////////////////////// ++ {0xf2,0x00}, ++ {0xf6,0x00}, ++ {0xfc,0x04}, ++ {0xf7,0x01}, ++ {0xf8,0x0c}, ++ {0xf9,0x00}, // 06 ++ {0xfa,0x80}, ++ {0xfc,0x0e}, ++ ///////////////////////////////////////////////////// ++ //////////////// ANALOG & CISCTL //////////////// ++ ///////////////////////////////////////////////////// ++ {0xfe,0x00}, ++ {0x03,0x02}, ++ {0x04,0xa6}, ++ {0x05,0x02}, //HB ++ {0x06,0x07}, ++ {0x07,0x00}, //VB ++ {0x08,0x0a}, ++ {0x09,0x00}, ++ ++ {0x0a,0x04}, //row start ++ {0x0b,0x00}, ++ {0x0c,0x00}, //col start ++ ++ {0x0d,0x02}, ++ {0x0e,0xd4}, //height 724 ++ ++ {0x0f,0x05}, ++ {0x10,0x08}, //width 1288 ++ ++ ++ {0x17,0xc0}, ++ {0x18,0x02}, ++ {0x19,0x08}, ++ {0x1a,0x18}, ++ {0x1d,0x12}, ++ {0x1e,0x50}, ++ {0x1f,0x80}, ++ {0x21,0x30}, ++ {0x23,0xf8}, ++ {0x25,0x10}, ++ {0x28,0x20}, ++ {0x34,0x08}, //data low ++ {0x3c,0x10}, ++ {0x3d,0x0e}, ++ {0xcc,0x8e}, ++ {0xcd,0x9a}, ++ {0xcf,0x70}, ++ {0xd0,0xa9}, ++ {0xd1,0xc5}, ++ {0xd2,0xed}, //data high ++ {0xd8,0x3c}, //dacin offset ++ {0xd9,0x7a}, ++ {0xda,0x12}, ++ {0xdb,0x50}, ++ {0xde,0x0c}, ++ {0xe3,0x60}, ++ {0xe4,0x78}, ++ {0xfe,0x01}, ++ {0xe3,0x01}, ++ {0xe6,0x10}, //ramps offset ++ ///////////////////////////////////////////////////// ++ ////////////////////// ISP ////////////////////// ++ ///////////////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0x80,0x50}, ++ {0x88,0x23}, ++ {0x89,0x03}, ++// {0x8c,0x01},//bit0:test color bar. ++ {0x90,0x01}, ++ {0x92,0x02}, //crop win 2<=y<=4 ++ {0x94,0x03}, //crop win 2<=x<=5 ++ {0x95,0x02}, //crop win height ++ {0x96,0xd0}, ++ {0x97,0x05}, //crop win width ++ {0x98,0x00}, ++ ///////////////////////////////////////////////////// ++ ////////////////////// BLK ////////////////////// ++ ///////////////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0x40,0x22}, ++ {0x43,0x03}, ++ {0x4e,0x3c}, ++ {0x4f,0x00}, ++ {0x60,0x00}, ++ {0x61,0x80}, ++ ///////////////////////////////////////////////////// ++ ////////////////////// GAIN ///////////////////// ++ ///////////////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0xb0,0x48}, ++ {0xb1,0x01}, ++ {0xb2,0x00}, ++ {0xb6,0x00}, ++ {0xfe,0x02}, ++ {0x01,0x00}, ++ {0x02,0x01}, ++ {0x03,0x02}, ++ {0x04,0x03}, ++ {0x05,0x04}, ++ {0x06,0x05}, ++ {0x07,0x06}, ++ {0x08,0x0e}, ++ {0x09,0x16}, ++ {0x0a,0x1e}, ++ {0x0b,0x36}, ++ {0x0c,0x3e}, ++ {0x0d,0x56}, ++ {0xfe,0x02}, ++ {0xb0,0x00}, //col_gain[11:8] ++ {0xb1,0x00}, ++ {0xb2,0x00}, ++ {0xb3,0x11}, ++ {0xb4,0x22}, ++ {0xb5,0x54}, ++ {0xb6,0xb8}, ++ {0xb7,0x60}, ++ {0xb9,0x00}, //col_gain[12] ++ {0xba,0xc0}, ++ {0xc0,0x20}, //col_gain[7:0] ++ {0xc1,0x2d}, ++ {0xc2,0x40}, ++ {0xc3,0x5b}, ++ {0xc4,0x80}, ++ {0xc5,0xb5}, ++ {0xc6,0x00}, ++ {0xc7,0x6a}, ++ {0xc8,0x00}, ++ {0xc9,0xd4}, ++ {0xca,0x00}, ++ {0xcb,0xa8}, ++ {0xcc,0x00}, ++ {0xcd,0x50}, ++ {0xce,0x00}, ++ {0xcf,0xa1}, ++ ///////////////////////////////////////////////////// ++ //////////////////// DARKSUN //////////////////// ++ ///////////////////////////////////////////////////// ++ {0xfe,0x02}, ++ {0x54,0xf7}, ++ {0x55,0xf0}, ++ {0x56,0x00}, ++ {0x57,0x00}, ++ {0x58,0x00}, ++ {0x5a,0x04}, ++ ///////////////////////////////////////////////////// ++ /////////////////////// DD ////////////////////// ++ ///////////////////////////////////////////////////// ++ {0xfe,0x04}, ++ {0x81,0x8a}, ++ ///////////////////////////////////////////////////// ++ ////////////////////// DVI ///////////////////// ++ ///////////////////////////////////////////////////// ++ {0xfe,0x03}, ++ {0x01,0x00}, ++ {0x02,0x00}, ++ {0x03,0x00}, ++ {0x10,0x11}, ++ ++ {0x15,0x00}, ++ {0x40,0x01}, ++ {0x41,0x00}, ++//////////////////////////////////////////// ++///////////// pad enable /////////////// ++//////////////////////////////////////////// ++ {0xfe,0x00}, ++ {0xf2,0x0f}, ++ ++ {GC1054_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list gc1054_init_regs_1080_360_60fps_dvp[] = { ++//Mclk=24Mhz,PCLK=39Mhz ++//HD=1626,VD=399,row_time=HD/PCLK=41.69us ++//Actual_window_size=1280*720 ++///////////////////////////////////////////////////// ++////////////////////// SYS ////////////////////// ++///////////////////////////////////////////////////// ++ {0xf2,0x00}, ++ {0xf6,0x00}, ++ {0xfc,0x04}, ++ {0xf7,0x01}, ++// {0xf8,0x0c},//pclk 39Mhz. ++ {0xf8,0x11},//pclk 54Mhz. ++ {0xf9,0x00}, ++ {0xfa,0x80}, ++ {0xfc,0x0e}, ++//////////////////////////////////////////// ++/////// ANALOG & CISCTL //////////////// ++//////////////////////////////////////////// ++ {0xfe,0x00}, ++// {0x03,0x02},////// exposure 12bit~8bit ++// {0x04,0xa6},///// exposure 7bit~0bit 720p default:678 ,1080*360<399 ++ /////////// ++ {0x03,0x01}, ++ {0x04,0x08}, //xtang debug :384 ++ ///////////// ++ {0x05,0x02}, //HB ++ {0x06,0x07}, ++ {0x07,0x00}, //VB ++ {0x08,0x13},//====ori ++// {0x08,0x0a},//====720p def ++ ///////////// ++ {0x09,0x00}, ++// {0x0a,0x04}, //row start ++ {0x0a,0xb4}, //row start 180 ++ {0x0b,0x00}, ++// {0x0c,0x00}, //col start ++ {0x0c,0xc8}, //64 col start 100 ++ //////////// ++ {0x0d,0x01}, ++ {0x0e,0x78}, //height 376 ++ {0x0f,0x04}, ++ {0x10,0x48}, //width 1096 ++ ///////// ++// {0x0d,0x02}, ++// {0x0e,0xd4},//724 ++// {0x0f,0x05}, ++// {0x10,0x08}, //1288 ++ ///////// ++ {0x17,0xc0}, ++ {0x18,0x02}, ++ {0x19,0x08}, ++ {0x1a,0x18}, ++ {0x1d,0x12}, ++ {0x1e,0x50}, ++ {0x1f,0x80}, ++ {0x21,0x30}, ++ {0x23,0xf8}, ++ {0x25,0x10}, ++ {0x28,0x20}, ++ {0x34,0x08}, //data low ++ {0x3c,0x10}, ++ {0x3d,0x0e}, ++ {0xcc,0x8e}, ++ {0xcd,0x9a}, ++ {0xcf,0x70}, ++ {0xd0,0xa9}, ++ {0xd1,0xc5}, ++ {0xd2,0xed}, //data high ++ {0xd8,0x3c}, //dacin offset ++ {0xd9,0x7a}, ++ {0xda,0x12}, ++ {0xdb,0x50}, ++ {0xde,0x0c}, ++ {0xe3,0x60}, ++ {0xe4,0x78}, ++ {0xfe,0x01}, ++ {0xe3,0x01}, ++ {0xe6,0x10}, //ramps offset ++///////////////////,///////////////////////// ++///////////// ISP ////////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0x80,0x50}, ++ {0x88,0x23}, ++ {0x89,0x03}, ++// {0x8c,0x01},//test color bar ++ {0x90,0x01}, ++ {0x92,0x02}, //crop win 2<=y<=4 ++ {0x94,0x03}, //crop win 2<=x<=5 ++ {0x95,0x01}, //crop win height ++ {0x96,0x68}, ++ {0x97,0x04}, //crop win width ++ {0x98,0x38}, ++//////////////////////////////////////////// ++///////////// BLK ////////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0x40,0x22}, ++ {0x43,0x03}, ++ {0x4e,0x3c}, ++ {0x4f,0x00}, ++ {0x60,0x00}, ++ {0x61,0x80}, ++//////////////////////////////////////////// ++///////////// GAIN ///////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0xb0,0x48}, ++ {0xb1,0x01}, ++ {0xb2,0x00}, ++ {0xb6,0x00}, ++ {0xfe,0x02}, ++ {0x01,0x00}, ++ {0x02,0x01}, ++ {0x03,0x02}, ++ {0x04,0x03}, ++ {0x05,0x04}, ++ {0x06,0x05}, ++ {0x07,0x06}, ++ {0x08,0x0e}, ++ {0x09,0x16}, ++ {0x0a,0x1e}, ++ {0x0b,0x36}, ++ {0x0c,0x3e}, ++ {0x0d,0x56}, ++ {0xfe,0x02}, ++ {0xb0,0x00}, //col_gain[11:8] ++ {0xb1,0x00}, ++ {0xb2,0x00}, ++ {0xb3,0x11}, ++ {0xb4,0x22}, ++ {0xb5,0x54}, ++ {0xb6,0xb8}, ++ {0xb7,0x60}, ++ {0xb9,0x00}, //col_gain[12] ++ {0xba,0xc0}, ++ {0xc0,0x20}, //col_gain[7:0] ++ {0xc1,0x2d}, ++ {0xc2,0x40}, ++ {0xc3,0x5b}, ++ {0xc4,0x80}, ++ {0xc5,0xb5}, ++ {0xc6,0x00}, ++ {0xc7,0x6a}, ++ {0xc8,0x00}, ++ {0xc9,0xd4}, ++ {0xca,0x00}, ++ {0xcb,0xa8}, ++ {0xcc,0x00}, ++ {0xcd,0x50}, ++ {0xce,0x00}, ++ {0xcf,0xa1}, ++//////////////////////////////////////////// ++/////////// DARKSUN //////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x02}, ++ {0x54,0xf7}, ++ {0x55,0xf0}, ++ {0x56,0x00}, ++ {0x57,0x00}, ++ {0x58,0x00}, ++ {0x5a,0x04}, ++//////////////////////////////////////////// ++////////////// DD ////////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x04}, ++ {0x81,0x8a}, ++//////////////////////////////////////////// ++///////////// MIPI ///////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x03}, ++ {0x01,0x00}, ++ {0x02,0x00}, ++ {0x03,0x00}, ++ {0x10,0x11}, ++ {0x15,0x00}, ++ {0x40,0x01}, ++ {0x41,0x00}, ++ /////////// ++ {0x42,0x38}, ++ {0x43,0x04},// width 1080 (must set!) ++//////////////////////////////////////////// ++///////////// pad enable /////////////// ++//////////////////////////////////////////// ++ {0xfe,0x00}, ++ {0xf2,0x0f}, ++ {GC1054_REG_END, 0x00}, /* END MARKER */ ++ ++}; ++static struct regval_list gc1054_init_regs_540_360_100fps_dvp[] = { ++//Mclk=24Mhz,PCLK=39Mhz ++//HD=1626,VD=398,row_time=HD/PCLK=25.1us ++//Actual_window_size=540*360 ++///////////////////////////////////////////////////// ++////////////////////// SYS ////////////////////// ++///////////////////////////////////////////////////// ++ {0xf2,0x00}, ++ {0xf6,0x00}, ++ {0xfc,0x04}, ++ {0xf7,0x01}, ++// {0xf8,0x11},// stage:3M,54MHZ. ++ {0xf8,0x0c},// stage:3M,39MHZ. ++ {0xf9,0x00}, ++ {0xfa,0x80}, ++ {0xfc,0x0e}, ++//////////////////////////////////////////// ++/////// ANALOG & CISCTL //////////////// ++//////////////////////////////////////////// ++ {0xfe,0x00}, ++// {0x03,0x02}, ++// {0x04,0xa6}, ++ //////// ++ {0x03,0x01}, ++// {0x04,0x08}, //xtang debug:384 ++ {0x04,0x00}, //gc debug:256 ++ //////// ++ {0x05,0x02}, //HB ++// {0x06,0x07}, ++// ////// ++ {0x06,0x06},// xtang debug hb ++ ///// ++ {0x07,0x00}, //VB ++ {0x08,0x12}, ++ {0x09,0x00}, ++ {0x0a,0x04}, //row start ++ {0x0b,0x00}, ++ {0x0c,0x00}, //col start ++ {0x0d,0x01}, ++ {0x0e,0x78}, //height 724 ++// {0x0f,0x04}, ++// {0x10,0x48}, //width 1288 ++// //// ++ {0x0f,0x02}, ++ {0x10,0x2c}, //debug width 556 ++// //// ++ {0x17,0xc0}, ++ {0x18,0x02}, ++ {0x19,0x08}, ++ {0x1a,0x18}, ++ {0x1d,0x12}, ++ {0x1e,0x50}, ++ {0x1f,0x80}, ++ {0x21,0x30}, ++ {0x23,0xf8}, ++ {0x25,0x10}, ++ {0x28,0x20}, ++ {0x34,0x08}, //data low ++ {0x3c,0x10}, ++ {0x3d,0x0e}, ++ {0xcc,0x8e}, ++ {0xcd,0x9a}, ++ {0xcf,0x70}, ++ {0xd0,0xa9}, ++ {0xd1,0xc5}, ++ {0xd2,0xed}, //data high ++ {0xd8,0x3c}, //dacin offset ++ {0xd9,0x7a}, ++ {0xda,0x12}, ++ {0xdb,0x50}, ++ {0xde,0x0c}, ++ {0xe3,0x60}, ++ {0xe4,0x78}, ++ {0xfe,0x01}, ++ {0xe3,0x01}, ++ {0xe6,0x10}, //ramps offset ++//////////////////////////////////////////// ++///////////// ISP ////////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0x80,0x50}, ++ {0x88,0x23}, ++ {0x89,0x03}, ++ {0x90,0x01}, ++ {0x92,0x02}, //crop win 2<=y<=4 ++ {0x94,0x03}, //crop win 2<=x<=5 ++ {0x95,0x01}, //crop win height ++ {0x96,0x68}, ++ {0x97,0x02}, //crop win width ++ {0x98,0x1c}, ++//////////////////////////////////////////// ++///////////// BLK ////////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0x40,0x22}, ++ {0x43,0x03}, ++ {0x4e,0x3c}, ++ {0x4f,0x00}, ++ {0x60,0x00}, ++ {0x61,0x80}, ++//////////////////////////////////////////// ++///////////// GAIN ///////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0xb0,0x48}, ++ {0xb1,0x01}, ++ {0xb2,0x00}, ++ {0xb6,0x00}, ++ {0xfe,0x02}, ++ {0x01,0x00}, ++ {0x02,0x01}, ++ {0x03,0x02}, ++ {0x04,0x03}, ++ {0x05,0x04}, ++ {0x06,0x05}, ++ {0x07,0x06}, ++ {0x08,0x0e}, ++ {0x09,0x16}, ++ {0x0a,0x1e}, ++ {0x0b,0x36}, ++ {0x0c,0x3e}, ++ {0x0d,0x56}, ++ {0xfe,0x02}, ++ {0xb0,0x00}, //col_gain[11:8] ++ {0xb1,0x00}, ++ {0xb2,0x00}, ++ {0xb3,0x11}, ++ {0xb4,0x22}, ++ {0xb5,0x54}, ++ {0xb6,0xb8}, ++ {0xb7,0x60}, ++ {0xb9,0x00}, //col_gain[12] ++ {0xba,0xc0}, ++ {0xc0,0x20}, //col_gain[7:0] ++ {0xc1,0x2d}, ++ {0xc2,0x40}, ++ {0xc3,0x5b}, ++ {0xc4,0x80}, ++ {0xc5,0xb5}, ++ {0xc6,0x00}, ++ {0xc7,0x6a}, ++ {0xc8,0x00}, ++ {0xc9,0xd4}, ++ {0xca,0x00}, ++ {0xcb,0xa8}, ++ {0xcc,0x00}, ++ {0xcd,0x50}, ++ {0xce,0x00}, ++ {0xcf,0xa1}, ++//////////////////////////////////////////// ++/////////// DARKSUN //////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x02}, ++ {0x54,0xf7}, ++ {0x55,0xf0}, ++ {0x56,0x00}, ++ {0x57,0x00}, ++ {0x58,0x00}, ++ {0x5a,0x04}, ++//////////////////////////////////////////// ++////////////// DD ////////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x04}, ++ {0x81,0x8a}, ++//////////////////////////////////////////// ++///////////// MIPI ///////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x03}, ++ {0x01,0x00}, ++ {0x02,0x00}, ++ {0x03,0x00}, ++ {0x10,0x11}, ++ {0x15,0x00}, ++ {0x40,0x01}, ++ {0x41,0x00}, ++ {0x42,0x1c}, ++ {0x43,0x02}, ++//////////////////////////////////////////// ++///////////// pad enable /////////////// ++//////////////////////////////////////////// ++ {0xfe,0x00}, ++ {0xf2,0x0f}, ++ {GC1054_REG_END, 0x00}, ++}; ++static struct regval_list gc1054_init_regs_720_360_100fps_dvp[] = { ++//Mclk=24Mhz,PCLK=39Mhz ++//HD=1626,VD=398,row_time=HD/PCLK=25.1us ++//Actual_window_size=720*360 ++///////////////////////////////////////////////////// ++////////////////////// SYS ////////////////////// ++///////////////////////////////////////////////////// ++ {0xf2,0x00}, ++ {0xf6,0x00}, ++ {0xfc,0x04}, ++ {0xf7,0x01}, ++ {0xf8,0x11}, ++ {0xf9,0x00}, ++ {0xfa,0x80}, ++ {0xfc,0x0e}, ++//////////////////////////////////////////// ++/////// ANALOG & CISCTL //////////////// ++//////////////////////////////////////////// ++ {0xfe,0x00}, ++ {0x03,0x01}, ++ {0x04,0x00}, ++ {0x05,0x02}, //HB ++ {0x06,0x07}, ++ {0x07,0x00}, //VB ++ {0x08,0x12}, ++ {0x09,0x00}, ++ {0x0a,0x04}, //row start ++ {0x0b,0x00}, ++ {0x0c,0x02}, //col start ++ {0x0d,0x01}, ++ {0x0e,0x90}, //height 724 ++ {0x0f,0x02}, ++ {0x10,0xe0},//width 1288 ++ {0x17,0xc0}, ++ {0x18,0x02}, ++ {0x19,0x08}, ++ {0x1a,0x18}, ++ {0x1d,0x12}, ++ {0x1e,0x50}, ++ {0x1f,0x80}, ++ {0x21,0x30}, ++ {0x23,0xf8}, ++ {0x25,0x10}, ++ {0x28,0x20}, ++ {0x34,0x08}, //data low ++ {0x3c,0x10}, ++ {0x3d,0x0e}, ++ {0xcc,0x8e}, ++ {0xcd,0x9a}, ++ {0xcf,0x70}, ++ {0xd0,0xa9}, ++ {0xd1,0xc5}, ++ {0xd2,0xed}, //data high ++ {0xd8,0x3c}, //dacin offset ++ {0xd9,0x7a}, ++ {0xda,0x12}, ++ {0xdb,0x50}, ++ {0xde,0x0c}, ++ {0xe3,0x60}, ++ {0xe4,0x78}, ++ {0xfe,0x01}, ++ {0xe3,0x01}, ++ {0xe6,0x10}, //ramps offset ++//////////////////////////////////////////// ++///////////// ISP ////////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0x80,0x50}, ++ {0x88,0x23}, ++ {0x89,0x03}, ++ {0x90,0x01}, ++ {0x92,0x01}, //crop win 2<=y<=4 ++ {0x94,0x02}, //crop win 2<=x<=5 ++ {0x95,0x01}, //crop win height ++ {0x96,0x68}, ++ {0x97,0x02}, //crop win width ++ {0x98,0xd0}, ++//////////////////////////////////////////// ++///////////// BLK ////////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0x40,0x22}, ++ {0x43,0x03}, ++ {0x4e,0x3c}, ++ {0x4f,0x00}, ++ {0x60,0x00}, ++ {0x61,0x80}, ++//////////////////////////////////////////// ++///////////// GAIN ///////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x01}, ++ {0xb0,0x48}, ++ {0xb1,0x01}, ++ {0xb2,0x00}, ++ {0xb6,0x00}, ++ {0xfe,0x02}, ++ {0x01,0x00}, ++ {0x02,0x01}, ++ {0x03,0x02}, ++ {0x04,0x03}, ++ {0x05,0x04}, ++ {0x06,0x05}, ++ {0x07,0x06}, ++ {0x08,0x0e}, ++ {0x09,0x16}, ++ {0x0a,0x1e}, ++ {0x0b,0x36}, ++ {0x0c,0x3e}, ++ {0x0d,0x56}, ++ {0xfe,0x02}, ++ {0xb0,0x00}, //col_gain[11:8] ++ {0xb1,0x00}, ++ {0xb2,0x00}, ++ {0xb3,0x11}, ++ {0xb4,0x22}, ++ {0xb5,0x54}, ++ {0xb6,0xb8}, ++ {0xb7,0x60}, ++ {0xb9,0x00}, //col_gain[12] ++ {0xba,0xc0}, ++ {0xc0,0x20}, //col_gain[7:0] ++ {0xc1,0x2d}, ++ {0xc2,0x40}, ++ {0xc3,0x5b}, ++ {0xc4,0x80}, ++ {0xc5,0xb5}, ++ {0xc6,0x00}, ++ {0xc7,0x6a}, ++ {0xc8,0x00}, ++ {0xc9,0xd4}, ++ {0xca,0x00}, ++ {0xcb,0xa8}, ++ {0xcc,0x00}, ++ {0xcd,0x50}, ++ {0xce,0x00}, ++ {0xcf,0xa1}, ++//////////////////////////////////////////// ++/////////// DARKSUN //////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x02}, ++ {0x54,0xf7}, ++ {0x55,0xf0}, ++ {0x56,0x00}, ++ {0x57,0x00}, ++ {0x58,0x00}, ++ {0x5a,0x04}, ++//////////////////////////////////////////// ++////////////// DD ////////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x04}, ++ {0x81,0x8a}, ++//////////////////////////////////////////// ++///////////// MIPI ///////////////////// ++//////////////////////////////////////////// ++ {0xfe,0x03}, ++ {0x01,0x00}, ++ {0x02,0x00}, ++ {0x03,0x00}, ++ {0x10,0x11}, ++ {0x15,0x00}, ++ {0x40,0x01}, ++ {0x41,0x00}, ++ {0x42,0xd0}, ++ {0x43,0x02}, ++//////////////////////////////////////////// ++///////////// pad enable /////////////// ++//////////////////////////////////////////// ++ {0xfe,0x00}, ++ {0xf2,0x0f}, ++ {GC1054_REG_END, 0x00}, ++ ++}; ++ ++// reg: 0xf2 ++//「陌上桑: DVP用这个控制stream on〠++//————————— ++//「陌上桑: 0x0f写0x00就是关闭输出了〠++//————————— ++// ++static struct regval_list gc1054_stream_on[] = { ++ {0xfe, 0x03}, ++// {0x10, 0x90},//mipi stream on ++ {0x10, 0x11},//dvp fake stream on ++ ++ {GC1054_REG_END, 0x00}, ++}; ++ ++static struct regval_list gc1054_stream_off[] = { ++ {0xfe, 0x03}, ++ {0x10, 0x00},//fake stream off ++ ++ {GC1054_REG_END, 0x00}, ++}; ++ ++ ++int gc1054_read(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 1, ++ .buf = ®, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc1054_write(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ unsigned char buf[2] = {reg, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc1054_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != GC1054_REG_END) { ++ if (vals->reg_num == GC1054_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc1054_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++// dev_vdbg(&sd->dev, "array: 0x%02x, 0x%02x", ++ pr_debug("array: 0x%02x, 0x%02x\n", ++ vals->reg_num, val); ++ } ++ vals++; ++ } ++ return 0; ++} ++static int gc1054_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != GC1054_REG_END) { ++ if (vals->reg_num == GC1054_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc1054_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int gc1054_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc1054_info *info = to_state(sd); ++return 0; ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(20); ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(20); ++ } ++ return 0; ++} ++ ++static int gc1054_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc1054_info *info = to_state(sd); ++return 0; ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int gc1054_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc1054_info *info = to_state(sd); ++ int ret = 0; ++// struct regval_list*reg = info->win->regs; ++// ret = gc1054_write_array(sd, info->win->regs); ++//#if 0 ++// while(reg->reg_num != GC1054_REG_END) ++// { ++// printk("--->reg:0x%02x,value:[0x%02x]\n",reg->reg_num,reg->value); ++// reg ++; ++// ++// } ++//#else ++// ret = gc1054_read_array(sd, info->win->regs); ++// if (ret<0) ++//#endif ++ ++ return ret; ++} ++ ++ ++ ++static int gc1054_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ ++ ret = gc1054_read(sd, GC1054_REG_CHIP_ID_HIGH, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC1054_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = gc1054_read(sd, GC1054_REG_CHIP_ID_LOW, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC1054_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ printk(" gc1054 id %x\n", *ident); ++ return 0; ++} ++ ++ ++static struct gc1054_win_size gc1054_win_sizes[] = { ++ /* 1280*720 */ ++ ++ { ++ .width = 1280, ++ .height = 720, ++ .sensor_info.fps = 30 << 16 | 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = gc1054_init_regs_1280_720_30fps_dvp, ++ }, ++ /* 1080*360 */ ++ ++ { ++ .width = 1080, ++ .height = 360, ++ .sensor_info.fps = 60 << 16 | 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = gc1054_init_regs_1080_360_60fps_dvp, ++ }, ++ ++ /* 720*360 */ ++ ++ { ++ .width = 720, ++ .height = 360, ++ .sensor_info.fps = 100 << 16 | 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = gc1054_init_regs_720_360_100fps_dvp, ++ }, ++ ++}; ++static const struct gc1054_win_size *gc1054_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(gc1054_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(gc1054_win_sizes); i++) { ++ if ((*width >= gc1054_win_sizes[i].width) && ++ (*height >= gc1054_win_sizes[i].height)) { ++ *width = gc1054_win_sizes[i].width; ++ *height = gc1054_win_sizes[i].height; ++ return &gc1054_win_sizes[i]; ++ } ++ } ++ ++ *width = gc1054_win_sizes[default_size].width; ++ *height = gc1054_win_sizes[default_size].height; ++// printk("------w=%d,h=%d--default_size=%d---->line=%d,func=%s\n",*width,*height,default_size,__LINE__,__func__); ++ return &gc1054_win_sizes[default_size]; ++} ++ ++static int gc1054_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_GC1054_FMTS) ++ return -EINVAL; ++ ++ code->code = gc1054_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int gc1054_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc1054_format_struct *ovfmt; ++ struct gc1054_win_size *wsize; ++ struct gc1054_info *info = to_state(sd); ++ int ret; ++ ++// if (format->pad) ++// return -EINVAL; ++ ++ info->win = gc1054_select_win(&format->format.width, &format->format.height); ++ ++ ++ return 0; ++} ++ ++static int gc1054_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc1054_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++ printk("----%s, %d, width: %d, height: %d, code: %x\n", ++ __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int gc1054_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc1054_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc1054_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc1054_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int gc1054_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int gc1054_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(gc1054_again_lut); i++) { ++ lut = &gc1054_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(gc1054_again_lut); i++) { ++ lut = &gc1054_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++ ++static int gc1054_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret = gc1054_read(sd, 0x23, &v); ++ reg_val |= v ; ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++ ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int gc1054_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct gc1054_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++//gc1054_mipi.c// ++ ret = gc1054_write(sd, 0xfe, 0x01); ++ ret += gc1054_write(sd, 0xb6, (unsigned char)reg_value); ++ ret = gc1054_write(sd, 0xfe, 0x00); ++// printk("gc1054_write ok ,set analog gain from gc1054_again_lut array. %d\n" ,__LINE__ ); ++//gc1054_mipi.c// ++ ++ if (ret < 0){ ++ printk("gc1054_write error %d\n" ,__LINE__ ); ++ return ret; ++ } ++ return 0; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int gc1054_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc1054_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct gc1054_info *info = to_state(sd); ++ int ret = 0; ++ ++// ret = gc1054_write(sd, 0xfd, 0x01); ++// ret += gc1054_write(sd, 0x4, (unsigned char)(value & 0xff)); ++// ret += gc1054_write(sd, 0x3, (unsigned char)((value & 0xff00) >> 8)); ++// ret += gc1054_write(sd, 0x01, 0x01); ++// ++// if (ret < 0) { ++// printk("gc1054_write error %d\n" ,__LINE__); ++// return ret; ++// } ++ return ret; ++} ++ ++static int gc1054_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc1054_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return gc1054_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc1054_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int gc1054_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc1054_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return gc1054_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return gc1054_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return gc1054_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return gc1054_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* gc1054_s_gain turns off auto gain */ ++ return gc1054_s_gain(sd, info->gain->val); ++ } ++ return gc1054_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return gc1054_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc1054_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return gc1054_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops gc1054_ctrl_ops = { ++ .s_ctrl = gc1054_s_ctrl, ++ .g_volatile_ctrl = gc1054_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int gc1054_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = gc1054_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int gc1054_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ gc1054_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int gc1054_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct gc1054_info *info = to_state(sd); ++ int ret = 0; ++ if (enable) { ++ ret = gc1054_write_array(sd, info->win->regs); ++ if(ret<0) ++ return ret; ++ ret = gc1054_write_array(sd, gc1054_stream_on); ++ pr_debug("gc1054 stream on\n"); ++ ++ } ++ else { ++ ret = gc1054_write_array(sd, gc1054_stream_off); ++ pr_debug("gc1054 stream off\n"); ++ } ++ return ret; ++} ++ ++int gc1054_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct gc1054_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops gc1054_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = gc1054_g_register, ++ .s_register = gc1054_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops gc1054_video_ops = { ++ .s_stream = gc1054_s_stream, ++ .g_frame_interval = gc1054_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops gc1054_pad_ops = { ++ //.enum_frame_interval = gc1054_enum_frame_interval, ++ //.num_frame_size = gc1054_enum_frame_size, ++ //.enum_mbus_code = gc1054_enum_mbus_code, ++ .set_fmt = gc1054_set_fmt, ++ .get_fmt = gc1054_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops gc1054_ops = { ++ .core = &gc1054_core_ops, ++ .video = &gc1054_video_ops, ++ .pad = &gc1054_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int gc1054_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct gc1054_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++printk(" gc1054 probe \n\n"); ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++// gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,cim-rst-gpio", 0, &flags); ++// if(gpio_is_valid(gpio)) { ++// info->reset.pin = gpio; ++// info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++// printk("~~~~~~~line=%d,reset gpio=%d,value=%d\n",__LINE__,info->reset.pin,info->reset.active_level); ++// ret = gpio_request_one(info->reset.pin, GPIOF_DIR_OUT, "rst"); ++// if(ret < 0) { ++// dev_err(&client->dev, "Failed to request reset pin!\n"); ++// return ret; ++// } ++// } ++ ++ ++ ++//init cim-en-gpio:3v3 ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,cim-en-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->cimen.pin = gpio; ++ info->cimen.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ ret = gpio_request_one(info->cimen.pin, GPIOF_DIR_OUT, "cim-en"); ++ if(ret < 0) { ++ dev_err(&client->dev, "Failed to request cimen pin!\n"); ++ return ret; ++ } ++ ret = gpio_direction_output(info->cimen.pin,info->cimen.active_level); //0 ++ if(ret < 0) { ++ dev_err(&client->dev, "Failed to output cimen pin 0!\n"); ++ return ret; ++ } ++ ++ } ++ ++ ++ v4l2_i2c_subdev_init(sd, client, &gc1054_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++// gc1054_reset(sd, 1); ++ ++#if 1 ++ /* Make sure it's an gc1054 */ ++ ret = gc1054_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an gc1054 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ /*IRCUT ctl 0:off 1:on*/ ++// gc1054_ircut(sd, 0); ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &gc1054_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &gc1054_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &gc1054_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &gc1054_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &gc1054_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &gc1054_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 259142, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &gc1054_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1899 - 4, 1, 1500); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++// info->win = &gc1054_win_sizes[0];//720p ++// info->win = &gc1054_win_sizes[1];//1080*360 ++// info->win = &gc1054_win_sizes[2];//720*360 ++ gc1054_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "gc1054 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int gc1054_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct gc1054_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id gc1054_id[] = { ++ { "gc1054", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, gc1054_id); ++ ++static const struct of_device_id gc1054_of_match[] = { ++ {.compatible = "galaxyc,gc1054", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++ ++static struct i2c_driver gc1054_driver = { ++ .driver = { ++ .name = "gc1054", ++ .of_match_table = of_match_ptr(gc1054_of_match), ++ }, ++ .probe = gc1054_probe, ++ .remove = gc1054_remove, ++ .id_table = gc1054_id, ++}; ++ ++module_i2c_driver(gc1054_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision gc1054 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/gc2093.c b/module_drivers/drivers/media/i2c/ingenic-isp/gc2093.c +new file mode 100644 +index 000000000..ad64d5e09 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/gc2093.c +@@ -0,0 +1,1043 @@ ++/* ++ * A V4L2 driver for OmniVision gc2093 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#define DEBUG ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define GC2093_CHIP_ID_H (0x20) ++#define GC2093_CHIP_ID_L (0x93) ++#define GC2093_REG_CHIP_ID_HIGH 0x03f0 ++#define GC2093_REG_CHIP_ID_LOW 0x03f1 ++ ++ ++#define GC2093_REG_END 0xffff ++#define GC2093_REG_DELAY 0x00 ++#define GC2093_PAGE_REG 0xfd ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct gc2093_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++}; ++ ++struct gc2093_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct gc2093_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct gc2093_win_size *win; ++ ++ struct gc2093_gpio pwr; ++ ++ struct gc2093_gpio reset; ++ struct gc2093_gpio cimen; ++ struct gc2093_gpio ircutp; ++ struct gc2093_gpio ircutn; ++}; ++ ++ ++ ++static unsigned int regValTable_t30[25][8] = { ++ // {0xb3,0xb8,0xb9,0x155,0xc2,0xcf,0xd9}, ++ {0x00,0x01,0x00,0x08,0x10,0x08,0x0a,0}, ++ {0x10,0x01,0x0c,0x08,0x10,0x08,0x0a,14997}, ++ {0x20,0x01,0x1b,0x08,0x11,0x08,0x0c,32233}, ++ {0x30,0x01,0x2c,0x08,0x12,0x08,0x0e,46808}, ++ {0x40,0x01,0x3f,0x08,0x14,0x08,0x12,60995}, ++ {0x50,0x02,0x16,0x08,0x15,0x08,0x14,75348}, ++ {0x60,0x02,0x35,0x08,0x17,0x08,0x18,90681}, ++ {0x70,0x03,0x16,0x08,0x18,0x08,0x1a,104361}, ++ {0x80,0x04,0x02,0x08,0x1a,0x08,0x1e,118021}, ++ {0x90,0x04,0x31,0x08,0x1b,0x08,0x20,131438}, ++ {0xa0,0x05,0x32,0x08,0x1d,0x08,0x24,145749}, ++ {0xb0,0x06,0x35,0x08,0x1e,0x08,0x26,159553}, ++ {0xc0,0x08,0x04,0x08,0x20,0x08,0x2a,172553}, ++ {0x5a,0x09,0x19,0x08,0x1e,0x08,0x2a,183132}, ++ {0x83,0x0b,0x0f,0x08,0x1f,0x08,0x2a,198614}, ++ {0x93,0x0d,0x12,0x08,0x21,0x08,0x2e,212697}, ++ {0x84,0x10,0x00,0x0b,0x22,0x08,0x30,226175}, ++ {0x94,0x12,0x3a,0x0b,0x24,0x08,0x34,240788}, ++ {0x5d,0x1a,0x02,0x0b,0x26,0x08,0x34,271536}, ++ {0x9b,0x1b,0x20,0x0b,0x26,0x08,0x34,272451}, ++ {0x8c,0x20,0x0f,0x0b,0x26,0x08,0x34,287144}, ++ {0x9c,0x26,0x07,0x12,0x26,0x08,0x34,302425}, ++ {0xB6,0x36,0x21,0x12,0x26,0x08,0x34,334228}, ++ {0xad,0x37,0x3a,0x12,0x26,0x08,0x34,351574}, ++ {0xbd,0x3d,0x02,0x12,0x26,0x08,0x34,367506}, ++}; ++unsigned int gainLevelTable[26] = { ++ 64, ++ 76, ++ 91, ++ 107, ++ 125, ++ 147, ++ 177, ++ 211, ++ 248, ++ 297, ++ 356, ++ 425, ++ 504, ++ 599, ++ 709, ++ 836, ++ 978, ++ 1153, ++ 1647, ++ 1651, ++ 1935, ++ 2292, ++ 3239, ++ 3959, ++ 4686, ++ 0xffffffff, ++}; ++ ++/***********************************/ ++ ++ ++struct again_lut { ++ unsigned int index; ++ unsigned char regb0; ++ unsigned char regb1; ++ unsigned int regb2; ++ unsigned char regb3; ++ unsigned char regb4; ++ unsigned char regb5; ++ unsigned char regb6; ++ unsigned char regb7; ++ ++ unsigned int gain; ++}; ++ ++ ++static inline struct gc2093_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct gc2093_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct gc2093_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list gc2093_init_regs_1920_1080_60fps_mipi[] = { ++ /****system****/ ++ {0x03fe, 0xf0}, ++ {0x03fe, 0xf0}, ++ {0x03fe, 0xf0}, ++ {0x03fe, 0x00}, ++ {0x03f2, 0x00}, ++ {0x03f3, 0x00}, ++ {0x03f4, 0x36}, ++ {0x03f5, 0xc0}, ++ {0x03f6, 0x0B}, ++ {0x03f7, 0x01}, ++ // {0x03f8, 0x58}, //24Mhz ++ {0x03f8, 0x58}, //27Mhz ++ {0x03f9, 0x40}, ++ {0x03fc, 0x8e}, ++ /****CISCTL & NALOG****/ ++ {0x0087, 0x18}, ++ {0x00ee, 0x30}, ++ {0x00d0, 0xbf}, ++ {0x01a0, 0x00}, ++ {0x01a4, 0x40}, ++ {0x01a5, 0x40}, ++ {0x01a6, 0x40}, ++ {0x01af, 0x09}, ++ {0x0001, 0x00}, ++ {0x0002, 0x02}, ++ {0x0003, 0x04}, ++ {0x0004, 0x02}, ++ {0x0005, 0x02}, ++ {0x0006, 0x94}, ++ {0x0007, 0x00}, ++ {0x0008, 0x11}, ++ {0x0009, 0x00}, ++ {0x000a, 0x02}, ++ {0x000b, 0x00}, ++ {0x000c, 0x04}, ++ {0x000d, 0x04}, ++ {0x000e, 0x40}, ++ {0x000f, 0x07}, ++ {0x0010, 0x8c}, ++ {0x0013, 0x15}, ++ {0x0019, 0x0c}, ++ {0x0041, 0x04}, ++ {0x0042, 0xE2}, //frame length 0x04e2=1250 ++ ++ // {0x0041, 0x05}, //or dorp ++ // {0x0042, 0xE6}, //frame length 0x05E6=1350 ++ ++ {0x0053, 0x60}, ++ {0x008d, 0x92}, ++ {0x0090, 0x00}, ++ {0x00c7, 0xe1}, ++ {0x001b, 0x73}, ++ {0x0028, 0x0d}, ++ {0x0029, 0x24}, ++ {0x002b, 0x04}, ++ {0x002e, 0x23}, ++ {0x0037, 0x03}, ++ {0x0043, 0x04}, ++ {0x0044, 0x28}, ++ {0x004a, 0x01}, ++ {0x004b, 0x20}, ++ {0x0055, 0x28}, ++ {0x0066, 0x3f}, ++ {0x0068, 0x3f}, ++ {0x006b, 0x44}, ++ {0x0077, 0x00}, ++ {0x0078, 0x20}, ++ {0x007c, 0xa1}, ++ {0x00ce, 0x7c}, ++ {0x00d3, 0xd4}, ++ {0x00e6, 0x50}, ++ /****gain****/ ++ {0x00b6, 0xc0}, ++ {0x00b0, 0x68}, //0x60 ++ ++ {0x00b3,0x00}, ++ {0x00b8,0x01}, ++ {0x00b9,0x00}, ++ {0x00b1,0x01}, ++ {0x00b2,0x00}, ++ ++ /*****isp****/ ++ //{0x0101, 0x0c}, ++ {0x0102, 0x89}, ++ {0x0104, 0x01}, ++ {0x010f, 0x00}, ++ {0x0158, 0x00}, ++ {/*dark sun*/}, ++ {0x0123, 0x08}, ++ {0x0123, 0x00}, ++ {0x0120, 0x01}, ++ {0x0121, 0x04}, ++ {0x0122, 0xd8}, ++ {0x0124, 0x03}, ++ {0x0125, 0xff}, ++ {0x001a, 0x8c}, ++ {0x00c6, 0xe0}, ++ /****blk****/ ++ {0x0026, 0x30}, ++ {0x0142, 0x00}, ++ {0x0149, 0x1e}, ++ {0x014a, 0x0f}, ++ {0x014b, 0x00}, ++ {0x0155, 0x07}, ++ {0x0414, 0x78}, ++ {0x0415, 0x78}, ++ {0x0416, 0x78}, ++ {0x0417, 0x78}, ++ {0x0454, 0x78}, ++ {0x0455, 0x78}, ++ {0x0456, 0x78}, ++ {0x0457, 0x78}, ++ {0x04e0, 0x18}, ++ /****window****/ ++ {0x0192, 0x02}, ++ {0x0194, 0x03}, ++ {0x0195, 0x04}, ++ {0x0196, 0x38}, ++ {0x0197, 0x07}, ++ {0x0198, 0x80}, ++ /****DVP & MIP*****/ ++ {0x019a, 0x06}, ++ {0x007b, 0x2a}, ++ {0x0023, 0x2d}, ++ {0x0201, 0x27}, ++ {0x0202, 0x56}, ++ //{0x0203, 0xb6}, //try 0xce or 0x8e or drop ++ {0x0203, 0x8e}, //try 0xce or 0x8e or drop ++ {0x0212, 0x80}, ++ {0x0213, 0x07}, ++ {0x0215, 0x10}, ++ {0x003e, 0x91}, ++ {GC2093_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list gc2093_stream_on[] = { ++ {GC2093_REG_END, 0x00}, ++}; ++ ++static struct regval_list gc2093_stream_off[] = { ++ {GC2093_REG_END, 0x00}, ++}; ++ ++ ++int gc2093_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2]={(reg>>8)&0xff,reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3]={(reg>>8)&0xff,reg&0xff,value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != GC2093_REG_END) { ++ if (vals->reg_num == GC2093_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc2093_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ { ++ printk("array: 0x%02x, 0x%02x\n",vals->reg_num, val); ++ return ret; ++ } ++ } ++ vals++; ++ } ++ return 0; ++} ++static int gc2093_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != GC2093_REG_END) { ++ if (vals->reg_num == GC2093_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc2093_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int gc2093_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2093_info *info = to_state(sd); ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(20); ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(20); ++ } ++ return 0; ++} ++ ++static int gc2093_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2093_info *info = to_state(sd); ++return 0; ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int gc2093_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2093_info *info = to_state(sd); ++ int ret = 0; ++ struct regval_list*reg = info->win->regs; ++ ret = gc2093_write_array(sd, info->win->regs); ++//#if 0 ++// while(reg->reg_num != gc2093_REG_END) ++// { ++// printk("--->reg:0x%02x,value:[0x%02x]\n",reg->reg_num,reg->value); ++// reg ++; ++// ++// } ++//#else ++// ret = gc2093_read_array(sd, info->win->regs); ++// if (ret<0) ++//#endif ++ ++ return ret; ++} ++ ++ ++ ++ ++static int gc2093_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ ++ ret = gc2093_read(sd, GC2093_REG_CHIP_ID_HIGH, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC2093_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = gc2093_read(sd, GC2093_REG_CHIP_ID_LOW, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC2093_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ printk(" gc2093 id %x\n", *ident); ++ return 0; ++} ++ ++ ++static struct gc2093_win_size gc2093_win_sizes[] = { ++ { ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 55 << 16 | 1, ++ ++ .width = 1920, ++ .height = 1080, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = gc2093_init_regs_1920_1080_60fps_mipi, ++ }, ++ ++}; ++static const struct gc2093_win_size *gc2093_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(gc2093_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(gc2093_win_sizes); i++) { ++ if ((*width >= gc2093_win_sizes[i].width) && ++ (*height >= gc2093_win_sizes[i].height)) { ++ *width = gc2093_win_sizes[i].width; ++ *height = gc2093_win_sizes[i].height; ++ return &gc2093_win_sizes[i]; ++ } ++ } ++ ++ *width = gc2093_win_sizes[default_size].width; ++ *height = gc2093_win_sizes[default_size].height; ++ printk("------w=%d,h=%d--default_size=%d---->line=%d,func=%s\n",*width,*height,default_size,__LINE__,__func__); ++ return &gc2093_win_sizes[default_size]; ++} ++ ++static int gc2093_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_gc2093_FMTS) ++ return -EINVAL; ++ ++ code->code = gc2093_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int gc2093_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc2093_format_struct *ovfmt; ++ struct gc2093_win_size *wsize; ++ struct gc2093_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++// info->win = gc2093_select_win(&format->format.width, &format->format.height); ++ ++ ++ return 0; ++} ++ ++static int gc2093_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc2093_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ printk("----%s, %d, width: %d, height: %d, code: %x\n", ++ __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int gc2093_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int gc2093_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int gc2093_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++#if 0 ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(gc2093_again_lut); i++) { ++ lut = &gc2093_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(gc2093_again_lut); i++) { ++ lut = &gc2093_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++#endif ++ ++static int gc2093_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++// printk("~~~g_again=%d\n",*value); ++#if 1 ++ return 0; ++#else ++ char v=0; ++ unsigned int reg_val=0; ++ int ret=0; ++ int i=0; ++ int total; ++ total = sizeof(gainLevelTable) / sizeof(unsigned int); ++ ++ ret=gc2093_read(sd,0x00b1,&v); ++ reg_val|=(v<<6); ++ ret+=gc2093_read(sd,0x00b2,&v); ++ reg_val|=((v>>2)|0x3f); ++ ++ for (i = 0; i < total; i++) ++ { ++ if ((gainLevelTable[i] <= reg_val)&&(reg_val < gainLevelTable[i+1])) ++ { ++ *value=reg_val; ++ break; ++ } ++ } ++ return ret; ++#endif ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int gc2093_s_again(struct v4l2_subdev *sd, int value) ++{ ++// printk("~~~s_again=%d\n",value); ++ int index; ++ //return 0; ++ ++#if 1 ++ int i,ret=0; ++ int total; ++ unsigned int tol_dig_gain = 0; ++ ++ total = sizeof(gainLevelTable) / sizeof(unsigned int); ++ ++ for (i = 0; i < total; i++) ++ { ++ //if ((regValTable[i][8] <= value)&&(value < regValTable[i+1][8])) ++ if (value <= regValTable_t30[i][7]) ++ break; ++ } ++// printk("~~i=%d,~~~gainLevelTable[i]=%d\n",i,gainLevelTable[i]); ++// printk("~~~regValTable[i][7]=%d\n",regValTable[i][7]); ++ tol_dig_gain = value*64/regValTable_t30[i][7]; ++ ++ ret += gc2093_write(sd,0x00b3,regValTable_t30[i][0]); ++ ret += gc2093_write(sd,0x00b8,regValTable_t30[i][1]); ++ ret += gc2093_write(sd,0x00b9,regValTable_t30[i][2]); ++ ret += gc2093_write(sd,0x0155,regValTable_t30[i][3]); ++ gc2093_write(sd,0x031d,0x2d); ++ // ret += gc2093_write(sd,0x00c2,regValTable_t30[i][4]); ++ // ret += gc2093_write(sd,0x00cf,regValTable_t30[i][5]); ++ // ret += gc2093_write(sd,0x00d9,regValTable_t30[i][6]); ++ gc2093_write(sd,0x031d,0x28); ++ ++ ret +=gc2093_write(sd,0x00b1,(tol_dig_gain>>6)); ++ ret +=gc2093_write(sd,0x00b2,((tol_dig_gain&0x3f)<<2)); ++ if (ret < 0) { ++ printk("gc2093_write error %d" ,__LINE__ ); ++ return ret; ++ } ++#endif ++ return 0; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int gc2093_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_exp(struct v4l2_subdev *sd, int intt) ++{ ++ int line_frame_total=1200; ++ int frame_length; ++ if(intt>line_frame_total) ++ frame_length=intt+1; ++ else ++ frame_length=line_frame_total; ++ gc2093_write(sd,0x0003,(intt>>8)&0x3f); ++ gc2093_write(sd,0x0004,intt & 0xff); ++ return 0; ++} ++ ++static int gc2093_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc2093_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return gc2093_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc2093_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int gc2093_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc2093_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return gc2093_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return gc2093_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return gc2093_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return gc2093_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* gc2093_s_gain turns off auto gain */ ++ return gc2093_s_gain(sd, info->gain->val); ++ } ++ return gc2093_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return gc2093_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc2093_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return gc2093_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops gc2093_ctrl_ops = { ++ .s_ctrl = gc2093_s_ctrl, ++ .g_volatile_ctrl = gc2093_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int gc2093_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = gc2093_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int gc2093_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ gc2093_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int gc2093_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct gc2093_info *info = to_state(sd); ++ int ret = 0; ++ int val=0; ++ printk("------------>line=%d,func=%s\n",__LINE__,__func__); ++ if (enable) { ++ // ret = gc2093_write_array(sd, info->win->regs); ++ // if(ret<0) ++ // return ret; ++ ret = gc2093_write_array(sd, gc2093_stream_on); ++ ++ // ret = gc2093_read(sd, 0x0199, &val); ++ ++ pr_debug("gc2093 stream on\n"); ++ printk("----on-------->line=%d,func=%s\n",__LINE__,__func__); ++ ++ } ++ else { ++ ret = gc2093_write_array(sd, gc2093_stream_off); ++ pr_debug("gc2093 stream off\n"); ++ printk("----off-------->line=%d,func=%s\n",__LINE__,__func__); ++ } ++ return ret; ++} ++ ++int gc2093_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct gc2093_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops gc2093_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = gc2093_g_register, ++ .s_register = gc2093_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops gc2093_video_ops = { ++ .s_stream = gc2093_s_stream, ++ .g_frame_interval = gc2093_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops gc2093_pad_ops = { ++ //.enum_frame_interval = gc2093_enum_frame_interval, ++ //.num_frame_size = gc2093_enum_frame_size, ++ //.enum_mbus_code = gc2093_enum_mbus_code, ++ .set_fmt = gc2093_set_fmt, ++ .get_fmt = gc2093_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops gc2093_ops = { ++ .core = &gc2093_core_ops, ++ .video = &gc2093_video_ops, ++ .pad = &gc2093_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int gc2093_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct gc2093_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ printk(" gc2093 probe \n\n"); ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &gc2093_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 27000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ gc2093_reset(sd, 1); ++ ++ /* Make sure it's an gc2093 */ ++ ret = gc2093_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an gc2093 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++// gc2093_ircut(sd, 0); ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ // V4L2_CID_ANALOGUE_GAIN, 0, 259142, 1, 10000); ++ V4L2_CID_ANALOGUE_GAIN, 0, 405939, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1899 - 4, 1, 1500); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &gc2093_win_sizes[0];//720p ++ ++ gc2093_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "gc2093 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int gc2093_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct gc2093_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id gc2093_id[] = { ++ { "gc2093", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, gc2093_id); ++ ++static const struct of_device_id gc2093_of_match[] = { ++ {.compatible = "galaxyc,gc2093", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++ ++static struct i2c_driver gc2093_driver = { ++ .driver = { ++ .name = "gc2093", ++ .of_match_table = of_match_ptr(gc2093_of_match), ++ }, ++ .probe = gc2093_probe, ++ .remove = gc2093_remove, ++ .id_table = gc2093_id, ++}; ++ ++module_i2c_driver(gc2093_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision gc2093 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/gm8914_gm8913_gc2093.c b/module_drivers/drivers/media/i2c/ingenic-isp/gm8914_gm8913_gc2093.c +new file mode 100644 +index 000000000..084b9cf37 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/gm8914_gm8913_gc2093.c +@@ -0,0 +1,1508 @@ ++/* ++ * A V4L2 driver for OmniVision gc2093 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#define DEBUG ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define GC2093_CHIP_ID_H (0x20) ++#define GC2093_CHIP_ID_L (0x93) ++#define GC2093_REG_CHIP_ID_HIGH 0x03f0 ++#define GC2093_REG_CHIP_ID_LOW 0x03f1 ++ ++ ++#define LHAN 0 ++ ++ ++#define GC2093_REG_END 0xffff ++#define GC2093_REG_DELAY 0x00 ++#define GC2093_PAGE_REG 0xfd ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct gc2093_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int fps; ++ unsigned int mbus_code; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct gc2093_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct gc2093_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct gc2093_win_size *win; ++ ++ struct gc2093_gpio pwr; ++ ++ struct gc2093_gpio reset; ++ struct gc2093_gpio cimen; ++ struct gc2093_gpio ircutp; ++ struct gc2093_gpio ircutn; ++}; ++ ++ ++ ++static unsigned int regValTable_t30[25][8] = { ++ // {0xb3,0xb8,0xb9,0x155,0xc2,0xcf,0xd9}, ++ {0x00,0x01,0x00,0x08,0x10,0x08,0x0a,0}, ++ {0x10,0x01,0x0c,0x08,0x10,0x08,0x0a,14997}, ++ {0x20,0x01,0x1b,0x08,0x11,0x08,0x0c,32233}, ++ {0x30,0x01,0x2c,0x08,0x12,0x08,0x0e,46808}, ++ {0x40,0x01,0x3f,0x08,0x14,0x08,0x12,60995}, ++ {0x50,0x02,0x16,0x08,0x15,0x08,0x14,75348}, ++ {0x60,0x02,0x35,0x08,0x17,0x08,0x18,90681}, ++ {0x70,0x03,0x16,0x08,0x18,0x08,0x1a,104361}, ++ {0x80,0x04,0x02,0x08,0x1a,0x08,0x1e,118021}, ++ {0x90,0x04,0x31,0x08,0x1b,0x08,0x20,131438}, ++ {0xa0,0x05,0x32,0x08,0x1d,0x08,0x24,145749}, ++ {0xb0,0x06,0x35,0x08,0x1e,0x08,0x26,159553}, ++ {0xc0,0x08,0x04,0x08,0x20,0x08,0x2a,172553}, ++ {0x5a,0x09,0x19,0x08,0x1e,0x08,0x2a,183132}, ++ {0x83,0x0b,0x0f,0x08,0x1f,0x08,0x2a,198614}, ++ {0x93,0x0d,0x12,0x08,0x21,0x08,0x2e,212697}, ++ {0x84,0x10,0x00,0x0b,0x22,0x08,0x30,226175}, ++ {0x94,0x12,0x3a,0x0b,0x24,0x08,0x34,240788}, ++ {0x5d,0x1a,0x02,0x0b,0x26,0x08,0x34,271536}, ++ {0x9b,0x1b,0x20,0x0b,0x26,0x08,0x34,272451}, ++ {0x8c,0x20,0x0f,0x0b,0x26,0x08,0x34,287144}, ++ {0x9c,0x26,0x07,0x12,0x26,0x08,0x34,302425}, ++ {0xB6,0x36,0x21,0x12,0x26,0x08,0x34,334228}, ++ {0xad,0x37,0x3a,0x12,0x26,0x08,0x34,351574}, ++ {0xbd,0x3d,0x02,0x12,0x26,0x08,0x34,367506}, ++}; ++unsigned int gainLevelTable[26] = { ++ 64, ++ 76, ++ 91, ++ 107, ++ 125, ++ 147, ++ 177, ++ 211, ++ 248, ++ 297, ++ 356, ++ 425, ++ 504, ++ 599, ++ 709, ++ 836, ++ 978, ++ 1153, ++ 1647, ++ 1651, ++ 1935, ++ 2292, ++ 3239, ++ 3959, ++ 4686, ++ 0xffffffff, ++}; ++ ++/***********************************/ ++ ++ ++struct again_lut { ++ unsigned int index; ++ unsigned char regb0; ++ unsigned char regb1; ++ unsigned int regb2; ++ unsigned char regb3; ++ unsigned char regb4; ++ unsigned char regb5; ++ unsigned char regb6; ++ unsigned char regb7; ++ ++ unsigned int gain; ++}; ++ ++ ++static inline struct gc2093_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct gc2093_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct gc2093_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list gc2093_init_regs_1920_1080_30fps_mipi[] = { ++/* ++mclk=27mhz ++pclk:74.25Mhz ++Linelength:2200 ++row time:29.629us ++frame rate:30fps ++window height:1125 ++size:1920*1080 ++*/ ++ ++/****system****/ ++{0x03fe,0x80}, ++{0x03fe,0x80}, ++{0x03fe,0x80}, ++{0x03fe,0x00}, ++{0x03f2,0x00}, ++{0x03f3,0x0f}, ++{0x03f4,0x36}, ++{0x03f5,0xc0}, ++{0x03f6,0x0A}, ++{0x03f7,0x01}, ++{0x03f8,0x2C}, ++{0x03f9,0x10}, ++{0x03fc,0x8e}, ++/****CISCTL & ANALOG****/ ++{0x0087,0x18}, ++{0x00ee,0x30}, ++{0x00d0,0xb7}, ++{0x01a0,0x00}, ++{0x01a4,0x40}, ++{0x01a5,0x40}, ++{0x01a6,0x40}, ++{0x01af,0x09}, ++{0x0001,0x00}, ++{0x0002,0x02}, ++{0x0003,0x00}, ++{0x0004,0x02}, ++{0x0005,0x04}, ++{0x0006,0x4c}, ++{0x0007,0x00}, ++{0x0008,0x11}, ++{0x0009,0x00}, ++{0x000a,0x02}, ++{0x000b,0x00}, ++{0x000c,0x04}, ++{0x000d,0x04}, ++{0x000e,0x40}, ++{0x000f,0x07}, ++{0x0010,0x8c}, ++{0x0013,0x15}, ++{0x0019,0x0c}, ++{0x0041,0x04}, ++{0x0042,0x65}, ++{0x0053,0x60}, ++{0x008d,0x92}, ++{0x0090,0x00}, ++{0x0053,0x60}, ++{0x00c7,0xe1}, ++{0x001b,0x73}, ++{0x0028,0x0d}, ++{0x0029,0x24}, ++{0x002b,0x04}, ++{0x002e,0x23}, ++{0x0037,0x03}, ++{0x0043,0x04}, ++{0x0044,0x20}, ++{0x0046,0x0b}, ++{0x004a,0x01}, ++{0x004b,0x20}, ++{0x0055,0x20}, ++{0x0068,0x20}, ++{0x0069,0x20}, ++{0x0077,0x00}, ++{0x0078,0x04}, ++{0x007c,0x91}, ++{0x00ce,0x7c}, ++{0x00d3,0xdc}, ++{0x00e6,0x50}, ++/*gain*/ ++{0x00b6,0xc0}, ++{0x00b0,0x60}, ++/*isp*/ ++{0x0102,0x89}, ++{0x0104,0x01}, ++/*blk*/ ++{0x0026,0x20}, ++{0x0142,0x00}, ++{0x0149,0x1e}, ++{0x014a,0x07}, ++{0x014b,0x80}, ++{0x0155,0x07}, ++{0x0414,0x7e}, ++{0x0415,0x7e}, ++{0x0416,0x7e}, ++{0x0417,0x7e}, ++/*window*/ ++{0x0192,0x02}, ++{0x0194,0x03}, ++{0x0195,0x04}, ++{0x0196,0x38}, ++{0x0197,0x07}, ++{0x0198,0x80}, ++/****DVP & MIPI****/ ++{0x019a,0x06}, ++//{0x007b,0x2a}, ++{0x0023,0x2d}, ++{0x0201,0x20}, ++{0x0202,0x56}, ++{0x0203,0xb2}, ++{0x0212,0x80}, ++{0x0213,0x07}, ++{0x003e,0x40}, ++ ++ {GC2093_REG_END, 0x00}, ++}; ++ ++static struct regval_list gc2093_init_regs_1920_1080_60fps_mipi[] = { ++//mclk=27mhz ++//pclk:148.5Mhz ++//Linelength:2200 ++//row time:14.814us ++//frame rate:60fps ++//window height:1125 ++//size:1920*1080 ++/****system****/ ++ {0x03fe, 0x80}, ++ {0x03fe, 0x80}, ++ {0x03fe, 0x80}, ++ {0x03fe, 0x00}, ++ {0x03f2, 0x00}, ++ {0x03f3, 0x0f}, ++ {0x03f4, 0x36}, ++ {0x03f5, 0xc0}, ++ {0x03f6, 0x42}, ++ {0x03f7, 0x01}, ++ {0x03f8, 0x2c}, ++ {0x03f9, 0x82}, // I2C transfer error, ABORT interrupt ++ {0x03fc, 0x8e}, ++ /****CISCTL & ANALOG****/ ++ {0x0087, 0x18}, ++ {0x00ee, 0x30}, ++ {0x00d0, 0xb7}, ++ {0x01a0, 0x00}, ++ {0x01a4, 0x40}, ++ {0x01a5, 0x40}, ++ {0x01a6, 0x40}, ++ {0x01af, 0x09}, ++ {0x0001, 0x00}, ++ {0x0002, 0x02}, ++ {0x0003, 0x00}, ++ {0x0004, 0x02}, ++ {0x0005, 0x02}, ++ {0x0006, 0x26}, ++ {0x0007, 0x00}, ++ {0x0008, 0x11}, ++ {0x0009, 0x00}, ++ {0x000a, 0x02}, ++ {0x000b, 0x00}, ++ {0x000c, 0x04}, ++ {0x000d, 0x04}, ++ {0x000e, 0x40}, ++ {0x000f, 0x07}, ++ {0x0010, 0x8c}, ++ {0x0013, 0x15}, ++ {0x0019, 0x0c}, ++ {0x0041, 0x04}, ++ {0x0042, 0x65}, ++ {0x0053, 0x60}, ++ {0x008d, 0x92}, ++ {0x0090, 0x00}, ++ {0x0053, 0x60}, ++ {0x00c7, 0xe1}, ++ {0x001b, 0x73}, ++ {0x0028, 0x0d}, ++ {0x0029, 0x24}, ++ {0x002b, 0x04}, ++ {0x002e, 0x23}, ++ {0x0037, 0x03}, ++ {0x0043, 0x04}, ++ {0x0044, 0x20}, ++ {0x0046, 0x0b}, ++ {0x004a, 0x01}, ++ {0x004b, 0x20}, ++ {0x0055, 0x20}, ++ {0x0068, 0x20}, ++ {0x0069, 0x20}, ++ {0x0077, 0x00}, ++ {0x0078, 0x04}, ++ {0x007c, 0x91}, ++ {0x00ce, 0x7c}, ++ {0x00d3, 0xdc}, ++ {0x00e6, 0x50}, ++ /*gain*/ ++ {0x00b6, 0xc0}, ++ {0x00b0, 0x60}, ++ /*isp*/ ++ {0x0102, 0x89}, ++ {0x0104, 0x01}, ++ /*blk*/ ++ {0x0026, 0x20}, ++ {0x0142, 0x00}, ++ {0x0149, 0x1e}, ++ {0x014a, 0x07}, ++ {0x014b, 0x80}, ++ {0x0155, 0x07}, ++ {0x0414, 0x7e}, ++ {0x0415, 0x7e}, ++ {0x0416, 0x7e}, ++ {0x0417, 0x7e}, ++ /*window*/ ++ {0x0192, 0x02}, ++ {0x0194, 0x03}, ++ {0x0195, 0x04}, ++ {0x0196, 0x38}, ++ {0x0197, 0x07}, ++ {0x0198, 0x80}, ++ /****DVP & MIPI****/ ++ {0x019a, 0x06}, ++ //{0x007b, 0x2a}, // I2C transfer error, ABORT interrupt ++ {0x0023, 0x2d}, ++ {0x0201, 0x20}, ++ {0x0202, 0x56}, ++ {0x0203, 0xb2}, ++ {0x0212, 0x80}, ++ {0x0213, 0x07}, ++ {0x003e, 0x40}, ++ {GC2093_REG_END, 0x00}, ++}; ++ ++static struct regval_list gc2093_stream_on[] = { ++ {GC2093_REG_END, 0x00}, ++}; ++ ++static struct regval_list gc2093_stream_off[] = { ++ {GC2093_REG_END, 0x00}, ++}; ++ ++ ++int gc2093_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2]={(reg>>8)&0xff,reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3]={(reg>>8)&0xff,reg&0xff,value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != GC2093_REG_END) { ++ if (vals->reg_num == GC2093_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc2093_read(sd, vals->reg_num, &val); ++ printk("%s() 0x%02x, 0x%02x\n", __func__, vals->reg_num, val); ++ if (ret < 0) ++ { ++ return ret; ++ } ++ } ++ vals++; ++ } ++ return 0; ++} ++static int gc2093_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != GC2093_REG_END) { ++ if (vals->reg_num == GC2093_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = gc2093_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int gc2093_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2093_info *info = to_state(sd); ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(20); ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(20); ++ } ++ return 0; ++} ++ ++static int gc2093_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2093_info *info = to_state(sd); ++return 0; ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++ ++static int gc2093_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ ++ ret = gc2093_read(sd, GC2093_REG_CHIP_ID_HIGH, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC2093_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = gc2093_read(sd, GC2093_REG_CHIP_ID_LOW, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != GC2093_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ printk(" gc2093 id %x\n", *ident); ++ return 0; ++} ++ ++static int gm8914_i2c_read(unsigned int reg, unsigned int *data); ++static int gm8914_i2c_write(unsigned int reg, unsigned int data); ++static int gm8913_i2c_read(unsigned int reg, unsigned int *data); ++static int gm8913_i2c_write(unsigned int reg, unsigned int data); ++ ++ ++static int I2C_write(int addr, int reg, int data) ++{ ++ switch(addr) { ++ case 0xC0: ++ gm8914_i2c_write(reg, data); ++ break; ++ case 0x32: ++ gm8913_i2c_write(reg, data); ++ break; ++ /* ++ case 0x52: ++ gc2093_i2c_write(reg, data); ++ break;*/ ++ default: ++ printk("%s() error slave i2c addr: 0x%x\n", __func__, addr); ++ } ++ ++ return; ++} ++ ++static int gm8914_gm8913_init(void) ++{ ++ I2C_write(0xC0, 0x50, 0x32); ++ I2C_write(0xC0, 0x54, 0x02); ++ I2C_write(0xC0, 0x04, 0x07); ++ mdelay(10); ++ ++ I2C_write(0xC0, 0x07, 0x32); ++ mdelay(10); ++ I2C_write(0x32, 0x11, 0x31); // i2c 100kHz ++ I2C_write(0x32, 0x12, 0x31); // i2c 100kHz ++ I2C_write(0x32, 0x53, 0x3f); ++ //I2C_write(0x32, 0x53, 0x0f); ++ mdelay(10); ++ I2C_write(0xC0, 0x08, 0x6e); // sensor id: 0x6e/6f, ++ I2C_write(0xC0, 0x10, 0x52); ++ mdelay(10); ++} ++ ++ ++static int gc2093_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct gc2093_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret = 0; ++ ++ ret = gc2093_write_array(sd, info->win->regs); ++ if (ret < 0) { ++ dev_err(&client->dev, "%s: Error\n", __func__); ++ return ret; ++ } ++#if 1 ++ ret = gc2093_read_array(sd, info->win->regs); ++ if (ret < 0) { ++ dev_err(&client->dev, "%s: Error\n", __func__); ++ return ret; ++ } ++#endif ++ return ret; ++} ++ ++ ++static struct gc2093_win_size gc2093_win_sizes[] = { ++ { ++ .width = 1920, ++ .height = 1080, ++ .fps = 30 << 16 | 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = gc2093_init_regs_1920_1080_30fps_mipi, ++ //.regs = gc2093_init_regs_1920_1080_60fps_mipi, ++ }, ++ ++}; ++static const struct gc2093_win_size *gc2093_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(gc2093_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(gc2093_win_sizes); i++) { ++ if ((*width >= gc2093_win_sizes[i].width) && ++ (*height >= gc2093_win_sizes[i].height)) { ++ *width = gc2093_win_sizes[i].width; ++ *height = gc2093_win_sizes[i].height; ++ return &gc2093_win_sizes[i]; ++ } ++ } ++ ++ *width = gc2093_win_sizes[default_size].width; ++ *height = gc2093_win_sizes[default_size].height; ++ printk("------w=%d,h=%d--default_size=%d---->line=%d,func=%s\n",*width,*height,default_size,__LINE__,__func__); ++ return &gc2093_win_sizes[default_size]; ++} ++ ++static int gc2093_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_gc2093_FMTS) ++ return -EINVAL; ++ ++ code->code = gc2093_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int gc2093_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc2093_format_struct *ovfmt; ++ struct gc2093_win_size *wsize; ++ struct gc2093_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++// info->win = gc2093_select_win(&format->format.width, &format->format.height); ++ ++ ++ return 0; ++} ++ ++static int gc2093_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct gc2093_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ ++ ++ printk("----%s, %d, width: %d, height: %d, code: %x\n", ++ __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int gc2093_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int gc2093_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int gc2093_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++#if 0 ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(gc2093_again_lut); i++) { ++ lut = &gc2093_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(gc2093_again_lut); i++) { ++ lut = &gc2093_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++#endif ++ ++static int gc2093_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++// printk("~~~g_again=%d\n",*value); ++#if 1 ++ return 0; ++#else ++ char v=0; ++ unsigned int reg_val=0; ++ int ret=0; ++ int i=0; ++ int total; ++ total = sizeof(gainLevelTable) / sizeof(unsigned int); ++ ++ ret=gc2093_read(sd,0x00b1,&v); ++ reg_val|=(v<<6); ++ ret+=gc2093_read(sd,0x00b2,&v); ++ reg_val|=((v>>2)|0x3f); ++ ++ for (i = 0; i < total; i++) ++ { ++ if ((gainLevelTable[i] <= reg_val)&&(reg_val < gainLevelTable[i+1])) ++ { ++ *value=reg_val; ++ break; ++ } ++ } ++ return ret; ++#endif ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int gc2093_s_again(struct v4l2_subdev *sd, int value) ++{ ++// printk("~~~s_again=%d\n",value); ++ int index; ++ //return 0; ++ ++#if 1 ++ int i,ret=0; ++ int total; ++ unsigned int tol_dig_gain = 0; ++ ++ total = sizeof(gainLevelTable) / sizeof(unsigned int); ++ ++ for (i = 0; i < total; i++) ++ { ++ //if ((regValTable[i][8] <= value)&&(value < regValTable[i+1][8])) ++ if (value <= regValTable_t30[i][7]) ++ break; ++ } ++// printk("~~i=%d,~~~gainLevelTable[i]=%d\n",i,gainLevelTable[i]); ++// printk("~~~regValTable[i][7]=%d\n",regValTable[i][7]); ++ tol_dig_gain = value*64/regValTable_t30[i][7]; ++ ++ ret += gc2093_write(sd,0x00b3,regValTable_t30[i][0]); ++ ret += gc2093_write(sd,0x00b8,regValTable_t30[i][1]); ++ ret += gc2093_write(sd,0x00b9,regValTable_t30[i][2]); ++ ret += gc2093_write(sd,0x0155,regValTable_t30[i][3]); ++ gc2093_write(sd,0x031d,0x2d); ++ // ret += gc2093_write(sd,0x00c2,regValTable_t30[i][4]); ++ // ret += gc2093_write(sd,0x00cf,regValTable_t30[i][5]); ++ // ret += gc2093_write(sd,0x00d9,regValTable_t30[i][6]); ++ gc2093_write(sd,0x031d,0x28); ++ ++ ret +=gc2093_write(sd,0x00b1,(tol_dig_gain>>6)); ++ ret +=gc2093_write(sd,0x00b2,((tol_dig_gain&0x3f)<<2)); ++ if (ret < 0) { ++ printk("gc2093_write error %d" ,__LINE__ ); ++ return ret; ++ } ++#endif ++ return 0; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int gc2093_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int gc2093_s_exp(struct v4l2_subdev *sd, int intt) ++{ ++ int line_frame_total=1200; ++ int frame_length; ++ if(intt>line_frame_total) ++ frame_length=intt+1; ++ else ++ frame_length=line_frame_total; ++ gc2093_write(sd,0x0003,(intt>>8)&0x3f); ++ gc2093_write(sd,0x0004,intt & 0xff); ++ return 0; ++} ++ ++static int gc2093_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc2093_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return gc2093_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc2093_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int gc2093_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct gc2093_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return gc2093_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return gc2093_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return gc2093_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return gc2093_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* gc2093_s_gain turns off auto gain */ ++ return gc2093_s_gain(sd, info->gain->val); ++ } ++ return gc2093_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return gc2093_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return gc2093_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return gc2093_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops gc2093_ctrl_ops = { ++ .s_ctrl = gc2093_s_ctrl, ++ .g_volatile_ctrl = gc2093_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int gc2093_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = gc2093_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int gc2093_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ gc2093_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int gc2093_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct gc2093_info *info = to_state(sd); ++ int ret = 0; ++ int val=0; ++ printk("------------>line=%d,func=%s\n",__LINE__,__func__); ++ if (enable) { ++ // ret = gc2093_write_array(sd, info->win->regs); ++ // if(ret<0) ++ // return ret; ++ ret = gc2093_write_array(sd, gc2093_stream_on); ++ ++ // ret = gc2093_read(sd, 0x0199, &val); ++ ++ pr_debug("gc2093 stream on\n"); ++ printk("----on-------->line=%d,func=%s\n",__LINE__,__func__); ++ ++ } ++ else { ++ ret = gc2093_write_array(sd, gc2093_stream_off); ++ pr_debug("gc2093 stream off\n"); ++ printk("----off-------->line=%d,func=%s\n",__LINE__,__func__); ++ } ++ return ret; ++} ++ ++int gc2093_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct gc2093_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops gc2093_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = gc2093_g_register, ++ .s_register = gc2093_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops gc2093_video_ops = { ++ .s_stream = gc2093_s_stream, ++ .g_frame_interval = gc2093_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops gc2093_pad_ops = { ++ //.enum_frame_interval = gc2093_enum_frame_interval, ++ //.num_frame_size = gc2093_enum_frame_size, ++ //.enum_mbus_code = gc2093_enum_mbus_code, ++ .set_fmt = gc2093_set_fmt, ++ .get_fmt = gc2093_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops gc2093_ops = { ++ .core = &gc2093_core_ops, ++ .video = &gc2093_video_ops, ++ .pad = &gc2093_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int gc2093_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct gc2093_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ printk(" gc2093 probe \n\n"); ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &gc2093_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 27000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ gc2093_reset(sd, 1); ++ ++ gm8914_gm8913_init(); ++ ++ /* Make sure it's an gc2093 */ ++ ret = gc2093_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an gc2093 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++// gc2093_ircut(sd, 0); ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ // V4L2_CID_ANALOGUE_GAIN, 0, 259142, 1, 10000); ++ V4L2_CID_ANALOGUE_GAIN, 0, 405939, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &gc2093_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1899 - 4, 1, 1500); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &gc2093_win_sizes[0];//720p ++// info->win = &gc2093_win_sizes[1];//1080*360 ++// info->win = &gc2093_win_sizes[2];//720*360 ++ ++ gc2093_init(sd, 1); ++ ++ gc2093_init(sd, 1); /* try 2 time init. */ ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ } ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "gc2093 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int gc2093_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct gc2093_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id gc2093_id[] = { ++ { "gc2093", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, gc2093_id); ++ ++static const struct of_device_id gc2093_of_match[] = { ++ {.compatible = "galaxyc,gc2093", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, gc2093_of_match); ++ ++ ++static struct i2c_driver gc2093_driver = { ++ .driver = { ++ .name = "gc2093", ++ .of_match_table = of_match_ptr(gc2093_of_match), ++ }, ++ .probe = gc2093_probe, ++ .remove = gc2093_remove, ++ .id_table = gc2093_id, ++}; ++ ++module_i2c_driver(gc2093_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for galaxyc gc2093 sensors"); ++MODULE_LICENSE("GPL"); ++ ++ ++/* ================================= GM8913 ===================================== */ ++ ++struct gm8913_info { ++ struct i2c_client *i2c; ++ struct i2c_device_id *id; ++}; ++ ++static struct gm8913_info *gm8913info; ++ ++static int gm8913_read(struct i2c_client *i2c, unsigned char reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = i2c; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 1, ++ .buf = ®, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gm8913_write(struct i2c_client *i2c, unsigned char reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = i2c; ++ unsigned char buf[2] = {reg, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gm8913_i2c_read(unsigned int reg, unsigned int *data) ++{ ++ int ret; ++ if (gm8913info==NULL) ++ return -1; ++ ++ ret = gm8913_read(gm8913info->i2c, reg, (unsigned char *)data); ++ printk("%s() gm8913info=%p, reg=%02x, data=%02x\n", __func__, gm8913info, reg, *data); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int gm8913_i2c_write(unsigned int reg, unsigned int data) ++{ ++ int ret; ++ printk("%s() gm8913info=%p, reg=%02x, data=%02x\n", __func__, gm8913info, reg, data); ++ if (gm8913info==NULL) ++ return -1; ++ ++ ret = gm8913_write(gm8913info->i2c, reg, data); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int gm8913_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct gm8913_info *info; ++ ++ printk("===========func=%s,line=%d\n\n",__func__,__LINE__); ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ gm8913info = info; ++ info->i2c = client; ++ ++ return 0; ++} ++ ++static int gm8913_remove(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static const struct i2c_device_id gm8913_id[] = { ++ { "gm8913", 0}, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(i2c, gm8913_id); ++ ++static const struct of_device_id gm8913_of_match[] = { ++ {.compatible = "zhenxin,gm8913", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, gm8913_of_match); ++ ++ ++static struct i2c_driver gm8913_driver = { ++ .driver = { ++ .name = "gm8913", ++ .of_match_table = of_match_ptr(gm8913_of_match), ++ }, ++ .probe = gm8913_probe, ++ .remove = gm8913_remove, ++ .id_table = gm8913_id, ++}; ++ ++module_i2c_driver(gm8913_driver); ++ ++/* ================================= GM8913 ===================================== */ ++ ++/* ================================= GM8914 ===================================== */ ++ ++struct gm8914_info { ++ struct i2c_client *i2c; ++ struct i2c_device_id *id; ++}; ++ ++static struct gm8914_info *gm8914info; ++ ++static int gm8914_read(struct i2c_client *i2c, unsigned char reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = i2c; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 1, ++ .buf = ®, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gm8914_write(struct i2c_client *i2c, unsigned char reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = i2c; ++ unsigned char buf[2] = {reg, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int gm8914_i2c_read(unsigned int reg, unsigned int *data) ++{ ++ int ret; ++ if (gm8914info==NULL) ++ return -1; ++ ++ ret = gm8914_read(gm8914info->i2c, reg, (unsigned char *)data); ++ printk("%s() gm8914info=%p, reg=%02x, data=%02x\n", __func__, gm8914info, reg, *data); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int gm8914_i2c_write(unsigned int reg, unsigned int data) ++{ ++ int ret; ++ printk("%s() gm8914info=%p, reg=%02x, data=%02x\n", __func__, gm8914info, reg, data); ++ if (gm8914info==NULL) ++ return -1; ++ ++ ret = gm8914_write(gm8914info->i2c, reg, data); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int gm8914_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct gm8914_info *info; ++ ++ printk("===========func=%s,line=%d\n\n",__func__,__LINE__); ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ gm8914info = info; ++ info->i2c = client; ++ ++ return 0; ++} ++ ++static int gm8914_remove(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static const struct i2c_device_id gm8914_id[] = { ++ { "gm8914", 0}, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(i2c, gm8914_id); ++ ++static const struct of_device_id gm8914_of_match[] = { ++ {.compatible = "zhenxin,gm8914", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, gm8914_of_match); ++ ++ ++static struct i2c_driver gm8914_driver = { ++ .driver = { ++ .name = "gm8914", ++ .of_match_table = of_match_ptr(gm8914_of_match), ++ }, ++ .probe = gm8914_probe, ++ .remove = gm8914_remove, ++ .id_table = gm8914_id, ++}; ++ ++module_i2c_driver(gm8914_driver); ++ ++/* ================================= GM8914 ===================================== */ ++ ++/* ================================= board dts ===================================== */ ++#if 0 ++&i2c3 { ++ status = "okay"; ++ clock-frequency = <100000>; ++ timeout = <1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c3_pa>; ++ ++ gm8914:gm8914@0x60 { ++ status = "ok"; ++ compatible = "zhenxin,gm8914"; ++ reg = <0x60>; ++ }; ++ gm8913:gm8913@0x19 { ++ status = "ok"; ++ compatible = "zhenxin,gm8913"; ++ reg = <0x19>; ++ }; ++ ++/* gc8914 sensor slave id :0x37*/ ++ ++ gc2093:gc2093@0x29 { ++ status = "ok"; ++ compatible = "galaxyc,gc2093"; ++ reg = <0x29>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&vic_pa_low_10bit>; ++ ++ port { ++ gc2093_ep0:endpoint { ++ remote-endpoint = <&isp0_ep>; ++ bus-width = <10>; /* Used data lines */ ++ data-shift = <0>; /* Lines 9:0 are used */ ++ ++ /* If hsync-active/vsync-active are missing, ++ embedded BT.656 sync is used */ ++ hsync-active = <1>; /* Active high */ ++ vsync-active = <1>; /* Active high */ ++ data-active = <1>; /* Active high */ ++ pclk-sample = <1>; /* Rising */ ++ }; ++ }; ++ ++ }; ++ ++}; ++ ++&isp0_ep { ++ remote-endpoint = <&gc2093_ep0>; ++ bus-width = <10>; /* Used data lines */ ++ data-shift = <0>; /* Lines 9:0 are used */ ++ ++ /* If hsync-active/vsync-active are missing, ++ embedded BT.656 sync is used */ ++ hsync-active = <1>; /* Active high */ ++ vsync-active = <1>; /* Active high */ ++ ++ data-active = <1>; /* Active high */ ++ pclk-sample = <1>; /* Rising */ ++}; ++#endif ++/* ================================= board dts ===================================== */ +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/hm2140.c b/module_drivers/drivers/media/i2c/ingenic-isp/hm2140.c +new file mode 100644 +index 000000000..b16d9310d +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/hm2140.c +@@ -0,0 +1,1091 @@ ++/* ++ * A V4L2 driver for Himax HM2140 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define HM2140_CHIP_ID_H (0x21) ++#define HM2140_CHIP_ID_L (0x40) ++#define HM2140_REG_END 0xff ++#define HM2140_REG_DELAY 0x00 ++#define HM2140_PAGE_REG 0xfd ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct hm2140_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct hm2140_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct hm2140_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct hm2140_win_size *win; ++ ++ struct hm2140_gpio pwdn; ++ struct hm2140_gpio sync; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++ ++struct again_lut hm2140_again_lut[] ={ ++ {0x00, 0}, ++ {0x01, 4096}, ++ {0x02, 8192}, ++ {0x03, 12288}, ++ {0x04, 16384}, ++ {0x05, 20480}, ++ {0x06, 24576}, ++ {0x07, 28672}, ++ {0x08, 32768}, ++ {0x09, 36864}, ++ {0x0A, 40960}, ++ {0x0B, 45056}, ++ {0x0C, 49152}, ++ {0x0D, 53248}, ++ {0x0E, 57344}, ++ {0x0F, 61440}, ++ {0x10, 65536}, ++ {0x12, 69632}, ++ {0x14, 73728}, ++ {0x16, 77824}, ++ {0x18, 81920}, ++ {0x1A, 86016}, ++ {0x1C, 90112}, ++ {0x1E, 94208}, ++ {0x20, 98304}, ++ {0x22, 102400}, ++ {0x24, 106496}, ++ {0x26, 110592}, ++ {0x28, 114688}, ++ {0x2A, 118784}, ++ {0x2C, 122880}, ++ {0x2E, 126976}, ++ {0x30, 131072}, ++ {0x34, 135168}, ++ {0x38, 139264}, ++ {0x3C, 143360}, ++ {0x40, 147456}, ++ {0x44, 151552}, ++ {0x48, 155648}, ++ {0x4C, 159744}, ++ {0x50, 163840}, ++ {0x54, 167936}, ++ {0x58, 172032}, ++ {0x5C, 176128}, ++ {0x60, 180224}, ++ {0x64, 184320}, ++ {0x68, 188416}, ++ {0x6C, 192512}, ++ {0x70, 196608}, ++}; ++ ++static inline struct hm2140_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct hm2140_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct hm2140_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list hm2140_init_regs_1920_1080_30fps_MIPI[] = { ++ {0x0103, 0x00}, ++ {HM2140_REG_DELAY, 5}, ++ {0x5227, 0x74}, ++ {0x030B, 0x11}, ++ {HM2140_REG_DELAY, 100}, ++ {0x0307, 0x00}, ++ {0x0309, 0x00}, ++ {0x030A, 0x0A}, ++ {0x030D, 0x03}, ++ {0x030F, 0x2B}, ++ {0x5235, 0xA4}, ++ {0x5236, 0x92}, ++ {0x5237, 0x23}, ++ {0x5238, 0xDC}, ++ {0x5239, 0x01}, ++ {0x0100, 0x02}, ++ {0x4001, 0x00}, ++ {0x4002, 0x2B}, ++ {0x0101, 0x00}, ++ {0x4026, 0x3B}, ++ {0x0202, 0x04}, ++ {0x0203, 0x92}, ++ {0x0340, 0x04}, ++ {0x0341, 0x94}, ++ {0x0342, 0x08}, ++ {0x0343, 0x98}, ++ {0x034c, 0x07}, ++ {0x034d, 0x80}, ++ {0x034e, 0x04}, ++ {0x034f, 0x38}, ++ {0x0350, 0x73}, ++ {0x5015, 0x33}, ++ {0x50DD, 0x01}, ++ {0x50CB, 0xA3}, ++ {0x5004, 0x40}, ++ {0x5005, 0x28}, ++ {0x504D, 0x7F}, ++ {0x504E, 0x00}, ++ {0x5040, 0x07}, ++ {0x5011, 0x00}, ++ {0x501D, 0x4C}, ++ {0x5011, 0x0B}, ++ {0x5012, 0x01}, ++ {0x5013, 0x03}, ++ {0x4131, 0x01}, ++ {0x5282, 0xFF}, ++ {0x5283, 0x07}, ++ {0x5010, 0x20}, ++ {0x4132, 0x20}, ++ {0x50D5, 0xE0}, ++ {0x50D7, 0x12}, ++ {0x50BB, 0x14}, ++ {0x50B7, 0x00}, ++ {0x50B8, 0x35}, ++ {0x50B9, 0x11}, ++ {0x50BA, 0x30}, ++ {0x50B3, 0x24}, ++ {0x50B4, 0x00}, ++ {0x50FA, 0x02}, ++ {0x509B, 0x01}, ++ {0x50AA, 0xFF}, ++ {0x50AB, 0x45}, ++ {0x509C, 0x00}, ++ {0x50AD, 0x0C}, ++ {0x5096, 0x00}, ++ {0x50A1, 0x12}, ++ {0x50AF, 0x21}, ++ {0x50A0, 0x11}, ++ {0x50A2, 0x21}, ++ {0x509D, 0x20}, ++ {0x50AC, 0x55}, ++ {0x50AE, 0x26}, ++ {0x509E, 0x03}, ++ {0x509F, 0x01}, ++ {0x5097, 0x12}, ++ {0x5099, 0x00}, ++ {0x50B5, 0x00}, ++ {0x50B6, 0x10}, ++ {0x5094, 0x08}, ++ {0x5200, 0x43}, ++ {0x5201, 0xC0}, ++ {0x5202, 0x00}, ++ {0x5203, 0x00}, ++ {0x5204, 0x00}, ++ {0x5205, 0x05}, ++ {0x5206, 0xA1}, ++ {0x5207, 0x01}, ++ {0x5208, 0x0A}, ++ {0x5209, 0x0C}, ++ {0x520A, 0x00}, ++ {0x520B, 0x45}, ++ {0x520C, 0x15}, ++ {0x520D, 0x40}, ++ {0x520E, 0x50}, ++ {0x520F, 0x10}, ++ {0x5214, 0x40}, ++ {0x5215, 0x14}, ++ {0x5216, 0x00}, ++ {0x5217, 0x02}, ++ {0x5218, 0x07}, ++ {0x521C, 0x00}, ++ {0x521E, 0x00}, ++ {0x522A, 0x3F}, ++ {0x522C, 0x00}, ++ {0x5230, 0x00}, ++ {0x5232, 0x05}, ++ {0x523A, 0x20}, ++ {0x523B, 0x34}, ++ {0x523C, 0x03}, ++ {0x523D, 0x00}, ++ {0x523E, 0x00}, ++ {0x523F, 0x70}, ++ {0x50E8, 0x16}, ++ {0x50E9, 0x00}, ++ {0x50EB, 0x0F}, ++ {0x4B11, 0x0F}, ++ {0x4B12, 0x0F}, ++ {0x4B31, 0x04}, ++ {0x4B3B, 0x02}, ++ {0x4B44, 0x80}, ++ {0x4B45, 0x00}, ++ {0x4B47, 0x00}, ++ {0x4B4E, 0x30}, ++ {0x4020, 0x20}, ++ {0x5100, 0x13}, ++ {0x5101, 0x2B}, ++ {0x5102, 0x3B}, ++ {0x5103, 0x4B}, ++ {0x5104, 0x5F}, ++ {0x5105, 0x6F}, ++ {0x5106, 0x7F}, ++ {0x5108, 0x00}, ++ {0x5109, 0x00}, ++ {0x510A, 0x00}, ++ {0x510B, 0x00}, ++ {0x510C, 0x00}, ++ {0x510D, 0x00}, ++ {0x510E, 0x00}, ++ {0x5110, 0x0E}, ++ {0x5111, 0x0E}, ++ {0x5112, 0x0E}, ++ {0x5113, 0x0E}, ++ {0x5114, 0x0E}, ++ {0x5115, 0x0E}, ++ {0x5116, 0x0E}, ++ {0x5118, 0x09}, ++ {0x5119, 0x09}, ++ {0x511A, 0x09}, ++ {0x511B, 0x09}, ++ {0x511C, 0x09}, ++ {0x511D, 0x09}, ++ {0x511E, 0x09}, ++ {0x5120, 0xEA}, ++ {0x5121, 0x6A}, ++ {0x5122, 0x6A}, ++ {0x5123, 0x6A}, ++ {0x5124, 0x6A}, ++ {0x5125, 0x6A}, ++ {0x5126, 0x6A}, ++ {0x5140, 0x0B}, ++ {0x5141, 0x1B}, ++ {0x5142, 0x2B}, ++ {0x5143, 0x3B}, ++ {0x5144, 0x4B}, ++ {0x5145, 0x5B}, ++ {0x5146, 0x6B}, ++ {0x5148, 0x02}, ++ {0x5149, 0x02}, ++ {0x514A, 0x02}, ++ {0x514B, 0x02}, ++ {0x514C, 0x02}, ++ {0x514D, 0x02}, ++ {0x514E, 0x02}, ++ {0x5150, 0x08}, ++ {0x5151, 0x08}, ++ {0x5152, 0x08}, ++ {0x5153, 0x08}, ++ {0x5154, 0x08}, ++ {0x5155, 0x08}, ++ {0x5156, 0x08}, ++ {0x5158, 0x02}, ++ {0x5159, 0x02}, ++ {0x515A, 0x02}, ++ {0x515B, 0x02}, ++ {0x515C, 0x02}, ++ {0x515D, 0x02}, ++ {0x515E, 0x02}, ++ {0x5160, 0x66}, ++ {0x5161, 0x66}, ++ {0x5162, 0x66}, ++ {0x5163, 0x66}, ++ {0x5164, 0x66}, ++ {0x5165, 0x66}, ++ {0x5166, 0x66}, ++ {0x5180, 0x00}, ++ {0x5189, 0x00}, ++ {0x5192, 0x00}, ++ {0x519B, 0x00}, ++ {0x51A4, 0x00}, ++ {0x51AD, 0x00}, ++ {0x51B6, 0x00}, ++ {0x51C0, 0x00}, ++ {0x5181, 0x00}, ++ {0x518A, 0x00}, ++ {0x5193, 0x00}, ++ {0x519C, 0x00}, ++ {0x51A5, 0x00}, ++ {0x51AE, 0x00}, ++ {0x51B7, 0x00}, ++ {0x51C1, 0x00}, ++ {0x5182, 0x85}, ++ {0x518B, 0x85}, ++ {0x5194, 0x85}, ++ {0x519D, 0x85}, ++ {0x51A6, 0x85}, ++ {0x51AF, 0x85}, ++ {0x51B8, 0x85}, ++ {0x51C2, 0x85}, ++ {0x5183, 0x52}, ++ {0x518C, 0x52}, ++ {0x5195, 0x52}, ++ {0x519E, 0x52}, ++ {0x51A7, 0x52}, ++ {0x51B0, 0x52}, ++ {0x51B9, 0x52}, ++ {0x51C3, 0x52}, ++ {0x5184, 0x00}, ++ {0x518D, 0x00}, ++ {0x5196, 0x08}, ++ {0x519F, 0x08}, ++ {0x51A8, 0x08}, ++ {0x51B1, 0x08}, ++ {0x51BA, 0x08}, ++ {0x51C4, 0x08}, ++ {0x5185, 0x73}, ++ {0x518E, 0x73}, ++ {0x5197, 0x73}, ++ {0x51A0, 0x73}, ++ {0x51A9, 0x73}, ++ {0x51B2, 0x73}, ++ {0x51BB, 0x73}, ++ {0x51C5, 0x73}, ++ {0x5186, 0x34}, ++ {0x518F, 0xA4}, ++ {0x5198, 0x34}, ++ {0x51A1, 0x34}, ++ {0x51AA, 0x34}, ++ {0x51B3, 0x3F}, ++ {0x51BC, 0x3F}, ++ {0x51C6, 0x3F}, ++ {0x5187, 0x40}, ++ {0x5190, 0x38}, ++ {0x5199, 0x20}, ++ {0x51A2, 0x08}, ++ {0x51AB, 0x04}, ++ {0x51B4, 0x04}, ++ {0x51BD, 0x02}, ++ {0x51C7, 0x01}, ++ {0x5188, 0x20}, ++ {0x5191, 0x40}, ++ {0x519A, 0x40}, ++ {0x51A3, 0x40}, ++ {0x51AC, 0x40}, ++ {0x51B5, 0x78}, ++ {0x51BE, 0x78}, ++ {0x51C8, 0x78}, ++ {0x51E1, 0x07}, ++ {0x51E3, 0x07}, ++ {0x51E5, 0x07}, ++ {0x51ED, 0x00}, ++ {0x51EE, 0x00}, ++ {0x4002, 0x2B}, ++ {0x3132, 0x00}, ++ {0x4024, 0x40}, ++ {0x5229, 0xFC}, ++ {0x4002, 0x2B}, ++ {0x3110, 0x03}, ++ {0x373D, 0x12}, ++ {0xBAA2, 0xC0}, ++ {0xBAA2, 0x40}, ++ {0xBA90, 0x01}, ++ {0xBA93, 0x02}, ++ {0x350D, 0x01}, ++ {0x3514, 0x00}, ++ {0x350C, 0x01}, ++ {0x3519, 0x00}, ++ {0x351A, 0x01}, ++ {0x351B, 0x1E}, ++ {0x351C, 0x90}, ++ {0x351E, 0x05}, ++ {0x351D, 0x05}, ++ {0x4B20, 0x8E}, ++ {0x4B18, 0x00}, ++ {0x4B3E, 0x00}, ++ {0x4B0E, 0x21}, ++#if 0 // test pattern ++ {0x4026, 0x3a}, ++ {0x0601, 0x02}, ++ {0x3110, 0x01}, ++ {0x3735, 0x00}, ++ {0x5013, 0x00}, ++ {0x501d, 0x04}, ++ {0x4131, 0x00}, ++#endif ++ {0x0104, 0x01}, ++ {0x0104, 0x00}, ++ {0x0100, 0x00}, ++ {HM2140_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++ ++static struct regval_list hm2140_stream_on[] = { ++ {0x0100, 0x01}, ++ {HM2140_REG_END, 0x00}, ++}; ++ ++static struct regval_list hm2140_stream_off[] = { ++ {0x0100, 0x00}, ++ {HM2140_REG_END, 0x00}, ++}; ++ ++/* read a register */ ++static int hm2140_read(struct v4l2_subdev *sd, uint16_t reg, uint8_t *val) ++{ ++ int ret; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(uint8_t)((reg & 0xFF00) >> 8), (uint8_t)((reg & 0x00FF))}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = val, ++ }, ++ }; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/* write a register */ ++static int hm2140_write(struct v4l2_subdev *sd, uint16_t reg, uint8_t val) ++{ ++ int ret; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3]; ++ struct i2c_msg msg; ++ ++ buf[0] = (uint8_t)((reg & 0xFF00) >> 8); ++ buf[1] = (uint8_t)((reg & 0x00FF)); ++ buf[2] = val; ++ ++ msg.addr = client->addr; ++ msg.flags = 0; ++ msg.len = 3; ++ msg.buf = buf; ++ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret < 0) { ++ dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int hm2140_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != HM2140_REG_END) { ++ if (vals->reg_num == HM2140_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = hm2140_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ if (vals->reg_num == HM2140_PAGE_REG){ ++ val &= 0xf8; ++ val |= (vals->value & 0x07); ++ ret = hm2140_write(sd, vals->reg_num, val); ++ ret = hm2140_read(sd, vals->reg_num, &val); ++ } ++ } ++ vals++; ++ } ++ return 0; ++} ++static int hm2140_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != HM2140_REG_END) { ++ if (vals->reg_num == HM2140_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = hm2140_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int hm2140_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct hm2140_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->pwdn.pin, info->pwdn.active_level); ++ msleep(10); ++ gpio_direction_output(info->pwdn.pin, !info->pwdn.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++ ++static int hm2140_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ ret = hm2140_read(sd, 0x0000, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != HM2140_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = hm2140_read(sd, 0x0001, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != HM2140_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++ ++static struct hm2140_win_size hm2140_win_sizes[] = { ++ /* 1920*1080 */ ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 30 << 16 | 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = hm2140_init_regs_1920_1080_30fps_MIPI, ++ } ++}; ++ ++static int hm2140_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_HM2140_FMTS) ++ return -EINVAL; ++ ++ code->code = hm2140_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int hm2140_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct hm2140_format_struct *ovfmt; ++ struct hm2140_win_size *wsize; ++ struct hm2140_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int hm2140_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct hm2140_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int hm2140_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int hm2140_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int hm2140_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int hm2140_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int hm2140_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int hm2140_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(hm2140_again_lut); i++) { ++ lut = &hm2140_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(hm2140_again_lut); i++) { ++ lut = &hm2140_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++ ++static int hm2140_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ struct hm2140_info *info = to_state(sd); ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret += hm2140_read(sd, 0x0205, &v); ++ reg_val |= v; ++ ++ *value = regval_to_again(reg_val); ++ return ret; ++} ++ ++static int hm2140_s_again(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ struct hm2140_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int i; ++ ++ printk("[%s %d ]````\n", __func__, __LINE__); ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += hm2140_write(sd, 0x0205, (unsigned char)(reg_value & 0xff)); ++ ret += hm2140_write(sd, 0x0104, 0x01); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int hm2140_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int hm2140_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct hm2140_info *info = to_state(sd); ++ int ret = 0; ++ ret += hm2140_write(sd, 0x0203, ((unsigned char)(value & 0xff))); ++ ret += hm2140_write(sd, 0x0202, ((unsigned char)(value >> 8)) & 0xff); ++ ret += hm2140_write(sd, 0x0104, 0x01); ++ return 0; ++} ++ ++static int hm2140_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct hm2140_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return -EINVAL; //hm2140_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return hm2140_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int hm2140_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct hm2140_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return hm2140_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return hm2140_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return hm2140_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return hm2140_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* hm2140_s_gain turns off auto gain */ ++ return hm2140_s_gain(sd, info->gain->val); ++ } ++ return hm2140_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return hm2140_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return hm2140_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return hm2140_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops hm2140_ctrl_ops = { ++ .s_ctrl = hm2140_s_ctrl, ++ .g_volatile_ctrl = hm2140_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int hm2140_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = hm2140_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int hm2140_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ hm2140_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int hm2140_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ int ret = 0; ++ ++ if (enable) { ++ ret = hm2140_write_array(sd, hm2140_stream_on); ++ printk("hm2140 stream on\n"); ++ } ++ else { ++ ret = hm2140_write_array(sd, hm2140_stream_off); ++ printk("hm2140 stream off\n"); ++ } ++ return ret; ++} ++ ++ ++int hm2140_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct hm2140_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops hm2140_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = hm2140_g_register, ++ .s_register = hm2140_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops hm2140_video_ops = { ++ .s_stream = hm2140_s_stream, ++ .g_frame_interval = hm2140_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops hm2140_pad_ops = { ++ //.enum_frame_interval = hm2140_enum_frame_interval, ++ //.num_frame_size = hm2140_enum_frame_size, ++ //.enum_mbus_code = hm2140_enum_mbus_code, ++ .set_fmt = hm2140_set_fmt, ++ .get_fmt = hm2140_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops hm2140_ops = { ++ .core = &hm2140_core_ops, ++ .video = &hm2140_video_ops, ++ .pad = &hm2140_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int hm2140_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct hm2140_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ printk("------------%s, %d\n", __func__, __LINE__); ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwdn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwdn.pin = gpio; ++ info->pwdn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,sync-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->sync.pin = gpio; ++ info->sync.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &hm2140_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ info->win = &hm2140_win_sizes[0]; ++ ++ hm2140_reset(sd, 1); ++ /* Make sure it's an hm2140 */ ++ ret = hm2140_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an hm2140 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ret = hm2140_write_array(sd, info->win->regs); ++ if (ret) { ++ v4l_err(client, ++ "hm2140 init failed!\n"); ++ return ret; ++ } ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &hm2140_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &hm2140_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &hm2140_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &hm2140_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &hm2140_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &hm2140_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 262144, 1, 1); ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &hm2140_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 1080, 1, 0x0108); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "hm2140 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int hm2140_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct hm2140_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id hm2140_id[] = { ++ { "hm2140", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, hm2140_id); ++ ++static const struct of_device_id hm2140_of_match[] = { ++ {.compatible = "himax,hm2140", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, hm2140_of_match); ++ ++ ++static struct i2c_driver hm2140_driver = { ++ .driver = { ++ .name = "hm2140", ++ .of_match_table = of_match_ptr(hm2140_of_match), ++ }, ++ .probe = hm2140_probe, ++ .remove = hm2140_remove, ++ .id_table = hm2140_id, ++}; ++ ++module_i2c_driver(hm2140_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for Himax hm2140 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/imx335.c b/module_drivers/drivers/media/i2c/ingenic-isp/imx335.c +new file mode 100644 +index 000000000..4a68885db +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/imx335.c +@@ -0,0 +1,1429 @@ ++/* ++ * A V4L2 driver for Sony imx335 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ * ++ * imx335 datasheet description: ++ * Input frequency: 6 to 27 MHz / 37.125 MHz / 74.25 MHz ++ * â—† Built-in timing adjustment circuit, H/V driver and serial communication circuit ++ * â—† Number of recommended recording pixels: 2592 (H) × 1944 (V) approx. 5.04M pixel ++ * uboot epll clock config:#define CONFIG_SYS_EPLL_FREQ 297000000 ++ */ ++#define DEBUG ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define IMX335_CHIP_ID_H (0x08) ++#define IMX335_CHIP_ID_L (0x00) ++#define IMX335_REG_CHIP_ID_HIGH 0x3112 ++#define IMX335_REG_CHIP_ID_LOW 0x3113 ++#define IMX335_REG_END 0xffff ++#define IMX335_REG_DELAY 0x00 ++#define IMX335_PAGE_REG 0xfd ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct imx335_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct imx335_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct imx335_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ struct clk *sclka; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct imx335_win_size *win; ++ ++ struct imx335_gpio pwr; ++ ++ struct imx335_gpio reset; ++ struct imx335_gpio pwdn; ++ struct imx335_gpio ircutp; ++ struct imx335_gpio ircutn; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; ++ unsigned int gain; ++}; ++ ++static inline struct imx335_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct imx335_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct imx335_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++ ++struct again_lut imx335_again_lut[] = { ++ /* analog gain */ ++ {0x0, 0}, ++ {0x1, 3265}, ++ {0x2, 6531}, ++ {0x3, 9796}, ++ {0x4, 13062}, ++ {0x5, 16327}, ++ {0x6, 19593}, ++ {0x7, 22859}, ++ {0x8, 26124}, ++ {0x9, 29390}, ++ {0xa, 32655}, ++ {0xb, 35921}, ++ {0xc, 39187}, ++ {0xd, 42452}, ++ {0xe, 45718}, ++ {0xf, 48983}, ++ {0x10, 52249}, ++ {0x11, 55514}, ++ {0x12, 58780}, ++ {0x13, 62046}, ++ {0x14, 65311}, ++ {0x15, 68577}, ++ {0x16, 71842}, ++ {0x17, 75108}, ++ {0x18, 78374}, ++ {0x19, 81639}, ++ {0x1a, 84905}, ++ {0x1b, 88170}, ++ {0x1c, 91436}, ++ {0x1d, 94702}, ++ {0x1e, 97967}, ++ {0x1f, 101233}, ++ {0x20, 104498}, ++ {0x21, 107764}, ++ {0x22, 111029}, ++ {0x23, 114295}, ++ {0x24, 117561}, ++ {0x25, 120826}, ++ {0x26, 124092}, ++ {0x27, 127357}, ++ {0x28, 130623}, ++ {0x29, 133889}, ++ {0x2a, 137154}, ++ {0x2b, 140420}, ++ {0x2c, 143685}, ++ {0x2d, 146951}, ++ {0x2e, 150217}, ++ {0x2f, 153482}, ++ {0x30, 156748}, ++ {0x31, 160013}, ++ {0x32, 163279}, ++ {0x33, 166544}, ++ {0x34, 169810}, ++ {0x35, 173076}, ++ {0x36, 176341}, ++ {0x37, 179607}, ++ {0x38, 182872}, ++ {0x39, 186138}, ++ {0x3a, 189404}, ++ {0x3b, 192669}, ++ {0x3c, 195935}, ++ {0x3d, 199200}, ++ {0x3e, 202466}, ++ {0x3f, 205732}, ++ {0x40, 208997}, ++ {0x41, 212263}, ++ {0x42, 215528}, ++ {0x43, 218794}, ++ {0x44, 222059}, ++ {0x45, 225325}, ++ {0x46, 228591}, ++ {0x47, 231856}, ++ {0x48, 235122}, ++ {0x49, 238387}, ++ {0x4a, 241653}, ++ {0x4b, 244919}, ++ {0x4c, 248184}, ++ {0x4d, 251450}, ++ {0x4e, 254715}, ++ {0x4f, 257981}, ++ {0x50, 261247}, ++ {0x51, 264512}, ++ {0x52, 267778}, ++ {0x53, 271043}, ++ {0x54, 274309}, ++ {0x55, 277574}, ++ {0x56, 280840}, ++ {0x57, 284106}, ++ {0x58, 287371}, ++ {0x59, 290637}, ++ {0x5a, 293902}, ++ {0x5b, 297168}, ++ {0x5c, 300434}, ++ {0x5d, 303699}, ++ {0x5e, 306965}, ++ {0x5f, 310230}, ++ {0x60, 313496}, ++ {0x61, 316762}, ++ {0x62, 320027}, ++ {0x63, 323293}, ++ {0x64, 326558}, ++ /* analog+digital */ ++ {0x65, 329824}, ++ {0x66, 333089}, ++ {0x67, 336355}, ++ {0x68, 339621}, ++ {0x69, 342886}, ++ {0x6a, 346152}, ++ {0x6b, 349417}, ++ {0x6c, 352683}, ++ {0x6d, 355949}, ++ {0x6e, 359214}, ++ {0x6f, 362480}, ++ {0x70, 365745}, ++ {0x71, 369011}, ++ {0x72, 372277}, ++ {0x73, 375542}, ++ {0x74, 378808}, ++ {0x75, 382073}, ++ {0x76, 385339}, ++ {0x77, 388604}, ++ {0x78, 391870}, ++ {0x79, 395136}, ++ {0x7a, 398401}, ++ {0x7b, 401667}, ++ {0x7c, 404932}, ++ {0x7d, 408198}, ++ {0x7e, 411464}, ++ {0x7f, 414729}, ++ {0x80, 417995}, ++ {0x81, 421260}, ++ {0x82, 424526}, ++ {0x83, 427792}, ++ {0x84, 431057}, ++ {0x85, 434323}, ++ {0x86, 437588}, ++ {0x87, 440854}, ++ {0x88, 444119}, ++ {0x89, 447385}, ++ {0x8a, 450651}, ++ {0x8b, 453916}, ++ {0x8c, 457182}, ++ {0x8d, 460447}, ++ {0x8e, 463713}, ++ {0x8f, 466979}, ++ {0x90, 470244}, ++ {0x91, 473510}, ++ {0x92, 476775}, ++ {0x93, 480041}, ++ {0x94, 483307}, ++ {0x95, 486572}, ++ {0x96, 489838}, ++ {0x97, 493103}, ++ {0x98, 496369}, ++ {0x99, 499634}, ++ {0x9a, 502900},/*204x*/ ++ {0x9b, 506166}, ++ {0x9c, 509431}, ++ {0x9d, 512697}, ++ {0x9e, 515962}, ++ {0x9f, 519228}, ++ {0xa0, 522494}, ++ {0xa1, 525759}, ++ {0xa2, 529025}, ++ {0xa3, 532290}, ++ {0xa4, 535556}, ++ {0xa5, 538822}, ++ {0xa6, 542087}, ++ {0xa7, 545353}, ++ {0xa8, 548618}, ++ {0xa9, 551884}, ++ {0xaa, 555149}, ++ {0xab, 558415}, ++ {0xac, 561681}, ++ {0xad, 564946}, ++ {0xae, 568212}, ++ {0xaf, 571477}, ++ {0xb0, 574743}, ++ {0xb1, 578009}, ++ {0xb2, 581274}, ++ {0xb3, 584540}, ++ {0xb4, 587805}, ++ {0xb5, 591071}, ++ {0xb6, 594337}, ++ {0xb7, 597602}, ++ {0xb8, 600868}, ++ {0xb9, 604133}, ++ {0xba, 607399}, ++ {0xbb, 610664}, ++ {0xbc, 613930}, ++ {0xbd, 617196}, ++ {0xbe, 620461}, ++ {0xbf, 623727}, ++ {0xc0, 626992}, ++ {0xc1, 630258}, ++ {0xc2, 633524}, ++ {0xc3, 636789}, ++ {0xc4, 640055}, ++ {0xc5, 643320}, ++ {0xc6, 646586}, ++ {0xc7, 649852}, ++ {0xc8, 653117}, ++ {0xc9, 656383}, ++ {0xca, 659648}, ++ {0xcb, 662914}, ++ {0xcc, 666179}, ++ {0xcd, 669445}, ++ {0xce, 672711}, ++ {0xcf, 675976}, ++ {0xd0, 679242}, ++ {0xd1, 682507}, ++ {0xd2, 685773}, ++ {0xd3, 689039}, ++ {0xd4, 692304}, ++ {0xd5, 695570}, ++ {0xd6, 698835}, ++ {0xd7, 702101}, ++ {0xd8, 705367}, ++ {0xd9, 708632}, ++ {0xda, 711898}, ++ {0xdb, 715163}, ++ {0xdc, 718429}, ++ {0xdd, 721694}, ++ {0xde, 724960}, ++ {0xdf, 728226}, ++ {0xe0, 731491}, ++ {0xe1, 734757}, ++ {0xe2, 738022}, ++ {0xe3, 741288}, ++ {0xe4, 744554}, ++ {0xe5, 747819}, ++ {0xe6, 751085}, ++ {0xe7, 754350}, ++ {0xe8, 757616}, ++ {0xe9, 760882}, ++ {0xea, 764147}, ++ {0xeb, 767413}, ++ {0xec, 770678}, ++ {0xed, 773944}, ++ {0xee, 777209}, ++ {0xef, 780475}, ++ {0xf0, 783741}, ++}; ++ ++/***********************************/ ++ ++static struct regval_list imx335_init_regs_2592_1944_15fps_mipi[] = { ++ {0x3000, 0x01}, ++ {0x3001, 0x00}, ++ {0x3002, 0x01}, ++ {0x3004, 0x00}, ++ {0x300C, 0x5B}, ++ {0x300D, 0x40}, ++ {0x3018, 0x00}, ++ {0x302C, 0x30}, ++ {0x302D, 0x00}, ++ {0x302E, 0x38}, ++ {0x302F, 0x0A}, ++ {0x3030, 0x1d}, ++ {0x3031, 0x10}, ++ {0x3032, 0x00}, ++ {0x3034, 0xb0}, ++ {0x3035, 0x04},/* 20fps 0x384 */ ++ {0x3048, 0x00}, ++ {0x3049, 0x00}, ++ {0x304A, 0x03}, ++ {0x304B, 0x01}, ++ {0x304C, 0x14}, ++ {0x304E, 0x00}, ++ {0x304F, 0x00},/* vflip */ ++ {0x3050, 0x00}, ++ {0x3056, 0xAC}, ++ {0x3057, 0x07}, ++ {0x3058, 0x09}, ++ {0x3059, 0x00}, ++ {0x305A, 0x00}, ++ {0x305C, 0x12}, ++ {0x305D, 0x00}, ++ {0x305E, 0x00}, ++ {0x3060, 0xE8}, ++ {0x3061, 0x00}, ++ {0x3062, 0x00}, ++ {0x3064, 0x09}, ++ {0x3065, 0x00}, ++ {0x3066, 0x00}, ++ {0x3068, 0xCE}, ++ {0x3069, 0x00}, ++ {0x306A, 0x00}, ++ {0x306C, 0x68}, ++ {0x306D, 0x06}, ++ {0x306E, 0x00}, ++ {0x3072, 0x28}, ++ {0x3073, 0x00}, ++ {0x3074, 0xB0}, ++ {0x3075, 0x00}, ++ {0x3076, 0x58}, ++ {0x3077, 0x0F}, ++ {0x3078, 0x01}, ++ {0x3079, 0x02}, ++ {0x307A, 0xFF}, ++ {0x307B, 0x02}, ++ {0x307C, 0x00}, ++ {0x307D, 0x00}, ++ {0x307E, 0x00}, ++ {0x307F, 0x00}, ++ {0x3080, 0x01}, ++ {0x3081, 0x02}, ++ {0x3082, 0xFF}, ++ {0x3083, 0x02}, ++ {0x3084, 0x00}, ++ {0x3085, 0x00}, ++ {0x3086, 0x00}, ++ {0x3087, 0x00}, ++ {0x30A4, 0x33}, ++ {0x30A8, 0x10}, ++ {0x30A9, 0x04}, ++ {0x30AC, 0x00}, ++ {0x30AD, 0x00}, ++ {0x30B0, 0x10}, ++ {0x30B1, 0x08}, ++ {0x30B4, 0x00}, ++ {0x30B5, 0x00}, ++ {0x30B6, 0x00}, ++ {0x30B7, 0x00}, ++ {0x30C6, 0x00}, ++ {0x30C7, 0x00}, ++ {0x30CE, 0x00}, ++ {0x30CF, 0x00}, ++ {0x30D8, 0x4C}, ++ {0x30D9, 0x10}, ++ {0x30E8, 0x00}, ++ {0x30E9, 0x00}, ++ {0x30EA, 0x00}, ++ {0x30EB, 0x00}, ++ {0x30EC, 0x00}, ++ {0x30ED, 0x00}, ++ {0x30EE, 0x00}, ++ {0x30EF, 0x00}, ++ {0x3112, 0x08}, ++ {0x3113, 0x00}, ++ {0x3116, 0x08}, ++ {0x3117, 0x00}, ++ {0x314C, 0x80}, ++ {0x314D, 0x00}, ++ {0x315A, 0x06}, ++ {0x3167, 0x01}, ++ {0x3168, 0x68}, ++ {0x316A, 0x7E}, ++ {0x3199, 0x00}, ++ {0x319D, 0x00}, ++ {0x319E, 0x03}, ++ {0x31A0, 0x2A}, ++ {0x31A1, 0x00}, ++ {0x31D4, 0x00}, ++ {0x31D5, 0x00}, ++ {0x3288, 0x21}, ++ {0x328A, 0x02}, ++ {0x3300, 0x00}, ++ {0x3302, 0x32}, ++ {0x3303, 0x00}, ++ {0x3414, 0x05}, ++ {0x3416, 0x18}, ++ {0x341C, 0xff},//0xFF}, ++ {0x341D, 0x01}, ++ {0x3648, 0x01}, ++ {0x364A, 0x04}, ++ {0x364C, 0x04}, ++ {0x3678, 0x01}, ++ {0x367C, 0x31}, ++ {0x367E, 0x31}, ++ {0x3706, 0x10}, ++ {0x3708, 0x03}, ++ {0x3714, 0x02}, ++ {0x3715, 0x02}, ++ {0x3716, 0x01}, ++ {0x3717, 0x03}, ++ {0x371C, 0x3D}, ++ {0x371D, 0x3F}, ++ {0x372C, 0x00}, ++ {0x372D, 0x00}, ++ {0x372E, 0x46}, ++ {0x372F, 0x00}, ++ {0x3730, 0x89}, ++ {0x3731, 0x00}, ++ {0x3732, 0x08}, ++ {0x3733, 0x01}, ++ {0x3734, 0xFE}, ++ {0x3735, 0x05}, ++ {0x3740, 0x02}, ++ {0x375D, 0x00}, ++ {0x375E, 0x00}, ++ {0x375F, 0x11}, ++ {0x3760, 0x01}, ++ {0x3768, 0x1B}, ++ {0x3769, 0x1B}, ++ {0x376A, 0x1B}, ++ {0x376B, 0x1B}, ++ {0x376C, 0x1A}, ++ {0x376D, 0x17}, ++ {0x376E, 0x0F}, ++ {0x3776, 0x00}, ++ {0x3777, 0x00}, ++ {0x3778, 0x46}, ++ {0x3779, 0x00}, ++ {0x377A, 0x89}, ++ {0x377B, 0x00}, ++ {0x377C, 0x08}, ++ {0x377D, 0x01}, ++ {0x377E, 0x23}, ++ {0x377F, 0x02}, ++ {0x3780, 0xD9}, ++ {0x3781, 0x03}, ++ {0x3782, 0xF5}, ++ {0x3783, 0x06}, ++ {0x3784, 0xA5}, ++ {0x3788, 0x0F}, ++ {0x378A, 0xD9}, ++ {0x378B, 0x03}, ++ {0x378C, 0xEB}, ++ {0x378D, 0x05}, ++ {0x378E, 0x87}, ++ {0x378F, 0x06}, ++ {0x3790, 0xF5}, ++ {0x3792, 0x43}, ++ {0x3794, 0x7A}, ++ {0x3796, 0xA1}, ++ {0x37B0, 0x36}, ++ {0x3A01, 0x01}, ++ {0x3A04, 0x48}, ++ {0x3A05, 0x09}, ++ {0x3A18, 0x67}, ++ {0x3A19, 0x00}, ++ {0x3A1A, 0x27}, ++ {0x3A1B, 0x00}, ++ {0x3A1C, 0x27}, ++ {0x3A1D, 0x00}, ++ {0x3A1E, 0xB7}, ++ {0x3A1F, 0x00}, ++ {0x3A20, 0x2F}, ++ {0x3A21, 0x00}, ++ {0x3A22, 0x4F}, ++ {0x3A23, 0x00}, ++ {0x3A24, 0x2F}, ++ {0x3A25, 0x00}, ++ {0x3A26, 0x47}, ++ {0x3A27, 0x00}, ++ {0x3A28, 0x27}, ++ {0x3A29, 0x00}, ++ ++ /*pattern generator*/ ++#ifdef IMX335_TESTPATTERN ++ {0x3148, 0x10}, ++ {0x3280, 0x00}, ++ {0x329c, 0x01}, ++ {0x329e, 0x0b}, ++ {0x32a0, 0x11},/*tpg colorwidth*/ ++#endif ++ {0x3002, 0x00}, ++ {0x3000, 0x00}, ++ ++ {IMX335_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list imx335_init_regs_2592_1944_25fps_mipi[] = { ++ {0x3000, 0x01}, ++ {0x3001, 0x00}, ++ {0x3002, 0x01}, ++ {0x3004, 0x00}, ++ {0x300c, 0x5b}, ++ {0x300d, 0x40}, ++ {0x3018, 0x00}, ++ {0x302c, 0x30}, ++ {0x302d, 0x00}, ++ {0x302e, 0x38}, ++ {0x302f, 0x0a}, ++ {0x3030, 0x18}, ++ {0x3031, 0x15},//1518 ++ {0x3032, 0x00}, ++ {0x3034, 0x26}, ++ {0x3035, 0x02}, ++ {0x3050, 0x00}, ++ {0x315a, 0x02}, ++ {0x316a, 0x7e}, ++ {0x319d, 0x00}, ++ {0x31a1, 0x00}, ++ {0x3288, 0x21}, ++ {0x328a, 0x02}, ++ {0x3414, 0x05}, ++ {0x3416, 0x18}, ++ {0x341c, 0xff}, ++ {0x341d, 0x01}, ++ {0x3648, 0x01}, ++ {0x364a, 0x04}, ++ {0x364c, 0x04}, ++ {0x3678, 0x01}, ++ {0x367c, 0x31}, ++ {0x367e, 0x31}, ++ {0x3706, 0x10}, ++ {0x3708, 0x03}, ++ {0x3714, 0x02}, ++ {0x3715, 0x02}, ++ {0x3716, 0x01}, ++ {0x3717, 0x03}, ++ {0x371c, 0x3d}, ++ {0x371d, 0x3f}, ++ {0x372c, 0x00}, ++ {0x372d, 0x00}, ++ {0x372e, 0x46}, ++ {0x372f, 0x00}, ++ {0x3730, 0x89}, ++ {0x3731, 0x00}, ++ {0x3732, 0x08}, ++ {0x3733, 0x01}, ++ {0x3734, 0xfe}, ++ {0x3735, 0x05}, ++ {0x3740, 0x02}, ++ {0x375d, 0x00}, ++ {0x375e, 0x00}, ++ {0x375f, 0x11}, ++ {0x3760, 0x01}, ++ {0x3768, 0x1b}, ++ {0x3769, 0x1b}, ++ {0x376a, 0x1b}, ++ {0x376b, 0x1b}, ++ {0x376c, 0x1a}, ++ {0x376d, 0x17}, ++ {0x376e, 0x0f}, ++ {0x3776, 0x00}, ++ {0x3777, 0x00}, ++ {0x3778, 0x46}, ++ {0x3779, 0x00}, ++ {0x377a, 0x89}, ++ {0x377b, 0x00}, ++ {0x377c, 0x08}, ++ {0x377d, 0x01}, ++ {0x377e, 0x23}, ++ {0x377f, 0x02}, ++ {0x3780, 0xd9}, ++ {0x3781, 0x03}, ++ {0x3782, 0xf5}, ++ {0x3783, 0x06}, ++ {0x3784, 0xa5}, ++ {0x3788, 0x0f}, ++ {0x378a, 0xd9}, ++ {0x378b, 0x03}, ++ {0x378c, 0xeb}, ++ {0x378d, 0x05}, ++ {0x378e, 0x87}, ++ {0x378f, 0x06}, ++ {0x3790, 0xf5}, ++ {0x3792, 0x43}, ++ {0x3794, 0x7a}, ++ {0x3796, 0xa1}, ++ {0x3a01, 0x01}, ++ /*pattern generator*/ ++#ifdef IMX335_TESTPATTERN ++ {0x3148, 0x10}, ++ {0x3280, 0x00}, ++ {0x329c, 0x01}, ++ {0x329e, 0x0b}, ++ {0x32a0, 0x11},/*tpg colorwidth*/ ++#endif ++ {0x3002, 0x00}, ++ {0x3000, 0x00}, ++ {IMX335_REG_END, 0x00},/* END MARKER */ ++}; ++ ++/* ++ * the part of driver was fixed. ++ */ ++static struct regval_list imx335_stream_on_mipi[] = { ++ {0x3000, 0x00}, ++ {IMX335_REG_END, 0x00}, ++}; ++ ++static struct regval_list imx335_stream_off_mipi[] = { ++ {0x3000, 0x01}, ++ {IMX335_REG_END, 0x00}, ++}; ++ ++int imx335_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int imx335_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int imx335_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != IMX335_REG_END) { ++ if (vals->reg_num == IMX335_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = imx335_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ { ++ printk("array: 0x%02x, 0x%02x\n",vals->reg_num, val); ++ return ret; ++ } ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int imx335_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != IMX335_REG_END) { ++ if (vals->reg_num == IMX335_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = imx335_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int imx335_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct imx335_info *info = to_state(sd); ++ gpio_direction_output(info->pwdn.pin, info->pwdn.active_level); ++// printk("==========file=%s,func=%s,line=%d,pwdn=%d,level=%d,\n\n",__FILE__,__func__,__LINE__,info->pwdn.pin,info->pwdn.active_level); ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int imx335_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct imx335_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int imx335_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct imx335_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = imx335_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++ ++static int imx335_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ ret = imx335_read(sd, IMX335_REG_CHIP_ID_HIGH, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != IMX335_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = imx335_read(sd, IMX335_REG_CHIP_ID_LOW, &v); ++ printk("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != IMX335_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ printk(" imx335 id %x\n", *ident); ++ return 0; ++} ++ ++ ++static struct imx335_win_size imx335_win_sizes[] = { ++#if 1 ++ { ++ .sensor_info.mipi_cfg.twidth = 2616, ++ .sensor_info.mipi_cfg.theight = 1944, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 648, //hcrop(2592-1944) ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 34, //Margin for color processing ++ .sensor_info.fps = 15 << 16 | 1, ++ ++ .width = 1944, ++ .height = 1944, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = imx335_init_regs_2592_1944_15fps_mipi, ++ }, ++#endif ++ { ++ .sensor_info.mipi_cfg.twidth = 2616, ++ .sensor_info.mipi_cfg.theight = 1944, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 648, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 34, ++ .sensor_info.fps = 25 << 16 | 1, ++ ++ .width = 1944, ++ .height = 1944, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = imx335_init_regs_2592_1944_25fps_mipi, ++ }, ++ ++}; ++static const struct imx335_win_size *imx335_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(imx335_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(imx335_win_sizes); i++) { ++ if ((*width >= imx335_win_sizes[i].width) && ++ (*height >= imx335_win_sizes[i].height)) { ++ *width = imx335_win_sizes[i].width; ++ *height = imx335_win_sizes[i].height; ++ return &imx335_win_sizes[i]; ++ } ++ } ++ ++ *width = imx335_win_sizes[default_size].width; ++ *height = imx335_win_sizes[default_size].height; ++ printk("------w=%d,h=%d--default_size=%d---->line=%d,func=%s\n",*width,*height,default_size,__LINE__,__func__); ++ return &imx335_win_sizes[default_size]; ++} ++ ++static int imx335_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_imx335_FMTS) ++ return -EINVAL; ++ ++ code->code = imx335_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int imx335_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct imx335_format_struct *ovfmt; ++ struct imx335_win_size *wsize; ++ struct imx335_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++// info->win = imx335_select_win(&format->format.width, &format->format.height); ++ ++ ++ return 0; ++} ++ ++static int imx335_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct imx335_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ printk("----%s, %d, width: %d, height: %d, code: %x\n", ++ __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int imx335_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int imx335_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int imx335_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int imx335_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int imx335_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int imx335_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++#if 0 ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(imx335_again_lut); i++) { ++ lut = &imx335_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(imx335_again_lut); i++) { ++ lut = &imx335_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++#endif ++ ++static int imx335_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++// printk("~~~g_again=%d\n",*value); ++#if 1 ++ return 0; ++#else ++ char v=0; ++ unsigned int reg_val=0; ++ int ret=0; ++ int i=0; ++ int total; ++ total = sizeof(gainLevelTable) / sizeof(unsigned int); ++ ++ ret=imx335_read(sd,0x00b1,&v); ++ reg_val|=(v<<6); ++ ret+=imx335_read(sd,0x00b2,&v); ++ reg_val|=((v>>2)|0x3f); ++ ++ for (i = 0; i < total; i++) ++ { ++ if ((gainLevelTable[i] <= reg_val)&&(reg_val < gainLevelTable[i+1])) ++ { ++ *value=reg_val; ++ break; ++ } ++ } ++ return ret; ++#endif ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int imx335_s_again(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++#if 0 ++ ret = imx335_write(sd, 0x30e8, (unsigned char)(value & 0xff)); ++ ret += imx335_write(sd, 0x30e9, (unsigned char)((value >> 8) & 0x07)); ++ if (ret < 0) ++ return ret; ++#endif ++ return 0; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int imx335_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int imx335_s_exp(struct v4l2_subdev *sd, int value) ++{ ++#if 1 ++ int ret = 0; ++ ++ unsigned short shr0 = 0; ++ unsigned short vmax = 0; ++ ++ vmax = imx335_win_sizes[0].sensor_info.mipi_cfg.theight; ++ printk("====================>>>>>>>>>>>>>>>vmax=%d\n",vmax); ++ shr0 = vmax - value; ++ printk("====================>>>>>>>>>>>>>>>shr0=%d\n",shr0); ++ ret = imx335_write(sd, 0x3058, (unsigned char)(shr0 & 0xff)); ++ ret += imx335_write(sd, 0x3059, (unsigned char)((shr0 >> 8) & 0xff)); ++ ret += imx335_write(sd, 0x305a, (unsigned char)((shr0 >> 16) & 0x0f)); ++ if (0 != ret) { ++ IS_ERR("err: imx335_write err\n"); ++ return ret; ++ } ++#endif ++ return 0; ++} ++ ++static int imx335_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct imx335_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return imx335_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return imx335_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int imx335_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct imx335_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return imx335_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return imx335_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return imx335_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return imx335_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* imx335_s_gain turns off auto gain */ ++ return imx335_s_gain(sd, info->gain->val); ++ } ++ return imx335_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return imx335_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return imx335_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return imx335_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops imx335_ctrl_ops = { ++ .s_ctrl = imx335_s_ctrl, ++ .g_volatile_ctrl = imx335_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int imx335_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = imx335_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 2; ++ return ret; ++} ++ ++static int imx335_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ imx335_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int imx335_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct imx335_info *info = to_state(sd); ++ int ret = 0; ++ int val=0; ++ printk("------------>line=%d,func=%s\n",__LINE__,__func__); ++ if (enable) { ++ imx335_reset(sd,1); ++ imx335_init(sd,1); ++ ret = imx335_write_array(sd, imx335_stream_on_mipi); ++ pr_debug("imx335 stream on\n"); ++ printk("----on-------->line=%d,func=%s\n",__LINE__,__func__); ++ ++ } ++ else { ++ ret = imx335_write_array(sd, imx335_stream_off_mipi); ++ pr_debug("imx335 stream off\n"); ++ printk("----off-------->line=%d,func=%s\n",__LINE__,__func__); ++ } ++ return ret; ++} ++ ++int imx335_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct imx335_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops imx335_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = imx335_g_register, ++ .s_register = imx335_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops imx335_video_ops = { ++ .s_stream = imx335_s_stream, ++ .g_frame_interval = imx335_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops imx335_pad_ops = { ++ //.enum_frame_interval = imx335_enum_frame_interval, ++ //.num_frame_size = imx335_enum_frame_size, ++ //.enum_mbus_code = imx335_enum_mbus_code, ++ .set_fmt = imx335_set_fmt, ++ .get_fmt = imx335_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops imx335_ops = { ++ .core = &imx335_core_ops, ++ .video = &imx335_video_ops, ++ .pad = &imx335_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int imx335_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct imx335_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned long rate; ++ ++ printk(" imx335 probe \n\n"); ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwdn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwdn.pin = gpio; ++ info->pwdn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &imx335_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++#if 1 ++ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++#if 1 ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ info->sclka = devm_clk_get(&client->dev, "mux_cim"); ++ ++ printk("sclka is %s\n", info->sclka?"NOT NULL":"NULL"); ++ rate = v4l2_clk_get_rate(info->clk); ++ if (((rate / 1000) % 37125) != 0) { ++ ret = clk_set_parent(info->sclka, clk_get(NULL, "epll")); ++ info->sclka = devm_clk_get(&client->dev, "epll"); ++ if (IS_ERR(info->sclka)) { ++ pr_err("get sclka failed\n"); ++ } else { ++ rate = clk_get_rate(info->sclka); ++ if (((rate / 1000) % 37125) != 0) { ++ clk_set_rate(info->sclka, 891000000); ++ } ++ } ++ } ++#endif ++ ++ ret = v4l2_clk_set_rate(info->clk, 37125000); ++ ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++#endif ++ ++ imx335_reset(sd, 1); ++ ++ /* Make sure it's an imx335 */ ++ ret = imx335_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an imx335 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++// imx335_ircut(sd, 0); ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &imx335_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &imx335_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &imx335_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &imx335_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &imx335_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &imx335_ctrl_ops, ++ // V4L2_CID_ANALOGUE_GAIN, 0, 259142, 1, 10000); ++ V4L2_CID_ANALOGUE_GAIN, 0, 405939, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &imx335_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1899 - 4, 1, 1500); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &imx335_win_sizes[0];//720p ++// info->win = &imx335_win_sizes[1];//1080*360 ++// info->win = &imx335_win_sizes[2];//720*360 ++ imx335_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "imx335 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int imx335_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct imx335_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id imx335_id[] = { ++ { "imx335", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, imx335_id); ++ ++static const struct of_device_id imx335_of_match[] = { ++ {.compatible = "sony,imx335", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, imx335_of_match); ++ ++ ++static struct i2c_driver imx335_driver = { ++ .driver = { ++ .name = "imx335", ++ .of_match_table = of_match_ptr(imx335_of_match), ++ }, ++ .probe = imx335_probe, ++ .remove = imx335_remove, ++ .id_table = imx335_id, ++}; ++ ++module_i2c_driver(imx335_driver); ++MODULE_DESCRIPTION("A low-level driver for Sony imx335 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/ov2735a.c b/module_drivers/drivers/media/i2c/ingenic-isp/ov2735a.c +new file mode 100644 +index 000000000..62ffa338a +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/ov2735a.c +@@ -0,0 +1,1157 @@ ++/* ++ * A V4L2 driver for OmniVision OV2735A cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define OV2735A_CHIP_ID_H (0x27) ++#define OV2735A_CHIP_ID_L (0x35) ++#define OV2735A_REG_END 0xff ++#define OV2735A_REG_DELAY 0x00 ++#define OV2735A_PAGE_REG 0xfd ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ov2735a_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ov2735a_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov2735a_supply{ ++ struct regulator *avdd; ++ struct regulator *dvdd; ++ struct regulator *dovdd; ++}; ++ ++struct ov2735a_info { ++ struct ov2735a_supply supply; ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ov2735a_win_size *win; ++ ++ struct ov2735a_gpio reset; ++ struct ov2735a_gpio ircutp; ++ struct ov2735a_gpio ircutn; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++ ++struct again_lut ov2735a_again_lut[] = { ++ {0x10, 0}, ++ {0x11, 5731}, ++ {0x12, 11136}, ++ {0x13, 16248}, ++ {0x14, 21097}, ++ {0x15, 25710}, ++ {0x16, 30109}, ++ {0x17, 34312}, ++ {0x18, 38336}, ++ {0x19, 42195}, ++ {0x1a, 45904}, ++ {0x1b, 49472}, ++ {0x1c, 52910}, ++ {0x1d, 56228}, ++ {0x1e, 59433}, ++ {0x1f, 62534}, ++ {0x20, 65536}, ++ {0x22, 71267}, ++ {0x24, 76672}, ++ {0x26, 81784}, ++ {0x28, 86633}, ++ {0x2a, 91246}, ++ {0x2c, 95645}, ++ {0x2e, 99848}, ++ {0x30, 103872}, ++ {0x32, 107731}, ++ {0x34, 111440}, ++ {0x36, 115008}, ++ {0x38, 118446}, ++ {0x3a, 121764}, ++ {0x3c, 124969}, ++ {0x3e, 128070}, ++ {0x40, 131072}, ++ {0x44, 136803}, ++ {0x48, 142208}, ++ {0x4c, 147320}, ++ {0x50, 152169}, ++ {0x54, 156782}, ++ {0x58, 161181}, ++ {0x5c, 165384}, ++ {0x60, 169408}, ++ {0x64, 173267}, ++ {0x68, 176976}, ++ {0x6c, 180544}, ++ {0x70, 183982}, ++ {0x74, 187300}, ++ {0x78, 190505}, ++ {0x7c, 193606}, ++ {0x80, 196608}, ++ {0x88, 202339}, ++ {0x90, 207744}, ++ {0x98, 212856}, ++ {0xa0, 217705}, ++ {0xa8, 222318}, ++ {0xb0, 226717}, ++ {0xb8, 230920}, ++ {0xc0, 234944}, ++ {0xc8, 238803}, ++ {0xd0, 242512}, ++ {0xd8, 246080}, ++ {0xe0, 249518}, ++ {0xe8, 252836}, ++ {0xf0, 256041}, ++ {0xf8, 259142}, ++}; ++ ++static inline struct ov2735a_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ov2735a_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov2735a_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list ov2735a_init_regs_1920_1080_30fps_MIPI[] = { ++ {0xfd, 0x00}, ++ {OV2735A_REG_DELAY, 0x05}, ++ {0xfd, 0x00}, ++ {0x2f, 0x10}, ++ {0x34, 0x00}, ++ {0x30, 0x15}, ++ {0x33, 0x01}, ++ {0x35, 0x20}, ++ {0xfd, 0x01}, ++ {0x0d, 0x00}, ++ {0x30, 0x00}, ++ {0x03, 0x01}, ++ {0x04, 0x8f}, ++ {0x01, 0x01}, ++ {0x09, 0x00}, ++ {0x0a, 0x20}, ++ {0x06, 0x0a}, ++ {0x24, 0x10}, ++ {0x01, 0x01}, ++ {0xfb, 0x73}, ++ {0x01, 0x01}, ++ {0xfd, 0x01}, ++ {0x1a, 0x6b}, ++ {0x1c, 0xea}, ++ {0x16, 0x0c}, ++ {0x21, 0x00}, ++ {0x11, 0xe8},//;63 ;fr ++ {0x19, 0xc3}, ++ {0x26, 0xda}, ++ {0x29, 0x01}, ++ {0x33, 0x6f}, ++ {0x2a, 0xd2}, ++ {0x2c, 0x40}, ++ {0xd0, 0x02}, ++ {0xd1, 0x01}, ++ {0xd2, 0x20}, ++ {0xd3, 0x03},//;04 ; ++ {0xd4, 0xa4},//;2a ; ++ {0x50, 0x00}, ++ {0x51, 0x2c}, ++ {0x52, 0x29}, ++ {0x53, 0x00}, ++ {0x55, 0x44}, ++ {0x58, 0x29}, ++ {0x5a, 0x00}, ++ {0x5b, 0x00}, ++ {0x5d, 0x00}, ++ {0x64, 0x2f}, ++ {0x66, 0x62}, ++ {0x68, 0x5b}, ++ {0x75, 0x46}, ++ {0x76, 0xf0}, ++ {0x77, 0x4f}, ++ {0x78, 0xef}, ++ {0x72, 0xcf}, ++ {0x73, 0x36}, ++ {0x7d, 0x0d}, ++ {0x7e, 0x0d}, ++ {0x8a, 0x77}, ++ {0x8b, 0x77}, ++ {0xfd, 0x01}, ++ {0xb1, 0x83},//;DPHY enable 8b ++ ++// {0xb2, 0x40},//hs mode ++ ++ {0xb3, 0x0b},//;0b;09;1d ++ {0xb4, 0x14},//;MIPI PLL enable;14;35;36 ++ {0x9d, 0x40},//;mipi hs dc level 40/03/55 ++ {0xa1, 0x05},//;speed/03 ++ {0x94, 0x44},//;dphy time ++ {0x95, 0x33},//;dphy time ++ {0x96, 0x1f},//;dphy time ++ {0x98, 0x45},//;dphy time ++ {0x9c, 0x10},//;dphy time ++ {0xb5, 0x70},//;30 ++ {0xa0, 0x01},//;mipi enable ++ {0x25, 0xe0}, ++ {0x20, 0x7b}, ++ {0x8f, 0x88}, ++ {0x91, 0x40}, ++ ++ {0xfd, 0x02}, ++ {0x5e, 0x03}, ++ {0xa1, 0x04}, ++ {0xa3, 0x40}, ++ {0xa5, 0x02}, ++ {0xa7, 0xc4}, ++ {0xfd, 0x01}, ++ {0x86, 0x77}, ++ {0x89, 0x77}, ++ {0x87, 0x74}, ++ {0x88, 0x74}, ++ {0xfc, 0xe0}, ++ {0xfe, 0xe0}, ++ {0xf0, 0x40}, ++ {0xf1, 0x40}, ++ {0xf2, 0x40}, ++ {0xf3, 0x40}, ++ ++#if 1 ++ {0xfd, 0x02},//;;crop to 1920x1080 ++ {0xa0, 0x00},//;Image vertical start MSB3bits ++ {0xa1, 0x08},//;Image vertical start LSB8bits ++ {0xa2, 0x04},//;image vertical size MSB8bits ++ {0xa3, 0x38},//;image vertical size LSB8bits ++ {0xa4, 0x00}, ++ {0xa5, 0x04},//;H start 8Lsb, keep center ++ {0xa6, 0x03}, ++ {0xa7, 0xc0},//;Half H size Lsb8bits ++ {0xfd, 0x01}, ++ {0x8e, 0x07}, ++ {0x8f, 0x80},//;MIPI column number ++ {0x90, 0x04},//;MIPI row number ++ {0x91, 0x38}, ++ ++ {0xfd, 0x03}, ++ {0xc0, 0x01},//;enable transfer OTP BP information ++ {0xfd, 0x04}, ++ {0x21, 0x14}, ++ {0x22, 0x14}, ++ {0x23, 0x14},//;enhance normal and dummy BPC ++ ++ {0xfd, 0x01}, ++ {0x06, 0xe0},//;insert dummy line , the frame rate is 30.01. ++// {0x01, 0x01},//; ++// {0xa0, 0x01},//;MIPI enable, stream on ++#else ++ {0xfd, 0x02},//;;crop to 1920x1080 ++ {0xa0, 0x00},//;Image vertical start MSB3bits ++ {0xa1, 0x08},//;Image vertical start LSB8bits ++ {0xa2, 0x01},//;image vertical size MSB8bits ++ {0xa3, 0xe0},//;image vertical size LSB8bits ++ {0xa4, 0x00}, ++ {0xa5, 0x04},//;H start 8Lsb, keep center ++ {0xa6, 0x01}, ++ {0xa7, 0x40},//;Half H size Lsb8bits ++ {0xfd, 0x01}, ++ {0x8e, 0x02}, ++ {0x8f, 0x80},//;MIPI column number ++ {0x90, 0x01},//;MIPI row number ++ {0x91, 0xe0}, ++ ++ {0xfd, 0x03}, ++ {0xc0, 0x01},//;enable transfer OTP BP information ++ {0xfd, 0x04}, ++ {0x21, 0x14}, ++ {0x22, 0x14}, ++ {0x23, 0x14},//;enhance normal and dummy BPC ++ ++ {0xfd, 0x01}, ++ {0x06, 0xe0},//;insert dummy line , the frame rate is 30.01. ++ {0x01, 0x01},//; ++ {0xa0, 0x01},//;MIPI enable, stream on ++#endif ++ ++#if 0 ++ {0xfd, 0x01},//@@ 1 11 Mirror_On_Flip_Off ++ ++ {0x3f, 0x01},//03 ++ {0xf8, 0x00},//02 ++ {0x01, 0x01}, ++ {0xfd, 0x02}, ++ {0x62, 0x01},//;full size mode flip off row start for OTP BPC ++ {0x63, 0x00}, ++ {0xfd, 0x01}, ++ ++#endif ++#if 0 ++ {0xfd, 0x01},//@@ 1 12 Mirror_On_Flip_On ++ ++ {0x3f, 0x03},// 03 ++ ++ {0xf8, 0x02},//02 ++ ++ {0x01, 0x01}, ++ {0xfd, 0x02}, ++ {0x62, 0x48}, ++ {0x63, 0x04},//;full size flip, row start:1096(0x448) ++ {0xfd, 0x01}, ++#endif ++ ++#if 0 ++ {0xfd, 0x01},//@@ 1 13 Mirror_Off_Flip_Off ++ ++ {0x3f, 0x00},//03 ++ {0xf8, 0x00},// 02 ++ ++ {0x01, 0x01}, ++ {0xfd, 0x02}, ++ {0x62, 0x01},//;full size mode flip off row start for OTP BPC ++ {0x63, 0x00}, ++ {0xfd, 0x01}, ++#endif ++ ++#if 1 ++ {0xfd, 0x01},//@@ 1 14 Mirror_Off_Flip_On ++ ++ {0x3f, 0x02},//03 ++ {0xf8, 0x02},//02 ++ {0x01, 0x01}, ++ ++ {0xfd, 0x02}, ++ {0x62, 0x48}, ++ {0x63, 0x04},//;full size flip, row start:1096(0x448) ++ {0xfd, 0x01}, ++#endif ++ ++ {0x01, 0x01},//; ++ {0xa0, 0x01},//;MIPI enable, stream on ++ {0xfd, 0x00}, ++ {0x36, 0x01}, ++ {0x37, 0x01},//fake stream off ++ ++ {OV2735A_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++ ++static struct regval_list ov2735a_stream_on[] = { ++ {0xfd, 0x00}, ++ {0x36, 0x00}, ++ {0x37, 0x00},//fake stream on ++ {OV2735A_REG_END, 0x00}, ++}; ++ ++static struct regval_list ov2735a_stream_off[] = { ++ {0xfd, 0x00}, ++ {0x36, 0x01}, ++ {0x37, 0x01},//fake stream off ++ {OV2735A_REG_END, 0x00}, ++}; ++ ++ ++int ov2735a_read(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 1, ++ .buf = ®, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_write(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ unsigned char buf[2] = {reg, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }; ++ int ret; ++ unsigned int timeout = 100; ++ while(timeout--){ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == -EAGAIN){ ++ msleep(100); ++ continue; ++ } ++ else ++ break; ++ } ++ ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != OV2735A_REG_END) { ++ if (vals->reg_num == OV2735A_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov2735a_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ if (vals->reg_num == OV2735A_PAGE_REG){ ++ val &= 0xf8; ++ val |= (vals->value & 0x07); ++ ret = ov2735a_write(sd, vals->reg_num, val); ++ ret = ov2735a_read(sd, vals->reg_num, &val); ++ } ++ } ++ vals++; ++ } ++ return 0; ++} ++static int ov2735a_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != OV2735A_REG_END) { ++ if (vals->reg_num == OV2735A_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov2735a_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ov2735a_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int ov2735a_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int ov2735a_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov2735a_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int ov2735a_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ ret = ov2735a_read(sd, 0x02, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV2735A_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = ov2735a_read(sd, 0x03, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV2735A_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ ret = ov2735a_read(sd, 0x04, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != 0x05 && v != 0x06 && v != 0x07) ++ return -ENODEV; ++ ++ ++ return 0; ++} ++ ++ ++static struct ov2735a_win_size ov2735a_win_sizes[] = { ++ /* 1920*1080 */ ++ { ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 30 << 16 | 1, ++ .sensor_info.total_width = 1936, ++ .sensor_info.total_height = 1304, ++ ++ .width = 1920, ++ .height = 1080, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov2735a_init_regs_1920_1080_30fps_MIPI, ++ } ++}; ++ ++#if 0 ++static int ov2735a_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->pad || code->index >= N_OV2735A_FMTS) ++ return -EINVAL; ++ ++ code->code = ov2735a_formats[code->index].mbus_code; ++ return 0; ++} ++#endif ++ ++/* ++ * Set a format. ++ */ ++static int ov2735a_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return ret; ++} ++ ++static int ov2735a_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = (unsigned int)&info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ov2735a_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ov2735a_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ov2735a_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov2735a_again_lut); i++) { ++ lut = &ov2735a_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov2735a_again_lut); i++) { ++ lut = &ov2735a_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++ ++static int ov2735a_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret = ov2735a_read(sd, 0x23, &v); ++ reg_val |= v ; ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++ ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ov2735a_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret = ov2735a_write(sd, 0xfd, 0x01); ++ ret += ov2735a_write(sd, 0x24, (unsigned char)reg_value); ++ ret += ov2735a_write(sd, 0x01, 0x01); ++ if (ret < 0){ ++ printk("ov2735a_write error %d\n" ,__LINE__ ); ++ return ret; ++ } ++ return 0; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ov2735a_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735a_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ ret = ov2735a_write(sd, 0xfd, 0x01); ++ ret += ov2735a_write(sd, 0x4, (unsigned char)(value & 0xff)); ++ ret += ov2735a_write(sd, 0x3, (unsigned char)((value & 0xff00) >> 8)); ++ ret += ov2735a_write(sd, 0x01, 0x01); ++ ++ if (ret < 0) { ++ printk("ov2735a_write error %d\n" ,__LINE__); ++ return ret; ++ } ++ return ret; ++} ++ ++static int ov2735a_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov2735a_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ov2735a_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov2735a_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ov2735a_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov2735a_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ov2735a_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ov2735a_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ov2735a_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ov2735a_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ov2735a_s_gain turns off auto gain */ ++ return ov2735a_s_gain(sd, info->gain->val); ++ } ++ return ov2735a_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ov2735a_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov2735a_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ov2735a_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ov2735a_ctrl_ops = { ++ .s_ctrl = ov2735a_s_ctrl, ++ .g_volatile_ctrl = ov2735a_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov2735a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ov2735a_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ov2735a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ov2735a_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++static int ov2735a_power(struct v4l2_subdev *sd, int on) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ info->supply.avdd = devm_regulator_get_optional(&client->dev, "avdd"); ++ info->supply.dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); ++ info->supply.dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); ++ ++ if (IS_ERR(info->supply.avdd)||IS_ERR(info->supply.dvdd) ++ ||IS_ERR(info->supply.dovdd)) { ++ if ((PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.dvdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.dovdd) == -EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ printk("No ov2735a vdd regulator found\n"); ++ } ++ ++ if ((!IS_ERR(info->supply.avdd))&&(!IS_ERR(info->supply.avdd)) ++ &&(!IS_ERR(info->supply.avdd))) { ++ if(on){ ++ ret = regulator_enable(info->supply.avdd); ++ ret = regulator_enable(info->supply.dvdd); ++ ret = regulator_enable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "ov2735a vdd supply disable failed\n"); ++ } ++ else{ ++ ret = regulator_disable(info->supply.avdd); ++ ret = regulator_disable(info->supply.dvdd); ++ ret = regulator_disable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "ov2735a vdd supply disable failed\n"); ++ } ++ }else{ ++ dev_err(&client->dev, "ov2735a vdd supply IS_ERR failed\n"); ++ } ++ return ret; ++} ++ ++int ov2735a_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ov2735a_reset(sd, 1); ++ ov2735a_write_array(sd, info->win->regs); ++ ret = ov2735a_write_array(sd, ov2735a_stream_on); ++ printk("ov2735a stream on\n"); ++ ++ } ++ else { ++ ret = ov2735a_write_array(sd, ov2735a_stream_off); ++ printk("ov2735a stream off\n"); ++ } ++ return ret; ++} ++ ++ ++int ov2735a_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct ov2735a_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ov2735a_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov2735a_g_register, ++ .s_register = ov2735a_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops ov2735a_video_ops = { ++ .s_stream = ov2735a_s_stream, ++ .g_frame_interval = ov2735a_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov2735a_pad_ops = { ++ //.enum_frame_interval = ov2735a_enum_frame_interval, ++ //.num_frame_size = ov2735a_enum_frame_size, ++ //.enum_mbus_code = ov2735a_enum_mbus_code, ++ .set_fmt = ov2735a_set_fmt, ++ .get_fmt = ov2735a_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops ov2735a_ops = { ++ .core = &ov2735a_core_ops, ++ .video = &ov2735a_video_ops, ++ .pad = &ov2735a_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int ov2735a_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct ov2735a_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &ov2735a_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ ov2735a_power(sd,1); ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ info->win = &ov2735a_win_sizes[0]; ++ ov2735a_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ov2735a */ ++ ret = ov2735a_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ov2735a chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ /*IRCUT ctl 0:off 1:on*/ ++ ov2735a_ircut(sd, 0); ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 259142, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov2735a_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1899 - 4, 1, 1500); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ov2735a Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ov2735a_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov2735a_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id ov2735a_id[] = { ++ { "ov2735a", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov2735a_id); ++ ++static const struct of_device_id ov2735a_of_match[] = { ++ {.compatible = "ovti,ov2735a", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2735a_of_match); ++ ++ ++static int ov2735a_suspend(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov2735a_info *info = to_state(sd); ++ int ret=0; ++ ++ ov2735a_power(sd,0); ++ v4l2_clk_disable(info->clk); ++ return ret; ++} ++ ++static int ov2735a_resume(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov2735a_info *info = to_state(sd); ++ int ret=0; ++ ++ ov2735a_power(sd,1); ++ v4l2_clk_enable(info->clk); ++ ov2735a_reset(sd, 1); ++ ov2735a_init(sd, 1); ++ return ret; ++} ++ ++const struct dev_pm_ops ov2735a_pm = ++{ ++ .suspend = ov2735a_suspend, ++ .resume = ov2735a_resume, ++}; ++ ++ ++static struct i2c_driver ov2735a_driver = { ++ .driver = { ++ .name = "ov2735a", ++ .of_match_table = of_match_ptr(ov2735a_of_match), ++ .pm = &ov2735a_pm, ++ }, ++ .probe = ov2735a_probe, ++ .remove = ov2735a_remove, ++ .id_table = ov2735a_id, ++}; ++ ++module_i2c_driver(ov2735a_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision ov2735a sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/ov2735b.c b/module_drivers/drivers/media/i2c/ingenic-isp/ov2735b.c +new file mode 100644 +index 000000000..e47728a18 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/ov2735b.c +@@ -0,0 +1,1202 @@ ++/* ++ * A V4L2 driver for OmniVision OV2735B cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define OV2735B_CHIP_ID_H (0x27) ++#define OV2735B_CHIP_ID_L (0x35) ++#define OV2735B_REG_END 0xff ++#define OV2735B_REG_DELAY 0x00 ++#define OV2735B_PAGE_REG 0xfd ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ov2735b_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ov2735b_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov2735b_supply{ ++ struct regulator *avdd; ++ struct regulator *dvdd; ++ struct regulator *dovdd; ++}; ++ ++struct ov2735b_info { ++ struct ov2735b_supply supply; ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ov2735b_win_size *win; ++ ++ struct ov2735b_gpio reset; ++ struct ov2735b_gpio ircutp; ++ struct ov2735b_gpio ircutn; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++ ++struct again_lut ov2735b_again_lut[] = { ++ {0x10, 0}, ++ {0x11, 5731}, ++ {0x12, 11136}, ++ {0x13, 16248}, ++ {0x14, 21097}, ++ {0x15, 25710}, ++ {0x16, 30109}, ++ {0x17, 34312}, ++ {0x18, 38336}, ++ {0x19, 42195}, ++ {0x1a, 45904}, ++ {0x1b, 49472}, ++ {0x1c, 52910}, ++ {0x1d, 56228}, ++ {0x1e, 59433}, ++ {0x1f, 62534}, ++ {0x20, 65536}, ++ {0x22, 71267}, ++ {0x24, 76672}, ++ {0x26, 81784}, ++ {0x28, 86633}, ++ {0x2a, 91246}, ++ {0x2c, 95645}, ++ {0x2e, 99848}, ++ {0x30, 103872}, ++ {0x32, 107731}, ++ {0x34, 111440}, ++ {0x36, 115008}, ++ {0x38, 118446}, ++ {0x3a, 121764}, ++ {0x3c, 124969}, ++ {0x3e, 128070}, ++ {0x40, 131072}, ++ {0x44, 136803}, ++ {0x48, 142208}, ++ {0x4c, 147320}, ++ {0x50, 152169}, ++ {0x54, 156782}, ++ {0x58, 161181}, ++ {0x5c, 165384}, ++ {0x60, 169408}, ++ {0x64, 173267}, ++ {0x68, 176976}, ++ {0x6c, 180544}, ++ {0x70, 183982}, ++ {0x74, 187300}, ++ {0x78, 190505}, ++ {0x7c, 193606}, ++ {0x80, 196608}, ++ {0x88, 202339}, ++ {0x90, 207744}, ++ {0x98, 212856}, ++ {0xa0, 217705}, ++ {0xa8, 222318}, ++ {0xb0, 226717}, ++ {0xb8, 230920}, ++ {0xc0, 234944}, ++ {0xc8, 238803}, ++ {0xd0, 242512}, ++ {0xd8, 246080}, ++ {0xe0, 249518}, ++ {0xe8, 252836}, ++ {0xf0, 256041}, ++ {0xf8, 259142}, ++}; ++ ++static inline struct ov2735b_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ov2735b_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov2735b_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list ov2735b_init_regs_1920_1080_30fps_dvp[] = { ++ {0xfd, 0x00}, ++ {OV2735B_REG_DELAY, 0x05}, ++ {0xfd, 0x00}, ++ {0x2f, 0x10}, ++ {0x34, 0x00}, ++ {0x30, 0x15}, ++ {0x33, 0x01}, ++ {0x35, 0x20}, ++ {0x1d, 0xa5}, ++ {0xfd, 0x01}, ++ {0x0d, 0x00}, ++ {0x30, 0x00}, ++ {0x03, 0x01}, ++ {0x04, 0x8f}, ++ {0x01, 0x01}, ++ {0x09, 0x00}, ++ {0x0a, 0x20}, ++ {0x06, 0x0a}, ++ {0x24, 0x10}, ++ {0x01, 0x01}, ++ {0xfb, 0x73}, ++ {0x01, 0x01}, ++ {0xfd, 0x01}, ++ {0x1a, 0x6b}, ++ {0x1c, 0xea}, ++ {0x16, 0x0c}, ++ {0x21, 0x00}, ++ {0x11, 0x63}, ++ {0x19, 0xc3}, ++ {0x26, 0xda}, ++ {0x29, 0x01}, ++ {0x33, 0x6f}, ++ {0x2a, 0xd2}, ++ {0x2c, 0x40}, ++ {0xd0, 0x02}, ++ {0xd1, 0x01}, ++ {0xd2, 0x20}, ++ {0xd3, 0x04}, ++ {0xd4, 0x2a}, ++ {0x50, 0x00}, ++ {0x51, 0x2c}, ++ {0x52, 0x29}, ++ {0x53, 0x00}, ++ {0x55, 0x44}, ++ {0x58, 0x29}, ++ {0x5a, 0x00}, ++ {0x5b, 0x00}, ++ {0x5d, 0x00}, ++ {0x64, 0x2f}, ++ {0x66, 0x62}, ++ {0x68, 0x5b}, ++ {0x75, 0x46}, ++ {0x76, 0xf0}, ++ {0x77, 0x4f}, ++ {0x78, 0xef}, ++ {0x72, 0xcf}, ++ {0x73, 0x36}, ++ {0x7d, 0x0d}, ++ {0x7e, 0x0d}, ++ {0x8a, 0x77}, ++ {0x8b, 0x77}, ++ {0xfd, 0x01}, ++ {0xb1, 0x82}, ++ {0xb3, 0x0b}, ++ {0xb4, 0x14}, ++ {0x9d, 0x40}, ++ {0xa1, 0x05}, ++ {0x94, 0x44}, ++ {0x95, 0x33}, ++ {0x96, 0x1f}, ++ {0x98, 0x45}, ++ {0x9c, 0x10}, ++ {0xb5, 0x70}, ++ {0xa0, 0x00}, ++ {0x25, 0xe0}, ++ {0x20, 0x7b}, ++ {0x8f, 0x88}, ++ {0x91, 0x40}, ++ {0xfd, 0x01}, ++ {0xfd, 0x02}, ++ {0x5e, 0x03}, ++ {0xfd, 0x02}, ++ {0x60, 0xf0}, ++ {0xa1, 0x04}, ++ {0xa3, 0x40}, ++ {0xa5, 0x02}, ++ {0xa7, 0xc4}, ++ {0xfd, 0x01}, ++ {0x86, 0x77}, ++ {0x89, 0x77}, ++ {0x87, 0x74}, ++ {0x88, 0x74}, ++ {0xfc, 0xe0}, ++ {0xfe, 0xe0}, ++ {0xf0, 0x40}, ++ {0xf1, 0x40}, ++ {0xf2, 0x40}, ++ {0xf3, 0x40}, ++ {0xfd, 0x02}, ++ {0x36, 0x08}, ++ {0xa0, 0x00}, ++ {0xa1, 0x08}, ++ {0xa2, 0x04}, ++ {0xa3, 0x38}, ++ {0xa4, 0x00}, ++ {0xa5, 0x04}, ++ {0xa6, 0x03}, ++ {0xa7, 0xc0}, ++ {0xfd, 0x03}, ++ {0xc0, 0x01},//OTP transf ++ {0xfd, 0x04}, ++ {0x22, 0x14}, ++ {0x23, 0x14}, ++ {0xfd, 0x01}, ++ {0x06, 0xe0}, ++ {0x01, 0x01}, ++ {0xfd, 0x00}, ++ {0x1b, 0x00}, ++ {0xfd, 0x01}, ++ {0x0d, 0x10}, ++ {0x0e, 0x05}, ++ {0x0f, 0x2b}, ++ {0x01, 0x01}, ++ {0xfd, 0x00}, ++ {0x36, 0x01}, ++ {0x37, 0x01},//fake stream off ++ ++ {OV2735B_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov2735b_init_regs_1920_1080_15fps_dvp[] = { ++ {0xfd, 0x00}, ++ {OV2735B_REG_DELAY, 0x05}, ++ {0xfd, 0x00}, ++ {0x2f, 0x08}, ++ {0x34, 0x00}, ++ {0x30, 0x15}, ++ {0x33, 0x01}, ++ {0x35, 0x20}, ++ {0x1d, 0xa5}, ++ {0xfd, 0x01}, ++ {0x0d, 0x00}, ++ {0x30, 0x00}, ++ {0x03, 0x01}, ++ {0x04, 0x8f}, ++ {0x01, 0x01}, ++ {0x09, 0x00}, ++ {0x0a, 0x20}, ++ {0x06, 0x0a}, ++ {0x24, 0x10}, ++ {0x01, 0x01}, ++ {0xfb, 0x73}, ++ {0x01, 0x01}, ++ {0xfd, 0x01}, ++ {0x1a, 0x6b}, ++ {0x1c, 0xea}, ++ {0x16, 0x0c}, ++ {0x21, 0x00}, ++ {0x11, 0x63}, ++ {0x19, 0xc3}, ++ {0x26, 0xda}, ++ {0x29, 0x01}, ++ {0x33, 0x6f}, ++ {0x2a, 0xd2}, ++ {0x2c, 0x40}, ++ {0xd0, 0x02}, ++ {0xd1, 0x01}, ++ {0xd2, 0x20}, ++ {0xd3, 0x04}, ++ {0xd4, 0x2a}, ++ {0x50, 0x00}, ++ {0x51, 0x2c}, ++ {0x52, 0x29}, ++ {0x53, 0x00}, ++ {0x55, 0x44}, ++ {0x58, 0x29}, ++ {0x5a, 0x00}, ++ {0x5b, 0x00}, ++ {0x5d, 0x00}, ++ {0x64, 0x2f}, ++ {0x66, 0x62}, ++ {0x68, 0x5b}, ++ {0x75, 0x46}, ++ {0x76, 0xf0}, ++ {0x77, 0x4f}, ++ {0x78, 0xef}, ++ {0x72, 0xcf}, ++ {0x73, 0x36}, ++ {0x7d, 0x0d}, ++ {0x7e, 0x0d}, ++ {0x8a, 0x77}, ++ {0x8b, 0x77}, ++ {0xfd, 0x01}, ++ {0xb1, 0x82}, ++ {0xb3, 0x0b}, ++ {0xb4, 0x14}, ++ {0x9d, 0x40}, ++ {0xa1, 0x05}, ++ {0x94, 0x44}, ++ {0x95, 0x33}, ++ {0x96, 0x1f}, ++ {0x98, 0x45}, ++ {0x9c, 0x10}, ++ {0xb5, 0x70}, ++ {0xa0, 0x00}, ++ {0x25, 0xe0}, ++ {0x20, 0x7b}, ++ {0x8f, 0x88}, ++ {0x91, 0x40}, ++ {0xfd, 0x01}, ++ {0xfd, 0x02}, ++ {0x5e, 0x03}, ++ {0xfd, 0x02}, ++ {0x60, 0xf0}, ++ {0xa1, 0x04}, ++ {0xa3, 0x40}, ++ {0xa5, 0x02}, ++ {0xa7, 0xc4}, ++ {0xfd, 0x01}, ++ {0x86, 0x77}, ++ {0x89, 0x77}, ++ {0x87, 0x74}, ++ {0x88, 0x74}, ++ {0xfc, 0xe0}, ++ {0xfe, 0xe0}, ++ {0xf0, 0x40}, ++ {0xf1, 0x40}, ++ {0xf2, 0x40}, ++ {0xf3, 0x40}, ++ {0xfd, 0x02}, ++ {0x36, 0x08}, ++ {0xa0, 0x00}, ++ {0xa1, 0x08}, ++ {0xa2, 0x04}, ++ {0xa3, 0x38}, ++ {0xa4, 0x00}, ++ {0xa5, 0x04}, ++ {0xa6, 0x03}, ++ {0xa7, 0xc0}, ++ {0xfd, 0x03}, ++ {0xc0, 0x01},//OTP transf ++ {0xfd, 0x04}, ++ {0x22, 0x14}, ++ {0x23, 0x14}, ++ {0xfd, 0x01}, ++ {0x06, 0xe0}, ++ {0x01, 0x01}, ++ {0xfd, 0x00}, ++ {0x1b, 0x00}, ++ {0xfd, 0x01}, ++ {0x0d, 0x10}, ++ {0x0e, 0x07}, ++ {0x0f, 0x6b}, ++ {0x01, 0x01}, ++ {0xfd, 0x00}, ++ {0x36, 0x01}, ++ {0x37, 0x01},//fake stream off ++ ++ {OV2735B_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov2735b_stream_on[] = { ++ {0xfd, 0x00}, ++ {0x36, 0x00}, ++ {0x37, 0x00},//fake stream on ++ ++ {OV2735B_REG_END, 0x00}, ++}; ++ ++static struct regval_list ov2735b_stream_off[] = { ++ {0xfd, 0x00}, ++ {0x36, 0x01}, ++ {0x37, 0x01},//fake stream off ++ ++ {OV2735B_REG_END, 0x00}, ++}; ++ ++ ++int ov2735b_read(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 1, ++ .buf = ®, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735b_write(struct v4l2_subdev *sd, unsigned char reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ unsigned char buf[2] = {reg, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }; ++ int ret; ++ unsigned int timeout = 100; ++ while(timeout--){ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == -EAGAIN){ ++ msleep(100); ++ continue; ++ } ++ else ++ break; ++ } ++ ++ if (ret > 0) ++ ret = 0; ++ return ret; ++} ++ ++static int ov2735b_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != OV2735B_REG_END) { ++ if (vals->reg_num == OV2735B_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov2735b_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ if (vals->reg_num == OV2735B_PAGE_REG){ ++ val &= 0xf8; ++ val |= (vals->value & 0x07); ++ ret = ov2735b_write(sd, vals->reg_num, val); ++ ret = ov2735b_read(sd, vals->reg_num, &val); ++ } ++ } ++ vals++; ++ } ++ return 0; ++} ++static int ov2735b_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != OV2735B_REG_END) { ++ if (vals->reg_num == OV2735B_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov2735b_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ov2735b_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov2735b_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int ov2735b_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov2735b_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int ov2735b_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov2735b_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov2735b_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int ov2735b_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ ret = ov2735b_read(sd, 0x02, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV2735B_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = ov2735b_read(sd, 0x03, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV2735B_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ ret = ov2735b_read(sd, 0x04, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != 0x05 && v != 0x06 && v != 0x07) ++ return -ENODEV; ++ ++ ++ return 0; ++} ++ ++ ++static struct ov2735b_win_size ov2735b_win_sizes[] = { ++ /* 1920*1080 */ ++ { ++ ++ .sensor_info.fps = 30 << 16 | 1, ++ ++ .width = 1920, ++ .height = 1080, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov2735b_init_regs_1920_1080_30fps_dvp, ++ } ++}; ++ ++static int ov2735b_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_OV2735B_FMTS) ++ return -EINVAL; ++ ++ code->code = ov2735b_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int ov2735b_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov2735b_format_struct *ovfmt; ++ struct ov2735b_win_size *wsize; ++ struct ov2735b_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ov2735b_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov2735b_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ov2735b_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735b_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735b_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735b_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ov2735b_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ov2735b_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov2735b_again_lut); i++) { ++ lut = &ov2735b_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov2735b_again_lut); i++) { ++ lut = &ov2735b_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++ ++static int ov2735b_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret = ov2735b_read(sd, 0x23, &v); ++ reg_val |= v ; ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++ ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ov2735b_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct ov2735b_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret = ov2735b_write(sd, 0xfd, 0x01); ++ ret += ov2735b_write(sd, 0x24, (unsigned char)reg_value); ++ ret += ov2735b_write(sd, 0x01, 0x01); ++ if (ret < 0){ ++ printk("ov2735b_write error %d\n" ,__LINE__ ); ++ return ret; ++ } ++ return 0; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ov2735b_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov2735b_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct ov2735b_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov2735b_write(sd, 0xfd, 0x01); ++ ret += ov2735b_write(sd, 0x4, (unsigned char)(value & 0xff)); ++ ret += ov2735b_write(sd, 0x3, (unsigned char)((value & 0xff00) >> 8)); ++ ret += ov2735b_write(sd, 0x01, 0x01); ++ ++ if (ret < 0) { ++ printk("ov2735b_write error %d\n" ,__LINE__); ++ return ret; ++ } ++ return ret; ++} ++ ++static int ov2735b_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov2735b_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ov2735b_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov2735b_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ov2735b_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov2735b_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ov2735b_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ov2735b_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ov2735b_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ov2735b_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ov2735b_s_gain turns off auto gain */ ++ return ov2735b_s_gain(sd, info->gain->val); ++ } ++ return ov2735b_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ov2735b_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov2735b_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ov2735b_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ov2735b_ctrl_ops = { ++ .s_ctrl = ov2735b_s_ctrl, ++ .g_volatile_ctrl = ov2735b_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov2735b_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ov2735b_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ov2735b_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ov2735b_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++static int ov2735b_power(struct v4l2_subdev *sd, int on) ++{ ++ struct ov2735b_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ info->supply.avdd = devm_regulator_get_optional(&client->dev, "avdd"); ++ info->supply.dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); ++ info->supply.dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); ++ ++ if (IS_ERR(info->supply.avdd)||IS_ERR(info->supply.dvdd) ++ ||IS_ERR(info->supply.dovdd)) { ++ if ((PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.avdd) == -EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ printk("No ov2735b vdd regulator found\n"); ++ } ++ ++ if ((!IS_ERR(info->supply.avdd))&&(!IS_ERR(info->supply.avdd)) ++ &&(!IS_ERR(info->supply.avdd))) { ++ if(on){ ++ ret = regulator_enable(info->supply.avdd); ++ ret = regulator_enable(info->supply.dvdd); ++ ret = regulator_enable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "ov2735b vdd supply disable failed\n"); ++ } ++ else{ ++ ret = regulator_disable(info->supply.avdd); ++ ret = regulator_disable(info->supply.dvdd); ++ ret = regulator_disable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "ov2735b vdd supply disable failed\n"); ++ } ++ }else{ ++ dev_err(&client->dev, "ov2735b vdd supply IS_ERR failed\n"); ++ } ++ return ret; ++} ++ ++ ++ ++ ++int ov2735b_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ov2735b_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ret = ov2735b_write_array(sd, ov2735b_stream_on); ++ pr_debug("ov2735b stream on\n"); ++ ++ } ++ else { ++ ret = ov2735b_write_array(sd, ov2735b_stream_off); ++ pr_debug("ov2735b stream off\n"); ++ } ++ return ret; ++} ++ ++int ov2735b_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct ov2735b_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ov2735b_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov2735b_g_register, ++ .s_register = ov2735b_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops ov2735b_video_ops = { ++ .s_stream = ov2735b_s_stream, ++ .g_frame_interval = ov2735b_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov2735b_pad_ops = { ++ //.enum_frame_interval = ov2735b_enum_frame_interval, ++ //.num_frame_size = ov2735b_enum_frame_size, ++ //.enum_mbus_code = ov2735b_enum_mbus_code, ++ .set_fmt = ov2735b_set_fmt, ++ .get_fmt = ov2735b_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops ov2735b_ops = { ++ .core = &ov2735b_core_ops, ++ .video = &ov2735b_video_ops, ++ .pad = &ov2735b_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int ov2735b_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct ov2735b_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &ov2735b_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ ov2735b_power(sd,1); ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ ov2735b_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ov2735b */ ++ ret = ov2735b_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ov2735b chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ /*IRCUT ctl 0:off 1:on*/ ++ ov2735b_ircut(sd, 0); ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735b_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735b_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735b_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ov2735b_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ov2735b_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ov2735b_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 259142, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov2735b_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1899 - 4, 1, 1500); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &ov2735b_win_sizes[0]; ++ ov2735b_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ov2735b Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ov2735b_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov2735b_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id ov2735b_id[] = { ++ { "ov2735b", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov2735b_id); ++ ++static const struct of_device_id ov2735b_of_match[] = { ++ {.compatible = "ovti,ov2735b", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2735b_of_match); ++ ++ ++static int ov2735b_suspend(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov2735b_info *info = to_state(sd); ++ int ret=0; ++ ++ ov2735b_power(sd,0); ++ v4l2_clk_disable(info->clk); ++ return 0; ++} ++ ++static int ov2735b_resume(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov2735b_info *info = to_state(sd); ++ int ret=0; ++ ++ ov2735b_power(sd,1); ++ v4l2_clk_enable(info->clk); ++ ov2735b_reset(sd, 1); ++ ov2735b_init(sd, 1); ++ return 0; ++} ++ ++const struct dev_pm_ops ov2735b_pm = ++{ ++ .suspend = ov2735b_suspend, ++ .resume = ov2735b_resume, ++}; ++ ++static struct i2c_driver ov2735b_driver = { ++ .driver = { ++ .name = "ov2735b", ++ .of_match_table = of_match_ptr(ov2735b_of_match), ++ .pm = &ov2735b_pm, ++ }, ++ .probe = ov2735b_probe, ++ .remove = ov2735b_remove, ++ .id_table = ov2735b_id, ++}; ++ ++module_i2c_driver(ov2735b_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision ov2735b sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/ov4689.c b/module_drivers/drivers/media/i2c/ingenic-isp/ov4689.c +new file mode 100644 +index 000000000..462ecff03 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/ov4689.c +@@ -0,0 +1,3224 @@ ++/* ++ * A V4L2 driver for OmniVision OV4689 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define OV4689_CHIP_ID_H (0x46) ++#define OV4689_CHIP_ID_L (0x88) ++#define OV4689_REG_END 0xffff ++#define OV4689_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ov4689_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ov4689_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov4689_supply{ ++ struct regulator *avdd; ++ struct regulator *dvdd; ++ struct regulator *dovdd; ++}; ++ ++struct ov4689_info { ++ struct ov4689_supply supply; ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ov4689_win_size *win; ++ ++ struct ov4689_gpio reset; ++ struct ov4689_gpio ircutp; ++ struct ov4689_gpio ircutn; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut ov4689_again_lut[] = { ++ ++ {0x80, 0}, ++ {0x88, 5731}, ++ {0x90, 11136}, ++ {0x98, 16248}, ++ {0xa0, 21097}, ++ {0xa8, 25710}, ++ {0xb0, 30109}, ++ {0xb8, 34312}, ++ {0xc0, 38336}, ++ {0xc8, 42195}, ++ {0xd0, 45904}, ++ {0xd8, 49472}, ++ {0xe0, 52910}, ++ {0xe8, 56228}, ++ {0xf0, 59433}, ++ {0xf8, 62534}, ++ {0x178, 65536}, ++ {0x17c, 68445}, ++ {0x180, 71267}, ++ {0x184, 74008}, ++ {0x188, 76672}, ++ {0x18c, 79262}, ++ {0x190, 81784}, ++ {0x194, 84240}, ++ {0x198, 86633}, ++ {0x19c, 88968}, ++ {0x1a0, 91246}, ++ {0x1a4, 93471}, ++ {0x1a8, 95645}, ++ {0x1ac, 97770}, ++ {0x1b0, 99848}, ++ {0x1b4, 101881}, ++ {0x1b8, 103872}, ++ {0x1bc, 105821}, ++ {0x1c0, 107731}, ++ {0x1c4, 109604}, ++ {0x1c8, 111440}, ++ {0x1cc, 113241}, ++ {0x1d0, 115008}, ++ {0x1d4, 116743}, ++ {0x1d8, 118446}, ++ {0x1dc, 120120}, ++ {0x1e0, 121764}, ++ {0x1e4, 123380}, ++ {0x1e8, 124969}, ++ {0x1ec, 126532}, ++ {0x1f0, 128070}, ++ {0x1f4, 129583}, ++ {0x374, 131072}, ++ {0x376, 132537}, ++ {0x378, 133981}, ++ {0x37a, 135403}, ++ {0x37c, 136803}, ++ {0x37e, 138184}, ++ {0x380, 139544}, ++ {0x382, 140885}, ++ {0x384, 142208}, ++ {0x386, 143512}, ++ {0x388, 144798}, ++ {0x38a, 146067}, ++ {0x38c, 147320}, ++ {0x38e, 148556}, ++ {0x390, 149776}, ++ {0x392, 150980}, ++ {0x394, 152169}, ++ {0x396, 153344}, ++ {0x398, 154504}, ++ {0x39a, 155650}, ++ {0x39c, 156782}, ++ {0x39e, 157901}, ++ {0x3a0, 159007}, ++ {0x3a2, 160100}, ++ {0x3a4, 161181}, ++ {0x3a6, 162249}, ++ {0x3a8, 163306}, ++ {0x3aa, 164350}, ++ {0x3ac, 165384}, ++ {0x3ae, 166406}, ++ {0x3b0, 167417}, ++ {0x3b2, 168418}, ++ {0x3b4, 169408}, ++ {0x3b6, 170387}, ++ {0x3b8, 171357}, ++ {0x3ba, 172317}, ++ {0x3bc, 173267}, ++ {0x3be, 174208}, ++ {0x3c0, 175140}, ++ {0x3c2, 176062}, ++ {0x3c4, 176976}, ++ {0x3c6, 177880}, ++ {0x3c8, 178777}, ++ {0x3ca, 179664}, ++ {0x3cc, 180544}, ++ {0x3ce, 181415}, ++ {0x3d0, 182279}, ++ {0x3d2, 183134}, ++ {0x3d4, 183982}, ++ {0x3d6, 184823}, ++ {0x3d8, 185656}, ++ {0x3da, 186482}, ++ {0x3dc, 187300}, ++ {0x3de, 188112}, ++ {0x3e0, 188916}, ++ {0x3e2, 189714}, ++ {0x3e4, 190505}, ++ {0x3e6, 191290}, ++ {0x3e8, 192068}, ++ {0x3ea, 192840}, ++ {0x3ec, 193606}, ++ {0x3ee, 194365}, ++ {0x3f0, 195119}, ++ {0x3f2, 195866}, ++ {0x778, 196608}, ++ {0x779, 197343}, ++ {0x77a, 198073}, ++ {0x77b, 198798}, ++ {0x77c, 199517}, ++ {0x77d, 200230}, ++ {0x77e, 200939}, ++ {0x77f, 201642}, ++ {0x780, 202339}, ++ {0x781, 203032}, ++ {0x782, 203720}, ++ {0x783, 204402}, ++ {0x784, 205080}, ++ {0x785, 205753}, ++ {0x786, 206421}, ++ {0x787, 207085}, ++ {0x788, 207744}, ++ {0x789, 208398}, ++ {0x78a, 209048}, ++ {0x78b, 209693}, ++ {0x78c, 210334}, ++ {0x78d, 210971}, ++ {0x78e, 211603}, ++ {0x78f, 212232}, ++ {0x790, 212856}, ++ {0x791, 213476}, ++ {0x792, 214092}, ++ {0x793, 214704}, ++ {0x794, 215312}, ++ {0x795, 215916}, ++ {0x796, 216516}, ++ {0x797, 217113}, ++ {0x798, 217705}, ++ {0x799, 218294}, ++ {0x79a, 218880}, ++ {0x79b, 219462}, ++ {0x79c, 220040}, ++ {0x79d, 220615}, ++ {0x79e, 221186}, ++ {0x79f, 221754}, ++ {0x7a0, 222318}, ++ {0x7a1, 222880}, ++ {0x7a2, 223437}, ++ {0x7a3, 223992}, ++ {0x7a4, 224543}, ++ {0x7a5, 225091}, ++ {0x7a6, 225636}, ++ {0x7a7, 226178}, ++ {0x7a8, 226717}, ++ {0x7a9, 227253}, ++ {0x7aa, 227785}, ++ {0x7ab, 228315}, ++ {0x7ac, 228842}, ++ {0x7ad, 229365}, ++ {0x7ae, 229886}, ++ {0x7af, 230404}, ++ {0x7b0, 230920}, ++ {0x7b1, 231432}, ++ {0x7b2, 231942}, ++ {0x7b3, 232449}, ++ {0x7b4, 232953}, ++ {0x7b5, 233455}, ++ {0x7b6, 233954}, ++ {0x7b7, 234450}, ++ {0x7b8, 234944}, ++ {0x7b9, 235435}, ++ {0x7ba, 235923}, ++ {0x7bb, 236410}, ++ {0x7bc, 236893}, ++ {0x7bd, 237374}, ++ {0x7be, 237853}, ++ {0x7bf, 238329}, ++ {0x7c0, 238803}, ++ {0x7c1, 239275}, ++ {0x7c2, 239744}, ++ {0x7c3, 240211}, ++ {0x7c4, 240676}, ++ {0x7c5, 241138}, ++ {0x7c6, 241598}, ++ {0x7c7, 242056}, ++ {0x7c8, 242512}, ++ {0x7c9, 242965}, ++ {0x7ca, 243416}, ++ {0x7cb, 243865}, ++ {0x7cc, 244313}, ++ {0x7cd, 244757}, ++ {0x7ce, 245200}, ++ {0x7cf, 245641}, ++ {0x7d0, 246080}, ++ {0x7d1, 246517}, ++ {0x7d2, 246951}, ++ {0x7d3, 247384}, ++ {0x7d4, 247815}, ++ {0x7d5, 248243}, ++ {0x7d6, 248670}, ++ {0x7d7, 249095}, ++ {0x7d8, 249518}, ++ {0x7d9, 249939}, ++ {0x7da, 250359}, ++ {0x7db, 250776}, ++ {0x7dc, 251192}, ++ {0x7dd, 251606}, ++ {0x7de, 252018}, ++ {0x7df, 252428}, ++ {0x7e0, 252836}, ++ {0x7e1, 253243}, ++ {0x7e2, 253648}, ++ {0x7e3, 254051}, ++ {0x7e4, 254452}, ++ {0x7e5, 254852}, ++ {0x7e6, 255250}, ++ {0x7e7, 255647}, ++ {0x7e8, 256041}, ++ {0x7e9, 256435}, ++ {0x7ea, 256826}, ++ {0x7eb, 257216}, ++ {0x7ec, 257604}, ++ {0x7ed, 257991}, ++ {0x7ee, 258376}, ++ {0x7ef, 258760}, ++ {0x7f0, 259142}, ++ {0x7f1, 259522}, ++ {0x7f2, 259901}, ++ {0x7f3, 260279}, ++ {0x7f4, 260655}, ++ {0x7f5, 261029}, ++ {0x7f6, 261402}, ++ {0x7f7, 261773}, ++}; ++ ++static inline struct ov4689_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ov4689_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov4689_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++ ++static struct regval_list ov4689_init_regs_1920_1080_120fps_mipi[] = { ++ // @@ 0 35 RES_1920x1080_120fps_1008Mbps ++ // 100 99 1920 1080 ++ //102 3601 2ee0 ++ ++ { 0x0103, 0x01 }, ++ { 0x3638, 0x00 }, ++ { 0x0300, 0x00 }, ++ { 0x0302, 0x2a }, ++ { 0x0303, 0x00 }, ++ { 0x0304, 0x03 }, ++ { 0x030b, 0x00 }, ++ { 0x030d, 0x1e }, ++ { 0x030e, 0x04 }, ++ { 0x030f, 0x01 }, ++ { 0x0312, 0x01 }, ++ { 0x031e, 0x00 }, ++ { 0x3000, 0x20 }, ++ { 0x3002, 0x00 }, ++ { 0x3018, 0x72 }, ++ { 0x3020, 0x93 }, ++ { 0x3021, 0x03 }, ++ { 0x3022, 0x01 }, ++ { 0x3031, 0x0a }, ++ { 0x303f, 0x0c }, ++ { 0x3305, 0xf1 }, ++ { 0x3307, 0x04 }, ++ { 0x3309, 0x29 }, ++ { 0x3500, 0x00 }, ++ { 0x3501, 0x4c }, ++ { 0x3502, 0x00 }, ++ { 0x3503, 0x04 }, ++ { 0x3504, 0x00 }, ++ { 0x3505, 0x00 }, ++ { 0x3506, 0x00 }, ++ { 0x3507, 0x00 }, ++ { 0x3508, 0x00 }, ++ { 0x3509, 0x80 }, ++ { 0x350a, 0x00 }, ++ { 0x350b, 0x00 }, ++ { 0x350c, 0x00 }, ++ { 0x350d, 0x00 }, ++ { 0x350e, 0x00 }, ++ { 0x350f, 0x80 }, ++ { 0x3510, 0x00 }, ++ { 0x3511, 0x00 }, ++ { 0x3512, 0x00 }, ++ { 0x3513, 0x00 }, ++ { 0x3514, 0x00 }, ++ { 0x3515, 0x80 }, ++ { 0x3516, 0x00 }, ++ { 0x3517, 0x00 }, ++ { 0x3518, 0x00 }, ++ { 0x3519, 0x00 }, ++ { 0x351a, 0x00 }, ++ { 0x351b, 0x80 }, ++ { 0x351c, 0x00 }, ++ { 0x351d, 0x00 }, ++ { 0x351e, 0x00 }, ++ { 0x351f, 0x00 }, ++ { 0x3520, 0x00 }, ++ { 0x3521, 0x80 }, ++ { 0x3522, 0x08 }, ++ { 0x3524, 0x08 }, ++ { 0x3526, 0x08 }, ++ { 0x3528, 0x08 }, ++ { 0x352a, 0x08 }, ++ { 0x3602, 0x00 }, ++ { 0x3603, 0x40 }, ++ { 0x3604, 0x02 }, ++ { 0x3605, 0x00 }, ++ { 0x3606, 0x00 }, ++ { 0x3607, 0x00 }, ++ { 0x3609, 0x12 }, ++ { 0x360a, 0x40 }, ++ { 0x360c, 0x08 }, ++ { 0x360f, 0xe5 }, ++ { 0x3608, 0x8f }, ++ { 0x3611, 0x00 }, ++ { 0x3613, 0xf7 }, ++ { 0x3616, 0x58 }, ++ { 0x3619, 0x99 }, ++ { 0x361b, 0x60 }, ++ { 0x361c, 0x7a }, ++ { 0x361e, 0x79 }, ++ { 0x361f, 0x02 }, ++ { 0x3632, 0x00 }, ++ { 0x3633, 0x10 }, ++ { 0x3634, 0x10 }, ++ { 0x3635, 0x10 }, ++ { 0x3636, 0x15 }, ++ { 0x3646, 0x86 }, ++ { 0x364a, 0x0b }, ++ { 0x3700, 0x17 }, ++ { 0x3701, 0x22 }, ++ { 0x3703, 0x10 }, ++ { 0x370a, 0x37 }, ++ { 0x3705, 0x00 }, ++ { 0x3706, 0x63 }, ++ { 0x3709, 0x3c }, ++ { 0x370b, 0x01 }, ++ { 0x370c, 0x30 }, ++ { 0x3710, 0x24 }, ++ { 0x3711, 0x0c }, ++ { 0x3716, 0x00 }, ++ { 0x3720, 0x28 }, ++ { 0x3729, 0x7b }, ++ { 0x372a, 0x84 }, ++ { 0x372b, 0xbd }, ++ { 0x372c, 0xbc }, ++ { 0x372e, 0x52 }, ++ { 0x373c, 0x0e }, ++ { 0x373e, 0x33 }, ++ { 0x3743, 0x10 }, ++ { 0x3744, 0x88 }, ++ { 0x3745, 0xc0 }, ++ { 0x374a, 0x43 }, ++ { 0x374c, 0x00 }, ++ { 0x374e, 0x23 }, ++ { 0x3751, 0x7b }, ++ { 0x3752, 0x84 }, ++ { 0x3753, 0xbd }, ++ { 0x3754, 0xbc }, ++ { 0x3756, 0x52 }, ++ { 0x375c, 0x00 }, ++ { 0x3760, 0x00 }, ++ { 0x3761, 0x00 }, ++ { 0x3762, 0x00 }, ++ { 0x3763, 0x00 }, ++ { 0x3764, 0x00 }, ++ { 0x3767, 0x04 }, ++ { 0x3768, 0x04 }, ++ { 0x3769, 0x08 }, ++ { 0x376a, 0x08 }, ++ { 0x376b, 0x20 }, ++ { 0x376c, 0x00 }, ++ { 0x376d, 0x00 }, ++ { 0x376e, 0x00 }, ++ { 0x3773, 0x00 }, ++ { 0x3774, 0x51 }, ++ { 0x3776, 0xbd }, ++ { 0x3777, 0xbd }, ++ { 0x3781, 0x18 }, ++ { 0x3783, 0x25 }, ++ { 0x3798, 0x1b }, ++ { 0x3800, 0x01 }, ++ { 0x3801, 0x88 }, ++ { 0x3802, 0x00 }, ++ { 0x3803, 0xe0 }, ++ { 0x3804, 0x09 }, ++ { 0x3805, 0x17 }, ++ { 0x3806, 0x05 }, ++ { 0x3807, 0x1f }, ++ { 0x3808, 0x07 }, ++ { 0x3809, 0x80 }, ++ { 0x380a, 0x04 }, ++ { 0x380b, 0x38 }, ++ { 0x380c, 0x03 }, ++ { 0x380d, 0x5c }, ++ { 0x380e, 0x04 }, ++ { 0x380f, 0x8A }, ++ { 0x3810, 0x00 }, ++ { 0x3811, 0x08 }, ++ { 0x3812, 0x00 }, ++ { 0x3813, 0x04 }, ++ { 0x3814, 0x01 }, ++ { 0x3815, 0x01 }, ++ { 0x3819, 0x01 }, ++ { 0x3820, 0x00 }, ++ { 0x3821, 0x06 }, ++ { 0x3829, 0x00 }, ++ { 0x382a, 0x01 }, ++ { 0x382b, 0x01 }, ++ { 0x382d, 0x7f }, ++ { 0x3830, 0x04 }, ++ { 0x3836, 0x01 }, ++ { 0x3837, 0x00 }, ++ { 0x3841, 0x02 }, ++ { 0x3846, 0x08 }, ++ { 0x3847, 0x07 }, ++ { 0x3d85, 0x36 }, ++ { 0x3d8c, 0x71 }, ++ { 0x3d8d, 0xcb }, ++ { 0x3f0a, 0x00 }, ++ { 0x4000, 0xf1 }, ++ { 0x4001, 0x40 }, ++ { 0x4002, 0x04 }, ++ { 0x4003, 0x14 }, ++ { 0x400e, 0x00 }, ++ { 0x4011, 0x00 }, ++ { 0x401a, 0x00 }, ++ { 0x401b, 0x00 }, ++ { 0x401c, 0x00 }, ++ { 0x401d, 0x00 }, ++ { 0x401f, 0x00 }, ++ { 0x4020, 0x00 }, ++ { 0x4021, 0x10 }, ++ { 0x4022, 0x06 }, ++ { 0x4023, 0x13 }, ++ { 0x4024, 0x07 }, ++ { 0x4025, 0x40 }, ++ { 0x4026, 0x07 }, ++ { 0x4027, 0x50 }, ++ { 0x4028, 0x00 }, ++ { 0x4029, 0x02 }, ++ { 0x402a, 0x06 }, ++ { 0x402b, 0x04 }, ++ { 0x402c, 0x02 }, ++ { 0x402d, 0x02 }, ++ { 0x402e, 0x0e }, ++ { 0x402f, 0x04 }, ++ { 0x4302, 0xff }, ++ { 0x4303, 0xff }, ++ { 0x4304, 0x00 }, ++ { 0x4305, 0x00 }, ++ { 0x4306, 0x00 }, ++ { 0x4308, 0x02 }, ++ { 0x4500, 0x6c }, ++ { 0x4501, 0xc4 }, ++ { 0x4502, 0x40 }, ++ { 0x4503, 0x01 }, ++ { 0x4601, 0x77 }, ++ { 0x4800, 0x04 }, ++ { 0x4813, 0x08 }, ++ { 0x481f, 0x40 }, ++ { 0x4829, 0x78 }, ++ { 0x4837, 0x10 }, // ++ { 0x4b00, 0x2a }, ++ { 0x4b0d, 0x00 }, ++ { 0x4d00, 0x04 }, ++ { 0x4d01, 0x42 }, ++ { 0x4d02, 0xd1 }, ++ { 0x4d03, 0x93 }, ++ { 0x4d04, 0xf5 }, ++ { 0x4d05, 0xc1 }, ++ { 0x5000, 0xf3 }, ++ { 0x5001, 0x11 }, ++ { 0x5004, 0x00 }, ++ { 0x500a, 0x00 }, ++ { 0x500b, 0x00 }, ++ { 0x5032, 0x00 }, ++ { 0x5040, 0x00 }, ++ { 0x5050, 0x0c }, ++ { 0x5500, 0x00 }, ++ { 0x5501, 0x10 }, ++ { 0x5502, 0x01 }, ++ { 0x5503, 0x0f }, ++ { 0x8000, 0x00 }, ++ { 0x8001, 0x00 }, ++ { 0x8002, 0x00 }, ++ { 0x8003, 0x00 }, ++ { 0x8004, 0x00 }, ++ { 0x8005, 0x00 }, ++ { 0x8006, 0x00 }, ++ { 0x8007, 0x00 }, ++ { 0x8008, 0x00 }, ++ { 0x3638, 0x00 }, ++ { 0x0100, 0x00 }, ++// { 0x5040, 0x80 }, /* color bar */ ++ {OV4689_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov4689_init_regs_1920_1080_30fps_mipi[] = { ++#if 0 //1080p@30fps 1 lane ok ++ /* @@ 0 35 RES_1920x1080_30fps_816Mbps 1Lane */ ++ /* ;SCLK = 80MHz MIPI CLK = 816Mbps/lane Mipi PCLK = 102MHz */ ++ /* ;HTS = 2294 VTS = 1162 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x22}, ++ {0x0303, 0x00}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x02}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++ {0x3018, 0x02}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x88}, ++ {0x3802, 0x00}, ++ {0x3803, 0xe0}, ++ {0x3804, 0x09}, ++ {0x3805, 0x17}, ++ {0x3806, 0x05}, ++ {0x3807, 0x1f}, ++ {0x3808, 0x07}, ++ {0x3809, 0x80}, ++ {0x380a, 0x04}, ++ {0x380b, 0x38}, ++ {0x380c, 0x08}, ++ {0x380d, 0xf6}, ++ {0x380e, 0x04}, ++ {0x380f, 0x8A}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x13}, ++ {0x4024, 0x07}, ++ {0x4025, 0x40}, ++ {0x4026, 0x07}, ++ {0x4027, 0x50}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x77}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x2d}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++#endif ++#if 1 ++ //1080p@30fps 2 or 4 lane ++ /* @@ 0 35 RES_1920x1080_30fps_816Mbps 2Lane */ ++ /* ;SCLK = 80MHz MIPI CLK = 816Mbps/lane Mipi PCLK = 102MHz */ ++ /* ;HTS = 2294 VTS = 1162 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x23}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x02}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++// {0x3018, 0x72}, //4lan ++ {0x3018, 0x32}, //2lan ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x88}, ++ {0x3802, 0x00}, ++ {0x3803, 0xe0}, ++ {0x3804, 0x09}, ++ {0x3805, 0x17}, ++ {0x3806, 0x05}, ++ {0x3807, 0x1f}, ++ {0x3808, 0x07}, ++ {0x3809, 0x80}, ++ {0x380a, 0x04}, ++ {0x380b, 0x38}, ++ {0x380c, 0x08}, ++ {0x380d, 0xf6}, ++ {0x380e, 0x04}, ++ {0x380f, 0x8A}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x13}, ++ {0x4024, 0x07}, ++ {0x4025, 0x40}, ++ {0x4026, 0x07}, ++ {0x4027, 0x50}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x77}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++// {0x4837, 0x14}, //for zebra ++ {0x4837, 0x80}, //for halley5 ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++#endif ++#if 0 ++ /*support by ov , dosen't word in zebra & halley5*/ ++// @@ 0 35 RES_1920x1080_30fps_1008Mbps 4lane ++//100 99 1920 1080 ++//102 3601 2ee0 ++ { 0x0103, 0x01 }, ++ { 0x3638, 0x00 }, ++ { 0x0300, 0x00 }, ++ { 0x0302, 0x2a }, ++ { 0x0303, 0x00 }, ++ { 0x0304, 0x03 }, ++ { 0x030b, 0x00 }, ++ { 0x030d, 0x1e }, ++ { 0x030e, 0x04 }, ++ { 0x030f, 0x01 }, ++ { 0x0312, 0x01 }, ++ { 0x031e, 0x00 }, ++ { 0x3000, 0x20 }, ++ { 0x3002, 0x00 }, ++ { 0x3018, 0x72 }, ++// { 0x3018, 0x32 }, ++ { 0x3020, 0x93 }, ++ { 0x3021, 0x03 }, ++ { 0x3022, 0x01 }, ++ { 0x3031, 0x0a }, ++ { 0x303f, 0x0c }, ++ { 0x3305, 0xf1 }, ++ { 0x3307, 0x04 }, ++ { 0x3309, 0x29 }, ++ { 0x3500, 0x00 }, ++ { 0x3501, 0x4c }, ++ { 0x3502, 0x00 }, ++ { 0x3503, 0x04 }, ++ { 0x3504, 0x00 }, ++ { 0x3505, 0x00 }, ++ { 0x3506, 0x00 }, ++ { 0x3507, 0x00 }, ++ { 0x3508, 0x00 }, ++ { 0x3509, 0x80 }, ++ { 0x350a, 0x00 }, ++ { 0x350b, 0x00 }, ++ { 0x350c, 0x00 }, ++ { 0x350d, 0x00 }, ++ { 0x350e, 0x00 }, ++ { 0x350f, 0x80 }, ++ { 0x3510, 0x00 }, ++ { 0x3511, 0x00 }, ++ { 0x3512, 0x00 }, ++ { 0x3513, 0x00 }, ++ { 0x3514, 0x00 }, ++ { 0x3515, 0x80 }, ++ { 0x3516, 0x00 }, ++ { 0x3517, 0x00 }, ++ { 0x3518, 0x00 }, ++ { 0x3519, 0x00 }, ++ { 0x351a, 0x00 }, ++ { 0x351b, 0x80 }, ++ { 0x351c, 0x00 }, ++ { 0x351d, 0x00 }, ++ { 0x351e, 0x00 }, ++ { 0x351f, 0x00 }, ++ { 0x3520, 0x00 }, ++ { 0x3521, 0x80 }, ++ { 0x3522, 0x08 }, ++ { 0x3524, 0x08 }, ++ { 0x3526, 0x08 }, ++ { 0x3528, 0x08 }, ++ { 0x352a, 0x08 }, ++ { 0x3602, 0x00 }, ++ { 0x3603, 0x40 }, ++ { 0x3604, 0x02 }, ++ { 0x3605, 0x00 }, ++ { 0x3606, 0x00 }, ++ { 0x3607, 0x00 }, ++ { 0x3609, 0x12 }, ++ { 0x360a, 0x40 }, ++ { 0x360c, 0x08 }, ++ { 0x360f, 0xe5 }, ++ { 0x3608, 0x8f }, ++ { 0x3611, 0x00 }, ++ { 0x3613, 0xf7 }, ++ { 0x3616, 0x58 }, ++ { 0x3619, 0x99 }, ++ { 0x361b, 0x60 }, ++ { 0x361c, 0x7a }, ++ { 0x361e, 0x79 }, ++ { 0x361f, 0x02 }, ++ { 0x3632, 0x00 }, ++ { 0x3633, 0x10 }, ++ { 0x3634, 0x10 }, ++ { 0x3635, 0x10 }, ++ { 0x3636, 0x15 }, ++ { 0x3646, 0x86 }, ++ { 0x364a, 0x0b }, ++ { 0x3700, 0x17 }, ++ { 0x3701, 0x22 }, ++ { 0x3703, 0x10 }, ++ { 0x370a, 0x37 }, ++ { 0x3705, 0x00 }, ++ { 0x3706, 0x63 }, ++ { 0x3709, 0x3c }, ++ { 0x370b, 0x01 }, ++ { 0x370c, 0x30 }, ++ { 0x3710, 0x24 }, ++ { 0x3711, 0x0c }, ++ { 0x3716, 0x00 }, ++ { 0x3720, 0x28 }, ++ { 0x3729, 0x7b }, ++ { 0x372a, 0x84 }, ++ { 0x372b, 0xbd }, ++ { 0x372c, 0xbc }, ++ { 0x372e, 0x52 }, ++ { 0x373c, 0x0e }, ++ { 0x373e, 0x33 }, ++ { 0x3743, 0x10 }, ++ { 0x3744, 0x88 }, ++ { 0x3745, 0xc0 }, ++ { 0x374a, 0x43 }, ++ { 0x374c, 0x00 }, ++ { 0x374e, 0x23 }, ++ { 0x3751, 0x7b }, ++ { 0x3752, 0x84 }, ++ { 0x3753, 0xbd }, ++ { 0x3754, 0xbc }, ++ { 0x3756, 0x52 }, ++ { 0x375c, 0x00 }, ++ { 0x3760, 0x00 }, ++ { 0x3761, 0x00 }, ++ { 0x3762, 0x00 }, ++ { 0x3763, 0x00 }, ++ { 0x3764, 0x00 }, ++ { 0x3767, 0x04 }, ++ { 0x3768, 0x04 }, ++ { 0x3769, 0x08 }, ++ { 0x376a, 0x08 }, ++ { 0x376b, 0x20 }, ++ { 0x376c, 0x00 }, ++ { 0x376d, 0x00 }, ++ { 0x376e, 0x00 }, ++ { 0x3773, 0x00 }, ++ { 0x3774, 0x51 }, ++ { 0x3776, 0xbd }, ++ { 0x3777, 0xbd }, ++ { 0x3781, 0x18 }, ++ { 0x3783, 0x25 }, ++ { 0x3798, 0x1b }, ++ { 0x3800, 0x01 }, ++ { 0x3801, 0x88 }, ++ { 0x3802, 0x00 }, ++ { 0x3803, 0xe0 }, ++ { 0x3804, 0x09 }, ++ { 0x3805, 0x17 }, ++ { 0x3806, 0x05 }, ++ { 0x3807, 0x1f }, ++ { 0x3808, 0x07 }, ++ { 0x3809, 0x80 }, ++ { 0x380a, 0x04 }, ++ { 0x380b, 0x38 }, ++ { 0x380c, 0x06 }, ++ { 0x380d, 0xb8 }, ++ { 0x380e, 0x09 }, ++ { 0x380f, 0x14 }, ++ { 0x3810, 0x00 }, ++ { 0x3811, 0x08 }, ++ { 0x3812, 0x00 }, ++ { 0x3813, 0x04 }, ++ { 0x3814, 0x01 }, ++ { 0x3815, 0x01 }, ++ { 0x3819, 0x01 }, ++ { 0x3820, 0x00 }, ++ { 0x3821, 0x06 }, ++ { 0x3829, 0x00 }, ++ { 0x382a, 0x01 }, ++ { 0x382b, 0x01 }, ++ { 0x382d, 0x7f }, ++ { 0x3830, 0x04 }, ++ { 0x3836, 0x01 }, ++ { 0x3837, 0x00 }, ++ { 0x3841, 0x02 }, ++ { 0x3846, 0x08 }, ++ { 0x3847, 0x07 }, ++ { 0x3d85, 0x36 }, ++ { 0x3d8c, 0x71 }, ++ { 0x3d8d, 0xcb }, ++ { 0x3f0a, 0x00 }, ++ { 0x4000, 0xf1 }, ++ { 0x4001, 0x40 }, ++ { 0x4002, 0x04 }, ++ { 0x4003, 0x14 }, ++ { 0x400e, 0x00 }, ++ { 0x4011, 0x00 }, ++ { 0x401a, 0x00 }, ++ { 0x401b, 0x00 }, ++ { 0x401c, 0x00 }, ++ { 0x401d, 0x00 }, ++ { 0x401f, 0x00 }, ++ { 0x4020, 0x00 }, ++ { 0x4021, 0x10 }, ++ { 0x4022, 0x06 }, ++ { 0x4023, 0x13 }, ++ { 0x4024, 0x07 }, ++ { 0x4025, 0x40 }, ++ { 0x4026, 0x07 }, ++ { 0x4027, 0x50 }, ++ { 0x4028, 0x00 }, ++ { 0x4029, 0x02 }, ++ { 0x402a, 0x06 }, ++ { 0x402b, 0x04 }, ++ { 0x402c, 0x02 }, ++ { 0x402d, 0x02 }, ++ { 0x402e, 0x0e }, ++ { 0x402f, 0x04 }, ++ { 0x4302, 0xff }, ++ { 0x4303, 0xff }, ++ { 0x4304, 0x00 }, ++ { 0x4305, 0x00 }, ++ { 0x4306, 0x00 }, ++ { 0x4308, 0x02 }, ++ { 0x4500, 0x6c }, ++ { 0x4501, 0xc4 }, ++ { 0x4502, 0x40 }, ++ { 0x4503, 0x01 }, ++ { 0x4601, 0x77 }, ++ { 0x4800, 0x04 }, ++ { 0x4813, 0x08 }, ++ { 0x481f, 0x40 }, ++ { 0x4829, 0x78 }, ++ { 0x4837, 0x10 }, ++ { 0x4b00, 0x2a }, ++ { 0x4b0d, 0x00 }, ++ { 0x4d00, 0x04 }, ++ { 0x4d01, 0x42 }, ++ { 0x4d02, 0xd1 }, ++ { 0x4d03, 0x93 }, ++ { 0x4d04, 0xf5 }, ++ { 0x4d05, 0xc1 }, ++ { 0x5000, 0xf3 }, ++ { 0x5001, 0x11 }, ++ { 0x5004, 0x00 }, ++ { 0x500a, 0x00 }, ++ { 0x500b, 0x00 }, ++ { 0x5032, 0x00 }, ++ { 0x5040, 0x00 }, ++ { 0x5050, 0x0c }, ++ { 0x5500, 0x00 }, ++ { 0x5501, 0x10 }, ++ { 0x5502, 0x01 }, ++ { 0x5503, 0x0f }, ++ { 0x8000, 0x00 }, ++ { 0x8001, 0x00 }, ++ { 0x8002, 0x00 }, ++ { 0x8003, 0x00 }, ++ { 0x8004, 0x00 }, ++ { 0x8005, 0x00 }, ++ { 0x8006, 0x00 }, ++ { 0x8007, 0x00 }, ++ { 0x8008, 0x00 }, ++ { 0x3638, 0x00 }, ++#endif ++ {0x0100, 0x00}, ++// {0x5040, 0x80}, ++ {OV4689_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov4689_init_regs_2048_1520_30fps_mipi[] = { ++#if 0 ++ /* @@ 0 35 RES_2048x1520_23.37fps_408Mbps 2Lane */ ++ /* ;SCLK = 80MHz MIPI CLK = 408Mbps/lane Mipi PCLK = 51MHz */ ++ /* ;HTS = 2200 VTS = 1556 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x22}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x02}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++ {0x3018, 0x32}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x48}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x09}, ++ {0x3805, 0x57}, ++ {0x3806, 0x05}, ++ {0x3807, 0xFB}, ++ {0x3808, 0x08}, ++ {0x3809, 0x00}, ++ {0x380A, 0x05}, ++ {0x380B, 0xF0}, ++ {0x380C, 0x08}, ++ {0x380D, 0x98}, ++ {0x380E, 0x06}, ++ {0x380F, 0x14}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x93}, ++ {0x4024, 0x07}, ++ {0x4025, 0xC0}, ++ {0x4026, 0x07}, ++ {0x4027, 0xD0}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x7f}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x14}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++ {0x0100, 0x00}, ++#endif ++ ++#if 1 ++ /* @@ 0 35 RES_2048x1520_30fps_600Mbps 2Lane */ ++ /* ;SCLK = 120 MHz MIPI CLK = 600Mbps/lane Mipi PCLK = 75MHz */ ++ /* ;HTS = 2570 VTS = 1556 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x19}, ++ {0x0303, 0x00}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x01}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++ {0x3018, 0x32}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x48}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x09}, ++ {0x3805, 0x57}, ++ {0x3806, 0x05}, ++ {0x3807, 0xFB}, ++ {0x3808, 0x08}, ++ {0x3809, 0x00}, ++ {0x380A, 0x05}, ++ {0x380B, 0xF0}, ++ {0x380C, 0x0a}, ++ {0x380D, 0x0a}, ++ {0x380E, 0x06}, ++ {0x380F, 0x14}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x93}, ++ {0x4024, 0x07}, ++ {0x4025, 0xC0}, ++ {0x4026, 0x07}, ++ {0x4027, 0xD0}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x7f}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x2d}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++ {0x0100, 0x00}, ++#endif ++ ++#if 0 ++ /* @@ 0 35 RES_2048x1520_25fps_420Mbps 2Lane */ ++ /* ;SCLK = 82.7MHz MIPI CLK = 420Mbps/lane Mipi PCLK = 52.5MHz */ ++ /* ;HTS = 2125 VTS = 1556 */ ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x23}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x030b, 0x00}, ++ {0x030d, 0x1f}, ++ {0x030e, 0x04}, ++ {0x030f, 0x02}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++#ifdef DRIVE_CAPABILITY_1 ++ {0x3011,0x00}, ++#elif defined(DRIVE_CAPABILITY_2) ++ {0x3011,0x20}, ++#elif defined(DRIVE_CAPABILITY_3) ++ {0x3011,0x40}, ++#elif defined(DRIVE_CAPABILITY_4) ++ {0x3011,0x60}, ++#endif ++ {0x3018, 0x32}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3037, 0x01}, ++// {0x303f, 0x0d}, ++// {0x3012, 0x22}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x4c}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x01}, ++ {0x3801, 0x48}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x09}, ++ {0x3805, 0x57}, ++ {0x3806, 0x05}, ++ {0x3807, 0xFB}, ++ {0x3808, 0x08}, ++ {0x3809, 0x00}, ++ {0x380A, 0x05}, ++ {0x380B, 0xF0}, ++ {0x380C, 0x08}, ++ {0x380D, 0x4d}, ++ {0x380E, 0x06}, ++ {0x380F, 0x14}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x06}, ++ {0x4023, 0x93}, ++ {0x4024, 0x07}, ++ {0x4025, 0xC0}, ++ {0x4026, 0x07}, ++ {0x4027, 0xD0}, ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0x7f}, ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x14}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++ //{0x5040, 0x80},//color bar ++ {0x0100, 0x00}, ++#endif ++ {OV4689_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov4689_init_regs_2592_1520_30fps_mipi[] = { ++ {0x0103, 0x01}, ++ {0x3638, 0x00}, ++ {0x0300, 0x00}, ++ {0x0302, 0x19}, //0x19 ++ {0x0303, 0x00}, ++ {0x0304, 0x03}, //0x03 ++ {0x030b, 0x00}, ++ {0x030d, 0x1e}, ++ {0x030e, 0x04}, ++ {0x030f, 0x01}, ++ {0x0311, 0x00}, ++ {0x0312, 0x01}, ++ {0x031e, 0x00}, ++ {0x3000, 0x20}, ++ {0x3002, 0x00}, ++ {0x3018, 0x32}, ++ {0x3019, 0x0c}, ++ {0x3020, 0x93}, ++ {0x3021, 0x03}, ++ {0x3022, 0x01}, ++ {0x3031, 0x0a}, ++ {0x303f, 0x0c}, ++ {0x3305, 0xf1}, ++ {0x3307, 0x04}, ++ {0x3309, 0x29}, ++ {0x3500, 0x00}, ++ {0x3501, 0x60}, ++ {0x3502, 0x00}, ++ {0x3503, 0x04}, ++ {0x3504, 0x00}, ++ {0x3505, 0x00}, ++ {0x3506, 0x00}, ++ {0x3507, 0x00}, ++ {0x3508, 0x00}, ++ {0x3509, 0x80}, ++ {0x350a, 0x00}, ++ {0x350b, 0x00}, ++ {0x350c, 0x00}, ++ {0x350d, 0x00}, ++ {0x350e, 0x00}, ++ {0x350f, 0x80}, ++ {0x3510, 0x00}, ++ {0x3511, 0x00}, ++ {0x3512, 0x00}, ++ {0x3513, 0x00}, ++ {0x3514, 0x00}, ++ {0x3515, 0x80}, ++ {0x3516, 0x00}, ++ {0x3517, 0x00}, ++ {0x3518, 0x00}, ++ {0x3519, 0x00}, ++ {0x351a, 0x00}, ++ {0x351b, 0x80}, ++ {0x351c, 0x00}, ++ {0x351d, 0x00}, ++ {0x351e, 0x00}, ++ {0x351f, 0x00}, ++ {0x3520, 0x00}, ++ {0x3521, 0x80}, ++ {0x3522, 0x08}, ++ {0x3524, 0x08}, ++ {0x3526, 0x08}, ++ {0x3528, 0x08}, ++ {0x352a, 0x08}, ++ {0x3602, 0x00}, ++ {0x3603, 0x40}, ++ {0x3604, 0x02}, ++ {0x3605, 0x00}, ++ {0x3606, 0x00}, ++ {0x3607, 0x00}, ++ {0x3609, 0x12}, ++ {0x360a, 0x40}, ++ {0x360c, 0x08}, ++ {0x360f, 0xe5}, ++ {0x3608, 0x8f}, ++ {0x3611, 0x00}, ++ {0x3613, 0xf7}, ++ {0x3616, 0x58}, ++ {0x3619, 0x99}, ++ {0x361b, 0x60}, ++ {0x361c, 0x7a}, ++ {0x361e, 0x79}, ++ {0x361f, 0x02}, ++ {0x3632, 0x00}, ++ {0x3633, 0x10}, ++ {0x3634, 0x10}, ++ {0x3635, 0x10}, ++ {0x3636, 0x15}, ++ {0x3646, 0x86}, ++ {0x364a, 0x0b}, ++ {0x3700, 0x17}, ++ {0x3701, 0x22}, ++ {0x3703, 0x10}, ++ {0x370a, 0x37}, ++ {0x3705, 0x00}, ++ {0x3706, 0x63}, ++ {0x3709, 0x3c}, ++ {0x370b, 0x01}, ++ {0x370c, 0x30}, ++ {0x3710, 0x24}, ++ {0x3711, 0x0c}, ++ {0x3716, 0x00}, ++ {0x3720, 0x28}, ++ {0x3729, 0x7b}, ++ {0x372a, 0x84}, ++ {0x372b, 0xbd}, ++ {0x372c, 0xbc}, ++ {0x372e, 0x52}, ++ {0x373c, 0x0e}, ++ {0x373e, 0x33}, ++ {0x3743, 0x10}, ++ {0x3744, 0x88}, ++ {0x3745, 0xc0}, ++ {0x374a, 0x43}, ++ {0x374c, 0x00}, ++ {0x374e, 0x23}, ++ {0x3751, 0x7b}, ++ {0x3752, 0x84}, ++ {0x3753, 0xbd}, ++ {0x3754, 0xbc}, ++ {0x3756, 0x52}, ++ {0x375c, 0x00}, ++ {0x3760, 0x00}, ++ {0x3761, 0x00}, ++ {0x3762, 0x00}, ++ {0x3763, 0x00}, ++ {0x3764, 0x00}, ++ {0x3767, 0x04}, ++ {0x3768, 0x04}, ++ {0x3769, 0x08}, ++ {0x376a, 0x08}, ++ {0x376b, 0x20}, ++ {0x376c, 0x00}, ++ {0x376d, 0x00}, ++ {0x376e, 0x00}, ++ {0x3773, 0x00}, ++ {0x3774, 0x51}, ++ {0x3776, 0xbd}, ++ {0x3777, 0xbd}, ++ {0x3781, 0x18}, ++ {0x3783, 0x25}, ++ {0x3798, 0x1b}, ++ {0x3800, 0x00}, ++ {0x3801, 0x38}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x0a}, ++ {0x3805, 0x67}, ++ {0x3806, 0x05}, ++ {0x3807, 0xfb}, ++ {0x3808, 0x0a}, ++ {0x3809, 0x20}, ++ {0x380a, 0x05}, ++ {0x380b, 0xf0}, ++ {0x380c, 0x0A}, ++ {0x380d, 0x82},//0x18 ++ {0x380e, 0x06}, ++ {0x380f, 0xfb}, ++ {0x3810, 0x00}, ++ {0x3811, 0x08}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x01}, ++ {0x3815, 0x01}, ++ {0x3819, 0x01}, ++ {0x3820, 0x00}, ++ {0x3821, 0x06}, ++ {0x3829, 0x00}, ++ {0x382a, 0x01}, ++ {0x382b, 0x01}, ++ {0x382d, 0x7f}, ++ {0x3830, 0x04}, ++ {0x3836, 0x01}, ++ {0x3837, 0x00}, ++ {0x3841, 0x02}, ++ {0x3846, 0x08}, ++ {0x3847, 0x07}, ++ {0x3d85, 0x36}, ++ {0x3d8c, 0x71}, ++ {0x3d8d, 0xcb}, ++ {0x3f0a, 0x00}, ++ {0x4000, 0xf1}, ++ {0x4001, 0x40}, ++ {0x4002, 0x04}, ++ {0x4003, 0x14}, ++ {0x400e, 0x00}, ++ {0x4011, 0x00}, ++ {0x401a, 0x00}, ++ {0x401b, 0x00}, ++ {0x401c, 0x00}, ++ {0x401d, 0x00}, ++ {0x401f, 0x00}, ++ {0x4020, 0x00}, ++ {0x4021, 0x10}, ++ {0x4022, 0x08}, ++ {0x4023, 0xb3}, ++ {0x4024, 0x09}, ++ {0x4025, 0xe0}, ++ {0x4026, 0x09}, ++ {0x4027, 0xf0},// ++ {0x4028, 0x00}, ++ {0x4029, 0x02}, ++ {0x402a, 0x06}, ++ {0x402b, 0x04}, ++ {0x402c, 0x02}, ++ {0x402d, 0x02}, ++ {0x402e, 0x0e}, ++ {0x402f, 0x04}, ++ {0x4302, 0xff}, ++ {0x4303, 0xff}, ++ {0x4304, 0x00}, ++ {0x4305, 0x00}, ++ {0x4306, 0x00}, ++ {0x4308, 0x02}, ++ {0x4500, 0x6c}, ++ {0x4501, 0xc4}, ++ {0x4502, 0x40}, ++ {0x4503, 0x01}, ++ {0x4601, 0xA1},// ++ {0x4800, 0x04}, ++ {0x4813, 0x08}, ++ {0x481f, 0x40}, ++ {0x4829, 0x78}, ++ {0x4837, 0x10}, ++ {0x4b00, 0x2a}, ++ {0x4b0d, 0x00}, ++ {0x4d00, 0x04}, ++ {0x4d01, 0x42}, ++ {0x4d02, 0xd1}, ++ {0x4d03, 0x93}, ++ {0x4d04, 0xf5}, ++ {0x4d05, 0xc1}, ++ {0x5000, 0xf3}, ++ {0x5001, 0x11}, ++ {0x5004, 0x00}, ++ {0x500a, 0x00}, ++ {0x500b, 0x00}, ++ {0x5032, 0x00}, ++ {0x5040, 0x00}, ++ {0x5050, 0x0c}, ++ {0x5500, 0x00}, ++ {0x5501, 0x10}, ++ {0x5502, 0x01}, ++ {0x5503, 0x0f}, ++ {0x8000, 0x00}, ++ {0x8001, 0x00}, ++ {0x8002, 0x00}, ++ {0x8003, 0x00}, ++ {0x8004, 0x00}, ++ {0x8005, 0x00}, ++ {0x8006, 0x00}, ++ {0x8007, 0x00}, ++ {0x8008, 0x00}, ++ {0x3638, 0x00}, ++ {0x0100, 0x00}, ++ {OV4689_REG_END, 0x00},/* END MARKER */ ++}; ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list ov4689_stream_on_mipi[] = { ++ {0x0100, 0x01}, ++ {OV4689_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov4689_stream_off_mipi[] = { ++ {0x0100, 0x00}, ++ {OV4689_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int ov4689_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct ov4689_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct ov4689_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != OV4689_REG_END) { ++ if (vals->reg_num == OV4689_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov4689_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int ov4689_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != OV4689_REG_END) { ++ if (vals->reg_num == OV4689_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov4689_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ov4689_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov4689_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int ov4689_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov4689_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int ov4689_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov4689_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov4689_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int ov4689_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ret = ov4689_read(sd, 0x300a, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV4689_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = ov4689_read(sd, 0x300b, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV4689_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++ ++static struct ov4689_win_size ov4689_win_sizes[] = { ++ { ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 30 << 16 | 1, ++ ++ .width = 1920, ++ .height = 1080, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++#ifdef CONFIG_OV4689_1080P_120FPS ++ .regs = ov4689_init_regs_1920_1080_120fps_mipi, ++#else ++ .regs = ov4689_init_regs_1920_1080_30fps_mipi, ++#endif ++ }, ++ { ++ .sensor_info.mipi_cfg.twidth = 2048, ++ .sensor_info.mipi_cfg.theight = 1520, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 25 << 16 | 1, ++ ++ .width = 2048, ++ .height = 1520, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov4689_init_regs_2048_1520_30fps_mipi, ++ }, ++ { ++ .sensor_info.mipi_cfg.twidth = 2592, ++ .sensor_info.mipi_cfg.theight = 1520, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 25 << 16 | 1, ++ ++ .width = 2592, ++ .height = 1520, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov4689_init_regs_2592_1520_30fps_mipi, ++ } ++}; ++ ++static int ov4689_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_OV4689_FMTS) ++ return -EINVAL; ++ ++ code->code = ov4689_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int ov4689_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov4689_format_struct *ovfmt; ++ struct ov4689_win_size *wsize; ++ struct ov4689_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ov4689_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov4689_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ov4689_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ov4689_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ov4689_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov4689_again_lut); i++) { ++ lut = &ov4689_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov4689_again_lut); i++) { ++ lut = &ov4689_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ov4689_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ struct ov4689_info *info = to_state(sd); ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret += ov4689_read(sd, 0x3509, &v); ++ ++ reg_val |= v; ++ ret += ov4689_read(sd, 0x3508, &v); ++ reg_val |= v << 8; ++ ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ov4689_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct ov4689_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ int i; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += ov4689_write(sd, 0x3509, (unsigned char)(reg_value & 0xff)); ++ ret += ov4689_write(sd, 0x3508, (unsigned char)((reg_value>>8) & 0xff)); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ov4689_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov4689_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct ov4689_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret += ov4689_write(sd, 0x3502, ((unsigned char)(value & 0xf)) << 4); ++ ret += ov4689_write(sd, 0x3501, (unsigned char)((value >> 4) & 0xff)); ++ ret += ov4689_write(sd, 0x3500, (unsigned char)((value >> 12) & 0xf)); ++ ++ return ret; ++} ++ ++static int ov4689_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov4689_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ov4689_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov4689_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ov4689_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov4689_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ov4689_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ov4689_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ov4689_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ov4689_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ov4689_s_gain turns off auto gain */ ++ return ov4689_s_gain(sd, info->gain->val); ++ } ++ return ov4689_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ov4689_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov4689_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ov4689_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ov4689_ctrl_ops = { ++ .s_ctrl = ov4689_s_ctrl, ++ .g_volatile_ctrl = ov4689_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov4689_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ov4689_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ov4689_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ov4689_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++static int ov4689_power(struct v4l2_subdev *sd, int on) ++{ ++ struct ov4689_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ info->supply.avdd = devm_regulator_get_optional(&client->dev, "avdd"); ++ info->supply.dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); ++ info->supply.dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); ++ ++ if (IS_ERR(info->supply.avdd)||IS_ERR(info->supply.dvdd) ++ ||IS_ERR(info->supply.dovdd)) { ++ if ((PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.avdd) == -EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ printk("No ov4689 vdd regulator found\n"); ++ } ++ ++ if ((!IS_ERR(info->supply.avdd))&&(!IS_ERR(info->supply.avdd)) ++ &&(!IS_ERR(info->supply.avdd))) { ++ if(on){ ++ ret = regulator_enable(info->supply.avdd); ++ ret = regulator_enable(info->supply.dvdd); ++ ret = regulator_enable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "ov4689 vdd supply disable failed\n"); ++ } ++ else{ ++ ret = regulator_disable(info->supply.avdd); ++ ret = regulator_disable(info->supply.dvdd); ++ ret = regulator_disable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "ov4689 vdd supply disable failed\n"); ++ } ++ }else{ ++ dev_err(&client->dev, "ov4689 vdd supply IS_ERR failed\n"); ++ } ++ return ret; ++} ++ ++ ++int ov4689_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ov4689_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ret = ov4689_write_array(sd, ov4689_stream_on_mipi); ++ pr_debug("ov4689 stream on\n"); ++ ++ } ++ else { ++ ret = ov4689_write_array(sd, ov4689_stream_off_mipi); ++ pr_debug("ov4689 stream off\n"); ++ } ++ return ret; ++} ++int ov4689_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct ov4689_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ov4689_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov4689_g_register, ++ .s_register = ov4689_s_register, ++#endif ++}; ++ ++static const struct v4l2_subdev_video_ops ov4689_video_ops = { ++ .s_stream = ov4689_s_stream, ++ .g_frame_interval = ov4689_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov4689_pad_ops = { ++ //.enum_frame_interval = ov4689_enum_frame_interval, ++ //.num_frame_size = ov4689_enum_frame_size, ++ //.enum_mbus_code = ov4689_enum_mbus_code, ++ .set_fmt = ov4689_set_fmt, ++ .get_fmt = ov4689_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops ov4689_ops = { ++ .core = &ov4689_core_ops, ++ .video = &ov4689_video_ops, ++ .pad = &ov4689_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int ov4689_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct ov4689_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &ov4689_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ov4689_power(sd,1); ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ ov4689_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ov4689 */ ++ ret = ov4689_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ov4689 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ /*IRCUT ctl 0:off 1:on*/ ++ ov4689_ircut(sd, 0); ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 261773, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov4689_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++#ifdef CONFIG_OV4689_2048X1520_30FPS ++ info->win = &ov4689_win_sizes[1]; ++#else ++ info->win = &ov4689_win_sizes[0]; ++#endif ++ ++ ov4689_init(sd, 1); ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ov4689 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ov4689_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov4689_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id ov4689_id[] = { ++ { "ov4689", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov4689_id); ++ ++static const struct of_device_id ov4689_of_match[] = { ++ {.compatible = "ovti,ov4689", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++static int ov4689_suspend(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov4689_info *info = to_state(sd); ++ int ret=0; ++ ++ ov4689_power(sd,0); ++ v4l2_clk_disable(info->clk); ++ return 0; ++} ++ ++static int ov4689_resume(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov4689_info *info = to_state(sd); ++ int ret=0; ++ ++ ov4689_power(sd,1); ++ v4l2_clk_enable(info->clk); ++ ov4689_reset(sd, 1); ++ ov4689_init(sd, 1); ++ return 0; ++} ++ ++const struct dev_pm_ops ov4689_pm = ++{ ++ .suspend = ov4689_suspend, ++ .resume = ov4689_resume, ++}; ++ ++ ++static struct i2c_driver ov4689_driver = { ++ .driver = { ++ .name = "ov4689", ++ .of_match_table = of_match_ptr(ov4689_of_match), ++ .pm = &ov4689_pm, ++ }, ++ .probe = ov4689_probe, ++ .remove = ov4689_remove, ++ .id_table = ov4689_id, ++}; ++ ++module_i2c_driver(ov4689_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision ov4689 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/ov6710.c b/module_drivers/drivers/media/i2c/ingenic-isp/ov6710.c +new file mode 100644 +index 000000000..ced0659fa +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/ov6710.c +@@ -0,0 +1,1549 @@ ++/* ++ * A V4L2 driver for OmniVision OV6710 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define OV6710_CHIP_ID_H (0x67) ++#define OV6710_CHIP_ID_L (0x10) ++#define OV6710_REG_END 0xffff ++#define OV6710_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ov6710_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ov6710_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov6710_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ov6710_win_size *win; ++ ++ struct ov6710_gpio reset; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut ov6710_again_lut[] = { ++ ++ {0x0,0}, ++ {0x2,2909}, ++ {0x5,5731}, ++ {0x7,8472}, ++ {0x10,11136}, ++ {0x12,13726}, ++ {0x15,16248}, ++ {0x17,18704}, ++ {0x20,21097}, ++ {0x22,23432}, ++ {0x25,25710}, ++ {0x27,27935}, ++ {0x30,30109}, ++ {0x32,32234}, ++ {0x35,34312}, ++ {0x37,36345}, ++ {0x40,38336}, ++ {0x42,40285}, ++ {0x45,42195}, ++ {0x47,44068}, ++ {0x50,45904}, ++ {0x52,47704}, ++ {0x55,49472}, ++ {0x57,51207}, ++ {0x60,52910}, ++ {0x62,54584}, ++ {0x65,56228}, ++ {0x67,57844}, ++ {0x70,59433}, ++ {0x72,60996}, ++ {0x75,62534}, ++ {0x77,64047}, ++ {0x80,65536}, ++ {0x82,67001}, ++ {0x85,68445}, ++ {0x87,69867}, ++ {0x90,71267}, ++ {0x92,72648}, ++ {0x95,74008}, ++ {0x97,75349}, ++ {0xa0,76672}, ++ {0xa2,77976}, ++ {0xa5,79262}, ++ {0xa7,80531}, ++ {0xb0,81784}, ++ {0xb2,83020}, ++ {0xb5,84240}, ++ {0xb7,85444}, ++ {0xc0,86633}, ++ {0xc2,87808}, ++ {0xc5,88968}, ++ {0xc7,90114}, ++ {0xd0,91246}, ++ {0xd2,92365}, ++ {0xd5,93471}, ++ {0xd7,94564}, ++ {0xe0,95645}, ++ {0xe2,96713}, ++ {0xe5,97770}, ++ {0xe7,98814}, ++ {0xf0,99848}, ++ {0xf2,100870}, ++ {0xf5,101881}, ++ {0xf7,102882}, ++ {0x100,103872}, ++ {0x102,104851}, ++ {0x105,105821}, ++ {0x107,106781}, ++ {0x110,107731}, ++ {0x112,108672}, ++ {0x115,109604}, ++ {0x117,110526}, ++ {0x120,111440}, ++ {0x122,112344}, ++ {0x125,113240}, ++ {0x127,114128}, ++ {0x130,115008}, ++ {0x132,115879}, ++ {0x135,116743}, ++ {0x137,117598}, ++ {0x140,118446}, ++ {0x142,119287}, ++ {0x145,120120}, ++ {0x147,120946}, ++ {0x150,121764}, ++ {0x152,122576}, ++ {0x155,123380}, ++ {0x157,124178}, ++ {0x160,124969}, ++ {0x162,125754}, ++ {0x165,126532}, ++ {0x167,127304}, ++ {0x170,128070}, ++ {0x172,128829}, ++ {0x175,129583}, ++ {0x177,130330}, ++ {0x180,131072}, ++ {0x182,131807}, ++ {0x185,132537}, ++ {0x187,133262}, ++ {0x190,133981}, ++ {0x192,134694}, ++ {0x195,135403}, ++ {0x197,136106}, ++ {0x1a0,136803}, ++ {0x1a2,137496}, ++ {0x1a5,138184}, ++ {0x1a7,138866}, ++ {0x1b0,139544}, ++ {0x1b2,140217}, ++ {0x1b5,140885}, ++ {0x1b7,141549}, ++ {0x1c0,142208}, ++ {0x1c2,142862}, ++ {0x1c5,143512}, ++ {0x1c7,144157}, ++ {0x1d0,144798}, ++ {0x1d2,145435}, ++ {0x1d5,146067}, ++ {0x1d7,146696}, ++ {0x1e0,147320}, ++ {0x1e2,147940}, ++ {0x1e5,148556}, ++ {0x1e7,149168}, ++ {0x1f0,149776}, ++ {0x1f2,150380}, ++ {0x1f5,150980}, ++ {0x1f7,151577}, ++ {0x200,152169}, ++ {0x202,152758}, ++ {0x205,153344}, ++ {0x207,153926}, ++ {0x210,154504}, ++ {0x212,155079}, ++ {0x215,155650}, ++ {0x217,156218}, ++ {0x220,156782}, ++ {0x222,157344}, ++ {0x225,157901}, ++ {0x227,158456}, ++ {0x230,159007}, ++ {0x232,159555}, ++ {0x235,160100}, ++ {0x237,160642}, ++ {0x240,161181}, ++ {0x242,161716}, ++ {0x245,162249}, ++ {0x247,162779}, ++ {0x250,163306}, ++ {0x252,163829}, ++ {0x255,164350}, ++ {0x257,164868}, ++ {0x260,165384}, ++ {0x262,165896}, ++ {0x265,166406}, ++ {0x267,166913}, ++ {0x270,167417}, ++ {0x272,167919}, ++ {0x275,168418}, ++ {0x277,168914}, ++ {0x280,169408}, ++ {0x282,169899}, ++ {0x285,170387}, ++ {0x287,170873}, ++ {0x290,171357}, ++ {0x292,171838}, ++ {0x295,172317}, ++ {0x297,172793}, ++ {0x2a0,173267}, ++ {0x2a2,173739}, ++ {0x2a5,174208}, ++ {0x2a7,174675}, ++ {0x2b0,175140}, ++ {0x2b2,175602}, ++ {0x2b5,176062}, ++ {0x2b7,176520}, ++ {0x2c0,176976}, ++ {0x2c2,177429}, ++ {0x2c5,177880}, ++ {0x2c7,178329}, ++ {0x2d0,178776}, ++ {0x2d2,179221}, ++ {0x2d5,179664}, ++ {0x2d7,180105}, ++ {0x2e0,180544}, ++ {0x2e2,180981}, ++ {0x2e5,181415}, ++ {0x2e7,181848}, ++ {0x2f0,182279}, ++ {0x2f2,182707}, ++ {0x2f5,183134}, ++ {0x2f7,183559}, ++ {0x300,183982}, ++ {0x302,184403}, ++ {0x305,184823}, ++ {0x307,185240}, ++ {0x310,185656}, ++ {0x312,186070}, ++ {0x315,186482}, ++ {0x317,186892}, ++ {0x320,187300}, ++ {0x322,187707}, ++ {0x325,188112}, ++ {0x327,188515}, ++ {0x330,188916}, ++ {0x332,189316}, ++ {0x335,189714}, ++ {0x337,190111}, ++ {0x340,190505}, ++ {0x342,190899}, ++ {0x345,191290}, ++ {0x347,191680}, ++ {0x350,192068}, ++ {0x352,192455}, ++ {0x355,192840}, ++ {0x357,193224}, ++ {0x360,193606}, ++ {0x362,193986}, ++ {0x365,194365}, ++ {0x367,194743}, ++ {0x370,195119}, ++ {0x372,195493}, ++ {0x375,195866}, ++ {0x377,196237}, ++ {0x380,196608}, ++ {0x382,196976}, ++ {0x385,197343}, ++ {0x387,197709}, ++ {0x390,198073}, ++ {0x392,198436}, ++ {0x395,198798}, ++ {0x397,199158}, ++ {0x3a0,199517}, ++ {0x3a2,199874}, ++ {0x3a5,200230}, ++ {0x3a7,200585}, ++ {0x3b0,200939}, ++ {0x3b2,201291}, ++ {0x3b5,201642}, ++ {0x3b7,201991}, ++ {0x3c0,202339}, ++ {0x3c2,202686}, ++ {0x3c5,203032}, ++ {0x3c7,203377}, ++ {0x3d0,203720}, ++ {0x3d2,204062}, ++ {0x3d5,204402}, ++ {0x3d7,204742}, ++ {0x3e0,205080}, ++ {0x3e2,205417}, ++ {0x3e5,205753}, ++ {0x3e7,206088}, ++ {0x3f0,206421}, ++ {0x3f2,206754}, ++ {0x3f5,207085}, ++ {0x3f7,207415}, ++}; ++ ++static inline struct ov6710_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ov6710_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov6710_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list ov6710_init_regs_400_400_120fps_mipi[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x3005, 0x00}, ++ {0x3013, 0x12}, ++ {0x3014, 0x04}, ++ {0x3016, 0x10}, ++ {0x3017, 0x00}, ++ {0x3018, 0x00}, ++ {0x301a, 0x00}, ++ {0x301b, 0x00}, ++ {0x301c, 0x00}, ++ {0x3037, 0xf0}, ++ {0x3080, 0x01}, ++ {0x3081, 0x00}, ++ {0x3082, 0x01}, ++ {0x3098, 0x04}, ++ {0x3099, 0x28}, ++ {0x309a, 0x06}, ++ {0x309b, 0x04}, ++ {0x309c, 0x00}, ++ {0x309d, 0x00}, ++ {0x309e, 0x01}, ++ {0x309f, 0x00}, ++ {0x30b0, 0x0a}, ++ {0x30b1, 0x02}, ++ {0x30b2, 0x00}, ++ {0x30b3, 0x32}, ++ {0x30b4, 0x02}, ++ {0x30b5, 0x05}, ++ {0x3106, 0xd9}, ++ {0x3500, 0x00}, ++ {0x3501, 0x73}, ++ {0x3502, 0x20}, ++ {0x3503, 0x07}, ++ {0x3509, 0x10}, ++ {0x350a, 0x00}, ++ {0x350b, 0x10}, ++ {0x3600, 0xfc}, ++ {0x3620, 0xb7}, ++ {0x3621, 0x05}, ++ {0x3626, 0x31}, ++ {0x3627, 0x40}, ++ {0x3632, 0xa3}, ++ {0x3633, 0x34}, ++ {0x3634, 0x40}, ++ {0x3636, 0x00}, ++ {0x3660, 0x80}, ++ {0x3662, 0x01}, ++ {0x3664, 0xf0}, ++ {0x366a, 0x10}, ++ {0x366b, 0x06}, ++ {0x3680, 0xf4}, ++ {0x3681, 0x50}, ++ {0x3682, 0x00}, ++ {0x3708, 0x20}, ++ {0x3709, 0x40}, ++ {0x370d, 0x03}, ++ {0x373b, 0x02}, ++ {0x373c, 0x08}, ++ {0x3742, 0x00}, ++ {0x3744, 0x16}, ++ {0x3745, 0x08}, ++ {0x3781, 0xfc}, ++ {0x3788, 0x00}, ++ {0x3800, 0x00}, ++ {0x3801, 0x04}, ++ {0x3802, 0x00}, ++ {0x3803, 0x04}, ++ {0x3804, 0x01}, ++ {0x3805, 0x9b}, ++ {0x3806, 0x01}, ++ {0x3807, 0x9b}, ++ {0x3808, 0x01}, ++ {0x3809, 0x90}, ++ {0x380a, 0x01}, ++ {0x380b, 0x90}, ++ {0x380c, 0x05}, ++ {0x380d, 0xf2}, ++ {0x380e, 0x08}, ++ {0x380f, 0x36}, ++ {0x3810, 0x00}, ++ {0x3811, 0x04}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x11}, ++ {0x3815, 0x11}, ++ {0x3820, 0x00}, ++ {0x3821, 0x00}, ++ {0x382b, 0xfa}, ++ {0x382f, 0x04}, ++ {0x3832, 0x00}, ++ {0x3833, 0x05}, ++ {0x3834, 0x00}, ++ {0x3835, 0x05}, ++ {0x3882, 0x04}, ++ {0x3883, 0x00}, ++ {0x38a4, 0x10}, ++ {0x38a5, 0x00}, ++ {0x38b1, 0x03}, ++ {0x3b80, 0x00}, ++ {0x3b81, 0xa5}, ++ {0x3b82, 0x10}, ++ {0x3b83, 0x00}, ++ {0x3b84, 0x08}, ++ {0x3b85, 0x00}, ++ {0x3b86, 0x01}, ++ {0x3b87, 0x00}, ++ {0x3b88, 0x00}, ++ {0x3b89, 0x00}, ++ {0x3b8a, 0x00}, ++ {0x3b8b, 0x05}, ++ {0x3b8c, 0x00}, ++ {0x3b8d, 0x00}, ++ {0x3b8e, 0x00}, ++ {0x3b8f, 0x1a}, ++ {0x3b94, 0x05}, ++ {0x3b95, 0xf2}, ++ {0x3b96, 0xf0}, ++ {0x4004, 0x04}, ++ {0x404e, 0x01}, ++ {0x4801, 0x0f}, ++ {0x4806, 0x0f}, ++ {0x4837, 0x43}, ++ {0x5a01, 0x00}, ++ {0x5a03, 0x00}, ++ {0x5a04, 0x10}, ++ {0x5a05, 0xa0}, ++ {0x5a06, 0x0c}, ++ {0x5a07, 0x78}, ++ {0x5a08, 0x00}, ++// {0x0100, 0x01}, ++ {OV6710_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov6710_init_regs_200_200_120fps_mipi_bin[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x3005, 0x00}, ++ {0x3013, 0x12}, ++ {0x3014, 0x04}, ++ {0x3016, 0x10}, ++ {0x3017, 0x00}, ++ {0x3018, 0x00}, ++ {0x301a, 0x00}, ++ {0x301b, 0x00}, ++ {0x301c, 0x00}, ++ {0x3037, 0xf0}, ++ {0x3080, 0x01}, ++ {0x3081, 0x00}, ++ {0x3082, 0x01}, ++ {0x3098, 0x04}, ++ {0x3099, 0x14}, ++ {0x309a, 0x06}, ++ {0x309b, 0x02}, ++ {0x309c, 0x00}, ++ {0x309d, 0x00}, ++ {0x309e, 0x01}, ++ {0x309f, 0x00}, ++ {0x30b0, 0x0a}, ++ {0x30b1, 0x04}, ++ {0x30b2, 0x00}, ++ {0x30b3, 0x32}, ++ {0x30b4, 0x02}, ++ {0x30b5, 0x05}, ++ {0x3106, 0xd9}, ++ {0x3500, 0x00}, ++ {0x3501, 0x0e}, ++ {0x3502, 0x80}, ++ {0x3503, 0x07}, ++ {0x3509, 0x10}, ++ {0x350b, 0x10}, ++ {0x3620, 0xb7}, ++ {0x3621, 0x05}, ++ {0x3626, 0x31}, ++ {0x3627, 0x40}, ++ {0x3632, 0xa3}, ++ {0x3633, 0x34}, ++ {0x3634, 0x40}, ++ {0x3636, 0x00}, ++ {0x3660, 0x80}, ++ {0x3662, 0x01}, ++ {0x3664, 0xf0}, ++ {0x366a, 0x00}, ++ {0x366b, 0x50}, ++ {0x3680, 0xf4}, ++ {0x3681, 0x50}, ++ {0x3682, 0x00}, ++ {0x3708, 0x20}, ++ {0x3709, 0x40}, ++ {0x370d, 0x03}, ++ {0x373b, 0x02}, ++ {0x373c, 0xe8}, ++ {0x3742, 0x00}, ++ {0x3744, 0x16}, ++ {0x3745, 0x08}, ++ {0x3781, 0xfc}, ++ {0x3788, 0x00}, ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x00}, ++ {0x3804, 0x01}, ++ {0x3805, 0x9f}, ++ {0x3806, 0x01}, ++ {0x3807, 0x9f}, ++ {0x3808, 0x00}, ++ {0x3809, 0xc8}, ++ {0x380a, 0x00}, ++ {0x380b, 0xc8}, ++ {0x380c, 0x05}, ++ {0x380d, 0x78}, ++ {0x380e, 0x00}, ++ {0x380f, 0xee}, ++ {0x3810, 0x00}, ++ {0x3811, 0x04}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ {0x3820, 0x02}, ++ {0x3821, 0x01}, ++ {0x382b, 0xfa}, ++ {0x382f, 0x04}, ++ {0x3832, 0x00}, ++ {0x3833, 0x05}, ++ {0x3834, 0x00}, ++ {0x3835, 0x05}, ++ {0x3882, 0x04}, ++ {0x3883, 0x00}, ++ {0x38a4, 0x10}, ++ {0x38a5, 0x00}, ++ {0x38b1, 0x03}, ++ {0x3b80, 0x00}, ++ {0x3b81, 0xa5}, ++ {0x3b82, 0x10}, ++ {0x3b83, 0x00}, ++ {0x3b84, 0x08}, ++ {0x3b85, 0x00}, ++ {0x3b86, 0x01}, ++ {0x3b87, 0x00}, ++ {0x3b88, 0x00}, ++ {0x3b89, 0x00}, ++ {0x3b8a, 0x00}, ++ {0x3b8b, 0x05}, ++ {0x3b8c, 0x00}, ++ {0x3b8d, 0x00}, ++ {0x3b8e, 0x00}, ++ {0x3b8f, 0x1a}, ++ {0x3b94, 0x05}, ++ {0x3b95, 0xf2}, ++ {0x3b96, 0xf0}, ++ {0x4004, 0x02}, ++ {0x404e, 0x01}, ++ {0x4801, 0x0f}, ++ {0x4806, 0x0f}, ++ {0x4837, 0x85}, ++ {0x0100, 0x01}, ++ {OV6710_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov6710_init_regs_200_200_120fps_mipi_skip[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x3005, 0x00}, ++ {0x3013, 0x12}, ++ {0x3014, 0x04}, ++ {0x3016, 0x10}, ++ {0x3017, 0x00}, ++ {0x3018, 0x00}, ++ {0x301a, 0x00}, ++ {0x301b, 0x00}, ++ {0x301c, 0x00}, ++ {0x3037, 0xf0}, ++ {0x3080, 0x01}, ++ {0x3081, 0x00}, ++ {0x3082, 0x01}, ++ {0x3098, 0x04}, ++ {0x3099, 0x14}, ++ {0x309a, 0x06}, ++ {0x309b, 0x02}, ++ {0x309c, 0x00}, ++ {0x309d, 0x00}, ++ {0x309e, 0x01}, ++ {0x309f, 0x00}, ++ {0x30b0, 0x0a}, ++ {0x30b1, 0x04}, ++ {0x30b2, 0x00}, ++ {0x30b3, 0x32}, ++ {0x30b4, 0x02}, ++ {0x30b5, 0x05}, ++ {0x3106, 0xd9}, ++ {0x3500, 0x00}, ++ {0x3501, 0x0e}, ++ {0x3502, 0x80}, ++ {0x3503, 0x07}, ++ {0x3509, 0x10}, ++ {0x350b, 0x10}, ++ {0x3620, 0xb7}, ++ {0x3621, 0x05}, ++ {0x3626, 0x31}, ++ {0x3627, 0x40}, ++ {0x3632, 0xa3}, ++ {0x3633, 0x34}, ++ {0x3634, 0x40}, ++ {0x3636, 0x00}, ++ {0x3660, 0x80}, ++ {0x3662, 0x01}, ++ {0x3664, 0xf0}, ++ {0x366a, 0x00}, ++ {0x366b, 0x50}, ++ {0x3680, 0xf4}, ++ {0x3681, 0x50}, ++ {0x3682, 0x00}, ++ {0x3708, 0x20}, ++ {0x3709, 0x40}, ++ {0x370d, 0x03}, ++ {0x373b, 0x02}, ++ {0x373c, 0x08}, ++ {0x3742, 0xe0}, ++ {0x3744, 0x16}, ++ {0x3745, 0x08}, ++ {0x3781, 0xfc}, ++ {0x3788, 0x21}, ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x00}, ++ {0x3804, 0x01}, ++ {0x3805, 0x9f}, ++ {0x3806, 0x01}, ++ {0x3807, 0x9f}, ++ {0x3808, 0x00}, ++ {0x3809, 0xc8}, ++ {0x380a, 0x00}, ++ {0x380b, 0xc8}, ++ {0x380c, 0x05}, ++ {0x380d, 0x78}, ++ {0x380e, 0x00}, ++ {0x380f, 0xee}, ++ {0x3810, 0x00}, ++ {0x3811, 0x04}, ++ {0x3812, 0x00}, ++ {0x3813, 0x04}, ++ {0x3814, 0x31}, ++ {0x3815, 0x22}, ++ {0x3820, 0x00}, ++ {0x3821, 0x00}, ++ {0x382b, 0xfa}, ++ {0x382f, 0x04}, ++ {0x3832, 0x00}, ++ {0x3833, 0x05}, ++ {0x3834, 0x00}, ++ {0x3835, 0x05}, ++ {0x3882, 0x04}, ++ {0x3883, 0x00}, ++ {0x38a4, 0x10}, ++ {0x38a5, 0x00}, ++ {0x38b1, 0x03}, ++ {0x3b80, 0x00}, ++ {0x3b81, 0xa5}, ++ {0x3b82, 0x10}, ++ {0x3b83, 0x00}, ++ {0x3b84, 0x08}, ++ {0x3b85, 0x00}, ++ {0x3b86, 0x01}, ++ {0x3b87, 0x00}, ++ {0x3b88, 0x00}, ++ {0x3b89, 0x00}, ++ {0x3b8a, 0x00}, ++ {0x3b8b, 0x05}, ++ {0x3b8c, 0x00}, ++ {0x3b8d, 0x00}, ++ {0x3b8e, 0x00}, ++ {0x3b8f, 0x1a}, ++ {0x3b94, 0x05}, ++ {0x3b95, 0xf2}, ++ {0x3b96, 0xf0}, ++ {0x4004, 0x02}, ++ {0x404e, 0x01}, ++ {0x4801, 0x0f}, ++ {0x4806, 0x0f}, ++ {0x4837, 0x53}, ++ {0x0100, 0x01}, ++ {OV6710_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov6710_init_regs_100_100_120fps_mipi[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x3005, 0x00}, ++ {0x3013, 0x12}, ++ {0x3014, 0x04}, ++ {0x3016, 0x10}, ++ {0x3017, 0x00}, ++ {0x3018, 0x00}, ++ {0x301a, 0x00}, ++ {0x301b, 0x00}, ++ {0x301c, 0x00}, ++ {0x3037, 0xf0}, ++ {0x3080, 0x01}, ++ {0x3081, 0x00}, ++ {0x3082, 0x01}, ++ {0x3098, 0x04}, ++ {0x3099, 0x14}, ++ {0x309a, 0x08}, ++ {0x309b, 0x02}, ++ {0x309c, 0x00}, ++ {0x309d, 0x00}, ++ {0x309e, 0x01}, ++ {0x309f, 0x00}, ++ {0x30b0, 0x0a}, ++ {0x30b1, 0x06}, ++ {0x30b2, 0x00}, ++ {0x30b3, 0x32}, ++ {0x30b4, 0x02}, ++ {0x30b5, 0x05}, ++ {0x3106, 0xd9}, ++ {0x3500, 0x00}, ++ {0x3501, 0x07}, ++ {0x3502, 0x80}, ++ {0x3503, 0x07}, ++ {0x3509, 0x10}, ++ {0x350b, 0x10}, ++ {0x3620, 0xb7}, ++ {0x3621, 0x05}, ++ {0x3626, 0x31}, ++ {0x3627, 0x40}, ++ {0x3632, 0xa3}, ++ {0x3633, 0x34}, ++ {0x3634, 0x40}, ++ {0x3636, 0x00}, ++ {0x3660, 0x80}, ++ {0x3662, 0x01}, ++ {0x3664, 0xf0}, ++ {0x366a, 0x00}, ++ {0x366b, 0x50}, ++ {0x3680, 0xf4}, ++ {0x3681, 0x50}, ++ {0x3682, 0x00}, ++ {0x3708, 0x20}, ++ {0x3709, 0x40}, ++ {0x370d, 0x03}, ++ {0x373b, 0x02}, ++ {0x373c, 0x08}, ++ {0x3742, 0xe0}, ++ {0x3744, 0x16}, ++ {0x3745, 0x08}, ++ {0x3781, 0xfc}, ++ {0x3788, 0x61}, ++ {0x3800, 0x00}, ++ {0x3801, 0x00}, ++ {0x3802, 0x00}, ++ {0x3803, 0x00}, ++ {0x3804, 0x01}, ++ {0x3805, 0x9f}, ++ {0x3806, 0x01}, ++ {0x3807, 0x9f}, ++ {0x3808, 0x00}, ++ {0x3809, 0x64}, ++ {0x380a, 0x00}, ++ {0x380b, 0x64}, ++ {0x380c, 0x05}, ++ {0x380d, 0x00}, ++ {0x380e, 0x00}, ++ {0x380f, 0xc4}, ++ {0x3810, 0x00}, ++ {0x3811, 0x02}, ++ {0x3812, 0x00}, ++ {0x3813, 0x02}, ++ {0x3814, 0x71}, ++ {0x3815, 0x44}, ++ {0x3820, 0x00}, ++ {0x3821, 0x01}, ++ {0x382b, 0xfa}, ++ {0x382f, 0x04}, ++ {0x3832, 0x00}, ++ {0x3833, 0x05}, ++ {0x3834, 0x00}, ++ {0x3835, 0x05}, ++ {0x3882, 0x04}, ++ {0x3883, 0x00}, ++ {0x38a4, 0x10}, ++ {0x38a5, 0x00}, ++ {0x38b1, 0x03}, ++ {0x3b80, 0x00}, ++ {0x3b81, 0xa5}, ++ {0x3b82, 0x10}, ++ {0x3b83, 0x00}, ++ {0x3b84, 0x08}, ++ {0x3b85, 0x00}, ++ {0x3b86, 0x01}, ++ {0x3b87, 0x00}, ++ {0x3b88, 0x00}, ++ {0x3b89, 0x00}, ++ {0x3b8a, 0x00}, ++ {0x3b8b, 0x05}, ++ {0x3b8c, 0x00}, ++ {0x3b8d, 0x00}, ++ {0x3b8e, 0x00}, ++ {0x3b8f, 0x1a}, ++ {0x3b94, 0x05}, ++ {0x3b95, 0xf2}, ++ {0x3b96, 0xf0}, ++ {0x4004, 0x02}, ++ {0x404e, 0x01}, ++ {0x4801, 0x0f}, ++ {0x4806, 0x0f}, ++ {0x4837, 0xc8}, ++ {0x0100, 0x01}, ++ {OV6710_REG_END, 0x00},/* END MARKER */ ++}; ++ ++static struct regval_list ov6710_stream_on_mipi[] = { ++ {0x0100, 0x01}, ++ {OV6710_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov6710_stream_off_mipi[] = { ++ {0x0100, 0x00}, ++ {OV6710_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int ov6710_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct ov6710_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov6710_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct ov6710_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov6710_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != OV6710_REG_END) { ++ if (vals->reg_num == OV6710_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov6710_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int ov6710_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != OV6710_REG_END) { ++ if (vals->reg_num == OV6710_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov6710_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ov6710_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov6710_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++ ++static int ov6710_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov6710_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov6710_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int ov6710_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ret = ov6710_read(sd, 0x300a, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV6710_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = ov6710_read(sd, 0x300b, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != OV6710_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++ ++static struct ov6710_win_size ov6710_win_sizes[] = { ++ { ++ ++ .sensor_info.mipi_cfg.twidth = 400, ++ .sensor_info.mipi_cfg.theight = 400, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 120 << 16 | 1, ++ ++ ++ .width = 400, ++ .height = 400, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov6710_init_regs_400_400_120fps_mipi, ++ }, ++ { ++ .sensor_info.mipi_cfg.twidth = 200, ++ .sensor_info.mipi_cfg.theight = 200, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 120 << 16 | 1, ++ ++ .width = 200, ++ .height = 200, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov6710_init_regs_200_200_120fps_mipi_skip, ++ }, ++ { ++ .sensor_info.mipi_cfg.twidth = 100, ++ .sensor_info.mipi_cfg.theight = 100, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 120 << 16 | 1, ++ ++ .width = 100, ++ .height = 100, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov6710_init_regs_100_100_120fps_mipi, ++ }, ++}; ++ ++static int ov6710_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_OV6710_FMTS) ++ return -EINVAL; ++ ++ code->code = ov6710_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int ov6710_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov6710_format_struct *ovfmt; ++ struct ov6710_win_size *wsize; ++ struct ov6710_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ov6710_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov6710_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ov6710_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov6710_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov6710_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov6710_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ov6710_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ov6710_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov6710_again_lut); i++) { ++ lut = &ov6710_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov6710_again_lut); i++) { ++ lut = &ov6710_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ov6710_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ struct ov6710_info *info = to_state(sd); ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret += ov6710_read(sd, 0x350a, &v); ++ ++ reg_val |= v; ++ ret += ov6710_read(sd, 0x350b, &v); ++ reg_val |= v << 8; ++ ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ov6710_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct ov6710_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ int i; ++ ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += ov6710_write(sd, 0x350a, (unsigned char)((reg_value>>8) & 0x3)); ++ ret += ov6710_write(sd, 0x350b, (unsigned char)(reg_value & 0xff)); ++ ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ov6710_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov6710_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct ov6710_info *info = to_state(sd); ++ int ret = 0; ++ unsigned char v; ++ int frame_length = 0; ++ ++ ret = ov6710_read(sd, 0x380e, &v); ++ frame_length = v << 8; ++ ++ ret += ov6710_read(sd, 0x380f, &v); ++ frame_length |= v; ++ ++ if(value < frame_length){ ++ ret += ov6710_write(sd, 0x3502, ((unsigned char)(value & 0xf)) << 4); ++ ret += ov6710_write(sd, 0x3501, (unsigned char)((value >> 4) & 0xff)); ++ ret += ov6710_write(sd, 0x3500, (unsigned char)((value >> 12) & 0xf)); ++ } ++ return ret; ++} ++ ++static int ov6710_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov6710_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ov6710_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov6710_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ov6710_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov6710_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ov6710_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ov6710_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ov6710_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ov6710_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ov6710_s_gain turns off auto gain */ ++ return ov6710_s_gain(sd, info->gain->val); ++ } ++ return ov6710_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ov6710_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov6710_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ov6710_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ov6710_ctrl_ops = { ++ .s_ctrl = ov6710_s_ctrl, ++ .g_volatile_ctrl = ov6710_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov6710_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ov6710_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ov6710_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ov6710_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int ov6710_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ov6710_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ov6710_write_array(sd, info->win->regs); ++ ov6710_s_again(sd, 100000); ++ ret = ov6710_write_array(sd, ov6710_stream_on_mipi); ++ pr_debug("ov6710 stream on\n"); ++ ++ } ++ else { ++ ret = ov6710_write_array(sd, ov6710_stream_off_mipi); ++ pr_debug("ov6710 stream off\n"); ++ } ++ return ret; ++} ++ ++int ov6710_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct ov6710_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ov6710_core_ops = { ++ //.reset = ov6710_reset, ++ .init = ov6710_init, ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov6710_g_register, ++ .s_register = ov6710_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops ov6710_video_ops = { ++ .s_stream = ov6710_s_stream, ++ .g_frame_interval = ov6710_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov6710_pad_ops = { ++ //.enum_frame_interval = ov6710_enum_frame_interval, ++ //.num_frame_size = ov6710_enum_frame_size, ++ //.enum_mbus_code = ov6710_enum_mbus_code, ++ .set_fmt = ov6710_set_fmt, ++ .get_fmt = ov6710_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops ov6710_ops = { ++ .core = &ov6710_core_ops, ++ .video = &ov6710_video_ops, ++ .pad = &ov6710_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int ov6710_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct ov6710_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ unsigned int iovcc_1v8; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ iovcc_1v8 = of_property_read_bool(client->dev.of_node, "ingenic,iovcc_1v8"); ++ if(iovcc_1v8) { ++ /*X2000 spec*/ ++ *(volatile unsigned int *)0xb00000e0 |= (1<<30); ++ } ++ v4l2_i2c_subdev_init(sd, client, &ov6710_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ ov6710_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ov6710 */ ++ ret = ov6710_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ov6710 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ov6710_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ov6710_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ov6710_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ov6710_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ov6710_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ov6710_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 261773, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov6710_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &ov6710_win_sizes[0]; ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ov6710 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ov6710_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov6710_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id ov6710_id[] = { ++ { "ov6710", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov6710_id); ++ ++static const struct of_device_id ov6710_of_match[] = { ++ {.compatible = "ovti,ov6710", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++ ++static struct i2c_driver ov6710_driver = { ++ .driver = { ++ .name = "ov6710", ++ .of_match_table = of_match_ptr(ov6710_of_match), ++ }, ++ .probe = ov6710_probe, ++ .remove = ov6710_remove, ++ .id_table = ov6710_id, ++}; ++ ++module_i2c_driver(ov6710_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision ov6710 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/ov7251.c b/module_drivers/drivers/media/i2c/ingenic-isp/ov7251.c +new file mode 100644 +index 000000000..4318853c5 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/ov7251.c +@@ -0,0 +1,1396 @@ ++/* ++ * A V4L2 driver for OmniVision OV7251 cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define OV7251_CHIP_ID_H (0x77) ++#define OV7251_CHIP_ID_L (0x50) ++#define OV7251_REG_END 0xffff ++#define OV7251_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct ov7251_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct ov7251_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct ov7251_supply { ++ struct regulator *vdd2v8; /* Digital Core supply */ ++ struct regulator *vdd1v8; /* Digital I/O supply */ ++}; ++ ++struct ov7251_info { ++ struct ov7251_supply supply; ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct ov7251_win_size *win; ++ ++ struct ov7251_gpio reset; ++ struct ov7251_gpio ircutp; ++ struct ov7251_gpio ircutn; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut ov7251_again_lut[] = { ++ ++ {0x80, 0}, ++ {0x88, 5731}, ++ {0x90, 11136}, ++ {0x98, 16248}, ++ {0xa0, 21097}, ++ {0xa8, 25710}, ++ {0xb0, 30109}, ++ {0xb8, 34312}, ++ {0xc0, 38336}, ++ {0xc8, 42195}, ++ {0xd0, 45904}, ++ {0xd8, 49472}, ++ {0xe0, 52910}, ++ {0xe8, 56228}, ++ {0xf0, 59433}, ++ {0xf8, 62534}, ++ {0x178, 65536}, ++ {0x17c, 68445}, ++ {0x180, 71267}, ++ {0x184, 74008}, ++ {0x188, 76672}, ++ {0x18c, 79262}, ++ {0x190, 81784}, ++ {0x194, 84240}, ++ {0x198, 86633}, ++ {0x19c, 88968}, ++ {0x1a0, 91246}, ++ {0x1a4, 93471}, ++ {0x1a8, 95645}, ++ {0x1ac, 97770}, ++ {0x1b0, 99848}, ++ {0x1b4, 101881}, ++ {0x1b8, 103872}, ++ {0x1bc, 105821}, ++ {0x1c0, 107731}, ++ {0x1c4, 109604}, ++ {0x1c8, 111440}, ++ {0x1cc, 113241}, ++ {0x1d0, 115008}, ++ {0x1d4, 116743}, ++ {0x1d8, 118446}, ++ {0x1dc, 120120}, ++ {0x1e0, 121764}, ++ {0x1e4, 123380}, ++ {0x1e8, 124969}, ++ {0x1ec, 126532}, ++ {0x1f0, 128070}, ++ {0x1f4, 129583}, ++ {0x374, 131072}, ++ {0x376, 132537}, ++ {0x378, 133981}, ++ {0x37a, 135403}, ++ {0x37c, 136803}, ++ {0x37e, 138184}, ++ {0x380, 139544}, ++ {0x382, 140885}, ++ {0x384, 142208}, ++ {0x386, 143512}, ++ {0x388, 144798}, ++ {0x38a, 146067}, ++ {0x38c, 147320}, ++ {0x38e, 148556}, ++ {0x390, 149776}, ++ {0x392, 150980}, ++ {0x394, 152169}, ++ {0x396, 153344}, ++ {0x398, 154504}, ++ {0x39a, 155650}, ++ {0x39c, 156782}, ++ {0x39e, 157901}, ++ {0x3a0, 159007}, ++ {0x3a2, 160100}, ++ {0x3a4, 161181}, ++ {0x3a6, 162249}, ++ {0x3a8, 163306}, ++ {0x3aa, 164350}, ++ {0x3ac, 165384}, ++ {0x3ae, 166406}, ++ {0x3b0, 167417}, ++ {0x3b2, 168418}, ++ {0x3b4, 169408}, ++ {0x3b6, 170387}, ++ {0x3b8, 171357}, ++ {0x3ba, 172317}, ++ {0x3bc, 173267}, ++ {0x3be, 174208}, ++ {0x3c0, 175140}, ++ {0x3c2, 176062}, ++ {0x3c4, 176976}, ++ {0x3c6, 177880}, ++ {0x3c8, 178777}, ++ {0x3ca, 179664}, ++ {0x3cc, 180544}, ++ {0x3ce, 181415}, ++ {0x3d0, 182279}, ++ {0x3d2, 183134}, ++ {0x3d4, 183982}, ++ {0x3d6, 184823}, ++ {0x3d8, 185656}, ++ {0x3da, 186482}, ++ {0x3dc, 187300}, ++ {0x3de, 188112}, ++ {0x3e0, 188916}, ++ {0x3e2, 189714}, ++ {0x3e4, 190505}, ++ {0x3e6, 191290}, ++ {0x3e8, 192068}, ++ {0x3ea, 192840}, ++ {0x3ec, 193606}, ++ {0x3ee, 194365}, ++ {0x3f0, 195119}, ++ {0x3f2, 195866}, ++ {0x778, 196608}, ++ {0x779, 197343}, ++ {0x77a, 198073}, ++ {0x77b, 198798}, ++ {0x77c, 199517}, ++ {0x77d, 200230}, ++ {0x77e, 200939}, ++ {0x77f, 201642}, ++ {0x780, 202339}, ++ {0x781, 203032}, ++ {0x782, 203720}, ++ {0x783, 204402}, ++ {0x784, 205080}, ++ {0x785, 205753}, ++ {0x786, 206421}, ++ {0x787, 207085}, ++ {0x788, 207744}, ++ {0x789, 208398}, ++ {0x78a, 209048}, ++ {0x78b, 209693}, ++ {0x78c, 210334}, ++ {0x78d, 210971}, ++ {0x78e, 211603}, ++ {0x78f, 212232}, ++ {0x790, 212856}, ++ {0x791, 213476}, ++ {0x792, 214092}, ++ {0x793, 214704}, ++ {0x794, 215312}, ++ {0x795, 215916}, ++ {0x796, 216516}, ++ {0x797, 217113}, ++ {0x798, 217705}, ++ {0x799, 218294}, ++ {0x79a, 218880}, ++ {0x79b, 219462}, ++ {0x79c, 220040}, ++ {0x79d, 220615}, ++ {0x79e, 221186}, ++ {0x79f, 221754}, ++ {0x7a0, 222318}, ++ {0x7a1, 222880}, ++ {0x7a2, 223437}, ++ {0x7a3, 223992}, ++ {0x7a4, 224543}, ++ {0x7a5, 225091}, ++ {0x7a6, 225636}, ++ {0x7a7, 226178}, ++ {0x7a8, 226717}, ++ {0x7a9, 227253}, ++ {0x7aa, 227785}, ++ {0x7ab, 228315}, ++ {0x7ac, 228842}, ++ {0x7ad, 229365}, ++ {0x7ae, 229886}, ++ {0x7af, 230404}, ++ {0x7b0, 230920}, ++ {0x7b1, 231432}, ++ {0x7b2, 231942}, ++ {0x7b3, 232449}, ++ {0x7b4, 232953}, ++ {0x7b5, 233455}, ++ {0x7b6, 233954}, ++ {0x7b7, 234450}, ++ {0x7b8, 234944}, ++ {0x7b9, 235435}, ++ {0x7ba, 235923}, ++ {0x7bb, 236410}, ++ {0x7bc, 236893}, ++ {0x7bd, 237374}, ++ {0x7be, 237853}, ++ {0x7bf, 238329}, ++ {0x7c0, 238803}, ++ {0x7c1, 239275}, ++ {0x7c2, 239744}, ++ {0x7c3, 240211}, ++ {0x7c4, 240676}, ++ {0x7c5, 241138}, ++ {0x7c6, 241598}, ++ {0x7c7, 242056}, ++ {0x7c8, 242512}, ++ {0x7c9, 242965}, ++ {0x7ca, 243416}, ++ {0x7cb, 243865}, ++ {0x7cc, 244313}, ++ {0x7cd, 244757}, ++ {0x7ce, 245200}, ++ {0x7cf, 245641}, ++ {0x7d0, 246080}, ++ {0x7d1, 246517}, ++ {0x7d2, 246951}, ++ {0x7d3, 247384}, ++ {0x7d4, 247815}, ++ {0x7d5, 248243}, ++ {0x7d6, 248670}, ++ {0x7d7, 249095}, ++ {0x7d8, 249518}, ++ {0x7d9, 249939}, ++ {0x7da, 250359}, ++ {0x7db, 250776}, ++ {0x7dc, 251192}, ++ {0x7dd, 251606}, ++ {0x7de, 252018}, ++ {0x7df, 252428}, ++ {0x7e0, 252836}, ++ {0x7e1, 253243}, ++ {0x7e2, 253648}, ++ {0x7e3, 254051}, ++ {0x7e4, 254452}, ++ {0x7e5, 254852}, ++ {0x7e6, 255250}, ++ {0x7e7, 255647}, ++ {0x7e8, 256041}, ++ {0x7e9, 256435}, ++ {0x7ea, 256826}, ++ {0x7eb, 257216}, ++ {0x7ec, 257604}, ++ {0x7ed, 257991}, ++ {0x7ee, 258376}, ++ {0x7ef, 258760}, ++ {0x7f0, 259142}, ++ {0x7f1, 259522}, ++ {0x7f2, 259901}, ++ {0x7f3, 260279}, ++ {0x7f4, 260655}, ++ {0x7f5, 261029}, ++ {0x7f6, 261402}, ++ {0x7f7, 261773}, ++}; ++ ++static inline struct ov7251_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct ov7251_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov7251_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++ ++ ++static struct regval_list ov7251_init_regs_640_480_mipi[] = { ++ {0x3501, 0x00}, ++ {0x3502, 0x80}, ++ {0x3674, 0xef}, ++ {0x373c, 0x8e}, ++ {0x37a8, 0x01}, ++ {0x37a9, 0xc0}, ++ {0x3803, 0x04}, ++ {0x3807, 0xeb}, ++ {0x3808, 0x02}, ++ {0x3809, 0x80}, ++ {0x380a, 0x01}, ++ {0x380b, 0xe0}, ++ {0x380c, 0x05}, ++ {0x380d, 0x70}, ++ {0x380e, 0x02}, ++ {0x380f, 0x40}, ++ {0x3813, 0x05}, ++ {0x3814, 0x11}, ++ {0x3815, 0x11}, ++ {0x3820, 0x40}, ++ {0x3821, 0x00}, ++ {0x3c0c, 0x01}, ++ {0x3c0d, 0xd0}, ++ {0x3c0e, 0x02}, ++ {0x3c0f, 0x0a}, ++ {0x4001, 0x42}, ++ {0x4004, 0x04}, ++ {0x0100, 0x01}, ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov7251_init_regs_320_240_mipi[] = { ++ {0x3501, 0x00}, ++ {0x3502, 0x90}, ++ {0x3674, 0xef}, ++ {0x373c, 0xe8}, ++ {0x37a8, 0x02}, ++ {0x37a9, 0x14}, ++ {0x3803, 0x00}, ++ {0x3807, 0xef}, ++ {0x3808, 0x01}, ++ {0x3809, 0x40}, ++ {0x380a, 0x00}, ++ {0x380b, 0xf0}, ++ {0x380c, 0x05}, ++ {0x380d, 0x70}, ++ {0x380e, 0x02}, ++ {0x380f, 0x40}, ++ {0x3813, 0x05}, ++ {0x3814, 0x31}, ++ {0x3815, 0x31}, ++ {0x3820, 0x42}, ++ {0x3821, 0x01}, ++ {0x3c0e, 0x01}, ++ {0x3c0f, 0x30}, ++ {0x4001, 0x40}, ++ {0x4004, 0x02}, ++ {0x0100, 0x01}, ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov7251_init_regs_160_120_mipi[] = { ++ {0x3501, 0x02}, // ++ {0x3502, 0x80}, //expo ++// {0x3509, 0x18}, ++// {0x3504, 0x03}, ++// {0x3505, 0x00}, //mannual again ++ {0x3674, 0xff}, // ++ {0x373c, 0xe8}, // ++ {0x37a8, 0x02}, // ++ {0x37a9, 0x14}, // ++ {0x3803, 0x00}, // ++ {0x3807, 0xef}, // ++ {0x3808, 0x00}, //01 ++ {0x3809, 0xa0}, //40 ++ {0x380a, 0x00}, // ++ {0x380b, 0x78}, //f0 ++ {0x380c, 0x03}, // ++ {0x380d, 0xa0}, //HTS ++ {0x380e, 0x02}, // ++ {0x380f, 0x0a}, //VTS ++ {0x3811, 0x02}, ++ {0x3813, 0x03}, //05 ++ {0x3814, 0x44}, //31 ++ {0x3815, 0x44}, //31 ++ {0x3820, 0x42}, // ++ {0x3821, 0x01}, // ++ {0x3c0c, 0x01}, // ++ {0x3c0d, 0x82}, // ++ {0x3c0e, 0x01}, // ++ {0x3c0f, 0x30}, // ++ {0x4001, 0x40}, // ++ {0x4004, 0x02}, // ++ {0x0100, 0x01}, // ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov7251_common_init_regs_mipi[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x3005, 0x00}, ++ {0x3012, 0xc0}, ++ {0x3013, 0xd2}, ++ {0x3014, 0x04}, ++ {0x3016, 0x10}, ++ {0x3017, 0x00}, ++ {0x3018, 0x00}, ++ {0x301a, 0x00}, ++ {0x301b, 0x00}, ++ {0x301c, 0x00}, ++ {0x3023, 0x05}, ++ {0x3037, 0xf0}, ++ {0x3098, 0x04}, ++ {0x3099, 0x28}, ++ {0x309a, 0x05}, ++ {0x309b, 0x04}, ++ {0x30b0, 0x0a}, ++ {0x30b1, 0x01}, ++ {0x30b3, 0x64}, ++ {0x30b4, 0x03}, ++ {0x30b5, 0x05}, ++ {0x3106, 0xda}, ++ {0x3500, 0x00}, ++ {0x3503, 0x07}, ++ {0x3509, 0x10}, ++ {0x350b, 0x10}, ++ {0x3600, 0x1c}, ++ {0x3602, 0x62}, ++ {0x3620, 0xb7}, ++ {0x3622, 0x04}, ++ {0x3626, 0x21}, ++ {0x3627, 0x30}, ++ {0x3630, 0x44}, ++ {0x3631, 0x35}, ++ {0x3634, 0x60}, ++ {0x3636, 0x00}, ++ {0x3662, 0x01}, ++ {0x3663, 0x70}, ++ {0x3664, 0xf0}, ++ {0x3666, 0x0a}, ++ {0x3669, 0x1a}, ++ {0x366a, 0x00}, ++ {0x366b, 0x50}, ++ {0x3673, 0x01}, ++ {0x3675, 0x03}, ++ {0x3705, 0x41}, ++ {0x3709, 0x40}, ++ {0x3742, 0x00}, ++ {0x3757, 0xb3}, ++ {0x3788, 0x00}, ++ {0x3800, 0x00}, ++ {0x3801, 0x04}, ++ {0x3802, 0x00}, ++ {0x3804, 0x02}, ++ {0x3805, 0x8b}, ++ {0x3806, 0x01}, ++ {0x3810, 0x00}, ++ {0x3811, 0x04}, ++ {0x3812, 0x00}, ++ {0x382f, 0x0e}, ++ {0x3832, 0x00}, ++ {0x3833, 0x05}, ++ {0x3834, 0x00}, ++ {0x3835, 0x0c}, ++ {0x3837, 0x00}, ++ {0x3b80, 0x00}, ++ {0x3b81, 0xa5}, ++ {0x3b82, 0x10}, ++ {0x3b83, 0x00}, ++ {0x3b84, 0x08}, ++ {0x3b85, 0x00}, ++ {0x3b86, 0x01}, ++ {0x3b87, 0x00}, ++ {0x3b88, 0x00}, ++ {0x3b89, 0x00}, ++ {0x3b8a, 0x00}, ++ {0x3b8b, 0x05}, ++ {0x3b8c, 0x00}, ++ {0x3b8d, 0x00}, ++ {0x3b8e, 0x00}, ++ {0x3b8f, 0x1a}, ++ {0x3b94, 0x05}, ++ {0x3b95, 0xf2}, ++ {0x3b96, 0x40}, ++ {0x3c00, 0x89}, ++ {0x3c01, 0x63}, ++ {0x3c02, 0x01}, ++ {0x3c03, 0x00}, ++ {0x3c04, 0x00}, ++ {0x3c05, 0x03}, ++ {0x3c06, 0x00}, ++ {0x3c07, 0x06}, ++ {0x4005, 0x00}, ++ {0x404e, 0x01}, ++ {0x4300, 0xff}, ++ {0x4301, 0x00}, ++ {0x4501, 0x48}, ++ {0x4600, 0x00}, ++ {0x4601, 0x4e}, ++ {0x4801, 0x0f}, ++ {0x4806, 0x0f}, ++ {0x4819, 0xaa}, ++ {0x4823, 0x3e}, ++ {0x4837, 0x19}, ++ {0x4a0d, 0x00}, ++ {0x4a47, 0x7f}, ++ {0x4a49, 0xf0}, ++ {0x4a4b, 0x30}, ++ {0x5000, 0x85}, ++ {0x5001, 0x80}, ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list ov7251_stream_on_mipi[] = { ++ {0x0100, 0x01}, ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list ov7251_stream_off_mipi[] = { ++ {0x0100, 0x00}, ++ {OV7251_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int ov7251_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct ov7251_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct ov7251_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != OV7251_REG_END) { ++ if (vals->reg_num == OV7251_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov7251_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int ov7251_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != OV7251_REG_END) { ++ if (vals->reg_num == OV7251_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = ov7251_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int ov7251_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov7251_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int ov7251_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov7251_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int ov7251_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct ov7251_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = ov7251_write_array(sd, ov7251_common_init_regs_mipi); ++ ++ return ret; ++} ++ ++ ++ ++static int ov7251_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v = 0; ++ int ret; ++//while(1) ++ { ++ ret = ov7251_read(sd, 0x300a, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ } ++ if (ret < 0) ++ return ret; ++ if (v != OV7251_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = ov7251_read(sd, 0x300b, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ ++ if (ret < 0) ++ return ret; ++ if (v != OV7251_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++ ++static struct ov7251_win_size ov7251_win_sizes[] = { ++ { ++ .sensor_info.mipi_cfg.twidth = 640, ++ .sensor_info.mipi_cfg.theight = 480, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 60 << 16 | 1, ++ ++ .width = 640, ++ .height = 480, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov7251_init_regs_640_480_mipi, ++ }, ++ { ++ .sensor_info.mipi_cfg.twidth = 320, ++ .sensor_info.mipi_cfg.theight = 240, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 60 << 16 | 1, ++ ++ .width = 320, ++ .height = 240, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov7251_init_regs_320_240_mipi, ++ }, ++ { ++ .sensor_info.mipi_cfg.twidth = 160, ++ .sensor_info.mipi_cfg.theight = 120, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 75 << 16 | 1, ++ ++ .width = 160, ++ .height = 120, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = ov7251_init_regs_160_120_mipi, ++ }, ++}; ++ ++static const struct ov7251_win_size *ov7251_select_win(u32 *width, u32 *height) ++{ ++ int i, default_size = ARRAY_SIZE(ov7251_win_sizes) - 1; ++ ++ for (i = 0; i < ARRAY_SIZE(ov7251_win_sizes); i++) { ++ if ((*width >= ov7251_win_sizes[i].width) && ++ (*height >= ov7251_win_sizes[i].height)) { ++ *width = ov7251_win_sizes[i].width; ++ *height = ov7251_win_sizes[i].height; ++ return &ov7251_win_sizes[i]; ++ } ++ } ++ ++ *width = ov7251_win_sizes[default_size].width; ++ *height = ov7251_win_sizes[default_size].height; ++ return &ov7251_win_sizes[default_size]; ++} ++ ++ ++static int ov7251_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_OV7251_FMTS) ++ return -EINVAL; ++ ++ code->code = ov7251_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int ov7251_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov7251_format_struct *ovfmt; ++ struct ov7251_win_size *wsize; ++ struct ov7251_info *info = to_state(sd); ++ int ret; ++ ++ info->win = ov7251_select_win(&format->format.width, &format->format.height); ++ ++ return 0; ++} ++ ++static int ov7251_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct ov7251_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int ov7251_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int ov7251_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int ov7251_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov7251_again_lut); i++) { ++ lut = &ov7251_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(ov7251_again_lut); i++) { ++ lut = &ov7251_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++} ++ ++static int ov7251_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ /* ++ struct ov7251_info *info = to_state(sd); ++ char v = 0; ++ unsigned int reg_val = 0; ++ ++ ++ ret += ov7251_read(sd, 0x3509, &v); ++ ++ reg_val |= v; ++ ret += ov7251_read(sd, 0x3508, &v); ++ reg_val |= v << 8; ++ ++ ++ *value = regval_to_again(reg_val); ++ */ ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int ov7251_s_again(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++#if 0 ++ struct ov7251_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int i; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += ov7251_write(sd, 0x3509, (unsigned char)(reg_value & 0xff)); ++ ret += ov7251_write(sd, 0x3508, (unsigned char)((reg_value>>8) & 0xff)); ++ if (ret < 0) ++ return ret; ++ ++#endif ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int ov7251_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int ov7251_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ /* ++ struct ov7251_info *info = to_state(sd); ++ ++ ret += ov7251_write(sd, 0x3502, ((unsigned char)(value & 0xf)) << 4); ++ ret += ov7251_write(sd, 0x3501, (unsigned char)((value >> 4) & 0xff)); ++ ret += ov7251_write(sd, 0x3500, (unsigned char)((value >> 12) & 0xf)); ++ ++ */ ++ return ret; ++} ++ ++static int ov7251_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov7251_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return ov7251_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov7251_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct ov7251_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return ov7251_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return ov7251_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return ov7251_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return ov7251_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* ov7251_s_gain turns off auto gain */ ++ return ov7251_s_gain(sd, info->gain->val); ++ } ++ return ov7251_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return ov7251_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return ov7251_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return ov7251_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops ov7251_ctrl_ops = { ++ .s_ctrl = ov7251_s_ctrl, ++ .g_volatile_ctrl = ov7251_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov7251_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = ov7251_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int ov7251_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ ov7251_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int ov7251_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct ov7251_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ov7251_write_array(sd, info->win->regs); ++ ov7251_s_again(sd, 100000); ++ ret = ov7251_write_array(sd, ov7251_stream_on_mipi); ++ pr_debug("ov7251 stream on\n"); ++ ++ } ++ else { ++ ret = ov7251_write_array(sd, ov7251_stream_off_mipi); ++ pr_debug("ov7251 stream off\n"); ++ } ++ return ret; ++} ++ ++int ov7251_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct ov7251_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops ov7251_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov7251_g_register, ++ .s_register = ov7251_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops ov7251_video_ops = { ++ .s_stream = ov7251_s_stream, ++ .g_frame_interval = ov7251_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops ov7251_pad_ops = { ++ //.enum_frame_interval = ov7251_enum_frame_interval, ++ //.num_frame_size = ov7251_enum_frame_size, ++ //.enum_mbus_code = ov7251_enum_mbus_code, ++ .set_fmt = ov7251_set_fmt, ++ .get_fmt = ov7251_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops ov7251_ops = { ++ .core = &ov7251_core_ops, ++ .video = &ov7251_video_ops, ++ .pad = &ov7251_pad_ops, ++}; ++ ++int ov7251_regulator_get_supply(struct device *dev) ++{ ++ int ret; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov7251_info *info = to_state(sd); ++ ++ info->supply.vdd2v8 = devm_regulator_get_optional(dev, "vdd2v8"); ++ info->supply.vdd1v8 = devm_regulator_get_optional(dev, "vdd1v8"); ++ ++ if (IS_ERR(info->supply.vdd2v8)) { ++ if (PTR_ERR(info->supply.vdd2v8) == -EPROBE_DEFER) { ++ printk("No vdd2v8 regulator found\n"); ++ return -EPROBE_DEFER; ++ } ++ } ++ ++ if (IS_ERR(info->supply.vdd1v8)) { ++ if (PTR_ERR(info->supply.vdd1v8) == -EPROBE_DEFER) { ++ printk("No vdd1v8 regulator found\n"); ++ return -EPROBE_DEFER; ++ } ++ } ++ if (!IS_ERR(info->supply.vdd2v8)) { ++ ret = regulator_enable(info->supply.vdd2v8); ++ if (ret) { ++ dev_err(&client->dev, "ov7251 vdd2v8 supply enable failed\n"); ++ return ret; ++ } ++ } ++ if (!IS_ERR(info->supply.vdd1v8)) { ++ ret = regulator_enable(info->supply.vdd1v8); ++ if (ret) { ++ dev_err(&client->dev, "ov7251 vdd1v8 supply enable failed\n"); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int ov7251_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct ov7251_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ int tmp; ++ ++ dev_info(&client->dev, "ov7251 probing\n"); ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &ov7251_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ ret = ov7251_regulator_get_supply(&client->dev); ++ if (ret) ++ dev_err(&client->dev, "get supply failed!\n"); ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ info->win = &ov7251_win_sizes[0]; ++ ov7251_reset(sd, 1); ++#if 1 ++ /* Make sure it's an ov7251 */ ++ ret = ov7251_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an ov7251 chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 261773, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov7251_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ ov7251_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "ov7251 Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int ov7251_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov7251_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id ov7251_id[] = { ++ { "ov7251", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov7251_id); ++ ++static const struct of_device_id ov7251_of_match[] = { ++ {.compatible = "ovti,ov7251", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++int ov7251_suspend(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov7251_info *info = to_state(sd); ++ int ret; ++ ++ if (!IS_ERR(info->supply.vdd2v8)) { ++ ret = regulator_disable(info->supply.vdd2v8); ++ if (ret) { ++ dev_err(dev, "ov7251 vdd2v8 supply disable failed\n"); ++ return ret; ++ } ++ } ++ if (!IS_ERR(info->supply.vdd1v8)) { ++ ret = regulator_disable(info->supply.vdd1v8); ++ if (ret) { ++ dev_err(dev, "ov7251 vdd1v8 supply disable failed\n"); ++ return ret; ++ } ++ } ++ ++ v4l2_clk_disable(info->clk); ++ return 0; ++} ++ ++int ov7251_resume(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct ov7251_info *info = to_state(sd); ++ int ret; ++ ++ if (!IS_ERR(info->supply.vdd2v8)) { ++ ret = regulator_enable(info->supply.vdd2v8); ++ if (ret) { ++ dev_err(dev, "ov7251 vdd2v8 supply enable failed\n"); ++ return ret; ++ } ++ } ++ if (!IS_ERR(info->supply.vdd1v8)) { ++ ret = regulator_enable(info->supply.vdd1v8); ++ if (ret) { ++ dev_err(dev, "ov7251 vdd1v8 supply enable failed\n"); ++ return ret; ++ } ++ } ++ ++ v4l2_clk_enable(info->clk); ++ ov7251_reset(sd, 1); ++ ov7251_init(sd, 1); ++ return 0; ++} ++ ++const struct dev_pm_ops ov7251_pm = ++{ ++ .suspend = ov7251_suspend, ++ .resume = ov7251_resume, ++}; ++ ++ ++ ++static struct i2c_driver ov7251_driver = { ++ .driver = { ++ .name = "ov7251", ++ .of_match_table = of_match_ptr(ov7251_of_match), ++ .pm = &ov7251_pm, ++ }, ++ .probe = ov7251_probe, ++ .remove = ov7251_remove, ++ .id_table = ov7251_id, ++}; ++ ++module_i2c_driver(ov7251_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision ov7251 sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/sc0132gs.c b/module_drivers/drivers/media/i2c/ingenic-isp/sc0132gs.c +new file mode 100644 +index 000000000..323b21b2d +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/sc0132gs.c +@@ -0,0 +1,1630 @@ ++/* ++ * A V4L2 driver for OmniVision SC0132GS cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SC0132GS_CHIP_ID_H (0x01) ++#define SC0132GS_CHIP_ID_L (0x32) ++#define SC0132GS_REG_END 0xffff ++#define SC0132GS_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct sc0132gs_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct sc0132gs_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct sc0132gs_supply{ ++ struct regulator *avdd; ++ struct regulator *dvdd; ++ struct regulator *dovdd; ++}; ++ ++struct sc0132gs_info { ++ struct sc0132gs_supply supply; ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ struct clk *sclka; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct sc0132gs_win_size *win; ++ ++ struct sc0132gs_gpio reset; ++ struct sc0132gs_gpio vcc_en; ++ struct sc0132gs_gpio ircutp; ++ struct sc0132gs_gpio ircutn; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut sc0132gs_again_lut[] = { ++ ++ {0x80, 0}, ++ {0x88, 5731}, ++ {0x90, 11136}, ++ {0x98, 16248}, ++ {0xa0, 21097}, ++ {0xa8, 25710}, ++ {0xb0, 30109}, ++ {0xb8, 34312}, ++ {0xc0, 38336}, ++ {0xc8, 42195}, ++ {0xd0, 45904}, ++ {0xd8, 49472}, ++ {0xe0, 52910}, ++ {0xe8, 56228}, ++ {0xf0, 59433}, ++ {0xf8, 62534}, ++ {0x178, 65536}, ++ {0x17c, 68445}, ++ {0x180, 71267}, ++ {0x184, 74008}, ++ {0x188, 76672}, ++ {0x18c, 79262}, ++ {0x190, 81784}, ++ {0x194, 84240}, ++ {0x198, 86633}, ++ {0x19c, 88968}, ++ {0x1a0, 91246}, ++ {0x1a4, 93471}, ++ {0x1a8, 95645}, ++ {0x1ac, 97770}, ++ {0x1b0, 99848}, ++ {0x1b4, 101881}, ++ {0x1b8, 103872}, ++ {0x1bc, 105821}, ++ {0x1c0, 107731}, ++ {0x1c4, 109604}, ++ {0x1c8, 111440}, ++ {0x1cc, 113241}, ++ {0x1d0, 115008}, ++ {0x1d4, 116743}, ++ {0x1d8, 118446}, ++ {0x1dc, 120120}, ++ {0x1e0, 121764}, ++ {0x1e4, 123380}, ++ {0x1e8, 124969}, ++ {0x1ec, 126532}, ++ {0x1f0, 128070}, ++ {0x1f4, 129583}, ++ {0x374, 131072}, ++ {0x376, 132537}, ++ {0x378, 133981}, ++ {0x37a, 135403}, ++ {0x37c, 136803}, ++ {0x37e, 138184}, ++ {0x380, 139544}, ++ {0x382, 140885}, ++ {0x384, 142208}, ++ {0x386, 143512}, ++ {0x388, 144798}, ++ {0x38a, 146067}, ++ {0x38c, 147320}, ++ {0x38e, 148556}, ++ {0x390, 149776}, ++ {0x392, 150980}, ++ {0x394, 152169}, ++ {0x396, 153344}, ++ {0x398, 154504}, ++ {0x39a, 155650}, ++ {0x39c, 156782}, ++ {0x39e, 157901}, ++ {0x3a0, 159007}, ++ {0x3a2, 160100}, ++ {0x3a4, 161181}, ++ {0x3a6, 162249}, ++ {0x3a8, 163306}, ++ {0x3aa, 164350}, ++ {0x3ac, 165384}, ++ {0x3ae, 166406}, ++ {0x3b0, 167417}, ++ {0x3b2, 168418}, ++ {0x3b4, 169408}, ++ {0x3b6, 170387}, ++ {0x3b8, 171357}, ++ {0x3ba, 172317}, ++ {0x3bc, 173267}, ++ {0x3be, 174208}, ++ {0x3c0, 175140}, ++ {0x3c2, 176062}, ++ {0x3c4, 176976}, ++ {0x3c6, 177880}, ++ {0x3c8, 178777}, ++ {0x3ca, 179664}, ++ {0x3cc, 180544}, ++ {0x3ce, 181415}, ++ {0x3d0, 182279}, ++ {0x3d2, 183134}, ++ {0x3d4, 183982}, ++ {0x3d6, 184823}, ++ {0x3d8, 185656}, ++ {0x3da, 186482}, ++ {0x3dc, 187300}, ++ {0x3de, 188112}, ++ {0x3e0, 188916}, ++ {0x3e2, 189714}, ++ {0x3e4, 190505}, ++ {0x3e6, 191290}, ++ {0x3e8, 192068}, ++ {0x3ea, 192840}, ++ {0x3ec, 193606}, ++ {0x3ee, 194365}, ++ {0x3f0, 195119}, ++ {0x3f2, 195866}, ++ {0x778, 196608}, ++ {0x779, 197343}, ++ {0x77a, 198073}, ++ {0x77b, 198798}, ++ {0x77c, 199517}, ++ {0x77d, 200230}, ++ {0x77e, 200939}, ++ {0x77f, 201642}, ++ {0x780, 202339}, ++ {0x781, 203032}, ++ {0x782, 203720}, ++ {0x783, 204402}, ++ {0x784, 205080}, ++ {0x785, 205753}, ++ {0x786, 206421}, ++ {0x787, 207085}, ++ {0x788, 207744}, ++ {0x789, 208398}, ++ {0x78a, 209048}, ++ {0x78b, 209693}, ++ {0x78c, 210334}, ++ {0x78d, 210971}, ++ {0x78e, 211603}, ++ {0x78f, 212232}, ++ {0x790, 212856}, ++ {0x791, 213476}, ++ {0x792, 214092}, ++ {0x793, 214704}, ++ {0x794, 215312}, ++ {0x795, 215916}, ++ {0x796, 216516}, ++ {0x797, 217113}, ++ {0x798, 217705}, ++ {0x799, 218294}, ++ {0x79a, 218880}, ++ {0x79b, 219462}, ++ {0x79c, 220040}, ++ {0x79d, 220615}, ++ {0x79e, 221186}, ++ {0x79f, 221754}, ++ {0x7a0, 222318}, ++ {0x7a1, 222880}, ++ {0x7a2, 223437}, ++ {0x7a3, 223992}, ++ {0x7a4, 224543}, ++ {0x7a5, 225091}, ++ {0x7a6, 225636}, ++ {0x7a7, 226178}, ++ {0x7a8, 226717}, ++ {0x7a9, 227253}, ++ {0x7aa, 227785}, ++ {0x7ab, 228315}, ++ {0x7ac, 228842}, ++ {0x7ad, 229365}, ++ {0x7ae, 229886}, ++ {0x7af, 230404}, ++ {0x7b0, 230920}, ++ {0x7b1, 231432}, ++ {0x7b2, 231942}, ++ {0x7b3, 232449}, ++ {0x7b4, 232953}, ++ {0x7b5, 233455}, ++ {0x7b6, 233954}, ++ {0x7b7, 234450}, ++ {0x7b8, 234944}, ++ {0x7b9, 235435}, ++ {0x7ba, 235923}, ++ {0x7bb, 236410}, ++ {0x7bc, 236893}, ++ {0x7bd, 237374}, ++ {0x7be, 237853}, ++ {0x7bf, 238329}, ++ {0x7c0, 238803}, ++ {0x7c1, 239275}, ++ {0x7c2, 239744}, ++ {0x7c3, 240211}, ++ {0x7c4, 240676}, ++ {0x7c5, 241138}, ++ {0x7c6, 241598}, ++ {0x7c7, 242056}, ++ {0x7c8, 242512}, ++ {0x7c9, 242965}, ++ {0x7ca, 243416}, ++ {0x7cb, 243865}, ++ {0x7cc, 244313}, ++ {0x7cd, 244757}, ++ {0x7ce, 245200}, ++ {0x7cf, 245641}, ++ {0x7d0, 246080}, ++ {0x7d1, 246517}, ++ {0x7d2, 246951}, ++ {0x7d3, 247384}, ++ {0x7d4, 247815}, ++ {0x7d5, 248243}, ++ {0x7d6, 248670}, ++ {0x7d7, 249095}, ++ {0x7d8, 249518}, ++ {0x7d9, 249939}, ++ {0x7da, 250359}, ++ {0x7db, 250776}, ++ {0x7dc, 251192}, ++ {0x7dd, 251606}, ++ {0x7de, 252018}, ++ {0x7df, 252428}, ++ {0x7e0, 252836}, ++ {0x7e1, 253243}, ++ {0x7e2, 253648}, ++ {0x7e3, 254051}, ++ {0x7e4, 254452}, ++ {0x7e5, 254852}, ++ {0x7e6, 255250}, ++ {0x7e7, 255647}, ++ {0x7e8, 256041}, ++ {0x7e9, 256435}, ++ {0x7ea, 256826}, ++ {0x7eb, 257216}, ++ {0x7ec, 257604}, ++ {0x7ed, 257991}, ++ {0x7ee, 258376}, ++ {0x7ef, 258760}, ++ {0x7f0, 259142}, ++ {0x7f1, 259522}, ++ {0x7f2, 259901}, ++ {0x7f3, 260279}, ++ {0x7f4, 260655}, ++ {0x7f5, 261029}, ++ {0x7f6, 261402}, ++ {0x7f7, 261773}, ++}; ++ ++static struct i2c_client *led_ic_client; ++static struct i2c_board_info aw9110b_info = { ++ I2C_BOARD_INFO("aw9110b", 0x5b), ++}; ++ ++static inline struct sc0132gs_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct sc0132gs_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct sc0132gs_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list sc0132gs_init_regs_1080_1280_60fps_mipi[] = { ++ //[ParaList] ++#if 1 ++ //sc132gs_setting_1080x1280 ++ {0x0103,0x01}, ++ {0x0100,0x00}, ++ //PLL bypass ++ {0x36e9,0x80}, ++ {0x36f9,0x80}, ++ {0x0100,0x00}, ++ {0x3018,0x32}, ++ {0x3019,0x0c}, ++ {0x301a,0xb4}, ++ {0x3031,0x08}, // raw8 ++ //{0x3031,0x0a}, // raw10 ++ {0x3032,0x60}, ++ {0x3038,0x44}, ++ {0x3207,0x17}, ++ {0x320c,0x05}, ++ {0x320d,0x35}, ++ {0x320e,0x05}, ++ {0x320f,0x46}, ++ {0x3250,0xcc}, ++ {0x3251,0x02}, ++ {0x3252,0x05}, ++ {0x3253,0x41}, ++ {0x3254,0x05}, ++ {0x3255,0x3b}, ++ {0x3306,0x78}, ++ {0x330a,0x00}, ++ {0x330b,0xc8}, ++ {0x330f,0x24}, ++ {0x3314,0x80}, ++ {0x3315,0x40}, ++ {0x3317,0xf0}, ++ {0x331f,0x12}, ++ {0x3364,0x00}, ++ {0x3385,0x41}, ++ {0x3387,0x41}, ++ {0x3389,0x09}, ++ {0x33ab,0x00}, ++ {0x33ac,0x00}, ++ {0x33b1,0x03}, ++ {0x33b2,0x12}, ++ {0x33f8,0x02}, ++ {0x33fa,0x01}, ++ {0x3409,0x08}, ++ {0x34f0,0xc0}, ++ {0x34f1,0x20}, ++ {0x34f2,0x03}, ++ {0x3622,0xf5}, ++ {0x3630,0x5c}, ++ {0x3631,0x80}, ++ {0x3632,0xc8}, ++ {0x3633,0x32}, ++ {0x3638,0x2a}, ++ {0x3639,0x07}, ++ {0x363b,0x48}, ++ {0x363c,0x83}, ++ {0x363d,0x10}, ++ {0x36ea,0x38}, ++ {0x36fa,0x25}, ++ {0x36fb,0x05}, ++ {0x36fd,0x04}, ++ {0x3900,0x11}, ++ {0x3901,0x05}, ++ {0x3902,0xc5}, ++ {0x3904,0x04}, ++ {0x3908,0x91}, ++ {0x391e,0x00}, ++ {0x3e01,0x53}, ++ {0x3e02,0xe0}, ++ {0x3e06,0x07},//Bit[3:0]: digital gain ++ {0x3e08,0x05},//10 gain ++ {0x3e09,0x12},// ++ {0x3e0e,0xd2}, ++ {0x3e14,0xb0}, ++ {0x3e1e,0x7c}, ++ {0x3e26,0x20}, ++ {0x4418,0x38}, ++ //{0x4501,0x08}, // test Bit[3]: incremental pattern ++ {0x4503,0x10}, ++ {0x4837,0x21}, ++ {0x5000,0x0e}, ++ {0x540c,0x51}, ++ {0x550f,0x38}, ++ {0x5780,0x67}, ++ {0x5784,0x10}, ++ {0x5785,0x06}, ++ {0x5787,0x02}, ++ {0x5788,0x00}, ++ {0x5789,0x00}, ++ {0x578a,0x02}, ++ {0x578b,0x00}, ++ {0x578c,0x00}, ++ {0x5790,0x00}, ++ {0x5791,0x00}, ++ {0x5792,0x00}, ++ {0x5793,0x00}, ++ {0x5794,0x00}, ++ {0x5795,0x00}, ++ {0x5799,0x04}, ++ //PLL set ++ {0x36e9,0x20}, ++ {0x36f9,0x24}, ++ {0x0100,0x01}, ++ {0x33fa,0x02}, ++ {0x3317,0x0a}, ++ {0x0100,0x01}, ++ {0x3221,0x66}, // flip,mirror on ++ //{0x3221,0x00}, // flip,mirror off ++#endif ++ {SC0132GS_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list sc0132gs_stream_on_mipi[] = { ++ {0x0100, 0x01}, ++ {SC0132GS_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc0132gs_stream_off_mipi[] = { ++ {0x0100, 0x00}, ++ {SC0132GS_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int sc0132gs_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct sc0132gs_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int sc0132gs_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct sc0132gs_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ //printk("sc0132gs write i2c with %d %d\n", buf[0], buf[1]); ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int sc0132gs_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != SC0132GS_REG_END) { ++ if (vals->reg_num == SC0132GS_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc0132gs_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int sc0132gs_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != SC0132GS_REG_END) { ++ if (vals->reg_num == SC0132GS_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc0132gs_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int sc0132gs_power(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc0132gs_info *info = to_state(sd); ++ /*struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret;*/ ++ ++ if(val){ ++ gpio_direction_output(info->vcc_en.pin, info->vcc_en.active_level); ++ }else{ ++ gpio_direction_output(info->vcc_en.pin, !info->vcc_en.active_level); ++ } ++ /*info->supply.avdd = devm_regulator_get_optional(&client->dev, "avdd"); ++ info->supply.dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); ++ info->supply.dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); ++ ++ if (IS_ERR(info->supply.avdd)||IS_ERR(info->supply.dvdd) ++ ||IS_ERR(info->supply.dovdd)) { ++ if ((PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.avdd) == -EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ printk("No sc230ai vdd regulator found\n"); ++ } ++ ++ if ((!IS_ERR(info->supply.avdd))&&(!IS_ERR(info->supply.avdd)) ++ &&(!IS_ERR(info->supply.avdd))) { ++ if(val){ ++ ret = regulator_enable(info->supply.avdd); ++ ret = regulator_enable(info->supply.dvdd); ++ ret = regulator_enable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "sc230ai vdd supply disable failed\n"); ++ } ++ else{ ++ ret = regulator_disable(info->supply.avdd); ++ ret = regulator_disable(info->supply.dvdd); ++ ret = regulator_disable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "sc230ai vdd supply disable failed\n"); ++ } ++ }else{ ++ dev_err(&client->dev, "sc230ai vdd supply IS_ERR failed\n"); ++ }*/ ++ return 0; ++} ++ ++static int sc0132gs_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc0132gs_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int sc0132gs_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc0132gs_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++/* ++static int sc0132gs_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc0132gs_info *info = to_state(sd); ++ int ret = 0; ++ //printk("sc0132gs init called ....\n"); ++ ret = sc0132gs_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++*/ ++ ++ ++static int sc0132gs_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v = 0; ++ int ret; ++ ++ ret = sc0132gs_read(sd, 0x3107, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC0132GS_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = sc0132gs_read(sd, 0x3108, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC0132GS_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++#if 0 ++/* grey y8 */ ++static struct sc0132gs_win_size sc0132gs_win_sizes[] = { ++ { ++ .width = 1080, ++ .height = 1280, ++ //.fps = 60 << 16 | 1, ++ .sensor_info.fps = 60 << 16 | 1, ++ .sensor_info.mipi_cfg.twidth = 1080, ++ .sensor_info.mipi_cfg.theight = 1280, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ //.mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc0132gs_init_regs_1080_1280_60fps_mipi, ++ }, ++}; ++#else ++/* YUV422 */ ++static struct sc0132gs_win_size sc0132gs_win_sizes[] = { ++ { ++ .width = 1080/2, ++ .height = 1280, ++ //.fps = 60 << 16 | 1, ++ .sensor_info.fps = 60 << 16 | 1, ++ .sensor_info.mipi_cfg.twidth = 1080/2, ++ .sensor_info.mipi_cfg.theight = 1280, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ //.mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ //.mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ //.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, ++ //.mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, ++ //.mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, ++ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, /* sc0132gs UYVY8_2X8 order ok. */ ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc0132gs_init_regs_1080_1280_60fps_mipi, ++ }, ++}; ++#endif ++ ++static int sc0132gs_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_SC0132GS_FMTS) ++ return -EINVAL; ++ ++ code->code = sc0132gs_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int sc0132gs_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc0132gs_format_struct *ovfmt; ++ struct sc0132gs_win_size *wsize; ++ struct sc0132gs_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int sc0132gs_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc0132gs_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++ // printk("----%s, %d, width: %d, height: %d, code: %x\n", ++ // __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int sc0132gs_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc0132gs_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc0132gs_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc0132gs_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int sc0132gs_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int sc0132gs_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc0132gs_again_lut); i++) { ++ lut = &sc0132gs_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc0132gs_again_lut); i++) { ++ lut = &sc0132gs_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++} ++ ++static int sc0132gs_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ /* ++ struct sc0132gs_info *info = to_state(sd); ++ char v = 0; ++ unsigned int reg_val = 0; ++ ++ ++ ret += sc0132gs_read(sd, 0x3509, &v); ++ ++ reg_val |= v; ++ ret += sc0132gs_read(sd, 0x3508, &v); ++ reg_val |= v << 8; ++ ++ ++ *value = regval_to_again(reg_val); ++ */ ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int sc0132gs_s_again(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++#if 0 ++ struct sc0132gs_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int i; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += sc0132gs_write(sd, 0x3509, (unsigned char)(reg_value & 0xff)); ++ ret += sc0132gs_write(sd, 0x3508, (unsigned char)((reg_value>>8) & 0xff)); ++ if (ret < 0) ++ return ret; ++ ++#endif ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int sc0132gs_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc0132gs_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ /* ++ struct sc0132gs_info *info = to_state(sd); ++ ++ if(info->exposure->val != value) { ++ ret += sc0132gs_write(sd, 0x3502, ((unsigned char)(value & 0xf)) << 4); ++ ret += sc0132gs_write(sd, 0x3501, (unsigned char)((value >> 4) & 0xff)); ++ ret += sc0132gs_write(sd, 0x3500, (unsigned char)((value >> 12) & 0xf)); ++ } ++ ++*/ ++ return ret; ++} ++ ++static int sc0132gs_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc0132gs_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return sc0132gs_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc0132gs_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int sc0132gs_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc0132gs_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return sc0132gs_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return sc0132gs_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return sc0132gs_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return sc0132gs_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* sc0132gs_s_gain turns off auto gain */ ++ return sc0132gs_s_gain(sd, info->gain->val); ++ } ++ return sc0132gs_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return sc0132gs_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc0132gs_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return sc0132gs_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops sc0132gs_ctrl_ops = { ++ .s_ctrl = sc0132gs_s_ctrl, ++ .g_volatile_ctrl = sc0132gs_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int sc0132gs_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = sc0132gs_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int sc0132gs_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ sc0132gs_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int sc0132gs_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct sc0132gs_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ret = sc0132gs_write_array(sd, sc0132gs_stream_on_mipi); ++ pr_debug("sc0132gs stream on\n"); ++ } ++ else { ++ ret = sc0132gs_write_array(sd, sc0132gs_stream_off_mipi); ++ pr_debug("sc0132gs stream off\n"); ++ } ++ return ret; ++} ++typedef struct I2C_regs{ ++ struct regval_list regs[8]; ++ u16 count; ++}TOMATO_I2C_regs; ++ ++#define TOMATO_VIDIOC_IIC_WRITE _IOWR('V', BASE_VIDIOC_PRIVATE + 1, TOMATO_I2C_regs) ++#define TOMATO_VIDIOC_IIC_READ _IOWR('V', BASE_VIDIOC_PRIVATE + 2, TOMATO_I2C_regs) ++ ++#define VIDIOC_S_SENSORPWRSTATE _IOW('v',60,int) ++#define VIDIOC_G_SENSORPWRSTATE _IOR('v',61,int) ++#define VIDIOC_S_ILLUMCTRL _IOW('v',62,int) ++#define ILLUM_WORKAROUND ++ ++#ifdef ILLUM_WORKAROUND ++#define ILLUM_PIN 32*1 + 24//PB_24 ++#define ILLUM_RED_PIN 32*1 + 29//PB_29 ++#define ILLUM_BLUE_PIN 32*1 + 30//PB_30 ++#define ILLUM_CHIP_PIN 32*1 + 31//PB_31 ++#define ILLUM_SET_LEVEL_LOW_PIN 32*1 + 14//GPIO_PB(14) ++#define ILLUM_SET_LEVEL_MID_PIN 32*1 + 13//GPIO_PB(13) ++#define ILLUM_SET_LEVEL_HIGH_PIN 32*1 + 12//GPIO_PB(12) ++#define AIMER_PIN 32*1 + 28//PB_28 ++ ++typedef struct { ++ int illum_low_level_is_set; ++ int illum_mid_level_is_set; ++ int illum_high_level_is_set; ++} Illum_level; ++ ++Illum_level Illum_level_status = {0,0,0}; ++ ++static int RequestIlluminationRelatedGpioPins(struct i2c_client *client) ++{ ++ int error = 0; ++ ++ #ifdef ILLUM_WORKAROUND ++ //illum_enable_ctrl_pin ++ if (!gpio_is_valid(ILLUM_PIN)) ++ { ++ //dev_info(&client->dev,"invalid ILLM_PIN gpio number\n"); ++ //PRINTDBG("invalid ILLM_PIN gpio number\n"); ++ return (-1); ++ } ++ error = gpio_request_one(ILLUM_PIN, GPIOF_OUT_INIT_LOW, "sc0132gs"); ++ if (error < 0) ++ { ++ //dev_info(&client->dev,"Failed to request GPIO %d, error %d\n", ILLUM_PIN, error); ++ //PRINTDBG("Failed to request GPIO %d, error %d\n", ILLUM_PIN, error); ++ return error; ++ } ++ //illum_enable_ctrl_pin ++ if (!gpio_is_valid(ILLUM_RED_PIN)) ++ { ++ //dev_info(&client->dev,"invalid ILLM_PIN gpio number\n"); ++ //PRINTDBG("invalid ILLM_PIN gpio number\n"); ++ return (-1); ++ } ++ error = gpio_request_one(ILLUM_RED_PIN, GPIOF_OUT_INIT_LOW, "sc0132gs"); ++ if (error < 0) ++ { ++ //dev_info(&client->dev,"Failed to request GPIO %d, error %d\n", ILLUM_PIN, error); ++ //PRINTDBG("Failed to request GPIO %d, error %d\n", ILLUM_PIN, error); ++ return error; ++ } ++ //illum_enable_ctrl_pin ++ if (!gpio_is_valid(ILLUM_BLUE_PIN)) ++ { ++ //dev_info(&client->dev,"invalid ILLM_PIN gpio number\n"); ++ //PRINTDBG("invalid ILLM_PIN gpio number\n"); ++ return (-1); ++ } ++ error = gpio_request_one(ILLUM_BLUE_PIN, GPIOF_OUT_INIT_LOW, "sc0132gs"); ++ if (error < 0) ++ { ++ //dev_info(&client->dev,"Failed to request GPIO %d, error %d\n", ILLUM_PIN, error); ++ //PRINTDBG("Failed to request GPIO %d, error %d\n", ILLUM_PIN, error); ++ return error; ++ } ++ //illum_enable_ctrl_pin ++ if (!gpio_is_valid(ILLUM_CHIP_PIN)) ++ { ++ //dev_info(&client->dev,"invalid ILLM_PIN gpio number\n"); ++ //PRINTDBG("invalid ILLM_PIN gpio number\n"); ++ return (-1); ++ } ++ error = gpio_request_one(ILLUM_CHIP_PIN, GPIOF_OUT_INIT_HIGH, "sc0132gs"); ++ if (error < 0) ++ { ++ //dev_info(&client->dev,"Failed to request GPIO %d, error %d\n", ILLUM_PIN, error); ++ //PRINTDBG("Failed to request GPIO %d, error %d\n", ILLUM_PIN, error); ++ return error; ++ } ++ //illum_low_level_pin ++ if (!gpio_is_valid(ILLUM_SET_LEVEL_LOW_PIN)) ++ { ++ dev_info(&client->dev,"invalid gpio number:%d!\n",ILLUM_SET_LEVEL_LOW_PIN); ++ return (-1); ++ } ++ error = gpio_request_one(ILLUM_SET_LEVEL_LOW_PIN, GPIOF_OUT_INIT_LOW, "sc0132gs"); ++ if (error < 0) ++ { ++ dev_info(&client->dev,"Failed to request GPIO %d, error %d\n", ILLUM_SET_LEVEL_LOW_PIN, error); ++ return error; ++ } ++ //illum_mid_level_pin ++ if (!gpio_is_valid(ILLUM_SET_LEVEL_MID_PIN)) ++ { ++ dev_info(&client->dev,"invalid gpio number:%d!\n",ILLUM_SET_LEVEL_MID_PIN); ++ return (-1); ++ } ++ error = gpio_request_one(ILLUM_SET_LEVEL_MID_PIN, GPIOF_OUT_INIT_LOW, "sc0132gs"); ++ if (error < 0) ++ { ++ dev_info(&client->dev,"Failed to request GPIO %d, error %d\n", ILLUM_SET_LEVEL_MID_PIN, error); ++ return error; ++ } ++ //illum_high_level_pin ++ if (!gpio_is_valid(ILLUM_SET_LEVEL_HIGH_PIN)) ++ { ++ dev_info(&client->dev,"invalid gpio number:%d!\n",ILLUM_SET_LEVEL_HIGH_PIN); ++ return (-1); ++ } ++ error = gpio_request_one(ILLUM_SET_LEVEL_HIGH_PIN, GPIOF_OUT_INIT_LOW, "sc0132gs"); ++ if (error < 0) ++ { ++ dev_info(&client->dev,"Failed to request GPIO %d, error %d\n", ILLUM_SET_LEVEL_HIGH_PIN, error); ++ return error; ++ } ++ if (!gpio_is_valid(AIMER_PIN)) ++ { ++ dev_info(&client->dev,"invalid AIMER_PIN gpio number\n"); ++ return (-1); ++ } ++ error = gpio_request_one(AIMER_PIN, GPIOF_OUT_INIT_LOW, "sc0132gs"); ++ if (error < 0) ++ { ++ dev_info(&client->dev,"Failed to request GPIO %d, error %d\n", AIMER_PIN, error); ++ return error; ++ } ++ i2c_smbus_write_byte_data(led_ic_client, 0x02, 0x00); ++ i2c_smbus_write_byte_data(led_ic_client, 0x11, 0x00); ++ i2c_smbus_write_byte_data(led_ic_client, 0x12, 0x00); ++ i2c_smbus_write_byte_data(led_ic_client, 0x13, 0x00); ++ i2c_smbus_write_byte_data(led_ic_client, 0x20, 0x80); ++ i2c_smbus_write_byte_data(led_ic_client, 0x21, 0x80); ++ i2c_smbus_write_byte_data(led_ic_client, 0x22, 0x80); ++ i2c_smbus_write_byte_data(led_ic_client, 0x23, 0x80); ++ i2c_smbus_write_byte_data(led_ic_client, 0x24, 0x80); ++ i2c_smbus_write_byte_data(led_ic_client, 0x25, 0x80); ++ i2c_smbus_write_byte_data(led_ic_client, 0x26, 0x80); ++ i2c_smbus_write_byte_data(led_ic_client, 0x27, 0x80); ++ i2c_smbus_write_byte_data(led_ic_client, 0x28, 0x80); ++ i2c_smbus_write_byte_data(led_ic_client, 0x29, 0x80); ++ #endif ++ ++ return error; ++} ++ ++static int IlluminationSetLevel(unsigned int illum_level_pin) ++{ ++ int error = 0; ++#ifdef ILLUM_WORKAROUND ++ ++ //PRINTDBG("Illum_level_status %d %d %d \r\n",Illum_level_status.illum_low_level_is_set,Illum_level_status.illum_mid_level_is_set,Illum_level_status.illum_high_level_is_set); ++ error = gpio_direction_output(illum_level_pin,1); ++ if (error<0) ++ { ++ //dev_info(&client->dev,"Failed to set out direction GPIO %d, error %d\n", illum_level_pin, error); ++ return - 1; ++ } ++ ++ if(ILLUM_SET_LEVEL_LOW_PIN == illum_level_pin) ++ { ++ Illum_level_status.illum_low_level_is_set = 1; ++ } ++ if(ILLUM_SET_LEVEL_MID_PIN == illum_level_pin) ++ { ++ Illum_level_status.illum_mid_level_is_set = 1; ++ } ++ if(ILLUM_SET_LEVEL_HIGH_PIN == illum_level_pin) ++ { ++ Illum_level_status.illum_high_level_is_set = 1; ++ } ++ ++ /******************set other illum pins direction input as hardward required***********************/ ++ if(ILLUM_SET_LEVEL_LOW_PIN != illum_level_pin) ++ { ++ error = gpio_direction_input(ILLUM_SET_LEVEL_LOW_PIN); ++ if (error<0) ++ { ++ //dev_info(&client->dev,"Failed to set input direction GPIO %d, error %d\n", ILLUM_SET_LEVEL_LOW_PIN, error); ++ return - 1; ++ } ++ else ++ { ++ Illum_level_status.illum_low_level_is_set = 0; ++ } ++ } ++ ++ if(ILLUM_SET_LEVEL_MID_PIN != illum_level_pin) ++ { ++ error = gpio_direction_input(ILLUM_SET_LEVEL_MID_PIN); ++ if (error<0) ++ { ++ //dev_info(&client->dev,"Failed to set input direction GPIO %d, error %d\n", ILLUM_SET_LEVEL_MID_PIN, error); ++ return - 1; ++ } ++ else ++ { ++ Illum_level_status.illum_mid_level_is_set = 0; ++ } ++ } ++ ++ if(ILLUM_SET_LEVEL_HIGH_PIN != illum_level_pin) ++ { ++ error = gpio_direction_input(ILLUM_SET_LEVEL_HIGH_PIN); ++ if (error<0) ++ { ++ //dev_info(&client->dev,"Failed to set input direction GPIO %d, error %d\n", ILLUM_SET_LEVEL_HIGH_PIN, error); ++ return - 1; ++ } ++ else ++ { ++ Illum_level_status.illum_high_level_is_set = 0; ++ } ++ } ++ /***********************************************************************************************/ ++#endif ++ return 0; ++} ++ ++static int IlluminationSetControl(long *illum_ctrl) ++{ ++ int error = 0; ++ ++#ifdef ILLUM_WORKAROUND ++ if (((*illum_ctrl)>>5)&0x1) // Aimer on ++ { ++ gpio_set_value(AIMER_PIN, 1); ++ } ++ else // Aimer off ++ { ++ gpio_set_value(AIMER_PIN, 0); ++ } ++ ++ if (((*illum_ctrl)>>4)&0x1) //Illum on ++ { ++ if (((*illum_ctrl)>>6)&0x1) ++ { ++ gpio_set_value(ILLUM_PIN, 0); ++ gpio_set_value(ILLUM_RED_PIN, 1); ++ gpio_set_value(ILLUM_BLUE_PIN, 0); ++ } ++ else if (((*illum_ctrl)>>7)&0x1) ++ { ++ gpio_set_value(ILLUM_PIN, 0); ++ gpio_set_value(ILLUM_RED_PIN, 0); ++ gpio_set_value(ILLUM_BLUE_PIN, 1); ++ } ++ else ++ { ++ gpio_set_value(ILLUM_PIN, 1); ++ gpio_set_value(ILLUM_RED_PIN, 0); ++ gpio_set_value(ILLUM_BLUE_PIN, 0); ++ } ++ ++ switch((*illum_ctrl)&0x03) ++ { ++ case 1: // illum low level ++ IlluminationSetLevel(ILLUM_SET_LEVEL_LOW_PIN); ++ break; ++ case 2: // illum mid level ++ IlluminationSetLevel(ILLUM_SET_LEVEL_MID_PIN); ++ break; ++ case 3: // illum high level ++ IlluminationSetLevel(ILLUM_SET_LEVEL_HIGH_PIN); ++ break; ++ default: ++ IlluminationSetLevel(ILLUM_SET_LEVEL_LOW_PIN); ++ break; ++ } ++ } ++ else //Illum off ++ { ++ gpio_set_value(ILLUM_PIN, 0); ++ gpio_set_value(ILLUM_RED_PIN, 0); ++ gpio_set_value(ILLUM_BLUE_PIN, 0); ++ } ++#endif ++ return error; ++} ++#endif ++ ++static int sc0132gs_read_I2cRegs(struct v4l2_subdev *sd, TOMATO_I2C_regs *vals) ++{ ++ int ret = -1; ++ int i; ++ struct regval_list *pregs = &(vals->regs); ++ for(i = 0; i < vals->count; i++) ++ { ++ unsigned char val; ++ ret = sc0132gs_read(sd, pregs->reg_num & 0xffff, &val); ++ if (ret < 0) ++ return ret; ++ pregs->value = val; ++ pregs++; ++ } ++ return 0; ++} ++ ++static int sc0132gs_write_I2cRegs(struct v4l2_subdev *sd,const TOMATO_I2C_regs *vals) ++{ ++ int ret; ++ int i; ++ struct regval_list *pregs = &(vals->regs); ++ for(i = 0; i < vals->count; i++) ++ { ++ ret = sc0132gs_write(sd, pregs->reg_num & 0xffff, (unsigned char)pregs->value); ++ //printk("[%s-%d]: 0x%02x, 0x%02x-----%p\n",__func__,__LINE__ ,pregs->reg_num, pregs->value,pregs);//dev_vdbg ++ if (ret < 0) ++ return ret; ++ pregs++; ++ } ++ return 0; ++} ++ ++/** ++ * sc0132gs_ioctl - IOCTL handler ++ * @sd: device object ++ * @cmd: Command ++ * @arg: arguments ++ */ ++static long sc0132gs_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ //struct sc031gs_priv *priv = to_sc031gs(client); ++ int ret = 0; ++ long powerstate = 0; ++ long illum_ctrl = 0; ++ TOMATO_I2C_regs *vals = (TOMATO_I2C_regs *)arg; ++ /*struct regval_list sc031gs_powerstatus_regs = {0x0100,0};*/ ++ ++ unsigned char val[2]; ++ uint16_t regVal; ++ switch (cmd) ++ { ++ case TOMATO_VIDIOC_IIC_WRITE: ++ ret = sc0132gs_write_I2cRegs(sd,vals); ++ break; ++ case TOMATO_VIDIOC_IIC_READ: ++ ret = sc0132gs_read_I2cRegs(sd,vals); ++ break; ++ case VIDIOC_S_SENSORPWRSTATE: ++ memcpy(&powerstate,arg,sizeof(long));//copy_from_usr ++ ret = sc0132gs_power(sd, powerstate?0:1); ++ break; ++ case VIDIOC_G_SENSORPWRSTATE: ++ //ret = ar0144_read(sd,AR0144_RESET_REG, val); ++ //regVal=(val[0]<<8)|val[1]; ++ //if(regVal&0x0004) ++ // powerstate = 0; ++ //else ++ powerstate = 0; ++ memcpy(arg,&powerstate,sizeof(long));//copy_to_usr ++ ret = 0; ++ break; ++#if defined(ILLUM_WORKAROUND)||defined(AIMER_WORKAROUND) ++ case VIDIOC_S_ILLUMCTRL: ++ memcpy(&illum_ctrl,arg,sizeof(long));//copy_from_usr ++ //Illum_value = illum_ctrl; ++ IlluminationSetControl(&illum_ctrl); ++ ret = 0; ++ break; ++#endif ++ default: ++ //dev_info(&client->dev, "no V4L2 CID: 0x%x \n", cmd); ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++int sc0132gs_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct sc0132gs_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops sc0132gs_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = sc0132gs_g_register, ++ .s_register = sc0132gs_s_register, ++#endif ++ .ioctl = sc0132gs_ioctl, ++}; ++ ++static const struct v4l2_subdev_video_ops sc0132gs_video_ops = { ++ .s_stream = sc0132gs_s_stream, ++ .g_frame_interval = sc0132gs_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops sc0132gs_pad_ops = { ++ //.enum_frame_interval = sc0132gs_enum_frame_interval, ++ //.num_frame_size = sc0132gs_enum_frame_size, ++ //.enum_mbus_code = sc0132gs_enum_mbus_code, ++ .set_fmt = sc0132gs_set_fmt, ++ .get_fmt = sc0132gs_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops sc0132gs_ops = { ++ .core = &sc0132gs_core_ops, ++ .video = &sc0132gs_video_ops, ++ .pad = &sc0132gs_pad_ops, ++}; ++ ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int sc0132gs_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct sc0132gs_info *info; ++ struct i2c_adapter *i2c_adap; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ int tmp; ++ ++ dev_info(&client->dev, "sc0132gs probing\n"); ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ printk("[%d] gpio=%d\n", __LINE__, gpio); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,vcc-en-gpio", 0, &flags); ++ printk("[%d] gpio=%d\n", __LINE__, gpio); ++ if(gpio_is_valid(gpio)) { ++ info->vcc_en.pin = gpio; ++ info->vcc_en.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ printk("[%d] gpio=%d\n", __LINE__, gpio); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ printk("[%d] gpio=%d\n", __LINE__, gpio); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &sc0132gs_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ sc0132gs_power(sd, 1); ++ msleep(10); ++ sc0132gs_reset(sd, 1); ++#if 1 ++ /* Make sure it's an sc0132gs */ ++ ret = sc0132gs_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an sc0132gs chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &sc0132gs_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &sc0132gs_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &sc0132gs_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &sc0132gs_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &sc0132gs_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &sc0132gs_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 261773, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &sc0132gs_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &sc0132gs_win_sizes[0]; ++ sc0132gs_write_array(sd, info->win->regs); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ #if defined(ILLUM_WORKAROUND)||defined(AIMER_WORKAROUND) ++ i2c_adap = i2c_get_adapter(2); ++ if (i2c_adap) ++ { ++ led_ic_client = i2c_new_device(i2c_adap, &aw9110b_info); ++ if (NULL == led_ic_client) { ++ printk(KERN_ERR "%s i2c_new_device is Err!\n", __func__); ++ return 0; ++ } ++ i2c_put_adapter(i2c_adap); ++ } ++ RequestIlluminationRelatedGpioPins(client); ++ #endif ++ ++ dev_info(&client->dev, "sc0132gs Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int sc0132gs_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct sc0132gs_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id sc0132gs_id[] = { ++ { "sc0132gs", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, sc0132gs_id); ++ ++static const struct of_device_id sc0132gs_of_match[] = { ++ {.compatible = "ovti,sc0132gs", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++ ++static struct i2c_driver sc0132gs_driver = { ++ .driver = { ++ .name = "sc0132gs", ++ .of_match_table = of_match_ptr(sc0132gs_of_match), ++ }, ++ .probe = sc0132gs_probe, ++ .remove = sc0132gs_remove, ++ .id_table = sc0132gs_id, ++}; ++ ++module_i2c_driver(sc0132gs_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision sc0132gs sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/sc031gs.c b/module_drivers/drivers/media/i2c/ingenic-isp/sc031gs.c +new file mode 100644 +index 000000000..035252766 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/sc031gs.c +@@ -0,0 +1,2226 @@ ++/* ++ * A V4L2 driver for OmniVision SC031GS cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define SC031GS_CHIP_ID_H (0x00) ++#define SC031GS_CHIP_ID_M (0x31) ++#define SC031GS_CHIP_ID_L (0x01) ++#define SC031GS_REG_END 0xffff ++#define SC031GS_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct sc031gs_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct sc031gs_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct sc031gs_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct sc031gs_win_size *win; ++ ++ struct sc031gs_gpio reset; ++ struct sc031gs_gpio vcc_en; ++ struct sc031gs_gpio ircutp; ++ struct sc031gs_gpio ircutn; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut sc031gs_again_lut[] = { ++ ++ {0x80, 0}, ++ {0x88, 5731}, ++ {0x90, 11136}, ++ {0x98, 16248}, ++ {0xa0, 21097}, ++ {0xa8, 25710}, ++ {0xb0, 30109}, ++ {0xb8, 34312}, ++ {0xc0, 38336}, ++ {0xc8, 42195}, ++ {0xd0, 45904}, ++ {0xd8, 49472}, ++ {0xe0, 52910}, ++ {0xe8, 56228}, ++ {0xf0, 59433}, ++ {0xf8, 62534}, ++ {0x178, 65536}, ++ {0x17c, 68445}, ++ {0x180, 71267}, ++ {0x184, 74008}, ++ {0x188, 76672}, ++ {0x18c, 79262}, ++ {0x190, 81784}, ++ {0x194, 84240}, ++ {0x198, 86633}, ++ {0x19c, 88968}, ++ {0x1a0, 91246}, ++ {0x1a4, 93471}, ++ {0x1a8, 95645}, ++ {0x1ac, 97770}, ++ {0x1b0, 99848}, ++ {0x1b4, 101881}, ++ {0x1b8, 103872}, ++ {0x1bc, 105821}, ++ {0x1c0, 107731}, ++ {0x1c4, 109604}, ++ {0x1c8, 111440}, ++ {0x1cc, 113241}, ++ {0x1d0, 115008}, ++ {0x1d4, 116743}, ++ {0x1d8, 118446}, ++ {0x1dc, 120120}, ++ {0x1e0, 121764}, ++ {0x1e4, 123380}, ++ {0x1e8, 124969}, ++ {0x1ec, 126532}, ++ {0x1f0, 128070}, ++ {0x1f4, 129583}, ++ {0x374, 131072}, ++ {0x376, 132537}, ++ {0x378, 133981}, ++ {0x37a, 135403}, ++ {0x37c, 136803}, ++ {0x37e, 138184}, ++ {0x380, 139544}, ++ {0x382, 140885}, ++ {0x384, 142208}, ++ {0x386, 143512}, ++ {0x388, 144798}, ++ {0x38a, 146067}, ++ {0x38c, 147320}, ++ {0x38e, 148556}, ++ {0x390, 149776}, ++ {0x392, 150980}, ++ {0x394, 152169}, ++ {0x396, 153344}, ++ {0x398, 154504}, ++ {0x39a, 155650}, ++ {0x39c, 156782}, ++ {0x39e, 157901}, ++ {0x3a0, 159007}, ++ {0x3a2, 160100}, ++ {0x3a4, 161181}, ++ {0x3a6, 162249}, ++ {0x3a8, 163306}, ++ {0x3aa, 164350}, ++ {0x3ac, 165384}, ++ {0x3ae, 166406}, ++ {0x3b0, 167417}, ++ {0x3b2, 168418}, ++ {0x3b4, 169408}, ++ {0x3b6, 170387}, ++ {0x3b8, 171357}, ++ {0x3ba, 172317}, ++ {0x3bc, 173267}, ++ {0x3be, 174208}, ++ {0x3c0, 175140}, ++ {0x3c2, 176062}, ++ {0x3c4, 176976}, ++ {0x3c6, 177880}, ++ {0x3c8, 178777}, ++ {0x3ca, 179664}, ++ {0x3cc, 180544}, ++ {0x3ce, 181415}, ++ {0x3d0, 182279}, ++ {0x3d2, 183134}, ++ {0x3d4, 183982}, ++ {0x3d6, 184823}, ++ {0x3d8, 185656}, ++ {0x3da, 186482}, ++ {0x3dc, 187300}, ++ {0x3de, 188112}, ++ {0x3e0, 188916}, ++ {0x3e2, 189714}, ++ {0x3e4, 190505}, ++ {0x3e6, 191290}, ++ {0x3e8, 192068}, ++ {0x3ea, 192840}, ++ {0x3ec, 193606}, ++ {0x3ee, 194365}, ++ {0x3f0, 195119}, ++ {0x3f2, 195866}, ++ {0x778, 196608}, ++ {0x779, 197343}, ++ {0x77a, 198073}, ++ {0x77b, 198798}, ++ {0x77c, 199517}, ++ {0x77d, 200230}, ++ {0x77e, 200939}, ++ {0x77f, 201642}, ++ {0x780, 202339}, ++ {0x781, 203032}, ++ {0x782, 203720}, ++ {0x783, 204402}, ++ {0x784, 205080}, ++ {0x785, 205753}, ++ {0x786, 206421}, ++ {0x787, 207085}, ++ {0x788, 207744}, ++ {0x789, 208398}, ++ {0x78a, 209048}, ++ {0x78b, 209693}, ++ {0x78c, 210334}, ++ {0x78d, 210971}, ++ {0x78e, 211603}, ++ {0x78f, 212232}, ++ {0x790, 212856}, ++ {0x791, 213476}, ++ {0x792, 214092}, ++ {0x793, 214704}, ++ {0x794, 215312}, ++ {0x795, 215916}, ++ {0x796, 216516}, ++ {0x797, 217113}, ++ {0x798, 217705}, ++ {0x799, 218294}, ++ {0x79a, 218880}, ++ {0x79b, 219462}, ++ {0x79c, 220040}, ++ {0x79d, 220615}, ++ {0x79e, 221186}, ++ {0x79f, 221754}, ++ {0x7a0, 222318}, ++ {0x7a1, 222880}, ++ {0x7a2, 223437}, ++ {0x7a3, 223992}, ++ {0x7a4, 224543}, ++ {0x7a5, 225091}, ++ {0x7a6, 225636}, ++ {0x7a7, 226178}, ++ {0x7a8, 226717}, ++ {0x7a9, 227253}, ++ {0x7aa, 227785}, ++ {0x7ab, 228315}, ++ {0x7ac, 228842}, ++ {0x7ad, 229365}, ++ {0x7ae, 229886}, ++ {0x7af, 230404}, ++ {0x7b0, 230920}, ++ {0x7b1, 231432}, ++ {0x7b2, 231942}, ++ {0x7b3, 232449}, ++ {0x7b4, 232953}, ++ {0x7b5, 233455}, ++ {0x7b6, 233954}, ++ {0x7b7, 234450}, ++ {0x7b8, 234944}, ++ {0x7b9, 235435}, ++ {0x7ba, 235923}, ++ {0x7bb, 236410}, ++ {0x7bc, 236893}, ++ {0x7bd, 237374}, ++ {0x7be, 237853}, ++ {0x7bf, 238329}, ++ {0x7c0, 238803}, ++ {0x7c1, 239275}, ++ {0x7c2, 239744}, ++ {0x7c3, 240211}, ++ {0x7c4, 240676}, ++ {0x7c5, 241138}, ++ {0x7c6, 241598}, ++ {0x7c7, 242056}, ++ {0x7c8, 242512}, ++ {0x7c9, 242965}, ++ {0x7ca, 243416}, ++ {0x7cb, 243865}, ++ {0x7cc, 244313}, ++ {0x7cd, 244757}, ++ {0x7ce, 245200}, ++ {0x7cf, 245641}, ++ {0x7d0, 246080}, ++ {0x7d1, 246517}, ++ {0x7d2, 246951}, ++ {0x7d3, 247384}, ++ {0x7d4, 247815}, ++ {0x7d5, 248243}, ++ {0x7d6, 248670}, ++ {0x7d7, 249095}, ++ {0x7d8, 249518}, ++ {0x7d9, 249939}, ++ {0x7da, 250359}, ++ {0x7db, 250776}, ++ {0x7dc, 251192}, ++ {0x7dd, 251606}, ++ {0x7de, 252018}, ++ {0x7df, 252428}, ++ {0x7e0, 252836}, ++ {0x7e1, 253243}, ++ {0x7e2, 253648}, ++ {0x7e3, 254051}, ++ {0x7e4, 254452}, ++ {0x7e5, 254852}, ++ {0x7e6, 255250}, ++ {0x7e7, 255647}, ++ {0x7e8, 256041}, ++ {0x7e9, 256435}, ++ {0x7ea, 256826}, ++ {0x7eb, 257216}, ++ {0x7ec, 257604}, ++ {0x7ed, 257991}, ++ {0x7ee, 258376}, ++ {0x7ef, 258760}, ++ {0x7f0, 259142}, ++ {0x7f1, 259522}, ++ {0x7f2, 259901}, ++ {0x7f3, 260279}, ++ {0x7f4, 260655}, ++ {0x7f5, 261029}, ++ {0x7f6, 261402}, ++ {0x7f7, 261773}, ++}; ++ ++static inline struct sc031gs_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct sc031gs_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct sc031gs_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list sc031gs_init_regs_640_480_60fps_mipi[] = { ++ //[ParaList] ++ {0x0103,0x01}, ++ {0x0100,0x00}, ++ ++ ++ //close mipi ++ //{0x3018,0x1f}, ++ //{0x3019,0xff}, ++ //{0x301c,0xb4}, ++ ++ ++ ++ //for mipi ++ {0x4603,0x00},//[0] fifo dvp read en ++ {0x3000,0x00},// ++ {0x3001,0x00},//pad dvp en ++ {0x303f,0x01},//[7] pll pclk dis ++ ++ {0x3018,0x13},//[7:5] lane num = [7:5] + 1 , [3:2] pd_mipi ++ ++ {0x3031,0x0a},//[3:0] mipi bit num ++ {0x3037,0x20},//[6:5] phy bit num 00~8bit 01~10bit 10~12bit ++ {0x301c,0x78},//[7] pclk_dvp_en [6] pclk_mipi_en [3] rst_dvp [2] rst_mipi ++ {0x3019,0xfe},//[3:0] lane_disable ++ ++ ++ {0x363c,0x08}, ++ {0x3630,0x82}, ++ ++ ++ {0x3638,0x0f}, //ramp offset ++ {0x3639,0x08}, //ramp_vref ++ {0x335b,0x80}, //pix_samp all high ++ //{0x3323,0x80}, //[7] srs all1 col fpn /with vln all 1 pix fpn ++ ++ {0x3636,0x25}, ++ {0x3640,0x02}, ++ {0x3306,0x38}, ++ ++ {0x3304,0x48}, ++ {0x3389,0x01}, //offset en ++ {0x3385,0x31}, //integ en ++ {0x330c,0x18}, //0109 ++ {0x3315,0x38}, ++ {0x3306,0x28}, ++ {0x3309,0x68}, ++ {0x3387,0x51}, //integ_en ++ {0x3306,0x48}, ++ ++ ++ //0101 ++ {0x3366,0x04}, //sb over count up ++ ++ {0x335f,0x80}, //avdd samp all high ++ {0x363a,0x00}, // psr ++ ++ {0x3622,0x01}, ++ {0x3633,0x62}, ++ ++ //bsi ++ {0x36f9,0x20}, ++ ++ //{0x3250,0xf0}, ++ {0x3637,0x80}, ++ {0x363d,0x04}, ++ {0x3e06,0x00}, ++ {0x363c,0x48}, ++ ++ ++ {0x320c,0x03}, ++ {0x320e,0x0e}, ++ {0x320f,0xa8}, ++ {0x3306,0x38}, ++ {0x330b,0xb6}, ++ ++ ++ //{0x3621,0x90}, ++ {0x36f9,0x24}, ++ ++ ++ //0104 ++ {0x363b,0x4a}, ++ {0x3366,0x02}, ++ ++ //precharge ++ {0x3316,0x78}, ++ {0x3344,0x74}, ++ {0x3335,0x74}, ++ {0x332f,0x70}, ++ {0x332d,0x6c}, ++ {0x3329,0x6c}, ++ ++ //0105 ++ //{0x3250,0xff}, ++ ++ //1.24 ++ {0x363c,0x08}, ++ {0x3630,0x81}, ++ ++ //{0x3314,0x28}, //for offset cancel ++ //{0x3317,0x23}, ++ //{0x3366,0x04}, ++ ++ {0x3366,0x06}, ++ ++ {0x3314,0x3a}, ++ {0x3317,0x28}, ++ ++ //0130 ++ {0x3622,0x05}, //blksun ++ {0x363d,0x00}, ++ {0x3637,0x86}, ++ ++ {0x3e01,0x62}, ++ {0x3633,0x52}, ++ {0x3630,0x86}, ++ {0x3306,0x4c}, ++ {0x330b,0xa0}, ++ ++ //0131 ++ {0x3631,0x48}, ++ ++ //0201 ++ {0x33b1,0x03}, // chis position ++ {0x33b2,0x06}, //[3:2]=chis_length [1:0] +1=trans_length ++ {0x320c,0x02}, ++ {0x320e,0x02}, ++ {0x320f,0x0d}, ++ {0x3e01,0x20}, ++ {0x3e02,0x20}, ++ ++ //precharge ++ {0x3316,0x48}, ++ {0x3344,0x44}, ++ {0x3335,0x44}, ++ {0x332f,0x40}, ++ {0x332d,0x3c}, ++ {0x3329,0x3c}, ++ ++ {0x3310,0x10}, //tx width ++ ++ {0x3637,0x87}, ++ {0x363e,0xf8}, ++ ++ ++ //power save mode 0201B ++ ++ {0x3254,0x02}, ++ {0x3255,0x07}, //{3204,3205}={3260,3261}+1 ++ ++ {0x3252,0x02}, ++ {0x3253,0xa6}, // {3252,3253}={320e,320f}-5 ++ ++ {0x3250,0xc0}, //[5:4]sa1 [3:2] opbuf [1:0] ramp 0724 ++ {0x3251,0x02}, //[1] opbuf [0] ramp ++ ++ //0322 ++ {0x330f,0x50}, ++ {0x3630,0x46}, ++ ++ //0324 ++ {0x3621,0xa2}, //aa? ++ ++ //0329 ++ {0x3621,0xa0}, ++ {0x4500,0x59}, //fifo delay ++ ++ //0404 ++ {0x3637,0x88}, //blksun margin ++ {0x3908,0x81}, //for digital gain ++ ++ {0x3640,0x00}, ++ {0x3641,0x02}, ++ ++ {0x363c,0x05}, //only for vt++ com1 dvp sample ++ {0x363b,0x4c}, ++ ++ //72MPCLK 183fps ++ ++ {0x36e9,0x40}, ++ {0x36ea,0x36}, ++ {0x36ed,0x13}, ++ ++ {0x36f9,0x04}, ++ {0x36fa,0x38}, ++ {0x330b,0x80}, ++ ++ ++ //{0x3304,0x40}, ++ //{0x3389,0x01}, //offset en ++ //{0x3385,0x31}, //integ en ++ //{0x330c,0x10}, //0109 ++ //{0x3315,0x30}, ++ //{0x3309,0x60}, ++ //{0x3387,0x51}, //integ_en ++ //{0x3306,0x50}, ++ ++ {0x3640,0x00}, ++ {0x3641,0x01}, ++ ++ //0502 ++ {0x3d08,0x00}, ++ {0x3306,0x48}, ++ {0x3621,0xa4}, ++ {0x300f,0x0f}, ++ ++ ++ //0612 ++ {0x4837, 0x1b}, //0x4837=2000/PCLK ++ {0x4809, 0x01}, //clock lane lp initialized to 11 ++ ++ //0622 24M input 72MPCLK 120fps ++ {0x363b,0x48}, ++ {0x363c,0x06}, ++ {0x36e9,0x00}, ++ {0x36ea,0x3b}, ++ {0x36eb,0x0e}, ++ {0x36ec,0x0e}, ++ {0x36ed,0x33}, ++ {0x36f9,0x00}, ++ {0x36fa,0x3a}, ++ {0x36fc,0x01}, ++#if 0 ++ {0x320c,0x03}, //for high temp more margin ++ {0x320d,0x6e}, ++ {0x320e,0x02}, ++ {0x320f,0xab}, //120fps ++#else ++ {0x320c,0x04}, //for high temp more margin ++ {0x320d,0x8e}, ++ {0x320e,0x03}, ++ {0x320f,0xeb}, //60fps ++#endif ++ ++ ++#if 0 ++ {0x3208,0x00}, ++ {0x3209,0x80}, ++ {0x320a,0x00}, ++ {0x320b,0x60}, //128*96 ++#endif ++ ++ {0x330b,0x80}, ++ {0x330f,0x50}, ++ ++ {0x3637,0x89}, //blksun margin ++ ++ {0x3641,0x01}, //0x01 for 2.8V dovdd 0x02 for 1.8V DOVDD ++ ++ //0625 for 70C 4ms 16X gain ++ {0x4501,0xc4}, ++ {0x5011,0x01}, ++ {0x3908,0x21}, ++ {0x3e01,0x01}, ++ {0x3e02,0xa0}, ++ {0x3306,0x38}, ++ {0x330b,0xe0}, //high temp [a0,f0] ++ {0x330f,0x20}, ++ ++ //0626 ++ {0x3d08,0x01}, ++ ++ //0724 ++ {0x5011,0x00}, ++ {0x3e06,0x0c}, ++ {0x3908,0x91}, ++ ++ //{0x3314,0x3a}, ++ //{0x3317,0x20}, ++ {0x3314,0x1e}, ++ {0x3317,0x10}, //gain ++ ++ //st light ++ {0x3635,0x18}, ++ ++ // reduce minimum precharge ++ {0x3316,0x40}, ++ {0x3344,0x3c}, ++ {0x3335,0x3c}, ++ {0x332f,0x38}, ++ {0x332d,0x34}, ++ {0x3329,0x34}, ++ //20180829 ++ {0x3624,0x47}, ++ ++ //20181101 ++ {0x3220,0x10},//[1:0] vflip blc���� ++ ++ //20181106 ++ {0x3635,0x18}, ++ ++ {0x0100,0x01}, //72M sysclk 576M cntclk ++ ++ ++ ++ {0x4418,0x08}, ++ {0x4419,0x8e}, //20190222 cover avdd 2.6V-3.0V ++ ++// {0x0100,0x01}, //72M sysclk 576M cntclk ++ ++ ++ /* ++ //[gain<2] ++ {0x3314,0x1e},//0222 ++ {0x3317,0x10}, ++ //[4>gain>=2] ++ {0x3314,0x4f}, //0222 ++ {0x3317,0x0f}, //0625 ++ //[gain>=4] ++ {0x3314,0x4f}, //0222 ++ {0x3317,0x0f}, //0625 ++ ++ //[half count_clk test] ++ {0x36f9,0x20}, ++ {0x3304,0x40}, ++ {0x3389,0x01}, //offset en ++ {0x3385,0x31}, //integ en ++ {0x330c,0x18}, //0109 ++ {0x3315,0x38}, ++ {0x3306,0x28}, ++ {0x3309,0x60}, ++ {0x3387,0x51}, //integ_en ++ {0x3306,0x48}, ++ ++ //[noise_test] ++ {0x3324,0x10}, ++ {0x3907,0x04}, ++ {0x3e06,0x03}, ++ ++ //[dark current test] ++ {0x3e01,0xea}, ++ {0x3e02,0x10}, ++ {0x3e06,0x03}, ++ {0x3902,0x05}, ++ {0x3909,0x0c}, ++ {0x3e08,0x1f}, ++ {0x3622,0x01}, ++ ++ //[pos offset] ++ {0x3314,0x34}, ++ {0x3317,0x29}, ++ ++ //[precharge test] ++ {0x3e09,0x1f}, ++ {0x3e08,0x1f}, ++ {0x3e06,0x03}, ++ {0x3902,0x05}, ++ {0x3909,0x0d}, ++ {0x390a,0x80}, ++ ++ ++ //[pls test] //AF=2.6 ++ {0x4419,0x8e}, ++ {0x3630,0x66}, ++ {0x3902,0x05}, ++ {0x3909,0x0f}, ++ {0x390a,0x80}, ++ {0x3314,0x4a}, ++ {0x3317,0x0e}, ++ {0x320e,0x10}, ++ //{0x3907,0x04}, ++ {0x3e01,0x00}, ++ {0x3e02,0x20}, ++ {0x320c,0x12}, ++ {0x320d,0xee}, ++ */ ++// {0x4501,0xac}, ++// {0x3902,0x05}, ++// {0x3e06,0x03}, ++ {SC031GS_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc031gs_init_regs_320_240_60fps_mipi[] = { ++ //[ParaList] ++ {0x0103,0x01}, ++ {0x0100,0x00}, ++ ++ ++ //close mipi ++ //{0x3018,0x1f}, ++ //{0x3019,0xff}, ++ //{0x301c,0xb4}, ++ ++ ++ ++ //for mipi ++ {0x4603,0x00},//[0] fifo dvp read en ++ {0x3000,0x00},// ++ {0x3001,0x00},//pad dvp en ++ {0x303f,0x01},//[7] pll pclk dis ++ ++ {0x3018,0x13},//[7:5] lane num = [7:5] + 1 , [3:2] pd_mipi ++ ++ {0x3031,0x0a},//[3:0] mipi bit num ++ {0x3037,0x20},//[6:5] phy bit num 00~8bit 01~10bit 10~12bit ++ {0x301c,0x78},//[7] pclk_dvp_en [6] pclk_mipi_en [3] rst_dvp [2] rst_mipi ++ {0x3019,0xfe},//[3:0] lane_disable ++ ++ ++ {0x363c,0x08}, ++ {0x3630,0x82}, ++ ++ ++ {0x3638,0x0f}, //ramp offset ++ {0x3639,0x08}, //ramp_vref ++ {0x335b,0x80}, //pix_samp all high ++ //{0x3323,0x80}, //[7] srs all1 col fpn /with vln all 1 pix fpn ++ ++ {0x3636,0x25}, ++ {0x3640,0x02}, ++ {0x3306,0x38}, ++ ++ {0x3304,0x48}, ++ {0x3389,0x01}, //offset en ++ {0x3385,0x31}, //integ en ++ {0x330c,0x18}, //0109 ++ {0x3315,0x38}, ++ {0x3306,0x28}, ++ {0x3309,0x68}, ++ {0x3387,0x51}, //integ_en ++ {0x3306,0x48}, ++ ++ ++ //0101 ++ {0x3366,0x04}, //sb over count up ++ ++ {0x335f,0x80}, //avdd samp all high ++ {0x363a,0x00}, // psr ++ ++ {0x3622,0x01}, ++ {0x3633,0x62}, ++ ++ //bsi ++ {0x36f9,0x20}, ++ ++ //{0x3250,0xf0}, ++ {0x3637,0x80}, ++ {0x363d,0x04}, ++ {0x3e06,0x00}, ++ {0x363c,0x48}, ++ ++ ++ {0x320c,0x03}, ++ {0x320e,0x0e}, ++ {0x320f,0xa8}, ++ {0x3306,0x38}, ++ {0x330b,0xb6}, ++ ++ ++ //{0x3621,0x90}, ++ {0x36f9,0x24}, ++ ++ ++ //0104 ++ {0x363b,0x4a}, ++ {0x3366,0x02}, ++ ++ //precharge ++ {0x3316,0x78}, ++ {0x3344,0x74}, ++ {0x3335,0x74}, ++ {0x332f,0x70}, ++ {0x332d,0x6c}, ++ {0x3329,0x6c}, ++ ++ //0105 ++ //{0x3250,0xff}, ++ ++ //1.24 ++ {0x363c,0x08}, ++ {0x3630,0x81}, ++ ++ //{0x3314,0x28}, //for offset cancel ++ //{0x3317,0x23}, ++ //{0x3366,0x04}, ++ ++ {0x3366,0x06}, ++ ++ {0x3314,0x3a}, ++ {0x3317,0x28}, ++ ++ //0130 ++ {0x3622,0x05}, //blksun ++ {0x363d,0x00}, ++ {0x3637,0x86}, ++ ++ {0x3e01,0x62}, ++ {0x3633,0x52}, ++ {0x3630,0x86}, ++ {0x3306,0x4c}, ++ {0x330b,0xa0}, ++ ++ //0131 ++ {0x3631,0x48}, ++ ++ //0201 ++ {0x33b1,0x03}, // chis position ++ {0x33b2,0x06}, //[3:2]=chis_length [1:0] +1=trans_length ++ {0x320c,0x02}, ++ {0x320e,0x02}, ++ {0x320f,0x0d}, ++ {0x3e01,0x20}, ++ {0x3e02,0x20}, ++ ++ //precharge ++ {0x3316,0x48}, ++ {0x3344,0x44}, ++ {0x3335,0x44}, ++ {0x332f,0x40}, ++ {0x332d,0x3c}, ++ {0x3329,0x3c}, ++ ++ {0x3310,0x10}, //tx width ++ ++ {0x3637,0x87}, ++ {0x363e,0xf8}, ++ ++ ++ //power save mode 0201B ++ ++ {0x3254,0x02}, ++ {0x3255,0x07}, //{3204,3205}={3260,3261}+1 ++ ++ {0x3252,0x02}, ++ {0x3253,0xa6}, // {3252,3253}={320e,320f}-5 ++ ++ {0x3250,0xc0}, //[5:4]sa1 [3:2] opbuf [1:0] ramp 0724 ++ {0x3251,0x02}, //[1] opbuf [0] ramp ++ ++ //0322 ++ {0x330f,0x50}, ++ {0x3630,0x46}, ++ ++ //0324 ++ {0x3621,0xa2}, //aa? ++ ++ //0329 ++ {0x3621,0xa0}, ++ {0x4500,0x59}, //fifo delay ++ ++ //0404 ++ {0x3637,0x88}, //blksun margin ++ {0x3908,0x81}, //for digital gain ++ ++ {0x3640,0x00}, ++ {0x3641,0x02}, ++ ++ {0x363c,0x05}, //only for vt++ com1 dvp sample ++ {0x363b,0x4c}, ++ ++ //72MPCLK 183fps ++ ++ {0x36e9,0x40}, ++ {0x36ea,0x36}, ++ {0x36ed,0x13}, ++ ++ {0x36f9,0x04}, ++ {0x36fa,0x38}, ++ {0x330b,0x80}, ++ ++ ++ //{0x3304,0x40}, ++ //{0x3389,0x01}, //offset en ++ //{0x3385,0x31}, //integ en ++ //{0x330c,0x10}, //0109 ++ //{0x3315,0x30}, ++ //{0x3309,0x60}, ++ //{0x3387,0x51}, //integ_en ++ //{0x3306,0x50}, ++ ++ {0x3640,0x00}, ++ {0x3641,0x01}, ++ ++ //0502 ++ {0x3d08,0x00}, ++ {0x3306,0x48}, ++ {0x3621,0xa4}, ++ {0x300f,0x0f}, ++ ++ ++ //0612 ++ {0x4837, 0x1b}, //0x4837=2000/PCLK ++ {0x4809, 0x01}, //clock lane lp initialized to 11 ++ ++ //0622 24M input 72MPCLK 120fps ++ {0x363b,0x48}, ++ {0x363c,0x06}, ++ {0x36e9,0x00}, ++ {0x36ea,0x3b}, ++ {0x36eb,0x0e}, ++ {0x36ec,0x0e}, ++ {0x36ed,0x33}, ++ {0x36f9,0x00}, ++ {0x36fa,0x3a}, ++ {0x36fc,0x01}, ++#if 0 ++ {0x320c,0x03}, //for high temp more margin ++ {0x320d,0x6e}, ++ {0x320e,0x02}, ++ {0x320f,0xab}, //120fps ++#else ++ {0x320c,0x04}, //for high temp more margin ++ {0x320d,0x8e}, ++ {0x320e,0x03}, ++ {0x320f,0xeb}, //60fps ++#endif ++ ++ ++#if 1 ++ {0x3208,0x01}, ++ {0x3209,0x40}, ++ {0x320a,0x00}, ++ {0x320b,0xf0}, //320*240 ++ ++ {0x3210, 0x00}, ++ {0x3211, 0xA0}, ++ {0x3212, 0x00}, ++ {0x3213, 0x78}, ++#endif ++ ++ {0x330b,0x80}, ++ {0x330f,0x50}, ++ ++ {0x3637,0x89}, //blksun margin ++ ++ {0x3641,0x01}, //0x01 for 2.8V dovdd 0x02 for 1.8V DOVDD ++ ++ //0625 for 70C 4ms 16X gain ++ {0x4501,0xc4}, ++ {0x5011,0x01}, ++ {0x3908,0x21}, ++ {0x3e01,0x0a}, ++ {0x3e02,0x80}, //expo time ++ {0x3306,0x38}, ++ {0x330b,0xe0}, //high temp [a0,f0] ++ {0x330f,0x20}, ++ ++ //0626 ++ {0x3d08,0x01}, ++ ++ //0724 ++ {0x5011,0x00}, ++ {0x3e06,0x0c}, ++ {0x3908,0x91}, ++ ++ //{0x3314,0x3a}, ++ //{0x3317,0x20}, ++ {0x3314,0x1e}, ++ {0x3317,0x10}, //gain ++ ++ //st light ++ {0x3635,0x18}, ++ ++ // reduce minimum precharge ++ {0x3316,0x40}, ++ {0x3344,0x3c}, ++ {0x3335,0x3c}, ++ {0x332f,0x38}, ++ {0x332d,0x34}, ++ {0x3329,0x34}, ++ //20180829 ++ {0x3624,0x47}, ++ ++ //20181101 ++ {0x3220,0x10},//[1:0] vflip blc���� ++ ++ //20181106 ++ {0x3635,0x18}, ++ ++ {0x0100,0x01}, //72M sysclk 576M cntclk ++ ++ ++ ++ {0x4418,0x08}, ++ {0x4419,0x8e}, //20190222 cover avdd 2.6V-3.0V ++ ++// {0x0100,0x01}, //72M sysclk 576M cntclk ++ ++ ++ /* ++ //[gain<2] ++ {0x3314,0x1e},//0222 ++ {0x3317,0x10}, ++ //[4>gain>=2] ++ {0x3314,0x4f}, //0222 ++ {0x3317,0x0f}, //0625 ++ //[gain>=4] ++ {0x3314,0x4f}, //0222 ++ {0x3317,0x0f}, //0625 ++ ++ //[half count_clk test] ++ {0x36f9,0x20}, ++ {0x3304,0x40}, ++ {0x3389,0x01}, //offset en ++ {0x3385,0x31}, //integ en ++ {0x330c,0x18}, //0109 ++ {0x3315,0x38}, ++ {0x3306,0x28}, ++ {0x3309,0x60}, ++ {0x3387,0x51}, //integ_en ++ {0x3306,0x48}, ++ ++ //[noise_test] ++ {0x3324,0x10}, ++ {0x3907,0x04}, ++ {0x3e06,0x03}, ++ ++ //[dark current test] ++ {0x3e01,0xea}, ++ {0x3e02,0x10}, ++ {0x3e06,0x03}, ++ {0x3902,0x05}, ++ {0x3909,0x0c}, ++ {0x3e08,0x1f}, ++ {0x3622,0x01}, ++ ++ //[pos offset] ++ {0x3314,0x34}, ++ {0x3317,0x29}, ++ ++ //[precharge test] ++ {0x3e09,0x1f}, ++ {0x3e08,0x1f}, ++ {0x3e06,0x03}, ++ {0x3902,0x05}, ++ {0x3909,0x0d}, ++ {0x390a,0x80}, ++ ++ ++ //[pls test] //AF=2.6 ++ {0x4419,0x8e}, ++ {0x3630,0x66}, ++ {0x3902,0x05}, ++ {0x3909,0x0f}, ++ {0x390a,0x80}, ++ {0x3314,0x4a}, ++ {0x3317,0x0e}, ++ {0x320e,0x10}, ++ //{0x3907,0x04}, ++ {0x3e01,0x00}, ++ {0x3e02,0x20}, ++ {0x320c,0x12}, ++ {0x320d,0xee}, ++ */ ++// {0x4501,0xac}, ++// {0x3902,0x05}, ++// {0x3e06,0x03}, ++ {SC031GS_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc031gs_init_regs_128_96_60fps_mipi[] = { ++ //[ParaList] ++ {0x0103,0x01}, ++ {0x0100,0x00}, ++ ++ ++ //close mipi ++ //{0x3018,0x1f}, ++ //{0x3019,0xff}, ++ //{0x301c,0xb4}, ++ ++ ++ ++ //for mipi ++ {0x4603,0x00},//[0] fifo dvp read en ++ {0x3000,0x00},// ++ {0x3001,0x00},//pad dvp en ++ {0x303f,0x01},//[7] pll pclk dis ++ ++ {0x3018,0x13},//[7:5] lane num = [7:5] + 1 , [3:2] pd_mipi ++ ++ {0x3031,0x0a},//[3:0] mipi bit num ++ {0x3037,0x20},//[6:5] phy bit num 00~8bit 01~10bit 10~12bit ++ {0x301c,0x78},//[7] pclk_dvp_en [6] pclk_mipi_en [3] rst_dvp [2] rst_mipi ++ {0x3019,0xfe},//[3:0] lane_disable ++ ++ ++ {0x363c,0x08}, ++ {0x3630,0x82}, ++ ++ ++ {0x3638,0x0f}, //ramp offset ++ {0x3639,0x08}, //ramp_vref ++ {0x335b,0x80}, //pix_samp all high ++ //{0x3323,0x80}, //[7] srs all1 col fpn /with vln all 1 pix fpn ++ ++ {0x3636,0x25}, ++ {0x3640,0x02}, ++ {0x3306,0x38}, ++ ++ {0x3304,0x48}, ++ {0x3389,0x01}, //offset en ++ {0x3385,0x31}, //integ en ++ {0x330c,0x18}, //0109 ++ {0x3315,0x38}, ++ {0x3306,0x28}, ++ {0x3309,0x68}, ++ {0x3387,0x51}, //integ_en ++ {0x3306,0x48}, ++ ++ ++ //0101 ++ {0x3366,0x04}, //sb over count up ++ ++ {0x335f,0x80}, //avdd samp all high ++ {0x363a,0x00}, // psr ++ ++ {0x3622,0x01}, ++ {0x3633,0x62}, ++ ++ //bsi ++ {0x36f9,0x20}, ++ ++ //{0x3250,0xf0}, ++ {0x3637,0x80}, ++ {0x363d,0x04}, ++ {0x3e06,0x00}, ++ {0x363c,0x48}, ++ ++ ++ {0x320c,0x03}, ++ {0x320e,0x0e}, ++ {0x320f,0xa8}, ++ {0x3306,0x38}, ++ {0x330b,0xb6}, ++ ++ ++ //{0x3621,0x90}, ++ {0x36f9,0x24}, ++ ++ ++ //0104 ++ {0x363b,0x4a}, ++ {0x3366,0x02}, ++ ++ //precharge ++ {0x3316,0x78}, ++ {0x3344,0x74}, ++ {0x3335,0x74}, ++ {0x332f,0x70}, ++ {0x332d,0x6c}, ++ {0x3329,0x6c}, ++ ++ //0105 ++ //{0x3250,0xff}, ++ ++ //1.24 ++ {0x363c,0x08}, ++ {0x3630,0x81}, ++ ++ //{0x3314,0x28}, //for offset cancel ++ //{0x3317,0x23}, ++ //{0x3366,0x04}, ++ ++ {0x3366,0x06}, ++ ++ {0x3314,0x3a}, ++ {0x3317,0x28}, ++ ++ //0130 ++ {0x3622,0x05}, //blksun ++ {0x363d,0x00}, ++ {0x3637,0x86}, ++ ++ {0x3e01,0x62}, ++ {0x3633,0x52}, ++ {0x3630,0x86}, ++ {0x3306,0x4c}, ++ {0x330b,0xa0}, ++ ++ //0131 ++ {0x3631,0x48}, ++ ++ //0201 ++ {0x33b1,0x03}, // chis position ++ {0x33b2,0x06}, //[3:2]=chis_length [1:0] +1=trans_length ++ {0x320c,0x02}, ++ {0x320e,0x02}, ++ {0x320f,0x0d}, ++ {0x3e01,0x20}, ++ {0x3e02,0x20}, ++ ++ //precharge ++ {0x3316,0x48}, ++ {0x3344,0x44}, ++ {0x3335,0x44}, ++ {0x332f,0x40}, ++ {0x332d,0x3c}, ++ {0x3329,0x3c}, ++ ++ {0x3310,0x10}, //tx width ++ ++ {0x3637,0x87}, ++ {0x363e,0xf8}, ++ ++ ++ //power save mode 0201B ++ ++ {0x3254,0x02}, ++ {0x3255,0x07}, //{3204,3205}={3260,3261}+1 ++ ++ {0x3252,0x02}, ++ {0x3253,0xa6}, // {3252,3253}={320e,320f}-5 ++ ++ {0x3250,0xc0}, //[5:4]sa1 [3:2] opbuf [1:0] ramp 0724 ++ {0x3251,0x02}, //[1] opbuf [0] ramp ++ ++ //0322 ++ {0x330f,0x50}, ++ {0x3630,0x46}, ++ ++ //0324 ++ {0x3621,0xa2}, //aa? ++ ++ //0329 ++ {0x3621,0xa0}, ++ {0x4500,0x59}, //fifo delay ++ ++ //0404 ++ {0x3637,0x88}, //blksun margin ++ {0x3908,0x81}, //for digital gain ++ ++ {0x3640,0x00}, ++ {0x3641,0x02}, ++ ++ {0x363c,0x05}, //only for vt++ com1 dvp sample ++ {0x363b,0x4c}, ++ ++ //72MPCLK 183fps ++ ++ {0x36e9,0x40}, ++ {0x36ea,0x36}, ++ {0x36ed,0x13}, ++ ++ {0x36f9,0x04}, ++ {0x36fa,0x38}, ++ {0x330b,0x80}, ++ ++ ++ //{0x3304,0x40}, ++ //{0x3389,0x01}, //offset en ++ //{0x3385,0x31}, //integ en ++ //{0x330c,0x10}, //0109 ++ //{0x3315,0x30}, ++ //{0x3309,0x60}, ++ //{0x3387,0x51}, //integ_en ++ //{0x3306,0x50}, ++ ++ {0x3640,0x00}, ++ {0x3641,0x01}, ++ ++ //0502 ++ {0x3d08,0x00}, ++ {0x3306,0x48}, ++ {0x3621,0xa4}, ++ {0x300f,0x0f}, ++ ++ ++ //0612 ++ {0x4837, 0x1b}, //0x4837=2000/PCLK ++ {0x4809, 0x01}, //clock lane lp initialized to 11 ++ ++ //0622 24M input 72MPCLK 120fps ++ {0x363b,0x48}, ++ {0x363c,0x06}, ++ {0x36e9,0x00}, ++ {0x36ea,0x3b}, ++ {0x36eb,0x0e}, ++ {0x36ec,0x0e}, ++ {0x36ed,0x33}, ++ {0x36f9,0x00}, ++ {0x36fa,0x3a}, ++ {0x36fc,0x01}, ++#if 0 ++ {0x320c,0x03}, //for high temp more margin ++ {0x320d,0x6e}, ++ {0x320e,0x02}, ++ {0x320f,0xab}, //120fps ++#else ++ {0x320c,0x04}, //for high temp more margin ++ {0x320d,0x8e}, ++ {0x320e,0x03}, ++ {0x320f,0xeb}, //60fps ++#endif ++ ++ ++#if 1 ++ {0x3208,0x00}, ++ {0x3209,0x80}, ++ {0x320a,0x00}, ++ {0x320b,0x60}, //128*96 ++#endif ++ ++ {0x330b,0x80}, ++ {0x330f,0x50}, ++ ++ {0x3637,0x89}, //blksun margin ++ ++ {0x3641,0x01}, //0x01 for 2.8V dovdd 0x02 for 1.8V DOVDD ++ ++ //0625 for 70C 4ms 16X gain ++ {0x4501,0xc4}, ++ {0x5011,0x01}, ++ {0x3908,0x21}, ++ {0x3e01,0x0a}, ++ {0x3e02,0x80}, ++ {0x3306,0x38}, ++ {0x330b,0xe0}, //high temp [a0,f0] ++ {0x330f,0x20}, ++ ++ //0626 ++ {0x3d08,0x01}, ++ ++ //0724 ++ {0x5011,0x00}, ++ {0x3e06,0x0c}, ++ {0x3908,0x91}, ++ ++ //{0x3314,0x3a}, ++ //{0x3317,0x20}, ++ {0x3314,0x1e}, ++ {0x3317,0x10}, //gain ++ ++ //st light ++ {0x3635,0x18}, ++ ++ // reduce minimum precharge ++ {0x3316,0x40}, ++ {0x3344,0x3c}, ++ {0x3335,0x3c}, ++ {0x332f,0x38}, ++ {0x332d,0x34}, ++ {0x3329,0x34}, ++ //20180829 ++ {0x3624,0x47}, ++ ++ //20181101 ++ {0x3220,0x10},//[1:0] vflip blc���� ++ ++ //20181106 ++ {0x3635,0x18}, ++ ++ {0x0100,0x01}, //72M sysclk 576M cntclk ++ ++ ++ ++ {0x4418,0x08}, ++ {0x4419,0x8e}, //20190222 cover avdd 2.6V-3.0V ++ ++// {0x0100,0x01}, //72M sysclk 576M cntclk ++ ++ ++ /* ++ //[gain<2] ++ {0x3314,0x1e},//0222 ++ {0x3317,0x10}, ++ //[4>gain>=2] ++ {0x3314,0x4f}, //0222 ++ {0x3317,0x0f}, //0625 ++ //[gain>=4] ++ {0x3314,0x4f}, //0222 ++ {0x3317,0x0f}, //0625 ++ ++ //[half count_clk test] ++ {0x36f9,0x20}, ++ {0x3304,0x40}, ++ {0x3389,0x01}, //offset en ++ {0x3385,0x31}, //integ en ++ {0x330c,0x18}, //0109 ++ {0x3315,0x38}, ++ {0x3306,0x28}, ++ {0x3309,0x60}, ++ {0x3387,0x51}, //integ_en ++ {0x3306,0x48}, ++ ++ //[noise_test] ++ {0x3324,0x10}, ++ {0x3907,0x04}, ++ {0x3e06,0x03}, ++ ++ //[dark current test] ++ {0x3e01,0xea}, ++ {0x3e02,0x10}, ++ {0x3e06,0x03}, ++ {0x3902,0x05}, ++ {0x3909,0x0c}, ++ {0x3e08,0x1f}, ++ {0x3622,0x01}, ++ ++ //[pos offset] ++ {0x3314,0x34}, ++ {0x3317,0x29}, ++ ++ //[precharge test] ++ {0x3e09,0x1f}, ++ {0x3e08,0x1f}, ++ {0x3e06,0x03}, ++ {0x3902,0x05}, ++ {0x3909,0x0d}, ++ {0x390a,0x80}, ++ ++ ++ //[pls test] //AF=2.6 ++ {0x4419,0x8e}, ++ {0x3630,0x66}, ++ {0x3902,0x05}, ++ {0x3909,0x0f}, ++ {0x390a,0x80}, ++ {0x3314,0x4a}, ++ {0x3317,0x0e}, ++ {0x320e,0x10}, ++ //{0x3907,0x04}, ++ {0x3e01,0x00}, ++ {0x3e02,0x20}, ++ {0x320c,0x12}, ++ {0x320d,0xee}, ++ */ ++// {0x4501,0xac}, ++// {0x3902,0x05}, ++// {0x3e06,0x03}, ++ {SC031GS_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++ ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list sc031gs_stream_on_mipi[] = { ++ {0x0100, 0x01}, ++ {SC031GS_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc031gs_stream_off_mipi[] = { ++ //close mipi ++// {0x3018,0x1f}, ++// {0x3019,0xff}, ++// {0x301c,0xb4}, ++ {SC031GS_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int sc031gs_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct sc031gs_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int sc031gs_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct sc031gs_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int sc031gs_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != SC031GS_REG_END) { ++ if (vals->reg_num == SC031GS_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc031gs_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int sc031gs_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != SC031GS_REG_END) { ++ if (vals->reg_num == SC031GS_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc031gs_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int sc031gs_power(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc031gs_info *info = to_state(sd); ++ ++ if(val){ ++ *(volatile unsigned int *)0xb0010230 &= ~(1 << 28); ++ *(volatile unsigned int *)0xb0010240 |= (1 << 28); ++// gpio_direction_output(info->reset.pin, info->reset.active_level); ++ }else{ ++ *(volatile unsigned int *)0xb0010230 |= (1 << 28); ++ *(volatile unsigned int *)0xb0010240 &= ~(1 << 28); ++// gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ } ++ return 0; ++} ++ ++static int sc031gs_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc031gs_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++static int sc031gs_ircut(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc031gs_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ } else { ++ gpio_direction_output(info->ircutp.pin, !info->ircutp.active_level); ++ gpio_direction_output(info->ircutn.pin, !info->ircutn.active_level); ++ msleep(10); ++ gpio_direction_output(info->ircutp.pin, info->ircutp.active_level); ++ } ++ return 0; ++} ++ ++static int sc031gs_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc031gs_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = sc031gs_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int sc031gs_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v = 0; ++ int ret; ++ ++ ret = sc031gs_read(sd, 0x3107, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC031GS_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = sc031gs_read(sd, 0x3108, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC031GS_CHIP_ID_M) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = sc031gs_read(sd, 0x3109, &v); ++ pr_info("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC031GS_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ return 0; ++} ++ ++ ++static struct sc031gs_win_size sc031gs_win_sizes[] = { ++ { ++ .sensor_info.mipi_cfg.twidth = 640, ++ .sensor_info.mipi_cfg.theight = 480, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 60 << 16 | 1, ++ ++ .width = 640, ++ .height = 480, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc031gs_init_regs_640_480_60fps_mipi, ++ }, ++ { ++ .sensor_info.mipi_cfg.twidth = 320, ++ .sensor_info.mipi_cfg.theight = 240, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 60 << 16 | 1, ++ ++ .width = 320, ++ .height = 240, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc031gs_init_regs_320_240_60fps_mipi, ++ }, ++ { ++ .sensor_info.mipi_cfg.twidth = 128, ++ .sensor_info.mipi_cfg.theight = 96, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .sensor_info.fps = 60 << 16 | 1, ++ ++ .width = 128, ++ .height = 96, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc031gs_init_regs_128_96_60fps_mipi, ++ }, ++}; ++ ++static int sc031gs_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_SC031GS_FMTS) ++ return -EINVAL; ++ ++ code->code = sc031gs_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int sc031gs_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc031gs_format_struct *ovfmt; ++ struct sc031gs_win_size *wsize; ++ struct sc031gs_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int sc031gs_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc031gs_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++ // printk("----%s, %d, width: %d, height: %d, code: %x\n", ++ // __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int sc031gs_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc031gs_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc031gs_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc031gs_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int sc031gs_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int sc031gs_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc031gs_again_lut); i++) { ++ lut = &sc031gs_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc031gs_again_lut); i++) { ++ lut = &sc031gs_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++} ++ ++static int sc031gs_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ /* ++ struct sc031gs_info *info = to_state(sd); ++ char v = 0; ++ unsigned int reg_val = 0; ++ ++ ++ ret += sc031gs_read(sd, 0x3509, &v); ++ ++ reg_val |= v; ++ ret += sc031gs_read(sd, 0x3508, &v); ++ reg_val |= v << 8; ++ ++ ++ *value = regval_to_again(reg_val); ++ */ ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int sc031gs_s_again(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++#if 0 ++ struct sc031gs_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int i; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ ++ ret += sc031gs_write(sd, 0x3509, (unsigned char)(reg_value & 0xff)); ++ ret += sc031gs_write(sd, 0x3508, (unsigned char)((reg_value>>8) & 0xff)); ++ if (ret < 0) ++ return ret; ++ ++#endif ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int sc031gs_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc031gs_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ /* ++ struct sc031gs_info *info = to_state(sd); ++ ++ ret += sc031gs_write(sd, 0x3502, ((unsigned char)(value & 0xf)) << 4); ++ ret += sc031gs_write(sd, 0x3501, (unsigned char)((value >> 4) & 0xff)); ++ ret += sc031gs_write(sd, 0x3500, (unsigned char)((value >> 12) & 0xf)); ++ ++*/ ++ return ret; ++} ++ ++static int sc031gs_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc031gs_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return sc031gs_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc031gs_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int sc031gs_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc031gs_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return sc031gs_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return sc031gs_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return sc031gs_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return sc031gs_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* sc031gs_s_gain turns off auto gain */ ++ return sc031gs_s_gain(sd, info->gain->val); ++ } ++ return sc031gs_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return sc031gs_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc031gs_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return sc031gs_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops sc031gs_ctrl_ops = { ++ .s_ctrl = sc031gs_s_ctrl, ++ .g_volatile_ctrl = sc031gs_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int sc031gs_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = sc031gs_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int sc031gs_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ sc031gs_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int sc031gs_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct sc031gs_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ++ sc031gs_write_array(sd, info->win->regs); ++ sc031gs_s_again(sd, 100000); ++ ret = sc031gs_write_array(sd, sc031gs_stream_on_mipi); ++ pr_debug("sc031gs stream on\n"); ++ ++ } ++ else { ++ ret = sc031gs_write_array(sd, sc031gs_stream_off_mipi); ++ pr_debug("sc031gs stream off\n"); ++ } ++ return ret; ++} ++ ++int sc031gs_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct sc031gs_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops sc031gs_core_ops = { ++ .reset = sc031gs_reset, ++ .init = sc031gs_init, ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = sc031gs_g_register, ++ .s_register = sc031gs_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops sc031gs_video_ops = { ++ .s_stream = sc031gs_s_stream, ++ .g_frame_interval = sc031gs_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops sc031gs_pad_ops = { ++ //.enum_frame_interval = sc031gs_enum_frame_interval, ++ //.num_frame_size = sc031gs_enum_frame_size, ++ //.enum_mbus_code = sc031gs_enum_mbus_code, ++ .set_fmt = sc031gs_set_fmt, ++ .get_fmt = sc031gs_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops sc031gs_ops = { ++ .core = &sc031gs_core_ops, ++ .video = &sc031gs_video_ops, ++ .pad = &sc031gs_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int sc031gs_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct sc031gs_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ int tmp; ++ ++ dev_info(&client->dev, "sc031gs probing\n"); ++ ++ /* ++ *(volatile unsigned int *)0xb0010340 &= ~(3 << 30); ++ ++ *(volatile unsigned int *)0xb0010010 &= ~(3 << 16); ++ *(volatile unsigned int *)0xb0010020 &= ~(3 << 16); ++ *(volatile unsigned int *)0xb0010030 &= ~(3 << 16); ++ *(volatile unsigned int *)0xb0010040 &= ~(3 << 16); ++ ++// *(volatile unsigned int *)0xb00100a0 |= (3 << 16); ++// *(volatile unsigned int *)0xb00100b0 |= (3 << 16); ++// *(volatile unsigned int *)0xb00100c0 |= (3 << 16); ++ */ ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ printk("[%d] gpio=%d\n", __LINE__, gpio); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,vcc-en-gpio", 0, &flags); ++ printk("[%d] gpio=%d\n", __LINE__, gpio); ++ if(gpio_is_valid(gpio)) { ++ info->vcc_en.pin = gpio; ++ info->vcc_en.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutp-gpio", 0, &flags); ++ printk("[%d] gpio=%d\n", __LINE__, gpio); ++ if(gpio_is_valid(gpio)) { ++ info->ircutp.pin = gpio; ++ info->ircutp.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,ircutn-gpio", 0, &flags); ++ printk("[%d] gpio=%d\n", __LINE__, gpio); ++ if(gpio_is_valid(gpio)) { ++ info->ircutn.pin = gpio; ++ info->ircutn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &sc031gs_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ sc031gs_power(sd, 1); ++ msleep(10); ++ sc031gs_reset(sd, 1); ++#if 1 ++ /* Make sure it's an sc031gs */ ++ ret = sc031gs_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an sc031gs chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &sc031gs_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &sc031gs_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &sc031gs_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &sc031gs_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &sc031gs_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &sc031gs_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 261773, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &sc031gs_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &sc031gs_win_sizes[0]; ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "sc031gs Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int sc031gs_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct sc031gs_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id sc031gs_id[] = { ++ { "sc031gs", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, sc031gs_id); ++ ++static const struct of_device_id sc031gs_of_match[] = { ++ {.compatible = "ovti,sc031gs", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++ ++static struct i2c_driver sc031gs_driver = { ++ .driver = { ++ .name = "sc031gs", ++ .of_match_table = of_match_ptr(sc031gs_of_match), ++ }, ++ .probe = sc031gs_probe, ++ .remove = sc031gs_remove, ++ .id_table = sc031gs_id, ++}; ++ ++module_i2c_driver(sc031gs_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision sc031gs sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/sc2232h.c b/module_drivers/drivers/media/i2c/ingenic-isp/sc2232h.c +new file mode 100644 +index 000000000..0e9bdee60 +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/sc2232h.c +@@ -0,0 +1,1173 @@ ++/* ++ * A V4L2 driver for OmniVision sc2232h cameras. ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define SC2232H_CHIP_ID_H (0xcb) ++#define SC2232H_CHIP_ID_M (0x07) ++#define SC2232H_CHIP_ID_L (0x01) ++#define SC2232H_REG_END 0xffff ++#define SC2232H_REG_DELAY 0xfffe ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct sc2232h_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct sc2232h_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct sc2232h_info { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct sc2232h_win_size *win; ++ struct sc2232h_gpio reset; ++ ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++struct again_lut sc2232h_again_lut[] = { ++ ++ {0x10, 0}, ++ {0x11, 5731}, ++ {0x12, 11136}, ++ {0x13, 16248}, ++ {0x14, 21097}, ++ {0x15, 25710}, ++ {0x16, 30109}, ++ {0x17, 34312}, ++ {0x18, 38336}, ++ {0x19, 42195}, ++ {0x1a, 45904}, ++ {0x1b, 49472}, ++ {0x1c, 52910}, ++ {0x1d, 56228}, ++ {0x1e, 59433}, ++ {0x1f, 62534}, ++ {0x110, 65536}, ++ {0x111, 71267}, ++ {0x112, 76672}, ++ {0x113, 81784}, ++ {0x114, 86633}, ++ {0x115, 91246}, ++ {0x116, 95645}, ++ {0x117, 99848}, ++ {0x118, 103872}, ++ {0x119, 107731}, ++ {0x11a, 111440}, ++ {0x11b, 115008}, ++ {0x11c, 118446}, ++ {0x11d, 121764}, ++ {0x11e, 124969}, ++ {0x11f, 128070}, ++ {0x310, 131072}, ++ {0x311, 136803}, ++ {0x312, 142208}, ++ {0x313, 147320}, ++ {0x314, 152169}, ++ {0x315, 156782}, ++ {0x316, 161181}, ++ {0x317, 165384}, ++ {0x318, 169408}, ++ {0x319, 173267}, ++ {0x31a, 176976}, ++ {0x31b, 180544}, ++ {0x31c, 183982}, ++ {0x31d, 187300}, ++ {0x31e, 190505}, ++ {0x31f, 193606}, ++ {0x710, 196608}, ++ {0x711, 202339}, ++ {0x712, 207744}, ++ {0x713, 212856}, ++ {0x714, 217705}, ++ {0x715, 222318}, ++ {0x716, 226717}, ++ {0x717, 230920}, ++ {0x718, 234944}, ++ {0x719, 238803}, ++ {0x71a, 242512}, ++ {0x71b, 246080}, ++ {0x71c, 249518}, ++ {0x71d, 252836}, ++ {0x71e, 256041}, ++ /* {0x71f, 259142}, */ ++}; ++ ++static inline struct sc2232h_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct sc2232h_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct sc2232h_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list sc2232h_init_regs_1920_1080_25fps_mipi[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x3034, 0x81}, ++ {0x3039, 0xd4}, ++ {0x3624, 0x08}, ++ {0x337f, 0x03}, ++ {0x3368, 0x04}, ++ {0x3369, 0x00}, ++ {0x336a, 0x00}, ++ {0x336b, 0x00}, ++ {0x3367, 0x08}, ++ {0x330e, 0x30}, ++ {0x3366, 0x7c}, ++ {0x3302, 0x1f}, ++ {0x3907, 0x00}, ++ {0x3908, 0x11}, ++ {0x335e, 0x01}, ++ {0x335f, 0x03}, ++ {0x337c, 0x04}, ++ {0x337d, 0x06}, ++ {0x33a0, 0x05}, ++ {0x3633, 0x4f}, ++ {0x3622, 0x06}, ++ {0x3631, 0x84}, ++ {0x366e, 0x08}, ++ {0x3326, 0x00}, ++ {0x3303, 0x20}, ++ {0x3638, 0x1f}, ++ {0x3636, 0x25}, ++ {0x3625, 0x02}, ++ {0x331b, 0x83}, ++ {0x3333, 0x30}, ++ {0x3635, 0xa0}, ++ {0x363c, 0x05}, ++ {0x3038, 0xff}, ++ {0x3639, 0x09}, ++ {0x3621, 0x28}, ++ {0x3211, 0x0c}, ++ {0x3320, 0x01}, ++ {0x331e, 0x19}, ++ {0x3620, 0x28}, ++ {0x3309, 0x60}, ++ {0x331f, 0x59}, ++ {0x3308, 0x10}, ++ {0x3f00, 0x07}, ++ {0x33aa, 0x10}, ++ {0x3677, 0x86}, ++ {0x3678, 0x88}, ++ {0x3679, 0x88}, ++ {0x367e, 0x08}, ++ {0x367f, 0x28}, ++ {0x3670, 0x0c}, ++ {0x3690, 0x33}, ++ {0x3691, 0x11}, ++ {0x3692, 0x43}, ++ {0x369c, 0x08}, ++ {0x369d, 0x28}, ++ {0x360f, 0x01}, ++ {0x3671, 0xc6}, ++ {0x3672, 0x06}, ++ {0x3673, 0x16}, ++ {0x367a, 0x28}, ++ {0x367b, 0x3f}, ++ {0x3221, 0x80}, ++ {0x3222, 0x29}, ++ {0x3901, 0x02}, ++ {0x3905, 0x98}, ++ {0x3e1e, 0x34}, ++ {0x3900, 0x19}, ++ {0x391d, 0x04}, ++ {0x391e, 0x00}, ++ {0x3641, 0x01}, ++ {0x3213, 0x04}, ++ {0x3614, 0x80}, ++ {0x363a, 0x9f}, ++ {0x3630, 0x9c}, ++ {0x3306, 0x48}, ++ {0x330b, 0xcd}, ++ {0x3018, 0x33}, ++ {0x3031, 0x0a}, ++ {0x3037, 0x20}, ++ {0x3001, 0xfe}, ++ {0x4603, 0x00}, ++ {0x4827, 0x48}, ++ {0x301c, 0x78}, ++ {0x4809, 0x01}, ++ {0x3314, 0x04}, ++ {0x3933, 0x0a}, ++ {0x3934, 0x18}, ++ {0x3940, 0x60}, ++ {0x3942, 0x02}, ++ {0x3943, 0x1f}, ++ {0x3960, 0xba}, ++ {0x3961, 0xae}, ++ {0x3966, 0xba}, ++ {0x3980, 0xa0}, ++ {0x3981, 0x40}, ++ {0x3982, 0x18}, ++ {0x3903, 0x08}, ++ {0x3984, 0x08}, ++ {0x3985, 0x20}, ++ {0x3986, 0x50}, ++ {0x3987, 0xb0}, ++ {0x3988, 0x08}, ++ {0x3989, 0x10}, ++ {0x398a, 0x20}, ++ {0x398b, 0x30}, ++ {0x398c, 0x60}, ++ {0x398d, 0x20}, ++ {0x398e, 0x10}, ++ {0x398f, 0x08}, ++ {0x3990, 0x60}, ++ {0x3991, 0x24}, ++ {0x3992, 0x15}, ++ {0x3993, 0x08}, ++ {0x3994, 0x0a}, ++ {0x3995, 0x20}, ++ {0x3996, 0x38}, ++ {0x3997, 0xa0}, ++ {0x3998, 0x08}, ++ {0x3999, 0x10}, ++ {0x399a, 0x18}, ++ {0x399b, 0x30}, ++ {0x399c, 0x30}, ++ {0x399d, 0x18}, ++ {0x399e, 0x10}, ++ {0x399f, 0x08}, ++ {0x3637, 0x55}, ++ {0x366f, 0x2c}, ++ {0x5000, 0x06}, ++ {0x5780, 0x7f}, ++ {0x5781, 0x04}, ++ {0x5782, 0x03}, ++ {0x5783, 0x02}, ++ {0x5784, 0x01}, ++ {0x5785, 0x18}, ++ {0x5786, 0x10}, ++ {0x5787, 0x08}, ++ {0x5788, 0x02}, ++ {0x57a0, 0x00}, ++ {0x57a1, 0x71}, ++ {0x57a2, 0x01}, ++ {0x57a3, 0xf1}, ++ {0x395e, 0xc0}, ++ {0x3962, 0x88}, ++ {0x303a, 0xb3}, ++ {0x303c, 0x0e}, ++ {0x3035, 0x9b}, ++ {0x320c, 0x08}, ++ {0x320d, 0x20}, ++ {0x320e, 0x05}, ++ {0x320f, 0xdc},/*25fps*/ ++ {0x3f04, 0x03}, ++ {0x3f05, 0xec}, ++ {0x3235, 0x09}, ++ {0x3236, 0xc2}, ++ {0x4837, 0x33}, ++ {0x3802, 0x00}, ++ {0x3963, 0x80}, ++ {0x303b, 0x16}, ++ {0x301f, 0x05}, ++ {0x363b, 0x26}, ++ {0x3902, 0xc5}, ++ {0x3e00, 0x00}, ++ {0x3e01, 0x9c}, ++ {0x3e02, 0x00}, ++ {0x3e03, 0x0b}, ++ {0x3e06, 0x00}, ++ {0x3e07, 0x80}, ++ {0x3e08, 0x03}, ++ {0x3e09, 0x10}, ++ {0x3301, 0x12}, ++ {0x3632, 0x08}, ++ {0x3034, 0x01}, ++ {0x3039, 0x24}, ++ ++ {SC2232H_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc2232h_init_regs_1920_1080_25fps_dvp[] = { ++ {0x0103, 0x01}, ++ {0x0100, 0x00}, ++ {0x3034, 0x81}, ++ {0x3039, 0xd4}, ++ {0x3018, 0x1f}, ++ {0x3019, 0xff}, ++ {0x301c, 0xb4}, ++ {0x3624, 0x08}, ++ {0x337f, 0x03}, ++ {0x3368, 0x04}, ++ {0x3369, 0x00}, ++ {0x336a, 0x00}, ++ {0x336b, 0x00}, ++ {0x3367, 0x08}, ++ {0x330e, 0x30}, ++ {0x3366, 0x7c}, ++ {0x3302, 0x1f}, ++ {0x303f, 0x81}, ++ {0x3907, 0x00}, ++ {0x3908, 0x11}, ++ {0x335e, 0x01}, ++ {0x335f, 0x03}, ++ {0x337c, 0x04}, ++ {0x337d, 0x06}, ++ {0x33a0, 0x05}, ++ {0x3633, 0x4f}, ++ {0x3622, 0x06}, ++ {0x3631, 0x84}, ++ {0x366e, 0x08}, ++ {0x3326, 0x00}, ++ {0x3303, 0x20}, ++ {0x3638, 0x1f}, ++ {0x3636, 0x25}, ++ {0x3625, 0x02}, ++ {0x331b, 0x83}, ++ {0x3333, 0x30}, ++ {0x3635, 0xa0}, ++ {0x363c, 0x05}, ++ {0x3038, 0xff}, ++ {0x3639, 0x09}, ++ {0x3621, 0x28}, ++ {0x3211, 0x0c}, ++ {0x3320, 0x01}, ++ {0x331e, 0x19}, ++ {0x3620, 0x28}, ++ {0x3309, 0x60}, ++ {0x331f, 0x59}, ++ {0x3308, 0x10}, ++ {0x3f00, 0x07}, ++ {0x33aa, 0x10}, ++ {0x3677, 0x86}, ++ {0x3678, 0x88}, ++ {0x3679, 0x88}, ++ {0x367e, 0x08}, ++ {0x367f, 0x28}, ++ {0x3670, 0x0c}, ++ {0x3690, 0x33}, ++ {0x3691, 0x11}, ++ {0x3692, 0x43}, ++ {0x369c, 0x08}, ++ {0x369d, 0x28}, ++ {0x360f, 0x01}, ++ {0x3671, 0xc6}, ++ {0x3672, 0x06}, ++ {0x3673, 0x16}, ++ {0x367a, 0x28}, ++ {0x367b, 0x3f}, ++ {0x3221, 0x80}, ++ {0x3222, 0x29}, ++ {0x3901, 0x02}, ++ {0x3905, 0x98}, ++ {0x3e1e, 0x34}, ++ {0x3900, 0x19}, ++ {0x391d, 0x04}, ++ {0x391e, 0x00}, ++ {0x3641, 0x01}, ++ {0x3213, 0x04}, ++ {0x3614, 0x80}, ++ {0x363a, 0x9f}, ++ {0x3630, 0x9c}, ++ {0x3306, 0x48}, ++ {0x330b, 0xcd}, ++ {0x3314, 0x04}, ++ {0x3933, 0x0a}, ++ {0x3934, 0x18}, ++ {0x3940, 0x60}, ++ {0x3942, 0x02}, ++ {0x3943, 0x1f}, ++ {0x3960, 0xba}, ++ {0x3961, 0xae}, ++ {0x3966, 0xba}, ++ {0x3980, 0xa0}, ++ {0x3981, 0x40}, ++ {0x3982, 0x18}, ++ {0x3903, 0x08}, ++ {0x3984, 0x08}, ++ {0x3985, 0x20}, ++ {0x3986, 0x50}, ++ {0x3987, 0xb0}, ++ {0x3988, 0x08}, ++ {0x3989, 0x10}, ++ {0x398a, 0x20}, ++ {0x398b, 0x30}, ++ {0x398c, 0x60}, ++ {0x398d, 0x20}, ++ {0x398e, 0x10}, ++ {0x398f, 0x08}, ++ {0x3990, 0x60}, ++ {0x3991, 0x24}, ++ {0x3992, 0x15}, ++ {0x3993, 0x08}, ++ {0x3994, 0x0a}, ++ {0x3995, 0x20}, ++ {0x3996, 0x38}, ++ {0x3997, 0xa0}, ++ {0x3998, 0x08}, ++ {0x3999, 0x10}, ++ {0x399a, 0x18}, ++ {0x399b, 0x30}, ++ {0x399c, 0x30}, ++ {0x399d, 0x18}, ++ {0x399e, 0x10}, ++ {0x399f, 0x08}, ++ {0x3637, 0x55}, ++ {0x366f, 0x2c}, ++ {0x5000, 0x06}, ++ {0x5780, 0x7f}, ++ {0x5781, 0x04}, ++ {0x5782, 0x03}, ++ {0x5783, 0x02}, ++ {0x5784, 0x01}, ++ {0x5785, 0x18}, ++ {0x5786, 0x10}, ++ {0x5787, 0x08}, ++ {0x5788, 0x02}, ++ {0x57a0, 0x00}, ++ {0x57a1, 0x71}, ++ {0x57a2, 0x01}, ++ {0x57a3, 0xf1}, ++ {0x395e, 0xc0}, ++ {0x3962, 0x88}, ++ {0x303a, 0xb3}, ++ {0x303c, 0x0e}, ++ {0x3035, 0x9b}, ++ {0x320c, 0x08}, ++ {0x320d, 0x20}, ++ {0x320e, 0x05}, ++ {0x320f, 0xd0},/*vts for 25fps*/ ++ {0x3f04, 0x03}, ++ {0x3f05, 0xec}, ++ {0x3235, 0x09}, ++ {0x3236, 0xc2}, ++ {0x3802, 0x00}, ++ {0x3963, 0x80}, ++ {0x303b, 0x16}, ++ {0x301f, 0x03}, ++ {0x363b, 0x26}, ++ {0x3902, 0xc5}, ++ {0x3e00, 0x00}, ++// {0x3e01, 0x9c}, ++ {0x3e01, 0xbc}, ++ {0x3e02, 0x00}, ++ {0x3e03, 0x0b}, ++ {0x3e06, 0x00}, ++ {0x3e07, 0x80}, ++ {0x3e08, 0x03}, ++ {0x3e09, 0x10}, ++ {0x3d08, 0x00},//PCLK polarity ++ {0x3301, 0x12}, ++ {0x3632, 0x08}, ++ {0x3034, 0x01}, ++ {0x3039, 0x24}, ++ ++ {SC2232H_REG_END, 0x00}, /* END MARKER */ ++}; ++/* ++ * the part of driver was fixed. ++ */ ++ ++static struct regval_list sc2232h_stream_on[] = { ++ {0x0100, 0x01}, ++ {SC2232H_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc2232h_stream_off[] = { ++ {0x0100, 0x00}, ++ {SC2232H_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static int sc2232h_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct sc2232h_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret = 0; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if(ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int sc2232h_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct sc2232h_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int sc2232h_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != SC2232H_REG_END) { ++ if (vals->reg_num == SC2232H_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc2232h_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++/* ++ * Write a list of register settings; ff/ff stops the process. ++ */ ++static int sc2232h_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != SC2232H_REG_END) { ++ if (vals->reg_num == SC2232H_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc2232h_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int sc2232h_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc2232h_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->reset.pin, info->reset.active_level); ++ msleep(10); ++ gpio_direction_output(info->reset.pin, !info->reset.active_level); ++ msleep(10); ++ } ++ return 0; ++} ++ ++ ++static int sc2232h_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc2232h_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = sc2232h_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++ ++static int sc2232h_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ret = sc2232h_read(sd, 0x3107, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC2232H_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = sc2232h_read(sd, 0x3108, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC2232H_CHIP_ID_M) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ ++ ret = sc2232h_read(sd, 0x3109, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC2232H_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ return 0; ++} ++ ++ ++static struct sc2232h_win_size sc2232h_win_sizes[] = { ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 25 << 16 | 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc2232h_init_regs_1920_1080_25fps_dvp, ++ }, ++}; ++ ++static int sc2232h_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_SC2232H_FMTS) ++ return -EINVAL; ++ ++ code->code = sc2232h_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int sc2232h_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc2232h_format_struct *ovfmt; ++ struct sc2232h_win_size *wsize; ++ struct sc2232h_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int sc2232h_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc2232h_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int sc2232h_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc2232h_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc2232h_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc2232h_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int sc2232h_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int sc2232h_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc2232h_again_lut); i++) { ++ lut = &sc2232h_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ return lut->value; ++ } ++ } ++ ++ /*last value.*/ ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc2232h_again_lut); i++) { ++ lut = &sc2232h_again_lut[i]; ++ ++ if(regval == lut->value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int sc2232h_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ struct sc2232h_info *info = to_state(sd); ++ char v = 0; ++ unsigned int reg_val = 0; ++ int ret = 0; ++ ++ ++ ret += sc2232h_read(sd, 0x3509, &v); ++ ++ reg_val |= v; ++ ret += sc2232h_read(sd, 0x3508, &v); ++ reg_val |= v << 8; ++ ++ ++ *value = regval_to_again(reg_val); ++ ++ return ret; ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int sc2232h_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct sc2232h_info *info = to_state(sd); ++ unsigned int reg_value = 0; ++ int ret = 0; ++ int i; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ reg_value = again_to_regval(info->again->default_value); ++ } else { ++ reg_value = again_to_regval(value); ++ } ++ /* denoise logic */ ++ if (reg_value < 0x110) { ++ sc2232h_write(sd, 0x3812, 0x00); ++ sc2232h_write(sd, 0x3301, 0x12); ++ sc2232h_write(sd, 0x3632, 0x08); ++ sc2232h_write(sd, 0x3812, 0x30); ++ } else if (reg_value >= 0x110 && reg_value < 0x310) { ++ sc2232h_write(sd, 0x3812, 0x00); ++ sc2232h_write(sd, 0x3301, 0x20); ++ sc2232h_write(sd, 0x3632, 0x08); ++ sc2232h_write(sd, 0x3812, 0x30); ++ } else if(reg_value >= 0x310&®_value < 0x710) { ++ sc2232h_write(sd, 0x3812, 0x00); ++ sc2232h_write(sd, 0x3301, 0x28); ++ sc2232h_write(sd, 0x3632, 0x08); ++ sc2232h_write(sd, 0x3812, 0x30); ++ } else if(reg_value >= 0x710&®_value <= 0x71e) { ++ sc2232h_write(sd, 0x3812, 0x00); ++ sc2232h_write(sd, 0x3301, 0x64); ++ sc2232h_write(sd, 0x3632, 0x08); ++ sc2232h_write(sd, 0x3812, 0x30); ++ } else { //may be flick ++ sc2232h_write(sd, 0x3812, 0x00); ++ sc2232h_write(sd, 0x3301, 0x64); ++ sc2232h_write(sd, 0x3632, 0x48); ++ sc2232h_write(sd, 0x3812, 0x30); ++ } ++ ret = sc2232h_write(sd, 0x3e09, (unsigned char)(reg_value & 0xff)); ++ ret += sc2232h_write(sd, 0x3e08, (unsigned char)((reg_value >> 8 << 2) | 0x03)); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int sc2232h_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc2232h_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct sc2232h_info *info = to_state(sd); ++ int ret = 0; ++ ++ value *= 2; ++ ret = sc2232h_write(sd, 0x3e00, (unsigned char)((value >> 12) & 0x0f)); ++ ret += sc2232h_write(sd, 0x3e01, (unsigned char)((value >> 4) & 0xff)); ++ ret += sc2232h_write(sd, 0x3e02, (unsigned char)((value & 0x0f) << 4)); ++ ++ if (value < 250) { ++ ret += sc2232h_write(sd, 0x3314, 0x14); ++ } ++ else if(value > 450){ ++ ret += sc2232h_write(sd, 0x3314, 0x04); ++ } ++ ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++static int sc2232h_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc2232h_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return sc2232h_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc2232h_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int sc2232h_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc2232h_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return sc2232h_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return sc2232h_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return sc2232h_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return sc2232h_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* sc2232h_s_gain turns off auto gain */ ++ return sc2232h_s_gain(sd, info->gain->val); ++ } ++ return sc2232h_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return sc2232h_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc2232h_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return sc2232h_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops sc2232h_ctrl_ops = { ++ .s_ctrl = sc2232h_s_ctrl, ++ .g_volatile_ctrl = sc2232h_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int sc2232h_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = sc2232h_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int sc2232h_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ sc2232h_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++int sc2232h_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct sc2232h_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ret = sc2232h_write_array(sd, sc2232h_stream_on); ++ pr_debug("sc2232h stream on\n"); ++ ++ } ++ else { ++ ret = sc2232h_write_array(sd, sc2232h_stream_off); ++ pr_debug("sc2232h stream off\n"); ++ } ++ return ret; ++} ++ ++int sc2232h_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct sc2232h_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops sc2232h_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = sc2232h_g_register, ++ .s_register = sc2232h_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops sc2232h_video_ops = { ++ .s_stream = sc2232h_s_stream, ++ .g_frame_interval = sc2232h_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops sc2232h_pad_ops = { ++ //.enum_frame_interval = sc2232h_enum_frame_interval, ++ //.num_frame_size = sc2232h_enum_frame_size, ++ //.enum_mbus_code = sc2232h_enum_mbus_code, ++ .set_fmt = sc2232h_set_fmt, ++ .get_fmt = sc2232h_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops sc2232h_ops = { ++ .core = &sc2232h_core_ops, ++ .video = &sc2232h_video_ops, ++ .pad = &sc2232h_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int sc2232h_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_fract tpf; ++ struct v4l2_subdev *sd; ++ struct sc2232h_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,rst-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->reset.pin = gpio; ++ info->reset.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ v4l2_i2c_subdev_init(sd, client, &sc2232h_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ sc2232h_reset(sd, 1); ++ ++#if 1 ++ /* Make sure it's an sc2232h */ ++ ret = sc2232h_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an sc2232h chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &sc2232h_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &sc2232h_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &sc2232h_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &sc2232h_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &sc2232h_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &sc2232h_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 261773, 1, 10000); ++ ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &sc2232h_ctrl_ops, ++ V4L2_CID_EXPOSURE, 4, 1520 - 4, 1, 1000); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &sc2232h_win_sizes[0]; ++ sc2232h_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "sc2232h Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ return ret; ++} ++ ++ ++static int sc2232h_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct sc2232h_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ return 0; ++} ++ ++static const struct i2c_device_id sc2232h_id[] = { ++ { "sc2232h", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, sc2232h_id); ++ ++static const struct of_device_id sc2232h_of_match[] = { ++ {.compatible = "ingenic,sc2232h", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ov2640_of_match); ++ ++ ++static struct i2c_driver sc2232h_driver = { ++ .driver = { ++ .name = "sc2232h", ++ .of_match_table = of_match_ptr(sc2232h_of_match), ++ }, ++ .probe = sc2232h_probe, ++ .remove = sc2232h_remove, ++ .id_table = sc2232h_id, ++}; ++ ++module_i2c_driver(sc2232h_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for OmniVision sc2232h sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/i2c/ingenic-isp/sc230ai.c b/module_drivers/drivers/media/i2c/ingenic-isp/sc230ai.c +new file mode 100644 +index 000000000..9156c61dc +--- /dev/null ++++ b/module_drivers/drivers/media/i2c/ingenic-isp/sc230ai.c +@@ -0,0 +1,1653 @@ ++/* ++ * A V4L2 driver for OmniVision SC230AI cameras. ++ * ++ * Copyright 2006 One Laptop Per Child Association, Inc. Written ++ * by Jonathan Corbet with substantial inspiration from Mark ++ * McClelland's ovcamchip code. ++ * ++ * Copyright 2006-7 Jonathan Corbet ++ * ++ * This file may be distributed under the terms of the GNU General ++ * Public License, version 2. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define SC230AI_CHIP_ID_H (0xcb) ++#define SC230AI_CHIP_ID_L (0x34) ++#define SC230AI_REG_END 0xff ++#define SC230AI_REG_DELAY 0x00 ++#define SC230AI_PAGE_REG 0xfd ++ ++static bool debug; ++module_param(debug, bool, 0644); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++ ++struct sc230ai_win_size { ++ unsigned int width; ++ unsigned int height; ++ unsigned int mbus_code; ++ struct sensor_info sensor_info; ++ enum v4l2_colorspace colorspace; ++ void *regs; ++ ++}; ++ ++struct sc230ai_gpio { ++ int pin; ++ int active_level; ++}; ++ ++struct sc230ai_supply{ ++ struct regulator *avdd; ++ struct regulator *dvdd; ++ struct regulator *dovdd; ++}; ++ ++struct sc230ai_info { ++ struct sc230ai_supply supply; ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_ctrl *gain; ++ struct v4l2_ctrl *again; ++ ++ struct v4l2_clk *clk; ++ struct clk *sclka; ++ ++ struct v4l2_ctrl *exposure; ++ ++ struct media_pad pad; ++ ++ struct v4l2_subdev_format *format; /*current fmt.*/ ++ struct sc230ai_win_size *win; ++ ++ struct sc230ai_gpio xshutdn; ++ struct sc230ai_gpio pwdn; ++ struct sc230ai_gpio efsync; ++ struct sc230ai_gpio led; ++}; ++ ++ ++/* ++ * the part of driver maybe modify about different sensor and different board. ++ */ ++struct again_lut { ++ unsigned int value; /*sensor regs value*/ ++ unsigned int fine_value; /*sensor regs value*/ ++ unsigned int gain; /*isp gain*/ ++}; ++ ++struct again_lut sc230ai_again_lut[] = { ++ /* ++ {0x00, 0}, ++ {0x01, 65536}, ++ {0x40, 115455}, ++ {0x48, 180991}, ++ {0x49, 246527}, ++ {0x4b, 312063}, ++ {0x4f, 377599}, ++ {0x5f, 443135}, ++ */ ++ ++ {0x00,0x80,0}, ++ {0x00,0x82,1501}, ++ {0x00,0x84,2886}, ++ {0x00,0x86,4343}, ++ {0x00,0x88,5776}, ++ {0x00,0x8a,7101}, ++ {0x00,0x8c,8494}, ++ {0x00,0x8e,9782}, ++ {0x00,0x90,11136}, ++ {0x00,0x92,12471}, ++ {0x00,0x94,13706}, ++ {0x00,0x96,15006}, ++ {0x00,0x98,16288}, ++ {0x00,0x9a,17474}, ++ {0x00,0x9c,18724}, ++ {0x00,0x9e,19880}, ++ {0x00,0xa0,21098}, ++ {0x00,0xa2,22300}, ++ {0x00,0xa4,23414}, ++ {0x00,0xa6,24588}, ++ {0x00,0xa8,25747}, ++ {0x00,0xaa,26821}, ++ {0x00,0xac,27953}, ++ {0x00,0xae,29003}, ++ {0x00,0xb0,30109}, ++ {0x00,0xb2,31203}, ++ {0x00,0xb4,32217}, ++ {0x00,0xb6,33287}, ++ {0x00,0xb8,34345}, ++ {0x00,0xba,35326}, ++ {0x00,0xbc,36362}, ++ {0x00,0xbe,37322}, ++ {0x00,0xc0,38336}, ++ {0x00,0xc2,39339}, ++ {0x00,0xc4,40270}, ++ {0x00,0xc6,41253}, ++ {0x00,0xc8,42226}, ++ {0x00,0xca,43129}, ++ {0x00,0xcc,44083}, ++ {0x00,0xce,44968}, ++ {0x00,0xd0,45904}, ++ {0x00,0xd2,46830}, ++ {0x00,0xd4,47691}, ++ {0x00,0xd6,48600}, ++ {0x00,0xd8,49500}, ++ {0x00,0xda,50337}, ++ {0x00,0xdc,51221}, ++ {0x00,0xdf,52042}, ++ {0x00,0xe0,52911}, ++ {0x00,0xe2,53771}, ++ {0x00,0xe4,54571}, ++ {0x00,0xe6,55417}, ++ {0x00,0xe8,56255}, ++ {0x00,0xea,57034}, ++ {0x00,0xec,57858}, ++ {0x00,0xee,58624}, ++ {0x00,0xf0,59434}, ++ {0x00,0xf2,60237}, ++ {0x00,0xf4,60984}, ++ {0x00,0xf6,61775}, ++ {0x00,0xf8,62559}, ++ {0x00,0xfa,63288}, ++ {0x00,0xfc,64059}, ++ {0x00,0xfe,64777}, ++ {0x01,0x80,65536}, ++ {0x01,0x82,66990}, ++ {0x01,0x84,68468}, ++ {0x01,0x86,69879}, ++ {0x01,0x88,71268}, ++ {0x01,0x8a,72637}, ++ {0x01,0x8c,74030}, ++ {0x01,0x8e,75360}, ++ {0x01,0x90,76672}, ++ {0x01,0x92,77966}, ++ {0x01,0x94,79283}, ++ {0x01,0x96,80542}, ++ {0x01,0x98,81784}, ++ {0x01,0x9a,83010}, ++ {0x01,0x9c,84260}, ++ {0x01,0x9e,85454}, ++ {0x01,0xa0,86634}, ++ {0x01,0xa2,87799}, ++ {0x01,0xa4,88987}, ++ {0x01,0xa6,90124}, ++ {0x01,0xa8,91247}, ++ {0x01,0xaa,92357}, ++ {0x01,0xac,93489}, ++ {0x01,0xae,94573}, ++ {0x01,0xb0,95645}, ++ {0x01,0xb2,96705}, ++ {0x01,0xb4,97787}, ++ {0x01,0xb6,98823}, ++ {0x01,0xb8,99848}, ++ {0x01,0xba,100862}, ++ {0x01,0xbc,101898}, ++ {0x01,0xbe,102890}, ++ {0x01,0xc0,103872}, ++ {0x01,0xc2,104844}, ++ {0x01,0xc4,105837}, ++ {0x01,0xc6,106789}, ++ {0x01,0xc8,107732}, ++ {0x01,0xca,108665}, ++ {0x01,0xcc,109619}, ++ {0x01,0xce,110534}, ++ {0x01,0xd0,111440}, ++ {0x01,0xd2,112338}, ++ {0x01,0xd4,113255}, ++ {0x01,0xd6,114136}, ++ {0x01,0xd8,115008}, ++ {0x40,0x80,115455}, ++ {0x40,0x82,116323}, ++ {0x40,0x84,117182}, ++ {0x40,0x86,118034}, ++ {0x40,0x88,118878}, ++ {0x40,0x8a,119715}, ++ {0x40,0x8c,120544}, ++ {0x40,0x8e,121366}, ++ {0x40,0x90,122181}, ++ {0x40,0x92,122989}, ++ {0x40,0x94,123790}, ++ {0x40,0x96,124585}, ++ {0x40,0x98,125373}, ++ {0x40,0x9a,126154}, ++ {0x40,0x9c,126929}, ++ {0x40,0x9e,127697}, ++ {0x40,0xa0,128460}, ++ {0x40,0xa2,129216}, ++ {0x40,0xa4,129966}, ++ {0x40,0xa6,130711}, ++ {0x40,0xa8,131449}, ++ {0x40,0xaa,132910}, ++ {0x40,0xac,134347}, ++ {0x40,0xae,135764}, ++ {0x40,0xb0,137159}, ++ {0x40,0xb2,138534}, ++ {0x40,0xb4,139890}, ++ {0x40,0xb6,141226}, ++ {0x40,0xb8,142544}, ++ {0x40,0xba,143843}, ++ {0x40,0xbc,145125}, ++ {0x40,0xbe,146390}, ++ {0x40,0xc0,147638}, ++ {0x40,0xc2,148870}, ++ {0x40,0xc4,150086}, ++ {0x40,0xc6,151286}, ++ {0x40,0xc8,152472}, ++ {0x40,0xca,153643}, ++ {0x40,0xcc,154799}, ++ {0x40,0xce,155942}, ++ {0x40,0xd0,157071}, ++ {0x40,0xd2,158186}, ++ {0x40,0xd4,159289}, ++ {0x40,0xd6,160379}, ++ {0x40,0xd8,161456}, ++ {0x40,0xda,162521}, ++ {0x40,0xdc,163575}, ++ {0x40,0xdf,164616}, ++ {0x40,0xe0,165647}, ++ {0x40,0xe2,166666}, ++ {0x40,0xe4,167675}, ++ {0x40,0xe6,168672}, ++ {0x40,0xe8,169660}, ++ {0x40,0xea,170637}, ++ {0x40,0xec,171604}, ++ {0x40,0xee,172562}, ++ {0x40,0xf0,173509}, ++ {0x40,0xf2,174448}, ++ {0x40,0xf4,175377}, ++ {0x40,0xf6,176297}, ++ {0x40,0xf8,177208}, ++ {0x40,0xfa,178111}, ++ {0x40,0xfc,179005}, ++ {0x40,0xfe,179891}, ++ {0x48,0x80,180991}, ++ {0x48,0x82,181859}, ++ {0x48,0x84,182718}, ++ {0x48,0x86,183570}, ++ {0x48,0x88,184414}, ++ {0x48,0x8a,185251}, ++ {0x48,0x8c,186080}, ++ {0x48,0x8e,186902}, ++ {0x48,0x90,187717}, ++ {0x48,0x92,188525}, ++ {0x48,0x94,189326}, ++ {0x48,0x96,190121}, ++ {0x48,0x98,190909}, ++ {0x48,0x9a,191690}, ++ {0x48,0x9c,192465}, ++ {0x48,0x9e,193233}, ++ {0x48,0xa0,193996}, ++ {0x48,0xa2,194752}, ++ {0x48,0xa4,195502}, ++ {0x48,0xa6,196247}, ++ {0x48,0xa8,197718}, ++ {0x48,0xaa,199167}, ++ {0x48,0xac,200594}, ++ {0x48,0xae,202000}, ++ {0x48,0xb0,203385}, ++ {0x48,0xb2,204751}, ++ {0x48,0xb4,206096}, ++ {0x48,0xb6,207423}, ++ {0x48,0xb8,208732}, ++ {0x48,0xba,210022}, ++ {0x48,0xbc,211296}, ++ {0x48,0xbe,212552}, ++ {0x48,0xc0,213792}, ++ {0x48,0xc2,215016}, ++ {0x48,0xc4,216224}, ++ {0x48,0xc6,217417}, ++ {0x48,0xc8,218595}, ++ {0x48,0xca,219759}, ++ {0x48,0xcc,220908}, ++ {0x48,0xce,222044}, ++ {0x48,0xd0,223166}, ++ {0x48,0xd2,224275}, ++ {0x48,0xd4,225371}, ++ {0x48,0xd6,226455}, ++ {0x48,0xd8,227526}, ++ {0x48,0xda,228585}, ++ {0x48,0xdc,229633}, ++ {0x48,0xdf,230669}, ++ {0x48,0xe0,231694}, ++ {0x48,0xe2,232708}, ++ {0x48,0xe4,233711}, ++ {0x48,0xe6,234703}, ++ {0x48,0xe8,235686}, ++ {0x48,0xea,236658}, ++ {0x48,0xec,237620}, ++ {0x48,0xee,238573}, ++ {0x48,0xf0,239516}, ++ {0x48,0xf2,240450}, ++ {0x48,0xf4,241374}, ++ {0x48,0xf6,242290}, ++ {0x48,0xf8,243197}, ++ {0x48,0xfa,244095}, ++ {0x48,0xfc,244985}, ++ {0x48,0xfe,245866}, ++ {0x49,0x80,246527}, ++ {0x49,0x82,247395}, ++ {0x49,0x84,248254}, ++ {0x49,0x86,249106}, ++ {0x49,0x88,249950}, ++ {0x49,0x8a,250787}, ++ {0x49,0x8c,251616}, ++ {0x49,0x8e,252438}, ++ {0x49,0x90,253253}, ++ {0x49,0x92,254061}, ++ {0x49,0x94,254862}, ++ {0x49,0x96,255657}, ++ {0x49,0x98,256445}, ++ {0x49,0x9a,257226}, ++ {0x49,0x9c,258001}, ++ {0x49,0x9e,258769}, ++ {0x49,0xa0,259532}, ++ {0x49,0xa2,260288}, ++ {0x49,0xa4,261038}, ++ {0x49,0xa6,261783}, ++ {0x49,0xa8,263254}, ++ {0x49,0xaa,264703}, ++ {0x49,0xac,266130}, ++ {0x49,0xae,267536}, ++ {0x49,0xb0,268921}, ++ {0x49,0xb2,270287}, ++ {0x49,0xb4,271632}, ++ {0x49,0xb6,272959}, ++ {0x49,0xb8,274268}, ++ {0x49,0xba,275558}, ++ {0x49,0xbc,276832}, ++ {0x49,0xbe,278088}, ++ {0x49,0xc0,279328}, ++ {0x49,0xc2,280552}, ++ {0x49,0xc4,281760}, ++ {0x49,0xc6,282953}, ++ {0x49,0xc8,284131}, ++ {0x49,0xca,285295}, ++ {0x49,0xcc,286444}, ++ {0x49,0xce,287580}, ++ {0x49,0xd0,288702}, ++ {0x49,0xd2,289811}, ++ {0x49,0xd4,290907}, ++ {0x49,0xd6,291991}, ++ {0x49,0xd8,293062}, ++ {0x49,0xda,294121}, ++ {0x49,0xdc,295169}, ++ {0x49,0xdf,296205}, ++ {0x49,0xe0,297230}, ++ {0x49,0xe2,298244}, ++ {0x49,0xe4,299247}, ++ {0x49,0xe6,300239}, ++ {0x49,0xe8,301222}, ++ {0x49,0xea,302194}, ++ {0x49,0xec,303156}, ++ {0x49,0xee,304109}, ++ {0x49,0xf0,305052}, ++ {0x49,0xf2,305986}, ++ {0x49,0xf4,306910}, ++ {0x49,0xf6,307826}, ++ {0x49,0xf8,308733}, ++ {0x49,0xfa,309631}, ++ {0x49,0xfc,310521}, ++ {0x49,0xfe,311402}, ++ {0x4b,0x80,312063}, ++ {0x4b,0x82,312931}, ++ {0x4b,0x84,313790}, ++ {0x4b,0x86,314642}, ++ {0x4b,0x88,315486}, ++ {0x4b,0x8a,316323}, ++ {0x4b,0x8c,317152}, ++ {0x4b,0x8e,317974}, ++ {0x4b,0x90,318789}, ++ {0x4b,0x92,319597}, ++ {0x4b,0x94,320398}, ++ {0x4b,0x96,321193}, ++ {0x4b,0x98,321981}, ++ {0x4b,0x9a,322762}, ++ {0x4b,0x9c,323537}, ++ {0x4b,0x9e,324305}, ++ {0x4b,0xa0,325068}, ++ {0x4b,0xa2,325824}, ++ {0x4b,0xa4,326574}, ++ {0x4b,0xa6,327319}, ++ {0x4b,0xa8,328057}, ++ {0x4b,0xaa,329518}, ++ {0x4b,0xac,330955}, ++ {0x4b,0xae,332372}, ++ {0x4b,0xb0,333767}, ++ {0x4b,0xb2,335142}, ++ {0x4b,0xb4,336498}, ++ {0x4b,0xb6,337834}, ++ {0x4b,0xb8,339152}, ++ {0x4b,0xba,340451}, ++ {0x4b,0xbc,341733}, ++ {0x4b,0xbe,342998}, ++ {0x4b,0xc0,344246}, ++ {0x4b,0xc2,345478}, ++ {0x4b,0xc4,346694}, ++ {0x4b,0xc6,347894}, ++ {0x4b,0xc8,349080}, ++ {0x4b,0xca,350251}, ++ {0x4b,0xcc,351407}, ++ {0x4b,0xce,352550}, ++ {0x4b,0xd0,353679}, ++ {0x4b,0xd2,354794}, ++ {0x4b,0xd4,355897}, ++ {0x4b,0xd6,356987}, ++ {0x4b,0xd8,358064}, ++ {0x4b,0xda,359129}, ++ {0x4b,0xdc,360183}, ++ {0x4b,0xdf,361224}, ++ {0x4b,0xe0,362255}, ++ {0x4b,0xe2,363274}, ++ {0x4b,0xe4,364283}, ++ {0x4b,0xe6,365280}, ++ {0x4b,0xe8,366268}, ++ {0x4b,0xea,367245}, ++ {0x4b,0xec,368212}, ++ {0x4b,0xee,369170}, ++ {0x4b,0xf0,370117}, ++ {0x4b,0xf2,371056}, ++ {0x4b,0xf4,371985}, ++ {0x4b,0xf6,372905}, ++ {0x4b,0xf8,373816}, ++ {0x4b,0xfa,374719}, ++ {0x4b,0xfc,375613}, ++ {0x4b,0xfe,376499}, ++ {0x4f,0x80,377599}, ++ {0x4f,0x82,378467}, ++ {0x4f,0x84,379326}, ++ {0x4f,0x86,380178}, ++ {0x4f,0x88,381022}, ++ {0x4f,0x8a,381859}, ++ {0x4f,0x8c,382688}, ++ {0x4f,0x8e,383510}, ++ {0x4f,0x90,384325}, ++ {0x4f,0x92,385133}, ++ {0x4f,0x94,385934}, ++ {0x4f,0x96,386729}, ++ {0x4f,0x98,387517}, ++ {0x4f,0x9a,388298}, ++ {0x4f,0x9c,389073}, ++ {0x4f,0x9e,389841}, ++ {0x4f,0xa0,390604}, ++ {0x4f,0xa2,391360}, ++ {0x4f,0xa4,392110}, ++ {0x4f,0xa6,392855}, ++ {0x4f,0xa8,393593}, ++ {0x4f,0xaa,395054}, ++ {0x4f,0xac,396491}, ++ {0x4f,0xae,397908}, ++ {0x4f,0xb0,399303}, ++ {0x4f,0xb2,400678}, ++ {0x4f,0xb4,402034}, ++ {0x4f,0xb6,403370}, ++ {0x4f,0xb8,404688}, ++ {0x4f,0xba,405987}, ++ {0x4f,0xbc,407269}, ++ {0x4f,0xbe,408534}, ++ {0x4f,0xc0,409782}, ++ {0x4f,0xc2,411014}, ++ {0x4f,0xc4,412230}, ++ {0x4f,0xc6,413430}, ++ {0x4f,0xc8,414616}, ++ {0x4f,0xca,415787}, ++ {0x4f,0xcc,416943}, ++ {0x4f,0xce,418086}, ++ {0x4f,0xd0,419215}, ++ {0x4f,0xd2,420330}, ++ {0x4f,0xd4,421433}, ++ {0x4f,0xd6,422523}, ++ {0x4f,0xd8,423600}, ++ {0x4f,0xda,424665}, ++ {0x4f,0xdc,425719}, ++ {0x4f,0xdf,426760}, ++ {0x4f,0xe0,427791}, ++ {0x4f,0xe2,428810}, ++ {0x4f,0xe4,429819}, ++ {0x4f,0xe6,430816}, ++ {0x4f,0xe8,431804}, ++ {0x4f,0xea,432781}, ++ {0x4f,0xec,433748}, ++ {0x4f,0xee,434706}, ++ {0x4f,0xf0,435653}, ++ {0x4f,0xf2,436592}, ++ {0x4f,0xf4,437521}, ++ {0x4f,0xf6,438441}, ++ {0x4f,0xf8,439352}, ++ {0x4f,0xfa,440255}, ++ {0x4f,0xfc,441149}, ++ {0x4f,0xfe,442035}, ++ {0x5f,0x80,443135}, ++}; ++ ++static inline struct sc230ai_info *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct sc230ai_info, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct sc230ai_info, hdl)->sd; ++} ++struct regval_list { ++ uint16_t reg_num; ++ unsigned char value; ++}; ++ ++static struct regval_list sc230ai_init_regs_1920_1080_30fps_MIPI[] = { ++ {0x0103,0x01}, ++ {0x0100,0x00}, ++ {0x36e9,0x80}, ++ {0x37f9,0x80}, ++ {0x301f,0x01}, ++ {0x3221,0x06}, ++ {0x3301,0x07}, ++ {0x3304,0x50}, ++ {0x3306,0x70}, ++ {0x3308,0x18}, ++ {0x3309,0x68}, ++ {0x330a,0x01}, ++ {0x330b,0x20}, ++ {0x331e,0x41}, ++ {0x331f,0x59}, ++ {0x3333,0x10}, ++ {0x3334,0x40}, ++ {0x335d,0x60}, ++ {0x335e,0x06}, ++ {0x335f,0x08}, ++ {0x3364,0x5e}, ++ {0x337c,0x02}, ++ {0x337d,0x0a}, ++ {0x3390,0x01}, ++ {0x3391,0x0b}, ++ {0x3392,0x0f}, ++ {0x3393,0x09}, ++ {0x3394,0x0d}, ++ {0x3395,0x60}, ++ {0x3396,0x48}, ++ {0x3397,0x49}, ++ {0x3398,0x4b}, ++ {0x3399,0x06}, ++ {0x339a,0x0a}, ++ {0x339b,0x0d}, ++ {0x339c,0x60}, ++ {0x33a2,0x04}, ++ {0x33af,0x40}, ++ {0x33b1,0x80}, ++ {0x33b3,0x40}, ++ {0x33b9,0x0a}, ++ {0x33f9,0xa0}, ++ {0x33fb,0xbf}, ++ {0x33fc,0x5f}, ++ {0x33fd,0x7f}, ++ {0x349f,0x03}, ++ {0x34a6,0x4b}, ++ {0x34a7,0x5f}, ++ {0x34a8,0x30}, ++ {0x34a9,0x20}, ++ {0x34aa,0x01}, ++ {0x34ab,0x28}, ++ {0x34ac,0x01}, ++ {0x34ad,0x58}, ++ {0x34f8,0x7f}, ++ {0x34f9,0x10}, ++ {0x3630,0xc0}, ++ {0x3633,0x44}, ++ {0x363b,0x20}, ++ {0x3670,0x09}, ++ {0x3674,0xb0}, ++ {0x3675,0x80}, ++ {0x3676,0x88}, ++ {0x367c,0x40}, ++ {0x367d,0x49}, ++ {0x3690,0x44}, ++ {0x3691,0x33}, ++ {0x3692,0x43}, ++ {0x369c,0x49}, ++ {0x369d,0x4f}, ++ {0x36ae,0x4b}, ++ {0x36af,0x4f}, ++ {0x36b0,0x87}, ++ {0x36b1,0x94}, ++ {0x36b2,0xbc}, ++ {0x36d0,0x01}, ++ {0x3722,0x97}, ++ {0x3728,0x90}, ++ {0x3901,0x02}, ++ {0x3902,0xc5}, ++ {0x3904,0x04}, ++ {0x3907,0x00}, ++ {0x3908,0x41}, ++ {0x3909,0x00}, ++ {0x390a,0x00}, ++ {0x3933,0x84}, ++ {0x3934,0x10}, ++ {0x3940,0x78}, ++ {0x3942,0x04}, ++ {0x3943,0x11}, ++ {0x3e00,0x00}, ++ {0x3e01,0x8c}, ++ {0x3e02,0x20}, ++ {0x440e,0x02}, ++ {0x5010,0x01}, ++ {0x5787,0x08}, ++ {0x5788,0x03}, ++ {0x5789,0x00}, ++ {0x578a,0x10}, ++ {0x578b,0x08}, ++ {0x578c,0x00}, ++ {0x5790,0x08}, ++ {0x5791,0x04}, ++ {0x5792,0x00}, ++ {0x5793,0x10}, ++ {0x5794,0x08}, ++ {0x5795,0x00}, ++ {0x5799,0x06}, ++ {0x57ad,0x00}, ++ {0x5ae0,0xfe}, ++ {0x5ae1,0x40}, ++ {0x5ae2,0x3f}, ++ {0x5ae3,0x38}, ++ {0x5ae4,0x28}, ++ {0x5ae5,0x3f}, ++ {0x5ae6,0x38}, ++ {0x5ae7,0x28}, ++ {0x5ae8,0x3f}, ++ {0x5ae9,0x3c}, ++ {0x5aea,0x2c}, ++ {0x5aeb,0x3f}, ++ {0x5aec,0x3c}, ++ {0x5aed,0x2c}, ++ {0x5af4,0x3f}, ++ {0x5af5,0x38}, ++ {0x5af6,0x28}, ++ {0x5af7,0x3f}, ++ {0x5af8,0x38}, ++ {0x5af9,0x28}, ++ {0x5afa,0x3f}, ++ {0x5afb,0x3c}, ++ {0x5afc,0x2c}, ++ {0x5afd,0x3f}, ++ {0x5afe,0x3c}, ++ {0x5aff,0x2c}, ++ {0x36e9,0x20}, ++ {0x37f9,0x27}, ++ {SC230AI_REG_END, 0x00}, /* END MARKER */ ++}; ++ ++static struct regval_list sc230ai_init_regs_1920_1080_60fps_MIPI[] = { ++ {0x0103,0x01}, ++ {0x0100,0x00}, ++ {0x36e9,0x80}, ++ {0x37f9,0x80}, ++ {0x301f,0x02}, ++ {0x3221,0x06}, ++ {0x3301,0x09}, ++ {0x3304,0x50}, ++ {0x3306,0x48}, ++ {0x3308,0x18}, ++ {0x3309,0x68}, ++ {0x330a,0x00}, ++ {0x330b,0xc0}, ++ {0x331e,0x41}, ++ {0x331f,0x59}, ++ {0x3333,0x10}, ++ {0x3334,0x40}, ++ {0x335d,0x60}, ++ {0x335e,0x06}, ++ {0x335f,0x08}, ++ {0x3364,0x5e}, ++ {0x337c,0x02}, ++ {0x337d,0x0a}, ++ {0x3390,0x01}, ++ {0x3391,0x0b}, ++ {0x3392,0x0f}, ++ {0x3393,0x0c}, ++ {0x3394,0x0d}, ++ {0x3395,0x60}, ++ {0x3396,0x48}, ++ {0x3397,0x49}, ++ {0x3398,0x4f}, ++ {0x3399,0x0a}, ++ {0x339a,0x0f}, ++ {0x339b,0x14}, ++ {0x339c,0x60}, ++ {0x33a2,0x04}, ++ {0x33af,0x40}, ++ {0x33b1,0x80}, ++ {0x33b3,0x40}, ++ {0x33b9,0x0a}, ++ {0x33f9,0x70}, ++ {0x33fb,0x90}, ++ {0x33fc,0x4b}, ++ {0x33fd,0x5f}, ++ {0x349f,0x03}, ++ {0x34a6,0x4b}, ++ {0x34a7,0x4f}, ++ {0x34a8,0x30}, ++ {0x34a9,0x20}, ++ {0x34aa,0x00}, ++ {0x34ab,0xe0}, ++ {0x34ac,0x01}, ++ {0x34ad,0x00}, ++ {0x34f8,0x5f}, ++ {0x34f9,0x10}, ++ {0x3630,0xc0}, ++ {0x3633,0x44}, ++ {0x3637,0x29}, ++ {0x363b,0x20}, ++ {0x3670,0x09}, ++ {0x3674,0xb0}, ++ {0x3675,0x80}, ++ {0x3676,0x88}, ++ {0x367c,0x40}, ++ {0x367d,0x49}, ++ {0x3690,0x44}, ++ {0x3691,0x44}, ++ {0x3692,0x54}, ++ {0x369c,0x49}, ++ {0x369d,0x4f}, ++ {0x36ae,0x4b}, ++ {0x36af,0x4f}, ++ {0x36b0,0x87}, ++ {0x36b1,0x94}, ++ {0x36b2,0xbc}, ++ {0x36d0,0x01}, ++ {0x36ea,0x0b}, ++ {0x36eb,0x04}, ++ {0x36ec,0x0c}, ++ {0x36ed,0x24}, ++ {0x370f,0x01}, ++ {0x3722,0x17}, ++ {0x3728,0x90}, ++ {0x37b0,0x17}, ++ {0x37b1,0x17}, ++ {0x37b2,0x97}, ++ {0x37b3,0x4b}, ++ {0x37b4,0x4f}, ++ {0x37fa,0x0b}, ++ {0x37fb,0x24}, ++ {0x37fc,0x10}, ++ {0x37fd,0x22}, ++ {0x3901,0x02}, ++ {0x3902,0xc5}, ++ {0x3904,0x04}, ++ {0x3907,0x00}, ++ {0x3908,0x41}, ++ {0x3909,0x00}, ++ {0x390a,0x00}, ++ {0x391f,0x04}, ++ {0x3933,0x84}, ++ {0x3934,0x10}, ++ {0x3940,0x78}, ++ {0x3942,0x04}, ++ {0x3943,0x11}, ++ {0x3e00,0x00}, ++ {0x3e01,0x8c}, ++ {0x3e02,0x20}, ++ {0x440e,0x02}, ++ {0x5010,0x01}, ++ {0x5787,0x08}, ++ {0x5788,0x03}, ++ {0x5789,0x00}, ++ {0x578a,0x10}, ++ {0x578b,0x08}, ++ {0x578c,0x00}, ++ {0x5790,0x08}, ++ {0x5791,0x04}, ++ {0x5792,0x00}, ++ {0x5793,0x10}, ++ {0x5794,0x08}, ++ {0x5795,0x00}, ++ {0x5799,0x06}, ++ {0x57ad,0x00}, ++ {0x5ae0,0xfe}, ++ {0x5ae1,0x40}, ++ {0x5ae2,0x3f}, ++ {0x5ae3,0x38}, ++ {0x5ae4,0x28}, ++ {0x5ae5,0x3f}, ++ {0x5ae6,0x38}, ++ {0x5ae7,0x28}, ++ {0x5ae8,0x3f}, ++ {0x5ae9,0x3c}, ++ {0x5aea,0x2c}, ++ {0x5aeb,0x3f}, ++ {0x5aec,0x3c}, ++ {0x5aed,0x2c}, ++ {0x5af4,0x3f}, ++ {0x5af5,0x38}, ++ {0x5af6,0x28}, ++ {0x5af7,0x3f}, ++ {0x5af8,0x38}, ++ {0x5af9,0x28}, ++ {0x5afa,0x3f}, ++ {0x5afb,0x3c}, ++ {0x5afc,0x2c}, ++ {0x5afd,0x3f}, ++ {0x5afe,0x3c}, ++ {0x5aff,0x2c}, ++ {0x36e9,0x20}, ++ {0x37f9,0x24}, ++ {SC230AI_REG_END, 0x00}, ++}; ++ ++ ++static struct regval_list sc230ai_stream_on[] = { ++ {0x0100,0x01}, ++ {SC230AI_REG_END, 0x00}, ++}; ++ ++static struct regval_list sc230ai_stream_off[] = { ++ {0x0100,0x00}, ++ {SC230AI_REG_END, 0x00}, ++}; ++ ++ ++int sc230ai_read(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char *value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[2] = {(reg>>8)&0xff, reg&0xff}; ++ struct i2c_msg msg[2] = { ++ [0] = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = buf, ++ }, ++ [1] = { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = 1, ++ .buf = value, ++ } ++ }; ++ int ret; ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret > 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++static int sc230ai_write(struct v4l2_subdev *sd, unsigned short reg, ++ unsigned char value) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ uint8_t buf[3] = {(reg>>8)&0xff, reg&0xff, value}; ++ struct i2c_msg msg = { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 3, ++ .buf = buf, ++ }; ++ int ret; ++ unsigned int timeout = 100; ++ while(timeout--){ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if(ret == -EAGAIN){ ++ msleep(100); ++ continue; ++ } ++ else ++ break; ++ } ++ if (ret > 0) ++ ret = 0; ++ return ret; ++} ++ ++static int sc230ai_read_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ unsigned char val; ++ while (vals->reg_num != SC230AI_REG_END) { ++ if (vals->reg_num == SC230AI_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc230ai_read(sd, vals->reg_num, &val); ++ if (ret < 0) ++ return ret; ++ if (vals->reg_num == SC230AI_PAGE_REG){ ++ val &= 0xf8; ++ val |= (vals->value & 0x07); ++ ret = sc230ai_write(sd, vals->reg_num, val); ++ ret = sc230ai_read(sd, vals->reg_num, &val); ++ } ++ } ++ vals++; ++ } ++ return 0; ++} ++static int sc230ai_write_array(struct v4l2_subdev *sd, struct regval_list *vals) ++{ ++ int ret; ++ while (vals->reg_num != SC230AI_REG_END) { ++ if (vals->reg_num == SC230AI_REG_DELAY) { ++ msleep(vals->value); ++ } else { ++ ret = sc230ai_write(sd, vals->reg_num, vals->value); ++ if (ret < 0) ++ return ret; ++ } ++ vals++; ++ } ++ return 0; ++} ++ ++ ++/* ++ * Stuff that knows about the sensor. ++ */ ++static int sc230ai_lightup(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->led.pin, info->led.active_level); ++ } else { ++ gpio_direction_output(info->led.pin, !info->led.active_level); ++ } ++ return 0; ++} ++ ++static int sc230ai_xshutdn(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->xshutdn.pin, info->xshutdn.active_level); ++ } else { ++ gpio_direction_output(info->xshutdn.pin, !info->xshutdn.active_level); ++ } ++ return 0; ++} ++ ++static int sc230ai_pwdn(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ ++ if(val) { ++ gpio_direction_output(info->pwdn.pin, info->pwdn.active_level); ++ msleep(10); ++ } else { ++ gpio_direction_output(info->pwdn.pin, !info->pwdn.active_level); ++ } ++ return 0; ++} ++ ++static int sc230ai_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ unsigned char v; ++ int ret; ++ ++ /*software reset*/ ++ ret = sc230ai_read(sd, 0x0103, &v); ++ ++ if(val) { ++ v |= 1; ++ ret += sc230ai_write(sd, 0x0103, v); ++ } ++ return 0; ++} ++ ++ ++static int sc230ai_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ int ret = 0; ++ ++ ret = sc230ai_write_array(sd, info->win->regs); ++ ++ return ret; ++} ++ ++ ++static int sc230ai_detect(struct v4l2_subdev *sd, unsigned int *ident) ++{ ++ unsigned char v; ++ int ret; ++ ++ ret = sc230ai_read(sd, 0x3107, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC230AI_CHIP_ID_H) ++ return -ENODEV; ++ *ident = v; ++ ++ ret = sc230ai_read(sd, 0x3108, &v); ++ pr_debug("-----%s: %d ret = %d, v = 0x%02x\n", __func__, __LINE__, ret,v); ++ if (ret < 0) ++ return ret; ++ if (v != SC230AI_CHIP_ID_L) ++ return -ENODEV; ++ *ident = (*ident << 8) | v; ++ return 0; ++ ++} ++ ++static struct sc230ai_win_size sc230ai_win_sizes[] = { ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 30 << 16 | 1, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc230ai_init_regs_1920_1080_30fps_MIPI, ++ }, ++ { ++ .width = 1920, ++ .height = 1080, ++ .sensor_info.fps = 60 << 16 | 1, ++ .sensor_info.mipi_cfg.twidth = 1920, ++ .sensor_info.mipi_cfg.theight = 1080, ++ .sensor_info.mipi_cfg.mipi_crop_start0x = 0, ++ .sensor_info.mipi_cfg.mipi_crop_start0y = 0, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ .regs = sc230ai_init_regs_1920_1080_60fps_MIPI, ++ }, ++}; ++ ++static int sc230ai_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++#if 0 ++ if (code->pad || code->index >= N_SC230AI_FMTS) ++ return -EINVAL; ++ ++ code->code = sc230ai_formats[code->index].mbus_code; ++#endif ++ return 0; ++} ++ ++/* ++ * Set a format. ++ */ ++static int sc230ai_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc230ai_format_struct *ovfmt; ++ struct sc230ai_win_size *wsize; ++ struct sc230ai_info *info = to_state(sd); ++ int ret; ++ ++ if (format->pad) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int sc230ai_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ int ret = 0; ++ ++ if(!info->win) { ++ dev_err(sd->dev, "sensor win_size not set!\n"); ++ return -EINVAL; ++ } ++ ++ fmt->width = info->win->width; ++ fmt->height = info->win->height; ++ fmt->code = info->win->mbus_code; ++ fmt->colorspace = info->win->colorspace; ++ *(unsigned int *)fmt->reserved = &info->win->sensor_info; ++ ++ ++// printk("----%s, %d, width: %d, height: %d, code: %x\n", ++// __func__, __LINE__, fmt->width, fmt->height, fmt->code); ++ ++ return ret; ++} ++ ++static int sc230ai_s_brightness(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc230ai_s_contrast(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc230ai_s_hflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc230ai_s_vflip(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++/* ++ * GAIN is split between REG_GAIN and REG_VREF[7:6]. If one believes ++ * the data sheet, the VREF parts should be the most significant, but ++ * experience shows otherwise. There seems to be little value in ++ * messing with the VREF bits, so we leave them alone. ++ */ ++static int sc230ai_g_gain(struct v4l2_subdev *sd, __s32 *value) ++{ ++ int ret = 0; ++ unsigned char gain = 0; ++ ++ *value = gain; ++ return ret; ++} ++ ++static int sc230ai_s_gain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++// printk("---%s, %d, s_gain: value: %d\n", __func__, __LINE__, value); ++ ++ return ret; ++} ++ ++static unsigned int again_to_regval(int gain, unsigned int *value, unsigned int *fine_value) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc230ai_again_lut); i++) { ++ lut = &sc230ai_again_lut[i]; ++ ++ if(gain <= lut->gain) { ++ *value = lut->value; ++ *fine_value = lut->fine_value; ++ return lut->value; ++ } ++ } ++ /*last value.*/ ++ *value = lut->value; ++ *fine_value = lut->fine_value; ++ return lut->value; ++} ++ ++static int regval_to_again(unsigned int regval, unsigned int fine_reg_val) ++{ ++ struct again_lut *lut = NULL; ++ int i = 0; ++ for(i = 0; i < ARRAY_SIZE(sc230ai_again_lut); i++) { ++ lut = &sc230ai_again_lut[i]; ++ ++ if(regval == lut->value && fine_reg_val == lut->fine_value) { ++ return lut->gain; ++ } ++ } ++ printk("%s, %d regval not mapped to isp gain\n", __func__, __LINE__); ++ return -EINVAL; ++} ++ ++static int sc230ai_g_again(struct v4l2_subdev *sd, __s32 *value) ++{ ++ char v = 0; ++ unsigned int reg_val = 0; ++ unsigned int fine_reg_val = 0; ++ int ret = 0; ++ ++ ++ ret = sc230ai_read(sd, 0x3e09, &v); ++ reg_val = v ; ++ ret = sc230ai_read(sd, 0x3e07, &v); ++ fine_reg_val = v ; ++ ++ *value = regval_to_again(reg_val, fine_reg_val); ++ ++ return ret; ++ ++} ++/*set analog gain db value, map value to sensor register.*/ ++static int sc230ai_s_again(struct v4l2_subdev *sd, int value) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ unsigned int reg_value; ++ unsigned int reg_fine_value; ++ int ret = 0; ++ ++ if(value < info->again->minimum || value > info->again->maximum) { ++ /* use default value. */ ++ again_to_regval(info->again->default_value, ®_value, ®_fine_value); ++ } else { ++ again_to_regval(value, ®_value, ®_fine_value); ++ } ++ ++ ret += sc230ai_write(sd, 0x3e09, (unsigned char)(reg_value)); ++ ret += sc230ai_write(sd, 0x3e07, (unsigned char)(reg_fine_value)); ++ if (ret < 0){ ++ printk("sc230ai_write error %d\n" ,__LINE__ ); ++ return ret; ++ } ++ return 0; ++} ++ ++/* ++ * Tweak autogain. ++ */ ++static int sc230ai_s_autogain(struct v4l2_subdev *sd, int value) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static int sc230ai_s_exp(struct v4l2_subdev *sd, int value) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ int ret = 0; ++ ++ value *= 2; /*unit in half line*/ ++ ret += sc230ai_write(sd, 0x3e00, (unsigned char)((value >> 12) & 0xf)); ++ ret += sc230ai_write(sd, 0x3e01, (unsigned char)((value >> 4) & 0xff)); ++ ret += sc230ai_write(sd, 0x3e02, (unsigned char)(value & 0xf) << 4); ++ ++ if (ret < 0) { ++ printk("sc230ai_write error %d\n" ,__LINE__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int sc230ai_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc230ai_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_AUTOGAIN: ++ return sc230ai_g_gain(sd, &info->gain->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc230ai_g_again(sd, &info->again->val); ++ } ++ return -EINVAL; ++} ++ ++static int sc230ai_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct sc230ai_info *info = to_state(sd); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ return sc230ai_s_brightness(sd, ctrl->val); ++ case V4L2_CID_CONTRAST: ++ return sc230ai_s_contrast(sd, ctrl->val); ++ case V4L2_CID_VFLIP: ++ return sc230ai_s_vflip(sd, ctrl->val); ++ case V4L2_CID_HFLIP: ++ return sc230ai_s_hflip(sd, ctrl->val); ++ case V4L2_CID_AUTOGAIN: ++ /* Only set manual gain if auto gain is not explicitly ++ turned on. */ ++ if (!ctrl->val) { ++ /* sc230ai_s_gain turns off auto gain */ ++ return sc230ai_s_gain(sd, info->gain->val); ++ } ++ return sc230ai_s_autogain(sd, ctrl->val); ++ case V4L2_CID_GAIN: ++ return sc230ai_s_gain(sd, ctrl->val); ++ case V4L2_CID_ANALOGUE_GAIN: ++ return sc230ai_s_again(sd, ctrl->val); ++ case V4L2_CID_EXPOSURE: ++ return sc230ai_s_exp(sd, ctrl->val); ++ } ++ return -EINVAL; ++} ++ ++static const struct v4l2_ctrl_ops sc230ai_ctrl_ops = { ++ .s_ctrl = sc230ai_s_ctrl, ++ .g_volatile_ctrl = sc230ai_g_volatile_ctrl, ++}; ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int sc230ai_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) ++{ ++ unsigned char val = 0; ++ int ret; ++ ++ ret = sc230ai_read(sd, reg->reg & 0xffff, &val); ++ reg->val = val; ++ reg->size = 1; ++ return ret; ++} ++ ++static int sc230ai_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) ++{ ++ sc230ai_write(sd, reg->reg & 0xffff, reg->val & 0xff); ++ return 0; ++} ++#endif ++ ++static int sc230ai_power(struct v4l2_subdev *sd, int on) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ ++ info->supply.avdd = devm_regulator_get_optional(&client->dev, "avdd"); ++ info->supply.dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); ++ info->supply.dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); ++ ++ if (IS_ERR(info->supply.avdd)||IS_ERR(info->supply.dvdd) ++ ||IS_ERR(info->supply.dovdd)) { ++ if ((PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.avdd) == -EPROBE_DEFER) ++ ||(PTR_ERR(info->supply.avdd) == -EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ printk("No sc230ai vdd regulator found\n"); ++ } ++ ++ if ((!IS_ERR(info->supply.avdd))&&(!IS_ERR(info->supply.avdd)) ++ &&(!IS_ERR(info->supply.avdd))) { ++ if(on){ ++ ret = regulator_enable(info->supply.avdd); ++ ret = regulator_enable(info->supply.dvdd); ++ ret = regulator_enable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "sc230ai vdd supply disable failed\n"); ++ } ++ else{ ++ ret = regulator_disable(info->supply.avdd); ++ ret = regulator_disable(info->supply.dvdd); ++ ret = regulator_disable(info->supply.dovdd); ++ if (ret) ++ dev_err(&client->dev, "sc230ai vdd supply disable failed\n"); ++ } ++ }else{ ++ dev_err(&client->dev, "sc230ai vdd supply IS_ERR failed\n"); ++ } ++ return ret; ++} ++ ++ ++ ++int sc230ai_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ int ret = 0; ++ ++ if (enable) { ++ ret = sc230ai_write_array(sd, sc230ai_stream_on); ++ printk("sc230ai stream on\n"); ++ ++ } ++ else { ++ ret = sc230ai_write_array(sd, sc230ai_stream_off); ++ printk("sc230ai stream off\n"); ++ } ++ return ret; ++} ++ ++ ++int sc230ai_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) ++{ ++ struct sc230ai_info *info = to_state(sd); ++ if(info->win->sensor_info.fps){ ++ interval->interval.numerator = info->win->sensor_info.fps & 0xffff; ++ interval->interval.denominator = info->win->sensor_info.fps >> 16; ++ return 0; ++ } ++ return -EINVAL; ++} ++/* ----------------------------------------------------------------------- */ ++ ++static const struct v4l2_subdev_core_ops sc230ai_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = sc230ai_g_register, ++ .s_register = sc230ai_s_register, ++#endif ++ ++}; ++ ++static const struct v4l2_subdev_video_ops sc230ai_video_ops = { ++ .s_stream = sc230ai_s_stream, ++ .g_frame_interval = sc230ai_g_frame_interval, ++}; ++ ++static const struct v4l2_subdev_pad_ops sc230ai_pad_ops = { ++ //.enum_frame_interval = sc230ai_enum_frame_interval, ++ //.num_frame_size = sc230ai_enum_frame_size, ++ //.enum_mbus_code = sc230ai_enum_mbus_code, ++ .set_fmt = sc230ai_set_fmt, ++ .get_fmt = sc230ai_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops sc230ai_ops = { ++ .core = &sc230ai_core_ops, ++ .video = &sc230ai_video_ops, ++ .pad = &sc230ai_pad_ops, ++}; ++ ++/* ----------------------------------------------------------------------- */ ++ ++static int sc230ai_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct v4l2_subdev *sd; ++ struct sc230ai_info *info; ++ int ret; ++ unsigned int ident = 0; ++ int gpio = -EINVAL; ++ unsigned int flags; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (info == NULL) ++ return -ENOMEM; ++ sd = &info->sd; ++ ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,xshutdn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->xshutdn.pin = gpio; ++ info->xshutdn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,pwdn-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->pwdn.pin = gpio; ++ info->pwdn.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,efsync-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->efsync.pin = gpio; ++ info->efsync.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ gpio = of_get_named_gpio_flags(client->dev.of_node, "ingenic,led-gpio", 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ info->led.pin = gpio; ++ info->led.active_level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ } ++ ++ ++ v4l2_i2c_subdev_init(sd, client, &sc230ai_ops); ++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ ++ sc230ai_power(sd,1); ++ ++ /*clk*/ ++ info->clk = v4l2_clk_get(&client->dev, "div_cim"); ++ if (IS_ERR(info->clk)) { ++ ret = PTR_ERR(info->clk); ++ goto err_clkget; ++ } ++ ++ ret = v4l2_clk_set_rate(info->clk, 24000000); ++ if(ret) ++ dev_err(sd->dev, "clk_set_rate err!\n"); ++ ++ ret = v4l2_clk_enable(info->clk); ++ if(ret) ++ dev_err(sd->dev, "clk_enable err!\n"); ++ ++ sc230ai_xshutdn(sd, 1); ++ sc230ai_pwdn(sd, 1); ++ sc230ai_lightup(sd, 0); ++ sc230ai_reset(sd, 1); ++#if 1 ++ /* Make sure it's an sc230ai */ ++ ret = sc230ai_detect(sd, &ident); ++ if (ret) { ++ v4l_err(client, ++ "chip found @ 0x%x (%s) is not an sc230ai chip.\n", ++ client->addr << 1, client->adapter->name); ++ return ret; ++ } ++#endif ++ ++ v4l_info(client, "chip found @ 0x%02x (%s)\n", ++ client->addr << 1, client->adapter->name); ++ ++ v4l2_ctrl_handler_init(&info->hdl, 8); ++ v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); ++ v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 127, 1, 64); ++ v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ info->gain = v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_GAIN, 0, 255, 1, 128); ++ info->again = v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_ANALOGUE_GAIN, 0, 443135, 1, 10000); ++ /*unit exposure lines: */ ++ info->exposure = v4l2_ctrl_new_std(&info->hdl, &sc230ai_ctrl_ops, ++ V4L2_CID_EXPOSURE, 1, 1152 - 4 , 4, 600); ++ ++ sd->ctrl_handler = &info->hdl; ++ if (info->hdl.error) { ++ int err = info->hdl.error; ++ ++ v4l2_ctrl_handler_free(&info->hdl); ++ return err; ++ } ++ v4l2_ctrl_handler_setup(&info->hdl); ++ ++ info->win = &sc230ai_win_sizes[0]; ++ sc230ai_init(sd, 1); ++ ++ info->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); ++ if(ret < 0) { ++ goto err_entity_init; ++ } ++ info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ ret = v4l2_async_register_subdev(&info->sd); ++ if (ret < 0) ++ goto err_videoprobe; ++ ++ dev_info(&client->dev, "sc230ai Probed\n"); ++ return 0; ++err_videoprobe: ++err_entity_init: ++ v4l2_clk_put(info->clk); ++err_clkget: ++ return ret; ++} ++ ++ ++static int sc230ai_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct sc230ai_info *info = to_state(sd); ++ ++ v4l2_device_unregister_subdev(sd); ++ v4l2_ctrl_handler_free(&info->hdl); ++ v4l2_clk_put(info->clk); ++ return 0; ++} ++ ++static const struct i2c_device_id sc230ai_id[] = { ++ { "sc230ai", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, sc230ai_id); ++ ++static const struct of_device_id sc230ai_of_match[] = { ++ {.compatible = "smartsens,sc230ai", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sc230ai_of_match); ++ ++ ++static int sc230ai_suspend(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct sc230ai_info *info = to_state(sd); ++ int ret=0; ++ ++ sc230ai_power(sd,0); ++ v4l2_clk_disable(info->clk); ++ return 0; ++} ++ ++static int sc230ai_resume(struct device *dev) ++{ ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct sc230ai_info *info = to_state(sd); ++ int ret=0; ++ ++ sc230ai_power(sd,1); ++ v4l2_clk_enable(info->clk); ++ sc230ai_reset(sd, 1); ++ sc230ai_init(sd, 1); ++ return 0; ++} ++ ++const struct dev_pm_ops sc230ai_pm = ++{ ++ .suspend = sc230ai_suspend, ++ .resume = sc230ai_resume, ++}; ++ ++ ++static struct i2c_driver sc230ai_driver = { ++ .driver = { ++ .name = "sc230ai", ++ .of_match_table = of_match_ptr(sc230ai_of_match), ++ .pm = &sc230ai_pm, ++ }, ++ .probe = sc230ai_probe, ++ .remove = sc230ai_remove, ++ .id_table = sc230ai_id, ++}; ++ ++module_i2c_driver(sc230ai_driver); ++MODULE_AUTHOR("qpz "); ++MODULE_DESCRIPTION("A low-level driver for SmartSens sc230ai sensors"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/platform/Kconfig b/module_drivers/drivers/media/platform/Kconfig +new file mode 100644 +index 000000000..1296b5b56 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/Kconfig +@@ -0,0 +1,41 @@ ++menu "[ISP] Drivers" ++ ++ ++config VIDEO_INGENIC_ISP ++ tristate "V4L2 Driver for ingenic isp" ++ depends on VIDEO_DEV && VIDEO_V4L2 ++ depends on SOC_X2000_V12 || SOC_X2000 || SOC_M300 || SOC_X2100 ++ select VIDEOBUF2_DMA_CONTIG ++ select VIDEOBUF2_DMA_CONTIG_INGENIC ++source "module_drivers/drivers/media/platform/ingenic-isp/Kconfig" ++ ++ ++config VIDEO_INGENIC_ISP_V2 ++ tristate "V4L2 Driver for ingenic isp version 2" ++ depends on VIDEO_DEV && VIDEO_V4L2 ++ depends on SOC_X2500 ++ select VIDEOBUF2_DMA_CONTIG ++ select VIDEOBUF2_DMA_CONTIG_INGENIC ++source "module_drivers/drivers/media/platform/ingenic-isp-v2/Kconfig" ++endmenu ++ ++menu "[CIM] Drivers" ++ depends on SOC_X2000_V12 || SOC_X2000 || SOC_M300 || SOC_X1600 || SOC_X2100 ++source "module_drivers/drivers/media/platform/ingenic-cim/Kconfig" ++endmenu ++ ++ ++menu "[Rotator] Drivers" ++ depends on SOC_X2000_V12 || SOC_X2000 || SOC_M300 || SOC_X2100 ++source "module_drivers/drivers/media/platform/ingenic-rotate/Kconfig" ++endmenu ++ ++menu "[I2D] Drivers" ++ depends on SOC_X2500 ++source "module_drivers/drivers/media/platform/ingenic-i2d/Kconfig" ++endmenu ++ ++menu "[VPU] Drivers" ++ depends on SOC_X2000_V12 || SOC_X2000 || SOC_M300 || SOC_X2100 ++source "module_drivers/drivers/media/platform/ingenic-vcodec/Kconfig" ++endmenu +diff --git a/module_drivers/drivers/media/platform/Makefile b/module_drivers/drivers/media/platform/Makefile +new file mode 100644 +index 000000000..9defda6d7 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/Makefile +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_VIDEO_INGENIC_ISP) += ingenic-isp/ ++obj-$(CONFIG_VIDEO_INGENIC_ISP_V2) += ingenic-isp-v2/ ++obj-$(CONFIG_VIDEO_INGENIC_ROTATE) += ingenic-rotate/ ++obj-$(CONFIG_VIDEO_INGENIC_VCODEC) += ingenic-vcodec/ ++obj-$(CONFIG_INGENIC_I2D) += ingenic-i2d/ ++obj-$(CONFIG_VIDEO_INGENIC_CIM) += ingenic-cim/ +diff --git a/module_drivers/drivers/media/platform/ingenic-cim/Kconfig b/module_drivers/drivers/media/platform/ingenic-cim/Kconfig +new file mode 100644 +index 000000000..c230a6a98 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-cim/Kconfig +@@ -0,0 +1,82 @@ ++config VIDEO_INGENIC_CIM ++ tristate "Ingenic Soc Camera Driver for X2000 && M300 && X1600" ++ select VIDEOBUF2_DMA_CONTIG_INGENIC ++ select V4L2_FWNODE ++ help ++ CIM Driver for X2000 && M300 && X1600 ++ ++config CAMERA_USE_SNAPSHOT ++ bool "Sensor support snapshot function" ++ depends on VIDEO_INGENIC_CIM ++ help ++ Sensor support snapshot function ++ ++config SNAPSHOT_PULSE_WIDTH ++ int "Snapshot pulse width" ++ depends on CAMERA_USE_SNAPSHOT ++ default 8 ++ help ++ Snapshot pulse width ++ ++config SNAPSHOT_FRAME_DELAY ++ int "One frame end delay" ++ depends on CAMERA_USE_SNAPSHOT ++ default 100 ++ help ++ One frame end delay ++ ++menuconfig PANDA_CAMERA_BOARD ++ bool "panda_camera_board" ++ depends on VIDEO_INGENIC_CIM ++ depends on SOC_X1600 ++ default n ++ help ++ Say Y here to enable support for panda_camera_boards. ++ ++config RD_X1600_PANDA_MIPI_CAMERA_1V0 ++ bool "panda camera driver for RD_X1600_PANDA_MIPI_CAMERA_1V0" ++ depends on PANDA_CAMERA_BOARD ++ select INGENIC_CIM_CAMERA_OV5645 ++ ++config RD_X1600_PANDA_MIPI_CAMERA_2V0 ++ bool "panda camera driver for RD_X1600_PANDA_MIPI_CAMERA_2V0" ++ depends on PANDA_CAMERA_BOARD ++ select INGENIC_CIM_CAMERA_OV9281 ++ ++config RD_X1600_PANDA_MIPI_CAMERA_3V2 ++ bool "panda camera driver for RD_X1600_PANDA_MIPI_CAMERA_3V2" ++ depends on PANDA_CAMERA_BOARD ++ select INGENIC_CIM_CAMERA_OV4689 ++ ++config RD_X1600_PANDA_DVP_CAMERA_1V0 ++ bool "panda camera driver for RD_X1600_PANDA_DVP_CAMERA_V1.0" ++ depends on PANDA_CAMERA_BOARD ++ select INGENIC_CIM_CAMERA_SC031GS ++ ++config RD_X1600_PANDA_DVP_CAMERA_AND_LCD_1V0 ++ bool "panda camera driver for RD_X1600_PANDA_DVP_CAMERA_AND_LCD_V1.0" ++ depends on PANDA_CAMERA_BOARD ++ select INGENIC_CIM_CAMERA_OV5640 ++ ++config RD_X1600_PANDA_DVP_CAMERA_2V0 ++ bool "panda camera driver for RD_X1600_PANDA_DVP_CAMERA_V2.0" ++ depends on PANDA_CAMERA_BOARD ++ select INGENIC_CIM_CAMERA_OV9281_DVP_SNAPSHOT ++ ++menuconfig HALLEY6_CAMERA_BOARD ++ bool "halley6_camera_board" ++ depends on VIDEO_INGENIC_CIM ++ depends on SOC_X1600 ++ default n ++ help ++ Say Y here to enable support for panda_camera_boards. ++ ++config RD_X1600_HALLEY6_MIPI_CAMERA ++ bool "halley6 camera driver for RD_X1600_HALLEY6_MIPI_CAMERA" ++ depends on HALLEY6_CAMERA_BOARD ++ select INGENIC_CIM_CAMERA_MIPI_SC031GS ++ ++config RD_X1600_HALLEY6_DVP_CAMERA ++ bool "halley6 camera driver for RD_X1600_HALLEY6_DVP_CAMERA" ++ depends on HALLEY6_CAMERA_BOARD ++ select INGENIC_CIM_CAMERA_SC031GS +diff --git a/module_drivers/drivers/media/platform/ingenic-cim/Makefile b/module_drivers/drivers/media/platform/ingenic-cim/Makefile +new file mode 100644 +index 000000000..520cd2c08 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-cim/Makefile +@@ -0,0 +1,2 @@ ++obj-y += ingenic_camera.o mipi_csi.o ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-cim/ingenic_camera.c b/module_drivers/drivers/media/platform/ingenic-cim/ingenic_camera.c +new file mode 100644 +index 000000000..6b016518b +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-cim/ingenic_camera.c +@@ -0,0 +1,2566 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Core file for Ingenic Display Controller driver ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic_camera.h" ++#include "mipi_csi.h" ++#include ++#include ++#include ++#include ++ ++ ++ ++int max_buffer_num = 3; ++module_param(max_buffer_num, int, 0644); ++MODULE_PARM_DESC(max_buffer_num, "cim max buffer number"); ++ ++static int frame_size_check_flag = 0; ++static int showFPS = 0; ++ ++struct cim_video_format cim_formats[] = { ++ /*MONO */ ++ { ++ .name = "Y8, GREY", ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .name = "Y10, Y10 ", ++ .fourcc = V4L2_PIX_FMT_Y10, ++ .depth = {10}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_Y10_1X10, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ }, ++ { ++ .name = "Y12, Y12 ", ++ .fourcc = V4L2_PIX_FMT_Y12, ++ .depth = {12}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_Y12_1X12, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ }, ++ /*yuv422 */ ++ { ++ .name = "YUV422, YUYV", ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "YUV422, YVYU", ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "YUV422, UYVY", ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "YUV422, VYUY", ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ /*RGB*/ ++ { ++ .name = "RGB565, RGBP", ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "RBG565, RBGP", ++ .fourcc = INGENIC_V4L2_PIX_FMT_RBG565, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = INGENIC_MEDIA_BUS_FMT_RBG565_2X8_LE, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "BGR565, BGRP", ++ .fourcc = INGENIC_V4L2_PIX_FMT_BGR565, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_BGR565_2X8_LE, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "BRG565, BRGP", ++ .fourcc = INGENIC_V4L2_PIX_FMT_BRG565, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = INGENIC_MEDIA_BUS_FMT_BRG565_2X8_LE, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "GRB565, GRBP", ++ .fourcc = INGENIC_V4L2_PIX_FMT_GRB565, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = INGENIC_MEDIA_BUS_FMT_GRB565_2X8_LE, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "GBR565, GBRP", ++ .fourcc = INGENIC_V4L2_PIX_FMT_GBR565, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = INGENIC_MEDIA_BUS_FMT_GBR565_2X8_LE, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "GBR888, GBR3", ++ .fourcc = V4L2_PIX_FMT_RGB24, ++ .depth = {24}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ /* RAW8 */ ++ { ++ .name = "RAW8, 8 BGBG.. GRGR..", ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW8, 8 GBGB.. RGRG..", ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW8, 8 GRGR.. BGBG..", ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW8, 8 RGRG.. GBGB..", ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ /* RAW10 */ ++ { ++ .name = "RAW10, 10 BGBG.. GRGR..", ++ .fourcc = V4L2_PIX_FMT_SBGGR10, ++ .depth = {10}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW10, 10 GBGB.. RGRG..", ++ .fourcc = V4L2_PIX_FMT_SGBRG10, ++ .depth = {10}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW10, 10 GRGR.. BGBG..", ++ .fourcc = V4L2_PIX_FMT_SGRBG10, ++ .depth = {10}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW10, 10 RGRG.. GBGB..", ++ .fourcc = V4L2_PIX_FMT_SRGGB10, ++ .depth = {10}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ /* RAW12 */ ++ { ++ .name = "RAW12, 12 BGBG.. GRGR..", ++ .fourcc = V4L2_PIX_FMT_SBGGR12, ++ .depth = {12}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW12, 12 GBGB.. RGRG..", ++ .fourcc = V4L2_PIX_FMT_SGBRG12, ++ .depth = {12}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW12, 12 GRGR.. BGBG..", ++ .fourcc = V4L2_PIX_FMT_SGRBG12, ++ .depth = {12}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW12, 12 RGRG.. GBGB..", ++ .fourcc = V4L2_PIX_FMT_SRGGB12, ++ .depth = {12}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++}; ++ ++ ++static struct ingenic_camera_dev *v4l2_dev_to_pcdev(struct v4l2_device *v4l2_dev) ++{ ++ return container_of(v4l2_dev, struct ingenic_camera_dev, v4l2_dev); ++} ++ ++static struct cim_video_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) ++{ ++ return container_of(ctrl->handler, struct cim_video_ctx, hdl); ++} ++ ++static int get_asd_index(struct v4l2_async_subdev *asd) ++{ ++ struct cim_async_subdev *casd = container_of(asd, struct cim_async_subdev, asd); ++ return casd->index; ++} ++ ++static int is_cim_disabled(struct ingenic_camera_dev *pcdev) ++{ ++ return !(cim_readl(pcdev, CIM_ST) & CIM_ST_WORKING); ++} ++ ++static int ingenic_cim_get_video_nr(int index) ++{ ++ if(index == 0) ++ return INGENIC_CIM_VIDEO_NR_0; ++ else if(index == 1) ++ return INGENIC_CIM_VIDEO_NR_1; ++ else ++ return 0; ++} ++ ++void cim_dump_reg(struct ingenic_camera_dev *pcdev) ++{ ++ if(!pcdev) { ++ printk("===>>%s,%d pcdev is NULL!\n",__func__,__LINE__); ++ return; ++ } ++ printk("\n***************************************\n"); ++ printk("GLB_CFG 0x%08x\n", cim_readl(pcdev, GLB_CFG)); ++ printk("FRM_SIZE 0x%08x\n", cim_readl(pcdev, FRM_SIZE)); ++ printk("CROP_SITE 0x%08x\n", cim_readl(pcdev, CROP_SITE)); ++ printk("RESIZE_CFG 0x%08x\n", cim_readl(pcdev, RESIZE_CFG)); ++ printk("RESIZE_COEF_X 0x%08x\n", cim_readl(pcdev, RESIZE_COEF_X)); ++ printk("RESIZE_COEF_Y 0x%08x\n", cim_readl(pcdev, RESIZE_COEF_Y)); ++ printk("SCAN_CFG 0x%08x\n", cim_readl(pcdev, SCAN_CFG)); ++ printk("QOS_CTRL 0x%08x\n", cim_readl(pcdev, QOS_CTRL)); ++ printk("QOS_CFG 0x%08x\n", cim_readl(pcdev, QOS_CFG)); ++ printk("DLY_CFG 0x%08x\n", cim_readl(pcdev, DLY_CFG)); ++ printk("DES_ADDR 0x%08x\n", cim_readl(pcdev, DES_ADDR)); ++ printk("CIM_ST 0x%08x\n", cim_readl(pcdev, CIM_ST)); ++ printk("CIM_CLR_ST 0x%08x\n", cim_readl(pcdev, CIM_CLR_ST)); ++ printk("CIM_INTC 0x%08x\n", cim_readl(pcdev, CIM_INTC)); ++ printk("INT_FLAG 0x%08x\n", cim_readl(pcdev, INT_FLAG)); ++ printk("FRAME_ID 0x%08x\n", cim_readl(pcdev, FRAME_ID)); ++ printk("ACT_SIZE 0x%08x\n", cim_readl(pcdev, ACT_SIZE)); ++ printk("DBG_CGC 0x%08x\n", cim_readl(pcdev, DBG_CGC)); ++ printk("***************************************\n\n"); ++} ++ ++void cim_dump_reg_des(struct ingenic_camera_dev *pcdev) ++{ ++ int version = pcdev->cim_priv->version_num; ++ printk("\n***************************************\n"); ++ printk("DBG_DES next 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DBG_DES WRBK_ADDR: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DBG_DES WRBK_STRD: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DBG_DES DES_INTC_t: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DBG_DES DES_CFG_t: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ if (version == 2) { ++ printk("DES_HIST_CFG_t: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("HIST_WRBK_ADDR: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ } else { ++ printk("DES_HIST_CFG_t: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("HIST_WRBK_ADDR: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ } ++ printk("SF_WRBK_ADDR: 0x%08x\n", cim_readl(pcdev, DBG_DES)); ++ printk("DBG_DMA: 0x%08x\n", cim_readl(pcdev, DBG_DMA)); ++ printk("***************************************\n\n"); ++} ++ ++void cim_dump_des(struct ingenic_camera_dev *pcdev) ++{ ++ struct ingenic_camera_desc_v1 *desc_v1 = NULL; ++ struct ingenic_camera_desc_v2 *desc_v2 = NULL; ++ int i; ++ int version = pcdev->cim_priv->version_num; ++ if (version == 1) { ++ desc_v1 = (struct ingenic_camera_desc_v1 *)pcdev->desc_vaddr; ++ printk("\n***************************************\n"); ++ for(i = 0; i < pcdev->buf_cnt; i++) { ++ printk("print des %d\n",i); ++ printk("next: 0x%08x\n", desc_v1[i].next); ++ printk("WRBK_ADDR: 0x%08x\n", desc_v1[i].WRBK_ADDR); ++ printk("WRBK_STRD: 0x%08x\n", desc_v1[i].WRBK_STRD); ++ printk("DES_INTC_t: 0x%08x\n", desc_v1[i].DES_INTC_t.d32); ++ printk("DES_CFG_t: 0x%08x\n", desc_v1[i].DES_CFG_t.d32); ++ printk("DES_HIST_CFG_t: 0x%08x\n", desc_v1[i].DES_HIST_CFG_t.d32); ++ printk("HIST_WRBK_ADDR: 0x%08x\n", desc_v1[i].HIST_WRBK_ADDR); ++ printk("SF_WRBK_ADDR: 0x%08x\n", desc_v1[i].SF_WRBK_ADDR); ++ } ++ printk("***************************************\n\n"); ++ } else { ++ desc_v2 = (struct ingenic_camera_desc_v2 *)pcdev->desc_vaddr; ++ printk("\n***************************************\n"); ++ for(i = 0; i < pcdev->buf_cnt; i++) { ++ printk("print des %d\n",i); ++ printk("next: 0x%08x\n", desc_v2[i].next); ++ printk("WRBK_ADDR: 0x%08x\n", desc_v2[i].WRBK_ADDR); ++ printk("WRBK_STRD: 0x%08x\n", desc_v2[i].WRBK_STRD); ++ printk("DES_INTC_t: 0x%08x\n", desc_v2[i].DES_INTC_t.d32); ++ printk("DES_CFG_t: 0x%08x\n", desc_v2[i].DES_CFG_t.d32); ++ printk("DES_LUMI_CFG_t: 0x%08x\n", desc_v2[i].DES_LUMI_CFG_t.d32); ++ printk("LUMI_WRBK_ADDR: 0x%08x\n", desc_v2[i].LUMI_WRBK_ADDR); ++ printk("SF_WRBK_ADDR: 0x%08x\n", desc_v2[i].SF_WRBK_ADDR); ++ } ++ printk("***************************************\n\n"); ++ } ++} ++ ++static void calculate_frame_rate(void) ++{ ++ static ktime_t time_now, time_last; ++ unsigned int interval_in_us; ++ static unsigned int fpsCount = 0; ++ ++ switch(showFPS){ ++ case 1: ++ fpsCount++; ++ time_now = ktime_get(); ++ interval_in_us =time_now - time_last; ++ if ( interval_in_us > (NSEC_PER_SEC) ) { /* 1 second = 1000000 us. */ ++ printk(" CIM FPS: %d\n",fpsCount); ++ fpsCount = 0; ++ time_last = time_now; ++ } ++ break; ++ case 2: ++ time_now = ktime_get(); ++ interval_in_us =time_now - time_last; ++ printk(" CIM tow frame interval in ns: %d\n",interval_in_us); ++ time_last = time_now; ++ break; ++ default: ++ if (showFPS > 2) { ++ int d, f; ++ fpsCount++; ++ time_now = ktime_get(); ++ interval_in_us =time_now - time_last; ++ if (interval_in_us > NSEC_PER_SEC * showFPS ) { /* 1 second = 1000000 us. */ ++ d = fpsCount / showFPS; ++ f = (fpsCount * 10) / showFPS - d * 10; ++ printk(" CIM FPS: %d.%01d\n", d, f); ++ fpsCount = 0; ++ time_last = time_now; ++ } ++ } ++ break; ++ } ++} ++ ++ ++ ++static unsigned int fourcc_to_mbus_code(unsigned int fourcc){ ++ const struct cim_video_format *fmt = NULL; ++ int i; ++ for(i=0; ifourcc) ++ return fmt->mbus_code; ++ } ++ return 0; ++} ++ ++static unsigned int fourcc_to_mbus_depth(unsigned int fourcc){ ++ const struct cim_video_format *fmt = NULL; ++ int i; ++ for(i=0; ifourcc) ++ return fmt->depth[0]; ++ } ++ return 0; ++} ++ ++ ++static int ingenic_camera_alloc_desc(struct ingenic_camera_dev *pcdev, unsigned int count) ++{ ++ ++ int desc_size = 0; ++ pcdev->buf_cnt = count; ++ if (pcdev->cim_priv->version_num == 2) { ++ desc_size = sizeof(struct ingenic_camera_desc_v2); ++ pcdev->desc_vaddr = dma_alloc_coherent(pcdev->v4l2_dev.dev, ++ desc_size * pcdev->buf_cnt, ++ (dma_addr_t *)&pcdev->desc_v2_paddr, GFP_KERNEL); ++ if (!pcdev->desc_v2_paddr) ++ return -ENOMEM; ++ } else { ++ desc_size = sizeof(struct ingenic_camera_desc_v1); ++ pcdev->desc_vaddr = dma_alloc_coherent(pcdev->v4l2_dev.dev, ++ desc_size * pcdev->buf_cnt, ++ (dma_addr_t *)&pcdev->desc_v1_paddr, GFP_KERNEL); ++ if (!pcdev->desc_v1_paddr) ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void ingenic_camera_free_desc(struct ingenic_camera_dev *pcdev) ++{ ++ int desc_size = 0; ++ if (pcdev->cim_priv->version_num == 2) { ++ desc_size = sizeof(struct ingenic_camera_desc_v2); ++ ++ if(pcdev && pcdev->desc_vaddr) { ++ dma_free_coherent(pcdev->v4l2_dev.dev, ++ desc_size * pcdev->buf_cnt, ++ pcdev->desc_vaddr, (dma_addr_t )pcdev->desc_v2_paddr); ++ ++ pcdev->desc_vaddr = NULL; ++ } ++ } else { ++ desc_size = sizeof(struct ingenic_camera_desc_v1); ++ if (pcdev && pcdev->desc_vaddr) { ++ dma_free_coherent(pcdev->v4l2_dev.dev, ++ desc_size * pcdev->buf_cnt, ++ pcdev->desc_vaddr, (dma_addr_t )pcdev->desc_v1_paddr); ++ ++ pcdev->desc_vaddr = NULL; ++ } ++ } ++} ++ ++static int ingenic_init_desc(struct vb2_buffer *vb2) { ++ struct cim_video_ctx *ctx = vb2_get_drv_priv(vb2->vb2_queue); ++ struct v4l2_pix_format *user_fmt = &ctx->format.fmt.pix; ++ struct ingenic_camera_dev *pcdev = ctx->cimvideo.pcdev; ++ struct ingenic_camera_desc_v1 *desc_v1; ++ struct ingenic_camera_desc_v2 *desc_v2; ++ dma_addr_t dma_address; ++ u32 index = vb2->index; ++ u32 pixfmt = user_fmt->pixelformat; ++ u32 sizeimage = user_fmt->sizeimage; ++ u32 user_width = user_fmt->width; ++ ++ dma_address = *(dma_addr_t *)vb2_plane_cookie(vb2, 0); ++ if(!dma_address) { ++ dev_err(ctx->cimvideo.dev, "Failed to setup DMA address\n"); ++ return -ENOMEM; ++ } ++ ++ if (pcdev->cim_priv->version_num == 2) { ++ desc_v2 = (struct ingenic_camera_desc_v2 *) pcdev->desc_vaddr; ++ desc_v2[index].DES_CFG_t.data.ID = index; ++ desc_v2[index].WRBK_ADDR = dma_address; ++ } else { ++ desc_v1 = (struct ingenic_camera_desc_v1 *) pcdev->desc_vaddr; ++ desc_v1[index].DES_CFG_t.data.ID = index; ++ desc_v1[index].WRBK_ADDR = dma_address; ++ } ++ ++ switch (pixfmt){ ++ case V4L2_PIX_FMT_RGB565: ++ case INGENIC_V4L2_PIX_FMT_RBG565: ++ case INGENIC_V4L2_PIX_FMT_BGR565: ++ case INGENIC_V4L2_PIX_FMT_BRG565: ++ case INGENIC_V4L2_PIX_FMT_GRB565: ++ case INGENIC_V4L2_PIX_FMT_GBR565: ++ if (pcdev->cim_priv->version_num == 2) { ++ desc_v2[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_RGB565; ++ } else { ++ desc_v1[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_RGB565; ++ } ++ break; ++ case V4L2_PIX_FMT_RGB32: ++ if (pcdev->cim_priv->version_num == 2) { ++ desc_v2[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_RGB888; ++ } else { ++ desc_v1[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_RGB888; ++ } ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ case V4L2_PIX_FMT_YVYU: ++ case V4L2_PIX_FMT_UYVY: ++ case V4L2_PIX_FMT_VYUY: ++ if (pcdev->cim_priv->version_num == 2) { ++ desc_v2[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_YUV422; ++ } else { ++ desc_v1[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_YUV422; ++ } ++ break; ++ case V4L2_PIX_FMT_GREY: ++ case V4L2_PIX_FMT_SBGGR8: ++ case V4L2_PIX_FMT_SGBRG8: ++ case V4L2_PIX_FMT_SGRBG8: ++ case V4L2_PIX_FMT_SRGGB8: ++ case V4L2_PIX_FMT_SBGGR10: ++ case V4L2_PIX_FMT_SGBRG10: ++ case V4L2_PIX_FMT_SGRBG10: ++ case V4L2_PIX_FMT_SRGGB10: ++ if (pcdev->cim_priv->version_num == 2) { ++ desc_v2[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_MONO; ++ } else { ++ desc_v1[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_MONO; ++ } ++ break; ++ default: ++ dev_err(ctx->cimvideo.dev, "No support format!\n"); ++ return -EINVAL; ++ } ++ ++ if(pcdev->cim_priv->version_num == 2 && ctx->output_y == 1) ++ desc_v2[index].DES_CFG_t.data.WRBK_FMT = WRBK_FMT_Y; ++ ++ ++ if(pcdev->cim_priv->version_num == 1 && !pcdev->desc_v1_head && ++ !pcdev->desc_v1_tail) { ++ pcdev->desc_v1_head = &desc_v1[index]; ++ pcdev->desc_v1_tail = &desc_v1[index]; ++ desc_v1[index].DES_INTC_t.data.EOF_MSK = 0; ++ desc_v1[index].DES_CFG_t.data.DES_END = 1; ++ desc_v1[index].next = 0; ++ } else if(pcdev->cim_priv->version_num == 1 && pcdev->desc_v1_head != NULL && ++ pcdev->desc_v1_tail != NULL) { ++ pcdev->desc_v1_tail->next = (dma_addr_t)(&pcdev->desc_v1_paddr[index]); ++ v4l2_async_notifier_init(&pcdev->notifier); ++ pcdev->desc_v1_tail->DES_INTC_t.data.EOF_MSK = 1; ++ pcdev->desc_v1_tail->DES_CFG_t.data.DES_END = 0; ++ pcdev->desc_v1_tail = &desc_v1[index]; ++ ++ desc_v1[index].DES_INTC_t.data.EOF_MSK = 0; ++ desc_v1[index].DES_CFG_t.data.DES_END = 1; ++ desc_v1[index].next = 0; ++ } else if (pcdev->cim_priv->version_num == 2 && !pcdev->desc_v2_head && ++ !pcdev->desc_v2_tail) { ++ pcdev->desc_v2_head = &desc_v2[index]; ++ pcdev->desc_v2_tail = &desc_v2[index]; ++ desc_v2[index].DES_INTC_t.data.EOF_MSK = 0; ++ desc_v2[index].DES_CFG_t.data.DES_END = 1; ++ desc_v2[index].next = 0; ++ } else if(pcdev->cim_priv->version_num == 2 && pcdev->desc_v2_head != NULL && ++ pcdev->desc_v2_tail != NULL) { ++ pcdev->desc_v2_tail->next = (dma_addr_t)(&pcdev->desc_v2_paddr[index]); ++ pcdev->desc_v2_tail->DES_INTC_t.data.EOF_MSK = 1; ++ pcdev->desc_v2_tail->DES_CFG_t.data.DES_END = 0; ++ pcdev->desc_v2_tail = &desc_v2[index]; ++ ++ desc_v2[index].DES_INTC_t.data.EOF_MSK = 0; ++ desc_v2[index].DES_CFG_t.data.DES_END = 1; ++ desc_v2[index].next = 0; ++ } ++ ++ if(pcdev->cim_priv->version_num == 2) { ++ if(!ctx->lumi_en) { ++ desc_v2[index].DES_LUMI_CFG_t.d32 = 0; ++ desc_v2[index].LUMI_WRBK_ADDR = 0; ++ } else { ++ desc_v2[index].DES_LUMI_CFG_t.LUMI_EN = 1; ++ desc_v2[index].LUMI_WRBK_ADDR ++ = desc_v2[index].WRBK_ADDR + sizeimage; ++ } ++ ++ if(!ctx->interlace) { ++ desc_v2[index].WRBK_STRD = user_width; ++ desc_v2[index].SF_WRBK_ADDR = 0; ++ } else { ++ desc_v2[index].WRBK_STRD = user_width * 2; ++ desc_v2[index].SF_WRBK_ADDR = ++ desc_v2[index].WRBK_ADDR + user_width * 2; ++ } ++ } else { ++ if(!ctx->hist_en) { ++ desc_v1[index].DES_HIST_CFG_t.d32 = 0; ++ desc_v1[index].HIST_WRBK_ADDR = 0; ++ } else { ++ if(pixfmt != V4L2_PIX_FMT_YUYV && ++ pixfmt != V4L2_PIX_FMT_GREY) { ++ dev_err(ctx->cimvideo.dev,"fmt not support hist!\n"); ++ return -EINVAL; ++ } ++ desc_v1[index].DES_HIST_CFG_t.HIST_EN = 1; ++ desc_v1[index].DES_HIST_CFG_t.GAIN_MUL = ctx->hist_gain_mul; ++ desc_v1[index].DES_HIST_CFG_t.GAIN_ADD = ctx->hist_gain_add; ++ desc_v1[index].HIST_WRBK_ADDR ++ = desc_v1[index].WRBK_ADDR + sizeimage; ++ } ++ ++ if(!ctx->interlace) { ++ desc_v1[index].WRBK_STRD = user_width; ++ desc_v1[index].SF_WRBK_ADDR = 0; ++ } else { ++ desc_v1[index].WRBK_STRD = user_width * 2; ++ desc_v1[index].SF_WRBK_ADDR = ++ desc_v1[index].WRBK_ADDR + user_width * 2; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ingenic_camera_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct cim_video_ctx *ctx = ctrl_to_ctx(ctrl); ++ struct ingenic_camera_dev *pcdev = ctx->cimvideo.pcdev; ++ struct ingenic_camera_desc_v1 *desc_v1; ++ unsigned int tmp; ++ int i; ++ int expo_width = 0x08; ++ int dly_num = 0x80; ++ ++ switch (ctrl->id) { ++ case INGENIC_CID_CROP_WAY: ++ // img_sz->crop_way = ctrl->val; ++ break; ++ case INGENIC_CID_LUMI_EN: ++ ctx->lumi_en = 1; ++ break; ++ case INGENIC_CID_OUTPUT_Y: ++ ctx->output_y = 1; ++ break; ++ case INGENIC_CID_POINT1_X: ++ tmp = cim_readl(pcdev, LUMI_POINT1); ++ tmp &= ~0x7ff; ++ tmp |= ctrl->val; ++ cim_writel(pcdev, tmp, LUMI_POINT1); ++ break; ++ case INGENIC_CID_POINT1_Y: ++ tmp = cim_readl(pcdev, LUMI_POINT1); ++ tmp &= ~(0x7ff << 16); ++ tmp |= ctrl->val << 16; ++ cim_writel(pcdev, tmp, LUMI_POINT1); ++ break; ++ case INGENIC_CID_POINT2_X: ++ tmp = cim_readl(pcdev, LUMI_POINT2); ++ tmp &= ~0x7ff; ++ tmp |= ctrl->val; ++ cim_writel(pcdev, tmp, LUMI_POINT2); ++ break; ++ case INGENIC_CID_POINT2_Y: ++ tmp = cim_readl(pcdev, LUMI_POINT2); ++ tmp &= ~(0x7ff << 16); ++ tmp |= ctrl->val << 16; ++ cim_writel(pcdev, tmp, LUMI_POINT2); ++ break; ++ case INGENIC_CID_SNAPSHOT_EN: ++ if(!is_cim_disabled(pcdev)){ ++ printk("too late to set snapshot mode\n"); ++ return 0; ++ } ++ ctx->snapshot = 1; ++ tmp = cim_readl(pcdev, GLB_CFG); ++ tmp |= GLB_CFG_DAT_MODE; ++ tmp &= ~GLB_CFG_EXPO_WIDTH_MASK_V2; ++ tmp |= (expo_width << GLB_CFG_EXPO_WIDTH_LBIT); ++ cim_writel(pcdev, tmp, GLB_CFG); ++ tmp = dly_num; ++ tmp |= CIM_DLY_EN; ++ tmp |= CIM_DLY_MD; ++ cim_writel(pcdev, tmp, DLY_CFG); ++ break; ++ case INGENIC_CID_EXP_PULSE_W: ++ if(!is_cim_disabled(pcdev)){ ++ printk("too late to set exposure width!\n"); ++ return 0; ++ } ++ if(!ctx->snapshot) ++ return 0; ++ tmp = cim_readl(pcdev, GLB_CFG); ++ tmp &= ~GLB_CFG_EXPO_WIDTH_MASK_V2; ++ tmp |= ((ctrl->val & 0x1f) << GLB_CFG_EXPO_WIDTH_LBIT); ++ cim_writel(pcdev, tmp, GLB_CFG); ++ expo_width = ctrl->val; ++ break; ++ case INGENIC_CID_SNAPSHOT_DELAY_T: ++ if(!is_cim_disabled(pcdev)){ ++ printk("too late to set delay number!\n"); ++ return 0; ++ } ++ if(!ctx->snapshot) ++ return 0; ++ tmp = ctrl->val; ++ tmp |= CIM_DLY_EN; ++ tmp |= CIM_DLY_MD; ++ cim_writel(pcdev, tmp, DLY_CFG); ++ dly_num = ctrl->val; ++ break; ++ case INGENIC_CID_SCALE_SHARP: ++ tmp = cim_readl(pcdev,RESIZE_CFG); ++ tmp &= ~CIM_SHARPL_MASK; ++ tmp |= ctrl->val << CIM_SHARPL_LBIT; ++ cim_writel(pcdev, tmp, RESIZE_CFG); ++ break; ++ case INGENIC_CID_HIST_EN: ++ ctx->hist_en = 1; ++ break; ++ case INGENIC_CID_HIST_GAIN_ADD: ++ ctx->hist_gain_add = ctrl->val; ++ desc_v1 = (struct ingenic_camera_desc_v1 *) pcdev->desc_vaddr; ++ if(!ctx->hist_en || !desc_v1) { ++ dev_dbg(pcdev->dev, "setting hist_add are not satisfied!\n"); ++ return 0; ++ } ++ for(i = 0; i < pcdev->buf_cnt; i++) ++ desc_v1[i].DES_HIST_CFG_t.GAIN_ADD = ctx->hist_gain_add; ++ break; ++ case INGENIC_CID_HIST_GAIN_MUL: ++ ctx->hist_gain_mul = ctrl->val; ++ desc_v1 = (struct ingenic_camera_desc_v1 *) pcdev->desc_vaddr; ++ if(!ctx->hist_en || !desc_v1) { ++ dev_dbg(pcdev->dev, "setting hist_mul are not satisfied!\n"); ++ return 0; ++ } ++ for(i = 0; i < pcdev->buf_cnt; i++) ++ desc_v1[i].DES_HIST_CFG_t.GAIN_MUL = ctx->hist_gain_mul; ++ break; ++ default: ++ dev_err(pcdev->dev, "ctrl id not supported!\n"); ++ break; ++ } ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops ingenic_camera_ctrl_ops = { ++ .s_ctrl = ingenic_camera_s_ctrl, ++}; ++ ++static const struct v4l2_ctrl_config img_crop_way = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_CROP_WAY, ++ .name = "crop way", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .def = CROP_SPECIFY_ZONE, ++ .max = CROP_BASE_MAX_PIC, ++ .min = CROP_SPECIFY_ZONE, ++ .max = CROP_BASE_MAX_PIC, ++ .step = 1, ++}; ++ ++static const struct v4l2_ctrl_config lumi_en = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_LUMI_EN, ++ .type = V4L2_CTRL_TYPE_BUTTON, ++ .name = "lumi enable", ++}; ++ ++static const struct v4l2_ctrl_config output_y = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_OUTPUT_Y, ++ .type = V4L2_CTRL_TYPE_BUTTON, ++ .name = "output Y enable", ++}; ++ ++static const struct v4l2_ctrl_config point1_x = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_POINT1_X, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "point1 x-offset", ++ .def = 0x78, ++ .min = 0, ++ .max = 0x7ff, ++ .step = 1, ++}; ++ ++static const struct v4l2_ctrl_config point1_y = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_POINT1_Y, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "point1 y-offset", ++ .def = 0x78, ++ .min = 0, ++ .max = 0x7ff, ++ .step = 1, ++}; ++ ++static const struct v4l2_ctrl_config point2_x = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_POINT2_X, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "point2 x-offset", ++ .def = 0xf0, ++ .min = 0, ++ .max = 0x7ff, ++ .step = 1, ++}; ++ ++static const struct v4l2_ctrl_config point2_y = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_POINT2_Y, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "point2 y-offset", ++ .def = 0xf0, ++ .min = 0, ++ .max = 0x7ff, ++ .step = 1, ++}; ++static const struct v4l2_ctrl_config snapshot_en = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_SNAPSHOT_EN, ++ .type = V4L2_CTRL_TYPE_BUTTON, ++ .name = "snapshot enable", ++}; ++ ++static const struct v4l2_ctrl_config exp_pulse_w= { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_EXP_PULSE_W, ++ .name = "pulse width", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .def = 0xf, ++ .min = 0x01, ++ .max = 0x1f, ++ .step = 1, ++}; ++ ++static const struct v4l2_ctrl_config delay_t= { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_SNAPSHOT_DELAY_T, ++ .name = "delay number", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .def = 0x00, ++ .min = 0x00, ++ .max = 0x800000, ++ .step = 1, ++}; ++ ++static const struct v4l2_ctrl_config img_scale_sharp = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_SCALE_SHARP, ++ .name = "scale sharp", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .def = 2, ++ .min = 0, ++ .max = 3, ++ .step = 1, ++}; ++ ++static const struct v4l2_ctrl_config hist_en = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_HIST_EN, ++ .type = V4L2_CTRL_TYPE_BUTTON, ++ .name = "histgram enable", ++}; ++ ++static const struct v4l2_ctrl_config hist_gain_add = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_HIST_GAIN_ADD, ++ .name = "hist gain add", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .def = 0, ++ .min = 0, ++ .max = 0xff, ++ .step = 1, ++}; ++ ++static const struct v4l2_ctrl_config hist_gain_mul = { ++ .ops = &ingenic_camera_ctrl_ops, ++ .id = INGENIC_CID_HIST_GAIN_MUL, ++ .name = "hist gain mul", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .def = 0x20, ++ .min = 0, ++ .max = 0xff, ++ .step = 1, ++}; ++ ++ ++static int ingenic_camera_wakeup(struct ingenic_camera_dev *pcdev) { ++ struct ingenic_buffer *buf = pcdev->active; ++ struct vb2_v4l2_buffer *vbuf = &pcdev->active->vb; ++ int id = cim_readl(pcdev, FRAME_ID); ++ ++ if(!buf || vbuf->vb2_buf.index != id) { ++ dev_err(pcdev->dev, "cim buf synchronous problems!\n"); ++ return -EINVAL; ++ } ++ ++ list_del_init(&buf->list); ++ vbuf->vb2_buf.timestamp = ktime_get_ns(); ++ vbuf->sequence = pcdev->sequence++; ++ vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); ++ ++ return 0; ++} ++ ++static irqreturn_t ingenic_camera_irq_handler(int irq, void *data) { ++ struct ingenic_camera_dev *pcdev = (struct ingenic_camera_dev *)data; ++ struct ingenic_camera_desc_v1 *desc_v1_p; ++ struct ingenic_camera_desc_v2 *desc_v2_p; ++ unsigned long status = 0; ++ unsigned long flags = 0; ++ unsigned long regval = 0; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ++ /* read interrupt flag register */ ++ status = cim_readl(pcdev,INT_FLAG); ++ if (!status) { ++ dev_err(pcdev->dev, "cim irq_flag is NULL! \n"); ++ goto out; ++ } ++ ++ if(status & CIM_INT_FLAG_EOW) { ++ cim_writel(pcdev, CIM_INT_FLAG_EOW, CIM_CLR_ST); ++ ++ if(status & CIM_INT_FLAG_EOF) { ++ cim_writel(pcdev, CIM_INT_FLAG_EOF, CIM_CLR_ST); ++ } ++ ++ if(ingenic_camera_wakeup(pcdev)) ++ goto out; ++ ++ if (list_empty(&pcdev->video_buffer_list)) { ++ pcdev->active = NULL; ++ goto out; ++ } ++ ++ /* start next dma frame. */ ++ if (pcdev->cim_priv->version_num == 2) { ++ desc_v2_p = pcdev->desc_v2_paddr; ++ regval = (unsigned long)(pcdev->desc_v2_head->next); ++ pcdev->desc_v2_head = ++ (struct ingenic_camera_desc_v2 *)((regval)|0xa0000000); ++ } else { ++ desc_v1_p = pcdev->desc_v1_paddr; ++ regval = (unsigned long)(pcdev->desc_v1_head->next); ++ pcdev->desc_v1_head = ++ (struct ingenic_camera_desc_v1 *)(regval|0xa0000000); ++ } ++ ++ cim_writel(pcdev, regval, DES_ADDR); ++ cim_writel(pcdev, CIM_CTRL_START, CIM_CTRL); ++ ++ pcdev->active = ++ list_entry(pcdev->video_buffer_list.next, struct ingenic_buffer, list); ++ goto out; ++ } ++ ++ if(status & CIM_INT_FLAG_EOF) { ++ cim_writel(pcdev, CIM_INT_FLAG_EOF, CIM_CLR_ST); ++ ++ if(ingenic_camera_wakeup(pcdev)) ++ goto out; ++ ++ pcdev->active = ++ list_entry(pcdev->video_buffer_list.next, struct ingenic_buffer, list); ++ if (pcdev->cim_priv->version_num == 2) { ++ pcdev->desc_v2_head = ++ (struct ingenic_camera_desc_v2 *)((pcdev->desc_v2_head->next)|0xa0000000); ++ } else ++ pcdev->desc_v1_head = ++ (struct ingenic_camera_desc_v1 *)((pcdev->desc_v1_head->next)|0xa0000000); ++ ++ goto out; ++ } ++ ++ if (status & CIM_INT_FLAG_SZ_ERR) { ++ unsigned int val; ++ val = cim_readl(pcdev, ACT_SIZE); ++ cim_writel(pcdev, CIM_CLR_SZ_ERR, CIM_CLR_ST); ++ dev_err(pcdev->dev, "cim size err! w = %d h = %d\n", val&0x3ff, val>>16&0x3ff); ++ goto out; ++ } ++ ++ if (status & CIM_INT_FLAG_OVER) { ++ cim_writel(pcdev, CIM_INT_FLAG_OVER, CIM_CLR_ST); ++ dev_err(pcdev->dev, "cim overflow! \n"); ++ goto out; ++ } ++ ++ if(status & CIM_INT_FLAG_GSA) { ++ cim_writel(pcdev, CIM_INT_FLAG_GSA, CIM_CLR_ST); ++ printk("cim general stop! \n"); ++ goto out; ++ } ++ ++ if(status & CIM_INT_FLAG_SOF) { ++ cim_writel(pcdev, CIM_INT_FLAG_SOF, CIM_CLR_ST); ++ goto out; ++ } ++ ++out: ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ return IRQ_HANDLED; ++} ++ ++/*ioctl_ops*/ ++static int ingenic_camera_querycap(struct file *file, void *fh, ++ struct v4l2_capability *cap) ++{ ++ struct cim_video_ctx *ctx = video_drvdata(file); ++ ++ strlcpy(cap->driver, "ingenic-camera", sizeof(cap->driver)); ++ cap->version = VERSION_CODE; ++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; ++ ++ return 0; ++} ++ ++static int ingenic_camera_enum_fmt_vid_cap(struct file *file, void *fh, ++ struct v4l2_fmtdesc *f) ++{ ++ struct cim_video_ctx *ctx = video_drvdata(file); ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ const struct cim_video_format *fmt = NULL; ++ struct v4l2_subdev_mbus_code_enum code = { ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ }; ++ int i, ret = 0; ++ ++ code.index = f->index; ++ ret = v4l2_subdev_call(cimvideo->subdev, pad, enum_mbus_code, NULL, &code); ++ if (ret < 0) ++ return -EINVAL; ++ ++ for(i=0; i < ARRAY_SIZE(cim_formats); i++) { ++ fmt = &cim_formats[i]; ++ if(fmt->mbus_code == code.code) ++ { ++ strlcpy(f->description, fmt->name, sizeof(f->description)); ++ f->pixelformat = fmt->fourcc; ++ return 0; ++ } ++ } ++ return -EINVAL; ++} ++ ++static int ingenic_camera_set_bus_param(struct cim_video_ctx *ctx) { ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ struct v4l2_pix_format *user_fmt = &ctx->format.fmt.pix; ++ struct ingenic_camera_dev *pcdev = cimvideo->pcdev; ++ struct cim_async_subdev *casd = &pcdev->casd[cimvideo->index]; ++ struct ingenic_image_sz *img_sz = &ctx->img_sz; ++ int version = pcdev->cim_priv->version_num; ++ unsigned long common_flags; ++ unsigned long glb_cfg = 0; ++ unsigned long tmp; ++ unsigned long intc = 0; ++ ++ glb_cfg = cim_readl(pcdev,GLB_CFG); ++ if(casd->bus_type == V4L2_MBUS_CSI2_DPHY) { ++ /***Csi2 interface requirements***/ ++ common_flags = V4L2_MBUS_MASTER | ++ V4L2_MBUS_HSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_VSYNC_ACTIVE_HIGH | ++ V4L2_MBUS_PCLK_SAMPLE_RISING; ++ glb_cfg |= GLB_CFG_DAT_IF_SEL; ++ ++ } else if(casd->bus_type == V4L2_MBUS_PARALLEL) { ++ common_flags = casd->parallel.flags; ++ glb_cfg &= ~GLB_CFG_DAT_IF_SEL; ++ } else if(casd->bus_type == V4L2_MBUS_BT656) { ++ common_flags = casd->parallel.flags; ++ if(common_flags & V4L2_MBUS_SLAVE) { ++ dev_err(cimvideo->dev, "bt656_mbus slave mode not supported!\n"); ++ return -EINVAL; ++ } ++ glb_cfg &= ~GLB_CFG_DAT_IF_SEL; ++ } else { ++ dev_err(cimvideo->dev, "cim interface not supported!\n"); ++ return -EINVAL; ++ } ++ ++ /*PCLK Polarity Set*/ ++ glb_cfg = (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) ? ++ (glb_cfg | GLB_CFG_DE_PCLK) : (glb_cfg & (~GLB_CFG_DE_PCLK)); ++ ++ /*VSYNC Polarity Set*/ ++ glb_cfg = (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) ? ++ (glb_cfg | GLB_CFG_DL_VSYNC) : (glb_cfg & (~GLB_CFG_DL_VSYNC)); ++ ++ /*HSYNC Polarity Set*/ ++ glb_cfg = (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) ? ++ (glb_cfg | GLB_CFG_DL_HSYNC) : (glb_cfg & (~GLB_CFG_DL_HSYNC)); ++ ++ glb_cfg &= (version == 1) ? (~GLB_CFG_C_ORDER_MASK_V1) : (~GLB_CFG_C_ORDER_MASK_V2); ++ glb_cfg &= (~GLB_CFG_C_ORDER_MASK_V1); ++ ++ if(casd->bus_type != V4L2_MBUS_BT656) { ++ switch(fourcc_to_mbus_code(user_fmt->pixelformat)) { ++ case MEDIA_BUS_FMT_RGB565_2X8_LE: ++ glb_cfg |= (GLB_CFG_ORG_FMT_RGB565 | GLB_CFG_C_ORDER_RGB); ++ break; ++ case INGENIC_MEDIA_BUS_FMT_RBG565_2X8_LE: ++ glb_cfg |= (GLB_CFG_ORG_FMT_RGB565 | GLB_CFG_C_ORDER_RBG); ++ break; ++ case MEDIA_BUS_FMT_BGR565_2X8_LE: ++ glb_cfg |= (GLB_CFG_ORG_FMT_RGB565 | GLB_CFG_C_ORDER_BGR); ++ break; ++ case INGENIC_MEDIA_BUS_FMT_BRG565_2X8_LE: ++ glb_cfg |= (GLB_CFG_ORG_FMT_RGB565 | GLB_CFG_C_ORDER_BRG); ++ break; ++ case INGENIC_MEDIA_BUS_FMT_GRB565_2X8_LE: ++ glb_cfg |= (GLB_CFG_ORG_FMT_RGB565 | GLB_CFG_C_ORDER_GRB); ++ break; ++ case INGENIC_MEDIA_BUS_FMT_GBR565_2X8_LE: ++ glb_cfg |= (GLB_CFG_ORG_FMT_RGB565 | GLB_CFG_C_ORDER_GBR); ++ break; ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_YUYV422 | GLB_CFG_C_ORDER_UYVY); ++ break; ++ case MEDIA_BUS_FMT_VYUY8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_YUYV422 | GLB_CFG_C_ORDER_VYUY); ++ break; ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_YUYV422 | GLB_CFG_C_ORDER_YUYV); ++ break; ++ case MEDIA_BUS_FMT_YVYU8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_YUYV422 | GLB_CFG_C_ORDER_YVYU); ++ break; ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ glb_cfg |= (GLB_CFG_ORG_FMT_RGB888 | GLB_CFG_C_ORDER_RGB); ++ break; ++ case MEDIA_BUS_FMT_Y8_1X8: ++ glb_cfg |= GLB_CFG_ORG_FMT_MONO; ++ break; ++ case MEDIA_BUS_FMT_Y10_1X10: ++ glb_cfg |= GLB_CFG_ORG_FMT_10BIT_MONO; ++ break; ++ case MEDIA_BUS_FMT_Y12_1X12: ++ glb_cfg |= GLB_CFG_ORG_FMT_12BIT_MONO; ++ break; ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ glb_cfg |= (GLB_CFG_C_ORDER_BGGR | GLB_CFG_ORG_FMT_8BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ glb_cfg |= (GLB_CFG_C_ORDER_GBRG | GLB_CFG_ORG_FMT_8BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ glb_cfg |= (GLB_CFG_C_ORDER_GRBG | GLB_CFG_ORG_FMT_8BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ glb_cfg |= (GLB_CFG_C_ORDER_RGGB | GLB_CFG_ORG_FMT_8BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ glb_cfg |= (GLB_CFG_C_ORDER_BGGR | GLB_CFG_ORG_FMT_10BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ glb_cfg |= (GLB_CFG_C_ORDER_GBRG | GLB_CFG_ORG_FMT_10BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ glb_cfg |= (GLB_CFG_C_ORDER_GRBG | GLB_CFG_ORG_FMT_10BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ glb_cfg |= (GLB_CFG_C_ORDER_RGGB | GLB_CFG_ORG_FMT_10BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ glb_cfg |= (GLB_CFG_C_ORDER_BGGR | GLB_CFG_ORG_FMT_12BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ glb_cfg |= (GLB_CFG_C_ORDER_GBRG | GLB_CFG_ORG_FMT_12BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ glb_cfg |= (GLB_CFG_C_ORDER_GRBG | GLB_CFG_ORG_FMT_12BIT_RAW); ++ break; ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ glb_cfg |= (GLB_CFG_C_ORDER_RGGB | GLB_CFG_ORG_FMT_12BIT_RAW); ++ break; ++ default: ++ dev_err(cimvideo->dev, "Providing code %x not support\n", fourcc_to_mbus_code(user_fmt->pixelformat)); ++ return -EINVAL; ++ } ++ } else { ++ unsigned int sf_cfg = 0; ++ switch(fourcc_to_mbus_code(user_fmt->pixelformat)) { ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_ITU656 | GLB_CFG_C_ORDER_YUYV); ++ break; ++ case MEDIA_BUS_FMT_YVYU8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_ITU656 | GLB_CFG_C_ORDER_YVYU); ++ break; ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_ITU656 | GLB_CFG_C_ORDER_UYVY); ++ break; ++ case MEDIA_BUS_FMT_VYUY8_2X8: ++ glb_cfg |= (GLB_CFG_ORG_FMT_ITU656 | GLB_CFG_C_ORDER_VYUY); ++ break; ++ default: ++ dev_err(cimvideo->dev, "Providing code %d not support\n", ++ fourcc_to_mbus_code(user_fmt->pixelformat)); ++ break; ++ } ++ ++ if(user_fmt->field == V4L2_FIELD_NONE) { ++ ctx->interlace = 0; ++ } else { ++ switch(user_fmt->field) { ++ case V4L2_FIELD_INTERLACED_TB: ++ case V4L2_FIELD_INTERLACED: ++ sf_cfg &= ~CIM_F_ORDER; ++ break; ++ case V4L2_FIELD_INTERLACED_BT: ++ sf_cfg |= CIM_F_ORDER; ++ break; ++ default: ++ dev_err(cimvideo->dev, ++ "itu656 unsupported field"); ++ break; ++ } ++ sf_cfg |= CIM_SCAN_MD; ++ sf_cfg &= ~CIM_SF_HEIGHT_MASK; ++ sf_cfg |= ((img_sz->src_h / 2) & 0xfff); ++ ctx->interlace = 1; ++ } ++ cim_writel(pcdev, sf_cfg, SCAN_CFG); ++ } ++ ++ glb_cfg |= GLB_CFG_BURST_LEN_32; ++ glb_cfg |= GLB_CFG_AUTO_RECOVERY; ++ if(frame_size_check_flag == 1) ++ glb_cfg |= GLB_CFG_SIZE_CHK; ++ else ++ glb_cfg &= ~GLB_CFG_SIZE_CHK; ++ ++#ifdef CONFIG_CAMERA_USE_SNAPSHOT ++ tmp = CONFIG_SNAPSHOT_PULSE_WIDTH; ++ if(!tmp) { ++ tmp = 0x08; ++ } ++ glb_cfg |= GLB_CFG_DAT_MODE; ++ if (version == 1) { ++ glb_cfg &= ~GLB_CFG_EXPO_WIDTH_MASK_V1; ++ glb_cfg |= (((tmp-1) & 0x7) << GLB_CFG_EXPO_WIDTH_LBIT); ++ } else { ++ glb_cfg &= ~GLB_CFG_EXPO_WIDTH_MASK_V2; ++ glb_cfg |= ((tmp & 0x1f) << GLB_CFG_EXPO_WIDTH_LBIT); ++ } ++ tmp = CONFIG_SNAPSHOT_FRAME_DELAY & 0xffffff; ++ tmp |= CIM_DLY_EN; ++ tmp |= CIM_DLY_MD; ++ if (version == 2) ++ tmp |= CIM_EXPO_WIDTH_EN; ++ cim_writel(pcdev, tmp, DLY_CFG); ++#else ++ cim_writel(pcdev, 0, DLY_CFG); ++#endif ++ ++ if(ctx->interlace) { ++ img_sz->src_h = img_sz->src_h / 2; ++ } ++ tmp = (img_sz->src_w << CIM_CROP_WIDTH_LBIT) | ++ (img_sz->src_h << CIM_CROP_HEIGHT_LBIT); ++ cim_writel(pcdev, tmp, FRM_SIZE); ++ tmp = cim_readl(pcdev, FRM_SIZE); ++ cim_writel(pcdev, 0, CROP_SITE); ++ ++ /* enable stop of frame interrupt. */ ++ intc |= CIM_INTC_MSK_EOW; ++ ++ /* enable end of frame interrupt, ++ * Work together with DES_INTC.EOF_MSK, ++ * only when both are 1 will generate interrupt. */ ++ intc |= CIM_INTC_MSK_EOF; ++ ++ /* enable general stop of frame interrupt. */ ++ intc |= CIM_INTC_MSK_GSA; ++ ++ /* enable rxfifo overflow interrupt */ ++ intc |= CIM_INTC_MSK_OVER; ++ ++ /* enable size check err */ ++ if(frame_size_check_flag == 1) ++ intc |= CIM_INTC_MSK_SZ_ERR; ++ else ++ intc &= ~CIM_INTC_MSK_SZ_ERR; ++ ++ cim_writel(pcdev, 0, DBG_CGC); ++ cim_writel(pcdev, glb_cfg, GLB_CFG); ++ cim_writel(pcdev, intc, CIM_INTC); ++ cim_writel(pcdev, 0, QOS_CTRL); ++ ++ return 0; ++} ++ ++static int __ingenic_camera_try_fmt(struct cim_video_ctx *ctx, struct v4l2_format *f) ++{ ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ struct v4l2_subdev *sd = cimvideo->subdev; ++ struct v4l2_subdev_format format = { ++ .which = V4L2_SUBDEV_FORMAT_TRY, ++ }; ++ struct v4l2_subdev_pad_config cfg; ++ struct v4l2_mbus_framefmt *mf = &format.format; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ struct ingenic_image_sz *img_sz = &ctx->img_sz; ++ int depth = 0; ++ int ret = 0; ++ ++ v4l_bound_align_image(&pix->width, 100, 2046, ++ (pix->pixelformat == V4L2_PIX_FMT_YUYV ? 1 : 0), ++ &pix->height, 100, 2046, 0, 0); ++ ++ mf->width = pix->width; ++ mf->height = pix->height; ++ mf->field = pix->field; ++ mf->colorspace = pix->colorspace; ++ mf->code = fourcc_to_mbus_code(pix->pixelformat); ++ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, &cfg, &format); ++ if (ret < 0){ ++ return ret; ++ } ++ ++ pix->width = mf->width; ++ pix->height = mf->height; ++ pix->field = mf->field; ++ pix->colorspace = mf->colorspace; ++ depth = fourcc_to_mbus_depth(pix->pixelformat); ++ pix->bytesperline = pix->width * depth / 8; ++ pix->sizeimage = pix->bytesperline * pix->height; ++ ++ return 0; ++} ++ ++static int ingenic_camera_try_fmt_vid_cap(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct cim_video_ctx *ctx = video_drvdata(file); ++ return __ingenic_camera_try_fmt(ctx, f); ++} ++ ++static int ingenic_camera_s_fmt_vid_cap(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct cim_video_ctx *ctx = video_drvdata(file); ++ struct v4l2_pix_format *user_fmt = &ctx->format.fmt.pix; ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ struct v4l2_subdev *sd = cimvideo->subdev; ++ struct ingenic_image_sz *img_sz = &ctx->img_sz; ++ struct v4l2_subdev_format format = { ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ }; ++ struct v4l2_mbus_framefmt *mf = &format.format; ++ struct v4l2_pix_format *pix = &f->fmt.pix; ++ unsigned int pad = 0; ++ int ret = 0; ++ ++ printk("%s:%d\n",__func__, __LINE__); ++ ret = __ingenic_camera_try_fmt(ctx, f); ++ if(ret) ++ return ret; ++ ++ mf->width = pix->width; ++ mf->height = pix->height; ++ mf->field = pix->field; ++ mf->colorspace = pix->colorspace; ++ mf->code = fourcc_to_mbus_code(pix->pixelformat); ++ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); ++ if (ret < 0){ ++ return ret; ++ } ++ ++ img_sz->src_w = mf->width; ++ img_sz->src_h = mf->height; ++ ++ if(unlikely(img_sz->rsz_flag == true)) { ++ dev_err(cimvideo->dev, "Set_crop should be behind set_fmt!\n"); ++ return -EINVAL; ++ } ++ ++ user_fmt->width = pix->width; ++ user_fmt->height = pix->height; ++ user_fmt->bytesperline = pix->bytesperline; ++ user_fmt->sizeimage = pix->sizeimage; ++ user_fmt->pixelformat = pix->pixelformat; ++ user_fmt->colorspace = pix->colorspace; ++ user_fmt->field = pix->field; ++ ++ return ingenic_camera_set_bus_param(ctx); ++} ++ ++static int ingenic_camera_g_fmt_vid_cap(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct cim_video_ctx *ctx = video_drvdata(file); ++ struct v4l2_pix_format *user_fmt = &ctx->format.fmt.pix; ++ ++ printk("%s:%d\n",__func__, __LINE__); ++ memcpy(&f->fmt.pix, user_fmt, sizeof(struct v4l2_pix_format)); ++ ++ return 0; ++} ++ ++static int ingenic_camera_g_selection(struct file *file, void *fh, ++ struct v4l2_selection *s) ++{ ++ struct cim_video_ctx *ctx = video_drvdata(file); ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ struct v4l2_subdev *sd = cimvideo->subdev; ++ struct ingenic_image_sz *img_sz = &ctx->img_sz; ++ struct v4l2_subdev_selection sel; ++ struct v4l2_subdev_pad_config cfg; ++ int ret = 0; ++ ++ switch (s->target) { ++ case V4L2_SEL_TGT_CROP: ++ printk("%s:%d\n",__func__, __LINE__); ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ printk("%s:%d\n",__func__, __LINE__); ++ s->r.left= img_sz->c_left; ++ s->r.top= img_sz->c_top; ++ s->r.width= img_sz->c_w; ++ s->r.height= img_sz->c_h; ++ return 0; ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ printk("%s:%d\n",__func__, __LINE__); ++ ret = v4l2_subdev_call(sd, pad, get_selection, &cfg, &sel); ++ if(!ret) ++ s->r =sel.r; ++ else ++ memset(&s->r, sizeof(struct v4l2_rect), 0); ++ return 0; ++ } ++ printk("%s:%d\n",__func__, __LINE__); ++ return -EINVAL; ++} ++ ++static int ingenic_camera_check_crop(struct cim_video_ctx *ctx, struct v4l2_rect *r) ++{ ++ struct v4l2_rect rect_w = *r; ++ struct v4l2_pix_format *user_fmt = &ctx->format.fmt.pix; ++ u32 pixfmt = user_fmt->pixelformat; ++ unsigned int walign; ++ unsigned int halign; ++ ++ if(user_fmt->field != V4L2_FIELD_NONE) { ++ dev_err(ctx->cimvideo.dev, "field not supported by crop!\n"); ++ return -EINVAL; ++ } ++ ++ if((rect_w.width + rect_w.left > 2046) || ++ (rect_w.height + rect_w.top > 2046)) { ++ dev_err(ctx->cimvideo.dev, "crop bounds check failed!\n"); ++ return -EINVAL; ++ } ++ ++ switch(pixfmt){ ++ case V4L2_PIX_FMT_YUYV: ++ case V4L2_PIX_FMT_YVYU: ++ case V4L2_PIX_FMT_VYUY: ++ case V4L2_PIX_FMT_UYVY: ++ walign = 1; ++ halign = 0; ++ break; ++ case V4L2_PIX_FMT_SBGGR8: ++ case V4L2_PIX_FMT_SGBRG8: ++ case V4L2_PIX_FMT_SGRBG8: ++ case V4L2_PIX_FMT_SRGGB8: ++ case V4L2_PIX_FMT_SBGGR10: ++ case V4L2_PIX_FMT_SGBRG10: ++ case V4L2_PIX_FMT_SGRBG10: ++ case V4L2_PIX_FMT_SRGGB10: ++ case V4L2_PIX_FMT_SBGGR12: ++ case V4L2_PIX_FMT_SGBRG12: ++ case V4L2_PIX_FMT_SGRBG12: ++ case V4L2_PIX_FMT_SRGGB12: ++ walign = 1; ++ halign = 1; ++ break; ++ default: ++ walign = 0; ++ halign = 0; ++ break; ++ } ++ ++ v4l_bound_align_image(&rect_w.width, 100, 2046, walign, ++ &rect_w.height, 100, 2046, halign, 0); ++ ++ if((rect_w.width != r->width) || ++ (rect_w.height != r->height)) { ++ dev_err(ctx->cimvideo.dev, "crop sizes check failed!\n"); ++ return -EINVAL; ++ } ++ ++ if((pixfmt == V4L2_PIX_FMT_YUYV) ++ && (rect_w.left % 2)) { ++ dev_err(ctx->cimvideo.dev, "crop align check failed!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_camera_s_selection(struct file *file, void *fh, ++ struct v4l2_selection *s) ++{ ++ struct cim_video_ctx *ctx = video_drvdata(file); ++ struct v4l2_pix_format *user_fmt = &ctx->format.fmt.pix; ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ struct v4l2_subdev *sd = cimvideo->subdev; ++ struct ingenic_camera_dev *pcdev = cimvideo->pcdev; ++ struct v4l2_rect rect_w = s->r; ++ struct v4l2_subdev_selection sel = { ++ .r = rect_w, ++ }; ++ struct ingenic_image_sz *img_sz = &ctx->img_sz; ++ unsigned int framesize = 0; ++ unsigned int cropsite = 0; ++ int depth = 0; ++ int width, height; ++ int ret; ++ ++ ret = v4l2_subdev_call(sd, pad, set_selection, NULL ,&sel); ++ if(!ret){ ++ /*crop by sensor*/ ++ dev_dbg(cimvideo->dev, "Sensor cropped %dx%d\n", ++ rect_w.width, rect_w.height); ++ ++ img_sz->src_w = rect_w.width; ++ img_sz->src_h = rect_w.height; ++ ++ img_sz->c_left = sel.r.left; ++ img_sz->c_top = sel.r.top; ++ img_sz->c_w = sel.r.width; ++ img_sz->c_h = sel.r.height; ++ ++ framesize = (img_sz->src_w << CIM_CROP_WIDTH_LBIT) | ++ (img_sz->src_h << CIM_CROP_HEIGHT_LBIT); ++ cropsite = 0; ++ } else { ++ /*crop by cim*/ ++ ret = ingenic_camera_check_crop(ctx, &rect_w); ++ if (ret) ++ return ret; ++ ++ width = img_sz->src_w; ++ height = img_sz->src_h; ++ ++ if(((rect_w.left + rect_w.width) > width) || ++ ((rect_w.top + rect_w.height) > height)) { ++ dev_err(cimvideo->dev, "please enum appropriate framesizes!\n"); ++ return -EINVAL; ++ } ++ ++ img_sz->c_left = rect_w.left; ++ img_sz->c_top = rect_w.top; ++ img_sz->c_w = rect_w.width; ++ img_sz->c_h = rect_w.height; ++ ++ ++ framesize = (img_sz->c_w << CIM_CROP_WIDTH_LBIT) | ++ (img_sz->c_h << CIM_CROP_HEIGHT_LBIT); ++ cropsite = (img_sz->c_left << CIM_CROP_X_LBIT) | ++ (img_sz->c_top << CIM_CROP_Y_LBIT); ++ ++ } ++ user_fmt->width = rect_w.width; ++ user_fmt->height = rect_w.height; ++ depth = fourcc_to_mbus_depth(user_fmt->pixelformat); ++ user_fmt->bytesperline = user_fmt->width * depth / 8; ++ user_fmt->sizeimage = user_fmt->bytesperline * user_fmt->height; ++ ++ img_sz->rsz_flag = true; ++ ++ cim_writel(pcdev, framesize, FRM_SIZE); ++ cim_writel(pcdev, cropsite, CROP_SITE); ++ ++ printk("%s:%d\n",__func__, __LINE__); ++ return 0; ++} ++ ++static int ingenic_camera_enum_framesizes(struct file *file, void *fh, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct cim_video_ctx *ctx = video_drvdata(file); ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ struct v4l2_subdev *sd = cimvideo->subdev; ++ struct v4l2_subdev_frame_size_enum fse = { ++ .index = fsize->index, ++ .which = V4L2_SUBDEV_FORMAT_ACTIVE, ++ }; ++ int ret; ++ ++ ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse); ++ if (ret < 0) ++ return ret; ++ ++ if (fse.min_width == fse.max_width && ++ fse.min_height == fse.max_height) { ++ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; ++ fsize->discrete.width = fse.min_width; ++ fsize->discrete.height = fse.min_height; ++ return 0; ++ } ++ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; ++ fsize->stepwise.min_width = fse.min_width; ++ fsize->stepwise.max_width = fse.max_width; ++ fsize->stepwise.min_height = fse.min_height; ++ fsize->stepwise.max_height = fse.max_height; ++ fsize->stepwise.step_width = 1; ++ fsize->stepwise.step_height = 1; ++ ++ return 0; ++} ++ ++static int ingenic_camera_s_input(struct file *file, void *fh, unsigned int i) ++{ ++ return 0; ++} ++ ++static const struct v4l2_ioctl_ops cim_video_ioctl_ops = { ++ .vidioc_querycap = ingenic_camera_querycap, ++ .vidioc_enum_fmt_vid_cap = ingenic_camera_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = ingenic_camera_g_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = ingenic_camera_s_fmt_vid_cap, ++ .vidioc_g_selection = ingenic_camera_g_selection, ++ .vidioc_s_selection = ingenic_camera_s_selection, ++ .vidioc_try_fmt_vid_cap = ingenic_camera_try_fmt_vid_cap, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ .vidioc_enum_framesizes = ingenic_camera_enum_framesizes, ++ .vidioc_s_input = ingenic_camera_s_input, ++// .vidioc_g_parm = isp_video_g_parm, ++// .vidioc_s_ctrl = isp_video_s_ctrl, ++// .vidioc_g_ctrl = isp_video_g_ctrl, ++}; ++ ++ ++/*video_queue_ops*/ ++static int ingenic_videobuf_init(struct vb2_buffer *vb2) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); ++ struct ingenic_buffer *buf = container_of(vbuf, struct ingenic_buffer, vb); ++ ++ INIT_LIST_HEAD(&buf->list); ++ ++ return 0; ++} ++ ++ ++static int ingenic_videobuf_setup(struct vb2_queue *q, ++ unsigned int *num_buffers, unsigned int *num_planes, ++ unsigned int sizes[], struct device *alloc_devs[]) ++{ ++ struct cim_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct v4l2_pix_format *user_fmt = &ctx->format.fmt.pix; ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ struct ingenic_camera_dev *pcdev = cimvideo->pcdev; ++ int max_video_mem = pcdev->cim_priv->max_video_mem; ++ int size; ++ ++ *num_planes = 1; ++ size = user_fmt->sizeimage; ++ if(ctx->hist_en) ++ size += CIM_HIST_SIZE; ++ else if(ctx->lumi_en){ ++ size += CIM_LUMI_SIZE; ++ } ++ ++ if (!*num_buffers || *num_buffers > max_buffer_num) ++ *num_buffers = max_buffer_num; ++ ++ if (size * *num_buffers > max_video_mem) ++ *num_buffers = max_video_mem / size; ++ ++ sizes[0] = size; ++ alloc_devs[0] = cimvideo->pcdev->dev; ++ ++ pcdev->start_streaming_called = 0; ++ pcdev->sequence = 0; ++ pcdev->active = NULL; ++ ++ if(ingenic_camera_alloc_desc(pcdev, *num_buffers)) ++ return -ENOMEM; ++ dev_info(cimvideo->dev, "%s, count=%d, size=%d\n", __func__, ++ *num_buffers, size); ++ ++ return 0; ++} ++ ++static int ingenic_buffer_prepare(struct vb2_buffer *vb) ++{ ++ struct cim_video_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct v4l2_pix_format *user_fmt = &ctx->format.fmt.pix; ++ int ret = 0; ++ ++ dev_vdbg(ctx->cimvideo.dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, ++ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); ++ ++ vb2_set_plane_payload(vb, 0, user_fmt->sizeimage); ++ if (vb2_plane_vaddr(vb, 0) && ++ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { ++ ret = -EINVAL; ++ return ret; ++ } ++ ++ return 0; ++ ++} ++ ++ ++static void ingenic_buffer_queue(struct vb2_buffer *vb) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ struct cim_video_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct ingenic_camera_dev *pcdev = ctx->cimvideo.pcdev; ++ struct ingenic_buffer *buf = container_of(vbuf, struct ingenic_buffer, vb); ++ struct ingenic_camera_desc_v1 *desc_v1_v; ++ struct ingenic_camera_desc_v1 *desc_v1_p; ++ struct ingenic_camera_desc_v2 *desc_v2_v; ++ struct ingenic_camera_desc_v2 *desc_v2_p; ++ unsigned long flags; ++ unsigned int regval; ++ int index = vb->index; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ++ list_add_tail(&buf->list, &pcdev->video_buffer_list); ++ if (!pcdev->active) { ++ pcdev->active = buf; ++ } ++ ++ if(!pcdev->start_streaming_called) { ++ goto out; ++ } ++ ++ if((index > pcdev->buf_cnt) || (index < 0)) { ++ dev_err(ctx->cimvideo.dev,"Warning: index %d out of range!\n", index); ++ goto out; ++ } ++ ++ if(pcdev->cim_priv->version_num == 2) { ++ desc_v2_v = (struct ingenic_camera_desc_v2 *) pcdev->desc_vaddr; ++ desc_v2_p = pcdev->desc_v2_paddr; ++ ++ if(is_cim_disabled(pcdev) && list_is_singular(&pcdev->video_buffer_list)) { ++ desc_v2_v[index].DES_CFG_t.data.DES_END = 1; ++ desc_v2_v[index].DES_INTC_t.data.EOF_MSK = 0; ++ ++ pcdev->desc_v2_head = &desc_v2_v[index]; ++ pcdev->desc_v2_tail = &desc_v2_v[index]; ++ ++ regval = (dma_addr_t)(&desc_v2_p[index]); ++ cim_writel(pcdev, regval, DES_ADDR); ++ cim_writel(pcdev, CIM_CTRL_START, CIM_CTRL); ++ } else { ++ pcdev->desc_v2_tail->next = (dma_addr_t)(&desc_v2_p[index]); ++ pcdev->desc_v2_tail->DES_INTC_t.data.EOF_MSK = 1; ++ pcdev->desc_v2_tail->DES_CFG_t.data.DES_END = 0; ++ pcdev->desc_v2_tail = &desc_v2_v[index]; ++ ++ desc_v2_v[index].DES_CFG_t.data.DES_END = 1; ++ desc_v2_v[index].DES_INTC_t.data.EOF_MSK = 0; ++ } ++ } else { ++ desc_v1_v = (struct ingenic_camera_desc_v1 *) pcdev->desc_vaddr; ++ desc_v1_p = pcdev->desc_v1_paddr; ++ ++ if(is_cim_disabled(pcdev) && list_is_singular(&pcdev->video_buffer_list)) { ++ desc_v1_v[index].DES_CFG_t.data.DES_END = 1; ++ desc_v1_v[index].DES_INTC_t.data.EOF_MSK = 0; ++ ++ pcdev->desc_v1_head = &desc_v1_v[index]; ++ pcdev->desc_v1_tail = &desc_v1_v[index]; ++ ++ regval = (dma_addr_t)(&desc_v1_p[index]); ++ cim_writel(pcdev, regval, DES_ADDR); ++ cim_writel(pcdev, CIM_CTRL_START, CIM_CTRL); ++ } else { ++ pcdev->desc_v1_tail->next = (dma_addr_t)(&desc_v1_p[index]); ++ pcdev->desc_v1_tail->DES_INTC_t.data.EOF_MSK = 1; ++ pcdev->desc_v1_tail->DES_CFG_t.data.DES_END = 0; ++ pcdev->desc_v1_tail = &desc_v1_v[index]; ++ ++ desc_v1_v[index].DES_CFG_t.data.DES_END = 1; ++ } ++ } ++ ++out: ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ ++ if(showFPS){ ++ calculate_frame_rate(); ++ } ++ ++ return; ++} ++ ++static void ingenic_cim_start(struct ingenic_camera_dev *pcdev) ++{ ++ struct vb2_buffer *vb2 = &pcdev->active->vb.vb2_buf; ++ unsigned regval = 0; ++ int index; ++ ++ BUG_ON(!pcdev->active); ++ ++ /* clear status register */ ++ cim_writel(pcdev, CIM_CLR_ALL, CIM_CLR_ST); ++ ++ /* configure dma desc addr*/ ++ index = vb2->index; ++ if (pcdev->cim_priv->version_num == 2) ++ regval = (dma_addr_t)(&(pcdev->desc_v2_paddr[index])); ++ else ++ regval = (dma_addr_t)(&(pcdev->desc_v1_paddr[index])); ++ ++ cim_writel(pcdev, regval, DES_ADDR); ++ ++ cim_writel(pcdev, CIM_CTRL_START, CIM_CTRL); ++} ++ ++static void ingenic_cim_stop(struct ingenic_camera_dev *pcdev) ++{ ++ cim_writel(pcdev, CIM_CTRL_QCK_STOP, CIM_CTRL); ++ cim_writel(pcdev, CIM_CLR_ALL, CIM_CLR_ST); ++} ++ ++static int ingenic_cim_soft_reset(struct cim_video_ctx *ctx) ++{ ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ struct ingenic_camera_dev *pcdev = cimvideo->pcdev; ++ struct v4l2_subdev *sd = cimvideo->subdev; ++ int count = 4000; ++ ++ v4l2_subdev_call(sd, video, s_stream, 1); ++ ++ cim_writel(pcdev, CIM_CTRL_SOFT_RST, CIM_CTRL); ++ while((!(cim_readl(pcdev,CIM_ST) & CIM_ST_SRST)) && count--) { ++ udelay(1000); ++ } ++ ++ if (count < 0) { ++ v4l2_subdev_call(sd, video, s_stream, 0); ++ dev_err(pcdev->dev, "cim soft reset failed!\n"); ++ return -ENODEV; ++ } ++ cim_writel(pcdev,CIM_CLR_SRST,CIM_CLR_ST); ++ ++ v4l2_subdev_call(sd, video, s_stream, 0); ++ ++ return 0; ++} ++ ++static int ingenic_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct cim_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct ingenic_camera_dev *pcdev = ctx->cimvideo.pcdev; ++ struct v4l2_subdev *sd = ctx->cimvideo.subdev; ++ struct ingenic_buffer *buf, *node; ++ int version = pcdev->cim_priv->version_num; ++ int index = ctx->cimvideo.index; ++ struct cim_async_subdev *casd = &pcdev->casd[index]; ++ unsigned long flags; ++ int ret = 0; ++ unsigned int tmp = 0; ++ ++ list_for_each_entry_safe(buf, node, &pcdev->video_buffer_list, list) { ++ ret = ingenic_init_desc(&buf->vb.vb2_buf); ++ if(ret) { ++ dev_err(ctx->cimvideo.dev, "%s:Desc initialization failed\n", ++ __func__); ++ return ret; ++ } ++ } ++ ++ if(casd->bus_type == V4L2_MBUS_CSI2_DPHY) { ++ ret = csi_phy_start(version, casd->mipi_csi2.num_data_lanes); ++ if(ret < 0) { ++ dev_err(ctx->cimvideo.dev, "csi starting failed!\n"); ++ return ret; ++ } ++ } ++ ++ ret = ingenic_cim_soft_reset(ctx); ++ if(ret) ++ goto err; ++ ++ v4l2_subdev_call(sd, video, s_stream, 1); ++ ++ if(ret) ++ goto err; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ingenic_cim_start(pcdev); ++ pcdev->start_streaming_called = 1; ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ ++ return 0; ++err: ++ if(casd->bus_type == V4L2_MBUS_CSI2_DPHY) ++ csi_phy_stop(version); ++ ++ if(ctx->snapshot){ ++ tmp = cim_readl(pcdev, GLB_CFG); ++ tmp &= ~GLB_CFG_DAT_MODE; ++ tmp &= ~GLB_CFG_EXPO_WIDTH_MASK_V2; ++ cim_writel(pcdev, tmp, GLB_CFG); ++ cim_writel(pcdev, 0, DLY_CFG); ++ } ++ ++ list_for_each_entry_safe(buf, node, &pcdev->video_buffer_list, list) { ++ list_del_init(&buf->list); ++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); ++ } ++ ++ pcdev->desc_v1_head = NULL; ++ pcdev->desc_v1_tail = NULL; ++ pcdev->desc_v2_head = NULL; ++ pcdev->desc_v2_tail = NULL; ++ ++ return ret; ++} ++ ++static void ingenic_stop_streaming(struct vb2_queue *q) ++{ ++ struct cim_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct v4l2_subdev *sd = ctx->cimvideo.subdev; ++ struct ingenic_camera_dev *pcdev = ctx->cimvideo.pcdev; ++ struct ingenic_buffer *buf, *node; ++ int version = pcdev->cim_priv->version_num; ++ int index = ctx->cimvideo.index; ++ struct cim_async_subdev *casd = &pcdev->casd[index]; ++ unsigned long flags; ++ unsigned int tmp = 0; ++ ++ spin_lock_irqsave(&pcdev->lock, flags); ++ ingenic_cim_stop(pcdev); ++// printk("[%d]~~~~~~~~%x\n", __LINE__, *(volatile unsigned int *)0xb3062004); ++ ++ /* Release all active buffers */ ++ list_for_each_entry_safe(buf, node, &pcdev->video_buffer_list, list) { ++ list_del_init(&buf->list); ++ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ } ++ ++ pcdev->start_streaming_called = 0; ++ pcdev->desc_v1_head = NULL; ++ pcdev->desc_v1_tail = NULL; ++ pcdev->desc_v2_head = NULL; ++ pcdev->desc_v2_tail = NULL; ++ pcdev->active = NULL; ++ ++ if(ctx->snapshot){ ++ tmp = cim_readl(pcdev, GLB_CFG); ++ tmp &= ~GLB_CFG_DAT_MODE; ++ tmp &= ~GLB_CFG_EXPO_WIDTH_MASK_V2; ++ cim_writel(pcdev, tmp, GLB_CFG); ++ cim_writel(pcdev, 0, DLY_CFG); ++ } ++ ++ spin_unlock_irqrestore(&pcdev->lock, flags); ++ ++ if(casd->bus_type == V4L2_MBUS_CSI2_DPHY) ++ csi_phy_stop(version); ++ v4l2_subdev_call(sd, video, s_stream, 0); ++} ++ ++ ++static struct vb2_ops cim_video_queue_ops = { ++ .buf_init = ingenic_videobuf_init, ++ .queue_setup = ingenic_videobuf_setup, ++ .buf_prepare = ingenic_buffer_prepare, ++ .buf_queue = ingenic_buffer_queue, ++ .start_streaming = ingenic_start_streaming, ++ .stop_streaming = ingenic_stop_streaming, ++}; ++ ++static void ingenic_camera_activate(struct ingenic_camera_dev *pcdev) { ++ int ret = -1; ++ ++ if(pcdev->clk) { ++ ret = clk_prepare_enable(pcdev->clk); ++ } ++ if(pcdev->mipi_clk) { ++ ret = clk_prepare_enable(pcdev->mipi_clk); ++ } ++} ++ ++static void ingenic_camera_deactivate(struct ingenic_camera_dev *pcdev) { ++ if( pcdev->mipi_clk) { ++ clk_disable_unprepare(pcdev->mipi_clk); ++ } ++ if(pcdev->clk) { ++ clk_disable_unprepare(pcdev->clk); ++ } ++} ++ ++ ++static int cim_video_open(struct file *file) ++{ ++ struct cim_video_ctx *ctx = video_drvdata(file); ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ struct ingenic_camera_dev *pcdev = cimvideo->pcdev; ++ struct video_device *video = &cimvideo->video; ++ struct vb2_queue *queue = NULL; ++ int ret = 0; ++ ++ mutex_lock(&pcdev->mutex); ++ ++ if(pcdev->active_ctx){ ++ if(cimvideo->index != pcdev->active_ctx->cimvideo.index) ++ dev_info(cimvideo->dev, "Only one cim video device node can be operated at the same time"); ++ ret = -EBUSY; ++ goto err_busy; ++ } ++ ++ v4l2_fh_init(&ctx->fh, &cimvideo->video); ++ v4l2_fh_add(&ctx->fh); ++ ++ queue = &ctx->queue; ++ queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ queue->io_modes = VB2_MMAP |VB2_USERPTR; ++ queue->drv_priv = ctx; ++ queue->ops = &cim_video_queue_ops; ++ queue->mem_ops = &ingenic_vb2_dma_contig_memops; ++ queue->buf_struct_size = sizeof(struct ingenic_buffer); ++ queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ queue->lock = &cimvideo->queue_lock; ++ ++ ret = vb2_queue_init(queue); ++ if(ret < 0) { ++ goto err_vb2_queue_init; ++ } ++ ++ video->queue = queue; ++ ++ file->private_data = &ctx->fh; ++ pcdev->active_ctx = ctx; ++ ingenic_camera_activate(pcdev); ++ ++ mutex_unlock(&pcdev->mutex); ++ ++ return 0; ++ ++err_vb2_queue_init: ++ v4l2_fh_del(&ctx->fh); ++err_busy: ++ mutex_unlock(&pcdev->mutex); ++ return ret; ++} ++ ++static int cim_video_release(struct file *file) ++{ ++ struct cim_video_ctx *ctx = video_drvdata(file); ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ struct ingenic_camera_dev *pcdev = cimvideo->pcdev; ++ struct video_device *video = &cimvideo->video; ++ ++ /*lock*/ ++ mutex_lock(&pcdev->mutex); ++ ++ vb2_queue_release(video->queue); ++ ++ ingenic_camera_deactivate(pcdev); ++ ingenic_camera_free_desc(pcdev); ++ ++ pcdev->active_ctx = NULL; ++ file->private_data = NULL; ++ video->queue = NULL; ++ ++ memset(&ctx->img_sz, 0, sizeof(struct ingenic_image_sz)); ++ memset(&ctx->format, 0, sizeof(struct v4l2_format)); ++ ctx->interlace = 0; ++ ctx->uv_offset = 0; ++ ctx->payload_size = 0; ++ ++ ctx->hist_en = 0; ++ ctx->hist_gain_add = 0; ++ ctx->hist_gain_mul = 0; ++ ctx->lumi_en = 0; ++ ctx->snapshot = 0; ++ ctx->output_y = 0; ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ ++ /*unlock*/ ++ mutex_unlock(&pcdev->mutex); ++ ++ return 0; ++ ++} ++ ++ ++static struct v4l2_file_operations cim_video_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = video_ioctl2, ++ .open = cim_video_open, ++ .release = cim_video_release, ++ .poll = vb2_fop_poll, ++ .mmap = vb2_fop_mmap, ++}; ++ ++int ingenic_cim_asd_notifier_bound(struct v4l2_async_notifier *notifier, ++ struct v4l2_subdev *subdev, ++ struct v4l2_async_subdev *asd) ++{ ++ struct v4l2_device *v4l2_dev = notifier->v4l2_dev; ++ struct ingenic_camera_dev *pcdev = v4l2_dev_to_pcdev(v4l2_dev); ++ struct cim_video_device *cimvideo = NULL; ++ struct video_device *video = NULL; ++ int index = get_asd_index(asd); ++ struct cim_video_ctx *ctx = pcdev->ctx[index]; ++ int ret = 0; ++ ++ ctx = kzalloc(sizeof(struct cim_video_ctx), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(ctx)) { ++ dev_err(cimvideo->dev, "Failed to alloc ctx for cim_video_ctx\n"); ++ ret = -ENOMEM; ++ goto err_ctx_alloc; ++ } ++ ++ cimvideo = &ctx->cimvideo; ++ video = &cimvideo->video; ++ ++ cimvideo->pcdev = pcdev; ++ cimvideo->index = index; ++ cimvideo->alloc_ctx = ingenic_vb2_dma_contig_init_ctx(cimvideo->dev); ++ if(IS_ERR_OR_NULL(cimvideo->alloc_ctx)) { ++ ret = -ENOMEM; ++ goto err_dma_alloc_ctx; ++ } ++ ++ mutex_init(&cimvideo->queue_lock); ++ mutex_init(&cimvideo->stream_lock); ++ ++ /*ctrl_handler*/ ++ v4l2_ctrl_handler_init(&ctx->hdl, 10); ++ v4l2_ctrl_new_custom(&ctx->hdl, &img_crop_way, NULL); ++ if (pcdev->cim_priv->version_num == 2) { ++ v4l2_ctrl_new_custom(&ctx->hdl, &lumi_en, NULL); ++ v4l2_ctrl_new_custom(&ctx->hdl, &output_y, NULL); ++ v4l2_ctrl_new_custom(&ctx->hdl, &point1_x, NULL); ++ v4l2_ctrl_new_custom(&ctx->hdl, &point1_y, NULL); ++ v4l2_ctrl_new_custom(&ctx->hdl, &point2_x, NULL); ++ v4l2_ctrl_new_custom(&ctx->hdl, &point2_y, NULL); ++ } else { ++ v4l2_ctrl_new_custom(&ctx->hdl, &img_scale_sharp, NULL); ++ v4l2_ctrl_new_custom(&ctx->hdl, &hist_en, NULL); ++ v4l2_ctrl_new_custom(&ctx->hdl, &hist_gain_add, NULL); ++ v4l2_ctrl_new_custom(&ctx->hdl, &hist_gain_mul, NULL); ++ } ++ v4l2_ctrl_new_custom(&ctx->hdl, &snapshot_en, NULL); ++ v4l2_ctrl_new_custom(&ctx->hdl, &exp_pulse_w, NULL); ++ v4l2_ctrl_new_custom(&ctx->hdl, &delay_t, NULL); ++ ++ v4l2_ctrl_handler_setup(&ctx->hdl); ++ ++ /*video register device*/ ++ snprintf(video->name, sizeof(video->name), "%s-%d", v4l2_dev->name, index); ++ video->fops = &cim_video_fops; ++ video->ioctl_ops = &cim_video_ioctl_ops; ++ video->release = video_device_release_empty; ++ video->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ video->v4l2_dev = v4l2_dev; ++ video->ctrl_handler = &ctx->hdl; ++ video_set_drvdata(video, ctx); ++ ++ cimvideo->dev = pcdev->dev; ++ cimvideo->subdev = subdev; ++ ++ ret = video_register_device(video, VFL_TYPE_VIDEO, ingenic_cim_get_video_nr(index)); ++ if(ret < 0) { ++ goto err_video_register_device; ++ } ++ ++ dev_info(pcdev->dev, "register video device %s @ /dev/video%d ok\n", video->name, video->num); ++ ++ return 0; ++ ++err_video_register_device: ++ ingenic_vb2_dma_contig_cleanup_ctx(cimvideo->alloc_ctx); ++err_dma_alloc_ctx: ++ kfree(ctx); ++err_ctx_alloc: ++ return ret; ++} ++ ++int ingenic_cim_asd_notifier_complete(struct v4l2_async_notifier *notifier){ ++ ++ return 0; ++} ++ ++void ingenic_cim_asd_notifier_unbind(struct v4l2_async_notifier *notifier, ++ struct v4l2_subdev *subdev, ++ struct v4l2_async_subdev *asd) ++{ ++ struct v4l2_device *v4l2_dev = notifier->v4l2_dev; ++ struct ingenic_camera_dev *pcdev = v4l2_dev_to_pcdev(v4l2_dev); ++ int index = get_asd_index(asd); ++ struct cim_video_ctx *ctx = pcdev->ctx[index]; ++ struct cim_video_device *cimvideo = &ctx->cimvideo; ++ ++ v4l2_ctrl_handler_free(&ctx->hdl); ++ video_unregister_device(&cimvideo->video); ++ ingenic_vb2_dma_contig_cleanup_ctx(cimvideo->alloc_ctx); ++ kfree(ctx); ++} ++ ++struct v4l2_async_notifier_operations ingenic_cim_async_ops = { ++ .bound = ingenic_cim_asd_notifier_bound, ++ .complete = ingenic_cim_asd_notifier_complete, ++ .unbind = ingenic_cim_asd_notifier_unbind, ++}; ++ ++ ++static int ingenic_cim_phrase_remote_endpoint(struct ingenic_camera_dev *pcdev) ++{ ++ struct device_node *node = NULL; ++ struct v4l2_async_subdev *asd = NULL; ++ int ret = 0; ++ ++ v4l2_async_notifier_init(&pcdev->notifier); ++ while((node = of_graph_get_next_endpoint(pcdev->dev->of_node, node)) && pcdev->asd_num < MAX_ASYNC_SUBDEVS) ++ { ++ pcdev->casd[pcdev->asd_num].index = pcdev->asd_num; ++ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &pcdev->vep[pcdev->asd_num]); ++ if(ret) { ++ of_node_put(node); ++ return ret; ++ } ++ pcdev->casd[pcdev->asd_num].bus_type = pcdev->vep[pcdev->asd_num].bus_type; ++ pcdev->casd[pcdev->asd_num].parallel = pcdev->vep[pcdev->asd_num].bus.parallel; ++ pcdev->casd[pcdev->asd_num].mipi_csi2 = pcdev->vep[pcdev->asd_num].bus.mipi_csi2; ++ pcdev->casd[pcdev->asd_num].index = pcdev->asd_num; ++ ++ asd = &pcdev->casd[pcdev->asd_num].asd; ++ asd->match.fwnode = fwnode_graph_get_remote_port_parent(of_fwnode_handle(node)); ++ asd->match_type = V4L2_ASYNC_MATCH_FWNODE; ++ ++ of_node_put(node); ++ ++ ret = v4l2_async_notifier_add_subdev(&pcdev->notifier, asd); ++ if (ret) { ++ fwnode_handle_put(asd->match.fwnode); ++ return ret; ++ } ++ ++ fwnode_handle_put(asd->match.fwnode); ++ ++ pcdev->asd_num++; ++ } ++ return ret; ++} ++ ++/**********************cim_debug***************************/ ++static ssize_t frame_size_check_r(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ snprintf(buf, 100, " 0: disable frame size check.\n 1: enable frame size check.\n"); ++ return 100; ++} ++ ++static ssize_t frame_size_check_w(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ if (count != 2) ++ return -EINVAL; ++ ++ if (*buf == '0') { ++ frame_size_check_flag = 0; ++ } else if (*buf == '1') { ++ frame_size_check_flag = 1; ++ } else { ++ return -EINVAL; ++ } ++ ++ return count; ++} ++ ++static ssize_t fps_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ printk("\n-----you can choice print way:\n"); ++ printk("Example: echo NUM > show_fps\n"); ++ printk("NUM = 0: close fps statistics\n"); ++ printk("NUM = 1: print recently fps\n"); ++ printk("NUM = 2: print interval between last and this queue buffers\n"); ++ printk("NUM > 2: print fps after NUM second\n"); ++ return 0; ++} ++ ++static ssize_t fps_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ int num = 0; ++ num = simple_strtoul(buf, NULL, 0); ++ if(num < 0){ ++ printk("\n--please 'cat show_fps' to view using the method\n\n"); ++ return n; ++ } ++ showFPS = num; ++ return n; ++} ++ ++static DEVICE_ATTR(frame_size_check, S_IRUGO|S_IWUSR, frame_size_check_r, frame_size_check_w); ++static DEVICE_ATTR(show_fps, S_IRUGO|S_IWUSR, fps_show, fps_store); ++ ++static struct attribute *cim_debug_attrs[] = { ++ &dev_attr_frame_size_check.attr, ++ &dev_attr_show_fps.attr, ++ NULL, ++}; ++const char cim_group_name[] = "debug"; ++static struct attribute_group cim_debug_attr_group = { ++ .name = cim_group_name, ++ .attrs = cim_debug_attrs, ++}; ++ ++/***************************prob*******************************/ ++static struct cim_private version1_pri = { ++ .max_video_mem = VIDEO_MEM + CIM_HIST_SIZE, ++ .version_num = 1, ++ ++}; ++ ++static struct cim_private version2_pri = { ++ .max_video_mem = VIDEO_MEM + CIM_LUMI_SIZE, ++ .version_num = 2, ++}; ++ ++static const struct of_device_id ingenic_camera_of_match[] = { ++ { .compatible = "ingenic,m300-cim", .data = (struct cim_private *)&version1_pri }, ++ { .compatible = "ingenic,x2000-cim", .data = (struct cim_private *)&version1_pri }, ++ { .compatible = "ingenic,x1600-cim", .data = (struct cim_private *)&version2_pri }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_camera_of_match); ++ ++static int ingenic_camera_probe(struct platform_device *pdev) { ++ int ret = 0; ++ unsigned int irq; ++ struct resource *res; ++ void __iomem *base; ++ struct ingenic_camera_dev *pcdev; ++ ++ /* malloc */ ++ pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL); ++ if (!pcdev) { ++ dev_err(&pdev->dev, "Could not allocate pcdev\n"); ++ ret = -ENOMEM; ++ goto err_kzalloc; ++ } ++ ++ /* resource */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(!res) { ++ dev_err(&pdev->dev, "Could not get resource!\n"); ++ ret = -ENODEV; ++ goto err_get_resource; ++ } ++ ++ /* irq */ ++ irq = platform_get_irq(pdev, 0); ++ if (irq <= 0) { ++ dev_err(&pdev->dev, "Could not get irq!\n"); ++ ret = -ENODEV; ++ goto err_get_irq; ++ } ++ ++ pcdev->priv = of_match_node(ingenic_camera_of_match, pdev->dev.of_node); ++ pcdev->cim_priv = (struct cim_private *)pcdev->priv->data; ++ ++ printk("cim current version: %d\n", pcdev->cim_priv->version_num); ++ ++ /*get cim clk*/ ++ pcdev->clk = of_clk_get(pdev->dev.of_node, 1); ++ if (pcdev->clk == NULL) { ++ ret = PTR_ERR(pcdev->clk); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__, "cim"); ++ goto err_clk_get_cim; ++ } ++ ++ /*get mipi clk*/ ++ pcdev->mipi_clk = of_clk_get(pdev->dev.of_node, 2); ++ if (pcdev->mipi_clk == NULL) { ++ ret = PTR_ERR(pcdev->clk); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__, "cim"); ++ goto err_clk_get_mipi; ++ } ++ ++ /* Request the regions. */ ++ if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) { ++ ret = -EBUSY; ++ goto err_request_mem_region; ++ } ++ base = ioremap(res->start, resource_size(res)); ++ if (!base) { ++ ret = -ENOMEM; ++ goto err_ioremap; ++ } ++ ++ spin_lock_init(&pcdev->lock); ++ INIT_LIST_HEAD(&pcdev->video_buffer_list); ++ mutex_init(&pcdev->mutex); ++ ++ pcdev->dev = &pdev->dev; ++ pcdev->res = res; ++ pcdev->irq = irq; ++ pcdev->base = base; ++ pcdev->active = NULL; ++ pcdev->desc_v1_head = NULL; ++ pcdev->desc_v1_tail = NULL; ++ pcdev->desc_v2_head = NULL; ++ pcdev->desc_v2_tail = NULL; ++ ++ /* request irq */ ++ ret = devm_request_irq(&pdev->dev, pcdev->irq, ingenic_camera_irq_handler, 0, ++ dev_name(&pdev->dev), pcdev); ++ if(ret) { ++ dev_err(&pdev->dev, "request irq failed!\n"); ++ goto err_request_irq; ++ } ++ ++ ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev); ++ if (ret) ++ goto err_v4l2_dev_register; ++ ++ ret = sysfs_create_group(&pcdev->dev->kobj, &cim_debug_attr_group); ++ if (ret) { ++ dev_err(&pdev->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_free_file; ++ } ++ ++ /*asd*/ ++ ret = ingenic_cim_phrase_remote_endpoint(pcdev); ++ if(ret) ++ goto err_phrase_remote_endpoint; ++ ++ pcdev->notifier.ops = &ingenic_cim_async_ops; ++ ret = v4l2_async_notifier_register(&pcdev->v4l2_dev, &pcdev->notifier); ++ if(ret){ ++ printk( "v4l2_async_notifier_register failed %d\n", ret); ++ goto err_regist_notifier; ++ } ++ ++ ret = of_reserved_mem_device_init(pcdev->dev); ++ if(ret) ++ dev_warn(pcdev->dev, "failed to init reserved mem\n"); ++ ++ dev_dbg(&pdev->dev, "ingenic Camera driver loaded!\n"); ++ ++ platform_set_drvdata(pdev, pcdev); ++ return 0; ++ ++err_regist_notifier: ++err_phrase_remote_endpoint: ++ sysfs_remove_group(&pcdev->dev->kobj, &cim_debug_attr_group); ++err_free_file: ++ v4l2_device_unregister(&pcdev->v4l2_dev); ++err_v4l2_dev_register: ++ free_irq(pcdev->irq, pcdev); ++err_request_irq: ++ iounmap(pcdev->base); ++err_ioremap: ++ release_mem_region(res->start, resource_size(res)); ++err_request_mem_region: ++ devm_clk_put(&pdev->dev, pcdev->mipi_clk); ++err_clk_get_mipi: ++ devm_clk_put(&pdev->dev, pcdev->clk); ++err_clk_get_cim: ++err_get_irq: ++err_get_resource: ++ kfree(pcdev); ++// cimvideo->ops = video_ops; ++err_kzalloc: ++ return ret; ++ ++} ++ ++static int ingenic_camera_remove(struct platform_device *pdev) ++{ ++ struct ingenic_camera_dev *pcdev = platform_get_drvdata(pdev); ++ ++ v4l2_async_notifier_unregister(&pcdev->notifier); ++ sysfs_remove_group(&pcdev->dev->kobj, &cim_debug_attr_group); ++ v4l2_device_unregister(&pcdev->v4l2_dev); ++ free_irq(pcdev->irq, pcdev); ++ iounmap(pcdev->base); ++ release_mem_region(pcdev->res->start, resource_size(pcdev->res)); ++ devm_clk_put(&pdev->dev, pcdev->mipi_clk); ++ devm_clk_put(&pdev->dev, pcdev->clk); ++ kfree(pcdev); ++ dev_dbg(&pdev->dev, "ingenic Camera driver unloaded\n"); ++ return 0; ++} ++ ++static struct platform_driver ingenic_camera_driver = { ++ .probe = ingenic_camera_probe, ++ .remove = ingenic_camera_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = ingenic_camera_of_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_camera_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("anan "); ++MODULE_DESCRIPTION("ingenic Soc Camera Host Driver"); ++MODULE_ALIAS("a ingenic-cim platform"); +diff --git a/module_drivers/drivers/media/platform/ingenic-cim/ingenic_camera.h b/module_drivers/drivers/media/platform/ingenic-cim/ingenic_camera.h +new file mode 100644 +index 000000000..444929776 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-cim/ingenic_camera.h +@@ -0,0 +1,581 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Core file for Ingenic Display Controller driver ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __INGENIC_CAMERA_H__ ++#define __INGENIC_CAMERA_H__ ++ ++#include ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++//#include ++//#include ++ ++ ++#define VERSION_CODE KERNEL_VERSION(0, 0, 1) ++#define DRIVER_NAME "ingenic-cim" ++#define CAMERA_GSENSOR_VCC "vcc_gsensor" ++#define CIM_BUS_FLAGS \ ++ (SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | \ ++ SOCAM_VSYNC_ACTIVE_LOW | SOCAM_HSYNC_ACTIVE_HIGH | \ ++ SOCAM_HSYNC_ACTIVE_LOW | SOCAM_PCLK_SAMPLE_RISING | \ ++ SOCAM_PCLK_SAMPLE_FALLING | SOCAM_DATAWIDTH_8) ++ ++#define CIM_LUMI_SIZE (9 * 4) ++#define CIM_HIST_SIZE (256 * 4) ++#define VIDEO_MEM (16 * 2046 * 2046) ++#define INGENIC_CAMERA_CSI2_2_LANE 1 ++#define INGENIC_CAMERA_HSYNC_HIGH 2 ++#define INGENIC_CAMERA_PCLK_RISING 4 ++#define INGENIC_CAMERA_VSYNC_HIGH 6 ++ ++/* ingenic cim ctrl id */ ++#define INGENIC_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) ++#define INGENIC_CID_SCALE_SHARP (INGENIC_CID_CUSTOM_BASE + 1) ++#define INGENIC_CID_HIST_EN (INGENIC_CID_CUSTOM_BASE + 2) ++#define INGENIC_CID_HIST_GAIN_ADD (INGENIC_CID_CUSTOM_BASE + 3) ++#define INGENIC_CID_HIST_GAIN_MUL (INGENIC_CID_CUSTOM_BASE + 4) ++#define INGENIC_CID_CROP_WAY (INGENIC_CID_CUSTOM_BASE + 5) ++#define INGENIC_CID_SNAPSHOT_EN (INGENIC_CID_CUSTOM_BASE + 6) ++#define INGENIC_CID_EXP_PULSE_W (INGENIC_CID_CUSTOM_BASE + 7) ++#define INGENIC_CID_SNAPSHOT_DELAY_T (INGENIC_CID_CUSTOM_BASE + 8) ++#define INGENIC_CID_POINT2_X (INGENIC_CID_CUSTOM_BASE + 9) ++#define INGENIC_CID_POINT2_Y (INGENIC_CID_CUSTOM_BASE + 10) ++#define INGENIC_CID_OUTPUT_Y (INGENIC_CID_CUSTOM_BASE + 11) ++#define INGENIC_CID_LUMI_EN (INGENIC_CID_CUSTOM_BASE + 12) ++#define INGENIC_CID_POINT1_X (INGENIC_CID_CUSTOM_BASE + 13) ++#define INGENIC_CID_POINT1_Y (INGENIC_CID_CUSTOM_BASE + 14) ++ ++#define INGENIC_MEDIA_BUS_FMT_RBG565_2X8_LE 0x1118 ++#define INGENIC_MEDIA_BUS_FMT_BRG565_2X8_LE 0x1119 ++#define INGENIC_MEDIA_BUS_FMT_GRB565_2X8_LE 0x111a ++#define INGENIC_MEDIA_BUS_FMT_GBR565_2X8_LE 0x111b ++ ++ ++#define INGENIC_V4L2_PIX_FMT_RBG565 v4l2_fourcc('R', 'B', 'G', 'P') /* 16 RBG-5-6-5 */ ++#define INGENIC_V4L2_PIX_FMT_BGR565 v4l2_fourcc('B', 'G', 'R', 'P') /* 16 BGR-5-6-5 */ ++#define INGENIC_V4L2_PIX_FMT_BRG565 v4l2_fourcc('B', 'R', 'G', 'P') /* 16 BRG-5-6-5 */ ++#define INGENIC_V4L2_PIX_FMT_GRB565 v4l2_fourcc('G', 'R', 'B', 'P') /* 16 GRB-5-6-5 */ ++#define INGENIC_V4L2_PIX_FMT_GBR565 v4l2_fourcc('G', 'B', 'R', 'P') /* 16 GBR-5-6-5 */ ++ ++struct cim_video_format { ++ const char *name; ++ unsigned int fourcc; ++ unsigned int depth[3]; /*max 3 plane*/ ++ unsigned int mbus_code; ++ unsigned int num_planes; ++ enum v4l2_colorspace colorspace; ++}; ++ ++typedef union DES_INTC{ ++ unsigned int d32; ++ struct{ ++ unsigned reserved0:1; ++ unsigned EOF_MSK:1; ++ unsigned SOF_MSK:1; ++ unsigned reserved3_31:29; ++ }data; ++ ++}DES_INTC_t; ++ ++typedef union DES_CFG{ ++ unsigned int d32; ++ struct{ ++ unsigned DES_END:1; ++ unsigned reserved1_15:15; ++ unsigned WRBK_FMT:3; ++ unsigned reserved19_25:7; ++ unsigned ID:6; ++ }data; ++ ++}DES_CFG_t; ++ ++typedef union DES_HIST_CFG { ++ unsigned int d32; ++ struct{ ++ unsigned int GAIN_MUL:8; ++ unsigned int GAIN_ADD:8; ++ unsigned int reserved16_30:15; ++ unsigned int HIST_EN:1; ++ }; ++}DES_HIST_CFG_t; ++ ++typedef union DES_LUMI_CFG { ++ unsigned int d32; ++ struct{ ++ unsigned int reserved0_29:30; ++ unsigned int LUMI_EN:1; ++ unsigned int reserved31:1; ++ }; ++}DES_LUMI_CFG_t; ++ ++struct ingenic_camera_desc_v1{ ++ dma_addr_t next; ++ unsigned int WRBK_ADDR; ++ unsigned int WRBK_STRD; ++ DES_INTC_t DES_INTC_t; ++ DES_CFG_t DES_CFG_t; ++ DES_HIST_CFG_t DES_HIST_CFG_t; ++ unsigned int HIST_WRBK_ADDR; ++ unsigned int SF_WRBK_ADDR; ++}__attribute__ ((aligned (8))); ++ ++struct ingenic_camera_desc_v2{ ++ dma_addr_t next; ++ unsigned int WRBK_ADDR; ++ unsigned int WRBK_STRD; ++ DES_INTC_t DES_INTC_t; ++ DES_CFG_t DES_CFG_t; ++ DES_LUMI_CFG_t DES_LUMI_CFG_t; ++ unsigned int LUMI_WRBK_ADDR; ++ unsigned int SF_WRBK_ADDR; ++}__attribute__ ((aligned (8))); ++ ++struct cim_private { ++ int max_video_mem; ++ int version_num; ++}; ++ ++struct sensor_pdata { ++ unsigned int gpio_rst; ++ unsigned int gpio_power; ++ unsigned int gpio_en; ++// enum v4l2_mbus_type dat_if; ++ /* senser support snapshot function */ ++ unsigned short snapshot; ++ /* snapshot exposure pulse time, unit pixclk cycle */ ++ unsigned short exp_pulse_w; ++ /* the time it takes to end a frame ++ * to the next frame start*/ ++ unsigned int delay_t; ++}; ++ ++struct ingenic_camera_pdata { ++ unsigned long mclk_10khz; ++ unsigned long flags; ++ struct sensor_pdata sensor_pdata; ++}; ++ ++/* buffer for one video frame */ ++struct ingenic_buffer { ++ /* common v4l buffer stuff -- must be first */ ++ struct vb2_v4l2_buffer vb; ++ struct list_head list; ++}; ++ ++enum { ++ IMG_NO_RESIZE, ++ IMG_RESIZE_CROP, ++}; ++ ++enum { ++ CROP_SPECIFY_ZONE, ++ CROP_BASE_MAX_PIC, ++}; ++ ++struct ingenic_image_sz{ ++ bool rsz_flag; ++ unsigned int src_w; //camera input size ++ unsigned int src_h; ++ ++ unsigned int c_left; //crop size ++ unsigned int c_top; ++ unsigned int c_w; ++ unsigned int c_h; ++}; ++ ++struct cim_async_subdev { ++// struct v4l2_subdev *sd; ++ struct v4l2_async_subdev asd; ++ int index; ++ ++ enum v4l2_mbus_type bus_type; ++ struct v4l2_fwnode_bus_parallel parallel; ++ struct v4l2_fwnode_bus_mipi_csi2 mipi_csi2; ++ ++// int enabled; ++ ++// unsigned int source_pad; ++}; ++ ++ ++struct cim_video_device { ++ struct ingenic_camera_dev *pcdev; ++ struct device *dev; ++ struct v4l2_subdev *subdev; ++ char *name; ++ int index; ++ struct video_device video; ++ ++ void *alloc_ctx; ++// struct vb2_queue *queue; ++ struct mutex queue_lock; ++ struct mutex stream_lock; ++ ++ unsigned int max_buffer_num; /*max vb2 num*/ ++}; ++ ++struct cim_video_ctx { ++ struct cim_video_device cimvideo; ++ struct vb2_queue queue; ++ struct v4l2_ctrl_handler hdl; ++ struct v4l2_fh fh; /*handle*/ ++ struct ingenic_image_sz img_sz; ++ struct v4l2_format format; ++ unsigned int interlace; ++ unsigned int uv_offset; ++ unsigned int payload_size; ++ ++ unsigned int hist_en; ++ unsigned int hist_gain_add; ++ unsigned int hist_gain_mul; ++ unsigned int lumi_en; ++ unsigned int snapshot; ++ unsigned int output_y; ++}; ++ ++ ++#define MAX_ASYNC_SUBDEVS 2 ++ ++struct ingenic_camera_dev { ++ struct v4l2_device v4l2_dev; ++ struct v4l2_async_notifier notifier; ++ struct cim_async_subdev casd[MAX_ASYNC_SUBDEVS]; ++ struct v4l2_fwnode_endpoint vep[MAX_ASYNC_SUBDEVS]; ++ struct cim_video_ctx *ctx[MAX_ASYNC_SUBDEVS]; ++ struct cim_video_ctx *active_ctx; ++ unsigned int asd_num; ++ struct mutex mutex; ++ ++ struct ingenic_buffer *active; ++ struct list_head video_buffer_list; ++ ++ int sequence; ++ int start_streaming_called; ++ unsigned int buf_cnt; ++ ++ ++ struct device *dev; ++ struct resource *res; ++ struct clk *clk; ++ struct clk *mclk; ++ struct clk *mipi_clk; ++ void __iomem *base; ++ unsigned int irq; ++ unsigned long mclk_freq; ++ spinlock_t lock; ++ ++ void *desc_vaddr; ++ struct ingenic_camera_desc_v1 *desc_v1_paddr; ++ struct ingenic_camera_desc_v1 *desc_v1_head; ++ struct ingenic_camera_desc_v1 *desc_v1_tail; ++ ++ struct ingenic_camera_desc_v2 *desc_v2_paddr; ++ struct ingenic_camera_desc_v2 *desc_v2_head; ++ struct ingenic_camera_desc_v2 *desc_v2_tail; ++ ++ struct ingenic_camera_pdata *pdata; ++ const struct of_device_id *priv; ++ struct cim_private *cim_priv; ++}; ++ ++#define GENMASK(h, l) \ ++ (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ++ ++#define GLB_CFG (0x0000) ++#define FRM_SIZE (0x0004) ++#define CROP_SITE (0x0008) ++#define RESIZE_CFG (0x000c) ++#define RESIZE_COEF_X (0x0010) ++#define RESIZE_COEF_Y (0x0014) ++#define SCAN_CFG (0x0018) ++#define DLY_CFG (0x001C) ++#define QOS_CTRL (0x0020) ++#define QOS_CFG (0x0024) ++#define LUMI_POINT1 (0x0028) ++#define LUMI_POINT2 (0x002c) ++#define DES_ADDR (0x1000) ++#define CIM_CTRL (0x2000) ++#define CIM_ST (0x2004) ++#define CIM_CLR_ST (0x2008) ++#define CIM_INTC (0x200c) ++#define INT_FLAG (0x2010) ++#define FRAME_ID (0x2014) ++#define ACT_SIZE (0x2018) ++#define DBG_DES (0x3000) ++#define DBG_DMA (0x3004) ++#define DBG_CGC (0x3008) ++ ++/** GLOBAL register*/ ++#define GLB_CFG_C_ORDER_HBIT_V1 23 ++#define GLB_CFG_C_ORDER_HBIT_V2 24 ++#define GLB_CFG_C_ORDER_LBIT 20 ++#define GLB_CFG_C_ORDER_MASK_V1 \ ++ GENMASK(GLB_CFG_C_ORDER_HBIT_V1, GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_MASK_V2 \ ++ GENMASK(GLB_CFG_C_ORDER_HBIT_V2, GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_RGB (0x0 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_RBG (0x1 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_GRB (0x2 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_GBR (0x3 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_BRG (0x4 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_BGR (0x5 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_YUYV (0x8 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_YVYU (0x9 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_UYVY (0xa << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_VYUY (0xb << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_RGGB (0x10 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_BGGR (0x11 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_GRBG (0x12 << GLB_CFG_C_ORDER_LBIT) ++#define GLB_CFG_C_ORDER_GBRG (0x13 << GLB_CFG_C_ORDER_LBIT) ++ ++#define GLB_CFG_ORG_FMT_HBIT_V1 18 ++#define GLB_CFG_ORG_FMT_HBIT_V2 19 ++#define GLB_CFG_ORG_FMT_LBIT 16 ++#define GLB_CFG_ORG_FMT_MASK_V1 \ ++ GENMASK(GLB_CFG_ORG_FMT_HBIT_V1, GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_MASK_V2 \ ++ GENMASK(GLB_CFG_ORG_FMT_HBIT_V2, GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_RGB565 (0x0 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_RGB888 (0x1 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_YUYV422 (0x2 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_ITU656 (0x3 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_MONO (0x4 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_10BIT_MONO (0x5 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_12BIT_MONO (0x6 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_8BIT_RAW (0x7 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_10BIT_RAW (0x8 << GLB_CFG_ORG_FMT_LBIT) ++#define GLB_CFG_ORG_FMT_12BIT_RAW (0x9 << GLB_CFG_ORG_FMT_LBIT) ++ ++#define GLB_CFG_DE_PCLK BIT(15) ++#define GLB_CFG_DL_VSYNC BIT(14) ++#define GLB_CFG_DL_HSYNC BIT(13) ++ ++#define GLB_CFG_EXPO_WIDTH_HBIT_V1 10 ++#define GLB_CFG_EXPO_WIDTH_HBIT_V2 12 ++#define GLB_CFG_EXPO_WIDTH_LBIT 8 ++#define GLB_CFG_EXPO_WIDTH_MASK_V1 \ ++ GENMASK(GLB_CFG_EXPO_WIDTH_HBIT_V1, GLB_CFG_EXPO_WIDTH_LBIT) ++#define GLB_CFG_EXPO_WIDTH_MASK_V2 \ ++ GENMASK(GLB_CFG_EXPO_WIDTH_HBIT_V2, GLB_CFG_EXPO_WIDTH_LBIT) ++#define GLB_CFG_SIZE_CHK BIT(5) ++#define GLB_CFG_DAT_IF_SEL BIT(4) ++#define GLB_CFG_DAT_MODE BIT(3) ++ ++#define GLB_CFG_BURST_LEN_HBIT 2 ++#define GLB_CFG_BURST_LEN_LBIT 1 ++#define GLB_CFG_BURST_LEN_MASK \ ++ GENMASK(GLB_CFG_BURST_LEN_HBIT, GLB_CFG_BURST_LEN_LBIT) ++#define GLB_CFG_BURST_LEN_4 (0x0 << GLB_CFG_BURST_LEN_LBIT) ++#define GLB_CFG_BURST_LEN_8 (0x1 << GLB_CFG_BURST_LEN_LBIT) ++#define GLB_CFG_BURST_LEN_16 (0x2 << GLB_CFG_BURST_LEN_LBIT) ++#define GLB_CFG_BURST_LEN_32 (0x3 << GLB_CFG_BURST_LEN_LBIT) ++ ++#define GLB_CFG_AUTO_RECOVERY BIT(0) ++ ++ ++/**Frame size register*/ ++#define CIM_CROP_WIDTH_HBIT 10 ++#define CIM_CROP_WIDTH_LBIT 0 ++#define CIM_CROP_WIDTH_MASK \ ++ GENMASK(CIM_CROP_WIDTH_HBIT, CIM_CROP_WIDTH_LBIT) ++ ++#define CIM_CROP_HEIGHT_HBIT 26 ++#define CIM_CROP_HEIGHT_LBIT 16 ++#define CIM_CROP_HEIGHT_MASK \ ++ GENMASK(CIM_CROP_HEIGHT_HBIT, CIM_CROP_HEIGHT_LBIT) ++ ++/**Crop site register*/ ++ ++#define CIM_CROP_X_HBIT 10 ++#define CIM_CROP_X_LBIT 0 ++#define CIM_CROP_X_MASK \ ++ GENMASK(CIM_CROP_X_HBIT, CIM_CROP_X_LBIT) ++ ++#define CIM_CROP_Y_HBIT 26 ++#define CIM_CROP_Y_LBIT 16 ++#define CIM_CROP_Y_MASK \ ++ GENMASK(CIM_CROP_Y_HBIT, CIM_CROP_Y_LBIT) ++ ++/** Scale size register*/ ++#define CIM_TAR_WIDTH_HBIT 10 ++#define CIM_TAR_WIDTH_LBIT 0 ++#define CIM_TAR_WIDTH_MASK \ ++ GENMASK(CIM_TAR_WIDTH_HBIT, CIM_TAR_WIDTH_LBIT) ++ ++#define CIM_TAR_HEIGHT_HBIT 26 ++#define CIM_TAR_HEIGHT_LBIT 16 ++#define CIM_TAR_HEIGHT_MASK \ ++ GENMASK(CIM_TAR_HEIGHT_HBIT, CIM_TAR_HEIGHT_LBIT) ++ ++#define CIM_SHARPL_HBIT 15 ++#define CIM_SHARPL_LBIT 14 ++#define CIM_SHARPL_MASK \ ++ GENMASK(CIM_SHARPL_HBIT, CIM_SHARPL_LBIT) ++#define CIM_LOWST_SHARPL (0x0 << CIM_SHARPL_LBIT) ++#define CIM_HIGST_SHARPL (0x3 << CIM_SHARPL_LBIT) ++ ++#define CIM_SCALE_EN BIT(31) ++ ++/**Resize Coef X register*/ ++#define CIM_RESIZE_COEF_X_HBIT 19 ++#define CIM_RESIZE_COEF_X_LBIT 0 ++#define CIM_RESIZE_COEF_X_MASK \ ++ GENMASK(CIM_RESIZE_COEF_X_HBIT, CIM_RESIZE_COEF_X_LBIT) ++ ++/**Resize Coef Y register*/ ++ ++#define CIM_RESIZE_COEF_Y_HBIT 19 ++#define CIM_RESIZE_COEF_Y_LBIT 0 ++#define CIM_RESIZE_COEF_Y_MASK \ ++ GENMASK(CIM_RESIZE_COEF_Y_HBIT, CIM_RESIZE_COEF_Y_LBIT) ++ ++/**Second Field Height register*/ ++#define CIM_SF_HEIGHT_HBIT 11 ++#define CIM_SF_HEIGHT_LBIT 0 ++#define CIM_SF_HEIGHT_MASK \ ++ GENMASK(CIM_SF_HEIGHT_HBIT, CIM_SF_HEIGHT_LBIT) ++ ++#define CIM_F_ORDER BIT(30) ++#define CIM_SCAN_MD BIT(31) ++ ++/**Delay counter register*/ ++#define CIM_DLY_NUM_HBIT 23 ++#define CIM_DLY_NUM_LBIT 0 ++#define CIM_DLY_NUM_MASK \ ++ GENMASK(CIM_DLY_NUM_HBIT, CIM_DLY_NUM_LBIT) ++ ++#define CIM_EXPO_WIDTH_EN BIT(0) ++#define CIM_DLY_MD BIT(30) ++#define CIM_DLY_EN BIT(31) ++ ++#define CIM_QOS_CTRL BIT(0) ++#define CIM_QOS_VAL_HBIT 2 ++#define CIM_QOS_VAL_LBIT 1 ++#define CIM_QOS_VAL_MASK \ ++ GENMASK(CIM_QOS_VAL_HBIT, CIM_QOS_VAL_LBIT) ++ ++#define CIM_QOS_CFG_TH2_LBIT (26) ++#define CIM_QOS_CFG_TH2_HBIT (18) ++#define CIM_QOS_CFG_TH2_MASK \ ++ GENMASK(CIM_QOS_CFG_TH2_HBIT, CIM_QOS_CFG_TH2_LBIT) ++#define CIM_QOS_CFG_TH1_LBIT (17) ++#define CIM_QOS_CFG_TH1_HBIT (9) ++#define CIM_QOS_CFG_TH1_MASK \ ++ GENMASK(CIM_QOS_CFG_TH1_HBIT, CIM_QOS_CFG_TH1_LBIT) ++#define CIM_QOS_CFG_TH0_LBIT (0) ++#define CIM_QOS_CFG_TH0_HBIT (8) ++#define CIM_QOS_CFG_TH0_MASK \ ++ GENMASK(CIM_QOS_CFG_TH0_HBIT, CIM_QOS_CFG_TH0_LBIT) ++ ++/**Descriptor address register*/ ++#define CIM_DES_ADDR_HBIT 31 ++#define CIM_DES_ADDR_LBIT 0 ++#define CIM_DES_ADDR_MASK \ ++ GENMASK(CIM_DES_ADDR_HBIT, CIM_DES_ADDR_LBIT) ++ ++/**Control register*/ ++#define CIM_CTRL_START BIT(0) ++#define CIM_CTRL_QCK_STOP BIT(1) ++#define CIM_CTRL_GEN_STOP BIT(2) ++#define CIM_CTRL_SOFT_RST BIT(3) ++#define CIM_CTRL_DBG_DES_RST BIT(4) ++ ++/**status register*/ ++#define CIM_ST_WORKING BIT(0) ++#define CIM_ST_EOF BIT(1) ++#define CIM_ST_SOF BIT(2) ++#define CIM_ST_GSA BIT(3) ++#define CIM_ST_OVER BIT(4) ++#define CIM_ST_EOW BIT(5) ++#define CIM_ST_SZ_ERR BIT(6) ++#define CIM_ST_SRST BIT(7) ++ ++/**Clear status register*/ ++#define CIM_CLR_FRM_END BIT(1) ++#define CIM_CLR_FRM_START BIT(2) ++#define CIM_CLR_GSA BIT(3) ++#define CIM_CLR_OVER BIT(4) ++#define CIM_CLR_EOW BIT(5) ++#define CIM_CLR_SZ_ERR BIT(6) ++#define CIM_CLR_SRST BIT(7) ++#define CIM_CLR_ALL \ ++ (CIM_CLR_FRM_END | CIM_CLR_FRM_START | \ ++ CIM_CLR_GSA | CIM_CLR_OVER | \ ++ CIM_CLR_EOW | CIM_CLR_SZ_ERR) ++ ++/**CIM INTC register*/ ++#define CIM_INTC_MSK_EOF BIT(1) ++#define CIM_INTC_MSK_SOF BIT(2) ++#define CIM_INTC_MSK_GSA BIT(3) ++#define CIM_INTC_MSK_OVER BIT(4) ++#define CIM_INTC_MSK_EOW BIT(5) ++#define CIM_INTC_MSK_SZ_ERR BIT(6) ++ ++/**CIM_INT_FLAG*/ ++#define CIM_INT_FLAG_EOF BIT(1) ++#define CIM_INT_FLAG_SOF BIT(2) ++#define CIM_INT_FLAG_GSA BIT(3) ++#define CIM_INT_FLAG_OVER BIT(4) ++#define CIM_INT_FLAG_EOW BIT(5) ++#define CIM_INT_FLAG_SZ_ERR BIT(6) ++ ++#define CIM_CGC_FLOW BIT(0) ++#define CIM_CGC_DVP BIT(1) ++#define CIM_CGC_SCALE BIT(2) ++#define CIM_CGC_DES BIT(3) ++#define CIM_CGC_WRBK BIT(4) ++#define CIM_CGC_REG BIT(5) ++ ++/**dma Write back format*/ ++#define DES_CFG_WRBK_FMT_HBIT 18 ++#define DES_CFG_WRBK_FMT_LBIT 16 ++#define DES_CFG_WRBK_FMT_MASK \ ++ GENMASK(DES_CFG_WRBK_FMT_HBIT, DES_CFG_WRBK_FMT_LBIT) ++ ++#define WRBK_FMT_RGB888 (6) ++#define WRBK_FMT_Y (5) ++#define WRBK_FMT_MONO (4) ++#define WRBK_FMT_YUV422 (3) ++#define WRBK_FMT_RGB565 (1) ++ ++ ++#define CIM_HSIT_EN BIT(31) ++#define CIM_GAIN_ADD_HBIT 15 ++#define CIM_GAIN_ADD_LBIT 8 ++#define CIM_GAIN_ADD_MASK \ ++ GENMASK(CIM_GAIN_ADD_HBIT, CIM_GAIN_ADD_LBIT) ++#define CIM_GAIN_MUL_HBIT 7 ++#define CIM_GAIN_MUL_LBIT 0 ++#define CIM_GAIN_MUL_MASK \ ++ GENMASK(CIM_GAIN_MUL_HBIT, CIM_GAIN_MUL_LBIT) ++ ++static inline void cim_writel(struct ingenic_camera_dev *pcdev, ++ unsigned int val, unsigned int off) ++{ ++ writel(val, pcdev->base + off); ++} ++ ++static inline unsigned int cim_readl(struct ingenic_camera_dev *pcdev, ++ unsigned int off) ++{ ++ return readl(pcdev->base + off); ++} ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-cim/mipi_csi.c b/module_drivers/drivers/media/platform/ingenic-cim/mipi_csi.c +new file mode 100644 +index 000000000..cf143f883 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-cim/mipi_csi.c +@@ -0,0 +1,222 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Core file for Ingenic Display Controller driver ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mipi_csi.h" ++ ++void dump_csi_reg(void) ++{ ++ printk("****>>>>> dump csi reg <<<<<******\n"); ++ printk("**********VERSION =%08x\n", csi_core_read(VERSION)); ++ printk("**********N_LANES =%08x\n", csi_core_read(N_LANES)); ++ printk("**********PHY_SHUTDOWNZ = %08x\n", csi_core_read(PHY_SHUTDOWNZ)); ++ printk("**********DPHY_RSTZ = %08x\n", csi_core_read(DPHY_RSTZ)); ++ printk("**********CSI2_RESETN =%08x\n", csi_core_read(CSI2_RESETN)); ++ printk("**********PHY_STATE = %08x\n", csi_core_read(PHY_STATE)); ++ printk("**********DATA_IDS_1 = %08x\n", csi_core_read(DATA_IDS_1)); ++ printk("**********DATA_IDS_2 = %08x\n", csi_core_read(DATA_IDS_2)); ++ printk("**********ERR1 = %08x\n", csi_core_read(ERR1)); ++ printk("**********ERR2 = %08x\n", csi_core_read(ERR2)); ++ printk("**********MASK1 =%08x\n", csi_core_read(MASK1)); ++ printk("**********MASK2 =%08x\n", csi_core_read(MASK2)); ++ printk("**********PHY_TST_CTRL0 = %08x\n", csi_core_read(PHY_TST_CTRL0)); ++ printk("**********PHY_TST_CTRL1 = %08x\n", csi_core_read(PHY_TST_CTRL1)); ++} ++ ++void check_csi_error(void) { ++ ++ unsigned int temp1, temp2; ++ while(1){ ++ dump_csi_reg(); ++ temp1 = csi_core_read(ERR1); ++ temp2 = csi_core_read(ERR2); ++ if(temp1 != 0) ++ printk("error-------- 1:0x%08x\n", temp1); ++ if(temp2 != 0) ++ printk("error-------- 2:0x%08x\n", temp2); ++ } ++} ++ ++static unsigned char csi_core_write_part(unsigned int address, unsigned int data, unsigned char shift, unsigned char width) ++{ ++ unsigned int mask = (1 << width) - 1; ++ unsigned int temp = csi_core_read(address); ++ temp &= ~(mask << shift); ++ temp |= (data & mask) << shift; ++ csi_core_write(address, temp); ++ ++ return 0; ++} ++ ++static unsigned char csi_event_disable(unsigned int mask, unsigned char err_reg_no) ++{ ++ switch (err_reg_no) ++ { ++ case 1: ++ csi_core_write(MASK1, mask | csi_core_read(MASK1)); ++ break; ++ case 2: ++ csi_core_write(MASK2, mask | csi_core_read(MASK2)); ++ break; ++ default: ++ return ERR_OUT_OF_BOUND; ++ } ++ ++ return 0; ++} ++ ++unsigned char csi_set_on_lanes(unsigned char lanes) ++{ ++ csi_core_write_part(N_LANES, (lanes - 1), 0, 2); ++ return 0; ++} ++ ++static int csi_phy_ready(void) ++{ ++ int ready; ++ ++ // TODO: phy0: lane0 is ready. need to be update for other lane ++ ready = csi_core_read(PHY_STATE); ++ ++ if ((ready & (1 << 10 )) && (ready & (1<<4))) ++ return 1; ++ ++ return 0; ++} ++ ++ ++/* Reduce power consumption */ ++int csi_phy_set_bandgap(void) ++{ ++ unsigned int reg; ++ ++ /*reset phy*/ ++ csi_core_write_part(PHY_SHUTDOWNZ, 0, 0, 1); ++ csi_core_write_part(CSI2_RESETN, 0, 0, 1); ++ csi_core_write_part(DPHY_RSTZ, 0, 0, 1); ++ ++ csi_core_write_part(CSI2_RESETN, 1, 0, 1); ++ csi_core_write_part(DPHY_RSTZ, 1, 0, 1); ++ csi_core_write_part(PHY_SHUTDOWNZ, 1, 0, 1); ++ ++ /* set bandgap (reg0b[7])*/ ++ reg = csi_phy_read(RXPHY_REG_0_0b); ++ reg |= (0x1 << 7); ++ csi_phy_write(RXPHY_REG_0_0b, reg); ++ /* printk("debug ---- > reg0b[7]:0x%08x, %d\n", csi_phy_read(RXPHY_REG_0_0b), __LINE__); */ ++ return 0; ++} ++ ++int csi_phy_start(int version, unsigned int lans) ++{ ++ int retries = 30; ++ int i; ++ unsigned int reg; ++ ++ if (version == 1) { ++ printk("*******%s***** lans = %d\n", __func__, lans); ++ csi_set_on_lanes(lans); ++ ++ /* both csi0 csi1 */ ++ *(volatile unsigned int *) 0xb0074008 = 1; ++ *(volatile unsigned int *) 0xb007400c = 1; ++ *(volatile unsigned int *) 0xb0073008 = 1; ++ *(volatile unsigned int *) 0xb007300c = 1; ++ ++ csi_core_write_part(CSI2_RESETN, 0, 0, 1); ++ csi_core_write_part(CSI2_RESETN, 1, 0, 1); ++ } else { ++ /*reset phy*/ ++ csi_core_write_part(PHY_SHUTDOWNZ, 0, 0, 1); ++ csi_core_write_part(CSI2_RESETN, 0, 0, 1); ++ csi_core_write_part(DPHY_RSTZ, 0, 0, 1); ++ ++ printk("lans: %d\n", lans); ++ csi_set_on_lanes(lans); ++ ++ csi_core_write_part(CSI2_RESETN, 1, 0, 1); ++ csi_core_write_part(DPHY_RSTZ, 1, 0, 1); ++ csi_core_write_part(PHY_SHUTDOWNZ, 1, 0, 1); ++ ++ udelay(1000); ++ ++ /*r/w phy register*/ ++ switch(lans) { ++ case 1: ++ csi_phy_write(RXPHY_REG_0_00, 0x75); ++ break; ++ case 2: ++ csi_phy_write(RXPHY_REG_0_00, 0x7d); ++ break; ++ default: ++ printk("Config lans error\n"); ++ break; ++ } ++ csi_phy_write(RXPHY_REG_2_0a, 0x3f); ++ ++ /* clear bandgap (reg0b[7])*/ ++ reg = csi_phy_read(RXPHY_REG_0_0b); ++ reg &= ~(0x1 << 7); ++ csi_phy_write(RXPHY_REG_0_0b, reg); ++ /* printk("debug ---- > reg0b[7]:0x%08x\n", csi_phy_read(RXPHY_REG_0_0b)); */ ++ ++ } ++ ++ /* MASK all interrupts */ ++ csi_event_disable(0xffffffff, 1); ++ csi_event_disable(0xffffffff, 2); ++ ++ if (version == 2) { ++ /* wait for phy ready */ ++ for (i = 0; i < retries; i++) { ++ if (csi_phy_ready()) ++ break; ++ udelay(300); ++ } ++ ++ if (i >= retries) { ++ printk("CSI PHY is not ready\n"); ++ return -1; ++ ++ ++ } ++ } ++ ++ return 0; ++} ++ ++int csi_phy_stop(int version) ++{ ++ ++ printk("csi_phy_stop being called \n"); ++ /*reset phy*/ ++ /* both csi0 csi1 */ ++ if (version == 1) { ++ *(volatile unsigned int *) 0xb0074008 = 0; ++ *(volatile unsigned int *) 0xb007400c = 0; ++ } else { ++ csi_phy_set_bandgap(); ++ } ++ *(volatile unsigned int *) 0xb0073008 = 0; ++ *(volatile unsigned int *) 0xb007300c = 0; ++// csi_core_write_part(PHY_SHUTDOWNZ, 0, 0, 1); ++// csi_core_write_part(DPHY_RSTZ, 0, 0, 1); ++ csi_core_write_part(CSI2_RESETN, 0, 0, 1); ++ ++ return 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-cim/mipi_csi.h b/module_drivers/drivers/media/platform/ingenic-cim/mipi_csi.h +new file mode 100644 +index 000000000..fbb11cc5e +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-cim/mipi_csi.h +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (c) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com/ ++ * ++ * Core file for Ingenic Display Controller driver ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __MIPI_CSI_H__ ++#define __MIPI_CSI_H__ ++ ++/* csi host regs, base addr should be defined in board cfg */ ++#ifdef CONFIG_SOC_X1600 ++#define DWC_CSI_CTRL_BASE 0xB0073000 ++#else ++#define DWC_CSI_CTRL_BASE 0xB0074000 ++#endif ++#define INNO_CSI_PHY_BASE 0xB0076000 ++ ++/* csi controller */ ++#define VERSION 0x00 ++#define N_LANES 0x04 ++#define PHY_SHUTDOWNZ 0x08 ++#define DPHY_RSTZ 0x0C ++#define CSI2_RESETN 0x10 ++#define PHY_STATE 0x14 ++#define DATA_IDS_1 0x18 ++#define DATA_IDS_2 0x1C ++#define ERR1 0x20 ++#define ERR2 0x24 ++#define MASK1 0x28 ++#define MASK2 0x2C ++#define PHY_TST_CTRL0 0x30 ++#define PHY_TST_CTRL1 0x34 ++#define DEBUG 0x40 ++ ++/* csi d-phy */ ++#define LANE_EN 0x000 ++#define CLK_CNT_TIME 0x100 ++#define L0_CNT_TIME 0x180 ++#define L1_CNT_TIME 0x200 ++#define L2_CNT_TIME 0x280 ++#define L3_CNT_TIME 0x300 ++#define CLK_CON_MODE 0x128 ++#define SWITCH_LVDS_BANK 0x080 ++#define MODEL_EN 0x2cc ++#define LVDS_LOGICAL_EN 0x300 ++ ++/* inno d-phy*/ ++#define RXPHY_REG_0_00 0x00 ++#define RXPHY_REG_0_0b 0x2c ++#define RXPHY_REG_0_0d 0x34 ++#define RXPHY_REG_0_0e 0x38 ++#define RXPHY_REG_0_0f 0x3c ++#define RXPHY_REG_0_12 0x48 ++#define RXPHY_REG_1_00 0x80 ++#define RXPHY_REG_2_0a 0x128 ++#define RXPHY_REG_2_10 0x140 ++#define RXPHY_REG_2_11 0x144 ++#define RXPHY_REG_2_12 0x148 ++ ++typedef enum ++{ ++ ERR_NOT_INIT = 0xFE, ++ ERR_ALREADY_INIT = 0xFD, ++ ERR_NOT_COMPATIBLE = 0xFC, ++ ERR_UNDEFINED = 0xFB, ++ ERR_OUT_OF_BOUND = 0xFA, ++ SUCCESS = 0 ++} csi_error_t; ++ ++ ++#define dwc_csi_readl(reg) \ ++ readl((unsigned int *)(DWC_CSI_CTRL_BASE + reg)) ++#define dwc_csi_writel(reg, value) \ ++ writel((value), (unsigned int *)(DWC_CSI_CTRL_BASE + reg)) ++ ++#define csi_core_write(addr, value) dwc_csi_writel(addr, value) ++#define csi_core_read(addr) dwc_csi_readl(addr) ++ ++#define csi_phy_read(reg) \ ++ readl((unsigned int *)(INNO_CSI_PHY_BASE + reg)) ++#define csi_phy_write(reg, value) \ ++ writel((value), (unsigned int *)(INNO_CSI_PHY_BASE + reg)) ++ ++/* function */ ++extern int csi_phy_init(void); ++extern int csi_phy_start(int version, unsigned int lans); ++extern int csi_phy_stop(int version); ++ ++extern void dump_csi_reg(void); ++extern void check_csi_error(void); ++extern unsigned char csi_set_on_lanes(unsigned char lanes); ++ ++#endif/*__MIPI_CSI_H__*/ +diff --git a/module_drivers/drivers/media/platform/ingenic-i2d/Kconfig b/module_drivers/drivers/media/platform/ingenic-i2d/Kconfig +new file mode 100644 +index 000000000..cfbf78953 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-i2d/Kconfig +@@ -0,0 +1,16 @@ ++menuconfig JZ_I2D ++ bool "JZ I2D Driver" ++ default n ++ depends on SOC_X2500 && VIDEO_DEV && VIDEO_V4L2 ++ select VIDEOBUF2_DMA_CONTIG_INGENIC ++ select V4L2_MEM2MEM_DEV ++ help ++ Support for Ingenic i2d Driver ++ ++config INGENIC_I2D ++ tristate "Ingenic I2D Driver" ++ depends on JZ_I2D ++ default n ++ help ++ Support for Ingenic i2d operations (image rotater). ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-i2d/Makefile b/module_drivers/drivers/media/platform/ingenic-i2d/Makefile +new file mode 100644 +index 000000000..3a4ab3a39 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-i2d/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_INGENIC_I2D) += i2d_video.o ingenic_i2d.o +diff --git a/module_drivers/drivers/media/platform/ingenic-i2d/i2d_video.c b/module_drivers/drivers/media/platform/ingenic-i2d/i2d_video.c +new file mode 100644 +index 000000000..8e703661f +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-i2d/i2d_video.c +@@ -0,0 +1,751 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "i2d_video.h" ++#include "ingenic_i2d.h" ++ ++#define JZ_I2D_NAME "jz-i2d" ++ ++ ++static struct i2d_fmt formats[] = { ++ { ++ .name = "YUV 420", ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .depth = 12, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "RAW8", ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .depth = 16, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "RGB_565", ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .depth = 16, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "ARGB_8888", ++ .fourcc = V4L2_PIX_FMT_ARGB32, ++ .depth = 32, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++}; ++ ++#define NUM_FORMATS ARRAY_SIZE(formats) ++ ++static struct i2d_fmt *find_fmt(struct v4l2_format *f) ++{ ++ unsigned int i; ++ for (i = 0; i < NUM_FORMATS; i++) { ++ if (formats[i].fourcc == f->fmt.pix.pixelformat) ++ return &formats[i]; ++ } ++ return NULL; ++} ++ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ strncpy(cap->driver, JZ_I2D_NAME, sizeof(cap->driver) - 1); ++ strncpy(cap->card, JZ_I2D_NAME, sizeof(cap->card) - 1); ++ cap->bus_info[0] = 0; ++ cap->version = KERNEL_VERSION(4, 4, 19); ++ /* ++ * This is only a mem-to-mem video device. The capture and output ++ * device capability flags are left only for backward compatibility ++ * and are scheduled for removal. ++ */ ++ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; ++ cap->capabilities = cap->device_caps | ++ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | ++ V4L2_CAP_DEVICE_CAPS; ++ ++ return 0; ++} ++ ++static inline struct ingenic_i2d_ctx *fh_to_ctx(struct v4l2_fh *fh) ++{ ++ return container_of(fh, struct ingenic_i2d_ctx, fh); ++} ++ ++static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) ++{ ++ int i, num; ++ struct i2d_fmt *fmt; ++ ++ num = 0; ++ for (i = 0; i < NUM_FORMATS; ++i) { ++ if (formats[i].types & type) { ++ /* index-th format of type type found ? */ ++ if (num == f->index) ++ break; ++ /* Correct type but haven't reached our index yet, ++ * just increment per-type index */ ++ ++num; ++ } ++ } ++ ++ if (i < NUM_FORMATS) { ++ /* Format found */ ++ fmt = &formats[i]; ++ strncpy(f->description, fmt->name, sizeof(f->description) - 1); ++ f->pixelformat = fmt->fourcc; ++ return 0; ++ } ++ ++ /* Format not found */ ++ return -EINVAL; ++} ++ ++static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) ++{ ++ struct i2d_fmt *fmt; ++ enum v4l2_field *field; ++ ++ fmt = find_fmt(f); ++ if (!fmt) ++ return -EINVAL; ++ ++ field = &f->fmt.pix.field; ++ if (*field == V4L2_FIELD_ANY) ++ *field = V4L2_FIELD_NONE; ++ else if (*field != V4L2_FIELD_NONE) ++ return -EINVAL; ++ ++ if (f->fmt.pix.width > MAX_WIDTH ++ || f->fmt.pix.height > MAX_HEIGHT ++ || f->fmt.pix.width < MIN_WIDTH ++ || f->fmt.pix.height < MIN_HEIGHT) { ++ return -EINVAL; ++ } ++ ++ f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; ++ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; ++ return 0; ++} ++static struct i2d_frame_info *get_frame(struct ingenic_i2d_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ switch (type) { ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ return &ctx->out_info; ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ return &ctx->cap_info; ++ default: ++ return ERR_PTR(-EINVAL); ++ } ++} ++static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return enum_fmt(f, MEM2MEM_CAPTURE); ++} ++ ++static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return enum_fmt(f, MEM2MEM_OUTPUT); ++} ++ ++static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) ++{ ++ struct ingenic_i2d_ctx *ctx = fh_to_ctx(prv); ++ struct vb2_queue *vq; ++ struct i2d_frame_info *frame; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ frame = get_frame(ctx, f->type); ++ if (IS_ERR(frame)) ++ return PTR_ERR(frame); ++ ++ f->fmt.pix.width = frame->width; ++ f->fmt.pix.height = frame->height; ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ f->fmt.pix.pixelformat = frame->fmt->fourcc; ++ f->fmt.pix.bytesperline = (frame->width * frame->fmt->depth) >> 3; ++ f->fmt.pix.sizeimage = frame->size; ++ return 0; ++} ++ ++static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) ++{ ++ struct ingenic_i2d_ctx *ctx = fh_to_ctx(prv); ++ struct ingenic_i2d_dev *dev = ctx->i2d_dev; ++ struct vb2_queue *vq; ++ struct i2d_frame_info *frame; ++ struct i2d_fmt *fmt; ++ int ret = 0; ++ ++ /* Adjust all values accordingly to the hardware capabilities ++ * and chosen format. */ ++ ret = vidioc_try_fmt(file, prv, f); ++ if (ret) ++ return ret; ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (vb2_is_busy(vq)) { ++ v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type); ++ return -EBUSY; ++ } ++ frame = get_frame(ctx, f->type); ++ if (IS_ERR(frame)) ++ return PTR_ERR(frame); ++ fmt = find_fmt(f); ++ if (!fmt) ++ return -EINVAL; ++ frame->width = f->fmt.pix.width; ++ frame->height = f->fmt.pix.height; ++ frame->size = f->fmt.pix.sizeimage; ++ frame->fmt = fmt; ++ frame->bytesperline = f->fmt.pix.bytesperline; ++ return 0; ++} ++ ++static int vidioc_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_i2d_ctx *ctx = priv; ++ ++ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); ++} ++ ++static int vidioc_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_i2d_ctx *ctx = priv; ++ ++ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); ++} ++ ++static int _i2d_vidioc_expbuf(struct file *file, void* prv, ++ struct v4l2_exportbuffer *eb) ++{ ++ struct vb2_queue *vq; ++ struct ingenic_i2d_ctx *ctx = fh_to_ctx(prv); ++ if(ctx->m2m_ctx){ ++ return v4l2_m2m_expbuf(file,ctx->m2m_ctx,eb); ++ } ++ return -EINVAL; ++} ++ ++static int i2d_queue_setup(struct vb2_queue *vq, ++ unsigned int *num_buffers, unsigned int *num_planes, ++ unsigned int sizes[], struct device *alloc_devs[]) ++{ ++ struct ingenic_i2d_ctx *ctx = vb2_get_drv_priv(vq); ++ struct i2d_frame_info *frame = get_frame(ctx, vq->type); ++ ++ if (IS_ERR(frame)) ++ return PTR_ERR(frame); ++ ++ *num_planes = 1; ++ sizes[0] = frame->size; ++ alloc_devs[0] = ctx->i2d_dev->dev; ++ ++ if (*num_buffers == 0) ++ *num_buffers = 1; ++ ++ return 0; ++} ++ ++static int i2d_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ingenic_i2d_ctx *ctx = container_of(ctrl->handler, struct ingenic_i2d_ctx,ctrl_handler); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ctx->i2d_dev->ctrl_lock, flags); ++ switch (ctrl->id) { ++ case V4L2_CID_HFLIP: ++ ctx->hflip = ctx->ctrl_hflip->val; ++ break; ++ case V4L2_CID_VFLIP: ++ ctx->vflip = ctx->ctrl_vflip->val; ++ break; ++ case V4L2_CID_ROTATE: ++ ctx->angle = ctx->ctrl_rot->val; ++ break; ++ } ++ spin_unlock_irqrestore(&ctx->i2d_dev->ctrl_lock, flags); ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops i2d_ctrl_ops = { ++ .s_ctrl = i2d_s_ctrl, ++}; ++ ++static int i2d_setup_ctrls(struct ingenic_i2d_ctx *ctx) ++{ ++ struct ingenic_i2d_dev *dev = ctx->i2d_dev; ++ ++ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); ++ ++ ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &i2d_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ ++ ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &i2d_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ ctx->ctrl_rot = v4l2_ctrl_new_std(&ctx->ctrl_handler, &i2d_ctrl_ops, ++ V4L2_CID_ROTATE, 0, 270, 90, 0); ++ ++ if (ctx->ctrl_handler.error) { ++ int err = ctx->ctrl_handler.error; ++ v4l2_err(&dev->v4l2_dev, "rot_setup_ctrls failed\n"); ++ v4l2_ctrl_handler_free(&ctx->ctrl_handler); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int i2d_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct ingenic_i2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct i2d_frame_info *frame = get_frame(ctx, vb->vb2_queue->type); ++ ++ if (IS_ERR(frame)) ++ return PTR_ERR(frame); ++ vb2_set_plane_payload(vb, 0, frame->size); ++ return 0; ++} ++ ++static void i2d_buf_queue(struct vb2_buffer *vb) ++{ ++ struct ingenic_i2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ ++ if (ctx->m2m_ctx) ++ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); ++} ++ ++static struct vb2_ops i2d_qops = { ++ .queue_setup = i2d_queue_setup, ++ .buf_prepare = i2d_buf_prepare, ++ .buf_queue = i2d_buf_queue, ++}; ++ ++static int queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq) ++{ ++ struct ingenic_i2d_ctx *ctx = priv; ++ int ret; ++ ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; ++ src_vq->drv_priv = ctx; ++ src_vq->ops = &i2d_qops; ++ src_vq->mem_ops = &ingenic_vb2_dma_contig_memops; ++ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); ++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ src_vq->lock = &ctx->i2d_dev->dev_mutex; ++ ++ ret = vb2_queue_init(src_vq); ++ if (ret) ++ return ret; ++ ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; ++ dst_vq->drv_priv = ctx; ++ dst_vq->ops = &i2d_qops; ++ dst_vq->mem_ops = &ingenic_vb2_dma_contig_memops; ++ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); ++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ dst_vq->lock = &ctx->i2d_dev->dev_mutex; ++ ++ return vb2_queue_init(dst_vq); ++} ++ ++static void set_default_fmt(struct ingenic_i2d_ctx *ctx) ++{ ++ struct i2d_frame_info *cap, *out; ++ ++ cap = &ctx->cap_info; ++ out = &ctx->out_info; ++ ++ cap->width = DEFAULT_WIDTH; ++ cap->height = DEFAULT_HEIGHT; ++ cap->fmt = &formats[0]; ++ cap->bytesperline = DEFAULT_WIDTH * cap->fmt->depth >> 3; ++ cap->size = cap->bytesperline * cap->height; ++ ++ out->width = DEFAULT_WIDTH; ++ out->height = DEFAULT_HEIGHT; ++ out->fmt = &formats[0]; ++ out->bytesperline = DEFAULT_WIDTH * out->fmt->depth >> 3; ++ out->size = out->bytesperline * out->height; ++} ++ ++ ++static int i2d_open(struct file *file) ++{ ++ struct ingenic_i2d_dev *dev = video_drvdata(file); ++ struct ingenic_i2d_ctx *ctx = NULL; ++ int ret = 0; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ if (mutex_lock_interruptible(&dev->dev_mutex)) { ++ kfree(ctx); ++ return -ERESTARTSYS; ++ } ++ ctx->i2d_dev = dev; ++ ++ /* Set default formats */ ++ set_default_fmt(ctx); ++ ++ v4l2_fh_init(&ctx->fh, video_devdata(file)); ++ ctx->fh.ctrl_handler = &ctx->ctrl_handler; ++ file->private_data = &ctx->fh; ++ v4l2_fh_add(&ctx->fh); ++ ++ ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); ++ if (IS_ERR(ctx->m2m_ctx)) { ++ ret = PTR_ERR(ctx->m2m_ctx); ++ goto err; ++ } ++ ctx->fh.m2m_ctx = ctx->m2m_ctx; ++ ++ ret = i2d_setup_ctrls(ctx); ++ if(ret) ++ goto err; ++ ++ /* Write the default values to the ctx struct */ ++ v4l2_ctrl_handler_setup(&ctx->ctrl_handler); ++ ++ clk_prepare_enable(dev->clk); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ return 0; ++err: ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ mutex_unlock(&dev->dev_mutex); ++ kfree(ctx); ++ return ret; ++} ++ ++static int i2d_release(struct file *file) ++{ ++ struct ingenic_i2d_dev *dev = video_drvdata(file); ++ struct ingenic_i2d_ctx *ctx = fh_to_ctx(file->private_data); ++ ++ clk_disable_unprepare(dev->clk); ++ ++ mutex_lock(&dev->dev_mutex); ++ v4l2_m2m_ctx_release(ctx->m2m_ctx); ++ mutex_unlock(&dev->dev_mutex); ++ v4l2_ctrl_handler_free(&ctx->ctrl_handler); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ kfree(ctx); ++ return 0; ++} ++ ++static irqreturn_t i2d_irq_handler(int irq, void *prv) ++{ ++ struct ingenic_i2d_dev *dev = prv; ++ struct ingenic_i2d_ctx *ctx = dev->cur_ctx; ++ struct vb2_v4l2_buffer *src, *dst; ++ ++ unsigned int status = i2d_irq_clear(dev); ++ ++ if(unlikely(ctx == NULL)) { ++ printk("I2D:ctx == NULL\n"); ++ return IRQ_HANDLED; ++ } ++ ++ src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); ++ if(unlikely(src == NULL)) { ++ printk("I2D:src == NULL\n"); ++ return IRQ_HANDLED; ++ } ++ dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ if(unlikely(dst == NULL)) { ++ printk("I2D:dst == NULL\n"); ++ return IRQ_HANDLED; ++ } ++ ++ /* dst->timecode = src->timecode; */ ++ /* dst->timestamp = src->timestamp; */ ++ ++ v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); ++ v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); ++ v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); ++ ++ dev->cur_ctx = NULL; ++ if(status & 0x1) ++ wake_up(&dev->irq_queue); ++ return IRQ_HANDLED; ++} ++ ++static void device_run(void *prv) ++{ ++ struct ingenic_i2d_ctx *ctx = prv; ++ struct ingenic_i2d_dev *dev = ctx->i2d_dev; ++ struct vb2_v4l2_buffer *src, *dst; ++ unsigned long flags; ++ unsigned int srcaddr,dstaddr; ++ dev->cur_ctx = ctx; ++ ++ src = v4l2_m2m_next_src_buf(ctx->m2m_ctx); ++ dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); ++ ++ spin_lock_irqsave(&dev->ctrl_lock, flags); ++ ++ /* clk_prepare_enable(dev->clk); */ ++ i2d_safe_reset(dev); ++ srcaddr = ingenic_vb2_dma_contig_plane_dma_addr(&src->vb2_buf,0); ++ dstaddr = ingenic_vb2_dma_contig_plane_dma_addr(&dst->vb2_buf,0); ++ i2d_set_init_info(dev, &ctx->out_info,srcaddr,dstaddr); ++ /* do_gettimeofday(&time_now); */ ++ i2d_start(dev); ++ spin_unlock_irqrestore(&dev->ctrl_lock, flags); ++} ++ ++ ++ ++#define I2D_TIMEOUT 2000 ++static void job_abort(void *prv) ++{ ++ struct ingenic_i2d_ctx *ctx = prv; ++ struct ingenic_i2d_dev *dev = ctx->i2d_dev; ++ int ret; ++ ++ if (dev->cur_ctx == NULL) /* No job currently running */ ++ return; ++ ++ ret = wait_event_timeout(dev->irq_queue,dev->cur_ctx == NULL,msecs_to_jiffies(I2D_TIMEOUT)); ++ if(!ret) { ++ struct vb2_v4l2_buffer *src_vb, *dst_vb; ++ ++ i2d_safe_reset(dev); ++ ++ src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); ++ dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; ++ dst_vb->timecode = src_vb->timecode; ++ dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; ++ dst_vb->flags |= ++ src_vb->flags ++ & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; ++ ++ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR); ++ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR); ++ ++ v4l2_m2m_job_finish(dev->m2m_dev, ++ ctx->m2m_ctx); ++ dev->cur_ctx = NULL; ++ /* clk_disable_unprepare(dev->clk); */ ++ } else { ++ printk("I2D : wait_event_timeout %s []%d] >>>>>>>\n",__func__,__LINE__); ++ } ++} ++ ++static const struct v4l2_file_operations i2d_fops = { ++ .owner = THIS_MODULE, ++ .open = i2d_open, ++ .release = i2d_release, ++ .poll = v4l2_m2m_fop_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = v4l2_m2m_fop_mmap, ++}; ++ ++static const struct v4l2_ioctl_ops i2d_ioctl_ops = { ++ .vidioc_querycap = vidioc_querycap, ++ ++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt, ++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt, ++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt, ++ ++ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, ++ .vidioc_g_fmt_vid_out = vidioc_g_fmt, ++ .vidioc_try_fmt_vid_out = vidioc_try_fmt, ++ .vidioc_s_fmt_vid_out = vidioc_s_fmt, ++ ++ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, ++ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, ++ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, ++ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, ++ .vidioc_expbuf = _i2d_vidioc_expbuf, ++ ++ .vidioc_streamon = vidioc_streamon, ++ .vidioc_streamoff = vidioc_streamoff, ++}; ++ ++ ++static struct video_device i2d_videodev = { ++ .name = "ingenic-i2d", ++ .fops = &i2d_fops, ++ .ioctl_ops = &i2d_ioctl_ops, ++ .minor = -1, ++ .release = video_device_release, ++ .vfl_dir = VFL_DIR_M2M, ++}; ++ ++static struct v4l2_m2m_ops i2d_m2m_ops = { ++ .device_run = device_run, ++ .job_abort = job_abort, ++}; ++ ++static int ingenic_i2d_probe(struct platform_device *pdev) ++{ ++ struct ingenic_i2d_dev *i2d_dev; ++ struct video_device *vfd; ++ struct resource *res; ++ int ret = 0; ++ i2d_dev = devm_kzalloc(&pdev->dev, sizeof(*i2d_dev), GFP_KERNEL); ++ if (!i2d_dev) ++ return -ENOMEM; ++ i2d_dev->dev = &pdev->dev; ++ spin_lock_init(&i2d_dev->irqlock); ++ spin_lock_init(&i2d_dev->ctrl_lock); ++ mutex_init(&i2d_dev->dev_mutex); ++ atomic_set(&i2d_dev->num_inst,0); ++ init_waitqueue_head(&i2d_dev->irq_queue); ++ init_completion(&i2d_dev->done_i2d); ++ ++ res = platform_get_resource(pdev,IORESOURCE_MEM,0); ++ ++ i2d_dev->base = devm_ioremap_resource(&pdev->dev,res); ++ if(IS_ERR(i2d_dev->base)) ++ return PTR_ERR(i2d_dev->base); ++ ++ i2d_dev->irq = platform_get_irq(pdev,0); ++ if(i2d_dev->irq < 0){ ++ dev_err(&pdev->dev,"get i2d irq num error\n"); ++ return i2d_dev->irq; ++ } ++ ++ i2d_dev->name = pdev->name; ++ ++ ret = devm_request_irq(i2d_dev->dev, i2d_dev->irq, i2d_irq_handler, ++ IRQF_SHARED, i2d_dev->name, i2d_dev); ++ if(ret < 0){ ++ dev_err(i2d_dev->dev,"i2d request irq error\n"); ++ return ret; ++ } ++ /* i2d_dev->irq_is_request = 0; */ ++ ++ /* clocks */ ++ i2d_dev->clk = clk_get(&pdev->dev, "gate_i2d"); ++ if (IS_ERR(i2d_dev->clk)) { ++ dev_err(&pdev->dev, "cannot get clock\n"); ++ return PTR_ERR(i2d_dev->clk); ++ } ++ dev_dbg(&pdev->dev, "i2d clock source %p\n", i2d_dev->clk); ++ ++ ++ i2d_dev->alloc_ctx = ingenic_vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(i2d_dev->alloc_ctx)) { ++ ret = PTR_ERR(i2d_dev->alloc_ctx); ++ goto clk_get_cleanup; ++ } ++ ret = v4l2_device_register(&pdev->dev, &i2d_dev->v4l2_dev); ++ if (ret) ++ goto alloc_ctx_cleanup; ++ ++ vfd = &i2d_videodev; ++ vfd->lock = &i2d_dev->dev_mutex; ++ vfd->v4l2_dev = &i2d_dev->v4l2_dev; ++ vfd->device_caps = V4L2_CAP_STREAMING | ++ V4L2_CAP_VIDEO_M2M; ++ ++ ret = video_register_device(vfd, VFL_TYPE_VIDEO, INGENIC_ROTATE_VIDEO_NR); ++ if (ret) { ++ v4l2_err(&i2d_dev->v4l2_dev, "Failed to register video device\n"); ++ goto free_video_device; ++ } ++ ++ video_set_drvdata(vfd, i2d_dev); ++ snprintf(vfd->name, sizeof(vfd->name), "%s", i2d_videodev.name); ++ i2d_dev->vfd = vfd; ++ v4l2_info(&i2d_dev->v4l2_dev, "device registered as /dev/video%d\n",vfd->num); ++ ++ platform_set_drvdata(pdev, i2d_dev); ++ i2d_dev->m2m_dev = v4l2_m2m_init(&i2d_m2m_ops); ++ ++ if (IS_ERR(i2d_dev->m2m_dev)) { ++ v4l2_err(&i2d_dev->v4l2_dev, "Failed to init mem2mem device\n"); ++ ret = PTR_ERR(i2d_dev->m2m_dev); ++ goto unreg_video_dev; ++ } ++ printk("%s ok >>>>>>>>>>>>>>>>>>>>>>\n",__func__); ++ return 0; ++ ++unreg_video_dev: ++ video_unregister_device(vfd); ++free_video_device: ++unreg_v4l2_dev: ++ v4l2_device_unregister(&i2d_dev->v4l2_dev); ++alloc_ctx_cleanup: ++ ingenic_vb2_dma_contig_cleanup_ctx(i2d_dev->alloc_ctx); ++clk_get_cleanup: ++ clk_put(i2d_dev->clk); ++ ++ return 0; ++} ++ ++static int ingenic_i2d_remove(struct platform_device *pdev) ++{ ++ struct ingenic_i2d_dev *dev = (struct ingenic_i2d_dev *)platform_get_drvdata(pdev); ++ ++ v4l2_info(&dev->v4l2_dev, "Removing " JZ_I2D_NAME); ++ v4l2_m2m_release(dev->m2m_dev); ++ video_unregister_device(dev->vfd); ++ v4l2_device_unregister(&dev->v4l2_dev); ++ ingenic_vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); ++ clk_put(dev->clk); ++ return 0; ++} ++ ++ ++static const struct of_device_id ingenic_i2d_match[] = { ++ { ++ .compatible = "ingenic,x2500-i2d", ++ .data = NULL, ++ }, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_i2d_match); ++ ++ ++static struct platform_driver i2d_pdrv = { ++ .probe = ingenic_i2d_probe, ++ .remove = ingenic_i2d_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_i2d_match), ++ .name = JZ_I2D_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(i2d_pdrv); ++ ++MODULE_DESCRIPTION("X2500 i2d driver"); ++MODULE_LICENSE("GPL"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-i2d/i2d_video.h b/module_drivers/drivers/media/platform/ingenic-i2d/i2d_video.h +new file mode 100644 +index 000000000..912219abb +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-i2d/i2d_video.h +@@ -0,0 +1,75 @@ ++#ifndef __I2D_VIDEO_H__ ++#define __I2D_VIDEO_H__ ++ ++#include ++#include ++#include ++ ++#define MAX_WIDTH 3840 ++#define MAX_HEIGHT 2160 ++#define MIN_WIDTH 0 ++#define MIN_HEIGHT 0 ++ ++#define DEFAULT_WIDTH 640 ++#define DEFAULT_HEIGHT 480 ++ ++ ++#define MEM2MEM_CAPTURE (1 << 0) ++#define MEM2MEM_OUTPUT (1 << 1) ++ ++struct i2d_fmt { ++ char *name; ++ u32 fourcc; ++ int depth; ++ u32 types; ++}; ++ ++struct i2d_frame_info{ ++ uint16_t width; ++ uint16_t height; ++ struct i2d_fmt *fmt; ++ uint32_t size; ++ uint32_t bytesperline; ++}; ++ ++struct ingenic_i2d_dev { ++ char* name; ++ struct device *dev; ++ struct v4l2_device v4l2_dev; ++ struct v4l2_m2m_dev *m2m_dev; ++ struct video_device *vfd; ++ atomic_t num_inst; ++ struct mutex dev_mutex; ++ spinlock_t irqlock; ++ spinlock_t ctrl_lock; ++ void __iomem *base; ++ struct clk *clk; ++ int irq; ++ int irq_is_request; ++ wait_queue_head_t irq_queue; ++ void* *alloc_ctx; ++ struct ingenic_i2d_ctx *cur_ctx; ++ struct completion done_i2d; ++}; ++ ++struct ingenic_i2d_ctx { ++ struct v4l2_fh fh; ++ struct ingenic_i2d_dev *i2d_dev; ++ struct v4l2_m2m_ctx *m2m_ctx; ++ struct v4l2_ctrl_handler ctrl_handler; ++ struct v4l2_ctrl *ctrl_hflip; ++ struct v4l2_ctrl *ctrl_vflip; ++ struct v4l2_ctrl *ctrl_rot; ++ struct i2d_frame_info cap_info; ++ struct i2d_frame_info out_info; ++ uint32_t vflip; ++ uint32_t hflip; ++ uint32_t angle; ++ dma_addr_t paddr; ++}; ++ ++ ++ ++#endif // __I2D_VIDEO_H__ ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-i2d/ingenic_i2d.c b/module_drivers/drivers/media/platform/ingenic-i2d/ingenic_i2d.c +new file mode 100644 +index 000000000..9571f4799 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-i2d/ingenic_i2d.c +@@ -0,0 +1,252 @@ ++#include ++#include ++ ++#include "i2d_video.h" ++#include "ingenic_i2d.h" ++ ++ ++ ++static void reg_bit_set(struct ingenic_i2d_dev* dev,int offset,int bit) ++{ ++ unsigned int val = 0; ++ val = reg_read(dev,offset); ++ val |= bit; ++ reg_write(dev,offset,val); ++} ++ ++static void reg_bit_clr(struct ingenic_i2d_dev *dev,int offset, int bit) ++{ ++ unsigned int val = 0; ++ val = reg_read(dev,offset); ++ val &= ~ (bit); ++ reg_write(dev,offset,val); ++} ++ ++void i2d_safe_reset(struct ingenic_i2d_dev *dev) ++{ ++ reg_bit_set(dev,I2D_CTRL,I2D_SAFE_RESET); ++} ++ ++void i2d_reset(struct ingenic_i2d_dev *dev) ++{ ++ reg_bit_set(dev,I2D_CTRL,I2D_RESET); ++} ++ ++static int i2d_reg_set(struct ingenic_i2d_dev *i2d, struct i2d_param *i2d_param) ++{ ++ unsigned int fmt = 0; ++ unsigned int srcw = 0; ++ unsigned int srch = 0; ++ unsigned int flip_enable = 0, mirr_enable = 0, rotate_angle = 0, rotate_enable = 0; ++ unsigned int flip_mode = 0; ++ unsigned int value = 0; ++ ++ unsigned int src_y_pbuf = 0; ++ unsigned int src_uv_pbuf = 0; ++ unsigned int dst_y_pbuf = 0; ++ unsigned int dst_uv_pbuf = 0; ++ ++ unsigned int src_y_strid = 0; ++ unsigned int src_uv_strid = 0; ++ unsigned int dst_y_strid = 0; ++ unsigned int dst_uv_strid = 0; ++ ++ struct i2d_param *ip = i2d_param; ++ if (i2d == NULL) { ++ dev_err(i2d->dev, "i2d: i2d is NULL or i2d_param is NULL\n"); ++ return -1; ++ } ++ ++ fmt = ip->data_type; ++ srcw = ip->src_w; ++ srch = ip->src_h; ++ flip_enable = ip->flip_enable; ++ mirr_enable = ip->mirr_enable; ++ rotate_enable = ip->rotate_enable; ++ rotate_angle = ip->rotate_angle; ++ ++ switch(fmt) { ++ case V4L2_PIX_FMT_NV12: ++ src_y_strid = srcw; ++ src_uv_strid = srcw; ++ if ((rotate_angle == 0) || (rotate_angle == 180) || (flip_enable == 1) || (mirr_enable == 1)) { ++ dst_y_strid = srcw; ++ dst_uv_strid = srcw; ++ } else if ((rotate_angle == 90) || (rotate_angle == 270)) { ++ dst_y_strid = srch; ++ dst_uv_strid = srch; ++ } ++ reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_NV12); ++ break; ++ case V4L2_PIX_FMT_SBGGR8: ++ src_y_strid = srcw; ++ src_uv_strid = srcw; ++ if ((rotate_angle == 0) || (rotate_angle == 180) || (flip_enable == 1) || (mirr_enable == 1)) { ++ dst_y_strid = srcw; ++ dst_uv_strid = srcw; ++ } else if ((rotate_angle == 90) || (rotate_angle == 270)) { ++ dst_y_strid = srch; ++ dst_uv_strid = srch; ++ } ++ reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_RAW8); ++ break; ++ case V4L2_PIX_FMT_RGB565: ++ src_y_strid = srcw << 1; ++ src_uv_strid = srcw; ++ if ((rotate_angle == 0) || (rotate_angle == 180) || (flip_enable == 1) || (mirr_enable == 1)) { ++ dst_y_strid = srcw << 1; ++ dst_uv_strid = srcw; ++ } else if ((rotate_angle == 90) || (rotate_angle == 270)) { ++ dst_y_strid = srch << 1; ++ dst_uv_strid = srch; ++ } ++ reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_RGB565); ++ break; ++ case V4L2_PIX_FMT_ARGB32: ++ src_y_strid = srcw << 2; ++ src_uv_strid = srcw; ++ if ((rotate_angle == 0) || (rotate_angle == 180) || (flip_enable == 1) || (mirr_enable == 1)) { ++ dst_y_strid = srcw << 2; ++ dst_uv_strid = srcw; ++ } else if ((rotate_angle == 90) || (rotate_angle == 270)) { ++ dst_y_strid = srch << 2; ++ dst_uv_strid = srch; ++ } ++ reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_ARGB8888); ++ break; ++ default: ++ src_y_strid = srcw; ++ src_uv_strid = srcw; ++ if ((rotate_angle == 0) || (rotate_angle == 180) || (flip_enable == 1) || (mirr_enable == 1)) { ++ dst_y_strid = srcw; ++ dst_uv_strid = srcw; ++ } else if ((rotate_angle == 90) || (rotate_angle == 270)) { ++ dst_y_strid = srch; ++ dst_uv_strid = srch; ++ } ++ printk("not support fmt ,set default nv12"); ++ reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_NV12); ++ break; ++ } ++ ++ ++#ifdef TIMEOUT_TEST ++ reg_write(i2d, I2D_TIMEOUT_MODE, (0 << 0)); //timeout mode 0:not restart 1:auto restart ++ reg_write(i2d, I2D_TIMEOUT_VALUE, (0x64 << 0)); //timeout value ++#endif ++ reg_write(i2d, I2D_IMG_SIZE, (srcw << I2D_WIDTH | srch << I2D_HEIGHT)); ++ // reg_write(i2d, I2D_IMG_MODE, I2D_DATA_TYPE_NV12); ++ reg_write(i2d, I2D_IMG_SIZE, (srcw << I2D_WIDTH | srch << I2D_HEIGHT)); ++ //reg_write(i2d, I2D_IMG_MODE, I2D_FLIP_MODE_90); ++ ++ if(rotate_enable == 1) { ++ unsigned int value = 0, tmp1 = 0; ++ if(rotate_angle == 0){ ++ tmp1 = 0; ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*srch; ++ } else if(rotate_angle == 90){ ++ tmp1 = 1; ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*srcw; ++ } else if(rotate_angle == 180){ ++ tmp1 = 2; ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*srch; ++ } else if(rotate_angle == 270){ ++ tmp1 = 3; ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*srcw; ++ } else { ++ tmp1 = 0; ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*srch; ++ } ++ /* set rotate angle */ ++ value = reg_read(i2d,I2D_IMG_MODE); ++ value &= ~(3 << 2); ++ value |= (tmp1 << 2); ++ reg_write(i2d,I2D_IMG_MODE,value); ++ } ++ ++ if(mirr_enable == 1) { ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*srch; ++ value = reg_read(i2d, I2D_IMG_MODE); ++ reg_write(i2d, I2D_IMG_MODE, (value | I2D_MIRR)); ++ } ++ ++ if(flip_enable == 1) { ++ dst_uv_pbuf = ip->dst_addr_y + dst_y_strid*srch; ++ value = reg_read(i2d, I2D_IMG_MODE); ++ reg_write(i2d, I2D_IMG_MODE, (value | I2D_FLIP)); ++ } ++ ++ ++ ++ src_y_pbuf = ip->src_addr_y; ++ src_uv_pbuf = ip->src_addr_y + src_y_strid*srch; ++ dst_y_pbuf = ip->dst_addr_y; ++ ++ reg_write(i2d, I2D_SRC_ADDR_Y, src_y_pbuf); ++ reg_write(i2d, I2D_SRC_ADDR_UV, src_uv_pbuf); ++ reg_write(i2d, I2D_DST_ADDR_Y, dst_y_pbuf); ++ reg_write(i2d, I2D_DST_ADDR_UV, dst_uv_pbuf); ++ ++ ++ reg_write(i2d, I2D_SRC_Y_STRID, src_y_strid); ++ reg_write(i2d, I2D_SRC_UV_STRID, src_uv_strid); ++ reg_write(i2d, I2D_DST_Y_STRID, dst_y_strid); ++ reg_write(i2d, I2D_DST_UV_STRID, dst_uv_strid); ++ ++ ++ return 0; ++} ++ ++int i2d_set_init_info(struct ingenic_i2d_dev *dev,struct i2d_frame_info *info,dma_addr_t src_addr,dma_addr_t dst_addr) ++{ ++ struct ingenic_i2d_ctx *ctx; ++ struct i2d_param param; ++ ctx = dev->cur_ctx; ++ param.src_w = info->width; ++ param.src_h = info->height; ++ param.data_type = info->fmt->fourcc; ++ param.rotate_enable = 1; ++ param.rotate_angle = ctx->angle; ++ param.flip_enable = ctx->vflip; ++ param.mirr_enable = ctx->hflip; ++ param.src_addr_y = src_addr; ++ param.dst_addr_y = dst_addr; ++ return i2d_reg_set(dev,¶m); ++} ++ ++#if 0 ++int i2d_set_angle(ingenic_i2d_dev* dev, uint32_t angle) ++{ ++ ++} ++ ++int i2d_set_vflip(ingenic_i2d_dev* dev, uint32_t vflip) ++{ ++ ++} ++ ++int i2d_set_hflip(ingenic_i2d_dev* dev, uint32_t hflip) ++{ ++ ++} ++#endif ++ ++int i2d_start(struct ingenic_i2d_dev *dev) ++{ ++ reg_bit_set(dev, I2D_IRQ_MASK, (I2D_IRQ_TIMEOUT_MASK | I2D_IRQ_FRAME_DONE_MASK)); // mask 0 ++ reg_write(dev,I2D_SHD_CTRL,0xffffffff); ++ reg_bit_set(dev, I2D_CTRL, I2D_START); ++ return 0; ++} ++ ++ ++int i2d_irq_clear(struct ingenic_i2d_dev *dev) ++{ ++ unsigned int status; ++ status = reg_read(dev,I2D_IRQ_STATE); ++ reg_bit_set(dev,I2D_IRQ_CLEAR,status); ++ /* if (status & 0x1){ */ ++ /* complete(&dev->done_i2d); */ ++ /* } */ ++ return status; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-i2d/ingenic_i2d.h b/module_drivers/drivers/media/platform/ingenic-i2d/ingenic_i2d.h +new file mode 100644 +index 000000000..3dad61722 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-i2d/ingenic_i2d.h +@@ -0,0 +1,157 @@ ++#ifndef __I2D_H__ ++#define __I2D_H__ ++ ++#define I2D_BASE 0xB30B0000 ++ ++#define I2D_RTL_VERSION 0x00 ++#define I2D_SHD_CTRL 0x08 ++#define I2D_CTRL 0x10 ++#define I2D_IMG_SIZE 0x14 ++#define I2D_IMG_MODE 0x18 ++#define I2D_SRC_ADDR_Y 0x20 ++#define I2D_SRC_ADDR_UV 0x24 ++#define I2D_SRC_Y_STRID 0x28 ++#define I2D_SRC_UV_STRID 0x2C ++#define I2D_DST_ADDR_Y 0x30 ++#define I2D_DST_ADDR_UV 0x34 ++#define I2D_DST_Y_STRID 0x38 ++#define I2D_DST_UV_STRID 0x3C ++#define I2D_IRQ_STATE 0x80 ++#define I2D_IRQ_CLEAR 0x84 ++#define I2D_IRQ_MASK 0x88 ++#define I2D_TIMEOUT_VALUE 0x90 ++#define I2D_TIMEOUT_MODE 0x94 ++#define I2D_CLK_GATE 0x98 ++#define I2D_DBG_0 0xA0 ++ ++#define u32 unsigned int ++ ++/* VERSION*/ ++#define I2D_VERSION (1 << 0) ++ ++/* SHD_CTRL */ ++#define I2D_MODE_SHADOW (1 << 1) ++ ++/* SHD_CTRL */ ++#define I2D_MODE_SHADOW (1 << 1) ++#define I2D_ADDR_SHADOW (1 << 0) ++ ++/* CTRL */ ++#define I2D_RESET (1 << 16) ++#define I2D_SAFE_RESET (1 << 4) ++#define I2D_START (1 << 0) ++ ++/* IMG_SIZE */ ++#define I2D_WIDTH (16) ++#define I2D_HEIGHT (0) ++ ++/* I2D_MODE */ ++#define I2D_DATA_TYPE (4) ++#define I2D_DATA_TYPE_NV12 (0 << I2D_DATA_TYPE) ++#define I2D_DATA_TYPE_RAW8 (1 << I2D_DATA_TYPE) ++#define I2D_DATA_TYPE_RGB565 (2 << I2D_DATA_TYPE) ++#define I2D_DATA_TYPE_ARGB8888 (3 << I2D_DATA_TYPE) ++ ++#define I2D_FLIP_MODE (2) ++#define I2D_FLIP_MODE_0 (0 << I2D_FLIP_MODE) ++#define I2D_FLIP_MODE_90 (1 << I2D_FLIP_MODE) ++#define I2D_FLIP_MODE_180 (2 << I2D_FLIP_MODE) ++#define I2D_FLIP_MODE_270 (3 << I2D_FLIP_MODE) ++ ++#define I2D_MIRR (1 << 1) ++#define I2D_FLIP (1 << 0) ++ ++/* SRC_ADDR_Y */ ++#define I2D_SRC_Y (0) ++ ++/* SRC_ADDR_UV */ ++#define I2D_SRC_UV (0) ++ ++/* SRC_Y_STRID */ ++#define I2D_SRC_STRID_Y (0) ++ ++/* SRC_UV_STRID */ ++#define I2D_SRC_STRID_UV (0) ++ ++/* DST_ADDR_Y */ ++#define I2D_DST_Y (0) ++ ++/* DST_ADDR_UV */ ++#define I2D_DST_UV (0) ++ ++/* DST_Y_STRID */ ++#define I2D_DST_STRID_Y (0) ++ ++/* DST_UV_STRID */ ++#define I2D_DST_STRID_UV (0) ++ ++/* IRQ_STATE */ ++#define I2D_IRQ_TIMEOUT (1) ++#define I2D_IRQ_FRAME_DONE (0) ++ ++/* IRQ_CLEAR */ ++#define I2D_IRQ_TIMEOUT_CLR (1 << 1) ++#define I2D_IRQ_FRAME_DONE_CLR (1 << 0) ++ ++/* IRQ_MASK */ ++#define I2D_IRQ_TIMEOUT_MASK (0 << 1) ++#define I2D_IRQ_FRAME_DONE_MASK (0 << 0) ++ ++/* TIMEOUT_MODE */ ++#define I2D_TIMEOUT_RST (0) ++ ++enum ++{ ++ FLIP_MODE_0_DEGREE = 1, ++ FLIP_MODE_90_DEGREE = 2, ++ FLIP_MODE_180_DEGREE = 3, ++ FLIP_MODE_270_DEGREE = 4, ++ FLIP_MODE_MIRR = 5, ++ FLIP_MODE_FLIP = 6, ++}; ++ ++ ++struct i2d_param ++{ ++ unsigned int src_w; ++ unsigned int src_h; ++ unsigned int data_type; ++ unsigned int rotate_enable; ++ unsigned int rotate_angle; ++ unsigned int flip_enable; ++ unsigned int mirr_enable; ++ ++ unsigned int src_addr_y; ++ unsigned int src_addr_uv; ++ unsigned int dst_addr_y; ++ unsigned int dst_addr_uv; ++ ++ unsigned int src_y_strid; ++ unsigned int src_uv_strid; ++ unsigned int dst_y_strid; ++ unsigned int dst_uv_strid; ++}; ++ ++static inline unsigned int reg_read(struct ingenic_i2d_dev *dev,int offset) ++{ ++ return readl(dev->base + offset); ++} ++ ++static inline void reg_write(struct ingenic_i2d_dev *dev,int offset, unsigned int val) ++{ ++ writel(val, dev->base + offset); ++} ++ ++void i2d_safe_reset(struct ingenic_i2d_dev *dev); ++ ++void i2d_reset(struct ingenic_i2d_dev *dev); ++ ++int i2d_set_init_info(struct ingenic_i2d_dev *dev,struct i2d_frame_info *info,dma_addr_t src_addr,dma_addr_t dst_addr); ++ ++int i2d_start(struct ingenic_i2d_dev *dev); ++ ++int i2d_irq_clear(struct ingenic_i2d_dev *dev); ++#endif // __I2D_H__ ++ ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/Kconfig b/module_drivers/drivers/media/platform/ingenic-isp-v2/Kconfig +new file mode 100644 +index 000000000..bc235d500 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/Kconfig +@@ -0,0 +1,56 @@ ++choice ++ prompt "isp total sensor num select" ++ depends on VIDEO_INGENIC_ISP_V2 ++ default INGENIC_ISP_V2_SENSOR_NUM_TWO ++ help ++ Select isp total sensor number. ++config INGENIC_ISP_V2_SENSOR_NUM_ONE ++ bool "isp total sensor num one" ++config INGENIC_ISP_V2_SENSOR_NUM_TWO ++ bool "isp total sensor num two" ++config INGENIC_ISP_V2_SENSOR_NUM_THREE ++ bool "isp total sensor num three" ++endchoice ++ ++ ++menuconfig HIPPO_CAMERA_BOARD ++ bool "hippo_camera_board" ++ depends on VIDEO_INGENIC_ISP_V2 ++ default n ++ help ++ Say Y here to enable support for hippo_camera_boards. ++ ++ ++config RD_X2500_HIPPO_CAMERA_1V0 ++ bool "X2500 isp camera driver for RD_X2500_HIPPO_CAMERA_1V0" ++ depends on HIPPO_CAMERA_BOARD ++ select INGENIC_ISP_V2_CAMERA_SC230AI ++ select INGENIC_ISP_V2_CAMERA_GC2155 ++ ++config RD_X2500_HIPPO_CAMERA_1V1 ++ bool "X2500 isp camera driver for RD_X2500_HIPPO_CAMERA_1V1" ++ depends on HIPPO_CAMERA_BOARD ++ select INGENIC_ISP_V2_CAMERA_SC230AI ++ ++config RD_X2000_HALLEY5_CAMERA_3V2 ++ bool "X2500 isp camera driver for RD_X2000_HALLEY5_CAMERA_3V2" ++ depends on HIPPO_CAMERA_BOARD ++ select INGENIC_ISP_V2_CAMERA_OV4689 ++ ++config RD_X2000_HALLEY5_CAMERA_4V3 ++ bool "X2500 isp camera driver for RD_X2000_HALLEY5_CAMERA_4V3" ++ depends on HIPPO_CAMERA_BOARD ++ select INGENIC_ISP_V2_CAMERA_OV2735A ++ ++ ++config VIC_DMA_ROUTE ++ bool "vic dma out route enable" ++ default n ++ depends on VIDEO_INGENIC_ISP_V2 ++ ++config MSCA_BDEV ++ bool "mscaler bdev support" ++ default n ++ depends on VIDEO_INGENIC_ISP_V2 ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/Makefile b/module_drivers/drivers/media/platform/ingenic-isp-v2/Makefile +new file mode 100644 +index 000000000..0f8f900b4 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/Makefile +@@ -0,0 +1,20 @@ ++obj-y += isp-drv.o ++obj-y += csi.o ++obj-y += mscaler.o ++obj-y += vic.o ++obj-y += isp.o ++obj-y += sensor.o ++obj-y += isp-video.o ++obj-y += isp-core-tuning.o ++obj-$(CONFIG_MSCA_BDEV) += mscaler-bdev.o ++ ++ccflags-y += -I$(srctree)/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc ++ccflags-$(CONFIG_MSCA_BDEV) += -I$(srctree)/module_drivers/drivers/media/platform/ingenic-vcodec/helix ++obj-y += isp-core/ ++ ++FILE=$(srctree)/module_drivers/drivers/media/platform/ingenic-isp/isp-core/isp-core.a_shipped ++ifeq ($(FILE), $(wildcard $(FILE))) ++$(error "please remove overlay isp-core.a_shipped") ++endif ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/csi-regs.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/csi-regs.h +new file mode 100644 +index 000000000..c0348374c +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/csi-regs.h +@@ -0,0 +1,69 @@ ++#ifndef __INGENIC_ISP_CSI_H__ ++#define __INGENIC_ISP_CSI_H__ ++ ++#define VERSION 0x00 ++#define N_LANES 0x04 ++#define PHY_SHUTDOWNZ 0x08 ++#define DPHY_RSTZ 0x0C ++#define CSI2_RESETN 0x10 ++#define PHY_STATE 0x14 ++#define DATA_IDS_1 0x18 ++#define DATA_IDS_2 0x1C ++#define ERR1 0x20 ++#define ERR2 0x24 ++#define MASK1 0x28 ++#define MASK2 0x2C ++#define PHY_TST_CTRL0 0x30 ++#define PHY_TST_CTRL1 0x34 ++#define CTRL_DUAL_ENABLE 0x080 ++#define RXVALID_MASK 0x100 ++ ++ ++#define VC0_FRAME_NUM 0x40 /*[31:16] FS End, [15:0] FS Start*/ ++#define VC1_FRAME_NUM 0x44 ++#define VC2_FRAME_NUM 0x48 ++#define VC3_FRAME_NUM 0x4c ++#define VC0_LINE_NUM 0x50 /*[31:16] Line End, [15:0] Line Start*/ ++#define VC1_LINE_NUM 0x54 ++#define VC2_LINE_NUM 0x58 ++#define VC3_LINE_NUM 0x60 ++ ++ ++ ++#define csi_readl(port, reg) \ ++ __raw_readl((unsigned int *)((port)->base + reg)) ++#define csi_writel(port, reg, value) \ ++ __raw_writel((value), (unsigned int *)((port)->base + reg)) ++ ++#define csi_core_writel(csi, addr, value) \ ++ writel(value, (unsigned int *)((csi)->iobase + addr)) ++#define csi_core_readl(csi, addr) \ ++ readl((unsigned int *)((csi)->iobase + addr)) ++ ++ ++#define CSI_PHY_IOBASE 0x10022000 ++ ++#define PHY_ENB 0x000 ++#define PHY_DUAL_CLK_ENB 0x080 ++#define PHY_CK0_CONTI 0x128 ++#define PHY_CK0_SETTLE 0x160 ++#define PHY_DATA0_CONTI 0x1A8 ++#define PHY_DATA0_SETTLE 0x1E0 ++#define PHY_DATA1_CONTI 0x228 ++#define PHY_DATA1_SETTLE 0x260 ++#define PHY_DATA2_CONTI 0x2A8 ++#define PHY_DATA2_SETTLE 0x2E0 ++#define PHY_DATA3_CONTI 0x328 ++#define PHY_DATA3_SETTLE 0x360 ++#define PHY_CK1_CONTI 0x3A8 ++#define PHY_CK1_SETTLE 0x3E0 ++ ++ ++#define csi_phy_writel(csi, addr, value) \ ++ writel(value, (unsigned int *)((csi)->phy_base + addr)) ++ ++#define csi_phy_readl(csi, addr) \ ++ readl((unsigned int *)((csi)->phy_base + addr)) ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/csi.c b/module_drivers/drivers/media/platform/ingenic-isp-v2/csi.c +new file mode 100644 +index 000000000..b11ec63bd +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/csi.c +@@ -0,0 +1,554 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "isp-drv.h" ++#include "csi-regs.h" ++ ++static const struct v4l2_subdev_core_ops csi_subdev_core_ops = { ++ .log_status = v4l2_ctrl_subdev_log_status, ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++int rx_settle_time = 0; ++module_param(rx_settle_time, int, 0664); ++MODULE_PARM_DESC(rx_settle_time, "csi rx-settle counter"); ++ ++static int csi_subdev_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct csi_device *csi = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ int ret = 0; ++ ++ remote = media_entity_remote_pad(&csi->pads[CSI_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ ret = v4l2_subdev_call(remote_sd, pad, set_fmt, NULL, format); ++ if(ret < 0) { ++ dev_dbg(csi->dev, "Failed to set_fmt from remote pad\n"); ++ } ++ ++ return 0; ++} ++static int csi_subdev_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct csi_device *csi = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ struct v4l2_subdev_format remote_subdev_fmt; ++ int ret = 0; ++ ++ remote = media_entity_remote_pad(&csi->pads[CSI_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ /*èŽ·å–æºå½“剿 ¼å¼ï¼Œå¤åˆ¶åˆ°è¾“出格å¼.*/ ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_err(csi->dev, "Failed to get_fmt from remote pad\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(&format->format, &remote_subdev_fmt.format, sizeof(format->format)); ++ ++ csi->formats[CSI_PAD_SINK] = csi->formats[CSI_PAD_SOURCE] = *format; ++ csi->sensor_info = (struct sensor_info *)*(unsigned int *)format->format.reserved; ++ //printk("----%s, %d, format->pad: %d\n", __func__, __LINE__, format->pad); ++ return 0; ++} ++ ++ ++static const struct v4l2_subdev_pad_ops csi_subdev_pad_ops = { ++ .set_fmt = csi_subdev_set_fmt, ++ .get_fmt = csi_subdev_get_fmt, ++ /* ++ .init_cfg = csi_subdev_init_cfg, ++ .enum_mbus_code = csi_subdev_enum_mbus_code, ++ .enum_frame_size = csi_subdev_enum_frame_size, ++ .get_fmt = csi_subdev_get_fmt, ++ */ ++}; ++ ++struct phy_reseter { ++ struct csi_device *csi[2]; ++ unsigned int phy_started[2]; ++}; ++ ++struct phy_reseter global_phy_reseter = { ++ .csi = {NULL, NULL}, ++ .phy_started = {0, 0} ++}; ++ ++DEFINE_SPINLOCK(reset_lock); ++ ++static unsigned char csi_core_write_part(struct csi_device *csi,unsigned int address, ++ unsigned int data, unsigned char shift, unsigned char width) ++{ ++ unsigned int mask = (1 << width) - 1; ++ unsigned int temp = csi_core_readl(csi, address); ++ ++ temp &= ~(mask << shift); ++ temp |= (data & mask) << shift; ++ csi_core_writel(csi, address, temp); ++ ++ return 0; ++} ++ ++static inline int csi_core_write_io(unsigned int iobase, unsigned int address, unsigned int data, unsigned char shift, unsigned char width) ++{ ++ unsigned int mask = (1 << width) - 1; ++ unsigned int temp = readl((unsigned int *)(iobase + address)); ++ ++ temp &= ~(mask << shift); ++ temp |= (data & mask) << shift; ++ writel(temp, (unsigned int *)(iobase + address)); ++ return 0; ++} ++ ++ ++#define CSI0_IOBASE 0xb0054000 ++#define CSI1_IOBASE 0xb0023000 ++static int csi_phy_start(struct csi_device *csi, struct phy_reseter *reseter) ++{ ++ unsigned long flags; ++ /*already reseted.*/ ++ spin_lock_irqsave(&reset_lock, flags); ++ if(reseter->phy_started[0] || reseter->phy_started[1]) { ++ reseter->phy_started[csi->reset_index] = 1; ++ spin_unlock_irqrestore(&reset_lock, flags); ++ return 0; ++ } ++ ++ /* CSI0 and CSI1 reset both at CSI0. */ ++ csi_core_write_io(CSI0_IOBASE, DPHY_RSTZ, 0, 0, 1); ++ csi_core_write_io(CSI0_IOBASE, DPHY_RSTZ, 1, 0, 1); ++ ++ reseter->phy_started[csi->reset_index] = 1; ++ spin_unlock_irqrestore(&reset_lock, flags); ++ ++ ++ return 0; ++} ++ ++static void csi_phy_stop(struct csi_device *csi, struct phy_reseter *reseter) ++{ ++ ++ unsigned long flags; ++ ++ /* CSI2_RESET */ ++ spin_lock_irqsave(&reset_lock, flags); ++ csi_core_write_part(csi, CSI2_RESETN, 0, 0, 1); ++ ++ reseter->phy_started[csi->reset_index] = 0; ++ ++ if((reseter->phy_started[0] == 0) && (reseter->phy_started[1] == 0)) { ++ /* shutdown phy. */ ++ csi_core_write_io(CSI0_IOBASE, DPHY_RSTZ, 0, 0, 1); ++ } ++ ++ spin_unlock_irqrestore(&reset_lock, flags); ++} ++ ++ ++static unsigned int settle_time_cal(unsigned int clk) ++{ ++ unsigned int settle_time = 0; ++ ++ if(clk >= 80 && clk < 110) ++ settle_time = 0x2; ++ else if(clk >= 110 && clk < 150) ++ settle_time = 0x3; ++ else if(clk >= 150 && clk < 300) ++ settle_time = 0x6; ++ else if(clk >= 300 && clk < 400) ++ settle_time = 0x8; ++ else if(clk >= 400 && clk < 500) ++ settle_time = 0xb; ++ else if(clk >= 500 && clk < 600) ++ settle_time = 0xe; ++ else if(clk >= 600 && clk < 700) ++ settle_time = 0x10; ++ else if(clk >= 700 && clk < 800) ++ settle_time = 0x12; ++ else if(clk >= 800 && clk < 1000) ++ settle_time = 0x16; ++ else if(clk >= 1000 && clk < 1200) ++ settle_time = 0x1e; ++ else if(clk >= 1200 && clk < 1400) ++ settle_time = 0x23; ++ else if(clk >= 1400 && clk < 1600) ++ settle_time = 0x2d; ++ else if(clk >= 1600 && clk < 1800) ++ settle_time = 0x32; ++ else if(clk >= 1800 && clk < 2000) ++ settle_time = 0x37; ++ else if(clk >= 2000 && clk < 2400) ++ settle_time = 0x3c; ++ else ++ settle_time = 0x3c; ++ ++ return settle_time; ++} ++ ++ ++static int csi_subdev_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct csi_device *csi = v4l2_get_subdevdata(sd); ++ struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = ispcam_get_bus_mipi_csi2(csi->ispcam); ++ struct mipi_cfg *mipi_cfg = &csi->sensor_info->mipi_cfg; ++ unsigned short nlanes = mipi_csi2->num_data_lanes; ++ int conti = 0; ++ ++ if(enable) { ++ if(csi->enabled++ > 0) { ++ return 0; ++ } ++ ++ csi_phy_start(csi, &global_phy_reseter); ++ ++ if(nlanes > 2){ ++ csi_core_writel(csi,CTRL_DUAL_ENABLE, 0x0); /*1c mode*/ ++ csi_phy_writel(csi, PHY_DUAL_CLK_ENB, 0x1f); ++ } else { ++ csi_core_writel(csi,CTRL_DUAL_ENABLE, 0x1); /*2c mode*/ ++ csi_phy_writel(csi, PHY_DUAL_CLK_ENB, 0x5f); ++ } ++ csi_core_writel(csi, N_LANES, nlanes - 1); ++ ++ if(csi->iobase == (unsigned int *)0xb0054000) ++ conti = 0x3f; ++ else ++ conti = 0x0f; ++ csi_phy_writel(csi, PHY_CK0_CONTI, conti); ++ csi_phy_writel(csi, PHY_DATA0_CONTI, conti); ++ csi_phy_writel(csi, PHY_DATA1_CONTI, conti); ++ csi_phy_writel(csi, PHY_DATA2_CONTI, conti); ++ csi_phy_writel(csi, PHY_DATA3_CONTI, conti); ++ csi_phy_writel(csi, PHY_CK1_CONTI, conti); ++ ++ csi->settle_time = settle_time_cal(mipi_cfg->clk); ++ ++ if(rx_settle_time) { ++ printk("debug rx_settle_time: %d\n", rx_settle_time); ++ csi->settle_time = rx_settle_time; ++ } ++ ++ if((!csi->settle_time) && (!mipi_cfg->clk)) { ++ printk("[Error], mipi_cfg->clk is invalid, using incorrect mipi rx_settle_time, **** check ****\n"); ++ } ++ ++ csi_phy_writel(csi, PHY_CK0_SETTLE, csi->settle_time); ++ csi_phy_writel(csi, PHY_DATA0_SETTLE, csi->settle_time); ++ csi_phy_writel(csi, PHY_DATA1_SETTLE, csi->settle_time); ++ csi_phy_writel(csi, PHY_DATA2_SETTLE, csi->settle_time); ++ csi_phy_writel(csi, PHY_DATA3_SETTLE, csi->settle_time); ++ csi_phy_writel(csi, PHY_CK1_SETTLE, csi->settle_time); ++ /* CSI2_RESET */ ++ csi_core_writel(csi, CSI2_RESETN, 0x0); ++ csi_core_writel(csi, CSI2_RESETN, 0x1); ++ ++ if(nlanes > 2){ ++ csi_core_writel(csi, RXVALID_MASK, 0xf); ++ } else { ++ csi_core_writel(csi, RXVALID_MASK, 0x3); ++ } ++ ++ csi_core_writel(csi, PHY_SHUTDOWNZ, 0x0); ++ csi_core_writel(csi, MASK1, 0xffffffff); ++ csi_core_writel(csi, MASK2, 0xffffffff); ++ csi_phy_writel(csi, PHY_ENB, 0x7d); ++ } else { ++ ++ if(--csi->enabled > 0) { ++ return 0; ++ } ++ csi_phy_stop(csi, &global_phy_reseter); ++ } ++ ++ return 0; ++} ++ ++ ++static const struct v4l2_subdev_video_ops csi_subdev_video_ops = { ++ .s_stream = csi_subdev_s_stream, ++}; ++ ++ ++static const struct v4l2_subdev_ops csi_subdev_ops = { ++ .core = &csi_subdev_core_ops, ++ .pad = &csi_subdev_pad_ops, ++ .video = &csi_subdev_video_ops, ++}; ++ ++static ssize_t ++dump_csi(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct csi_device *csi = dev_get_drvdata(dev); ++ char *p = buf; ++ ++ p += sprintf(p, "VERSION :0x%08x\n", csi_core_readl(csi, VERSION)); ++ p += sprintf(p, "N_LANES :0x%08x\n", csi_core_readl(csi, N_LANES)); ++ p += sprintf(p, "PHY_SHUTDOWNZ :0x%08x\n", csi_core_readl(csi, PHY_SHUTDOWNZ)); ++ p += sprintf(p, "DPHY_RSTZ :0x%08x\n", csi_core_readl(csi, DPHY_RSTZ)); ++ p += sprintf(p, "CSI2_RESETN :0x%08x\n", csi_core_readl(csi, CSI2_RESETN)); ++ p += sprintf(p, "PHY_STATE :0x%08x\n", csi_core_readl(csi, PHY_STATE)); ++ p += sprintf(p, "DATA_IDS_1 :0x%08x\n", csi_core_readl(csi, DATA_IDS_1)); ++ p += sprintf(p, "DATA_IDS_2 :0x%08x\n", csi_core_readl(csi, DATA_IDS_2)); ++ p += sprintf(p, "ERR1 :0x%08x\n", csi_core_readl(csi, ERR1)); ++ p += sprintf(p, "ERR2 :0x%08x\n", csi_core_readl(csi, ERR2)); ++ p += sprintf(p, "MASK1 :0x%08x\n", csi_core_readl(csi, MASK1)); ++ p += sprintf(p, "MASK2 :0x%08x\n", csi_core_readl(csi, MASK2)); ++ p += sprintf(p, "PHY_TST_CTRL0 :0x%08x\n", csi_core_readl(csi, PHY_TST_CTRL0)); ++ p += sprintf(p, "PHY_TST_CTRL1 :0x%08x\n", csi_core_readl(csi, PHY_TST_CTRL1)); ++ p += sprintf(p, "VC0_FRAME_NUM :0x%08x\n", csi_core_readl(csi, VC0_FRAME_NUM)); ++ p += sprintf(p, "VC1_FRAME_NUM :0x%08x\n", csi_core_readl(csi, VC1_FRAME_NUM)); ++ p += sprintf(p, "VC2_FRAME_NUM :0x%08x\n", csi_core_readl(csi, VC2_FRAME_NUM)); ++ p += sprintf(p, "VC3_FRAME_NUM :0x%08x\n", csi_core_readl(csi, VC3_FRAME_NUM)); ++ p += sprintf(p, "VC0_LINE_NUM :0x%08x\n", csi_core_readl(csi, VC0_LINE_NUM)); ++ p += sprintf(p, "VC1_LINE_NUM :0x%08x\n", csi_core_readl(csi, VC1_LINE_NUM)); ++ p += sprintf(p, "VC2_LINE_NUM :0x%08x\n", csi_core_readl(csi, VC2_LINE_NUM)); ++ p += sprintf(p, "VC3_LINE_NUM :0x%08x\n", csi_core_readl(csi, VC3_LINE_NUM)); ++ ++ return p - buf; ++} ++ ++ ++static DEVICE_ATTR(dump_csi, S_IRUGO|S_IWUSR, dump_csi, NULL); ++ ++static struct attribute *csi_debug_attrs[] = { ++ &dev_attr_dump_csi.attr, ++ NULL, ++}; ++ ++static struct attribute_group csi_debug_attr_group = { ++ .name = "debug", ++ .attrs = csi_debug_attrs, ++}; ++ ++ ++static int csi_comp_bind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct csi_device *csi = dev_get_drvdata(comp); ++ struct ispcam_device *ispcam = (struct ispcam_device *)master_data; ++ struct v4l2_device *v4l2_dev = &ispcam->v4l2_dev; ++ struct v4l2_subdev *sd = &csi->sd; ++ int ret = 0; ++ ++ //dev_info(comp, "----dev_name(comp): %s----%s, %d \n", dev_name(comp), __func__, __LINE__); ++ ++ /* link subdev to master.*/ ++ csi->ispcam = (void *)ispcam; ++ ispcam->csi = csi; ++ ++ /*1. register supported subdev ctrls.*/ ++ ++ ++ /*2. init v4l2_subdev*/ ++ ++ v4l2_subdev_init(sd, &csi_subdev_ops); ++ ++ sd->owner = THIS_MODULE; ++ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ strscpy(sd->name, dev_name(comp), sizeof(sd->name)); ++ v4l2_set_subdevdata(sd, csi); ++ ++ ++ /* init csi pads. */ ++ csi->pads = kzalloc(sizeof(struct media_pad) * CSI_NUM_PADS, GFP_KERNEL); ++ if(!csi->pads) { ++ ret = -ENOMEM; ++ goto err_alloc_pads; ++ } ++ csi->pads[0].index = CSI_PAD_SINK; ++ csi->pads[0].flags = MEDIA_PAD_FL_SINK; ++ csi->pads[1].index = CSI_PAD_SOURCE; ++ csi->pads[1].flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&sd->entity, CSI_NUM_PADS, csi->pads); ++ ++ /*3. register v4l2_subdev*/ ++ sd->entity.function = MEDIA_ENT_F_IO_V4L; ++ ret = v4l2_device_register_subdev(v4l2_dev, sd); ++ if(ret < 0) { ++ dev_err(comp, "Failed to register v4l2_subdev for csi\n"); ++ goto err_subdev_register; ++ } ++ ++ ++ return 0; ++err_subdev_register: ++err_alloc_pads: ++ return ret; ++} ++ ++ ++static void csi_comp_unbind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct csi_device *csi = dev_get_drvdata(comp); ++ ++ dev_info(comp, "----TODO-implement unbind: %p---%s, %d \n",csi, __func__, __LINE__); ++} ++ ++ ++ ++static const struct component_ops csi_comp_ops = { ++ .bind = csi_comp_bind, ++ .unbind = csi_comp_unbind, ++}; ++ ++ ++static int ingenic_csi_probe(struct platform_device *pdev) ++{ ++ ++ struct csi_device *csi = NULL; ++ struct resource *regs = NULL; ++ ++ int ret = 0; ++ int i = 0; ++ ++ csi = kzalloc(sizeof(struct csi_device), GFP_KERNEL); ++ if(!csi) { ++ pr_err("Failed to alloc csi dev [%s]\n", pdev->name); ++ return -ENOMEM; ++ } ++ ++ csi->dev = &pdev->dev; ++ platform_set_drvdata(pdev, csi); ++ dev_set_drvdata(csi->dev, csi); ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(!regs) { ++ dev_err(&pdev->dev, "No iomem resource!\n"); ++ goto err_get_resource; ++ } ++ ++ csi->iobase = devm_ioremap_resource(&pdev->dev, regs); ++ if(!csi->iobase) { ++ goto err_ioremap; ++ } ++ ++ csi->phy_base = CSI_PHY_IOBASE | 0xa0000000; ++ ++ /*TODO: clk*/ ++ csi->gate_clk = of_clk_get(csi->dev->of_node, 0); ++ if(!csi->gate_clk) { ++ dev_err(csi->dev, "failed to get gate clk\n"); ++ goto err_gate_clk; ++ } ++ clk_prepare_enable(csi->gate_clk); ++ ++ ret = sysfs_create_group(&csi->dev->kobj, &csi_debug_attr_group); ++ if (ret) { ++ dev_err(csi->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_sys_group; ++ } ++ ++ for(i = 0; i < 2; i++) { ++ if(global_phy_reseter.csi[i] == NULL) { ++ global_phy_reseter.csi[i] = csi; ++ csi->reset_index = i; ++ break; ++ } ++ } ++ ++ ret = component_add(csi->dev, &csi_comp_ops); ++ if(ret < 0) { ++ dev_err(csi->dev, "Failed to add component csi!\n"); ++ } ++ ++ return 0; ++err_sys_group: ++err_gate_clk: ++err_ioremap: ++err_get_resource: ++ ++ return ret; ++} ++ ++ ++ ++static int ingenic_csi_remove(struct platform_device *pdev) ++{ ++ struct csi_device *csi = dev_get_drvdata(&pdev->dev); ++ ++ clk_disable_unprepare(csi->gate_clk); ++ return 0; ++} ++ ++ ++ ++static const struct of_device_id ingenic_csi_dt_match[] = { ++ { .compatible = "ingenic,x2500-csi" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_csi_dt_match); ++ ++static int __maybe_unused ingenic_csi_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct csi_device *csi = dev_get_drvdata(&pdev->dev); ++ ++ if(csi->enabled){ ++ dev_err(csi->dev, "faild to suspend, csi is streaming on\n"); ++ return -EBUSY; ++ } ++ ++ clk_disable_unprepare(csi->gate_clk); ++ return 0; ++} ++ ++static int __maybe_unused ingenic_csi_resume(struct platform_device *pdev) ++{ ++ struct csi_device *csi = dev_get_drvdata(&pdev->dev); ++ ++ clk_prepare_enable(csi->gate_clk); ++ return 0; ++} ++ ++ ++static struct platform_driver ingenic_csi_driver = { ++ .probe = ingenic_csi_probe, ++ .remove = ingenic_csi_remove, ++ .suspend = ingenic_csi_suspend, ++ .resume = ingenic_csi_resume, ++ .driver = { ++ .name = "ingenic-csi", ++ .of_match_table = ingenic_csi_dt_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_csi_driver); ++ ++MODULE_ALIAS("platform:ingenic-csi"); ++MODULE_DESCRIPTION("ingenic csi subsystem"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core-tuning.c b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core-tuning.c +new file mode 100644 +index 000000000..954afe3ae +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core-tuning.c +@@ -0,0 +1,704 @@ ++#include ++#include ++#include ++#include ++#include "isp-drv.h" ++ ++static inline int tx_isp_isp_hflip_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int hvflip; ++ int value = control->value; ++ isp->ctrls.hflip = value; ++ ++ hvflip = (isp->ctrls.hflip << 0)|(isp->ctrls.vflip << 1); ++ tisp_hv_flip_enable(isp->sensor_id, hvflip); ++ ++ return 0; ++} ++ ++static inline int tx_isp_isp_hflip_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int ret = 0; ++ control->value = isp->ctrls.hflip; ++ return ret; ++} ++ ++static inline int tx_isp_isp_vflip_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int hvflip; ++ int value = control->value; ++ isp->ctrls.vflip = value; ++ ++ hvflip = (isp->ctrls.hflip << 0)|(isp->ctrls.vflip << 1); ++ tisp_hv_flip_enable(isp->sensor_id, hvflip); ++ ++ return 0; ++} ++ ++static inline int tx_isp_isp_vflip_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int ret = 0; ++ control->value = isp->ctrls.vflip; ++ return ret; ++} ++ ++static inline int tx_isp_isp_sat_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int value = control->value; ++ tisp_set_saturation(isp->sensor_id, value); ++ isp->ctrls.saturation = value; ++ return 0; ++} ++ ++static inline int tx_isp_isp_sat_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ control->value = isp->ctrls.saturation; ++ return 0; ++} ++ ++static inline int tx_isp_isp_bright_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int value = control->value; ++ tisp_set_brightness(isp->sensor_id, value); ++ isp->ctrls.brightness = value; ++ ++ return 0; ++} ++ ++static inline int tx_isp_isp_bright_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ control->value = isp->ctrls.brightness; ++ ++ return 0; ++} ++ ++static inline int tx_isp_isp_contrast_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int value = control->value; ++ tisp_set_contrast(isp->sensor_id, value); ++ isp->ctrls.contrast = value; ++ ++ return 0; ++} ++ ++static inline int tx_isp_isp_contrast_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ control->value = isp->ctrls.contrast; ++ ++ return 0; ++} ++ ++static inline int tx_isp_isp_sharp_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int value = control->value; ++ tisp_set_sharpness(isp->sensor_id, value); ++ isp->ctrls.sharpness = value; ++ ++ return 0; ++} ++ ++static inline int tx_isp_isp_sharp_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ control->value = isp->ctrls.sharpness; ++ ++ return 0; ++} ++ ++ ++extern int tisp_ae_main_manual_set(tisp_ae_ctrls_t ae_manual); ++extern int tisp_ae_main_manual_get(tisp_ae_ctrls_t *ae_manual); ++extern int tisp_ae_sec_manual_set(tisp_ae_ctrls_t ae_manual); ++extern int tisp_ae_sec_manual_get(tisp_ae_ctrls_t *ae_manual); ++ ++static int ispcore_exp_auto_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_ae_ctrls_t ae_manual; ++ int ret = 0; ++ /* ++ * control->value. ++ * 0: 自动æ›å…‰. ++ * 1: 手动æ›å…‰. ++ * 2. 快门优先. ++ * 3. 光圈优先. ++ * */ ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_get(&ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_get(&ae_manual); ++ else ++ ret = -EINVAL; ++ if(ret) ++ return ret; ++ ++ if(control->value == V4L2_EXPOSURE_AUTO) { ++ ae_manual.tisp_ae_it_manual = 0; ++ } else if(control->value == V4L2_EXPOSURE_MANUAL) { ++ ae_manual.tisp_ae_it_manual = 1; ++ } ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_set(ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_set(ae_manual); ++ else ++ ret = -EINVAL; ++ ++ return ret; ++} ++ ++/* 获å–当剿›å…‰æ–¹å¼.*/ ++static int ispcore_exp_auto_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_ae_ctrls_t ae_manual; ++ int ret = 0; ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_get(&ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_get(&ae_manual); ++ else ++ ret = -EINVAL; ++ ++ control->value = ae_manual.tisp_ae_it_manual == 0 ? V4L2_EXPOSURE_AUTO : V4L2_EXPOSURE_MANUAL; ++ ++ return ret; ++} ++ ++/* 设置æ›å…‰ç­‰çº§. eg: [-4, 4] ++ * ++ * 相对æ›å…‰æ—¶é—´. 从 [-4, 4] -> [inte_min, inte_max] ++ * */ ++static int ispcore_exp_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ return 0; ++} ++ ++static int ispcore_exp_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ return 0; ++} ++ ++/* 设置æ›å…‰æ—¶é—´. */ ++static int ispcore_exp_abs_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_ae_ctrls_t ae_manual; ++ int ret = 0; ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_get(&ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_get(&ae_manual); ++ else ++ ret = -EINVAL; ++ if(ret) ++ return ret; ++ ++ if(ae_manual.tisp_ae_it_manual) { ++ ae_manual.tisp_ae_sensor_integration_time = control->value; ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_set(ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_set(ae_manual); ++ else ++ ret = -EINVAL; ++ } else { ++ dev_warn(isp->dev, "set exp_abs while in exposure [auto] mode.\n"); ++ } ++ ++ return ret; ++ ++} ++ ++static int ispcore_exp_abs_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_ae_ctrls_t ae_manual; ++ int ret = 0; ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_get(&ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_get(&ae_manual); ++ else ++ ret = -EINVAL; ++ ++ control->value = ae_manual.tisp_ae_sensor_integration_time; ++ ++ return ret; ++} ++ ++/*è®¾ç½®è‡ªåŠ¨å¢žç›ŠæŽ§åˆ¶æ–¹å¼ ++ * 0: 自动增益控制 ++ * 1: 手动增益控制. ++ * */ ++static inline int ispcore_auto_gain_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_ae_ctrls_t ae_manual; ++ int ret = 0; ++ ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_get(&ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_get(&ae_manual); ++ else ++ ret = -EINVAL; ++ if(ret) ++ return ret; ++ ++ ae_manual.tisp_ae_ag_manual = control->value; ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_set(ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_set(ae_manual); ++ else ++ ret = -EINVAL; ++ ++ return ret; ++} ++ ++/*获å–自动增益控制方å¼.*/ ++static inline int ispcore_auto_gain_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_ae_ctrls_t ae_manual; ++ int ret = 0; ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_get(&ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_get(&ae_manual); ++ else ++ ret = -EINVAL; ++ ++ control->value = ae_manual.tisp_ae_ag_manual; ++ ++ return ret; ++} ++ ++/*手动增益控制模å¼ä¸‹ï¼Œè®¾ç½®å½“å‰å¢žç›Š.*/ ++static inline int ispcore_gain_s_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_ae_ctrls_t ae_manual; ++ int ret = 0; ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_get(&ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_get(&ae_manual); ++ else ++ ret = -EINVAL; ++ if(ret) ++ return ret; ++ ++ if(ae_manual.tisp_ae_ag_manual) { ++ ae_manual.tisp_ae_sensor_again = control->value; ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_set(ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_set(ae_manual); ++ else ++ ret = -EINVAL; ++ } else { ++ dev_warn(isp->dev, "set exp_abs while in exposure [auto] mode.\n"); ++ } ++ ++ return ret; ++} ++static inline int ispcore_gain_g_control(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_ae_ctrls_t ae_manual; ++ int ret = 0; ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_ae_main_manual_get(&ae_manual); ++ else if(isp->sensor_id == 1) ++ ret = tisp_ae_sec_manual_get(&ae_manual); ++ else ++ ret = -EINVAL; ++ ++ control->value = ae_manual.tisp_ae_sensor_again; ++ ++ return ret; ++} ++ ++static inline int tx_isp_isp_flicker_s_attr(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_anfiflicker_attr_t attr; ++ int ret = 0; ++ ++ ret = copy_from_user(&attr, (const void __user*)control->value, sizeof(tisp_anfiflicker_attr_t)); ++ if(ret != 0){ ++ ISP_ERROR("[ %s:%d ] copy error!!!\n", __func__, __LINE__); ++ } else { ++ ret = tisp_s_antiflick(isp->sensor_id, &attr); ++ if(ret != 0) ++ ISP_WARNING("[ %s:%d ] set control failed!!!\n", __func__, __LINE__); ++ } ++ ++ return ret; ++} ++ ++static inline int tx_isp_isp_flicker_g_attr(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_anfiflicker_attr_t attr; ++ int ret = 0; ++ ++ ret = tisp_g_antiflick(isp->sensor_id, &attr); ++ if(ret != 0){ ++ ISP_ERROR("[ %s:%d ] get control failed!!!\n", __func__, __LINE__); ++ goto err_get_flicker; ++ } ++ ++ ret = copy_to_user((void __user*)control->value, (const void *)&attr, sizeof(tisp_anfiflicker_attr_t)); ++ if(ret != 0) ++ ISP_ERROR("[ %s:%d ] copy error!!!\n", __func__, __LINE__); ++ ++err_get_flicker: ++ return ret; ++} ++ ++static int tx_isp_isp_module_s_attr(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_module_control_t module; ++ int ret = 0; ++ ++ module.key = control->value; ++ tisp_s_module_control(isp->sensor_id, module); ++ ++ return ret; ++} ++ ++static int tx_isp_isp_module_g_attr(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_module_control_t module; ++ int ret = 0; ++ ++ tisp_g_module_control(isp->sensor_id, &module); ++ control->value = module.key; ++ ++ return ret; ++} ++ ++static inline int tx_isp_isp_day_or_night_g_ctrl(struct isp_device *isp, struct v4l2_control *control) ++{ ++ control->value = isp->ctrls.daynight; ++ return 0; ++} ++ ++static inline int tx_isp_isp_day_or_night_s_ctrl(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int ret = 0; ++ TISP_MODE_DN_E dn = control->value; ++ ++ if(dn != isp->ctrls.daynight){ ++ tisp_day_or_night_s_ctrl(isp->sensor_id, dn); ++ isp->ctrls.daynight = dn; ++ } ++ ++ return ret; ++} ++ ++static int tx_isp_isp_ae_luma_g_ctrl(struct isp_device *isp, struct v4l2_control *control) ++{ ++#if 0 ++ unsigned char luma; ++ struct v4l2_subdev_format *input_fmt = &isp->formats[ISP_PAD_SINK]; ++ int width = input_fmt->format.width; ++ int height = input_fmt->format.height; ++ ++ tisp_g_ae_luma(&core->core_tuning, &luma, width, height); ++ control->value = luma; ++#endif ++ return 0; ++} ++ ++static int tx_isp_bcsh_hue_s_ctrl(struct isp_device *isp, struct v4l2_control *control) ++{ ++ unsigned char value = control->value; ++ int ret = 0; ++ ++ tisp_set_bcsh_hue(isp->sensor_id, value); ++ isp->ctrls.hue = value; ++ ++ return ret; ++} ++ ++static int tx_isp_bcsh_hue_g_ctrl(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int ret = 0; ++ ++ control->value = isp->ctrls.hue; ++ ++ return ret; ++} ++ ++static int tx_isp_switch_bin(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_bin_t attr; ++ int ret = 0; ++ ++ ret = private_copy_from_user(&attr, (const void __user*)control->value, sizeof(attr)); ++ if(ret != 0){ ++ ISP_ERROR("[ %s:%d ] copy error!!!\n", __func__, __LINE__); ++ } else { ++ //printk("\n------------------>> Test:%d-%d-%s <<------------------\n", attr.enable, attr.mode, attr.bname); ++ ret = tisp_switch_bin(isp->sensor_id, &attr); ++ if(ret != 0) ++ ISP_WARNING("[ %s:%d ] switch bin failed!!!\n", __func__, __LINE__); ++ } ++ return ret; ++} ++ ++static int tx_isp_faceae_s_attr(struct isp_video_device *ispvideo, struct v4l2_control *control) ++{ ++ ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct mscaler_device *mscaler = ispcam->mscaler; ++ struct isp_device *isp = ispcam->isp; ++ struct media_pad *remote = media_entity_remote_pad(&ispvideo->pad); ++ struct v4l2_subdev_format *input_fmt = &mscaler->formats[MSCALER_PAD_SINK]; ++ struct v4l2_subdev_format *output_fmt = &mscaler->formats[remote->index]; ++ ++ int in_width = input_fmt->format.width; ++ int in_height = input_fmt->format.height; ++ int out_width = output_fmt->format.width; ++ int out_height = output_fmt->format.height; ++ ++ tisp_face_t attr; ++ int ret = 0; ++ ++ ret = copy_from_user(&attr, (const void __user*)control->value, sizeof(attr)); ++ if(ret != 0){ ++ ISP_ERROR("[ %s:%d ] copy error!!!\n", __func__, __LINE__); ++ } else { ++ attr.top = (attr.top * in_height)/out_height; ++ attr.bottom = (attr.bottom * in_height)/out_height; ++ attr.left = (attr.left * in_width)/out_width; ++ attr.right = (attr.right * in_width)/out_width; ++ ret = tisp_ae_face_set(isp->sensor_id, &attr); ++ if(ret != 0) ++ ISP_WARNING("[ %s:%d ] set ae face failed!!!\n", __func__, __LINE__); ++ ++ } ++ return ret; ++} ++ ++static int tx_isp_faceae_g_attr(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_face_t attr; ++ int ret = 0; ++ ++ ret = tisp_ae_face_get(isp->sensor_id, &attr); ++ if(ret != 0){ ++ ISP_WARNING("[ %s:%d ] get ae smart failed!!!\n", __func__, __LINE__); ++ goto err_get_aesmart; ++ } ++ ++ ret = copy_to_user((void __user*)control->value, (const void *)&attr, sizeof(attr)); ++ if(ret != 0) ++ ISP_ERROR("[ %s:%d ] copy error!!!\n", __func__, __LINE__); ++ ++err_get_aesmart: ++ return ret; ++} ++ ++static int tx_isp_faceawb_s_attr(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_face_t attr; ++ int ret = 0; ++ ++ ret = copy_from_user(&attr, (const void __user*)control->value, sizeof(attr)); ++ if(ret != 0){ ++ ISP_ERROR("[ %s:%d ] copy error!!!\n", __func__, __LINE__); ++ } else { ++ ret = tisp_awb_face_set(isp->sensor_id, &attr); ++ if(ret != 0) ++ ISP_WARNING("[ %s:%d ] set awb face failed!!!\n", __func__, __LINE__); ++ ++ } ++ return ret; ++} ++ ++static int tx_isp_faceawb_g_attr(struct isp_device *isp, struct v4l2_control *control) ++{ ++ tisp_face_t attr; ++ int ret = 0; ++ ++ ret = tisp_awb_face_get(isp->sensor_id, &attr); ++ if(ret != 0){ ++ ISP_WARNING("[ %s:%d ] get awb face attr failed!!!\n", __func__, __LINE__); ++ goto err_get_aesmart; ++ } ++ ++ ret = copy_to_user((void __user*)control->value, (const void *)&attr, sizeof(attr)); ++ if(ret != 0) ++ ISP_ERROR("[ %s:%d ] copy error!!!\n", __func__, __LINE__); ++ ++err_get_aesmart: ++ return ret; ++} ++ ++static int wdr_enable(struct isp_device *isp, struct v4l2_control *control) ++{ ++ struct isp_async_device *isd = &isp->ispcam->isd[0]; ++ //int enable = control->value; ++ int ret = 0; ++ ++ ret = v4l2_s_ctrl(NULL, isd->sd->ctrl_handler, control); ++ return ret; ++} ++ ++static int tx_isp_set_default_bin_path(struct isp_device *isp, struct v4l2_control *control) ++{ ++ int ret = 0; ++ ret = copy_from_user(&isp->bpath, (const void __user*)control->value, sizeof(isp->bpath)); ++ return ret; ++} ++ ++int isp_video_g_ctrl(struct file *file, void *fh, struct v4l2_control *a) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct isp_device *isp = ispcam->isp; ++ int ret = 0; ++ ++ switch(a->id){ ++ case V4L2_CID_HFLIP: ++ ret = tx_isp_isp_hflip_g_control(isp, a); ++ break; ++ case V4L2_CID_VFLIP: ++ ret = tx_isp_isp_vflip_g_control(isp, a); ++ break; ++ case V4L2_CID_SATURATION: ++ ret = tx_isp_isp_sat_g_control(isp, a); ++ break; ++ case V4L2_CID_BRIGHTNESS: ++ ret = tx_isp_isp_bright_g_control(isp, a); ++ break; ++ case V4L2_CID_CONTRAST: ++ ret = tx_isp_isp_contrast_g_control(isp, a); ++ break; ++ case V4L2_CID_SHARPNESS: ++ ret = tx_isp_isp_sharp_g_control(isp, a); ++ break; ++ case V4L2_CID_EXPOSURE_AUTO: ++ ret = ispcore_exp_auto_g_control(isp, a); ++ break; ++ case V4L2_CID_EXPOSURE_ABSOLUTE: ++ ret = ispcore_exp_abs_g_control(isp, a); ++ break; ++ case V4L2_CID_EXPOSURE: ++ ret = ispcore_exp_g_control(isp, a); ++ break; ++ case V4L2_CID_AUTOGAIN: ++ ret = ispcore_auto_gain_g_control(isp, a); ++ break; ++ case V4L2_CID_GAIN: ++ ret = ispcore_gain_g_control(isp, a); ++ break; ++ case V4L2_CID_HUE: ++ ret = tx_isp_bcsh_hue_g_ctrl(isp, a); ++ break; ++ case V4L2_CID_POWER_LINE_FREQUENCY: ++ ret = tx_isp_isp_flicker_g_attr(isp, a); ++ break; ++ case IMAGE_TUNING_CID_MODULE_CONTROL: ++ ret = tx_isp_isp_module_g_attr(isp, a); ++ break; ++ case IMAGE_TUNING_CID_DAY_OR_NIGHT: ++ ret = tx_isp_isp_day_or_night_g_ctrl(isp, a); ++ break; ++ case IMAGE_TUNING_CID_AE_LUMA: ++ ret = tx_isp_isp_ae_luma_g_ctrl(isp, a); ++ break; ++ case IMAGE_TUNING_CID_FACE_AE_CONTROL: ++ ret = tx_isp_faceae_g_attr(isp, a); ++ break; ++ case IMAGE_TUNING_CID_FACE_AWB_CONTROL: ++ ret = tx_isp_faceawb_g_attr(isp, a); ++ break; ++ default: ++ ret = -EPERM; ++ break; ++ } ++ ++ return ret; ++} ++ ++ ++int isp_video_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct isp_device *isp = ispcam->isp; ++ int ret = 0; ++ ++ switch (a->id) { ++ case V4L2_CID_HFLIP: ++ ret = tx_isp_isp_hflip_s_control(isp, a); ++ break; ++ case V4L2_CID_VFLIP: ++ ret = tx_isp_isp_vflip_s_control(isp, a); ++ break; ++ case V4L2_CID_SATURATION: ++ ret = tx_isp_isp_sat_s_control(isp, a); ++ break; ++ case V4L2_CID_BRIGHTNESS: ++ ret = tx_isp_isp_bright_s_control(isp, a); ++ break; ++ case V4L2_CID_CONTRAST: ++ ret = tx_isp_isp_contrast_s_control(isp, a); ++ break; ++ case V4L2_CID_SHARPNESS: ++ ret = tx_isp_isp_sharp_s_control(isp, a); ++ break; ++ case V4L2_CID_EXPOSURE_AUTO: ++ ret = ispcore_exp_auto_s_control(isp, a); ++ break; ++ case V4L2_CID_EXPOSURE_ABSOLUTE: ++ ret = ispcore_exp_abs_s_control(isp, a); ++ break; ++ case V4L2_CID_EXPOSURE: ++ ret = ispcore_exp_s_control(isp, a); ++ break; ++ case V4L2_CID_AUTOGAIN: ++ ret = ispcore_auto_gain_s_control(isp, a); ++ break; ++ case V4L2_CID_GAIN: ++ ret = ispcore_gain_s_control(isp, a); ++ break; ++ case V4L2_CID_HUE: ++ ret = tx_isp_bcsh_hue_s_ctrl(isp, a); ++ break; ++ case IMAGE_TUNING_CID_SWITCH_BIN: ++ ret = tx_isp_switch_bin(isp, a); ++ break; ++ case V4L2_CID_POWER_LINE_FREQUENCY: ++ ret = tx_isp_isp_flicker_s_attr(isp, a); ++ break; ++ case IMAGE_TUNING_CID_MODULE_CONTROL: ++ ret = tx_isp_isp_module_s_attr(isp, a); ++ break; ++ case IMAGE_TUNING_CID_DAY_OR_NIGHT: ++ ret = tx_isp_isp_day_or_night_s_ctrl(isp, a); ++ break; ++ case IMAGE_TUNING_CID_FACE_AE_CONTROL: ++ ret = tx_isp_faceae_s_attr(ispvideo, a); ++ break; ++ case IMAGE_TUNING_CID_FACE_AWB_CONTROL: ++ ret = tx_isp_faceawb_s_attr(isp, a); ++ break; ++ case V4L2_CID_WIDE_DYNAMIC_RANGE: ++ ret = wdr_enable(isp, a); ++ break; ++ case IMAGE_TUNING_CID_SET_DEFAULT_BIN_PATH: ++ ret = tx_isp_set_default_bin_path(isp, a); ++ break; ++ default: ++ ret = -EPERM; ++ break; ++ } ++ return ret; ++} ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/Makefile b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/Makefile +new file mode 100755 +index 000000000..a0e01ba43 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/Makefile +@@ -0,0 +1 @@ ++obj-y +=isp-core.a +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/system_sensor_drv.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/system_sensor_drv.h +new file mode 100644 +index 000000000..e6546a59d +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/system_sensor_drv.h +@@ -0,0 +1,96 @@ ++#ifndef __SENSOR_DRV_H__ ++#define __SENSOR_DRV_H__ ++ ++#include "linux/types.h" ++ ++#define LOG2_GAIN_SHIFT 16 ++ ++typedef struct _sensor_context_t ++{ ++ int sensor_id; ++ uint16_t again; ++ uint16_t dgain; ++ uint8_t n_context; ++ uint8_t wdr_mode; ++ uint16_t again_x2; ++ uint16_t dgain_coarse; ++ uint16_t dgain_fine; ++ uint8_t column_buffer_gain_index; ++ uint16_t again_short; ++ uint16_t it; ++ uint16_t it_short; ++ uint16_t dgain_short; ++} sensor_context_t; ++ ++typedef struct _image_resolution_t ++{ ++ uint16_t width; ++ uint16_t height; ++} image_resolution_t; ++ ++typedef struct _sensor_param_t ++{ ++ uint8_t mode; ++ image_resolution_t total; ++ image_resolution_t active; ++ sensor_context_t sensor_ctx; ++ int32_t again_log2_max; ++ int32_t dgain_log2_max; ++ uint32_t integration_time_min; ++ uint32_t integration_time_max; ++ uint32_t integration_time_long_max; ++ uint32_t integration_time_limit; ++ uint16_t day_light_integration_time_max; ++ uint8_t integration_time_apply_delay; ++ uint8_t analog_gain_apply_delay; ++ uint8_t digital_gain_apply_delay; ++ int32_t xoffset; ++ int32_t yoffset; ++ int32_t anti_flicker_pos; ++ uint32_t lines_per_second; ++ uint32_t integration_time_min_short; ++ uint32_t integration_time_max_short; ++ uint32_t again_log2_max_short; ++ uint32_t dgain_log2_max_short; ++ uint8_t analog_gain_short_apply_delay; ++ uint8_t digital_gain_short_apply_delay; ++ uint8_t integration_time_short_apply_delay; ++} sensor_param_t; ++ ++typedef struct _sensor_control_t ++{ ++ sensor_param_t param[3]; ++ void (*hw_reset_disable)(void); ++ void (*hw_reset_enable)(void); ++ int32_t (*alloc_analog_gain)(int32_t gain, sensor_context_t *p_ctx); ++ int32_t (*alloc_analog_gain_short)(int32_t gain, sensor_context_t *p_ctx); ++ int32_t (*alloc_digital_gain)(int32_t gain, sensor_context_t *p_ctx); ++ int32_t (*alloc_digital_gain_short)(int32_t gain, sensor_context_t *p_ctx); ++ uint32_t (*alloc_integration_time)(uint32_t int_time, sensor_context_t *p_ctx); ++ uint32_t (*alloc_integration_time_short)(uint32_t int_time, sensor_context_t *p_ctx); ++ void (*set_integration_time)(uint16_t int_time, sensor_param_t *param); ++ void (*set_integration_time_short)(uint16_t int_time, sensor_param_t *param); ++ void (*start_changes)(sensor_context_t *p_ctx); ++ void (*end_changes)(sensor_context_t *p_ctx); ++ void (*set_analog_gain)(uint32_t again_reg_val, sensor_context_t *p_ctx); ++ void (*get_analog_gain)(uint32_t *again_reg_val, sensor_context_t *p_ctx); ++ void (*set_analog_gain_short)(uint32_t again_reg_val, sensor_context_t *p_ctx); ++ void (*get_analog_gain_short)(uint32_t *again_reg_val, sensor_context_t *p_ctx); ++ void (*set_digital_gain)(uint32_t dgain_reg_val, sensor_context_t *p_ctx); ++ void (*set_digital_gain_short)(uint32_t dgain_reg_val, sensor_context_t *p_ctx); ++ uint16_t (*get_normal_fps)(sensor_param_t *param); ++ uint16_t (*read_black_pedestal)(int i, uint32_t gain); ++ void (*set_mode)( uint8_t mode, sensor_param_t *param); ++ void (*set_wdr_mode)(uint8_t wdr, sensor_param_t *param); ++ uint32_t (*fps_control)(uint8_t fps, sensor_param_t *param); ++ uint16_t (*get_id)(sensor_context_t *p_ctx); ++ void (*disable_isp)(sensor_context_t *p_ctx); ++ uint32_t (*get_lines_per_second)(sensor_param_t *param); ++} sensor_control_t; ++ ++typedef sensor_control_t *sensor_control_ptr_t; ++ ++void sensor_init(sensor_control_t *ctrl, int vinum); ++int sensor_early_init(void *ispcore); ++ ++#endif /* __SENSOR_DRV_H__ */ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano-core-ctrl.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano-core-ctrl.h +new file mode 100644 +index 000000000..2bbacd171 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano-core-ctrl.h +@@ -0,0 +1,868 @@ ++#ifndef __TIZIANO_TIZIANO_CORE_TUNING_H__ ++#define __TIZIANO_TIZIANO_CORE_TUNING_H__ ++#include "tiziano-isp.h" ++extern int day_night[2]; ++ ++typedef enum tisp_mode_day_and_night { ++ TISP_RUNING_MODE_DAY_MODE, ++ TISP_RUNING_MODE_NIGHT_MODE, ++ TISP_RUNING_MODE_CUSTOM_MODE, ++ TISP_RUNING_MODE_BUTT, ++} TISP_MODE_DN_E; ++ ++struct isp_core_sensor_attr{ ++ unsigned int hts;/* sensor hts */ ++ unsigned int vts;/* sensor vts */ ++ unsigned int fps;/* sensor fps: */ ++ unsigned int width;/* sensor width*/ ++ unsigned int height;/* sensor height*/ ++}; ++ ++typedef enum { ++ ISP_CORE_FLIP_NORMAL_MODE = 0, ++ ISP_CORE_FLIP_H_MODE = 1, ++ ISP_CORE_FLIP_V_MODE = 2, ++ ISP_CORE_FLIP_HV_MODE = 3, ++ ISP_CORE_FLIP_MODE_BUTT, ++} ISP_CORE_HVFLIP; ++ ++typedef struct tisp_ncu_info { ++ uint32_t width; ++ uint32_t height; ++ uint32_t sta_y_block_size; ++ uint32_t sta_y_stride; ++ uint32_t sta_y_buf_size; ++} tisp_ncu_info_t; ++ ++typedef enum { ++ IMP_ISP_GAMMA_CURVE_DEFAULT, ++ IMP_ISP_GAMMA_CURVE_SRGB, ++ IMP_ISP_GAMMA_CURVE_HDR, ++ IMP_ISP_GAMMA_CURVE_USER, ++ IMP_ISP_GAMMA_CURVE_BUTT, ++} tisp_gamma_type_t; ++typedef struct tisp_gamma_lut{ ++ tisp_gamma_type_t type; ++ unsigned short gamma[129]; ++} tisp_gamma_t; ++ ++typedef struct { ++ unsigned char weight[225]; ++} tisp_3a_weight_t; ++ ++typedef struct tisp_zone_info{ ++ unsigned int zone[15][15]; ++} __attribute__((packed, aligned(1))) tisp_zone_info_t; ++ ++typedef struct { ++ tisp_zone_info_t wb_r; ++ tisp_zone_info_t wb_g; ++ tisp_zone_info_t wb_b; ++} tisp_wb_statis_info_t; ++ ++typedef enum tisp_wb_algo_t{ ++ IMPISP_AWB_ALGO_NORMAL, ++ IMPISP_AWB_ALGO_GRAYWORLD, ++ IMPISP_AWB_ALGO_REWEIGHT, ++} TISP_AWB_ALGO; ++ ++typedef struct tisp_ae_ex_min { ++ unsigned int min_it; ++ unsigned int min_again; ++ unsigned int min_it_short; ++ unsigned int min_again_short; ++} tisp_ae_ex_min_t; ++ ++typedef union tisp_module_control { ++ unsigned int key; ++ struct { ++ unsigned int bitBypassBLC : 1; /* [0] */ ++ unsigned int bitBypassLSC : 1; /* [1] */ ++ unsigned int bitBypassAWB0 : 1; /* [2] */ ++ unsigned int bitBypassWDR : 1; /* [3] */ ++ unsigned int bitBypassDPC : 1; /* [4] */ ++ unsigned int bitBypassGIB : 1; /* [5] */ ++ unsigned int bitBypassAWB1 : 1; /* [6] */ ++ unsigned int bitBypassADR : 1; /* [7] */ ++ unsigned int bitBypassDMSC : 1; /* [8] */ ++ unsigned int bitBypassCCM : 1; /* [9] */ ++ unsigned int bitBypassGAMMA : 1; /* [10] */ ++ unsigned int bitBypassDEFOG : 1; /* [11] */ ++ unsigned int bitBypassCSC : 1; /* [12] */ ++ unsigned int bitBypassMDNS : 1; /* [13] */ ++ unsigned int bitBypassYDNS : 1; /* [14] */ ++ unsigned int bitBypassBCSH : 1; /* [15] */ ++ unsigned int bitBypassCLM : 1; /* [16] */ ++ unsigned int bitBypassYSP : 1; /* [17] */ ++ unsigned int bitBypassSDNS : 1; /* [18] */ ++ unsigned int bitBypassCDNS : 1; /* [19] */ ++ unsigned int bitBypassHLDC : 1; /* [20] */ ++ unsigned int bitBypassLCE : 1; /* [21] */ ++ unsigned int bitRsv : 10; /* [22 ~ 30] */ ++ }; ++} tisp_module_control_t; ++ ++typedef struct tisp_autozoom_control { ++ int32_t zoom_chx_en[3]; ++ int32_t zoom_left[3]; ++ int32_t zoom_top[3]; ++ int32_t zoom_width[3]; ++ int32_t zoom_height[3]; ++} tisp_autozoom_attr_t; ++ ++typedef enum { ++ ISP_CSC_CG_BT601_FULL, ++ ISP_CSC_CG_BT601_LIMITED, ++ ISP_CSC_CG_BT709_FULL, ++ ISP_CSC_CG_BT709_LIMITED, ++ ISP_CSC_CG_USER, ++ ISP_CSC_CG_BUTT, ++} tisp_csc_cg_t; ++ ++typedef struct { ++ int CscCoef[9]; ++ unsigned char CscOffset[2]; ++ unsigned char CscClip[4]; ++} tisp_csc_matrix_t; ++ ++typedef struct { ++ tisp_csc_cg_t ColorGamut; ++ tisp_csc_matrix_t Matrix; ++ tisp_csc_matrix_t Matrixin; ++} tisp_csc_attr_t; ++ ++typedef struct tisp_ccm_attr{ ++ char ccm_manual; ++ char sat_en; ++ int32_t ccm[9]; ++} tisp_ccm_t; ++ ++typedef enum { ++ ISP_ANTIFLICKER_DISABLE_MODE, ++ ISP_ANTIFLICKER_NORMAL_MODE, ++ ISP_ANTIFLICKER_AUTO_MODE,// can reach min it ++ ISP_ANTIFLICKER_BUTT, ++} tisp_antiflicker_mode_t; ++typedef struct { ++ tisp_antiflicker_mode_t mode; ++ uint8_t freq; ++} tisp_anfiflicker_attr_t; ++ ++typedef enum { ++ IMPISP_MASK_TYPE_RGB = 0, ++ IMPISP_MASK_TYPE_YUV = 1, ++} mask_value_type_t; ++ ++typedef union { ++ struct { ++ unsigned char r_value; ++ unsigned char g_value; ++ unsigned char b_value; ++ } mask_argb; ++ struct { ++ unsigned char y_value; ++ unsigned char u_value; ++ unsigned char v_value; ++ } mask_ayuv; ++} mask_value_t; ++ ++struct isp_mask_block_par { ++ unsigned char mask_en; ++ unsigned short mask_pos_top; ++ unsigned short mask_pos_left; ++ unsigned short mask_width; ++ unsigned short mask_height; ++ mask_value_t mask_value; ++}; ++ ++typedef struct { ++ struct isp_mask_block_par mask_chx[3][4]; ++ mask_value_type_t mask_type; ++} tisp_mask_attr_t; ++ ++/** ++ * OSD picture atribution ++ */ ++typedef struct { ++ uint8_t osd_enable; /**< osd enable */ ++ uint16_t osd_left; /**< osd area x value */ ++ uint16_t osd_top; /**< osd area y value */ ++ uint16_t osd_width; /**< osd area width */ ++ uint16_t osd_height; /**< osd area height */ ++ char osd_image_path[128]; ++ uint16_t osd_stride; /**< osd stride */ ++} tisp_osd_pic_attr_t; ++ ++/** ++ * OSD picture type ++ */ ++typedef enum { ++ IMP_ISP_PIC_ARGB_1555, /**< ARGB1555 */ ++ IMP_ISP_PIC_ARGB_8888, /**< ARGB888 */ ++} tisp_pic_type_t; ++ ++/** ++ * OSD type ++ */ ++typedef enum { ++ IMP_ISP_ARGB_TYPE_ARGB = 0, ++ IMP_ISP_ARGB_TYPE_ARBG, ++ IMP_ISP_ARGB_TYPE_AGRB, ++ IMP_ISP_ARGB_TYPE_AGBR, ++ IMP_ISP_ARGB_TYPE_ABRG, ++ IMP_ISP_ARGB_TYPE_ABGR, ++ IMP_ISP_ARGB_TYPE_RGBA = 8, ++ IMP_ISP_ARGB_TYPE_RBGA, ++ IMP_ISP_ARGB_TYPE_GRBA, ++ IMP_ISP_ARGB_TYPE_GBRA, ++ IMP_ISP_ARGB_TYPE_BRGA, ++ IMP_ISP_ARGB_TYPE_BGRA, ++} tisp_argb_type_t; ++ ++/** ++ * OSD channel attribution ++ */ ++typedef struct { ++ tisp_pic_type_t osd_type; /**< OSD picture type */ ++ tisp_argb_type_t osd_argb_type; /**< OSD argb type */ ++ TISP_OPS_MODE osd_pixel_alpha_disable; /**< OSD pixel alpha disable function enable */ ++ tisp_osd_pic_attr_t pic[8]; /**< OSD picture attribution */ ++} tisp_osd_chx_attr_t; ++ ++typedef struct { ++ tisp_osd_chx_attr_t osd_chx[2]; ++} tisp_osd_attr_t; ++ ++/** ++ * Draw window attribution ++ */ ++typedef struct { ++ uint8_t wind_enable; /**< draw window enable */ ++ uint16_t wind_x; /**< window start pixel in horizental */ ++ uint16_t wind_y; /**< window start pixel in vertical */ ++ uint16_t wind_w; /**< window width */ ++ uint16_t wind_h; /**< window height */ ++ mask_value_t wind_color; /**< window color */ ++ uint8_t wind_line_w; /**< window line width */ ++ uint8_t wind_alpha; /**< window alpha */ ++} tisp_draw_wind_attr_t; ++ ++/** ++ * Draw range attribution ++ */ ++typedef struct { ++ uint8_t rang_enable; /**< draw range enable */ ++ uint16_t rang_x; /**< range start pixel in horizental */ ++ uint16_t rang_y; /**< range start pixel in vertical */ ++ uint16_t rang_w; /**< range width */ ++ uint16_t rang_h; /**< range height */ ++ mask_value_t rang_color; /**< range color */ ++ uint8_t rang_line_w; /**< range line width */ ++ uint8_t rang_alpha; /**< range alpha(3bit) */ ++ uint16_t rang_extend; /**< range extend */ ++} tisp_draw_range_attr_t; ++ ++/** ++ * Draw line attribution ++ */ ++typedef struct { ++ uint8_t line_enable; /**< draw line enable */ ++ uint16_t line_startx; /**< line start pixel in horizental */ ++ uint16_t line_starty; /**< line start pixel in vertical */ ++ uint16_t line_endx; /**< line width */ ++ uint16_t line_endy; /**< line height */ ++ mask_value_t line_color; /**< line color */ ++ uint8_t line_width; /**< line line width */ ++ uint8_t line_alpha; /**< line alpha */ ++} tisp_draw_line_attr_t; ++ ++/** ++ * Draw type ++ */ ++typedef enum { ++ TISP_DRAW_LINE, /**< Draw line */ ++ TISP_DRAW_RANGE, /**< Draw range */ ++ TISP_DRAW_WIND, /**< Draw window */ ++} tisp_draw_type_t; ++ ++/** ++ * Draw unit Attribution ++ */ ++typedef struct { ++ tisp_draw_type_t type; /**< draw type */ ++ union { ++ tisp_draw_wind_attr_t wind; /**< draw window attr */ ++ tisp_draw_range_attr_t rang; /**< draw range attr */ ++ tisp_draw_line_attr_t line; /**< draw line attr */ ++ } draw_cfg; /**< draw attr */ ++} tisp_draw_attr_t; ++ ++/** ++ * Draw Attribution for each channel ++ */ ++typedef struct { ++ tisp_draw_attr_t draw_chx[2][16]; /**< draw attr for channel0, the max draw num is 16 */ ++} tisp_draw_chx_attr_t; ++ ++ ++/** ++ * awb mode ++ */ ++typedef enum { ++ ISP_CORE_WB_MODE_AUTO = 0, /**< auto mode */ ++ ISP_CORE_WB_MODE_MANUAL, /**< manual mode */ ++ ISP_CORE_WB_MODE_DAY_LIGHT, /**< day light mode */ ++ ISP_CORE_WB_MODE_CLOUDY, /**< cloudy mode */ ++ ISP_CORE_WB_MODE_INCANDESCENT, /**< incandescent mode */ ++ ISP_CORE_WB_MODE_FLOURESCENT, /**< flourescent mode */ ++ ISP_CORE_WB_MODE_TWILIGHT, /**< twilight mode */ ++ ISP_CORE_WB_MODE_SHADE, /**< shade mode */ ++ ISP_CORE_WB_MODE_WARM_FLOURESCENT, /**< warm flourescent mode */ ++ ISP_CORE_WB_MODE_COLORTEND, /**< Color Trend Mode */ ++} TISPAWBMode; ++ ++/** ++ * awb gain ++ */ ++typedef struct { ++ uint32_t rgain; /**< awb r-gain */ ++ uint32_t bgain; /**< awb b-gain */ ++} tisp_awb_gain_t; ++ ++/** ++ * awb custom mode attribution ++ */ ++typedef struct { ++ TISP_OPS_MODE customEn; /**< awb custom enable */ ++ tisp_awb_gain_t gainH; /**< awb gain on high ct */ ++ tisp_awb_gain_t gainM; /**< awb gain on medium ct */ ++ tisp_awb_gain_t gainL; /**< awb gain on low ct */ ++ uint32_t ct_node[4]; /**< awb custom mode nodes */ ++} tisp_awb_custom_attr_t; ++ ++/** ++ * awb attribution ++ */ ++typedef struct isp_core_wb_attr{ ++ TISPAWBMode mode; /**< awb mode */ ++ tisp_awb_gain_t gain_val; /**< awb gain on manual mode */ ++ TISP_OPS_MODE frz; ++ unsigned int ct; /**< awb current ct value */ ++ tisp_awb_custom_attr_t custom; /**< awb custom attribution */ ++ TISP_OPS_MODE awb_start_en; /**< awb algo start function enable */ ++ tisp_awb_gain_t awb_start; /**< awb algo start point */ ++} tisp_awb_attr_t; ++ ++ ++typedef struct isp_core_awb_global_statis { ++ tisp_awb_gain_t statis_weight_gain; /**< awb statistics */ ++ tisp_awb_gain_t statis_gol_gain; /**< awb global statistics */ ++} tisp_awb_global_statics_t; ++ ++/** ++ * AE scence mode ++ */ ++typedef enum { ++ TISP_AE_SCENCE_AUTO, /**< auto mode */ ++ TISP_AE_SCENCE_DISABLE, /**< diable mode */ ++ TISP_AE_SCENCE_ROI_ENABLE, /**< enable mode */ ++ TISP_AE_SCENCE_GLOBAL_ENABLE, /**< enable mode */ ++ TISP_AE_SCENCE_BUTT, /**< effect paramater, parameters have to be less than this value */ ++} TISPAEScenceMode; ++ ++/** ++ * AE scence mode attr ++ */ ++typedef struct { ++ TISPAEScenceMode AeHLCEn; /**< AE high light depress enable */ ++ unsigned char AeHLCStrength; /**< AE high light depress strength (0 ~ 10) */ ++ TISPAEScenceMode AeBLCEn; /**< AE back light compensation */ ++ unsigned char AeBLCStrength; /**< AE back light compensation strength (0 ~ 10) */ ++ TISPAEScenceMode AeTargetCompEn; /**< AE luma target compensation enable */ ++ uint32_t AeTargetComp; /**< AE luma target compensation strength(0 ~ 255)*/ ++ TISPAEScenceMode AeStartEn; /**< AE start point enable */ ++ uint32_t AeStartEv; /**< AE start ev value */ ++ ++ uint32_t luma; /**< AE luma value */ ++ uint32_t luma_scence; /**< AE luma value */ ++} tisp_ae_scence_attr_t; ++ ++typedef enum { ++ ISP_CORE_EXPR_UNIT_LINE, /**< The unit is integration line */ ++ ISP_CORE_EXPR_UNIT_US, /**< The unit is millisecond */ ++} TISPAEIntegrationTimeUnit; ++ ++/** ++ * AE exposure info ++ */ ++typedef struct { ++ TISPAEIntegrationTimeUnit AeIntegrationTimeUnit; /**< AE integration time unit */ ++ TISP_OPS_TYPE AeMode; /**< AE freezen enable */ ++ TISP_OPS_TYPE AeIntegrationTimeMode; /**< AE integration time manual */ ++ TISP_OPS_TYPE AeAGainManualMode; /**< AE sensor analog gain manual */ ++ TISP_OPS_TYPE AeDGainManualMode; /**< AE sensor digital gain manual */ ++ TISP_OPS_TYPE AeIspDGainManualMode; /**< AE ISP digital gain manual */ ++ uint32_t AeIntegrationTime; /**< AE integration time value */ ++ uint32_t AeAGain; /**< AE sensor analog gain value */ ++ uint32_t AeDGain; /**< AE sensor digital gain value */ ++ uint32_t AeIspDGain; /**< AE ISP digital gain value */ ++ ++ TISP_OPS_TYPE AeMinIntegrationTimeMode; /**< Reserve */ ++ TISP_OPS_TYPE AeMinAGainMode; /**< AE min analog gain enable */ ++ TISP_OPS_TYPE AeMinDgainMode; /**< Reserve */ ++ TISP_OPS_TYPE AeMinIspDGainMode; /**< Reserve */ ++ TISP_OPS_TYPE AeMaxIntegrationTimeMode; /**< AE max integration time enable */ ++ TISP_OPS_TYPE AeMaxAGainMode; /**< AE max sensor analog gain enable */ ++ TISP_OPS_TYPE AeMaxDgainMode; /**< AE max sensor digital gain enable */ ++ TISP_OPS_TYPE AeMaxIspDGainMode; /**< AE max isp digital gain enable */ ++ uint32_t AeMinIntegrationTime; /**< AE min integration time */ ++ uint32_t AeMinAGain; /**< AE min sensor analog gain */ ++ uint32_t AeMinDgain; /**< AE min sensor digital gain */ ++ uint32_t AeMinIspDGain; /**< AE min isp digital gain */ ++ uint32_t AeMaxIntegrationTime; /**< AE max integration time */ ++ uint32_t AeMaxAGain; /**< AE max sensor analog gain */ ++ uint32_t AeMaxDgain; /**< AE max sensor digital gain */ ++ uint32_t AeMaxIspDGain; /**< AE max isp digital gain */ ++ ++ /* WDR模å¼ä¸‹çŸ­å¸§çš„AE 手动模å¼å±žæ€§*/ ++ TISP_OPS_TYPE AeShortMode; /**< AE freezen enable */ ++ TISP_OPS_TYPE AeShortIntegrationTimeMode; /**< AE integration time manual */ ++ TISP_OPS_TYPE AeShortAGainManualMode; /**< AE sensor analog gain manual */ ++ TISP_OPS_TYPE AeShortDGainManualMode; /**< AE sensor digital gain manual */ ++ TISP_OPS_TYPE AeShortIspDGainManualMode; /**< AE ISP digital gain manual */ ++ uint32_t AeShortIntegrationTime; /**< AE integration time value */ ++ uint32_t AeShortAGain; /**< AE sensor analog gain value */ ++ uint32_t AeShortDGain; /**< AE sensor digital gain value */ ++ uint32_t AeShortIspDGain; /**< AE ISP digital gain value */ ++ ++ TISP_OPS_TYPE AeShortMinIntegrationTimeMode; /**< Reserve */ ++ TISP_OPS_TYPE AeShortMinAGainMode; /**< AE min analog gain enable */ ++ TISP_OPS_TYPE AeShortMinDgainMode; /**< Reserve */ ++ TISP_OPS_TYPE AeShortMinIspDGainMode; /**< Reserve */ ++ TISP_OPS_TYPE AeShortMaxIntegrationTimeMode; /**< AE max integration time enable */ ++ TISP_OPS_TYPE AeShortMaxAGainMode; /**< AE max sensor analog gain enable */ ++ TISP_OPS_TYPE AeShortMaxDgainMode; /**< AE max sensor digital gain enable */ ++ TISP_OPS_TYPE AeShortMaxIspDGainMode; /**< AE max isp digital gain enable */ ++ uint32_t AeShortMinIntegrationTime; /**< AE min integration time */ ++ uint32_t AeShortMinAGain; /**< AE min sensor analog gain */ ++ uint32_t AeShortMinDgain; /**< AE min sensor digital gain */ ++ uint32_t AeShortMinIspDGain; /**< AE min isp digital gain */ ++ uint32_t AeShortMaxIntegrationTime; /**< AE max integration time */ ++ uint32_t AeShortMaxAGain; /**< AE max sensor analog gain */ ++ uint32_t AeShortMaxDgain; /**< AE max sensor digital gain */ ++ uint32_t AeShortMaxIspDGain; /**< AE max isp digital gain */ ++ ++ uint32_t TotalGainDb; /**< AE total gain, unit is dB */ ++ uint32_t TotalGainDbShort; /**< AE total gain, unit is dB */ ++ uint32_t ExposureValue; /**< AE exposure value(integration time x again x dgain) */ ++ uint32_t EVLog2; /**< AE exposure value cal by log */ ++} tisp_ae_exprinfo_t; ++ ++/** ++ * AE statistics info ++ */ ++typedef struct { ++ unsigned short ae_hist_5bin[5]; /**< AE hist bin value [0 ~ 65535] */ ++ uint32_t ae_hist_256bin[256]; /**< AE hist bin value, is the true value of pixels num each bin */ ++ tisp_zone_info_t ae_statis; /**< AE statistics info */ ++} __attribute__((packed, aligned(1))) tisp_ae_statis_info_t; ++ ++/** ++ * AF statistics info ++ */ ++typedef struct { ++ tisp_zone_info_t Af_Fir0; ++ tisp_zone_info_t Af_Fir1; ++ tisp_zone_info_t Af_Iir0; ++ tisp_zone_info_t Af_Iir1; ++ tisp_zone_info_t Af_YSum; ++ tisp_zone_info_t Af_HighLumaCnt; ++} tisp_af_statis_info_t; ++ ++/** ++ * AE weight attribute ++ */ ++typedef struct { ++ TISP_OPS_MODE roi_enable; /**< roi weight set enable */ ++ TISP_OPS_MODE weight_enable; /**< global weight set enable */ ++ tisp_3a_weight_t ae_roi; /**< roi weight value (0 ~ 8) */ ++ tisp_3a_weight_t ae_weight; /**< global weight value (0 ~ 8)*/ ++} tisp_ae_weight_t; ++ ++/** ++ * statistics color domain ++ */ ++typedef enum { ++ IMP_ISP_HIST_ON_RAW, /**< Raw Domain */ ++ IMP_ISP_HIST_ON_YUV, /**< YUV Domain */ ++} TISPHistDomain; ++ ++/** ++ * statistics hist area struct ++ */ ++typedef struct { ++ unsigned int start_h; /**< start pixel in the horizontal */ ++ unsigned int start_v; /**< start pixel in the vertical */ ++ unsigned char node_h; /**< the statistics node num in the horizontal */ ++ unsigned char node_v; /**< the statistics node num in the vertical */ ++} tisp_statis_location_t; ++ ++/** ++ * AE statistics attribution ++ */ ++typedef struct { ++ TISP_OPS_MODE ae_statis_en; ++ tisp_statis_location_t local; /**< AE statistics location */ ++ TISPHistDomain hist_domain; /**< AE Hist statistics color domain */ ++ unsigned char histThresh[4]; /**< AE Hist Thresh */ ++} tisp_ae_statis_attr_t; ++ ++/** ++ * AWB statistics value attribution ++ */ ++typedef enum { ++ IMP_ISP_AWB_ORIGIN, /**< Original value */ ++ IMP_ISP_AWB_LIMITED, /**< Limited statistics value */ ++} TISPAWBStatisMode; ++ ++/** ++ * AWB statistics attribution ++ */ ++typedef struct { ++ TISP_OPS_MODE awb_statis_en; ++ tisp_statis_location_t local; /**< AWB Statistic area */ ++ TISPAWBStatisMode mode; /**< AWB Statistic mode */ ++} tisp_awb_statis_attr_t; ++ ++/** ++ * AF statistics attribution ++ */ ++typedef struct { ++ TISP_OPS_MODE af_statis_en; ++ tisp_statis_location_t local; /**< AF statistics area */ ++ unsigned char af_metrics_shift; /**< Metrics scaling factor 0x0 is default*/ ++ unsigned short af_delta; /**< AF statistics low pass fliter weight [0 ~ 64]*/ ++ unsigned short af_theta; /**< AF statistics high pass fliter weight [0 ~ 64]*/ ++ unsigned short af_hilight_th; /**< AF high light threshold [0 ~ 255]*/ ++ unsigned short af_alpha_alt; /**< AF statistics H and V direction weight [0 ~ 64]*/ ++ unsigned short af_belta_alt; /**< AF statistics H and V direction weight [0 ~ 64]*/ ++} tisp_af_statis_attr_t; ++ ++/** ++ * Statistics info attribution ++ */ ++typedef struct { ++ tisp_ae_statis_attr_t ae; /**< AE statistics info attr */ ++ tisp_awb_statis_attr_t awb; /**< AWB statistics info attr */ ++ tisp_af_statis_attr_t af; /**< AF statistics info attr */ ++} tisp_statis_config_t; ++ ++typedef enum { ++ IMP_ISP_MODULE_SINTER = 0, /**< 2Dé™å™ªä¸‹æ ‡ */ ++ IMP_ISP_MODULE_TEMPER, /**< 3Dé™å™ªä¸‹æ ‡ */ ++ IMP_ISP_MODULE_DRC, /**< 数字宽动æ€ä¸‹æ ‡ */ ++ IMP_ISP_MODULE_DPC, /**< 动æ€åŽ»å点下标 */ ++ IMP_ISP_MODULE_BUTT, /**< ç”¨äºŽåˆ¤æ–­å‚æ•°æœ‰æ•ˆæ€§çš„值,必须大于此值 */ ++} IMPISPModuleRatioArrayList; ++ ++typedef struct { ++ TISP_OPS_MODE en; /**< module ratio enable */ ++ uint8_t ratio; /**< module ratio value. The default value is 128, more than 128 (increase strength), and less than 128 (decrease strength) */ ++} tisp_ratio_unit_t; ++ ++/** ++ * ISP module ratio Attrbution ++ */ ++typedef struct { ++ tisp_ratio_unit_t ratio_attr[16]; /**< module ratio attr */ ++} tisp_module_ratio_t; ++ ++typedef struct { ++ uint32_t af_metrics; /**< AF Main metrics */ ++ uint32_t af_metrics_alt; /**< AF second metrics */ ++ uint8_t af_frame_num; /**< AF frame num */ ++} tisp_af_metric_info_t; ++ ++typedef struct { ++ TISP_OPS_MODE enable; ++ unsigned int left; ++ unsigned int top; ++ unsigned int right; ++ unsigned int bottom; ++ unsigned int target; ++} tisp_face_t; ++ ++typedef enum { ++ TISP_WDR_OUTPUT_MODE_FUS_FRAME, ++ TISP_WDR_OUTPUT_MODE_LONG_FRAME, ++ TISP_WDR_OUTPUT_MODE_SHORT_FRAME, ++ TISP_WDR_OUTPUT_MODE_BUTT, ++} tisp_wdr_output_mode_t; ++ ++typedef struct { ++ TISPAEIntegrationTimeUnit AeIntegrationTimeUnit; /**< AEæ›å…‰æ—¶é—´å•ä½ */ ++ uint32_t AeIntegrationTime; /**< AE手动模å¼ä¸‹çš„æ›å…‰å€¼ */ ++ uint32_t AeAGain; /**< AE Sensor 模拟增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeDGain; /**< AE Sensor数字增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeIspDGain; /**< AE ISP 数字增益值,å•ä½å€æ•° x 1024*/ ++ ++ uint32_t AeMinIntegrationTime; /**< AEæœ€å°æ›å…‰æ—¶é—´ */ ++ uint32_t AeMinAGain; /**< AE最å°sensor模拟增益 */ ++ uint32_t AeMinDgain; /**< AE最å°sensor数字增益 */ ++ uint32_t AeMinIspDGain; /**< AE最å°ISP数字增益 */ ++ uint32_t AeMaxIntegrationTime; /**< AE最大æ›å…‰æ—¶é—´ */ ++ uint32_t AeMaxAGain; /**< AE最大sensor模拟增益 */ ++ uint32_t AeMaxDgain; /**< AE最大sensor数字增益 */ ++ uint32_t AeMaxIspDGain; /**< AE最大ISP数字增益 */ ++ ++ /* WDR模å¼ä¸‹çŸ­å¸§çš„AE 手动模å¼å±žæ€§*/ ++ uint32_t AeShortIntegrationTime; /**< AE手动模å¼ä¸‹çš„æ›å…‰å€¼ */ ++ uint32_t AeShortAGain; /**< AE Sensor 模拟增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeShortDGain; /**< AE Sensor数字增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeShortIspDGain; /**< AE ISP 数字增益值,å•ä½å€æ•° x 1024*/ ++ ++ uint32_t AeShortMinIntegrationTime; /**< AEæœ€å°æ›å…‰æ—¶é—´ */ ++ uint32_t AeShortMinAGain; /**< AE最å°sensor模拟增益 */ ++ uint32_t AeShortMinDgain; /**< AE最å°sensor数字增益 */ ++ uint32_t AeShortMinIspDGain; /**< AE最å°ISP数字增益 */ ++ uint32_t AeShortMaxIntegrationTime; /**< AE最大æ›å…‰æ—¶é—´ */ ++ uint32_t AeShortMaxAGain; /**< AE最大sensor模拟增益 */ ++ uint32_t AeShortMaxDgain; /**< AE最大sensor数字增益 */ ++ uint32_t AeShortMaxIspDGain; /**< AE最大ISP数字增益 */ ++ uint32_t fps; /**< sensor 帧率 */ ++ tisp_ae_statis_attr_t AeStatis; ++} tisp_ae_algo_init_t; ++ ++typedef struct { ++ tisp_ae_statis_info_t ae_info; ++ TISPAEIntegrationTimeUnit AeIntegrationTimeUnit; /**< AEæ›å…‰æ—¶é—´å•ä½ */ ++ uint32_t AeIntegrationTime; /**< AE手动模å¼ä¸‹çš„æ›å…‰å€¼ */ ++ uint32_t AeAGain; /**< AE Sensor 模拟增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeDGain; /**< AE Sensor数字增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeIspDGain; /**< AE ISP 数字增益值,å•ä½å€æ•° x 1024*/ ++ uint32_t AeShortIntegrationTime; /**< AE手动模å¼ä¸‹çš„æ›å…‰å€¼ */ ++ uint32_t AeShortAGain; /**< AE Sensor 模拟增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeShortDGain; /**< AE Sensor数字增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeShortIspDGain; /**< AE ISP 数字增益值,å•ä½å€æ•° x 1024*/ ++ ++ uint32_t Wdr_mode; ++ struct isp_core_sensor_attr sensor_attr; ++} __attribute__((packed, aligned(1))) tisp_ae_algo_info_t; ++ ++typedef struct { ++ uint32_t change; ++ TISPAEIntegrationTimeUnit AeIntegrationTimeUnit; /**< AEæ›å…‰æ—¶é—´å•ä½ */ ++ uint32_t AeIntegrationTime; /**< AE手动模å¼ä¸‹çš„æ›å…‰å€¼ */ ++ uint32_t AeAGain; /**< AE Sensor 模拟增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeDGain; /**< AE Sensor数字增益值,å•使˜¯å€æ•° x 1024 */ ++ ++ uint32_t AeIspDGain; /**< AE ISP 数字增益值,å•ä½å€æ•° x 1024*/ ++ uint32_t AeShortIntegrationTime; /**< AE手动模å¼ä¸‹çš„æ›å…‰å€¼ */ ++ uint32_t AeShortAGain; /**< AE Sensor 模拟增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeShortDGain; /**< AE Sensor数字增益值,å•使˜¯å€æ•° x 1024 */ ++ uint32_t AeShortIspDGain; /**< AE ISP 数字增益值,å•ä½å€æ•° x 1024*/ ++ ++ uint32_t luma; /**< AE Luma值 */ ++ uint32_t luma_scence; /**< AE 场景Luma值 */ ++} tisp_ae_algo_attr_t; ++ ++typedef struct { ++ uint32_t version; ++ int vinum; ++ tisp_ae_algo_init_t AeInitAttr; ++} tisp_ae_algo_init_self_t; ++ ++typedef struct { ++ uint32_t version; ++ int vinum; ++ tisp_ae_algo_info_t Aeinfo; ++} __attribute__((packed, aligned(1))) tisp_ae_algo_info_self_t; ++ ++typedef struct { ++ uint32_t version; ++ int vinum; ++ tisp_ae_algo_attr_t AeAttr; ++} tisp_ae_algo_attr_self_t; ++ ++typedef enum { ++ IMPISP_AE_NOTIFY_FPS_CHANGE, ++} tisp_ae_algo_notify_t; ++ ++typedef struct { ++ void *priv_data; ++ int (*open)(void *priv_data, tisp_ae_algo_init_t AeInitAttr); ++ void (*close)(void *priv_data); ++ void (*handle)(void *priv_data, const tisp_ae_algo_info_t *AeInfo, tisp_ae_algo_attr_t *AeAttr); ++ int (*notify)(void *priv_data, tisp_ae_algo_notify_t notify, void* data); ++} tisp_ae_algo_func_t; ++ ++typedef struct { ++ tisp_awb_statis_attr_t AwbStatis; ++} tisp_awb_algo_init_t; ++ ++typedef struct { ++ uint32_t cur_r_gain; ++ uint32_t cur_b_gain; ++ uint32_t r_gain_statis; ++ uint32_t b_gain_statis; ++ uint32_t r_gain_wei_statis; ++ uint32_t b_gain_wei_statis; ++ tisp_wb_statis_info_t awb_statis; ++}__attribute__((packed, aligned(1))) tisp_awb_algo_info_t; ++ ++typedef struct { ++ uint32_t change; ++ uint32_t r_gain; ++ uint32_t b_gain; ++ uint32_t ct; ++} tisp_awb_algo_attr_t; ++ ++typedef enum { ++ IMPISP_AWB_NOTIFY_MODE_CHANGE, ++} tisp_awb_algo_notify_t; ++ ++typedef struct { ++ uint32_t version; ++ int vinum; ++ tisp_awb_algo_init_t AwbInitAttr; ++} tisp_awb_algo_init_self_t; ++ ++typedef struct { ++ uint32_t version; ++ int vinum; ++ tisp_awb_algo_info_t Awbinfo; ++} __attribute__((packed, aligned(1))) tisp_awb_algo_info_self_t; ++ ++typedef struct { ++ uint32_t version; ++ int vinum; ++ tisp_awb_algo_attr_t AwbAttr; ++} tisp_awb_algo_attr_self_t; ++ ++typedef struct { ++ void *priv_data; ++ int (*open)(void *priv_data, tisp_awb_algo_init_self_t *AwbInitAttr); ++ void (*close)(void *priv_data); ++ void (*handle)(void *priv_data, const tisp_awb_algo_info_self_t *AwbInfo, tisp_awb_algo_attr_self_t *AwbAttr); ++ int (*notify)(void *priv_data, tisp_awb_algo_notify_t notify, void *data); ++} tisp_awb_algo_func_t; ++ ++typedef struct { ++ char version[8]; ++ char rbpath[64]; ++ uint32_t dstatus; ++ uint32_t nstatus; ++} tisp_show_bin; ++ ++typedef struct { ++ unsigned char saturation[3]; ++ unsigned char contrast[3]; ++ unsigned char sharpness[3]; ++ unsigned char brightness[3]; ++ unsigned char hue[3]; ++ tisp_ae_exprinfo_t ae_info[3]; ++ tisp_ae_scence_attr_t ae_scence[3]; ++ tisp_module_ratio_t module_ratio[3]; ++ tisp_statis_config_t stattis_config[2]; ++ tisp_awb_attr_t awb_attr[3]; ++ tisp_ae_weight_t ae_weight[3]; ++ tisp_awb_custom_attr_t awb_custom[3]; ++ tisp_anfiflicker_attr_t flicker_attr[3]; ++ tisp_show_bin swbin[2]; ++} tisp_core_tuning_attr; ++ ++typedef struct { ++ TISP_OPS_MODE enable; ++ unsigned char bname[64]; ++} tisp_bin_t; ++ ++typedef struct { ++ TISP_OPS_MODE enable; ++ uint8_t lsize; ++ uint32_t fmark; ++} tisp_frame_drop_t; ++ ++typedef struct { ++ uint8_t vinum; ++ tisp_frame_drop_t fdrop[3]; ++} tisp_frame_drop_attr_t; ++ ++int tisp_enable_tuning(void); ++void tisp_disable_tuning(void); ++tisp_core_tuning_attr* tisp_get_tuning(void); ++ ++int32_t tisp_day_or_night_s_ctrl(int vinum, TISP_MODE_DN_E dn); ++TISP_MODE_DN_E tisp_day_or_night_g_ctrl(int vinum); ++int tisp_set_fps(int vinum, int fps); ++ ++int tisp_ae_face_get(int vinum, tisp_face_t *attr); ++int tisp_ae_face_set(int vinum, tisp_face_t *attr); ++int tisp_awb_face_get(int vinum, tisp_face_t *attr); ++int tisp_awb_face_set(int vinum, tisp_face_t *attr); ++void tisp_set_brightness(int vinum, unsigned char brightness); ++void tisp_set_sharpness(int vinum, unsigned char sharpness); ++void tisp_set_saturation(int vinum, unsigned char saturation); ++void tisp_set_contrast(int vinum, unsigned char contrast); ++int tisp_set_csc_attr(int vinum, tisp_csc_attr_t *attr); ++void tisp_get_csc_attr(int vinum, tisp_csc_attr_t *attr); ++int tisp_s_ccm_attr(int vinum, tisp_ccm_t *ccm_attr); ++int tisp_g_ccm_attr(int vinum, tisp_ccm_t *ccm_attr); ++int tisp_s_Gamma(int vinum, tisp_gamma_t *gammas); ++int tisp_g_Gamma(int vinum, tisp_gamma_t *gammag); ++void tisp_s_module_control(int vinum, tisp_module_control_t top); ++void tisp_g_module_control(int vinum, tisp_module_control_t *top); ++void tisp_set_bcsh_hue(int vinum, unsigned char hue); ++int tisp_s_antiflick(int vinum, tisp_anfiflicker_attr_t *attr); ++int tisp_g_antiflick(int vinum, tisp_anfiflicker_attr_t *attr); ++void tisp_hv_flip_enable(int vinum, unsigned char en); ++void tisp_hv_flip_get(unsigned char *en); ++int tisp_s_autozoom_control(int vinum, tisp_autozoom_attr_t *autozoom_attr); ++int tisp_g_autozoom_control(int vinum, tisp_autozoom_attr_t *autozoom_attr); ++int tisp_s_mscaler_mask_attr(int vinum, tisp_mask_attr_t *attr); ++int tisp_g_mscaler_mask_attr(int vinum, tisp_mask_attr_t *attr); ++int tisp_s_osd_attr(int vinum, tisp_osd_attr_t *attr); ++int tisp_g_osd_attr(int vinum, tisp_osd_attr_t *attr); ++int tisp_s_draw_attr(int vinum, tisp_draw_chx_attr_t *attr); ++int tisp_g_draw_attr(int vinum, tisp_draw_chx_attr_t *attr); ++int tisp_s_ae_scence_attr(int vinum, tisp_ae_scence_attr_t *attr); ++int tisp_g_ae_scence_attr(int vinum, tisp_ae_scence_attr_t *attr); ++int tisp_g_af_metric_attr(int vinum, tisp_af_metric_info_t *metrics); ++int tisp_g_ae_exprinfo_attr(int vinum, tisp_ae_exprinfo_t *attr); ++ ++int tisp_s_wdr_en(int vinum, int enable); ++int tisp_g_wdr_en(int *enable); ++void wdr_init_mine(void); ++int tisp_s_af_weight_attr(int vinum, tisp_3a_weight_t *attr); ++int tisp_g_af_weight_attr(int vinum, tisp_3a_weight_t *attr); ++int tisp_s_awb_weight_attr(int vinum, tisp_3a_weight_t *attr); ++int tisp_g_awb_weight_attr(int vinum, tisp_3a_weight_t *attr); ++int tisp_g_awb_attr(int vinum, tisp_awb_attr_t *attr); ++int tisp_s_awb_attr(int vinum, tisp_awb_attr_t *attr); ++int tisp_g_awb_statis_attr(int vinum, tisp_wb_statis_info_t *attr); ++int tisp_g_awb_global_statis_attr(int vinum, tisp_awb_global_statics_t *attr); ++int tisp_s_ae_exprinfo_attr(int vinum, tisp_ae_exprinfo_t *attr); ++int tisp_g_ae_statis_attr(int vinum, tisp_ae_statis_info_t *attr); ++int tisp_g_af_statis_attr(int vinum, tisp_af_statis_info_t *attr); ++int tisp_s_ae_weight_attr(int vinum, tisp_ae_weight_t *attr); ++int tisp_g_ae_weight_attr(int vinum, tisp_ae_weight_t *attr); ++int tisp_s_statis_config_attr(int vinum, tisp_statis_config_t *attr); ++int tisp_g_statis_config_attr(int vinum, tisp_statis_config_t *attr); ++int tisp_s_module_ratio_attr(int vinum, tisp_module_ratio_t *attr); ++int tisp_g_module_ratio_attr(int vinum, tisp_module_ratio_t *attr); ++int tisp_switch_bin(int vinum, tisp_bin_t *attr); ++int tisp_core_switch_bin(int num, tisp_bin_t *attr); ++void tisp_msca_Shd_ctrl(int vinum, int omd_index); ++uint32_t tisp_msca_state(void); ++void tisp_ae_algo_handle(int vinum, tisp_ae_algo_attr_self_t *ae_attr); ++void tisp_ae_algo_init(int vinum, int enable, tisp_ae_algo_init_self_t *ae_init); ++void tisp_awb_algo_handle(int vinum, tisp_awb_algo_attr_self_t *awb_attr); ++void tisp_awb_algo_init(int vinum, int enable, tisp_awb_algo_init_self_t *awb_init); ++int tisp_get_antiflicker_step(int vinum, uint16_t *gdeflick_lut, uint16_t *gnodes); ++void tisp_get_ae_tgain(int vinum, unsigned int *tgain); ++void tisp_ae_algo_deinit(int vinum); ++void tisp_awb_algo_deinit(int vinum); ++int32_t tisp_set_wdr_output_mode(int vinum, tisp_wdr_output_mode_t *mode); ++int32_t tisp_get_wdr_output_mode(int vinum, tisp_wdr_output_mode_t *mode); ++int32_t tisp_set_frame_drop(int vinum, int chx, tisp_frame_drop_t *tfd); ++int32_t tisp_get_frame_drop(int vinum, int chx, tisp_frame_drop_t *tfd); ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano-isp.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano-isp.h +new file mode 100644 +index 000000000..79ebf4315 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano-isp.h +@@ -0,0 +1,257 @@ ++#ifndef __TIZIANO_ISP_H__ ++#define __TIZIANO_ISP_H__ ++ ++#include ++ ++typedef enum { ++ TISP_OPS_MODE_DISABLE, /**< DISABLE mode of the current module */ ++ TISP_OPS_MODE_ENABLE, /**< ENABLE mode of the current module */ ++ TISP_OPS_MODE_BUTT, /**< effect paramater, parameters have to be less than this value*/ ++} TISP_OPS_MODE; ++ ++/** ++ * ISP Function Mode ++ */ ++typedef enum { ++ TISP_OPS_TYPE_AUTO, /**< AUTO mode of the current module*/ ++ TISP_OPS_TYPE_MANUAL, /**< MANUAL mode of the current module*/ ++ TISP_OPS_TYPE_BUTT, /**< effect paramater, parameters have to be less than this value*/ ++} TISP_OPS_TYPE; ++ ++typedef struct { ++ unsigned int max_again; //the format is .16 ++ unsigned int max_dgain; //the format is .16 ++ unsigned int again; ++ unsigned int dgain; ++ unsigned int fps; ++ unsigned short min_integration_time; ++ unsigned short min_integration_time_native; ++ unsigned short max_integration_time_native; ++ unsigned short integration_time_limit; ++ unsigned int integration_time; ++ unsigned short total_width; ++ unsigned short total_height; ++ unsigned short max_integration_time; ++ unsigned short integration_time_apply_delay; ++ unsigned short again_apply_delay; ++ unsigned short dgain_apply_delay; ++ unsigned short one_line_expr_in_us; ++ unsigned short min_integration_time_short; ++ unsigned short max_integration_time_short; ++ unsigned int integration_time_short; ++ unsigned int max_again_short; //the format is .16 ++ unsigned int again_short; ++ unsigned int max_dgain_short; //the format is .16 ++ unsigned int dgain_short; ++ unsigned short again_short_apply_delay; ++ unsigned short dgain_short_apply_delay; ++ unsigned short integration_time_short_apply_delay; ++} sensor_info_t; ++ ++typedef enum { ++ IMPISP_DUALSENSOR_SIGLE_BYPASS_MODE = 0, ++ IMPISP_DUALSENSOR_DUAL_DIRECT_MODE, ++ IMPISP_DUALSENSOR_DUAL_SELECT_MODE, ++ IMPISP_DUALSENSOR_DUAL_SINGLECACHED_MODE, ++ IMPISP_DUALSENSOR_DUAL_ALLCACHED_MODE, ++ IMPISP_DUALSENSOR_MODE_BUTT, ++} dual_sensor_mode_t; ++ ++typedef struct { ++ TISP_OPS_MODE en; ++ uint32_t switch_con; ++ uint32_t switch_con_num; ++} tisp_dual_sensor_switch_t; ++ ++typedef enum { ++ IMPISP_TOTAL_ONE = 1, ++ IMPISP_TOTAL_TWO, ++ IMPISP_TOTAL_THR, ++ IMPISP_TOTAL_BUTT, ++} sensor_num_t; ++ ++ ++typedef enum{ ++ IMPISP_NOT_JOINT = 0, ++ IMPISP_MAIN_ON_THE_LEFT, ++ IMPISP_MAIN_ON_THE_RIGHT, ++ IMPISP_MAIN_ON_THE_ABOVE, ++ IMPISP_MAIN_ON_THE_UNDER, ++ IMPISP_MIAN_JOINT_BUTT, ++} dual_sensor_split_joint; ++ ++typedef struct { ++ sensor_num_t sensor_num; ++ dual_sensor_mode_t dual_mode; ++ tisp_dual_sensor_switch_t dual_mode_switch; ++ dual_sensor_split_joint joint_mode; ++} multisensor_mode_t; ++ ++typedef struct { ++ int width; ++ int height; ++ int bayer; ++ char sensor[16]; ++ sensor_info_t sensor_info; ++ int WdrEn; ++ int DNMode; ++ int sensorId; //the sensor id:mark the struct for sensor 0/1 ++ multisensor_mode_t multi_mode; ++} tisp_init_param_t; ++ ++typedef struct { ++ tisp_init_param_t sensor[3]; ++ multisensor_mode_t multi_mode; ++} tisp_init_par_t; ++ ++typedef struct { ++ int scaler_en; ++ int scaler_width; ++ int scaler_height; ++ int crop_en; ++ int crop_x; ++ int crop_y; ++ int crop_width; ++ int crop_height; ++ int fcrop_en; ++ int fcrop_x; ++ int fcrop_y; ++ int fcrop_width; ++ int fcrop_height; ++} tisp_channel_attr_t; ++ ++//ae ++typedef struct { ++ uint32_t tisp_ae_manual; ++ uint32_t tisp_ae_sensor_again; ++ uint32_t tisp_ae_sensor_dgain; ++ uint32_t tisp_ae_sensor_integration_time; ++ uint32_t tisp_ae_isp_dgian; ++ uint32_t tisp_ae_max_sensor_again; ++ uint32_t tisp_ae_max_sensor_dgain; ++ uint32_t tisp_ae_max_sensor_integration_time; ++ uint32_t tisp_ae_max_isp_dgain; ++ uint32_t tisp_ae_ev; ++ uint32_t tisp_ae_tgain_db; ++ uint32_t tisp_ae_again_db; ++ uint32_t tisp_ae_ir; ++ uint32_t tisp_ae_it_manual; ++ uint32_t tisp_ae_ag_manual; ++ uint32_t tisp_ae_dg_manual; ++ uint32_t tisp_ae_it_short_manual; ++ uint32_t tisp_ae_ag_short_manual; ++ uint32_t tisp_ae_sensor_again_short; ++ uint32_t tisp_ae_sensor_integration_time_short; ++ uint32_t tisp_ae_max_sensor_again_short; ++ uint32_t tisp_ae_max_sensor_integration_time_short; ++ uint32_t tisp_ae_max_sensor_dgain_short; ++ uint32_t tisp_ae_max_isp_dgain_short; ++ uint32_t tisp_ae_manual_short; ++ uint32_t tisp_ae_sensor_dgain_short; ++ uint32_t tisp_ae_dg_manual_short; ++ uint32_t tisp_ae_isp_dgian_short; ++ uint32_t tisp_ae_min_sensor_again; ++ uint32_t tisp_ae_min_sensor_dgain; ++ uint32_t tisp_ae_min_sensor_integration_time; ++ uint32_t tisp_ae_min_isp_dgain; ++ uint32_t tisp_ae_min_sensor_again_short; ++ uint32_t tisp_ae_min_sensor_integration_time_short; ++ uint32_t tisp_ae_min_sensor_dgain_short; ++ uint32_t tisp_ae_min_isp_dgain_short; ++ uint32_t tisp_ae_sensor_dg_manual; ++ uint32_t tisp_ae_sensor_dg_short_manual; ++ uint32_t tisp_ae_ev_short; ++ uint32_t tisp_ae_tgain_db_short; ++ uint32_t tisp_ae_again_db_short; ++} tisp_ae_ctrls_t; ++ ++typedef struct { ++ uint32_t tisp_wb_manual; ++ uint32_t tisp_wb_rg; ++ uint32_t tisp_wb_bg; ++ uint32_t tisp_wb_rg_sta_global; ++ uint32_t tisp_wb_bg_sta_global; ++ uint32_t tisp_wb_rg_sta_weight; ++ uint32_t tisp_wb_bg_sta_weight; ++} tisp_wb_attr_t; ++ ++typedef struct { ++ uint32_t ae_hist[256]; ++ uint32_t ae_hist_5bin[5]; ++ uint32_t ae_hist_nodes[4]; ++ uint8_t ae_hist_hv[2]; ++} tisp_ae_sta_t; ++ ++typedef struct { ++ unsigned int af_metrics; ++ unsigned int af_metrics_alt; ++ unsigned char af_enable; ++ unsigned char af_metrics_shift; ++ unsigned short af_delta; ++ unsigned short af_theta; ++ unsigned short af_hilight_th; ++ unsigned short af_alpha_alt; ++ unsigned char af_hstart; ++ unsigned char af_vstart; ++ unsigned char af_stat_nodeh; ++ unsigned char af_stat_nodev; ++ unsigned short af_belta_alt; ++} tisp_af_attr; ++ ++typedef struct { ++ int vinum; ++ char path[64]; ++} tx_isp_bin_path; ++ ++extern struct completion ae_algo_comp[2]; ++extern struct completion ae_algo_close_comp[2]; ++extern struct completion awb_algo_comp[2]; ++extern struct completion awb_algo_close_comp[2]; ++extern tisp_ae_ctrls_t tisp_ae_main_ctrls; ++extern tisp_ae_ctrls_t tisp_ae_sec_ctrls; ++extern tisp_init_par_t tisp_par_info; ++extern int main_day_night_switch; ++extern int event_busy; ++ ++int tisp_main_init(tisp_init_param_t *p, char *bpath); ++int tisp_sec_init(tisp_init_param_t *p, char *bpath); ++void tisp_ipc_triger(void); ++int tisp_deinit(int vinum); ++void tisp_stream_on(tisp_init_param_t *p); ++void tisp_process_init(void); ++void tisp_process_deinit(int vinum); ++void tisp_slake_all(void); ++void tisp_activate_all(void); ++ ++int tisp_channel_main_start(int chx); ++int tisp_channel_sec_start(int chx); ++int tisp_channel_main_stop(int chx); ++int tisp_channel_sec_stop(int chx); ++int tisp_channel_main_fifo_clear(int chx); ++int tisp_channel_sec_fifo_clear(int chx); ++int tisp_channel_main_attr_set(int chx ,tisp_channel_attr_t * cattr); ++int tisp_channel_sec_attr_set(int chx ,tisp_channel_attr_t * cattr); ++ ++int tisp_fw_process(int vinum); ++int tiziano_sync_sensor_attr(tisp_init_param_t *sensor_attr); ++ ++void Tzn_Msca_addr_fifo_write(uint8_t sensor_num/*{{{*/ ++ ,uint8_t channel ++ ,uint32_t phy_y_addr ++ ,uint32_t phy_c_addr ++ );/*}}}*/ ++ ++void Tzn_Msca_addr_fifo_read(uint8_t sensor_num/*{{{*/ ++ ,uint8_t channel ++ ,uint32_t * phy_y_addr ++ ,uint32_t * phy_c_addr ++ );/*}}}*/ ++ ++uint8_t Tzn_Msca_addr_fifo_have_read(uint8_t sensor_num/*{{{*/ ++ ,uint8_t channel ++ );/*}}}*/ ++ ++void tisp_hardware_reg_refresh(int vinum); ++void tisp_lce_get_debug(unsigned int *deinfo); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano_sys.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano_sys.h +new file mode 100644 +index 000000000..fddd7e027 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/tiziano_sys.h +@@ -0,0 +1,11 @@ ++#ifndef __TIZIANO_SYS_H__ ++#define __TIZIANO_SYS_H__ ++ ++extern int system_reg_write(unsigned int reg, unsigned int value); ++extern unsigned int system_reg_read(unsigned int reg); ++extern int system_lock(void); ++extern int system_unlock(void); ++extern int system_irq_func_main_set(int irq, void *func); ++extern int system_irq_func_sec_set(int irq, void *func); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/txx-funcs.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/txx-funcs.h +new file mode 100644 +index 000000000..0cc04ccbe +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-core/inc/txx-funcs.h +@@ -0,0 +1,222 @@ ++#ifndef __TXX_DRV_FUNCS_H__ ++#define __TXX_DRV_FUNCS_H__ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++/*#include */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++// #include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++// #include ++/*#include */ ++#include ++ ++#ifndef U16_MAX ++#define U16_MAX 0xFFFF ++#endif ++ ++#define ISP_INFO_LEVEL 0x0 ++#define ISP_WARNING_LEVEL 0x1 ++#define ISP_ERROR_LEVEL 0x2 ++#define ISP_PRINT(level, format, ...) \ ++ isp_printf(level, format, ##__VA_ARGS__) ++#define ISP_INFO(...) ISP_PRINT(ISP_INFO_LEVEL, __VA_ARGS__) ++#define ISP_WARNING(...) ISP_PRINT(ISP_WARNING_LEVEL, __VA_ARGS__) ++#define ISP_ERROR(...) ISP_PRINT(ISP_ERROR_LEVEL, __VA_ARGS__) ++ ++//extern unsigned int isp_print_level; ++/*int isp_debug_init(void);*/ ++/*int isp_debug_deinit(void);*/ ++int isp_printf(unsigned int level, unsigned char *fmt, ...); ++int get_isp_clk(void); ++void *private_vmalloc(unsigned long size); ++void private_vfree(const void *addr); ++ ++#define paddr2vaddr(phyaddr) ((void *)((phyaddr) + PAGE_OFFSET - PHYS_OFFSET)) ++ ++uint8_t private_leading_one_position(const uint32_t in); ++uint32_t private_log2_int_to_fixed(const uint32_t val, const uint8_t out_precision, const uint8_t shift_out); ++uint32_t private_log2_fixed_to_fixed(const uint32_t val, const int in_fix_point, const uint8_t out_fix_point); ++int32_t private_log2_fixed_to_fixed_64(uint64_t val, int32_t in_fix_point, uint8_t out_fix_point); ++uint32_t private_math_exp2(uint32_t val, const unsigned char shift_in, const unsigned char shift_out); ++ ++/* platform interfaces */ ++int private_platform_driver_register(struct platform_driver *drv); ++void private_platform_driver_unregister(struct platform_driver *drv); ++void private_platform_set_drvdata(struct platform_device *pdev, void *data); ++void *private_platform_get_drvdata(struct platform_device *pdev); ++int private_platform_device_register(struct platform_device *pdev); ++void private_platform_device_unregister(struct platform_device *pdev); ++struct resource *private_platform_get_resource(struct platform_device *dev, ++ unsigned int type, unsigned int num); ++void private_dev_set_drvdata(struct device *dev, void *data); ++void* private_dev_get_drvdata(const struct device *dev); ++int private_platform_get_irq(struct platform_device *dev, unsigned int num); ++struct resource * private_request_mem_region(resource_size_t start, resource_size_t n, ++ const char *name); ++void private_release_mem_region(resource_size_t start, resource_size_t n); ++ ++void __iomem * private_ioremap(phys_addr_t offset, unsigned long size); ++void private_iounmap(const volatile void __iomem *addr); ++/* interrupt interfaces */ ++int private_request_threaded_irq(unsigned int irq, irq_handler_t handler, ++ irq_handler_t thread_fn, unsigned long irqflags, ++ const char *devname, void *dev_id); ++void private_enable_irq(unsigned int irq); ++void private_disable_irq(unsigned int irq); ++void private_free_irq(unsigned int irq, void *dev_id); ++ ++/* lock and mutex interfaces */ ++void __private_spin_lock_irqsave(spinlock_t *lock, unsigned long *flags); ++#define private_spin_lock_irqsave(lock, flags) \ ++ __private_spin_lock_irqsave(lock, (&flags)); ++void private_spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags); ++void private_spin_lock_init(spinlock_t *lock); ++void private_mutex_lock(struct mutex *lock); ++void private_mutex_unlock(struct mutex *lock); ++void private_raw_mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key); ++ ++#define private_mutex_init(mutex) \ ++ do { \ ++ static struct lock_class_key __key; \ ++ \ ++ private_raw_mutex_init((mutex), #mutex, &__key); \ ++} while (0) ++ ++/* clock interfaces */ ++struct clk * private_clk_get(struct device *dev, const char *id); ++int private_clk_enable(struct clk *clk); ++void private_clk_disable(struct clk *clk); ++unsigned long private_clk_get_rate(struct clk *clk); ++void private_clk_put(struct clk *clk); ++int private_clk_set_rate(struct clk *clk, unsigned long rate); ++ ++struct clk *private_devm_clk_get(struct device *dev, const char *id); ++int private_clk_prepare_enable(struct clk *clk); ++void private_clk_disable_unprepare(struct clk *clk); ++void private_devm_clk_put(struct device *dev, struct clk *clk); ++ ++/* i2c interfaces */ ++struct i2c_adapter* private_i2c_get_adapter(int nr); ++void private_i2c_put_adapter(struct i2c_adapter *adap); ++int private_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); ++int private_i2c_register_driver(struct module *, struct i2c_driver *); ++void private_i2c_del_driver(struct i2c_driver *drv); ++struct i2c_client *private_i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info); ++void private_i2c_set_clientdata(struct i2c_client *dev, void *data); ++void *private_i2c_get_clientdata(const struct i2c_client *dev); ++int private_i2c_add_driver(struct i2c_driver *drv); ++void private_i2c_unregister_device(struct i2c_client *client); ++ ++/* gpio interfaces */ ++int private_gpio_request(unsigned gpio, const char *label); ++void private_gpio_free(unsigned gpio); ++int private_gpio_direction_output(unsigned gpio, int value); ++int private_gpio_direction_input(unsigned gpio); ++int private_gpio_set_debounce(unsigned gpio, unsigned debounce); ++int private_jzgpio_set_func(enum gpio_port port, enum gpio_function func,unsigned long pins); ++// int private_jzgpio_ctrl_pull(enum gpio_port port, int enable_pull,unsigned long pins); ++ ++/* system interfaces */ ++void private_msleep(unsigned int msecs); ++bool private_capable(int cap); ++unsigned long long private_sched_clock(void); ++bool private_try_module_get(struct module *module); ++int private_request_module(bool wait, const char *fmt, ...); ++void private_module_put(struct module *module); ++ ++/* wait interfaces */ ++void private_init_completion(struct completion *x); ++void private_complete(struct completion *x); ++int private_wait_for_completion_interruptible(struct completion *x); ++unsigned long private_wait_for_completion_timeout(struct completion *x, unsigned long timeover); ++int private_wait_event_interruptible(wait_queue_head_t *q, int (*state)(void *), void *data); ++void private_wake_up_all(wait_queue_head_t *q); ++void private_wake_up(wait_queue_head_t *q); ++void private_init_waitqueue_head(wait_queue_head_t *q); ++ ++/* misc driver interfaces */ ++int private_misc_register(struct miscdevice *mdev); ++void private_misc_deregister(struct miscdevice *mdev); ++ ++struct proc_dir_entry *private_proc_create_data(const char *name, umode_t mode, struct proc_dir_entry *parent,const struct proc_ops *proc_ops, void *data); ++/* proc file interfaces */ ++ssize_t private_seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos); ++loff_t private_seq_lseek(struct file *file, loff_t offset, int whence); ++int private_single_release(struct inode *inode, struct file *file); ++int private_single_open_size(struct file *file, int (*show)(struct seq_file *, void *), ++ void *data, size_t size); ++struct proc_dir_entry* private_jz_proc_mkdir(char *s); ++void private_proc_remove(struct proc_dir_entry *de); ++void private_seq_printf(struct seq_file *m, const char *f, ...); ++unsigned long long private_simple_strtoull(const char *cp, char **endp, unsigned int base); ++ ++/* kthread interfaces */ ++bool private_kthread_should_stop(void); ++struct task_struct* private_kthread_run(int (*threadfn)(void *data), void *data, const char namefmt[]); ++int private_kthread_stop(struct task_struct *k); ++ ++void* private_kmalloc(size_t s, gfp_t gfp); ++void private_kfree(void *p); ++long private_copy_from_user(void *to, const void __user *from, long size); ++long private_copy_to_user(void __user *to, const void *from, long size); ++ ++/* netlink */ ++struct sk_buff* private_nlmsg_new(size_t payload, gfp_t flags); ++struct nlmsghdr *private_nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, ++ int type, int payload, int flags); ++int private_netlink_unicast(struct sock *ssk, struct sk_buff *skb, ++ u32 portid, int nonblock); ++struct sock *private_netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg); ++void private_sock_release(struct socket *sock); ++ ++/* file ops */ ++struct file *private_filp_open(const char *filename, int flags, umode_t mode); ++int private_filp_close(struct file *filp, fl_owner_t id); ++ssize_t private_vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos); ++ssize_t private_vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos); ++loff_t private_vfs_llseek(struct file *file, loff_t offset, int whence); ++mm_segment_t private_get_fs(void); ++void private_set_fs(mm_segment_t val); ++void private_dma_cache_sync(struct device *dev, void *vaddr, size_t size, ++ enum dma_data_direction direction); ++void private_getrawmonotonic(struct timespec64 *ts); ++struct net *private_get_init_net(void); ++ ++/* isp driver interface */ ++void private_get_isp_priv_mem(unsigned int *phyaddr, unsigned int *size); ++ ++/* int private_driver_get_interface(void); */ ++ ++#endif /*__TXX_DRV_FUNCS_H__*/ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-drv.c b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-drv.c +new file mode 100644 +index 000000000..59e97dcb0 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-drv.c +@@ -0,0 +1,451 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++ ++ ++static const struct of_device_id ingenic_isp_dt_match[]; ++ ++static int ingenic_isp_parse_dt(struct ispcam_device * ispcam) ++{ ++ struct device *dev = ispcam->dev; ++ struct device_node *node = NULL; ++ struct v4l2_async_notifier *notifier = &ispcam->notifier; ++ struct platform_device *pdev = NULL; ++ struct v4l2_async_subdev *asd = NULL; ++ const char *compatible = NULL; ++ unsigned int cplen = 0; ++ int ret = 0; ++ ++ ++ for_each_child_of_node(dev->of_node, node) { ++ compatible = of_get_property(node, "compatible", &cplen); ++ ++ if(!compatible && (cplen == 0)) { ++ continue; ++ } ++ if(!of_device_is_available(node)) { ++ continue; ++ } ++ pdev = of_platform_device_create(node, NULL,dev); ++ if(!pdev) { ++ printk("failed to populate_platform_device, node->full_name"); ++ } ++ ++ ispcam->subdevs[ispcam->subdev_num++] = pdev; ++ if(ispcam->subdev_num > MAX_SUB_DEVS) { ++ printk("too many sub platform devices!\n"); ++ return -EINVAL; ++ } ++ } ++ ++ ++ printk("start parse remote-endpoint!\n"); ++ asd = devm_kzalloc(dev, MAX_ASYNC_SUBDEVS * sizeof(*notifier->sd->asd), GFP_KERNEL); ++ ++ /* è§£æžendpoint, 远程端点,建立关系, åœ¨ä¸‹é¢æ³¨å†Œå›žè°ƒï¼Œç­‰æ³¨å†Œå®Œæˆé€šçŸ¥.创建video_device.*/ ++ ++ while( ++ (node = of_graph_get_next_endpoint(dev->of_node, node))) { ++ ispcam->isd[ispcam->asd_num].asd = *asd; ++ ispcam->isd[ispcam->asd_num].index = ispcam->asd_num; ++ ++ /*TODO: 构建与vep对应的数æ®ç»“构,存储从dts中传入的数æ®.*/ ++ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &ispcam->vep[ispcam->asd_num]); ++ if(ret < 0) { ++ of_node_put(node); ++ return -EINVAL; ++ } ++ ispcam->isd[ispcam->asd_num].bus_type = ispcam->vep[ispcam->asd_num].bus_type; ++ ispcam->isd[ispcam->asd_num].parallel = ispcam->vep[ispcam->asd_num].bus.parallel; ++ ispcam->isd[ispcam->asd_num].mipi_csi2 = ispcam->vep[ispcam->asd_num].bus.mipi_csi2; ++ ++ ++ asd->match.fwnode = fwnode_graph_get_remote_port_parent(of_fwnode_handle(node)); ++ asd->match_type = V4L2_ASYNC_MATCH_FWNODE; ++ ++ of_node_put(node); ++ ++ v4l2_async_notifier_init(&ispcam->notifier); ++ ++ ret = v4l2_async_notifier_add_subdev(&ispcam->notifier, asd); ++ if (ret) { ++ fwnode_handle_put(asd->match.fwnode); ++ return ret; ++ } ++ ++ fwnode_handle_put(asd->match.fwnode); ++ ispcam->asd_num ++; ++ } ++ ++#if 0 ++ ++ printk("dump subdevs ------------ pdevs:\n"); ++ for(i = 0; i < ispcam->subdev_num; i++) { ++ printk("---sudev: %d, name: %s\n", i, ispcam->subdevs[i]->name); ++ } ++ ++ printk("dump async subdevs!\n"); ++ /*dump of parse subdevs.*/ ++ for(i = 0; i < ispcam->asd_num; i++) { ++ asd = &ispcam->isd[i].asd; ++ printk("asd: %d, asd->match.of.node->full_name: %s\n", i, asd->match.fwnode->dev->of_node->full_name); ++ } ++ ++#endif ++ return ret; ++} ++ ++static int ispcam_asd_notifier_bound(struct v4l2_async_notifier *async, ++ struct v4l2_subdev *subdev, ++ struct v4l2_async_subdev *asd) ++{ ++ struct ispcam_device *ispcam = container_of(async, struct ispcam_device, ++ notifier); ++ struct isp_async_device *isd = &ispcam->isd[0]; ++ ++ struct media_entity *entity = &subdev->entity; /*SOURCE_PAD*/ ++ int i = 0; ++ int ret = 0; ++ ++ if(entity->num_pads == 0) { ++ dev_err(ispcam->dev, "%s, %d No pad found in async entity(%s)\n", __func__, __LINE__, subdev->name); ++ return -EINVAL; ++ } ++ ++ for(i = 0; i < entity->num_pads; i++) { ++ if(entity->pads[i].flags & MEDIA_PAD_FL_SOURCE) ++ break; ++ } ++ ++ ++ if(i == entity->num_pads) { ++ dev_err(ispcam->dev, "%s, %d, no source pad in async entity (%s)\n", __func__, __LINE__, subdev->name); ++ return -EINVAL; ++ } ++ ++ isd->source_pad = i; ++ ++ isd->sd = subdev; ++ /*TODO: pass common args from isp host to sensor driver.*/ ++ isd->sd->host_priv = NULL; ++ ++ ++ ret = sensor_device_probe(&ispcam->sensor, ispcam); ++ if(ret < 0) { ++ /*TODO*/ ++ } ++ ++ dev_info(ispcam->dev, "%s, %d\n", __func__, __LINE__); ++ ++ return 0; ++} ++ ++static int ispcam_asd_notifier_complete(struct v4l2_async_notifier *async) ++{ ++ struct ispcam_device *ispcam = container_of(async, struct ispcam_device, ++ notifier); ++ ++ int ret = 0; ++ struct media_entity *input = NULL; /*SINK PAD*/ ++ unsigned int flags = 0; ++ unsigned int pad = 0; ++ struct isp_async_device *isd = &ispcam->isd[0]; ++ ++ dev_info(ispcam->dev, "%s, %d\n", __func__, __LINE__); ++ /*1. 绑定所有的å­component,ç¡®ä¿æ‰€æœ‰çš„å­çš„硬件设备在线, å­è®¾å¤‡ä¼šåœ¨é‡Œé¢è¿›è¡Œsubdevçš„åˆå§‹åŒ–和注册等æ“作.*/ ++ ret = component_bind_all(ispcam->dev, ispcam); ++ if(ret < 0) { ++ goto err_component_bind_all; ++ } ++ ++ /*CSI <-> VIC*/ ++ ++ /*VIC <-> ISP*/ ++ //printk("creating link vic to isp\n"); ++ if(ispcam->vic && ispcam->isp) ++ ret = media_create_pad_link( ++ &ispcam->vic->sd.entity, VIC_PAD_SOURCE, ++ &ispcam->isp->sd.entity, ISP_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ ++#ifdef CONFIG_VIC_DMA_ROUTE ++ /*VIC <-> Memory*/ ++ if(ispcam->vic) ++ ret = media_create_pad_link( ++ &ispcam->vic->sd.entity, VIC_PAD_SOURCE, ++ &ispcam->vic->ispvideo.video.entity, ISP_VIDEO_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++#endif ++ ++ /*ISP <-> MSCALER*/ ++ //printk("creating link isp to mscaler\n"); ++ if(ispcam->isp && ispcam->mscaler) ++ ret = media_create_pad_link( ++ &ispcam->isp->sd.entity, ISP_PAD_SOURCE, ++ &ispcam->mscaler->sd.entity, MSCALER_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ ++ /*Sensor -> 0]CSI[1 -> 0]VIC[1 -> 0]ISP[1 -> 0]Mscaler[1 -> ]Memory*/ ++ //printk("creating link from mscaler to isp-video\n"); ++ if(ispcam->mscaler) { ++ ret = media_create_pad_link( ++ &ispcam->mscaler->sd.entity, MSCALER_PAD_SOURCE_CH0, ++ &ispcam->mscaler->ispvideo[0].video.entity, ISP_VIDEO_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ ++ /*CH1*/ ++ if(MSCALER_MAX_CH > 1) { ++ ret = media_create_pad_link( ++ &ispcam->mscaler->sd.entity, MSCALER_PAD_SOURCE_CH1, ++ &ispcam->mscaler->ispvideo[1].video.entity, ISP_VIDEO_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ } ++ /*CH2*/ ++ if(MSCALER_MAX_CH > 2) { ++ ret = media_create_pad_link( ++ &ispcam->mscaler->sd.entity, MSCALER_PAD_SOURCE_CH2, ++ &ispcam->mscaler->ispvideo[2].video.entity, ISP_VIDEO_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ } ++ } ++ if(isd->bus_type == V4L2_MBUS_CSI2_DPHY) { ++ dev_info(ispcam->dev, "creating link csi to vic\n"); ++ if(!ispcam->csi) { ++ dev_err(ispcam->dev, "*** Error: MIPI Sensor Found while CSI not enabled in dts ***\n"); ++ return -EINVAL; ++ } ++ /*1. connect csi to vic.*/ ++ if(ispcam->csi && ispcam->vic) ++ ret = media_create_pad_link( ++ &ispcam->csi->sd.entity, CSI_PAD_SOURCE, ++ &ispcam->vic->sd.entity, VIC_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ /*connect to csi pad*/ ++ input = &ispcam->csi->sd.entity; ++ flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; ++ pad = CSI_PAD_SINK; ++ } else if(isd->bus_type == V4L2_MBUS_PARALLEL) { ++ dev_info(ispcam->dev, "creating link dvp to vic.\n"); ++ /*connect to vic dvp port.*/ ++ input = &ispcam->vic->sd.entity; ++ pad = VIC_PAD_SINK; ++ flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; ++ ++ } else { ++ dev_err(ispcam->dev, "Unsupported v4l2 mbus type.\n"); ++ return -EINVAL; ++ } ++ /* connect sensor to csi or vic. */ ++ ret = media_create_pad_link(&isd->sd->entity, isd->source_pad, ++ input, pad, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ if(ret < 0) { ++ dev_err(ispcam->dev, "%s, %d, failed to create link from [%s] to [%s]\n", ++ __func__, __LINE__, isd->sd->entity.name, input->name); ++ return -EINVAL; ++ } ++ ++ /* Expose all subdev's nodes*/ ++ ret = v4l2_device_register_subdev_nodes(&ispcam->v4l2_dev); ++ if (ret) { ++ dev_err(ispcam->mdev.dev, ++ "vimc subdev nodes registration failed (err=%d)\n", ++ ret); ++ goto err_register_subdev_nodes; ++ } ++ ++ return 0; ++err_register_subdev_nodes: ++err_component_bind_all: ++ return ret; ++} ++ ++ ++ ++static int ispcam_comp_bind(struct device *master) ++{ ++ struct ispcam_device *ispcam = platform_get_drvdata(to_platform_device(master)); ++ int ret = 0; ++ struct v4l2_async_notifier_operations ops = { ++ .bound = ispcam_asd_notifier_bound, ++ .complete = ispcam_asd_notifier_complete, ++ }; ++ dev_info(master, "master component bind.!\n"); ++ media_device_init(&ispcam->mdev); ++ ++ /* Register the v4l2 struct */ ++ ret = v4l2_device_register(ispcam->mdev.dev, &ispcam->v4l2_dev); ++ if (ret) { ++ dev_err(ispcam->mdev.dev, ++ "v4l2 device register failed (err=%d)\n", ret); ++ return ret; ++ } ++ ++ ret = media_device_register(&ispcam->mdev); ++ if(ret < 0) { ++ dev_err(ispcam->mdev.dev, "media device register failed\n"); ++ goto err_media_device_register; ++ } ++ ++ ++ ++ ++ /*3. 注册异步设备完æˆé€šçŸ¥,ç¡®ä¿æ‰€æœ‰çš„sensor在线.在完æˆé€šçŸ¥é‡Œé¢è¿›è¡Œmedia_deviceå’Œlink的创建.*/ ++ ispcam->notifier.ops = &ops; ++ ret = v4l2_async_notifier_register(&ispcam->v4l2_dev, &ispcam->notifier); ++ if(ret < 0) { ++ goto err_v4l2_async_notifier_register; ++ } ++ ++ ++ return 0; ++err_v4l2_async_notifier_register: ++err_media_device_register: ++ return ret; ++} ++ ++static void ispcam_comp_unbind(struct device *master) ++{ ++ struct ispcam_device *ispcam = platform_get_drvdata(to_platform_device(master)); ++ ++ dev_info(master, "TODO: %p master component unbind!\n", ispcam); ++ ++} ++ ++ ++static const struct component_master_ops ispcam_comp_ops = { ++ .bind = ispcam_comp_bind, ++ .unbind = ispcam_comp_unbind, ++}; ++ ++ ++static int comp_compare(struct device *comp, void *data) ++{ ++ return comp == data; ++} ++ ++static int ingenic_isp_probe(struct platform_device *pdev) ++{ ++ ++ struct ispcam_device *ispcam = NULL; ++ struct component_match *match = NULL; ++ const struct of_device_id *of_match; ++ struct ispcam_data *data = NULL; ++ int ret; ++ int i; ++ char *dev_nr = NULL; ++ ++ ispcam = kzalloc(sizeof(struct ispcam_device), GFP_KERNEL); ++ if(!ispcam) { ++ pr_err("Failed to alloc ispcam dev [%s]\n", pdev->name); ++ return -ENOMEM; ++ } ++ ++ ispcam->dev = &pdev->dev; ++ platform_set_drvdata(pdev, ispcam); ++ ++ of_match = of_match_node(ingenic_isp_dt_match, pdev->dev.of_node); ++ if (!of_match){ ++ return -ENODEV; ++ } ++ ++ data = (struct ispcam_data *)of_match->data; ++ if(data->chip_name) ++ memcpy(ispcam->chip_name, data->chip_name, sizeof(ispcam->chip_name)); ++ else ++ return -ENODEV; ++ ++ ingenic_isp_parse_dt(ispcam); ++ ++ for(i = 0; i < ispcam->subdev_num; i++) { ++ component_match_add(ispcam->dev, &match, comp_compare, &ispcam->subdevs[i]->dev); ++ } ++ ++ ++ mutex_init(&ispcam->mutex); ++ ispcam->v4l2_dev.mdev = &ispcam->mdev; ++ ++ ispcam->mdev.dev = ispcam->dev; ++ strlcpy(ispcam->mdev.model, "ingenic-isp", sizeof(ispcam->mdev.model)); ++ ++ dev_nr = strchr(pdev->name, '@'); ++ if(!dev_nr){ ++ dev_err(ispcam->dev, "failed to get dev_nr\n"); ++ return -ENODEV; ++ } ++ ispcam->dev_nr = dev_nr[1]-'0'; ++ ++ /* add self to component */ ++ ret = component_master_add_with_match(ispcam->dev, &ispcam_comp_ops, match); ++ if(ret < 0) { ++ dev_err(ispcam->dev, "failed to add component master\n"); ++ /*TODO*/ ++ } ++ ++ ret = of_reserved_mem_device_init(ispcam->dev); ++ if(ret) ++ dev_warn(ispcam->dev, "failed to init reserved mem\n"); ++ ++ return 0; ++ ++ ++ return ret; ++} ++ ++ ++ ++static int ingenic_isp_remove(struct platform_device *pdev) ++{ ++ ++ return 0; ++} ++ ++struct ispcam_data ingenic_x2500_camera_data = { ++ .chip_name = "x2500", ++}; ++ ++ ++static const struct of_device_id ingenic_isp_dt_match[] = { ++ { .compatible = "ingenic,x2500-isp-camera", .data = (void *)&ingenic_x2500_camera_data}, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_isp_dt_match); ++ ++static int __maybe_unused ingenic_isp_drv_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ return 0; ++} ++ ++static int __maybe_unused ingenic_isp_drv_resume(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver ingenic_isp_driver = { ++ .probe = ingenic_isp_probe, ++ .remove = ingenic_isp_remove, ++ .suspend = ingenic_isp_drv_suspend, ++ .resume = ingenic_isp_drv_resume, ++ .driver = { ++ .name = "ingenic-ispdrv", ++ .of_match_table = ingenic_isp_dt_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_isp_driver); ++ ++MODULE_ALIAS("platform:ingenic-ispdrv"); ++MODULE_DESCRIPTION("ingenic isp subsystem"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-drv.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-drv.h +new file mode 100644 +index 000000000..4f6df6755 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-drv.h +@@ -0,0 +1,398 @@ ++#ifndef __INGENIC_ISP_DRV_H__ ++#define __INGENIC_ISP_DRV_H__ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include "isp-sensor.h" ++ ++ ++#define MAX_SUB_DEVS 5 ++#define MAX_ASYNC_SUBDEVS 1 /*æ¯ä¸ªISPåŒæ—¶æœ€å¤§æ”¯æŒ1个sensor.*/ ++ ++extern unsigned int MAIN_ISP_INDEX; ++extern unsigned int SEC_ISP_INDEX; ++ ++struct isp_video_format { ++ const char *name; ++ unsigned int fourcc; ++ unsigned int depth[3]; /*max 3 plane*/ ++ unsigned int mbus_code; ++ unsigned int num_planes; ++ enum v4l2_colorspace colorspace; ++}; ++ ++struct isp_pipeline { ++ struct media_pipeline pipeline; ++}; ++ ++ ++#define to_isp_buffer(buf) container_of(buf, struct isp_video_buffer, vb2) ++struct isp_video_buffer { ++ struct vb2_v4l2_buffer vb2; ++ struct list_head list_entry; ++ unsigned int uv_offset; /* 当使用single planeçš„bufferæ—¶,表明uvçš„å移大å°.*/ ++}; ++ ++/*æ¯ä¸ªmscaler_video_device代表一个数æ®èŠ‚ç‚¹ç¤ºä¾‹, mscaler有三个channel,所有三个video_device.*/ ++/*通用video_device, mscaler 的三个channelå¯ä»¥æ³¨å†Œ, vic也å¯ä»¥æ³¨å†Œï¼Œæ‰€ä»¥é€šç§°ä¸ºisp_video_device.*/ ++#define ISP_VIDEO_PAD_SINK 0 ++#define ISP_VIDEO_NUM_PADS 1 ++struct isp_video_device { ++ char *name; ++ ++ struct video_device video; ++ struct device *dev; ++ struct isp_video_ctx *ctx; ++ ++ struct media_pad pad; ++ ++ struct ispcam_device *ispcam; ++ ++ void *alloc_ctx; ++ struct vb2_queue *queue; ++ struct mutex queue_lock; ++ ++ struct mutex mutex; ++ ++ struct mutex stream_lock; ++ struct isp_pipeline pipe; ++ ++ ++ struct v4l2_format format; ++ struct isp_video_format *(*find_format)(const u32 *pixelformat, const u32 *mbus_code, int index); ++ struct isp_video_format *current_format; ++ const struct isp_video_ops *ops; ++ ++ int bypass; /*bypass isp.*/ ++ unsigned int max_buffer_num; /*max vb2 num*/ ++}; ++ ++struct isp_video_ops { ++ /**/ ++ struct isp_video_format *(*find_format)(const u32 *pixelformat, const u32 *mbus_code, int index); ++ ++ /*qbuf*/ ++ /*called by VIDIOC_QBUF in isp-video.c*/ ++ int (*qbuf)(struct isp_video_device *ispvideo, struct isp_video_buffer *isp_buffer); ++}; ++ ++/* isp-core-tuning*/ ++struct isp_core_tuning_ctrl { ++ unsigned int vflip; ++ unsigned int hflip; ++ TISP_MODE_DN_E daynight; ++ int saturation; ++ int brightness; ++ int contrast; ++ int sharpness; ++ char hue; ++}; ++ ++enum isp_image_tuning_private_cmd_id { ++ IMAGE_TUNING_CID_MODULE_CONTROL = V4L2_CID_PRIVATE_BASE, ++ IMAGE_TUNING_CID_DAY_OR_NIGHT, ++ IMAGE_TUNING_CID_AE_LUMA, ++ IMAGE_TUNING_CID_FACE_AE_CONTROL, ++ IMAGE_TUNING_CID_FACE_AWB_CONTROL, ++ IMAGE_TUNING_CID_SWITCH_BIN, ++ IMAGE_TUNING_CID_SET_DEFAULT_BIN_PATH, ++}; ++ ++#define CSI_PAD_SINK 0 ++#define CSI_PAD_SOURCE 1 ++#define CSI_NUM_PADS 2 ++struct csi_device { ++ struct device *dev; ++ int irq; ++ void __iomem *iobase; ++ unsigned int phy_base; ++ struct ispcam_device *ispcam; /*struct ispcam_device*/ ++ ++ struct v4l2_subdev sd; ++ ++ struct media_pad *pads; ++ struct v4l2_subdev_format formats[CSI_NUM_PADS]; ++ ++ struct clk *gate_clk; ++ ++ int reset_index; ++ int enabled; ++ ++ int settle_time; ++ struct sensor_info *sensor_info; ++}; ++ ++ ++#define VIC_PAD_SINK 0 ++#define VIC_PAD_SOURCE 1 ++#define VIC_NUM_PADS 2 ++struct vic_device { ++ struct device *dev; ++ ++ int irq; ++ void __iomem *iobase; ++ struct ispcam_device *ispcam; /*struct ispcam_device*/ ++ ++ struct v4l2_subdev sd; ++ ++ struct media_pad *pads; ++ struct isp_video_device ispvideo; /*VIC support video out*/ ++ struct v4l2_subdev_format formats[VIC_NUM_PADS]; ++ ++ unsigned int active_sink_pad; ++ ++ struct list_head dma_queued_list; ++ spinlock_t lock; ++ int enabled; ++ ++ unsigned int buffer_index; ++ int buffer_count; ++ int stop_flag; ++ int global_reset; ++ int frame_capture_counter; ++ ++ unsigned int framenum; ++ ++ unsigned int snap_paddr; ++ void* snap_vaddr; ++ struct completion snap_comp; ++ ++ unsigned int dma_complete; ++ struct sensor_info *sensor_info; ++}; ++ ++#define ISP_PAD_SINK 0 ++#define ISP_PAD_SOURCE 1 ++#define ISP_NUM_PADS 2 ++ ++#define MDNS_BUF 0 ++struct buf_info { ++ dma_addr_t paddr; ++ void *vaddr; ++ unsigned int size; ++}; ++ ++ ++struct isp_device { ++ struct device *dev; ++ int irq; ++ void __iomem *iobase; ++ struct ispcam_device *ispcam; ++ spinlock_t lock; ++ ++ void __iomem *cpm_reset; ++ unsigned int bit_sr; ++ unsigned int bit_stp; ++ unsigned int bit_ack; ++ ++ struct v4l2_subdev sd; ++ ++ struct media_pad *pads; ++ struct v4l2_subdev_format formats[ISP_NUM_PADS]; ++ ++ struct clk *div_clk; ++ struct clk *gate_clk; ++ struct clk *power_clk; ++ ++ multisensor_mode_t multi_mode; ++ ++ struct task_struct *process_thread; ++// tisp_core_t core; ++ int enabled; ++ unsigned int index; ++ unsigned int sensor_id; ++ ++ /* IRQ callbacks.*/ ++ int (*irq_func_cb[32])(void); ++ void *irq_func_data[32]; ++ ++ struct buf_info buf_info[3]; ++ struct isp_core_tuning_ctrl ctrls; ++ struct sensor_info *sensor_info; ++ ++ tx_isp_bin_path bpath; ++}; ++ ++ ++#ifdef CONFIG_MSCA_BDEV ++struct mscaler_backend_device { ++ struct device *dev; ++ struct list_head processing_list; ++ spinlock_t lock; ++ wait_queue_head_t wq; ++ ++ struct task_struct *process_thread; ++ ++ /* mscaler output fmt. */ ++ unsigned int width; ++ unsigned int height; ++ unsigned int fmt; ++ unsigned int ch; /*which channel this backend device belongs to.*/ ++ ++ int activated; /* is bdev activated??*/ ++ ++ struct ingenic_venc_ctx *ctx; ++}; ++#endif ++ ++/*MSCALER最大支æŒ3个ch输出,æ¯ä¸ªch支æŒä¸åŒçš„缩放等级. 这里åªä½¿ç”¨1个channel.*/ ++#define MSCALER_MAX_CH 3 ++#define MSCALER_PAD_SINK 0 ++#define MSCALER_PAD_SOURCE_CH0 1 ++#define MSCALER_PAD_SOURCE_CH1 2 ++#define MSCALER_PAD_SOURCE_CH2 3 ++#define MSCALER_NUM_PADS 4 ++struct mscaler_device { ++ struct device *dev; ++ int irq; ++ void __iomem *iobase; ++ struct ispcam_device *ispcam; ++ ++ struct v4l2_subdev sd; ++ struct media_pad *pads; ++ ++ struct list_head dma_queued_list[MSCALER_MAX_CH]; ++ struct list_head dma_pending_list[MSCALER_MAX_CH]; ++ ++ struct isp_video_device ispvideo[MSCALER_MAX_CH]; ++ /*包å«äº†è¾“å…¥pad和输出padçš„format*/ ++ struct v4l2_subdev_format formats[MSCALER_NUM_PADS]; ++ tisp_channel_attr_t attr[MSCALER_MAX_CH]; ++ ++ spinlock_t lock; ++ ++ unsigned int state[MSCALER_MAX_CH]; /*0: stopped, 1: streaming*/ ++ unsigned int framenum[MSCALER_MAX_CH]; ++ ++ struct kobject *mask_kobj; ++ struct kobject *mask_ch_kobj[MSCALER_MAX_CH]; ++ ++ unsigned int sensor_id; ++#ifdef CONFIG_MSCA_BDEV ++ struct mscaler_backend_device bdev[MSCALER_MAX_CH]; ++#endif ++}; ++ ++ ++/* æ¯ä¸ª isp_async_device 代表一个异步注册的 sensor设备. */ ++struct isp_async_device { ++ struct v4l2_subdev *sd; ++ struct v4l2_async_subdev asd; ++ int index; ++ ++ enum v4l2_mbus_type bus_type; ++ struct v4l2_fwnode_bus_parallel parallel; ++ struct v4l2_fwnode_bus_mipi_csi2 mipi_csi2; ++ ++ int enabled; ++ ++ unsigned int source_pad; ++}; ++ ++struct sensor_device { ++ struct isp_async_device *isd; ++ ++ struct ispcam_device *ispcam; ++ struct isp_device *isp; ++ ++}; ++ ++ ++ ++ ++#define to_isp_video_ctx(fh) container_of(fh, struct isp_video_ctx, fh) ++ ++/*every open create one ctx, should only one ctx is running at a time*/ ++struct isp_video_ctx { ++ struct isp_video_device *ispvideo; ++ ++ struct v4l2_fh fh; /*handle*/ ++ struct vb2_queue queue; ++ struct v4l2_format format; ++ unsigned int uv_offset; ++ unsigned int payload_size; ++}; ++ ++#define SUBDEV_PAD_SINK 0 ++#define SUBDEV_PAD_SOURCE 1 ++#define SUBDEV_NUM_PADS 2 ++ ++ ++struct ispcam_data { ++ char chip_name[32]; ++}; ++ ++struct ispcam_device { ++ struct device *dev; ++ struct platform_device *subdevs[MAX_SUB_DEVS]; ++ unsigned int subdev_num; ++ char chip_name[32]; ++ int dev_nr; ++ unsigned int sensor_id; ++ ++ struct media_device mdev; ++ struct v4l2_device v4l2_dev; ++ struct v4l2_async_notifier notifier; /*å¼‚æ­¥é€šçŸ¥ï¼Œç”¨æ¥æŽ¥æ”¶sensor注册完æˆä¿¡æ¯.*/ ++ ++ /*TODO: 应该åªä¼šæ”¯æŒä¸€ä¸ªsensor, MAX_ASYNC_SUBDEVS 应该为1*/ ++ struct isp_async_device isd[MAX_ASYNC_SUBDEVS]; ++ //struct v4l2_async_subdev asd[MAX_ASYNC_SUBDEVS]; ++ unsigned int asd_num; /*实际的async device个数,从endpoint中解æžå‡ºæ¥çš„.*/ ++ struct v4l2_fwnode_endpoint vep[MAX_ASYNC_SUBDEVS]; /*æ¯ä¸ªå¼‚步设备对应到一个端点上.*/ ++ ++ int enabled; ++ ++ struct mutex mutex; ++ struct isp_device *isp; ++ struct csi_device *csi; ++ struct vic_device *vic; ++ struct mscaler_device *mscaler; ++ struct sensor_device sensor; ++ ++}; ++ ++ ++/* isp-video*/ ++extern int isp_video_init(struct isp_video_device *ispvideo, char *name, const struct isp_video_ops *ops); ++ ++extern int isp_video_cleanup(struct isp_video_device *ispvideo); ++ ++extern int isp_video_register(struct isp_video_device *ispvideo, struct v4l2_device *v4l2_dev, int nr); ++ ++extern int isp_video_unregister(struct isp_video_device *ispvideo); ++ ++static inline struct v4l2_fwnode_bus_parallel *ispcam_get_bus_parallel(struct ispcam_device *ispcam) ++{ ++ return &ispcam->isd[0].parallel; ++} ++ ++static inline struct v4l2_fwnode_bus_mipi_csi2 *ispcam_get_bus_mipi_csi2(struct ispcam_device *ispcam) ++{ ++ return &ispcam->isd[0].mipi_csi2; ++} ++ ++/* sensor */ ++ ++int sensor_device_probe(struct sensor_device *sensor, struct ispcam_device *ispcam); ++ ++#ifdef CONFIG_MSCA_BDEV ++/* mscaler backend */ ++int ms_bdev_init(struct mscaler_backend_device *ms_bdev); ++ ++int ms_bdev_deinit(struct mscaler_backend_device *ms_bdev); ++ ++int ms_bdev_qbuf(struct mscaler_backend_device *ms_bdev, struct isp_video_buffer *isp_buffer); ++#endif ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-regs-x2000.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-regs-x2000.h +new file mode 100755 +index 000000000..410bedd3a +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-regs-x2000.h +@@ -0,0 +1,1453 @@ ++#ifndef TIZIANO_MAP__H ++#define TIZIANO_MAP__H ++#ifndef TIZIANO_BASE ++#define TIZIANO_BASE 0x0 ++#endif ++#ifndef TIZIANO_MAN ++#define TIZIANO_MAN 3 ++#endif ++ ++//============================================================ ++// BASE ADDRESS ++//============================================================ ++#define VIC_BASE (TIZIANO_BASE + 0x10000) ++#define TOP_BASE (TIZIANO_BASE + 0x00000) ++#define IP_BASE (TIZIANO_BASE + 0x00100) ++#define DPC_BASE (TIZIANO_BASE + 0x00200) ++#define GIB_BASE (TIZIANO_BASE + 0x00400) ++#define LSC_BASE (TIZIANO_BASE + 0x00500) ++#define AG_BASE (TIZIANO_BASE + 0x00600) ++#define AE_BASE (TIZIANO_BASE + 0x00700) ++#define AWB_BASE (TIZIANO_BASE + 0x00800) ++#define AF_BASE (TIZIANO_BASE + 0x00900) ++#define ADR_BASE (TIZIANO_BASE + 0x00A00) ++#define IRINT_BASE (TIZIANO_BASE + 0x00F00) ++#define DMSC_BASE (TIZIANO_BASE + 0x01000) ++#define CCM_BASE (TIZIANO_BASE + 0x01200) ++#define DEFOG_BASE (TIZIANO_BASE + 0x01300) ++#define CSC_BASE (TIZIANO_BASE + 0x01700) ++#define CLM_BASE (TIZIANO_BASE + 0x01800) ++#define SP_BASE (TIZIANO_BASE + 0x01900) ++#define MDNS_BASE (TIZIANO_BASE + 0x01B00) ++#define SDNS_BASE (TIZIANO_BASE + 0x02000) ++#define HLDC_BASE (TIZIANO_BASE + 0x02200) ++#define MSCA_BASE (TIZIANO_BASE + 0x02300) ++ ++#define DPC_MEM_BASE (TIZIANO_BASE + 0x04000) ++#define LSC_MEM_BASE (TIZIANO_BASE + 0x06000) ++#define GIB_MEM_BASE (TIZIANO_BASE + 0x08000) ++#define AE_HIST_MEM_BASE (TIZIANO_BASE + 0x08200) ++#define R_GAMMA_MEM_BASE (TIZIANO_BASE + 0x08A00) ++#define G_GAMMA_MEM_BASE (TIZIANO_BASE + 0x08C00) ++#define B_GAMMA_MEM_BASE (TIZIANO_BASE + 0x08E00) ++#define DEFOG_MEM_BASE (TIZIANO_BASE + 0x09000) ++#define CLM_H_0_MEM_BASE (TIZIANO_BASE + 0x0A000) ++#define CLM_H_1_MEM_BASE (TIZIANO_BASE + 0x0A800) ++#define CLM_S_0_MEM_BASE (TIZIANO_BASE + 0x0B000) ++#define CLM_S_1_MEM_BASE (TIZIANO_BASE + 0x0B800) ++ ++#if 0 ++//============================================================ ++// VIC ++//============================================================ ++#define VIC_ADDR_CONTROL (VIC_BASE + 0x00) ++#define VIC_ADDR_RESOLUTION (VIC_BASE + 0x04) ++#define VIC_ADDR_FRAME_ECC (VIC_BASE + 0x08) ++#define VIC_ADDR_INTF_TYPE (VIC_BASE + 0x0C) ++#define VIC_ADDR_BT_CFG (VIC_BASE + 0x10) ++#define VIC_ADDR_PCLK_GATE (VIC_BASE + 0x1C) ++#define VIC_ADDR_HOR_PARA0 (VIC_BASE + 0x20) ++#define VIC_ADDR_HOR_PARA1 (VIC_BASE + 0x24) ++#define VIC_ADDR_VER_PARA0 (VIC_BASE + 0x30) ++#define VIC_ADDR_VER_PARA1 (VIC_BASE + 0x34) ++#define VIC_ADDR_VER_PARA2 (VIC_BASE + 0x38) ++#define VIC_ADDR_VER_PARA3 (VIC_BASE + 0x3C) ++#define VIC_ADDR_GLB_CFG (VIC_BASE + 0x50) ++#define VIC_ADDR_AB_VLA (VIC_BASE + 0x54) ++#define VIC_ADDR_HBLK_R (VIC_BASE + 0x58) ++#define VIC_ADDR_VBLK_R (VIC_BASE + 0x5C) ++#define VIC_ADDR_SAV_VALUE0 (VIC_BASE + 0x60) ++#define VIC_ADDR_EAV_VALUE0 (VIC_BASE + 0x64) ++#define VIC_ADDR_SAV_VALUE1 (VIC_BASE + 0x68) ++#define VIC_ADDR_EAV_VALUE1 (VIC_BASE + 0x6C) ++#define VIC_ADDR_SAV_VALUE2 (VIC_BASE + 0x70) ++#define VIC_ADDR_EAV_VALUE2 (VIC_BASE + 0x74) ++#define VIC_ADDR_WORK_STATE (VIC_BASE + 0x0090) ++#define VIC_ADDR_PIX_REG (VIC_BASE + 0x0094) ++#define VIC_ADDR_LINE_REG (VIC_BASE + 0x0098) ++#define VIC_ADDR_OFIFO_CNT (VIC_BASE + 0x009C) ++#define VIC_ADDR_BF_BAR_CTRL (VIC_BASE + 0x00A0) ++#define VIC_ADDR_BF_BAR_BLANK (VIC_BASE + 0x00A4) ++#define VIC_ADDR_AF_BAR_CTRL (VIC_BASE + 0x00B0) ++#define VIC_ADDR_AF_BAR_BLANK (VIC_BASE + 0x00B4) ++#define VIC_ADDR_WHITE_BAR (VIC_BASE + 0x00C0) ++#define VIC_ADDR_BLACK_BAR (VIC_BASE + 0x00C4) ++#define VIC_ADDR_BLUE_BAR (VIC_BASE + 0x00C8) ++#define VIC_ADDR_GREEN_BAR (VIC_BASE + 0x00CC) ++#define VIC_ADDR_RED_BAR (VIC_BASE + 0x00D0) ++#define VIC_ADDR_CYAN_BAR (VIC_BASE + 0x00D4) ++#define VIC_ADDR_YELLOW_BAR (VIC_BASE + 0x00D8) ++#define VIC_ADDR_MAGENTA_BAR (VIC_BASE + 0x00DC) ++#define VIC_ADDR_WHITE_BAR2 (VIC_BASE + 0x00E0) ++#define VIC_ADDR_BLACK_BAR2 (VIC_BASE + 0x00E4) ++#define VIC_ADDR_BLUE_BAR2 (VIC_BASE + 0x00E8) ++#define VIC_ADDR_GREEN_BAR2 (VIC_BASE + 0x00EC) ++#define VIC_ADDR_RED_BAR2 (VIC_BASE + 0x00F0) ++#define VIC_ADDR_CYAN_BAR2 (VIC_BASE + 0x00F4) ++#define VIC_ADDR_YELLOW_BAR2 (VIC_BASE + 0x00F8) ++#define VIC_ADDR_MAGENTA_BAR2 (VIC_BASE + 0x00FC) ++#define VIC_ADDR_INT_STA (VIC_BASE + 0x0100) ++#define VIC_ADDR_INT_MASK (VIC_BASE + 0x0104) ++#define VIC_ADDR_INT_CLR (VIC_BASE + 0x0108) ++#define VIC_ADDR_DMA_CONFIGURE (VIC_BASE + 0x0200) ++#define VIC_ADDR_DMA_RES_R (VIC_BASE + 0x0204) ++#define VIC_ADDR_DMA_RESET (VIC_BASE + 0x0208) ++#define VIC_ADDR_DMA_Y_CH_BANK_CONTROL (VIC_BASE + 0x0210) ++#define VIC_ADDR_DMA_Y_CH_LINE_STRIDE (VIC_BASE + 0x0214) ++#define VIC_ADDR_DMA_Y_CH_BANK0_ADDR (VIC_BASE + 0x0218) ++#define VIC_ADDR_DMA_Y_CH_BANK1_ADDR (VIC_BASE + 0x021c) ++#define VIC_ADDR_DMA_Y_CH_BANK2_ADDR (VIC_BASE + 0x0220) ++#define VIC_ADDR_DMA_Y_CH_BANK3_ADDR (VIC_BASE + 0x0224) ++#define VIC_ADDR_DMA_Y_CH_BANK4_ADDR (VIC_BASE + 0x0228) ++#define VIC_ADDR_DMA_UV_CH_BANK_CONTROL (VIC_BASE + 0x0230) ++#define VIC_ADDR_DMA_UV_CH_LINE_STRIDE (VIC_BASE + 0x0234) ++#define VIC_ADDR_DMA_UV_CH_BANK0_ADDR (VIC_BASE + 0x0238) ++#define VIC_ADDR_DMA_UV_CH_BANK1_ADDR (VIC_BASE + 0x023c) ++#define VIC_ADDR_DMA_UV_CH_BANK2_ADDR (VIC_BASE + 0x0240) ++#define VIC_ADDR_DMA_UV_CH_BANK3_ADDR (VIC_BASE + 0x0244) ++#define VIC_ADDR_DMA_UV_CH_BANK4_ADDR (VIC_BASE + 0x0248) ++#define VIC_ADDR_SYFIFO_USED (VIC_BASE + 0x0300) ++#define VIC_ADDR_FR_DONE_CNT (VIC_BASE + 0x0304) ++#define VIC_ADDR_DVP_SIZE (VIC_BASE + 0x0308) ++#define VIC_ADDR_DVP_WORK_STA (VIC_BASE + 0x030C) ++ ++#endif ++ ++//============================================================ ++// TOP ++//============================================================ ++#define DPC (0 << 0) ++#define GIB (0 << 1) ++#define LSC (0 << 2) ++#define AWB (0 << 3) ++#define ADR (1 << 4) ++#define DMS (0 << 5) ++#define CCM (0 << 6) ++#define GAMMA (0 << 7) ++#define DEFOG (1 << 8) ++#define CLM (0 << 9) ++#define Y_SHARPEN (0 << 10) ++#define MDNS (0 << 11) ++#define SDNS (0 << 12) ++#define HLDC (1 << 13) ++#define TP (1 << 14) ++#define FONT (1 << 15) ++#define SEL (0 << 31) ++#define TIZIANO_BYPASS_INIT (DPC|GIB|LSC|AWB|ADR|DMS|CCM|GAMMA|DEFOG|CLM|Y_SHARPEN|MDNS|SDNS|HLDC|TP|FONT|SEL) ++ ++#define TIZIANO_FM_SIZE (TOP_BASE + 0X0004) ++#define TIZIANO_BATER_TYPE (TOP_BASE + 0X0008) ++#define TIZAINO_BYPASS_CON (TOP_BASE + 0X000C) ++#define TIZIANO_TOP_CON (TOP_BASE + 0X0010) ++#define TIZIANO_REG_CON (TOP_BASE + 0X001C) ++#define TIZAINO_INT_EN (TOP_BASE + 0X0080) ++ ++#define TOP_CTRL_ADDR_VERSION (TOP_BASE + 0x0000) ++#define TOP_CTRL_ADDR_FM_SIZE (TOP_BASE + 0x0004) ++#define TOP_CTRL_ADDR_BAYER_TYPE (TOP_BASE + 0x0008) ++#define TOP_CTRL_ADDR_BYPASS_CON (TOP_BASE + 0x000C) ++#define TOP_CTRL_ADDR_TOP_CON (TOP_BASE + 0x0010) ++#define TOP_CTRL_ADDR_TOP_STATE (TOP_BASE + 0x0014) ++#define TOP_CTRL_ADDR_LINE_SPACE (TOP_BASE + 0x0018) ++#define TOP_CTRL_ADDR_REG_CON (TOP_BASE + 0x001C) ++#define TOP_CTRL_ADDR_DMA_RC_TRIG (TOP_BASE + 0x0030) ++#define TOP_CTRL_ADDR_DMA_RC_CON (TOP_BASE + 0x0034) ++#define TOP_CTRL_ADDR_DMA_RC_ADDR (TOP_BASE + 0x0038) ++#define TOP_CTRL_ADDR_DMA_RC_STATE (TOP_BASE + 0x003C) ++#define TOP_CTRL_ADDR_DMA_RC_APB_WR_DATA (TOP_BASE + 0x0040) ++#define TOP_CTRL_ADDR_DMA_RC_APB_WR_ADDR (TOP_BASE + 0x0044) ++#define TOP_CTRL_ADDR_DMA_RD_CON (TOP_BASE + 0x0050) ++#define TOP_CTRL_ADDR_DMA_WR_CON (TOP_BASE + 0x0054) ++#define TOP_CTRL_ADDR_DMA_FR_WR_CON (TOP_BASE + 0x0058) ++#define TOP_CTRL_ADDR_DMA_STA_WR_CON (TOP_BASE + 0x005C) ++#define TOP_CTRL_ADDR_DMA_RD_DEBUG (TOP_BASE + 0x0060) ++#define TOP_CTRL_ADDR_DMA_WR_DEBUG (TOP_BASE + 0x0064) ++#define TOP_CTRL_ADDR_DMA_FR_WR_DEBUG (TOP_BASE + 0x0068) ++#define TOP_CTRL_ADDR_DMA_STA_WR_DEBUG (TOP_BASE + 0x006C) ++#define TOP_CTRL_ADDR_INT_EN (TOP_BASE + 0x0080) ++#define TOP_CTRL_ADDR_INT_REG (TOP_BASE + 0x0084) ++#define TOP_CTRL_ADDR_INT_CLR (TOP_BASE + 0x0088) ++#define TOP_CTRL_ADDR_TP_FREERUN (TOP_BASE + 0x00A0) ++#define TOP_CTRL_ADDR_TP_CON (TOP_BASE + 0x00A4) ++#define TOP_CTRL_ADDR_TP_SIZE (TOP_BASE + 0x00A8) ++#define TOP_CTRL_ADDR_TP_FONT (TOP_BASE + 0x00AC) ++#define TOP_CTRL_ADDR_TP_FLICK (TOP_BASE + 0x00B0) ++#define TOP_CTRL_ADDR_TP_CS_TYPE (TOP_BASE + 0x00B4) ++#define TOP_CTRL_ADDR_TP_CS_FCLO (TOP_BASE + 0x00B8) ++#define TOP_CTRL_ADDR_TP_CS_BCLO (TOP_BASE + 0x00BC) ++ ++//============================================================ ++// Input Interface ++//============================================================ ++#define INPUT_CTRL_ADDR_IP_TRIG (IP_BASE + 0x0000) ++#define INPUT_CTRL_ADDR_CONTROL (IP_BASE + 0x0004) ++#define INPUT_CTRL_ADDR_CHK_TRIG (IP_BASE + 0x0008) ++#define INPUT_CTRL_ADDR_CHK_TIME (IP_BASE + 0x000C) ++#define INPUT_CTRL_ADDR_CHK_CNT (IP_BASE + 0x0010) ++#define INPUT_CTRL_ADDR_CHK_FR_CNT (IP_BASE + 0x0014) ++#define INPUT_CTRL_ADDR_IP_STATE (IP_BASE + 0x0018) ++#define INPUT_CTRL_ADDR_IN_CNT (IP_BASE + 0x001C) ++#define INPUT_CTRL_ADDR_OUT_CNT (IP_BASE + 0x0020) ++ ++//============================================================ ++// DPC ++//============================================================ ++#if 0 ++#define DPC_ADDR_SYNC (DPC_BASE + 0x0000) ++#define DPC_ADDR_S_EN (DPC_BASE + 0x0004) ++#define DPC_ADDR_S_OC_BLEND_ALPHA (DPC_BASE + 0x0008) ++#define DPC_ADDR_OC_BLEND_ALPHA (DPC_BASE + 0x000C) ++#define DPC_ADDR_SD_LV1_SLOPE (DPC_BASE + 0x0010) ++#define DPC_ADDR_SD_LV2_SLOPE (DPC_BASE + 0x0014) ++#define DPC_ADDR_LS_BLEND_ALPHA_RB (DPC_BASE + 0x0018) ++#define DPC_ADDR_LV1_DIFF_THRES_RB (DPC_BASE + 0x001C) ++#define DPC_ADDR_SD_LV2_DIFF_THRES_RB (DPC_BASE + 0x0020) ++#define DPC_ADDR_SD_LV2_P0_THRES_RB (DPC_BASE + 0x0024) ++#define DPC_ADDR_SD_LV2_P2_THRES_RB (DPC_BASE + 0x0028) ++#define DPC_ADDR_SD_LV2_P0_DIST_THRES_RB (DPC_BASE + 0x002C) ++#define DPC_ADDR_SD_LV2_P2_DIST_THRES_RB (DPC_BASE + 0x0030) ++#define DPC_ADDR_LD_LV2_THRES_RB (DPC_BASE + 0x0034) ++#define DPC_ADDR_LS_BLEND_ALPHA_G (DPC_BASE + 0x0038) ++#define DPC_ADDR_LV1_DIFF_THRES_G (DPC_BASE + 0x003C) ++#define DPC_ADDR_SD_LV2_DIFF_THRES_G (DPC_BASE + 0x0040) ++#define DPC_ADDR_SD_LV2_P0_THRES_G (DPC_BASE + 0x0044) ++#define DPC_ADDR_SD_LV2_P2_THRES_G (DPC_BASE + 0x0048) ++#define DPC_ADDR_SD_LV2_P0_DIST_THRES_G (DPC_BASE + 0x004C) ++#define DPC_ADDR_SD_LV2_P2_DIST_THRES_G (DPC_BASE + 0x0050) ++#define DPC_ADDR_LD_LV2_THRES_G (DPC_BASE + 0x0054) ++#define DPC_ADDR_CTR_FUNC_EN (DPC_BASE + 0x0058) ++#define DPC_ADDR_CTR_MD_SEG_OPT (DPC_BASE + 0x005C) ++#define DPC_ADDR_CTR_BASE_THRES (DPC_BASE + 0x0060) ++#define DPC_ADDR_RDNS_FUNC_EN (DPC_BASE + 0x0064) ++#define DPC_ADDR_RDNS_FLAT_THRES (DPC_BASE + 0x0068) ++#define DPC_ADDR_RDNS_TEXT_THRES (DPC_BASE + 0x006C) ++#define DPC_ADDR_RDNS_SIGMA_X1 (DPC_BASE + 0x0070) ++#define DPC_ADDR_RDNS_STD (DPC_BASE + 0x0074) ++#define DPC_ADDR_RDNS_RB_GAUS_SIGMA (DPC_BASE + 0x0078) ++#define DPC_ADDR_RDNS_G_SIGMA_X (DPC_BASE + 0x007C) ++#define DPC_ADDR_RDNS_G_SIGMA_S (DPC_BASE + 0x0080) ++#define DPC_ADDR_RDNS_RB_SIGMA_X (DPC_BASE + 0x0084) ++#define DPC_ADDR_RDNS_RB_SIGMA_S (DPC_BASE + 0x0088) ++#define DPC_ADDR_CTR_MD_NP_ARRAY_RG0 (DPC_BASE + 0x008C) ++#define DPC_ADDR_CTR_MD_NP_ARRAY_RG1 (DPC_BASE + 0x0090) ++#define DPC_ADDR_CTR_MD_NP_ARRAY_RG2 (DPC_BASE + 0x0094) ++#define DPC_ADDR_CTR_MD_NP_ARRAY_RG3 (DPC_BASE + 0x0098) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG0 (DPC_BASE + 0x009C) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG1 (DPC_BASE + 0x00A0) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG2 (DPC_BASE + 0x00A4) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG3 (DPC_BASE + 0x00A8) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG4 (DPC_BASE + 0x00AC) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG5 (DPC_BASE + 0x00B0) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG6 (DPC_BASE + 0x00B4) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG7 (DPC_BASE + 0x00B8) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG0 (DPC_BASE + 0x00BC) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG1 (DPC_BASE + 0x00C0) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG2 (DPC_BASE + 0x00C4) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG3 (DPC_BASE + 0x00C8) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG4 (DPC_BASE + 0x00CC) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG5 (DPC_BASE + 0x00D0) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG6 (DPC_BASE + 0x00D4) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG7 (DPC_BASE + 0x00D8) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG0 (DPC_BASE + 0x00DC) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG1 (DPC_BASE + 0x00E0) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG2 (DPC_BASE + 0x00E4) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG3 (DPC_BASE + 0x00E8) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG4 (DPC_BASE + 0x00EC) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG5 (DPC_BASE + 0x00F0) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG6 (DPC_BASE + 0x00F4) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG7 (DPC_BASE + 0x00F8) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG0 (DPC_BASE + 0x00FC) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG1 (DPC_BASE + 0x0100) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG2 (DPC_BASE + 0x0104) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG3 (DPC_BASE + 0x0108) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG4 (DPC_BASE + 0x010C) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG5 (DPC_BASE + 0x0110) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG6 (DPC_BASE + 0x0114) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG7 (DPC_BASE + 0x0118) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG0 (DPC_BASE + 0x011C) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG1 (DPC_BASE + 0x0120) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG2 (DPC_BASE + 0x0124) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG3 (DPC_BASE + 0x0128) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG4 (DPC_BASE + 0x012C) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG5 (DPC_BASE + 0x0130) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG6 (DPC_BASE + 0x0134) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG7 (DPC_BASE + 0x0138) ++#define DPC_ADDR_SDP_NUM (DPC_BASE + 0x013C) ++#define DPC_ADDR_SP_DEBUG_REG_0 (DPC_BASE + 0x0140) ++#define DPC_ADDR_SP_DEBUG_REG_1 (DPC_BASE + 0x0144) ++ ++//============================================================ ++// GIB ++//============================================================ ++#define GIB_ADDR_REG_CTRL (GIB_BASE + 0x0000) ++#define GIB_ADDR_CONFIG (GIB_BASE + 0x0004) ++#define GIB_ADDR_R_G (GIB_BASE + 0x0008) ++#define GIB_ADDR_B_IR (GIB_BASE + 0x000c) ++#define GIB_ADDR_DEIRM_R12 (GIB_BASE + 0x0010) ++#define GIB_ADDR_DEIRM_R34 (GIB_BASE + 0x0014) ++#define GIB_ADDR_DEIRM_C1 (GIB_BASE + 0x0018) ++#define GIB_ADDR_DEIRM_G12 (GIB_BASE + 0x001c) ++#define GIB_ADDR_DEIRM_G34 (GIB_BASE + 0x0020) ++#define GIB_ADDR_DEIRM_C2 (GIB_BASE + 0x0024) ++#define GIB_ADDR_DEIRM_B12 (GIB_BASE + 0x0028) ++#define GIB_ADDR_DEIRM_B34 (GIB_BASE + 0x002c) ++#define GIB_ADDR_DEIRM_C3 (GIB_BASE + 0x0030) ++#define GIB_ADDR_DEIRM_BLC12 (GIB_BASE + 0x0034) ++#define GIB_ADDR_DEIRM_BLC34 (GIB_BASE + 0x0038) ++#define GIB_ADDR_DEIRM_BLC5 (GIB_BASE + 0x003c) ++#define GIB_ADDR_DEBUG0 (GIB_BASE + 0x0040) ++#define GIB_DEIR_R_BASE (GIB_MEM_BASE + 0x0000) ++#define GIB_DEIR_G_BASE (GIB_MEM_BASE + 0x0080) ++#define GIB_DEIR_B_BASE (GIB_MEM_BASE + 0x0100) ++ ++//============================================================ ++// LSC ++//============================================================ ++#define LSC_ADDR_T_VERSION (LSC_BASE + 0x0000) ++#define LSC_ADDR_T_DBG_SEL (LSC_BASE + 0x0004) ++#define LSC_ADDR_T_DBG_VALUE (LSC_BASE + 0x0008) ++#define LSC_ADDR_MESH_SIZE (LSC_BASE + 0x0010) ++#define LSC_ADDR_MESH_SCALE (LSC_BASE + 0x0014) ++#define LSC_ADDR_LUT_STRIDE (LSC_BASE + 0x0018) ++ ++//============================================================ ++// AG ++//============================================================ ++#define AWB_GAIN_ADDR_REG_CTRL (AG_BASE + 0x0000) ++#define AWB_GAIN_ADDR_R_G (AG_BASE + 0x0004) ++#define AWB_GAIN_ADDR_B_IR (AG_BASE + 0x0008) ++#define AWB_GAIN_ADDR_DEBUG0 (AG_BASE + 0x000c) ++ ++//============================================================ ++// AE ++//============================================================ ++#define AE_STAT_ADDR_REG_CTRL (AE_BASE + 0x0000) ++#define AE_STAT_ADDR_ZONE_NUM_START (AE_BASE + 0x0004) ++#define AE_STAT_ADDR_HOR_ZONE_SIZE_14 (AE_BASE + 0x0008) ++#define AE_STAT_ADDR_HOR_ZONE_SIZE_58 (AE_BASE + 0x000c) ++#define AE_STAT_ADDR_HOR_ZONE_SIZE_912 (AE_BASE + 0x0010) ++#define AE_STAT_ADDR_HOR_ZONE_SIZE_1315 (AE_BASE + 0x0014) ++#define AE_STAT_ADDR_VER_ZONE_SIZE_14 (AE_BASE + 0x0018) ++#define AE_STAT_ADDR_VER_ZONE_SIZE_58 (AE_BASE + 0x001c) ++#define AE_STAT_ADDR_VER_ZONE_SIZE_912 (AE_BASE + 0x0020) ++#define AE_STAT_ADDR_VER_ZONE_SIZE_1315 (AE_BASE + 0x0024) ++#define AE_STAT_ADDR_LUM_TH_FREQ (AE_BASE + 0x0028) ++#define AE_STAT_ADDR_AE_DMA_BASE_1 (AE_BASE + 0x002c) ++#define AE_STAT_ADDR_AE_DMA_BASE_2 (AE_BASE + 0x0030) ++#define AE_STAT_ADDR_AE_DMA_BASE_3 (AE_BASE + 0x0034) ++#define AE_STAT_ADDR_AE_DMA_BASE_4 (AE_BASE + 0x0038) ++#define AE_STAT_ADDR_HIST_DMA_BASE_1 (AE_BASE + 0x003c) ++#define AE_STAT_ADDR_HIST_DMA_BASE_2 (AE_BASE + 0x0040) ++#define AE_STAT_ADDR_HIST_DMA_BASE_3 (AE_BASE + 0x0044) ++#define AE_STAT_ADDR_HIST_DMA_BASE_4 (AE_BASE + 0x0048) ++#define AE_STAT_ADDR_DMA_BASE_NUM (AE_BASE + 0x004c) ++#define AE_STAT_ADDR_DMA_INFO (AE_BASE + 0x0050) ++#define AE_STAT_ADDR_DEBUG0 (AE_BASE + 0x0054) ++#define AE_STAT_ADDR_DEBUG1 (AE_BASE + 0x0058) ++ ++//============================================================ ++// AWB ++//============================================================ ++#define AWB_STAT_ADDR_REG_CTRL (AWB_BASE + 0x0000) ++#define AWB_STAT_ADDR_ZONE_NUM_START (AWB_BASE + 0x0004) ++#define AWB_STAT_ADDR_HOR_ZONE_SIZE_14 (AWB_BASE + 0x0008) ++#define AWB_STAT_ADDR_HOR_ZONE_SIZE_58 (AWB_BASE + 0x000c) ++#define AWB_STAT_ADDR_HOR_ZONE_SIZE_912 (AWB_BASE + 0x0010) ++#define AWB_STAT_ADDR_HOR_ZONE_SIZE_1315 (AWB_BASE + 0x0014) ++#define AWB_STAT_ADDR_VER_ZONE_SIZE_14 (AWB_BASE + 0x0018) ++#define AWB_STAT_ADDR_VER_ZONE_SIZE_58 (AWB_BASE + 0x001c) ++#define AWB_STAT_ADDR_VER_ZONE_SIZE_912 (AWB_BASE + 0x0020) ++#define AWB_STAT_ADDR_VER_ZONE_SIZE_1315 (AWB_BASE + 0x0024) ++#define AWB_STAT_ADDR_RG_TH (AWB_BASE + 0x0028) ++#define AWB_STAT_ADDR_BG_TH (AWB_BASE + 0x002c) ++#define AWB_STAT_ADDR_K1_A1 (AWB_BASE + 0x0030) ++#define AWB_STAT_ADDR_K2_A2 (AWB_BASE + 0x0034) ++#define AWB_STAT_ADDR_LUM_TH_FREQ (AWB_BASE + 0x0038) ++#define AWB_STAT_ADDR_AWB_DMA_BASE_1 (AWB_BASE + 0x003c) ++#define AWB_STAT_ADDR_AWB_DMA_BASE_2 (AWB_BASE + 0x0040) ++#define AWB_STAT_ADDR_AWB_DMA_BASE_3 (AWB_BASE + 0x0044) ++#define AWB_STAT_ADDR_AWB_DMA_BASE_4 (AWB_BASE + 0x0048) ++#define AWB_STAT_ADDR_DMA_BASE_NUM (AWB_BASE + 0x004c) ++#define AWB_STAT_ADDR_DMA_INFO (AWB_BASE + 0x0050) ++#define AWB_STAT_ADDR_DEBUG0 (AWB_BASE + 0x0054) ++#define AWB_STAT_ADDR_DEBUG1 (AWB_BASE + 0x0058) ++ ++//============================================================ ++// AF ++//============================================================ ++#define AF_STAT_ADDR_REG_CTRL (AF_BASE + 0x0000) ++#define AF_STAT_ADDR_ZONE_NUM_START (AF_BASE + 0x0004) ++#define AF_STAT_ADDR_HOR_ZONE_SIZE_14 (AF_BASE + 0x0008) ++#define AF_STAT_ADDR_HOR_ZONE_SIZE_58 (AF_BASE + 0x000c) ++#define AF_STAT_ADDR_HOR_ZONE_SIZE_912 (AF_BASE + 0x0010) ++#define AF_STAT_ADDR_HOR_ZONE_SIZE_1315 (AF_BASE + 0x0014) ++#define AF_STAT_ADDR_VER_ZONE_SIZE_14 (AF_BASE + 0x0018) ++#define AF_STAT_ADDR_VER_ZONE_SIZE_58 (AF_BASE + 0x001c) ++#define AF_STAT_ADDR_VER_ZONE_SIZE_912 (AF_BASE + 0x0020) ++#define AF_STAT_ADDR_VER_ZONE_SIZE_1315 (AF_BASE + 0x0024) ++#define AF_STAT_ADDR_FREQ_IIR_EN_LUM_TH (AF_BASE + 0x0028) ++#define AF_STAT_ADDR_LDG_COR_EN (AF_BASE + 0x002c) ++#define AF_STAT_ADDR_FIR0_G1_G2 (AF_BASE + 0x0030) ++#define AF_STAT_ADDR_FIR0_G3_G4 (AF_BASE + 0x0034) ++#define AF_STAT_ADDR_FIR0_G5 (AF_BASE + 0x0038) ++#define AF_STAT_ADDR_FIR1_G1_G2 (AF_BASE + 0x003c) ++#define AF_STAT_ADDR_FIR1_G3_G4 (AF_BASE + 0x0040) ++#define AF_STAT_ADDR_FIR1_G5 (AF_BASE + 0x0044) ++#define AF_STAT_ADDR_IIR0_G1_G3 (AF_BASE + 0x0048) ++#define AF_STAT_ADDR_IIR0_G4_G5 (AF_BASE + 0x004c) ++#define AF_STAT_ADDR_IIR0_G6_G8 (AF_BASE + 0x0050) ++#define AF_STAT_ADDR_IIR0_G9_G10 (AF_BASE + 0x0054) ++#define AF_STAT_ADDR_IIR1_G1_G3 (AF_BASE + 0x0058) ++#define AF_STAT_ADDR_IIR1_G4_G5 (AF_BASE + 0x005c) ++#define AF_STAT_ADDR_IIR1_G6_G8 (AF_BASE + 0x0060) ++#define AF_STAT_ADDR_IIR1_G9_G10 (AF_BASE + 0x0064) ++#define AF_STAT_ADDR_LDG_FIR0_LOW (AF_BASE + 0x0068) ++#define AF_STAT_ADDR_LDG_FIR0_HIGH (AF_BASE + 0x006c) ++#define AF_STAT_ADDR_LDG_FIR1_LOW (AF_BASE + 0x0070) ++#define AF_STAT_ADDR_LDG_FIR1_HIGH (AF_BASE + 0x0074) ++#define AF_STAT_ADDR_LDG_IIR0_LOW (AF_BASE + 0x0078) ++#define AF_STAT_ADDR_LDG_IIR0_HIGH (AF_BASE + 0x007c) ++#define AF_STAT_ADDR_LDG_IIR1_LOW (AF_BASE + 0x0080) ++#define AF_STAT_ADDR_LDG_IIR1_HIGH (AF_BASE + 0x0084) ++#define AF_STAT_ADDR_COR_F0_TH_LH (AF_BASE + 0x0088) ++#define AF_STAT_ADDR_COR_F0_SLP_LIM (AF_BASE + 0x008c) ++#define AF_STAT_ADDR_COR_F1_TH_LH (AF_BASE + 0x0090) ++#define AF_STAT_ADDR_COR_F1_SLP_LIM (AF_BASE + 0x0094) ++#define AF_STAT_ADDR_COR_I0_TH_LH (AF_BASE + 0x0098) ++#define AF_STAT_ADDR_COR_I0_SLP_LIM (AF_BASE + 0x009c) ++#define AF_STAT_ADDR_COR_I1_TH_LH (AF_BASE + 0x00a0) ++#define AF_STAT_ADDR_COR_I1_SLP_LIM (AF_BASE + 0x00a4) ++#define AF_STAT_ADDR_AF_DMA_BASE_1 (AF_BASE + 0x00a8) ++#define AF_STAT_ADDR_AF_DMA_BASE_2 (AF_BASE + 0x00ac) ++#define AF_STAT_ADDR_AF_DMA_BASE_3 (AF_BASE + 0x00b0) ++#define AF_STAT_ADDR_AF_DMA_BASE_4 (AF_BASE + 0x00b4) ++#define AF_STAT_ADDR_DMA_BASE_NUM (AF_BASE + 0x00b8) ++#define AF_STAT_ADDR_DMA_INFO (AF_BASE + 0x00bc) ++#define AF_STAT_ADDR_DEBUG0 (AF_BASE + 0x00c0) ++ ++//============================================================ ++// ADR ++//============================================================ ++#define ADR_ADDR_T_VERSION (ADR_BASE + 0x0000) ++#define ADR_ADDR_T_DBG_SEL (ADR_BASE + 0x0004) ++#define ADR_ADDR_T_DEG_VALUE (ADR_BASE + 0x0008) ++#define ADR_ADDR_STEP_PAR (ADR_BASE + 0x000C) ++#define ADR_ADDR_BLK_COORD_M_P_0 (ADR_BASE + 0x0010) ++#define ADR_ADDR_BLK_COORD_M_P_1 (ADR_BASE + 0x0014) ++#define ADR_ADDR_BLK_COORD_M_P_2 (ADR_BASE + 0x0018) ++#define ADR_ADDR_BLK_COORD_N_P_0 (ADR_BASE + 0x001C) ++#define ADR_ADDR_BLK_COORD_N_P_1 (ADR_BASE + 0x0020) ++#define ADR_ADDR_BLK_COORD_N_P_2 (ADR_BASE + 0x0024) ++#define ADR_ADDR_CEN_DIS_P_0 (ADR_BASE + 0x0028) ++#define ADR_ADDR_CEN_DIS_P_1 (ADR_BASE + 0x002C) ++#define ADR_ADDR_CEN_DIS_P_2 (ADR_BASE + 0x0030) ++#define ADR_ADDR_CEN_DIS_P_3 (ADR_BASE + 0x0034) ++#define ADR_ADDR_CEN_DIS_P_4 (ADR_BASE + 0x0038) ++#define ADR_ADDR_CEN_DIS_P_5 (ADR_BASE + 0x003C) ++#define ADR_ADDR_CEN_DIS_P_6 (ADR_BASE + 0x0040) ++#define ADR_ADDR_CEN_DIS_P_7 (ADR_BASE + 0x0044) ++#define ADR_ADDR_CEN_DIS_P_8 (ADR_BASE + 0x0048) ++#define ADR_ADDR_CEN_DIS_P_9 (ADR_BASE + 0x004C) ++#define ADR_ADDR_CEN_DIS_P_A (ADR_BASE + 0x0050) ++#define ADR_ADDR_CEN_DIS_P_B (ADR_BASE + 0x0054) ++#define ADR_ADDR_CEN_DIS_P_C (ADR_BASE + 0x0058) ++#define ADR_ADDR_CEN_DIS_P_D (ADR_BASE + 0x005C) ++#define ADR_ADDR_CEN_DIS_P_E (ADR_BASE + 0x0060) ++#define ADR_ADDR_CEN_DIS_P_F (ADR_BASE + 0x0064) ++#define ADR_ADDR_MAP_KPOINT_X_P0 (ADR_BASE + 0x0068) ++#define ADR_ADDR_MAP_KPOINT_X_P1 (ADR_BASE + 0x006C) ++#define ADR_ADDR_MAP_KPOINT_X_P2 (ADR_BASE + 0x0070) ++#define ADR_ADDR_MAP_KPOINT_X_P3 (ADR_BASE + 0x0074) ++#define ADR_ADDR_MAP_KPOINT_X_P4 (ADR_BASE + 0x0078) ++#define ADR_ADDR_MAP_KPOINT_X_P5 (ADR_BASE + 0x007C) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_0 (ADR_BASE + 0x0080) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_1 (ADR_BASE + 0x0084) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_2 (ADR_BASE + 0x0088) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_3 (ADR_BASE + 0x008C) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_4 (ADR_BASE + 0x0090) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_5 (ADR_BASE + 0x0094) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_0 (ADR_BASE + 0x0098) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_1 (ADR_BASE + 0x009C) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_2 (ADR_BASE + 0x00A0) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_3 (ADR_BASE + 0x00A4) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_4 (ADR_BASE + 0x00A8) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_5 (ADR_BASE + 0x00AC) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_0 (ADR_BASE + 0x00B0) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_1 (ADR_BASE + 0x00B4) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_2 (ADR_BASE + 0x00B8) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_3 (ADR_BASE + 0x00BC) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_4 (ADR_BASE + 0x00C0) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_5 (ADR_BASE + 0x00C4) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_0 (ADR_BASE + 0x00C8) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_1 (ADR_BASE + 0x00CC) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_2 (ADR_BASE + 0x00D0) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_3 (ADR_BASE + 0x00D4) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_4 (ADR_BASE + 0x00D8) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_5 (ADR_BASE + 0x00DC) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_0 (ADR_BASE + 0x00E0) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_1 (ADR_BASE + 0x00E4) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_2 (ADR_BASE + 0x00E8) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_3 (ADR_BASE + 0x00EC) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_4 (ADR_BASE + 0x00F0) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_5 (ADR_BASE + 0x00F4) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_0 (ADR_BASE + 0x00F8) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_1 (ADR_BASE + 0x00FC) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_2 (ADR_BASE + 0x0100) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_3 (ADR_BASE + 0x0104) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_4 (ADR_BASE + 0x0108) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_5 (ADR_BASE + 0x010C) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_0 (ADR_BASE + 0x0110) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_1 (ADR_BASE + 0x0114) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_2 (ADR_BASE + 0x0118) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_3 (ADR_BASE + 0x011C) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_4 (ADR_BASE + 0x0120) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_5 (ADR_BASE + 0x0124) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_0 (ADR_BASE + 0x0128) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_1 (ADR_BASE + 0x012C) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_2 (ADR_BASE + 0x0130) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_3 (ADR_BASE + 0x0134) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_4 (ADR_BASE + 0x0138) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_5 (ADR_BASE + 0x013C) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_0 (ADR_BASE + 0x0140) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_1 (ADR_BASE + 0x0144) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_2 (ADR_BASE + 0x0148) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_3 (ADR_BASE + 0x014C) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_4 (ADR_BASE + 0x0150) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_5 (ADR_BASE + 0x0154) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_0 (ADR_BASE + 0x0158) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_1 (ADR_BASE + 0x015C) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_2 (ADR_BASE + 0x0160) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_3 (ADR_BASE + 0x0164) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_4 (ADR_BASE + 0x0168) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_5 (ADR_BASE + 0x016C) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_0 (ADR_BASE + 0x0170) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_1 (ADR_BASE + 0x0174) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_2 (ADR_BASE + 0x0178) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_3 (ADR_BASE + 0x017C) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_4 (ADR_BASE + 0x0180) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_5 (ADR_BASE + 0x0184) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_0 (ADR_BASE + 0x0188) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_1 (ADR_BASE + 0x018C) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_2 (ADR_BASE + 0x0190) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_3 (ADR_BASE + 0x0194) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_4 (ADR_BASE + 0x0198) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_5 (ADR_BASE + 0x019C) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_0 (ADR_BASE + 0x01A0) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_1 (ADR_BASE + 0x01A4) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_2 (ADR_BASE + 0x01A8) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_3 (ADR_BASE + 0x01AC) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_4 (ADR_BASE + 0x01B0) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_5 (ADR_BASE + 0x01B4) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_0 (ADR_BASE + 0x01B8) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_1 (ADR_BASE + 0x01BC) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_2 (ADR_BASE + 0x01C0) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_3 (ADR_BASE + 0x01C4) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_4 (ADR_BASE + 0x01C8) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_5 (ADR_BASE + 0x01CC) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_0 (ADR_BASE + 0x01D0) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_1 (ADR_BASE + 0x01D4) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_2 (ADR_BASE + 0x01D8) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_3 (ADR_BASE + 0x01DC) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_4 (ADR_BASE + 0x01E0) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_5 (ADR_BASE + 0x01E4) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_0 (ADR_BASE + 0x01E8) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_1 (ADR_BASE + 0x01EC) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_2 (ADR_BASE + 0x01F0) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_3 (ADR_BASE + 0x01F4) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_4 (ADR_BASE + 0x01F8) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_5 (ADR_BASE + 0x01FC) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_0 (ADR_BASE + 0x0200) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_1 (ADR_BASE + 0x0204) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_2 (ADR_BASE + 0x0208) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_3 (ADR_BASE + 0x020C) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_4 (ADR_BASE + 0x0210) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_5 (ADR_BASE + 0x0214) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_0 (ADR_BASE + 0x0218) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_1 (ADR_BASE + 0x021C) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_2 (ADR_BASE + 0x0220) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_3 (ADR_BASE + 0x0224) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_4 (ADR_BASE + 0x0228) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_5 (ADR_BASE + 0x022C) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_0 (ADR_BASE + 0x0230) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_1 (ADR_BASE + 0x0234) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_2 (ADR_BASE + 0x0238) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_3 (ADR_BASE + 0x023C) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_4 (ADR_BASE + 0x0240) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_5 (ADR_BASE + 0x0244) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_0 (ADR_BASE + 0x0248) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_1 (ADR_BASE + 0x024C) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_2 (ADR_BASE + 0x0250) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_3 (ADR_BASE + 0x0254) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_4 (ADR_BASE + 0x0258) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_5 (ADR_BASE + 0x025C) ++#define ADR_ADDR_WEILUT20_P0 (ADR_BASE + 0x0260) ++#define ADR_ADDR_WEILUT20_P1 (ADR_BASE + 0x0264) ++#define ADR_ADDR_WEILUT20_P2 (ADR_BASE + 0x0268) ++#define ADR_ADDR_WEILUT20_P3 (ADR_BASE + 0x026C) ++#define ADR_ADDR_WEILUT20_P4 (ADR_BASE + 0x0270) ++#define ADR_ADDR_WEILUT20_P5 (ADR_BASE + 0x0274) ++#define ADR_ADDR_WEILUT20_P6 (ADR_BASE + 0x0278) ++#define ADR_ADDR_WEILUT20_P7 (ADR_BASE + 0x027C) ++#define ADR_ADDR_WEILUT02_P0 (ADR_BASE + 0x0280) ++#define ADR_ADDR_WEILUT02_P1 (ADR_BASE + 0x0284) ++#define ADR_ADDR_WEILUT02_P2 (ADR_BASE + 0x0288) ++#define ADR_ADDR_WEILUT02_P3 (ADR_BASE + 0x028C) ++#define ADR_ADDR_WEILUT02_P4 (ADR_BASE + 0x0290) ++#define ADR_ADDR_WEILUT02_P5 (ADR_BASE + 0x0294) ++#define ADR_ADDR_WEILUT02_P6 (ADR_BASE + 0x0298) ++#define ADR_ADDR_WEILUT02_P7 (ADR_BASE + 0x029C) ++#define ADR_ADDR_WEILUT12_P0 (ADR_BASE + 0x02A0) ++#define ADR_ADDR_WEILUT12_P1 (ADR_BASE + 0x02A4) ++#define ADR_ADDR_WEILUT12_P2 (ADR_BASE + 0x02A8) ++#define ADR_ADDR_WEILUT12_P3 (ADR_BASE + 0x02AC) ++#define ADR_ADDR_WEILUT12_P4 (ADR_BASE + 0x02B0) ++#define ADR_ADDR_WEILUT12_P5 (ADR_BASE + 0x02B4) ++#define ADR_ADDR_WEILUT12_P6 (ADR_BASE + 0x02B8) ++#define ADR_ADDR_WEILUT12_P7 (ADR_BASE + 0x02BC) ++#define ADR_ADDR_WEILUT22_P0 (ADR_BASE + 0x02C0) ++#define ADR_ADDR_WEILUT22_P1 (ADR_BASE + 0x02C4) ++#define ADR_ADDR_WEILUT22_P2 (ADR_BASE + 0x02C8) ++#define ADR_ADDR_WEILUT22_P3 (ADR_BASE + 0x02CC) ++#define ADR_ADDR_WEILUT22_P4 (ADR_BASE + 0x02D0) ++#define ADR_ADDR_WEILUT22_P5 (ADR_BASE + 0x02D4) ++#define ADR_ADDR_WEILUT22_P6 (ADR_BASE + 0x02D8) ++#define ADR_ADDR_WEILUT22_P7 (ADR_BASE + 0x02DC) ++#define ADR_ADDR_WEILUT21_P0 (ADR_BASE + 0x02E0) ++#define ADR_ADDR_WEILUT21_P1 (ADR_BASE + 0x02E4) ++#define ADR_ADDR_WEILUT21_P2 (ADR_BASE + 0x02E8) ++#define ADR_ADDR_WEILUT21_P3 (ADR_BASE + 0x02EC) ++#define ADR_ADDR_WEILUT21_P4 (ADR_BASE + 0x02F0) ++#define ADR_ADDR_WEILUT21_P5 (ADR_BASE + 0x02F4) ++#define ADR_ADDR_WEILUT21_P6 (ADR_BASE + 0x02F8) ++#define ADR_ADDR_WEILUT21_P7 (ADR_BASE + 0x02FC) ++#define ADR_ADDR_MAP_KPOINT_POW_P0 (ADR_BASE + 0x0300) ++#define ADR_ADDR_MAP_KPOINT_POW_P1 (ADR_BASE + 0x0304) ++#define ADR_ADDR_MAP_KPOINT_POW_P2 (ADR_BASE + 0x0308) ++#define ADR_ADDR_CTC_KPOINT_X_P0 (ADR_BASE + 0x0310) ++#define ADR_ADDR_CTC_KPOINT_X_P1 (ADR_BASE + 0x0314) ++#define ADR_ADDR_CON_W_DIS_P00 (ADR_BASE + 0x0320) ++#define ADR_ADDR_CON_W_DIS_P01 (ADR_BASE + 0x0324) ++#define ADR_ADDR_CON_W_DIS_P02 (ADR_BASE + 0x0328) ++#define ADR_ADDR_CON_W_DIS_P03 (ADR_BASE + 0x032C) ++#define ADR_ADDR_CON_W_DIS_P04 (ADR_BASE + 0x0330) ++#define ADR_ADDR_CON_W_DIS_P05 (ADR_BASE + 0x0334) ++#define ADR_ADDR_CON_W_DIS_P06 (ADR_BASE + 0x0338) ++#define ADR_ADDR_CON_W_DIS_P07 (ADR_BASE + 0x033C) ++#define ADR_ADDR_CON_W_DIS_P08 (ADR_BASE + 0x0340) ++#define ADR_ADDR_CON_W_DIS_P09 (ADR_BASE + 0x0344) ++#define ADR_ADDR_CON_W_DIS_P10 (ADR_BASE + 0x0348) ++#define ADR_ADDR_CON_W_DIS_P11 (ADR_BASE + 0x034C) ++#define ADR_ADDR_CON_W_DIS_P12 (ADR_BASE + 0x0350) ++#define ADR_ADDR_CON_W_DIS_P13 (ADR_BASE + 0x0354) ++#define ADR_ADDR_CON_W_DIS_P14 (ADR_BASE + 0x0358) ++#define ADR_ADDR_CON_W_DIS_P15 (ADR_BASE + 0x035C) ++#define ADR_ADDR_CON_W_DIS_P16 (ADR_BASE + 0x0360) ++#define ADR_ADDR_CON_W_DIS_P17 (ADR_BASE + 0x0364) ++#define ADR_ADDR_CON_W_DIS_P18 (ADR_BASE + 0x0368) ++#define ADR_ADDR_CON_W_DIS_P19 (ADR_BASE + 0x036C) ++#define ADR_ADDR_CON_W_DIS_P20 (ADR_BASE + 0x0370) ++#define ADR_ADDR_CON_W_DIS_P21 (ADR_BASE + 0x0374) ++#define ADR_ADDR_CON_W_DIS_P22 (ADR_BASE + 0x0378) ++#define ADR_ADDR_CON_W_DIS_P23 (ADR_BASE + 0x037C) ++#define ADR_ADDR_CON_W_DIS_P24 (ADR_BASE + 0x0380) ++#define ADR_ADDR_CON_W_DIS_P25 (ADR_BASE + 0x0384) ++#define ADR_ADDR_CON_W_DIS_P26 (ADR_BASE + 0x0388) ++#define ADR_ADDR_CON_W_DIS_P27 (ADR_BASE + 0x038C) ++#define ADR_ADDR_CON_W_DIS_P28 (ADR_BASE + 0x0390) ++#define ADR_ADDR_CON_W_DIS_P29 (ADR_BASE + 0x0394) ++#define ADR_ADDR_CON_W_DIS_P30 (ADR_BASE + 0x0398) ++#define ADR_ADDR_CON_W_DIS_P31 (ADR_BASE + 0x039C) ++#define ADR_ADDR_CTC_KPOINT_MUX_P0 (ADR_BASE + 0x03A0) ++#define ADR_ADDR_CTC_KPOINT_MUX_P1 (ADR_BASE + 0x03A4) ++#define ADR_ADDR_CTC_RATIO (ADR_BASE + 0x03A8) ++#define ADR_ADDR_MIN_KPOINT_X_P0 (ADR_BASE + 0x03B0) ++#define ADR_ADDR_MIN_KPOINT_X_P1 (ADR_BASE + 0x03B4) ++#define ADR_ADDR_MIN_KPOINT_X_P2 (ADR_BASE + 0x03B8) ++#define ADR_ADDR_MIN_KPOINT_X_P3 (ADR_BASE + 0x03BC) ++#define ADR_ADDR_MIN_KPOINT_X_P4 (ADR_BASE + 0x03C0) ++#define ADR_ADDR_MIN_KPOINT_X_P5 (ADR_BASE + 0x03C4) ++#define ADR_ADDR_MIN_KPOINT_Y_P0 (ADR_BASE + 0x03C8) ++#define ADR_ADDR_MIN_KPOINT_Y_P1 (ADR_BASE + 0x03CC) ++#define ADR_ADDR_MIN_KPOINT_Y_P2 (ADR_BASE + 0x03D0) ++#define ADR_ADDR_MIN_KPOINT_Y_P3 (ADR_BASE + 0x03D4) ++#define ADR_ADDR_MIN_KPOINT_Y_P4 (ADR_BASE + 0x03D8) ++#define ADR_ADDR_MIN_KPOINT_Y_P5 (ADR_BASE + 0x03DC) ++#define ADR_ADDR_MIN_KPOINT_POW_P0 (ADR_BASE + 0x03E0) ++#define ADR_ADDR_MIN_KPOINT_POW_P1 (ADR_BASE + 0x03E4) ++#define ADR_ADDR_MIN_KPOINT_POW_P2 (ADR_BASE + 0x03E8) ++#define ADR_ADDR_COC_KPOINT_X_P0 (ADR_BASE + 0x03F0) ++#define ADR_ADDR_COC_KPOINT_X_P1 (ADR_BASE + 0x03F4) ++#define ADR_ADDR_COC_KPOINT_X_P2 (ADR_BASE + 0x03F8) ++#define ADR_ADDR_COC_KPOINT_X_P3 (ADR_BASE + 0x03FC) ++#define ADR_ADDR_COC_KPOINT_X_P4 (ADR_BASE + 0x0400) ++#define ADR_ADDR_COC_KPOINT_X_P5 (ADR_BASE + 0x0404) ++#define ADR_ADDR_COC_THRES (ADR_BASE + 0x0408) ++#define ADR_ADDR_COC_STREN (ADR_BASE + 0x040C) ++#define ADR_ADDR_COC_MODE (ADR_BASE + 0x0410) ++#define ADR_ADDR_COC_KPOINT_POW_P0 (ADR_BASE + 0x0414) ++#define ADR_ADDR_COC_KPOINT_POW_P1 (ADR_BASE + 0x0418) ++#define ADR_ADDR_COC_KPOINT_POW_P2 (ADR_BASE + 0x041C) ++#define ADR_ADDR_STAT_BLOCK_DIFF_P_0 (ADR_BASE + 0x0420) ++#define ADR_ADDR_STAT_BLOCK_DIFF_P_1 (ADR_BASE + 0x0424) ++#define ADR_ADDR_BANK_ADDR_P0 (ADR_BASE + 0x0428) ++#define ADR_ADDR_BANK_ADDR_P1 (ADR_BASE + 0x042C) ++#define ADR_ADDR_BANK_ADDR_P2 (ADR_BASE + 0x0430) ++#define ADR_ADDR_BANK_ADDR_P3 (ADR_BASE + 0x0434) ++#define ADR_ADDR_BANK_NUMBER (ADR_BASE + 0x0438) ++#define ADR_ADDR_FRAME_ADDR (ADR_BASE + 0x043C) ++#define ADR_ADDR_FRAME_ID (ADR_BASE + 0x0440) ++#define ADR_ADDR_FRAME_RATE (ADR_BASE + 0x0444) ++#define ADR_ADDR_SHADOW_CTRL (ADR_BASE + 0x0448) ++#define ADR_ADDR_DEBUG_SIGNAL_0 (ADR_BASE + 0x0450) ++#define ADR_ADDR_DEBUG_SIGNAL_1 (ADR_BASE + 0x0454) ++#define ADR_ADDR_DEBUG_SIGNAL_2 (ADR_BASE + 0x0458) ++#define ADR_ADDR_DEBUG_SIGNAL_3 (ADR_BASE + 0x045C) ++#define ADR_ADDR_DEBUG_SIGNAL_4 (ADR_BASE + 0x0460) ++#define ADR_ADDR_DEBUG_SIGNAL_5 (ADR_BASE + 0x0464) ++ ++//============================================================ ++// IRINT ++//============================================================ ++#define IRINT_ADDR_T_VERSION (IRINT_BASE + 0x0000) ++#define IRINT_ADDR_T_DBG_SEL (IRINT_BASE + 0x0004) ++#define IRINT_ADDR_T_DBG_VALUE (IRINT_BASE + 0x0008) ++#define IRINT_ADDR_DIFF_PAR (IRINT_BASE + 0x0010) ++#define IRINT_ADDR_MIN_PAR (IRINT_BASE + 0x0014) ++ ++//============================================================ ++// DMSC ++//============================================================ ++#define DMSC_ADDR_SYNC (DMSC_BASE + 0x0000) ++#define DMSC_ADDR_G_STD_STREN (DMSC_BASE + 0x0004) ++#define DMSC_ADDR_UU_THRES (DMSC_BASE + 0x0008) ++#define DMSC_ADDR_ALIAS_DIR_DIFF (DMSC_BASE + 0x000C) ++#define DMSC_ADDR_WIN5_HV_EDGE_THRES (DMSC_BASE + 0x0010) ++#define DMSC_ADDR_HV_EDGE_THRES (DMSC_BASE + 0x0014) ++#define DMSC_ADDR_HV_EDGE (DMSC_BASE + 0x0020) ++#define DMSC_ADDR_AA_EDGE_THRES (DMSC_BASE + 0x0024) ++#define DMSC_ADDR_AA_EDGE (DMSC_BASE + 0x0028) ++#define DMSC_ADDR_HVAA_EDGE_THRES (DMSC_BASE + 0x002C) ++#define DMSC_ADDR_HVAA_EDGE (DMSC_BASE + 0x0030) ++#define DMSC_ADDR_ALIAS_STREN (DMSC_BASE + 0x0034) ++#define DMSC_ADDR_ALIAS_THRES (DMSC_BASE + 0x0038) ++#define DMSC_ADDR_NOR_ALIAS_BLUR (DMSC_BASE + 0x003C) ++#define DMSC_ADDR_NOR_UU_WEI_STREN (DMSC_BASE + 0x0040) ++#define DMSC_ADDR_SP_D_V2_SIGMA (DMSC_BASE + 0x0044) ++#define DMSC_ADDR_SP_D_W_SP_STREN (DMSC_BASE + 0x0048) ++#define DMSC_ADDR_SP_D_LL_STREN (DMSC_BASE + 0x004C) ++#define DMSC_ADDR_SP_D_LL_THRES (DMSC_BASE + 0x0050) ++#define DMSC_ADDR_SP_D_W_LIMIT (DMSC_BASE + 0x0054) ++#define DMSC_ADDR_SP_D_B_LIMIT (DMSC_BASE + 0x0058) ++#define DMSC_ADDR_SP_UD_V2_SIGMA (DMSC_BASE + 0x005C) ++#define DMSC_ADDR_SP_UD_W_SP_STREN (DMSC_BASE + 0x0060) ++#define DMSC_ADDR_SP_UD_LL_STREN (DMSC_BASE + 0x0064) ++#define DMSC_ADDR_SP_UD_LL_THRES (DMSC_BASE + 0x0068) ++#define DMSC_ADDR_SP_UD_W_LIMIT (DMSC_BASE + 0x006C) ++#define DMSC_ADDR_SP_UD_B_LIMIT (DMSC_BASE + 0x0070) ++#define DMSC_ADDR_SP_NOR_ALIAS_THRES (DMSC_BASE + 0x0074) ++#define DMSC_ADDR_ALIAS_FUSION_THRES (DMSC_BASE + 0x0078) ++#define DMSC_ADDR_ALIAS_DIR_INTP_SP_STREN (DMSC_BASE + 0x007C) ++#define DMSC_ADDR_FC_ALIAS_STREN (DMSC_BASE + 0x0080) ++#define DMSC_ADDR_FC_ALIAS_THRES (DMSC_BASE + 0x0084) ++#define DMSC_ADDR_FC_NOR_SAT_THRES (DMSC_BASE + 0x0088) ++#define DMSC_ADDR_FC_TEXT_THRES (DMSC_BASE + 0x008C) ++#define DMSC_ADDR_FC_NOR_EDGE_SLOPE (DMSC_BASE + 0x0090) ++#define DMSC_ADDR_UU_NP_ARRAY_RG0 (DMSC_BASE + 0x0094) ++#define DMSC_ADDR_UU_NP_ARRAY_RG1 (DMSC_BASE + 0x0098) ++#define DMSC_ADDR_UU_NP_ARRAY_RG2 (DMSC_BASE + 0x009C) ++#define DMSC_ADDR_UU_NP_ARRAY_RG3 (DMSC_BASE + 0x00A0) ++#define DMSC_ADDR_UU_NP_ARRAY_RG4 (DMSC_BASE + 0x00A4) ++#define DMSC_ADDR_UU_NP_ARRAY_RG5 (DMSC_BASE + 0x00A8) ++#define DMSC_ADDR_UU_NP_ARRAY_RG6 (DMSC_BASE + 0x00AC) ++#define DMSC_ADDR_UU_NP_ARRAY_RG7 (DMSC_BASE + 0x00B0) ++#define DMSC_ADDR_SP_D_SIGMA_3_NP_ARRAY_RG0 (DMSC_BASE + 0x00B4) ++#define DMSC_ADDR_SP_D_SIGMA_3_NP_ARRAY_RG1 (DMSC_BASE + 0x00B8) ++#define DMSC_ADDR_SP_D_SIGMA_3_NP_ARRAY_RG2 (DMSC_BASE + 0x00BC) ++#define DMSC_ADDR_SP_D_W_WEI_NP_ARRAY_RG0 (DMSC_BASE + 0x00C0) ++#define DMSC_ADDR_SP_D_W_WEI_NP_ARRAY_RG1 (DMSC_BASE + 0x00C4) ++#define DMSC_ADDR_SP_D_W_WEI_NP_ARRAY_RG2 (DMSC_BASE + 0x00C8) ++#define DMSC_ADDR_SP_D_W_WEI_NP_ARRAY_RG3 (DMSC_BASE + 0x00CC) ++#define DMSC_ADDR_SP_D_B_WEI_NP_ARRAY_RG0 (DMSC_BASE + 0x00D0) ++#define DMSC_ADDR_SP_D_B_WEI_NP_ARRAY_RG1 (DMSC_BASE + 0x00D4) ++#define DMSC_ADDR_SP_D_B_WEI_NP_ARRAY_RG2 (DMSC_BASE + 0x00D8) ++#define DMSC_ADDR_SP_D_B_WEI_NP_ARRAY_RG3 (DMSC_BASE + 0x00DC) ++#define DMSC_ADDR_SP_UD_W_WEI_NP_ARRAY_RG0 (DMSC_BASE + 0x00E0) ++#define DMSC_ADDR_SP_UD_W_WEI_NP_ARRAY_RG1 (DMSC_BASE + 0x00E4) ++#define DMSC_ADDR_SP_UD_W_WEI_NP_ARRAY_RG2 (DMSC_BASE + 0x00E8) ++#define DMSC_ADDR_SP_UD_W_WEI_NP_ARRAY_RG3 (DMSC_BASE + 0x00EC) ++#define DMSC_ADDR_SP_UD_B_WEI_NP_ARRAY_RG0 (DMSC_BASE + 0x00F0) ++#define DMSC_ADDR_SP_UD_B_WEI_NP_ARRAY_RG1 (DMSC_BASE + 0x00F4) ++#define DMSC_ADDR_SP_UD_B_WEI_NP_ARRAY_RG2 (DMSC_BASE + 0x00F8) ++#define DMSC_ADDR_SP_UD_B_WEI_NP_ARRAY_RG3 (DMSC_BASE + 0x00FC) ++#define DMSC_ADDR_OUT_OPT (DMSC_BASE + 0x0100) ++#define DMSC_ADDR_SP_DEBUG_REG_0 (DMSC_BASE + 0x0104) ++#define DMSC_ADDR_SP_DEBUG_REG_1 (DMSC_BASE + 0x0108) ++#define DMSC_ADDR_FC_TEXT_2_STREN (DMSC_BASE + 0x010C) ++#define DMSC_ADDR_FC_TEXT_2_THRES (DMSC_BASE + 0x0110) ++#define DMSC_ADDR_FC_THRES_H_1 (DMSC_BASE + 0x0114) ++#define DMSC_ADDR_FC_THRES_H_2 (DMSC_BASE + 0x0118) ++ ++//============================================================ ++// CCM ++//============================================================ ++#define CCM_ADDR_REG_CTRL (CCM_BASE + 0x0000) ++#define CCM_ADDR_CCM_RRRG (CCM_BASE + 0x0004) ++#define CCM_ADDR_CCM_RBGR (CCM_BASE + 0x0008) ++#define CCM_ADDR_CCM_GGGB (CCM_BASE + 0x000c) ++#define CCM_ADDR_CCM_BRBG (CCM_BASE + 0x0010) ++#define CCM_ADDR_CCM_BB (CCM_BASE + 0x0014) ++#define CCM_ADDR_DP_CFG (CCM_BASE + 0x0018) ++#define CCM_ADDR_DP_SLOP (CCM_BASE + 0x001c) ++#define CCM_ADDR_SAT_THRES (CCM_BASE + 0x0020) ++ ++//=============================================== ++// DEFOG ++//=============================================== ++#define DEFOG_ADDR_BLOCK_COORD_M_01_00 (DEFOG_BASE + 0x0000) ++#define DEFOG_ADDR_BLOCK_COORD_M_03_02 (DEFOG_BASE + 0x0004) ++#define DEFOG_ADDR_BLOCK_COORD_M_05_04 (DEFOG_BASE + 0x0008) ++#define DEFOG_ADDR_BLOCK_COORD_M_07_06 (DEFOG_BASE + 0x000C) ++#define DEFOG_ADDR_BLOCK_COORD_M_09_08 (DEFOG_BASE + 0x0010) ++#define DEFOG_ADDR_BLOCK_COORD_M____10 (DEFOG_BASE + 0x0014) ++#define DEFOG_ADDR_BLOCK_COORD_N_01_00 (DEFOG_BASE + 0x0020) ++#define DEFOG_ADDR_BLOCK_COORD_N_03_02 (DEFOG_BASE + 0x0024) ++#define DEFOG_ADDR_BLOCK_COORD_N_05_04 (DEFOG_BASE + 0x0028) ++#define DEFOG_ADDR_BLOCK_COORD_N_07_06 (DEFOG_BASE + 0x002C) ++#define DEFOG_ADDR_BLOCK_COORD_N_09_08 (DEFOG_BASE + 0x0030) ++#define DEFOG_ADDR_BLOCK_COORD_N_11_10 (DEFOG_BASE + 0x0034) ++#define DEFOG_ADDR_BLOCK_COORD_N_13_12 (DEFOG_BASE + 0x0038) ++#define DEFOG_ADDR_BLOCK_COORD_N_15_14 (DEFOG_BASE + 0x003C) ++#define DEFOG_ADDR_BLOCK_COORD_N_17_16 (DEFOG_BASE + 0x0040) ++#define DEFOG_ADDR_BLOCK_COORD_N_19_18 (DEFOG_BASE + 0x0044) ++#define DEFOG_ADDR_BLOCK_COORD_N____20 (DEFOG_BASE + 0x0048) ++#define DEFOG_ADDR_CT3X3_DIS_01_00 (DEFOG_BASE + 0x0050) ++#define DEFOG_ADDR_CT3X3_DIS_03_02 (DEFOG_BASE + 0x0054) ++#define DEFOG_ADDR_CT3X3_DIS_05_04 (DEFOG_BASE + 0x0058) ++#define DEFOG_ADDR_CT3X3_DIS_07_06 (DEFOG_BASE + 0x005C) ++#define DEFOG_ADDR_CT3X3_DIS_09_08 (DEFOG_BASE + 0x0060) ++#define DEFOG_ADDR_CT3X3_DIS_11_10 (DEFOG_BASE + 0x0064) ++#define DEFOG_ADDR_CT3X3_DIS_13_12 (DEFOG_BASE + 0x0068) ++#define DEFOG_ADDR_CT3X3_DIS_15_14 (DEFOG_BASE + 0x006C) ++#define DEFOG_ADDR_CT3X3_DIS_17_16 (DEFOG_BASE + 0x0070) ++#define DEFOG_ADDR_CT3X3_DIS_19_18 (DEFOG_BASE + 0x0074) ++#define DEFOG_ADDR_CT3X3_DIS_21_20 (DEFOG_BASE + 0x0078) ++#define DEFOG_ADDR_CT3X3_DIS_23_22 (DEFOG_BASE + 0x007C) ++#define DEFOG_ADDR_CT5X5_DIS_01_00 (DEFOG_BASE + 0x0080) ++#define DEFOG_ADDR_CT5X5_DIS_03_02 (DEFOG_BASE + 0x0084) ++#define DEFOG_ADDR_CT5X5_DIS_05_04 (DEFOG_BASE + 0x0088) ++#define DEFOG_ADDR_CT5X5_DIS_07_06 (DEFOG_BASE + 0x008C) ++#define DEFOG_ADDR_CT5X5_DIS_09_08 (DEFOG_BASE + 0x0090) ++#define DEFOG_ADDR_CT5X5_DIS_11_10 (DEFOG_BASE + 0x0094) ++#define DEFOG_ADDR_CT5X5_DIS_13_12 (DEFOG_BASE + 0x0098) ++#define DEFOG_ADDR_CT5X5_DIS_15_14 (DEFOG_BASE + 0x009C) ++#define DEFOG_ADDR_CT5X5_DIS_17_16 (DEFOG_BASE + 0x00A0) ++#define DEFOG_ADDR_CT5X5_DIS_19_18 (DEFOG_BASE + 0x00A4) ++#define DEFOG_ADDR_CT5X5_DIS_21_20 (DEFOG_BASE + 0x00A8) ++#define DEFOG_ADDR_CT5X5_DIS_23_22 (DEFOG_BASE + 0x00AC) ++#define DEFOG_ADDR_CT5X5_DIS_25_24 (DEFOG_BASE + 0x00B0) ++#define DEFOG_ADDR_CT5X5_DIS_27_26 (DEFOG_BASE + 0x00B4) ++#define DEFOG_ADDR_CT5X5_DIS_29_28 (DEFOG_BASE + 0x00B8) ++#define DEFOG_ADDR_CT5X5_DIS_31_30 (DEFOG_BASE + 0x00BC) ++#define DEFOG_ADDR_WEIGHTLUT02_05_00 (DEFOG_BASE + 0x00C0) ++#define DEFOG_ADDR_WEIGHTLUT02_11_06 (DEFOG_BASE + 0x00C4) ++#define DEFOG_ADDR_WEIGHTLUT02_17_12 (DEFOG_BASE + 0x00C8) ++#define DEFOG_ADDR_WEIGHTLUT02_23_18 (DEFOG_BASE + 0x00CC) ++#define DEFOG_ADDR_WEIGHTLUT02_29_24 (DEFOG_BASE + 0x00D0) ++#define DEFOG_ADDR_WEIGHTLUT02_31_30 (DEFOG_BASE + 0x00D4) ++#define DEFOG_ADDR_WEIGHTLUT20_05_00 (DEFOG_BASE + 0x00E0) ++#define DEFOG_ADDR_WEIGHTLUT20_11_06 (DEFOG_BASE + 0x00E4) ++#define DEFOG_ADDR_WEIGHTLUT20_17_12 (DEFOG_BASE + 0x00E8) ++#define DEFOG_ADDR_WEIGHTLUT20_23_18 (DEFOG_BASE + 0x00EC) ++#define DEFOG_ADDR_WEIGHTLUT20_29_24 (DEFOG_BASE + 0x00F0) ++#define DEFOG_ADDR_WEIGHTLUT20_31_30 (DEFOG_BASE + 0x00F4) ++#define DEFOG_ADDR_WEIGHTLUT21_05_00 (DEFOG_BASE + 0x0100) ++#define DEFOG_ADDR_WEIGHTLUT21_11_06 (DEFOG_BASE + 0x0104) ++#define DEFOG_ADDR_WEIGHTLUT21_17_12 (DEFOG_BASE + 0x0108) ++#define DEFOG_ADDR_WEIGHTLUT21_23_18 (DEFOG_BASE + 0x010C) ++#define DEFOG_ADDR_WEIGHTLUT21_29_24 (DEFOG_BASE + 0x0110) ++#define DEFOG_ADDR_WEIGHTLUT21_31_30 (DEFOG_BASE + 0x0114) ++#define DEFOG_ADDR_WEIGHTLUT12_05_00 (DEFOG_BASE + 0x0120) ++#define DEFOG_ADDR_WEIGHTLUT12_11_06 (DEFOG_BASE + 0x0124) ++#define DEFOG_ADDR_WEIGHTLUT12_17_12 (DEFOG_BASE + 0x0128) ++#define DEFOG_ADDR_WEIGHTLUT12_23_18 (DEFOG_BASE + 0x012C) ++#define DEFOG_ADDR_WEIGHTLUT12_29_24 (DEFOG_BASE + 0x0130) ++#define DEFOG_ADDR_WEIGHTLUT12_31_30 (DEFOG_BASE + 0x0134) ++#define DEFOG_ADDR_WEIGHTLUT22_05_00 (DEFOG_BASE + 0x0140) ++#define DEFOG_ADDR_WEIGHTLUT22_11_06 (DEFOG_BASE + 0x0144) ++#define DEFOG_ADDR_WEIGHTLUT22_17_12 (DEFOG_BASE + 0x0148) ++#define DEFOG_ADDR_WEIGHTLUT22_23_18 (DEFOG_BASE + 0x014C) ++#define DEFOG_ADDR_WEIGHTLUT22_29_24 (DEFOG_BASE + 0x0150) ++#define DEFOG_ADDR_WEIGHTLUT22_31_30 (DEFOG_BASE + 0x0154) ++#define DEFOG_ADDR_BANK_BUFF_NUM (DEFOG_BASE + 0x0160) ++#define DEFOG_ADDR_BANK_ADDR_0 (DEFOG_BASE + 0x0164) ++#define DEFOG_ADDR_BANK_ADDR_1 (DEFOG_BASE + 0x0168) ++#define DEFOG_ADDR_BANK_ADDR_2 (DEFOG_BASE + 0x016C) ++#define DEFOG_ADDR_BANK_ADDR_3 (DEFOG_BASE + 0x0170) ++#define DEFOG_ADDR_PARA (DEFOG_BASE + 0x0180) ++#define DEFOG_ADDR_CLOR_CTRL_X3210 (DEFOG_BASE + 0x0190) ++#define DEFOG_ADDR_CLOR_CTRL_Y3210 (DEFOG_BASE + 0x0194) ++#define DEFOG_ADDR_CLOR_CTRL_XY44 (DEFOG_BASE + 0x0198) ++#define DEFOG_ADDR_CLOR_CTRL_POW3210 (DEFOG_BASE + 0x019C) ++#define DEFOG_ADDR_TRANS_DARK_CTRL_X3210 (DEFOG_BASE + 0x01A0) ++#define DEFOG_ADDR_TRANS_DARK_CTRL_Y3210 (DEFOG_BASE + 0x01A4) ++#define DEFOG_ADDR_TRANS_DARK_CTRL_XY44 (DEFOG_BASE + 0x01A8) ++#define DEFOG_ADDR_TRANS_DARK_CTRL_POW3210 (DEFOG_BASE + 0x01AC) ++#define DEFOG_ADDR_OVEREXPO_WGT_X3210 (DEFOG_BASE + 0x01B0) ++#define DEFOG_ADDR_OVEREXPO_WGT_Y3210 (DEFOG_BASE + 0x01B4) ++#define DEFOG_ADDR_OVEREXPO_WGT_POW210 (DEFOG_BASE + 0x01B8) ++#define DEFOG_ADDR_DARKSPC_WGT_X3210 (DEFOG_BASE + 0x01C0) ++#define DEFOG_ADDR_DARKSPC_WGT_Y3210 (DEFOG_BASE + 0x01C4) ++#define DEFOG_ADDR_DARKSPC_WGT_POW210 (DEFOG_BASE + 0x01C8) ++#define DEFOG_ADDR_FRAME_RATE (DEFOG_BASE + 0x01D0) ++#define DEFOG_ADDR_CTRL (DEFOG_BASE + 0x01E0) ++#define DEFOG_ADDR_FRAME_ADDR (DEFOG_BASE + 0x0200) ++#define DEFOG_ADDR_FRAME_ID (DEFOG_BASE + 0x0204) ++#define DEFOG_ADDR_DEBUG_SIGNAL_0 (DEFOG_BASE + 0x0208) ++#define DEFOG_ADDR_DEBUG_SIGNAL_1 (DEFOG_BASE + 0x020C) ++#define DEFOG_ADDR_DEBUG_SIGNAL_2 (DEFOG_BASE + 0x0210) ++#define DEFOG_ADDR_DEBUG_SIGNAL_3 (DEFOG_BASE + 0x0214) ++#define DEFOG_ADDR_DEBUG_SIGNAL_4 (DEFOG_BASE + 0x0218) ++#define DEFOG_ADDR_BLOCK_CFG_SEL (DEFOG_BASE + 0x0220) ++#define DEFOG_ADDR_BLOCK_CFG_BASE (DEFOG_BASE + 0x0224) ++ ++//============================================================ ++// CSC ++//============================================================ ++#define CSC_ADDR_CTRL (CSC_BASE + 0x0000) ++#define CSC_ADDR_SUB (CSC_BASE + 0x0004) ++#define CSC_ADDR_PAR_0 (CSC_BASE + 0x0010) ++#define CSC_ADDR_PAR_1 (CSC_BASE + 0x0014) ++#define CSC_ADDR_PAR_2 (CSC_BASE + 0x0018) ++#define CSC_ADDR_OFF_SET (CSC_BASE + 0x0020) ++#define CSC_ADDR_CLIP (CSC_BASE + 0x0030) ++ ++//============================================================ ++// CLM ++//============================================================ ++#define CLM_ADDR_REG_CTRL (CLM_BASE + 0x0000) ++#define CLM_ADDR_LUT_SHIFT (CLM_BASE + 0x0004) ++#define CLM_ADDR_CSC_RB (CLM_BASE + 0x0008) ++#define CLM_ADDR_CSC_G (CLM_BASE + 0x000c) ++#define CLM_ADDR_CSC_U (CLM_BASE + 0x0010) ++#define CLM_ADDR_CSC_V (CLM_BASE + 0x0014) ++#define CLM_ADDR_CSC_Y (CLM_BASE + 0x0018) ++#define CLM_ADDR_CA_S_THRES (CLM_BASE + 0x001c) ++#define CLM_ADDR_CA_S_SLOP (CLM_BASE + 0x0020) ++#define CLM_ADDR_CA_V_THRES (CLM_BASE + 0x0024) ++#define CLM_ADDR_CA_V_SLOP (CLM_BASE + 0x0028) ++#define CLM_ADDR_DEBUG0 (CLM_BASE + 0x002c) ++ ++//============================================================ ++// Sharpen ++//============================================================ ++#define SHARPEN_ADDR_SYNC (SP_BASE + 0x0000) ++#define SHARPEN_ADDR_STD_DIV_OPT (SP_BASE + 0x0004) ++#define SHARPEN_ADDR_V2_SIGMA (SP_BASE + 0x0008) ++#define SHARPEN_ADDR_W_WEI_SEG_OPT (SP_BASE + 0x000C) ++#define SHARPEN_ADDR_STREN (SP_BASE + 0x0010) ++#define SHARPEN_ADDR_THRES (SP_BASE + 0x0014) ++#define SHARPEN_ADDR_UU_SLOPE (SP_BASE + 0x0018) ++#define SHARPEN_ADDR_UU_NP_ARRAY_RG0 (SP_BASE + 0x001C) ++#define SHARPEN_ADDR_UU_NP_ARRAY_RG1 (SP_BASE + 0x0020) ++#define SHARPEN_ADDR_UU_NP_ARRAY_RG2 (SP_BASE + 0x0024) ++#define SHARPEN_ADDR_UU_NP_ARRAY_RG3 (SP_BASE + 0x0028) ++#define SHARPEN_ADDR_V1_SIGMA_NP_ARRAY_RG0 (SP_BASE + 0x002C) ++#define SHARPEN_ADDR_V1_SIGMA_NP_ARRAY_RG1 (SP_BASE + 0x0030) ++#define SHARPEN_ADDR_V1_SIGMA_NP_ARRAY_RG2 (SP_BASE + 0x0034) ++#define SHARPEN_ADDR_W_WEI_NP_ARRAY_RG0 (SP_BASE + 0x0038) ++#define SHARPEN_ADDR_W_WEI_NP_ARRAY_RG1 (SP_BASE + 0x003C) ++#define SHARPEN_ADDR_W_WEI_NP_ARRAY_RG2 (SP_BASE + 0x0040) ++#define SHARPEN_ADDR_W_WEI_NP_ARRAY_RG3 (SP_BASE + 0x0044) ++#define SHARPEN_ADDR_B_WEI_NP_ARRAY_RG0 (SP_BASE + 0x0048) ++#define SHARPEN_ADDR_B_WEI_NP_ARRAY_RG1 (SP_BASE + 0x004C) ++#define SHARPEN_ADDR_B_WEI_NP_ARRAY_RG2 (SP_BASE + 0x0050) ++#define SHARPEN_ADDR_B_WEI_NP_ARRAY_RG3 (SP_BASE + 0x0054) ++ ++//============================================================ ++// MDNS ++//============================================================ ++#define MDNS_ADDR_T_VERSION (MDNS_BASE + 0x0000) ++#define MDNS_ADDR_REG_CTRL (MDNS_BASE + 0x0004) ++#define MDNS_ADDR_DBG_SEL (MDNS_BASE + 0x0008) ++#define MDNS_ADDR_DBG_VALUE (MDNS_BASE + 0x000C) ++#define MDNS_ADDR_Y_REF_BASE_ADDR (MDNS_BASE + 0x0010) ++#define MDNS_ADDR_Y_REF_STRIDE (MDNS_BASE + 0x0014) ++#define MDNS_ADDR_Y_REF_FRM_SIZE (MDNS_BASE + 0x0018) ++#define MDNS_ADDR_Y_REF_FRM_NUM (MDNS_BASE + 0x001C) ++#define MDNS_ADDR_UV_REF_BASE_ADDR (MDNS_BASE + 0x0020) ++#define MDNS_ADDR_UV_REF_STRIDE (MDNS_BASE + 0x0024) ++#define MDNS_ADDR_UV_REF_FRM_SIZE (MDNS_BASE + 0x0028) ++#define MDNS_ADDR_UV_REF_FRM_NUM (MDNS_BASE + 0x002C) ++#define MDNS_ADDR_STA_BASE_ADDR (MDNS_BASE + 0x0030) ++#define MDNS_ADDR_STA_STRIDE (MDNS_BASE + 0x0034) ++#define MDNS_ADDR_STA_FRM_SIZE (MDNS_BASE + 0x0038) ++#define MDNS_ADDR_STA_FRM_NUM (MDNS_BASE + 0x003C) ++#define MDNS_ADDR_PBT_BASE_ADDR (MDNS_BASE + 0x0040) ++#define MDNS_ADDR_PBT_STRIDE (MDNS_BASE + 0x0044) ++#define MDNS_ADDR_PBT_FRM_SIZE (MDNS_BASE + 0x0048) ++#define MDNS_ADDR_PBT_FRM_NUM (MDNS_BASE + 0x004C) ++#define MDNS_ADDR_T_FRM_NUM (MDNS_BASE + 0x0050) ++#define MDNS_ADDR_T_TOP_FUN (MDNS_BASE + 0x0060) ++#define MDNS_ADDR_STA_OVER_CFG (MDNS_BASE + 0x0070) ++#define MDNS_ADDR_STA_WIN_CFG (MDNS_BASE + 0x0074) ++#define MDNS_ADDR_STA_BLK_SIZE (MDNS_BASE + 0x0078) ++#define MDNS_ADDR_STA_BLK_NUM (MDNS_BASE + 0x007C) ++#define MDNS_ADDR_STA_MAX_NUM (MDNS_BASE + 0x0080) ++#define MDNS_ADDR_STA_DIFF_THRES (MDNS_BASE + 0x0084) ++#define MDNS_ADDR_STA_MV_NUM_THRES00 (MDNS_BASE + 0x0090) ++#define MDNS_ADDR_STA_MV_NUM_THRES01 (MDNS_BASE + 0x0094) ++#define MDNS_ADDR_STA_MV_NUM_THRES10 (MDNS_BASE + 0x0098) ++#define MDNS_ADDR_STA_MV_NUM_THRES11 (MDNS_BASE + 0x009C) ++#define MDNS_ADDR_PBT_START_POINT (MDNS_BASE + 0x00A0) ++#define MDNS_ADDR_PBT_WIN_SIZE (MDNS_BASE + 0x00A4) ++#define MDNS_ADDR_PBT_OVER_CFG (MDNS_BASE + 0x00B0) ++#define MDNS_ADDR_PBT_WIN_CFG (MDNS_BASE + 0x00B4) ++#define MDNS_ADDR_PBT_BLK_SIZE (MDNS_BASE + 0x00B8) ++#define MDNS_ADDR_PBT_BLK_NUM (MDNS_BASE + 0x00BC) ++#define MDNS_ADDR_PBT_MAX_NUM (MDNS_BASE + 0x00C0) ++#define MDNS_ADDR_PBT_DIFF_THRES (MDNS_BASE + 0x00C4) ++#define MDNS_ADDR_PBT_MV_NUM_THRES00 (MDNS_BASE + 0x00D0) ++#define MDNS_ADDR_PBT_MV_NUM_THRES01 (MDNS_BASE + 0x00D4) ++#define MDNS_ADDR_PBT_MV_NUM_THRES10 (MDNS_BASE + 0x00D8) ++#define MDNS_ADDR_PBT_MV_NUM_THRES11 (MDNS_BASE + 0x00DC) ++#define MDNS_ADDR_Y_CUT_VALUE (MDNS_BASE + 0x00E0) ++#define MDNS_ADDR_Y_EDGE_PAR (MDNS_BASE + 0x00E4) ++#define MDNS_ADDR_Y_BI_PAR0 (MDNS_BASE + 0x00E8) ++#define MDNS_ADDR_Y_BI_PAR1 (MDNS_BASE + 0x00EC) ++#define MDNS_ADDR_Y_TCA_PAR (MDNS_BASE + 0x00F0) ++#define MDNS_ADDR_Y_TEA_T_PAR0 (MDNS_BASE + 0x00F4) ++#define MDNS_ADDR_Y_TEA_T_PAR1 (MDNS_BASE + 0x00F8) ++#define MDNS_ADDR_Y_TEA_V_PAR0 (MDNS_BASE + 0x00FC) ++#define MDNS_ADDR_Y_TEA_V_PAR1 (MDNS_BASE + 0x0100) ++#define MDNS_ADDR_Y_TEA_W_PAR0 (MDNS_BASE + 0x0104) ++#define MDNS_ADDR_Y_TEA_W_PAR1 (MDNS_BASE + 0x0108) ++#define MDNS_ADDR_Y_TLA_WIN_OPT (MDNS_BASE + 0x010C) ++#define MDNS_ADDR_Y_TLA_T_PAR0 (MDNS_BASE + 0x0110) ++#define MDNS_ADDR_Y_TLA_T_PAR1 (MDNS_BASE + 0x0114) ++#define MDNS_ADDR_Y_TLA_T_PAR2 (MDNS_BASE + 0x0118) ++#define MDNS_ADDR_Y_TLA_T_PAR3 (MDNS_BASE + 0x011C) ++#define MDNS_ADDR_Y_TLA_V_PAR0 (MDNS_BASE + 0x0120) ++#define MDNS_ADDR_Y_TLA_V_PAR1 (MDNS_BASE + 0x0124) ++#define MDNS_ADDR_Y_TLA_V_PAR2 (MDNS_BASE + 0x0128) ++#define MDNS_ADDR_Y_TLA_V_PAR3 (MDNS_BASE + 0x012C) ++#define MDNS_ADDR_Y_TLA_W_PAR0 (MDNS_BASE + 0x0130) ++#define MDNS_ADDR_Y_TLA_W_PAR1 (MDNS_BASE + 0x0134) ++#define MDNS_ADDR_Y_TLA_W_PAR2 (MDNS_BASE + 0x0138) ++#define MDNS_ADDR_Y_TLA_W_PAR3 (MDNS_BASE + 0x013C) ++#define MDNS_ADDR_Y_SAD_CFG (MDNS_BASE + 0x0140) ++#define MDNS_ADDR_Y_STA_WEI_PAR0 (MDNS_BASE + 0x0150) ++#define MDNS_ADDR_Y_STA_WEI_PAR1 (MDNS_BASE + 0x0154) ++#define MDNS_ADDR_Y_STA_WEI_PAR2 (MDNS_BASE + 0x0158) ++#define MDNS_ADDR_Y_STA_WEI_PAR3 (MDNS_BASE + 0x015C) ++#define MDNS_ADDR_Y_STA_WEI_PAR4 (MDNS_BASE + 0x0160) ++#define MDNS_ADDR_Y_STA_WEI_PAR5 (MDNS_BASE + 0x0164) ++#define MDNS_ADDR_Y_STA_WEI_PAR6 (MDNS_BASE + 0x0168) ++#define MDNS_ADDR_Y_STA_WEI_PAR7 (MDNS_BASE + 0x016C) ++#define MDNS_ADDR_Y_STA_WEI_PAR8 (MDNS_BASE + 0x0170) ++#define MDNS_ADDR_Y_STA_WEI_PAR9 (MDNS_BASE + 0x0174) ++#define MDNS_ADDR_Y_STA_WEI_PARa (MDNS_BASE + 0x0178) ++#define MDNS_ADDR_Y_STA_WEI_PARb (MDNS_BASE + 0x017C) ++#define MDNS_ADDR_Y_STA_WEI_PARc (MDNS_BASE + 0x0180) ++#define MDNS_ADDR_Y_STA_WEI_PARd (MDNS_BASE + 0x0184) ++#define MDNS_ADDR_Y_STA_WEI_PARe (MDNS_BASE + 0x0188) ++#define MDNS_ADDR_Y_STA_WEI_PARf (MDNS_BASE + 0x018C) ++#define MDNS_ADDR_Y_PBT_WEI_PAR0 (MDNS_BASE + 0x0190) ++#define MDNS_ADDR_Y_PBT_WEI_PAR1 (MDNS_BASE + 0x0194) ++#define MDNS_ADDR_Y_PBT_WEI_PAR2 (MDNS_BASE + 0x0198) ++#define MDNS_ADDR_Y_PBT_WEI_PAR3 (MDNS_BASE + 0x019C) ++#define MDNS_ADDR_Y_PBT_WEI_PAR4 (MDNS_BASE + 0x01A0) ++#define MDNS_ADDR_Y_PBT_WEI_PAR5 (MDNS_BASE + 0x01A4) ++#define MDNS_ADDR_Y_PBT_WEI_PAR6 (MDNS_BASE + 0x01A8) ++#define MDNS_ADDR_Y_PBT_WEI_PAR7 (MDNS_BASE + 0x01AC) ++#define MDNS_ADDR_Y_PBT_WEI_PAR8 (MDNS_BASE + 0x01B0) ++#define MDNS_ADDR_Y_PBT_WEI_PAR9 (MDNS_BASE + 0x01B4) ++#define MDNS_ADDR_Y_PBT_WEI_PARa (MDNS_BASE + 0x01B8) ++#define MDNS_ADDR_Y_PBT_WEI_PARb (MDNS_BASE + 0x01BC) ++#define MDNS_ADDR_Y_PBT_WEI_PARc (MDNS_BASE + 0x01C0) ++#define MDNS_ADDR_Y_PBT_WEI_PARd (MDNS_BASE + 0x01C4) ++#define MDNS_ADDR_Y_PBT_WEI_PARe (MDNS_BASE + 0x01C8) ++#define MDNS_ADDR_Y_PBT_WEI_PARf (MDNS_BASE + 0x01CC) ++#define MDNS_ADDR_Y_WSA_S_PAR (MDNS_BASE + 0x01D0) ++#define MDNS_ADDR_Y_WSA_M_PAR (MDNS_BASE + 0x01D4) ++#define MDNS_ADDR_Y_WFA_PAR (MDNS_BASE + 0x01D8) ++#define MDNS_ADDR_Y_REF_WEI_LMT (MDNS_BASE + 0x01DC) ++#define MDNS_ADDR_Y_REF_WEI_SGM_X_PAR0 (MDNS_BASE + 0x01E0) ++#define MDNS_ADDR_Y_REF_WEI_SGM_X_PAR1 (MDNS_BASE + 0x01E4) ++#define MDNS_ADDR_Y_REF_WEI_SGM_X_PAR2 (MDNS_BASE + 0x01E8) ++#define MDNS_ADDR_Y_REF_WEI_SGM_Y_PAR0 (MDNS_BASE + 0x01EC) ++#define MDNS_ADDR_Y_REF_WEI_SGM_Y_PAR1 (MDNS_BASE + 0x01F0) ++#define MDNS_ADDR_Y_REF_WEI_SGM_S_PAR0 (MDNS_BASE + 0x01F4) ++#define MDNS_ADDR_Y_REF_WEI_SGM_S_PAR1 (MDNS_BASE + 0x01F8) ++#define MDNS_ADDR_Y_FS_MV_JUDGE_THRES (MDNS_BASE + 0x01FC) ++#define MDNS_ADDR_Y_FS_S_CUR_SHP_WIN_OPT (MDNS_BASE + 0x0200) ++#define MDNS_ADDR_Y_FS_S_CUR_SHP_STREN_P0 (MDNS_BASE + 0x0204) ++#define MDNS_ADDR_Y_FS_S_CUR_SHP_STREN_P1 (MDNS_BASE + 0x0208) ++#define MDNS_ADDR_Y_FS_S_CUR_SHP_STREN_P2 (MDNS_BASE + 0x020C) ++#define MDNS_ADDR_Y_FS_S_CUR_SHP_STREN_P3 (MDNS_BASE + 0x0210) ++#define MDNS_ADDR_Y_FS_S_REF_SHP_WIN_OPT (MDNS_BASE + 0x0214) ++#define MDNS_ADDR_Y_FS_S_REF_SHP_STREN_P0 (MDNS_BASE + 0x0218) ++#define MDNS_ADDR_Y_FS_S_REF_SHP_STREN_P1 (MDNS_BASE + 0x021C) ++#define MDNS_ADDR_Y_FS_S_REF_SHP_STREN_P2 (MDNS_BASE + 0x0220) ++#define MDNS_ADDR_Y_FS_S_REF_SHP_STREN_P3 (MDNS_BASE + 0x0224) ++#define MDNS_ADDR_Y_FS_S_SHP_WEI (MDNS_BASE + 0x0228) ++#define MDNS_ADDR_Y_FS_M_CUR_SHP_WIN_OPT (MDNS_BASE + 0x022C) ++#define MDNS_ADDR_Y_FS_M_CUR_SHP_STREN_P0 (MDNS_BASE + 0x0230) ++#define MDNS_ADDR_Y_FS_M_CUR_SHP_STREN_P1 (MDNS_BASE + 0x0234) ++#define MDNS_ADDR_Y_FS_M_CUR_SHP_STREN_P2 (MDNS_BASE + 0x0238) ++#define MDNS_ADDR_Y_FS_M_CUR_SHP_STREN_P3 (MDNS_BASE + 0x023C) ++#define MDNS_ADDR_Y_FS_M_REF_SHP_WIN_OPT (MDNS_BASE + 0x0240) ++#define MDNS_ADDR_Y_FS_M_REF_SHP_STREN_P0 (MDNS_BASE + 0x0244) ++#define MDNS_ADDR_Y_FS_M_REF_SHP_STREN_P1 (MDNS_BASE + 0x0248) ++#define MDNS_ADDR_Y_FS_M_REF_SHP_STREN_P2 (MDNS_BASE + 0x024C) ++#define MDNS_ADDR_Y_FS_M_REF_SHP_STREN_P3 (MDNS_BASE + 0x0250) ++#define MDNS_ADDR_Y_FS_M_SHP_WEI (MDNS_BASE + 0x0254) ++#define MDNS_ADDR_Y_FS_SHP_CUR_STA_WEI_P0 (MDNS_BASE + 0x0258) ++#define MDNS_ADDR_Y_FS_SHP_CUR_STA_WEI_P1 (MDNS_BASE + 0x025C) ++#define MDNS_ADDR_Y_FS_SHP_REF_STA_WEI_P0 (MDNS_BASE + 0x0260) ++#define MDNS_ADDR_Y_FS_SHP_REF_STA_WEI_P1 (MDNS_BASE + 0x0264) ++#define MDNS_ADDR_Y_FS_SHP_CUR_FLUCT_PAR (MDNS_BASE + 0x0268) ++#define MDNS_ADDR_Y_FS_SHP_REF_FLUCT_PAR (MDNS_BASE + 0x026C) ++#define MDNS_ADDR_UV_CUT_VALUE (MDNS_BASE + 0x0280) ++#define MDNS_ADDR_UV_SAD_CFG (MDNS_BASE + 0x0284) ++#define MDNS_ADDR_UV_TCA_PAR (MDNS_BASE + 0x0290) ++#define MDNS_ADDR_UV_TMA_T_PAR0 (MDNS_BASE + 0x0294) ++#define MDNS_ADDR_UV_TMA_T_PAR1 (MDNS_BASE + 0x0298) ++#define MDNS_ADDR_UV_TMA_V_PAR0 (MDNS_BASE + 0x029C) ++#define MDNS_ADDR_UV_TMA_V_PAR1 (MDNS_BASE + 0x02a0) ++#define MDNS_ADDR_UV_TMA_W_PAR0 (MDNS_BASE + 0x02a4) ++#define MDNS_ADDR_UV_TMA_W_PAR1 (MDNS_BASE + 0x02a8) ++#define MDNS_ADDR_UV_STA_WEI_PAR0 (MDNS_BASE + 0x02b0) ++#define MDNS_ADDR_UV_STA_WEI_PAR1 (MDNS_BASE + 0x02b4) ++#define MDNS_ADDR_UV_STA_WEI_PAR2 (MDNS_BASE + 0x02b8) ++#define MDNS_ADDR_UV_STA_WEI_PAR3 (MDNS_BASE + 0x02bC) ++#define MDNS_ADDR_UV_STA_WEI_PAR4 (MDNS_BASE + 0x02c0) ++#define MDNS_ADDR_UV_STA_WEI_PAR5 (MDNS_BASE + 0x02c4) ++#define MDNS_ADDR_UV_STA_WEI_PAR6 (MDNS_BASE + 0x02c8) ++#define MDNS_ADDR_UV_STA_WEI_PAR7 (MDNS_BASE + 0x02cC) ++#define MDNS_ADDR_UV_STA_WEI_PAR8 (MDNS_BASE + 0x02d0) ++#define MDNS_ADDR_UV_STA_WEI_PAR9 (MDNS_BASE + 0x02d4) ++#define MDNS_ADDR_UV_STA_WEI_PARa (MDNS_BASE + 0x02d8) ++#define MDNS_ADDR_UV_STA_WEI_PARb (MDNS_BASE + 0x02dC) ++#define MDNS_ADDR_UV_STA_WEI_PARc (MDNS_BASE + 0x02e0) ++#define MDNS_ADDR_UV_STA_WEI_PARd (MDNS_BASE + 0x02e4) ++#define MDNS_ADDR_UV_STA_WEI_PARe (MDNS_BASE + 0x02e8) ++#define MDNS_ADDR_UV_STA_WEI_PARf (MDNS_BASE + 0x02eC) ++#define MDNS_ADDR_UV_PBT_WEI_PAR0 (MDNS_BASE + 0x02f0) ++#define MDNS_ADDR_UV_PBT_WEI_PAR1 (MDNS_BASE + 0x02f4) ++#define MDNS_ADDR_UV_PBT_WEI_PAR2 (MDNS_BASE + 0x02f8) ++#define MDNS_ADDR_UV_PBT_WEI_PAR3 (MDNS_BASE + 0x02fC) ++#define MDNS_ADDR_UV_PBT_WEI_PAR4 (MDNS_BASE + 0x0300) ++#define MDNS_ADDR_UV_PBT_WEI_PAR5 (MDNS_BASE + 0x0304) ++#define MDNS_ADDR_UV_PBT_WEI_PAR6 (MDNS_BASE + 0x0308) ++#define MDNS_ADDR_UV_PBT_WEI_PAR7 (MDNS_BASE + 0x030C) ++#define MDNS_ADDR_UV_PBT_WEI_PAR8 (MDNS_BASE + 0x0310) ++#define MDNS_ADDR_UV_PBT_WEI_PAR9 (MDNS_BASE + 0x0314) ++#define MDNS_ADDR_UV_PBT_WEI_PARa (MDNS_BASE + 0x0318) ++#define MDNS_ADDR_UV_PBT_WEI_PARb (MDNS_BASE + 0x031C) ++#define MDNS_ADDR_UV_PBT_WEI_PARc (MDNS_BASE + 0x0320) ++#define MDNS_ADDR_UV_PBT_WEI_PARd (MDNS_BASE + 0x0324) ++#define MDNS_ADDR_UV_PBT_WEI_PARe (MDNS_BASE + 0x0328) ++#define MDNS_ADDR_UV_PBT_WEI_PARf (MDNS_BASE + 0x032C) ++#define MDNS_ADDR_UV_WSA_S_PAR (MDNS_BASE + 0x0330) ++#define MDNS_ADDR_UV_WSA_M_PAR (MDNS_BASE + 0x0334) ++#define MDNS_ADDR_UV_REF_WEI_LMT (MDNS_BASE + 0x0338) ++#define MDNS_ADDR_UV_REF_WEI_SGM_X_PAR0 (MDNS_BASE + 0x0340) ++#define MDNS_ADDR_UV_REF_WEI_SGM_X_PAR1 (MDNS_BASE + 0x0344) ++#define MDNS_ADDR_UV_REF_WEI_SGM_X_PAR2 (MDNS_BASE + 0x0348) ++#define MDNS_ADDR_UV_REF_WEI_SGM_Y_PAR0 (MDNS_BASE + 0x034C) ++#define MDNS_ADDR_UV_REF_WEI_SGM_Y_PAR1 (MDNS_BASE + 0x0350) ++#define MDNS_ADDR_UV_REF_WEI_SGM_S_PAR0 (MDNS_BASE + 0x0354) ++#define MDNS_ADDR_UV_REF_WEI_SGM_S_PAR1 (MDNS_BASE + 0x0358) ++#define MDNS_ADDR_UV_FS_MV_JUDGE_THRES (MDNS_BASE + 0x035C) ++#define MDNS_ADDR_UV_FC_TYPE (MDNS_BASE + 0x0360) ++#define MDNS_ADDR_UV_FC_S_PAR0 (MDNS_BASE + 0x0370) ++#define MDNS_ADDR_UV_FC_S_PAR1 (MDNS_BASE + 0x0374) ++#define MDNS_ADDR_UV_FC_M_PAR0 (MDNS_BASE + 0x0378) ++#define MDNS_ADDR_UV_FC_M_PAR1 (MDNS_BASE + 0x037C) ++#define MDNS_ADDR_UV_BLUR_WEI (MDNS_BASE + 0x0380) ++ ++//============================================================ ++// SDNS ++//============================================================ ++#define SDNS_ADDR_T_VERSION (SDNS_BASE + 0x0000) ++#define SDNS_ADDR_REG_CTRL (SDNS_BASE + 0x0004) ++#define SDNS_ADDR_DBG_SEL (SDNS_BASE + 0x0008) ++#define SDNS_ADDR_DBG_VALUE (SDNS_BASE + 0x000C) ++#define SDNS_ADDR_Y_FUN_EN (SDNS_BASE + 0x0010) ++#define SDNS_ADDR_Y_COM_PAR0 (SDNS_BASE + 0x0014) ++#define SDNS_ADDR_Y_COM_PAR1 (SDNS_BASE + 0x0018) ++#define SDNS_ADDR_Y_FUSION_PAR0 (SDNS_BASE + 0x001C) ++#define SDNS_ADDR_Y_FUSION_PAR1 (SDNS_BASE + 0x0020) ++#define SDNS_ADDR_Y_FUSION_PAR2 (SDNS_BASE + 0x0024) ++#define SDNS_ADDR_Y_FUSION_PAR3 (SDNS_BASE + 0x0028) ++#define SDNS_ADDR_Y_DETAIL_PAR0 (SDNS_BASE + 0x002C) ++#define SDNS_ADDR_Y_DETAIL_PAR1 (SDNS_BASE + 0x0030) ++#define SDNS_ADDR_Y_DETAIL_PAR2 (SDNS_BASE + 0x0034) ++#define SDNS_ADDR_Y_DETAIL_PAR3 (SDNS_BASE + 0x0038) ++#define SDNS_ADDR_Y_LUMA_PAR0 (SDNS_BASE + 0x003C) ++#define SDNS_ADDR_Y_LUMA_PAR1 (SDNS_BASE + 0x0040) ++#define SDNS_ADDR_Y_LUMA_PAR2 (SDNS_BASE + 0x0044) ++#define SDNS_ADDR_Y_LUMA_PAR3 (SDNS_BASE + 0x0048) ++#define SDNS_ADDR_Y_BSHP_PAR0 (SDNS_BASE + 0x004C) ++#define SDNS_ADDR_Y_BSHP_PAR1 (SDNS_BASE + 0x0050) ++#define SDNS_ADDR_Y_BSHP_PAR2 (SDNS_BASE + 0x0054) ++#define SDNS_ADDR_Y_BSHP_PAR3 (SDNS_BASE + 0x0058) ++#define SDNS_ADDR_Y_DSHP_PAR0 (SDNS_BASE + 0x005C) ++#define SDNS_ADDR_Y_DSHP_PAR1 (SDNS_BASE + 0x0060) ++#define SDNS_ADDR_Y_DSHP_PAR2 (SDNS_BASE + 0x0064) ++#define SDNS_ADDR_Y_DSHP_PAR3 (SDNS_BASE + 0x0068) ++#define SDNS_ADDR_Y_BI_PAR0 (SDNS_BASE + 0x006C) ++#define SDNS_ADDR_Y_BI_PAR1 (SDNS_BASE + 0x0070) ++#define SDNS_ADDR_Y_BI_PAR2 (SDNS_BASE + 0x0074) ++#define SDNS_ADDR_Y_BI_PAR3 (SDNS_BASE + 0x0078) ++#define SDNS_ADDR_UV_FUN_EN (SDNS_BASE + 0x0080) ++#define SDNS_ADDR_UV_COM_PAR (SDNS_BASE + 0x0084) ++#define SDNS_ADDR_UV_FUSION_PAR0 (SDNS_BASE + 0x0088) ++#define SDNS_ADDR_UV_FUSION_PAR1 (SDNS_BASE + 0x008C) ++#define SDNS_ADDR_UV_FUSION_PAR2 (SDNS_BASE + 0x0090) ++#define SDNS_ADDR_UV_FUSION_PAR3 (SDNS_BASE + 0x0094) ++ ++//============================================================ ++// HLDC ++//============================================================ ++#define HLDC_ADDR_REG_CTRL (HLDC_BASE + 0x0000) ++#define HLDC_ADDR_DIS_Y_COEFF_X (HLDC_BASE + 0x0004) ++#define HLDC_ADDR_DIS_UV_COEFF_X (HLDC_BASE + 0x0008) ++#define HLDC_ADDR_P1_Y_VAL (HLDC_BASE + 0x000C) ++#define HLDC_ADDR_P1_UV_VAL (HLDC_BASE + 0x0010) ++#define HLDC_ADDR_R2_Y_REP (HLDC_BASE + 0x0014) ++#define HLDC_ADDR_R2_UV_REP (HLDC_BASE + 0x0018) ++#define HLDC_ADDR_Y_OFFSET (HLDC_BASE + 0x001C) ++#define HLDC_ADDR_UV_OFFSET (HLDC_BASE + 0x0020) ++#define HLDC_ADDR_LINE_BLK_Y (HLDC_BASE + 0x0024) ++#define HLDC_ADDR_LINE_BLK_UV (HLDC_BASE + 0x0028) ++ ++//============================================================ ++// Mscaler ++//============================================================ ++#define MSCA_CTRL (MSCA_BASE+0x000) ++#define MSCA_CH_EN (MSCA_BASE+0x004) ++#define MSCA_CH_STA (MSCA_BASE+0x008) ++#define MSCA_INT_STA (MSCA_BASE+0x00C) ++#define MSCA_INT_MSK (MSCA_BASE+0x010) ++#define MSCA_INT_CLR (MSCA_BASE+0x014) ++#define MSCA_DMAOUT_ARB (MSCA_BASE+0x018) ++#define MSCA_CLK_GATE_EN (MSCA_BASE+0x01C) ++#define MSCA_CLK_DIS (MSCA_BASE+0x020) ++#define MSCA_SRC_IN (MSCA_BASE+0x030) ++#define MSCA_SRC_SIZE (MSCA_BASE+0x034) ++#define MSCA_GLO_RSZ_COEF_WR (MSCA_BASE+0x040) ++#define MSCA_SYS_PRO_CLK_EN (MSCA_BASE+0x050) ++#define MSCA_DS0_CLK_NUM (MSCA_BASE+0x054) ++#define MSCA_DS1_CLK_NUM (MSCA_BASE+0x058) ++#define MSCA_DS2_CLK_NUM (MSCA_BASE+0x05C) ++ ++//ds0 ++#define MSCA_ADDR_DS0_RSZ_SIZE (MSCA_BASE+0x100) ++#define MSCA_ADDR_DS0_RSZ_STEP (MSCA_BASE+0x104) ++#define MSCA_ADDR_DS0_CROP_POS (MSCA_BASE+0x128) ++#define MSCA_ADDR_DS0_CROP_SIZE (MSCA_BASE+0x12C) ++#define MSCA_ADDR_DS0_FRA_RATE_LOOP (MSCA_BASE+0x130) ++#define MSCA_ADDR_DS0_FRA_RATE_MASK (MSCA_BASE+0x134) ++#define MSCA_ADDR_DS0_MASK0_POS (MSCA_BASE+0x138) ++#define MSCA_ADDR_DS0_MASK0_SIZE (MSCA_BASE+0x13C) ++#define MSCA_ADDR_DS0_MASK0_ARGB (MSCA_BASE+0x140) ++#define MSCA_ADDR_DS0_MASK1_POS (MSCA_BASE+0x144) ++#define MSCA_ADDR_DS0_MASK1_SIZE (MSCA_BASE+0x148) ++#define MSCA_ADDR_DS0_MASK1_ARGB (MSCA_BASE+0x14C) ++#define MSCA_ADDR_DS0_MASK2_POS (MSCA_BASE+0x150) ++#define MSCA_ADDR_DS0_MASK2_SIZE (MSCA_BASE+0x154) ++#define MSCA_ADDR_DS0_MASK2_ARGB (MSCA_BASE+0x158) ++#define MSCA_ADDR_DS0_MASK3_POS (MSCA_BASE+0x15C) ++#define MSCA_ADDR_DS0_MASK3_SIZE (MSCA_BASE+0x160) ++#define MSCA_ADDR_DS0_MASK3_ARGB (MSCA_BASE+0x164) ++#define MSCA_ADDR_DS0_DMAOUT_FMT (MSCA_BASE+0x168) ++#define MSCA_ADDR_DS0_DMAOUT_Y_ADDR (MSCA_BASE+0x16C) ++#define MSCA_ADDR_DS0_DMAOUT_Y_FIFO_STA (MSCA_BASE+0x170) ++#define MSCA_ADDR_DS0_DMAOUT_Y_LAST_ADDR (MSCA_BASE+0x174) ++#define MSCA_ADDR_DS0_DMAOUT_Y_LAST_STATS_NUM (MSCA_BASE+0x178) ++#define MSCA_ADDR_DS0_DMAOUT_Y_LAST_FIFO_STA (MSCA_BASE+0x17C) ++#define MSCA_ADDR_DS0_DMAOUT_Y_STR (MSCA_BASE+0x180) ++#define MSCA_ADDR_DS0_DMAOUT_UV_ADDR (MSCA_BASE+0x184) ++#define MSCA_ADDR_DS0_DMAOUT_UV_FIFO_STA (MSCA_BASE+0x188) ++#define MSCA_ADDR_DS0_DMAOUT_UV_LAST_ADDR (MSCA_BASE+0x18C) ++#define MSCA_ADDR_DS0_DMAOUT_UV_LAST_STATS_NUM (MSCA_BASE+0x190) ++#define MSCA_ADDR_DS0_DMAOUT_UV_LAST_FIFO_STA (MSCA_BASE+0x194) ++#define MSCA_ADDR_DS0_DMAOUT_UV_STR (MSCA_BASE+0x198) ++#define MSCA_ADDR_DS0_DMAOUT_Y_FIFO_CLR (MSCA_BASE+0x19C) ++#define MSCA_ADDR_DS0_DMAOUT_UV_FIFO_CLR (MSCA_BASE+0x1A0) ++#define MSCA_ADDR_DS0_DMAOUT_Y_LAST_FIFO_CLR (MSCA_BASE+0x1A4) ++#define MSCA_ADDR_DS0_DMAOUT_UV_LAST_FIFO_CLR (MSCA_BASE+0x1A8) ++#define MSCA_ADDR_DS0_DMAOUT_Y_ADDR_SEL (MSCA_BASE+0x1AC) ++#define MSCA_ADDR_DS0_DMAOUT_UV_ADDR_SEL (MSCA_BASE+0x1B0) ++ ++//-- ds1 ++#define MSCA_ADDR_DS1_RSZ_SIZE (MSCA_BASE+0x200) ++#define MSCA_ADDR_DS1_RSZ_STEP (MSCA_BASE+0x204) ++#define MSCA_ADDR_DS1_CROP_POS (MSCA_BASE+0x228) ++#define MSCA_ADDR_DS1_CROP_SIZE (MSCA_BASE+0x22C) ++#define MSCA_ADDR_DS1_FRA_RATE_LOOP (MSCA_BASE+0x230) ++#define MSCA_ADDR_DS1_FRA_RATE_MASK (MSCA_BASE+0x234) ++#define MSCA_ADDR_DS1_MASK0_POS (MSCA_BASE+0x238) ++#define MSCA_ADDR_DS1_MASK0_SIZE (MSCA_BASE+0x23C) ++#define MSCA_ADDR_DS1_MASK0_ARGB (MSCA_BASE+0x240) ++#define MSCA_ADDR_DS1_MASK1_POS (MSCA_BASE+0x244) ++#define MSCA_ADDR_DS1_MASK1_SIZE (MSCA_BASE+0x248) ++#define MSCA_ADDR_DS1_MASK1_ARGB (MSCA_BASE+0x24C) ++#define MSCA_ADDR_DS1_MASK2_POS (MSCA_BASE+0x250) ++#define MSCA_ADDR_DS1_MASK2_SIZE (MSCA_BASE+0x254) ++#define MSCA_ADDR_DS1_MASK2_ARGB (MSCA_BASE+0x258) ++#define MSCA_ADDR_DS1_MASK3_POS (MSCA_BASE+0x25C) ++#define MSCA_ADDR_DS1_MASK3_SIZE (MSCA_BASE+0x260) ++#define MSCA_ADDR_DS1_MASK3_ARGB (MSCA_BASE+0x264) ++#define MSCA_ADDR_DS1_DMAOUT_FMT (MSCA_BASE+0x268) ++#define MSCA_ADDR_DS1_DMAOUT_Y_ADDR (MSCA_BASE+0x26C) ++#define MSCA_ADDR_DS1_DMAOUT_Y_FIFO_STA (MSCA_BASE+0x270) ++#define MSCA_ADDR_DS1_DMAOUT_Y_LAST_ADDR (MSCA_BASE+0x274) ++#define MSCA_ADDR_DS1_DMAOUT_Y_LAST_STATS_NUM (MSCA_BASE+0x278) ++#define MSCA_ADDR_DS1_DMAOUT_Y_LAST_FIFO_STA (MSCA_BASE+0x27C) ++#define MSCA_ADDR_DS1_DMAOUT_Y_STR (MSCA_BASE+0x280) ++#define MSCA_ADDR_DS1_DMAOUT_UV_ADDR (MSCA_BASE+0x284) ++#define MSCA_ADDR_DS1_DMAOUT_UV_FIFO_STA (MSCA_BASE+0x288) ++#define MSCA_ADDR_DS1_DMAOUT_UV_LAST_ADDR (MSCA_BASE+0x28C) ++#define MSCA_ADDR_DS1_DMAOUT_UV_LAST_STATS_NUM (MSCA_BASE+0x290) ++#define MSCA_ADDR_DS1_DMAOUT_UV_LAST_FIFO_STA (MSCA_BASE+0x294) ++#define MSCA_ADDR_DS1_DMAOUT_UV_STR (MSCA_BASE+0x298) ++#define MSCA_ADDR_DS1_DMAOUT_Y_FIFO_CLR (MSCA_BASE+0x29C) ++#define MSCA_ADDR_DS1_DMAOUT_UV_FIFO_CLR (MSCA_BASE+0x2A0) ++#define MSCA_ADDR_DS1_DMAOUT_Y_LAST_FIFO_CLR (MSCA_BASE+0x2A4) ++#define MSCA_ADDR_DS1_DMAOUT_UV_LAST_FIFO_CLR (MSCA_BASE+0x2A8) ++#define MSCA_ADDR_DS1_DMAOUT_Y_ADDR_SEL (MSCA_BASE+0x2AC) ++#define MSCA_ADDR_DS1_DMAOUT_UV_ADDR_SEL (MSCA_BASE+0x2B0) ++ ++ ++//-- ds2 ++#define MSCA_ADDR_DS2_RSZ_SIZE (MSCA_BASE+0x300) ++#define MSCA_ADDR_DS2_RSZ_STEP (MSCA_BASE+0x304) ++#define MSCA_ADDR_DS2_CROP_POS (MSCA_BASE+0x328) ++#define MSCA_ADDR_DS2_CROP_SIZE (MSCA_BASE+0x32C) ++#define MSCA_ADDR_DS2_FRA_RATE_LOOP (MSCA_BASE+0x330) ++#define MSCA_ADDR_DS2_FRA_RATE_MASK (MSCA_BASE+0x334) ++#define MSCA_ADDR_DS2_MASK0_POS (MSCA_BASE+0x338) ++#define MSCA_ADDR_DS2_MASK0_SIZE (MSCA_BASE+0x33C) ++#define MSCA_ADDR_DS2_MASK0_ARGB (MSCA_BASE+0x340) ++#define MSCA_ADDR_DS2_MASK1_POS (MSCA_BASE+0x344) ++#define MSCA_ADDR_DS2_MASK1_SIZE (MSCA_BASE+0x348) ++#define MSCA_ADDR_DS2_MASK1_ARGB (MSCA_BASE+0x34C) ++#define MSCA_ADDR_DS2_MASK2_POS (MSCA_BASE+0x350) ++#define MSCA_ADDR_DS2_MASK2_SIZE (MSCA_BASE+0x354) ++#define MSCA_ADDR_DS2_MASK2_ARGB (MSCA_BASE+0x358) ++#define MSCA_ADDR_DS2_MASK3_POS (MSCA_BASE+0x35C) ++#define MSCA_ADDR_DS2_MASK3_SIZE (MSCA_BASE+0x360) ++#define MSCA_ADDR_DS2_MASK3_ARGB (MSCA_BASE+0x364) ++#define MSCA_ADDR_DS2_DMAOUT_FMT (MSCA_BASE+0x368) ++#define MSCA_ADDR_DS2_DMAOUT_Y_ADDR (MSCA_BASE+0x36C) ++#define MSCA_ADDR_DS2_DMAOUT_Y_FIFO_STA (MSCA_BASE+0x370) ++#define MSCA_ADDR_DS2_DMAOUT_Y_LAST_ADDR (MSCA_BASE+0x374) ++#define MSCA_ADDR_DS2_DMAOUT_Y_LAST_STATS_NUM (MSCA_BASE+0x378) ++#define MSCA_ADDR_DS2_DMAOUT_Y_LAST_FIFO_STA (MSCA_BASE+0x37C) ++#define MSCA_ADDR_DS2_DMAOUT_Y_STR (MSCA_BASE+0x380) ++#define MSCA_ADDR_DS2_DMAOUT_UV_ADDR (MSCA_BASE+0x384) ++#define MSCA_ADDR_DS2_DMAOUT_UV_FIFO_STA (MSCA_BASE+0x388) ++#define MSCA_ADDR_DS2_DMAOUT_UV_LAST_ADDR (MSCA_BASE+0x38C) ++#define MSCA_ADDR_DS2_DMAOUT_UV_LAST_STATS_NUM (MSCA_BASE+0x390) ++#define MSCA_ADDR_DS2_DMAOUT_UV_LAST_FIFO_STA (MSCA_BASE+0x394) ++#define MSCA_ADDR_DS2_DMAOUT_UV_STR (MSCA_BASE+0x398) ++#define MSCA_ADDR_DS2_DMAOUT_Y_FIFO_CLR (MSCA_BASE+0x39C) ++#define MSCA_ADDR_DS2_DMAOUT_UV_FIFO_CLR (MSCA_BASE+0x3A0) ++#define MSCA_ADDR_DS2_DMAOUT_Y_LAST_FIFO_CLR (MSCA_BASE+0x3A4) ++#define MSCA_ADDR_DS2_DMAOUT_UV_LAST_FIFO_CLR (MSCA_BASE+0x3A8) ++#define MSCA_ADDR_DS2_DMAOUT_Y_ADDR_SEL (MSCA_BASE+0x3AC) ++#define MSCA_ADDR_DS2_DMAOUT_UV_ADDR_SEL (MSCA_BASE+0x3B0) ++ ++//--DEBUG ++#define MSCA_ADDR_VRSZ_Y_DBG_SEL (MSCA_BASE+0x080) ++#define MSCA_ADDR_VRSZ_UV_DBG_SEL (MSCA_BASE+0x084) ++#define MSCA_ADDR_DS0_DMA_OUT_DBG0_SEL (MSCA_BASE+0x088) ++#define MSCA_ADDR_DS0_DMA_OUT_DBG1_SEL (MSCA_BASE+0x08C) ++#define MSCA_ADDR_DS0_DMA_OUT_DBG2_SEL (MSCA_BASE+0x090) ++#define MSCA_ADDR_DS1_DMA_OUT_DBG0_SEL (MSCA_BASE+0x094) ++#define MSCA_ADDR_DS1_DMA_OUT_DBG1_SEL (MSCA_BASE+0x098) ++#define MSCA_ADDR_DS1_DMA_OUT_DBG2_SEL (MSCA_BASE+0x09C) ++#define MSCA_ADDR_DS2_DMA_OUT_DBG0_SEL (MSCA_BASE+0x0A0) ++#define MSCA_ADDR_DS2_DMA_OUT_DBG1_SEL (MSCA_BASE+0x0A4) ++#define MSCA_ADDR_DS2_DMA_OUT_DBG2_SEL (MSCA_BASE+0x0A8) ++#define MSCA_ADDR_DS0_HRSZ_Y_DBG_SEL (MSCA_BASE+0x0AC) ++#define MSCA_ADDR_DS0_HRSZ_UV_DBG_SEL (MSCA_BASE+0x0B0) ++#define MSCA_ADDR_DS1_HRSZ_Y_DBG_SEL (MSCA_BASE+0x0B4) ++#define MSCA_ADDR_DS1_HRSZ_UV_DBG_SEL (MSCA_BASE+0x0B8) ++#define MSCA_ADDR_DS2_HRSZ_Y_DBG_SEL (MSCA_BASE+0x0BC) ++#define MSCA_ADDR_DS2_HRSZ_UV_DBG_SEL (MSCA_BASE+0x0C0) ++#define MSCA_ADDR_BP_BUS0_DBG_SEL (MSCA_BASE+0x0C4) ++#define MSCA_ADDR_BP_BUS1_DBG_SEL (MSCA_BASE+0x0C8) ++#define MSCA_ADDR_BP_BUS2_DBG_SEL (MSCA_BASE+0x0CC) ++#define MSCA_ADDR_STP_DBG_SEL (MSCA_BASE+0x0D0) ++ ++#define MSCA_ADDR_DS0_CRC_Y_SEL (MSCA_BASE+0x0E0) ++#define MSCA_ADDR_DS0_CRC_UV_SEL (MSCA_BASE+0x0E4) ++#define MSCA_ADDR_DS1_CRC_Y_SEL (MSCA_BASE+0x0E8) ++#define MSCA_ADDR_DS1_CRC_UV_SEL (MSCA_BASE+0x0EC) ++#define MSCA_ADDR_DS2_CRC_Y_SEL (MSCA_BASE+0x0F0) ++#define MSCA_ADDR_DS2_CRC_UV_SEL (MSCA_BASE+0x0F4) ++ ++#define CHx_RSZ_OSIZE(n) (MSCA_BASE+(0x0100*(n))+0x100) ++#define CHx_RSZ_STEP(n) (MSCA_BASE+(0x0100*(n))+0x104) ++ ++#define CHx_CROP_OPOS(n) (MSCA_BASE+(0x0100*(n))+0x128) ++#define CHx_CROP_OSIZE(n) (MSCA_BASE+(0x0100*(n))+0x12c) ++#define CHx_FRA_CTRL_LOOP(n) (MSCA_BASE+(0x0100*(n))+0x130) ++#define CHx_FRA_CTRL_MASK(n) (MSCA_BASE+(0x0100*(n))+0x134) ++#define CHx_MS0_POS(n) (MSCA_BASE+(0x0100*(n))+0x138) ++#define CHx_MS0_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x13c) ++#define CHx_MS0_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x140) ++#define CHx_MS1_POS(n) (MSCA_BASE+(0x0100*(n))+0x144) ++#define CHx_MS1_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x148) ++#define CHx_MS1_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x14c) ++#define CHx_MS2_POS(n) (MSCA_BASE+(0x0100*(n))+0x150) ++#define CHx_MS2_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x154) ++#define CHx_MS2_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x158) ++#define CHx_MS3_POS(n) (MSCA_BASE+(0x0100*(n))+0x15c) ++#define CHx_MS3_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x160) ++#define CHx_MS3_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x164) ++#define CHx_OUT_FMT(n) (MSCA_BASE+(0x0100*(n))+0x168) ++#define CHx_DMAOUT_Y_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x16c) ++#define CHx_Y_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x170) ++#define CHx_DMAOUT_Y_LAST_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x174) ++#define CHx_DMAOUT_Y_LAST_STATS_NUM(n) (MSCA_BASE+(0x0100*(n))+0x178) ++#define CHx_Y_LAST_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x17c) ++#define CHx_DMAOUT_Y_STRI(n) (MSCA_BASE+(0x0100*(n))+0x180) ++#define CHx_DMAOUT_UV_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x184) ++#define CHx_UV_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x188) ++#define CHx_DMAOUT_UV_LAST_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x18c) ++#define CHx_DMAOUT_UV_LAST_STATS_NUM(n) (MSCA_BASE+(0x0100*(n))+0x190) ++#define CHx_UV_LAST_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x194) ++#define CHx_DMAOUT_UV_STRI(n) (MSCA_BASE+(0x0100*(n))+0x198) ++#define CHx_DMAOUT_Y_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x19c) ++#define CHx_DMAOUT_UV_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a0) ++#define CHx_DMAOUT_Y_LAST_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a4) ++#define CHx_DMAOUT_UV_LAST_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a8) ++#define CHx_DMAOUT_Y_ADDR_SEL(n) (MSCA_BASE+(0x0100*(n))+0x1ac) ++#define CHx_DMAOUT_UV_ADDR_SEL(n) (MSCA_BASE+(0x0100*(n))+0x1b0) ++ ++#define TIZIANO_ISP_IRQ_ISP_FRD (0) ++#define TIZIANO_ISP_IRQ_STOP (4) ++#define TIZIANO_ISP_IRQ_CTM_STATIC (8) ++#define TIZIANO_ISP_IRQ_AE_STATIC (16) ++#define TIZIANO_ISP_IRQ_AE_HIST (17) ++#define TIZIANO_ISP_IRQ_AWB_STATIC (18) ++#define TIZIANO_ISP_IRQ_AF_STATIC (19) ++#define TIZIANO_ISP_IRQ_ADR_STATIC (20) ++#define TIZIANO_ISP_IRQ_DEFOG_STATIC (21) ++#define TIZIANO_ISP_IRQ_DMAOUT_FRD (23) ++#endif ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-regs.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-regs.h +new file mode 100755 +index 000000000..cd3d04bd7 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-regs.h +@@ -0,0 +1,4289 @@ ++#ifndef TIZIANO_MAP_H ++#define TIZIANO_MAP_H ++ ++#ifndef TIZIANO_BASE ++#define TIZIANO_BASE 0x0 ++#endif ++ ++//============================================================ ++// BASE ADDRESS ++//============================================================ ++#define TOP_BASE (TIZIANO_BASE + 0x00000) ++#define IPC_BASE (TIZIANO_BASE + 0x01000) ++#define FBIST_BASE (TIZIANO_BASE + 0x70000) ++#define RESP_BASE (TIZIANO_BASE + 0x40000) ++#define MCFG_BASE (TIZIANO_BASE + 0x50000) ++ ++#define BLC0_BASE (TIZIANO_BASE + 0x02000) ++#define LSC0_BASE (TIZIANO_BASE + 0x03000) ++#define AWBG00_BASE (TIZIANO_BASE + 0x04000) ++#define AWBG10_BASE (TIZIANO_BASE + 0x05000) ++#define WDR0_BASE (TIZIANO_BASE + 0x06000) ++#define WDR_BASE(n) (TIZIANO_BASE + 0x06000 + n * 0x0800) ++#define DPC_BASE(n) (TIZIANO_BASE + 0x07000 + n * 0x0100) ++#define GIB_BASE(n) (TIZIANO_BASE + 0x08000 + n * 0x0080) ++#define ADR0_BASE (TIZIANO_BASE + 0x09000) ++#define ADR_BASE(n) (TIZIANO_BASE + 0x09000 + n * 0x0800) ++#define DEMOSAIC_BASE(n) (TIZIANO_BASE + 0x0A000 + n * 0x0400) ++#define CCM0_BASE (TIZIANO_BASE + 0x0B000) ++#define DEFOG_BASE(n) (TIZIANO_BASE + 0x0C000 + n * 0x0400) ++#define CSC_BASE(n) (TIZIANO_BASE + 0x0D000 + n * 0x0080) ++#define LCE0_BASE (TIZIANO_BASE + 0x0E000) ++#define MDNS_BASE(n) (TIZIANO_BASE + 0x0F000 + 0x0800 * n) ++#define YDNS_BASE(n) (TIZIANO_BASE + 0x10000 + n * 0x100) ++#define BCSH0_BASE (TIZIANO_BASE + 0x11000) ++#define CLM0_BASE (TIZIANO_BASE + 0x12000) ++#define Y_SHARPEN_BASE(n) (TIZIANO_BASE + 0x13000 + n * 0x0200) ++#define SDNS_BASE(n) (TIZIANO_BASE + 0x14000 + n * 0x0400) ++#define HLDC_BASE(n) (TIZIANO_BASE + 0x15000 + n * 0x0080) ++#define MSCALER0_BASE (TIZIANO_BASE + 0x16000) ++#define AWB0_BASE (TIZIANO_BASE + 0x18000) ++#define AE0_BASE (TIZIANO_BASE + 0x19000) ++#define AF_BASE (TIZIANO_BASE + 0x1A000) ++#define GSM0_BASE (TIZIANO_BASE + 0x1B000) ++#define CDNS_BASE(n) (TIZIANO_BASE + 0x1C000 + n * 0x80) ++#define TSTP_BASE(n) (TIZIANO_BASE + 0x60000 + n * 0x0100) ++ ++#define BLC1_BASE (TIZIANO_BASE + 0x02000 + 0x0080) ++#define LSC1_BASE (TIZIANO_BASE + 0x03000 + 0x0080) ++#define AWBG01_BASE (TIZIANO_BASE + 0x04000 + 0x0020) ++#define AWBG11_BASE (TIZIANO_BASE + 0x05000 + 0x0020) ++#define WDR1_BASE (TIZIANO_BASE + 0x06000 + 0x0800) ++#define ADR1_BASE (TIZIANO_BASE + 0x09000 + 0x0800) ++#define CCM1_BASE (TIZIANO_BASE + 0x0B000 + 0x0040) ++#define LCE1_BASE (TIZIANO_BASE + 0x0E000 + 0x0100) ++#define BCSH1_BASE (TIZIANO_BASE + 0x11000 + 0x0100) ++#define CLM1_BASE (TIZIANO_BASE + 0x12000 + 0x0080) ++#define MSCALER1_BASE (TIZIANO_BASE + 0x16000 + 0x1000) ++#define AWB1_BASE (TIZIANO_BASE + 0x18000 + 0x0200) ++#define AE1_BASE (TIZIANO_BASE + 0x19000 + 0x0200) ++#define GSM1_BASE (TIZIANO_BASE + 0x1B000 + 0x0040) ++ ++//============================================================ ++// TOP ADDRESS ++//============================================================ ++#define TOP_ADDR_VERSION (TOP_BASE + 0x0000) ++#define TOP_ADDR_TOP_CON (TOP_BASE + 0x0020) ++ ++#define FUN_RST (1 << 2) ++#define REG_RST (1 << 1) ++#define ALL_RST (1 << 0) ++#define TOP_ADDR_TOP_RST (TOP_BASE + 0x0024) ++#define TOP_ADDR_TOP_INFO (TOP_BASE + 0x0028) ++ ++#define BLC_BYPASS (1 << 0) ++#define LSC_BYPASS (1 << 1) ++#define AWB0_BYPASS (1 << 2) ++#define WDR_BYPASS (1 << 3) ++#define DPC_BYPASS (1 << 4) ++#define GIB_BYPASS (1 << 5) ++#define AWB1_BYPASS (1 << 6) ++#define ADR_BYPASS (1 << 7) ++#define DMSC_BYPASS (1 << 8) ++#define CCM_BYPASS (1 << 9) ++#define GAMMA_BYPASS (1 << 10) ++#define DEFOG_BYPASS (1 << 11) ++#define CSC_BYPASS (1 << 12) ++#define MDNS_BYPASS (1 << 13) ++#define YDNS_BYPASS (1 << 14) ++#define BCSH_BYPASS (1 << 15) ++#define CLM_BYPASS (1 << 16) ++#define YSP_BYPASS (1 << 17) ++#define SDNS_BYPASS (1 << 18) ++#define CDNS_BYPASS (1 << 19) ++#define HLDC_BYPASS (1 << 20) ++#define LCE_BYPASS (1 << 21) ++#define TPRAW_PAT_BYPASS (1 << 22) ++#define TPRGB_PAT_BYPASS (1 << 23) ++#define TPYUV_PAT_BYPASS (1 << 24) ++#define TPRAW_FONT_BYPASS (1 << 25) ++#define TPRGB_FONT_BYPASS (1 << 26) ++#define TPYUV_FONT_BYPASS (1 << 27) ++#define TPRAW_FREE_BYPASS (1 << 28) ++#define TPRGB_FREE_BYPASS (1 << 29) ++#define TPYUV_FREE_BYPASS (1 << 30) ++ ++#define TIZIANO_BYPASS_INIT (BLC_BYPASS|LSC_BYPASS|AWB0_BYPASS|WDR_BYPASS|DPC_BYPASS|GIB_BYPASS|AWB1_BYPASS|ADR_BYPASS|DMSC_BYPASS|CCM_BYPASS|GAMMA_BYPASS|DEFOG_BYPASS|CSC_BYPASS|MDNS_BYPASS|YDNS_BYPASS|BCSH_BYPASS|CLM_BYPASS|YSP_BYPASS|SDNS_BYPASS|CDNS_BYPASS|HLDC_BYPASS|LCE_BYPASS|TPRAW_PAT_BYPASS |TPRGB_PAT_BYPASS|TPYUV_PAT_BYPASS|TPRAW_FONT_BYPASS|TPRGB_FONT_BYPASS|TPYUV_FONT_BYPASS|TPRAW_FREE_BYPASS|TPRGB_FREE_BYPASS|TPYUV_FREE_BYPASS) ++ ++#define TOP_ADDR_BYPASS(num) (TOP_BASE + 0x0040 + num * 4) ++#define TOP_ADDR_REG_CON (TOP_BASE + 0x0048) ++#define TOP_ADDR_STATIC_EN1 (TOP_BASE + 0x0050) ++#define TOP_ADDR_STATIC_POS1 (TOP_BASE + 0x005C) ++ ++ ++#define AE_STATIC_EN ( 1 << 0) ++#define AE_HIST_EN ( 1 << 1) ++#define AE_IR_HIST_EN ( 1 << 2) ++#define AWB_STATIC_EN ( 1 << 3) ++#define AF_STATIC_EN ( 1 << 4) ++#define GSM_STATIC_EN ( 1 << 5) ++#define WDR_STATIC_EN ( 1 << 6) ++#define ADR_STATIC_EN ( 1 << 7) ++#define DEFOG_STATIC_EN ( 1 << 8) ++#define LCE_STATIC_EN ( 1 << 9) ++#define TOP_ADDR_STATIC_EN (TOP_BASE + 0x0060) ++#define TOP_ADDR_STATIC_STOP (TOP_BASE + 0x0064) ++#define TOP_ADDR_STATIC_RST (TOP_BASE + 0x0068) ++#define TOP_ADDR_STATIC_POS (TOP_BASE + 0x006C) ++#define TOP_ADDR_S0_FRM_SIZE (TOP_BASE + 0x0080) ++#define TOP_ADDR_S1_FRM_SIZE (TOP_BASE + 0x0084) ++#define TOP_ADDR_S0_BAYER_TYPE (TOP_BASE + 0x0088) ++#define TOP_ADDR_S1_BAYER_TYPE (TOP_BASE + 0x008C) ++#define TOP_ADDR_S0_LINE_SPACE_0 (TOP_BASE + 0x0090) ++#define TOP_ADDR_S0_LINE_SPACE_1 (TOP_BASE + 0x0094) ++#define TOP_ADDR_S1_LINE_SPACE_0 (TOP_BASE + 0x0098) ++#define TOP_ADDR_S1_LINE_SPACE_1 (TOP_BASE + 0x009C) ++#define TOP_ADDR_STOP_CON (TOP_BASE + 0x0200) ++#define TOP_ADDR_STOP_STATE (TOP_BASE + 0x0204) ++#define TOP_ADDR_DMA_RD_CON (TOP_BASE + 0x0220) ++#define TOP_ADDR_DMA_RD_INFO (TOP_BASE + 0x0224) ++#define TOP_ADDR_DMA_WR_CON_0 (TOP_BASE + 0x0240) ++#define TOP_ADDR_DMA_WR_CON_1 (TOP_BASE + 0x0244) ++#define TOP_ADDR_DMA_WR_CON_2 (TOP_BASE + 0x0248) ++#define TOP_ADDR_DMA_WR_CON_3 (TOP_BASE + 0x024C) ++#define TOP_ADDR_DMA_WR_CON_4 (TOP_BASE + 0x0250) ++#define TOP_ADDR_DMA_WR_CON_5 (TOP_BASE + 0x0254) ++#define TOP_ADDR_DMA_WR_INFO_0 (TOP_BASE + 0x0280) ++#define TOP_ADDR_DMA_WR_INFO_1 (TOP_BASE + 0x0284) ++#define TOP_ADDR_DMA_WR_INFO_2 (TOP_BASE + 0x0288) ++#define TOP_ADDR_DMA_WR_INFO_3 (TOP_BASE + 0x028C) ++#define TOP_ADDR_DMA_WR_INFO_4 (TOP_BASE + 0x0290) ++#define TOP_ADDR_DMA_WR_INFO_5 (TOP_BASE + 0x0294) ++#define TOP_ADDR_DMA_WR_INFO_6 (TOP_BASE + 0x0298) ++#define TOP_ADDR_DMA_WR_INFO_7 (TOP_BASE + 0x029C) ++#define TOP_ADDR_DMA_WR_INFO_8 (TOP_BASE + 0x02A0) ++#define TOP_ADDR_DMA_WR_INFO_9 (TOP_BASE + 0x02A4) ++ ++//============================================================ ++// BLC ADDRESS ++//============================================================ ++#define MAIN_BLC_ADDR_SHD_CTRL (BLC0_BASE + 0x0000) ++#define MAIN_BLC_ADDR_BL_L_0 (BLC0_BASE + 0x0004) ++#define MAIN_BLC_ADDR_BL_L_1 (BLC0_BASE + 0x0008) ++#define MAIN_BLC_ADDR_BL_L_2 (BLC0_BASE + 0x000c) ++#define MAIN_BLC_ADDR_BL_MIN_L (BLC0_BASE + 0x0010) ++#define MAIN_BLC_ADDR_BL_S_0 (BLC0_BASE + 0x0014) ++#define MAIN_BLC_ADDR_BL_S_1 (BLC0_BASE + 0x0018) ++#define MAIN_BLC_ADDR_BL_S_2 (BLC0_BASE + 0x001c) ++#define MAIN_BLC_ADDR_BL_MIN_S (BLC0_BASE + 0x0020) ++#define MAIN_BLC_ADDR_R_G_GAIN_L (BLC0_BASE + 0x0024) ++#define MAIN_BLC_ADDR_B_IR_GAIN_L (BLC0_BASE + 0x0028) ++#define MAIN_BLC_ADDR_GAIN_SFT_OPT_L (BLC0_BASE + 0x002c) ++#define MAIN_BLC_ADDR_R_G_GAIN_S (BLC0_BASE + 0x0030) ++#define MAIN_BLC_ADDR_B_IR_GAIN_S (BLC0_BASE + 0x0034) ++#define MAIN_BLC_ADDR_GAIN_SFT_OPT_S (BLC0_BASE + 0x0038) ++#define MAIN_BLC_ADDR_DEBUG0 (BLC0_BASE + 0x003c) ++#define MAIN_BLC_ADDR_DEBUG1 (BLC0_BASE + 0x0040) ++#define MAIN_BLC_ADDR_DEBUG2 (BLC0_BASE + 0x0044) ++ ++#define SEC_BLC_ADDR_SHD_CTRL (BLC1_BASE + 0x0000) ++#define SEC_BLC_ADDR_BL_L_0 (BLC1_BASE + 0x0004) ++#define SEC_BLC_ADDR_BL_L_1 (BLC1_BASE + 0x0008) ++#define SEC_BLC_ADDR_BL_L_2 (BLC1_BASE + 0x000c) ++#define SEC_BLC_ADDR_BL_MIN_L (BLC1_BASE + 0x0010) ++#define SEC_BLC_ADDR_BL_S_0 (BLC1_BASE + 0x0014) ++#define SEC_BLC_ADDR_BL_S_1 (BLC1_BASE + 0x0018) ++#define SEC_BLC_ADDR_BL_S_2 (BLC1_BASE + 0x001c) ++#define SEC_BLC_ADDR_BL_MIN_S (BLC1_BASE + 0x0020) ++#define SEC_BLC_ADDR_R_G_GAIN_L (BLC1_BASE + 0x0024) ++#define SEC_BLC_ADDR_B_IR_GAIN_L (BLC1_BASE + 0x0028) ++#define SEC_BLC_ADDR_GAIN_SFT_OPT_L (BLC1_BASE + 0x002c) ++#define SEC_BLC_ADDR_R_G_GAIN_S (BLC1_BASE + 0x0030) ++#define SEC_BLC_ADDR_B_IR_GAIN_S (BLC1_BASE + 0x0034) ++#define SEC_BLC_ADDR_GAIN_SFT_OPT_S (BLC1_BASE + 0x0038) ++#define SEC_BLC_ADDR_DEBUG0 (BLC1_BASE + 0x003c) ++#define SEC_BLC_ADDR_DEBUG1 (BLC1_BASE + 0x0040) ++#define SEC_BLC_ADDR_DEBUG2 (BLC1_BASE + 0x0044) ++ ++//=========================================================== ++// LSC ADDRESS ++//============================================================ ++#define MAIN_LSC_ADDR_MESH_SIZE (LSC0_BASE + 0x0000) ++#define MAIN_LSC_ADDR_SCALE_MEAN_OFST (LSC0_BASE + 0x0004) ++#define MAIN_LSC_ADDR_DARK_ZONE_IMPRV_L (LSC0_BASE + 0x0008) ++#define MAIN_LSC_ADDR_DARK_ZONE_IMPRV_S (LSC0_BASE + 0x000c) ++#define MAIN_LSC_ADDR_FRAME_STREN (LSC0_BASE + 0x0010) ++#define MAIN_LSC_ADDR_DEBUG_0 (LSC0_BASE + 0x0014) ++#define MAIN_LSC_ADDR_DEBUG_1 (LSC0_BASE + 0x0018) ++#define MAIN_LSC_ADDR_DEBUG_2 (LSC0_BASE + 0x001c) ++#define MAIN_LSC_ADDR_DEBUG_3 (LSC0_BASE + 0x0020) ++#define MAIN_LSC_ADDR_DEBUG_4 (LSC0_BASE + 0x0024) ++#define MAIN_LSC_ADDR_DEBUG_5 (LSC0_BASE + 0x0028) ++#define MAIN_LSC_ADDR_DEBUG_6 (LSC0_BASE + 0x002c) ++#define MAIN_LSC_ADDR_DEBUG_7 (LSC0_BASE + 0x0030) ++#define MAIN_LSC_ADDR_DEBUG_8 (LSC0_BASE + 0x0034) ++#define MAIN_LSC_ADDR_DEBUG_9 (LSC0_BASE + 0x0038) ++#define MAIN_LSC_ADDR_DEBUG_10 (LSC0_BASE + 0x003c) ++#define MAIN_LSC_ADDR_DEBUG_11 (LSC0_BASE + 0x0040) ++#define MAIN_LSC_ADDR_DEBUG_12 (LSC0_BASE + 0x0044) ++#define MAIN_LSC_ADDR_DEBUG_13 (LSC0_BASE + 0x0048) ++#define MAIN_LSC_ADDR_DEBUG_14 (LSC0_BASE + 0x004c) ++#define MAIN_LSC_ADDR_DEBUG_15 (LSC0_BASE + 0x0050) ++#define MAIN_LSC_ADDR_DEBUG_16 (LSC0_BASE + 0x0054) ++#define MAIN_LSC_ADDR_DEBUG_17 (LSC0_BASE + 0x0058) ++#define MAIN_LSC_ADDR_DEBUG_18 (LSC0_BASE + 0x005c) ++#define MAIN_LSC_ADDR_DEBUG_19 (LSC0_BASE + 0x0060) ++#define MAIN_LSC_ADDR_DEBUG_20 (LSC0_BASE + 0x0064) ++#define MAIN_LSC_ADDR_DEBUG_21 (LSC0_BASE + 0x0068) ++#define MAIN_LSC_ADDR_DEBUG_22 (LSC0_BASE + 0x006c) ++ ++#define SEC_LSC_ADDR_MESH_SIZE (LSC1_BASE + 0x0000) ++#define SEC_LSC_ADDR_SCALE_MEAN_OFST (LSC1_BASE + 0x0004) ++#define SEC_LSC_ADDR_DARK_ZONE_IMPRV_L (LSC1_BASE + 0x0008) ++#define SEC_LSC_ADDR_DARK_ZONE_IMPRV_S (LSC1_BASE + 0x000c) ++#define SEC_LSC_ADDR_FRAME_STREN (LSC1_BASE + 0x0010) ++#define SEC_LSC_ADDR_DEBUG_0 (LSC1_BASE + 0x0014) ++#define SEC_LSC_ADDR_DEBUG_1 (LSC1_BASE + 0x0018) ++#define SEC_LSC_ADDR_DEBUG_2 (LSC1_BASE + 0x001c) ++#define SEC_LSC_ADDR_DEBUG_3 (LSC1_BASE + 0x0020) ++#define SEC_LSC_ADDR_DEBUG_4 (LSC1_BASE + 0x0024) ++#define SEC_LSC_ADDR_DEBUG_5 (LSC1_BASE + 0x0028) ++#define SEC_LSC_ADDR_DEBUG_6 (LSC1_BASE + 0x002c) ++#define SEC_LSC_ADDR_DEBUG_7 (LSC1_BASE + 0x0030) ++#define SEC_LSC_ADDR_DEBUG_8 (LSC1_BASE + 0x0034) ++#define SEC_LSC_ADDR_DEBUG_9 (LSC1_BASE + 0x0038) ++#define SEC_LSC_ADDR_DEBUG_10 (LSC1_BASE + 0x003c) ++#define SEC_LSC_ADDR_DEBUG_11 (LSC1_BASE + 0x0040) ++#define SEC_LSC_ADDR_DEBUG_12 (LSC1_BASE + 0x0044) ++#define SEC_LSC_ADDR_DEBUG_13 (LSC1_BASE + 0x0048) ++#define SEC_LSC_ADDR_DEBUG_14 (LSC1_BASE + 0x004c) ++#define SEC_LSC_ADDR_DEBUG_15 (LSC1_BASE + 0x0050) ++#define SEC_LSC_ADDR_DEBUG_16 (LSC1_BASE + 0x0054) ++#define SEC_LSC_ADDR_DEBUG_17 (LSC1_BASE + 0x0058) ++#define SEC_LSC_ADDR_DEBUG_18 (LSC1_BASE + 0x005c) ++#define SEC_LSC_ADDR_DEBUG_19 (LSC1_BASE + 0x0060) ++#define SEC_LSC_ADDR_DEBUG_20 (LSC1_BASE + 0x0064) ++#define SEC_LSC_ADDR_DEBUG_21 (LSC1_BASE + 0x0068) ++#define SEC_LSC_ADDR_DEBUG_22 (LSC1_BASE + 0x006c) ++ ++//============================================================ ++// AWBG0 ADDRESS ++//============================================================ ++#define MAIN_AWBG0_ADDR_SHD_CTRL (AWBG00_BASE + 0x0000) ++#define MAIN_AWBG0_ADDR_R_G_GAIN_L (AWBG00_BASE + 0x0004) ++#define MAIN_AWBG0_ADDR_B_IR_GAIN_L (AWBG00_BASE + 0x0008) ++#define MAIN_AWBG0_ADDR_R_G_GAIN_S (AWBG00_BASE + 0x000c) ++#define MAIN_AWBG0_ADDR_B_IR_GAIN_S (AWBG00_BASE + 0x0010) ++#define MAIN_AWBG0_ADDR_DEBUG1 (AWBG00_BASE + 0x0014) ++#define MAIN_AWBG0_ADDR_DEBUG2 (AWBG00_BASE + 0x0018) ++ ++#define SEC_AWBG0_ADDR_SHD_CTRL (AWBG01_BASE + 0x0000) ++#define SEC_AWBG0_ADDR_R_G_GAIN_L (AWBG01_BASE + 0x0004) ++#define SEC_AWBG0_ADDR_B_IR_GAIN_L (AWBG01_BASE + 0x0008) ++#define SEC_AWBG0_ADDR_R_G_GAIN_S (AWBG01_BASE + 0x000c) ++#define SEC_AWBG0_ADDR_B_IR_GAIN_S (AWBG01_BASE + 0x0010) ++#define SEC_AWBG0_ADDR_DEBUG1 (AWBG01_BASE + 0x0014) ++#define SEC_AWBG0_ADDR_DEBUG2 (AWBG01_BASE + 0x0018) ++ ++//============================================================ ++// WDR ADDRESS ++//============================================================ ++#define WDR_ADDR_T_VERSION(n) (WDR_BASE(n) + 0x0000) ++#define WDR_ADDR_STA_ST_ADDR_000_00(n) (WDR_BASE(n) + 0x0010) ++#define WDR_ADDR_STA_ST_ADDR_001_01(n) (WDR_BASE(n) + 0x0014) ++#define WDR_ADDR_STA_ST_ADDR_002_02(n) (WDR_BASE(n) + 0x0018) ++#define WDR_ADDR_STA_ST_ADDR_003_03(n) (WDR_BASE(n) + 0x001c) ++#define WDR_ADDR_STA_BUF_NUM(n) (WDR_BASE(n) + 0x0030) ++#define WDR_ADDR_STA_EXT_PRIO(n) (WDR_BASE(n) + 0x0034) ++#define WDR_ADDR_DEBUG(n) (WDR_BASE(n) + 0x0040) ++#define WDR_ADDR_STA_THR(n) (WDR_BASE(n) + 0x0048) ++#define WDR_ADDR_DEGOSTPARA_0(n) (WDR_BASE(n) + 0x004c) ++#define WDR_ADDR_DEGOSTPARA_1(n) (WDR_BASE(n) + 0x0050) ++#define WDR_ADDR_DEGOSTPARA_2(n) (WDR_BASE(n) + 0x0054) ++#define WDR_ADDR_DEGOSTPARA_3(n) (WDR_BASE(n) + 0x0058) ++#define WDR_ADDR_DEGOSTPARA_4(n) (WDR_BASE(n) + 0x005c) ++#define WDR_ADDR_MAPR_01_00(n) (WDR_BASE(n) + 0x0060) ++#define WDR_ADDR_MAPR_03_02(n) (WDR_BASE(n) + 0x0064) ++#define WDR_ADDR_MAPR_05_04(n) (WDR_BASE(n) + 0x0068) ++#define WDR_ADDR_MAPR_07_06(n) (WDR_BASE(n) + 0x006c) ++#define WDR_ADDR_MAPR_09_08(n) (WDR_BASE(n) + 0x0070) ++#define WDR_ADDR_MAPR_11_10(n) (WDR_BASE(n) + 0x0074) ++#define WDR_ADDR_MAPR_13_12(n) (WDR_BASE(n) + 0x0078) ++#define WDR_ADDR_MAPR_15_14(n) (WDR_BASE(n) + 0x007c) ++#define WDR_ADDR_MAPR_17_16(n) (WDR_BASE(n) + 0x0080) ++#define WDR_ADDR_MAPR_19_18(n) (WDR_BASE(n) + 0x0084) ++#define WDR_ADDR_MAPR_21_20(n) (WDR_BASE(n) + 0x0088) ++#define WDR_ADDR_MAPR_23_22(n) (WDR_BASE(n) + 0x008c) ++#define WDR_ADDR_MAPR_25_24(n) (WDR_BASE(n) + 0x0090) ++#define WDR_ADDR_MAPR_27_26(n) (WDR_BASE(n) + 0x0094) ++#define WDR_ADDR_MAPR_29_28(n) (WDR_BASE(n) + 0x0098) ++#define WDR_ADDR_MAPR_31_30(n) (WDR_BASE(n) + 0x009c) ++#define WDR_ADDR_MAPR_33_32(n) (WDR_BASE(n) + 0x00a0) ++#define WDR_ADDR_MAPR_35_34(n) (WDR_BASE(n) + 0x00a4) ++#define WDR_ADDR_MAPR_37_36(n) (WDR_BASE(n) + 0x00a8) ++#define WDR_ADDR_MAPR_39_38(n) (WDR_BASE(n) + 0x00ac) ++#define WDR_ADDR_MAPR_41_40(n) (WDR_BASE(n) + 0x00b0) ++#define WDR_ADDR_MAPR_43_42(n) (WDR_BASE(n) + 0x00b4) ++#define WDR_ADDR_MAPR_45_44(n) (WDR_BASE(n) + 0x00b8) ++#define WDR_ADDR_MAPR_47_46(n) (WDR_BASE(n) + 0x00bc) ++#define WDR_ADDR_MAPR_49_48(n) (WDR_BASE(n) + 0x00c0) ++#define WDR_ADDR_MAPR_51_50(n) (WDR_BASE(n) + 0x00c4) ++#define WDR_ADDR_MAPR_53_52(n) (WDR_BASE(n) + 0x00c8) ++#define WDR_ADDR_MAPR_55_54(n) (WDR_BASE(n) + 0x00cc) ++#define WDR_ADDR_MAPR_57_56(n) (WDR_BASE(n) + 0x00d0) ++#define WDR_ADDR_MAPR_59_58(n) (WDR_BASE(n) + 0x00d4) ++#define WDR_ADDR_MAPR_61_60(n) (WDR_BASE(n) + 0x00d8) ++#define WDR_ADDR_MAPR_63_62(n) (WDR_BASE(n) + 0x00dc) ++#define WDR_ADDR_MAPR_65_64(n) (WDR_BASE(n) + 0x00e0) ++#define WDR_ADDR_MAPR_67_66(n) (WDR_BASE(n) + 0x00e4) ++#define WDR_ADDR_MAPR_69_68(n) (WDR_BASE(n) + 0x00e8) ++#define WDR_ADDR_MAPR_71_70(n) (WDR_BASE(n) + 0x00ec) ++#define WDR_ADDR_MAPR_73_72(n) (WDR_BASE(n) + 0x00f0) ++#define WDR_ADDR_MAPR_75_74(n) (WDR_BASE(n) + 0x00f4) ++#define WDR_ADDR_MAPR_77_76(n) (WDR_BASE(n) + 0x00f8) ++#define WDR_ADDR_MAPR_79_78(n) (WDR_BASE(n) + 0x00fc) ++#define WDR_ADDR_MAPR_80_80(n) (WDR_BASE(n) + 0x0100) ++#define WDR_ADDR_MAPG_01_00(n) (WDR_BASE(n) + 0x0104) ++#define WDR_ADDR_MAPG_03_02(n) (WDR_BASE(n) + 0x0108) ++#define WDR_ADDR_MAPG_05_04(n) (WDR_BASE(n) + 0x010c) ++#define WDR_ADDR_MAPG_07_06(n) (WDR_BASE(n) + 0x0110) ++#define WDR_ADDR_MAPG_09_08(n) (WDR_BASE(n) + 0x0114) ++#define WDR_ADDR_MAPG_11_10(n) (WDR_BASE(n) + 0x0118) ++#define WDR_ADDR_MAPG_13_12(n) (WDR_BASE(n) + 0x011c) ++#define WDR_ADDR_MAPG_15_14(n) (WDR_BASE(n) + 0x0120) ++#define WDR_ADDR_MAPG_17_16(n) (WDR_BASE(n) + 0x0124) ++#define WDR_ADDR_MAPG_19_18(n) (WDR_BASE(n) + 0x0128) ++#define WDR_ADDR_MAPG_21_20(n) (WDR_BASE(n) + 0x012c) ++#define WDR_ADDR_MAPG_23_22(n) (WDR_BASE(n) + 0x0130) ++#define WDR_ADDR_MAPG_25_24(n) (WDR_BASE(n) + 0x0134) ++#define WDR_ADDR_MAPG_27_26(n) (WDR_BASE(n) + 0x0138) ++#define WDR_ADDR_MAPG_29_28(n) (WDR_BASE(n) + 0x013c) ++#define WDR_ADDR_MAPG_31_30(n) (WDR_BASE(n) + 0x0140) ++#define WDR_ADDR_MAPG_33_32(n) (WDR_BASE(n) + 0x0144) ++#define WDR_ADDR_MAPG_35_34(n) (WDR_BASE(n) + 0x0148) ++#define WDR_ADDR_MAPG_37_36(n) (WDR_BASE(n) + 0x014c) ++#define WDR_ADDR_MAPG_39_38(n) (WDR_BASE(n) + 0x0150) ++#define WDR_ADDR_MAPG_41_40(n) (WDR_BASE(n) + 0x0154) ++#define WDR_ADDR_MAPG_43_42(n) (WDR_BASE(n) + 0x0158) ++#define WDR_ADDR_MAPG_45_44(n) (WDR_BASE(n) + 0x015c) ++#define WDR_ADDR_MAPG_47_46(n) (WDR_BASE(n) + 0x0160) ++#define WDR_ADDR_MAPG_49_48(n) (WDR_BASE(n) + 0x0164) ++#define WDR_ADDR_MAPG_51_50(n) (WDR_BASE(n) + 0x0168) ++#define WDR_ADDR_MAPG_53_52(n) (WDR_BASE(n) + 0x016c) ++#define WDR_ADDR_MAPG_55_54(n) (WDR_BASE(n) + 0x0170) ++#define WDR_ADDR_MAPG_57_56(n) (WDR_BASE(n) + 0x0174) ++#define WDR_ADDR_MAPG_59_58(n) (WDR_BASE(n) + 0x0178) ++#define WDR_ADDR_MAPG_61_60(n) (WDR_BASE(n) + 0x017c) ++#define WDR_ADDR_MAPG_63_62(n) (WDR_BASE(n) + 0x0180) ++#define WDR_ADDR_MAPG_65_64(n) (WDR_BASE(n) + 0x0184) ++#define WDR_ADDR_MAPG_67_66(n) (WDR_BASE(n) + 0x0188) ++#define WDR_ADDR_MAPG_69_68(n) (WDR_BASE(n) + 0x018c) ++#define WDR_ADDR_MAPG_71_70(n) (WDR_BASE(n) + 0x0190) ++#define WDR_ADDR_MAPG_73_72(n) (WDR_BASE(n) + 0x0194) ++#define WDR_ADDR_MAPG_75_74(n) (WDR_BASE(n) + 0x0198) ++#define WDR_ADDR_MAPG_77_76(n) (WDR_BASE(n) + 0x019c) ++#define WDR_ADDR_MAPG_79_78(n) (WDR_BASE(n) + 0x01a0) ++#define WDR_ADDR_MAPG_80_80(n) (WDR_BASE(n) + 0x01a4) ++#define WDR_ADDR_MAPB_01_00(n) (WDR_BASE(n) + 0x01a8) ++#define WDR_ADDR_MAPB_03_02(n) (WDR_BASE(n) + 0x01ac) ++#define WDR_ADDR_MAPB_05_04(n) (WDR_BASE(n) + 0x01b0) ++#define WDR_ADDR_MAPB_07_06(n) (WDR_BASE(n) + 0x01b4) ++#define WDR_ADDR_MAPB_09_08(n) (WDR_BASE(n) + 0x01b8) ++#define WDR_ADDR_MAPB_11_10(n) (WDR_BASE(n) + 0x01bc) ++#define WDR_ADDR_MAPB_13_12(n) (WDR_BASE(n) + 0x01c0) ++#define WDR_ADDR_MAPB_15_14(n) (WDR_BASE(n) + 0x01c4) ++#define WDR_ADDR_MAPB_17_16(n) (WDR_BASE(n) + 0x01c8) ++#define WDR_ADDR_MAPB_19_18(n) (WDR_BASE(n) + 0x01cc) ++#define WDR_ADDR_MAPB_21_20(n) (WDR_BASE(n) + 0x01d0) ++#define WDR_ADDR_MAPB_23_22(n) (WDR_BASE(n) + 0x01d4) ++#define WDR_ADDR_MAPB_25_24(n) (WDR_BASE(n) + 0x01d8) ++#define WDR_ADDR_MAPB_27_26(n) (WDR_BASE(n) + 0x01dc) ++#define WDR_ADDR_MAPB_29_28(n) (WDR_BASE(n) + 0x01e0) ++#define WDR_ADDR_MAPB_31_30(n) (WDR_BASE(n) + 0x01e4) ++#define WDR_ADDR_MAPB_33_32(n) (WDR_BASE(n) + 0x01e8) ++#define WDR_ADDR_MAPB_35_34(n) (WDR_BASE(n) + 0x01ec) ++#define WDR_ADDR_MAPB_37_36(n) (WDR_BASE(n) + 0x01f0) ++#define WDR_ADDR_MAPB_39_38(n) (WDR_BASE(n) + 0x01f4) ++#define WDR_ADDR_MAPB_41_40(n) (WDR_BASE(n) + 0x01f8) ++#define WDR_ADDR_MAPB_43_42(n) (WDR_BASE(n) + 0x01fc) ++#define WDR_ADDR_MAPB_45_44(n) (WDR_BASE(n) + 0x0200) ++#define WDR_ADDR_MAPB_47_46(n) (WDR_BASE(n) + 0x0204) ++#define WDR_ADDR_MAPB_49_48(n) (WDR_BASE(n) + 0x0208) ++#define WDR_ADDR_MAPB_51_50(n) (WDR_BASE(n) + 0x020c) ++#define WDR_ADDR_MAPB_53_52(n) (WDR_BASE(n) + 0x0210) ++#define WDR_ADDR_MAPB_55_54(n) (WDR_BASE(n) + 0x0214) ++#define WDR_ADDR_MAPB_57_56(n) (WDR_BASE(n) + 0x0218) ++#define WDR_ADDR_MAPB_59_58(n) (WDR_BASE(n) + 0x021c) ++#define WDR_ADDR_MAPB_61_60(n) (WDR_BASE(n) + 0x0220) ++#define WDR_ADDR_MAPB_63_62(n) (WDR_BASE(n) + 0x0224) ++#define WDR_ADDR_MAPB_65_64(n) (WDR_BASE(n) + 0x0228) ++#define WDR_ADDR_MAPB_67_66(n) (WDR_BASE(n) + 0x022c) ++#define WDR_ADDR_MAPB_69_68(n) (WDR_BASE(n) + 0x0230) ++#define WDR_ADDR_MAPB_71_70(n) (WDR_BASE(n) + 0x0234) ++#define WDR_ADDR_MAPB_73_72(n) (WDR_BASE(n) + 0x0238) ++#define WDR_ADDR_MAPB_75_74(n) (WDR_BASE(n) + 0x023c) ++#define WDR_ADDR_MAPB_77_76(n) (WDR_BASE(n) + 0x0240) ++#define WDR_ADDR_MAPB_79_78(n) (WDR_BASE(n) + 0x0244) ++#define WDR_ADDR_MAPB_80_80(n) (WDR_BASE(n) + 0x0248) ++#define WDR_ADDR_THRLABLE_01_00(n) (WDR_BASE(n) + 0x024c) ++#define WDR_ADDR_THRLABLE_03_02(n) (WDR_BASE(n) + 0x0250) ++#define WDR_ADDR_THRLABLE_05_04(n) (WDR_BASE(n) + 0x0254) ++#define WDR_ADDR_THRLABLE_07_06(n) (WDR_BASE(n) + 0x0258) ++#define WDR_ADDR_THRLABLE_09_08(n) (WDR_BASE(n) + 0x025c) ++#define WDR_ADDR_THRLABLE_11_10(n) (WDR_BASE(n) + 0x0260) ++#define WDR_ADDR_THRLABLE_13_12(n) (WDR_BASE(n) + 0x0264) ++#define WDR_ADDR_THRLABLE_15_14(n) (WDR_BASE(n) + 0x0268) ++#define WDR_ADDR_THRLABLE_17_16(n) (WDR_BASE(n) + 0x026c) ++#define WDR_ADDR_THRLABLE_19_18(n) (WDR_BASE(n) + 0x0270) ++#define WDR_ADDR_THRLABLE_21_20(n) (WDR_BASE(n) + 0x0274) ++#define WDR_ADDR_THRLABLE_23_22(n) (WDR_BASE(n) + 0x0278) ++#define WDR_ADDR_THRLABLE_25_24(n) (WDR_BASE(n) + 0x027c) ++#define WDR_ADDR_THRLABLE_26_26(n) (WDR_BASE(n) + 0x0280) ++#define WDR_ADDR_THRLABLEN_01_00(n) (WDR_BASE(n) + 0x0284) ++#define WDR_ADDR_THRLABLEN_03_02(n) (WDR_BASE(n) + 0x0288) ++#define WDR_ADDR_THRLABLEN_05_04(n) (WDR_BASE(n) + 0x028c) ++#define WDR_ADDR_THRLABLEN_07_06(n) (WDR_BASE(n) + 0x0290) ++#define WDR_ADDR_THRLABLEN_09_08(n) (WDR_BASE(n) + 0x0294) ++#define WDR_ADDR_THRLABLEN_11_10(n) (WDR_BASE(n) + 0x0298) ++#define WDR_ADDR_THRLABLEN_13_12(n) (WDR_BASE(n) + 0x029c) ++#define WDR_ADDR_THRLABLEN_15_14(n) (WDR_BASE(n) + 0x02a0) ++#define WDR_ADDR_THRLABLEN_17_16(n) (WDR_BASE(n) + 0x02a4) ++#define WDR_ADDR_THRLABLEN_19_18(n) (WDR_BASE(n) + 0x02a8) ++#define WDR_ADDR_THRLABLEN_21_20(n) (WDR_BASE(n) + 0x02ac) ++#define WDR_ADDR_THRLABLEN_23_22(n) (WDR_BASE(n) + 0x02b0) ++#define WDR_ADDR_THRLABLEN_25_24(n) (WDR_BASE(n) + 0x02b4) ++#define WDR_ADDR_THRALL_01_00(n) (WDR_BASE(n) + 0x02b8) ++#define WDR_ADDR_THRALL_03_02(n) (WDR_BASE(n) + 0x02bc) ++#define WDR_ADDR_THRALL_05_04(n) (WDR_BASE(n) + 0x02c0) ++#define WDR_ADDR_THRALL_07_06(n) (WDR_BASE(n) + 0x02c4) ++#define WDR_ADDR_THRALL_09_08(n) (WDR_BASE(n) + 0x02c8) ++#define WDR_ADDR_THRALL_11_10(n) (WDR_BASE(n) + 0x02cc) ++#define WDR_ADDR_THRALL_13_12(n) (WDR_BASE(n) + 0x02d0) ++#define WDR_ADDR_THRALL_15_14(n) (WDR_BASE(n) + 0x02d4) ++#define WDR_ADDR_THRALL_17_16(n) (WDR_BASE(n) + 0x02d8) ++#define WDR_ADDR_THRALL_19_18(n) (WDR_BASE(n) + 0x02dc) ++#define WDR_ADDR_THRALL_21_20(n) (WDR_BASE(n) + 0x02e0) ++#define WDR_ADDR_THRALL_23_22(n) (WDR_BASE(n) + 0x02e4) ++#define WDR_ADDR_THRALL_25_24(n) (WDR_BASE(n) + 0x02e8) ++#define WDR_ADDR_THRALL_26_26(n) (WDR_BASE(n) + 0x02ec) ++#define WDR_ADDR_THRRANGEK_00_00(n) (WDR_BASE(n) + 0x02f0) ++#define WDR_ADDR_THRRANGEK_01_01(n) (WDR_BASE(n) + 0x02f4) ++#define WDR_ADDR_THRRANGEK_02_02(n) (WDR_BASE(n) + 0x02f8) ++#define WDR_ADDR_THRRANGEK_03_03(n) (WDR_BASE(n) + 0x02fc) ++#define WDR_ADDR_THRRANGEK_04_04(n) (WDR_BASE(n) + 0x0300) ++#define WDR_ADDR_THRRANGEK_05_05(n) (WDR_BASE(n) + 0x0304) ++#define WDR_ADDR_THRRANGEK_06_06(n) (WDR_BASE(n) + 0x0308) ++#define WDR_ADDR_THRRANGEK_07_07(n) (WDR_BASE(n) + 0x030c) ++#define WDR_ADDR_THRRANGEK_08_08(n) (WDR_BASE(n) + 0x0310) ++#define WDR_ADDR_THRRANGEK_09_09(n) (WDR_BASE(n) + 0x0314) ++#define WDR_ADDR_THRRANGEK_10_10(n) (WDR_BASE(n) + 0x0318) ++#define WDR_ADDR_THRRANGEK_11_11(n) (WDR_BASE(n) + 0x031c) ++#define WDR_ADDR_THRRANGEK_12_12(n) (WDR_BASE(n) + 0x0320) ++#define WDR_ADDR_THRRANGEK_13_13(n) (WDR_BASE(n) + 0x0324) ++#define WDR_ADDR_THRRANGEK_14_14(n) (WDR_BASE(n) + 0x0328) ++#define WDR_ADDR_THRRANGEK_15_15(n) (WDR_BASE(n) + 0x032c) ++#define WDR_ADDR_THRRANGEK_16_16(n) (WDR_BASE(n) + 0x0330) ++#define WDR_ADDR_THRRANGEK_17_17(n) (WDR_BASE(n) + 0x0334) ++#define WDR_ADDR_THRRANGEK_18_18(n) (WDR_BASE(n) + 0x0338) ++#define WDR_ADDR_THRRANGEK_19_19(n) (WDR_BASE(n) + 0x033c) ++#define WDR_ADDR_THRRANGEK_20_20(n) (WDR_BASE(n) + 0x0340) ++#define WDR_ADDR_THRRANGEK_21_21(n) (WDR_BASE(n) + 0x0344) ++#define WDR_ADDR_THRRANGEK_22_22(n) (WDR_BASE(n) + 0x0348) ++#define WDR_ADDR_THRRANGEK_23_23(n) (WDR_BASE(n) + 0x034c) ++#define WDR_ADDR_THRRANGEK_24_24(n) (WDR_BASE(n) + 0x0350) ++#define WDR_ADDR_THRRANGEK_25_25(n) (WDR_BASE(n) + 0x0354) ++#define WDR_ADDR_THRRANGEK_26_26(n) (WDR_BASE(n) + 0x0358) ++#define WDR_ADDR_DARKLABLE_01_00(n) (WDR_BASE(n) + 0x035c) ++#define WDR_ADDR_DARKLABLE_03_02(n) (WDR_BASE(n) + 0x0360) ++#define WDR_ADDR_DARKLABLE_04_04(n) (WDR_BASE(n) + 0x0364) ++#define WDR_ADDR_DARKLABLEN_01_00(n) (WDR_BASE(n) + 0x0368) ++#define WDR_ADDR_DARKLABLEN_03_02(n) (WDR_BASE(n) + 0x036c) ++#define WDR_ADDR_DARKWEIGHT_01_00(n) (WDR_BASE(n) + 0x0370) ++#define WDR_ADDR_DARKWEIGHT_03_02(n) (WDR_BASE(n) + 0x0374) ++#define WDR_ADDR_DARKWEIGHT_04_04(n) (WDR_BASE(n) + 0x0378) ++#define WDR_ADDR_NOISEREDUCELABLE_00_00(n) (WDR_BASE(n) + 0x037c) ++#define WDR_ADDR_LABLE_ENRATE(n) (WDR_BASE(n) + 0x0380) ++#define WDR_ADDR_VALUE_ENRATE(n) (WDR_BASE(n) + 0x0384) ++#define WDR_ADDR_K_ENRATE1(n) (WDR_BASE(n) + 0x0388) ++#define WDR_ADDR_K_ENRATE2(n) (WDR_BASE(n) + 0x038c) ++#define WDR_ADDR_ENMAXMIN_V1(n) (WDR_BASE(n) + 0x0390) ++#define WDR_ADDR_RATIO_MINMAX_X(n) (WDR_BASE(n) + 0x0394) ++#define WDR_ADDR_K_RATIO_MINMAX_Y(n) (WDR_BASE(n) + 0x039c) ++#define WDR_ADDR_K_K_RATIO(n) (WDR_BASE(n) + 0x03a0) ++#define WDR_ADDR_FUSIONTHRMINMAX_X(n) (WDR_BASE(n) + 0x03a4) ++#define WDR_ADDR_K_WEIGHT(n) (WDR_BASE(n) + 0x03a8) ++#define WDR_ADDR_MAXVALUE(n) (WDR_BASE(n) + 0x03ac) ++#define WDR_ADDR_TMP_MAXVALUE(n) (WDR_BASE(n) + 0x03b0) ++#define WDR_ADDR_THR_MAXVALUE_12BIT(n) (WDR_BASE(n) + 0x03b4) ++#define WDR_ADDR_TMP_FUSION_MAX(n) (WDR_BASE(n) + 0x03b8) ++#define WDR_ADDR_W_FUSION_X(n) (WDR_BASE(n) + 0x03bc) ++#define WDR_ADDR_K_W_FUSION0(n) (WDR_BASE(n) + 0x03c0) ++#define WDR_ADDR_LAMDA_01(n) (WDR_BASE(n) + 0x03c4) ++#define WDR_ADDR_LAMDA_23(n) (WDR_BASE(n) + 0x03c8) ++#define WDR_ADDR_LAMDA_4(n) (WDR_BASE(n) + 0x03cc) ++#define WDR_ADDR_W_FUSION_X1(n) (WDR_BASE(n) + 0x03d0) ++#define WDR_ADDR_W_FUSION_X_N(n) (WDR_BASE(n) + 0x03d4) ++#define WDR_ADDR_CONSTRACT_MAXVALUE_LOG(n) (WDR_BASE(n) + 0x03d8) ++#define WDR_ADDR_TMP_MAXVALUE_LOG(n) (WDR_BASE(n) + 0x03dc) ++#define WDR_ADDR_LABLE_EN_01(n) (WDR_BASE(n) + 0x03e0) ++#define WDR_ADDR_LABLE_EN_2(n) (WDR_BASE(n) + 0x03e4) ++#define WDR_ADDR_VALUE_EN1(n) (WDR_BASE(n) + 0x03e8) ++#define WDR_ADDR_LABLE_EN_Y_01(n) (WDR_BASE(n) + 0x03ec) ++#define WDR_ADDR_LABLE_EN_Y_2(n) (WDR_BASE(n) + 0x03f0) ++#define WDR_ADDR_K_EN1(n) (WDR_BASE(n) + 0x03f4) ++#define WDR_ADDR_K_EN2(n) (WDR_BASE(n) + 0x03f8) ++#define WDR_ADDR_TMP_EN1(n) (WDR_BASE(n) + 0x03fc) ++#define WDR_ADDR_TMP_EN2(n) (WDR_BASE(n) + 0x0400) ++#define WDR_ADDR_D_RATIO(n) (WDR_BASE(n) + 0x0404) ++#define WDR_ADDR_LABLE_Y_SHORT(n) (WDR_BASE(n) + 0x0408) ++#define WDR_ADDR_LABLE_W(n) (WDR_BASE(n) + 0x040c) ++#define WDR_ADDR_THR_DENOISE(n) (WDR_BASE(n) + 0x0410) ++#define WDR_ADDR_VALUE_GAMMA_01_00(n) (WDR_BASE(n) + 0x0420) ++#define WDR_ADDR_VALUE_GAMMA_03_02(n) (WDR_BASE(n) + 0x0424) ++#define WDR_ADDR_VALUE_GAMMA_05_04(n) (WDR_BASE(n) + 0x0428) ++#define WDR_ADDR_VALUE_GAMMA_07_06(n) (WDR_BASE(n) + 0x042c) ++#define WDR_ADDR_VALUE_GAMMA_09_08(n) (WDR_BASE(n) + 0x0430) ++#define WDR_ADDR_VALUE_GAMMA_11_10(n) (WDR_BASE(n) + 0x0434) ++#define WDR_ADDR_VALUE_GAMMA_13_12(n) (WDR_BASE(n) + 0x0438) ++#define WDR_ADDR_VALUE_GAMMA_15_14(n) (WDR_BASE(n) + 0x043c) ++#define WDR_ADDR_VALUE_GAMMA_17_16(n) (WDR_BASE(n) + 0x0440) ++#define WDR_ADDR_VALUE_GAMMA_19_18(n) (WDR_BASE(n) + 0x0444) ++#define WDR_ADDR_VALUE_GAMMA_21_20(n) (WDR_BASE(n) + 0x0448) ++#define WDR_ADDR_VALUE_GAMMA_23_22(n) (WDR_BASE(n) + 0x044c) ++#define WDR_ADDR_VALUE_GAMMA_25_24(n) (WDR_BASE(n) + 0x0450) ++#define WDR_ADDR_VALUE_GAMMA_27_26(n) (WDR_BASE(n) + 0x0454) ++#define WDR_ADDR_VALUE_GAMMA_29_28(n) (WDR_BASE(n) + 0x0458) ++#define WDR_ADDR_VALUE_GAMMA_31_30(n) (WDR_BASE(n) + 0x045c) ++#define WDR_ADDR_VALUE_GAMMA_33_32(n) (WDR_BASE(n) + 0x0460) ++#define WDR_ADDR_VALUE_GAMMA_35_34(n) (WDR_BASE(n) + 0x0464) ++#define WDR_ADDR_VALUE_GAMMA_37_36(n) (WDR_BASE(n) + 0x0468) ++#define WDR_ADDR_VALUE_GAMMA_39_38(n) (WDR_BASE(n) + 0x046c) ++#define WDR_ADDR_VALUE_GAMMA_41_40(n) (WDR_BASE(n) + 0x0470) ++#define WDR_ADDR_VALUE_GAMMA_43_42(n) (WDR_BASE(n) + 0x0474) ++#define WDR_ADDR_VALUE_GAMMA_45_44(n) (WDR_BASE(n) + 0x0478) ++#define WDR_ADDR_VALUE_GAMMA_47_46(n) (WDR_BASE(n) + 0x047c) ++#define WDR_ADDR_VALUE_GAMMA_49_48(n) (WDR_BASE(n) + 0x0480) ++#define WDR_ADDR_VALUE_GAMMA_51_50(n) (WDR_BASE(n) + 0x0484) ++#define WDR_ADDR_VALUE_GAMMA_53_52(n) (WDR_BASE(n) + 0x0488) ++#define WDR_ADDR_VALUE_GAMMA_55_54(n) (WDR_BASE(n) + 0x048c) ++#define WDR_ADDR_VALUE_GAMMA_57_56(n) (WDR_BASE(n) + 0x0490) ++#define WDR_ADDR_VALUE_GAMMA_59_58(n) (WDR_BASE(n) + 0x0494) ++#define WDR_ADDR_VALUE_GAMMA_61_60(n) (WDR_BASE(n) + 0x0498) ++#define WDR_ADDR_VALUE_GAMMA_63_62(n) (WDR_BASE(n) + 0x049c) ++#define WDR_ADDR_VALUE_GAMMA_65_64(n) (WDR_BASE(n) + 0x04a0) ++#define WDR_ADDR_VALUE_GAMMA_67_66(n) (WDR_BASE(n) + 0x04a4) ++#define WDR_ADDR_VALUE_GAMMA_69_68(n) (WDR_BASE(n) + 0x04a8) ++#define WDR_ADDR_VALUE_GAMMA_71_70(n) (WDR_BASE(n) + 0x04ac) ++#define WDR_ADDR_VALUE_GAMMA_73_72(n) (WDR_BASE(n) + 0x04b0) ++#define WDR_ADDR_VALUE_GAMMA_75_74(n) (WDR_BASE(n) + 0x04b4) ++#define WDR_ADDR_VALUE_GAMMA_77_76(n) (WDR_BASE(n) + 0x04b8) ++#define WDR_ADDR_VALUE_GAMMA_79_78(n) (WDR_BASE(n) + 0x04bc) ++#define WDR_ADDR_VALUE_GAMMA_81_80(n) (WDR_BASE(n) + 0x04c0) ++#define WDR_ADDR_VALUE_GAMMA_83_82(n) (WDR_BASE(n) + 0x04c4) ++#define WDR_ADDR_VALUE_GAMMA_85_84(n) (WDR_BASE(n) + 0x04c8) ++#define WDR_ADDR_VALUE_GAMMA_87_86(n) (WDR_BASE(n) + 0x04cc) ++#define WDR_ADDR_VALUE_GAMMA_89_88(n) (WDR_BASE(n) + 0x04d0) ++#define WDR_ADDR_VALUE_GAMMA_91_90(n) (WDR_BASE(n) + 0x04d4) ++#define WDR_ADDR_VALUE_GAMMA_93_92(n) (WDR_BASE(n) + 0x04d8) ++#define WDR_ADDR_VALUE_GAMMA_95_94(n) (WDR_BASE(n) + 0x04dc) ++#define WDR_ADDR_VALUE_GAMMA_96_96(n) (WDR_BASE(n) + 0x04e0) ++#define WDR_ADDR_VALUE_ZIP_01_00(n) (WDR_BASE(n) + 0x04e4) ++#define WDR_ADDR_VALUE_ZIP_03_02(n) (WDR_BASE(n) + 0x04e8) ++#define WDR_ADDR_VALUE_ZIP_05_04(n) (WDR_BASE(n) + 0x04ec) ++#define WDR_ADDR_VALUE_ZIP_07_06(n) (WDR_BASE(n) + 0x04f0) ++#define WDR_ADDR_VALUE_ZIP_09_08(n) (WDR_BASE(n) + 0x04f4) ++#define WDR_ADDR_VALUE_ZIP_11_10(n) (WDR_BASE(n) + 0x04f8) ++#define WDR_ADDR_VALUE_ZIP_13_12(n) (WDR_BASE(n) + 0x04fc) ++#define WDR_ADDR_VALUE_ZIP_15_14(n) (WDR_BASE(n) + 0x0500) ++#define WDR_ADDR_VALUE_ZIP_17_16(n) (WDR_BASE(n) + 0x0504) ++#define WDR_ADDR_VALUE_ZIP_19_18(n) (WDR_BASE(n) + 0x0508) ++#define WDR_ADDR_VALUE_ZIP_21_20(n) (WDR_BASE(n) + 0x050c) ++#define WDR_ADDR_VALUE_ZIP_23_22(n) (WDR_BASE(n) + 0x0510) ++#define WDR_ADDR_VALUE_ZIP_25_24(n) (WDR_BASE(n) + 0x0514) ++#define WDR_ADDR_VALUE_ZIP_27_26(n) (WDR_BASE(n) + 0x0518) ++#define WDR_ADDR_VALUE_ZIP_29_28(n) (WDR_BASE(n) + 0x051c) ++#define WDR_ADDR_VALUE_ZIP_31_30(n) (WDR_BASE(n) + 0x0520) ++#define WDR_ADDR_VALUE_ZIP_33_32(n) (WDR_BASE(n) + 0x0524) ++#define WDR_ADDR_VALUE_ZIP_35_34(n) (WDR_BASE(n) + 0x0528) ++#define WDR_ADDR_VALUE_ZIP_37_36(n) (WDR_BASE(n) + 0x052c) ++#define WDR_ADDR_VALUE_ZIP_39_38(n) (WDR_BASE(n) + 0x0530) ++#define WDR_ADDR_VALUE_ZIP_41_40(n) (WDR_BASE(n) + 0x0534) ++#define WDR_ADDR_VALUE_ZIP_43_42(n) (WDR_BASE(n) + 0x0538) ++#define WDR_ADDR_VALUE_ZIP_45_44(n) (WDR_BASE(n) + 0x053c) ++#define WDR_ADDR_VALUE_ZIP_47_46(n) (WDR_BASE(n) + 0x0540) ++#define WDR_ADDR_VALUE_ZIP_49_48(n) (WDR_BASE(n) + 0x0544) ++#define WDR_ADDR_VALUE_ZIP_51_50(n) (WDR_BASE(n) + 0x0548) ++#define WDR_ADDR_VALUE_ZIP_53_52(n) (WDR_BASE(n) + 0x054c) ++#define WDR_ADDR_VALUE_ZIP_55_54(n) (WDR_BASE(n) + 0x0550) ++#define WDR_ADDR_VALUE_ZIP_57_56(n) (WDR_BASE(n) + 0x0554) ++#define WDR_ADDR_VALUE_ZIP_59_58(n) (WDR_BASE(n) + 0x0558) ++#define WDR_ADDR_VALUE_ZIP_61_60(n) (WDR_BASE(n) + 0x055c) ++#define WDR_ADDR_VALUE_ZIP_63_62(n) (WDR_BASE(n) + 0x0560) ++#define WDR_ADDR_VALUE_ZIP_65_64(n) (WDR_BASE(n) + 0x0564) ++#define WDR_ADDR_VALUE_ZIP_67_66(n) (WDR_BASE(n) + 0x0568) ++#define WDR_ADDR_VALUE_ZIP_69_68(n) (WDR_BASE(n) + 0x056c) ++#define WDR_ADDR_VALUE_ZIP_71_70(n) (WDR_BASE(n) + 0x0570) ++#define WDR_ADDR_VALUE_ZIP_73_72(n) (WDR_BASE(n) + 0x0574) ++#define WDR_ADDR_VALUE_ZIP_75_74(n) (WDR_BASE(n) + 0x0578) ++#define WDR_ADDR_VALUE_ZIP_77_76(n) (WDR_BASE(n) + 0x057c) ++#define WDR_ADDR_VALUE_ZIP_79_78(n) (WDR_BASE(n) + 0x0580) ++#define WDR_ADDR_VALUE_ZIP_81_80(n) (WDR_BASE(n) + 0x0584) ++#define WDR_ADDR_VALUE_ZIP_83_82(n) (WDR_BASE(n) + 0x0588) ++#define WDR_ADDR_VALUE_ZIP_85_84(n) (WDR_BASE(n) + 0x058c) ++#define WDR_ADDR_VALUE_ZIP_87_86(n) (WDR_BASE(n) + 0x0590) ++#define WDR_ADDR_VALUE_ZIP_89_88(n) (WDR_BASE(n) + 0x0594) ++#define WDR_ADDR_VALUE_ZIP_91_90(n) (WDR_BASE(n) + 0x0598) ++#define WDR_ADDR_VALUE_ZIP_93_92(n) (WDR_BASE(n) + 0x059c) ++#define WDR_ADDR_VALUE_ZIP_95_94(n) (WDR_BASE(n) + 0x05a0) ++#define WDR_ADDR_VALUE_ZIP_97_96(n) (WDR_BASE(n) + 0x05a4) ++#define WDR_ADDR_VALUE_ZIP_98_98(n) (WDR_BASE(n) + 0x05a8) ++#define WDR_ADDR_VALUE_FUSION_01_00(n) (WDR_BASE(n) + 0x05ac) ++#define WDR_ADDR_VALUE_FUSION_03_02(n) (WDR_BASE(n) + 0x05b0) ++#define WDR_ADDR_VALUE_FUSION_05_04(n) (WDR_BASE(n) + 0x05b4) ++#define WDR_ADDR_VALUE_FUSION_07_06(n) (WDR_BASE(n) + 0x05b8) ++#define WDR_ADDR_VALUE_FUSION_09_08(n) (WDR_BASE(n) + 0x05bc) ++#define WDR_ADDR_VALUE_FUSION_11_10(n) (WDR_BASE(n) + 0x05c0) ++#define WDR_ADDR_VALUE_FUSION_13_12(n) (WDR_BASE(n) + 0x05c4) ++#define WDR_ADDR_VALUE_FUSION_15_14(n) (WDR_BASE(n) + 0x05c8) ++#define WDR_ADDR_VALUE_FUSION_17_16(n) (WDR_BASE(n) + 0x05cc) ++#define WDR_ADDR_VALUE_FUSION_19_18(n) (WDR_BASE(n) + 0x05d0) ++#define WDR_ADDR_VALUE_FUSION_21_20(n) (WDR_BASE(n) + 0x05d4) ++#define WDR_ADDR_VALUE_FUSION_23_22(n) (WDR_BASE(n) + 0x05d8) ++#define WDR_ADDR_VALUE_FUSION_25_24(n) (WDR_BASE(n) + 0x05dc) ++#define WDR_ADDR_VALUE_FUSION_27_26(n) (WDR_BASE(n) + 0x05e0) ++#define WDR_ADDR_VALUE_FUSION_29_28(n) (WDR_BASE(n) + 0x05e4) ++#define WDR_ADDR_VALUE_FUSION_31_30(n) (WDR_BASE(n) + 0x05e8) ++#define WDR_ADDR_VALUE_FUSION_32_32(n) (WDR_BASE(n) + 0x05ec) ++#define WDR_ADDR_VALUE_W_LINE_01_00(n) (WDR_BASE(n) + 0x05f0) ++#define WDR_ADDR_VALUE_W_LINE_03_02(n) (WDR_BASE(n) + 0x05f4) ++#define WDR_ADDR_VALUE_W_LINE_04_04(n) (WDR_BASE(n) + 0x05f8) ++#define WDR_ADDR_FUSIONTHRMAX_Y(n) (WDR_BASE(n) + 0x05fc) ++#define WDR_ADDR_D_WH(n) (WDR_BASE(n) + 0x0600) ++#define WDR_ADDR_STAT_EN(n) (WDR_BASE(n) + 0x0604) ++#define WDR_ADDR_STA_INFO_ADDR0(n) (WDR_BASE(n) + 0x0610) ++#define WDR_ADDR_STA_INFO_CNT0(n) (WDR_BASE(n) + 0x0614) ++#define WDR_ADDR_STA_INFO_ADDR1(n) (WDR_BASE(n) + 0x0618) ++#define WDR_ADDR_STA_INFO_CNT1(n) (WDR_BASE(n) + 0x061c) ++#define WDR_ADDR_DBG_00_00(n) (WDR_BASE(n) + 0x0680) ++#define WDR_ADDR_DBG_01_01(n) (WDR_BASE(n) + 0x0684) ++#define WDR_ADDR_DBG_02_02(n) (WDR_BASE(n) + 0x0688) ++#define WDR_ADDR_DBG_03_03(n) (WDR_BASE(n) + 0x068c) ++#define WDR_ADDR_DBG_04_04(n) (WDR_BASE(n) + 0x0690) ++#define WDR_ADDR_DBG_05_05(n) (WDR_BASE(n) + 0x0694) ++#define WDR_ADDR_DBG_06_06(n) (WDR_BASE(n) + 0x0698) ++#define WDR_ADDR_DBG_07_07(n) (WDR_BASE(n) + 0x069c) ++ ++#define MAIN_WDR_ADDR_T_VERSION (WDR0_BASE + 0x0000) ++#define MAIN_WDR_ADDR_STA_ST_ADDR_000_00 (WDR0_BASE + 0x0010) ++#define MAIN_WDR_ADDR_STA_ST_ADDR_001_01 (WDR0_BASE + 0x0014) ++#define MAIN_WDR_ADDR_STA_ST_ADDR_002_02 (WDR0_BASE + 0x0018) ++#define MAIN_WDR_ADDR_STA_ST_ADDR_003_03 (WDR0_BASE + 0x001c) ++#define MAIN_WDR_ADDR_STA_BUF_NUM (WDR0_BASE + 0x0030) ++#define MAIN_WDR_ADDR_STA_EXT_PRIO (WDR0_BASE + 0x0034) ++#define MAIN_WDR_ADDR_DEBUG (WDR0_BASE + 0x0040) ++#define MAIN_WDR_ADDR_STA_THR (WDR0_BASE + 0x0048) ++#define MAIN_WDR_ADDR_STA_INFO_ADDR0 (WDR0_BASE + 0x0610) ++#define MAIN_WDR_ADDR_STA_INFO_CNT0 (WDR0_BASE + 0x0614) ++#define MAIN_WDR_ADDR_STA_INFO_ADDR1 (WDR0_BASE + 0x0618) ++#define MAIN_WDR_ADDR_STA_INFO_CNT1 (WDR0_BASE + 0x061c) ++#define MAIN_WDR_ADDR_DBG_00_00 (WDR0_BASE + 0x0680) ++#define MAIN_WDR_ADDR_DBG_01_01 (WDR0_BASE + 0x0684) ++#define MAIN_WDR_ADDR_DBG_02_02 (WDR0_BASE + 0x0688) ++#define MAIN_WDR_ADDR_DBG_03_03 (WDR0_BASE + 0x068c) ++#define MAIN_WDR_ADDR_DBG_04_04 (WDR0_BASE + 0x0690) ++#define MAIN_WDR_ADDR_DBG_05_05 (WDR0_BASE + 0x0694) ++#define MAIN_WDR_ADDR_DBG_06_06 (WDR0_BASE + 0x0698) ++#define MAIN_WDR_ADDR_DBG_07_07 (WDR0_BASE + 0x069c) ++ ++#define SEC_WDR_ADDR_T_VERSION (WDR1_BASE + 0x0000) ++#define SEC_WDR_ADDR_STA_ST_ADDR_000_00 (WDR1_BASE + 0x0010) ++#define SEC_WDR_ADDR_STA_ST_ADDR_001_01 (WDR1_BASE + 0x0014) ++#define SEC_WDR_ADDR_STA_ST_ADDR_002_02 (WDR1_BASE + 0x0018) ++#define SEC_WDR_ADDR_STA_ST_ADDR_003_03 (WDR1_BASE + 0x001c) ++#define SEC_WDR_ADDR_STA_BUF_NUM (WDR1_BASE + 0x0030) ++#define SEC_WDR_ADDR_STA_EXT_PRIO (WDR1_BASE + 0x0034) ++#define SEC_WDR_ADDR_DEBUG (WDR1_BASE + 0x0040) ++#define SEC_WDR_ADDR_STA_THR (WDR1_BASE + 0x0048) ++#define SEC_WDR_ADDR_DEGOSTPARA_0 (WDR1_BASE + 0x004c) ++#define SEC_WDR_ADDR_DEGOSTPARA_1 (WDR1_BASE + 0x0050) ++#define SEC_WDR_ADDR_DEGOSTPARA_2 (WDR1_BASE + 0x0054) ++#define SEC_WDR_ADDR_DEGOSTPARA_3 (WDR1_BASE + 0x0058) ++#define SEC_WDR_ADDR_DEGOSTPARA_4 (WDR1_BASE + 0x005c) ++#define SEC_WDR_ADDR_MAPR_01_00 (WDR1_BASE + 0x0060) ++#define SEC_WDR_ADDR_MAPR_03_02 (WDR1_BASE + 0x0064) ++#define SEC_WDR_ADDR_MAPR_05_04 (WDR1_BASE + 0x0068) ++#define SEC_WDR_ADDR_MAPR_07_06 (WDR1_BASE + 0x006c) ++#define SEC_WDR_ADDR_MAPR_09_08 (WDR1_BASE + 0x0070) ++#define SEC_WDR_ADDR_MAPR_11_10 (WDR1_BASE + 0x0074) ++#define SEC_WDR_ADDR_MAPR_13_12 (WDR1_BASE + 0x0078) ++#define SEC_WDR_ADDR_MAPR_15_14 (WDR1_BASE + 0x007c) ++#define SEC_WDR_ADDR_MAPR_17_16 (WDR1_BASE + 0x0080) ++#define SEC_WDR_ADDR_MAPR_19_18 (WDR1_BASE + 0x0084) ++#define SEC_WDR_ADDR_MAPR_21_20 (WDR1_BASE + 0x0088) ++#define SEC_WDR_ADDR_MAPR_23_22 (WDR1_BASE + 0x008c) ++#define SEC_WDR_ADDR_MAPR_25_24 (WDR1_BASE + 0x0090) ++#define SEC_WDR_ADDR_MAPR_27_26 (WDR1_BASE + 0x0094) ++#define SEC_WDR_ADDR_MAPR_29_28 (WDR1_BASE + 0x0098) ++#define SEC_WDR_ADDR_MAPR_31_30 (WDR1_BASE + 0x009c) ++#define SEC_WDR_ADDR_MAPR_33_32 (WDR1_BASE + 0x00a0) ++#define SEC_WDR_ADDR_MAPR_35_34 (WDR1_BASE + 0x00a4) ++#define SEC_WDR_ADDR_MAPR_37_36 (WDR1_BASE + 0x00a8) ++#define SEC_WDR_ADDR_MAPR_39_38 (WDR1_BASE + 0x00ac) ++#define SEC_WDR_ADDR_MAPR_41_40 (WDR1_BASE + 0x00b0) ++#define SEC_WDR_ADDR_MAPR_43_42 (WDR1_BASE + 0x00b4) ++#define SEC_WDR_ADDR_MAPR_45_44 (WDR1_BASE + 0x00b8) ++#define SEC_WDR_ADDR_MAPR_47_46 (WDR1_BASE + 0x00bc) ++#define SEC_WDR_ADDR_MAPR_49_48 (WDR1_BASE + 0x00c0) ++#define SEC_WDR_ADDR_MAPR_51_50 (WDR1_BASE + 0x00c4) ++#define SEC_WDR_ADDR_MAPR_53_52 (WDR1_BASE + 0x00c8) ++#define SEC_WDR_ADDR_MAPR_55_54 (WDR1_BASE + 0x00cc) ++#define SEC_WDR_ADDR_MAPR_57_56 (WDR1_BASE + 0x00d0) ++#define SEC_WDR_ADDR_MAPR_59_58 (WDR1_BASE + 0x00d4) ++#define SEC_WDR_ADDR_MAPR_61_60 (WDR1_BASE + 0x00d8) ++#define SEC_WDR_ADDR_MAPR_63_62 (WDR1_BASE + 0x00dc) ++#define SEC_WDR_ADDR_MAPR_65_64 (WDR1_BASE + 0x00e0) ++#define SEC_WDR_ADDR_MAPR_67_66 (WDR1_BASE + 0x00e4) ++#define SEC_WDR_ADDR_MAPR_69_68 (WDR1_BASE + 0x00e8) ++#define SEC_WDR_ADDR_MAPR_71_70 (WDR1_BASE + 0x00ec) ++#define SEC_WDR_ADDR_MAPR_73_72 (WDR1_BASE + 0x00f0) ++#define SEC_WDR_ADDR_MAPR_75_74 (WDR1_BASE + 0x00f4) ++#define SEC_WDR_ADDR_MAPR_77_76 (WDR1_BASE + 0x00f8) ++#define SEC_WDR_ADDR_MAPR_79_78 (WDR1_BASE + 0x00fc) ++#define SEC_WDR_ADDR_MAPR_80_80 (WDR1_BASE + 0x0100) ++#define SEC_WDR_ADDR_MAPG_01_00 (WDR1_BASE + 0x0104) ++#define SEC_WDR_ADDR_MAPG_03_02 (WDR1_BASE + 0x0108) ++#define SEC_WDR_ADDR_MAPG_05_04 (WDR1_BASE + 0x010c) ++#define SEC_WDR_ADDR_MAPG_07_06 (WDR1_BASE + 0x0110) ++#define SEC_WDR_ADDR_MAPG_09_08 (WDR1_BASE + 0x0114) ++#define SEC_WDR_ADDR_MAPG_11_10 (WDR1_BASE + 0x0118) ++#define SEC_WDR_ADDR_MAPG_13_12 (WDR1_BASE + 0x011c) ++#define SEC_WDR_ADDR_MAPG_15_14 (WDR1_BASE + 0x0120) ++#define SEC_WDR_ADDR_MAPG_17_16 (WDR1_BASE + 0x0124) ++#define SEC_WDR_ADDR_MAPG_19_18 (WDR1_BASE + 0x0128) ++#define SEC_WDR_ADDR_MAPG_21_20 (WDR1_BASE + 0x012c) ++#define SEC_WDR_ADDR_MAPG_23_22 (WDR1_BASE + 0x0130) ++#define SEC_WDR_ADDR_MAPG_25_24 (WDR1_BASE + 0x0134) ++#define SEC_WDR_ADDR_MAPG_27_26 (WDR1_BASE + 0x0138) ++#define SEC_WDR_ADDR_MAPG_29_28 (WDR1_BASE + 0x013c) ++#define SEC_WDR_ADDR_MAPG_31_30 (WDR1_BASE + 0x0140) ++#define SEC_WDR_ADDR_MAPG_33_32 (WDR1_BASE + 0x0144) ++#define SEC_WDR_ADDR_MAPG_35_34 (WDR1_BASE + 0x0148) ++#define SEC_WDR_ADDR_MAPG_37_36 (WDR1_BASE + 0x014c) ++#define SEC_WDR_ADDR_MAPG_39_38 (WDR1_BASE + 0x0150) ++#define SEC_WDR_ADDR_MAPG_41_40 (WDR1_BASE + 0x0154) ++#define SEC_WDR_ADDR_MAPG_43_42 (WDR1_BASE + 0x0158) ++#define SEC_WDR_ADDR_MAPG_45_44 (WDR1_BASE + 0x015c) ++#define SEC_WDR_ADDR_MAPG_47_46 (WDR1_BASE + 0x0160) ++#define SEC_WDR_ADDR_MAPG_49_48 (WDR1_BASE + 0x0164) ++#define SEC_WDR_ADDR_MAPG_51_50 (WDR1_BASE + 0x0168) ++#define SEC_WDR_ADDR_MAPG_53_52 (WDR1_BASE + 0x016c) ++#define SEC_WDR_ADDR_MAPG_55_54 (WDR1_BASE + 0x0170) ++#define SEC_WDR_ADDR_MAPG_57_56 (WDR1_BASE + 0x0174) ++#define SEC_WDR_ADDR_MAPG_59_58 (WDR1_BASE + 0x0178) ++#define SEC_WDR_ADDR_MAPG_61_60 (WDR1_BASE + 0x017c) ++#define SEC_WDR_ADDR_MAPG_63_62 (WDR1_BASE + 0x0180) ++#define SEC_WDR_ADDR_MAPG_65_64 (WDR1_BASE + 0x0184) ++#define SEC_WDR_ADDR_MAPG_67_66 (WDR1_BASE + 0x0188) ++#define SEC_WDR_ADDR_MAPG_69_68 (WDR1_BASE + 0x018c) ++#define SEC_WDR_ADDR_MAPG_71_70 (WDR1_BASE + 0x0190) ++#define SEC_WDR_ADDR_MAPG_73_72 (WDR1_BASE + 0x0194) ++#define SEC_WDR_ADDR_MAPG_75_74 (WDR1_BASE + 0x0198) ++#define SEC_WDR_ADDR_MAPG_77_76 (WDR1_BASE + 0x019c) ++#define SEC_WDR_ADDR_MAPG_79_78 (WDR1_BASE + 0x01a0) ++#define SEC_WDR_ADDR_MAPG_80_80 (WDR1_BASE + 0x01a4) ++#define SEC_WDR_ADDR_MAPB_01_00 (WDR1_BASE + 0x01a8) ++#define SEC_WDR_ADDR_MAPB_03_02 (WDR1_BASE + 0x01ac) ++#define SEC_WDR_ADDR_MAPB_05_04 (WDR1_BASE + 0x01b0) ++#define SEC_WDR_ADDR_MAPB_07_06 (WDR1_BASE + 0x01b4) ++#define SEC_WDR_ADDR_MAPB_09_08 (WDR1_BASE + 0x01b8) ++#define SEC_WDR_ADDR_MAPB_11_10 (WDR1_BASE + 0x01bc) ++#define SEC_WDR_ADDR_MAPB_13_12 (WDR1_BASE + 0x01c0) ++#define SEC_WDR_ADDR_MAPB_15_14 (WDR1_BASE + 0x01c4) ++#define SEC_WDR_ADDR_MAPB_17_16 (WDR1_BASE + 0x01c8) ++#define SEC_WDR_ADDR_MAPB_19_18 (WDR1_BASE + 0x01cc) ++#define SEC_WDR_ADDR_MAPB_21_20 (WDR1_BASE + 0x01d0) ++#define SEC_WDR_ADDR_MAPB_23_22 (WDR1_BASE + 0x01d4) ++#define SEC_WDR_ADDR_MAPB_25_24 (WDR1_BASE + 0x01d8) ++#define SEC_WDR_ADDR_MAPB_27_26 (WDR1_BASE + 0x01dc) ++#define SEC_WDR_ADDR_MAPB_29_28 (WDR1_BASE + 0x01e0) ++#define SEC_WDR_ADDR_MAPB_31_30 (WDR1_BASE + 0x01e4) ++#define SEC_WDR_ADDR_MAPB_33_32 (WDR1_BASE + 0x01e8) ++#define SEC_WDR_ADDR_MAPB_35_34 (WDR1_BASE + 0x01ec) ++#define SEC_WDR_ADDR_MAPB_37_36 (WDR1_BASE + 0x01f0) ++#define SEC_WDR_ADDR_MAPB_39_38 (WDR1_BASE + 0x01f4) ++#define SEC_WDR_ADDR_MAPB_41_40 (WDR1_BASE + 0x01f8) ++#define SEC_WDR_ADDR_MAPB_43_42 (WDR1_BASE + 0x01fc) ++#define SEC_WDR_ADDR_MAPB_45_44 (WDR1_BASE + 0x0200) ++#define SEC_WDR_ADDR_MAPB_47_46 (WDR1_BASE + 0x0204) ++#define SEC_WDR_ADDR_MAPB_49_48 (WDR1_BASE + 0x0208) ++#define SEC_WDR_ADDR_MAPB_51_50 (WDR1_BASE + 0x020c) ++#define SEC_WDR_ADDR_MAPB_53_52 (WDR1_BASE + 0x0210) ++#define SEC_WDR_ADDR_MAPB_55_54 (WDR1_BASE + 0x0214) ++#define SEC_WDR_ADDR_MAPB_57_56 (WDR1_BASE + 0x0218) ++#define SEC_WDR_ADDR_MAPB_59_58 (WDR1_BASE + 0x021c) ++#define SEC_WDR_ADDR_MAPB_61_60 (WDR1_BASE + 0x0220) ++#define SEC_WDR_ADDR_MAPB_63_62 (WDR1_BASE + 0x0224) ++#define SEC_WDR_ADDR_MAPB_65_64 (WDR1_BASE + 0x0228) ++#define SEC_WDR_ADDR_MAPB_67_66 (WDR1_BASE + 0x022c) ++#define SEC_WDR_ADDR_MAPB_69_68 (WDR1_BASE + 0x0230) ++#define SEC_WDR_ADDR_MAPB_71_70 (WDR1_BASE + 0x0234) ++#define SEC_WDR_ADDR_MAPB_73_72 (WDR1_BASE + 0x0238) ++#define SEC_WDR_ADDR_MAPB_75_74 (WDR1_BASE + 0x023c) ++#define SEC_WDR_ADDR_MAPB_77_76 (WDR1_BASE + 0x0240) ++#define SEC_WDR_ADDR_MAPB_79_78 (WDR1_BASE + 0x0244) ++#define SEC_WDR_ADDR_MAPB_80_80 (WDR1_BASE + 0x0248) ++#define SEC_WDR_ADDR_THRLABLE_01_00 (WDR1_BASE + 0x024c) ++#define SEC_WDR_ADDR_THRLABLE_03_02 (WDR1_BASE + 0x0250) ++#define SEC_WDR_ADDR_THRLABLE_05_04 (WDR1_BASE + 0x0254) ++#define SEC_WDR_ADDR_THRLABLE_07_06 (WDR1_BASE + 0x0258) ++#define SEC_WDR_ADDR_THRLABLE_09_08 (WDR1_BASE + 0x025c) ++#define SEC_WDR_ADDR_THRLABLE_11_10 (WDR1_BASE + 0x0260) ++#define SEC_WDR_ADDR_THRLABLE_13_12 (WDR1_BASE + 0x0264) ++#define SEC_WDR_ADDR_THRLABLE_15_14 (WDR1_BASE + 0x0268) ++#define SEC_WDR_ADDR_THRLABLE_17_16 (WDR1_BASE + 0x026c) ++#define SEC_WDR_ADDR_THRLABLE_19_18 (WDR1_BASE + 0x0270) ++#define SEC_WDR_ADDR_THRLABLE_21_20 (WDR1_BASE + 0x0274) ++#define SEC_WDR_ADDR_THRLABLE_23_22 (WDR1_BASE + 0x0278) ++#define SEC_WDR_ADDR_THRLABLE_25_24 (WDR1_BASE + 0x027c) ++#define SEC_WDR_ADDR_THRLABLE_26_26 (WDR1_BASE + 0x0280) ++#define SEC_WDR_ADDR_THRLABLEN_01_00 (WDR1_BASE + 0x0284) ++#define SEC_WDR_ADDR_THRLABLEN_03_02 (WDR1_BASE + 0x0288) ++#define SEC_WDR_ADDR_THRLABLEN_05_04 (WDR1_BASE + 0x028c) ++#define SEC_WDR_ADDR_THRLABLEN_07_06 (WDR1_BASE + 0x0290) ++#define SEC_WDR_ADDR_THRLABLEN_09_08 (WDR1_BASE + 0x0294) ++#define SEC_WDR_ADDR_THRLABLEN_11_10 (WDR1_BASE + 0x0298) ++#define SEC_WDR_ADDR_THRLABLEN_13_12 (WDR1_BASE + 0x029c) ++#define SEC_WDR_ADDR_THRLABLEN_15_14 (WDR1_BASE + 0x02a0) ++#define SEC_WDR_ADDR_THRLABLEN_17_16 (WDR1_BASE + 0x02a4) ++#define SEC_WDR_ADDR_THRLABLEN_19_18 (WDR1_BASE + 0x02a8) ++#define SEC_WDR_ADDR_THRLABLEN_21_20 (WDR1_BASE + 0x02ac) ++#define SEC_WDR_ADDR_THRLABLEN_23_22 (WDR1_BASE + 0x02b0) ++#define SEC_WDR_ADDR_THRLABLEN_25_24 (WDR1_BASE + 0x02b4) ++#define SEC_WDR_ADDR_THRALL_01_00 (WDR1_BASE + 0x02b8) ++#define SEC_WDR_ADDR_THRALL_03_02 (WDR1_BASE + 0x02bc) ++#define SEC_WDR_ADDR_THRALL_05_04 (WDR1_BASE + 0x02c0) ++#define SEC_WDR_ADDR_THRALL_07_06 (WDR1_BASE + 0x02c4) ++#define SEC_WDR_ADDR_THRALL_09_08 (WDR1_BASE + 0x02c8) ++#define SEC_WDR_ADDR_THRALL_11_10 (WDR1_BASE + 0x02cc) ++#define SEC_WDR_ADDR_THRALL_13_12 (WDR1_BASE + 0x02d0) ++#define SEC_WDR_ADDR_THRALL_15_14 (WDR1_BASE + 0x02d4) ++#define SEC_WDR_ADDR_THRALL_17_16 (WDR1_BASE + 0x02d8) ++#define SEC_WDR_ADDR_THRALL_19_18 (WDR1_BASE + 0x02dc) ++#define SEC_WDR_ADDR_THRALL_21_20 (WDR1_BASE + 0x02e0) ++#define SEC_WDR_ADDR_THRALL_23_22 (WDR1_BASE + 0x02e4) ++#define SEC_WDR_ADDR_THRALL_25_24 (WDR1_BASE + 0x02e8) ++#define SEC_WDR_ADDR_THRALL_26_26 (WDR1_BASE + 0x02ec) ++#define SEC_WDR_ADDR_THRRANGEK_00_00 (WDR1_BASE + 0x02f0) ++#define SEC_WDR_ADDR_THRRANGEK_01_01 (WDR1_BASE + 0x02f4) ++#define SEC_WDR_ADDR_THRRANGEK_02_02 (WDR1_BASE + 0x02f8) ++#define SEC_WDR_ADDR_THRRANGEK_03_03 (WDR1_BASE + 0x02fc) ++#define SEC_WDR_ADDR_THRRANGEK_04_04 (WDR1_BASE + 0x0300) ++#define SEC_WDR_ADDR_THRRANGEK_05_05 (WDR1_BASE + 0x0304) ++#define SEC_WDR_ADDR_THRRANGEK_06_06 (WDR1_BASE + 0x0308) ++#define SEC_WDR_ADDR_THRRANGEK_07_07 (WDR1_BASE + 0x030c) ++#define SEC_WDR_ADDR_THRRANGEK_08_08 (WDR1_BASE + 0x0310) ++#define SEC_WDR_ADDR_THRRANGEK_09_09 (WDR1_BASE + 0x0314) ++#define SEC_WDR_ADDR_THRRANGEK_10_10 (WDR1_BASE + 0x0318) ++#define SEC_WDR_ADDR_THRRANGEK_11_11 (WDR1_BASE + 0x031c) ++#define SEC_WDR_ADDR_THRRANGEK_12_12 (WDR1_BASE + 0x0320) ++#define SEC_WDR_ADDR_THRRANGEK_13_13 (WDR1_BASE + 0x0324) ++#define SEC_WDR_ADDR_THRRANGEK_14_14 (WDR1_BASE + 0x0328) ++#define SEC_WDR_ADDR_THRRANGEK_15_15 (WDR1_BASE + 0x032c) ++#define SEC_WDR_ADDR_THRRANGEK_16_16 (WDR1_BASE + 0x0330) ++#define SEC_WDR_ADDR_THRRANGEK_17_17 (WDR1_BASE + 0x0334) ++#define SEC_WDR_ADDR_THRRANGEK_18_18 (WDR1_BASE + 0x0338) ++#define SEC_WDR_ADDR_THRRANGEK_19_19 (WDR1_BASE + 0x033c) ++#define SEC_WDR_ADDR_THRRANGEK_20_20 (WDR1_BASE + 0x0340) ++#define SEC_WDR_ADDR_THRRANGEK_21_21 (WDR1_BASE + 0x0344) ++#define SEC_WDR_ADDR_THRRANGEK_22_22 (WDR1_BASE + 0x0348) ++#define SEC_WDR_ADDR_THRRANGEK_23_23 (WDR1_BASE + 0x034c) ++#define SEC_WDR_ADDR_THRRANGEK_24_24 (WDR1_BASE + 0x0350) ++#define SEC_WDR_ADDR_THRRANGEK_25_25 (WDR1_BASE + 0x0354) ++#define SEC_WDR_ADDR_THRRANGEK_26_26 (WDR1_BASE + 0x0358) ++#define SEC_WDR_ADDR_DARKLABLE_01_00 (WDR1_BASE + 0x035c) ++#define SEC_WDR_ADDR_DARKLABLE_03_02 (WDR1_BASE + 0x0360) ++#define SEC_WDR_ADDR_DARKLABLE_04_04 (WDR1_BASE + 0x0364) ++#define SEC_WDR_ADDR_DARKLABLEN_01_00 (WDR1_BASE + 0x0368) ++#define SEC_WDR_ADDR_DARKLABLEN_03_02 (WDR1_BASE + 0x036c) ++#define SEC_WDR_ADDR_DARKWEIGHT_01_00 (WDR1_BASE + 0x0370) ++#define SEC_WDR_ADDR_DARKWEIGHT_03_02 (WDR1_BASE + 0x0374) ++#define SEC_WDR_ADDR_DARKWEIGHT_04_04 (WDR1_BASE + 0x0378) ++#define SEC_WDR_ADDR_NOISEREDUCELABLE_00_00 (WDR1_BASE + 0x037c) ++#define SEC_WDR_ADDR_LABLE_ENRATE (WDR1_BASE + 0x0380) ++#define SEC_WDR_ADDR_VALUE_ENRATE (WDR1_BASE + 0x0384) ++#define SEC_WDR_ADDR_K_ENRATE1 (WDR1_BASE + 0x0388) ++#define SEC_WDR_ADDR_K_ENRATE2 (WDR1_BASE + 0x038c) ++#define SEC_WDR_ADDR_ENMAXMIN_V1 (WDR1_BASE + 0x0390) ++#define SEC_WDR_ADDR_RATIO_MINMAX_X (WDR1_BASE + 0x0394) ++#define SEC_WDR_ADDR_K_RATIO_MINMAX_Y (WDR1_BASE + 0x039c) ++#define SEC_WDR_ADDR_K_K_RATIO (WDR1_BASE + 0x03a0) ++#define SEC_WDR_ADDR_FUSIONTHRMINMAX_X (WDR1_BASE + 0x03a4) ++#define SEC_WDR_ADDR_K_WEIGHT (WDR1_BASE + 0x03a8) ++#define SEC_WDR_ADDR_MAXVALUE (WDR1_BASE + 0x03ac) ++#define SEC_WDR_ADDR_TMP_MAXVALUE (WDR1_BASE + 0x03b0) ++#define SEC_WDR_ADDR_THR_MAXVALUE_12BIT (WDR1_BASE + 0x03b4) ++#define SEC_WDR_ADDR_TMP_FUSION_MAX (WDR1_BASE + 0x03b8) ++#define SEC_WDR_ADDR_W_FUSION_X (WDR1_BASE + 0x03bc) ++#define SEC_WDR_ADDR_K_W_FUSION0 (WDR1_BASE + 0x03c0) ++#define SEC_WDR_ADDR_LAMDA_01 (WDR1_BASE + 0x03c4) ++#define SEC_WDR_ADDR_LAMDA_23 (WDR1_BASE + 0x03c8) ++#define SEC_WDR_ADDR_LAMDA_4 (WDR1_BASE + 0x03cc) ++#define SEC_WDR_ADDR_W_FUSION_X1 (WDR1_BASE + 0x03d0) ++#define SEC_WDR_ADDR_W_FUSION_X_N (WDR1_BASE + 0x03d4) ++#define SEC_WDR_ADDR_CONSTRACT_MAXVALUE_LOG (WDR1_BASE + 0x03d8) ++#define SEC_WDR_ADDR_TMP_MAXVALUE_LOG (WDR1_BASE + 0x03dc) ++#define SEC_WDR_ADDR_LABLE_EN_01 (WDR1_BASE + 0x03e0) ++#define SEC_WDR_ADDR_LABLE_EN_2 (WDR1_BASE + 0x03e4) ++#define SEC_WDR_ADDR_VALUE_EN1 (WDR1_BASE + 0x03e8) ++#define SEC_WDR_ADDR_LABLE_EN_Y_01 (WDR1_BASE + 0x03ec) ++#define SEC_WDR_ADDR_LABLE_EN_Y_2 (WDR1_BASE + 0x03f0) ++#define SEC_WDR_ADDR_K_EN1 (WDR1_BASE + 0x03f4) ++#define SEC_WDR_ADDR_K_EN2 (WDR1_BASE + 0x03f8) ++#define SEC_WDR_ADDR_TMP_EN1 (WDR1_BASE + 0x03fc) ++#define SEC_WDR_ADDR_TMP_EN2 (WDR1_BASE + 0x0400) ++#define SEC_WDR_ADDR_D_RATIO (WDR1_BASE + 0x0404) ++#define SEC_WDR_ADDR_LABLE_Y_SHORT (WDR1_BASE + 0x0408) ++#define SEC_WDR_ADDR_LABLE_W (WDR1_BASE + 0x040c) ++#define SEC_WDR_ADDR_THR_DENOISE (WDR1_BASE + 0x0410) ++#define SEC_WDR_ADDR_VALUE_GAMMA_01_00 (WDR1_BASE + 0x0420) ++#define SEC_WDR_ADDR_VALUE_GAMMA_03_02 (WDR1_BASE + 0x0424) ++#define SEC_WDR_ADDR_VALUE_GAMMA_05_04 (WDR1_BASE + 0x0428) ++#define SEC_WDR_ADDR_VALUE_GAMMA_07_06 (WDR1_BASE + 0x042c) ++#define SEC_WDR_ADDR_VALUE_GAMMA_09_08 (WDR1_BASE + 0x0430) ++#define SEC_WDR_ADDR_VALUE_GAMMA_11_10 (WDR1_BASE + 0x0434) ++#define SEC_WDR_ADDR_VALUE_GAMMA_13_12 (WDR1_BASE + 0x0438) ++#define SEC_WDR_ADDR_VALUE_GAMMA_15_14 (WDR1_BASE + 0x043c) ++#define SEC_WDR_ADDR_VALUE_GAMMA_17_16 (WDR1_BASE + 0x0440) ++#define SEC_WDR_ADDR_VALUE_GAMMA_19_18 (WDR1_BASE + 0x0444) ++#define SEC_WDR_ADDR_VALUE_GAMMA_21_20 (WDR1_BASE + 0x0448) ++#define SEC_WDR_ADDR_VALUE_GAMMA_23_22 (WDR1_BASE + 0x044c) ++#define SEC_WDR_ADDR_VALUE_GAMMA_25_24 (WDR1_BASE + 0x0450) ++#define SEC_WDR_ADDR_VALUE_GAMMA_27_26 (WDR1_BASE + 0x0454) ++#define SEC_WDR_ADDR_VALUE_GAMMA_29_28 (WDR1_BASE + 0x0458) ++#define SEC_WDR_ADDR_VALUE_GAMMA_31_30 (WDR1_BASE + 0x045c) ++#define SEC_WDR_ADDR_VALUE_GAMMA_33_32 (WDR1_BASE + 0x0460) ++#define SEC_WDR_ADDR_VALUE_GAMMA_35_34 (WDR1_BASE + 0x0464) ++#define SEC_WDR_ADDR_VALUE_GAMMA_37_36 (WDR1_BASE + 0x0468) ++#define SEC_WDR_ADDR_VALUE_GAMMA_39_38 (WDR1_BASE + 0x046c) ++#define SEC_WDR_ADDR_VALUE_GAMMA_41_40 (WDR1_BASE + 0x0470) ++#define SEC_WDR_ADDR_VALUE_GAMMA_43_42 (WDR1_BASE + 0x0474) ++#define SEC_WDR_ADDR_VALUE_GAMMA_45_44 (WDR1_BASE + 0x0478) ++#define SEC_WDR_ADDR_VALUE_GAMMA_47_46 (WDR1_BASE + 0x047c) ++#define SEC_WDR_ADDR_VALUE_GAMMA_49_48 (WDR1_BASE + 0x0480) ++#define SEC_WDR_ADDR_VALUE_GAMMA_51_50 (WDR1_BASE + 0x0484) ++#define SEC_WDR_ADDR_VALUE_GAMMA_53_52 (WDR1_BASE + 0x0488) ++#define SEC_WDR_ADDR_VALUE_GAMMA_55_54 (WDR1_BASE + 0x048c) ++#define SEC_WDR_ADDR_VALUE_GAMMA_57_56 (WDR1_BASE + 0x0490) ++#define SEC_WDR_ADDR_VALUE_GAMMA_59_58 (WDR1_BASE + 0x0494) ++#define SEC_WDR_ADDR_VALUE_GAMMA_61_60 (WDR1_BASE + 0x0498) ++#define SEC_WDR_ADDR_VALUE_GAMMA_63_62 (WDR1_BASE + 0x049c) ++#define SEC_WDR_ADDR_VALUE_GAMMA_65_64 (WDR1_BASE + 0x04a0) ++#define SEC_WDR_ADDR_VALUE_GAMMA_67_66 (WDR1_BASE + 0x04a4) ++#define SEC_WDR_ADDR_VALUE_GAMMA_69_68 (WDR1_BASE + 0x04a8) ++#define SEC_WDR_ADDR_VALUE_GAMMA_71_70 (WDR1_BASE + 0x04ac) ++#define SEC_WDR_ADDR_VALUE_GAMMA_73_72 (WDR1_BASE + 0x04b0) ++#define SEC_WDR_ADDR_VALUE_GAMMA_75_74 (WDR1_BASE + 0x04b4) ++#define SEC_WDR_ADDR_VALUE_GAMMA_77_76 (WDR1_BASE + 0x04b8) ++#define SEC_WDR_ADDR_VALUE_GAMMA_79_78 (WDR1_BASE + 0x04bc) ++#define SEC_WDR_ADDR_VALUE_GAMMA_81_80 (WDR1_BASE + 0x04c0) ++#define SEC_WDR_ADDR_VALUE_GAMMA_83_82 (WDR1_BASE + 0x04c4) ++#define SEC_WDR_ADDR_VALUE_GAMMA_85_84 (WDR1_BASE + 0x04c8) ++#define SEC_WDR_ADDR_VALUE_GAMMA_87_86 (WDR1_BASE + 0x04cc) ++#define SEC_WDR_ADDR_VALUE_GAMMA_89_88 (WDR1_BASE + 0x04d0) ++#define SEC_WDR_ADDR_VALUE_GAMMA_91_90 (WDR1_BASE + 0x04d4) ++#define SEC_WDR_ADDR_VALUE_GAMMA_93_92 (WDR1_BASE + 0x04d8) ++#define SEC_WDR_ADDR_VALUE_GAMMA_95_94 (WDR1_BASE + 0x04dc) ++#define SEC_WDR_ADDR_VALUE_GAMMA_96_96 (WDR1_BASE + 0x04e0) ++#define SEC_WDR_ADDR_VALUE_ZIP_01_00 (WDR1_BASE + 0x04e4) ++#define SEC_WDR_ADDR_VALUE_ZIP_03_02 (WDR1_BASE + 0x04e8) ++#define SEC_WDR_ADDR_VALUE_ZIP_05_04 (WDR1_BASE + 0x04ec) ++#define SEC_WDR_ADDR_VALUE_ZIP_07_06 (WDR1_BASE + 0x04f0) ++#define SEC_WDR_ADDR_VALUE_ZIP_09_08 (WDR1_BASE + 0x04f4) ++#define SEC_WDR_ADDR_VALUE_ZIP_11_10 (WDR1_BASE + 0x04f8) ++#define SEC_WDR_ADDR_VALUE_ZIP_13_12 (WDR1_BASE + 0x04fc) ++#define SEC_WDR_ADDR_VALUE_ZIP_15_14 (WDR1_BASE + 0x0500) ++#define SEC_WDR_ADDR_VALUE_ZIP_17_16 (WDR1_BASE + 0x0504) ++#define SEC_WDR_ADDR_VALUE_ZIP_19_18 (WDR1_BASE + 0x0508) ++#define SEC_WDR_ADDR_VALUE_ZIP_21_20 (WDR1_BASE + 0x050c) ++#define SEC_WDR_ADDR_VALUE_ZIP_23_22 (WDR1_BASE + 0x0510) ++#define SEC_WDR_ADDR_VALUE_ZIP_25_24 (WDR1_BASE + 0x0514) ++#define SEC_WDR_ADDR_VALUE_ZIP_27_26 (WDR1_BASE + 0x0518) ++#define SEC_WDR_ADDR_VALUE_ZIP_29_28 (WDR1_BASE + 0x051c) ++#define SEC_WDR_ADDR_VALUE_ZIP_31_30 (WDR1_BASE + 0x0520) ++#define SEC_WDR_ADDR_VALUE_ZIP_33_32 (WDR1_BASE + 0x0524) ++#define SEC_WDR_ADDR_VALUE_ZIP_35_34 (WDR1_BASE + 0x0528) ++#define SEC_WDR_ADDR_VALUE_ZIP_37_36 (WDR1_BASE + 0x052c) ++#define SEC_WDR_ADDR_VALUE_ZIP_39_38 (WDR1_BASE + 0x0530) ++#define SEC_WDR_ADDR_VALUE_ZIP_41_40 (WDR1_BASE + 0x0534) ++#define SEC_WDR_ADDR_VALUE_ZIP_43_42 (WDR1_BASE + 0x0538) ++#define SEC_WDR_ADDR_VALUE_ZIP_45_44 (WDR1_BASE + 0x053c) ++#define SEC_WDR_ADDR_VALUE_ZIP_47_46 (WDR1_BASE + 0x0540) ++#define SEC_WDR_ADDR_VALUE_ZIP_49_48 (WDR1_BASE + 0x0544) ++#define SEC_WDR_ADDR_VALUE_ZIP_51_50 (WDR1_BASE + 0x0548) ++#define SEC_WDR_ADDR_VALUE_ZIP_53_52 (WDR1_BASE + 0x054c) ++#define SEC_WDR_ADDR_VALUE_ZIP_55_54 (WDR1_BASE + 0x0550) ++#define SEC_WDR_ADDR_VALUE_ZIP_57_56 (WDR1_BASE + 0x0554) ++#define SEC_WDR_ADDR_VALUE_ZIP_59_58 (WDR1_BASE + 0x0558) ++#define SEC_WDR_ADDR_VALUE_ZIP_61_60 (WDR1_BASE + 0x055c) ++#define SEC_WDR_ADDR_VALUE_ZIP_63_62 (WDR1_BASE + 0x0560) ++#define SEC_WDR_ADDR_VALUE_ZIP_65_64 (WDR1_BASE + 0x0564) ++#define SEC_WDR_ADDR_VALUE_ZIP_67_66 (WDR1_BASE + 0x0568) ++#define SEC_WDR_ADDR_VALUE_ZIP_69_68 (WDR1_BASE + 0x056c) ++#define SEC_WDR_ADDR_VALUE_ZIP_71_70 (WDR1_BASE + 0x0570) ++#define SEC_WDR_ADDR_VALUE_ZIP_73_72 (WDR1_BASE + 0x0574) ++#define SEC_WDR_ADDR_VALUE_ZIP_75_74 (WDR1_BASE + 0x0578) ++#define SEC_WDR_ADDR_VALUE_ZIP_77_76 (WDR1_BASE + 0x057c) ++#define SEC_WDR_ADDR_VALUE_ZIP_79_78 (WDR1_BASE + 0x0580) ++#define SEC_WDR_ADDR_VALUE_ZIP_81_80 (WDR1_BASE + 0x0584) ++#define SEC_WDR_ADDR_VALUE_ZIP_83_82 (WDR1_BASE + 0x0588) ++#define SEC_WDR_ADDR_VALUE_ZIP_85_84 (WDR1_BASE + 0x058c) ++#define SEC_WDR_ADDR_VALUE_ZIP_87_86 (WDR1_BASE + 0x0590) ++#define SEC_WDR_ADDR_VALUE_ZIP_89_88 (WDR1_BASE + 0x0594) ++#define SEC_WDR_ADDR_VALUE_ZIP_91_90 (WDR1_BASE + 0x0598) ++#define SEC_WDR_ADDR_VALUE_ZIP_93_92 (WDR1_BASE + 0x059c) ++#define SEC_WDR_ADDR_VALUE_ZIP_95_94 (WDR1_BASE + 0x05a0) ++#define SEC_WDR_ADDR_VALUE_ZIP_97_96 (WDR1_BASE + 0x05a4) ++#define SEC_WDR_ADDR_VALUE_ZIP_98_98 (WDR1_BASE + 0x05a8) ++#define SEC_WDR_ADDR_VALUE_FUSION_01_00 (WDR1_BASE + 0x05ac) ++#define SEC_WDR_ADDR_VALUE_FUSION_03_02 (WDR1_BASE + 0x05b0) ++#define SEC_WDR_ADDR_VALUE_FUSION_05_04 (WDR1_BASE + 0x05b4) ++#define SEC_WDR_ADDR_VALUE_FUSION_07_06 (WDR1_BASE + 0x05b8) ++#define SEC_WDR_ADDR_VALUE_FUSION_09_08 (WDR1_BASE + 0x05bc) ++#define SEC_WDR_ADDR_VALUE_FUSION_11_10 (WDR1_BASE + 0x05c0) ++#define SEC_WDR_ADDR_VALUE_FUSION_13_12 (WDR1_BASE + 0x05c4) ++#define SEC_WDR_ADDR_VALUE_FUSION_15_14 (WDR1_BASE + 0x05c8) ++#define SEC_WDR_ADDR_VALUE_FUSION_17_16 (WDR1_BASE + 0x05cc) ++#define SEC_WDR_ADDR_VALUE_FUSION_19_18 (WDR1_BASE + 0x05d0) ++#define SEC_WDR_ADDR_VALUE_FUSION_21_20 (WDR1_BASE + 0x05d4) ++#define SEC_WDR_ADDR_VALUE_FUSION_23_22 (WDR1_BASE + 0x05d8) ++#define SEC_WDR_ADDR_VALUE_FUSION_25_24 (WDR1_BASE + 0x05dc) ++#define SEC_WDR_ADDR_VALUE_FUSION_27_26 (WDR1_BASE + 0x05e0) ++#define SEC_WDR_ADDR_VALUE_FUSION_29_28 (WDR1_BASE + 0x05e4) ++#define SEC_WDR_ADDR_VALUE_FUSION_31_30 (WDR1_BASE + 0x05e8) ++#define SEC_WDR_ADDR_VALUE_FUSION_32_32 (WDR1_BASE + 0x05ec) ++#define SEC_WDR_ADDR_VALUE_W_LINE_01_00 (WDR1_BASE + 0x05f0) ++#define SEC_WDR_ADDR_VALUE_W_LINE_03_02 (WDR1_BASE + 0x05f4) ++#define SEC_WDR_ADDR_VALUE_W_LINE_04_04 (WDR1_BASE + 0x05f8) ++#define SEC_WDR_ADDR_FUSIONTHRMAX_Y (WDR1_BASE + 0x05fc) ++#define SEC_WDR_ADDR_D_WH (WDR1_BASE + 0x0600) ++#define SEC_WDR_ADDR_STAT_EN (WDR1_BASE + 0x0604) ++#define SEC_WDR_ADDR_STA_INFO_ADDR0 (WDR1_BASE + 0x0610) ++#define SEC_WDR_ADDR_STA_INFO_CNT0 (WDR1_BASE + 0x0614) ++#define SEC_WDR_ADDR_STA_INFO_ADDR1 (WDR1_BASE + 0x0618) ++#define SEC_WDR_ADDR_STA_INFO_CNT1 (WDR1_BASE + 0x061c) ++#define SEC_WDR_ADDR_DBG_00_00 (WDR1_BASE + 0x0680) ++#define SEC_WDR_ADDR_DBG_01_01 (WDR1_BASE + 0x0684) ++#define SEC_WDR_ADDR_DBG_02_02 (WDR1_BASE + 0x0688) ++#define SEC_WDR_ADDR_DBG_03_03 (WDR1_BASE + 0x068c) ++#define SEC_WDR_ADDR_DBG_04_04 (WDR1_BASE + 0x0690) ++#define SEC_WDR_ADDR_DBG_05_05 (WDR1_BASE + 0x0694) ++#define SEC_WDR_ADDR_DBG_06_06 (WDR1_BASE + 0x0698) ++#define SEC_WDR_ADDR_DBG_07_07 (WDR1_BASE + 0x069c) ++ ++//============================================================ ++// DPC ADDRESS ++//============================================================ ++#define DPC_ADDR_S_CON(n) (DPC_BASE(n) + 0x0000) ++#define DPC_ADDR_ALPHA(n) (DPC_BASE(n) + 0x0004) ++#define DPC_ADDR_LV_EN(n) (DPC_BASE(n) + 0x0008) ++#define DPC_ADDR_LV2_POS_EN(n) (DPC_BASE(n) + 0x000c) ++#define DPC_ADDR_SC_WEI(n) (DPC_BASE(n) + 0x0010) ++#define DPC_ADDR_SLOPE_1(n) (DPC_BASE(n) + 0x0014) ++#define DPC_ADDR_SLOPE_2(n) (DPC_BASE(n) + 0x0018) ++#define DPC_ADDR_LV1_THRES_RB(n) (DPC_BASE(n) + 0x001c) ++#define DPC_ADDR_LV2_DIFF_THRES_RB(n) (DPC_BASE(n) + 0x0020) ++#define DPC_ADDR_LV2_POS_THRES_RB_1(n) (DPC_BASE(n) + 0x0024) ++#define DPC_ADDR_LV2_POS_THRES_RB_2(n) (DPC_BASE(n) + 0x0028) ++#define DPC_ADDR_LV2_POS_DIST_THRES_RB_1(n) (DPC_BASE(n) + 0x002c) ++#define DPC_ADDR_LV2_POS_DIST_THRES_RB_2(n) (DPC_BASE(n) + 0x0030) ++#define DPC_ADDR_LV3_THRES_RB(n) (DPC_BASE(n) + 0x0034) ++#define DPC_ADDR_LV1_THRES_G(n) (DPC_BASE(n) + 0x0038) ++#define DPC_ADDR_LV2_DIFF_THRES_G(n) (DPC_BASE(n) + 0x003c) ++#define DPC_ADDR_LV2_POS_THRES_G_1(n) (DPC_BASE(n) + 0x0040) ++#define DPC_ADDR_LV2_POS_THRES_G_2(n) (DPC_BASE(n) + 0x0044) ++#define DPC_ADDR_LV2_POS_DIST_THRES_G_1(n) (DPC_BASE(n) + 0x0048) ++#define DPC_ADDR_LV2_POS_DIST_THRES_G_2(n) (DPC_BASE(n) + 0x004c) ++#define DPC_ADDR_LV3_THRES_G(n) (DPC_BASE(n) + 0x0050) ++#define DPC_ADDR_CTR_CON(n) (DPC_BASE(n) + 0x0054) ++#define DPC_ADDR_CTR_MD_CON(n) (DPC_BASE(n) + 0x0058) ++#define DPC_ADDR_CTR_STD_CON(n) (DPC_BASE(n) + 0x005c) ++#define DPC_ADDR_CTR_BASE_THRES(n) (DPC_BASE(n) + 0x0060) ++#define DPC_ADDR_CTR_MD_NP_1(n) (DPC_BASE(n) + 0x0064) ++#define DPC_ADDR_CTR_MD_NP_2(n) (DPC_BASE(n) + 0x0068) ++#define DPC_ADDR_CTR_MD_NP_3(n) (DPC_BASE(n) + 0x006c) ++#define DPC_ADDR_CTR_MD_NP_4(n) (DPC_BASE(n) + 0x0070) ++#define DPC_ADDR_CTR_STD_NP_1(n) (DPC_BASE(n) + 0x0074) ++#define DPC_ADDR_CTR_STD_NP_2(n) (DPC_BASE(n) + 0x0078) ++#define DPC_ADDR_CTR_STD_NP_3(n) (DPC_BASE(n) + 0x007c) ++#define DPC_ADDR_CTR_STD_NP_4(n) (DPC_BASE(n) + 0x0080) ++#define DPC_ADDR_STILL_STD_THRES(n) (DPC_BASE(n) + 0x0084) ++#define DPC_ADDR_DBG_0(n) (DPC_BASE(n) + 0x0088) ++#define DPC_ADDR_DBG_1(n) (DPC_BASE(n) + 0x008c) ++#define DPC_ADDR_DBG_2(n) (DPC_BASE(n) + 0x0090) ++#define DPC_ADDR_DBG_3(n) (DPC_BASE(n) + 0x0094) ++#define DPC_ADDR_DBG_4(n) (DPC_BASE(n) + 0x0098) ++#define DPC_ADDR_SHD_CTRL(n) (DPC_BASE(n) + 0x009c) ++#define DPC_ADDR_DNS_STD_THRES(n) (DPC_BASE(n) + 0x00a0) ++ ++//============================================================ ++// GIB ADDRESS ++//============================================================ ++#define GIB_ADDR_GIB_GAIN_0(n) (GIB_BASE(n) + 0x0000) ++#define GIB_ADDR_GIB_GAIN_1(n) (GIB_BASE(n) + 0x0004) ++#define GIB_ADDR_GIB_OVEXP_THRES(n) (GIB_BASE(n) + 0x0008) ++#define GIB_ADDR_GIB_EN(n) (GIB_BASE(n) + 0x000c) ++#define GIB_ADDR_GIB_DEIRM_R_0(n) (GIB_BASE(n) + 0x0010) ++#define GIB_ADDR_GIB_DEIRM_R_1(n) (GIB_BASE(n) + 0x0014) ++#define GIB_ADDR_GIB_DEIRM_G_0(n) (GIB_BASE(n) + 0x0018) ++#define GIB_ADDR_GIB_DEIRM_G_1(n) (GIB_BASE(n) + 0x001c) ++#define GIB_ADDR_GIB_DEIRM_B_0(n) (GIB_BASE(n) + 0x0020) ++#define GIB_ADDR_GIB_DEIRM_B_1(n) (GIB_BASE(n) + 0x0024) ++#define GIB_ADDR_GIB_DEIRM_C_0(n) (GIB_BASE(n) + 0x0028) ++#define GIB_ADDR_GIB_DEIRM_C_1(n) (GIB_BASE(n) + 0x002c) ++#define GIB_ADDR_GIB_BLC_CH(n) (GIB_BASE(n) + 0x0030) ++#define GIB_ADDR_GIB_BLC_CH_0(n) (GIB_BASE(n) + 0x0034) ++#define GIB_ADDR_GIB_BLC_CH_1(n) (GIB_BASE(n) + 0x0038) ++#define GIB_ADDR_GIB_BLC_CH_2(n) (GIB_BASE(n) + 0x003c) ++#define GIB_ADDR_SHD_CTRL(n) (GIB_BASE(n) + 0x0040) ++#define GIB_ADDR_DEBUG0(n) (GIB_BASE(n) + 0x0044) ++#define GIB_ADDR_DEBUG1(n) (GIB_BASE(n) + 0x0048) ++#define GIB_ADDR_DEBUG2(n) (GIB_BASE(n) + 0x004c) ++#define GIB_ADDR_DEBUG3(n) (GIB_BASE(n) + 0x0050) ++#define GIB_ADDR_DEBUG4(n) (GIB_BASE(n) + 0x0054) ++#define GIB_ADDR_DEBUG5(n) (GIB_BASE(n) + 0x0058) ++ ++//============================================================ ++// AWBG1 ADDRESS ++//============================================================ ++#define MAIN_AWBG1_ADDR_SHD_CTRL (AWBG10_BASE + 0x0000) ++#define MAIN_AWBG1_ADDR_R_G_GAIN_L (AWBG10_BASE + 0x0004) ++#define MAIN_AWBG1_ADDR_B_IR_GAIN_L (AWBG10_BASE + 0x0008) ++#define MAIN_AWBG1_ADDR_R_G_GAIN_S (AWBG10_BASE + 0x000c) ++#define MAIN_AWBG1_ADDR_B_IR_GAIN_S (AWBG10_BASE + 0x0010) ++#define MAIN_AWBG1_ADDR_DEBUG1 (AWBG10_BASE + 0x0014) ++#define MAIN_AWBG1_ADDR_DEBUG2 (AWBG10_BASE + 0x0018) ++ ++#define SEC_AWBG1_ADDR_SHD_CTRL (AWBG11_BASE + 0x0000) ++#define SEC_AWBG1_ADDR_R_G_GAIN_L (AWBG11_BASE + 0x0004) ++#define SEC_AWBG1_ADDR_B_IR_GAIN_L (AWBG11_BASE + 0x0008) ++#define SEC_AWBG1_ADDR_R_G_GAIN_S (AWBG11_BASE + 0x000c) ++#define SEC_AWBG1_ADDR_B_IR_GAIN_S (AWBG11_BASE + 0x0010) ++#define SEC_AWBG1_ADDR_DEBUG1 (AWBG11_BASE + 0x0014) ++#define SEC_AWBG1_ADDR_DEBUG2 (AWBG11_BASE + 0x0018) ++ ++//============================================================ ++// ADR ADDRESS ++//============================================================ ++#define MAIN_ADR_ADDR_MODE (ADR0_BASE + 0x0000) ++#define MAIN_ADR_ADDR_EXT_PRIO (ADR0_BASE + 0x0004) ++ ++#define ADR_ADDR_MODULES_EN(n) (ADR_BASE(n) + 0x0008) ++#define ADR_ADDR_ADR_COC_IN_TH(n) (ADR_BASE(n) + 0x0010) ++#define ADR_ADDR_ADR_COC_GAM_DIV(n) (ADR_BASE(n) + 0x0014) ++#define ADR_ADDR_COC_W_DEFAULT(n) (ADR_BASE(n) + 0x0018) ++#define ADR_ADDR_IR_LIMIT(n) (ADR_BASE(n) + 0x001c) ++#define ADR_ADDR_LEAST_BWC_MODE_EN(n) (ADR_BASE(n) + 0x0020) ++#define ADR_ADDR_BWC_TH(n) (ADR_BASE(n) + 0x0024) ++#define ADR_ADDR_ADR_COC_W_EN(n) (ADR_BASE(n) + 0x0028) ++#define ADR_ADDR_ADR_BLOCK_COORD_M_01_00(n) (ADR_BASE(n) + 0x0030) ++#define ADR_ADDR_ADR_BLOCK_COORD_M_03_02(n) (ADR_BASE(n) + 0x0034) ++#define ADR_ADDR_ADR_BLOCK_COORD_M_04_04(n) (ADR_BASE(n) + 0x0038) ++#define ADR_ADDR_ADR_BLOCK_COORD_N_01_00(n) (ADR_BASE(n) + 0x003c) ++#define ADR_ADDR_ADR_BLOCK_COORD_N_03_02(n) (ADR_BASE(n) + 0x0040) ++#define ADR_ADDR_ADR_BLOCK_COORD_N_05_04(n) (ADR_BASE(n) + 0x0044) ++#define ADR_ADDR_ADR_BLOCK_COORD_N_06_06(n) (ADR_BASE(n) + 0x0048) ++#define ADR_ADDR_ADR_WEIGHTLUT20__03_00(n) (ADR_BASE(n) + 0x004c) ++#define ADR_ADDR_ADR_WEIGHTLUT20__07_04(n) (ADR_BASE(n) + 0x0050) ++#define ADR_ADDR_ADR_WEIGHTLUT20__11_08(n) (ADR_BASE(n) + 0x0054) ++#define ADR_ADDR_ADR_WEIGHTLUT20__15_12(n) (ADR_BASE(n) + 0x0058) ++#define ADR_ADDR_ADR_WEIGHTLUT20__19_16(n) (ADR_BASE(n) + 0x005c) ++#define ADR_ADDR_ADR_WEIGHTLUT20__23_20(n) (ADR_BASE(n) + 0x0060) ++#define ADR_ADDR_ADR_WEIGHTLUT20__27_24(n) (ADR_BASE(n) + 0x0064) ++#define ADR_ADDR_ADR_WEIGHTLUT20__31_28(n) (ADR_BASE(n) + 0x0068) ++#define ADR_ADDR_ADR_WEIGHTLUT02__03_00(n) (ADR_BASE(n) + 0x006c) ++#define ADR_ADDR_ADR_WEIGHTLUT02__07_04(n) (ADR_BASE(n) + 0x0070) ++#define ADR_ADDR_ADR_WEIGHTLUT02__11_08(n) (ADR_BASE(n) + 0x0074) ++#define ADR_ADDR_ADR_WEIGHTLUT02__15_12(n) (ADR_BASE(n) + 0x0078) ++#define ADR_ADDR_ADR_WEIGHTLUT02__19_16(n) (ADR_BASE(n) + 0x007c) ++#define ADR_ADDR_ADR_WEIGHTLUT02__23_20(n) (ADR_BASE(n) + 0x0080) ++#define ADR_ADDR_ADR_WEIGHTLUT02__27_24(n) (ADR_BASE(n) + 0x0084) ++#define ADR_ADDR_ADR_WEIGHTLUT02__31_28(n) (ADR_BASE(n) + 0x0088) ++#define ADR_ADDR_ADR_WEIGHTLUT12__03_00(n) (ADR_BASE(n) + 0x008c) ++#define ADR_ADDR_ADR_WEIGHTLUT12__07_04(n) (ADR_BASE(n) + 0x0090) ++#define ADR_ADDR_ADR_WEIGHTLUT12__11_08(n) (ADR_BASE(n) + 0x0094) ++#define ADR_ADDR_ADR_WEIGHTLUT12__15_12(n) (ADR_BASE(n) + 0x0098) ++#define ADR_ADDR_ADR_WEIGHTLUT12__19_16(n) (ADR_BASE(n) + 0x009c) ++#define ADR_ADDR_ADR_WEIGHTLUT12__23_20(n) (ADR_BASE(n) + 0x00a0) ++#define ADR_ADDR_ADR_WEIGHTLUT12__27_24(n) (ADR_BASE(n) + 0x00a4) ++#define ADR_ADDR_ADR_WEIGHTLUT12__31_28(n) (ADR_BASE(n) + 0x00a8) ++#define ADR_ADDR_ADR_WEIGHTLUT22__03_00(n) (ADR_BASE(n) + 0x00ac) ++#define ADR_ADDR_ADR_WEIGHTLUT22__07_04(n) (ADR_BASE(n) + 0x00b0) ++#define ADR_ADDR_ADR_WEIGHTLUT22__11_08(n) (ADR_BASE(n) + 0x00b4) ++#define ADR_ADDR_ADR_WEIGHTLUT22__15_12(n) (ADR_BASE(n) + 0x00b8) ++#define ADR_ADDR_ADR_WEIGHTLUT22__19_16(n) (ADR_BASE(n) + 0x00bc) ++#define ADR_ADDR_ADR_WEIGHTLUT22__23_20(n) (ADR_BASE(n) + 0x00c0) ++#define ADR_ADDR_ADR_WEIGHTLUT22__27_24(n) (ADR_BASE(n) + 0x00c4) ++#define ADR_ADDR_ADR_WEIGHTLUT22__31_28(n) (ADR_BASE(n) + 0x00c8) ++#define ADR_ADDR_ADR_WEIGHTLUT21__03_00(n) (ADR_BASE(n) + 0x00cc) ++#define ADR_ADDR_ADR_WEIGHTLUT21__07_04(n) (ADR_BASE(n) + 0x00d0) ++#define ADR_ADDR_ADR_WEIGHTLUT21__11_08(n) (ADR_BASE(n) + 0x00d4) ++#define ADR_ADDR_ADR_WEIGHTLUT21__15_12(n) (ADR_BASE(n) + 0x00d8) ++#define ADR_ADDR_ADR_WEIGHTLUT21__19_16(n) (ADR_BASE(n) + 0x00dc) ++#define ADR_ADDR_ADR_WEIGHTLUT21__23_20(n) (ADR_BASE(n) + 0x00e0) ++#define ADR_ADDR_ADR_WEIGHTLUT21__27_24(n) (ADR_BASE(n) + 0x00e4) ++#define ADR_ADDR_ADR_WEIGHTLUT21__31_28(n) (ADR_BASE(n) + 0x00e8) ++#define ADR_ADDR_CTC_KNEEPOINT_Y__01_00(n) (ADR_BASE(n) + 0x00ec) ++#define ADR_ADDR_CTC_KNEEPOINT_Y__03_02(n) (ADR_BASE(n) + 0x00f0) ++#define ADR_ADDR_CTC_KNEEPOINT_Y__05_04(n) (ADR_BASE(n) + 0x00f4) ++#define ADR_ADDR_CTC_KNEEPOINT_Y__07_06(n) (ADR_BASE(n) + 0x00f8) ++#define ADR_ADDR_CTC_KNEEPOINT_Y__09_08(n) (ADR_BASE(n) + 0x00fc) ++#define ADR_ADDR_CTC_KNEEPOINT_Y__11_10(n) (ADR_BASE(n) + 0x0100) ++#define ADR_ADDR_CTC_KNEEPOINT_Y__13_12(n) (ADR_BASE(n) + 0x0104) ++#define ADR_ADDR_CTC_KNEEPOINT_Y__15_14(n) (ADR_BASE(n) + 0x0108) ++#define ADR_ADDR_ADR_CTC1_Y__01_00(n) (ADR_BASE(n) + 0x010c) ++#define ADR_ADDR_ADR_CTC1_Y__03_02(n) (ADR_BASE(n) + 0x0110) ++#define ADR_ADDR_ADR_CTC1_Y__05_04(n) (ADR_BASE(n) + 0x0114) ++#define ADR_ADDR_ADR_CTC1_Y__07_06(n) (ADR_BASE(n) + 0x0118) ++#define ADR_ADDR_ADR_CTC1_Y__09_08(n) (ADR_BASE(n) + 0x011c) ++#define ADR_ADDR_ADR_CTC1_Y__11_10(n) (ADR_BASE(n) + 0x0120) ++#define ADR_ADDR_ADR_CTC1_Y__13_12(n) (ADR_BASE(n) + 0x0124) ++#define ADR_ADDR_ADR_CTC1_Y__15_14(n) (ADR_BASE(n) + 0x0128) ++#define ADR_ADDR_ADR_CTC1_Y__17_16(n) (ADR_BASE(n) + 0x012c) ++#define ADR_ADDR_ADR_CTC1_Y__19_18(n) (ADR_BASE(n) + 0x0130) ++#define ADR_ADDR_ADR_CTC1_Y__20_20(n) (ADR_BASE(n) + 0x0134) ++#define ADR_ADDR_MIN_KNEEPOINT_Y__01_00(n) (ADR_BASE(n) + 0x0138) ++#define ADR_ADDR_MIN_KNEEPOINT_Y__03_02(n) (ADR_BASE(n) + 0x013c) ++#define ADR_ADDR_MIN_KNEEPOINT_Y__05_04(n) (ADR_BASE(n) + 0x0140) ++#define ADR_ADDR_MIN_KNEEPOINT_Y__07_06(n) (ADR_BASE(n) + 0x0144) ++#define ADR_ADDR_MIN_KNEEPOINT_Y__09_08(n) (ADR_BASE(n) + 0x0148) ++#define ADR_ADDR_MIN_KNEEPOINT_Y__11_10(n) (ADR_BASE(n) + 0x014c) ++#define ADR_ADDR_MIN_KNEEPOINT_Y__13_12(n) (ADR_BASE(n) + 0x0150) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_00__01_00(n) (ADR_BASE(n) + 0x0154) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_00__03_02(n) (ADR_BASE(n) + 0x0158) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_00__05_04(n) (ADR_BASE(n) + 0x015c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_00__07_06(n) (ADR_BASE(n) + 0x0160) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_00__09_08(n) (ADR_BASE(n) + 0x0164) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_00__11_10(n) (ADR_BASE(n) + 0x0168) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_00__13_12(n) (ADR_BASE(n) + 0x016c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_01__01_00(n) (ADR_BASE(n) + 0x0170) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_01__03_02(n) (ADR_BASE(n) + 0x0174) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_01__05_04(n) (ADR_BASE(n) + 0x0178) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_01__07_06(n) (ADR_BASE(n) + 0x017c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_01__09_08(n) (ADR_BASE(n) + 0x0180) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_01__11_10(n) (ADR_BASE(n) + 0x0184) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_01__13_12(n) (ADR_BASE(n) + 0x0188) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_02__01_00(n) (ADR_BASE(n) + 0x018c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_02__03_02(n) (ADR_BASE(n) + 0x0190) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_02__05_04(n) (ADR_BASE(n) + 0x0194) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_02__07_06(n) (ADR_BASE(n) + 0x0198) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_02__09_08(n) (ADR_BASE(n) + 0x019c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_02__11_10(n) (ADR_BASE(n) + 0x01a0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_02__13_12(n) (ADR_BASE(n) + 0x01a4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_03__01_00(n) (ADR_BASE(n) + 0x01a8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_03__03_02(n) (ADR_BASE(n) + 0x01ac) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_03__05_04(n) (ADR_BASE(n) + 0x01b0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_03__07_06(n) (ADR_BASE(n) + 0x01b4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_03__09_08(n) (ADR_BASE(n) + 0x01b8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_03__11_10(n) (ADR_BASE(n) + 0x01bc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_03__13_12(n) (ADR_BASE(n) + 0x01c0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_04__01_00(n) (ADR_BASE(n) + 0x01c4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_04__03_02(n) (ADR_BASE(n) + 0x01c8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_04__05_04(n) (ADR_BASE(n) + 0x01cc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_04__07_06(n) (ADR_BASE(n) + 0x01d0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_04__09_08(n) (ADR_BASE(n) + 0x01d4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_04__11_10(n) (ADR_BASE(n) + 0x01d8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_04__13_12(n) (ADR_BASE(n) + 0x01dc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_05__01_00(n) (ADR_BASE(n) + 0x01e0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_05__03_02(n) (ADR_BASE(n) + 0x01e4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_05__05_04(n) (ADR_BASE(n) + 0x01e8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_05__07_06(n) (ADR_BASE(n) + 0x01ec) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_05__09_08(n) (ADR_BASE(n) + 0x01f0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_05__11_10(n) (ADR_BASE(n) + 0x01f4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_05__13_12(n) (ADR_BASE(n) + 0x01f8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_06__01_00(n) (ADR_BASE(n) + 0x01fc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_06__03_02(n) (ADR_BASE(n) + 0x0200) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_06__05_04(n) (ADR_BASE(n) + 0x0204) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_06__07_06(n) (ADR_BASE(n) + 0x0208) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_06__09_08(n) (ADR_BASE(n) + 0x020c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_06__11_10(n) (ADR_BASE(n) + 0x0210) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_06__13_12(n) (ADR_BASE(n) + 0x0214) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_07__01_00(n) (ADR_BASE(n) + 0x0218) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_07__03_02(n) (ADR_BASE(n) + 0x021c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_07__05_04(n) (ADR_BASE(n) + 0x0220) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_07__07_06(n) (ADR_BASE(n) + 0x0224) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_07__09_08(n) (ADR_BASE(n) + 0x0228) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_07__11_10(n) (ADR_BASE(n) + 0x022c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_07__13_12(n) (ADR_BASE(n) + 0x0230) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_08__01_00(n) (ADR_BASE(n) + 0x0234) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_08__03_02(n) (ADR_BASE(n) + 0x0238) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_08__05_04(n) (ADR_BASE(n) + 0x023c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_08__07_06(n) (ADR_BASE(n) + 0x0240) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_08__09_08(n) (ADR_BASE(n) + 0x0244) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_08__11_10(n) (ADR_BASE(n) + 0x0248) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_08__13_12(n) (ADR_BASE(n) + 0x024c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_09__01_00(n) (ADR_BASE(n) + 0x0250) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_09__03_02(n) (ADR_BASE(n) + 0x0254) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_09__05_04(n) (ADR_BASE(n) + 0x0258) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_09__07_06(n) (ADR_BASE(n) + 0x025c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_09__09_08(n) (ADR_BASE(n) + 0x0260) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_09__11_10(n) (ADR_BASE(n) + 0x0264) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_09__13_12(n) (ADR_BASE(n) + 0x0268) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_10__01_00(n) (ADR_BASE(n) + 0x026c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_10__03_02(n) (ADR_BASE(n) + 0x0270) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_10__05_04(n) (ADR_BASE(n) + 0x0274) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_10__07_06(n) (ADR_BASE(n) + 0x0278) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_10__09_08(n) (ADR_BASE(n) + 0x027c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_10__11_10(n) (ADR_BASE(n) + 0x0280) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_10__13_12(n) (ADR_BASE(n) + 0x0284) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_11__01_00(n) (ADR_BASE(n) + 0x0288) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_11__03_02(n) (ADR_BASE(n) + 0x028c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_11__05_04(n) (ADR_BASE(n) + 0x0290) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_11__07_06(n) (ADR_BASE(n) + 0x0294) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_11__09_08(n) (ADR_BASE(n) + 0x0298) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_11__11_10(n) (ADR_BASE(n) + 0x029c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_11__13_12(n) (ADR_BASE(n) + 0x02a0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_12__01_00(n) (ADR_BASE(n) + 0x02a4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_12__03_02(n) (ADR_BASE(n) + 0x02a8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_12__05_04(n) (ADR_BASE(n) + 0x02ac) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_12__07_06(n) (ADR_BASE(n) + 0x02b0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_12__09_08(n) (ADR_BASE(n) + 0x02b4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_12__11_10(n) (ADR_BASE(n) + 0x02b8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_12__13_12(n) (ADR_BASE(n) + 0x02bc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_13__01_00(n) (ADR_BASE(n) + 0x02c0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_13__03_02(n) (ADR_BASE(n) + 0x02c4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_13__05_04(n) (ADR_BASE(n) + 0x02c8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_13__07_06(n) (ADR_BASE(n) + 0x02cc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_13__09_08(n) (ADR_BASE(n) + 0x02d0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_13__11_10(n) (ADR_BASE(n) + 0x02d4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_13__13_12(n) (ADR_BASE(n) + 0x02d8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_14__01_00(n) (ADR_BASE(n) + 0x02dc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_14__03_02(n) (ADR_BASE(n) + 0x02e0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_14__05_04(n) (ADR_BASE(n) + 0x02e4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_14__07_06(n) (ADR_BASE(n) + 0x02e8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_14__09_08(n) (ADR_BASE(n) + 0x02ec) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_14__11_10(n) (ADR_BASE(n) + 0x02f0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_14__13_12(n) (ADR_BASE(n) + 0x02f4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_15__01_00(n) (ADR_BASE(n) + 0x02f8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_15__03_02(n) (ADR_BASE(n) + 0x02fc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_15__05_04(n) (ADR_BASE(n) + 0x0300) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_15__07_06(n) (ADR_BASE(n) + 0x0304) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_15__09_08(n) (ADR_BASE(n) + 0x0308) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_15__11_10(n) (ADR_BASE(n) + 0x030c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_15__13_12(n) (ADR_BASE(n) + 0x0310) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_16__01_00(n) (ADR_BASE(n) + 0x0314) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_16__03_02(n) (ADR_BASE(n) + 0x0318) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_16__05_04(n) (ADR_BASE(n) + 0x031c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_16__07_06(n) (ADR_BASE(n) + 0x0320) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_16__09_08(n) (ADR_BASE(n) + 0x0324) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_16__11_10(n) (ADR_BASE(n) + 0x0328) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_16__13_12(n) (ADR_BASE(n) + 0x032c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_17__01_00(n) (ADR_BASE(n) + 0x0330) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_17__03_02(n) (ADR_BASE(n) + 0x0334) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_17__05_04(n) (ADR_BASE(n) + 0x0338) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_17__07_06(n) (ADR_BASE(n) + 0x033c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_17__09_08(n) (ADR_BASE(n) + 0x0340) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_17__11_10(n) (ADR_BASE(n) + 0x0344) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_17__13_12(n) (ADR_BASE(n) + 0x0348) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_18__01_00(n) (ADR_BASE(n) + 0x034c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_18__03_02(n) (ADR_BASE(n) + 0x0350) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_18__05_04(n) (ADR_BASE(n) + 0x0354) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_18__07_06(n) (ADR_BASE(n) + 0x0358) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_18__09_08(n) (ADR_BASE(n) + 0x035c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_18__11_10(n) (ADR_BASE(n) + 0x0360) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_18__13_12(n) (ADR_BASE(n) + 0x0364) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_19__01_00(n) (ADR_BASE(n) + 0x0368) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_19__03_02(n) (ADR_BASE(n) + 0x036c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_19__05_04(n) (ADR_BASE(n) + 0x0370) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_19__07_06(n) (ADR_BASE(n) + 0x0374) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_19__09_08(n) (ADR_BASE(n) + 0x0378) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_19__11_10(n) (ADR_BASE(n) + 0x037c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_19__13_12(n) (ADR_BASE(n) + 0x0380) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_20__01_00(n) (ADR_BASE(n) + 0x0384) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_20__03_02(n) (ADR_BASE(n) + 0x0388) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_20__05_04(n) (ADR_BASE(n) + 0x038c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_20__07_06(n) (ADR_BASE(n) + 0x0390) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_20__09_08(n) (ADR_BASE(n) + 0x0394) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_20__11_10(n) (ADR_BASE(n) + 0x0398) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_20__13_12(n) (ADR_BASE(n) + 0x039c) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_21__01_00(n) (ADR_BASE(n) + 0x03a0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_21__03_02(n) (ADR_BASE(n) + 0x03a4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_21__05_04(n) (ADR_BASE(n) + 0x03a8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_21__07_06(n) (ADR_BASE(n) + 0x03ac) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_21__09_08(n) (ADR_BASE(n) + 0x03b0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_21__11_10(n) (ADR_BASE(n) + 0x03b4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_21__13_12(n) (ADR_BASE(n) + 0x03b8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_22__01_00(n) (ADR_BASE(n) + 0x03bc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_22__03_02(n) (ADR_BASE(n) + 0x03c0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_22__05_04(n) (ADR_BASE(n) + 0x03c4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_22__07_06(n) (ADR_BASE(n) + 0x03c8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_22__09_08(n) (ADR_BASE(n) + 0x03cc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_22__11_10(n) (ADR_BASE(n) + 0x03d0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_22__13_12(n) (ADR_BASE(n) + 0x03d4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_23__01_00(n) (ADR_BASE(n) + 0x03d8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_23__03_02(n) (ADR_BASE(n) + 0x03dc) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_23__05_04(n) (ADR_BASE(n) + 0x03e0) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_23__07_06(n) (ADR_BASE(n) + 0x03e4) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_23__09_08(n) (ADR_BASE(n) + 0x03e8) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_23__11_10(n) (ADR_BASE(n) + 0x03ec) ++#define ADR_ADDR_MAP_KNEEPOINT_Y_23__13_12(n) (ADR_BASE(n) + 0x03f0) ++#define ADR_ADDR_COC_KNEEPOINT_Y1__01_00(n) (ADR_BASE(n) + 0x03f4) ++#define ADR_ADDR_COC_KNEEPOINT_Y1__03_02(n) (ADR_BASE(n) + 0x03f8) ++#define ADR_ADDR_COC_KNEEPOINT_Y1__05_04(n) (ADR_BASE(n) + 0x03fc) ++#define ADR_ADDR_COC_KNEEPOINT_Y1__07_06(n) (ADR_BASE(n) + 0x0400) ++#define ADR_ADDR_COC_KNEEPOINT_Y1__09_08(n) (ADR_BASE(n) + 0x0404) ++#define ADR_ADDR_COC_KNEEPOINT_Y1__11_10(n) (ADR_BASE(n) + 0x0408) ++#define ADR_ADDR_COC_KNEEPOINT_Y2__01_00(n) (ADR_BASE(n) + 0x040c) ++#define ADR_ADDR_COC_KNEEPOINT_Y2__03_02(n) (ADR_BASE(n) + 0x0410) ++#define ADR_ADDR_COC_KNEEPOINT_Y2__05_04(n) (ADR_BASE(n) + 0x0414) ++#define ADR_ADDR_COC_KNEEPOINT_Y2__07_06(n) (ADR_BASE(n) + 0x0418) ++#define ADR_ADDR_COC_KNEEPOINT_Y2__09_08(n) (ADR_BASE(n) + 0x041c) ++#define ADR_ADDR_COC_KNEEPOINT_Y2__11_10(n) (ADR_BASE(n) + 0x0420) ++#define ADR_ADDR_COC_KNEEPOINT_Y3__01_00(n) (ADR_BASE(n) + 0x0424) ++#define ADR_ADDR_COC_KNEEPOINT_Y3__03_02(n) (ADR_BASE(n) + 0x0428) ++#define ADR_ADDR_COC_KNEEPOINT_Y3__05_04(n) (ADR_BASE(n) + 0x042c) ++#define ADR_ADDR_COC_KNEEPOINT_Y3__07_06(n) (ADR_BASE(n) + 0x0430) ++#define ADR_ADDR_COC_KNEEPOINT_Y3__09_08(n) (ADR_BASE(n) + 0x0434) ++#define ADR_ADDR_COC_KNEEPOINT_Y3__11_10(n) (ADR_BASE(n) + 0x0438) ++#define ADR_ADDR_COC_KNEEPOINT_Y4__01_00(n) (ADR_BASE(n) + 0x043c) ++#define ADR_ADDR_COC_KNEEPOINT_Y4__03_02(n) (ADR_BASE(n) + 0x0440) ++#define ADR_ADDR_COC_KNEEPOINT_Y4__05_04(n) (ADR_BASE(n) + 0x0444) ++#define ADR_ADDR_COC_KNEEPOINT_Y4__07_06(n) (ADR_BASE(n) + 0x0448) ++#define ADR_ADDR_COC_KNEEPOINT_Y4__09_08(n) (ADR_BASE(n) + 0x044c) ++#define ADR_ADDR_COC_KNEEPOINT_Y4__11_10(n) (ADR_BASE(n) + 0x0450) ++#define ADR_ADDR_COC_KNEEPOINT_Y5__01_00(n) (ADR_BASE(n) + 0x0454) ++#define ADR_ADDR_COC_KNEEPOINT_Y5__03_02(n) (ADR_BASE(n) + 0x0458) ++#define ADR_ADDR_COC_KNEEPOINT_Y5__05_04(n) (ADR_BASE(n) + 0x045c) ++#define ADR_ADDR_COC_KNEEPOINT_Y5__07_06(n) (ADR_BASE(n) + 0x0460) ++#define ADR_ADDR_COC_KNEEPOINT_Y5__09_08(n) (ADR_BASE(n) + 0x0464) ++#define ADR_ADDR_COC_KNEEPOINT_Y5__11_10(n) (ADR_BASE(n) + 0x0468) ++#define ADR_ADDR_ADR_COC_GAM1_Y__01_00(n) (ADR_BASE(n) + 0x046c) ++#define ADR_ADDR_ADR_COC_GAM1_Y__03_02(n) (ADR_BASE(n) + 0x0470) ++#define ADR_ADDR_ADR_COC_GAM1_Y__04_04(n) (ADR_BASE(n) + 0x0474) ++#define ADR_ADDR_ADR_COC_GAM2_Y__01_00(n) (ADR_BASE(n) + 0x0478) ++#define ADR_ADDR_ADR_COC_GAM2_Y__03_02(n) (ADR_BASE(n) + 0x047c) ++#define ADR_ADDR_ADR_COC_GAM2_Y__05_04(n) (ADR_BASE(n) + 0x0480) ++#define ADR_ADDR_ADR_COC_GAM2_Y__07_06(n) (ADR_BASE(n) + 0x0484) ++#define ADR_ADDR_ADR_COC_GAM2_Y__09_08(n) (ADR_BASE(n) + 0x0488) ++#define ADR_ADDR_ADR_COC_GAM2_Y__11_10(n) (ADR_BASE(n) + 0x048c) ++#define ADR_ADDR_ADR_COC_GAM2_Y__13_12(n) (ADR_BASE(n) + 0x0490) ++#define ADR_ADDR_ADR_COC_GAM2_Y__15_14(n) (ADR_BASE(n) + 0x0494) ++#define ADR_ADDR_ADR_COC_GAM2_Y__17_16(n) (ADR_BASE(n) + 0x0498) ++#define ADR_ADDR_CENTRE_W_DISTANCE__01_00(n) (ADR_BASE(n) + 0x049c) ++#define ADR_ADDR_CENTRE_W_DISTANCE__03_02(n) (ADR_BASE(n) + 0x04a0) ++#define ADR_ADDR_CENTRE_W_DISTANCE__05_04(n) (ADR_BASE(n) + 0x04a4) ++#define ADR_ADDR_CENTRE_W_DISTANCE__07_06(n) (ADR_BASE(n) + 0x04a8) ++#define ADR_ADDR_CENTRE_W_DISTANCE__09_08(n) (ADR_BASE(n) + 0x04ac) ++#define ADR_ADDR_CENTRE_W_DISTANCE__11_10(n) (ADR_BASE(n) + 0x04b0) ++#define ADR_ADDR_CENTRE_W_DISTANCE__13_12(n) (ADR_BASE(n) + 0x04b4) ++#define ADR_ADDR_CENTRE_W_DISTANCE__15_14(n) (ADR_BASE(n) + 0x04b8) ++#define ADR_ADDR_CENTRE_W_DISTANCE__17_16(n) (ADR_BASE(n) + 0x04bc) ++#define ADR_ADDR_CENTRE_W_DISTANCE__19_18(n) (ADR_BASE(n) + 0x04c0) ++#define ADR_ADDR_CENTRE_W_DISTANCE__21_20(n) (ADR_BASE(n) + 0x04c4) ++#define ADR_ADDR_CENTRE_W_DISTANCE__23_22(n) (ADR_BASE(n) + 0x04c8) ++#define ADR_ADDR_CENTRE_W_DISTANCE__25_24(n) (ADR_BASE(n) + 0x04cc) ++#define ADR_ADDR_CENTRE_W_DISTANCE__27_26(n) (ADR_BASE(n) + 0x04d0) ++#define ADR_ADDR_CENTRE_W_DISTANCE__29_28(n) (ADR_BASE(n) + 0x04d4) ++#define ADR_ADDR_CENTRE_W_DISTANCE__30_30(n) (ADR_BASE(n) + 0x04d8) ++#define ADR_ADDR_ADR_COC_GAM_01_00(n) (ADR_BASE(n) + 0x04dc) ++#define ADR_ADDR_ADR_COC_GAM_03_02(n) (ADR_BASE(n) + 0x04e0) ++#define ADR_ADDR_ADR_COC_GAM_04_04(n) (ADR_BASE(n) + 0x04e4) ++#define ADR_ADDR_ADR_COC_W_X_01_00(n) (ADR_BASE(n) + 0x04e8) ++#define ADR_ADDR_ADR_COC_W_X_03_02(n) (ADR_BASE(n) + 0x04ec) ++#define ADR_ADDR_ADR_COC_W_Y_01_00(n) (ADR_BASE(n) + 0x04f0) ++#define ADR_ADDR_ADR_COC_W_Y_03_02(n) (ADR_BASE(n) + 0x04f4) ++#define ADR_ADDR_ADR_COC_W_POW_01_00(n) (ADR_BASE(n) + 0x04f8) ++#define ADR_ADDR_ADR_COC_W_POW_02_02(n) (ADR_BASE(n) + 0x04fc) ++ ++#define MAIN_ADR_ADDR_STAT_FRAME_RATE (ADR0_BASE + 0x0500) ++#define MAIN_ADR_ADDR_BANK_BUFFER_NUMBER (ADR0_BASE + 0x0510) ++#define MAIN_ADR_ADDR_BANK00_ADDR (ADR0_BASE + 0x0514) ++#define MAIN_ADR_ADDR_BANK01_ADDR (ADR0_BASE + 0x0518) ++#define MAIN_ADR_ADDR_BANK02_ADDR (ADR0_BASE + 0x051c) ++#define MAIN_ADR_ADDR_BANK03_ADDR (ADR0_BASE + 0x0520) ++#define MAIN_ADR_ADDR_FRAME_ADDR0 (ADR0_BASE + 0x0540) ++#define MAIN_ADR_ADDR_FRAME_ID0 (ADR0_BASE + 0x0544) ++#define MAIN_ADR_ADDR_FRAME_ADDR1 (ADR0_BASE + 0x0548) ++#define MAIN_ADR_ADDR_FRAME_ID1 (ADR0_BASE + 0x054c) ++#define MAIN_ADR_ADDR_DBG_0 (ADR0_BASE + 0x0580) ++#define MAIN_ADR_ADDR_DBG_1 (ADR0_BASE + 0x0584) ++#define MAIN_ADR_ADDR_DBG_2 (ADR0_BASE + 0x0588) ++#define MAIN_ADR_ADDR_DBG_3 (ADR0_BASE + 0x058c) ++#define MAIN_ADR_ADDR_DBG_4 (ADR0_BASE + 0x0590) ++#define MAIN_ADR_ADDR_DBG_5 (ADR0_BASE + 0x0594) ++#define MAIN_ADR_ADDR_DBG_6 (ADR0_BASE + 0x0598) ++#define MAIN_ADR_ADDR_DBG_7 (ADR0_BASE + 0x059c) ++#define MAIN_ADR_ADDR_DBG_8 (ADR0_BASE + 0x05a0) ++ ++#define SEC_ADR_ADDR_MODE (ADR1_BASE + 0x0000) ++#define SEC_ADR_ADDR_EXT_PRIO (ADR1_BASE + 0x0004) ++ ++#define SEC_ADR_ADDR_STAT_FRAME_RATE (ADR1_BASE + 0x0500) ++#define SEC_ADR_ADDR_BANK_BUFFER_NUMBER (ADR1_BASE + 0x0510) ++#define SEC_ADR_ADDR_BANK00_ADDR (ADR1_BASE + 0x0514) ++#define SEC_ADR_ADDR_BANK01_ADDR (ADR1_BASE + 0x0518) ++#define SEC_ADR_ADDR_BANK02_ADDR (ADR1_BASE + 0x051c) ++#define SEC_ADR_ADDR_BANK03_ADDR (ADR1_BASE + 0x0520) ++#define SEC_ADR_ADDR_FRAME_ADDR0 (ADR1_BASE + 0x0540) ++#define SEC_ADR_ADDR_FRAME_ID0 (ADR1_BASE + 0x0544) ++#define SEC_ADR_ADDR_FRAME_ADDR1 (ADR1_BASE + 0x0548) ++#define SEC_ADR_ADDR_FRAME_ID1 (ADR1_BASE + 0x054c) ++#define SEC_ADR_ADDR_DBG_0 (ADR1_BASE + 0x0580) ++#define SEC_ADR_ADDR_DBG_1 (ADR1_BASE + 0x0584) ++#define SEC_ADR_ADDR_DBG_2 (ADR1_BASE + 0x0588) ++#define SEC_ADR_ADDR_DBG_3 (ADR1_BASE + 0x058c) ++#define SEC_ADR_ADDR_DBG_4 (ADR1_BASE + 0x0590) ++#define SEC_ADR_ADDR_DBG_5 (ADR1_BASE + 0x0594) ++#define SEC_ADR_ADDR_DBG_6 (ADR1_BASE + 0x0598) ++#define SEC_ADR_ADDR_DBG_7 (ADR1_BASE + 0x059c) ++#define SEC_ADR_ADDR_DBG_8 (ADR1_BASE + 0x05a0) ++ ++//============================================================ ++// DMSC ADDRESS ++//============================================================ ++#define DEMOSAIC_ADDR_OUT_OPT(n) (DEMOSAIC_BASE(n) + 0x0000) ++#define DEMOSAIC_ADDR_G_STD_STREN(n) (DEMOSAIC_BASE(n) + 0x0004) ++#define DEMOSAIC_ADDR_UU_THRES(n) (DEMOSAIC_BASE(n) + 0x0008) ++#define DEMOSAIC_ADDR_ALIAS_DIR_DIFF(n) (DEMOSAIC_BASE(n) + 0x000c) ++#define DEMOSAIC_ADDR_WIN5_HV_EDGE_THRES(n) (DEMOSAIC_BASE(n) + 0x0010) ++#define DEMOSAIC_ADDR_HV_EDGE_THRES(n) (DEMOSAIC_BASE(n) + 0x0014) ++#define DEMOSAIC_ADDR_HV_EDGE(n) (DEMOSAIC_BASE(n) + 0x0020) ++#define DEMOSAIC_ADDR_AA_EDGE_THRES(n) (DEMOSAIC_BASE(n) + 0x0024) ++#define DEMOSAIC_ADDR_AA_EDGE(n) (DEMOSAIC_BASE(n) + 0x0028) ++#define DEMOSAIC_ADDR_HVAA_EDGE_THRES(n) (DEMOSAIC_BASE(n) + 0x002c) ++#define DEMOSAIC_ADDR_HVAA_EDGE(n) (DEMOSAIC_BASE(n) + 0x0030) ++#define DEMOSAIC_ADDR_ALIAS_STREN(n) (DEMOSAIC_BASE(n) + 0x0034) ++#define DEMOSAIC_ADDR_ALIAS_THRES(n) (DEMOSAIC_BASE(n) + 0x0038) ++#define DEMOSAIC_ADDR_NOR_ALIAS_BLUR(n) (DEMOSAIC_BASE(n) + 0x003c) ++#define DEMOSAIC_ADDR_NOR_UU_WEI_STREN(n) (DEMOSAIC_BASE(n) + 0x0040) ++#define DEMOSAIC_ADDR_SP_D_V2_SIGMA(n) (DEMOSAIC_BASE(n) + 0x0044) ++#define DEMOSAIC_ADDR_SP_D_W_SP_STREN(n) (DEMOSAIC_BASE(n) + 0x0048) ++#define DEMOSAIC_ADDR_SP_D_LL_STREN(n) (DEMOSAIC_BASE(n) + 0x004c) ++#define DEMOSAIC_ADDR_SP_D_THRES(n) (DEMOSAIC_BASE(n) + 0x0050) ++#define DEMOSAIC_ADDR_SP_D_W_LIMIT(n) (DEMOSAIC_BASE(n) + 0x0054) ++#define DEMOSAIC_ADDR_SP_D_B_LIMIT(n) (DEMOSAIC_BASE(n) + 0x0058) ++#define DEMOSAIC_ADDR_SP_UD_V2_SIGMA(n) (DEMOSAIC_BASE(n) + 0x005c) ++#define DEMOSAIC_ADDR_SP_UD_W_SP_STREN(n) (DEMOSAIC_BASE(n) + 0x0060) ++#define DEMOSAIC_ADDR_SP_UD_LL_STREN(n) (DEMOSAIC_BASE(n) + 0x0064) ++#define DEMOSAIC_ADDR_SP_UD_LL_THRES(n) (DEMOSAIC_BASE(n) + 0x0068) ++#define DEMOSAIC_ADDR_SP_UD_W_LIMIT(n) (DEMOSAIC_BASE(n) + 0x006c) ++#define DEMOSAIC_ADDR_SP_UD_B_LIMIT(n) (DEMOSAIC_BASE(n) + 0x0070) ++#define DEMOSAIC_ADDR_SP_NOR_ALIAS_THRES(n) (DEMOSAIC_BASE(n) + 0x0074) ++#define DEMOSAIC_ADDR_ALIAS_FUSION_THRES(n) (DEMOSAIC_BASE(n) + 0x0078) ++#define DEMOSAIC_ADDR_ALIAS_DIR_INTP_SP_STREN(n) (DEMOSAIC_BASE(n) + 0x007c) ++#define DEMOSAIC_ADDR_FC_ALIAS_STREN(n) (DEMOSAIC_BASE(n) + 0x0080) ++#define DEMOSAIC_ADDR_FC_ALIAS_THRES(n) (DEMOSAIC_BASE(n) + 0x0084) ++#define DEMOSAIC_ADDR_FC_NOR_SAT_THRES(n) (DEMOSAIC_BASE(n) + 0x0088) ++#define DEMOSAIC_ADDR_FC_TEXT_THRES(n) (DEMOSAIC_BASE(n) + 0x008c) ++#define DEMOSAIC_ADDR_FC_NOR_EDGE_SLOPE(n) (DEMOSAIC_BASE(n) + 0x0090) ++#define DEMOSAIC_ADDR_FC_THRES_H_1(n) (DEMOSAIC_BASE(n) + 0x009c) ++#define DEMOSAIC_ADDR_SP_D_V2_WIN5_THRES(n) (DEMOSAIC_BASE(n) + 0x00a4) ++#define DEMOSAIC_ADDR_SP_D_OE_EN(n) (DEMOSAIC_BASE(n) + 0x00ac) ++#define DEMOSAIC_ADDR_SP_UD_V1_SEL_OPT(n) (DEMOSAIC_BASE(n) + 0x00b0) ++#define DEMOSAIC_ADDR_SP_UD_V2_SEL_OPT(n) (DEMOSAIC_BASE(n) + 0x00b4) ++#define DEMOSAIC_ADDR_SP_UD_STD_THRES(n) (DEMOSAIC_BASE(n) + 0x00b8) ++#define DEMOSAIC_ADDR_SP_UD_OE_EN(n) (DEMOSAIC_BASE(n) + 0x00c4) ++#define DEMOSAIC_ADDR_UU_NP_REG0(n) (DEMOSAIC_BASE(n) + 0x00c8) ++#define DEMOSAIC_ADDR_UU_NP_REG1(n) (DEMOSAIC_BASE(n) + 0x00cc) ++#define DEMOSAIC_ADDR_UU_NP_REG2(n) (DEMOSAIC_BASE(n) + 0x00d0) ++#define DEMOSAIC_ADDR_UU_NP_REG3(n) (DEMOSAIC_BASE(n) + 0x00d4) ++#define DEMOSAIC_ADDR_UU_NP_REG4(n) (DEMOSAIC_BASE(n) + 0x00d8) ++#define DEMOSAIC_ADDR_UU_NP_REG5(n) (DEMOSAIC_BASE(n) + 0x00dc) ++#define DEMOSAIC_ADDR_UU_NP_REG6(n) (DEMOSAIC_BASE(n) + 0x00e0) ++#define DEMOSAIC_ADDR_UU_NP_REG7(n) (DEMOSAIC_BASE(n) + 0x00e4) ++#define DEMOSAIC_ADDR_SP_D_W_WEI_NP_REG0(n) (DEMOSAIC_BASE(n) + 0x00f4) ++#define DEMOSAIC_ADDR_SP_D_W_WEI_NP_REG1(n) (DEMOSAIC_BASE(n) + 0x00f8) ++#define DEMOSAIC_ADDR_SP_D_W_WEI_NP_REG2(n) (DEMOSAIC_BASE(n) + 0x00fc) ++#define DEMOSAIC_ADDR_SP_D_W_WEI_NP_REG3(n) (DEMOSAIC_BASE(n) + 0x0100) ++#define DEMOSAIC_ADDR_SP_D_W_WEI_NP_REG4(n) (DEMOSAIC_BASE(n) + 0x0104) ++#define DEMOSAIC_ADDR_SP_D_W_WEI_NP_REG5(n) (DEMOSAIC_BASE(n) + 0x0108) ++#define DEMOSAIC_ADDR_SP_D_W_WEI_NP_REG6(n) (DEMOSAIC_BASE(n) + 0x010c) ++#define DEMOSAIC_ADDR_SP_UD_W_WEI_NP_REG0(n) (DEMOSAIC_BASE(n) + 0x011c) ++#define DEMOSAIC_ADDR_SP_UD_W_WEI_NP_REG1(n) (DEMOSAIC_BASE(n) + 0x0120) ++#define DEMOSAIC_ADDR_SP_UD_W_WEI_NP_REG2(n) (DEMOSAIC_BASE(n) + 0x0124) ++#define DEMOSAIC_ADDR_SP_UD_W_WEI_NP_REG3(n) (DEMOSAIC_BASE(n) + 0x0128) ++#define DEMOSAIC_ADDR_SP_UD_W_WEI_NP_REG4(n) (DEMOSAIC_BASE(n) + 0x012c) ++#define DEMOSAIC_ADDR_SP_UD_W_WEI_NP_REG5(n) (DEMOSAIC_BASE(n) + 0x0130) ++#define DEMOSAIC_ADDR_SP_UD_W_WEI_NP_REG6(n) (DEMOSAIC_BASE(n) + 0x0134) ++#define DEMOSAIC_ADDR_DEIR_EN(n) (DEMOSAIC_BASE(n) + 0x0144) ++#define DEMOSAIC_ADDR_DEIR_RGB_OE(n) (DEMOSAIC_BASE(n) + 0x0148) ++#define DEMOSAIC_ADDR_DEIR_IR_OE(n) (DEMOSAIC_BASE(n) + 0x014c) ++#define DEMOSAIC_ADDR_R_DEIR_NP_REG0(n) (DEMOSAIC_BASE(n) + 0x0150) ++#define DEMOSAIC_ADDR_R_DEIR_NP_REG1(n) (DEMOSAIC_BASE(n) + 0x0154) ++#define DEMOSAIC_ADDR_R_DEIR_NP_REG2(n) (DEMOSAIC_BASE(n) + 0x0158) ++#define DEMOSAIC_ADDR_R_DEIR_NP_REG3(n) (DEMOSAIC_BASE(n) + 0x015c) ++#define DEMOSAIC_ADDR_G_DEIR_NP_REG0(n) (DEMOSAIC_BASE(n) + 0x0160) ++#define DEMOSAIC_ADDR_G_DEIR_NP_REG1(n) (DEMOSAIC_BASE(n) + 0x0164) ++#define DEMOSAIC_ADDR_G_DEIR_NP_REG2(n) (DEMOSAIC_BASE(n) + 0x0168) ++#define DEMOSAIC_ADDR_G_DEIR_NP_REG3(n) (DEMOSAIC_BASE(n) + 0x016c) ++#define DEMOSAIC_ADDR_B_DEIR_NP_REG0(n) (DEMOSAIC_BASE(n) + 0x0170) ++#define DEMOSAIC_ADDR_B_DEIR_NP_REG1(n) (DEMOSAIC_BASE(n) + 0x0174) ++#define DEMOSAIC_ADDR_B_DEIR_NP_REG2(n) (DEMOSAIC_BASE(n) + 0x0178) ++#define DEMOSAIC_ADDR_B_DEIR_NP_REG3(n) (DEMOSAIC_BASE(n) + 0x017c) ++#define DEMOSAIC_ADDR_FC_LUM_THRES(n) (DEMOSAIC_BASE(n) + 0x0180) ++#define DEMOSAIC_ADDR_AWB_GAIN(n) (DEMOSAIC_BASE(n) + 0x0184) ++#define DEMOSAIC_ADDR_DEIR_FUSION_THRES(n) (DEMOSAIC_BASE(n) + 0x0188) ++#define DEMOSAIC_ADDR_DEBUG_0(n) (DEMOSAIC_BASE(n) + 0x018c) ++#define DEMOSAIC_ADDR_DEBUG_1(n) (DEMOSAIC_BASE(n) + 0x0190) ++#define DEMOSAIC_ADDR_DEBUG_2(n) (DEMOSAIC_BASE(n) + 0x0194) ++#define DEMOSAIC_ADDR_DEBUG_3(n) (DEMOSAIC_BASE(n) + 0x0198) ++#define DEMOSAIC_ADDR_SHD_CTRL(n) (DEMOSAIC_BASE(n) + 0x019c) ++#define DEMOSAIC_ADDR_FC_H_SAT_THRES(n) (DEMOSAIC_BASE(n) + 0x01a8) ++#define DEMOSAIC_ADDR_SP_FLAT_THRES(n) (DEMOSAIC_BASE(n) + 0x01ac) ++#define DEMOSAIC_ADDR_SP_FLAT_SLOPE(n) (DEMOSAIC_BASE(n) + 0x01b0) ++#define DEMOSAIC_ADDR_SP_FLAT_STREN(n) (DEMOSAIC_BASE(n) + 0x01b4) ++#define DEMOSAIC_ADDR_SP_D_DIR_THRES(n) (DEMOSAIC_BASE(n) + 0x01b8) ++#define DEMOSAIC_ADDR_H_SP_P1_VALUE(n) (DEMOSAIC_BASE(n) + 0x01bc) ++#define DEMOSAIC_ADDR_H_SP_P1_THRES(n) (DEMOSAIC_BASE(n) + 0x01c0) ++#define DEMOSAIC_ADDR_H_SP_P1_S_LOW_HIGH(n) (DEMOSAIC_BASE(n) + 0x01c4) ++#define DEMOSAIC_ADDR_H_SP_P2_VALUE(n) (DEMOSAIC_BASE(n) + 0x01c8) ++#define DEMOSAIC_ADDR_H_SP_P2_THRES(n) (DEMOSAIC_BASE(n) + 0x01cc) ++#define DEMOSAIC_ADDR_H_SP_P2_S_LOW_HIGH(n) (DEMOSAIC_BASE(n) + 0x01d0) ++#define DEMOSAIC_ADDR_H_SP_P3_VALUE(n) (DEMOSAIC_BASE(n) + 0x01d4) ++#define DEMOSAIC_ADDR_H_SP_P3_THRES(n) (DEMOSAIC_BASE(n) + 0x01d8) ++#define DEMOSAIC_ADDR_H_SP_P3_S_LOW_HIGH(n) (DEMOSAIC_BASE(n) + 0x01dc) ++#define DEMOSAIC_ADDR_H_SP_SLOPE(n) (DEMOSAIC_BASE(n) + 0x01e0) ++#define DEMOSAIC_ADDR_S_S0_SEL(n) (DEMOSAIC_BASE(n) + 0x01e4) ++#define DEMOSAIC_ADDR_S_UU_THRES(n) (DEMOSAIC_BASE(n) + 0x01e8) ++#define DEMOSAIC_ADDR_S_UU_SLOPE(n) (DEMOSAIC_BASE(n) + 0x01ec) ++#define DEMOSAIC_ADDR_S_V2_COEF1234(n) (DEMOSAIC_BASE(n) + 0x01f0) ++#define DEMOSAIC_ADDR_S_V2_COEF5(n) (DEMOSAIC_BASE(n) + 0x01f4) ++#define DEMOSAIC_ADDR_S_V1_COEF012(n) (DEMOSAIC_BASE(n) + 0x01f8) ++#define DEMOSAIC_ADDR_S_WEI_SEG_OPT(n) (DEMOSAIC_BASE(n) + 0x01fc) ++#define DEMOSAIC_ADDR_S_WEI_SEG_OPT_1(n) (DEMOSAIC_BASE(n) + 0x0200) ++#define DEMOSAIC_ADDR_S_B_SP_STREN(n) (DEMOSAIC_BASE(n) + 0x0204) ++#define DEMOSAIC_ADDR_S_G_STD(n) (DEMOSAIC_BASE(n) + 0x0208) ++#define DEMOSAIC_ADDR_S_LL_THRES(n) (DEMOSAIC_BASE(n) + 0x020c) ++#define DEMOSAIC_ADDR_S_HL_THRES(n) (DEMOSAIC_BASE(n) + 0x0210) ++#define DEMOSAIC_ADDR_S_FLAT_THRES(n) (DEMOSAIC_BASE(n) + 0x0214) ++#define DEMOSAIC_ADDR_S_OE_EN(n) (DEMOSAIC_BASE(n) + 0x0218) ++#define DEMOSAIC_ADDR_S_SHRINK_EN(n) (DEMOSAIC_BASE(n) + 0x021c) ++#define DEMOSAIC_ADDR_FC_NOR_SAT(n) (DEMOSAIC_BASE(n) + 0x0220) ++#define DEMOSAIC_ADDR_FC_NOR_SAT_1(n) (DEMOSAIC_BASE(n) + 0x0224) ++#define DEMOSAIC_ADDR_FC_NOR_H_THRES(n) (DEMOSAIC_BASE(n) + 0x0228) ++#define DEMOSAIC_ADDR_FC_TEXT_SAT_THRES(n) (DEMOSAIC_BASE(n) + 0x022c) ++#define DEMOSAIC_ADDR_FC_TEXT_LUM_THRES(n) (DEMOSAIC_BASE(n) + 0x0230) ++#define DEMOSAIC_ADDR_FC_TEXT_S_STD_THRES(n) (DEMOSAIC_BASE(n) + 0x0234) ++#define DEMOSAIC_ADDR_FC_TEXT_H_THRES(n) (DEMOSAIC_BASE(n) + 0x0238) ++#define DEMOSAIC_ADDR_FC_NOR_H_SLOPE(n) (DEMOSAIC_BASE(n) + 0x023c) ++#define DEMOSAIC_ADDR_S_FLAT_SLOPE(n) (DEMOSAIC_BASE(n) + 0x0240) ++#define DEMOSAIC_ADDR_FC_OE_SAT_THRES(n) (DEMOSAIC_BASE(n) + 0x0244) ++#define DEMOSAIC_ADDR_FC_OE_H_THRES(n) (DEMOSAIC_BASE(n) + 0x0248) ++#define DEMOSAIC_ADDR_SP_S_WEI_NP_ARRAY(n) (DEMOSAIC_BASE(n) + 0x024c) ++#define DEMOSAIC_ADDR_SP_S_WEI_NP_ARRAY_1(n) (DEMOSAIC_BASE(n) + 0x0250) ++#define DEMOSAIC_ADDR_SP_S_WEI_NP_ARRAY_2(n) (DEMOSAIC_BASE(n) + 0x0254) ++#define DEMOSAIC_ADDR_SP_S_WEI_NP_ARRAY_3(n) (DEMOSAIC_BASE(n) + 0x0258) ++#define DEMOSAIC_ADDR_SP_S_WEI_NP_ARRAY_4(n) (DEMOSAIC_BASE(n) + 0x025c) ++#define DEMOSAIC_ADDR_SP_S_WEI_NP_ARRAY_5(n) (DEMOSAIC_BASE(n) + 0x0260) ++#define DEMOSAIC_ADDR_SP_S_WEI_NP_ARRAY_6(n) (DEMOSAIC_BASE(n) + 0x0264) ++#define DEMOSAIC_ADDR_SP_S_WEI_NP_ARRAY_7(n) (DEMOSAIC_BASE(n) + 0x0268) ++#define DEMOSAIC_ADDR_S_LAP_3_MUL_FACTOR(n) (DEMOSAIC_BASE(n) + 0x026c) ++#define DEMOSAIC_ADDR_S_LAP_3_STD_SLOPE(n) (DEMOSAIC_BASE(n) + 0x0270) ++#define DEMOSAIC_ADDR_G_LAP_3_MUL_FACTOR(n) (DEMOSAIC_BASE(n) + 0x0274) ++#define DEMOSAIC_ADDR_G_LAP_3_STD_SLOPE(n) (DEMOSAIC_BASE(n) + 0x0278) ++ ++//============================================================ ++// CCM ADDRESS ++//============================================================ ++#define MAIN_CCM_ADDR_SHD_CTRL (CCM0_BASE + 0x0000) ++#define MAIN_CCM_ADDR_CCM_RRRG (CCM0_BASE + 0x0004) ++#define MAIN_CCM_ADDR_CCM_RBGR (CCM0_BASE + 0x0008) ++#define MAIN_CCM_ADDR_CCM_GGGB (CCM0_BASE + 0x000c) ++#define MAIN_CCM_ADDR_CCM_BRBG (CCM0_BASE + 0x0010) ++#define MAIN_CCM_ADDR_CCM_BB (CCM0_BASE + 0x0014) ++#define MAIN_CCM_ADDR_CCM_DP_CFG (CCM0_BASE + 0x0018) ++#define MAIN_CCM_ADDR_CCM_DP_SLOPE (CCM0_BASE + 0x001c) ++#define MAIN_CCM_ADDR_CCM_SAT_THRES (CCM0_BASE + 0x0020) ++#define MAIN_CCM_ADDR_DEBUG0 (CCM0_BASE + 0x0024) ++#define MAIN_CCM_ADDR_DEBUG1 (CCM0_BASE + 0x0028) ++ ++#define SEC_CCM_ADDR_SHD_CTRL (CCM1_BASE + 0x0000) ++#define SEC_CCM_ADDR_CCM_RRRG (CCM1_BASE + 0x0004) ++#define SEC_CCM_ADDR_CCM_RBGR (CCM1_BASE + 0x0008) ++#define SEC_CCM_ADDR_CCM_GGGB (CCM1_BASE + 0x000c) ++#define SEC_CCM_ADDR_CCM_BRBG (CCM1_BASE + 0x0010) ++#define SEC_CCM_ADDR_CCM_BB (CCM1_BASE + 0x0014) ++#define SEC_CCM_ADDR_CCM_DP_CFG (CCM1_BASE + 0x0018) ++#define SEC_CCM_ADDR_CCM_DP_SLOPE (CCM1_BASE + 0x001c) ++#define SEC_CCM_ADDR_CCM_SAT_THRES (CCM1_BASE + 0x0020) ++#define SEC_CCM_ADDR_DEBUG0 (CCM1_BASE + 0x0024) ++#define SEC_CCM_ADDR_DEBUG1 ++ ++//============================================================ ++// DEFOG ADDRESS ++//============================================================ ++#define DEFOG_ADDR_VERSION(n) (DEFOG_BASE(n) + 0x0000) ++#define DEFOG_ADDR_CTRL(n) (DEFOG_BASE(n) + 0x0004) ++#define DEFOG_ADDR_BLOCKSIZE_BS(n) (DEFOG_BASE(n) + 0x0008) ++#define DEFOG_ADDR_BLOCKSIZE_SY(n) (DEFOG_BASE(n) + 0x000c) ++#define DEFOG_ADDR_PARA(n) (DEFOG_BASE(n) + 0x0010) ++#define DEFOG_ADDR_EXT_PRIO(n) (DEFOG_BASE(n) + 0x0014) ++#define DEFOG_ADDR_W_3X3_TABLE__01_00(n) (DEFOG_BASE(n) + 0x0020) ++#define DEFOG_ADDR_W_3X3_TABLE__03_02(n) (DEFOG_BASE(n) + 0x0024) ++#define DEFOG_ADDR_W_3X3_TABLE__05_04(n) (DEFOG_BASE(n) + 0x0028) ++#define DEFOG_ADDR_W_3X3_TABLE__07_06(n) (DEFOG_BASE(n) + 0x002c) ++#define DEFOG_ADDR_W_3X3_TABLE__09_08(n) (DEFOG_BASE(n) + 0x0030) ++#define DEFOG_ADDR_W_3X3_TABLE__11_10(n) (DEFOG_BASE(n) + 0x0034) ++#define DEFOG_ADDR_W_3X3_TABLE__13_12(n) (DEFOG_BASE(n) + 0x0038) ++#define DEFOG_ADDR_W_3X3_TABLE__15_14(n) (DEFOG_BASE(n) + 0x003c) ++#define DEFOG_ADDR_W_3X3_TABLE__17_16(n) (DEFOG_BASE(n) + 0x0040) ++#define DEFOG_ADDR_W_3X3_TABLE__19_18(n) (DEFOG_BASE(n) + 0x0044) ++#define DEFOG_ADDR_W_3X3_TABLE__21_20(n) (DEFOG_BASE(n) + 0x0048) ++#define DEFOG_ADDR_W_3X3_TABLE__23_22(n) (DEFOG_BASE(n) + 0x004c) ++#define DEFOG_ADDR_W_5X5_TABLE__01_00(n) (DEFOG_BASE(n) + 0x0050) ++#define DEFOG_ADDR_W_5X5_TABLE__03_02(n) (DEFOG_BASE(n) + 0x0054) ++#define DEFOG_ADDR_W_5X5_TABLE__05_04(n) (DEFOG_BASE(n) + 0x0058) ++#define DEFOG_ADDR_W_5X5_TABLE__07_06(n) (DEFOG_BASE(n) + 0x005c) ++#define DEFOG_ADDR_W_5X5_TABLE__09_08(n) (DEFOG_BASE(n) + 0x0060) ++#define DEFOG_ADDR_W_5X5_TABLE__11_10(n) (DEFOG_BASE(n) + 0x0064) ++#define DEFOG_ADDR_W_5X5_TABLE__13_12(n) (DEFOG_BASE(n) + 0x0068) ++#define DEFOG_ADDR_W_5X5_TABLE__15_14(n) (DEFOG_BASE(n) + 0x006c) ++#define DEFOG_ADDR_W_5X5_TABLE__17_16(n) (DEFOG_BASE(n) + 0x0070) ++#define DEFOG_ADDR_W_5X5_TABLE__19_18(n) (DEFOG_BASE(n) + 0x0074) ++#define DEFOG_ADDR_W_5X5_TABLE__21_20(n) (DEFOG_BASE(n) + 0x0078) ++#define DEFOG_ADDR_W_5X5_TABLE__23_22(n) (DEFOG_BASE(n) + 0x007c) ++#define DEFOG_ADDR_W_5X5_TABLE__25_24(n) (DEFOG_BASE(n) + 0x0080) ++#define DEFOG_ADDR_W_5X5_TABLE__27_26(n) (DEFOG_BASE(n) + 0x0084) ++#define DEFOG_ADDR_W_5X5_TABLE__29_28(n) (DEFOG_BASE(n) + 0x0088) ++#define DEFOG_ADDR_W_5X5_TABLE__30_30(n) (DEFOG_BASE(n) + 0x008c) ++#define DEFOG_ADDR_WEIGHT_A__03_00(n) (DEFOG_BASE(n) + 0x0090) ++#define DEFOG_ADDR_WEIGHT_A__07_04(n) (DEFOG_BASE(n) + 0x0094) ++#define DEFOG_ADDR_WEIGHT_A__11_08(n) (DEFOG_BASE(n) + 0x0098) ++#define DEFOG_ADDR_WEIGHT_A__15_12(n) (DEFOG_BASE(n) + 0x009c) ++#define DEFOG_ADDR_WEIGHT_A__19_16(n) (DEFOG_BASE(n) + 0x00a0) ++#define DEFOG_ADDR_WEIGHT_A__23_20(n) (DEFOG_BASE(n) + 0x00a4) ++#define DEFOG_ADDR_WEIGHT_A__27_24(n) (DEFOG_BASE(n) + 0x00a8) ++#define DEFOG_ADDR_WEIGHT_A__31_28(n) (DEFOG_BASE(n) + 0x00ac) ++#define DEFOG_ADDR_WEIGHT_B1__03_00(n) (DEFOG_BASE(n) + 0x00b0) ++#define DEFOG_ADDR_WEIGHT_B1__07_04(n) (DEFOG_BASE(n) + 0x00b4) ++#define DEFOG_ADDR_WEIGHT_B1__11_08(n) (DEFOG_BASE(n) + 0x00b8) ++#define DEFOG_ADDR_WEIGHT_B1__15_12(n) (DEFOG_BASE(n) + 0x00bc) ++#define DEFOG_ADDR_WEIGHT_B1__19_16(n) (DEFOG_BASE(n) + 0x00c0) ++#define DEFOG_ADDR_WEIGHT_B1__23_20(n) (DEFOG_BASE(n) + 0x00c4) ++#define DEFOG_ADDR_WEIGHT_B1__27_24(n) (DEFOG_BASE(n) + 0x00c8) ++#define DEFOG_ADDR_WEIGHT_B1__31_28(n) (DEFOG_BASE(n) + 0x00cc) ++#define DEFOG_ADDR_WEIGHT_B2__03_00(n) (DEFOG_BASE(n) + 0x00d0) ++#define DEFOG_ADDR_WEIGHT_B2__07_04(n) (DEFOG_BASE(n) + 0x00d4) ++#define DEFOG_ADDR_WEIGHT_B2__11_08(n) (DEFOG_BASE(n) + 0x00d8) ++#define DEFOG_ADDR_WEIGHT_B2__15_12(n) (DEFOG_BASE(n) + 0x00dc) ++#define DEFOG_ADDR_WEIGHT_B2__19_16(n) (DEFOG_BASE(n) + 0x00e0) ++#define DEFOG_ADDR_WEIGHT_B2__23_20(n) (DEFOG_BASE(n) + 0x00e4) ++#define DEFOG_ADDR_WEIGHT_B2__27_24(n) (DEFOG_BASE(n) + 0x00e8) ++#define DEFOG_ADDR_WEIGHT_B2__31_28(n) (DEFOG_BASE(n) + 0x00ec) ++#define DEFOG_ADDR_WEIGHT_C1__03_00(n) (DEFOG_BASE(n) + 0x00f0) ++#define DEFOG_ADDR_WEIGHT_C1__07_04(n) (DEFOG_BASE(n) + 0x00f4) ++#define DEFOG_ADDR_WEIGHT_C1__11_08(n) (DEFOG_BASE(n) + 0x00f8) ++#define DEFOG_ADDR_WEIGHT_C1__15_12(n) (DEFOG_BASE(n) + 0x00fc) ++#define DEFOG_ADDR_WEIGHT_C1__19_16(n) (DEFOG_BASE(n) + 0x0100) ++#define DEFOG_ADDR_WEIGHT_C1__23_20(n) (DEFOG_BASE(n) + 0x0104) ++#define DEFOG_ADDR_WEIGHT_C1__27_24(n) (DEFOG_BASE(n) + 0x0108) ++#define DEFOG_ADDR_WEIGHT_C1__31_28(n) (DEFOG_BASE(n) + 0x010c) ++#define DEFOG_ADDR_WEIGHT_C2__03_00(n) (DEFOG_BASE(n) + 0x0110) ++#define DEFOG_ADDR_WEIGHT_C2__07_04(n) (DEFOG_BASE(n) + 0x0114) ++#define DEFOG_ADDR_WEIGHT_C2__11_08(n) (DEFOG_BASE(n) + 0x0118) ++#define DEFOG_ADDR_WEIGHT_C2__15_12(n) (DEFOG_BASE(n) + 0x011c) ++#define DEFOG_ADDR_WEIGHT_C2__19_16(n) (DEFOG_BASE(n) + 0x0120) ++#define DEFOG_ADDR_WEIGHT_C2__23_20(n) (DEFOG_BASE(n) + 0x0124) ++#define DEFOG_ADDR_WEIGHT_C2__27_24(n) (DEFOG_BASE(n) + 0x0128) ++#define DEFOG_ADDR_WEIGHT_C2__31_28(n) (DEFOG_BASE(n) + 0x012c) ++#define DEFOG_ADDR_LC_SAT__03_00(n) (DEFOG_BASE(n) + 0x0130) ++#define DEFOG_ADDR_LC_SAT__07_04(n) (DEFOG_BASE(n) + 0x0134) ++#define DEFOG_ADDR_LC_SAT__11_08(n) (DEFOG_BASE(n) + 0x0138) ++#define DEFOG_ADDR_LC_SAT__15_12(n) (DEFOG_BASE(n) + 0x013c) ++#define DEFOG_ADDR_LC_SAT__19_16(n) (DEFOG_BASE(n) + 0x0140) ++#define DEFOG_ADDR_LC_SAT__23_20(n) (DEFOG_BASE(n) + 0x0144) ++#define DEFOG_ADDR_LC_SAT__27_24(n) (DEFOG_BASE(n) + 0x0148) ++#define DEFOG_ADDR_LC_SAT__31_28(n) (DEFOG_BASE(n) + 0x014c) ++#define DEFOG_ADDR_LC_VAL__03_00(n) (DEFOG_BASE(n) + 0x0150) ++#define DEFOG_ADDR_LC_VAL__07_04(n) (DEFOG_BASE(n) + 0x0154) ++#define DEFOG_ADDR_LC_VAL__11_08(n) (DEFOG_BASE(n) + 0x0158) ++#define DEFOG_ADDR_LC_VAL__15_12(n) (DEFOG_BASE(n) + 0x015c) ++#define DEFOG_ADDR_LC_VAL__19_16(n) (DEFOG_BASE(n) + 0x0160) ++#define DEFOG_ADDR_LC_VAL__23_20(n) (DEFOG_BASE(n) + 0x0164) ++#define DEFOG_ADDR_LC_VAL__27_24(n) (DEFOG_BASE(n) + 0x0168) ++#define DEFOG_ADDR_LC_VAL__31_28(n) (DEFOG_BASE(n) + 0x016c) ++#define DEFOG_ADDR_K_ADJUST__01_00(n) (DEFOG_BASE(n) + 0x0170) ++#define DEFOG_ADDR_K_ADJUST__03_02(n) (DEFOG_BASE(n) + 0x0174) ++#define DEFOG_ADDR_K_ADJUST__05_04(n) (DEFOG_BASE(n) + 0x0178) ++#define DEFOG_ADDR_K_ADJUST__07_06(n) (DEFOG_BASE(n) + 0x017c) ++#define DEFOG_ADDR_K_ADJUST__09_08(n) (DEFOG_BASE(n) + 0x0180) ++#define DEFOG_ADDR_K_ADJUST__11_10(n) (DEFOG_BASE(n) + 0x0184) ++#define DEFOG_ADDR_K_ADJUST__13_12(n) (DEFOG_BASE(n) + 0x0188) ++#define DEFOG_ADDR_K_ADJUST__15_14(n) (DEFOG_BASE(n) + 0x018c) ++#define DEFOG_ADDR_K_ADJUST__16_16(n) (DEFOG_BASE(n) + 0x0190) ++#define DEFOG_ADDR_SSJ_DIFF_THR__03_00(n) (DEFOG_BASE(n) + 0x0194) ++#define DEFOG_ADDR_SSJ_DIFF_THR__07_04(n) (DEFOG_BASE(n) + 0x0198) ++#define DEFOG_ADDR_SSJ_DIFF_THR__11_08(n) (DEFOG_BASE(n) + 0x019c) ++#define DEFOG_ADDR_SSJ_DIFF_THR__15_12(n) (DEFOG_BASE(n) + 0x01a0) ++#define DEFOG_ADDR_SSJ_DIFF_THR__19_16(n) (DEFOG_BASE(n) + 0x01a4) ++#define DEFOG_ADDR_SSJ_DIFF_THR__23_20(n) (DEFOG_BASE(n) + 0x01a8) ++#define DEFOG_ADDR_SSJ_DIFF_THR__27_24(n) (DEFOG_BASE(n) + 0x01ac) ++#define DEFOG_ADDR_SSJ_DIFF_THR__31_28(n) (DEFOG_BASE(n) + 0x01b0) ++#define DEFOG_ADDR_ADJUST_RED__03_00(n) (DEFOG_BASE(n) + 0x01b4) ++#define DEFOG_ADDR_ADJUST_RED__07_04(n) (DEFOG_BASE(n) + 0x01b8) ++#define DEFOG_ADDR_ADJUST_RED__11_08(n) (DEFOG_BASE(n) + 0x01bc) ++#define DEFOG_ADDR_ADJUST_RED__15_12(n) (DEFOG_BASE(n) + 0x01c0) ++#define DEFOG_ADDR_ADJUST_RED__16_16(n) (DEFOG_BASE(n) + 0x01c4) ++#define DEFOG_ADDR_ADJUST_GREEN__03_00(n) (DEFOG_BASE(n) + 0x01c8) ++#define DEFOG_ADDR_ADJUST_GREEN__07_04(n) (DEFOG_BASE(n) + 0x01cc) ++#define DEFOG_ADDR_ADJUST_GREEN__11_08(n) (DEFOG_BASE(n) + 0x01d0) ++#define DEFOG_ADDR_ADJUST_GREEN__15_12(n) (DEFOG_BASE(n) + 0x01d4) ++#define DEFOG_ADDR_ADJUST_GREEN__16_16(n) (DEFOG_BASE(n) + 0x01d8) ++#define DEFOG_ADDR_ADJUST_BLUE__03_00(n) (DEFOG_BASE(n) + 0x01dc) ++#define DEFOG_ADDR_ADJUST_BLUE__07_04(n) (DEFOG_BASE(n) + 0x01e0) ++#define DEFOG_ADDR_ADJUST_BLUE__11_08(n) (DEFOG_BASE(n) + 0x01e4) ++#define DEFOG_ADDR_ADJUST_BLUE__15_12(n) (DEFOG_BASE(n) + 0x01e8) ++#define DEFOG_ADDR_ADJUST_BLUE__16_16(n) (DEFOG_BASE(n) + 0x01ec) ++#define DEFOG_ADDR_ADJUST_YELLOW__03_00(n) (DEFOG_BASE(n) + 0x01f0) ++#define DEFOG_ADDR_ADJUST_YELLOW__07_04(n) (DEFOG_BASE(n) + 0x01f4) ++#define DEFOG_ADDR_ADJUST_YELLOW__11_08(n) (DEFOG_BASE(n) + 0x01f8) ++#define DEFOG_ADDR_ADJUST_YELLOW__15_12(n) (DEFOG_BASE(n) + 0x01fc) ++#define DEFOG_ADDR_ADJUST_YELLOW__16_16(n) (DEFOG_BASE(n) + 0x0200) ++#define DEFOG_ADDR_ADJUST_PURPLE__03_00(n) (DEFOG_BASE(n) + 0x0204) ++#define DEFOG_ADDR_ADJUST_PURPLE__07_04(n) (DEFOG_BASE(n) + 0x0208) ++#define DEFOG_ADDR_ADJUST_PURPLE__11_08(n) (DEFOG_BASE(n) + 0x020c) ++#define DEFOG_ADDR_ADJUST_PURPLE__15_12(n) (DEFOG_BASE(n) + 0x0210) ++#define DEFOG_ADDR_ADJUST_PURPLE__16_16(n) (DEFOG_BASE(n) + 0x0214) ++#define DEFOG_ADDR_ADJUST_CYAN__03_00(n) (DEFOG_BASE(n) + 0x0218) ++#define DEFOG_ADDR_ADJUST_CYAN__07_04(n) (DEFOG_BASE(n) + 0x021c) ++#define DEFOG_ADDR_ADJUST_CYAN__11_08(n) (DEFOG_BASE(n) + 0x0220) ++#define DEFOG_ADDR_ADJUST_CYAN__15_12(n) (DEFOG_BASE(n) + 0x0224) ++#define DEFOG_ADDR_ADJUST_CYAN__16_16(n) (DEFOG_BASE(n) + 0x0228) ++#define DEFOG_ADDR_DEFOG_DB__03_00(n) (DEFOG_BASE(n) + 0x022c) ++#define DEFOG_ADDR_DEFOG_DB__07_04(n) (DEFOG_BASE(n) + 0x0230) ++#define DEFOG_ADDR_DEFOG_DB__11_08(n) (DEFOG_BASE(n) + 0x0234) ++#define DEFOG_ADDR_DEFOG_DB__15_12(n) (DEFOG_BASE(n) + 0x0238) ++#define DEFOG_ADDR_DEFOG_DB__19_16(n) (DEFOG_BASE(n) + 0x023c) ++#define DEFOG_ADDR_DEFOG_DB__23_20(n) (DEFOG_BASE(n) + 0x0240) ++#define DEFOG_ADDR_DEFOG_DB__27_24(n) (DEFOG_BASE(n) + 0x0244) ++#define DEFOG_ADDR_DEFOG_DB__31_28(n) (DEFOG_BASE(n) + 0x0248) ++#define DEFOG_ADDR_FRAME_RATE(n) (DEFOG_BASE(n) + 0x0280) ++#define DEFOG_ADDR_STAT(n) (DEFOG_BASE(n) + 0x0284) ++#define DEFOG_ADDR_BANK_BUFF_NUM(n) (DEFOG_BASE(n) + 0x028c) ++#define DEFOG_ADDR_BANK_ADDR0_00_00(n) (DEFOG_BASE(n) + 0x0290) ++#define DEFOG_ADDR_BANK_ADDR0_01_01(n) (DEFOG_BASE(n) + 0x0294) ++#define DEFOG_ADDR_BANK_ADDR0_02_02(n) (DEFOG_BASE(n) + 0x0298) ++#define DEFOG_ADDR_BANK_ADDR0_03_03(n) (DEFOG_BASE(n) + 0x029c) ++#define DEFOG_ADDR_DEBUG_REG_FLAG(n) (DEFOG_BASE(n) + 0x02a0) ++#define DEFOG_ADDR_LUT_RD_SEL(n) (DEFOG_BASE(n) + 0x02a8) ++#define DEFOG_ADDR_LUT_SHD_EN(n) (DEFOG_BASE(n) + 0x02ac) ++#define DEFOG_ADDR_FRAME_ID0(n) (DEFOG_BASE(n) + 0x02b0) ++#define DEFOG_ADDR_FRAME_ADDR(n) (DEFOG_BASE(0) + 0x02b4 + 8 * n) ++#define DEFOG_ADDR_FRAME_ID1(n) (DEFOG_BASE(n) + 0x02b8) ++#define DEFOG_ADDR_DEBUG_SIGNAL_0(n) (DEFOG_BASE(n) + 0x0300) ++#define DEFOG_ADDR_DEBUG_SIGNAL_1(n) (DEFOG_BASE(n) + 0x0304) ++#define DEFOG_ADDR_DEBUG_SIGNAL_2(n) (DEFOG_BASE(n) + 0x0308) ++#define DEFOG_ADDR_DEBUG_SIGNAL_3(n) (DEFOG_BASE(n) + 0x030c) ++#define DEFOG_ADDR_DEBUG_SIGNAL_4(n) (DEFOG_BASE(n) + 0x0310) ++#define DEFOG_ADDR_DEBUG_SIGNAL_5(n) (DEFOG_BASE(n) + 0x0314) ++#define DEFOG_ADDR_DEBUG_SIGNAL_6(n) (DEFOG_BASE(n) + 0x0318) ++#define DEFOG_ADDR_DEBUG_SIGNAL_7(n) (DEFOG_BASE(n) + 0x031c) ++ ++//============================================================ ++// CSC ADDRESS ++//============================================================ ++#define CSC_ADDR_CTRL(n) (CSC_BASE(n) + 0x0000) ++#define CSC_ADDR_SUB(n) (CSC_BASE(n) + 0x0004) ++#define CSC_ADDR_PAR_0(n) (CSC_BASE(n) + 0x0010) ++#define CSC_ADDR_PAR_1(n) (CSC_BASE(n) + 0x0014) ++#define CSC_ADDR_PAR_2(n) (CSC_BASE(n) + 0x0018) ++#define CSC_ADDR_OFF_SET(n) (CSC_BASE(n) + 0x0020) ++#define CSC_ADDR_CLIP(n) (CSC_BASE(n) + 0x0030) ++#define CSC_ADDR_MODE(n) (CSC_BASE(n) + 0x0034) ++#define CSC_ADDR_DBG_0(n) (CSC_BASE(n) + 0x0040) ++#define CSC_ADDR_DBG_1(n) (CSC_BASE(n) + 0x0044) ++#define CSC_ADDR_DBG_2(n) (CSC_BASE(n) + 0x0048) ++#define CSC_ADDR_DBG_3(n) (CSC_BASE(n) + 0x004c) ++ ++//============================================================ ++// LCE ADDRESS ++//============================================================ ++#define MAIN_LCE_ADDR_ZONE_INFO1 (LCE0_BASE + 0x0000) ++#define MAIN_LCE_ADDR_ZONE_INFO2 (LCE0_BASE + 0x0004) ++#define MAIN_LCE_ADDR_AREA_SIZE1 (LCE0_BASE + 0x0008) ++#define MAIN_LCE_ADDR_AREA_SIZE2 (LCE0_BASE + 0x000c) ++#define MAIN_LCE_ADDR_RAM_INFO1 (LCE0_BASE + 0x0010) ++#define MAIN_LCE_ADDR_RAM_INFO2 (LCE0_BASE + 0x0014) ++#define MAIN_LCE_ADDR_DEBUG_0 (LCE0_BASE + 0x0018) ++#define MAIN_LCE_ADDR_DEBUG_1 (LCE0_BASE + 0x001c) ++#define MAIN_LCE_ADDR_DEBUG_2 (LCE0_BASE + 0x0020) ++#define MAIN_LCE_ADDR_DEBUG_3 (LCE0_BASE + 0x0024) ++#define MAIN_LCE_ADDR_DEBUG_4 (LCE0_BASE + 0x0028) ++#define MAIN_LCE_ADDR_DEBUG_5 (LCE0_BASE + 0x002c) ++#define MAIN_LCE_ADDR_DEBUG_6 (LCE0_BASE + 0x0030) ++#define MAIN_LCE_ADDR_DEBUG_7 (LCE0_BASE + 0x0034) ++#define MAIN_LCE_ADDR_DEBUG_8 (LCE0_BASE + 0x0038) ++#define MAIN_LCE_ADDR_DEBUG_9 (LCE0_BASE + 0x003c) ++#define MAIN_LCE_ADDR_DEBUG_10 (LCE0_BASE + 0x0040) ++#define MAIN_LCE_ADDR_DEBUG_11 (LCE0_BASE + 0x0044) ++#define MAIN_LCE_ADDR_DEBUG_12 (LCE0_BASE + 0x0048) ++#define MAIN_LCE_ADDR_DEBUG_13 (LCE0_BASE + 0x004c) ++#define MAIN_LCE_ADDR_PARSTORE_CLR (LCE0_BASE + 0x0080) ++#define MAIN_LCE_ADDR_PARSTORE_DONE (LCE0_BASE + 0x0084) ++#define MAIN_LCE_ADDR_PARSTORE_RBSEL (LCE0_BASE + 0x0088) ++ ++#define SEC_LCE_ADDR_ZONE_INFO1 (LCE1_BASE + 0x0000) ++#define SEC_LCE_ADDR_ZONE_INFO2 (LCE1_BASE + 0x0004) ++#define SEC_LCE_ADDR_AREA_SIZE1 (LCE1_BASE + 0x0008) ++#define SEC_LCE_ADDR_AREA_SIZE2 (LCE1_BASE + 0x000c) ++#define SEC_LCE_ADDR_RAM_INFO1 (LCE1_BASE + 0x0010) ++#define SEC_LCE_ADDR_RAM_INFO2 (LCE1_BASE + 0x0014) ++#define SEC_LCE_ADDR_DEBUG_0 (LCE1_BASE + 0x0018) ++#define SEC_LCE_ADDR_DEBUG_1 (LCE1_BASE + 0x001c) ++#define SEC_LCE_ADDR_DEBUG_2 (LCE1_BASE + 0x0020) ++#define SEC_LCE_ADDR_DEBUG_3 (LCE1_BASE + 0x0024) ++#define SEC_LCE_ADDR_DEBUG_4 (LCE1_BASE + 0x0028) ++#define SEC_LCE_ADDR_DEBUG_5 (LCE1_BASE + 0x002c) ++#define SEC_LCE_ADDR_DEBUG_6 (LCE1_BASE + 0x0030) ++#define SEC_LCE_ADDR_DEBUG_7 (LCE1_BASE + 0x0034) ++#define SEC_LCE_ADDR_DEBUG_8 (LCE1_BASE + 0x0038) ++#define SEC_LCE_ADDR_DEBUG_9 (LCE1_BASE + 0x003c) ++#define SEC_LCE_ADDR_DEBUG_10 (LCE1_BASE + 0x0040) ++#define SEC_LCE_ADDR_DEBUG_11 (LCE1_BASE + 0x0044) ++#define SEC_LCE_ADDR_DEBUG_12 (LCE1_BASE + 0x0048) ++#define SEC_LCE_ADDR_DEBUG_13 (LCE1_BASE + 0x004c) ++#define SEC_LCE_ADDR_PARSTORE_CLR (LCE1_BASE + 0x0080) ++#define SEC_LCE_ADDR_PARSTORE_DONE (LCE1_BASE + 0x0084) ++#define SEC_LCE_ADDR_PARSTORE_RBSEL (LCE1_BASE + 0x0088) ++ ++//============================================================ ++// MDNS ADDRESS ++//============================================================ ++#define MDNS_ADDR_VERSION(n) (MDNS_BASE(n) + 0x0000) ++#define MDNS_ADDR_SHD_CTRL(n) (MDNS_BASE(n) + 0x0004) ++#define MDNS_ADDR_START(n) (MDNS_BASE(n) + 0x0008) ++#define MDNS_ADDR_OUTSEL(n) (MDNS_BASE(n) + 0x000c) ++#define MDNS_ADDR_MD_EN(n) (MDNS_BASE(n) + 0x0020) ++#define MDNS_ADDR_FUNC_EN(n) (MDNS_BASE(n) + 0x0024) ++#define MDNS_ADDR_YREF_ADDR(n) (MDNS_BASE(n) + 0x0040) ++#define MDNS_ADDR_YREF_STRIDE(n) (MDNS_BASE(n) + 0x0044) ++#define MDNS_ADDR_CREF_ADDR(n) (MDNS_BASE(n) + 0x0048) ++#define MDNS_ADDR_CREF_STRIDE(n) (MDNS_BASE(n) + 0x004c) ++#define MDNS_ADDR_BSN_ADDR(n) (MDNS_BASE(n) + 0x0050) ++#define MDNS_ADDR_BSN_STRIDE(n) (MDNS_BASE(n) + 0x0054) ++#define MDNS_ADDR_ASS_ADDR(n) (MDNS_BASE(n) + 0x0058) ++#define MDNS_ADDR_ASS_STRIDE(n) (MDNS_BASE(n) + 0x005c) ++#define MDNS_ADDR_LYN_ADDR(n) (MDNS_BASE(n) + 0x0060) ++#define MDNS_ADDR_LYN_STRIDE(n) (MDNS_BASE(n) + 0x0064) ++#define MDNS_ADDR_YTTPHASE(n) (MDNS_BASE(n) + 0x0068) ++#define MDNS_ADDR_CTTPHASE(n) (MDNS_BASE(n) + 0x006c) ++#define MDNS_ADDR_YRESENDPOINT(n) (MDNS_BASE(n) + 0x0070) ++#define MDNS_ADDR_CRESENDPOINT(n) (MDNS_BASE(n) + 0x0074) ++#define MDNS_ADDR_BSNBLKSIZE(n) (MDNS_BASE(n) + 0x0100) ++#define MDNS_ADDR_BSNPOS(n) (MDNS_BASE(n) + 0x0104) ++#define MDNS_ADDR_BSNIMGSIZE(n) (MDNS_BASE(n) + 0x0108) ++#define MDNS_ADDR_BSNNUM(n) (MDNS_BASE(n) + 0x010c) ++#define MDNS_ADDR_BSNLINPAR(n) (MDNS_BASE(n) + 0x0110) ++#define MDNS_ADDR_BSNTHRES(n) (MDNS_BASE(n) + 0x0114) ++#define MDNS_ADDR_PBV0THRES(n) (MDNS_BASE(n) + 0x0118) ++#define MDNS_ADDR_PBV1THRES(n) (MDNS_BASE(n) + 0x011c) ++#define MDNS_ADDR_CNRADJPAR0(n) (MDNS_BASE(n) + 0x0120) ++#define MDNS_ADDR_LUMAADJPAR0(n) (MDNS_BASE(n) + 0x0124) ++#define MDNS_ADDR_LUMAADJPAR1(n) (MDNS_BASE(n) + 0x0128) ++#define MDNS_ADDR_LUMAADJPAR2(n) (MDNS_BASE(n) + 0x012c) ++#define MDNS_ADDR_EDGEADJPAR0(n) (MDNS_BASE(n) + 0x0130) ++#define MDNS_ADDR_EDGEADJPAR1(n) (MDNS_BASE(n) + 0x0134) ++#define MDNS_ADDR_EDGEADJPAR2(n) (MDNS_BASE(n) + 0x0138) ++#define MDNS_ADDR_SADTHRES(n) (MDNS_BASE(n) + 0x013c) ++#define MDNS_ADDR_LIMREFWEI(n) (MDNS_BASE(n) + 0x0150) ++#define MDNS_ADDR_BSNREFWEIPAR0(n) (MDNS_BASE(n) + 0x0154) ++#define MDNS_ADDR_BSNREFWEIPAR1(n) (MDNS_BASE(n) + 0x0158) ++#define MDNS_ADDR_PBV0REFWEIPAR0(n) (MDNS_BASE(n) + 0x015c) ++#define MDNS_ADDR_PBV0REFWEIPAR1(n) (MDNS_BASE(n) + 0x0160) ++#define MDNS_ADDR_PBV1REFWEIPAR0(n) (MDNS_BASE(n) + 0x0164) ++#define MDNS_ADDR_PBV1REFWEIPAR1(n) (MDNS_BASE(n) + 0x0168) ++#define MDNS_ADDR_PSNREFWEI(n) (MDNS_BASE(n) + 0x016c) ++#define MDNS_ADDR_PBVFUSWEIPAR0(n) (MDNS_BASE(n) + 0x0170) ++#define MDNS_ADDR_PBVFUSWEIPAR1(n) (MDNS_BASE(n) + 0x0174) ++#define MDNS_ADDR_PBVFUSWEIPAR2(n) (MDNS_BASE(n) + 0x0178) ++#define MDNS_ADDR_BSNFUSWEIPAR0(n) (MDNS_BASE(n) + 0x017c) ++#define MDNS_ADDR_BSNFUSWEIPAR1(n) (MDNS_BASE(n) + 0x0180) ++#define MDNS_ADDR_BSNFUSWEIPAR2(n) (MDNS_BASE(n) + 0x0184) ++#define MDNS_ADDR_LUMAFUSWEIPAR0(n) (MDNS_BASE(n) + 0x0188) ++#define MDNS_ADDR_LUMAFUSWEIPAR1(n) (MDNS_BASE(n) + 0x018c) ++#define MDNS_ADDR_LUMAFUSWEIPAR2(n) (MDNS_BASE(n) + 0x0190) ++#define MDNS_ADDR_PSNFUSWEI(n) (MDNS_BASE(n) + 0x0194) ++#define MDNS_ADDR_CNRFUSWEI(n) (MDNS_BASE(n) + 0x0198) ++#define MDNS_ADDR_BGMWEIMINPAR0(n) (MDNS_BASE(n) + 0x01b0) ++#define MDNS_ADDR_BGMWEIMINPAR1(n) (MDNS_BASE(n) + 0x01b4) ++#define MDNS_ADDR_BGMWEIMINPAR2(n) (MDNS_BASE(n) + 0x01b8) ++#define MDNS_ADDR_STILLSTAGEPAR0(n) (MDNS_BASE(n) + 0x01bc) ++#define MDNS_ADDR_STILLSTAGEPAR1(n) (MDNS_BASE(n) + 0x01c0) ++#define MDNS_ADDR_EDGEVALPAR0(n) (MDNS_BASE(n) + 0x01c4) ++#define MDNS_ADDR_EDGEVALPAR1(n) (MDNS_BASE(n) + 0x01c8) ++#define MDNS_ADDR_EDGEVALPAR2(n) (MDNS_BASE(n) + 0x01cc) ++#define MDNS_ADDR_EDGEVALPAR3(n) (MDNS_BASE(n) + 0x01d0) ++#define MDNS_ADDR_EDGEVALPAR4(n) (MDNS_BASE(n) + 0x01d4) ++#define MDNS_ADDR_CBMFUSWEIPAR0(n) (MDNS_BASE(n) + 0x01d8) ++#define MDNS_ADDR_CBMFUSWEIPAR1(n) (MDNS_BASE(n) + 0x01dc) ++#define MDNS_ADDR_CBMFUSWEIPAR2(n) (MDNS_BASE(n) + 0x01e0) ++#define MDNS_ADDR_RBMFUSWEIPAR0(n) (MDNS_BASE(n) + 0x01e4) ++#define MDNS_ADDR_RBMFUSWEIPAR1(n) (MDNS_BASE(n) + 0x01e8) ++#define MDNS_ADDR_RBMFUSWEIPAR2(n) (MDNS_BASE(n) + 0x01ec) ++#define MDNS_ADDR_SPATHRES(n) (MDNS_BASE(n) + 0x01f0) ++#define MDNS_ADDR_BGMFUSWEIPAR0(n) (MDNS_BASE(n) + 0x01f4) ++#define MDNS_ADDR_BGMFUSWEIPAR1(n) (MDNS_BASE(n) + 0x01f8) ++#define MDNS_ADDR_CURSPAFUSWEIPAR0(n) (MDNS_BASE(n) + 0x01fc) ++#define MDNS_ADDR_CURSPAFUSWEIPAR1(n) (MDNS_BASE(n) + 0x0200) ++#define MDNS_ADDR_REFSPAFUSWEIPAR0(n) (MDNS_BASE(n) + 0x0204) ++#define MDNS_ADDR_REFSPAFUSWEIPAR1(n) (MDNS_BASE(n) + 0x0208) ++#define MDNS_ADDR_REFRECALWEI(n) (MDNS_BASE(n) + 0x020c) ++#define MDNS_ADDR_IIRPAR0(n) (MDNS_BASE(n) + 0x0210) ++#define MDNS_ADDR_IIRPAR1(n) (MDNS_BASE(n) + 0x0214) ++#define MDNS_ADDR_IIRPAR2(n) (MDNS_BASE(n) + 0x0218) ++#define MDNS_ADDR_CSADTHRES(n) (MDNS_BASE(n) + 0x0230) ++#define MDNS_ADDR_CLIMREFWEI(n) (MDNS_BASE(n) + 0x0234) ++#define MDNS_ADDR_LYNWEIMINPAR0(n) (MDNS_BASE(n) + 0x0238) ++#define MDNS_ADDR_LYNWEIMINPAR1(n) (MDNS_BASE(n) + 0x023c) ++#define MDNS_ADDR_LYNWEIMINPAR2(n) (MDNS_BASE(n) + 0x0240) ++#define MDNS_ADDR_LYNFUSWEIPAR0(n) (MDNS_BASE(n) + 0x0244) ++#define MDNS_ADDR_LYNFUSWEIPAR1(n) (MDNS_BASE(n) + 0x0248) ++#define MDNS_ADDR_CCBMFUSWEIPAR0(n) (MDNS_BASE(n) + 0x024c) ++#define MDNS_ADDR_CCBMFUSWEIPAR1(n) (MDNS_BASE(n) + 0x0250) ++#define MDNS_ADDR_CCBMFUSWEIPAR2(n) (MDNS_BASE(n) + 0x0254) ++#define MDNS_ADDR_CRBMFUSWEIPAR0(n) (MDNS_BASE(n) + 0x0258) ++#define MDNS_ADDR_CRBMFUSWEIPAR1(n) (MDNS_BASE(n) + 0x025c) ++#define MDNS_ADDR_CRBMFUSWEIPAR2(n) (MDNS_BASE(n) + 0x0260) ++#define MDNS_ADDR_CCURSPAFUSWEIPAR0(n) (MDNS_BASE(n) + 0x0264) ++#define MDNS_ADDR_CCURSPAFUSWEIPAR1(n) (MDNS_BASE(n) + 0x0268) ++#define MDNS_ADDR_CREFSPAFUSWEIPAR0(n) (MDNS_BASE(n) + 0x026c) ++#define MDNS_ADDR_CREFSPAFUSWEIPAR1(n) (MDNS_BASE(n) + 0x0270) ++#define MDNS_ADDR_CREFRECALWEI(n) (MDNS_BASE(n) + 0x0274) ++#define MDNS_ADDR_CIIRPAR0(n) (MDNS_BASE(n) + 0x0278) ++#define MDNS_ADDR_CIIRPAR1(n) (MDNS_BASE(n) + 0x027c) ++#define MDNS_ADDR_CIIRPAR2(n) (MDNS_BASE(n) + 0x0280) ++#define MDNS_ADDR_DEPURPLEPAR0(n) (MDNS_BASE(n) + 0x02a0) ++#define MDNS_ADDR_DEPURPLEPAR1(n) (MDNS_BASE(n) + 0x02a4) ++#define MDNS_ADDR_DEPURPLEPAR2(n) (MDNS_BASE(n) + 0x02a8) ++#define MDNS_ADDR_DEPURPLEPAR3(n) (MDNS_BASE(n) + 0x02ac) ++#define MDNS_ADDR_DBGSIG0(n) (MDNS_BASE(n) + 0x0300) ++#define MDNS_ADDR_DBGSIG1(n) (MDNS_BASE(n) + 0x0304) ++#define MDNS_ADDR_DBGSIG2(n) (MDNS_BASE(n) + 0x0308) ++#define MDNS_ADDR_DBGSIG3(n) (MDNS_BASE(n) + 0x030c) ++#define MDNS_ADDR_DBGSIG4(n) (MDNS_BASE(n) + 0x0310) ++#define MDNS_ADDR_DBGSIG5(n) (MDNS_BASE(n) + 0x0314) ++#define MDNS_ADDR_DBGSIG6(n) (MDNS_BASE(n) + 0x0318) ++#define MDNS_ADDR_DBGSIG7(n) (MDNS_BASE(n) + 0x031c) ++#define MDNS_ADDR_DBGSIG8(n) (MDNS_BASE(n) + 0x0320) ++#define MDNS_ADDR_DBGSIG9(n) (MDNS_BASE(n) + 0x0324) ++#define MDNS_ADDR_DBGSIG10(n) (MDNS_BASE(n) + 0x0328) ++#define MDNS_ADDR_DBGSIG11(n) (MDNS_BASE(n) + 0x032c) ++#define MDNS_ADDR_DBGSIG12(n) (MDNS_BASE(n) + 0x0330) ++#define MDNS_ADDR_DBGSIG13(n) (MDNS_BASE(n) + 0x0334) ++#define MDNS_ADDR_DBGSIG14(n) (MDNS_BASE(n) + 0x0338) ++#define MDNS_ADDR_DBGSIG15(n) (MDNS_BASE(n) + 0x033c) ++#define MDNS_ADDR_DBGSIG16(n) (MDNS_BASE(n) + 0x0340) ++#define MDNS_ADDR_DBGSIG17(n) (MDNS_BASE(n) + 0x0344) ++#define MDNS_ADDR_DBGSIG18(n) (MDNS_BASE(n) + 0x0348) ++#define MDNS_ADDR_DBGSIG19(n) (MDNS_BASE(n) + 0x034c) ++#define MDNS_ADDR_DBGSIG20(n) (MDNS_BASE(n) + 0x0350) ++#define MDNS_ADDR_DBGSIG21(n) (MDNS_BASE(n) + 0x0354) ++#define MDNS_ADDR_DBGSIG22(n) (MDNS_BASE(n) + 0x0358) ++#define MDNS_ADDR_DBGSIG23(n) (MDNS_BASE(n) + 0x035c) ++#define MDNS_ADDR_DBGSIG24(n) (MDNS_BASE(n) + 0x0360) ++#define MDNS_ADDR_DBGSIG25(n) (MDNS_BASE(n) + 0x0364) ++#define MDNS_ADDR_DBGSIG26(n) (MDNS_BASE(n) + 0x0368) ++#define MDNS_ADDR_DBGSIG27(n) (MDNS_BASE(n) + 0x036c) ++#define MDNS_ADDR_DBGSIG28(n) (MDNS_BASE(n) + 0x0370) ++#define MDNS_ADDR_DBGSIG29(n) (MDNS_BASE(n) + 0x0374) ++#define MDNS_ADDR_DBGSIG30(n) (MDNS_BASE(n) + 0x0378) ++#define MDNS_ADDR_DBGSIG31(n) (MDNS_BASE(n) + 0x037c) ++#define MDNS_ADDR_DBGSIG32(n) (MDNS_BASE(n) + 0x0380) ++#define MDNS_ADDR_DBGSIG33(n) (MDNS_BASE(n) + 0x0384) ++#define MDNS_ADDR_DBGSIG34(n) (MDNS_BASE(n) + 0x0388) ++#define MDNS_ADDR_DBGSIG35(n) (MDNS_BASE(n) + 0x038c) ++#define MDNS_ADDR_DBGSIG36(n) (MDNS_BASE(n) + 0x0390) ++#define MDNS_ADDR_DBGSIG37(n) (MDNS_BASE(n) + 0x0394) ++#define MDNS_ADDR_DBGSIG38(n) (MDNS_BASE(n) + 0x0398) ++#define MDNS_ADDR_DBGSIG39(n) (MDNS_BASE(n) + 0x039c) ++#define MDNS_ADDR_DBGSIG40(n) (MDNS_BASE(n) + 0x03a0) ++#define MDNS_ADDR_DBGSIG41(n) (MDNS_BASE(n) + 0x03a4) ++#define MDNS_ADDR_DBGSIG42(n) (MDNS_BASE(n) + 0x03a8) ++#define MDNS_ADDR_DBGSIG43(n) (MDNS_BASE(n) + 0x03ac) ++#define MDNS_ADDR_DBGSIG44(n) (MDNS_BASE(n) + 0x03b0) ++#define MDNS_ADDR_DBGSIG45(n) (MDNS_BASE(n) + 0x03b4) ++#define MDNS_ADDR_DBGSIG46(n) (MDNS_BASE(n) + 0x03b8) ++#define MDNS_ADDR_DBGSIG47(n) (MDNS_BASE(n) + 0x03bc) ++#define MDNS_ADDR_DBGSIG48(n) (MDNS_BASE(n) + 0x03c0) ++#define MDNS_ADDR_DBGSIG49(n) (MDNS_BASE(n) + 0x03c4) ++#define MDNS_ADDR_DBGSIG50(n) (MDNS_BASE(n) + 0x03c8) ++#define MDNS_ADDR_DBGSIG51(n) (MDNS_BASE(n) + 0x03cc) ++#define MDNS_ADDR_DBGSIG52(n) (MDNS_BASE(n) + 0x03d0) ++#define MDNS_ADDR_DBGSIG53(n) (MDNS_BASE(n) + 0x03d4) ++#define MDNS_ADDR_DBGSIG54(n) (MDNS_BASE(n) + 0x03d8) ++#define MDNS_ADDR_DBGSIG55(n) (MDNS_BASE(n) + 0x03dc) ++#define MDNS_ADDR_DBGSIG56(n) (MDNS_BASE(n) + 0x03e0) ++#define MDNS_ADDR_DBGSIG57(n) (MDNS_BASE(n) + 0x03e4) ++#define MDNS_ADDR_DBGSIG58(n) (MDNS_BASE(n) + 0x03e8) ++#define MDNS_ADDR_DBGSIG59(n) (MDNS_BASE(n) + 0x03ec) ++#define MDNS_ADDR_DBGSIG60(n) (MDNS_BASE(n) + 0x03f0) ++#define MDNS_ADDR_DBGSIG61(n) (MDNS_BASE(n) + 0x03f4) ++#define MDNS_ADDR_DBGSIG62(n) (MDNS_BASE(n) + 0x03f8) ++#define MDNS_ADDR_DBGSIG63(n) (MDNS_BASE(n) + 0x03fc) ++#define MDNS_ADDR_DBGSIG64(n) (MDNS_BASE(n) + 0x0400) ++#define MDNS_ADDR_DBGSIG65(n) (MDNS_BASE(n) + 0x0404) ++#define MDNS_ADDR_DBGSIG66(n) (MDNS_BASE(n) + 0x0408) ++#define MDNS_ADDR_DBGSIG67(n) (MDNS_BASE(n) + 0x040c) ++ ++//============================================================ ++// YDNS ADDRESS ++//============================================================ ++#define YDNS_ADDR_VERSION(n) (YDNS_BASE(n) + 0x0000) ++#define YDNS_ADDR_SHD_CTRL(n) (YDNS_BASE(n) + 0x0004) ++#define YDNS_ADDR_OUTSEL(n) (YDNS_BASE(n) + 0x0008) ++#define YDNS_ADDR_MD_EN(n) (YDNS_BASE(n) + 0x0010) ++#define YDNS_ADDR_YEDGEPAR(n) (YDNS_BASE(n) + 0x0020) ++#define YDNS_ADDR_YFUSWEIPAR0(n) (YDNS_BASE(n) + 0x0024) ++#define YDNS_ADDR_YFUSWEIPAR1(n) (YDNS_BASE(n) + 0x0028) ++#define YDNS_ADDR_CIIRPAR(n) (YDNS_BASE(n) + 0x0040) ++#define YDNS_ADDR_CFUSWEIPAR0(n) (YDNS_BASE(n) + 0x0044) ++#define YDNS_ADDR_CFUSWEIPAR1(n) (YDNS_BASE(n) + 0x0048) ++#define YDNS_ADDR_DBGSIG0(n) (YDNS_BASE(n) + 0x0060) ++#define YDNS_ADDR_DBGSIG1(n) (YDNS_BASE(n) + 0x0064) ++#define YDNS_ADDR_DBGSIG2(n) (YDNS_BASE(n) + 0x0068) ++#define YDNS_ADDR_DBGSIG3(n) (YDNS_BASE(n) + 0x006c) ++#define YDNS_ADDR_DBGSIG4(n) (YDNS_BASE(n) + 0x0070) ++#define YDNS_ADDR_DBGSIG5(n) (YDNS_BASE(n) + 0x0074) ++#define YDNS_ADDR_DBGSIG6(n) (YDNS_BASE(n) + 0x0078) ++#define YDNS_ADDR_DBGSIG7(n) (YDNS_BASE(n) + 0x007c) ++#define YDNS_ADDR_DBGSIG8(n) (YDNS_BASE(n) + 0x0080) ++ ++//============================================================ ++// CDNS ADDRESS ++//============================================================ ++#define CDNS_ADDR_VERSION(n) (CDNS_BASE(n) + 0x0000) ++#define CDNS_ADDR_SHD_CTRL(n) (CDNS_BASE(n) + 0x0004) ++#define CDNS_ADDR_OUTSEL(n) (CDNS_BASE(n) + 0x0008) ++#define CDNS_ADDR_STDDIVOPT(n) (CDNS_BASE(n) + 0x0010) ++#define CDNS_ADDR_SPEC0PAR(n) (CDNS_BASE(n) + 0x0020) ++#define CDNS_ADDR_SPEC1PAR(n) (CDNS_BASE(n) + 0x0024) ++#define CDNS_ADDR_SPEC2PAR(n) (CDNS_BASE(n) + 0x0028) ++#define CDNS_ADDR_SPEC3PAR(n) (CDNS_BASE(n) + 0x002c) ++#define CDNS_ADDR_SPEC4PAR(n) (CDNS_BASE(n) + 0x0030) ++#define CDNS_ADDR_SPEC5PAR(n) (CDNS_BASE(n) + 0x0034) ++#define CDNS_ADDR_SPEC6PAR(n) (CDNS_BASE(n) + 0x0038) ++#define CDNS_ADDR_SPEC7PAR(n) (CDNS_BASE(n) + 0x003c) ++#define CDNS_ADDR_IIRWEIGHT(n) (CDNS_BASE(n) + 0x0040) ++#define CDNS_ADDR_FUSWEIGHT(n) (CDNS_BASE(n) + 0x0050) ++#define CDNS_ADDR_DBGSIG0(n) (CDNS_BASE(n) + 0x0060) ++#define CDNS_ADDR_DBGSIG1(n) (CDNS_BASE(n) + 0x0064) ++#define CDNS_ADDR_DBGSIG2(n) (CDNS_BASE(n) + 0x0068) ++#define CDNS_ADDR_DBGSIG3(n) (CDNS_BASE(n) + 0x006c) ++#define CDNS_ADDR_DBGSIG4(n) (CDNS_BASE(n) + 0x0070) ++#define CDNS_ADDR_DBGSIG5(n) (CDNS_BASE(n) + 0x0074) ++#define CDNS_ADDR_DBGSIG6(n) (CDNS_BASE(n) + 0x0078) ++ ++//============================================================ ++// BCSH ADDRESS ++//============================================================ ++#define MAIN_BCSH_ADDR_CLIP_Y0_LIMIT (BCSH0_BASE + 0x0000) ++#define MAIN_BCSH_ADDR_CLIP_Y1_LIMIT (BCSH0_BASE + 0x0004) ++#define MAIN_BCSH_ADDR_CLIP_Y2_LIMIT (BCSH0_BASE + 0x0008) ++#define MAIN_BCSH_ADDR_CLIP_C0_LIMIT (BCSH0_BASE + 0x000c) ++#define MAIN_BCSH_ADDR_CLIP_C1_LIMIT (BCSH0_BASE + 0x0010) ++#define MAIN_BCSH_ADDR_CLIP_C2_LIMIT (BCSH0_BASE + 0x0014) ++#define MAIN_BCSH_ADDR_OFFSET_Y (BCSH0_BASE + 0x0018) ++#define MAIN_BCSH_ADDR_OFFSET_U (BCSH0_BASE + 0x001c) ++#define MAIN_BCSH_ADDR_OFFSET_V (BCSH0_BASE + 0x0020) ++#define MAIN_BCSH_ADDR_MATRIX_COEF00 (BCSH0_BASE + 0x0024) ++#define MAIN_BCSH_ADDR_MATRIX_COEF02 (BCSH0_BASE + 0x0028) ++#define MAIN_BCSH_ADDR_MATRIX_COEF10 (BCSH0_BASE + 0x002c) ++#define MAIN_BCSH_ADDR_MATRIX_COEF12 (BCSH0_BASE + 0x0030) ++#define MAIN_BCSH_ADDR_MATRIX_COEF20 (BCSH0_BASE + 0x0034) ++#define MAIN_BCSH_ADDR_MATRIX_COEF22 (BCSH0_BASE + 0x0038) ++#define MAIN_BCSH_ADDR_PRO_DK (BCSH0_BASE + 0x003c) ++#define MAIN_BCSH_ADDR_PRO_DK_TH (BCSH0_BASE + 0x0040) ++#define MAIN_BCSH_ADDR_PRO_BR (BCSH0_BASE + 0x0044) ++#define MAIN_BCSH_ADDR_PRO_BR_TH (BCSH0_BASE + 0x0048) ++#define MAIN_BCSH_ADDR_PRO_SAT (BCSH0_BASE + 0x004c) ++#define MAIN_BCSH_ADDR_PRO_SAT_TH (BCSH0_BASE + 0x0050) ++#define MAIN_BCSH_ADDR_CON_ENABLE (BCSH0_BASE + 0x0054) ++#define MAIN_BCSH_ADDR_CON_S1 (BCSH0_BASE + 0x0058) ++#define MAIN_BCSH_ADDR_CON_X (BCSH0_BASE + 0x005c) ++#define MAIN_BCSH_ADDR_CON_Y (BCSH0_BASE + 0x0060) ++#define MAIN_BCSH_ADDR_SAT_ENABLE (BCSH0_BASE + 0x0064) ++#define MAIN_BCSH_ADDR_SAT_TH (BCSH0_BASE + 0x0068) ++#define MAIN_BCSH_ADDR_SAT_STREN_S (BCSH0_BASE + 0x006c) ++#define MAIN_BCSH_ADDR_SAT_STREN_M (BCSH0_BASE + 0x0070) ++#define MAIN_BCSH_ADDR_DEBUG_0 (BCSH0_BASE + 0x0074) ++#define MAIN_BCSH_ADDR_DEBUG_1 (BCSH0_BASE + 0x0078) ++#define MAIN_BCSH_ADDR_DEBUG_2 (BCSH0_BASE + 0x007c) ++#define MAIN_BCSH_ADDR_DEBUG_3 (BCSH0_BASE + 0x0080) ++#define MAIN_BCSH_ADDR_DEBUG_4 (BCSH0_BASE + 0x0084) ++#define MAIN_BCSH_ADDR_DEBUG_5 (BCSH0_BASE + 0x0088) ++#define MAIN_BCSH_ADDR_DEBUG_6 (BCSH0_BASE + 0x008c) ++#define MAIN_BCSH_ADDR_DEBUG_7 (BCSH0_BASE + 0x0090) ++#define MAIN_BCSH_ADDR_DEBUG_8 (BCSH0_BASE + 0x0094) ++ ++#define SEC_BCSH_ADDR_CLIP_Y0_LIMIT (BCSH1_BASE + 0x0000) ++#define SEC_BCSH_ADDR_CLIP_Y1_LIMIT (BCSH1_BASE + 0x0004) ++#define SEC_BCSH_ADDR_CLIP_Y2_LIMIT (BCSH1_BASE + 0x0008) ++#define SEC_BCSH_ADDR_CLIP_C0_LIMIT (BCSH1_BASE + 0x000c) ++#define SEC_BCSH_ADDR_CLIP_C1_LIMIT (BCSH1_BASE + 0x0010) ++#define SEC_BCSH_ADDR_CLIP_C2_LIMIT (BCSH1_BASE + 0x0014) ++#define SEC_BCSH_ADDR_OFFSET_Y (BCSH1_BASE + 0x0018) ++#define SEC_BCSH_ADDR_OFFSET_U (BCSH1_BASE + 0x001c) ++#define SEC_BCSH_ADDR_OFFSET_V (BCSH1_BASE + 0x0020) ++#define SEC_BCSH_ADDR_MATRIX_COEF00 (BCSH1_BASE + 0x0024) ++#define SEC_BCSH_ADDR_MATRIX_COEF02 (BCSH1_BASE + 0x0028) ++#define SEC_BCSH_ADDR_MATRIX_COEF10 (BCSH1_BASE + 0x002c) ++#define SEC_BCSH_ADDR_MATRIX_COEF12 (BCSH1_BASE + 0x0030) ++#define SEC_BCSH_ADDR_MATRIX_COEF20 (BCSH1_BASE + 0x0034) ++#define SEC_BCSH_ADDR_MATRIX_COEF22 (BCSH1_BASE + 0x0038) ++#define SEC_BCSH_ADDR_PRO_DK (BCSH1_BASE + 0x003c) ++#define SEC_BCSH_ADDR_PRO_DK_TH (BCSH1_BASE + 0x0040) ++#define SEC_BCSH_ADDR_PRO_BR (BCSH1_BASE + 0x0044) ++#define SEC_BCSH_ADDR_PRO_BR_TH (BCSH1_BASE + 0x0048) ++#define SEC_BCSH_ADDR_PRO_SAT (BCSH1_BASE + 0x004c) ++#define SEC_BCSH_ADDR_PRO_SAT_TH (BCSH1_BASE + 0x0050) ++#define SEC_BCSH_ADDR_CON_ENABLE (BCSH1_BASE + 0x0054) ++#define SEC_BCSH_ADDR_CON_S1 (BCSH1_BASE + 0x0058) ++#define SEC_BCSH_ADDR_CON_X (BCSH1_BASE + 0x005c) ++#define SEC_BCSH_ADDR_CON_Y (BCSH1_BASE + 0x0060) ++#define SEC_BCSH_ADDR_SAT_ENABLE (BCSH1_BASE + 0x0064) ++#define SEC_BCSH_ADDR_SAT_TH (BCSH1_BASE + 0x0068) ++#define SEC_BCSH_ADDR_SAT_STREN_S (BCSH1_BASE + 0x006c) ++#define SEC_BCSH_ADDR_SAT_STREN_M (BCSH1_BASE + 0x0070) ++#define SEC_BCSH_ADDR_DEBUG_0 (BCSH1_BASE + 0x0074) ++#define SEC_BCSH_ADDR_DEBUG_1 (BCSH1_BASE + 0x0078) ++#define SEC_BCSH_ADDR_DEBUG_2 (BCSH1_BASE + 0x007c) ++#define SEC_BCSH_ADDR_DEBUG_3 (BCSH1_BASE + 0x0080) ++#define SEC_BCSH_ADDR_DEBUG_4 (BCSH1_BASE + 0x0084) ++#define SEC_BCSH_ADDR_DEBUG_5 (BCSH1_BASE + 0x0088) ++#define SEC_BCSH_ADDR_DEBUG_6 (BCSH1_BASE + 0x008c) ++#define SEC_BCSH_ADDR_DEBUG_7 (BCSH1_BASE + 0x0090) ++#define SEC_BCSH_ADDR_DEBUG_8 (BCSH1_BASE + 0x0094) ++ ++ ++//============================================================ ++// CLM ADDRESS ++//============================================================ ++#define MAIN_CLM_ADDR_SHD_CTRL (CLM0_BASE + 0x0000) ++#define MAIN_CLM_ADDR_LUT_SHIFT (CLM0_BASE + 0x0004) ++#define MAIN_CLM_ADDR_CSC_RB (CLM0_BASE + 0x0008) ++#define MAIN_CLM_ADDR_CSC_G (CLM0_BASE + 0x000c) ++#define MAIN_CLM_ADDR_CSC_U (CLM0_BASE + 0x0010) ++#define MAIN_CLM_ADDR_CSC_V (CLM0_BASE + 0x0014) ++#define MAIN_CLM_ADDR_CSC_Y (CLM0_BASE + 0x0018) ++#define MAIN_CLM_ADDR_CA_S_THRES (CLM0_BASE + 0x001c) ++#define MAIN_CLM_ADDR_CA_S_SLOPE (CLM0_BASE + 0x0020) ++#define MAIN_CLM_ADDR_CA_V_THRES (CLM0_BASE + 0x0024) ++#define MAIN_CLM_ADDR_CA_V_SLOPE (CLM0_BASE + 0x0028) ++#define MAIN_CLM_ADDR_DEBUG0 (CLM0_BASE + 0x002c) ++#define MAIN_CLM_ADDR_DEBUG1 (CLM0_BASE + 0x0030) ++#define MAIN_CLM_ADDR_DEBUG2 (CLM0_BASE + 0x0034) ++#define MAIN_CLM_ADDR_DEBUG3 (CLM0_BASE + 0x0038) ++#define MAIN_CLM_ADDR_DEBUG4 (CLM0_BASE + 0x003c) ++#define MAIN_CLM_ADDR_DEBUG5 (CLM0_BASE + 0x0040) ++#define MAIN_CLM_ADDR_DEBUG6 (CLM0_BASE + 0x0044) ++#define MAIN_CLM_ADDR_DEBUG7 (CLM0_BASE + 0x0048) ++ ++#define SEC_CLM_ADDR_SHD_CTRL (CLM1_BASE + 0x0000) ++#define SEC_CLM_ADDR_LUT_SHIFT (CLM1_BASE + 0x0004) ++#define SEC_CLM_ADDR_CSC_RB (CLM1_BASE + 0x0008) ++#define SEC_CLM_ADDR_CSC_G (CLM1_BASE + 0x000c) ++#define SEC_CLM_ADDR_CSC_U (CLM1_BASE + 0x0010) ++#define SEC_CLM_ADDR_CSC_V (CLM1_BASE + 0x0014) ++#define SEC_CLM_ADDR_CSC_Y (CLM1_BASE + 0x0018) ++#define SEC_CLM_ADDR_CA_S_THRES (CLM1_BASE + 0x001c) ++#define SEC_CLM_ADDR_CA_S_SLOPE (CLM1_BASE + 0x0020) ++#define SEC_CLM_ADDR_CA_V_THRES (CLM1_BASE + 0x0024) ++#define SEC_CLM_ADDR_CA_V_SLOPE (CLM1_BASE + 0x0028) ++#define SEC_CLM_ADDR_DEBUG0 (CLM1_BASE + 0x002c) ++#define SEC_CLM_ADDR_DEBUG1 (CLM1_BASE + 0x0030) ++#define SEC_CLM_ADDR_DEBUG2 (CLM1_BASE + 0x0034) ++#define SEC_CLM_ADDR_DEBUG3 (CLM1_BASE + 0x0038) ++#define SEC_CLM_ADDR_DEBUG4 (CLM1_BASE + 0x003c) ++#define SEC_CLM_ADDR_DEBUG5 (CLM1_BASE + 0x0040) ++#define SEC_CLM_ADDR_DEBUG6 (CLM1_BASE + 0x0044) ++#define SEC_CLM_ADDR_DEBUG7 (CLM1_BASE + 0x0048) ++ ++ ++//============================================================ ++// YSP0 ADDRESS ++//============================================================ ++#define Y_SHARPEN_ADDR_SL_EXP(n) (Y_SHARPEN_BASE(n) + 0x0000) ++#define Y_SHARPEN_ADDR_SL_SEL_OPT(n) (Y_SHARPEN_BASE(n) + 0x0004) ++#define Y_SHARPEN_ADDR_EDGE_THRES(n) (Y_SHARPEN_BASE(n) + 0x0008) ++#define Y_SHARPEN_ADDR_OS_MAX_THRES(n) (Y_SHARPEN_BASE(n) + 0x000c) ++#define Y_SHARPEN_ADDR_OS_SUP(n) (Y_SHARPEN_BASE(n) + 0x0010) ++#define Y_SHARPEN_ADDR_HV_THRES(n) (Y_SHARPEN_BASE(n) + 0x0014) ++#define Y_SHARPEN_ADDR_HV_STREN_T(n) (Y_SHARPEN_BASE(n) + 0x0018) ++#define Y_SHARPEN_ADDR_AA_THRES(n) (Y_SHARPEN_BASE(n) + 0x001c) ++#define Y_SHARPEN_ADDR_AA_STREN_T(n) (Y_SHARPEN_BASE(n) + 0x0020) ++#define Y_SHARPEN_ADDR_HVAA_THRES(n) (Y_SHARPEN_BASE(n) + 0x0024) ++#define Y_SHARPEN_ADDR_HVAA_STREN_T(n) (Y_SHARPEN_BASE(n) + 0x0028) ++#define Y_SHARPEN_ADDR_THRES(n) (Y_SHARPEN_BASE(n) + 0x002c) ++#define Y_SHARPEN_ADDR_V1(n) (Y_SHARPEN_BASE(n) + 0x0030) ++#define Y_SHARPEN_ADDR_V2(n) (Y_SHARPEN_BASE(n) + 0x0034) ++#define Y_SHARPEN_ADDR_DNS_OPT(n) (Y_SHARPEN_BASE(n) + 0x0038) ++#define Y_SHARPEN_ADDR_D_0(n) (Y_SHARPEN_BASE(n) + 0x003c) ++#define Y_SHARPEN_ADDR_D_1(n) (Y_SHARPEN_BASE(n) + 0x0040) ++#define Y_SHARPEN_ADDR_D_2(n) (Y_SHARPEN_BASE(n) + 0x0044) ++#define Y_SHARPEN_ADDR_D_3(n) (Y_SHARPEN_BASE(n) + 0x0048) ++#define Y_SHARPEN_ADDR_UD_1(n) (Y_SHARPEN_BASE(n) + 0x004c) ++#define Y_SHARPEN_ADDR_UD_2(n) (Y_SHARPEN_BASE(n) + 0x0050) ++#define Y_SHARPEN_ADDR_UD_3(n) (Y_SHARPEN_BASE(n) + 0x0054) ++#define Y_SHARPEN_ADDR_DEBUG0(n) (Y_SHARPEN_BASE(n) + 0x0058) ++#define Y_SHARPEN_ADDR_DEBUG1(n) (Y_SHARPEN_BASE(n) + 0x005c) ++#define Y_SHARPEN_ADDR_DEBUG2(n) (Y_SHARPEN_BASE(n) + 0x0060) ++#define Y_SHARPEN_ADDR_DEBUG3(n) (Y_SHARPEN_BASE(n) + 0x0064) ++#define Y_SHARPEN_ADDR_DEBUG4(n) (Y_SHARPEN_BASE(n) + 0x0068) ++#define Y_SHARPEN_ADDR_DEBUG5(n) (Y_SHARPEN_BASE(n) + 0x006c) ++#define Y_SHARPEN_ADDR_DEBUG6(n) (Y_SHARPEN_BASE(n) + 0x0070) ++#define Y_SHARPEN_ADDR_DEBUG7(n) (Y_SHARPEN_BASE(n) + 0x0074) ++#define Y_SHARPEN_ADDR_SHD_CTRL(n) (Y_SHARPEN_BASE(n) + 0x0078) ++#define Y_SHARPEN_ADDR_UV_EDGE(n) (Y_SHARPEN_BASE(n) + 0x007c) ++#define Y_SHARPEN_ADDR_DNS_THRES_0_SL__03_00(n) (Y_SHARPEN_BASE(n) + 0x0080) ++#define Y_SHARPEN_ADDR_DNS_THRES_0_SL__07_04(n) (Y_SHARPEN_BASE(n) + 0x0084) ++#define Y_SHARPEN_ADDR_DNS_STREN_0_SL__03_00(n) (Y_SHARPEN_BASE(n) + 0x0088) ++#define Y_SHARPEN_ADDR_DNS_STREN_0_SL__07_04(n) (Y_SHARPEN_BASE(n) + 0x008c) ++#define Y_SHARPEN_ADDR_DNS_THRES_1_SL__03_00(n) (Y_SHARPEN_BASE(n) + 0x0090) ++#define Y_SHARPEN_ADDR_DNS_THRES_1_SL__07_04(n) (Y_SHARPEN_BASE(n) + 0x0094) ++#define Y_SHARPEN_ADDR_DNS_STREN_1_SL__03_00(n) (Y_SHARPEN_BASE(n) + 0x0098) ++#define Y_SHARPEN_ADDR_DNS_STREN_1_SL__07_04(n) (Y_SHARPEN_BASE(n) + 0x009c) ++#define Y_SHARPEN_ADDR_DNS_STREN_2_SL__03_00(n) (Y_SHARPEN_BASE(n) + 0x00a0) ++#define Y_SHARPEN_ADDR_DNS_STREN_2_SL__07_04(n) (Y_SHARPEN_BASE(n) + 0x00a4) ++#define Y_SHARPEN_ADDR_UU_NP__03_00(n) (Y_SHARPEN_BASE(n) + 0x00a8) ++#define Y_SHARPEN_ADDR_UU_NP__07_04(n) (Y_SHARPEN_BASE(n) + 0x00ac) ++#define Y_SHARPEN_ADDR_UU_NP__11_08(n) (Y_SHARPEN_BASE(n) + 0x00b0) ++#define Y_SHARPEN_ADDR_UU_NP__15_12(n) (Y_SHARPEN_BASE(n) + 0x00b4) ++#define Y_SHARPEN_ADDR_D_UU_THRES_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x00b8) ++#define Y_SHARPEN_ADDR_D_UU_THRES_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x00bc) ++#define Y_SHARPEN_ADDR_D_UU_THRES_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x00c0) ++#define Y_SHARPEN_ADDR_D_UU_THRES_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x00c4) ++#define Y_SHARPEN_ADDR_D_WEI_NP__03_00(n) (Y_SHARPEN_BASE(n) + 0x00c8) ++#define Y_SHARPEN_ADDR_D_WEI_NP__07_04(n) (Y_SHARPEN_BASE(n) + 0x00cc) ++#define Y_SHARPEN_ADDR_D_WEI_NP__11_08(n) (Y_SHARPEN_BASE(n) + 0x00d0) ++#define Y_SHARPEN_ADDR_D_WEI_NP__15_12(n) (Y_SHARPEN_BASE(n) + 0x00d4) ++#define Y_SHARPEN_ADDR_D_WEI_NP__19_16(n) (Y_SHARPEN_BASE(n) + 0x00d8) ++#define Y_SHARPEN_ADDR_D_WEI_NP__23_20(n) (Y_SHARPEN_BASE(n) + 0x00dc) ++#define Y_SHARPEN_ADDR_D_WEI_NP__27_24(n) (Y_SHARPEN_BASE(n) + 0x00e0) ++#define Y_SHARPEN_ADDR_D_WEI_NP__31_28(n) (Y_SHARPEN_BASE(n) + 0x00e4) ++#define Y_SHARPEN_ADDR_D_LL_THRES_SL__03_00(n) (Y_SHARPEN_BASE(n) + 0x00e8) ++#define Y_SHARPEN_ADDR_D_LL_THRES_SL__07_04(n) (Y_SHARPEN_BASE(n) + 0x00ec) ++#define Y_SHARPEN_ADDR_D_LL_STREN_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x00f0) ++#define Y_SHARPEN_ADDR_D_LL_STREN_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x00f4) ++#define Y_SHARPEN_ADDR_D_LL_STREN_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x00f8) ++#define Y_SHARPEN_ADDR_D_LL_STREN_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x00fc) ++#define Y_SHARPEN_ADDR_D_HL_THRES_SL__03_00(n) (Y_SHARPEN_BASE(n) + 0x0100) ++#define Y_SHARPEN_ADDR_D_HL_THRES_SL__07_04(n) (Y_SHARPEN_BASE(n) + 0x0104) ++#define Y_SHARPEN_ADDR_D_HL_STREN_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x0108) ++#define Y_SHARPEN_ADDR_D_HL_STREN_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x010c) ++#define Y_SHARPEN_ADDR_D_HL_STREN_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x0110) ++#define Y_SHARPEN_ADDR_D_HL_STREN_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x0114) ++#define Y_SHARPEN_ADDR_UD_UU_THRES_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x0118) ++#define Y_SHARPEN_ADDR_UD_UU_THRES_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x011c) ++#define Y_SHARPEN_ADDR_UD_UU_THRES_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x0120) ++#define Y_SHARPEN_ADDR_UD_UU_THRES_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x0124) ++#define Y_SHARPEN_ADDR_UD_WEI_NP__03_00(n) (Y_SHARPEN_BASE(n) + 0x0128) ++#define Y_SHARPEN_ADDR_UD_WEI_NP__07_04(n) (Y_SHARPEN_BASE(n) + 0x012c) ++#define Y_SHARPEN_ADDR_UD_WEI_NP__11_08(n) (Y_SHARPEN_BASE(n) + 0x0130) ++#define Y_SHARPEN_ADDR_UD_WEI_NP__15_12(n) (Y_SHARPEN_BASE(n) + 0x0134) ++#define Y_SHARPEN_ADDR_UD_WEI_NP__19_16(n) (Y_SHARPEN_BASE(n) + 0x0138) ++#define Y_SHARPEN_ADDR_UD_WEI_NP__23_20(n) (Y_SHARPEN_BASE(n) + 0x013c) ++#define Y_SHARPEN_ADDR_UD_WEI_NP__27_24(n) (Y_SHARPEN_BASE(n) + 0x0140) ++#define Y_SHARPEN_ADDR_UD_WEI_NP__31_28(n) (Y_SHARPEN_BASE(n) + 0x0144) ++#define Y_SHARPEN_ADDR_UD_LL_THRES_SL__03_00(n) (Y_SHARPEN_BASE(n) + 0x0148) ++#define Y_SHARPEN_ADDR_UD_LL_THRES_SL__07_04(n) (Y_SHARPEN_BASE(n) + 0x014c) ++#define Y_SHARPEN_ADDR_UD_LL_STREN_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x0150) ++#define Y_SHARPEN_ADDR_UD_LL_STREN_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x0154) ++#define Y_SHARPEN_ADDR_UD_LL_STREN_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x0158) ++#define Y_SHARPEN_ADDR_UD_LL_STREN_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x015c) ++#define Y_SHARPEN_ADDR_UD_HL_THRES_SL__03_00(n) (Y_SHARPEN_BASE(n) + 0x0160) ++#define Y_SHARPEN_ADDR_UD_HL_THRES_SL__07_04(n) (Y_SHARPEN_BASE(n) + 0x0164) ++#define Y_SHARPEN_ADDR_UD_HL_STREN_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x0168) ++#define Y_SHARPEN_ADDR_UD_HL_STREN_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x016c) ++#define Y_SHARPEN_ADDR_UD_HL_STREN_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x0170) ++#define Y_SHARPEN_ADDR_UD_HL_STREN_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x0174) ++#define Y_SHARPEN_ADDR_D_UU_STREN_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x0178) ++#define Y_SHARPEN_ADDR_D_UU_STREN_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x017c) ++#define Y_SHARPEN_ADDR_D_UU_STREN_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x0180) ++#define Y_SHARPEN_ADDR_D_UU_STREN_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x0184) ++#define Y_SHARPEN_ADDR_D_W_SP_STREN_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x0188) ++#define Y_SHARPEN_ADDR_D_W_SP_STREN_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x018c) ++#define Y_SHARPEN_ADDR_D_W_SP_STREN_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x0190) ++#define Y_SHARPEN_ADDR_D_W_SP_STREN_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x0194) ++#define Y_SHARPEN_ADDR_D_B_SP_STREN_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x0198) ++#define Y_SHARPEN_ADDR_D_B_SP_STREN_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x019c) ++#define Y_SHARPEN_ADDR_D_B_SP_STREN_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x01a0) ++#define Y_SHARPEN_ADDR_D_B_SP_STREN_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x01a4) ++#define Y_SHARPEN_ADDR_UD_UU_STREN_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x01a8) ++#define Y_SHARPEN_ADDR_UD_UU_STREN_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x01ac) ++#define Y_SHARPEN_ADDR_UD_UU_STREN_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x01b0) ++#define Y_SHARPEN_ADDR_UD_UU_STREN_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x01b4) ++#define Y_SHARPEN_ADDR_UD_W_SP_STREN_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x01b8) ++#define Y_SHARPEN_ADDR_UD_W_SP_STREN_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x01bc) ++#define Y_SHARPEN_ADDR_UD_W_SP_STREN_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x01c0) ++#define Y_SHARPEN_ADDR_UD_W_SP_STREN_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x01c4) ++#define Y_SHARPEN_ADDR_UD_B_SP_STREN_SL__01_00(n) (Y_SHARPEN_BASE(n) + 0x01c8) ++#define Y_SHARPEN_ADDR_UD_B_SP_STREN_SL__03_02(n) (Y_SHARPEN_BASE(n) + 0x01cc) ++#define Y_SHARPEN_ADDR_UD_B_SP_STREN_SL__05_04(n) (Y_SHARPEN_BASE(n) + 0x01d0) ++#define Y_SHARPEN_ADDR_UD_B_SP_STREN_SL__07_06(n) (Y_SHARPEN_BASE(n) + 0x01d4) ++#define Y_SHARPEN_ADDR_FLAT_SLOPE(n) (Y_SHARPEN_BASE(n) + 0x01d8) ++#define Y_SHARPEN_ADDR_LAP_3_0(n) (Y_SHARPEN_BASE(n) + 0x01dc) ++#define Y_SHARPEN_ADDR_LAP_3_1(n) (Y_SHARPEN_BASE(n) + 0x01e0) ++#define Y_SHARPEN_ADDR_LAP_3_2(n) (Y_SHARPEN_BASE(n) + 0x01e4) ++ ++//============================================================ ++// SDNS ADDRESS main ++//============================================================ ++#define SDNS_ADDR_ABCD_SEG_OPT(n) (SDNS_BASE(n) + 0x0000) ++#define SDNS_ADDR_STD_THR(n) (SDNS_BASE(n) + 0x0004) ++#define SDNS_ADDR_GRAD_ZXY_THRES(n) (SDNS_BASE(n) + 0x000c) ++#define SDNS_ADDR_MMEM_YB_THRES(n) (SDNS_BASE(n) + 0x0010) ++#define SDNS_ADDR_DIFF_R_STD_OUT_VAL_THRES(n) (SDNS_BASE(n) + 0x0014) ++#define SDNS_ADDR_H_VAL_MAX(n) (SDNS_BASE(n) + 0x0018) ++#define SDNS_ADDR_MV_INFOR_THRES(n) (SDNS_BASE(n) + 0x001c) ++#define SDNS_ADDR_HLS_EN(n) (SDNS_BASE(n) + 0x0020) ++#define SDNS_ADDR_AVE_SEG_OPT_EN(n) (SDNS_BASE(n) + 0x0024) ++#define SDNS_ADDR_AVE_SEG_OPT_THRES(n) (SDNS_BASE(n) + 0x0028) ++#define SDNS_ADDR_AVE_SEG_OPT(n) (SDNS_BASE(n) + 0x002c) ++#define SDNS_ADDR_AVE_SLOPE(n) (SDNS_BASE(n) + 0x0030) ++#define SDNS_ADDR_ROW_COPY_OPT(n) (SDNS_BASE(n) + 0x0034) ++#define SDNS_ADDR_ROW_STDAVE_THRES(n) (SDNS_BASE(n) + 0x0038) ++#define SDNS_ADDR_STA_STD_EN(n) (SDNS_BASE(n) + 0x003c) ++#define SDNS_ADDR_STA_COUNT_THRES(n) (SDNS_BASE(n) + 0x0040) ++#define SDNS_ADDR_DEBUG_0(n) (SDNS_BASE(n) + 0x0044) ++#define SDNS_ADDR_DEBUG_1(n) (SDNS_BASE(n) + 0x0048) ++#define SDNS_ADDR_DEBUG_2(n) (SDNS_BASE(n) + 0x004c) ++#define SDNS_ADDR_DEBUG_3(n) (SDNS_BASE(n) + 0x0050) ++#define SDNS_ADDR_SHD_CTRL(n) (SDNS_BASE(n) + 0x0054) ++#define SDNS_ADDR_DMAO_CFG(n) (SDNS_BASE(n) + 0x0058) ++#define SDNS_ADDR_DMAO_ADDR_0(n) (SDNS_BASE(n) + 0x005c) ++#define SDNS_ADDR_DMAO_ADDR_1(n) (SDNS_BASE(n) + 0x0060) ++#define SDNS_ADDR_DMAO_ADDR_2(n) (SDNS_BASE(n) + 0x0064) ++#define SDNS_ADDR_DMAO_ADDR_3(n) (SDNS_BASE(n) + 0x0068) ++#define SDNS_ADDR_DMAO_CUR_ADDR(n) (SDNS_BASE(n) + 0x006c) ++#define SDNS_ADDR_DMAI_CFG(n) (SDNS_BASE(n) + 0x0070) ++#define SDNS_ADDR_DMAI_ADDR_0(n) (SDNS_BASE(n) + 0x0074) ++#define SDNS_ADDR_DMAI_ADDR_1(n) (SDNS_BASE(n) + 0x0078) ++#define SDNS_ADDR_DMAI_ADDR_2(n) (SDNS_BASE(n) + 0x007c) ++#define SDNS_ADDR_DMAI_ADDR_3(n) (SDNS_BASE(n) + 0x0080) ++#define SDNS_ADDR_FRST_FRM_FLAG(n) (SDNS_BASE(n) + 0x0084) ++#define SDNS_ADDR_STA_STD_OPT(n) (SDNS_BASE(n) + 0x0088) ++#define SDNS_ADDR_G_DET_VAL(n) (SDNS_BASE(n) + 0x008c) ++#define SDNS_ADDR_HOR_VER_T01_THRES(n) (SDNS_BASE(n) + 0x0090) ++#define SDNS_ADDR_H_VAL_MAX_LIGHT(n) (SDNS_BASE(n) + 0x0094) ++#define SDNS_ADDR_SP_LIMIT(n) (SDNS_BASE(n) + 0x0098) ++#define SDNS_ADDR_SP_LL_THRES(n) (SDNS_BASE(n) + 0x009c) ++#define SDNS_ADDR_R_S_01_00(n) (SDNS_BASE(n) + 0x0100) ++#define SDNS_ADDR_R_S_03_02(n) (SDNS_BASE(n) + 0x0104) ++#define SDNS_ADDR_R_S_05_04(n) (SDNS_BASE(n) + 0x0108) ++#define SDNS_ADDR_R_S_07_06(n) (SDNS_BASE(n) + 0x010c) ++#define SDNS_ADDR_R_S_09_08(n) (SDNS_BASE(n) + 0x0110) ++#define SDNS_ADDR_R_S_11_10(n) (SDNS_BASE(n) + 0x0114) ++#define SDNS_ADDR_R_S_13_12(n) (SDNS_BASE(n) + 0x0118) ++#define SDNS_ADDR_R_S_14_14(n) (SDNS_BASE(n) + 0x011c) ++#define SDNS_ADDR_R_MV_01_00(n) (SDNS_BASE(n) + 0x0120) ++#define SDNS_ADDR_R_MV_03_02(n) (SDNS_BASE(n) + 0x0124) ++#define SDNS_ADDR_R_MV_05_04(n) (SDNS_BASE(n) + 0x0128) ++#define SDNS_ADDR_R_MV_07_06(n) (SDNS_BASE(n) + 0x012c) ++#define SDNS_ADDR_R_MV_09_08(n) (SDNS_BASE(n) + 0x0130) ++#define SDNS_ADDR_R_MV_11_10(n) (SDNS_BASE(n) + 0x0134) ++#define SDNS_ADDR_R_MV_13_12(n) (SDNS_BASE(n) + 0x0138) ++#define SDNS_ADDR_R_MV_14_14(n) (SDNS_BASE(n) + 0x013c) ++#define SDNS_ADDR_H_S_03_00(n) (SDNS_BASE(n) + 0x0140) ++#define SDNS_ADDR_H_S_07_04(n) (SDNS_BASE(n) + 0x0144) ++#define SDNS_ADDR_H_S_11_08(n) (SDNS_BASE(n) + 0x0148) ++#define SDNS_ADDR_H_S_15_12(n) (SDNS_BASE(n) + 0x014c) ++#define SDNS_ADDR_H_MV_03_00(n) (SDNS_BASE(n) + 0x0150) ++#define SDNS_ADDR_H_MV_07_04(n) (SDNS_BASE(n) + 0x0154) ++#define SDNS_ADDR_H_MV_11_08(n) (SDNS_BASE(n) + 0x0158) ++#define SDNS_ADDR_H_MV_15_12(n) (SDNS_BASE(n) + 0x015c) ++#define SDNS_ADDR_BLOCK_R_S_03_00(n) (SDNS_BASE(n) + 0x0160) ++#define SDNS_ADDR_BLOCK_R_S_07_04(n) (SDNS_BASE(n) + 0x0164) ++#define SDNS_ADDR_BLOCK_R_S_10_08(n) (SDNS_BASE(n) + 0x0168) ++#define SDNS_ADDR_BLOCK_H_S_03_00(n) (SDNS_BASE(n) + 0x016c) ++#define SDNS_ADDR_BLOCK_H_S_07_04(n) (SDNS_BASE(n) + 0x0170) ++#define SDNS_ADDR_BLOCK_H_S_11_08(n) (SDNS_BASE(n) + 0x0174) ++#define SDNS_ADDR_TT_OPT_THRES_01_00(n) (SDNS_BASE(n) + 0x0178) ++#define SDNS_ADDR_TT_OPT_THRES_03_02(n) (SDNS_BASE(n) + 0x017c) ++#define SDNS_ADDR_TT_OPT_THRES_05_04(n) (SDNS_BASE(n) + 0x0180) ++#define SDNS_ADDR_D_S1_THR_01_00(n) (SDNS_BASE(n) + 0x0184) ++#define SDNS_ADDR_D_S1_THR_03_02(n) (SDNS_BASE(n) + 0x0188) ++#define SDNS_ADDR_D_S1_THR_05_04(n) (SDNS_BASE(n) + 0x018c) ++#define SDNS_ADDR_D_S1_THR_06_06(n) (SDNS_BASE(n) + 0x0190) ++#define SDNS_ADDR_W_THR_03_00(n) (SDNS_BASE(n) + 0x0194) ++#define SDNS_ADDR_W_THR_07_04(n) (SDNS_BASE(n) + 0x0198) ++#define SDNS_ADDR_H_MV_WEI_03_00(n) (SDNS_BASE(n) + 0x019c) ++#define SDNS_ADDR_H_MV_WEI_07_04(n) (SDNS_BASE(n) + 0x01a0) ++#define SDNS_ADDR_DARK_THRES_03_00(n) (SDNS_BASE(n) + 0x01a4) ++#define SDNS_ADDR_DARK_THRES_07_04(n) (SDNS_BASE(n) + 0x01a8) ++#define SDNS_ADDR_LIGHT_THRES_03_00(n) (SDNS_BASE(n) + 0x01ac) ++#define SDNS_ADDR_LIGHT_THRES_07_04(n) (SDNS_BASE(n) + 0x01b0) ++#define SDNS_ADDR_SP_UU_THRES_01_00(n) (SDNS_BASE(n) + 0x01b4) ++#define SDNS_ADDR_SP_UU_THRES_03_02(n) (SDNS_BASE(n) + 0x01b8) ++#define SDNS_ADDR_SP_UU_THRES_05_04(n) (SDNS_BASE(n) + 0x01bc) ++#define SDNS_ADDR_SP_UU_THRES_07_06(n) (SDNS_BASE(n) + 0x01c0) ++#define SDNS_ADDR_SP_UU_STREN_01_00(n) (SDNS_BASE(n) + 0x01c4) ++#define SDNS_ADDR_SP_UU_STREN_03_02(n) (SDNS_BASE(n) + 0x01c8) ++#define SDNS_ADDR_SP_UU_STREN_05_04(n) (SDNS_BASE(n) + 0x01cc) ++#define SDNS_ADDR_SP_UU_STREN_07_06(n) (SDNS_BASE(n) + 0x01d0) ++#define SDNS_ADDR_SP_WEI_NP_ARRAY_03_00(n) (SDNS_BASE(n) + 0x01d4) ++#define SDNS_ADDR_SP_WEI_NP_ARRAY_07_04(n) (SDNS_BASE(n) + 0x01d8) ++#define SDNS_ADDR_SP_WEI_NP_ARRAY_11_08(n) (SDNS_BASE(n) + 0x01dc) ++#define SDNS_ADDR_SP_WEI_NP_ARRAY_15_12(n) (SDNS_BASE(n) + 0x01e0) ++#define SDNS_ADDR_SP_WEI_NP_ARRAY_19_16(n) (SDNS_BASE(n) + 0x01e4) ++#define SDNS_ADDR_SP_WEI_NP_ARRAY_23_20(n) (SDNS_BASE(n) + 0x01e8) ++#define SDNS_ADDR_SP_WEI_NP_ARRAY_27_24(n) (SDNS_BASE(n) + 0x01ec) ++#define SDNS_ADDR_SP_WEI_NP_ARRAY_31_28(n) (SDNS_BASE(n) + 0x01f0) ++#define SDNS_ADDR_SP_W_STREN_03_00(n) (SDNS_BASE(n) + 0x01f4) ++#define SDNS_ADDR_SP_W_STREN_07_04(n) (SDNS_BASE(n) + 0x01f8) ++#define SDNS_ADDR_SP_B_STREN_03_00(n) (SDNS_BASE(n) + 0x01fc) ++#define SDNS_ADDR_SP_B_STREN_07_04(n) (SDNS_BASE(n) + 0x0200) ++ ++//============================================================ ++// YSP1 ADDRESS ++//============================================================ ++#define YSP1_BASE1 YSP1_BASE + 0x0200 ++#define MAIN_YSP1_ADDR_SL_EXP (YSP1_BASE + 0x0000) ++#define MAIN_YSP1_ADDR_SL_SEL_OPT (YSP1_BASE + 0x0004) ++#define MAIN_YSP1_ADDR_EDGE_THRES (YSP1_BASE + 0x0008) ++#define MAIN_YSP1_ADDR_EDGE_MAX_THRES (YSP1_BASE + 0x000c) ++#define MAIN_YSP1_ADDR_EDGE_SCALE_OPT (YSP1_BASE + 0x0010) ++#define MAIN_YSP1_ADDR_OS_0 (YSP1_BASE + 0x0014) ++#define MAIN_YSP1_ADDR_OS_1 (YSP1_BASE + 0x0018) ++#define MAIN_YSP1_ADDR_OS_2 (YSP1_BASE + 0x001c) ++#define MAIN_YSP1_ADDR_OS_3 (YSP1_BASE + 0x0020) ++#define MAIN_YSP1_ADDR_V1 (YSP1_BASE + 0x0024) ++#define MAIN_YSP1_ADDR_V2 (YSP1_BASE + 0x0028) ++#define MAIN_YSP1_ADDR_DNS_0 (YSP1_BASE + 0x002c) ++#define MAIN_YSP1_ADDR_DNS_1 (YSP1_BASE + 0x0030) ++#define MAIN_YSP1_ADDR_DNS_2 (YSP1_BASE + 0x0034) ++#define MAIN_YSP1_ADDR_DNS_3 (YSP1_BASE + 0x0038) ++#define MAIN_YSP1_ADDR_DNS_4 (YSP1_BASE + 0x003c) ++#define MAIN_YSP1_ADDR_DNS_5 (YSP1_BASE + 0x0040) ++#define MAIN_YSP1_ADDR_DIR_0 (YSP1_BASE + 0x0044) ++#define MAIN_YSP1_ADDR_DIR_1 (YSP1_BASE + 0x0048) ++#define MAIN_YSP1_ADDR_UU_0 (YSP1_BASE + 0x004c) ++#define MAIN_YSP1_ADDR_UU_1 (YSP1_BASE + 0x0050) ++#define MAIN_YSP1_ADDR_LL (YSP1_BASE + 0x0054) ++#define MAIN_YSP1_ADDR_HL (YSP1_BASE + 0x0058) ++#define MAIN_YSP1_ADDR_W_WEI (YSP1_BASE + 0x005c) ++#define MAIN_YSP1_ADDR_DIR_0_0 (YSP1_BASE + 0x0060) ++#define MAIN_YSP1_ADDR_DIR_1_1 (YSP1_BASE + 0x0064) ++#define MAIN_YSP1_ADDR_DIR_2 (YSP1_BASE + 0x0068) ++#define MAIN_YSP1_ADDR_UDIR_0 (YSP1_BASE + 0x006c) ++#define MAIN_YSP1_ADDR_UDIR_1 (YSP1_BASE + 0x0070) ++#define MAIN_YSP1_ADDR_DETAIL_0 (YSP1_BASE + 0x0074) ++#define MAIN_YSP1_ADDR_DETAIL_1 (YSP1_BASE + 0x0078) ++#define MAIN_YSP1_ADDR_DETAIL_2 (YSP1_BASE + 0x007c) ++#define MAIN_YSP1_ADDR_DEBUG0 (YSP0_BASE + 0x0080) ++#define MAIN_YSP1_ADDR_DEBUG1 (YSP0_BASE + 0x0084) ++#define MAIN_YSP1_ADDR_SHD_CTRL (YSP1_BASE + 0x0088) ++#define MAIN_YSP1_ADDR_UU_NP_ARRAY_03_00 (YSP1_BASE + 0x008c) ++#define MAIN_YSP1_ADDR_UU_NP_ARRAY_07_04 (YSP1_BASE + 0x0090) ++#define MAIN_YSP1_ADDR_UU_NP_ARRAY_11_08 (YSP1_BASE + 0x0094) ++#define MAIN_YSP1_ADDR_UU_NP_ARRAY_15_12 (YSP1_BASE + 0x0098) ++#define MAIN_YSP1_ADDR_W_WEI_NP_ARRAY_03_00 (YSP1_BASE + 0x009c) ++#define MAIN_YSP1_ADDR_W_WEI_NP_ARRAY_07_04 (YSP1_BASE + 0x00a0) ++#define MAIN_YSP1_ADDR_W_WEI_NP_ARRAY_11_08 (YSP1_BASE + 0x00a4) ++#define MAIN_YSP1_ADDR_W_WEI_NP_ARRAY_15_12 (YSP1_BASE + 0x00a8) ++#define MAIN_YSP1_ADDR_B_WEI_NP_ARRAY_03_00 (YSP1_BASE + 0x00ac) ++#define MAIN_YSP1_ADDR_B_WEI_NP_ARRAY_07_04 (YSP1_BASE + 0x00b0) ++#define MAIN_YSP1_ADDR_B_WEI_NP_ARRAY_11_08 (YSP1_BASE + 0x00b4) ++#define MAIN_YSP1_ADDR_B_WEI_NP_ARRAY_15_12 (YSP1_BASE + 0x00b8) ++#define MAIN_YSP1_ADDR_DNS_THRES_0_SL_ARRAY_03_00 (YSP1_BASE + 0x00bc) ++#define MAIN_YSP1_ADDR_DNS_THRES_0_SL_ARRAY_07_04 (YSP1_BASE + 0x00c0) ++#define MAIN_YSP1_ADDR_DNS_STREN_0_SL_ARRAY_03_00 (YSP1_BASE + 0x00c4) ++#define MAIN_YSP1_ADDR_DNS_STREN_0_SL_ARRAY_07_04 (YSP1_BASE + 0x00c8) ++#define MAIN_YSP1_ADDR_DNS_THRES_1_SL_ARRAY_03_00 (YSP1_BASE + 0x00cc) ++#define MAIN_YSP1_ADDR_DNS_THRES_1_SL_ARRAY_07_04 (YSP1_BASE + 0x00d0) ++#define MAIN_YSP1_ADDR_DNS_STREN_1_SL_ARRAY_03_00 (YSP1_BASE + 0x00d4) ++#define MAIN_YSP1_ADDR_DNS_STREN_1_SL_ARRAY_07_04 (YSP1_BASE + 0x00d8) ++#define MAIN_YSP1_ADDR_DNS_STREN_2_SL_ARRAY_03_00 (YSP1_BASE + 0x00dc) ++#define MAIN_YSP1_ADDR_DNS_STREN_2_SL_ARRAY_07_04 (YSP1_BASE + 0x00e0) ++#define MAIN_YSP1_ADDR_DIR_WEI_THRES_SL_ARRAY_03_00 (YSP1_BASE + 0x00e4) ++#define MAIN_YSP1_ADDR_DIR_WEI_THRES_SL_ARRAY_07_04 (YSP1_BASE + 0x00e8) ++#define MAIN_YSP1_ADDR_UU_THRES_SL_ARRAY_03_00 (YSP1_BASE + 0x00ec) ++#define MAIN_YSP1_ADDR_UU_THRES_SL_ARRAY_07_04 (YSP1_BASE + 0x00f0) ++#define MAIN_YSP1_ADDR_DIR_SP_SL_ARRAY_03_00 (YSP1_BASE + 0x00f4) ++#define MAIN_YSP1_ADDR_DIR_SP_SL_ARRAY_07_04 (YSP1_BASE + 0x00f8) ++#define MAIN_YSP1_ADDR_UDIR_SP_SL_ARRAY_03_00 (YSP1_BASE + 0x00fc) ++#define MAIN_YSP1_ADDR_UDIR_SP_SL_ARRAY_07_04 (YSP1_BASE + 0x0100) ++#define MAIN_YSP1_ADDR_DETAIL_SP_SL_ARRAY_03_00 (YSP1_BASE + 0x0104) ++#define MAIN_YSP1_ADDR_DETAIL_SP_SL_ARRAY_07_04 (YSP1_BASE + 0x0108) ++ ++#define SEC_YSP1_ADDR_SL_EXP (YSP1_BASE1 + 0x0000) ++#define SEC_YSP1_ADDR_SL_SEL_OPT (YSP1_BASE1 + 0x0004) ++#define SEC_YSP1_ADDR_EDGE_THRES (YSP1_BASE1 + 0x0008) ++#define SEC_YSP1_ADDR_EDGE_MAX_THRES (YSP1_BASE1 + 0x000c) ++#define SEC_YSP1_ADDR_EDGE_SCALE_OPT (YSP1_BASE1 + 0x0010) ++#define SEC_YSP1_ADDR_OS_0 (YSP1_BASE1 + 0x0014) ++#define SEC_YSP1_ADDR_OS_1 (YSP1_BASE1 + 0x0018) ++#define SEC_YSP1_ADDR_OS_2 (YSP1_BASE1 + 0x001c) ++#define SEC_YSP1_ADDR_OS_3 (YSP1_BASE1 + 0x0020) ++#define SEC_YSP1_ADDR_V1 (YSP1_BASE1 + 0x0024) ++#define SEC_YSP1_ADDR_V2 (YSP1_BASE1 + 0x0028) ++#define SEC_YSP1_ADDR_DNS_0 (YSP1_BASE1 + 0x002c) ++#define SEC_YSP1_ADDR_DNS_1 (YSP1_BASE1 + 0x0030) ++#define SEC_YSP1_ADDR_DNS_2 (YSP1_BASE1 + 0x0034) ++#define SEC_YSP1_ADDR_DNS_3 (YSP1_BASE1 + 0x0038) ++#define SEC_YSP1_ADDR_DNS_4 (YSP1_BASE1 + 0x003c) ++#define SEC_YSP1_ADDR_DNS_5 (YSP1_BASE1 + 0x0040) ++#define SEC_YSP1_ADDR_DIR_0 (YSP1_BASE1 + 0x0044) ++#define SEC_YSP1_ADDR_DIR_1 (YSP1_BASE1 + 0x0048) ++#define SEC_YSP1_ADDR_UU_0 (YSP1_BASE1 + 0x004c) ++#define SEC_YSP1_ADDR_UU_1 (YSP1_BASE1 + 0x0050) ++#define SEC_YSP1_ADDR_LL (YSP1_BASE1 + 0x0054) ++#define SEC_YSP1_ADDR_HL (YSP1_BASE1 + 0x0058) ++#define SEC_YSP1_ADDR_W_WEI (YSP1_BASE1 + 0x005c) ++#define SEC_YSP1_ADDR_DIR_0_0 (YSP1_BASE1 + 0x0060) ++#define SEC_YSP1_ADDR_DIR_1_1 (YSP1_BASE1 + 0x0064) ++#define SEC_YSP1_ADDR_DIR_2 (YSP1_BASE1 + 0x0068) ++#define SEC_YSP1_ADDR_UDIR_0 (YSP1_BASE1 + 0x006c) ++#define SEC_YSP1_ADDR_UDIR_1 (YSP1_BASE1 + 0x0070) ++#define SEC_YSP1_ADDR_DETAIL_0 (YSP1_BASE1 + 0x0074) ++#define SEC_YSP1_ADDR_DETAIL_1 (YSP1_BASE1 + 0x0078) ++#define SEC_YSP1_ADDR_DETAIL_2 (YSP1_BASE1 + 0x007c) ++#define SEC_YSP1_ADDR_DEBUG0 (YSP0_BASE1 + 0x0080) ++#define SEC_YSP1_ADDR_DEBUG1 (YSP0_BASE1 + 0x0084) ++#define SEC_YSP1_ADDR_SHD_CTRL (YSP1_BASE1 + 0x0088) ++#define SEC_YSP1_ADDR_UU_NP_ARRAY_03_00 (YSP1_BASE1 + 0x008c) ++#define SEC_YSP1_ADDR_UU_NP_ARRAY_07_04 (YSP1_BASE1 + 0x0090) ++#define SEC_YSP1_ADDR_UU_NP_ARRAY_11_08 (YSP1_BASE1 + 0x0094) ++#define SEC_YSP1_ADDR_UU_NP_ARRAY_15_12 (YSP1_BASE1 + 0x0098) ++#define SEC_YSP1_ADDR_W_WEI_NP_ARRAY_03_00 (YSP1_BASE1 + 0x009c) ++#define SEC_YSP1_ADDR_W_WEI_NP_ARRAY_07_04 (YSP1_BASE1 + 0x00a0) ++#define SEC_YSP1_ADDR_W_WEI_NP_ARRAY_11_08 (YSP1_BASE1 + 0x00a4) ++#define SEC_YSP1_ADDR_W_WEI_NP_ARRAY_15_12 (YSP1_BASE1 + 0x00a8) ++#define SEC_YSP1_ADDR_B_WEI_NP_ARRAY_03_00 (YSP1_BASE1 + 0x00ac) ++#define SEC_YSP1_ADDR_B_WEI_NP_ARRAY_07_04 (YSP1_BASE1 + 0x00b0) ++#define SEC_YSP1_ADDR_B_WEI_NP_ARRAY_11_08 (YSP1_BASE1 + 0x00b4) ++#define SEC_YSP1_ADDR_B_WEI_NP_ARRAY_15_12 (YSP1_BASE1 + 0x00b8) ++#define SEC_YSP1_ADDR_DNS_THRES_0_SL_ARRAY_03_00 (YSP1_BASE1 + 0x00bc) ++#define SEC_YSP1_ADDR_DNS_THRES_0_SL_ARRAY_07_04 (YSP1_BASE1 + 0x00c0) ++#define SEC_YSP1_ADDR_DNS_STREN_0_SL_ARRAY_03_00 (YSP1_BASE1 + 0x00c4) ++#define SEC_YSP1_ADDR_DNS_STREN_0_SL_ARRAY_07_04 (YSP1_BASE1 + 0x00c8) ++#define SEC_YSP1_ADDR_DNS_THRES_1_SL_ARRAY_03_00 (YSP1_BASE1 + 0x00cc) ++#define SEC_YSP1_ADDR_DNS_THRES_1_SL_ARRAY_07_04 (YSP1_BASE1 + 0x00d0) ++#define SEC_YSP1_ADDR_DNS_STREN_1_SL_ARRAY_03_00 (YSP1_BASE1 + 0x00d4) ++#define SEC_YSP1_ADDR_DNS_STREN_1_SL_ARRAY_07_04 (YSP1_BASE1 + 0x00d8) ++#define SEC_YSP1_ADDR_DNS_STREN_2_SL_ARRAY_03_00 (YSP1_BASE1 + 0x00dc) ++#define SEC_YSP1_ADDR_DNS_STREN_2_SL_ARRAY_07_04 (YSP1_BASE1 + 0x00e0) ++#define SEC_YSP1_ADDR_DIR_WEI_THRES_SL_ARRAY_03_00 (YSP1_BASE1 + 0x00e4) ++#define SEC_YSP1_ADDR_DIR_WEI_THRES_SL_ARRAY_07_04 (YSP1_BASE1 + 0x00e8) ++#define SEC_YSP1_ADDR_UU_THRES_SL_ARRAY_03_00 (YSP1_BASE1 + 0x00ec) ++#define SEC_YSP1_ADDR_UU_THRES_SL_ARRAY_07_04 (YSP1_BASE1 + 0x00f0) ++#define SEC_YSP1_ADDR_DIR_SP_SL_ARRAY_03_00 (YSP1_BASE1 + 0x00f4) ++#define SEC_YSP1_ADDR_DIR_SP_SL_ARRAY_07_04 (YSP1_BASE1 + 0x00f8) ++#define SEC_YSP1_ADDR_UDIR_SP_SL_ARRAY_03_00 (YSP1_BASE1 + 0x00fc) ++#define SEC_YSP1_ADDR_UDIR_SP_SL_ARRAY_07_04 (YSP1_BASE1 + 0x0100) ++#define SEC_YSP1_ADDR_DETAIL_SP_SL_ARRAY_03_00 (YSP1_BASE1 + 0x0104) ++#define SEC_YSP1_ADDR_DETAIL_SP_SL_ARRAY_07_04 (YSP1_BASE1 + 0x0108) ++ ++//============================================================ ++// HLDC ADDRESS ++//============================================================ ++#define HLDC_ADDR_FRAME_BP_EN(n) (HLDC_BASE(n) + 0x0000) ++#define HLDC_ADDR_DIS_Y_COEFF_X(n) (HLDC_BASE(n) + 0x0004) ++#define HLDC_ADDR_DIS_UV_COEFF_X(n) (HLDC_BASE(n) + 0x0008) ++#define HLDC_ADDR_P1_Y_VAL(n) (HLDC_BASE(n) + 0x000c) ++#define HLDC_ADDR_P1_UV_VAL(n) (HLDC_BASE(n) + 0x0010) ++#define HLDC_ADDR_R2_Y_REP(n) (HLDC_BASE(n) + 0x0014) ++#define HLDC_ADDR_R2_UV_REP(n) (HLDC_BASE(n) + 0x0018) ++#define HLDC_ADDR_Y_OFFSET(n) (HLDC_BASE(n) + 0x001c) ++#define HLDC_ADDR_UV_OFFSET(n) (HLDC_BASE(n) + 0x0020) ++#define HLDC_ADDR_LINE_BLK_Y(n) (HLDC_BASE(n) + 0x0024) ++#define HLDC_ADDR_LINE_BLK_UV(n) (HLDC_BASE(n) + 0x0028) ++#define HLDC_ADDR_DBG_Y_0(n) (HLDC_BASE(n) + 0x002c) ++#define HLDC_ADDR_DBG_Y_1(n) (HLDC_BASE(n) + 0x0030) ++#define HLDC_ADDR_DBG_Y_2(n) (HLDC_BASE(n) + 0x0034) ++#define HLDC_ADDR_DBG_UV_0(n) (HLDC_BASE(n) + 0x0038) ++#define HLDC_ADDR_DBG_UV_1(n) (HLDC_BASE(n) + 0x003c) ++#define HLDC_ADDR_DBG_UV_2(n) (HLDC_BASE(n) + 0x0040) ++#define HLDC_ADDR_SHD_CTRL(n) (HLDC_BASE(n) + 0x0044) ++ ++//============================================================ ++// AE ADDRESS ++//============================================================ ++#define MAIN_AE_ADDR_SHD_CTRL (AE0_BASE + 0x0000) ++#define MAIN_AE_ADDR_ZONE_NUM_START (AE0_BASE + 0x0004) ++#define MAIN_AE_ADDR_HOR_ZONE_SIZE_14 (AE0_BASE + 0x0008) ++#define MAIN_AE_ADDR_HOR_ZONE_SIZE_58 (AE0_BASE + 0x000c) ++#define MAIN_AE_ADDR_HOR_ZONE_SIZE_912 (AE0_BASE + 0x0010) ++#define MAIN_AE_ADDR_HOR_ZONE_SIZE_1315 (AE0_BASE + 0x0014) ++#define MAIN_AE_ADDR_VER_ZONE_SIZE_14 (AE0_BASE + 0x0018) ++#define MAIN_AE_ADDR_VER_ZONE_SIZE_58 (AE0_BASE + 0x001c) ++#define MAIN_AE_ADDR_VER_ZONE_SIZE_912 (AE0_BASE + 0x0020) ++#define MAIN_AE_ADDR_VER_ZONE_SIZE_1315 (AE0_BASE + 0x0024) ++#define MAIN_AE_ADDR_LUM_TH_FREQ (AE0_BASE + 0x0028) ++#define MAIN_AE_ADDR_AE_DMA_BASE_1 (AE0_BASE + 0x002c) ++#define MAIN_AE_ADDR_AE_DMA_BASE_2 (AE0_BASE + 0x0030) ++#define MAIN_AE_ADDR_AE_DMA_BASE_3 (AE0_BASE + 0x0034) ++#define MAIN_AE_ADDR_AE_DMA_BASE_4 (AE0_BASE + 0x0038) ++#define MAIN_AE_ADDR_HIST_DMA_BASE_1 (AE0_BASE + 0x003c) ++#define MAIN_AE_ADDR_HIST_DMA_BASE_2 (AE0_BASE + 0x0040) ++#define MAIN_AE_ADDR_HIST_DMA_BASE_3 (AE0_BASE + 0x0044) ++#define MAIN_AE_ADDR_HIST_DMA_BASE_4 (AE0_BASE + 0x0048) ++#define MAIN_AE_ADDR_DMA_BASE_NUM (AE0_BASE + 0x004c) ++#define MAIN_AE_ADDR_DMA_INFO (AE0_BASE + 0x0050) ++#define MAIN_AE_ADDR_SPEC_ZONE_HSIZE (AE0_BASE + 0x0054) ++#define MAIN_AE_ADDR_SPEC_ZONE_VSIZE (AE0_BASE + 0x0058) ++#define MAIN_AE_ADDR_SPEC_SUM_DARK (AE0_BASE + 0x005c) ++#define MAIN_AE_ADDR_SPEC_SUM_MID (AE0_BASE + 0x0060) ++#define MAIN_AE_ADDR_SPEC_SUM_SAT (AE0_BASE + 0x0064) ++#define MAIN_AE_ADDR_SPEC_CNT_DARK (AE0_BASE + 0x0068) ++#define MAIN_AE_ADDR_SPEC_CNT_SAT (AE0_BASE + 0x006c) ++#define MAIN_AE_ADDR_SPEC_SUM_IR (AE0_BASE + 0x0070) ++#define MAIN_AE_ADDR_DEBUG_0 (AE0_BASE + 0x0074) ++#define MAIN_AE_ADDR_DEBUG_1 (AE0_BASE + 0x0078) ++#define MAIN_AE_ADDR_DEBUG_2 (AE0_BASE + 0x007c) ++#define MAIN_AE_ADDR_DEBUG_3 (AE0_BASE + 0x0080) ++#define MAIN_AE_ADDR_DEBUG_4 (AE0_BASE + 0x0084) ++#define MAIN_AE_ADDR_DEBUG_5 (AE0_BASE + 0x0088) ++#define MAIN_AE_ADDR_DEBUG_6 (AE0_BASE + 0x008c) ++#define MAIN_AE_ADDR_DEBUG_7 (AE0_BASE + 0x0090) ++#define MAIN_AE_ADDR_DEBUG_8 (AE0_BASE + 0x0094) ++#define MAIN_AE_ADDR_DEBUG_9 (AE0_BASE + 0x0098) ++#define MAIN_AE_ADDR_DEBUG_10 (AE0_BASE + 0x009c) ++#define MAIN_AE_ADDR_DEBUG_11 (AE0_BASE + 0x00a0) ++#define MAIN_AE_ADDR_DEBUG_12 (AE0_BASE + 0x00a4) ++#define MAIN_AE_ADDR_DEBUG_13 (AE0_BASE + 0x00a8) ++ ++#define SEC_AE_ADDR_SHD_CTRL (AE1_BASE + 0x0000) ++#define SEC_AE_ADDR_ZONE_NUM_START (AE1_BASE + 0x0004) ++#define SEC_AE_ADDR_HOR_ZONE_SIZE_14 (AE1_BASE + 0x0008) ++#define SEC_AE_ADDR_HOR_ZONE_SIZE_58 (AE1_BASE + 0x000c) ++#define SEC_AE_ADDR_HOR_ZONE_SIZE_912 (AE1_BASE + 0x0010) ++#define SEC_AE_ADDR_HOR_ZONE_SIZE_1315 (AE1_BASE + 0x0014) ++#define SEC_AE_ADDR_VER_ZONE_SIZE_14 (AE1_BASE + 0x0018) ++#define SEC_AE_ADDR_VER_ZONE_SIZE_58 (AE1_BASE + 0x001c) ++#define SEC_AE_ADDR_VER_ZONE_SIZE_912 (AE1_BASE + 0x0020) ++#define SEC_AE_ADDR_VER_ZONE_SIZE_1315 (AE1_BASE + 0x0024) ++#define SEC_AE_ADDR_LUM_TH_FREQ (AE1_BASE + 0x0028) ++#define SEC_AE_ADDR_AE_DMA_BASE_1 (AE1_BASE + 0x002c) ++#define SEC_AE_ADDR_AE_DMA_BASE_2 (AE1_BASE + 0x0030) ++#define SEC_AE_ADDR_AE_DMA_BASE_3 (AE1_BASE + 0x0034) ++#define SEC_AE_ADDR_AE_DMA_BASE_4 (AE1_BASE + 0x0038) ++#define SEC_AE_ADDR_HIST_DMA_BASE_1 (AE1_BASE + 0x003c) ++#define SEC_AE_ADDR_HIST_DMA_BASE_2 (AE1_BASE + 0x0040) ++#define SEC_AE_ADDR_HIST_DMA_BASE_3 (AE1_BASE + 0x0044) ++#define SEC_AE_ADDR_HIST_DMA_BASE_4 (AE1_BASE + 0x0048) ++#define SEC_AE_ADDR_DMA_BASE_NUM (AE1_BASE + 0x004c) ++#define SEC_AE_ADDR_DMA_INFO (AE1_BASE + 0x0050) ++#define SEC_AE_ADDR_SPEC_ZONE_HSIZE (AE1_BASE + 0x0054) ++#define SEC_AE_ADDR_SPEC_ZONE_VSIZE (AE1_BASE + 0x0058) ++#define SEC_AE_ADDR_SPEC_SUM_DARK (AE1_BASE + 0x005c) ++#define SEC_AE_ADDR_SPEC_SUM_MID (AE1_BASE + 0x0060) ++#define SEC_AE_ADDR_SPEC_SUM_SAT (AE1_BASE + 0x0064) ++#define SEC_AE_ADDR_SPEC_CNT_DARK (AE1_BASE + 0x0068) ++#define SEC_AE_ADDR_SPEC_CNT_SAT (AE1_BASE + 0x006c) ++#define SEC_AE_ADDR_SPEC_SUM_IR (AE1_BASE + 0x0070) ++#define SEC_AE_ADDR_DEBUG_0 (AE1_BASE + 0x0074) ++#define SEC_AE_ADDR_DEBUG_1 (AE1_BASE + 0x0078) ++#define SEC_AE_ADDR_DEBUG_2 (AE1_BASE + 0x007c) ++#define SEC_AE_ADDR_DEBUG_3 (AE1_BASE + 0x0080) ++#define SEC_AE_ADDR_DEBUG_4 (AE1_BASE + 0x0084) ++#define SEC_AE_ADDR_DEBUG_5 (AE1_BASE + 0x0088) ++#define SEC_AE_ADDR_DEBUG_6 (AE1_BASE + 0x008c) ++#define SEC_AE_ADDR_DEBUG_7 (AE1_BASE + 0x0090) ++#define SEC_AE_ADDR_DEBUG_8 (AE1_BASE + 0x0094) ++#define SEC_AE_ADDR_DEBUG_9 (AE1_BASE + 0x0098) ++#define SEC_AE_ADDR_DEBUG_10 (AE1_BASE + 0x009c) ++#define SEC_AE_ADDR_DEBUG_11 (AE1_BASE + 0x00a0) ++#define SEC_AE_ADDR_DEBUG_12 (AE1_BASE + 0x00a4) ++#define SEC_AE_ADDR_DEBUG_13 (AE1_BASE + 0x00a8) ++ ++//============================================================ ++// AWB ADDRESS ++//============================================================ ++#define MAIN_AWB_ADDR_SHD_CTRL (AWB0_BASE + 0x0000) ++#define MAIN_AWB_ADDR_ZONE_NUM_START (AWB0_BASE + 0x0004) ++#define MAIN_AWB_ADDR_HOR_ZONE_SIZE_14 (AWB0_BASE + 0x0008) ++#define MAIN_AWB_ADDR_HOR_ZONE_SIZE_58 (AWB0_BASE + 0x000c) ++#define MAIN_AWB_ADDR_HOR_ZONE_SIZE_912 (AWB0_BASE + 0x0010) ++#define MAIN_AWB_ADDR_HOR_ZONE_SIZE_1315 (AWB0_BASE + 0x0014) ++#define MAIN_AWB_ADDR_VER_ZONE_SIZE_14 (AWB0_BASE + 0x0018) ++#define MAIN_AWB_ADDR_VER_ZONE_SIZE_58 (AWB0_BASE + 0x001c) ++#define MAIN_AWB_ADDR_VER_ZONE_SIZE_912 (AWB0_BASE + 0x0020) ++#define MAIN_AWB_ADDR_VER_ZONE_SIZE_1315 (AWB0_BASE + 0x0024) ++#define MAIN_AWB_ADDR_RG_TH (AWB0_BASE + 0x0028) ++#define MAIN_AWB_ADDR_BG_TH (AWB0_BASE + 0x002c) ++#define MAIN_AWB_ADDR_K1_A1 (AWB0_BASE + 0x0030) ++#define MAIN_AWB_ADDR_K2_A2 (AWB0_BASE + 0x0034) ++#define MAIN_AWB_ADDR_LUM_TH_FREQ (AWB0_BASE + 0x0038) ++#define MAIN_AWB_ADDR_AWB_DMA_BASE_1 (AWB0_BASE + 0x003c) ++#define MAIN_AWB_ADDR_AWB_DMA_BASE_2 (AWB0_BASE + 0x0040) ++#define MAIN_AWB_ADDR_AWB_DMA_BASE_3 (AWB0_BASE + 0x0044) ++#define MAIN_AWB_ADDR_AWB_DMA_BASE_4 (AWB0_BASE + 0x0048) ++#define MAIN_AWB_ADDR_DMA_BASE_NUM (AWB0_BASE + 0x004c) ++#define MAIN_AWB_ADDR_DMA_INFO (AWB0_BASE + 0x0050) ++#define MAIN_AWB_ADDR_REMV_RG_INFO_0 (AWB0_BASE + 0x0054) ++#define MAIN_AWB_ADDR_REMV_RG_INFO_1 (AWB0_BASE + 0x0058) ++#define MAIN_AWB_ADDR_REMV_RG_INFO_2 (AWB0_BASE + 0x005c) ++#define MAIN_AWB_ADDR_REMV_RG_INFO_3 (AWB0_BASE + 0x0060) ++#define MAIN_AWB_ADDR_REMV_RG_INFO_4 (AWB0_BASE + 0x0064) ++#define MAIN_AWB_ADDR_REMV_BG_INFO_0 (AWB0_BASE + 0x0068) ++#define MAIN_AWB_ADDR_REMV_BG_INFO_1 (AWB0_BASE + 0x006c) ++#define MAIN_AWB_ADDR_REMV_BG_INFO_2 (AWB0_BASE + 0x0070) ++#define MAIN_AWB_ADDR_REMV_BG_INFO_3 (AWB0_BASE + 0x0074) ++#define MAIN_AWB_ADDR_REMV_BG_INFO_4 (AWB0_BASE + 0x0078) ++#define MAIN_AWB_ADDR_REMV_RADIUS_INFO_0 (AWB0_BASE + 0x007c) ++#define MAIN_AWB_ADDR_REMV_RADIUS_INFO_1 (AWB0_BASE + 0x0080) ++#define MAIN_AWB_ADDR_REMV_RADIUS_INFO_2 (AWB0_BASE + 0x0084) ++#define MAIN_AWB_ADDR_REMV_RADIUS_INFO_3 (AWB0_BASE + 0x0088) ++#define MAIN_AWB_ADDR_REMV_RADIUS_INFO_4 (AWB0_BASE + 0x008c) ++#define MAIN_AWB_ADDR_REMV_RADIUS_INFO_5 (AWB0_BASE + 0x0090) ++#define MAIN_AWB_ADDR_REMV_RADIUS_INFO_6 (AWB0_BASE + 0x0094) ++#define MAIN_AWB_ADDR_REMV_RADIUS_INFO_7 (AWB0_BASE + 0x0098) ++#define MAIN_AWB_ADDR_REMV_RADIUS_INFO_8 (AWB0_BASE + 0x009c) ++#define MAIN_AWB_ADDR_REMV_RADIUS_INFO_9 (AWB0_BASE + 0x00a0) ++#define MAIN_AWB_ADDR_SPEC_ZONE_INFO_0 (AWB0_BASE + 0x00a4) ++#define MAIN_AWB_ADDR_SPEC_ZONE_INFO_1 (AWB0_BASE + 0x00a8) ++#define MAIN_AWB_ADDR_R_SUM_SPEC (AWB0_BASE + 0x00ac) ++#define MAIN_AWB_ADDR_G_SUM_SPEC (AWB0_BASE + 0x00b0) ++#define MAIN_AWB_ADDR_B_SUM_SPEC (AWB0_BASE + 0x00b4) ++#define MAIN_AWB_ADDR_IR_SUM_SPEC (AWB0_BASE + 0x00b8) ++#define MAIN_AWB_ADDR_PIX_SUM_SPEC (AWB0_BASE + 0x00bc) ++#define MAIN_AWB_ADDR_DEBUG_0 (AWB0_BASE + 0x00c0) ++#define MAIN_AWB_ADDR_DEBUG_1 (AWB0_BASE + 0x00c4) ++#define MAIN_AWB_ADDR_DEBUG_2 (AWB0_BASE + 0x00c8) ++#define MAIN_AWB_ADDR_DEBUG_3 (AWB0_BASE + 0x00cc) ++#define MAIN_AWB_ADDR_DEBUG_4 (AWB0_BASE + 0x00d0) ++#define MAIN_AWB_ADDR_DEBUG_5 (AWB0_BASE + 0x00d4) ++#define MAIN_AWB_ADDR_DEBUG_6 (AWB0_BASE + 0x00d8) ++#define MAIN_AWB_ADDR_DEBUG_7 (AWB0_BASE + 0x00dc) ++#define MAIN_AWB_ADDR_DEBUG_8 (AWB0_BASE + 0x00e0) ++#define MAIN_AWB_ADDR_DEBUG_9 (AWB0_BASE + 0x00e4) ++#define MAIN_AWB_ADDR_DEBUG_10 (AWB0_BASE + 0x00e8) ++#define MAIN_AWB_ADDR_DEBUG_11 (AWB0_BASE + 0x00ec) ++#define MAIN_AWB_ADDR_DEBUG_12 (AWB0_BASE + 0x00f0) ++#define MAIN_AWB_ADDR_DEBUG_13 (AWB0_BASE + 0x00f4) ++#define MAIN_AWB_ADDR_DEBUG_14 (AWB0_BASE + 0x00f8) ++ ++#define SEC_AWB_ADDR_SHD_CTRL (AWB1_BASE + 0x0000) ++#define SEC_AWB_ADDR_ZONE_NUM_START (AWB1_BASE + 0x0004) ++#define SEC_AWB_ADDR_HOR_ZONE_SIZE_14 (AWB1_BASE + 0x0008) ++#define SEC_AWB_ADDR_HOR_ZONE_SIZE_58 (AWB1_BASE + 0x000c) ++#define SEC_AWB_ADDR_HOR_ZONE_SIZE_912 (AWB1_BASE + 0x0010) ++#define SEC_AWB_ADDR_HOR_ZONE_SIZE_1315 (AWB1_BASE + 0x0014) ++#define SEC_AWB_ADDR_VER_ZONE_SIZE_14 (AWB1_BASE + 0x0018) ++#define SEC_AWB_ADDR_VER_ZONE_SIZE_58 (AWB1_BASE + 0x001c) ++#define SEC_AWB_ADDR_VER_ZONE_SIZE_912 (AWB1_BASE + 0x0020) ++#define SEC_AWB_ADDR_VER_ZONE_SIZE_1315 (AWB1_BASE + 0x0024) ++#define SEC_AWB_ADDR_RG_TH (AWB1_BASE + 0x0028) ++#define SEC_AWB_ADDR_BG_TH (AWB1_BASE + 0x002c) ++#define SEC_AWB_ADDR_K1_A1 (AWB1_BASE + 0x0030) ++#define SEC_AWB_ADDR_K2_A2 (AWB1_BASE + 0x0034) ++#define SEC_AWB_ADDR_LUM_TH_FREQ (AWB1_BASE + 0x0038) ++#define SEC_AWB_ADDR_AWB_DMA_BASE_1 (AWB1_BASE + 0x003c) ++#define SEC_AWB_ADDR_AWB_DMA_BASE_2 (AWB1_BASE + 0x0040) ++#define SEC_AWB_ADDR_AWB_DMA_BASE_3 (AWB1_BASE + 0x0044) ++#define SEC_AWB_ADDR_AWB_DMA_BASE_4 (AWB1_BASE + 0x0048) ++#define SEC_AWB_ADDR_DMA_BASE_NUM (AWB1_BASE + 0x004c) ++#define SEC_AWB_ADDR_DMA_INFO (AWB1_BASE + 0x0050) ++#define SEC_AWB_ADDR_REMV_RG_INFO_0 (AWB1_BASE + 0x0054) ++#define SEC_AWB_ADDR_REMV_RG_INFO_1 (AWB1_BASE + 0x0058) ++#define SEC_AWB_ADDR_REMV_RG_INFO_2 (AWB1_BASE + 0x005c) ++#define SEC_AWB_ADDR_REMV_RG_INFO_3 (AWB1_BASE + 0x0060) ++#define SEC_AWB_ADDR_REMV_RG_INFO_4 (AWB1_BASE + 0x0064) ++#define SEC_AWB_ADDR_REMV_BG_INFO_0 (AWB1_BASE + 0x0068) ++#define SEC_AWB_ADDR_REMV_BG_INFO_1 (AWB1_BASE + 0x006c) ++#define SEC_AWB_ADDR_REMV_BG_INFO_2 (AWB1_BASE + 0x0070) ++#define SEC_AWB_ADDR_REMV_BG_INFO_3 (AWB1_BASE + 0x0074) ++#define SEC_AWB_ADDR_REMV_BG_INFO_4 (AWB1_BASE + 0x0078) ++#define SEC_AWB_ADDR_REMV_RADIUS_INFO_0 (AWB1_BASE + 0x007c) ++#define SEC_AWB_ADDR_REMV_RADIUS_INFO_1 (AWB1_BASE + 0x0080) ++#define SEC_AWB_ADDR_REMV_RADIUS_INFO_2 (AWB1_BASE + 0x0084) ++#define SEC_AWB_ADDR_REMV_RADIUS_INFO_3 (AWB1_BASE + 0x0088) ++#define SEC_AWB_ADDR_REMV_RADIUS_INFO_4 (AWB1_BASE + 0x008c) ++#define SEC_AWB_ADDR_REMV_RADIUS_INFO_5 (AWB1_BASE + 0x0090) ++#define SEC_AWB_ADDR_REMV_RADIUS_INFO_6 (AWB1_BASE + 0x0094) ++#define SEC_AWB_ADDR_REMV_RADIUS_INFO_7 (AWB1_BASE + 0x0098) ++#define SEC_AWB_ADDR_REMV_RADIUS_INFO_8 (AWB1_BASE + 0x009c) ++#define SEC_AWB_ADDR_REMV_RADIUS_INFO_9 (AWB1_BASE + 0x00a0) ++#define SEC_AWB_ADDR_SPEC_ZONE_INFO_0 (AWB1_BASE + 0x00a4) ++#define SEC_AWB_ADDR_SPEC_ZONE_INFO_1 (AWB1_BASE + 0x00a8) ++#define SEC_AWB_ADDR_R_SUM_SPEC (AWB1_BASE + 0x00ac) ++#define SEC_AWB_ADDR_G_SUM_SPEC (AWB1_BASE + 0x00b0) ++#define SEC_AWB_ADDR_B_SUM_SPEC (AWB1_BASE + 0x00b4) ++#define SEC_AWB_ADDR_IR_SUM_SPEC (AWB1_BASE + 0x00b8) ++#define SEC_AWB_ADDR_PIX_SUM_SPEC (AWB1_BASE + 0x00bc) ++#define SEC_AWB_ADDR_DEBUG_0 (AWB1_BASE + 0x00c0) ++#define SEC_AWB_ADDR_DEBUG_1 (AWB1_BASE + 0x00c4) ++#define SEC_AWB_ADDR_DEBUG_2 (AWB1_BASE + 0x00c8) ++#define SEC_AWB_ADDR_DEBUG_3 (AWB1_BASE + 0x00cc) ++#define SEC_AWB_ADDR_DEBUG_4 (AWB1_BASE + 0x00d0) ++#define SEC_AWB_ADDR_DEBUG_5 (AWB1_BASE + 0x00d4) ++#define SEC_AWB_ADDR_DEBUG_6 (AWB1_BASE + 0x00d8) ++#define SEC_AWB_ADDR_DEBUG_7 (AWB1_BASE + 0x00dc) ++#define SEC_AWB_ADDR_DEBUG_8 (AWB1_BASE + 0x00e0) ++#define SEC_AWB_ADDR_DEBUG_9 (AWB1_BASE + 0x00e4) ++#define SEC_AWB_ADDR_DEBUG_10 (AWB1_BASE + 0x00e8) ++#define SEC_AWB_ADDR_DEBUG_11 (AWB1_BASE + 0x00ec) ++#define SEC_AWB_ADDR_DEBUG_12 (AWB1_BASE + 0x00f0) ++#define SEC_AWB_ADDR_DEBUG_13 (AWB1_BASE + 0x00f4) ++#define SEC_AWB_ADDR_DEBUG_14 (AWB1_BASE + 0x00f8) ++ ++//============================================================ ++// AF ADDRESS ++//============================================================ ++#define AF_BASE1 (AF_BASE + 0x200) ++#define MAIN_AF_ADDR_SHD_CTRL (AF_BASE + 0x0000) ++#define MAIN_AF_ADDR_ZONE_NUM_START (AF_BASE + 0x0004) ++#define MAIN_AF_ADDR_HOR_ZONE_SIZE_1 (AF_BASE + 0x0008) ++#define MAIN_AF_ADDR_HOR_ZONE_SIZE_3 (AF_BASE + 0x000c) ++#define MAIN_AF_ADDR_HOR_ZONE_SIZE_5 (AF_BASE + 0x0010) ++#define MAIN_AF_ADDR_HOR_ZONE_SIZE_7 (AF_BASE + 0x0014) ++#define MAIN_AF_ADDR_HOR_ZONE_SIZE_9 (AF_BASE + 0x0018) ++#define MAIN_AF_ADDR_HOR_ZONE_SIZE_11 (AF_BASE + 0x001c) ++#define MAIN_AF_ADDR_HOR_ZONE_SIZE_13 (AF_BASE + 0x0020) ++#define MAIN_AF_ADDR_HOR_ZONE_SIZE_15 (AF_BASE + 0x0024) ++#define MAIN_AF_ADDR_VER_ZONE_SIZE_1 (AF_BASE + 0x0028) ++#define MAIN_AF_ADDR_VER_ZONE_SIZE_5 (AF_BASE + 0x002c) ++#define MAIN_AF_ADDR_VER_ZONE_SIZE_9 (AF_BASE + 0x0030) ++#define MAIN_AF_ADDR_VER_ZONE_SIZE_13 (AF_BASE + 0x0034) ++#define MAIN_AF_ADDR_FREQ_IIR_EN_LUM_TH (AF_BASE + 0x0038) ++#define MAIN_AF_ADDR_LDG_COR_EN (AF_BASE + 0x003c) ++#define MAIN_AF_ADDR_FIR0_G1_G2 (AF_BASE + 0x0040) ++#define MAIN_AF_ADDR_FIR0_G3_G4 (AF_BASE + 0x0044) ++#define MAIN_AF_ADDR_FIR0_G5 (AF_BASE + 0x0048) ++#define MAIN_AF_ADDR_FIR1_G1_G2 (AF_BASE + 0x004c) ++#define MAIN_AF_ADDR_FIR1_G3_G4 (AF_BASE + 0x0050) ++#define MAIN_AF_ADDR_FIR1_G5 (AF_BASE + 0x0054) ++#define MAIN_AF_ADDR_IIR0_G1_G3 (AF_BASE + 0x0058) ++#define MAIN_AF_ADDR_IIR0_G4_G5 (AF_BASE + 0x005c) ++#define MAIN_AF_ADDR_IIR0_G6_G8 (AF_BASE + 0x0060) ++#define MAIN_AF_ADDR_IIR0_G9_G10 (AF_BASE + 0x0064) ++#define MAIN_AF_ADDR_IIR1_G1_G3 (AF_BASE + 0x0068) ++#define MAIN_AF_ADDR_IIR1_G4_G5 (AF_BASE + 0x006c) ++#define MAIN_AF_ADDR_IIR1_G6_G8 (AF_BASE + 0x0070) ++#define MAIN_AF_ADDR_IIR1_G9_G10 (AF_BASE + 0x0074) ++#define MAIN_AF_ADDR_LDG_FIR0_LOW (AF_BASE + 0x0078) ++#define MAIN_AF_ADDR_LDG_FIR0_HIGH (AF_BASE + 0x007c) ++#define MAIN_AF_ADDR_LDG_FIR1_LOW (AF_BASE + 0x0080) ++#define MAIN_AF_ADDR_LDG_FIR1_HIGH (AF_BASE + 0x0084) ++#define MAIN_AF_ADDR_LDG_IIR0_LOW (AF_BASE + 0x0088) ++#define MAIN_AF_ADDR_LDG_IIR0_HIGH (AF_BASE + 0x008c) ++#define MAIN_AF_ADDR_LDG_IIR1_LOW (AF_BASE + 0x0090) ++#define MAIN_AF_ADDR_LDG_IIR1_HIGH (AF_BASE + 0x0094) ++#define MAIN_AF_ADDR_LDG_FIR_GAIN (AF_BASE + 0x0098) ++#define MAIN_AF_ADDR_LDG_IIR_GAIN (AF_BASE + 0x009c) ++#define MAIN_AF_ADDR_COR_F0_TH_LH (AF_BASE + 0x00a0) ++#define MAIN_AF_ADDR_COR_F1_TH_LH (AF_BASE + 0x00a4) ++#define MAIN_AF_ADDR_COR_I0_TH_LH (AF_BASE + 0x00a8) ++#define MAIN_AF_ADDR_COR_I1_TH_LH (AF_BASE + 0x00ac) ++#define MAIN_AF_ADDR_STAT_MODE_EN (AF_BASE + 0x00b0) ++#define MAIN_AF_ADDR_STAT_TH_F (AF_BASE + 0x00b4) ++#define MAIN_AF_ADDR_STAT_TH_I (AF_BASE + 0x00b8) ++#define MAIN_AF_ADDR_STAT_SLP_LIM_F0 (AF_BASE + 0x00bc) ++#define MAIN_AF_ADDR_STAT_SLP_LIM_F1 (AF_BASE + 0x00c0) ++#define MAIN_AF_ADDR_STAT_SLP_LIM_I0 (AF_BASE + 0x00c4) ++#define MAIN_AF_ADDR_STAT_SLP_LIM_I1 (AF_BASE + 0x00c8) ++#define MAIN_AF_ADDR_AF_DMA_BASE_1 (AF_BASE + 0x00cc) ++#define MAIN_AF_ADDR_AF_DMA_BASE_2 (AF_BASE + 0x00d0) ++#define MAIN_AF_ADDR_AF_DMA_BASE_3 (AF_BASE + 0x00d4) ++#define MAIN_AF_ADDR_AF_DMA_BASE_4 (AF_BASE + 0x00d8) ++#define MAIN_AF_ADDR_DMA_BASE_NUM (AF_BASE + 0x00dc) ++#define MAIN_AF_ADDR_DMA_INFO (AF_BASE + 0x00e0) ++#define MAIN_AF_ADDR_DEBUG_0 (AF_BASE + 0x00e4) ++#define MAIN_AF_ADDR_DEBUG_1 (AF_BASE + 0x00e8) ++#define MAIN_AF_ADDR_DEBUG_2 (AF_BASE + 0x00ec) ++#define MAIN_AF_ADDR_DEBUG_3 (AF_BASE + 0x00f0) ++ ++#define SEC_AF_ADDR_SHD_CTRL (AF_BASE1 + 0x0000) ++#define SEC_AF_ADDR_ZONE_NUM_START (AF_BASE1 + 0x0004) ++#define SEC_AF_ADDR_HOR_ZONE_SIZE_1 (AF_BASE1 + 0x0008) ++#define SEC_AF_ADDR_HOR_ZONE_SIZE_3 (AF_BASE1 + 0x000c) ++#define SEC_AF_ADDR_HOR_ZONE_SIZE_5 (AF_BASE1 + 0x0010) ++#define SEC_AF_ADDR_HOR_ZONE_SIZE_7 (AF_BASE1 + 0x0014) ++#define SEC_AF_ADDR_HOR_ZONE_SIZE_9 (AF_BASE1 + 0x0018) ++#define SEC_AF_ADDR_HOR_ZONE_SIZE_11 (AF_BASE1 + 0x001c) ++#define SEC_AF_ADDR_HOR_ZONE_SIZE_13 (AF_BASE1 + 0x0020) ++#define SEC_AF_ADDR_HOR_ZONE_SIZE_15 (AF_BASE1 + 0x0024) ++#define SEC_AF_ADDR_VER_ZONE_SIZE_1 (AF_BASE1 + 0x0028) ++#define SEC_AF_ADDR_VER_ZONE_SIZE_5 (AF_BASE1 + 0x002c) ++#define SEC_AF_ADDR_VER_ZONE_SIZE_9 (AF_BASE1 + 0x0030) ++#define SEC_AF_ADDR_VER_ZONE_SIZE_13 (AF_BASE1 + 0x0034) ++#define SEC_AF_ADDR_FREQ_IIR_EN_LUM_TH (AF_BASE1 + 0x0038) ++#define SEC_AF_ADDR_LDG_COR_EN (AF_BASE1 + 0x003c) ++#define SEC_AF_ADDR_FIR0_G1_G2 (AF_BASE1 + 0x0040) ++#define SEC_AF_ADDR_FIR0_G3_G4 (AF_BASE1 + 0x0044) ++#define SEC_AF_ADDR_FIR0_G5 (AF_BASE1 + 0x0048) ++#define SEC_AF_ADDR_FIR1_G1_G2 (AF_BASE1 + 0x004c) ++#define SEC_AF_ADDR_FIR1_G3_G4 (AF_BASE1 + 0x0050) ++#define SEC_AF_ADDR_FIR1_G5 (AF_BASE1 + 0x0054) ++#define SEC_AF_ADDR_IIR0_G1_G3 (AF_BASE1 + 0x0058) ++#define SEC_AF_ADDR_IIR0_G4_G5 (AF_BASE1 + 0x005c) ++#define SEC_AF_ADDR_IIR0_G6_G8 (AF_BASE1 + 0x0060) ++#define SEC_AF_ADDR_IIR0_G9_G10 (AF_BASE1 + 0x0064) ++#define SEC_AF_ADDR_IIR1_G1_G3 (AF_BASE1 + 0x0068) ++#define SEC_AF_ADDR_IIR1_G4_G5 (AF_BASE1 + 0x006c) ++#define SEC_AF_ADDR_IIR1_G6_G8 (AF_BASE1 + 0x0070) ++#define SEC_AF_ADDR_IIR1_G9_G10 (AF_BASE1 + 0x0074) ++#define SEC_AF_ADDR_LDG_FIR0_LOW (AF_BASE1 + 0x0078) ++#define SEC_AF_ADDR_LDG_FIR0_HIGH (AF_BASE1 + 0x007c) ++#define SEC_AF_ADDR_LDG_FIR1_LOW (AF_BASE1 + 0x0080) ++#define SEC_AF_ADDR_LDG_FIR1_HIGH (AF_BASE1 + 0x0084) ++#define SEC_AF_ADDR_LDG_IIR0_LOW (AF_BASE1 + 0x0088) ++#define SEC_AF_ADDR_LDG_IIR0_HIGH (AF_BASE1 + 0x008c) ++#define SEC_AF_ADDR_LDG_IIR1_LOW (AF_BASE1 + 0x0090) ++#define SEC_AF_ADDR_LDG_IIR1_HIGH (AF_BASE1 + 0x0094) ++#define SEC_AF_ADDR_LDG_FIR_GAIN (AF_BASE1 + 0x0098) ++#define SEC_AF_ADDR_LDG_IIR_GAIN (AF_BASE1 + 0x009c) ++#define SEC_AF_ADDR_COR_F0_TH_LH (AF_BASE1 + 0x00a0) ++#define SEC_AF_ADDR_COR_F1_TH_LH (AF_BASE1 + 0x00a4) ++#define SEC_AF_ADDR_COR_I0_TH_LH (AF_BASE1 + 0x00a8) ++#define SEC_AF_ADDR_COR_I1_TH_LH (AF_BASE1 + 0x00ac) ++#define SEC_AF_ADDR_STAT_MODE_EN (AF_BASE1 + 0x00b0) ++#define SEC_AF_ADDR_STAT_TH_F (AF_BASE1 + 0x00b4) ++#define SEC_AF_ADDR_STAT_TH_I (AF_BASE1 + 0x00b8) ++#define SEC_AF_ADDR_STAT_SLP_LIM_F0 (AF_BASE1 + 0x00bc) ++#define SEC_AF_ADDR_STAT_SLP_LIM_F1 (AF_BASE1 + 0x00c0) ++#define SEC_AF_ADDR_STAT_SLP_LIM_I0 (AF_BASE1 + 0x00c4) ++#define SEC_AF_ADDR_STAT_SLP_LIM_I1 (AF_BASE1 + 0x00c8) ++#define SEC_AF_ADDR_AF_DMA_BASE_1 (AF_BASE1 + 0x00cc) ++#define SEC_AF_ADDR_AF_DMA_BASE_2 (AF_BASE1 + 0x00d0) ++#define SEC_AF_ADDR_AF_DMA_BASE_3 (AF_BASE1 + 0x00d4) ++#define SEC_AF_ADDR_AF_DMA_BASE_4 (AF_BASE1 + 0x00d8) ++#define SEC_AF_ADDR_DMA_BASE_NUM (AF_BASE1 + 0x00dc) ++#define SEC_AF_ADDR_DMA_INFO (AF_BASE1 + 0x00e0) ++#define SEC_AF_ADDR_DEBUG_0 (AF_BASE1 + 0x00e4) ++#define SEC_AF_ADDR_DEBUG_1 (AF_BASE1 + 0x00e8) ++#define SEC_AF_ADDR_DEBUG_2 (AF_BASE1 + 0x00ec) ++#define SEC_AF_ADDR_DEBUG_3 (AF_BASE1 + 0x00f0) ++ ++//============================================================ ++// GSM ADDRESS ++//============================================================ ++#define GSM0_ADDR_BUF_CLR (GSM0_BASE + 0x0000) ++#define GSM0_ADDR_BUF_STATE (GSM0_BASE + 0x0004) ++#define GSM0_ADDR_FRM_RATE (GSM0_BASE + 0x0010) ++#define GSM0_ADDR_ADJUST (GSM0_BASE + 0x0020) ++#define GSM0_ADDR_DBGSIG0 (GSM0_BASE + 0x0030) ++ ++#define GSM1_ADDR_BUF_CLR (GSM1_BASE + 0x0000) ++#define GSM1_ADDR_BUF_STATE (GSM1_BASE + 0x0004) ++#define GSM1_ADDR_FRM_RATE (GSM1_BASE + 0x0010) ++#define GSM1_ADDR_ADJUST (GSM1_BASE + 0x0020) ++#define GSM1_ADDR_DBGSIG0 (GSM1_BASE + 0x0030) ++ ++//============================================================ ++// IPC ADDRESS ++//============================================================ ++#define IPC_ADDR_IP_TRIG (IPC_BASE + 0x0000) ++#define IPC_ADDR_SHD_CTRL (IPC_BASE + 0x0004) ++#define IPC_ADDR_CONTROL (IPC_BASE + 0x0008) ++#define IPC_ADDR_CHK_TRIG (IPC_BASE + 0x000c) ++#define IPC_ADDR_DUAL_CHN_SWITCH_CON (IPC_BASE + 0x0010) ++#define IPC_ADDR_DUAL_CHN_SWITCH_CON_NUM (IPC_BASE + 0x0014) ++#define IPC_ADDR_DUAL_CHN_SEL (IPC_BASE + 0x0018) ++#define IPC_ADDR_V0_NEAR_FULL (IPC_BASE + 0x001c) ++#define IPC_ADDR_V0_NEAR_FULL_THRES (IPC_BASE + 0x0020) ++#define IPC_ADDR_V1_NEAR_FULL (IPC_BASE + 0x0024) ++#define IPC_ADDR_V1_NEAR_FULL_THRES (IPC_BASE + 0x0028) ++#define IPC_ADDR_DF_CHN_COMP_EN (IPC_BASE + 0x002c) ++#define IPC_ADDR_DF_CH0_ADDR (IPC_BASE + 0x0030) ++#define IPC_ADDR_DF_CH1_ADDR (IPC_BASE + 0x0034) ++#define IPC_ADDR_DF_CH2_ADDR (IPC_BASE + 0x0038) ++#define IPC_ADDR_DF_CH3_ADDR (IPC_BASE + 0x003c) ++#define IPC_ADDR_DF_CH0_SIZE (IPC_BASE + 0x0040) ++#define IPC_ADDR_DF_CH1_SIZE (IPC_BASE + 0x0044) ++#define IPC_ADDR_DF_CH2_SIZE (IPC_BASE + 0x0048) ++#define IPC_ADDR_DF_CH3_SIZE (IPC_BASE + 0x004c) ++#define IPC_ADDR_YUV_OFFSET (IPC_BASE + 0x0050) ++#define IPC_ADDR_WDMA_THRES_0 (IPC_BASE + 0x0054) ++#define IPC_ADDR_WDMA_THRES_1 (IPC_BASE + 0x0058) ++#define IPC_ADDR_RDMA_THRES (IPC_BASE + 0x005c) ++#define IPC_ADDR_DUAL_M3_ORI_MODE (IPC_BASE + 0x0060) ++#define IPC_ADDR_M3_V0_URGENT_THRES (IPC_BASE + 0x0064) ++#define IPC_ADDR_M3_V1_URGENT_THRES (IPC_BASE + 0x0068) ++#define IPC_ADDR_M3_V0_V0_THRES (IPC_BASE + 0x006c) ++#define IPC_ADDR_M3_V0_V1_THRES (IPC_BASE + 0x0070) ++#define IPC_ADDR_M3_V1_V0_THRES (IPC_BASE + 0x0074) ++#define IPC_ADDR_M3_V1_V1_THRES (IPC_BASE + 0x0078) ++#define IPC_ADDR_V0_CH0_IN_CNT (IPC_BASE + 0x0100) ++#define IPC_ADDR_V0_CH1_IN_CNT (IPC_BASE + 0x0104) ++#define IPC_ADDR_V1_CH0_IN_CNT (IPC_BASE + 0x0108) ++#define IPC_ADDR_V1_CH1_IN_CNT (IPC_BASE + 0x010c) ++#define IPC_ADDR_V0_CH0_ERR_CNT (IPC_BASE + 0x0110) ++#define IPC_ADDR_V0_CH1_ERR_CNT (IPC_BASE + 0x0114) ++#define IPC_ADDR_V1_CH0_ERR_CNT (IPC_BASE + 0x0118) ++#define IPC_ADDR_V1_CH1_ERR_CNT (IPC_BASE + 0x011c) ++#define IPC_ADDR_ERR_CHN_INDEX (IPC_BASE + 0x0120) ++#define IPC_ADDR_V0_CH0_CHK_FR_CNT (IPC_BASE + 0x0124) ++#define IPC_ADDR_V0_CH1_CHK_FR_CNT (IPC_BASE + 0x0128) ++#define IPC_ADDR_V1_CH0_CHK_FR_CNT (IPC_BASE + 0x012c) ++#define IPC_ADDR_V1_CH1_CHK_FR_CNT (IPC_BASE + 0x0130) ++#define IPC_ADDR_CHN_OUT_CNT (IPC_BASE + 0x0134) ++#define IPC_ADDR_IN_OUT_STATE (IPC_BASE + 0x0138) ++#define IPC_ADDR_IN_CH01_FIFO_CNT (IPC_BASE + 0x013c) ++#define IPC_ADDR_IN_CH2_FIFO_CNT (IPC_BASE + 0x0140) ++#define IPC_ADDR_COMP_CH0_DMA_CNT (IPC_BASE + 0x0144) ++#define IPC_ADDR_COMP_CH1_DMA_CNT (IPC_BASE + 0x0148) ++#define IPC_ADDR_COMP_CH2_DMA_CNT (IPC_BASE + 0x014c) ++#define IPC_ADDR_COMP_CH3_DMA_CNT (IPC_BASE + 0x0150) ++#define IPC_ADDR_FR_PRO_NUM (IPC_BASE + 0x0154) ++#define IPC_ADDR_CH0_FR_INTERVAL (IPC_BASE + 0x0158) ++#define IPC_ADDR_CH1_FR_INTERVAL (IPC_BASE + 0x015c) ++ ++//============================================================ ++// MCFG ADDRESS ++//============================================================ ++#define MCFG_ADDR_S0_DPC_CNTL (MCFG_BASE + 0x0000) ++#define MCFG_ADDR_S0_DPC_WCHNL (MCFG_BASE + 0x0004) ++#define MCFG_ADDR_S0_DPC_RCHNL (MCFG_BASE + 0x0008) ++#define MCFG_ADDR_S0_DPC_RESP (MCFG_BASE + 0x000c) ++#define MCFG_ADDR_S1_DPC_CNTL (MCFG_BASE + 0x0010) ++#define MCFG_ADDR_S1_DPC_WCHNL (MCFG_BASE + 0x0014) ++#define MCFG_ADDR_S1_DPC_RCHNL (MCFG_BASE + 0x0018) ++#define MCFG_ADDR_S1_DPC_RESP (MCFG_BASE + 0x001c) ++#define MCFG_ADDR_S0_LSC_CNTL (MCFG_BASE + 0x0020) ++#define MCFG_ADDR_S0_LSC_WCHNL (MCFG_BASE + 0x0024) ++#define MCFG_ADDR_S0_LSC_RCHNL (MCFG_BASE + 0x0028) ++#define MCFG_ADDR_S0_LSC_RESP (MCFG_BASE + 0x002c) ++#define MCFG_ADDR_S1_LSC_CNTL (MCFG_BASE + 0x0030) ++#define MCFG_ADDR_S1_LSC_WCHNL (MCFG_BASE + 0x0034) ++#define MCFG_ADDR_S1_LSC_RCHNL (MCFG_BASE + 0x0038) ++#define MCFG_ADDR_S1_LSC_RESP (MCFG_BASE + 0x003c) ++#define MCFG_ADDR_S0_RGAMMA_CNTL (MCFG_BASE + 0x0040) ++#define MCFG_ADDR_S0_RGAMMA_WCHNL (MCFG_BASE + 0x0044) ++#define MCFG_ADDR_S0_RGAMMA_RCHNL (MCFG_BASE + 0x0048) ++#define MCFG_ADDR_S0_RGAMMA_RESP (MCFG_BASE + 0x004c) ++#define MCFG_ADDR_S1_RGAMMA_CNTL (MCFG_BASE + 0x0050) ++#define MCFG_ADDR_S1_RGAMMA_WCHNL (MCFG_BASE + 0x0054) ++#define MCFG_ADDR_S1_RGAMMA_RCHNL (MCFG_BASE + 0x0058) ++#define MCFG_ADDR_S1_RGAMMA_RESP (MCFG_BASE + 0x005c) ++#define MCFG_ADDR_S0_BGAMMA_CNTL (MCFG_BASE + 0x0060) ++#define MCFG_ADDR_S0_BGAMMA_WCHNL (MCFG_BASE + 0x0064) ++#define MCFG_ADDR_S0_BGAMMA_RCHNL (MCFG_BASE + 0x0068) ++#define MCFG_ADDR_S0_BGAMMA_RESP (MCFG_BASE + 0x006c) ++#define MCFG_ADDR_S1_BGAMMA_CNTL (MCFG_BASE + 0x0070) ++#define MCFG_ADDR_S1_BGAMMA_WCHNL (MCFG_BASE + 0x0074) ++#define MCFG_ADDR_S1_BGAMMA_RCHNL (MCFG_BASE + 0x0078) ++#define MCFG_ADDR_S1_BGAMMA_RESP (MCFG_BASE + 0x007c) ++#define MCFG_ADDR_S0_GGAMMA_CNTL (MCFG_BASE + 0x0080) ++#define MCFG_ADDR_S0_GGAMMA_WCHNL (MCFG_BASE + 0x0084) ++#define MCFG_ADDR_S0_GGAMMA_RCHNL (MCFG_BASE + 0x0088) ++#define MCFG_ADDR_S0_GGAMMA_RESP (MCFG_BASE + 0x008c) ++#define MCFG_ADDR_S1_GGAMMA_CNTL (MCFG_BASE + 0x0090) ++#define MCFG_ADDR_S1_GGAMMA_WCHNL (MCFG_BASE + 0x0094) ++#define MCFG_ADDR_S1_GGAMMA_RCHNL (MCFG_BASE + 0x0098) ++#define MCFG_ADDR_S1_GGAMMA_RESP (MCFG_BASE + 0x009c) ++#define MCFG_ADDR_S0_DEFOG_CNTL (MCFG_BASE + 0x00a0) ++#define MCFG_ADDR_S0_DEFOG_WCHNL (MCFG_BASE + 0x00a4) ++#define MCFG_ADDR_S0_DEFOG_RCHNL (MCFG_BASE + 0x00a8) ++#define MCFG_ADDR_S0_DEFOG_RESP (MCFG_BASE + 0x00ac) ++#define MCFG_ADDR_S1_DEFOG_CNTL (MCFG_BASE + 0x00b0) ++#define MCFG_ADDR_S1_DEFOG_WCHNL (MCFG_BASE + 0x00b4) ++#define MCFG_ADDR_S1_DEFOG_RCHNL (MCFG_BASE + 0x00b8) ++#define MCFG_ADDR_S1_DEFOG_RESP (MCFG_BASE + 0x00bc) ++#define MCFG_ADDR_S0_CLMH0_CNTL (MCFG_BASE + 0x00c0) ++#define MCFG_ADDR_S0_CLMH0_WCHNL (MCFG_BASE + 0x00c4) ++#define MCFG_ADDR_S0_CLMH0_RCHNL (MCFG_BASE + 0x00c8) ++#define MCFG_ADDR_S0_CLMH0_RESP (MCFG_BASE + 0x00cc) ++#define MCFG_ADDR_S1_CLMH0_CNTL (MCFG_BASE + 0x00d0) ++#define MCFG_ADDR_S1_CLMH0_WCHNL (MCFG_BASE + 0x00d4) ++#define MCFG_ADDR_S1_CLMH0_RCHNL (MCFG_BASE + 0x00d8) ++#define MCFG_ADDR_S1_CLMH0_RESP (MCFG_BASE + 0x00dc) ++#define MCFG_ADDR_S0_CLMH1_CNTL (MCFG_BASE + 0x00e0) ++#define MCFG_ADDR_S0_CLMH1_WCHNL (MCFG_BASE + 0x00e4) ++#define MCFG_ADDR_S0_CLMH1_RCHNL (MCFG_BASE + 0x00e8) ++#define MCFG_ADDR_S0_CLMH1_RESP (MCFG_BASE + 0x00ec) ++#define MCFG_ADDR_S1_CLMH1_CNTL (MCFG_BASE + 0x00f0) ++#define MCFG_ADDR_S1_CLMH1_WCHNL (MCFG_BASE + 0x00f4) ++#define MCFG_ADDR_S1_CLMH1_RCHNL (MCFG_BASE + 0x00f8) ++#define MCFG_ADDR_S1_CLMH1_RESP (MCFG_BASE + 0x00fc) ++#define MCFG_ADDR_S0_CLMS0_CNTL (MCFG_BASE + 0x0100) ++#define MCFG_ADDR_S0_CLMS0_WCHNL (MCFG_BASE + 0x0104) ++#define MCFG_ADDR_S0_CLMS0_RCHNL (MCFG_BASE + 0x0108) ++#define MCFG_ADDR_S0_CLMS0_RESP (MCFG_BASE + 0x010c) ++#define MCFG_ADDR_S1_CLMS0_CNTL (MCFG_BASE + 0x0110) ++#define MCFG_ADDR_S1_CLMS0_WCHNL (MCFG_BASE + 0x0114) ++#define MCFG_ADDR_S1_CLMS0_RCHNL (MCFG_BASE + 0x0118) ++#define MCFG_ADDR_S1_CLMS0_RESP (MCFG_BASE + 0x011c) ++#define MCFG_ADDR_S0_CLMS1_CNTL (MCFG_BASE + 0x0120) ++#define MCFG_ADDR_S0_CLMS1_WCHNL (MCFG_BASE + 0x0124) ++#define MCFG_ADDR_S0_CLMS1_RCHNL (MCFG_BASE + 0x0128) ++#define MCFG_ADDR_S0_CLMS1_RESP (MCFG_BASE + 0x012c) ++#define MCFG_ADDR_S1_CLMS1_CNTL (MCFG_BASE + 0x0130) ++#define MCFG_ADDR_S1_CLMS1_WCHNL (MCFG_BASE + 0x0134) ++#define MCFG_ADDR_S1_CLMS1_RCHNL (MCFG_BASE + 0x0138) ++#define MCFG_ADDR_S1_CLMS1_RESP (MCFG_BASE + 0x013c) ++#define MCFG_ADDR_S0_GIBR_CNTL (MCFG_BASE + 0x0140) ++#define MCFG_ADDR_S0_GIBR_WCHNL (MCFG_BASE + 0x0144) ++#define MCFG_ADDR_S0_GIBR_RCHNL (MCFG_BASE + 0x0148) ++#define MCFG_ADDR_S0_GIBR_RESP (MCFG_BASE + 0x014c) ++#define MCFG_ADDR_S0_GIBG_CNTL (MCFG_BASE + 0x0150) ++#define MCFG_ADDR_S0_GIBG_WCHNL (MCFG_BASE + 0x0154) ++#define MCFG_ADDR_S0_GIBG_RCHNL (MCFG_BASE + 0x0158) ++#define MCFG_ADDR_S0_GIBG_RESP (MCFG_BASE + 0x015c) ++#define MCFG_ADDR_S0_GIBB_CNTL (MCFG_BASE + 0x0160) ++#define MCFG_ADDR_S0_GIBB_WCHNL (MCFG_BASE + 0x0164) ++#define MCFG_ADDR_S0_GIBB_RCHNL (MCFG_BASE + 0x0168) ++#define MCFG_ADDR_S0_GIBB_RESP (MCFG_BASE + 0x016c) ++#define MCFG_ADDR_S1_GIBR_CNTL (MCFG_BASE + 0x0170) ++#define MCFG_ADDR_S1_GIBR_WCHNL (MCFG_BASE + 0x0174) ++#define MCFG_ADDR_S1_GIBR_RCHNL (MCFG_BASE + 0x0178) ++#define MCFG_ADDR_S1_GIBR_RESP (MCFG_BASE + 0x017c) ++#define MCFG_ADDR_S1_GIBG_CNTL (MCFG_BASE + 0x0180) ++#define MCFG_ADDR_S1_GIBG_WCHNL (MCFG_BASE + 0x0184) ++#define MCFG_ADDR_S1_GIBG_RCHNL (MCFG_BASE + 0x0188) ++#define MCFG_ADDR_S1_GIBG_RESP (MCFG_BASE + 0x018c) ++#define MCFG_ADDR_S1_GIBB_CNTL (MCFG_BASE + 0x0190) ++#define MCFG_ADDR_S1_GIBB_WCHNL (MCFG_BASE + 0x0194) ++#define MCFG_ADDR_S1_GIBB_RCHNL (MCFG_BASE + 0x0198) ++#define MCFG_ADDR_S1_GIBB_RESP (MCFG_BASE + 0x019c) ++#define MCFG_ADDR_S0_GSM_CNTL (MCFG_BASE + 0x01a0) ++#define MCFG_ADDR_S0_GSM_WCHNL (MCFG_BASE + 0x01a4) ++#define MCFG_ADDR_S0_GSM_RCHNL (MCFG_BASE + 0x01a8) ++#define MCFG_ADDR_S0_GSM_RESP (MCFG_BASE + 0x01ac) ++#define MCFG_ADDR_S1_GSM_CNTL (MCFG_BASE + 0x01b0) ++#define MCFG_ADDR_S1_GSM_WCHNL (MCFG_BASE + 0x01b4) ++#define MCFG_ADDR_S1_GSM_RCHNL (MCFG_BASE + 0x01b8) ++#define MCFG_ADDR_S1_GSM_RESP (MCFG_BASE + 0x01bc) ++#define MCFG_ADDR_S0_LCE_CNTL (MCFG_BASE + 0x01c0) ++#define MCFG_ADDR_S0_LCE_WCHNL (MCFG_BASE + 0x01c4) ++#define MCFG_ADDR_S0_LCE_RCHNL (MCFG_BASE + 0x01c8) ++#define MCFG_ADDR_S0_LCE_RESP (MCFG_BASE + 0x01cc) ++#define MCFG_ADDR_S1_LCE_CNTL (MCFG_BASE + 0x01d0) ++#define MCFG_ADDR_S1_LCE_WCHNL (MCFG_BASE + 0x01d4) ++#define MCFG_ADDR_S1_LCE_RCHNL (MCFG_BASE + 0x01d8) ++#define MCFG_ADDR_S1_LCE_RESP (MCFG_BASE + 0x01dc) ++#define MCFG_ADDR_S0_LCEP_CNTL (MCFG_BASE + 0x01e0) ++#define MCFG_ADDR_S0_LCEP_WCHNL (MCFG_BASE + 0x01e4) ++#define MCFG_ADDR_S0_LCEP_RCHNL (MCFG_BASE + 0x01e8) ++#define MCFG_ADDR_S0_LCEP_RESP (MCFG_BASE + 0x01ec) ++#define MCFG_ADDR_S1_LCEP_CNTL (MCFG_BASE + 0x01f0) ++#define MCFG_ADDR_S1_LCEP_WCHNL (MCFG_BASE + 0x01f4) ++#define MCFG_ADDR_S1_LCEP_RCHNL (MCFG_BASE + 0x01f8) ++#define MCFG_ADDR_S1_LCEP_RESP (MCFG_BASE + 0x01fc) ++#define MCFG_ADDR_S0_LCEY_CNTL (MCFG_BASE + 0x0200) ++#define MCFG_ADDR_S0_LCEY_WCHNL (MCFG_BASE + 0x0204) ++#define MCFG_ADDR_S0_LCEY_RCHNL (MCFG_BASE + 0x0208) ++#define MCFG_ADDR_S0_LCEY_RESP (MCFG_BASE + 0x020c) ++#define MCFG_ADDR_S1_LCEY_CNTL (MCFG_BASE + 0x0210) ++#define MCFG_ADDR_S1_LCEY_WCHNL (MCFG_BASE + 0x0214) ++#define MCFG_ADDR_S1_LCEY_RCHNL (MCFG_BASE + 0x0218) ++#define MCFG_ADDR_S1_LCEY_RESP (MCFG_BASE + 0x021c) ++#define MCFG_ADDR_ADR_VSHD_CNTL (MCFG_BASE + 0x0300) ++#define MCFG_ADDR_ADR_VSHD_WCHNL (MCFG_BASE + 0x0304) ++#define MCFG_ADDR_ADR_VSHD_RCHNL (MCFG_BASE + 0x0308) ++#define MCFG_ADDR_ADR_VSHD_RESP (MCFG_BASE + 0x030c) ++#define MCFG_ADDR_WDR_VSHD_CNTL (MCFG_BASE + 0x0310) ++#define MCFG_ADDR_WDR_VSHD_WCHNL (MCFG_BASE + 0x0314) ++#define MCFG_ADDR_WDR_VSHD_RCHNL (MCFG_BASE + 0x0318) ++#define MCFG_ADDR_WDR_VSHD_RESP (MCFG_BASE + 0x031c) ++#define MCFG_ADDR_MSCA_VSHD_CNTL (MCFG_BASE + 0x0320) ++#define MCFG_ADDR_MSCA_VSHD_WCHNL (MCFG_BASE + 0x0324) ++#define MCFG_ADDR_MSCA_VSHD_RCHNL (MCFG_BASE + 0x0328) ++#define MCFG_ADDR_MSCA_VSHD_RESP (MCFG_BASE + 0x032c) ++#define MCFG_ADDR_ADR_VSHD_REGPAR (MCFG_BASE + 0x0400) ++#define MCFG_ADDR_ADR_VSHD_MEMPAR (MCFG_BASE + 0x0404) ++#define MCFG_ADDR_ADR_VSHD_START (MCFG_BASE + 0x0408) ++#define MCFG_ADDR_ADR_VSHD_DONE (MCFG_BASE + 0x040c) ++#define MCFG_ADDR_WDR_VSHD_REGPAR (MCFG_BASE + 0x0410) ++#define MCFG_ADDR_WDR_VSHD_MEMPAR (MCFG_BASE + 0x0414) ++#define MCFG_ADDR_WDR_VSHD_START (MCFG_BASE + 0x0418) ++#define MCFG_ADDR_WDR_VSHD_DONE (MCFG_BASE + 0x041c) ++#define MCFG_ADDR_MSCA_VSHD_CNTRL (MCFG_BASE + 0x0420) ++ ++//============================================================ ++// MSCA ADDRESS ++//============================================================ ++#define MAIN_MSCA_ADDR_CH_WORK_EN (MSCALER0_BASE + 0x0008) ++#define MAIN_MSCA_ADDR_FORCE (MSCALER0_BASE + 0x000c) ++#define MAIN_MSCA_ADDR_CTRL (MSCALER0_BASE + 0x0010) ++#define MAIN_MSCA_ADDR_MASK_EN (MSCALER0_BASE + 0x0014) ++#define MAIN_MSCA_ADDR_OSD_EN (MSCALER0_BASE + 0x0018) ++#define MAIN_MSCA_ADDR_COEF_FIX_EN (MSCALER0_BASE + 0x0028) ++#define MAIN_MSCA_ADDR_MIRR_FLIP_RSMP_SAMP_DONE (MSCALER0_BASE + 0x002c) ++#define MAIN_MSCA_ADDR_CLK_GATE_EN (MSCALER0_BASE + 0x0030) ++#define MAIN_MSCA_ADDR_CLK_GATE (MSCALER0_BASE + 0x0034) ++#define MAIN_MSCA_ADDR_OSD_COEF_R (MSCALER0_BASE + 0x0050) ++#define MAIN_MSCA_ADDR_OSD_COEF_G (MSCALER0_BASE + 0x0054) ++#define MAIN_MSCA_ADDR_OSD_COEF_B (MSCALER0_BASE + 0x0058) ++#define MAIN_MSCA_ADDR_OSD_COEF_OFT (MSCALER0_BASE + 0x005c) ++#define MAIN_MSCA_ADDR_OSD_MODE (MSCALER0_BASE + 0x0060) ++#define MAIN_MSCA_ADDR_OSD_ARGB_TYPE (MSCALER0_BASE + 0x0064) ++#define MAIN_MSCA_ADDR_CH0_PRIO (MSCALER0_BASE + 0x0070) ++#define MAIN_MSCA_ADDR_CH1_PRIO (MSCALER0_BASE + 0x0074) ++#define MAIN_MSCA_ADDR_CH2_PRIO (MSCALER0_BASE + 0x0078) ++#define MAIN_MSCA_ADDR_SRC_RSZ_POS (MSCALER0_BASE + 0x0080) ++#define MAIN_MSCA_ADDR_SRC_RSZ_SIZE (MSCALER0_BASE + 0x0084) ++#define MAIN_MSCA_ADDR_COEF_SEL (MSCALER0_BASE + 0x0088) ++#define MAIN_MSCA_ADDR_CH0_BEFORE_IRQ (MSCALER0_BASE + 0x0090) ++#define MAIN_MSCA_ADDR_CH1_BEFORE_IRQ (MSCALER0_BASE + 0x0094) ++#define MAIN_MSCA_ADDR_CH2_BEFORE_IRQ (MSCALER0_BASE + 0x0098) ++#define MAIN_MSCA_ADDR_CH0_FCROP_POS (MSCALER0_BASE + 0x00a0) ++#define MAIN_MSCA_ADDR_CH0_FCROP_IMG (MSCALER0_BASE + 0x00a4) ++#define MAIN_MSCA_ADDR_CH1_FCROP_POS (MSCALER0_BASE + 0x00a8) ++#define MAIN_MSCA_ADDR_CH1_FCROP_IMG (MSCALER0_BASE + 0x00ac) ++#define MAIN_MSCA_ADDR_CH2_FCROP_POS (MSCALER0_BASE + 0x00b0) ++#define MAIN_MSCA_ADDR_CH2_FCROP_IMG (MSCALER0_BASE + 0x00b4) ++#define MAIN_MSCA_ADDR_WORK_STAT (MSCALER0_BASE + 0x00e0) ++#define MAIN_MSCA_ADDR_SYS_PRO_CLK_EN (MSCALER0_BASE + 0x00f0) ++#define MAIN_MSCA_ADDR_CH0_CLK_NUM (MSCALER0_BASE + 0x00f4) ++#define MAIN_MSCA_ADDR_CH1_CLK_NUM (MSCALER0_BASE + 0x00f8) ++#define MAIN_MSCA_ADDR_CH2_CLK_NUM (MSCALER0_BASE + 0x00fc) ++#define MAIN_MSCA_ADDR_CH0_RSZ_SIZE (MSCALER0_BASE + 0x0100) ++#define MAIN_MSCA_ADDR_CH0_RSZ_STEP (MSCALER0_BASE + 0x0104) ++#define MAIN_MSCA_ADDR_CH0_CROP_POS (MSCALER0_BASE + 0x0128) ++#define MAIN_MSCA_ADDR_CH0_CROP_SIZE (MSCALER0_BASE + 0x012c) ++#define MAIN_MSCA_ADDR_CH0_FR_CTRL_LOOP (MSCALER0_BASE + 0x0130) ++#define MAIN_MSCA_ADDR_CH0_FR_CTRL_MASK (MSCALER0_BASE + 0x0134) ++#define MAIN_MSCA_ADDR_CH0_MS0_POS (MSCALER0_BASE + 0x0138) ++#define MAIN_MSCA_ADDR_CH0_MS0_SIZE (MSCALER0_BASE + 0x013c) ++#define MAIN_MSCA_ADDR_CH0_MS0_VALUE (MSCALER0_BASE + 0x0140) ++#define MAIN_MSCA_ADDR_CH0_MS1_POS (MSCALER0_BASE + 0x0144) ++#define MAIN_MSCA_ADDR_CH0_MS1_SIZE (MSCALER0_BASE + 0x0148) ++#define MAIN_MSCA_ADDR_CH0_MS1_VALUE (MSCALER0_BASE + 0x014c) ++#define MAIN_MSCA_ADDR_CH0_MS2_POS (MSCALER0_BASE + 0x0150) ++#define MAIN_MSCA_ADDR_CH0_MS2_SIZE (MSCALER0_BASE + 0x0154) ++#define MAIN_MSCA_ADDR_CH0_MS2_VALUE (MSCALER0_BASE + 0x0158) ++#define MAIN_MSCA_ADDR_CH0_MS3_POS (MSCALER0_BASE + 0x015c) ++#define MAIN_MSCA_ADDR_CH0_MS3_SIZE (MSCALER0_BASE + 0x0160) ++#define MAIN_MSCA_ADDR_CH0_MS3_VALUE (MSCALER0_BASE + 0x0164) ++#define MAIN_MSCA_ADDR_CH0_OUT_FMT (MSCALER0_BASE + 0x0168) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_Y_ADDR (MSCALER0_BASE + 0x016c) ++#define MAIN_MSCA_ADDR_CH0_Y_ADDR_FIFO_STA (MSCALER0_BASE + 0x0170) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_Y_LAST_ADDR (MSCALER0_BASE + 0x0174) ++#define MAIN_MSCA_ADDR_CH0_Y_LAST_ADDR_FIFO_STA (MSCALER0_BASE + 0x017c) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_Y_STRIDE (MSCALER0_BASE + 0x0180) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_UV_ADDR (MSCALER0_BASE + 0x0184) ++#define MAIN_MSCA_ADDR_CH0_UV_ADDR_FIFO_STA (MSCALER0_BASE + 0x0188) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_UV_LAST_ADDR (MSCALER0_BASE + 0x018c) ++#define MAIN_MSCA_ADDR_CH0_UV_LAST_ADDR_FIFO_STA (MSCALER0_BASE + 0x0194) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_UV_STRIDE (MSCALER0_BASE + 0x0198) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_Y_ADDR_CLR (MSCALER0_BASE + 0x019c) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_UV_ADDR_CLR (MSCALER0_BASE + 0x01a0) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_Y_LAST_ADDR_CLR (MSCALER0_BASE + 0x01a4) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_UV_LAST_ADDR_CLR (MSCALER0_BASE + 0x01a8) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_Y_ADDR_SEL (MSCALER0_BASE + 0x01ac) ++#define MAIN_MSCA_ADDR_CH0_DMAOUT_UV_ADDR_SEL (MSCALER0_BASE + 0x01b0) ++#define MAIN_MSCA_ADDR_CH0_COE_ZERO_VRSZ_H (MSCALER0_BASE + 0x01c0) ++#define MAIN_MSCA_ADDR_CH0_COE_ZERO_VRSZ_L (MSCALER0_BASE + 0x01c4) ++#define MAIN_MSCA_ADDR_CH0_COE_ZERO_HRSZ_H (MSCALER0_BASE + 0x01c8) ++#define MAIN_MSCA_ADDR_CH0_COE_ZERO_HRSZ_L (MSCALER0_BASE + 0x01cc) ++#define MAIN_MSCA_ADDR_CH0_COE_OFT (MSCALER0_BASE + 0x01d0) ++#define MAIN_MSCA_ADDR_CH0_ARF (MSCALER0_BASE + 0x01f0) ++#define MAIN_MSCA_ADDR_CH0_CLR (MSCALER0_BASE + 0x01f4) ++#define MAIN_MSCA_ADDR_CH1_RSZ_SIZE (MSCALER0_BASE + 0x0200) ++#define MAIN_MSCA_ADDR_CH1_RSZ_STEP (MSCALER0_BASE + 0x0204) ++#define MAIN_MSCA_ADDR_CH1_CROP_POS (MSCALER0_BASE + 0x0228) ++#define MAIN_MSCA_ADDR_CH1_CROP_SIZE (MSCALER0_BASE + 0x022c) ++#define MAIN_MSCA_ADDR_CH1_FR_CTRL_LOOP (MSCALER0_BASE + 0x0230) ++#define MAIN_MSCA_ADDR_CH1_FR_CTRL_MASK (MSCALER0_BASE + 0x0234) ++#define MAIN_MSCA_ADDR_CH1_MS0_POS (MSCALER0_BASE + 0x0238) ++#define MAIN_MSCA_ADDR_CH1_MS0_SIZE (MSCALER0_BASE + 0x023c) ++#define MAIN_MSCA_ADDR_CH1_MS0_VALUE (MSCALER0_BASE + 0x0240) ++#define MAIN_MSCA_ADDR_CH1_MS1_POS (MSCALER0_BASE + 0x0244) ++#define MAIN_MSCA_ADDR_CH1_MS1_SIZE (MSCALER0_BASE + 0x0248) ++#define MAIN_MSCA_ADDR_CH1_MS1_VALUE (MSCALER0_BASE + 0x024c) ++#define MAIN_MSCA_ADDR_CH1_MS2_POS (MSCALER0_BASE + 0x0250) ++#define MAIN_MSCA_ADDR_CH1_MS2_SIZE (MSCALER0_BASE + 0x0254) ++#define MAIN_MSCA_ADDR_CH1_MS2_VALUE (MSCALER0_BASE + 0x0258) ++#define MAIN_MSCA_ADDR_CH1_MS3_POS (MSCALER0_BASE + 0x025c) ++#define MAIN_MSCA_ADDR_CH1_MS3_SIZE (MSCALER0_BASE + 0x0260) ++#define MAIN_MSCA_ADDR_CH1_MS3_VALUE (MSCALER0_BASE + 0x0264) ++#define MAIN_MSCA_ADDR_CH1_OUT_FMT (MSCALER0_BASE + 0x0268) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_Y_ADDR (MSCALER0_BASE + 0x026c) ++#define MAIN_MSCA_ADDR_CH1_Y_ADDR_FIFO_STA (MSCALER0_BASE + 0x0270) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_Y_LAST_ADDR (MSCALER0_BASE + 0x0274) ++#define MAIN_MSCA_ADDR_CH1_Y_LAST_ADDR_FIFO_STA (MSCALER0_BASE + 0x027c) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_Y_STRIDE (MSCALER0_BASE + 0x0280) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_UV_ADDR (MSCALER0_BASE + 0x0284) ++#define MAIN_MSCA_ADDR_CH1_UV_ADDR_FIFO_STA (MSCALER0_BASE + 0x0288) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_UV_LAST_ADDR (MSCALER0_BASE + 0x028c) ++#define MAIN_MSCA_ADDR_CH1_UV_LAST_ADDR_FIFO_STA (MSCALER0_BASE + 0x0294) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_UV_STRIDE (MSCALER0_BASE + 0x0298) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_Y_ADDR_CLR (MSCALER0_BASE + 0x029c) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_UV_ADDR_CLR (MSCALER0_BASE + 0x02a0) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_Y_LAST_ADDR_CLR (MSCALER0_BASE + 0x02a4) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_UV_LAST_ADDR_CLR (MSCALER0_BASE + 0x02a8) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_Y_ADDR_SEL (MSCALER0_BASE + 0x02ac) ++#define MAIN_MSCA_ADDR_CH1_DMAOUT_UV_ADDR_SEL (MSCALER0_BASE + 0x02b0) ++#define MAIN_MSCA_ADDR_CH1_COE_ZERO_VRSZ_H (MSCALER0_BASE + 0x02c0) ++#define MAIN_MSCA_ADDR_CH1_COE_ZERO_VRSZ_L (MSCALER0_BASE + 0x02c4) ++#define MAIN_MSCA_ADDR_CH1_COE_ZERO_HRSZ_H (MSCALER0_BASE + 0x02c8) ++#define MAIN_MSCA_ADDR_CH1_COE_ZERO_HRSZ_L (MSCALER0_BASE + 0x02cc) ++#define MAIN_MSCA_ADDR_CH1_COE_OFT (MSCALER0_BASE + 0x02d0) ++#define MAIN_MSCA_ADDR_CH1_ARF (MSCALER0_BASE + 0x02f0) ++#define MAIN_MSCA_ADDR_CH1_CLR (MSCALER0_BASE + 0x02f4) ++#define MAIN_MSCA_ADDR_CH2_RSZ_SIZE (MSCALER0_BASE + 0x0300) ++#define MAIN_MSCA_ADDR_CH2_RSZ_STEP (MSCALER0_BASE + 0x0304) ++#define MAIN_MSCA_ADDR_CH2_CROP_POS (MSCALER0_BASE + 0x0328) ++#define MAIN_MSCA_ADDR_CH2_CROP_SIZE (MSCALER0_BASE + 0x032c) ++#define MAIN_MSCA_ADDR_CH2_FR_CTRL_LOOP (MSCALER0_BASE + 0x0330) ++#define MAIN_MSCA_ADDR_CH2_FR_CTRL_MASK (MSCALER0_BASE + 0x0334) ++#define MAIN_MSCA_ADDR_CH2_MS0_POS (MSCALER0_BASE + 0x0338) ++#define MAIN_MSCA_ADDR_CH2_MS0_SIZE (MSCALER0_BASE + 0x033c) ++#define MAIN_MSCA_ADDR_CH2_MS0_VALUE (MSCALER0_BASE + 0x0340) ++#define MAIN_MSCA_ADDR_CH2_MS1_POS (MSCALER0_BASE + 0x0344) ++#define MAIN_MSCA_ADDR_CH2_MS1_SIZE (MSCALER0_BASE + 0x0348) ++#define MAIN_MSCA_ADDR_CH2_MS1_VALUE (MSCALER0_BASE + 0x034c) ++#define MAIN_MSCA_ADDR_CH2_MS2_POS (MSCALER0_BASE + 0x0350) ++#define MAIN_MSCA_ADDR_CH2_MS2_SIZE (MSCALER0_BASE + 0x0354) ++#define MAIN_MSCA_ADDR_CH2_MS2_VALUE (MSCALER0_BASE + 0x0358) ++#define MAIN_MSCA_ADDR_CH2_MS3_POS (MSCALER0_BASE + 0x035c) ++#define MAIN_MSCA_ADDR_CH2_MS3_SIZE (MSCALER0_BASE + 0x0360) ++#define MAIN_MSCA_ADDR_CH2_MS3_VALUE (MSCALER0_BASE + 0x0364) ++#define MAIN_MSCA_ADDR_CH2_OUT_FMT (MSCALER0_BASE + 0x0368) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_Y_ADDR (MSCALER0_BASE + 0x036c) ++#define MAIN_MSCA_ADDR_CH2_Y_ADDR_FIFO_STA (MSCALER0_BASE + 0x0370) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_Y_LAST_ADDR (MSCALER0_BASE + 0x0374) ++#define MAIN_MSCA_ADDR_CH2_Y_LAST_ADDR_FIFO_STA (MSCALER0_BASE + 0x037c) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_Y_STRIDE (MSCALER0_BASE + 0x0380) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_UV_ADDR (MSCALER0_BASE + 0x0384) ++#define MAIN_MSCA_ADDR_CH2_UV_ADDR_FIFO_STA (MSCALER0_BASE + 0x0388) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_UV_LAST_ADDR (MSCALER0_BASE + 0x038c) ++#define MAIN_MSCA_ADDR_CH2_UV_LAST_ADDR_FIFO_STA (MSCALER0_BASE + 0x0394) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_UV_STRIDE (MSCALER0_BASE + 0x0398) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_Y_ADDR_CLR (MSCALER0_BASE + 0x039c) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_UV_ADDR_CLR (MSCALER0_BASE + 0x03a0) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_Y_LAST_ADDR_CLR (MSCALER0_BASE + 0x03a4) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_UV_LAST_ADDR_CLR (MSCALER0_BASE + 0x03a8) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_Y_ADDR_SEL (MSCALER0_BASE + 0x03ac) ++#define MAIN_MSCA_ADDR_CH2_DMAOUT_UV_ADDR_SEL (MSCALER0_BASE + 0x03b0) ++#define MAIN_MSCA_ADDR_CH2_COE_ZERO_VRSZ_H (MSCALER0_BASE + 0x03c0) ++#define MAIN_MSCA_ADDR_CH2_COE_ZERO_VRSZ_L (MSCALER0_BASE + 0x03c4) ++#define MAIN_MSCA_ADDR_CH2_COE_ZERO_HRSZ_H (MSCALER0_BASE + 0x03c8) ++#define MAIN_MSCA_ADDR_CH2_COE_ZERO_HRSZ_L (MSCALER0_BASE + 0x03cc) ++#define MAIN_MSCA_ADDR_CH2_COE_OFT (MSCALER0_BASE + 0x03d0) ++#define MAIN_MSCA_ADDR_CH2_ARF (MSCALER0_BASE + 0x03f0) ++#define MAIN_MSCA_ADDR_CH2_CLR (MSCALER0_BASE + 0x03f4) ++#define MAIN_MSCA_ADDR_CH0_LINE0_POS (MSCALER0_BASE + 0x0400) ++#define MAIN_MSCA_ADDR_CH0_LINE0_SIZE (MSCALER0_BASE + 0x0404) ++#define MAIN_MSCA_ADDR_CH0_LINE0_PAR0 (MSCALER0_BASE + 0x0408) ++#define MAIN_MSCA_ADDR_CH0_LINE0_PAR1 (MSCALER0_BASE + 0x040c) ++#define MAIN_MSCA_ADDR_CH0_LINE1_POS (MSCALER0_BASE + 0x0410) ++#define MAIN_MSCA_ADDR_CH0_LINE1_SIZE (MSCALER0_BASE + 0x0414) ++#define MAIN_MSCA_ADDR_CH0_LINE1_PAR0 (MSCALER0_BASE + 0x0418) ++#define MAIN_MSCA_ADDR_CH0_LINE1_PAR1 (MSCALER0_BASE + 0x041c) ++#define MAIN_MSCA_ADDR_CH0_LINE2_POS (MSCALER0_BASE + 0x0420) ++#define MAIN_MSCA_ADDR_CH0_LINE2_SIZE (MSCALER0_BASE + 0x0424) ++#define MAIN_MSCA_ADDR_CH0_LINE2_PAR0 (MSCALER0_BASE + 0x0428) ++#define MAIN_MSCA_ADDR_CH0_LINE2_PAR1 (MSCALER0_BASE + 0x042c) ++#define MAIN_MSCA_ADDR_CH0_LINE3_POS (MSCALER0_BASE + 0x0430) ++#define MAIN_MSCA_ADDR_CH0_LINE3_SIZE (MSCALER0_BASE + 0x0434) ++#define MAIN_MSCA_ADDR_CH0_LINE3_PAR0 (MSCALER0_BASE + 0x0438) ++#define MAIN_MSCA_ADDR_CH0_LINE3_PAR1 (MSCALER0_BASE + 0x043c) ++#define MAIN_MSCA_ADDR_CH0_LINE4_POS (MSCALER0_BASE + 0x0440) ++#define MAIN_MSCA_ADDR_CH0_LINE4_SIZE (MSCALER0_BASE + 0x0444) ++#define MAIN_MSCA_ADDR_CH0_LINE4_PAR0 (MSCALER0_BASE + 0x0448) ++#define MAIN_MSCA_ADDR_CH0_LINE4_PAR1 (MSCALER0_BASE + 0x044c) ++#define MAIN_MSCA_ADDR_CH0_LINE5_POS (MSCALER0_BASE + 0x0450) ++#define MAIN_MSCA_ADDR_CH0_LINE5_SIZE (MSCALER0_BASE + 0x0454) ++#define MAIN_MSCA_ADDR_CH0_LINE5_PAR0 (MSCALER0_BASE + 0x0458) ++#define MAIN_MSCA_ADDR_CH0_LINE5_PAR1 (MSCALER0_BASE + 0x045c) ++#define MAIN_MSCA_ADDR_CH0_LINE6_POS (MSCALER0_BASE + 0x0460) ++#define MAIN_MSCA_ADDR_CH0_LINE6_SIZE (MSCALER0_BASE + 0x0464) ++#define MAIN_MSCA_ADDR_CH0_LINE6_PAR0 (MSCALER0_BASE + 0x0468) ++#define MAIN_MSCA_ADDR_CH0_LINE6_PAR1 (MSCALER0_BASE + 0x046c) ++#define MAIN_MSCA_ADDR_CH0_LINE7_POS (MSCALER0_BASE + 0x0470) ++#define MAIN_MSCA_ADDR_CH0_LINE7_SIZE (MSCALER0_BASE + 0x0474) ++#define MAIN_MSCA_ADDR_CH0_LINE7_PAR0 (MSCALER0_BASE + 0x0478) ++#define MAIN_MSCA_ADDR_CH0_LINE7_PAR1 (MSCALER0_BASE + 0x047c) ++#define MAIN_MSCA_ADDR_CH0_LINE8_POS (MSCALER0_BASE + 0x0480) ++#define MAIN_MSCA_ADDR_CH0_LINE8_SIZE (MSCALER0_BASE + 0x0484) ++#define MAIN_MSCA_ADDR_CH0_LINE8_PAR0 (MSCALER0_BASE + 0x0488) ++#define MAIN_MSCA_ADDR_CH0_LINE8_PAR1 (MSCALER0_BASE + 0x048c) ++#define MAIN_MSCA_ADDR_CH0_LINE9_POS (MSCALER0_BASE + 0x0490) ++#define MAIN_MSCA_ADDR_CH0_LINE9_SIZE (MSCALER0_BASE + 0x0494) ++#define MAIN_MSCA_ADDR_CH0_LINE9_PAR0 (MSCALER0_BASE + 0x0498) ++#define MAIN_MSCA_ADDR_CH0_LINE9_PAR1 (MSCALER0_BASE + 0x049c) ++#define MAIN_MSCA_ADDR_CH0_LINE10_POS (MSCALER0_BASE + 0x04a0) ++#define MAIN_MSCA_ADDR_CH0_LINE10_SIZE (MSCALER0_BASE + 0x04a4) ++#define MAIN_MSCA_ADDR_CH0_LINE10_PAR0 (MSCALER0_BASE + 0x04a8) ++#define MAIN_MSCA_ADDR_CH0_LINE10_PAR1 (MSCALER0_BASE + 0x04ac) ++#define MAIN_MSCA_ADDR_CH0_LINE11_POS (MSCALER0_BASE + 0x04b0) ++#define MAIN_MSCA_ADDR_CH0_LINE11_SIZE (MSCALER0_BASE + 0x04b4) ++#define MAIN_MSCA_ADDR_CH0_LINE11_PAR0 (MSCALER0_BASE + 0x04b8) ++#define MAIN_MSCA_ADDR_CH0_LINE11_PAR1 (MSCALER0_BASE + 0x04bc) ++#define MAIN_MSCA_ADDR_CH0_LINE12_POS (MSCALER0_BASE + 0x04c0) ++#define MAIN_MSCA_ADDR_CH0_LINE12_SIZE (MSCALER0_BASE + 0x04c4) ++#define MAIN_MSCA_ADDR_CH0_LINE12_PAR0 (MSCALER0_BASE + 0x04c8) ++#define MAIN_MSCA_ADDR_CH0_LINE12_PAR1 (MSCALER0_BASE + 0x04cc) ++#define MAIN_MSCA_ADDR_CH0_LINE13_POS (MSCALER0_BASE + 0x04d0) ++#define MAIN_MSCA_ADDR_CH0_LINE13_SIZE (MSCALER0_BASE + 0x04d4) ++#define MAIN_MSCA_ADDR_CH0_LINE13_PAR0 (MSCALER0_BASE + 0x04d8) ++#define MAIN_MSCA_ADDR_CH0_LINE13_PAR1 (MSCALER0_BASE + 0x04dc) ++#define MAIN_MSCA_ADDR_CH0_LINE14_POS (MSCALER0_BASE + 0x04e0) ++#define MAIN_MSCA_ADDR_CH0_LINE14_SIZE (MSCALER0_BASE + 0x04e4) ++#define MAIN_MSCA_ADDR_CH0_LINE14_PAR0 (MSCALER0_BASE + 0x04e8) ++#define MAIN_MSCA_ADDR_CH0_LINE14_PAR1 (MSCALER0_BASE + 0x04ec) ++#define MAIN_MSCA_ADDR_CH0_LINE15_POS (MSCALER0_BASE + 0x04f0) ++#define MAIN_MSCA_ADDR_CH0_LINE15_SIZE (MSCALER0_BASE + 0x04f4) ++#define MAIN_MSCA_ADDR_CH0_LINE15_PAR0 (MSCALER0_BASE + 0x04f8) ++#define MAIN_MSCA_ADDR_CH0_LINE15_PAR1 (MSCALER0_BASE + 0x04fc) ++#define MAIN_MSCA_ADDR_CH1_LINE0_POS (MSCALER0_BASE + 0x0500) ++#define MAIN_MSCA_ADDR_CH1_LINE0_SIZE (MSCALER0_BASE + 0x0504) ++#define MAIN_MSCA_ADDR_CH1_LINE0_PAR0 (MSCALER0_BASE + 0x0508) ++#define MAIN_MSCA_ADDR_CH1_LINE0_PAR1 (MSCALER0_BASE + 0x050c) ++#define MAIN_MSCA_ADDR_CH1_LINE1_POS (MSCALER0_BASE + 0x0510) ++#define MAIN_MSCA_ADDR_CH1_LINE1_SIZE (MSCALER0_BASE + 0x0514) ++#define MAIN_MSCA_ADDR_CH1_LINE1_PAR0 (MSCALER0_BASE + 0x0518) ++#define MAIN_MSCA_ADDR_CH1_LINE1_PAR1 (MSCALER0_BASE + 0x051c) ++#define MAIN_MSCA_ADDR_CH1_LINE2_POS (MSCALER0_BASE + 0x0520) ++#define MAIN_MSCA_ADDR_CH1_LINE2_SIZE (MSCALER0_BASE + 0x0524) ++#define MAIN_MSCA_ADDR_CH1_LINE2_PAR0 (MSCALER0_BASE + 0x0528) ++#define MAIN_MSCA_ADDR_CH1_LINE2_PAR1 (MSCALER0_BASE + 0x052c) ++#define MAIN_MSCA_ADDR_CH1_LINE3_POS (MSCALER0_BASE + 0x0530) ++#define MAIN_MSCA_ADDR_CH1_LINE3_SIZE (MSCALER0_BASE + 0x0534) ++#define MAIN_MSCA_ADDR_CH1_LINE3_PAR0 (MSCALER0_BASE + 0x0538) ++#define MAIN_MSCA_ADDR_CH1_LINE3_PAR1 (MSCALER0_BASE + 0x053c) ++#define MAIN_MSCA_ADDR_CH1_LINE4_POS (MSCALER0_BASE + 0x0540) ++#define MAIN_MSCA_ADDR_CH1_LINE4_SIZE (MSCALER0_BASE + 0x0544) ++#define MAIN_MSCA_ADDR_CH1_LINE4_PAR0 (MSCALER0_BASE + 0x0548) ++#define MAIN_MSCA_ADDR_CH1_LINE4_PAR1 (MSCALER0_BASE + 0x054c) ++#define MAIN_MSCA_ADDR_CH1_LINE5_POS (MSCALER0_BASE + 0x0550) ++#define MAIN_MSCA_ADDR_CH1_LINE5_SIZE (MSCALER0_BASE + 0x0554) ++#define MAIN_MSCA_ADDR_CH1_LINE5_PAR0 (MSCALER0_BASE + 0x0558) ++#define MAIN_MSCA_ADDR_CH1_LINE5_PAR1 (MSCALER0_BASE + 0x055c) ++#define MAIN_MSCA_ADDR_CH1_LINE6_POS (MSCALER0_BASE + 0x0560) ++#define MAIN_MSCA_ADDR_CH1_LINE6_SIZE (MSCALER0_BASE + 0x0564) ++#define MAIN_MSCA_ADDR_CH1_LINE6_PAR0 (MSCALER0_BASE + 0x0568) ++#define MAIN_MSCA_ADDR_CH1_LINE6_PAR1 (MSCALER0_BASE + 0x056c) ++#define MAIN_MSCA_ADDR_CH1_LINE7_POS (MSCALER0_BASE + 0x0570) ++#define MAIN_MSCA_ADDR_CH1_LINE7_SIZE (MSCALER0_BASE + 0x0574) ++#define MAIN_MSCA_ADDR_CH1_LINE7_PAR0 (MSCALER0_BASE + 0x0578) ++#define MAIN_MSCA_ADDR_CH1_LINE7_PAR1 (MSCALER0_BASE + 0x057c) ++#define MAIN_MSCA_ADDR_CH1_LINE8_POS (MSCALER0_BASE + 0x0580) ++#define MAIN_MSCA_ADDR_CH1_LINE8_SIZE (MSCALER0_BASE + 0x0584) ++#define MAIN_MSCA_ADDR_CH1_LINE8_PAR0 (MSCALER0_BASE + 0x0588) ++#define MAIN_MSCA_ADDR_CH1_LINE8_PAR1 (MSCALER0_BASE + 0x058c) ++#define MAIN_MSCA_ADDR_CH1_LINE9_POS (MSCALER0_BASE + 0x0590) ++#define MAIN_MSCA_ADDR_CH1_LINE9_SIZE (MSCALER0_BASE + 0x0594) ++#define MAIN_MSCA_ADDR_CH1_LINE9_PAR0 (MSCALER0_BASE + 0x0598) ++#define MAIN_MSCA_ADDR_CH1_LINE9_PAR1 (MSCALER0_BASE + 0x059c) ++#define MAIN_MSCA_ADDR_CH1_LINE10_POS (MSCALER0_BASE + 0x05a0) ++#define MAIN_MSCA_ADDR_CH1_LINE10_SIZE (MSCALER0_BASE + 0x05a4) ++#define MAIN_MSCA_ADDR_CH1_LINE10_PAR0 (MSCALER0_BASE + 0x05a8) ++#define MAIN_MSCA_ADDR_CH1_LINE10_PAR1 (MSCALER0_BASE + 0x05ac) ++#define MAIN_MSCA_ADDR_CH1_LINE11_POS (MSCALER0_BASE + 0x05b0) ++#define MAIN_MSCA_ADDR_CH1_LINE11_SIZE (MSCALER0_BASE + 0x05b4) ++#define MAIN_MSCA_ADDR_CH1_LINE11_PAR0 (MSCALER0_BASE + 0x05b8) ++#define MAIN_MSCA_ADDR_CH1_LINE11_PAR1 (MSCALER0_BASE + 0x05bc) ++#define MAIN_MSCA_ADDR_CH1_LINE12_POS (MSCALER0_BASE + 0x05c0) ++#define MAIN_MSCA_ADDR_CH1_LINE12_SIZE (MSCALER0_BASE + 0x05c4) ++#define MAIN_MSCA_ADDR_CH1_LINE12_PAR0 (MSCALER0_BASE + 0x05c8) ++#define MAIN_MSCA_ADDR_CH1_LINE12_PAR1 (MSCALER0_BASE + 0x05cc) ++#define MAIN_MSCA_ADDR_CH1_LINE13_POS (MSCALER0_BASE + 0x05d0) ++#define MAIN_MSCA_ADDR_CH1_LINE13_SIZE (MSCALER0_BASE + 0x05d4) ++#define MAIN_MSCA_ADDR_CH1_LINE13_PAR0 (MSCALER0_BASE + 0x05d8) ++#define MAIN_MSCA_ADDR_CH1_LINE13_PAR1 (MSCALER0_BASE + 0x05dc) ++#define MAIN_MSCA_ADDR_CH1_LINE14_POS (MSCALER0_BASE + 0x05e0) ++#define MAIN_MSCA_ADDR_CH1_LINE14_SIZE (MSCALER0_BASE + 0x05e4) ++#define MAIN_MSCA_ADDR_CH1_LINE14_PAR0 (MSCALER0_BASE + 0x05e8) ++#define MAIN_MSCA_ADDR_CH1_LINE14_PAR1 (MSCALER0_BASE + 0x05ec) ++#define MAIN_MSCA_ADDR_CH1_LINE15_POS (MSCALER0_BASE + 0x05f0) ++#define MAIN_MSCA_ADDR_CH1_LINE15_SIZE (MSCALER0_BASE + 0x05f4) ++#define MAIN_MSCA_ADDR_CH1_LINE15_PAR0 (MSCALER0_BASE + 0x05f8) ++#define MAIN_MSCA_ADDR_CH1_LINE15_PAR1 (MSCALER0_BASE + 0x05fc) ++#define MAIN_MSCA_ADDR_CH0_OSD0_POS (MSCALER0_BASE + 0x0600) ++#define MAIN_MSCA_ADDR_CH0_OSD0_SIZE (MSCALER0_BASE + 0x0604) ++#define MAIN_MSCA_ADDR_CH0_OSD0_ADDR (MSCALER0_BASE + 0x0608) ++#define MAIN_MSCA_ADDR_CH0_OSD0_STRIDE (MSCALER0_BASE + 0x060c) ++#define MAIN_MSCA_ADDR_CH0_OSD1_POS (MSCALER0_BASE + 0x0610) ++#define MAIN_MSCA_ADDR_CH0_OSD1_SIZE (MSCALER0_BASE + 0x0614) ++#define MAIN_MSCA_ADDR_CH0_OSD1_ADDR (MSCALER0_BASE + 0x0618) ++#define MAIN_MSCA_ADDR_CH0_OSD1_STRIDE (MSCALER0_BASE + 0x061c) ++#define MAIN_MSCA_ADDR_CH0_OSD2_POS (MSCALER0_BASE + 0x0620) ++#define MAIN_MSCA_ADDR_CH0_OSD2_SIZE (MSCALER0_BASE + 0x0624) ++#define MAIN_MSCA_ADDR_CH0_OSD2_ADDR (MSCALER0_BASE + 0x0628) ++#define MAIN_MSCA_ADDR_CH0_OSD2_STRIDE (MSCALER0_BASE + 0x062c) ++#define MAIN_MSCA_ADDR_CH0_OSD3_POS (MSCALER0_BASE + 0x0630) ++#define MAIN_MSCA_ADDR_CH0_OSD3_SIZE (MSCALER0_BASE + 0x0634) ++#define MAIN_MSCA_ADDR_CH0_OSD3_ADDR (MSCALER0_BASE + 0x0638) ++#define MAIN_MSCA_ADDR_CH0_OSD3_STRIDE (MSCALER0_BASE + 0x063c) ++#define MAIN_MSCA_ADDR_CH0_OSD4_POS (MSCALER0_BASE + 0x0640) ++#define MAIN_MSCA_ADDR_CH0_OSD4_SIZE (MSCALER0_BASE + 0x0644) ++#define MAIN_MSCA_ADDR_CH0_OSD4_ADDR (MSCALER0_BASE + 0x0648) ++#define MAIN_MSCA_ADDR_CH0_OSD4_STRIDE (MSCALER0_BASE + 0x064c) ++#define MAIN_MSCA_ADDR_CH0_OSD5_POS (MSCALER0_BASE + 0x0650) ++#define MAIN_MSCA_ADDR_CH0_OSD5_SIZE (MSCALER0_BASE + 0x0654) ++#define MAIN_MSCA_ADDR_CH0_OSD5_ADDR (MSCALER0_BASE + 0x0658) ++#define MAIN_MSCA_ADDR_CH0_OSD5_STRIDE (MSCALER0_BASE + 0x065c) ++#define MAIN_MSCA_ADDR_CH0_OSD6_POS (MSCALER0_BASE + 0x0660) ++#define MAIN_MSCA_ADDR_CH0_OSD6_SIZE (MSCALER0_BASE + 0x0664) ++#define MAIN_MSCA_ADDR_CH0_OSD6_ADDR (MSCALER0_BASE + 0x0668) ++#define MAIN_MSCA_ADDR_CH0_OSD6_STRIDE (MSCALER0_BASE + 0x066c) ++#define MAIN_MSCA_ADDR_CH0_OSD7_POS (MSCALER0_BASE + 0x0670) ++#define MAIN_MSCA_ADDR_CH0_OSD7_SIZE (MSCALER0_BASE + 0x0674) ++#define MAIN_MSCA_ADDR_CH0_OSD7_ADDR (MSCALER0_BASE + 0x0678) ++#define MAIN_MSCA_ADDR_CH0_OSD7_STRIDE (MSCALER0_BASE + 0x067c) ++#define MAIN_MSCA_ADDR_CH1_OSD0_POS (MSCALER0_BASE + 0x0680) ++#define MAIN_MSCA_ADDR_CH1_OSD0_SIZE (MSCALER0_BASE + 0x0684) ++#define MAIN_MSCA_ADDR_CH1_OSD0_ADDR (MSCALER0_BASE + 0x0688) ++#define MAIN_MSCA_ADDR_CH1_OSD0_STRIDE (MSCALER0_BASE + 0x068c) ++#define MAIN_MSCA_ADDR_CH1_OSD1_POS (MSCALER0_BASE + 0x0690) ++#define MAIN_MSCA_ADDR_CH1_OSD1_SIZE (MSCALER0_BASE + 0x0694) ++#define MAIN_MSCA_ADDR_CH1_OSD1_ADDR (MSCALER0_BASE + 0x0698) ++#define MAIN_MSCA_ADDR_CH1_OSD1_STRIDE (MSCALER0_BASE + 0x069c) ++#define MAIN_MSCA_ADDR_CH1_OSD2_POS (MSCALER0_BASE + 0x06a0) ++#define MAIN_MSCA_ADDR_CH1_OSD2_SIZE (MSCALER0_BASE + 0x06a4) ++#define MAIN_MSCA_ADDR_CH1_OSD2_ADDR (MSCALER0_BASE + 0x06a8) ++#define MAIN_MSCA_ADDR_CH1_OSD2_STRIDE (MSCALER0_BASE + 0x06ac) ++#define MAIN_MSCA_ADDR_CH1_OSD3_POS (MSCALER0_BASE + 0x06b0) ++#define MAIN_MSCA_ADDR_CH1_OSD3_SIZE (MSCALER0_BASE + 0x06b4) ++#define MAIN_MSCA_ADDR_CH1_OSD3_ADDR (MSCALER0_BASE + 0x06b8) ++#define MAIN_MSCA_ADDR_CH1_OSD3_STRIDE (MSCALER0_BASE + 0x06bc) ++#define MAIN_MSCA_ADDR_CH1_OSD4_POS (MSCALER0_BASE + 0x06c0) ++#define MAIN_MSCA_ADDR_CH1_OSD4_SIZE (MSCALER0_BASE + 0x06c4) ++#define MAIN_MSCA_ADDR_CH1_OSD4_ADDR (MSCALER0_BASE + 0x06c8) ++#define MAIN_MSCA_ADDR_CH1_OSD4_STRIDE (MSCALER0_BASE + 0x06cc) ++#define MAIN_MSCA_ADDR_CH1_OSD5_POS (MSCALER0_BASE + 0x06d0) ++#define MAIN_MSCA_ADDR_CH1_OSD5_SIZE (MSCALER0_BASE + 0x06d4) ++#define MAIN_MSCA_ADDR_CH1_OSD5_ADDR (MSCALER0_BASE + 0x06d8) ++#define MAIN_MSCA_ADDR_CH1_OSD5_STRIDE (MSCALER0_BASE + 0x06dc) ++#define MAIN_MSCA_ADDR_CH1_OSD6_POS (MSCALER0_BASE + 0x06e0) ++#define MAIN_MSCA_ADDR_CH1_OSD6_SIZE (MSCALER0_BASE + 0x06e4) ++#define MAIN_MSCA_ADDR_CH1_OSD6_ADDR (MSCALER0_BASE + 0x06e8) ++#define MAIN_MSCA_ADDR_CH1_OSD6_STRIDE (MSCALER0_BASE + 0x06ec) ++#define MAIN_MSCA_ADDR_CH1_OSD7_POS (MSCALER0_BASE + 0x06f0) ++#define MAIN_MSCA_ADDR_CH1_OSD7_SIZE (MSCALER0_BASE + 0x06f4) ++#define MAIN_MSCA_ADDR_CH1_OSD7_ADDR (MSCALER0_BASE + 0x06f8) ++#define MAIN_MSCA_ADDR_CH1_OSD7_STRIDE (MSCALER0_BASE + 0x06fc) ++#define MAIN_MSCA_ADDR_BACK_DOOR (MSCALER0_BASE + 0x0700) ++#define MAIN_MSCA_ADDR_DBG__00_00 (MSCALER0_BASE + 0x0710) ++#define MAIN_MSCA_ADDR_DBG__01_01 (MSCALER0_BASE + 0x0714) ++#define MAIN_MSCA_ADDR_DBG__02_02 (MSCALER0_BASE + 0x0718) ++#define MAIN_MSCA_ADDR_DBG__03_03 (MSCALER0_BASE + 0x071c) ++#define MAIN_MSCA_ADDR_DBG__04_04 (MSCALER0_BASE + 0x0720) ++#define MAIN_MSCA_ADDR_DBG__05_05 (MSCALER0_BASE + 0x0724) ++#define MAIN_MSCA_ADDR_DBG__06_06 (MSCALER0_BASE + 0x0728) ++#define MAIN_MSCA_ADDR_DBG__07_07 (MSCALER0_BASE + 0x072c) ++#define MAIN_MSCA_ADDR_DBG__08_08 (MSCALER0_BASE + 0x0730) ++#define MAIN_MSCA_ADDR_DBG__09_09 (MSCALER0_BASE + 0x0734) ++#define MAIN_MSCA_ADDR_DBG__10_10 (MSCALER0_BASE + 0x0738) ++#define MAIN_MSCA_ADDR_DBG__11_11 (MSCALER0_BASE + 0x073c) ++#define MAIN_MSCA_ADDR_DBG__12_12 (MSCALER0_BASE + 0x0740) ++#define MAIN_MSCA_ADDR_DBG__13_13 (MSCALER0_BASE + 0x0744) ++#define MAIN_MSCA_ADDR_DBG__14_14 (MSCALER0_BASE + 0x0748) ++#define MAIN_MSCA_ADDR_DBG__15_15 (MSCALER0_BASE + 0x074c) ++#define MAIN_MSCA_ADDR_DBG__16_16 (MSCALER0_BASE + 0x0750) ++#define MAIN_MSCA_ADDR_DBG__17_17 (MSCALER0_BASE + 0x0754) ++#define MAIN_MSCA_ADDR_DBG__18_18 (MSCALER0_BASE + 0x0758) ++#define MAIN_MSCA_ADDR_DBG__19_19 (MSCALER0_BASE + 0x075c) ++#define MAIN_MSCA_ADDR_DBG__20_20 (MSCALER0_BASE + 0x0760) ++#define MAIN_MSCA_ADDR_DBG__21_21 (MSCALER0_BASE + 0x0764) ++#define MAIN_MSCA_ADDR_DBG__22_22 (MSCALER0_BASE + 0x0768) ++#define MAIN_MSCA_ADDR_DBG__23_23 (MSCALER0_BASE + 0x076c) ++#define MAIN_MSCA_ADDR_DBG__24_24 (MSCALER0_BASE + 0x0770) ++#define MAIN_MSCA_ADDR_DBG__25_25 (MSCALER0_BASE + 0x0774) ++#define MAIN_MSCA_ADDR_DBG__26_26 (MSCALER0_BASE + 0x0778) ++#define MAIN_MSCA_ADDR_DBG__27_27 (MSCALER0_BASE + 0x077c) ++#define MAIN_MSCA_ADDR_DBG__28_28 (MSCALER0_BASE + 0x0780) ++#define MAIN_MSCA_ADDR_DBG__29_29 (MSCALER0_BASE + 0x0784) ++#define MAIN_MSCA_ADDR_DBG__30_30 (MSCALER0_BASE + 0x0788) ++#define MAIN_MSCA_ADDR_DBG__31_31 (MSCALER0_BASE + 0x078c) ++#define MAIN_MSCA_ADDR_DBG__32_32 (MSCALER0_BASE + 0x0790) ++#define MAIN_MSCA_ADDR_DBG__33_33 (MSCALER0_BASE + 0x0794) ++#define MAIN_MSCA_ADDR_DBG__34_34 (MSCALER0_BASE + 0x0798) ++#define MAIN_MSCA_ADDR_DBG__35_35 (MSCALER0_BASE + 0x079c) ++#define MAIN_MSCA_ADDR_DBG__36_36 (MSCALER0_BASE + 0x07a0) ++#define MAIN_MSCA_ADDR_DBG__37_37 (MSCALER0_BASE + 0x07a4) ++#define MAIN_MSCA_ADDR_DBG__38_38 (MSCALER0_BASE + 0x07a8) ++#define MAIN_MSCA_ADDR_DBG__39_39 (MSCALER0_BASE + 0x07ac) ++#define MAIN_MSCA_ADDR_DBG__40_40 (MSCALER0_BASE + 0x07b0) ++#define MAIN_MSCA_ADDR_DBG__41_41 (MSCALER0_BASE + 0x07b4) ++#define MAIN_MSCA_ADDR_DBG__42_42 (MSCALER0_BASE + 0x07b8) ++#define MAIN_MSCA_ADDR_DBG__43_43 (MSCALER0_BASE + 0x07bc) ++#define MAIN_MSCA_ADDR_DBG__44_44 (MSCALER0_BASE + 0x07c0) ++#define MAIN_MSCA_ADDR_DBG__45_45 (MSCALER0_BASE + 0x07c4) ++#define MAIN_MSCA_ADDR_DBG__46_46 (MSCALER0_BASE + 0x07c8) ++#define MAIN_MSCA_ADDR_DBG__47_47 (MSCALER0_BASE + 0x07cc) ++#define MAIN_MSCA_ADDR_DBG__48_48 (MSCALER0_BASE + 0x07d0) ++#define MAIN_MSCA_ADDR_DBG__49_49 (MSCALER0_BASE + 0x07d4) ++#define MAIN_MSCA_ADDR_DBG__50_50 (MSCALER0_BASE + 0x07d8) ++#define MAIN_MSCA_ADDR_DBG__51_51 (MSCALER0_BASE + 0x07dc) ++#define MAIN_MSCA_ADDR_DBG__52_52 (MSCALER0_BASE + 0x07e0) ++#define MAIN_MSCA_ADDR_DBG__53_53 (MSCALER0_BASE + 0x07e4) ++#define MAIN_MSCA_ADDR_DBG__54_54 (MSCALER0_BASE + 0x07e8) ++#define MAIN_MSCA_ADDR_DBG__55_55 (MSCALER0_BASE + 0x07ec) ++#define MAIN_MSCA_ADDR_DBG__56_56 (MSCALER0_BASE + 0x07f0) ++#define MAIN_MSCA_ADDR_DBG__57_57 (MSCALER0_BASE + 0x07f4) ++#define MAIN_MSCA_ADDR_DBG__58_58 (MSCALER0_BASE + 0x07f8) ++#define MAIN_MSCA_ADDR_DBG__59_59 (MSCALER0_BASE + 0x07fc) ++#define MAIN_MSCA_ADDR_DBG__60_60 (MSCALER0_BASE + 0x0800) ++ ++#define SEC_MSCA_ADDR_CH_WORK_EN (MSCALER1_BASE + 0x0008) ++#define SEC_MSCA_ADDR_FORCE (MSCALER1_BASE + 0x000c) ++#define SEC_MSCA_ADDR_CTRL (MSCALER1_BASE + 0x0010) ++#define SEC_MSCA_ADDR_MASK_EN (MSCALER1_BASE + 0x0014) ++#define SEC_MSCA_ADDR_OSD_EN (MSCALER1_BASE + 0x0018) ++#define SEC_MSCA_ADDR_COEF_FIX_EN (MSCALER1_BASE + 0x0028) ++#define SEC_MSCA_ADDR_MIRR_FLIP_RSMP_SAMP_DONE (MSCALER1_BASE + 0x002c) ++#define SEC_MSCA_ADDR_CLK_GATE_EN (MSCALER1_BASE + 0x0030) ++#define SEC_MSCA_ADDR_CLK_GATE (MSCALER1_BASE + 0x0034) ++#define SEC_MSCA_ADDR_OSD_COEF_R (MSCALER1_BASE + 0x0050) ++#define SEC_MSCA_ADDR_OSD_COEF_G (MSCALER1_BASE + 0x0054) ++#define SEC_MSCA_ADDR_OSD_COEF_B (MSCALER1_BASE + 0x0058) ++#define SEC_MSCA_ADDR_OSD_COEF_OFT (MSCALER1_BASE + 0x005c) ++#define SEC_MSCA_ADDR_OSD_MODE (MSCALER1_BASE + 0x0060) ++#define SEC_MSCA_ADDR_OSD_ARGB_TYPE (MSCALER1_BASE + 0x0064) ++#define SEC_MSCA_ADDR_CH0_PRIO (MSCALER1_BASE + 0x0070) ++#define SEC_MSCA_ADDR_CH1_PRIO (MSCALER1_BASE + 0x0074) ++#define SEC_MSCA_ADDR_CH2_PRIO (MSCALER1_BASE + 0x0078) ++#define SEC_MSCA_ADDR_SRC_RSZ_POS (MSCALER1_BASE + 0x0080) ++#define SEC_MSCA_ADDR_SRC_RSZ_SIZE (MSCALER1_BASE + 0x0084) ++#define SEC_MSCA_ADDR_COEF_SEL (MSCALER1_BASE + 0x0088) ++#define SEC_MSCA_ADDR_CH0_BEFORE_IRQ (MSCALER1_BASE + 0x0090) ++#define SEC_MSCA_ADDR_CH1_BEFORE_IRQ (MSCALER1_BASE + 0x0094) ++#define SEC_MSCA_ADDR_CH2_BEFORE_IRQ (MSCALER1_BASE + 0x0098) ++#define SEC_MSCA_ADDR_CH0_FCROP_POS (MSCALER1_BASE + 0x00a0) ++#define SEC_MSCA_ADDR_CH0_FCROP_IMG (MSCALER1_BASE + 0x00a4) ++#define SEC_MSCA_ADDR_CH1_FCROP_POS (MSCALER1_BASE + 0x00a8) ++#define SEC_MSCA_ADDR_CH1_FCROP_IMG (MSCALER1_BASE + 0x00ac) ++#define SEC_MSCA_ADDR_CH2_FCROP_POS (MSCALER1_BASE + 0x00b0) ++#define SEC_MSCA_ADDR_CH2_FCROP_IMG (MSCALER1_BASE + 0x00b4) ++#define SEC_MSCA_ADDR_WORK_STAT (MSCALER1_BASE + 0x00e0) ++#define SEC_MSCA_ADDR_SYS_PRO_CLK_EN (MSCALER1_BASE + 0x00f0) ++#define SEC_MSCA_ADDR_CH0_CLK_NUM (MSCALER1_BASE + 0x00f4) ++#define SEC_MSCA_ADDR_CH1_CLK_NUM (MSCALER1_BASE + 0x00f8) ++#define SEC_MSCA_ADDR_CH2_CLK_NUM (MSCALER1_BASE + 0x00fc) ++#define SEC_MSCA_ADDR_CH0_RSZ_SIZE (MSCALER1_BASE + 0x0100) ++#define SEC_MSCA_ADDR_CH0_RSZ_STEP (MSCALER1_BASE + 0x0104) ++#define SEC_MSCA_ADDR_CH0_CROP_POS (MSCALER1_BASE + 0x0128) ++#define SEC_MSCA_ADDR_CH0_CROP_SIZE (MSCALER1_BASE + 0x012c) ++#define SEC_MSCA_ADDR_CH0_FR_CTRL_LOOP (MSCALER1_BASE + 0x0130) ++#define SEC_MSCA_ADDR_CH0_FR_CTRL_MASK (MSCALER1_BASE + 0x0134) ++#define SEC_MSCA_ADDR_CH0_MS0_POS (MSCALER1_BASE + 0x0138) ++#define SEC_MSCA_ADDR_CH0_MS0_SIZE (MSCALER1_BASE + 0x013c) ++#define SEC_MSCA_ADDR_CH0_MS0_VALUE (MSCALER1_BASE + 0x0140) ++#define SEC_MSCA_ADDR_CH0_MS1_POS (MSCALER1_BASE + 0x0144) ++#define SEC_MSCA_ADDR_CH0_MS1_SIZE (MSCALER1_BASE + 0x0148) ++#define SEC_MSCA_ADDR_CH0_MS1_VALUE (MSCALER1_BASE + 0x014c) ++#define SEC_MSCA_ADDR_CH0_MS2_POS (MSCALER1_BASE + 0x0150) ++#define SEC_MSCA_ADDR_CH0_MS2_SIZE (MSCALER1_BASE + 0x0154) ++#define SEC_MSCA_ADDR_CH0_MS2_VALUE (MSCALER1_BASE + 0x0158) ++#define SEC_MSCA_ADDR_CH0_MS3_POS (MSCALER1_BASE + 0x015c) ++#define SEC_MSCA_ADDR_CH0_MS3_SIZE (MSCALER1_BASE + 0x0160) ++#define SEC_MSCA_ADDR_CH0_MS3_VALUE (MSCALER1_BASE + 0x0164) ++#define SEC_MSCA_ADDR_CH0_OUT_FMT (MSCALER1_BASE + 0x0168) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_Y_ADDR (MSCALER1_BASE + 0x016c) ++#define SEC_MSCA_ADDR_CH0_Y_ADDR_FIFO_STA (MSCALER1_BASE + 0x0170) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_Y_LAST_ADDR (MSCALER1_BASE + 0x0174) ++#define SEC_MSCA_ADDR_CH0_Y_LAST_ADDR_FIFO_STA (MSCALER1_BASE + 0x017c) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_Y_STRIDE (MSCALER1_BASE + 0x0180) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_UV_ADDR (MSCALER1_BASE + 0x0184) ++#define SEC_MSCA_ADDR_CH0_UV_ADDR_FIFO_STA (MSCALER1_BASE + 0x0188) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_UV_LAST_ADDR (MSCALER1_BASE + 0x018c) ++#define SEC_MSCA_ADDR_CH0_UV_LAST_ADDR_FIFO_STA (MSCALER1_BASE + 0x0194) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_UV_STRIDE (MSCALER1_BASE + 0x0198) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_Y_ADDR_CLR (MSCALER1_BASE + 0x019c) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_UV_ADDR_CLR (MSCALER1_BASE + 0x01a0) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_Y_LAST_ADDR_CLR (MSCALER1_BASE + 0x01a4) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_UV_LAST_ADDR_CLR (MSCALER1_BASE + 0x01a8) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_Y_ADDR_SEL (MSCALER1_BASE + 0x01ac) ++#define SEC_MSCA_ADDR_CH0_DMAOUT_UV_ADDR_SEL (MSCALER1_BASE + 0x01b0) ++#define SEC_MSCA_ADDR_CH0_COE_ZERO_VRSZ_H (MSCALER1_BASE + 0x01c0) ++#define SEC_MSCA_ADDR_CH0_COE_ZERO_VRSZ_L (MSCALER1_BASE + 0x01c4) ++#define SEC_MSCA_ADDR_CH0_COE_ZERO_HRSZ_H (MSCALER1_BASE + 0x01c8) ++#define SEC_MSCA_ADDR_CH0_COE_ZERO_HRSZ_L (MSCALER1_BASE + 0x01cc) ++#define SEC_MSCA_ADDR_CH0_COE_OFT (MSCALER1_BASE + 0x01d0) ++#define SEC_MSCA_ADDR_CH0_ARF (MSCALER1_BASE + 0x01f0) ++#define SEC_MSCA_ADDR_CH0_CLR (MSCALER1_BASE + 0x01f4) ++#define SEC_MSCA_ADDR_CH1_RSZ_SIZE (MSCALER1_BASE + 0x0200) ++#define SEC_MSCA_ADDR_CH1_RSZ_STEP (MSCALER1_BASE + 0x0204) ++#define SEC_MSCA_ADDR_CH1_CROP_POS (MSCALER1_BASE + 0x0228) ++#define SEC_MSCA_ADDR_CH1_CROP_SIZE (MSCALER1_BASE + 0x022c) ++#define SEC_MSCA_ADDR_CH1_FR_CTRL_LOOP (MSCALER1_BASE + 0x0230) ++#define SEC_MSCA_ADDR_CH1_FR_CTRL_MASK (MSCALER1_BASE + 0x0234) ++#define SEC_MSCA_ADDR_CH1_MS0_POS (MSCALER1_BASE + 0x0238) ++#define SEC_MSCA_ADDR_CH1_MS0_SIZE (MSCALER1_BASE + 0x023c) ++#define SEC_MSCA_ADDR_CH1_MS0_VALUE (MSCALER1_BASE + 0x0240) ++#define SEC_MSCA_ADDR_CH1_MS1_POS (MSCALER1_BASE + 0x0244) ++#define SEC_MSCA_ADDR_CH1_MS1_SIZE (MSCALER1_BASE + 0x0248) ++#define SEC_MSCA_ADDR_CH1_MS1_VALUE (MSCALER1_BASE + 0x024c) ++#define SEC_MSCA_ADDR_CH1_MS2_POS (MSCALER1_BASE + 0x0250) ++#define SEC_MSCA_ADDR_CH1_MS2_SIZE (MSCALER1_BASE + 0x0254) ++#define SEC_MSCA_ADDR_CH1_MS2_VALUE (MSCALER1_BASE + 0x0258) ++#define SEC_MSCA_ADDR_CH1_MS3_POS (MSCALER1_BASE + 0x025c) ++#define SEC_MSCA_ADDR_CH1_MS3_SIZE (MSCALER1_BASE + 0x0260) ++#define SEC_MSCA_ADDR_CH1_MS3_VALUE (MSCALER1_BASE + 0x0264) ++#define SEC_MSCA_ADDR_CH1_OUT_FMT (MSCALER1_BASE + 0x0268) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_Y_ADDR (MSCALER1_BASE + 0x026c) ++#define SEC_MSCA_ADDR_CH1_Y_ADDR_FIFO_STA (MSCALER1_BASE + 0x0270) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_Y_LAST_ADDR (MSCALER1_BASE + 0x0274) ++#define SEC_MSCA_ADDR_CH1_Y_LAST_ADDR_FIFO_STA (MSCALER1_BASE + 0x027c) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_Y_STRIDE (MSCALER1_BASE + 0x0280) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_UV_ADDR (MSCALER1_BASE + 0x0284) ++#define SEC_MSCA_ADDR_CH1_UV_ADDR_FIFO_STA (MSCALER1_BASE + 0x0288) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_UV_LAST_ADDR (MSCALER1_BASE + 0x028c) ++#define SEC_MSCA_ADDR_CH1_UV_LAST_ADDR_FIFO_STA (MSCALER1_BASE + 0x0294) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_UV_STRIDE (MSCALER1_BASE + 0x0298) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_Y_ADDR_CLR (MSCALER1_BASE + 0x029c) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_UV_ADDR_CLR (MSCALER1_BASE + 0x02a0) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_Y_LAST_ADDR_CLR (MSCALER1_BASE + 0x02a4) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_UV_LAST_ADDR_CLR (MSCALER1_BASE + 0x02a8) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_Y_ADDR_SEL (MSCALER1_BASE + 0x02ac) ++#define SEC_MSCA_ADDR_CH1_DMAOUT_UV_ADDR_SEL (MSCALER1_BASE + 0x02b0) ++#define SEC_MSCA_ADDR_CH1_COE_ZERO_VRSZ_H (MSCALER1_BASE + 0x02c0) ++#define SEC_MSCA_ADDR_CH1_COE_ZERO_VRSZ_L (MSCALER1_BASE + 0x02c4) ++#define SEC_MSCA_ADDR_CH1_COE_ZERO_HRSZ_H (MSCALER1_BASE + 0x02c8) ++#define SEC_MSCA_ADDR_CH1_COE_ZERO_HRSZ_L (MSCALER1_BASE + 0x02cc) ++#define SEC_MSCA_ADDR_CH1_COE_OFT (MSCALER1_BASE + 0x02d0) ++#define SEC_MSCA_ADDR_CH1_ARF (MSCALER1_BASE + 0x02f0) ++#define SEC_MSCA_ADDR_CH1_CLR (MSCALER1_BASE + 0x02f4) ++#define SEC_MSCA_ADDR_CH2_RSZ_SIZE (MSCALER1_BASE + 0x0300) ++#define SEC_MSCA_ADDR_CH2_RSZ_STEP (MSCALER1_BASE + 0x0304) ++#define SEC_MSCA_ADDR_CH2_CROP_POS (MSCALER1_BASE + 0x0328) ++#define SEC_MSCA_ADDR_CH2_CROP_SIZE (MSCALER1_BASE + 0x032c) ++#define SEC_MSCA_ADDR_CH2_FR_CTRL_LOOP (MSCALER1_BASE + 0x0330) ++#define SEC_MSCA_ADDR_CH2_FR_CTRL_MASK (MSCALER1_BASE + 0x0334) ++#define SEC_MSCA_ADDR_CH2_MS0_POS (MSCALER1_BASE + 0x0338) ++#define SEC_MSCA_ADDR_CH2_MS0_SIZE (MSCALER1_BASE + 0x033c) ++#define SEC_MSCA_ADDR_CH2_MS0_VALUE (MSCALER1_BASE + 0x0340) ++#define SEC_MSCA_ADDR_CH2_MS1_POS (MSCALER1_BASE + 0x0344) ++#define SEC_MSCA_ADDR_CH2_MS1_SIZE (MSCALER1_BASE + 0x0348) ++#define SEC_MSCA_ADDR_CH2_MS1_VALUE (MSCALER1_BASE + 0x034c) ++#define SEC_MSCA_ADDR_CH2_MS2_POS (MSCALER1_BASE + 0x0350) ++#define SEC_MSCA_ADDR_CH2_MS2_SIZE (MSCALER1_BASE + 0x0354) ++#define SEC_MSCA_ADDR_CH2_MS2_VALUE (MSCALER1_BASE + 0x0358) ++#define SEC_MSCA_ADDR_CH2_MS3_POS (MSCALER1_BASE + 0x035c) ++#define SEC_MSCA_ADDR_CH2_MS3_SIZE (MSCALER1_BASE + 0x0360) ++#define SEC_MSCA_ADDR_CH2_MS3_VALUE (MSCALER1_BASE + 0x0364) ++#define SEC_MSCA_ADDR_CH2_OUT_FMT (MSCALER1_BASE + 0x0368) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_Y_ADDR (MSCALER1_BASE + 0x036c) ++#define SEC_MSCA_ADDR_CH2_Y_ADDR_FIFO_STA (MSCALER1_BASE + 0x0370) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_Y_LAST_ADDR (MSCALER1_BASE + 0x0374) ++#define SEC_MSCA_ADDR_CH2_Y_LAST_ADDR_FIFO_STA (MSCALER1_BASE + 0x037c) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_Y_STRIDE (MSCALER1_BASE + 0x0380) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_UV_ADDR (MSCALER1_BASE + 0x0384) ++#define SEC_MSCA_ADDR_CH2_UV_ADDR_FIFO_STA (MSCALER1_BASE + 0x0388) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_UV_LAST_ADDR (MSCALER1_BASE + 0x038c) ++#define SEC_MSCA_ADDR_CH2_UV_LAST_ADDR_FIFO_STA (MSCALER1_BASE + 0x0394) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_UV_STRIDE (MSCALER1_BASE + 0x0398) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_Y_ADDR_CLR (MSCALER1_BASE + 0x039c) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_UV_ADDR_CLR (MSCALER1_BASE + 0x03a0) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_Y_LAST_ADDR_CLR (MSCALER1_BASE + 0x03a4) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_UV_LAST_ADDR_CLR (MSCALER1_BASE + 0x03a8) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_Y_ADDR_SEL (MSCALER1_BASE + 0x03ac) ++#define SEC_MSCA_ADDR_CH2_DMAOUT_UV_ADDR_SEL (MSCALER1_BASE + 0x03b0) ++#define SEC_MSCA_ADDR_CH2_COE_ZERO_VRSZ_H (MSCALER1_BASE + 0x03c0) ++#define SEC_MSCA_ADDR_CH2_COE_ZERO_VRSZ_L (MSCALER1_BASE + 0x03c4) ++#define SEC_MSCA_ADDR_CH2_COE_ZERO_HRSZ_H (MSCALER1_BASE + 0x03c8) ++#define SEC_MSCA_ADDR_CH2_COE_ZERO_HRSZ_L (MSCALER1_BASE + 0x03cc) ++#define SEC_MSCA_ADDR_CH2_COE_OFT (MSCALER1_BASE + 0x03d0) ++#define SEC_MSCA_ADDR_CH2_ARF (MSCALER1_BASE + 0x03f0) ++#define SEC_MSCA_ADDR_CH2_CLR (MSCALER1_BASE + 0x03f4) ++#define SEC_MSCA_ADDR_CH0_LINE0_POS (MSCALER1_BASE + 0x0400) ++#define SEC_MSCA_ADDR_CH0_LINE0_SIZE (MSCALER1_BASE + 0x0404) ++#define SEC_MSCA_ADDR_CH0_LINE0_PAR0 (MSCALER1_BASE + 0x0408) ++#define SEC_MSCA_ADDR_CH0_LINE0_PAR1 (MSCALER1_BASE + 0x040c) ++#define SEC_MSCA_ADDR_CH0_LINE1_POS (MSCALER1_BASE + 0x0410) ++#define SEC_MSCA_ADDR_CH0_LINE1_SIZE (MSCALER1_BASE + 0x0414) ++#define SEC_MSCA_ADDR_CH0_LINE1_PAR0 (MSCALER1_BASE + 0x0418) ++#define SEC_MSCA_ADDR_CH0_LINE1_PAR1 (MSCALER1_BASE + 0x041c) ++#define SEC_MSCA_ADDR_CH0_LINE2_POS (MSCALER1_BASE + 0x0420) ++#define SEC_MSCA_ADDR_CH0_LINE2_SIZE (MSCALER1_BASE + 0x0424) ++#define SEC_MSCA_ADDR_CH0_LINE2_PAR0 (MSCALER1_BASE + 0x0428) ++#define SEC_MSCA_ADDR_CH0_LINE2_PAR1 (MSCALER1_BASE + 0x042c) ++#define SEC_MSCA_ADDR_CH0_LINE3_POS (MSCALER1_BASE + 0x0430) ++#define SEC_MSCA_ADDR_CH0_LINE3_SIZE (MSCALER1_BASE + 0x0434) ++#define SEC_MSCA_ADDR_CH0_LINE3_PAR0 (MSCALER1_BASE + 0x0438) ++#define SEC_MSCA_ADDR_CH0_LINE3_PAR1 (MSCALER1_BASE + 0x043c) ++#define SEC_MSCA_ADDR_CH0_LINE4_POS (MSCALER1_BASE + 0x0440) ++#define SEC_MSCA_ADDR_CH0_LINE4_SIZE (MSCALER1_BASE + 0x0444) ++#define SEC_MSCA_ADDR_CH0_LINE4_PAR0 (MSCALER1_BASE + 0x0448) ++#define SEC_MSCA_ADDR_CH0_LINE4_PAR1 (MSCALER1_BASE + 0x044c) ++#define SEC_MSCA_ADDR_CH0_LINE5_POS (MSCALER1_BASE + 0x0450) ++#define SEC_MSCA_ADDR_CH0_LINE5_SIZE (MSCALER1_BASE + 0x0454) ++#define SEC_MSCA_ADDR_CH0_LINE5_PAR0 (MSCALER1_BASE + 0x0458) ++#define SEC_MSCA_ADDR_CH0_LINE5_PAR1 (MSCALER1_BASE + 0x045c) ++#define SEC_MSCA_ADDR_CH0_LINE6_POS (MSCALER1_BASE + 0x0460) ++#define SEC_MSCA_ADDR_CH0_LINE6_SIZE (MSCALER1_BASE + 0x0464) ++#define SEC_MSCA_ADDR_CH0_LINE6_PAR0 (MSCALER1_BASE + 0x0468) ++#define SEC_MSCA_ADDR_CH0_LINE6_PAR1 (MSCALER1_BASE + 0x046c) ++#define SEC_MSCA_ADDR_CH0_LINE7_POS (MSCALER1_BASE + 0x0470) ++#define SEC_MSCA_ADDR_CH0_LINE7_SIZE (MSCALER1_BASE + 0x0474) ++#define SEC_MSCA_ADDR_CH0_LINE7_PAR0 (MSCALER1_BASE + 0x0478) ++#define SEC_MSCA_ADDR_CH0_LINE7_PAR1 (MSCALER1_BASE + 0x047c) ++#define SEC_MSCA_ADDR_CH0_LINE8_POS (MSCALER1_BASE + 0x0480) ++#define SEC_MSCA_ADDR_CH0_LINE8_SIZE (MSCALER1_BASE + 0x0484) ++#define SEC_MSCA_ADDR_CH0_LINE8_PAR0 (MSCALER1_BASE + 0x0488) ++#define SEC_MSCA_ADDR_CH0_LINE8_PAR1 (MSCALER1_BASE + 0x048c) ++#define SEC_MSCA_ADDR_CH0_LINE9_POS (MSCALER1_BASE + 0x0490) ++#define SEC_MSCA_ADDR_CH0_LINE9_SIZE (MSCALER1_BASE + 0x0494) ++#define SEC_MSCA_ADDR_CH0_LINE9_PAR0 (MSCALER1_BASE + 0x0498) ++#define SEC_MSCA_ADDR_CH0_LINE9_PAR1 (MSCALER1_BASE + 0x049c) ++#define SEC_MSCA_ADDR_CH0_LINE10_POS (MSCALER1_BASE + 0x04a0) ++#define SEC_MSCA_ADDR_CH0_LINE10_SIZE (MSCALER1_BASE + 0x04a4) ++#define SEC_MSCA_ADDR_CH0_LINE10_PAR0 (MSCALER1_BASE + 0x04a8) ++#define SEC_MSCA_ADDR_CH0_LINE10_PAR1 (MSCALER1_BASE + 0x04ac) ++#define SEC_MSCA_ADDR_CH0_LINE11_POS (MSCALER1_BASE + 0x04b0) ++#define SEC_MSCA_ADDR_CH0_LINE11_SIZE (MSCALER1_BASE + 0x04b4) ++#define SEC_MSCA_ADDR_CH0_LINE11_PAR0 (MSCALER1_BASE + 0x04b8) ++#define SEC_MSCA_ADDR_CH0_LINE11_PAR1 (MSCALER1_BASE + 0x04bc) ++#define SEC_MSCA_ADDR_CH0_LINE12_POS (MSCALER1_BASE + 0x04c0) ++#define SEC_MSCA_ADDR_CH0_LINE12_SIZE (MSCALER1_BASE + 0x04c4) ++#define SEC_MSCA_ADDR_CH0_LINE12_PAR0 (MSCALER1_BASE + 0x04c8) ++#define SEC_MSCA_ADDR_CH0_LINE12_PAR1 (MSCALER1_BASE + 0x04cc) ++#define SEC_MSCA_ADDR_CH0_LINE13_POS (MSCALER1_BASE + 0x04d0) ++#define SEC_MSCA_ADDR_CH0_LINE13_SIZE (MSCALER1_BASE + 0x04d4) ++#define SEC_MSCA_ADDR_CH0_LINE13_PAR0 (MSCALER1_BASE + 0x04d8) ++#define SEC_MSCA_ADDR_CH0_LINE13_PAR1 (MSCALER1_BASE + 0x04dc) ++#define SEC_MSCA_ADDR_CH0_LINE14_POS (MSCALER1_BASE + 0x04e0) ++#define SEC_MSCA_ADDR_CH0_LINE14_SIZE (MSCALER1_BASE + 0x04e4) ++#define SEC_MSCA_ADDR_CH0_LINE14_PAR0 (MSCALER1_BASE + 0x04e8) ++#define SEC_MSCA_ADDR_CH0_LINE14_PAR1 (MSCALER1_BASE + 0x04ec) ++#define SEC_MSCA_ADDR_CH0_LINE15_POS (MSCALER1_BASE + 0x04f0) ++#define SEC_MSCA_ADDR_CH0_LINE15_SIZE (MSCALER1_BASE + 0x04f4) ++#define SEC_MSCA_ADDR_CH0_LINE15_PAR0 (MSCALER1_BASE + 0x04f8) ++#define SEC_MSCA_ADDR_CH0_LINE15_PAR1 (MSCALER1_BASE + 0x04fc) ++#define SEC_MSCA_ADDR_CH1_LINE0_POS (MSCALER1_BASE + 0x0500) ++#define SEC_MSCA_ADDR_CH1_LINE0_SIZE (MSCALER1_BASE + 0x0504) ++#define SEC_MSCA_ADDR_CH1_LINE0_PAR0 (MSCALER1_BASE + 0x0508) ++#define SEC_MSCA_ADDR_CH1_LINE0_PAR1 (MSCALER1_BASE + 0x050c) ++#define SEC_MSCA_ADDR_CH1_LINE1_POS (MSCALER1_BASE + 0x0510) ++#define SEC_MSCA_ADDR_CH1_LINE1_SIZE (MSCALER1_BASE + 0x0514) ++#define SEC_MSCA_ADDR_CH1_LINE1_PAR0 (MSCALER1_BASE + 0x0518) ++#define SEC_MSCA_ADDR_CH1_LINE1_PAR1 (MSCALER1_BASE + 0x051c) ++#define SEC_MSCA_ADDR_CH1_LINE2_POS (MSCALER1_BASE + 0x0520) ++#define SEC_MSCA_ADDR_CH1_LINE2_SIZE (MSCALER1_BASE + 0x0524) ++#define SEC_MSCA_ADDR_CH1_LINE2_PAR0 (MSCALER1_BASE + 0x0528) ++#define SEC_MSCA_ADDR_CH1_LINE2_PAR1 (MSCALER1_BASE + 0x052c) ++#define SEC_MSCA_ADDR_CH1_LINE3_POS (MSCALER1_BASE + 0x0530) ++#define SEC_MSCA_ADDR_CH1_LINE3_SIZE (MSCALER1_BASE + 0x0534) ++#define SEC_MSCA_ADDR_CH1_LINE3_PAR0 (MSCALER1_BASE + 0x0538) ++#define SEC_MSCA_ADDR_CH1_LINE3_PAR1 (MSCALER1_BASE + 0x053c) ++#define SEC_MSCA_ADDR_CH1_LINE4_POS (MSCALER1_BASE + 0x0540) ++#define SEC_MSCA_ADDR_CH1_LINE4_SIZE (MSCALER1_BASE + 0x0544) ++#define SEC_MSCA_ADDR_CH1_LINE4_PAR0 (MSCALER1_BASE + 0x0548) ++#define SEC_MSCA_ADDR_CH1_LINE4_PAR1 (MSCALER1_BASE + 0x054c) ++#define SEC_MSCA_ADDR_CH1_LINE5_POS (MSCALER1_BASE + 0x0550) ++#define SEC_MSCA_ADDR_CH1_LINE5_SIZE (MSCALER1_BASE + 0x0554) ++#define SEC_MSCA_ADDR_CH1_LINE5_PAR0 (MSCALER1_BASE + 0x0558) ++#define SEC_MSCA_ADDR_CH1_LINE5_PAR1 (MSCALER1_BASE + 0x055c) ++#define SEC_MSCA_ADDR_CH1_LINE6_POS (MSCALER1_BASE + 0x0560) ++#define SEC_MSCA_ADDR_CH1_LINE6_SIZE (MSCALER1_BASE + 0x0564) ++#define SEC_MSCA_ADDR_CH1_LINE6_PAR0 (MSCALER1_BASE + 0x0568) ++#define SEC_MSCA_ADDR_CH1_LINE6_PAR1 (MSCALER1_BASE + 0x056c) ++#define SEC_MSCA_ADDR_CH1_LINE7_POS (MSCALER1_BASE + 0x0570) ++#define SEC_MSCA_ADDR_CH1_LINE7_SIZE (MSCALER1_BASE + 0x0574) ++#define SEC_MSCA_ADDR_CH1_LINE7_PAR0 (MSCALER1_BASE + 0x0578) ++#define SEC_MSCA_ADDR_CH1_LINE7_PAR1 (MSCALER1_BASE + 0x057c) ++#define SEC_MSCA_ADDR_CH1_LINE8_POS (MSCALER1_BASE + 0x0580) ++#define SEC_MSCA_ADDR_CH1_LINE8_SIZE (MSCALER1_BASE + 0x0584) ++#define SEC_MSCA_ADDR_CH1_LINE8_PAR0 (MSCALER1_BASE + 0x0588) ++#define SEC_MSCA_ADDR_CH1_LINE8_PAR1 (MSCALER1_BASE + 0x058c) ++#define SEC_MSCA_ADDR_CH1_LINE9_POS (MSCALER1_BASE + 0x0590) ++#define SEC_MSCA_ADDR_CH1_LINE9_SIZE (MSCALER1_BASE + 0x0594) ++#define SEC_MSCA_ADDR_CH1_LINE9_PAR0 (MSCALER1_BASE + 0x0598) ++#define SEC_MSCA_ADDR_CH1_LINE9_PAR1 (MSCALER1_BASE + 0x059c) ++#define SEC_MSCA_ADDR_CH1_LINE10_POS (MSCALER1_BASE + 0x05a0) ++#define SEC_MSCA_ADDR_CH1_LINE10_SIZE (MSCALER1_BASE + 0x05a4) ++#define SEC_MSCA_ADDR_CH1_LINE10_PAR0 (MSCALER1_BASE + 0x05a8) ++#define SEC_MSCA_ADDR_CH1_LINE10_PAR1 (MSCALER1_BASE + 0x05ac) ++#define SEC_MSCA_ADDR_CH1_LINE11_POS (MSCALER1_BASE + 0x05b0) ++#define SEC_MSCA_ADDR_CH1_LINE11_SIZE (MSCALER1_BASE + 0x05b4) ++#define SEC_MSCA_ADDR_CH1_LINE11_PAR0 (MSCALER1_BASE + 0x05b8) ++#define SEC_MSCA_ADDR_CH1_LINE11_PAR1 (MSCALER1_BASE + 0x05bc) ++#define SEC_MSCA_ADDR_CH1_LINE12_POS (MSCALER1_BASE + 0x05c0) ++#define SEC_MSCA_ADDR_CH1_LINE12_SIZE (MSCALER1_BASE + 0x05c4) ++#define SEC_MSCA_ADDR_CH1_LINE12_PAR0 (MSCALER1_BASE + 0x05c8) ++#define SEC_MSCA_ADDR_CH1_LINE12_PAR1 (MSCALER1_BASE + 0x05cc) ++#define SEC_MSCA_ADDR_CH1_LINE13_POS (MSCALER1_BASE + 0x05d0) ++#define SEC_MSCA_ADDR_CH1_LINE13_SIZE (MSCALER1_BASE + 0x05d4) ++#define SEC_MSCA_ADDR_CH1_LINE13_PAR0 (MSCALER1_BASE + 0x05d8) ++#define SEC_MSCA_ADDR_CH1_LINE13_PAR1 (MSCALER1_BASE + 0x05dc) ++#define SEC_MSCA_ADDR_CH1_LINE14_POS (MSCALER1_BASE + 0x05e0) ++#define SEC_MSCA_ADDR_CH1_LINE14_SIZE (MSCALER1_BASE + 0x05e4) ++#define SEC_MSCA_ADDR_CH1_LINE14_PAR0 (MSCALER1_BASE + 0x05e8) ++#define SEC_MSCA_ADDR_CH1_LINE14_PAR1 (MSCALER1_BASE + 0x05ec) ++#define SEC_MSCA_ADDR_CH1_LINE15_POS (MSCALER1_BASE + 0x05f0) ++#define SEC_MSCA_ADDR_CH1_LINE15_SIZE (MSCALER1_BASE + 0x05f4) ++#define SEC_MSCA_ADDR_CH1_LINE15_PAR0 (MSCALER1_BASE + 0x05f8) ++#define SEC_MSCA_ADDR_CH1_LINE15_PAR1 (MSCALER1_BASE + 0x05fc) ++#define SEC_MSCA_ADDR_CH0_OSD0_POS (MSCALER1_BASE + 0x0600) ++#define SEC_MSCA_ADDR_CH0_OSD0_SIZE (MSCALER1_BASE + 0x0604) ++#define SEC_MSCA_ADDR_CH0_OSD0_ADDR (MSCALER1_BASE + 0x0608) ++#define SEC_MSCA_ADDR_CH0_OSD0_STRIDE (MSCALER1_BASE + 0x060c) ++#define SEC_MSCA_ADDR_CH0_OSD1_POS (MSCALER1_BASE + 0x0610) ++#define SEC_MSCA_ADDR_CH0_OSD1_SIZE (MSCALER1_BASE + 0x0614) ++#define SEC_MSCA_ADDR_CH0_OSD1_ADDR (MSCALER1_BASE + 0x0618) ++#define SEC_MSCA_ADDR_CH0_OSD1_STRIDE (MSCALER1_BASE + 0x061c) ++#define SEC_MSCA_ADDR_CH0_OSD2_POS (MSCALER1_BASE + 0x0620) ++#define SEC_MSCA_ADDR_CH0_OSD2_SIZE (MSCALER1_BASE + 0x0624) ++#define SEC_MSCA_ADDR_CH0_OSD2_ADDR (MSCALER1_BASE + 0x0628) ++#define SEC_MSCA_ADDR_CH0_OSD2_STRIDE (MSCALER1_BASE + 0x062c) ++#define SEC_MSCA_ADDR_CH0_OSD3_POS (MSCALER1_BASE + 0x0630) ++#define SEC_MSCA_ADDR_CH0_OSD3_SIZE (MSCALER1_BASE + 0x0634) ++#define SEC_MSCA_ADDR_CH0_OSD3_ADDR (MSCALER1_BASE + 0x0638) ++#define SEC_MSCA_ADDR_CH0_OSD3_STRIDE (MSCALER1_BASE + 0x063c) ++#define SEC_MSCA_ADDR_CH0_OSD4_POS (MSCALER1_BASE + 0x0640) ++#define SEC_MSCA_ADDR_CH0_OSD4_SIZE (MSCALER1_BASE + 0x0644) ++#define SEC_MSCA_ADDR_CH0_OSD4_ADDR (MSCALER1_BASE + 0x0648) ++#define SEC_MSCA_ADDR_CH0_OSD4_STRIDE (MSCALER1_BASE + 0x064c) ++#define SEC_MSCA_ADDR_CH0_OSD5_POS (MSCALER1_BASE + 0x0650) ++#define SEC_MSCA_ADDR_CH0_OSD5_SIZE (MSCALER1_BASE + 0x0654) ++#define SEC_MSCA_ADDR_CH0_OSD5_ADDR (MSCALER1_BASE + 0x0658) ++#define SEC_MSCA_ADDR_CH0_OSD5_STRIDE (MSCALER1_BASE + 0x065c) ++#define SEC_MSCA_ADDR_CH0_OSD6_POS (MSCALER1_BASE + 0x0660) ++#define SEC_MSCA_ADDR_CH0_OSD6_SIZE (MSCALER1_BASE + 0x0664) ++#define SEC_MSCA_ADDR_CH0_OSD6_ADDR (MSCALER1_BASE + 0x0668) ++#define SEC_MSCA_ADDR_CH0_OSD6_STRIDE (MSCALER1_BASE + 0x066c) ++#define SEC_MSCA_ADDR_CH0_OSD7_POS (MSCALER1_BASE + 0x0670) ++#define SEC_MSCA_ADDR_CH0_OSD7_SIZE (MSCALER1_BASE + 0x0674) ++#define SEC_MSCA_ADDR_CH0_OSD7_ADDR (MSCALER1_BASE + 0x0678) ++#define SEC_MSCA_ADDR_CH0_OSD7_STRIDE (MSCALER1_BASE + 0x067c) ++#define SEC_MSCA_ADDR_CH1_OSD0_POS (MSCALER1_BASE + 0x0680) ++#define SEC_MSCA_ADDR_CH1_OSD0_SIZE (MSCALER1_BASE + 0x0684) ++#define SEC_MSCA_ADDR_CH1_OSD0_ADDR (MSCALER1_BASE + 0x0688) ++#define SEC_MSCA_ADDR_CH1_OSD0_STRIDE (MSCALER1_BASE + 0x068c) ++#define SEC_MSCA_ADDR_CH1_OSD1_POS (MSCALER1_BASE + 0x0690) ++#define SEC_MSCA_ADDR_CH1_OSD1_SIZE (MSCALER1_BASE + 0x0694) ++#define SEC_MSCA_ADDR_CH1_OSD1_ADDR (MSCALER1_BASE + 0x0698) ++#define SEC_MSCA_ADDR_CH1_OSD1_STRIDE (MSCALER1_BASE + 0x069c) ++#define SEC_MSCA_ADDR_CH1_OSD2_POS (MSCALER1_BASE + 0x06a0) ++#define SEC_MSCA_ADDR_CH1_OSD2_SIZE (MSCALER1_BASE + 0x06a4) ++#define SEC_MSCA_ADDR_CH1_OSD2_ADDR (MSCALER1_BASE + 0x06a8) ++#define SEC_MSCA_ADDR_CH1_OSD2_STRIDE (MSCALER1_BASE + 0x06ac) ++#define SEC_MSCA_ADDR_CH1_OSD3_POS (MSCALER1_BASE + 0x06b0) ++#define SEC_MSCA_ADDR_CH1_OSD3_SIZE (MSCALER1_BASE + 0x06b4) ++#define SEC_MSCA_ADDR_CH1_OSD3_ADDR (MSCALER1_BASE + 0x06b8) ++#define SEC_MSCA_ADDR_CH1_OSD3_STRIDE (MSCALER1_BASE + 0x06bc) ++#define SEC_MSCA_ADDR_CH1_OSD4_POS (MSCALER1_BASE + 0x06c0) ++#define SEC_MSCA_ADDR_CH1_OSD4_SIZE (MSCALER1_BASE + 0x06c4) ++#define SEC_MSCA_ADDR_CH1_OSD4_ADDR (MSCALER1_BASE + 0x06c8) ++#define SEC_MSCA_ADDR_CH1_OSD4_STRIDE (MSCALER1_BASE + 0x06cc) ++#define SEC_MSCA_ADDR_CH1_OSD5_POS (MSCALER1_BASE + 0x06d0) ++#define SEC_MSCA_ADDR_CH1_OSD5_SIZE (MSCALER1_BASE + 0x06d4) ++#define SEC_MSCA_ADDR_CH1_OSD5_ADDR (MSCALER1_BASE + 0x06d8) ++#define SEC_MSCA_ADDR_CH1_OSD5_STRIDE (MSCALER1_BASE + 0x06dc) ++#define SEC_MSCA_ADDR_CH1_OSD6_POS (MSCALER1_BASE + 0x06e0) ++#define SEC_MSCA_ADDR_CH1_OSD6_SIZE (MSCALER1_BASE + 0x06e4) ++#define SEC_MSCA_ADDR_CH1_OSD6_ADDR (MSCALER1_BASE + 0x06e8) ++#define SEC_MSCA_ADDR_CH1_OSD6_STRIDE (MSCALER1_BASE + 0x06ec) ++#define SEC_MSCA_ADDR_CH1_OSD7_POS (MSCALER1_BASE + 0x06f0) ++#define SEC_MSCA_ADDR_CH1_OSD7_SIZE (MSCALER1_BASE + 0x06f4) ++#define SEC_MSCA_ADDR_CH1_OSD7_ADDR (MSCALER1_BASE + 0x06f8) ++#define SEC_MSCA_ADDR_CH1_OSD7_STRIDE (MSCALER1_BASE + 0x06fc) ++#define SEC_MSCA_ADDR_BACK_DOOR (MSCALER1_BASE + 0x0700) ++#define SEC_MSCA_ADDR_DBG__00_00 (MSCALER1_BASE + 0x0710) ++#define SEC_MSCA_ADDR_DBG__01_01 (MSCALER1_BASE + 0x0714) ++#define SEC_MSCA_ADDR_DBG__02_02 (MSCALER1_BASE + 0x0718) ++#define SEC_MSCA_ADDR_DBG__03_03 (MSCALER1_BASE + 0x071c) ++#define SEC_MSCA_ADDR_DBG__04_04 (MSCALER1_BASE + 0x0720) ++#define SEC_MSCA_ADDR_DBG__05_05 (MSCALER1_BASE + 0x0724) ++#define SEC_MSCA_ADDR_DBG__06_06 (MSCALER1_BASE + 0x0728) ++#define SEC_MSCA_ADDR_DBG__07_07 (MSCALER1_BASE + 0x072c) ++#define SEC_MSCA_ADDR_DBG__08_08 (MSCALER1_BASE + 0x0730) ++#define SEC_MSCA_ADDR_DBG__09_09 (MSCALER1_BASE + 0x0734) ++#define SEC_MSCA_ADDR_DBG__10_10 (MSCALER1_BASE + 0x0738) ++#define SEC_MSCA_ADDR_DBG__11_11 (MSCALER1_BASE + 0x073c) ++#define SEC_MSCA_ADDR_DBG__12_12 (MSCALER1_BASE + 0x0740) ++#define SEC_MSCA_ADDR_DBG__13_13 (MSCALER1_BASE + 0x0744) ++#define SEC_MSCA_ADDR_DBG__14_14 (MSCALER1_BASE + 0x0748) ++#define SEC_MSCA_ADDR_DBG__15_15 (MSCALER1_BASE + 0x074c) ++#define SEC_MSCA_ADDR_DBG__16_16 (MSCALER1_BASE + 0x0750) ++#define SEC_MSCA_ADDR_DBG__17_17 (MSCALER1_BASE + 0x0754) ++#define SEC_MSCA_ADDR_DBG__18_18 (MSCALER1_BASE + 0x0758) ++#define SEC_MSCA_ADDR_DBG__19_19 (MSCALER1_BASE + 0x075c) ++#define SEC_MSCA_ADDR_DBG__20_20 (MSCALER1_BASE + 0x0760) ++#define SEC_MSCA_ADDR_DBG__21_21 (MSCALER1_BASE + 0x0764) ++#define SEC_MSCA_ADDR_DBG__22_22 (MSCALER1_BASE + 0x0768) ++#define SEC_MSCA_ADDR_DBG__23_23 (MSCALER1_BASE + 0x076c) ++#define SEC_MSCA_ADDR_DBG__24_24 (MSCALER1_BASE + 0x0770) ++#define SEC_MSCA_ADDR_DBG__25_25 (MSCALER1_BASE + 0x0774) ++#define SEC_MSCA_ADDR_DBG__26_26 (MSCALER1_BASE + 0x0778) ++#define SEC_MSCA_ADDR_DBG__27_27 (MSCALER1_BASE + 0x077c) ++#define SEC_MSCA_ADDR_DBG__28_28 (MSCALER1_BASE + 0x0780) ++#define SEC_MSCA_ADDR_DBG__29_29 (MSCALER1_BASE + 0x0784) ++#define SEC_MSCA_ADDR_DBG__30_30 (MSCALER1_BASE + 0x0788) ++#define SEC_MSCA_ADDR_DBG__31_31 (MSCALER1_BASE + 0x078c) ++#define SEC_MSCA_ADDR_DBG__32_32 (MSCALER1_BASE + 0x0790) ++#define SEC_MSCA_ADDR_DBG__33_33 (MSCALER1_BASE + 0x0794) ++#define SEC_MSCA_ADDR_DBG__34_34 (MSCALER1_BASE + 0x0798) ++#define SEC_MSCA_ADDR_DBG__35_35 (MSCALER1_BASE + 0x079c) ++#define SEC_MSCA_ADDR_DBG__36_36 (MSCALER1_BASE + 0x07a0) ++#define SEC_MSCA_ADDR_DBG__37_37 (MSCALER1_BASE + 0x07a4) ++#define SEC_MSCA_ADDR_DBG__38_38 (MSCALER1_BASE + 0x07a8) ++#define SEC_MSCA_ADDR_DBG__39_39 (MSCALER1_BASE + 0x07ac) ++#define SEC_MSCA_ADDR_DBG__40_40 (MSCALER1_BASE + 0x07b0) ++#define SEC_MSCA_ADDR_DBG__41_41 (MSCALER1_BASE + 0x07b4) ++#define SEC_MSCA_ADDR_DBG__42_42 (MSCALER1_BASE + 0x07b8) ++#define SEC_MSCA_ADDR_DBG__43_43 (MSCALER1_BASE + 0x07bc) ++#define SEC_MSCA_ADDR_DBG__44_44 (MSCALER1_BASE + 0x07c0) ++#define SEC_MSCA_ADDR_DBG__45_45 (MSCALER1_BASE + 0x07c4) ++#define SEC_MSCA_ADDR_DBG__46_46 (MSCALER1_BASE + 0x07c8) ++#define SEC_MSCA_ADDR_DBG__47_47 (MSCALER1_BASE + 0x07cc) ++#define SEC_MSCA_ADDR_DBG__48_48 (MSCALER1_BASE + 0x07d0) ++#define SEC_MSCA_ADDR_DBG__49_49 (MSCALER1_BASE + 0x07d4) ++#define SEC_MSCA_ADDR_DBG__50_50 (MSCALER1_BASE + 0x07d8) ++#define SEC_MSCA_ADDR_DBG__51_51 (MSCALER1_BASE + 0x07dc) ++#define SEC_MSCA_ADDR_DBG__52_52 (MSCALER1_BASE + 0x07e0) ++#define SEC_MSCA_ADDR_DBG__53_53 (MSCALER1_BASE + 0x07e4) ++#define SEC_MSCA_ADDR_DBG__54_54 (MSCALER1_BASE + 0x07e8) ++#define SEC_MSCA_ADDR_DBG__55_55 (MSCALER1_BASE + 0x07ec) ++#define SEC_MSCA_ADDR_DBG__56_56 (MSCALER1_BASE + 0x07f0) ++#define SEC_MSCA_ADDR_DBG__57_57 (MSCALER1_BASE + 0x07f4) ++#define SEC_MSCA_ADDR_DBG__58_58 (MSCALER1_BASE + 0x07f8) ++#define SEC_MSCA_ADDR_DBG__59_59 (MSCALER1_BASE + 0x07fc) ++#define SEC_MSCA_ADDR_DBG__60_60 (MSCALER1_BASE + 0x0800) ++ ++#define MSCA_ADDR_CH_WORK_EN (MSCALER0_BASE + 0x0008) ++#define MSCA_ADDR_FORCE (MSCALER0_BASE + 0x000C) ++#define MSCA_ADDR_CTRL (MSCALER0_BASE + 0x0010) ++#define MSCA_ADDR_MASK_EN (MSCALER0_BASE + 0x0014) ++#define MSCA_ADDR_OSD_EN (MSCALER0_BASE + 0x0018) ++#define MSCA_ADDR_MIRR_FLIP_RSMP_SAMP_DONE (MSCALER0_BASE + 0x002c) ++#define MSCA_ADDR_OSD_MODE (MSCALER0_BASE + 0x0060) ++#define MSCA_ADDR_OSD_ARGB_TYPE (MSCALER0_BASE + 0x0064) ++#define MSCA_ADDR_SRC_RSZ_POS (MSCALER0_BASE + 0x0080) ++#define MSCA_ADDR_SRC_RSZ_SIZE (MSCALER0_BASE + 0x0084) ++ ++#define MSCA_ADDR_CHx_FCROP_POS(n) (MSCALER0_BASE + 0x00a0 + (n * 0x008)) ++#define MSCA_ADDR_CHx_FCROP_IMG(n) (MSCALER0_BASE + 0x00a4 + (n * 0x008)) ++#define MSCA_ADDR_CHx_RSZ_SIZE(n) (MSCALER0_BASE + 0x0100 + (n * 0x100)) ++#define MSCA_ADDR_CHx_RSZ_STEP(n) (MSCALER0_BASE + 0x0104 + (n * 0x100)) ++#define MSCA_ADDR_CHx_CROP_POS(n) (MSCALER0_BASE + 0x0128 + (n * 0x100)) ++#define MSCA_ADDR_CHx_CROP_SIZE(n) (MSCALER0_BASE + 0x012c + (n * 0x100)) ++#define MSCA_ADDR_CHx_FR_CTRL_LOOP(n) (MSCALER0_BASE + 0x0130 + (n * 0x100)) ++#define MSCA_ADDR_CHx_FR_CTRL_MASK(n) (MSCALER0_BASE + 0x0134 + (n * 0x100)) ++#define MSCA_ADDR_CHx_OUT_FMT(n) (MSCALER0_BASE + 0x0168 + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_Y_ADDR(n) (MSCALER0_BASE + 0x016c + (n * 0x100)) ++#define MSCA_ADDR_CHx_Y_ADDR_FIFO_STA(n) (MSCALER0_BASE + 0x0170 + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_Y_LAST_ADDR(n) (MSCALER0_BASE + 0x0174 + (n * 0x100)) ++#define MSCA_ADDR_CHx_Y_LAST_ADDR_FIFO_STA(n) (MSCALER0_BASE + 0x017c + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_Y_STRIDE(n) (MSCALER0_BASE + 0x0180 + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_UV_ADDR(n) (MSCALER0_BASE + 0x0184 + (n * 0x100)) ++#define MSCA_ADDR_CHx_UV_ADDR_FIFO_STA(n) (MSCALER0_BASE + 0x0188 + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_UV_LAST_ADDR(n) (MSCALER0_BASE + 0x018c + (n * 0x100)) ++#define MSCA_ADDR_CHx_UV_LAST_ADDR_FIFO_STA(n) (MSCALER0_BASE + 0x0194 + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_UV_STRIDE(n) (MSCALER0_BASE + 0x0198 + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_Y_ADDR_CLR(n) (MSCALER0_BASE + 0x019c + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_UV_ADDR_CLR(n) (MSCALER0_BASE + 0x01a0 + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_Y_LAST_ADDR_CLR(n) (MSCALER0_BASE + 0x01a4 + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_UV_LAST_ADDR_CLR(n) (MSCALER0_BASE + 0x01a8 + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_Y_ADDR_SEL(n) (MSCALER0_BASE + 0x01ac + (n * 0x100)) ++#define MSCA_ADDR_CHx_DMAOUT_UV_ADDR_SEL(n) (MSCALER0_BASE + 0x01b0 + (n * 0x100)) ++#define MSCA_ADDR_CHx_COE_ZERO_VRSZ_H(n) (MSCALER0_BASE + 0x01c0 + (n * 0x100)) ++#define MSCA_ADDR_CHx_COE_ZERO_VRSZ_L(n) (MSCALER0_BASE + 0x01c4 + (n * 0x100)) ++#define MSCA_ADDR_CHx_COE_ZERO_HRSZ_H(n) (MSCALER0_BASE + 0x01c8 + (n * 0x100)) ++#define MSCA_ADDR_CHx_COE_ZERO_HRSZ_L(n) (MSCALER0_BASE + 0x01cc + (n * 0x100)) ++#define MSCA_ADDR_CHx_COE_OFT(n) (MSCALER0_BASE + 0x01d0 + (n * 0x100)) ++#define MSCA_ADDR_CHx_ARF(n) (MSCALER0_BASE + 0x01f0 + (n * 0x100)) ++#define MSCA_ADDR_CHx_CLR(n) (MSCALER0_BASE + 0x01f4 + (n * 0x100)) ++ ++#define MSCA_ADDR_CHx_MSx_POS(n,k) (MSCALER0_BASE + 0x0138 + (n * 0x100) + (k * 0x0c)) ++#define MSCA_ADDR_CHx_MSx_SIZE(n,k) (MSCALER0_BASE + 0x013c + (n * 0x100) + (k * 0x0c)) ++#define MSCA_ADDR_CHx_MSx_VALUE(n,k) (MSCALER0_BASE + 0x0140 + (n * 0x100) + (k * 0x0c)) ++ ++#define MSCA_ADDR_CHx_LINEx_POS(n,k) (MSCALER0_BASE + 0x0400 + (n * 0x100) + (k * 0x10)) ++#define MSCA_ADDR_CHx_LINEx_SIZE(n,k) (MSCALER0_BASE + 0x0404 + (n * 0x100) + (k * 0x10)) ++#define MSCA_ADDR_CHx_LINEx_PAR0(n,k) (MSCALER0_BASE + 0x0408 + (n * 0x100) + (k * 0x10)) ++#define MSCA_ADDR_CHx_LINEx_PAR1(n,k) (MSCALER0_BASE + 0x040c + (n * 0x100) + (k * 0x10)) ++ ++#define MSCA_ADDR_CHx_OSDx_POS(n,k) (MSCALER0_BASE + 0x0600 + (n * 0x100) + (k * 0x10)) ++#define MSCA_ADDR_CHx_OSDx_SIZE(n,k) (MSCALER0_BASE + 0x0604 + (n * 0x100) + (k * 0x10)) ++#define MSCA_ADDR_CHx_OSDx_ADDR(n,k) (MSCALER0_BASE + 0x0608 + (n * 0x100) + (k * 0x10)) ++#define MSCA_ADDR_CHx_OSDx_STRIDE(n,k) (MSCALER0_BASE + 0x060c + (n * 0x100) + (k * 0x10)) ++//============================================================ ++// RESP ADDRESS ++//============================================================ ++#define RESP_ADDR_INT_CNTRL (RESP_BASE + 0x0000) ++ ++#define CH0_FRM_DONE_INT (1 << 0) ++#define CH1_FRM_DONE_INT (1 << 1) ++#define CH2_FRM_DONE_INT (1 << 2) ++#define AWB_STATIC_INT (1 << 3) ++#define AE_STATIC_INT (1 << 4) ++#define AE_HIST_INT (1 << 5) ++#define AF_STATIC_INT (1 << 6) ++#define GSM_STATIC_INT (1 << 7) ++#define LCE_STATIC_INT (1 << 8) ++#define ADR_STATIC_INT (1 << 9) ++#define DEFOG_STATIC_INT (1 << 10) ++#define WDR_STATIC_INT (1 << 11) ++#define STOP_FINISH_INT (1 << 12) ++#define CH0_FRM_DONE_BF_INT (1 << 13) ++#define CH1_FRM_DONE_BF_INT (1 << 14) ++#define CH2_FRM_DONE_BF_INT (1 << 15) ++#define SDNS_STATIC_INT (1 << 16) ++#define RESP_ADDR_INT_COMMON_0_EN (RESP_BASE + 0x0020) ++#define RESP_ADDR_INT_COMMON_0_CLR (RESP_BASE + 0x0024) ++#define RESP_ADDR_INT_COMMON_0_INFO (RESP_BASE + 0x0028) ++#define RESP_ADDR_INT_COMMON_1_EN (RESP_BASE + 0x0030) ++#define RESP_ADDR_INT_COMMON_1_CLR (RESP_BASE + 0x0034) ++#define RESP_ADDR_INT_COMMON_1_INFO (RESP_BASE + 0x0038) ++ ++#define BROKEN_FRAME_INT (1 << 4) ++#define IP_OF_ERR_INT (1 << 5) ++#define RESP_ADDR_INT_UNUSUAL_0_EN (RESP_BASE + 0x0060) ++#define RESP_ADDR_INT_UNUSUAL_0_CLR (RESP_BASE + 0x0064) ++#define RESP_ADDR_INT_UNUSUAL_0_INFO (RESP_BASE + 0x0068) ++#define RESP_ADDR_INT_UNUSUAL_1_EN (RESP_BASE + 0x0070) ++#define RESP_ADDR_INT_UNUSUAL_1_CLR (RESP_BASE + 0x0074) ++#define RESP_ADDR_INT_UNUSUAL_1_INFO (RESP_BASE + 0x0078) ++#define RESP_ADDR_INT_BACKUP_0_EN (RESP_BASE + 0x00A0) ++#define RESP_ADDR_INT_BACKUP_0_CLR (RESP_BASE + 0x00A4) ++#define RESP_ADDR_INT_BACKUP_0_INFO (RESP_BASE + 0x00A8) ++#define RESP_ADDR_INT_BACKUP_1_EN (RESP_BASE + 0x00B0) ++#define RESP_ADDR_INT_BACKUP_1_CLR (RESP_BASE + 0x00B4) ++#define RESP_ADDR_INT_BACKUP_1_INFO (RESP_BASE + 0x00B8) ++#define RESP_ADDR_BP_INFO (RESP_BASE + 0x0100) ++#define RESP_ADDR_POSITIO_0_INFO (RESP_BASE + 0x0200) ++#define RESP_ADDR_POSITIO_1_INFO (RESP_BASE + 0x0204) ++#define RESP_ADDR_POSITIO_2_INFO (RESP_BASE + 0x0208) ++#define RESP_ADDR_POSITIO_3_INFO (RESP_BASE + 0x020C) ++#define RESP_ADDR_POSITIO_4_INFO (RESP_BASE + 0x0210) ++#define RESP_ADDR_POSITIO_5_INFO (RESP_BASE + 0x0214) ++#define RESP_ADDR_POSITIO_6_INFO (RESP_BASE + 0x0218) ++#define RESP_ADDR_POSITIO_7_INFO (RESP_BASE + 0x021C) ++#define RESP_ADDR_POSITIO_8_INFO (RESP_BASE + 0x0220) ++#define RESP_ADDR_POSITIO_9_INFO (RESP_BASE + 0x0224) ++#define RESP_ADDR_POSITIO_10_INFO (RESP_BASE + 0x0228) ++#define RESP_ADDR_POSITIO_11_INFO (RESP_BASE + 0x022C) ++#define RESP_ADDR_POSITIO_12_INFO (RESP_BASE + 0x0230) ++#define RESP_ADDR_POSITIO_13_INFO (RESP_BASE + 0x0234) ++#define RESP_ADDR_POSITIO_14_INFO (RESP_BASE + 0x0238) ++#define RESP_ADDR_POSITIO_15_INFO (RESP_BASE + 0x023C) ++#define RESP_ADDR_POSITIO_16_INFO (RESP_BASE + 0x0240) ++#define RESP_ADDR_POSITIO_17_INFO (RESP_BASE + 0x0244) ++#define RESP_ADDR_POSITIO_18_INFO (RESP_BASE + 0x0248) ++#define RESP_ADDR_POSITIO_19_INFO (RESP_BASE + 0x024C) ++#define RESP_ADDR_POSITIO_20_INFO (RESP_BASE + 0x0250) ++#define RESP_ADDR_POSITIO_21_INFO (RESP_BASE + 0x0254) ++#define RESP_ADDR_POSITIO_22_INFO (RESP_BASE + 0x0258) ++#define RESP_ADDR_POSITIO_23_INFO (RESP_BASE + 0x025C) ++#define RESP_ADDR_POSITIO_24_INFO (RESP_BASE + 0x0260) ++#define RESP_ADDR_POSITIO_25_INFO (RESP_BASE + 0x0264) ++#define RESP_ADDR_POSITIO_26_INFO (RESP_BASE + 0x0268) ++#define RESP_ADDR_POSITIO_27_INFO (RESP_BASE + 0x026C) ++#define RESP_ADDR_POSITIO_28_INFO (RESP_BASE + 0x0270) ++#define RESP_ADDR_POSITIO_29_INFO (RESP_BASE + 0x0274) ++#define RESP_ADDR_POSITIO_30_INFO (RESP_BASE + 0x0278) ++#define RESP_ADDR_POSITIO_31_INFO (RESP_BASE + 0x027C) ++#define RESP_ADDR_FRM_INTVAL_CNTRL (RESP_BASE + 0x0300) ++#define RESP_ADDR_FRM_INTVAL_ORG (RESP_BASE + 0x0304) ++#define RESP_ADDR_FRM_INTVAL_LCK (RESP_BASE + 0x0308) ++ ++//============================================================ ++// TSTP ADDRESS ++//============================================================ ++#define TSTP_ADDR_RAW_TOTAL(n) (TSTP_BASE(n) + 0x0000) ++#define TSTP_ADDR_RAW_SEL(n) (TSTP_BASE(n) + 0x0004) ++#define TSTP_ADDR_RAW_IRVAL0(n) (TSTP_BASE(n) + 0x0008) ++#define TSTP_ADDR_RAW_IRVAL1(n) (TSTP_BASE(n) + 0x000c) ++#define TSTP_ADDR_RGB_TOTAL(n) (TSTP_BASE(n) + 0x0010) ++#define TSTP_ADDR_RGB_SEL(n) (TSTP_BASE(n) + 0x0014) ++#define TSTP_ADDR_YUV_TOTAL(n) (TSTP_BASE(n) + 0x0020) ++#define TSTP_ADDR_YUV_SEL(n) (TSTP_BASE(n) + 0x0024) ++#define TSTP_ADDR_WDR_SEL(n) (TSTP_BASE(n) + 0x0028) ++#define TSTP_ADDR_DRAW_EN(n) (TSTP_BASE(n) + 0x0030) ++#define TSTP_ADDR_MARK0_PAR(n) (TSTP_BASE(n) + 0x0040) ++#define TSTP_ADDR_MARK1_PAR0(n) (TSTP_BASE(n) + 0x0050) ++#define TSTP_ADDR_MARK1_PAR1(n) (TSTP_BASE(n) + 0x0054) ++#define TSTP_ADDR_MARK1_PAR2(n) (TSTP_BASE(n) + 0x0058) ++#define TSTP_ADDR_MARK1_PAR3(n) (TSTP_BASE(n) + 0x005c) ++#define TSTP_ADDR_MARK1_PAR4(n) (TSTP_BASE(n) + 0x0060) ++#define TSTP_ADDR_MARK1_PAR5(n) (TSTP_BASE(n) + 0x0064) ++#define TSTP_ADDR_MARK1_PAR6(n) (TSTP_BASE(n) + 0x0068) ++#define TSTP_ADDR_MARK1_PAR7(n) (TSTP_BASE(n) + 0x006c) ++#define TSTP_ADDR_MARK1_PAR8(n) (TSTP_BASE(n) + 0x0070) ++#define TSTP_ADDR_MARK1_PAR9(n) (TSTP_BASE(n) + 0x0074) ++#define TSTP_ADDR_MARK1_PAR10(n) (TSTP_BASE(n) + 0x0078) ++#define TSTP_ADDR_MARK1_PAR11(n) (TSTP_BASE(n) + 0x007c) ++#define TSTP_ADDR_MARK1_PAR12(n) (TSTP_BASE(n) + 0x0080) ++#define TSTP_ADDR_MARK1_PAR13(n) (TSTP_BASE(n) + 0x0084) ++#define TSTP_ADDR_MARK1_PAR14(n) (TSTP_BASE(n) + 0x0088) ++#define TSTP_ADDR_MARK1_PAR15(n) (TSTP_BASE(n) + 0x008c) ++#define TSTP_ADDR_MARK1_PAR16(n) (TSTP_BASE(n) + 0x0090) ++#define TSTP_ADDR_MARK2_PAR0(n) (TSTP_BASE(n) + 0x00a0) ++#define TSTP_ADDR_MARK2_PAR1(n) (TSTP_BASE(n) + 0x00a4) ++#define TSTP_ADDR_MARK2_PAR2(n) (TSTP_BASE(n) + 0x00a8) ++ ++#define TIZIANO_ISP_IRQ_AWB_STATIC (3) ++#define TIZIANO_ISP_IRQ_AE_STATIC (4) ++#define TIZIANO_ISP_IRQ_AE_HIST (5) ++#define TIZIANO_ISP_IRQ_AF_STATIC (6) ++#define TIZIANO_ISP_IRQ_GSM_STATIC (7) ++#define TIZIANO_ISP_IRQ_LCE_STATIC (8) ++#define TIZIANO_ISP_IRQ_ADR_STATIC (9) ++#define TIZIANO_ISP_IRQ_DEFOG_STATIC (10) ++#define TIZIANO_ISP_IRQ_WDR_MAIN_STATIC (11) ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-sensor.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-sensor.h +new file mode 100644 +index 000000000..55c4fea1c +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-sensor.h +@@ -0,0 +1,97 @@ ++#ifndef __ISP_SENSOR_H__ ++#define __ISP_SENSOR_H__ ++ ++#define V4L2_CID_USER_ANALOG_GAIN_SHORT (V4L2_CID_USER_BASE + 0x1090) ++#define V4L2_CID_USER_EXPOSURE_SHORT (V4L2_CID_USER_BASE + 0x1091) ++ ++enum mipi_sensor_data_type_value { ++ YUV422_8BIT = 0x1e, ++ RAW8 = 0x2a, ++ RAW10 = 0x2b, ++ RAW12 = 0x2c, ++}; ++ ++enum tx_sensor_frm_mode { ++ TX_SENSOR_DEFAULT_FRAME_MODE = 0, ++ TX_SENSOR_WDR_2_FRAME_MODE, ++ TX_SENSOR_WDR_3_FRAME_MODE, ++ TX_SENSOR_WDR_4_FRAME_MODE, ++}; ++ ++enum tx_sensor_mode { ++ TX_SENSOR_DEFAULT_MODE = 0, ++ TX_SENSOR_NOT_VC_MODE, ++ TX_SENSOR_VC_MODE, ++}; ++ ++enum tx_sensor_csi_fmt { ++ TX_SENSOR_RAW8 = 0, ++ TX_SENSOR_RAW10, ++ TX_SENSOR_RAW12, ++}; ++ ++typedef enum { ++ SENSOR_MIPI_OTHER_MODE, ++ SENSOR_MIPI_SONY_MODE, ++}sensor_mipi_mode; ++ ++struct mipi_cfg { ++ unsigned int clk; ++ unsigned int twidth; ++ unsigned int theight; ++ sensor_mipi_mode mipi_mode; ++ unsigned int hcrop_diff_en; ++ unsigned int mipi_vcomp_en; ++ unsigned int mipi_hcomp_en; ++ unsigned short mipi_crop_start0x; ++ unsigned short mipi_crop_start0y; ++ unsigned short mipi_crop_start1x; ++ unsigned short mipi_crop_start1y; ++ unsigned short mipi_crop_start2x; ++ unsigned short mipi_crop_start2y; ++ unsigned short mipi_crop_start3x; ++ unsigned short mipi_crop_start3y; ++ unsigned int line_sync_mode; ++ unsigned int work_start_flag; ++ unsigned int data_type_en; ++ enum mipi_sensor_data_type_value data_type_value; ++ unsigned int del_start; ++ unsigned int sensor_fid_mode; ++ enum tx_sensor_frm_mode sensor_frame_mode; ++ enum tx_sensor_mode sensor_mode; ++ enum tx_sensor_csi_fmt sensor_csi_fmt; ++}; ++ ++struct dvp_cfg { ++ ++}; ++ ++typedef enum { ++ START_FIELD_ODD, ++ START_FIELD_EVEN, ++}start_field; ++ ++typedef enum { ++ EAV_BF_SAV, ++ SAV_BF_EAV, ++}bt_sav_eav; ++ ++struct bt_cfg { ++ unsigned int interlace_en; ++ start_field start_field; ++ bt_sav_eav bt_sav_eav; ++}; ++ ++struct sensor_info { ++ unsigned int fps; ++ unsigned int total_width; ++ unsigned int total_height; ++ int wdr_en; ++ union { ++ struct mipi_cfg mipi_cfg; ++ struct dvp_cfg dvp_cfg; ++ struct bt_cfg bt_cfg; ++ }; ++}; ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-video-mplane.c b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-video-mplane.c +new file mode 100644 +index 000000000..3c06e109b +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-video-mplane.c +@@ -0,0 +1,729 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++#define ISP_VIDEO_DRIVER_NAME "ispvideo" ++ ++ ++ ++static struct v4l2_subdev * ++isp_video_remote_subdev(struct isp_video_device *ispvideo, u32 *pad) ++{ ++ struct media_pad *remote; ++ ++ printk("------%s, %d\n", __func__, __LINE__); ++ ++ remote = media_entity_remote_pad(&ispvideo->pad); ++ ++ if (remote == NULL || ++ media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) ++ return NULL; ++ ++ if (pad) ++ *pad = remote->index; ++ ++ return media_entity_to_v4l2_subdev(remote->entity); ++} ++ ++ ++/* ----------------------------------------------------------------------------- ++ * V4L2 ioctls ++ */ ++ ++static int ++isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver)); ++ strlcpy(cap->card, ispvideo->video.name, sizeof(cap->card)); ++ strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); ++ ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; ++ ++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING; ++ ++ return 0; ++} ++ ++static int isp_video_enum_fmt_vid_cap_mplane(struct file *file, void *fh, ++ struct v4l2_fmtdesc *f) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ const struct isp_video_format *fmt = NULL; ++ ++ fmt = ispvideo->ops->find_format(NULL, NULL, f->index); ++ if(fmt == NULL) { ++ return -EINVAL; ++ } ++ strlcpy(f->description, fmt->name, sizeof(f->description)); ++ f->pixelformat = fmt->fourcc; ++ ++ return 0; ++} ++static int ++isp_video_g_fmt_vid_cap_mplane(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ printk("------%s, %d\n", __func__, __LINE__); ++ ++ //mutex_lock(&ispvideo->mutex); ++ if(ctx->format.type == 0) { ++ dev_warn(ispvideo->dev, "Format not setted before calling g_fmt\n"); ++ } else { ++ *format = ctx->format; ++ } ++ //mutex_unlock(&ispvideo->mutex); ++ ++ return 0; ++} ++ ++static int ++__isp_video_try_format(struct isp_video_device *ispvideo, struct v4l2_pix_format_mplane *pix_mp, ++ const struct isp_video_format **ofmt) ++{ ++ struct v4l2_plane_pix_format *plane_fmt; ++ struct isp_video_format *fmt = NULL; ++ ++ fmt = ispvideo->ops->find_format(&pix_mp->pixelformat, NULL, -1); ++ if(fmt == NULL) { ++ dev_err(ispvideo->dev, "Cannot find appropriate format for pix->pixelformat:[%x]\n", pix_mp->pixelformat); ++ return -EINVAL; ++ } ++ ++ pix_mp->colorspace = fmt->colorspace; ++ pix_mp->field = V4L2_FIELD_NONE; ++ pix_mp->pixelformat = fmt->fourcc; ++ pix_mp->num_planes = fmt->num_planes; ++ ++ plane_fmt = &pix_mp->plane_fmt[0]; ++ plane_fmt->bytesperline = pix_mp->width * fmt->depth[0] / 8; ++ plane_fmt->sizeimage = plane_fmt->bytesperline * pix_mp->height; ++ ++ plane_fmt = &pix_mp->plane_fmt[1]; ++ plane_fmt->bytesperline = pix_mp->width * fmt->depth[1] / 8; ++ plane_fmt->sizeimage = plane_fmt->bytesperline * pix_mp->height; ++ ++ if(ofmt) { ++ *ofmt = fmt; ++ } ++ ++ /*TODO, bound width and height!*/ ++ printk("=======%s,%d, pixelformat: %x, widht: %d, height: %d, num_planes: %d\n", __func__, __LINE__, pix_mp->pixelformat, pix_mp->width, pix_mp->height, pix_mp->num_planes); ++ ++ return 0; ++} ++ ++static void to_v4l2_mbus_framefmt(struct isp_video_device *ispvideo, struct v4l2_format *format, struct v4l2_mbus_framefmt *fmt) ++{ ++ struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp; ++ struct isp_video_format *ispfmt = NULL; ++ ++ ispfmt = ispvideo->ops->find_format(&pix_mp->pixelformat, NULL, -1); ++ ++ fmt->width = pix_mp->width; ++ fmt->height = pix_mp->height; ++ fmt->code = ispfmt->mbus_code; ++ fmt->field = pix_mp->field; ++ fmt->colorspace = pix_mp->colorspace; ++ fmt->ycbcr_enc = pix_mp->ycbcr_enc; ++ fmt->quantization = pix_mp->quantization; ++ fmt->xfer_func = pix_mp->xfer_func; ++} ++ ++static int ++isp_video_s_fmt_vid_cap_mplane(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct v4l2_subdev *sd = NULL; ++ struct v4l2_subdev_format subdev_fmt; ++ unsigned int pad = 0; ++ int ret = 0; ++ ++ if(vb2_is_busy(&ctx->queue)) { ++ return -EBUSY; ++ } ++ ++ ret = __isp_video_try_format(ispvideo, &format->fmt.pix_mp, NULL); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to set format cap!\n"); ++ return -EINVAL; ++ } ++ ++ sd = isp_video_remote_subdev(ispvideo, &pad); ++ if(sd == NULL) { ++ return -EINVAL; ++ } ++ ++ ctx->format = *format; ++ ++ to_v4l2_mbus_framefmt(ispvideo, format, &subdev_fmt.format); ++ ++ subdev_fmt.pad = pad; ++ subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &subdev_fmt); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to set subdev format\n"); ++ return -EINVAL; ++ } ++ ++ //printk("-%s, %d--ctx: %x--queue: %x, queue->lock: %x\n", __func__, __LINE__, ctx, &ctx->queue, ctx->queue.lock); ++ return 0; ++} ++ ++static int ++isp_video_try_format_cap_mplane(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ int ret = 0; ++ ++ printk("-----------%s, %d------------\n", __func__, __LINE__); ++ ++ ret = __isp_video_try_format(ispvideo, &format->fmt.pix_mp, NULL); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Try format cap mplane error!\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int ++isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) ++{ ++ printk("-----------%s, %d------------\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ++isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) ++{ ++ printk("-----------%s, %d------------\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ++isp_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop) ++{ ++ printk("-----------%s, %d------------\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int isp_video_enum_input(struct file *file, void *priv, ++ struct v4l2_input *inp) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ if (inp->index != 0) ++ return -EINVAL; ++ ++ /* default is camera */ ++ inp->type = V4L2_INPUT_TYPE_CAMERA; ++ inp->std = ispvideo->video.tvnorms; ++ strcpy(inp->name, "Camera"); ++ ++ return 0; ++} ++ ++static int isp_video_g_input(struct file *file, void *priv, unsigned int *i) ++{ ++ *i = 0; ++ ++ return 0; ++} ++ ++static int isp_video_s_input(struct file *file, void *priv, unsigned int i) ++{ ++ if (i > 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { ++ .vidioc_querycap = isp_video_querycap, ++ .vidioc_enum_fmt_vid_cap_mplane = isp_video_enum_fmt_vid_cap_mplane, ++ .vidioc_g_fmt_vid_cap_mplane = isp_video_g_fmt_vid_cap_mplane, ++ .vidioc_s_fmt_vid_cap_mplane = isp_video_s_fmt_vid_cap_mplane, ++ .vidioc_try_fmt_vid_cap_mplane = isp_video_try_format_cap_mplane, ++ .vidioc_cropcap = isp_video_cropcap, ++ .vidioc_g_crop = isp_video_get_crop, ++ .vidioc_s_crop = isp_video_set_crop, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ .vidioc_enum_input = isp_video_enum_input, ++ .vidioc_g_input = isp_video_g_input, ++ .vidioc_s_input = isp_video_s_input, ++}; ++ ++/* ----------------------------------------------------------------------------- ++ * Video queue operations ++ */ ++ ++static int isp_video_queue_setup(struct vb2_queue *queue, ++ const void *parg, ++ unsigned int *count, unsigned int *num_planes, ++ unsigned int sizes[], void *alloc_ctxs[]) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(queue); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct v4l2_format *format = &ctx->format; ++ int i = 0; ++ ++ if(*num_planes) { ++ for(i = 0; i < *num_planes; i++) { ++ if(sizes[i] < format->fmt.pix_mp.plane_fmt[i].sizeimage) { ++ return -EINVAL; ++ } ++ } ++ } else { ++ *num_planes = format->fmt.pix_mp.num_planes; ++ for(i = 0; i < *num_planes; i++) { ++ sizes[i] = format->fmt.pix_mp.plane_fmt[i].sizeimage; ++ alloc_ctxs[i] = ispvideo->alloc_ctx; ++ } ++ } ++ ++ /*MAX_BUFFER_NUMS:*/ ++ if(*count >= 3) { ++ *count = 3; ++ } ++ ++ return 0; ++} ++ ++static int isp_video_buffer_prepare(struct vb2_buffer *buf) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(buf->vb2_queue); ++ struct v4l2_format *format = &ctx->format; ++ struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp; ++ int i; ++ ++ for(i = 0; i < buf->num_planes; i++) { ++ vb2_set_plane_payload(buf, i, pix_mp->plane_fmt[i].sizeimage); ++ } ++ ++ return 0; ++} ++ ++static void isp_video_buffer_queue(struct vb2_buffer *buf) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buf); ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(buf->vb2_queue); ++ struct isp_video_buffer *isp_buffer = to_isp_buffer(vbuf); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ int ret = 0; ++ ++ ret = ispvideo->ops->qbuf(ispvideo, isp_buffer); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "failed to queue buf!\n"); ++ } ++} ++ ++static int isp_video_subdev_init(struct isp_video_device *ispvideo) ++{ ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ int ret = 0; ++ ++ /*subdevs reset.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || ++ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, core, init, 1); ++ if(ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_err(ispvideo->dev, "failed to reset subdev[%s]\n", entity->name); ++ } else { ++ ret = 0; ++ } ++ } ++ ++ return ret; ++} ++ ++static int isp_video_subdev_reset(struct isp_video_device *ispvideo) ++{ ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ int ret = 0; ++ ++ /*subdevs reset.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || ++ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, core, reset, 1); ++ if(ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_err(ispvideo->dev, "failed to reset subdev[%s]\n", entity->name); ++ } else { ++ ret = 0; ++ } ++ } ++ ++ return ret; ++ ++} ++ ++static int isp_video_subdev_stream(struct isp_video_device *ispvideo, int enable) ++{ ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ int ret = 0; ++ ++ /*subdevs stream on.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || ++ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, video, s_stream, enable); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "unable to start stream[%s]\n", entity->name); ++ } ++ ++ } ++ ++ return ret; ++} ++ ++static int isp_video_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct isp_pipeline *pipe = &ispvideo->pipe; ++ int ret = 0; ++ printk("-----********* -%s, %d\n", __func__, __LINE__); ++ ++ mutex_lock(&ispvideo->stream_lock); ++ ret = media_entity_pipeline_start(entity, &pipe->pipeline); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to start pipeline\n"); ++ goto err_pipeline_start; ++ } ++ ++ ret = isp_video_subdev_reset(ispvideo); ++ ++ ++ ret = isp_video_subdev_init(ispvideo); ++ ++ ++ ret = isp_video_subdev_stream(ispvideo, 1); ++ ++ if(ret < 0) { ++ goto err_start_stream; ++ } ++ ++ mutex_unlock(&ispvideo->stream_lock); ++ ++ return 0; ++ ++err_start_stream: ++ media_entity_pipeline_stop(entity); ++err_pipeline_start: ++ mutex_unlock(&ispvideo->stream_lock); ++ return ret; ++} ++static void isp_video_stop_streaming(struct vb2_queue *q) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct media_entity *entity = &ispvideo->video.entity; ++ //struct isp_pipeline *pipe = &ispvideo->pipe; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ unsigned int is_streaming = 0; ++ int ret = 0; ++ ++ mutex_lock(&ispvideo->stream_lock); ++ ++ is_streaming = vb2_is_streaming(q); ++ ++ if(!is_streaming) ++ goto done; ++ ++ /*subdevs stream off.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || ++ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, video, s_stream, 0); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "unable to start stream[%s]\n", entity->name); ++ break; ++ } ++ ++ } ++ media_entity_pipeline_stop(&ispvideo->video.entity); ++ ++done: ++ mutex_unlock(&ispvideo->stream_lock); ++} ++ ++static const struct vb2_ops isp_video_queue_ops = { ++ .queue_setup = isp_video_queue_setup, ++ .buf_prepare = isp_video_buffer_prepare, ++ .buf_queue = isp_video_buffer_queue, ++ .start_streaming = isp_video_start_streaming, ++ .stop_streaming = isp_video_stop_streaming, ++}; ++ ++ ++static int isp_video_open(struct file *file) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct video_device *vdev = &ispvideo->video; ++ struct isp_video_ctx *ctx = NULL; ++ struct vb2_queue *queue = NULL; ++ int ret = 0; ++ printk("-----name: %s %s, %d \n", ispvideo->name, __func__, __LINE__); ++ mutex_lock(&ispvideo->mutex); ++ if(ispvideo->queue != NULL) { ++ mutex_unlock(&ispvideo->mutex); ++ return -EBUSY; ++ } ++ ++ ctx = kzalloc(sizeof(struct isp_video_ctx), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(ctx)) { ++ dev_err(ispvideo->ispcam->dev, "Failed to alloc ctx for isp_video_ctx\n"); ++ ret = -ENOMEM; ++ goto err_ctx_alloc; ++ } ++ ++ v4l2_fh_init(&ctx->fh, &ispvideo->video); ++ v4l2_fh_add(&ctx->fh); ++ ++ queue = &ctx->queue; ++ queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ queue->io_modes = VB2_MMAP; ++ queue->drv_priv = ctx; ++ queue->ops = &isp_video_queue_ops; ++ queue->mem_ops = &vb2_dma_contig_memops; ++ queue->buf_struct_size = sizeof(struct isp_video_buffer); ++ queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ queue->lock = &ispvideo->queue_lock; ++ ++ ret = vb2_queue_init(&ctx->queue); ++ if(ret < 0) { ++ goto err_vb2_queue_init; ++ } ++ ++ ctx->ispvideo = ispvideo; ++ vdev->queue = ispvideo->queue = queue; ++ ++ file->private_data = &ctx->fh; ++ ++ mutex_unlock(&ispvideo->mutex); ++ ++ return 0; ++err_vb2_queue_init: ++ v4l2_fh_del(&ctx->fh); ++ kfree(ctx); ++err_ctx_alloc: ++ mutex_unlock(&ispvideo->mutex); ++ return ret; ++} ++static int isp_video_release(struct file *file) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct video_device *vdev = &ispvideo->video; ++ struct v4l2_fh *fh = file->private_data; ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ ++ printk("-----name: %s %s, %d \n", ispvideo->name, __func__, __LINE__); ++ /*lock*/ ++ ++ mutex_lock(&ispvideo->mutex); ++ ++ vb2_queue_release(&ctx->queue); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ ++ kfree(ctx); ++ file->private_data = NULL; ++ vdev->queue = ispvideo->queue = NULL; ++ ++ mutex_unlock(&ispvideo->mutex); ++ ++ /*unlock*/ ++ ++ return 0; ++} ++ ++#if 0 ++static unsigned int isp_video_poll(struct file *file, poll_table *wait) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct v4l2_fh *fh = file->private_data; ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ int ret = 0; ++ printk("-----name: %s %s, %d \n", ispvideo->name, __func__, __LINE__); ++ ++ mutex_lock(&ispvideo->queue_lock); ++ ret = vb2_poll(&ctx->queue, file, wait); ++ mutex_unlock(&ispvideo->queue_lock); ++ ++ return ret; ++} ++ ++static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct v4l2_fh *fh = file->private_data; ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ printk("-----name: %s %s, %d \n", ispvideo->name, __func__, __LINE__); ++ ++ return vb2_mmap(&ctx->queue, vma); ++} ++#endif ++ ++static struct v4l2_file_operations isp_video_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = video_ioctl2, ++ .open = isp_video_open, ++ .release = isp_video_release, ++ .poll = vb2_fop_poll, /*isp_video_poll,*/ ++ .mmap = vb2_fop_mmap, /*isp_video_mmap,*/ ++}; ++ ++ ++int isp_video_init(struct isp_video_device *ispvideo, char *name, const struct isp_video_ops *video_ops) ++{ ++ int ret = 0; ++ struct video_device *video = &ispvideo->video; ++ ++ ++ /*创建buffer分é…器*/ ++ ispvideo->alloc_ctx = ingenic_vb2_dma_contig_init_ctx(ispvideo->ispcam->dev); ++ if(IS_ERR(ispvideo)) { ++ return -ENOMEM; ++ } ++ ++ /*åˆå§‹åŒ–一个sink pad*/ ++ ispvideo->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; ++ ret = media_entity_pads_init(&video->entity, 1, &ispvideo->pad); ++ if(ret < 0) { ++ /*TODO: error case*/ ++ } ++ ++ mutex_init(&ispvideo->queue_lock); ++ mutex_init(&ispvideo->mutex); ++ mutex_init(&ispvideo->stream_lock); ++ ++ snprintf(video->name, sizeof(video->name), "isp-%s", name); ++ video->fops = &isp_video_fops; ++ video->ioctl_ops = &isp_video_ioctl_ops; ++ video->release = video_device_release_empty; ++ ++ ispvideo->name = video->name; ++ ispvideo->ops = video_ops; ++ ispvideo->dev = ispvideo->ispcam->dev; ++ ++ video_set_drvdata(&ispvideo->video, ispvideo); ++ ++ return 0; ++ ++} ++ ++int isp_video_cleanup(struct isp_video_device *ispvideo) ++{ ++ ++ return 0; ++} ++ ++int isp_video_register(struct isp_video_device *ispvideo, struct v4l2_device *v4l2_dev) ++{ ++ struct video_device *video = &ispvideo->video; ++ int ret = 0; ++ ++ video->v4l2_dev = v4l2_dev; ++ ++ ret = video_register_device(video, VFL_TYPE_GRABBER, -1); ++ if(ret < 0) { ++ /*TODO: error case*/ ++ } ++ ++ dev_info(ispvideo->dev, "register video device %s @ /dev/video%d ok\n", video->name, video->index); ++ ++ return ret; ++} ++int isp_video_unregister(struct isp_video_device *ispvideo) ++{ ++ ++ return 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-video.c b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-video.c +new file mode 100644 +index 000000000..04abbf3bc +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp-video.c +@@ -0,0 +1,992 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++#define ISP_VIDEO_DRIVER_NAME "ispvideo" ++ ++int isp_max_buffer_num = 3; ++module_param(isp_max_buffer_num, int, 0644); ++MODULE_PARM_DESC(isp_max_buffer_num, "isp max buffer numer"); ++ ++int isp_force_img_depth = 0; ++module_param(isp_force_img_depth, int, 0644); ++MODULE_PARM_DESC(isp_force_img_depth, "force fmt depth, usefull when need mem more than real fmt."); ++ ++struct sensor_id_t { ++ unsigned int sensor_id; ++ bool available; ++}; ++ ++struct sensor_id_t sensor_id_pool[2] = { ++ {.sensor_id = 0, ++ .available = true}, ++ {.sensor_id = 1, ++ .available = true}, ++}; ++ ++static int get_sensor_id(void) ++{ ++ int i; ++ for(i=0; i < 2; i++) { ++ if(sensor_id_pool[i].available){ ++ sensor_id_pool[i].available = false; ++ return sensor_id_pool[i].sensor_id; ++ } ++ } ++ return -1; ++} ++ ++static void put_sensor_id(unsigned int sensor_id) ++{ ++ sensor_id_pool[sensor_id].available = true; ++} ++ ++struct mutex sensor_id_lock; ++ ++static struct v4l2_subdev * ++isp_video_remote_subdev(struct isp_video_device *ispvideo, u32 *pad) ++{ ++ struct media_pad *remote; ++ ++ remote = media_entity_remote_pad(&ispvideo->pad); ++ ++ if (remote == NULL || !is_media_entity_v4l2_subdev(remote->entity)) ++ return NULL; ++ ++ if (pad) ++ *pad = remote->index; ++ ++ return media_entity_to_v4l2_subdev(remote->entity); ++} ++ ++ ++/* ----------------------------------------------------------------------------- ++ * V4L2 ioctls ++ */ ++ ++static int ++isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver)); ++ strlcpy(cap->card, ispvideo->video.name, sizeof(cap->card)); ++ strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); ++ ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; ++ ++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ ++ return 0; ++} ++ ++static int isp_video_enum_fmt_vid_cap(struct file *file, void *fh, ++ struct v4l2_fmtdesc *f) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ const struct isp_video_format *fmt = NULL; ++ ++ fmt = ispvideo->ops->find_format(NULL, NULL, f->index); ++ if(fmt == NULL) { ++ return -EINVAL; ++ } ++ strlcpy(f->description, fmt->name, sizeof(f->description)); ++ f->pixelformat = fmt->fourcc; ++ ++ return 0; ++} ++static int ++isp_video_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct isp_video_ctx *ctx = ispvideo->ctx; ++ ++ //mutex_lock(&ispvideo->mutex); ++ if(ctx->format.type == 0) { ++ dev_warn(ispvideo->dev, "Format not setted before calling g_fmt\n"); ++ } else { ++ *format = ctx->format; ++ } ++ //mutex_unlock(&ispvideo->mutex); ++ ++ return 0; ++} ++ ++static int ++__isp_video_try_format(struct isp_video_ctx *ctx, struct v4l2_pix_format *pix, ++ const struct isp_video_format **ofmt) ++{ ++ struct isp_video_format *fmt = NULL; ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ unsigned int depth = 0; ++ unsigned int use_depth = 0; ++ int i; ++ ++ fmt = ispvideo->ops->find_format(&pix->pixelformat, NULL, -1); ++ if(fmt == NULL) { ++ dev_err(ispvideo->dev, "Cannot find appropriate format for pix->pixelformat:[%x]\n", pix->pixelformat); ++ return -EINVAL; ++ } ++ ispvideo->current_format = fmt; ++ ++ for(i = 0; i < fmt->num_planes; i++) { ++ depth += fmt->depth[i]; ++ } ++ ++ pix->colorspace = fmt->colorspace; ++ pix->field = V4L2_FIELD_NONE; ++ pix->pixelformat = fmt->fourcc; ++ pix->bytesperline = pix->width * depth / 8; ++ //pix->sizeimage = pix->bytesperline * pix->height; ++ ++ use_depth = isp_force_img_depth > depth ? isp_force_img_depth : depth; ++ pix->sizeimage = pix->width * use_depth / 8 * pix->height; ++ ++ ctx->uv_offset = pix->width * fmt->depth[0] * pix->height / 8; ++ ctx->payload_size = pix->bytesperline * pix->height; ++ ++ if(ofmt) { ++ *ofmt = fmt; ++ } ++ ++ /*TODO, bound width and height!*/ ++ //printk("=======%s,%d, pixelformat: %x, widht: %d, height: %d, num_planes: %d, uv_offset: %d\n", __func__, __LINE__, pix->pixelformat, pix->width, pix->height, fmt->num_planes, ctx->uv_offset); ++ ++ return 0; ++} ++ ++static void to_v4l2_mbus_framefmt(struct isp_video_device *ispvideo, struct v4l2_format *format, struct v4l2_mbus_framefmt *fmt) ++{ ++ struct v4l2_pix_format *pix = &format->fmt.pix; ++ struct isp_video_format *ispfmt = NULL; ++ ++ ispfmt = ispvideo->ops->find_format(&pix->pixelformat, NULL, -1); ++ ++ fmt->width = pix->width; ++ fmt->height = pix->height; ++ fmt->code = ispfmt->mbus_code; ++ fmt->field = pix->field; ++ fmt->colorspace = pix->colorspace; ++ fmt->ycbcr_enc = pix->ycbcr_enc; ++ fmt->quantization = pix->quantization; ++ fmt->xfer_func = pix->xfer_func; ++} ++ ++static int ++isp_video_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct isp_video_ctx *ctx = ispvideo->ctx; ++ struct v4l2_subdev *sd = NULL; ++ struct v4l2_subdev_format subdev_fmt; ++ unsigned int pad = 0; ++ int ret = 0; ++ ++ ++ if(vb2_is_busy(&ctx->queue)) { ++ return -EBUSY; ++ } ++ ++ ret = __isp_video_try_format(ctx, &format->fmt.pix, NULL); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to set format cap!\n"); ++ return -EINVAL; ++ } ++ ++ sd = isp_video_remote_subdev(ispvideo, &pad); ++ if(sd == NULL) { ++ return -EINVAL; ++ } ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ++ ctx->format = *format; ++ ++ to_v4l2_mbus_framefmt(ispvideo, format, &subdev_fmt.format); ++ ++ subdev_fmt.pad = pad; ++ subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &subdev_fmt); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to set subdev format\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++isp_video_try_format_cap(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct isp_video_ctx *ctx = ispvideo->ctx; ++ int ret = 0; ++ ++ ret = __isp_video_try_format(ctx, &format->fmt.pix, NULL); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Try format cap error!\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int isp_video_pixelaspect(struct file *file, void *fh, int buf_type, struct v4l2_fract *aspect) ++{ ++ printk("-----------%s, %d------------\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ++isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct mscaler_device *mscaler= ispcam->mscaler; ++ int ret = 0; ++ ++ ret = v4l2_subdev_call(&mscaler->sd, video, cropcap, cropcap); ++ ++ return ret; ++} ++ ++static int ++isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct mscaler_device *mscaler= ispcam->mscaler; ++ int ret = 0; ++ ++ ret = v4l2_subdev_call(&mscaler->sd, video, g_crop, crop); ++ ++ return ret; ++} ++ ++static int ++isp_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct mscaler_device *mscaler= ispcam->mscaler; ++ int ret = 0; ++ ++ ret = v4l2_subdev_call(&mscaler->sd, video, s_crop, crop); ++ ++ return ret; ++} ++ ++static int isp_video_get_selection(struct file *file, void *fh, struct v4l2_selection *s) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct v4l2_subdev *sd = NULL; ++ struct v4l2_subdev_selection sel = {0}; ++ int ret = 0; ++ int pad = 0; ++ ++ sd = isp_video_remote_subdev(ispvideo, &pad); ++ sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ sel.pad = pad; ++ sel.target = s->target; ++ ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sel); ++ memcpy(&s->r, &sel.r, sizeof(struct v4l2_rect)); ++ ++ return ret; ++} ++ ++static int isp_video_set_selection(struct file *file, void *fh, struct v4l2_selection *s) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct isp_video_ctx *ctx = ispvideo->ctx; ++ struct v4l2_format *format = &ctx->format; ++ struct v4l2_subdev *sd = NULL; ++ struct v4l2_subdev_selection sel; ++ int ret = 0; ++ int pad = 0; ++ ++ sd = isp_video_remote_subdev(ispvideo, &pad); ++ sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ sel.pad = pad; ++ sel.flags = s->flags; ++ sel.target = s->target; ++ memcpy(&sel.r, &s->r, sizeof(struct v4l2_rect)); ++ ret = v4l2_subdev_call(sd, pad, set_selection, NULL, &sel); ++ ++ format->fmt.pix.width = sel.r.width; ++ format->fmt.pix.height = sel.r.height; ++ ret = __isp_video_try_format(ctx, &format->fmt.pix, NULL); ++ ++ return ret; ++} ++ ++static int isp_video_enum_input(struct file *file, void *priv, ++ struct v4l2_input *inp) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ if (inp->index != 0) ++ return -EINVAL; ++ ++ /* default is camera */ ++ inp->type = V4L2_INPUT_TYPE_CAMERA; ++ inp->std = ispvideo->video.tvnorms; ++ strcpy(inp->name, "Camera"); ++ ++ return 0; ++} ++ ++static int isp_video_g_input(struct file *file, void *priv, unsigned int *i) ++{ ++ *i = 0; ++ ++ return 0; ++} ++ ++static int isp_video_s_input(struct file *file, void *priv, unsigned int i) ++{ ++ if (i > 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++int isp_video_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct mscaler_device *mscaler= ispcam->mscaler; ++ struct v4l2_subdev_frame_size_enum fse; ++ int ret = 0; ++ ++ fse.code = fsize->pixel_format; ++ fse.index = fsize->index; ++ ++ ret = v4l2_subdev_call(&mscaler->sd, pad, enum_frame_size, NULL, &fse); ++ if (ret < 0) ++ return ret; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; ++ fsize->discrete.width = fse.min_width; ++ fsize->discrete.height = fse.min_height; ++ return 0; ++} ++ ++int isp_video_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a){ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct isp_async_device *isd = &ispcam->isd[0]; ++ int ret = 0; ++ struct v4l2_subdev_frame_interval interval; ++ ++ interval.pad = 0; ++ ret = v4l2_subdev_call(isd->sd, video, g_frame_interval, &interval); ++ if(ret < 0) { ++ return ret; ++ } ++ a->parm.capture.timeperframe.numerator = interval.interval.numerator; ++ a->parm.capture.timeperframe.denominator = interval.interval.denominator; ++ return 0; ++} ++ ++extern int isp_video_s_ctrl(struct file *file, void *fh, struct v4l2_control *a); ++extern int isp_video_g_ctrl(struct file *file, void *fh, struct v4l2_control *a); ++ ++extern int bypass_video_s_ctrl(struct file *file, void *fh, struct v4l2_control *a); ++extern int bypass_video_g_ctrl(struct file *file, void *fh, struct v4l2_control *a); ++ ++static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { ++ .vidioc_querycap = isp_video_querycap, ++ .vidioc_enum_fmt_vid_cap = isp_video_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = isp_video_g_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = isp_video_s_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = isp_video_try_format_cap, ++ .vidioc_cropcap = isp_video_cropcap, ++ .vidioc_g_crop = isp_video_get_crop, ++ .vidioc_s_crop = isp_video_set_crop, ++ .vidioc_g_selection = isp_video_get_selection, ++ .vidioc_s_selection = isp_video_set_selection, ++ .vidioc_g_pixelaspect = isp_video_pixelaspect, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ .vidioc_enum_input = isp_video_enum_input, ++ .vidioc_g_input = isp_video_g_input, ++ .vidioc_s_input = isp_video_s_input, ++ .vidioc_enum_framesizes = isp_video_enum_framesizes, ++ .vidioc_g_parm = isp_video_g_parm, ++ .vidioc_s_ctrl = isp_video_s_ctrl, ++ .vidioc_g_ctrl = isp_video_g_ctrl, ++}; ++ ++static const struct v4l2_ioctl_ops bypass_video_ioctl_ops = { ++ .vidioc_querycap = isp_video_querycap, /**/ ++ .vidioc_enum_fmt_vid_cap = isp_video_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = isp_video_g_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = isp_video_s_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = isp_video_try_format_cap, ++ .vidioc_g_pixelaspect = isp_video_pixelaspect, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ .vidioc_enum_input = isp_video_enum_input, /**/ ++ .vidioc_g_input = isp_video_g_input, ++ .vidioc_s_input = isp_video_s_input, ++ .vidioc_enum_framesizes = isp_video_enum_framesizes, ++ .vidioc_g_parm = isp_video_g_parm, /**/ ++// .vidioc_s_ctrl = bypass_video_s_ctrl, ++// .vidioc_g_ctrl = bypass_video_g_ctrl, ++}; ++ ++/* ----------------------------------------------------------------------------- ++ * Video queue operations ++ */ ++ ++static int isp_video_queue_setup(struct vb2_queue *queue, ++ unsigned int *count, unsigned int *num_planes, ++ unsigned int sizes[], struct device *alloc_ctxs[]) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(queue); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct v4l2_format *format = &ctx->format; ++ ++ *num_planes = 1; ++ ++ sizes[0] = format->fmt.pix.sizeimage; ++ if(sizes[0] == 0) { ++ dev_err(ispvideo->dev, "queue setup 0 sizeimage\n"); ++ return -EINVAL; ++ } ++ ++ alloc_ctxs[0] = ispvideo->ispcam->dev; ++ ++ /*MAX_BUFFER_NUMS:*/ ++ if(ispvideo->bypass) ++ isp_max_buffer_num = 5; ++ if(*count >= isp_max_buffer_num) { ++ *count = isp_max_buffer_num; ++ } ++ ++ ispvideo->max_buffer_num = *count; ++ ++ return 0; ++} ++ ++static int isp_video_buffer_prepare(struct vb2_buffer *buf) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(buf->vb2_queue); ++ ++ //vb2_set_plane_payload(buf, 0, format->fmt.pix.sizeimage); ++ vb2_set_plane_payload(buf, 0, ctx->payload_size); ++ return 0; ++} ++ ++static void isp_video_buffer_queue(struct vb2_buffer *buf) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buf); ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(buf->vb2_queue); ++ struct isp_video_buffer *isp_buffer = to_isp_buffer(vbuf); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ int ret = 0; ++ ++ isp_buffer->uv_offset = ctx->uv_offset; ++ ++ ret = ispvideo->ops->qbuf(ispvideo, isp_buffer); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "failed to queue buf!\n"); ++ } ++} ++ ++static int isp_video_subdev_init(struct isp_video_device *ispvideo) ++{ ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ int ret = 0; ++ ++ /*subdevs reset.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || !is_media_entity_v4l2_subdev(pad->entity)) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, core, init, ispcam->sensor_id); ++ if(ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_err(ispvideo->dev, "failed to init subdev[%s]\n", entity->name); ++ break; ++ } else { ++ ret = 0; ++ } ++ } ++ ++ return ret; ++} ++ ++static int isp_video_subdev_reset(struct isp_video_device *ispvideo) ++{ ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ int ret = 0; ++ ++ /*subdevs reset.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || !is_media_entity_v4l2_subdev(pad->entity)) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, core, reset, 1); ++ if(ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_err(ispvideo->dev, "failed to reset subdev[%s]\n", entity->name); ++ } else { ++ ret = 0; ++ } ++ } ++ ++ return ret; ++ ++} ++ ++ ++static int isp_video_subdev_streamon(struct isp_video_device *ispvideo) ++{ ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct mscaler_device *mscaler= ispcam->mscaler; ++ struct isp_device *isp = ispcam->isp; ++ struct vic_device *vic = ispcam->vic; ++ struct csi_device *csi = ispcam->csi; ++ struct isp_async_device *isd = &ispcam->isd[0]; ++ int ret = 0; ++ ++ if(!ispvideo->bypass) { ++ v4l2_set_subdev_hostdata(&mscaler->sd, ispvideo); ++ ret = v4l2_subdev_call(&mscaler->sd, video, s_stream, 1); ++ if(ret < 0) { ++ goto mscaler_streamon_err; ++ } ++ ++ ret = v4l2_subdev_call(&isp->sd, video, s_stream, 1); ++ if(ret < 0) { ++ goto isp_streamon_err; ++ } ++ } ++ ++ if(csi && (isd->bus_type == V4L2_MBUS_CSI2_DPHY)) { ++ ret = v4l2_subdev_call(&csi->sd, video, s_stream, 1); ++ if(ret < 0) { ++ goto csi_streamon_err; ++ } ++ } ++ ++ if(!isd->enabled) { ++ ret = v4l2_subdev_call(isd->sd, video, s_stream, 1); ++ if(ret < 0) { ++ goto isd_streamon_err; ++ } ++ } ++ isd->enabled++; ++ ++ ret = v4l2_subdev_call(&vic->sd, video, s_stream, 1); ++ if(ret < 0) { ++ goto vic_streamon_err; ++ } ++ ++ return ret; ++vic_streamon_err: ++ isd->enabled--; ++ if(!isd->enabled) { ++ ret = v4l2_subdev_call(isd->sd, video, s_stream, 0); ++ } ++isd_streamon_err: ++ if(csi && (isd->bus_type == V4L2_MBUS_CSI2_DPHY)) ++ v4l2_subdev_call(&csi->sd, video, s_stream, 0); ++csi_streamon_err: ++ if(!ispvideo->bypass) ++ v4l2_subdev_call(&isp->sd, video, s_stream, 0); ++isp_streamon_err: ++ if(!ispvideo->bypass) ++ v4l2_subdev_call(&mscaler->sd, video, s_stream, 0); ++mscaler_streamon_err: ++ dev_err(ispvideo->dev, "start stream error\n"); ++ return ret; ++} ++ ++static int isp_video_subdev_streamoff(struct isp_video_device *ispvideo) ++{ ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct mscaler_device *mscaler= ispcam->mscaler; ++ struct isp_device *isp = ispcam->isp; ++ struct vic_device *vic = ispcam->vic; ++ struct csi_device *csi = ispcam->csi; ++ struct isp_async_device *isd = &ispcam->isd[0]; ++ int ret = 0; ++ ++ //global ispcam device mutex. ++ if(!ispvideo->bypass) { ++ v4l2_set_subdev_hostdata(&mscaler->sd, ispvideo); ++ ret = v4l2_subdev_call(&mscaler->sd, video, s_stream, 0); ++ if(ret < 0) { ++ goto err; ++ } ++ ++ ret = v4l2_subdev_call(&isp->sd, video, s_stream, 0); ++ if(ret < 0) { ++ goto err; ++ } ++ } ++ ++ if(csi && (isd->bus_type == V4L2_MBUS_CSI2_DPHY)) { ++ ret = v4l2_subdev_call(&csi->sd, video, s_stream, 0); ++ if(ret < 0) { ++ goto err; ++ } ++ } ++ ++ isd->enabled--; ++ if(!isd->enabled) { ++ ret = v4l2_subdev_call(isd->sd, video, s_stream, 0); ++ if(ret < 0) { ++ goto err; ++ } ++ } ++ ++ ret = v4l2_subdev_call(&vic->sd, video, s_stream, 0); ++ if(ret < 0) { ++ goto err; ++ } ++ ++ return ret; ++err: ++ dev_err(ispvideo->dev, "start stream error\n"); ++ return ret; ++ ++} ++ ++static int isp_video_subdev_stream(struct isp_video_device *ispvideo, int enable) ++{ ++ int ret = 0; ++ ++ //mutex lock. ++ ++ if(enable) { ++ ret = isp_video_subdev_streamon(ispvideo); ++ } else { ++ ret = isp_video_subdev_streamoff(ispvideo); ++ } ++ ++ return ret; ++} ++ ++static int isp_video_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct isp_pipeline *pipe = &ispvideo->pipe; ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ int ret = 0; ++ ++ mutex_lock(&ispcam->mutex); ++ ++ mutex_lock(&ispvideo->stream_lock); ++ ++ if(ispcam->enabled++ == 0) { ++ mutex_lock(&sensor_id_lock); ++ ispcam->sensor_id = get_sensor_id(); ++ //printk("~~~~~~~~~~~~~~sensor_id = %d\n", ispcam->sensor_id); ++ if(ispcam->sensor_id < 0) ++ goto err_get_sensor_id; ++ mutex_unlock(&sensor_id_lock); ++ ret = media_pipeline_start(entity, &pipe->pipeline); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to start pipeline\n"); ++ goto err_pipeline_start; ++ } ++ ++ ret = isp_video_subdev_reset(ispvideo); ++ ret = isp_video_subdev_init(ispvideo); ++ if(ret) { ++ dev_err(ispvideo->dev, "Failed to init subdev\n"); ++ goto err_subdev_init; ++ } ++ } ++ ++ ret = isp_video_subdev_stream(ispvideo, 1); ++ ++ if(ret < 0) { ++ goto err_start_stream; ++ } ++ ++ mutex_unlock(&ispvideo->stream_lock); ++ ++ mutex_unlock(&ispcam->mutex); ++ return 0; ++ ++err_start_stream: ++err_subdev_init: ++ media_pipeline_stop(entity); ++err_pipeline_start: ++ put_sensor_id(ispcam->sensor_id); ++err_get_sensor_id: ++ ispcam->enabled--; ++ mutex_unlock(&ispvideo->stream_lock); ++ mutex_unlock(&ispcam->mutex); ++ return ret; ++} ++static void isp_video_stop_streaming(struct vb2_queue *q) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ unsigned int is_streaming = 0; ++ int ret = 0; ++ ++ mutex_lock(&ispcam->mutex); ++ ++ mutex_lock(&ispvideo->stream_lock); ++ ++ ++ ++ is_streaming = vb2_is_streaming(q); ++ ++ if(!is_streaming) ++ goto done; ++ ++ ret = isp_video_subdev_stream(ispvideo, 0); ++ ++ if(--ispcam->enabled > 0) { ++ goto finish; ++ } ++ ++ mutex_lock(&sensor_id_lock); ++ put_sensor_id(ispcam->sensor_id); ++ mutex_unlock(&sensor_id_lock); ++ media_pipeline_stop(&ispvideo->video.entity); ++ ++finish: ++done: ++ mutex_unlock(&ispvideo->stream_lock); ++ mutex_unlock(&ispcam->mutex); ++} ++ ++static const struct vb2_ops isp_video_queue_ops = { ++ .queue_setup = isp_video_queue_setup, ++ .buf_prepare = isp_video_buffer_prepare, ++ .buf_queue = isp_video_buffer_queue, ++ .start_streaming = isp_video_start_streaming, ++ .stop_streaming = isp_video_stop_streaming, ++}; ++ ++ ++static int isp_video_open(struct file *file) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct video_device *vdev = &ispvideo->video; ++ struct isp_video_ctx *ctx = NULL; ++ struct vb2_queue *queue = NULL; ++ int ret = 0; ++ mutex_lock(&ispvideo->mutex); ++ if(ispvideo->queue != NULL) { ++ mutex_unlock(&ispvideo->mutex); ++ return -EBUSY; ++ } ++ ++ ctx = kzalloc(sizeof(struct isp_video_ctx), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(ctx)) { ++ dev_err(ispvideo->ispcam->dev, "Failed to alloc ctx for isp_video_ctx\n"); ++ ret = -ENOMEM; ++ goto err_ctx_alloc; ++ } ++ ++ v4l2_fh_init(&ctx->fh, &ispvideo->video); ++ v4l2_fh_add(&ctx->fh); ++ ++ queue = &ctx->queue; ++ queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ queue->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; ++ queue->drv_priv = ctx; ++ queue->ops = &isp_video_queue_ops; ++ queue->mem_ops = &ingenic_vb2_dma_contig_memops; ++ queue->buf_struct_size = sizeof(struct isp_video_buffer); ++ queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ queue->lock = &ispvideo->queue_lock; ++ ++ ret = vb2_queue_init(&ctx->queue); ++ if(ret < 0) { ++ goto err_vb2_queue_init; ++ } ++ ++ ctx->ispvideo = ispvideo; ++ ispvideo->ctx = ctx; ++ vdev->queue = ispvideo->queue = queue; ++ ++ file->private_data = &ctx->fh; ++ ++ mutex_unlock(&ispvideo->mutex); ++ ++ return 0; ++err_vb2_queue_init: ++ v4l2_fh_del(&ctx->fh); ++ kfree(ctx); ++err_ctx_alloc: ++ mutex_unlock(&ispvideo->mutex); ++ return ret; ++} ++static int isp_video_release(struct file *file) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct video_device *vdev = &ispvideo->video; ++ struct isp_video_ctx *ctx = ispvideo->ctx; ++ ++ /*lock*/ ++ ++ mutex_lock(&ispvideo->mutex); ++ ++ vb2_queue_release(&ctx->queue); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ ++ kfree(ctx); ++ file->private_data = NULL; ++ vdev->queue = ispvideo->queue = NULL; ++ ++ mutex_unlock(&ispvideo->mutex); ++ ++ /*unlock*/ ++ ++ return 0; ++} ++ ++const static struct v4l2_file_operations isp_video_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = video_ioctl2, ++ .open = isp_video_open, ++ .release = isp_video_release, ++ .poll = vb2_fop_poll, /*isp_video_poll,*/ ++ .mmap = vb2_fop_mmap, /*isp_video_mmap,*/ ++}; ++ ++ ++int isp_video_init(struct isp_video_device *ispvideo, char *name, const struct isp_video_ops *video_ops) ++{ ++ int ret = 0; ++ struct video_device *video = &ispvideo->video; ++ struct media_entity *entity = &video->entity; ++ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); ++ ++ ++ /*创建buffer分é…器*/ ++ ispvideo->alloc_ctx = ingenic_vb2_dma_contig_init_ctx(ispvideo->ispcam->dev); ++ if(IS_ERR(ispvideo)) { ++ return -ENOMEM; ++ } ++ ++ /*åˆå§‹åŒ–一个sink pad*/ ++ ispvideo->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; ++ ret = media_entity_pads_init(&video->entity, 1, &ispvideo->pad); ++ if(ret < 0) { ++ /*TODO: error case*/ ++ } ++ sd->owner = THIS_MODULE; ++ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ sd->entity.function = MEDIA_ENT_F_IO_V4L; ++ ++ mutex_init(&ispvideo->queue_lock); ++ mutex_init(&ispvideo->mutex); ++ mutex_init(&ispvideo->stream_lock); ++ ++ snprintf(video->name, sizeof(video->name), "isp-%s", name); ++ video->fops = &isp_video_fops; ++ ++ if(ispvideo->bypass) ++ video->ioctl_ops = &bypass_video_ioctl_ops; ++ else ++ video->ioctl_ops = &isp_video_ioctl_ops; ++ ++ video->release = video_device_release_empty; ++ video->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ ++ ispvideo->name = video->name; ++ ispvideo->ops = video_ops; ++ ispvideo->dev = ispvideo->ispcam->dev; ++ ++ video_set_drvdata(&ispvideo->video, ispvideo); ++ ++ return 0; ++ ++} ++ ++int isp_video_cleanup(struct isp_video_device *ispvideo) ++{ ++ ++ return 0; ++} ++ ++int isp_video_register(struct isp_video_device *ispvideo, struct v4l2_device *v4l2_dev, int nr) ++{ ++ struct video_device *video = &ispvideo->video; ++ int ret = 0; ++ ++ video->v4l2_dev = v4l2_dev; ++ ++ ret = video_register_device(video, VFL_TYPE_VIDEO, nr); ++ if(ret < 0) { ++ /*TODO: error case*/ ++ } ++ ++ dev_info(ispvideo->dev, "register video device %s @ /dev/video%d ok\n", video->name, video->num); ++ mutex_init(&sensor_id_lock); ++ ++ return ret; ++} ++int isp_video_unregister(struct isp_video_device *ispvideo) ++{ ++ ++ return 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/isp.c b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp.c +new file mode 100644 +index 000000000..219554c5d +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/isp.c +@@ -0,0 +1,1173 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++ ++#include "isp-drv.h" ++#include "isp-regs.h" ++#include "tiziano-isp.h" ++ ++int isp_clk = 300000000; ++module_param(isp_clk, int, S_IRUGO); ++MODULE_PARM_DESC(isp_clk, "isp core clock"); ++ ++struct isp_device *g_isp_device[2] = {0}; ++unsigned int MAIN_ISP_INDEX; ++unsigned int SEC_ISP_INDEX; ++unsigned int flag; ++unsigned int isp_enabled; ++ ++static inline unsigned int isp_reg_readl(struct isp_device *isp, unsigned int reg) ++{ ++ return readl(isp->iobase + reg); ++} ++ ++static inline void isp_reg_writel(struct isp_device *isp, unsigned int reg, unsigned int val) ++{ ++ writel(val, isp->iobase + reg); ++} ++ ++ ++ ++/* interface used by isp-core.*/ ++int system_reg_write(unsigned int reg, unsigned int value) ++{ ++ struct isp_device *isp = g_isp_device[0]; ++ isp_reg_writel(isp, reg, value); ++ return 0; ++} ++ ++unsigned int system_reg_read(unsigned int reg) ++{ ++ struct isp_device *isp = g_isp_device[0]; ++ return isp_reg_readl(isp, reg); ++} ++ ++int system_irq_func_main_set(int irq, void *func) ++{ ++ struct isp_device *core = g_isp_device[MAIN_ISP_INDEX]; ++ ++ core->irq_func_cb[irq] = func; ++ return 0; ++} ++ ++int system_irq_func_sec_set(int irq, void *func) ++{ ++ struct isp_device *core = g_isp_device[SEC_ISP_INDEX]; ++ ++ core->irq_func_cb[irq] = func; ++ return 0; ++} ++ ++static int isp_cpm_stop(struct isp_device *isp) ++{ ++ int timeout = 0xffffff; ++ unsigned int value = 0; ++ ++ ++ /*stop request*/ ++ value = readl(isp->cpm_reset); ++ value |= 1 << isp->bit_stp; ++ writel(value, isp->cpm_reset); ++ ++ /*stop ack*/ ++ while(!(readl(isp->cpm_reset) & (1 << isp->bit_ack)) && --timeout); ++ ++ if(timeout == 0) { ++ dev_err(isp->dev, "isp wait stop timeout\n"); ++ return -ETIMEDOUT; ++ } ++ return 0; ++} ++ ++static int isp_cpm_reset(struct isp_device *isp) ++{ ++ int timeout = 0xffffff; ++ unsigned int value = 0; ++ ++ /*stop request*/ ++ value = readl(isp->cpm_reset); ++ value |= 1 << isp->bit_stp; ++ writel(value, isp->cpm_reset); ++ ++ /*stop ack*/ ++ while(!(readl(isp->cpm_reset) & (1 << isp->bit_ack)) && --timeout); ++ ++ if(timeout == 0) { ++ dev_err(isp->dev, "isp wait stop timeout\n"); ++ return -ETIMEDOUT; ++ } ++ ++ /* activate reset */ ++ value = readl(isp->cpm_reset); ++ value &= ~(1 << isp->bit_stp); ++ value |= 1 << isp->bit_sr; ++ writel(value, isp->cpm_reset); ++ ++ /* deactive reset */ ++ value = readl(isp->cpm_reset); ++ value &= ~(1 << isp->bit_sr); ++ writel(value, isp->cpm_reset); ++ ++ return 0; ++} ++ ++static int ingenic_isp_parse_dt(struct isp_device * isp) ++{ ++ struct device *dev = isp->dev; ++ unsigned int cpm_reset = 0; ++ int ret = 0; ++ ++ of_property_read_u32(dev->of_node, "ingenic,index", &isp->index); ++ of_property_read_u32(dev->of_node, "ingenic,cpm_reset", &cpm_reset); ++ of_property_read_u32(dev->of_node, "ingenic,bit_sr", &isp->bit_sr); ++ of_property_read_u32(dev->of_node, "ingenic,bit_stp", &isp->bit_stp); ++ of_property_read_u32(dev->of_node, "ingenic,bit_ack", &isp->bit_ack); ++ ++ isp->cpm_reset = (void __iomem *)cpm_reset; ++ ++ return ret; ++} ++ ++#if 0 ++int isp_load_params(tisp_init_param_t *iparam, char *bpath) ++{ ++ struct file *file = NULL; ++ struct inode *inode = NULL; ++ mm_segment_t old_fs; ++ loff_t fsize = 0; ++ loff_t *pos = NULL; ++ tisp_bin_t attr; ++ unsigned int ret = 0; ++ ++ char file_name[64] = {0}; ++ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ if(strlen(bpath)) ++ sprintf(attr.bname, bpath); ++ else ++ snprintf(attr.bname, sizeof(attr.bname), "/etc/sensor/%s-x2500.bin", iparam->sensor); ++ sprintf(bpath, attr.bname); ++ sprintf(file_name, attr.bname); ++ ++ /* open file */ ++ file = filp_open(file_name, O_RDONLY, 0); ++ if (file < 0 || IS_ERR(file)) { ++ printk("ISP: open %s file for isp calibrate read failed\n", file_name); ++ ret = -1; ++ iparam->tuned_params = NULL; ++ goto failed_open_file; ++ } ++ ++ /* read file */ ++ inode = file->f_inode; ++ fsize = inode->i_size; ++ pos = &(file->f_pos); ++ ++ if(iparam->tuned_params == NULL){ ++ iparam->tuned_params = kzalloc(fsize, GFP_KERNEL); ++ if(iparam->tuned_params == NULL){ ++ printk("%s[%d]: Failed to alloc %lld KB buffer!\n",__func__,__LINE__, fsize >> 10); ++ ret = -1; ++ goto failed_malloc_data; ++ } ++ iparam->tuned_params_size = fsize; ++ } ++ ++ vfs_read(file, iparam->tuned_params, fsize, pos); ++ ++failed_malloc_data: ++ filp_close(file, NULL); ++ set_fs(old_fs); ++failed_open_file: ++ return ret; ++} ++ ++int isp_release_params(tisp_init_param_t *iparam) ++{ ++ if(iparam->tuned_params) { ++ kfree(iparam->tuned_params); ++ iparam->tuned_params = NULL; ++ iparam->tuned_params_size = 0; ++ } ++ ++ return 0; ++} ++#endif ++ ++static int isp_subdev_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct isp_device *isp = v4l2_get_subdevdata(sd); ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct v4l2_subdev_format *input_fmt = &isp->formats[ISP_PAD_SINK]; ++ tisp_init_param_t iparam = {0}; ++ int ret = 0; ++ ++ if(isp_enabled == 0) { ++ ret = isp_cpm_reset(isp); ++ if(ret) { ++ return ret; ++ } ++ } ++ ++ isp->sensor_id = val; ++ if(val == 0) { ++ MAIN_ISP_INDEX = isp->index; ++ //printk("MIAN_ISP_INDEC is %d\n",isp->index); ++ } else if(val == 1) { ++ SEC_ISP_INDEX = isp->index; ++ //printk("SEC_ISP_INDEC is %d\n",isp->index); ++ } ++ ++ iparam.width = input_fmt->format.width; ++ iparam.height = input_fmt->format.height; ++ ++ iparam.WdrEn = isp->sensor_info->wdr_en; ++ iparam.sensorId = isp->sensor_id; //the sensor id:mark the struct for sensor 0/1 ++ memcpy(&iparam.multi_mode, &isp->multi_mode, sizeof(multisensor_mode_t)); ++ ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ iparam.bayer = 0; ++ break; ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ iparam.bayer = 1 << 16; ++ break; ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ iparam.bayer = 2 << 16; ++ break; ++ default: ++ dev_err(isp->dev, "%s[%d] the format(0x%08x) of input couldn't be handled!\n", ++ __func__,__LINE__, input_fmt->format.code); ++ return -EINVAL; ++ break; ++ } ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: ++ case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE: ++ case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE: ++ case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE: ++ case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE: ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ iparam.bayer += 1; ++ break; ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ iparam.bayer += 3; ++ break; ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ iparam.bayer += 2; ++ break; ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ iparam.bayer += 0; ++ break; ++ default: ++ dev_err(isp->dev, "%s[%d] the format(0x%08x) of input couldn't be handled!\n", ++ __func__,__LINE__, input_fmt->format.code); ++ return -EINVAL; ++ break; ++ } ++ ++ ++ strncpy(iparam.sensor, ispcam->isd[0].sd->dev->driver->name, sizeof(iparam.sensor)); ++ iparam.sensor_info.fps = isp->sensor_info->fps; ++ iparam.sensor_info.total_width = isp->sensor_info->total_width; ++ iparam.sensor_info.total_height = isp->sensor_info->total_height; ++ ++ if(isp->sensor_id == 0) ++ ret = tisp_main_init(&iparam, isp->bpath.path); ++ else if(isp->sensor_id == 1) ++ ret = tisp_sec_init(&iparam, isp->bpath.path); ++ ++ if(ret) ++ return ret; ++ ++ tisp_stream_on(&iparam); ++ system_reg_write(SEC_MSCA_ADDR_FORCE, 1); ++ ++ return 0; ++} ++ ++/* interface should be removed. */ ++static int isp_subdev_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ //struct isp_device *isp = v4l2_get_subdevdata(sd); ++ int ret = 0; ++ ++// ret = isp_cpm_reset(isp); ++ ++ return ret; ++} ++ ++static const struct v4l2_subdev_core_ops isp_subdev_core_ops = { ++ .init = isp_subdev_init, ++ .reset = isp_subdev_reset, ++ .log_status = v4l2_ctrl_subdev_log_status, ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static int isp_subdev_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct isp_device *isp = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ struct v4l2_subdev_format remote_subdev_fmt; ++ int ret = 0; ++ ++ remote = media_entity_remote_pad(&isp->pads[ISP_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ /*èŽ·å–æºå½“剿 ¼å¼ï¼Œå¤åˆ¶åˆ°è¾“出格å¼.*/ ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_err(isp->dev, "Failed to get_fmt from remote pad\n"); ++ return -EINVAL; ++ } ++ ++ /*本身ISP时没有格å¼åŒºåˆ«çš„, 这里必须从VIC获å–,å³ISPçš„SINK_PAD.*/ ++ if(format->pad == ISP_PAD_SOURCE) { ++ memcpy(&format->format, &remote_subdev_fmt.format, sizeof(format->format)); ++ } else { ++ dev_warn(isp->dev, "ISP_PAD_SOURCE should be set!\n"); ++ } ++ ++ isp->formats[ISP_PAD_SINK] = isp->formats[ISP_PAD_SOURCE] = *format; ++ isp->sensor_info = (struct sensor_info *)*(unsigned int *)format->format.reserved; ++ ++ //printk("----%s, %d, format->pad: %d\n", __func__, __LINE__, format->pad); ++ return 0; ++} ++ ++static int isp_subdev_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct isp_device *isp = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ int ret = 0; ++ ++ remote = media_entity_remote_pad(&isp->pads[ISP_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ ret = v4l2_subdev_call(remote_sd, pad, set_fmt, NULL, format); ++ if(ret < 0) { ++ dev_dbg(isp->dev, "Failed to set_fmt from remote pad\n"); ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_pad_ops isp_subdev_pad_ops = { ++ .set_fmt = isp_subdev_set_fmt, ++ .get_fmt = isp_subdev_get_fmt, ++ /* ++ .init_cfg = isp_subdev_init_cfg, ++ .enum_mbus_code = isp_subdev_enum_mbus_code, ++ .enum_frame_size = isp_subdev_enum_frame_size, ++ */ ++}; ++ ++static int isp_fw_process(void *data) ++{ ++ while(!kthread_should_stop()){ ++ tisp_fw_process(0); ++ } ++ return 0; ++} ++ ++static int isp_fw_process1(void *data) ++{ ++ while(!kthread_should_stop()){ ++ tisp_fw_process(1); ++ } ++ return 0; ++} ++ ++ ++ ++dma_addr_t wdr_paddr; ++void *wdr_vaddr; ++int wdr_size; ++ ++dma_addr_t dualsensor_paddr; ++void *dualsensor_vaddr; ++int dualsensor_size; ++ ++ ++int isp_set_wdr(struct isp_device *isp) ++{ ++ struct v4l2_subdev_format *input_fmt = &isp->formats[ISP_PAD_SINK]; ++ int width = input_fmt->format.width; ++ int height = input_fmt->format.height; ++ uint32_t tsize = width* height * 2 * 2; ++ wdr_size = tsize; ++ wdr_vaddr = dma_alloc_noncoherent(isp->ispcam->dev, tsize, &wdr_paddr, DMA_BIDIRECTIONAL, GFP_KERNEL); ++ if(!wdr_vaddr || !wdr_paddr) ++ return -ENOMEM; ++ system_reg_write(IPC_ADDR_DF_CH0_ADDR, wdr_paddr); ++ system_reg_write(IPC_ADDR_DF_CH0_SIZE , tsize / 2); ++ system_reg_write(IPC_ADDR_DF_CHN_COMP_EN, 0x0); ++ system_reg_write(IPC_ADDR_DF_CH1_ADDR, wdr_paddr); ++ system_reg_write(IPC_ADDR_DF_CH1_SIZE , tsize / 2); ++ return 0; ++} ++ ++int isp_set_mdns(struct isp_device *isp) ++{ ++ ++ struct v4l2_subdev_format *input_fmt = &isp->formats[ISP_PAD_SINK]; ++ int width = input_fmt->format.width; ++ int height = input_fmt->format.height; ++ uint32_t tsize = 0; ++ uint32_t tmpsize = 0; ++ uint32_t stride = 0; ++ uint32_t mdns_res_end_point_y; ++ uint32_t mdns_res_end_point_c; ++ int vinum = isp->sensor_id; ++ dma_addr_t mdns_paddr = 0; ++ ++ /*get mdns bufinfo*/ ++ //Ref Y ++ stride = ((width + 15) / 16) * 16; ++ tmpsize = stride * height + ((stride * height) >> 5) ; ++ tmpsize = ((tmpsize + 1023) / 1024 * 1024); ++ mdns_res_end_point_y = tmpsize / 256; ++ tsize += tmpsize; ++ ++ //Ref UV ++ stride = ((width + 31) / 32) * 32; ++ tmpsize = stride*height / 2 + ((stride*height / 2)>>6); ++ tmpsize = ((tmpsize + 1023) / 1024 * 1024); ++ mdns_res_end_point_c = tmpsize / 256; ++ tsize += tmpsize; ++ ++ //Bsn ++ stride = ((((width + 7) / 8) + 15) / 16) * 16; ++ tmpsize = (stride * height) / 4; ++ tmpsize = ((tmpsize + 1023) / 1024 * 1024); ++ tsize += tmpsize; ++ ++ //Ass ++ stride = ((width + 31) / 32) * 32; ++ tmpsize = stride * height / 2; ++ tmpsize = ((tmpsize + 1023) / 1024 * 1024); ++ tsize += tmpsize; ++ ++ //Lynne ++ stride = ((width + 31) / 32) * 16; ++ tmpsize = stride * height / 4; ++ tmpsize = ((tmpsize + 1023) / 1024 * 1024); ++ tsize += tmpsize; ++ ++ // bufinfo.paddr = 0; ++ // bufinfo.size = tsize; ++ isp->buf_info[MDNS_BUF].size = tsize; ++ isp->buf_info[MDNS_BUF].vaddr = dma_alloc_noncoherent(isp->ispcam->dev, tsize, &isp->buf_info[MDNS_BUF].paddr, DMA_BIDIRECTIONAL, GFP_KERNEL); ++ if(!isp->buf_info[MDNS_BUF].vaddr || !isp->buf_info[MDNS_BUF].paddr) ++ return -ENOMEM; ++ ++ mdns_paddr = isp->buf_info[MDNS_BUF].paddr; ++ tsize = 0; ++ ++ /*set mdns bufinfo*/ ++ //Ref Y ++ stride = ((width + 15) / 16) * 16; ++ tmpsize = stride * height + ((stride * height) >> 5) ; ++ tmpsize = ((tmpsize + 1023) / 1024 * 1024); ++ mdns_res_end_point_y = tmpsize / 256; ++ system_reg_write(MDNS_ADDR_YRESENDPOINT(vinum), mdns_res_end_point_y); ++ system_reg_write(MDNS_ADDR_YREF_ADDR(vinum), mdns_paddr + tsize); ++ system_reg_write(MDNS_ADDR_YREF_STRIDE(vinum), stride); ++ tsize += tmpsize; ++ if (tsize > isp->buf_info[MDNS_BUF].size) { ++ dev_err(isp->dev, "[ %s:%d ] buf size too small\n", __func__, __LINE__); ++ return -EFAULT; ++ } ++ ++ //REF UV ++ stride = ((width + 31) / 32) * 32; ++ tmpsize = stride*height / 2 + ((stride*height / 2)>>6); ++ tmpsize = ((tmpsize + 1023) / 1024 * 1024); ++ mdns_res_end_point_c = tmpsize / 256; ++ system_reg_write(MDNS_ADDR_CRESENDPOINT(vinum), mdns_res_end_point_c); ++ system_reg_write(MDNS_ADDR_CREF_ADDR(vinum), mdns_paddr + tsize); ++ system_reg_write(MDNS_ADDR_CREF_STRIDE(vinum), stride); ++ tsize += tmpsize; ++ if (tsize > isp->buf_info[MDNS_BUF].size) { ++ dev_err(isp->dev, "[ %s:%d ] buf size too small\n", __func__, __LINE__); ++ return -EFAULT; ++ } ++ ++ //Bsn ++ stride = ((((width + 7) / 8) + 15) / 16) * 16; ++ tmpsize = (stride * height) / 4; ++ tmpsize = ((tmpsize + 1023) /1024 * 1024); ++ system_reg_write(MDNS_ADDR_BSN_ADDR(vinum), mdns_paddr + tsize); ++ system_reg_write(MDNS_ADDR_BSN_STRIDE(vinum), stride); ++ tsize += tmpsize; ++ if (tsize > isp->buf_info[MDNS_BUF].size) { ++ dev_err(isp->dev, "[ %s:%d ] buf size too small\n", __func__, __LINE__); ++ return -EFAULT; ++ } ++ ++ //Ass ++ stride = ((width + 31) / 32) * 32; ++ tmpsize = stride * height / 2; ++ tmpsize = ((tmpsize + 1023) /1024 * 1024); ++ system_reg_write(MDNS_ADDR_ASS_ADDR(vinum), mdns_paddr + tsize); ++ system_reg_write(MDNS_ADDR_ASS_STRIDE(vinum), stride); ++ tsize += tmpsize; ++ if (tsize > isp->buf_info[MDNS_BUF].size) { ++ dev_err(isp->dev, "[ %s:%d ] buf size too small\n", __func__, __LINE__); ++ return -EFAULT; ++ } ++ ++ //Lynne ++ stride = ((width + 31) / 32) * 16; ++ tmpsize = stride * height / 4; ++ tmpsize = ((tmpsize + 1023) / 1024 * 1024); ++ system_reg_write(MDNS_ADDR_LYN_ADDR(vinum), mdns_paddr + tsize); ++ system_reg_write(MDNS_ADDR_LYN_STRIDE(vinum), stride); ++ tsize += tmpsize; ++ if (tsize > isp->buf_info[MDNS_BUF].size) { ++ dev_err(isp->dev, "[ %s:%d ] buf size too small\n", __func__, __LINE__); ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++int isp_set_dualsensor_buf(struct isp_device *isp) ++{ ++ struct v4l2_subdev_format *input_fmt = NULL; ++ uint32_t tsize = 0; ++ input_fmt = &g_isp_device[MAIN_ISP_INDEX]->formats[ISP_PAD_SINK]; ++ tsize += input_fmt->format.width * input_fmt->format.height * 2 * 2; ++ input_fmt = &g_isp_device[SEC_ISP_INDEX]->formats[ISP_PAD_SINK]; ++ tsize += input_fmt->format.width * input_fmt->format.height * 2 * 2; ++ ++ dualsensor_size = tsize; ++ if(!dualsensor_vaddr && !dualsensor_paddr) { ++ dualsensor_vaddr = dma_alloc_noncoherent(isp->ispcam->dev, tsize, &dualsensor_paddr, DMA_BIDIRECTIONAL, GFP_KERNEL); ++ if(!dualsensor_vaddr || !dualsensor_paddr) ++ return -ENOMEM; ++ } ++ ++ input_fmt = &g_isp_device[MAIN_ISP_INDEX]->formats[ISP_PAD_SINK]; ++ system_reg_write(IPC_ADDR_DF_CH1_ADDR, dualsensor_paddr); ++ system_reg_write(IPC_ADDR_DF_CH3_ADDR, dualsensor_paddr + tsize / 2); ++ ++ system_reg_write(IPC_ADDR_DF_CH1_SIZE, tsize / 2); ++ system_reg_write(IPC_ADDR_DF_CH3_SIZE, tsize / 2); ++ ++ system_reg_write(IPC_ADDR_DUAL_M3_ORI_MODE , 0x0); ++ system_reg_write(IPC_ADDR_M3_V0_URGENT_THRES, 0x60); ++ system_reg_write(IPC_ADDR_M3_V1_URGENT_THRES, 0x60); ++ system_reg_write(IPC_ADDR_M3_V0_V0_THRES , (input_fmt->format.width * input_fmt->format.height * 9 / 8)/ 256); /* width * height * 1.5 * 0.75 */ ++ system_reg_write(IPC_ADDR_M3_V0_V1_THRES , 0x0); ++ system_reg_write(IPC_ADDR_M3_V1_V0_THRES , 0x0); ++ input_fmt = &g_isp_device[MAIN_ISP_INDEX]->formats[ISP_PAD_SINK]; ++ system_reg_write(IPC_ADDR_M3_V1_V1_THRES , (input_fmt->format.width * input_fmt->format.height * 9 / 8)/ 256); ++ ++ system_reg_write(0x101c, 0x3000); //IPC OVER FLOW ++ system_reg_write(0x1020, 0x3000); ++ system_reg_write(0x1024, 0x3000); ++ system_reg_write(0x1028, 0x3000); ++ ++ return 0; ++ /* ++ bufinfo.paddr = 0; ++ bufinfo.size = vin->vi_max_width * vin->vi_max_height * 2 * 4; ++ vin = &core->vin[0]; ++ bufinfo.size += vin->vi_max_width * vin->vi_max_height * 2 * 4; ++ */ ++} ++ ++ ++static int isp_subdev_streamon(struct v4l2_subdev *sd) { ++ struct isp_device *isp = v4l2_get_subdevdata(sd); ++ unsigned long flags = 0; ++ int ret = 0; ++ ++ if(isp->enabled++ > 0) { ++ return 0; ++ } ++ ++ ret = isp_set_mdns(isp); ++ if(ret) ++ goto set_mdns_err; ++ ++ if(isp->sensor_info->wdr_en) { ++ ret = isp_set_wdr(isp); ++ if(ret) ++ goto set_wdr_err; ++ } ++ ++#ifndef CONFIG_INGENIC_ISP_V2_SENSOR_NUM_ONE ++ ret = isp_set_dualsensor_buf(isp); /*dual sensor all cached mode*/ ++ if(ret) ++ goto set_dualsensor_buf_err; ++#endif ++ ++ if(isp_enabled == 0) ++ { ++ tisp_activate_all(); ++ tisp_process_init(); ++ ret = tisp_enable_tuning(); ++ if(ret) ++ goto enable_tuning_err; ++ } ++ ++ /*For event engine.*/ ++ if(isp->sensor_id == 0) { ++ g_isp_device[0]->process_thread = kthread_run(isp_fw_process, isp, "isp_fw_process"); ++ if(IS_ERR_OR_NULL(g_isp_device[0]->process_thread)){ ++ dev_err(isp->dev, "%s[%d] kthread_run was failed!\n",__func__,__LINE__); ++ ret = -EINVAL; ++ } ++ if(ret) ++ goto process_thread_err; ++ /*enable irq*/ ++ spin_lock_irqsave(&isp->lock, flags); ++ system_reg_write(RESP_ADDR_INT_COMMON_0_EN, 0xffffffff); //common intp ++ //system_reg_write(RESP_ADDR_INT_UNUSUAL_0_EN, 0xffffffff); //unusual intp ++ //system_reg_write(RESP_ADDR_INT_BACKUP_0_EN, 1 << 27); //back0 intp ++ spin_unlock_irqrestore(&isp->lock, flags); ++ } else if (isp->sensor_id == 1) { ++ g_isp_device[1]->process_thread = kthread_run(isp_fw_process1, isp, "isp_fw_process1"); ++ if(IS_ERR_OR_NULL(g_isp_device[1]->process_thread)){ ++ dev_err(isp->dev, "%s[%d] kthread_run was failed!\n",__func__,__LINE__); ++ ret = -EINVAL; ++ } ++ if(ret) ++ goto process_thread_err; ++ /*enable irq*/ ++ spin_lock_irqsave(&isp->lock, flags); ++ system_reg_write(RESP_ADDR_INT_COMMON_1_EN, 0xffffffff); //common intp ++ spin_unlock_irqrestore(&isp->lock, flags); ++ } ++ ++ tisp_ipc_triger(); ++ isp_enabled++; ++ ++ return 0; ++ ++ ++process_thread_err: ++ if(isp_enabled == 1) { ++ tisp_disable_tuning(); ++ tisp_process_deinit(isp->sensor_id); ++ tisp_slake_all(); ++ } ++enable_tuning_err: ++#ifndef CONFIG_INGENIC_ISP_V2_SENSOR_NUM_ONE ++ if(dualsensor_vaddr && dualsensor_paddr) { ++ dma_free_noncoherent(g_isp_device[MAIN_ISP_INDEX]->ispcam->dev, dualsensor_size, dualsensor_vaddr, dualsensor_paddr, DMA_BIDIRECTIONAL); ++ } ++#endif ++set_dualsensor_buf_err: ++ dualsensor_vaddr = 0; ++ dualsensor_paddr = 0; ++ if(isp->sensor_info->wdr_en && wdr_vaddr && wdr_paddr){ ++ dma_free_noncoherent(isp->ispcam->dev, wdr_size, wdr_vaddr, wdr_paddr, DMA_BIDIRECTIONAL); ++ } ++set_wdr_err: ++ wdr_vaddr = 0; ++ wdr_paddr = 0; ++ if(isp->buf_info[MDNS_BUF].vaddr && isp->buf_info[MDNS_BUF].paddr) ++ dma_free_noncoherent(isp->ispcam->dev, isp->buf_info[MDNS_BUF].size, isp->buf_info[MDNS_BUF].vaddr, isp->buf_info[MDNS_BUF].paddr, DMA_BIDIRECTIONAL); ++set_mdns_err: ++ isp->buf_info[MDNS_BUF].vaddr = 0; ++ isp->buf_info[MDNS_BUF].paddr = 0; ++ isp->enabled--; ++ return ret; ++} ++ ++unsigned int sensor1_deinit_flag; ++static int isp_subdev_streamoff(struct v4l2_subdev *sd) { ++ struct isp_device *isp = v4l2_get_subdevdata(sd); ++ unsigned long flags = 0; ++ unsigned int top_val = 0; ++ int timeout = 0xffffff; ++ ++ if(--isp->enabled > 0) { ++ return 0; ++ } ++ ++ if(isp->sensor_info->wdr_en && wdr_vaddr && wdr_paddr){ ++ dma_free_noncoherent(isp->ispcam->dev, wdr_size, wdr_vaddr, wdr_paddr, DMA_BIDIRECTIONAL); ++ wdr_vaddr = 0; ++ wdr_paddr = 0; ++ } ++ ++ if(isp->sensor_id == 0) { ++ /*disable irq*/ ++ spin_lock_irqsave(&isp->lock, flags); ++ system_reg_write(RESP_ADDR_INT_COMMON_0_EN, 0x0); //common intp ++ spin_unlock_irqrestore(&isp->lock, flags); ++ kthread_stop(g_isp_device[0]->process_thread); ++ tisp_deinit(0); ++ } else if(isp->sensor_id == 1) { ++ /*disable irq*/ ++ spin_lock_irqsave(&isp->lock, flags); ++ system_reg_write(RESP_ADDR_INT_COMMON_1_EN, 0x0); //common intp ++ spin_unlock_irqrestore(&isp->lock, flags); ++ kthread_stop(g_isp_device[1]->process_thread); ++ tisp_deinit(1); ++ } ++ ++ if(--isp_enabled == 0) { ++ tisp_disable_tuning(); ++ tisp_slake_all(); ++#ifndef CONFIG_INGENIC_ISP_V2_SENSOR_NUM_ONE ++ if(dualsensor_vaddr && dualsensor_paddr) { ++ dma_free_noncoherent(g_isp_device[MAIN_ISP_INDEX]->ispcam->dev, dualsensor_size, dualsensor_vaddr, dualsensor_paddr, DMA_BIDIRECTIONAL); ++ dualsensor_vaddr = 0; ++ dualsensor_paddr = 0; ++ } ++#endif ++ } ++ tisp_process_deinit(isp->sensor_id); ++ ++ if(isp->buf_info[MDNS_BUF].vaddr && isp->buf_info[MDNS_BUF].paddr) { ++ dma_free_noncoherent(isp->ispcam->dev, isp->buf_info[MDNS_BUF].size, isp->buf_info[MDNS_BUF].vaddr, isp->buf_info[MDNS_BUF].paddr, DMA_BIDIRECTIONAL); ++ isp->buf_info[MDNS_BUF].vaddr = 0; ++ isp->buf_info[MDNS_BUF].paddr = 0; ++ } ++ ++ system_reg_write(SEC_MSCA_ADDR_FORCE, 1); ++ ++ if(isp_enabled == 0) { ++ top_val = system_reg_read(TOP_ADDR_STOP_CON); ++ system_reg_write(TOP_ADDR_STOP_CON, top_val | 0x1); ++ while(timeout--){ ++ top_val = system_reg_read(TOP_ADDR_STOP_STATE); ++ if(top_val & 0x01) ++ break; ++ } ++ ++ if(timeout == 0) { ++ dev_err(isp->dev, "isp wait stop timeout\n"); ++ return -ETIMEDOUT; ++ } ++ ++ top_val = system_reg_read(TOP_ADDR_TOP_RST); ++ system_reg_write(TOP_ADDR_TOP_RST, top_val | ALL_RST); ++ system_reg_write(TOP_ADDR_TOP_RST, top_val & (~ALL_RST)); ++ } ++ ++ return 0; ++} ++ ++ ++ ++static int isp_subdev_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ if(enable) ++ return isp_subdev_streamon(sd); ++ else ++ return isp_subdev_streamoff(sd); ++} ++ ++ ++static const struct v4l2_subdev_video_ops isp_subdev_video_ops = { ++ .s_stream = isp_subdev_s_stream, ++}; ++ ++ ++static const struct v4l2_subdev_ops isp_subdev_ops = { ++ .core = &isp_subdev_core_ops, ++ .pad = &isp_subdev_pad_ops, ++ .video = &isp_subdev_video_ops, ++}; ++static ssize_t ++dump_isp(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ //struct isp_device *isp = dev_get_drvdata(dev); ++ char *p = buf; ++ ++ /* ++ p += sprintf(p, "TOP_CTRL_ADDR_VERSION :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_VERSION )); ++ p += sprintf(p, "TOP_CTRL_ADDR_FM_SIZE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_FM_SIZE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_BAYER_TYPE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_BAYER_TYPE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_BYPASS_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_BYPASS_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TOP_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TOP_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TOP_STATE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TOP_STATE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_LINE_SPACE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_LINE_SPACE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_REG_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_REG_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_TRIG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_TRIG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_ADDR :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_ADDR )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_STATE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_STATE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_APB_WR_DATA :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_APB_WR_DATA )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_APB_WR_ADDR :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_APB_WR_ADDR )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RD_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RD_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_WR_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_WR_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_FR_WR_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_FR_WR_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_STA_WR_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_STA_WR_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RD_DEBUG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RD_DEBUG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_WR_DEBUG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_WR_DEBUG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_FR_WR_DEBUG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_FR_WR_DEBUG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_STA_WR_DEBUG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_STA_WR_DEBUG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_INT_EN :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_INT_EN )); ++ p += sprintf(p, "TOP_CTRL_ADDR_INT_REG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_INT_REG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_INT_CLR :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_INT_CLR )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_FREERUN :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_FREERUN )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_SIZE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_SIZE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_FONT :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_FONT )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_FLICK :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_FLICK )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_CS_TYPE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_CS_TYPE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_CS_FCLO :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_CS_FCLO )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_CS_BCLO :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_CS_BCLO )); ++*/ ++ return p - buf; ++} ++ ++ ++static DEVICE_ATTR(dump_isp, S_IRUGO|S_IWUSR, dump_isp, NULL); ++ ++static struct attribute *isp_debug_attrs[] = { ++ &dev_attr_dump_isp.attr, ++ NULL, ++}; ++ ++static struct attribute_group isp_debug_attr_group = { ++ .name = "debug", ++ .attrs = isp_debug_attrs, ++}; ++ ++ ++static int isp_comp_bind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct isp_device *isp = dev_get_drvdata(comp); ++ struct ispcam_device *ispcam = (struct ispcam_device *)master_data; ++ struct v4l2_device *v4l2_dev = &ispcam->v4l2_dev; ++ struct v4l2_subdev *sd = &isp->sd; ++ int ret = 0; ++ ++ //dev_info(comp, "----dev_name(comp): %s----%s, %d \n", dev_name(comp), __func__, __LINE__); ++ ++ /* link subdev to master.*/ ++ isp->ispcam = (void *)ispcam; ++ ispcam->isp = isp; ++ ++ /*1. register supported subdev ctrls.*/ ++ ++ ++ /*2. init v4l2_subdev*/ ++ ++ v4l2_subdev_init(sd, &isp_subdev_ops); ++ ++ sd->owner = THIS_MODULE; ++ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ strscpy(sd->name, dev_name(comp), sizeof(sd->name)); ++ v4l2_set_subdevdata(sd, isp); ++ ++ ++ /* init isp pads. */ ++ isp->pads = kzalloc(sizeof(struct media_pad) * ISP_NUM_PADS, GFP_KERNEL); ++ if(!isp->pads) { ++ ret = -ENOMEM; ++ goto err_alloc_pads; ++ } ++ isp->pads[0].index = ISP_PAD_SINK; ++ isp->pads[0].flags = MEDIA_PAD_FL_SINK; ++ isp->pads[1].index = ISP_PAD_SOURCE; ++ isp->pads[1].flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&sd->entity, ISP_NUM_PADS, isp->pads); ++ ++ /*3. register v4l2_subdev*/ ++ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_COMPOSER; ++ ret = v4l2_device_register_subdev(v4l2_dev, sd); ++ if(ret < 0) { ++ dev_err(comp, "Failed to register v4l2_subdev for isp\n"); ++ goto err_subdev_register; ++ } ++ ++ return 0; ++err_subdev_register: ++err_alloc_pads: ++ return ret; ++} ++ ++ ++static void isp_comp_unbind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct isp_device *isp = dev_get_drvdata(comp); ++ ++ dev_info(comp, "---TODO:--%p---%s, %d \n", isp, __func__, __LINE__); ++ ++} ++ ++static const struct component_ops isp_comp_ops = { ++ .bind = isp_comp_bind, ++ .unbind = isp_comp_unbind, ++}; ++ ++static irqreturn_t isp_irq_handler(int irq, void *data) ++{ ++ struct isp_device *isp = (struct isp_device *)data; ++ bool handled = 0; ++ unsigned int status, status_sec; ++ int ret = 0; ++ int i = 0; ++ ++ spin_lock(&isp->lock); ++ /*read irq_flags*/ ++ status = isp_reg_readl(isp, RESP_ADDR_INT_COMMON_0_INFO); ++ status_sec = isp_reg_readl(isp, RESP_ADDR_INT_COMMON_1_INFO); ++// printk("0x%08x 0x%08x\n", status,status_sec); ++ ++ /*1. process irq by subdev.*/ ++#if 1 ++ if(status) { ++ ret = v4l2_subdev_call(&g_isp_device[MAIN_ISP_INDEX]->ispcam->mscaler->sd, core, interrupt_service_routine, status, &handled); ++ if(ret < 0) { ++ ++ } ++ } ++ ++ if(status_sec) { ++ ret = v4l2_subdev_call(&g_isp_device[SEC_ISP_INDEX]->ispcam->mscaler->sd, core, interrupt_service_routine, status_sec, &handled); ++ if(ret < 0) { ++ ++ } ++ } ++#endif ++#if 1 ++ if (status & CH0_FRM_DONE_BF_INT) ++ tisp_hardware_reg_refresh(0); ++ ++ if (status_sec & CH0_FRM_DONE_BF_INT) ++ tisp_hardware_reg_refresh(1); ++#endif ++ ++ /*2. isp-core irq callbacks */ ++ for(i = 0; i < 32; i++) { ++ if(status & (1 << i) && g_isp_device[MAIN_ISP_INDEX]->irq_func_cb[i]) { ++ ret = g_isp_device[MAIN_ISP_INDEX]->irq_func_cb[i](); ++ if(ret < 0) { ++ ++ } ++ } ++ if(status_sec & (1 << i) && g_isp_device[SEC_ISP_INDEX]->irq_func_cb[i]) { ++ ret = g_isp_device[SEC_ISP_INDEX]->irq_func_cb[i](); ++ if(ret < 0) { ++ ++ } ++ } ++ } ++ ++ /*clear irq_flags*/ ++ isp_reg_writel(isp, RESP_ADDR_INT_COMMON_0_CLR, status); ++ isp_reg_writel(isp, RESP_ADDR_INT_COMMON_1_CLR, status_sec); ++ spin_unlock(&isp->lock); ++ return IRQ_HANDLED; ++} ++ ++static int ingenic_isp_probe(struct platform_device *pdev) ++{ ++ ++ struct isp_device *isp = NULL; ++ int ret = 0; ++ ++ isp = kzalloc(sizeof(struct isp_device), GFP_KERNEL); ++ if(!isp) { ++ pr_err("Failed to alloc isp dev [%s]\n", pdev->name); ++ return -ENOMEM; ++ } ++ ++ isp->dev = &pdev->dev; ++ platform_set_drvdata(pdev, isp); ++ ++ ++ ingenic_isp_parse_dt(isp); ++ ++#ifdef CONFIG_INGENIC_ISP_V2_SENSOR_NUM_ONE ++ isp->multi_mode.sensor_num = IMPISP_TOTAL_ONE; ++#else ++ isp->multi_mode.sensor_num = IMPISP_TOTAL_TWO; ++#endif ++ isp->multi_mode.dual_mode = IMPISP_DUALSENSOR_DUAL_ALLCACHED_MODE; ++ isp->multi_mode.joint_mode = IMPISP_NOT_JOINT; ++ ++ ret = component_add(isp->dev, &isp_comp_ops); ++ if(ret < 0) { ++ dev_err(isp->dev, "Failed to add component isp!\n"); ++ } ++ ++ g_isp_device[isp->index] = isp; ++ ++ isp->iobase = (unsigned int *)0xb3300000; ++ isp->irq = 31+8; ++ ++ spin_lock_init(&isp->lock); ++ ++ if(!flag){ ++ // ret = devm_request_irq(isp->dev, isp->irq, isp_irq_handler, 0, ++ // dev_name(isp->dev), isp); ++ ++ ret = request_irq(isp->irq, isp_irq_handler, 0, ++ dev_name(isp->dev), isp); ++ ++ if(ret) { ++ dev_err(isp->dev, "request irq failed!\n"); ++ goto err_request_irq; ++ } ++ ++ ++ isp->div_clk = of_clk_get(isp->dev->of_node, 0); ++ if(!isp->div_clk) { ++ dev_err(isp->dev, "failed to get isp div_clk\n"); ++ goto err_div_clk; ++ } ++ ++ clk_set_rate(isp->div_clk, isp_clk); ++ ++ clk_prepare_enable(isp->div_clk); ++ ++ isp->gate_clk = of_clk_get(isp->dev->of_node, 1); ++ if(!isp->gate_clk) { ++ dev_err(isp->dev, "failed to get isp gate_clk\n"); ++ goto err_gate_clk; ++ } ++ ++ clk_prepare_enable(isp->gate_clk); ++ ++ ++ ret = sysfs_create_group(&isp->dev->kobj, &isp_debug_attr_group); ++ if (ret) { ++ dev_err(isp->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_sys_group; ++ } ++ flag = 1; ++ } ++ ++ return 0; ++err_sys_group: ++err_gate_clk: ++err_div_clk: ++err_request_irq: ++ return ret; ++} ++ ++ ++ ++static int ingenic_isp_remove(struct platform_device *pdev) ++{ ++ struct isp_device *isp = dev_get_drvdata(&pdev->dev); ++ ++ clk_disable_unprepare(isp->power_clk); ++ clk_disable_unprepare(isp->gate_clk); ++ clk_disable_unprepare(isp->div_clk); ++ return 0; ++} ++ ++ ++ ++static const struct of_device_id ingenic_isp_dt_match[] = { ++ { .compatible = "ingenic,x2500-isp" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_isp_dt_match); ++ ++static int __maybe_unused ingenic_isp_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct isp_device *isp = dev_get_drvdata(&pdev->dev); ++ ++ if(isp->enabled){ ++ dev_err(isp->dev, "faild to suspend, isp is streaming on\n"); ++ return -EBUSY; ++ } ++ ++ isp_cpm_stop(isp); ++ clk_disable_unprepare(isp->power_clk); ++ clk_disable_unprepare(isp->gate_clk); ++ clk_disable_unprepare(isp->div_clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused ingenic_isp_resume(struct platform_device *pdev) ++{ ++ struct isp_device *isp = dev_get_drvdata(&pdev->dev); ++ ++ clk_prepare_enable(isp->div_clk); ++ clk_prepare_enable(isp->gate_clk); ++ clk_prepare_enable(isp->power_clk); ++ isp_cpm_reset(isp); ++ ++ return 0; ++} ++ ++static struct platform_driver ingenic_isp_driver = { ++ .probe = ingenic_isp_probe, ++ .remove = ingenic_isp_remove, ++ .suspend = ingenic_isp_suspend, ++ .resume = ingenic_isp_resume, ++ .driver = { ++ .name = "ingenic-isp", ++ .of_match_table = ingenic_isp_dt_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_isp_driver); ++ ++MODULE_ALIAS("platform:ingenic-isp"); ++MODULE_DESCRIPTION("ingenic isp subsystem"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler-bdev.c b/module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler-bdev.c +new file mode 100644 +index 000000000..3bd1bb032 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler-bdev.c +@@ -0,0 +1,255 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "helix_drv.h" ++#include "jpge.h" ++ ++#include "isp-drv.h" ++ ++ ++int ms_bdev_qbuf(struct mscaler_backend_device *ms_bdev, struct isp_video_buffer *isp_buffer) ++{ ++ ++ unsigned long flags; ++ ++// printk("--------%s, %d\n", __func__, __LINE__); ++ ++ spin_lock_irqsave(&ms_bdev->lock, flags); ++ ++ list_add_tail(&isp_buffer->list_entry, &ms_bdev->processing_list); ++ ++ spin_unlock_irqrestore(&ms_bdev->lock, flags); ++ ++ /* wakeup possible process thread. */ ++ wake_up(&ms_bdev->wq); ++} ++ ++ ++static int ms_bdev_kthread(void *data) ++{ ++ ++ struct mscaler_backend_device *ms_bdev = data; ++ int ret = 0; ++ unsigned long flags; ++ ++ struct ingenic_venc_ctx *ctx = ms_bdev->ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ ++ struct video_frame_buffer src_frame; ++ ++ while(1) { ++ ++ if(kthread_should_stop()) ++ break; ++ ++ ++ ret = wait_event_interruptible(ms_bdev->wq, !list_empty(&ms_bdev->processing_list) || ms_bdev->activated == 0); ++ if(ret || ms_bdev->activated == 0) { ++ /*wakeup by interrupt?*/ ++ /* STOP*/ ++ continue; ++ } ++ ++ spin_lock_irqsave(&ms_bdev->lock, flags); ++ struct isp_video_buffer *isp_buffer = list_first_entry_or_null(&ms_bdev->processing_list, struct isp_video_buffer, list_entry); ++ ++ if(!isp_buffer) { ++ dev_err(ms_bdev->dev, "No Buffer available!\n"); ++ } else { ++ ++ list_del(&isp_buffer->list_entry); ++ } ++ spin_unlock_irqrestore(&ms_bdev->lock, flags); ++ ++ struct vb2_v4l2_buffer *vb2 = &isp_buffer->vb2; ++ ++ ++ mutex_lock(&ctx->dev->dev_mutex); ++ /* Processing ....*/ ++ ++ memset(&src_frame, 0, sizeof(struct video_frame_buffer)); ++ ++ src_frame.num_planes = 2; ++ src_frame.fb_addr[0].pa = ingenic_vb2_dma_contig_plane_dma_addr(&vb2->vb2_buf, 0); ++ src_frame.fb_addr[1].pa = src_frame.fb_addr[0].pa + isp_buffer->uv_offset; ++ ++ src_frame.fb_addr[0].va = vb2_plane_vaddr(&vb2->vb2_buf, 0); ++ src_frame.fb_addr[1].va = src_frame.fb_addr[0].va + isp_buffer->uv_offset; ++ ++ src_frame.fb_addr[0].size = isp_buffer->uv_offset; ++ src_frame.fb_addr[1].size = vb2_get_plane_payload(&vb2->vb2_buf, 0) - src_frame.fb_addr[0].size; ++ ++ dma_sync_single_for_device(ms_bdev->dev,(unsigned long)jpge_ctx->bs->pa, jpge_ctx->bs->size, DMA_FROM_DEVICE); ++ ++ jpeg_encoder_encode(jpge_ctx, &src_frame, jpge_ctx->bs); ++ ++ memcpy(vb2_plane_vaddr(&vb2->vb2_buf, 0), jpge_ctx->bs->va, jpge_ctx->bslen); ++ ++ vb2_set_plane_payload(&vb2->vb2_buf, 0, jpge_ctx->bslen); ++ ++#if 0 ++ wait_process_buffer(); ++ ++ done_process_buffer(); ++#endif ++ mutex_unlock(&ctx->dev->dev_mutex); ++// printk("----done_processing_buffer: %d\n", isp_buffer->vb2.vb2_buf.index); ++ vb2_buffer_done(&isp_buffer->vb2.vb2_buf, VB2_BUF_STATE_DONE); ++ ++ } ++ ++ return 0; ++} ++ ++ ++static int venc_create_ctx(struct mscaler_backend_device *ms_bdev) ++{ ++ ++ struct ingenic_venc_ctx *ctx = kzalloc(sizeof(struct ingenic_venc_ctx), GFP_KERNEL); ++ struct h264e_ctx * h264e_ctx = NULL; ++ struct jpge_ctx * jpge_ctx = NULL; ++ struct ingenic_vcodec_mem *bs = NULL; ++ int ret = 0; ++ ++ if(ctx == NULL) { ++ return -ENOMEM; ++ } ++ ++ ctx->dev = ingenic_venc_dev_get(); ++ ++ mutex_lock(&ctx->dev->dev_mutex); ++ ++#if 0 ++ if (!ctx->dev->id_counter) { ++ vpu_on(ctx->dev); ++ } ++#endif ++ ++ ctx->id = ctx->dev->id_counter++; ++ init_waitqueue_head(&ctx->queue); ++ ++ mutex_unlock(&ctx->dev->dev_mutex); ++ ++ ms_bdev->ctx = ctx; ++ ++ /*switch FMT: JPEG H264.*/ ++ jpge_ctx = &ctx->jpge_ctx; ++ ctx->codec_id = CODEC_ID_JPGE; ++ ++ ret = jpeg_encoder_init(jpge_ctx); ++ jpeg_encoder_set_priv(jpge_ctx, ctx); ++ ++ ++ jpeg_encoder_set_fmt(jpge_ctx, ms_bdev->width, ms_bdev->height, HELIX_NV12_MODE); ++ ++ ret = jpeg_encoder_alloc_workbuf(jpge_ctx); ++ if(ret < 0) { ++ goto err_alloc_workbuf; ++ } ++ ++ /* alloc bs output buffer. */ ++ bs = kzalloc(sizeof(struct ingenic_vcodec_mem), GFP_KERNEL); ++ if(!bs) { ++ goto err_bs_alloc; ++ } ++ bs->size = ms_bdev->width * ms_bdev->height; ++ ++ bs->va = dma_alloc_noncoherent(ms_bdev->dev, bs->size, &bs->pa, GFP_KERNEL); ++ if(!bs->va) { ++ goto err_bs_va_alloc; ++ } ++ ++ jpge_ctx->bs = bs; ++ ++ ++ return 0; ++err_bs_va_alloc: ++ kfree(bs); ++err_bs_alloc: ++ jpeg_encoder_free_workbuf(jpge_ctx); ++err_alloc_workbuf: ++ jpeg_encoder_deinit(jpge_ctx); ++ ++ kfree(ctx); ++ ms_bdev->ctx = NULL; ++ return ret; ++} ++ ++static int venc_free_ctx(struct mscaler_backend_device *ms_bdev) ++{ ++ struct ingenic_venc_ctx *ctx = ms_bdev->ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct ingenic_vcodec_mem *bs = jpge_ctx->bs; ++ ++ ++ ++ mutex_lock(&ctx->dev->dev_mutex); ++#if 0 ++ if (!--ctx->dev->id_counter) { ++ vpu_off(ctx->dev); ++ } ++#endif ++ mutex_unlock(&ctx->dev->dev_mutex); ++ ++ dma_free_noncoherent(ms_bdev->dev, bs->size, bs->va, bs->pa); ++ kfree(bs); ++ ++ jpeg_encoder_free_workbuf(jpge_ctx); ++ jpeg_encoder_deinit(jpge_ctx); ++ ++ kfree(ctx); ++} ++ ++ ++int ms_bdev_init(struct mscaler_backend_device *ms_bdev) ++{ ++ int ret = 0; ++ printk("--------%s, %d\n", __func__, __LINE__); ++ ++ ret = venc_create_ctx(ms_bdev); ++ if(ret < 0) { ++ return -EINVAL; ++ } ++ ++ spin_lock_init(&ms_bdev->lock); ++ INIT_LIST_HEAD(&ms_bdev->processing_list); ++ init_waitqueue_head(&ms_bdev->wq); ++ ++ ms_bdev->process_thread = kthread_run(ms_bdev_kthread, ms_bdev, "ms-bdev-ch%d", ms_bdev->ch); ++ if(IS_ERR_OR_NULL(ms_bdev->process_thread)) { ++ ++ dev_err(ms_bdev->dev, "Failed to run kthread for ms-bdev-ch%d", ms_bdev->ch); ++ ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int ms_bdev_deinit(struct mscaler_backend_device *ms_bdev) ++{ ++ ++ printk("--------%s, %d\n", __func__, __LINE__); ++ ++ if(!ms_bdev->activated) { ++ return 0; ++ } ++ ++ ++ kthread_stop(ms_bdev->process_thread); ++ ++ ms_bdev->process_thread = NULL; ++ ++ venc_free_ctx(ms_bdev); ++ ++ memset(ms_bdev, 0, sizeof(struct mscaler_backend_device)); ++ ++ return 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler-regs.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler-regs.h +new file mode 100644 +index 000000000..dfbbb43bf +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler-regs.h +@@ -0,0 +1,80 @@ ++#ifndef __INGENIC_ISP_MSCALER_REGS_H__ ++#define __INGENIC_ISP_MSCALER_REGS_H__ ++ ++#define MSCA_BASE 0 ++ ++//============================================================ ++// Mscaler ++//============================================================ ++#define MSCA_CH_EN (MSCA_BASE+0x008) ++#define MSCA_INT_STA (MSCA_BASE+0x00C) ++#define MSCA_INT_MSK (MSCA_BASE+0x010) ++#define MSCA_MASK_EN (MSCA_BASE+0x014) ++#define MSCA_DMAOUT_ARB (MSCA_BASE+0x018) ++#define MSCA_CLK_GATE_EN (MSCA_BASE+0x01C) ++#define MSCA_CLK_DIS (MSCA_BASE+0x020) ++#define MSCA_SRC_IN (MSCA_BASE+0x030) ++#define MSCA_SRC_SIZE (MSCA_BASE+0x034) ++#define MSCA_GLO_RSZ_COEF_WR (MSCA_BASE+0x040) ++#define MSCA_SYS_PRO_CLK_EN (MSCA_BASE+0x050) ++#define MSCA_DS0_CLK_NUM (MSCA_BASE+0x054) ++#define MSCA_DS1_CLK_NUM (MSCA_BASE+0x058) ++#define MSCA_DS2_CLK_NUM (MSCA_BASE+0x05C) ++ ++#define CHx_RSZ_OSIZE(n) (MSCA_BASE+(0x0100*(n))+0x100) ++#define CHx_RSZ_STEP(n) (MSCA_BASE+(0x0100*(n))+0x104) ++ ++#define CHx_CROP_OPOS(n) (MSCA_BASE+(0x0100*(n))+0x128) ++#define CHx_CROP_OSIZE(n) (MSCA_BASE+(0x0100*(n))+0x12c) ++#define CHx_FRA_CTRL_LOOP(n) (MSCA_BASE+(0x0100*(n))+0x130) ++#define CHx_FRA_CTRL_MASK(n) (MSCA_BASE+(0x0100*(n))+0x134) ++#define CHx_MSx_POS(n,m) (MSCA_BASE+(0x0100*(n))+0x138+(0x0c*(m))) ++#define CHx_MSx_SIZE(n,m) (MSCA_BASE+(0x0100*(n))+0x13c+(0x0c*(m))) ++#define CHx_MSx_VALUE(n,m) (MSCA_BASE+(0x0100*(n))+0x140+(0x0c*(m))) ++#define CHx_MS0_POS(n) (MSCA_BASE+(0x0100*(n))+0x138) ++#define CHx_MS0_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x13c) ++#define CHx_MS0_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x140) ++#define CHx_MS1_POS(n) (MSCA_BASE+(0x0100*(n))+0x144) ++#define CHx_MS1_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x148) ++#define CHx_MS1_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x14c) ++#define CHx_MS2_POS(n) (MSCA_BASE+(0x0100*(n))+0x150) ++#define CHx_MS2_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x154) ++#define CHx_MS2_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x158) ++#define CHx_MS3_POS(n) (MSCA_BASE+(0x0100*(n))+0x15c) ++#define CHx_MS3_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x160) ++#define CHx_MS3_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x164) ++#define CHx_OUT_FMT(n) (MSCA_BASE+(0x0100*(n))+0x168) ++#define CHx_DMAOUT_Y_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x16c) ++#define CHx_Y_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x170) ++#define CHx_DMAOUT_Y_LAST_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x174) ++#define CHx_DMAOUT_Y_LAST_STATS_NUM(n) (MSCA_BASE+(0x0100*(n))+0x178) ++#define CHx_Y_LAST_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x17c) ++#define CHx_DMAOUT_Y_STRI(n) (MSCA_BASE+(0x0100*(n))+0x180) ++#define CHx_DMAOUT_UV_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x184) ++#define CHx_UV_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x188) ++#define CHx_DMAOUT_UV_LAST_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x18c) ++#define CHx_DMAOUT_UV_LAST_STATS_NUM(n) (MSCA_BASE+(0x0100*(n))+0x190) ++#define CHx_UV_LAST_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x194) ++#define CHx_DMAOUT_UV_STRI(n) (MSCA_BASE+(0x0100*(n))+0x198) ++#define CHx_DMAOUT_Y_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x19c) ++#define CHx_DMAOUT_UV_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a0) ++#define CHx_DMAOUT_Y_LAST_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a4) ++#define CHx_DMAOUT_UV_LAST_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a8) ++#define CHx_DMAOUT_Y_ADDR_SEL(n) (MSCA_BASE+(0x0100*(n))+0x1ac) ++#define CHx_DMAOUT_UV_ADDR_SEL(n) (MSCA_BASE+(0x0100*(n))+0x1b0) ++ ++#define MSCA_CH0_FRM_DONE_INT (0) ++#define MSCA_CH1_FRM_DONE_INT (1) ++#define MSCA_CH2_FRM_DONE_INT (2) ++#define MSCA_CH0_CROP_ERR_INT (3) ++#define MSCA_CH1_CROP_ERR_INT (4) ++#define MSCA_CH2_CROP_ERR_INT (5) ++ ++#define CHx_OUT_FMT_NV12 0x0 ++#define CHx_OUT_FMT_NV21 0x1 ++#define CHx_OUT_FMT_ARGB8888 0x2 ++#define CHx_OUT_FMT_RGB565 0x3 ++#define CHx_OUT_FMT_Y_OUT_ONLY (1 << 6) ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler.c b/module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler.c +new file mode 100644 +index 000000000..d72c464d6 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/mscaler.c +@@ -0,0 +1,1411 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++#include "mscaler-regs.h" ++ ++static void dump_mscaler_regs(struct mscaler_device *mscaler); ++ ++static struct isp_video_format mscaler_output_formats[] = { ++ { ++ .name = "NV12, Y/CbCr 4:2:0", ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .depth = {8, 4}, ++ .num_planes = 2, ++ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "NV21, Y/CrCb 4:2:0", ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .depth = {8, 4}, ++ .num_planes = 2, ++ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "GREY, Greyscale", ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++#ifdef CONFIG_MSCA_BDEV ++ { ++ .name = "JFIF JPEG", ++ .fourcc = V4L2_PIX_FMT_JPEG, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .name = "H264 with start codes", ++ .fourcc = V4L2_PIX_FMT_H264, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, ++#endif ++ /* ++ { ++ .name = "RGB565, RGB-5-6-5", ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_RGB565_1X16, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "ARGB32, ARGB-8-8-8-8", ++ .fourcc = V4L2_PIX_FMT_ARGB32, ++ .depth = {32}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_ARGB8888_1X32, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ */ ++}; ++ ++struct ingenic_isp_framesizes { ++ u32 fourcc; ++ struct v4l2_frmsize_discrete discrete; ++}; ++ ++static const struct ingenic_isp_framesizes ingenic_isp_framesizes[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {320, 240}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {240, 320}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {640, 480}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {480, 640}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {960, 720}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {720, 960}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {1280, 720}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {1280, 960}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {1920, 1080}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {320, 240}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {240, 320}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {640, 480}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {480, 640}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {960, 720}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {720, 960}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {1280, 720}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {1280, 960}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {1920, 1080}, ++ } ++}; ++ ++struct mask_kobj_attr { ++ struct kobj_attribute attr; ++ unsigned int id; ++}; ++ ++#define to_mask_attr(attr) \ ++ container_of(attr, struct mask_kobj_attr, attr) ++ ++static inline void mscaler_reg_writel(struct mscaler_device *mscaler, unsigned int reg, unsigned int val) ++{ ++ writel(val, mscaler->iobase + reg); ++} ++ ++static inline unsigned int mscaler_reg_readl(struct mscaler_device *mscaler, unsigned int reg) ++{ ++ return readl(mscaler->iobase + reg); ++} ++ ++ ++/* isp video 回调函数,用æ¥å¯»æ‰¾å½“剿”¯æŒçš„输出视频格å¼ï¼Œç”±äºŽmscalerå¯ä»¥è¾“出,vic也å¯ä»¥è¾“出,所以这里设计æˆå›žè°ƒçš„æ–¹å¼.*/ ++ ++/** ++ * @brief ++ * ++ * @param pixelformat 如果pixelformatä¸ä¸ºç©ºï¼Œåˆ™ä½¿ç”¨pixelformat匹é…. ++ * @param mbus_code ++ * @param index ++ * ++ * @return ++ */ ++struct isp_video_format *mscaler_find_format(const u32 *pixelformat, const u32 *mbus_code, int index) ++{ ++ int i; ++ struct isp_video_format *fmt = NULL; ++ ++ for(i = 0; i < ARRAY_SIZE(mscaler_output_formats); i++) { ++ fmt = &mscaler_output_formats[i]; ++ ++ if(pixelformat && fmt->fourcc == *pixelformat) { ++ return fmt; ++ } ++ if(mbus_code && fmt->mbus_code == *mbus_code) { ++ return fmt; ++ } ++ ++ if(index == i) { ++ return fmt; ++ } ++ } ++ ++ return NULL; ++} ++ ++ ++/* In irq context. */ ++static int mscaler_irq_notify_ch_done(struct mscaler_device *mscaler, int ch) ++{ ++ struct isp_video_buffer *isp_buffer = NULL; ++ //unsigned int y_last_addr = 0; ++ //unsigned int uv_last_addr = 0; ++ unsigned int fifo_empty = 0; ++ unsigned int fifo_full = 0; ++ unsigned int y_fifo_st = 0, uv_fifo_st = 0; ++ dma_addr_t y_addr = 0; ++ dma_addr_t uv_addr = 0; ++ struct vb2_buffer *vb2_buf = NULL; ++ ++ spin_lock(&mscaler->lock); ++ /*由于mscaler stop streamæ—¶, ISP å¯èƒ½è¿˜ä¼šäº§ç”Ÿä¸­æ–­,这个时候ä¸ç”¨å¤„ç†*/ ++ if(mscaler->state[ch] == 0) { ++ spin_unlock(&mscaler->lock); ++ return 0; ++ } ++ ++ isp_buffer = list_first_entry_or_null(&mscaler->dma_queued_list[ch], struct isp_video_buffer, list_entry); ++ if(!isp_buffer) { ++ dev_err(mscaler->dev, "[warning] no isp_buffer found in dma_queued_list when interrupt happend!\n"); ++ spin_unlock(&mscaler->lock); ++ return 0; ++ } ++ ++ list_del(&isp_buffer->list_entry); ++ ++ ++// y_last_addr = mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_LAST_ADDR(ch)); ++ ++// uv_last_addr = mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_LAST_ADDR(ch)); ++ ++ /*TODO Sequence.*/ ++ //if(isp_buffer->vb2.vb2_buf.state == VB2_BUF_STATE_ACTIVE) ++ isp_buffer->vb2.vb2_buf.timestamp = ktime_get_ns(); ++ isp_buffer->vb2.sequence = mscaler->framenum[ch]++; ++ ++#ifdef CONFIG_MSCA_BDEV ++ /*如果åŽç«¯è®¾å¤‡å­˜åœ¨ï¼Œåˆ™è°ƒç”¨ms_bdev_qbuf,交给åŽç«¯å¤„ç†.*/ ++ if(mscaler->bdev[ch].activated) { ++ ms_bdev_qbuf(&mscaler->bdev[ch], isp_buffer); ++ } else { ++ vb2_buffer_done(&isp_buffer->vb2.vb2_buf, VB2_BUF_STATE_DONE); ++ } ++#else ++ vb2_buffer_done(&isp_buffer->vb2.vb2_buf, VB2_BUF_STATE_DONE); ++#endif ++ ++ y_fifo_st = mscaler_reg_readl(mscaler, CHx_Y_ADDR_FIFO_STA(ch)); ++ uv_fifo_st = mscaler_reg_readl(mscaler, CHx_UV_ADDR_FIFO_STA(ch)); ++ ++ if((y_fifo_st & (1<<0)) && (uv_fifo_st & (1<<0))) { ++ fifo_empty = 1; ++ } else if((y_fifo_st & (1<<4)) || (uv_fifo_st & (1<<4))) { ++ fifo_full = 1; ++ } ++ ++ /* 如果stream on了,就写入硬件.*/ ++ if(mscaler->state[ch] == 1 && !fifo_full) { ++ isp_buffer = list_first_entry_or_null(&mscaler->dma_pending_list[ch], struct isp_video_buffer, list_entry); ++ if(isp_buffer){ ++ vb2_buf = &isp_buffer->vb2.vb2_buf; ++ /*Y*/ ++ y_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 0); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_ADDR(ch), y_addr); ++ ++ uv_addr = y_addr + isp_buffer->uv_offset; ++ /*UV*/ ++ if(vb2_buf->num_planes == 2) { ++ uv_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 1); ++ } ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_ADDR(ch), uv_addr); ++ list_del(&isp_buffer->list_entry); ++ list_add_tail(&isp_buffer->list_entry, &mscaler->dma_queued_list[ch]); ++ } ++ } ++ ++ spin_unlock(&mscaler->lock); ++ ++ return 0; ++} ++ ++static int mscaler_interrupt_service_routine(struct v4l2_subdev *sd, ++ u32 status, bool *handled) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ int ret = 0; ++ ++ /*åªç®¡å¿ƒ mscaler的三个chçš„done中断和crop出错的中断.*/ ++ if(status & (1 << MSCA_CH0_FRM_DONE_INT)) { ++ ret = mscaler_irq_notify_ch_done(mscaler, 0); ++ } ++ if(status & (1 << MSCA_CH1_FRM_DONE_INT)) { ++ ret = mscaler_irq_notify_ch_done(mscaler, 1); ++ } ++ ++ if(status & (1 << MSCA_CH2_FRM_DONE_INT)) { ++ ret = mscaler_irq_notify_ch_done(mscaler, 2); ++ } ++ ++ /*TODO: add handler.*/ ++ ++ return ret; ++} ++ ++static int mscaler_subdev_init(struct v4l2_subdev *sd, u32 val) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ mscaler->sensor_id = val; ++ if(val == 0) ++ mscaler->iobase = (void __iomem *)0xb3316000; ++ else if(val == 1) ++ mscaler->iobase = (void __iomem *)0xb3317000; ++ return 0; ++} ++ ++static int mscaler_subdev_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ return 0; ++} ++ ++static const struct v4l2_subdev_core_ops mscaler_subdev_core_ops = { ++ .init = mscaler_subdev_init, ++ .reset = mscaler_subdev_reset, ++ .log_status = v4l2_ctrl_subdev_log_status, ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++ .interrupt_service_routine = mscaler_interrupt_service_routine, ++}; ++ ++static unsigned int ch_to_pad[] = { ++ MSCALER_PAD_SOURCE_CH0, ++ MSCALER_PAD_SOURCE_CH1, ++ MSCALER_PAD_SOURCE_CH2 ++}; ++ ++static int pad_to_ch(int pad) ++{ ++ switch(pad) { ++ case MSCALER_PAD_SOURCE_CH0: ++ return 0; ++ case MSCALER_PAD_SOURCE_CH1: ++ return 1; ++ case MSCALER_PAD_SOURCE_CH2: ++ return 2; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int mscaler_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ //printk("------%s, %d, sd->name: %s\n", __func__, __LINE__, sd->name); ++ ++ if(code->index >= ARRAY_SIZE(mscaler_output_formats)) { ++ dev_err(sd->dev, "too many mbus formats!\n"); ++ return -EINVAL; ++ } ++ ++ code->code = mscaler_output_formats[code->index].mbus_code; ++ ++ return 0; ++} ++static int mscaler_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int index = fse->index; ++ int num_valid = -1; ++ int i = 0; ++ if(index >= ARRAY_SIZE(ingenic_isp_framesizes)) ++ return -EINVAL; ++ ++ for(i = 0; i < ARRAY_SIZE(ingenic_isp_framesizes); i++) { ++ if(fse->code != ingenic_isp_framesizes[i].fourcc) ++ continue; ++ if(index == ++num_valid) { ++ fse->max_height = ingenic_isp_framesizes[i].discrete.height; ++ fse->min_height = fse->max_height; ++ fse->max_width = ingenic_isp_framesizes[i].discrete.width; ++ fse->min_width = fse->max_width; ++ return 0; ++ } ++ } ++ return -EINVAL; ++} ++ ++static int mscaler_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct v4l2_mbus_framefmt *framefmt = NULL; ++ //printk("------%s, %d, sd->name: %s\n", __func__, __LINE__, sd->name); ++ ++ if(format->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); ++ } else { ++ framefmt = &mscaler->formats[format->pad].format; ++ } ++ ++ format->format = *framefmt; ++ ++ return 0; ++} ++ ++static int mscaler_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct isp_video_device *ispvideo = v4l2_get_subdev_hostdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ struct v4l2_subdev_format remote_subdev_fmt = {0}; ++ int ch = 0; ++ int i = 0, ret = 0; ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ if(ispvideo == &mscaler->ispvideo[i]) { ++ ch = i; ++ break; ++ } ++ } ++ ++ //printk("%s, %d, width: %d, height: %d, mbus_code: %x\n", __func__, __LINE__, format->format.width, format->format.height, format->format.code); ++ ++ mscaler->formats[format->pad] = *format; ++ ++ remote = media_entity_remote_pad(&mscaler->pads[MSCALER_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ memcpy(&remote_subdev_fmt, format, sizeof(struct v4l2_subdev_format)); ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, set_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_dbg(mscaler->dev, "Failed to set_fmt from remote pad\n"); ++ } ++ ++ memset(&remote_subdev_fmt, 0, sizeof(struct v4l2_subdev_format)); ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_err(mscaler->dev, "Failed to get_fmt from remote pad\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(&mscaler->formats[MSCALER_PAD_SINK], &remote_subdev_fmt, sizeof(struct v4l2_subdev_format)); ++ ++ /*def crop info.*/ ++ mscaler->attr[ch].fcrop_en = 0; ++ mscaler->attr[ch].fcrop_x = 0; ++ mscaler->attr[ch].fcrop_y = 0; ++ mscaler->attr[ch].fcrop_width = mscaler->formats[MSCALER_PAD_SINK].format.width; ++ mscaler->attr[ch].fcrop_height = mscaler->formats[MSCALER_PAD_SINK].format.height; ++ mscaler->attr[ch].scaler_en = 0; ++ mscaler->attr[ch].scaler_width = mscaler->formats[format->pad].format.width; ++ mscaler->attr[ch].scaler_height = mscaler->formats[format->pad].format.height; ++ mscaler->attr[ch].crop_en = 0; ++ mscaler->attr[ch].crop_x = 0; ++ mscaler->attr[ch].crop_y = 0; ++ mscaler->attr[ch].crop_width = mscaler->formats[format->pad].format.width; ++ mscaler->attr[ch].crop_height = mscaler->formats[format->pad].format.height; ++ ++ return 0; ++} ++ ++static int mscaler_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct v4l2_subdev_format *output_fmt = NULL; ++ int ch = pad_to_ch(sel->pad); ++ ++ if(ch < 0) ++ return -EINVAL; ++ ++ output_fmt = &mscaler->formats[sel->pad]; ++ if(sel->target == V4L2_SEL_TGT_CROP || sel->target == V4L2_SEL_TGT_CROP_DEFAULT){ ++ sel->r.left = mscaler->attr[ch].crop_x; ++ sel->r.top = mscaler->attr[ch].crop_y; ++ sel->r.width = mscaler->attr[ch].crop_width; ++ sel->r.height = mscaler->attr[ch].crop_height; ++ } else if(sel->target == V4L2_SEL_TGT_CROP_BOUNDS) { ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = output_fmt->format.width; ++ sel->r.height = output_fmt->format.height; ++ } else { ++ dev_warn(mscaler->dev, "unsupported selection target!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int mscaler_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ int ch = pad_to_ch(sel->pad); ++ ++ if(ch < 0) ++ return -EINVAL; ++ ++ if(sel->flags == V4L2_SEL_FLAG_GE) { ++ dev_warn(mscaler->dev, "unsupported selection flags!\n"); ++ return -EINVAL; ++ } ++ ++ if(sel->target == V4L2_SEL_TGT_CROP){ ++ mscaler->attr[ch].crop_en = 1; ++ mscaler->attr[ch].crop_x = sel->r.left; ++ mscaler->attr[ch].crop_y = sel->r.top; ++ mscaler->attr[ch].crop_width = sel->r.width; ++ mscaler->attr[ch].crop_height = sel->r.height; ++ } else { ++ dev_warn(mscaler->dev, "unsupported selection target!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_pad_ops mscaler_subdev_pad_ops = { ++ .enum_mbus_code = mscaler_enum_mbus_code, ++ .enum_frame_size = mscaler_enum_frame_size, ++ .get_fmt = mscaler_get_fmt, ++ .set_fmt = mscaler_set_fmt, ++ .get_selection = mscaler_get_selection, ++ .set_selection = mscaler_set_selection, ++}; ++ ++static int mscaler_stream_enable(struct mscaler_device *mscaler, int ch) ++{ ++ struct v4l2_subdev_format *input_fmt = &mscaler->formats[MSCALER_PAD_SINK]; ++ struct v4l2_subdev_format *output_fmt = &mscaler->formats[ch_to_pad[ch]]; ++ unsigned long flags = 0; ++ int ret = 0; ++ struct isp_video_buffer *isp_buffer = NULL; ++ struct isp_video_buffer *tmp = NULL; ++ dma_addr_t y_addr = 0; ++ dma_addr_t uv_addr = 0; ++ unsigned int fifo_empty = 0; ++ unsigned int fifo_full = 0; ++ unsigned int y_fifo_st = 0, uv_fifo_st = 0; ++ struct vb2_buffer *vb2_buf = NULL; ++ tisp_channel_attr_t attr; ++ ++ dev_dbg(mscaler->dev, "-----input_fmt->format.width: %d, input_fmt->format.height: %d\n", input_fmt->format.width, input_fmt->format.height); ++ dev_dbg(mscaler->dev, "-----output_fmt->format.width: %d, output_fmt->format.height: %d\n", output_fmt->format.width, output_fmt->format.height); ++ ++ spin_lock_irqsave(&mscaler->lock, flags); ++ ++ memset(&attr, 0, sizeof(tisp_channel_attr_t)); ++ ++ /*TODO fcrop*/ ++ /*TODO output_fmt*/ ++ ++ if(mscaler->sensor_id == 0) ++ tisp_channel_main_attr_set(ch, &mscaler->attr[ch]); ++ else if(mscaler->sensor_id == 1) ++ tisp_channel_sec_attr_set(ch, &mscaler->attr[ch]); ++ mscaler->state[ch] = 1; ++ mscaler->framenum[ch] = 0; ++ ++ /*因为ISPå¤ä½çš„æ‰§è¡Œæ—¶é—´æ—¶åœ¨stream_on的时候,这个时候上层qbufå·²ç»è°ƒç”¨äº†ï¼Œ ++ * 如果部将这些buffer釿–°åŠ å…¥ç¡¬ä»¶é˜Ÿåˆ—ï¼Œåˆ™ä¼šå‡ºçŽ°é—®é¢˜.*/ ++ list_for_each_entry_safe(isp_buffer, tmp, &mscaler->dma_pending_list[ch], list_entry) { ++ y_fifo_st = mscaler_reg_readl(mscaler, CHx_Y_ADDR_FIFO_STA(ch)); ++ uv_fifo_st = mscaler_reg_readl(mscaler, CHx_UV_ADDR_FIFO_STA(ch)); ++ if((y_fifo_st & (1<<0)) && (uv_fifo_st & (1<<0))) { ++ fifo_empty = 1; ++ } else if((y_fifo_st & (1<<4)) || (uv_fifo_st & (1<<4))) { ++ fifo_full = 1; ++ } ++ if(fifo_full) ++ break; ++ ++ vb2_buf = &isp_buffer->vb2.vb2_buf; ++ /*Y*/ ++ y_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 0); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_ADDR(ch), y_addr); ++ ++ uv_addr = y_addr + isp_buffer->uv_offset; ++ if(vb2_buf->num_planes == 2) { ++ uv_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 1); ++ } ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_ADDR(ch), uv_addr); ++ list_del(&isp_buffer->list_entry); ++ list_add_tail(&isp_buffer->list_entry, &mscaler->dma_queued_list[ch]); ++ } ++ if(mscaler->sensor_id == 0) ++ tisp_channel_main_start(ch); ++ else if(mscaler->sensor_id == 1) ++ tisp_channel_sec_start(ch); ++ ++ spin_unlock_irqrestore(&mscaler->lock, flags); ++ ++#ifdef CONFIG_MSCA_BDEV ++ if(mscaler->bdev[ch].activated == 1) { ++ ret = ms_bdev_init(&mscaler->bdev[ch]); ++ if(ret < 0) { ++ return -EINVAL; ++ } ++ } ++#endif ++ ++ return ret; ++} ++ ++static int mscaler_stream_disable(struct mscaler_device *mscaler, int ch) ++{ ++ unsigned long flags = 0; ++ int ret = 0; ++ unsigned int timeout = 0xffffff; ++ struct isp_video_buffer *isp_buffer = NULL; ++ struct isp_video_buffer *tmp = NULL; ++ ++ ++ spin_lock_irqsave(&mscaler->lock, flags); ++ ++ if(mscaler->sensor_id == 0) ++ tisp_channel_main_stop(ch); ++ else ++ tisp_channel_sec_stop(ch); ++ ++ spin_unlock_irqrestore(&mscaler->lock, flags); ++ ++ /* polling status to make sure channel stopped.*/ ++ /* ++ do { ++ val = mscaler_reg_readl(mscaler, MSCA_CH_STA); ++ ++ } while(!!((val & (1<dev, "[Warning] mscaler disable timeout!\n"); ++ } ++ ++ spin_lock_irqsave(&mscaler->lock, flags); ++ ++ /* clear fifo*/ ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_ADDR_CLR(ch), 1); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_ADDR_CLR(ch), 1); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_LAST_ADDR_CLR(ch), 1); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_LAST_ADDR_CLR(ch), 1); ++ ++ ++ list_for_each_entry_safe(isp_buffer, tmp, &mscaler->dma_queued_list[ch], list_entry) { ++ struct vb2_buffer *vb2_buf = &isp_buffer->vb2.vb2_buf; ++ vb2_buffer_done(vb2_buf, VB2_BUF_STATE_ERROR); ++ list_del(&isp_buffer->list_entry); ++ } ++ list_for_each_entry_safe(isp_buffer, tmp, &mscaler->dma_pending_list[ch], list_entry) { ++ struct vb2_buffer *vb2_buf = &isp_buffer->vb2.vb2_buf; ++ vb2_buffer_done(vb2_buf, VB2_BUF_STATE_ERROR); ++ list_del(&isp_buffer->list_entry); ++ } ++ ++ mscaler->state[ch] = 0; ++ spin_unlock_irqrestore(&mscaler->lock, flags); ++ ++#ifdef CONFIG_MSCA_BDEV ++ if(mscaler->bdev[ch].activated) { ++ ms_bdev_deinit(&mscaler->bdev[ch]); ++ mscaler->bdev[ch].activated = 0; ++ } ++#endif ++ ++ return ret; ++} ++ ++static int mscaler_subdev_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct isp_video_device *ispvideo = v4l2_get_subdev_hostdata(sd); ++ int ch = 0; ++ int i = 0, ret = 0; ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ if(ispvideo == &mscaler->ispvideo[i]) { ++ ch = i; ++ break; ++ } ++ } ++ ++// printk("%s,%d, sd->video_device->name:%s, ispvideo: %p, ch = %d, enable = %d\n", __func__, __LINE__, sd->devnode->name, ispvideo, ch, enable); ++ /*获å–当å‰channel.*/ ++ if(enable) { ++ ret = mscaler_stream_enable(mscaler, ch); ++ //dump_mscaler_regs(mscaler); ++ } else { ++ ret = mscaler_stream_disable(mscaler, ch); ++ } ++ ++ if(ret < 0) { ++ dev_err(mscaler->dev, "enable stream error!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int mscaler_subdev_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *cc) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct isp_video_device *ispvideo = v4l2_get_subdev_hostdata(sd); ++ struct v4l2_subdev_format *input_fmt = NULL; ++ int ch = 0; ++ int i = 0, ret = 0; ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ if(ispvideo == &mscaler->ispvideo[i]) { ++ ch = i; ++ break; ++ } ++ } ++ ++ input_fmt = &mscaler->formats[MSCALER_PAD_SINK]; ++ ++ cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ cc->bounds.left = 0; ++ cc->bounds.top = 0; ++ cc->bounds.width = input_fmt->format.width; ++ cc->bounds.height = input_fmt->format.height; ++ cc->defrect.left = 0; ++ cc->defrect.top = 0; ++ cc->defrect.width = input_fmt->format.width; ++ cc->defrect.height = input_fmt->format.height; ++ cc->pixelaspect.numerator = input_fmt->format.height; ++ cc->pixelaspect.denominator = input_fmt->format.width; ++ ++ return ret; ++} ++ ++static int mscaler_subdev_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct isp_video_device *ispvideo = v4l2_get_subdev_hostdata(sd); ++ int ch = 0; ++ int i = 0, ret = 0; ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ if(ispvideo == &mscaler->ispvideo[i]) { ++ ch = i; ++ break; ++ } ++ } ++ ++ crop->c.top = mscaler->attr[ch].fcrop_y; ++ crop->c.left = mscaler->attr[ch].fcrop_x; ++ crop->c.width = mscaler->attr[ch].fcrop_width; ++ crop->c.height = mscaler->attr[ch].fcrop_height; ++ ++ return ret; ++} ++ ++static int mscaler_subdev_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *crop) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct isp_video_device *ispvideo = v4l2_get_subdev_hostdata(sd); ++ int ch = 0; ++ int i = 0, ret = 0; ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ if(ispvideo == &mscaler->ispvideo[i]) { ++ ch = i; ++ break; ++ } ++ } ++ ++ mscaler->attr[ch].fcrop_en = 1; ++ mscaler->attr[ch].fcrop_y = crop->c.top; ++ mscaler->attr[ch].fcrop_x = crop->c.left; ++ mscaler->attr[ch].fcrop_width = crop->c.width; ++ mscaler->attr[ch].fcrop_height = crop->c.height; ++ ++ return ret; ++} ++ ++ ++static const struct v4l2_subdev_video_ops mscaler_subdev_video_ops = { ++ .s_stream = mscaler_subdev_s_stream, ++ .cropcap = mscaler_subdev_cropcap, ++ .g_crop = mscaler_subdev_g_crop, ++ .s_crop = mscaler_subdev_s_crop, ++}; ++ ++ ++static const struct v4l2_subdev_ops mscaler_subdev_ops = { ++ .core = &mscaler_subdev_core_ops, ++ .pad = &mscaler_subdev_pad_ops, ++ .video = &mscaler_subdev_video_ops, ++}; ++ ++ ++static int mscaler_video_qbuf(struct isp_video_device *ispvideo, struct isp_video_buffer *isp_buffer) ++{ ++ struct mscaler_device *mscaler = ispvideo->ispcam->mscaler; ++ struct vb2_buffer *vb2_buf = NULL; ++ int ch = 0; ++ unsigned long flags = 0; ++ unsigned int fifo_empty = 0; ++ unsigned int fifo_full = 0; ++ unsigned int y_fifo_st = 0, uv_fifo_st = 0; ++ dma_addr_t y_addr = 0; ++ dma_addr_t uv_addr = 0; ++ ++ int i = 0; ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ if(ispvideo == &mscaler->ispvideo[i]) { ++ ch = i; ++ break; ++ } ++ } ++ ++ spin_lock_irqsave(&mscaler->lock, flags); ++ ++ list_add_tail(&isp_buffer->list_entry, &mscaler->dma_pending_list[ch]); ++ ++ if(mscaler->iobase){ ++ y_fifo_st = mscaler_reg_readl(mscaler, CHx_Y_ADDR_FIFO_STA(ch)); ++ uv_fifo_st = mscaler_reg_readl(mscaler, CHx_UV_ADDR_FIFO_STA(ch)); ++ ++ if((y_fifo_st & (1<<0)) && (uv_fifo_st & (1<<0))) { ++ fifo_empty = 1; ++ } else if((y_fifo_st & (1<<4)) || (uv_fifo_st & (1<<4))) { ++ fifo_full = 1; ++ } ++ ++ if(mscaler->state[ch] == 1 && !fifo_full) { ++ isp_buffer = list_first_entry_or_null(&mscaler->dma_pending_list[ch], struct isp_video_buffer, list_entry); ++ if(isp_buffer){ ++ vb2_buf = &isp_buffer->vb2.vb2_buf; ++ /*Y*/ ++ y_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 0); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_ADDR(ch), y_addr); ++ ++ uv_addr = y_addr + isp_buffer->uv_offset; ++ /*UV*/ ++ if(vb2_buf->num_planes == 2) { ++ uv_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 1); ++ } ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_ADDR(ch), uv_addr); ++ list_del(&isp_buffer->list_entry); ++ list_add_tail(&isp_buffer->list_entry, &mscaler->dma_queued_list[ch]); ++ } ++ } ++ } ++ ++ spin_unlock_irqrestore(&mscaler->lock, flags); ++ ++ //printk("-----%s,%d queued buffer y_addr: 0x%08x, uv: 0x%08x on ch: %d\n", __func__, __LINE__, y_addr, uv_addr, ch); ++ ++ return 0; ++} ++ ++static const struct isp_video_ops mscaler_video_ops = { ++ .find_format = mscaler_find_format, ++ .qbuf = mscaler_video_qbuf, ++}; ++ ++static ssize_t ++dump_mscaler(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = dev_get_drvdata(dev); ++ char *p = buf; ++ int i = 0; ++ ++ p += sprintf(p, "MSCA_CH_EN :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_CH_EN)); ++ p += sprintf(p, "MSCA_INT_STA :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_INT_STA)); ++ p += sprintf(p, "MSCA_INT_MSK :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_INT_MSK)); ++ p += sprintf(p, "MSCA_MASK_EN :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_MASK_EN)); ++ p += sprintf(p, "MSCA_DMAOUT_ARB:0x%08x\n", mscaler_reg_readl(mscaler, MSCA_DMAOUT_ARB)); ++ p += sprintf(p, "MSCA_CLK_GATE_EN:0x%08x\n", mscaler_reg_readl(mscaler, MSCA_CLK_GATE_EN)); ++ p += sprintf(p, "MSCA_CLK_DIS :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_CLK_DIS)); ++ p += sprintf(p, "MSCA_SRC_IN :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_SRC_IN)); ++ p += sprintf(p, "MSCA_SRC_SIZE :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_SRC_SIZE)); ++ p += sprintf(p, "MSCA_GLO_RSZ_COEF_WR:0x%08x\n", mscaler_reg_readl(mscaler, MSCA_GLO_RSZ_COEF_WR)); ++ p += sprintf(p, "MSCA_SYS_PRO_CLK_EN :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_SYS_PRO_CLK_EN)); ++ p += sprintf(p, "MSCA_DS0_CLK_NUM :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_DS0_CLK_NUM)); ++ p += sprintf(p, "MSCA_DS1_CLK_NUM :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_DS1_CLK_NUM)); ++ p += sprintf(p, "MSCA_DS2_CLK_NUM :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_DS2_CLK_NUM)); ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ ++ p += sprintf(p, "CHx_RSZ_OSIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_RSZ_OSIZE(i))); ++ p += sprintf(p, "CHx_RSZ_STEP(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_RSZ_STEP(i))); ++ p += sprintf(p, "CHx_CROP_OPOS(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_CROP_OPOS(i))); ++ p += sprintf(p, "CHx_CROP_OSIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_CROP_OSIZE(i))); ++ p += sprintf(p, "CHx_FRA_CTRL_LOOP(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_FRA_CTRL_LOOP(i))); ++ p += sprintf(p, "CHx_FRA_CTRL_MASK(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_FRA_CTRL_MASK(i))); ++ p += sprintf(p, "CHx_MS0_POS(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS0_POS(i))); ++ p += sprintf(p, "CHx_MS0_SIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS0_SIZE(i))); ++ p += sprintf(p, "CHx_MS0_VALUE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS0_VALUE(i))); ++ p += sprintf(p, "CHx_MS1_POS(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS1_POS(i))); ++ p += sprintf(p, "CHx_MS1_SIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS1_SIZE(i))); ++ p += sprintf(p, "CHx_MS1_VALUE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS1_VALUE(i))); ++ p += sprintf(p, "CHx_MS2_POS(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS2_POS(i))); ++ p += sprintf(p, "CHx_MS2_SIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS2_SIZE(i))); ++ p += sprintf(p, "CHx_MS2_VALUE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS2_VALUE(i))); ++ p += sprintf(p, "CHx_MS3_POS(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS3_POS(i))); ++ p += sprintf(p, "CHx_MS3_SIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS3_SIZE(i))); ++ p += sprintf(p, "CHx_MS3_VALUE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS3_VALUE(i))); ++ p += sprintf(p, "CHx_OUT_FMT(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_OUT_FMT(i))); ++ p += sprintf(p, "CHx_DMAOUT_Y_ADDR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_ADDR(i))); ++ p += sprintf(p, "CHx_Y_ADDR_FIFO_STA(%d):0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_Y_ADDR_FIFO_STA(i))); ++ // p += sprintf(p, "CHx_DMAOUT_Y_LAST_ADDR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_LAST_ADDR(i))); ++ // p += sprintf(p, "CHx_DMAOUT_Y_LAST_STATS_NUM(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_LAST_STATS_NUM(i))); ++ p += sprintf(p, "CHx_Y_LAST_ADDR_FIFO_STA(%d):0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_Y_LAST_ADDR_FIFO_STA(i))); ++ p += sprintf(p, "CHx_DMAOUT_Y_STRI(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_STRI(i))); ++ p += sprintf(p, "CHx_DMAOUT_UV_ADDR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_ADDR(i))); ++ p += sprintf(p, "CHx_UV_ADDR_FIFO_STA(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_UV_ADDR_FIFO_STA(i))); ++ // p += sprintf(p, "CHx_DMAOUT_UV_LAST_ADDR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_LAST_ADDR(i))); ++ // p += sprintf(p, "CHx_DMAOUT_UV_LAST_STATS_NUM(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_LAST_STATS_NUM(i))); ++ p += sprintf(p, "CHx_UV_LAST_ADDR_FIFO_STA(%d):0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_UV_LAST_ADDR_FIFO_STA(i))); ++ p += sprintf(p, "CHx_DMAOUT_UV_STRI(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_STRI(i))); ++ p += sprintf(p, "CHx_DMAOUT_Y_ADDR_CLR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_ADDR_CLR(i))); ++ p += sprintf(p, "CHx_DMAOUT_UV_ADDR_CLR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_ADDR_CLR(i))); ++ p += sprintf(p, "CHx_DMAOUT_Y_LAST_ADDR_CLR(%d):0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_LAST_ADDR_CLR(i))); ++ p += sprintf(p, "CHx_DMAOUT_UV_LAST_ADDR_CLR(%d):0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_LAST_ADDR_CLR(i))); ++ p += sprintf(p, "CHx_DMAOUT_Y_ADDR_SEL(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_ADDR_SEL(i))); ++ p += sprintf(p, "CHx_DMAOUT_UV_ADDR_SEL(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_ADDR_SEL(i))); ++ } ++ ++ return p - buf; ++} ++ ++ ++static DEVICE_ATTR(dump_mscaler, S_IRUGO|S_IWUSR, dump_mscaler, NULL); ++ ++static struct attribute *mscaler_debug_attrs[] = { ++ &dev_attr_dump_mscaler.attr, ++ NULL, ++}; ++ ++static struct attribute_group mscaler_debug_attr_group = { ++ .name = "debug", ++ .attrs = mscaler_debug_attrs, ++}; ++ ++ ++#define to_mscaler_device(kobj) dev_get_drvdata(container_of(kobj->parent->parent, struct device, kobj)) ++ ++static ssize_t mask_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch = kobj->name[2] - '0'; ++ char *p = buf; ++ unsigned int tmp = 0; ++ ++ tmp = mscaler_reg_readl(mscaler, MSCA_MASK_EN); ++ p += sprintf(p, "%d\n", (tmp >> ch) & 1); ++ ++ return p - buf; ++} ++ ++static ssize_t mask_enable_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch = kobj->name[2] - '0'; ++ unsigned int tmp = 0; ++ int enable = simple_strtol(buf, NULL, 10); ++ ++ tmp = mscaler_reg_readl(mscaler, MSCA_MASK_EN); ++ if(enable == 1) ++ tmp |= 1 << ch; ++ else if(enable == 0) ++ tmp &= ~(1 << ch); ++ else ++ return -EINVAL; ++ ++ mscaler_reg_writel(mscaler, MSCA_MASK_EN, tmp); ++ return count; ++} ++ ++static struct kobj_attribute enable_attribute = ++__ATTR(enable,S_IRUGO|S_IWUSR, mask_enable_show, mask_enable_store); ++ ++ ++static ssize_t mask_pos_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p = buf; ++ unsigned int tmp = 0; ++ ++ tmp = mscaler_reg_readl(mscaler, CHx_MSx_POS(ch,mask)); ++ p += sprintf(p, "x:%d\ty:%d\n", tmp >> 16, tmp & 0xffff); ++ ++ return p - buf; ++} ++ ++static ssize_t mask_pos_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p; ++ char *s = (char *)buf; ++ int pos_x, pos_y; ++ ++ p = strsep(&s, "*"); ++ if(!s) { ++ return -EINVAL; ++ } ++ ++ pos_x = simple_strtoul(p, NULL, 10); ++ pos_y = simple_strtoul(s, NULL, 10); ++ ++ mscaler_reg_writel(mscaler, CHx_MSx_POS(ch,mask), (pos_x << 16) | pos_y); ++ return count; ++} ++ ++static ssize_t mask_size_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p = buf; ++ unsigned int tmp = 0; ++ ++ tmp = mscaler_reg_readl(mscaler, CHx_MSx_SIZE(ch,mask)); ++ p += sprintf(p, "width:%d\theight:%d\n", tmp >> 16, tmp & 0xffff); ++ ++ return p - buf; ++} ++ ++static ssize_t mask_size_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p; ++ char *s = (char *)buf; ++ int width, height; ++ ++ p = strsep(&s, "*"); ++ if(!s) { ++ return -EINVAL; ++ } ++ ++ width = simple_strtoul(p, NULL, 10); ++ height = simple_strtoul(s, NULL, 10); ++ ++ mscaler_reg_writel(mscaler, CHx_MSx_SIZE(ch,mask), (width << 16) | height); ++ return count; ++} ++static ssize_t mask_color_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p = buf; ++ unsigned int tmp = 0; ++ ++ tmp = mscaler_reg_readl(mscaler, CHx_MSx_VALUE(ch,mask)); ++ p += sprintf(p, "0x%08x\n", tmp); ++ ++ return p - buf; ++} ++ ++static ssize_t mask_color_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p; ++ char *s = (char *)buf; ++ int value = 0; ++ ++ p = strsep(&s, "x"); ++ if(!s) { ++ return -EINVAL; ++ } ++ ++ value = simple_strtoul(s, NULL, 16); ++ ++ mscaler_reg_writel(mscaler, CHx_MSx_VALUE(ch,mask), value); ++ return count; ++} ++ ++#define MASK_ATTR(mask, _name, _mode, _show, _store) \ ++{ \ ++ .attr = __ATTR(_name, _mode, _show, _store), \ ++ .id = mask, \ ++} ++ ++ ++#define MASK_ATTRIBUTE(_name, _mode, _show, _store) \ ++ static struct mask_kobj_attr kobj_attr_##_name##mask0 = MASK_ATTR(0, _name, _mode, _show, _store); \ ++ static struct mask_kobj_attr kobj_attr_##_name##mask1 = MASK_ATTR(1, _name, _mode, _show, _store); \ ++ static struct mask_kobj_attr kobj_attr_##_name##mask2 = MASK_ATTR(2, _name, _mode, _show, _store); \ ++ static struct mask_kobj_attr kobj_attr_##_name##mask3 = MASK_ATTR(3, _name, _mode, _show, _store) ++ ++MASK_ATTRIBUTE(pos, S_IRUGO|S_IWUSR, mask_pos_show, mask_pos_store); ++MASK_ATTRIBUTE(size, S_IRUGO|S_IWUSR, mask_size_show, mask_size_store); ++MASK_ATTRIBUTE(color, S_IRUGO|S_IWUSR, mask_color_show, mask_color_store); ++ ++#define MASK_ATTRIBUTE_GROUP(name) \ ++ static struct attribute *mscaler_##name##_attrs[] = { \ ++ &kobj_attr_pos##name.attr.attr, \ ++ &kobj_attr_size##name.attr.attr, \ ++ &kobj_attr_color##name.attr.attr, \ ++ NULL, \ ++ }; ++ ++MASK_ATTRIBUTE_GROUP(mask0); ++MASK_ATTRIBUTE_GROUP(mask1); ++MASK_ATTRIBUTE_GROUP(mask2); ++MASK_ATTRIBUTE_GROUP(mask3); ++ ++ ++static struct attribute_group mscaler_mask0_group = { ++ .name = "mask0", ++ .attrs = mscaler_mask0_attrs, ++}; ++static struct attribute_group mscaler_mask1_group = { ++ .name = "mask1", ++ .attrs = mscaler_mask1_attrs, ++}; ++static struct attribute_group mscaler_mask2_group = { ++ .name = "mask2", ++ .attrs = mscaler_mask2_attrs, ++}; ++static struct attribute_group mscaler_mask3_group = { ++ .name = "mask3", ++ .attrs = mscaler_mask3_attrs, ++}; ++ ++ ++static const struct attribute_group *mscaler_maskx_groups[] = { ++ &mscaler_mask0_group, ++ &mscaler_mask1_group, ++ &mscaler_mask2_group, ++ &mscaler_mask3_group, ++ NULL, ++}; ++ ++static void __maybe_unused dump_mscaler_regs(struct mscaler_device *mscaler) ++{ ++ char *buf = kzalloc(4 * 1024, GFP_KERNEL); ++ int ret = 0; ++ ++ ret = dump_mscaler(mscaler->dev, NULL, buf); ++ ++ printk("%s", buf); ++ ++ kfree(buf); ++} ++ ++int mscaler_video_nr_map[2][3] = { ++ {INGENIC_MSCA0_CH0_VIDEO_NR , INGENIC_MSCA0_CH1_VIDEO_NR , INGENIC_MSCA0_CH2_VIDEO_NR}, ++ {INGENIC_MSCA1_CH0_VIDEO_NR , INGENIC_MSCA1_CH1_VIDEO_NR , INGENIC_MSCA1_CH2_VIDEO_NR}, ++ ++}; ++ ++static int mscaler_comp_bind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct mscaler_device *mscaler = dev_get_drvdata(comp); ++ struct ispcam_device *ispcam = (struct ispcam_device *)master_data; ++ struct v4l2_device *v4l2_dev = &ispcam->v4l2_dev; ++ struct v4l2_subdev *sd = &mscaler->sd; ++ int i = 0; ++ int ret = 0; ++ int nr = -1; ++ ++ //dev_info(comp, "----dev_name(comp): %s----%s, %d \n", dev_name(comp), __func__, __LINE__); ++ ++ /* link subdev to master.*/ ++ mscaler->ispcam = (void *)ispcam; ++ ispcam->mscaler = mscaler; ++ ++ /*1. register supported subdev ctrls.*/ ++ ++ ++ /*2. init v4l2_subdev*/ ++ ++ v4l2_subdev_init(sd, &mscaler_subdev_ops); ++ ++ sd->owner = THIS_MODULE; ++ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ strscpy(sd->name, dev_name(comp), sizeof(sd->name)); ++ v4l2_set_subdevdata(sd, mscaler); ++ ++ ++ /* init mscaler pads. */ ++ mscaler->pads = kzalloc(sizeof(struct media_pad) * MSCALER_NUM_PADS, GFP_KERNEL); ++ if(!mscaler->pads) { ++ ret = -ENOMEM; ++ goto err_alloc_pads; ++ } ++ mscaler->pads[0].index = MSCALER_PAD_SINK; ++ mscaler->pads[0].flags = MEDIA_PAD_FL_SINK; ++ mscaler->pads[1].index = MSCALER_PAD_SOURCE_CH0; ++ mscaler->pads[1].flags = MEDIA_PAD_FL_SOURCE; ++ mscaler->pads[2].index = MSCALER_PAD_SOURCE_CH1; ++ mscaler->pads[2].flags = MEDIA_PAD_FL_SOURCE; ++ mscaler->pads[3].index = MSCALER_PAD_SOURCE_CH2; ++ mscaler->pads[3].flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&sd->entity, MSCALER_NUM_PADS, mscaler->pads); ++ ++ /*3. register v4l2_subdev*/ ++ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; ++ ret = v4l2_device_register_subdev(v4l2_dev, sd); ++ if(ret < 0) { ++ dev_err(comp, "Failed to register v4l2_subdev for mscaler\n"); ++ goto err_subdev_register; ++ } ++ ++ /*create mask dir*/ ++ mscaler->mask_kobj = kobject_create_and_add("mask", &mscaler->dev->kobj); ++ if (!mscaler->mask_kobj) { ++ dev_err(mscaler->dev, "device create kobject failed\n"); ++ ret = -EINVAL; ++ goto err_mask_kobj; ++ } ++ ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ struct isp_video_device *ispvideo = &mscaler->ispvideo[i]; ++ char name[32]; ++ sprintf(name, "%s-ch%d", dev_name(mscaler->dev), i); ++ ++ ispvideo->ispcam = ispcam; ++ ret = isp_video_init(ispvideo, name, &mscaler_video_ops); ++ if(ret < 0){ ++ /*TODO*/ ++ } ++ ++ nr = mscaler_video_nr_map[ispcam->dev_nr][i]; ++ ret = isp_video_register(ispvideo, &ispcam->v4l2_dev, nr); ++ if(ret < 0){ ++ /*TODO*/ ++ } ++ ++ /*create mask/chx dir*/ ++ sprintf(name, "ch%d", i); ++ mscaler->mask_ch_kobj[i] = kobject_create_and_add(name, mscaler->mask_kobj); ++ if (!mscaler->mask_ch_kobj[i]) { ++ dev_err(mscaler->dev, "device create kobject failed\n"); ++ ret = -EINVAL; ++ goto err_mask_ch_kobj; ++ } ++ ++ /*create enable attr*/ ++ ret = sysfs_create_file(mscaler->mask_ch_kobj[i], &enable_attribute.attr); ++ if(ret){ ++ dev_err(mscaler->dev, "device create sys file failed\n"); ++ goto err_mask_create_file; ++ } ++ ++ /*create mask/chx/maskx dir*/ ++ ret = sysfs_create_groups(mscaler->mask_ch_kobj[i], mscaler_maskx_groups); ++ if(ret){ ++ dev_err(mscaler->dev, "device create sys groups failed\n"); ++ goto err_mask_create_groups; ++ } ++ ++ } ++ return 0; ++err_mask_create_groups: ++err_mask_create_file: ++err_mask_ch_kobj: ++err_mask_kobj: ++err_subdev_register: ++err_alloc_pads: ++ return ret; ++} ++ ++ ++static void mscaler_comp_unbind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct mscaler_device *mscaler = dev_get_drvdata(comp); ++ ++ dev_info(comp, "----TODO: %p----%s, %d \n", mscaler, __func__, __LINE__); ++ ++} ++ ++static const struct component_ops mscaler_comp_ops = { ++ .bind = mscaler_comp_bind, ++ .unbind = mscaler_comp_unbind, ++}; ++ ++ ++ ++ ++static int ingenic_mscaler_probe(struct platform_device *pdev) ++{ ++ ++ struct mscaler_device *mscaler = NULL; ++ int ret = 0; ++ int i = 0; ++ ++ mscaler = kzalloc(sizeof(struct mscaler_device), GFP_KERNEL); ++ if(!mscaler) { ++ pr_err("Failed to alloc mscaler dev [%s]\n", pdev->name); ++ return -ENOMEM; ++ } ++ ++ mscaler->dev = &pdev->dev; ++ platform_set_drvdata(pdev, mscaler); ++ ++ spin_lock_init(&mscaler->lock); ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ INIT_LIST_HEAD(&mscaler->dma_queued_list[i]); ++ INIT_LIST_HEAD(&mscaler->dma_pending_list[i]); ++ } ++ ++ ret = sysfs_create_group(&mscaler->dev->kobj, &mscaler_debug_attr_group); ++ if (ret) { ++ dev_err(mscaler->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_sys_group; ++ } ++ ++ ++ ret = component_add(mscaler->dev, &mscaler_comp_ops); ++ if(ret < 0) { ++ dev_err(mscaler->dev, "Failed to add component mscaler!\n"); ++ } ++ ++ return 0; ++err_sys_group: ++ return ret; ++} ++ ++ ++ ++static int ingenic_mscaler_remove(struct platform_device *pdev) ++{ ++ ++ return 0; ++} ++ ++ ++ ++static const struct of_device_id ingenic_mscaler_dt_match[] = { ++ { .compatible = "ingenic,x2500-mscaler" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_mscaler_dt_match); ++ ++static int __maybe_unused ingenic_mscaler_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ return 0; ++} ++ ++static int __maybe_unused ingenic_mscaler_resume(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver ingenic_mscaler_driver = { ++ .probe = ingenic_mscaler_probe, ++ .remove = ingenic_mscaler_remove, ++ .suspend = ingenic_mscaler_suspend, ++ .resume = ingenic_mscaler_resume, ++ .driver = { ++ .name = "ingenic-mscaler", ++ .of_match_table = ingenic_mscaler_dt_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_mscaler_driver); ++ ++MODULE_ALIAS("platform:ingenic-mscaler"); ++MODULE_DESCRIPTION("ingenic mscaler subsystem"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/sensor.c b/module_drivers/drivers/media/platform/ingenic-isp-v2/sensor.c +new file mode 100644 +index 000000000..e04dfe508 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/sensor.c +@@ -0,0 +1,463 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++ ++#define to_sensor_device(isp) &isp->ispcam->sensor ++ ++extern unsigned int MAIN_ISP_INDEX; ++extern unsigned int SEC_ISP_INDEX; ++ ++extern struct isp_device *g_isp_device[2]; ++struct isp_device *index_to_isp_device(int isp_index) ++{ ++ if(isp_index == 0) ++ return g_isp_device[0]; ++ else if(isp_index == 1) ++ return g_isp_device[1]; ++ else{ ++ printk("unsupported isp index!\n"); ++ return NULL; ++ } ++} ++ ++static void sensor_hw_reset_enable(void) ++{ ++// printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static void sensor_hw_reset_disable(void) ++{ ++// printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static int32_t sensor_alloc_analog_gain(int32_t gain, sensor_context_t *p_ctx) ++{ ++ /* printk("result gain is 0x%x\n",again); */ ++ return gain; ++} ++ ++static int32_t sensor_alloc_analog_gain_short(int32_t gain, sensor_context_t *p_ctx) ++{ ++ /* printk("result gain is 0x%x\n",again); */ ++ return gain; ++} ++ ++static int32_t sensor_alloc_digital_gain(int32_t gain, sensor_context_t *p_ctx) ++{ ++// printk("----%s, %d, gain: %d\n", __func__, __LINE__, gain); ++ ++ /* printk("result gain is 0x%x\n",p_ctx->dgain); */ ++ return gain; ++} ++ ++static uint32_t sensor_alloc_integration_time(uint32_t int_time, sensor_context_t *p_ctx) ++{ ++ p_ctx->it = int_time; ++ return int_time; ++} ++ ++static uint32_t sensor_alloc_integration_time_short(uint32_t int_time, sensor_context_t *p_ctx) ++{ ++ p_ctx->it_short = int_time; ++ return int_time; ++} ++ ++static void sensor_set_integration_time(uint16_t int_time, sensor_param_t* param) ++{ ++ int isp_index = -1; ++ struct isp_device *isp = NULL; ++ struct sensor_device *sensor = NULL; ++ struct v4l2_control exposure; ++ int ret = 0; ++ ++ if(param->sensor_ctx.sensor_id == 0) ++ isp_index = MAIN_ISP_INDEX; ++ else if(param->sensor_ctx.sensor_id == 1) ++ isp_index = SEC_ISP_INDEX; ++ isp = index_to_isp_device(isp_index); ++ sensor = to_sensor_device(isp); ++ ++ exposure.id = V4L2_CID_EXPOSURE; ++ exposure.value = int_time; ++ ++ ret = v4l2_s_ctrl(NULL, sensor->isd->sd->ctrl_handler, &exposure); ++ if(ret < 0) { ++ dev_err(isp->dev, "failed to set exposure!\n"); ++ } ++} ++ ++static void sensor_set_integration_time_short(uint16_t int_time, sensor_param_t* param) ++{ ++ int isp_index = -1; ++ struct isp_device *isp = NULL; ++ struct sensor_device *sensor = NULL; ++ struct v4l2_control exposure; ++ int ret = 0; ++ ++ if(param->sensor_ctx.sensor_id == 0) ++ isp_index = MAIN_ISP_INDEX; ++ else if(param->sensor_ctx.sensor_id == 1) ++ isp_index = SEC_ISP_INDEX; ++ isp = index_to_isp_device(isp_index); ++ sensor = to_sensor_device(isp); ++ ++ exposure.id = V4L2_CID_USER_EXPOSURE_SHORT; ++ exposure.value = int_time; ++ ++ ret = v4l2_s_ctrl(NULL, sensor->isd->sd->ctrl_handler, &exposure); ++ if(ret < 0) { ++ dev_err(isp->dev, "failed to set exposure!\n"); ++ } ++} ++ ++static void sensor_set_analog_gain(uint32_t again_reg_val, sensor_context_t *p_ctx) ++{ ++ int isp_index = -1; ++ struct isp_device *isp = NULL; ++ struct sensor_device *sensor = NULL; ++ struct v4l2_control analog; ++ int ret = 0; ++ ++ if(p_ctx->sensor_id == 0) ++ isp_index = MAIN_ISP_INDEX; ++ else if(p_ctx->sensor_id == 1) ++ isp_index = SEC_ISP_INDEX; ++ isp = index_to_isp_device(isp_index); ++ sensor = to_sensor_device(isp); ++ ++ analog.id = V4L2_CID_ANALOGUE_GAIN; ++ analog.value = again_reg_val; ++ ++ ret = v4l2_s_ctrl(NULL, sensor->isd->sd->ctrl_handler, &analog); ++ if(ret < 0) { ++ printk("error s_ctrl, ret: %d\n", ret); ++ } ++} ++ ++static void sensor_get_analog_gain(uint32_t *again_reg_val, sensor_context_t *p_ctx) ++{ ++ int isp_index = -1; ++ struct isp_device *isp = NULL; ++ struct sensor_device *sensor = NULL; ++ struct v4l2_control analog; ++ int ret = 0; ++ ++ if(p_ctx->sensor_id == 0) ++ isp_index = MAIN_ISP_INDEX; ++ else if(p_ctx->sensor_id == 1) ++ isp_index = SEC_ISP_INDEX; ++ isp = index_to_isp_device(isp_index); ++ sensor = to_sensor_device(isp); ++ ++ analog.id = V4L2_CID_ANALOGUE_GAIN; ++ analog.value = 0; ++ ++ ret = v4l2_g_ctrl(sensor->isd->sd->ctrl_handler, &analog); ++ if(ret < 0) { ++ printk("error s_ctrl, ret: %d\n", ret); ++ } ++ ++ ++ *again_reg_val = analog.value; ++} ++ ++static void sensor_set_analog_gain_short(uint32_t again_reg_val, sensor_context_t *p_ctx) ++{ ++ int isp_index = -1; ++ struct isp_device *isp = NULL; ++ struct sensor_device *sensor = NULL; ++ struct v4l2_control analog; ++ int ret = 0; ++ ++ if(p_ctx->sensor_id == 0) ++ isp_index = MAIN_ISP_INDEX; ++ else if(p_ctx->sensor_id == 1) ++ isp_index = SEC_ISP_INDEX; ++ isp = index_to_isp_device(isp_index); ++ sensor = to_sensor_device(isp); ++ ++ analog.id = V4L2_CID_USER_ANALOG_GAIN_SHORT; ++ analog.value = again_reg_val; ++ ++ ret = v4l2_s_ctrl(NULL, sensor->isd->sd->ctrl_handler, &analog); ++ if(ret < 0) { ++ printk("error s_ctrl, ret: %d\n", ret); ++ } ++} ++ ++static void sensor_get_analog_gain_short(uint32_t *again_reg_val, sensor_context_t *p_ctx) ++{ ++ int isp_index = -1; ++ struct isp_device *isp = NULL; ++ struct sensor_device *sensor = NULL; ++ struct v4l2_control analog; ++ int ret = 0; ++ ++ if(p_ctx->sensor_id == 0) ++ isp_index = MAIN_ISP_INDEX; ++ else if(p_ctx->sensor_id == 1) ++ isp_index = SEC_ISP_INDEX; ++ isp = index_to_isp_device(isp_index); ++ sensor = to_sensor_device(isp); ++ ++ analog.id = V4L2_CID_USER_ANALOG_GAIN_SHORT; ++ analog.value = 0; ++ ++ ret = v4l2_g_ctrl(sensor->isd->sd->ctrl_handler, &analog); ++ if(ret < 0) { ++ printk("error s_ctrl, ret: %d\n", ret); ++ } ++ ++ ++ *again_reg_val = analog.value; ++} ++ ++static void sensor_set_digital_gain(uint32_t dgain_reg_val, sensor_context_t *p_ctx) ++{ ++ int isp_index = -1; ++ struct isp_device *isp = NULL; ++ struct sensor_device *sensor = NULL; ++ struct v4l2_control control; ++ int ret = 0; ++ ++ if(p_ctx->sensor_id == 0) ++ isp_index = MAIN_ISP_INDEX; ++ else if(p_ctx->sensor_id == 1) ++ isp_index = SEC_ISP_INDEX; ++ isp = index_to_isp_device(isp_index); ++ sensor = to_sensor_device(isp); ++ ++ control.id = V4L2_CID_GAIN; ++ control.value = dgain_reg_val; ++ ++ ret = v4l2_s_ctrl(NULL, sensor->isd->sd->ctrl_handler, &control); ++ if(ret < 0) { ++ printk("error s_ctrl, ret: %d\n", ret); ++ } ++} ++ ++#if 0 ++static int sensor_get_digital_gain(uint32_t *dgain_reg_val, sensor_context_t *p_ctx) ++{ ++ int isp_index = -1; ++ struct isp_device *isp = NULL; ++ struct sensor_device *sensor = NULL; ++ struct v4l2_control control; ++ int ret = 0; ++ ++ if(p_ctx->sensor_id == 0) ++ isp_index = MAIN_ISP_INDEX; ++ else if(p_ctx->sensor_id == 1) ++ isp_index = SEC_ISP_INDEX; ++ isp = index_to_isp_device(isp_index); ++ sensor = to_sensor_device(isp); ++ ++ control.id = V4L2_CID_GAIN; ++ control.value = 0; ++ ++ ret = v4l2_g_ctrl(sensor->isd->sd->ctrl_handler, &control); ++ if(ret < 0) { ++ printk("error s_ctrl, ret: %d\n", ret); ++ } ++ ++ *dgain_reg_val = control.value; ++ ++ return ret; ++} ++#endif ++ ++#if 1 ++static uint16_t sensor_get_normal_fps(sensor_param_t* param) ++{ ++// printk("----%s, %d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static uint16_t sensor_read_black_pedestal(int i,uint32_t gain) ++{ ++// printk("----%s, %d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static void sensor_set_mode(uint8_t mode, sensor_param_t* param) ++{ ++// printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static void sensor_start_changes(sensor_context_t *p_ctx) ++{ ++// printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static void sensor_end_changes(sensor_context_t *p_ctx) ++{ ++// printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++ ++static uint16_t sensor_get_id(sensor_context_t *p_ctx) ++{ ++// printk("----%s, %d\n", __func__, __LINE__); ++ ++ return 0; ++} ++ ++static void sensor_set_wdr_mode(uint8_t mode, sensor_param_t* param) ++{ ++// printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static uint32_t sensor_fps_control(uint8_t fps, sensor_param_t* param) ++{ ++ ++// printk("----%s, %d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static void sensor_disable_isp(sensor_context_t *p_ctx) ++{ ++// printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static uint32_t sensor_get_lines_per_second(sensor_param_t* param) ++{ ++ uint32_t lines_per_second=0; ++// printk("----%s, %d\n", __func__, __LINE__); ++ return lines_per_second; ++} ++#endif ++ ++ ++extern tisp_init_par_t tisp_par_info; ++void sensor_init(sensor_control_t *ctrl, int vinum) ++{ ++ struct isp_device *isp = NULL; ++ struct sensor_device *sensor = NULL; ++ struct v4l2_queryctrl query; ++ tisp_init_param_t *sensor_info = &tisp_par_info.sensor[vinum]; ++ int ret = 0; ++ int isp_index = -1; ++ ++ if(vinum == 0) ++ isp_index = MAIN_ISP_INDEX; ++ else if(vinum == 1) ++ isp_index = SEC_ISP_INDEX; ++ ++ isp = g_isp_device[isp_index]; ++ sensor = to_sensor_device(isp); ++ ++ query.id = V4L2_CID_EXPOSURE; ++ query.type = V4L2_CTRL_TYPE_INTEGER; ++ ret = v4l2_queryctrl(sensor->isd->sd->ctrl_handler, &query); ++ if(ret < 0) { ++ dev_err(isp->dev, "query sensor V4L2_CID_EXPOSURE failed\n"); ++ } ++ ++ ctrl->param[vinum].integration_time_min = query.minimum; ++ ctrl->param[vinum].integration_time_max = query.maximum; ++ ++ query.id = V4L2_CID_USER_EXPOSURE_SHORT; ++ query.type = V4L2_CTRL_TYPE_INTEGER; ++ ret = v4l2_queryctrl(sensor->isd->sd->ctrl_handler, &query); ++ if(ret < 0) { ++ dev_err(isp->dev, "query sensor V4L2_CID_USER_EXPOSURE_SHORT failed\n"); ++ } ++ ++ ctrl->param[vinum].integration_time_min_short = query.minimum; ++ ctrl->param[vinum].integration_time_max_short = query.maximum; ++ ++ query.id = V4L2_CID_ANALOGUE_GAIN; ++ query.type = V4L2_CTRL_TYPE_INTEGER; ++ ret = v4l2_queryctrl(sensor->isd->sd->ctrl_handler, &query); ++ if(ret < 0) { ++ dev_err(isp->dev, "query sensor V4L2_CID_ANALOGUE_GAIN failed\n"); ++ } ++ ctrl->param[vinum].again_log2_max = query.maximum; ++ ++ query.id = V4L2_CID_USER_ANALOG_GAIN_SHORT; ++ query.type = V4L2_CTRL_TYPE_INTEGER; ++ ret = v4l2_queryctrl(sensor->isd->sd->ctrl_handler, &query); ++ if(ret < 0) { ++ dev_err(isp->dev, "query sensor V4L2_CID_USER_ANALOG_GAIN failed\n"); ++ } ++ ctrl->param[vinum].again_log2_max_short = query.maximum; ++ ++ ++ query.id = V4L2_CID_GAIN; ++ query.type = V4L2_CTRL_TYPE_INTEGER; ++ ret = v4l2_queryctrl(sensor->isd->sd->ctrl_handler, &query); ++ if(ret < 0) { ++ dev_err(isp->dev, "queyr sensor V4L2_CID_GAIN failed\n"); ++ } ++ ctrl->param[vinum].dgain_log2_max = query.maximum; ++ ++#if 1 ++ /*fill sensor_info*/ ++ sensor_info->sensor_info.max_again = ctrl->param[vinum].again_log2_max; //the format is .16 ++ sensor_info->sensor_info.max_again_short = ctrl->param[vinum].again_log2_max_short; //the format is .16 ++ sensor_info->sensor_info.max_dgain = ctrl->param[vinum].dgain_log2_max; //the format is .16 ++// sensor_info->sensor_info.again = core->vin.attr->again; ++// sensor_info->sensor_info.dgain = core->vin.attr->dgain; ++// sensor_info->sensor_info.fps = core->vin.fps; ++ sensor_info->sensor_info.min_integration_time = ctrl->param[vinum].integration_time_min; ++ sensor_info->sensor_info.max_integration_time = ctrl->param[vinum].integration_time_max; ++ sensor_info->sensor_info.min_integration_time_short = ctrl->param[vinum].integration_time_min_short; ++ sensor_info->sensor_info.max_integration_time_short = ctrl->param[vinum].integration_time_max_short; ++// sensor_info->sensor_info.min_integration_time_native = core->vin.attr->min_integration_time_native; ++// sensor_info->sensor_info.max_integration_time_native = core->vin.attr->max_integration_time_native; ++// sensor_info->sensor_info.integration_time_limit = core->vin.attr->integration_time_limit; ++// sensor_info->sensor_info.integration_time = core->vin.attr->integration_time; ++// sensor_info->sensor_info.total_width = core->vin.attr->total_width; ++// sensor_info->sensor_info.total_height = core->vin.attr->total_height; ++// sensor_info->sensor_info.integration_time_apply_delay = core->vin.attr->integration_time_apply_delay; ++// sensor_info->sensor_info.again_apply_delay = core->vin.attr->again_apply_delay; ++// sensor_info->sensor_info.dgain_apply_delay = core->vin.attr->dgain_apply_delay; ++// sensor_info->sensor_info.one_line_expr_in_us = core->vin.attr->one_line_expr_in_us; ++#endif ++ ++ ctrl->hw_reset_disable = sensor_hw_reset_disable; ++ ctrl->hw_reset_enable = sensor_hw_reset_enable; ++ ctrl->alloc_analog_gain = sensor_alloc_analog_gain; ++ ctrl->alloc_analog_gain_short = sensor_alloc_analog_gain_short; ++ ctrl->alloc_digital_gain = sensor_alloc_digital_gain; ++ ctrl->alloc_integration_time = sensor_alloc_integration_time; ++ ctrl->alloc_integration_time_short = sensor_alloc_integration_time_short; ++ ctrl->set_integration_time = sensor_set_integration_time; ++ ctrl->set_integration_time_short = sensor_set_integration_time_short; ++ ctrl->start_changes = sensor_start_changes; ++ ctrl->end_changes = sensor_end_changes; ++ ctrl->set_analog_gain = sensor_set_analog_gain; ++ ctrl->get_analog_gain = sensor_get_analog_gain; ++ ctrl->set_analog_gain_short = sensor_set_analog_gain_short; ++ ctrl->get_analog_gain_short = sensor_get_analog_gain_short; ++ ctrl->set_digital_gain = sensor_set_digital_gain; ++ ctrl->get_normal_fps = sensor_get_normal_fps; ++ ctrl->read_black_pedestal = sensor_read_black_pedestal; ++ ctrl->set_mode = sensor_set_mode; ++ ctrl->set_wdr_mode = sensor_set_wdr_mode; ++ ctrl->fps_control = sensor_fps_control; ++ ctrl->get_id = sensor_get_id; ++ ctrl->disable_isp = sensor_disable_isp; ++ ctrl->get_lines_per_second = sensor_get_lines_per_second; ++} ++ ++ ++int sensor_device_probe(struct sensor_device *sensor, struct ispcam_device *ispcam) ++{ ++ int ret = 0; ++ sensor->ispcam = ispcam; ++ sensor->isp = ispcam->isp; ++ sensor->isd = &ispcam->isd[0]; ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(sensor_device_probe); +diff --git a/module_drivers/drivers/media/platform/ingenic-isp-v2/tx-vic-regs.h b/module_drivers/drivers/media/platform/ingenic-isp-v2/tx-vic-regs.h +new file mode 100755 +index 000000000..012c6e1b3 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp-v2/tx-vic-regs.h +@@ -0,0 +1,182 @@ ++#ifndef __VIC_REG_H__ ++#define __VIC_REG_H__ ++ ++#define VIC_BASE(n) (0x0 + 0x00000 + n * 0x10000) ++ ++//#define VIC_DB_CFG 0x10 ++#define DVP_DATA_POS (1<<24) ++#define DVP_RGB_ORDER (1<<21) ++#define DVP_RAW_ALIG (1<<20) ++#define DVP_DATA_TYPE (17) ++#define DVP_RAW8 (0< ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++#include "vic-regs.h" ++ ++#define VIC_STOP_BUFFER_COUNT 2 ++#define VIC_RESTART_BUFFER_COUNT 3 ++ ++int count_period = 256; ++module_param(count_period, int, S_IRUGO); ++MODULE_PARM_DESC(count_period, "vic counter period"); ++ ++int vic_stop_counter = 0; ++module_param(vic_stop_counter, int, S_IRUGO); ++MODULE_PARM_DESC(vic_stop_counter, "vic0 bypass mode stop counter"); ++ ++int dma_debug_en = 0; ++module_param(dma_debug_en, int, 0664); ++MODULE_PARM_DESC(dma_debug_en, "vic dma debug mode enable"); ++ ++struct isp_video_format vic_mipi_formats[] = { ++ /*yuv420*/ ++ { ++ .name = "NV12, Y/CbCr 4:2:0", ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .depth = {8, 4}, ++ .num_planes = 2, ++ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "NV21, Y/CbCr 4:2:0", ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .depth = {8, 4}, ++ .num_planes = 2, ++ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ ++ /*yuv422 */ ++ { ++ .name = "YUV422, YUYV", ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "YUV422, YVYU", ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "YUV422, UYVY", ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "YUV422, VYUY", ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ /* dvp: Y8_1X8 */ ++ { ++ .name = "Y8, GREY", ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ }, ++ /* RAW8 */ ++ { ++ .name = "RAW8, 8 BGBG.. GRGR..", ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW8, 8 GBGB.. RGRG..", ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW8, 8 GRGR.. BGBG..", ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW8, 8 RGRG.. GBGB..", ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ /* RAW10 */ ++ { ++ .name = "RAW10, 10 BGBG.. GRGR..", ++ .fourcc = V4L2_PIX_FMT_SBGGR10, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW10, 10 GBGB.. RGRG..", ++ .fourcc = V4L2_PIX_FMT_SGBRG10, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW10, 10 GRGR.. BGBG..", ++ .fourcc = V4L2_PIX_FMT_SGRBG10, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW10, 10 RGRG.. GBGB..", ++ .fourcc = V4L2_PIX_FMT_SRGGB10, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ /* RAW12 */ ++ { ++ .name = "RAW12, 12 BGBG.. GRGR..", ++ .fourcc = V4L2_PIX_FMT_SBGGR12, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW12, 12 GBGB.. RGRG..", ++ .fourcc = V4L2_PIX_FMT_SGBRG12, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW12, 12 GRGR.. BGBG..", ++ .fourcc = V4L2_PIX_FMT_SGRBG12, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW12, 12 RGRG.. GBGB..", ++ .fourcc = V4L2_PIX_FMT_SRGGB12, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++}; ++ ++struct isp_video_format vic_dvp_formats = { ++ ++}; ++ ++ ++static inline void vic_reg_writel(struct vic_device *vic, unsigned int reg, unsigned int val) ++{ ++ writel(val, vic->iobase + reg); ++} ++ ++static inline unsigned int vic_reg_readl(struct vic_device *vic, unsigned int reg) ++{ ++ return readl(vic->iobase + reg); ++} ++ ++ ++static int ingenic_vic_parse_dt(struct vic_device * vic) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++unsigned int mux_out; ++static int vic_subdev_core_init(struct v4l2_subdev *sd, u32 ispcam_enabled) ++{ ++ struct vic_device *vic = v4l2_get_subdevdata(sd); ++ if((ispcam_enabled == 0 && vic->iobase == (unsigned int *)0xb3380000) || (ispcam_enabled == 1 && vic->iobase == (unsigned int *)0xb3390000)) ++ mux_out = 0; ++ else ++ mux_out = INPUT_MXU_OUT; ++ return 0; ++} ++ ++static const struct v4l2_subdev_core_ops vic_subdev_core_ops = { ++ .init = vic_subdev_core_init, ++ .log_status = v4l2_ctrl_subdev_log_status, ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static int vic_subdev_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct vic_device *vic = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ struct v4l2_subdev_format remote_subdev_fmt; ++ int ret = 0; ++ ++ remote = media_entity_remote_pad(&vic->pads[VIC_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ /*èŽ·å–æºå½“剿 ¼å¼ï¼Œå¤åˆ¶åˆ°è¾“出格å¼.*/ ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_err(vic->dev, "Failed to get_fmt from remote pad\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(&format->format, &remote_subdev_fmt.format, sizeof(format->format)); ++ ++ vic->formats[VIC_PAD_SINK] = vic->formats[VIC_PAD_SOURCE] = *format; ++ ++ //printk("----%s, %d, format->pad: %d\n", __func__, __LINE__, format->pad); ++ return 0; ++} ++ ++static int vic_subdev_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct vic_device *vic = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ struct v4l2_subdev_format remote_subdev_fmt; ++ int ret = 0; ++ ++ dev_dbg(vic->dev, "%s, %d, width: %d, height: %d, mbus_code: %x\n", __func__, __LINE__, format->format.width, format->format.height, format->format.code); ++ ++ vic->formats[VIC_PAD_SOURCE] = *format; ++ ++ remote = media_entity_remote_pad(&vic->pads[VIC_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ ret = v4l2_subdev_call(remote_sd, pad, set_fmt, NULL, format); ++ if(ret < 0) { ++ dev_dbg(vic->dev, "Failed to set_fmt from remote pad\n"); ++ } ++ ++ /*èŽ·å–æºå½“剿 ¼å¼ï¼Œå¤åˆ¶åˆ°è¾“出格å¼.*/ ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_err(vic->dev, "Failed to get_fmt from remote pad\n"); ++ printk("Failed to get_fmt from remote pad\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(&vic->formats[VIC_PAD_SINK], &remote_subdev_fmt, sizeof(struct v4l2_subdev_format)); ++ vic->sensor_info = (struct sensor_info *)*(unsigned int *)remote_subdev_fmt.format.reserved; ++ ++ return 0; ++} ++ ++ ++static const struct v4l2_subdev_pad_ops vic_subdev_pad_ops = { ++ .get_fmt = vic_subdev_get_fmt, ++ .set_fmt = vic_subdev_set_fmt, ++}; ++ ++ ++static int vic_cfg_stream_mipi(struct vic_device *vic) ++{ ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ //struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = ispcam_get_bus_mipi_csi2(vic->ispcam); ++ struct mipi_cfg *mipi_cfg = &vic->sensor_info->mipi_cfg; ++ //unsigned int timeout = 10000; ++ unsigned int mipi_sensor_ctl = 0; ++ ++ dev_dbg(vic->dev, "%s, %d, input_fmt->format.width: %d, intput_fmt->format.height: %d\n", ++ __func__, __LINE__, input_fmt->format.width, input_fmt->format.height); ++ ++ ++ if(mipi_cfg->mipi_mode == SENSOR_MIPI_SONY_MODE) { ++ dev_info(vic->dev, "[ %s:%d ] sensor type is SONY_MIPI!\n", __func__, __LINE__); ++ /*imx307 nomal*/ ++ vic_reg_writel(vic, VIC_IN_DVP, (0x0 << 31 | 0x0 <<24 | 0x1 << 17 | 0x0 << 11 | 0x0 << 4)); ++ vic_reg_writel(vic, VIC_CONTROL_CONTROL, 0x00100010); ++ } else { ++ dev_info(vic->dev, "[ %s:%d ] sensor type is OTHER_MIPI!\n", __func__, __LINE__); ++ vic_reg_writel(vic, VIC_CONTROL_DELAY, (10 << 16) | (10)); ++ } ++ ++ vic_reg_writel(vic, VIC_INTF_TYPE, INTF_TYPE_MIPI); ++ ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ vic_reg_writel(vic, VIC_IN_CSI_FMT,MIPI_RAW8);//RAW8 ++ vic_reg_writel(vic, MIPI_ALL_WIDTH_4BYTE, (mipi_cfg->twidth * 8 % 32) ? (mipi_cfg->twidth * 8 / 32)+ 1 : (mipi_cfg->twidth * 8 / 32)); ++ break; ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ vic_reg_writel(vic, VIC_IN_CSI_FMT,MIPI_RAW10);//RAW10 ++ vic_reg_writel(vic, MIPI_ALL_WIDTH_4BYTE, (mipi_cfg->twidth * 10 % 32) ? (mipi_cfg->twidth * 10 / 32)+ 1 : (mipi_cfg->twidth * 10 / 32)); ++ break; ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ vic_reg_writel(vic, VIC_IN_CSI_FMT,MIPI_RAW12);//RAW12 ++ vic_reg_writel(vic, MIPI_ALL_WIDTH_4BYTE, (mipi_cfg->twidth * 12 % 32) ? (mipi_cfg->twidth * 12 / 32)+ 1 : (mipi_cfg->twidth * 12 / 32)); ++ break; ++ case MEDIA_BUS_FMT_Y8_1X8 : ++ vic_reg_writel(vic, VIC_IN_CSI_FMT, MIPI_YUV422);//YUV422 ++ vic_reg_writel(vic, MIPI_ALL_WIDTH_4BYTE, (mipi_cfg->twidth*2 * 8 % 32) ? (mipi_cfg->twidth*2 * 8 / 32)+ 1 : (mipi_cfg->twidth*2 * 8 / 32)); ++ break; ++ case MEDIA_BUS_FMT_YUYV8_2X8 : ++ case MEDIA_BUS_FMT_YVYU8_2X8 : ++ case MEDIA_BUS_FMT_UYVY8_2X8 : ++ case MEDIA_BUS_FMT_VYUY8_2X8 : ++ vic_reg_writel(vic, VIC_IN_CSI_FMT, MIPI_YUV422);//YUV422 ++ vic_reg_writel(vic, MIPI_ALL_WIDTH_4BYTE, (mipi_cfg->twidth * 8 % 32) ? (mipi_cfg->twidth * 8 / 32)+ 1 : (mipi_cfg->twidth * 8 / 32)); ++ break; ++ default: ++ dev_err(vic->dev, "unsupported mbus fmt: %x\n", input_fmt->format.code); ++ return -EINVAL; ++ } ++ ++ vic_reg_writel(vic, VIC_CONTROL_CONTROL, mipi_cfg->sensor_mode << SENSOR_MODE | mipi_cfg->sensor_frame_mode << SENSOR_FRM_NUM); ++ ++ mipi_sensor_ctl = mipi_cfg->hcrop_diff_en << HCROP_DIFF_EN | mipi_cfg->mipi_vcomp_en << VCOMP_EN | mipi_cfg->mipi_hcomp_en << HCOMP_EN |mipi_cfg->line_sync_mode << LINE_SYNC_MODE | mipi_cfg->work_start_flag << WORK_START_FLAG | mipi_cfg->data_type_en << DATA_TYPE_EN | mipi_cfg->data_type_value << DATA_TYPE_VALUE | mipi_cfg->del_start << DEL_START | mipi_cfg->sensor_frame_mode << SENSOR_FRM_NUM | mipi_cfg->sensor_fid_mode << SENSOR_FID_MODE | mipi_cfg->sensor_mode << SENSOR_MODE; ++ vic_reg_writel(vic, MIPI_SENSOR_CONTROL, mipi_sensor_ctl); ++ ++ vic_reg_writel(vic, MIPI_HCROP_CH0, (mipi_cfg->twidth << 16) | mipi_cfg->mipi_crop_start0x); ++ vic_reg_writel(vic, MIPI_HCROP_CH1, mipi_cfg->mipi_crop_start1x); ++ vic_reg_writel(vic, MIPI_HCROP_CH2, mipi_cfg->mipi_crop_start2x); ++ vic_reg_writel(vic, MIPI_HCROP_CH3, mipi_cfg->mipi_crop_start3x); ++ ++ vic_reg_writel(vic, MIPI_VCROP_DEL01, mipi_cfg->mipi_crop_start1y << 16 | mipi_cfg->mipi_crop_start0y); ++ vic_reg_writel(vic, MIPI_VCROP_DEL23, mipi_cfg->mipi_crop_start3y << 16 | mipi_cfg->mipi_crop_start2y); ++ ++ return 0; ++} ++ ++static int vic_cfg_stream_dvp(struct vic_device *vic) ++{ ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ struct v4l2_fwnode_bus_parallel *parallel = ispcam_get_bus_parallel(vic->ispcam); ++ //struct dvp_cfg *dvp_cfg = &vic->sensor_info->dvp_cfg; ++ unsigned int input_cfg = 0; ++ ++ vic->frame_capture_counter = 0; /* reset counter */ ++ vic->global_reset = 0; ++ ++ dev_dbg(vic->dev, "parallel->flags: 0x%x\n", parallel->flags); ++ dev_dbg(vic->dev, "parallel->bus_width: %d\n", parallel->bus_width); ++ dev_dbg(vic->dev, "parallel->data_shift: %d\n", parallel->data_shift); ++ vic_reg_writel(vic, VIC_INTF_TYPE, INTF_TYPE_DVP); ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ if(parallel->data_shift) { ++ input_cfg = DVP_RAW8 | DVP_RAW_ALIG; ++ } else { ++ input_cfg = DVP_RAW8; ++ } ++ break; ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ if(parallel->data_shift) { ++ input_cfg = DVP_RAW10 | DVP_RAW_ALIG; ++ } else { ++ input_cfg = DVP_RAW10; ++ } ++ break; ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ input_cfg = DVP_RAW12; ++ break; ++ case MEDIA_BUS_FMT_UYVY8_1_5X8 : ++ case MEDIA_BUS_FMT_VYUY8_1_5X8 : ++ case MEDIA_BUS_FMT_YUYV8_1_5X8 : ++ case MEDIA_BUS_FMT_YVYU8_1_5X8 : ++ case MEDIA_BUS_FMT_YUYV8_1X16 : ++ case MEDIA_BUS_FMT_YUYV8_2X8 : ++ case MEDIA_BUS_FMT_YVYU8_2X8 : ++ case MEDIA_BUS_FMT_UYVY8_2X8 : ++ case MEDIA_BUS_FMT_VYUY8_2X8 : ++ case MEDIA_BUS_FMT_Y8_1X8 : ++ input_cfg = DVP_YUV422_8BIT; ++ break; ++ ++ default: ++ dev_err(vic->dev, "unsupported input formats\n"); ++ return -EINVAL; ++ } ++ if(parallel->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) { ++ input_cfg |= HSYN_POLAR; ++ } ++ if(parallel->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) { ++ input_cfg |= VSYN_POLAR; ++ } ++ vic_reg_writel(vic, VIC_IN_DVP, input_cfg); ++ /*dev_info(vic->dev, "VIC_IN_DVP input_cfg=0x%x\n", input_cfg); ++ if (input_fmt->format.width>2048 && input_fmt->format.height == 1) { ++ vic_reg_writel(vic, VIC_IN_DVP, 0x6<<17 | 1<<1 | 1<<0); //cisadc, 0x6<<17 | 1<<1 | 1<<0; ++ }*/ ++ /*TODO: hblank and vblank*/ ++ ++ if(input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_2X8) ++ vic_reg_writel(vic, VIC_IN_HOR_PARA0, input_fmt->format.width * 2 + 0 /*hblank*/); ++ else ++ vic_reg_writel(vic, VIC_IN_HOR_PARA0, input_fmt->format.width + 0 /*hblank*/); ++ // vc control ++ vic_reg_writel(vic, VIC_CONTROL_DELAY, 0x10 << 16 | 0x10); ++ vic_reg_writel(vic, VIC_CONTROL_DELEY_BLK, 0x10); ++ vic_reg_writel(vic, VIC_CONTROL_LIMIT, 0); ++ ++ return 0; ++} ++ ++static int vic_cfg_stream_bt1120(struct vic_device *vic) ++{ ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ struct v4l2_fwnode_bus_parallel *parallel = ispcam_get_bus_parallel(vic->ispcam); ++ struct bt_cfg *bt_cfg = &vic->sensor_info->bt_cfg; ++ unsigned int input_cfg = 0; ++ ++ vic->frame_capture_counter = 0; /* reset counter */ ++ vic->global_reset = 0; ++ ++ dev_dbg(vic->dev, "parallel->flags: 0x%x\n", parallel->flags); ++ dev_dbg(vic->dev, "parallel->bus_width: %d\n", parallel->bus_width); ++ dev_dbg(vic->dev, "parallel->data_shift: %d\n", parallel->data_shift); ++ vic_reg_writel(vic, VIC_INTF_TYPE, INTF_TYPE_BT1120); ++ ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_YUYV8_2X8 : ++ input_cfg |= YUYV; ++ break; ++ case MEDIA_BUS_FMT_YVYU8_2X8 : ++ input_cfg |= YVYU; ++ break; ++ case MEDIA_BUS_FMT_UYVY8_2X8 : ++ input_cfg |= UYVY; ++ break; ++ case MEDIA_BUS_FMT_VYUY8_2X8 : ++ input_cfg |= VYUY; ++ break; ++ default: ++ dev_err(vic->dev, "unsupported input formats\n"); ++ return -EINVAL; ++ } ++ ++ if(parallel->bus_width == 16) { ++ input_cfg |= BT_INTF_WIDE; ++ input_cfg |= DVP_YUV422_16BIT; ++ } else ++ input_cfg |= DVP_YUV422_8BIT; ++ ++ if(bt_cfg->interlace_en) ++ input_cfg |= INTERLACE_EN; ++ if(bt_cfg->bt_sav_eav == SAV_BF_EAV) ++ input_cfg |= BT_LINE_MODE; ++ ++ vic_reg_writel(vic, VIC_IN_DVP, input_cfg); ++ /*dev_info(vic->dev, "VIC_IN_DVP input_cfg=0x%x\n", input_cfg); ++ if (input_fmt->format.width>2048 && input_fmt->format.height == 1) { ++ vic_reg_writel(vic, VIC_IN_DVP, 0x6<<17 | 1<<1 | 1<<0); //cisadc, 0x6<<17 | 1<<1 | 1<<0; ++ }*/ ++ /*TODO: hblank and vblank*/ ++ ++ vic_reg_writel(vic, VIC_IN_HOR_PARA0, input_fmt->format.width + 0 /*hblank*/); ++ // vc control ++ vic_reg_writel(vic, VIC_CONTROL_DELAY, 0x10 << 16 | 0x10); ++ vic_reg_writel(vic, VIC_CONTROL_DELEY_BLK, 0x10); ++ vic_reg_writel(vic, VIC_CONTROL_LIMIT, 0); ++ ++ return 0; ++} ++ ++static int vic_subdev_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct vic_device *vic = v4l2_get_subdevdata(sd); ++ struct isp_async_device *isd = &vic->ispcam->isd[0]; /*TODO: 默认支æŒä¸€ä¸ªasd.*/ ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ struct isp_video_device *ispvideo = v4l2_get_subdev_hostdata(sd); ++ struct isp_video_buffer *isp_buffer = NULL; ++ struct isp_video_buffer *tmp = NULL; ++ int ret = 0; ++ unsigned long flags; ++ int width; ++ unsigned int regval; ++ unsigned int y_stride; ++ unsigned int uv_stride; ++ ++ spin_lock_irqsave(&vic->lock, flags); ++ /*hw configure.*/ ++ if(enable) { ++ ++ if(vic->enabled++ > 0) { ++ goto finish; ++ } ++ ++ /* set width */ ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_Y8_1X8 : ++ input_fmt->format.width /= 2; /* */ ++ width = input_fmt->format.width; ++ break; ++ /* TODO: NV21/NV12 */ ++ default: ++ width = input_fmt->format.width; ++ } ++ ++#if 0 ++ /* enable timestamp .*/ ++ vic_reg_writel(vic, VIC_TS_COUNTER, count_period - 1); ++ vic_reg_writel(vic, VIC_TS_DMA_OFFSET, 0); ++ vic_reg_writel(vic, VIC_TS_MS_CH0_OFFSET, 0); ++ vic_reg_writel(vic, VIC_TS_MS_CH1_OFFSET, 0); ++ vic_reg_writel(vic, VIC_TS_MS_CH2_OFFSET, 0); ++ vic_reg_writel(vic, VIC_TS_ENABLE, TS_COUNTER_EN | ++ TS_VIC_DMA_EN | TS_MS_CH0_EN | ++ TS_MS_CH1_EN | TS_MS_CH2_EN); ++#endif ++ ++ /*confgure hw and start*/ ++ if(isd->bus_type == V4L2_MBUS_CSI2_DPHY) { ++ ret = vic_cfg_stream_mipi(vic); ++ mux_out |= INPUT_MXU_MIPI_EN; ++ } else if(isd->bus_type == V4L2_MBUS_PARALLEL){ ++ ret = vic_cfg_stream_dvp(vic); ++ mux_out |= INPUT_MXU_DVP_EN; ++ } else if(isd->bus_type == V4L2_MBUS_BT656) { ++ ret = vic_cfg_stream_bt1120(vic); ++ mux_out |= INPUT_MXU_DVP_EN; ++ } ++ ++ vic_reg_writel(vic, VIC_RESOLUTION, (width << 16) | ++ input_fmt->format.height); ++ ++ if(ispvideo->bypass == 1) { ++ if(dma_debug_en) { ++ printk("please disable vic dma debug mode\ntry \"echo 0 > /sys/module/vic/parameters/dma_debug_en\"\n"); ++ goto finish; ++ } ++ /*DMA config*/ ++ regval = 0; ++ /*TODO: fmts.*/ ++ switch(ispvideo->current_format->fourcc) { ++ case V4L2_PIX_FMT_YUYV : ++ regval |= 3<<8; /* Y1UY2V */ ++ regval |= 3<<0; /* mode 3: YUV422 */ ++ y_stride = width * 2; ++ uv_stride = width * 2; ++ break; ++ case V4L2_PIX_FMT_YVYU : ++ regval |= 2<<8; /* Y2VY1U */ ++ regval |= 3<<0; /* mode 3: YUV422 */ ++ y_stride = width * 2; ++ uv_stride = width * 2; ++ break; ++ case V4L2_PIX_FMT_UYVY : ++ regval |= 1<<8; /* UY1VY2 */ ++ regval |= 3<<0; /* mode 3: YUV422 */ ++ y_stride = width * 2; ++ uv_stride = width * 2; ++ break; ++ case V4L2_PIX_FMT_VYUY : ++ regval |= 0<<8; /* VY2UY1 */ ++ regval |= 3<<0; /* mode 3: YUV422 */ ++ y_stride = width * 2; ++ uv_stride = width * 2; ++ break; ++ case V4L2_PIX_FMT_GREY : ++ regval |= 3<<0; /* mode 3: YUV422 */ ++ y_stride = width * 2; ++ uv_stride = width * 2; ++ break; ++ case V4L2_PIX_FMT_NV12 : ++ regval |= 6<<0; /* mode 6: NV12 */ ++ y_stride = width; ++ uv_stride = width; ++ break; ++ case V4L2_PIX_FMT_NV21 : ++ regval |= 7<<0; /* mode 7: NV12 */ ++ y_stride = width; ++ uv_stride = width; ++ break; ++ case V4L2_PIX_FMT_SBGGR8: ++ case V4L2_PIX_FMT_SGBRG8: ++ case V4L2_PIX_FMT_SGRBG8: ++ case V4L2_PIX_FMT_SRGGB8: ++ case V4L2_PIX_FMT_SBGGR10: ++ case V4L2_PIX_FMT_SGBRG10: ++ case V4L2_PIX_FMT_SGRBG10: ++ case V4L2_PIX_FMT_SRGGB10: ++ case V4L2_PIX_FMT_SBGGR12: ++ case V4L2_PIX_FMT_SGBRG12: ++ case V4L2_PIX_FMT_SGRBG12: ++ case V4L2_PIX_FMT_SRGGB12: ++ regval |= 0; ++ y_stride = width * 2; ++ uv_stride = width * 2; ++ break; ++ default: ++ dev_info(vic->dev, "%s(), TODO: DMA config, input_fmt->format.code=0x%x\n", ++ __func__, input_fmt->format.code); ++ return -EINVAL; ++ } ++ regval |= 1 << 31; /* enable dma */ ++ regval |= (ispvideo->max_buffer_num - 1) << 3; ++ regval |= 8 << 16; /*max outout num*/ ++ vic_reg_writel(vic, VIC_DMA_CONFIG, regval); ++ ++ vic_reg_writel(vic, VIC_DMA_RESOLUTION, (width << 16) | ++ input_fmt->format.height); ++ vic_reg_writel(vic, VIC_DMA_Y_STRID, y_stride); ++ vic_reg_writel(vic, VIC_DMA_UV_STRID, uv_stride); ++ ++ vic_reg_writel(vic, VIC_CONTROL_TIZIANO_ROUTE, 0); ++ if(isd->bus_type == V4L2_MBUS_CSI2_DPHY) ++ vic_reg_writel(vic, VIC_CONTROL_DMA_ROUTE, 0x4440); ++ else ++ vic_reg_writel(vic, VIC_CONTROL_DMA_ROUTE, 0x4210); ++ vic_reg_writel(vic, VIC_INT_MASK, 0x0); ++ vic_reg_writel(vic, VIC_INT_MASK2, 0x0); ++ /* ++ if(input_fmt->format.width > 2048) { ++ if(0 && input_fmt->format.height > 1) ++ vic_reg_writel(vic, VIC_CONTROL_LIMIT, (1 << 31)|((input_fmt->format.width / 8 * 3) << 16)); ++ else ++ vic_reg_writel(vic, VIC_CONTROL_LIMIT, (1 << 31)|(512<<16)); // cisadc, height==1, width > 2048 ++ } ++ */ ++ vic->framenum = 0; ++ ++ } else { ++ if(vic->sensor_info->wdr_en) ++ vic_reg_writel(vic, VIC_CONTROL_TIZIANO_ROUTE, 0x4410); ++ else ++ vic_reg_writel(vic, VIC_CONTROL_TIZIANO_ROUTE, 0x4404); ++ if(dma_debug_en) ++ if(vic->sensor_info->wdr_en) ++ vic_reg_writel(vic, VIC_CONTROL_DMA_ROUTE, 0x4410); ++ else{ ++ if(isd->bus_type == V4L2_MBUS_CSI2_DPHY) ++ vic_reg_writel(vic, VIC_CONTROL_DMA_ROUTE, 0x4440); ++ else ++ vic_reg_writel(vic, VIC_CONTROL_DMA_ROUTE, 0x4210); ++ } ++ else ++ vic_reg_writel(vic, VIC_CONTROL_DMA_ROUTE, 0); ++ vic_reg_writel(vic, VIC_INT_MASK, 0); ++ vic_reg_writel(vic, VIC_INT_MASK2, 0); ++ ++ vic_reg_writel(vic, VIC_CONTROL, GLB_RST); ++ } ++ ++ vic_reg_writel(vic, VIC_CONTROL_INPUT_MUX_OUTROUTE, mux_out); ++ if(vic->iobase == (unsigned int *)0xb3390000 && *(volatile unsigned int *)0xb33801c0 == 0) ++ *(volatile unsigned int *)0xb33801c0 = 0x02; ++ ++ /* ++ vic_reg_writel(vic, VIC_CONTROL, REG_ENABLE); ++ unsigned int timeout = 0xfffff; ++ while(vic_reg_readl(vic,VIC_CONTROL) && --timeout); ++ if(!timeout) { ++ dev_err(vic->dev, "wait vic init timeout!\n"); ++ } ++ */ ++ vic_reg_writel(vic, VIC_CONTROL, VIC_START); ++ ++ ++ } else { ++ /*reset flags*/ ++ vic->buffer_index = 0; ++ vic->stop_flag = 0; ++ vic_stop_counter = 0; ++ ++ if(--vic->enabled) { ++ goto finish; ++ } ++ ++ /* disable timestamp */ ++ vic_reg_writel(vic, VIC_TS_COUNTER, 0); ++ vic_reg_writel(vic, VIC_TS_ENABLE, 0); ++ ++ if(ispvideo->bypass) { ++ /*disable dma*/ ++ vic_reg_writel(vic, VIC_DMA_CONFIG, 0); ++ /*disable contro limit*/ ++ if(input_fmt->format.width > 2048) ++ vic_reg_writel(vic, VIC_CONTROL_LIMIT, 0); ++ } ++ ++ /* keep reset*/ ++ vic_reg_writel(vic, VIC_CONTROL, GLB_RST); ++ ++ /* stop vic. */ ++ list_for_each_entry_safe(isp_buffer, tmp, &vic->dma_queued_list, list_entry) { ++ struct vb2_buffer *vb2_buf = &isp_buffer->vb2.vb2_buf; ++ vb2_buffer_done(vb2_buf, VB2_BUF_STATE_ERROR); ++ list_del(&isp_buffer->list_entry); ++ vic->buffer_count--; ++ } ++ ++ } ++ ++finish: ++ spin_unlock_irqrestore(&vic->lock, flags); ++ ++ return ret; ++} ++ ++ ++static const struct v4l2_subdev_video_ops vic_subdev_video_ops = { ++ .s_stream = vic_subdev_s_stream, ++}; ++static const struct v4l2_subdev_ops vic_subdev_ops = { ++ .core = &vic_subdev_core_ops, ++ .pad = &vic_subdev_pad_ops, ++ .video = &vic_subdev_video_ops, ++}; ++ ++struct isp_video_format *vic_find_format(const u32 *pixelformat, const u32 *mbus_code, int index) ++{ ++ int i; ++ struct isp_video_format *fmt = NULL; ++ ++ for(i = 0; i < ARRAY_SIZE(vic_mipi_formats); i++) { ++ fmt = &vic_mipi_formats[i]; ++ ++ if(pixelformat && fmt->fourcc == *pixelformat) { ++ return fmt; ++ } ++ if(mbus_code && fmt->mbus_code == *mbus_code) { ++ return fmt; ++ } ++ ++ if(index == i) { ++ return fmt; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int vic_video_qbuf(struct isp_video_device *ispvideo, struct isp_video_buffer *isp_buffer) ++{ ++ struct vic_device *vic = ispvideo->ispcam->vic; ++ struct vb2_buffer *vb2_buf = NULL; ++ struct isp_video_buffer *tmp = NULL; ++ unsigned long flags = 0; ++ dma_addr_t y_addr = 0; ++ dma_addr_t uv_addr = 0; ++ unsigned int regval; ++ ++ spin_lock_irqsave(&vic->lock, flags); ++ ++ vb2_buf = &isp_buffer->vb2.vb2_buf; ++ ++ list_add_tail(&isp_buffer->list_entry, &vic->dma_queued_list); ++ vic->buffer_count++; ++ ++ ++ /*Y*/ ++ y_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 0); ++ vic_reg_writel(vic, VIC_DMA_Y_CH0_BUF0 + vic->buffer_index * 4, y_addr); ++ ++ uv_addr = y_addr + isp_buffer->uv_offset; ++ /*UV*/ ++ if(vb2_buf->num_planes == 2) { ++ uv_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 1); ++ } ++ vic_reg_writel(vic, VIC_DMA_UV_CH0_BUF0 + vic->buffer_index * 4, uv_addr); ++ ++ vic->buffer_index++; ++ vic->buffer_index %= ispvideo->max_buffer_num; ++ ++ if(vic->buffer_count >= VIC_RESTART_BUFFER_COUNT && vic->stop_flag) ++ { ++ /*reset flags*/ ++ vic->stop_flag = 0; ++ vic->buffer_index = 0; ++ ++ /*buffers in the list refill in register*/ ++ list_for_each_entry_safe(isp_buffer, tmp, &vic->dma_queued_list, list_entry) { ++ ++ vb2_buf = &isp_buffer->vb2.vb2_buf; ++ /*Y*/ ++ y_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 0); ++ vic_reg_writel(vic, VIC_DMA_Y_CH0_BUF0 + vic->buffer_index * 4, y_addr); ++ ++ uv_addr = y_addr + isp_buffer->uv_offset; ++ /*UV*/ ++ if(vb2_buf->num_planes == 2) { ++ uv_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 1); ++ } ++ vic_reg_writel(vic, VIC_DMA_UV_CH0_BUF0 + vic->buffer_index * 4, uv_addr); ++ ++ vic->buffer_index++; ++ vic->buffer_index %= ispvideo->max_buffer_num; ++ ++ } ++ /*restart*/ ++ regval = vic_reg_readl(vic, VIC_DMA_CONFIG); ++ vic_reg_writel(vic, VIC_DMA_RESET, 1); ++ vic_reg_writel(vic, VIC_DMA_RESET, 0); ++ regval |= 1 << 31; /* enable dma */ ++ regval &= ~(0xf<<3); /* reset dma buffer num */ ++ regval |= (ispvideo->max_buffer_num - 1) << 3; ++ vic_reg_writel(vic, VIC_DMA_CONFIG, regval); ++ /* lgwang, re-start vic */ ++ if (vic->global_reset) { ++ vic_reg_writel(vic, VIC_CONTROL, 0x1); ++ vic->global_reset = 0; ++ } ++ goto done; ++ } ++ ++done: ++ spin_unlock_irqrestore(&vic->lock, flags); ++ ++ return 0; ++} ++ ++static const struct isp_video_ops vic_video_ops = { ++ .find_format = vic_find_format, ++ .qbuf = vic_video_qbuf, ++}; ++ ++static ssize_t ++dump_vic(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct vic_device *vic = dev_get_drvdata(dev); ++ char *p = buf; ++ ++ p += sprintf(p, "VIC_CONTROL :0x%08x\n", vic_reg_readl(vic, VIC_CONTROL)); ++ p += sprintf(p, "VIC_RESOLUTION :0x%08x\n", vic_reg_readl(vic, VIC_RESOLUTION)); ++ p += sprintf(p, "VIC_FRM_ECC :0x%08x\n", vic_reg_readl(vic, VIC_FRM_ECC)); ++ p += sprintf(p, "VIC_INTF_TYPE :0x%08x\n", vic_reg_readl(vic, VIC_INTF_TYPE)); ++ p += sprintf(p, "VIC_IN_DVP :0x%08x\n", vic_reg_readl(vic, VIC_IN_DVP)); ++ p += sprintf(p, "VIC_IN_CSI_FMT :0x%08x\n", vic_reg_readl(vic, VIC_IN_CSI_FMT)); ++ p += sprintf(p, "VIC_IN_HOR_PARA0 :0x%08x\n", vic_reg_readl(vic, VIC_IN_HOR_PARA0)); ++ p += sprintf(p, "VIC_IN_HOR_PARA1 :0x%08x\n", vic_reg_readl(vic, VIC_IN_HOR_PARA1)); ++ p += sprintf(p, "VIC_IN_VER_PARA0 :0x%08x\n", vic_reg_readl(vic, VIC_IN_VER_PARA0)); ++ p += sprintf(p, "VIC_IN_VER_PARA1 :0x%08x\n", vic_reg_readl(vic, VIC_IN_VER_PARA1)); ++ p += sprintf(p, "VIC_IN_VER_PARA2 :0x%08x\n", vic_reg_readl(vic, VIC_IN_VER_PARA2)); ++ p += sprintf(p, "VIC_IN_VER_PARA3 :0x%08x\n", vic_reg_readl(vic, VIC_IN_VER_PARA3)); ++ p += sprintf(p, "VIC_VLD_LINE_SAV :0x%08x\n", vic_reg_readl(vic, VIC_VLD_LINE_SAV)); ++ p += sprintf(p, "VIC_VLD_LINE_EAV :0x%08x\n", vic_reg_readl(vic, VIC_VLD_LINE_EAV)); ++ p += sprintf(p, "VIC_VLD_FRM_SAV :0x%08x\n", vic_reg_readl(vic, VIC_VLD_FRM_SAV)); ++ p += sprintf(p, "VIC_VLD_FRM_EAV :0x%08x\n", vic_reg_readl(vic, VIC_VLD_FRM_EAV)); ++ p += sprintf(p, "VIC_VC_CONTROL :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH0_PIX :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH0_PIX)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH1_PIX :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH1_PIX)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH2_PIX :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH2_PIX)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH3_PIX :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH3_PIX)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH0_LINE :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH0_LINE)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH1_LINE :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH1_LINE)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH2_LINE :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH2_LINE)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH3_LINE :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH3_LINE)); ++ p += sprintf(p, "VIC_VC_CONTROL_FIFO_USE :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_FIFO_USE)); ++ p += sprintf(p, "MIPI_ALL_WIDTH_4BYTE :0x%08x\n", vic_reg_readl(vic, MIPI_ALL_WIDTH_4BYTE)); ++ p += sprintf(p, "MIPI_VCROP_DEL01 :0x%08x\n", vic_reg_readl(vic, MIPI_VCROP_DEL01)); ++ p += sprintf(p, "MIPI_SENSOR_CONTROL :0x%08x\n", vic_reg_readl(vic, MIPI_SENSOR_CONTROL)); ++ p += sprintf(p, "MIPI_HCROP_CH0 :0x%08x\n", vic_reg_readl(vic, MIPI_HCROP_CH0)); ++ p += sprintf(p, "VIC_CONTROL_LIMIT :0x%08x\n", vic_reg_readl(vic, VIC_CONTROL_LIMIT)); ++ p += sprintf(p, "VIC_CONTROL_DELAY :0x%08x\n", vic_reg_readl(vic, VIC_CONTROL_DELAY)); ++ p += sprintf(p, "VIC_CONTROL_TIZIANO_ROUTE :0x%08x\n", vic_reg_readl(vic, VIC_CONTROL_TIZIANO_ROUTE)); ++ p += sprintf(p, "VIC_CONTROL_DMA_ROUTE :0x%08x\n", vic_reg_readl(vic, VIC_CONTROL_DMA_ROUTE)); ++ p += sprintf(p, "VIC_INT_STA :0x%08x\n", vic_reg_readl(vic, VIC_INT_STA)); ++ p += sprintf(p, "VIC_INT_MASK :0x%08x\n", vic_reg_readl(vic, VIC_INT_MASK)); ++ p += sprintf(p, "VIC_INT_CLR :0x%08x\n", vic_reg_readl(vic, VIC_INT_CLR)); ++ p += sprintf(p, "VIC_DMA_CONFIG :0x%08x\n", vic_reg_readl(vic, VIC_DMA_CONFIG)); ++ p += sprintf(p, "VIC_DMA_RESOLUTION :0x%08x\n", vic_reg_readl(vic, VIC_DMA_RESOLUTION)); ++ p += sprintf(p, "VIC_DMA_RESET :0x%08x\n", vic_reg_readl(vic, VIC_DMA_RESET)); ++ p += sprintf(p, "VIC_DMA_Y_STRID :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_STRID)); ++ p += sprintf(p, "VIC_DMA_Y_CH0_BUF0 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_CH0_BUF0)); ++ p += sprintf(p, "VIC_DMA_Y_CH0_BUF1 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_CH0_BUF1)); ++ p += sprintf(p, "VIC_DMA_Y_CH0_BUF2 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_CH0_BUF2)); ++ p += sprintf(p, "VIC_DMA_Y_CH0_BUF3 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_CH0_BUF3)); ++ p += sprintf(p, "VIC_DMA_Y_CH0_BUF4 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_CH0_BUF4)); ++ p += sprintf(p, "VIC_DMA_UV_STRID :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_STRID)); ++ p += sprintf(p, "VIC_DMA_UV_CH0_BUF0 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_CH0_BUF0)); ++ p += sprintf(p, "VIC_DMA_UV_CH0_BUF1 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_CH0_BUF1)); ++ p += sprintf(p, "VIC_DMA_UV_CH0_BUF2 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_CH0_BUF2)); ++ p += sprintf(p, "VIC_DMA_UV_CH0_BUF3 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_CH0_BUF3)); ++ p += sprintf(p, "VIC_DMA_UV_CH0_BUF4 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_CH0_BUF4)); ++ ++ ++ ++ return p - buf; ++} ++ ++ssize_t vic_dma_debug(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct vic_device *vic = dev_get_drvdata(dev); ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int imagesize = 0; ++ unsigned int lineoffset = 0; ++ unsigned int num = 0; ++ int loop = 100; ++ struct file *fd = NULL; ++ mm_segment_t old_fs; ++ loff_t *pos; ++ int ret = 0; ++ ++ if (!strncmp(buf, "snapraw", sizeof("snapraw")-1)) { ++ if(!dma_debug_en) { ++ printk("please enable vic dma debug mode\ntry \"echo 1 > /sys/module/vic/parameters/dma_debug_en\"\n"); ++ return -EINVAL; ++ } ++ ++ lineoffset = input_fmt->format.width * 2; ++ imagesize = lineoffset * input_fmt->format.height; ++ dev_info(vic->dev, "width is %d,height is %d,imagesize is %d\n",input_fmt->format.width,input_fmt->format.height,imagesize); ++ if(input_fmt->format.width > VIC_DMA_OUTPUT_MAX_WIDTH){ ++ return -EINVAL; ++ } ++ if(vic->snap_paddr){ ++ return -EBUSY; ++ } ++ ++ if(vic->sensor_info->wdr_en) ++ num = 2; ++ else ++ num = 1; ++ vic->snap_vaddr = kmalloc(imagesize * num, GFP_KERNEL); ++ ++ if(vic->snap_vaddr){ ++ vic->snap_paddr = virt_to_phys((void *)vic->snap_vaddr); ++ vic_reg_writel(vic, VIC_DMA_RESET, 0x01); ++ vic_reg_writel(vic, VIC_DMA_RESOLUTION, input_fmt->format.width << 16 | input_fmt->format.height); ++ vic_reg_writel(vic, VIC_DMA_Y_STRID, lineoffset); ++ vic_reg_writel(vic, VIC_DMA_Y_CH0_BUF0, vic->snap_paddr); ++ if(vic->sensor_info->wdr_en) ++ vic_reg_writel(vic, VIC_DMA_Y_CH1_BUF0, vic->snap_paddr + imagesize); ++ vic_reg_writel(vic, VIC_DMA_CONFIG, ++ (1 << 31) // enable dma ++ | (num << 16) // get > max ++ | (0 << 3) // use buffer num ++ | (0 << 0) // raw ++ ); ++ while(loop){ ++ ret = wait_for_completion_interruptible(&vic->snap_comp); ++ if (ret >= 0) ++ break; ++ loop--; ++ } ++ if(!loop){ ++ dev_err(vic->dev, "snapraw timeout!\n"); ++ goto exit; ++ } ++ ++ vic->dma_complete = 0; ++ /* save raw */ ++ fd = filp_open("/tmp/snap.raw", O_CREAT | O_WRONLY | O_TRUNC, 00766); ++ if (fd < 0) { ++ dev_err(vic->dev, "Failed to open /tmp/snap.raw\n"); ++ goto exit; ++ } ++ ++ /* write file */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ pos = &(fd->f_pos); ++ vfs_write(fd, vic->snap_vaddr, imagesize, pos); ++ if(vic->sensor_info->wdr_en) ++ vfs_write(fd, vic->snap_vaddr + imagesize, imagesize, pos); ++ filp_close(fd, NULL); ++ set_fs(old_fs); ++ } ++ } ++ ++exit: ++ kfree(vic->snap_vaddr); ++ vic->snap_paddr = 0; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(dump_vic, S_IRUGO|S_IWUSR, dump_vic, NULL); ++static DEVICE_ATTR(vic_dma_debug, S_IRUGO|S_IWUSR, NULL, vic_dma_debug); ++ ++static struct attribute *vic_debug_attrs[] = { ++ &dev_attr_dump_vic.attr, ++#ifdef CONFIG_VIC_DMA_ROUTE ++ &dev_attr_vic_dma_debug.attr, ++#endif ++ NULL, ++}; ++ ++static struct attribute_group vic_debug_attr_group = { ++ .name = "debug", ++ .attrs = vic_debug_attrs, ++}; ++ ++int bypass_video_g_ctrl(struct file *file, void *fh, struct v4l2_control *a) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct isp_device *isp = ispcam->isp; ++ struct sensor_device *sensor = &isp->ispcam->sensor; ++ int ret = 0; ++ ++ ret = v4l2_g_ctrl(sensor->isd->sd->ctrl_handler, a); ++ if(ret < 0) { ++ dev_err(isp->dev, "failed to get ID:%d!\n", a->id); ++ } ++ return ret; ++} ++ ++int bypass_video_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct isp_device *isp = ispcam->isp; ++ struct sensor_device *sensor = &isp->ispcam->sensor; ++ int ret = 0; ++ ++ ret = v4l2_s_ctrl(NULL, sensor->isd->sd->ctrl_handler, a); ++ if(ret < 0) { ++ dev_err(isp->dev, "failed to set ID:%d!\n", a->id); ++ } ++ return ret; ++} ++ ++int vic_video_nr_map[3] = { ++ INGENIC_VIC0_VIDEO_NR, ++ INGENIC_VIC1_VIDEO_NR, ++ INGENIC_VIC2_VIDEO_NR, ++}; ++ ++static int vic_comp_bind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct vic_device *vic = dev_get_drvdata(comp); ++ struct ispcam_device *ispcam = (struct ispcam_device *)master_data; ++ struct v4l2_device *v4l2_dev = &ispcam->v4l2_dev; ++ struct v4l2_subdev *sd = &vic->sd; ++ int ret = 0; ++ int nr = vic_video_nr_map[ispcam->dev_nr]; ++ struct isp_video_device *ispvideo = &vic->ispvideo; ++ char name[32]; ++ ++ //dev_info(comp, "--------%s, %d \n", __func__, __LINE__); ++ /* link subdev to master.*/ ++ vic->ispcam = (void *)ispcam; ++ ispcam->vic = vic; ++ ++ v4l2_subdev_init(sd, &vic_subdev_ops); ++ ++ ++ sd->owner = THIS_MODULE; ++ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ strscpy(sd->name, dev_name(comp), sizeof(sd->name)); ++ v4l2_set_subdevdata(sd, vic); ++ ++ /* init vic pads. */ ++ vic->pads = kzalloc(sizeof(struct media_pad) * VIC_NUM_PADS, GFP_KERNEL); ++ if(!vic->pads) { ++ ret = -ENOMEM; ++ goto err_alloc_pads; ++ } ++ vic->pads[0].index = VIC_PAD_SINK; ++ vic->pads[0].flags = MEDIA_PAD_FL_SINK; /* CSI->VIC, MIPI Interface*/ ++ vic->pads[1].index = VIC_PAD_SOURCE; ++ vic->pads[1].flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&sd->entity, VIC_NUM_PADS, vic->pads); ++ ++ /*3. register v4l2_subdev*/ ++ sd->entity.function = MEDIA_ENT_F_IO_V4L; ++ ret = v4l2_device_register_subdev(v4l2_dev, sd); ++ if(ret < 0) { ++ dev_err(comp, "Failed to register v4l2_subdev for vic\n"); ++ goto err_subdev_register; ++ } ++ ++#ifdef CONFIG_VIC_DMA_ROUTE ++ init_completion(&vic->snap_comp); ++ ++ ispvideo->ispcam = ispcam; ++ ispvideo->bypass = 1; ++ sprintf(name, "%s", dev_name(vic->dev)); ++ ret = isp_video_init(ispvideo, name, &vic_video_ops); ++ if(ret < 0) { ++ /*TODO:*/ ++ ++ } ++ ++ ret = isp_video_register(ispvideo, &ispcam->v4l2_dev, nr); ++ if(ret < 0) { ++ /*TODO:*/ ++ }; ++#endif ++ ++err_subdev_register: ++err_alloc_pads: ++ ++ ++ return ret; ++} ++ ++ ++static void vic_comp_unbind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct vic_device *vic = dev_get_drvdata(comp); ++ ++ dev_info(comp, "---TODO: %p-----%s, %d \n", vic, __func__, __LINE__); ++ ++} ++ ++static const struct component_ops vic_comp_ops = { ++ .bind = vic_comp_bind, ++ .unbind = vic_comp_unbind, ++}; ++ ++static int vic_err[13] = {0}; ++ ++static irqreturn_t vic_irq_handler(int irq, void *data) ++{ ++ struct vic_device *vic = (struct vic_device *)data; ++ unsigned int status = 0; ++ unsigned int status2 = 0; ++ struct isp_video_buffer *isp_buffer = NULL; ++ unsigned int regval = 0; ++ unsigned int complete_num = 0; ++ ++ spin_lock(&vic->lock); ++ status = vic_reg_readl(vic, VIC_INT_STA); ++ status2 = vic_reg_readl(vic, VIC_INT_STA2); ++// printk("VIC_INT_STA=%x\n", status); ++// printk("VIC_INT_STA2=%x\n", status2); ++ /* DMA FRAME DONE */ ++ if(status2 & (1 << 0)) { ++ vic->frame_capture_counter++; ++ //printk(KERN_DEBUG "%d: vic->buffer_count=0x%x\n", vic->frame_capture_counter, vic->buffer_count); ++ ++#ifdef CONFIG_VIC_DMA_ROUTE ++ if(dma_debug_en){ ++ vic->dma_complete++; ++ } else { ++ isp_buffer = list_first_entry_or_null(&vic->dma_queued_list, struct isp_video_buffer, list_entry); ++ if(!isp_buffer) { ++ dev_err(vic->dev, "[warning] no isp_buffer found in dma_queued_list when interrupt happend!\n"); ++ goto done; ++ } ++ ++ list_del(&isp_buffer->list_entry); ++ vic->buffer_count--; ++ ++ isp_buffer->vb2.vb2_buf.timestamp = ktime_get_ns(); ++ isp_buffer->vb2.sequence = vic->framenum++; ++ ++ vb2_buffer_done(&isp_buffer->vb2.vb2_buf, VB2_BUF_STATE_DONE); ++ ++ if(vic->buffer_count <= VIC_STOP_BUFFER_COUNT) ++ { ++ vic->stop_flag = 1; ++ regval = vic_reg_readl(vic, VIC_DMA_CONFIG); ++ regval &= ~(1 << 31); ++ vic_reg_writel(vic, VIC_DMA_CONFIG, regval); ++ vic_stop_counter++; ++ goto done; ++ } ++ } ++#endif ++ } ++ ++ if(status2 & (1 << 1)) ++ if(dma_debug_en) ++ vic->dma_complete++; ++ ++#if 0 ++ if(status & (1 << 9)) { ++ //dev_err(vic->dev, ++ printk(KERN_DEBUG "vic->frame_capture_counter=%d, Image output limit too small! VIC_INT_STA=%x\n", vic->frame_capture_counter, status); ++ /* lgwang -- reset vic */ ++ vic->global_reset = 1; ++ vic_reg_writel(vic, VIC_CONTROL, 0x4); ++ vic->stop_flag = 1; ++ vic_stop_counter++; ++ } ++#endif ++ if((1 << 9) & status) { ++ vic_err[11]++; ++ dev_err(vic->dev, "Err [VIC_INT] : frame asfifo ovf!!!!!\n"); ++ } ++ if((1 << 10) & status) { ++ vic_err[0]++; ++ dev_err(vic->dev, "Err [VIC_INT] : hor err ch0 !!!!!\n"); ++ } ++ if((1 << 11) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : hor err ch1 !!!!!\n"); ++ } ++ if((1 << 12) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : hor err ch2 !!!!!\n"); ++ } ++ if((1 << 13) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : hor err ch3 !!!!!\n"); ++ } ++ if((1 << 14) & status) { ++ vic_err[1]++; ++ dev_err(vic->dev, "Err [VIC_INT] : ver err ch0 !!!!!\n"); ++ } ++ if((1 << 15) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : ver err ch1 !!!!!\n"); ++ } ++ if((1 << 16) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : ver err ch2 !!!!!\n"); ++ } ++ if((1 << 17) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : ver err ch3 !!!!!\n"); ++ } ++ if((1 << 18) & status) { ++ vic_err[2]++; ++ dev_err(vic->dev, "Err [VIC_INT] : hvf err !!!!!\n"); ++ } ++ if((1 << 19) & status) { ++ vic_err[3]++; ++ dev_err(vic->dev, "Err [VIC_INT] : dvp hcomp err!!!!\n"); ++ } ++ if((1 << 20) & status) { ++ vic_err[4]++; ++ dev_err(vic->dev, "Err [VIC_INT] : dma syfifo ovf!!!\n"); ++ } ++ if((1 << 21) & status) { ++ vic_err[5]++; ++ dev_err(vic->dev, "Err [VIC_INT] : control limit err!!!\n"); ++ } ++ if((1 << 22) & status) { ++ vic_err[6]++; ++ dev_err(vic->dev, "Err [VIC_INT] : image syfifo ovf !!!\n"); ++ } ++ if((1 << 23) & status) { ++ vic_err[7]++; ++ dev_err(vic->dev, "Err [VIC_INT] : mipi fid asfifo ovf!!!\n"); ++ } ++ if((1 << 24) & status) { ++ vic_err[8]++; ++ dev_err(vic->dev, "Err [VIC_INT] : mipi ch0 hcomp err !!!\n"); ++ } ++ if((1 << 25) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : mipi ch1 hcomp err !!!\n"); ++ } ++ if((1 << 26) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : mipi ch2 hcomp err !!!\n"); ++ } ++ if((1 << 27) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : mipi ch3 hcomp err !!!\n"); ++ } ++ if((1 << 28) & status) { ++ vic_err[9]++; ++ dev_err(vic->dev, "Err [VIC_INT] : mipi ch0 vcomp err !!!\n"); ++ } ++ if((1 << 29) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : mipi ch1 vcomp err !!!\n"); ++ } ++ if((1 << 30) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : mipi ch2 vcomp err !!!\n"); ++ } ++ if((1 << 31) & status) { ++ vic_err[12]++; ++ dev_err(vic->dev, "Err [VIC_INT] : mipi ch3 vcomp err !!!\n"); ++ } ++ ++ if(dma_debug_en) ++ { ++ if(vic->sensor_info->wdr_en) ++ complete_num = 2; ++ else ++ complete_num = 1; ++ ++ if(vic->dma_complete == complete_num) ++ { ++ vic_reg_writel(vic, VIC_DMA_CONFIG, 0); ++ complete(&vic->snap_comp); ++ } ++ } ++done: ++ vic_reg_writel(vic, VIC_INT_CLR, status); ++ vic_reg_writel(vic, VIC_INT_CLR2, status2); ++ spin_unlock(&vic->lock); ++ return IRQ_HANDLED; ++ ++} ++ ++static int ingenic_vic_probe(struct platform_device *pdev) ++{ ++ ++ struct vic_device *vic = NULL; ++ struct resource *regs = NULL; ++ int ret = 0; ++ ++ vic = kzalloc(sizeof(struct vic_device), GFP_KERNEL); ++ if(!vic) { ++ pr_err("Failed to alloc vic dev [%s]\n", pdev->name); ++ return -ENOMEM; ++ } ++ ++ vic->dev = &pdev->dev; ++ platform_set_drvdata(pdev, vic); ++ ++ ++ ingenic_vic_parse_dt(vic); ++ ++ vic->irq = platform_get_irq(pdev, 0); ++ if(vic->irq < 0) { ++ dev_warn(&pdev->dev, "No CSI IRQ specified\n"); ++ } ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(!regs) { ++ dev_err(&pdev->dev, "No iomem resource!\n"); ++ goto err_get_resource; ++ } ++ ++ vic->iobase = devm_ioremap_resource(&pdev->dev, regs); ++ if(!vic->iobase) { ++ goto err_ioremap; ++ } ++ ++ spin_lock_init(&vic->lock); ++ INIT_LIST_HEAD(&vic->dma_queued_list); ++ ++ ret = devm_request_irq(vic->dev, vic->irq, vic_irq_handler, 0, ++ dev_name(vic->dev), vic); ++ if(ret) { ++ dev_err(vic->dev, "request irq failed!\n"); ++ goto err_request_irq; ++ } ++ ++ ret = sysfs_create_group(&vic->dev->kobj, &vic_debug_attr_group); ++ if (ret) { ++ dev_err(vic->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_sys_group; ++ } ++ ++ ret = component_add(vic->dev, &vic_comp_ops); ++ if(ret < 0) { ++ dev_err(vic->dev, "Failed to add component vic!\n"); ++ goto err_component; ++ } ++ ++ return 0; ++err_component: ++err_sys_group: ++err_request_irq: ++err_ioremap: ++err_get_resource: ++ return ret; ++} ++ ++ ++ ++static int ingenic_vic_remove(struct platform_device *pdev) ++{ ++ ++ return 0; ++} ++ ++ ++ ++static const struct of_device_id ingenic_vic_dt_match[] = { ++ { .compatible = "ingenic,x2500-vic" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_vic_dt_match); ++ ++static int __maybe_unused ingenic_vic_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct vic_device *vic = dev_get_drvdata(&pdev->dev); ++ ++ if(vic->enabled){ ++ dev_err(vic->dev, "faild to suspend, vic is streaming on\n"); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static int __maybe_unused ingenic_vic_resume(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver ingenic_vic_driver = { ++ .probe = ingenic_vic_probe, ++ .remove = ingenic_vic_remove, ++ .suspend = ingenic_vic_suspend, ++ .resume = ingenic_vic_resume, ++ .driver = { ++ .name = "ingenic-vic", ++ .of_match_table = ingenic_vic_dt_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_vic_driver); ++ ++MODULE_ALIAS("platform:ingenic-vic"); ++MODULE_DESCRIPTION("ingenic vic subsystem"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/Kconfig b/module_drivers/drivers/media/platform/ingenic-isp/Kconfig +new file mode 100644 +index 000000000..d4a2e5b98 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/Kconfig +@@ -0,0 +1,113 @@ ++config VIC_DMA_ROUTE ++ bool "vic dma out route enable" ++ default n ++ depends on VIDEO_INGENIC_ISP ++ ++config MSCA_BDEV ++ bool "mscaler bdev support" ++ default n ++ depends on VIDEO_INGENIC_ISP ++ ++# halley5 board ++menuconfig HALLEY5_CAMERA_BOARD ++ bool "halley5_camera_board" ++ depends on VIDEO_INGENIC_ISP ++ default n ++ help ++ Say Y here to enable support for halley5_camera_boards. ++ ++config RD_X2000_HALLEY5_CAMERA_1V0 ++ bool "halley5 camera driver for RD_X2000_HALLEY5_CAMERA_1V0" ++ depends on HALLEY5_CAMERA_BOARD ++ select INGENIC_ISP_CAMERA_AR0144 ++ select INGENIC_ISP_CAMERA_AR0234 ++ ++config RD_X2000_HALLEY5_CAMERA_2V1 ++ bool "halley5 camera driver for RD_X2000_HALLEY5_CAMERA_2V1" ++ depends on HALLEY5_CAMERA_BOARD ++ select INGENIC_ISP_CAMERA_OV2735B ++ select INGENIC_ISP_CAMERA_OV2735A ++ ++config RD_X2000_HALLEY5_CAMERA_4V2 ++ bool "halley5 camera driver for RD_X2000_HALLEY5_CAMERA_4V2" ++ depends on HALLEY5_CAMERA_BOARD ++ select INGENIC_ISP_CAMERA_OV2735B ++ select INGENIC_ISP_CAMERA_OV2735A ++ ++config RD_X2000_HALLEY5_CAMERA_4V3 ++ bool "halley5 camera driver for RD_X2000_HALLEY5_CAMERA_4V3" ++ depends on HALLEY5_CAMERA_BOARD ++ select INGENIC_ISP_CAMERA_OV2735A ++ select V4L2_FWNODE ++ ++config RD_X2000_HALLEY5_CAMERA_3V2 ++ bool "halley5 camera driver for RD_X2000_HALLEY5_CAMERA_3V2" ++ depends on HALLEY5_CAMERA_BOARD ++ select INGENIC_ISP_CAMERA_OV4689 ++ ++choice ++ prompt "ov4689 resolution and frame rate select" ++ depends on RD_X2000_HALLEY5_CAMERA_3V2 ++ default OV4689_1080P_30FPS ++ help ++ Select ov4689 sensor's resolution and frame rate that driver supported. ++ ++config OV4689_1080P_120FPS ++ bool "OV4689_1080P_120fps" ++ depends on RD_X2000_HALLEY5_CAMERA_3V2 || CAMERA_V10 ++ ++config OV4689_1080P_30FPS ++ bool "OV4689_1080P_30fps" ++ depends on RD_X2000_HALLEY5_CAMERA_3V2 || CAMERA_V10 ++ ++config OV4689_2048X1520_30FPS ++ bool "ov4689_2048x1520_30fps" ++ depends on RD_X2000_HALLEY5_CAMERA_3V2 || CAMERA_V10 ++endchoice ++ ++config RD_X2000_HALLEY5_CAMERA_5V0 ++ bool "halley5 camera driver for RD_X2000_HALLEY5_CAMERA_5V0" ++ depends on HALLEY5_CAMERA_BOARD ++ select INGENIC_ISP_CAMERA_AR0144 ++ ++config RD_X2500_HIPPO_CAMERA_1V1 ++ bool "halley5 camera driver for RD_X2500_HIPPO_CAMERA_1V1" ++ depends on HALLEY5_CAMERA_BOARD ++ select INGENIC_ISP_CAMERA_SC230AI ++ ++# gewu board ++menuconfig GEWU_CAMERA_BOARD ++ bool "gewu_camera_board" ++ depends on VIDEO_INGENIC_ISP ++ default n ++ help ++ Say Y here to enable support for gewu_camera_boards. ++ ++config CAMERA_V10 ++ bool "gewu camera driver for CAMERA_1.0" ++ depends on GEWU_CAMERA_BOARD ++ select INGENIC_ISP_CAMERA_OV4689 ++ ++choice ++ prompt "ov4689 resolution and frame rate select" ++ depends on CAMERA_V10 ++ default GEWU_OV4689_1080P_30FPS ++ help ++ Select ov4689 sensor's resolution and frame rate that driver supported. ++ ++config GEWU_OV4689_1080P_120FPS ++ bool "OV4689_1080P_120fps" ++ select OV4689_1080P_120FPS ++ depends on CAMERA_V10 ++ ++config GEWU_OV4689_1080P_30FPS ++ bool "OV4689_1080P_30fps" ++ select OV4689_1080P_30FPS ++ depends on CAMERA_V10 ++ ++config GEWU_OV4689_2048X1520_30FPS ++ bool "ov4689_2048x1520_30fps" ++ select OV4689_2048X1520_30FPS ++ depends on CAMERA_V10 ++endchoice ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/Makefile b/module_drivers/drivers/media/platform/ingenic-isp/Makefile +new file mode 100644 +index 000000000..afd5f085b +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/Makefile +@@ -0,0 +1,20 @@ ++obj-y += isp-drv.o ++obj-y += csi.o ++obj-y += mscaler.o ++obj-y += vic.o ++obj-y += isp.o ++obj-y += sensor.o ++obj-y += isp-video.o ++obj-y += isp-core-tuning.o ++obj-$(CONFIG_MSCA_BDEV) += mscaler-bdev.o ++ ++ccflags-y += -I$(srctree)/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc ++ccflags-$(CONFIG_MSCA_BDEV) += -I$(srctree)/module_drivers/drivers/media/platform/ingenic-vcodec/helix ++obj-y += isp-core/ ++ ++FILE=$(srctree)/module_drivers/drivers/media/platform/ingenic-isp/isp-core/isp-core.a_shipped ++ifeq ($(FILE), $(wildcard $(FILE))) ++$(error "please remove overlay isp-core.a_shipped") ++endif ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/csi-regs.h b/module_drivers/drivers/media/platform/ingenic-isp/csi-regs.h +new file mode 100644 +index 000000000..56c0fddd8 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/csi-regs.h +@@ -0,0 +1,51 @@ ++#ifndef __INGENIC_ISP_CSI_H__ ++#define __INGENIC_ISP_CSI_H__ ++ ++#define VERSION 0x00 ++#define N_LANES 0x04 ++#define PHY_SHUTDOWNZ 0x08 ++#define DPHY_RSTZ 0x0C ++#define CSI2_RESETN 0x10 ++#define PHY_STATE 0x14 ++#define DATA_IDS_1 0x18 ++#define DATA_IDS_2 0x1C ++#define ERR1 0x20 ++#define ERR2 0x24 ++#define MASK1 0x28 ++#define MASK2 0x2C ++#define PHY_TST_CTRL0 0x30 ++#define PHY_TST_CTRL1 0x34 ++ ++#define VC0_FRAME_NUM 0x40 /*[31:16] FS End, [15:0] FS Start*/ ++#define VC1_FRAME_NUM 0x44 ++#define VC2_FRAME_NUM 0x48 ++#define VC3_FRAME_NUM 0x4c ++#define VC0_LINE_NUM 0x50 /*[31:16] Line End, [15:0] Line Start*/ ++#define VC1_LINE_NUM 0x54 ++#define VC2_LINE_NUM 0x58 ++#define VC3_LINE_NUM 0x60 ++ ++#define csi_readl(port, reg) \ ++ __raw_readl((unsigned int *)((port)->base + reg)) ++#define csi_writel(port, reg, value) \ ++ __raw_writel((value), (unsigned int *)((port)->base + reg)) ++ ++#define csi_core_writel(csi, addr, value) \ ++ writel(value, (unsigned int *)((csi)->iobase + addr)) ++#define csi_core_readl(csi, addr) \ ++ readl((unsigned int *)((csi)->iobase + addr)) ++ ++ ++#define CSI_PHY_IOBASE 0x10076000 ++#define CSI_PHY_1C2C_MODE 0xc4 ++#define CSI_PHY_PRECOUNTER_IN_CLK 0xb8 ++#define CSI_PHY_PRECOUNTER_IN_DATA 0xbc ++ ++#define csi_phy_writel(csi, addr, value) \ ++ writel(value, (unsigned int *)((csi)->phy_base + addr)) ++ ++#define csi_phy_readl(csi, addr) \ ++ readl((unsigned int *)((csi)->phy_base + addr)) ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/csi.c b/module_drivers/drivers/media/platform/ingenic-isp/csi.c +new file mode 100644 +index 000000000..4df28ed54 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/csi.c +@@ -0,0 +1,482 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "isp-drv.h" ++#include "csi-regs.h" ++ ++static const struct v4l2_subdev_core_ops csi_subdev_core_ops = { ++ .log_status = v4l2_ctrl_subdev_log_status, ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static int csi_subdev_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct csi_device *csi = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ int ret = 0; ++ ++ remote = media_entity_remote_pad(&csi->pads[CSI_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ ret = v4l2_subdev_call(remote_sd, pad, set_fmt, NULL, format); ++ if(ret < 0) { ++ dev_dbg(csi->dev, "Failed to set_fmt from remote pad\n"); ++ } ++ ++ return 0; ++} ++static int csi_subdev_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct csi_device *csi = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ struct v4l2_subdev_format remote_subdev_fmt; ++ int ret = 0; ++ ++ remote = media_entity_remote_pad(&csi->pads[CSI_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ /*èŽ·å–æºå½“剿 ¼å¼ï¼Œå¤åˆ¶åˆ°è¾“出格å¼.*/ ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_err(csi->dev, "Failed to get_fmt from remote pad\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(&format->format, &remote_subdev_fmt.format, sizeof(format->format)); ++ ++ //printk("----%s, %d, format->pad: %d\n", __func__, __LINE__, format->pad); ++ return 0; ++} ++ ++ ++static const struct v4l2_subdev_pad_ops csi_subdev_pad_ops = { ++ .set_fmt = csi_subdev_set_fmt, ++ .get_fmt = csi_subdev_get_fmt, ++ /* ++ .init_cfg = csi_subdev_init_cfg, ++ .enum_mbus_code = csi_subdev_enum_mbus_code, ++ .enum_frame_size = csi_subdev_enum_frame_size, ++ .get_fmt = csi_subdev_get_fmt, ++ */ ++}; ++ ++struct phy_reseter { ++ struct csi_device *csi[2]; ++ unsigned int phy_started[2]; ++}; ++ ++struct phy_reseter global_phy_reseter = { ++ .csi = {NULL, NULL}, ++ .phy_started = {0, 0} ++}; ++ ++DEFINE_SPINLOCK(reset_lock); ++ ++static unsigned char csi_core_write_part(struct csi_device *csi,unsigned int address, ++ unsigned int data, unsigned char shift, unsigned char width) ++{ ++ unsigned int mask = (1 << width) - 1; ++ unsigned int temp = csi_core_readl(csi, address); ++ ++ temp &= ~(mask << shift); ++ temp |= (data & mask) << shift; ++ csi_core_writel(csi, address, temp); ++ ++ return 0; ++} ++ ++static inline int csi_core_write_io(unsigned int iobase, unsigned int address, unsigned int data, unsigned char shift, unsigned char width) ++{ ++ unsigned int mask = (1 << width) - 1; ++ unsigned int temp = readl((unsigned int *)(iobase + address)); ++ ++ temp &= ~(mask << shift); ++ temp |= (data & mask) << shift; ++ writel(temp, (unsigned int *)(iobase + address)); ++ return 0; ++} ++ ++ ++#define CSI0_IOBASE 0xb0074000 ++#define CSI1_IOBASE 0xb0073000 ++static int csi_phy_start(struct csi_device *csi, struct phy_reseter *reseter) ++{ ++ unsigned long flags; ++ /*already reseted.*/ ++ spin_lock_irqsave(&reset_lock, flags); ++ if(reseter->phy_started[0] || reseter->phy_started[1]) { ++ reseter->phy_started[csi->reset_index] = 1; ++ spin_unlock_irqrestore(&reset_lock, flags); ++ return 0; ++ } ++ ++ /* CSI0 and CSI1 reset at the same time. */ ++ csi_core_write_io(CSI0_IOBASE, DPHY_RSTZ, 0, 0, 1); ++ csi_core_write_io(CSI1_IOBASE, DPHY_RSTZ, 0, 0, 1); ++ ++ csi_core_write_io(CSI0_IOBASE, DPHY_RSTZ, 1, 0, 1); ++ csi_core_write_io(CSI1_IOBASE, DPHY_RSTZ, 1, 0, 1); ++ ++ reseter->phy_started[csi->reset_index] = 1; ++ spin_unlock_irqrestore(&reset_lock, flags); ++ ++ ++ return 0; ++} ++ ++static void csi_phy_stop(struct csi_device *csi, struct phy_reseter *reseter) ++{ ++ ++ unsigned long flags; ++ ++ /* CSI2_RESET */ ++ spin_lock_irqsave(&reset_lock, flags); ++ csi_core_write_part(csi, CSI2_RESETN, 0, 0, 1); ++ ++ reseter->phy_started[csi->reset_index] = 0; ++ ++ if((reseter->phy_started[0] == 0) && (reseter->phy_started[1] == 0)) { ++ /* shutdown phy. */ ++ csi_core_write_io(CSI0_IOBASE, DPHY_RSTZ, 0, 0, 1); ++ csi_core_write_io(CSI1_IOBASE, DPHY_RSTZ, 0, 0, 1); ++ } ++ ++ spin_unlock_irqrestore(&reset_lock, flags); ++} ++ ++static int csi_subdev_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct csi_device *csi = v4l2_get_subdevdata(sd); ++ struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = ispcam_get_bus_mipi_csi2(csi->ispcam); ++ unsigned short nlanes = mipi_csi2->num_data_lanes; ++ ++ if(enable) { ++ if(csi->enabled++ > 0) { ++ return 0; ++ } ++ ++ if(nlanes > 2) ++ csi_phy_writel(csi, CSI_PHY_1C2C_MODE, 0); /*1c mode.*/ ++ else ++ csi_phy_writel(csi, CSI_PHY_1C2C_MODE, 1); /*2c mode.*/ ++ csi_core_writel(csi, N_LANES, nlanes - 1); ++ csi_phy_start(csi, &global_phy_reseter); ++ ++ /* CSI2_RESET */ ++ csi_core_write_part(csi, CSI2_RESETN, 0, 0, 1); ++ csi_core_write_part(csi, CSI2_RESETN, 1, 0, 1); ++ ++ } else { ++ ++ if(--csi->enabled > 0) { ++ return 0; ++ } ++ csi_phy_stop(csi, &global_phy_reseter); ++ } ++ ++ return 0; ++} ++ ++ ++static const struct v4l2_subdev_video_ops csi_subdev_video_ops = { ++ .s_stream = csi_subdev_s_stream, ++}; ++ ++ ++static const struct v4l2_subdev_ops csi_subdev_ops = { ++ .core = &csi_subdev_core_ops, ++ .pad = &csi_subdev_pad_ops, ++ .video = &csi_subdev_video_ops, ++}; ++ ++static ssize_t ++dump_csi(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct csi_device *csi = dev_get_drvdata(dev); ++ char *p = buf; ++ ++ p += sprintf(p, "VERSION :0x%08x\n", csi_core_readl(csi, VERSION)); ++ p += sprintf(p, "N_LANES :0x%08x\n", csi_core_readl(csi, N_LANES)); ++ p += sprintf(p, "PHY_SHUTDOWNZ :0x%08x\n", csi_core_readl(csi, PHY_SHUTDOWNZ)); ++ p += sprintf(p, "DPHY_RSTZ :0x%08x\n", csi_core_readl(csi, DPHY_RSTZ)); ++ p += sprintf(p, "CSI2_RESETN :0x%08x\n", csi_core_readl(csi, CSI2_RESETN)); ++ p += sprintf(p, "PHY_STATE :0x%08x\n", csi_core_readl(csi, PHY_STATE)); ++ p += sprintf(p, "DATA_IDS_1 :0x%08x\n", csi_core_readl(csi, DATA_IDS_1)); ++ p += sprintf(p, "DATA_IDS_2 :0x%08x\n", csi_core_readl(csi, DATA_IDS_2)); ++ p += sprintf(p, "ERR1 :0x%08x\n", csi_core_readl(csi, ERR1)); ++ p += sprintf(p, "ERR2 :0x%08x\n", csi_core_readl(csi, ERR2)); ++ p += sprintf(p, "MASK1 :0x%08x\n", csi_core_readl(csi, MASK1)); ++ p += sprintf(p, "MASK2 :0x%08x\n", csi_core_readl(csi, MASK2)); ++ p += sprintf(p, "PHY_TST_CTRL0 :0x%08x\n", csi_core_readl(csi, PHY_TST_CTRL0)); ++ p += sprintf(p, "PHY_TST_CTRL1 :0x%08x\n", csi_core_readl(csi, PHY_TST_CTRL1)); ++ p += sprintf(p, "VC0_FRAME_NUM :0x%08x\n", csi_core_readl(csi, VC0_FRAME_NUM)); ++ p += sprintf(p, "VC1_FRAME_NUM :0x%08x\n", csi_core_readl(csi, VC1_FRAME_NUM)); ++ p += sprintf(p, "VC2_FRAME_NUM :0x%08x\n", csi_core_readl(csi, VC2_FRAME_NUM)); ++ p += sprintf(p, "VC3_FRAME_NUM :0x%08x\n", csi_core_readl(csi, VC3_FRAME_NUM)); ++ p += sprintf(p, "VC0_LINE_NUM :0x%08x\n", csi_core_readl(csi, VC0_LINE_NUM)); ++ p += sprintf(p, "VC1_LINE_NUM :0x%08x\n", csi_core_readl(csi, VC1_LINE_NUM)); ++ p += sprintf(p, "VC2_LINE_NUM :0x%08x\n", csi_core_readl(csi, VC2_LINE_NUM)); ++ p += sprintf(p, "VC3_LINE_NUM :0x%08x\n", csi_core_readl(csi, VC3_LINE_NUM)); ++ ++ p += sprintf(p, "CSI_PHY_1C2C_MODE :0x%08x\n", csi_phy_readl(csi, CSI_PHY_1C2C_MODE)); ++ ++ return p - buf; ++} ++ ++ ++static DEVICE_ATTR(dump_csi, S_IRUGO|S_IWUSR, dump_csi, NULL); ++ ++static struct attribute *csi_debug_attrs[] = { ++ &dev_attr_dump_csi.attr, ++ NULL, ++}; ++ ++static struct attribute_group csi_debug_attr_group = { ++ .name = "debug", ++ .attrs = csi_debug_attrs, ++}; ++ ++ ++static int csi_comp_bind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct csi_device *csi = dev_get_drvdata(comp); ++ struct ispcam_device *ispcam = (struct ispcam_device *)master_data; ++ struct v4l2_device *v4l2_dev = &ispcam->v4l2_dev; ++ struct v4l2_subdev *sd = &csi->sd; ++ int ret = 0; ++ ++ //dev_info(comp, "----dev_name(comp): %s----%s, %d \n", dev_name(comp), __func__, __LINE__); ++ ++ /* link subdev to master.*/ ++ csi->ispcam = (void *)ispcam; ++ ispcam->csi = csi; ++ ++ /*1. register supported subdev ctrls.*/ ++ ++ ++ /*2. init v4l2_subdev*/ ++ ++ v4l2_subdev_init(sd, &csi_subdev_ops); ++ ++ sd->owner = THIS_MODULE; ++ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ strscpy(sd->name, dev_name(comp), sizeof(sd->name)); ++ v4l2_set_subdevdata(sd, csi); ++ ++ ++ /* init csi pads. */ ++ csi->pads = kzalloc(sizeof(struct media_pad) * CSI_NUM_PADS, GFP_KERNEL); ++ if(!csi->pads) { ++ ret = -ENOMEM; ++ goto err_alloc_pads; ++ } ++ csi->pads[0].index = CSI_PAD_SINK; ++ csi->pads[0].flags = MEDIA_PAD_FL_SINK; ++ csi->pads[1].index = CSI_PAD_SOURCE; ++ csi->pads[1].flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&sd->entity, CSI_NUM_PADS, csi->pads); ++ ++ /*3. register v4l2_subdev*/ ++ sd->entity.function = MEDIA_ENT_F_IO_V4L; ++ ret = v4l2_device_register_subdev(v4l2_dev, sd); ++ if(ret < 0) { ++ dev_err(comp, "Failed to register v4l2_subdev for csi\n"); ++ goto err_subdev_register; ++ } ++ ++ ++ return 0; ++err_subdev_register: ++err_alloc_pads: ++ return ret; ++} ++ ++ ++static void csi_comp_unbind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct csi_device *csi = dev_get_drvdata(comp); ++ ++ dev_info(comp, "----TODO-implement unbind: %p---%s, %d \n",csi, __func__, __LINE__); ++} ++ ++ ++ ++static const struct component_ops csi_comp_ops = { ++ .bind = csi_comp_bind, ++ .unbind = csi_comp_unbind, ++}; ++ ++ ++static int ingenic_csi_probe(struct platform_device *pdev) ++{ ++ ++ struct csi_device *csi = NULL; ++ struct resource *regs = NULL; ++ ++ int ret = 0; ++ int i = 0; ++ ++ csi = kzalloc(sizeof(struct csi_device), GFP_KERNEL); ++ if(!csi) { ++ pr_err("Failed to alloc csi dev [%s]\n", pdev->name); ++ return -ENOMEM; ++ } ++ ++ csi->dev = &pdev->dev; ++ platform_set_drvdata(pdev, csi); ++ dev_set_drvdata(csi->dev, csi); ++ ++ csi->irq = platform_get_irq(pdev, 0); ++ if(csi->irq < 0) { ++ dev_warn(&pdev->dev, "No CSI IRQ specified\n"); ++ } ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(!regs) { ++ dev_err(&pdev->dev, "No iomem resource!\n"); ++ goto err_get_resource; ++ } ++ ++ csi->iobase = devm_ioremap_resource(&pdev->dev, regs); ++ if(!csi->iobase) { ++ goto err_ioremap; ++ } ++ ++ of_property_read_u32(csi->dev->of_node, "clk_precounter", &csi->clk_precounter); ++ of_property_read_u32(csi->dev->of_node, "data_precounter", &csi->data_precounter); ++ ++ csi->phy_base = CSI_PHY_IOBASE | 0xa0000000; ++ ++ /*TODO: clk*/ ++ csi->gate_clk = of_clk_get(csi->dev->of_node, 0); ++ if(!csi->gate_clk) { ++ dev_err(csi->dev, "failed to get gate clk\n"); ++ goto err_gate_clk; ++ } ++ clk_prepare_enable(csi->gate_clk); ++ ++ if(csi->clk_precounter) ++ csi_phy_writel(csi, CSI_PHY_PRECOUNTER_IN_CLK, csi->clk_precounter); ++ if(csi->data_precounter) ++ csi_phy_writel(csi, CSI_PHY_PRECOUNTER_IN_DATA, csi->data_precounter); ++ ++ ret = sysfs_create_group(&csi->dev->kobj, &csi_debug_attr_group); ++ if (ret) { ++ dev_err(csi->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_sys_group; ++ } ++ ++ for(i = 0; i < 2; i++) { ++ if(global_phy_reseter.csi[i] == NULL) { ++ global_phy_reseter.csi[i] = csi; ++ csi->reset_index = i; ++ break; ++ } ++ } ++ ++ ret = component_add(csi->dev, &csi_comp_ops); ++ if(ret < 0) { ++ dev_err(csi->dev, "Failed to add component csi!\n"); ++ } ++ ++ return 0; ++err_sys_group: ++err_gate_clk: ++err_ioremap: ++err_get_resource: ++ ++ return ret; ++} ++ ++ ++ ++static int ingenic_csi_remove(struct platform_device *pdev) ++{ ++ struct csi_device *csi = dev_get_drvdata(&pdev->dev); ++ ++ clk_disable_unprepare(csi->gate_clk); ++ return 0; ++} ++ ++ ++ ++static const struct of_device_id ingenic_csi_dt_match[] = { ++ { .compatible = "ingenic,x2000-csi" }, ++ { .compatible = "ingenic,m300-csi" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_csi_dt_match); ++ ++static int __maybe_unused ingenic_csi_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct csi_device *csi = dev_get_drvdata(&pdev->dev); ++ ++ if(csi->enabled){ ++ dev_err(csi->dev, "faild to suspend, csi is streaming on\n"); ++ return -EBUSY; ++ } ++ ++ clk_disable_unprepare(csi->gate_clk); ++ return 0; ++} ++ ++static int __maybe_unused ingenic_csi_resume(struct platform_device *pdev) ++{ ++ struct csi_device *csi = dev_get_drvdata(&pdev->dev); ++ ++ clk_prepare_enable(csi->gate_clk); ++ return 0; ++} ++ ++ ++static struct platform_driver ingenic_csi_driver = { ++ .probe = ingenic_csi_probe, ++ .remove = ingenic_csi_remove, ++ .suspend = ingenic_csi_suspend, ++ .resume = ingenic_csi_resume, ++ .driver = { ++ .name = "ingenic-csi", ++ .of_match_table = ingenic_csi_dt_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_csi_driver); ++ ++MODULE_ALIAS("platform:ingenic-csi"); ++MODULE_DESCRIPTION("ingenic csi subsystem"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core-tuning.c b/module_drivers/drivers/media/platform/ingenic-isp/isp-core-tuning.c +new file mode 100644 +index 000000000..cb05679f1 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core-tuning.c +@@ -0,0 +1,1130 @@ ++#include ++#include ++#include ++#include "isp-drv.h" ++ ++static inline int apical_isp_hflip_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ int ret = 0; ++ unsigned int value = 0; ++ value = isp->ctrls.hflip; ++ ++ tisp_mirror_enable(&core->core_tuning, value); ++ ++ return ret; ++} ++ ++static inline int apical_isp_vflip_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ int ret = 0; ++ unsigned int value = 0; ++ value = isp->ctrls.vflip; ++ ++ tisp_flip_enable(&core->core_tuning, value); ++ ++ return ret; ++} ++ ++static inline int apical_isp_sat_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct vic_device *vic = ispcam->vic; ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int value = 128; ++ int ret = 0; ++ ++ if (input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16) { ++ return ret; ++ } ++ /* the original value */ ++ value = isp->ctrls.sat & 0xff; ++ tisp_set_saturation(&core->core_tuning, value); ++ ++ return ret; ++} ++ ++static inline int apical_isp_sat_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct vic_device *vic = ispcam->vic; ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int value = 128; ++ int ret = 0; ++ ++ if(input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16){ ++ return ret; ++ } ++ /* the original value */ ++ value = tisp_get_saturation(&core->core_tuning); ++ isp->ctrls.contrast = value; ++ ++ return ret; ++} ++ ++static inline int apical_isp_bright_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct vic_device *vic = ispcam->vic; ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int value = 128; ++ int ret = 0; ++ ++ if (input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16) { ++ return ret; ++ } ++ /* the original value */ ++ value = isp->ctrls.bright & 0xff; ++ tisp_set_brightness(&core->core_tuning, value); ++ ++ return ret; ++} ++ ++static inline int apical_isp_bright_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct vic_device *vic = ispcam->vic; ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int value = 128; ++ int ret = 0; ++ ++ if (input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16) { ++ return ret; ++ } ++ /* the original value */ ++ value = tisp_get_brightness(&core->core_tuning); ++ isp->ctrls.bright = value; ++ ++ return ret; ++} ++ ++static inline int apical_isp_contrast_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct vic_device *vic = ispcam->vic; ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int value = 128; ++ int ret = 0; ++ ++ if (input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16) { ++ return ret; ++ } ++ /* the original value */ ++ value = isp->ctrls.contrast & 0xff; ++ tisp_set_contrast(&core->core_tuning, value); ++ ++ return ret; ++} ++ ++static inline int apical_isp_contrast_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct vic_device *vic = ispcam->vic; ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int value = 128; ++ int ret = 0; ++ ++ if (input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16) { ++ return ret; ++ } ++ /* the original value */ ++ value = tisp_get_contrast(&core->core_tuning); ++ isp->ctrls.contrast = value; ++ ++ return ret; ++} ++ ++static inline int apical_isp_sharp_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct vic_device *vic = ispcam->vic; ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int value = 128; ++ int ret = 0; ++ ++ if(input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16){ ++ return ret; ++ } ++ /* the original value */ ++ value = isp->ctrls.sharp & 0xff; ++ tisp_set_sharpness(&core->core_tuning, value); ++ ++ return ret; ++} ++ ++static inline int apical_isp_sharp_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct vic_device *vic = ispcam->vic; ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int value = 128; ++ int ret = 0; ++ ++ if (input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16) { ++ return ret; ++ } ++ /* the original value */ ++ value = tisp_get_sharpness(&core->core_tuning); ++ isp->ctrls.sharp = value; ++ ++ return ret; ++} ++ ++ ++static int ispcore_exp_auto_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_ev_attr_t ae_attr; ++ int ret = 0; ++ /* ++ * control->value. ++ * 0: 自动æ›å…‰. ++ * 1: 手动æ›å…‰. ++ * 2. 快门优先. ++ * 3. 光圈优先. ++ * */ ++ ++ ret = tisp_g_ev_attr(&core->core_tuning, &ae_attr); ++ if (isp->ctrls.exp_auto == V4L2_EXPOSURE_AUTO) { ++ ae_attr.manual_it = 0; ++ } else if(isp->ctrls.exp_auto == V4L2_EXPOSURE_MANUAL) { ++ ae_attr.manual_it = 1; ++ } ++ ++ ret = tisp_s_ae_attr(&core->core_tuning, ae_attr); ++ ++ return ret; ++} ++ ++/* 获å–当剿›å…‰æ–¹å¼.*/ ++static int ispcore_exp_auto_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_ev_attr_t ae_attr; ++ int ret = 0; ++ ++ ret = tisp_g_ev_attr(&core->core_tuning, &ae_attr); ++ ++ isp->ctrls.exp_auto = ae_attr.manual_it == 0 ? V4L2_EXPOSURE_AUTO : V4L2_EXPOSURE_MANUAL; ++ ++ return ret; ++} ++ ++/* 设置æ›å…‰ç­‰çº§. eg: [-4, 4] ++ * ++ * 相对æ›å…‰æ—¶é—´. 从 [-4, 4] -> [inte_min, inte_max] ++ * */ ++static int ispcore_exp_s_control(tisp_core_t *core) ++{ ++ ++ return 0; ++} ++ ++static int ispcore_exp_g_control(tisp_core_t *core) ++{ ++ ++ return 0; ++} ++ ++/* 设置æ›å…‰æ—¶é—´. */ ++static int ispcore_exp_abs_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_ev_attr_t ae_attr; ++ int ret = 0; ++ ++ ret = tisp_g_ev_attr(&core->core_tuning, &ae_attr); ++ if (ae_attr.manual_it) { ++ ae_attr.integration_time = isp->ctrls.exp_abs; ++ ret = tisp_s_ae_attr(&core->core_tuning, ae_attr); ++ } else { ++ dev_warn(isp->dev, "set exp_abs while in exposure [auto] mode.\n"); ++ } ++ ++ return ret; ++} ++ ++static int ispcore_exp_abs_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_ev_attr_t ae_attr; ++ int ret = 0; ++ ++ ret = tisp_g_ev_attr(&core->core_tuning, &ae_attr); ++ ++ isp->ctrls.exp_abs = ae_attr.integration_time; ++ ++ return ret; ++} ++ ++/*è®¾ç½®è‡ªåŠ¨å¢žç›ŠæŽ§åˆ¶æ–¹å¼ ++ * 0: 自动增益控制 ++ * 1: 手动增益控制. ++ * */ ++static inline int ispcore_auto_gain_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_ev_attr_t ae_attr; ++ int ret = 0; ++ ret = tisp_g_ev_attr(&core->core_tuning, &ae_attr); ++ ++ if (isp->ctrls.auto_gain == 0 ) { ++ ae_attr.manual_ag = 0; ++ } else if (isp->ctrls.auto_gain == 1 ){ ++ ae_attr.manual_ag = 1; ++ } ++ ++ ret = tisp_s_ae_attr_ag(&core->core_tuning, ae_attr); ++ ++ return ret; ++} ++ ++/*获å–自动增益控制方å¼.*/ ++static inline int ispcore_auto_gain_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_ev_attr_t ae_attr; ++ int ret = 0; ++ ret = tisp_g_ev_attr(&core->core_tuning, &ae_attr); ++ ++ isp->ctrls.auto_gain = ae_attr.manual_ag; ++ ++ return ret; ++} ++ ++/*手动增益控制模å¼ä¸‹ï¼Œè®¾ç½®å½“å‰å¢žç›Š.*/ ++static inline int ispcore_gain_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_ev_attr_t ae_attr; ++ int ret = 0; ++ ret = tisp_g_ev_attr(&core->core_tuning, &ae_attr); ++ ++ if (ae_attr.manual_ag) { ++ ae_attr.again = isp->ctrls.gain; ++ ret = tisp_s_ae_attr_ag(&core->core_tuning, ae_attr); ++ } else { ++ dev_warn(isp->dev, "set gain_s warning while in gain mode.\n"); ++ } ++ ++ return ret; ++} ++ ++static inline int ispcore_gain_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_ev_attr_t ae_attr; ++ int ret = 0; ++ ret = tisp_g_ev_attr(&core->core_tuning, &ae_attr); ++ ++ isp->ctrls.gain = ae_attr.again; ++ ++ return ret; ++} ++ ++static inline int ispcore_auto_wb_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_wb_attr_t *wb_attr = &isp->ctrls.wb_attr; ++ int ret = 0; ++ ++ ret = tisp_s_wb_frz_attr(&core->core_tuning, 0); ++ switch(isp->ctrls.auto_wb) { ++ case 1: ++ wb_attr->tisp_wb_manual = 0; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ break; ++ case 0: ++ wb_attr->tisp_wb_manual = 1; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ ret = tisp_s_wb_frz_attr(&core->core_tuning, 1); ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++ ++static inline int ispcore_auto_n_wb_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_wb_attr_t *wb_attr = &isp->ctrls.wb_attr; ++ int ret = 0; ++ ++ ret = tisp_s_wb_frz_attr(&core->core_tuning, 0); ++ switch(isp->ctrls.wb) { ++ case V4L2_WHITE_BALANCE_AUTO: ++ wb_attr->tisp_wb_manual = 0; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ break; ++ case V4L2_WHITE_BALANCE_MANUAL: ++ wb_attr->tisp_wb_manual = 1; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ ret = tisp_s_wb_frz_attr(&core->core_tuning, 1); ++ break; ++ case V4L2_WHITE_BALANCE_FLASH: ++ wb_attr->tisp_wb_manual = 2; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ break; ++ case V4L2_WHITE_BALANCE_FLUORESCENT: ++ wb_attr->tisp_wb_manual = 3; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ break; ++ case V4L2_WHITE_BALANCE_CLOUDY: ++ wb_attr->tisp_wb_manual = 4; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ break; ++ case V4L2_WHITE_BALANCE_HORIZON: ++ wb_attr->tisp_wb_manual = 5; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ break; ++ case V4L2_WHITE_BALANCE_DAYLIGHT: ++ wb_attr->tisp_wb_manual = 6; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ break; ++ case V4L2_WHITE_BALANCE_FLUORESCENT_H: ++ wb_attr->tisp_wb_manual = 7; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ break; ++ case V4L2_WHITE_BALANCE_INCANDESCENT: ++ wb_attr->tisp_wb_manual = 8; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ break; ++ case V4L2_WHITE_BALANCE_SHADE: ++ wb_attr->tisp_wb_manual = 9; ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ ret = tisp_s_wb_frz_attr(&core->core_tuning, 1); ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++ ++static inline int ispcore_red_wb_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_wb_attr_t *wb_attr = &isp->ctrls.wb_attr; ++ int ret = 0; ++ ++ wb_attr->tisp_wb_rg = isp->ctrls.red_wb; ++ return ret; ++} ++ ++ ++static inline int ispcore_blue_wb_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_wb_attr_t *wb_attr = &isp->ctrls.wb_attr; ++ int ret = 0; ++ ++ wb_attr->tisp_wb_bg = isp->ctrls.blue_wb; ++ return ret; ++} ++ ++ ++static inline int ispcore_do_wb_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_wb_attr_t *wb_attr = &isp->ctrls.wb_attr; ++ int ret = 0; ++ ++ ret = tisp_s_wb_frz_attr(&core->core_tuning, 0); ++ ret = tisp_s_wb_attr(&core->core_tuning, *wb_attr); ++ return ret; ++} ++ ++ ++static inline int ispcore_auto_wb_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_wb_attr_t wb_attr; ++ int ret = 0; ++ ++ ret = tisp_g_wb_attr(&core->core_tuning, &wb_attr); ++ switch( wb_attr.tisp_wb_manual ) { ++ case 0: ++ isp->ctrls.auto_wb = V4L2_WHITE_BALANCE_AUTO; ++ break; ++ case 1: ++ isp->ctrls.auto_wb = V4L2_WHITE_BALANCE_MANUAL; ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++ ++static inline int ispcore_auto_n_wb_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_wb_attr_t wb_attr; ++ int ret = 0; ++ ++ ret = tisp_g_wb_attr(&core->core_tuning, &wb_attr); ++ switch( wb_attr.tisp_wb_manual ) { ++ case 0: ++ isp->ctrls.wb = V4L2_WHITE_BALANCE_AUTO; ++ break; ++ case 1: ++ isp->ctrls.wb = V4L2_WHITE_BALANCE_MANUAL; ++ break; ++ case 2: ++ isp->ctrls.wb = V4L2_WHITE_BALANCE_FLASH; ++ break; ++ case 3: ++ isp->ctrls.wb = V4L2_WHITE_BALANCE_FLUORESCENT; ++ break; ++ case 4: ++ isp->ctrls.wb = V4L2_WHITE_BALANCE_CLOUDY; ++ break; ++ case 5: ++ isp->ctrls.wb = V4L2_WHITE_BALANCE_HORIZON; ++ break; ++ case 6: ++ isp->ctrls.wb = V4L2_WHITE_BALANCE_DAYLIGHT; ++ break; ++ case 7: ++ isp->ctrls.wb = V4L2_WHITE_BALANCE_FLUORESCENT_H; ++ break; ++ case 8: ++ isp->ctrls.wb = V4L2_WHITE_BALANCE_INCANDESCENT; ++ break; ++ case 9: ++ isp->ctrls.wb = V4L2_WHITE_BALANCE_SHADE; ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++static inline int ispcore_red_wb_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_wb_attr_t wb_attr; ++ int ret = 0; ++ ++ ret = tisp_g_wb_attr(&core->core_tuning, &wb_attr); ++ if (wb_attr.tisp_wb_manual == 0) { ++ isp->ctrls.red_wb = 65536 / wb_attr.tisp_wb_rg_sta_weight; ++ } else { ++ isp->ctrls.red_wb = wb_attr.tisp_wb_rg; ++ } ++ return ret; ++} ++ ++static inline int ispcore_blue_wb_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ tisp_wb_attr_t wb_attr; ++ int ret = 0; ++ ++ ret = tisp_g_wb_attr(&core->core_tuning, &wb_attr); ++ if (wb_attr.tisp_wb_manual == 0) { ++ isp->ctrls.blue_wb = 65536 / wb_attr.tisp_wb_bg_sta_weight; ++ } else { ++ isp->ctrls.blue_wb = wb_attr.tisp_wb_bg; ++ } ++ return ret; ++} ++ ++ ++static inline int apical_isp_hilightdepress_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct vic_device *vic = ispcam->vic; ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int value = 0; ++ int ret = 0; ++ ++ if(input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16){ ++ return ret; ++ } ++ value = isp->ctrls.hill; ++ ret = tisp_s_Hilightdepress(&core->core_tuning, value); ++ ++ return ret; ++} ++ ++ ++static inline int apical_isp_hilightdepress_g_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct vic_device *vic = ispcam->vic; ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ int ret=0; ++ ++ if(input_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16){ ++ return -1; ++ } ++ ret = tisp_g_Hilightdepress(&core->core_tuning, &isp->ctrls.hill); ++ ++ return 0; ++} ++ ++ ++static inline int flicker_value_v4l2_to_tuning(int val) ++{ ++ int ret = 0; ++ switch(val){ ++ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: ++ ret = 0; ++ break; ++ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: ++ ret = 50; ++ break; ++ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: ++ ret = 60; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++ ++static inline int apical_isp_flicker_s_control(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ int ret = 0; ++ ++ ret = tisp_s_antiflick(&core->core_tuning, flicker_value_v4l2_to_tuning(isp->ctrls.flicker)); ++ if(ret != 0) ++ dev_err(isp->dev, "set flicker failed!!!\n"); ++ ++ return ret; ++} ++ ++static int apical_isp_module_s_attr(tisp_core_t *core) ++{ ++ tisp_module_control_t module; ++ struct isp_device *isp = core->priv_data; ++ module.key = isp->ctrls.module; ++ ++ tisp_s_module_control(&core->core_tuning, module); ++ ++ return 0; ++} ++ ++static int apical_isp_module_g_attr(tisp_core_t *core) ++{ ++ tisp_module_control_t module; ++ struct isp_device *isp = core->priv_data; ++ int ret = 0; ++ ++ tisp_g_module_control(&core->core_tuning, &module); ++ isp->ctrls.module = module.key; ++ ++ return ret; ++} ++ ++static inline int apical_isp_day_or_night_s_ctrl(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ int ret = 0; ++ TISP_MODE_DN_E dn = isp->ctrls.daynight; ++ ++ tisp_day_or_night_s_ctrl(&core->core_tuning, dn); ++ ++ return ret; ++} ++ ++static inline int apical_isp_day_or_night_g_ctrl(tisp_core_t *core) ++{ ++ struct isp_device *isp = core->priv_data; ++ TISP_MODE_DN_E dn ; ++ ++ dn = tisp_day_or_night_g_ctrl(&core->core_tuning); ++ isp->ctrls.daynight = dn; ++ ++ return 0; ++} ++ ++ ++static int apical_isp_ae_luma_g_ctrl(tisp_core_t *core) ++{ ++ unsigned char luma; ++ struct isp_device *isp = core->priv_data; ++ struct v4l2_subdev_format *input_fmt = &isp->formats[ISP_PAD_SINK]; ++ int width = input_fmt->format.width; ++ int height = input_fmt->format.height; ++ ++ tisp_g_ae_luma(&core->core_tuning, &luma, width, height); ++ isp->ctrls.luma = luma; ++ ++ return 0; ++} ++ ++int isp_core_tuning_param_sync(tisp_core_t *core) ++{ ++ int ret = 0; ++ struct isp_device *isp = core->priv_data; ++ struct v4l2_control *control; ++ control = kzalloc(sizeof(struct v4l2_control), GFP_KERNEL); ++ ++ if (isp->ctrls.hflip_pending) { ++ ret = apical_isp_hflip_s_control(core); ++ isp->ctrls.hflip_pending = 0; ++ } ++ if (isp->ctrls.vflip_pending) { ++ ret = apical_isp_vflip_s_control(core); ++ isp->ctrls.vflip_pending = 0; ++ } ++ if (isp->ctrls.sat_pending) { ++ ret = apical_isp_sat_s_control(core); ++ isp->ctrls.sat_pending = 0; ++ } ++ if (isp->ctrls.bright_pending) { ++ ret = apical_isp_bright_s_control(core); ++ isp->ctrls.bright_pending = 0; ++ } ++ if (isp->ctrls.contrast_pending) { ++ ret = apical_isp_contrast_s_control(core); ++ isp->ctrls.contrast_pending = 0; ++ } ++ if (isp->ctrls.sharp_pending) { ++ ret = apical_isp_sharp_s_control(core); ++ isp->ctrls.sharp_pending = 0; ++ } ++ if (isp->ctrls.exp_auto_pending) { ++ ret = ispcore_exp_auto_s_control(core); ++ isp->ctrls.exp_auto_pending = 0; ++ } ++ if (isp->ctrls.exp_abs_pending) { ++ ret = ispcore_exp_abs_s_control(core); ++ isp->ctrls.exp_abs_pending = 0; ++ } ++ if (isp->ctrls.auto_gain_pending) { ++ ret = ispcore_auto_gain_s_control(core); ++ isp->ctrls.auto_gain_pending = 0; ++ } ++ if (isp->ctrls.gain_pending) { ++ ret = ispcore_gain_s_control(core); ++ isp->ctrls.gain_pending = 0; ++ } ++ if (isp->ctrls.wb_pending) { ++ ret = ispcore_auto_n_wb_s_control(core); ++ isp->ctrls.wb_pending = 0; ++ } ++ if (isp->ctrls.auto_wb_pending) { ++ ret = ispcore_auto_wb_s_control(core); ++ isp->ctrls.auto_wb_pending = 0; ++ } ++ if (isp->ctrls.red_wb_pending) { ++ ret = ispcore_red_wb_s_control(core); ++ isp->ctrls.red_wb_pending = 0; ++ } ++ if (isp->ctrls.blue_wb_pending) { ++ ret = ispcore_blue_wb_s_control(core); ++ isp->ctrls.blue_wb_pending = 0; ++ } ++ if (isp->ctrls.do_wb_pending) { ++ ret = ispcore_do_wb_s_control(core); ++ isp->ctrls.do_wb_pending = 0; ++ } ++ if (isp->ctrls.hill_pending) { ++ ret = apical_isp_hilightdepress_s_control(core); ++ isp->ctrls.hill_pending = 0; ++ } ++ if (isp->ctrls.flicker_pending) { ++ ret = apical_isp_flicker_s_control(core); ++ isp->ctrls.flicker_pending = 0; ++ } ++ if (isp->ctrls.module_pending) { ++ ret = apical_isp_module_s_attr(core); ++ isp->ctrls.module_pending = 0; ++ } ++ if (isp->ctrls.daynight_pending) { ++ ret = apical_isp_day_or_night_s_ctrl(core); ++ isp->ctrls.daynight_pending = 0; ++ } ++ return ret; ++} ++ ++ ++static int isp_video_g_ctrl_inited(struct isp_device *isp, struct v4l2_control *a) ++{ ++ tisp_core_t *core = &isp->core; ++ int ret = 0; ++ ++ switch (a->id) { ++ case V4L2_CID_HFLIP: ++ a->value = isp->ctrls.hflip; ++ break; ++ case V4L2_CID_VFLIP: ++ a->value = isp->ctrls.vflip; ++ break; ++ case V4L2_CID_SATURATION: ++ ret = apical_isp_sat_g_control(core); ++ a->value = isp->ctrls.sat; ++ break; ++ case V4L2_CID_BRIGHTNESS: ++ ret = apical_isp_bright_g_control(core); ++ a->value = isp->ctrls.bright; ++ break; ++ case V4L2_CID_CONTRAST: ++ ret = apical_isp_contrast_g_control(core); ++ a->value = isp->ctrls.contrast; ++ break; ++ case V4L2_CID_SHARPNESS: ++ ret = apical_isp_sharp_g_control(core); ++ a->value = isp->ctrls.sharp; ++ break; ++ case V4L2_CID_EXPOSURE_AUTO: ++ ret = ispcore_exp_auto_g_control(core); ++ a->value = isp->ctrls.exp_auto; ++ break; ++ case V4L2_CID_EXPOSURE_ABSOLUTE: ++ ret = ispcore_exp_abs_g_control(core); ++ a->value = isp->ctrls.exp_abs; ++ break; ++ case V4L2_CID_EXPOSURE: ++ ret = ispcore_exp_g_control(core); ++ break; ++ case V4L2_CID_AUTOGAIN: ++ ret = ispcore_auto_gain_g_control(core); ++ a->value = isp->ctrls.auto_gain; ++ break; ++ case V4L2_CID_GAIN: ++ ret = ispcore_gain_g_control(core); ++ a->value = isp->ctrls.gain; ++ break; ++ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: ++ ret = ispcore_auto_n_wb_g_control(core); ++ a->value = isp->ctrls.wb; ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ ret = ispcore_auto_wb_g_control(core); ++ a->value = isp->ctrls.auto_wb; ++ break; ++ case V4L2_CID_RED_BALANCE: ++ ret = ispcore_red_wb_g_control(core); ++ a->value = isp->ctrls.red_wb; ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ ret = ispcore_blue_wb_g_control(core); ++ a->value = isp->ctrls.blue_wb; ++ break; ++ case IMAGE_TUNING_CID_HILIGHTDEPRESS: ++ ret = apical_isp_hilightdepress_g_control(core); ++ a->value = isp->ctrls.hill; ++ break; ++ case V4L2_CID_POWER_LINE_FREQUENCY: ++ a->value = isp->ctrls.flicker; ++ break; ++ case IMAGE_TUNING_CID_MODULE_CONTROL: ++ ret = apical_isp_module_g_attr(core); ++ a->value = isp->ctrls.module; ++ break; ++ case IMAGE_TUNING_CID_DAY_OR_NIGHT: ++ ret = apical_isp_day_or_night_g_ctrl(core); ++ a->value = isp->ctrls.daynight; ++ break; ++ case IMAGE_TUNING_CID_AE_LUMA: ++ ret = apical_isp_ae_luma_g_ctrl(core); ++ a->value = isp->ctrls.luma; ++ break; ++ default: ++ ret = -EPERM; ++ break; ++ } ++ return ret; ++} ++ ++ ++static int isp_video_g_ctrl_noinited(struct isp_device *isp, struct v4l2_control *a) ++{ ++ int ret = 0; ++ ++ switch (a->id) { ++ case V4L2_CID_HFLIP: ++ a->value = isp->ctrls.hflip; ++ break; ++ case V4L2_CID_VFLIP: ++ a->value = isp->ctrls.vflip; ++ break; ++ case V4L2_CID_SATURATION: ++ a->value = isp->ctrls.sat; ++ break; ++ case V4L2_CID_BRIGHTNESS: ++ a->value = isp->ctrls.bright; ++ break; ++ case V4L2_CID_CONTRAST: ++ a->value = isp->ctrls.contrast; ++ break; ++ case V4L2_CID_SHARPNESS: ++ a->value = isp->ctrls.sharp; ++ break; ++ case V4L2_CID_EXPOSURE_AUTO: ++ a->value = isp->ctrls.exp_auto; ++ break; ++ case V4L2_CID_EXPOSURE_ABSOLUTE: ++ a->value = isp->ctrls.exp_abs; ++ break; ++ case V4L2_CID_AUTOGAIN: ++ a->value = isp->ctrls.auto_gain; ++ break; ++ case V4L2_CID_GAIN: ++ a->value = isp->ctrls.gain; ++ break; ++ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: ++ a->value = isp->ctrls.wb; ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ a->value = isp->ctrls.auto_wb; ++ break; ++ case V4L2_CID_RED_BALANCE: ++ a->value = isp->ctrls.red_wb; ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ a->value = isp->ctrls.blue_wb; ++ break; ++ case IMAGE_TUNING_CID_HILIGHTDEPRESS: ++ a->value = isp->ctrls.hill; ++ break; ++ case V4L2_CID_POWER_LINE_FREQUENCY: ++ a->value = isp->ctrls.flicker; ++ break; ++ case IMAGE_TUNING_CID_MODULE_CONTROL: ++ a->value = isp->ctrls.module; ++ break; ++ case IMAGE_TUNING_CID_DAY_OR_NIGHT: ++ a->value = isp->ctrls.daynight; ++ break; ++ case IMAGE_TUNING_CID_AE_LUMA: ++ a->value = isp->ctrls.luma; ++ break; ++ default: ++ ret = -EPERM; ++ break; ++ } ++ return ret; ++} ++ ++ ++int isp_video_g_ctrl(struct file *file, void *fh, struct v4l2_control *a) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct isp_device *isp = ispcam->isp; ++ int ret = 0; ++ ++ if (isp->core_inited) { ++ ret = isp_video_g_ctrl_inited(isp, a); ++ } else { ++ ret = isp_video_g_ctrl_noinited(isp, a); ++ } ++ ++ return ret; ++} ++ ++static int isp_video_s_ctrl_inited(struct isp_device *isp, struct v4l2_control *a) ++{ ++ tisp_core_t *core = &isp->core; ++ int ret = 0; ++ ++ switch (a->id) { ++ case V4L2_CID_HFLIP: ++ isp->ctrls.hflip = a->value; ++ ret = apical_isp_hflip_s_control(core); ++ break; ++ case V4L2_CID_VFLIP: ++ isp->ctrls.vflip = a->value; ++ ret = apical_isp_vflip_s_control(core); ++ break; ++ case V4L2_CID_SATURATION: ++ isp->ctrls.sat = a->value; ++ ret = apical_isp_sat_s_control(core); ++ break; ++ case V4L2_CID_BRIGHTNESS: ++ isp->ctrls.bright = a->value; ++ ret = apical_isp_bright_s_control(core); ++ break; ++ case V4L2_CID_CONTRAST: ++ isp->ctrls.contrast = a->value; ++ ret = apical_isp_contrast_s_control(core); ++ break; ++ case V4L2_CID_SHARPNESS: ++ isp->ctrls.sharp = a->value; ++ ret = apical_isp_sharp_s_control(core); ++ break; ++ case V4L2_CID_EXPOSURE_AUTO: ++ isp->ctrls.exp_auto = a->value; ++ ret = ispcore_exp_auto_s_control(core); ++ break; ++ case V4L2_CID_EXPOSURE_ABSOLUTE: ++ isp->ctrls.exp_abs = a->value; ++ ret = ispcore_exp_abs_s_control(core); ++ break; ++ case V4L2_CID_EXPOSURE: ++ ret = ispcore_exp_s_control(core); ++ break; ++ case V4L2_CID_AUTOGAIN: ++ isp->ctrls.auto_gain = a->value; ++ ret = ispcore_auto_gain_s_control(core); ++ break; ++ case V4L2_CID_GAIN: ++ isp->ctrls.gain = a->value; ++ ret = ispcore_gain_s_control(core); ++ break; ++ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: ++ isp->ctrls.wb = a->value; ++ ret = ispcore_auto_n_wb_s_control(core); ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ isp->ctrls.auto_wb = a->value; ++ ret = ispcore_auto_wb_s_control(core); ++ break; ++ case V4L2_CID_RED_BALANCE: ++ isp->ctrls.red_wb = a->value; ++ ret = ispcore_red_wb_s_control(core); ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ isp->ctrls.blue_wb = a->value; ++ ret = ispcore_blue_wb_s_control(core); ++ break; ++ case V4L2_CID_DO_WHITE_BALANCE: ++ ret = ispcore_do_wb_s_control(core); ++ break; ++ case IMAGE_TUNING_CID_HILIGHTDEPRESS: ++ isp->ctrls.hill = a->value; ++ ret = apical_isp_hilightdepress_s_control(core); ++ break; ++ case V4L2_CID_POWER_LINE_FREQUENCY: ++ isp->ctrls.flicker = a->value; ++ ret = apical_isp_flicker_s_control(core); ++ break; ++ case IMAGE_TUNING_CID_MODULE_CONTROL: ++ isp->ctrls.module = a->value; ++ ret = apical_isp_module_s_attr(core); ++ break; ++ case IMAGE_TUNING_CID_DAY_OR_NIGHT: ++ isp->ctrls.daynight = a->value; ++ ret = apical_isp_day_or_night_s_ctrl(core); ++ break; ++ default: ++ ret = -EPERM; ++ break; ++ } ++ return ret; ++} ++ ++static int isp_video_s_ctrl_noinited(struct isp_device *isp, struct v4l2_control *a) ++{ ++ int ret = 0; ++ ++ switch (a->id) { ++ case V4L2_CID_HFLIP: ++ isp->ctrls.hflip = a->value; ++ isp->ctrls.hflip_pending = 1; ++ break; ++ case V4L2_CID_VFLIP: ++ isp->ctrls.vflip = a->value; ++ isp->ctrls.vflip_pending = 1; ++ break; ++ case V4L2_CID_SATURATION: ++ isp->ctrls.sat = a->value; ++ isp->ctrls.sat_pending = 1; ++ break; ++ case V4L2_CID_BRIGHTNESS: ++ isp->ctrls.bright = a->value; ++ isp->ctrls.bright_pending = 1; ++ break; ++ case V4L2_CID_CONTRAST: ++ isp->ctrls.contrast = a->value; ++ isp->ctrls.contrast_pending = 1; ++ break; ++ case V4L2_CID_SHARPNESS: ++ isp->ctrls.sharp = a->value; ++ isp->ctrls.sharp_pending = 1; ++ break; ++ case V4L2_CID_EXPOSURE_AUTO: ++ isp->ctrls.exp_auto = a->value; ++ isp->ctrls.exp_auto_pending = 1; ++ break; ++ case V4L2_CID_EXPOSURE_ABSOLUTE: ++ isp->ctrls.exp_abs = a->value; ++ isp->ctrls.exp_abs_pending = 1; ++ break; ++ case V4L2_CID_AUTOGAIN: ++ isp->ctrls.auto_gain = a->value; ++ isp->ctrls.auto_gain_pending = 1; ++ break; ++ case V4L2_CID_GAIN: ++ isp->ctrls.gain = a->value; ++ isp->ctrls.gain_pending = 1; ++ break; ++ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: ++ isp->ctrls.wb = a->value; ++ isp->ctrls.wb_pending = 1; ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ isp->ctrls.auto_wb = a->value; ++ isp->ctrls.auto_wb_pending = 1; ++ break; ++ case V4L2_CID_RED_BALANCE: ++ isp->ctrls.red_wb = a->value; ++ isp->ctrls.red_wb_pending = 1; ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ isp->ctrls.blue_wb = a->value; ++ isp->ctrls.blue_wb_pending = 1; ++ break; ++ case V4L2_CID_DO_WHITE_BALANCE: ++ isp->ctrls.do_wb_pending = 1; ++ break; ++ case IMAGE_TUNING_CID_HILIGHTDEPRESS: ++ isp->ctrls.hill = a->value; ++ isp->ctrls.hill_pending = 1; ++ break; ++ case V4L2_CID_POWER_LINE_FREQUENCY: ++ isp->ctrls.flicker = a->value; ++ isp->ctrls.flicker_pending = 1; ++ break; ++ case IMAGE_TUNING_CID_MODULE_CONTROL: ++ isp->ctrls.module = a->value; ++ isp->ctrls.module_pending = 1; ++ break; ++ case IMAGE_TUNING_CID_DAY_OR_NIGHT: ++ isp->ctrls.daynight = a->value; ++ isp->ctrls.daynight_pending = 1; ++ break; ++ default: ++ ret = -EPERM; ++ break; ++ } ++ return ret; ++} ++ ++int isp_video_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct isp_device *isp = ispcam->isp; ++ int ret = 0; ++ ++ if (isp->core_inited) { ++ ret = isp_video_s_ctrl_inited(isp, a); ++ } else { ++ ret = isp_video_s_ctrl_noinited(isp, a); ++ } ++ return ret; ++} ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/Makefile b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/Makefile +new file mode 100644 +index 000000000..d0cd033a6 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/Makefile +@@ -0,0 +1,3 @@ ++obj-y += src/ ++obj-y += tiziano_priv.o ++obj-y += tiziano_netlink.o +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/system_sensor_drv.h b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/system_sensor_drv.h +new file mode 100644 +index 000000000..e17e497b2 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/system_sensor_drv.h +@@ -0,0 +1,85 @@ ++#ifndef __SENSOR_DRV_H__ ++#define __SENSOR_DRV_H__ ++ ++#include ++ ++#define LOG2_GAIN_SHIFT 16 ++ ++typedef struct _sensor_context_t ++{ ++ uint16_t again; ++ uint16_t dgain; ++ uint8_t n_context; ++ uint8_t wdr_mode; ++ uint16_t again_x2; ++ uint16_t dgain_coarse; ++ uint16_t dgain_fine; ++ uint8_t column_buffer_gain_index; ++} sensor_context_t; ++ ++typedef struct _image_resolution_t ++{ ++ uint16_t width; ++ uint16_t height; ++} image_resolution_t; ++ ++typedef struct _sensor_param_t ++{ ++ uint8_t mode; ++ image_resolution_t total; ++ image_resolution_t active; ++ sensor_context_t sensor_ctx; ++ int32_t again_log2_max; ++ int32_t dgain_log2_max; ++ uint32_t integration_time_min; ++ uint32_t integration_time_max; ++ uint32_t integration_time_long_max; ++ uint32_t integration_time_limit; ++ uint16_t day_light_integration_time_max; ++ uint8_t integration_time_apply_delay; ++ uint8_t analog_gain_apply_delay; ++ uint8_t digital_gain_apply_delay; ++ int32_t xoffset; ++ int32_t yoffset; ++ int32_t anti_flicker_pos; ++ uint32_t lines_per_second; ++} sensor_param_t; ++ ++typedef struct _sensor_control_t ++{ ++ sensor_param_t param; ++ void *priv_data; /*handle to ispcore*/ ++ ++} sensor_control_t; ++ ++struct sensor_control_ops { ++ ++ void (*hw_reset_disable)(sensor_control_t *ctrl); ++ void (*hw_reset_enable)(sensor_control_t *ctrl); ++ int32_t (*alloc_analog_gain)(sensor_control_t *ctrl, int32_t gain, sensor_context_t *p_ctx); ++ int32_t (*alloc_digital_gain)(sensor_control_t *ctrl, int32_t gain, sensor_context_t *p_ctx); ++ void (*alloc_integration_time)(sensor_control_t *ctrl, uint16_t *int_time, sensor_context_t *p_ctx); ++ void (*set_integration_time)(sensor_control_t *ctrl, uint16_t int_time, sensor_param_t *param); ++ void (*start_changes)(sensor_control_t *ctrl, sensor_context_t *p_ctx); ++ void (*end_changes)(sensor_control_t *ctrl, sensor_context_t *p_ctx); ++ void (*set_analog_gain)(sensor_control_t *ctrl, uint32_t again_reg_val, sensor_context_t *p_ctx); ++ int (*get_analog_gain)(sensor_control_t *ctrl, uint32_t *again_reg_val, sensor_context_t *p_ctx); ++ void (*set_digital_gain)(sensor_control_t *ctrl, uint32_t dgain_reg_val, sensor_context_t *p_ctx); ++ int (*get_digital_gain)(sensor_control_t *ctrl, uint32_t *dgain_reg_val, sensor_context_t *p_ctx); ++ uint16_t (*get_normal_fps)(sensor_control_t *ctrl, sensor_param_t *param); ++ uint16_t (*read_black_pedestal)(sensor_control_t *ctrl, int i, uint32_t gain); ++ void (*set_mode)(sensor_control_t *ctrl, uint8_t mode, sensor_param_t *param); ++ void (*set_wdr_mode)(sensor_control_t *ctrl, uint8_t wdr, sensor_param_t *param); ++ uint32_t (*fps_control)(sensor_control_t *ctrl, uint8_t fps, sensor_param_t *param); ++ uint16_t (*get_id)(sensor_control_t *ctrl); ++ void (*disable_isp)(sensor_control_t *ctrl); ++ uint32_t (*get_lines_per_second)(sensor_control_t *ctrl, sensor_param_t *param); ++ ++}; ++ ++typedef sensor_control_t *sensor_control_ptr_t; ++ ++void sensor_init(sensor_control_ptr_t, void *ispcore); ++int sensor_early_init(void *ispcore); ++ ++#endif /* __SENSOR_DRV_H__ */ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_core.h b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_core.h +new file mode 100644 +index 000000000..b89fa186a +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_core.h +@@ -0,0 +1,1223 @@ ++#ifndef __TIZIANO_ISP_CORE_API_H__ ++#define __TIZIANO_ISP_CORE_API_H__ ++ ++#include "system_sensor_drv.h" ++#include "tiziano_core_tuning.h" ++#include "tiziano_isp.h" ++#include "tiziano_sys.h" ++#include "tiziano_priv.h" ++ ++/* ++ -----------core--------- ++ | awb, gamma, ++ ++*/ ++ ++/* --------- defog ---------*/ ++ ++typedef struct Tiziano_Isp_Defog_Ct_Detect_Para ++{ ++ uint32_t *DefogBlockRStat ; ++ uint32_t *DefogBlockGStat ; ++ uint32_t *DefogBlockBStat ; ++ uint32_t *DefogBlockYStat ; ++ uint32_t *DefogBlockDetailStat ; ++ uint32_t *DefogBlockVarianceStat ; ++ uint32_t *DefogDefogBlockTX ; ++ uint32_t *DefogDefogBlockTY ; ++ uint32_t *DefogDetailX ; ++ uint32_t *DefogDetailY ; ++ uint32_t *DefogColorVarX ; ++ uint32_t *DefogColorVarY ; ++ uint32_t *DefogFpgaPara ; ++ uint32_t *DefogBlockTransmitT ; ++ uint32_t *DefogBlockAirLightR ; ++ uint32_t *DefogBlockAirLightG ; ++ uint32_t *DefogBlockAirLightB ; ++}Isp_Defog_Ct_Detect_Para; ++ ++typedef struct tisp_defog { ++ uint32_t ev_now; ++ uint32_t ev_changed; ++ ++ uint32_t defog_ev_list[9]; ++ uint32_t defog_trsy0_list[9]; ++ uint32_t defog_trsy1_list[9]; ++ uint32_t defog_trsy2_list[9]; ++ uint32_t defog_trsy3_list[9]; ++ uint32_t defog_trsy4_list[9]; ++ uint32_t defog_rgbra_list[9]; ++ uint32_t defog_meam_block_r[200]; ++ uint32_t defog_meam_block_g[200]; ++ uint32_t defog_meam_block_b[200]; ++ uint32_t defog_meam_block_y[200]; ++ uint32_t defog_variance_block[200]; ++ uint32_t defog_detial_block[200]; ++ uint32_t defog_defog_block_t_x[5]; ++ uint32_t defog_defog_block_t_y[5]; ++ uint32_t defog_detail_x[5]; ++ uint32_t defog_detail_y[5]; ++ uint32_t defog_color_var_x[5]; ++ uint32_t defog_color_var_y[5]; ++ uint32_t defog_fpga_para[8]; ++ uint32_t param_defog_weightlut20[32]; ++ uint32_t param_defog_weightlut02[32]; ++ uint32_t param_defog_weightlut12[32]; ++ uint32_t param_defog_weightlut22[32]; ++ uint32_t param_defog_weightlut21[32]; ++ uint32_t param_defog_ct_par_array[4]; ++ uint32_t param_defog_dark_ct_array[14]; ++ uint32_t param_defog_over_expo_w_array[11]; ++ uint32_t param_defog_dark_spe_w_array[11]; ++ uint32_t param_defog_col_ct_array[14]; ++ uint32_t param_defog_cent3_w_dis_array[24]; ++ uint32_t param_defog_cent5_w_dis_array[31]; ++ uint32_t param_defog_blk_trans_array[10]; ++ uint32_t param_defog_detail_ct_array[10]; ++ uint32_t param_defog_col_var_array[10]; ++ uint32_t param_defog_soft_ct_par_array[6]; ++ ++ uint32_t defog_block_transmit_t[200]; ++ uint32_t defog_block_air_light_r[200]; ++ uint32_t defog_block_air_light_g[200]; ++ uint32_t defog_block_air_light_b[200]; ++ ++ Isp_Defog_Ct_Detect_Para TizianoDefogStructMe; ++ ++ void *core; ++} tisp_defog_t; ++ ++ ++/* -------- adr -------- */ ++typedef struct Tiziano_Isp_Adr_Ct_Detect_Para ++{ ++ int *CtcKneepointX; ++ int *CtcKneepointMux; ++ int *MinKneepointX; ++ int *MinKneepointY; ++ int *MapKneepointX; ++ int *MapKneepointY; ++ int *ContrastWDistance; ++ int *AdrHist; ++ int *AdrBlockY; ++ int *AdrBlockHist; ++ int *TmBaseLut; ++ int *AdrGamX; ++ int *AdrGamY; ++ int *AdrMapMode; ++ int *AdrLightEnd; ++ int *AdrBlockLight; ++}Isp_Adr_Ct_Detect_Para; ++ ++typedef struct tisp_adr { ++ ++ unsigned int ev_changed; ++ unsigned int ev_now; ++ unsigned int width_def; ++ unsigned int height_def; ++ unsigned int adr_ratio; ++ uint32_t adr_ev_list[9]; ++ uint32_t adr_ligb_list[9]; ++ uint32_t adr_mapb1_list[9]; ++ uint32_t adr_mapb2_list[9]; ++ uint32_t adr_mapb3_list[9]; ++ uint32_t adr_mapb4_list[9]; ++ uint32_t adr_blp2_list[9]; ++ ++ Isp_Adr_Ct_Detect_Para TizianoAdrFpgaStructMe; ++ ++ uint32_t param_adr_ct_par_array[8]; ++ uint32_t param_adr_weight_20_lut_array[32]; ++ uint32_t param_adr_weight_02_lut_array[32]; ++ uint32_t param_adr_weight_12_lut_array[32]; ++ uint32_t param_adr_weight_22_lut_array[32]; ++ uint32_t param_adr_weight_21_lut_array[32]; ++ uint32_t param_adr_ctc_kneepoint_array[8]; ++ uint32_t param_adr_min_kneepoint_array[23]; ++ uint32_t param_adr_map_kneepoint_array[23]; ++ uint32_t param_adr_coc_kneepoint_array[21]; ++ uint32_t param_adr_centre_w_dis_array[31]; ++ uint32_t param_adr_contrast_w_dis_array[32]; ++ uint32_t param_adr_stat_block_hist_diff_array[4]; ++ ++ uint32_t adr_block_y[20]; ++ uint32_t adr_block_hist[100]; ++ uint32_t adr_hist[512]; ++ ++ uint32_t ctc_kneepoint_x[4]; ++ uint32_t ctc_kneepoint_mux[4]; ++ uint32_t min_kneepoint_x[11]; ++ uint32_t min_kneepoint_y[11]; ++ /* {0,2,4,6,8,30,60,70,80,100,120}; */ ++ uint32_t min_kneepoint_pow[12]; ++ uint32_t map_kneepoint_x[11]; ++ uint32_t map_kneepoint_y[220]; ++ uint32_t map_kneepoint_pow[12]; ++ uint32_t coc_kneepoint_x[11]; ++ uint32_t coc_kneepoint_pow[10]; ++ uint32_t centre_w_distance[31]; ++ uint32_t contrast_w_distance[32]; ++ ++ uint32_t adr_stat_block_hist_diff[4]; ++ uint32_t adr_tm_base_lut[9]; ++ uint32_t adr_gam_x[129]; ++ uint32_t adr_gam_y[129]; ++ uint32_t adr_light_end[29]; ++ uint32_t adr_block_light[15]; ++ uint32_t adr_map_mode[11]; ++ uint32_t histSub_4096[9]; ++ uint32_t histSub_4096_out[9]; ++ uint32_t histSub_4096_diff[8]; ++ ++ ++ ++ ++ ++ ++ void *core; ++} tisp_adr_t; ++ ++/*ae struct*/ ++typedef struct { ++ uint32_t tisp_ae_manual; ++ uint32_t tisp_ae_sensor_again; ++ uint32_t tisp_ae_sensor_dgain; ++ uint32_t tisp_ae_sensor_integration_time; ++ uint32_t tisp_ae_isp_dgian; ++ uint32_t tisp_ae_max_sensor_again; ++ uint32_t tisp_ae_max_sensor_dgain; ++ uint32_t tisp_ae_max_sensor_integration_time; ++ uint32_t tisp_ae_max_isp_dgain; ++ uint32_t tisp_ae_ev; ++ uint32_t tisp_ae_tgain_db; ++ uint32_t tisp_ae_again_db; ++ uint32_t tisp_ae_ir; ++ uint32_t tisp_ae_it_manual; ++ uint32_t tisp_ae_ag_manual; ++ uint32_t tisp_ae_dg_manual; ++} tisp_ae_ctrls_t; ++ ++typedef struct { ++ uint32_t tisp_ae_sensor_agian; ++ uint32_t tisp_ae_sensor_dgian; ++ uint32_t tisp_ae_sensor_integration_time; ++ uint32_t tisp_ae_isp_dgian; ++} tisp_ae_ctrls_internal_t; ++ ++typedef struct Tiziano_Isp_Ae_Wmean_Param { ++ uint32_t *a_ae_array_d; ++ uint32_t *a_ae_array_m; ++ uint32_t *a_ae_array_s; ++ uint32_t *a_ae_array_ir; ++ uint32_t *a_ae_array_dc; ++ uint32_t *a_ae_array_sc; ++ uint32_t *a_ae_parameter; ++ uint32_t *a_ae_zone_weight; ++ uint32_t *a_exp_parameter; ++ uint32_t *a_ae_stat; ++ uint32_t *a_scene_roui_weight; ++ uint32_t *a_scene_roi_weight; ++ uint32_t *a_log2_lut; ++ uint32_t *a_weight_lut; ++ uint32_t *a_AePointPos; ++} Isp_Ae_Wmean_Param; ++ ++typedef struct Tiziano_Isp_Ae_Tune_Param { ++ uint32_t *a_exp_parameter; ++ uint32_t *a_ev_list; ++ uint32_t *a_lum_list; ++ uint32_t *a_at_list; ++ uint32_t *a_ae_result; ++ uint32_t *a_ae_reg; ++ uint32_t *a_ae_stat; ++ uint32_t *a_ae_wm_q; ++ uint32_t *a_flicker_t; ++ uint32_t *a_deflicker_para; ++ uint32_t *a_ae_ev_step; ++ uint32_t *a_ae_scene_mode_th; ++ uint32_t *a_ae_stable_tol; ++ uint32_t *a_AePointPos; ++ uint32_t *a_ae_hist_ir_array; ++ uint32_t *a_ae_nodes_num; ++ uint32_t *a_ae_compensation; ++} Isp_Ae_Tune_Param; ++ ++typedef struct tisp_ae { ++ int ftune; ++ uint32_t min_it; ++ uint32_t min_ag; ++ uint32_t min_dg; ++ uint32_t y_zone[15][15]; ++ uint32_t y_zone_last[15][15]; ++ spinlock_t slock; ++ spinlock_t slock_hist; ++ spinlock_t aelock; ++ tisp_ae_sta_t tisp_ae_hist; ++ tisp_ae_sta_t tisp_ae_hist_last; ++ int ae_first; ++ int expt_first_frame; ++ ++ Isp_Ae_Wmean_Param IspAeWmeanParam; ++ Isp_Ae_Tune_Param IspAeTuneParam; ++ tisp_ae_ctrls_t tisp_ae_ctrls; ++ tisp_ae_ctrls_internal_t ae_ctrls; ++ ++ uint32_t ae_array_d[225]; ++ uint32_t ae_array_m[225]; ++ uint32_t ae_array_s[225]; ++ uint32_t ae_array_ir[225]; ++ uint32_t ae_array_dc[225]; ++ uint32_t ae_array_sc[225]; ++ ++ uint32_t ae_hist_array[256]; ++ uint32_t ae_hist_ir_array[256]; ++ uint32_t _ae_reg[4]; //--->awb ++ uint32_t _ae_ev; ++ uint32_t ae_dn_refresh_flag; ++ uint32_t ae_compensation; ++ uint32_t ae_ev_init_strict; ++ uint32_t ae_ev_init_en; ++ ++ /*parameter*/ ++ uint32_t _ae_parameter[38]; ++ uint32_t ae_switch_night_mode[4]; ++ uint32_t _AePointPos[2]; ++ uint32_t _exp_parameter[11]; ++ uint32_t ae_ev_step[5]; ++ uint32_t ae_stable_tol[4]; ++ uint32_t _ev_list[10]; ++ uint32_t _lum_list[6]; ++ uint32_t _at_list[10]; ++ uint32_t _deflicker_para[3]; ++ uint32_t _flicker_t[6]; ++ uint32_t _deflick_lut[120]; ++ uint32_t _nodes_num; ++ uint32_t _scene_para[11]; ++ uint32_t ae_scene_mode_th[4]; ++ uint32_t _log2_lut[20]; ++ uint32_t _weight_lut[20]; ++ uint32_t _ae_zone_weight[225]; ++ uint32_t _scene_roui_weight[225]; ++ uint32_t _scene_roi_weight[225]; ++ uint32_t ev_cache[10]; ++ uint32_t ad_cache[10]; ++ uint32_t ag_cache[9]; ++ uint32_t dg_cache[9]; ++ ++ /*find ones*/ ++ uint32_t _ae_result[4]; ++ uint32_t _ae_stat[5]; ++ uint32_t _ae_wm_q[15]; ++ ++ int trig; ++ int force_trig; ++ int trig_deflick; ++ int trig_cal; ++ ++ uint32_t again_old; ++ uint32_t again_new; ++ uint32_t total_gain_old; ++ uint32_t total_gain_new; ++ uint32_t ag_old; ++ uint32_t dg_old; ++ uint32_t ag_new; ++ uint32_t dg_new; ++ uint32_t EffectFrame; ++ int32_t EffectCount; ++ ++ void *core; ++} tisp_ae_t; ++ ++/*awb struct*/ ++typedef struct Tiziano_Isp_Awb_Ct_Detect_Param { ++ unsigned int *auint16LightSrc; ++ unsigned int uint16LightSrcNum; ++ unsigned int *auint32CtTh; ++ unsigned int *auint32CtThPara; ++ unsigned int *auint16RgBgWeight; ++ unsigned int uint32HorZone; ++ unsigned int uint32VerZone; ++ unsigned int *auint16RgPos; ++ unsigned int *auint16BgPos; ++ unsigned int *auint16ColorTempMesh; ++ unsigned int *auint16AwbWght; ++ uint32_t *auint64AwbDisTw; ++ unsigned int *uint32AwbCt; ++ unsigned int *auint32LsWLut; ++ unsigned int *auint32AwbPointPos; ++} ISP_AWB_CT_DETECT_PARAM; ++ ++typedef struct Tiziano_Isp_Awb_Fpga_Param ++{ ++ unsigned int *a_r_sum; ++ unsigned int *a_g_sum; ++ unsigned int *a_b_sum; ++ unsigned int *a_pix_cnt; ++ unsigned int *a_awb_cof; ++ unsigned int *a_awb_mf_para; ++ unsigned int *a_awb_parameter; ++ unsigned int pixel_cnt_th; ++ uint32_t *a_awb_static; ++ unsigned int *a_AwbPointPos; ++} ISP_AWB_FPGA_PARAM; ++ ++typedef struct tisp_awb { ++ tisp_wb_attr_t tisp_wb_attr; ++ int awb_moa; ++ int awb_frz; ++ int awb_first; ++ uint32_t awb_dn_refresh_flag; ++ ISP_AWB_FPGA_PARAM IspAwbFpgaParam; ++ ISP_AWB_CT_DETECT_PARAM IspAwbCtDetectParam; ++ unsigned int awb_array_r[225]; ++ unsigned int awb_array_g[225]; ++ unsigned int awb_array_b[225]; ++ unsigned int awb_array_p[225]; ++ ++ unsigned int awb_rg_global; ++ unsigned int awb_bg_global; ++ unsigned int awb_pix_cnt[2]; ++ ++ uint32_t zone_rgbg_last[450]; ++ uint32_t zone_rgbg[450]; ++ unsigned int zone_pix_cnt[225]; ++ unsigned int awb_gain_original[2]; ++ unsigned int first_frame; ++ int offet_thres; ++ ++ /*parameter*/ ++ unsigned int _awb_parameter[45]; ++ unsigned int _pixel_cnt_th; ++ unsigned int _awb_lowlight_rg_th[2]; ++ unsigned int _AwbPointPos[2]; ++ unsigned int _awb_cof[2]; ++ unsigned int _awb_mf_para[6]; ++ unsigned int _awb_mode[3]; ++ // ce_detcet ++ unsigned int _awb_ct; ++ unsigned int _awb_ct_last; ++ uint32_t _wb_static[2]; ++ unsigned int _light_src[20]; ++ unsigned int _light_src_num; ++ unsigned int _rg_pos[15]; ++ unsigned int _bg_pos[15]; ++ unsigned int _awb_ct_th_ot_luxhigh[4]; ++ unsigned int _awb_ct_th_ot_luxlow[4]; ++ unsigned int _awb_ct_th_in[4]; ++ unsigned int _awb_ct_para_ot[2]; ++ unsigned int _awb_ct_para_in[2]; ++ uint32_t _awb_dis_tw[3]; ++ unsigned int _rgbg_weight[225]; ++ unsigned int _color_temp_mesh[225]; ++ unsigned int _awb_wght[225]; ++ unsigned int _rgbg_weight_ot[225]; ++ unsigned int _ls_w_lut[514]; ++ uint32_t _ev; ++ ++ void *core; /*pointer to isp core top.*/ ++} tisp_awb_t; ++ ++typedef struct tisp_gamma { ++ u32 tiziano_gamma_lut[129]; ++ void *core; /*pinter to isp core.*/ ++} tisp_gamma_t; ++ ++/* ------ af ------- */ ++ ++typedef struct TizianoIsp_Af_Static_Param { ++ unsigned int *a_af_zone; ++ unsigned int *a_af_array_fird0; ++ unsigned int *a_af_array_fird1; ++ unsigned int *a_af_array_iird0; ++ unsigned int *a_af_array_iird1; ++ unsigned int *a_af_array_y_sum; ++ unsigned int *a_af_array_high_luma_cnt; ++ unsigned int *a_af_weight; ++ unsigned int *a_af_fv; ++ unsigned int *a_af_fvwmean; ++ uint32_t *a_af_tilt; ++ uint32_t *a_AfPointPos; ++ uint32_t width; ++ uint32_t height; ++} Isp_Af_Static_Param; ++ ++typedef struct tisp_af { ++ Isp_Af_Static_Param IspAfStaticParam; ++ uint32_t af_array_fird0[225]; ++ uint32_t af_array_fird1[225]; ++ uint32_t af_array_iird0[225]; ++ uint32_t af_array_iird1[225]; ++ uint32_t af_array_y_sum[225]; ++ uint32_t af_array_high_luma_cnt[225]; ++ unsigned int stAFParam_Zone[36]; ++ unsigned int stAFParam_ThresEnable[13]; ++ unsigned int stAFParam_FIR0_V[5]; ++ unsigned int stAFParam_FIR0_Ldg[8]; ++ unsigned int stAFParam_FIR0_Coring[4]; ++ unsigned int stAFParam_FIR1_V[5]; ++ unsigned int stAFParam_FIR1_Ldg[8]; ++ unsigned int stAFParam_FIR1_Coring[4]; ++ unsigned int stAFParam_IIR0_H[10]; ++ unsigned int stAFParam_IIR0_Ldg[8]; ++ unsigned int stAFParam_IIR0_Coring[4]; ++ unsigned int stAFParam_IIR1_H[10]; ++ unsigned int stAFParam_IIR1_Ldg[8]; ++ unsigned int stAFParam_IIR1_Coring[4]; ++ ++ /******Algorithm Param********/ ++ uint32_t AFParam_PointPos[2]; ++ uint32_t AFParam_Fv_Alt; ++ /* Alpha,Belta,Delta,Theta,BlendShift */ ++ uint32_t AFParam_Tilt[5]; //[0 ~ 1] * 64 6bit point float ++ ++ unsigned int AFParam_FvWmean[15]; ++ unsigned int AFParam_Fv[3]; ++ /* Fv1-->Alpha*h1+(1-Alpha)*v1 */ ++ /* Fv2-->Belta*h2+(1-Belta)*v2 */ ++ /* Fv -->Delta*Fv1+Theta*Fv2 */ ++ ++ unsigned int AFWeight_Param[225]; ++ ++ unsigned int FvWmean_num; ++ ++ tisp_af_attr af_attr; ++ unsigned char af_set_trig; ++ ++ ++ void *core; ++} tisp_af_t; ++ ++typedef struct tisp_gib { ++ uint32_t trig_set_deir; ++ /*parameter*/ ++ uint32_t tiziano_gib_config_line[6]; ++ uint32_t tiziano_gib_r_g_linear[2]; ++ uint32_t tiziano_gib_b_ir_linear[2]; ++ ++ uint32_t tiziano_gib_deirm_blc_r_linear[9]; ++ uint32_t tiziano_gib_deirm_blc_gr_linear[9]; ++ uint32_t tiziano_gib_deirm_blc_gb_linear[9]; ++ uint32_t tiziano_gib_deirm_blc_b_linear[9]; ++ uint32_t tiziano_gib_deirm_blc_ir_linear[9]; ++ ++ uint32_t gib_ir_value[2]; ++ uint32_t gib_ir_point[4]; ++ uint32_t gib_ir_reser[15]; ++ uint32_t tiziano_gib_deir_r_h[33]; ++ uint32_t tiziano_gib_deir_g_h[33]; ++ uint32_t tiziano_gib_deir_b_h[33]; ++ ++ uint32_t tiziano_gib_deir_r_m[33]; ++ uint32_t tiziano_gib_deir_g_m[33]; ++ ++ uint32_t tiziano_gib_deir_b_m[33]; ++ ++ uint32_t tiziano_gib_deir_r_l[33]; ++ uint32_t tiziano_gib_deir_g_l[33]; ++ uint32_t tiziano_gib_deir_b_l[33]; ++ ++ uint32_t tiziano_gib_deir_matrix_h[15]; ++ uint32_t tiziano_gib_deir_matrix_m[15]; ++ uint32_t tiziano_gib_deir_matrix_l[15]; ++ void *core; ++} tisp_gib_t; ++ ++typedef struct tisp_lsc { ++ uint32_t lut_num; ++ uint32_t mesh_scale; ++ uint32_t lut_stride; ++ uint32_t mesh_size[2]; ++ uint32_t a_linear[2047]; ++ uint32_t t_linear[2047]; ++ uint32_t d_linear[2047]; ++ uint32_t mesh_lsc_str[9]; ++ uint32_t lsc_change_flag; ++ uint32_t lsc_change_flag_last; ++ uint32_t tiziano_lsc_ct_points[4]; ++ uint32_t ct; ++ uint32_t ct_last; ++ uint32_t lsc_gain_thres; ++ uint32_t lsc_gain_old; ++ uint32_t gain_no_change; ++ void *core; ++} tisp_lsc_t; ++ ++ ++/*ccm struct*/ ++struct tisp_ccm_real { ++ uint32_t first_tune; ++ uint32_t ev_old; ++ uint32_t ev_threshold; ++ uint32_t ct_old; ++ uint32_t ct_threshold; ++ uint32_t cm_sat; ++}; ++typedef struct tisp_ccm { ++ ++ uint32_t tiziano_ccm_dp_cfg[1]; ++ uint32_t tiziano_ccm_a_linear[9]; ++ uint32_t tiziano_ccm_t_linear[9]; ++ uint32_t tiziano_ccm_d_linear[9]; ++ uint32_t tiziano_linear_value; ++ int32_t ccm_parameter[9]; ++ ++ uint32_t _ev; ++ uint32_t _ct; ++ struct tisp_ccm_real ccm_real; ++ ++ int32_t _ccm_a_parameter[9]; ++ int32_t _ccm_t_parameter[9]; ++ int32_t _ccm_d_parameter[9]; ++ uint32_t cm_ev_list[9]; ++ uint32_t cm_sat_list[9]; ++ uint32_t cm_awb_list[2]; ++ void *core; ++} tisp_ccm_t; ++ ++typedef struct tisp_dmsc { ++ int32_t dmsc_uu_np_array[16]; ++ int32_t dmsc_sp_d_sigma_3_np_array[16]; ++ int32_t dmsc_sp_d_w_wei_np_array[16]; ++ int32_t dmsc_sp_d_b_wei_np_array[16]; ++ int32_t dmsc_sp_ud_w_wei_np_array[16]; ++ int32_t dmsc_sp_ud_b_wei_np_array[16]; ++ /* out option */ ++ int32_t dmsc_out_opt; ++ /* direction(hv aa hvaa value) tuning parameters */ ++ int32_t dmsc_hv_thres_1_array[9]; ++ int32_t dmsc_hv_stren_array[9]; ++ int32_t dmsc_aa_thres_1_array[9]; ++ int32_t dmsc_aa_stren_array[9]; ++ int32_t dmsc_hvaa_thres_1_array[9]; ++ int32_t dmsc_hvaa_stren_array[9]; ++ int32_t dmsc_dir_par_array[9]; ++ /* std and uu value tuning parameters */ ++ int32_t dmsc_uu_thres_array[9]; ++ int32_t dmsc_uu_stren_array[9]; ++ int32_t dmsc_uu_par_array[3]; ++ /* alias tuning parameters */ ++ int32_t dmsc_alias_stren_array[9]; ++ int32_t dmsc_alias_thres_1_array[9]; ++ int32_t dmsc_alias_thres_2_array[9]; ++ int32_t dmsc_alias_dir_thres_array[9]; ++ int32_t dmsc_alias_par_array[4]; ++ /* rgb nor blur wei tuning parameters */ ++ int32_t dmsc_nor_alias_thres_array[9]; ++ int32_t dmsc_nor_par_array[4]; ++ /* d sharpen tuning parameters */ ++ int32_t dmsc_sp_d_w_stren_array[9]; ++ int32_t dmsc_sp_d_b_stren_array[9]; ++ int32_t dmsc_sp_d_brig_thres_array[9]; ++ int32_t dmsc_sp_d_dark_thres_array[9]; ++ int32_t dmsc_sp_d_par_array[8]; ++ /* ud sharpen tuning parameters */ ++ int32_t dmsc_sp_ud_w_stren_array[9]; ++ int32_t dmsc_sp_ud_b_stren_array[9]; ++ int32_t dmsc_sp_ud_brig_thres_array[9]; ++ int32_t dmsc_sp_ud_dark_thres_array[9]; ++ int32_t dmsc_sp_ud_par_array[8]; ++ /* sp wei tuning parameters */ ++ int32_t dmsc_sp_alias_thres_array[9]; ++ int32_t dmsc_sp_alias_par_array[2]; ++ /* alias rgb tuning parameters */ ++ int32_t dmsc_rgb_dir_thres_array[9]; ++ int32_t dmsc_rgb_alias_stren_array[9]; ++ int32_t dmsc_rgb_alias_par_array[2]; ++ /* fc tuning parameters */ ++ int32_t dmsc_fc_alias_stren_array[9]; ++ int32_t dmsc_fc_t1_thres_array[9]; ++ int32_t dmsc_fc_t1_stren_array[9]; ++ int32_t dmsc_fc_t2_stren_array[9]; ++ int32_t dmsc_fc_t3_stren_array[9]; ++ int32_t dmsc_fc_par_array[9]; ++ ++ uint32_t dmsc_hv_thres_1_intp; ++ uint32_t dmsc_hv_stren_intp; ++ uint32_t dmsc_aa_thres_1_intp; ++ uint32_t dmsc_aa_stren_intp; ++ uint32_t dmsc_hvaa_thres_1_intp; ++ uint32_t dmsc_hvaa_stren_intp; ++ uint32_t dmsc_uu_thres_intp; ++ uint32_t dmsc_uu_stren_intp; ++ uint32_t dmsc_alias_stren_intp; ++ uint32_t dmsc_alias_thres_1_intp; ++ uint32_t dmsc_alias_thres_2_intp; ++ uint32_t dmsc_alias_dir_thres_intp; ++ uint32_t dmsc_nor_alias_thres_intp; ++ uint32_t dmsc_sp_d_w_stren_intp; ++ uint32_t dmsc_sp_d_b_stren_intp; ++ uint32_t dmsc_sp_d_brig_thres_intp; ++ uint32_t dmsc_sp_d_dark_thres_intp; ++ uint32_t dmsc_sp_ud_w_stren_intp; ++ uint32_t dmsc_sp_ud_b_stren_intp; ++ uint32_t dmsc_sp_ud_brig_thres_intp; ++ uint32_t dmsc_sp_ud_dark_thres_intp; ++ uint32_t dmsc_sp_alias_thres_intp; ++ uint32_t dmsc_rgb_dir_thres_intp; ++ uint32_t dmsc_rgb_alias_stren_intp; ++ uint32_t dmsc_fc_alias_stren_intp; ++ uint32_t dmsc_fc_t1_thres_intp; ++ uint32_t dmsc_fc_t1_stren_intp; ++ uint32_t dmsc_fc_t2_stren_intp; ++ uint32_t dmsc_fc_t3_stren_intp; ++ ++ uint32_t gain_old; ++ uint32_t gain_thres; ++ uint32_t shadow_en; ++ ++ void *core; ++} tisp_dmsc_t; ++ ++typedef struct tisp_sharpen { ++ int32_t sharpen_uu_np_array[16]; //8 bits 0~255 ++ int32_t sharpen_v1_sigma_np_array[16]; //5 bits 0~16 ++ int32_t sharpen_w_wei_np_array[16]; //6 bits 0~32 ++ int32_t sharpen_b_wei_np_array[16]; //6 bits 0~32 ++ int32_t sharpen_uu_thres_array[9]; ++ int32_t sharpen_uu_stren_array[9]; ++ int32_t sharpen_uu_par_array[3]; ++ int32_t sharpen_pixel_thres_array[9]; ++ int32_t sharpen_w_stren_array[9]; ++ int32_t sharpen_b_stren_array[9]; ++ int32_t sharpen_brig_thres_array[9]; ++ int32_t sharpen_dark_thres_array[9]; ++ int32_t sharpen_con_par_array[8]; ++ ++ /* sharpen intp parameters */ ++ uint32_t sharpen_uu_thres_intp; ++ uint32_t sharpen_uu_stren_intp; ++ uint32_t sharpen_pixel_thres_intp; ++ uint32_t sharpen_w_stren_intp; ++ uint32_t sharpen_b_stren_intp; ++ uint32_t sharpen_birg_thres_intp; ++ uint32_t sharpen_dark_thres_intp; ++ ++ uint32_t gain_old; ++ uint32_t gain_thres; ++ uint32_t shadow_en; ++ void *core; ++} tisp_sharpen_t; ++ ++typedef struct tisp_sdns { ++ int32_t sdns_top_func_array[2]; ++ int32_t sdns_y_dtl_thres_array[9]; ++ int32_t sdns_y_fus_slope_array[9]; ++ int32_t sdns_y_lum_divop_array[9]; ++ int32_t sdns_y_dtl_segop_array[9]; ++ int32_t sdns_y_fus_segop_array[9]; ++ int32_t sdns_y_lum_segop_array[9]; ++ int32_t sdns_y_dsp_segop_array[9]; ++ int32_t sdns_y_bsp_segop_array[9]; ++ int32_t sdns_y_dtl_stren_array[9]; ++ int32_t sdns_y_fus_stren_array[9]; ++ int32_t sdns_y_lum_stren_array[9]; ++ int32_t sdns_y_dsp_stren_array[9]; ++ int32_t sdns_y_bsp_stren_array[9]; ++ int32_t sdns_y_dtl_npv_0_array[9]; ++ int32_t sdns_y_dtl_npv_1_array[9]; ++ int32_t sdns_y_dtl_npv_2_array[9]; ++ int32_t sdns_y_dtl_npv_3_array[9]; ++ int32_t sdns_y_dtl_npv_4_array[9]; ++ int32_t sdns_y_fus_npv_array[16]; ++ int32_t sdns_y_lum_npv_array[16]; ++ int32_t sdns_y_dsp_npv_array[16]; ++ int32_t sdns_y_bsp_npv_array[16]; ++ int32_t sdns_y_bil_stren_array[9]; ++ int32_t sdns_y_bil_npv_array[15]; ++ int32_t sdns_c_bas_wei_array[9]; ++ int32_t sdns_c_fus_mod_array[9]; ++ int32_t sdns_c_flu_cal_array[9]; ++ int32_t sdns_c_flu_stren_array[9]; ++ int32_t sdns_c_flu_npv_array[16]; ++ ++ /* sdns intp parameters */ ++ uint32_t sdns_y_dtl_thres_intp; ++ uint32_t sdns_y_fus_slope_intp; ++ uint32_t sdns_y_lum_divop_intp; ++ uint32_t sdns_y_dtl_segop_intp; ++ uint32_t sdns_y_fus_segop_intp; ++ uint32_t sdns_y_lum_segop_intp; ++ uint32_t sdns_y_dsp_segop_intp; ++ uint32_t sdns_y_bsp_segop_intp; ++ uint32_t sdns_y_dtl_stren_intp; ++ uint32_t sdns_y_fus_stren_intp; ++ uint32_t sdns_y_lum_stren_intp; ++ uint32_t sdns_y_dsp_stren_intp; ++ uint32_t sdns_y_bsp_stren_intp; ++ uint32_t sdns_y_bil_stren_intp; ++ uint32_t sdns_y_dtl_npv_0_intp; ++ uint32_t sdns_y_dtl_npv_1_intp; ++ uint32_t sdns_y_dtl_npv_2_intp; ++ uint32_t sdns_y_dtl_npv_3_intp; ++ uint32_t sdns_y_dtl_npv_4_intp; ++ uint32_t sdns_c_bas_wei_intp; ++ uint32_t sdns_c_fus_mod_intp; ++ uint32_t sdns_c_flu_cal_intp; ++ uint32_t sdns_c_flu_stren_intp; ++ ++ uint32_t gain_old; ++ uint32_t gain_thres; ++ void *core; ++} tisp_sdns_t; ++ ++/* ----------- dpc ------------*/ ++typedef struct tisp_dpc { ++ /* dpc parameters */ ++ int32_t ctr_md_np_array[16]; ++ int32_t rdns_uu_np_array[16]; ++ int32_t rdns_g_lum_np_array[16]; ++ int32_t rdns_g_std_np_array[16]; ++ int32_t rdns_rb_lum_np_array[16]; ++ int32_t rdns_rb_std_np_array[16]; ++ int32_t dpc_s_text_thres_array[9]; ++ int32_t dpc_s_con_par_array[5]; ++ int32_t dpc_d_m1_level_array[9]; ++ int32_t dpc_d_m1_l0_fthres_array[9]; ++ int32_t dpc_d_m1_l0_dthres_array[9]; ++ int32_t dpc_d_m1_l1_hthres_array[9]; ++ int32_t dpc_d_m1_l1_lthres_array[9]; ++ int32_t dpc_d_m1_l1_d1_thres_array[9]; ++ int32_t dpc_d_m1_l1_d2_thres_array[9]; ++ int32_t dpc_d_m1_con_par_array[14]; ++ int32_t dpc_d_m2_level_array[9]; ++ int32_t dpc_d_m2_l0_thres_array[9]; ++ int32_t dpc_d_m2_l1_ldthres_array[9]; ++ int32_t dpc_d_m2_l1_pdthres_array[9]; ++ int32_t dpc_d_m2_con_par_array[6]; ++ int32_t ctr_stren_array[9]; ++ int32_t ctr_md_thres_array[9]; ++ int32_t ctr_el_thres_array[9]; ++ int32_t ctr_eh_thres_array[9]; ++ int32_t ctr_con_par_array[5]; ++ int32_t rdns_stren_array[9]; ++ int32_t rdns_std_thres_array[9]; ++ int32_t rdns_y_fthres_array[9]; ++ int32_t rdns_y_tthres_array[9]; ++ int32_t rdns_uv_fthres_array[9]; ++ int32_t rdns_uv_tthres_array[9]; ++ int32_t rdns_con_par_array[10]; ++ int32_t dpc_s_text_thres_intp; ++ int32_t dpc_d_m1_level_intp; ++ int32_t dpc_d_m1_l0_fthres_intp; ++ int32_t dpc_d_m1_l0_dthres_intp; ++ int32_t dpc_d_m1_l1_hthres_intp; ++ int32_t dpc_d_m1_l1_lthres_intp; ++ int32_t dpc_d_m1_l1_d1_thres_intp; ++ int32_t dpc_d_m1_l1_d2_thres_intp; ++ int32_t dpc_d_m2_level_intp; ++ int32_t dpc_d_m2_l0_thres_intp; ++ int32_t dpc_d_m2_l1_ldthres_intp; ++ int32_t dpc_d_m2_l1_pdthres_intp; ++ int32_t ctr_stren_intp; ++ int32_t ctr_md_thres_intp; ++ int32_t ctr_el_thres_intp; ++ int32_t ctr_eh_thres_intp; ++ int32_t rdns_stren_intp; ++ int32_t rdns_std_thres_intp; ++ int32_t rdns_y_fthres_intp; ++ int32_t rdns_y_tthres_intp; ++ int32_t rdns_uv_fthres_intp; ++ int32_t rdns_uv_tthres_intp; ++ void *core; ++} tisp_dpc_t; ++ ++/* --------- mdns --------------*/ ++ ++typedef struct tisp_mdns { ++ int vin_width; ++ int vin_height; ++ ++ /* mdns parameters */ ++ int32_t mdns_top_func_array[24]; ++ int32_t mdns_sta_size_array[9]; ++ int32_t mdns_pbt_size_array[9]; ++ int32_t mdns_pbt_ponit_array[2]; ++ int32_t mdns_y_sad_thres_array[9]; ++ int32_t mdns_y_sta_thres_array[9]; ++ int32_t mdns_y_pbt_thres_array[9]; ++ int32_t mdns_y_sad_stren_array[9]; ++ int32_t mdns_y_sta_stren_array[9]; ++ int32_t mdns_y_pbt_stren_array[9]; ++ int32_t mdns_y_sad_win_opt_array[9]; ++ int32_t mdns_y_sta_win_opt_array[9]; ++ int32_t mdns_y_pbt_win_opt_array[9]; ++ int32_t mdns_y_sad_win_wei_array[9]; ++ int32_t mdns_y_sta_win_wei_array[9]; ++ int32_t mdns_y_pbt_win_wei_array[9]; ++ int32_t mdns_y_sta_mv_num_array[9]; ++ int32_t mdns_y_pbt_mv_num_array[9]; ++ int32_t mdns_y_sta_mx_num_array[9]; ++ int32_t mdns_y_pbt_mx_num_array[9]; ++ int32_t mdns_y_sad_npv_array[4]; ++ int32_t mdns_y_sta_npv_array[32]; ++ int32_t mdns_y_pbt_npv_array[32]; ++ int32_t mdns_y_ref_wei_min_array[9]; ++ int32_t mdns_y_ref_wei_max_array[9]; ++ int32_t mdns_y_edge_type_array[1]; ++ int32_t mdns_y_edge_win_array[9]; ++ int32_t mdns_y_bi_thres_array[9]; ++ int32_t mdns_y_smj_thres_array[9]; ++ int32_t mdns_y_shp_swei_array[9]; ++ int32_t mdns_y_shp_mwei_array[9]; ++ int32_t mdns_y_cs_bhold_array[9]; ++ int32_t mdns_y_cm_bhold_array[9]; ++ int32_t mdns_y_rs_bhold_array[9]; ++ int32_t mdns_y_rm_bhold_array[9]; ++ int32_t mdns_y_cs_bwin_array[9]; ++ int32_t mdns_y_cm_bwin_array[9]; ++ int32_t mdns_y_rs_bwin_array[9]; ++ int32_t mdns_y_rm_bwin_array[9]; ++ int32_t mdns_y_cs_iwin_array[9]; ++ int32_t mdns_y_cm_iwin_array[9]; ++ int32_t mdns_y_rs_iwin_array[9]; ++ int32_t mdns_y_rm_iwin_array[9]; ++ int32_t mdns_y_cs_ewin_array[9]; ++ int32_t mdns_y_cm_ewin_array[9]; ++ int32_t mdns_y_rs_ewin_array[9]; ++ int32_t mdns_y_rm_ewin_array[9]; ++ int32_t mdns_y_cs_sego_array[9]; ++ int32_t mdns_y_cm_sego_array[9]; ++ int32_t mdns_y_rs_sego_array[9]; ++ int32_t mdns_y_rm_sego_array[9]; ++ int32_t mdns_y_cs_stren_array[9]; ++ int32_t mdns_y_cm_stren_array[9]; ++ int32_t mdns_y_rs_stren_array[9]; ++ int32_t mdns_y_rm_stren_array[9]; ++ int32_t mdns_y_cs_npv_array[16]; ++ int32_t mdns_y_cm_npv_array[16]; ++ int32_t mdns_y_rs_npv_array[16]; ++ int32_t mdns_y_rm_npv_array[16]; ++ int32_t mdns_y_shp_c_0_npv_array[9]; ++ int32_t mdns_y_shp_c_1_npv_array[9]; ++ int32_t mdns_y_shp_c_2_npv_array[9]; ++ int32_t mdns_y_shp_c_3_npv_array[9]; ++ int32_t mdns_y_shp_c_4_npv_array[9]; ++ int32_t mdns_y_shp_c_5_npv_array[9]; ++ int32_t mdns_y_shp_c_6_npv_array[9]; ++ int32_t mdns_y_shp_c_7_npv_array[9]; ++ int32_t mdns_y_shp_c_8_npv_array[9]; ++ int32_t mdns_y_shp_c_9_npv_array[9]; ++ int32_t mdns_y_shp_c_a_npv_array[9]; ++ int32_t mdns_y_shp_c_b_npv_array[9]; ++ int32_t mdns_y_shp_c_c_npv_array[9]; ++ int32_t mdns_y_shp_c_d_npv_array[9]; ++ int32_t mdns_y_shp_c_e_npv_array[9]; ++ int32_t mdns_y_shp_c_f_npv_array[9]; ++ int32_t mdns_y_shp_r_0_npv_array[9]; ++ int32_t mdns_y_shp_r_1_npv_array[9]; ++ int32_t mdns_y_shp_r_2_npv_array[9]; ++ int32_t mdns_y_shp_r_3_npv_array[9]; ++ int32_t mdns_y_shp_r_4_npv_array[9]; ++ int32_t mdns_y_shp_r_5_npv_array[9]; ++ int32_t mdns_y_shp_r_6_npv_array[9]; ++ int32_t mdns_y_shp_r_7_npv_array[9]; ++ int32_t mdns_y_shp_r_8_npv_array[9]; ++ int32_t mdns_y_shp_r_9_npv_array[9]; ++ int32_t mdns_y_shp_r_a_npv_array[9]; ++ int32_t mdns_y_shp_r_b_npv_array[9]; ++ int32_t mdns_y_shp_r_c_npv_array[9]; ++ int32_t mdns_y_shp_r_d_npv_array[9]; ++ int32_t mdns_y_shp_r_e_npv_array[9]; ++ int32_t mdns_y_shp_r_f_npv_array[9]; ++ int32_t mdns_y_adj_cnr_array[4]; ++ int32_t mdns_y_fluct_lmt_array[8]; ++ int32_t mdns_y_adj_sta_array[9]; ++ int32_t mdns_y_adj_tedg_s_array[9]; ++ int32_t mdns_y_adj_wedg_s_array[9]; ++ int32_t mdns_y_adj_tedg_n_array[8]; ++ int32_t mdns_y_adj_wedg_n_array[8]; ++ int32_t mdns_y_adj_lum_win_array[1]; ++ int32_t mdns_y_adj_tlum_s_array[9]; ++ int32_t mdns_y_adj_wlum_s_array[9]; ++ int32_t mdns_y_adj_tlum_n_array[16]; ++ int32_t mdns_y_adj_wlum_n_array[16]; ++ int32_t mdns_c_sad_thres_array[9]; ++ int32_t mdns_c_sad_win_opt_array[9]; ++ int32_t mdns_c_sad_stren_array[9]; ++ int32_t mdns_c_sta_stren_array[9]; ++ int32_t mdns_c_pbt_stren_array[9]; ++ int32_t mdns_c_sad_npv_array[4]; ++ int32_t mdns_c_sta_npv_array[32]; ++ int32_t mdns_c_pbt_npv_array[32]; ++ int32_t mdns_c_ref_wei_min_array[9]; ++ int32_t mdns_c_ref_wei_max_array[9]; ++ int32_t mdns_c_cur_blur_array[9]; ++ int32_t mdns_c_ref_blur_array[9]; ++ int32_t mdns_c_smj_thres_array[9]; ++ int32_t mdns_c_sfla_boh_t_array[9]; ++ int32_t mdns_c_sfla_cut_t_array[9]; ++ int32_t mdns_c_sfla_boh_s_array[9]; ++ int32_t mdns_c_sfla_cut_s_array[9]; ++ int32_t mdns_c_mfla_boh_t_array[9]; ++ int32_t mdns_c_mfla_cut_t_array[9]; ++ int32_t mdns_c_mfla_boh_s_array[9]; ++ int32_t mdns_c_mfla_cut_s_array[9]; ++ int32_t mdns_c_adj_cnr_array[4]; ++ int32_t mdns_c_adj_sta_array[6]; ++ int32_t mdns_c_adj_tcrm_s_array[9]; ++ int32_t mdns_c_adj_wcrm_s_array[9]; ++ int32_t mdns_c_adj_tcrm_n_array[8]; ++ int32_t mdns_c_adj_wcrm_n_array[8]; ++ ++ /* mdns intp parameters */ ++ uint32_t mdns_sta_size_intp; ++ uint32_t mdns_pbt_size_intp; ++ uint32_t mdns_y_sad_thres_intp; ++ uint32_t mdns_y_sta_thres_intp; ++ uint32_t mdns_y_pbt_thres_intp; ++ uint32_t mdns_y_sad_stren_intp; ++ uint32_t mdns_y_sta_stren_intp; ++ uint32_t mdns_y_pbt_stren_intp; ++ uint32_t mdns_y_sad_win_opt_intp; ++ uint32_t mdns_y_sta_win_opt_intp; ++ uint32_t mdns_y_pbt_win_opt_intp; ++ uint32_t mdns_y_sad_win_wei_intp; ++ uint32_t mdns_y_sta_win_wei_intp; ++ uint32_t mdns_y_pbt_win_wei_intp; ++ uint32_t mdns_y_sta_mv_num_intp; ++ uint32_t mdns_y_pbt_mv_num_intp; ++ uint32_t mdns_y_sta_mx_num_intp; ++ uint32_t mdns_y_pbt_mx_num_intp; ++ uint32_t mdns_y_ref_wei_min_intp; ++ uint32_t mdns_y_ref_wei_max_intp; ++ uint32_t mdns_y_edge_win_intp; ++ uint32_t mdns_y_bi_thres_intp; ++ uint32_t mdns_y_smj_thres_intp; ++ uint32_t mdns_y_shp_swei_intp; ++ uint32_t mdns_y_shp_mwei_intp; ++ uint32_t mdns_y_cs_bhold_intp; ++ uint32_t mdns_y_cm_bhold_intp; ++ uint32_t mdns_y_rs_bhold_intp; ++ uint32_t mdns_y_rm_bhold_intp; ++ uint32_t mdns_y_cs_bwin_intp; ++ uint32_t mdns_y_cm_bwin_intp; ++ uint32_t mdns_y_rs_bwin_intp; ++ uint32_t mdns_y_rm_bwin_intp; ++ uint32_t mdns_y_cs_iwin_intp; ++ uint32_t mdns_y_cm_iwin_intp; ++ uint32_t mdns_y_rs_iwin_intp; ++ uint32_t mdns_y_rm_iwin_intp; ++ uint32_t mdns_y_cs_ewin_intp; ++ uint32_t mdns_y_cm_ewin_intp; ++ uint32_t mdns_y_rs_ewin_intp; ++ uint32_t mdns_y_rm_ewin_intp; ++ uint32_t mdns_y_cs_sego_intp; ++ uint32_t mdns_y_cm_sego_intp; ++ uint32_t mdns_y_rs_sego_intp; ++ uint32_t mdns_y_rm_sego_intp; ++ uint32_t mdns_y_cs_stren_intp; ++ uint32_t mdns_y_cm_stren_intp; ++ uint32_t mdns_y_rs_stren_intp; ++ uint32_t mdns_y_rm_stren_intp; ++ uint32_t mdns_y_shp_c_0_npv_intp; ++ uint32_t mdns_y_shp_c_1_npv_intp; ++ uint32_t mdns_y_shp_c_2_npv_intp; ++ uint32_t mdns_y_shp_c_3_npv_intp; ++ uint32_t mdns_y_shp_c_4_npv_intp; ++ uint32_t mdns_y_shp_c_5_npv_intp; ++ uint32_t mdns_y_shp_c_6_npv_intp; ++ uint32_t mdns_y_shp_c_7_npv_intp; ++ uint32_t mdns_y_shp_c_8_npv_intp; ++ uint32_t mdns_y_shp_c_9_npv_intp; ++ uint32_t mdns_y_shp_c_a_npv_intp; ++ uint32_t mdns_y_shp_c_b_npv_intp; ++ uint32_t mdns_y_shp_c_c_npv_intp; ++ uint32_t mdns_y_shp_c_d_npv_intp; ++ uint32_t mdns_y_shp_c_e_npv_intp; ++ uint32_t mdns_y_shp_c_f_npv_intp; ++ uint32_t mdns_y_shp_r_0_npv_intp; ++ uint32_t mdns_y_shp_r_1_npv_intp; ++ uint32_t mdns_y_shp_r_2_npv_intp; ++ uint32_t mdns_y_shp_r_3_npv_intp; ++ uint32_t mdns_y_shp_r_4_npv_intp; ++ uint32_t mdns_y_shp_r_5_npv_intp; ++ uint32_t mdns_y_shp_r_6_npv_intp; ++ uint32_t mdns_y_shp_r_7_npv_intp; ++ uint32_t mdns_y_shp_r_8_npv_intp; ++ uint32_t mdns_y_shp_r_9_npv_intp; ++ uint32_t mdns_y_shp_r_a_npv_intp; ++ uint32_t mdns_y_shp_r_b_npv_intp; ++ uint32_t mdns_y_shp_r_c_npv_intp; ++ uint32_t mdns_y_shp_r_d_npv_intp; ++ uint32_t mdns_y_shp_r_e_npv_intp; ++ uint32_t mdns_y_shp_r_f_npv_intp; ++ uint32_t mdns_y_adj_tedg_s_intp; ++ uint32_t mdns_y_adj_wedg_s_intp; ++ uint32_t mdns_y_adj_tlum_s_intp; ++ uint32_t mdns_y_adj_wlum_s_intp; ++ uint32_t mdns_c_sad_thres_intp; ++ uint32_t mdns_c_sad_win_opt_intp; ++ uint32_t mdns_c_sad_stren_intp; ++ uint32_t mdns_c_sta_stren_intp; ++ uint32_t mdns_c_pbt_stren_intp; ++ uint32_t mdns_c_ref_wei_min_intp; ++ uint32_t mdns_c_ref_wei_max_intp; ++ uint32_t mdns_c_cur_blur_intp; ++ uint32_t mdns_c_ref_blur_intp; ++ uint32_t mdns_c_smj_thres_intp; ++ uint32_t mdns_c_sfla_boh_t_intp; ++ uint32_t mdns_c_sfla_cut_t_intp; ++ uint32_t mdns_c_sfla_boh_s_intp; ++ uint32_t mdns_c_sfla_cut_s_intp; ++ uint32_t mdns_c_mfla_boh_t_intp; ++ uint32_t mdns_c_mfla_cut_t_intp; ++ uint32_t mdns_c_mfla_boh_s_intp; ++ uint32_t mdns_c_mfla_cut_s_intp; ++ uint32_t mdns_c_adj_tcrm_s_intp; ++ uint32_t mdns_c_adj_wcrm_s_intp; ++ void *core; ++} tisp_mdns_t; ++ ++/* -------- clm --------*/ ++typedef struct tisp_clm { ++ int32_t tiziano_clm_h_lut[30 * 7 * 5]; ++ int32_t tiziano_clm_s_lut[30 * 7 * 5]; ++ int32_t tiziano_clm_s_reg[420]; ++ int32_t tiziano_clm_h_reg[420]; ++ uint32_t tiziano_clm_lut_shift; ++ ++ void *core; ++} tisp_clm_t; ++ ++ ++/* ------------ hldc ------------*/ ++typedef struct tisp_hldc { ++ uint32_t hldc_con_par_array[18]; ++ ++ void *core; ++} tisp_hldc_t; ++ ++typedef int32_t (*net_event_cb)(void *cb_data, void *data, uint32_t len); ++typedef struct tisp_netlink { ++ struct sock *nlsk; ++ net_event_cb net_event_process; ++ void *cb_data; ++} tisp_netlink_t; ++ ++ ++/*------------param_op-----------*/ ++typedef struct { ++ uint32_t msg_type; ++ uint32_t msg_data1; ++ uint32_t msg_data2; ++ uint32_t msg_data3; ++ uint32_t msg_data4; ++ uint32_t msg_ret; ++ uint8_t msg_buf[0]; ++} tisp_param_op_msg_t; ++ ++typedef struct tisp_param_operate { ++ tisp_param_op_msg_t *opmsg; /*tisp_param_op_msg_t 类型.*/ ++ tisp_netlink_t nl; ++ ++ void *core; ++} tisp_param_operate_t; ++ ++ ++/* ---------- event ----------*/ ++enum { ++ //ae ++ TISP_EVENT_TYPE_START = 0, ++ TISP_EVENT_TYPE_EXIT = TISP_EVENT_TYPE_START, ++ TISP_EVENT_TYPE_AE_PROCESS, ++ TISP_EVENT_TYPE_ADR_PROCESS, ++ TISP_EVENT_TYPE_DEFOG_PROCESS, ++ TISP_EVENT_TYPE_AE_TGAIN_UPDATE, ++ TISP_EVENT_TYPE_AE_AGAIN_UPDATE, ++ //for awb ++ TISP_EVENT_TYPE_AE_EV, ++ TISP_EVENT_TYPE_AE_IR, ++ TISP_EVENT_TYPE_AWB_CT, ++ //for awb ++ TISP_EVENT_TYPE_WB_STAITCS, ++ TISP_EVENT_TYPE_MAX, ++}; ++ ++#define TISP_PROCESS_EVENT_NUM 20 ++ ++typedef struct { ++ struct list_head entry; ++ uint32_t type; ++ uint64_t data1; ++ uint64_t data2; ++ uint64_t data3; ++ uint64_t data4; ++} tisp_event_t; ++ ++typedef struct { ++ struct completion event_compl; ++ tisp_event_t events[TISP_PROCESS_EVENT_NUM]; ++ struct list_head event_working; ++ struct list_head event_free; ++ spinlock_t event_slock; ++} tisp_event_info_t; ++ ++typedef int32_t (*event_process_cb)(void *cb_data, uint64_t data1, uint64_t data2, uint64_t data3, uint64_t data4); ++ ++/* event manager .*/ ++typedef struct tisp_event_mg { ++ tisp_event_info_t tevent_info; ++ ++ event_process_cb cb[TISP_EVENT_TYPE_MAX]; ++ void *cb_data[TISP_EVENT_TYPE_MAX]; ++ ++ void *core; ++ ++} tisp_event_mg_t; ++ ++ ++ ++typedef struct tisp_core { ++ tisp_info_t tispinfo; ++ ++ sensor_control_t sensor_ctrl; ++ struct sensor_control_ops *sensor_ctrl_ops; ++ ++ tisp_custom_effect_t custom_eff; ++ tisp_mdns_ratio_t mdns_ratio; ++ int deir_en; ++ int ae_switch; ++ uint32_t topreg_val; ++ tisp_init_param_t sensor_info; ++ ++ /* sub handles. */ ++ tisp_awb_t awb; ++ tisp_gamma_t gamma; ++ tisp_defog_t defog; ++ tisp_adr_t adr; ++ tisp_ae_t ae; ++ tisp_af_t af; ++ tisp_gib_t gib; ++ tisp_dmsc_t dmsc; ++ tisp_lsc_t lsc; ++ tisp_ccm_t ccm; ++ tisp_sharpen_t sharpen; ++ tisp_dpc_t dpc; ++ tisp_sdns_t sdns; ++ tisp_mdns_t mdns; ++ tisp_clm_t clm; ++ tisp_hldc_t hldc; ++ tisp_param_operate_t param_operate; ++ ++ tisp_core_tuning_t core_tuning; ++ tisp_event_mg_t tisp_event_mg; ++ ++ void *tuned_params; ++ loff_t tuned_params_size; ++ ++ void *priv_data; ++} tisp_core_t; ++ ++int tisp_core_init(tisp_core_t *core, tisp_init_param_t *p, void *priv_data); ++int tisp_core_deinit(tisp_core_t *core); ++ ++int tisp_channel_start(tisp_core_t *core, int chx); ++int tisp_channel_start_restore(tisp_core_t *core); ++int tisp_channel_stop(tisp_core_t *core, int chx); ++int tisp_channel_stop_save(tisp_core_t *core); ++int tisp_channel_attr_set(tisp_core_t *core, int chx ,tisp_channel_attr_t * cattr); ++int tisp_channel_attr_set_crop_scaler(tisp_core_t *core, int chx ,tisp_channel_attr_t * cattr); ++ ++int tisp_fw_process(tisp_core_t *core); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_core_tuning.h b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_core_tuning.h +new file mode 100644 +index 000000000..5d351588e +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_core_tuning.h +@@ -0,0 +1,170 @@ ++#ifndef __TIZIANO_TIZIANO_CORE_TUNING_H__ ++#define __TIZIANO_TIZIANO_CORE_TUNING_H__ ++#include "tiziano_isp.h" ++ ++extern int day_night; ++ ++typedef enum tisp_mode_day_and_night { ++ TISP_MODE_DAY_MODE, ++ TISP_MODE_NIGHT_MODE, ++ TISP_MODE_BUTT, ++} TISP_MODE_DN_E; ++ ++typedef struct tisp_custom_effect { ++ unsigned char brightness; ++ unsigned char sharpness; ++ unsigned char contrast; ++ unsigned char saturation; ++ unsigned int brightness_ori_day[20]; ++ unsigned int brightness_ori_night[20]; ++ unsigned int saturation_ori_day[9]; ++ unsigned int sharpen_ori_day[36]; ++ unsigned int sharpen_ori_night[36]; ++ ++} tisp_custom_effect_t; ++ ++typedef struct tisp_mdns_ratio { ++ int dysad_thres_def_day[9]; ++ int dysta_thres_def_day[9]; ++ int dypbt_thres_def_day[9]; ++ int dywei_max_def_day[9]; ++ int dywei_min_def_day[9]; ++ int dysad_thres_def_night[9]; ++ int dysta_thres_def_night[9]; ++ int dypbt_thres_def_night[9]; ++ int dywei_max_def_night[9]; ++ int dywei_min_def_night[9]; ++} tisp_mdns_ratio_t; ++ ++typedef struct tisp_ncu_info { ++ uint32_t width; ++ uint32_t height; ++ uint32_t sta_y_block_size; ++ uint32_t sta_y_stride; ++ uint32_t sta_y_buf_size; ++} tisp_ncu_info_t; ++ ++typedef struct tisp_gamma_lut{ ++ unsigned int gamma[129]; ++} tisp_gamma_lut_t; ++ ++typedef struct tisp_3a_weight{ ++ unsigned int weight[225]; ++} tisp_3a_weight_t; ++ ++typedef struct tisp_zone_info{ ++ unsigned int zone[15][15]; ++} tisp_zone_info_t; ++ ++typedef struct tisp_ev_attr { ++ unsigned int integration_time; ++ unsigned int ev; ++ unsigned int expr_us; ++ unsigned int ev_log2; ++ unsigned int again; ++ unsigned int dgain; ++ unsigned int gain_log2; ++ unsigned int total_gain; ++ unsigned int max_again; ++ unsigned int max_isp_dgain; ++ unsigned int sensor_dgain; ++ unsigned int max_sensor_dgain; ++ int manual_it; ++ int manual_ag; ++ int manual_isp_dgain; ++} tisp_ev_attr_t; ++ ++typedef struct tisp_ae_ex_min { ++ unsigned int min_it; ++ unsigned int min_again; ++} tisp_ae_ex_min_t; ++ ++typedef union tisp_module_control { ++ unsigned int key; ++ struct { ++ unsigned int bitBypassDPC : 1; /* [0] */ ++ unsigned int bitBypassGIB : 1; /* [1] */ ++ unsigned int bitBypassLSC : 1; /* [2] */ ++ unsigned int bitBypassAWB : 1; /* [3] */ ++ unsigned int bitBypassADR : 1; /* [4] */ ++ unsigned int bitBypassDMSC : 1; /* [5] */ ++ unsigned int bitBypassCCM : 1; /* [6] */ ++ unsigned int bitBypassGAMMA : 1; /* [7] */ ++ unsigned int bitBypassDEFOG : 1; /* [8] */ ++ unsigned int bitBypassCLM : 1; /* [9] */ ++ unsigned int bitBypassYSHARPEN : 1; /* [10] */ ++ unsigned int bitBypassMDNS : 1; /* [11] */ ++ unsigned int bitBypassSDNS : 1; /* [12] */ ++ unsigned int bitBypassHLDC : 1; /* [13] */ ++ unsigned int bitBypassTP : 1; /* [14] */ ++ unsigned int bitBypassFONT : 1; /* [15] */ ++ unsigned int bitRsv : 15; /* [16 ~ 30] */ ++ unsigned int bitRsv2 : 1; /* [31] */ ++ }; ++} tisp_module_control_t; ++ ++ ++ ++typedef struct tisp_core_tuning { ++ int day_night; ++ int flicker_hz; ++ void *core; /*tisp_core_t in tiziano_core.h*/ ++} tisp_core_tuning_t; ++ ++ ++int32_t tisp_day_or_night_s_ctrl(tisp_core_tuning_t *core_tuning, TISP_MODE_DN_E dn); ++TISP_MODE_DN_E tisp_day_or_night_g_ctrl(tisp_core_tuning_t *core_tuning); ++void tisp_mirror_enable(tisp_core_tuning_t *core_tuning, int en); ++void tisp_flip_enable(tisp_core_tuning_t *core_tuning, int en); ++int tisp_set_fps(tisp_core_tuning_t *core_tuning, int fps); ++ ++void tisp_set_brightness(tisp_core_tuning_t *core_tuning, unsigned char brightness); ++void tisp_set_sharpness(tisp_core_tuning_t *core_tuning, unsigned char sharpness); ++void tisp_set_saturation(tisp_core_tuning_t *core_tuning, unsigned char saturation); ++void tisp_set_contrast(tisp_core_tuning_t *core_tuning, unsigned char contrast); ++ ++unsigned char tisp_get_brightness(tisp_core_tuning_t *core_tuning); ++unsigned char tisp_get_sharpness(tisp_core_tuning_t *core_tuning); ++unsigned char tisp_get_saturation(tisp_core_tuning_t *core_tuning); ++unsigned char tisp_get_contrast(tisp_core_tuning_t *core_tuning); ++void tisp_top_sel(tisp_core_tuning_t *core_tuning, int sel); ++int tisp_g_ncuinfo(tisp_core_tuning_t *core_tuning, tisp_ncu_info_t *ncuinfo); ++unsigned int tisp_top_read(tisp_core_tuning_t *core_tuning); ++int tisp_s_antiflick(tisp_core_tuning_t *core_tuning, int hz); ++int tisp_s_Hilightdepress(tisp_core_tuning_t *core_tuning, unsigned int strength); ++int tisp_g_Hilightdepress(tisp_core_tuning_t *core_tuning, unsigned int *strength); ++int tisp_s_Gamma(tisp_core_tuning_t *core_tuning, tisp_gamma_lut_t *gammas); ++int tisp_g_Gamma(tisp_core_tuning_t *core_tuning, tisp_gamma_lut_t *gammag); ++int tisp_s_aeroi_weight(tisp_core_tuning_t *core_tuning, tisp_3a_weight_t * roi_weight); ++int tisp_g_aeroi_weight(tisp_core_tuning_t *core_tuning, tisp_3a_weight_t * roi_weight); ++int tisp_s_aezone_weight(tisp_core_tuning_t *core_tuning, tisp_3a_weight_t * zone_weight); ++int tisp_g_aezone_weight(tisp_core_tuning_t *core_tuning, tisp_3a_weight_t * zone_weight); ++int tisp_g_ev_attr(tisp_core_tuning_t *core_tuning, tisp_ev_attr_t *ev_attr); ++int tisp_g_wb_attr(tisp_core_tuning_t *core_tuning, tisp_wb_attr_t *wb_attr); ++int tisp_s_wb_frz_attr(tisp_core_tuning_t *core_tuning, unsigned char frz); ++int tisp_s_wb_attr(tisp_core_tuning_t *core_tuning, tisp_wb_attr_t wb_attr); ++int tisp_g_ae_hist(tisp_core_tuning_t *core_tuning, tisp_ae_sta_t *ae_hist); ++int tisp_s_ae_hist(tisp_core_tuning_t *core_tuning, tisp_ae_sta_t ae_hist); ++int tisp_s_3dns_ratio(tisp_core_tuning_t *core_tuning, unsigned int ratio); ++int tisp_s_ae_attr(tisp_core_tuning_t *core_tuning, tisp_ev_attr_t ae_attr); ++int tisp_s_ae_attr_ag(tisp_core_tuning_t *core_tuning, tisp_ev_attr_t ae_attr); ++int tisp_g_ae_attr(tisp_core_tuning_t *core_tuning, tisp_ev_attr_t *ae_attr); ++int tisp_s_ae_min(tisp_core_tuning_t *core_tuning, tisp_ae_ex_min_t ae_min); ++int tisp_g_ae_min(tisp_core_tuning_t *core_tuning, tisp_ae_ex_min_t *ae_min); ++int tisp_g_ae_zone(tisp_core_tuning_t *core_tuning, tisp_zone_info_t *ae_zone); ++void tisp_g_ae_luma(tisp_core_tuning_t *core_tuning, unsigned char *luma, int width, int height); ++int tisp_g_af_metric(tisp_core_tuning_t *core_tuning, unsigned int *metric); ++int tisp_g_af_attr(tisp_core_tuning_t *core_tuning, tisp_af_attr *af_info); ++int tisp_s_af_attr(tisp_core_tuning_t *core_tuning, tisp_af_attr af_info); ++int tisp_s_af_weight(tisp_core_tuning_t *core_tuning, tisp_3a_weight_t * af_weight); ++int tisp_g_af_weight(tisp_core_tuning_t *core_tuning, tisp_3a_weight_t * af_weight); ++void tisp_s_wb_frz(tisp_core_tuning_t *core_tuning, unsigned char frz); ++void tisp_g_wb_frz(tisp_core_tuning_t *core_tuning, unsigned char *frz); ++void tisp_s_module_control(tisp_core_tuning_t *core_tuning, tisp_module_control_t top); ++void tisp_g_module_control(tisp_core_tuning_t *core_tuning, tisp_module_control_t *top); ++void tisp_s_ev_start(tisp_core_tuning_t *core_tuning, unsigned int ev_start); ++void tisp_s_max_again(tisp_core_tuning_t *core_tuning, unsigned int max_again); ++void tisp_s_max_isp_dgain(tisp_core_tuning_t *core_tuning, unsigned int max_isp_dgain); ++int tisp_g_drc_strength(tisp_core_tuning_t *core_tuning, unsigned int *strength); ++int tisp_s_drc_strength(tisp_core_tuning_t *core_tuning, unsigned int strength); ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_isp.h b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_isp.h +new file mode 100755 +index 000000000..e756bbee2 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_isp.h +@@ -0,0 +1,104 @@ ++#ifndef __TIZIANO_ISP_H__ ++#define __TIZIANO_ISP_H__ ++ ++typedef struct { ++ unsigned int max_again; //the format is .16 ++ unsigned int max_dgain; //the format is .16 ++ unsigned int again; ++ unsigned int dgain; ++ unsigned int fps; ++ unsigned short min_integration_time; ++ unsigned short min_integration_time_native; ++ unsigned short max_integration_time_native; ++ unsigned short integration_time_limit; ++ unsigned int integration_time; ++ unsigned short total_width; ++ unsigned short total_height; ++ unsigned short max_integration_time; ++ unsigned short integration_time_apply_delay; ++ unsigned short again_apply_delay; ++ unsigned short dgain_apply_delay; ++ unsigned short one_line_expr_in_us; ++} sensor_info_t; ++ ++typedef struct { ++ int width; ++ int height; ++ int bayer; ++ char sensor[16]; ++ sensor_info_t sensor_info; ++} tisp_init_param_t; ++ ++typedef struct { ++ int sensor_width; ++ int sensor_height; ++ unsigned int buf_ae_num; ++ unsigned int buf_ae_vaddr; ++ unsigned int buf_ae_paddr; ++ unsigned int buf_aehist_num; ++ unsigned int buf_aehist_vaddr; ++ unsigned int buf_aehist_paddr; ++ unsigned int buf_awb_num; ++ unsigned int buf_awb_vaddr; ++ unsigned int buf_awb_paddr; ++ unsigned int buf_adr_num; ++ unsigned int buf_adr_vaddr; ++ unsigned int buf_adr_paddr; ++ unsigned int buf_defog_num; ++ unsigned int buf_defog_vaddr; ++ unsigned int buf_defog_paddr; ++ unsigned int buf_af_num; ++ unsigned int buf_af_vaddr; ++ unsigned int buf_af_paddr; ++ ++} tisp_info_t; ++ ++ ++typedef struct { ++ int scaler_en; ++ int scaler_width; ++ int scaler_height; ++ int crop_en; ++ int crop_x; ++ int crop_y; ++ int crop_width; ++ int crop_height; ++} tisp_channel_attr_t; ++ ++ ++ ++typedef struct { ++ uint32_t tisp_wb_manual; ++ uint32_t tisp_wb_rg; ++ uint32_t tisp_wb_bg; ++ uint32_t tisp_wb_rg_sta_global; ++ uint32_t tisp_wb_bg_sta_global; ++ uint32_t tisp_wb_rg_sta_weight; ++ uint32_t tisp_wb_bg_sta_weight; ++} tisp_wb_attr_t; ++ ++typedef struct { ++ int ae_hist[256]; ++ int ae_hist_5bin[5]; ++ int ae_hist_nodes[4]; ++ int ae_hist_hv[2]; ++} tisp_ae_sta_t; ++ ++typedef struct { ++ unsigned int af_metrics; ++ unsigned int af_metrics_alt; ++ unsigned char af_enable; ++ unsigned char af_metrics_shift; ++ unsigned short af_delta; ++ unsigned short af_theta; ++ unsigned short af_hilight_th; ++ unsigned short af_alpha_alt; ++ unsigned char af_hstart; ++ unsigned char af_vstart; ++ unsigned char af_stat_nodeh; ++ unsigned char af_stat_nodev; ++} tisp_af_attr; ++ ++//extern tisp_ae_ctrls_t tisp_ae_ctrls; ++extern tisp_init_param_t sensor_info; ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_netlink.h b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_netlink.h +new file mode 100644 +index 000000000..06a6adf00 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_netlink.h +@@ -0,0 +1,12 @@ ++#ifndef __TIZIANO_NETLINK_H__ ++#define __TIZIANO_NETLINK_H__ ++#include "tiziano_core.h" ++ ++int32_t netlink_send_msg(tisp_netlink_t *nl, int8_t *pbuf, uint16_t len); ++int32_t tisp_netlink_event_set_cb(tisp_netlink_t *nl, net_event_cb cb, void *cb_data); ++ ++int32_t tisp_netlink_init(tisp_netlink_t *nl); ++ ++void tisp_netlink_exit(tisp_netlink_t *nl); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_priv.h b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_priv.h +new file mode 100644 +index 000000000..abd92e6fb +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_priv.h +@@ -0,0 +1,47 @@ ++#ifndef __TIZIANO_PRIV_H__ ++#define __TIZIANO_PRIV_H__ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++void *isp_kmalloc(size_t size, gfp_t flags); ++void isp_kfree(void *objp); ++ ++void isp_spin_lock_init(spinlock_t *lock); ++void _isp_spin_lock_irqsave(spinlock_t *lock, unsigned long *flags); ++#define isp_spin_lock_irqsave(lock, flags) \ ++ _isp_spin_lock_irqsave(lock, (&flags)); ++void isp_spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags); ++ ++#define ISP_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL ++void isp_dma_cache_sync(struct device *dev, void *vaddr, size_t size, ++ enum dma_data_direction direction); ++ ++void ISP_INIT_LIST_HEAD(struct list_head *list); ++void isp_list_add_tail(struct list_head *new, struct list_head *head); ++#define isp_list_first_entry(ptr, type, member) list_first_entry(ptr, type, member) ++void isp_list_del(struct list_head *entry); ++int isp_list_empty(const struct list_head *head); ++ ++void isp_complete(struct completion *); ++unsigned long isp_wait_for_completion_timeout(struct completion *x, unsigned long timeout); ++void isp_init_completion(struct completion *x); ++ ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_sys.h b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_sys.h +new file mode 100644 +index 000000000..8abaeafb0 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/inc/tiziano_sys.h +@@ -0,0 +1,10 @@ ++#ifndef __TIZIANO_SYS_H__ ++#define __TIZIANO_SYS_H__ ++ ++extern int system_reg_write(void *hdl, unsigned int reg, unsigned int value); ++extern unsigned int system_reg_read(void *hdl, unsigned int reg); ++extern int system_lock(void *hdl); ++extern int system_unlock(void *hdl); ++extern int system_irq_func_set(void *hdl, int irq, void *func, void *data); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/src/Makefile b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/src/Makefile +new file mode 100644 +index 000000000..e3c2e981f +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/src/Makefile +@@ -0,0 +1,2 @@ ++obj-y += isp-core.a ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/tiziano_netlink.c b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/tiziano_netlink.c +new file mode 100644 +index 000000000..eaee433df +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/tiziano_netlink.c +@@ -0,0 +1,125 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "inc/tiziano_netlink.h" ++ ++#define NETLINK_USER 22 ++#define USER_MSG (NETLINK_USER + 1) ++#define USER_PORT 50 ++ ++#if 0 ++static struct sock *nlsk = NULL; ++#endif ++struct nl_sock_map { ++ tisp_netlink_t *nl; ++ struct sock *nlsk; ++}; ++ ++#define MAX_NL_SK 2 ++struct nl_sock_map nl_sock_map[MAX_NL_SK] = {NULL}; ++ ++static tisp_netlink_t * sock_to_nl(struct sock *sk) ++{ ++ int i = 0; ++ for(i = 0; i < MAX_NL_SK; i++) { ++ if(nl_sock_map[i].nlsk == sk) { ++ return nl_sock_map[i].nl; ++ } ++ } ++ ++ return NULL; ++} ++ ++//net_event_cb net_event_process = NULL; ++ ++int32_t netlink_send_msg(tisp_netlink_t *nl, int8_t *pbuf, uint16_t len) ++{ ++ int32_t ret; ++ struct sk_buff *nl_skb; ++ struct nlmsghdr *nlh; ++ nl_skb = nlmsg_new(len, GFP_ATOMIC); ++ if (!nl_skb) { ++ pr_err("%s,%d: netlink_alloc_skb error\n", __func__, __LINE__); ++ return -1; ++ } ++ nlh = nlmsg_put(nl_skb, 0, 0, USER_MSG, len, 0); ++ if (nlh == NULL) { ++ pr_err("%s,%d: nlmsg_put() error\n", __func__, __LINE__); ++ nlmsg_free(nl_skb); ++ return -1; ++ } ++ memcpy(nlmsg_data(nlh), pbuf, len); ++ ret = netlink_unicast(nl->nlsk, nl_skb, USER_PORT, MSG_DONTWAIT); ++ return ret; ++} ++ ++static void netlink_rcv_msg(struct sk_buff *skb) ++{ ++ struct nlmsghdr *nlh = NULL; ++ struct sock *sock = skb->sk; ++ tisp_netlink_t * nl = sock_to_nl(sock); ++ void *data = NULL; ++ ++ if (skb->len >= nlmsg_total_size(0)) { ++ nlh = nlmsg_hdr(skb); ++ data = NLMSG_DATA(nlh); ++ if (data) { ++ if (NULL != nl->net_event_process) { ++ nl->net_event_process(nl->cb_data, data, nlmsg_len(nlh)); ++ } ++ //netlink_send_msg(data, nlmsg_len(nlh)); ++ } ++ } ++} ++ ++struct netlink_kernel_cfg nlcfg = { ++ .input = netlink_rcv_msg, ++}; ++ ++int32_t tisp_netlink_event_set_cb(tisp_netlink_t *nl, net_event_cb cb, void *cb_data) ++{ ++ nl->net_event_process = cb; ++ nl->cb_data = cb_data; ++ return 0; ++} ++ ++int32_t tisp_netlink_init(tisp_netlink_t *nl) ++{ ++// pr_err("%s,%d: \n", __func__, __LINE__); ++ int i; ++ nl->nlsk = (struct sock *)netlink_kernel_create(&init_net, USER_MSG, &nlcfg); ++ if (!nl->nlsk) { ++ pr_err("%s,%d: create netlink socket error.\n", __func__, __LINE__); ++ return -1; ++ } ++ ++ for(i = 0; i < MAX_NL_SK; i++) { ++ if(nl_sock_map[i].nl == NULL || nl_sock_map[i].nlsk == NULL) { ++ nl_sock_map[i].nl = nl; ++ nl_sock_map[i].nlsk = nl->nlsk; ++ } ++ } ++// pr_err("%s,%d: \n", __func__, __LINE__); ++ return 0; ++} ++ ++void tisp_netlink_exit(tisp_netlink_t *nl) ++{ ++ int i; ++ ++ if (nl->nlsk != NULL && nl->nlsk->sk_socket != NULL) { ++ sock_release(nl->nlsk->sk_socket); ++ } ++ ++ for(i = 0; i < MAX_NL_SK; i++) { ++ if(nl_sock_map[i].nl == nl) { ++ nl_sock_map[i].nl = NULL; ++ nl_sock_map[i].nlsk = NULL; ++ } ++ } ++ ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-core/tiziano_priv.c b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/tiziano_priv.c +new file mode 100644 +index 000000000..6fe89ab66 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-core/tiziano_priv.c +@@ -0,0 +1,56 @@ ++#include "inc/tiziano_priv.h" ++ ++void *isp_kmalloc(size_t size, gfp_t flags){ ++ return kmalloc(size, flags); ++} ++ ++void isp_kfree(void *objp){ ++ kfree(objp); ++} ++ ++void isp_spin_lock_init(spinlock_t *lock){ ++ spin_lock_init(lock); ++} ++ ++void _isp_spin_lock_irqsave(spinlock_t *lock, unsigned long *flags){ ++ spin_lock_irqsave(lock, *flags); ++} ++ ++void isp_spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags){ ++ spin_unlock_irqrestore(lock, flags); ++} ++ ++void isp_dma_cache_sync(struct device *dev, void *vaddr, size_t size, ++ enum dma_data_direction direction) ++{ ++ arch_sync_dma_for_device(virt_to_phys(vaddr),size,direction); ++} ++ ++ ++void ISP_INIT_LIST_HEAD(struct list_head *list){ ++ INIT_LIST_HEAD(list); ++} ++ ++void isp_list_add_tail(struct list_head *new, struct list_head *head){ ++ list_add_tail(new, head); ++} ++ ++void isp_list_del(struct list_head *entry){ ++ list_del(entry); ++} ++ ++int isp_list_empty(const struct list_head *head){ ++ return list_empty(head); ++} ++ ++void isp_complete(struct completion *com){ ++ complete(com); ++} ++ ++unsigned long isp_wait_for_completion_timeout(struct completion *x, unsigned long timeout){ ++ return wait_for_completion_timeout(x, timeout); ++} ++ ++void isp_init_completion(struct completion *x){ ++ init_completion(x); ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-drv.c b/module_drivers/drivers/media/platform/ingenic-isp/isp-drv.c +new file mode 100644 +index 000000000..b79ed2f9b +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-drv.c +@@ -0,0 +1,451 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++ ++ ++static const struct of_device_id ingenic_isp_dt_match[]; ++ ++static int ingenic_isp_parse_dt(struct ispcam_device * ispcam) ++{ ++ struct device *dev = ispcam->dev; ++ struct device_node *node = NULL; ++ struct v4l2_async_notifier *notifier = &ispcam->notifier; ++ struct platform_device *pdev = NULL; ++ struct v4l2_async_subdev *asd = NULL; ++ const char *compatible = NULL; ++ unsigned int cplen = 0; ++ int ret = 0; ++ ++ ++ for_each_child_of_node(dev->of_node, node) { ++ compatible = of_get_property(node, "compatible", &cplen); ++ ++ if(!compatible && (cplen == 0)) { ++ continue; ++ } ++ if(!of_device_is_available(node)) { ++ continue; ++ } ++ pdev = of_platform_device_create(node, NULL,dev); ++ if(!pdev) { ++ printk("failed to populate_platform_device, node->full_name"); ++ } ++ ++ ispcam->subdevs[ispcam->subdev_num++] = pdev; ++ if(ispcam->subdev_num > MAX_SUB_DEVS) { ++ printk("too many sub platform devices!\n"); ++ return -EINVAL; ++ } ++ } ++ ++ ++ printk("start parse remote-endpoint!\n"); ++ asd = devm_kzalloc(dev, MAX_ASYNC_SUBDEVS * sizeof(*notifier->sd->asd), GFP_KERNEL); ++ ++ /* è§£æžendpoint, 远程端点,建立关系, åœ¨ä¸‹é¢æ³¨å†Œå›žè°ƒï¼Œç­‰æ³¨å†Œå®Œæˆé€šçŸ¥.创建video_device.*/ ++ ++ while((node = of_graph_get_next_endpoint(dev->of_node, node))) { ++ ++ /*TODO: 构建与vep对应的数æ®ç»“构,存储从dts中传入的数æ®.*/ ++ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &ispcam->vep[ispcam->asd_num]); ++ if(ret < 0) { ++ of_node_put(node); ++ return -EINVAL; ++ } ++ ispcam->isd[ispcam->asd_num].bus_type = ispcam->vep[ispcam->asd_num].bus_type; ++ ispcam->isd[ispcam->asd_num].parallel = ispcam->vep[ispcam->asd_num].bus.parallel; ++ ispcam->isd[ispcam->asd_num].mipi_csi2 = ispcam->vep[ispcam->asd_num].bus.mipi_csi2; ++ ++ ++ asd->match.fwnode = fwnode_graph_get_remote_port_parent(of_fwnode_handle(node)); ++ asd->match_type = V4L2_ASYNC_MATCH_FWNODE; ++ ++ of_node_put(node); ++ ++ ++ ++ v4l2_async_notifier_init(&ispcam->notifier); ++ ++ ret = v4l2_async_notifier_add_subdev(&ispcam->notifier, asd); ++ if (ret) { ++ fwnode_handle_put(asd->match.fwnode); ++ return ret; ++ } ++ ++ ++ ispcam->asd_num ++; ++ } ++ ++#if 0 ++ ++ printk("dump subdevs ------------ pdevs:\n"); ++ int i; ++ for(i = 0; i < ispcam->subdev_num; i++) { ++ printk("---sudev: %d, name: %s\n", i, ispcam->subdevs[i]->name); ++ } ++ ++ printk("dump async subdevs!\n"); ++ /*dump of parse subdevs.*/ ++ for(i = 0; i < ispcam->asd_num; i++) { ++ asd = &ispcam->isd[i].asd; ++ printk("asd: %d, asd->match.of.node->full_name: %s\n", i, asd->match.fwnode->dev->of_node->full_name); ++ } ++ ++#endif ++ return ret; ++} ++ ++static int ispcam_asd_notifier_bound(struct v4l2_async_notifier *async, ++ struct v4l2_subdev *subdev, ++ struct v4l2_async_subdev *asd) ++{ ++ struct ispcam_device *ispcam = container_of(async, struct ispcam_device, ++ notifier); ++ struct isp_async_device *isd = &ispcam->isd[0]; ++ ++ struct media_entity *entity = &subdev->entity; /*SOURCE_PAD*/ ++ int i = 0; ++ int ret = 0; ++ ++ if(entity->num_pads == 0) { ++ dev_err(ispcam->dev, "%s, %d No pad found in async entity(%s)\n", __func__, __LINE__, subdev->name); ++ return -EINVAL; ++ } ++ ++ for(i = 0; i < entity->num_pads; i++) { ++ if(entity->pads[i].flags & MEDIA_PAD_FL_SOURCE) ++ break; ++ } ++ ++ ++ if(i == entity->num_pads) { ++ dev_err(ispcam->dev, "%s, %d, no source pad in async entity (%s)\n", __func__, __LINE__, subdev->name); ++ return -EINVAL; ++ } ++ ++ isd->source_pad = i; ++ ++ isd->sd = subdev; ++ /*TODO: pass common args from isp host to sensor driver.*/ ++ isd->sd->host_priv = NULL; ++ ++ ++ ret = sensor_device_probe(&ispcam->sensor, ispcam); ++ if(ret < 0) { ++ /*TODO*/ ++ } ++ ++ dev_info(ispcam->dev, "%s, %d\n", __func__, __LINE__); ++ ++ return 0; ++} ++ ++static int ispcam_asd_notifier_complete(struct v4l2_async_notifier *async) ++{ ++ struct ispcam_device *ispcam = container_of(async, struct ispcam_device, ++ notifier); ++ ++ int ret = 0; ++ struct media_entity *input = NULL; /*SINK PAD*/ ++ unsigned int flags = 0; ++ unsigned int pad = 0; ++ struct isp_async_device *isd = &ispcam->isd[0]; ++ ++ dev_info(ispcam->dev, "%s, %d\n", __func__, __LINE__); ++ /*1. 绑定所有的å­component,ç¡®ä¿æ‰€æœ‰çš„å­çš„硬件设备在线, å­è®¾å¤‡ä¼šåœ¨é‡Œé¢è¿›è¡Œsubdevçš„åˆå§‹åŒ–和注册等æ“作.*/ ++ ret = component_bind_all(ispcam->dev, ispcam); ++ if(ret < 0) { ++ goto err_component_bind_all; ++ } ++ ++ /*CSI <-> VIC*/ ++ ++ /*VIC <-> ISP*/ ++ //printk("creating link vic to isp\n"); ++ ret = media_create_pad_link( ++ &ispcam->vic->sd.entity, VIC_PAD_SOURCE, ++ &ispcam->isp->sd.entity, ISP_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ ++#ifdef CONFIG_VIC_DMA_ROUTE ++ /*VIC <-> Memory*/ ++ ret = media_create_pad_link( ++ &ispcam->vic->sd.entity, VIC_PAD_SOURCE, ++ &ispcam->vic->ispvideo.video.entity, ISP_VIDEO_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++#endif ++ ++ /*ISP <-> MSCALER*/ ++ //printk("creating link isp to mscaler\n"); ++ ret = media_create_pad_link( ++ &ispcam->isp->sd.entity, ISP_PAD_SOURCE, ++ &ispcam->mscaler->sd.entity, MSCALER_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ ++ /*Sensor -> 0]CSI[1 -> 0]VIC[1 -> 0]ISP[1 -> 0]Mscaler[1 -> ]Memory*/ ++ //printk("creating link from mscaler to isp-video\n"); ++ ret = media_create_pad_link( ++ &ispcam->mscaler->sd.entity, MSCALER_PAD_SOURCE_CH0, ++ &ispcam->mscaler->ispvideo[0].video.entity, ISP_VIDEO_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ ++ if(MSCALER_MAX_CH > 1) { ++ /*CH1*/ ++ ret = media_create_pad_link( ++ &ispcam->mscaler->sd.entity, MSCALER_PAD_SOURCE_CH1, ++ &ispcam->mscaler->ispvideo[1].video.entity, ISP_VIDEO_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ } ++ /*CH2*/ ++ if(MSCALER_MAX_CH > 2) { ++ ret = media_create_pad_link( ++ &ispcam->mscaler->sd.entity, MSCALER_PAD_SOURCE_CH2, ++ &ispcam->mscaler->ispvideo[2].video.entity, ISP_VIDEO_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ } ++ if(isd->bus_type == V4L2_MBUS_CSI2_DPHY) { ++ dev_info(ispcam->dev, "creating link csi to vic\n"); ++ if(!ispcam->csi) { ++ dev_err(ispcam->dev, "*** Error: MIPI Sensor Found while CSI not enabled in dts ***\n"); ++ return -EINVAL; ++ } ++ /*1. connect csi to vic.*/ ++ ret = media_create_pad_link( ++ &ispcam->csi->sd.entity, CSI_PAD_SOURCE, ++ &ispcam->vic->sd.entity, VIC_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ /*connect to csi pad*/ ++ input = &ispcam->csi->sd.entity; ++ flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; ++ pad = CSI_PAD_SINK; ++ } else if(isd->bus_type == V4L2_MBUS_PARALLEL) { ++ dev_info(ispcam->dev, "creating link dvp to vic.\n"); ++ /*connect to vic dvp port.*/ ++ input = &ispcam->vic->sd.entity; ++ pad = VIC_PAD_SINK; ++ flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; ++ ++ } else { ++ dev_err(ispcam->dev, "Unsupported v4l2 mbus type.\n"); ++ return -EINVAL; ++ } ++ /* connect sensor to csi or vic. */ ++ ret = media_create_pad_link(&isd->sd->entity, isd->source_pad, ++ input, pad, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); ++ if(ret < 0) { ++ dev_err(ispcam->dev, "%s, %d, failed to create link from [%s] to [%s]\n", ++ __func__, __LINE__, isd->sd->entity.name, input->name); ++ return -EINVAL; ++ } ++ ++ /* Expose all subdev's nodes*/ ++ ret = v4l2_device_register_subdev_nodes(&ispcam->v4l2_dev); ++ if (ret) { ++ dev_err(ispcam->mdev.dev, ++ "vimc subdev nodes registration failed (err=%d)\n", ++ ret); ++ goto err_register_subdev_nodes; ++ } ++ ++ return 0; ++err_register_subdev_nodes: ++err_component_bind_all: ++ return ret; ++} ++ ++ ++ ++static int ispcam_comp_bind(struct device *master) ++{ ++ struct ispcam_device *ispcam = platform_get_drvdata(to_platform_device(master)); ++ int ret = 0; ++ struct v4l2_async_notifier_operations ops = { ++ .bound = ispcam_asd_notifier_bound, ++ .complete = ispcam_asd_notifier_complete, ++ }; ++ dev_info(master, "master component bind.!\n"); ++ media_device_init(&ispcam->mdev); ++ ++ /* Register the v4l2 struct */ ++ ret = v4l2_device_register(ispcam->mdev.dev, &ispcam->v4l2_dev); ++ if (ret) { ++ dev_err(ispcam->mdev.dev, ++ "v4l2 device register failed (err=%d)\n", ret); ++ return ret; ++ } ++ ++ ret = media_device_register(&ispcam->mdev); ++ if(ret < 0) { ++ dev_err(ispcam->mdev.dev, "media device register failed\n"); ++ goto err_media_device_register; ++ } ++ ++ ++ ++ ++ /*3. 注册异步设备完æˆé€šçŸ¥,ç¡®ä¿æ‰€æœ‰çš„sensor在线.在完æˆé€šçŸ¥é‡Œé¢è¿›è¡Œmedia_deviceå’Œlink的创建.*/ ++ ++ ispcam->notifier.ops = &ops; ++ ret = v4l2_async_notifier_register(&ispcam->v4l2_dev, &ispcam->notifier); ++ if(ret < 0) { ++ goto err_v4l2_async_notifier_register; ++ } ++ ++ ++ return 0; ++err_v4l2_async_notifier_register: ++err_media_device_register: ++ return ret; ++} ++ ++static void ispcam_comp_unbind(struct device *master) ++{ ++ struct ispcam_device *ispcam = platform_get_drvdata(to_platform_device(master)); ++ ++ dev_info(master, "TODO: %p master component unbind!\n", ispcam); ++ ++} ++ ++ ++static const struct component_master_ops ispcam_comp_ops = { ++ .bind = ispcam_comp_bind, ++ .unbind = ispcam_comp_unbind, ++}; ++ ++ ++static int comp_compare(struct device *comp, void *data) ++{ ++ return comp == data; ++} ++ ++static int ingenic_isp_probe(struct platform_device *pdev) ++{ ++ ++ struct ispcam_device *ispcam = NULL; ++ struct component_match *match = NULL; ++ const struct of_device_id *of_match; ++ struct ispcam_data *data = NULL; ++ int ret; ++ int i; ++ char *dev_nr = NULL; ++ ++ ispcam = kzalloc(sizeof(struct ispcam_device), GFP_KERNEL); ++ if(!ispcam) { ++ pr_err("Failed to alloc ispcam dev [%s]\n", pdev->name); ++ return -ENOMEM; ++ } ++ ++ ispcam->dev = &pdev->dev; ++ platform_set_drvdata(pdev, ispcam); ++ ++ of_match = of_match_node(ingenic_isp_dt_match, pdev->dev.of_node); ++ if (!of_match){ ++ return -ENODEV; ++ } ++ ++ data = (struct ispcam_data *)of_match->data; ++ if(data->chip_name) ++ memcpy(ispcam->chip_name, data->chip_name, sizeof(ispcam->chip_name)); ++ else ++ return -ENODEV; ++ ++ ingenic_isp_parse_dt(ispcam); ++ ++ for(i = 0; i < ispcam->subdev_num; i++) { ++ component_match_add(ispcam->dev, &match, comp_compare, &ispcam->subdevs[i]->dev); ++ } ++ ++ ++ mutex_init(&ispcam->mutex); ++ ispcam->v4l2_dev.mdev = &ispcam->mdev; ++ ++ ispcam->mdev.dev = ispcam->dev; ++ strlcpy(ispcam->mdev.model, "ingenic-isp", sizeof(ispcam->mdev.model)); ++ ++ dev_nr = strchr(pdev->name, '@'); ++ if(!dev_nr){ ++ dev_err(ispcam->dev, "failed to get dev_nr\n"); ++ return -ENODEV; ++ } ++ ispcam->dev_nr = dev_nr[1]-'0'; ++ ++ /* add self to component */ ++ ret = component_master_add_with_match(ispcam->dev, &ispcam_comp_ops, match); ++ if(ret < 0) { ++ dev_err(ispcam->dev, "failed to add component master\n"); ++ /*TODO*/ ++ } ++ ++ ret = of_reserved_mem_device_init(ispcam->dev); ++ if(ret) ++ dev_warn(ispcam->dev, "failed to init reserved mem\n"); ++ ++ return 0; ++ ++ ++ return ret; ++} ++ ++ ++ ++static int ingenic_isp_remove(struct platform_device *pdev) ++{ ++ ++ return 0; ++} ++ ++struct ispcam_data ingenic_x2000_camera_data = { ++ .chip_name = "x2000", ++}; ++ ++struct ispcam_data ingenic_m300_camera_data = { ++ .chip_name = "m300", ++}; ++ ++static const struct of_device_id ingenic_isp_dt_match[] = { ++ { .compatible = "ingenic,x2000-isp-camera", .data = (void *)&ingenic_x2000_camera_data}, ++ { .compatible = "ingenic,m300-isp-camera", .data = (void *)&ingenic_m300_camera_data}, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_isp_dt_match); ++ ++static int __maybe_unused ingenic_isp_drv_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ return 0; ++} ++ ++static int __maybe_unused ingenic_isp_drv_resume(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver ingenic_isp_driver = { ++ .probe = ingenic_isp_probe, ++ .remove = ingenic_isp_remove, ++ .suspend = ingenic_isp_drv_suspend, ++ .resume = ingenic_isp_drv_resume, ++ .driver = { ++ .name = "ingenic-ispdrv", ++ .of_match_table = ingenic_isp_dt_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_isp_driver); ++ ++MODULE_ALIAS("platform:ingenic-ispdrv"); ++MODULE_DESCRIPTION("ingenic isp subsystem"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-drv.h b/module_drivers/drivers/media/platform/ingenic-isp/isp-drv.h +new file mode 100644 +index 000000000..3b2451ba7 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-drv.h +@@ -0,0 +1,415 @@ ++#ifndef __INGENIC_ISP_DRV_H__ ++#define __INGENIC_ISP_DRV_H__ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "tiziano_core.h" ++#include "isp-sensor.h" ++ ++ ++#define MAX_SUB_DEVS 5 ++#define MAX_ASYNC_SUBDEVS 1 /*æ¯ä¸ªISPåŒæ—¶æœ€å¤§æ”¯æŒ1个sensor.*/ ++#define MSCALER_MAX_CH 3 ++ ++ ++struct isp_video_format { ++ const char *name; ++ unsigned int fourcc; ++ unsigned int depth[3]; /*max 3 plane*/ ++ unsigned int mbus_code; ++ unsigned int num_planes; ++ enum v4l2_colorspace colorspace; ++}; ++ ++struct isp_pipeline { ++ struct media_pipeline pipeline; ++}; ++ ++ ++#define to_isp_buffer(buf) container_of(buf, struct isp_video_buffer, vb2) ++struct isp_video_buffer { ++ struct vb2_v4l2_buffer vb2; ++ struct list_head list_entry; ++ unsigned int uv_offset; /* 当使用single planeçš„bufferæ—¶,表明uvçš„å移大å°.*/ ++ int uv_value_filled; ++ unsigned int uv_value_backup[MSCALER_MAX_CH]; ++}; ++ ++/*æ¯ä¸ªmscaler_video_device代表一个数æ®èŠ‚ç‚¹ç¤ºä¾‹, mscaler有三个channel,所有三个video_device.*/ ++/*通用video_device, mscaler 的三个channelå¯ä»¥æ³¨å†Œ, vic也å¯ä»¥æ³¨å†Œï¼Œæ‰€ä»¥é€šç§°ä¸ºisp_video_device.*/ ++#define ISP_VIDEO_PAD_SINK 0 ++#define ISP_VIDEO_NUM_PADS 1 ++struct isp_video_device { ++ char *name; ++ ++ struct video_device video; ++ struct device *dev; ++ ++ struct media_pad pad; ++ ++ struct ispcam_device *ispcam; ++ ++ void *alloc_ctx; ++ struct vb2_queue *queue; ++ struct mutex queue_lock; ++ ++ struct mutex mutex; ++ ++ struct mutex stream_lock; ++ struct isp_pipeline pipe; ++ ++ ++ struct v4l2_format format; ++ struct isp_video_format *(*find_format)(const u32 *pixelformat, const u32 *mbus_code, int index); ++ const struct isp_video_ops *ops; ++ ++ int bypass; /*bypass isp.*/ ++ unsigned int max_buffer_num; /*max vb2 num*/ ++}; ++ ++struct isp_video_ops { ++ /**/ ++ struct isp_video_format *(*find_format)(const u32 *pixelformat, const u32 *mbus_code, int index); ++ ++ /*qbuf*/ ++ /*called by VIDIOC_QBUF in isp-video.c*/ ++ int (*qbuf)(struct isp_video_device *ispvideo, struct isp_video_buffer *isp_buffer); ++}; ++ ++/* isp-core-tuning*/ ++struct isp_core_tuning_ctrl { ++ tisp_wb_attr_t wb_attr; ++ unsigned int luma; ++ ++ unsigned int hflip; ++ unsigned int vflip; ++ unsigned int sat; ++ unsigned int bright; ++ unsigned int contrast; ++ unsigned int sharp; ++ unsigned int exp_auto; ++ unsigned int exp_abs; ++ unsigned int auto_gain; ++ unsigned int gain; ++ unsigned int hill; ++ unsigned int flicker; ++ unsigned int module; ++ TISP_MODE_DN_E daynight; ++ unsigned int wb; ++ unsigned int auto_wb; ++ unsigned int red_wb; ++ unsigned int blue_wb; ++ ++ ++ char hflip_pending; ++ char vflip_pending; ++ char sat_pending; ++ char bright_pending; ++ char contrast_pending; ++ char sharp_pending; ++ char exp_auto_pending; ++ char exp_abs_pending; ++ char auto_gain_pending; ++ char gain_pending; ++ char hill_pending; ++ char flicker_pending; ++ char module_pending; ++ char daynight_pending; ++ char wb_pending; ++ char auto_wb_pending; ++ char red_wb_pending; ++ char blue_wb_pending; ++ char do_wb_pending; ++}; ++ ++enum isp_image_tuning_private_cmd_id { ++ IMAGE_TUNING_CID_MODULE_CONTROL = V4L2_CID_PRIVATE_BASE, ++ IMAGE_TUNING_CID_DAY_OR_NIGHT, ++ IMAGE_TUNING_CID_AE_LUMA, ++ IMAGE_TUNING_CID_HILIGHTDEPRESS, ++}; ++ ++#define CSI_PAD_SINK 0 ++#define CSI_PAD_SOURCE 1 ++#define CSI_NUM_PADS 2 ++struct csi_device { ++ struct device *dev; ++ int irq; ++ void __iomem *iobase; ++ unsigned int phy_base; ++ struct ispcam_device *ispcam; /*struct ispcam_device*/ ++ ++ struct v4l2_subdev sd; ++ ++ struct media_pad *pads; ++ ++ struct clk *gate_clk; ++ ++ int reset_index; ++ int enabled; ++ ++ int clk_precounter; ++ int data_precounter; ++}; ++ ++ ++#define VIC_PAD_SINK 0 ++#define VIC_PAD_SOURCE 1 ++#define VIC_NUM_PADS 2 ++struct vic_device { ++ struct device *dev; ++ ++ int irq; ++ void __iomem *iobase; ++ struct ispcam_device *ispcam; /*struct ispcam_device*/ ++ ++ struct v4l2_subdev sd; ++ ++ struct media_pad *pads; ++ struct isp_video_device ispvideo; /*VIC support video out*/ ++ struct v4l2_subdev_format formats[VIC_NUM_PADS]; ++ ++ unsigned int active_sink_pad; ++ ++ struct list_head dma_queued_list; ++ spinlock_t lock; ++ int enabled; ++ ++ unsigned int buffer_index; ++ int buffer_count; ++ int stop_flag; ++ int global_reset; ++ int frame_capture_counter; ++ ++ unsigned int framenum; ++ ++ unsigned int snap_paddr; ++ void* snap_vaddr; ++ struct completion snap_comp; ++ struct sensor_info *sensor_info; ++}; ++ ++#define ISP_PAD_SINK 0 ++#define ISP_PAD_SOURCE 1 ++#define ISP_NUM_PADS 2 ++struct isp_device { ++ struct device *dev; ++ int irq; ++ void __iomem *iobase; ++ struct ispcam_device *ispcam; ++ ++ void __iomem *cpm_reset; ++ unsigned int bit_sr; ++ unsigned int bit_stp; ++ unsigned int bit_ack; ++ ++ struct v4l2_subdev sd; ++ ++ struct media_pad *pads; ++ struct v4l2_subdev_format formats[ISP_NUM_PADS]; ++ ++ struct clk *div_clk; ++ struct clk *gate_clk; ++ struct clk *power_clk; ++ ++ struct task_struct *process_thread; ++ tisp_core_t core; ++ int enabled; ++ ++ /* IRQ callbacks.*/ ++ int (*irq_func_cb[32])(void*); ++ void *irq_func_data[32]; ++ ++ struct isp_core_tuning_ctrl ctrls; ++ struct sensor_info *sensor_info; ++ int core_inited; ++}; ++ ++ ++#ifdef CONFIG_MSCA_BDEV ++struct mscaler_backend_device { ++ struct device *dev; ++ struct list_head processing_list; ++ spinlock_t lock; ++ wait_queue_head_t wq; ++ ++ struct task_struct *process_thread; ++ ++ /* mscaler output fmt. */ ++ unsigned int width; ++ unsigned int height; ++ unsigned int fmt; ++ unsigned int ch; /*which channel this backend device belongs to.*/ ++ ++ int activated; /* is bdev activated??*/ ++ ++ struct ingenic_venc_ctx *ctx; ++}; ++#endif ++ ++struct yonly_ctrl_filled { ++ unsigned int uv_value; ++ unsigned int yonly_enable; ++}; ++ ++/*MSCALER最大支æŒ3个ch输出,æ¯ä¸ªch支æŒä¸åŒçš„缩放等级. 这里åªä½¿ç”¨1个channel.*/ ++#define MSCALER_MAX_CH 3 ++#define MSCALER_PAD_SINK 0 ++#define MSCALER_PAD_SOURCE_CH0 1 ++#define MSCALER_PAD_SOURCE_CH1 2 ++#define MSCALER_PAD_SOURCE_CH2 3 ++#define MSCALER_NUM_PADS 4 ++struct mscaler_device { ++ struct device *dev; ++ int irq; ++ void __iomem *iobase; ++ struct ispcam_device *ispcam; ++ ++ struct v4l2_subdev sd; ++ struct media_pad *pads; ++ ++ struct list_head dma_queued_list[MSCALER_MAX_CH]; ++ struct list_head dma_pending_list[MSCALER_MAX_CH]; ++ ++ struct isp_video_device ispvideo[MSCALER_MAX_CH]; ++ /*包å«äº†è¾“å…¥pad和输出padçš„format*/ ++ struct v4l2_subdev_format formats[MSCALER_NUM_PADS]; ++ struct v4l2_subdev_selection sel[MSCALER_MAX_CH]; ++ ++ spinlock_t lock; ++ ++ unsigned int state[MSCALER_MAX_CH]; /*0: stopped, 1: streaming*/ ++ unsigned int framenum[MSCALER_MAX_CH]; ++ ++ struct kobject *mask_kobj; ++ struct kobject *mask_ch_kobj[MSCALER_MAX_CH]; ++ struct kobject *yonly_kobj; ++ struct kobject *yonly_ch_kobj[MSCALER_MAX_CH]; ++ struct yonly_ctrl_filled yonly_cf[MSCALER_MAX_CH]; ++ ++#ifdef CONFIG_MSCA_BDEV ++ struct mscaler_backend_device bdev[MSCALER_MAX_CH]; ++#endif ++}; ++ ++ ++/* æ¯ä¸ª isp_async_device 代表一个异步注册的 sensor设备. */ ++struct isp_async_device { ++ struct v4l2_subdev *sd; ++ struct v4l2_async_subdev asd; ++ int index; ++ ++ enum v4l2_mbus_type bus_type; ++ struct v4l2_fwnode_bus_parallel parallel; ++ struct v4l2_fwnode_bus_mipi_csi2 mipi_csi2; ++ ++ int enabled; ++ ++ unsigned int source_pad; ++}; ++ ++struct sensor_device { ++ struct isp_async_device *isd; ++ ++ struct ispcam_device *ispcam; ++ struct isp_device *isp; ++ ++}; ++ ++ ++ ++ ++#define to_isp_video_ctx(fh) container_of(fh, struct isp_video_ctx, fh) ++ ++/*every open create one ctx, should only one ctx is running at a time*/ ++struct isp_video_ctx { ++ struct isp_video_device *ispvideo; ++ ++ struct v4l2_fh fh; /*handle*/ ++ struct vb2_queue queue; ++ struct v4l2_format format; ++ unsigned int uv_offset; ++ unsigned int payload_size; ++}; ++ ++#define SUBDEV_PAD_SINK 0 ++#define SUBDEV_PAD_SOURCE 1 ++#define SUBDEV_NUM_PADS 2 ++ ++ ++struct ispcam_data { ++ char chip_name[32]; ++}; ++ ++struct ispcam_device { ++ struct device *dev; ++ struct platform_device *subdevs[MAX_SUB_DEVS]; ++ unsigned int subdev_num; ++ char chip_name[32]; ++ int dev_nr; ++ ++ struct media_device mdev; ++ struct v4l2_device v4l2_dev; ++ struct v4l2_async_notifier notifier; /*å¼‚æ­¥é€šçŸ¥ï¼Œç”¨æ¥æŽ¥æ”¶sensor注册完æˆä¿¡æ¯.*/ ++ ++ /*TODO: 应该åªä¼šæ”¯æŒä¸€ä¸ªsensor, MAX_ASYNC_SUBDEVS 应该为1*/ ++ struct isp_async_device isd[MAX_ASYNC_SUBDEVS]; ++ //struct v4l2_async_subdev asd[MAX_ASYNC_SUBDEVS]; ++ unsigned int asd_num; /*实际的async device个数,从endpoint中解æžå‡ºæ¥çš„.*/ ++ struct v4l2_fwnode_endpoint vep[MAX_ASYNC_SUBDEVS]; /*æ¯ä¸ªå¼‚步设备对应到一个端点上.*/ ++ ++ int enabled; ++ ++ struct mutex mutex; ++ struct isp_device *isp; ++ struct csi_device *csi; ++ struct vic_device *vic; ++ struct mscaler_device *mscaler; ++ struct sensor_device sensor; ++ ++}; ++ ++ ++/* isp-video*/ ++extern int isp_video_init(struct isp_video_device *ispvideo, char *name, const struct isp_video_ops *ops); ++ ++extern int isp_video_cleanup(struct isp_video_device *ispvideo); ++ ++extern int isp_video_register(struct isp_video_device *ispvideo, struct v4l2_device *v4l2_dev, int nr); ++ ++extern int isp_video_unregister(struct isp_video_device *ispvideo); ++ ++static inline struct v4l2_fwnode_bus_parallel *ispcam_get_bus_parallel(struct ispcam_device *ispcam) ++{ ++ return &ispcam->isd[0].parallel; ++} ++ ++static inline struct v4l2_fwnode_bus_mipi_csi2 *ispcam_get_bus_mipi_csi2(struct ispcam_device *ispcam) ++{ ++ return &ispcam->isd[0].mipi_csi2; ++} ++ ++/* sensor */ ++int sensor_device_probe(struct sensor_device *sensor, struct ispcam_device *ispcam); ++/* tuning */ ++int isp_core_tuning_param_sync(tisp_core_t *core); ++ ++#ifdef CONFIG_MSCA_BDEV ++/* mscaler backend */ ++int ms_bdev_init(struct mscaler_backend_device *ms_bdev); ++ ++int ms_bdev_deinit(struct mscaler_backend_device *ms_bdev); ++ ++int ms_bdev_qbuf(struct mscaler_backend_device *ms_bdev, struct isp_video_buffer *isp_buffer); ++#endif ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-regs.h b/module_drivers/drivers/media/platform/ingenic-isp/isp-regs.h +new file mode 100755 +index 000000000..d86106afa +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-regs.h +@@ -0,0 +1,1450 @@ ++#ifndef TIZIANO_MAP__H ++#define TIZIANO_MAP__H ++#ifndef TIZIANO_BASE ++#define TIZIANO_BASE 0x0 ++#endif ++#ifndef TIZIANO_MAN ++#define TIZIANO_MAN 3 ++#endif ++ ++//============================================================ ++// BASE ADDRESS ++//============================================================ ++#define VIC_BASE (TIZIANO_BASE + 0x10000) ++#define TOP_BASE (TIZIANO_BASE + 0x00000) ++#define IP_BASE (TIZIANO_BASE + 0x00100) ++#define DPC_BASE (TIZIANO_BASE + 0x00200) ++#define GIB_BASE (TIZIANO_BASE + 0x00400) ++#define LSC_BASE (TIZIANO_BASE + 0x00500) ++#define AG_BASE (TIZIANO_BASE + 0x00600) ++#define AE_BASE (TIZIANO_BASE + 0x00700) ++#define AWB_BASE (TIZIANO_BASE + 0x00800) ++#define AF_BASE (TIZIANO_BASE + 0x00900) ++#define ADR_BASE (TIZIANO_BASE + 0x00A00) ++#define IRINT_BASE (TIZIANO_BASE + 0x00F00) ++#define DMSC_BASE (TIZIANO_BASE + 0x01000) ++#define CCM_BASE (TIZIANO_BASE + 0x01200) ++#define DEFOG_BASE (TIZIANO_BASE + 0x01300) ++#define CSC_BASE (TIZIANO_BASE + 0x01700) ++#define CLM_BASE (TIZIANO_BASE + 0x01800) ++#define SP_BASE (TIZIANO_BASE + 0x01900) ++#define MDNS_BASE (TIZIANO_BASE + 0x01B00) ++#define SDNS_BASE (TIZIANO_BASE + 0x02000) ++#define HLDC_BASE (TIZIANO_BASE + 0x02200) ++#define MSCA_BASE (TIZIANO_BASE + 0x02300) ++ ++#define DPC_MEM_BASE (TIZIANO_BASE + 0x04000) ++#define LSC_MEM_BASE (TIZIANO_BASE + 0x06000) ++#define GIB_MEM_BASE (TIZIANO_BASE + 0x08000) ++#define AE_HIST_MEM_BASE (TIZIANO_BASE + 0x08200) ++#define R_GAMMA_MEM_BASE (TIZIANO_BASE + 0x08A00) ++#define G_GAMMA_MEM_BASE (TIZIANO_BASE + 0x08C00) ++#define B_GAMMA_MEM_BASE (TIZIANO_BASE + 0x08E00) ++#define DEFOG_MEM_BASE (TIZIANO_BASE + 0x09000) ++#define CLM_H_0_MEM_BASE (TIZIANO_BASE + 0x0A000) ++#define CLM_H_1_MEM_BASE (TIZIANO_BASE + 0x0A800) ++#define CLM_S_0_MEM_BASE (TIZIANO_BASE + 0x0B000) ++#define CLM_S_1_MEM_BASE (TIZIANO_BASE + 0x0B800) ++ ++//============================================================ ++// VIC ++//============================================================ ++#define VIC_ADDR_CONTROL (VIC_BASE + 0x00) ++#define VIC_ADDR_RESOLUTION (VIC_BASE + 0x04) ++#define VIC_ADDR_FRAME_ECC (VIC_BASE + 0x08) ++#define VIC_ADDR_INTF_TYPE (VIC_BASE + 0x0C) ++#define VIC_ADDR_BT_CFG (VIC_BASE + 0x10) ++#define VIC_ADDR_PCLK_GATE (VIC_BASE + 0x1C) ++#define VIC_ADDR_HOR_PARA0 (VIC_BASE + 0x20) ++#define VIC_ADDR_HOR_PARA1 (VIC_BASE + 0x24) ++#define VIC_ADDR_VER_PARA0 (VIC_BASE + 0x30) ++#define VIC_ADDR_VER_PARA1 (VIC_BASE + 0x34) ++#define VIC_ADDR_VER_PARA2 (VIC_BASE + 0x38) ++#define VIC_ADDR_VER_PARA3 (VIC_BASE + 0x3C) ++#define VIC_ADDR_GLB_CFG (VIC_BASE + 0x50) ++#define VIC_ADDR_AB_VLA (VIC_BASE + 0x54) ++#define VIC_ADDR_HBLK_R (VIC_BASE + 0x58) ++#define VIC_ADDR_VBLK_R (VIC_BASE + 0x5C) ++#define VIC_ADDR_SAV_VALUE0 (VIC_BASE + 0x60) ++#define VIC_ADDR_EAV_VALUE0 (VIC_BASE + 0x64) ++#define VIC_ADDR_SAV_VALUE1 (VIC_BASE + 0x68) ++#define VIC_ADDR_EAV_VALUE1 (VIC_BASE + 0x6C) ++#define VIC_ADDR_SAV_VALUE2 (VIC_BASE + 0x70) ++#define VIC_ADDR_EAV_VALUE2 (VIC_BASE + 0x74) ++#define VIC_ADDR_WORK_STATE (VIC_BASE + 0x0090) ++#define VIC_ADDR_PIX_REG (VIC_BASE + 0x0094) ++#define VIC_ADDR_LINE_REG (VIC_BASE + 0x0098) ++#define VIC_ADDR_OFIFO_CNT (VIC_BASE + 0x009C) ++#define VIC_ADDR_BF_BAR_CTRL (VIC_BASE + 0x00A0) ++#define VIC_ADDR_BF_BAR_BLANK (VIC_BASE + 0x00A4) ++#define VIC_ADDR_AF_BAR_CTRL (VIC_BASE + 0x00B0) ++#define VIC_ADDR_AF_BAR_BLANK (VIC_BASE + 0x00B4) ++#define VIC_ADDR_WHITE_BAR (VIC_BASE + 0x00C0) ++#define VIC_ADDR_BLACK_BAR (VIC_BASE + 0x00C4) ++#define VIC_ADDR_BLUE_BAR (VIC_BASE + 0x00C8) ++#define VIC_ADDR_GREEN_BAR (VIC_BASE + 0x00CC) ++#define VIC_ADDR_RED_BAR (VIC_BASE + 0x00D0) ++#define VIC_ADDR_CYAN_BAR (VIC_BASE + 0x00D4) ++#define VIC_ADDR_YELLOW_BAR (VIC_BASE + 0x00D8) ++#define VIC_ADDR_MAGENTA_BAR (VIC_BASE + 0x00DC) ++#define VIC_ADDR_WHITE_BAR2 (VIC_BASE + 0x00E0) ++#define VIC_ADDR_BLACK_BAR2 (VIC_BASE + 0x00E4) ++#define VIC_ADDR_BLUE_BAR2 (VIC_BASE + 0x00E8) ++#define VIC_ADDR_GREEN_BAR2 (VIC_BASE + 0x00EC) ++#define VIC_ADDR_RED_BAR2 (VIC_BASE + 0x00F0) ++#define VIC_ADDR_CYAN_BAR2 (VIC_BASE + 0x00F4) ++#define VIC_ADDR_YELLOW_BAR2 (VIC_BASE + 0x00F8) ++#define VIC_ADDR_MAGENTA_BAR2 (VIC_BASE + 0x00FC) ++#define VIC_ADDR_INT_STA (VIC_BASE + 0x0100) ++#define VIC_ADDR_INT_MASK (VIC_BASE + 0x0104) ++#define VIC_ADDR_INT_CLR (VIC_BASE + 0x0108) ++#define VIC_ADDR_DMA_CONFIGURE (VIC_BASE + 0x0200) ++#define VIC_ADDR_DMA_RES_R (VIC_BASE + 0x0204) ++#define VIC_ADDR_DMA_RESET (VIC_BASE + 0x0208) ++#define VIC_ADDR_DMA_Y_CH_BANK_CONTROL (VIC_BASE + 0x0210) ++#define VIC_ADDR_DMA_Y_CH_LINE_STRIDE (VIC_BASE + 0x0214) ++#define VIC_ADDR_DMA_Y_CH_BANK0_ADDR (VIC_BASE + 0x0218) ++#define VIC_ADDR_DMA_Y_CH_BANK1_ADDR (VIC_BASE + 0x021c) ++#define VIC_ADDR_DMA_Y_CH_BANK2_ADDR (VIC_BASE + 0x0220) ++#define VIC_ADDR_DMA_Y_CH_BANK3_ADDR (VIC_BASE + 0x0224) ++#define VIC_ADDR_DMA_Y_CH_BANK4_ADDR (VIC_BASE + 0x0228) ++#define VIC_ADDR_DMA_UV_CH_BANK_CONTROL (VIC_BASE + 0x0230) ++#define VIC_ADDR_DMA_UV_CH_LINE_STRIDE (VIC_BASE + 0x0234) ++#define VIC_ADDR_DMA_UV_CH_BANK0_ADDR (VIC_BASE + 0x0238) ++#define VIC_ADDR_DMA_UV_CH_BANK1_ADDR (VIC_BASE + 0x023c) ++#define VIC_ADDR_DMA_UV_CH_BANK2_ADDR (VIC_BASE + 0x0240) ++#define VIC_ADDR_DMA_UV_CH_BANK3_ADDR (VIC_BASE + 0x0244) ++#define VIC_ADDR_DMA_UV_CH_BANK4_ADDR (VIC_BASE + 0x0248) ++#define VIC_ADDR_SYFIFO_USED (VIC_BASE + 0x0300) ++#define VIC_ADDR_FR_DONE_CNT (VIC_BASE + 0x0304) ++#define VIC_ADDR_DVP_SIZE (VIC_BASE + 0x0308) ++#define VIC_ADDR_DVP_WORK_STA (VIC_BASE + 0x030C) ++ ++ ++//============================================================ ++// TOP ++//============================================================ ++#define DPC (0 << 0) ++#define GIB (0 << 1) ++#define LSC (0 << 2) ++#define AWB (0 << 3) ++#define ADR (1 << 4) ++#define DMS (0 << 5) ++#define CCM (0 << 6) ++#define GAMMA (0 << 7) ++#define DEFOG (1 << 8) ++#define CLM (0 << 9) ++#define Y_SHARPEN (0 << 10) ++#define MDNS (0 << 11) ++#define SDNS (0 << 12) ++#define HLDC (1 << 13) ++#define TP (1 << 14) ++#define FONT (1 << 15) ++#define SEL (0 << 31) ++#define TIZIANO_BYPASS_INIT (DPC|GIB|LSC|AWB|ADR|DMS|CCM|GAMMA|DEFOG|CLM|Y_SHARPEN|MDNS|SDNS|HLDC|TP|FONT|SEL) ++ ++#define TIZIANO_FM_SIZE (TOP_BASE + 0X0004) ++#define TIZIANO_BATER_TYPE (TOP_BASE + 0X0008) ++#define TIZAINO_BYPASS_CON (TOP_BASE + 0X000C) ++#define TIZIANO_TOP_CON (TOP_BASE + 0X0010) ++#define TIZIANO_REG_CON (TOP_BASE + 0X001C) ++#define TIZAINO_INT_EN (TOP_BASE + 0X0080) ++ ++#define TOP_CTRL_ADDR_VERSION (TOP_BASE + 0x0000) ++#define TOP_CTRL_ADDR_FM_SIZE (TOP_BASE + 0x0004) ++#define TOP_CTRL_ADDR_BAYER_TYPE (TOP_BASE + 0x0008) ++#define TOP_CTRL_ADDR_BYPASS_CON (TOP_BASE + 0x000C) ++#define TOP_CTRL_ADDR_TOP_CON (TOP_BASE + 0x0010) ++#define TOP_CTRL_ADDR_TOP_STATE (TOP_BASE + 0x0014) ++#define TOP_CTRL_ADDR_LINE_SPACE (TOP_BASE + 0x0018) ++#define TOP_CTRL_ADDR_REG_CON (TOP_BASE + 0x001C) ++#define TOP_CTRL_ADDR_DMA_RC_TRIG (TOP_BASE + 0x0030) ++#define TOP_CTRL_ADDR_DMA_RC_CON (TOP_BASE + 0x0034) ++#define TOP_CTRL_ADDR_DMA_RC_ADDR (TOP_BASE + 0x0038) ++#define TOP_CTRL_ADDR_DMA_RC_STATE (TOP_BASE + 0x003C) ++#define TOP_CTRL_ADDR_DMA_RC_APB_WR_DATA (TOP_BASE + 0x0040) ++#define TOP_CTRL_ADDR_DMA_RC_APB_WR_ADDR (TOP_BASE + 0x0044) ++#define TOP_CTRL_ADDR_DMA_RD_CON (TOP_BASE + 0x0050) ++#define TOP_CTRL_ADDR_DMA_WR_CON (TOP_BASE + 0x0054) ++#define TOP_CTRL_ADDR_DMA_FR_WR_CON (TOP_BASE + 0x0058) ++#define TOP_CTRL_ADDR_DMA_STA_WR_CON (TOP_BASE + 0x005C) ++#define TOP_CTRL_ADDR_DMA_RD_DEBUG (TOP_BASE + 0x0060) ++#define TOP_CTRL_ADDR_DMA_WR_DEBUG (TOP_BASE + 0x0064) ++#define TOP_CTRL_ADDR_DMA_FR_WR_DEBUG (TOP_BASE + 0x0068) ++#define TOP_CTRL_ADDR_DMA_STA_WR_DEBUG (TOP_BASE + 0x006C) ++#define TOP_CTRL_ADDR_INT_EN (TOP_BASE + 0x0080) ++#define TOP_CTRL_ADDR_INT_REG (TOP_BASE + 0x0084) ++#define TOP_CTRL_ADDR_INT_CLR (TOP_BASE + 0x0088) ++#define TOP_CTRL_ADDR_TP_FREERUN (TOP_BASE + 0x00A0) ++#define TOP_CTRL_ADDR_TP_CON (TOP_BASE + 0x00A4) ++#define TOP_CTRL_ADDR_TP_SIZE (TOP_BASE + 0x00A8) ++#define TOP_CTRL_ADDR_TP_FONT (TOP_BASE + 0x00AC) ++#define TOP_CTRL_ADDR_TP_FLICK (TOP_BASE + 0x00B0) ++#define TOP_CTRL_ADDR_TP_CS_TYPE (TOP_BASE + 0x00B4) ++#define TOP_CTRL_ADDR_TP_CS_FCLO (TOP_BASE + 0x00B8) ++#define TOP_CTRL_ADDR_TP_CS_BCLO (TOP_BASE + 0x00BC) ++ ++//============================================================ ++// Input Interface ++//============================================================ ++#define INPUT_CTRL_ADDR_IP_TRIG (IP_BASE + 0x0000) ++#define INPUT_CTRL_ADDR_CONTROL (IP_BASE + 0x0004) ++#define INPUT_CTRL_ADDR_CHK_TRIG (IP_BASE + 0x0008) ++#define INPUT_CTRL_ADDR_CHK_TIME (IP_BASE + 0x000C) ++#define INPUT_CTRL_ADDR_CHK_CNT (IP_BASE + 0x0010) ++#define INPUT_CTRL_ADDR_CHK_FR_CNT (IP_BASE + 0x0014) ++#define INPUT_CTRL_ADDR_IP_STATE (IP_BASE + 0x0018) ++#define INPUT_CTRL_ADDR_IN_CNT (IP_BASE + 0x001C) ++#define INPUT_CTRL_ADDR_OUT_CNT (IP_BASE + 0x0020) ++ ++//============================================================ ++// DPC ++//============================================================ ++#define DPC_ADDR_SYNC (DPC_BASE + 0x0000) ++#define DPC_ADDR_S_EN (DPC_BASE + 0x0004) ++#define DPC_ADDR_S_OC_BLEND_ALPHA (DPC_BASE + 0x0008) ++#define DPC_ADDR_OC_BLEND_ALPHA (DPC_BASE + 0x000C) ++#define DPC_ADDR_SD_LV1_SLOPE (DPC_BASE + 0x0010) ++#define DPC_ADDR_SD_LV2_SLOPE (DPC_BASE + 0x0014) ++#define DPC_ADDR_LS_BLEND_ALPHA_RB (DPC_BASE + 0x0018) ++#define DPC_ADDR_LV1_DIFF_THRES_RB (DPC_BASE + 0x001C) ++#define DPC_ADDR_SD_LV2_DIFF_THRES_RB (DPC_BASE + 0x0020) ++#define DPC_ADDR_SD_LV2_P0_THRES_RB (DPC_BASE + 0x0024) ++#define DPC_ADDR_SD_LV2_P2_THRES_RB (DPC_BASE + 0x0028) ++#define DPC_ADDR_SD_LV2_P0_DIST_THRES_RB (DPC_BASE + 0x002C) ++#define DPC_ADDR_SD_LV2_P2_DIST_THRES_RB (DPC_BASE + 0x0030) ++#define DPC_ADDR_LD_LV2_THRES_RB (DPC_BASE + 0x0034) ++#define DPC_ADDR_LS_BLEND_ALPHA_G (DPC_BASE + 0x0038) ++#define DPC_ADDR_LV1_DIFF_THRES_G (DPC_BASE + 0x003C) ++#define DPC_ADDR_SD_LV2_DIFF_THRES_G (DPC_BASE + 0x0040) ++#define DPC_ADDR_SD_LV2_P0_THRES_G (DPC_BASE + 0x0044) ++#define DPC_ADDR_SD_LV2_P2_THRES_G (DPC_BASE + 0x0048) ++#define DPC_ADDR_SD_LV2_P0_DIST_THRES_G (DPC_BASE + 0x004C) ++#define DPC_ADDR_SD_LV2_P2_DIST_THRES_G (DPC_BASE + 0x0050) ++#define DPC_ADDR_LD_LV2_THRES_G (DPC_BASE + 0x0054) ++#define DPC_ADDR_CTR_FUNC_EN (DPC_BASE + 0x0058) ++#define DPC_ADDR_CTR_MD_SEG_OPT (DPC_BASE + 0x005C) ++#define DPC_ADDR_CTR_BASE_THRES (DPC_BASE + 0x0060) ++#define DPC_ADDR_RDNS_FUNC_EN (DPC_BASE + 0x0064) ++#define DPC_ADDR_RDNS_FLAT_THRES (DPC_BASE + 0x0068) ++#define DPC_ADDR_RDNS_TEXT_THRES (DPC_BASE + 0x006C) ++#define DPC_ADDR_RDNS_SIGMA_X1 (DPC_BASE + 0x0070) ++#define DPC_ADDR_RDNS_STD (DPC_BASE + 0x0074) ++#define DPC_ADDR_RDNS_RB_GAUS_SIGMA (DPC_BASE + 0x0078) ++#define DPC_ADDR_RDNS_G_SIGMA_X (DPC_BASE + 0x007C) ++#define DPC_ADDR_RDNS_G_SIGMA_S (DPC_BASE + 0x0080) ++#define DPC_ADDR_RDNS_RB_SIGMA_X (DPC_BASE + 0x0084) ++#define DPC_ADDR_RDNS_RB_SIGMA_S (DPC_BASE + 0x0088) ++#define DPC_ADDR_CTR_MD_NP_ARRAY_RG0 (DPC_BASE + 0x008C) ++#define DPC_ADDR_CTR_MD_NP_ARRAY_RG1 (DPC_BASE + 0x0090) ++#define DPC_ADDR_CTR_MD_NP_ARRAY_RG2 (DPC_BASE + 0x0094) ++#define DPC_ADDR_CTR_MD_NP_ARRAY_RG3 (DPC_BASE + 0x0098) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG0 (DPC_BASE + 0x009C) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG1 (DPC_BASE + 0x00A0) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG2 (DPC_BASE + 0x00A4) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG3 (DPC_BASE + 0x00A8) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG4 (DPC_BASE + 0x00AC) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG5 (DPC_BASE + 0x00B0) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG6 (DPC_BASE + 0x00B4) ++#define DPC_ADDR_RDNS_STD_NP_ARRAY_RG7 (DPC_BASE + 0x00B8) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG0 (DPC_BASE + 0x00BC) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG1 (DPC_BASE + 0x00C0) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG2 (DPC_BASE + 0x00C4) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG3 (DPC_BASE + 0x00C8) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG4 (DPC_BASE + 0x00CC) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG5 (DPC_BASE + 0x00D0) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG6 (DPC_BASE + 0x00D4) ++#define DPC_ADDR_RDNS_G_LUM_NP_ARRAY_RG7 (DPC_BASE + 0x00D8) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG0 (DPC_BASE + 0x00DC) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG1 (DPC_BASE + 0x00E0) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG2 (DPC_BASE + 0x00E4) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG3 (DPC_BASE + 0x00E8) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG4 (DPC_BASE + 0x00EC) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG5 (DPC_BASE + 0x00F0) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG6 (DPC_BASE + 0x00F4) ++#define DPC_ADDR_RDNS_G_STD_NP_ARRAY_RG7 (DPC_BASE + 0x00F8) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG0 (DPC_BASE + 0x00FC) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG1 (DPC_BASE + 0x0100) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG2 (DPC_BASE + 0x0104) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG3 (DPC_BASE + 0x0108) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG4 (DPC_BASE + 0x010C) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG5 (DPC_BASE + 0x0110) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG6 (DPC_BASE + 0x0114) ++#define DPC_ADDR_RDNS_RB_LUM_NP_ARRAY_RG7 (DPC_BASE + 0x0118) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG0 (DPC_BASE + 0x011C) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG1 (DPC_BASE + 0x0120) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG2 (DPC_BASE + 0x0124) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG3 (DPC_BASE + 0x0128) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG4 (DPC_BASE + 0x012C) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG5 (DPC_BASE + 0x0130) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG6 (DPC_BASE + 0x0134) ++#define DPC_ADDR_RDNS_RB_STD_NP_ARRAY_RG7 (DPC_BASE + 0x0138) ++#define DPC_ADDR_SDP_NUM (DPC_BASE + 0x013C) ++#define DPC_ADDR_SP_DEBUG_REG_0 (DPC_BASE + 0x0140) ++#define DPC_ADDR_SP_DEBUG_REG_1 (DPC_BASE + 0x0144) ++ ++//============================================================ ++// GIB ++//============================================================ ++#define GIB_ADDR_REG_CTRL (GIB_BASE + 0x0000) ++#define GIB_ADDR_CONFIG (GIB_BASE + 0x0004) ++#define GIB_ADDR_R_G (GIB_BASE + 0x0008) ++#define GIB_ADDR_B_IR (GIB_BASE + 0x000c) ++#define GIB_ADDR_DEIRM_R12 (GIB_BASE + 0x0010) ++#define GIB_ADDR_DEIRM_R34 (GIB_BASE + 0x0014) ++#define GIB_ADDR_DEIRM_C1 (GIB_BASE + 0x0018) ++#define GIB_ADDR_DEIRM_G12 (GIB_BASE + 0x001c) ++#define GIB_ADDR_DEIRM_G34 (GIB_BASE + 0x0020) ++#define GIB_ADDR_DEIRM_C2 (GIB_BASE + 0x0024) ++#define GIB_ADDR_DEIRM_B12 (GIB_BASE + 0x0028) ++#define GIB_ADDR_DEIRM_B34 (GIB_BASE + 0x002c) ++#define GIB_ADDR_DEIRM_C3 (GIB_BASE + 0x0030) ++#define GIB_ADDR_DEIRM_BLC12 (GIB_BASE + 0x0034) ++#define GIB_ADDR_DEIRM_BLC34 (GIB_BASE + 0x0038) ++#define GIB_ADDR_DEIRM_BLC5 (GIB_BASE + 0x003c) ++#define GIB_ADDR_DEBUG0 (GIB_BASE + 0x0040) ++#define GIB_DEIR_R_BASE (GIB_MEM_BASE + 0x0000) ++#define GIB_DEIR_G_BASE (GIB_MEM_BASE + 0x0080) ++#define GIB_DEIR_B_BASE (GIB_MEM_BASE + 0x0100) ++ ++//============================================================ ++// LSC ++//============================================================ ++#define LSC_ADDR_T_VERSION (LSC_BASE + 0x0000) ++#define LSC_ADDR_T_DBG_SEL (LSC_BASE + 0x0004) ++#define LSC_ADDR_T_DBG_VALUE (LSC_BASE + 0x0008) ++#define LSC_ADDR_MESH_SIZE (LSC_BASE + 0x0010) ++#define LSC_ADDR_MESH_SCALE (LSC_BASE + 0x0014) ++#define LSC_ADDR_LUT_STRIDE (LSC_BASE + 0x0018) ++ ++//============================================================ ++// AG ++//============================================================ ++#define AWB_GAIN_ADDR_REG_CTRL (AG_BASE + 0x0000) ++#define AWB_GAIN_ADDR_R_G (AG_BASE + 0x0004) ++#define AWB_GAIN_ADDR_B_IR (AG_BASE + 0x0008) ++#define AWB_GAIN_ADDR_DEBUG0 (AG_BASE + 0x000c) ++ ++//============================================================ ++// AE ++//============================================================ ++#define AE_STAT_ADDR_REG_CTRL (AE_BASE + 0x0000) ++#define AE_STAT_ADDR_ZONE_NUM_START (AE_BASE + 0x0004) ++#define AE_STAT_ADDR_HOR_ZONE_SIZE_14 (AE_BASE + 0x0008) ++#define AE_STAT_ADDR_HOR_ZONE_SIZE_58 (AE_BASE + 0x000c) ++#define AE_STAT_ADDR_HOR_ZONE_SIZE_912 (AE_BASE + 0x0010) ++#define AE_STAT_ADDR_HOR_ZONE_SIZE_1315 (AE_BASE + 0x0014) ++#define AE_STAT_ADDR_VER_ZONE_SIZE_14 (AE_BASE + 0x0018) ++#define AE_STAT_ADDR_VER_ZONE_SIZE_58 (AE_BASE + 0x001c) ++#define AE_STAT_ADDR_VER_ZONE_SIZE_912 (AE_BASE + 0x0020) ++#define AE_STAT_ADDR_VER_ZONE_SIZE_1315 (AE_BASE + 0x0024) ++#define AE_STAT_ADDR_LUM_TH_FREQ (AE_BASE + 0x0028) ++#define AE_STAT_ADDR_AE_DMA_BASE_1 (AE_BASE + 0x002c) ++#define AE_STAT_ADDR_AE_DMA_BASE_2 (AE_BASE + 0x0030) ++#define AE_STAT_ADDR_AE_DMA_BASE_3 (AE_BASE + 0x0034) ++#define AE_STAT_ADDR_AE_DMA_BASE_4 (AE_BASE + 0x0038) ++#define AE_STAT_ADDR_HIST_DMA_BASE_1 (AE_BASE + 0x003c) ++#define AE_STAT_ADDR_HIST_DMA_BASE_2 (AE_BASE + 0x0040) ++#define AE_STAT_ADDR_HIST_DMA_BASE_3 (AE_BASE + 0x0044) ++#define AE_STAT_ADDR_HIST_DMA_BASE_4 (AE_BASE + 0x0048) ++#define AE_STAT_ADDR_DMA_BASE_NUM (AE_BASE + 0x004c) ++#define AE_STAT_ADDR_DMA_INFO (AE_BASE + 0x0050) ++#define AE_STAT_ADDR_DEBUG0 (AE_BASE + 0x0054) ++#define AE_STAT_ADDR_DEBUG1 (AE_BASE + 0x0058) ++ ++//============================================================ ++// AWB ++//============================================================ ++#define AWB_STAT_ADDR_REG_CTRL (AWB_BASE + 0x0000) ++#define AWB_STAT_ADDR_ZONE_NUM_START (AWB_BASE + 0x0004) ++#define AWB_STAT_ADDR_HOR_ZONE_SIZE_14 (AWB_BASE + 0x0008) ++#define AWB_STAT_ADDR_HOR_ZONE_SIZE_58 (AWB_BASE + 0x000c) ++#define AWB_STAT_ADDR_HOR_ZONE_SIZE_912 (AWB_BASE + 0x0010) ++#define AWB_STAT_ADDR_HOR_ZONE_SIZE_1315 (AWB_BASE + 0x0014) ++#define AWB_STAT_ADDR_VER_ZONE_SIZE_14 (AWB_BASE + 0x0018) ++#define AWB_STAT_ADDR_VER_ZONE_SIZE_58 (AWB_BASE + 0x001c) ++#define AWB_STAT_ADDR_VER_ZONE_SIZE_912 (AWB_BASE + 0x0020) ++#define AWB_STAT_ADDR_VER_ZONE_SIZE_1315 (AWB_BASE + 0x0024) ++#define AWB_STAT_ADDR_RG_TH (AWB_BASE + 0x0028) ++#define AWB_STAT_ADDR_BG_TH (AWB_BASE + 0x002c) ++#define AWB_STAT_ADDR_K1_A1 (AWB_BASE + 0x0030) ++#define AWB_STAT_ADDR_K2_A2 (AWB_BASE + 0x0034) ++#define AWB_STAT_ADDR_LUM_TH_FREQ (AWB_BASE + 0x0038) ++#define AWB_STAT_ADDR_AWB_DMA_BASE_1 (AWB_BASE + 0x003c) ++#define AWB_STAT_ADDR_AWB_DMA_BASE_2 (AWB_BASE + 0x0040) ++#define AWB_STAT_ADDR_AWB_DMA_BASE_3 (AWB_BASE + 0x0044) ++#define AWB_STAT_ADDR_AWB_DMA_BASE_4 (AWB_BASE + 0x0048) ++#define AWB_STAT_ADDR_DMA_BASE_NUM (AWB_BASE + 0x004c) ++#define AWB_STAT_ADDR_DMA_INFO (AWB_BASE + 0x0050) ++#define AWB_STAT_ADDR_DEBUG0 (AWB_BASE + 0x0054) ++#define AWB_STAT_ADDR_DEBUG1 (AWB_BASE + 0x0058) ++ ++//============================================================ ++// AF ++//============================================================ ++#define AF_STAT_ADDR_REG_CTRL (AF_BASE + 0x0000) ++#define AF_STAT_ADDR_ZONE_NUM_START (AF_BASE + 0x0004) ++#define AF_STAT_ADDR_HOR_ZONE_SIZE_14 (AF_BASE + 0x0008) ++#define AF_STAT_ADDR_HOR_ZONE_SIZE_58 (AF_BASE + 0x000c) ++#define AF_STAT_ADDR_HOR_ZONE_SIZE_912 (AF_BASE + 0x0010) ++#define AF_STAT_ADDR_HOR_ZONE_SIZE_1315 (AF_BASE + 0x0014) ++#define AF_STAT_ADDR_VER_ZONE_SIZE_14 (AF_BASE + 0x0018) ++#define AF_STAT_ADDR_VER_ZONE_SIZE_58 (AF_BASE + 0x001c) ++#define AF_STAT_ADDR_VER_ZONE_SIZE_912 (AF_BASE + 0x0020) ++#define AF_STAT_ADDR_VER_ZONE_SIZE_1315 (AF_BASE + 0x0024) ++#define AF_STAT_ADDR_FREQ_IIR_EN_LUM_TH (AF_BASE + 0x0028) ++#define AF_STAT_ADDR_LDG_COR_EN (AF_BASE + 0x002c) ++#define AF_STAT_ADDR_FIR0_G1_G2 (AF_BASE + 0x0030) ++#define AF_STAT_ADDR_FIR0_G3_G4 (AF_BASE + 0x0034) ++#define AF_STAT_ADDR_FIR0_G5 (AF_BASE + 0x0038) ++#define AF_STAT_ADDR_FIR1_G1_G2 (AF_BASE + 0x003c) ++#define AF_STAT_ADDR_FIR1_G3_G4 (AF_BASE + 0x0040) ++#define AF_STAT_ADDR_FIR1_G5 (AF_BASE + 0x0044) ++#define AF_STAT_ADDR_IIR0_G1_G3 (AF_BASE + 0x0048) ++#define AF_STAT_ADDR_IIR0_G4_G5 (AF_BASE + 0x004c) ++#define AF_STAT_ADDR_IIR0_G6_G8 (AF_BASE + 0x0050) ++#define AF_STAT_ADDR_IIR0_G9_G10 (AF_BASE + 0x0054) ++#define AF_STAT_ADDR_IIR1_G1_G3 (AF_BASE + 0x0058) ++#define AF_STAT_ADDR_IIR1_G4_G5 (AF_BASE + 0x005c) ++#define AF_STAT_ADDR_IIR1_G6_G8 (AF_BASE + 0x0060) ++#define AF_STAT_ADDR_IIR1_G9_G10 (AF_BASE + 0x0064) ++#define AF_STAT_ADDR_LDG_FIR0_LOW (AF_BASE + 0x0068) ++#define AF_STAT_ADDR_LDG_FIR0_HIGH (AF_BASE + 0x006c) ++#define AF_STAT_ADDR_LDG_FIR1_LOW (AF_BASE + 0x0070) ++#define AF_STAT_ADDR_LDG_FIR1_HIGH (AF_BASE + 0x0074) ++#define AF_STAT_ADDR_LDG_IIR0_LOW (AF_BASE + 0x0078) ++#define AF_STAT_ADDR_LDG_IIR0_HIGH (AF_BASE + 0x007c) ++#define AF_STAT_ADDR_LDG_IIR1_LOW (AF_BASE + 0x0080) ++#define AF_STAT_ADDR_LDG_IIR1_HIGH (AF_BASE + 0x0084) ++#define AF_STAT_ADDR_COR_F0_TH_LH (AF_BASE + 0x0088) ++#define AF_STAT_ADDR_COR_F0_SLP_LIM (AF_BASE + 0x008c) ++#define AF_STAT_ADDR_COR_F1_TH_LH (AF_BASE + 0x0090) ++#define AF_STAT_ADDR_COR_F1_SLP_LIM (AF_BASE + 0x0094) ++#define AF_STAT_ADDR_COR_I0_TH_LH (AF_BASE + 0x0098) ++#define AF_STAT_ADDR_COR_I0_SLP_LIM (AF_BASE + 0x009c) ++#define AF_STAT_ADDR_COR_I1_TH_LH (AF_BASE + 0x00a0) ++#define AF_STAT_ADDR_COR_I1_SLP_LIM (AF_BASE + 0x00a4) ++#define AF_STAT_ADDR_AF_DMA_BASE_1 (AF_BASE + 0x00a8) ++#define AF_STAT_ADDR_AF_DMA_BASE_2 (AF_BASE + 0x00ac) ++#define AF_STAT_ADDR_AF_DMA_BASE_3 (AF_BASE + 0x00b0) ++#define AF_STAT_ADDR_AF_DMA_BASE_4 (AF_BASE + 0x00b4) ++#define AF_STAT_ADDR_DMA_BASE_NUM (AF_BASE + 0x00b8) ++#define AF_STAT_ADDR_DMA_INFO (AF_BASE + 0x00bc) ++#define AF_STAT_ADDR_DEBUG0 (AF_BASE + 0x00c0) ++ ++//============================================================ ++// ADR ++//============================================================ ++#define ADR_ADDR_T_VERSION (ADR_BASE + 0x0000) ++#define ADR_ADDR_T_DBG_SEL (ADR_BASE + 0x0004) ++#define ADR_ADDR_T_DEG_VALUE (ADR_BASE + 0x0008) ++#define ADR_ADDR_STEP_PAR (ADR_BASE + 0x000C) ++#define ADR_ADDR_BLK_COORD_M_P_0 (ADR_BASE + 0x0010) ++#define ADR_ADDR_BLK_COORD_M_P_1 (ADR_BASE + 0x0014) ++#define ADR_ADDR_BLK_COORD_M_P_2 (ADR_BASE + 0x0018) ++#define ADR_ADDR_BLK_COORD_N_P_0 (ADR_BASE + 0x001C) ++#define ADR_ADDR_BLK_COORD_N_P_1 (ADR_BASE + 0x0020) ++#define ADR_ADDR_BLK_COORD_N_P_2 (ADR_BASE + 0x0024) ++#define ADR_ADDR_CEN_DIS_P_0 (ADR_BASE + 0x0028) ++#define ADR_ADDR_CEN_DIS_P_1 (ADR_BASE + 0x002C) ++#define ADR_ADDR_CEN_DIS_P_2 (ADR_BASE + 0x0030) ++#define ADR_ADDR_CEN_DIS_P_3 (ADR_BASE + 0x0034) ++#define ADR_ADDR_CEN_DIS_P_4 (ADR_BASE + 0x0038) ++#define ADR_ADDR_CEN_DIS_P_5 (ADR_BASE + 0x003C) ++#define ADR_ADDR_CEN_DIS_P_6 (ADR_BASE + 0x0040) ++#define ADR_ADDR_CEN_DIS_P_7 (ADR_BASE + 0x0044) ++#define ADR_ADDR_CEN_DIS_P_8 (ADR_BASE + 0x0048) ++#define ADR_ADDR_CEN_DIS_P_9 (ADR_BASE + 0x004C) ++#define ADR_ADDR_CEN_DIS_P_A (ADR_BASE + 0x0050) ++#define ADR_ADDR_CEN_DIS_P_B (ADR_BASE + 0x0054) ++#define ADR_ADDR_CEN_DIS_P_C (ADR_BASE + 0x0058) ++#define ADR_ADDR_CEN_DIS_P_D (ADR_BASE + 0x005C) ++#define ADR_ADDR_CEN_DIS_P_E (ADR_BASE + 0x0060) ++#define ADR_ADDR_CEN_DIS_P_F (ADR_BASE + 0x0064) ++#define ADR_ADDR_MAP_KPOINT_X_P0 (ADR_BASE + 0x0068) ++#define ADR_ADDR_MAP_KPOINT_X_P1 (ADR_BASE + 0x006C) ++#define ADR_ADDR_MAP_KPOINT_X_P2 (ADR_BASE + 0x0070) ++#define ADR_ADDR_MAP_KPOINT_X_P3 (ADR_BASE + 0x0074) ++#define ADR_ADDR_MAP_KPOINT_X_P4 (ADR_BASE + 0x0078) ++#define ADR_ADDR_MAP_KPOINT_X_P5 (ADR_BASE + 0x007C) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_0 (ADR_BASE + 0x0080) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_1 (ADR_BASE + 0x0084) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_2 (ADR_BASE + 0x0088) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_3 (ADR_BASE + 0x008C) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_4 (ADR_BASE + 0x0090) ++#define ADR_ADDR_MAP_KPOINT_Y_P00_5 (ADR_BASE + 0x0094) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_0 (ADR_BASE + 0x0098) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_1 (ADR_BASE + 0x009C) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_2 (ADR_BASE + 0x00A0) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_3 (ADR_BASE + 0x00A4) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_4 (ADR_BASE + 0x00A8) ++#define ADR_ADDR_MAP_KPOINT_Y_P01_5 (ADR_BASE + 0x00AC) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_0 (ADR_BASE + 0x00B0) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_1 (ADR_BASE + 0x00B4) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_2 (ADR_BASE + 0x00B8) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_3 (ADR_BASE + 0x00BC) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_4 (ADR_BASE + 0x00C0) ++#define ADR_ADDR_MAP_KPOINT_Y_P02_5 (ADR_BASE + 0x00C4) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_0 (ADR_BASE + 0x00C8) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_1 (ADR_BASE + 0x00CC) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_2 (ADR_BASE + 0x00D0) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_3 (ADR_BASE + 0x00D4) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_4 (ADR_BASE + 0x00D8) ++#define ADR_ADDR_MAP_KPOINT_Y_P03_5 (ADR_BASE + 0x00DC) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_0 (ADR_BASE + 0x00E0) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_1 (ADR_BASE + 0x00E4) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_2 (ADR_BASE + 0x00E8) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_3 (ADR_BASE + 0x00EC) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_4 (ADR_BASE + 0x00F0) ++#define ADR_ADDR_MAP_KPOINT_Y_P04_5 (ADR_BASE + 0x00F4) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_0 (ADR_BASE + 0x00F8) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_1 (ADR_BASE + 0x00FC) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_2 (ADR_BASE + 0x0100) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_3 (ADR_BASE + 0x0104) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_4 (ADR_BASE + 0x0108) ++#define ADR_ADDR_MAP_KPOINT_Y_P05_5 (ADR_BASE + 0x010C) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_0 (ADR_BASE + 0x0110) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_1 (ADR_BASE + 0x0114) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_2 (ADR_BASE + 0x0118) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_3 (ADR_BASE + 0x011C) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_4 (ADR_BASE + 0x0120) ++#define ADR_ADDR_MAP_KPOINT_Y_P06_5 (ADR_BASE + 0x0124) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_0 (ADR_BASE + 0x0128) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_1 (ADR_BASE + 0x012C) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_2 (ADR_BASE + 0x0130) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_3 (ADR_BASE + 0x0134) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_4 (ADR_BASE + 0x0138) ++#define ADR_ADDR_MAP_KPOINT_Y_P07_5 (ADR_BASE + 0x013C) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_0 (ADR_BASE + 0x0140) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_1 (ADR_BASE + 0x0144) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_2 (ADR_BASE + 0x0148) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_3 (ADR_BASE + 0x014C) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_4 (ADR_BASE + 0x0150) ++#define ADR_ADDR_MAP_KPOINT_Y_P08_5 (ADR_BASE + 0x0154) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_0 (ADR_BASE + 0x0158) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_1 (ADR_BASE + 0x015C) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_2 (ADR_BASE + 0x0160) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_3 (ADR_BASE + 0x0164) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_4 (ADR_BASE + 0x0168) ++#define ADR_ADDR_MAP_KPOINT_Y_P09_5 (ADR_BASE + 0x016C) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_0 (ADR_BASE + 0x0170) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_1 (ADR_BASE + 0x0174) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_2 (ADR_BASE + 0x0178) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_3 (ADR_BASE + 0x017C) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_4 (ADR_BASE + 0x0180) ++#define ADR_ADDR_MAP_KPOINT_Y_P10_5 (ADR_BASE + 0x0184) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_0 (ADR_BASE + 0x0188) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_1 (ADR_BASE + 0x018C) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_2 (ADR_BASE + 0x0190) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_3 (ADR_BASE + 0x0194) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_4 (ADR_BASE + 0x0198) ++#define ADR_ADDR_MAP_KPOINT_Y_P11_5 (ADR_BASE + 0x019C) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_0 (ADR_BASE + 0x01A0) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_1 (ADR_BASE + 0x01A4) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_2 (ADR_BASE + 0x01A8) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_3 (ADR_BASE + 0x01AC) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_4 (ADR_BASE + 0x01B0) ++#define ADR_ADDR_MAP_KPOINT_Y_P12_5 (ADR_BASE + 0x01B4) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_0 (ADR_BASE + 0x01B8) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_1 (ADR_BASE + 0x01BC) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_2 (ADR_BASE + 0x01C0) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_3 (ADR_BASE + 0x01C4) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_4 (ADR_BASE + 0x01C8) ++#define ADR_ADDR_MAP_KPOINT_Y_P13_5 (ADR_BASE + 0x01CC) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_0 (ADR_BASE + 0x01D0) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_1 (ADR_BASE + 0x01D4) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_2 (ADR_BASE + 0x01D8) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_3 (ADR_BASE + 0x01DC) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_4 (ADR_BASE + 0x01E0) ++#define ADR_ADDR_MAP_KPOINT_Y_P14_5 (ADR_BASE + 0x01E4) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_0 (ADR_BASE + 0x01E8) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_1 (ADR_BASE + 0x01EC) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_2 (ADR_BASE + 0x01F0) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_3 (ADR_BASE + 0x01F4) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_4 (ADR_BASE + 0x01F8) ++#define ADR_ADDR_MAP_KPOINT_Y_P15_5 (ADR_BASE + 0x01FC) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_0 (ADR_BASE + 0x0200) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_1 (ADR_BASE + 0x0204) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_2 (ADR_BASE + 0x0208) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_3 (ADR_BASE + 0x020C) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_4 (ADR_BASE + 0x0210) ++#define ADR_ADDR_MAP_KPOINT_Y_P16_5 (ADR_BASE + 0x0214) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_0 (ADR_BASE + 0x0218) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_1 (ADR_BASE + 0x021C) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_2 (ADR_BASE + 0x0220) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_3 (ADR_BASE + 0x0224) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_4 (ADR_BASE + 0x0228) ++#define ADR_ADDR_MAP_KPOINT_Y_P17_5 (ADR_BASE + 0x022C) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_0 (ADR_BASE + 0x0230) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_1 (ADR_BASE + 0x0234) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_2 (ADR_BASE + 0x0238) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_3 (ADR_BASE + 0x023C) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_4 (ADR_BASE + 0x0240) ++#define ADR_ADDR_MAP_KPOINT_Y_P18_5 (ADR_BASE + 0x0244) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_0 (ADR_BASE + 0x0248) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_1 (ADR_BASE + 0x024C) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_2 (ADR_BASE + 0x0250) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_3 (ADR_BASE + 0x0254) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_4 (ADR_BASE + 0x0258) ++#define ADR_ADDR_MAP_KPOINT_Y_P19_5 (ADR_BASE + 0x025C) ++#define ADR_ADDR_WEILUT20_P0 (ADR_BASE + 0x0260) ++#define ADR_ADDR_WEILUT20_P1 (ADR_BASE + 0x0264) ++#define ADR_ADDR_WEILUT20_P2 (ADR_BASE + 0x0268) ++#define ADR_ADDR_WEILUT20_P3 (ADR_BASE + 0x026C) ++#define ADR_ADDR_WEILUT20_P4 (ADR_BASE + 0x0270) ++#define ADR_ADDR_WEILUT20_P5 (ADR_BASE + 0x0274) ++#define ADR_ADDR_WEILUT20_P6 (ADR_BASE + 0x0278) ++#define ADR_ADDR_WEILUT20_P7 (ADR_BASE + 0x027C) ++#define ADR_ADDR_WEILUT02_P0 (ADR_BASE + 0x0280) ++#define ADR_ADDR_WEILUT02_P1 (ADR_BASE + 0x0284) ++#define ADR_ADDR_WEILUT02_P2 (ADR_BASE + 0x0288) ++#define ADR_ADDR_WEILUT02_P3 (ADR_BASE + 0x028C) ++#define ADR_ADDR_WEILUT02_P4 (ADR_BASE + 0x0290) ++#define ADR_ADDR_WEILUT02_P5 (ADR_BASE + 0x0294) ++#define ADR_ADDR_WEILUT02_P6 (ADR_BASE + 0x0298) ++#define ADR_ADDR_WEILUT02_P7 (ADR_BASE + 0x029C) ++#define ADR_ADDR_WEILUT12_P0 (ADR_BASE + 0x02A0) ++#define ADR_ADDR_WEILUT12_P1 (ADR_BASE + 0x02A4) ++#define ADR_ADDR_WEILUT12_P2 (ADR_BASE + 0x02A8) ++#define ADR_ADDR_WEILUT12_P3 (ADR_BASE + 0x02AC) ++#define ADR_ADDR_WEILUT12_P4 (ADR_BASE + 0x02B0) ++#define ADR_ADDR_WEILUT12_P5 (ADR_BASE + 0x02B4) ++#define ADR_ADDR_WEILUT12_P6 (ADR_BASE + 0x02B8) ++#define ADR_ADDR_WEILUT12_P7 (ADR_BASE + 0x02BC) ++#define ADR_ADDR_WEILUT22_P0 (ADR_BASE + 0x02C0) ++#define ADR_ADDR_WEILUT22_P1 (ADR_BASE + 0x02C4) ++#define ADR_ADDR_WEILUT22_P2 (ADR_BASE + 0x02C8) ++#define ADR_ADDR_WEILUT22_P3 (ADR_BASE + 0x02CC) ++#define ADR_ADDR_WEILUT22_P4 (ADR_BASE + 0x02D0) ++#define ADR_ADDR_WEILUT22_P5 (ADR_BASE + 0x02D4) ++#define ADR_ADDR_WEILUT22_P6 (ADR_BASE + 0x02D8) ++#define ADR_ADDR_WEILUT22_P7 (ADR_BASE + 0x02DC) ++#define ADR_ADDR_WEILUT21_P0 (ADR_BASE + 0x02E0) ++#define ADR_ADDR_WEILUT21_P1 (ADR_BASE + 0x02E4) ++#define ADR_ADDR_WEILUT21_P2 (ADR_BASE + 0x02E8) ++#define ADR_ADDR_WEILUT21_P3 (ADR_BASE + 0x02EC) ++#define ADR_ADDR_WEILUT21_P4 (ADR_BASE + 0x02F0) ++#define ADR_ADDR_WEILUT21_P5 (ADR_BASE + 0x02F4) ++#define ADR_ADDR_WEILUT21_P6 (ADR_BASE + 0x02F8) ++#define ADR_ADDR_WEILUT21_P7 (ADR_BASE + 0x02FC) ++#define ADR_ADDR_MAP_KPOINT_POW_P0 (ADR_BASE + 0x0300) ++#define ADR_ADDR_MAP_KPOINT_POW_P1 (ADR_BASE + 0x0304) ++#define ADR_ADDR_MAP_KPOINT_POW_P2 (ADR_BASE + 0x0308) ++#define ADR_ADDR_CTC_KPOINT_X_P0 (ADR_BASE + 0x0310) ++#define ADR_ADDR_CTC_KPOINT_X_P1 (ADR_BASE + 0x0314) ++#define ADR_ADDR_CON_W_DIS_P00 (ADR_BASE + 0x0320) ++#define ADR_ADDR_CON_W_DIS_P01 (ADR_BASE + 0x0324) ++#define ADR_ADDR_CON_W_DIS_P02 (ADR_BASE + 0x0328) ++#define ADR_ADDR_CON_W_DIS_P03 (ADR_BASE + 0x032C) ++#define ADR_ADDR_CON_W_DIS_P04 (ADR_BASE + 0x0330) ++#define ADR_ADDR_CON_W_DIS_P05 (ADR_BASE + 0x0334) ++#define ADR_ADDR_CON_W_DIS_P06 (ADR_BASE + 0x0338) ++#define ADR_ADDR_CON_W_DIS_P07 (ADR_BASE + 0x033C) ++#define ADR_ADDR_CON_W_DIS_P08 (ADR_BASE + 0x0340) ++#define ADR_ADDR_CON_W_DIS_P09 (ADR_BASE + 0x0344) ++#define ADR_ADDR_CON_W_DIS_P10 (ADR_BASE + 0x0348) ++#define ADR_ADDR_CON_W_DIS_P11 (ADR_BASE + 0x034C) ++#define ADR_ADDR_CON_W_DIS_P12 (ADR_BASE + 0x0350) ++#define ADR_ADDR_CON_W_DIS_P13 (ADR_BASE + 0x0354) ++#define ADR_ADDR_CON_W_DIS_P14 (ADR_BASE + 0x0358) ++#define ADR_ADDR_CON_W_DIS_P15 (ADR_BASE + 0x035C) ++#define ADR_ADDR_CON_W_DIS_P16 (ADR_BASE + 0x0360) ++#define ADR_ADDR_CON_W_DIS_P17 (ADR_BASE + 0x0364) ++#define ADR_ADDR_CON_W_DIS_P18 (ADR_BASE + 0x0368) ++#define ADR_ADDR_CON_W_DIS_P19 (ADR_BASE + 0x036C) ++#define ADR_ADDR_CON_W_DIS_P20 (ADR_BASE + 0x0370) ++#define ADR_ADDR_CON_W_DIS_P21 (ADR_BASE + 0x0374) ++#define ADR_ADDR_CON_W_DIS_P22 (ADR_BASE + 0x0378) ++#define ADR_ADDR_CON_W_DIS_P23 (ADR_BASE + 0x037C) ++#define ADR_ADDR_CON_W_DIS_P24 (ADR_BASE + 0x0380) ++#define ADR_ADDR_CON_W_DIS_P25 (ADR_BASE + 0x0384) ++#define ADR_ADDR_CON_W_DIS_P26 (ADR_BASE + 0x0388) ++#define ADR_ADDR_CON_W_DIS_P27 (ADR_BASE + 0x038C) ++#define ADR_ADDR_CON_W_DIS_P28 (ADR_BASE + 0x0390) ++#define ADR_ADDR_CON_W_DIS_P29 (ADR_BASE + 0x0394) ++#define ADR_ADDR_CON_W_DIS_P30 (ADR_BASE + 0x0398) ++#define ADR_ADDR_CON_W_DIS_P31 (ADR_BASE + 0x039C) ++#define ADR_ADDR_CTC_KPOINT_MUX_P0 (ADR_BASE + 0x03A0) ++#define ADR_ADDR_CTC_KPOINT_MUX_P1 (ADR_BASE + 0x03A4) ++#define ADR_ADDR_CTC_RATIO (ADR_BASE + 0x03A8) ++#define ADR_ADDR_MIN_KPOINT_X_P0 (ADR_BASE + 0x03B0) ++#define ADR_ADDR_MIN_KPOINT_X_P1 (ADR_BASE + 0x03B4) ++#define ADR_ADDR_MIN_KPOINT_X_P2 (ADR_BASE + 0x03B8) ++#define ADR_ADDR_MIN_KPOINT_X_P3 (ADR_BASE + 0x03BC) ++#define ADR_ADDR_MIN_KPOINT_X_P4 (ADR_BASE + 0x03C0) ++#define ADR_ADDR_MIN_KPOINT_X_P5 (ADR_BASE + 0x03C4) ++#define ADR_ADDR_MIN_KPOINT_Y_P0 (ADR_BASE + 0x03C8) ++#define ADR_ADDR_MIN_KPOINT_Y_P1 (ADR_BASE + 0x03CC) ++#define ADR_ADDR_MIN_KPOINT_Y_P2 (ADR_BASE + 0x03D0) ++#define ADR_ADDR_MIN_KPOINT_Y_P3 (ADR_BASE + 0x03D4) ++#define ADR_ADDR_MIN_KPOINT_Y_P4 (ADR_BASE + 0x03D8) ++#define ADR_ADDR_MIN_KPOINT_Y_P5 (ADR_BASE + 0x03DC) ++#define ADR_ADDR_MIN_KPOINT_POW_P0 (ADR_BASE + 0x03E0) ++#define ADR_ADDR_MIN_KPOINT_POW_P1 (ADR_BASE + 0x03E4) ++#define ADR_ADDR_MIN_KPOINT_POW_P2 (ADR_BASE + 0x03E8) ++#define ADR_ADDR_COC_KPOINT_X_P0 (ADR_BASE + 0x03F0) ++#define ADR_ADDR_COC_KPOINT_X_P1 (ADR_BASE + 0x03F4) ++#define ADR_ADDR_COC_KPOINT_X_P2 (ADR_BASE + 0x03F8) ++#define ADR_ADDR_COC_KPOINT_X_P3 (ADR_BASE + 0x03FC) ++#define ADR_ADDR_COC_KPOINT_X_P4 (ADR_BASE + 0x0400) ++#define ADR_ADDR_COC_KPOINT_X_P5 (ADR_BASE + 0x0404) ++#define ADR_ADDR_COC_THRES (ADR_BASE + 0x0408) ++#define ADR_ADDR_COC_STREN (ADR_BASE + 0x040C) ++#define ADR_ADDR_COC_MODE (ADR_BASE + 0x0410) ++#define ADR_ADDR_COC_KPOINT_POW_P0 (ADR_BASE + 0x0414) ++#define ADR_ADDR_COC_KPOINT_POW_P1 (ADR_BASE + 0x0418) ++#define ADR_ADDR_COC_KPOINT_POW_P2 (ADR_BASE + 0x041C) ++#define ADR_ADDR_STAT_BLOCK_DIFF_P_0 (ADR_BASE + 0x0420) ++#define ADR_ADDR_STAT_BLOCK_DIFF_P_1 (ADR_BASE + 0x0424) ++#define ADR_ADDR_BANK_ADDR_P0 (ADR_BASE + 0x0428) ++#define ADR_ADDR_BANK_ADDR_P1 (ADR_BASE + 0x042C) ++#define ADR_ADDR_BANK_ADDR_P2 (ADR_BASE + 0x0430) ++#define ADR_ADDR_BANK_ADDR_P3 (ADR_BASE + 0x0434) ++#define ADR_ADDR_BANK_NUMBER (ADR_BASE + 0x0438) ++#define ADR_ADDR_FRAME_ADDR (ADR_BASE + 0x043C) ++#define ADR_ADDR_FRAME_ID (ADR_BASE + 0x0440) ++#define ADR_ADDR_FRAME_RATE (ADR_BASE + 0x0444) ++#define ADR_ADDR_SHADOW_CTRL (ADR_BASE + 0x0448) ++#define ADR_ADDR_DEBUG_SIGNAL_0 (ADR_BASE + 0x0450) ++#define ADR_ADDR_DEBUG_SIGNAL_1 (ADR_BASE + 0x0454) ++#define ADR_ADDR_DEBUG_SIGNAL_2 (ADR_BASE + 0x0458) ++#define ADR_ADDR_DEBUG_SIGNAL_3 (ADR_BASE + 0x045C) ++#define ADR_ADDR_DEBUG_SIGNAL_4 (ADR_BASE + 0x0460) ++#define ADR_ADDR_DEBUG_SIGNAL_5 (ADR_BASE + 0x0464) ++ ++//============================================================ ++// IRINT ++//============================================================ ++#define IRINT_ADDR_T_VERSION (IRINT_BASE + 0x0000) ++#define IRINT_ADDR_T_DBG_SEL (IRINT_BASE + 0x0004) ++#define IRINT_ADDR_T_DBG_VALUE (IRINT_BASE + 0x0008) ++#define IRINT_ADDR_DIFF_PAR (IRINT_BASE + 0x0010) ++#define IRINT_ADDR_MIN_PAR (IRINT_BASE + 0x0014) ++ ++//============================================================ ++// DMSC ++//============================================================ ++#define DMSC_ADDR_SYNC (DMSC_BASE + 0x0000) ++#define DMSC_ADDR_G_STD_STREN (DMSC_BASE + 0x0004) ++#define DMSC_ADDR_UU_THRES (DMSC_BASE + 0x0008) ++#define DMSC_ADDR_ALIAS_DIR_DIFF (DMSC_BASE + 0x000C) ++#define DMSC_ADDR_WIN5_HV_EDGE_THRES (DMSC_BASE + 0x0010) ++#define DMSC_ADDR_HV_EDGE_THRES (DMSC_BASE + 0x0014) ++#define DMSC_ADDR_HV_EDGE (DMSC_BASE + 0x0020) ++#define DMSC_ADDR_AA_EDGE_THRES (DMSC_BASE + 0x0024) ++#define DMSC_ADDR_AA_EDGE (DMSC_BASE + 0x0028) ++#define DMSC_ADDR_HVAA_EDGE_THRES (DMSC_BASE + 0x002C) ++#define DMSC_ADDR_HVAA_EDGE (DMSC_BASE + 0x0030) ++#define DMSC_ADDR_ALIAS_STREN (DMSC_BASE + 0x0034) ++#define DMSC_ADDR_ALIAS_THRES (DMSC_BASE + 0x0038) ++#define DMSC_ADDR_NOR_ALIAS_BLUR (DMSC_BASE + 0x003C) ++#define DMSC_ADDR_NOR_UU_WEI_STREN (DMSC_BASE + 0x0040) ++#define DMSC_ADDR_SP_D_V2_SIGMA (DMSC_BASE + 0x0044) ++#define DMSC_ADDR_SP_D_W_SP_STREN (DMSC_BASE + 0x0048) ++#define DMSC_ADDR_SP_D_LL_STREN (DMSC_BASE + 0x004C) ++#define DMSC_ADDR_SP_D_LL_THRES (DMSC_BASE + 0x0050) ++#define DMSC_ADDR_SP_D_W_LIMIT (DMSC_BASE + 0x0054) ++#define DMSC_ADDR_SP_D_B_LIMIT (DMSC_BASE + 0x0058) ++#define DMSC_ADDR_SP_UD_V2_SIGMA (DMSC_BASE + 0x005C) ++#define DMSC_ADDR_SP_UD_W_SP_STREN (DMSC_BASE + 0x0060) ++#define DMSC_ADDR_SP_UD_LL_STREN (DMSC_BASE + 0x0064) ++#define DMSC_ADDR_SP_UD_LL_THRES (DMSC_BASE + 0x0068) ++#define DMSC_ADDR_SP_UD_W_LIMIT (DMSC_BASE + 0x006C) ++#define DMSC_ADDR_SP_UD_B_LIMIT (DMSC_BASE + 0x0070) ++#define DMSC_ADDR_SP_NOR_ALIAS_THRES (DMSC_BASE + 0x0074) ++#define DMSC_ADDR_ALIAS_FUSION_THRES (DMSC_BASE + 0x0078) ++#define DMSC_ADDR_ALIAS_DIR_INTP_SP_STREN (DMSC_BASE + 0x007C) ++#define DMSC_ADDR_FC_ALIAS_STREN (DMSC_BASE + 0x0080) ++#define DMSC_ADDR_FC_ALIAS_THRES (DMSC_BASE + 0x0084) ++#define DMSC_ADDR_FC_NOR_SAT_THRES (DMSC_BASE + 0x0088) ++#define DMSC_ADDR_FC_TEXT_THRES (DMSC_BASE + 0x008C) ++#define DMSC_ADDR_FC_NOR_EDGE_SLOPE (DMSC_BASE + 0x0090) ++#define DMSC_ADDR_UU_NP_ARRAY_RG0 (DMSC_BASE + 0x0094) ++#define DMSC_ADDR_UU_NP_ARRAY_RG1 (DMSC_BASE + 0x0098) ++#define DMSC_ADDR_UU_NP_ARRAY_RG2 (DMSC_BASE + 0x009C) ++#define DMSC_ADDR_UU_NP_ARRAY_RG3 (DMSC_BASE + 0x00A0) ++#define DMSC_ADDR_UU_NP_ARRAY_RG4 (DMSC_BASE + 0x00A4) ++#define DMSC_ADDR_UU_NP_ARRAY_RG5 (DMSC_BASE + 0x00A8) ++#define DMSC_ADDR_UU_NP_ARRAY_RG6 (DMSC_BASE + 0x00AC) ++#define DMSC_ADDR_UU_NP_ARRAY_RG7 (DMSC_BASE + 0x00B0) ++#define DMSC_ADDR_SP_D_SIGMA_3_NP_ARRAY_RG0 (DMSC_BASE + 0x00B4) ++#define DMSC_ADDR_SP_D_SIGMA_3_NP_ARRAY_RG1 (DMSC_BASE + 0x00B8) ++#define DMSC_ADDR_SP_D_SIGMA_3_NP_ARRAY_RG2 (DMSC_BASE + 0x00BC) ++#define DMSC_ADDR_SP_D_W_WEI_NP_ARRAY_RG0 (DMSC_BASE + 0x00C0) ++#define DMSC_ADDR_SP_D_W_WEI_NP_ARRAY_RG1 (DMSC_BASE + 0x00C4) ++#define DMSC_ADDR_SP_D_W_WEI_NP_ARRAY_RG2 (DMSC_BASE + 0x00C8) ++#define DMSC_ADDR_SP_D_W_WEI_NP_ARRAY_RG3 (DMSC_BASE + 0x00CC) ++#define DMSC_ADDR_SP_D_B_WEI_NP_ARRAY_RG0 (DMSC_BASE + 0x00D0) ++#define DMSC_ADDR_SP_D_B_WEI_NP_ARRAY_RG1 (DMSC_BASE + 0x00D4) ++#define DMSC_ADDR_SP_D_B_WEI_NP_ARRAY_RG2 (DMSC_BASE + 0x00D8) ++#define DMSC_ADDR_SP_D_B_WEI_NP_ARRAY_RG3 (DMSC_BASE + 0x00DC) ++#define DMSC_ADDR_SP_UD_W_WEI_NP_ARRAY_RG0 (DMSC_BASE + 0x00E0) ++#define DMSC_ADDR_SP_UD_W_WEI_NP_ARRAY_RG1 (DMSC_BASE + 0x00E4) ++#define DMSC_ADDR_SP_UD_W_WEI_NP_ARRAY_RG2 (DMSC_BASE + 0x00E8) ++#define DMSC_ADDR_SP_UD_W_WEI_NP_ARRAY_RG3 (DMSC_BASE + 0x00EC) ++#define DMSC_ADDR_SP_UD_B_WEI_NP_ARRAY_RG0 (DMSC_BASE + 0x00F0) ++#define DMSC_ADDR_SP_UD_B_WEI_NP_ARRAY_RG1 (DMSC_BASE + 0x00F4) ++#define DMSC_ADDR_SP_UD_B_WEI_NP_ARRAY_RG2 (DMSC_BASE + 0x00F8) ++#define DMSC_ADDR_SP_UD_B_WEI_NP_ARRAY_RG3 (DMSC_BASE + 0x00FC) ++#define DMSC_ADDR_OUT_OPT (DMSC_BASE + 0x0100) ++#define DMSC_ADDR_SP_DEBUG_REG_0 (DMSC_BASE + 0x0104) ++#define DMSC_ADDR_SP_DEBUG_REG_1 (DMSC_BASE + 0x0108) ++#define DMSC_ADDR_FC_TEXT_2_STREN (DMSC_BASE + 0x010C) ++#define DMSC_ADDR_FC_TEXT_2_THRES (DMSC_BASE + 0x0110) ++#define DMSC_ADDR_FC_THRES_H_1 (DMSC_BASE + 0x0114) ++#define DMSC_ADDR_FC_THRES_H_2 (DMSC_BASE + 0x0118) ++ ++//============================================================ ++// CCM ++//============================================================ ++#define CCM_ADDR_REG_CTRL (CCM_BASE + 0x0000) ++#define CCM_ADDR_CCM_RRRG (CCM_BASE + 0x0004) ++#define CCM_ADDR_CCM_RBGR (CCM_BASE + 0x0008) ++#define CCM_ADDR_CCM_GGGB (CCM_BASE + 0x000c) ++#define CCM_ADDR_CCM_BRBG (CCM_BASE + 0x0010) ++#define CCM_ADDR_CCM_BB (CCM_BASE + 0x0014) ++#define CCM_ADDR_DP_CFG (CCM_BASE + 0x0018) ++#define CCM_ADDR_DP_SLOP (CCM_BASE + 0x001c) ++#define CCM_ADDR_SAT_THRES (CCM_BASE + 0x0020) ++ ++//=============================================== ++// DEFOG ++//=============================================== ++#define DEFOG_ADDR_BLOCK_COORD_M_01_00 (DEFOG_BASE + 0x0000) ++#define DEFOG_ADDR_BLOCK_COORD_M_03_02 (DEFOG_BASE + 0x0004) ++#define DEFOG_ADDR_BLOCK_COORD_M_05_04 (DEFOG_BASE + 0x0008) ++#define DEFOG_ADDR_BLOCK_COORD_M_07_06 (DEFOG_BASE + 0x000C) ++#define DEFOG_ADDR_BLOCK_COORD_M_09_08 (DEFOG_BASE + 0x0010) ++#define DEFOG_ADDR_BLOCK_COORD_M____10 (DEFOG_BASE + 0x0014) ++#define DEFOG_ADDR_BLOCK_COORD_N_01_00 (DEFOG_BASE + 0x0020) ++#define DEFOG_ADDR_BLOCK_COORD_N_03_02 (DEFOG_BASE + 0x0024) ++#define DEFOG_ADDR_BLOCK_COORD_N_05_04 (DEFOG_BASE + 0x0028) ++#define DEFOG_ADDR_BLOCK_COORD_N_07_06 (DEFOG_BASE + 0x002C) ++#define DEFOG_ADDR_BLOCK_COORD_N_09_08 (DEFOG_BASE + 0x0030) ++#define DEFOG_ADDR_BLOCK_COORD_N_11_10 (DEFOG_BASE + 0x0034) ++#define DEFOG_ADDR_BLOCK_COORD_N_13_12 (DEFOG_BASE + 0x0038) ++#define DEFOG_ADDR_BLOCK_COORD_N_15_14 (DEFOG_BASE + 0x003C) ++#define DEFOG_ADDR_BLOCK_COORD_N_17_16 (DEFOG_BASE + 0x0040) ++#define DEFOG_ADDR_BLOCK_COORD_N_19_18 (DEFOG_BASE + 0x0044) ++#define DEFOG_ADDR_BLOCK_COORD_N____20 (DEFOG_BASE + 0x0048) ++#define DEFOG_ADDR_CT3X3_DIS_01_00 (DEFOG_BASE + 0x0050) ++#define DEFOG_ADDR_CT3X3_DIS_03_02 (DEFOG_BASE + 0x0054) ++#define DEFOG_ADDR_CT3X3_DIS_05_04 (DEFOG_BASE + 0x0058) ++#define DEFOG_ADDR_CT3X3_DIS_07_06 (DEFOG_BASE + 0x005C) ++#define DEFOG_ADDR_CT3X3_DIS_09_08 (DEFOG_BASE + 0x0060) ++#define DEFOG_ADDR_CT3X3_DIS_11_10 (DEFOG_BASE + 0x0064) ++#define DEFOG_ADDR_CT3X3_DIS_13_12 (DEFOG_BASE + 0x0068) ++#define DEFOG_ADDR_CT3X3_DIS_15_14 (DEFOG_BASE + 0x006C) ++#define DEFOG_ADDR_CT3X3_DIS_17_16 (DEFOG_BASE + 0x0070) ++#define DEFOG_ADDR_CT3X3_DIS_19_18 (DEFOG_BASE + 0x0074) ++#define DEFOG_ADDR_CT3X3_DIS_21_20 (DEFOG_BASE + 0x0078) ++#define DEFOG_ADDR_CT3X3_DIS_23_22 (DEFOG_BASE + 0x007C) ++#define DEFOG_ADDR_CT5X5_DIS_01_00 (DEFOG_BASE + 0x0080) ++#define DEFOG_ADDR_CT5X5_DIS_03_02 (DEFOG_BASE + 0x0084) ++#define DEFOG_ADDR_CT5X5_DIS_05_04 (DEFOG_BASE + 0x0088) ++#define DEFOG_ADDR_CT5X5_DIS_07_06 (DEFOG_BASE + 0x008C) ++#define DEFOG_ADDR_CT5X5_DIS_09_08 (DEFOG_BASE + 0x0090) ++#define DEFOG_ADDR_CT5X5_DIS_11_10 (DEFOG_BASE + 0x0094) ++#define DEFOG_ADDR_CT5X5_DIS_13_12 (DEFOG_BASE + 0x0098) ++#define DEFOG_ADDR_CT5X5_DIS_15_14 (DEFOG_BASE + 0x009C) ++#define DEFOG_ADDR_CT5X5_DIS_17_16 (DEFOG_BASE + 0x00A0) ++#define DEFOG_ADDR_CT5X5_DIS_19_18 (DEFOG_BASE + 0x00A4) ++#define DEFOG_ADDR_CT5X5_DIS_21_20 (DEFOG_BASE + 0x00A8) ++#define DEFOG_ADDR_CT5X5_DIS_23_22 (DEFOG_BASE + 0x00AC) ++#define DEFOG_ADDR_CT5X5_DIS_25_24 (DEFOG_BASE + 0x00B0) ++#define DEFOG_ADDR_CT5X5_DIS_27_26 (DEFOG_BASE + 0x00B4) ++#define DEFOG_ADDR_CT5X5_DIS_29_28 (DEFOG_BASE + 0x00B8) ++#define DEFOG_ADDR_CT5X5_DIS_31_30 (DEFOG_BASE + 0x00BC) ++#define DEFOG_ADDR_WEIGHTLUT02_05_00 (DEFOG_BASE + 0x00C0) ++#define DEFOG_ADDR_WEIGHTLUT02_11_06 (DEFOG_BASE + 0x00C4) ++#define DEFOG_ADDR_WEIGHTLUT02_17_12 (DEFOG_BASE + 0x00C8) ++#define DEFOG_ADDR_WEIGHTLUT02_23_18 (DEFOG_BASE + 0x00CC) ++#define DEFOG_ADDR_WEIGHTLUT02_29_24 (DEFOG_BASE + 0x00D0) ++#define DEFOG_ADDR_WEIGHTLUT02_31_30 (DEFOG_BASE + 0x00D4) ++#define DEFOG_ADDR_WEIGHTLUT20_05_00 (DEFOG_BASE + 0x00E0) ++#define DEFOG_ADDR_WEIGHTLUT20_11_06 (DEFOG_BASE + 0x00E4) ++#define DEFOG_ADDR_WEIGHTLUT20_17_12 (DEFOG_BASE + 0x00E8) ++#define DEFOG_ADDR_WEIGHTLUT20_23_18 (DEFOG_BASE + 0x00EC) ++#define DEFOG_ADDR_WEIGHTLUT20_29_24 (DEFOG_BASE + 0x00F0) ++#define DEFOG_ADDR_WEIGHTLUT20_31_30 (DEFOG_BASE + 0x00F4) ++#define DEFOG_ADDR_WEIGHTLUT21_05_00 (DEFOG_BASE + 0x0100) ++#define DEFOG_ADDR_WEIGHTLUT21_11_06 (DEFOG_BASE + 0x0104) ++#define DEFOG_ADDR_WEIGHTLUT21_17_12 (DEFOG_BASE + 0x0108) ++#define DEFOG_ADDR_WEIGHTLUT21_23_18 (DEFOG_BASE + 0x010C) ++#define DEFOG_ADDR_WEIGHTLUT21_29_24 (DEFOG_BASE + 0x0110) ++#define DEFOG_ADDR_WEIGHTLUT21_31_30 (DEFOG_BASE + 0x0114) ++#define DEFOG_ADDR_WEIGHTLUT12_05_00 (DEFOG_BASE + 0x0120) ++#define DEFOG_ADDR_WEIGHTLUT12_11_06 (DEFOG_BASE + 0x0124) ++#define DEFOG_ADDR_WEIGHTLUT12_17_12 (DEFOG_BASE + 0x0128) ++#define DEFOG_ADDR_WEIGHTLUT12_23_18 (DEFOG_BASE + 0x012C) ++#define DEFOG_ADDR_WEIGHTLUT12_29_24 (DEFOG_BASE + 0x0130) ++#define DEFOG_ADDR_WEIGHTLUT12_31_30 (DEFOG_BASE + 0x0134) ++#define DEFOG_ADDR_WEIGHTLUT22_05_00 (DEFOG_BASE + 0x0140) ++#define DEFOG_ADDR_WEIGHTLUT22_11_06 (DEFOG_BASE + 0x0144) ++#define DEFOG_ADDR_WEIGHTLUT22_17_12 (DEFOG_BASE + 0x0148) ++#define DEFOG_ADDR_WEIGHTLUT22_23_18 (DEFOG_BASE + 0x014C) ++#define DEFOG_ADDR_WEIGHTLUT22_29_24 (DEFOG_BASE + 0x0150) ++#define DEFOG_ADDR_WEIGHTLUT22_31_30 (DEFOG_BASE + 0x0154) ++#define DEFOG_ADDR_BANK_BUFF_NUM (DEFOG_BASE + 0x0160) ++#define DEFOG_ADDR_BANK_ADDR_0 (DEFOG_BASE + 0x0164) ++#define DEFOG_ADDR_BANK_ADDR_1 (DEFOG_BASE + 0x0168) ++#define DEFOG_ADDR_BANK_ADDR_2 (DEFOG_BASE + 0x016C) ++#define DEFOG_ADDR_BANK_ADDR_3 (DEFOG_BASE + 0x0170) ++#define DEFOG_ADDR_PARA (DEFOG_BASE + 0x0180) ++#define DEFOG_ADDR_CLOR_CTRL_X3210 (DEFOG_BASE + 0x0190) ++#define DEFOG_ADDR_CLOR_CTRL_Y3210 (DEFOG_BASE + 0x0194) ++#define DEFOG_ADDR_CLOR_CTRL_XY44 (DEFOG_BASE + 0x0198) ++#define DEFOG_ADDR_CLOR_CTRL_POW3210 (DEFOG_BASE + 0x019C) ++#define DEFOG_ADDR_TRANS_DARK_CTRL_X3210 (DEFOG_BASE + 0x01A0) ++#define DEFOG_ADDR_TRANS_DARK_CTRL_Y3210 (DEFOG_BASE + 0x01A4) ++#define DEFOG_ADDR_TRANS_DARK_CTRL_XY44 (DEFOG_BASE + 0x01A8) ++#define DEFOG_ADDR_TRANS_DARK_CTRL_POW3210 (DEFOG_BASE + 0x01AC) ++#define DEFOG_ADDR_OVEREXPO_WGT_X3210 (DEFOG_BASE + 0x01B0) ++#define DEFOG_ADDR_OVEREXPO_WGT_Y3210 (DEFOG_BASE + 0x01B4) ++#define DEFOG_ADDR_OVEREXPO_WGT_POW210 (DEFOG_BASE + 0x01B8) ++#define DEFOG_ADDR_DARKSPC_WGT_X3210 (DEFOG_BASE + 0x01C0) ++#define DEFOG_ADDR_DARKSPC_WGT_Y3210 (DEFOG_BASE + 0x01C4) ++#define DEFOG_ADDR_DARKSPC_WGT_POW210 (DEFOG_BASE + 0x01C8) ++#define DEFOG_ADDR_FRAME_RATE (DEFOG_BASE + 0x01D0) ++#define DEFOG_ADDR_CTRL (DEFOG_BASE + 0x01E0) ++#define DEFOG_ADDR_FRAME_ADDR (DEFOG_BASE + 0x0200) ++#define DEFOG_ADDR_FRAME_ID (DEFOG_BASE + 0x0204) ++#define DEFOG_ADDR_DEBUG_SIGNAL_0 (DEFOG_BASE + 0x0208) ++#define DEFOG_ADDR_DEBUG_SIGNAL_1 (DEFOG_BASE + 0x020C) ++#define DEFOG_ADDR_DEBUG_SIGNAL_2 (DEFOG_BASE + 0x0210) ++#define DEFOG_ADDR_DEBUG_SIGNAL_3 (DEFOG_BASE + 0x0214) ++#define DEFOG_ADDR_DEBUG_SIGNAL_4 (DEFOG_BASE + 0x0218) ++#define DEFOG_ADDR_BLOCK_CFG_SEL (DEFOG_BASE + 0x0220) ++#define DEFOG_ADDR_BLOCK_CFG_BASE (DEFOG_BASE + 0x0224) ++ ++//============================================================ ++// CSC ++//============================================================ ++#define CSC_ADDR_CTRL (CSC_BASE + 0x0000) ++#define CSC_ADDR_SUB (CSC_BASE + 0x0004) ++#define CSC_ADDR_PAR_0 (CSC_BASE + 0x0010) ++#define CSC_ADDR_PAR_1 (CSC_BASE + 0x0014) ++#define CSC_ADDR_PAR_2 (CSC_BASE + 0x0018) ++#define CSC_ADDR_OFF_SET (CSC_BASE + 0x0020) ++#define CSC_ADDR_CLIP (CSC_BASE + 0x0030) ++ ++//============================================================ ++// CLM ++//============================================================ ++#define CLM_ADDR_REG_CTRL (CLM_BASE + 0x0000) ++#define CLM_ADDR_LUT_SHIFT (CLM_BASE + 0x0004) ++#define CLM_ADDR_CSC_RB (CLM_BASE + 0x0008) ++#define CLM_ADDR_CSC_G (CLM_BASE + 0x000c) ++#define CLM_ADDR_CSC_U (CLM_BASE + 0x0010) ++#define CLM_ADDR_CSC_V (CLM_BASE + 0x0014) ++#define CLM_ADDR_CSC_Y (CLM_BASE + 0x0018) ++#define CLM_ADDR_CA_S_THRES (CLM_BASE + 0x001c) ++#define CLM_ADDR_CA_S_SLOP (CLM_BASE + 0x0020) ++#define CLM_ADDR_CA_V_THRES (CLM_BASE + 0x0024) ++#define CLM_ADDR_CA_V_SLOP (CLM_BASE + 0x0028) ++#define CLM_ADDR_DEBUG0 (CLM_BASE + 0x002c) ++ ++//============================================================ ++// Sharpen ++//============================================================ ++#define SHARPEN_ADDR_SYNC (SP_BASE + 0x0000) ++#define SHARPEN_ADDR_STD_DIV_OPT (SP_BASE + 0x0004) ++#define SHARPEN_ADDR_V2_SIGMA (SP_BASE + 0x0008) ++#define SHARPEN_ADDR_W_WEI_SEG_OPT (SP_BASE + 0x000C) ++#define SHARPEN_ADDR_STREN (SP_BASE + 0x0010) ++#define SHARPEN_ADDR_THRES (SP_BASE + 0x0014) ++#define SHARPEN_ADDR_UU_SLOPE (SP_BASE + 0x0018) ++#define SHARPEN_ADDR_UU_NP_ARRAY_RG0 (SP_BASE + 0x001C) ++#define SHARPEN_ADDR_UU_NP_ARRAY_RG1 (SP_BASE + 0x0020) ++#define SHARPEN_ADDR_UU_NP_ARRAY_RG2 (SP_BASE + 0x0024) ++#define SHARPEN_ADDR_UU_NP_ARRAY_RG3 (SP_BASE + 0x0028) ++#define SHARPEN_ADDR_V1_SIGMA_NP_ARRAY_RG0 (SP_BASE + 0x002C) ++#define SHARPEN_ADDR_V1_SIGMA_NP_ARRAY_RG1 (SP_BASE + 0x0030) ++#define SHARPEN_ADDR_V1_SIGMA_NP_ARRAY_RG2 (SP_BASE + 0x0034) ++#define SHARPEN_ADDR_W_WEI_NP_ARRAY_RG0 (SP_BASE + 0x0038) ++#define SHARPEN_ADDR_W_WEI_NP_ARRAY_RG1 (SP_BASE + 0x003C) ++#define SHARPEN_ADDR_W_WEI_NP_ARRAY_RG2 (SP_BASE + 0x0040) ++#define SHARPEN_ADDR_W_WEI_NP_ARRAY_RG3 (SP_BASE + 0x0044) ++#define SHARPEN_ADDR_B_WEI_NP_ARRAY_RG0 (SP_BASE + 0x0048) ++#define SHARPEN_ADDR_B_WEI_NP_ARRAY_RG1 (SP_BASE + 0x004C) ++#define SHARPEN_ADDR_B_WEI_NP_ARRAY_RG2 (SP_BASE + 0x0050) ++#define SHARPEN_ADDR_B_WEI_NP_ARRAY_RG3 (SP_BASE + 0x0054) ++ ++//============================================================ ++// MDNS ++//============================================================ ++#define MDNS_ADDR_T_VERSION (MDNS_BASE + 0x0000) ++#define MDNS_ADDR_REG_CTRL (MDNS_BASE + 0x0004) ++#define MDNS_ADDR_DBG_SEL (MDNS_BASE + 0x0008) ++#define MDNS_ADDR_DBG_VALUE (MDNS_BASE + 0x000C) ++#define MDNS_ADDR_Y_REF_BASE_ADDR (MDNS_BASE + 0x0010) ++#define MDNS_ADDR_Y_REF_STRIDE (MDNS_BASE + 0x0014) ++#define MDNS_ADDR_Y_REF_FRM_SIZE (MDNS_BASE + 0x0018) ++#define MDNS_ADDR_Y_REF_FRM_NUM (MDNS_BASE + 0x001C) ++#define MDNS_ADDR_UV_REF_BASE_ADDR (MDNS_BASE + 0x0020) ++#define MDNS_ADDR_UV_REF_STRIDE (MDNS_BASE + 0x0024) ++#define MDNS_ADDR_UV_REF_FRM_SIZE (MDNS_BASE + 0x0028) ++#define MDNS_ADDR_UV_REF_FRM_NUM (MDNS_BASE + 0x002C) ++#define MDNS_ADDR_STA_BASE_ADDR (MDNS_BASE + 0x0030) ++#define MDNS_ADDR_STA_STRIDE (MDNS_BASE + 0x0034) ++#define MDNS_ADDR_STA_FRM_SIZE (MDNS_BASE + 0x0038) ++#define MDNS_ADDR_STA_FRM_NUM (MDNS_BASE + 0x003C) ++#define MDNS_ADDR_PBT_BASE_ADDR (MDNS_BASE + 0x0040) ++#define MDNS_ADDR_PBT_STRIDE (MDNS_BASE + 0x0044) ++#define MDNS_ADDR_PBT_FRM_SIZE (MDNS_BASE + 0x0048) ++#define MDNS_ADDR_PBT_FRM_NUM (MDNS_BASE + 0x004C) ++#define MDNS_ADDR_T_FRM_NUM (MDNS_BASE + 0x0050) ++#define MDNS_ADDR_T_TOP_FUN (MDNS_BASE + 0x0060) ++#define MDNS_ADDR_STA_OVER_CFG (MDNS_BASE + 0x0070) ++#define MDNS_ADDR_STA_WIN_CFG (MDNS_BASE + 0x0074) ++#define MDNS_ADDR_STA_BLK_SIZE (MDNS_BASE + 0x0078) ++#define MDNS_ADDR_STA_BLK_NUM (MDNS_BASE + 0x007C) ++#define MDNS_ADDR_STA_MAX_NUM (MDNS_BASE + 0x0080) ++#define MDNS_ADDR_STA_DIFF_THRES (MDNS_BASE + 0x0084) ++#define MDNS_ADDR_STA_MV_NUM_THRES00 (MDNS_BASE + 0x0090) ++#define MDNS_ADDR_STA_MV_NUM_THRES01 (MDNS_BASE + 0x0094) ++#define MDNS_ADDR_STA_MV_NUM_THRES10 (MDNS_BASE + 0x0098) ++#define MDNS_ADDR_STA_MV_NUM_THRES11 (MDNS_BASE + 0x009C) ++#define MDNS_ADDR_PBT_START_POINT (MDNS_BASE + 0x00A0) ++#define MDNS_ADDR_PBT_WIN_SIZE (MDNS_BASE + 0x00A4) ++#define MDNS_ADDR_PBT_OVER_CFG (MDNS_BASE + 0x00B0) ++#define MDNS_ADDR_PBT_WIN_CFG (MDNS_BASE + 0x00B4) ++#define MDNS_ADDR_PBT_BLK_SIZE (MDNS_BASE + 0x00B8) ++#define MDNS_ADDR_PBT_BLK_NUM (MDNS_BASE + 0x00BC) ++#define MDNS_ADDR_PBT_MAX_NUM (MDNS_BASE + 0x00C0) ++#define MDNS_ADDR_PBT_DIFF_THRES (MDNS_BASE + 0x00C4) ++#define MDNS_ADDR_PBT_MV_NUM_THRES00 (MDNS_BASE + 0x00D0) ++#define MDNS_ADDR_PBT_MV_NUM_THRES01 (MDNS_BASE + 0x00D4) ++#define MDNS_ADDR_PBT_MV_NUM_THRES10 (MDNS_BASE + 0x00D8) ++#define MDNS_ADDR_PBT_MV_NUM_THRES11 (MDNS_BASE + 0x00DC) ++#define MDNS_ADDR_Y_CUT_VALUE (MDNS_BASE + 0x00E0) ++#define MDNS_ADDR_Y_EDGE_PAR (MDNS_BASE + 0x00E4) ++#define MDNS_ADDR_Y_BI_PAR0 (MDNS_BASE + 0x00E8) ++#define MDNS_ADDR_Y_BI_PAR1 (MDNS_BASE + 0x00EC) ++#define MDNS_ADDR_Y_TCA_PAR (MDNS_BASE + 0x00F0) ++#define MDNS_ADDR_Y_TEA_T_PAR0 (MDNS_BASE + 0x00F4) ++#define MDNS_ADDR_Y_TEA_T_PAR1 (MDNS_BASE + 0x00F8) ++#define MDNS_ADDR_Y_TEA_V_PAR0 (MDNS_BASE + 0x00FC) ++#define MDNS_ADDR_Y_TEA_V_PAR1 (MDNS_BASE + 0x0100) ++#define MDNS_ADDR_Y_TEA_W_PAR0 (MDNS_BASE + 0x0104) ++#define MDNS_ADDR_Y_TEA_W_PAR1 (MDNS_BASE + 0x0108) ++#define MDNS_ADDR_Y_TLA_WIN_OPT (MDNS_BASE + 0x010C) ++#define MDNS_ADDR_Y_TLA_T_PAR0 (MDNS_BASE + 0x0110) ++#define MDNS_ADDR_Y_TLA_T_PAR1 (MDNS_BASE + 0x0114) ++#define MDNS_ADDR_Y_TLA_T_PAR2 (MDNS_BASE + 0x0118) ++#define MDNS_ADDR_Y_TLA_T_PAR3 (MDNS_BASE + 0x011C) ++#define MDNS_ADDR_Y_TLA_V_PAR0 (MDNS_BASE + 0x0120) ++#define MDNS_ADDR_Y_TLA_V_PAR1 (MDNS_BASE + 0x0124) ++#define MDNS_ADDR_Y_TLA_V_PAR2 (MDNS_BASE + 0x0128) ++#define MDNS_ADDR_Y_TLA_V_PAR3 (MDNS_BASE + 0x012C) ++#define MDNS_ADDR_Y_TLA_W_PAR0 (MDNS_BASE + 0x0130) ++#define MDNS_ADDR_Y_TLA_W_PAR1 (MDNS_BASE + 0x0134) ++#define MDNS_ADDR_Y_TLA_W_PAR2 (MDNS_BASE + 0x0138) ++#define MDNS_ADDR_Y_TLA_W_PAR3 (MDNS_BASE + 0x013C) ++#define MDNS_ADDR_Y_SAD_CFG (MDNS_BASE + 0x0140) ++#define MDNS_ADDR_Y_STA_WEI_PAR0 (MDNS_BASE + 0x0150) ++#define MDNS_ADDR_Y_STA_WEI_PAR1 (MDNS_BASE + 0x0154) ++#define MDNS_ADDR_Y_STA_WEI_PAR2 (MDNS_BASE + 0x0158) ++#define MDNS_ADDR_Y_STA_WEI_PAR3 (MDNS_BASE + 0x015C) ++#define MDNS_ADDR_Y_STA_WEI_PAR4 (MDNS_BASE + 0x0160) ++#define MDNS_ADDR_Y_STA_WEI_PAR5 (MDNS_BASE + 0x0164) ++#define MDNS_ADDR_Y_STA_WEI_PAR6 (MDNS_BASE + 0x0168) ++#define MDNS_ADDR_Y_STA_WEI_PAR7 (MDNS_BASE + 0x016C) ++#define MDNS_ADDR_Y_STA_WEI_PAR8 (MDNS_BASE + 0x0170) ++#define MDNS_ADDR_Y_STA_WEI_PAR9 (MDNS_BASE + 0x0174) ++#define MDNS_ADDR_Y_STA_WEI_PARa (MDNS_BASE + 0x0178) ++#define MDNS_ADDR_Y_STA_WEI_PARb (MDNS_BASE + 0x017C) ++#define MDNS_ADDR_Y_STA_WEI_PARc (MDNS_BASE + 0x0180) ++#define MDNS_ADDR_Y_STA_WEI_PARd (MDNS_BASE + 0x0184) ++#define MDNS_ADDR_Y_STA_WEI_PARe (MDNS_BASE + 0x0188) ++#define MDNS_ADDR_Y_STA_WEI_PARf (MDNS_BASE + 0x018C) ++#define MDNS_ADDR_Y_PBT_WEI_PAR0 (MDNS_BASE + 0x0190) ++#define MDNS_ADDR_Y_PBT_WEI_PAR1 (MDNS_BASE + 0x0194) ++#define MDNS_ADDR_Y_PBT_WEI_PAR2 (MDNS_BASE + 0x0198) ++#define MDNS_ADDR_Y_PBT_WEI_PAR3 (MDNS_BASE + 0x019C) ++#define MDNS_ADDR_Y_PBT_WEI_PAR4 (MDNS_BASE + 0x01A0) ++#define MDNS_ADDR_Y_PBT_WEI_PAR5 (MDNS_BASE + 0x01A4) ++#define MDNS_ADDR_Y_PBT_WEI_PAR6 (MDNS_BASE + 0x01A8) ++#define MDNS_ADDR_Y_PBT_WEI_PAR7 (MDNS_BASE + 0x01AC) ++#define MDNS_ADDR_Y_PBT_WEI_PAR8 (MDNS_BASE + 0x01B0) ++#define MDNS_ADDR_Y_PBT_WEI_PAR9 (MDNS_BASE + 0x01B4) ++#define MDNS_ADDR_Y_PBT_WEI_PARa (MDNS_BASE + 0x01B8) ++#define MDNS_ADDR_Y_PBT_WEI_PARb (MDNS_BASE + 0x01BC) ++#define MDNS_ADDR_Y_PBT_WEI_PARc (MDNS_BASE + 0x01C0) ++#define MDNS_ADDR_Y_PBT_WEI_PARd (MDNS_BASE + 0x01C4) ++#define MDNS_ADDR_Y_PBT_WEI_PARe (MDNS_BASE + 0x01C8) ++#define MDNS_ADDR_Y_PBT_WEI_PARf (MDNS_BASE + 0x01CC) ++#define MDNS_ADDR_Y_WSA_S_PAR (MDNS_BASE + 0x01D0) ++#define MDNS_ADDR_Y_WSA_M_PAR (MDNS_BASE + 0x01D4) ++#define MDNS_ADDR_Y_WFA_PAR (MDNS_BASE + 0x01D8) ++#define MDNS_ADDR_Y_REF_WEI_LMT (MDNS_BASE + 0x01DC) ++#define MDNS_ADDR_Y_REF_WEI_SGM_X_PAR0 (MDNS_BASE + 0x01E0) ++#define MDNS_ADDR_Y_REF_WEI_SGM_X_PAR1 (MDNS_BASE + 0x01E4) ++#define MDNS_ADDR_Y_REF_WEI_SGM_X_PAR2 (MDNS_BASE + 0x01E8) ++#define MDNS_ADDR_Y_REF_WEI_SGM_Y_PAR0 (MDNS_BASE + 0x01EC) ++#define MDNS_ADDR_Y_REF_WEI_SGM_Y_PAR1 (MDNS_BASE + 0x01F0) ++#define MDNS_ADDR_Y_REF_WEI_SGM_S_PAR0 (MDNS_BASE + 0x01F4) ++#define MDNS_ADDR_Y_REF_WEI_SGM_S_PAR1 (MDNS_BASE + 0x01F8) ++#define MDNS_ADDR_Y_FS_MV_JUDGE_THRES (MDNS_BASE + 0x01FC) ++#define MDNS_ADDR_Y_FS_S_CUR_SHP_WIN_OPT (MDNS_BASE + 0x0200) ++#define MDNS_ADDR_Y_FS_S_CUR_SHP_STREN_P0 (MDNS_BASE + 0x0204) ++#define MDNS_ADDR_Y_FS_S_CUR_SHP_STREN_P1 (MDNS_BASE + 0x0208) ++#define MDNS_ADDR_Y_FS_S_CUR_SHP_STREN_P2 (MDNS_BASE + 0x020C) ++#define MDNS_ADDR_Y_FS_S_CUR_SHP_STREN_P3 (MDNS_BASE + 0x0210) ++#define MDNS_ADDR_Y_FS_S_REF_SHP_WIN_OPT (MDNS_BASE + 0x0214) ++#define MDNS_ADDR_Y_FS_S_REF_SHP_STREN_P0 (MDNS_BASE + 0x0218) ++#define MDNS_ADDR_Y_FS_S_REF_SHP_STREN_P1 (MDNS_BASE + 0x021C) ++#define MDNS_ADDR_Y_FS_S_REF_SHP_STREN_P2 (MDNS_BASE + 0x0220) ++#define MDNS_ADDR_Y_FS_S_REF_SHP_STREN_P3 (MDNS_BASE + 0x0224) ++#define MDNS_ADDR_Y_FS_S_SHP_WEI (MDNS_BASE + 0x0228) ++#define MDNS_ADDR_Y_FS_M_CUR_SHP_WIN_OPT (MDNS_BASE + 0x022C) ++#define MDNS_ADDR_Y_FS_M_CUR_SHP_STREN_P0 (MDNS_BASE + 0x0230) ++#define MDNS_ADDR_Y_FS_M_CUR_SHP_STREN_P1 (MDNS_BASE + 0x0234) ++#define MDNS_ADDR_Y_FS_M_CUR_SHP_STREN_P2 (MDNS_BASE + 0x0238) ++#define MDNS_ADDR_Y_FS_M_CUR_SHP_STREN_P3 (MDNS_BASE + 0x023C) ++#define MDNS_ADDR_Y_FS_M_REF_SHP_WIN_OPT (MDNS_BASE + 0x0240) ++#define MDNS_ADDR_Y_FS_M_REF_SHP_STREN_P0 (MDNS_BASE + 0x0244) ++#define MDNS_ADDR_Y_FS_M_REF_SHP_STREN_P1 (MDNS_BASE + 0x0248) ++#define MDNS_ADDR_Y_FS_M_REF_SHP_STREN_P2 (MDNS_BASE + 0x024C) ++#define MDNS_ADDR_Y_FS_M_REF_SHP_STREN_P3 (MDNS_BASE + 0x0250) ++#define MDNS_ADDR_Y_FS_M_SHP_WEI (MDNS_BASE + 0x0254) ++#define MDNS_ADDR_Y_FS_SHP_CUR_STA_WEI_P0 (MDNS_BASE + 0x0258) ++#define MDNS_ADDR_Y_FS_SHP_CUR_STA_WEI_P1 (MDNS_BASE + 0x025C) ++#define MDNS_ADDR_Y_FS_SHP_REF_STA_WEI_P0 (MDNS_BASE + 0x0260) ++#define MDNS_ADDR_Y_FS_SHP_REF_STA_WEI_P1 (MDNS_BASE + 0x0264) ++#define MDNS_ADDR_Y_FS_SHP_CUR_FLUCT_PAR (MDNS_BASE + 0x0268) ++#define MDNS_ADDR_Y_FS_SHP_REF_FLUCT_PAR (MDNS_BASE + 0x026C) ++#define MDNS_ADDR_UV_CUT_VALUE (MDNS_BASE + 0x0280) ++#define MDNS_ADDR_UV_SAD_CFG (MDNS_BASE + 0x0284) ++#define MDNS_ADDR_UV_TCA_PAR (MDNS_BASE + 0x0290) ++#define MDNS_ADDR_UV_TMA_T_PAR0 (MDNS_BASE + 0x0294) ++#define MDNS_ADDR_UV_TMA_T_PAR1 (MDNS_BASE + 0x0298) ++#define MDNS_ADDR_UV_TMA_V_PAR0 (MDNS_BASE + 0x029C) ++#define MDNS_ADDR_UV_TMA_V_PAR1 (MDNS_BASE + 0x02a0) ++#define MDNS_ADDR_UV_TMA_W_PAR0 (MDNS_BASE + 0x02a4) ++#define MDNS_ADDR_UV_TMA_W_PAR1 (MDNS_BASE + 0x02a8) ++#define MDNS_ADDR_UV_STA_WEI_PAR0 (MDNS_BASE + 0x02b0) ++#define MDNS_ADDR_UV_STA_WEI_PAR1 (MDNS_BASE + 0x02b4) ++#define MDNS_ADDR_UV_STA_WEI_PAR2 (MDNS_BASE + 0x02b8) ++#define MDNS_ADDR_UV_STA_WEI_PAR3 (MDNS_BASE + 0x02bC) ++#define MDNS_ADDR_UV_STA_WEI_PAR4 (MDNS_BASE + 0x02c0) ++#define MDNS_ADDR_UV_STA_WEI_PAR5 (MDNS_BASE + 0x02c4) ++#define MDNS_ADDR_UV_STA_WEI_PAR6 (MDNS_BASE + 0x02c8) ++#define MDNS_ADDR_UV_STA_WEI_PAR7 (MDNS_BASE + 0x02cC) ++#define MDNS_ADDR_UV_STA_WEI_PAR8 (MDNS_BASE + 0x02d0) ++#define MDNS_ADDR_UV_STA_WEI_PAR9 (MDNS_BASE + 0x02d4) ++#define MDNS_ADDR_UV_STA_WEI_PARa (MDNS_BASE + 0x02d8) ++#define MDNS_ADDR_UV_STA_WEI_PARb (MDNS_BASE + 0x02dC) ++#define MDNS_ADDR_UV_STA_WEI_PARc (MDNS_BASE + 0x02e0) ++#define MDNS_ADDR_UV_STA_WEI_PARd (MDNS_BASE + 0x02e4) ++#define MDNS_ADDR_UV_STA_WEI_PARe (MDNS_BASE + 0x02e8) ++#define MDNS_ADDR_UV_STA_WEI_PARf (MDNS_BASE + 0x02eC) ++#define MDNS_ADDR_UV_PBT_WEI_PAR0 (MDNS_BASE + 0x02f0) ++#define MDNS_ADDR_UV_PBT_WEI_PAR1 (MDNS_BASE + 0x02f4) ++#define MDNS_ADDR_UV_PBT_WEI_PAR2 (MDNS_BASE + 0x02f8) ++#define MDNS_ADDR_UV_PBT_WEI_PAR3 (MDNS_BASE + 0x02fC) ++#define MDNS_ADDR_UV_PBT_WEI_PAR4 (MDNS_BASE + 0x0300) ++#define MDNS_ADDR_UV_PBT_WEI_PAR5 (MDNS_BASE + 0x0304) ++#define MDNS_ADDR_UV_PBT_WEI_PAR6 (MDNS_BASE + 0x0308) ++#define MDNS_ADDR_UV_PBT_WEI_PAR7 (MDNS_BASE + 0x030C) ++#define MDNS_ADDR_UV_PBT_WEI_PAR8 (MDNS_BASE + 0x0310) ++#define MDNS_ADDR_UV_PBT_WEI_PAR9 (MDNS_BASE + 0x0314) ++#define MDNS_ADDR_UV_PBT_WEI_PARa (MDNS_BASE + 0x0318) ++#define MDNS_ADDR_UV_PBT_WEI_PARb (MDNS_BASE + 0x031C) ++#define MDNS_ADDR_UV_PBT_WEI_PARc (MDNS_BASE + 0x0320) ++#define MDNS_ADDR_UV_PBT_WEI_PARd (MDNS_BASE + 0x0324) ++#define MDNS_ADDR_UV_PBT_WEI_PARe (MDNS_BASE + 0x0328) ++#define MDNS_ADDR_UV_PBT_WEI_PARf (MDNS_BASE + 0x032C) ++#define MDNS_ADDR_UV_WSA_S_PAR (MDNS_BASE + 0x0330) ++#define MDNS_ADDR_UV_WSA_M_PAR (MDNS_BASE + 0x0334) ++#define MDNS_ADDR_UV_REF_WEI_LMT (MDNS_BASE + 0x0338) ++#define MDNS_ADDR_UV_REF_WEI_SGM_X_PAR0 (MDNS_BASE + 0x0340) ++#define MDNS_ADDR_UV_REF_WEI_SGM_X_PAR1 (MDNS_BASE + 0x0344) ++#define MDNS_ADDR_UV_REF_WEI_SGM_X_PAR2 (MDNS_BASE + 0x0348) ++#define MDNS_ADDR_UV_REF_WEI_SGM_Y_PAR0 (MDNS_BASE + 0x034C) ++#define MDNS_ADDR_UV_REF_WEI_SGM_Y_PAR1 (MDNS_BASE + 0x0350) ++#define MDNS_ADDR_UV_REF_WEI_SGM_S_PAR0 (MDNS_BASE + 0x0354) ++#define MDNS_ADDR_UV_REF_WEI_SGM_S_PAR1 (MDNS_BASE + 0x0358) ++#define MDNS_ADDR_UV_FS_MV_JUDGE_THRES (MDNS_BASE + 0x035C) ++#define MDNS_ADDR_UV_FC_TYPE (MDNS_BASE + 0x0360) ++#define MDNS_ADDR_UV_FC_S_PAR0 (MDNS_BASE + 0x0370) ++#define MDNS_ADDR_UV_FC_S_PAR1 (MDNS_BASE + 0x0374) ++#define MDNS_ADDR_UV_FC_M_PAR0 (MDNS_BASE + 0x0378) ++#define MDNS_ADDR_UV_FC_M_PAR1 (MDNS_BASE + 0x037C) ++#define MDNS_ADDR_UV_BLUR_WEI (MDNS_BASE + 0x0380) ++ ++//============================================================ ++// SDNS ++//============================================================ ++#define SDNS_ADDR_T_VERSION (SDNS_BASE + 0x0000) ++#define SDNS_ADDR_REG_CTRL (SDNS_BASE + 0x0004) ++#define SDNS_ADDR_DBG_SEL (SDNS_BASE + 0x0008) ++#define SDNS_ADDR_DBG_VALUE (SDNS_BASE + 0x000C) ++#define SDNS_ADDR_Y_FUN_EN (SDNS_BASE + 0x0010) ++#define SDNS_ADDR_Y_COM_PAR0 (SDNS_BASE + 0x0014) ++#define SDNS_ADDR_Y_COM_PAR1 (SDNS_BASE + 0x0018) ++#define SDNS_ADDR_Y_FUSION_PAR0 (SDNS_BASE + 0x001C) ++#define SDNS_ADDR_Y_FUSION_PAR1 (SDNS_BASE + 0x0020) ++#define SDNS_ADDR_Y_FUSION_PAR2 (SDNS_BASE + 0x0024) ++#define SDNS_ADDR_Y_FUSION_PAR3 (SDNS_BASE + 0x0028) ++#define SDNS_ADDR_Y_DETAIL_PAR0 (SDNS_BASE + 0x002C) ++#define SDNS_ADDR_Y_DETAIL_PAR1 (SDNS_BASE + 0x0030) ++#define SDNS_ADDR_Y_DETAIL_PAR2 (SDNS_BASE + 0x0034) ++#define SDNS_ADDR_Y_DETAIL_PAR3 (SDNS_BASE + 0x0038) ++#define SDNS_ADDR_Y_LUMA_PAR0 (SDNS_BASE + 0x003C) ++#define SDNS_ADDR_Y_LUMA_PAR1 (SDNS_BASE + 0x0040) ++#define SDNS_ADDR_Y_LUMA_PAR2 (SDNS_BASE + 0x0044) ++#define SDNS_ADDR_Y_LUMA_PAR3 (SDNS_BASE + 0x0048) ++#define SDNS_ADDR_Y_BSHP_PAR0 (SDNS_BASE + 0x004C) ++#define SDNS_ADDR_Y_BSHP_PAR1 (SDNS_BASE + 0x0050) ++#define SDNS_ADDR_Y_BSHP_PAR2 (SDNS_BASE + 0x0054) ++#define SDNS_ADDR_Y_BSHP_PAR3 (SDNS_BASE + 0x0058) ++#define SDNS_ADDR_Y_DSHP_PAR0 (SDNS_BASE + 0x005C) ++#define SDNS_ADDR_Y_DSHP_PAR1 (SDNS_BASE + 0x0060) ++#define SDNS_ADDR_Y_DSHP_PAR2 (SDNS_BASE + 0x0064) ++#define SDNS_ADDR_Y_DSHP_PAR3 (SDNS_BASE + 0x0068) ++#define SDNS_ADDR_Y_BI_PAR0 (SDNS_BASE + 0x006C) ++#define SDNS_ADDR_Y_BI_PAR1 (SDNS_BASE + 0x0070) ++#define SDNS_ADDR_Y_BI_PAR2 (SDNS_BASE + 0x0074) ++#define SDNS_ADDR_Y_BI_PAR3 (SDNS_BASE + 0x0078) ++#define SDNS_ADDR_UV_FUN_EN (SDNS_BASE + 0x0080) ++#define SDNS_ADDR_UV_COM_PAR (SDNS_BASE + 0x0084) ++#define SDNS_ADDR_UV_FUSION_PAR0 (SDNS_BASE + 0x0088) ++#define SDNS_ADDR_UV_FUSION_PAR1 (SDNS_BASE + 0x008C) ++#define SDNS_ADDR_UV_FUSION_PAR2 (SDNS_BASE + 0x0090) ++#define SDNS_ADDR_UV_FUSION_PAR3 (SDNS_BASE + 0x0094) ++ ++//============================================================ ++// HLDC ++//============================================================ ++#define HLDC_ADDR_REG_CTRL (HLDC_BASE + 0x0000) ++#define HLDC_ADDR_DIS_Y_COEFF_X (HLDC_BASE + 0x0004) ++#define HLDC_ADDR_DIS_UV_COEFF_X (HLDC_BASE + 0x0008) ++#define HLDC_ADDR_P1_Y_VAL (HLDC_BASE + 0x000C) ++#define HLDC_ADDR_P1_UV_VAL (HLDC_BASE + 0x0010) ++#define HLDC_ADDR_R2_Y_REP (HLDC_BASE + 0x0014) ++#define HLDC_ADDR_R2_UV_REP (HLDC_BASE + 0x0018) ++#define HLDC_ADDR_Y_OFFSET (HLDC_BASE + 0x001C) ++#define HLDC_ADDR_UV_OFFSET (HLDC_BASE + 0x0020) ++#define HLDC_ADDR_LINE_BLK_Y (HLDC_BASE + 0x0024) ++#define HLDC_ADDR_LINE_BLK_UV (HLDC_BASE + 0x0028) ++ ++//============================================================ ++// Mscaler ++//============================================================ ++#define MSCA_CTRL (MSCA_BASE+0x000) ++#define MSCA_CH_EN (MSCA_BASE+0x004) ++#define MSCA_CH_STA (MSCA_BASE+0x008) ++#define MSCA_INT_STA (MSCA_BASE+0x00C) ++#define MSCA_INT_MSK (MSCA_BASE+0x010) ++#define MSCA_INT_CLR (MSCA_BASE+0x014) ++#define MSCA_DMAOUT_ARB (MSCA_BASE+0x018) ++#define MSCA_CLK_GATE_EN (MSCA_BASE+0x01C) ++#define MSCA_CLK_DIS (MSCA_BASE+0x020) ++#define MSCA_SRC_IN (MSCA_BASE+0x030) ++#define MSCA_SRC_SIZE (MSCA_BASE+0x034) ++#define MSCA_GLO_RSZ_COEF_WR (MSCA_BASE+0x040) ++#define MSCA_SYS_PRO_CLK_EN (MSCA_BASE+0x050) ++#define MSCA_DS0_CLK_NUM (MSCA_BASE+0x054) ++#define MSCA_DS1_CLK_NUM (MSCA_BASE+0x058) ++#define MSCA_DS2_CLK_NUM (MSCA_BASE+0x05C) ++ ++//ds0 ++#define MSCA_ADDR_DS0_RSZ_SIZE (MSCA_BASE+0x100) ++#define MSCA_ADDR_DS0_RSZ_STEP (MSCA_BASE+0x104) ++#define MSCA_ADDR_DS0_CROP_POS (MSCA_BASE+0x128) ++#define MSCA_ADDR_DS0_CROP_SIZE (MSCA_BASE+0x12C) ++#define MSCA_ADDR_DS0_FRA_RATE_LOOP (MSCA_BASE+0x130) ++#define MSCA_ADDR_DS0_FRA_RATE_MASK (MSCA_BASE+0x134) ++#define MSCA_ADDR_DS0_MASK0_POS (MSCA_BASE+0x138) ++#define MSCA_ADDR_DS0_MASK0_SIZE (MSCA_BASE+0x13C) ++#define MSCA_ADDR_DS0_MASK0_ARGB (MSCA_BASE+0x140) ++#define MSCA_ADDR_DS0_MASK1_POS (MSCA_BASE+0x144) ++#define MSCA_ADDR_DS0_MASK1_SIZE (MSCA_BASE+0x148) ++#define MSCA_ADDR_DS0_MASK1_ARGB (MSCA_BASE+0x14C) ++#define MSCA_ADDR_DS0_MASK2_POS (MSCA_BASE+0x150) ++#define MSCA_ADDR_DS0_MASK2_SIZE (MSCA_BASE+0x154) ++#define MSCA_ADDR_DS0_MASK2_ARGB (MSCA_BASE+0x158) ++#define MSCA_ADDR_DS0_MASK3_POS (MSCA_BASE+0x15C) ++#define MSCA_ADDR_DS0_MASK3_SIZE (MSCA_BASE+0x160) ++#define MSCA_ADDR_DS0_MASK3_ARGB (MSCA_BASE+0x164) ++#define MSCA_ADDR_DS0_DMAOUT_FMT (MSCA_BASE+0x168) ++#define MSCA_ADDR_DS0_DMAOUT_Y_ADDR (MSCA_BASE+0x16C) ++#define MSCA_ADDR_DS0_DMAOUT_Y_FIFO_STA (MSCA_BASE+0x170) ++#define MSCA_ADDR_DS0_DMAOUT_Y_LAST_ADDR (MSCA_BASE+0x174) ++#define MSCA_ADDR_DS0_DMAOUT_Y_LAST_STATS_NUM (MSCA_BASE+0x178) ++#define MSCA_ADDR_DS0_DMAOUT_Y_LAST_FIFO_STA (MSCA_BASE+0x17C) ++#define MSCA_ADDR_DS0_DMAOUT_Y_STR (MSCA_BASE+0x180) ++#define MSCA_ADDR_DS0_DMAOUT_UV_ADDR (MSCA_BASE+0x184) ++#define MSCA_ADDR_DS0_DMAOUT_UV_FIFO_STA (MSCA_BASE+0x188) ++#define MSCA_ADDR_DS0_DMAOUT_UV_LAST_ADDR (MSCA_BASE+0x18C) ++#define MSCA_ADDR_DS0_DMAOUT_UV_LAST_STATS_NUM (MSCA_BASE+0x190) ++#define MSCA_ADDR_DS0_DMAOUT_UV_LAST_FIFO_STA (MSCA_BASE+0x194) ++#define MSCA_ADDR_DS0_DMAOUT_UV_STR (MSCA_BASE+0x198) ++#define MSCA_ADDR_DS0_DMAOUT_Y_FIFO_CLR (MSCA_BASE+0x19C) ++#define MSCA_ADDR_DS0_DMAOUT_UV_FIFO_CLR (MSCA_BASE+0x1A0) ++#define MSCA_ADDR_DS0_DMAOUT_Y_LAST_FIFO_CLR (MSCA_BASE+0x1A4) ++#define MSCA_ADDR_DS0_DMAOUT_UV_LAST_FIFO_CLR (MSCA_BASE+0x1A8) ++#define MSCA_ADDR_DS0_DMAOUT_Y_ADDR_SEL (MSCA_BASE+0x1AC) ++#define MSCA_ADDR_DS0_DMAOUT_UV_ADDR_SEL (MSCA_BASE+0x1B0) ++ ++//-- ds1 ++#define MSCA_ADDR_DS1_RSZ_SIZE (MSCA_BASE+0x200) ++#define MSCA_ADDR_DS1_RSZ_STEP (MSCA_BASE+0x204) ++#define MSCA_ADDR_DS1_CROP_POS (MSCA_BASE+0x228) ++#define MSCA_ADDR_DS1_CROP_SIZE (MSCA_BASE+0x22C) ++#define MSCA_ADDR_DS1_FRA_RATE_LOOP (MSCA_BASE+0x230) ++#define MSCA_ADDR_DS1_FRA_RATE_MASK (MSCA_BASE+0x234) ++#define MSCA_ADDR_DS1_MASK0_POS (MSCA_BASE+0x238) ++#define MSCA_ADDR_DS1_MASK0_SIZE (MSCA_BASE+0x23C) ++#define MSCA_ADDR_DS1_MASK0_ARGB (MSCA_BASE+0x240) ++#define MSCA_ADDR_DS1_MASK1_POS (MSCA_BASE+0x244) ++#define MSCA_ADDR_DS1_MASK1_SIZE (MSCA_BASE+0x248) ++#define MSCA_ADDR_DS1_MASK1_ARGB (MSCA_BASE+0x24C) ++#define MSCA_ADDR_DS1_MASK2_POS (MSCA_BASE+0x250) ++#define MSCA_ADDR_DS1_MASK2_SIZE (MSCA_BASE+0x254) ++#define MSCA_ADDR_DS1_MASK2_ARGB (MSCA_BASE+0x258) ++#define MSCA_ADDR_DS1_MASK3_POS (MSCA_BASE+0x25C) ++#define MSCA_ADDR_DS1_MASK3_SIZE (MSCA_BASE+0x260) ++#define MSCA_ADDR_DS1_MASK3_ARGB (MSCA_BASE+0x264) ++#define MSCA_ADDR_DS1_DMAOUT_FMT (MSCA_BASE+0x268) ++#define MSCA_ADDR_DS1_DMAOUT_Y_ADDR (MSCA_BASE+0x26C) ++#define MSCA_ADDR_DS1_DMAOUT_Y_FIFO_STA (MSCA_BASE+0x270) ++#define MSCA_ADDR_DS1_DMAOUT_Y_LAST_ADDR (MSCA_BASE+0x274) ++#define MSCA_ADDR_DS1_DMAOUT_Y_LAST_STATS_NUM (MSCA_BASE+0x278) ++#define MSCA_ADDR_DS1_DMAOUT_Y_LAST_FIFO_STA (MSCA_BASE+0x27C) ++#define MSCA_ADDR_DS1_DMAOUT_Y_STR (MSCA_BASE+0x280) ++#define MSCA_ADDR_DS1_DMAOUT_UV_ADDR (MSCA_BASE+0x284) ++#define MSCA_ADDR_DS1_DMAOUT_UV_FIFO_STA (MSCA_BASE+0x288) ++#define MSCA_ADDR_DS1_DMAOUT_UV_LAST_ADDR (MSCA_BASE+0x28C) ++#define MSCA_ADDR_DS1_DMAOUT_UV_LAST_STATS_NUM (MSCA_BASE+0x290) ++#define MSCA_ADDR_DS1_DMAOUT_UV_LAST_FIFO_STA (MSCA_BASE+0x294) ++#define MSCA_ADDR_DS1_DMAOUT_UV_STR (MSCA_BASE+0x298) ++#define MSCA_ADDR_DS1_DMAOUT_Y_FIFO_CLR (MSCA_BASE+0x29C) ++#define MSCA_ADDR_DS1_DMAOUT_UV_FIFO_CLR (MSCA_BASE+0x2A0) ++#define MSCA_ADDR_DS1_DMAOUT_Y_LAST_FIFO_CLR (MSCA_BASE+0x2A4) ++#define MSCA_ADDR_DS1_DMAOUT_UV_LAST_FIFO_CLR (MSCA_BASE+0x2A8) ++#define MSCA_ADDR_DS1_DMAOUT_Y_ADDR_SEL (MSCA_BASE+0x2AC) ++#define MSCA_ADDR_DS1_DMAOUT_UV_ADDR_SEL (MSCA_BASE+0x2B0) ++ ++ ++//-- ds2 ++#define MSCA_ADDR_DS2_RSZ_SIZE (MSCA_BASE+0x300) ++#define MSCA_ADDR_DS2_RSZ_STEP (MSCA_BASE+0x304) ++#define MSCA_ADDR_DS2_CROP_POS (MSCA_BASE+0x328) ++#define MSCA_ADDR_DS2_CROP_SIZE (MSCA_BASE+0x32C) ++#define MSCA_ADDR_DS2_FRA_RATE_LOOP (MSCA_BASE+0x330) ++#define MSCA_ADDR_DS2_FRA_RATE_MASK (MSCA_BASE+0x334) ++#define MSCA_ADDR_DS2_MASK0_POS (MSCA_BASE+0x338) ++#define MSCA_ADDR_DS2_MASK0_SIZE (MSCA_BASE+0x33C) ++#define MSCA_ADDR_DS2_MASK0_ARGB (MSCA_BASE+0x340) ++#define MSCA_ADDR_DS2_MASK1_POS (MSCA_BASE+0x344) ++#define MSCA_ADDR_DS2_MASK1_SIZE (MSCA_BASE+0x348) ++#define MSCA_ADDR_DS2_MASK1_ARGB (MSCA_BASE+0x34C) ++#define MSCA_ADDR_DS2_MASK2_POS (MSCA_BASE+0x350) ++#define MSCA_ADDR_DS2_MASK2_SIZE (MSCA_BASE+0x354) ++#define MSCA_ADDR_DS2_MASK2_ARGB (MSCA_BASE+0x358) ++#define MSCA_ADDR_DS2_MASK3_POS (MSCA_BASE+0x35C) ++#define MSCA_ADDR_DS2_MASK3_SIZE (MSCA_BASE+0x360) ++#define MSCA_ADDR_DS2_MASK3_ARGB (MSCA_BASE+0x364) ++#define MSCA_ADDR_DS2_DMAOUT_FMT (MSCA_BASE+0x368) ++#define MSCA_ADDR_DS2_DMAOUT_Y_ADDR (MSCA_BASE+0x36C) ++#define MSCA_ADDR_DS2_DMAOUT_Y_FIFO_STA (MSCA_BASE+0x370) ++#define MSCA_ADDR_DS2_DMAOUT_Y_LAST_ADDR (MSCA_BASE+0x374) ++#define MSCA_ADDR_DS2_DMAOUT_Y_LAST_STATS_NUM (MSCA_BASE+0x378) ++#define MSCA_ADDR_DS2_DMAOUT_Y_LAST_FIFO_STA (MSCA_BASE+0x37C) ++#define MSCA_ADDR_DS2_DMAOUT_Y_STR (MSCA_BASE+0x380) ++#define MSCA_ADDR_DS2_DMAOUT_UV_ADDR (MSCA_BASE+0x384) ++#define MSCA_ADDR_DS2_DMAOUT_UV_FIFO_STA (MSCA_BASE+0x388) ++#define MSCA_ADDR_DS2_DMAOUT_UV_LAST_ADDR (MSCA_BASE+0x38C) ++#define MSCA_ADDR_DS2_DMAOUT_UV_LAST_STATS_NUM (MSCA_BASE+0x390) ++#define MSCA_ADDR_DS2_DMAOUT_UV_LAST_FIFO_STA (MSCA_BASE+0x394) ++#define MSCA_ADDR_DS2_DMAOUT_UV_STR (MSCA_BASE+0x398) ++#define MSCA_ADDR_DS2_DMAOUT_Y_FIFO_CLR (MSCA_BASE+0x39C) ++#define MSCA_ADDR_DS2_DMAOUT_UV_FIFO_CLR (MSCA_BASE+0x3A0) ++#define MSCA_ADDR_DS2_DMAOUT_Y_LAST_FIFO_CLR (MSCA_BASE+0x3A4) ++#define MSCA_ADDR_DS2_DMAOUT_UV_LAST_FIFO_CLR (MSCA_BASE+0x3A8) ++#define MSCA_ADDR_DS2_DMAOUT_Y_ADDR_SEL (MSCA_BASE+0x3AC) ++#define MSCA_ADDR_DS2_DMAOUT_UV_ADDR_SEL (MSCA_BASE+0x3B0) ++ ++//--DEBUG ++#define MSCA_ADDR_VRSZ_Y_DBG_SEL (MSCA_BASE+0x080) ++#define MSCA_ADDR_VRSZ_UV_DBG_SEL (MSCA_BASE+0x084) ++#define MSCA_ADDR_DS0_DMA_OUT_DBG0_SEL (MSCA_BASE+0x088) ++#define MSCA_ADDR_DS0_DMA_OUT_DBG1_SEL (MSCA_BASE+0x08C) ++#define MSCA_ADDR_DS0_DMA_OUT_DBG2_SEL (MSCA_BASE+0x090) ++#define MSCA_ADDR_DS1_DMA_OUT_DBG0_SEL (MSCA_BASE+0x094) ++#define MSCA_ADDR_DS1_DMA_OUT_DBG1_SEL (MSCA_BASE+0x098) ++#define MSCA_ADDR_DS1_DMA_OUT_DBG2_SEL (MSCA_BASE+0x09C) ++#define MSCA_ADDR_DS2_DMA_OUT_DBG0_SEL (MSCA_BASE+0x0A0) ++#define MSCA_ADDR_DS2_DMA_OUT_DBG1_SEL (MSCA_BASE+0x0A4) ++#define MSCA_ADDR_DS2_DMA_OUT_DBG2_SEL (MSCA_BASE+0x0A8) ++#define MSCA_ADDR_DS0_HRSZ_Y_DBG_SEL (MSCA_BASE+0x0AC) ++#define MSCA_ADDR_DS0_HRSZ_UV_DBG_SEL (MSCA_BASE+0x0B0) ++#define MSCA_ADDR_DS1_HRSZ_Y_DBG_SEL (MSCA_BASE+0x0B4) ++#define MSCA_ADDR_DS1_HRSZ_UV_DBG_SEL (MSCA_BASE+0x0B8) ++#define MSCA_ADDR_DS2_HRSZ_Y_DBG_SEL (MSCA_BASE+0x0BC) ++#define MSCA_ADDR_DS2_HRSZ_UV_DBG_SEL (MSCA_BASE+0x0C0) ++#define MSCA_ADDR_BP_BUS0_DBG_SEL (MSCA_BASE+0x0C4) ++#define MSCA_ADDR_BP_BUS1_DBG_SEL (MSCA_BASE+0x0C8) ++#define MSCA_ADDR_BP_BUS2_DBG_SEL (MSCA_BASE+0x0CC) ++#define MSCA_ADDR_STP_DBG_SEL (MSCA_BASE+0x0D0) ++ ++#define MSCA_ADDR_DS0_CRC_Y_SEL (MSCA_BASE+0x0E0) ++#define MSCA_ADDR_DS0_CRC_UV_SEL (MSCA_BASE+0x0E4) ++#define MSCA_ADDR_DS1_CRC_Y_SEL (MSCA_BASE+0x0E8) ++#define MSCA_ADDR_DS1_CRC_UV_SEL (MSCA_BASE+0x0EC) ++#define MSCA_ADDR_DS2_CRC_Y_SEL (MSCA_BASE+0x0F0) ++#define MSCA_ADDR_DS2_CRC_UV_SEL (MSCA_BASE+0x0F4) ++ ++#define CHx_RSZ_OSIZE(n) (MSCA_BASE+(0x0100*(n))+0x100) ++#define CHx_RSZ_STEP(n) (MSCA_BASE+(0x0100*(n))+0x104) ++ ++#define CHx_CROP_OPOS(n) (MSCA_BASE+(0x0100*(n))+0x128) ++#define CHx_CROP_OSIZE(n) (MSCA_BASE+(0x0100*(n))+0x12c) ++#define CHx_FRA_CTRL_LOOP(n) (MSCA_BASE+(0x0100*(n))+0x130) ++#define CHx_FRA_CTRL_MASK(n) (MSCA_BASE+(0x0100*(n))+0x134) ++#define CHx_MS0_POS(n) (MSCA_BASE+(0x0100*(n))+0x138) ++#define CHx_MS0_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x13c) ++#define CHx_MS0_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x140) ++#define CHx_MS1_POS(n) (MSCA_BASE+(0x0100*(n))+0x144) ++#define CHx_MS1_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x148) ++#define CHx_MS1_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x14c) ++#define CHx_MS2_POS(n) (MSCA_BASE+(0x0100*(n))+0x150) ++#define CHx_MS2_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x154) ++#define CHx_MS2_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x158) ++#define CHx_MS3_POS(n) (MSCA_BASE+(0x0100*(n))+0x15c) ++#define CHx_MS3_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x160) ++#define CHx_MS3_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x164) ++#define CHx_OUT_FMT(n) (MSCA_BASE+(0x0100*(n))+0x168) ++#define CHx_DMAOUT_Y_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x16c) ++#define CHx_Y_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x170) ++#define CHx_DMAOUT_Y_LAST_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x174) ++#define CHx_DMAOUT_Y_LAST_STATS_NUM(n) (MSCA_BASE+(0x0100*(n))+0x178) ++#define CHx_Y_LAST_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x17c) ++#define CHx_DMAOUT_Y_STRI(n) (MSCA_BASE+(0x0100*(n))+0x180) ++#define CHx_DMAOUT_UV_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x184) ++#define CHx_UV_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x188) ++#define CHx_DMAOUT_UV_LAST_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x18c) ++#define CHx_DMAOUT_UV_LAST_STATS_NUM(n) (MSCA_BASE+(0x0100*(n))+0x190) ++#define CHx_UV_LAST_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x194) ++#define CHx_DMAOUT_UV_STRI(n) (MSCA_BASE+(0x0100*(n))+0x198) ++#define CHx_DMAOUT_Y_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x19c) ++#define CHx_DMAOUT_UV_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a0) ++#define CHx_DMAOUT_Y_LAST_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a4) ++#define CHx_DMAOUT_UV_LAST_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a8) ++#define CHx_DMAOUT_Y_ADDR_SEL(n) (MSCA_BASE+(0x0100*(n))+0x1ac) ++#define CHx_DMAOUT_UV_ADDR_SEL(n) (MSCA_BASE+(0x0100*(n))+0x1b0) ++ ++#define TIZIANO_ISP_IRQ_ISP_FRD (0) ++#define TIZIANO_ISP_IRQ_STOP (4) ++#define TIZIANO_ISP_IRQ_CTM_STATIC (8) ++#define TIZIANO_ISP_IRQ_AE_STATIC (16) ++#define TIZIANO_ISP_IRQ_AE_HIST (17) ++#define TIZIANO_ISP_IRQ_AWB_STATIC (18) ++#define TIZIANO_ISP_IRQ_AF_STATIC (19) ++#define TIZIANO_ISP_IRQ_ADR_STATIC (20) ++#define TIZIANO_ISP_IRQ_DEFOG_STATIC (21) ++#define TIZIANO_ISP_IRQ_DMAOUT_FRD (23) ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-sensor.h b/module_drivers/drivers/media/platform/ingenic-isp/isp-sensor.h +new file mode 100644 +index 000000000..a35fb51c4 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-sensor.h +@@ -0,0 +1,80 @@ ++#ifndef __ISP_SENSOR_H__ ++#define __ISP_SENSOR_H__ ++ ++#define V4L2_CID_USER_ANALOG_GAIN_SHORT (V4L2_CID_USER_BASE + 0x1090) ++#define V4L2_CID_USER_EXPOSURE_SHORT (V4L2_CID_USER_BASE + 0x1091) ++ ++enum mipi_sensor_data_type_value { ++ YUV422_8BIT = 0x1e, ++ RAW8 = 0x2a, ++ RAW10 = 0x2b, ++ RAW12 = 0x2c, ++}; ++ ++enum tx_sensor_frm_mode { ++ TX_SENSOR_DEFAULT_FRAME_MODE = 0, ++ TX_SENSOR_WDR_2_FRAME_MODE, ++ TX_SENSOR_WDR_3_FRAME_MODE, ++ TX_SENSOR_WDR_4_FRAME_MODE, ++}; ++ ++enum tx_sensor_mode { ++ TX_SENSOR_DEFAULT_MODE = 0, ++ TX_SENSOR_NOT_VC_MODE, ++ TX_SENSOR_VC_MODE, ++}; ++ ++enum tx_sensor_csi_fmt { ++ TX_SENSOR_RAW8 = 0, ++ TX_SENSOR_RAW10, ++ TX_SENSOR_RAW12, ++}; ++ ++typedef enum { ++ SENSOR_MIPI_OTHER_MODE, ++ SENSOR_MIPI_SONY_MODE, ++}sensor_mipi_mode; ++ ++struct mipi_cfg { ++ unsigned int clk; ++ unsigned int twidth; ++ unsigned int theight; ++ sensor_mipi_mode mipi_mode; ++ unsigned int hcrop_diff_en; ++ unsigned int mipi_vcomp_en; ++ unsigned int mipi_hcomp_en; ++ unsigned short mipi_crop_start0x; ++ unsigned short mipi_crop_start0y; ++ unsigned short mipi_crop_start1x; ++ unsigned short mipi_crop_start1y; ++ unsigned short mipi_crop_start2x; ++ unsigned short mipi_crop_start2y; ++ unsigned short mipi_crop_start3x; ++ unsigned short mipi_crop_start3y; ++ unsigned int line_sync_mode; ++ unsigned int work_start_flag; ++ unsigned int data_type_en; ++ enum mipi_sensor_data_type_value data_type_value; ++ unsigned int del_start; ++ unsigned int sensor_fid_mode; ++ enum tx_sensor_frm_mode sensor_frame_mode; ++ enum tx_sensor_mode sensor_mode; ++ enum tx_sensor_csi_fmt sensor_csi_fmt; ++}; ++ ++struct dvp_cfg { ++ ++}; ++ ++struct sensor_info { ++ unsigned int fps; ++ unsigned int total_width; ++ unsigned int total_height; ++ int wdr_en; ++ union { ++ struct mipi_cfg mipi_cfg; ++ struct dvp_cfg dvp_cfg; ++ }; ++}; ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-video-mplane.c b/module_drivers/drivers/media/platform/ingenic-isp/isp-video-mplane.c +new file mode 100644 +index 000000000..52dd774b5 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-video-mplane.c +@@ -0,0 +1,729 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++#define ISP_VIDEO_DRIVER_NAME "ispvideo" ++ ++ ++ ++static struct v4l2_subdev * ++isp_video_remote_subdev(struct isp_video_device *ispvideo, u32 *pad) ++{ ++ struct media_pad *remote; ++ ++ printk("------%s, %d\n", __func__, __LINE__); ++ ++ remote = media_entity_remote_pad(&ispvideo->pad); ++ ++ if (remote == NULL || ++ media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) ++ return NULL; ++ ++ if (pad) ++ *pad = remote->index; ++ ++ return media_entity_to_v4l2_subdev(remote->entity); ++} ++ ++ ++/* ----------------------------------------------------------------------------- ++ * V4L2 ioctls ++ */ ++ ++static int ++isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver)); ++ strlcpy(cap->card, ispvideo->video.name, sizeof(cap->card)); ++ strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); ++ ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; ++ ++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING; ++ ++ return 0; ++} ++ ++static int isp_video_enum_fmt_vid_cap_mplane(struct file *file, void *fh, ++ struct v4l2_fmtdesc *f) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ const struct isp_video_format *fmt = NULL; ++ ++ fmt = ispvideo->ops->find_format(NULL, NULL, f->index); ++ if(fmt == NULL) { ++ return -EINVAL; ++ } ++ strlcpy(f->description, fmt->name, sizeof(f->description)); ++ f->pixelformat = fmt->fourcc; ++ ++ return 0; ++} ++static int ++isp_video_g_fmt_vid_cap_mplane(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ printk("------%s, %d\n", __func__, __LINE__); ++ ++ //mutex_lock(&ispvideo->mutex); ++ if(ctx->format.type == 0) { ++ dev_warn(ispvideo->dev, "Format not setted before calling g_fmt\n"); ++ } else { ++ *format = ctx->format; ++ } ++ //mutex_unlock(&ispvideo->mutex); ++ ++ return 0; ++} ++ ++static int ++__isp_video_try_format(struct isp_video_device *ispvideo, struct v4l2_pix_format_mplane *pix_mp, ++ const struct isp_video_format **ofmt) ++{ ++ struct v4l2_plane_pix_format *plane_fmt; ++ struct isp_video_format *fmt = NULL; ++ ++ fmt = ispvideo->ops->find_format(&pix_mp->pixelformat, NULL, -1); ++ if(fmt == NULL) { ++ dev_err(ispvideo->dev, "Cannot find appropriate format for pix->pixelformat:[%x]\n", pix_mp->pixelformat); ++ return -EINVAL; ++ } ++ ++ pix_mp->colorspace = fmt->colorspace; ++ pix_mp->field = V4L2_FIELD_NONE; ++ pix_mp->pixelformat = fmt->fourcc; ++ pix_mp->num_planes = fmt->num_planes; ++ ++ plane_fmt = &pix_mp->plane_fmt[0]; ++ plane_fmt->bytesperline = pix_mp->width * fmt->depth[0] / 8; ++ plane_fmt->sizeimage = plane_fmt->bytesperline * pix_mp->height; ++ ++ plane_fmt = &pix_mp->plane_fmt[1]; ++ plane_fmt->bytesperline = pix_mp->width * fmt->depth[1] / 8; ++ plane_fmt->sizeimage = plane_fmt->bytesperline * pix_mp->height; ++ ++ if(ofmt) { ++ *ofmt = fmt; ++ } ++ ++ /*TODO, bound width and height!*/ ++ printk("=======%s,%d, pixelformat: %x, widht: %d, height: %d, num_planes: %d\n", __func__, __LINE__, pix_mp->pixelformat, pix_mp->width, pix_mp->height, pix_mp->num_planes); ++ ++ return 0; ++} ++ ++static void to_v4l2_mbus_framefmt(struct isp_video_device *ispvideo, struct v4l2_format *format, struct v4l2_mbus_framefmt *fmt) ++{ ++ struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp; ++ struct isp_video_format *ispfmt = NULL; ++ ++ ispfmt = ispvideo->ops->find_format(&pix_mp->pixelformat, NULL, -1); ++ ++ fmt->width = pix_mp->width; ++ fmt->height = pix_mp->height; ++ fmt->code = ispfmt->mbus_code; ++ fmt->field = pix_mp->field; ++ fmt->colorspace = pix_mp->colorspace; ++ fmt->ycbcr_enc = pix_mp->ycbcr_enc; ++ fmt->quantization = pix_mp->quantization; ++ fmt->xfer_func = pix_mp->xfer_func; ++} ++ ++static int ++isp_video_s_fmt_vid_cap_mplane(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct v4l2_subdev *sd = NULL; ++ struct v4l2_subdev_format subdev_fmt; ++ unsigned int pad = 0; ++ int ret = 0; ++ ++ if(vb2_is_busy(&ctx->queue)) { ++ return -EBUSY; ++ } ++ ++ ret = __isp_video_try_format(ispvideo, &format->fmt.pix_mp, NULL); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to set format cap!\n"); ++ return -EINVAL; ++ } ++ ++ sd = isp_video_remote_subdev(ispvideo, &pad); ++ if(sd == NULL) { ++ return -EINVAL; ++ } ++ ++ ctx->format = *format; ++ ++ to_v4l2_mbus_framefmt(ispvideo, format, &subdev_fmt.format); ++ ++ subdev_fmt.pad = pad; ++ subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &subdev_fmt); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to set subdev format\n"); ++ return -EINVAL; ++ } ++ ++ //printk("-%s, %d--ctx: %x--queue: %x, queue->lock: %x\n", __func__, __LINE__, ctx, &ctx->queue, ctx->queue.lock); ++ return 0; ++} ++ ++static int ++isp_video_try_format_cap_mplane(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ int ret = 0; ++ ++ printk("-----------%s, %d------------\n", __func__, __LINE__); ++ ++ ret = __isp_video_try_format(ispvideo, &format->fmt.pix_mp, NULL); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Try format cap mplane error!\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int ++isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) ++{ ++ printk("-----------%s, %d------------\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ++isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) ++{ ++ printk("-----------%s, %d------------\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ++isp_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop) ++{ ++ printk("-----------%s, %d------------\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int isp_video_enum_input(struct file *file, void *priv, ++ struct v4l2_input *inp) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ if (inp->index != 0) ++ return -EINVAL; ++ ++ /* default is camera */ ++ inp->type = V4L2_INPUT_TYPE_CAMERA; ++ inp->std = ispvideo->video.tvnorms; ++ strcpy(inp->name, "Camera"); ++ ++ return 0; ++} ++ ++static int isp_video_g_input(struct file *file, void *priv, unsigned int *i) ++{ ++ *i = 0; ++ ++ return 0; ++} ++ ++static int isp_video_s_input(struct file *file, void *priv, unsigned int i) ++{ ++ if (i > 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { ++ .vidioc_querycap = isp_video_querycap, ++ .vidioc_enum_fmt_vid_cap_mplane = isp_video_enum_fmt_vid_cap_mplane, ++ .vidioc_g_fmt_vid_cap_mplane = isp_video_g_fmt_vid_cap_mplane, ++ .vidioc_s_fmt_vid_cap_mplane = isp_video_s_fmt_vid_cap_mplane, ++ .vidioc_try_fmt_vid_cap_mplane = isp_video_try_format_cap_mplane, ++ .vidioc_cropcap = isp_video_cropcap, ++ .vidioc_g_crop = isp_video_get_crop, ++ .vidioc_s_crop = isp_video_set_crop, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ .vidioc_enum_input = isp_video_enum_input, ++ .vidioc_g_input = isp_video_g_input, ++ .vidioc_s_input = isp_video_s_input, ++}; ++ ++/* ----------------------------------------------------------------------------- ++ * Video queue operations ++ */ ++ ++static int isp_video_queue_setup(struct vb2_queue *queue, ++ const void *parg, ++ unsigned int *count, unsigned int *num_planes, ++ unsigned int sizes[], void *alloc_ctxs[]) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(queue); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct v4l2_format *format = &ctx->format; ++ int i = 0; ++ ++ if(*num_planes) { ++ for(i = 0; i < *num_planes; i++) { ++ if(sizes[i] < format->fmt.pix_mp.plane_fmt[i].sizeimage) { ++ return -EINVAL; ++ } ++ } ++ } else { ++ *num_planes = format->fmt.pix_mp.num_planes; ++ for(i = 0; i < *num_planes; i++) { ++ sizes[i] = format->fmt.pix_mp.plane_fmt[i].sizeimage; ++ alloc_ctxs[i] = ispvideo->alloc_ctx; ++ } ++ } ++ ++ /*MAX_BUFFER_NUMS:*/ ++ if(*count >= 3) { ++ *count = 3; ++ } ++ ++ return 0; ++} ++ ++static int isp_video_buffer_prepare(struct vb2_buffer *buf) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(buf->vb2_queue); ++ struct v4l2_format *format = &ctx->format; ++ struct v4l2_pix_format_mplane *pix_mp = &format->fmt.pix_mp; ++ int i; ++ ++ for(i = 0; i < buf->num_planes; i++) { ++ vb2_set_plane_payload(buf, i, pix_mp->plane_fmt[i].sizeimage); ++ } ++ ++ return 0; ++} ++ ++static void isp_video_buffer_queue(struct vb2_buffer *buf) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buf); ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(buf->vb2_queue); ++ struct isp_video_buffer *isp_buffer = to_isp_buffer(vbuf); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ int ret = 0; ++ ++ ret = ispvideo->ops->qbuf(ispvideo, isp_buffer); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "failed to queue buf!\n"); ++ } ++} ++ ++static int isp_video_subdev_init(struct isp_video_device *ispvideo) ++{ ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ int ret = 0; ++ ++ /*subdevs reset.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || ++ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, core, init, 1); ++ if(ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_err(ispvideo->dev, "failed to reset subdev[%s]\n", entity->name); ++ } else { ++ ret = 0; ++ } ++ } ++ ++ return ret; ++} ++ ++static int isp_video_subdev_reset(struct isp_video_device *ispvideo) ++{ ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ int ret = 0; ++ ++ /*subdevs reset.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || ++ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, core, reset, 1); ++ if(ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_err(ispvideo->dev, "failed to reset subdev[%s]\n", entity->name); ++ } else { ++ ret = 0; ++ } ++ } ++ ++ return ret; ++ ++} ++ ++static int isp_video_subdev_stream(struct isp_video_device *ispvideo, int enable) ++{ ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ int ret = 0; ++ ++ /*subdevs stream on.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || ++ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, video, s_stream, enable); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "unable to start stream[%s]\n", entity->name); ++ } ++ ++ } ++ ++ return ret; ++} ++ ++static int isp_video_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct isp_pipeline *pipe = &ispvideo->pipe; ++ int ret = 0; ++ printk("-----********* -%s, %d\n", __func__, __LINE__); ++ ++ mutex_lock(&ispvideo->stream_lock); ++ ret = media_entity_pipeline_start(entity, &pipe->pipeline); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to start pipeline\n"); ++ goto err_pipeline_start; ++ } ++ ++ ret = isp_video_subdev_reset(ispvideo); ++ ++ ++ ret = isp_video_subdev_init(ispvideo); ++ ++ ++ ret = isp_video_subdev_stream(ispvideo, 1); ++ ++ if(ret < 0) { ++ goto err_start_stream; ++ } ++ ++ mutex_unlock(&ispvideo->stream_lock); ++ ++ return 0; ++ ++err_start_stream: ++ media_entity_pipeline_stop(entity); ++err_pipeline_start: ++ mutex_unlock(&ispvideo->stream_lock); ++ return ret; ++} ++static void isp_video_stop_streaming(struct vb2_queue *q) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct media_entity *entity = &ispvideo->video.entity; ++ //struct isp_pipeline *pipe = &ispvideo->pipe; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ unsigned int is_streaming = 0; ++ int ret = 0; ++ ++ mutex_lock(&ispvideo->stream_lock); ++ ++ is_streaming = vb2_is_streaming(q); ++ ++ if(!is_streaming) ++ goto done; ++ ++ /*subdevs stream off.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || ++ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, video, s_stream, 0); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "unable to start stream[%s]\n", entity->name); ++ break; ++ } ++ ++ } ++ media_entity_pipeline_stop(&ispvideo->video.entity); ++ ++done: ++ mutex_unlock(&ispvideo->stream_lock); ++} ++ ++static const struct vb2_ops isp_video_queue_ops = { ++ .queue_setup = isp_video_queue_setup, ++ .buf_prepare = isp_video_buffer_prepare, ++ .buf_queue = isp_video_buffer_queue, ++ .start_streaming = isp_video_start_streaming, ++ .stop_streaming = isp_video_stop_streaming, ++}; ++ ++ ++static int isp_video_open(struct file *file) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct video_device *vdev = &ispvideo->video; ++ struct isp_video_ctx *ctx = NULL; ++ struct vb2_queue *queue = NULL; ++ int ret = 0; ++ printk("-----name: %s %s, %d \n", ispvideo->name, __func__, __LINE__); ++ mutex_lock(&ispvideo->mutex); ++ if(ispvideo->queue != NULL) { ++ mutex_unlock(&ispvideo->mutex); ++ return -EBUSY; ++ } ++ ++ ctx = kzalloc(sizeof(struct isp_video_ctx), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(ctx)) { ++ dev_err(ispvideo->ispcam->dev, "Failed to alloc ctx for isp_video_ctx\n"); ++ ret = -ENOMEM; ++ goto err_ctx_alloc; ++ } ++ ++ v4l2_fh_init(&ctx->fh, &ispvideo->video); ++ v4l2_fh_add(&ctx->fh); ++ ++ queue = &ctx->queue; ++ queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ queue->io_modes = VB2_MMAP; ++ queue->drv_priv = ctx; ++ queue->ops = &isp_video_queue_ops; ++ queue->mem_ops = &vb2_dma_contig_memops; ++ queue->buf_struct_size = sizeof(struct isp_video_buffer); ++ queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ queue->lock = &ispvideo->queue_lock; ++ ++ ret = vb2_queue_init(&ctx->queue); ++ if(ret < 0) { ++ goto err_vb2_queue_init; ++ } ++ ++ ctx->ispvideo = ispvideo; ++ vdev->queue = ispvideo->queue = queue; ++ ++ file->private_data = &ctx->fh; ++ ++ mutex_unlock(&ispvideo->mutex); ++ ++ return 0; ++err_vb2_queue_init: ++ v4l2_fh_del(&ctx->fh); ++ kfree(ctx); ++err_ctx_alloc: ++ mutex_unlock(&ispvideo->mutex); ++ return ret; ++} ++static int isp_video_release(struct file *file) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct video_device *vdev = &ispvideo->video; ++ struct v4l2_fh *fh = file->private_data; ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ ++ printk("-----name: %s %s, %d \n", ispvideo->name, __func__, __LINE__); ++ /*lock*/ ++ ++ mutex_lock(&ispvideo->mutex); ++ ++ vb2_queue_release(&ctx->queue); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ ++ kfree(ctx); ++ file->private_data = NULL; ++ vdev->queue = ispvideo->queue = NULL; ++ ++ mutex_unlock(&ispvideo->mutex); ++ ++ /*unlock*/ ++ ++ return 0; ++} ++ ++#if 0 ++static unsigned int isp_video_poll(struct file *file, poll_table *wait) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct v4l2_fh *fh = file->private_data; ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ int ret = 0; ++ printk("-----name: %s %s, %d \n", ispvideo->name, __func__, __LINE__); ++ ++ mutex_lock(&ispvideo->queue_lock); ++ ret = vb2_poll(&ctx->queue, file, wait); ++ mutex_unlock(&ispvideo->queue_lock); ++ ++ return ret; ++} ++ ++static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct v4l2_fh *fh = file->private_data; ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ printk("-----name: %s %s, %d \n", ispvideo->name, __func__, __LINE__); ++ ++ return vb2_mmap(&ctx->queue, vma); ++} ++#endif ++ ++static struct v4l2_file_operations isp_video_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = video_ioctl2, ++ .open = isp_video_open, ++ .release = isp_video_release, ++ .poll = vb2_fop_poll, /*isp_video_poll,*/ ++ .mmap = vb2_fop_mmap, /*isp_video_mmap,*/ ++}; ++ ++ ++int isp_video_init(struct isp_video_device *ispvideo, char *name, const struct isp_video_ops *video_ops) ++{ ++ int ret = 0; ++ struct video_device *video = &ispvideo->video; ++ ++ ++ /*创建buffer分é…器*/ ++ ispvideo->alloc_ctx = ingenic_vb2_dma_contig_init_ctx(ispvideo->ispcam->dev); ++ if(IS_ERR(ispvideo)) { ++ return -ENOMEM; ++ } ++ ++ /*åˆå§‹åŒ–一个sink pad*/ ++ ispvideo->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; ++ ret = media_entity_init(&video->entity, 1, &ispvideo->pad, 0); ++ if(ret < 0) { ++ /*TODO: error case*/ ++ } ++ ++ mutex_init(&ispvideo->queue_lock); ++ mutex_init(&ispvideo->mutex); ++ mutex_init(&ispvideo->stream_lock); ++ ++ snprintf(video->name, sizeof(video->name), "isp-%s", name); ++ video->fops = &isp_video_fops; ++ video->ioctl_ops = &isp_video_ioctl_ops; ++ video->release = video_device_release_empty; ++ ++ ispvideo->name = video->name; ++ ispvideo->ops = video_ops; ++ ispvideo->dev = ispvideo->ispcam->dev; ++ ++ video_set_drvdata(&ispvideo->video, ispvideo); ++ ++ return 0; ++ ++} ++ ++int isp_video_cleanup(struct isp_video_device *ispvideo) ++{ ++ ++ return 0; ++} ++ ++int isp_video_register(struct isp_video_device *ispvideo, struct v4l2_device *v4l2_dev) ++{ ++ struct video_device *video = &ispvideo->video; ++ int ret = 0; ++ ++ video->v4l2_dev = v4l2_dev; ++ ++ ret = video_register_device(video, VFL_TYPE_GRABBER, -1); ++ if(ret < 0) { ++ /*TODO: error case*/ ++ } ++ ++ dev_info(ispvideo->dev, "register video device %s @ /dev/video%d ok\n", video->name, video->index); ++ ++ return ret; ++} ++int isp_video_unregister(struct isp_video_device *ispvideo) ++{ ++ ++ return 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp-video.c b/module_drivers/drivers/media/platform/ingenic-isp/isp-video.c +new file mode 100644 +index 000000000..5ef05bd74 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp-video.c +@@ -0,0 +1,890 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++#define ISP_VIDEO_DRIVER_NAME "ispvideo" ++ ++int isp_max_buffer_num = 3; ++module_param(isp_max_buffer_num, int, 0644); ++MODULE_PARM_DESC(isp_max_buffer_num, "isp max buffer numer"); ++ ++int isp_force_img_depth = 12; ++module_param(isp_force_img_depth, int, 0644); ++MODULE_PARM_DESC(isp_force_img_depth, "force fmt depth, usefull when need mem more than real fmt."); ++ ++static struct v4l2_subdev * ++isp_video_remote_subdev(struct isp_video_device *ispvideo, u32 *pad) ++{ ++ struct media_pad *remote; ++ ++ remote = media_entity_remote_pad(&ispvideo->pad); ++ ++ if (remote == NULL || !is_media_entity_v4l2_subdev(remote->entity)) ++ return NULL; ++ ++ if (pad) ++ *pad = remote->index; ++ ++ return media_entity_to_v4l2_subdev(remote->entity); ++} ++ ++ ++/* ----------------------------------------------------------------------------- ++ * V4L2 ioctls ++ */ ++ ++static int ++isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver)); ++ strlcpy(cap->card, ispvideo->video.name, sizeof(cap->card)); ++ strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); ++ ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; ++ ++ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ ++ return 0; ++} ++ ++static int isp_video_enum_fmt_vid_cap(struct file *file, void *fh, ++ struct v4l2_fmtdesc *f) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ const struct isp_video_format *fmt = NULL; ++ ++ fmt = ispvideo->ops->find_format(NULL, NULL, f->index); ++ if(fmt == NULL) { ++ return -EINVAL; ++ } ++ strlcpy(f->description, fmt->name, sizeof(f->description)); ++ f->pixelformat = fmt->fourcc; ++ ++ return 0; ++} ++static int ++isp_video_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ //mutex_lock(&ispvideo->mutex); ++ if(ctx->format.type == 0) { ++ dev_warn(ispvideo->dev, "Format not setted before calling g_fmt\n"); ++ } else { ++ *format = ctx->format; ++ } ++ //mutex_unlock(&ispvideo->mutex); ++ ++ return 0; ++} ++ ++static int ++__isp_video_try_format(struct isp_video_ctx *ctx, struct v4l2_pix_format *pix, ++ const struct isp_video_format **ofmt) ++{ ++ struct isp_video_format *fmt = NULL; ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ unsigned int depth = 0; ++ unsigned int use_depth = 0; ++ int i; ++ ++ fmt = ispvideo->ops->find_format(&pix->pixelformat, NULL, -1); ++ if(fmt == NULL) { ++ dev_err(ispvideo->dev, "Cannot find appropriate format for pix->pixelformat:[%x]\n", pix->pixelformat); ++ return -EINVAL; ++ } ++ ++ for(i = 0; i < fmt->num_planes; i++) { ++ depth += fmt->depth[i]; ++ } ++ ++ pix->colorspace = fmt->colorspace; ++ pix->field = V4L2_FIELD_NONE; ++ pix->pixelformat = fmt->fourcc; ++ pix->bytesperline = pix->width * depth / 8; ++ //pix->sizeimage = pix->bytesperline * pix->height; ++ ++ use_depth = isp_force_img_depth > depth ? isp_force_img_depth : depth; ++ pix->sizeimage = pix->width * use_depth / 8 * pix->height; ++ ++ ctx->uv_offset = pix->width * fmt->depth[0] * pix->height / 8; ++ ctx->payload_size = pix->bytesperline * pix->height; ++ ++ if(ofmt) { ++ *ofmt = fmt; ++ } ++ ++ /*TODO, bound width and height!*/ ++ //printk("=======%s,%d, pixelformat: %x, widht: %d, height: %d, num_planes: %d, uv_offset: %d\n", __func__, __LINE__, pix->pixelformat, pix->width, pix->height, fmt->num_planes, ctx->uv_offset); ++ ++ return 0; ++} ++ ++static void to_v4l2_mbus_framefmt(struct isp_video_device *ispvideo, struct v4l2_format *format, struct v4l2_mbus_framefmt *fmt) ++{ ++ struct v4l2_pix_format *pix = &format->fmt.pix; ++ struct isp_video_format *ispfmt = NULL; ++ ++ ispfmt = ispvideo->ops->find_format(&pix->pixelformat, NULL, -1); ++ ++ fmt->width = pix->width; ++ fmt->height = pix->height; ++ fmt->code = ispfmt->mbus_code; ++ fmt->field = pix->field; ++ fmt->colorspace = pix->colorspace; ++ fmt->ycbcr_enc = pix->ycbcr_enc; ++ fmt->quantization = pix->quantization; ++ fmt->xfer_func = pix->xfer_func; ++} ++ ++static int ++isp_video_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct v4l2_subdev *sd = NULL; ++ struct v4l2_subdev_format subdev_fmt; ++ unsigned int pad = 0; ++ int ret = 0; ++ ++ ++ if(vb2_is_busy(&ctx->queue)) { ++ return -EBUSY; ++ } ++ ++ ret = __isp_video_try_format(ctx, &format->fmt.pix, NULL); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to set format cap!\n"); ++ return -EINVAL; ++ } ++ ++ sd = isp_video_remote_subdev(ispvideo, &pad); ++ if(sd == NULL) { ++ return -EINVAL; ++ } ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ++ ctx->format = *format; ++ ++ to_v4l2_mbus_framefmt(ispvideo, format, &subdev_fmt.format); ++ ++ subdev_fmt.pad = pad; ++ subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ++ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &subdev_fmt); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to set subdev format\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++isp_video_try_format_cap(struct file *file, void *fh, struct v4l2_format *format) ++{ ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ int ret = 0; ++ ++ ret = __isp_video_try_format(ctx, &format->fmt.pix, NULL); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Try format cap error!\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int isp_video_pixelaspect(struct file *file, void *fh, int buf_type, struct v4l2_fract *aspect) ++{ ++ printk("-----------%s, %d------------\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int ++isp_video_get_selection(struct file *file, void *fh, struct v4l2_selection *s) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct v4l2_subdev *sd = NULL; ++ struct v4l2_subdev_selection sel = {0}; ++ int ret = 0; ++ int pad = 0; ++ ++ sd = isp_video_remote_subdev(ispvideo, &pad); ++ sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ sel.pad = pad; ++ sel.target = s->target; ++ ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sel); ++ memcpy(&s->r, &sel.r, sizeof(struct v4l2_rect)); ++ ++ return ret; ++} ++ ++static int ++isp_video_set_selection(struct file *file, void *fh, struct v4l2_selection *s) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ struct v4l2_format *format = &ctx->format; ++ struct v4l2_subdev *sd = NULL; ++ struct v4l2_subdev_selection sel; ++ int ret = 0; ++ int pad = 0; ++ ++ sd = isp_video_remote_subdev(ispvideo, &pad); ++ sel.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ sel.pad = pad; ++ sel.flags = s->flags; ++ sel.target = s->target; ++ memcpy(&sel.r, &s->r, sizeof(struct v4l2_rect)); ++ ret = v4l2_subdev_call(sd, pad, set_selection, NULL, &sel); ++ if(ret) ++ return ret; ++ ++ format->fmt.pix.width = sel.r.width; ++ format->fmt.pix.height = sel.r.height; ++ ret = __isp_video_try_format(ctx, &format->fmt.pix, NULL); ++ ++ return ret; ++} ++ ++static int isp_video_enum_input(struct file *file, void *priv, ++ struct v4l2_input *inp) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ ++ if (inp->index != 0) ++ return -EINVAL; ++ ++ /* default is camera */ ++ inp->type = V4L2_INPUT_TYPE_CAMERA; ++ inp->std = ispvideo->video.tvnorms; ++ strcpy(inp->name, "Camera"); ++ ++ return 0; ++} ++ ++static int isp_video_g_input(struct file *file, void *priv, unsigned int *i) ++{ ++ *i = 0; ++ ++ return 0; ++} ++ ++static int isp_video_s_input(struct file *file, void *priv, unsigned int i) ++{ ++ if (i > 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++int isp_video_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct mscaler_device *mscaler= ispcam->mscaler; ++ struct v4l2_subdev_frame_size_enum fse; ++ int ret = 0; ++ ++ fse.code = fsize->pixel_format; ++ fse.index = fsize->index; ++ ++ ret = v4l2_subdev_call(&mscaler->sd, pad, enum_frame_size, NULL, &fse); ++ if (ret < 0) ++ return ret; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; ++ fsize->discrete.width = fse.min_width; ++ fsize->discrete.height = fse.min_height; ++ return 0; ++} ++ ++int isp_video_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a){ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct isp_async_device *isd = &ispcam->isd[0]; ++ int ret = 0; ++ struct v4l2_subdev_frame_interval interval; ++ ++ interval.pad = 0; ++ ret = v4l2_subdev_call(isd->sd, video, g_frame_interval, &interval); ++ if(ret < 0) { ++ return ret; ++ } ++ ++ a->parm.capture.timeperframe.numerator = interval.interval.numerator; ++ a->parm.capture.timeperframe.denominator = interval.interval.denominator; ++ ++ return 0; ++} ++ ++extern int isp_video_s_ctrl(struct file *file, void *fh, struct v4l2_control *a); ++extern int isp_video_g_ctrl(struct file *file, void *fh, struct v4l2_control *a); ++ ++extern int bypass_video_s_ctrl(struct file *file, void *fh, struct v4l2_control *a); ++extern int bypass_video_g_ctrl(struct file *file, void *fh, struct v4l2_control *a); ++ ++static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { ++ .vidioc_querycap = isp_video_querycap, ++ .vidioc_enum_fmt_vid_cap = isp_video_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = isp_video_g_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = isp_video_s_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = isp_video_try_format_cap, ++ .vidioc_g_pixelaspect = isp_video_pixelaspect, ++ .vidioc_g_selection = isp_video_get_selection, ++ .vidioc_s_selection = isp_video_set_selection, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ .vidioc_enum_input = isp_video_enum_input, ++ .vidioc_g_input = isp_video_g_input, ++ .vidioc_s_input = isp_video_s_input, ++ .vidioc_enum_framesizes = isp_video_enum_framesizes, ++ .vidioc_g_parm = isp_video_g_parm, ++ .vidioc_s_ctrl = isp_video_s_ctrl, ++ .vidioc_g_ctrl = isp_video_g_ctrl, ++}; ++ ++static const struct v4l2_ioctl_ops bypass_video_ioctl_ops = { ++ .vidioc_querycap = isp_video_querycap, /**/ ++ .vidioc_enum_fmt_vid_cap = isp_video_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = isp_video_g_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = isp_video_s_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = isp_video_try_format_cap, ++ .vidioc_g_pixelaspect = isp_video_pixelaspect, ++ .vidioc_reqbufs = vb2_ioctl_reqbufs, ++ .vidioc_querybuf = vb2_ioctl_querybuf, ++ .vidioc_qbuf = vb2_ioctl_qbuf, ++ .vidioc_dqbuf = vb2_ioctl_dqbuf, ++ .vidioc_expbuf = vb2_ioctl_expbuf, ++ .vidioc_streamon = vb2_ioctl_streamon, ++ .vidioc_streamoff = vb2_ioctl_streamoff, ++ .vidioc_enum_input = isp_video_enum_input, /**/ ++ .vidioc_g_input = isp_video_g_input, ++ .vidioc_s_input = isp_video_s_input, ++ .vidioc_enum_framesizes = isp_video_enum_framesizes, ++ .vidioc_g_parm = isp_video_g_parm, /**/ ++ .vidioc_s_ctrl = bypass_video_s_ctrl, ++ .vidioc_g_ctrl = bypass_video_g_ctrl, ++}; ++ ++/* ----------------------------------------------------------------------------- ++ * Video queue operations ++ */ ++ ++static int isp_video_queue_setup(struct vb2_queue *queue, ++ unsigned int *count, unsigned int *num_planes, ++ unsigned int sizes[], struct device *alloc_ctxs[]) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(queue); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct v4l2_format *format = &ctx->format; ++ ++ *num_planes = 1; ++ ++ sizes[0] = format->fmt.pix.sizeimage; ++ if(sizes[0] == 0) { ++ dev_err(ispvideo->dev, "queue setup 0 sizeimage\n"); ++ return -EINVAL; ++ } ++ ++ alloc_ctxs[0] = ispvideo->ispcam->dev; ++ ++ /*MAX_BUFFER_NUMS:*/ ++ if(ispvideo->bypass) ++ isp_max_buffer_num = 5; ++ if(*count >= isp_max_buffer_num) { ++ *count = isp_max_buffer_num; ++ } ++ ++ ispvideo->max_buffer_num = *count; ++ ++ return 0; ++} ++ ++static int isp_video_buffer_prepare(struct vb2_buffer *buf) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(buf->vb2_queue); ++ ++ //vb2_set_plane_payload(buf, 0, format->fmt.pix.sizeimage); ++ vb2_set_plane_payload(buf, 0, ctx->payload_size); ++ return 0; ++} ++ ++static void isp_video_buffer_queue(struct vb2_buffer *buf) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(buf); ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(buf->vb2_queue); ++ struct isp_video_buffer *isp_buffer = to_isp_buffer(vbuf); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ int ret = 0; ++ ++ isp_buffer->uv_offset = ctx->uv_offset; ++ ++ ret = ispvideo->ops->qbuf(ispvideo, isp_buffer); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "failed to queue buf!\n"); ++ } ++} ++ ++static int isp_video_subdev_init(struct isp_video_device *ispvideo) ++{ ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ int ret = 0; ++ ++ /*subdevs reset.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || !is_media_entity_v4l2_subdev(pad->entity)) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, core, init, 1); ++ if(ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_err(ispvideo->dev, "failed to reset subdev[%s]\n", entity->name); ++ } else { ++ ret = 0; ++ } ++ } ++ ++ return ret; ++} ++ ++static int isp_video_subdev_reset(struct isp_video_device *ispvideo) ++{ ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct v4l2_subdev *sd = NULL; ++ struct media_pad *pad = NULL; ++ int ret = 0; ++ ++ /*subdevs reset.*/ ++ while(1) { ++ pad = &entity->pads[0]; ++ /*直到找到该pipeline上的仅有一个FL_SOURCE pad设备.*/ ++ if(!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (pad == NULL || !is_media_entity_v4l2_subdev(pad->entity)) ++ break; ++ entity = pad->entity; ++ sd = media_entity_to_v4l2_subdev(entity); ++ ++ /*stream on*/ ++ v4l2_set_subdev_hostdata(sd, ispvideo); ++ ret = v4l2_subdev_call(sd, core, reset, 1); ++ if(ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_err(ispvideo->dev, "failed to reset subdev[%s]\n", entity->name); ++ } else { ++ ret = 0; ++ } ++ } ++ ++ return ret; ++ ++} ++ ++ ++static int isp_video_subdev_streamon(struct isp_video_device *ispvideo) ++{ ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct mscaler_device *mscaler= ispcam->mscaler; ++ struct isp_device *isp = ispcam->isp; ++ struct vic_device *vic = ispcam->vic; ++ struct csi_device *csi = ispcam->csi; ++ struct isp_async_device *isd = &ispcam->isd[0]; ++ int ret = 0; ++ ++ if(!ispvideo->bypass) { ++ v4l2_set_subdev_hostdata(&mscaler->sd, ispvideo); ++ ret = v4l2_subdev_call(&mscaler->sd, video, s_stream, 1); ++ if(ret < 0) { ++ goto err; ++ } ++ ++ ret = v4l2_subdev_call(&isp->sd, video, s_stream, 1); ++ if(ret < 0) { ++ goto err; ++ } ++ } ++ ++ if(csi && (isd->bus_type == V4L2_MBUS_CSI2_DPHY)) { ++ ret = v4l2_subdev_call(&csi->sd, video, s_stream, 1); ++ if(ret < 0) { ++ goto err; ++ } ++ } ++ ++ if(!isd->enabled) { ++ ret = v4l2_subdev_call(isd->sd, video, s_stream, 1); ++ if(ret < 0) { ++ goto err; ++ } ++ } ++ isd->enabled++; ++ ++ ret = v4l2_subdev_call(&vic->sd, video, s_stream, 1); ++ if(ret < 0) { ++ goto err; ++ } ++ ++ return ret; ++err: ++ dev_err(ispvideo->dev, "start stream error\n"); ++ return ret; ++} ++ ++static int isp_video_subdev_streamoff(struct isp_video_device *ispvideo) ++{ ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct mscaler_device *mscaler= ispcam->mscaler; ++ struct isp_device *isp = ispcam->isp; ++ struct vic_device *vic = ispcam->vic; ++ struct csi_device *csi = ispcam->csi; ++ struct isp_async_device *isd = &ispcam->isd[0]; ++ int ret = 0; ++ ++ //global ispcam device mutex. ++ if(!ispvideo->bypass) { ++ v4l2_set_subdev_hostdata(&mscaler->sd, ispvideo); ++ ret = v4l2_subdev_call(&mscaler->sd, video, s_stream, 0); ++ if(ret < 0) { ++ goto err; ++ } ++ ++ ret = v4l2_subdev_call(&isp->sd, video, s_stream, 0); ++ if(ret < 0) { ++ goto err; ++ } ++ } ++ ++ if(csi && (isd->bus_type == V4L2_MBUS_CSI2_DPHY)) { ++ ret = v4l2_subdev_call(&csi->sd, video, s_stream, 0); ++ if(ret < 0) { ++ goto err; ++ } ++ } ++ ++ isd->enabled--; ++ if(!isd->enabled) { ++ ret = v4l2_subdev_call(isd->sd, video, s_stream, 0); ++ if(ret < 0) { ++ goto err; ++ } ++ } ++ ++ ret = v4l2_subdev_call(&vic->sd, video, s_stream, 0); ++ if(ret < 0) { ++ goto err; ++ } ++ ++ return ret; ++err: ++ dev_err(ispvideo->dev, "start stream error\n"); ++ return ret; ++ ++} ++ ++static int isp_video_subdev_stream(struct isp_video_device *ispvideo, int enable) ++{ ++ int ret = 0; ++ ++ if(enable) { ++ ret = isp_video_subdev_streamon(ispvideo); ++ } else { ++ ret = isp_video_subdev_streamoff(ispvideo); ++ } ++ ++ return ret; ++} ++ ++static int isp_video_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ struct media_entity *entity = &ispvideo->video.entity; ++ struct isp_pipeline *pipe = &ispvideo->pipe; ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ int ret = 0; ++ ++ mutex_lock(&ispcam->mutex); ++ ++ mutex_lock(&ispvideo->stream_lock); ++ ++ if(ispcam->enabled++ == 0) { ++ ret = media_pipeline_start(entity, &pipe->pipeline); ++ if(ret < 0) { ++ dev_err(ispvideo->dev, "Failed to start pipeline\n"); ++ goto err_pipeline_start; ++ } ++ ++ ret = isp_video_subdev_reset(ispvideo); ++ ret = isp_video_subdev_init(ispvideo); ++ } ++ ++ ret = isp_video_subdev_stream(ispvideo, 1); ++ ++ if(ret < 0) { ++ goto err_start_stream; ++ } ++ ++ mutex_unlock(&ispvideo->stream_lock); ++ ++ mutex_unlock(&ispcam->mutex); ++ return 0; ++ ++err_start_stream: ++ media_pipeline_stop(entity); ++err_pipeline_start: ++ mutex_unlock(&ispvideo->stream_lock); ++ mutex_unlock(&ispcam->mutex); ++ return ret; ++} ++static void isp_video_stop_streaming(struct vb2_queue *q) ++{ ++ struct isp_video_ctx *ctx = vb2_get_drv_priv(q); ++ struct isp_video_device *ispvideo = ctx->ispvideo; ++ //struct isp_pipeline *pipe = &ispvideo->pipe; ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ unsigned int is_streaming = 0; ++ int ret = 0; ++ ++ mutex_lock(&ispcam->mutex); ++ ++ mutex_lock(&ispvideo->stream_lock); ++ ++ ++ ++ is_streaming = vb2_is_streaming(q); ++ ++ if(!is_streaming) ++ goto done; ++ ++ ret = isp_video_subdev_stream(ispvideo, 0); ++ ++ if(--ispcam->enabled > 0) { ++ goto finish; ++ } ++ ++ media_pipeline_stop(&ispvideo->video.entity); ++ ++finish: ++done: ++ mutex_unlock(&ispvideo->stream_lock); ++ mutex_unlock(&ispcam->mutex); ++} ++ ++static const struct vb2_ops isp_video_queue_ops = { ++ .queue_setup = isp_video_queue_setup, ++ .buf_prepare = isp_video_buffer_prepare, ++ .buf_queue = isp_video_buffer_queue, ++ .start_streaming = isp_video_start_streaming, ++ .stop_streaming = isp_video_stop_streaming, ++}; ++ ++ ++static int isp_video_open(struct file *file) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct video_device *vdev = &ispvideo->video; ++ struct isp_video_ctx *ctx = NULL; ++ struct vb2_queue *queue = NULL; ++ int ret = 0; ++ mutex_lock(&ispvideo->mutex); ++ if(ispvideo->queue != NULL) { ++ mutex_unlock(&ispvideo->mutex); ++ return -EBUSY; ++ } ++ ++ ctx = kzalloc(sizeof(struct isp_video_ctx), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(ctx)) { ++ dev_err(ispvideo->ispcam->dev, "Failed to alloc ctx for isp_video_ctx\n"); ++ ret = -ENOMEM; ++ goto err_ctx_alloc; ++ } ++ ++ v4l2_fh_init(&ctx->fh, &ispvideo->video); ++ v4l2_fh_add(&ctx->fh); ++ ++ queue = &ctx->queue; ++ queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ queue->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; ++ queue->drv_priv = ctx; ++ queue->ops = &isp_video_queue_ops; ++ queue->mem_ops = &ingenic_vb2_dma_contig_memops; ++ queue->buf_struct_size = sizeof(struct isp_video_buffer); ++ queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ++ queue->lock = &ispvideo->queue_lock; ++ ++ ret = vb2_queue_init(&ctx->queue); ++ if(ret < 0) { ++ goto err_vb2_queue_init; ++ } ++ ++ ctx->ispvideo = ispvideo; ++ ctx->format.type = queue->type; ++ vdev->queue = ispvideo->queue = queue; ++ ++ file->private_data = &ctx->fh; ++ ++ mutex_unlock(&ispvideo->mutex); ++ ++ return 0; ++err_vb2_queue_init: ++ v4l2_fh_del(&ctx->fh); ++ kfree(ctx); ++err_ctx_alloc: ++ mutex_unlock(&ispvideo->mutex); ++ return ret; ++} ++static int isp_video_release(struct file *file) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct video_device *vdev = &ispvideo->video; ++ struct v4l2_fh *fh = file->private_data; ++ struct isp_video_ctx *ctx = to_isp_video_ctx(fh); ++ ++ /*lock*/ ++ ++ mutex_lock(&ispvideo->mutex); ++ ++ vb2_queue_release(&ctx->queue); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ ++ kfree(ctx); ++ file->private_data = NULL; ++ vdev->queue = ispvideo->queue = NULL; ++ ++ mutex_unlock(&ispvideo->mutex); ++ ++ /*unlock*/ ++ ++ return 0; ++} ++ ++static struct v4l2_file_operations isp_video_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = video_ioctl2, ++ .open = isp_video_open, ++ .release = isp_video_release, ++ .poll = vb2_fop_poll, /*isp_video_poll,*/ ++ .mmap = vb2_fop_mmap, /*isp_video_mmap,*/ ++}; ++ ++ ++int isp_video_init(struct isp_video_device *ispvideo, char *name, const struct isp_video_ops *video_ops) ++{ ++ int ret = 0; ++ struct video_device *video = &ispvideo->video; ++ struct media_entity *entity = &video->entity; ++ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); ++ ++ ++ /*创建buffer分é…器*/ ++ ispvideo->alloc_ctx = ingenic_vb2_dma_contig_init_ctx(ispvideo->ispcam->dev); ++ if(IS_ERR(ispvideo)) { ++ return -ENOMEM; ++ } ++ ++ /*åˆå§‹åŒ–一个sink pad*/ ++ ispvideo->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; ++ ret = media_entity_pads_init(&video->entity, 1, &ispvideo->pad); ++ if(ret < 0) { ++ /*TODO: error case*/ ++ } ++ ++ sd->owner = THIS_MODULE; ++ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ sd->entity.function = MEDIA_ENT_F_IO_V4L; ++ ++ mutex_init(&ispvideo->queue_lock); ++ mutex_init(&ispvideo->mutex); ++ mutex_init(&ispvideo->stream_lock); ++ ++ snprintf(video->name, sizeof(video->name), "isp-%s", name); ++ video->fops = &isp_video_fops; ++ ++ if(ispvideo->bypass) ++ video->ioctl_ops = &bypass_video_ioctl_ops; ++ else ++ video->ioctl_ops = &isp_video_ioctl_ops; ++ ++ video->release = video_device_release_empty; ++ video->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ++ ++ ispvideo->name = video->name; ++ ispvideo->ops = video_ops; ++ ispvideo->dev = ispvideo->ispcam->dev; ++ ++ video_set_drvdata(&ispvideo->video, ispvideo); ++ ++ return 0; ++} ++ ++int isp_video_cleanup(struct isp_video_device *ispvideo) ++{ ++ ++ return 0; ++} ++ ++int isp_video_register(struct isp_video_device *ispvideo, struct v4l2_device *v4l2_dev, int nr) ++{ ++ struct video_device *video = &ispvideo->video; ++ int ret = 0; ++ ++ video->v4l2_dev = v4l2_dev; ++ ++ ret = video_register_device(video, VFL_TYPE_VIDEO, nr); ++ if(ret < 0) { ++ /*TODO: error case*/ ++ } ++ ++ dev_info(ispvideo->dev, "register video device %s @ /dev/video%d ok\n", video->name, video->num); ++ ++ return ret; ++} ++int isp_video_unregister(struct isp_video_device *ispvideo) ++{ ++ ++ return 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/isp.c b/module_drivers/drivers/media/platform/ingenic-isp/isp.c +new file mode 100644 +index 000000000..7ddb43e7f +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/isp.c +@@ -0,0 +1,785 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++ ++#include "isp-drv.h" ++#include "isp-regs.h" ++#include "tiziano_core.h" ++ ++int isp_clk = 300000000; ++module_param(isp_clk, int, S_IRUGO); ++MODULE_PARM_DESC(isp_clk, "isp core clock"); ++ ++DEFINE_SPINLOCK(isp_cpm_lock); ++ ++static inline unsigned int isp_reg_readl(struct isp_device *isp, unsigned int reg) ++{ ++ return readl(isp->iobase + reg); ++} ++ ++static inline void isp_reg_writel(struct isp_device *isp, unsigned int reg, unsigned int val) ++{ ++ writel(val, isp->iobase + reg); ++} ++ ++ ++ ++/* interface used by isp-core.*/ ++int system_reg_write(void *isp, unsigned int reg, unsigned int value) ++{ ++ isp_reg_writel(isp, reg, value); ++ return 0; ++} ++ ++unsigned int system_reg_read(void *isp, unsigned int reg) ++{ ++ return isp_reg_readl(isp, reg); ++} ++ ++int system_irq_func_set(void *hdl, int irq, void *func, void *data) ++{ ++ struct isp_device *core = hdl; ++ ++ core->irq_func_cb[irq] = func; ++ core->irq_func_data[irq] = data; ++ return 0; ++} ++ ++static int isp_cpm_stop(struct isp_device *isp) ++{ ++ int timeout = 0xffffff; ++ unsigned int value = 0; ++ ++ ++ spin_lock(&isp_cpm_lock); ++ /*stop request*/ ++ value = readl(isp->cpm_reset); ++ value |= 1 << isp->bit_stp; ++ writel(value, isp->cpm_reset); ++ ++ /*stop ack*/ ++ while(!(readl(isp->cpm_reset) & (1 << isp->bit_ack)) && --timeout); ++ ++ if(timeout == 0) { ++ spin_unlock(&isp_cpm_lock); ++ dev_err(isp->dev, "isp wait stop timeout\n"); ++ return -ETIMEDOUT; ++ } ++ ++ spin_unlock(&isp_cpm_lock); ++ return 0; ++} ++ ++static int isp_cpm_reset(struct isp_device *isp) ++{ ++ int timeout = 0xffffff; ++ unsigned int value = 0; ++ int ret = 0; ++ ++ ++ spin_lock(&isp_cpm_lock); ++ /*stop request*/ ++ value = readl(isp->cpm_reset); ++ value |= 1 << isp->bit_stp; ++ writel(value, isp->cpm_reset); ++ ++ /*stop ack*/ ++ while(!(readl(isp->cpm_reset) & (1 << isp->bit_ack)) && --timeout); ++ ++ if(timeout == 0) { ++ dev_err(isp->dev, "isp wait stop timeout\n"); ++ ret = -ETIMEDOUT; ++ goto reset_timeout; ++ } ++ ++ /* activate reset */ ++ value = readl(isp->cpm_reset); ++ value &= ~(1 << isp->bit_stp); ++ value |= 1 << isp->bit_sr; ++ writel(value, isp->cpm_reset); ++ ++ /* deactive reset */ ++ value = readl(isp->cpm_reset); ++ value &= ~(1 << isp->bit_sr); ++ writel(value, isp->cpm_reset); ++ ++ spin_unlock(&isp_cpm_lock); ++ return 0; ++ ++reset_timeout: ++ spin_unlock(&isp_cpm_lock); ++ return ret; ++} ++ ++static int ingenic_isp_parse_dt(struct isp_device * isp) ++{ ++ struct device *dev = isp->dev; ++ unsigned int cpm_reset = 0; ++ int ret = 0; ++ ++ of_property_read_u32(dev->of_node, "ingenic,cpm_reset", &cpm_reset); ++ of_property_read_u32(dev->of_node, "ingenic,bit_sr", &isp->bit_sr); ++ of_property_read_u32(dev->of_node, "ingenic,bit_stp", &isp->bit_stp); ++ of_property_read_u32(dev->of_node, "ingenic,bit_ack", &isp->bit_ack); ++ ++ isp->cpm_reset = (void __iomem *)cpm_reset; ++ ++ return ret; ++} ++ ++ ++/* interface should be removed. */ ++static int isp_subdev_init(struct v4l2_subdev *sd, u32 val) ++{ ++ ++ return 0; ++} ++ ++/* interface should be removed. */ ++static int isp_subdev_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ struct isp_device *isp = v4l2_get_subdevdata(sd); ++ int ret = 0; ++ ++ ret = isp_cpm_reset(isp); ++ ++ return ret; ++} ++ ++static const struct v4l2_subdev_core_ops isp_subdev_core_ops = { ++ .init = isp_subdev_init, ++ .reset = isp_subdev_reset, ++ .log_status = v4l2_ctrl_subdev_log_status, ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static int isp_subdev_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct isp_device *isp = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ struct v4l2_subdev_format remote_subdev_fmt; ++ int ret = 0; ++ ++ remote = media_entity_remote_pad(&isp->pads[ISP_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ /*èŽ·å–æºå½“剿 ¼å¼ï¼Œå¤åˆ¶åˆ°è¾“出格å¼.*/ ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_err(isp->dev, "Failed to get_fmt from remote pad\n"); ++ return -EINVAL; ++ } ++ ++ /*本身ISP时没有格å¼åŒºåˆ«çš„, 这里必须从VIC获å–,å³ISPçš„SINK_PAD.*/ ++ if(format->pad == ISP_PAD_SOURCE) { ++ memcpy(&format->format, &remote_subdev_fmt.format, sizeof(format->format)); ++ } else { ++ dev_warn(isp->dev, "ISP_PAD_SOURCE should be set!\n"); ++ } ++ ++ isp->formats[ISP_PAD_SINK] = isp->formats[ISP_PAD_SOURCE] = *format; ++ isp->sensor_info = (struct sensor_info *)*(unsigned int *)format->format.reserved; ++ ++ //printk("----%s, %d, format->pad: %d\n", __func__, __LINE__, format->pad); ++ return 0; ++} ++ ++static int isp_subdev_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct isp_device *isp = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ int ret = 0; ++ ++ remote = media_entity_remote_pad(&isp->pads[ISP_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ ret = v4l2_subdev_call(remote_sd, pad, set_fmt, NULL, format); ++ if(ret < 0) { ++ dev_dbg(isp->dev, "Failed to set_fmt from remote pad\n"); ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_pad_ops isp_subdev_pad_ops = { ++ .set_fmt = isp_subdev_set_fmt, ++ .get_fmt = isp_subdev_get_fmt, ++ /* ++ .init_cfg = isp_subdev_init_cfg, ++ .enum_mbus_code = isp_subdev_enum_mbus_code, ++ .enum_frame_size = isp_subdev_enum_frame_size, ++ */ ++}; ++ ++enum isp_bayer_type { ++ TIZIANO_BAYER_TYPE_RGGB = 0, ++ TIZIANO_BAYER_TYPE_BGGR, ++ TIZIANO_BAYER_TYPE_GRBG, ++ TIZIANO_BAYER_TYPE_GBRG ++}; ++ ++ ++static int isp_fw_process(void *data) ++{ ++ struct isp_device *isp = (struct isp_device *)data; ++ ++ while(!kthread_should_stop()){ ++ tisp_fw_process(&isp->core); ++ } ++ return 0; ++} ++ ++ ++static int isp_load_params(struct isp_device *isp) ++{ ++ struct v4l2_subdev_format *input_fmt = &isp->formats[ISP_PAD_SINK]; ++ struct ispcam_device *ispcam = isp->ispcam; ++ unsigned int ret = 0; ++ struct file *file = NULL; ++ struct inode *inode = NULL; ++ mm_segment_t old_fs; ++ loff_t fsize = 0; ++ loff_t *pos = NULL; ++ ++ char file_name[64] = {0}; ++ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ snprintf(file_name, sizeof(file_name), "/etc/sensor/%s-%s-%d-%d.bin", ispcam->isd[0].sd->dev->driver->name, ispcam->chip_name, input_fmt->format.width, input_fmt->format.height); ++ file = filp_open(file_name, O_RDONLY, 0); ++ if (file < 0 || IS_ERR(file)) { ++ dev_dbg(isp->dev, "ISP: open %s file for isp calibrate read failed\n", file_name); ++ ++ snprintf(file_name, sizeof(file_name), "/etc/sensor/%s-%s.bin", ispcam->isd[0].sd->dev->driver->name, ispcam->chip_name); ++ file = filp_open(file_name, O_RDONLY, 0); ++ if (file < 0 || IS_ERR(file)) { ++ dev_dbg(isp->dev, "ISP: open %s file for isp calibrate read failed\n", file_name); ++ ret = -1; ++ isp->core.tuned_params = NULL; ++ goto failed_open_file; ++ } ++ } ++ ++ /* read file */ ++ inode = file->f_inode; ++ fsize = inode->i_size; ++ pos = &(file->f_pos); ++ ++ if(isp->core.tuned_params == NULL){ ++ isp->core.tuned_params = kzalloc(fsize, GFP_KERNEL); ++ if(isp->core.tuned_params == NULL){ ++ dev_err(isp->dev, "%s[%d]: Failed to alloc %lld KB buffer!\n",__func__,__LINE__, fsize >> 10); ++ ret = -1; ++ goto failed_malloc_data; ++ } ++ isp->core.tuned_params_size = fsize; ++ } ++ ++ vfs_read(file, isp->core.tuned_params, fsize, pos); ++ ++failed_malloc_data: ++ filp_close(file, NULL); ++ set_fs(old_fs); ++failed_open_file: ++ return ret; ++} ++ ++static int isp_release_params(struct isp_device *isp) ++{ ++ if(isp->core.tuned_params) { ++ kfree(isp->core.tuned_params); ++ isp->core.tuned_params = NULL; ++ isp->core.tuned_params_size = 0; ++ } ++ ++ return 0; ++} ++ ++static int isp_subdev_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct isp_device *isp = v4l2_get_subdevdata(sd); ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct v4l2_subdev_format *input_fmt = &isp->formats[ISP_PAD_SINK]; ++ ++ tisp_init_param_t iparam; ++ ++ if(enable) { ++ ++ if(isp->enabled++ > 0) { ++ return 0; ++ } ++ ++ iparam.width = input_fmt->format.width; ++ iparam.height = input_fmt->format.height; ++ ++ ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: ++ case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE: ++ case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE: ++ case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE: ++ case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE: ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ // printk("BGGR\n"); ++ iparam.bayer = 2; ++ break; ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ // printk("GBRG\n"); ++ iparam.bayer = 3; ++ break; ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ iparam.bayer = 1; ++ // printk("GRBG\n"); ++ break; ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ iparam.bayer = 0; ++ // printk("RGGB\n"); ++ break; ++ default: ++ dev_err(isp->dev, "%s[%d] the format(0x%08x) of input couldn't be handled!\n", ++ __func__,__LINE__, input_fmt->format.code); ++ return -EINVAL; ++ break; ++ } ++ ++ ++ strncpy(iparam.sensor, ispcam->isd[0].sd->dev->driver->name, sizeof(iparam.sensor)); ++ iparam.sensor_info.fps = isp->sensor_info->fps; ++ iparam.sensor_info.total_width = isp->sensor_info->total_width; ++ iparam.sensor_info.total_height = isp->sensor_info->total_height; ++ ++ ++ isp_load_params(isp); ++ tisp_core_init(&isp->core, &iparam, isp); ++ isp->core_inited = 1; ++ isp_core_tuning_param_sync(&isp->core); ++ ++ isp_release_params(isp); ++ ++ /*For event engine.*/ ++ isp->process_thread = kthread_run(isp_fw_process, isp, "isp_fw_process"); ++ if(IS_ERR_OR_NULL(isp->process_thread)){ ++ dev_err(isp->dev, "%s[%d] kthread_run was failed!\n",__func__,__LINE__); ++ return -EINVAL; ++ } ++ ++ ++ isp_reg_writel(isp, TOP_CTRL_ADDR_INT_EN, 0x283f03ff); ++#if 0 ++ iparam.sensor_info.max_again = core->vin.attr->max_again; //the format is .16 ++ iparam.sensor_info.max_dgain = core->vin.attr->max_dgain; //the format is .16 ++ iparam.sensor_info.again = core->vin.attr->again; ++ iparam.sensor_info.dgain = core->vin.attr->dgain; ++ iparam.sensor_info.fps = core->vin.fps; ++ iparam.sensor_info.min_integration_time = core->vin.attr->min_integration_time; ++ iparam.sensor_info.min_integration_time_native = core->vin.attr->min_integration_time_native; ++ iparam.sensor_info.max_integration_time_native = core->vin.attr->max_integration_time_native; ++ iparam.sensor_info.integration_time_limit = core->vin.attr->integration_time_limit; ++ iparam.sensor_info.integration_time = core->vin.attr->integration_time; ++ iparam.sensor_info.total_width = core->vin.attr->total_width; ++ iparam.sensor_info.total_height = core->vin.attr->total_height; ++ iparam.sensor_info.max_integration_time = core->vin.attr->max_integration_time; ++ iparam.sensor_info.integration_time_apply_delay = core->vin.attr->integration_time_apply_delay; ++ iparam.sensor_info.again_apply_delay = core->vin.attr->again_apply_delay; ++ iparam.sensor_info.dgain_apply_delay = core->vin.attr->dgain_apply_delay; ++ iparam.sensor_info.one_line_expr_in_us = core->vin.attr->one_line_expr_in_us; ++#endif ++ ++ } else { ++ ++ if(--isp->enabled > 0) { ++ return 0; ++ } ++ /*disable irq.*/ ++ isp_reg_writel(isp, TOP_CTRL_ADDR_INT_EN, 0); ++ /* isp tirger */ ++ isp_reg_writel(isp, INPUT_CTRL_ADDR_IP_TRIG, 0x0); ++ ++ kthread_stop(isp->process_thread); ++ ++ tisp_core_deinit(&isp->core); ++ isp->core_inited = 0; ++ ++ } ++ ++ return 0; ++} ++ ++ ++static const struct v4l2_subdev_video_ops isp_subdev_video_ops = { ++ .s_stream = isp_subdev_s_stream, ++}; ++ ++ ++static const struct v4l2_subdev_ops isp_subdev_ops = { ++ .core = &isp_subdev_core_ops, ++ .pad = &isp_subdev_pad_ops, ++ .video = &isp_subdev_video_ops, ++}; ++static ssize_t ++dump_isp(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct isp_device *isp = dev_get_drvdata(dev); ++ char *p = buf; ++ ++ p += sprintf(p, "TOP_CTRL_ADDR_VERSION :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_VERSION )); ++ p += sprintf(p, "TOP_CTRL_ADDR_FM_SIZE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_FM_SIZE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_BAYER_TYPE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_BAYER_TYPE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_BYPASS_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_BYPASS_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TOP_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TOP_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TOP_STATE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TOP_STATE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_LINE_SPACE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_LINE_SPACE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_REG_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_REG_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_TRIG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_TRIG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_ADDR :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_ADDR )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_STATE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_STATE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_APB_WR_DATA :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_APB_WR_DATA )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RC_APB_WR_ADDR :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RC_APB_WR_ADDR )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RD_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RD_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_WR_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_WR_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_FR_WR_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_FR_WR_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_STA_WR_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_STA_WR_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_RD_DEBUG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_RD_DEBUG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_WR_DEBUG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_WR_DEBUG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_FR_WR_DEBUG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_FR_WR_DEBUG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_DMA_STA_WR_DEBUG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_DMA_STA_WR_DEBUG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_INT_EN :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_INT_EN )); ++ p += sprintf(p, "TOP_CTRL_ADDR_INT_REG :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_INT_REG )); ++ p += sprintf(p, "TOP_CTRL_ADDR_INT_CLR :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_INT_CLR )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_FREERUN :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_FREERUN )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_CON :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_CON )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_SIZE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_SIZE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_FONT :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_FONT )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_FLICK :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_FLICK )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_CS_TYPE :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_CS_TYPE )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_CS_FCLO :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_CS_FCLO )); ++ p += sprintf(p, "TOP_CTRL_ADDR_TP_CS_BCLO :0x%08x\n", isp_reg_readl(isp, TOP_CTRL_ADDR_TP_CS_BCLO )); ++ ++ return p - buf; ++} ++ ++ ++static DEVICE_ATTR(dump_isp, S_IRUGO|S_IWUSR, dump_isp, NULL); ++ ++static struct attribute *isp_debug_attrs[] = { ++ &dev_attr_dump_isp.attr, ++ NULL, ++}; ++ ++static struct attribute_group isp_debug_attr_group = { ++ .name = "debug", ++ .attrs = isp_debug_attrs, ++}; ++ ++ ++static int isp_comp_bind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct isp_device *isp = dev_get_drvdata(comp); ++ struct ispcam_device *ispcam = (struct ispcam_device *)master_data; ++ struct v4l2_device *v4l2_dev = &ispcam->v4l2_dev; ++ struct v4l2_subdev *sd = &isp->sd; ++ int ret = 0; ++ ++ //dev_info(comp, "----dev_name(comp): %s----%s, %d \n", dev_name(comp), __func__, __LINE__); ++ ++ /* link subdev to master.*/ ++ isp->ispcam = (void *)ispcam; ++ ispcam->isp = isp; ++ ++ /*1. register supported subdev ctrls.*/ ++ ++ ++ /*2. init v4l2_subdev*/ ++ ++ v4l2_subdev_init(sd, &isp_subdev_ops); ++ ++ sd->owner = THIS_MODULE; ++ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ strscpy(sd->name, dev_name(comp), sizeof(sd->name)); ++ v4l2_set_subdevdata(sd, isp); ++ ++ ++ /* init isp pads. */ ++ isp->pads = kzalloc(sizeof(struct media_pad) * ISP_NUM_PADS, GFP_KERNEL); ++ if(!isp->pads) { ++ ret = -ENOMEM; ++ goto err_alloc_pads; ++ } ++ isp->pads[0].index = ISP_PAD_SINK; ++ isp->pads[0].flags = MEDIA_PAD_FL_SINK; ++ isp->pads[1].index = ISP_PAD_SOURCE; ++ isp->pads[1].flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&sd->entity, ISP_NUM_PADS, isp->pads); ++ ++ /*3. register v4l2_subdev*/ ++ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_COMPOSER; ++ ret = v4l2_device_register_subdev(v4l2_dev, sd); ++ if(ret < 0) { ++ dev_err(comp, "Failed to register v4l2_subdev for isp\n"); ++ goto err_subdev_register; ++ } ++ ++ return 0; ++err_subdev_register: ++err_alloc_pads: ++ return ret; ++} ++ ++ ++static void isp_comp_unbind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct isp_device *isp = dev_get_drvdata(comp); ++ ++ dev_info(comp, "---TODO:--%p---%s, %d \n", isp, __func__, __LINE__); ++ ++} ++ ++static const struct component_ops isp_comp_ops = { ++ .bind = isp_comp_bind, ++ .unbind = isp_comp_unbind, ++}; ++ ++static irqreturn_t isp_irq_handler(int irq, void *data) ++{ ++ struct isp_device *isp = (struct isp_device *)data; ++ struct ispcam_device *ispcam = isp->ispcam; ++ struct mscaler_device *mscaler = ispcam->mscaler; ++ struct v4l2_subdev *sd = &mscaler->sd; ++ bool handled = 0; ++ unsigned int status; ++ int ret = 0; ++ int i = 0; ++ ++ /*read irq_flags*/ ++ status = isp_reg_readl(isp, TOP_CTRL_ADDR_INT_REG); ++ ++ ++ /*1. process irq by subdev.*/ ++ ret = v4l2_subdev_call(sd, core, interrupt_service_routine, status, &handled); ++ if(ret < 0) { ++ ++ } ++ ++ /*2. isp-core irq callbacks */ ++ for(i = 0; i < 32; i++) { ++ if(status & (1 << i) && isp->irq_func_cb[i]) { ++ ret = isp->irq_func_cb[i](isp->irq_func_data[i]); ++ if(ret < 0) { ++ ++ } ++ } ++ } ++ /*clear irq_flags*/ ++ isp_reg_writel(isp, TOP_CTRL_ADDR_INT_CLR, status); ++ ++ ++ return IRQ_HANDLED; ++} ++ ++static int ingenic_isp_probe(struct platform_device *pdev) ++{ ++ ++ struct isp_device *isp = NULL; ++ int ret = 0; ++ struct resource *regs = NULL; ++ ++ isp = kzalloc(sizeof(struct isp_device), GFP_KERNEL); ++ if(!isp) { ++ pr_err("Failed to alloc isp dev [%s]\n", pdev->name); ++ return -ENOMEM; ++ } ++ ++ isp->dev = &pdev->dev; ++ platform_set_drvdata(pdev, isp); ++ ++ ++ ingenic_isp_parse_dt(isp); ++ ++ isp->irq = platform_get_irq(pdev, 0); ++ if(isp->irq < 0) { ++ dev_warn(&pdev->dev, "No ISP IRQ specified\n"); ++ } ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(!regs) { ++ dev_err(&pdev->dev, "No iomem resource!\n"); ++ goto err_get_resource; ++ } ++ ++ isp->iobase = devm_ioremap_resource(&pdev->dev, regs); ++ if(!isp->iobase) { ++ goto err_ioremap; ++ } ++ ++ ret = devm_request_irq(isp->dev, isp->irq, isp_irq_handler, 0, ++ dev_name(isp->dev), isp); ++ if(ret) { ++ dev_err(isp->dev, "request irq failed!\n"); ++ goto err_request_irq; ++ } ++ ++ isp->div_clk = of_clk_get(isp->dev->of_node, 0); ++ if(!isp->div_clk) { ++ dev_err(isp->dev, "failed to get isp div_clk\n"); ++ goto err_div_clk; ++ } ++ ++ clk_set_rate(isp->div_clk, isp_clk); ++ ++ clk_prepare_enable(isp->div_clk); ++ ++ isp->gate_clk = of_clk_get(isp->dev->of_node, 1); ++ if(!isp->gate_clk) { ++ dev_err(isp->dev, "failed to get isp gate_clk\n"); ++ goto err_gate_clk; ++ } ++ ++ clk_prepare_enable(isp->gate_clk); ++ ++ isp->power_clk = of_clk_get(isp->dev->of_node, 2); ++ if(!isp->power_clk) { ++ dev_err(isp->dev, "failed to get isp power clk!\n"); ++ goto err_power_clk; ++ } ++ clk_prepare_enable(isp->power_clk); ++ ++ ret = sysfs_create_group(&isp->dev->kobj, &isp_debug_attr_group); ++ if (ret) { ++ dev_err(isp->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_sys_group; ++ } ++ ++ ++ ret = component_add(isp->dev, &isp_comp_ops); ++ if(ret < 0) { ++ dev_err(isp->dev, "Failed to add component isp!\n"); ++ } ++ ++ return 0; ++err_sys_group: ++err_power_clk: ++err_gate_clk: ++err_div_clk: ++err_request_irq: ++err_ioremap: ++err_get_resource: ++ return ret; ++} ++ ++ ++ ++static int ingenic_isp_remove(struct platform_device *pdev) ++{ ++ struct isp_device *isp = dev_get_drvdata(&pdev->dev); ++ ++ clk_disable_unprepare(isp->power_clk); ++ clk_disable_unprepare(isp->gate_clk); ++ clk_disable_unprepare(isp->div_clk); ++ return 0; ++} ++ ++ ++ ++static const struct of_device_id ingenic_isp_dt_match[] = { ++ { .compatible = "ingenic,x2000-isp" }, ++ { .compatible = "ingenic,m300-isp" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_isp_dt_match); ++ ++static int __maybe_unused ingenic_isp_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct isp_device *isp = dev_get_drvdata(&pdev->dev); ++ ++ if(isp->enabled){ ++ dev_err(isp->dev, "faild to suspend, isp is streaming on\n"); ++ return -EBUSY; ++ } ++ ++ isp_cpm_stop(isp); ++ clk_disable_unprepare(isp->power_clk); ++ clk_disable_unprepare(isp->gate_clk); ++ clk_disable_unprepare(isp->div_clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused ingenic_isp_resume(struct platform_device *pdev) ++{ ++ struct isp_device *isp = dev_get_drvdata(&pdev->dev); ++ ++ clk_prepare_enable(isp->div_clk); ++ clk_prepare_enable(isp->gate_clk); ++ clk_prepare_enable(isp->power_clk); ++ isp_cpm_reset(isp); ++ ++ return 0; ++} ++ ++static struct platform_driver ingenic_isp_driver = { ++ .probe = ingenic_isp_probe, ++ .remove = ingenic_isp_remove, ++ .suspend = ingenic_isp_suspend, ++ .resume = ingenic_isp_resume, ++ .driver = { ++ .name = "ingenic-isp", ++ .of_match_table = ingenic_isp_dt_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_isp_driver); ++ ++MODULE_ALIAS("platform:ingenic-isp"); ++MODULE_DESCRIPTION("ingenic isp subsystem"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/mscaler-bdev.c b/module_drivers/drivers/media/platform/ingenic-isp/mscaler-bdev.c +new file mode 100644 +index 000000000..3bd1bb032 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/mscaler-bdev.c +@@ -0,0 +1,255 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "helix_drv.h" ++#include "jpge.h" ++ ++#include "isp-drv.h" ++ ++ ++int ms_bdev_qbuf(struct mscaler_backend_device *ms_bdev, struct isp_video_buffer *isp_buffer) ++{ ++ ++ unsigned long flags; ++ ++// printk("--------%s, %d\n", __func__, __LINE__); ++ ++ spin_lock_irqsave(&ms_bdev->lock, flags); ++ ++ list_add_tail(&isp_buffer->list_entry, &ms_bdev->processing_list); ++ ++ spin_unlock_irqrestore(&ms_bdev->lock, flags); ++ ++ /* wakeup possible process thread. */ ++ wake_up(&ms_bdev->wq); ++} ++ ++ ++static int ms_bdev_kthread(void *data) ++{ ++ ++ struct mscaler_backend_device *ms_bdev = data; ++ int ret = 0; ++ unsigned long flags; ++ ++ struct ingenic_venc_ctx *ctx = ms_bdev->ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ ++ struct video_frame_buffer src_frame; ++ ++ while(1) { ++ ++ if(kthread_should_stop()) ++ break; ++ ++ ++ ret = wait_event_interruptible(ms_bdev->wq, !list_empty(&ms_bdev->processing_list) || ms_bdev->activated == 0); ++ if(ret || ms_bdev->activated == 0) { ++ /*wakeup by interrupt?*/ ++ /* STOP*/ ++ continue; ++ } ++ ++ spin_lock_irqsave(&ms_bdev->lock, flags); ++ struct isp_video_buffer *isp_buffer = list_first_entry_or_null(&ms_bdev->processing_list, struct isp_video_buffer, list_entry); ++ ++ if(!isp_buffer) { ++ dev_err(ms_bdev->dev, "No Buffer available!\n"); ++ } else { ++ ++ list_del(&isp_buffer->list_entry); ++ } ++ spin_unlock_irqrestore(&ms_bdev->lock, flags); ++ ++ struct vb2_v4l2_buffer *vb2 = &isp_buffer->vb2; ++ ++ ++ mutex_lock(&ctx->dev->dev_mutex); ++ /* Processing ....*/ ++ ++ memset(&src_frame, 0, sizeof(struct video_frame_buffer)); ++ ++ src_frame.num_planes = 2; ++ src_frame.fb_addr[0].pa = ingenic_vb2_dma_contig_plane_dma_addr(&vb2->vb2_buf, 0); ++ src_frame.fb_addr[1].pa = src_frame.fb_addr[0].pa + isp_buffer->uv_offset; ++ ++ src_frame.fb_addr[0].va = vb2_plane_vaddr(&vb2->vb2_buf, 0); ++ src_frame.fb_addr[1].va = src_frame.fb_addr[0].va + isp_buffer->uv_offset; ++ ++ src_frame.fb_addr[0].size = isp_buffer->uv_offset; ++ src_frame.fb_addr[1].size = vb2_get_plane_payload(&vb2->vb2_buf, 0) - src_frame.fb_addr[0].size; ++ ++ dma_sync_single_for_device(ms_bdev->dev,(unsigned long)jpge_ctx->bs->pa, jpge_ctx->bs->size, DMA_FROM_DEVICE); ++ ++ jpeg_encoder_encode(jpge_ctx, &src_frame, jpge_ctx->bs); ++ ++ memcpy(vb2_plane_vaddr(&vb2->vb2_buf, 0), jpge_ctx->bs->va, jpge_ctx->bslen); ++ ++ vb2_set_plane_payload(&vb2->vb2_buf, 0, jpge_ctx->bslen); ++ ++#if 0 ++ wait_process_buffer(); ++ ++ done_process_buffer(); ++#endif ++ mutex_unlock(&ctx->dev->dev_mutex); ++// printk("----done_processing_buffer: %d\n", isp_buffer->vb2.vb2_buf.index); ++ vb2_buffer_done(&isp_buffer->vb2.vb2_buf, VB2_BUF_STATE_DONE); ++ ++ } ++ ++ return 0; ++} ++ ++ ++static int venc_create_ctx(struct mscaler_backend_device *ms_bdev) ++{ ++ ++ struct ingenic_venc_ctx *ctx = kzalloc(sizeof(struct ingenic_venc_ctx), GFP_KERNEL); ++ struct h264e_ctx * h264e_ctx = NULL; ++ struct jpge_ctx * jpge_ctx = NULL; ++ struct ingenic_vcodec_mem *bs = NULL; ++ int ret = 0; ++ ++ if(ctx == NULL) { ++ return -ENOMEM; ++ } ++ ++ ctx->dev = ingenic_venc_dev_get(); ++ ++ mutex_lock(&ctx->dev->dev_mutex); ++ ++#if 0 ++ if (!ctx->dev->id_counter) { ++ vpu_on(ctx->dev); ++ } ++#endif ++ ++ ctx->id = ctx->dev->id_counter++; ++ init_waitqueue_head(&ctx->queue); ++ ++ mutex_unlock(&ctx->dev->dev_mutex); ++ ++ ms_bdev->ctx = ctx; ++ ++ /*switch FMT: JPEG H264.*/ ++ jpge_ctx = &ctx->jpge_ctx; ++ ctx->codec_id = CODEC_ID_JPGE; ++ ++ ret = jpeg_encoder_init(jpge_ctx); ++ jpeg_encoder_set_priv(jpge_ctx, ctx); ++ ++ ++ jpeg_encoder_set_fmt(jpge_ctx, ms_bdev->width, ms_bdev->height, HELIX_NV12_MODE); ++ ++ ret = jpeg_encoder_alloc_workbuf(jpge_ctx); ++ if(ret < 0) { ++ goto err_alloc_workbuf; ++ } ++ ++ /* alloc bs output buffer. */ ++ bs = kzalloc(sizeof(struct ingenic_vcodec_mem), GFP_KERNEL); ++ if(!bs) { ++ goto err_bs_alloc; ++ } ++ bs->size = ms_bdev->width * ms_bdev->height; ++ ++ bs->va = dma_alloc_noncoherent(ms_bdev->dev, bs->size, &bs->pa, GFP_KERNEL); ++ if(!bs->va) { ++ goto err_bs_va_alloc; ++ } ++ ++ jpge_ctx->bs = bs; ++ ++ ++ return 0; ++err_bs_va_alloc: ++ kfree(bs); ++err_bs_alloc: ++ jpeg_encoder_free_workbuf(jpge_ctx); ++err_alloc_workbuf: ++ jpeg_encoder_deinit(jpge_ctx); ++ ++ kfree(ctx); ++ ms_bdev->ctx = NULL; ++ return ret; ++} ++ ++static int venc_free_ctx(struct mscaler_backend_device *ms_bdev) ++{ ++ struct ingenic_venc_ctx *ctx = ms_bdev->ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct ingenic_vcodec_mem *bs = jpge_ctx->bs; ++ ++ ++ ++ mutex_lock(&ctx->dev->dev_mutex); ++#if 0 ++ if (!--ctx->dev->id_counter) { ++ vpu_off(ctx->dev); ++ } ++#endif ++ mutex_unlock(&ctx->dev->dev_mutex); ++ ++ dma_free_noncoherent(ms_bdev->dev, bs->size, bs->va, bs->pa); ++ kfree(bs); ++ ++ jpeg_encoder_free_workbuf(jpge_ctx); ++ jpeg_encoder_deinit(jpge_ctx); ++ ++ kfree(ctx); ++} ++ ++ ++int ms_bdev_init(struct mscaler_backend_device *ms_bdev) ++{ ++ int ret = 0; ++ printk("--------%s, %d\n", __func__, __LINE__); ++ ++ ret = venc_create_ctx(ms_bdev); ++ if(ret < 0) { ++ return -EINVAL; ++ } ++ ++ spin_lock_init(&ms_bdev->lock); ++ INIT_LIST_HEAD(&ms_bdev->processing_list); ++ init_waitqueue_head(&ms_bdev->wq); ++ ++ ms_bdev->process_thread = kthread_run(ms_bdev_kthread, ms_bdev, "ms-bdev-ch%d", ms_bdev->ch); ++ if(IS_ERR_OR_NULL(ms_bdev->process_thread)) { ++ ++ dev_err(ms_bdev->dev, "Failed to run kthread for ms-bdev-ch%d", ms_bdev->ch); ++ ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int ms_bdev_deinit(struct mscaler_backend_device *ms_bdev) ++{ ++ ++ printk("--------%s, %d\n", __func__, __LINE__); ++ ++ if(!ms_bdev->activated) { ++ return 0; ++ } ++ ++ ++ kthread_stop(ms_bdev->process_thread); ++ ++ ms_bdev->process_thread = NULL; ++ ++ venc_free_ctx(ms_bdev); ++ ++ memset(ms_bdev, 0, sizeof(struct mscaler_backend_device)); ++ ++ return 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/mscaler-regs.h b/module_drivers/drivers/media/platform/ingenic-isp/mscaler-regs.h +new file mode 100644 +index 000000000..d7a2de2cc +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/mscaler-regs.h +@@ -0,0 +1,82 @@ ++#ifndef __INGENIC_ISP_MSCALER_REGS_H__ ++#define __INGENIC_ISP_MSCALER_REGS_H__ ++ ++#define MSCA_BASE 0 ++ ++//============================================================ ++// Mscaler ++//============================================================ ++#define MSCA_CTRL (MSCA_BASE+0x000) ++#define MSCA_CH_EN (MSCA_BASE+0x004) ++#define MSCA_CH_STA (MSCA_BASE+0x008) ++#define MSCA_INT_STA (MSCA_BASE+0x00C) ++#define MSCA_INT_MSK (MSCA_BASE+0x010) ++#define MSCA_INT_CLR (MSCA_BASE+0x014) ++#define MSCA_DMAOUT_ARB (MSCA_BASE+0x018) ++#define MSCA_CLK_GATE_EN (MSCA_BASE+0x01C) ++#define MSCA_CLK_DIS (MSCA_BASE+0x020) ++#define MSCA_SRC_IN (MSCA_BASE+0x030) ++#define MSCA_SRC_SIZE (MSCA_BASE+0x034) ++#define MSCA_GLO_RSZ_COEF_WR (MSCA_BASE+0x040) ++#define MSCA_SYS_PRO_CLK_EN (MSCA_BASE+0x050) ++#define MSCA_DS0_CLK_NUM (MSCA_BASE+0x054) ++#define MSCA_DS1_CLK_NUM (MSCA_BASE+0x058) ++#define MSCA_DS2_CLK_NUM (MSCA_BASE+0x05C) ++ ++#define CHx_RSZ_OSIZE(n) (MSCA_BASE+(0x0100*(n))+0x100) ++#define CHx_RSZ_STEP(n) (MSCA_BASE+(0x0100*(n))+0x104) ++ ++#define CHx_CROP_OPOS(n) (MSCA_BASE+(0x0100*(n))+0x128) ++#define CHx_CROP_OSIZE(n) (MSCA_BASE+(0x0100*(n))+0x12c) ++#define CHx_FRA_CTRL_LOOP(n) (MSCA_BASE+(0x0100*(n))+0x130) ++#define CHx_FRA_CTRL_MASK(n) (MSCA_BASE+(0x0100*(n))+0x134) ++#define CHx_MSx_POS(n,m) (MSCA_BASE+(0x0100*(n))+0x138+(0x0c*(m))) ++#define CHx_MSx_SIZE(n,m) (MSCA_BASE+(0x0100*(n))+0x13c+(0x0c*(m))) ++#define CHx_MSx_VALUE(n,m) (MSCA_BASE+(0x0100*(n))+0x140+(0x0c*(m))) ++#define CHx_MS0_POS(n) (MSCA_BASE+(0x0100*(n))+0x138) ++#define CHx_MS0_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x13c) ++#define CHx_MS0_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x140) ++#define CHx_MS1_POS(n) (MSCA_BASE+(0x0100*(n))+0x144) ++#define CHx_MS1_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x148) ++#define CHx_MS1_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x14c) ++#define CHx_MS2_POS(n) (MSCA_BASE+(0x0100*(n))+0x150) ++#define CHx_MS2_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x154) ++#define CHx_MS2_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x158) ++#define CHx_MS3_POS(n) (MSCA_BASE+(0x0100*(n))+0x15c) ++#define CHx_MS3_SIZE(n) (MSCA_BASE+(0x0100*(n))+0x160) ++#define CHx_MS3_VALUE(n) (MSCA_BASE+(0x0100*(n))+0x164) ++#define CHx_OUT_FMT(n) (MSCA_BASE+(0x0100*(n))+0x168) ++#define CHx_DMAOUT_Y_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x16c) ++#define CHx_Y_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x170) ++#define CHx_DMAOUT_Y_LAST_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x174) ++#define CHx_DMAOUT_Y_LAST_STATS_NUM(n) (MSCA_BASE+(0x0100*(n))+0x178) ++#define CHx_Y_LAST_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x17c) ++#define CHx_DMAOUT_Y_STRI(n) (MSCA_BASE+(0x0100*(n))+0x180) ++#define CHx_DMAOUT_UV_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x184) ++#define CHx_UV_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x188) ++#define CHx_DMAOUT_UV_LAST_ADDR(n) (MSCA_BASE+(0x0100*(n))+0x18c) ++#define CHx_DMAOUT_UV_LAST_STATS_NUM(n) (MSCA_BASE+(0x0100*(n))+0x190) ++#define CHx_UV_LAST_ADDR_FIFO_STA(n) (MSCA_BASE+(0x0100*(n))+0x194) ++#define CHx_DMAOUT_UV_STRI(n) (MSCA_BASE+(0x0100*(n))+0x198) ++#define CHx_DMAOUT_Y_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x19c) ++#define CHx_DMAOUT_UV_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a0) ++#define CHx_DMAOUT_Y_LAST_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a4) ++#define CHx_DMAOUT_UV_LAST_ADDR_CLR(n) (MSCA_BASE+(0x0100*(n))+0x1a8) ++#define CHx_DMAOUT_Y_ADDR_SEL(n) (MSCA_BASE+(0x0100*(n))+0x1ac) ++#define CHx_DMAOUT_UV_ADDR_SEL(n) (MSCA_BASE+(0x0100*(n))+0x1b0) ++ ++#define MSCA_CH0_FRM_DONE_INT (0) ++#define MSCA_CH1_FRM_DONE_INT (1) ++#define MSCA_CH2_FRM_DONE_INT (2) ++#define MSCA_CH0_CROP_ERR_INT (3) ++#define MSCA_CH1_CROP_ERR_INT (4) ++#define MSCA_CH2_CROP_ERR_INT (5) ++ ++#define CHx_OUT_FMT_NV12 0x0 ++#define CHx_OUT_FMT_NV21 0x1 ++#define CHx_OUT_FMT_ARGB8888 0x2 ++#define CHx_OUT_FMT_RGB565 0x3 ++#define CHx_OUT_FMT_Y_OUT_ONLY (1 << 6) ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/mscaler.c b/module_drivers/drivers/media/platform/ingenic-isp/mscaler.c +new file mode 100644 +index 000000000..9517419f7 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/mscaler.c +@@ -0,0 +1,1531 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++#include "mscaler-regs.h" ++ ++static void dump_mscaler_regs(struct mscaler_device *mscaler); ++ ++static struct isp_video_format mscaler_output_formats[] = { ++ { ++ .name = "NV12, Y/CbCr 4:2:0", ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .depth = {8, 4}, ++ .num_planes = 2, ++ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "NV21, Y/CrCb 4:2:0", ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .depth = {8, 4}, ++ .num_planes = 2, ++ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "GREY, Greyscale", ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++#ifdef CONFIG_MSCA_BDEV ++ { ++ .name = "JFIF JPEG", ++ .fourcc = V4L2_PIX_FMT_JPEG, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, ++ { ++ .name = "H264 with start codes", ++ .fourcc = V4L2_PIX_FMT_H264, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, ++#endif ++ /* ++ { ++ .name = "RGB565, RGB-5-6-5", ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_RGB565_1X16, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "ARGB32, ARGB-8-8-8-8", ++ .fourcc = V4L2_PIX_FMT_ARGB32, ++ .depth = {32}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_ARGB8888_1X32, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ */ ++}; ++ ++struct ingenic_isp_framesizes { ++ u32 fourcc; ++ struct v4l2_frmsize_discrete discrete; ++}; ++ ++static const struct ingenic_isp_framesizes ingenic_isp_framesizes[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {320, 240}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {240, 320}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {640, 480}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {480, 640}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {960, 720}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {720, 960}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {1280, 720}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {1280, 960}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .discrete = {1920, 1080}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {320, 240}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {240, 320}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {640, 480}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {480, 640}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {960, 720}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {720, 960}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {1280, 720}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {1280, 960}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .discrete = {1920, 1080}, ++ } ++}; ++ ++struct mask_kobj_attr { ++ struct kobj_attribute attr; ++ unsigned int id; ++}; ++ ++#define to_mask_attr(attr) \ ++ container_of(attr, struct mask_kobj_attr, attr) ++ ++static inline void mscaler_reg_writel(struct mscaler_device *mscaler, unsigned int reg, unsigned int val) ++{ ++ writel(val, mscaler->iobase + reg); ++} ++ ++static inline unsigned int mscaler_reg_readl(struct mscaler_device *mscaler, unsigned int reg) ++{ ++ return readl(mscaler->iobase + reg); ++} ++ ++ ++/* isp video 回调函数,用æ¥å¯»æ‰¾å½“剿”¯æŒçš„输出视频格å¼ï¼Œç”±äºŽmscalerå¯ä»¥è¾“出,vic也å¯ä»¥è¾“出,所以这里设计æˆå›žè°ƒçš„æ–¹å¼.*/ ++ ++/** ++ * @brief ++ * ++ * @param pixelformat 如果pixelformatä¸ä¸ºç©ºï¼Œåˆ™ä½¿ç”¨pixelformat匹é…. ++ * @param mbus_code ++ * @param index ++ * ++ * @return ++ */ ++struct isp_video_format *mscaler_find_format(const u32 *pixelformat, const u32 *mbus_code, int index) ++{ ++ int i; ++ struct isp_video_format *fmt = NULL; ++ ++ for(i = 0; i < ARRAY_SIZE(mscaler_output_formats); i++) { ++ fmt = &mscaler_output_formats[i]; ++ ++ if(pixelformat && fmt->fourcc == *pixelformat) { ++ return fmt; ++ } ++ if(mbus_code && fmt->mbus_code == *mbus_code) { ++ return fmt; ++ } ++ ++ if(index == i) { ++ return fmt; ++ } ++ } ++ ++ return NULL; ++} ++ ++ ++/* In irq context. */ ++static int mscaler_irq_notify_ch_done(struct mscaler_device *mscaler, int ch) ++{ ++ struct isp_video_buffer *isp_buffer = NULL; ++ unsigned int y_last_addr = 0; ++ unsigned int uv_last_addr = 0; ++ unsigned int y_frame_num = 0; ++ unsigned int uv_frame_num = 0; ++ unsigned int fifo_empty = 0; ++ unsigned int fifo_full = 0; ++ unsigned int y_fifo_st = 0, uv_fifo_st = 0; ++ dma_addr_t y_addr = 0; ++ dma_addr_t uv_addr = 0; ++ struct vb2_buffer *vb2_buf = NULL; ++ ++ //printk("------%s, ch: %d\n", __func__, ch); ++ ++ ++ spin_lock(&mscaler->lock); ++ /*由于mscaler stop streamæ—¶, ISP å¯èƒ½è¿˜ä¼šäº§ç”Ÿä¸­æ–­,这个时候ä¸ç”¨å¤„ç†*/ ++ if(mscaler->state[ch] == 0) { ++ spin_unlock(&mscaler->lock); ++ return 0; ++ } ++ ++ isp_buffer = list_first_entry_or_null(&mscaler->dma_queued_list[ch], struct isp_video_buffer, list_entry); ++ if(!isp_buffer) { ++ dev_err(mscaler->dev, "[warning] no isp_buffer found in dma_queued_list when interrupt happend!\n"); ++ spin_unlock(&mscaler->lock); ++ return 0; ++ } ++ ++ list_del(&isp_buffer->list_entry); ++ ++ ++ y_last_addr = mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_LAST_ADDR(ch)); ++ y_frame_num = mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_LAST_STATS_NUM(ch)); ++ ++ uv_last_addr = mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_LAST_ADDR(ch)); ++ uv_frame_num = mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_LAST_STATS_NUM(ch)); ++ ++ /*TODO Sequence.*/ ++ //if(isp_buffer->vb2.vb2_buf.state == VB2_BUF_STATE_ACTIVE) ++ isp_buffer->vb2.vb2_buf.timestamp = ktime_get_ns(); ++ isp_buffer->vb2.sequence = mscaler->framenum[ch]++; ++ ++#ifdef CONFIG_MSCA_BDEV ++ /*如果åŽç«¯è®¾å¤‡å­˜åœ¨ï¼Œåˆ™è°ƒç”¨ms_bdev_qbuf,交给åŽç«¯å¤„ç†.*/ ++ if(mscaler->bdev[ch].activated) { ++ ms_bdev_qbuf(&mscaler->bdev[ch], isp_buffer); ++ } else { ++ vb2_buffer_done(&isp_buffer->vb2.vb2_buf, VB2_BUF_STATE_DONE); ++ } ++#else ++ vb2_buffer_done(&isp_buffer->vb2.vb2_buf, VB2_BUF_STATE_DONE); ++#endif ++ ++ y_fifo_st = mscaler_reg_readl(mscaler, CHx_Y_ADDR_FIFO_STA(ch)); ++ uv_fifo_st = mscaler_reg_readl(mscaler, CHx_UV_ADDR_FIFO_STA(ch)); ++ ++ if((y_fifo_st & (1<<0)) && (uv_fifo_st & (1<<0))) { ++ fifo_empty = 1; ++ } else if((y_fifo_st & (1<<4)) || (uv_fifo_st & (1<<4))) { ++ fifo_full = 1; ++ } ++ ++ /* 如果stream on了,就写入硬件.*/ ++ if(mscaler->state[ch] == 1 && !fifo_full) { ++ isp_buffer = list_first_entry_or_null(&mscaler->dma_pending_list[ch], struct isp_video_buffer, list_entry); ++ if(isp_buffer){ ++ vb2_buf = &isp_buffer->vb2.vb2_buf; ++ /*Y*/ ++ y_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 0); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_ADDR(ch), y_addr); ++ ++ uv_addr = y_addr + isp_buffer->uv_offset; ++ /*UV*/ ++ if(vb2_buf->num_planes == 2) { ++ uv_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 1); ++ } ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_ADDR(ch), uv_addr); ++ list_del(&isp_buffer->list_entry); ++ list_add_tail(&isp_buffer->list_entry, &mscaler->dma_queued_list[ch]); ++ } ++ } ++ ++ spin_unlock(&mscaler->lock); ++ ++ return 0; ++} ++ ++static int mscaler_interrupt_service_routine(struct v4l2_subdev *sd, ++ u32 status, bool *handled) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ int ret = 0; ++ ++ /*åªç®¡å¿ƒ mscaler的三个chçš„done中断和crop出错的中断.*/ ++ if(status & (1 << MSCA_CH0_FRM_DONE_INT)) { ++ ret = mscaler_irq_notify_ch_done(mscaler, 0); ++ } ++ if(status & (1 << MSCA_CH1_FRM_DONE_INT)) { ++ ret = mscaler_irq_notify_ch_done(mscaler, 1); ++ } ++ ++ if(status & (1 << MSCA_CH2_FRM_DONE_INT)) { ++ ret = mscaler_irq_notify_ch_done(mscaler, 2); ++ } ++ ++ /*TODO: add handler.*/ ++ if(status & (1 << MSCA_CH0_CROP_ERR_INT)) { ++ ++ } ++ if(status & (1 << MSCA_CH1_CROP_ERR_INT)) { ++ ++ } ++ if(status & (1 << MSCA_CH2_CROP_ERR_INT)) { ++ ++ } ++ ++ return ret; ++} ++ ++static int mscaler_subdev_init(struct v4l2_subdev *sd, u32 val) ++{ ++ ++ return 0; ++} ++ ++static int mscaler_subdev_reset(struct v4l2_subdev *sd, u32 val) ++{ ++ return 0; ++} ++ ++static const struct v4l2_subdev_core_ops mscaler_subdev_core_ops = { ++ .init = mscaler_subdev_init, ++ .reset = mscaler_subdev_reset, ++ .log_status = v4l2_ctrl_subdev_log_status, ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++ .interrupt_service_routine = mscaler_interrupt_service_routine, ++}; ++ ++static unsigned int ch_to_pad[] = { ++ MSCALER_PAD_SOURCE_CH0, ++ MSCALER_PAD_SOURCE_CH1, ++ MSCALER_PAD_SOURCE_CH2 ++}; ++ ++static int pad_to_ch(int pad) ++{ ++ switch(pad) { ++ case MSCALER_PAD_SOURCE_CH0: ++ return 0; ++ case MSCALER_PAD_SOURCE_CH1: ++ return 1; ++ case MSCALER_PAD_SOURCE_CH2: ++ return 2; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int mscaler_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ //printk("------%s, %d, sd->name: %s\n", __func__, __LINE__, sd->name); ++ ++ if(code->index >= ARRAY_SIZE(mscaler_output_formats)) { ++ dev_err(sd->dev, "too many mbus formats!\n"); ++ return -EINVAL; ++ } ++ ++ code->code = mscaler_output_formats[code->index].mbus_code; ++ ++ return 0; ++} ++static int mscaler_enum_frame_size(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_frame_size_enum *fse) ++{ ++ int index = fse->index; ++ int num_valid = -1; ++ int i = 0; ++ if(index >= ARRAY_SIZE(ingenic_isp_framesizes)) ++ return -EINVAL; ++ ++ for(i = 0; i < ARRAY_SIZE(ingenic_isp_framesizes); i++) { ++ if(fse->code != ingenic_isp_framesizes[i].fourcc) ++ continue; ++ if(index == ++num_valid) { ++ fse->max_height = ingenic_isp_framesizes[i].discrete.height; ++ fse->min_height = fse->max_height; ++ fse->max_width = ingenic_isp_framesizes[i].discrete.width; ++ fse->min_width = fse->max_width; ++ return 0; ++ } ++ } ++ return -EINVAL; ++} ++ ++static int mscaler_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct v4l2_mbus_framefmt *framefmt = NULL; ++ //printk("------%s, %d, sd->name: %s\n", __func__, __LINE__, sd->name); ++ ++ if(format->which == V4L2_SUBDEV_FORMAT_TRY) { ++ framefmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); ++ } else { ++ framefmt = &mscaler->formats[format->pad].format; ++ } ++ ++ format->format = *framefmt; ++ ++ return 0; ++} ++ ++static int mscaler_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ struct v4l2_subdev_format remote_subdev_fmt; ++ struct isp_video_device *ispvideo = v4l2_get_subdev_hostdata(sd); ++ int ch = 0, i = 0, ret = 0; ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ if(ispvideo == &mscaler->ispvideo[i]) { ++ ch = i; ++ break; ++ } ++ } ++ ++ //printk("%s, %d, width: %d, height: %d, mbus_code: %x\n", __func__, __LINE__, format->format.width, format->format.height, format->format.code); ++ ++ mscaler->formats[format->pad] = *format; ++ ++ remote = media_entity_remote_pad(&mscaler->pads[MSCALER_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ ret = v4l2_subdev_call(remote_sd, pad, set_fmt, NULL, format); ++ if(ret < 0) { ++ dev_dbg(mscaler->dev, "Failed to set_fmt from remote pad\n"); ++ } ++ ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_err(mscaler->dev, "Failed to get_fmt from remote pad\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(&mscaler->formats[MSCALER_PAD_SINK], &remote_subdev_fmt, sizeof(struct v4l2_subdev_format)); ++ ++ /*def crop info.*/ ++ mscaler->sel[ch].r.left = 0; ++ mscaler->sel[ch].r.top = 0; ++ mscaler->sel[ch].r.width = format->format.width; ++ mscaler->sel[ch].r.height = format->format.height; ++ ++ return 0; ++} ++ ++static int mscaler_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct v4l2_subdev_format *output_fmt = NULL; ++ int ch = pad_to_ch(sel->pad); ++ ++ if(ch < 0) ++ return -EINVAL; ++ ++ output_fmt = &mscaler->formats[sel->pad]; ++ if(sel->target == V4L2_SEL_TGT_CROP || sel->target == V4L2_SEL_TGT_CROP_DEFAULT){ ++ memcpy(&sel->r, &mscaler->sel[ch].r, sizeof(struct v4l2_rect)); ++ } else if(sel->target == V4L2_SEL_TGT_CROP_BOUNDS) { ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = output_fmt->format.width; ++ sel->r.height = output_fmt->format.height; ++ } else { ++ dev_warn(mscaler->dev, "unsupported selection target!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int mscaler_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct v4l2_subdev_format *output_fmt = NULL; ++ int ch = pad_to_ch(sel->pad); ++ ++ if(ch < 0) ++ return -EINVAL; ++ ++ if(sel->flags == V4L2_SEL_FLAG_GE) { ++ dev_warn(mscaler->dev, "unsupported selection flags!\n"); ++ return -EINVAL; ++ } ++ ++ output_fmt = &mscaler->formats[sel->pad]; ++ if(sel->r.top + sel->r.height > output_fmt->format.height || ++ sel->r.left + sel->r.width > output_fmt->format.width) { ++ dev_warn(mscaler->dev, "selection out of range! please check the boundry.\n"); ++ return -EINVAL; ++ } ++ ++ if(sel->target == V4L2_SEL_TGT_CROP){ ++ memcpy(&mscaler->sel[ch].r, &sel->r, sizeof(struct v4l2_rect)); ++ } else { ++ dev_warn(mscaler->dev, "unsupported selection target!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++ ++static const struct v4l2_subdev_pad_ops mscaler_subdev_pad_ops = { ++ .enum_mbus_code = mscaler_enum_mbus_code, ++ .enum_frame_size = mscaler_enum_frame_size, ++ .get_fmt = mscaler_get_fmt, ++ .set_fmt = mscaler_set_fmt, ++ .get_selection = mscaler_get_selection, ++ .set_selection = mscaler_set_selection, ++}; ++ ++static int mscaler_stream_enable(struct mscaler_device *mscaler, int ch) ++{ ++ struct v4l2_subdev_format *input_fmt = &mscaler->formats[MSCALER_PAD_SINK]; ++ struct v4l2_subdev_format *output_fmt = &mscaler->formats[ch_to_pad[ch]]; ++ unsigned long flags = 0; ++ unsigned int step_w = 0, step_h = 0; ++ unsigned int val = 0; ++ int ret = 0; ++ struct isp_video_buffer *isp_buffer = NULL; ++ struct isp_video_buffer *tmp = NULL; ++ dma_addr_t y_addr = 0; ++ dma_addr_t uv_addr = 0; ++ unsigned int fifo_empty = 0; ++ unsigned int fifo_full = 0; ++ unsigned int y_fifo_st = 0, uv_fifo_st = 0; ++ struct vb2_buffer *vb2_buf = NULL; ++ ++ dev_dbg(mscaler->dev, "-----input_fmt->format.width: %d, input_fmt->format.height: %d\n", input_fmt->format.width, input_fmt->format.height); ++ dev_dbg(mscaler->dev, "-----output_fmt->format.width: %d, output_fmt->format.height: %d\n", output_fmt->format.width, output_fmt->format.height); ++ ++ spin_lock_irqsave(&mscaler->lock, flags); ++ /*1. mscaler_hw_configure.*/ ++ mscaler_reg_writel(mscaler, CHx_RSZ_OSIZE(ch), (output_fmt->format.width << 16) | (output_fmt->format.height)); ++ ++ step_w = input_fmt->format.width * 512 / output_fmt->format.width; ++ step_h = input_fmt->format.height * 512 / output_fmt->format.height; ++ ++ mscaler_reg_writel(mscaler, CHx_RSZ_STEP(ch), step_w << 16 | step_h); ++ ++ /*Crop info.*/ ++ mscaler_reg_writel(mscaler, CHx_CROP_OPOS(ch), (mscaler->sel[ch].r.left << 16) | mscaler->sel[ch].r.top); ++ mscaler_reg_writel(mscaler, CHx_CROP_OSIZE(ch), (mscaler->sel[ch].r.width << 16) | mscaler->sel[ch].r.height); ++ ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_STRI(ch), mscaler->sel[ch].r.width); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_STRI(ch), mscaler->sel[ch].r.width); ++ ++ val = mscaler_reg_readl(mscaler, MSCA_DMAOUT_ARB); ++ val |= 1 << (ch + 1); ++ mscaler_reg_writel(mscaler, MSCA_DMAOUT_ARB, val); ++ ++ /*output fmt set*/ ++ switch(output_fmt->format.code){ ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ val = CHx_OUT_FMT_NV12; ++ break; ++ case MEDIA_BUS_FMT_YVYU8_2X8: ++ val = CHx_OUT_FMT_NV21; ++ break; ++ case MEDIA_BUS_FMT_Y8_1X8: ++ val = CHx_OUT_FMT_NV12; ++ val |= CHx_OUT_FMT_Y_OUT_ONLY; ++ break; ++#ifdef CONFIG_MSCA_BDEV ++ case MEDIA_BUS_FMT_JPEG_1X8: ++ val = CHx_OUT_FMT_NV12; ++ ++ mscaler->bdev[ch].width = output_fmt->format.width; ++ mscaler->bdev[ch].height = output_fmt->format.height; ++ //mscaler->bdev[ch].fmt = CHx_OUT_FMT_NV12; ++ mscaler->bdev[ch].ch = ch; ++ mscaler->bdev[ch].dev = mscaler->dev; ++ mscaler->bdev[ch].activated = 1; // 使用bdev进行格å¼è½¬æ¢. ++ break; ++ // case MEDIA_BUS_FMT_RGB565_1X16: ++ // val = CHx_OUT_FMT_RGB565; ++ // break; ++ // case MEDIA_BUS_FMT_ARGB8888_1X32: ++ // val = CHx_OUT_FMT_ARGB8888; ++ // break; ++#endif ++ default: ++ printk("output format not supported!\n"); ++ } ++ if(mscaler->yonly_cf[ch].yonly_enable) { ++ val |= CHx_OUT_FMT_Y_OUT_ONLY; ++ } ++ mscaler_reg_writel(mscaler, CHx_OUT_FMT(ch), val); ++ ++ ++ /*2. mscaler_hw_start*/ ++ val = mscaler_reg_readl(mscaler, MSCA_CH_EN); ++ val |= 1 << ch; ++ val |= (1 << 8) << ch; //fix_vrsz_en ++ val |= (1 << 11) << ch; //fix_hrsz_en ++ mscaler_reg_writel(mscaler, MSCA_CH_EN, val); ++ ++ mscaler->state[ch] = 1; ++ mscaler->framenum[ch] = 0; ++ ++ /*因为ISPå¤ä½çš„æ‰§è¡Œæ—¶é—´æ—¶åœ¨stream_on的时候,这个时候上层qbufå·²ç»è°ƒç”¨äº†ï¼Œ ++ * 如果部将这些buffer釿–°åŠ å…¥ç¡¬ä»¶é˜Ÿåˆ—ï¼Œåˆ™ä¼šå‡ºçŽ°é—®é¢˜.*/ ++ list_for_each_entry_safe(isp_buffer, tmp, &mscaler->dma_pending_list[ch], list_entry) { ++ y_fifo_st = mscaler_reg_readl(mscaler, CHx_Y_ADDR_FIFO_STA(ch)); ++ uv_fifo_st = mscaler_reg_readl(mscaler, CHx_UV_ADDR_FIFO_STA(ch)); ++ if((y_fifo_st & (1<<0)) && (uv_fifo_st & (1<<0))) { ++ fifo_empty = 1; ++ } else if((y_fifo_st & (1<<4)) || (uv_fifo_st & (1<<4))) { ++ fifo_full = 1; ++ } ++ if(fifo_full) ++ break; ++ ++ vb2_buf = &isp_buffer->vb2.vb2_buf; ++ /*Y*/ ++ y_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 0); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_ADDR(ch), y_addr); ++ ++ uv_addr = y_addr + isp_buffer->uv_offset; ++ if(vb2_buf->num_planes == 2) { ++ uv_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 1); ++ } ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_ADDR(ch), uv_addr); ++ list_del(&isp_buffer->list_entry); ++ list_add_tail(&isp_buffer->list_entry, &mscaler->dma_queued_list[ch]); ++ } ++ ++ spin_unlock_irqrestore(&mscaler->lock, flags); ++ ++#ifdef CONFIG_MSCA_BDEV ++ if(mscaler->bdev[ch].activated == 1) { ++ ret = ms_bdev_init(&mscaler->bdev[ch]); ++ if(ret < 0) { ++ return -EINVAL; ++ } ++ } ++#endif ++ ++ return ret; ++} ++ ++static int mscaler_stream_disable(struct mscaler_device *mscaler, int ch) ++{ ++ unsigned long flags = 0; ++ unsigned int val = 0; ++ int ret = 0; ++ unsigned int timeout = 0xffffff; ++ struct isp_video_buffer *isp_buffer = NULL; ++ struct isp_video_buffer *tmp = NULL; ++ ++ ++ spin_lock_irqsave(&mscaler->lock, flags); ++ ++ val = mscaler_reg_readl(mscaler, MSCA_CH_EN); ++ val &= ~(1 << ch); ++ mscaler_reg_writel(mscaler, MSCA_CH_EN, val); ++ ++ spin_unlock_irqrestore(&mscaler->lock, flags); ++ ++ /* polling status to make sure channel stopped.*/ ++ do { ++ val = mscaler_reg_readl(mscaler, MSCA_CH_STA); ++ ++ } while(!!((val & (1<dev, "[Warning] mscaler disable timeout!\n"); ++ } ++ ++ spin_lock_irqsave(&mscaler->lock, flags); ++ ++ /* clear fifo*/ ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_ADDR_CLR(ch), 1); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_ADDR_CLR(ch), 1); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_LAST_ADDR_CLR(ch), 1); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_LAST_ADDR_CLR(ch), 1); ++ ++ ++ list_for_each_entry_safe(isp_buffer, tmp, &mscaler->dma_queued_list[ch], list_entry) { ++ struct vb2_buffer *vb2_buf = &isp_buffer->vb2.vb2_buf; ++ vb2_buffer_done(vb2_buf, VB2_BUF_STATE_ERROR); ++ list_del(&isp_buffer->list_entry); ++ } ++ list_for_each_entry_safe(isp_buffer, tmp, &mscaler->dma_pending_list[ch], list_entry) { ++ struct vb2_buffer *vb2_buf = &isp_buffer->vb2.vb2_buf; ++ vb2_buffer_done(vb2_buf, VB2_BUF_STATE_ERROR); ++ list_del(&isp_buffer->list_entry); ++ } ++ ++ ++ mscaler->state[ch] = 0; ++ spin_unlock_irqrestore(&mscaler->lock, flags); ++ ++#ifdef CONFIG_MSCA_BDEV ++ if(mscaler->bdev[ch].activated) { ++ ms_bdev_deinit(&mscaler->bdev[ch]); ++ mscaler->bdev[ch].activated = 0; ++ } ++#endif ++ ++ return ret; ++} ++ ++static int mscaler_subdev_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct mscaler_device *mscaler = v4l2_get_subdevdata(sd); ++ struct isp_video_device *ispvideo = v4l2_get_subdev_hostdata(sd); ++ int ch = 0; ++ int i = 0, ret = 0; ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ if(ispvideo == &mscaler->ispvideo[i]) { ++ ch = i; ++ break; ++ } ++ } ++ ++// printk("%s,%d, sd->video_device->name:%s, ispvideo: %p, ch = %d, enable = %d\n", __func__, __LINE__, sd->devnode->name, ispvideo, ch, enable); ++ /*获å–当å‰channel.*/ ++ if(enable) { ++ ret = mscaler_stream_enable(mscaler, ch); ++ //dump_mscaler_regs(mscaler); ++ } else { ++ ret = mscaler_stream_disable(mscaler, ch); ++ } ++ ++ if(ret < 0) { ++ dev_err(mscaler->dev, "enable stream error!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++ ++static const struct v4l2_subdev_video_ops mscaler_subdev_video_ops = { ++ .s_stream = mscaler_subdev_s_stream, ++}; ++ ++ ++static const struct v4l2_subdev_ops mscaler_subdev_ops = { ++ .core = &mscaler_subdev_core_ops, ++ .pad = &mscaler_subdev_pad_ops, ++ .video = &mscaler_subdev_video_ops, ++}; ++ ++ ++static int mscaler_video_qbuf(struct isp_video_device *ispvideo, struct isp_video_buffer *isp_buffer) ++{ ++ struct mscaler_device *mscaler = ispvideo->ispcam->mscaler; ++ struct vb2_buffer *vb2_buf = NULL; ++ int ch = 0; ++ unsigned long flags = 0; ++ unsigned int fifo_empty = 0; ++ unsigned int fifo_full = 0; ++ unsigned int y_fifo_st = 0, uv_fifo_st = 0; ++ dma_addr_t y_addr = 0; ++ dma_addr_t uv_addr = 0; ++ unsigned char *virt_uv_addr = NULL; ++ unsigned int uv_size = 0; ++ unsigned int uv_value; ++ ++ int i = 0; ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ if(ispvideo == &mscaler->ispvideo[i]) { ++ ch = i; ++ break; ++ } ++ } ++ ++ spin_lock_irqsave(&mscaler->lock, flags); ++ ++ list_add_tail(&isp_buffer->list_entry, &mscaler->dma_pending_list[ch]); ++ ++ y_fifo_st = mscaler_reg_readl(mscaler, CHx_Y_ADDR_FIFO_STA(ch)); ++ uv_fifo_st = mscaler_reg_readl(mscaler, CHx_UV_ADDR_FIFO_STA(ch)); ++ ++ if((y_fifo_st & (1<<0)) && (uv_fifo_st & (1<<0))) { ++ fifo_empty = 1; ++ } else if((y_fifo_st & (1<<4)) || (uv_fifo_st & (1<<4))) { ++ fifo_full = 1; ++ } ++ ++ uv_value = mscaler->yonly_cf[ch].uv_value ; ++ /* 如果stream on了,就写入硬件.*/ ++ if(mscaler->state[ch] == 1 && !fifo_full) { ++ isp_buffer = list_first_entry_or_null(&mscaler->dma_pending_list[ch], struct isp_video_buffer, list_entry); ++ vb2_buf = &isp_buffer->vb2.vb2_buf; ++ /*Y*/ ++ y_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 0); ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_Y_ADDR(ch), y_addr); ++ ++ /*UV*/ ++ if(vb2_buf->num_planes == 2) { ++ uv_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 1); ++ virt_uv_addr = vb2_plane_vaddr(vb2_buf, 1); ++ uv_size = vb2_plane_size(vb2_buf, 1); ++ } else { ++ uv_addr = y_addr + isp_buffer->uv_offset; ++ virt_uv_addr = vb2_plane_vaddr(vb2_buf, 0) + isp_buffer->uv_offset; ++ uv_size = vb2_plane_size(vb2_buf, 0) - isp_buffer->uv_offset; ++ } ++ ++ if(mscaler->yonly_cf[ch].yonly_enable) { ++ if( isp_buffer->uv_value_backup[ch] != uv_value) ++ isp_buffer->uv_value_filled = 0; ++ if(!isp_buffer->uv_value_filled) { ++ memset(virt_uv_addr, uv_value, uv_size); ++ isp_buffer->uv_value_backup[ch] = uv_value; ++ isp_buffer->uv_value_filled = 1; ++ } ++ } else { ++ if(isp_buffer->uv_value_filled) ++ isp_buffer->uv_value_filled = 0; ++ } ++ ++ mscaler_reg_writel(mscaler, CHx_DMAOUT_UV_ADDR(ch), uv_addr); ++ list_del(&isp_buffer->list_entry); ++ list_add_tail(&isp_buffer->list_entry, &mscaler->dma_queued_list[ch]); ++ } ++ ++ spin_unlock_irqrestore(&mscaler->lock, flags); ++ ++ //printk("-----%s,%d queued buffer y_addr: 0x%08x, uv: 0x%08x on ch: %d\n", __func__, __LINE__, y_addr, uv_addr, ch); ++ ++ return 0; ++} ++ ++static const struct isp_video_ops mscaler_video_ops = { ++ .find_format = mscaler_find_format, ++ .qbuf = mscaler_video_qbuf, ++}; ++ ++static ssize_t ++dump_mscaler(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = dev_get_drvdata(dev); ++ char *p = buf; ++ int i = 0; ++ ++ p += sprintf(p, "MSCA_CTRL :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_CTRL)); ++ p += sprintf(p, "MSCA_CH_EN :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_CH_EN)); ++ p += sprintf(p, "MSCA_CH_STA :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_CH_STA)); ++ p += sprintf(p, "MSCA_INT_STA :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_INT_STA)); ++ p += sprintf(p, "MSCA_INT_MSK :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_INT_MSK)); ++ p += sprintf(p, "MSCA_INT_CLR :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_INT_CLR)); ++ p += sprintf(p, "MSCA_DMAOUT_ARB:0x%08x\n", mscaler_reg_readl(mscaler, MSCA_DMAOUT_ARB)); ++ p += sprintf(p, "MSCA_CLK_GATE_EN:0x%08x\n", mscaler_reg_readl(mscaler, MSCA_CLK_GATE_EN)); ++ p += sprintf(p, "MSCA_CLK_DIS :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_CLK_DIS)); ++ p += sprintf(p, "MSCA_SRC_IN :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_SRC_IN)); ++ p += sprintf(p, "MSCA_SRC_SIZE :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_SRC_SIZE)); ++ p += sprintf(p, "MSCA_GLO_RSZ_COEF_WR:0x%08x\n", mscaler_reg_readl(mscaler, MSCA_GLO_RSZ_COEF_WR)); ++ p += sprintf(p, "MSCA_SYS_PRO_CLK_EN :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_SYS_PRO_CLK_EN)); ++ p += sprintf(p, "MSCA_DS0_CLK_NUM :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_DS0_CLK_NUM)); ++ p += sprintf(p, "MSCA_DS1_CLK_NUM :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_DS1_CLK_NUM)); ++ p += sprintf(p, "MSCA_DS2_CLK_NUM :0x%08x\n", mscaler_reg_readl(mscaler, MSCA_DS2_CLK_NUM)); ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ ++ p += sprintf(p, "CHx_RSZ_OSIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_RSZ_OSIZE(i))); ++ p += sprintf(p, "CHx_RSZ_STEP(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_RSZ_STEP(i))); ++ p += sprintf(p, "CHx_CROP_OPOS(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_CROP_OPOS(i))); ++ p += sprintf(p, "CHx_CROP_OSIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_CROP_OSIZE(i))); ++ p += sprintf(p, "CHx_FRA_CTRL_LOOP(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_FRA_CTRL_LOOP(i))); ++ p += sprintf(p, "CHx_FRA_CTRL_MASK(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_FRA_CTRL_MASK(i))); ++ p += sprintf(p, "CHx_MS0_POS(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS0_POS(i))); ++ p += sprintf(p, "CHx_MS0_SIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS0_SIZE(i))); ++ p += sprintf(p, "CHx_MS0_VALUE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS0_VALUE(i))); ++ p += sprintf(p, "CHx_MS1_POS(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS1_POS(i))); ++ p += sprintf(p, "CHx_MS1_SIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS1_SIZE(i))); ++ p += sprintf(p, "CHx_MS1_VALUE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS1_VALUE(i))); ++ p += sprintf(p, "CHx_MS2_POS(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS2_POS(i))); ++ p += sprintf(p, "CHx_MS2_SIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS2_SIZE(i))); ++ p += sprintf(p, "CHx_MS2_VALUE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS2_VALUE(i))); ++ p += sprintf(p, "CHx_MS3_POS(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS3_POS(i))); ++ p += sprintf(p, "CHx_MS3_SIZE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS3_SIZE(i))); ++ p += sprintf(p, "CHx_MS3_VALUE(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_MS3_VALUE(i))); ++ p += sprintf(p, "CHx_OUT_FMT(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_OUT_FMT(i))); ++ p += sprintf(p, "CHx_DMAOUT_Y_ADDR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_ADDR(i))); ++ p += sprintf(p, "CHx_Y_ADDR_FIFO_STA(%d):0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_Y_ADDR_FIFO_STA(i))); ++ // p += sprintf(p, "CHx_DMAOUT_Y_LAST_ADDR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_LAST_ADDR(i))); ++ // p += sprintf(p, "CHx_DMAOUT_Y_LAST_STATS_NUM(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_LAST_STATS_NUM(i))); ++ p += sprintf(p, "CHx_Y_LAST_ADDR_FIFO_STA(%d):0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_Y_LAST_ADDR_FIFO_STA(i))); ++ p += sprintf(p, "CHx_DMAOUT_Y_STRI(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_STRI(i))); ++ p += sprintf(p, "CHx_DMAOUT_UV_ADDR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_ADDR(i))); ++ p += sprintf(p, "CHx_UV_ADDR_FIFO_STA(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_UV_ADDR_FIFO_STA(i))); ++ // p += sprintf(p, "CHx_DMAOUT_UV_LAST_ADDR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_LAST_ADDR(i))); ++ // p += sprintf(p, "CHx_DMAOUT_UV_LAST_STATS_NUM(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_LAST_STATS_NUM(i))); ++ p += sprintf(p, "CHx_UV_LAST_ADDR_FIFO_STA(%d):0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_UV_LAST_ADDR_FIFO_STA(i))); ++ p += sprintf(p, "CHx_DMAOUT_UV_STRI(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_STRI(i))); ++ p += sprintf(p, "CHx_DMAOUT_Y_ADDR_CLR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_ADDR_CLR(i))); ++ p += sprintf(p, "CHx_DMAOUT_UV_ADDR_CLR(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_ADDR_CLR(i))); ++ p += sprintf(p, "CHx_DMAOUT_Y_LAST_ADDR_CLR(%d):0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_LAST_ADDR_CLR(i))); ++ p += sprintf(p, "CHx_DMAOUT_UV_LAST_ADDR_CLR(%d):0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_LAST_ADDR_CLR(i))); ++ p += sprintf(p, "CHx_DMAOUT_Y_ADDR_SEL(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_Y_ADDR_SEL(i))); ++ p += sprintf(p, "CHx_DMAOUT_UV_ADDR_SEL(%d) :0x%08x\n", i, mscaler_reg_readl(mscaler, CHx_DMAOUT_UV_ADDR_SEL(i))); ++ } ++ ++ return p - buf; ++} ++ ++ ++static DEVICE_ATTR(dump_mscaler, S_IRUGO|S_IWUSR, dump_mscaler, NULL); ++ ++static struct attribute *mscaler_debug_attrs[] = { ++ &dev_attr_dump_mscaler.attr, ++ NULL, ++}; ++ ++static struct attribute_group mscaler_debug_attr_group = { ++ .name = "debug", ++ .attrs = mscaler_debug_attrs, ++}; ++ ++ ++#define to_mscaler_device(kobj) dev_get_drvdata(container_of(kobj->parent->parent, struct device, kobj)) ++ ++static ssize_t uv_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch = kobj->name[2] - '0'; ++ char *p = buf; ++ unsigned int uv_value= mscaler->yonly_cf[ch].uv_value ; ++ ++ p += sprintf(p, "0x%x\n", uv_value); ++ ++ return p - buf; ++} ++ ++static ssize_t uv_value_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch = kobj->name[2] - '0'; ++ mscaler->yonly_cf[ch].uv_value = simple_strtol(buf, NULL, 10); ++ ++ return count; ++} ++ ++static struct kobj_attribute uv_value_attribute = ++__ATTR(uv_value,S_IRUGO|S_IWUSR, uv_value_show, uv_value_store); ++ ++static ssize_t yonly_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch = kobj->name[2] - '0'; ++ char *p = buf; ++ unsigned int enable= mscaler->yonly_cf[ch].yonly_enable ; ++ ++ p += sprintf(p, "%d\n", enable); ++ ++ return p - buf; ++} ++ ++static ssize_t yonly_enable_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch = kobj->name[2] - '0'; ++ struct v4l2_subdev_format *output_fmt = &mscaler->formats[ch_to_pad[ch]]; ++ int enable = simple_strtol(buf, NULL, 10); ++ unsigned int val = 0; ++ ++ if(enable == 1) ++ mscaler->yonly_cf[ch].yonly_enable=1; ++ else if(enable == 0) ++ mscaler->yonly_cf[ch].yonly_enable=0; ++ else ++ return -EINVAL; ++ ++ if((output_fmt->format.code != MEDIA_BUS_FMT_YUYV8_2X8) ++ && (output_fmt->format.code != MEDIA_BUS_FMT_YVYU8_2X8)) { ++ /*åªè®°å½•enable状æ€ï¼Œæ­¤æ—¶å¯èƒ½æ²¡æœ‰start_streaming, ä¸èƒ½ç¡®å®šæ ¼å¼.*/ ++ return count; ++ } ++ ++ val = mscaler_reg_readl(mscaler, CHx_OUT_FMT(ch)); ++ if(enable) { ++ val |= CHx_OUT_FMT_Y_OUT_ONLY; ++ } else { ++ val &= ~(CHx_OUT_FMT_Y_OUT_ONLY); ++ } ++ mscaler_reg_writel(mscaler, CHx_OUT_FMT(ch), val); ++ ++ return count; ++} ++ ++static struct kobj_attribute yonly_enable_attribute = ++__ATTR(enable,S_IRUGO|S_IWUSR, yonly_enable_show, yonly_enable_store); ++ ++static ssize_t mask_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch = kobj->name[2] - '0'; ++ char *p = buf; ++ unsigned int tmp = 0; ++ ++ tmp = mscaler_reg_readl(mscaler, MSCA_CH_EN); ++ p += sprintf(p, "%d\n", (tmp >> (ch + 3)) & 1); ++ ++ return p - buf; ++} ++ ++static ssize_t mask_enable_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch = kobj->name[2] - '0'; ++ unsigned int tmp = 0; ++ int enable = simple_strtol(buf, NULL, 10); ++ ++ tmp = mscaler_reg_readl(mscaler, MSCA_CH_EN); ++ if(enable == 1) ++ tmp |= 1 << (ch + 3); ++ else if(enable == 0) ++ tmp &= ~(1 << (ch + 3)); ++ else ++ return -EINVAL; ++ ++ mscaler_reg_writel(mscaler, MSCA_CH_EN, tmp); ++ return count; ++} ++ ++static struct kobj_attribute enable_attribute = ++__ATTR(enable,S_IRUGO|S_IWUSR, mask_enable_show, mask_enable_store); ++ ++ ++static ssize_t mask_pos_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p = buf; ++ unsigned int tmp = 0; ++ ++ tmp = mscaler_reg_readl(mscaler, CHx_MSx_POS(ch,mask)); ++ p += sprintf(p, "x:%d\ty:%d\n", tmp >> 16, tmp & 0xffff); ++ ++ return p - buf; ++} ++ ++static ssize_t mask_pos_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p; ++ char *s = (char *)buf; ++ int pos_x, pos_y; ++ ++ p = strsep(&s, "*"); ++ if(!s) { ++ return -EINVAL; ++ } ++ ++ pos_x = simple_strtoul(p, NULL, 10); ++ pos_y = simple_strtoul(s, NULL, 10); ++ ++ mscaler_reg_writel(mscaler, CHx_MSx_POS(ch,mask), (pos_x << 16) | pos_y); ++ return count; ++} ++ ++static ssize_t mask_size_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p = buf; ++ unsigned int tmp = 0; ++ ++ tmp = mscaler_reg_readl(mscaler, CHx_MSx_SIZE(ch,mask)); ++ p += sprintf(p, "width:%d\theight:%d\n", tmp >> 16, tmp & 0xffff); ++ ++ return p - buf; ++} ++ ++static ssize_t mask_size_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p; ++ char *s = (char *)buf; ++ int width, height; ++ ++ p = strsep(&s, "*"); ++ if(!s) { ++ return -EINVAL; ++ } ++ ++ width = simple_strtoul(p, NULL, 10); ++ height = simple_strtoul(s, NULL, 10); ++ ++ mscaler_reg_writel(mscaler, CHx_MSx_SIZE(ch,mask), (width << 16) | height); ++ return count; ++} ++static ssize_t mask_color_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p = buf; ++ unsigned int tmp = 0; ++ ++ tmp = mscaler_reg_readl(mscaler, CHx_MSx_VALUE(ch,mask)); ++ p += sprintf(p, "0x%08x\n", tmp); ++ ++ return p - buf; ++} ++ ++static ssize_t mask_color_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ struct mscaler_device *mscaler = to_mscaler_device(kobj); ++ int ch= kobj->name[2] - '0'; ++ int mask = to_mask_attr(attr)->id; ++ char *p; ++ char *s = (char *)buf; ++ int value = 0; ++ ++ p = strsep(&s, "x"); ++ if(!s) { ++ return -EINVAL; ++ } ++ ++ value = simple_strtoul(s, NULL, 16); ++ ++ mscaler_reg_writel(mscaler, CHx_MSx_VALUE(ch,mask), value); ++ return count; ++ return count; ++} ++ ++#define MASK_ATTR(mask, _name, _mode, _show, _store) \ ++{ \ ++ .attr = __ATTR(_name, _mode, _show, _store), \ ++ .id = mask, \ ++} ++ ++ ++#define MASK_ATTRIBUTE(_name, _mode, _show, _store) \ ++ static struct mask_kobj_attr kobj_attr_##_name##mask0 = MASK_ATTR(0, _name, _mode, _show, _store); \ ++ static struct mask_kobj_attr kobj_attr_##_name##mask1 = MASK_ATTR(1, _name, _mode, _show, _store); \ ++ static struct mask_kobj_attr kobj_attr_##_name##mask2 = MASK_ATTR(2, _name, _mode, _show, _store); \ ++ static struct mask_kobj_attr kobj_attr_##_name##mask3 = MASK_ATTR(3, _name, _mode, _show, _store) ++ ++MASK_ATTRIBUTE(pos, S_IRUGO|S_IWUSR, mask_pos_show, mask_pos_store); ++MASK_ATTRIBUTE(size, S_IRUGO|S_IWUSR, mask_size_show, mask_size_store); ++MASK_ATTRIBUTE(color, S_IRUGO|S_IWUSR, mask_color_show, mask_color_store); ++ ++#define MASK_ATTRIBUTE_GROUP(name) \ ++ static struct attribute *mscaler_##name##_attrs[] = { \ ++ &kobj_attr_pos##name.attr.attr, \ ++ &kobj_attr_size##name.attr.attr, \ ++ &kobj_attr_color##name.attr.attr, \ ++ NULL, \ ++ }; ++ ++MASK_ATTRIBUTE_GROUP(mask0); ++MASK_ATTRIBUTE_GROUP(mask1); ++MASK_ATTRIBUTE_GROUP(mask2); ++MASK_ATTRIBUTE_GROUP(mask3); ++ ++ ++static struct attribute_group mscaler_mask0_group = { ++ .name = "mask0", ++ .attrs = mscaler_mask0_attrs, ++}; ++static struct attribute_group mscaler_mask1_group = { ++ .name = "mask1", ++ .attrs = mscaler_mask1_attrs, ++}; ++static struct attribute_group mscaler_mask2_group = { ++ .name = "mask2", ++ .attrs = mscaler_mask2_attrs, ++}; ++static struct attribute_group mscaler_mask3_group = { ++ .name = "mask3", ++ .attrs = mscaler_mask3_attrs, ++}; ++ ++ ++static const struct attribute_group *mscaler_maskx_groups[] = { ++ &mscaler_mask0_group, ++ &mscaler_mask1_group, ++ &mscaler_mask2_group, ++ &mscaler_mask3_group, ++ NULL, ++}; ++ ++static void __maybe_unused dump_mscaler_regs(struct mscaler_device *mscaler) ++{ ++ char *buf = kzalloc(4 * 1024, GFP_KERNEL); ++ int ret = 0; ++ ++ ret = dump_mscaler(mscaler->dev, NULL, buf); ++ ++ printk("%s", buf); ++ ++ kfree(buf); ++} ++ ++int mscaler_video_nr_map[2][3] = { ++ {INGENIC_MSCA0_CH0_VIDEO_NR, INGENIC_MSCA0_CH1_VIDEO_NR, INGENIC_MSCA0_CH2_VIDEO_NR}, ++ {INGENIC_MSCA1_CH0_VIDEO_NR, INGENIC_MSCA1_CH1_VIDEO_NR, INGENIC_MSCA1_CH2_VIDEO_NR}, ++ ++}; ++ ++static int mscaler_comp_bind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct mscaler_device *mscaler = dev_get_drvdata(comp); ++ struct ispcam_device *ispcam = (struct ispcam_device *)master_data; ++ struct v4l2_device *v4l2_dev = &ispcam->v4l2_dev; ++ struct v4l2_subdev *sd = &mscaler->sd; ++ int i = 0; ++ int ret = 0; ++ int nr = -1; ++ ++ //dev_info(comp, "----dev_name(comp): %s----%s, %d \n", dev_name(comp), __func__, __LINE__); ++ ++ /* link subdev to master.*/ ++ mscaler->ispcam = (void *)ispcam; ++ ispcam->mscaler = mscaler; ++ ++ /*1. register supported subdev ctrls.*/ ++ ++ ++ /*2. init v4l2_subdev*/ ++ ++ v4l2_subdev_init(sd, &mscaler_subdev_ops); ++ ++ sd->owner = THIS_MODULE; ++ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ strscpy(sd->name, dev_name(comp), sizeof(sd->name)); ++ v4l2_set_subdevdata(sd, mscaler); ++ ++ ++ /* init mscaler pads. */ ++ mscaler->pads = kzalloc(sizeof(struct media_pad) * MSCALER_NUM_PADS, GFP_KERNEL); ++ if(!mscaler->pads) { ++ ret = -ENOMEM; ++ goto err_alloc_pads; ++ } ++ mscaler->pads[0].index = MSCALER_PAD_SINK; ++ mscaler->pads[0].flags = MEDIA_PAD_FL_SINK; ++ mscaler->pads[1].index = MSCALER_PAD_SOURCE_CH0; ++ mscaler->pads[1].flags = MEDIA_PAD_FL_SOURCE; ++ mscaler->pads[2].index = MSCALER_PAD_SOURCE_CH1; ++ mscaler->pads[2].flags = MEDIA_PAD_FL_SOURCE; ++ mscaler->pads[3].index = MSCALER_PAD_SOURCE_CH2; ++ mscaler->pads[3].flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&sd->entity, MSCALER_NUM_PADS, mscaler->pads); ++ ++ /*3. register v4l2_subdev*/ ++ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; ++ ret = v4l2_device_register_subdev(v4l2_dev, sd); ++ if(ret < 0) { ++ dev_err(comp, "Failed to register v4l2_subdev for mscaler\n"); ++ goto err_subdev_register; ++ } ++ ++ /*create mask dir*/ ++ mscaler->mask_kobj = kobject_create_and_add("mask", &mscaler->dev->kobj); ++ if (!mscaler->mask_kobj) { ++ dev_err(mscaler->dev, "device create kobject failed\n"); ++ ret = -EINVAL; ++ goto err_mask_kobj; ++ } ++ mscaler->yonly_kobj = kobject_create_and_add("yonly", &mscaler->dev->kobj); ++ if (!mscaler->yonly_kobj) { ++ dev_err(mscaler->dev, "device create kobject failed\n"); ++ ret = -EINVAL; ++ goto err_yonly_kobj; ++ } ++ ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ struct isp_video_device *ispvideo = &mscaler->ispvideo[i]; ++ char name[32]; ++ sprintf(name, "%s-ch%d", dev_name(mscaler->dev), i); ++ ++ ispvideo->ispcam = ispcam; ++ ispvideo->video.v4l2_dev = &ispcam->v4l2_dev; ++ ret = isp_video_init(ispvideo, name, &mscaler_video_ops); ++ if(ret < 0){ ++ /*TODO*/ ++ } ++ ++ nr = mscaler_video_nr_map[ispcam->dev_nr][i]; ++ ret = isp_video_register(ispvideo, &ispcam->v4l2_dev, nr); ++ if(ret < 0){ ++ /*TODO*/ ++ } ++ ++ /*create mask/chx dir*/ ++ sprintf(name, "ch%d", i); ++ mscaler->mask_ch_kobj[i] = kobject_create_and_add(name, mscaler->mask_kobj); ++ if (!mscaler->mask_ch_kobj[i]) { ++ dev_err(mscaler->dev, "device create kobject failed\n"); ++ ret = -EINVAL; ++ goto err_mask_ch_kobj; ++ } ++ ++ /*create yonly/chx dir*/ ++ sprintf(name, "ch%d", i); ++ mscaler->yonly_ch_kobj[i] = kobject_create_and_add(name, mscaler->yonly_kobj); ++ if (!mscaler->yonly_ch_kobj[i]) { ++ dev_err(mscaler->dev, "device create kobject failed\n"); ++ ret = -EINVAL; ++ goto err_yonly_ch_kobj; ++ } ++ ++ /*create enable attr*/ ++ ret = sysfs_create_file(mscaler->mask_ch_kobj[i], &enable_attribute.attr); ++ if(ret){ ++ dev_err(mscaler->dev, "device create sys file failed\n"); ++ goto err_mask_create_file; ++ } ++ ++ /*create yonly enable attr*/ ++ ret = sysfs_create_file(mscaler->yonly_ch_kobj[i], &yonly_enable_attribute.attr); ++ if(ret){ ++ dev_err(mscaler->dev, "device create sys file failed\n"); ++ goto err_yonly_create_file; ++ } ++ ++ /*create yonly uv attr*/ ++ ret = sysfs_create_file(mscaler->yonly_ch_kobj[i], &uv_value_attribute.attr); ++ if(ret){ ++ dev_err(mscaler->dev, "device create sys file failed\n"); ++ goto err_yonly_create_file; ++ } ++ mscaler->yonly_cf[i].uv_value = 0x80; ++ ++ /*create mask/chx/maskx dir*/ ++ ret = sysfs_create_groups(mscaler->mask_ch_kobj[i], mscaler_maskx_groups); ++ if(ret){ ++ dev_err(mscaler->dev, "device create sys groups failed\n"); ++ goto err_mask_create_groups; ++ } ++ ++ } ++ return 0; ++err_mask_create_groups: ++err_mask_create_file: ++err_yonly_create_file: ++err_mask_ch_kobj: ++err_yonly_ch_kobj: ++err_mask_kobj: ++err_yonly_kobj: ++err_subdev_register: ++err_alloc_pads: ++ return ret; ++} ++ ++ ++static void mscaler_comp_unbind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct mscaler_device *mscaler = dev_get_drvdata(comp); ++ ++ dev_info(comp, "----TODO: %p----%s, %d \n", mscaler, __func__, __LINE__); ++ ++} ++ ++static const struct component_ops mscaler_comp_ops = { ++ .bind = mscaler_comp_bind, ++ .unbind = mscaler_comp_unbind, ++}; ++ ++ ++ ++ ++static int ingenic_mscaler_probe(struct platform_device *pdev) ++{ ++ ++ struct mscaler_device *mscaler = NULL; ++ struct resource *regs = NULL; ++ int ret = 0; ++ int i = 0; ++ ++ mscaler = kzalloc(sizeof(struct mscaler_device), GFP_KERNEL); ++ if(!mscaler) { ++ pr_err("Failed to alloc mscaler dev [%s]\n", pdev->name); ++ return -ENOMEM; ++ } ++ ++ mscaler->dev = &pdev->dev; ++ platform_set_drvdata(pdev, mscaler); ++ ++ ++ mscaler->irq = platform_get_irq(pdev, 0); ++ if(mscaler->irq < 0) { ++ dev_warn(&pdev->dev, "No MScaler IRQ specified\n"); ++ } ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(!regs) { ++ dev_err(&pdev->dev, "No iomem resource!\n"); ++ goto err_get_resource; ++ } ++ ++ mscaler->iobase = devm_ioremap_resource(&pdev->dev, regs); ++ if(!mscaler->iobase) { ++ goto err_ioremap; ++ } ++ ++ spin_lock_init(&mscaler->lock); ++ ++ for(i = 0; i < MSCALER_MAX_CH; i++) { ++ INIT_LIST_HEAD(&mscaler->dma_queued_list[i]); ++ INIT_LIST_HEAD(&mscaler->dma_pending_list[i]); ++ } ++ ++ ret = sysfs_create_group(&mscaler->dev->kobj, &mscaler_debug_attr_group); ++ if (ret) { ++ dev_err(mscaler->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_sys_group; ++ } ++ ++ ++ ret = component_add(mscaler->dev, &mscaler_comp_ops); ++ if(ret < 0) { ++ dev_err(mscaler->dev, "Failed to add component mscaler!\n"); ++ } ++ ++ return 0; ++err_sys_group: ++err_ioremap: ++err_get_resource: ++ ++ return ret; ++} ++ ++ ++ ++static int ingenic_mscaler_remove(struct platform_device *pdev) ++{ ++ ++ return 0; ++} ++ ++ ++ ++static const struct of_device_id ingenic_mscaler_dt_match[] = { ++ { .compatible = "ingenic,x2000-mscaler" }, ++ { .compatible = "ingenic,m300-mscaler" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_mscaler_dt_match); ++ ++static int __maybe_unused ingenic_mscaler_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ return 0; ++} ++ ++static int __maybe_unused ingenic_mscaler_resume(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver ingenic_mscaler_driver = { ++ .probe = ingenic_mscaler_probe, ++ .remove = ingenic_mscaler_remove, ++ .suspend = ingenic_mscaler_suspend, ++ .resume = ingenic_mscaler_resume, ++ .driver = { ++ .name = "ingenic-mscaler", ++ .of_match_table = ingenic_mscaler_dt_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_mscaler_driver); ++ ++MODULE_ALIAS("platform:ingenic-mscaler"); ++MODULE_DESCRIPTION("ingenic mscaler subsystem"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/sensor.c b/module_drivers/drivers/media/platform/ingenic-isp/sensor.c +new file mode 100644 +index 000000000..08342aed0 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/sensor.c +@@ -0,0 +1,302 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++ ++ ++#define to_isp_device(c) (struct isp_device *)c->priv_data ++#define to_sensor_device(isp) &isp->ispcam->sensor ++ ++static void sensor_hw_reset_enable(sensor_control_t *ctrl) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static void sensor_hw_reset_disable(sensor_control_t *ctrl) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static int32_t sensor_alloc_analog_gain(sensor_control_t *ctrl, int32_t gain, sensor_context_t *p_ctx) ++{ ++ /* printk("result gain is 0x%x\n",again); */ ++ return gain; ++} ++ ++static int32_t sensor_alloc_digital_gain(sensor_control_t *ctrl, int32_t gain, sensor_context_t *p_ctx) ++{ ++ printk("----%s, %d, gain: %d\n", __func__, __LINE__, gain); ++ ++ /* printk("result gain is 0x%x\n",p_ctx->dgain); */ ++ return gain; ++} ++ ++static void sensor_alloc_integration_time(sensor_control_t *ctrl, uint16_t *int_time, sensor_context_t *p_ctx) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static void sensor_set_integration_time(sensor_control_t *ctrl, uint16_t int_time, sensor_param_t* param) ++{ ++ struct isp_device *isp = to_isp_device(ctrl); ++ struct sensor_device *sensor = to_sensor_device(isp); ++ struct v4l2_control exposure; ++ int ret = 0; ++ ++ exposure.id = V4L2_CID_EXPOSURE; ++ exposure.value = int_time; ++ ++ ret = v4l2_s_ctrl(NULL, sensor->isd->sd->ctrl_handler, &exposure); ++ if(ret < 0) { ++ dev_err(isp->dev, "failed to set exposure!\n"); ++ } ++} ++ ++static void sensor_set_analog_gain(sensor_control_t *ctrl, uint32_t again_reg_val, sensor_context_t *p_ctx) ++{ ++ struct isp_device *isp = to_isp_device(ctrl); ++ struct sensor_device *sensor = to_sensor_device(isp); ++ struct v4l2_control analog; ++ int ret = 0; ++ ++ analog.id = V4L2_CID_ANALOGUE_GAIN; ++ analog.value = again_reg_val; ++ ++ ret = v4l2_s_ctrl(NULL, sensor->isd->sd->ctrl_handler, &analog); ++ if(ret < 0) { ++ printk("error s_ctrl, ret: %d\n", ret); ++ } ++} ++ ++static int sensor_get_analog_gain(sensor_control_t *ctrl, uint32_t *again_reg_val, sensor_context_t *p_ctx) ++{ ++ struct isp_device *isp = to_isp_device(ctrl); ++ struct sensor_device *sensor = to_sensor_device(isp); ++ struct v4l2_control analog; ++ int ret = 0; ++ ++ analog.id = V4L2_CID_ANALOGUE_GAIN; ++ analog.value = 0; ++ ++ ret = v4l2_g_ctrl(sensor->isd->sd->ctrl_handler, &analog); ++ if(ret < 0) { ++ printk("error s_ctrl, ret: %d\n", ret); ++ } ++ ++ ++ *again_reg_val = analog.value; ++ ++ return ret; ++} ++ ++ ++static void sensor_set_digital_gain(sensor_control_t *ctrl, uint32_t dgain_reg_val, sensor_context_t *p_ctx) ++{ ++ struct isp_device *isp = to_isp_device(ctrl); ++ struct sensor_device *sensor = to_sensor_device(isp); ++ struct v4l2_control control; ++ int ret = 0; ++ ++ control.id = V4L2_CID_GAIN; ++ control.value = dgain_reg_val; ++ ++ ret = v4l2_s_ctrl(NULL, sensor->isd->sd->ctrl_handler, &control); ++ if(ret < 0) { ++ printk("error s_ctrl, ret: %d\n", ret); ++ } ++} ++ ++static int sensor_get_digital_gain(sensor_control_t *ctrl, uint32_t *dgain_reg_val, sensor_context_t *p_ctx) ++{ ++ struct isp_device *isp = to_isp_device(ctrl); ++ struct sensor_device *sensor = to_sensor_device(isp); ++ struct v4l2_control control; ++ int ret = 0; ++ ++ control.id = V4L2_CID_GAIN; ++ control.value = 0; ++ ++ ret = v4l2_g_ctrl(sensor->isd->sd->ctrl_handler, &control); ++ if(ret < 0) { ++ printk("error s_ctrl, ret: %d\n", ret); ++ } ++ ++ *dgain_reg_val = control.value; ++ ++ return ret; ++} ++ ++ ++static uint16_t sensor_get_normal_fps(sensor_control_t *ctrl, sensor_param_t* param) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static uint16_t sensor_read_black_pedestal(sensor_control_t *ctrl, int i,uint32_t gain) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static void sensor_set_mode(sensor_control_t *ctrl, uint8_t mode, sensor_param_t* param) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static void sensor_start_changes(sensor_control_t *ctrl, sensor_context_t *p_ctx) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static void sensor_end_changes(sensor_control_t *ctrl, sensor_context_t *p_ctx) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static uint16_t sensor_get_id(sensor_control_t *ctrl) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++ ++ return 0; ++} ++ ++static void sensor_set_wdr_mode(sensor_control_t *ctrl, uint8_t mode, sensor_param_t* param) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static uint32_t sensor_fps_control(sensor_control_t *ctrl, uint8_t fps, sensor_param_t* param) ++{ ++ ++ printk("----%s, %d\n", __func__, __LINE__); ++ return 0; ++} ++ ++static void sensor_disable_isp(sensor_control_t *ctrl) ++{ ++ printk("----%s, %d\n", __func__, __LINE__); ++} ++ ++static uint32_t sensor_get_lines_per_second(sensor_control_t *ctrl, sensor_param_t* param) ++{ ++ uint32_t lines_per_second=0; ++ printk("----%s, %d\n", __func__, __LINE__); ++ return lines_per_second; ++} ++ ++struct sensor_control_ops sensor_ctrl_ops = { ++ .hw_reset_disable = sensor_hw_reset_disable, ++ .hw_reset_enable = sensor_hw_reset_enable, ++ .alloc_analog_gain = sensor_alloc_analog_gain, ++ .alloc_digital_gain = sensor_alloc_digital_gain, ++ .alloc_integration_time = sensor_alloc_integration_time, ++ .set_integration_time = sensor_set_integration_time, ++ .start_changes = sensor_start_changes, ++ .end_changes = sensor_end_changes, ++ .set_analog_gain = sensor_set_analog_gain, ++ .get_analog_gain = sensor_get_analog_gain, ++ .set_digital_gain = sensor_set_digital_gain, ++ .get_digital_gain = sensor_get_digital_gain, ++ .get_normal_fps = sensor_get_normal_fps, ++ .read_black_pedestal = sensor_read_black_pedestal, ++ .set_mode = sensor_set_mode, ++ .set_wdr_mode = sensor_set_wdr_mode, ++ .fps_control = sensor_fps_control, ++ .get_id = sensor_get_id, ++ .disable_isp = sensor_disable_isp, ++ .get_lines_per_second = sensor_get_lines_per_second ++}; ++ ++void sensor_init(sensor_control_t *ctrl, void *priv_data) ++{ ++ tisp_core_t *core = priv_data; ++ struct isp_device *isp = core->priv_data; ++ struct sensor_device *sensor = to_sensor_device(isp); ++ struct v4l2_queryctrl query; ++ tisp_init_param_t *sensor_info = &core->sensor_info; ++ int ret = 0; ++ ++ query.id = V4L2_CID_EXPOSURE; ++ query.type = V4L2_CTRL_TYPE_INTEGER; ++ ret = v4l2_queryctrl(sensor->isd->sd->ctrl_handler, &query); ++ if(ret < 0) { ++ dev_err(isp->dev, "query sensor V4L2_CID_EXPOSURE failed\n"); ++ } ++ ++ ctrl->param.integration_time_min = query.minimum; ++ ctrl->param.integration_time_max = query.maximum; ++ ++ query.id = V4L2_CID_ANALOGUE_GAIN; ++ query.type = V4L2_CTRL_TYPE_INTEGER; ++ ret = v4l2_queryctrl(sensor->isd->sd->ctrl_handler, &query); ++ if(ret < 0) { ++ dev_err(isp->dev, "query sensor V4L2_CID_ANALOGUE_GAIN failed\n"); ++ } ++ ctrl->param.again_log2_max = query.maximum; ++ ++ ++ query.id = V4L2_CID_GAIN; ++ query.type = V4L2_CTRL_TYPE_INTEGER; ++ ret = v4l2_queryctrl(sensor->isd->sd->ctrl_handler, &query); ++ if(ret < 0) { ++ dev_err(isp->dev, "queyr sensor V4L2_CID_GAIN failed\n"); ++ } ++ ctrl->param.dgain_log2_max = query.maximum; ++ ++#if 0 ++ struct tx_isp_video_in *vin = &core->vin; ++ struct tx_isp_sensor_attribute *attr = vin->attr; ++ ++ ctrl->param.again_log2_max = attr->max_again; ++ ctrl->param.dgain_log2_max= attr->max_dgain; ++ ctrl->param.integration_time_apply_delay = attr->integration_time_apply_delay; ++ ctrl->param.analog_gain_apply_delay = attr->again_apply_delay; ++ ctrl->param.digital_gain_apply_delay = attr->dgain_apply_delay; ++ ctrl->param.integration_time_min = attr->min_integration_time; ++ ctrl->param.integration_time_max = attr->max_integration_time; ++#endif ++ ctrl->priv_data = isp; ++ isp->core.sensor_ctrl_ops = &sensor_ctrl_ops; ++ ++ /*fill sensor_info*/ ++ sensor_info->sensor_info.max_again = ctrl->param.again_log2_max; //the format is .16 ++ sensor_info->sensor_info.max_dgain = ctrl->param.dgain_log2_max; //the format is .16 ++// sensor_info->sensor_info.again = core->vin.attr->again; ++// sensor_info->sensor_info.dgain = core->vin.attr->dgain; ++// sensor_info->sensor_info.fps = core->vin.fps; ++ sensor_info->sensor_info.min_integration_time = ctrl->param.integration_time_min; ++ sensor_info->sensor_info.max_integration_time = ctrl->param.integration_time_max; ++// sensor_info->sensor_info.min_integration_time_native = core->vin.attr->min_integration_time_native; ++// sensor_info->sensor_info.max_integration_time_native = core->vin.attr->max_integration_time_native; ++// sensor_info->sensor_info.integration_time_limit = core->vin.attr->integration_time_limit; ++// sensor_info->sensor_info.integration_time = core->vin.attr->integration_time; ++// sensor_info->sensor_info.total_width = core->vin.attr->total_width; ++// sensor_info->sensor_info.total_height = core->vin.attr->total_height; ++// sensor_info->sensor_info.integration_time_apply_delay = core->vin.attr->integration_time_apply_delay; ++// sensor_info->sensor_info.again_apply_delay = core->vin.attr->again_apply_delay; ++// sensor_info->sensor_info.dgain_apply_delay = core->vin.attr->dgain_apply_delay; ++// sensor_info->sensor_info.one_line_expr_in_us = core->vin.attr->one_line_expr_in_us; ++ ++} ++ ++ ++ ++int sensor_device_probe(struct sensor_device *sensor, struct ispcam_device *ispcam) ++{ ++ int ret = 0; ++ sensor->ispcam = ispcam; ++ sensor->isp = ispcam->isp; ++ sensor->isd = &ispcam->isd[0]; ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(sensor_device_probe); +diff --git a/module_drivers/drivers/media/platform/ingenic-isp/vic-regs.h b/module_drivers/drivers/media/platform/ingenic-isp/vic-regs.h +new file mode 100644 +index 000000000..46d8fa84a +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-isp/vic-regs.h +@@ -0,0 +1,157 @@ ++#ifndef __INGENIC_ISP_VIC_REG_H__ ++#define __INGENIC_ISP_VIC_REG_H__ ++ ++#define VIC_CONTROL 0x00 ++#define VIC_RESOLUTION 0x04 ++#define VIC_FRM_ECC 0x08 ++#define VIC_INTF_TYPE 0x0C ++#define VIC_IN_DVP 0x10 ++#define VIC_IN_CSI_FMT 0x14 ++#define VIC_IN_HOR_PARA0 0x18 ++#define VIC_IN_HOR_PARA1 0x1C ++#define VIC_BK_CB_CTRL 0x28 ++#define VIC_BK_CB_BLK 0x2C ++#define VIC_IN_VER_PARA0 0x30 ++#define VIC_IN_VER_PARA1 0x34 ++#define VIC_IN_VER_PARA2 0x38 ++#define VIC_IN_VER_PARA3 0x3C ++#define VIC_VLD_LINE_SAV 0x60 ++#define VIC_VLD_LINE_EAV 0x64 ++#define VIC_VLD_FRM_SAV 0x70 ++#define VIC_VLD_FRM_EAV 0x74 ++#define VIC_VC_CONTROL 0x8C ++#define VIC_VC_CONTROL_CH0_PIX 0x90 ++#define VIC_VC_CONTROL_CH1_PIX 0x94 ++#define VIC_VC_CONTROL_CH2_PIX 0x98 ++#define VIC_VC_CONTROL_CH3_PIX 0x9C ++#define VIC_VC_CONTROL_CH0_LINE 0xA0 ++#define VIC_VC_CONTROL_CH1_LINE 0xA4 ++#define VIC_VC_CONTROL_CH2_LINE 0xA8 ++#define VIC_VC_CONTROL_CH3_LINE 0xAC ++#define VIC_VC_CONTROL_FIFO_USE 0xB0 ++#define VIC_CB_1ST 0xC0 ++#define VIC_CB_2ND 0xC4 ++#define VIC_CB_3RD 0xC8 ++#define VIC_CB_4TH 0xCC ++#define VIC_CB_5TH 0xD0 ++#define VIC_CB_6TH 0xD4 ++#define VIC_CB_7TH 0xD8 ++#define VIC_CB_8TH 0xDC ++#define VIC_CB2_1ST 0xE0 ++#define VIC_CB2_2ND 0xE4 ++#define VIC_CB2_3RD 0xE8 ++#define VIC_CB2_4TH 0xEC ++#define VIC_CB2_5TH 0xF0 ++#define VIC_CB2_6TH 0xF4 ++#define VIC_CB2_7TH 0xF8 ++#define VIC_CB2_8TH 0xFC ++#define MIPI_ALL_WIDTH_4BYTE 0x100 ++#define MIPI_VCROP_DEL01 0x104 ++#define MIPI_SENSOR_CONTROL 0x10C ++#define MIPI_HCROP_CH0 0x110 ++#define MIPI_VCROP_SHADOW_CFG 0x120 ++#define VIC_CONTROL_LIMIT 0x1A0 ++#define VIC_CONTROL_DELAY 0x1A4 ++#define VIC_CONTROL_TIZIANO_ROUTE 0x1A8 ++#define VIC_CONTROL_DMA_ROUTE 0x1B0 ++#define VIC_INT_STA 0X1E0 ++#define VIC_INT_MASK 0x1E8 ++#define VIC_INT_CLR 0x1F0 ++/*DMA register*/ ++#define VIC_DMA_OUTPUT_MAX_WIDTH 2688 ++#define VIC_DMA_CONFIG 0x300 ++#define VIC_DMA_RESOLUTION 0x304 ++#define VIC_DMA_RESET 0x308 ++#define VIC_DMA_Y_STRID 0x314 ++#define VIC_DMA_Y_BUF0 0x318 ++#define VIC_DMA_Y_BUF1 0x31c ++#define VIC_DMA_Y_BUF2 0x320 ++#define VIC_DMA_Y_BUF3 0x324 ++#define VIC_DMA_Y_BUF4 0x328 ++#define VIC_DMA_UV_STRID 0x334 ++#define VIC_DMA_UV_BUF0 0x338 ++#define VIC_DMA_UV_BUF1 0x33c ++#define VIC_DMA_UV_BUF2 0x340 ++#define VIC_DMA_UV_BUF3 0x344 ++#define VIC_DMA_UV_BUF4 0x348 ++ ++/*TIMESTAMP registers*/ ++#define VIC_TS_ENABLE 0x360 /* 控制使能*/ ++ #define TS_COUNTER_EN (1 << 0)/*使能计数器*/ ++ #define TS_VIC_DMA_EN (1 << 4)/*使能VIC DMAçš„timstsamp*/ ++ #define TS_MS_CH0_EN (1 << 5)/*使能MSCALER CH0 ts*/ ++ #define TS_MS_CH1_EN (1 << 6)/*使能MSCALER CH1 ts*/ ++ #define TS_MS_CH2_EN (1 << 7)/*使能MSCALER CH2 ts*/ ++#define VIC_TS_COUNTER 0x368 /* 多少个ISP时钟周期计数一次 */ ++/* timestamp 写入到帧数æ®ä¸­çš„åç§»ä½ç½®.*/ ++#define VIC_TS_DMA_OFFSET 0x370 ++#define VIC_TS_MS_CH0_OFFSET 0x374 ++#define VIC_TS_MS_CH1_OFFSET 0x378 ++#define VIC_TS_MS_CH2_OFFSET 0x37c ++ ++ ++ ++ ++ ++/*VIC_CONTROL*/ ++//#define VIC_RESET (1<<4) ++#define GLB_RST (1<<2) ++#define REG_ENABLE (1<<1) ++#define VIC_START (1<<0) ++ ++/*VIC_RESOLUTION*/ ++#define H_RESOLUTION (1<<16) ++#define V_RESOLUTION (1) ++ ++/*VIC_FRM_ECC*/ ++#define FRAME_ECC_EN (1<<0) ++#define FRAME_ECC_MODE (1<<1) ++ ++/*VIC_INTF_TYPE*/ ++#define INTF_TYPE_BT656 0x0 ++#define INTF_TYPE_BT601 0x1 ++#define INTF_TYPE_MIPI 0x2 ++#define INTF_TYPE_DVP 0x3 ++#define INTF_TYPE_BT1120 0x4 ++ ++/*VIC_IN_DVP*/ ++#define DVP_DATA_POS (1<<24) ++#define DVP_RGB_ORDER (1<<21) ++#define DVP_RAW_ALIG (1<<20) ++#define DVP_DATA_TYPE (17) ++#define DVP_RAW8 (0< ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isp-drv.h" ++#include "vic-regs.h" ++ ++#define VIC_STOP_BUFFER_COUNT 2 ++#define VIC_RESTART_BUFFER_COUNT 3 ++ ++int count_period = 256; ++module_param(count_period, int, S_IRUGO); ++MODULE_PARM_DESC(count_period, "vic counter period"); ++ ++int vic_stop_counter = 0; ++module_param(vic_stop_counter, int, S_IRUGO); ++MODULE_PARM_DESC(vic_stop_counter, "vic0 bypass mode stop counter"); ++ ++int dma_debug_en = 0; ++module_param(dma_debug_en, int, 0664); ++MODULE_PARM_DESC(dma_debug_en, "vic dma debug mode enable"); ++ ++int timestamp_en = 0; ++module_param(timestamp_en, int, 0664); ++MODULE_PARM_DESC(timestamp_en, "vic dma debug mode enable"); ++ ++struct isp_video_format vic_mipi_formats[] = { ++ /*yuv422 */ ++ { ++ .name = "YUV422, YUYV", ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "YUV422, YVYU", ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "YUV422, UYVY", ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ { ++ .name = "YUV422, VYUY", ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, ++ .colorspace = V4L2_COLORSPACE_DEFAULT, ++ }, ++ /* dvp: Y8_1X8 */ ++ { ++ .name = "Y8, GREY", ++ .fourcc = V4L2_PIX_FMT_GREY, ++ .depth = {8}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_Y8_1X8, ++ .colorspace = V4L2_COLORSPACE_RAW, ++ }, ++ /* RAW8 */ ++ { ++ .name = "RAW8, 8 BGBG.. GRGR..", ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW8, 8 GBGB.. RGRG..", ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW8, 8 GRGR.. BGBG..", ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW8, 8 RGRG.. GBGB..", ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ /* RAW10 */ ++ { ++ .name = "RAW10, 10 BGBG.. GRGR..", ++ .fourcc = V4L2_PIX_FMT_SBGGR10, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW10, 10 GBGB.. RGRG..", ++ .fourcc = V4L2_PIX_FMT_SGBRG10, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW10, 10 GRGR.. BGBG..", ++ .fourcc = V4L2_PIX_FMT_SGRBG10, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW10, 10 RGRG.. GBGB..", ++ .fourcc = V4L2_PIX_FMT_SRGGB10, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ /* RAW12 */ ++ { ++ .name = "RAW12, 12 BGBG.. GRGR..", ++ .fourcc = V4L2_PIX_FMT_SBGGR12, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW12, 12 GBGB.. RGRG..", ++ .fourcc = V4L2_PIX_FMT_SGBRG12, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW12, 12 GRGR.. BGBG..", ++ .fourcc = V4L2_PIX_FMT_SGRBG12, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++ { ++ .name = "RAW12, 12 RGRG.. GBGB..", ++ .fourcc = V4L2_PIX_FMT_SRGGB12, ++ .depth = {16}, ++ .num_planes = 1, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, ++}; ++ ++struct isp_video_format vic_dvp_formats = { ++ ++}; ++ ++ ++static inline void vic_reg_writel(struct vic_device *vic, unsigned int reg, unsigned int val) ++{ ++ writel(val, vic->iobase + reg); ++} ++ ++static inline unsigned int vic_reg_readl(struct vic_device *vic, unsigned int reg) ++{ ++ return readl(vic->iobase + reg); ++} ++ ++ ++static int ingenic_vic_parse_dt(struct vic_device * vic) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++static const struct v4l2_subdev_core_ops vic_subdev_core_ops = { ++ .log_status = v4l2_ctrl_subdev_log_status, ++ .subscribe_event = v4l2_ctrl_subdev_subscribe_event, ++ .unsubscribe_event = v4l2_event_subdev_unsubscribe, ++}; ++ ++static int vic_subdev_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct vic_device *vic = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ struct v4l2_subdev_format remote_subdev_fmt; ++ int ret = 0; ++ ++ remote = media_entity_remote_pad(&vic->pads[VIC_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ /*èŽ·å–æºå½“剿 ¼å¼ï¼Œå¤åˆ¶åˆ°è¾“出格å¼.*/ ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_err(vic->dev, "Failed to get_fmt from remote pad\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(&format->format, &remote_subdev_fmt.format, sizeof(format->format)); ++ ++ vic->formats[VIC_PAD_SINK] = vic->formats[VIC_PAD_SOURCE] = *format; ++ ++ //printk("----%s, %d, format->pad: %d\n", __func__, __LINE__, format->pad); ++ return 0; ++} ++ ++static int vic_subdev_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct vic_device *vic = v4l2_get_subdevdata(sd); ++ struct media_pad *remote = NULL; ++ struct v4l2_subdev *remote_sd = NULL; ++ struct v4l2_subdev_format remote_subdev_fmt; ++ int ret = 0; ++ ++ dev_dbg(vic->dev, "%s, %d, width: %d, height: %d, mbus_code: %x\n", __func__, __LINE__, format->format.width, format->format.height, format->format.code); ++ ++ vic->formats[VIC_PAD_SOURCE] = *format; ++ ++ remote = media_entity_remote_pad(&vic->pads[VIC_PAD_SINK]); ++ remote_sd = media_entity_to_v4l2_subdev(remote->entity); ++ ++ ret = v4l2_subdev_call(remote_sd, pad, set_fmt, NULL, format); ++ if(ret < 0) { ++ dev_dbg(vic->dev, "Failed to set_fmt from remote pad\n"); ++ } ++ ++ /*èŽ·å–æºå½“剿 ¼å¼ï¼Œå¤åˆ¶åˆ°è¾“出格å¼.*/ ++ remote_subdev_fmt.pad = remote->index; ++ remote_subdev_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ++ ret = v4l2_subdev_call(remote_sd, pad, get_fmt, NULL, &remote_subdev_fmt); ++ if(ret < 0) { ++ dev_err(vic->dev, "Failed to get_fmt from remote pad\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(&vic->formats[VIC_PAD_SINK], &remote_subdev_fmt, sizeof(struct v4l2_subdev_format)); ++ vic->sensor_info = (struct sensor_info *)*(unsigned int *)remote_subdev_fmt.format.reserved; ++ ++ return 0; ++} ++ ++ ++static const struct v4l2_subdev_pad_ops vic_subdev_pad_ops = { ++ .get_fmt = vic_subdev_get_fmt, ++ .set_fmt = vic_subdev_set_fmt, ++}; ++ ++ ++static int vic_cfg_stream_mipi(struct vic_device *vic) ++{ ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ struct mipi_cfg *mipi_cfg = &vic->sensor_info->mipi_cfg; ++ //unsigned int timeout = 10000; ++ int mwidth = mipi_cfg->twidth; ++ ++ dev_dbg(vic->dev, "%s, %d, input_fmt->format.width: %d, intput_fmt->format.height: %d\n", ++ __func__, __LINE__, input_fmt->format.width, input_fmt->format.height); ++ dev_dbg(vic->dev, "%s, %d, mipi_cfg->twidth: %d\n", ++ __func__, __LINE__, mipi_cfg->twidth); ++ ++ vic_reg_writel(vic, VIC_INTF_TYPE, INTF_TYPE_MIPI); ++ ++ if (input_fmt->format.code == MEDIA_BUS_FMT_Y8_1X8) { ++ mwidth /= 2; /* (y8 width)/2 = yuv422 width */ ++ } ++ ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ vic_reg_writel(vic, VIC_IN_CSI_FMT,MIPI_RAW8);//RAW8 ++ vic_reg_writel(vic, MIPI_ALL_WIDTH_4BYTE, ((mwidth * 8 / 32) + !!(mwidth * 8 % 32))); ++ break; ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ vic_reg_writel(vic, VIC_IN_CSI_FMT,MIPI_RAW10);//RAW10 ++ vic_reg_writel(vic, MIPI_ALL_WIDTH_4BYTE, ((mwidth * 10 / 32) + !!(mwidth * 10 % 32))); ++ break; ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ vic_reg_writel(vic, VIC_IN_CSI_FMT,MIPI_RAW12);//RAW12 ++ vic_reg_writel(vic, MIPI_ALL_WIDTH_4BYTE, ((mwidth * 12 / 32) + !!(mwidth * 12 % 32))); ++ break; ++ case MEDIA_BUS_FMT_Y8_1X8 : ++ case MEDIA_BUS_FMT_YUYV8_2X8 : ++ case MEDIA_BUS_FMT_YVYU8_2X8 : ++ case MEDIA_BUS_FMT_UYVY8_2X8 : ++ case MEDIA_BUS_FMT_VYUY8_2X8 : ++ vic_reg_writel(vic, VIC_IN_CSI_FMT, MIPI_YUV422);//YUV422 ++ vic_reg_writel(vic, MIPI_ALL_WIDTH_4BYTE, ((mwidth * 8 / 32) + !!(mwidth * 8 % 32))); ++ break; ++ default: ++ dev_err(vic->dev, "unsupported mbus fmt: %x\n", input_fmt->format.code); ++ return -EINVAL; ++ } ++ vic_reg_writel(vic, MIPI_VCROP_DEL01, mipi_cfg->mipi_crop_start0y); ++ vic_reg_writel(vic, MIPI_HCROP_CH0, (mwidth << 16) | mipi_cfg->mipi_crop_start0x); ++ ++ return 0; ++} ++ ++static int vic_cfg_stream_dvp(struct vic_device *vic) ++{ ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ struct v4l2_fwnode_bus_parallel *parallel = ispcam_get_bus_parallel(vic->ispcam); ++ unsigned int input_cfg = 0; ++ int width = input_fmt->format.width; ++ ++ if (input_fmt->format.code == MEDIA_BUS_FMT_Y8_1X8) { ++ width /= 2; /* (y8 width)/2 = yuv422 width */ ++ } ++ ++ vic->frame_capture_counter = 0; /* reset counter */ ++ vic->global_reset = 0; ++ ++ dev_dbg(vic->dev, "parallel->flags: 0x%x\n", parallel->flags); ++ dev_dbg(vic->dev, "parallel->bus_width: %d\n", parallel->bus_width); ++ dev_dbg(vic->dev, "parallel->data_shift: %d\n", parallel->data_shift); ++ vic_reg_writel(vic, VIC_INTF_TYPE, INTF_TYPE_DVP); ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ if(parallel->data_shift) { ++ input_cfg = DVP_RAW8 | DVP_RAW_ALIG; ++ } else { ++ input_cfg = DVP_RAW8; ++ } ++ break; ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ if(parallel->data_shift) { ++ input_cfg = DVP_RAW10 | DVP_RAW_ALIG; ++ } else { ++ input_cfg = DVP_RAW10; ++ } ++ break; ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ input_cfg = DVP_RAW12; ++ break; ++ case MEDIA_BUS_FMT_UYVY8_1_5X8 : ++ case MEDIA_BUS_FMT_VYUY8_1_5X8 : ++ case MEDIA_BUS_FMT_YUYV8_1_5X8 : ++ case MEDIA_BUS_FMT_YVYU8_1_5X8 : ++ case MEDIA_BUS_FMT_YUYV8_1X16 : ++ case MEDIA_BUS_FMT_YUYV8_2X8 : ++ case MEDIA_BUS_FMT_YVYU8_2X8 : ++ case MEDIA_BUS_FMT_UYVY8_2X8 : ++ case MEDIA_BUS_FMT_VYUY8_2X8 : ++ case MEDIA_BUS_FMT_Y8_1X8 : ++ input_cfg = DVP_YUV422_8BIT; ++ break; ++ ++ default: ++ dev_err(vic->dev, "unsupported input formats\n"); ++ return -EINVAL; ++ } ++ if(parallel->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) { ++ input_cfg |= HSYN_POLAR; ++ } ++ if(parallel->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) { ++ input_cfg |= VSYN_POLAR; ++ } ++ vic_reg_writel(vic, VIC_IN_DVP, input_cfg); ++ /*dev_info(vic->dev, "VIC_IN_DVP input_cfg=0x%x\n", input_cfg); ++ if (input_fmt->format.width>2048 && input_fmt->format.height == 1) { ++ vic_reg_writel(vic, VIC_IN_DVP, 0x6<<17 | 1<<1 | 1<<0); //cisadc, 0x6<<17 | 1<<1 | 1<<0; ++ }*/ ++ /*TODO: hblank and vblank*/ ++ ++ vic_reg_writel(vic, VIC_IN_HOR_PARA0, width + 0 /*hblank*/); ++ ++ return 0; ++} ++ ++static int vic_subdev_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct vic_device *vic = v4l2_get_subdevdata(sd); ++ struct isp_async_device *isd = &vic->ispcam->isd[0]; /*TODO: 默认支æŒä¸€ä¸ªasd.*/ ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ struct isp_video_device *ispvideo = v4l2_get_subdev_hostdata(sd); ++ struct isp_video_buffer *isp_buffer = NULL; ++ struct isp_video_buffer *tmp = NULL; ++ int ret = 0; ++ unsigned long flags; ++ int width; ++ unsigned int regval; ++ ++ spin_lock_irqsave(&vic->lock, flags); ++ /*hw configure.*/ ++ if(enable) { ++ ++ if(vic->enabled++ > 0) { ++ goto finish; ++ } ++ ++ /* set width */ ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_Y8_1X8 : ++ width = input_fmt->format.width/2; /* (y8 width)/2 = yuv422 width */ ++ break; ++ /* TODO: NV21/NV12 */ ++ default: ++ width = input_fmt->format.width; ++ } ++ ++ /* enable timestamp .*/ ++ if(timestamp_en) { ++ vic_reg_writel(vic, VIC_TS_COUNTER, count_period - 1); ++ vic_reg_writel(vic, VIC_TS_DMA_OFFSET, 0); ++ vic_reg_writel(vic, VIC_TS_MS_CH0_OFFSET, 0); ++ vic_reg_writel(vic, VIC_TS_MS_CH1_OFFSET, 0); ++ vic_reg_writel(vic, VIC_TS_MS_CH2_OFFSET, 0); ++ vic_reg_writel(vic, VIC_TS_ENABLE, TS_COUNTER_EN | ++ TS_VIC_DMA_EN | TS_MS_CH0_EN | ++ TS_MS_CH1_EN | TS_MS_CH2_EN); ++ } ++ ++ /*confgure hw and start*/ ++ if(isd->bus_type == V4L2_MBUS_CSI2_DPHY) { ++ ret = vic_cfg_stream_mipi(vic); ++ } else { ++ ret = vic_cfg_stream_dvp(vic); ++ } ++ ++ vic_reg_writel(vic, VIC_RESOLUTION, (width << 16) | ++ input_fmt->format.height); ++ ++ vic_reg_writel(vic, VIC_CONTROL_DELAY, (10 << 0| 10 << 16)); ++ ++ if(ispvideo->bypass == 1) { ++ if(dma_debug_en) { ++ printk("please disable vic dma debug mode\ntry \"echo 0 > /sys/module/vic/parameters/dma_debug_en\"\n"); ++ goto finish; ++ } ++ /*DMA config*/ ++ regval = 0; ++ /*TODO: fmts.*/ ++ switch(input_fmt->format.code) { ++ case MEDIA_BUS_FMT_UYVY8_1_5X8 : ++ case MEDIA_BUS_FMT_VYUY8_1_5X8 : ++ case MEDIA_BUS_FMT_YUYV8_1_5X8 : ++ case MEDIA_BUS_FMT_YVYU8_1_5X8 : ++ case MEDIA_BUS_FMT_YUYV8_1X16 : ++ case MEDIA_BUS_FMT_YUYV8_2X8 : ++ regval |= 1<<8; /* Y1UY2V */ ++ regval |= 3<<0; /* mode 3: YUV422 */ ++ break; ++ case MEDIA_BUS_FMT_YVYU8_2X8 : ++ regval |= 0<<8; /* Y2VY1U */ ++ regval |= 3<<0; /* mode 3: YUV422 */ ++ break; ++ case MEDIA_BUS_FMT_UYVY8_2X8 : ++ regval |= 3<<8; /* UY1VY2 */ ++ regval |= 3<<0; /* mode 3: YUV422 */ ++ break; ++ case MEDIA_BUS_FMT_VYUY8_2X8 : ++ regval |= 2<<8; /* VY2UY1 */ ++ regval |= 3<<0; /* mode 3: YUV422 */ ++ break; ++ case MEDIA_BUS_FMT_Y8_1X8 : ++ //regval |= 0<<8; /* Y2VY1U */ ++ //regval |= 1<<8; /* Y1UY2V */ ++ //regval |= 2<<8; /* VY2UY1 */ ++ //regval |= 3<<8; /* Y1UY2V(U1Y1V1Y2) */ ++ regval |= 3<<0; /* mode 3: YUV422 */ ++ break; ++ /* TODO: NV21/NV12 */ ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ regval |= 0; ++ break; ++ default: ++ dev_info(vic->dev, "%s(), TODO: DMA config, input_fmt->format.code=0x%x\n", ++ __func__, input_fmt->format.code); ++ return -EINVAL; ++ } ++ regval |= 1 << 31; /* enable dma */ ++ regval |= (ispvideo->max_buffer_num - 1) << 3; ++ vic_reg_writel(vic, VIC_DMA_CONFIG, regval); ++ ++ vic_reg_writel(vic, VIC_DMA_RESOLUTION, (width << 16) | ++ input_fmt->format.height); ++ vic_reg_writel(vic, VIC_DMA_Y_STRID, width*2); ++ vic_reg_writel(vic, VIC_DMA_UV_STRID, width*2); ++ ++ vic_reg_writel(vic, VIC_CONTROL_TIZIANO_ROUTE, 0); ++ vic_reg_writel(vic, VIC_CONTROL_DMA_ROUTE, 1); ++ /*TODO:*/ ++ vic_reg_writel(vic, VIC_INT_MASK, 0x3ff7f); ++ if(input_fmt->format.width > 2048) { ++ if(input_fmt->format.height > 1) ++ vic_reg_writel(vic, VIC_CONTROL_LIMIT, (1 << 31)|((input_fmt->format.width / 8 * 3) << 16)); ++ else ++ vic_reg_writel(vic, VIC_CONTROL_LIMIT, (1 << 31)|(512<<16)); // cisadc, height==1, width > 2048 ++ } ++ vic->framenum = 0; ++ ++ } else { ++ vic_reg_writel(vic, VIC_CONTROL_TIZIANO_ROUTE, 1); ++ if(dma_debug_en) ++ vic_reg_writel(vic, VIC_CONTROL_DMA_ROUTE, 1); ++ else ++ vic_reg_writel(vic, VIC_CONTROL_DMA_ROUTE, 0); ++ vic_reg_writel(vic, VIC_INT_MASK, 0x3ff7f); ++ } ++ ++ vic_reg_writel(vic, VIC_CONTROL, ~GLB_RST); ++ vic_reg_writel(vic, VIC_CONTROL, REG_ENABLE); ++#if 0 ++ unsigned int timeout = 0xfffff; ++ while(vic_reg_readl(vic,VIC_CONTROL) && --timeout); ++ if(!timeout) { ++ dev_err(vic->dev, "wait vic init timeout!\n"); ++ } ++#endif ++ ++ vic_reg_writel(vic, VIC_CONTROL, VIC_START); ++ ++ ++ } else { ++ /*reset flags*/ ++ vic->buffer_index = 0; ++ vic->stop_flag = 0; ++ vic_stop_counter = 0; ++ ++ if(--vic->enabled) { ++ goto finish; ++ } ++ ++ /* disable timestamp */ ++ vic_reg_writel(vic, VIC_TS_COUNTER, 0); ++ vic_reg_writel(vic, VIC_TS_ENABLE, 0); ++ ++ if(ispvideo->bypass) { ++ /*disable dma*/ ++ vic_reg_writel(vic, VIC_DMA_CONFIG, 0); ++ /*disable contro limit*/ ++ if(input_fmt->format.width > 2048) ++ vic_reg_writel(vic, VIC_CONTROL_LIMIT, 0); ++ } ++ ++ /* keep reset*/ ++ vic_reg_writel(vic, VIC_CONTROL, GLB_RST); ++ ++ /* stop vic. */ ++ list_for_each_entry_safe(isp_buffer, tmp, &vic->dma_queued_list, list_entry) { ++ struct vb2_buffer *vb2_buf = &isp_buffer->vb2.vb2_buf; ++ vb2_buffer_done(vb2_buf, VB2_BUF_STATE_ERROR); ++ list_del(&isp_buffer->list_entry); ++ vic->buffer_count--; ++ } ++ ++ } ++ ++finish: ++ spin_unlock_irqrestore(&vic->lock, flags); ++ ++ return ret; ++} ++ ++ ++static const struct v4l2_subdev_video_ops vic_subdev_video_ops = { ++ .s_stream = vic_subdev_s_stream, ++}; ++static const struct v4l2_subdev_ops vic_subdev_ops = { ++ .core = &vic_subdev_core_ops, ++ .pad = &vic_subdev_pad_ops, ++ .video = &vic_subdev_video_ops, ++}; ++ ++struct isp_video_format *vic_find_format(const u32 *pixelformat, const u32 *mbus_code, int index) ++{ ++ int i; ++ struct isp_video_format *fmt = NULL; ++ ++ for(i = 0; i < ARRAY_SIZE(vic_mipi_formats); i++) { ++ fmt = &vic_mipi_formats[i]; ++ ++ if(pixelformat && fmt->fourcc == *pixelformat) { ++ return fmt; ++ } ++ if(mbus_code && fmt->mbus_code == *mbus_code) { ++ return fmt; ++ } ++ ++ if(index == i) { ++ return fmt; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int vic_video_qbuf(struct isp_video_device *ispvideo, struct isp_video_buffer *isp_buffer) ++{ ++ struct vic_device *vic = ispvideo->ispcam->vic; ++ struct vb2_buffer *vb2_buf = NULL; ++ struct isp_video_buffer *tmp = NULL; ++ unsigned long flags = 0; ++ dma_addr_t y_addr = 0; ++ dma_addr_t uv_addr = 0; ++ unsigned int regval; ++ ++ spin_lock_irqsave(&vic->lock, flags); ++ ++ vb2_buf = &isp_buffer->vb2.vb2_buf; ++ ++ list_add_tail(&isp_buffer->list_entry, &vic->dma_queued_list); ++ vic->buffer_count++; ++ ++ ++ /*Y*/ ++ y_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 0); ++ vic_reg_writel(vic, VIC_DMA_Y_BUF0 + vic->buffer_index * 4, y_addr); ++ ++ uv_addr = y_addr + isp_buffer->uv_offset; ++ /*UV*/ ++ if(vb2_buf->num_planes == 2) { ++ uv_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 1); ++ } ++ vic_reg_writel(vic, VIC_DMA_UV_BUF0 + vic->buffer_index * 4, uv_addr); ++ ++ vic->buffer_index++; ++ vic->buffer_index %= ispvideo->max_buffer_num; ++ ++ if(vic->buffer_count >= VIC_RESTART_BUFFER_COUNT && vic->stop_flag) ++ { ++ /*reset flags*/ ++ vic->stop_flag = 0; ++ vic->buffer_index = 0; ++ ++ /*buffers in the list refill in register*/ ++ list_for_each_entry_safe(isp_buffer, tmp, &vic->dma_queued_list, list_entry) { ++ ++ vb2_buf = &isp_buffer->vb2.vb2_buf; ++ /*Y*/ ++ y_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 0); ++ vic_reg_writel(vic, VIC_DMA_Y_BUF0 + vic->buffer_index * 4, y_addr); ++ ++ uv_addr = y_addr + isp_buffer->uv_offset; ++ /*UV*/ ++ if(vb2_buf->num_planes == 2) { ++ uv_addr = ingenic_vb2_dma_contig_plane_dma_addr(vb2_buf, 1); ++ } ++ vic_reg_writel(vic, VIC_DMA_UV_BUF0 + vic->buffer_index * 4, uv_addr); ++ ++ vic->buffer_index++; ++ vic->buffer_index %= ispvideo->max_buffer_num; ++ ++ } ++ /*restart*/ ++ regval = vic_reg_readl(vic, VIC_DMA_CONFIG); ++ vic_reg_writel(vic, VIC_DMA_RESET, 1); ++ vic_reg_writel(vic, VIC_DMA_RESET, 0); ++ regval |= 1 << 31; /* enable dma */ ++ regval &= ~(0xf<<3); /* reset dma buffer num */ ++ regval |= (ispvideo->max_buffer_num - 1) << 3; ++ vic_reg_writel(vic, VIC_DMA_CONFIG, regval); ++ /* lgwang, re-start vic */ ++ if (vic->global_reset) { ++ vic_reg_writel(vic, VIC_CONTROL, 0x1); ++ vic->global_reset = 0; ++ } ++ goto done; ++ } ++ ++done: ++ spin_unlock_irqrestore(&vic->lock, flags); ++ ++ return 0; ++} ++ ++static const struct isp_video_ops vic_video_ops = { ++ .find_format = vic_find_format, ++ .qbuf = vic_video_qbuf, ++}; ++ ++static ssize_t ++dump_vic(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct vic_device *vic = dev_get_drvdata(dev); ++ char *p = buf; ++ ++ p += sprintf(p, "VIC_CONTROL :0x%08x\n", vic_reg_readl(vic, VIC_CONTROL)); ++ p += sprintf(p, "VIC_RESOLUTION :0x%08x\n", vic_reg_readl(vic, VIC_RESOLUTION)); ++ p += sprintf(p, "VIC_FRM_ECC :0x%08x\n", vic_reg_readl(vic, VIC_FRM_ECC)); ++ p += sprintf(p, "VIC_INTF_TYPE :0x%08x\n", vic_reg_readl(vic, VIC_INTF_TYPE)); ++ p += sprintf(p, "VIC_IN_DVP :0x%08x\n", vic_reg_readl(vic, VIC_IN_DVP)); ++ p += sprintf(p, "VIC_IN_CSI_FMT :0x%08x\n", vic_reg_readl(vic, VIC_IN_CSI_FMT)); ++ p += sprintf(p, "VIC_IN_HOR_PARA0 :0x%08x\n", vic_reg_readl(vic, VIC_IN_HOR_PARA0)); ++ p += sprintf(p, "VIC_IN_HOR_PARA1 :0x%08x\n", vic_reg_readl(vic, VIC_IN_HOR_PARA1)); ++ p += sprintf(p, "VIC_BK_CB_CTRL :0x%08x\n", vic_reg_readl(vic, VIC_BK_CB_CTRL)); ++ p += sprintf(p, "VIC_BK_CB_BLK :0x%08x\n", vic_reg_readl(vic, VIC_BK_CB_BLK)); ++ p += sprintf(p, "VIC_IN_VER_PARA0 :0x%08x\n", vic_reg_readl(vic, VIC_IN_VER_PARA0)); ++ p += sprintf(p, "VIC_IN_VER_PARA1 :0x%08x\n", vic_reg_readl(vic, VIC_IN_VER_PARA1)); ++ p += sprintf(p, "VIC_IN_VER_PARA2 :0x%08x\n", vic_reg_readl(vic, VIC_IN_VER_PARA2)); ++ p += sprintf(p, "VIC_IN_VER_PARA3 :0x%08x\n", vic_reg_readl(vic, VIC_IN_VER_PARA3)); ++ p += sprintf(p, "VIC_VLD_LINE_SAV :0x%08x\n", vic_reg_readl(vic, VIC_VLD_LINE_SAV)); ++ p += sprintf(p, "VIC_VLD_LINE_EAV :0x%08x\n", vic_reg_readl(vic, VIC_VLD_LINE_EAV)); ++ p += sprintf(p, "VIC_VLD_FRM_SAV :0x%08x\n", vic_reg_readl(vic, VIC_VLD_FRM_SAV)); ++ p += sprintf(p, "VIC_VLD_FRM_EAV :0x%08x\n", vic_reg_readl(vic, VIC_VLD_FRM_EAV)); ++ p += sprintf(p, "VIC_VC_CONTROL :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH0_PIX :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH0_PIX)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH1_PIX :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH1_PIX)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH2_PIX :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH2_PIX)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH3_PIX :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH3_PIX)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH0_LINE :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH0_LINE)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH1_LINE :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH1_LINE)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH2_LINE :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH2_LINE)); ++ p += sprintf(p, "VIC_VC_CONTROL_CH3_LINE :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_CH3_LINE)); ++ p += sprintf(p, "VIC_VC_CONTROL_FIFO_USE :0x%08x\n", vic_reg_readl(vic, VIC_VC_CONTROL_FIFO_USE)); ++ p += sprintf(p, "VIC_CB_1ST :0x%08x\n", vic_reg_readl(vic, VIC_CB_1ST)); ++ p += sprintf(p, "VIC_CB_2ND :0x%08x\n", vic_reg_readl(vic, VIC_CB_2ND)); ++ p += sprintf(p, "VIC_CB_3RD :0x%08x\n", vic_reg_readl(vic, VIC_CB_3RD)); ++ p += sprintf(p, "VIC_CB_4TH :0x%08x\n", vic_reg_readl(vic, VIC_CB_4TH)); ++ p += sprintf(p, "VIC_CB_5TH :0x%08x\n", vic_reg_readl(vic, VIC_CB_5TH)); ++ p += sprintf(p, "VIC_CB_6TH :0x%08x\n", vic_reg_readl(vic, VIC_CB_6TH)); ++ p += sprintf(p, "VIC_CB_7TH :0x%08x\n", vic_reg_readl(vic, VIC_CB_7TH)); ++ p += sprintf(p, "VIC_CB_8TH :0x%08x\n", vic_reg_readl(vic, VIC_CB_8TH)); ++ p += sprintf(p, "VIC_CB2_1ST :0x%08x\n", vic_reg_readl(vic, VIC_CB2_1ST)); ++ p += sprintf(p, "VIC_CB2_2ND :0x%08x\n", vic_reg_readl(vic, VIC_CB2_2ND)); ++ p += sprintf(p, "VIC_CB2_3RD :0x%08x\n", vic_reg_readl(vic, VIC_CB2_3RD)); ++ p += sprintf(p, "VIC_CB2_4TH :0x%08x\n", vic_reg_readl(vic, VIC_CB2_4TH)); ++ p += sprintf(p, "VIC_CB2_5TH :0x%08x\n", vic_reg_readl(vic, VIC_CB2_5TH)); ++ p += sprintf(p, "VIC_CB2_6TH :0x%08x\n", vic_reg_readl(vic, VIC_CB2_6TH)); ++ p += sprintf(p, "VIC_CB2_7TH :0x%08x\n", vic_reg_readl(vic, VIC_CB2_7TH)); ++ p += sprintf(p, "VIC_CB2_8TH :0x%08x\n", vic_reg_readl(vic, VIC_CB2_8TH)); ++ p += sprintf(p, "MIPI_ALL_WIDTH_4BYTE :0x%08x\n", vic_reg_readl(vic, MIPI_ALL_WIDTH_4BYTE)); ++ p += sprintf(p, "MIPI_VCROP_DEL01 :0x%08x\n", vic_reg_readl(vic, MIPI_VCROP_DEL01)); ++ p += sprintf(p, "MIPI_SENSOR_CONTROL :0x%08x\n", vic_reg_readl(vic, MIPI_SENSOR_CONTROL)); ++ p += sprintf(p, "MIPI_HCROP_CH0 :0x%08x\n", vic_reg_readl(vic, MIPI_HCROP_CH0)); ++ p += sprintf(p, "MIPI_VCROP_SHADOW_CFG :0x%08x\n", vic_reg_readl(vic, MIPI_VCROP_SHADOW_CFG)); ++ p += sprintf(p, "VIC_CONTROL_LIMIT :0x%08x\n", vic_reg_readl(vic, VIC_CONTROL_LIMIT)); ++ p += sprintf(p, "VIC_CONTROL_DELAY :0x%08x\n", vic_reg_readl(vic, VIC_CONTROL_DELAY)); ++ p += sprintf(p, "VIC_CONTROL_TIZIANO_ROUTE :0x%08x\n", vic_reg_readl(vic, VIC_CONTROL_TIZIANO_ROUTE)); ++ p += sprintf(p, "VIC_CONTROL_DMA_ROUTE :0x%08x\n", vic_reg_readl(vic, VIC_CONTROL_DMA_ROUTE)); ++ p += sprintf(p, "VIC_INT_STA :0x%08x\n", vic_reg_readl(vic, VIC_INT_STA)); ++ p += sprintf(p, "VIC_INT_MASK :0x%08x\n", vic_reg_readl(vic, VIC_INT_MASK)); ++ p += sprintf(p, "VIC_INT_CLR :0x%08x\n", vic_reg_readl(vic, VIC_INT_CLR)); ++ p += sprintf(p, "VIC_DMA_CONFIG :0x%08x\n", vic_reg_readl(vic, VIC_DMA_CONFIG)); ++ p += sprintf(p, "VIC_DMA_RESOLUTION :0x%08x\n", vic_reg_readl(vic, VIC_DMA_RESOLUTION)); ++ p += sprintf(p, "VIC_DMA_RESET :0x%08x\n", vic_reg_readl(vic, VIC_DMA_RESET)); ++ p += sprintf(p, "VIC_DMA_Y_STRID :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_STRID)); ++ p += sprintf(p, "VIC_DMA_Y_BUF0 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_BUF0)); ++ p += sprintf(p, "VIC_DMA_Y_BUF1 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_BUF1)); ++ p += sprintf(p, "VIC_DMA_Y_BUF2 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_BUF2)); ++ p += sprintf(p, "VIC_DMA_Y_BUF3 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_BUF3)); ++ p += sprintf(p, "VIC_DMA_Y_BUF4 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_Y_BUF4)); ++ p += sprintf(p, "VIC_DMA_UV_STRID :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_STRID)); ++ p += sprintf(p, "VIC_DMA_UV_BUF0 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_BUF0)); ++ p += sprintf(p, "VIC_DMA_UV_BUF1 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_BUF1)); ++ p += sprintf(p, "VIC_DMA_UV_BUF2 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_BUF2)); ++ p += sprintf(p, "VIC_DMA_UV_BUF3 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_BUF3)); ++ p += sprintf(p, "VIC_DMA_UV_BUF4 :0x%08x\n", vic_reg_readl(vic, VIC_DMA_UV_BUF4)); ++ ++ ++ ++ return p - buf; ++} ++ ++ssize_t vic_dma_debug(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct vic_device *vic = dev_get_drvdata(dev); ++ struct v4l2_subdev_format *input_fmt = &vic->formats[VIC_PAD_SINK]; ++ unsigned int imagesize = 0; ++ unsigned int lineoffset = 0; ++ int loop = 100; ++ struct file *fd = NULL; ++ mm_segment_t old_fs; ++ loff_t *pos; ++ int ret = 0; ++ ++ if (!strncmp(buf, "snapraw", sizeof("snapraw")-1)) { ++ if(!dma_debug_en) { ++ printk("please enable vic dma debug mode\ntry \"echo 1 > /sys/module/vic/parameters/dma_debug_en\"\n"); ++ return -EINVAL; ++ } ++ ++ lineoffset = input_fmt->format.width * 2; ++ imagesize = lineoffset * input_fmt->format.height; ++ dev_info(vic->dev, "width is %d,height is %d,imagesize is %d\n",input_fmt->format.width,input_fmt->format.height,imagesize); ++ if(input_fmt->format.width > VIC_DMA_OUTPUT_MAX_WIDTH){ ++ return -EINVAL; ++ } ++ if(vic->snap_paddr){ ++ return -EBUSY; ++ } ++ ++ vic->snap_vaddr = kmalloc(imagesize, GFP_KERNEL); ++ if(vic->snap_vaddr){ ++ vic->snap_paddr = virt_to_phys((void *)vic->snap_vaddr); ++ vic_reg_writel(vic, VIC_DMA_RESET, 0x01); ++ vic_reg_writel(vic, VIC_DMA_RESOLUTION, input_fmt->format.width << 16 | input_fmt->format.height); ++ vic_reg_writel(vic, VIC_DMA_Y_STRID, lineoffset); ++ vic_reg_writel(vic, VIC_DMA_Y_BUF0, vic->snap_paddr); ++ vic_reg_writel(vic, VIC_DMA_CONFIG, 0x1<<31); ++ while(loop){ ++ ret = wait_for_completion_interruptible(&vic->snap_comp); ++ if (ret >= 0) ++ break; ++ loop--; ++ } ++ if(!loop){ ++ dev_err(vic->dev, "snapraw timeout!\n"); ++ goto exit; ++ } ++ /* save raw */ ++ fd = filp_open("/tmp/snap.raw", O_CREAT | O_WRONLY | O_TRUNC, 00766); ++ if (fd < 0) { ++ dev_err(vic->dev, "Failed to open /tmp/snap.raw\n"); ++ goto exit; ++ } ++ ++ /* write file */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ pos = &(fd->f_pos); ++ vfs_write(fd, vic->snap_vaddr, imagesize, pos); ++ filp_close(fd, NULL); ++ set_fs(old_fs); ++ } ++ } ++ ++exit: ++ kfree(vic->snap_vaddr); ++ vic->snap_paddr = 0; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(dump_vic, S_IRUGO|S_IWUSR, dump_vic, NULL); ++static DEVICE_ATTR(vic_dma_debug, S_IRUGO|S_IWUSR, NULL, vic_dma_debug); ++ ++static struct attribute *vic_debug_attrs[] = { ++ &dev_attr_dump_vic.attr, ++#ifdef CONFIG_VIC_DMA_ROUTE ++ &dev_attr_vic_dma_debug.attr, ++#endif ++ NULL, ++}; ++ ++static struct attribute_group vic_debug_attr_group = { ++ .name = "debug", ++ .attrs = vic_debug_attrs, ++}; ++ ++int bypass_video_g_ctrl(struct file *file, void *fh, struct v4l2_control *a) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct isp_device *isp = ispcam->isp; ++ struct sensor_device *sensor = &isp->ispcam->sensor; ++ int ret = 0; ++ ++ ret = v4l2_g_ctrl(sensor->isd->sd->ctrl_handler,a); ++ if(ret < 0) { ++ dev_err(isp->dev, "failed to get ID:%d!\n", a->id); ++ } ++ return ret; ++} ++ ++int bypass_video_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) ++{ ++ struct isp_video_device *ispvideo = video_drvdata(file); ++ struct ispcam_device *ispcam = ispvideo->ispcam; ++ struct isp_device *isp = ispcam->isp; ++ struct sensor_device *sensor = &isp->ispcam->sensor; ++ int ret = 0; ++ ++ ret = v4l2_s_ctrl(NULL,sensor->isd->sd->ctrl_handler,a); ++ if(ret < 0) { ++ dev_err(isp->dev, "failed to set ID:%d!\n", a->id); ++ } ++ return ret; ++} ++ ++int vic_video_nr_map[2] = { ++ INGENIC_VIC0_VIDEO_NR, ++ INGENIC_VIC1_VIDEO_NR, ++}; ++ ++static int vic_comp_bind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct vic_device *vic = dev_get_drvdata(comp); ++ struct ispcam_device *ispcam = (struct ispcam_device *)master_data; ++ struct v4l2_device *v4l2_dev = &ispcam->v4l2_dev; ++ struct v4l2_subdev *sd = &vic->sd; ++ int ret = 0; ++ int nr = vic_video_nr_map[ispcam->dev_nr]; ++ struct isp_video_device *ispvideo = &vic->ispvideo; ++ char name[32]; ++ ++ //dev_info(comp, "--------%s, %d \n", __func__, __LINE__); ++ /* link subdev to master.*/ ++ vic->ispcam = (void *)ispcam; ++ ispcam->vic = vic; ++ ++ v4l2_subdev_init(sd, &vic_subdev_ops); ++ ++ ++ sd->owner = THIS_MODULE; ++ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ strscpy(sd->name, dev_name(comp), sizeof(sd->name)); ++ v4l2_set_subdevdata(sd, vic); ++ ++ /* init vic pads. */ ++ vic->pads = kzalloc(sizeof(struct media_pad) * VIC_NUM_PADS, GFP_KERNEL); ++ if(!vic->pads) { ++ ret = -ENOMEM; ++ goto err_alloc_pads; ++ } ++ vic->pads[0].index = VIC_PAD_SINK; ++ vic->pads[0].flags = MEDIA_PAD_FL_SINK; /* CSI->VIC, MIPI Interface*/ ++ vic->pads[1].index = VIC_PAD_SOURCE; ++ vic->pads[1].flags = MEDIA_PAD_FL_SOURCE; ++ ++ ret = media_entity_pads_init(&sd->entity, VIC_NUM_PADS, vic->pads); ++ ++ /*3. register v4l2_subdev*/ ++ sd->entity.function = MEDIA_ENT_F_IO_V4L; ++ ret = v4l2_device_register_subdev(v4l2_dev, sd); ++ if(ret < 0) { ++ dev_err(comp, "Failed to register v4l2_subdev for vic\n"); ++ goto err_subdev_register; ++ } ++ ++#ifdef CONFIG_VIC_DMA_ROUTE ++ init_completion(&vic->snap_comp); ++ ++ ispvideo->ispcam = ispcam; ++ ispvideo->bypass = 1; ++ sprintf(name, "%s", dev_name(vic->dev)); ++ ispvideo->video.v4l2_dev = &ispcam->v4l2_dev; ++ ret = isp_video_init(ispvideo, name, &vic_video_ops); ++ if(ret < 0) { ++ /*TODO:*/ ++ ++ } ++ ++ ret = isp_video_register(ispvideo, &ispcam->v4l2_dev, nr); ++ if(ret < 0) { ++ /*TODO:*/ ++ }; ++#endif ++ ++err_subdev_register: ++err_alloc_pads: ++ ++ ++ return ret; ++} ++ ++ ++static void vic_comp_unbind(struct device *comp, struct device *master, ++ void *master_data) ++{ ++ struct vic_device *vic = dev_get_drvdata(comp); ++ ++ dev_info(comp, "---TODO: %p-----%s, %d \n", vic, __func__, __LINE__); ++ ++} ++ ++static const struct component_ops vic_comp_ops = { ++ .bind = vic_comp_bind, ++ .unbind = vic_comp_unbind, ++}; ++ ++static irqreturn_t vic_irq_handler(int irq, void *data) ++{ ++ struct vic_device *vic = (struct vic_device *)data; ++ unsigned int status = 0; ++ struct isp_video_buffer *isp_buffer = NULL; ++ unsigned int regval; ++ ++ spin_lock(&vic->lock); ++ status = vic_reg_readl(vic, VIC_INT_STA); ++ //printk(KERN_DEBUG "VIC_INT_STA=%x\n", status); ++ /* DMA FRAME DONE */ ++ if(status & (1 << 7)) { ++ vic->frame_capture_counter++; ++ //printk(KERN_DEBUG "%d: vic->buffer_count=0x%x\n", vic->frame_capture_counter, vic->buffer_count); ++ ++#ifdef CONFIG_VIC_DMA_ROUTE ++ if(dma_debug_en){ ++ vic_reg_writel(vic, VIC_DMA_CONFIG, 0); ++ complete(&vic->snap_comp); ++ } else { ++ isp_buffer = list_first_entry_or_null(&vic->dma_queued_list, struct isp_video_buffer, list_entry); ++ if(!isp_buffer) { ++ dev_err(vic->dev, "[warning] no isp_buffer found in dma_queued_list when interrupt happend!\n"); ++ goto done; ++ } ++ ++ list_del(&isp_buffer->list_entry); ++ vic->buffer_count--; ++ ++ isp_buffer->vb2.vb2_buf.timestamp = ktime_get_ns(); ++ isp_buffer->vb2.sequence = vic->framenum++; ++ ++ vb2_buffer_done(&isp_buffer->vb2.vb2_buf, VB2_BUF_STATE_DONE); ++ ++ if(vic->buffer_count <= VIC_STOP_BUFFER_COUNT) ++ { ++ vic->stop_flag = 1; ++ regval = vic_reg_readl(vic, VIC_DMA_CONFIG); ++ regval &= ~(1 << 31); ++ vic_reg_writel(vic, VIC_DMA_CONFIG, regval); ++ vic_stop_counter++; ++ goto done; ++ } ++ } ++#endif ++ } ++ ++ if(status & (1 << 9)) { ++ //dev_err(vic->dev, ++ printk(KERN_DEBUG "vic->frame_capture_counter=%d, Image output limit too small! VIC_INT_STA=%x\n", vic->frame_capture_counter, status); ++ /* lgwang -- reset vic */ ++ vic->global_reset = 1; ++ vic_reg_writel(vic, VIC_CONTROL, 0x4); ++ vic->stop_flag = 1; ++ vic_stop_counter++; ++ } ++ ++done: ++ vic_reg_writel(vic, VIC_INT_CLR, status); ++ spin_unlock(&vic->lock); ++ return IRQ_HANDLED; ++ ++} ++ ++static int ingenic_vic_probe(struct platform_device *pdev) ++{ ++ ++ struct vic_device *vic = NULL; ++ struct resource *regs = NULL; ++ int ret = 0; ++ ++ vic = kzalloc(sizeof(struct vic_device), GFP_KERNEL); ++ if(!vic) { ++ pr_err("Failed to alloc vic dev [%s]\n", pdev->name); ++ return -ENOMEM; ++ } ++ ++ vic->dev = &pdev->dev; ++ platform_set_drvdata(pdev, vic); ++ ++ ++ ingenic_vic_parse_dt(vic); ++ ++ vic->irq = platform_get_irq(pdev, 0); ++ if(vic->irq < 0) { ++ dev_warn(&pdev->dev, "No CSI IRQ specified\n"); ++ } ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(!regs) { ++ dev_err(&pdev->dev, "No iomem resource!\n"); ++ goto err_get_resource; ++ } ++ ++ vic->iobase = devm_ioremap_resource(&pdev->dev, regs); ++ if(!vic->iobase) { ++ goto err_ioremap; ++ } ++ ++ spin_lock_init(&vic->lock); ++ INIT_LIST_HEAD(&vic->dma_queued_list); ++ ++ ret = devm_request_irq(vic->dev, vic->irq, vic_irq_handler, 0, ++ dev_name(vic->dev), vic); ++ if(ret) { ++ dev_err(vic->dev, "request irq failed!\n"); ++ goto err_request_irq; ++ } ++ ++ ret = sysfs_create_group(&vic->dev->kobj, &vic_debug_attr_group); ++ if (ret) { ++ dev_err(vic->dev, "device create sysfs group failed\n"); ++ ++ ret = -EINVAL; ++ goto err_sys_group; ++ } ++ ++ ret = component_add(vic->dev, &vic_comp_ops); ++ if(ret < 0) { ++ dev_err(vic->dev, "Failed to add component vic!\n"); ++ goto err_component; ++ } ++ ++ return 0; ++err_component: ++err_sys_group: ++err_request_irq: ++err_ioremap: ++err_get_resource: ++ return ret; ++} ++ ++ ++ ++static int ingenic_vic_remove(struct platform_device *pdev) ++{ ++ ++ return 0; ++} ++ ++ ++ ++static const struct of_device_id ingenic_vic_dt_match[] = { ++ { .compatible = "ingenic,x2000-vic" }, ++ { .compatible = "ingenic,m300-vic" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_vic_dt_match); ++ ++static int __maybe_unused ingenic_vic_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct vic_device *vic = dev_get_drvdata(&pdev->dev); ++ ++ if(vic->enabled){ ++ dev_err(vic->dev, "faild to suspend, vic is streaming on\n"); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static int __maybe_unused ingenic_vic_resume(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver ingenic_vic_driver = { ++ .probe = ingenic_vic_probe, ++ .remove = ingenic_vic_remove, ++ .suspend = ingenic_vic_suspend, ++ .resume = ingenic_vic_resume, ++ .driver = { ++ .name = "ingenic-vic", ++ .of_match_table = ingenic_vic_dt_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_vic_driver); ++ ++MODULE_ALIAS("platform:ingenic-vic"); ++MODULE_DESCRIPTION("ingenic vic subsystem"); ++MODULE_AUTHOR("qipengzhen "); ++MODULE_LICENSE("GPL v2"); ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-rotate/Kconfig b/module_drivers/drivers/media/platform/ingenic-rotate/Kconfig +new file mode 100644 +index 000000000..8cc9e556a +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-rotate/Kconfig +@@ -0,0 +1,8 @@ ++config VIDEO_INGENIC_ROTATE ++ depends on VIDEO_DEV && VIDEO_V4L2 ++ tristate "Ingenic rotate driver" ++ select VIDEOBUF2_DMA_CONTIG_INGENIC ++ select V4L2_MEM2MEM_DEV ++ help ++ This is a v4l2 driver for Ingenic rotate ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-rotate/Makefile b/module_drivers/drivers/media/platform/ingenic-rotate/Makefile +new file mode 100644 +index 000000000..1fa30b670 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-rotate/Makefile +@@ -0,0 +1,2 @@ ++ingenic_rotate-y := rotate.o rotate-hw.o ++obj-$(CONFIG_VIDEO_INGENIC_ROTATE) += ingenic_rotate.o +diff --git a/module_drivers/drivers/media/platform/ingenic-rotate/rotate-hw.c b/module_drivers/drivers/media/platform/ingenic-rotate/rotate-hw.c +new file mode 100644 +index 000000000..fefc6de7d +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-rotate/rotate-hw.c +@@ -0,0 +1,317 @@ ++/* * drivers/media/platform/ingenic_rotate/rotate-hw.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * This program is free software, you can redistribute it and/or modify it ++ * ++ * under the terms of the GNU General Public License version 2 as published by ++ * ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++ ++#include "rotate.h" ++#include "rotate-regs.h" ++ ++void dump_rot_reg(struct ingenic_rot_dev *dev) ++{ ++ printk("-----------------rot_reg------------------\n"); ++ printk("ROT_FRM_CFG_ADDR: 0x%lx\n",reg_read(dev, ROT_FRM_CFG_ADDR)); ++ printk("ROT_FRM_SIZE: 0x%lx\n",reg_read(dev, ROT_FRM_SIZE)); ++ printk("ROT_GLB_CFG: 0x%lx\n",reg_read(dev, ROT_GLB_CFG)); ++ printk("ROT_CTRL: 0x%lx\n",reg_read(dev, ROT_CTRL)); ++ printk("ROT_ST: 0x%lx\n",reg_read(dev, ROT_ST)); ++ printk("ROT_CLR_ST: 0x%lx\n",reg_read(dev, ROT_CLR_ST)); ++ printk("ROT_INT_MASK: 0x%lx\n",reg_read(dev, ROT_INT_MASK)); ++ printk("ROT_RDMA_SITE: 0x%lx\n",reg_read(dev, ROT_RDMA_SITE)); ++ printk("ROT_WDMA_SITE: 0x%lx\n",reg_read(dev, ROT_WDMA_SITE)); ++ printk("ROT_QOS_CTRL: 0x%lx\n",reg_read(dev, ROT_QOS_CTRL)); ++ printk("ROT_QOS_CFG: 0x%lx\n",reg_read(dev, ROT_QOS_CFG)); ++ printk("-----------------rot_reg------------------\n"); ++} ++ ++void dump_rot_desc(struct ingenic_rot_desc *desc) ++{ ++ printk("-----------------rot_desc------------------\n"); ++ printk("rot_des 0x%x\n",(uint32_t)desc); ++ printk("NextCfgAddr: 0x%x\n",desc->NextCfgAddr); ++ printk("SrcBufferAddr: 0x%x\n",desc->SrcBufferAddr); ++ printk("SrcStride: 0x%x\n",desc->SrcStride); ++ printk("FrameStop: 0x%x\n",desc->FrameStop.d32); ++ printk("TargetBufferAddr: 0x%x\n",desc->TargetBufferAddr); ++ printk("TargetStride: 0x%x\n",desc->TargetStride); ++ printk("irq_ctrl: 0x%x\n",desc->irq_ctrl.d32); ++ printk("-----------------rot_desc------------------\n"); ++} ++ ++void dump_rot_desc_reg(struct ingenic_rot_dev *dev) ++{ ++ reg_write(dev, ROT_CTRL, ROT_DES_CNT_RST); ++ printk("-----------------rot_desc_reg------------------\n"); ++ printk("NextCfgAddr: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("SrcBufferAddr: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("SrcStride: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("FrameStop: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("TargetBufferAddr: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("TargetStride: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("irq_ctrl: 0x%lx\n",reg_read(dev, ROT_DS_FRM_DES)); ++ printk("-----------------rot_desc_reg------------------\n"); ++} ++ ++void dump_all(struct ingenic_rot_dev *dev) ++{ ++ struct ingenic_rot_ctx *ctx; ++ ++ ctx = dev->curr; ++ ++ dump_rot_reg(dev); ++ dump_rot_desc_reg(dev); ++ dump_rot_desc(ctx->desc[0]); ++} ++ ++void rot_clr_irq(struct ingenic_rot_dev *dev) ++{ ++ uint32_t flag; ++ ++ flag = reg_read(dev, ROT_INT_MASK) & reg_read(dev, ROT_ST); ++ if(flag & ROT_EOF) { ++ reg_write(dev, ROT_CLR_ST, ROT_CLR_EOF); ++ } ++ if(flag & ROT_SOF) { ++ reg_write(dev, ROT_CLR_ST, ROT_CLR_SOF); ++ } ++ if(flag & ROT_GEN_STOP_ACK) { ++ reg_write(dev, ROT_CLR_ST, ROT_GEN_STOP_ACK); ++ } ++} ++ ++int wait_rot_state(struct ingenic_rot_dev *dev, int32_t state, uint32_t flag) ++{ ++ unsigned long timeout = 100000; ++ while(( (!(reg_read(dev, ROT_ST) & state)) == flag) && timeout) { ++ timeout--; ++ udelay(10); ++ } ++ if(timeout <= 0) { ++ printk("wait state timeout! state = %d, ROT_ST = 0x%lx\n", state, reg_read(dev, ROT_ST)); ++ return -1; ++ } ++ return 0; ++} ++ ++void rot_set_src_desc(struct ingenic_rot_dev *dev, dma_addr_t addr) ++{ ++ struct ingenic_rot_ctx *ctx; ++ struct ingenic_rot_desc *desc; ++ struct rot_frm_info *frm_info; ++ ++ ctx = dev->curr; ++ desc = ctx->desc[0]; ++ frm_info = &ctx->in; ++ ++ desc->NextCfgAddr = ctx->desc_phys[0]; ++ desc->SrcBufferAddr = addr; ++ desc->SrcStride = frm_info->width; ++} ++ ++void rot_set_dst_desc(struct ingenic_rot_dev *dev, dma_addr_t addr) ++{ ++ struct ingenic_rot_ctx *ctx; ++ struct ingenic_rot_desc *desc; ++ struct rot_frm_info *frm_info; ++ ++ ctx = dev->curr; ++ desc = ctx->desc[0]; ++ frm_info = &ctx->out; ++ ++ desc->TargetBufferAddr = addr; ++ ++ if((ctx->angle == 90) || (ctx->angle == 270)) ++ desc->TargetStride = frm_info->height; ++ else ++ desc->TargetStride = frm_info->width; ++} ++ ++void rot_set_hflip(struct ingenic_rot_dev *dev, uint32_t hflip) ++{ ++ uint32_t cfg; ++ ++ cfg = reg_read(dev, ROT_GLB_CFG); ++ if(hflip) ++ cfg |= ROT_H_MIRROR; ++ else ++ cfg &= ~ROT_H_MIRROR; ++ ++ reg_write(dev, ROT_GLB_CFG, cfg); ++} ++ ++void rot_set_vflip(struct ingenic_rot_dev *dev, uint32_t vflip) ++{ ++ uint32_t cfg; ++ ++ cfg = reg_read(dev, ROT_GLB_CFG); ++ if(vflip) ++ cfg |= ROT_V_MIRROR; ++ else ++ cfg &= ~ROT_V_MIRROR; ++ ++ reg_write(dev, ROT_GLB_CFG, cfg); ++} ++ ++void rot_set_angle(struct ingenic_rot_dev *dev, uint32_t angle) ++{ ++ uint32_t cfg; ++ ++ cfg = reg_read(dev, ROT_GLB_CFG); ++ switch(angle) { ++ case 0: ++ cfg |= ROT_ANGLE_0; ++ break; ++ case 90: ++ cfg |= ROT_ANGLE_90; ++ break; ++ case 180: ++ cfg |= ROT_ANGLE_180; ++ break; ++ case 270: ++ cfg |= ROT_ANGLE_270; ++ break; ++ default: ++ printk("!!!!!Not support angle!\n"); ++ break; ++ } ++ ++ reg_write(dev, ROT_GLB_CFG, cfg); ++} ++ ++void rot_set_dst_cfg(struct ingenic_rot_dev *dev, struct rot_frm_info *out) ++{ ++ uint32_t cfg; ++ ++ cfg = reg_read(dev, ROT_GLB_CFG); ++ switch(out->fmt->fourcc) { ++ case V4L2_PIX_FMT_RGB32: ++ case V4L2_PIX_FMT_XRGB32: ++ case V4L2_PIX_FMT_ARGB32: ++ cfg |= ROT_WDMA_FMT_ARGB8888; ++ break; ++ case V4L2_PIX_FMT_RGB565: ++ cfg |= ROT_WDMA_FMT_RGB565; ++ break; ++ case V4L2_PIX_FMT_RGB555: ++ cfg |= ROT_WDMA_FMT_RGB555; ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ cfg |= ROT_WDMA_FMT_YUV422; ++ break; ++ default: ++ printk("!!!!!Not support fmt!\n"); ++ break; ++ } ++ reg_write(dev, ROT_GLB_CFG, cfg); ++} ++ ++void rot_set_src_cfg(struct ingenic_rot_dev *dev, struct rot_frm_info *in) ++{ ++ uint32_t cfg; ++ uint32_t frm_size = 0; ++ ++ frm_size |= in->width << ROT_FRM_WIDTH_LBIT; ++ frm_size |= in->height << ROT_FRM_HEIGHT_LBIT; ++ reg_write(dev, ROT_FRM_SIZE, frm_size); ++ ++ cfg = reg_read(dev, ROT_GLB_CFG); ++ switch(in->fmt->fourcc) { ++ case V4L2_PIX_FMT_ARGB32: ++ case V4L2_PIX_FMT_RGB32: ++ cfg |= ROT_RDMA_FMT_ARGB8888; ++ break; ++ case V4L2_PIX_FMT_XRGB32: ++ cfg |= ROT_RDMA_FMT_RGB888; ++ break; ++ case V4L2_PIX_FMT_ABGR32: ++ case V4L2_PIX_FMT_BGR32: ++ cfg |= ROT_RDMA_FMT_ARGB8888; ++ cfg |= ROT_RDMA_ORDER_BGR; ++ break; ++ case V4L2_PIX_FMT_XBGR32: ++ cfg |= ROT_RDMA_FMT_RGB888; ++ cfg |= ROT_RDMA_ORDER_BGR; ++ break; ++ case V4L2_PIX_FMT_RGB565: ++ cfg |= ROT_RDMA_FMT_RGB565; ++ break; ++ case V4L2_PIX_FMT_RGB555: ++ cfg |= ROT_RDMA_FMT_RGB555; ++ break; ++ case V4L2_PIX_FMT_ARGB555: ++ cfg |= ROT_RDMA_FMT_RGB1555; ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ cfg |= ROT_RDMA_FMT_YUV422; ++ break; ++ default: ++ printk("!!!!!Not support fmt!\n"); ++ break; ++ } ++ reg_write(dev, ROT_GLB_CFG, cfg); ++} ++ ++#define CPM_ROT_SOFT_RESET (0x1 << 17) ++#define CPM_SOFT_RESET (0xb00000c4) ++void rot_cpm_reset(void) ++{ ++ outl(CPM_ROT_SOFT_RESET, CPM_SOFT_RESET); ++ udelay(2); ++ outl(0, CPM_SOFT_RESET); ++} ++ ++void rot_reset(struct ingenic_rot_dev *dev) ++{ ++ struct ingenic_rot_ctx *ctx; ++ uint32_t cfg = 0; ++ int i; ++ ++ ctx = dev->curr; ++ ++ for(i = 0; i < ROT_DESC_NUM; i++) { ++ memset(ctx->desc[i], 0, sizeof(struct ingenic_rot_desc)); ++ } ++#if defined(ROT_GEN_STOP) || defined(ROT_QCK_STOP) ++ ctx->desc[0]->FrameStop.b.stop = 0; ++#else ++ ctx->desc[0]->FrameStop.b.stop = 1; ++#endif ++ ctx->desc[0]->irq_ctrl.d32 = ROT_EOF_MASK | ROT_SOF_MASK; ++ cfg = ROT_WDMA_BURST_32 | ROT_RDMA_BURST_32; ++ cfg |= ROT_RDMA_ORDER_RGB; ++ ++ /* ahb0 = 300M 720p 60fps */ ++ reg_write(dev, ROT_QOS_CFG, (reg_read(dev, ROT_QOS_CFG) & (~0xff)) | 13); ++ /* Set rot qos value */ ++ reg_write(dev, ROT_QOS_CTRL, 0x1); ++ reg_write(dev, ROT_GLB_CFG, cfg); ++ reg_write(dev, ROT_FRM_CFG_ADDR, ctx->desc_phys[0]); ++} ++ ++void rot_start(struct ingenic_rot_dev *dev) ++{ ++ reg_write(dev, ROT_INT_MASK, ROT_EOF_MASK); ++ reg_write(dev, ROT_CTRL, ROT_START); ++} ++ ++void rot_qck_stop(struct ingenic_rot_dev *dev) ++{ ++ reg_write(dev, ROT_CTRL, ROT_QCK_STP); ++ return; ++} ++ ++void rot_gen_stop(struct ingenic_rot_dev *dev) ++{ ++ reg_write(dev, ROT_CTRL, ROT_GEN_STP); ++ return; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-rotate/rotate-regs.h b/module_drivers/drivers/media/platform/ingenic-rotate/rotate-regs.h +new file mode 100644 +index 000000000..e66d6c643 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-rotate/rotate-regs.h +@@ -0,0 +1,204 @@ ++/* * drivers/media/platform/ingenic_rotate/rotate-regs.h ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * This program is free software, you can redistribute it and/or modify it ++ * ++ * under the terms of the GNU General Public License version 2 as published by ++ * ++ * the Free Software Foundation. ++ */ ++ ++#ifndef __ROTATER_REG_H__ ++#define __ROTATER_REG_H__ ++ ++/*------------------------------------------------------------------------------- ++ * Rotater Register Offset ++ * -----------------------------------------------------------------------------*/ ++ ++ ++/* RW 32 0x0000_0000 frame descriptor's addres */ ++#define ROT_FRM_CFG_ADDR (0x0000) ++/* RW 32 0x0000_0000 frame's size */ ++#define ROT_FRM_SIZE (0x0004) ++/* RW 32 0x0000_0000 global config */ ++#define ROT_GLB_CFG (0x0008) ++/* -W 32 0x0000_0000 rotate control */ ++#define ROT_CTRL (0x000c) ++/* R- 32 0x0000_0000 rotate status */ ++#define ROT_ST (0x0010) ++/* R- 32 0x0000_0000 rotarer clear status */ ++#define ROT_CLR_ST (0x0014) ++/* -W 32 0x0000_0000 rotator interrupt mask */ ++#define ROT_INT_MASK (0x0018) ++/* RW 32 0x0000_0000 RDMA`s current site */ ++#define ROT_RDMA_SITE (0x0020) ++/* RW 32 0x0000_0000 WDMA`s current site */ ++#define ROT_WDMA_SITE (0x0024) ++/* R- 32 0x0000_0000 Read the frame configure */ ++#define ROT_DS_FRM_DES (0x0028) ++/* RW 32 0x0000_0000 Rotator QOS config */ ++#define ROT_QOS_CTRL (0x0030) ++#define ROT_QOS_CFG (0x0034) ++ ++ ++/*------------------------------------------------------------------------------- ++ * DPU Registers Bits Field Define ++ * -----------------------------------------------------------------------------*/ ++ ++ ++/* frame's size(ROT_FRM_SIZE) bit field define */ ++ ++/* Frame's width */ ++#define ROT_FRM_WIDTH_LBIT (0) ++#define ROT_FRM_WIDTH_HBIT (10) ++#define ROT_FRM_WIDTH_MASK \ ++ GENMASK(ROT_FRM_WIDTH_HBIT, ROT_FRM_WIDTH_LBIT) ++/* Frame's height */ ++#define ROT_FRM_HEIGHT_LBIT (16) ++#define ROT_FRM_HEIGHT_HBIT (26) ++#define ROT_FRM_HEIGHT_MASK \ ++ GENMASK(ROT_FRM_HEIGHT_HBIT, ROT_FRM_HEIGHT_LBIT) ++ ++/* global config(ROT_GLB_CFG) bit field define */ ++ ++/* RDMA max length of the block DMA's burst. */ ++#define ROT_RDMA_BURST_LEN_LBIT (0) ++#define ROT_RDMA_BURST_LEN_HBIT (1) ++#define ROT_RDMA_BURST_LEN_MASK \ ++ GENMASK(ROT_RDMA_BURST_LEN_HBIT, ROT_RDMA_BURST_LEN_LBIT) ++ ++#define ROT_RDMA_BURST_4 (0) << ROT_RDMA_BURST_LEN_LBIT ++#define ROT_RDMA_BURST_8 (1) << ROT_RDMA_BURST_LEN_LBIT ++#define ROT_RDMA_BURST_16 (2) << ROT_RDMA_BURST_LEN_LBIT ++#define ROT_RDMA_BURST_32 (3) << ROT_RDMA_BURST_LEN_LBIT ++/* WDMA max length of the block DMA's burst. */ ++#define ROT_WDMA_BURST_LEN_LBIT (2) ++#define ROT_WDMA_BURST_LEN_HBIT (3) ++#define ROT_WDMA_BURST_LEN_MASK \ ++ GENMASK(ROT_WDMA_BURST_LEN_HBIT, ROT_WDMA_BURST_LEN_LBIT) ++ ++#define ROT_WDMA_BURST_4 (0) << ROT_WDMA_BURST_LEN_LBIT ++#define ROT_WDMA_BURST_8 (1) << ROT_WDMA_BURST_LEN_LBIT ++#define ROT_WDMA_BURST_16 (2) << ROT_WDMA_BURST_LEN_LBIT ++#define ROT_WDMA_BURST_32 (3) << ROT_WDMA_BURST_LEN_LBIT ++/* Rotater angle. */ ++#define ROT_ANGLE_LBIT (4) ++#define ROT_ANGLE_HBIT (5) ++#define ROT_ANGLE_MASK \ ++ GENMASK(ROT_ANGLE_HBIT, ROT_ANGLE_LBIT) ++ ++#define ROT_ANGLE_0 (0) << ROT_ANGLE_LBIT ++#define ROT_ANGLE_90 (1) << ROT_ANGLE_LBIT ++#define ROT_ANGLE_180 (2) << ROT_ANGLE_LBIT ++#define ROT_ANGLE_270 (3) << ROT_ANGLE_LBIT ++/* Vertical mirror */ ++#define ROT_V_MIRROR BIT(6) ++/* Horizontal mirror */ ++#define ROT_H_MIRROR BIT(7) ++/* Target format. */ ++#define ROT_WDMA_FMT_LBIT (12) ++#define ROT_WDMA_FMT_HBIT (13) ++#define ROT_WDMA_FMT_MASK \ ++ GENMASK(ROT_WDMA_FMT_HBIT, ROT_WDMA_FMT_LBIT) ++ ++#define ROT_WDMA_FMT_ARGB8888 (0) << ROT_WDMA_FMT_LBIT ++#define ROT_WDMA_FMT_RGB565 (1) << ROT_WDMA_FMT_LBIT ++#define ROT_WDMA_FMT_RGB555 (2) << ROT_WDMA_FMT_LBIT ++#define ROT_WDMA_FMT_YUV422 (3) << ROT_WDMA_FMT_LBIT ++/* RDMA ORDER. */ ++#define ROT_RDMA_ORDER_LBIT (16) ++#define ROT_RDMA_ORDER_HBIT (18) ++#define ROT_RDMA_ORDER_MASK \ ++ GENMASK(ROT_RDMA_ORDER_HBIT, ROT_RDMA_ORDER_LBIT) ++ ++#define ROT_RDMA_ORDER_RGB (0) << ROT_RDMA_ORDER_LBIT ++#define ROT_RDMA_ORDER_RBG (1) << ROT_RDMA_ORDER_LBIT ++#define ROT_RDMA_ORDER_GRB (2) << ROT_RDMA_ORDER_LBIT ++#define ROT_RDMA_ORDER_GBR (3) << ROT_RDMA_ORDER_LBIT ++#define ROT_RDMA_ORDER_BRG (4) << ROT_RDMA_ORDER_LBIT ++#define ROT_RDMA_ORDER_BGR (5) << ROT_RDMA_ORDER_LBIT ++/* RDMA format. */ ++#define ROT_RDMA_FMT_LBIT (24) ++#define ROT_RDMA_FMT_HBIT (27) ++#define ROT_RDMA_FMT_MASK \ ++ GENMASK(ROT_RDMA_FMT_HBIT, ROT_RDMA_FMT_LBIT) ++ ++#define ROT_RDMA_FMT_RGB555 (0) << ROT_RDMA_FMT_LBIT ++#define ROT_RDMA_FMT_RGB1555 (1) << ROT_RDMA_FMT_LBIT ++#define ROT_RDMA_FMT_RGB565 (2) << ROT_RDMA_FMT_LBIT ++#define ROT_RDMA_FMT_RGB888 (4) << ROT_RDMA_FMT_LBIT ++#define ROT_RDMA_FMT_ARGB8888 (5) << ROT_RDMA_FMT_LBIT ++#define ROT_RDMA_FMT_YUV422 (10) << ROT_RDMA_FMT_LBIT ++ ++/* rotate control(ROT_CTRL) bit field define */ ++ ++/* START */ ++#define ROT_START BIT(0) ++/* QCK_STOP */ ++#define ROT_QCK_STP BIT(1) ++/* GEN_STOP */ ++#define ROT_GEN_STP BIT(2) ++/* Reset the counter of FRM_DES */ ++#define ROT_DES_CNT_RST BIT(3) ++ ++/* rotate status(ROT_SATUS) bit field define */ ++ ++/* Rotater is working */ ++#define ROT_WORKING BIT(0) ++/* Rotater is general stop */ ++#define ROT_GEN_STOP_ACK BIT(1) ++/* One frame read end */ ++#define ROT_EOF BIT(2) ++/* One frme read start */ ++#define ROT_SOF BIT(3) ++/* Mask of ROT_GEN_STOP_ACK */ ++#define ROT_GSA_MASK_ST BIT(17) ++/* Mask of FRM_END */ ++#define ROT_EOF_MASK_ST BIT(18) ++/* Mask of FRM_START */ ++#define ROT_SOF_MASK_ST BIT(19) ++ ++/* rotarer clear status(ROT_CLR_ST) bit field define */ ++ ++/* Clear general stop acknowledge */ ++#define ROT_CLR_GEN_STOP_ACK BIT(1) ++/* Clear FRM_END */ ++#define ROT_CLR_EOF BIT(2) ++/* Clear FRM_START */ ++#define ROT_CLR_SOF BIT(3) ++ ++/* rotator interrupt mask(ROT_INT_MASK) bit field define */ ++ ++/* Mask general stop acknowledge */ ++#define ROT_GSA_MASK BIT(1) ++/* Mask FRM_END */ ++#define ROT_EOF_MASK BIT(2) ++/* Mask FRM_START */ ++#define ROT_SOF_MASK BIT(3) ++ ++/* rotator QOS config (ROT_QOS) bit field define */ ++ ++/* STD_CLK */ ++#define ROT_STD_CLK_LBIT (0) ++#define ROT_STD_CLK_HBIT (7) ++#define ROT_STD_CLK_MASK \ ++ GENMASK(ROT_STD_CLK_HBIT, ROT_STD_CLK_LBIT) ++/* STD_THR0 */ ++#define ROT_STD_THR0_LBIT (8) ++#define ROT_STD_THR0_HBIT (15) ++#define ROT_STD_THR0_MASK \ ++ GENMASK(ROT_STD_THR0_HBIT, ROT_STD_THR0_LBIT) ++/* STD_THR1 */ ++#define ROT_STD_THR1_LBIT (16) ++#define ROT_STD_THR1_HBIT (23) ++#define ROT_STD_THR1_MASK \ ++ GENMASK(ROT_STD_THR1_HBIT, ROT_STD_THR1_LBIT) ++/* STD_THR2 */ ++#define ROT_STD_THR2_LBIT (24) ++#define ROT_STD_THR2_HBIT (31) ++#define ROT_STD_THR2_MASK \ ++ GENMASK(ROT_STD_THR2_HBIT, ROT_STD_THR2_LBIT) ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-rotate/rotate.c b/module_drivers/drivers/media/platform/ingenic-rotate/rotate.c +new file mode 100644 +index 000000000..f09e60380 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-rotate/rotate.c +@@ -0,0 +1,876 @@ ++/* * drivers/media/platform/ingenic_rotate/rotate.c ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * This program is free software, you can redistribute it and/or modify it ++ * ++ * under the terms of the GNU General Public License version 2 as published by ++ * ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++#include ++#include ++ ++#include "rotate.h" ++#include "rotate-regs.h" ++ ++#define fh2ctx(__fh) container_of(__fh, struct ingenic_rot_ctx, fh) ++ ++static ktime_t time_now, time_last; ++static long interval_in_ns; ++ ++static struct rot_fmt formats[] = { ++ { ++ .name = "ARGB_8888", ++ .fourcc = V4L2_PIX_FMT_ARGB32, ++ .depth = 32, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "RGB_8888", ++ .fourcc = V4L2_PIX_FMT_RGB32, ++ .depth = 32, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "RGB_8888", ++ .fourcc = V4L2_PIX_FMT_XRGB32, ++ .depth = 32, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "ABGR_8888", ++ .fourcc = V4L2_PIX_FMT_ABGR32, ++ .depth = 32, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "BGR_8888", ++ .fourcc = V4L2_PIX_FMT_BGR32, ++ .depth = 32, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "BGR_8888", ++ .fourcc = V4L2_PIX_FMT_XBGR32, ++ .depth = 32, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "RGB_565", ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .depth = 16, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "RGB_555", ++ .fourcc = V4L2_PIX_FMT_RGB555, ++ .depth = 16, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "ARGB_1555", ++ .fourcc = V4L2_PIX_FMT_ARGB555, ++ .depth = 16, ++ .types = MEM2MEM_OUTPUT, ++ }, ++ { ++ .name = "YUV 422P", ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .depth = 16, ++ .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, ++ }, ++}; ++#define NUM_FORMATS ARRAY_SIZE(formats) ++ ++static struct rot_fmt *find_fmt(struct v4l2_format *f) ++{ ++ unsigned int i; ++ for (i = 0; i < NUM_FORMATS; i++) { ++ if (formats[i].fourcc == f->fmt.pix.pixelformat) ++ return &formats[i]; ++ } ++ return NULL; ++} ++ ++ ++static struct rot_frm_info *get_frame(struct ingenic_rot_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ switch (type) { ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ return &ctx->in; ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ return &ctx->out; ++ default: ++ return ERR_PTR(-EINVAL); ++ } ++} ++ ++static int rot_queue_setup(struct vb2_queue *vq, ++ unsigned int *nbuffers, unsigned int *nplanes, ++ unsigned int sizes[], struct device *alloc_ctxs[]) ++{ ++ struct ingenic_rot_ctx *ctx = vb2_get_drv_priv(vq); ++ struct rot_frm_info *f = get_frame(ctx, vq->type); ++ ++ if (IS_ERR(f)) ++ return PTR_ERR(f); ++ ++ *nplanes = 1; ++ sizes[0] = f->size; ++ alloc_ctxs[0] = ctx->dev->dev; ++ ++ if (*nbuffers == 0) ++ *nbuffers = 1; ++ ++ return 0; ++} ++ ++static int rot_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct ingenic_rot_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct rot_frm_info *f = get_frame(ctx, vb->vb2_queue->type); ++ ++ if (IS_ERR(f)) ++ return PTR_ERR(f); ++ vb2_set_plane_payload(vb, 0, f->size); ++ return 0; ++} ++ ++static void rot_buf_queue(struct vb2_buffer *vb) ++{ ++ struct ingenic_rot_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ ++ if (ctx->m2m_ctx) ++ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); ++} ++ ++ ++static struct vb2_ops rot_qops = { ++ .queue_setup = rot_queue_setup, ++ .buf_prepare = rot_buf_prepare, ++ .buf_queue = rot_buf_queue, ++}; ++ ++static int queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq) ++{ ++ struct ingenic_rot_ctx *ctx = priv; ++ int ret; ++ ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ src_vq->io_modes = VB2_MMAP | VB2_USERPTR; ++ src_vq->drv_priv = ctx; ++ src_vq->ops = &rot_qops; ++ src_vq->mem_ops = &ingenic_vb2_dma_contig_memops; ++ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); ++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ src_vq->lock = &ctx->dev->mutex; ++ ++ ret = vb2_queue_init(src_vq); ++ if (ret) ++ return ret; ++ ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; ++ dst_vq->drv_priv = ctx; ++ dst_vq->ops = &rot_qops; ++ dst_vq->mem_ops = &ingenic_vb2_dma_contig_memops; ++ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); ++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ dst_vq->lock = &ctx->dev->mutex; ++ ++ return vb2_queue_init(dst_vq); ++} ++ ++static int rot_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ingenic_rot_ctx *ctx = container_of(ctrl->handler, struct ingenic_rot_ctx, ++ ctrl_handler); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ctx->dev->ctrl_lock, flags); ++ switch (ctrl->id) { ++ case V4L2_CID_HFLIP: ++ ctx->hflip = ctx->ctrl_hflip->val; ++ break; ++ case V4L2_CID_VFLIP: ++ ctx->vflip = ctx->ctrl_vflip->val; ++ break; ++ case V4L2_CID_ROTATE: ++ ctx->angle = ctx->ctrl_rot->val; ++ break; ++ } ++ spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags); ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops rot_ctrl_ops = { ++ .s_ctrl = rot_s_ctrl, ++}; ++ ++static int rot_setup_ctrls(struct ingenic_rot_ctx *ctx) ++{ ++ struct ingenic_rot_dev *dev = ctx->dev; ++ ++ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); ++ ++ ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &rot_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ ++ ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &rot_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ ctx->ctrl_rot = v4l2_ctrl_new_std(&ctx->ctrl_handler, &rot_ctrl_ops, ++ V4L2_CID_ROTATE, 0, 270, 90, 0); ++ ++ if (ctx->ctrl_handler.error) { ++ int err = ctx->ctrl_handler.error; ++ v4l2_err(&dev->v4l2_dev, "rot_setup_ctrls failed\n"); ++ v4l2_ctrl_handler_free(&ctx->ctrl_handler); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void rot_update_info(struct ingenic_rot_ctx *ctx) ++{ ++ struct rot_frm_info *in, *out; ++ ++ in = &ctx->in; ++ out = &ctx->out; ++ ++ in->width = DEFAULT_WIDTH; ++ in->height = DEFAULT_HEIGHT; ++ in->fmt = &formats[1]; ++ in->bytesperline = DEFAULT_WIDTH * in->fmt->depth >> 3; ++ in->size = in->bytesperline * in->height; ++ ++ out->width = DEFAULT_WIDTH; ++ out->height = DEFAULT_HEIGHT; ++ out->fmt = &formats[0]; ++ out->bytesperline = DEFAULT_WIDTH * out->fmt->depth >> 3; ++ out->size = out->bytesperline * out->height; ++} ++ ++static int rot_reqdesc(struct ingenic_rot_ctx *ctx) ++{ ++ struct ingenic_rot_dev *dev = ctx->dev; ++ struct video_device *vfd = dev->vfd; ++ int i, size; ++ ++ size = sizeof(struct ingenic_rot_desc) * ROT_DESC_NUM; ++ vfd->dev.coherent_dma_mask = DMA_BIT_MASK(32); ++ ctx->desc[0] = (struct ingenic_rot_desc *)dma_alloc_coherent(&vfd->dev, size, ++ &ctx->desc_phys[0], GFP_KERNEL); ++ if (!ctx->desc[0]) { ++ dev_err(&vfd->dev, "dma_alloc_coherent of size %d failed\n", size); ++ return -ENOMEM; ++ } ++ ++ for(i = 1; i < ROT_DESC_NUM; i++) { ++ ctx->desc[i] = ctx->desc[0] + i; ++ ctx->desc_phys[i] = ctx->desc_phys[0] + i*sizeof(struct ingenic_rot_desc); ++ } ++ return 0; ++} ++ ++static void rot_freedesc(struct ingenic_rot_ctx *ctx) ++{ ++ struct ingenic_rot_dev *dev = ctx->dev; ++ struct video_device *vfd = dev->vfd; ++ int size; ++ ++ size = sizeof(struct ingenic_rot_desc) * ROT_DESC_NUM; ++ dma_free_coherent(&vfd->dev, size, ctx->desc[0], ctx->desc_phys[0]); ++} ++ ++static int rot_open(struct file *file) ++{ ++ struct ingenic_rot_dev *dev = video_drvdata(file); ++ struct ingenic_rot_ctx *ctx = NULL; ++ int ret = 0; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ if (mutex_lock_interruptible(&dev->mutex)) { ++ kfree(ctx); ++ return -ERESTARTSYS; ++ } ++ ctx->dev = dev; ++ ++ /* Set default formats */ ++ rot_update_info(ctx); ++ ++ ret = rot_reqdesc(ctx); ++ if(ret) { ++ goto free; ++ } ++ ++ v4l2_fh_init(&ctx->fh, video_devdata(file)); ++ ctx->fh.ctrl_handler = &ctx->ctrl_handler; ++ file->private_data = &ctx->fh; ++ v4l2_fh_add(&ctx->fh); ++ ++ ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); ++ if (IS_ERR(ctx->m2m_ctx)) { ++ ret = PTR_ERR(ctx->m2m_ctx); ++ goto err; ++ } ++ ctx->fh.m2m_ctx = ctx->m2m_ctx; ++ ++ ret = rot_setup_ctrls(ctx); ++ if(ret) ++ goto err; ++ ++ /* Write the default values to the ctx struct */ ++ v4l2_ctrl_handler_setup(&ctx->ctrl_handler); ++ ++ clk_prepare_enable(dev->clk); ++ ++ mutex_unlock(&dev->mutex); ++ ++ return 0; ++err: ++ rot_freedesc(ctx); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++free: ++ mutex_unlock(&dev->mutex); ++ kfree(ctx); ++ return ret; ++} ++ ++static int rot_release(struct file *file) ++{ ++ struct ingenic_rot_dev *dev = video_drvdata(file); ++ struct ingenic_rot_ctx *ctx = fh2ctx(file->private_data); ++ ++ clk_disable_unprepare(dev->clk); ++ ++ mutex_lock(&dev->mutex); ++ v4l2_m2m_ctx_release(ctx->m2m_ctx); ++ mutex_unlock(&dev->mutex); ++ v4l2_ctrl_handler_free(&ctx->ctrl_handler); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ rot_freedesc(ctx); ++ kfree(ctx); ++ return 0; ++} ++ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ strncpy(cap->driver, JZ_ROT_NAME, sizeof(cap->driver) - 1); ++ strncpy(cap->card, JZ_ROT_NAME, sizeof(cap->card) - 1); ++ cap->bus_info[0] = 0; ++ cap->version = KERNEL_VERSION(1, 0, 0); ++ /* ++ * This is only a mem-to-mem video device. The capture and output ++ * device capability flags are left only for backward compatibility ++ * and are scheduled for removal. ++ */ ++ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; ++ cap->capabilities = cap->device_caps | ++ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | ++ V4L2_CAP_DEVICE_CAPS; ++ ++ return 0; ++} ++ ++static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) ++{ ++ int i, num; ++ struct rot_fmt *fmt; ++ ++ num = 0; ++ for (i = 0; i < NUM_FORMATS; ++i) { ++ if (formats[i].types & type) { ++ /* index-th format of type type found ? */ ++ if (num == f->index) ++ break; ++ /* Correct type but haven't reached our index yet, ++ * just increment per-type index */ ++ ++num; ++ } ++ } ++ ++ if (i < NUM_FORMATS) { ++ /* Format found */ ++ fmt = &formats[i]; ++ strncpy(f->description, fmt->name, sizeof(f->description) - 1); ++ f->pixelformat = fmt->fourcc; ++ return 0; ++ } ++ ++ /* Format not found */ ++ return -EINVAL; ++} ++ ++static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return enum_fmt(f, MEM2MEM_CAPTURE); ++} ++ ++static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return enum_fmt(f, MEM2MEM_OUTPUT); ++} ++ ++static inline struct ingenic_rot_ctx *fh_to_ctx(struct v4l2_fh *fh) ++{ ++ return container_of(fh, struct ingenic_rot_ctx, fh); ++} ++ ++static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) ++{ ++ struct ingenic_rot_ctx *ctx = fh_to_ctx(prv); ++ struct vb2_queue *vq; ++ struct rot_frm_info *frm; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ frm = get_frame(ctx, f->type); ++ if (IS_ERR(frm)) ++ return PTR_ERR(frm); ++ ++ f->fmt.pix.width = frm->width; ++ f->fmt.pix.height = frm->height; ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ f->fmt.pix.pixelformat = frm->fmt->fourcc; ++ f->fmt.pix.bytesperline = (frm->width * frm->fmt->depth) >> 3; ++ f->fmt.pix.sizeimage = frm->size; ++ return 0; ++} ++ ++static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) ++{ ++ struct rot_fmt *fmt; ++ enum v4l2_field *field; ++ ++ fmt = find_fmt(f); ++ if (!fmt) ++ return -EINVAL; ++ ++ field = &f->fmt.pix.field; ++ if (*field == V4L2_FIELD_ANY) ++ *field = V4L2_FIELD_NONE; ++ else if (*field != V4L2_FIELD_NONE) ++ return -EINVAL; ++ ++ if (f->fmt.pix.width > MAX_WIDTH ++ || f->fmt.pix.height > MAX_HEIGHT ++ || f->fmt.pix.width < MIN_WIDTH ++ || f->fmt.pix.height < MIN_HEIGHT) { ++ return -EINVAL; ++ } ++ ++ f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; ++ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; ++ return 0; ++} ++ ++static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) ++{ ++ struct ingenic_rot_ctx *ctx = fh_to_ctx(prv); ++ struct ingenic_rot_dev *dev = ctx->dev; ++ struct vb2_queue *vq; ++ struct rot_frm_info *frm; ++ struct rot_fmt *fmt; ++ int ret = 0; ++ ++ /* Adjust all values accordingly to the hardware capabilities ++ * and chosen format. */ ++ ret = vidioc_try_fmt(file, prv, f); ++ if (ret) ++ return ret; ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (vb2_is_busy(vq)) { ++ v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type); ++ return -EBUSY; ++ } ++ frm = get_frame(ctx, f->type); ++ if (IS_ERR(frm)) ++ return PTR_ERR(frm); ++ fmt = find_fmt(f); ++ if (!fmt) ++ return -EINVAL; ++ frm->width = f->fmt.pix.width; ++ frm->height = f->fmt.pix.height; ++ frm->size = f->fmt.pix.sizeimage; ++ frm->fmt = fmt; ++ frm->bytesperline = f->fmt.pix.bytesperline; ++ return 0; ++} ++ ++static int vidioc_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_rot_ctx *ctx = priv; ++ ++ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); ++} ++ ++static int vidioc_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_rot_ctx *ctx = priv; ++ ++ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); ++} ++ ++/* Need change, One frame spends times */ ++#define ROT_TIMEOUT 400 ++ ++static void job_abort(void *prv) ++{ ++ struct ingenic_rot_ctx *ctx = prv; ++ struct ingenic_rot_dev *dev = ctx->dev; ++ int ret; ++ ++ if (dev->curr == NULL) /* No job currently running */ ++ return; ++ ++ ret = wait_event_timeout(dev->irq_queue, ++ dev->curr == NULL, ++ msecs_to_jiffies(ROT_TIMEOUT)); ++ if(!ret) { ++ struct vb2_v4l2_buffer *src_vb, *dst_vb; ++ ++ rot_cpm_reset(); ++ src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); ++ dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; ++ dst_vb->timecode = src_vb->timecode; ++ dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; ++ dst_vb->flags |= ++ src_vb->flags ++ & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; ++ ++ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR); ++ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR); ++ ++ v4l2_m2m_job_finish(dev->m2m_dev, ++ ctx->m2m_ctx); ++ dev->curr = NULL; ++ } ++} ++ ++static void device_run(void *prv) ++{ ++ struct ingenic_rot_ctx *ctx = prv; ++ struct ingenic_rot_dev *dev = ctx->dev; ++ struct vb2_v4l2_buffer *src, *dst; ++ unsigned long flags; ++ ++ dev->curr = ctx; ++ ++ src = v4l2_m2m_next_src_buf(ctx->m2m_ctx); ++ dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); ++ ++ spin_lock_irqsave(&dev->ctrl_lock, flags); ++ ++ rot_reset(dev); ++ ++ rot_set_src_cfg(dev, &ctx->in); ++ rot_set_src_desc(dev, ingenic_vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0)); ++ ++ rot_set_dst_cfg(dev, &ctx->out); ++ rot_set_dst_desc(dev, ingenic_vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0)); ++ ++ rot_set_angle(dev, ctx->angle); ++ rot_set_vflip(dev, ctx->vflip); ++ rot_set_hflip(dev, ctx->hflip); ++ ++ time_now = ktime_get(); ++ ++ rot_start(dev); ++ ++#ifdef ROT_GEN_STOP ++ rot_gen_stop(dev); ++#endif ++ ++ spin_unlock_irqrestore(&dev->ctrl_lock, flags); ++} ++ ++static irqreturn_t rot_irq_handler(int irq, void *prv) ++{ ++ struct ingenic_rot_dev *dev = prv; ++ struct ingenic_rot_ctx *ctx = dev->curr; ++ struct vb2_v4l2_buffer *src, *dst; ++ ++ time_last = ktime_get(); ++ interval_in_ns = time_last - time_now; ++ ++ rot_clr_irq(dev); ++ ++ if(unlikely(ctx == NULL)) { ++ printk("Rotater:ctx == NULL\n"); ++ return IRQ_HANDLED; ++ } ++ ++ src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); ++ if(unlikely(src == NULL)) { ++ printk("Rotater:src == NULL\n"); ++ return IRQ_HANDLED; ++ } ++ dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ if(unlikely(dst == NULL)) { ++ printk("Rotater:dst == NULL\n"); ++ return IRQ_HANDLED; ++ } ++ ++ dst->timecode = src->timecode; ++ dst->vb2_buf.timestamp = src->vb2_buf.timestamp; ++ ++ v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); ++ v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); ++ v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); ++ ++ dev->curr = NULL; ++#ifdef ROT_QCK_STOP ++ rot_qck_stop(dev); ++#endif ++#if defined(ROT_GEN_STOP) || defined(ROT_QCK_STOP) ++ schedule_work(&dev->rot_work); ++#endif ++ wake_up(&dev->irq_queue); ++ return IRQ_HANDLED; ++} ++ ++#if defined(ROT_GEN_STOP) || defined(ROT_QCK_STOP) ++static void rot_wait_dev_end(struct work_struct *rot_work) ++{ ++ struct ingenic_rot_dev *dev; ++ ++ dev = container_of(rot_work, struct ingenic_rot_dev, rot_work); ++ wait_rot_state(dev, ROT_WORKING, 0); ++} ++#endif ++ ++static const struct v4l2_file_operations rot_fops = { ++ .owner = THIS_MODULE, ++ .open = rot_open, ++ .release = rot_release, ++ .poll = v4l2_m2m_fop_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = v4l2_m2m_fop_mmap, ++}; ++ ++static const struct v4l2_ioctl_ops rot_ioctl_ops = { ++ .vidioc_querycap = vidioc_querycap, ++ ++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt, ++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt, ++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt, ++ ++ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, ++ .vidioc_g_fmt_vid_out = vidioc_g_fmt, ++ .vidioc_try_fmt_vid_out = vidioc_try_fmt, ++ .vidioc_s_fmt_vid_out = vidioc_s_fmt, ++ ++ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, ++ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, ++ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, ++ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, ++ ++ .vidioc_streamon = vidioc_streamon, ++ .vidioc_streamoff = vidioc_streamoff, ++}; ++ ++static struct video_device rot_videodev = { ++ .name = "ingenic-rot", ++ .fops = &rot_fops, ++ .ioctl_ops = &rot_ioctl_ops, ++ .minor = -1, ++ .release = video_device_release, ++ .vfl_dir = VFL_DIR_M2M, ++}; ++ ++static struct v4l2_m2m_ops rot_m2m_ops = { ++ .device_run = device_run, ++ .job_abort = job_abort, ++}; ++ ++static int ingenic_rot_probe(struct platform_device *pdev) ++{ ++ struct ingenic_rot_dev *dev; ++ struct video_device *vfd; ++ struct resource *res; ++ int ret = 0; ++ ++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ ++ dev->dev = &pdev->dev; ++ spin_lock_init(&dev->ctrl_lock); ++ mutex_init(&dev->mutex); ++ atomic_set(&dev->num_inst, 0); ++ init_waitqueue_head(&dev->irq_queue); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ dev->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(dev->regs)) ++ return PTR_ERR(dev->regs); ++ ++ /* interrupt service routine registration */ ++ dev->irq = ret = platform_get_irq(pdev, 0); ++ if (dev->irq < 0) { ++ dev_err(&pdev->dev, "cannot find IRQ\n"); ++ return ret; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, dev->irq, rot_irq_handler, ++ 0, pdev->name, dev); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to install IRQ\n"); ++ return ret; ++ } ++ ++ /* clocks */ ++ dev->clk = clk_get(&pdev->dev, "gate_rot"); ++ if (IS_ERR(dev->clk)) { ++ dev_err(&pdev->dev, "cannot get clock\n"); ++ ret = PTR_ERR(dev->clk); ++ return ret; ++ } ++ dev_dbg(&pdev->dev, "rot clock source %p\n", dev->clk); ++ ++#if defined(ROT_QCK_STOP) || defined(ROT_GEN_STOP) ++ INIT_WORK(&dev->rot_work, rot_wait_dev_end); ++#endif ++ dev->alloc_ctx = ingenic_vb2_dma_contig_init_ctx(&pdev->dev); ++ if (IS_ERR(dev->alloc_ctx)) { ++ ret = PTR_ERR(dev->alloc_ctx); ++ goto clk_get_rollback; ++ } ++ ++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ if (ret) ++ goto alloc_ctx_cleanup; ++ vfd = video_device_alloc(); ++ if (!vfd) { ++ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); ++ ret = -ENOMEM; ++ goto unreg_v4l2_dev; ++ } ++ *vfd = rot_videodev; ++ vfd->lock = &dev->mutex; ++ vfd->v4l2_dev = &dev->v4l2_dev; ++ vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; ++ ++ ret = video_register_device(vfd, VFL_TYPE_VIDEO, INGENIC_ROTATE_VIDEO_NR); ++ if (ret) { ++ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); ++ goto rel_vdev; ++ } ++ video_set_drvdata(vfd, dev); ++ snprintf(vfd->name, sizeof(vfd->name), "%s", rot_videodev.name); ++ dev->vfd = vfd; ++ v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n", ++ vfd->num); ++ platform_set_drvdata(pdev, dev); ++ dev->m2m_dev = v4l2_m2m_init(&rot_m2m_ops); ++ if (IS_ERR(dev->m2m_dev)) { ++ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); ++ ret = PTR_ERR(dev->m2m_dev); ++ goto unreg_video_dev; ++ } ++ ++ ret = of_reserved_mem_device_init(&pdev->dev); ++ if(ret) ++ dev_warn(&pdev->dev, "failed to init reserved mem\n"); ++ ++ return 0; ++ ++unreg_video_dev: ++ video_unregister_device(dev->vfd); ++rel_vdev: ++ video_device_release(vfd); ++unreg_v4l2_dev: ++ v4l2_device_unregister(&dev->v4l2_dev); ++alloc_ctx_cleanup: ++ ingenic_vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); ++clk_get_rollback: ++ clk_put(dev->clk); ++ ++ return ret; ++} ++ ++static int ingenic_rot_remove(struct platform_device *pdev) ++{ ++ struct ingenic_rot_dev *dev = (struct ingenic_rot_dev *)platform_get_drvdata(pdev); ++ ++ v4l2_info(&dev->v4l2_dev, "Removing " JZ_ROT_NAME); ++ v4l2_m2m_release(dev->m2m_dev); ++ video_unregister_device(dev->vfd); ++ video_device_release(dev->vfd); ++ v4l2_device_unregister(&dev->v4l2_dev); ++ ingenic_vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); ++ clk_put(dev->clk); ++ return 0; ++} ++ ++static const struct of_device_id ingenic_rotate_match[] = { ++ { ++ .compatible = "ingenic,x2000-rotate", ++ .data = NULL, ++ }, ++ { ++ .compatible = "ingenic,m300-rotate", ++ .data = NULL, ++ }, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_rotate_match); ++ ++ ++static struct platform_driver rot_pdrv = { ++ .probe = ingenic_rot_probe, ++ .remove = ingenic_rot_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_rotate_match), ++ .name = JZ_ROT_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(rot_pdrv); ++ ++MODULE_AUTHOR("clwang"); ++MODULE_DESCRIPTION("X2000 rotate driver"); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/media/platform/ingenic-rotate/rotate.h b/module_drivers/drivers/media/platform/ingenic-rotate/rotate.h +new file mode 100644 +index 000000000..5fdf650f8 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-rotate/rotate.h +@@ -0,0 +1,150 @@ ++/* * drivers/media/platform/ingenic_rotate/rotate.h ++ * ++ * Copyright (C) 2016 Ingenic Semiconductor Inc. ++ * ++ * Author:clwang ++ * ++ * This program is free software, you can redistribute it and/or modify it ++ * ++ * under the terms of the GNU General Public License version 2 as published by ++ * ++ * the Free Software Foundation. ++ */ ++ ++#ifndef __ROTATER_H__ ++#define __ROTATER_H__ ++ ++#include ++#include ++#include ++ ++#define JZ_ROT_NAME "jz-rot" ++#define ROT_DESC_NUM 1 ++ ++#define DEFAULT_WIDTH (100) ++#define DEFAULT_HEIGHT (100) ++ ++#define MIN_WIDTH (4) ++#define MIN_HEIGHT (4) ++#define MAX_WIDTH (2047) ++#define MAX_HEIGHT (2047) ++ ++#define MEM2MEM_CAPTURE (1 << 0) ++#define MEM2MEM_OUTPUT (1 << 1) ++ ++//#define ROT_QCK_STOP ++//#define ROT_GEN_STOP ++ ++typedef unsigned int uint32_t; ++typedef unsigned short uint16_t; ++typedef unsigned char uint8_t; ++ ++typedef union frame_stop { ++ uint32_t d32; ++ struct { ++ uint32_t stop:1; ++ uint32_t reserve31_1:31; ++ } b; ++} frame_stop_t; ++ ++typedef union irq_ctrl { ++ uint32_t d32; ++ struct { ++ uint32_t reserve1_0:2; ++ uint32_t eof_mask:1; ++ uint32_t sof_mask:1; ++ uint32_t reserve31_4:28; ++ } b; ++} irq_ctrl_t; ++ ++struct ingenic_rot_desc { ++ uint32_t NextCfgAddr; ++ uint32_t SrcBufferAddr; ++ uint32_t SrcStride; ++ frame_stop_t FrameStop; ++ uint32_t TargetBufferAddr; ++ uint32_t TargetStride; ++ irq_ctrl_t irq_ctrl; ++} __attribute__ ((aligned(8))); ++ ++struct rot_fmt { ++ char *name; ++ u32 fourcc; ++ int depth; ++ u32 types; ++}; ++ ++struct rot_frm_info { ++ uint32_t width; ++ uint32_t height; ++ ++ struct rot_fmt *fmt; ++ ++ uint32_t bytesperline; ++ uint32_t size; ++}; ++ ++struct ingenic_rot_ctx { ++ struct v4l2_fh fh; ++ struct ingenic_rot_dev *dev; ++ struct v4l2_m2m_ctx *m2m_ctx; ++ struct v4l2_ctrl_handler ctrl_handler; ++ struct rot_frm_info in; ++ struct rot_frm_info out; ++ struct v4l2_ctrl *ctrl_hflip; ++ struct v4l2_ctrl *ctrl_vflip; ++ struct v4l2_ctrl *ctrl_rot; ++ uint32_t vflip; ++ uint32_t hflip; ++ uint32_t angle; ++ struct ingenic_rot_desc *desc[ROT_DESC_NUM]; ++ dma_addr_t desc_phys[ROT_DESC_NUM]; ++}; ++ ++struct ingenic_rot_dev { ++ struct device *dev; ++ struct v4l2_device v4l2_dev; ++ struct v4l2_m2m_dev *m2m_dev; ++ struct video_device *vfd; ++ struct mutex mutex; ++ spinlock_t ctrl_lock; ++ atomic_t num_inst; ++ struct vb2_alloc_ctx *alloc_ctx; ++ void __iomem *regs; ++ struct clk *clk; ++ struct ingenic_rot_ctx *curr; ++ int irq; ++ wait_queue_head_t irq_queue; ++#if defined(ROT_QCK_STOP) || defined(ROT_GEN_STOP) ++ struct work_struct rot_work; ++#endif ++}; ++ ++static inline unsigned long reg_read(struct ingenic_rot_dev *dev, int offset) ++{ ++ return readl(dev->regs + offset); ++} ++ ++static inline void reg_write(struct ingenic_rot_dev *dev, int offset, unsigned long val) ++{ ++ writel(val, dev->regs + offset); ++} ++ ++void rot_set_src_desc(struct ingenic_rot_dev *dev, dma_addr_t addr); ++void rot_set_dst_desc(struct ingenic_rot_dev *dev, dma_addr_t addr); ++void rot_set_hflip(struct ingenic_rot_dev *dev, uint32_t hflip); ++void rot_set_vflip(struct ingenic_rot_dev *dev, uint32_t vflip); ++void rot_set_angle(struct ingenic_rot_dev *dev, uint32_t angle); ++void rot_set_dst_cfg(struct ingenic_rot_dev *dev, struct rot_frm_info *out); ++void rot_set_src_cfg(struct ingenic_rot_dev *dev, struct rot_frm_info *in); ++int wait_rot_state(struct ingenic_rot_dev *dev, int32_t state, uint32_t flag); ++void dump_all(struct ingenic_rot_dev *dev); ++void dump_rot_desc_reg(struct ingenic_rot_dev *dev); ++void dump_rot_desc(struct ingenic_rot_desc *desc); ++void rot_clr_irq(struct ingenic_rot_dev *dev); ++void rot_gen_stop(struct ingenic_rot_dev *dev); ++void rot_qck_stop(struct ingenic_rot_dev *dev); ++void rot_start(struct ingenic_rot_dev *dev); ++void rot_reset(struct ingenic_rot_dev *dev); ++void rot_cpm_reset(void); ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/Kconfig b/module_drivers/drivers/media/platform/ingenic-vcodec/Kconfig +new file mode 100644 +index 000000000..50f3106f1 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/Kconfig +@@ -0,0 +1,16 @@ ++config VIDEO_INGENIC_VCODEC ++ tristate "V4L2 driver for ingenic Video Codec" ++ depends on VIDEO_DEV && VIDEO_V4L2 ++ select V4L2_MEM2MEM_DEV ++ select VIDEOBUF2_DMA_CONTIG_INGENIC ++ select VIDEOBUF2_DMA_CONTIG ++ ++config INGENIC_HELIX ++ tristate "[ENC] ingenic video helix" ++ depends on VIDEO_INGENIC_VCODEC ++config INGENIC_FELIX ++ tristate "[DEC] ingenic video felix" ++ depends on VIDEO_INGENIC_VCODEC ++ ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/Makefile b/module_drivers/drivers/media/platform/ingenic-vcodec/Makefile +new file mode 100644 +index 000000000..3e3f2408b +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/Makefile +@@ -0,0 +1,2 @@ ++obj-y += helix/ ++obj-y += felix/ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/Makefile b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/Makefile +new file mode 100644 +index 000000000..01459285d +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/Makefile +@@ -0,0 +1,29 @@ ++ ++ccflags-y += -I$(srctree)/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/ ++ccflags-y += -I$(srctree)/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include ++ ++ingenic_felix-y := felix_drv.o \ ++ felix_ops.o \ ++ libh264/api/jzm_h264_dec.o\ ++ libh264/src/log.o \ ++ libh264/src/mem.o \ ++ libh264/src/h264_picture.o \ ++ libh264/src/golomb.o \ ++ libh264/src/h264data.o \ ++ libh264/src/h264_refs.o \ ++ libh264/src/mathtables.o \ ++ libh264/src/h2645_parse.o \ ++ libh264/src/h264_parse.o \ ++ libh264/src/h264_direct.o \ ++ libh264/src/h264_ps.o \ ++ libh264/src/h264_sei.o \ ++ libh264/src/buffer.o \ ++ libh264/src/vpu_ops.o \ ++ libh264/src/h264_slice.o \ ++ libh264/src/h264dec.o ++ ++obj-$(CONFIG_INGENIC_FELIX) += ingenic_felix.o ++ ++ ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_drv.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_drv.c +new file mode 100644 +index 000000000..bf865381e +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_drv.c +@@ -0,0 +1,658 @@ ++/* ++ * Copyright (c) 2014 Ingenic Inc. ++ * Author: qipengzhen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "felix_drv.h" ++#include "felix_ops.h" ++ ++#include "h264dec.h" ++ ++#undef pr_debug ++#define pr_debug pr_info ++ ++ ++/* ++TODO: do not support multi ctx for now. ++*/ ++ ++static int vpu_on(struct ingenic_vdec_dev *dev); ++static int vpu_off(struct ingenic_vdec_dev *dev); ++extern struct vpu_ops ingenic_vpu_ops; ++ ++static int fops_vcodec_open(struct file *file) ++{ ++ struct ingenic_vdec_dev *dev = video_drvdata(file); ++ struct ingenic_vdec_ctx *ctx = NULL; ++ int ret = 0; ++ ++// printk("%s:%d sizeof(*ctx): %d, sizeof(AVCodecContext):%d, sizeof(H264Context):%d\n", __func__, __LINE__, sizeof(*ctx), sizeof(AVCodecContext), sizeof(H264Context)); ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if(!ctx) ++ return -ENOMEM; ++ ++ ctx->avctx = kzalloc(sizeof(AVCodecContext), GFP_KERNEL); ++ if(!ctx->avctx) { ++ kfree(ctx); ++ return -ENOMEM; ++ } ++ ++ ctx->h = kzalloc(sizeof(H264Context), GFP_KERNEL); ++ if(!ctx->h) { ++ kfree(ctx->avctx); ++ kfree(ctx); ++ return -ENOMEM; ++ } ++ ctx->avctx->priv_data = ctx->h; ++ //ctx->avctx->flags2 |= AV_CODEC_FLAG2_CHUNKS; ++ //ctx->avctx->debug |= FF_DEBUG_PICT_INFO; ++ ctx->h->devmem_ctx.dev = dev->dev; ++ ++ ret = h264_decode_init(ctx->avctx); ++ if(ret < 0) { ++ kfree(ctx->h); ++ kfree(ctx->avctx); ++ kfree(ctx); ++ return -EINVAL; ++ } ++ ++ h264_set_vpu_ops(ctx->h, ctx, &ingenic_vpu_ops); ++ ++ mutex_lock(&dev->dev_mutex); ++ ++ mutex_init(&ctx->lock); ++ ++ if (!dev->id_counter) { ++ vpu_on(dev); ++ } ++ ++ ctx->id = dev->id_counter++; ++ v4l2_fh_init(&ctx->fh, video_devdata(file)); ++ file->private_data = &ctx->fh; ++ v4l2_fh_add(&ctx->fh); ++ //INIT_LIST_HEAD(&ctx->list); ++ ctx->dev = dev; ++ init_waitqueue_head(&ctx->queue); ++ ++ ++ ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &ingenic_vcodec_vdec_queue_init); ++ if(IS_ERR((__force void *)ctx->m2m_ctx)) { ++ ret = PTR_ERR((__force void *)ctx->m2m_ctx); ++ ++ goto err_m2m_ctx_init; ++ } ++ ++ ingenic_vcodec_init_default_params(ctx); ++ pr_debug("Create instance [%d]@%p m2m_ctx=%p\n", ++ ctx->id, ctx, ctx->m2m_ctx); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ pr_debug("%s vcodec [%d]\n", dev_name(dev->dev), ctx->id); ++ ++ return ret; ++err_m2m_ctx_init: ++ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ kfree(ctx->h); ++ kfree(ctx->avctx); ++ kfree(ctx); ++ mutex_unlock(&dev->dev_mutex); ++ return ret; ++} ++ ++static int fops_vcodec_release(struct file *file) ++{ ++ ++ struct ingenic_vdec_dev *dev = video_drvdata(file); ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(file->private_data); ++ ++ pr_debug("[%d] vcodec release\n", ctx->id); ++ ++ mutex_lock(&dev->dev_mutex); ++ ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); ++ v4l2_m2m_ctx_release(ctx->m2m_ctx); ++ ++ ++ ingenic_vcodec_deinit_default_params(ctx); ++ ++ h264_decode_end(ctx->avctx); ++ ++ if(ctx->avctx) ++ kfree(ctx->avctx); ++ ++ if(ctx->h) ++ kfree(ctx->h); ++ ++ kfree(ctx); ++ ++ if (!(--dev->id_counter)) { ++ vpu_off(dev); ++ } ++ ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ return 0; ++} ++ ++static unsigned int fops_vcodec_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ struct ingenic_vdec_dev *dev = video_drvdata(file); ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(file->private_data); ++ unsigned int ret = 0; ++ ++ if(mutex_lock_interruptible(&dev->dev_mutex)) { ++ return -ERESTARTSYS; ++ } ++ ++ ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ return ret; ++} ++ ++static int fops_vcodec_mmap(struct file *file, ++ struct vm_area_struct *vma) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(file->private_data); ++ ++ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); ++} ++ ++static const struct v4l2_file_operations ingenic_vdec_fops = { ++ .owner = THIS_MODULE, ++ .open = fops_vcodec_open, ++ .release = fops_vcodec_release, ++ .poll = fops_vcodec_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = fops_vcodec_mmap, ++}; ++ ++ ++#define vpu_readl(dev, offset) \ ++ readl(dev->reg_base + (offset)) ++ ++#define vpu_writel(dev, offset, data) \ ++ writel((data), dev->reg_base + (offset)) ++ ++static void inline vpu_clear_bits(struct ingenic_vdec_dev *dev, unsigned int offset, unsigned int bits) ++{ ++ unsigned int val = vpu_readl(dev, offset); ++ val &= ~bits; ++ vpu_writel(dev, offset, val); ++} ++ ++ ++#define REG_VPU_STATUS ( *(volatile unsigned int*)0xb3200034 ) ++#define REG_VPU_LOCK ( *(volatile unsigned int*)0xb329004c ) ++#define REG_VPUCDR ( *(volatile unsigned int*)0xb0000030 ) ++#define REG_CPM_VPU_SWRST ( *(volatile unsigned int*)0xb00000c4 ) ++#define REG_VPU_TLBBASE (*(volatile unsigned int *)(0x30 + 0xb3200000)) ++#define CPM_VPU_SR (0x1<<31) ++#define CPM_VPU_STP (0x1<<30) ++#define CPM_VPU_ACK (0x1<<29) ++ ++ ++ ++#define REG_VPU_GLBC 0x00000 ++#define VPU_INTE_ACFGERR (0x1<<20) ++#define VPU_INTE_TLBERR (0x1<<18) ++#define VPU_INTE_BSERR (0x1<<17) ++#define VPU_INTE_ENDF (0x1<<16) ++ ++#define REG_VPU_STAT 0x00034 ++#define VPU_STAT_ENDF (0x1<<0) ++#define VPU_STAT_BPF (0x1<<1) ++#define VPU_STAT_ACFGERR (0x1<<2) ++#define VPU_STAT_TIMEOUT (0x1<<3) ++#define VPU_STAT_JPGEND (0x1<<4) ++#define VPU_STAT_BSERR (0x1<<7) ++ ++#define VPU_STAT_TLBERR (0x1F<<10) ++#define VPU_STAT_SLDERR (0x1<<16) ++ ++#define REG_VPU_JPGC_STAT 0xE0008 ++#define JPGC_STAT_ENDF (0x1<<31) ++ ++#define REG_VPU_SDE_STAT 0x90000 ++#define SDE_STAT_BSEND (0x1<<1) ++ ++#define REG_VPU_DBLK_STAT 0x70070 ++#define DBLK_STAT_DOEND (0x1<<0) ++ ++#define REG_VPU_AUX_STAT 0xA0010 ++#define AUX_STAT_MIRQP (0x1<<0) ++ ++static irqreturn_t ingenic_vpu_irq(int irq, void *priv) ++{ ++ struct ingenic_vdec_dev *dev = (struct ingenic_vdec_dev *)priv; ++ struct ingenic_vdec_ctx *ctx = dev->curr_ctx; ++ H264Context *h = ctx->h; ++ vpu_ctx_t *vpu_ctx = &h->vpu_ctx; ++ unsigned long flags; ++ ++ unsigned int vpu_stat; ++ unsigned int sde_stat; ++ int err = 0; ++ ++#define check_vpu_status(STAT, fmt, args...) do { \ ++ if(vpu_stat & STAT) \ ++ dev_err(dev->dev, fmt, ##args); \ ++ }while(0) ++ ++ spin_lock_irqsave(&dev->spinlock, flags); ++ ++ vpu_stat = vpu_readl(dev, REG_SCH_STAT); ++ sde_stat = vpu_readl(dev, REG_SDE_STAT); ++ ++ if(vpu_stat) { ++ if(vpu_stat & VPU_STAT_ENDF) { ++ if(vpu_stat & VPU_STAT_JPGEND) { ++ dev_dbg(dev->dev, "JPG successfully done!\n"); ++ vpu_stat = vpu_readl(dev, REG_VPU_JPGC_STAT); ++ vpu_clear_bits(dev, REG_VPU_JPGC_STAT, ++ JPGC_STAT_ENDF); ++ } else { ++ dev_dbg(dev->dev, "SCH successfully done!\n"); ++ vpu_clear_bits(dev, REG_VPU_SDE_STAT, ++ SDE_STAT_BSEND); ++ vpu_clear_bits(dev, REG_VPU_DBLK_STAT, ++ DBLK_STAT_DOEND); ++ } ++ } else { ++ err = 1; ++ check_vpu_status(VPU_STAT_SLDERR, "SHLD error!\n"); ++ check_vpu_status(VPU_STAT_TLBERR, "TLB error! Addr is 0x%08x\n", ++ vpu_readl(dev, REG_VPU_STAT)); ++ check_vpu_status(VPU_STAT_BSERR, "BS error!\n"); ++ check_vpu_status(VPU_STAT_ACFGERR, "ACFG error!\n"); ++ check_vpu_status(VPU_STAT_TIMEOUT, "TIMEOUT error!\n"); ++ vpu_clear_bits(dev,REG_VPU_GLBC, (VPU_INTE_ACFGERR | ++ VPU_INTE_TLBERR | VPU_INTE_BSERR | ++ VPU_INTE_ENDF)); ++ } ++ } else { ++ if(vpu_readl(dev,REG_VPU_AUX_STAT) & AUX_STAT_MIRQP) { ++ dev_dbg(dev->dev, "AUX successfully done!\n"); ++ vpu_clear_bits(dev, REG_VPU_AUX_STAT, AUX_STAT_MIRQP); ++ } else { ++ dev_dbg(dev->dev, "illegal interrupt happened!\n"); ++ err = 1; ++ return IRQ_HANDLED; ++ } ++ } ++ ++ ctx->int_cond = 1; ++ vpu_ctx->error = err; ++ vpu_ctx->sch_stat = vpu_stat; ++ vpu_ctx->sde_stat = sde_stat; ++ //ctx->int_status = vpu_stat; ++ spin_unlock_irqrestore(&dev->spinlock, flags); ++ ++ wake_up_interruptible(&ctx->queue); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++static void vpu_dump_regs(struct ingenic_vdec_dev *dev) ++{ ++ ++#if 1 ++ /*SDE*/ ++ printk("REG_SDE_STAT: 0x%x\n", vpu_readl(dev, REG_SDE_STAT)); ++ printk("REG_SDE_CFG0: 0x%x\n", vpu_readl(dev, REG_SDE_CFG0)); ++ printk("REG_SDE_CFG1: 0x%x\n", vpu_readl(dev, REG_SDE_CFG1)); ++ printk("REG_SDE_CFG13: 0x%x\n", vpu_readl(dev, REG_SDE_CFG13)); ++ printk("REG_SDE_CFG14: 0x%x\n", vpu_readl(dev, REG_SDE_CFG14)); ++ printk("REG_DBLK_GSTA: 0x%x\n", vpu_readl(dev, REG_DBLK_GSTA)); ++ printk("REG_VMAU_POS: 0x%x\n", vpu_readl(dev, REG_VMAU_POS)); ++ printk("REG_SCH_STAT: 0x%x\n", vpu_readl(dev, REG_SCH_STAT)); ++#endif ++} ++ ++ ++#define VPU_RUN_TIMEOUT_MS (3000) ++ ++#ifdef CONFIG_SOC_M200 ++static int vpu_reset_m200(struct ingenic_vdec_dev *dev) ++{ ++ int timeout = 0xffffff; ++ ++ REG_CPM_VPU_SWRST |= CPM_VPU_STP; ++ while(!(REG_CPM_VPU_SWRST & CPM_VPU_ACK) && --timeout) ++ ; ++ ++ if(!timeout) { ++ dev_err(dev->dev, ++ "[%d:%d] wait stop ack timeout when stop VPU\n", ++ current->tgid, current->pid); ++ } ++ ++ REG_CPM_VPU_SWRST = ((REG_CPM_VPU_SWRST | CPM_VPU_SR) & ~CPM_VPU_STP); ++ REG_CPM_VPU_SWRST = (REG_CPM_VPU_SWRST & ~CPM_VPU_SR & ~CPM_VPU_STP); ++ REG_VPU_LOCK = 0; ++ ++ return 0; ++} ++#endif ++ ++/******************************************** ++ SW_RESET (VPU software reset) ++*********************************************/ ++#define REG_CFGC_SW_RESET 0x00000 ++#define REG_CFGC_RST (0x1<<30) ++#define REG_CFGC_RST_CLR (0x0<<30) ++#define REG_CFGC_EARB_STAT 0x0000d ++#define REG_CFGC_EARB_EMPT (0x20000) ++ ++static int vpu_reset_x2000(struct ingenic_vdec_dev *dev) ++{ ++ int timeout = 0xffff; ++ vpu_writel(dev, REG_CFGC_SW_RESET, REG_CFGC_RST); ++ while((vpu_readl(dev, REG_CFGC_EARB_STAT) & REG_CFGC_EARB_EMPT) && --timeout); ++ ++ if(!timeout) { ++ printk("vpu reset timeout!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++static int vpu_reset(struct ingenic_vdec_dev *dev) ++{ ++#ifdef CONFIG_SOC_M200 ++ return vpu_reset_m200(dev); ++#else ++ return vpu_reset_x2000(dev); ++#endif ++} ++ ++/*global clk on.*/ ++static int vpu_on(struct ingenic_vdec_dev *dev) ++{ ++ clk_prepare_enable(dev->clk_gate); ++ __asm__ __volatile__ ( ++ "mfc0 $2, $16, 7 \n\t" ++ "ori $2, $2, 0x340 \n\t" ++ "andi $2, $2, 0x3ff \n\t" ++ "mtc0 $2, $16, 7 \n\t" ++ "nop \n\t"); ++ ++ return 0; ++} ++ ++/* shutdown */ ++static int vpu_off(struct ingenic_vdec_dev *dev) ++{ ++ clk_disable_unprepare(dev->clk_gate); ++ ++ return 0; ++} ++ ++ ++static int ingenic_vpu_start(void *priv) ++{ ++ struct ingenic_vdec_ctx *ctx = (struct ingenic_vdec_ctx *)priv; ++ struct ingenic_vdec_dev *dev = ctx->dev; ++ H264Context *h = ctx->h; ++ vpu_ctx_t *vpu_ctx = &h->vpu_ctx; ++ ++ unsigned int sch_glbc = 0; ++ unsigned int des_pa; ++ unsigned long flags; ++ int ret = 0; ++ ++ ++ mutex_lock(&ctx->lock); ++ ++ des_pa = vpu_ctx->desc_pa; ++ ++ spin_lock_irqsave(&dev->spinlock, flags); ++ ++ /* æ˜¯ä¸æ˜¯å°†vpu_start å’Œ wait放在一起,更加åˆç†ä¸€äº› ++ * 针对ctx åšåŠ é”处ç†, ä¿è¯curr_ctxåœ¨ä¸€æ¬¡å¤„ç†æœŸé—´ä¸ä¼šå‘生å˜åŒ–. ++ * */ ++ dev->curr_ctx = ctx; ++ ctx->int_cond = 0; ++ ++ ++ /* vpu reset ... */ ++ vpu_reset(dev); ++ ++ /*TODO: 如果使用tlb,此处è¦ä¿®æ”¹.*/ ++ sch_glbc = SCH_GLBC_HIAXI | SCH_INTE_ACFGERR | SCH_INTE_BSERR | SCH_INTE_ENDF; ++ /*|SCH_INTE_ENDF | SCH_INTE_TLBERR | SCH_INTE_BSFULL;*/ ++ ++ vpu_writel(dev, REG_SCH_GLBC, sch_glbc); ++ ++ /*trigger start.*/ ++ vpu_writel(dev, REG_VDMA_TASKRG, VDMA_ACFG_DHA(des_pa) | VDMA_ACFG_RUN); ++ ++ /* wait event time out ... */ ++ spin_unlock_irqrestore(&dev->spinlock, flags); ++ ++ ret = wait_event_interruptible_timeout(ctx->queue, ctx->int_cond, msecs_to_jiffies(VPU_RUN_TIMEOUT_MS)); ++ if(!ret) { ++ pr_err("wait vpu run timeout!\n"); ++ printk("efe_stat %x, sch_stat %x\n", vpu_readl(dev, REG_EFE_STAT), vpu_readl(dev, REG_SCH_STAT)); ++ ++ vpu_dump_regs(dev); ++ ret = -ETIMEDOUT; ++ } else if(ret == -ERESTARTSYS) { ++ pr_err("vpu interrupted by a signal!\n"); ++ ++ } ++ ++ mutex_unlock(&ctx->lock); ++ return ret; ++} ++ ++static int ingenic_vpu_wait(void *priv) ++{ ++ return 0; ++} ++ ++static int ingenic_vpu_stop(void *priv) ++{ ++ return 0; ++} ++ ++struct vpu_ops ingenic_vpu_ops = { ++ .start = ingenic_vpu_start, ++ .wait = ingenic_vpu_wait, ++ .end = ingenic_vpu_stop, ++}; ++ ++static int ingenic_vcodec_probe(struct platform_device *pdev) ++{ ++ struct ingenic_vdec_dev *dev; ++ struct video_device *vfd; ++ int ret; ++ ++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); ++ if(!dev) ++ return -ENOMEM; ++ ++ dev->dev = &pdev->dev; ++ dev->plat_dev = pdev; ++ ++ /*io,clk,irq*/ ++ ++ dev->reg_base = of_iomap(pdev->dev.of_node, 0);; ++ if(IS_ERR(dev->reg_base)) { ++ ret = -ENODEV; ++ goto err_ioremap; ++ } ++ ++ /*TODO: clk pm ...*/ ++ dev->irq = platform_get_irq(pdev, 0); ++ ret = devm_request_irq(&pdev->dev, dev->irq, ingenic_vpu_irq, 0, pdev->name, dev); ++ if(ret ) { ++ dev_err(&pdev->dev, "Failed to request vpu irq!\n"); ++ goto err_irq; ++ } ++ ++ dev->clk_gate = clk_get(&pdev->dev, "power_felix"); ++ if (IS_ERR(dev->clk_gate)) { ++ ret = PTR_ERR(dev->clk_gate); ++ goto err_get_clk_gate; ++ } ++ ++ spin_lock_init(&dev->spinlock); ++ mutex_init(&dev->dev_mutex); ++ ++ dev->alloc_ctx = ingenic_vb2_dma_contig_init_ctx(&pdev->dev); ++ if(IS_ERR(dev->alloc_ctx)) { ++ ret = -ENOMEM; ++ goto err_ctx; ++ } ++ ++ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", "ingenic-v4l2-felix"); ++ ++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ if(ret) { ++ dev_err(&pdev->dev, "Failed to register v4l2_dev\n"); ++ goto err_v4l2; ++ } ++ ++ vfd = video_device_alloc(); ++ if(!vfd) { ++ dev_err(&pdev->dev, "Failed to alloc video device!\n"); ++ ret = -ENOMEM; ++ goto err_vdev; ++ } ++ ++ ++ vfd->fops = &ingenic_vdec_fops; ++ vfd->ioctl_ops = &ingenic_vdec_ioctl_ops; ++ vfd->release = video_device_release; ++ vfd->lock = &dev->dev_mutex; ++ vfd->v4l2_dev = &dev->v4l2_dev; ++ vfd->vfl_dir = VFL_DIR_M2M; ++ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; ++ ++ snprintf(vfd->name, sizeof(vfd->name), "%s", INGENIC_VCODEC_DEC_NAME); ++ ++ video_set_drvdata(vfd, dev); ++ dev->vfd = vfd; ++ platform_set_drvdata(pdev, dev); ++ ++ dev->m2m_dev = v4l2_m2m_init(&ingenic_vdec_m2m_ops); ++ if(IS_ERR((__force void *)dev->m2m_dev)) { ++ dev_err(&pdev->dev, "Failed to init m2m device!\n"); ++ ret = PTR_ERR((__force void *)dev->m2m_dev); ++ goto err_m2m; ++ } ++ ++ dev->dec_workqueue = alloc_ordered_workqueue(INGENIC_VCODEC_DEC_NAME, ++ WQ_MEM_RECLAIM | WQ_FREEZABLE); ++ if(!dev->dec_workqueue) { ++ dev_err(&pdev->dev, "Failed to create decode workqueue\n"); ++ ret = -EINVAL; ++ goto err_workq; ++ } ++ ++ ret = video_register_device(vfd, VFL_TYPE_VIDEO, INGENIC_FELIX_VIDEO_NR); ++ if(ret) { ++ dev_err(&pdev->dev, "Failed to register video device!\n"); ++ goto err_video_reg; ++ } ++ ++ ret = of_reserved_mem_device_init(dev->dev); ++ if(ret) ++ dev_warn(&pdev->dev, "failed to init reserved mem\n"); ++ ++ dev_info(&pdev->dev, "h264decoder(felix) registered as /dev/video%d\n", ++ vfd->num); ++ ++ return 0; ++err_video_reg: ++err_workq: ++err_m2m: ++err_vdev: ++err_v4l2: ++ ingenic_vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); ++err_ctx: ++//err_get_clk_cgu: ++err_get_clk_gate: ++err_irq: ++err_ioremap: ++ return ret; ++} ++ ++static int ingenic_vcodec_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static const struct of_device_id felix_of_match[] = { ++ { .compatible = "ingenic,x2000-felix"}, ++ { .compatible = "ingenic,m300-felix"}, ++ {}, ++}; ++ ++static struct platform_driver ingenic_vcodec_driver = { ++ .probe = ingenic_vcodec_probe, ++ .remove = ingenic_vcodec_remove, ++ .driver = { ++ .name = INGENIC_VCODEC_DEC_NAME, ++ .of_match_table = felix_of_match, ++ }, ++}; ++ ++static int __init felix_device_init(void) ++{ ++ platform_driver_register(&ingenic_vcodec_driver); ++ return 0; ++} ++ ++static void __exit felix_device_exit(void) ++{ ++ platform_driver_unregister(&ingenic_vcodec_driver); ++} ++ ++module_init(felix_device_init); ++module_exit(felix_device_exit); ++ ++ ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Ingenic Video Codec v4l2 encoder driver."); +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_drv.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_drv.h +new file mode 100644 +index 000000000..39e352671 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_drv.h +@@ -0,0 +1,159 @@ ++#ifndef __INGENIC_FELIX_DRV_H__ ++#define __INGENIC_FELIX_DRV_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "avcodec.h" ++#include "frame.h" ++#include "h264dec.h" ++ ++ ++#define INGENIC_VCODEC_DEC_NAME "felix-vdec" ++#define INGENIC_VCODEC_MAX_PLANES 3 ++ ++enum ingenic_fmt_type { ++ INGENIC_FMT_FRAME = 0, ++ INGENIC_FMT_DEC = 1, ++}; ++ ++enum felix_raw_format { ++ FELIX_TILE_MODE = 0, ++ FELIX_420P_MODE = 4, /* not support */ ++ FELIX_NV12_MODE = 8, ++ FELIX_NV21_MODE = 12, /* not support */ ++ FELIX_FORMAT_NONE, ++}; ++ ++struct ingenic_video_fmt { ++ u32 fourcc; ++ enum ingenic_fmt_type type; ++ u32 num_planes; ++ enum felix_raw_format format; ++}; ++ ++struct ingenic_vcodec_framesizes { ++ u32 fourcc; ++ struct v4l2_frmsize_stepwise stepwise; ++}; ++ ++enum ingenic_vcodec_state { ++ INGENIC_STATE_IDLE = 0, ++ INGENIC_STATE_HEADER, ++ INGENIC_STATE_RUNNING, ++ INGENIC_STATE_ABORT, ++}; ++ ++ ++/* private vcode buf related to each vb2, TODO: will implement in future. */ ++/* ++ * 这里的大å°å¿…须是struct v4l2_m2m_buffer. ++ * */ ++struct ingenic_vcodec_buf { ++ struct vb2_v4l2_buffer vb; ++ struct list_head list; //struct v4l2_m2m_buffer ++ ++ /*䏋颿‰æ˜¯è‡ªå·±ç§æœ‰çš„æ•°æ®ç»“æž„.*/ ++ AVFrame frame; ++ int is_last_frame; /*End of Stream.*/ ++}; ++ ++enum ingenic_q_type { ++ INGENIC_Q_DATA_SRC = 0, ++ INGENIC_Q_DATA_DST = 1, ++}; ++ ++struct ingenic_vcodec_q_data { ++ unsigned int visible_width; ++ unsigned int visible_height; ++ unsigned int coded_width; ++ unsigned int coded_height; ++ enum v4l2_field field; ++ unsigned int bytesperline[INGENIC_VCODEC_MAX_PLANES]; ++ unsigned int sizeimage[INGENIC_VCODEC_MAX_PLANES]; ++ unsigned int real_sizeimage[INGENIC_VCODEC_MAX_PLANES]; ++ struct ingenic_video_fmt *fmt; ++}; ++ ++/* vpu hw ctx ?? */ ++ ++ ++ ++ ++/* Each open creates a ctx ? */ ++struct ingenic_vdec_ctx { ++ ++ struct ingenic_vdec_dev *dev; ++ struct v4l2_fh fh; ++ struct v4l2_m2m_ctx *m2m_ctx; ++ ++ struct v4l2_ctrl_handler ctrl_hdl; ++ ++ int id; /* used for debug ?*/ ++ ++ struct ingenic_vcodec_q_data q_data[2]; ++ ++ wait_queue_head_t queue; ++ int output_stopped; ++ int capture_stopped; ++ ++ enum ingenic_vcodec_state state; ++ ++ enum v4l2_colorspace colorspace; ++ struct work_struct decode_work; ++ ++ struct ingenic_vcodec_buf *empty_flush_buf; ++ ++ int int_cond; ++ struct mutex lock; ++ ++ AVCodecContext *avctx; ++ H264Context *h; ++ ++}; ++ ++ ++struct ingenic_vdec_dev { ++ struct v4l2_device v4l2_dev; ++ struct video_device *vfd; ++ struct device *dev; ++ ++ struct v4l2_m2m_dev *m2m_dev; ++ struct platform_device *plat_dev; ++ ++ struct mutex dev_mutex; ++ ++ /* TODO: add workqueue*/ ++ struct workqueue_struct *dec_workqueue; ++ ++ spinlock_t spinlock; ++ ++ struct ingenic_vdec_ctx *curr_ctx; ++ struct vb2_dc_conf *alloc_ctx; ++ ++ int id_counter; ++ ++ void __iomem *reg_base; ++ int irq; ++ struct clk *clk_gate; ++ struct clk *clk; ++}; ++ ++ ++/* -----------------------------------helpler-------------------------------------*/ ++static inline struct ingenic_vdec_ctx *fh_to_ctx(struct v4l2_fh *fh) ++{ ++ return container_of(fh, struct ingenic_vdec_ctx, fh); ++} ++ ++static inline struct ingenic_vdec_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) ++{ ++ return container_of(ctrl->handler, struct ingenic_vdec_ctx, ctrl_hdl); ++} ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_ops.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_ops.c +new file mode 100644 +index 000000000..d7e038d28 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_ops.c +@@ -0,0 +1,1235 @@ ++/* ++* Copyright (c) 2014 Ingenic Inc. ++* Author: qipengzhen ++* ++* This program is free software; you can redistribute it and/or modify ++* it under the terms of the GNU General Public License version 2 as ++* published by the Free Software Foundation. ++* ++* This program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++*/ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "felix_drv.h" ++#include "felix_ops.h" ++ ++#undef pr_debug ++#define pr_debug pr_info ++ ++#define fh_to_ctx(__fh) container_of(__fh, struct ingenic_vdec_ctx, fh) ++ ++#define pixelformat_str(a) a >> 0, a >> 8, a >> 16, a >> 24 ++ ++ ++#define INGENIC_VDEC_MIN_W 160U ++#define INGENIC_VDEC_MIN_H 120U ++#define INGENIC_VDEC_MAX_W 2560U ++#define INGENIC_VDEC_MAX_H 2048U ++ ++ ++/*#define MAX_SUPPORT_FRAME_BUFFERS 16*/ ++ ++#define MAX_SUPPORT_FRAME_BUFFERS 6 ++ ++#define av_frame_to_vcode_buf(f) \ ++ container_of(f, struct ingenic_vcodec_buf, frame) \ ++ ++ ++static unsigned int max_frame_buffers = MAX_SUPPORT_FRAME_BUFFERS; ++module_param(max_frame_buffers, uint, S_IRUGO | S_IWUSR); ++ ++static struct ingenic_video_fmt ingenic_video_formats[] = { ++ /* out */ ++ { ++ .fourcc = V4L2_PIX_FMT_H264, ++ .type = INGENIC_FMT_DEC, ++ .num_planes = 1, ++ .format = FELIX_FORMAT_NONE, ++ }, ++#ifndef CONFIG_SOC_M200 ++ /* cap */ ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 2, ++ .format = FELIX_NV12_MODE, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 2, ++ .format = FELIX_NV21_MODE, ++ }, ++#endif ++ { ++ .fourcc = V4L2_PIX_FMT_JZ420B, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 2, ++ .format = FELIX_TILE_MODE, ++ } ++}; ++ ++#define NUM_FORMATS ARRAY_SIZE(ingenic_video_formats) ++#define OUT_FMT_IDX 0 ++#define NUM_OUT_FORMATS 1 ++#define CAP_FMT_IDX (OUT_FMT_IDX + NUM_OUT_FORMATS) ++ ++static const struct ingenic_vcodec_framesizes ingenic_vcodec_framesizes[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_H264, ++ .stepwise = { INGENIC_VDEC_MIN_W, INGENIC_VDEC_MAX_W, 2, ++ INGENIC_VDEC_MIN_H, INGENIC_VDEC_MAX_H, 2}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .stepwise = { INGENIC_VDEC_MIN_W, INGENIC_VDEC_MAX_W, 2, ++ INGENIC_VDEC_MIN_H, INGENIC_VDEC_MAX_H, 2}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .stepwise = { INGENIC_VDEC_MIN_W, INGENIC_VDEC_MAX_W, 2, ++ INGENIC_VDEC_MIN_H, INGENIC_VDEC_MAX_H, 2}, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_JZ420B, ++ .stepwise = { INGENIC_VDEC_MIN_W, INGENIC_VDEC_MAX_W, 2, ++ INGENIC_VDEC_MIN_H, INGENIC_VDEC_MAX_H, 2}, ++ }, ++}; ++ ++#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(ingenic_vcodec_framesizes) ++ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ strlcpy(cap->driver, INGENIC_VCODEC_DEC_NAME, sizeof(cap->driver)); ++ strlcpy(cap->bus_info, "vpu-felix", sizeof(cap->bus_info)); ++ strlcpy(cap->card, "vpu-felix", sizeof(cap->card)); ++ ++ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; ++ cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | ++ V4L2_CAP_VIDEO_CAPTURE_MPLANE | ++ V4L2_CAP_VIDEO_OUTPUT_MPLANE | ++ V4L2_CAP_DEVICE_CAPS; ++ ++ return 0; ++} ++ ++ ++static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) ++{ ++ struct ingenic_video_fmt *fmt; ++ int i,j = 0; ++ ++ ++ for(i = 0; i < NUM_FORMATS; i++) { ++ if(output_queue && ingenic_video_formats[i].type != INGENIC_FMT_DEC) ++ continue; ++ if(!output_queue && ingenic_video_formats[i].type != INGENIC_FMT_FRAME) ++ continue; ++ ++ if(j == f->index) { ++ fmt = &ingenic_video_formats[i]; ++ f->pixelformat = fmt->fourcc; ++ memset(f->reserved, 0, sizeof(f->reserved)); ++ return 0; ++ } ++ ++ j++; ++ } ++ ++ return -EINVAL; ++} ++ ++static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return vidioc_enum_fmt(f, false); ++} ++static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return vidioc_enum_fmt(f, true); ++} ++ ++static int vidioc_try_fmt(struct v4l2_format *f, struct ingenic_video_fmt *fmt) ++{ ++ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; ++ int i; ++ ++ pix_fmt_mp->field = V4L2_FIELD_NONE; ++ ++ if(f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ++ pix_fmt_mp->num_planes = 1; ++ pix_fmt_mp->plane_fmt[0].bytesperline = 0; ++ } else if(f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE){ ++ int tmp_w, tmp_h; ++ ++ pix_fmt_mp->height = clamp(pix_fmt_mp->height, ++ INGENIC_VDEC_MIN_H, ++ INGENIC_VDEC_MAX_H); ++ pix_fmt_mp->width = clamp(pix_fmt_mp->width, ++ INGENIC_VDEC_MIN_W, ++ INGENIC_VDEC_MAX_W); ++ ++ tmp_w = pix_fmt_mp->width; ++ tmp_h = pix_fmt_mp->height; ++ ++ ++#if 0 ++ v4l_bound_align_image(&pix_fmt_mp->width, ++ INGENIC_VDEC_MIN_W, ++ INGENIC_VDEC_MAX_W, 7, //128Bytes align ++ &pix_fmt_mp->height, ++ INGENIC_VDEC_MIN_H, ++ INGENIC_VDEC_MAX_H, 0, 0); ++ /*v4l2_bound_align_image will only round near, will round_down width.*/ ++#endif ++ tmp_w = ALIGN(pix_fmt_mp->width, 128); ++ tmp_h = pix_fmt_mp->height; ++ pr_debug("tmp_w %d tmp_h %d, w %d h %d\n", ++ tmp_w, tmp_h, ++ pix_fmt_mp->width, ++ pix_fmt_mp->height); ++ ++ ++ pix_fmt_mp->num_planes = fmt->num_planes; ++ pix_fmt_mp->plane_fmt[0].sizeimage = ++ tmp_w * tmp_h; ++ ++ pix_fmt_mp->plane_fmt[0].bytesperline = tmp_w; ++ ++ if(pix_fmt_mp->num_planes == 2) { ++ pix_fmt_mp->plane_fmt[1].sizeimage = ++ tmp_w * tmp_h / 2; ++ pix_fmt_mp->plane_fmt[2].sizeimage = 0; ++ ++ pix_fmt_mp->plane_fmt[1].bytesperline = tmp_w; ++ pix_fmt_mp->plane_fmt[2].bytesperline = 0; ++ } else if(pix_fmt_mp->num_planes == 3) { ++ pix_fmt_mp->plane_fmt[1].sizeimage = ++ pix_fmt_mp->plane_fmt[2].sizeimage = ++ (tmp_w * tmp_h) / 4; ++ ++ pix_fmt_mp->plane_fmt[1].bytesperline = ++ pix_fmt_mp->plane_fmt[2].bytesperline = ++ tmp_w / 2; ++ } ++ } ++ ++ for(i = 0; i < pix_fmt_mp->num_planes; i++) { ++ memset(&(pix_fmt_mp->plane_fmt[i].reserved[0]), 0x0, ++ sizeof(pix_fmt_mp->plane_fmt[0].reserved)); ++ } ++ ++// pix_fmt_mp->flags = 0; ++ ++ memset(&pix_fmt_mp->reserved, 0x0, ++ sizeof(pix_fmt_mp->reserved)); ++ ++ return 0; ++} ++ ++static struct ingenic_vcodec_q_data *ingenic_vcodec_get_q_data(struct ingenic_vdec_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ if(V4L2_TYPE_IS_OUTPUT(type)) ++ return &ctx->q_data[INGENIC_Q_DATA_SRC]; ++ ++ return &ctx->q_data[INGENIC_Q_DATA_DST]; ++} ++ ++static struct ingenic_video_fmt *ingenic_vcodec_find_format(struct v4l2_format *f) ++{ ++ struct ingenic_video_fmt *fmt; ++ int i; ++ ++ for(i = 0; i < NUM_FORMATS; i++) { ++ fmt = &ingenic_video_formats[i]; ++ if(fmt->fourcc == f->fmt.pix_mp.pixelformat) ++ return fmt; ++ } ++ ++ return NULL; ++} ++ ++static int vidioc_s_fmt_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_vcodec_q_data *q_data; ++ struct ingenic_video_fmt *fmt; ++ unsigned int pixelformat; ++ int i, ret; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if(!vq) { ++ pr_err("failed to get cap vq !\n"); ++ return -EINVAL; ++ } ++ ++ if(vb2_is_busy(vq)) { ++ pr_err("cap vq is busy!\n"); ++ return -EINVAL; ++ } ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, f->type); ++ if(!q_data) { ++ pr_err("fail to get cap q data!\n"); ++ return -EINVAL; ++ } ++ ++ ++ fmt = ingenic_vcodec_find_format(f); ++ if(!fmt) { ++ /* change to the first support cap format.*/ ++ f->fmt.pix.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ /* if buf type MPLANE, use pix_mp ..*/ ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ fmt = ingenic_vcodec_find_format(f); ++ } ++ ++ ++ q_data->fmt = fmt; ++ ++ ret = vidioc_try_fmt(f, q_data->fmt); ++ if(ret) ++ return ret; ++ ++ q_data->coded_width = ALIGN(f->fmt.pix_mp.width, 128); ++ q_data->coded_height = ALIGN(f->fmt.pix_mp.height, 16); ++ q_data->visible_width = f->fmt.pix_mp.width; ++ q_data->visible_height = f->fmt.pix_mp.height; ++ q_data->field = f->fmt.pix_mp.field; ++ ++ for(i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ struct v4l2_plane_pix_format *plane_fmt; ++ ++ plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; ++ q_data->bytesperline[i] = plane_fmt->bytesperline; ++ q_data->sizeimage[i] = plane_fmt->sizeimage; ++ q_data->real_sizeimage[i] = q_data->sizeimage[i] / q_data->visible_height * ALIGN(q_data->visible_height, 16); ++ } ++ ++ pixelformat = f->fmt.pix_mp.pixelformat; ++ switch(pixelformat) { ++ case V4L2_PIX_FMT_NV12: ++ h264_set_output_format(ctx->h, VPU_FORMAT_NV12, q_data->coded_width, q_data->coded_height); ++ break; ++ case V4L2_PIX_FMT_NV21: ++ h264_set_output_format(ctx->h, VPU_FORMAT_NV21, q_data->coded_width, q_data->coded_height); ++ break; ++ case V4L2_PIX_FMT_JZ420B: ++ h264_set_output_format(ctx->h, VPU_FORMAT_TILE420, q_data->coded_width, q_data->coded_height); ++ break; ++ default: ++ pr_err("Unsupported pix fmt: %x\n", pixelformat); ++ ret = -EINVAL; ++ break; ++ } ++ ++ ++ return ret; ++} ++ ++static int vidioc_s_fmt_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_vcodec_q_data *q_data; ++ struct ingenic_video_fmt *fmt; ++ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; ++ int ret, i; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if(!vq) { ++ pr_err("fail to get out vq!\n"); ++ return -EINVAL; ++ } ++ if(vb2_is_busy(vq)) { ++ pr_err("out vq is busy!\n"); ++ return -EINVAL; ++ } ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, f->type); ++ if(!q_data) { ++ pr_err("failed to get out q_data!\n"); ++ return -EINVAL; ++ } ++ ++ ++ fmt = ingenic_vcodec_find_format(f); ++ if(!fmt) { ++ /* change to the first support cap format.*/ ++ f->fmt.pix.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ fmt = ingenic_vcodec_find_format(f); ++ } ++ ++ ++ pix_fmt_mp->height = clamp(pix_fmt_mp->height, ++ INGENIC_VDEC_MIN_H, ++ INGENIC_VDEC_MAX_H); ++ pix_fmt_mp->width = clamp(pix_fmt_mp->width, ++ INGENIC_VDEC_MIN_W, ++ INGENIC_VDEC_MAX_W); ++ ++ q_data->visible_width = f->fmt.pix_mp.width; ++ q_data->visible_height = f->fmt.pix_mp.height; ++ q_data->fmt = fmt; ++ ret = vidioc_try_fmt(f, q_data->fmt); ++ if (ret) ++ return ret; ++ ++ q_data->coded_width = ALIGN(f->fmt.pix_mp.width, 128); ++ q_data->coded_height = ALIGN(f->fmt.pix_mp.height, 16); ++ ++ q_data->field = f->fmt.pix_mp.field; ++ ctx->colorspace = f->fmt.pix_mp.colorspace; ++ //ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; ++ //ctx->quantization = f->fmt.pix_mp.quantization; ++ //ctx->xfer_func = f->fmt.pix_mp.xfer_func; ++ ++ ++ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ struct v4l2_plane_pix_format *plane_fmt; ++ ++ plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; ++ q_data->bytesperline[i] = plane_fmt->bytesperline; ++ q_data->sizeimage[i] = plane_fmt->sizeimage; ++ q_data->real_sizeimage[i] = plane_fmt->sizeimage; ++ } ++ ++ { /* set capture as same as output, necessary for gstream v4l2videodec. */ ++ struct v4l2_format fmt; ++ memset(&fmt, 0, sizeof(struct v4l2_format)); ++ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ fmt.fmt.pix_mp.width = f->fmt.pix_mp.width; ++ fmt.fmt.pix_mp.height = f->fmt.pix_mp.height; ++ vidioc_s_fmt_cap(file, priv, &fmt); ++ } ++ ++ ++ ++ return 0; ++} ++ ++static int vidioc_g_fmt(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_vcodec_q_data *q_data; ++ int i; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, f->type); ++ ++ if (q_data->fmt == NULL) ++ return -EINVAL; ++ ++ pix->width = q_data->visible_width; ++ pix->height = q_data->visible_height; ++ pix->pixelformat = q_data->fmt->fourcc; ++ pix->field = q_data->field; ++ pix->num_planes = q_data->fmt->num_planes; ++ for (i = 0; i < pix->num_planes; i++) { ++ pix->plane_fmt[i].bytesperline = q_data->bytesperline[i]; ++ pix->plane_fmt[i].sizeimage = q_data->sizeimage[i]; ++ memset(&(pix->plane_fmt[i].reserved[0]), 0x0, ++ sizeof(pix->plane_fmt[i].reserved)); ++ } ++ ++// pix->flags = 0; ++ pix->colorspace = ctx->colorspace; ++// pix->ycbcr_enc = ctx->ycbcr_enc; ++// pix->quantization = ctx->quantization; ++// pix->xfer_func = ctx->xfer_func; ++ ++ return 0; ++} ++ ++static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct ingenic_video_fmt *fmt; ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ fmt = ingenic_vcodec_find_format(f); ++ if (!fmt) { ++ f->fmt.pix.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ fmt = ingenic_vcodec_find_format(f); ++ } ++ f->fmt.pix_mp.colorspace = ctx->colorspace; ++ //f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; ++ //f->fmt.pix_mp.quantization = ctx->quantization; ++ //f->fmt.pix_mp.xfer_func = ctx->xfer_func; ++ ++ return vidioc_try_fmt(f, fmt); ++} ++ ++static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct ingenic_video_fmt *fmt; ++ ++ fmt = ingenic_vcodec_find_format(f); ++ if (!fmt) { ++ f->fmt.pix.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ fmt = ingenic_vcodec_find_format(f); ++ } ++ if (!f->fmt.pix_mp.colorspace) { ++ f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; ++ // f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; ++ // f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; ++ // f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; ++ } ++ ++ return vidioc_try_fmt(f, fmt); ++} ++ ++static int vidioc_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *reqbufs) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); ++} ++ ++static int vidioc_querybuf(struct file *file, void *priv, ++ struct v4l2_buffer *buf) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); ++ ++} ++ ++static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ int ret = 0; ++ ++ if(ctx->state == INGENIC_STATE_ABORT) { ++ return -EIO; ++ } ++ ++ ret = v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); ++ ++#if 0 ++ { ++ struct vb2_queue *vq; ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type); ++ printk("---%s, %d, index: %d, type:%d [%s], state:%d\n", ++ __func__, __LINE__, buf->index, buf->type, buf->type == 10 ? "OUTPUT":"CAPTUR", vq->bufs[buf->index]->state); ++ } ++#endif ++ return ret; ++} ++ ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ int ret = 0; ++ ++ ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); ++ if(buf->flags & V4L2_BUF_FLAG_LAST) ++ buf->flags &= ~V4L2_BUF_FLAG_LAST; ++#if 0 ++ { ++ struct vb2_queue *vq; ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type); ++ printk("---%s, %d, index: %d, type:%d [%s], state:%d\n", ++ __func__, __LINE__, buf->index, buf->type, buf->type == 10 ? "OUTPUT":"CAPTUR", vq->bufs[buf->index]->state); ++ } ++#endif ++ return ret; ++} ++ ++static int vidioc_expbuf(struct file *file, void *priv, ++ struct v4l2_exportbuffer *eb) ++{ ++ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); ++} ++ ++static int vidioc_create_bufs(struct file *file, void *priv, ++ struct v4l2_create_buffers *create) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ struct ingenic_vcodec_q_data *q_data = NULL; ++ struct ingenic_video_fmt *fmt = NULL; ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); ++ fmt = q_data->fmt; ++ ++ if(fmt->fourcc == V4L2_PIX_FMT_JZ420B && create->count < 2) ++ create->count = 2; ++ ++ return v4l2_m2m_create_bufs(file, ctx->m2m_ctx, create); ++} ++static int vidioc_prepare_buf(struct file *file, void *fh, struct v4l2_buffer *b) ++{ ++ ++ return 0; ++} ++ ++static int vidioc_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); ++} ++ ++static int vidioc_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); ++} ++ ++ ++static int vidioc_g_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ struct ingenic_vcodec_q_data *q_data; ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, s->type); ++ ++ s->r.left = 0; ++ s->r.top = 0; ++ s->r.width = q_data->visible_width; ++ s->r.height = q_data->visible_height; ++ ++ return 0; ++} ++ ++static int vidioc_s_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ return 0; ++} ++ ++static int vidioc_enum_framesizes(struct file *file, void *fh, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ int i = 0; ++ if(fsize->index != 0) ++ return -EINVAL; ++ ++ for(i = 0; i < NUM_SUPPORTED_FRAMESIZE; i++) { ++ if(fsize->pixel_format != ingenic_vcodec_framesizes[i].fourcc) ++ continue; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; ++ fsize->stepwise = ingenic_vcodec_framesizes[i].stepwise; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int vidioc_enum_frameintervals(struct file *file, void *priv, ++ struct v4l2_frmivalenum *fe) ++{ ++ if (fe->index) ++ return -EINVAL; ++ ++ fe->type = V4L2_FRMIVAL_TYPE_STEPWISE; ++ ++ fe->stepwise.min.numerator = 1; ++ fe->stepwise.min.denominator = 0; ++ ++ fe->stepwise.max.numerator = 1001; ++ fe->stepwise.max.denominator = 80000; ++ ++ fe->stepwise.step.numerator = 1; ++ fe->stepwise.step.denominator = 1; ++ return 0; ++} ++ ++static int vidioc_try_decoder_cmd (struct file *file, void *priv, ++ struct v4l2_decoder_cmd *cmd) ++{ ++ switch (cmd->cmd) { ++ case V4L2_DEC_CMD_STOP: ++ case V4L2_DEC_CMD_START: ++ if (cmd->flags != 0) { ++ pr_err("cmd->flags=%u", cmd->flags); ++ return -EINVAL; ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ++ return 0; ++} ++static int vidioc_decoder_cmd (struct file *file, void *priv, ++ struct v4l2_decoder_cmd *cmd) ++{ ++ struct ingenic_vdec_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *src_vq, *dst_vq; ++ int ret = 0; ++ ++ ret = vidioc_try_decoder_cmd(file, priv, cmd); ++ if(ret < 0) { ++ return ret; ++ } ++ ++ dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, ++ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ switch(cmd->cmd) { ++ case V4L2_DEC_CMD_STOP: ++ src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, ++ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); ++ if (!vb2_is_streaming(src_vq)) { ++ pr_info("Output stream is off. No need to flush."); ++ return 0; ++ } ++ if (!vb2_is_streaming(dst_vq)) { ++ pr_info("Capture stream is off. No need to flush."); ++ return 0; ++ } ++ ++ ++ v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf->vb); ++ ++ v4l2_m2m_try_schedule(ctx->m2m_ctx); ++ break; ++ case V4L2_DEC_CMD_START: ++ vb2_clear_last_buffer_dequeued(dst_vq); ++ break; ++ ++ default: ++ return -EINVAL; ++ ++ } ++ ++ return 0; ++} ++ ++ ++ ++const struct v4l2_ioctl_ops ingenic_vdec_ioctl_ops = { ++ ++ /* VIDIOC_QUERYCAP handler */ ++ .vidioc_querycap = vidioc_querycap, ++ ++ /* VIDIOC_ENUM_FMT handlers */ ++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap_mplane, ++ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out_mplane, ++ ++ /* VIDIOC_G_FMT handlers */ ++ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, ++ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, ++ ++ /* VIDIOC_S_FMT handlers */ ++ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap, ++ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out, ++ ++ /* VIDIOC_TRY_FMT handlers */ ++ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, ++ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, ++ ++ /* Buffer handlers */ ++ .vidioc_reqbufs = vidioc_reqbufs, ++ .vidioc_querybuf = vidioc_querybuf, ++ .vidioc_qbuf = vidioc_qbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ .vidioc_expbuf = vidioc_expbuf, ++ ++ .vidioc_create_bufs = vidioc_create_bufs, ++ .vidioc_prepare_buf = vidioc_prepare_buf, ++ ++ /* Stream on/off */ ++ .vidioc_streamon = vidioc_streamon, ++ .vidioc_streamoff = vidioc_streamoff, ++ ++ /* Crop ioctls */ ++ .vidioc_g_selection = vidioc_g_selection, ++ .vidioc_s_selection = vidioc_s_selection, ++ ++ .vidioc_decoder_cmd = vidioc_decoder_cmd, ++ .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd, ++ ++ .vidioc_enum_framesizes = vidioc_enum_framesizes, ++ ++ .vidioc_enum_frameintervals = vidioc_enum_frameintervals, ++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++ ++}; ++ ++ ++static void __maybe_unused dump_vb2_buffer(struct vb2_buffer *vb2, const char *str) ++{ ++ int i; ++ printk("======dump vb2: %s=========\n", str); ++ printk("vb2->num_planes: %d\n", vb2->num_planes); ++ printk("vb2->index: %d\n", vb2->index); ++ printk("vb2->type: %d\n", vb2->type); ++ //printk("vb2->v4l2_buf.sequence: %d\n", vb2->v4l2_buf.sequence); ++ //printk("vb2->v4l2_buf.length: %d\n", vb2->v4l2_buf.length); ++ for(i = 0; i < vb2->num_planes; i++) { ++ printk("planes@ %d : \n", i); ++ printk("\tbyteused: %d\n", vb2->planes[i].bytesused); ++ printk("\tlength: %d\n", vb2->planes[i].length); ++ ++ printk("\tvaddr: 0x%p\n", vb2_plane_vaddr(vb2, i)); ++ printk("\tpaddr: 0x%08x\n", ingenic_vb2_dma_contig_plane_dma_addr(vb2, i)); ++ ++ /* data from vaddr to vaddr + length */ ++ print_hex_dump(KERN_INFO, "data@ ", DUMP_PREFIX_ADDRESS, 16, 1, vb2_plane_vaddr(vb2, i), 128, true); ++ ++ printk("----------------------------------------\n"); ++ } ++} ++ ++static void ingenic_vdec_worker(struct work_struct *work) ++{ ++ struct ingenic_vdec_ctx *ctx = container_of(work, struct ingenic_vdec_ctx, decode_work); ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ struct ingenic_vcodec_buf *vcodec_src_buf; ++ AVCodecContext *avctx = ctx->avctx; ++ H264Context *h = ctx->h; ++ AVFrame *f = NULL; ++ AVPacket avpkt; ++ int got_frame = 0; ++ int ret = 0; ++ int decode_error = 0; ++ int eos = 0; ++ ++ ++ src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); ++ if(src_buf == NULL) { ++ pr_info("src_buf empty\n"); ++ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx); ++ return; ++ } ++ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); ++ if(dst_buf == NULL) { ++ pr_info("dst_buf empty\n"); ++ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx); ++ return; ++ } ++ ++ //dump_vb2_buffer(src_buf, "src_buf"); ++ ++ if(src_buf->vb2_buf.planes[0].bytesused > src_buf->vb2_buf.planes[0].length) { ++ printk("**** Error, src_buf out of range [%d > %d]\n", src_buf->vb2_buf.planes[0].bytesused, src_buf->vb2_buf.planes[0].length); ++ } ++ ++ ++ vcodec_src_buf = container_of(src_buf, struct ingenic_vcodec_buf, vb); ++ ++ /*如果当å‰å¤„ç†çš„æ˜¯empty buf, ä¸ç”¨å¤„ç†è§£ç ï¼Œç›´æŽ¥ä»Žé˜Ÿåˆ—中删除src_buf.*/ ++ if((vcodec_src_buf->is_last_frame == true) || ++ (src_buf->vb2_buf.planes[0].bytesused == 0)) { ++ ++ /*Got Empty stream, End of stream.*/ ++ eos = 1; ++ v4l2_m2m_src_buf_remove(ctx->m2m_ctx); ++ ++ /*å°†vpu残留的中间buffer全部还给内核.*/ ++ goto done; ++ } ++ ++ src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); ++ dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ ++ ++ avpkt.size = vb2_get_plane_payload(&src_buf->vb2_buf, 0); ++ avpkt.data_pa = ingenic_vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); ++ if (src_buf->vb2_buf.memory == VB2_MEMORY_USERPTR) ++ avpkt.data = phys_to_virt(avpkt.data_pa); ++ else ++ avpkt.data = vb2_plane_vaddr(&src_buf->vb2_buf, 0); ++ ++ if(dst_buf) { ++ struct ingenic_vcodec_buf *buf = container_of(dst_buf, ++ struct ingenic_vcodec_buf, vb); ++ ++ dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; ++ dst_buf->timecode = src_buf->timecode; ++ dst_buf->sequence = src_buf->sequence; ++ ++ h264_enqueue_frame(h, &buf->frame); ++ } ++ ++ ret = h264_decode_frame(avctx, NULL, &got_frame, &avpkt); ++ if(ret < 0) { ++ decode_error = 1; ++ } ++ ++ if(got_frame) { ++ /*drain display frame*/ ++ f = h264_dequeue_frame(h); ++ if(f) { ++ struct ingenic_vcodec_buf *done_buf = av_frame_to_vcode_buf(f); ++ //printk("------done_buf: %x done frame f: %x-----buf->index:%d, f->index: %d\n", done_buf, f, done_buf->vb.v4l2_buf.index, f->index); ++ ++ ++ vb2_set_plane_payload(&done_buf->vb.vb2_buf, 0, f->buf[0]->size); ++ vb2_set_plane_payload(&done_buf->vb.vb2_buf, 1, f->buf[1]->size); ++ //dump_vb2_buffer(&done_buf->vb, "dst_buf"); ++ v4l2_m2m_buf_done(&done_buf->vb, VB2_BUF_STATE_DONE); ++ } ++ } ++ ++ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); ++ ++done: ++ if((decode_error) || (eos)) { ++ ++ if(eos) { ++ while((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { ++ dst_buf->vb2_buf.planes[0].bytesused = 0; ++ dst_buf->flags |= V4L2_BUF_FLAG_DONE; ++ dst_buf->flags |= V4L2_BUF_FLAG_LAST; ++ dst_buf->vb2_buf.timestamp = ktime_get(); ++ /*ä¿è¯ä¸¤ä¸ªçš„æ—¶é—´æˆ³ä¸ä¸€æ ·.*/ ++ dst_buf->vb2_buf.timestamp = ktime_add_ns(dst_buf->vb2_buf.timestamp, 10); ++ /* work around, return buffer to userspace with 0 byteused. */ ++ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); ++ } ++ } ++ ++ /* retrain all enqueued frame, do not stop decode.*/ ++ while((f = h264_get_queued_frame(h))) { ++ struct ingenic_vcodec_buf *err_buf = av_frame_to_vcode_buf(f); ++ vb2_set_plane_payload(&err_buf->vb.vb2_buf, 0, 0); ++ vb2_set_plane_payload(&err_buf->vb.vb2_buf, 1, 0); ++ v4l2_m2m_buf_done(&err_buf->vb, VB2_BUF_STATE_ERROR); ++ } ++ ++ while((f = h264_dequeue_frame(h))) { ++ struct ingenic_vcodec_buf *err_buf = av_frame_to_vcode_buf(f); ++ vb2_set_plane_payload(&err_buf->vb.vb2_buf, 0, 0); ++ vb2_set_plane_payload(&err_buf->vb.vb2_buf, 1, 0); ++ v4l2_m2m_buf_done(&err_buf->vb, VB2_BUF_STATE_ERROR); ++ } ++ } ++ ++ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx); ++} ++ ++static void m2mops_vdec_device_run(void *priv) ++{ ++ struct ingenic_vdec_ctx *ctx = priv; ++ struct ingenic_vdec_dev *dev = ctx->dev; ++ ++ queue_work(dev->dec_workqueue, &ctx->decode_work); ++} ++ ++static int m2mops_vdec_job_ready(void *m2m_priv) ++{ ++ struct ingenic_vdec_ctx *ctx = m2m_priv; ++ ++ if(ctx->state == INGENIC_STATE_ABORT || ctx->state == INGENIC_STATE_IDLE) { ++ pr_info("job not ready, ctx->state %d\n", ctx->state); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static void m2mops_vdec_job_abort(void *priv) ++{ ++ struct ingenic_vdec_ctx *ctx = priv; ++ ctx->state = INGENIC_STATE_ABORT; ++} ++ ++const struct v4l2_m2m_ops ingenic_vdec_m2m_ops = { ++ .device_run = m2mops_vdec_device_run, ++ .job_ready = m2mops_vdec_job_ready, ++ .job_abort = m2mops_vdec_job_abort, ++}; ++ ++static int vb2ops_vcodec_queue_setup(struct vb2_queue *vq, ++ unsigned int *nbuffers, ++ unsigned int *nplanes, ++ unsigned int sizes[], ++ struct device *alloc_ctxs[]) ++{ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(vq); ++ struct ingenic_vcodec_q_data *q_data; ++ int i; ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, vq->type); ++ if(q_data == NULL) ++ return -EINVAL; ++ ++ if(*nplanes) { ++ for(i = 0; i < *nplanes; i++) { ++ sizes[i] = q_data->real_sizeimage[i]; ++ if(sizes[i] < q_data->real_sizeimage[i]) { ++ return -EINVAL; ++ } ++ } ++ } else { ++ *nplanes = q_data->fmt->num_planes; ++ for (i = 0; i < *nplanes; i++) { ++ sizes[i] = q_data->real_sizeimage[i]; ++ alloc_ctxs[i] = ctx->dev->dev; ++ } ++ } ++ ++ if(*nbuffers > max_frame_buffers) ++ *nbuffers = max_frame_buffers; ++ ++ return 0; ++} ++ ++static int vb2ops_vcodec_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct ingenic_vcodec_q_data *q_data; ++ int i; ++ ++ q_data = ingenic_vcodec_get_q_data(ctx, vb->vb2_queue->type); ++ ++ for(i = 0; i < q_data->fmt->num_planes; i++) { ++ if(vb2_plane_size(vb, i) > q_data->real_sizeimage[i]) { ++ ++ pr_err("Failed to prepare buf!\n"); ++ ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++static int vb2ops_vcodec_buf_init(struct vb2_buffer *vb) ++{ ++ struct ingenic_vcodec_buf *buf = container_of(to_vb2_v4l2_buffer(vb), ++ struct ingenic_vcodec_buf, vb); ++ ++ int i; ++ AVFrame *f = &buf->frame; ++ ++ f->index = vb->index; ++ for(i = 0; i < vb->num_planes; i++) { ++ f->buf[i] = av_buffer_create(vb2_plane_vaddr(vb, i), ++ ingenic_vb2_dma_contig_plane_dma_addr(vb, i), ++ vb2_plane_size(vb, i) ++ ); ++ } ++ return 0; ++} ++static void vb2ops_vcodec_buf_cleanup(struct vb2_buffer *vb) ++{ ++ struct ingenic_vcodec_buf *buf = container_of(to_vb2_v4l2_buffer(vb), ++ struct ingenic_vcodec_buf, vb); ++ int i; ++ AVFrame *f = &buf->frame; ++ ++ for(i = 0; i < vb->num_planes; i++) { ++ av_buffer_del(f->buf[i]); ++ } ++} ++ ++static void vb2ops_vcodec_buf_queue(struct vb2_buffer *vb) ++{ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); ++ return; ++} ++ ++static void vb2ops_vcodec_buf_finish(struct vb2_buffer *vb) ++{ ++ return; ++} ++ ++ ++static int vb2ops_vcodec_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(q); ++ struct ingenic_vcodec_q_data *q_data_src; ++ struct ingenic_vcodec_q_data *q_data_dst; ++ ++ if(V4L2_TYPE_IS_OUTPUT(q->type)) { ++ ctx->output_stopped = 0; ++ } else { ++ ctx->capture_stopped = 0; ++ } ++ ++ if(ctx->output_stopped || ctx->capture_stopped) ++ return 0; ++ ++ q_data_src = ingenic_vcodec_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); ++ q_data_dst = ingenic_vcodec_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ ++ ctx->state = INGENIC_STATE_RUNNING; ++ return 0; ++} ++ ++static void vb2ops_vcodec_stop_streaming(struct vb2_queue *q) ++{ ++ ++ struct ingenic_vdec_ctx *ctx = vb2_get_drv_priv(q); ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ H264Context *h = ctx->h; ++ AVFrame *f = NULL; ++ ++ if(q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ++ ++ while((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { ++ dst_buf->vb2_buf.planes[0].bytesused = 0; ++ dst_buf->flags |= V4L2_BUF_FLAG_DONE; ++ dst_buf->vb2_buf.timestamp = ktime_get(); ++ /*ä¿è¯ä¸¤ä¸ªçš„æ—¶é—´æˆ³ä¸ä¸€æ ·.*/ ++ dst_buf->vb2_buf.timestamp = ktime_add_ns(dst_buf->vb2_buf.timestamp, 10); ++ /* work around, return buffer to userspace with 0 byteused. */ ++ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); ++ } ++ ++ while((f = h264_get_queued_frame(h))) { ++ struct ingenic_vcodec_buf *err_buf = av_frame_to_vcode_buf(f); ++ vb2_set_plane_payload(&err_buf->vb.vb2_buf, 0, 0); ++ vb2_set_plane_payload(&err_buf->vb.vb2_buf, 1, 0); ++ v4l2_m2m_buf_done(&err_buf->vb, VB2_BUF_STATE_DONE); ++ } ++ ++ while((f = h264_dequeue_frame(h))) { ++ struct ingenic_vcodec_buf *err_buf = av_frame_to_vcode_buf(f); ++ vb2_set_plane_payload(&err_buf->vb.vb2_buf, 0, 0); ++ vb2_set_plane_payload(&err_buf->vb.vb2_buf, 1, 0); ++ v4l2_m2m_buf_done(&err_buf->vb, VB2_BUF_STATE_DONE); ++ } ++ ++ } else { ++ while((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) { ++ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); ++ } ++ } ++ ++ if(q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ++ ctx->capture_stopped = 1; ++ else ++ ctx->output_stopped = 1; ++ ++ if((ctx->capture_stopped && ctx->output_stopped) == 0) { ++ return; ++ } ++ ++ ctx->state = INGENIC_STATE_IDLE; ++ ++ return; ++} ++ ++static const struct vb2_ops ingenic_vcodec_vb2_ops = { ++ .queue_setup = vb2ops_vcodec_queue_setup, ++ .buf_prepare = vb2ops_vcodec_buf_prepare, ++ .buf_init = vb2ops_vcodec_buf_init, ++ .buf_cleanup = vb2ops_vcodec_buf_cleanup, ++ .buf_queue = vb2ops_vcodec_buf_queue, ++ .buf_finish = vb2ops_vcodec_buf_finish, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++ .start_streaming = vb2ops_vcodec_start_streaming, ++ .stop_streaming = vb2ops_vcodec_stop_streaming, ++}; ++ ++int ingenic_vcodec_vdec_queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq) ++{ ++ struct ingenic_vdec_ctx *ctx = priv; ++ int ret = 0; ++ ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ++ src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; ++ src_vq->drv_priv = ctx; ++ src_vq->buf_struct_size = sizeof(struct ingenic_vcodec_buf); ++ src_vq->ops = &ingenic_vcodec_vb2_ops; ++ src_vq->mem_ops = &ingenic_vb2_dma_contig_memops; ++ src_vq->lock = &ctx->dev->dev_mutex; ++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ src_vq->dev = ctx->dev->dev; ++ ++ ret = vb2_queue_init(src_vq); ++ if(ret) ++ return ret; ++ ++ ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; ++ dst_vq->drv_priv = ctx; ++ dst_vq->buf_struct_size = sizeof(struct ingenic_vcodec_buf); ++ dst_vq->ops = &ingenic_vcodec_vb2_ops; ++ dst_vq->mem_ops = &ingenic_vb2_dma_contig_memops; ++ dst_vq->lock = &ctx->dev->dev_mutex; ++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ dst_vq->dev = ctx->dev->dev; ++ ++ ret = vb2_queue_init(dst_vq); ++ if(ret) { ++ vb2_queue_release(src_vq); ++ } ++ ++ return ret; ++} ++ ++ ++int ingenic_vcodec_init_default_params(struct ingenic_vdec_ctx *ctx) ++{ ++ struct vb2_queue *src_vq; ++ int ret = 0; ++ ctx->capture_stopped = 1; ++ ctx->output_stopped = 1; ++ ctx->state = INGENIC_STATE_IDLE; ++ INIT_WORK(&ctx->decode_work, ingenic_vdec_worker); ++ ++ src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); ++ ++ ctx->empty_flush_buf = kzalloc(sizeof(struct ingenic_vcodec_buf), GFP_KERNEL); ++ if(!ctx->empty_flush_buf) { ++ pr_err("failed to alloc empty_flush_buf\n"); ++ return -ENOMEM; ++ } ++ ++ ctx->empty_flush_buf->vb.vb2_buf.vb2_queue = src_vq; ++ ctx->empty_flush_buf->is_last_frame = true; ++ ++ ++ return ret; ++} ++ ++int ingenic_vcodec_deinit_default_params(struct ingenic_vdec_ctx *ctx) ++{ ++ ++ kfree(ctx->empty_flush_buf); ++ ++ return 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_ops.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_ops.h +new file mode 100644 +index 000000000..26099956c +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/felix_ops.h +@@ -0,0 +1,15 @@ ++#ifndef __FELIX_OPS_H__ ++#define __FELIX_OPS_H__ ++ ++ ++extern const struct v4l2_ioctl_ops ingenic_vdec_ioctl_ops; ++extern const struct v4l2_m2m_ops ingenic_vdec_m2m_ops; ++ ++int ingenic_vcodec_vdec_queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq); ++ ++int ingenic_vcodec_init_default_params(struct ingenic_vdec_ctx *ctx); ++ ++int ingenic_vcodec_deinit_default_params(struct ingenic_vdec_ctx *ctx); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/Makefile b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/Makefile +new file mode 100644 +index 000000000..f2bf4c329 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/Makefile +@@ -0,0 +1,25 @@ ++ifneq ($(KERNELRELEASE),) ++obj-y += api/jzm_h264_dec.o ++ ++obj-y += src/ ++ ++else ++#KDIR := "/home1/pzqi/Manhatton-halley2-v2.0-release/kernel/" ++KDIR := "/home/boysic/work/dorado/platform/kernel" ++EXTRA_CFLAGS := -I`pwd` -I`pwd`/include ++all: ++ $(MAKE) -C $(KDIR) M=`pwd` modules EXTRA_CFLAGS+=$(EXTRA_CFLAGS) ++ ++clean: ++ rm -f libavcodec/api/.*.cmd ++ rm -f libavcodec/api/*.o ++ rm -f libavcodec/.*.cmd ++ rm -f libavcodec/*.mod.c ++ rm -f libavcodec/*.order ++ rm -f libavcodec/*.o ++ rm -f libavcodec/*.ko ++ rm -f libavutil/.*.cmd ++ rm -f libavutil/.*.o ++ rm -f libavutil/*.o ++endif ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_h264_dec.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_h264_dec.c +new file mode 100644 +index 000000000..958d4ec2e +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_h264_dec.c +@@ -0,0 +1,1123 @@ ++#ifndef _JZM_H264_API_C_ ++#define _JZM_H264_API_C_ ++ ++#include "jzm_h264_dec.h" ++ ++__place_k0_data__ unsigned lps_comb[128]={ ++ 0xefcfaffe,0xefcfafff,0xe2c4a6fe,0xe2c4a6ff,0xd7ba9dfe,0xd7ba9dff,0xccb195f4,0xccb195f5, ++ 0xc2a88de6,0xc2a88de7,0xb89f86dc,0xb89f86dd,0xae977fd0,0xae977fd1,0xa58f79c6,0xa58f79c7, ++ 0x9d8873bc,0x9d8873bd,0x95816db2,0x95816db3,0x8d7a67a8,0x8d7a67a9,0x867462a0,0x867462a1, ++ 0x7f6e5d98,0x7f6e5d99,0x79685890,0x79685891,0x73635488,0x73635489,0x6d5e4f82,0x6d5e4f83, ++ 0x67594b7a,0x67594b7b,0x62554774,0x62554775,0x5d50446e,0x5d50446f,0x584c4068,0x584c4069, ++ 0x54483d64,0x54483d65,0x4f443a5e,0x4f443a5f,0x4b41375a,0x4b41375b,0x473e3454,0x473e3455, ++ 0x443a3150,0x443a3151,0x40372f4c,0x40372f4d,0x3d352c48,0x3d352c49,0x3a322a44,0x3a322a45, ++ 0x372f2840,0x372f2841,0x342d263e,0x342d263f,0x312a243a,0x312a243b,0x2f282238,0x2f282239, ++ 0x2c262034,0x2c262035,0x2a241e32,0x2a241e33,0x28221d2e,0x28221d2f,0x26201b2c,0x26201b2d, ++ 0x241f1a2a,0x241f1a2b,0x221d1928,0x221d1929,0x201c1726,0x201c1727,0x1e1a1624,0x1e1a1625, ++ 0x1d191522,0x1d191523,0x1b181420,0x1b181421,0x1a16131e,0x1a16131f,0x1815121c,0x1815121d, ++ 0x1714111a,0x1714111b,0x1613101a,0x1613101b,0x15120f18,0x15120f19,0x14110e16,0x14110e17, ++ 0x13100d16,0x13100d17,0x120f0d14,0x120f0d15,0x110e0c14,0x110e0c15,0x100e0b12,0x100e0b13, ++ 0xf0d0b12,0xf0d0b13,0xe0c0a10,0xe0c0a11,0xd0b0a10,0xd0b0a11,0xd0b090e,0xd0b090f,0xc0a080e, ++ 0xc0a080f,0xb0a080c,0xb0a080d,0xb09080c,0xb09080d,0xa09070c,0xa09070d,0xa08070a,0xa08070b, ++ 0x908060a,0x908060b,0x807060a,0x807060b,0x1010102,0x1010103 ++}; ++ ++__place_k0_data__ struct SDE_VLC_STA sde_vlc2_sta[7] = { ++ {0 , 128, 6}, // vlc_tables_coeff_token_table_0 ++ {128, 116, 5}, // vlc_tables_coeff_token_table_1 ++ {256, 104, 6}, // vlc_tables_coeff_token_table_2 ++ {384, 64, 6}, // vlc_tables_coeff_token_table_3 ++ {512, 70, 6}, // vlc_tables_chroma_dc_coeff_token_table ++ {640, 74, 6}, // vlc_tables_total_zeros_table_0 ++ {768, 96, 6}, // vlc_tables_run7_table ++}; ++__place_k0_data__ unsigned short sde_vlc2_table[7][128]={ ++ { // 0 ++ 0xa020, 0x887c, 0x806c, 0x200f, 0x100a, 0x100a, 0x100a, 0x100a, ++ 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 32 ++ 0xa040, 0x9070, 0x8078, 0x807a, 0x2023, 0x201a, 0x2015, 0x2010, ++ 0x181f, 0x181f, 0x1816, 0x1816, 0x1811, 0x1811, 0x180c, 0x180c, ++ 0x101b, 0x101b, 0x101b, 0x101b, 0x1012, 0x1012, 0x1012, 0x1012, ++ 0x100d, 0x100d, 0x100d, 0x100d, 0x1008, 0x1008, 0x1008, 0x1008, // 64 ++ 0x4001, 0x2035, 0x8060, 0x8062, 0x8064, 0x8066, 0x8068, 0x806a, ++ 0x203b, 0x2036, 0x2031, 0x2030, 0x2037, 0x2032, 0x202d, 0x202c, ++ 0x1833, 0x1833, 0x182e, 0x182e, 0x1829, 0x1829, 0x1828, 0x1828, ++ 0x182f, 0x182f, 0x182a, 0x182a, 0x1825, 0x1825, 0x1824, 0x1824, // 96 ++ 0x0040, 0x0042, 0x0041, 0x003c, 0x0043, 0x003e, 0x003d, 0x0038, // 104 ++ 0x003f, 0x003a, 0x0039, 0x0034, 0x0009, 0x0004, 0x4000, 0x4000, // 112 ++ 0x1020, 0x1026, 0x1021, 0x101c, 0x102b, 0x1022, 0x101d, 0x1018, // 120 ++ 0x0027, 0x001e, 0x0019, 0x0014, 0x0817, 0x080e, 0x0013, 0x0013, // 128 ++ }, ++ { // 1 ++ 0xa020, 0x8868, 0x806c, 0x806e, 0x8070, 0x8072, 0x2017, 0x2009, ++ 0x1813, 0x1813, 0x180f, 0x180f, 0x100a, 0x100a, 0x100a, 0x100a, ++ 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, 0x0805, ++ 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, ++ 0x9840, 0x9050, 0x8858, 0x885c, 0x8060, 0x8062, 0x8064, 0x8066, ++ 0x1827, 0x1827, 0x181e, 0x181e, 0x181d, 0x181d, 0x1818, 0x1818, ++ 0x1014, 0x1014, 0x1014, 0x1014, 0x101a, 0x101a, 0x101a, 0x101a, ++ 0x1019, 0x1019, 0x1019, 0x1019, 0x1010, 0x1010, 0x1010, 0x1010, ++ 0x4001, 0x4001, 0x103f, 0x103f, 0x1843, 0x1842, 0x1841, 0x1840, ++ 0x183d, 0x183c, 0x183e, 0x1839, 0x103a, 0x103a, 0x1038, 0x1038, ++ 0x103b, 0x1036, 0x1035, 0x1034, 0x1037, 0x1032, 0x1031, 0x1030, ++ 0x082c, 0x082e, 0x082d, 0x0828, 0x0833, 0x082a, 0x0829, 0x0824, ++ 0x002f, 0x0026, 0x0025, 0x0020, 0x002b, 0x0022, 0x0021, 0x001c, ++ 0x0823, 0x0816, 0x0815, 0x080c, 0x001f, 0x0012, 0x0011, 0x0008, ++ 0x001b, 0x000e, 0x000d, 0x0004, ++ }, ++ { // 2 ++ 0x9840, 0x9050, 0x8858, 0x885c, 0x8060, 0x8062, 0x8064, 0x8066, ++ 0x280c, 0x281e, 0x281d, 0x2808, 0x2827, 0x281a, 0x2819, 0x2804, ++ 0x2015, 0x2015, 0x2016, 0x2016, 0x2011, 0x2011, 0x2012, 0x2012, ++ 0x200d, 0x200d, 0x2023, 0x2023, 0x200e, 0x200e, 0x2009, 0x2009, ++ 0x181f, 0x181f, 0x181f, 0x181f, 0x181b, 0x181b, 0x181b, 0x181b, ++ 0x1817, 0x1817, 0x1817, 0x1817, 0x1813, 0x1813, 0x1813, 0x1813, ++ 0x180f, 0x180f, 0x180f, 0x180f, 0x180a, 0x180a, 0x180a, 0x180a, ++ 0x1805, 0x1805, 0x1805, 0x1805, 0x1800, 0x1800, 0x1800, 0x1800, ++ 0x4001, 0x1840, 0x1843, 0x1842, 0x1841, 0x183c, 0x183f, 0x183e, ++ 0x183d, 0x1838, 0x183b, 0x183a, 0x1839, 0x1834, 0x1035, 0x1035, ++ 0x1030, 0x1036, 0x1031, 0x102c, 0x1037, 0x1032, 0x102d, 0x1028, ++ 0x0833, 0x082e, 0x0829, 0x0824, 0x082f, 0x082a, 0x0825, 0x0820, ++ 0x001c, 0x0018, 0x0026, 0x0014, 0x002b, 0x0022, 0x0021, 0x0010, ++ }, ++ { // 3 ++ 0x2804, 0x2805, 0x4001, 0x2800, 0x2808, 0x2809, 0x280a, 0x4001, ++ 0x280c, 0x280d, 0x280e, 0x280f, 0x2810, 0x2811, 0x2812, 0x2813, ++ 0x2814, 0x2815, 0x2816, 0x2817, 0x2818, 0x2819, 0x281a, 0x281b, ++ 0x281c, 0x281d, 0x281e, 0x281f, 0x2820, 0x2821, 0x2822, 0x2823, ++ 0x2824, 0x2825, 0x2826, 0x2827, 0x2828, 0x2829, 0x282a, 0x282b, ++ 0x282c, 0x282d, 0x282e, 0x282f, 0x2830, 0x2831, 0x2832, 0x2833, ++ 0x2834, 0x2835, 0x2836, 0x2837, 0x2838, 0x2839, 0x283a, 0x283b, ++ 0x283c, 0x283d, 0x283e, 0x283f, 0x2840, 0x2841, 0x2842, 0x2843, ++ }, ++ { // 4 ++ 0x8840, 0x8044, 0x2810, 0x280c, 0x2808, 0x280f, 0x2809, 0x2804, ++ 0x100a, 0x100a, 0x100a, 0x100a, 0x100a, 0x100a, 0x100a, 0x100a, ++ 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, ++ 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, ++ 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, ++ 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, ++ 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, ++ 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, ++ 0x0013, 0x0013, 0x0812, 0x0811, 0x000e, 0x000d, ++ }, ++ { ++ 0x9040, 0x8048, 0x2808, 0x2807, 0x2006, 0x2006, 0x2005, 0x2005, ++ 0x1804, 0x1804, 0x1804, 0x1804, 0x1803, 0x1803, 0x1803, 0x1803, ++ 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, ++ 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x4001, 0x100f, 0x100e, 0x100d, 0x080c, 0x080c, 0x080b, 0x080b, ++ 0x000a, 0x0009, ++ }, ++ { ++ 0xa040, 0x2809, 0x2008, 0x2008, 0x1807, 0x1807, 0x1807, 0x1807, ++ 0x1006, 0x1006, 0x1006, 0x1006, 0x1006, 0x1006, 0x1006, 0x1006, ++ 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, 0x1005, ++ 0x1004, 0x1004, 0x1004, 0x1004, 0x1004, 0x1004, 0x1004, 0x1004, ++ 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, ++ 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, 0x1002, ++ 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, 0x1001, ++ 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, ++ 0x4001, 0x200e, 0x180d, 0x180d, 0x100c, 0x100c, 0x100c, 0x100c, ++ 0x080b, 0x080b, 0x080b, 0x080b, 0x080b, 0x080b, 0x080b, 0x080b, ++ 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, ++ 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, ++ }, ++}; ++ ++__place_k0_data__ char cabac_context_init_I[460][2] = ++{ ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28,127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 unsused for I */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, ++ ++ /* 24- 39 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ ++ /* 40 - 53 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, ++ ++ /* 54 - 59 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 -> 87 */ ++ { 0, 11 }, { 1, 55 }, { 0, 69 }, { -17, 127 }, ++ { -13, 102 },{ 0, 82 }, { -7, 74 }, { -21, 107 }, ++ { -27, 127 },{ -31, 127 },{ -24, 127 }, { -18, 95 }, ++ { -27, 127 },{ -21, 114 },{ -30, 127 }, { -17, 123 }, ++ { -12, 115 },{ -16, 122 }, ++ ++ /* 88 -> 104 */ ++ { -11, 115 },{ -12, 63 }, { -2, 68 }, { -15, 84 }, ++ { -13, 104 },{ -3, 70 }, { -8, 93 }, { -10, 90 }, ++ { -30, 127 },{ -1, 74 }, { -6, 97 }, { -7, 91 }, ++ { -20, 127 },{ -4, 56 }, { -5, 82 }, { -7, 76 }, ++ { -22, 125 }, ++ ++ /* 105 -> 135 */ ++ { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, ++ { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, ++ { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, ++ { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, ++ { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, ++ { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, ++ { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, ++ { 14, 62 }, { -13, 108 },{ -15, 100 }, ++ ++ /* 136 -> 165 */ ++ { -13, 101 },{ -13, 91 }, { -12, 94 }, { -10, 88 }, ++ { -16, 84 }, { -10, 86 }, { -7, 83 }, { -13, 87 }, ++ { -19, 94 }, { 1, 70 }, { 0, 72 }, { -5, 74 }, ++ { 18, 59 }, { -8, 102 }, { -15, 100 }, { 0, 95 }, ++ { -4, 75 }, { 2, 72 }, { -11, 75 }, { -3, 71 }, ++ { 15, 46 }, { -13, 69 }, { 0, 62 }, { 0, 65 }, ++ { 21, 37 }, { -15, 72 }, { 9, 57 }, { 16, 54 }, ++ { 0, 62 }, { 12, 72 }, ++ ++ /* 166 -> 196 */ ++ { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, ++ { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, ++ { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, ++ { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, ++ { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, ++ { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, ++ { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, ++ { 0, 89 }, { 26, -19 }, { 22, -17 }, ++ ++ /* 197 -> 226 */ ++ { 26, -17 }, { 30, -25 }, { 28, -20 }, { 33, -23 }, ++ { 37, -27 }, { 33, -23 }, { 40, -28 }, { 38, -17 }, ++ { 33, -11 }, { 40, -15 }, { 41, -6 }, { 38, 1 }, ++ { 41, 17 }, { 30, -6 }, { 27, 3 }, { 26, 22 }, ++ { 37, -16 }, { 35, -4 }, { 38, -8 }, { 38, -3 }, ++ { 37, 3 }, { 38, 5 }, { 42, 0 }, { 35, 16 }, ++ { 39, 22 }, { 14, 48 }, { 27, 37 }, { 21, 60 }, ++ { 12, 68 }, { 2, 97 }, ++ ++ /* 227 -> 251 */ ++ { -3, 71 }, { -6, 42 }, { -5, 50 }, { -3, 54 }, ++ { -2, 62 }, { 0, 58 }, { 1, 63 }, { -2, 72 }, ++ { -1, 74 }, { -9, 91 }, { -5, 67 }, { -5, 27 }, ++ { -3, 39 }, { -2, 44 }, { 0, 46 }, { -16, 64 }, ++ { -8, 68 }, { -10, 78 }, { -6, 77 }, { -10, 86 }, ++ { -12, 92 }, { -15, 55 }, { -10, 60 }, { -6, 62 }, ++ { -4, 65 }, ++ ++ /* 252 -> 275 */ ++ { -12, 73 }, { -8, 76 }, { -7, 80 }, { -9, 88 }, ++ { -17, 110 },{ -11, 97 }, { -20, 84 }, { -11, 79 }, ++ { -6, 73 }, { -4, 74 }, { -13, 86 }, { -13, 96 }, ++ { -11, 97 }, { -19, 117 },{ -8, 78 }, { -5, 33 }, ++ { -4, 48 }, { -2, 53 }, { -3, 62 }, { -13, 71 }, ++ { -10, 79 }, { -12, 86 }, { -13, 90 }, { -14, 97 }, ++ ++ /* 276 a bit special (not used, bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 -> 307 */ ++ { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, ++ { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, ++ { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, ++ { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, ++ { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, ++ { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, ++ { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, ++ { 9, 64 }, { -12, 104 },{ -11, 97 }, ++ ++ /* 308 -> 337 */ ++ { -16, 96 }, { -7, 88 }, { -8, 85 }, { -7, 85 }, ++ { -9, 85 }, { -13, 88 }, { 4, 66 }, { -3, 77 }, ++ { -3, 76 }, { -6, 76 }, { 10, 58 }, { -1, 76 }, ++ { -1, 83 }, { -7, 99 }, { -14, 95 }, { 2, 95 }, ++ { 0, 76 }, { -5, 74 }, { 0, 70 }, { -11, 75 }, ++ { 1, 68 }, { 0, 65 }, { -14, 73 }, { 3, 62 }, ++ { 4, 62 }, { -1, 68 }, { -13, 75 }, { 11, 55 }, ++ { 5, 64 }, { 12, 70 }, ++ ++ /* 338 -> 368 */ ++ { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, ++ { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, ++ { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, ++ { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, ++ { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, ++ { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, ++ { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, ++ { -12, 109 },{ 36, -35 }, { 36, -34 }, ++ ++ /* 369 -> 398 */ ++ { 32, -26 }, { 37, -30 }, { 44, -32 }, { 34, -18 }, ++ { 34, -15 }, { 40, -15 }, { 33, -7 }, { 35, -5 }, ++ { 33, 0 }, { 38, 2 }, { 33, 13 }, { 23, 35 }, ++ { 13, 58 }, { 29, -3 }, { 26, 0 }, { 22, 30 }, ++ { 31, -7 }, { 35, -15 }, { 34, -3 }, { 34, 3 }, ++ { 36, -1 }, { 34, 5 }, { 32, 11 }, { 35, 5 }, ++ { 34, 12 }, { 39, 11 }, { 30, 29 }, { 34, 26 }, ++ { 29, 39 }, { 19, 66 }, ++ ++ /* 399 -> 435 */ ++ { 31, 21 }, { 31, 31 }, { 25, 50 }, ++ { -17, 120 }, { -20, 112 }, { -18, 114 }, { -11, 85 }, ++ { -15, 92 }, { -14, 89 }, { -26, 71 }, { -15, 81 }, ++ { -14, 80 }, { 0, 68 }, { -14, 70 }, { -24, 56 }, ++ { -23, 68 }, { -24, 50 }, { -11, 74 }, { 23, -13 }, ++ { 26, -13 }, { 40, -15 }, { 49, -14 }, { 44, 3 }, ++ { 45, 6 }, { 44, 34 }, { 33, 54 }, { 19, 82 }, ++ { -3, 75 }, { -1, 23 }, { 1, 34 }, { 1, 43 }, ++ { 0, 54 }, { -2, 55 }, { 0, 61 }, { 1, 64 }, ++ { 0, 68 }, { -9, 92 }, ++ ++ /* 436 -> 459 */ ++ { -14, 106 }, { -13, 97 }, { -15, 90 }, { -12, 90 }, ++ { -18, 88 }, { -10, 73 }, { -9, 79 }, { -14, 86 }, ++ { -10, 73 }, { -10, 70 }, { -10, 69 }, { -5, 66 }, ++ { -9, 64 }, { -5, 58 }, { 2, 59 }, { 21, -10 }, ++ { 24, -11 }, { 28, -8 }, { 28, -1 }, { 29, 3 }, ++ { 29, 9 }, { 35, 20 }, { 29, 36 }, { 14, 67 } ++}; ++__place_k0_data__ char cabac_context_init_PB[3][460][2] = ++{ ++ /* i_cabac_init_idc == 0 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 23, 33 }, { 23, 2 }, { 21, 0 }, { 1, 9 }, ++ { 0, 49 }, { -37, 118 }, { 5, 57 }, { -13, 78 }, ++ { -11, 65 }, { 1, 62 }, { 12, 49 }, { -4, 73 }, ++ { 17, 50 }, ++ ++ /* 24 - 39 */ ++ { 18, 64 }, { 9, 43 }, { 29, 0 }, { 26, 67 }, ++ { 16, 90 }, { 9, 104 }, { -46, 127 }, { -20, 104 }, ++ { 1, 67 }, { -13, 78 }, { -11, 65 }, { 1, 62 }, ++ { -6, 86 }, { -17, 95 }, { -6, 61 }, { 9, 45 }, ++ ++ /* 40 - 53 */ ++ { -3, 69 }, { -6, 81 }, { -11, 96 }, { 6, 55 }, ++ { 7, 67 }, { -5, 86 }, { 2, 88 }, { 0, 58 }, ++ { -3, 76 }, { -10, 94 }, { 5, 54 }, { 4, 69 }, ++ { -3, 81 }, { 0, 88 }, ++ ++ /* 54 - 59 */ ++ { -7, 67 }, { -5, 74 }, { -4, 74 }, { -5, 80 }, ++ { -7, 72 }, { 1, 58 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 87 */ ++ { 0, 45 }, { -4, 78 }, { -3, 96 }, { -27, 126 }, ++ { -28, 98 }, { -25, 101 }, { -23, 67 }, { -28, 82 }, ++ { -20, 94 }, { -16, 83 }, { -22, 110 }, { -21, 91 }, ++ { -18, 102 }, { -13, 93 }, { -29, 127 }, { -7, 92 }, ++ { -5, 89 }, { -7, 96 }, { -13, 108 }, { -3, 46 }, ++ { -1, 65 }, { -1, 57 }, { -9, 93 }, { -3, 74 }, ++ { -9, 92 }, { -8, 87 }, { -23, 126 }, { 5, 54 }, ++ { 6, 60 }, { 6, 59 }, { 6, 69 }, { -1, 48 }, ++ { 0, 68 }, { -4, 69 }, { -8, 88 }, ++ ++ /* 105 -> 165 */ ++ { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, ++ { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, ++ { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, ++ { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, ++ { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, ++ { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, ++ { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, ++ { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, ++ { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, ++ { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, ++ { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, ++ { 3, 64 }, { 1, 61 }, { 9, 63 }, { 7, 50 }, ++ { 16, 39 }, { 5, 44 }, { 4, 52 }, { 11, 48 }, ++ { -5, 60 }, { -1, 59 }, { 0, 59 }, { 22, 33 }, ++ { 5, 44 }, { 14, 43 }, { -1, 78 }, { 0, 60 }, ++ { 9, 69 }, ++ ++ /* 166 - 226 */ ++ { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, ++ { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, ++ { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, ++ { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, ++ { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, ++ { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, ++ { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, ++ { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, ++ { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, ++ { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, ++ { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, ++ { 1, 67 }, { 5, 59 }, { 9, 67 }, { 16, 30 }, ++ { 18, 32 }, { 18, 35 }, { 22, 29 }, { 24, 31 }, ++ { 23, 38 }, { 18, 43 }, { 20, 41 }, { 11, 63 }, ++ { 9, 59 }, { 9, 64 }, { -1, 94 }, { -2, 89 }, ++ { -9, 108 }, ++ ++ /* 227 - 275 */ ++ { -6, 76 }, { -2, 44 }, { 0, 45 }, { 0, 52 }, ++ { -3, 64 }, { -2, 59 }, { -4, 70 }, { -4, 75 }, ++ { -8, 82 }, { -17, 102 }, { -9, 77 }, { 3, 24 }, ++ { 0, 42 }, { 0, 48 }, { 0, 55 }, { -6, 59 }, ++ { -7, 71 }, { -12, 83 }, { -11, 87 }, { -30, 119 }, ++ { 1, 58 }, { -3, 29 }, { -1, 36 }, { 1, 38 }, ++ { 2, 43 }, { -6, 55 }, { 0, 58 }, { 0, 64 }, ++ { -3, 74 }, { -10, 90 }, { 0, 70 }, { -4, 29 }, ++ { 5, 31 }, { 7, 42 }, { 1, 59 }, { -2, 58 }, ++ { -3, 72 }, { -3, 81 }, { -11, 97 }, { 0, 58 }, ++ { 8, 5 }, { 10, 14 }, { 14, 18 }, { 13, 27 }, ++ { 2, 40 }, { 0, 58 }, { -3, 70 }, { -6, 79 }, ++ { -8, 85 }, ++ ++ /* 276 a bit special (not used, bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, ++ { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, ++ { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, ++ { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, ++ { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, ++ { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, ++ { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, ++ { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, ++ { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, ++ { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, ++ { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, ++ { -2, 69 }, { -2, 59 }, { 6, 70 }, { 10, 44 }, ++ { 9, 31 }, { 12, 43 }, { 3, 53 }, { 14, 34 }, ++ { 10, 38 }, { -3, 52 }, { 13, 40 }, { 17, 32 }, ++ { 7, 44 }, { 7, 38 }, { 13, 50 }, { 10, 57 }, ++ { 26, 43 }, ++ ++ /* 338 - 398 */ ++ { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, ++ { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, ++ { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, ++ { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, ++ { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, ++ { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, ++ { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, ++ { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, ++ { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, ++ { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, ++ { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, ++ { 8, 60 }, { 6, 63 }, { 17, 65 }, { 21, 24 }, ++ { 23, 20 }, { 26, 23 }, { 27, 32 }, { 28, 23 }, ++ { 28, 24 }, { 23, 40 }, { 24, 32 }, { 28, 29 }, ++ { 23, 42 }, { 19, 57 }, { 22, 53 }, { 22, 61 }, ++ { 11, 86 }, ++ ++ /* 399 - 435 */ ++ { 12, 40 }, { 11, 51 }, { 14, 59 }, ++ { -4, 79 }, { -7, 71 }, { -5, 69 }, { -9, 70 }, ++ { -8, 66 }, { -10, 68 }, { -19, 73 }, { -12, 69 }, ++ { -16, 70 }, { -15, 67 }, { -20, 62 }, { -19, 70 }, ++ { -16, 66 }, { -22, 65 }, { -20, 63 }, { 9, -2 }, ++ { 26, -9 }, { 33, -9 }, { 39, -7 }, { 41, -2 }, ++ { 45, 3 }, { 49, 9 }, { 45, 27 }, { 36, 59 }, ++ { -6, 66 }, { -7, 35 }, { -7, 42 }, { -8, 45 }, ++ { -5, 48 }, { -12, 56 }, { -6, 60 }, { -5, 62 }, ++ { -8, 66 }, { -8, 76 }, ++ ++ /* 436 - 459 */ ++ { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, ++ { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, ++ { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, ++ { -14, 66 }, { 0, 59 }, { 2, 59 }, { 21, -13 }, ++ { 33, -14 }, { 39, -7 }, { 46, -2 }, { 51, 2 }, ++ { 60, 6 }, { 61, 17 }, { 55, 34 }, { 42, 62 }, ++ }, ++ ++ /* i_cabac_init_idc == 1 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 22, 25 }, { 34, 0 }, { 16, 0 }, { -2, 9 }, ++ { 4, 41 }, { -29, 118 }, { 2, 65 }, { -6, 71 }, ++ { -13, 79 }, { 5, 52 }, { 9, 50 }, { -3, 70 }, ++ { 10, 54 }, ++ ++ /* 24 - 39 */ ++ { 26, 34 }, { 19, 22 }, { 40, 0 }, { 57, 2 }, ++ { 41, 36 }, { 26, 69 }, { -45, 127 }, { -15, 101 }, ++ { -4, 76 }, { -6, 71 }, { -13, 79 }, { 5, 52 }, ++ { 6, 69 }, { -13, 90 }, { 0, 52 }, { 8, 43 }, ++ ++ /* 40 - 53 */ ++ { -2, 69 },{ -5, 82 },{ -10, 96 },{ 2, 59 }, ++ { 2, 75 },{ -3, 87 },{ -3, 100 },{ 1, 56 }, ++ { -3, 74 },{ -6, 85 },{ 0, 59 },{ -3, 81 }, ++ { -7, 86 },{ -5, 95 }, ++ ++ /* 54 - 59 */ ++ { -1, 66 },{ -1, 77 },{ 1, 70 },{ -2, 86 }, ++ { -5, 72 },{ 0, 61 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 104 */ ++ { 13, 15 }, { 7, 51 }, { 2, 80 }, { -39, 127 }, ++ { -18, 91 }, { -17, 96 }, { -26, 81 }, { -35, 98 }, ++ { -24, 102 }, { -23, 97 }, { -27, 119 }, { -24, 99 }, ++ { -21, 110 }, { -18, 102 }, { -36, 127 }, { 0, 80 }, ++ { -5, 89 }, { -7, 94 }, { -4, 92 }, { 0, 39 }, ++ { 0, 65 }, { -15, 84 }, { -35, 127 }, { -2, 73 }, ++ { -12, 104 }, { -9, 91 }, { -31, 127 }, { 3, 55 }, ++ { 7, 56 }, { 7, 55 }, { 8, 61 }, { -3, 53 }, ++ { 0, 68 }, { -7, 74 }, { -9, 88 }, ++ ++ /* 105 -> 165 */ ++ { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, ++ { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, ++ { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, ++ { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, ++ { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, ++ { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, ++ { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, ++ { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, ++ { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, ++ { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, ++ { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, ++ { -4, 71 }, { 0, 58 }, { 7, 61 }, { 9, 41 }, ++ { 18, 25 }, { 9, 32 }, { 5, 43 }, { 9, 47 }, ++ { 0, 44 }, { 0, 51 }, { 2, 46 }, { 19, 38 }, ++ { -4, 66 }, { 15, 38 }, { 12, 42 }, { 9, 34 }, ++ { 0, 89 }, ++ ++ /* 166 - 226 */ ++ { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, ++ { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, ++ { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, ++ { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, ++ { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, ++ { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, ++ { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, ++ { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, ++ { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, ++ { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, ++ { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, ++ { 0, 75 }, { 2, 72 }, { 8, 77 }, { 14, 35 }, ++ { 18, 31 }, { 17, 35 }, { 21, 30 }, { 17, 45 }, ++ { 20, 42 }, { 18, 45 }, { 27, 26 }, { 16, 54 }, ++ { 7, 66 }, { 16, 56 }, { 11, 73 }, { 10, 67 }, ++ { -10, 116 }, ++ ++ /* 227 - 275 */ ++ { -23, 112 }, { -15, 71 }, { -7, 61 }, { 0, 53 }, ++ { -5, 66 }, { -11, 77 }, { -9, 80 }, { -9, 84 }, ++ { -10, 87 }, { -34, 127 }, { -21, 101 }, { -3, 39 }, ++ { -5, 53 }, { -7, 61 }, { -11, 75 }, { -15, 77 }, ++ { -17, 91 }, { -25, 107 }, { -25, 111 }, { -28, 122 }, ++ { -11, 76 }, { -10, 44 }, { -10, 52 }, { -10, 57 }, ++ { -9, 58 }, { -16, 72 }, { -7, 69 }, { -4, 69 }, ++ { -5, 74 }, { -9, 86 }, { 2, 66 }, { -9, 34 }, ++ { 1, 32 }, { 11, 31 }, { 5, 52 }, { -2, 55 }, ++ { -2, 67 }, { 0, 73 }, { -8, 89 }, { 3, 52 }, ++ { 7, 4 }, { 10, 8 }, { 17, 8 }, { 16, 19 }, ++ { 3, 37 }, { -1, 61 }, { -5, 73 }, { -1, 70 }, ++ { -4, 78 }, ++ ++ /* 276 a bit special (not used, bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, ++ { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, ++ { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, ++ { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, ++ { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, ++ { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, ++ { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, ++ { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, ++ { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, ++ { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, ++ { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, ++ { -1, 70 }, { -9, 72 }, { 14, 60 }, { 16, 37 }, ++ { 0, 47 }, { 18, 35 }, { 11, 37 }, { 12, 41 }, ++ { 10, 41 }, { 2, 48 }, { 12, 41 }, { 13, 41 }, ++ { 0, 59 }, { 3, 50 }, { 19, 40 }, { 3, 66 }, ++ { 18, 50 }, ++ ++ /* 338 - 398 */ ++ { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, ++ { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, ++ { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, ++ { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, ++ { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, ++ { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, ++ { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, ++ { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, ++ { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, ++ { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, ++ { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, ++ { 12, 48 }, { 11, 49 }, { 26, 45 }, { 22, 22 }, ++ { 23, 22 }, { 27, 21 }, { 33, 20 }, { 26, 28 }, ++ { 30, 24 }, { 27, 34 }, { 18, 42 }, { 25, 39 }, ++ { 18, 50 }, { 12, 70 }, { 21, 54 }, { 14, 71 }, ++ { 11, 83 }, ++ ++ /* 399 - 435 */ ++ { 25, 32 }, { 21, 49 }, { 21, 54 }, ++ { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, ++ { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, ++ { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, ++ { -14, 66 }, { 0, 59 }, { 2, 59 }, { 17, -10 }, ++ { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, ++ { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, ++ { -5, 71 }, { 0, 24 }, { -1, 36 }, { -2, 42 }, ++ { -2, 52 }, { -9, 57 }, { -6, 63 }, { -4, 65 }, ++ { -4, 67 }, { -7, 82 }, ++ ++ /* 436 - 459 */ ++ { -3, 81 }, { -3, 76 }, { -7, 72 }, { -6, 78 }, ++ { -12, 72 }, { -14, 68 }, { -3, 70 }, { -6, 76 }, ++ { -5, 66 }, { -5, 62 }, { 0, 57 }, { -4, 61 }, ++ { -9, 60 }, { 1, 54 }, { 2, 58 }, { 17, -10 }, ++ { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, ++ { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, ++ }, ++ ++ /* i_cabac_init_idc == 2 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 29, 16 }, { 25, 0 }, { 14, 0 }, { -10, 51 }, ++ { -3, 62 }, { -27, 99 }, { 26, 16 }, { -4, 85 }, ++ { -24, 102 }, { 5, 57 }, { 6, 57 }, { -17, 73 }, ++ { 14, 57 }, ++ ++ /* 24 - 39 */ ++ { 20, 40 }, { 20, 10 }, { 29, 0 }, { 54, 0 }, ++ { 37, 42 }, { 12, 97 }, { -32, 127 }, { -22, 117 }, ++ { -2, 74 }, { -4, 85 }, { -24, 102 }, { 5, 57 }, ++ { -6, 93 }, { -14, 88 }, { -6, 44 }, { 4, 55 }, ++ ++ /* 40 - 53 */ ++ { -11, 89 },{ -15, 103 },{ -21, 116 },{ 19, 57 }, ++ { 20, 58 },{ 4, 84 },{ 6, 96 },{ 1, 63 }, ++ { -5, 85 },{ -13, 106 },{ 5, 63 },{ 6, 75 }, ++ { -3, 90 },{ -1, 101 }, ++ ++ /* 54 - 59 */ ++ { 3, 55 },{ -4, 79 },{ -2, 75 },{ -12, 97 }, ++ { -7, 50 },{ 1, 60 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 104 */ ++ { 7, 34 }, { -9, 88 }, { -20, 127 }, { -36, 127 }, ++ { -17, 91 }, { -14, 95 }, { -25, 84 }, { -25, 86 }, ++ { -12, 89 }, { -17, 91 }, { -31, 127 }, { -14, 76 }, ++ { -18, 103 }, { -13, 90 }, { -37, 127 }, { 11, 80 }, ++ { 5, 76 }, { 2, 84 }, { 5, 78 }, { -6, 55 }, ++ { 4, 61 }, { -14, 83 }, { -37, 127 }, { -5, 79 }, ++ { -11, 104 }, { -11, 91 }, { -30, 127 }, { 0, 65 }, ++ { -2, 79 }, { 0, 72 }, { -4, 92 }, { -6, 56 }, ++ { 3, 68 }, { -8, 71 }, { -13, 98 }, ++ ++ /* 105 -> 165 */ ++ { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, ++ { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, ++ { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, ++ { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, ++ { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, ++ { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, ++ { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, ++ { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, ++ { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, ++ { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, ++ { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, ++ { 3, 65 }, { -7, 69 }, { 8, 77 }, { -10, 66 }, ++ { 3, 62 }, { -3, 68 }, { -20, 81 }, { 0, 30 }, ++ { 1, 7 }, { -3, 23 }, { -21, 74 }, { 16, 66 }, ++ { -23, 124 }, { 17, 37 }, { 44, -18 }, { 50, -34 }, ++ { -22, 127 }, ++ ++ /* 166 - 226 */ ++ { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, ++ { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, ++ { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, ++ { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, ++ { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, ++ { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, ++ { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, ++ { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, ++ { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, ++ { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, ++ { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, ++ { 20, 34 }, { 19, 31 }, { 27, 44 }, { 19, 16 }, ++ { 15, 36 }, { 15, 36 }, { 21, 28 }, { 25, 21 }, ++ { 30, 20 }, { 31, 12 }, { 27, 16 }, { 24, 42 }, ++ { 0, 93 }, { 14, 56 }, { 15, 57 }, { 26, 38 }, ++ { -24, 127 }, ++ ++ /* 227 - 275 */ ++ { -24, 115 }, { -22, 82 }, { -9, 62 }, { 0, 53 }, ++ { 0, 59 }, { -14, 85 }, { -13, 89 }, { -13, 94 }, ++ { -11, 92 }, { -29, 127 }, { -21, 100 }, { -14, 57 }, ++ { -12, 67 }, { -11, 71 }, { -10, 77 }, { -21, 85 }, ++ { -16, 88 }, { -23, 104 }, { -15, 98 }, { -37, 127 }, ++ { -10, 82 }, { -8, 48 }, { -8, 61 }, { -8, 66 }, ++ { -7, 70 }, { -14, 75 }, { -10, 79 }, { -9, 83 }, ++ { -12, 92 }, { -18, 108 }, { -4, 79 }, { -22, 69 }, ++ { -16, 75 }, { -2, 58 }, { 1, 58 }, { -13, 78 }, ++ { -9, 83 }, { -4, 81 }, { -13, 99 }, { -13, 81 }, ++ { -6, 38 }, { -13, 62 }, { -6, 58 }, { -2, 59 }, ++ { -16, 73 }, { -10, 76 }, { -13, 86 }, { -9, 83 }, ++ { -10, 87 }, ++ ++ /* 276 a bit special (not used, bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, ++ { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, ++ { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, ++ { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, ++ { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, ++ { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, ++ { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, ++ { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, ++ { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, ++ { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, ++ { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, ++ { -2, 76 }, { -18, 86 }, { 12, 70 }, { 5, 64 }, ++ { -12, 70 }, { 11, 55 }, { 5, 56 }, { 0, 69 }, ++ { 2, 65 }, { -6, 74 }, { 5, 54 }, { 7, 54 }, ++ { -6, 76 }, { -11, 82 }, { -2, 77 }, { -2, 77 }, ++ { 25, 42 }, ++ ++ /* 338 - 398 */ ++ { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, ++ { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, ++ { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, ++ { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, ++ { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, ++ { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, ++ { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, ++ { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, ++ { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, ++ { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, ++ { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, ++ { 18, 31 }, { 19, 26 }, { 36, 24 }, { 24, 23 }, ++ { 27, 16 }, { 24, 30 }, { 31, 29 }, { 22, 41 }, ++ { 22, 42 }, { 16, 60 }, { 15, 52 }, { 14, 60 }, ++ { 3, 78 }, { -16, 123 }, { 21, 53 }, { 22, 56 }, ++ { 25, 61 }, ++ ++ /* 399 - 435 */ ++ { 21, 33 }, { 19, 50 }, { 17, 61 }, ++ { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, ++ { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, ++ { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, ++ { -14, 59 }, { -9, 52 }, { -11, 68 }, { 9, -2 }, ++ { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, ++ { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, ++ { -9, 71 }, { -7, 37 }, { -8, 44 }, { -11, 49 }, ++ { -10, 56 }, { -12, 59 }, { -8, 63 }, { -9, 67 }, ++ { -6, 68 }, { -10, 79 }, ++ ++ /* 436 - 459 */ ++ { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, ++ { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, ++ { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, ++ { -14, 59 }, { -9, 52 }, { -11, 68 }, { 9, -2 }, ++ { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, ++ { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, ++ } ++}; ++ ++ ++ ++static inline int jzm_clip2(int a, int min, int max) ++{ ++ if (a < min) return min; ++ else if (a > max) return max; ++ else return a; ++} ++ ++void jzm_h264_slice_init_vdma(struct JZM_H264 * st_h264) ++{ ++ int i, j; ++ volatile unsigned int *chn = (volatile unsigned int *)st_h264->des_va; ++ ++ /*------------------------------------------------------ ++ scheduler ++ ------------------------------------------------------*/ ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, 0x0); ++ if (st_h264->slice_type == JZM_H264_I_TYPE) { ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, SCH_CH3_HID(HID_DBLK) | SCH_CH2_HID(HID_VMAU) | SCH_DEPTH(DESP_FIFO_WIDTH)); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHG0, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE1, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE2, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE3, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE4, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, SCH_CH2_PE | SCH_CH3_PE); ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, SCH_CH3_HID(HID_DBLK) | SCH_CH2_HID(HID_VMAU) | ++ SCH_DEPTH(DESP_FIFO_WIDTH) | SCH_BND_G0F2 | SCH_BND_G0F3); ++ } else { ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, SCH_CH3_HID(HID_DBLK) | SCH_CH2_HID(HID_VMAU) | SCH_CH1_HID(HID_MCE) | ++ SCH_DEPTH(DESP_FIFO_WIDTH)); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHG0, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE1, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE2, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE3, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE4, 0, 0x0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, SCH_CH1_PE | SCH_CH2_PE | SCH_CH3_PE); ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, SCH_CH3_HID(HID_DBLK) | SCH_CH2_HID(HID_VMAU) | SCH_CH1_HID(HID_MCE) | ++ SCH_DEPTH(DESP_FIFO_WIDTH) | SCH_BND_G0F1 | SCH_BND_G0F2 | SCH_BND_G0F3); ++ } ++ ++ /*------------------------------------------------------ ++ vmau ++ ------------------------------------------------------*/ ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_RUN, 0, VMAU_RESET); ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_CTR, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_VMAU_VIDEO_TYPE, 0, VMAU_FMT_H264); ++ GEN_VDMA_ACFG(chn, REG_VMAU_NCCHN_ADDR, 0, VMAU_DESP_ADDR); ++ GEN_VDMA_ACFG(chn, REG_VMAU_DEC_DONE, 0, VPU_BASE + REG_SCH_SCHE2); ++ GEN_VDMA_ACFG(chn, REG_VMAU_Y_GS, 0, st_h264->mb_width*16); ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_CTR, 0, (VMAU_CTRL_FIFO_M | VMAU_CTRL_TO_DBLK)); ++ GEN_VDMA_ACFG(chn, REG_VMAU_POS, 0, ((st_h264->start_mb_x & 0xff) | ((st_h264->start_mb_y & 0xff)<<16))); ++ unsigned int qt_ram_addr = REG_VMAU_QT; ++ unsigned int *tbl_ptr = (unsigned int *)st_h264->scaling_matrix8; ++ for ( i = 0 ; i < 32; i++) { ++ GEN_VDMA_ACFG(chn, (qt_ram_addr+i*4), 0, tbl_ptr[i]); ++ } ++ qt_ram_addr = REG_VMAU_QT + 32*4; ++ tbl_ptr = (unsigned int *)st_h264->scaling_matrix4; ++ for ( i = 0 ; i < 24; i++) { ++ GEN_VDMA_ACFG(chn, (qt_ram_addr+i*4), 0, tbl_ptr[i]); ++ } ++ ++ /*------------------------------------------------------ ++ dblk ++ ------------------------------------------------------*/ ++ GEN_VDMA_ACFG(chn, REG_DBLK_TRIG, 0, DBLK_RESET); ++ GEN_VDMA_ACFG(chn, REG_DBLK_DHA, 0, DBLK_DESP_ADDR); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GENDA, 0, VPU_BASE + REG_SCH_SCHE3); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GSIZE, 0, st_h264->mb_width | (st_h264->mb_height << 16)); ++ int normal_first_slice = (st_h264->start_mb_x == 0) && (st_h264->start_mb_y == 0); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPOS, 0, ((st_h264->start_mb_x & 0x3ff) | ++ ((st_h264->start_mb_y & 0x3ff)<<16) | ++ ((!normal_first_slice)<<31)) ++ ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_YA, 0, st_h264->dec_result_y); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_CA, 0, st_h264->dec_result_uv); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GP_ENDA, 0, DBLK_GP_ENDF_BASE); ++#define DEBLK_VTR_FMT_I 0 ++#define DEBLK_VTR_FMT_P (1<<3) ++#define DEBLK_VTR_FMT_B (2<<3) ++#define DEBLK_VTR_BETA_SFT (16) ++#define DEBLK_VTR_BETA_MSK (0xff) ++#define DEBLK_VTR_ALPHA_SFT (24) ++#define DEBLK_VTR_ALPHA_MSK (0xff) ++ unsigned int h264_vtr = ((st_h264->slice_type == JZM_H264_I_TYPE) ? DEBLK_VTR_FMT_I : ++ ((st_h264->slice_type == JZM_H264_P_TYPE) ? DEBLK_VTR_FMT_P : DEBLK_VTR_FMT_B) ++ ) | DBLK_FMT_H264; ++ h264_vtr = h264_vtr | ((st_h264->slice_beta_offset & DEBLK_VTR_BETA_MSK) << DEBLK_VTR_BETA_SFT) ++ | ((st_h264->slice_alpha_c0_offset & DEBLK_VTR_ALPHA_MSK) << DEBLK_VTR_ALPHA_SFT); ++ GEN_VDMA_ACFG(chn, REG_DBLK_VTR, 0, h264_vtr); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_STR, 0, (st_h264->mb_width*256) | (st_h264->mb_width*128)<<16); ++ ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_Y1A, 0, st_h264->dec_result1_y); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_C1A, 0, st_h264->dec_result1_uv); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_STR1, 0, (st_h264->frm_y_stride) | (st_h264->frm_c_stride)<<16); ++ GEN_VDMA_ACFG(chn, REG_DBLK_CTRL, 0, 0x1 | (st_h264->new_odma_flag)<<6 | (st_h264->new_odma_format)<<7 | (0<<8) | (1 << 9)); ++ ++ GEN_VDMA_ACFG(chn, REG_DBLK_TRIG, 0, DBLK_SLICE_RUN); ++ //GEN_VDMA_ACFG(chn, REG_DBLK_CTRL, 0, 0x1); ++ //write_reg(DBLK_GP_ENDF_BASE, -1); ++ ++ /*------------------------------------------------------ ++ motion ++ ------------------------------------------------------*/ ++ //video_motion_init(H264_QPEL, H264_EPEL); ++ int intpid = H264_QPEL; ++ int cintpid = H264_EPEL; ++ for(i=0; i<16; i++){ ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_ILUT+i*8, 0, ++ MCE_CH1_IINFO(IntpFMT[intpid][i].intp[0],/*intp1*/ ++ IntpFMT[intpid][i].tap,/*tap*/ ++ IntpFMT[intpid][i].intp_pkg[0],/*intp1_pkg*/ ++ IntpFMT[intpid][i].hldgl,/*hldgl*/ ++ IntpFMT[intpid][i].avsdgl,/*avsdgl*/ ++ IntpFMT[intpid][i].intp_dir[0],/*intp0_dir*/ ++ IntpFMT[intpid][i].intp_rnd[0],/*intp0_rnd*/ ++ IntpFMT[intpid][i].intp_sft[0],/*intp0_sft*/ ++ IntpFMT[intpid][i].intp_sintp[0],/*sintp0*/ ++ IntpFMT[intpid][i].intp_srnd[0],/*sintp0_rnd*/ ++ IntpFMT[intpid][i].intp_sbias[0]/*sintp0_bias*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_ILUT+i*8+4, 0, ++ MCE_CH1_IINFO(IntpFMT[intpid][i].intp[1],/*intp1*/ ++ 0,/*tap*/ ++ IntpFMT[intpid][i].intp_pkg[1],/*intp1_pkg*/ ++ IntpFMT[intpid][i].hldgl,/*hldgl*/ ++ IntpFMT[intpid][i].avsdgl,/*avsdgl*/ ++ IntpFMT[intpid][i].intp_dir[1],/*intp1_dir*/ ++ IntpFMT[intpid][i].intp_rnd[1],/*intp1_rnd*/ ++ IntpFMT[intpid][i].intp_sft[1],/*intp1_sft*/ ++ IntpFMT[intpid][i].intp_sintp[1],/*sintp1*/ ++ IntpFMT[intpid][i].intp_srnd[1],/*sintp1_rnd*/ ++ IntpFMT[intpid][i].intp_sbias[1]/*sintp1_bias*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_CLUT+i*8+4, 0, ++ MCE_RLUT_WT(IntpFMT[intpid][i].intp_coef[0][7],/*coef8*/ ++ IntpFMT[intpid][i].intp_coef[0][6],/*coef7*/ ++ IntpFMT[intpid][i].intp_coef[0][5],/*coef6*/ ++ IntpFMT[intpid][i].intp_coef[0][4]/*coef5*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_CLUT+i*8, 0, ++ MCE_RLUT_WT(IntpFMT[intpid][i].intp_coef[0][3],/*coef8*/ ++ IntpFMT[intpid][i].intp_coef[0][2],/*coef7*/ ++ IntpFMT[intpid][i].intp_coef[0][1],/*coef6*/ ++ IntpFMT[intpid][i].intp_coef[0][0]/*coef5*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_CLUT+(i+16)*8+4, 0, ++ MCE_RLUT_WT(IntpFMT[intpid][i].intp_coef[1][7],/*coef8*/ ++ IntpFMT[intpid][i].intp_coef[1][6],/*coef7*/ ++ IntpFMT[intpid][i].intp_coef[1][5],/*coef6*/ ++ IntpFMT[intpid][i].intp_coef[1][4]/*coef5*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_CLUT+(i+16)*8, 0, ++ MCE_RLUT_WT(IntpFMT[intpid][i].intp_coef[1][3],/*coef8*/ ++ IntpFMT[intpid][i].intp_coef[1][2],/*coef7*/ ++ IntpFMT[intpid][i].intp_coef[1][1],/*coef6*/ ++ IntpFMT[intpid][i].intp_coef[1][0]/*coef5*/ ++ )); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_ILUT+i*8, 0, ++ MCE_CH2_IINFO(IntpFMT[cintpid][i].intp[0], ++ IntpFMT[cintpid][i].intp_dir[0], ++ IntpFMT[cintpid][i].intp_sft[0], ++ IntpFMT[cintpid][i].intp_coef[0][0], ++ IntpFMT[cintpid][i].intp_coef[0][1], ++ IntpFMT[cintpid][i].intp_rnd[0]) ); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_ILUT+i*8+4, 0, ++ MCE_CH2_IINFO(IntpFMT[cintpid][i].intp[1], ++ IntpFMT[cintpid][i].intp_dir[1], ++ IntpFMT[cintpid][i].intp_sft[1], ++ IntpFMT[cintpid][i].intp_coef[1][0], ++ IntpFMT[cintpid][i].intp_coef[1][1], ++ IntpFMT[cintpid][i].intp_rnd[1]) ); ++ } ++#define STAT_PFE_SFT 2 ++#define STAT_PFE_MSK 0x1 ++#define STAT_LKE_SFT 1 ++#define STAT_LKE_MSK 0x1 ++#define STAT_TKE_SFT 0 ++#define STAT_TKE_MSK 0x1 ++#define MCE_PRI (0x3 << 9) ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_STAT, 0, ((1 & STAT_PFE_MSK )<luma_weight[0][i], st_h264->luma_offset[0][i])); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_RLUT+(i)*8+4, 0, st_h264->mc_ref_y[0][i]); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_RLUT+(i)*8, 0, MCE_RLUT_WT(st_h264->chroma_weight[0][i][1], st_h264->chroma_offset[0][i][1], ++ st_h264->chroma_weight[0][i][0], st_h264->chroma_offset[0][i][0])); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_RLUT+(i)*8+4, 0, st_h264->mc_ref_c[0][i]); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_RLUT+(16+i)*8, 0, MCE_RLUT_WT(0,0,st_h264->luma_weight[1][i], st_h264->luma_offset[1][i])); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_RLUT+(16+i)*8+4, 0, st_h264->mc_ref_y[1][i]); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_RLUT+(16+i)*8, 0, MCE_RLUT_WT(st_h264->chroma_weight[1][i][1], st_h264->chroma_offset[1][i][1], ++ st_h264->chroma_weight[1][i][0], st_h264->chroma_offset[1][i][0])); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_RLUT+(16+i)*8+4, 0, st_h264->mc_ref_c[1][i]); ++ } ++ ++ for(j=0; j<16; j++){ ++ for(i=0; i<16; i+=4){ ++ GEN_VDMA_ACFG(chn, (MOTION_IWTA_BASE+j*16+i), 0, *((int*)(&st_h264->implicit_weight[j][i]))); ++ } ++ } ++ GEN_VDMA_ACFG(chn, REG_MCE_IWTA, 0, MOTION_IWTA_BASE); ++ ++ GEN_VDMA_ACFG(chn, (REG_MCE_CH1_WINFO), 0, MCE_WINFO(0, (st_h264->use_weight == IS_WT1), ++ st_h264->use_weight, 1, st_h264->luma_log2_weight_denom, 5, 0, 0)); ++ GEN_VDMA_ACFG(chn, (REG_MCE_CH1_WTRND), 0, MCE_WTRND(0, 1<<5)); ++ GEN_VDMA_ACFG(chn, (REG_MCE_CH2_WINFO1), 0, MCE_WINFO(0, st_h264->use_weight_chroma && (st_h264->use_weight == IS_WT1), ++ st_h264->use_weight, 1, st_h264->chroma_log2_weight_denom, 5, 0, 0)); ++ GEN_VDMA_ACFG(chn, (REG_MCE_CH2_WINFO2), 0, MCE_WINFO(0, 0, 0, 0, 0, 5, 0, 0)); ++ GEN_VDMA_ACFG(chn, (REG_MCE_CH2_WTRND), 0, MCE_WTRND(1<<5, 1<<5)); ++ ++ GEN_VDMA_ACFG(chn, REG_MCE_CH1_STRD, 0, MCE_STRD(st_h264->mb_width*16, 0, DOUT_Y_STRD)); ++ GEN_VDMA_ACFG(chn, REG_MCE_GEOM, 0, MCE_GEOM(st_h264->mb_height*16,st_h264->mb_width*16)); ++ GEN_VDMA_ACFG(chn, REG_MCE_CH2_STRD, 0, MCE_STRD(st_h264->mb_width*16, 0, DOUT_C_STRD)); ++ GEN_VDMA_ACFG(chn, REG_MCE_DSA, 0, VPU_BASE + REG_SCH_SCHE1); ++ GEN_VDMA_ACFG(chn, REG_MCE_DDC, 0, MC_DESP_ADDR); ++ ++ /*------------------------------------------------------ ++ sde ++ ------------------------------------------------------*/ ++ // multi-slice ++#if 0 ++ int start_mb_num= st_h264->start_mb_x + st_h264->start_mb_y * st_h264->mb_width; ++ int slice_start_mx = st_h264->start_mb_x; ++ int slice_start_my = st_h264->start_mb_y; ++ if (st_h264->slice_num == 0) { ++ for (i=0; i<32; i++) ++ st_h264->curr_frm_slice_start_mb[i] = INT_MAX; ++ } ++ int ref_frm_start_mb = 0; ++ if ( (st_h264->slice_type == JZM_H264_B_TYPE) && (st_h264->slice_num)) { ++ for (i=0; i<32; i++){ ++ if ( (start_mb_num >= st_h264->ref_frm_slice_start_mb[i]) && ++ (start_mb_num < st_h264->ref_frm_slice_start_mb[i+1]) ) ++ break; ++ } ++ ref_frm_start_mb = st_h264->ref_frm_slice_start_mb[i]; ++ } ++ st_h264->curr_frm_slice_start_mb[st_h264->slice_num] = start_mb_num; ++#else ++ int start_mb_num = st_h264->start_mb_x + st_h264->start_mb_y * st_h264->mb_width; ++ int slice_start_mx = st_h264->start_mb_x; ++ int slice_start_my = st_h264->start_mb_y; ++ int ref_frm_start_mb = start_mb_num; ++#endif ++ ++ // bs init ++ unsigned int bs_addr = st_h264->bs_buffer; ++ unsigned int bs_ofst = st_h264->bs_index; ++#if 0 ++ for (i=0; imb_height,st_h264->mb_width,slice_start_my,slice_start_mx)); ++ GEN_VDMA_ACFG(chn, REG_SDE_GL_CTRL, 0, 1); ++ GEN_VDMA_ACFG(chn, REG_SDE_CODEC_ID, 0, (1 << 0)); ++ unsigned int cfg_0 = (((!st_h264->cabac) << 0) + ++ (((st_h264->slice_type) & 0x7) << 1) + ++ (((st_h264->field_picture) & 0x1) << 4) + ++ (((st_h264->transform_8x8_mode) & 0x1) << 5) + ++ (((st_h264->constrained_intra_pred) & 0x1) << 6) + ++ (((st_h264->direct_8x8_inference_flag) & 0x1) << 7) + ++ (((st_h264->direct_spatial_mv_pred) & 0x1) << 8) + ++ ((1 & 0x1) << 9) + /*dir_max_word_64*/ ++ (((st_h264->x264_build > 33) & 0x1) << 10) + ++ (((!st_h264->x264_build) & 0x1) << 11) + ++ ((st_h264->dblk_left_en & 0x1) << 14) + ++ ((st_h264->dblk_top_en & 0x1) << 15) + ++ ((st_h264->ref_count_0 & 0xF) << 16) + ++ ((st_h264->ref_count_1 & 0xF) << 20) + ++ ((bs_ofst & 0x1F) << 24) + ++ 0 ); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG0, 0, cfg_0); ++ unsigned int cfg_1 = (((st_h264->qscale & 0xFF) << 0) + ++ (((st_h264->deblocking_filter) & 0x1) << 8) + ++ 0); ++ //GEN_VDMA_ACFG(chn, REG_SDE_CFG1, 0, cfg_1 ); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG1, 0, (cfg_1 + ++ ((st_h264->bs_rbsp_en & 0x1) << 16)) ); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG2, 0, bs_addr); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG3, 0, TOP_NEI_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG4, 0, RESIDUAL_DOUT_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG5, 0, VMAU_DESP_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG6, 0, DBLK_DESP_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG7, 0, DBLK_MV_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG8, 0, MC_DESP_ADDR); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG9, 0, st_h264->ref_frm_ctrl + ref_frm_start_mb*2*4); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG10, 0, st_h264->ref_frm_mv + ref_frm_start_mb*32*4); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG11, 0, st_h264->curr_frm_ctrl + start_mb_num*2*4); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG12, 0, st_h264->curr_frm_mv + start_mb_num*32*4); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG13, 0, (start_mb_num & 0xFFFF) + (((start_mb_num - ref_frm_start_mb) & 0xFFFF) << 16)); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG14, 0, st_h264->bs_size_in_bits); ++ ++ // ctx table init ++ unsigned int * sde_table_base = REG_SDE_CTX_TBL; ++ if (st_h264->cabac) { ++ unsigned char state; ++ for( i= 0; i < 460; i++ ) { ++ int pre; ++ if( st_h264->slice_type == JZM_H264_I_TYPE ) ++ pre = jzm_clip2( ((cabac_context_init_I[i][0] * st_h264->qscale) >>4 ) + cabac_context_init_I[i][1], 1, 126 ); ++ else ++ pre = jzm_clip2( ((cabac_context_init_PB[st_h264->cabac_init_idc][i][0] * st_h264->qscale) >>4 ) + cabac_context_init_PB[st_h264->cabac_init_idc][i][1], 1, 126 ); ++ if( pre <= 63 ) ++ state = 2 * ( 63 - pre ) + 0; ++ else ++ state = 2 * ( pre - 64 ) + 1; ++ GEN_VDMA_ACFG(chn, sde_table_base+i, 0, lps_comb[state]); ++ } ++ GEN_VDMA_ACFG(chn, sde_table_base+276, 0, lps_comb[126]); ++ } else { ++ int tbl; ++ for (tbl = 0; tbl < 7; tbl++) { ++ unsigned int * hw_base = sde_table_base + (sde_vlc2_sta[tbl].ram_ofst >> 1); ++ unsigned int * tbl_base = (unsigned int *)&sde_vlc2_table[tbl][0]; ++ int size = (sde_vlc2_sta[tbl].size + 1) >> 1; ++ for (i = 0; i < size; i++){ ++ GEN_VDMA_ACFG(chn, hw_base+i, 0, tbl_base[i]); ++ } ++ } ++ } ++ // direct prediction scal table ++ for (i=0; i<16; i++) { ++ GEN_VDMA_ACFG(chn, sde_table_base + 480 + i, 0, st_h264->dir_scale_table[i]); ++ } ++ // set chroma_qp table ++ unsigned int * sde_cqp_tbl = REG_SDE_CQP_TBL; ++ for(i=0;i<128;i++) { ++ GEN_VDMA_ACFG(chn, sde_cqp_tbl + i, 0, st_h264->chroma_qp_table[i]); ++ } ++ ++ GEN_VDMA_ACFG(chn, (REG_SDE_SL_CTRL), VDMA_ACFG_TERM, SDE_MB_RUN); ++} ++ ++#endif // _JZM_H264_API_C_ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_h264_dec.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_h264_dec.h +new file mode 100644 +index 000000000..e8943f8b2 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_h264_dec.h +@@ -0,0 +1,125 @@ ++#ifndef _JZM_H264_API_H_ ++#define _JZM_H264_API_H_ ++ ++#include "jzm_vpu.h" ++ ++/*-------------- vmem def --------------*/ ++#define VRAM_TCSM1_BASE (VPU_BASE + 0xC0000) ++#define VRAM_SRAM_BASE (VPU_BASE + 0xF0000) ++#ifdef JZM_SIMPLE ++#define DESP_FIFO_WIDTH 3 ++#else ++#define DESP_FIFO_WIDTH 4 ++#endif //JZM_SIMPLE ++#define DESP_FIFO_DEPTH (1 << DESP_FIFO_WIDTH) ++#define VRAM_SCH_FIFO_DEPTH DESP_FIFO_DEPTH ++#define TOP_NEI_ADDR (VRAM_TCSM1_BASE) ++#ifdef JZM_SIMPLE ++#define TOP_NEI_SIZE (80*16*4) ++#else ++#define TOP_NEI_SIZE (128*16*4) ++#endif //JZM_SIMPLE ++#define MC_DESP_ADDR (TOP_NEI_ADDR + TOP_NEI_SIZE) ++#define MC_DESP_ONE_SIZE (128*4) ++#define MC_DESP_SIZE (MC_DESP_ONE_SIZE*DESP_FIFO_DEPTH) ++#define DBLK_MV_ADDR (MC_DESP_ADDR + MC_DESP_SIZE) ++#define DBLK_MV_ONE_SIZE (64*4) ++#define DBLK_MV_SIZE (DBLK_MV_ONE_SIZE*DESP_FIFO_DEPTH) ++#define VMAU_DESP_ADDR (DBLK_MV_ADDR + DBLK_MV_SIZE) ++#define VMAU_DESP_ONE_SIZE (16*4) ++#define VMAU_DESP_SIZE (VMAU_DESP_ONE_SIZE*DESP_FIFO_DEPTH) ++#define DBLK_DESP_ADDR (VMAU_DESP_ADDR + VMAU_DESP_SIZE) ++#define DBLK_DESP_ONE_SIZE (8*4) ++#define DBLK_DESP_SIZE (DBLK_DESP_ONE_SIZE*DESP_FIFO_DEPTH) ++#define MOTION_IWTA_BASE ((DBLK_DESP_ADDR+DBLK_DESP_SIZE + 1024) & 0xFFFFFC00) ++#define MOTION_IWTA_SIZE (2048) ++#define MOTION_DSA_BASE (MOTION_IWTA_BASE + MOTION_IWTA_SIZE) ++#define MAU_ENDF_BASE (MOTION_DSA_BASE+4)//(MAU_SRC_BASE + MAU_SRC_SIZE) ++#define DBLK_ENDF_BASE ( MAU_ENDF_BASE + 4 ) ++#define DBLK_GP_ENDF_BASE ( DBLK_ENDF_BASE + 4 ) ++#define TCSM1_END (MAU_SRC_BASE+MAU_SRC_SIZE) ++#define RESIDUAL_DOUT_ADDR (VRAM_SRAM_BASE) ++#define RESIDUAL_DOUT_ONE_SIZE (256*4) ++#define RESIDUAL_DOUT_SIZE (RESIDUAL_DOUT_ONE_SIZE*DESP_FIFO_DEPTH) ++#define SRAM_END (RESIDUAL_DOUT_ADDR+RESIDUAL_DOUT_SIZE) ++#define PMON_BUF (SRAM_END) ++ ++/*----------------------------*/ ++#define JZM_H264_I_TYPE 1 ++#define JZM_H264_P_TYPE 2 ++#define JZM_H264_B_TYPE 4 ++ ++#define ROA_ALN 256 ++#define DOUT_Y_STRD 16 ++#define DOUT_C_STRD 8 ++ ++typedef struct JZM_H264{ ++ unsigned short start_mb_x; ++ unsigned short start_mb_y; ++ unsigned short mb_width; ++ unsigned short mb_height; ++ unsigned char slice_num; ++ unsigned char slice_type; ++ unsigned char qscale; /* s->qscale */ ++ unsigned char field_picture; ++ unsigned char cabac; /* h->pps.cabac */ ++ unsigned char transform_8x8_mode; /* !!h->pps.transform_8x8_mode */ ++ unsigned char constrained_intra_pred; /* !!h->pps.constrained_intra_pred */ ++ unsigned char direct_8x8_inference_flag; /* !!h->pps.direct_8x8_inference_flag */ ++ unsigned char direct_spatial_mv_pred; /* !!h->direct_spatial_mv_pred */ ++ unsigned char ref_count_0; /* h->ref_count[0] */ ++ unsigned char ref_count_1; /* h->ref_count[1] */ ++ unsigned char deblocking_filter; /* !!h->deblocking_filter */ ++ int dblk_left_en; ++ int dblk_top_en; ++ int x264_build; /* h->x264_build */ ++ int slice_alpha_c0_offset; ++ int slice_beta_offset; ++ unsigned long bs_buffer; /* s->gb.buffer */ ++ unsigned int bs_index; /* s->gb.index */ ++ unsigned int bs_size_in_bits; /* s->gb.index */ ++ int cabac_init_idc; ++/* int * curr_frm_slice_start_mb; */ ++/* int * ref_frm_slice_start_mb; */ ++ unsigned int ref_frm_ctrl; ++ unsigned int ref_frm_mv; ++ unsigned int curr_frm_ctrl; ++ unsigned int curr_frm_mv; ++ unsigned int dir_scale_table[16]; ++ unsigned int chroma_qp_table[128]; ++ unsigned char scaling_matrix8[6][64]; //2x64 ++ unsigned char scaling_matrix4[6][16]; ++ unsigned int tlb_phy_addr; ++ unsigned int dec_result_y; ++ unsigned int dec_result_uv; ++ unsigned int mc_ref_y[2][16]; ++ unsigned int mc_ref_c[2][16]; ++ unsigned int luma_weight[2][16]; ++ unsigned int luma_offset[2][16]; ++ unsigned int chroma_weight[2][16][2]; ++ unsigned int chroma_offset[2][16][2]; ++ unsigned char implicit_weight[16][16]; ++ unsigned int use_weight; ++ unsigned int use_weight_chroma; ++ unsigned int luma_log2_weight_denom; ++ unsigned int chroma_log2_weight_denom; ++ int * des_va, * des_pa; ++ unsigned char new_odma_flag; ++ unsigned char new_odma_format; //0: nv12, 1: nv21. ++ unsigned int dec_result1_y; ++ unsigned int dec_result1_uv; ++ unsigned int frm_y_stride; ++ unsigned int frm_c_stride; ++ unsigned int bs_rbsp_en; ++} jzm_h264; ++ ++struct SDE_VLC_STA ++{ ++ int ram_ofst; ++ int size; ++ int lvl0_len; ++}; ++ ++extern void jzm_h264_slice_init_vdma(struct JZM_H264 * st_h264); ++ ++#endif // _JZM_H264_API_H_ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_vpu.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_vpu.h +new file mode 100644 +index 000000000..dd4d69495 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/api/jzm_vpu.h +@@ -0,0 +1,2674 @@ ++/**************************************************************** ++*****************************************************************/ ++#ifndef __JZM_VPU_H__ ++#define __JZM_VPU_H__ ++ ++/**************************************************************** ++ VPU register map ++*****************************************************************/ ++ ++#ifdef JZM_HUNT_SIM ++# include "hunt.h" ++#else ++# define __place_k0_data__ ++# define __place_k0_text__ ++#endif ++ ++#define VPU_BASE 0x13200000 ++ ++#define HID_SCH 0x0 ++#define HID_VDMA 0x1 ++#define HID_EFE 0x4 ++#define HID_MCE 0x5 ++#define HID_DBLK 0x7 ++#define HID_VMAU 0x8 ++#define HID_SDE 0x9 ++#define HID_AUX 0xA ++#define HID_TCSM 0xB ++#define HID_JPGC 0xE ++#define HID_SRAM 0xF ++ ++#define VPU_MAX_MB_WIDTH 256 ++ ++#define MSCOPE_START(mbnum) write_reg(VPU_BASE+0x24, mbnum) ++#define MSCOPE_STOP() write_reg(VPU_BASE+0x28, 0) ++ ++/******************************************** ++ SCH (Scheduler) ++*********************************************/ ++#define TCSM_FLUSH 0xc0000 ++#define REG_SCH_GLBC 0x00000 ++#define SCH_GLBC_SLDE (0x1<<31) ++#define SCH_GLBC_TLBE (0x1<<30) ++#define SCH_GLBC_TLBINV (0x1<<29) ++#define SCH_INTE_ACFGERR (0x1<<20) ++#define SCH_INTE_TLBERR (0x1<<18) ++#define SCH_INTE_BSERR (0x1<<17) ++#define SCH_INTE_ENDF (0x1<<16) ++#define SCH_GLBC_HIMAP (0x1<<15) ++#define SCH_GLBC_HIAXI (0x1<<9) ++#define SCH_GLBC_EPRI0 (0x0<<7) ++#define SCH_GLBC_EPRI1 (0x1<<7) ++#define SCH_GLBC_EPRI2 (0x2<<7) ++#define SCH_GLBC_EPRI3 (0x3<<7) ++ ++#define REG_SCH_TLBA 0x00030 ++ ++#define REG_SCH_STAT 0x00034 ++ ++#define REG_SCH_SLDE0 0x00040 ++#define REG_SCH_SLDE1 0x00044 ++#define REG_SCH_SLDE2 0x00048 ++#define REG_SCH_SLDE3 0x0004C ++#define SCH_SLD_VTAG(val) (((val) & 0xFFF)<<20) ++#define SCH_SLD_MASK(val) (((val) & 0xFFF)<<8) ++#define SCH_SLD_VLD (0x1<<0) ++ ++#define REG_SCH_SCHC 0x00060 ++#define SCH_CH1_PCH(ch) (((ch) & 0x3)<<0) ++#define SCH_CH2_PCH(ch) (((ch) & 0x3)<<8) ++#define SCH_CH3_PCH(ch) (((ch) & 0x3)<<16) ++#define SCH_CH4_PCH(ch) (((ch) & 0x3)<<24) ++#define SCH_CH1_PE (0x1<<2) ++#define SCH_CH2_PE (0x1<<10) ++#define SCH_CH3_PE (0x1<<18) ++#define SCH_CH4_PE (0x1<<26) ++#define SCH_CH1_GS0 (0x0<<3) ++#define SCH_CH1_GS1 (0x1<<3) ++#define SCH_CH2_GS0 (0x0<<11) ++#define SCH_CH2_GS1 (0x1<<11) ++#define SCH_CH3_GS0 (0x0<<19) ++#define SCH_CH3_GS1 (0x1<<19) ++#define SCH_CH4_GS0 (0x0<<27) ++#define SCH_CH4_GS1 (0x1<<27) ++ ++#define REG_SCH_BND 0x00064 ++#define SCH_CH1_HID(hid) (((hid) & 0xF)<<16) ++#define SCH_CH2_HID(hid) (((hid) & 0xF)<<20) ++#define SCH_CH3_HID(hid) (((hid) & 0xF)<<24) ++#define SCH_CH4_HID(hid) (((hid) & 0xF)<<28) ++#define SCH_BND_G0F1 (0x1<<0) ++#define SCH_BND_G0F2 (0x1<<1) ++#define SCH_BND_G0F3 (0x1<<2) ++#define SCH_BND_G0F4 (0x1<<3) ++#define SCH_BND_G1F1 (0x1<<4) ++#define SCH_BND_G1F2 (0x1<<5) ++#define SCH_BND_G1F3 (0x1<<6) ++#define SCH_BND_G1F4 (0x1<<7) ++#define SCH_DEPTH(val) (((val-1) & 0xF)<<8) ++ ++#define REG_SCH_SCHG0 0x00068 ++#define REG_SCH_SCHG1 0x0006C ++#define REG_SCH_SCHE1 0x00070 ++#define REG_SCH_SCHE2 0x00074 ++#define REG_SCH_SCHE3 0x00078 ++#define REG_SCH_SCHE4 0x0007C ++ ++#define DSA_SCH_CH1 (VPU_BASE | REG_SCH_SCHE1) ++#define DSA_SCH_CH2 (VPU_BASE | REG_SCH_SCHE2) ++#define DSA_SCH_CH3 (VPU_BASE | REG_SCH_SCHE3) ++#define DSA_SCH_CH4 (VPU_BASE | REG_SCH_SCHE4) ++ ++/******************************************** ++ VDMA (VPU general-purpose DMA) ++*********************************************/ ++#define REG_VDMA_LOCK 0x10000 ++#define REG_VDMA_UNLK 0x10004 ++ ++#define REG_VDMA_TASKRG 0x10008 ++#define VDMA_ACFG_RUN (0x1) ++#define VDMA_DESC_RUN (0x3) ++#define VDMA_ACFG_CLR (0x8) ++#define VDMA_ACFG_SAFE (0x4) ++#define VDMA_ACFG_DHA(a) (((unsigned int)(a)) & 0xFFFFFF80) ++#define VDMA_DESC_DHA(a) (((unsigned int)(a)) & 0xFFFF0) ++ ++#define REG_VDMA_TASKST 0x1000C ++#define VDMA_ACFG_ERR (0x1<<3) ++#define VDMA_ACFG_END (0x1<<2) ++#define VDMA_DESC_END (0x1<<1) ++#define VDMA_VPU_BUSY (0x1<<0) ++ ++#define VDMA_DESC_EXTSEL (0x1<<0) ++#define VDMA_DESC_TLBSEL (0x1<<1) ++#define VDMA_DESC_LK (0x1<<31) ++ ++#define VDMA_ACFG_VLD (0x1<<31) ++#define VDMA_ACFG_TERM (0x1<<30) ++#define VDMA_ACFG_IDX(a) (((unsigned int)(a)) & 0xFFFFC) ++ ++#define GEN_VDMA_ACFG(chn, reg, lk, val) \ ++({*chn++ = val; \ ++ *chn++ = (VDMA_ACFG_VLD | (lk) | VDMA_ACFG_IDX(reg)); \ ++}) ++ ++/******************************************** ++ EFE (Encoder Front End) ++*********************************************/ ++#define REG_EFE_CTRL 0x40000 ++#define EFE_BP_MBY(mb) (((mb) & 0xFF)<<24) ++#define EFE_BP_MBX(mb) (((mb) & 0xFF)<<16) ++#define EFE_X264_QP(qp) (((qp) & 0x3F)<<8) ++#define EFE_DBLK_EN (0x1<<5) ++#define EFE_SLICE_TYPE(a) (((a) & 0x1)<<4) ++#define EFE_DEBUG_EN (0x1<<2) ++#define EFE_EN (0x1<<1) ++#define EFE_RUN (0x1<<0) ++ ++#define REG_EFE_GEOM 0x40004 ++#define EFE_FST_MBY(mb) (((mb) & 0xFF)<<24) ++#define EFE_FST_MBX(mb) (((0/*FIXME*/) & 0xFF)<<16) ++#define EFE_LST_MBY(mb) (((mb) & 0xFF)<<8) ++#define EFE_LST_MBX(mb) (((mb) & 0xFF)<<0) ++ ++#define REG_EFE_COEF_BA 0x4000C ++#define REG_EFE_RAWY_SBA 0x40010 ++#define REG_EFE_RAWC_SBA 0x40014 ++#define REG_EFE_TOPMV_BA 0x40018 ++#define REG_EFE_TOPPA_BA 0x4001C ++#define REG_EFE_MECHN_BA 0x40020 ++#define REG_EFE_MAUCHN_BA 0x40024 ++#define REG_EFE_DBLKCHN_BA 0x40028 ++#define REG_EFE_SDECHN_BA 0x4002C ++#define REG_EFE_RAW_DBA 0x40030 ++#define REG_EFE_MVRP 0x40100 ++#define REG_EFE_STAT 0x40110 ++ ++/******************************************** ++ MCE (Motion Compensation/Estimation COMBO) ++*********************************************/ ++#define REG_MCE_CTRL 0x50000 ++#define MCE_ESTI_MAX_BDIA(a) (((a) & 0xF)<<28) ++#define MCE_ESTI_MAX_SDIA(a) (((a) & 0xF)<<24) ++#define MCE_ESTI_USE_PMV (0x1<<22) ++#define MCE_ESTI_INTPEL (0x0<<20) ++#define MCE_ESTI_HPEL (0x2<<20) ++#define MCE_ESTI_QPEL (0x3<<20) ++#define MCE_ESTI_PUT_MET (0x1<<19) ++#define MCE_COMP_AUTO_EXPD (0x1<<17) ++#define MCE_CH2_EN (0x1<<11) ++#define MCE_CLKG_EN (0x1<<8) ++#define MCE_OFA_EN (0x1<<7) ++#define MCE_MODE_COMP (0x0<<4) ++#define MCE_MODE_ESTI (0x1<<4) ++#define MCE_CACHE_FLUSH (0x1<<3) ++#define MCE_EN (0x1<<0) ++ ++#define REG_MCE_CH1_STAT 0x50004 ++#define REG_MCE_CH2_STAT 0x50804 ++#define MCE_PREF_END (0x1<<2) ++#define MCE_LINK_END (0x1<<1) ++#define MCE_TASK_END (0x1<<0) ++ ++#define REG_MCE_MVPA 0x5000C ++#define REG_MCE_IWTA 0x5000C ++ ++#define REG_MCE_CH1_PINFO 0x50020 ++#define REG_MCE_CH2_PINFO 0x50820 ++#define MCE_PINFO(rgr, its, its_sft, its_scale, its_rnd) \ ++( ((rgr) & 0x1)<<31 | \ ++ ((its) & 0x1)<<28 | \ ++ ((its_sft) & 0x7)<<24 | \ ++ ((its_scale) & 0xFF)<<16 | \ ++ ((its_rnd) & 0xFFFF)<<0 \ ++) ++ ++#define REG_MCE_CH1_WINFO 0x50024 ++#define REG_MCE_CH2_WINFO1 0x50824 ++#define REG_MCE_CH2_WINFO2 0x50828 ++#define MCE_WINFO(wt, wtpd, wtmd, biavg_rnd, wt_denom, \ ++ wt_sft, wt_lcoef, wt_rcoef) \ ++( ((wt) & 0x1)<<31 | \ ++ ((wtpd) & 0x1)<<30 | \ ++ ((wtmd) & 0x3)<<28 | \ ++ ((biavg_rnd) & 0x1)<<27 | \ ++ ((wt_denom) & 0x7)<<24 | \ ++ ((wt_sft) & 0xF)<<16 | \ ++ ((wt_lcoef) & 0xFF)<<8 | \ ++ ((wt_rcoef) & 0xFF)<<0 \ ++) ++ ++#define REG_MCE_CH1_WTRND 0x5002C ++#define REG_MCE_CH2_WTRND 0x5082C ++#define MCE_WTRND(wt2_rnd, wt1_rnd) \ ++( ((wt2_rnd) & 0xFFFF)<<16 | \ ++ ((wt1_rnd) & 0xFFFF)<<0 \ ++) ++ ++#define REG_MCE_CH1_BINFO 0x50030 ++#define REG_MCE_CH2_BINFO 0x50830 ++#define MCE_BINFO(ary, expdy, expdx, ilmd, pel) \ ++( ((ary) & 0x1)<<31 | \ ++ ((expdy) & 0xF)<<24 | \ ++ ((expdx) & 0xF)<<20 | \ ++ ((ilmd) & 0x3)<<16 | \ ++ ((pel) & 0x3)<<14 \ ++) ++ ++#define REG_MCE_CH1_IINFO1 0x50034 ++#define REG_MCE_CH1_IINFO2 0x50038 ++#define MCE_CH1_IINFO(intp, tap, pkg, hldgl, avsdgl, \ ++ intp_dir, intp_rnd, intp_sft, \ ++ sintp, sintp_rnd, sintp_bias) \ ++( ((intp) & 0x1)<<31 | \ ++ ((tap) & 0x3)<<28 | \ ++ ((pkg) & 0x1)<<27 | \ ++ ((hldgl) & 0x1)<<26 | \ ++ ((avsdgl) & 0x1)<<25 | \ ++ ((intp_dir) & 0x1)<<24 | \ ++ ((intp_rnd) & 0xFF)<<16 | \ ++ ((intp_sft) & 0xF)<<8 | \ ++ ((sintp) & 0x1)<<2 | \ ++ ((sintp_rnd) & 0x1)<<1 | \ ++ ((sintp_bias) & 0x1)<<0 \ ++) ++ ++#define REG_MCE_CH2_IINFO1 0x50834 ++#define REG_MCE_CH2_IINFO2 0x50838 ++#define MCE_CH2_IINFO(intp, intp_dir, intp_sft, \ ++ intp_lcoef, intp_rcoef, intp_rnd) \ ++( ((intp) & 0x1)<<31 | \ ++ ((intp_dir) & 0x1)<<15 | \ ++ ((intp_sft) & 0x7)<<12 | \ ++ ((intp_lcoef) & 0x7)<<9 | \ ++ ((intp_rcoef) & 0x7)<<6 | \ ++ ((intp_rnd) & 0x3F)<<0 \ ++) ++ ++#define REG_MCE_CH1_TAP1L 0x5003C ++#define REG_MCE_CH1_TAP2L 0x50040 ++#define REG_MCE_CH1_TAP1M 0x50044 ++#define REG_MCE_CH1_TAP2M 0x50048 ++#define MCE_CH1_TAP(c1, c2, c3, c4) \ ++( ((c4) & 0xFF)<<24 | \ ++ ((c3) & 0xFF)<<16 | \ ++ ((c2) & 0xFF)<<8 | \ ++ ((c1) & 0xFF)<<0 \ ++) ++ ++#define REG_MCE_CH1_STRD 0x5004C ++#define REG_MCE_CH2_STRD 0x5084C ++#define MCE_STRD(ref_strd, raw_strd, dst_strd) \ ++( ((ref_strd) & 0xFFF)<<16 | \ ++ ((raw_strd) & 0xFF)<<8 | \ ++ ((dst_strd) & 0xFF)<<0 \ ++) ++ ++#define REG_MCE_GEOM 0x50050 ++#define MCE_GEOM(frm_height, frm_width) \ ++( ((frm_height) & 0xFFF)<<16 | \ ++ ((frm_width) & 0xFFF)<<0 \ ++) ++ ++#define REG_MCE_DDC 0x50054 ++#define MCE_TDD_RUN 0x1<<0 ++ ++#define REG_MCE_DSA 0x50058 ++ ++#define REG_MCE_ESTIC 0x5005C ++#define MCE_ESTIC(fsct, fsst, fsce, fsse) \ ++( ((fsct) & 0xFFFF)<<16 | \ ++ ((fsst) & 0xF)<<4 | \ ++ ((fsce) & 0x1)<<1 | \ ++ ((fsse) & 0x1)<<0 \ ++) ++ ++#define REG_MCE_CH1_RLUT 0x50300 ++#define REG_MCE_CH2_RLUT 0x50B00 ++#define MCE_RLUT_WT(wcoef2, wofst2, wcoef1, wofst1) \ ++( ((wcoef2) & 0xFF)<<24 | \ ++ ((wofst2) & 0xFF)<<16 | \ ++ ((wcoef1) & 0xFF)<<8 | \ ++ ((wofst1) & 0xFF)<<0 \ ++) ++ ++#define REG_MCE_CH1_CLUT 0x50400 ++ ++#define REG_MCE_CH1_ILUT 0x50500 ++#define REG_MCE_CH2_ILUT 0x50D00 ++ ++/*Motion TDD*/ ++#define MCE_TDD_COMP_HEAD(vld, lk, ch1pel, ch2pel, \ ++ posmd, mvmd, tkn, mby, mbx) \ ++( ((vld) & 0x1)<<31 | \ ++ ((lk) & 0x1)<<30 | \ ++ ((ch1pel) & 0x1)<<27 | \ ++ ((ch2pel) & 0x3)<<25 | \ ++ ((posmd) & 0x1)<<24 | \ ++ ((mvmd) & 0x1)<<23 | \ ++ ((tkn) & 0x7F)<<16 | \ ++ ((mby) & 0xFF)<<8 | \ ++ ((mbx) & 0xFF)<<0 \ ++) ++#define MCE_TDD_COMP_MV(mvy, mvx) \ ++( ((mvy) & 0xFFFF)<<16 | \ ++ ((mvx) & 0xFFFF)<<0 \ ++) ++#define MCE_TDD_COMP_CMD(bidir, refdir, fld, fldsel, \ ++ rgr, its, doe, cflo, ypos, \ ++ lilmd, cilmd, list, \ ++ boy, box, bh, bw, pos) \ ++( ((bidir) & 0x1)<<31 | \ ++ ((refdir) & 0x1)<<30 | \ ++ ((fld) & 0x1)<<29 | \ ++ ((fldsel) & 0x1)<<28 | \ ++ ((rgr) & 0x1)<<27 | \ ++ ((its) & 0x1)<<26 | \ ++ ((doe) & 0x1)<<25 | \ ++ ((cflo) & 0x1)<<24 | \ ++ ((ypos) & 0xF)<<20 | \ ++ ((lilmd) & 0x3)<<18 | \ ++ ((cilmd) & 0x3)<<16 | \ ++ ((list) & 0xF)<<12 | \ ++ ((boy) & 0x3)<<10 | \ ++ ((box) & 0x3)<<8 | \ ++ ((bh) & 0x3)<<6 | \ ++ ((bw) & 0x3)<<4 | \ ++ ((pos) & 0xF)<<0 \ ++) ++#define MCE_TDD_ESTI(vld, lk, dmy, pmc, list, \ ++ boy, box, bh, bw, mby, mbx) \ ++( ((vld) & 0x1)<<31 | \ ++ ((lk) & 0x1)<<30 | \ ++ ((dmy) & 0x1)<<27 | \ ++ ((pmc) & 0x1)<<26 | \ ++ ((list) & 0x3)<<24 | \ ++ ((boy) & 0x3)<<22 | \ ++ ((box) & 0x3)<<20 | \ ++ ((bh) & 0x3)<<18 | \ ++ ((bw) & 0x3)<<16 | \ ++ ((mby) & 0xFF)<<8 | \ ++ ((mbx) & 0xFF)<<0 \ ++) ++#define MCE_TDD_CFG(vld, lk, cidx) \ ++( 0x1<<28 | \ ++ ((vld) & 0x1)<<31 | \ ++ ((lk) & 0x1)<<30 | \ ++ ((cidx) & 0xFFF)<<0 \ ++) ++#define MCE_TDD_SYNC(vld, lk, crst, id) \ ++( 0x1<<29 | \ ++ ((vld) & 0x1)<<31 | \ ++ ((lk) & 0x1)<<30 | \ ++ ((crst) & 0x1)<<27 | \ ++ ((id) & 0xFFFF)<<0 \ ++) ++ ++/******************************************** ++ VMAU (VPU Matrix Arithmetic Unit) ++*********************************************/ ++#define REG_VMAU_MCBP 0x80000 ++ ++#define REG_VMAU_QTPARA 0x80004 ++ ++#define REG_VMAU_MAIN_ADDR 0x80008 ++ ++#define REG_VMAU_NCCHN_ADDR 0x8000C ++ ++#define REG_VMAU_CHN_LEN 0x80010 ++ ++#define REG_VMAU_ACBP 0x80014 ++ ++#define REG_VMAU_CPREDM_TLV 0x80018 ++ ++#define REG_VMAU_YPREDM0 0x8001C ++ ++#define REG_VMAU_YPREDM1 0x80020 ++ ++#define REG_VMAU_GBL_RUN 0x80040 ++#define VMAU_RUN 0x1 ++#define VMAU_STOP 0x2 ++#define VMAU_RESET 0x4 ++ ++#define REG_VMAU_GBL_CTR 0x80044 ++#define VMAU_CTRL_FIFO_M 0x1 ++#define VMAU_CTRL_IRQ_EN 0x10 ++#define VMAU_CTRL_SLPOW 0x10000 ++#define VMAU_CTRL_TO_DBLK 0x1000000 ++ ++#define REG_VMAU_STATUS 0x80048 ++ ++#define REG_VMAU_CCHN_ADDR 0x8004C ++ ++#define REG_VMAU_VIDEO_TYPE 0x80050 ++#define VMAU_FMT_H264 0x1 ++#define VMAU_FMT_RV9 0x2 ++#define VMAU_FMT_VC1 0x3 ++#define VMAU_FMT_MPEG2 0x4 ++#define VMAU_FMT_MPEG4 0x5 ++#define VMAU_FMT_VP8 0x6 ++#define VMAU_MODE_DEC (0x0<<11) ++#define VMAU_MODE_ENC (0x1<<11) ++ ++#define REG_VMAU_Y_GS 0x80054 ++ ++#define REG_VMAU_DEC_DONE 0x80058 ++ ++#define REG_VMAU_ENC_DONE 0x8005C ++ ++#define REG_VMAU_POS 0x80060 ++ ++#define REG_VMAU_MCF_STA 0x80064 ++ ++#define REG_VMAU_DEC_YADDR 0x80068 ++ ++#define REG_VMAU_DEC_UADDR 0x8006C ++ ++#define REG_VMAU_DEC_VADDR 0x80070 ++ ++#define REG_VMAU_DEC_STR 0x80074 ++ ++#define REG_VMAU_MEML 0x84000 ++#define REG_VMAU_QT 0x88000 ++ ++/******************************************** ++ DBLK (deblock) ++*********************************************/ ++#define REG_DBLK_DHA 0x70000 ++ ++#define REG_DBLK_TRIG 0x70060 ++#define DBLK_RUN 0x1 ++#define DBLK_STOP 0x2 ++#define DBLK_RESET 0x4 ++#define DBLK_SLICE_RUN 0x8 ++ ++#define REG_DBLK_CTRL 0x70064 ++#define DBLK_CTRL(expand, rotate, loop_filter) \ ++( ((expand) & 0x1)<<4 | \ ++ ((rotate) & 0x3)<<1 | \ ++ ((loop_filter) & 0x1)<<0 \ ++) ++ ++#define REG_DBLK_VTR 0x70068 ++#define DBLK_FMT_H264 0x1 ++#define DBLK_FMT_RV9 0x2 ++#define DBLK_FMT_VC1 0x3 ++#define DBLK_FMT_MPEG2 0x4 ++#define DBLK_FMT_MPEG4 0x5 ++#define DBLK_FMT_VP8 0x6 ++#define DBLK_FRM_I 0x0 ++#define DBLK_FRM_P 0x1 ++#define DBLK_FRM_B 0x2 ++#define DBLK_VTR(beta, alpha, vp8_spl, vp8_kf, \ ++ frm_typ, video_fmt) \ ++( ((beta) & 0xFF)<<24 | \ ++ ((alpha) & 0xFF)<<16 | \ ++ ((vp8_spl) & 0x1)<<9 | \ ++ ((vp8_kf) & 0x1)<<5 | \ ++ ((frm_typ) & 0x3)<<3 | \ ++ ((video_fmt) & 0x7)<<0 \ ++) ++ ++#define REG_DBLK_FSTA 0x7006C ++ ++#define REG_DBLK_GSTA 0x70070 ++ ++#define REG_DBLK_GSIZE 0x70074 ++#define DBLK_GSIZE(mb_height, mb_width) \ ++( ((mb_height) & 0xFFFF)<<16 | \ ++ ((mb_width) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GENDA 0x70078 ++ ++#define REG_DBLK_GPOS 0x7007C ++#define DBLK_GPOS(first_mby, first_mbx) \ ++( ((first_mby) & 0xFFFF)<<16 | \ ++ ((first_mbx) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GPIC_STR 0x70080 ++#define DBLK_GPIC_STR(dst_strd_c, dst_strd_y) \ ++( ((dst_strd_c) & 0xFFFF)<<16 | \ ++ ((dst_strd_y) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GPIC_YA 0x70084 ++ ++#define REG_DBLK_GPIC_CA 0x70088 ++ ++#define REG_DBLK_GP_ENDA 0x7008C ++ ++#define REG_DBLK_SLICE_ENDA 0x70090 ++ ++#define REG_DBLK_BLK_CTRL 0x70094 ++ ++#define REG_DBLK_BLK_FIFO 0x70098 ++ ++#define REG_DBLK_GPIC_Y1A 0x700A0 ++ ++#define REG_DBLK_GPIC_C1A 0x700A4 ++ ++#define REG_DBLK_GPIC_STR1 0x700A8 ++ ++/******************************************** ++ SDE (stream parser/encoding) ++*********************************************/ ++#define REG_SDE_STAT 0x90000 ++ ++#define REG_SDE_SL_CTRL 0x90004 ++#define SDE_SLICE_INIT (0x1<<1) ++#define SDE_MB_RUN (0x1<<0) ++ ++#define REG_SDE_SL_GEOM 0x90008 ++#define SDE_SL_GEOM(mb_height, mb_width, \ ++ first_mby, first_mbx) \ ++( ((mb_height) & 0xFF)<<24 | \ ++ ((mb_width) & 0xFF)<<16 | \ ++ ((first_mby) & 0xFF)<<8 | \ ++ ((first_mbx) & 0xFF)<<0 \ ++) ++ ++#define REG_SDE_GL_CTRL 0x9000C ++#define SDE_BP(mby, mbx) \ ++( ((mby) & 0xFF)<<24 | \ ++ ((mbx) & 0xFF)<<16 \ ++) ++#define SDE_MODE_AUTO (0x0<<4) ++#define SDE_MODE_STEP (0x1<<4) ++#define SDE_MODE_DEBUG (0x2<<4) ++#define SDE_EN (0x1<<0) ++ ++#define REG_SDE_CODEC_ID 0x90010 ++#define SDE_FMT_H264_DEC (0x1<<0) ++#define SDE_FMT_H264_ENC (0x1<<1) ++#define SDE_FMT_VP8_DEC (0x1<<2) ++#define SDE_FMT_VC1_DEC (0x1<<3) ++#define SDE_FMT_MPEG2_DEC (0x1<<4) ++ ++#define REG_SDE_CFG0 0x90014 ++#define REG_SDE_CFG1 0x90018 ++#define REG_SDE_CFG2 0x9001C ++#define REG_SDE_CFG3 0x90020 ++#define REG_SDE_CFG4 0x90024 ++#define REG_SDE_CFG5 0x90028 ++#define REG_SDE_CFG6 0x9002C ++#define REG_SDE_CFG7 0x90030 ++#define REG_SDE_CFG8 0x90034 ++#define REG_SDE_CFG9 0x90038 ++#define REG_SDE_CFG10 0x9003C ++#define REG_SDE_CFG11 0x90040 ++#define REG_SDE_CFG12 0x90044 ++#define REG_SDE_CFG13 0x90048 ++#define REG_SDE_CFG14 0x9004C ++#define REG_SDE_CFG15 0x90050 ++ ++#define REG_SDE_CTX_TBL 0x92000 ++#define REG_SDE_CQP_TBL 0x93800 ++ ++/**************************************************************** ++ VPU tables ++*****************************************************************/ ++/******************************************** ++ Motion interpolation programable table ++*********************************************/ ++#define IS_SKIRT 0 ++#define IS_MIRROR 1 ++ ++#define IS_BIAVG 0 ++#define IS_WT1 1 ++#define IS_WT2 2 ++#define IS_FIXWT 3 ++ ++#define IS_ILUT0 0 ++#define IS_ILUT1 2 ++#define IS_EC 1 ++ ++#define IS_TCS 1 ++#define NOT_TCS 0 ++#define IS_SCS 1 ++#define NOT_SCS 0 ++#define IS_HLDGL 1 ++#define NOT_HLDGL 0 ++#define IS_AVSDGL 1 ++#define NOT_AVSDGL 0 ++ ++#define INTP_HDIR 0 ++#define INTP_VDIR 1 ++ ++enum IntpID { ++ MPEG_HPEL = 0, ++ MPEG_QPEL, ++ H264_QPEL, ++ H264_EPEL, ++ RV8_TPEL, ++ RV9_QPEL, ++ RV9_CPEL, ++ WMV2_QPEL, ++ VC1_QPEL, ++ AVS_QPEL, ++ VP6_QPEL, ++ VP8_QPEL, ++ VP8_EPEL, ++ VP8_BIL, ++ VP8_FPEL, /*full-pixel for chroma*/ ++}; ++ ++enum PosID { ++ H0V0 = 0, ++ H1V0, ++ H2V0, ++ H3V0, ++ H0V1, ++ H1V1, ++ H2V1, ++ H3V1, ++ H0V2, ++ H1V2, ++ H2V2, ++ H3V2, ++ H0V3, ++ H1V3, ++ H2V3, ++ H3V3, ++}; ++ ++enum TapTYP { ++ TAP2 = 0, ++ TAP4, ++ TAP6, ++ TAP8, ++}; ++ ++enum SPelSFT { ++ HPEL = 1, ++ QPEL, ++ EPEL, ++}; ++ ++typedef struct IntpFMT_t{ ++ char tap; ++ char intp_pkg[2]; ++ char hldgl; ++ char avsdgl; ++ char intp[2]; ++ char intp_dir[2]; ++ char intp_coef[2][8]; ++ char intp_rnd[2]; ++ char intp_sft[2]; ++ char intp_sintp[2]; ++ char intp_srnd[2]; ++ char intp_sbias[2]; ++}IntpFMT_t; ++ ++__place_k0_data__ ++static char AryFMT[] = {IS_SKIRT, IS_MIRROR, IS_SKIRT, IS_SKIRT, ++ IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, ++ IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, ++ IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT}; ++ ++__place_k0_data__ ++static char SubPel[] = {HPEL, QPEL, QPEL, EPEL, ++ QPEL, QPEL, QPEL, QPEL, ++ QPEL, QPEL, QPEL, QPEL, ++ EPEL, HPEL, QPEL, QPEL}; ++ ++__place_k0_data__ ++static IntpFMT_t IntpFMT[][16] = { ++ { ++ /************* MPEG_HPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ }, ++ ++ { ++ /************* MPEG_QPEL ***************/ ++ {/*H0V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H1V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H3V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* H264_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H3V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* H264_EPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/0}, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/0}, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* RV8_TPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0}, {-1, 12, 6, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0}, {-1, 12, 6, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0}, {-1, 6, 12, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0}, {-1, 6, 12, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* RV9_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 32}, ++ {/*intp_sft*/5, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 16}, ++ {/*intp_sft*/6, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 16}, ++ {/*intp_sft*/6, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 20, 52, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 52, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 32}, ++ {/*intp_sft*/5, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* RV9_CPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 1}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 1}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* WMV2_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* VC1_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/31, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 8}, ++ {/*intp_sft*/6, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/7, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 32}, ++ {/*intp_sft*/4, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 32}, ++ {/*intp_sft*/4, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/31, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 8}, ++ {/*intp_sft*/6, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* AVS_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -1, 5, 5, -1, 0, 0, 0}, {-1, -2, 96, 42, -7, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0}, {0, -1, 5, 5, -1, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, 5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0}, {0, -1, 5, 5, -1, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0}, {0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -1, 5, 5, -1, 0, 0, 0}, {0, -7, 42, 96, -2, -1, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* VP6_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_EPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/0}, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/0}, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 4}, ++ {/*intp_sft*/3, 3}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* VP8_BIL ***************/ ++ {/*H0V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 2}, ++ {/*intp_sft*/1, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 1}, ++ {/*intp_sft*/2, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 1}, ++ {/*intp_sft*/1, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 1}, ++ {/*intp_sft*/2, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 2}, ++ {/*intp_sft*/1, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_FPEL ***************/ ++ {/*H0V0*/0}, ++ {/*H1V0*/0}, ++ {/*H2V0*/0}, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/0}, ++ {/*H1V2*/0}, ++ {/*H2V2*/0}, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++}; ++ ++#endif /*__JZM_VPU_H__*/ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/avassert.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/avassert.h +new file mode 100644 +index 000000000..c71f51f1e +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/avassert.h +@@ -0,0 +1,53 @@ ++#ifndef AVUTIL_AVASSERT_H ++#define AVUTIL_AVASSERT_H ++ ++#ifdef __KERNEL__ ++#else ++#include ++#endif ++//#include "avutil.h" ++#include "log.h" ++ ++/** ++ * assert() equivalent, that is always enabled. ++ */ ++#define av_assert0(cond) do { \ ++ if (!(cond)) { \ ++ av_log(NULL, AV_LOG_PANIC, "Assertion %s failed at %s:%d\n", \ ++ cond, __FILE__, __LINE__); \ ++ } \ ++} while (0) ++ ++#define assert(cond) av_assert0(cond) ++ ++ ++/** ++ * assert() equivalent, that does not lie in speed critical code. ++ * These asserts() thus can be enabled without fearing speed loss. ++ */ ++#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0 ++#define av_assert1(cond) av_assert0(cond) ++#else ++#define av_assert1(cond) ((void)0) ++#endif ++ ++ ++/** ++ * assert() equivalent, that does lie in speed critical code. ++ */ ++#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 ++#define av_assert2(cond) av_assert0(cond) ++#define av_assert2_fpu() av_assert0_fpu() ++#else ++#define av_assert2(cond) ((void)0) ++#define av_assert2_fpu() ((void)0) ++#endif ++ ++/** ++ * Assert that floating point operations can be executed. ++ * ++ * This will av_assert0() that the cpu is not in MMX state on X86 ++ */ ++void av_assert0_fpu(void); ++ ++#endif /* AVUTIL_AVASSERT_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/avcodec.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/avcodec.h +new file mode 100644 +index 000000000..b312fe4d7 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/avcodec.h +@@ -0,0 +1,404 @@ ++#ifndef __AVCODEC_H__ ++#define __AVCODEC_H__ ++ ++#include "buffer.h" ++#include "frame.h" ++ ++/** ++ * Allow decoders to produce frames with data planes that are not aligned ++ * to CPU requirements (e.g. due to cropping). ++ */ ++#define AV_CODEC_FLAG_UNALIGNED (1 << 0) ++/** ++ * Use fixed qscale. ++ */ ++#define AV_CODEC_FLAG_QSCALE (1 << 1) ++/** ++ * 4 MV per MB allowed / advanced prediction for H.263. ++ */ ++#define AV_CODEC_FLAG_4MV (1 << 2) ++/** ++ * Output even those frames that might be corrupted. ++ */ ++#define AV_CODEC_FLAG_OUTPUT_CORRUPT (1 << 3) ++/** ++ * Use qpel MC. ++ */ ++#define AV_CODEC_FLAG_QPEL (1 << 4) ++/** ++ * Use internal 2pass ratecontrol in first pass mode. ++ */ ++#define AV_CODEC_FLAG_PASS1 (1 << 9) ++/** ++ * Use internal 2pass ratecontrol in second pass mode. ++ */ ++#define AV_CODEC_FLAG_PASS2 (1 << 10) ++/** ++ * loop filter. ++ */ ++#define AV_CODEC_FLAG_LOOP_FILTER (1 << 11) ++/** ++ * Only decode/encode grayscale. ++ */ ++#define AV_CODEC_FLAG_GRAY (1 << 13) ++/** ++ * error[?] variables will be set during encoding. ++ */ ++#define AV_CODEC_FLAG_PSNR (1 << 15) ++/** ++ * Input bitstream might be truncated at a random location ++ * instead of only at frame boundaries. ++ */ ++#define AV_CODEC_FLAG_TRUNCATED (1 << 16) ++/** ++ * Use interlaced DCT. ++ */ ++#define AV_CODEC_FLAG_INTERLACED_DCT (1 << 18) ++/** ++ * Force low delay. ++ */ ++#define AV_CODEC_FLAG_LOW_DELAY (1 << 19) ++/** ++ * Place global headers in extradata instead of every keyframe. ++ */ ++#define AV_CODEC_FLAG_GLOBAL_HEADER (1 << 22) ++/** ++ * Use only bitexact stuff (except (I)DCT). ++ */ ++#define AV_CODEC_FLAG_BITEXACT (1 << 23) ++/* Fx : Flag for H.263+ extra options */ ++/** ++ * H.263 advanced intra coding / MPEG-4 AC prediction ++ */ ++#define AV_CODEC_FLAG_AC_PRED (1 << 24) ++/** ++ * interlaced motion estimation ++ */ ++#define AV_CODEC_FLAG_INTERLACED_ME (1 << 29) ++#define AV_CODEC_FLAG_CLOSED_GOP (1U << 31) ++ ++/** ++ * Allow non spec compliant speedup tricks. ++ */ ++#define AV_CODEC_FLAG2_FAST (1 << 0) ++/** ++ * Skip bitstream encoding. ++ */ ++#define AV_CODEC_FLAG2_NO_OUTPUT (1 << 2) ++/** ++ * Place global headers at every keyframe instead of in extradata. ++ */ ++#define AV_CODEC_FLAG2_LOCAL_HEADER (1 << 3) ++ ++/** ++ * timecode is in drop frame format. DEPRECATED!!!! ++ */ ++#define AV_CODEC_FLAG2_DROP_FRAME_TIMECODE (1 << 13) ++ ++/** ++ * Input bitstream might be truncated at a packet boundaries ++ * instead of only at frame boundaries. ++ */ ++#define AV_CODEC_FLAG2_CHUNKS (1 << 15) ++/** ++ * Discard cropping information from SPS. ++ */ ++#define AV_CODEC_FLAG2_IGNORE_CROP (1 << 16) ++ ++/** ++ * Show all frames before the first keyframe ++ */ ++#define AV_CODEC_FLAG2_SHOW_ALL (1 << 22) ++/** ++ * Export motion vectors through frame side data ++ */ ++#define AV_CODEC_FLAG2_EXPORT_MVS (1 << 28) ++/** ++ * Do not skip samples and export skip information as frame side data ++ */ ++#define AV_CODEC_FLAG2_SKIP_MANUAL (1 << 29) ++/** ++ * Do not reset ASS ReadOrder field on flush (subtitles decoding) ++ */ ++#define AV_CODEC_FLAG2_RO_FLUSH_NOOP (1 << 30) ++ ++/** ++ * Identify the syntax and semantics of the bitstream. ++ * The principle is roughly: ++ * Two decoders with the same ID can decode the same streams. ++ * Two encoders with the same ID can encode compatible streams. ++ * There may be slight deviations from the principle due to implementation ++ * details. ++ * ++ * If you add a codec ID to this list, add it so that ++ * 1. no value of an existing codec ID changes (that would break ABI), ++ * 2. it is as close as possible to similar codecs ++ * ++ * After adding new codec IDs, do not forget to add an entry to the codec ++ * descriptor list and bump libavcodec minor version. ++ */ ++enum AVCodecID { ++ AV_CODEC_ID_NONE, ++ ++ AV_CODEC_ID_H264 ++}; ++ ++ ++typedef struct AVCodecContext { ++ ++ ++ int log_level_offset; ++ ++ enum AVCodecID codec_id; ++ ++ /** ++ * AV_CODEC_FLAG_*. ++ * - encoding: Set by user. ++ * - decoding: Set by user. ++ */ ++ int flags; ++ ++ /** ++ * AV_CODEC_FLAG2_* ++ * - encoding: Set by user. ++ * - decoding: Set by user. ++ */ ++ int flags2; ++ ++ /** ++ * number of reference frames ++ * - encoding: Set by user. ++ * - decoding: Set by lavc. ++ */ ++ int refs; ++ ++ /* video only */ ++ /** ++ * picture width / height. ++ * ++ * @note Those fields may not match the values of the last ++ * AVFrame output by avcodec_decode_video2 due frame ++ * reordering. ++ * ++ * - encoding: MUST be set by user. ++ * - decoding: May be set by the user before opening the decoder if known e.g. ++ * from the container. Some decoders will require the dimensions ++ * to be set by the caller. During decoding, the decoder may ++ * overwrite those values as required while parsing the data. ++ */ ++ int width, height; ++ ++ /** ++ * Bitstream width / height, may be different from width/height e.g. when ++ * the decoded frame is cropped before being output or lowres is enabled. ++ * ++ * @note Those field may not match the value of the last ++ * AVFrame output by avcodec_receive_frame() due frame ++ * reordering. ++ * ++ * - encoding: unused ++ * - decoding: May be set by the user before opening the decoder if known ++ * e.g. from the container. During decoding, the decoder may ++ * overwrite those values as required while parsing the data. ++ */ ++ int coded_width, coded_height; ++ ++ /** ++ * Size of the frame reordering buffer in the decoder. ++ * For MPEG-2 it is 1 IPB or 0 low delay IP. ++ * - encoding: Set by libavcodec. ++ * - decoding: Set by libavcodec. ++ */ ++ int has_b_frames; ++ ++ /** ++ * debug ++ * - encoding: Set by user. ++ * - decoding: Set by user. ++ */ ++ int debug; ++#define FF_DEBUG_PICT_INFO 1 ++#define FF_DEBUG_RC 2 ++#define FF_DEBUG_BITSTREAM 4 ++#define FF_DEBUG_MB_TYPE 8 ++#define FF_DEBUG_QP 16 ++ ++#define FF_DEBUG_DCT_COEFF 0x00000040 ++#define FF_DEBUG_SKIP 0x00000080 ++#define FF_DEBUG_STARTCODE 0x00000100 ++#define FF_DEBUG_ER 0x00000400 ++#define FF_DEBUG_MMCO 0x00000800 ++#define FF_DEBUG_BUGS 0x00001000 ++ ++#define FF_DEBUG_BUFFERS 0x00008000 ++#define FF_DEBUG_THREADS 0x00010000 ++#define FF_DEBUG_GREEN_MD 0x00800000 ++#define FF_DEBUG_NOMC 0x01000000 ++ ++ /** ++ * Error recognition; may misdetect some more or less valid parts as errors. ++ * - encoding: unused ++ * - decoding: Set by user. ++ */ ++ int err_recognition; ++ ++/** ++ * Verify checksums embedded in the bitstream (could be of either encoded or ++ * decoded data, depending on the codec) and print an error message on mismatch. ++ * If AV_EF_EXPLODE is also set, a mismatching checksum will result in the ++ * decoder returning an error. ++ */ ++#define AV_EF_CRCCHECK (1<<0) ++#define AV_EF_BITSTREAM (1<<1) ///< detect bitstream specification deviations ++#define AV_EF_BUFFER (1<<2) ///< detect improper bitstream length ++#define AV_EF_EXPLODE (1<<3) ///< abort decoding on minor error detection ++ ++#define AV_EF_IGNORE_ERR (1<<15) ///< ignore errors and continue ++#define AV_EF_CAREFUL (1<<16) ///< consider things that violate the spec, are fast to calculate and have not been seen in the wild as errors ++#define AV_EF_COMPLIANT (1<<17) ///< consider all spec non compliances as errors ++#define AV_EF_AGGRESSIVE (1<<18) ///< consider things that a sane encoder should not do as an error ++ ++ /** ++ * profile ++ * - encoding: Set by user. ++ * - decoding: Set by libavcodec. ++ */ ++ int profile; ++#define FF_PROFILE_UNKNOWN -99 ++#define FF_PROFILE_RESERVED -100 ++ ++#define FF_PROFILE_AAC_MAIN 0 ++#define FF_PROFILE_AAC_LOW 1 ++#define FF_PROFILE_AAC_SSR 2 ++#define FF_PROFILE_AAC_LTP 3 ++#define FF_PROFILE_AAC_HE 4 ++#define FF_PROFILE_AAC_HE_V2 28 ++#define FF_PROFILE_AAC_LD 22 ++#define FF_PROFILE_AAC_ELD 38 ++#define FF_PROFILE_MPEG2_AAC_LOW 128 ++#define FF_PROFILE_MPEG2_AAC_HE 131 ++ ++#define FF_PROFILE_DNXHD 0 ++#define FF_PROFILE_DNXHR_LB 1 ++#define FF_PROFILE_DNXHR_SQ 2 ++#define FF_PROFILE_DNXHR_HQ 3 ++#define FF_PROFILE_DNXHR_HQX 4 ++#define FF_PROFILE_DNXHR_444 5 ++ ++#define FF_PROFILE_DTS 20 ++#define FF_PROFILE_DTS_ES 30 ++#define FF_PROFILE_DTS_96_24 40 ++#define FF_PROFILE_DTS_HD_HRA 50 ++#define FF_PROFILE_DTS_HD_MA 60 ++#define FF_PROFILE_DTS_EXPRESS 70 ++ ++#define FF_PROFILE_MPEG2_422 0 ++#define FF_PROFILE_MPEG2_HIGH 1 ++#define FF_PROFILE_MPEG2_SS 2 ++#define FF_PROFILE_MPEG2_SNR_SCALABLE 3 ++#define FF_PROFILE_MPEG2_MAIN 4 ++#define FF_PROFILE_MPEG2_SIMPLE 5 ++ ++#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag ++#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag ++ ++#define FF_PROFILE_H264_BASELINE 66 ++#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) ++#define FF_PROFILE_H264_MAIN 77 ++#define FF_PROFILE_H264_EXTENDED 88 ++#define FF_PROFILE_H264_HIGH 100 ++#define FF_PROFILE_H264_HIGH_10 110 ++#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA) ++#define FF_PROFILE_H264_MULTIVIEW_HIGH 118 ++#define FF_PROFILE_H264_HIGH_422 122 ++#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA) ++#define FF_PROFILE_H264_STEREO_HIGH 128 ++#define FF_PROFILE_H264_HIGH_444 144 ++#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244 ++#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA) ++#define FF_PROFILE_H264_CAVLC_444 44 ++ ++#define FF_PROFILE_VC1_SIMPLE 0 ++#define FF_PROFILE_VC1_MAIN 1 ++#define FF_PROFILE_VC1_COMPLEX 2 ++#define FF_PROFILE_VC1_ADVANCED 3 ++ ++#define FF_PROFILE_MPEG4_SIMPLE 0 ++#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1 ++#define FF_PROFILE_MPEG4_CORE 2 ++#define FF_PROFILE_MPEG4_MAIN 3 ++#define FF_PROFILE_MPEG4_N_BIT 4 ++#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5 ++#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 ++#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 ++#define FF_PROFILE_MPEG4_HYBRID 8 ++#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 ++#define FF_PROFILE_MPEG4_CORE_SCALABLE 10 ++#define FF_PROFILE_MPEG4_ADVANCED_CODING 11 ++#define FF_PROFILE_MPEG4_ADVANCED_CORE 12 ++#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 ++#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14 ++#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15 ++ ++#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 1 ++#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 2 ++#define FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 32768 ++#define FF_PROFILE_JPEG2000_DCINEMA_2K 3 ++#define FF_PROFILE_JPEG2000_DCINEMA_4K 4 ++ ++#define FF_PROFILE_VP9_0 0 ++#define FF_PROFILE_VP9_1 1 ++#define FF_PROFILE_VP9_2 2 ++#define FF_PROFILE_VP9_3 3 ++ ++#define FF_PROFILE_HEVC_MAIN 1 ++#define FF_PROFILE_HEVC_MAIN_10 2 ++#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3 ++#define FF_PROFILE_HEVC_REXT 4 ++ ++#define FF_PROFILE_AV1_MAIN 0 ++#define FF_PROFILE_AV1_HIGH 1 ++#define FF_PROFILE_AV1_PROFESSIONAL 2 ++ ++#define FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT 0xc0 ++#define FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT 0xc1 ++#define FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT 0xc2 ++#define FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS 0xc3 ++#define FF_PROFILE_MJPEG_JPEG_LS 0xf7 ++ ++#define FF_PROFILE_SBC_MSBC 1 ++ ++ /** ++ * level ++ * - encoding: Set by user. ++ * - decoding: Set by libavcodec. ++ */ ++ int level; ++#define FF_LEVEL_UNKNOWN -99 ++ ++ void *priv_data; ++ ++} AVCodecContext; ++ ++/** ++ * @ingroup lavc_decoding ++ * Required number of additionally allocated bytes at the end of the input bitstream for decoding. ++ * This is mainly needed because some optimized bitstream readers read ++ * 32 or 64 bit at once and could read over the end.
++ * Note: If the first 23 bits of the additional bytes are not 0, then damaged ++ * MPEG bitstreams could cause overread and segfault. ++ */ ++#define AV_INPUT_BUFFER_PADDING_SIZE 64 ++ ++ ++typedef struct AVPacket { ++ ++ uint8_t *data; ++ unsigned int data_pa; /*physical address of data.*/ ++ int size; ++ ++} AVPacket; ++ ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/bswap.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/bswap.h +new file mode 100644 +index 000000000..e63a3eab3 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/bswap.h +@@ -0,0 +1,54 @@ ++#ifndef AVUTIL_BSWAP_H ++#define AVUTIL_BSWAP_H ++ ++//#include "libavutil/avconfig.h" ++//#include "attributes.h" ++ ++#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) ++#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) ++#define AV_BSWAP64C(x) (AV_BSWAP32C(x) << 32 | AV_BSWAP32C((x) >> 32)) ++ ++#define AV_BSWAPC(s, x) AV_BSWAP##s##C(x) ++ ++#ifndef av_bswap16 ++static inline const uint16_t av_bswap16(uint16_t x) ++{ ++ x= (x>>8) | (x<<8); ++ return x; ++} ++#endif ++ ++#ifndef av_bswap32 ++static inline const uint32_t av_bswap32(uint32_t x) ++{ ++ return AV_BSWAP32C(x); ++} ++#endif ++ ++#ifndef av_bswap64 ++static inline uint64_t const av_bswap64(uint64_t x) ++{ ++ return (uint64_t)av_bswap32(x) << 32 | av_bswap32(x >> 32); ++} ++#endif ++ ++// be2ne ... big-endian to native-endian ++// le2ne ... little-endian to native-endian ++ ++#define av_be2ne16(x) av_bswap16(x) ++#define av_be2ne32(x) av_bswap32(x) ++#define av_be2ne64(x) av_bswap64(x) ++#define av_le2ne16(x) (x) ++#define av_le2ne32(x) (x) ++#define av_le2ne64(x) (x) ++#define AV_BE2NEC(s, x) AV_BSWAPC(s, x) ++#define AV_LE2NEC(s, x) (x) ++ ++#define AV_BE2NE16C(x) AV_BE2NEC(16, x) ++#define AV_BE2NE32C(x) AV_BE2NEC(32, x) ++#define AV_BE2NE64C(x) AV_BE2NEC(64, x) ++#define AV_LE2NE16C(x) AV_LE2NEC(16, x) ++#define AV_LE2NE32C(x) AV_LE2NEC(32, x) ++#define AV_LE2NE64C(x) AV_LE2NEC(64, x) ++ ++#endif /* AVUTIL_BSWAP_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/buffer.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/buffer.h +new file mode 100644 +index 000000000..24b3b5dcf +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/buffer.h +@@ -0,0 +1,70 @@ ++#ifndef __BUFFER_H__ ++#define __BUFFER_H__ ++ ++#include "devmem.h" ++ ++#define DMA_TO_DEVICE DEVMEM_SYNC_TO_DEVICE ++#define DMA_FROM_DEVICE DEVMEM_SYNC_FROM_DEVICE ++ ++struct devmem_ctx; ++ ++typedef struct devmem_ops { ++ int (*alloc)(struct devmem_ctx *ctx, devmem_info_t *di); ++ void (*free)(struct devmem_ctx *ctx, devmem_info_t *di); ++ void (*sync)(struct devmem_ctx *ctx, devmem_info_t *di); ++ ++} devmem_ops_t; ++ ++typedef struct devmem_ctx { ++ int fd; ++ devmem_ops_t *ops; ++ struct device *dev; ++} devmem_ctx_t; ++ ++int devmem_ctx_init(devmem_ctx_t *ctx, devmem_ops_t *ops); ++void devmem_ctx_uninit(devmem_ctx_t *ctx); ++ ++ ++ ++ ++typedef struct AVBuffer { ++ unsigned char *buffer; ++ unsigned int buffer_pa; /* physical address of buffer. */ ++ unsigned int size; ++ ++ devmem_info_t di; /*mem info used by devmem allocator.*/ ++} AVBuffer; ++ ++ ++ ++ ++/* ++ * create: use exists buffer fill AVBuffer struct. ++ * alloc: allocate for AVBuffer. ++ * free: free AVBuffer. ++ * ++ * */ ++ ++ ++/** ++ * @brief 使用已ç»åˆ†é…好的内存,创建AVBuffer结构体. ++ * caller: å¿…é¡»è¦ä¿è¯å†…存有效. ++ * ++ * @param va va æ˜¯è™šæ‹Ÿåœ°å€ ++ * @param pa pa 是对应的物ç†åœ°å€ï¼Œç»™åˆ°dma使用. ++ * @param size ++ * @param buf 输出buf. ++ * ++ * @return ++ */ ++AVBuffer *av_buffer_create(char *va, unsigned int pa, unsigned int size); ++void av_buffer_del(AVBuffer *buf); ++ ++AVBuffer *av_buffer_alloc(devmem_ctx_t *ctx, unsigned int size); ++ ++ ++void av_buffer_sync(devmem_ctx_t *ctx, AVBuffer *buf, int dir); ++ ++ ++void av_buffer_free(devmem_ctx_t *ctx, AVBuffer *buf); ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/bytestream.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/bytestream.h +new file mode 100644 +index 000000000..b11e725fb +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/bytestream.h +@@ -0,0 +1,358 @@ ++#ifndef AVCODEC_BYTESTREAM_H ++#define AVCODEC_BYTESTREAM_H ++ ++#ifdef __KERNEL__ ++#include ++#else ++#include ++#include ++#endif ++ ++#include "avassert.h" ++#include "common.h" ++#include "intreadwrite.h" ++ ++typedef struct GetByteContext { ++ const uint8_t *buffer, *buffer_end, *buffer_start; ++} GetByteContext; ++ ++typedef struct PutByteContext { ++ uint8_t *buffer, *buffer_end, *buffer_start; ++ int eof; ++} PutByteContext; ++ ++#define DEF(type, name, bytes, read, write) \ ++static inline type bytestream_get_ ## name(const uint8_t **b) \ ++{ \ ++ (*b) += bytes; \ ++ return read(*b - bytes); \ ++} \ ++static inline void bytestream_put_ ## name(uint8_t **b, \ ++ const type value) \ ++{ \ ++ write(*b, value); \ ++ (*b) += bytes; \ ++} \ ++static inline void bytestream2_put_ ## name ## u(PutByteContext *p, \ ++ const type value) \ ++{ \ ++ bytestream_put_ ## name(&p->buffer, value); \ ++} \ ++static inline void bytestream2_put_ ## name(PutByteContext *p, \ ++ const type value) \ ++{ \ ++ if (!p->eof && (p->buffer_end - p->buffer >= bytes)) { \ ++ write(p->buffer, value); \ ++ p->buffer += bytes; \ ++ } else \ ++ p->eof = 1; \ ++} \ ++static inline type bytestream2_get_ ## name ## u(GetByteContext *g) \ ++{ \ ++ return bytestream_get_ ## name(&g->buffer); \ ++} \ ++static inline type bytestream2_get_ ## name(GetByteContext *g) \ ++{ \ ++ if (g->buffer_end - g->buffer < bytes) { \ ++ g->buffer = g->buffer_end; \ ++ return 0; \ ++ } \ ++ return bytestream2_get_ ## name ## u(g); \ ++} \ ++static inline type bytestream2_peek_ ## name(GetByteContext *g) \ ++{ \ ++ if (g->buffer_end - g->buffer < bytes) \ ++ return 0; \ ++ return read(g->buffer); \ ++} ++ ++DEF(uint64_t, le64, 8, AV_RL64, AV_WL64) ++DEF(unsigned int, le32, 4, AV_RL32, AV_WL32) ++DEF(unsigned int, le24, 3, AV_RL24, AV_WL24) ++DEF(unsigned int, le16, 2, AV_RL16, AV_WL16) ++DEF(uint64_t, be64, 8, AV_RB64, AV_WB64) ++DEF(unsigned int, be32, 4, AV_RB32, AV_WB32) ++DEF(unsigned int, be24, 3, AV_RB24, AV_WB24) ++DEF(unsigned int, be16, 2, AV_RB16, AV_WB16) ++DEF(unsigned int, byte, 1, AV_RB8 , AV_WB8) ++ ++#if AV_HAVE_BIGENDIAN ++# define bytestream2_get_ne16 bytestream2_get_be16 ++# define bytestream2_get_ne24 bytestream2_get_be24 ++# define bytestream2_get_ne32 bytestream2_get_be32 ++# define bytestream2_get_ne64 bytestream2_get_be64 ++# define bytestream2_get_ne16u bytestream2_get_be16u ++# define bytestream2_get_ne24u bytestream2_get_be24u ++# define bytestream2_get_ne32u bytestream2_get_be32u ++# define bytestream2_get_ne64u bytestream2_get_be64u ++# define bytestream2_put_ne16 bytestream2_put_be16 ++# define bytestream2_put_ne24 bytestream2_put_be24 ++# define bytestream2_put_ne32 bytestream2_put_be32 ++# define bytestream2_put_ne64 bytestream2_put_be64 ++# define bytestream2_peek_ne16 bytestream2_peek_be16 ++# define bytestream2_peek_ne24 bytestream2_peek_be24 ++# define bytestream2_peek_ne32 bytestream2_peek_be32 ++# define bytestream2_peek_ne64 bytestream2_peek_be64 ++#else ++# define bytestream2_get_ne16 bytestream2_get_le16 ++# define bytestream2_get_ne24 bytestream2_get_le24 ++# define bytestream2_get_ne32 bytestream2_get_le32 ++# define bytestream2_get_ne64 bytestream2_get_le64 ++# define bytestream2_get_ne16u bytestream2_get_le16u ++# define bytestream2_get_ne24u bytestream2_get_le24u ++# define bytestream2_get_ne32u bytestream2_get_le32u ++# define bytestream2_get_ne64u bytestream2_get_le64u ++# define bytestream2_put_ne16 bytestream2_put_le16 ++# define bytestream2_put_ne24 bytestream2_put_le24 ++# define bytestream2_put_ne32 bytestream2_put_le32 ++# define bytestream2_put_ne64 bytestream2_put_le64 ++# define bytestream2_peek_ne16 bytestream2_peek_le16 ++# define bytestream2_peek_ne24 bytestream2_peek_le24 ++# define bytestream2_peek_ne32 bytestream2_peek_le32 ++# define bytestream2_peek_ne64 bytestream2_peek_le64 ++#endif ++ ++static inline void bytestream2_init(GetByteContext *g, ++ const uint8_t *buf, ++ int buf_size) ++{ ++ av_assert0(buf_size >= 0); ++ g->buffer = buf; ++ g->buffer_start = buf; ++ g->buffer_end = buf + buf_size; ++} ++ ++static inline void bytestream2_init_writer(PutByteContext *p, ++ uint8_t *buf, ++ int buf_size) ++{ ++ av_assert0(buf_size >= 0); ++ p->buffer = buf; ++ p->buffer_start = buf; ++ p->buffer_end = buf + buf_size; ++ p->eof = 0; ++} ++ ++static inline unsigned int bytestream2_get_bytes_left(GetByteContext *g) ++{ ++ return g->buffer_end - g->buffer; ++} ++ ++static inline unsigned int bytestream2_get_bytes_left_p(PutByteContext *p) ++{ ++ return p->buffer_end - p->buffer; ++} ++ ++static inline void bytestream2_skip(GetByteContext *g, ++ unsigned int size) ++{ ++ g->buffer += FFMIN(g->buffer_end - g->buffer, size); ++} ++ ++static inline void bytestream2_skipu(GetByteContext *g, ++ unsigned int size) ++{ ++ g->buffer += size; ++} ++ ++static inline void bytestream2_skip_p(PutByteContext *p, ++ unsigned int size) ++{ ++ int size2; ++ if (p->eof) ++ return; ++ size2 = FFMIN(p->buffer_end - p->buffer, size); ++ if (size2 != size) ++ p->eof = 1; ++ p->buffer += size2; ++} ++ ++static inline int bytestream2_tell(GetByteContext *g) ++{ ++ return (int)(g->buffer - g->buffer_start); ++} ++ ++static inline int bytestream2_tell_p(PutByteContext *p) ++{ ++ return (int)(p->buffer - p->buffer_start); ++} ++ ++static inline int bytestream2_size(GetByteContext *g) ++{ ++ return (int)(g->buffer_end - g->buffer_start); ++} ++ ++static inline int bytestream2_size_p(PutByteContext *p) ++{ ++ return (int)(p->buffer_end - p->buffer_start); ++} ++ ++static inline int bytestream2_seek(GetByteContext *g, ++ int offset, ++ int whence) ++{ ++ switch (whence) { ++ case SEEK_CUR: ++ offset = av_clip(offset, -(g->buffer - g->buffer_start), ++ g->buffer_end - g->buffer); ++ g->buffer += offset; ++ break; ++ case SEEK_END: ++ offset = av_clip(offset, -(g->buffer_end - g->buffer_start), 0); ++ g->buffer = g->buffer_end + offset; ++ break; ++ case SEEK_SET: ++ offset = av_clip(offset, 0, g->buffer_end - g->buffer_start); ++ g->buffer = g->buffer_start + offset; ++ break; ++ default: ++ return AVERROR(EINVAL); ++ } ++ return bytestream2_tell(g); ++} ++ ++static inline int bytestream2_seek_p(PutByteContext *p, ++ int offset, ++ int whence) ++{ ++ p->eof = 0; ++ switch (whence) { ++ case SEEK_CUR: ++ if (p->buffer_end - p->buffer < offset) ++ p->eof = 1; ++ offset = av_clip(offset, -(p->buffer - p->buffer_start), ++ p->buffer_end - p->buffer); ++ p->buffer += offset; ++ break; ++ case SEEK_END: ++ if (offset > 0) ++ p->eof = 1; ++ offset = av_clip(offset, -(p->buffer_end - p->buffer_start), 0); ++ p->buffer = p->buffer_end + offset; ++ break; ++ case SEEK_SET: ++ if (p->buffer_end - p->buffer_start < offset) ++ p->eof = 1; ++ offset = av_clip(offset, 0, p->buffer_end - p->buffer_start); ++ p->buffer = p->buffer_start + offset; ++ break; ++ default: ++ return AVERROR(EINVAL); ++ } ++ return bytestream2_tell_p(p); ++} ++ ++static inline unsigned int bytestream2_get_buffer(GetByteContext *g, ++ uint8_t *dst, ++ unsigned int size) ++{ ++ int size2 = FFMIN(g->buffer_end - g->buffer, size); ++ memcpy(dst, g->buffer, size2); ++ g->buffer += size2; ++ return size2; ++} ++ ++static inline unsigned int bytestream2_get_bufferu(GetByteContext *g, ++ uint8_t *dst, ++ unsigned int size) ++{ ++ memcpy(dst, g->buffer, size); ++ g->buffer += size; ++ return size; ++} ++ ++static inline unsigned int bytestream2_put_buffer(PutByteContext *p, ++ const uint8_t *src, ++ unsigned int size) ++{ ++ int size2; ++ if (p->eof) ++ return 0; ++ size2 = FFMIN(p->buffer_end - p->buffer, size); ++ if (size2 != size) ++ p->eof = 1; ++ memcpy(p->buffer, src, size2); ++ p->buffer += size2; ++ return size2; ++} ++ ++static inline unsigned int bytestream2_put_bufferu(PutByteContext *p, ++ const uint8_t *src, ++ unsigned int size) ++{ ++ memcpy(p->buffer, src, size); ++ p->buffer += size; ++ return size; ++} ++ ++static inline void bytestream2_set_buffer(PutByteContext *p, ++ const uint8_t c, ++ unsigned int size) ++{ ++ int size2; ++ if (p->eof) ++ return; ++ size2 = FFMIN(p->buffer_end - p->buffer, size); ++ if (size2 != size) ++ p->eof = 1; ++ memset(p->buffer, c, size2); ++ p->buffer += size2; ++} ++ ++static inline void bytestream2_set_bufferu(PutByteContext *p, ++ const uint8_t c, ++ unsigned int size) ++{ ++ memset(p->buffer, c, size); ++ p->buffer += size; ++} ++ ++static inline unsigned int bytestream2_get_eof(PutByteContext *p) ++{ ++ return p->eof; ++} ++ ++static inline unsigned int bytestream2_copy_bufferu(PutByteContext *p, ++ GetByteContext *g, ++ unsigned int size) ++{ ++ memcpy(p->buffer, g->buffer, size); ++ p->buffer += size; ++ g->buffer += size; ++ return size; ++} ++ ++static inline unsigned int bytestream2_copy_buffer(PutByteContext *p, ++ GetByteContext *g, ++ unsigned int size) ++{ ++ int size2; ++ ++ if (p->eof) ++ return 0; ++ size = FFMIN(g->buffer_end - g->buffer, size); ++ size2 = FFMIN(p->buffer_end - p->buffer, size); ++ if (size2 != size) ++ p->eof = 1; ++ ++ return bytestream2_copy_bufferu(p, g, size2); ++} ++ ++static inline unsigned int bytestream_get_buffer(const uint8_t **b, ++ uint8_t *dst, ++ unsigned int size) ++{ ++ memcpy(dst, *b, size); ++ (*b) += size; ++ return size; ++} ++ ++static inline void bytestream_put_buffer(uint8_t **b, ++ const uint8_t *src, ++ unsigned int size) ++{ ++ memcpy(*b, src, size); ++ (*b) += size; ++} ++ ++#endif /* AVCODEC_BYTESTREAM_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/common.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/common.h +new file mode 100644 +index 000000000..11dad8f04 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/common.h +@@ -0,0 +1,476 @@ ++#ifndef AVUTIL_COMMON_H ++#define AVUTIL_COMMON_H ++ ++#ifdef __KERNEL__ ++#include ++//#include ++#include ++#include ++#include ++//#include "pstdint.h" ++ ++typedef long intptr_t; ++#define printf printk ++ ++# define INT16_MAX (32767) ++ ++#else ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++//#include "attributes.h" ++//#include "macros.h" ++//#include "version.h" ++//#include "libavutil/avconfig.h" ++ ++# define AV_NE(be, le) (le) ++ ++//rounded division & shift ++#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) ++/* assume b>0 */ ++#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) ++/* Fast a/(1<=0 and b>=0 */ ++#define AV_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \ ++ : ((a) + (1<<(b)) - 1) >> (b)) ++/* Backwards compat. */ ++#define FF_CEIL_RSHIFT AV_CEIL_RSHIFT ++ ++#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b)) ++#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b)) ++ ++/** ++ * Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they ++ * are not representable as absolute values of their type. This is the same ++ * as with *abs() ++ * @see FFNABS() ++ */ ++#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) ++#define FFSIGN(a) ((a) > 0 ? 1 : -1) ++ ++/** ++ * Negative Absolute value. ++ * this works for all integers of all types. ++ * As with many macros, this evaluates its argument twice, it thus must not have ++ * a sideeffect, that is FFNABS(x++) has undefined behavior. ++ */ ++#define FFNABS(a) ((a) <= 0 ? (a) : (-(a))) ++ ++/** ++ * Comparator. ++ * For two numerical expressions x and y, gives 1 if x > y, -1 if x < y, and 0 ++ * if x == y. This is useful for instance in a qsort comparator callback. ++ * Furthermore, compilers are able to optimize this to branchless code, and ++ * there is no risk of overflow with signed types. ++ * As with many macros, this evaluates its argument multiple times, it thus ++ * must not have a side-effect. ++ */ ++#define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y))) ++ ++#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) ++#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) ++#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) ++#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) ++ ++#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) ++#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) ++ ++/* misc math functions */ ++ ++#ifdef HAVE_AV_CONFIG_H ++# include "config.h" ++# include "intmath.h" ++#endif ++ ++/* Pull in unguarded fallback defines at the end of this file. */ ++#include "common.h" ++ ++#ifndef av_log2 ++const int av_log2(unsigned v); ++#endif ++ ++#ifndef av_log2_16bit ++const int av_log2_16bit(unsigned v); ++#endif ++ ++/** ++ * Clip a signed integer value into the amin-amax range. ++ * @param a value to clip ++ * @param amin minimum value of the clip range ++ * @param amax maximum value of the clip range ++ * @return clipped value ++ */ ++static inline const int av_clip_c(int a, int amin, int amax) ++{ ++#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 ++ if (amin > amax) abort(); ++#endif ++ if (a < amin) return amin; ++ else if (a > amax) return amax; ++ else return a; ++} ++ ++/** ++ * Clip a signed 64bit integer value into the amin-amax range. ++ * @param a value to clip ++ * @param amin minimum value of the clip range ++ * @param amax maximum value of the clip range ++ * @return clipped value ++ */ ++static inline const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax) ++{ ++#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 ++ if (amin > amax) abort(); ++#endif ++ if (a < amin) return amin; ++ else if (a > amax) return amax; ++ else return a; ++} ++ ++/** ++ * Clip a signed integer value into the 0-255 range. ++ * @param a value to clip ++ * @return clipped value ++ */ ++static inline const uint8_t av_clip_uint8_c(int a) ++{ ++ if (a&(~0xFF)) return (~a)>>31; ++ else return a; ++} ++ ++/** ++ * Clip a signed integer value into the -128,127 range. ++ * @param a value to clip ++ * @return clipped value ++ */ ++static inline const int8_t av_clip_int8_c(int a) ++{ ++ if ((a+0x80U) & ~0xFF) return (a>>31) ^ 0x7F; ++ else return a; ++} ++ ++/** ++ * Clip a signed integer value into the 0-65535 range. ++ * @param a value to clip ++ * @return clipped value ++ */ ++static inline const uint16_t av_clip_uint16_c(int a) ++{ ++ if (a&(~0xFFFF)) return (~a)>>31; ++ else return a; ++} ++ ++/** ++ * Clip a signed integer value into the -32768,32767 range. ++ * @param a value to clip ++ * @return clipped value ++ */ ++static inline const int16_t av_clip_int16_c(int a) ++{ ++ if ((a+0x8000U) & ~0xFFFF) return (a>>31) ^ 0x7FFF; ++ else return a; ++} ++ ++/** ++ * Clip a signed integer into the -(2^p),(2^p-1) range. ++ * @param a value to clip ++ * @param p bit position to clip at ++ * @return clipped value ++ */ ++static inline const int av_clip_intp2_c(int a, int p) ++{ ++ if (((unsigned)a + (1 << p)) & ~((2 << p) - 1)) ++ return (a >> 31) ^ ((1 << p) - 1); ++ else ++ return a; ++} ++ ++/** ++ * Clip a signed integer to an unsigned power of two range. ++ * @param a value to clip ++ * @param p bit position to clip at ++ * @return clipped value ++ */ ++static inline const unsigned av_clip_uintp2_c(int a, int p) ++{ ++ if (a & ~((1<> 31 & ((1<= 2 ++ if (amin > amax) abort(); ++#endif ++ if (a < amin) return amin; ++ else if (a > amax) return amax; ++ else return a; ++} ++ ++/** ++ * Clip a double value into the amin-amax range. ++ * @param a value to clip ++ * @param amin minimum value of the clip range ++ * @param amax maximum value of the clip range ++ * @return clipped value ++ */ ++static inline const double av_clipd_c(double a, double amin, double amax) ++{ ++#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 ++ if (amin > amax) abort(); ++#endif ++ if (a < amin) return amin; ++ else if (a > amax) return amax; ++ else return a; ++} ++ ++/** Compute ceil(log2(x)). ++ * @param x value used to compute ceil(log2(x)) ++ * @return computed ceiling of log2(x) ++ */ ++static inline const int av_ceil_log2_c(int x) ++{ ++ return av_log2((x - 1) << 1); ++} ++ ++/** ++ * Count number of bits set to one in x ++ * @param x value to count bits of ++ * @return the number of bits set to one in x ++ */ ++static inline const int av_popcount_c(uint32_t x) ++{ ++ x -= (x >> 1) & 0x55555555; ++ x = (x & 0x33333333) + ((x >> 2) & 0x33333333); ++ x = (x + (x >> 4)) & 0x0F0F0F0F; ++ x += x >> 8; ++ return (x + (x >> 16)) & 0x3F; ++} ++ ++/** ++ * Count number of bits set to one in x ++ * @param x value to count bits of ++ * @return the number of bits set to one in x ++ */ ++static inline const int av_popcount64_c(uint64_t x) ++{ ++ return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32)); ++} ++ ++static inline const int av_parity_c(uint32_t v) ++{ ++ return av_popcount(v) & 1; ++} ++ ++#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24)) ++#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24)) ++ ++/** ++ * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form. ++ * ++ * @param val Output value, must be an lvalue of type uint32_t. ++ * @param GET_BYTE Expression reading one byte from the input. ++ * Evaluated up to 7 times (4 for the currently ++ * assigned Unicode range). With a memory buffer ++ * input, this could be *ptr++. ++ * @param ERROR Expression to be evaluated on invalid input, ++ * typically a goto statement. ++ * ++ * @warning ERROR should not contain a loop control statement which ++ * could interact with the internal while loop, and should force an ++ * exit from the macro code (e.g. through a goto or a return) in order ++ * to prevent undefined results. ++ */ ++#define GET_UTF8(val, GET_BYTE, ERROR)\ ++ val= (GET_BYTE);\ ++ {\ ++ uint32_t top = (val & 128) >> 1;\ ++ if ((val & 0xc0) == 0x80 || val >= 0xFE)\ ++ ERROR\ ++ while (val & top) {\ ++ int tmp= (GET_BYTE) - 128;\ ++ if(tmp>>6)\ ++ ERROR\ ++ val= (val<<6) + tmp;\ ++ top <<= 5;\ ++ }\ ++ val &= (top << 1) - 1;\ ++ } ++ ++/** ++ * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form. ++ * ++ * @param val Output value, must be an lvalue of type uint32_t. ++ * @param GET_16BIT Expression returning two bytes of UTF-16 data converted ++ * to native byte order. Evaluated one or two times. ++ * @param ERROR Expression to be evaluated on invalid input, ++ * typically a goto statement. ++ */ ++#define GET_UTF16(val, GET_16BIT, ERROR)\ ++ val = GET_16BIT;\ ++ {\ ++ unsigned int hi = val - 0xD800;\ ++ if (hi < 0x800) {\ ++ val = GET_16BIT - 0xDC00;\ ++ if (val > 0x3FFU || hi > 0x3FFU)\ ++ ERROR\ ++ val += (hi<<10) + 0x10000;\ ++ }\ ++ }\ ++ ++/** ++ * @def PUT_UTF8(val, tmp, PUT_BYTE) ++ * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long). ++ * @param val is an input-only argument and should be of type uint32_t. It holds ++ * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If ++ * val is given as a function it is executed only once. ++ * @param tmp is a temporary variable and should be of type uint8_t. It ++ * represents an intermediate value during conversion that is to be ++ * output by PUT_BYTE. ++ * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination. ++ * It could be a function or a statement, and uses tmp as the input byte. ++ * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be ++ * executed up to 4 times for values in the valid UTF-8 range and up to ++ * 7 times in the general case, depending on the length of the converted ++ * Unicode character. ++ */ ++#define PUT_UTF8(val, tmp, PUT_BYTE)\ ++ {\ ++ int bytes, shift;\ ++ uint32_t in = val;\ ++ if (in < 0x80) {\ ++ tmp = in;\ ++ PUT_BYTE\ ++ } else {\ ++ bytes = (av_log2(in) + 4) / 5;\ ++ shift = (bytes - 1) * 6;\ ++ tmp = (256 - (256 >> bytes)) | (in >> shift);\ ++ PUT_BYTE\ ++ while (shift >= 6) {\ ++ shift -= 6;\ ++ tmp = 0x80 | ((in >> shift) & 0x3f);\ ++ PUT_BYTE\ ++ }\ ++ }\ ++ } ++ ++/** ++ * @def PUT_UTF16(val, tmp, PUT_16BIT) ++ * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes). ++ * @param val is an input-only argument and should be of type uint32_t. It holds ++ * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If ++ * val is given as a function it is executed only once. ++ * @param tmp is a temporary variable and should be of type uint16_t. It ++ * represents an intermediate value during conversion that is to be ++ * output by PUT_16BIT. ++ * @param PUT_16BIT writes the converted UTF-16 data to any proper destination ++ * in desired endianness. It could be a function or a statement, and uses tmp ++ * as the input byte. For example, PUT_BYTE could be "*output++ = tmp;" ++ * PUT_BYTE will be executed 1 or 2 times depending on input character. ++ */ ++#define PUT_UTF16(val, tmp, PUT_16BIT)\ ++ {\ ++ uint32_t in = val;\ ++ if (in < 0x10000) {\ ++ tmp = in;\ ++ PUT_16BIT\ ++ } else {\ ++ tmp = 0xD800 | ((in - 0x10000) >> 10);\ ++ PUT_16BIT\ ++ tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\ ++ PUT_16BIT\ ++ }\ ++ }\ ++ ++ ++ ++#include "mem.h" ++ ++#ifdef HAVE_AV_CONFIG_H ++# include "internal.h" ++#endif /* HAVE_AV_CONFIG_H */ ++ ++#endif /* AVUTIL_COMMON_H */ ++ ++/* ++ * The following definitions are outside the multiple inclusion guard ++ * to ensure they are immediately available in intmath.h. ++ */ ++#ifndef av_ceil_log2 ++# define av_ceil_log2 av_ceil_log2_c ++#endif ++#ifndef av_clip ++# define av_clip av_clip_c ++#endif ++#ifndef av_clip64 ++# define av_clip64 av_clip64_c ++#endif ++#ifndef av_clip_uint8 ++# define av_clip_uint8 av_clip_uint8_c ++#endif ++#ifndef av_clip_int8 ++# define av_clip_int8 av_clip_int8_c ++#endif ++#ifndef av_clip_uint16 ++# define av_clip_uint16 av_clip_uint16_c ++#endif ++#ifndef av_clip_int16 ++# define av_clip_int16 av_clip_int16_c ++#endif ++#ifndef av_clip_intp2 ++# define av_clip_intp2 av_clip_intp2_c ++#endif ++#ifndef av_clip_uintp2 ++# define av_clip_uintp2 av_clip_uintp2_c ++#endif ++#ifndef av_mod_uintp2 ++# define av_mod_uintp2 av_mod_uintp2_c ++#endif ++#ifndef av_sat_dadd32 ++# define av_sat_dadd32 av_sat_dadd32_c ++#endif ++#ifndef av_sat_sub32 ++# define av_sat_sub32 av_sat_sub32_c ++#endif ++#ifndef av_sat_dsub32 ++# define av_sat_dsub32 av_sat_dsub32_c ++#endif ++#ifndef av_clipf ++# define av_clipf av_clipf_c ++#endif ++#ifndef av_clipd ++# define av_clipd av_clipd_c ++#endif ++#ifndef av_popcount ++# define av_popcount av_popcount_c ++#endif ++#ifndef av_popcount64 ++# define av_popcount64 av_popcount64_c ++#endif ++#ifndef av_parity ++# define av_parity av_parity_c ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/devmem.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/devmem.h +new file mode 100644 +index 000000000..2277659b0 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/devmem.h +@@ -0,0 +1,26 @@ ++#ifndef __DEVMEM_H__ ++#define __DEVMEM_H__ ++ ++typedef struct devmem_info { ++ unsigned long userptr; ++ unsigned long paddr; ++ unsigned long length; ++ unsigned long kva; ++ int coherent; ++ int sync_dir; ++} devmem_info_t; ++ ++#define DEVMEM_MAGIC 'D' ++ ++#define DEVMEM_SYNC_NONE 0 ++#define DEVMEM_SYNC_TO_DEVICE 1 ++#define DEVMEM_SYNC_FROM_DEVICE 2 ++ ++#define DEVMEM_ALLOC _IOWR(DEVMEM_MAGIC, 10, devmem_info_t) ++#define DEVMEM_FREE _IOW(DEVMEM_MAGIC, 11, devmem_info_t) ++#define DEVMEM_SYNC _IOW(DEVMEM_MAGIC, 12, devmem_info_t) ++ ++ ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/error.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/error.h +new file mode 100644 +index 000000000..fb538d122 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/error.h +@@ -0,0 +1,108 @@ ++#ifndef AVUTIL_ERROR_H ++#define AVUTIL_ERROR_H ++ ++#ifdef __KERNEL__ ++#include ++#include ++#else ++#include ++#include ++#endif ++ ++/** ++ * @addtogroup lavu_error ++ * ++ * @{ ++ */ ++ ++ ++/* error handling */ ++#if EDOM > 0 ++#define AVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. ++#define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. ++#else ++/* Some platforms have E* and errno already negated. */ ++#define AVERROR(e) (e) ++#define AVUNERROR(e) (e) ++#endif ++ ++#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d)) ++ ++#define AVERROR_BSF_NOT_FOUND FFERRTAG(0xF8,'B','S','F') ///< Bitstream filter not found ++#define AVERROR_BUG FFERRTAG( 'B','U','G','!') ///< Internal bug, also see AVERROR_BUG2 ++#define AVERROR_BUFFER_TOO_SMALL FFERRTAG( 'B','U','F','S') ///< Buffer too small ++#define AVERROR_DECODER_NOT_FOUND FFERRTAG(0xF8,'D','E','C') ///< Decoder not found ++#define AVERROR_DEMUXER_NOT_FOUND FFERRTAG(0xF8,'D','E','M') ///< Demuxer not found ++#define AVERROR_ENCODER_NOT_FOUND FFERRTAG(0xF8,'E','N','C') ///< Encoder not found ++#define AVERROR_EOF FFERRTAG( 'E','O','F',' ') ///< End of file ++#define AVERROR_EXIT FFERRTAG( 'E','X','I','T') ///< Immediate exit was requested; the called function should not be restarted ++#define AVERROR_EXTERNAL FFERRTAG( 'E','X','T',' ') ///< Generic error in an external library ++#define AVERROR_FILTER_NOT_FOUND FFERRTAG(0xF8,'F','I','L') ///< Filter not found ++#define AVERROR_INVALIDDATA FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input ++#define AVERROR_MUXER_NOT_FOUND FFERRTAG(0xF8,'M','U','X') ///< Muxer not found ++#define AVERROR_OPTION_NOT_FOUND FFERRTAG(0xF8,'O','P','T') ///< Option not found ++#define AVERROR_PATCHWELCOME FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome ++#define AVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found ++ ++#define AVERROR_STREAM_NOT_FOUND FFERRTAG(0xF8,'S','T','R') ///< Stream not found ++/** ++ * This is semantically identical to AVERROR_BUG ++ * it has been introduced in Libav after our AVERROR_BUG and with a modified value. ++ */ ++#define AVERROR_BUG2 FFERRTAG( 'B','U','G',' ') ++#define AVERROR_UNKNOWN FFERRTAG( 'U','N','K','N') ///< Unknown error, typically from an external library ++#define AVERROR_EXPERIMENTAL (-0x2bb2afa8) ///< Requested feature is flagged experimental. Set strict_std_compliance if you really want to use it. ++#define AVERROR_INPUT_CHANGED (-0x636e6701) ///< Input changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_OUTPUT_CHANGED) ++#define AVERROR_OUTPUT_CHANGED (-0x636e6702) ///< Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED) ++/* HTTP & RTSP errors */ ++#define AVERROR_HTTP_BAD_REQUEST FFERRTAG(0xF8,'4','0','0') ++#define AVERROR_HTTP_UNAUTHORIZED FFERRTAG(0xF8,'4','0','1') ++#define AVERROR_HTTP_FORBIDDEN FFERRTAG(0xF8,'4','0','3') ++#define AVERROR_HTTP_NOT_FOUND FFERRTAG(0xF8,'4','0','4') ++#define AVERROR_HTTP_OTHER_4XX FFERRTAG(0xF8,'4','X','X') ++#define AVERROR_HTTP_SERVER_ERROR FFERRTAG(0xF8,'5','X','X') ++ ++#define AV_ERROR_MAX_STRING_SIZE 64 ++ ++/** ++ * Put a description of the AVERROR code errnum in errbuf. ++ * In case of failure the global variable errno is set to indicate the ++ * error. Even in case of failure av_strerror() will print a generic ++ * error message indicating the errnum provided to errbuf. ++ * ++ * @param errnum error code to describe ++ * @param errbuf buffer to which description is written ++ * @param errbuf_size the size in bytes of errbuf ++ * @return 0 on success, a negative value if a description for errnum ++ * cannot be found ++ */ ++int av_strerror(int errnum, char *errbuf, size_t errbuf_size); ++ ++/** ++ * Fill the provided buffer with a string containing an error string ++ * corresponding to the AVERROR code errnum. ++ * ++ * @param errbuf a buffer ++ * @param errbuf_size size in bytes of errbuf ++ * @param errnum error code to describe ++ * @return the buffer in input, filled with the error description ++ * @see av_strerror() ++ */ ++static inline char *av_make_error_string(char *errbuf, size_t errbuf_size, int errnum) ++{ ++ av_strerror(errnum, errbuf, errbuf_size); ++ return errbuf; ++} ++ ++/** ++ * Convenience macro, the return value should be used only directly in ++ * function arguments but never stand-alone. ++ */ ++#define av_err2str(errnum) \ ++ av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum) ++ ++/** ++ * @} ++ */ ++ ++#endif /* AVUTIL_ERROR_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/frame.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/frame.h +new file mode 100644 +index 000000000..0e5b0b0fb +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/frame.h +@@ -0,0 +1,308 @@ ++#ifndef AVUTIL_FRAME_H ++#define AVUTIL_FRAME_H ++ ++ ++#include "list.h" ++#include "buffer.h" ++ ++#define AVBufferRef AVBuffer ++ ++enum AVPictureType { ++ AV_PICTURE_TYPE_NONE = 0, ///< Undefined ++ AV_PICTURE_TYPE_I, ///< Intra ++ AV_PICTURE_TYPE_P, ///< Predicted ++ AV_PICTURE_TYPE_B, ///< Bi-dir predicted ++ AV_PICTURE_TYPE_S, ///< S(GMC)-VOP MPEG-4 ++ AV_PICTURE_TYPE_SI, ///< Switching Intra ++ AV_PICTURE_TYPE_SP, ///< Switching Predicted ++ AV_PICTURE_TYPE_BI, ///< BI type ++}; ++ ++typedef struct AVFrame { ++#define AV_NUM_DATA_POINTERS 4 ++ /** ++ * pointer to the picture/channel planes. ++ * This might be different from the first allocated byte ++ * ++ * Some decoders access areas outside 0,0 - width,height, please ++ * see avcodec_align_dimensions2(). Some filters and swscale can read ++ * up to 16 bytes beyond the planes, if these filters are to be used, ++ * then 16 extra bytes must be allocated. ++ * ++ * NOTE: Except for hwaccel formats, pointers not needed by the format ++ * MUST be set to NULL. ++ */ ++ uint8_t *data[AV_NUM_DATA_POINTERS]; ++ ++ /** ++ * For video, size in bytes of each picture line. ++ * For audio, size in bytes of each plane. ++ * ++ * For audio, only linesize[0] may be set. For planar audio, each channel ++ * plane must be the same size. ++ * ++ * For video the linesizes should be multiples of the CPUs alignment ++ * preference, this is 16 or 32 for modern desktop CPUs. ++ * Some code requires such alignment other code can be slower without ++ * correct alignment, for yet other it makes no difference. ++ * ++ * @note The linesize may be larger than the size of usable data -- there ++ * may be extra padding present for performance reasons. ++ */ ++ int linesize[AV_NUM_DATA_POINTERS]; ++ ++ /*当å‰Frame是å¦å®Œæˆ.是å¦å¯è¢«ä½¿ç”¨.*/ ++ struct list_head queued_entry; ++ int queued; /*表示当å‰Frameå·²ç»åœ¨é˜Ÿåˆ—当中.*/ ++ struct list_head done_entry; ++ int index; ++ ++ ++ /** ++ * pointers to the data planes/channels. ++ * ++ * For video, this should simply point to data[]. ++ * ++ * For planar audio, each channel has a separate data pointer, and ++ * linesize[0] contains the size of each channel buffer. ++ * For packed audio, there is just one data pointer, and linesize[0] ++ * contains the total size of the buffer for all channels. ++ * ++ * Note: Both data and extended_data should always be set in a valid frame, ++ * but for planar audio with more channels that can fit in data, ++ * extended_data must be used in order to access all channels. ++ */ ++ uint8_t **extended_data; ++ ++ /** ++ * @name Video dimensions ++ * Video frames only. The coded dimensions (in pixels) of the video frame, ++ * i.e. the size of the rectangle that contains some well-defined values. ++ * ++ * @note The part of the frame intended for display/presentation is further ++ * restricted by the @ref cropping "Cropping rectangle". ++ * @{ ++ */ ++ int width, height; ++ /** ++ * @} ++ */ ++ ++ /** ++ * number of audio samples (per channel) described by this frame ++ */ ++ int nb_samples; ++ ++ /** ++ * format of the frame, -1 if unknown or unset ++ * Values correspond to enum AVPixelFormat for video frames, ++ * enum AVSampleFormat for audio) ++ */ ++ int format; ++ ++ /** ++ * 1 -> keyframe, 0-> not ++ */ ++ int key_frame; ++ ++ /** ++ * Picture type of the frame. ++ */ ++ enum AVPictureType pict_type; ++ ++ /** ++ * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified. ++ */ ++ //AVRational sample_aspect_ratio; ++ ++ /** ++ * Presentation timestamp in time_base units (time when frame should be shown to user). ++ */ ++ int64_t pts; ++ ++ /** ++ * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used) ++ * This is also the Presentation time of this AVFrame calculated from ++ * only AVPacket.dts values without pts values. ++ */ ++ int64_t pkt_dts; ++ ++ /** ++ * picture number in bitstream order ++ */ ++ int coded_picture_number; ++ /** ++ * picture number in display order ++ */ ++ int display_picture_number; ++ ++ /** ++ * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) ++ */ ++ int quality; ++ ++ /** ++ * for some private data of the user ++ */ ++ void *opaque; ++ ++ /** ++ * When decoding, this signals how much the picture must be delayed. ++ * extra_delay = repeat_pict / (2*fps) ++ */ ++ int repeat_pict; ++ ++ /** ++ * The content of the picture is interlaced. ++ */ ++ int interlaced_frame; ++ ++ /** ++ * If the content is interlaced, is top field displayed first. ++ */ ++ int top_field_first; ++ ++ /** ++ * Tell user application that palette has changed from previous frame. ++ */ ++ int palette_has_changed; ++ ++ /** ++ * reordered opaque 64 bits (generally an integer or a double precision float ++ * PTS but can be anything). ++ * The user sets AVCodecContext.reordered_opaque to represent the input at ++ * that time, ++ * the decoder reorders values as needed and sets AVFrame.reordered_opaque ++ * to exactly one of the values provided by the user through AVCodecContext.reordered_opaque ++ * @deprecated in favor of pkt_pts ++ */ ++ int64_t reordered_opaque; ++ ++ /** ++ * Sample rate of the audio data. ++ */ ++ int sample_rate; ++ ++ /** ++ * Channel layout of the audio data. ++ */ ++ uint64_t channel_layout; ++ ++ /** ++ * AVBuffer references backing the data for this frame. If all elements of ++ * this array are NULL, then this frame is not reference counted. This array ++ * must be filled contiguously -- if buf[i] is non-NULL then buf[j] must ++ * also be non-NULL for all j < i. ++ * ++ * There may be at most one AVBuffer per data plane, so for video this array ++ * always contains all the references. For planar audio with more than ++ * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in ++ * this array. Then the extra AVBufferRef pointers are stored in the ++ * extended_buf array. ++ */ ++ AVBufferRef *buf[AV_NUM_DATA_POINTERS]; ++ ++/** ++ * @defgroup lavu_frame_flags AV_FRAME_FLAGS ++ * @ingroup lavu_frame ++ * Flags describing additional frame properties. ++ * ++ * @{ ++ */ ++ ++/** ++ * The frame data may be corrupted, e.g. due to decoding errors. ++ */ ++#define AV_FRAME_FLAG_CORRUPT (1 << 0) ++/** ++ * A flag to mark the frames which need to be decoded, but shouldn't be output. ++ */ ++#define AV_FRAME_FLAG_DISCARD (1 << 2) ++/** ++ * @} ++ */ ++ ++ /** ++ * Frame flags, a combination of @ref lavu_frame_flags ++ */ ++ int flags; ++ ++ /** ++ * frame timestamp estimated using various heuristics, in stream time base ++ * - encoding: unused ++ * - decoding: set by libavcodec, read by user. ++ */ ++ int64_t best_effort_timestamp; ++ ++ /** ++ * reordered pos from the last AVPacket that has been input into the decoder ++ * - encoding: unused ++ * - decoding: Read by user. ++ */ ++ int64_t pkt_pos; ++ ++ /** ++ * duration of the corresponding packet, expressed in ++ * AVStream->time_base units, 0 if unknown. ++ * - encoding: unused ++ * - decoding: Read by user. ++ */ ++ int64_t pkt_duration; ++ ++ /** ++ * decode error flags of the frame, set to a combination of ++ * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there ++ * were errors during the decoding. ++ * - encoding: unused ++ * - decoding: set by libavcodec, read by user. ++ */ ++ int decode_error_flags; ++#define FF_DECODE_ERROR_INVALID_BITSTREAM 1 ++#define FF_DECODE_ERROR_MISSING_REFERENCE 2 ++ ++ /** ++ * number of audio channels, only used for audio. ++ * - encoding: unused ++ * - decoding: Read by user. ++ */ ++ int channels; ++ ++ /** ++ * size of the corresponding packet containing the compressed ++ * frame. ++ * It is set to a negative value if unknown. ++ * - encoding: unused ++ * - decoding: set by libavcodec, read by user. ++ */ ++ int pkt_size; ++ ++ /** ++ * @anchor cropping ++ * @name Cropping ++ * Video frames only. The number of pixels to discard from the the ++ * top/bottom/left/right border of the frame to obtain the sub-rectangle of ++ * the frame intended for presentation. ++ * @{ ++ */ ++ size_t crop_top; ++ size_t crop_bottom; ++ size_t crop_left; ++ size_t crop_right; ++ /** ++ * @} ++ */ ++ ++} AVFrame; ++ ++/** ++ * Get the buffer reference a given data plane is stored in. ++ * ++ * @param plane index of the data plane of interest in frame->extended_data. ++ * ++ * @return the buffer reference that contains the plane or NULL if the input ++ * frame is not valid. ++ */ ++AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane); ++ ++ ++#endif /* AVUTIL_FRAME_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/get_bits.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/get_bits.h +new file mode 100644 +index 000000000..b38b8b7bf +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/get_bits.h +@@ -0,0 +1,810 @@ ++#ifndef AVCODEC_GET_BITS_H ++#define AVCODEC_GET_BITS_H ++ ++#include "common.h" ++#include "intreadwrite.h" ++#include "log.h" ++#include "avassert.h" ++#include "avcodec.h" ++#include "mathops.h" ++//#include "vlc.h" ++ ++#define UNCHECKED_BITSTREAM_READER 1 ++ ++/* ++ * Safe bitstream reading: ++ * optionally, the get_bits API can check to ensure that we ++ * don't read past input buffer boundaries. This is protected ++ * with CONFIG_SAFE_BITSTREAM_READER at the global level, and ++ * then below that with UNCHECKED_BITSTREAM_READER at the per- ++ * decoder level. This means that decoders that check internally ++ * can "#define UNCHECKED_BITSTREAM_READER 1" to disable ++ * overread checks. ++ * Boundary checking causes a minor performance penalty so for ++ * applications that won't want/need this, it can be disabled ++ * globally using "#define CONFIG_SAFE_BITSTREAM_READER 0". ++ */ ++#ifndef UNCHECKED_BITSTREAM_READER ++#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER ++#endif ++ ++#ifndef CACHED_BITSTREAM_READER ++#define CACHED_BITSTREAM_READER 0 ++#endif ++ ++typedef struct GetBitContext { ++ const uint8_t *buffer, *buffer_end; ++#if CACHED_BITSTREAM_READER ++ uint64_t cache; ++ unsigned bits_left; ++#endif ++ int index; ++ int size_in_bits; ++ int size_in_bits_plus8; ++} GetBitContext; ++ ++static inline unsigned int get_bits(GetBitContext *s, int n); ++static inline void skip_bits(GetBitContext *s, int n); ++static inline unsigned int show_bits(GetBitContext *s, int n); ++ ++/* Bitstream reader API docs: ++ * name ++ * arbitrary name which is used as prefix for the internal variables ++ * ++ * gb ++ * getbitcontext ++ * ++ * OPEN_READER(name, gb) ++ * load gb into local variables ++ * ++ * CLOSE_READER(name, gb) ++ * store local vars in gb ++ * ++ * UPDATE_CACHE(name, gb) ++ * Refill the internal cache from the bitstream. ++ * After this call at least MIN_CACHE_BITS will be available. ++ * ++ * GET_CACHE(name, gb) ++ * Will output the contents of the internal cache, ++ * next bit is MSB of 32 or 64 bits (FIXME 64 bits). ++ * ++ * SHOW_UBITS(name, gb, num) ++ * Will return the next num bits. ++ * ++ * SHOW_SBITS(name, gb, num) ++ * Will return the next num bits and do sign extension. ++ * ++ * SKIP_BITS(name, gb, num) ++ * Will skip over the next num bits. ++ * Note, this is equivalent to SKIP_CACHE; SKIP_COUNTER. ++ * ++ * SKIP_CACHE(name, gb, num) ++ * Will remove the next num bits from the cache (note SKIP_COUNTER ++ * MUST be called before UPDATE_CACHE / CLOSE_READER). ++ * ++ * SKIP_COUNTER(name, gb, num) ++ * Will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS). ++ * ++ * LAST_SKIP_BITS(name, gb, num) ++ * Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER. ++ * ++ * BITS_LEFT(name, gb) ++ * Return the number of bits left ++ * ++ * For examples see get_bits, show_bits, skip_bits, get_vlc. ++ */ ++ ++#if CACHED_BITSTREAM_READER ++# define MIN_CACHE_BITS 64 ++#elif defined LONG_BITSTREAM_READER ++# define MIN_CACHE_BITS 32 ++#else ++# define MIN_CACHE_BITS 25 ++#endif ++ ++#if !CACHED_BITSTREAM_READER ++ ++#define OPEN_READER_NOSIZE(name, gb) \ ++ unsigned int name ## _index = (gb)->index; \ ++ unsigned int __maybe_unused name ## _cache ++ ++#if UNCHECKED_BITSTREAM_READER ++#define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb) ++ ++#define BITS_AVAILABLE(name, gb) 1 ++#else ++#define OPEN_READER(name, gb) \ ++ OPEN_READER_NOSIZE(name, gb); \ ++ unsigned int name ## _size_plus8 = (gb)->size_in_bits_plus8 ++ ++#define BITS_AVAILABLE(name, gb) name ## _index < name ## _size_plus8 ++#endif ++ ++#define CLOSE_READER(name, gb) (gb)->index = name ## _index ++ ++# ifdef LONG_BITSTREAM_READER ++ ++# define UPDATE_CACHE_LE(name, gb) name ## _cache = \ ++ AV_RL64((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) ++ ++# define UPDATE_CACHE_BE(name, gb) name ## _cache = \ ++ AV_RB64((gb)->buffer + (name ## _index >> 3)) >> (32 - (name ## _index & 7)) ++ ++#else ++ ++# define UPDATE_CACHE_LE(name, gb) name ## _cache = \ ++ AV_RL32((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) ++ ++# define UPDATE_CACHE_BE(name, gb) name ## _cache = \ ++ AV_RB32((gb)->buffer + (name ## _index >> 3)) << (name ## _index & 7) ++ ++#endif ++ ++ ++#ifdef BITSTREAM_READER_LE ++ ++# define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) ++ ++# define SKIP_CACHE(name, gb, num) name ## _cache >>= (num) ++ ++#else ++ ++# define UPDATE_CACHE(name, gb) UPDATE_CACHE_BE(name, gb) ++ ++# define SKIP_CACHE(name, gb, num) name ## _cache <<= (num) ++ ++#endif ++ ++#if UNCHECKED_BITSTREAM_READER ++# define SKIP_COUNTER(name, gb, num) name ## _index += (num) ++#else ++# define SKIP_COUNTER(name, gb, num) \ ++ name ## _index = FFMIN(name ## _size_plus8, name ## _index + (num)) ++#endif ++ ++#define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name ## _index)) ++ ++#define SKIP_BITS(name, gb, num) \ ++ do { \ ++ SKIP_CACHE(name, gb, num); \ ++ SKIP_COUNTER(name, gb, num); \ ++ } while (0) ++ ++#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) ++ ++#define SHOW_UBITS_LE(name, gb, num) zero_extend(name ## _cache, num) ++#define SHOW_SBITS_LE(name, gb, num) sign_extend(name ## _cache, num) ++ ++#define SHOW_UBITS_BE(name, gb, num) NEG_USR32(name ## _cache, num) ++#define SHOW_SBITS_BE(name, gb, num) NEG_SSR32(name ## _cache, num) ++ ++#ifdef BITSTREAM_READER_LE ++# define SHOW_UBITS(name, gb, num) SHOW_UBITS_LE(name, gb, num) ++# define SHOW_SBITS(name, gb, num) SHOW_SBITS_LE(name, gb, num) ++#else ++# define SHOW_UBITS(name, gb, num) SHOW_UBITS_BE(name, gb, num) ++# define SHOW_SBITS(name, gb, num) SHOW_SBITS_BE(name, gb, num) ++#endif ++ ++#define GET_CACHE(name, gb) ((uint32_t) name ## _cache) ++ ++#endif ++ ++static inline int get_bits_count(const GetBitContext *s) ++{ ++#if CACHED_BITSTREAM_READER ++ return s->index - s->bits_left; ++#else ++ return s->index; ++#endif ++} ++ ++#if CACHED_BITSTREAM_READER ++static inline void refill_32(GetBitContext *s) ++{ ++#if !UNCHECKED_BITSTREAM_READER ++ if (s->index >> 3 >= s->buffer_end - s->buffer) ++ return; ++#endif ++ ++#ifdef BITSTREAM_READER_LE ++ s->cache = (uint64_t)AV_RL32(s->buffer + (s->index >> 3)) << s->bits_left | s->cache; ++#else ++ s->cache = s->cache | (uint64_t)AV_RB32(s->buffer + (s->index >> 3)) << (32 - s->bits_left); ++#endif ++ s->index += 32; ++ s->bits_left += 32; ++} ++ ++static inline void refill_64(GetBitContext *s) ++{ ++#if !UNCHECKED_BITSTREAM_READER ++ if (s->index >> 3 >= s->buffer_end - s->buffer) ++ return; ++#endif ++ ++#ifdef BITSTREAM_READER_LE ++ s->cache = AV_RL64(s->buffer + (s->index >> 3)); ++#else ++ s->cache = AV_RB64(s->buffer + (s->index >> 3)); ++#endif ++ s->index += 64; ++ s->bits_left = 64; ++} ++ ++static inline uint64_t get_val(GetBitContext *s, unsigned n, int is_le) ++{ ++ uint64_t ret; ++ av_assert2(n>0 && n<=63); ++ if (is_le) { ++ ret = s->cache & ((UINT64_C(1) << n) - 1); ++ s->cache >>= n; ++ } else { ++ ret = s->cache >> (64 - n); ++ s->cache <<= n; ++ } ++ s->bits_left -= n; ++ return ret; ++} ++ ++static inline unsigned show_val(const GetBitContext *s, unsigned n) ++{ ++#ifdef BITSTREAM_READER_LE ++ return s->cache & ((UINT64_C(1) << n) - 1); ++#else ++ return s->cache >> (64 - n); ++#endif ++} ++#endif ++ ++/** ++ * Skips the specified number of bits. ++ * @param n the number of bits to skip, ++ * For the UNCHECKED_BITSTREAM_READER this must not cause the distance ++ * from the start to overflow int32_t. Staying within the bitstream + padding ++ * is sufficient, too. ++ */ ++static inline void skip_bits_long(GetBitContext *s, int n) ++{ ++#if CACHED_BITSTREAM_READER ++ skip_bits(s, n); ++#else ++#if UNCHECKED_BITSTREAM_READER ++ s->index += n; ++#else ++ s->index += av_clip(n, -s->index, s->size_in_bits_plus8 - s->index); ++#endif ++#endif ++} ++ ++#if CACHED_BITSTREAM_READER ++static inline void skip_remaining(GetBitContext *s, unsigned n) ++{ ++#ifdef BITSTREAM_READER_LE ++ s->cache >>= n; ++#else ++ s->cache <<= n; ++#endif ++ s->bits_left -= n; ++} ++#endif ++ ++/** ++ * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB). ++ * if MSB not set it is negative ++ * @param n length in bits ++ */ ++static inline int get_xbits(GetBitContext *s, int n) ++{ ++#if CACHED_BITSTREAM_READER ++ int32_t cache = show_bits(s, 32); ++ int sign = ~cache >> 31; ++ skip_remaining(s, n); ++ ++ return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign; ++#else ++ register int sign; ++ register int32_t cache; ++ OPEN_READER(re, s); ++ av_assert2(n>0 && n<=25); ++ UPDATE_CACHE(re, s); ++ cache = GET_CACHE(re, s); ++ sign = ~cache >> 31; ++ LAST_SKIP_BITS(re, s, n); ++ CLOSE_READER(re, s); ++ return (NEG_USR32(sign ^ cache, n) ^ sign) - sign; ++#endif ++} ++ ++#if !CACHED_BITSTREAM_READER ++static inline int get_xbits_le(GetBitContext *s, int n) ++{ ++ register int sign; ++ register int32_t cache; ++ OPEN_READER(re, s); ++ av_assert2(n>0 && n<=25); ++ UPDATE_CACHE_LE(re, s); ++ cache = GET_CACHE(re, s); ++ sign = sign_extend(~cache, n) >> 31; ++ LAST_SKIP_BITS(re, s, n); ++ CLOSE_READER(re, s); ++ return (zero_extend(sign ^ cache, n) ^ sign) - sign; ++} ++#endif ++ ++static inline int get_sbits(GetBitContext *s, int n) ++{ ++ register int tmp; ++#if CACHED_BITSTREAM_READER ++ av_assert2(n>0 && n<=25); ++ tmp = sign_extend(get_bits(s, n), n); ++#else ++ OPEN_READER(re, s); ++ av_assert2(n>0 && n<=25); ++ UPDATE_CACHE(re, s); ++ tmp = SHOW_SBITS(re, s, n); ++ LAST_SKIP_BITS(re, s, n); ++ CLOSE_READER(re, s); ++#endif ++ return tmp; ++} ++ ++/** ++ * Read 1-25 bits. ++ */ ++static inline unsigned int get_bits(GetBitContext *s, int n) ++{ ++ register int tmp; ++#if CACHED_BITSTREAM_READER ++ ++ av_assert2(n>0 && n<=32); ++ if (n > s->bits_left) { ++ refill_32(s); ++ if (s->bits_left < 32) ++ s->bits_left = n; ++ } ++ ++#ifdef BITSTREAM_READER_LE ++ tmp = get_val(s, n, 1); ++#else ++ tmp = get_val(s, n, 0); ++#endif ++#else ++ OPEN_READER(re, s); ++ av_assert2(n>0 && n<=25); ++ UPDATE_CACHE(re, s); ++ tmp = SHOW_UBITS(re, s, n); ++ LAST_SKIP_BITS(re, s, n); ++ CLOSE_READER(re, s); ++#endif ++ return tmp; ++} ++ ++/** ++ * Read 0-25 bits. ++ */ ++static inline int get_bitsz(GetBitContext *s, int n) ++{ ++ return n ? get_bits(s, n) : 0; ++} ++ ++static inline unsigned int get_bits_le(GetBitContext *s, int n) ++{ ++#if CACHED_BITSTREAM_READER ++ av_assert2(n>0 && n<=32); ++ if (n > s->bits_left) { ++ refill_32(s); ++ if (s->bits_left < 32) ++ s->bits_left = n; ++ } ++ ++ return get_val(s, n, 1); ++#else ++ register int tmp; ++ OPEN_READER(re, s); ++ av_assert2(n>0 && n<=25); ++ UPDATE_CACHE_LE(re, s); ++ tmp = SHOW_UBITS_LE(re, s, n); ++ LAST_SKIP_BITS(re, s, n); ++ CLOSE_READER(re, s); ++ return tmp; ++#endif ++} ++ ++/** ++ * Show 1-25 bits. ++ */ ++static inline unsigned int show_bits(GetBitContext *s, int n) ++{ ++ register int tmp; ++#if CACHED_BITSTREAM_READER ++ if (n > s->bits_left) ++ refill_32(s); ++ ++ tmp = show_val(s, n); ++#else ++ OPEN_READER_NOSIZE(re, s); ++ av_assert2(n>0 && n<=25); ++ UPDATE_CACHE(re, s); ++ tmp = SHOW_UBITS(re, s, n); ++#endif ++ return tmp; ++} ++ ++static inline void skip_bits(GetBitContext *s, int n) ++{ ++#if CACHED_BITSTREAM_READER ++ if (n < s->bits_left) ++ skip_remaining(s, n); ++ else { ++ n -= s->bits_left; ++ s->cache = 0; ++ s->bits_left = 0; ++ ++ if (n >= 64) { ++ unsigned skip = (n / 8) * 8; ++ ++ n -= skip; ++ s->index += skip; ++ } ++ refill_64(s); ++ if (n) ++ skip_remaining(s, n); ++ } ++#else ++ OPEN_READER(re, s); ++ LAST_SKIP_BITS(re, s, n); ++ CLOSE_READER(re, s); ++#endif ++} ++ ++static inline unsigned int get_bits1(GetBitContext *s) ++{ ++#if CACHED_BITSTREAM_READER ++ if (!s->bits_left) ++ refill_64(s); ++ ++#ifdef BITSTREAM_READER_LE ++ return get_val(s, 1, 1); ++#else ++ return get_val(s, 1, 0); ++#endif ++#else ++ unsigned int index = s->index; ++ uint8_t result = s->buffer[index >> 3]; ++#ifdef BITSTREAM_READER_LE ++ result >>= index & 7; ++ result &= 1; ++#else ++ result <<= index & 7; ++ result >>= 8 - 1; ++#endif ++#if !UNCHECKED_BITSTREAM_READER ++ if (s->index < s->size_in_bits_plus8) ++#endif ++ index++; ++ s->index = index; ++ ++ return result; ++#endif ++} ++ ++static inline unsigned int show_bits1(GetBitContext *s) ++{ ++ return show_bits(s, 1); ++} ++ ++static inline void skip_bits1(GetBitContext *s) ++{ ++ skip_bits(s, 1); ++} ++ ++/** ++ * Read 0-32 bits. ++ */ ++static inline unsigned int get_bits_long(GetBitContext *s, int n) ++{ ++ av_assert2(n>=0 && n<=32); ++ if (!n) { ++ return 0; ++#if CACHED_BITSTREAM_READER ++ } ++ return get_bits(s, n); ++#else ++ } else if (n <= MIN_CACHE_BITS) { ++ return get_bits(s, n); ++ } else { ++#ifdef BITSTREAM_READER_LE ++ unsigned ret = get_bits(s, 16); ++ return ret | (get_bits(s, n - 16) << 16); ++#else ++ unsigned ret = get_bits(s, 16) << (n - 16); ++ return ret | get_bits(s, n - 16); ++#endif ++ } ++#endif ++} ++ ++/** ++ * Read 0-64 bits. ++ */ ++static inline uint64_t get_bits64(GetBitContext *s, int n) ++{ ++ if (n <= 32) { ++ return get_bits_long(s, n); ++ } else { ++#ifdef BITSTREAM_READER_LE ++ uint64_t ret = get_bits_long(s, 32); ++ return ret | (uint64_t) get_bits_long(s, n - 32) << 32; ++#else ++ uint64_t ret = (uint64_t) get_bits_long(s, n - 32) << 32; ++ return ret | get_bits_long(s, 32); ++#endif ++ } ++} ++ ++/** ++ * Read 0-32 bits as a signed integer. ++ */ ++static inline int get_sbits_long(GetBitContext *s, int n) ++{ ++ // sign_extend(x, 0) is undefined ++ if (!n) ++ return 0; ++ ++ return sign_extend(get_bits_long(s, n), n); ++} ++ ++/** ++ * Show 0-32 bits. ++ */ ++static inline unsigned int show_bits_long(GetBitContext *s, int n) ++{ ++ if (n <= MIN_CACHE_BITS) { ++ return show_bits(s, n); ++ } else { ++ GetBitContext gb = *s; ++ return get_bits_long(&gb, n); ++ } ++} ++ ++static inline int check_marker(void *logctx, GetBitContext *s, const char *msg) ++{ ++ int bit = get_bits1(s); ++ if (!bit) ++ av_log(logctx, AV_LOG_INFO, "Marker bit missing at %d of %d %s\n", ++ get_bits_count(s) - 1, s->size_in_bits, msg); ++ ++ return bit; ++} ++ ++/** ++ * Initialize GetBitContext. ++ * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes ++ * larger than the actual read bits because some optimized bitstream ++ * readers read 32 or 64 bit at once and could read over the end ++ * @param bit_size the size of the buffer in bits ++ * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. ++ */ ++static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, ++ int bit_size) ++{ ++ int buffer_size; ++ int ret = 0; ++ ++ if (bit_size >= INT_MAX - FFMAX(7, AV_INPUT_BUFFER_PADDING_SIZE*8) || bit_size < 0 || !buffer) { ++ bit_size = 0; ++ buffer = NULL; ++ ret = AVERROR_INVALIDDATA; ++ } ++ ++ buffer_size = (bit_size + 7) >> 3; ++ ++ s->buffer = buffer; ++ s->size_in_bits = bit_size; ++ s->size_in_bits_plus8 = bit_size + 8; ++ s->buffer_end = buffer + buffer_size; ++ s->index = 0; ++ ++#if CACHED_BITSTREAM_READER ++ refill_64(s); ++#endif ++ ++ return ret; ++} ++ ++/** ++ * Initialize GetBitContext. ++ * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes ++ * larger than the actual read bits because some optimized bitstream ++ * readers read 32 or 64 bit at once and could read over the end ++ * @param byte_size the size of the buffer in bytes ++ * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. ++ */ ++static inline int init_get_bits8(GetBitContext *s, const uint8_t *buffer, ++ int byte_size) ++{ ++ if (byte_size > INT_MAX / 8 || byte_size < 0) ++ byte_size = -1; ++ return init_get_bits(s, buffer, byte_size * 8); ++} ++ ++static inline const uint8_t *align_get_bits(GetBitContext *s) ++{ ++ int n = -get_bits_count(s) & 7; ++ if (n) ++ skip_bits(s, n); ++ return s->buffer + (s->index >> 3); ++} ++ ++#if 0 ++/** ++ * If the vlc code is invalid and max_depth=1, then no bits will be removed. ++ * If the vlc code is invalid and max_depth>1, then the number of bits removed ++ * is undefined. ++ */ ++#define GET_VLC(code, name, gb, table, bits, max_depth) \ ++ do { \ ++ int n, nb_bits; \ ++ unsigned int index; \ ++ \ ++ index = SHOW_UBITS(name, gb, bits); \ ++ code = table[index][0]; \ ++ n = table[index][1]; \ ++ \ ++ if (max_depth > 1 && n < 0) { \ ++ LAST_SKIP_BITS(name, gb, bits); \ ++ UPDATE_CACHE(name, gb); \ ++ \ ++ nb_bits = -n; \ ++ \ ++ index = SHOW_UBITS(name, gb, nb_bits) + code; \ ++ code = table[index][0]; \ ++ n = table[index][1]; \ ++ if (max_depth > 2 && n < 0) { \ ++ LAST_SKIP_BITS(name, gb, nb_bits); \ ++ UPDATE_CACHE(name, gb); \ ++ \ ++ nb_bits = -n; \ ++ \ ++ index = SHOW_UBITS(name, gb, nb_bits) + code; \ ++ code = table[index][0]; \ ++ n = table[index][1]; \ ++ } \ ++ } \ ++ SKIP_BITS(name, gb, n); \ ++ } while (0) ++ ++#define GET_RL_VLC(level, run, name, gb, table, bits, \ ++ max_depth, need_update) \ ++ do { \ ++ int n, nb_bits; \ ++ unsigned int index; \ ++ \ ++ index = SHOW_UBITS(name, gb, bits); \ ++ level = table[index].level; \ ++ n = table[index].len; \ ++ \ ++ if (max_depth > 1 && n < 0) { \ ++ SKIP_BITS(name, gb, bits); \ ++ if (need_update) { \ ++ UPDATE_CACHE(name, gb); \ ++ } \ ++ \ ++ nb_bits = -n; \ ++ \ ++ index = SHOW_UBITS(name, gb, nb_bits) + level; \ ++ level = table[index].level; \ ++ n = table[index].len; \ ++ if (max_depth > 2 && n < 0) { \ ++ LAST_SKIP_BITS(name, gb, nb_bits); \ ++ if (need_update) { \ ++ UPDATE_CACHE(name, gb); \ ++ } \ ++ nb_bits = -n; \ ++ \ ++ index = SHOW_UBITS(name, gb, nb_bits) + level; \ ++ level = table[index].level; \ ++ n = table[index].len; \ ++ } \ ++ } \ ++ run = table[index].run; \ ++ SKIP_BITS(name, gb, n); \ ++ } while (0) ++ ++/* Return the LUT element for the given bitstream configuration. */ ++static inline int set_idx(GetBitContext *s, int code, int *n, int *nb_bits, ++ VLC_TYPE (*table)[2]) ++{ ++ unsigned idx; ++ ++ *nb_bits = -*n; ++ idx = show_bits(s, *nb_bits) + code; ++ *n = table[idx][1]; ++ ++ return table[idx][0]; ++} ++ ++/** ++ * Parse a vlc code. ++ * @param bits is the number of bits which will be read at once, must be ++ * identical to nb_bits in init_vlc() ++ * @param max_depth is the number of times bits bits must be read to completely ++ * read the longest vlc code ++ * = (max_vlc_length + bits - 1) / bits ++ * @returns the code parsed or -1 if no vlc matches ++ */ ++static inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], ++ int bits, int max_depth) ++{ ++#if CACHED_BITSTREAM_READER ++ int nb_bits; ++ unsigned idx = show_bits(s, bits); ++ int code = table[idx][0]; ++ int n = table[idx][1]; ++ ++ if (max_depth > 1 && n < 0) { ++ skip_remaining(s, bits); ++ code = set_idx(s, code, &n, &nb_bits, table); ++ if (max_depth > 2 && n < 0) { ++ skip_remaining(s, nb_bits); ++ code = set_idx(s, code, &n, &nb_bits, table); ++ } ++ } ++ skip_remaining(s, n); ++ ++ return code; ++#else ++ int code; ++ ++ OPEN_READER(re, s); ++ UPDATE_CACHE(re, s); ++ ++ GET_VLC(code, re, s, table, bits, max_depth); ++ ++ CLOSE_READER(re, s); ++ ++ return code; ++#endif ++} ++#endif ++ ++static inline int decode012(GetBitContext *gb) ++{ ++ int n; ++ n = get_bits1(gb); ++ if (n == 0) ++ return 0; ++ else ++ return get_bits1(gb) + 1; ++} ++ ++static inline int decode210(GetBitContext *gb) ++{ ++ if (get_bits1(gb)) ++ return 0; ++ else ++ return 2 - get_bits1(gb); ++} ++ ++static inline int get_bits_left(GetBitContext *gb) ++{ ++ return gb->size_in_bits - get_bits_count(gb); ++} ++ ++static inline int skip_1stop_8data_bits(GetBitContext *gb) ++{ ++ if (get_bits_left(gb) <= 0) ++ return AVERROR_INVALIDDATA; ++ ++ while (get_bits1(gb)) { ++ skip_bits(gb, 8); ++ if (get_bits_left(gb) <= 0) ++ return AVERROR_INVALIDDATA; ++ } ++ ++ return 0; ++} ++ ++ ++#endif /* AVCODEC_GET_BITS_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/golomb.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/golomb.h +new file mode 100644 +index 000000000..6ad02b412 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/golomb.h +@@ -0,0 +1,715 @@ ++#ifndef AVCODEC_GOLOMB_H ++#define AVCODEC_GOLOMB_H ++ ++ ++//#include ++ ++#include "get_bits.h" ++#include "put_bits.h" ++ ++#define INVALID_VLC 0x80000000 ++ ++extern const uint8_t ff_golomb_vlc_len[512]; ++extern const uint8_t ff_ue_golomb_vlc_code[512]; ++extern const int8_t ff_se_golomb_vlc_code[512]; ++extern const uint8_t ff_ue_golomb_len[256]; ++ ++extern const uint8_t ff_interleaved_golomb_vlc_len[256]; ++extern const uint8_t ff_interleaved_ue_golomb_vlc_code[256]; ++extern const int8_t ff_interleaved_se_golomb_vlc_code[256]; ++extern const uint8_t ff_interleaved_dirac_golomb_vlc_code[256]; ++ ++/** ++ * Read an unsigned Exp-Golomb code in the range 0 to 8190. ++ * ++ * @returns the read value or a negative error code. ++ */ ++static inline int get_ue_golomb(GetBitContext *gb) ++{ ++ unsigned int buf; ++ ++#if CACHED_BITSTREAM_READER ++ buf = show_bits_long(gb, 32); ++ ++ if (buf >= (1 << 27)) { ++ buf >>= 32 - 9; ++ skip_bits_long(gb, ff_golomb_vlc_len[buf]); ++ ++ return ff_ue_golomb_vlc_code[buf]; ++ } else { ++ int log = 2 * av_log2(buf) - 31; ++ buf >>= log; ++ buf--; ++ skip_bits_long(gb, 32 - log); ++ ++ return buf; ++ } ++#else ++ OPEN_READER(re, gb); ++ UPDATE_CACHE(re, gb); ++ buf = GET_CACHE(re, gb); ++ ++ if (buf >= (1 << 27)) { ++ buf >>= 32 - 9; ++ LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); ++ CLOSE_READER(re, gb); ++ ++ return ff_ue_golomb_vlc_code[buf]; ++ } else { ++ int log = 2 * av_log2(buf) - 31; ++ LAST_SKIP_BITS(re, gb, 32 - log); ++ CLOSE_READER(re, gb); ++ if (log < 7) { ++ av_log(NULL, AV_LOG_ERROR, "Invalid UE golomb code\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ buf >>= log; ++ buf--; ++ ++ return buf; ++ } ++#endif ++} ++ ++/** ++ * Read an unsigned Exp-Golomb code in the range 0 to UINT32_MAX-1. ++ */ ++static inline unsigned get_ue_golomb_long(GetBitContext *gb) ++{ ++ unsigned buf, log; ++ ++ buf = show_bits_long(gb, 32); ++ log = 31 - av_log2(buf); ++ skip_bits_long(gb, log); ++ ++ return get_bits_long(gb, log + 1) - 1; ++} ++ ++/** ++ * read unsigned exp golomb code, constraint to a max of 31. ++ * the return value is undefined if the stored value exceeds 31. ++ */ ++static inline int get_ue_golomb_31(GetBitContext *gb) ++{ ++ unsigned int buf; ++ ++#if CACHED_BITSTREAM_READER ++ buf = show_bits_long(gb, 32); ++ ++ buf >>= 32 - 9; ++ skip_bits_long(gb, ff_golomb_vlc_len[buf]); ++#else ++ ++ OPEN_READER(re, gb); ++ UPDATE_CACHE(re, gb); ++ buf = GET_CACHE(re, gb); ++ ++ buf >>= 32 - 9; ++ LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); ++ CLOSE_READER(re, gb); ++#endif ++ ++ return ff_ue_golomb_vlc_code[buf]; ++} ++ ++static inline unsigned get_interleaved_ue_golomb(GetBitContext *gb) ++{ ++ uint32_t buf; ++ ++#if CACHED_BITSTREAM_READER ++ buf = show_bits_long(gb, 32); ++ ++ if (buf & 0xAA800000) { ++ buf >>= 32 - 8; ++ skip_bits_long(gb, ff_interleaved_golomb_vlc_len[buf]); ++ ++ return ff_interleaved_ue_golomb_vlc_code[buf]; ++ } else { ++ unsigned ret = 1; ++ ++ do { ++ buf >>= 32 - 8; ++ skip_bits_long(gb, FFMIN(ff_interleaved_golomb_vlc_len[buf], 8)); ++ ++ if (ff_interleaved_golomb_vlc_len[buf] != 9) { ++ ret <<= (ff_interleaved_golomb_vlc_len[buf] - 1) >> 1; ++ ret |= ff_interleaved_dirac_golomb_vlc_code[buf]; ++ break; ++ } ++ ret = (ret << 4) | ff_interleaved_dirac_golomb_vlc_code[buf]; ++ buf = show_bits_long(gb, 32); ++ } while (get_bits_left(gb) > 0); ++ ++ return ret - 1; ++ } ++#else ++ OPEN_READER(re, gb); ++ UPDATE_CACHE(re, gb); ++ buf = GET_CACHE(re, gb); ++ ++ if (buf & 0xAA800000) { ++ buf >>= 32 - 8; ++ LAST_SKIP_BITS(re, gb, ff_interleaved_golomb_vlc_len[buf]); ++ CLOSE_READER(re, gb); ++ ++ return ff_interleaved_ue_golomb_vlc_code[buf]; ++ } else { ++ unsigned ret = 1; ++ ++ do { ++ buf >>= 32 - 8; ++ LAST_SKIP_BITS(re, gb, ++ FFMIN(ff_interleaved_golomb_vlc_len[buf], 8)); ++ ++ if (ff_interleaved_golomb_vlc_len[buf] != 9) { ++ ret <<= (ff_interleaved_golomb_vlc_len[buf] - 1) >> 1; ++ ret |= ff_interleaved_dirac_golomb_vlc_code[buf]; ++ break; ++ } ++ ret = (ret << 4) | ff_interleaved_dirac_golomb_vlc_code[buf]; ++ UPDATE_CACHE(re, gb); ++ buf = GET_CACHE(re, gb); ++ } while (ret<0x8000000U && BITS_AVAILABLE(re, gb)); ++ ++ CLOSE_READER(re, gb); ++ return ret - 1; ++ } ++#endif ++} ++ ++/** ++ * read unsigned truncated exp golomb code. ++ */ ++static inline int get_te0_golomb(GetBitContext *gb, int range) ++{ ++ av_assert2(range >= 1); ++ ++ if (range == 1) ++ return 0; ++ else if (range == 2) ++ return get_bits1(gb) ^ 1; ++ else ++ return get_ue_golomb(gb); ++} ++ ++/** ++ * read unsigned truncated exp golomb code. ++ */ ++static inline int get_te_golomb(GetBitContext *gb, int range) ++{ ++ av_assert2(range >= 1); ++ ++ if (range == 2) ++ return get_bits1(gb) ^ 1; ++ else ++ return get_ue_golomb(gb); ++} ++ ++/** ++ * read signed exp golomb code. ++ */ ++static inline int get_se_golomb(GetBitContext *gb) ++{ ++ unsigned int buf; ++ ++#if CACHED_BITSTREAM_READER ++ buf = show_bits_long(gb, 32); ++ ++ if (buf >= (1 << 27)) { ++ buf >>= 32 - 9; ++ skip_bits_long(gb, ff_golomb_vlc_len[buf]); ++ ++ return ff_se_golomb_vlc_code[buf]; ++ } else { ++ int log = 2 * av_log2(buf) - 31; ++ buf >>= log; ++ ++ skip_bits_long(gb, 32 - log); ++ ++ if (buf & 1) ++ buf = -(buf >> 1); ++ else ++ buf = (buf >> 1); ++ ++ return buf; ++ } ++#else ++ OPEN_READER(re, gb); ++ UPDATE_CACHE(re, gb); ++ buf = GET_CACHE(re, gb); ++ ++ if (buf >= (1 << 27)) { ++ buf >>= 32 - 9; ++ LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); ++ CLOSE_READER(re, gb); ++ ++ return ff_se_golomb_vlc_code[buf]; ++ } else { ++ int log = av_log2(buf), sign; ++ LAST_SKIP_BITS(re, gb, 31 - log); ++ UPDATE_CACHE(re, gb); ++ buf = GET_CACHE(re, gb); ++ ++ buf >>= log; ++ ++ LAST_SKIP_BITS(re, gb, 32 - log); ++ CLOSE_READER(re, gb); ++ ++ sign = -(buf & 1); ++ buf = ((buf >> 1) ^ sign) - sign; ++ ++ return buf; ++ } ++#endif ++} ++ ++static inline int get_se_golomb_long(GetBitContext *gb) ++{ ++ unsigned int buf = get_ue_golomb_long(gb); ++ int sign = (buf & 1) - 1; ++ return ((buf >> 1) ^ sign) + 1; ++} ++ ++static inline int get_interleaved_se_golomb(GetBitContext *gb) ++{ ++ unsigned int buf; ++ ++#if CACHED_BITSTREAM_READER ++ buf = show_bits_long(gb, 32); ++ ++ if (buf & 0xAA800000) { ++ buf >>= 32 - 8; ++ skip_bits_long(gb, ff_interleaved_golomb_vlc_len[buf]); ++ ++ return ff_interleaved_se_golomb_vlc_code[buf]; ++ } else { ++ int log; ++ skip_bits(gb, 8); ++ buf |= 1 | show_bits_long(gb, 24); ++ ++ if ((buf & 0xAAAAAAAA) == 0) ++ return INVALID_VLC; ++ ++ for (log = 31; (buf & 0x80000000) == 0; log--) ++ buf = (buf << 2) - ((buf << log) >> (log - 1)) + (buf >> 30); ++ ++ skip_bits_long(gb, 63 - 2 * log - 8); ++ ++ return (signed) (((((buf << log) >> log) - 1) ^ -(buf & 0x1)) + 1) >> 1; ++ } ++#else ++ OPEN_READER(re, gb); ++ UPDATE_CACHE(re, gb); ++ buf = GET_CACHE(re, gb); ++ ++ if (buf & 0xAA800000) { ++ buf >>= 32 - 8; ++ LAST_SKIP_BITS(re, gb, ff_interleaved_golomb_vlc_len[buf]); ++ CLOSE_READER(re, gb); ++ ++ return ff_interleaved_se_golomb_vlc_code[buf]; ++ } else { ++ int log; ++ LAST_SKIP_BITS(re, gb, 8); ++ UPDATE_CACHE(re, gb); ++ buf |= 1 | (GET_CACHE(re, gb) >> 8); ++ ++ if ((buf & 0xAAAAAAAA) == 0) ++ return INVALID_VLC; ++ ++ for (log = 31; (buf & 0x80000000) == 0; log--) ++ buf = (buf << 2) - ((buf << log) >> (log - 1)) + (buf >> 30); ++ ++ LAST_SKIP_BITS(re, gb, 63 - 2 * log - 8); ++ CLOSE_READER(re, gb); ++ ++ return (signed) (((((buf << log) >> log) - 1) ^ -(buf & 0x1)) + 1) >> 1; ++ } ++#endif ++} ++ ++static inline int dirac_get_se_golomb(GetBitContext *gb) ++{ ++ uint32_t ret = get_interleaved_ue_golomb(gb); ++ ++ if (ret) { ++ int sign = -get_bits1(gb); ++ ret = (ret ^ sign) - sign; ++ } ++ ++ return ret; ++} ++ ++/** ++ * read unsigned golomb rice code (ffv1). ++ */ ++static inline int get_ur_golomb(GetBitContext *gb, int k, int limit, ++ int esc_len) ++{ ++ unsigned int buf; ++ int log; ++ ++#if CACHED_BITSTREAM_READER ++ buf = show_bits_long(gb, 32); ++ ++ log = av_log2(buf); ++ ++ if (log > 31 - limit) { ++ buf >>= log - k; ++ buf += (30 - log) << k; ++ skip_bits_long(gb, 32 + k - log); ++ ++ return buf; ++ } else { ++ skip_bits_long(gb, limit); ++ buf = get_bits_long(gb, esc_len); ++ ++ return buf + limit - 1; ++ } ++#else ++ OPEN_READER(re, gb); ++ UPDATE_CACHE(re, gb); ++ buf = GET_CACHE(re, gb); ++ ++ log = av_log2(buf); ++ ++ if (log > 31 - limit) { ++ buf >>= log - k; ++ buf += (30U - log) << k; ++ LAST_SKIP_BITS(re, gb, 32 + k - log); ++ CLOSE_READER(re, gb); ++ ++ return buf; ++ } else { ++ LAST_SKIP_BITS(re, gb, limit); ++ UPDATE_CACHE(re, gb); ++ ++ buf = SHOW_UBITS(re, gb, esc_len); ++ ++ LAST_SKIP_BITS(re, gb, esc_len); ++ CLOSE_READER(re, gb); ++ ++ return buf + limit - 1; ++ } ++#endif ++} ++ ++/** ++ * read unsigned golomb rice code (jpegls). ++ */ ++static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit, ++ int esc_len) ++{ ++ unsigned int buf; ++ int log; ++ ++#if CACHED_BITSTREAM_READER ++ buf = show_bits_long(gb, 32); ++ ++ log = av_log2(buf); ++ ++ if (log - k >= 1 && 32 - log < limit) { ++ buf >>= log - k; ++ buf += (30 - log) << k; ++ skip_bits_long(gb, 32 + k - log); ++ ++ return buf; ++ } else { ++ int i; ++ for (i = 0; ++ i < limit && get_bits1(gb) == 0 && get_bits_left(gb) > 0; ++ i++); ++ ++ if (i < limit - 1) { ++ buf = get_bits_long(gb, k); ++ ++ return buf + (i << k); ++ } else if (i == limit - 1) { ++ buf = get_bits_long(gb, esc_len); ++ ++ return buf + 1; ++ } else ++ return -1; ++ } ++#else ++ OPEN_READER(re, gb); ++ UPDATE_CACHE(re, gb); ++ buf = GET_CACHE(re, gb); ++ ++ log = av_log2(buf); ++ ++ av_assert2(k <= 31); ++ ++ if (log - k >= 32 - MIN_CACHE_BITS + (MIN_CACHE_BITS == 32) && ++ 32 - log < limit) { ++ buf >>= log - k; ++ buf += (30U - log) << k; ++ LAST_SKIP_BITS(re, gb, 32 + k - log); ++ CLOSE_READER(re, gb); ++ ++ return buf; ++ } else { ++ int i; ++ for (i = 0; i < limit && SHOW_UBITS(re, gb, 1) == 0; i++) { ++ if (gb->size_in_bits <= re_index) { ++ CLOSE_READER(re, gb); ++ return -1; ++ } ++ LAST_SKIP_BITS(re, gb, 1); ++ UPDATE_CACHE(re, gb); ++ } ++ SKIP_BITS(re, gb, 1); ++ ++ if (i < limit - 1) { ++ if (k) { ++ if (k > MIN_CACHE_BITS - 1) { ++ buf = SHOW_UBITS(re, gb, 16) << (k-16); ++ LAST_SKIP_BITS(re, gb, 16); ++ UPDATE_CACHE(re, gb); ++ buf |= SHOW_UBITS(re, gb, k-16); ++ LAST_SKIP_BITS(re, gb, k-16); ++ } else { ++ buf = SHOW_UBITS(re, gb, k); ++ LAST_SKIP_BITS(re, gb, k); ++ } ++ } else { ++ buf = 0; ++ } ++ ++ buf += ((unsigned)i << k); ++ } else if (i == limit - 1) { ++ buf = SHOW_UBITS(re, gb, esc_len); ++ LAST_SKIP_BITS(re, gb, esc_len); ++ ++ buf ++; ++ } else { ++ buf = -1; ++ } ++ CLOSE_READER(re, gb); ++ return buf; ++ } ++#endif ++} ++ ++/** ++ * read signed golomb rice code (ffv1). ++ */ ++static inline int get_sr_golomb(GetBitContext *gb, int k, int limit, ++ int esc_len) ++{ ++ unsigned v = get_ur_golomb(gb, k, limit, esc_len); ++ return (v >> 1) ^ -(v & 1); ++} ++ ++/** ++ * read signed golomb rice code (flac). ++ */ ++static inline int get_sr_golomb_flac(GetBitContext *gb, int k, int limit, ++ int esc_len) ++{ ++ unsigned v = get_ur_golomb_jpegls(gb, k, limit, esc_len); ++ return (v >> 1) ^ -(v & 1); ++} ++ ++/** ++ * read unsigned golomb rice code (shorten). ++ */ ++static inline unsigned int get_ur_golomb_shorten(GetBitContext *gb, int k) ++{ ++ return get_ur_golomb_jpegls(gb, k, INT_MAX, 0); ++} ++ ++/** ++ * read signed golomb rice code (shorten). ++ */ ++static inline int get_sr_golomb_shorten(GetBitContext *gb, int k) ++{ ++ int uvar = get_ur_golomb_jpegls(gb, k + 1, INT_MAX, 0); ++ return (uvar >> 1) ^ -(uvar & 1); ++} ++ ++#ifdef TRACE ++ ++static inline int get_ue(GetBitContext *s, const char *file, const char *func, ++ int line) ++{ ++ int show = show_bits(s, 24); ++ int pos = get_bits_count(s); ++ int i = get_ue_golomb(s); ++ int len = get_bits_count(s) - pos; ++ int bits = show >> (24 - len); ++ ++ av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d ue @%5d in %s %s:%d\n", ++ bits, len, i, pos, file, func, line); ++ ++ return i; ++} ++ ++static inline int get_se(GetBitContext *s, const char *file, const char *func, ++ int line) ++{ ++ int show = show_bits(s, 24); ++ int pos = get_bits_count(s); ++ int i = get_se_golomb(s); ++ int len = get_bits_count(s) - pos; ++ int bits = show >> (24 - len); ++ ++ av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d se @%5d in %s %s:%d\n", ++ bits, len, i, pos, file, func, line); ++ ++ return i; ++} ++ ++static inline int get_te(GetBitContext *s, int r, char *file, const char *func, ++ int line) ++{ ++ int show = show_bits(s, 24); ++ int pos = get_bits_count(s); ++ int i = get_te0_golomb(s, r); ++ int len = get_bits_count(s) - pos; ++ int bits = show >> (24 - len); ++ ++ av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d te @%5d in %s %s:%d\n", ++ bits, len, i, pos, file, func, line); ++ ++ return i; ++} ++ ++#define get_ue_golomb(a) get_ue(a, __FILE__, __func__, __LINE__) ++#define get_se_golomb(a) get_se(a, __FILE__, __func__, __LINE__) ++#define get_te_golomb(a, r) get_te(a, r, __FILE__, __func__, __LINE__) ++#define get_te0_golomb(a, r) get_te(a, r, __FILE__, __func__, __LINE__) ++ ++#endif /* TRACE */ ++ ++/** ++ * write unsigned exp golomb code. 2^16 - 2 at most ++ */ ++static inline void set_ue_golomb(PutBitContext *pb, int i) ++{ ++ av_assert2(i >= 0); ++ av_assert2(i <= 0xFFFE); ++ ++ if (i < 256) ++ put_bits(pb, ff_ue_golomb_len[i], i + 1); ++ else { ++ int e = av_log2(i + 1); ++ put_bits(pb, 2 * e + 1, i + 1); ++ } ++} ++ ++/** ++ * write unsigned exp golomb code. 2^32-2 at most. ++ */ ++static inline void set_ue_golomb_long(PutBitContext *pb, uint32_t i) ++{ ++ av_assert2(i <= (UINT32_MAX - 1)); ++ ++ if (i < 256) ++ put_bits(pb, ff_ue_golomb_len[i], i + 1); ++ else { ++ int e = av_log2(i + 1); ++ put_bits64(pb, 2 * e + 1, i + 1); ++ } ++} ++ ++/** ++ * write truncated unsigned exp golomb code. ++ */ ++static inline void set_te_golomb(PutBitContext *pb, int i, int range) ++{ ++ av_assert2(range >= 1); ++ av_assert2(i <= range); ++ ++ if (range == 2) ++ put_bits(pb, 1, i ^ 1); ++ else ++ set_ue_golomb(pb, i); ++} ++ ++/** ++ * write signed exp golomb code. 16 bits at most. ++ */ ++static inline void set_se_golomb(PutBitContext *pb, int i) ++{ ++ i = 2 * i - 1; ++ if (i < 0) ++ i ^= -1; //FIXME check if gcc does the right thing ++ set_ue_golomb(pb, i); ++} ++ ++/** ++ * write unsigned golomb rice code (ffv1). ++ */ ++static inline void set_ur_golomb(PutBitContext *pb, int i, int k, int limit, ++ int esc_len) ++{ ++ int e; ++ ++ av_assert2(i >= 0); ++ ++ e = i >> k; ++ if (e < limit) ++ put_bits(pb, e + k + 1, (1 << k) + av_mod_uintp2(i, k)); ++ else ++ put_bits(pb, limit + esc_len, i - limit + 1); ++} ++ ++/** ++ * write unsigned golomb rice code (jpegls). ++ */ ++static inline void set_ur_golomb_jpegls(PutBitContext *pb, int i, int k, ++ int limit, int esc_len) ++{ ++ int e; ++ ++ av_assert2(i >= 0); ++ ++ e = (i >> k) + 1; ++ if (e < limit) { ++ while (e > 31) { ++ put_bits(pb, 31, 0); ++ e -= 31; ++ } ++ put_bits(pb, e, 1); ++ if (k) ++ put_sbits(pb, k, i); ++ } else { ++ while (limit > 31) { ++ put_bits(pb, 31, 0); ++ limit -= 31; ++ } ++ put_bits(pb, limit, 1); ++ put_bits(pb, esc_len, i - 1); ++ } ++} ++ ++/** ++ * write signed golomb rice code (ffv1). ++ */ ++static inline void set_sr_golomb(PutBitContext *pb, int i, int k, int limit, ++ int esc_len) ++{ ++ int v; ++ ++ v = -2 * i - 1; ++ v ^= (v >> 31); ++ ++ set_ur_golomb(pb, v, k, limit, esc_len); ++} ++ ++/** ++ * write signed golomb rice code (flac). ++ */ ++static inline void set_sr_golomb_flac(PutBitContext *pb, int i, int k, ++ int limit, int esc_len) ++{ ++ int v; ++ ++ v = -2 * i - 1; ++ v ^= (v >> 31); ++ ++ set_ur_golomb_jpegls(pb, v, k, limit, esc_len); ++} ++ ++#endif /* AVCODEC_GOLOMB_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264.h +new file mode 100644 +index 000000000..7a1fb6d68 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264.h +@@ -0,0 +1,113 @@ ++/* ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/** ++ * @file ++ * H.264 common definitions ++ */ ++ ++#ifndef AVCODEC_H264_H ++#define AVCODEC_H264_H ++ ++#define QP_MAX_NUM (51 + 6*6) // The maximum supported qp ++ ++/* ++ * Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes in ++ * T-REC-H.264-201704 ++ */ ++enum { ++ H264_NAL_UNSPECIFIED = 0, ++ H264_NAL_SLICE = 1, ++ H264_NAL_DPA = 2, ++ H264_NAL_DPB = 3, ++ H264_NAL_DPC = 4, ++ H264_NAL_IDR_SLICE = 5, ++ H264_NAL_SEI = 6, ++ H264_NAL_SPS = 7, ++ H264_NAL_PPS = 8, ++ H264_NAL_AUD = 9, ++ H264_NAL_END_SEQUENCE = 10, ++ H264_NAL_END_STREAM = 11, ++ H264_NAL_FILLER_DATA = 12, ++ H264_NAL_SPS_EXT = 13, ++ H264_NAL_PREFIX = 14, ++ H264_NAL_SUB_SPS = 15, ++ H264_NAL_DPS = 16, ++ H264_NAL_RESERVED17 = 17, ++ H264_NAL_RESERVED18 = 18, ++ H264_NAL_AUXILIARY_SLICE = 19, ++ H264_NAL_EXTEN_SLICE = 20, ++ H264_NAL_DEPTH_EXTEN_SLICE = 21, ++ H264_NAL_RESERVED22 = 22, ++ H264_NAL_RESERVED23 = 23, ++ H264_NAL_UNSPECIFIED24 = 24, ++ H264_NAL_UNSPECIFIED25 = 25, ++ H264_NAL_UNSPECIFIED26 = 26, ++ H264_NAL_UNSPECIFIED27 = 27, ++ H264_NAL_UNSPECIFIED28 = 28, ++ H264_NAL_UNSPECIFIED29 = 29, ++ H264_NAL_UNSPECIFIED30 = 30, ++ H264_NAL_UNSPECIFIED31 = 31, ++}; ++ ++ ++enum { ++ // 7.4.2.1.1: seq_parameter_set_id is in [0, 31]. ++ H264_MAX_SPS_COUNT = 32, ++ // 7.4.2.2: pic_parameter_set_id is in [0, 255]. ++ H264_MAX_PPS_COUNT = 256, ++ ++ // A.3: MaxDpbFrames is bounded above by 16. ++ H264_MAX_DPB_FRAMES = 16, ++ // 7.4.2.1.1: max_num_ref_frames is in [0, MaxDpbFrames], and ++ // each reference frame can have two fields. ++ H264_MAX_REFS = 2 * H264_MAX_DPB_FRAMES, ++ ++ // 7.4.3.1: modification_of_pic_nums_idc is not equal to 3 at most ++ // num_ref_idx_lN_active_minus1 + 1 times (that is, once for each ++ // possible reference), then equal to 3 once. ++ H264_MAX_RPLM_COUNT = H264_MAX_REFS + 1, ++ ++ // 7.4.3.3: in the worst case, we begin with a full short-term ++ // reference picture list. Each picture in turn is moved to the ++ // long-term list (type 3) and then discarded from there (type 2). ++ // Then, we set the length of the long-term list (type 4), mark ++ // the current picture as long-term (type 6) and terminate the ++ // process (type 0). ++ H264_MAX_MMCO_COUNT = H264_MAX_REFS * 2 + 3, ++ ++ // A.2.1, A.2.3: profiles supporting FMO constrain ++ // num_slice_groups_minus1 to be in [0, 7]. ++ H264_MAX_SLICE_GROUPS = 8, ++ ++ // E.2.2: cpb_cnt_minus1 is in [0, 31]. ++ H264_MAX_CPB_CNT = 32, ++ ++ // A.3: in table A-1 the highest level allows a MaxFS of 139264. ++ H264_MAX_MB_PIC_SIZE = 139264, ++ // A.3.1, A.3.2: PicWidthInMbs and PicHeightInMbs are constrained ++ // to be not greater than sqrt(MaxFS * 8). Hence height/width are ++ // bounded above by sqrt(139264 * 8) = 1055.5 macroblocks. ++ H264_MAX_MB_WIDTH = 1055, ++ H264_MAX_MB_HEIGHT = 1055, ++ H264_MAX_WIDTH = H264_MAX_MB_WIDTH * 16, ++ H264_MAX_HEIGHT = H264_MAX_MB_HEIGHT * 16, ++}; ++ ++ ++#endif /* AVCODEC_H264_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h2645_parse.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h2645_parse.h +new file mode 100644 +index 000000000..6f817b803 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h2645_parse.h +@@ -0,0 +1,93 @@ ++#ifndef AVCODEC_H2645_PARSE_H ++#define AVCODEC_H2645_PARSE_H ++ ++ ++#include "avcodec.h" ++#include "get_bits.h" ++ ++#define MAX_MBPAIR_SIZE (256*1024) // a tighter bound could be calculated if someone cares about a few bytes ++#define MAX_NALS_PER_PACKET (8) ++ ++typedef struct H2645NAL { ++ int size; ++ const uint8_t *data; ++ ++ /** ++ * Size, in bits, of just the data, excluding the stop bit and any trailing ++ * padding. I.e. what HEVC calls SODB. ++ */ ++ int size_bits; ++ ++ int raw_size; ++ const uint8_t *raw_data; ++ ++ GetBitContext gb; ++ ++ /** ++ * NAL unit type ++ */ ++ int type; ++ ++ /** ++ * HEVC only, nuh_temporal_id_plus_1 - 1 ++ */ ++ int temporal_id; ++ ++ int skipped_bytes; ++ int skipped_bytes_pos_size; ++ int *skipped_bytes_pos; ++ /** ++ * H.264 only, nal_ref_idc ++ */ ++ int ref_idc; ++} H2645NAL; ++ ++/* an input packet split into unescaped NAL units */ ++typedef struct H2645Packet { ++ H2645NAL *nals; ++ int nb_nals; ++ int nals_allocated; ++} H2645Packet; ++ ++/** ++ * Extract the raw (unescaped) bitstream. ++ */ ++int ff_h2645_extract_rbsp(const uint8_t *src, int length, ++ H2645NAL *nal, int small_padding); ++ ++/** ++ * Split an input packet into NAL units. ++ */ ++int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, ++ void *logctx, int is_nalff, int nal_length_size, ++ int small_padding); ++ ++/** ++ * Free all the allocated memory in the packet. ++ */ ++void ff_h2645_packet_uninit(H2645Packet *pkt); ++ ++static inline int get_nalsize(int nal_length_size, const uint8_t *buf, ++ int buf_size, int *buf_index, void *logctx) ++{ ++ int i, nalsize = 0; ++ ++ if (*buf_index >= buf_size - nal_length_size) { ++ // the end of the buffer is reached, refill it ++ return AVERROR(EAGAIN); ++ } ++ ++ /*å‡è®¾nal_length_size 为4 , 就是将buf里é¢çš„å†…å®¹è½¬æ¢æˆå®žé™…的大å°???? ++ *那么buffer里é¢çš„内容是什么呢? ++ * */ ++ for (i = 0; i < nal_length_size; i++) ++ nalsize = ((unsigned)nalsize << 8) | buf[(*buf_index)++]; ++ if (nalsize <= 0 || nalsize > buf_size - *buf_index) { ++ av_log(logctx, AV_LOG_ERROR, ++ "Invalid NAL unit size (%d > %d).\n", nalsize, buf_size - *buf_index); ++ return AVERROR_INVALIDDATA; ++ } ++ return nalsize; ++} ++ ++#endif /* AVCODEC_H2645_PARSE_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_parse.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_parse.h +new file mode 100644 +index 000000000..ec49093b1 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_parse.h +@@ -0,0 +1,70 @@ ++#ifndef AVCODEC_H264_PARSE_H ++#define AVCODEC_H264_PARSE_H ++ ++#include "get_bits.h" ++#include "h264_ps.h" ++ ++typedef struct H264PredWeightTable { ++ int use_weight; ++ int use_weight_chroma; ++ int luma_log2_weight_denom; ++ int chroma_log2_weight_denom; ++ int luma_weight_flag[2]; ///< 7.4.3.2 luma_weight_lX_flag ++ int chroma_weight_flag[2]; ///< 7.4.3.2 chroma_weight_lX_flag ++ // The following 2 can be changed to int8_t but that causes a 10 CPU cycles speed loss ++ int luma_weight[48][2][2]; ++ int chroma_weight[48][2][2][2]; ++ int implicit_weight[48][48][2]; ++} H264PredWeightTable; ++ ++typedef struct H264POCContext { ++ int poc_lsb; ++ int poc_msb; ++ int delta_poc_bottom; ++ int delta_poc[2]; ++ int frame_num; ++ int prev_poc_msb; ///< poc_msb of the last reference pic for POC type 0 ++ int prev_poc_lsb; ///< poc_lsb of the last reference pic for POC type 0 ++ int frame_num_offset; ///< for POC type 2 ++ int prev_frame_num_offset; ///< for POC type 2 ++ int prev_frame_num; ///< frame_num of the last pic for POC type 1/2 ++} H264POCContext; ++ ++int ff_h264_pred_weight_table(GetBitContext *gb, const SPS *sps, ++ const int *ref_count, int slice_type_nos, ++ H264PredWeightTable *pwt, ++ int picture_structure, void *logctx); ++ ++/** ++ * Check if the top & left blocks are available if needed & change the ++ * dc mode so it only uses the available blocks. ++ */ ++int ff_h264_check_intra4x4_pred_mode(int8_t *pred_mode_cache, void *logctx, ++ int top_samples_available, int left_samples_available); ++ ++/** ++ * Check if the top & left blocks are available if needed & change the ++ * dc mode so it only uses the available blocks. ++ */ ++int ff_h264_check_intra_pred_mode(void *logctx, int top_samples_available, ++ int left_samples_available, ++ int mode, int is_chroma); ++ ++int ff_h264_parse_ref_count(int *plist_count, int ref_count[2], ++ GetBitContext *gb, const PPS *pps, ++ int slice_type_nos, int picture_structure, void *logctx); ++ ++int ff_h264_init_poc(int pic_field_poc[2], int *pic_poc, ++ const SPS *sps, H264POCContext *poc, ++ int picture_structure, int nal_ref_idc); ++ ++int ff_h264_decode_extradata(const uint8_t *data, int size, H264ParamSets *ps, ++ int *is_avc, int *nal_length_size, ++ int err_recognition, void *logctx); ++ ++/** ++ * compute profile from sps ++ */ ++int ff_h264_get_profile(const SPS *sps); ++ ++#endif /* AVCODEC_H264_PARSE_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_ps.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_ps.h +new file mode 100644 +index 000000000..61ce1d584 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_ps.h +@@ -0,0 +1,184 @@ ++#ifndef AVCODEC_H264_PS_H ++#define AVCODEC_H264_PS_H ++ ++//#include "libavutil/buffer.h" ++//#include "libavutil/pixfmt.h" ++//#include "libavutil/rational.h" ++ ++#include "avcodec.h" ++#include "get_bits.h" ++#include "h264.h" ++ ++#if 0 ++#define MAX_SPS_COUNT 32 ++#define MAX_PPS_COUNT 256 ++#endif ++ ++#define MAX_SPS_COUNT 3 ++#define MAX_PPS_COUNT 4 ++#define MAX_LOG2_MAX_FRAME_NUM (12 + 4) ++ ++typedef struct AVRational{ ++ int num; ///< Numerator ++ int den; ///< Denominator ++} AVRational; ++ ++static const AVRational ff_h264_pixel_aspect[17] = { ++ { 0, 1 }, ++ { 1, 1 }, ++ { 12, 11 }, ++ { 10, 11 }, ++ { 16, 11 }, ++ { 40, 33 }, ++ { 24, 11 }, ++ { 20, 11 }, ++ { 32, 11 }, ++ { 80, 33 }, ++ { 18, 11 }, ++ { 15, 11 }, ++ { 64, 33 }, ++ { 160, 99 }, ++ { 4, 3 }, ++ { 3, 2 }, ++ { 2, 1 }, ++}; ++/** ++ * Sequence parameter set ++ */ ++typedef struct SPS { ++ unsigned int sps_id; ++ int profile_idc; ++ int level_idc; ++ int chroma_format_idc; ++ int transform_bypass; ///< qpprime_y_zero_transform_bypass_flag ++ int log2_max_frame_num; ///< log2_max_frame_num_minus4 + 4 ++ int poc_type; ///< pic_order_cnt_type ++ int log2_max_poc_lsb; ///< log2_max_pic_order_cnt_lsb_minus4 ++ int delta_pic_order_always_zero_flag; ++ int offset_for_non_ref_pic; ++ int offset_for_top_to_bottom_field; ++ int poc_cycle_length; ///< num_ref_frames_in_pic_order_cnt_cycle ++ int ref_frame_count; ///< num_ref_frames ++ int gaps_in_frame_num_allowed_flag; ++ int mb_width; ///< pic_width_in_mbs_minus1 + 1 ++ ///< (pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag) ++ int mb_height; ++ int frame_mbs_only_flag; ++ int mb_aff; ///< mb_adaptive_frame_field_flag ++ int direct_8x8_inference_flag; ++ int crop; ///< frame_cropping_flag ++ ++ /* those 4 are already in luma samples */ ++ unsigned int crop_left; ///< frame_cropping_rect_left_offset ++ unsigned int crop_right; ///< frame_cropping_rect_right_offset ++ unsigned int crop_top; ///< frame_cropping_rect_top_offset ++ unsigned int crop_bottom; ///< frame_cropping_rect_bottom_offset ++ int vui_parameters_present_flag; ++ AVRational sar; ++ int video_signal_type_present_flag; ++ int full_range; ++ int colour_description_present_flag; ++#if 0 ++ enum AVColorPrimaries color_primaries; ++ enum AVColorTransferCharacteristic color_trc; ++ enum AVColorSpace colorspace; ++#endif ++ int timing_info_present_flag; ++ uint32_t num_units_in_tick; ++ uint32_t time_scale; ++ int fixed_frame_rate_flag; ++ //short offset_for_ref_frame[256]; // FIXME dyn aloc? ++ short offset_for_ref_frame[128]; // FIXME dyn aloc? ++ int bitstream_restriction_flag; ++ int num_reorder_frames; ++ int scaling_matrix_present; ++ uint8_t scaling_matrix4[6][16]; ++ uint8_t scaling_matrix8[6][64]; ++ int nal_hrd_parameters_present_flag; ++ int vcl_hrd_parameters_present_flag; ++ int pic_struct_present_flag; ++ int time_offset_length; ++ int cpb_cnt; ///< See H.264 E.1.2 ++ int initial_cpb_removal_delay_length; ///< initial_cpb_removal_delay_length_minus1 + 1 ++ int cpb_removal_delay_length; ///< cpb_removal_delay_length_minus1 + 1 ++ int dpb_output_delay_length; ///< dpb_output_delay_length_minus1 + 1 ++ int bit_depth_luma; ///< bit_depth_luma_minus8 + 8 ++ int bit_depth_chroma; ///< bit_depth_chroma_minus8 + 8 ++ int residual_color_transform_flag; ///< residual_colour_transform_flag ++ int constraint_set_flags; ///< constraint_set[0-3]_flag ++#if 0 ++ uint8_t data[4096]; ++ size_t data_size; ++#endif ++} SPS; ++ ++/** ++ * Picture parameter set ++ */ ++typedef struct PPS { ++ unsigned int sps_id; ++ int cabac; ///< entropy_coding_mode_flag ++ int pic_order_present; ///< pic_order_present_flag ++ int slice_group_count; ///< num_slice_groups_minus1 + 1 ++ int mb_slice_group_map_type; ++ unsigned int ref_count[2]; ///< num_ref_idx_l0/1_active_minus1 + 1 ++ int weighted_pred; ///< weighted_pred_flag ++ int weighted_bipred_idc; ++ int init_qp; ///< pic_init_qp_minus26 + 26 ++ int init_qs; ///< pic_init_qs_minus26 + 26 ++ int chroma_qp_index_offset[2]; ++ int deblocking_filter_parameters_present; ///< deblocking_filter_parameters_present_flag ++ int constrained_intra_pred; ///< constrained_intra_pred_flag ++ int redundant_pic_cnt_present; ///< redundant_pic_cnt_present_flag ++ int transform_8x8_mode; ///< transform_8x8_mode_flag ++ uint8_t scaling_matrix4[6][16]; ++ uint8_t scaling_matrix8[6][64]; ++ uint8_t chroma_qp_table[2][QP_MAX_NUM+1]; ///< pre-scaled (with chroma_qp_index_offset) version of qp_table ++ int chroma_qp_diff; ++#if 0 ++ uint8_t data[4096]; ++ size_t data_size; ++#endif ++ ++#if 0 ++ uint32_t dequant4_buffer[6][QP_MAX_NUM + 1][16]; ++ uint32_t dequant8_buffer[6][QP_MAX_NUM + 1][64]; ++ uint32_t(*dequant4_coeff[6])[16]; ++ uint32_t(*dequant8_coeff[6])[64]; ++#endif ++} PPS; ++ ++typedef struct H264ParamSets { ++#if 0 ++ AVBufferRef *sps_list[MAX_SPS_COUNT]; ++ AVBufferRef *pps_list[MAX_PPS_COUNT]; ++ ++ AVBufferRef *pps_ref; ++ AVBufferRef *sps_ref; ++#endif ++ ++ SPS sps_list[MAX_SPS_COUNT]; ++ PPS pps_list[MAX_PPS_COUNT]; ++ /* currently active parameters sets */ ++ const PPS *pps; ++ const SPS *sps; ++} H264ParamSets; ++ ++/** ++ * Decode SPS ++ */ ++int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, ++ H264ParamSets *ps, int ignore_truncation); ++ ++/** ++ * Decode PPS ++ */ ++int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avctx, ++ H264ParamSets *ps, int bit_length); ++ ++/** ++ * Uninit H264 param sets structure. ++ */ ++void ff_h264_ps_uninit(H264ParamSets *ps); ++ ++#endif /* AVCODEC_H264_PS_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_sei.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_sei.h +new file mode 100644 +index 000000000..ed81d46e3 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264_sei.h +@@ -0,0 +1,189 @@ ++#ifndef AVCODEC_H264_SEI_H ++#define AVCODEC_H264_SEI_H ++ ++#include "get_bits.h" ++ ++/** ++ * SEI message types ++ */ ++typedef enum { ++ H264_SEI_TYPE_BUFFERING_PERIOD = 0, ///< buffering period (H.264, D.1.1) ++ H264_SEI_TYPE_PIC_TIMING = 1, ///< picture timing ++ H264_SEI_TYPE_PAN_SCAN_RECT = 2, ///< pan-scan rectangle ++ H264_SEI_TYPE_FILLER_PAYLOAD = 3, ///< filler data ++ H264_SEI_TYPE_USER_DATA_REGISTERED = 4, ///< registered user data as specified by Rec. ITU-T T.35 ++ H264_SEI_TYPE_USER_DATA_UNREGISTERED = 5, ///< unregistered user data ++ H264_SEI_TYPE_RECOVERY_POINT = 6, ///< recovery point (frame # to decoder sync) ++ H264_SEI_TYPE_FRAME_PACKING = 45, ///< frame packing arrangement ++ H264_SEI_TYPE_DISPLAY_ORIENTATION = 47, ///< display orientation ++ H264_SEI_TYPE_GREEN_METADATA = 56, ///< GreenMPEG information ++ H264_SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME = 137, ///< mastering display properties ++ H264_SEI_TYPE_ALTERNATIVE_TRANSFER = 147, ///< alternative transfer ++} H264_SEI_Type; ++ ++/** ++ * pic_struct in picture timing SEI message ++ */ ++typedef enum { ++ H264_SEI_PIC_STRUCT_FRAME = 0, ///< 0: %frame ++ H264_SEI_PIC_STRUCT_TOP_FIELD = 1, ///< 1: top field ++ H264_SEI_PIC_STRUCT_BOTTOM_FIELD = 2, ///< 2: bottom field ++ H264_SEI_PIC_STRUCT_TOP_BOTTOM = 3, ///< 3: top field, bottom field, in that order ++ H264_SEI_PIC_STRUCT_BOTTOM_TOP = 4, ///< 4: bottom field, top field, in that order ++ H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP = 5, ///< 5: top field, bottom field, top field repeated, in that order ++ H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6, ///< 6: bottom field, top field, bottom field repeated, in that order ++ H264_SEI_PIC_STRUCT_FRAME_DOUBLING = 7, ///< 7: %frame doubling ++ H264_SEI_PIC_STRUCT_FRAME_TRIPLING = 8 ///< 8: %frame tripling ++} H264_SEI_PicStructType; ++ ++/** ++ * frame_packing_arrangement types ++ */ ++typedef enum { ++ H264_SEI_FPA_TYPE_CHECKERBOARD = 0, ++ H264_SEI_FPA_TYPE_INTERLEAVE_COLUMN = 1, ++ H264_SEI_FPA_TYPE_INTERLEAVE_ROW = 2, ++ H264_SEI_FPA_TYPE_SIDE_BY_SIDE = 3, ++ H264_SEI_FPA_TYPE_TOP_BOTTOM = 4, ++ H264_SEI_FPA_TYPE_INTERLEAVE_TEMPORAL = 5, ++ H264_SEI_FPA_TYPE_2D = 6, ++} H264_SEI_FpaType; ++ ++typedef struct H264SEITimeCode { ++ /* When not continuously receiving full timecodes, we have to reference ++ the previous timecode received */ ++ int full; ++ int frame; ++ int seconds; ++ int minutes; ++ int hours; ++ int dropframe; ++} H264SEITimeCode; ++ ++typedef struct H264SEIPictureTiming { ++ int present; ++ H264_SEI_PicStructType pic_struct; ++ ++ /** ++ * Bit set of clock types for fields/frames in picture timing SEI message. ++ * For each found ct_type, appropriate bit is set (e.g., bit 1 for ++ * interlaced). ++ */ ++ int ct_type; ++ ++ /** ++ * dpb_output_delay in picture timing SEI message, see H.264 C.2.2 ++ */ ++ int dpb_output_delay; ++ ++ /** ++ * cpb_removal_delay in picture timing SEI message, see H.264 C.1.2 ++ */ ++ int cpb_removal_delay; ++ ++ /** ++ * Maximum three timecodes in a pic_timing SEI. ++ */ ++ H264SEITimeCode timecode[3]; ++ ++ /** ++ * Number of timecode in use ++ */ ++ int timecode_cnt; ++} H264SEIPictureTiming; ++ ++typedef struct H264SEIAFD { ++ int present; ++ uint8_t active_format_description; ++} H264SEIAFD; ++ ++typedef struct H264SEIA53Caption { ++#if 0 ++ AVBufferRef *buf_ref; ++#endif ++} H264SEIA53Caption; ++ ++typedef struct H264SEIUnregistered { ++ int x264_build; ++} H264SEIUnregistered; ++ ++typedef struct H264SEIRecoveryPoint { ++ /** ++ * recovery_frame_cnt ++ * ++ * Set to -1 if no recovery point SEI message found or to number of frames ++ * before playback synchronizes. Frames having recovery point are key ++ * frames. ++ */ ++ int recovery_frame_cnt; ++} H264SEIRecoveryPoint; ++ ++typedef struct H264SEIBufferingPeriod { ++ int present; ///< Buffering period SEI flag ++ int initial_cpb_removal_delay[32]; ///< Initial timestamps for CPBs ++} H264SEIBufferingPeriod; ++ ++typedef struct H264SEIFramePacking { ++ int present; ++ int arrangement_id; ++ int arrangement_cancel_flag; ///< is previous arrangement canceled, -1 if never received ++ H264_SEI_FpaType arrangement_type; ++ int arrangement_repetition_period; ++ int content_interpretation_type; ++ int quincunx_sampling_flag; ++ int current_frame_is_frame0_flag; ++} H264SEIFramePacking; ++ ++typedef struct H264SEIDisplayOrientation { ++ int present; ++ int anticlockwise_rotation; ++ int hflip, vflip; ++} H264SEIDisplayOrientation; ++ ++typedef struct H264SEIGreenMetaData { ++ uint8_t green_metadata_type; ++ uint8_t period_type; ++ uint16_t num_seconds; ++ uint16_t num_pictures; ++ uint8_t percent_non_zero_macroblocks; ++ uint8_t percent_intra_coded_macroblocks; ++ uint8_t percent_six_tap_filtering; ++ uint8_t percent_alpha_point_deblocking_instance; ++ uint8_t xsd_metric_type; ++ uint16_t xsd_metric_value; ++} H264SEIGreenMetaData; ++ ++typedef struct H264SEIAlternativeTransfer { ++ int present; ++ int preferred_transfer_characteristics; ++} H264SEIAlternativeTransfer; ++ ++typedef struct H264SEIContext { ++ H264SEIPictureTiming picture_timing; ++ H264SEIAFD afd; ++ H264SEIA53Caption a53_caption; ++ H264SEIUnregistered unregistered; ++ H264SEIRecoveryPoint recovery_point; ++ H264SEIBufferingPeriod buffering_period; ++ H264SEIFramePacking frame_packing; ++ H264SEIDisplayOrientation display_orientation; ++ H264SEIGreenMetaData green_metadata; ++ H264SEIAlternativeTransfer alternative_transfer; ++} H264SEIContext; ++ ++struct H264ParamSets; ++ ++int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, ++ const struct H264ParamSets *ps, void *logctx); ++ ++/** ++ * Reset SEI values at the beginning of the frame. ++ */ ++void ff_h264_sei_uninit(H264SEIContext *h); ++ ++/** ++ * Get stereo_mode string from the h264 frame_packing_arrangement ++ */ ++const char *ff_h264_sei_stereo_mode(const H264SEIFramePacking *h); ++ ++#endif /* AVCODEC_H264_SEI_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264data.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264data.h +new file mode 100644 +index 000000000..fdf6c4292 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264data.h +@@ -0,0 +1,41 @@ ++#ifndef AVCODEC_H264DATA_H ++#define AVCODEC_H264DATA_H ++ ++ ++#include "h264dec.h" ++ ++extern const uint8_t ff_h264_golomb_to_pict_type[5]; ++extern const uint8_t ff_h264_golomb_to_intra4x4_cbp[48]; ++extern const uint8_t ff_h264_golomb_to_inter_cbp[48]; ++ ++extern const uint8_t ff_h264_chroma_dc_scan[4]; ++extern const uint8_t ff_h264_chroma422_dc_scan[8]; ++ ++typedef struct IMbInfo { ++ uint16_t type; ++ uint8_t pred_mode; ++ uint8_t cbp; ++} IMbInfo; ++ ++extern const IMbInfo ff_h264_i_mb_type_info[26]; ++ ++typedef struct PMbInfo { ++ uint16_t type; ++ uint8_t partition_count; ++} PMbInfo; ++ ++extern const PMbInfo ff_h264_p_mb_type_info[5]; ++extern const PMbInfo ff_h264_p_sub_mb_type_info[4]; ++extern const PMbInfo ff_h264_b_mb_type_info[23]; ++extern const PMbInfo ff_h264_b_sub_mb_type_info[13]; ++ ++ ++extern const uint8_t ff_h264_dequant4_coeff_init[6][3]; ++extern const uint8_t ff_h264_dequant8_coeff_init_scan[16]; ++extern const uint8_t ff_h264_dequant8_coeff_init[6][6]; ++extern const uint8_t ff_h264_quant_rem6[QP_MAX_NUM + 1]; ++extern const uint8_t ff_h264_quant_div6[QP_MAX_NUM + 1]; ++ ++extern const uint8_t ff_h264_chroma_qp[7][QP_MAX_NUM + 1]; ++ ++#endif /* AVCODEC_H264DATA_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264dec.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264dec.h +new file mode 100644 +index 000000000..1ceb50128 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/h264dec.h +@@ -0,0 +1,622 @@ ++#ifndef AVCODEC_H264DEC_H ++#define AVCODEC_H264DEC_H ++ ++//#include "libavutil/intreadwrite.h" ++#include "list.h" ++#include "api/jzm_h264_dec.h" ++ ++#include "buffer.h" ++#include "vpu_ops.h" ++ ++#include "h264_parse.h" ++#include "h264_ps.h" ++#include "h264_sei.h" ++#include "h2645_parse.h" ++#include "mpegutils.h" ++ ++//#define H264_MAX_PICTURE_COUNT 36 ++#define H264_MAX_PICTURE_COUNT 16 ++ ++#define MAX_MMCO_COUNT 66 ++ ++#define MAX_DELAYED_PIC_COUNT 8 ++ ++/* Compiling in interlaced support reduces the speed ++ * of progressive decoding by about 2%. */ ++#define ALLOW_INTERLACE ++ ++#define FMO 0 ++ ++/** ++ * The maximum number of slices supported by the decoder. ++ * must be a power of 2 ++ */ ++#define MAX_SLICES 32 ++ ++#ifdef ALLOW_INTERLACE ++#define MB_MBAFF(h) (h)->mb_mbaff ++#define MB_FIELD(sl) (sl)->mb_field_decoding_flag ++#define FRAME_MBAFF(h) (h)->mb_aff_frame ++#define FIELD_PICTURE(h) ((h)->picture_structure != PICT_FRAME) ++#define LEFT_MBS 2 ++#define LTOP 0 ++#define LBOT 1 ++#define LEFT(i) (i) ++#else ++#define MB_MBAFF(h) 0 ++#define MB_FIELD(sl) 0 ++#define FRAME_MBAFF(h) 0 ++#define FIELD_PICTURE(h) 0 ++#undef IS_INTERLACED ++#define IS_INTERLACED(mb_type) 0 ++#define LEFT_MBS 1 ++#define LTOP 0 ++#define LBOT 0 ++#define LEFT(i) 0 ++#endif ++#define FIELD_OR_MBAFF_PICTURE(h) (FRAME_MBAFF(h) || FIELD_PICTURE(h)) ++ ++#ifndef CABAC ++#define CABAC(h) (h)->ps.pps->cabac ++#endif ++ ++#define CHROMA(h) ((h)->ps.sps->chroma_format_idc) ++#define CHROMA422(h) ((h)->ps.sps->chroma_format_idc == 2) ++#define CHROMA444(h) ((h)->ps.sps->chroma_format_idc == 3) ++ ++#define MB_TYPE_REF0 MB_TYPE_ACPRED // dirty but it fits in 16 bit ++#define MB_TYPE_8x8DCT 0x01000000 ++#define IS_REF0(a) ((a) & MB_TYPE_REF0) ++#define IS_8x8DCT(a) ((a) & MB_TYPE_8x8DCT) ++ ++#define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) ++/** ++ * Memory management control operation opcode. ++ */ ++typedef enum MMCOOpcode { ++ MMCO_END = 0, ++ MMCO_SHORT2UNUSED, ++ MMCO_LONG2UNUSED, ++ MMCO_SHORT2LONG, ++ MMCO_SET_MAX_LONG, ++ MMCO_RESET, ++ MMCO_LONG, ++} MMCOOpcode; ++ ++/** ++ * Memory management control operation. ++ */ ++typedef struct MMCO { ++ MMCOOpcode opcode; ++ int short_pic_num; ///< pic_num without wrapping (pic_num & max_pic_num) ++ int long_arg; ///< index, pic_num, or num long refs depending on opcode ++} MMCO; ++ ++typedef struct H264Picture { ++ AVFrame *f; ++ //ThreadFrame tf; ++ ++ AVBuffer *frm_info_ctrl; ++ AVBuffer *frm_info_mv; ++ ++ AVBuffer *dec_result_y; ++ AVBuffer *dec_result_uv; ++ ++ int field_poc[2]; ///< top/bottom POC ++ int poc; ///< frame POC ++ int frame_num; ///< frame_num (raw frame_num from slice header) ++ int mmco_reset; /**< MMCO_RESET set this 1. Reordering code must ++ not mix pictures before and after MMCO_RESET. */ ++ int pic_id; /**< pic_num (short -> no wrap version of pic_num, ++ pic_num & max_pic_num; long -> long_pic_num) */ ++ int long_ref; ///< 1->long term reference 0->short term reference ++ int ref_poc[2][2][32]; ///< POCs of the frames/fields used as reference (FIXME need per slice) ++ int ref_count[2][2]; ///< number of entries in ref_poc (FIXME need per slice) ++ int mbaff; ///< 1 -> MBAFF frame 0-> not MBAFF ++ int field_picture; ///< whether or not picture was encoded in separate fields ++ ++ int reference; ++ int recovered; ///< picture at IDR or recovery point + recovery count ++ int invalid_gap; ++ int sei_recovery_frame_cnt; ++ ++} H264Picture; ++ ++typedef struct H264Ref { ++ uint8_t *data[3]; ++ int linesize[3]; ++ ++ int reference; ++ int poc; ++ int pic_id; ++ ++ H264Picture *parent; ++} H264Ref; ++ ++typedef struct H264SliceContext { ++ struct H264Context *h264; ++ GetBitContext gb; ++ //ERContext er; ++ ++ int slice_num; ++ int slice_type; ++ int slice_type_nos; ///< S free slice type (SI/SP are remapped to I/P) ++ int slice_type_fixed; ++ ++ int qscale; ++ int chroma_qp[2]; // QPc ++ int qp_thresh; ///< QP threshold to skip loopfilter ++ int last_qscale_diff; ++ ++ // deblock ++ int deblocking_filter; ///< disable_deblocking_filter_idc with 1 <-> 0 ++ int slice_alpha_c0_offset; ++ int slice_beta_offset; ++ ++ H264PredWeightTable pwt; ++ ++ int prev_mb_skipped; ++ int next_mb_skipped; ++ ++ int chroma_pred_mode; ++ int intra16x16_pred_mode; ++ ++ ptrdiff_t linesize, uvlinesize; ++ ptrdiff_t mb_linesize; ///< may be equal to s->linesize or s->linesize * 2, for mbaff ++ ptrdiff_t mb_uvlinesize; ++ ++ int mb_x, mb_y; ++ int mb_xy; ++ int resync_mb_x; ++ int resync_mb_y; ++ unsigned int first_mb_addr; ++ // index of the first MB of the next slice ++ int next_slice_idx; ++ int mb_skip_run; ++ int is_complex; ++ ++ int picture_structure; ++ int mb_field_decoding_flag; ++ int mb_mbaff; ///< mb_aff_frame && mb_field_decoding_flag ++ ++ int redundant_pic_count; ++ ++ /** ++ * number of neighbors (top and/or left) that used 8x8 dct ++ */ ++ int neighbor_transform_size; ++ ++ int direct_spatial_mv_pred; ++ int col_parity; ++ int col_fieldoff; ++ ++ int cbp; ++ int top_cbp; ++ int left_cbp; ++ ++ int dist_scale_factor[32]; ++ int dist_scale_factor_field[2][32]; ++ int map_col_to_list0[2][16 + 32]; ++ int map_col_to_list0_field[2][2][16 + 32]; ++ ++ /** ++ * num_ref_idx_l0/1_active_minus1 + 1 ++ */ ++ unsigned int ref_count[2]; ///< counts frames or fields, depending on current mb mode ++ unsigned int list_count; ++ H264Ref ref_list[2][48]; /**< 0..15: frame refs, 16..47: mbaff field refs. ++ * Reordered version of default_ref_list ++ * according to picture reordering in slice header */ ++ struct { ++ uint8_t op; ++ uint32_t val; ++ } ref_modifications[2][32]; ++ int nb_ref_modifications[2]; ++ ++ unsigned int pps_id; ++ ++ const uint8_t *intra_pcm_ptr; ++ int16_t *dc_val_base; ++ ++ uint8_t *bipred_scratchpad; ++ uint8_t *edge_emu_buffer; ++ uint8_t (*top_borders[2])[(16 * 3) * 2]; ++ int bipred_scratchpad_allocated; ++ int edge_emu_buffer_allocated; ++ int top_borders_allocated[2]; ++ ++ int cabac_init_idc; ++ ++ MMCO mmco[MAX_MMCO_COUNT]; ++ int nb_mmco; ++ int explicit_ref_marking; ++ ++ int frame_num; ++ int poc_lsb; ++ int delta_poc_bottom; ++ int delta_poc[2]; ++ int curr_pic_num; ++ int max_pic_num; ++} H264SliceContext; ++ ++ ++#define SOC_TYPE_M200 1 ++#define SOC_TYPE_X2000 2 ++ ++#define VPU_FORMAT_TILE420 1 ++#define VPU_FORMAT_NV12 2 ++#define VPU_FORMAT_NV21 3 ++/** ++ * H264Context ++ */ ++typedef struct H264Context { ++ AVCodecContext *avctx; ++ ++ unsigned int api_version; ++ unsigned int format; /* output format.*/ ++ jzm_h264 *st_h264; /* 硬件解ç å™¨å¥æŸ„.*/ ++ ++#define DMA_DESC_SIZE (128*1024) ++ AVBuffer *dma_desc; ++ ++ devmem_ctx_t devmem_ctx; /*设备内存分é…噍奿Ÿ„.*/ ++ vpu_ctx_t vpu_ctx; /*vpuç¡¬ä»¶æŽ§åˆ¶å¥æŸ„*/ ++ ++ H264Picture DPB[H264_MAX_PICTURE_COUNT]; ++ H264Picture *cur_pic_ptr; ++ //H264Picture cur_pic; ++ //H264Picture last_pic_for_ec; ++ ++ /* ++ * è§£ç æ¯æ¬¡è°ƒç”¨ä¸€æ¬¡output_frame,将图象放入output_picture_list; ++ * 未æ¥ä¼šå°†output_picture_list,æ¢æˆoutput_frame_list.åªç”¨æ¥å­˜æ”¾è§£ç åŽçš„帧信æ¯. ++ * ++ * */ ++ struct list_head done_list; /* 完æˆçš„frame列表.*/ ++ struct list_head queued_list; /*å¯ä»¥ç”¨äºŽè§£ç çš„frame_buffer list.*/ ++ ++ H264SliceContext *slice_ctx; ++ int nb_slice_ctx; ++ int nb_slice_ctx_queued; ++ ++ H2645Packet pkt; ++ ++ int pixel_shift; ///< 0 for 8-bit H.264, 1 for high-bit-depth H.264 ++ ++ /* coded dimensions -- 16 * mb w/h */ ++ int width, height; ++ int chroma_x_shift, chroma_y_shift; ++ ++ int droppable; ++ int coded_picture_number; ++ ++ int context_initialized; ++ int flags; ++ int workaround_bugs; ++ int x264_build; ++ /* Set when slice threading is used and at least one slice uses deblocking ++ * mode 1 (i.e. across slice boundaries). Then we disable the loop filter ++ * during normal MB decoding and execute it serially at the end. ++ */ ++ int postpone_filter; ++ ++ /* ++ * Set to 1 when the current picture is IDR, 0 otherwise. ++ */ ++ int picture_idr; ++ ++ int crop_left; ++ int crop_right; ++ int crop_top; ++ int crop_bottom; ++ ++ ++#define LIST_NOT_USED -1 // FIXME rename? ++#define PART_NOT_AVAILABLE -2 ++ ++ int b_stride; // FIXME use s->b4_stride ++ uint16_t *slice_table; ///< slice_table_base + 2*mb_stride + 1 ++ ++ // interlacing specific flags ++ int mb_aff_frame; ++ int picture_structure; ++ int first_field; ++ ++ uint8_t *list_counts; ///< Array of list_count per MB specifying the slice type ++ ++ int mb_y; ++ int mb_height, mb_width; ++ int mb_stride; ++ int mb_num; ++ ++ // ============================================================= ++ // Things below are not used in the MB or more inner code ++ ++ int nal_ref_idc; ++ int nal_unit_type; ++ ++ int has_slice; ///< slice NAL is found in the packet, set by decode_nal_units, its state does not need to be preserved outside h264_decode_frame() ++ ++ /** ++ * Used to parse AVC variant of H.264 ++ */ ++ int is_avc; ///< this flag is != 0 if codec is avc1 ++ int nal_length_size; ///< Number of bytes used for nal length (1, 2 or 4) ++ ++ int bit_depth_luma; ///< luma bit depth from sps to detect changes ++ int chroma_format_idc; ///< chroma format from sps to detect changes ++ ++ H264ParamSets ps; ++ ++ // uint16_t *slice_table_base; ++ ++ H264POCContext poc; ++ ++ H264Ref default_ref[2]; ++ H264Picture *short_ref[32]; ++ H264Picture *long_ref[32]; ++ H264Picture *delayed_pic[MAX_DELAYED_PIC_COUNT + 2]; // FIXME size? ++ int last_pocs[MAX_DELAYED_PIC_COUNT]; ++ H264Picture *next_output_pic; ++ int next_outputed_poc; ++ ++ /** ++ * memory management control operations buffer. ++ */ ++ MMCO mmco[MAX_MMCO_COUNT]; ++ int nb_mmco; ++ int mmco_reset; ++ int explicit_ref_marking; ++ ++ int long_ref_count; ///< number of actual long term references ++ int short_ref_count; ///< number of actual short term references ++ ++ /** ++ * @name Members for slice based multithreading ++ * @{ ++ */ ++ /** ++ * current slice number, used to initialize slice_num of each thread/context ++ */ ++ int current_slice; ++ ++ /** @} */ ++ ++ /** ++ * Complement sei_pic_struct ++ * SEI_PIC_STRUCT_TOP_BOTTOM and SEI_PIC_STRUCT_BOTTOM_TOP indicate interlaced frames. ++ * However, soft telecined frames may have these values. ++ * This is used in an attempt to flag soft telecine progressive. ++ */ ++ int prev_interlaced_frame; ++ ++ /** ++ * Are the SEI recovery points looking valid. ++ */ ++ int valid_recovery_point; ++ ++ /** ++ * recovery_frame is the frame_num at which the next frame should ++ * be fully constructed. ++ * ++ * Set to -1 when not expecting a recovery point. ++ */ ++ int recovery_frame; ++ ++/** ++ * We have seen an IDR, so all the following frames in coded order are correctly ++ * decodable. ++ */ ++#define FRAME_RECOVERED_IDR (1 << 0) ++/** ++ * Sufficient number of frames have been decoded since a SEI recovery point, ++ * so all the following frames in presentation order are correct. ++ */ ++#define FRAME_RECOVERED_SEI (1 << 1) ++ ++ int frame_recovered; ///< Initial frame has been completely recovered ++ ++ int has_recovery_point; ++ ++ int missing_fields; ++ ++ /* for frame threading, this is set to 1 ++ * after finish_setup() has been called, so we cannot modify ++ * some context properties (which are supposed to stay constant between ++ * slices) anymore */ ++ int setup_finished; ++ ++ int cur_chroma_format_idc; ++ int cur_bit_depth_luma; ++ //int16_t slice_row[MAX_SLICES]; ///< to detect when MAX_SLICES is too low ++ ++ /* original AVCodecContext dimensions, used to handle container ++ * cropping */ ++ int width_from_caller; ++ int height_from_caller; ++ ++ unsigned int coded_width; ++ unsigned int coded_height; ++ ++ int enable_er; ++ ++ //H264SEIContext sei; ++ //int ref2frm[MAX_SLICES][2][64]; ///< reference to frame number lists, used in the loop filter, the first 2 are for -2,-1 ++} H264Context; ++ ++extern const uint16_t ff_h264_mb_sizes[4]; ++ ++/** ++ * Reconstruct bitstream slice_type. ++ */ ++int ff_h264_get_slice_type(const H264SliceContext *sl); ++ ++/** ++ * Allocate tables. ++ * needs width/height ++ */ ++int ff_h264_alloc_tables(H264Context *h); ++ ++int ff_h264_decode_ref_pic_list_reordering(H264SliceContext *sl, void *logctx); ++int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl); ++void ff_h264_remove_all_refs(H264Context *h); ++ ++/** ++ * Execute the reference picture marking (memory management control operations). ++ */ ++int ff_h264_execute_ref_pic_marking(H264Context *h); ++ ++int ff_h264_decode_ref_pic_marking(H264SliceContext *sl, GetBitContext *gb, ++ const H2645NAL *nal, void *logctx); ++ ++void ff_h264_hl_decode_mb(const H264Context *h, H264SliceContext *sl); ++void ff_h264_decode_init_vlc(void); ++ ++#if 0 ++/** ++ * Decode a macroblock ++ * @return 0 if OK, ER_AC_ERROR / ER_DC_ERROR / ER_MV_ERROR on error ++ */ ++int ff_h264_decode_mb_cavlc(const H264Context *h, H264SliceContext *sl); ++ ++/** ++ * Decode a CABAC coded macroblock ++ * @return 0 if OK, ER_AC_ERROR / ER_DC_ERROR / ER_MV_ERROR on error ++ */ ++int ff_h264_decode_mb_cabac(const H264Context *h, H264SliceContext *sl); ++#endif ++ ++void ff_h264_init_cabac_states(const H264Context *h, H264SliceContext *sl); ++ ++void ff_h264_direct_dist_scale_factor(const H264Context *const h, H264SliceContext *sl); ++void ff_h264_direct_ref_list_init(const H264Context *const h, H264SliceContext *sl); ++void ff_h264_pred_direct_motion(const H264Context *const h, H264SliceContext *sl, ++ int *mb_type); ++ ++void ff_h264_filter_mb_fast(const H264Context *h, H264SliceContext *sl, int mb_x, int mb_y, ++ uint8_t *img_y, uint8_t *img_cb, uint8_t *img_cr, ++ unsigned int linesize, unsigned int uvlinesize); ++void ff_h264_filter_mb(const H264Context *h, H264SliceContext *sl, int mb_x, int mb_y, ++ uint8_t *img_y, uint8_t *img_cb, uint8_t *img_cr, ++ unsigned int linesize, unsigned int uvlinesize); ++ ++/* ++ * o-o o-o ++ * / / / ++ * o-o o-o ++ * ,---' ++ * o-o o-o ++ * / / / ++ * o-o o-o ++ */ ++ ++/* Scan8 organization: ++ * 0 1 2 3 4 5 6 7 ++ * 0 DY y y y y y ++ * 1 y Y Y Y Y ++ * 2 y Y Y Y Y ++ * 3 y Y Y Y Y ++ * 4 y Y Y Y Y ++ * 5 DU u u u u u ++ * 6 u U U U U ++ * 7 u U U U U ++ * 8 u U U U U ++ * 9 u U U U U ++ * 10 DV v v v v v ++ * 11 v V V V V ++ * 12 v V V V V ++ * 13 v V V V V ++ * 14 v V V V V ++ * DY/DU/DV are for luma/chroma DC. ++ */ ++ ++#define LUMA_DC_BLOCK_INDEX 48 ++#define CHROMA_DC_BLOCK_INDEX 49 ++ ++// This table must be here because scan8[constant] must be known at compiletime ++static const uint8_t scan8[16 * 3 + 3] = { ++ 4 + 1 * 8, 5 + 1 * 8, 4 + 2 * 8, 5 + 2 * 8, ++ 6 + 1 * 8, 7 + 1 * 8, 6 + 2 * 8, 7 + 2 * 8, ++ 4 + 3 * 8, 5 + 3 * 8, 4 + 4 * 8, 5 + 4 * 8, ++ 6 + 3 * 8, 7 + 3 * 8, 6 + 4 * 8, 7 + 4 * 8, ++ 4 + 6 * 8, 5 + 6 * 8, 4 + 7 * 8, 5 + 7 * 8, ++ 6 + 6 * 8, 7 + 6 * 8, 6 + 7 * 8, 7 + 7 * 8, ++ 4 + 8 * 8, 5 + 8 * 8, 4 + 9 * 8, 5 + 9 * 8, ++ 6 + 8 * 8, 7 + 8 * 8, 6 + 9 * 8, 7 + 9 * 8, ++ 4 + 11 * 8, 5 + 11 * 8, 4 + 12 * 8, 5 + 12 * 8, ++ 6 + 11 * 8, 7 + 11 * 8, 6 + 12 * 8, 7 + 12 * 8, ++ 4 + 13 * 8, 5 + 13 * 8, 4 + 14 * 8, 5 + 14 * 8, ++ 6 + 13 * 8, 7 + 13 * 8, 6 + 14 * 8, 7 + 14 * 8, ++ 0 + 0 * 8, 0 + 5 * 8, 0 + 10 * 8 ++}; ++ ++static inline uint32_t pack16to32(unsigned a, unsigned b) ++{ ++ return (a & 0xFFFF) + (b << 16); ++} ++ ++static inline uint16_t pack8to16(unsigned a, unsigned b) ++{ ++ return (a & 0xFF) + (b << 8); ++} ++ ++/** ++ * Get the chroma qp. ++ */ ++static inline int get_chroma_qp(const PPS *pps, int t, int qscale) ++{ ++ return pps->chroma_qp_table[t][qscale]; ++} ++ ++int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup); ++ ++int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src); ++void ff_h264_unref_picture(H264Context *h, H264Picture *pic); ++void ff_h264_release_picture(H264Context *h, H264Picture *pic); ++ ++int ff_h264_slice_context_init(H264Context *h, H264SliceContext *sl); ++ ++void ff_h264_draw_horiz_band(const H264Context *h, H264SliceContext *sl, int y, int height); ++ ++int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl, ++ const H2645NAL *nal); ++/** ++ * Submit a slice for decoding. ++ * ++ * Parse the slice header, starting a new field/frame if necessary. If any ++ * slices are queued for the previous field, they are decoded. ++ */ ++int ff_h264_queue_decode_slice(H264Context *h, const H2645NAL *nal); ++int ff_h264_execute_decode_slices(H264Context *h); ++int ff_h264_update_thread_context(AVCodecContext *dst, ++ const AVCodecContext *src); ++ ++void ff_h264_flush_change(H264Context *h); ++ ++void ff_h264_free_tables(H264Context *h); ++#if 0 ++void ff_h264_set_erpic(ERPicture *dst, H264Picture *src); ++#endif ++int h264_enqueue_frame(H264Context *h, AVFrame *f); ++AVFrame *h264_get_queued_frame(H264Context *h); /*get frame from queued list.*/ ++AVFrame *h264_dequeue_frame(H264Context *h); ++ ++int h264_decode_frame(AVCodecContext *avctx, void *data, ++ int *got_frame, AVPacket *avpkt); ++ ++int h264_decode_init(AVCodecContext *avctx); ++int h264_decode_end(AVCodecContext *avctx); ++int h264_set_vpu_ops(H264Context *h, void *priv_data, struct vpu_ops *ops); ++ ++static inline void h264_set_output_format(H264Context *h, int format, unsigned int coded_width, unsigned int coded_height) ++{ ++ h->format = format; ++ h->coded_width = coded_width; ++ h->coded_height = coded_height; ++} ++static inline int h264_get_output_format(H264Context *h) ++{ ++ return h->format; ++} ++ ++#endif /* AVCODEC_H264DEC_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/intreadwrite.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/intreadwrite.h +new file mode 100644 +index 000000000..d7a3f08a7 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/intreadwrite.h +@@ -0,0 +1,509 @@ ++#ifndef AVUTIL_INTREADWRITE_H ++#define AVUTIL_INTREADWRITE_H ++ ++#ifdef __KERNEL__ ++#else ++#include ++#endif ++ ++//#include "libavutil/avconfig.h" ++//#include "attributes.h" ++#include "bswap.h" ++ ++typedef union { ++ uint64_t u64; ++ uint32_t u32[2]; ++ uint16_t u16[4]; ++ uint8_t u8 [8]; ++ double f64; ++ float f32[2]; ++} av_alias64; ++ ++typedef union { ++ uint32_t u32; ++ uint16_t u16[2]; ++ uint8_t u8 [4]; ++ float f32; ++} av_alias32; ++ ++typedef union { ++ uint16_t u16; ++ uint8_t u8 [2]; ++} av_alias16; ++ ++ ++/* ++ * Map AV_RNXX <-> AV_R[BL]XX for all variants provided by per-arch headers. ++ */ ++ ++# if defined(AV_RN16) && !defined(AV_RL16) ++# define AV_RL16(p) AV_RN16(p) ++# elif !defined(AV_RN16) && defined(AV_RL16) ++# define AV_RN16(p) AV_RL16(p) ++# endif ++ ++# if defined(AV_WN16) && !defined(AV_WL16) ++# define AV_WL16(p, v) AV_WN16(p, v) ++# elif !defined(AV_WN16) && defined(AV_WL16) ++# define AV_WN16(p, v) AV_WL16(p, v) ++# endif ++ ++# if defined(AV_RN24) && !defined(AV_RL24) ++# define AV_RL24(p) AV_RN24(p) ++# elif !defined(AV_RN24) && defined(AV_RL24) ++# define AV_RN24(p) AV_RL24(p) ++# endif ++ ++# if defined(AV_WN24) && !defined(AV_WL24) ++# define AV_WL24(p, v) AV_WN24(p, v) ++# elif !defined(AV_WN24) && defined(AV_WL24) ++# define AV_WN24(p, v) AV_WL24(p, v) ++# endif ++ ++# if defined(AV_RN32) && !defined(AV_RL32) ++# define AV_RL32(p) AV_RN32(p) ++# elif !defined(AV_RN32) && defined(AV_RL32) ++# define AV_RN32(p) AV_RL32(p) ++# endif ++ ++# if defined(AV_WN32) && !defined(AV_WL32) ++# define AV_WL32(p, v) AV_WN32(p, v) ++# elif !defined(AV_WN32) && defined(AV_WL32) ++# define AV_WN32(p, v) AV_WL32(p, v) ++# endif ++ ++# if defined(AV_RN48) && !defined(AV_RL48) ++# define AV_RL48(p) AV_RN48(p) ++# elif !defined(AV_RN48) && defined(AV_RL48) ++# define AV_RN48(p) AV_RL48(p) ++# endif ++ ++# if defined(AV_WN48) && !defined(AV_WL48) ++# define AV_WL48(p, v) AV_WN48(p, v) ++# elif !defined(AV_WN48) && defined(AV_WL48) ++# define AV_WN48(p, v) AV_WL48(p, v) ++# endif ++ ++# if defined(AV_RN64) && !defined(AV_RL64) ++# define AV_RL64(p) AV_RN64(p) ++# elif !defined(AV_RN64) && defined(AV_RL64) ++# define AV_RN64(p) AV_RL64(p) ++# endif ++ ++# if defined(AV_WN64) && !defined(AV_WL64) ++# define AV_WL64(p, v) AV_WN64(p, v) ++# elif !defined(AV_WN64) && defined(AV_WL64) ++# define AV_WN64(p, v) AV_WL64(p, v) ++# endif ++ ++ ++/* ++ * Define AV_[RW]N helper macros to simplify definitions not provided ++ * by per-arch headers. ++ */ ++ ++#if defined(__GNUC__) ++ ++union unaligned_64 { uint64_t l; } __attribute__((packed)); ++union unaligned_32 { uint32_t l; } __attribute__((packed)); ++union unaligned_16 { uint16_t l; } __attribute__((packed)); ++ ++# define AV_RN(s, p) (((const union unaligned_##s *) (p))->l) ++# define AV_WN(s, p, v) ((((union unaligned_##s *) (p))->l) = (v)) ++ ++#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_X64) || defined(_M_ARM64)) && AV_HAVE_FAST_UNALIGNED ++ ++# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) ++# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) ++ ++#elif AV_HAVE_FAST_UNALIGNED ++ ++# define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) ++# define AV_WN(s, p, v) (((av_alias##s*)(p))->u##s = (v)) ++ ++#else ++ ++#ifndef AV_RB16 ++# define AV_RB16(x) \ ++ ((((const uint8_t*)(x))[0] << 8) | \ ++ ((const uint8_t*)(x))[1]) ++#endif ++#ifndef AV_WB16 ++# define AV_WB16(p, val) do { \ ++ uint16_t d = (val); \ ++ ((uint8_t*)(p))[1] = (d); \ ++ ((uint8_t*)(p))[0] = (d)>>8; \ ++ } while(0) ++#endif ++ ++#ifndef AV_RL16 ++# define AV_RL16(x) \ ++ ((((const uint8_t*)(x))[1] << 8) | \ ++ ((const uint8_t*)(x))[0]) ++#endif ++#ifndef AV_WL16 ++# define AV_WL16(p, val) do { \ ++ uint16_t d = (val); \ ++ ((uint8_t*)(p))[0] = (d); \ ++ ((uint8_t*)(p))[1] = (d)>>8; \ ++ } while(0) ++#endif ++ ++#ifndef AV_RB32 ++# define AV_RB32(x) \ ++ (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ ++ (((const uint8_t*)(x))[1] << 16) | \ ++ (((const uint8_t*)(x))[2] << 8) | \ ++ ((const uint8_t*)(x))[3]) ++#endif ++#ifndef AV_WB32 ++# define AV_WB32(p, val) do { \ ++ uint32_t d = (val); \ ++ ((uint8_t*)(p))[3] = (d); \ ++ ((uint8_t*)(p))[2] = (d)>>8; \ ++ ((uint8_t*)(p))[1] = (d)>>16; \ ++ ((uint8_t*)(p))[0] = (d)>>24; \ ++ } while(0) ++#endif ++ ++#ifndef AV_RL32 ++# define AV_RL32(x) \ ++ (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ ++ (((const uint8_t*)(x))[2] << 16) | \ ++ (((const uint8_t*)(x))[1] << 8) | \ ++ ((const uint8_t*)(x))[0]) ++#endif ++#ifndef AV_WL32 ++# define AV_WL32(p, val) do { \ ++ uint32_t d = (val); \ ++ ((uint8_t*)(p))[0] = (d); \ ++ ((uint8_t*)(p))[1] = (d)>>8; \ ++ ((uint8_t*)(p))[2] = (d)>>16; \ ++ ((uint8_t*)(p))[3] = (d)>>24; \ ++ } while(0) ++#endif ++ ++#ifndef AV_RB64 ++# define AV_RB64(x) \ ++ (((uint64_t)((const uint8_t*)(x))[0] << 56) | \ ++ ((uint64_t)((const uint8_t*)(x))[1] << 48) | \ ++ ((uint64_t)((const uint8_t*)(x))[2] << 40) | \ ++ ((uint64_t)((const uint8_t*)(x))[3] << 32) | \ ++ ((uint64_t)((const uint8_t*)(x))[4] << 24) | \ ++ ((uint64_t)((const uint8_t*)(x))[5] << 16) | \ ++ ((uint64_t)((const uint8_t*)(x))[6] << 8) | \ ++ (uint64_t)((const uint8_t*)(x))[7]) ++#endif ++#ifndef AV_WB64 ++# define AV_WB64(p, val) do { \ ++ uint64_t d = (val); \ ++ ((uint8_t*)(p))[7] = (d); \ ++ ((uint8_t*)(p))[6] = (d)>>8; \ ++ ((uint8_t*)(p))[5] = (d)>>16; \ ++ ((uint8_t*)(p))[4] = (d)>>24; \ ++ ((uint8_t*)(p))[3] = (d)>>32; \ ++ ((uint8_t*)(p))[2] = (d)>>40; \ ++ ((uint8_t*)(p))[1] = (d)>>48; \ ++ ((uint8_t*)(p))[0] = (d)>>56; \ ++ } while(0) ++#endif ++ ++#ifndef AV_RL64 ++# define AV_RL64(x) \ ++ (((uint64_t)((const uint8_t*)(x))[7] << 56) | \ ++ ((uint64_t)((const uint8_t*)(x))[6] << 48) | \ ++ ((uint64_t)((const uint8_t*)(x))[5] << 40) | \ ++ ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ ++ ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ ++ ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ ++ ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ ++ (uint64_t)((const uint8_t*)(x))[0]) ++#endif ++#ifndef AV_WL64 ++# define AV_WL64(p, val) do { \ ++ uint64_t d = (val); \ ++ ((uint8_t*)(p))[0] = (d); \ ++ ((uint8_t*)(p))[1] = (d)>>8; \ ++ ((uint8_t*)(p))[2] = (d)>>16; \ ++ ((uint8_t*)(p))[3] = (d)>>24; \ ++ ((uint8_t*)(p))[4] = (d)>>32; \ ++ ((uint8_t*)(p))[5] = (d)>>40; \ ++ ((uint8_t*)(p))[6] = (d)>>48; \ ++ ((uint8_t*)(p))[7] = (d)>>56; \ ++ } while(0) ++#endif ++ ++#if AV_HAVE_BIGENDIAN ++# define AV_RN(s, p) AV_RB##s(p) ++# define AV_WN(s, p, v) AV_WB##s(p, v) ++#else ++# define AV_RN(s, p) AV_RL##s(p) ++# define AV_WN(s, p, v) AV_WL##s(p, v) ++#endif ++ ++#endif /* HAVE_FAST_UNALIGNED */ ++ ++#ifndef AV_RN16 ++# define AV_RN16(p) AV_RN(16, p) ++#endif ++ ++#ifndef AV_RN32 ++# define AV_RN32(p) AV_RN(32, p) ++#endif ++ ++#ifndef AV_RN64 ++# define AV_RN64(p) AV_RN(64, p) ++#endif ++ ++#ifndef AV_WN16 ++# define AV_WN16(p, v) AV_WN(16, p, v) ++#endif ++ ++#ifndef AV_WN32 ++# define AV_WN32(p, v) AV_WN(32, p, v) ++#endif ++ ++#ifndef AV_WN64 ++# define AV_WN64(p, v) AV_WN(64, p, v) ++#endif ++ ++# define AV_RB(s, p) av_bswap##s(AV_RN##s(p)) ++# define AV_WB(s, p, v) AV_WN##s(p, av_bswap##s(v)) ++# define AV_RL(s, p) AV_RN##s(p) ++# define AV_WL(s, p, v) AV_WN##s(p, v) ++ ++#define AV_RB8(x) (((const uint8_t*)(x))[0]) ++#define AV_WB8(p, d) do { ((uint8_t*)(p))[0] = (d); } while(0) ++ ++#define AV_RL8(x) AV_RB8(x) ++#define AV_WL8(p, d) AV_WB8(p, d) ++ ++#ifndef AV_RB16 ++# define AV_RB16(p) AV_RB(16, p) ++#endif ++#ifndef AV_WB16 ++# define AV_WB16(p, v) AV_WB(16, p, v) ++#endif ++ ++#ifndef AV_RL16 ++# define AV_RL16(p) AV_RL(16, p) ++#endif ++#ifndef AV_WL16 ++# define AV_WL16(p, v) AV_WL(16, p, v) ++#endif ++ ++#ifndef AV_RB32 ++# define AV_RB32(p) AV_RB(32, p) ++#endif ++#ifndef AV_WB32 ++# define AV_WB32(p, v) AV_WB(32, p, v) ++#endif ++ ++#ifndef AV_RL32 ++# define AV_RL32(p) AV_RL(32, p) ++#endif ++#ifndef AV_WL32 ++# define AV_WL32(p, v) AV_WL(32, p, v) ++#endif ++ ++#ifndef AV_RB64 ++# define AV_RB64(p) AV_RB(64, p) ++#endif ++#ifndef AV_WB64 ++# define AV_WB64(p, v) AV_WB(64, p, v) ++#endif ++ ++#ifndef AV_RL64 ++# define AV_RL64(p) AV_RL(64, p) ++#endif ++#ifndef AV_WL64 ++# define AV_WL64(p, v) AV_WL(64, p, v) ++#endif ++ ++#ifndef AV_RB24 ++# define AV_RB24(x) \ ++ ((((const uint8_t*)(x))[0] << 16) | \ ++ (((const uint8_t*)(x))[1] << 8) | \ ++ ((const uint8_t*)(x))[2]) ++#endif ++#ifndef AV_WB24 ++# define AV_WB24(p, d) do { \ ++ ((uint8_t*)(p))[2] = (d); \ ++ ((uint8_t*)(p))[1] = (d)>>8; \ ++ ((uint8_t*)(p))[0] = (d)>>16; \ ++ } while(0) ++#endif ++ ++#ifndef AV_RL24 ++# define AV_RL24(x) \ ++ ((((const uint8_t*)(x))[2] << 16) | \ ++ (((const uint8_t*)(x))[1] << 8) | \ ++ ((const uint8_t*)(x))[0]) ++#endif ++#ifndef AV_WL24 ++# define AV_WL24(p, d) do { \ ++ ((uint8_t*)(p))[0] = (d); \ ++ ((uint8_t*)(p))[1] = (d)>>8; \ ++ ((uint8_t*)(p))[2] = (d)>>16; \ ++ } while(0) ++#endif ++ ++#ifndef AV_RB48 ++# define AV_RB48(x) \ ++ (((uint64_t)((const uint8_t*)(x))[0] << 40) | \ ++ ((uint64_t)((const uint8_t*)(x))[1] << 32) | \ ++ ((uint64_t)((const uint8_t*)(x))[2] << 24) | \ ++ ((uint64_t)((const uint8_t*)(x))[3] << 16) | \ ++ ((uint64_t)((const uint8_t*)(x))[4] << 8) | \ ++ (uint64_t)((const uint8_t*)(x))[5]) ++#endif ++#ifndef AV_WB48 ++# define AV_WB48(p, darg) do { \ ++ uint64_t d = (darg); \ ++ ((uint8_t*)(p))[5] = (d); \ ++ ((uint8_t*)(p))[4] = (d)>>8; \ ++ ((uint8_t*)(p))[3] = (d)>>16; \ ++ ((uint8_t*)(p))[2] = (d)>>24; \ ++ ((uint8_t*)(p))[1] = (d)>>32; \ ++ ((uint8_t*)(p))[0] = (d)>>40; \ ++ } while(0) ++#endif ++ ++#ifndef AV_RL48 ++# define AV_RL48(x) \ ++ (((uint64_t)((const uint8_t*)(x))[5] << 40) | \ ++ ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ ++ ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ ++ ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ ++ ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ ++ (uint64_t)((const uint8_t*)(x))[0]) ++#endif ++#ifndef AV_WL48 ++# define AV_WL48(p, darg) do { \ ++ uint64_t d = (darg); \ ++ ((uint8_t*)(p))[0] = (d); \ ++ ((uint8_t*)(p))[1] = (d)>>8; \ ++ ((uint8_t*)(p))[2] = (d)>>16; \ ++ ((uint8_t*)(p))[3] = (d)>>24; \ ++ ((uint8_t*)(p))[4] = (d)>>32; \ ++ ((uint8_t*)(p))[5] = (d)>>40; \ ++ } while(0) ++#endif ++ ++/* ++ * The AV_[RW]NA macros access naturally aligned data ++ * in a type-safe way. ++ */ ++ ++#define AV_RNA(s, p) (((const av_alias##s*)(p))->u##s) ++#define AV_WNA(s, p, v) (((av_alias##s*)(p))->u##s = (v)) ++ ++#ifndef AV_RN16A ++# define AV_RN16A(p) AV_RNA(16, p) ++#endif ++ ++#ifndef AV_RN32A ++# define AV_RN32A(p) AV_RNA(32, p) ++#endif ++ ++#ifndef AV_RN64A ++# define AV_RN64A(p) AV_RNA(64, p) ++#endif ++ ++#ifndef AV_WN16A ++# define AV_WN16A(p, v) AV_WNA(16, p, v) ++#endif ++ ++#ifndef AV_WN32A ++# define AV_WN32A(p, v) AV_WNA(32, p, v) ++#endif ++ ++#ifndef AV_WN64A ++# define AV_WN64A(p, v) AV_WNA(64, p, v) ++#endif ++ ++/* ++ * The AV_COPYxxU macros are suitable for copying data to/from unaligned ++ * memory locations. ++ */ ++ ++#define AV_COPYU(n, d, s) AV_WN##n(d, AV_RN##n(s)); ++ ++#ifndef AV_COPY16U ++# define AV_COPY16U(d, s) AV_COPYU(16, d, s) ++#endif ++ ++#ifndef AV_COPY32U ++# define AV_COPY32U(d, s) AV_COPYU(32, d, s) ++#endif ++ ++#ifndef AV_COPY64U ++# define AV_COPY64U(d, s) AV_COPYU(64, d, s) ++#endif ++ ++#ifndef AV_COPY128U ++# define AV_COPY128U(d, s) \ ++ do { \ ++ AV_COPY64U(d, s); \ ++ AV_COPY64U((char *)(d) + 8, (const char *)(s) + 8); \ ++ } while(0) ++#endif ++ ++/* Parameters for AV_COPY*, AV_SWAP*, AV_ZERO* must be ++ * naturally aligned. They may be implemented using MMX, ++ * so emms_c() must be called before using any float code ++ * afterwards. ++ */ ++ ++#define AV_COPY(n, d, s) \ ++ (((av_alias##n*)(d))->u##n = ((const av_alias##n*)(s))->u##n) ++ ++#ifndef AV_COPY16 ++# define AV_COPY16(d, s) AV_COPY(16, d, s) ++#endif ++ ++#ifndef AV_COPY32 ++# define AV_COPY32(d, s) AV_COPY(32, d, s) ++#endif ++ ++#ifndef AV_COPY64 ++# define AV_COPY64(d, s) AV_COPY(64, d, s) ++#endif ++ ++#ifndef AV_COPY128 ++# define AV_COPY128(d, s) \ ++ do { \ ++ AV_COPY64(d, s); \ ++ AV_COPY64((char*)(d)+8, (char*)(s)+8); \ ++ } while(0) ++#endif ++ ++#define AV_SWAP(n, a, b) FFSWAP(av_alias##n, *(av_alias##n*)(a), *(av_alias##n*)(b)) ++ ++#ifndef AV_SWAP64 ++# define AV_SWAP64(a, b) AV_SWAP(64, a, b) ++#endif ++ ++#define AV_ZERO(n, d) (((av_alias##n*)(d))->u##n = 0) ++ ++#ifndef AV_ZERO16 ++# define AV_ZERO16(d) AV_ZERO(16, d) ++#endif ++ ++#ifndef AV_ZERO32 ++# define AV_ZERO32(d) AV_ZERO(32, d) ++#endif ++ ++#ifndef AV_ZERO64 ++# define AV_ZERO64(d) AV_ZERO(64, d) ++#endif ++ ++#ifndef AV_ZERO128 ++# define AV_ZERO128(d) \ ++ do { \ ++ AV_ZERO64(d); \ ++ AV_ZERO64((char*)(d)+8); \ ++ } while(0) ++#endif ++ ++#endif /* AVUTIL_INTREADWRITE_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/list.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/list.h +new file mode 100644 +index 000000000..dcdd1ac72 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/list.h +@@ -0,0 +1,169 @@ ++#ifndef LIST_H ++#define LIST_H ++ ++#ifdef __KERNEL__ ++#include ++ ++#else ++ ++/* ++ * Copied from include/linux/... ++ */ ++ ++#undef offsetof ++#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) ++ ++/** ++ * container_of - cast a member of a structure out to the containing structure ++ * @ptr: the pointer to the member. ++ * @type: the type of the container struct this is embedded in. ++ * @member: the name of the member within the struct. ++ * ++ */ ++#define container_of(ptr, type, member) ({ \ ++ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ++ (type *)( (char *)__mptr - offsetof(type,member) );}) ++ ++ ++struct list_head { ++ struct list_head *next, *prev; ++}; ++ ++ ++#define LIST_HEAD_INIT(name) { &(name), &(name) } ++ ++#define LIST_HEAD(name) \ ++ struct list_head name = LIST_HEAD_INIT(name) ++ ++static inline void INIT_LIST_HEAD(struct list_head *list) ++{ ++ list->next = list; ++ list->prev = list; ++} ++ ++ ++/** ++ * list_entry - get the struct for this entry ++ * @ptr: the &struct list_head pointer. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_entry(ptr, type, member) \ ++ container_of(ptr, type, member) ++ ++/** ++ * list_first_entry - get the first element from a list ++ * @ptr: the list head to take the element from. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Note, that list is expected to be not empty. ++ */ ++#define list_first_entry(ptr, type, member) \ ++ list_entry((ptr)->next, type, member) ++ ++/** ++ * list_first_entry_or_null - get the first element from a list ++ * @ptr: the list head to take the element from. ++ * @type: the type of the struct this is embedded in. ++ * @member: the name of the list_struct within the struct. ++ * ++ * Note that if the list is empty, it returns NULL. ++ */ ++#define list_first_entry_or_null(ptr, type, member) \ ++ (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) ++ ++ ++/** ++ * list_for_each_entry - iterate over list of given type ++ * @pos: the type * to use as a loop cursor. ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry(pos, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member)) ++ ++/** ++ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry ++ * @pos: the type * to use as a loop cursor. ++ * @n: another type * to use as temporary storage ++ * @head: the head for your list. ++ * @member: the name of the list_struct within the struct. ++ */ ++#define list_for_each_entry_safe(pos, n, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member), \ ++ n = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.next, typeof(*n), member)) ++ ++/** ++ * list_empty - tests whether a list is empty ++ * @head: the list to test. ++ */ ++static inline int list_empty(const struct list_head *head) ++{ ++ return head->next == head; ++} ++ ++/* ++ * Insert a new entry between two known consecutive entries. ++ * ++ * This is only for internal list manipulation where we know ++ * the prev/next entries already! ++ */ ++static inline void __list_add(struct list_head *_new, ++ struct list_head *prev, ++ struct list_head *next) ++{ ++ next->prev = _new; ++ _new->next = next; ++ _new->prev = prev; ++ prev->next = _new; ++} ++ ++/** ++ * list_add_tail - add a new entry ++ * @new: new entry to be added ++ * @head: list head to add it before ++ * ++ * Insert a new entry before the specified head. ++ * This is useful for implementing queues. ++ */ ++static inline void list_add_tail(struct list_head *_new, struct list_head *head) ++{ ++ __list_add(_new, head->prev, head); ++} ++ ++/* ++ * Delete a list entry by making the prev/next entries ++ * point to each other. ++ * ++ * This is only for internal list manipulation where we know ++ * the prev/next entries already! ++ */ ++static inline void __list_del(struct list_head *prev, struct list_head *next) ++{ ++ next->prev = prev; ++ prev->next = next; ++} ++ ++#define LIST_POISON1 ((void *) 0x00100100) ++#define LIST_POISON2 ((void *) 0x00200200) ++/** ++ * list_del - deletes entry from list. ++ * @entry: the element to delete from the list. ++ * Note: list_empty() on entry does not return true after this, the entry is ++ * in an undefined state. ++ */ ++static inline void list_del(struct list_head *entry) ++{ ++ __list_del(entry->prev, entry->next); ++ entry->next = (struct list_head*)LIST_POISON1; ++ entry->prev = (struct list_head*)LIST_POISON2; ++} ++ ++#endif ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/log.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/log.h +new file mode 100644 +index 000000000..2f0345dcc +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/log.h +@@ -0,0 +1,341 @@ ++#ifndef AVUTIL_LOG_H ++#define AVUTIL_LOG_H ++ ++#include ++//#include "attributes.h" ++//#include "version.h" ++ ++typedef enum { ++ AV_CLASS_CATEGORY_NA = 0, ++ AV_CLASS_CATEGORY_INPUT, ++ AV_CLASS_CATEGORY_OUTPUT, ++ AV_CLASS_CATEGORY_MUXER, ++ AV_CLASS_CATEGORY_DEMUXER, ++ AV_CLASS_CATEGORY_ENCODER, ++ AV_CLASS_CATEGORY_DECODER, ++ AV_CLASS_CATEGORY_FILTER, ++ AV_CLASS_CATEGORY_BITSTREAM_FILTER, ++ AV_CLASS_CATEGORY_SWSCALER, ++ AV_CLASS_CATEGORY_SWRESAMPLER, ++ AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT = 40, ++ AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, ++ AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT, ++ AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, ++ AV_CLASS_CATEGORY_DEVICE_OUTPUT, ++ AV_CLASS_CATEGORY_DEVICE_INPUT, ++ AV_CLASS_CATEGORY_NB ///< not part of ABI/API ++}AVClassCategory; ++ ++#define AV_IS_INPUT_DEVICE(category) \ ++ (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \ ++ ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \ ++ ((category) == AV_CLASS_CATEGORY_DEVICE_INPUT)) ++ ++#define AV_IS_OUTPUT_DEVICE(category) \ ++ (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) || \ ++ ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) || \ ++ ((category) == AV_CLASS_CATEGORY_DEVICE_OUTPUT)) ++ ++struct AVOptionRanges; ++ ++/** ++ * Describe the class of an AVClass context structure. That is an ++ * arbitrary struct of which the first field is a pointer to an ++ * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.). ++ */ ++typedef struct AVClass { ++ /** ++ * The name of the class; usually it is the same name as the ++ * context structure type to which the AVClass is associated. ++ */ ++ const char* class_name; ++ ++ /** ++ * A pointer to a function which returns the name of a context ++ * instance ctx associated with the class. ++ */ ++ const char* (*item_name)(void* ctx); ++ ++ /** ++ * a pointer to the first option specified in the class if any or NULL ++ * ++ * @see av_set_default_options() ++ */ ++ const struct AVOption *option; ++ ++ /** ++ * LIBAVUTIL_VERSION with which this structure was created. ++ * This is used to allow fields to be added without requiring major ++ * version bumps everywhere. ++ */ ++ ++ int version; ++ ++ /** ++ * Offset in the structure where log_level_offset is stored. ++ * 0 means there is no such variable ++ */ ++ int log_level_offset_offset; ++ ++ /** ++ * Offset in the structure where a pointer to the parent context for ++ * logging is stored. For example a decoder could pass its AVCodecContext ++ * to eval as such a parent context, which an av_log() implementation ++ * could then leverage to display the parent context. ++ * The offset can be NULL. ++ */ ++ int parent_log_context_offset; ++ ++ /** ++ * Return next AVOptions-enabled child or NULL ++ */ ++ void* (*child_next)(void *obj, void *prev); ++ ++ /** ++ * Return an AVClass corresponding to the next potential ++ * AVOptions-enabled child. ++ * ++ * The difference between child_next and this is that ++ * child_next iterates over _already existing_ objects, while ++ * child_class_next iterates over _all possible_ children. ++ */ ++ const struct AVClass* (*child_class_next)(const struct AVClass *prev); ++ ++ /** ++ * Category used for visualization (like color) ++ * This is only set if the category is equal for all objects using this class. ++ * available since version (51 << 16 | 56 << 8 | 100) ++ */ ++ AVClassCategory category; ++ ++ /** ++ * Callback to return the category. ++ * available since version (51 << 16 | 59 << 8 | 100) ++ */ ++ AVClassCategory (*get_category)(void* ctx); ++ ++ /** ++ * Callback to return the supported/allowed ranges. ++ * available since version (52.12) ++ */ ++ int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags); ++} AVClass; ++ ++/** ++ * @addtogroup lavu_log ++ * ++ * @{ ++ * ++ * @defgroup lavu_log_constants Logging Constants ++ * ++ * @{ ++ */ ++ ++/** ++ * Print no output. ++ */ ++#define AV_LOG_QUIET -8 ++ ++/** ++ * Something went really wrong and we will crash now. ++ */ ++#define AV_LOG_PANIC 0 ++ ++/** ++ * Something went wrong and recovery is not possible. ++ * For example, no header was found for a format which depends ++ * on headers or an illegal combination of parameters is used. ++ */ ++#define AV_LOG_FATAL 8 ++ ++/** ++ * Something went wrong and cannot losslessly be recovered. ++ * However, not all future data is affected. ++ */ ++#define AV_LOG_ERROR 16 ++ ++/** ++ * Something somehow does not look correct. This may or may not ++ * lead to problems. An example would be the use of '-vstrict -2'. ++ */ ++#define AV_LOG_WARNING 24 ++ ++/** ++ * Standard information. ++ */ ++#define AV_LOG_INFO 32 ++ ++/** ++ * Detailed information. ++ */ ++#define AV_LOG_VERBOSE 40 ++ ++/** ++ * Stuff which is only useful for libav* developers. ++ */ ++#define AV_LOG_DEBUG 48 ++ ++/** ++ * Extremely verbose debugging, useful for libav* development. ++ */ ++#define AV_LOG_TRACE 56 ++ ++#define AV_LOG_MAX_OFFSET (AV_LOG_TRACE - AV_LOG_QUIET) ++ ++/** ++ * @} ++ */ ++ ++/** ++ * Sets additional colors for extended debugging sessions. ++ * @code ++ av_log(ctx, AV_LOG_DEBUG|AV_LOG_C(134), "Message in purple\n"); ++ @endcode ++ * Requires 256color terminal support. Uses outside debugging is not ++ * recommended. ++ */ ++#define AV_LOG_C(x) ((x) << 8) ++ ++/** ++ * Send the specified message to the log if the level is less than or equal ++ * to the current av_log_level. By default, all logging messages are sent to ++ * stderr. This behavior can be altered by setting a different logging callback ++ * function. ++ * @see av_log_set_callback ++ * ++ * @param avcl A pointer to an arbitrary struct of which the first field is a ++ * pointer to an AVClass struct or NULL if general log. ++ * @param level The importance level of the message expressed using a @ref ++ * lavu_log_constants "Logging Constant". ++ * @param fmt The format string (printf-compatible) that specifies how ++ * subsequent arguments are converted to output. ++ */ ++void av_log(void *avcl, int level, const char *fmt, ...); ++ ++ ++/** ++ * Send the specified message to the log if the level is less than or equal ++ * to the current av_log_level. By default, all logging messages are sent to ++ * stderr. This behavior can be altered by setting a different logging callback ++ * function. ++ * @see av_log_set_callback ++ * ++ * @param avcl A pointer to an arbitrary struct of which the first field is a ++ * pointer to an AVClass struct. ++ * @param level The importance level of the message expressed using a @ref ++ * lavu_log_constants "Logging Constant". ++ * @param fmt The format string (printf-compatible) that specifies how ++ * subsequent arguments are converted to output. ++ * @param vl The arguments referenced by the format string. ++ */ ++void av_vlog(void *avcl, int level, const char *fmt, va_list vl); ++ ++/** ++ * Get the current log level ++ * ++ * @see lavu_log_constants ++ * ++ * @return Current log level ++ */ ++int av_log_get_level(void); ++ ++/** ++ * Set the log level ++ * ++ * @see lavu_log_constants ++ * ++ * @param level Logging level ++ */ ++void av_log_set_level(int level); ++ ++/** ++ * Set the logging callback ++ * ++ * @note The callback must be thread safe, even if the application does not use ++ * threads itself as some codecs are multithreaded. ++ * ++ * @see av_log_default_callback ++ * ++ * @param callback A logging function with a compatible signature. ++ */ ++void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)); ++ ++/** ++ * Default logging callback ++ * ++ * It prints the message to stderr, optionally colorizing it. ++ * ++ * @param avcl A pointer to an arbitrary struct of which the first field is a ++ * pointer to an AVClass struct. ++ * @param level The importance level of the message expressed using a @ref ++ * lavu_log_constants "Logging Constant". ++ * @param fmt The format string (printf-compatible) that specifies how ++ * subsequent arguments are converted to output. ++ * @param vl The arguments referenced by the format string. ++ */ ++void av_log_default_callback(void *avcl, int level, const char *fmt, ++ va_list vl); ++ ++/** ++ * Return the context name ++ * ++ * @param ctx The AVClass context ++ * ++ * @return The AVClass class_name ++ */ ++const char* av_default_item_name(void* ctx); ++AVClassCategory av_default_get_category(void *ptr); ++ ++/** ++ * Format a line of log the same way as the default callback. ++ * @param line buffer to receive the formatted line ++ * @param line_size size of the buffer ++ * @param print_prefix used to store whether the prefix must be printed; ++ * must point to a persistent integer initially set to 1 ++ */ ++void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, ++ char *line, int line_size, int *print_prefix); ++ ++/** ++ * Format a line of log the same way as the default callback. ++ * @param line buffer to receive the formatted line; ++ * may be NULL if line_size is 0 ++ * @param line_size size of the buffer; at most line_size-1 characters will ++ * be written to the buffer, plus one null terminator ++ * @param print_prefix used to store whether the prefix must be printed; ++ * must point to a persistent integer initially set to 1 ++ * @return Returns a negative value if an error occurred, otherwise returns ++ * the number of characters that would have been written for a ++ * sufficiently large buffer, not including the terminating null ++ * character. If the return value is not less than line_size, it means ++ * that the log message was truncated to fit the buffer. ++ */ ++int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl, ++ char *line, int line_size, int *print_prefix); ++ ++/** ++ * Skip repeated messages, this requires the user app to use av_log() instead of ++ * (f)printf as the 2 would otherwise interfere and lead to ++ * "Last message repeated x times" messages below (f)printf messages with some ++ * bad luck. ++ * Also to receive the last, "last repeated" line if any, the user app must ++ * call av_log(NULL, AV_LOG_QUIET, "%s", ""); at the end ++ */ ++#define AV_LOG_SKIP_REPEATED 1 ++ ++/** ++ * Include the log severity in messages originating from codecs. ++ * ++ * Results in messages such as: ++ * [rawvideo @ 0xDEADBEEF] [error] encode did not produce valid pts ++ */ ++#define AV_LOG_PRINT_LEVEL 2 ++ ++void av_log_set_flags(int arg); ++int av_log_get_flags(void); ++ ++/** ++ * @} ++ */ ++ ++#endif /* AVUTIL_LOG_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mathops.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mathops.h +new file mode 100644 +index 000000000..d8266b305 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mathops.h +@@ -0,0 +1,63 @@ ++#ifndef __MATHOPS_H__ ++#define __MATHOPS_H__ ++ ++#ifdef __KERNEL__ ++#include ++#endif ++ ++ ++#define MAX_NEG_CROP 1024 ++extern const uint32_t ff_inverse[257]; ++extern const uint8_t ff_sqrt_tab[256]; ++extern const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP]; ++extern const uint8_t ff_zigzag_direct[64]; ++extern const uint8_t ff_zigzag_scan[16+1]; ++ ++#ifndef NEG_SSR32 ++# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) ++#endif ++ ++#ifndef NEG_USR32 ++# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) ++#endif ++ ++ ++#ifndef ff_ctz ++#define ff_ctz(v) __builtin_ctz(v) ++#endif ++#ifndef ff_ctzll ++#define ff_ctzll(v) __builtin_ctzll(v) ++#endif ++#ifndef ff_clz ++#define ff_clz(v) __builtin_clz(v) ++#endif ++ ++#ifndef ff_log2 ++#define ff_log2(x) (31 - __builtin_clz((x)|1)) ++#endif ++ ++#ifndef ff_log2_16bit ++#define ff_log2_16bit ff_log2 ++#endif ++ ++#define av_log2 ff_log2 ++ ++ ++#ifndef sign_extend ++static inline int sign_extend(int val, unsigned bits) ++{ ++ unsigned shift = 8 * sizeof(int) - bits; ++ union { unsigned u; int s; } v = { (unsigned) val << shift }; ++ return v.s >> shift; ++} ++#endif ++ ++#ifndef zero_extend ++static inline unsigned zero_extend(unsigned val, unsigned bits) ++{ ++ return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits); ++} ++#endif ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mem.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mem.h +new file mode 100644 +index 000000000..7b36d4b44 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mem.h +@@ -0,0 +1,71 @@ ++#ifndef AVUTIL_MEM_H ++#define AVUTIL_MEM_H ++ ++#ifdef __KERNEL__ ++#else ++#include ++#include ++#endif ++ ++//#include "attributes.h" ++#include "error.h" ++ ++void *av_malloc(size_t size) ;//av_malloc_attrib av_alloc_size(1); ++ ++void *av_mallocz(size_t size); ++ ++void *av_malloc_array(size_t nmemb, size_t size); ++ ++void *av_mallocz_array(size_t nmemb, size_t size); ++ ++void *av_calloc(size_t nmemb, size_t size); ++ ++void *av_realloc(void *ptr, size_t size); ++ ++int av_reallocp(void *ptr, size_t size); ++ ++void *av_realloc_f(void *ptr, size_t nelem, size_t elsize); ++ ++void *av_realloc_array(void *ptr, size_t nmemb, size_t size); ++ ++int av_reallocp_array(void *ptr, size_t nmemb, size_t size); ++ ++void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); ++ ++void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size); ++ ++void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size); ++ ++void av_free(void *ptr); ++ ++void av_freep(void *ptr); ++ ++char *av_strdup(const char *s); ++ ++char *av_strndup(const char *s, size_t len); ++ ++void *av_memdup(const void *p, size_t size); ++ ++void av_memcpy_backptr(uint8_t *dst, int back, int cnt); ++ ++/** ++ * Multiply two `size_t` values checking for overflow. ++ * ++ * @param[in] a,b Operands of multiplication ++ * @param[out] r Pointer to the result of the operation ++ * @return 0 on success, AVERROR(EINVAL) on overflow ++ */ ++static inline int av_size_mult(size_t a, size_t b, size_t *r) ++{ ++ size_t t = a * b; ++ /* Hack inspired from glibc: don't try the division if nelem and elsize ++ * are both less than sqrt(SIZE_MAX). */ ++ if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b) ++ return AVERROR(EINVAL); ++ *r = t; ++ return 0; ++} ++ ++void av_max_alloc(size_t max); ++ ++#endif /* AVUTIL_MEM_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mpegutils.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mpegutils.h +new file mode 100644 +index 000000000..6c3d6f764 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/mpegutils.h +@@ -0,0 +1,27 @@ ++#ifndef __MPEGUTILS_H__ ++#define __MPEGUTILS_H__ ++ ++ ++/** ++ * Return value for header parsers if frame is not coded. ++ * */ ++#define FRAME_SKIPPED 100 ++ ++/* picture type */ ++#define PICT_TOP_FIELD 1 ++#define PICT_BOTTOM_FIELD 2 ++#define PICT_FRAME 3 ++ ++/** ++ * Value of Picture.reference when Picture is not a reference picture, but ++ * is held for delayed output. ++ */ ++#define DELAYED_PIC_REF 4 ++ ++#define MAX_MB_BYTES (30 * 16 * 16 * 3 / 8 + 120) ++#define MAX_FCODE 7 ++ ++ ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/put_bits.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/put_bits.h +new file mode 100644 +index 000000000..32b96432c +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/put_bits.h +@@ -0,0 +1,337 @@ ++#ifndef AVCODEC_PUT_BITS_H ++#define AVCODEC_PUT_BITS_H ++ ++#include "intreadwrite.h" ++#include "avassert.h" ++ ++typedef struct PutBitContext { ++ uint32_t bit_buf; ++ int bit_left; ++ uint8_t *buf, *buf_ptr, *buf_end; ++ int size_in_bits; ++} PutBitContext; ++ ++/** ++ * Initialize the PutBitContext s. ++ * ++ * @param buffer the buffer where to put bits ++ * @param buffer_size the size in bytes of buffer ++ */ ++static inline void init_put_bits(PutBitContext *s, uint8_t *buffer, ++ int buffer_size) ++{ ++ if (buffer_size < 0) { ++ buffer_size = 0; ++ buffer = NULL; ++ } ++ ++ s->size_in_bits = 8 * buffer_size; ++ s->buf = buffer; ++ s->buf_end = s->buf + buffer_size; ++ s->buf_ptr = s->buf; ++ s->bit_left = 32; ++ s->bit_buf = 0; ++} ++ ++/** ++ * Rebase the bit writer onto a reallocated buffer. ++ * ++ * @param buffer the buffer where to put bits ++ * @param buffer_size the size in bytes of buffer, ++ * must be larger than the previous size ++ */ ++static inline void rebase_put_bits(PutBitContext *s, uint8_t *buffer, ++ int buffer_size) ++{ ++ av_assert0(8*buffer_size > s->size_in_bits); ++ ++ s->buf_end = buffer + buffer_size; ++ s->buf_ptr = buffer + (s->buf_ptr - s->buf); ++ s->buf = buffer; ++ s->size_in_bits = 8 * buffer_size; ++} ++ ++/** ++ * @return the total number of bits written to the bitstream. ++ */ ++static inline int put_bits_count(PutBitContext *s) ++{ ++ return (s->buf_ptr - s->buf) * 8 + 32 - s->bit_left; ++} ++ ++/** ++ * @return the number of bits available in the bitstream. ++ */ ++static inline int put_bits_left(PutBitContext* s) ++{ ++ return (s->buf_end - s->buf_ptr) * 8 - 32 + s->bit_left; ++} ++ ++/** ++ * Pad the end of the output stream with zeros. ++ */ ++static inline void flush_put_bits(PutBitContext *s) ++{ ++#ifndef BITSTREAM_WRITER_LE ++ if (s->bit_left < 32) ++ s->bit_buf <<= s->bit_left; ++#endif ++ while (s->bit_left < 32) { ++ av_assert0(s->buf_ptr < s->buf_end); ++#ifdef BITSTREAM_WRITER_LE ++ *s->buf_ptr++ = s->bit_buf; ++ s->bit_buf >>= 8; ++#else ++ *s->buf_ptr++ = s->bit_buf >> 24; ++ s->bit_buf <<= 8; ++#endif ++ s->bit_left += 8; ++ } ++ s->bit_left = 32; ++ s->bit_buf = 0; ++} ++ ++static inline void flush_put_bits_le(PutBitContext *s) ++{ ++ while (s->bit_left < 32) { ++ av_assert0(s->buf_ptr < s->buf_end); ++ *s->buf_ptr++ = s->bit_buf; ++ s->bit_buf >>= 8; ++ s->bit_left += 8; ++ } ++ s->bit_left = 32; ++ s->bit_buf = 0; ++} ++ ++#ifdef BITSTREAM_WRITER_LE ++#define avpriv_align_put_bits align_put_bits_unsupported_here ++#define avpriv_put_string ff_put_string_unsupported_here ++#define avpriv_copy_bits avpriv_copy_bits_unsupported_here ++#else ++/** ++ * Pad the bitstream with zeros up to the next byte boundary. ++ */ ++void avpriv_align_put_bits(PutBitContext *s); ++ ++/** ++ * Put the string string in the bitstream. ++ * ++ * @param terminate_string 0-terminates the written string if value is 1 ++ */ ++void avpriv_put_string(PutBitContext *pb, const char *string, ++ int terminate_string); ++ ++/** ++ * Copy the content of src to the bitstream. ++ * ++ * @param length the number of bits of src to copy ++ */ ++void avpriv_copy_bits(PutBitContext *pb, const uint8_t *src, int length); ++#endif ++ ++/** ++ * Write up to 31 bits into a bitstream. ++ * Use put_bits32 to write 32 bits. ++ */ ++static inline void put_bits(PutBitContext *s, int n, unsigned int value) ++{ ++ unsigned int bit_buf; ++ int bit_left; ++ ++ av_assert2(n <= 31 && value < (1U << n)); ++ ++ bit_buf = s->bit_buf; ++ bit_left = s->bit_left; ++ ++ /* XXX: optimize */ ++#ifdef BITSTREAM_WRITER_LE ++ bit_buf |= value << (32 - bit_left); ++ if (n >= bit_left) { ++ if (3 < s->buf_end - s->buf_ptr) { ++ AV_WL32(s->buf_ptr, bit_buf); ++ s->buf_ptr += 4; ++ } else { ++ av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); ++ av_assert2(0); ++ } ++ bit_buf = value >> bit_left; ++ bit_left += 32; ++ } ++ bit_left -= n; ++#else ++ if (n < bit_left) { ++ bit_buf = (bit_buf << n) | value; ++ bit_left -= n; ++ } else { ++ bit_buf <<= bit_left; ++ bit_buf |= value >> (n - bit_left); ++ if (3 < s->buf_end - s->buf_ptr) { ++ AV_WB32(s->buf_ptr, bit_buf); ++ s->buf_ptr += 4; ++ } else { ++ av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); ++ av_assert2(0); ++ } ++ bit_left += 32 - n; ++ bit_buf = value; ++ } ++#endif ++ ++ s->bit_buf = bit_buf; ++ s->bit_left = bit_left; ++} ++ ++static inline void put_bits_le(PutBitContext *s, int n, unsigned int value) ++{ ++ unsigned int bit_buf; ++ int bit_left; ++ ++ av_assert2(n <= 31 && value < (1U << n)); ++ ++ bit_buf = s->bit_buf; ++ bit_left = s->bit_left; ++ ++ bit_buf |= value << (32 - bit_left); ++ if (n >= bit_left) { ++ if (3 < s->buf_end - s->buf_ptr) { ++ AV_WL32(s->buf_ptr, bit_buf); ++ s->buf_ptr += 4; ++ } else { ++ av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); ++ av_assert2(0); ++ } ++ bit_buf = value >> bit_left; ++ bit_left += 32; ++ } ++ bit_left -= n; ++ ++ s->bit_buf = bit_buf; ++ s->bit_left = bit_left; ++} ++ ++static inline void put_sbits(PutBitContext *pb, int n, int32_t value) ++{ ++ av_assert2(n >= 0 && n <= 31); ++ ++ put_bits(pb, n, av_mod_uintp2(value, n)); ++} ++ ++/** ++ * Write exactly 32 bits into a bitstream. ++ */ ++static void __maybe_unused put_bits32(PutBitContext *s, uint32_t value) ++{ ++ unsigned int bit_buf; ++ int bit_left; ++ ++ bit_buf = s->bit_buf; ++ bit_left = s->bit_left; ++ ++#ifdef BITSTREAM_WRITER_LE ++ bit_buf |= value << (32 - bit_left); ++ if (3 < s->buf_end - s->buf_ptr) { ++ AV_WL32(s->buf_ptr, bit_buf); ++ s->buf_ptr += 4; ++ } else { ++ av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); ++ av_assert2(0); ++ } ++ bit_buf = (uint64_t)value >> bit_left; ++#else ++ bit_buf = (uint64_t)bit_buf << bit_left; ++ bit_buf |= value >> (32 - bit_left); ++ if (3 < s->buf_end - s->buf_ptr) { ++ AV_WB32(s->buf_ptr, bit_buf); ++ s->buf_ptr += 4; ++ } else { ++ av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); ++ av_assert2(0); ++ } ++ bit_buf = value; ++#endif ++ ++ s->bit_buf = bit_buf; ++ s->bit_left = bit_left; ++} ++ ++/** ++ * Write up to 64 bits into a bitstream. ++ */ ++static inline void put_bits64(PutBitContext *s, int n, uint64_t value) ++{ ++ av_assert2((n == 64) || (n < 64 && value < (UINT64_C(1) << n))); ++ ++ if (n < 32) ++ put_bits(s, n, value); ++ else if (n == 32) ++ put_bits32(s, value); ++ else if (n < 64) { ++ uint32_t lo = value & 0xffffffff; ++ uint32_t hi = value >> 32; ++#ifdef BITSTREAM_WRITER_LE ++ put_bits32(s, lo); ++ put_bits(s, n - 32, hi); ++#else ++ put_bits(s, n - 32, hi); ++ put_bits32(s, lo); ++#endif ++ } else { ++ uint32_t lo = value & 0xffffffff; ++ uint32_t hi = value >> 32; ++#ifdef BITSTREAM_WRITER_LE ++ put_bits32(s, lo); ++ put_bits32(s, hi); ++#else ++ put_bits32(s, hi); ++ put_bits32(s, lo); ++#endif ++ ++ } ++} ++ ++/** ++ * Return the pointer to the byte where the bitstream writer will put ++ * the next bit. ++ */ ++static inline uint8_t *put_bits_ptr(PutBitContext *s) ++{ ++ return s->buf_ptr; ++} ++ ++/** ++ * Skip the given number of bytes. ++ * PutBitContext must be flushed & aligned to a byte boundary before calling this. ++ */ ++static inline void skip_put_bytes(PutBitContext *s, int n) ++{ ++ av_assert2((put_bits_count(s) & 7) == 0); ++ av_assert2(s->bit_left == 32); ++ av_assert0(n <= s->buf_end - s->buf_ptr); ++ s->buf_ptr += n; ++} ++ ++/** ++ * Skip the given number of bits. ++ * Must only be used if the actual values in the bitstream do not matter. ++ * If n is 0 the behavior is undefined. ++ */ ++static inline void skip_put_bits(PutBitContext *s, int n) ++{ ++ s->bit_left -= n; ++ s->buf_ptr -= 4 * (s->bit_left >> 5); ++ s->bit_left &= 31; ++} ++ ++/** ++ * Change the end of the buffer. ++ * ++ * @param size the new size in bytes of the buffer where to put bits ++ */ ++static inline void set_put_bits_buffer_size(PutBitContext *s, int size) ++{ ++ av_assert0(size <= INT_MAX/8 - 32); ++ s->buf_end = s->buf + size; ++ s->size_in_bits = 8*size; ++} ++ ++#endif /* AVCODEC_PUT_BITS_H */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/vpu_ops.h b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/vpu_ops.h +new file mode 100644 +index 000000000..e983558b4 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/include/vpu_ops.h +@@ -0,0 +1,45 @@ ++#ifndef __VPU_OPS_H__ ++#define __VPU_OPS_H__ ++ ++#include "api/jzm_vpu.h" ++ ++struct vpu_ops; ++struct vpu_ctx; ++ ++typedef struct vpu_ctx { ++ int fd; /*vpu handle*/ ++ unsigned int vpu_base; ++ struct vpu_ops *ops; ++ ++ unsigned int desc_va; ++ unsigned int desc_pa; ++ ++ unsigned int sch_stat; ++ unsigned int sde_stat; ++ unsigned int error; ++ ++ void *priv; ++} vpu_ctx_t; ++ ++struct vpu_ops { ++ int (*start)(void *priv); ++ int (*wait)(void *priv); ++ int (*end)(void *priv); ++}; ++ ++#define WAIT_COMPLETE 0 ++#define CMD_VPU_RESET 105 ++ ++ ++int vpu_ctx_init(struct vpu_ctx *ctx); ++void vpu_ctx_uninit(struct vpu_ctx *ctx); ++ ++int vpu_hw_start(struct vpu_ctx *ctx); ++ ++int vpu_hw_wait(struct vpu_ctx *ctx); ++ ++int vpu_hw_end(struct vpu_ctx *ctx); ++ ++int vpu_ctx_set_ops(struct vpu_ctx *ctx, void *priv, struct vpu_ops *ops); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/Makefile b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/Makefile +new file mode 100644 +index 000000000..370727f89 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/Makefile +@@ -0,0 +1,25 @@ ++ccflags-y += -I$(srctree)/drivers/media/platform/ingenic-vcodec/felix/libh264/ ++ccflags-y += -I$(srctree)/drivers/media/platform/ingenic-vcodec/felix/libh264/include/ ++ ++ ++libh264-y += \ ++ log.o \ ++ mem.o \ ++ h264_picture.o \ ++ golomb.o \ ++ h264data.o \ ++ h264_refs.o \ ++ mathtables.o \ ++ h2645_parse.o \ ++ h264_parse.o \ ++ h264_direct.o \ ++ h264_ps.o \ ++ h264_sei.o \ ++ buffer.o \ ++ vpu_ops.o \ ++ h264_slice.o \ ++ h264dec.o ++ ++obj-y += libh264.o ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/buffer.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/buffer.c +new file mode 100644 +index 000000000..f07110efc +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/buffer.c +@@ -0,0 +1,194 @@ ++#ifdef __KERNEL__ ++#include ++ ++#else ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++#include "error.h" ++#include "mem.h" ++#include "devmem.h" ++#include "buffer.h" ++ ++#define DEBUG_MM_ALLOC 1 ++//#define DEBUG_MM_ALLOC_PRINT ++ ++static int devmem_alloc(devmem_ctx_t *ctx, devmem_info_t *di) ++{ ++ int ret = 0; ++ dma_addr_t dma_addr; ++ di->coherent = 0; ++ ++ if(di->coherent) { ++ di->kva = (unsigned long)dma_alloc_coherent(ctx->dev, di->length, &dma_addr, GFP_KERNEL); ++ } else { ++ di->kva = (unsigned long)dma_alloc_noncoherent(ctx->dev, di->length, &dma_addr, DMA_BIDIRECTIONAL, GFP_KERNEL); ++ } ++ ++ if(!di->kva) ++ return -ENOMEM; ++ ++ di->paddr = dma_addr; ++ di->userptr = di->kva; /* kernel mode, userptr = kernel address */ ++ return ret; ++} ++ ++static void devmem_free(devmem_ctx_t *ctx, devmem_info_t *di) ++{ ++ if(di->coherent) { ++ dma_free_coherent(ctx->dev, di->length, (void *)di->kva, (dma_addr_t)di->paddr); ++ } else { ++ dma_free_noncoherent(ctx->dev, di->length, (void *)di->kva, (dma_addr_t)di->paddr, DMA_BIDIRECTIONAL); ++ } ++} ++ ++static void devmem_sync(devmem_ctx_t *ctx, devmem_info_t *di) ++{ ++ if(di->coherent) ++ return; ++ ++ dma_sync_single_for_device(ctx->dev, (dma_addr_t)(di->paddr), di->length, di->sync_dir); ++ ++} ++ ++#ifdef DEBUG_MM_ALLOC ++struct debug_mm_alloc { ++ unsigned long alloc_size[128]; ++ unsigned long index; ++ ++ unsigned long long total_alloc_size; ++ unsigned long long total_alloc_cnt; ++ unsigned long long total_free_size; ++ unsigned long long total_free_cnt; ++} dbg_alloc; ++#endif ++ ++int devmem_ctx_init(devmem_ctx_t *ctx, devmem_ops_t *ops) ++{ ++ ++#ifdef DEBUG_MM_ALLOC ++ memset(&dbg_alloc, 0, sizeof(struct debug_mm_alloc)); ++#endif ++ ++ return 0; ++} ++ ++void devmem_ctx_uninit(devmem_ctx_t *ctx) ++{ ++ ++} ++ ++ ++/** ++ * @brief 使用已ç»åˆ†é…好的内存,创建AVBuffer结构体. ++ * caller: å¿…é¡»è¦ä¿è¯å†…存有效. ++ * ++ * @param va va æ˜¯è™šæ‹Ÿåœ°å€ ++ * @param pa pa 是对应的物ç†åœ°å€ï¼Œç»™åˆ°dma使用. ++ * @param size ++ * @param buf 输出buf. ++ * ++ * @return ++ */ ++ ++AVBuffer *av_buffer_create(char *va, unsigned int pa, unsigned int size) ++{ ++ AVBuffer *buf = av_malloc(sizeof(AVBuffer)); ++ ++ if(!buf) ++ return NULL; ++ ++ buf->buffer = va; ++ buf->buffer_pa = pa; ++ buf->size = size; ++ return buf; ++} ++ ++void av_buffer_del(AVBuffer *buf) ++{ ++ if(buf) ++ av_free(buf); ++} ++ ++AVBuffer *av_buffer_alloc(devmem_ctx_t *ctx, unsigned int size) ++{ ++ AVBuffer *buf = av_mallocz(sizeof(AVBuffer)); ++ int ret; ++ ++ if(!buf) { ++ return NULL; ++ } ++ ++ buf->di.length = size; ++ ++ ret = devmem_alloc(ctx, &buf->di); ++ if(ret < 0) { ++ goto err_alloc; ++ } ++ ++ buf->buffer = buf->di.userptr; ++ buf->buffer_pa = buf->di.paddr; ++ buf->size = size; ++ ++#ifdef DEBUG_MM_ALLOC ++ dbg_alloc.total_alloc_size += buf->size; ++ dbg_alloc.total_alloc_cnt ++; ++#ifdef DEBUG_MM_ALLOC_PRINT ++ printk("total_alloc_cnt: %llu, alloc_size: %d, total_alloc_size: %llu, total_free_size:%llu, total_free_cnt:%llu\n", ++ dbg_alloc.total_alloc_cnt, size, dbg_alloc.total_alloc_size, dbg_alloc.total_free_size, dbg_alloc.total_free_cnt); ++#endif ++#endif ++ ++ ++ return buf; ++err_alloc: ++#ifdef DEBUG_MM_ALLOC ++ printk("total_alloc_cnt: %llu, alloc_size: %d, total_alloc_size: %llu, total_free_size:%llu, total_free_cnt:%llu\n", ++ dbg_alloc.total_alloc_cnt, size, dbg_alloc.total_alloc_size, dbg_alloc.total_free_size, dbg_alloc.total_free_cnt); ++#endif ++ av_freep(buf); ++ return NULL; ++} ++ ++ ++ ++void av_buffer_sync(devmem_ctx_t *ctx, AVBuffer *buf, int dir) ++{ ++ buf->di.sync_dir = dir; ++ ++ devmem_sync(ctx, &buf->di); ++} ++ ++ ++void av_buffer_free(devmem_ctx_t *ctx, AVBuffer *buf) ++{ ++ if(!buf) ++ return; ++ ++ if(buf->buffer) { ++#ifdef DEBUG_MM_ALLOC ++ dbg_alloc.total_free_size += buf->size; ++ dbg_alloc.total_free_cnt ++; ++#endif ++ devmem_free(ctx, &buf->di); ++ buf->buffer = NULL; ++ } ++ ++ ++ av_free(buf); ++} ++ ++void av_buffer_dump(void) ++{ ++#ifdef DEBUG_MM_ALLOC ++ printk("total_alloc_cnt: %llu, total_alloc_size: %llu, total_free_size:%llu, total_free_cnt:%llu\n", ++ dbg_alloc.total_alloc_cnt, dbg_alloc.total_alloc_size, dbg_alloc.total_free_size, dbg_alloc.total_free_cnt); ++#endif ++ ++} ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/golomb.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/golomb.c +new file mode 100644 +index 000000000..0f4af0e7d +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/golomb.c +@@ -0,0 +1,145 @@ ++#include "common.h" ++ ++const uint8_t ff_golomb_vlc_len[512]={ ++19,17,15,15,13,13,13,13,11,11,11,11,11,11,11,11,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, ++7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, ++5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, ++5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, ++3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, ++3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, ++3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, ++3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ++}; ++ ++const uint8_t ff_ue_golomb_vlc_code[512]={ ++32,32,32,32,32,32,32,32,31,32,32,32,32,32,32,32,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, ++ 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14, ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, ++ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ++}; ++ ++const int8_t ff_se_golomb_vlc_code[512]={ ++ 17, 17, 17, 17, 17, 17, 17, 17, 16, 17, 17, 17, 17, 17, 17, 17, 8, -8, 9, -9, 10,-10, 11,-11, 12,-12, 13,-13, 14,-14, 15,-15, ++ 4, 4, 4, 4, -4, -4, -4, -4, 5, 5, 5, 5, -5, -5, -5, -5, 6, 6, 6, 6, -6, -6, -6, -6, 7, 7, 7, 7, -7, -7, -7, -7, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ++ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++}; ++ ++ ++const uint8_t ff_ue_golomb_len[256]={ ++ 1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11, ++11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,13, ++13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, ++13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,15, ++15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,17, ++}; ++ ++const uint8_t ff_interleaved_golomb_vlc_len[256]={ ++9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, ++9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, ++3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, ++3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, ++9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, ++9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, ++3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, ++3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++}; ++ ++const uint8_t ff_interleaved_ue_golomb_vlc_code[256]={ ++ 15,16,7, 7, 17,18,8, 8, 3, 3, 3, 3, 3, 3, 3, 3, ++ 19,20,9, 9, 21,22,10,10,4, 4, 4, 4, 4, 4, 4, 4, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 23,24,11,11,25,26,12,12,5, 5, 5, 5, 5, 5, 5, 5, ++ 27,28,13,13,29,30,14,14,6, 6, 6, 6, 6, 6, 6, 6, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++}; ++ ++const int8_t ff_interleaved_se_golomb_vlc_code[256]={ ++ 8, -8, 4, 4, 9, -9, -4, -4, 2, 2, 2, 2, 2, 2, 2, 2, ++ 10,-10, 5, 5, 11,-11, -5, -5, -2, -2, -2, -2, -2, -2, -2, -2, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 12,-12, 6, 6, 13,-13, -6, -6, 3, 3, 3, 3, 3, 3, 3, 3, ++ 14,-14, 7, 7, 15,-15, -7, -7, -3, -3, -3, -3, -3, -3, -3, -3, ++ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ++ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++}; ++ ++const uint8_t ff_interleaved_dirac_golomb_vlc_code[256]={ ++0, 1, 0, 0, 2, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, ++4, 5, 2, 2, 6, 7, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++8, 9, 4, 4, 10,11,5, 5, 2, 2, 2, 2, 2, 2, 2, 2, ++12,13,6, 6, 14,15,7, 7, 3, 3, 3, 3, 3, 3, 3, 3, ++1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h2645_parse.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h2645_parse.c +new file mode 100644 +index 000000000..7cca5fe4e +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h2645_parse.c +@@ -0,0 +1,401 @@ ++#ifdef __KERNEL__ ++#include ++#else ++#include ++#endif ++ ++#include "intreadwrite.h" ++#include "mem.h" ++ ++#include "bytestream.h" ++#include "h264.h" ++#include "h2645_parse.h" ++ ++int ff_h2645_extract_rbsp(const uint8_t *src, int length, ++ H2645NAL *nal, int small_padding) ++{ ++ int i; ++ int consumed = length; ++ ++ nal->skipped_bytes = 0; ++#define STARTCODE_TEST \ ++ if (i + 2 < length && src[i + 1] == 0 && src[i + 2] < 3) { \ ++ if (src[i + 2] != 3 && src[i + 2] != 0) { \ ++ /* startcode, so we must be past the end */ \ ++ length = i; \ ++ } \ ++ break; \ ++ } ++ ++ for (i = 0; i + 1 < length; i += 2) { ++ if (src[i]) ++ continue; ++ if (i > 0 && src[i - 1] == 0) ++ i--; ++ STARTCODE_TEST; ++ } ++ consumed = i; ++ nal->data = nal->raw_data = src; ++ nal->size = nal->raw_size = consumed + 1; ++ return consumed; ++} ++ ++static const char *hevc_nal_type_name[64] = { ++ "TRAIL_N", // HEVC_NAL_TRAIL_N ++ "TRAIL_R", // HEVC_NAL_TRAIL_R ++ "TSA_N", // HEVC_NAL_TSA_N ++ "TSA_R", // HEVC_NAL_TSA_R ++ "STSA_N", // HEVC_NAL_STSA_N ++ "STSA_R", // HEVC_NAL_STSA_R ++ "RADL_N", // HEVC_NAL_RADL_N ++ "RADL_R", // HEVC_NAL_RADL_R ++ "RASL_N", // HEVC_NAL_RASL_N ++ "RASL_R", // HEVC_NAL_RASL_R ++ "RSV_VCL_N10", // HEVC_NAL_VCL_N10 ++ "RSV_VCL_R11", // HEVC_NAL_VCL_R11 ++ "RSV_VCL_N12", // HEVC_NAL_VCL_N12 ++ "RSV_VLC_R13", // HEVC_NAL_VCL_R13 ++ "RSV_VCL_N14", // HEVC_NAL_VCL_N14 ++ "RSV_VCL_R15", // HEVC_NAL_VCL_R15 ++ "BLA_W_LP", // HEVC_NAL_BLA_W_LP ++ "BLA_W_RADL", // HEVC_NAL_BLA_W_RADL ++ "BLA_N_LP", // HEVC_NAL_BLA_N_LP ++ "IDR_W_RADL", // HEVC_NAL_IDR_W_RADL ++ "IDR_N_LP", // HEVC_NAL_IDR_N_LP ++ "CRA_NUT", // HEVC_NAL_CRA_NUT ++ "IRAP_IRAP_VCL22", // HEVC_NAL_IRAP_VCL22 ++ "IRAP_IRAP_VCL23", // HEVC_NAL_IRAP_VCL23 ++ "RSV_VCL24", // HEVC_NAL_RSV_VCL24 ++ "RSV_VCL25", // HEVC_NAL_RSV_VCL25 ++ "RSV_VCL26", // HEVC_NAL_RSV_VCL26 ++ "RSV_VCL27", // HEVC_NAL_RSV_VCL27 ++ "RSV_VCL28", // HEVC_NAL_RSV_VCL28 ++ "RSV_VCL29", // HEVC_NAL_RSV_VCL29 ++ "RSV_VCL30", // HEVC_NAL_RSV_VCL30 ++ "RSV_VCL31", // HEVC_NAL_RSV_VCL31 ++ "VPS", // HEVC_NAL_VPS ++ "SPS", // HEVC_NAL_SPS ++ "PPS", // HEVC_NAL_PPS ++ "AUD", // HEVC_NAL_AUD ++ "EOS_NUT", // HEVC_NAL_EOS_NUT ++ "EOB_NUT", // HEVC_NAL_EOB_NUT ++ "FD_NUT", // HEVC_NAL_FD_NUT ++ "SEI_PREFIX", // HEVC_NAL_SEI_PREFIX ++ "SEI_SUFFIX", // HEVC_NAL_SEI_SUFFIX ++ "RSV_NVCL41", // HEVC_NAL_RSV_NVCL41 ++ "RSV_NVCL42", // HEVC_NAL_RSV_NVCL42 ++ "RSV_NVCL43", // HEVC_NAL_RSV_NVCL43 ++ "RSV_NVCL44", // HEVC_NAL_RSV_NVCL44 ++ "RSV_NVCL45", // HEVC_NAL_RSV_NVCL45 ++ "RSV_NVCL46", // HEVC_NAL_RSV_NVCL46 ++ "RSV_NVCL47", // HEVC_NAL_RSV_NVCL47 ++ "UNSPEC48", // HEVC_NAL_UNSPEC48 ++ "UNSPEC49", // HEVC_NAL_UNSPEC49 ++ "UNSPEC50", // HEVC_NAL_UNSPEC50 ++ "UNSPEC51", // HEVC_NAL_UNSPEC51 ++ "UNSPEC52", // HEVC_NAL_UNSPEC52 ++ "UNSPEC53", // HEVC_NAL_UNSPEC53 ++ "UNSPEC54", // HEVC_NAL_UNSPEC54 ++ "UNSPEC55", // HEVC_NAL_UNSPEC55 ++ "UNSPEC56", // HEVC_NAL_UNSPEC56 ++ "UNSPEC57", // HEVC_NAL_UNSPEC57 ++ "UNSPEC58", // HEVC_NAL_UNSPEC58 ++ "UNSPEC59", // HEVC_NAL_UNSPEC59 ++ "UNSPEC60", // HEVC_NAL_UNSPEC60 ++ "UNSPEC61", // HEVC_NAL_UNSPEC61 ++ "UNSPEC62", // HEVC_NAL_UNSPEC62 ++ "UNSPEC63", // HEVC_NAL_UNSPEC63 ++}; ++ ++static const char *hevc_nal_unit_name(int nal_type) ++{ ++ av_assert0(nal_type >= 0 && nal_type < 64); ++ return hevc_nal_type_name[nal_type]; ++} ++ ++static const char *h264_nal_type_name[32] = { ++ "Unspecified 0", //H264_NAL_UNSPECIFIED ++ "Coded slice of a non-IDR picture", // H264_NAL_SLICE ++ "Coded slice data partition A", // H264_NAL_DPA ++ "Coded slice data partition B", // H264_NAL_DPB ++ "Coded slice data partition C", // H264_NAL_DPC ++ "IDR", // H264_NAL_IDR_SLICE ++ "SEI", // H264_NAL_SEI ++ "SPS", // H264_NAL_SPS ++ "PPS", // H264_NAL_PPS ++ "AUD", // H264_NAL_AUD ++ "End of sequence", // H264_NAL_END_SEQUENCE ++ "End of stream", // H264_NAL_END_STREAM ++ "Filler data", // H264_NAL_FILLER_DATA ++ "SPS extension", // H264_NAL_SPS_EXT ++ "Prefix", // H264_NAL_PREFIX ++ "Subset SPS", // H264_NAL_SUB_SPS ++ "Depth parameter set", // H264_NAL_DPS ++ "Reserved 17", // H264_NAL_RESERVED17 ++ "Reserved 18", // H264_NAL_RESERVED18 ++ "Auxiliary coded picture without partitioning", // H264_NAL_AUXILIARY_SLICE ++ "Slice extension", // H264_NAL_EXTEN_SLICE ++ "Slice extension for a depth view or a 3D-AVC texture view", // H264_NAL_DEPTH_EXTEN_SLICE ++ "Reserved 22", // H264_NAL_RESERVED22 ++ "Reserved 23", // H264_NAL_RESERVED23 ++ "Unspecified 24", // H264_NAL_UNSPECIFIED24 ++ "Unspecified 25", // H264_NAL_UNSPECIFIED25 ++ "Unspecified 26", // H264_NAL_UNSPECIFIED26 ++ "Unspecified 27", // H264_NAL_UNSPECIFIED27 ++ "Unspecified 28", // H264_NAL_UNSPECIFIED28 ++ "Unspecified 29", // H264_NAL_UNSPECIFIED29 ++ "Unspecified 30", // H264_NAL_UNSPECIFIED30 ++ "Unspecified 31", // H264_NAL_UNSPECIFIED31 ++}; ++ ++static const char *h264_nal_unit_name(int nal_type) ++{ ++ av_assert0(nal_type >= 0 && nal_type < 32); ++ return h264_nal_type_name[nal_type]; ++} ++ ++static int get_bit_length(H2645NAL *nal, int skip_trailing_zeros) ++{ ++ int size = nal->size; ++ int v; ++ ++ while (skip_trailing_zeros && size > 0 && nal->data[size - 1] == 0) ++ size--; ++ ++ if (!size) ++ return 0; ++ ++ v = nal->data[size - 1]; ++ ++ if (size > INT_MAX / 8) ++ return AVERROR(ERANGE); ++ size *= 8; ++ ++ /* remove the stop bit and following trailing zeros, ++ * or nothing for damaged bitstreams */ ++ if (v) ++ size -= ff_ctz(v) + 1; ++ ++ return size; ++} ++ ++/** ++ * @return AVERROR_INVALIDDATA if the packet is not a valid NAL unit, ++ * 0 if the unit should be skipped, 1 otherwise ++ */ ++static int hevc_parse_nal_header(H2645NAL *nal, void *logctx) ++{ ++ GetBitContext *gb = &nal->gb; ++ int nuh_layer_id; ++ ++ if (get_bits1(gb) != 0) ++ return AVERROR_INVALIDDATA; ++ ++ nal->type = get_bits(gb, 6); ++ ++ nuh_layer_id = get_bits(gb, 6); ++ nal->temporal_id = get_bits(gb, 3) - 1; ++ if (nal->temporal_id < 0) ++ return AVERROR_INVALIDDATA; ++ ++ av_log(logctx, AV_LOG_DEBUG, ++ "nal_unit_type: %d(%s), nuh_layer_id: %d, temporal_id: %d\n", ++ nal->type, hevc_nal_unit_name(nal->type), nuh_layer_id, nal->temporal_id); ++ ++ return nuh_layer_id == 0; ++} ++ ++static int h264_parse_nal_header(H2645NAL *nal, void *logctx) ++{ ++ GetBitContext *gb = &nal->gb; ++ char *src; ++ char *dst; ++ unsigned int si, di; ++ int removed_bytes = 0; ++ unsigned int length = 0; ++ ++ if (get_bits1(gb) != 0) ++ return AVERROR_INVALIDDATA; ++ ++ nal->ref_idc = get_bits(gb, 2); ++ nal->type = get_bits(gb, 5); ++ ++ if(nal->type != H264_NAL_SLICE && nal->type != H264_NAL_IDR_SLICE) { ++ si = di = 0; ++ src = dst = (char*)nal->data; ++ length = nal->size; ++ while (si + 2 < length) { ++ // remove escapes (very rare 1:2^22) ++ if (src[si + 2] > 3) { ++ dst[di++] = src[si++]; ++ dst[di++] = src[si++]; ++ } else if (src[si] == 0 && src[si + 1] == 0 && src[si + 2] == 3) { ++ dst[di++] = 0; ++ dst[di++] = 0; ++ si += 3; ++ } ++ dst[di++] = src[si++]; ++ } ++ ++ while (si < length) ++ dst[di++] = src[si++]; ++ ++ removed_bytes = si - di; ++ ++ nal->size -= removed_bytes; ++ ++ } ++ ++ av_log(logctx, AV_LOG_DEBUG, ++ "nal_unit_type: %d(%s), nal_ref_idc: %d\n", ++ nal->type, h264_nal_unit_name(nal->type), nal->ref_idc); ++ ++ return 1; ++} ++ ++static int find_next_start_code(const uint8_t *buf, const uint8_t *next_avc) ++{ ++ int i = 0; ++ ++ if (buf + 3 >= next_avc) ++ return next_avc - buf; ++ ++ while (buf + i + 3 < next_avc) { ++ if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1) ++ break; ++ i++; ++ } ++ return i + 3; ++} ++ ++extern void hexdump(unsigned char *buf, int len); ++ ++int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, ++ void *logctx, int is_nalff, int nal_length_size, ++ int small_padding) ++{ ++ GetByteContext bc; ++ int consumed, ret = 0; ++ int next_avc = is_nalff ? 0 : length; //如果nalæ—¶å…¨FF, 说明没有下一个avc, å¦åˆ™ä¸‹ä¸€ä¸ªavc就是buffer的长度?? ++ int64_t padding = small_padding ? 0 : MAX_MBPAIR_SIZE; ++ ++ /* bufferæ˜¯è¾“å…¥çš„åŽŸå§‹ç æµ.*/ ++ bytestream2_init(&bc, buf, length); ++ ++ ++ pkt->nb_nals = 0; ++ while (bytestream2_get_bytes_left(&bc) >= 4) { ++ H2645NAL *nal; ++ int extract_length = 0; ++ int skip_trailing_zeros = 1; ++ ++ int buf_index; ++ ++ if (bytestream2_tell(&bc) > next_avc) ++ av_log(logctx, AV_LOG_WARNING, "Exceeded next NALFF position, re-syncing.\n"); ++ ++ buf_index = find_next_start_code(bc.buffer, buf + next_avc); ++ ++ bytestream2_skip(&bc, buf_index); ++ ++ if (!bytestream2_get_bytes_left(&bc)) { ++ if (pkt->nb_nals > 0) { ++ // No more start codes: we discarded some irrelevant ++ // bytes at the end of the packet. ++ return 0; ++ } else { ++ av_log(logctx, AV_LOG_ERROR, "No start code is found.\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ } ++ ++ extract_length = FFMIN(bytestream2_get_bytes_left(&bc), next_avc - bytestream2_tell(&bc)); ++ ++ if (bytestream2_tell(&bc) >= next_avc) { ++ /* skip to the start of the next NAL */ ++ bytestream2_skip(&bc, next_avc - bytestream2_tell(&bc)); ++ continue; ++ } ++ ++ if (pkt->nals_allocated < pkt->nb_nals + 1) { ++ int new_size = pkt->nals_allocated + 1; ++ void *tmp = av_realloc_array(pkt->nals, new_size, sizeof(*pkt->nals)); ++ ++ if (!tmp) ++ return AVERROR(ENOMEM); ++ ++ if(new_size > MAX_NALS_PER_PACKET) { ++ av_log(logctx, AV_LOG_WARNING, ++ "Too Many nals (%d) in one packet, max is (%d)\n", ++ new_size, MAX_NALS_PER_PACKET); ++ return AVERROR(ENOMEM); ++ } ++ ++ pkt->nals = tmp; ++ memset(pkt->nals + pkt->nals_allocated, 0, ++ (new_size - pkt->nals_allocated) * sizeof(*pkt->nals)); ++ ++ nal = &pkt->nals[pkt->nb_nals]; ++#if 0 ++ nal->skipped_bytes_pos_size = 1024; // initial buffer size ++ nal->skipped_bytes_pos = av_malloc_array(nal->skipped_bytes_pos_size, sizeof(*nal->skipped_bytes_pos)); ++ if (!nal->skipped_bytes_pos) ++ return AVERROR(ENOMEM); ++#endif ++ pkt->nals_allocated = new_size; ++ } ++ nal = &pkt->nals[pkt->nb_nals]; ++ ++ /*æå– rbsp, 并且去掉 0x000003 åºåˆ—中的0x03. */ ++ consumed = ff_h2645_extract_rbsp(bc.buffer, extract_length, nal, small_padding); ++ if (consumed < 0) ++ return consumed; ++ ++ if (is_nalff && (extract_length != consumed) && extract_length) ++ av_log(logctx, AV_LOG_DEBUG, ++ "NALFF: Consumed only %d bytes instead of %d\n", ++ consumed, extract_length); ++ ++#if 0 ++ printk("----nal->data:%x, nal->size:%d\n", nal->data, nal->size); ++ hexdump(nal->data, 32); ++#endif ++ ++ /* è§£æžå‡ºæ¥çš„nal递增....*/ ++ ++ pkt->nb_nals++; ++ ++ bytestream2_skip(&bc, consumed); ++ ++ nal->size_bits = get_bit_length(nal, skip_trailing_zeros); ++ ++ ret = init_get_bits(&nal->gb, nal->data, nal->size_bits); ++ if (ret < 0) ++ return ret; ++ ++ ret = h264_parse_nal_header(nal, logctx); ++ ++ if (ret <= 0 || nal->size <= 0 || nal->size_bits <= 0) { ++ if (ret < 0) { ++ av_log(logctx, AV_LOG_ERROR, "Invalid NAL unit %d, skipping.\n", ++ nal->type); ++ } ++ pkt->nb_nals--; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++void ff_h2645_packet_uninit(H2645Packet *pkt) ++{ ++ int i; ++#if 0 ++ for (i = 0; i < pkt->nals_allocated; i++) { ++ av_freep(&pkt->nals[i].skipped_bytes_pos); ++ } ++#endif ++ av_freep(&pkt->nals); ++ pkt->nals_allocated = 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_direct.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_direct.c +new file mode 100644 +index 000000000..3c41fab78 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_direct.c +@@ -0,0 +1,146 @@ ++#include "avcodec.h" ++#include "h264dec.h" ++#include "h264_ps.h" ++ ++static int get_scale_factor(H264SliceContext *sl, ++ int poc, int poc1, int i) ++{ ++ int poc0 = sl->ref_list[0][i].poc; ++ int64_t pocdiff = poc1 - (int64_t)poc0; ++ int td = av_clip_int8(pocdiff); ++ ++ if (pocdiff != (int)pocdiff) ++ av_log(sl->h264->avctx, AV_LOG_WARNING, "pocdiff overflow\n"); ++ ++ if (td == 0 || sl->ref_list[0][i].parent->long_ref) { ++ return 256; ++ } else { ++ int64_t pocdiff0 = poc - (int64_t)poc0; ++ int tb = av_clip_int8(pocdiff0); ++ int tx = (16384 + (FFABS(td) >> 1)) / td; ++ ++ if (pocdiff0 != (int)pocdiff0) ++ av_log(sl->h264->avctx, AV_LOG_DEBUG, "pocdiff0 overflow\n"); ++ ++ return av_clip_intp2((tb * tx + 32) >> 6, 10); ++ } ++} ++ ++void ff_h264_direct_dist_scale_factor(const H264Context *const h, ++ H264SliceContext *sl) ++{ ++ const int poc = FIELD_PICTURE(h) ? h->cur_pic_ptr->field_poc[h->picture_structure == PICT_BOTTOM_FIELD] ++ : h->cur_pic_ptr->poc; ++ const int poc1 = sl->ref_list[1][0].poc; ++ int i, field; ++ ++ if (FRAME_MBAFF(h)) ++ for (field = 0; field < 2; field++) { ++ const int poc = h->cur_pic_ptr->field_poc[field]; ++ const int poc1 = sl->ref_list[1][0].parent->field_poc[field]; ++ for (i = 0; i < 2 * sl->ref_count[0]; i++) ++ sl->dist_scale_factor_field[field][i ^ field] = ++ get_scale_factor(sl, poc, poc1, i + 16); ++ } ++ ++ for (i = 0; i < sl->ref_count[0]; i++) ++ sl->dist_scale_factor[i] = get_scale_factor(sl, poc, poc1, i); ++} ++ ++static void fill_colmap(const H264Context *h, H264SliceContext *sl, ++ int map[2][16 + 32], int list, ++ int field, int colfield, int mbafi) ++{ ++ H264Picture *const ref1 = sl->ref_list[1][0].parent; ++ int j, old_ref, rfield; ++ int start = mbafi ? 16 : 0; ++ int end = mbafi ? 16 + 2 * sl->ref_count[0] : sl->ref_count[0]; ++ int interl = mbafi || h->picture_structure != PICT_FRAME; ++ ++ /* bogus; fills in for missing frames */ ++ memset(map[list], 0, sizeof(map[list])); ++ ++ for (rfield = 0; rfield < 2; rfield++) { ++ for (old_ref = 0; old_ref < ref1->ref_count[colfield][list]; old_ref++) { ++ int poc = ref1->ref_poc[colfield][list][old_ref]; ++ ++ if (!interl) ++ poc |= 3; ++ // FIXME: store all MBAFF references so this is not needed ++ else if (interl && (poc & 3) == 3) ++ poc = (poc & ~3) + rfield + 1; ++ ++ for (j = start; j < end; j++) { ++ if (4 * sl->ref_list[0][j].parent->frame_num + ++ (sl->ref_list[0][j].reference & 3) == poc) { ++ int cur_ref = mbafi ? (j - 16) ^ field : j; ++ if (ref1->mbaff) ++ map[list][2 * old_ref + (rfield ^ field) + 16] = cur_ref; ++ if (rfield == field || !interl) ++ map[list][old_ref] = cur_ref; ++ break; ++ } ++ } ++ } ++ } ++} ++ ++void ff_h264_direct_ref_list_init(const H264Context *const h, H264SliceContext *sl) ++{ ++ H264Ref *const ref1 = &sl->ref_list[1][0]; ++ H264Picture *const cur = h->cur_pic_ptr; ++ int list, j, field; ++ int sidx = (h->picture_structure & 1) ^ 1; ++ int ref1sidx = (ref1->reference & 1) ^ 1; ++ ++ for (list = 0; list < sl->list_count; list++) { ++ cur->ref_count[sidx][list] = sl->ref_count[list]; ++ for (j = 0; j < sl->ref_count[list]; j++) ++ cur->ref_poc[sidx][list][j] = 4 * sl->ref_list[list][j].parent->frame_num + ++ (sl->ref_list[list][j].reference & 3); ++ } ++ ++ if (h->picture_structure == PICT_FRAME) { ++ memcpy(cur->ref_count[1], cur->ref_count[0], sizeof(cur->ref_count[0])); ++ memcpy(cur->ref_poc[1], cur->ref_poc[0], sizeof(cur->ref_poc[0])); ++ } ++ ++ if (h->current_slice == 0) { ++ cur->mbaff = FRAME_MBAFF(h); ++ } else { ++ av_assert0(cur->mbaff == FRAME_MBAFF(h)); ++ } ++ ++ sl->col_fieldoff = 0; ++ ++ if (sl->list_count != 2 || !sl->ref_count[1]) ++ return; ++ ++ if (h->picture_structure == PICT_FRAME) { ++ int cur_poc = h->cur_pic_ptr->poc; ++ int *col_poc = sl->ref_list[1][0].parent->field_poc; ++ if (col_poc[0] == INT_MAX && col_poc[1] == INT_MAX) { ++ av_log(h->avctx, AV_LOG_ERROR, "co located POCs unavailable\n"); ++ sl->col_parity = 1; ++ } else ++ sl->col_parity = (FFABS(col_poc[0] - (int64_t)cur_poc) >= ++ FFABS(col_poc[1] - (int64_t)cur_poc)); ++ ref1sidx = ++ sidx = sl->col_parity; ++ // FL -> FL & differ parity ++ } else if (!(h->picture_structure & sl->ref_list[1][0].reference) && ++ !sl->ref_list[1][0].parent->mbaff) { ++ sl->col_fieldoff = 2 * sl->ref_list[1][0].reference - 3; ++ } ++ ++ if (sl->slice_type_nos != AV_PICTURE_TYPE_B || sl->direct_spatial_mv_pred) ++ return; ++ ++ for (list = 0; list < 2; list++) { ++ fill_colmap(h, sl, sl->map_col_to_list0, list, sidx, ref1sidx, 0); ++ if (FRAME_MBAFF(h)) ++ for (field = 0; field < 2; field++) ++ fill_colmap(h, sl, sl->map_col_to_list0_field[field], list, field, ++ field, 1); ++ } ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_parse.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_parse.c +new file mode 100644 +index 000000000..7a6114537 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_parse.c +@@ -0,0 +1,279 @@ ++#include "bytestream.h" ++#include "get_bits.h" ++#include "golomb.h" ++#include "h264.h" ++#include "h264dec.h" ++#include "h264_parse.h" ++#include "h264_ps.h" ++ ++int ff_h264_pred_weight_table(GetBitContext *gb, const SPS *sps, ++ const int *ref_count, int slice_type_nos, ++ H264PredWeightTable *pwt, ++ int picture_structure, void *logctx) ++{ ++ int list, i, j; ++ int luma_def, chroma_def; ++ ++ pwt->use_weight = 0; ++ pwt->use_weight_chroma = 0; ++ ++ pwt->luma_log2_weight_denom = get_ue_golomb(gb); ++ if (pwt->luma_log2_weight_denom > 7U) { ++ av_log(logctx, AV_LOG_ERROR, "luma_log2_weight_denom %d is out of range\n", pwt->luma_log2_weight_denom); ++ pwt->luma_log2_weight_denom = 0; ++ } ++ luma_def = 1 << pwt->luma_log2_weight_denom; ++ ++ if (sps->chroma_format_idc) { ++ pwt->chroma_log2_weight_denom = get_ue_golomb(gb); ++ if (pwt->chroma_log2_weight_denom > 7U) { ++ av_log(logctx, AV_LOG_ERROR, "chroma_log2_weight_denom %d is out of range\n", pwt->chroma_log2_weight_denom); ++ pwt->chroma_log2_weight_denom = 0; ++ } ++ chroma_def = 1 << pwt->chroma_log2_weight_denom; ++ } ++ ++ for (list = 0; list < 2; list++) { ++ pwt->luma_weight_flag[list] = 0; ++ pwt->chroma_weight_flag[list] = 0; ++ for (i = 0; i < ref_count[list]; i++) { ++ int luma_weight_flag, chroma_weight_flag; ++ ++ luma_weight_flag = get_bits1(gb); ++ if (luma_weight_flag) { ++ pwt->luma_weight[i][list][0] = get_se_golomb(gb); ++ pwt->luma_weight[i][list][1] = get_se_golomb(gb); ++ if ((int8_t)pwt->luma_weight[i][list][0] != pwt->luma_weight[i][list][0] || ++ (int8_t)pwt->luma_weight[i][list][1] != pwt->luma_weight[i][list][1]) ++ goto out_range_weight; ++ if (pwt->luma_weight[i][list][0] != luma_def || ++ pwt->luma_weight[i][list][1] != 0) { ++ pwt->use_weight = 1; ++ pwt->luma_weight_flag[list] = 1; ++ } ++ } else { ++ if(luma_def > 127) { ++ luma_def = 127; ++ } ++ pwt->luma_weight[i][list][0] = luma_def; ++ pwt->luma_weight[i][list][1] = 0; ++ } ++ ++ if (sps->chroma_format_idc) { ++ chroma_weight_flag = get_bits1(gb); ++ if (chroma_weight_flag) { ++ int j; ++ for (j = 0; j < 2; j++) { ++ pwt->chroma_weight[i][list][j][0] = get_se_golomb(gb); ++ pwt->chroma_weight[i][list][j][1] = get_se_golomb(gb); ++ if ((int8_t)pwt->chroma_weight[i][list][j][0] != pwt->chroma_weight[i][list][j][0] || ++ (int8_t)pwt->chroma_weight[i][list][j][1] != pwt->chroma_weight[i][list][j][1]) { ++ pwt->chroma_weight[i][list][j][0] = chroma_def; ++ pwt->chroma_weight[i][list][j][1] = 0; ++ goto out_range_weight; ++ } ++ if (pwt->chroma_weight[i][list][j][0] != chroma_def || ++ pwt->chroma_weight[i][list][j][1] != 0) { ++ pwt->use_weight_chroma = 1; ++ pwt->chroma_weight_flag[list] = 1; ++ } ++ } ++ } else { ++ int j; ++ for (j = 0; j < 2; j++) { ++ if(chroma_def > 127) { ++ chroma_def = 127; ++ } ++ pwt->chroma_weight[i][list][j][0] = chroma_def; ++ pwt->chroma_weight[i][list][j][1] = 0; ++ } ++ } ++ } ++ ++ // for MBAFF ++ if (picture_structure == PICT_FRAME) { ++ pwt->luma_weight[16 + 2 * i][list][0] = pwt->luma_weight[16 + 2 * i + 1][list][0] = pwt->luma_weight[i][list][0]; ++ pwt->luma_weight[16 + 2 * i][list][1] = pwt->luma_weight[16 + 2 * i + 1][list][1] = pwt->luma_weight[i][list][1]; ++ if (sps->chroma_format_idc) { ++ for (j = 0; j < 2; j++) { ++ pwt->chroma_weight[16 + 2 * i][list][j][0] = pwt->chroma_weight[16 + 2 * i + 1][list][j][0] = pwt->chroma_weight[i][list][j][0]; ++ pwt->chroma_weight[16 + 2 * i][list][j][1] = pwt->chroma_weight[16 + 2 * i + 1][list][j][1] = pwt->chroma_weight[i][list][j][1]; ++ } ++ } ++ } ++ } ++ if (slice_type_nos != AV_PICTURE_TYPE_B) ++ break; ++ } ++ pwt->use_weight = pwt->use_weight || pwt->use_weight_chroma; ++ return 0; ++out_range_weight: ++ av_log(logctx, AV_LOG_WARNING, "Out of range weight"); ++ return AVERROR_INVALIDDATA; ++} ++ ++ ++int ff_h264_parse_ref_count(int *plist_count, int ref_count[2], ++ GetBitContext *gb, const PPS *pps, ++ int slice_type_nos, int picture_structure, void *logctx) ++{ ++ int list_count; ++ int num_ref_idx_active_override_flag; ++ ++ // set defaults, might be overridden a few lines later ++ ref_count[0] = pps->ref_count[0]; ++ ref_count[1] = pps->ref_count[1]; ++ ++ if (slice_type_nos != AV_PICTURE_TYPE_I) { ++ unsigned max[2]; ++ max[0] = max[1] = picture_structure == PICT_FRAME ? 15 : 31; ++ ++ num_ref_idx_active_override_flag = get_bits1(gb); ++ ++ if (num_ref_idx_active_override_flag) { ++ ref_count[0] = get_ue_golomb(gb) + 1; ++ if (slice_type_nos == AV_PICTURE_TYPE_B) { ++ ref_count[1] = get_ue_golomb(gb) + 1; ++ } else ++ // full range is spec-ok in this case, even for frames ++ ref_count[1] = 1; ++ } ++ ++ if (ref_count[0] - 1 > max[0] || ref_count[1] - 1 > max[1]) { ++ av_log(logctx, AV_LOG_ERROR, "reference overflow %u > %u or %u > %u\n", ++ ref_count[0] - 1, max[0], ref_count[1] - 1, max[1]); ++ ref_count[0] = ref_count[1] = 0; ++ *plist_count = 0; ++ goto fail; ++ } ++ ++ if (slice_type_nos == AV_PICTURE_TYPE_B) ++ list_count = 2; ++ else ++ list_count = 1; ++ } else { ++ list_count = 0; ++ ref_count[0] = ref_count[1] = 0; ++ } ++ ++ *plist_count = list_count; ++ ++ return 0; ++fail: ++ *plist_count = 0; ++ ref_count[0] = 0; ++ ref_count[1] = 0; ++ return AVERROR_INVALIDDATA; ++} ++ ++int ff_h264_init_poc(int pic_field_poc[2], int *pic_poc, ++ const SPS *sps, H264POCContext *pc, ++ int picture_structure, int nal_ref_idc) ++{ ++ const int max_frame_num = 1 << sps->log2_max_frame_num; ++ int64_t field_poc[2]; ++ ++ pc->frame_num_offset = pc->prev_frame_num_offset; ++ if (pc->frame_num < pc->prev_frame_num) ++ pc->frame_num_offset += max_frame_num; ++ ++ if (sps->poc_type == 0) { ++ const int max_poc_lsb = 1 << sps->log2_max_poc_lsb; ++ ++ if (pc->poc_lsb < pc->prev_poc_lsb && ++ pc->prev_poc_lsb - pc->poc_lsb >= max_poc_lsb / 2) ++ pc->poc_msb = pc->prev_poc_msb + max_poc_lsb; ++ else if (pc->poc_lsb > pc->prev_poc_lsb && ++ pc->prev_poc_lsb - pc->poc_lsb < -max_poc_lsb / 2) ++ pc->poc_msb = pc->prev_poc_msb - max_poc_lsb; ++ else ++ pc->poc_msb = pc->prev_poc_msb; ++ field_poc[0] = ++ field_poc[1] = pc->poc_msb + pc->poc_lsb; ++ if (picture_structure == PICT_FRAME) ++ field_poc[1] += pc->delta_poc_bottom; ++ } else if (sps->poc_type == 1) { ++ int abs_frame_num; ++ int64_t expected_delta_per_poc_cycle, expectedpoc; ++ int i; ++ ++ if (sps->poc_cycle_length != 0) ++ abs_frame_num = pc->frame_num_offset + pc->frame_num; ++ else ++ abs_frame_num = 0; ++ ++ if (nal_ref_idc == 0 && abs_frame_num > 0) ++ abs_frame_num--; ++ ++ expected_delta_per_poc_cycle = 0; ++ for (i = 0; i < sps->poc_cycle_length; i++) ++ // FIXME integrate during sps parse ++ expected_delta_per_poc_cycle += sps->offset_for_ref_frame[i]; ++ ++ if (abs_frame_num > 0) { ++ int poc_cycle_cnt = (abs_frame_num - 1) / sps->poc_cycle_length; ++ int frame_num_in_poc_cycle = (abs_frame_num - 1) % sps->poc_cycle_length; ++ ++ expectedpoc = poc_cycle_cnt * expected_delta_per_poc_cycle; ++ for (i = 0; i <= frame_num_in_poc_cycle; i++) ++ expectedpoc = expectedpoc + sps->offset_for_ref_frame[i]; ++ } else ++ expectedpoc = 0; ++ ++ if (nal_ref_idc == 0) ++ expectedpoc = expectedpoc + sps->offset_for_non_ref_pic; ++ ++ field_poc[0] = expectedpoc + pc->delta_poc[0]; ++ field_poc[1] = field_poc[0] + sps->offset_for_top_to_bottom_field; ++ ++ if (picture_structure == PICT_FRAME) ++ field_poc[1] += pc->delta_poc[1]; ++ } else { ++ int poc = 2 * (pc->frame_num_offset + pc->frame_num); ++ ++ if (!nal_ref_idc) ++ poc--; ++ ++ field_poc[0] = poc; ++ field_poc[1] = poc; ++ } ++ ++ if ( field_poc[0] != (int)field_poc[0] ++ || field_poc[1] != (int)field_poc[1]) ++ return AVERROR_INVALIDDATA; ++ ++ if (picture_structure != PICT_BOTTOM_FIELD) ++ pic_field_poc[0] = field_poc[0]; ++ if (picture_structure != PICT_TOP_FIELD) ++ pic_field_poc[1] = field_poc[1]; ++ *pic_poc = FFMIN(pic_field_poc[0], pic_field_poc[1]); ++ ++ return 0; ++} ++ ++/** ++ * Compute profile from profile_idc and constraint_set?_flags. ++ * ++ * @param sps SPS ++ * ++ * @return profile as defined by FF_PROFILE_H264_* ++ */ ++int ff_h264_get_profile(const SPS *sps) ++{ ++ int profile = sps->profile_idc; ++ ++ switch (sps->profile_idc) { ++ case FF_PROFILE_H264_BASELINE: ++ // constraint_set1_flag set to 1 ++ profile |= (sps->constraint_set_flags & 1 << 1) ? FF_PROFILE_H264_CONSTRAINED : 0; ++ break; ++ case FF_PROFILE_H264_HIGH_10: ++ case FF_PROFILE_H264_HIGH_422: ++ case FF_PROFILE_H264_HIGH_444_PREDICTIVE: ++ // constraint_set3_flag set to 1 ++ profile |= (sps->constraint_set_flags & 1 << 3) ? FF_PROFILE_H264_INTRA : 0; ++ break; ++ } ++ ++ return profile; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_picture.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_picture.c +new file mode 100644 +index 000000000..5583bafaf +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_picture.c +@@ -0,0 +1,56 @@ ++#include "avassert.h" ++#include "avcodec.h" ++#include "h264dec.h" ++#include "h264data.h" ++#include "mpegutils.h" ++ ++void ff_h264_unref_picture(H264Context *h, H264Picture *pic) ++{ ++ if (!pic->f || !pic->f->buf[0]) ++ return; ++ ++} ++ ++int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src) ++{ ++ int i; ++ ++ for (i = 0; i < 2; i++) ++ dst->field_poc[i] = src->field_poc[i]; ++ ++ memcpy(dst->ref_poc, src->ref_poc, sizeof(src->ref_poc)); ++ memcpy(dst->ref_count, src->ref_count, sizeof(src->ref_count)); ++ ++ dst->poc = src->poc; ++ dst->frame_num = src->frame_num; ++ dst->mmco_reset = src->mmco_reset; ++ dst->long_ref = src->long_ref; ++ dst->mbaff = src->mbaff; ++ dst->field_picture = src->field_picture; ++ dst->reference = src->reference; ++ dst->recovered = src->recovered; ++ dst->invalid_gap = src->invalid_gap; ++ ++ return 0; ++} ++ ++int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup) ++{ ++ int err = 0; ++ h->mb_y = 0; ++ ++ ++ if (in_setup || 1 /*|| !(avctx->active_thread_type & FF_THREAD_FRAME)*/) { ++ if (!h->droppable) { ++ err = ff_h264_execute_ref_pic_marking(h); ++ h->poc.prev_poc_msb = h->poc.poc_msb; ++ h->poc.prev_poc_lsb = h->poc.poc_lsb; ++ } ++ h->poc.prev_frame_num_offset = h->poc.frame_num_offset; ++ h->poc.prev_frame_num = h->poc.frame_num; ++ } ++ ++ h->current_slice = 0; ++ ++ return err; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_ps.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_ps.c +new file mode 100644 +index 000000000..6c5bc4c99 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_ps.c +@@ -0,0 +1,779 @@ ++#ifdef __KERNEL__ ++#else ++#include ++#endif ++ ++#include "mathops.h" ++#include "avcodec.h" ++#include "h264data.h" ++#include "h264_ps.h" ++#include "golomb.h" ++ ++#define MIN_LOG2_MAX_FRAME_NUM 4 ++ ++#define EXTENDED_SAR 255 ++ ++static const uint8_t default_scaling4[2][16] = { ++ { 6, 13, 20, 28, 13, 20, 28, 32, ++ 20, 28, 32, 37, 28, 32, 37, 42 }, ++ { 10, 14, 20, 24, 14, 20, 24, 27, ++ 20, 24, 27, 30, 24, 27, 30, 34 } ++}; ++ ++static const uint8_t default_scaling8[2][64] = { ++ { 6, 10, 13, 16, 18, 23, 25, 27, ++ 10, 11, 16, 18, 23, 25, 27, 29, ++ 13, 16, 18, 23, 25, 27, 29, 31, ++ 16, 18, 23, 25, 27, 29, 31, 33, ++ 18, 23, 25, 27, 29, 31, 33, 36, ++ 23, 25, 27, 29, 31, 33, 36, 38, ++ 25, 27, 29, 31, 33, 36, 38, 40, ++ 27, 29, 31, 33, 36, 38, 40, 42 }, ++ { 9, 13, 15, 17, 19, 21, 22, 24, ++ 13, 13, 17, 19, 21, 22, 24, 25, ++ 15, 17, 19, 21, 22, 24, 25, 27, ++ 17, 19, 21, 22, 24, 25, 27, 28, ++ 19, 21, 22, 24, 25, 27, 28, 30, ++ 21, 22, 24, 25, 27, 28, 30, 32, ++ 22, 24, 25, 27, 28, 30, 32, 33, ++ 24, 25, 27, 28, 30, 32, 33, 35 } ++}; ++ ++/* maximum number of MBs in the DPB for a given level */ ++static const int level_max_dpb_mbs[][2] = { ++ { 10, 396 }, ++ { 11, 900 }, ++ { 12, 2376 }, ++ { 13, 2376 }, ++ { 20, 2376 }, ++ { 21, 4752 }, ++ { 22, 8100 }, ++ { 30, 8100 }, ++ { 31, 18000 }, ++ { 32, 20480 }, ++ { 40, 32768 }, ++ { 41, 32768 }, ++ { 42, 34816 }, ++ { 50, 110400 }, ++ { 51, 184320 }, ++ { 52, 184320 }, ++}; ++ ++static inline int decode_hrd_parameters(GetBitContext *gb, AVCodecContext *avctx, ++ SPS *sps) ++{ ++ int cpb_count, i; ++ cpb_count = get_ue_golomb_31(gb) + 1; ++ ++ if (cpb_count > 32U) { ++ av_log(avctx, AV_LOG_ERROR, "cpb_count %d invalid\n", cpb_count); ++ return AVERROR_INVALIDDATA; ++ } ++ ++ get_bits(gb, 4); /* bit_rate_scale */ ++ get_bits(gb, 4); /* cpb_size_scale */ ++ for (i = 0; i < cpb_count; i++) { ++ get_ue_golomb_long(gb); /* bit_rate_value_minus1 */ ++ get_ue_golomb_long(gb); /* cpb_size_value_minus1 */ ++ get_bits1(gb); /* cbr_flag */ ++ } ++ sps->initial_cpb_removal_delay_length = get_bits(gb, 5) + 1; ++ sps->cpb_removal_delay_length = get_bits(gb, 5) + 1; ++ sps->dpb_output_delay_length = get_bits(gb, 5) + 1; ++ sps->time_offset_length = get_bits(gb, 5); ++ sps->cpb_cnt = cpb_count; ++ return 0; ++} ++ ++static inline int decode_vui_parameters(GetBitContext *gb, AVCodecContext *avctx, ++ SPS *sps) ++{ ++ int aspect_ratio_info_present_flag; ++ unsigned int aspect_ratio_idc; ++ ++ aspect_ratio_info_present_flag = get_bits1(gb); ++ ++ if (aspect_ratio_info_present_flag) { ++ aspect_ratio_idc = get_bits(gb, 8); ++ if (aspect_ratio_idc == EXTENDED_SAR) { ++ sps->sar.num = get_bits(gb, 16); ++ sps->sar.den = get_bits(gb, 16); ++ } else if (aspect_ratio_idc < FF_ARRAY_ELEMS(ff_h264_pixel_aspect)) { ++ sps->sar = ff_h264_pixel_aspect[aspect_ratio_idc]; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "illegal aspect ratio\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ } else { ++ sps->sar.num = ++ sps->sar.den = 0; ++ } ++ ++ if (get_bits1(gb)) /* overscan_info_present_flag */ ++ get_bits1(gb); /* overscan_appropriate_flag */ ++ ++ sps->video_signal_type_present_flag = get_bits1(gb); ++ if (sps->video_signal_type_present_flag) { ++ get_bits(gb, 3); /* video_format */ ++ sps->full_range = get_bits1(gb); /* video_full_range_flag */ ++ ++ sps->colour_description_present_flag = get_bits1(gb); ++ if (sps->colour_description_present_flag) { ++ get_bits(gb, 8); /* colour_primaries */ ++ get_bits(gb, 8); /* transfer_characteristics */ ++ get_bits(gb, 8); /* matrix_coefficients */ ++ ++#if 0 ++ sps->color_primaries = get_bits(gb, 8); /* colour_primaries */ ++ sps->color_trc = get_bits(gb, 8); /* transfer_characteristics */ ++ sps->colorspace = get_bits(gb, 8); /* matrix_coefficients */ ++ // Set invalid values to "unspecified" ++ if (!av_color_primaries_name(sps->color_primaries)) ++ sps->color_primaries = AVCOL_PRI_UNSPECIFIED; ++ if (!av_color_transfer_name(sps->color_trc)) ++ sps->color_trc = AVCOL_TRC_UNSPECIFIED; ++ if (!av_color_space_name(sps->colorspace)) ++ sps->colorspace = AVCOL_SPC_UNSPECIFIED; ++#endif ++ } ++ } ++ ++ /* chroma_location_info_present_flag */ ++ if (get_bits1(gb)) { ++ /* chroma_sample_location_type_top_field */ ++#if 0 ++ avctx->chroma_sample_location = get_ue_golomb(gb) + 1; ++#else ++ get_ue_golomb(gb); ++#endif ++ get_ue_golomb(gb); /* chroma_sample_location_type_bottom_field */ ++ } ++ ++ if (show_bits1(gb) && get_bits_left(gb) < 10) { ++ av_log(avctx, AV_LOG_WARNING, "Truncated VUI\n"); ++ return 0; ++ } ++ ++ sps->timing_info_present_flag = get_bits1(gb); ++ if (sps->timing_info_present_flag) { ++ unsigned num_units_in_tick = get_bits_long(gb, 32); ++ unsigned time_scale = get_bits_long(gb, 32); ++ if (!num_units_in_tick || !time_scale) { ++ av_log(avctx, AV_LOG_ERROR, ++ "time_scale/num_units_in_tick invalid or unsupported (%u/%u)\n", ++ time_scale, num_units_in_tick); ++ sps->timing_info_present_flag = 0; ++ } else { ++ sps->num_units_in_tick = num_units_in_tick; ++ sps->time_scale = time_scale; ++ } ++ sps->fixed_frame_rate_flag = get_bits1(gb); ++ } ++ ++ sps->nal_hrd_parameters_present_flag = get_bits1(gb); ++ if (sps->nal_hrd_parameters_present_flag) ++ if (decode_hrd_parameters(gb, avctx, sps) < 0) ++ return AVERROR_INVALIDDATA; ++ sps->vcl_hrd_parameters_present_flag = get_bits1(gb); ++ if (sps->vcl_hrd_parameters_present_flag) ++ if (decode_hrd_parameters(gb, avctx, sps) < 0) ++ return AVERROR_INVALIDDATA; ++ if (sps->nal_hrd_parameters_present_flag || ++ sps->vcl_hrd_parameters_present_flag) ++ get_bits1(gb); /* low_delay_hrd_flag */ ++ sps->pic_struct_present_flag = get_bits1(gb); ++ if (!get_bits_left(gb)) ++ return 0; ++ sps->bitstream_restriction_flag = get_bits1(gb); ++ if (sps->bitstream_restriction_flag) { ++ get_bits1(gb); /* motion_vectors_over_pic_boundaries_flag */ ++ get_ue_golomb(gb); /* max_bytes_per_pic_denom */ ++ get_ue_golomb(gb); /* max_bits_per_mb_denom */ ++ get_ue_golomb(gb); /* log2_max_mv_length_horizontal */ ++ get_ue_golomb(gb); /* log2_max_mv_length_vertical */ ++ sps->num_reorder_frames = get_ue_golomb(gb); ++ get_ue_golomb(gb); /*max_dec_frame_buffering*/ ++ ++ if (get_bits_left(gb) < 0) { ++ sps->num_reorder_frames = 0; ++ sps->bitstream_restriction_flag = 0; ++ } ++ ++ if (sps->num_reorder_frames > 16U ++ /* max_dec_frame_buffering || max_dec_frame_buffering > 16 */) { ++ av_log(avctx, AV_LOG_ERROR, ++ "Clipping illegal num_reorder_frames %d\n", ++ sps->num_reorder_frames); ++ sps->num_reorder_frames = 16; ++ return AVERROR_INVALIDDATA; ++ } ++ } ++ ++ return 0; ++} ++ ++static int decode_scaling_list(GetBitContext *gb, uint8_t *factors, int size, ++ const uint8_t *jvt_list, ++ const uint8_t *fallback_list) ++{ ++ int i, last = 8, next = 8; ++ const uint8_t *scan = size == 16 ? ff_zigzag_scan : ff_zigzag_direct; ++ if (!get_bits1(gb)) /* matrix not written, we use the predicted one */ ++ memcpy(factors, fallback_list, size * sizeof(uint8_t)); ++ else ++ for (i = 0; i < size; i++) { ++ if (next) { ++ int v = get_se_golomb(gb); ++ if (v < -128 || v > 127) { ++ av_log(NULL, AV_LOG_ERROR, "delta scale %d is invalid\n", v); ++ return AVERROR_INVALIDDATA; ++ } ++ next = (last + v) & 0xff; ++ } ++ if (!i && !next) { /* matrix not written, we use the preset one */ ++ memcpy(factors, jvt_list, size * sizeof(uint8_t)); ++ break; ++ } ++ last = factors[scan[i]] = next ? next : last; ++ } ++ return 0; ++} ++ ++/* returns non zero if the provided SPS scaling matrix has been filled */ ++static int decode_scaling_matrices(GetBitContext *gb, const SPS *sps, ++ const PPS *pps, int is_sps, ++ uint8_t(*scaling_matrix4)[16], ++ uint8_t(*scaling_matrix8)[64]) ++{ ++ int fallback_sps = !is_sps && sps->scaling_matrix_present; ++ const uint8_t *fallback[4] = { ++ fallback_sps ? sps->scaling_matrix4[0] : default_scaling4[0], ++ fallback_sps ? sps->scaling_matrix4[3] : default_scaling4[1], ++ fallback_sps ? sps->scaling_matrix8[0] : default_scaling8[0], ++ fallback_sps ? sps->scaling_matrix8[3] : default_scaling8[1] ++ }; ++ int ret = 0; ++ if (get_bits1(gb)) { ++ ret |= decode_scaling_list(gb, scaling_matrix4[0], 16, default_scaling4[0], fallback[0]); // Intra, Y ++ ret |= decode_scaling_list(gb, scaling_matrix4[1], 16, default_scaling4[0], scaling_matrix4[0]); // Intra, Cr ++ ret |= decode_scaling_list(gb, scaling_matrix4[2], 16, default_scaling4[0], scaling_matrix4[1]); // Intra, Cb ++ ret |= decode_scaling_list(gb, scaling_matrix4[3], 16, default_scaling4[1], fallback[1]); // Inter, Y ++ ret |= decode_scaling_list(gb, scaling_matrix4[4], 16, default_scaling4[1], scaling_matrix4[3]); // Inter, Cr ++ ret |= decode_scaling_list(gb, scaling_matrix4[5], 16, default_scaling4[1], scaling_matrix4[4]); // Inter, Cb ++ if (is_sps || pps->transform_8x8_mode) { ++ ret |= decode_scaling_list(gb, scaling_matrix8[0], 64, default_scaling8[0], fallback[2]); // Intra, Y ++ ret |= decode_scaling_list(gb, scaling_matrix8[3], 64, default_scaling8[1], fallback[3]); // Inter, Y ++ if (sps->chroma_format_idc == 3) { ++ ret |= decode_scaling_list(gb, scaling_matrix8[1], 64, default_scaling8[0], scaling_matrix8[0]); // Intra, Cr ++ ret |= decode_scaling_list(gb, scaling_matrix8[4], 64, default_scaling8[1], scaling_matrix8[3]); // Inter, Cr ++ ret |= decode_scaling_list(gb, scaling_matrix8[2], 64, default_scaling8[0], scaling_matrix8[1]); // Intra, Cb ++ ret |= decode_scaling_list(gb, scaling_matrix8[5], 64, default_scaling8[1], scaling_matrix8[4]); // Inter, Cb ++ } ++ } ++ if (!ret) ++ ret = is_sps; ++ } ++ ++ return ret; ++} ++ ++void ff_h264_ps_uninit(H264ParamSets *ps) ++{ ++ int i; ++ ++ ps->pps = NULL; ++ ps->sps = NULL; ++} ++ ++int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, ++ H264ParamSets *ps, int ignore_truncation) ++{ ++ int profile_idc, level_idc, constraint_set_flags = 0; ++ unsigned int sps_id; ++ int i, log2_max_frame_num_minus4; ++ SPS *sps; ++ int ret; ++ ++ profile_idc = get_bits(gb, 8); ++ constraint_set_flags |= get_bits1(gb) << 0; // constraint_set0_flag ++ constraint_set_flags |= get_bits1(gb) << 1; // constraint_set1_flag ++ constraint_set_flags |= get_bits1(gb) << 2; // constraint_set2_flag ++ constraint_set_flags |= get_bits1(gb) << 3; // constraint_set3_flag ++ constraint_set_flags |= get_bits1(gb) << 4; // constraint_set4_flag ++ constraint_set_flags |= get_bits1(gb) << 5; // constraint_set5_flag ++ skip_bits(gb, 2); // reserved_zero_2bits ++ level_idc = get_bits(gb, 8); ++ sps_id = get_ue_golomb_31(gb); ++ ++ if (sps_id >= MAX_SPS_COUNT) { ++ av_log(avctx, AV_LOG_ERROR, "sps_id %u out of range\n", sps_id); ++ goto fail; ++ } ++ ++ sps = &ps->sps_list[sps_id]; ++ ++ sps->sps_id = sps_id; ++ sps->time_offset_length = 24; ++ sps->profile_idc = profile_idc; ++ sps->constraint_set_flags = constraint_set_flags; ++ sps->level_idc = level_idc; ++ sps->full_range = -1; ++ ++ memset(sps->scaling_matrix4, 16, sizeof(sps->scaling_matrix4)); ++ memset(sps->scaling_matrix8, 16, sizeof(sps->scaling_matrix8)); ++ sps->scaling_matrix_present = 0; ++// sps->colorspace = 2; //AVCOL_SPC_UNSPECIFIED ++ ++ if (sps->profile_idc == 100 || // High profile ++ sps->profile_idc == 110 || // High10 profile ++ sps->profile_idc == 122 || // High422 profile ++ sps->profile_idc == 244 || // High444 Predictive profile ++ sps->profile_idc == 44 || // Cavlc444 profile ++ sps->profile_idc == 83 || // Scalable Constrained High profile (SVC) ++ sps->profile_idc == 86 || // Scalable High Intra profile (SVC) ++ sps->profile_idc == 118 || // Stereo High profile (MVC) ++ sps->profile_idc == 128 || // Multiview High profile (MVC) ++ sps->profile_idc == 138 || // Multiview Depth High profile (MVCD) ++ sps->profile_idc == 144) { // old High444 profile ++ sps->chroma_format_idc = get_ue_golomb_31(gb); ++ if (sps->chroma_format_idc > 3U) { ++ av_log(avctx, AV_LOG_ERROR, "chroma_format_idc %u", ++ sps->chroma_format_idc); ++ goto fail; ++ } else if (sps->chroma_format_idc == 3) { ++ sps->residual_color_transform_flag = get_bits1(gb); ++ if (sps->residual_color_transform_flag) { ++ av_log(avctx, AV_LOG_ERROR, "separate color planes are not supported\n"); ++ goto fail; ++ } ++ } ++ sps->bit_depth_luma = get_ue_golomb(gb) + 8; ++ sps->bit_depth_chroma = get_ue_golomb(gb) + 8; ++ if (sps->bit_depth_chroma != sps->bit_depth_luma) { ++ av_log(avctx, AV_LOG_ERROR, ++ "Different chroma and luma bit depth"); ++ goto fail; ++ } ++ if (sps->bit_depth_luma < 8 || sps->bit_depth_luma > 14 || ++ sps->bit_depth_chroma < 8 || sps->bit_depth_chroma > 14) { ++ av_log(avctx, AV_LOG_ERROR, "illegal bit depth value (%d, %d)\n", ++ sps->bit_depth_luma, sps->bit_depth_chroma); ++ goto fail; ++ } ++ sps->transform_bypass = get_bits1(gb); ++ ret = decode_scaling_matrices(gb, sps, NULL, 1, ++ sps->scaling_matrix4, sps->scaling_matrix8); ++ if (ret < 0) ++ goto fail; ++ sps->scaling_matrix_present |= ret; ++ } else { ++ sps->chroma_format_idc = 1; ++ sps->bit_depth_luma = 8; ++ sps->bit_depth_chroma = 8; ++ } ++ ++ log2_max_frame_num_minus4 = get_ue_golomb(gb); ++ if (log2_max_frame_num_minus4 < MIN_LOG2_MAX_FRAME_NUM - 4 || ++ log2_max_frame_num_minus4 > MAX_LOG2_MAX_FRAME_NUM - 4) { ++ av_log(avctx, AV_LOG_ERROR, ++ "log2_max_frame_num_minus4 out of range (0-12): %d\n", ++ log2_max_frame_num_minus4); ++ goto fail; ++ } ++ sps->log2_max_frame_num = log2_max_frame_num_minus4 + 4; ++ ++ sps->poc_type = get_ue_golomb_31(gb); ++ ++ if (sps->poc_type == 0) { // FIXME #define ++ unsigned t = get_ue_golomb(gb); ++ if (t>12) { ++ av_log(avctx, AV_LOG_ERROR, "log2_max_poc_lsb (%d) is out of range\n", t); ++ goto fail; ++ } ++ sps->log2_max_poc_lsb = t + 4; ++ } else if (sps->poc_type == 1) { // FIXME #define ++ sps->delta_pic_order_always_zero_flag = get_bits1(gb); ++ sps->offset_for_non_ref_pic = get_se_golomb(gb); ++ sps->offset_for_top_to_bottom_field = get_se_golomb(gb); ++ sps->poc_cycle_length = get_ue_golomb(gb); ++ ++ if ((unsigned)sps->poc_cycle_length >= ++ FF_ARRAY_ELEMS(sps->offset_for_ref_frame)) { ++ av_log(avctx, AV_LOG_ERROR, ++ "poc_cycle_length overflow %d\n", sps->poc_cycle_length); ++ goto fail; ++ } ++ ++ for (i = 0; i < sps->poc_cycle_length; i++) ++ sps->offset_for_ref_frame[i] = get_se_golomb(gb); ++ } else if (sps->poc_type != 2) { ++ av_log(avctx, AV_LOG_ERROR, "illegal POC type %d\n", sps->poc_type); ++ goto fail; ++ } ++ ++ sps->ref_frame_count = get_ue_golomb_31(gb); ++ if (sps->ref_frame_count > MAX_DELAYED_PIC_COUNT) { ++ av_log(avctx, AV_LOG_ERROR, ++ "too many reference frames %d\n", sps->ref_frame_count); ++ goto fail; ++ } ++ sps->gaps_in_frame_num_allowed_flag = get_bits1(gb); ++ sps->mb_width = get_ue_golomb(gb) + 1; ++ sps->mb_height = get_ue_golomb(gb) + 1; ++ ++ sps->frame_mbs_only_flag = get_bits1(gb); ++ ++ if (sps->mb_height >= INT_MAX / 2U) { ++ av_log(avctx, AV_LOG_ERROR, "height overflow\n"); ++ goto fail; ++ } ++ sps->mb_height *= 2 - sps->frame_mbs_only_flag; ++ ++ if (!sps->frame_mbs_only_flag) ++ sps->mb_aff = get_bits1(gb); ++ else ++ sps->mb_aff = 0; ++ ++ if ((unsigned)sps->mb_width >= INT_MAX / 16 || ++ (unsigned)sps->mb_height >= INT_MAX / 16 || 0 ){ ++ //av_image_check_size(16 * sps->mb_width, ++ // 16 * sps->mb_height, 0, avctx)) { ++ av_log(avctx, AV_LOG_ERROR, "mb_width/height overflow\n"); ++ goto fail; ++ } ++ ++ sps->direct_8x8_inference_flag = get_bits1(gb); ++ ++#ifndef ALLOW_INTERLACE ++ if (sps->mb_aff) ++ av_log(avctx, AV_LOG_ERROR, ++ "MBAFF support not included; enable it at compile-time.\n"); ++#endif ++ sps->crop = get_bits1(gb); ++ if (sps->crop) { ++ unsigned int crop_left = get_ue_golomb(gb); ++ unsigned int crop_right = get_ue_golomb(gb); ++ unsigned int crop_top = get_ue_golomb(gb); ++ unsigned int crop_bottom = get_ue_golomb(gb); ++ int width = 16 * sps->mb_width; ++ int height = 16 * sps->mb_height; ++ ++ if (avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) { ++ av_log(avctx, AV_LOG_DEBUG, "discarding sps cropping, original " ++ "values are l:%d r:%d t:%d b:%d\n", ++ crop_left, crop_right, crop_top, crop_bottom); ++ ++ sps->crop_left = ++ sps->crop_right = ++ sps->crop_top = ++ sps->crop_bottom = 0; ++ } else { ++ int vsub = (sps->chroma_format_idc == 1) ? 1 : 0; ++ int hsub = (sps->chroma_format_idc == 1 || ++ sps->chroma_format_idc == 2) ? 1 : 0; ++ int step_x = 1 << hsub; ++ int step_y = (2 - sps->frame_mbs_only_flag) << vsub; ++ ++ if (crop_left > (unsigned)INT_MAX / 4 / step_x || ++ crop_right > (unsigned)INT_MAX / 4 / step_x || ++ crop_top > (unsigned)INT_MAX / 4 / step_y || ++ crop_bottom> (unsigned)INT_MAX / 4 / step_y || ++ (crop_left + crop_right ) * step_x >= width || ++ (crop_top + crop_bottom) * step_y >= height ++ ) { ++ av_log(avctx, AV_LOG_ERROR, "crop values invalid %d %d %d %d / %d %d\n", crop_left, crop_right, crop_top, crop_bottom, width, height); ++ goto fail; ++ } ++ ++ sps->crop_left = crop_left * step_x; ++ sps->crop_right = crop_right * step_x; ++ sps->crop_top = crop_top * step_y; ++ sps->crop_bottom = crop_bottom * step_y; ++ } ++ } else { ++ sps->crop_left = ++ sps->crop_right = ++ sps->crop_top = ++ sps->crop_bottom = ++ sps->crop = 0; ++ } ++ ++ sps->vui_parameters_present_flag = get_bits1(gb); ++ if (sps->vui_parameters_present_flag) { ++ int ret = decode_vui_parameters(gb, avctx, sps); ++ if (ret < 0) ++ goto fail; ++ } ++ ++ if (get_bits_left(gb) < 0) { ++ av_log(avctx, ignore_truncation ? AV_LOG_WARNING : AV_LOG_ERROR, ++ "Overread %s by %d bits\n", sps->vui_parameters_present_flag ? "VUI" : "SPS", -get_bits_left(gb)); ++ if (!ignore_truncation) ++ goto fail; ++ } ++ ++ /* if the maximum delay is not stored in the SPS, derive it based on the ++ * level */ ++ if (!sps->bitstream_restriction_flag && ++ (sps->ref_frame_count /*|| avctx->strict_std_compliance >= FF_COMPLIANCE_STRICT*/)) { ++ sps->num_reorder_frames = MAX_DELAYED_PIC_COUNT - 1; ++ for (i = 0; i < FF_ARRAY_ELEMS(level_max_dpb_mbs); i++) { ++ if (level_max_dpb_mbs[i][0] == sps->level_idc) { ++ sps->num_reorder_frames = FFMIN(level_max_dpb_mbs[i][1] / (sps->mb_width * sps->mb_height), ++ sps->num_reorder_frames); ++ break; ++ } ++ } ++ } ++ ++ if (!sps->sar.den) ++ sps->sar.den = 1; ++ ++ if (avctx->debug & FF_DEBUG_PICT_INFO) { ++ static const char csp[4][5] = { "Gray", "420", "422", "444" }; ++ av_log(avctx, AV_LOG_DEBUG, ++ "sps:%u profile:%d/%d poc:%d ref:%d %dx%d %s %s crop:%u/%u/%u/%u %s %s %d/%d b%d reo:%d\n", ++ sps_id, sps->profile_idc, sps->level_idc, ++ sps->poc_type, ++ sps->ref_frame_count, ++ sps->mb_width, sps->mb_height, ++ sps->frame_mbs_only_flag ? "FRM" : (sps->mb_aff ? "MB-AFF" : "PIC-AFF"), ++ sps->direct_8x8_inference_flag ? "8B8" : "", ++ sps->crop_left, sps->crop_right, ++ sps->crop_top, sps->crop_bottom, ++ sps->vui_parameters_present_flag ? "VUI" : "", ++ csp[sps->chroma_format_idc], ++ sps->timing_info_present_flag ? sps->num_units_in_tick : 0, ++ sps->timing_info_present_flag ? sps->time_scale : 0, ++ sps->bit_depth_luma, ++ sps->bitstream_restriction_flag ? sps->num_reorder_frames : -1 ++ ); ++ } ++ ++ return 0; ++ ++fail: ++ return AVERROR_INVALIDDATA; ++} ++ ++#if 0 ++static void init_dequant8_coeff_table(PPS *pps, const SPS *sps) ++{ ++ int i, j, q, x; ++ const int max_qp = 51 + 6 * (sps->bit_depth_luma - 8); ++ ++ for (i = 0; i < 6; i++) { ++ pps->dequant8_coeff[i] = pps->dequant8_buffer[i]; ++ for (j = 0; j < i; j++) ++ if (!memcmp(pps->scaling_matrix8[j], pps->scaling_matrix8[i], ++ 64 * sizeof(uint8_t))) { ++ pps->dequant8_coeff[i] = pps->dequant8_buffer[j]; ++ break; ++ } ++ if (j < i) ++ continue; ++ ++ for (q = 0; q < max_qp + 1; q++) { ++ int shift = ff_h264_quant_div6[q]; ++ int idx = ff_h264_quant_rem6[q]; ++ for (x = 0; x < 64; x++) ++ pps->dequant8_coeff[i][q][(x >> 3) | ((x & 7) << 3)] = ++ ((uint32_t)ff_h264_dequant8_coeff_init[idx][ff_h264_dequant8_coeff_init_scan[((x >> 1) & 12) | (x & 3)]] * ++ pps->scaling_matrix8[i][x]) << shift; ++ } ++ } ++} ++ ++static void init_dequant4_coeff_table(PPS *pps, const SPS *sps) ++{ ++ int i, j, q, x; ++ const int max_qp = 51 + 6 * (sps->bit_depth_luma - 8); ++ for (i = 0; i < 6; i++) { ++ pps->dequant4_coeff[i] = pps->dequant4_buffer[i]; ++ for (j = 0; j < i; j++) ++ if (!memcmp(pps->scaling_matrix4[j], pps->scaling_matrix4[i], ++ 16 * sizeof(uint8_t))) { ++ pps->dequant4_coeff[i] = pps->dequant4_buffer[j]; ++ break; ++ } ++ if (j < i) ++ continue; ++ ++ for (q = 0; q < max_qp + 1; q++) { ++ int shift = ff_h264_quant_div6[q] + 2; ++ int idx = ff_h264_quant_rem6[q]; ++ for (x = 0; x < 16; x++) ++ pps->dequant4_coeff[i][q][(x >> 2) | ((x << 2) & 0xF)] = ++ ((uint32_t)ff_h264_dequant4_coeff_init[idx][(x & 1) + ((x >> 2) & 1)] * ++ pps->scaling_matrix4[i][x]) << shift; ++ } ++ } ++} ++ ++static void init_dequant_tables(PPS *pps, const SPS *sps) ++{ ++ int i, x; ++ init_dequant4_coeff_table(pps, sps); ++ memset(pps->dequant8_coeff, 0, sizeof(pps->dequant8_coeff)); ++ ++ if (pps->transform_8x8_mode) ++ init_dequant8_coeff_table(pps, sps); ++ if (sps->transform_bypass) { ++ for (i = 0; i < 6; i++) ++ for (x = 0; x < 16; x++) ++ pps->dequant4_coeff[i][0][x] = 1 << 6; ++ if (pps->transform_8x8_mode) ++ for (i = 0; i < 6; i++) ++ for (x = 0; x < 64; x++) ++ pps->dequant8_coeff[i][0][x] = 1 << 6; ++ } ++} ++#endif ++static void build_qp_table(PPS *pps, int t, int index, const int depth) ++{ ++ int i; ++ const int max_qp = 51 + 6 * (depth - 8); ++ for (i = 0; i < max_qp + 1; i++) ++ pps->chroma_qp_table[t][i] = ++ ff_h264_chroma_qp[depth - 8][av_clip(i + index, 0, max_qp)]; ++} ++ ++static int more_rbsp_data_in_pps(const SPS *sps, void *logctx) ++{ ++ int profile_idc = sps->profile_idc; ++ ++ if ((profile_idc == 66 || profile_idc == 77 || ++ profile_idc == 88) && (sps->constraint_set_flags & 7)) { ++ av_log(logctx, AV_LOG_VERBOSE, ++ "Current profile doesn't provide more RBSP data in PPS, skipping\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avctx, ++ H264ParamSets *ps, int bit_length) ++{ ++ const SPS *sps; ++ unsigned int pps_id = get_ue_golomb(gb); ++ PPS *pps; ++ int qp_bd_offset; ++ int bits_left; ++ int ret; ++ ++ if (pps_id >= MAX_PPS_COUNT) { ++ av_log(avctx, AV_LOG_ERROR, "pps_id %u out of range\n", pps_id); ++ return AVERROR_INVALIDDATA; ++ } ++ ++ pps = &ps->pps_list[pps_id]; ++ ++ ++ pps->sps_id = get_ue_golomb_31(gb); ++ if ((unsigned)pps->sps_id >= MAX_SPS_COUNT || ++ !&ps->sps_list[pps->sps_id]) { ++ av_log(avctx, AV_LOG_ERROR, "sps_id %u out of range, max: %u\n", pps->sps_id, MAX_SPS_COUNT); ++ ret = AVERROR_INVALIDDATA; ++ goto fail; ++ } ++ sps = &ps->sps_list[pps->sps_id]; ++ ++ if (sps->bit_depth_luma > 14) { ++ av_log(avctx, AV_LOG_ERROR, ++ "Invalid luma bit depth=%d\n", ++ sps->bit_depth_luma); ++ ret = AVERROR_INVALIDDATA; ++ goto fail; ++ } else if (sps->bit_depth_luma == 11 || sps->bit_depth_luma == 13) { ++ av_log(avctx, AV_LOG_ERROR, ++ "Unimplemented luma bit depth=%d", ++ sps->bit_depth_luma); ++ ret = AVERROR_PATCHWELCOME; ++ goto fail; ++ } ++ ++ pps->cabac = get_bits1(gb); ++ pps->pic_order_present = get_bits1(gb); ++ pps->slice_group_count = get_ue_golomb(gb) + 1; ++ if (pps->slice_group_count > 1) { ++ pps->mb_slice_group_map_type = get_ue_golomb(gb); ++ av_log(avctx, AV_LOG_ERROR, "FMO not supported\n"); ++ } ++ pps->ref_count[0] = get_ue_golomb(gb) + 1; ++ pps->ref_count[1] = get_ue_golomb(gb) + 1; ++ if (pps->ref_count[0] - 1 > 32 - 1 || pps->ref_count[1] - 1 > 32 - 1) { ++ av_log(avctx, AV_LOG_ERROR, "reference overflow (pps)\n"); ++ ret = AVERROR_INVALIDDATA; ++ goto fail; ++ } ++ ++ qp_bd_offset = 6 * (sps->bit_depth_luma - 8); ++ ++ pps->weighted_pred = get_bits1(gb); ++ pps->weighted_bipred_idc = get_bits(gb, 2); ++ pps->init_qp = get_se_golomb(gb) + 26U + qp_bd_offset; ++ pps->init_qs = get_se_golomb(gb) + 26U + qp_bd_offset; ++ pps->chroma_qp_index_offset[0] = get_se_golomb(gb); ++ if (pps->chroma_qp_index_offset[0] < -12 || pps->chroma_qp_index_offset[0] > 12) { ++ ret = AVERROR_INVALIDDATA; ++ goto fail; ++ } ++ ++ pps->deblocking_filter_parameters_present = get_bits1(gb); ++ pps->constrained_intra_pred = get_bits1(gb); ++ pps->redundant_pic_cnt_present = get_bits1(gb); ++ ++ pps->transform_8x8_mode = 0; ++ memcpy(pps->scaling_matrix4, sps->scaling_matrix4, ++ sizeof(pps->scaling_matrix4)); ++ memcpy(pps->scaling_matrix8, sps->scaling_matrix8, ++ sizeof(pps->scaling_matrix8)); ++ ++ bits_left = bit_length - get_bits_count(gb); ++ if (bits_left > 0 && more_rbsp_data_in_pps(sps, avctx)) { ++ pps->transform_8x8_mode = get_bits1(gb); ++ ret = decode_scaling_matrices(gb, sps, pps, 0, ++ pps->scaling_matrix4, pps->scaling_matrix8); ++ if (ret < 0) ++ goto fail; ++ // second_chroma_qp_index_offset ++ pps->chroma_qp_index_offset[1] = get_se_golomb(gb); ++ if (pps->chroma_qp_index_offset[1] < -12 || pps->chroma_qp_index_offset[1] > 12) { ++ ret = AVERROR_INVALIDDATA; ++ goto fail; ++ } ++ } else { ++ pps->chroma_qp_index_offset[1] = pps->chroma_qp_index_offset[0]; ++ } ++ ++ build_qp_table(pps, 0, pps->chroma_qp_index_offset[0], ++ sps->bit_depth_luma); ++ build_qp_table(pps, 1, pps->chroma_qp_index_offset[1], ++ sps->bit_depth_luma); ++ ++ //init_dequant_tables(pps, sps); ++ ++ if (pps->chroma_qp_index_offset[0] != pps->chroma_qp_index_offset[1]) ++ pps->chroma_qp_diff = 1; ++ ++ if (avctx->debug & FF_DEBUG_PICT_INFO) { ++ av_log(avctx, AV_LOG_DEBUG, ++ "pps:%u sps:%u %s slice_groups:%d ref:%u/%u %s qp:%d/%d/%d/%d %s %s %s %s\n", ++ pps_id, pps->sps_id, ++ pps->cabac ? "CABAC" : "CAVLC", ++ pps->slice_group_count, ++ pps->ref_count[0], pps->ref_count[1], ++ pps->weighted_pred ? "weighted" : "", ++ pps->init_qp, pps->init_qs, pps->chroma_qp_index_offset[0], pps->chroma_qp_index_offset[1], ++ pps->deblocking_filter_parameters_present ? "LPAR" : "", ++ pps->constrained_intra_pred ? "CONSTR" : "", ++ pps->redundant_pic_cnt_present ? "REDU" : "", ++ pps->transform_8x8_mode ? "8x8DCT" : ""); ++ } ++ ++ return 0; ++ ++fail: ++ return ret; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_refs.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_refs.c +new file mode 100644 +index 000000000..39cff53d4 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_refs.c +@@ -0,0 +1,948 @@ ++#ifdef __KERNEL__ ++#else ++#include ++#endif ++ ++#include "avassert.h" ++#include "avcodec.h" ++#include "h264.h" ++#include "h264dec.h" ++#include "golomb.h" ++#include "mpegutils.h" ++ ++ ++static void pic_as_field(H264Ref *pic, const int parity) ++{ ++ int i; ++ for (i = 0; i < FF_ARRAY_ELEMS(pic->data); ++i) { ++ if (parity == PICT_BOTTOM_FIELD) ++ pic->data[i] += pic->linesize[i]; ++ pic->reference = parity; ++ pic->linesize[i] *= 2; ++ } ++ pic->poc = pic->parent->field_poc[parity == PICT_BOTTOM_FIELD]; ++} ++ ++static void ref_from_h264pic(H264Ref *dst, H264Picture *src) ++{ ++ memcpy(dst->data, src->f->data, sizeof(dst->data)); ++ memcpy(dst->linesize, src->f->linesize, sizeof(dst->linesize)); ++ dst->reference = src->reference; ++ dst->poc = src->poc; ++ dst->pic_id = src->pic_id; ++ dst->parent = src; ++} ++ ++static int split_field_copy(H264Ref *dest, H264Picture *src, int parity, int id_add) ++{ ++ int match = !!(src->reference & parity); ++ ++ if (match) { ++ ref_from_h264pic(dest, src); ++ if (parity != PICT_FRAME) { ++ pic_as_field(dest, parity); ++ dest->pic_id *= 2; ++ dest->pic_id += id_add; ++ } ++ } ++ ++ return match; ++} ++ ++static int build_def_list(H264Ref *def, int def_len, ++ H264Picture * const *in, int len, int is_long, int sel) ++{ ++ int i[2] = { 0 }; ++ int index = 0; ++ ++ while (i[0] < len || i[1] < len) { ++ ++ /*直到 创建的个数大于len? 或者in[]picture存在并且 两个的帧类型相åŒ?*/ ++ while (i[0] < len && !(in[i[0]] && (in[i[0]]->reference & sel))) ++ i[0]++; ++ while (i[1] < len && !(in[i[1]] && (in[i[1]]->reference & (sel ^ 3)))) ++ i[1]++; ++ if (i[0] < len) { ++ av_assert0(index < def_len); ++ in[i[0]]->pic_id = is_long ? i[0] : in[i[0]]->frame_num; ++ split_field_copy(&def[index++], in[i[0]++], sel, 1); ++ } ++ if (i[1] < len) { ++ av_assert0(index < def_len); ++ in[i[1]]->pic_id = is_long ? i[1] : in[i[1]]->frame_num; ++ split_field_copy(&def[index++], in[i[1]++], sel ^ 3, 0); ++ } ++ } ++ ++ return index; ++} ++ ++static int add_sorted(H264Picture **sorted, H264Picture * const *src, ++ int len, int limit, int dir) ++{ ++ int i, best_poc; ++ int out_i = 0; ++ ++ for (;;) { ++ best_poc = dir ? INT_MIN : INT_MAX; ++ ++ for (i = 0; i < len; i++) { ++ const int poc = src[i]->poc; ++ if (((poc > limit) ^ dir) && ((poc < best_poc) ^ dir)) { ++ best_poc = poc; ++ sorted[out_i] = src[i]; ++ } ++ } ++ if (best_poc == (dir ? INT_MIN : INT_MAX)) ++ break; ++ limit = sorted[out_i++]->poc - dir; ++ } ++ return out_i; ++} ++ ++static int mismatches_ref(const H264Context *h, const H264Picture *pic) ++{ ++ const AVFrame *f = pic->f; ++ return (h->cur_pic_ptr->f->width != f->width || ++ h->cur_pic_ptr->f->height != f->height || ++ h->cur_pic_ptr->f->format != f->format); ++} ++ ++static void h264_initialise_ref_list(H264Context *h, H264SliceContext *sl) ++{ ++ int i, len; ++ int j; ++ ++ if (sl->slice_type_nos == AV_PICTURE_TYPE_B) { ++ H264Picture *sorted[32]; ++ int cur_poc, list; ++ int lens[2]; ++ ++ /*mbaff å³å¸§åœºå®å—自适应。*/ ++ /*如果时场图片,*/ ++ if (FIELD_PICTURE(h)) ++ cur_poc = h->cur_pic_ptr->field_poc[h->picture_structure == PICT_BOTTOM_FIELD]; ++ else ++ cur_poc = h->cur_pic_ptr->poc; ++ ++ /* ++ * 两个链表 ++ * list0 是å‰å‘预测 ++ * list1 是åŽå‘预测 åªæœ‰B帧æ‰ä¼šæœ‰list1。 ++ * ++ * æ ¹æ®pic_order_countæ¥è®¡ç®—??? ++ * ++ * */ ++ for (list = 0; list < 2; list++) { ++ len = add_sorted(sorted, h->short_ref, h->short_ref_count, cur_poc, 1 ^ list); ++ len += add_sorted(sorted + len, h->short_ref, h->short_ref_count, cur_poc, 0 ^ list); ++ av_assert0(len <= 32); ++ ++ /*构建短的å‚考列表*/ ++ len = build_def_list(sl->ref_list[list], FF_ARRAY_ELEMS(sl->ref_list[0]), ++ sorted, len, 0, h->picture_structure); ++ /*é•¿å‚考*/ ++ len += build_def_list(sl->ref_list[list] + len, ++ FF_ARRAY_ELEMS(sl->ref_list[0]) - len, ++ h->long_ref, 16, 1, h->picture_structure); ++ av_assert0(len <= 32); ++ ++ if (len < sl->ref_count[list]) ++ memset(&sl->ref_list[list][len], 0, sizeof(H264Ref) * (sl->ref_count[list] - len)); ++ lens[list] = len; ++ } ++ ++ if (lens[0] == lens[1] && lens[1] > 1) { ++ for (i = 0; i < lens[0] && ++ sl->ref_list[0][i].parent->f->buf[0]->buffer == ++ sl->ref_list[1][i].parent->f->buf[0]->buffer; i++); ++ if (i == lens[0]) { ++ FFSWAP(H264Ref, sl->ref_list[1][0], sl->ref_list[1][1]); ++ } ++ } ++ } else { ++ /* 构建默认的 ref_list[0] 的短å‚考帧*/ ++ /*ref_list 是最终ç»è¿‡æŽ’åºçš„å‚考列表, 短期å‚考帧和长期å‚考帧. */ ++ /* 这里h->short_ref_countå¯èƒ½ä¸º0,比如当å‰slice是IDR帧, 或者mmco_reset è¦æ±‚å¤ä½å‚考列表时. ++ * ++ * 这里的short_ref与long_ref对应的是截至到上一帧,被用于标记的å‚考帧内容. ++ * è¿™é‡Œä¸»è¦æ˜¯è¦å°†short_ref放入到ref_list当中. 为什么ä¸èƒ½ç›´æŽ¥æ”¾å…¥å‘¢ï¼Ÿï¼Ÿï¼Ÿï¼Ÿï¼Ÿï¼Ÿ ++ * ++ * */ ++ len = build_def_list(sl->ref_list[0], FF_ARRAY_ELEMS(sl->ref_list[0]), ++ h->short_ref, h->short_ref_count, 0, h->picture_structure); ++ ++ /*é•¿å‚考*/ ++ len += build_def_list(sl->ref_list[0] + len, ++ FF_ARRAY_ELEMS(sl->ref_list[0]) - len, ++ h-> long_ref, 16, 1, h->picture_structure); ++ av_assert0(len <= 32); ++ ++ /*如果构建的长度大于解æžå‡ºæ¥çš„ref_count, å°†len到ref_count的内容清零:====》 ä¸è¦äº†å—???*/ ++ /*å‚è€ƒåˆ—è¡¨ä¸­å‰©ä½™çš„ä¿¡æ¯æ¸…é›¶.*/ ++ ++ if (len < sl->ref_count[0]) ++ memset(&sl->ref_list[0][len], 0, sizeof(H264Ref) * (sl->ref_count[0] - len)); ++ } ++#ifdef TRACE ++ for (i = 0; i < sl->ref_count[0]; i++) { ++ ff_tlog(h->avctx, "List0: %s fn:%d 0x%p\n", ++ (sl->ref_list[0][i].parent ? (sl->ref_list[0][i].parent->long_ref ? "LT" : "ST") : "??"), ++ sl->ref_list[0][i].pic_id, ++ sl->ref_list[0][i].data[0]); ++ } ++ if (sl->slice_type_nos == AV_PICTURE_TYPE_B) { ++ for (i = 0; i < sl->ref_count[1]; i++) { ++ ff_tlog(h->avctx, "List1: %s fn:%d 0x%p\n", ++ (sl->ref_list[1][i].parent ? (sl->ref_list[1][i].parent->long_ref ? "LT" : "ST") : "??"), ++ sl->ref_list[1][i].pic_id, ++ sl->ref_list[1][i].data[0]); ++ } ++ } ++#endif ++ ++ for (j = 0; j<1+(sl->slice_type_nos == AV_PICTURE_TYPE_B); j++) { ++ for (i = 0; i < sl->ref_count[j]; i++) { ++ if (sl->ref_list[j][i].parent) { ++ if (mismatches_ref(h, sl->ref_list[j][i].parent)) { ++ av_log(h->avctx, AV_LOG_ERROR, "Discarding mismatching reference\n"); ++ memset(&sl->ref_list[j][i], 0, sizeof(sl->ref_list[j][i])); ++ } ++ } ++ } ++ } ++ /*默认å‚考0å—???*/ ++ for (i = 0; i < sl->list_count; i++) ++ h->default_ref[i] = sl->ref_list[i][0]; ++} ++ ++/** ++ * print short term list ++ */ ++static void print_short_term(const H264Context *h) ++{ ++ uint32_t i; ++ if (h->avctx->debug & FF_DEBUG_MMCO) { ++ av_log(h->avctx, AV_LOG_DEBUG, "short term list:\n"); ++ for (i = 0; i < h->short_ref_count; i++) { ++ H264Picture *pic = h->short_ref[i]; ++ av_log(h->avctx, AV_LOG_DEBUG, "%u fn:%d poc:%d %p\n", ++ i, pic->frame_num, pic->poc, pic->f->data[0]); ++ } ++ } ++} ++ ++/** ++ * print long term list ++ */ ++static void print_long_term(const H264Context *h) ++{ ++ uint32_t i; ++ if (h->avctx->debug & FF_DEBUG_MMCO) { ++ av_log(h->avctx, AV_LOG_DEBUG, "long term list:\n"); ++ for (i = 0; i < 16; i++) { ++ H264Picture *pic = h->long_ref[i]; ++ if (pic) { ++ av_log(h->avctx, AV_LOG_DEBUG, "%u fn:%d poc:%d %p\n", ++ i, pic->frame_num, pic->poc, pic->f->data[0]); ++ } ++ } ++ } ++} ++ ++/** ++ * Extract structure information about the picture described by pic_num in ++ * the current decoding context (frame or field). Note that pic_num is ++ * picture number without wrapping (so, 0<=pic_numpicture_structure; ++ ++ /* æå–的方法是 ++ * 如果当å‰å›¾ç‰‡ä¸ºåœºå›¾ç‰‡ï¼Œå¦‚æžœpic_numä¸ºå¶æ•° ---> 修改类型为 PICT_FIELD_XXX?? ++ * ++ * ++ * */ ++ if (FIELD_PICTURE(h)) { ++ if (!(pic_num & 1)) ++ /* opposite field */ ++ *structure ^= PICT_FRAME; ++ pic_num >>= 1; ++ } ++ ++ return pic_num; ++} ++ ++static void h264_fill_mbaff_ref_list(H264SliceContext *sl) ++{ ++ int list, i, j; ++ for (list = 0; list < sl->list_count; list++) { ++ for (i = 0; i < sl->ref_count[list]; i++) { ++ H264Ref *frame = &sl->ref_list[list][i]; ++ H264Ref *field = &sl->ref_list[list][16 + 2 * i]; ++ ++ field[0] = *frame; ++ ++ for (j = 0; j < 3; j++) ++ field[0].linesize[j] <<= 1; ++ field[0].reference = PICT_TOP_FIELD; ++ field[0].poc = field[0].parent->field_poc[0]; ++ ++ field[1] = field[0]; ++ ++ for (j = 0; j < 3; j++) ++ field[1].data[j] += frame->parent->f->linesize[j]; ++ field[1].reference = PICT_BOTTOM_FIELD; ++ field[1].poc = field[1].parent->field_poc[1]; ++ } ++ } ++} ++ ++int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) ++{ ++ int list, index, pic_structure; ++ ++ print_short_term(h); ++ print_long_term(h); ++ ++ h264_initialise_ref_list(h, sl); ++ ++ for (list = 0; list < sl->list_count; list++) { ++ int pred = sl->curr_pic_num; // framenum ++ ++ /* æ ¹æ®slice_header里的list reordering è¯­æ³•ï¼Œé‡æŽ’åº??*/ ++ for (index = 0; index < sl->nb_ref_modifications[list]; index++) { ++ /*循环迭代,指导modification_of_pic_nums_idc == 3*/ ++ unsigned int modification_of_pic_nums_idc = sl->ref_modifications[list][index].op; ++ unsigned int val = sl->ref_modifications[list][index].val; ++ unsigned int pic_id; ++ int i; ++ H264Picture *ref = NULL; ++ ++ switch (modification_of_pic_nums_idc) { ++ case 0: ++ case 1: { ++ ++ /* ++ * 0: 短期å‚è€ƒå¸§é‡æŽ’åºï¼Œ abs_diff_pic_num_minus1ä¼šå‡ºçŽ°åœ¨ç æµä¸­ï¼Œä»Žå½“å‰å›¾åƒçš„PicNumå‡åŽ» (abs_diff_pic_num_minus1 + 1) åŽæŒ‡æ˜Žéœ€è¦é‡æŽ’åºçš„图åƒã€‚ ++ * 1: 短期å‚è€ƒå¸§é‡æŽ’åºï¼Œ abs_diff_pic_num_minus1ä¼šå‡ºçŽ°åœ¨ç æµä¸­ï¼Œä»Žå½“å‰å›¾åƒçš„PicNum加上 (abs_diff_pic_num_minus1 + 1) åŽæŒ‡æ˜Žéœ€è¦é‡æŽ’åºçš„图åƒã€‚ ++ * 2: 长期å‚è€ƒå¸§é‡æŽ’åºï¼Œ long_term_pic_numä¼šå‡ºçŽ°åœ¨ç æµä¸­ï¼ŒæŒ‡æ˜Žéœ€è¦é‡æŽ’åºçš„图åƒã€‚ ++ * 3: 结æŸå¾ªçŽ¯ï¼Œé€€å‡ºé‡æŽ’åºæ“作。 ++ * ++ * */ ++ ++ const unsigned int abs_diff_pic_num = val + 1; ++ int frame_num; ++ ++ if (abs_diff_pic_num > sl->max_pic_num) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "abs_diff_pic_num overflow\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ ++ ++ if (modification_of_pic_nums_idc == 0) ++ pred -= abs_diff_pic_num; ++ else ++ pred += abs_diff_pic_num; ++ ++ /* pred å·²ç»ä¿®æ”¹ä¸ºéœ€è¦å†²æŽ’åºçš„图åƒäº†.. */ ++ ++ /* 指明需è¦é‡æŽ’åºçš„图åƒ. round(sl->max_pic_num) */ ++ pred &= sl->max_pic_num - 1; ++ ++ /*æ ¹æ®ä¿®æ”¹åŽçš„predæå–å…¶frame_num, 帧å·.*/ ++ frame_num = pic_num_extract(h, pred, &pic_structure); ++ ++ /*é历短期å‚考帧列表*/ ++ for (i = h->short_ref_count - 1; i >= 0; i--) { ++ ref = h->short_ref[i]; ++ assert(ref->reference); ++ assert(!ref->long_ref); ++ /*如果计算出æ¥çš„frame_num在短期å‚考列表中,并且??*/ ++ if (ref->frame_num == frame_num && ++ (ref->reference & pic_structure)) ++ break; ++ } ++ ++ /*如果i >=0, 说明在short_ref中存在frame_num了?, 修改å‚考帧的pic_id为计算出æ¥çš„pred.???? */ ++ ++ /*那么 ref->frame_num 什么时候修改呢??????? */ ++ ++ /* frame_num å’Œ pic_id 的关系.........??*/ ++ ++ /* 这里的pic_id ä¸ºä»€ä¹ˆåƒæ˜¯è®¡ç®—出æ¥çš„poc? ++ * æ›´æ–°å‚考列表的pic_id???? ++ * */ ++ if (i >= 0) ++ ref->pic_id = pred; ++ break; ++ } ++ case 2: { ++ int long_idx; ++ pic_id = val; // long_term_pic_idx ++ ++ long_idx = pic_num_extract(h, pic_id, &pic_structure); ++ ++ if (long_idx > 31U) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "long_term_pic_idx overflow\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ ref = h->long_ref[long_idx]; ++ assert(!(ref && !ref->reference)); ++ if (ref && (ref->reference & pic_structure)) { ++ ref->pic_id = pic_id; ++ assert(ref->long_ref); ++ i = 0; ++ } else { ++ i = -1; ++ } ++ break; ++ } ++ default: ++ av_assert0(0); ++ } ++ ++ if (i < 0) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "reference picture missing during reorder\n"); ++ memset(&sl->ref_list[list][index], 0, sizeof(sl->ref_list[0][0])); // FIXME ++ } else { ++ ++ /*é历 æ¯ä¸ªlist çš„ref_count, ref_countæ˜¯é€šè¿‡ç æµè§£æžå‡ºæ¥çš„....*/ ++ ++ for (i = index; i + 1 < sl->ref_count[list]; i++) { ++ ++ /*如果æŸä¸ªref_listçš„parent存在, parent是个什么鬼?干什么用的??*/ ++ ++ /* parent 应该时当å‰Ref所属的Pic????*/ ++ ++ /*ä¸çŸ¥é“为什么è¦parent。。。。*/ ++ /*å‚考列表中对应的图片与当å‰çš„ref一致.*/ ++ if (sl->ref_list[list][i].parent && ++ ref->long_ref == sl->ref_list[list][i].parent->long_ref && ++ ref->pic_id == sl->ref_list[list][i].pic_id) ++ break; ++ } ++ for (; i > index; i--) { ++ sl->ref_list[list][i] = sl->ref_list[list][i - 1]; ++ } ++ ++ /*填充修改ref_list的内容....*/ ++ /*将对应的图片放到ref_list中.*/ ++ ref_from_h264pic(&sl->ref_list[list][index], ref); ++ if (FIELD_PICTURE(h)) { ++ pic_as_field(&sl->ref_list[list][index], pic_structure); ++ } ++ } ++ } ++ } ++ ++ /*é历 ref_list, 有效性和default ref_list。???*/ ++ for (list = 0; list < sl->list_count; list++) { ++ for (index = 0; index < sl->ref_count[list]; index++) { ++ if ( !sl->ref_list[list][index].parent ++ || (!FIELD_PICTURE(h) && (sl->ref_list[list][index].reference&3) != 3)) { ++ int i; ++ av_log(h->avctx, AV_LOG_ERROR, "Missing reference picture, default is %d\n", h->default_ref[list].poc); ++ for (i = 0; i < FF_ARRAY_ELEMS(h->last_pocs); i++) ++ h->last_pocs[i] = INT_MIN; ++ if (h->default_ref[list].parent ++ && !(!FIELD_PICTURE(h) && (h->default_ref[list].reference&3) != 3)) ++ sl->ref_list[list][index] = h->default_ref[list]; ++ else ++ return -1; ++ } ++ // av_assert0(av_buffer_get_ref_count(sl->ref_list[list][index].parent->f->buf[0]) > 0); ++ } ++ } ++ ++ /*如果帧场自适应的,填充帧场自适应å‚考列表.*/ ++ if (FRAME_MBAFF(h)) ++ h264_fill_mbaff_ref_list(sl); ++ ++ return 0; ++} ++ ++int ff_h264_decode_ref_pic_list_reordering(H264SliceContext *sl, void *logctx) ++{ ++ int list, index; ++ ++ sl->nb_ref_modifications[0] = 0; ++ sl->nb_ref_modifications[1] = 0; ++ ++ for (list = 0; list < sl->list_count; list++) { ++ if (!get_bits1(&sl->gb)) // ref_pic_list_modification_flag_l[01] ++ continue; ++ ++ for (index = 0; ; index++) { ++ unsigned int op = get_ue_golomb_31(&sl->gb); ++ ++ if (op == 3) ++ break; ++ ++ if (index >= sl->ref_count[list]) { ++ av_log(logctx, AV_LOG_ERROR, "reference count overflow\n"); ++ return AVERROR_INVALIDDATA; ++ } else if (op > 2) { ++ av_log(logctx, AV_LOG_ERROR, ++ "illegal modification_of_pic_nums_idc %u\n", ++ op); ++ return AVERROR_INVALIDDATA; ++ } ++ sl->ref_modifications[list][index].val = get_ue_golomb_long(&sl->gb); ++ sl->ref_modifications[list][index].op = op; ++ sl->nb_ref_modifications[list]++; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * Mark a picture as no longer needed for reference. The refmask ++ * argument allows unreferencing of individual fields or the whole frame. ++ * If the picture becomes entirely unreferenced, but is being held for ++ * display purposes, it is marked as such. ++ * @param refmask mask of fields to unreference; the mask is bitwise ++ * anded with the reference marking of pic ++ * @return non-zero if pic becomes entirely unreferenced (except possibly ++ * for display purposes) zero if one of the fields remains in ++ * reference ++ */ ++static inline int unreference_pic(H264Context *h, H264Picture *pic, int refmask) ++{ ++ int i; ++ if (pic->reference &= refmask) { ++ return 0; ++ } else { ++ for(i = 0; h->delayed_pic[i]; i++) ++ if(pic == h->delayed_pic[i]){ ++ pic->reference = DELAYED_PIC_REF; ++ break; ++ } ++ return 1; ++ } ++} ++ ++/** ++ * Find a H264Picture in the short term reference list by frame number. ++ * @param frame_num frame number to search for ++ * @param idx the index into h->short_ref where returned picture is found ++ * undefined if no picture found. ++ * @return pointer to the found picture, or NULL if no pic with the provided ++ * frame number is found ++ */ ++static H264Picture *find_short(H264Context *h, int frame_num, int *idx) ++{ ++ int i; ++ ++ for (i = 0; i < h->short_ref_count; i++) { ++ H264Picture *pic = h->short_ref[i]; ++ if (h->avctx->debug & FF_DEBUG_MMCO) ++ av_log(h->avctx, AV_LOG_DEBUG, "%d %d %p\n", i, pic->frame_num, pic); ++ if (pic->frame_num == frame_num) { ++ *idx = i; ++ return pic; ++ } ++ } ++ return NULL; ++} ++ ++/** ++ * Remove a picture from the short term reference list by its index in ++ * that list. This does no checking on the provided index; it is assumed ++ * to be valid. Other list entries are shifted down. ++ * @param i index into h->short_ref of picture to remove. ++ */ ++static void remove_short_at_index(H264Context *h, int i) ++{ ++ assert(i >= 0 && i < h->short_ref_count); ++ h->short_ref[i] = NULL; ++ if (--h->short_ref_count) ++ memmove(&h->short_ref[i], &h->short_ref[i + 1], ++ (h->short_ref_count - i) * sizeof(H264Picture*)); ++} ++ ++/** ++ * @return the removed picture or NULL if an error occurs ++ */ ++static H264Picture *remove_short(H264Context *h, int frame_num, int ref_mask) ++{ ++ H264Picture *pic; ++ int i; ++ ++ if (h->avctx->debug & FF_DEBUG_MMCO) ++ av_log(h->avctx, AV_LOG_DEBUG, "remove short %d count %d\n", frame_num, h->short_ref_count); ++ ++ pic = find_short(h, frame_num, &i); ++ if (pic) { ++ if (unreference_pic(h, pic, ref_mask)) ++ remove_short_at_index(h, i); ++ } ++ ++ return pic; ++} ++ ++/** ++ * Remove a picture from the long term reference list by its index in ++ * that list. ++ * @return the removed picture or NULL if an error occurs ++ */ ++static H264Picture *remove_long(H264Context *h, int i, int ref_mask) ++{ ++ H264Picture *pic; ++ ++ pic = h->long_ref[i]; ++ if (pic) { ++ if (unreference_pic(h, pic, ref_mask)) { ++ assert(h->long_ref[i]->long_ref == 1); ++ h->long_ref[i]->long_ref = 0; ++ h->long_ref[i] = NULL; ++ h->long_ref_count--; ++ } ++ } ++ ++ return pic; ++} ++ ++void ff_h264_remove_all_refs(H264Context *h) ++{ ++ int i; ++ ++ for (i = 0; i < 16; i++) { ++ remove_long(h, i, 0); ++ } ++ assert(h->long_ref_count == 0); ++ ++#if 0 ++ /*使用short_ref当中的第一帧作为错误æ¢å¤çš„图片. å…ˆä¸å¤„ç†. */ ++ if (h->short_ref_count && !h->last_pic_for_ec.f->data[0]) { ++ ff_h264_unref_picture(h, &h->last_pic_for_ec); ++ ff_h264_ref_picture(h, &h->last_pic_for_ec, h->short_ref[0]); ++ } ++#endif ++ ++ for (i = 0; i < h->short_ref_count; i++) { ++ unreference_pic(h, h->short_ref[i], 0); ++ h->short_ref[i] = NULL; ++ } ++ h->short_ref_count = 0; ++ ++ memset(h->default_ref, 0, sizeof(h->default_ref)); ++} ++ ++static void generate_sliding_window_mmcos(H264Context *h) ++{ ++ MMCO *mmco = h->mmco; ++ int nb_mmco = 0; ++ ++ if (h->short_ref_count && ++ h->long_ref_count + h->short_ref_count >= h->ps.sps->ref_frame_count && ++ !(FIELD_PICTURE(h) && !h->first_field && h->cur_pic_ptr->reference)) { ++ mmco[0].opcode = MMCO_SHORT2UNUSED; ++ mmco[0].short_pic_num = h->short_ref[h->short_ref_count - 1]->frame_num; ++ nb_mmco = 1; ++ if (FIELD_PICTURE(h)) { ++ mmco[0].short_pic_num *= 2; ++ mmco[1].opcode = MMCO_SHORT2UNUSED; ++ mmco[1].short_pic_num = mmco[0].short_pic_num + 1; ++ nb_mmco = 2; ++ } ++ } ++ ++ h->nb_mmco = nb_mmco; ++} ++ ++int ff_h264_execute_ref_pic_marking(H264Context *h) ++{ ++ MMCO *mmco = h->mmco; ++ int mmco_count; ++ int i, j; ++ int pps_ref_count[2] = {0}; ++ int current_ref_assigned = 0, err = 0; ++ H264Picture *pic; ++ ++ if (!h->ps.sps) { ++ av_log(h->avctx, AV_LOG_ERROR, "SPS is unset\n"); ++ err = AVERROR_INVALIDDATA; ++ goto out; ++ } ++ ++ /* è¦ä¹ˆä½¿ç”¨æ»‘åŠ¨çª—å£æ ‡è®°ï¼Œè¦ä¹ˆä½¿ç”¨ä¸Šé¢è§£ç å‡ºæ¥çš„mmco进行标记. */ ++ if (!h->explicit_ref_marking) ++ generate_sliding_window_mmcos(h); ++ mmco_count = h->nb_mmco; ++ ++ if ((h->avctx->debug & FF_DEBUG_MMCO) && mmco_count == 0) ++ av_log(h->avctx, AV_LOG_DEBUG, "no mmco here\n"); ++ ++ for (i = 0; i < mmco_count; i++) { ++ int structure, frame_num; ++ if (h->avctx->debug & FF_DEBUG_MMCO) ++ av_log(h->avctx, AV_LOG_DEBUG, "mmco:%d %d %d\n", h->mmco[i].opcode, ++ h->mmco[i].short_pic_num, h->mmco[i].long_arg); ++ ++ if (mmco[i].opcode == MMCO_SHORT2UNUSED || ++ mmco[i].opcode == MMCO_SHORT2LONG) { ++ frame_num = pic_num_extract(h, mmco[i].short_pic_num, &structure); ++ pic = find_short(h, frame_num, &j); ++ if (!pic) { ++ if (mmco[i].opcode != MMCO_SHORT2LONG || ++ !h->long_ref[mmco[i].long_arg] || ++ h->long_ref[mmco[i].long_arg]->frame_num != frame_num) { ++ av_log(h->avctx, h->short_ref_count ? AV_LOG_ERROR : AV_LOG_DEBUG, "mmco: unref short failure\n"); ++ err = AVERROR_INVALIDDATA; ++ } ++ continue; ++ } ++ } ++ ++ switch (mmco[i].opcode) { ++ case MMCO_SHORT2UNUSED: ++ if (h->avctx->debug & FF_DEBUG_MMCO) ++ av_log(h->avctx, AV_LOG_DEBUG, "mmco: unref short %d count %d\n", ++ h->mmco[i].short_pic_num, h->short_ref_count); ++ remove_short(h, frame_num, structure ^ PICT_FRAME); ++ break; ++ case MMCO_SHORT2LONG: ++ if (h->long_ref[mmco[i].long_arg] != pic) ++ remove_long(h, mmco[i].long_arg, 0); ++ ++ remove_short_at_index(h, j); ++ h->long_ref[ mmco[i].long_arg ] = pic; ++ if (h->long_ref[mmco[i].long_arg]) { ++ h->long_ref[mmco[i].long_arg]->long_ref = 1; ++ h->long_ref_count++; ++ } ++ break; ++ case MMCO_LONG2UNUSED: ++ j = pic_num_extract(h, mmco[i].long_arg, &structure); ++ pic = h->long_ref[j]; ++ if (pic) { ++ remove_long(h, j, structure ^ PICT_FRAME); ++ } else if (h->avctx->debug & FF_DEBUG_MMCO) ++ av_log(h->avctx, AV_LOG_DEBUG, "mmco: unref long failure\n"); ++ break; ++ case MMCO_LONG: ++ // Comment below left from previous code as it is an interesting note. ++ /* First field in pair is in short term list or ++ * at a different long term index. ++ * This is not allowed; see 7.4.3.3, notes 2 and 3. ++ * Report the problem and keep the pair where it is, ++ * and mark this field valid. ++ */ ++ if (h->short_ref[0] == h->cur_pic_ptr) { ++ av_log(h->avctx, AV_LOG_ERROR, "mmco: cannot assign current picture to short and long at the same time\n"); ++ remove_short_at_index(h, 0); ++ } ++ ++ /* make sure the current picture is not already assigned as a long ref */ ++ if (h->cur_pic_ptr->long_ref) { ++ for (j = 0; j < FF_ARRAY_ELEMS(h->long_ref); j++) { ++ if (h->long_ref[j] == h->cur_pic_ptr) { ++ if (j != mmco[i].long_arg) ++ av_log(h->avctx, AV_LOG_ERROR, "mmco: cannot assign current picture to 2 long term references\n"); ++ remove_long(h, j, 0); ++ } ++ } ++ } ++ ++ if (h->long_ref[mmco[i].long_arg] != h->cur_pic_ptr) { ++ av_assert0(!h->cur_pic_ptr->long_ref); ++ remove_long(h, mmco[i].long_arg, 0); ++ ++ h->long_ref[mmco[i].long_arg] = h->cur_pic_ptr; ++ h->long_ref[mmco[i].long_arg]->long_ref = 1; ++ h->long_ref_count++; ++ } ++ ++ h->cur_pic_ptr->reference |= h->picture_structure; ++ current_ref_assigned = 1; ++ break; ++ case MMCO_SET_MAX_LONG: ++ assert(mmco[i].long_arg <= 16); ++ // just remove the long term which index is greater than new max ++ for (j = mmco[i].long_arg; j < 16; j++) { ++ remove_long(h, j, 0); ++ } ++ break; ++ case MMCO_RESET: ++ while (h->short_ref_count) { ++ remove_short(h, h->short_ref[0]->frame_num, 0); ++ } ++ for (j = 0; j < 16; j++) { ++ remove_long(h, j, 0); ++ } ++ h->poc.frame_num = h->cur_pic_ptr->frame_num = 0; ++ h->mmco_reset = 1; ++ h->cur_pic_ptr->mmco_reset = 1; ++ for (j = 0; j < MAX_DELAYED_PIC_COUNT; j++) ++ h->last_pocs[j] = INT_MIN; ++ break; ++ default: assert(0); ++ } ++ } ++ ++ if (!current_ref_assigned) { ++ /* Second field of complementary field pair; the first field of ++ * which is already referenced. If short referenced, it ++ * should be first entry in short_ref. If not, it must exist ++ * in long_ref; trying to put it on the short list here is an ++ * error in the encoded bit stream (ref: 7.4.3.3, NOTE 2 and 3). ++ */ ++ if (h->short_ref_count && h->short_ref[0] == h->cur_pic_ptr) { ++ /* Just mark the second field valid */ ++ h->cur_pic_ptr->reference |= h->picture_structure; ++ } else if (h->cur_pic_ptr->long_ref) { ++ av_log(h->avctx, AV_LOG_ERROR, "illegal short term reference " ++ "assignment for second field " ++ "in complementary field pair " ++ "(first field is long term)\n"); ++ err = AVERROR_INVALIDDATA; ++ } else { ++ pic = remove_short(h, h->cur_pic_ptr->frame_num, 0); ++ if (pic) { ++ av_log(h->avctx, AV_LOG_ERROR, "illegal short term buffer state detected\n"); ++ err = AVERROR_INVALIDDATA; ++ } ++ ++ /*整体将short_refå¾€åŽç§»åŠ¨ä¸€ä¸ªå•å…ƒ, 将当å‰å›¾åƒæ”¾å…¥short_ref第一ä½*/ ++ if (h->short_ref_count) ++ memmove(&h->short_ref[1], &h->short_ref[0], ++ h->short_ref_count * sizeof(H264Picture*)); ++ ++ h->short_ref[0] = h->cur_pic_ptr; ++ h->short_ref_count++; ++ h->cur_pic_ptr->reference |= h->picture_structure; ++ } ++ } ++ ++ if (h->long_ref_count + h->short_ref_count > FFMAX(h->ps.sps->ref_frame_count, 1)) { ++ ++ /* We have too many reference frames, probably due to corrupted ++ * stream. Need to discard one frame. Prevents overrun of the ++ * short_ref and long_ref buffers. ++ */ ++ av_log(h->avctx, AV_LOG_ERROR, ++ "number of reference frames (%d+%d) exceeds max (%d; probably " ++ "corrupt input), discarding one\n", ++ h->long_ref_count, h->short_ref_count, h->ps.sps->ref_frame_count); ++ err = AVERROR_INVALIDDATA; ++ ++ if (h->long_ref_count && !h->short_ref_count) { ++ for (i = 0; i < 16; ++i) ++ if (h->long_ref[i]) ++ break; ++ ++ assert(i < 16); ++ remove_long(h, i, 0); ++ } else { ++ pic = h->short_ref[h->short_ref_count - 1]; ++ remove_short(h, pic->frame_num, 0); ++ } ++ } ++ ++ for (i = 0; ishort_ref_count; i++) { ++ pic = h->short_ref[i]; ++ if (pic->invalid_gap) { ++ int d = av_mod_uintp2(h->cur_pic_ptr->frame_num - pic->frame_num, h->ps.sps->log2_max_frame_num); ++ if (d > h->ps.sps->ref_frame_count) ++ remove_short(h, pic->frame_num, 0); ++ } ++ } ++ ++ print_short_term(h); ++ print_long_term(h); ++ ++ for (i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) { ++ if (&h->ps.pps_list[i]) { ++ const PPS *pps = &h->ps.pps_list[i]; ++ pps_ref_count[0] = FFMAX(pps_ref_count[0], pps->ref_count[0]); ++ pps_ref_count[1] = FFMAX(pps_ref_count[1], pps->ref_count[1]); ++ } ++ } ++ ++ // Detect unmarked random access points ++ if ( err >= 0 ++ && h->long_ref_count==0 ++ && ( h->short_ref_count<=2 ++ || pps_ref_count[0] <= 2 && pps_ref_count[1] <= 1 && h->avctx->has_b_frames ++ || pps_ref_count[0] <= 1 + (h->picture_structure != PICT_FRAME) && pps_ref_count[1] <= 1) ++ && pps_ref_count[0]<=2 + (h->picture_structure != PICT_FRAME) + (2*!h->has_recovery_point) ++ && h->cur_pic_ptr->f->pict_type == AV_PICTURE_TYPE_I){ ++ h->cur_pic_ptr->recovered |= 1; ++ if(!h->avctx->has_b_frames) ++ h->frame_recovered |= FRAME_RECOVERED_SEI; ++ } ++ ++out: ++ return (h->avctx->err_recognition & AV_EF_EXPLODE) ? err : 0; ++} ++ ++int ff_h264_decode_ref_pic_marking(H264SliceContext *sl, GetBitContext *gb, ++ const H2645NAL *nal, void *logctx) ++{ ++ int i; ++ MMCO *mmco = sl->mmco; ++ int nb_mmco = 0; ++ ++ if (nal->type == H264_NAL_IDR_SLICE) { // FIXME fields ++ skip_bits1(gb); // broken_link ++ if (get_bits1(gb)) { ++ mmco[0].opcode = MMCO_LONG; ++ mmco[0].long_arg = 0; ++ nb_mmco = 1; ++ } ++ sl->explicit_ref_marking = 1; ++ } else { ++ sl->explicit_ref_marking = get_bits1(gb); ++ if (sl->explicit_ref_marking) { ++ for (i = 0; i < MAX_MMCO_COUNT; i++) { ++ MMCOOpcode opcode = get_ue_golomb_31(gb); ++ ++ mmco[i].opcode = opcode; ++ if (opcode == MMCO_SHORT2UNUSED || opcode == MMCO_SHORT2LONG) { ++ mmco[i].short_pic_num = ++ (sl->curr_pic_num - get_ue_golomb_long(gb) - 1) & ++ (sl->max_pic_num - 1); ++ } ++ if (opcode == MMCO_SHORT2LONG || opcode == MMCO_LONG2UNUSED || ++ opcode == MMCO_LONG || opcode == MMCO_SET_MAX_LONG) { ++ unsigned int long_arg = get_ue_golomb_31(gb); ++ if (long_arg >= 32 || ++ (long_arg >= 16 && !(opcode == MMCO_SET_MAX_LONG && ++ long_arg == 16) && ++ !(opcode == MMCO_LONG2UNUSED && FIELD_PICTURE(sl)))) { ++ av_log(logctx, AV_LOG_ERROR, ++ "illegal long ref in memory management control " ++ "operation %d\n", opcode); ++ return -1; ++ } ++ mmco[i].long_arg = long_arg; ++ } ++ ++ if (opcode > (unsigned) MMCO_LONG) { ++ av_log(logctx, AV_LOG_ERROR, ++ "illegal memory management control operation %d\n", ++ opcode); ++ return -1; ++ } ++ if (opcode == MMCO_END) ++ break; ++ } ++ nb_mmco = i; ++ } ++ } ++ ++ sl->nb_mmco = nb_mmco; ++ ++ return 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_sei.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_sei.c +new file mode 100644 +index 000000000..3adc081b0 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_sei.c +@@ -0,0 +1,508 @@ ++#include "avcodec.h" ++#include "get_bits.h" ++#include "golomb.h" ++#include "h264_ps.h" ++#include "h264_sei.h" ++//#include "internal.h" ++ ++#define AVERROR_PS_NOT_FOUND FFERRTAG(0xF8,'?','P','S') ++ ++static const uint8_t sei_num_clock_ts_table[9] = { ++ 1, 1, 1, 2, 2, 3, 3, 2, 3 ++}; ++ ++void ff_h264_sei_uninit(H264SEIContext *h) ++{ ++ h->recovery_point.recovery_frame_cnt = -1; ++ ++ h->picture_timing.dpb_output_delay = 0; ++ h->picture_timing.cpb_removal_delay = -1; ++ ++ h->picture_timing.present = 0; ++ h->buffering_period.present = 0; ++ h->frame_packing.present = 0; ++ h->display_orientation.present = 0; ++ h->afd.present = 0; ++#if 0 ++ av_buffer_unref(&h->a53_caption.buf_ref); ++#endif ++} ++ ++static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb, ++ const H264ParamSets *ps, void *logctx) ++{ ++ int i; ++ const SPS *sps = ps->sps; ++ ++ for (i = 0; ilog2_max_frame_num) && &ps->sps_list[i]) ++ sps = &ps->sps_list[i]; ++ // sps = (const SPS *)ps->sps_list[i]->data; ++ ++ if (!sps) { ++ av_log(logctx, AV_LOG_ERROR, "SPS unavailable in decode_picture_timing\n"); ++ return AVERROR_PS_NOT_FOUND; ++ } ++ ++ if (sps->nal_hrd_parameters_present_flag || ++ sps->vcl_hrd_parameters_present_flag) { ++ h->cpb_removal_delay = get_bits_long(gb, sps->cpb_removal_delay_length); ++ h->dpb_output_delay = get_bits_long(gb, sps->dpb_output_delay_length); ++ } ++ if (sps->pic_struct_present_flag) { ++ unsigned int i, num_clock_ts; ++ ++ h->pic_struct = get_bits(gb, 4); ++ h->ct_type = 0; ++ ++ if (h->pic_struct > H264_SEI_PIC_STRUCT_FRAME_TRIPLING) ++ return AVERROR_INVALIDDATA; ++ ++ num_clock_ts = sei_num_clock_ts_table[h->pic_struct]; ++ h->timecode_cnt = 0; ++ for (i = 0; i < num_clock_ts; i++) { ++ if (get_bits(gb, 1)) { /* clock_timestamp_flag */ ++ H264SEITimeCode *tc = &h->timecode[h->timecode_cnt++]; ++ unsigned int full_timestamp_flag; ++ unsigned int counting_type, cnt_dropped_flag; ++ h->ct_type |= 1 << get_bits(gb, 2); ++ skip_bits(gb, 1); /* nuit_field_based_flag */ ++ counting_type = get_bits(gb, 5); /* counting_type */ ++ full_timestamp_flag = get_bits(gb, 1); ++ skip_bits(gb, 1); /* discontinuity_flag */ ++ cnt_dropped_flag = get_bits(gb, 1); /* cnt_dropped_flag */ ++ if (cnt_dropped_flag && counting_type > 1 && counting_type < 7) ++ tc->dropframe = 1; ++ tc->frame = get_bits(gb, 8); /* n_frames */ ++ if (full_timestamp_flag) { ++ tc->full = 1; ++ tc->seconds = get_bits(gb, 6); /* seconds_value 0..59 */ ++ tc->minutes = get_bits(gb, 6); /* minutes_value 0..59 */ ++ tc->hours = get_bits(gb, 5); /* hours_value 0..23 */ ++ } else { ++ tc->seconds = tc->minutes = tc->hours = tc->full = 0; ++ if (get_bits(gb, 1)) { /* seconds_flag */ ++ tc->seconds = get_bits(gb, 6); ++ if (get_bits(gb, 1)) { /* minutes_flag */ ++ tc->minutes = get_bits(gb, 6); ++ if (get_bits(gb, 1)) /* hours_flag */ ++ tc->hours = get_bits(gb, 5); ++ } ++ } ++ } ++ ++ if (sps->time_offset_length > 0) ++ skip_bits(gb, ++ sps->time_offset_length); /* time_offset */ ++ } ++ } ++ ++ av_log(logctx, AV_LOG_DEBUG, "ct_type:%X pic_struct:%d\n", ++ h->ct_type, h->pic_struct); ++ } ++ ++ h->present = 1; ++ return 0; ++} ++ ++static int decode_registered_user_data_afd(H264SEIAFD *h, GetBitContext *gb, int size) ++{ ++ int flag; ++ ++ if (size-- < 1) ++ return AVERROR_INVALIDDATA; ++ skip_bits(gb, 1); // 0 ++ flag = get_bits(gb, 1); // active_format_flag ++ skip_bits(gb, 6); // reserved ++ ++ if (flag) { ++ if (size-- < 1) ++ return AVERROR_INVALIDDATA; ++ skip_bits(gb, 4); // reserved ++ h->active_format_description = get_bits(gb, 4); ++ h->present = 1; ++ } ++ ++ return 0; ++} ++ ++static int decode_registered_user_data_closed_caption(H264SEIA53Caption *h, ++ GetBitContext *gb, void *logctx, ++ int size) ++{ ++ int flag; ++ int user_data_type_code; ++ int cc_count; ++ av_log(logctx, AV_LOG_ERROR, "TODO: not implemented: %d, %d\n", __func__, __LINE__); ++ ++ if (size < 3) ++ return AVERROR(EINVAL); ++ ++ user_data_type_code = get_bits(gb, 8); ++ if (user_data_type_code == 0x3) { ++ skip_bits(gb, 1); // reserved ++ ++ flag = get_bits(gb, 1); // process_cc_data_flag ++ if (flag) { ++ skip_bits(gb, 1); // zero bit ++ cc_count = get_bits(gb, 5); ++ skip_bits(gb, 8); // reserved ++ size -= 2; ++ ++ if (cc_count && size >= cc_count * 3) { ++#if 0 ++ int old_size = h->buf_ref ? h->buf_ref->size : 0; ++ const uint64_t new_size = (old_size + cc_count ++ * UINT64_C(3)); ++ int i, ret; ++ ++ if (new_size > INT_MAX) ++ return AVERROR(EINVAL); ++#endif ++#if 0 ++ /* Allow merging of the cc data from two fields. */ ++ ret = av_buffer_realloc(&h->buf_ref, new_size); ++ if (ret < 0) ++ return ret; ++ ++ /* Use of av_buffer_realloc assumes buffer is writeable */ ++ for (i = 0; i < cc_count; i++) { ++ h->buf_ref->data[old_size++] = get_bits(gb, 8); ++ h->buf_ref->data[old_size++] = get_bits(gb, 8); ++ h->buf_ref->data[old_size++] = get_bits(gb, 8); ++ } ++#else ++ int i; ++ for (i = 0; i < cc_count; i++) { ++ skip_bits(gb, 8); ++ skip_bits(gb, 8); ++ skip_bits(gb, 8); ++ } ++ ++#endif ++ skip_bits(gb, 8); // marker_bits ++ } ++ } ++ } else { ++ int i; ++ for (i = 0; i < size - 1; i++) ++ skip_bits(gb, 8); ++ } ++ return 0; ++} ++ ++static int decode_registered_user_data(H264SEIContext *h, GetBitContext *gb, ++ void *logctx, int size) ++{ ++ uint32_t country_code; ++ uint32_t user_identifier; ++ ++ if (size < 7) ++ return AVERROR_INVALIDDATA; ++ size -= 7; ++ ++ country_code = get_bits(gb, 8); // itu_t_t35_country_code ++ if (country_code == 0xFF) { ++ skip_bits(gb, 8); // itu_t_t35_country_code_extension_byte ++ size--; ++ } ++ ++ /* itu_t_t35_payload_byte follows */ ++ skip_bits(gb, 8); // terminal provider code ++ skip_bits(gb, 8); // terminal provider oriented code ++ user_identifier = get_bits_long(gb, 32); ++ ++ switch (user_identifier) { ++ case MKBETAG('D', 'T', 'G', '1'): // afd_data ++ return decode_registered_user_data_afd(&h->afd, gb, size); ++ case MKBETAG('G', 'A', '9', '4'): // closed captions ++ return decode_registered_user_data_closed_caption(&h->a53_caption, gb, ++ logctx, size); ++ default: ++ skip_bits(gb, size * 8); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int decode_unregistered_user_data(H264SEIUnregistered *h, GetBitContext *gb, ++ void *logctx, int size) ++{ ++ uint8_t *user_data; ++ int e, build, i; ++ ++ if (size < 16 || size >= INT_MAX - 16) ++ return AVERROR_INVALIDDATA; ++ ++ user_data = av_malloc(16 + size + 1); ++ if (!user_data) ++ return AVERROR(ENOMEM); ++ ++ for (i = 0; i < size + 16; i++) ++ user_data[i] = get_bits(gb, 8); ++ ++ user_data[i] = 0; ++ e = sscanf(user_data + 16, "x264 - core %d", &build); ++ if (e == 1 && build > 0) ++ h->x264_build = build; ++ if (e == 1 && build == 1 && !strncmp(user_data+16, "x264 - core 0000", 16)) ++ h->x264_build = 67; ++ ++ av_free(user_data); ++ return 0; ++} ++ ++static int decode_recovery_point(H264SEIRecoveryPoint *h, GetBitContext *gb, void *logctx) ++{ ++ unsigned recovery_frame_cnt = get_ue_golomb_long(gb); ++ ++ if (recovery_frame_cnt >= (1<recovery_frame_cnt = recovery_frame_cnt; ++ /* 1b exact_match_flag, ++ * 1b broken_link_flag, ++ * 2b changing_slice_group_idc */ ++ skip_bits(gb, 4); ++ ++ return 0; ++} ++ ++static int decode_buffering_period(H264SEIBufferingPeriod *h, GetBitContext *gb, ++ const H264ParamSets *ps, void *logctx) ++{ ++ unsigned int sps_id; ++ int sched_sel_idx; ++ const SPS *sps; ++ ++ sps_id = get_ue_golomb_31(gb); ++ if (sps_id > 31 || ! &ps->sps_list[sps_id]) { ++ av_log(logctx, AV_LOG_ERROR, ++ "non-existing SPS %d referenced in buffering period\n", sps_id); ++ return sps_id > 31 ? AVERROR_INVALIDDATA : AVERROR_PS_NOT_FOUND; ++ } ++ //sps = (const SPS*)ps->sps_list[sps_id]->data; ++ sps = &ps->sps_list[sps_id]; ++ ++ // NOTE: This is really so duplicated in the standard... See H.264, D.1.1 ++ if (sps->nal_hrd_parameters_present_flag) { ++ for (sched_sel_idx = 0; sched_sel_idx < sps->cpb_cnt; sched_sel_idx++) { ++ h->initial_cpb_removal_delay[sched_sel_idx] = ++ get_bits_long(gb, sps->initial_cpb_removal_delay_length); ++ // initial_cpb_removal_delay_offset ++ skip_bits(gb, sps->initial_cpb_removal_delay_length); ++ } ++ } ++ if (sps->vcl_hrd_parameters_present_flag) { ++ for (sched_sel_idx = 0; sched_sel_idx < sps->cpb_cnt; sched_sel_idx++) { ++ h->initial_cpb_removal_delay[sched_sel_idx] = ++ get_bits_long(gb, sps->initial_cpb_removal_delay_length); ++ // initial_cpb_removal_delay_offset ++ skip_bits(gb, sps->initial_cpb_removal_delay_length); ++ } ++ } ++ ++ h->present = 1; ++ return 0; ++} ++ ++static int decode_frame_packing_arrangement(H264SEIFramePacking *h, ++ GetBitContext *gb) ++{ ++ h->arrangement_id = get_ue_golomb_long(gb); ++ h->arrangement_cancel_flag = get_bits1(gb); ++ h->present = !h->arrangement_cancel_flag; ++ ++ if (h->present) { ++ h->arrangement_type = get_bits(gb, 7); ++ h->quincunx_sampling_flag = get_bits1(gb); ++ h->content_interpretation_type = get_bits(gb, 6); ++ ++ // spatial_flipping_flag, frame0_flipped_flag, field_views_flag ++ skip_bits(gb, 3); ++ h->current_frame_is_frame0_flag = get_bits1(gb); ++ // frame0_self_contained_flag, frame1_self_contained_flag ++ skip_bits(gb, 2); ++ ++ if (!h->quincunx_sampling_flag && h->arrangement_type != 5) ++ skip_bits(gb, 16); // frame[01]_grid_position_[xy] ++ skip_bits(gb, 8); // frame_packing_arrangement_reserved_byte ++ h->arrangement_repetition_period = get_ue_golomb_long(gb); ++ } ++ skip_bits1(gb); // frame_packing_arrangement_extension_flag ++ ++ return 0; ++} ++ ++static int decode_display_orientation(H264SEIDisplayOrientation *h, ++ GetBitContext *gb) ++{ ++ h->present = !get_bits1(gb); ++ ++ if (h->present) { ++ h->hflip = get_bits1(gb); // hor_flip ++ h->vflip = get_bits1(gb); // ver_flip ++ ++ h->anticlockwise_rotation = get_bits(gb, 16); ++ get_ue_golomb_long(gb); // display_orientation_repetition_period ++ skip_bits1(gb); // display_orientation_extension_flag ++ } ++ ++ return 0; ++} ++ ++static int decode_green_metadata(H264SEIGreenMetaData *h, GetBitContext *gb) ++{ ++ h->green_metadata_type = get_bits(gb, 8); ++ ++ if (h->green_metadata_type == 0) { ++ h->period_type = get_bits(gb, 8); ++ ++ if (h->period_type == 2) ++ h->num_seconds = get_bits(gb, 16); ++ else if (h->period_type == 3) ++ h->num_pictures = get_bits(gb, 16); ++ ++ h->percent_non_zero_macroblocks = get_bits(gb, 8); ++ h->percent_intra_coded_macroblocks = get_bits(gb, 8); ++ h->percent_six_tap_filtering = get_bits(gb, 8); ++ h->percent_alpha_point_deblocking_instance = get_bits(gb, 8); ++ ++ } else if (h->green_metadata_type == 1) { ++ h->xsd_metric_type = get_bits(gb, 8); ++ h->xsd_metric_value = get_bits(gb, 16); ++ } ++ ++ return 0; ++} ++ ++static int decode_alternative_transfer(H264SEIAlternativeTransfer *h, ++ GetBitContext *gb) ++{ ++ h->present = 1; ++ h->preferred_transfer_characteristics = get_bits(gb, 8); ++ return 0; ++} ++ ++int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, ++ const H264ParamSets *ps, void *logctx) ++{ ++ int master_ret = 0; ++ ++ while (get_bits_left(gb) > 16 && show_bits(gb, 16)) { ++ int type = 0; ++ unsigned size = 0; ++ unsigned next; ++ int ret = 0; ++ ++ do { ++ if (get_bits_left(gb) < 8) ++ return AVERROR_INVALIDDATA; ++ type += show_bits(gb, 8); ++ } while (get_bits(gb, 8) == 255); ++ ++ do { ++ if (get_bits_left(gb) < 8) ++ return AVERROR_INVALIDDATA; ++ size += show_bits(gb, 8); ++ } while (get_bits(gb, 8) == 255); ++ ++ if (size > get_bits_left(gb) / 8) { ++ av_log(logctx, AV_LOG_ERROR, "SEI type %d size %d truncated at %d\n", ++ type, 8*size, get_bits_left(gb)); ++ return AVERROR_INVALIDDATA; ++ } ++ next = get_bits_count(gb) + 8 * size; ++ ++ switch (type) { ++ case H264_SEI_TYPE_PIC_TIMING: // Picture timing SEI ++ ret = decode_picture_timing(&h->picture_timing, gb, ps, logctx); ++ break; ++ case H264_SEI_TYPE_USER_DATA_REGISTERED: ++ ret = decode_registered_user_data(h, gb, logctx, size); ++ break; ++ case H264_SEI_TYPE_USER_DATA_UNREGISTERED: ++ ret = decode_unregistered_user_data(&h->unregistered, gb, logctx, size); ++ break; ++ case H264_SEI_TYPE_RECOVERY_POINT: ++ ret = decode_recovery_point(&h->recovery_point, gb, logctx); ++ break; ++ case H264_SEI_TYPE_BUFFERING_PERIOD: ++ ret = decode_buffering_period(&h->buffering_period, gb, ps, logctx); ++ break; ++ case H264_SEI_TYPE_FRAME_PACKING: ++ ret = decode_frame_packing_arrangement(&h->frame_packing, gb); ++ break; ++ case H264_SEI_TYPE_DISPLAY_ORIENTATION: ++ ret = decode_display_orientation(&h->display_orientation, gb); ++ break; ++ case H264_SEI_TYPE_GREEN_METADATA: ++ ret = decode_green_metadata(&h->green_metadata, gb); ++ break; ++ case H264_SEI_TYPE_ALTERNATIVE_TRANSFER: ++ ret = decode_alternative_transfer(&h->alternative_transfer, gb); ++ break; ++ default: ++ av_log(logctx, AV_LOG_DEBUG, "unknown SEI type %d\n", type); ++ } ++ if (ret < 0 && ret != AVERROR_PS_NOT_FOUND) ++ return ret; ++ if (ret < 0) ++ master_ret = ret; ++ ++ skip_bits_long(gb, next - get_bits_count(gb)); ++ ++ // FIXME check bits here ++ align_get_bits(gb); ++ } ++ ++ return master_ret; ++} ++ ++const char *ff_h264_sei_stereo_mode(const H264SEIFramePacking *h) ++{ ++ if (h->arrangement_cancel_flag == 0) { ++ switch (h->arrangement_type) { ++ case H264_SEI_FPA_TYPE_CHECKERBOARD: ++ if (h->content_interpretation_type == 2) ++ return "checkerboard_rl"; ++ else ++ return "checkerboard_lr"; ++ case H264_SEI_FPA_TYPE_INTERLEAVE_COLUMN: ++ if (h->content_interpretation_type == 2) ++ return "col_interleaved_rl"; ++ else ++ return "col_interleaved_lr"; ++ case H264_SEI_FPA_TYPE_INTERLEAVE_ROW: ++ if (h->content_interpretation_type == 2) ++ return "row_interleaved_rl"; ++ else ++ return "row_interleaved_lr"; ++ case H264_SEI_FPA_TYPE_SIDE_BY_SIDE: ++ if (h->content_interpretation_type == 2) ++ return "right_left"; ++ else ++ return "left_right"; ++ case H264_SEI_FPA_TYPE_TOP_BOTTOM: ++ if (h->content_interpretation_type == 2) ++ return "bottom_top"; ++ else ++ return "top_bottom"; ++ case H264_SEI_FPA_TYPE_INTERLEAVE_TEMPORAL: ++ if (h->content_interpretation_type == 2) ++ return "block_rl"; ++ else ++ return "block_lr"; ++ case H264_SEI_FPA_TYPE_2D: ++ default: ++ return "mono"; ++ } ++ } else if (h->arrangement_cancel_flag == 1) { ++ return "mono"; ++ } else { ++ return NULL; ++ } ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_slice.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_slice.c +new file mode 100644 +index 000000000..c658fda5f +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264_slice.c +@@ -0,0 +1,1730 @@ ++#include ++#include "avassert.h" ++#include "avcodec.h" ++#include "h264.h" ++#include "h264dec.h" ++#include "h264data.h" ++#include "h264_ps.h" ++#include "golomb.h" ++#include "mathops.h" ++#include "mpegutils.h" ++#include "api/jzm_h264_dec.h" ++ ++void hexdump(unsigned char *buf, int len); ++ ++ ++static void release_picture(H264Context *h, H264Picture *pic) ++{ ++ if(!pic->f) ++ return; ++ ++ pic->f->data[0] = NULL; ++ pic->f->data[1] = NULL; ++ pic->f->linesize[0] = 0; ++ pic->f->linesize[1] = 0; ++ pic->f = NULL; ++ ++ av_buffer_free(&h->devmem_ctx, pic->frm_info_ctrl); ++ av_buffer_free(&h->devmem_ctx, pic->frm_info_mv); ++ if(h->format == VPU_FORMAT_NV12 || h->format == VPU_FORMAT_NV21) { ++ av_buffer_free(&h->devmem_ctx, pic->dec_result_y); ++ av_buffer_free(&h->devmem_ctx, pic->dec_result_uv); ++ } ++} ++ ++void ff_h264_release_picture(H264Context *h, H264Picture *pic) ++{ ++ release_picture(h, pic); ++} ++ ++static void release_unused_pictures(H264Context *h, int remove_current) ++{ ++ int i; ++ ++ /* release non reference frames */ ++ for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) { ++ //if (!h->DPB[i].inuse && !h->DPB[i].reference && ++ if (h->DPB[i].f && !h->DPB[i].reference && ++ (remove_current || &h->DPB[i] != h->cur_pic_ptr)) { ++ ++ release_picture(h, &h->DPB[i]); ++ ff_h264_unref_picture(h, &h->DPB[i]); ++ } ++ } ++} ++ ++static int alloc_picture(H264Context *h, H264Picture *pic) ++{ ++ int i, ret = 0; ++ AVFrame *f = NULL; ++ unsigned int mb_array_size = 0; ++ ++ f = list_first_entry_or_null(&h->queued_list, AVFrame, queued_entry); ++ if(!f) { ++ av_log(h->avctx, AV_LOG_ERROR, "cannot get AVframe from queued_list."); ++ return AVERROR(ENOMEM); ++ } ++ ++ f->data[0] = f->buf[0]->buffer; ++ f->data[1] = f->buf[1]->buffer; ++ f->linesize[0] = f->buf[0]->size; ++ f->linesize[1] = f->buf[1]->size; ++ ++ mb_array_size = h->mb_width * h->mb_height; ++ ++#define SDE_FMV_ADS (1 << 8) ++ pic->frm_info_ctrl = av_buffer_alloc(&h->devmem_ctx, mb_array_size * sizeof(unsigned int) * 2 + SDE_FMV_ADS); ++ if(!pic->frm_info_ctrl){ ++ av_log(NULL, AV_LOG_ERROR, "Failed to alloc frm_info_ctrl!\n"); ++ ret = AVERROR(ENOMEM); ++ goto err_frm_info_ctrl; ++ } ++ pic->frm_info_mv = av_buffer_alloc(&h->devmem_ctx, mb_array_size * sizeof(unsigned int) * 32 + SDE_FMV_ADS); ++ if(!pic->frm_info_mv) { ++ av_log(NULL, AV_LOG_ERROR, "aFailed to alloc frm_info_mv!\n"); ++ ret = AVERROR(ENOMEM); ++ goto err_frm_info_mv; ++ } ++ ++ ++ if(h->format == VPU_FORMAT_NV12 || h->format == VPU_FORMAT_NV21) { ++ pic->dec_result_y = av_buffer_alloc(&h->devmem_ctx, h->width * h->height); ++ if(!pic->dec_result_y) { ++ av_log(NULL, AV_LOG_ERROR, "aFailed to alloc dec_result_y!\n"); ++ ret = AVERROR(ENOMEM); ++ goto err_dec_result_y; ++ } ++ pic->dec_result_uv = av_buffer_alloc(&h->devmem_ctx, h->width * h->height / 2); ++ if(!pic->dec_result_uv) { ++ av_log(NULL, AV_LOG_ERROR, "aFailed to alloc dec_result_uv!\n"); ++ ret = AVERROR(ENOMEM); ++ goto err_dec_result_uv; ++ } ++ } else { ++ /* reference to output buffer.*/ ++ pic->dec_result_y = f->buf[0]; ++ pic->dec_result_uv = f->buf[1]; ++ } ++ ++ pic->f = f; ++ ++ list_del(&f->queued_entry); ++ ++ return 0; ++ ++err_dec_result_uv: ++ av_buffer_free(&h->devmem_ctx, pic->dec_result_y); ++err_dec_result_y: ++ av_buffer_free(&h->devmem_ctx, pic->frm_info_mv); ++err_frm_info_mv: ++ av_buffer_free(&h->devmem_ctx, pic->frm_info_ctrl); ++err_frm_info_ctrl: ++fail: ++ ff_h264_unref_picture(h, pic); ++ return (ret < 0) ? ret : AVERROR(ENOMEM); ++} ++ ++static int find_unused_picture(H264Context *h) ++{ ++ int i; ++ ++ for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) { ++ if(!h->DPB[i].f) ++ return i; ++ } ++ ++ return AVERROR_INVALIDDATA; ++} ++ ++ ++static int h264_slice_header_init(H264Context *h); ++ ++ ++static int h264_frame_start(H264Context *h) ++{ ++ H264Picture *pic; ++ int i, ret; ++ const int pixel_shift = h->pixel_shift; ++ int c[4] = { ++ 1<<(h->ps.sps->bit_depth_luma-1), ++ 1<<(h->ps.sps->bit_depth_chroma-1), ++ 1<<(h->ps.sps->bit_depth_chroma-1), ++ -1 ++ }; ++ ++ release_unused_pictures(h, 1); ++ h->cur_pic_ptr = NULL; ++ ++ ++ i = find_unused_picture(h); ++ if (i < 0) { ++ av_log(h->avctx, AV_LOG_ERROR, "no frame buffer available\n"); ++ return i; ++ } ++ pic = &h->DPB[i]; ++ ++ if ((ret = alloc_picture(h, pic)) < 0) ++ return ret; ++ ++ pic->reference = h->droppable ? 0 : h->picture_structure; ++ pic->f->coded_picture_number = h->coded_picture_number++; ++ pic->field_picture = h->picture_structure != PICT_FRAME; ++ pic->frame_num = h->poc.frame_num; ++ /* ++ * Zero key_frame here; IDR markings per slice in frame or fields are ORed ++ * in later. ++ * See decode_nal_units(). ++ */ ++ pic->f->key_frame = 0; ++ pic->mmco_reset = 0; ++ pic->recovered = 0; ++ pic->invalid_gap = 0; ++#if 0 ++ pic->sei_recovery_frame_cnt = h->sei.recovery_point.recovery_frame_cnt; ++#endif ++ ++ pic->f->pict_type = h->slice_ctx[0].slice_type; ++ ++ pic->f->crop_left = h->crop_left; ++ pic->f->crop_right = h->crop_right; ++ pic->f->crop_top = h->crop_top; ++ pic->f->crop_bottom = h->crop_bottom; ++ ++ h->cur_pic_ptr = pic; ++ ++ for (i = 0; i < h->nb_slice_ctx; i++) { ++ h->slice_ctx[i].linesize = h->cur_pic_ptr->f->linesize[0]; ++ h->slice_ctx[i].uvlinesize = h->cur_pic_ptr->f->linesize[1]; ++ } ++ ++ /* We mark the current picture as non-reference after allocating it, so ++ * that if we break out due to an error it can be released automatically ++ * in the next ff_mpv_frame_start(). ++ */ ++ h->cur_pic_ptr->reference = 0; ++ ++ h->cur_pic_ptr->field_poc[0] = h->cur_pic_ptr->field_poc[1] = INT_MAX; ++ ++ h->next_output_pic = NULL; ++ ++ h->postpone_filter = 0; ++ ++ h->mb_aff_frame = h->ps.sps->mb_aff && (h->picture_structure == PICT_FRAME); ++ ++#if 0 ++ if (h->sei.unregistered.x264_build >= 0) ++ h->x264_build = h->sei.unregistered.x264_build; ++#endif ++ ++ //assert(h->cur_pic_ptr->long_ref == 0); ++ ++ return 0; ++} ++ ++/** ++ * Initialize implicit_weight table. ++ * @param field 0/1 initialize the weight for interlaced MBAFF ++ * -1 initializes the rest ++ */ ++static void implicit_weight_table(const H264Context *h, H264SliceContext *sl, int field) ++{ ++ int ref0, ref1, i, cur_poc, ref_start, ref_count0, ref_count1; ++ ++ for (i = 0; i < 2; i++) { ++ sl->pwt.luma_weight_flag[i] = 0; ++ sl->pwt.chroma_weight_flag[i] = 0; ++ } ++ ++ if (field < 0) { ++ if (h->picture_structure == PICT_FRAME) { ++ cur_poc = h->cur_pic_ptr->poc; ++ } else { ++ cur_poc = h->cur_pic_ptr->field_poc[h->picture_structure - 1]; ++ } ++ if (sl->ref_count[0] == 1 && sl->ref_count[1] == 1 && !FRAME_MBAFF(h) && ++ sl->ref_list[0][0].poc + (int64_t)sl->ref_list[1][0].poc == 2LL * cur_poc) { ++ sl->pwt.use_weight = 0; ++ sl->pwt.use_weight_chroma = 0; ++ return; ++ } ++ ref_start = 0; ++ ref_count0 = sl->ref_count[0]; ++ ref_count1 = sl->ref_count[1]; ++ } else { ++ cur_poc = h->cur_pic_ptr->field_poc[field]; ++ ref_start = 16; ++ ref_count0 = 16 + 2 * sl->ref_count[0]; ++ ref_count1 = 16 + 2 * sl->ref_count[1]; ++ } ++ ++ sl->pwt.use_weight = 2; ++ sl->pwt.use_weight_chroma = 2; ++ sl->pwt.luma_log2_weight_denom = 5; ++ sl->pwt.chroma_log2_weight_denom = 5; ++ ++ for (ref0 = ref_start; ref0 < ref_count0; ref0++) { ++ int64_t poc0 = sl->ref_list[0][ref0].poc; ++ for (ref1 = ref_start; ref1 < ref_count1; ref1++) { ++ int w = 32; ++ if (!sl->ref_list[0][ref0].parent->long_ref && !sl->ref_list[1][ref1].parent->long_ref) { ++ int poc1 = sl->ref_list[1][ref1].poc; ++ int td = av_clip_int8(poc1 - poc0); ++ if (td) { ++ int tb = av_clip_int8(cur_poc - poc0); ++ int tx = (16384 + (FFABS(td) >> 1)) / td; ++ int dist_scale_factor = (tb * tx + 32) >> 8; ++ if (dist_scale_factor >= -64 && dist_scale_factor <= 128) ++ w = 64 - dist_scale_factor; ++ } ++ } ++ if (field < 0) { ++ sl->pwt.implicit_weight[ref0][ref1][0] = ++ sl->pwt.implicit_weight[ref0][ref1][1] = w; ++ } else { ++ sl->pwt.implicit_weight[ref0][ref1][field] = w; ++ } ++ } ++ } ++} ++ ++/* export coded and cropped frame dimensions to AVCodecContext */ ++static int init_dimensions(H264Context *h) ++{ ++ const SPS *sps = (const SPS*)h->ps.sps; ++ int cr = sps->crop_right; ++ int cl = sps->crop_left; ++ int ct = sps->crop_top; ++ int cb = sps->crop_bottom; ++ int width = h->width - (cr + cl); ++ int height = h->height - (ct + cb); ++ av_assert0(sps->crop_right + sps->crop_left < (unsigned)h->width); ++ av_assert0(sps->crop_top + sps->crop_bottom < (unsigned)h->height); ++ ++ /* handle container cropping */ ++ if (h->width_from_caller > 0 && h->height_from_caller > 0 && ++ !sps->crop_top && !sps->crop_left && ++ FFALIGN(h->width_from_caller, 16) == FFALIGN(width, 16) && ++ FFALIGN(h->height_from_caller, 16) == FFALIGN(height, 16) && ++ h->width_from_caller <= width && ++ h->height_from_caller <= height) { ++ width = h->width_from_caller; ++ height = h->height_from_caller; ++ cl = 0; ++ ct = 0; ++ cr = h->width - width; ++ cb = h->height - height; ++ } else { ++ h->width_from_caller = 0; ++ h->height_from_caller = 0; ++ } ++ ++ h->avctx->coded_width = h->width; ++ h->avctx->coded_height = h->height; ++ h->avctx->width = width; ++ h->avctx->height = height; ++ h->crop_right = cr; ++ h->crop_left = cl; ++ h->crop_top = ct; ++ h->crop_bottom = cb; ++ ++ return 0; ++} ++ ++static int h264_slice_header_init(H264Context *h) ++{ ++ const SPS *sps = h->ps.sps; ++ int i, ret; ++ ++ h->first_field = 0; ++ h->prev_interlaced_frame = 1; ++ ++ if (sps->bit_depth_luma < 8 || sps->bit_depth_luma > 14 || ++ sps->bit_depth_luma == 11 || sps->bit_depth_luma == 13 ++ ) { ++ av_log(h->avctx, AV_LOG_ERROR, "Unsupported bit depth %d\n", ++ sps->bit_depth_luma); ++ ret = AVERROR_INVALIDDATA; ++ goto fail; ++ } ++ ++ h->cur_bit_depth_luma = sps->bit_depth_luma; ++ h->cur_chroma_format_idc = sps->chroma_format_idc; ++ h->pixel_shift = sps->bit_depth_luma > 8; ++ h->chroma_format_idc = sps->chroma_format_idc; ++ h->bit_depth_luma = sps->bit_depth_luma; ++ ++ ++ h->context_initialized = 1; ++ ++ return 0; ++fail: ++ h->context_initialized = 0; ++ return ret; ++} ++ ++ ++static int h264_init_ps(H264Context *h, const H264SliceContext *sl, int first_slice) ++{ ++ const SPS *sps; ++ int needs_reinit = 0, must_reinit, ret; ++ ++ if (first_slice) { ++ h->ps.pps = &h->ps.pps_list[sl->pps_id]; ++ } ++ ++ if (h->ps.sps != &h->ps.sps_list[h->ps.pps->sps_id]) { ++ h->ps.sps = &h->ps.sps_list[h->ps.pps->sps_id]; ++ ++ if (h->mb_width != h->ps.sps->mb_width || ++ h->mb_height != h->ps.sps->mb_height || ++ h->cur_bit_depth_luma != h->ps.sps->bit_depth_luma || ++ h->cur_chroma_format_idc != h->ps.sps->chroma_format_idc ++ ) ++ needs_reinit = 1; ++ ++ if (h->bit_depth_luma != h->ps.sps->bit_depth_luma || ++ h->chroma_format_idc != h->ps.sps->chroma_format_idc) ++ needs_reinit = 1; ++ } ++ sps = h->ps.sps; ++ ++ must_reinit = (h->context_initialized && ++ ( 16*sps->mb_width != h->avctx->coded_width ++ || 16*sps->mb_height != h->avctx->coded_height ++ || h->cur_bit_depth_luma != sps->bit_depth_luma ++ || h->cur_chroma_format_idc != sps->chroma_format_idc ++ || h->mb_width != sps->mb_width ++ || h->mb_height != sps->mb_height ++ )); ++ ++ if (!h->setup_finished) { ++ h->avctx->profile = ff_h264_get_profile(sps); ++ h->avctx->level = sps->level_idc; ++ h->avctx->refs = sps->ref_frame_count; ++ ++ h->mb_width = sps->mb_width; ++ h->mb_height = sps->mb_height; ++ h->mb_num = h->mb_width * h->mb_height; ++ h->mb_stride = h->mb_width + 1; ++ ++ h->b_stride = h->mb_width * 4; ++ ++ h->chroma_y_shift = sps->chroma_format_idc <= 1; // 400 uses yuv420p ++ ++ h->width = 16 * h->mb_width; ++ h->height = 16 * h->mb_height; ++ ++ ret = init_dimensions(h); ++ if (ret < 0) ++ return ret; ++ } ++ ++ if (!h->context_initialized || must_reinit || needs_reinit) { ++ int flush_changes = h->context_initialized; ++ h->context_initialized = 0; ++ if (sl != h->slice_ctx) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "changing width %d -> %d / height %d -> %d on " ++ "slice %d\n", ++ h->width, h->avctx->coded_width, ++ h->height, h->avctx->coded_height, ++ h->current_slice + 1); ++ return AVERROR_INVALIDDATA; ++ } ++ ++ av_assert1(first_slice); ++ ++ if (flush_changes) ++ ff_h264_flush_change(h); ++ ++ if ((ret = h264_slice_header_init(h)) < 0) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "h264_slice_header_init() failed\n"); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int h264_select_output_frame(H264Context *h) ++{ ++ const SPS *sps = h->ps.sps; ++ H264Picture *out = h->cur_pic_ptr; ++ H264Picture *cur = h->cur_pic_ptr; ++ int i, pics, out_of_order, out_idx; ++ ++ cur->mmco_reset = h->mmco_reset; ++ h->mmco_reset = 0; ++ ++ if (sps->bitstream_restriction_flag ++ /*|| h->avctx->strict_std_compliance >= FF_COMPLIANCE_STRICT*/) { ++ h->avctx->has_b_frames = FFMAX(h->avctx->has_b_frames, sps->num_reorder_frames); ++ } ++ ++ for (i = 0; 1; i++) { ++ ++ if(i == MAX_DELAYED_PIC_COUNT || cur->poc < h->last_pocs[i]){ ++ if(i) ++ h->last_pocs[i-1] = cur->poc; ++ break; ++ } else if(i) { ++ h->last_pocs[i-1]= h->last_pocs[i]; ++ } ++ } ++ ++ out_of_order = MAX_DELAYED_PIC_COUNT - i; ++ if( cur->f->pict_type == AV_PICTURE_TYPE_B ++ || (h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > INT_MIN && h->last_pocs[MAX_DELAYED_PIC_COUNT-1] - (int64_t)h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > 2)) ++ out_of_order = FFMAX(out_of_order, 1); ++ if (out_of_order == MAX_DELAYED_PIC_COUNT) { ++ av_log(h->avctx, AV_LOG_VERBOSE, "Invalid POC %d<%d\n", cur->poc, h->last_pocs[0]); ++ for (i = 1; i < MAX_DELAYED_PIC_COUNT; i++) ++ h->last_pocs[i] = INT_MIN; ++ h->last_pocs[0] = cur->poc; ++ cur->mmco_reset = 1; ++ } else if(h->avctx->has_b_frames < out_of_order && !sps->bitstream_restriction_flag){ ++ int loglevel = AV_LOG_WARNING; ++ av_log(h->avctx, loglevel, "Increasing reorder buffer to %d\n", out_of_order); ++ h->avctx->has_b_frames = out_of_order; ++ } ++ ++ pics = 0; ++ while (h->delayed_pic[pics]) ++ pics++; ++ ++ av_assert0(pics <= MAX_DELAYED_PIC_COUNT); ++ ++ h->delayed_pic[pics++] = cur; ++ if (cur->reference == 0) ++ cur->reference = DELAYED_PIC_REF; ++ ++ out = h->delayed_pic[0]; ++ out_idx = 0; ++ for (i = 1; h->delayed_pic[i] && ++ !h->delayed_pic[i]->f->key_frame && ++ !h->delayed_pic[i]->mmco_reset; ++ i++) ++ if (h->delayed_pic[i]->poc < out->poc) { ++ out = h->delayed_pic[i]; ++ out_idx = i; ++ } ++ ++ ++ if (h->avctx->has_b_frames == 0 && ++ (h->delayed_pic[0]->f->key_frame || h->delayed_pic[0]->mmco_reset)) ++ h->next_outputed_poc = INT_MIN; ++ out_of_order = out->poc < h->next_outputed_poc; ++ ++ if (out_of_order || pics > h->avctx->has_b_frames) { ++ out->reference &= ~DELAYED_PIC_REF; ++ for (i = out_idx; h->delayed_pic[i]; i++) ++ h->delayed_pic[i] = h->delayed_pic[i + 1]; ++ } ++ if (!out_of_order && pics > h->avctx->has_b_frames) { ++ h->next_output_pic = out; ++ if (out_idx == 0 && h->delayed_pic[0] && (h->delayed_pic[0]->f->key_frame || h->delayed_pic[0]->mmco_reset)) { ++ h->next_outputed_poc = INT_MIN; ++ } else ++ h->next_outputed_poc = out->poc; ++ ++ if (out->recovered) { ++ // We have reached an recovery point and all frames after it in ++ // display order are "recovered". ++ h->frame_recovered |= FRAME_RECOVERED_SEI; ++ } ++ out->recovered |= !!(h->frame_recovered & FRAME_RECOVERED_SEI); ++ ++ if (!out->recovered) { ++ h->next_output_pic = NULL; ++#if 0 ++ if (!(h->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) && ++ !(h->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL)) { ++ h->next_output_pic = NULL; ++ } else { ++ out->f->flags |= AV_FRAME_FLAG_CORRUPT; ++ } ++#endif ++ } ++ } else { ++ av_log(h->avctx, AV_LOG_DEBUG, "no picture %s\n", out_of_order ? "ooo" : ""); ++ } ++ ++ return 0; ++} ++ ++/* This function is called right after decoding the slice header for a first ++ * slice in a field (or a frame). It decides whether we are decoding a new frame ++ * or a second field in a pair and does the necessary setup. ++ */ ++static int h264_field_start(H264Context *h, const H264SliceContext *sl, ++ const H2645NAL *nal, int first_slice) ++{ ++ int i; ++ const SPS *sps; ++ ++ int last_pic_structure, last_pic_droppable, ret; ++ ++ ret = h264_init_ps(h, sl, first_slice); ++ if (ret < 0) ++ return ret; ++ ++ sps = h->ps.sps; ++ ++ if (sps && sps->bitstream_restriction_flag && ++ h->avctx->has_b_frames < sps->num_reorder_frames) { ++ h->avctx->has_b_frames = sps->num_reorder_frames; ++ } ++ ++ last_pic_droppable = h->droppable; ++ last_pic_structure = h->picture_structure; ++ h->droppable = (nal->ref_idc == 0); ++ h->picture_structure = sl->picture_structure; ++ ++ h->poc.frame_num = sl->frame_num; ++ h->poc.poc_lsb = sl->poc_lsb; ++ h->poc.delta_poc_bottom = sl->delta_poc_bottom; ++ h->poc.delta_poc[0] = sl->delta_poc[0]; ++ h->poc.delta_poc[1] = sl->delta_poc[1]; ++ ++ /* Shorten frame num gaps so we don't have to allocate reference ++ * frames just to throw them away */ ++ if (h->poc.frame_num != h->poc.prev_frame_num) { ++ int unwrap_prev_frame_num = h->poc.prev_frame_num; ++ int max_frame_num = 1 << sps->log2_max_frame_num; ++ ++ if (unwrap_prev_frame_num > h->poc.frame_num) ++ unwrap_prev_frame_num -= max_frame_num; ++ ++ if ((h->poc.frame_num - unwrap_prev_frame_num) > sps->ref_frame_count) { ++ unwrap_prev_frame_num = (h->poc.frame_num - sps->ref_frame_count) - 1; ++ if (unwrap_prev_frame_num < 0) ++ unwrap_prev_frame_num += max_frame_num; ++ ++ h->poc.prev_frame_num = unwrap_prev_frame_num; ++ } ++ } ++ ++ /* See if we have a decoded first field looking for a pair... ++ * Here, we're using that to see if we should mark previously ++ * decode frames as "finished". ++ * We have to do that before the "dummy" in-between frame allocation, ++ * since that can modify h->cur_pic_ptr. */ ++ if (h->first_field) { ++ int last_field = last_pic_structure == PICT_BOTTOM_FIELD; ++ av_assert0(h->cur_pic_ptr); ++ av_assert0(h->cur_pic_ptr->f->buf[0]); ++ //assert(h->cur_pic_ptr->reference != DELAYED_PIC_REF); ++ ++ /* figure out if we have a complementary field pair */ ++ if (!FIELD_PICTURE(h) || h->picture_structure == last_pic_structure) { ++ /* Previous field is unmatched. Don't display it, but let it ++ * remain for reference if marked as such. */ ++ if (last_pic_structure != PICT_FRAME) { ++ } ++ } else { ++ if (h->cur_pic_ptr->frame_num != h->poc.frame_num) { ++ /* This and previous field were reference, but had ++ * different frame_nums. Consider this field first in ++ * pair. Throw away previous field except for reference ++ * purposes. */ ++ if (last_pic_structure != PICT_FRAME) { ++ } ++ } else { ++ /* Second field in complementary pair */ ++ if (!((last_pic_structure == PICT_TOP_FIELD && ++ h->picture_structure == PICT_BOTTOM_FIELD) || ++ (last_pic_structure == PICT_BOTTOM_FIELD && ++ h->picture_structure == PICT_TOP_FIELD))) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "Invalid field mode combination %d/%d\n", ++ last_pic_structure, h->picture_structure); ++ h->picture_structure = last_pic_structure; ++ h->droppable = last_pic_droppable; ++ return AVERROR_INVALIDDATA; ++ } else if (last_pic_droppable != h->droppable) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "Found reference and non-reference fields in the same frame, which"); ++ h->picture_structure = last_pic_structure; ++ h->droppable = last_pic_droppable; ++ return AVERROR_PATCHWELCOME; ++ } ++ } ++ } ++ } ++ ++ while (h->poc.frame_num != h->poc.prev_frame_num && !h->first_field && ++ h->poc.frame_num != (h->poc.prev_frame_num + 1) % (1 << sps->log2_max_frame_num)) { ++ H264Picture *prev = h->short_ref_count ? h->short_ref[0] : NULL; ++ av_log(h->avctx, AV_LOG_DEBUG, "Frame num gap %d %d\n", ++ h->poc.frame_num, h->poc.prev_frame_num); ++ if (!sps->gaps_in_frame_num_allowed_flag) ++ for(i=0; ilast_pocs); i++) ++ h->last_pocs[i] = INT_MIN; ++ ++ ret = h264_frame_start(h); ++ if (ret < 0) { ++ h->first_field = 0; ++ return ret; ++ } ++ ++ h->poc.prev_frame_num++; ++ h->poc.prev_frame_num %= 1 << sps->log2_max_frame_num; ++ h->cur_pic_ptr->frame_num = h->poc.prev_frame_num; ++ h->cur_pic_ptr->invalid_gap = !sps->gaps_in_frame_num_allowed_flag; ++ h->explicit_ref_marking = 0; ++ ret = ff_h264_execute_ref_pic_marking(h); ++ if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) ++ return ret; ++ } ++ ++ /* See if we have a decoded first field looking for a pair... ++ * We're using that to see whether to continue decoding in that ++ * frame, or to allocate a new one. */ ++ if (h->first_field) { ++ av_assert0(h->cur_pic_ptr); ++ av_assert0(h->cur_pic_ptr->f->buf[0]); ++ //assert(h->cur_pic_ptr->reference != DELAYED_PIC_REF); ++ ++ /* figure out if we have a complementary field pair */ ++ if (!FIELD_PICTURE(h) || h->picture_structure == last_pic_structure) { ++ /* Previous field is unmatched. Don't display it, but let it ++ * remain for reference if marked as such. */ ++ h->missing_fields ++; ++ h->cur_pic_ptr = NULL; ++ h->first_field = FIELD_PICTURE(h); ++ } else { ++ h->missing_fields = 0; ++ if (h->cur_pic_ptr->frame_num != h->poc.frame_num) { ++ /* This and the previous field had different frame_nums. ++ * Consider this field first in pair. Throw away previous ++ * one except for reference purposes. */ ++ h->first_field = 1; ++ h->cur_pic_ptr = NULL; ++ } else if (h->cur_pic_ptr->reference & DELAYED_PIC_REF) { ++ /* This frame was already output, we cannot draw into it ++ * anymore. ++ */ ++ h->first_field = 1; ++ h->cur_pic_ptr = NULL; ++ } else { ++ /* Second field in complementary pair */ ++ h->first_field = 0; ++ } ++ } ++ } else { ++ /* Frame or first field in a potentially complementary pair */ ++ h->first_field = FIELD_PICTURE(h); ++ } ++ ++ if (!FIELD_PICTURE(h) || h->first_field) { ++ if (h264_frame_start(h) < 0) { ++ h->first_field = 0; ++ return AVERROR_INVALIDDATA; ++ } ++ } else { ++ int field = h->picture_structure == PICT_BOTTOM_FIELD; ++ release_unused_pictures(h, 0); ++ } ++ ++ ++ ret = ff_h264_init_poc(h->cur_pic_ptr->field_poc, &h->cur_pic_ptr->poc, ++ h->ps.sps, &h->poc, h->picture_structure, nal->ref_idc); ++ if (ret < 0) ++ return ret; ++ ++ memcpy(h->mmco, sl->mmco, sl->nb_mmco * sizeof(*h->mmco)); ++ h->nb_mmco = sl->nb_mmco; ++ h->explicit_ref_marking = sl->explicit_ref_marking; ++ ++ h->picture_idr = nal->type == H264_NAL_IDR_SLICE; ++ ++ h->cur_pic_ptr->f->key_frame |= (nal->type == H264_NAL_IDR_SLICE); ++ ++ if (nal->type == H264_NAL_IDR_SLICE || ++ (h->recovery_frame == h->poc.frame_num && nal->ref_idc)) { ++ h->recovery_frame = -1; ++ h->cur_pic_ptr->recovered = 1; ++ } ++ // If we have an IDR, all frames after it in decoded order are ++ // "recovered". ++ if (nal->type == H264_NAL_IDR_SLICE) ++ h->frame_recovered |= FRAME_RECOVERED_IDR; ++ ++ h->cur_pic_ptr->recovered |= h->frame_recovered; ++ ++ /* Set the frame properties/side data. Only done for the second field in ++ * field coded frames, since some SEI information is present for each field ++ * and is merged by the SEI parsing code. */ ++ if (!FIELD_PICTURE(h) || !h->first_field || h->missing_fields > 1) { ++ ++ ret = h264_select_output_frame(h); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, ++ const H2645NAL *nal) ++{ ++ const SPS *sps; ++ const PPS *pps; ++ int ret; ++ unsigned int slice_type, tmp, i; ++ int field_pic_flag, bottom_field_flag; ++ int first_slice = sl == h->slice_ctx && !h->current_slice; ++ int picture_structure; ++ ++ if (first_slice) ++ av_assert0(!h->setup_finished); ++ ++ sl->first_mb_addr = get_ue_golomb_long(&sl->gb); ++ ++ slice_type = get_ue_golomb_31(&sl->gb); ++ if (slice_type > 9) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "slice type %d too large at %d\n", ++ slice_type, sl->first_mb_addr); ++ return AVERROR_INVALIDDATA; ++ } ++ if (slice_type > 4) { ++ slice_type -= 5; ++ sl->slice_type_fixed = 1; ++ } else ++ sl->slice_type_fixed = 0; ++ ++ slice_type = ff_h264_golomb_to_pict_type[slice_type]; ++ sl->slice_type = slice_type; ++ sl->slice_type_nos = slice_type & 3; ++ ++ if (nal->type == H264_NAL_IDR_SLICE && ++ sl->slice_type_nos != AV_PICTURE_TYPE_I) { ++ av_log(h->avctx, AV_LOG_ERROR, "A non-intra slice in an IDR NAL unit.\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ ++ sl->pps_id = get_ue_golomb(&sl->gb); ++ if (sl->pps_id >= MAX_PPS_COUNT) { ++ av_log(h->avctx, AV_LOG_ERROR, "pps_id %u out of range, max:%u\n", sl->pps_id, MAX_PPS_COUNT); ++ return AVERROR_INVALIDDATA; ++ } ++ if (!&h->ps.pps_list[sl->pps_id]) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "non-existing PPS %u referenced\n", ++ sl->pps_id); ++ return AVERROR_INVALIDDATA; ++ } ++#if 0 ++ pps = (const PPS*)h->ps.pps_list[sl->pps_id]->data; ++#else ++ pps = &h->ps.pps_list[sl->pps_id]; ++#endif ++ if (!&h->ps.sps_list[pps->sps_id]) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "non-existing SPS %u referenced\n", pps->sps_id); ++ return AVERROR_INVALIDDATA; ++ } ++ sps = &h->ps.sps_list[pps->sps_id]; ++ ++ sl->frame_num = get_bits(&sl->gb, sps->log2_max_frame_num); ++ if (!first_slice) { ++ if (h->poc.frame_num != sl->frame_num) { ++ av_log(h->avctx, AV_LOG_ERROR, "Frame num change from %d to %d\n", ++ h->poc.frame_num, sl->frame_num); ++// return AVERROR_INVALIDDATA; ++ } ++ } ++ ++ sl->mb_mbaff = 0; ++ ++ if (sps->frame_mbs_only_flag) { ++ picture_structure = PICT_FRAME; ++ } else { ++ if (!sps->direct_8x8_inference_flag && slice_type == AV_PICTURE_TYPE_B) { ++ av_log(h->avctx, AV_LOG_ERROR, "This stream was generated by a broken encoder, invalid 8x8 inference\n"); ++ return -1; ++ } ++ field_pic_flag = get_bits1(&sl->gb); ++ if (field_pic_flag) { ++ bottom_field_flag = get_bits1(&sl->gb); ++ picture_structure = PICT_TOP_FIELD + bottom_field_flag; ++ } else { ++ picture_structure = PICT_FRAME; ++ } ++ } ++ sl->picture_structure = picture_structure; ++ sl->mb_field_decoding_flag = picture_structure != PICT_FRAME; ++ ++ if (picture_structure == PICT_FRAME) { ++ sl->curr_pic_num = sl->frame_num; ++ sl->max_pic_num = 1 << sps->log2_max_frame_num; ++ } else { ++ sl->curr_pic_num = 2 * sl->frame_num + 1; ++ sl->max_pic_num = 1 << (sps->log2_max_frame_num + 1); ++ } ++ ++ if (nal->type == H264_NAL_IDR_SLICE) ++ get_ue_golomb_long(&sl->gb); /* idr_pic_id */ ++ ++ if (sps->poc_type == 0) { ++ sl->poc_lsb = get_bits(&sl->gb, sps->log2_max_poc_lsb); ++ ++ if (pps->pic_order_present == 1 && picture_structure == PICT_FRAME) ++ sl->delta_poc_bottom = get_se_golomb(&sl->gb); ++ } ++ ++ if (sps->poc_type == 1 && !sps->delta_pic_order_always_zero_flag) { ++ sl->delta_poc[0] = get_se_golomb(&sl->gb); ++ ++ if (pps->pic_order_present == 1 && picture_structure == PICT_FRAME) ++ sl->delta_poc[1] = get_se_golomb(&sl->gb); ++ } ++ ++ sl->redundant_pic_count = 0; ++ if (pps->redundant_pic_cnt_present) ++ sl->redundant_pic_count = get_ue_golomb(&sl->gb); ++ ++ if (sl->slice_type_nos == AV_PICTURE_TYPE_B) ++ sl->direct_spatial_mv_pred = get_bits1(&sl->gb); ++ ++ ret = ff_h264_parse_ref_count(&sl->list_count, sl->ref_count, ++ &sl->gb, pps, sl->slice_type_nos, ++ picture_structure, h->avctx); ++ if (ret < 0) ++ return ret; ++ ++ if (sl->slice_type_nos != AV_PICTURE_TYPE_I) { ++ ret = ff_h264_decode_ref_pic_list_reordering(sl, h->avctx); ++ if (ret < 0) { ++ sl->ref_count[1] = sl->ref_count[0] = 0; ++ return ret; ++ } ++ } ++ ++ sl->pwt.use_weight = 0; ++ for (i = 0; i < 2; i++) { ++ sl->pwt.luma_weight_flag[i] = 0; ++ sl->pwt.chroma_weight_flag[i] = 0; ++ } ++ if ((pps->weighted_pred && sl->slice_type_nos == AV_PICTURE_TYPE_P) || ++ (pps->weighted_bipred_idc == 1 && ++ sl->slice_type_nos == AV_PICTURE_TYPE_B)) { ++ ret = ff_h264_pred_weight_table(&sl->gb, sps, sl->ref_count, ++ sl->slice_type_nos, &sl->pwt, ++ picture_structure, h->avctx); ++ if (ret < 0) ++ return ret; ++ } ++ ++ sl->explicit_ref_marking = 0; ++ if (nal->ref_idc) { ++ ret = ff_h264_decode_ref_pic_marking(sl, &sl->gb, nal, h->avctx); ++ if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) ++ return AVERROR_INVALIDDATA; ++ } ++ ++ if (sl->slice_type_nos != AV_PICTURE_TYPE_I && pps->cabac) { ++ tmp = get_ue_golomb_31(&sl->gb); ++ if (tmp > 2) { ++ av_log(h->avctx, AV_LOG_ERROR, "cabac_init_idc %u overflow\n", tmp); ++ return AVERROR_INVALIDDATA; ++ } ++ sl->cabac_init_idc = tmp; ++ } ++ ++ sl->last_qscale_diff = 0; ++ tmp = pps->init_qp + (unsigned)get_se_golomb(&sl->gb); ++ if (tmp > 51 + 6 * (sps->bit_depth_luma - 8)) { ++ av_log(h->avctx, AV_LOG_ERROR, "QP %u out of range\n", tmp); ++ return AVERROR_INVALIDDATA; ++ } ++ sl->qscale = tmp; ++ sl->chroma_qp[0] = get_chroma_qp(pps, 0, sl->qscale); ++ sl->chroma_qp[1] = get_chroma_qp(pps, 1, sl->qscale); ++ // FIXME qscale / qp ... stuff ++ if (sl->slice_type == AV_PICTURE_TYPE_SP) ++ get_bits1(&sl->gb); /* sp_for_switch_flag */ ++ if (sl->slice_type == AV_PICTURE_TYPE_SP || ++ sl->slice_type == AV_PICTURE_TYPE_SI) ++ get_se_golomb(&sl->gb); /* slice_qs_delta */ ++ ++ sl->deblocking_filter = 1; ++ sl->slice_alpha_c0_offset = 0; ++ sl->slice_beta_offset = 0; ++ if (pps->deblocking_filter_parameters_present) { ++ tmp = get_ue_golomb_31(&sl->gb); ++ if (tmp > 2) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "deblocking_filter_idc %u out of range\n", tmp); ++ return AVERROR_INVALIDDATA; ++ } ++ sl->deblocking_filter = tmp; ++ if (sl->deblocking_filter < 2) ++ sl->deblocking_filter ^= 1; // 1<->0 ++ ++ if (sl->deblocking_filter) { ++ int slice_alpha_c0_offset_div2 = get_se_golomb(&sl->gb); ++ int slice_beta_offset_div2 = get_se_golomb(&sl->gb); ++ if (slice_alpha_c0_offset_div2 > 6 || ++ slice_alpha_c0_offset_div2 < -6 || ++ slice_beta_offset_div2 > 6 || ++ slice_beta_offset_div2 < -6) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "deblocking filter parameters %d %d out of range\n", ++ slice_alpha_c0_offset_div2, slice_beta_offset_div2); ++ return AVERROR_INVALIDDATA; ++ } ++ sl->slice_alpha_c0_offset = slice_alpha_c0_offset_div2 * 2; ++ sl->slice_beta_offset = slice_beta_offset_div2 * 2; ++ } ++ } ++ ++ return 0; ++} ++ ++/* do all the per-slice initialization needed before we can start decoding the ++ * actual MBs */ ++static int h264_slice_init(H264Context *h, H264SliceContext *sl, ++ const H2645NAL *nal) ++{ ++ int i, j, ret = 0; ++ ++ if (h->picture_idr && nal->type != H264_NAL_IDR_SLICE) { ++ av_log(h->avctx, AV_LOG_ERROR, "Invalid mix of IDR and non-IDR slices\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ ++ av_assert1(h->mb_num == h->mb_width * h->mb_height); ++ if (sl->first_mb_addr << FIELD_OR_MBAFF_PICTURE(h) >= h->mb_num || ++ sl->first_mb_addr >= h->mb_num) { ++ av_log(h->avctx, AV_LOG_ERROR, "first_mb_in_slice overflow\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ ++ sl->mb_x = sl->first_mb_addr % h->mb_width; ++ sl->mb_y = (sl->first_mb_addr / h->mb_width) << ++ FIELD_OR_MBAFF_PICTURE(h); ++ av_assert1(sl->mb_y < h->mb_height); ++ ++ ret = ff_h264_build_ref_list(h, sl); ++ if (ret < 0) ++ return ret; ++ ++ if (h->ps.pps->weighted_bipred_idc == 2 && ++ sl->slice_type_nos == AV_PICTURE_TYPE_B) { ++ implicit_weight_table(h, sl, -1); ++ if (FRAME_MBAFF(h)) { ++ implicit_weight_table(h, sl, 0); ++ implicit_weight_table(h, sl, 1); ++ } ++ } ++ ++ if (sl->slice_type_nos == AV_PICTURE_TYPE_B && !sl->direct_spatial_mv_pred) ++ ff_h264_direct_dist_scale_factor(h, sl); ++ if (!h->setup_finished) ++ ff_h264_direct_ref_list_init(h, sl); ++ sl->qp_thresh = 15 - ++ FFMIN(sl->slice_alpha_c0_offset, sl->slice_beta_offset) - ++ FFMAX3(0, ++ h->ps.pps->chroma_qp_index_offset[0], ++ h->ps.pps->chroma_qp_index_offset[1]) + ++ 6 * (h->ps.sps->bit_depth_luma - 8); ++ ++ sl->slice_num = ++h->current_slice; ++ ++ return 0; ++} ++ ++void dump_slice_header(H264SliceContext *sl) ++{ ++ printf("sl->slice_num: %d\n", sl->slice_num); ++ printf("sl->slice_type: %d\n", sl->slice_type); ++ printf("sl->slice_type_nos: %d\n", sl->slice_type_nos); ++ ++ printf("sl->mb_x: %d\n", sl->mb_x); ++ printf("sl->mb_y: %d\n", sl->mb_y); ++ printf("sl->ref_count[0]: %d, sl->ref_count[1]:%d\n", sl->ref_count[0], sl->ref_count[1]); ++ printf("sl->mb_mbaff: %d\n", sl->mb_mbaff); ++ printf("sl->frame_num: %d\n", sl->frame_num); ++ printf("sl->curr_pic_num: %d\n", sl->curr_pic_num); ++ printf("sl->delta_poc_bottom: %d\n", sl->delta_poc_bottom); ++} ++ ++ ++#define MAX_SLICE_HEADER_SIZE 32 ++int ff_h264_queue_decode_slice(H264Context *h, const H2645NAL *nal) ++{ ++ H264SliceContext *sl = h->slice_ctx + h->nb_slice_ctx_queued; ++ int first_slice = sl == h->slice_ctx && !h->current_slice; ++ int ret; ++ unsigned char slice_header[MAX_SLICE_HEADER_SIZE]; ++ unsigned char removed_at[10]; ++ GetBitContext sh_gb; ++ ++ sl->gb = nal->gb; ++ ++ /*1. copy 256 raw data.*/ ++ memcpy(slice_header, nal->gb.buffer, 32); ++ ++ ++// hexdump(slice_header, 32); ++ ++ /*2. remove 0x3 from slice_header */ ++ char *src; ++ char *dst; ++ unsigned int si, di; ++ int removed_bytes = 0; ++ unsigned int length = 0; ++ int i = 0; ++ ++ unsigned int slice_data_index = 0; ++ ++ ret = init_get_bits(&sh_gb, slice_header, MAX_SLICE_HEADER_SIZE * 8); ++ sh_gb.index += 8; ++ ++ /* Try to remove 0x3 in slice header. */ ++ si = di = 0; ++ src = dst = slice_header; ++ length = MAX_SLICE_HEADER_SIZE; ++ while (si + 2 < length) { ++ // remove escapes (very rare 1:2^22) ++ if (src[si + 2] > 3) { ++ dst[di++] = src[si++]; ++ dst[di++] = src[si++]; ++ } else if (src[si] == 0 && src[si + 1] == 0 && src[si + 2] == 3) { ++ dst[di++] = 0; ++ dst[di++] = 0; ++ si += 3; ++ removed_at[i++] = (si-1) * 8; ++ } ++ dst[di++] = src[si++]; ++ } ++ ++ while (si < length) ++ dst[di++] = src[si++]; ++ removed_bytes = si - di; ++ ++ sl->gb = sh_gb; ++ ret = h264_slice_header_parse(h, sl, nal); ++ if (ret < 0) ++ return ret; ++ ++ slice_data_index = sl->gb.index; ++ ++#if 0 ++ for(i = 0; i < removed_bytes; i++) { ++ if(removed_at[i] < sl->gb.index) { ++ slice_data_index += 8; ++ } ++ } ++#endif ++ ++ sl->gb = nal->gb; ++ sl->gb.index = slice_data_index; ++ ++ //dump_slice_header(sl); ++ ++ // discard redundant pictures ++ if (sl->redundant_pic_count > 0) { ++ sl->ref_count[0] = sl->ref_count[1] = 0; ++ return 0; ++ } ++ ++ /*如果第一个macroblock地å€ä¸º0, ????*/ ++ if (sl->first_mb_addr == 0 || !h->current_slice) { ++ if (h->setup_finished) { ++ av_log(h->avctx, AV_LOG_ERROR, "Too many fields\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ } ++ ++ if (!h->current_slice) ++ av_assert0(sl == h->slice_ctx); ++ ++ if (!first_slice) { ++ const PPS *pps = &h->ps.pps_list[sl->pps_id]; ++ ++ if (h->ps.pps->sps_id != pps->sps_id || ++ h->ps.pps->transform_8x8_mode != pps->transform_8x8_mode /*|| ++ (h->setup_finished && h->ps.pps != pps)*/) { ++ av_log(h->avctx, AV_LOG_ERROR, "PPS changed between slices\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ if (h->ps.sps != &h->ps.sps_list[h->ps.pps->sps_id]) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "SPS changed in the middle of the frame\n"); ++ return AVERROR_INVALIDDATA; ++ } ++ } ++ ++ if (h->current_slice == 0) { ++ ret = h264_field_start(h, sl, nal, first_slice); ++ if (ret < 0) ++ return ret; ++ } else { ++ if (h->picture_structure != sl->picture_structure || ++ h->droppable != (nal->ref_idc == 0)) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "Changing field mode (%d -> %d) between slices is not allowed\n", ++ h->picture_structure, sl->picture_structure); ++ return AVERROR_INVALIDDATA; ++ } else if (!h->cur_pic_ptr) { ++ av_log(h->avctx, AV_LOG_ERROR, ++ "unset cur_pic_ptr on slice %d\n", ++ h->current_slice + 1); ++ return AVERROR_INVALIDDATA; ++ } ++ } ++ ++ ret = h264_slice_init(h, sl, nal); ++ if (ret < 0) ++ return ret; ++ ++ h->nb_slice_ctx_queued++; ++ ++ return 0; ++} ++ ++int ff_h264_get_slice_type(const H264SliceContext *sl) ++{ ++ switch (sl->slice_type) { ++ case AV_PICTURE_TYPE_P: ++ return 0; ++ case AV_PICTURE_TYPE_B: ++ return 1; ++ case AV_PICTURE_TYPE_I: ++ return 2; ++ case AV_PICTURE_TYPE_SP: ++ return 3; ++ case AV_PICTURE_TYPE_SI: ++ return 4; ++ default: ++ return AVERROR_INVALIDDATA; ++ } ++} ++ ++void dump_st_h264(struct JZM_H264 *st_h264) ++{ ++ printf("st_h264->des_va :0x%x\n", st_h264->des_va ); ++ printf("st_h264->slice_type :0x%x\n", st_h264->slice_type ); ++ printf("st_h264->slice_num :0x%x\n", st_h264->slice_num ); ++ printf("st_h264->start_mb_x :0x%x\n", st_h264->start_mb_x ); ++ printf("st_h264->start_mb_y :0x%x\n", st_h264->start_mb_y ); ++ printf("st_h264->mb_width :0x%x\n", st_h264->mb_width ); ++ printf("st_h264->mb_height :0x%x\n", st_h264->mb_height ); ++ printf("st_h264->field_picture :0x%x\n", st_h264->field_picture ); ++ printf("st_h264->cabac :0x%x\n", st_h264->cabac ); ++ printf("st_h264->qscale :0x%x\n", st_h264->qscale ); ++ printf("st_h264->transform_8x8_mode :0x%x\n", st_h264->transform_8x8_mode ); ++ printf("st_h264->constrained_intra_pred :0x%x\n", st_h264->constrained_intra_pred ); ++ printf("st_h264->direct_8x8_inference_flag :0x%x\n", st_h264->direct_8x8_inference_flag); ++ printf("st_h264->direct_spatial_mv_pred :0x%x\n", st_h264->direct_spatial_mv_pred ); ++ printf("st_h264->x264_build :0x%x\n", st_h264->x264_build ); ++ printf("st_h264->ref_count_0 :0x%x\n", st_h264->ref_count_0 ); ++ printf("st_h264->ref_count_1 :0x%x\n", st_h264->ref_count_1 ); ++ printf("st_h264->deblocking_filter :0x%x\n", st_h264->deblocking_filter ); ++ printf("st_h264->slice_alpha_c0_offset :0x%x\n", st_h264->slice_alpha_c0_offset ); ++ printf("st_h264->slice_beta_offset :0x%x\n", st_h264->slice_beta_offset ); ++ printf("st_h264->bs_buffer :0x%x\n", st_h264->bs_buffer ); ++ printf("st_h264->bs_index :0x%x\n", st_h264->bs_index ); ++ printf("st_h264->bs_size_in_bits :0x%x\n", st_h264->bs_size_in_bits ); ++ printf("st_h264->cabac_init_idc :0x%x\n", st_h264->cabac_init_idc ); ++ printf("st_h264->ref_frm_ctrl :0x%x\n", st_h264->ref_frm_ctrl ); ++ printf("st_h264->ref_frm_mv :0x%x\n", st_h264->ref_frm_mv ); ++ printf("st_h264->curr_frm_ctrl :0x%x\n", st_h264->curr_frm_ctrl ); ++ printf("st_h264->curr_frm_mv :0x%x\n", st_h264->curr_frm_mv ); ++ printf("st_h264->use_weight :0x%x\n", st_h264->use_weight ); ++ printf("st_h264->use_weight_chroma :0x%x\n", st_h264->use_weight_chroma ); ++ printf("st_h264->use_weight_chroma :0x%x\n", st_h264->use_weight_chroma ); ++ printf("st_h264->luma_log2_weight_denom :0x%x\n", st_h264->luma_log2_weight_denom ); ++ printf("st_h264->chroma_log2_weight_denom :0x%x\n", st_h264->chroma_log2_weight_denom); ++ printf("st_h264->dblk_left_en :0x%x\n", st_h264->dblk_left_en ); ++ printf("st_h264->dblk_top_en :0x%x\n", st_h264->dblk_top_en ); ++ printf("st_h264->dec_result_y :0x%x\n", st_h264->dec_result_y ); ++ printf("st_h264->dec_result_uv :0x%x\n", st_h264->dec_result_uv ); ++ printf("st_h264->new_odma_flag :0x%x\n", st_h264->new_odma_flag ); ++ printf("st_h264->new_odma_format :0x%x\n", st_h264->new_odma_format ); ++ printf("st_h264->dec_result1_y :0x%x\n", st_h264->dec_result1_y ); ++ printf("st_h264->dec_result1_uv :0x%x\n", st_h264->dec_result1_uv ); ++ printf("st_h264->frm_y_stride :0x%x\n", st_h264->frm_y_stride ); ++ printf("st_h264->frm_c_stride :0x%x\n", st_h264->frm_c_stride ); ++ printf("st_h264->bs_rbsp_en :0x%x\n", st_h264->bs_rbsp_en ); ++ ++ int i; ++ printf("st_h264->dir_scale_table: \n--------------------\n"); ++ for (i=0; i<16/4; i++) { ++ printf("%x %x %x %x\n", st_h264->dir_scale_table[i], st_h264->dir_scale_table[i+1], st_h264->dir_scale_table[i+2], st_h264->dir_scale_table[i+3]); ++ } ++ printf("--------------------------------------------------\n"); ++ ++#if 1 ++ ++ printf("st_h264->mc_ref_y[0]: \n"); ++ for(i = 0; i < 16; i++) { ++ printf("%x ", st_h264->mc_ref_y[0][i]); ++ ++ } ++ printf("\n"); ++ printf("st_h264->mc_ref_c[0]: \n"); ++ for(i = 0; i < 16; i++) { ++ printf("%x ", st_h264->mc_ref_c[0][i]); ++ ++ } ++ printf("\n"); ++ printf("st_h264->mc_ref_y[1]: \n"); ++ for(i = 0; i < 16; i++) { ++ printf("%x ", st_h264->mc_ref_y[1][i]); ++ ++ } ++ printf("\n"); ++ printf("st_h264->mc_ref_c[1]: \n"); ++ for(i = 0; i < 16; i++) { ++ printf("%x ", st_h264->mc_ref_c[1][i]); ++ ++ } ++ printf("\n"); ++ ++ printf("st_h264->chroma_qp_table:---------------\n"); ++ for (i=0; i<128/16; i++) { ++ int j; ++ for(j = i * 16; j < i * 16 + 16; j++) { ++ printf("%08x ", st_h264->chroma_qp_table[j]); ++ } ++ printf("\n"); ++ } ++ ++ printf("##luma_weight:\n"); ++ for(i = 0; i<2; i++) { ++ int j; ++ for(j = 0; j< 16; j++) { ++ printf("%08d ", st_h264->luma_weight[i][j]); ++ } ++ printf("\n"); ++ } ++ printf("luma_offset:\n"); ++ for(i = 0; i<2; i++) { ++ int j; ++ for(j = 0; j< 16; j++) { ++ printf("%08d ", st_h264->luma_offset[i][j]); ++ } ++ printf("\n"); ++ } ++ ++ printf("##chroma_weight:\n"); ++ for(i = 0; i<2; i++) { ++ int j; ++ for(j = 0; j< 16; j++) { ++ int k; ++ if(!(j%8)) ++ printf("\n"); ++ for(k = 0 ; k < 2; k ++) ++ printf("%08d ", st_h264->chroma_weight[i][j][k]); ++ ++ ++ } ++ printf("\n"); ++ } ++ printf("chroma_offset:\n"); ++ for(i = 0; i<2; i++) { ++ int j; ++ for(j = 0; j< 16; j++) { ++ int k; ++ if(!(j%8)) ++ printf("\n"); ++ for(k = 0; k < 2; k++) { ++ printf("%08d ", st_h264->chroma_offset[i][j][k]); ++ } ++ } ++ printf("\n"); ++ } ++ ++ printf("### implicit_weight !\n"); ++ for(i = 0; i<16; i++) { ++ int j; ++ for(j = 0; j < 16; j++) { ++ printf("%08d ",st_h264->implicit_weight[i][j]); ++ } ++ printf("\n"); ++ } ++ ++ printf("dump matrix 4x4:\n"); ++ for(i=0; i< 6; i++) { ++ int j; ++ for(j = 0; j < 16; j++) { ++ printf("%08d ", st_h264->scaling_matrix4[i][j]); ++ } ++ printf("\n"); ++ } ++ ++ printf("dump matrix 8x8:\n"); ++ for(i = 0; i <2; i++) { ++ int j; ++ for(j=0; j<64; j++) { ++ if(!(j%16)) ++ printf("%08d ", st_h264->scaling_matrix8[i][j]); ++ } ++ printf("\n"); ++ } ++#endif ++ ++ ++} ++ ++void hexdump(unsigned char *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) { ++ if ((i % 16) == 0) ++ printf("%s%08x: ", i ? "\n" : "", ++ (unsigned int)&buf[i]); ++ printf("%02x ", buf[i]); ++ } ++ printf("\n"); ++} ++ ++void dump_bs_buffer(struct JZM_H264 *st_h264, char *bs, unsigned long len) ++{ ++ int i; ++ printf("dump bs buffer- bs_index :%d, %s\n", st_h264->bs_index, st_h264->bs_index % 8 ? "Not 8Bits align": "8Bits align"); ++ printf("----\n"); ++ int bs_index = st_h264->bs_index; ++ unsigned char *bs_buffer = bs; ++ /* dump 32bytes more after bs_index */ ++ for(i = 0; i < bs_index/8 + 32; i++) { ++ printf("%02x", bs_buffer[i]); ++ if(bs_index > i*8) { ++ printf(". "); ++ } else if(bs_index == i*8) { ++ printf("=>"); ++ } else { ++ printf(" "); ++ } ++ } ++ printf("\n----\n"); ++ ++ printf("bs @ start:\n"); ++ hexdump(bs, 64); ++ printf("bs @ end:\n"); ++ hexdump(bs + len - 64, 64); ++} ++ ++void dump_picture(H264Picture *pic) ++{ ++ AVFrame *f = pic->f; ++ printf("######## dump H264Picture #########\n"); ++ ++ printf("dump_picture f:%p\n", f); ++ printf("f->buf[0]: %p\n", f->buf[0]); ++ printf("f->buf[1]: %p\n", f->buf[1]); ++ printf("f->buf[0]->buffer_pa: %lx\n", f->buf[0]->buffer_pa); ++ printf("f->buf[1]->buffer_pa: %lx\n", f->buf[1]->buffer_pa); ++ printf("pic->frame_num: %d\n", pic->frame_num); ++ ++} ++ ++#if 0 ++#include ++#include ++#include ++#endif ++ ++ ++static int decode_slice(struct AVCodecContext *avctx, void *arg) ++{ ++ ++ /*我怎么知é“è¦è§£ç è¿™ä¸€å¸§å›¾ç‰‡ï¼Œä¸æ˜¯å¯¹äºŽB帧的解ç è¦å»¶åŽå¤„ç†å—??? */ ++ H264SliceContext *sl = arg; ++ const H264Context *h = sl->h264; ++ H264Picture *cur_pic = h->cur_pic_ptr; ++ jzm_h264 *st_h264 = h->st_h264; ++ int lf_x_start = sl->mb_x; ++ int orig_deblock = sl->deblocking_filter; ++ int ret; ++ int i; ++ unsigned int offset_y, offset_uv; ++ ++ for(i = 0; i < H264_MAX_PICTURE_COUNT; i++) { ++ if(h->cur_pic_ptr == &h->DPB[i]) ++ break; ++ } ++ ++ ++#if 0 ++ printf("use: %d in DPB\n", i); ++ dump_picture(h->cur_pic_ptr); ++ printf("---decode_slice----\n"); ++ printf("ref_count[0]: %d\n", sl->ref_count[0]); ++ printf("ref_count[1]: %d\n", sl->ref_count[1]); ++ printf("list_count: %d\n", sl->list_count); ++ for(i = 0; i < sl->ref_count[0]; i++) { ++ printf("H264Ref[i] : %x\n", &sl->ref_list[0][i]); ++ } ++#endif ++ ++ if(h->width > h->coded_width || h->height > h->coded_height) { ++ printf("App allocated buffer is too small, which is illegal.\n"); ++ printf("BS parsed width:%d, height:%d, while allocated width: %d, height: %d\n", h->width, h->height, h->coded_width, h->coded_height); ++ return AVERROR(EINVAL); ++ } ++ ++ st_h264->slice_type = (sl->slice_type==AV_PICTURE_TYPE_B) ? JZM_H264_B_TYPE \ ++ :(sl->slice_type==AV_PICTURE_TYPE_P) ? JZM_H264_P_TYPE \ ++ :JZM_H264_I_TYPE; ++ ++ st_h264->slice_num = sl->slice_num-1; ++ st_h264->start_mb_x = sl->mb_x; ++ st_h264->start_mb_y = sl->mb_y; ++ st_h264->mb_width = h->mb_width; ++ st_h264->mb_height = h->mb_height; ++ st_h264->field_picture = sl->picture_structure != PICT_FRAME; ++ st_h264->cabac = h->ps.pps->cabac; ++ st_h264->qscale = sl->qscale; ++ st_h264->transform_8x8_mode = !!h->ps.pps->transform_8x8_mode; ++ st_h264->constrained_intra_pred = !!h->ps.pps->constrained_intra_pred; ++ st_h264->direct_8x8_inference_flag = !!h->ps.sps->direct_8x8_inference_flag; ++ st_h264->direct_spatial_mv_pred = !!sl->direct_spatial_mv_pred; ++ st_h264->x264_build = 0xffff; ++ st_h264->ref_count_0 = sl->ref_count[0] - 1; ++ st_h264->ref_count_1 = sl->ref_count[1] - 1; ++ st_h264->deblocking_filter = !!sl->deblocking_filter; ++ st_h264->slice_alpha_c0_offset = sl->slice_alpha_c0_offset; ++ st_h264->slice_beta_offset = sl->slice_beta_offset; ++ ++ /*sl->gb.buffer 转物ç†åœ°å€. */ ++ //st_h264->bs_buffer = h->pkt.rbsp_buf->buffer_pa + sl->gb.buffer - h->pkt.rbsp_buf->buffer; ++ st_h264->bs_buffer = (unsigned int)sl->gb.buffer & 0x1fffffff; ++ st_h264->bs_index = sl->gb.index; ++ st_h264->bs_size_in_bits = sl->gb.size_in_bits; ++ ++#if 1 /*在M200上需è¦å¤„ç†ä»¥ä¸‹bs_addr,å¦åˆ™ä¼šå‡ºbs_error. ++ 原æ¥media部门æä¾›çš„api在api内部会åšå¤„ç†ï¼ŒçŽ°åœ¨éœ€è¦åœ¨å¤–é¢ä½œå¤„ç†äº†. ++ */ ++ unsigned int bs_addr; ++ unsigned int bs_ofst; ++ if (st_h264->cabac) { ++ int n = (-st_h264->bs_index) & 7; ++ if(n) st_h264->bs_index += n; ++ bs_addr = st_h264->bs_buffer + (st_h264->bs_index >> 3); ++ bs_ofst = (bs_addr & 0x3) << 3; ++ bs_addr = bs_addr & (~0x3); ++ st_h264->bs_rbsp_en = 1; ++ } else { ++ bs_addr = (unsigned int)(st_h264->bs_buffer + (st_h264->bs_index >> 3)) & (~0x3); ++ bs_ofst = ((((unsigned int)st_h264->bs_buffer & 0x3) << 3) + ((unsigned int)st_h264->bs_index & 0x1F)) & 0x1F; ++ unsigned int slice_bs_size = st_h264->bs_size_in_bits - st_h264->bs_index + bs_ofst; ++ //st_h264->bs_size_in_bits = slice_bs_size; ++ ++ char *src, *dst; ++ unsigned long length; ++ int si, di; ++ int removed_bytes = 0; ++ si = di = 0; ++ ++ src = dst = (char*)sl->gb.buffer; ++ length = (sl->gb.size_in_bits + 7) / 8; ++ ++ while (si + 2 < length) { ++ // remove escapes (very rare 1:2^22) ++ if (src[si + 2] > 3) { ++ dst[di++] = src[si++]; ++ dst[di++] = src[si++]; ++ } else if (src[si] == 0 && src[si + 1] == 0 && src[si + 2] == 3) { ++ dst[di++] = 0; ++ dst[di++] = 0; ++ si += 3; ++ } ++ dst[di++] = src[si++]; ++ } ++ ++ while (si < length) ++ dst[di++] = src[si++]; ++ ++ removed_bytes = si - di; ++ ++ st_h264->bs_size_in_bits = slice_bs_size - 8 * removed_bytes; ++ dma_sync_single_for_device(h->devmem_ctx.dev, (dma_addr_t)(virt_to_phys((void *)dst)), di, DMA_TO_DEVICE); ++ ++ st_h264->bs_rbsp_en = 0; ++ } ++ ++ st_h264->bs_buffer = bs_addr; /* slice_header之åŽçš„slice_data*/ ++ st_h264->bs_index = bs_ofst; ++ ++#endif ++ ++ st_h264->cabac_init_idc = sl->cabac_init_idc; ++ if(sl->ref_list[1][0].parent) { ++ st_h264->ref_frm_ctrl = sl->ref_list[1][0].parent->frm_info_ctrl->buffer_pa; ++ } ++ if(sl->ref_list[1][0].parent) { ++ st_h264->ref_frm_mv = sl->ref_list[1][0].parent->frm_info_mv->buffer_pa; ++ } ++ st_h264->curr_frm_ctrl = cur_pic->frm_info_ctrl->buffer_pa; ++ st_h264->curr_frm_mv = cur_pic->frm_info_mv->buffer_pa; ++ ++#if 0 ++ /*新版的api没有这两个å˜é‡.*/ ++ st_h264->curr_frm_slice_start_mb = cur_pic->frm_info_slice_start_mb; ++ st_h264->ref_frm_slice_start_mb = sl->ref_list[1][0].frm_info_slice_start_mb; ++#endif ++ st_h264->use_weight = sl->pwt.use_weight; ++ st_h264->use_weight_chroma = sl->pwt.use_weight_chroma; ++ st_h264->luma_log2_weight_denom = sl->pwt.luma_log2_weight_denom; ++ st_h264->chroma_log2_weight_denom = sl->pwt.chroma_log2_weight_denom; ++ st_h264->dblk_left_en = /*h->s.mb_x!=*/0; ++ st_h264->dblk_top_en = /*h->s.mb_y!=*/0; ++ ++#define ROUND_UP(x, align) (((int) (x) + (align - 1)) & ~(align - 1)) ++ ++ if(h->format == VPU_FORMAT_NV12 || h->format == VPU_FORMAT_NV21) { ++ st_h264->new_odma_flag = 1; /* enable new output dma */ ++ st_h264->new_odma_format = h->format == VPU_FORMAT_NV12 ? 0 : 1; /*0: NV12, 1 : NV21*/ ++ //st_h264->dec_result1_y = cur_pic->f->buf[0]->buffer_pa; ++ //st_h264->dec_result1_uv = cur_pic->f->buf[1]->buffer_pa; ++ st_h264->frm_y_stride = ROUND_UP(h->width, 128); ++ st_h264->frm_c_stride = st_h264->frm_y_stride; ++ ++ offset_y = st_h264->start_mb_y * 16 * st_h264->frm_y_stride + st_h264->start_mb_x * 16; ++ offset_uv = st_h264->start_mb_y * 8 * st_h264->frm_y_stride + st_h264->start_mb_x * 16; ++ st_h264->dec_result1_y = cur_pic->f->buf[0]->buffer_pa + offset_y; ++ st_h264->dec_result1_uv = cur_pic->f->buf[1]->buffer_pa + offset_uv; ++ ++ } else { ++ st_h264->new_odma_flag = 0; ++ } ++ ++ /* see alloc_picture()*/ ++ st_h264->dec_result_y = cur_pic->dec_result_y->buffer_pa; ++ st_h264->dec_result_uv = cur_pic->dec_result_uv->buffer_pa; ++ ++ for (i=0; i<16; i++) { ++ st_h264->dir_scale_table[i] = sl->map_col_to_list0[0][i] + (sl->map_col_to_list0[1][i] << 5) + (sl->dist_scale_factor[i] << 16); ++ } ++ ++ for (i=0; i<128; i++) { ++ ++ unsigned int qp_c0 = h->ps.pps->chroma_qp_table[0][i] & 0xFF; ++ unsigned int qp_c1 = h->ps.pps->chroma_qp_table[1][i] & 0xFF; ++ unsigned int qp_c0_d6 = qp_c0/6; ++ unsigned int qp_c0_m6 = qp_c0%6; ++ unsigned int qp_c1_d6 = qp_c1/6; ++ unsigned int qp_c1_m6 = qp_c1%6; ++ st_h264->chroma_qp_table[i] = ((((((qp_c1_d6 & 0xF) + ((qp_c1_m6 & 0x7) << 4)) << 7) + ++ (((qp_c0_d6 & 0xF) + ((qp_c0_m6 & 0x7) << 4)) << 0) ) << 16) + ++ ((qp_c1 & 0x3F) << 6) + ++ ((qp_c0 & 0x3F) << 0) ++ ); ++ } ++ ++ ++ for (i=0; i<16; i++) { ++ H264Picture *parent; ++ parent = sl->ref_list[0][i].parent; ++ ++ st_h264->mc_ref_y[0][i] = parent ? parent->dec_result_y->buffer_pa: 0; ++ st_h264->mc_ref_c[0][i] = parent ? parent->dec_result_uv->buffer_pa : 0; ++ ++ parent = sl->ref_list[1][i].parent; ++ st_h264->mc_ref_y[1][i] = parent? parent->dec_result_y->buffer_pa : 0; ++ st_h264->mc_ref_c[1][i] = parent? parent->dec_result_uv->buffer_pa : 0; ++ ++ int j; ++ for (j=0; j<2; j++) { ++ st_h264->luma_weight[j][i] = sl->pwt.luma_weight[i][j][0]; ++ st_h264->chroma_weight[j][i][0] = sl->pwt.chroma_weight[i][j][0][0]; ++ st_h264->chroma_weight[j][i][1] = sl->pwt.chroma_weight[i][j][1][0]; ++ st_h264->luma_offset[j][i] = sl->pwt.luma_weight[i][j][1]; ++ st_h264->chroma_offset[j][i][0] = sl->pwt.chroma_weight[i][j][0][1]; ++ st_h264->chroma_offset[j][i][1] = sl->pwt.chroma_weight[i][j][1][1]; ++ } ++ for (j=0; j<16; j++) { ++ st_h264->implicit_weight[i][j] = sl->pwt.implicit_weight[i][j][0]; ++ } ++ } ++ ++ memcpy(st_h264->scaling_matrix4, h->ps.pps->scaling_matrix4, sizeof(h->ps.pps->scaling_matrix4)); ++ memcpy(st_h264->scaling_matrix8, h->ps.pps->scaling_matrix8, sizeof(h->ps.pps->scaling_matrix8)); ++ ++ st_h264->des_va = (int *)h->dma_desc->buffer; ++ ++#if 0 ++ dump_st_h264(h->st_h264); ++ dump_bs_buffer(h->st_h264, st_h264->bs_buffer | 0x80000000, (st_h264->bs_size_in_bits + 7) / 8); ++#endif ++ ++ jzm_h264_slice_init_vdma(st_h264); ++ ++ ++ //memset(st_h264->dec_result_y | 0x80000000, 0, 256); ++ //memset(st_h264->dec_result_uv | 0x80000000, 0, 256); ++ ++ av_buffer_sync((void*)&h->devmem_ctx, h->dma_desc, DMA_TO_DEVICE); ++ //av_buffer_sync(&h->devmem_ctx, h->pkt.rbsp_buf, DMA_TO_DEVICE); ++ ++ ret = vpu_hw_start((void*)&h->vpu_ctx); ++ if(ret < 0) { ++ printf("h->mb_width: %d, h->mb_height: %d, current_decode mb_y: %d, mb_x: %d\n", ++ h->mb_width, h->mb_height, (h->vpu_ctx.sde_stat >> 24) & 0xff, (h->vpu_ctx.sde_stat >> 16) & 0xff); ++ //return AVERROR(EINVAL); ++ } ++ ++ vpu_hw_wait((void*)&h->vpu_ctx); ++ ++ if(h->vpu_ctx.error) { ++ sl->mb_y = h->mb_height; ++ } else { ++ ++ sl->mb_y = (h->vpu_ctx.sde_stat >> 24) & 0xff; ++ } ++// printf("----------decode_slice done ----------------\n"); ++ ++ return ret; ++} ++ ++/** ++ * Call decode_slice() for each context. ++ * ++ * @param h h264 master context ++ */ ++int ff_h264_execute_decode_slices(H264Context *h) ++{ ++ AVCodecContext *const avctx = h->avctx; ++ H264SliceContext *sl; ++ int context_count = h->nb_slice_ctx_queued; ++ int ret = 0; ++ int i, j; ++ ++ ++ h->slice_ctx[0].next_slice_idx = INT_MAX; ++ ++ if (/*h->avctx->hwaccel || */context_count < 1) ++ return 0; ++ ++ av_assert0(context_count && h->slice_ctx[context_count - 1].mb_y < h->mb_height); ++ ++ /* context_count æ˜¯ä¸æ˜¯å¯ä»¥ç†è§£ä¸ºç”±å¤šå°‘个线程or ???*/ ++ if (context_count == 1) { ++ ++ h->slice_ctx[0].next_slice_idx = h->mb_width * h->mb_height; ++ h->postpone_filter = 0; ++ ++ /* 能够到这里说明已ç»ç¡®åˆ‡çš„知é“è¦è§£ç çš„SLICE.*/ ++ ret = decode_slice(avctx, &h->slice_ctx[0]); ++ /*设置当å‰è§£ç åˆ°äº†å“ªä¸€ä¸ªmb*/ ++ h->mb_y = h->slice_ctx[0].mb_y; ++ if (ret < 0) { ++ h->next_output_pic = NULL; ++ goto finish; ++ } ++ } else { ++ av_log(NULL, AV_LOG_ERROR, "too many context in decode queue!\n"); ++ ret = -EINVAL; ++ } ++ ++finish: ++ h->nb_slice_ctx_queued = 0; ++ return ret; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264data.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264data.c +new file mode 100644 +index 000000000..f3a30e4d3 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264data.c +@@ -0,0 +1,114 @@ ++#include "avcodec.h" ++#include "h264dec.h" ++#include "h264data.h" ++ ++const uint8_t ff_h264_golomb_to_pict_type[5] = { ++ AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B, AV_PICTURE_TYPE_I, ++ AV_PICTURE_TYPE_SP, AV_PICTURE_TYPE_SI ++}; ++ ++const uint8_t ff_h264_golomb_to_intra4x4_cbp[48] = { ++ 47, 31, 15, 0, 23, 27, 29, 30, 7, 11, 13, 14, 39, 43, 45, 46, ++ 16, 3, 5, 10, 12, 19, 21, 26, 28, 35, 37, 42, 44, 1, 2, 4, ++ 8, 17, 18, 20, 24, 6, 9, 22, 25, 32, 33, 34, 36, 40, 38, 41 ++}; ++ ++const uint8_t ff_h264_golomb_to_inter_cbp[48] = { ++ 0, 16, 1, 2, 4, 8, 32, 3, 5, 10, 12, 15, 47, 7, 11, 13, ++ 14, 6, 9, 31, 35, 37, 42, 44, 33, 34, 36, 40, 39, 43, 45, 46, ++ 17, 18, 20, 24, 19, 21, 26, 28, 23, 27, 29, 30, 22, 25, 38, 41 ++}; ++ ++const uint8_t ff_h264_chroma_dc_scan[4] = { ++ (0 + 0 * 2) * 16, (1 + 0 * 2) * 16, ++ (0 + 1 * 2) * 16, (1 + 1 * 2) * 16, ++}; ++ ++const uint8_t ff_h264_chroma422_dc_scan[8] = { ++ (0 + 0 * 2) * 16, (0 + 1 * 2) * 16, ++ (1 + 0 * 2) * 16, (0 + 2 * 2) * 16, ++ (0 + 3 * 2) * 16, (1 + 1 * 2) * 16, ++ (1 + 2 * 2) * 16, (1 + 3 * 2) * 16, ++}; ++ ++const uint8_t ff_h264_dequant4_coeff_init[6][3] = { ++ { 10, 13, 16 }, ++ { 11, 14, 18 }, ++ { 13, 16, 20 }, ++ { 14, 18, 23 }, ++ { 16, 20, 25 }, ++ { 18, 23, 29 }, ++}; ++ ++const uint8_t ff_h264_dequant8_coeff_init_scan[16] = { ++ 0, 3, 4, 3, 3, 1, 5, 1, 4, 5, 2, 5, 3, 1, 5, 1 ++}; ++ ++const uint8_t ff_h264_dequant8_coeff_init[6][6] = { ++ { 20, 18, 32, 19, 25, 24 }, ++ { 22, 19, 35, 21, 28, 26 }, ++ { 26, 23, 42, 24, 33, 31 }, ++ { 28, 25, 45, 26, 35, 33 }, ++ { 32, 28, 51, 30, 40, 38 }, ++ { 36, 32, 58, 34, 46, 43 }, ++}; ++ ++const uint8_t ff_h264_quant_rem6[QP_MAX_NUM + 1] = { ++ 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, ++ 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, ++ 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, ++ 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, ++ 0, 1, 2, 3, ++}; ++ ++const uint8_t ff_h264_quant_div6[QP_MAX_NUM + 1] = { ++ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, ++ 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, ++ 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, ++ 10,10,10,11,11,11,11,11,11,12,12,12,12,12,12,13,13,13, 13, 13, 13, ++ 14,14,14,14, ++}; ++ ++#define QP(qP, depth) ((qP) + 6 * ((depth) - 8)) ++ ++#define CHROMA_QP_TABLE_END(d) \ ++ QP(0, d), QP(1, d), QP(2, d), QP(3, d), QP(4, d), QP(5, d), \ ++ QP(6, d), QP(7, d), QP(8, d), QP(9, d), QP(10, d), QP(11, d), \ ++ QP(12, d), QP(13, d), QP(14, d), QP(15, d), QP(16, d), QP(17, d), \ ++ QP(18, d), QP(19, d), QP(20, d), QP(21, d), QP(22, d), QP(23, d), \ ++ QP(24, d), QP(25, d), QP(26, d), QP(27, d), QP(28, d), QP(29, d), \ ++ QP(29, d), QP(30, d), QP(31, d), QP(32, d), QP(32, d), QP(33, d), \ ++ QP(34, d), QP(34, d), QP(35, d), QP(35, d), QP(36, d), QP(36, d), \ ++ QP(37, d), QP(37, d), QP(37, d), QP(38, d), QP(38, d), QP(38, d), \ ++ QP(39, d), QP(39, d), QP(39, d), QP(39, d) ++ ++const uint8_t ff_h264_chroma_qp[7][QP_MAX_NUM + 1] = { ++ { CHROMA_QP_TABLE_END(8) }, ++ { 0, 1, 2, 3, 4, 5, ++ CHROMA_QP_TABLE_END(9) }, ++ { 0, 1, 2, 3, 4, 5, ++ 6, 7, 8, 9, 10, 11, ++ CHROMA_QP_TABLE_END(10) }, ++ { 0, 1, 2, 3, 4, 5, ++ 6, 7, 8, 9, 10, 11, ++ 12,13,14,15, 16, 17, ++ CHROMA_QP_TABLE_END(11) }, ++ { 0, 1, 2, 3, 4, 5, ++ 6, 7, 8, 9, 10, 11, ++ 12,13,14,15, 16, 17, ++ 18,19,20,21, 22, 23, ++ CHROMA_QP_TABLE_END(12) }, ++ { 0, 1, 2, 3, 4, 5, ++ 6, 7, 8, 9, 10, 11, ++ 12,13,14,15, 16, 17, ++ 18,19,20,21, 22, 23, ++ 24,25,26,27, 28, 29, ++ CHROMA_QP_TABLE_END(13) }, ++ { 0, 1, 2, 3, 4, 5, ++ 6, 7, 8, 9, 10, 11, ++ 12,13,14,15, 16, 17, ++ 18,19,20,21, 22, 23, ++ 24,25,26,27, 28, 29, ++ 30,31,32,33, 34, 35, ++ CHROMA_QP_TABLE_END(14) }, ++}; +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264dec.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264dec.c +new file mode 100644 +index 000000000..c458e0066 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/h264dec.c +@@ -0,0 +1,613 @@ ++#include "avassert.h" ++#include "avcodec.h" ++#include "h264.h" ++#include "h264dec.h" ++#include "h2645_parse.h" ++#include "h264data.h" ++#include "h264_ps.h" ++#include "golomb.h" ++#include "mathops.h" ++ ++ ++/** ++ * Init context ++ * Allocate buffers which are not shared amongst multiple threads. ++ */ ++ ++AVFrame *h264_dequeue_frame(H264Context *h) ++{ ++ int index = 0; ++ AVFrame *f = NULL; ++ ++ f = list_first_entry_or_null(&h->done_list, AVFrame, done_entry); ++ ++ if(!f) { ++ return NULL; ++ } ++ ++ /*remove picture from output picture list.*/ ++ list_del(&f->done_entry); ++ ++ /*返回AVFrame.*/ ++ return f; ++} ++ ++int h264_enqueue_frame(H264Context *h, AVFrame *f) ++{ ++ INIT_LIST_HEAD(&f->queued_entry); ++ ++ list_add_tail(&f->queued_entry, &h->queued_list); ++ f->queued = 1; ++ ++ return 0; ++} ++ ++AVFrame * h264_get_queued_frame(H264Context *h) ++{ ++ AVFrame *f = NULL; ++ int i; ++ ++ /* 1. AVFrame From DPB, which is in processing. */ ++ for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) { ++ f = h->DPB[i].f; ++ if(f && f->queued) { ++ f->queued = 0; ++ return f; ++ } ++ } ++ ++ f = list_first_entry_or_null(&h->queued_list, AVFrame, queued_entry); ++ if(!f) { ++ return NULL; ++ } ++ ++ /*remove picture from output picture list.*/ ++ list_del(&f->queued_entry); ++ ++ return f; ++} ++ ++static int h264_init_context(AVCodecContext *avctx, H264Context *h) ++{ ++ int i; ++ int ret; ++ ++ h->avctx = avctx; ++ h->cur_chroma_format_idc = -1; ++ ++ h->width_from_caller = avctx->width; ++ h->height_from_caller = avctx->height; ++ h->format = VPU_FORMAT_TILE420; ++ ++ h->picture_structure = PICT_FRAME; ++ ++ h->flags = avctx->flags; ++ h->poc.prev_poc_msb = 1 << 16; ++ h->recovery_frame = -1; ++ h->frame_recovered = 0; ++ h->poc.prev_frame_num = -1; ++ ++ h->next_outputed_poc = INT_MIN; ++ for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++) ++ h->last_pocs[i] = INT_MIN; ++ ++ h->nb_slice_ctx = 1; ++ h->slice_ctx = av_mallocz_array(h->nb_slice_ctx, sizeof(*h->slice_ctx)); ++ if (!h->slice_ctx) { ++ h->nb_slice_ctx = 0; ++ return AVERROR(ENOMEM); ++ } ++ ++ for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) { ++ h->DPB[i].f = NULL; ++ } ++ ++ ++ ret = devmem_ctx_init(&h->devmem_ctx, NULL); ++ if(ret < 0) { ++ return AVERROR(EINVAL); ++ } ++ ++ ++ h->st_h264 = av_mallocz(sizeof(*h->st_h264)); ++ if(!h->st_h264) ++ return AVERROR(ENOMEM); ++ ++ h->dma_desc = av_buffer_alloc(&h->devmem_ctx, DMA_DESC_SIZE); ++ if(!h->dma_desc) ++ return AVERROR(ENOMEM); ++ memset(h->dma_desc->buffer, 0, DMA_DESC_SIZE); ++ ++ ret = vpu_ctx_init(&h->vpu_ctx); ++ if(ret < 0) ++ return AVERROR(EINVAL); ++ h->vpu_ctx.desc_va = h->dma_desc->buffer; ++ h->vpu_ctx.desc_pa = h->dma_desc->buffer_pa; ++ ++ for (i = 0; i < h->nb_slice_ctx; i++) ++ h->slice_ctx[i].h264 = h; ++ ++ INIT_LIST_HEAD(&h->done_list); ++ INIT_LIST_HEAD(&h->queued_list); ++ ++ return 0; ++} ++ ++extern void av_buffer_dump(void); ++int h264_decode_end(AVCodecContext *avctx) ++{ ++ H264Context *h = avctx->priv_data; ++ int i; ++ ++ ff_h264_remove_all_refs(h); ++ ++ for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) { ++ ff_h264_unref_picture(h, &h->DPB[i]); ++ ff_h264_release_picture(h, &h->DPB[i]); ++ } ++ memset(h->delayed_pic, 0, sizeof(h->delayed_pic)); ++ ++ h->cur_pic_ptr = NULL; ++ ++ av_freep(&h->slice_ctx); ++ h->nb_slice_ctx = 0; ++ ++ av_buffer_free(&h->devmem_ctx, h->dma_desc); ++ ++ av_free(h->st_h264); ++ ++ ++#if 0 ++ ff_h264_sei_uninit(&h->sei); ++#endif ++ ff_h264_ps_uninit(&h->ps); ++ ++ ff_h2645_packet_uninit(&h->pkt); ++ ++ vpu_ctx_uninit(&h->vpu_ctx); ++ devmem_ctx_uninit(&h->devmem_ctx); ++ ++ av_buffer_dump(); ++ ++ return 0; ++} ++ ++//static AVOnce h264_vlc_init = AV_ONCE_INIT; ++ ++int h264_decode_init(AVCodecContext *avctx) ++{ ++ H264Context *h = avctx->priv_data; ++ int ret; ++ ++ ret = h264_init_context(avctx, h); ++ if (ret < 0) ++ return ret; ++ ++ ff_h264_flush_change(h); ++ ++ av_log(avctx, AV_LOG_ERROR, "h264_decode_init done!\n"); ++ ++ return 0; ++} ++ ++int h264_set_vpu_ops(H264Context *h, void *priv_data, struct vpu_ops *ops) ++{ ++ return vpu_ctx_set_ops(&h->vpu_ctx, priv_data, ops); ++} ++ ++/** ++ * instantaneous decoder refresh. ++ */ ++static void idr(H264Context *h) ++{ ++ int i; ++ ff_h264_remove_all_refs(h); ++ h->poc.prev_frame_num = ++ h->poc.prev_frame_num_offset = 0; ++ h->poc.frame_num= 0; ++ h->poc.prev_poc_msb = 1<<16; ++ h->poc.prev_poc_lsb = 0; ++ for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++) ++ h->last_pocs[i] = INT_MIN; ++} ++ ++/* forget old pics after a seek */ ++void ff_h264_flush_change(H264Context *h) ++{ ++ int i, j; ++ ++ h->next_outputed_poc = INT_MIN; ++ h->prev_interlaced_frame = 1; ++ idr(h); ++ ++ h->poc.prev_frame_num = -1; ++ if (h->cur_pic_ptr) { ++ h->cur_pic_ptr->reference = 0; ++ for (j=i=0; h->delayed_pic[i]; i++) ++ if (h->delayed_pic[i] != h->cur_pic_ptr) ++ h->delayed_pic[j++] = h->delayed_pic[i]; ++ h->delayed_pic[j] = NULL; ++ } ++ ++ h->first_field = 0; ++ h->recovery_frame = -1; ++ h->frame_recovered = 0; ++ h->current_slice = 0; ++ h->mmco_reset = 1; ++} ++ ++/* forget old pics after a seek */ ++static void flush_dpb(AVCodecContext *avctx) ++{ ++ H264Context *h = avctx->priv_data; ++ int i; ++ ++ memset(h->delayed_pic, 0, sizeof(h->delayed_pic)); ++ ++ ff_h264_flush_change(h); ++#if 0 ++ ff_h264_sei_uninit(&h->sei); ++#endif ++ ++ for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) ++ ff_h264_unref_picture(h, &h->DPB[i]); ++ h->cur_pic_ptr = NULL; ++ ++ h->mb_y = 0; ++ ++ h->context_initialized = 0; ++} ++ ++static int get_last_needed_nal(H264Context *h) ++{ ++ int nals_needed = 0; ++ int first_slice = 0; ++ int i, ret; ++ ++ for (i = 0; i < h->pkt.nb_nals; i++) { ++ H2645NAL *nal = &h->pkt.nals[i]; ++ GetBitContext gb; ++ ++ /* packets can sometimes contain multiple PPS/SPS, ++ * e.g. two PAFF field pictures in one packet, or a demuxer ++ * which splits NALs strangely if so, when frame threading we ++ * can't start the next thread until we've read all of them */ ++ switch (nal->type) { ++ case H264_NAL_SPS: ++ case H264_NAL_PPS: ++ nals_needed = i; ++ break; ++ case H264_NAL_DPA: ++ case H264_NAL_IDR_SLICE: ++ case H264_NAL_SLICE: ++ ret = init_get_bits8(&gb, nal->data + 1, nal->size - 1); ++ if (ret < 0) { ++ av_log(h->avctx, AV_LOG_ERROR, "Invalid zero-sized VCL NAL unit\n"); ++ if (h->avctx->err_recognition & AV_EF_EXPLODE) ++ return ret; ++ ++ break; ++ } ++ if (!get_ue_golomb_long(&gb) || // first_mb_in_slice ++ !first_slice || ++ first_slice != nal->type) ++ nals_needed = i; ++ if (!first_slice) ++ first_slice = nal->type; ++ } ++ } ++ ++ return nals_needed; ++} ++ ++static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) ++{ ++ AVCodecContext *const avctx = h->avctx; ++ int nals_needed = 0; ///< number of NALs that need decoding before the next frame thread starts ++ int idr_cleared=0; ++ int i, ret = 0; ++ ++ h->has_slice = 0; ++ h->nal_unit_type= 0; ++ ++#if 0 ++ h->current_slice = 0; ++ if (!h->first_field) { ++ h->cur_pic_ptr = NULL; ++ ff_h264_sei_uninit(&h->sei); ++ } ++#endif ++ ++#if 0 ++ if (h->nal_length_size == 4) { ++ if (buf_size > 8 && AV_RB32(buf) == 1 && AV_RB32(buf+5) > (unsigned)buf_size) { ++ h->is_avc = 0; ++ }else if(buf_size > 3 && AV_RB32(buf) > 1 && AV_RB32(buf) <= (unsigned)buf_size) ++ h->is_avc = 1; ++ } ++#endif ++ ret = ff_h2645_packet_split(&h->pkt, buf, buf_size, avctx, 0, ++ h->nal_length_size, 0); ++ if (ret < 0) { ++ av_log(avctx, AV_LOG_ERROR, ++ "Error splitting the input into NAL units.\n"); ++ return ret; ++ } ++ ++ if (nals_needed < 0) ++ return nals_needed; ++ ++ for (i = 0; i < h->pkt.nb_nals; i++) { ++ H2645NAL *nal = &h->pkt.nals[i]; ++ int max_slice_ctx, err; ++ // FIXME these should stop being context-global variables ++ h->nal_ref_idc = nal->ref_idc; ++ h->nal_unit_type = nal->type; ++ ++ err = 0; ++ switch (nal->type) { ++ case H264_NAL_IDR_SLICE: ++ if ((nal->data[1] & 0xFC) == 0x98) { ++ av_log(h->avctx, AV_LOG_ERROR, "Invalid inter IDR frame\n"); ++ h->next_outputed_poc = INT_MIN; ++ ret = -1; ++ goto end; ++ } ++ if(!idr_cleared) { ++ idr(h); // FIXME ensure we don't lose some frames if there is reordering ++ } ++ idr_cleared = 1; ++ h->has_recovery_point = 1; ++ case H264_NAL_SLICE: ++ h->has_slice = 1; ++ ++ /* current_slice = 0 的。。。*/ ++ if ((err = ff_h264_queue_decode_slice(h, nal))) { ++ /*如果入队出错, å°† ref_count都清0.*/ ++ H264SliceContext *sl = h->slice_ctx + h->nb_slice_ctx_queued; ++ sl->ref_count[0] = sl->ref_count[1] = 0; ++ break; ++ } ++ ++ ++ if((ret = ff_h264_execute_decode_slices(h)) < 0) { ++ flush_dpb(h->avctx); ++ printk("===============%s, %d, ret:%d\n", __func__, __LINE__, ret); ++ goto end; ++ } ++ break; ++ case H264_NAL_DPA: ++ case H264_NAL_DPB: ++ case H264_NAL_DPC: ++ av_log(avctx, AV_LOG_ERROR, "data partitioning"); ++ break; ++ case H264_NAL_SEI: ++#if 0 ++ ret = ff_h264_sei_decode(&h->sei, &nal->gb, &h->ps, avctx); ++ h->has_recovery_point = h->has_recovery_point || h->sei.recovery_point.recovery_frame_cnt != -1; ++#endif ++#if 0 ++ if (avctx->debug & FF_DEBUG_GREEN_MD) ++ debug_green_metadata(&h->sei.green_metadata, h->avctx); ++#endif ++#if 0 ++ if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) ++ goto end; ++#endif ++ break; ++ case H264_NAL_SPS: { ++ GetBitContext tmp_gb = nal->gb; ++ ++ if (ff_h264_decode_seq_parameter_set(&tmp_gb, avctx, &h->ps, 0) >= 0) ++ break; ++ ++ av_log(h->avctx, AV_LOG_DEBUG, ++ "SPS decoding failure, trying again with the complete NAL\n"); ++ init_get_bits8(&tmp_gb, nal->raw_data + 1, nal->raw_size - 1); ++ if (ff_h264_decode_seq_parameter_set(&tmp_gb, avctx, &h->ps, 0) >= 0) ++ break; ++ ff_h264_decode_seq_parameter_set(&nal->gb, avctx, &h->ps, 1); ++ break; ++ } ++ case H264_NAL_PPS: ++ ret = ff_h264_decode_picture_parameter_set(&nal->gb, avctx, &h->ps, ++ nal->size_bits); ++ ++ if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) ++ goto end; ++ break; ++ case H264_NAL_AUD: ++ case H264_NAL_END_SEQUENCE: ++ case H264_NAL_END_STREAM: ++ case H264_NAL_FILLER_DATA: ++ case H264_NAL_SPS_EXT: ++ case H264_NAL_AUXILIARY_SLICE: ++ break; ++ default: ++ av_log(avctx, AV_LOG_DEBUG, "Unknown NAL code: %d (%d bits)\n", ++ nal->type, nal->size_bits); ++ } ++ ++ if (err < 0) { ++ av_log(h->avctx, AV_LOG_ERROR, "decode_slice_header error\n"); ++ ret = AVERROR_INVALIDDATA; ++ goto end; ++ } ++ } ++ ++#if 0 ++ ret = ff_h264_execute_decode_slices(h); ++ if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) ++ goto end; ++#endif ++ ret = 0; ++end: ++ return (ret < 0) ? ret : buf_size; ++} ++ ++/** ++ * Return the number of bytes consumed for building the current frame. ++ */ ++static int get_consumed_bytes(int pos, int buf_size) ++{ ++ if (pos == 0) ++ pos = 1; // avoid infinite loops (I doubt that is needed but...) ++ if (pos + 10 > buf_size) ++ pos = buf_size; // oops ;) ++ ++ return pos; ++} ++ ++static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp) ++{ ++ ++ AVFrame *f = srcp->f; ++ ++ f->queued = 0; ++ INIT_LIST_HEAD(&f->done_entry); ++ ++ list_add_tail(&f->done_entry, &h->done_list); ++ ++ if(dst) { ++ memcpy(dst, f, sizeof(AVFrame)); ++ } ++ return 0; ++} ++ ++static int is_extra(const uint8_t *buf, int buf_size) ++{ ++ int cnt= buf[5]&0x1f; ++ const uint8_t *p= buf+6; ++ if (!cnt) ++ return 0; ++ while(cnt--){ ++ int nalsize= AV_RB16(p) + 2; ++ if(nalsize > buf_size - (p-buf) || (p[2] & 0x9F) != 7) ++ return 0; ++ p += nalsize; ++ } ++ cnt = *(p++); ++ if(!cnt) ++ return 0; ++ while(cnt--){ ++ int nalsize= AV_RB16(p) + 2; ++ if(nalsize > buf_size - (p-buf) || (p[2] & 0x9F) != 8) ++ return 0; ++ p += nalsize; ++ } ++ return 1; ++} ++ ++static int finalize_frame(H264Context *h, AVFrame *dst, H264Picture *out, int *got_frame) ++{ ++ int ret; ++ ++ if(out->recovered) { ++ ++ ret = output_frame(h, dst, out); ++ if (ret < 0) ++ return ret; ++ ++ *got_frame = 1; ++ } ++ ++ return 0; ++} ++ ++static int send_next_delayed_frame(H264Context *h, AVFrame *dst_frame, ++ int *got_frame, int buf_index) ++{ ++ int ret, i, out_idx; ++ H264Picture *out = h->delayed_pic[0]; ++ ++ h->cur_pic_ptr = NULL; ++ h->first_field = 0; ++ ++ out_idx = 0; ++ for (i = 1; ++ h->delayed_pic[i] && ++ !h->delayed_pic[i]->f->key_frame && ++ !h->delayed_pic[i]->mmco_reset; ++ i++) ++ if (h->delayed_pic[i]->poc < out->poc) { ++ out = h->delayed_pic[i]; ++ out_idx = i; ++ } ++ ++ for (i = out_idx; h->delayed_pic[i]; i++) ++ h->delayed_pic[i] = h->delayed_pic[i + 1]; ++ ++ if (out) { ++ out->reference &= ~DELAYED_PIC_REF; ++ ret = finalize_frame(h, dst_frame, out, got_frame); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return buf_index; ++} ++ ++/** ++ * @brief è§£ç ä¸€ä¸ªpacket中包å«çš„帧数æ®,有å¯èƒ½æœ‰æ•°æ®ï¼Œæœ‰å¯èƒ½æ²¡æœ‰.通过got_frame指示. ++ * ++ * @param avctx 奿Ÿ„ ++ * @param data 输出buffer. ++ * @param got_frame æ˜¯å¦æœ‰æ•°æ® ++ * @param avpkt 输入数æ®. ++ * ++ * @return <0,解ç å‡ºé”™ >=0 返回消耗的数æ®é•¿åº¦. ++ */ ++int h264_decode_frame(AVCodecContext *avctx, void *data, ++ int *got_frame, AVPacket *avpkt) ++{ ++ const uint8_t *buf = avpkt->data; /* ç æµåœ°å€*/ ++ int buf_size = avpkt->size; /* ç æµå¤§å°*/ ++ H264Context *h = avctx->priv_data; ++ AVFrame *pict = data; /*è§£ç åˆ°çš„buffer.*/ ++ int buf_index; ++ int ret; ++ ++ h->flags = avctx->flags; ++ h->setup_finished = 0; ++ h->nb_slice_ctx_queued = 0; ++ ++ /* end of stream, output what is still in the buffers */ ++ if (buf_size == 0) ++ return send_next_delayed_frame(h, pict, got_frame, 0); /*为什么å«åšdelayed_frame, 䏿˜Žç™½. */ ++ ++ /* *************é‡ç‚¹å¤„ç†çš„内容 *******/ ++ buf_index = decode_nal_units(h, buf, buf_size); ++ if (buf_index < 0) ++ return AVERROR_INVALIDDATA; ++ ++ if (!h->cur_pic_ptr && h->nal_unit_type == H264_NAL_END_SEQUENCE) { ++ av_assert0(buf_index <= buf_size); ++ return send_next_delayed_frame(h, pict, got_frame, buf_index); ++ } ++ ++ ++#if 0 ++ if ((!h->cur_pic_ptr || !h->has_slice)) { ++ if (/*avctx->skip_frame >= AVDISCARD_NONREF ||*/ ++ buf_size >= 4 && !memcmp("Q264", buf, 4)) ++ return buf_size; ++ av_log(avctx, AV_LOG_ERROR, "no frame!\n"); ++ return AVERROR_INVALIDDATA; ++ } ++#endif ++ ++ ++ if(h->mb_y >= h->mb_height && h->mb_height) { ++ if ((ret = ff_h264_field_end(h, &h->slice_ctx[0], 0)) < 0) ++ return ret; ++ ++ if (h->next_output_pic) { ++ ret = finalize_frame(h, pict, h->next_output_pic, got_frame); ++ if (ret < 0) ++ return ret; ++ } ++ } ++ ++ return get_consumed_bytes(buf_index, buf_size); ++} ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/hexdump.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/hexdump.c +new file mode 100644 +index 000000000..1d91aa534 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/hexdump.c +@@ -0,0 +1,13 @@ ++ ++void hexdump(unsigned char *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) { ++ if ((i % 16) == 0) ++ printf("%s%08x: ", i ? "\n" : "", ++ (unsigned int)&buf[i]); ++ printf("%02x ", buf[i]); ++ } ++ printf("\n"); ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/log.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/log.c +new file mode 100644 +index 000000000..c1d544651 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/log.c +@@ -0,0 +1,108 @@ ++//#include "config.h" ++ ++#ifdef __KERNEL__ ++#else ++#include ++#include ++#endif ++#include "common.h" ++//#include "internal.h" ++#include "log.h" ++ ++ ++#define LINE_SZ 1024 ++ ++ ++static int av_log_level = AV_LOG_INFO; ++static int flags; ++ ++#define MAX_LOG_BUFFER_SIZE 1024 ++unsigned char print_buffer[MAX_LOG_BUFFER_SIZE]; ++void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) ++{ ++ int n = 0; ++ n = vsprintf(print_buffer, fmt, vl); ++ if(n > MAX_LOG_BUFFER_SIZE) { ++ printf("%s,%d, log too large.!\n", __func__, __LINE__); ++ return; ++ } ++ ++ if(level < av_log_level) ++ printf(print_buffer); ++} ++ ++static void (*av_log_callback)(void*, int, const char*, va_list) = ++ av_log_default_callback; ++ ++void av_log(void* avcl, int level, const char *fmt, ...) ++{ ++ va_list vl; ++ va_start(vl, fmt); ++ av_vlog(avcl, level, fmt, vl); ++ va_end(vl); ++} ++ ++void av_vlog(void* avcl, int level, const char *fmt, va_list vl) ++{ ++ void (*log_callback)(void*, int, const char*, va_list) = av_log_callback; ++ if (log_callback) ++ log_callback(avcl, level, fmt, vl); ++} ++ ++int av_log_get_level(void) ++{ ++ return av_log_level; ++} ++ ++void av_log_set_level(int level) ++{ ++ av_log_level = level; ++} ++ ++void av_log_set_flags(int arg) ++{ ++ flags = arg; ++} ++ ++int av_log_get_flags(void) ++{ ++ return flags; ++} ++ ++void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)) ++{ ++ av_log_callback = callback; ++ ++} ++ ++static void missing_feature_sample(int sample, void *avc, const char *msg, ++ va_list argument_list) ++{ ++ av_vlog(avc, AV_LOG_WARNING, msg, argument_list); ++ av_log(avc, AV_LOG_WARNING, " is not implemented. Update your FFmpeg " ++ "version to the newest one from Git. If the problem still " ++ "occurs, it means that your file has a feature which has not " ++ "been implemented.\n"); ++ if (sample) ++ av_log(avc, AV_LOG_WARNING, "If you want to help, upload a sample " ++ "of this file to ftp://upload.ffmpeg.org/incoming/ " ++ "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n"); ++} ++ ++void avpriv_request_sample(void *avc, const char *msg, ...) ++{ ++ va_list argument_list; ++ ++ va_start(argument_list, msg); ++ missing_feature_sample(1, avc, msg, argument_list); ++ va_end(argument_list); ++} ++ ++void avpriv_report_missing_feature(void *avc, const char *msg, ...) ++{ ++ va_list argument_list; ++ ++ va_start(argument_list, msg); ++ missing_feature_sample(0, avc, msg, argument_list); ++ va_end(argument_list); ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/mathtables.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/mathtables.c +new file mode 100644 +index 000000000..fd5da07ee +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/mathtables.c +@@ -0,0 +1,98 @@ ++#ifdef __KERNEL__ ++#include ++#else ++#include ++#endif ++ ++#include "mathops.h" ++ ++/* a*inverse[b]>>32 == a/b for all 0<=a<=16909558 && 2<=b<=256 ++ * for a>16909558, is an overestimate by less than 1 part in 1<<24 */ ++const uint32_t ff_inverse[257]={ ++ 0, 4294967295U,2147483648U,1431655766, 1073741824, 858993460, 715827883, 613566757, ++ 536870912, 477218589, 429496730, 390451573, 357913942, 330382100, 306783379, 286331154, ++ 268435456, 252645136, 238609295, 226050911, 214748365, 204522253, 195225787, 186737709, ++ 178956971, 171798692, 165191050, 159072863, 153391690, 148102321, 143165577, 138547333, ++ 134217728, 130150525, 126322568, 122713352, 119304648, 116080198, 113025456, 110127367, ++ 107374183, 104755300, 102261127, 99882961, 97612894, 95443718, 93368855, 91382283, ++ 89478486, 87652394, 85899346, 84215046, 82595525, 81037119, 79536432, 78090315, ++ 76695845, 75350304, 74051161, 72796056, 71582789, 70409300, 69273667, 68174085, ++ 67108864, 66076420, 65075263, 64103990, 63161284, 62245903, 61356676, 60492498, ++ 59652324, 58835169, 58040099, 57266231, 56512728, 55778797, 55063684, 54366675, ++ 53687092, 53024288, 52377650, 51746594, 51130564, 50529028, 49941481, 49367441, ++ 48806447, 48258060, 47721859, 47197443, 46684428, 46182445, 45691142, 45210183, ++ 44739243, 44278014, 43826197, 43383509, 42949673, 42524429, 42107523, 41698712, ++ 41297763, 40904451, 40518560, 40139882, 39768216, 39403370, 39045158, 38693400, ++ 38347923, 38008561, 37675152, 37347542, 37025581, 36709123, 36398028, 36092163, ++ 35791395, 35495598, 35204650, 34918434, 34636834, 34359739, 34087043, 33818641, ++ 33554432, 33294321, 33038210, 32786010, 32537632, 32292988, 32051995, 31814573, ++ 31580642, 31350127, 31122952, 30899046, 30678338, 30460761, 30246249, 30034737, ++ 29826162, 29620465, 29417585, 29217465, 29020050, 28825284, 28633116, 28443493, ++ 28256364, 28071682, 27889399, 27709467, 27531842, 27356480, 27183338, 27012373, ++ 26843546, 26676816, 26512144, 26349493, 26188825, 26030105, 25873297, 25718368, ++ 25565282, 25414008, 25264514, 25116768, 24970741, 24826401, 24683721, 24542671, ++ 24403224, 24265352, 24129030, 23994231, 23860930, 23729102, 23598722, 23469767, ++ 23342214, 23216040, 23091223, 22967740, 22845571, 22724695, 22605092, 22486740, ++ 22369622, 22253717, 22139007, 22025474, 21913099, 21801865, 21691755, 21582751, ++ 21474837, 21367997, 21262215, 21157475, 21053762, 20951060, 20849356, 20748635, ++ 20648882, 20550083, 20452226, 20355296, 20259280, 20164166, 20069941, 19976593, ++ 19884108, 19792477, 19701685, 19611723, 19522579, 19434242, 19346700, 19259944, ++ 19173962, 19088744, 19004281, 18920561, 18837576, 18755316, 18673771, 18592933, ++ 18512791, 18433337, 18354562, 18276457, 18199014, 18122225, 18046082, 17970575, ++ 17895698, 17821442, 17747799, 17674763, 17602325, 17530479, 17459217, 17388532, ++ 17318417, 17248865, 17179870, 17111424, 17043522, 16976156, 16909321, 16843010, ++ 16777216 ++}; ++ ++const uint8_t ff_sqrt_tab[256]={ ++ 0, 16, 23, 28, 32, 36, 40, 43, 46, 48, 51, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 77, 79, 80, 82, 84, 85, 87, 88, 90, ++ 91, 92, 94, 95, 96, 98, 99,100,102,103,104,105,107,108,109,110,111,112,114,115,116,117,118,119,120,121,122,123,124,125,126,127, ++128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,144,145,146,147,148,149,150,151,151,152,153,154,155,156,156, ++157,158,159,160,160,161,162,163,164,164,165,166,167,168,168,169,170,171,171,172,173,174,174,175,176,176,177,178,179,179,180,181, ++182,182,183,184,184,185,186,186,187,188,188,189,190,190,191,192,192,193,194,194,195,196,196,197,198,198,199,200,200,201,202,202, ++203,204,204,205,205,206,207,207,208,208,209,210,210,211,212,212,213,213,214,215,215,216,216,217,218,218,219,219,220,220,221,222, ++222,223,223,224,224,225,226,226,227,227,228,228,229,230,230,231,231,232,232,233,233,234,235,235,236,236,237,237,238,238,239,239, ++240,240,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255,255,255 ++}; ++ ++#define times4(x) x, x, x, x ++#define times256(x) times4(times4(times4(times4(times4(x))))) ++ ++const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP] = { ++times256(0x00), ++0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, ++0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, ++0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, ++0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, ++0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, ++0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, ++0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, ++0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, ++0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, ++0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, ++0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, ++0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, ++0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, ++0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, ++0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, ++0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, ++times256(0xFF) ++}; ++ ++const uint8_t ff_zigzag_direct[64] = { ++ 0, 1, 8, 16, 9, 2, 3, 10, ++ 17, 24, 32, 25, 18, 11, 4, 5, ++ 12, 19, 26, 33, 40, 48, 41, 34, ++ 27, 20, 13, 6, 7, 14, 21, 28, ++ 35, 42, 49, 56, 57, 50, 43, 36, ++ 29, 22, 15, 23, 30, 37, 44, 51, ++ 58, 59, 52, 45, 38, 31, 39, 46, ++ 53, 60, 61, 54, 47, 55, 62, 63 ++}; ++ ++const uint8_t ff_zigzag_scan[16+1] = { ++ 0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4, ++ 1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4, ++ 1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4, ++ 3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4, ++}; +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/mem.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/mem.c +new file mode 100644 +index 000000000..d0dadb208 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/mem.c +@@ -0,0 +1,311 @@ ++//#include "config.h" ++ ++#ifdef __KERNEL__ ++#include ++#define malloc(size) kmalloc(size, GFP_KERNEL) ++#define realloc(ptr, size) krealloc(ptr, size, GFP_KERNEL) ++#define free(ptr) kfree(ptr) ++ ++#else ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++#include "avassert.h" ++//#include "avutil.h" ++#include "common.h" ++//#include "dynarray.h" ++//#include "intreadwrite.h" ++#include "mem.h" ++ ++#if 0 ++#ifdef MALLOC_PREFIX ++ ++#define malloc AV_JOIN(MALLOC_PREFIX, malloc) ++#define memalign AV_JOIN(MALLOC_PREFIX, memalign) ++#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign) ++#define realloc AV_JOIN(MALLOC_PREFIX, realloc) ++#define free AV_JOIN(MALLOC_PREFIX, free) ++ ++void *malloc(size_t size); ++void *memalign(size_t align, size_t size); ++int posix_memalign(void **ptr, size_t align, size_t size); ++void *realloc(void *ptr, size_t size); ++void free(void *ptr); ++ ++#endif /* MALLOC_PREFIX */ ++#endif ++ ++ ++ ++/* NOTE: if you want to override these functions with your own ++ * implementations (not recommended) you have to link libav* as ++ * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags. ++ * Note that this will cost performance. */ ++ ++static size_t max_alloc_size= INT_MAX; ++ ++void av_max_alloc(size_t max){ ++ max_alloc_size = max; ++} ++ ++void *av_malloc(size_t size) ++{ ++ void *ptr = NULL; ++ ++ /* let's disallow possibly ambiguous cases */ ++ if (size > (max_alloc_size - 32)) ++ return NULL; ++ ++ ptr = malloc(size); ++ ++ if(!ptr && !size) { ++ size = 1; ++ ptr= av_malloc(1); ++ } ++ ++ return ptr; ++} ++ ++void *av_realloc(void *ptr, size_t size) ++{ ++ /* let's disallow possibly ambiguous cases */ ++ if (size > (max_alloc_size - 32)) ++ return NULL; ++ ++ return realloc(ptr, size + !size); ++} ++ ++void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) ++{ ++ size_t size; ++ void *r; ++ ++ if (av_size_mult(elsize, nelem, &size)) { ++ av_free(ptr); ++ return NULL; ++ } ++ r = av_realloc(ptr, size); ++ if (!r) ++ av_free(ptr); ++ return r; ++} ++ ++int av_reallocp(void *ptr, size_t size) ++{ ++ void *val; ++ ++ if (!size) { ++ av_freep(ptr); ++ return 0; ++ } ++ ++ memcpy(&val, ptr, sizeof(val)); ++ val = av_realloc(val, size); ++ ++ if (!val) { ++ av_freep(ptr); ++ return AVERROR(ENOMEM); ++ } ++ ++ memcpy(ptr, &val, sizeof(val)); ++ return 0; ++} ++ ++void *av_malloc_array(size_t nmemb, size_t size) ++{ ++ if (!size || nmemb >= INT_MAX / size) ++ return NULL; ++ return av_malloc(nmemb * size); ++} ++ ++void *av_mallocz_array(size_t nmemb, size_t size) ++{ ++ if (!size || nmemb >= INT_MAX / size) ++ return NULL; ++ return av_mallocz(nmemb * size); ++} ++ ++void *av_realloc_array(void *ptr, size_t nmemb, size_t size) ++{ ++ if (!size || nmemb >= INT_MAX / size) ++ return NULL; ++ return av_realloc(ptr, nmemb * size); ++} ++ ++int av_reallocp_array(void *ptr, size_t nmemb, size_t size) ++{ ++ void *val; ++ ++ memcpy(&val, ptr, sizeof(val)); ++ val = av_realloc_f(val, nmemb, size); ++ memcpy(ptr, &val, sizeof(val)); ++ if (!val && nmemb && size) ++ return AVERROR(ENOMEM); ++ ++ return 0; ++} ++ ++void av_free(void *ptr) ++{ ++ free(ptr); ++} ++ ++void av_freep(void *arg) ++{ ++ void *val; ++ ++ memcpy(&val, arg, sizeof(val)); ++ memcpy(arg, &(void *){ NULL }, sizeof(val)); ++ av_free(val); ++} ++ ++void *av_mallocz(size_t size) ++{ ++ void *ptr = av_malloc(size); ++ if (ptr) ++ memset(ptr, 0, size); ++ return ptr; ++} ++ ++void *av_calloc(size_t nmemb, size_t size) ++{ ++ if (size <= 0 || nmemb >= INT_MAX / size) ++ return NULL; ++ return av_mallocz(nmemb * size); ++} ++ ++char *av_strdup(const char *s) ++{ ++ char *ptr = NULL; ++ if (s) { ++ size_t len = strlen(s) + 1; ++ ptr = av_realloc(NULL, len); ++ if (ptr) ++ memcpy(ptr, s, len); ++ } ++ return ptr; ++} ++ ++char *av_strndup(const char *s, size_t len) ++{ ++ char *ret = NULL, *end; ++ ++ if (!s) ++ return NULL; ++ ++ end = memchr(s, 0, len); ++ if (end) ++ len = end - s; ++ ++ ret = av_realloc(NULL, len + 1); ++ if (!ret) ++ return NULL; ++ ++ memcpy(ret, s, len); ++ ret[len] = 0; ++ return ret; ++} ++ ++void *av_memdup(const void *p, size_t size) ++{ ++ void *ptr = NULL; ++ if (p) { ++ ptr = av_malloc(size); ++ if (ptr) ++ memcpy(ptr, p, size); ++ } ++ return ptr; ++} ++ ++void av_memcpy_backptr(uint8_t *dst, int back, int cnt) ++{ ++#if 0 ++ const uint8_t *src = &dst[-back]; ++ if (!back) ++ return; ++ ++ if (back == 1) { ++ memset(dst, *src, cnt); ++ } else if (back == 2) { ++ fill16(dst, cnt); ++ } else if (back == 3) { ++ fill24(dst, cnt); ++ } else if (back == 4) { ++ fill32(dst, cnt); ++ } else { ++ if (cnt >= 16) { ++ int blocklen = back; ++ while (cnt > blocklen) { ++ memcpy(dst, src, blocklen); ++ dst += blocklen; ++ cnt -= blocklen; ++ blocklen <<= 1; ++ } ++ memcpy(dst, src, cnt); ++ return; ++ } ++ if (cnt >= 8) { ++ AV_COPY32U(dst, src); ++ AV_COPY32U(dst + 4, src + 4); ++ src += 8; ++ dst += 8; ++ cnt -= 8; ++ } ++ if (cnt >= 4) { ++ AV_COPY32U(dst, src); ++ src += 4; ++ dst += 4; ++ cnt -= 4; ++ } ++ if (cnt >= 2) { ++ AV_COPY16U(dst, src); ++ src += 2; ++ dst += 2; ++ cnt -= 2; ++ } ++ if (cnt) ++ *dst = *src; ++ } ++#endif ++} ++ ++void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) ++{ ++#if 0 ++ if (min_size <= *size) ++ return ptr; ++ ++ if (min_size > max_alloc_size - 32) { ++ *size = 0; ++ return NULL; ++ } ++ ++ min_size = FFMIN(max_alloc_size - 32, FFMAX(min_size + min_size / 16 + 32, min_size)); ++ ++ ptr = av_realloc(ptr, min_size); ++ /* we could set this to the unmodified min_size but this is safer ++ * if the user lost the ptr and uses NULL now ++ */ ++ if (!ptr) ++ min_size = 0; ++ ++ *size = min_size; ++#endif ++ return ptr; ++} ++ ++#if 0 ++void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size) ++{ ++ ff_fast_malloc(ptr, size, min_size, 0); ++} ++ ++void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size) ++{ ++ ff_fast_malloc(ptr, size, min_size, 1); ++} ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/vpu_ops.c b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/vpu_ops.c +new file mode 100644 +index 000000000..3684fb631 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/felix/libh264/src/vpu_ops.c +@@ -0,0 +1,170 @@ ++#ifdef __KERNEL__ ++#else ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++#include "vpu_ops.h" ++ ++ ++static struct vpu_ctx *gvpu_ctx; ++ ++int vpu_ctx_set_ops(struct vpu_ctx *ctx, void *priv, struct vpu_ops *ops) ++{ ++ ctx->priv = priv; ++ ctx->ops = ops; ++ ++ return 0; ++} ++ ++#ifdef __KERNEL__ ++ ++static int vpu_start(void *priv) ++{ ++ return 0; ++} ++ ++ ++static int vpu_wait(void *priv) ++{ ++ int ret = 0; ++ ++ return ret; ++} ++ ++ ++static int vpu_end(void *priv) ++{ ++ return 0; ++} ++ ++ ++struct vpu_ops hw_vpu_ops = { ++ .start = vpu_start, ++ .wait = vpu_wait, ++ .end = vpu_end, ++}; ++ ++int vpu_ctx_init(struct vpu_ctx *ctx) ++{ ++ ++ /*ops will be replaced.*/ ++ ctx->ops = &hw_vpu_ops; ++ ctx->priv = ctx; ++ gvpu_ctx = ctx; ++ return 0; ++} ++ ++ ++void vpu_ctx_uninit(struct vpu_ctx *ctx) ++{ ++} ++ ++ ++#else ++ ++static int vpu_start(struct vpu_ctx *ctx) ++{ ++ unsigned int glbc = 0; ++ int ret = 0; ++ /*reset vpu*/ ++ ret = ioctl(ctx->fd, CMD_VPU_RESET, 0); ++ ++ /* this function will set st_h264 var dma */ ++ glbc = (SCH_GLBC_HIAXI | SCH_INTE_ACFGERR | SCH_INTE_BSERR | SCH_INTE_ENDF); ++ *((volatile unsigned int *)(ctx->vpu_base + REG_SCH_GLBC)) = glbc; ++ ++ /* start vmd regs config */ ++ *(volatile unsigned int *)(ctx->vpu_base + REG_VDMA_TASKRG) = (ctx->desc_pa & 0xffffff80) | 0x1; ++ ++ return 0; ++} ++ ++ ++static int vpu_wait(struct vpu_ctx *ctx) ++{ ++ ++ int vpu_status, ret; ++ ++ ret = ioctl(ctx->fd, WAIT_COMPLETE, &vpu_status); ++ if((vpu_status & 0x1) == 1){ ++ //printf("wait vpu ops complete done success.\n"); ++ } else { ++ printf("vpu sch status=0x%08x,vdma status=0x%08x,vdma dha=0x%08x, sde id=0x%08x,sde cfg0=0x%08x,sde bsaddr=0x%08x\n", ++ *(volatile unsigned int *)(ctx->vpu_base + REG_SCH_STAT), ++ *(volatile unsigned int *)(ctx->vpu_base + REG_VDMA_TASKST), ++ *(volatile unsigned int *)(ctx->vpu_base + REG_VDMA_TASKRG), ++ *(volatile unsigned int *)(ctx->vpu_base + REG_SDE_CODEC_ID), ++ *(volatile unsigned int *)(ctx->vpu_base + REG_SDE_CFG0), ++ *(volatile unsigned int *)(ctx->vpu_base + REG_SDE_CFG2) ++ ); ++ ++ printf("sde status=0x%08x\n", *(volatile unsigned int *)(ctx->vpu_base + REG_SDE_STAT)); ++ }; ++ ++ return ret; ++} ++ ++ ++static int vpu_end(struct vpu_ctx *ctx) ++{ ++ printf("vpu_end -----\n"); ++ ++ return 0; ++} ++ ++ ++struct vpu_ops hw_vpu_ops = { ++ .start = vpu_start, ++ .wait = vpu_wait, ++ .end = vpu_end, ++}; ++ ++ ++ ++ ++ ++#define VPU_DEVICE_NAME "/dev/jz-vpu" ++#define VPU_IOSIZE (0xF0000 - 1) ++int vpu_ctx_init(struct vpu_ctx *ctx) ++{ ++ ctx->fd = open("/dev/jz-vpu", O_RDWR); ++ if(ctx->fd < 0) { ++ printf("failed to open vpu devie!\n"); ++ return -1; ++ } ++ ++ ctx->vpu_base = mmap(NULL, VPU_IOSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, ctx->fd, VPU_BASE); ++ ++ ctx->ops = &hw_vpu_ops; ++ ctx->priv = ctx; ++ gvpu_ctx = ctx; ++ return 0; ++} ++ ++void vpu_ctx_uninit(struct vpu_ctx *ctx) ++{ ++ close(ctx->fd); ++ ++ munmap(ctx->vpu_base, VPU_IOSIZE); ++} ++#endif ++ ++int vpu_hw_start(struct vpu_ctx *ctx) ++{ ++ return ctx->ops->start(ctx->priv); ++} ++int vpu_hw_wait(struct vpu_ctx *ctx) ++{ ++ return ctx->ops->wait(ctx->priv); ++} ++ ++int vpu_hw_end(struct vpu_ctx *ctx) ++{ ++ return ctx->ops->end(ctx->priv); ++} ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/Makefile b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/Makefile +new file mode 100644 +index 000000000..934baeea2 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/Makefile +@@ -0,0 +1,17 @@ ++ingenic_helix-y := helix_drv.o \ ++ jpge.o \ ++ jpgd.o \ ++ default_sliceinfo.o \ ++ helix_ops.o \ ++ api/helix_x264_enc.o \ ++ api/helix_jpeg_enc.o \ ++ api/helix_jpeg_dec.o \ ++ h264enc/set.o \ ++ h264enc/cabac.o \ ++ h264enc/common.o \ ++ h264enc/slice.o \ ++ h264e_rc.o \ ++ h264e_rc_nl.o ++ ++obj-$(CONFIG_INGENIC_HELIX) += ingenic_helix.o ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/README b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/README +new file mode 100644 +index 000000000..7b97beed1 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/README +@@ -0,0 +1,4 @@ ++ ++helix-drv.c <---- v4l2 implementation. ++helix-ctrl.c <---- helix controller driver. ++helix-x264-enc.c <---- encoder APIs. +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix.h +new file mode 100755 +index 000000000..071117e92 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix.h +@@ -0,0 +1,3459 @@ ++/**************************************************************** ++*****************************************************************/ ++#ifndef __HELIX_H__ ++#define __HELIX_H__ ++ ++/**************************************************************** ++ VPU register map ++*****************************************************************/ ++#define JZM_V2_TLB ++ ++#ifdef JZM_HUNT_SIM ++#include "hunt.h" ++#else ++#ifndef __place_k0_data__ ++#define __place_k0_data__ ++#endif ++#ifndef __place_k0_text__ ++#define __place_k0_text__ ++#endif ++#endif ++ ++#define VPU_BASE 0x13300000 ++ ++#define HID_SCH 0x0 ++#define HID_JRFD 0x1 ++#define HID_EMC 0x3 ++#define HID_EFE 0x4 ++#define HID_MCE 0x5 ++#define HID_ODMA 0x6 ++#define HID_DBLK 0x7 ++#define HID_VMAU 0x8 ++#define HID_SDE 0x9 ++#define HID_AUX 0xA ++#define HID_TCSM 0xB ++#define HID_IFA 0xB //fixme ++#define HID_JPGC 0xE ++#define HID_SRAM 0xF ++ ++#define VPU_MAX_MB_WIDTH 256 ++ ++#define MSCOPE_START(mbnum) write_reg(VPU_BASE+0x24, mbnum) ++#define MSCOPE_STOP() write_reg(VPU_BASE+0x28, 0) ++ ++/******************************************** ++ SCH (Scheduler) ++*********************************************/ ++#define TCSM_FLUSH 0xc0000 ++#define REG_SCH_GLBC 0x00000 ++#define SCH_GLBC_SLDE (0x1<<31) ++#ifdef JZM_V2_TLB ++# define SCH_TLBE_JPGC (0x1<<26) ++# define SCH_TLBE_DBLK (0x1<<25) ++# define SCH_TLBE_SDE (0x1<<24) ++# define SCH_TLBE_EFE (0x1<<23) ++# define SCH_TLBE_VDMA (0x1<<22) ++# define SCH_TLBE_MCE (0x1<<21) ++#else ++# define SCH_GLBC_TLBE (0x1<<30) ++# define SCH_GLBC_TLBINV (0x1<<29) ++#endif ++#define SCH_INTE_RESERR (0x1<<29) ++#define SCH_INTE_BSFULL (0x1<<28) ++#define SCH_INTE_ACFGERR (0x1<<20) ++#define SCH_INTE_TLBERR (0x1<<18) ++#define SCH_INTE_BSERR (0x1<<17) ++#define SCH_INTE_ENDF (0x1<<16) ++#define SCH_GLBC_HIMAP (0x1<<15) ++#define SCH_GLBC_HIAXI (0x1<<9) ++#define SCH_GLBC_EPRI0 (0x0<<7) ++#define SCH_GLBC_EPRI1 (0x1<<7) ++#define SCH_GLBC_EPRI2 (0x2<<7) ++#define SCH_GLBC_EPRI3 (0x3<<7) ++ ++#define REG_SCH_TLBA 0x00030 ++ ++#ifdef JZM_V2_TLB ++# define REG_SCH_TLBC 0x00050 ++# define SCH_TLBC_VPN (0xFFFFF000) ++# define SCH_TLBC_RIDX(idx) (((idx) & 0xFF)<<4) ++# define SCH_TLBC_INVLD (0x1<<1) ++# define SCH_TLBC_RETRY (0x1<<0) ++ ++# define REG_SCH_TLBV 0x00054 ++# define SCH_TLBV_CNM(cnm) (((cnm) & 0xFFF)<<16) ++# define SCH_TLBV_GCN(gcn) (((gcn) & 0xFFF)<<0) ++# define SCH_TLBV_RCI_MC (0x1<<30) ++# define SCH_TLBV_RCI_EFE (0x1<<31) ++#endif ++ ++#define REG_SCH_STAT 0x00034 ++#define SCH_STAT_ENDF (0x1<<0) ++#define SCH_STAT_BPF (0x1<<1) ++#define SCH_STAT_ACFGERR (0x1<<2) ++#define SCH_STAT_TIMEOUT (0x1<<3) ++#define SCH_STAT_JPGEND (0x1<<4) ++#define SCH_STAT_BSERR (0x1<<7) ++#define SCH_STAT_TLBERR (0x1F<<10) ++#define SCH_STAT_SLDERR (0x1<<16) ++ ++ ++#define REG_SCH_SLDE0 0x00040 ++#define REG_SCH_SLDE1 0x00044 ++#define REG_SCH_SLDE2 0x00048 ++#define REG_SCH_SLDE3 0x0004C ++#define SCH_SLD_VTAG(val) (((val) & 0xFFF)<<20) ++#define SCH_SLD_MASK(val) (((val) & 0xFFF)<<8) ++#define SCH_SLD_VLD (0x1<<0) ++ ++#define REG_SCH_SCHC 0x00060 ++#define SCH_CH1_PCH(ch) (((ch) & 0x3)<<0) ++#define SCH_CH2_PCH(ch) (((ch) & 0x3)<<8) ++#define SCH_CH3_PCH(ch) (((ch) & 0x3)<<16) ++#define SCH_CH4_PCH(ch) (((ch) & 0x3)<<24) ++#define SCH_CH1_PE (0x1<<2) ++#define SCH_CH2_PE (0x1<<10) ++#define SCH_CH3_PE (0x1<<18) ++#define SCH_CH4_PE (0x1<<26) ++#define SCH_CH1_GS0 (0x0<<3) ++#define SCH_CH1_GS1 (0x1<<3) ++#define SCH_CH2_GS0 (0x0<<11) ++#define SCH_CH2_GS1 (0x1<<11) ++#define SCH_CH3_GS0 (0x0<<19) ++#define SCH_CH3_GS1 (0x1<<19) ++#define SCH_CH4_GS0 (0x0<<27) ++#define SCH_CH4_GS1 (0x1<<27) ++ ++#define REG_SCH_BND 0x00064 ++#define SCH_CH1_HID(hid) (((hid) & 0xF)<<16) ++#define SCH_CH2_HID(hid) (((hid) & 0xF)<<20) ++#define SCH_CH3_HID(hid) (((hid) & 0xF)<<24) ++#define SCH_CH4_HID(hid) (((hid) & 0xF)<<28) ++#define SCH_BND_G0F1 (0x1<<0) ++#define SCH_BND_G0F2 (0x1<<1) ++#define SCH_BND_G0F3 (0x1<<2) ++#define SCH_BND_G0F4 (0x1<<3) ++#define SCH_BND_G1F1 (0x1<<4) ++#define SCH_BND_G1F2 (0x1<<5) ++#define SCH_BND_G1F3 (0x1<<6) ++#define SCH_BND_G1F4 (0x1<<7) ++#define SCH_DEPTH(val) (((val-1) & 0xF)<<8) ++ ++#define REG_SCH_SCHG0 0x00068 ++#define REG_SCH_SCHG1 0x0006C ++#define REG_SCH_SCHE1 0x00070 ++#define REG_SCH_SCHE2 0x00074 ++#define REG_SCH_SCHE3 0x00078 ++#define REG_SCH_SCHE4 0x0007C ++ ++#define DSA_SCH_CH1 (VPU_BASE | REG_SCH_SCHE1) ++#define DSA_SCH_CH2 (VPU_BASE | REG_SCH_SCHE2) ++#define DSA_SCH_CH3 (VPU_BASE | REG_SCH_SCHE3) ++#define DSA_SCH_CH4 (VPU_BASE | REG_SCH_SCHE4) ++ ++/******************************************** ++ SW_RESET (VPU software reset) ++*********************************************/ ++#define REG_CFGC_SW_RESET 0x00004 ++#define CFGC_SW_RESET_RST (0x1<<1) ++#define CFGC_SW_RESET_RST_CLR (0x0<<1) ++#define CFGC_SW_RESET_EARB_EMPT (0x4) ++/******************************************** ++ VDMA (VPU general-purpose DMA) ++*********************************************/ ++#define REG_VDMA_LOCK 0x10000 ++#define REG_VDMA_UNLK 0x10004 ++ ++#define REG_VDMA_TASKRG 0x10008 ++#define VDMA_ACFG_RUN (0x1) ++#define VDMA_DESC_RUN (0x3) ++#define VDMA_ACFG_CLR (0x8) ++#define VDMA_ACFG_SAFE (0x4) ++#define VDMA_ACFG_DHA(a) (((unsigned int)(a)) & 0xFFFFFF80) ++#define VDMA_DESC_DHA(a) (((unsigned int)(a)) & 0xFFFF0) ++ ++#define REG_CFGC_ACM_CTRL 0x00084 ++#define REG_CFGC_ACM_STAT 0x00088 ++#define REG_CFGC_ACM_DHA 0x0008C ++ ++#define REG_VDMA_TASKST 0x1000C ++#define VDMA_ACFG_ERR (0x1<<3) ++#define VDMA_ACFG_END (0x1<<2) ++#define VDMA_DESC_END (0x1<<1) ++#define VDMA_VPU_BUSY (0x1<<0) ++ ++#define VDMA_DESC_EXTSEL (0x1<<0) ++#define VDMA_DESC_TLBSEL (0x1<<1) ++#define VDMA_DESC_LK (0x1<<31) ++ ++#define VDMA_ACFG_VLD (0x1<<31) ++#define VDMA_ACFG_TERM (0x1<<30) ++#define VDMA_ACFG_IDX(a) (((unsigned int)(a)) & 0xFFFFC) ++ ++#ifdef RW_REG_TEST ++#define GEN_VDMA_ACFG(chn, reg, term, val) write_reg(VPU_BASE+(reg), val) ++#else ++#define GEN_VDMA_ACFG(chn, reg, term, val) \ ++ ({*chn++ = val; \ ++ *chn++ = (VDMA_ACFG_VLD | (term) | VDMA_ACFG_IDX(reg)); \ ++ }) ++#endif ++ ++#define REG_EMC_FRM_SIZE 0x30000 ++#define REG_EMC_BS_ADDR 0x30004 ++#define REG_EMC_DBLK_ADDR 0x30008 ++#define REG_EMC_RECON_ADDR 0x3000c ++#define REG_EMC_MV_ADDR 0x30010 ++#define REG_EMC_SE_ADDR 0x30014 ++#define REG_EMC_QPT_ADDR 0x30018 ++#define REG_EMC_RC_RADDR 0x3001c ++#define REG_EMC_MOS_ADDR 0x30020 ++#define REG_EMC_SLV_INIT 0x30024 ++#define REG_EMC_DEBUG_INFO0 0x30028 ++#define REG_EMC_DEBUG_INFO1 0x3002c ++#define REG_EMC_CRC_INFO0 0x30030 ++#define REG_EMC_CRC_INFO1 0x30034 ++#define REG_EMC_CRC_INFO2 0x30038 ++#define REG_EMC_CRC_INFO3 0x3003c ++#define REG_EMC_BS_SIZE 0x30040 ++#define REG_EMC_BS_STAT 0x30044 ++#define REG_EMC_RC_WADDR 0x30048 ++#define REG_EMC_CPX_ADDR 0x3004c ++#define REG_EMC_MOD_ADDR 0x30050 ++#define REG_EMC_SAD_ADDR 0x30054 ++#define REG_EMC_NCU_ADDR 0x30058 ++ ++/******************************************** ++ EFE (Encoder Front End) ++*********************************************/ ++#define REG_EFE_CTRL 0x40000 ++#define EFE_TSE(en) (((en) & 0x1)<<31) ++#define EFE_FMVP(en) (((en) & 0x1)<<30) ++#define EFE_ID_X264 (0x0<<14) ++#define EFE_ID_JPEG (0x1<<14) ++#define EFE_ID_VP8 (0x2<<14) ++#define EFE_X264_QP(qp) (((qp) & 0x3F)<<8) ++#define EFE_VP8_QTB(qtb) (((qtb) & 0x7f)<<22) ++#define EFE_VP8_QIDX(qp) (((qp) & 0x3F)<<8) ++#define EFE_VP8_LF(lf) ((lf & 0x3F)<<16) ++#define EFE_HALN8_FLAG(en) (((en) & 0x1)<<7) ++#define EFE_STEP_MODE(en) (((en) & 0x1)<<6) ++#define EFE_DBLK_EN (0x1<<5) ++#define EFE_SLICE_TYPE(a) (((a) & 0x1)<<4) ++#define EFE_PLANE_TILE (0x0<<2) ++#define EFE_PLANE_420P (0x1<<2) ++#define EFE_PLANE_NV12 (0x2<<2) ++#define EFE_PLANE_NV21 (0x3<<2) ++#define EFE_EN (0x1<<1) ++#define EFE_RUN (0x1<<0) ++ ++#define REG_EFE_GEOM 0x40004 ++#define EFE_FST_MBY(mb) (((mb) & 0xFF)<<24) ++#define EFE_FST_MBX(mb) (((0/*FIXME*/) & 0xFF)<<16) ++#define EFE_LST_MBY(mb) (((mb) & 0xFF)<<8) ++#define EFE_LST_MBX(mb) (((mb) & 0xFF)<<0) ++#define EFE_JPGC_LST_MBY(mb) (((mb) & 0xFFFF)<<16) ++#define EFE_JPGC_LST_MBX(mb) ((mb) & 0xFFFF) ++ ++#define REG_EFE_COEF_BA 0x4000C ++#define REG_EFE_RAWY_SBA 0x40010 ++#define REG_EFE_RAWC_SBA 0x40014 ++#define REG_EFE_RAWU_SBA 0x40014 ++#define REG_EFE_TOPMV_BA 0x40018 ++#define REG_EFE_TOPPA_BA 0x4001C ++#define REG_EFE_MECHN_BA 0x40020 ++#define REG_EFE_MAUCHN_BA 0x40024 ++#define REG_EFE_DBLKCHN_BA 0x40028 ++#define REG_EFE_SDECHN_BA 0x4002C ++#define REG_EFE_RAW_DBA 0x40030 ++#define REG_EFE_RAWV_SBA 0x40034 ++ ++#define REG_EFE_ROI_MAX_QP 0x40040 ++#define REG_EFE_ROI_BASE_INFO0 0x40044 ++#define REG_EFE_ROI_BASE_INFO1 0x40048 ++#define REG_EFE_ROI_POS_INFO0 0x4004C ++#define REG_EFE_ROI_POS_INFO1 0x40050 ++#define REG_EFE_ROI_POS_INFO2 0x40054 ++#define REG_EFE_ROI_POS_INFO3 0x40058 ++#define REG_EFE_ROI_POS_INFO4 0x4005C ++#define REG_EFE_ROI_POS_INFO5 0x40060 ++#define REG_EFE_ROI_POS_INFO6 0x40064 ++#define REG_EFE_ROI_POS_INFO7 0x40068 ++ ++#define REG_EFE_QP_GEN_TAB 0x4006C ++ ++#define REG_EFE_QPG_CTRL 0x40074 ++#define REG_EFE_QPG_CFG0 0x40078 ++#define REG_EFE_QPG_CFG1 0x4007C ++#define REG_EFE_QPG_CFG2 0x40080 ++#define REG_EFE_QPG_CFG3 0x40084 ++#define REG_EFE_QPG_CFG4 0x40088 ++#define REG_EFE_QPG_CFG5 0x4008C ++#define REG_EFE_QPG_CFG6 0x40090 ++#define REG_EFE_QPG_RGNC_A 0x40094 ++#define REG_EFE_QPG_RGNC_B 0x40098 ++#define REG_EFE_QPG_RGNC_C 0x4009C ++#define REG_EFE_QPG_RGNC_D 0x400A0 ++#define REG_EFE_QP_SUM 0x400A4 ++ ++#define REG_EFE_EIGEN_CFG0 0x400C0 ++#define REG_EFE_EIGEN_CFG1 0x400C4 ++#define REG_EFE_EIGEN_CFG2 0x400C8 ++#define REG_EFE_EIGEN_CFG3 0x400CC ++#define REG_EFE_EIGEN_CFG4 0x400D0 ++#define REG_EFE_EIGEN_CFG5 0x400D4 ++#define REG_EFE_EIGEN_CFG6 0x400D8 ++#define REG_EFE_DIFFY_CFG 0x400DC ++#define REG_EFE_DIFFU_CFG 0x400E0 ++#define REG_EFE_DIFFV_CFG 0x400E4 ++ ++#define REG_EFE_SKIN_CTRL 0x400AC ++#define REG_EFE_SKIN_PTHD0 0x400B0 ++#define REG_EFE_SKIN_PTHD1 0x400B4 ++#define REG_EFE_SKIN_PTHD2 0x400B8 ++#define REG_EFE_SKIN_QP_OFST 0x400BC ++#define REG_EFE_SKIN_PARAM0 0x400E8 ++#define REG_EFE_SKIN_PARAM1 0x400EC ++#define REG_EFE_SKIN_PARAM2 0x400F0 ++ ++#define REG_EFE_RAW_STRD 0x40038 ++#define EFE_RAW_STRDY(y) (((y) & 0xFFFF)<<16) ++#define EFE_RAW_STRDC(c) (((c) & 0xFFFF)<<0) ++ ++#define REG_EFE_DBG_INFO 0x4003C ++#define EFE_DBG_EN (0x1<<31) ++#define EFE_DBG_BP_MBX(x) (((x) & 0xFFF)<<0) ++#define EFE_DBG_BP_MBY(y) (((y) & 0xFFF)<<16) ++ ++#define REG_EFE_MVRP 0x40100 ++#define REG_EFE_SSAD 0x40108 ++#define REG_EFE_DCS 0x4010C ++#define EFE_DCS_CLR(th) (0x1<<(th & 0xF)) ++#define EFE_DCS_EN(en) (((en) & 0x1)<<16) ++#define EFE_DCS_RT(rt) (((rt) & 0xF)<<20) ++#define EFE_DCS_OTH(oth) (((oth) & 0xF)<<24) ++#define REG_EFE_STAT 0x40110 ++#define REG_EFE_CQP_OFST 0x40120 ++ ++#define EFE_RC_QPO_CFG(c4, c3, c2, c1) \ ++( ((c4) & 0x3F)<<18 | \ ++ ((c3) & 0x3F)<<12 | \ ++ ((c2) & 0x3F)<<6 | \ ++ ((c1) & 0x3F)<<0 \ ++) ++ ++#define REG_EFE_RC_MINFO 0x40128 ++#define EFE_RC_MB_EN (0x1<<0) ++#define EFE_RC_MBGP_NUM(a) (((a) & 0x3fff)<<1) ++#define EFE_RC_MAD_CFG_RDY (0x1<<15) ++#define REG_EFE_RC_BINFO0 0x4012C ++#define EFE_RC_BU_EN (0x1<<0) ++#define EFE_RC_BU_NUM(a) (((a) & 0x7f)<<1) ++#define EFE_RC_BU_CFG(a) (((a) & 0x1)<<8) ++#define EFE_RC_SLICE_TP(a) (((a) & 0x1)<<10) ++#define REG_EFE_RC_BINFO1 0x40130 ++#define EFE_RC_BU_SIZE(a) (((a) & 0x3fff)<<0) ++#define EFE_RC_BU_LSIZE(a) (((a) & 0x3fff)<<14) ++#define REG_EFE_RC_GP0THD 0x40134 ++#define REG_EFE_RC_GP1THD 0x40138 ++#define REG_EFE_RC_GP2THD 0x4013C ++#define REG_EFE_RC_TBS 0x40140 ++#define REG_EFE_RC_BNQA0 0x40144 ++#define REG_EFE_RC_BPQA0 0x40148 ++#define REG_EFE_RC_BNQA1 0x4014C ++#define REG_EFE_RC_BPQA1 0x40150 ++#define REG_EFE_RC_MNQCS 0x40154 ++#define REG_EFE_RC_MPQCS 0x40158 ++#define REG_EFE_RC_MTBQ 0x4015C ++#define REG_EFE_RC_MRFQ 0x40160 ++#define REG_EFE_RC_MAMIN 0x40164 ++#define REG_EFE_RC_MAMAX 0x40168 ++#define REG_EFE_RC_BBS 0x4016C ++ ++/******************************************** ++ MCE (Motion Compensation/Estimation COMBO) ++*********************************************/ ++//GLB_CTRL ++#define REG_MCE_GLB_CTRL 0x50000 ++#define MCE_GLB_CTRL_FMV0(a) (((a) & 0xf)<<31) ++#define MCE_GLB_CTRL_STEP1(a) (((a) & 0xf)<<27) ++#define MCE_GLB_CTRL_STEP0(a) (((a) & 0xf)<<23) ++#define MCE_GLB_CTRL_MSTEP(a) (((a) & 0x1)<<22) ++#define MCE_GLB_CTRL_RBS(a) (((a) & 0xff)<<14) ++#define MCE_GLB_CTRL_FMS(a) (((a) & 0x7)<<11) ++#define MCE_GLB_CTRL_FRMMV(a) (((a) & 0x1)<<10) ++#define MCE_GLB_CTRL_GLBMV(a) (((a) & 0x1)<<9) ++#define MCE_GLB_CTRL_DCT8(a) (((a) & 0x1)<<8) ++#define MCE_GLB_CTRL_JRFD(a) (((a) & 0x1)<<7) ++#define MCE_GLB_CTRL_MREF(a) (((a) & 0x1)<<6) ++#define MCE_GLB_CTRL_PSKIP(a) (((a) & 0x1)<<5) ++#define MCE_GLB_CTRL_RM(a) (((a) & 0x1)<<4) ++#define MCE_GLB_CTRL_BF (0x1<<3) ++#define MCE_GLB_CTRL_CGE (0x1<<2) ++#define MCE_GLB_CTRL_WM (0x1<<1) ++#define MCE_GLB_CTRL_INIT (0x1<<0) ++ ++//COMP_CTRL ++#define REG_MCE_COMP_CTRL 0x50010 ++#define MCE_COMP_CTRL_CCE (0x1<<31) ++#define MCE_COMP_CTRL_CWT(a) (((a) & 0x3)<<26) ++#define MCE_COMP_CTRL_CRR (0x1<<25) ++#define MCE_COMP_CTRL_CIC (0x1<<24) ++#define MCE_COMP_CTRL_CAT (0x1<<23) ++#define MCE_COMP_CTRL_CTAP(a) (((a) & 0x3)<<20) ++#define MCE_COMP_CTRL_CSPT(a) (((a) & 0x3)<<18) ++#define MCE_COMP_CTRL_CSPP(a) (((a) & 0x3)<<16) ++#define MCE_COMP_CTRL_YCE (0x1<<15) ++#define MCE_COMP_CTRL_YWT(a) (((a) & 0x3)<<10) ++#define MCE_COMP_CTRL_YRR (0x1<<9) ++#define MCE_COMP_CTRL_YIC (0x1<<8) ++#define MCE_COMP_CTRL_YAT (0x1<<7) ++#define MCE_COMP_CTRL_YTAP(a) (((a) & 0x3)<<4) ++#define MCE_COMP_CTRL_YSPT(a) (((a) & 0x3)<<2) ++#define MCE_COMP_CTRL_YSPP(a) (((a) & 0x3)<<0) ++ ++#define MCE_WT_BIAVG 0 ++#define MCE_WT_UNIWT 1 ++#define MCE_WT_BIWT 2 ++#define MCE_WT_IMWT 3 ++ ++#define MCE_TAP_TAP2 0 ++#define MCE_TAP_TAP4 1 ++#define MCE_TAP_TAP6 2 ++#define MCE_TAP_TAP8 3 ++ ++#define MCE_SPT_AUTO 0 ++#define MCE_SPT_SPEC 1 ++#define MCE_SPT_BILI 2 ++#define MCE_SPT_SYMM 3 ++ ++#define MCE_SPP_HPEL 0 ++#define MCE_SPP_QPEL 1 ++#define MCE_SPP_EPEL 2 ++ ++//ESTI_CTRL ++#define REG_MCE_ESTI_CTRL 0x50040 ++#define MCE_ESTI_CTRL_LSP(a) (((a) & 0xF)<<28) ++#define MCE_ESTI_CTRL_FBG(a) (((a) & 0x1)<<27) ++#define MCE_ESTI_CTRL_CLMV (0x1<<26) ++#define MCE_ESTI_CTRL_SCL(a) (((a) & 0x3)<<24) ++#define MCE_ESTI_CTRL_MSS(a) (((a) & 0xFF)<<16) ++#define MCE_ESTI_CTRL_QRL(a) (((a) & 0x3)<<14) ++#define MCE_ESTI_CTRL_HRL(a) (((a) & 0x3)<<12) ++#define MCE_ESTI_CTRL_BDIR(a) (((a) & 0x1)<<10) ++#define MCE_ESTI_CTRL_PUE_64X64 (0x1<<9) ++#define MCE_ESTI_CTRL_PUE_32X32 (0x1<<6) ++#define MCE_ESTI_CTRL_PUE_32X16 (0x1<<5) ++#define MCE_ESTI_CTRL_PUE_16X32 (0x1<<4) ++#define MCE_ESTI_CTRL_PUE_16X16 (0x1<<3) ++#define MCE_ESTI_CTRL_PUE_16X8 (0x1<<2) ++#define MCE_ESTI_CTRL_PUE_8X16 (0x1<<1) ++#define MCE_ESTI_CTRL_PUE_8X8 (0x1<<0) ++ ++//MRGI ++#define REG_MCE_MRGI 0x50044 ++#define MCE_MRGI_MRGE_64X64 (0x1<<9) ++#define MCE_MRGI_MRGE_32X32 (0x1<<6) ++#define MCE_MRGI_MRGE_32X16 (0x1<<5) ++#define MCE_MRGI_MRGE_16X32 (0x1<<4) ++#define MCE_MRGI_MRGE_16X16 (0x1<<3) ++#define MCE_MRGI_MRGE_16X8 (0x1<<2) ++#define MCE_MRGI_MRGE_8X16 (0x1<<1) ++#define MCE_MRGI_MRGE_8X8 (0x1<<0) ++ ++//MVR ++#define REG_MCE_MVR 0x50048 ++#define MCE_MVR_MVRY(a) (((a) & 0xFFFF)<<16) ++#define MCE_MVR_MVRX(a) (((a) & 0xFFFF)<<0) ++ ++//FRM_SIZE ++#define REG_MCE_FRM_SIZE 0x50060 ++#define MCE_FRM_SIZE_FH(a) (((a) & 0xFFFF)<<16) ++#define MCE_FRM_SIZE_FW(a) (((a) & 0xFFFF)<<0) ++#define MCE_FRM_SIZE_LRE(a) (((a) & 0x1)<<14) ++#define MCE_FRM_SIZE_RRE(a) (((a) & 0x1)<<15) ++#define MCE_FRM_SIZE_TRE(a) (((a) & 0x1)<<30) ++#define MCE_FRM_SIZE_BRE(a) (((a) & 0x1)<<31) ++ ++//FSC ++#define REG_MCE_FSC 0x5004C ++#define MCE_FSC_FSE(a) (((a) & 0x1)<<31) ++#define MCE_FSC_FSMD(a) (((a) & 0x1)<<30) ++#define MCE_FSC_RECY(a) (((a) & 0x7F)<<24) ++#define MCE_FSC_RECX(a) (((a) & 0xFF)<<16) ++#define MCE_FSC_PERY(a) (((a) & 0xFF)<<8) ++#define MCE_FSC_PERX(a) (((a) & 0xFF)<<0) ++ ++//FRM_STRD ++#define REG_MCE_FRM_STRD 0x50064 ++#define MCE_FRM_STRD_STRDC(a) (((a) & 0xFFFF)<<16) ++#define MCE_FRM_STRD_STRDY(a) (((a) & 0xFFFF)<<0) ++ ++//SLC_SPOS ++#define REG_MCE_SLC_SPOS 0x50068 ++#define MCE_SLC_SPOS_CU64Y(a) (((a) & 0xFF)<<8) ++#define MCE_SLC_SPOS_CU64X(a) (((a) & 0xFF)<<0) ++ ++//REF ++#define REG_MCE_REFY0 0x5006C ++#define REG_MCE_REFC0 0x50070 ++ ++#define REG_MCE_REFY1 0x50074 ++#define REG_MCE_REFC1 0x50078 ++ ++#define REG_MCE_REFY0_1 0x50110 //!!! ++#define REG_MCE_REFC0_1 0x50114 ++ ++//GLB MV ++#define REG_MCE_GLB_MV 0x5007C ++#define MCE_GLB_MVX(a) (((a) & 0xFFF)<<0) ++#define MCE_GLB_MVY(a) (((a) & 0xFFF)<<16) ++ ++//RLUT ++#define SLUT_MCE_RLUT(l, i) (0x50800 + (i)*8 + (l)*0x80) ++ ++//ILUT ++#define SLUT_MCE_ILUT_Y 0x50900 ++#define SLUT_MCE_ILUT_C 0x50980 ++#define MCE_ILUT_INFO(fir, clip, idgl, edgl, dir, \ ++ rnd, sft, savg, srnd, sbias) \ ++( ((fir) & 0x1)<<31 | \ ++ ((clip) & 0x1)<<27 | \ ++ ((idgl) & 0x1)<<26 | \ ++ ((edgl) & 0x1)<<25 | \ ++ ((dir) & 0x1)<<24 | \ ++ ((rnd) & 0xFF)<<16 | \ ++ ((sft) & 0xF)<<8 | \ ++ ((savg) & 0x1)<<2 | \ ++ ((srnd) & 0x1)<<1 | \ ++ ((sbias) & 0x1)<<0 \ ++) ++ ++//CLUT ++#define SLUT_MCE_CLUT_Y 0x50A00 ++#define SLUT_MCE_CLUT_C 0x50B00 ++#define MCE_CLUT_INFO(c4, c3, c2, c1) \ ++( ((c4) & 0xFF)<<24 | \ ++ ((c3) & 0xFF)<<16 | \ ++ ((c2) & 0xFF)<<8 | \ ++ ((c1) & 0xFF)<<0 \ ++) ++ ++//CHAIN/TMV/SYNC ADDR ++ ++#define REG_MCE_TMV_BA 0x50104 ++#define REG_MCE_CHN_SYNC 0x50108 ++#define REG_MCE_CHN_BA 0x5010C ++ ++/******************************************** ++ VMAU (VPU Matrix Arithmetic Unit) ++*********************************************/ ++#define REG_VMAU_MCBP 0x80000 ++ ++#define REG_VMAU_QTPARA 0x80004 ++ ++#define REG_VMAU_MAIN_ADDR 0x80008 ++ ++#define REG_VMAU_NCCHN_ADDR 0x8000C ++ ++#define REG_VMAU_CHN_LEN 0x80010 ++ ++#define REG_VMAU_ACBP 0x80014 ++ ++#define REG_VMAU_CPREDM_TLV 0x80018 ++ ++#define REG_VMAU_YPREDM0 0x8001C ++ ++#define REG_VMAU_YPREDM1 0x80020 ++ ++ ++#define REG_VMAU_TOP_BASE 0x80028 ++ ++#define REG_VMAU_CTX 0x8002C ++ ++#define REG_VMAU_MD_CFG0 0x80030 ++#define VMAU_MD_SLICE_I(a) (((a) & 0x1)<<0) ++#define VMAU_MD_SLICE_P(a) (((a) & 0x1)<<1) ++#define VMAU_MD_IS_DECODE(a) (((a) & 0x1)<<4) ++#define VMAU_MD_I4_DIS(a) (((a) & 0x1)<<8) ++#define VMAU_MD_I16_DIS(a) (((a) & 0x1)<<9) ++#define VMAU_MD_PSKIP_DIS(a) (((a) & 0x1)<<10) ++#define VMAU_MD_P_L0_DIS(a) (((a) & 0x1)<<11) ++#define VMAU_MD_I8_DIS(a) (((a) & 0x1)<<12) ++#define VMAU_MD_PT8_DIS(a) (((a) & 0x1)<<13) ++#define VMAU_MD_DREF_EN(a) (((a) & 0x1)<<14) ++#define VMAU_MD_DCT8_EN(a) (((a) & 0x1)<<15) ++#define VMAU_MD_FRM_REDGE(a) (((a) & 0xFF)<<16) ++#define VMAU_MD_FRM_BEDGE(a) (((a) & 0xFF)<<24) ++ ++#define REG_VMAU_MD_CFG1 0x80034 ++#define VMAU_IPMY_BIAS_EN(a) (((a) & 0x1)<<0) ++#define VMAU_IPMC_BIAS_EN(a) (((a) & 0x1)<<1) ++#define VMAU_COST_BIAS_EN(a) (((a) & 0x1)<<2) ++#define VMAU_CSSE_BIAS_EN(a) (((a) & 0x1)<<3) ++#define VMAU_JMLAMBDA2_EN(a) (((a) & 0x1)<<4) ++#define VMAU_INTER_NEI_EN(a) (((a) & 0x1)<<5) ++#define VMAU_SKIP_BIAS_EN(a) (((a) & 0x3)<<6) ++#define VMAU_LMD_BIAS_EN(a) (((a) & 0x1)<<8) ++#define VMAU_INFO_EN(a) (((a) & 0x1)<<9) ++#define VMAU_DCM_EN(a) (((a) & 0x1)<<10) ++#define VMAU_MVDS_ALL(a) (((a) & 0x1)<<12) ++#define VMAU_MVDS_ABS(a) (((a) & 0x1)<<13) ++#define VMAU_MVS_ALL(a) (((a) & 0x1)<<14) ++#define VMAU_MVS_ABS(a) (((a) & 0x1)<<15) ++#define VMAU_P_L0_BIAS(a) (((a) & 0xF)<<16) ++#define VMAU_PSKIP_BIAS(a) (((a) & 0xF)<<20) ++#define VMAU_I4_BIAS(a) (((a) & 0xF)<<24) ++#define VMAU_I16_BIAS(a) (((a) & 0xF)<<28) ++ ++#define REG_VMAU_MD_CFG2 0x80038 ++#define VMAU_IPM_BIAS_0(a) (((a) & 0xF)<<0) ++#define VMAU_IPM_BIAS_1(a) (((a) & 0xF)<<4) ++#define VMAU_IPM_BIAS_2(a) (((a) & 0xF)<<8) ++#define VMAU_IPM_BIAS_QP0(a) (((a) & 0x3F)<<12) ++#define VMAU_IPM_BIAS_QP1(a) (((a) & 0x3F)<<18) ++#define VMAU_MD_FBC_EP(a) (((a) & 0xFF)<<24) ++ ++#define REG_VMAU_MD_CFG3 0x8003C ++#define VMAU_CSSE_BIAS_0(a) (((a) & 0xF)<<0) ++#define VMAU_CSSE_BIAS_1(a) (((a) & 0xF)<<4) ++#define VMAU_CSSE_BIAS_2(a) (((a) & 0xF)<<8) ++#define VMAU_CSSE_BIAS_QP0(a) (((a) & 0x3F)<<12) ++#define VMAU_CSSE_BIAS_QP1(a) (((a) & 0x3F)<<18) ++#define VMAU_LMD_BIAS(a) (((a) & 0xF)<<24) ++#define VMAU_PL0_FS_DIS(a) (((a) & 0x1)<<28) ++#define VMAU_PT8_FS_DIS(a) (((a) & 0x1)<<29) ++#define VMAU_PL0_COST_MAX(a) (((a) & 0x1)<<30) ++#define VMAU_PT8_COST_MAX(a) (((a) & 0x1)<<31) ++ ++#define REG_VMAU_GBL_RUN 0x80040 ++#define VMAU_RUN 0x1 ++#define VMAU_STOP 0x2 ++#define VMAU_RESET 0x4 ++ ++#define REG_VMAU_GBL_CTR 0x80044 ++#define VMAU_CTRL_FIFO_M 0x1 ++#define VMAU_CTRL_IRQ_EN 0x10 ++#define VMAU_CTRL_SLPOW 0x10000 ++#define VMAU_CTRL_TO_DBLK 0x1000000 ++#define VMAU_LAMBDA_THRETH(a) (((a) & 0x3)<<25) ++ ++#define REG_VMAU_STATUS 0x80048 ++ ++#define REG_VMAU_CCHN_ADDR 0x8004C ++ ++#define REG_VMAU_VIDEO_TYPE 0x80050 ++#define VMAU_FMT_H264 0x1 ++#define VMAU_FMT_RV9 0x2 ++#define VMAU_FMT_VC1 0x3 ++#define VMAU_FMT_MPEG2 0x4 ++#define VMAU_FMT_MPEG4 0x5 ++#define VMAU_FMT_VP8 0x6 ++#define VMAU_I4_MSK(a) (((a) & 0x1)<<3) ++#define VMAU_I16_MSK(a) (((a) & 0x1)<<4) ++#define VMAU_I8_MSK(a) (((a) & 0x1)<<5) ++#define VMAU_PT8_MSK(a) (((a) & 0x1)<<6) ++#define VMAU_MODE_DEC (0x0<<11) ++#define VMAU_MODE_ENC (0x1<<11) ++#define VMAU_IS_ISLICE(a) (((a) & 0x1)<<12) ++#define VMAU_PREDM_MSK(a) (((a) & 0x1FFFF)<<14) ++#define VMAU_TSE(en) (((en) & 0x1)<<31) ++ ++#define REG_VMAU_Y_GS 0x80054 ++#define VMAU_FRM_WID(a) (((a) & 0x3FFF)<<0) ++#define VMAU_FRM_HEI(a) (((a) & 0x3FFF)<<16) ++ ++#define REG_VMAU_DEC_DONE 0x80058 ++ ++#define REG_VMAU_ENC_DONE 0x8005C ++ ++#define REG_VMAU_POS 0x80060 ++ ++#define REG_VMAU_MCF_STA 0x80064 ++ ++#define REG_VMAU_DEC_YADDR 0x80068 ++ ++#define REG_VMAU_DEC_UADDR 0x8006C ++ ++#define REG_VMAU_DEC_VADDR 0x80070 ++ ++#define REG_VMAU_DEC_STR 0x80074 ++ ++#define REG_VMAU_DEADZONE 0x80078 ++#define VMAU_DEADZONE0_IY(a) (((a) & 0xFF)<<0) ++#define VMAU_DEADZONE1_PY(a) (((a) & 0xFF)<<8) ++#define VMAU_DEADZONE2_IC(a) (((a) & 0xFF)<<16) ++#define VMAU_DEADZONE3_PC(a) (((a) & 0xFF)<<24) ++ ++#define REG_VMAU_ACMASK 0x8007C ++ ++#define REG_VMAU_MD_CFG4 0x800D8 ++#define VMAU_YSSE_THR(a) (((a) & 0xFFFFFF)<<0) ++#define VMAU_I8_BIAS(a) (((a) & 0xF)<<24) ++#define VMAU_PT8_BIAS(a) (((a) & 0xF)<<28) ++ ++#define REG_VMAU_MD_CFG5 0x800DC ++#define VMAU_CSSE_THR(a) (((a) & 0xFFFFFF)<<0) ++#define VMAU_CQP_OFFSET(a) (((a) & 0x1F)<<24) ++#define VMAU_I4_COST_MAX(a) (((a) & 0x1)<<29) ++#define VMAU_I8_COST_MAX(a) (((a) & 0x1)<<30) ++#define VMAU_I16_COST_MAX(a) (((a) & 0x1)<<31) ++ ++#define REG_VMAU_MD_CFG6 0x800FC ++#define VMAU_DCM_PARAM(a) (((a) & 0xFFFFFF)<<0) ++#define VMAU_SDE_PRIOR(a) (((a) & 0xF)<<24) ++#define VMAU_DB_PRIOR(a) (((a) & 0xF)<<28) ++ ++#define REG_VMAU_MD_CFG7 0x80114 ++#define VMAU_CFG_SIZE_X(a) (((a) & 0xF)<<0) ++#define VMAU_CFG_SIZE_Y(a) (((a) & 0xF)<<4) ++#define VMAU_CFG_IW_THR(a) (((a) & 0x1FF)<<8) ++#define VMAU_CFG_BASEQP(a) (((a) & 0x3F)<<17) ++#define VMAU_CFG_ALPHA(a) (((a) & 0xFF)<<23) ++#define VMAU_PS_COST_MAX(a) (((a) & 0x1)<<31) ++ ++#define REG_VMAU_MD_CFG8 0x80118 ++#define VMAU_CFG_MVR_THR1(a) (((a) & 0x7FFF)<<0) ++#define VMAU_CFG_MVR_THR2(a) (((a) & 0x1FFFF)<<15) ++ ++#define REG_VMAU_MD_CFG9 0x8011C ++#define VMAU_CFG_MVR_THR3(a) (((a) & 0xFFFFF)<<0) ++#define VMAU_CFG_BETA(a) (((a) & 0xFF)<<20) ++ ++#define REG_VMAU_MD_CFG10 0x80190 ++ ++#define REG_VMAU_MD_CFG11 0x80194 ++#define VMAU_CFG_MD_RBIAS(a) (((a) & 0xf) << 21) ++#define VMAU_CFG_MD_RBIAS_EN(a) (((a) & 1) << 25) ++#define VMAU_CFG_MD_PCDC_N0(a) (((a) & 7) << 26) ++#define VMAU_CFG_MD_IFA_VLD(a) (((a) & 1) << 29) ++#define VMAU_CFG_MD_SLV_VLD(a) (((a) & 1) << 30) ++#define VMAU_CFG_MD_SET_VLD(a) (((a) & 1) << 31) ++ ++#define REG_VMAU_MD_MODE 0x80198 ++ ++#define REG_VMAU_DEADZONE1 0x8019C ++ ++#define REG_VMAU_IPRED_CFG0 0x801C0 ++#define VMAU_IP_MD_VAL(a) (((a) & 0x1)<<30) ++#define VMAU_IP_REF_NEB_4(a) (((a) & 0x1)<<29) ++#define VMAU_IP_REF_NEB_8(a) (((a) & 0x1)<<28) ++#define VMAU_IP_REF_PRD_C(a) (((a) & 0xF)<<24) ++#define VMAU_IP_REF_PRD_4(a) (((a) & 0xF)<<20) ++#define VMAU_IP_REF_PRD_8(a) (((a) & 0xF)<<16) ++#define VMAU_IP_REF_PRD_16(a) (((a) & 0xF)<<12) ++#define VMAU_IP_REF_CUV_EN(a) (((a) & 0x1)<<11) ++#define VMAU_IP_REF_C4_EN(a) (((a) & 0x1)<<10) ++#define VMAU_IP_REF_C8_EN(a) (((a) & 0x1)<<9) ++#define VMAU_IP_REF_C16_EN(a) (((a) & 0x1)<<8) ++#define VMAU_IP_REF_LMDUV_EN(a) (((a) & 0x1)<<7) ++#define VMAU_IP_REF_LMD4_EN(a) (((a) & 0x1)<<6) ++#define VMAU_IP_REF_LMD8_EN(a) (((a) & 0x1)<<5) ++#define VMAU_IP_REF_LMD16_EN(a) (((a) & 0x1)<<4) ++#define VMAU_IP_REF_BITUV_EN(a) (((a) & 0x1)<<3) ++#define VMAU_IP_REF_BIT4_EN(a) (((a) & 0x1)<<2) ++#define VMAU_IP_REF_BIT8_EN(a) (((a) & 0x1)<<1) ++#define VMAU_IP_REF_BIT16_EN(a) (((a) & 0x1)<<0) ++ ++#define REG_VMAU_IPRED_CFG1 0x801C4 ++#define VMAU_IP_REF_4_BIT0(a) (((a) & 0xF)<<0) ++#define VMAU_IP_REF_4_BIT1(a) (((a) & 0xF)<<4) ++#define VMAU_IP_REF_4_BIT2(a) (((a) & 0xF)<<8) ++#define VMAU_IP_REF_4_BIT3(a) (((a) & 0xF)<<12) ++#define VMAU_IP_REF_8_BIT0(a) (((a) & 0xF)<<16) ++#define VMAU_IP_REF_8_BIT1(a) (((a) & 0xF)<<20) ++#define VMAU_IP_REF_8_BIT2(a) (((a) & 0xF)<<24) ++#define VMAU_IP_REF_8_BIT3(a) (((a) & 0xF)<<28) ++ ++#define REG_VMAU_IPRED_CFG2 0x801C8 ++#define VMAU_IP_REF_16_BIT0(a) (((a) & 0xF)<<0) ++#define VMAU_IP_REF_16_BIT1(a) (((a) & 0xF)<<4) ++#define VMAU_IP_REF_16_BIT2(a) (((a) & 0xF)<<8) ++#define VMAU_IP_REF_16_BIT3(a) (((a) & 0xF)<<12) ++#define VMAU_IP_REF_C_BIT0(a) (((a) & 0xF)<<16) ++#define VMAU_IP_REF_C_BIT1(a) (((a) & 0xF)<<20) ++#define VMAU_IP_REF_C_BIT2(a) (((a) & 0xF)<<24) ++#define VMAU_IP_REF_C_BIT3(a) (((a) & 0xF)<<28) ++ ++#define REG_VMAU_IPRED_CFG3 0x801CC ++#define VMAU_IP_REF_LMD16_IFO(a) (((a) & 0xF)<<0) ++#define VMAU_IP_REF_LMD8_IFO(a) (((a) & 0xF)<<4) ++#define VMAU_IP_REF_LMD4_IFO(a) (((a) & 0xF)<<8) ++#define VMAU_IP_REF_LMDUV_IFO(a) (((a) & 0xF)<<12) ++#define VMAU_IP_REF_NEB_8REF(a) (((a) & 0xF)<<16) ++#define VMAU_IP_REF_NEB_4REF(a) (((a) & 0xF)<<20) ++ ++#define REG_VMAU_IPRED_CFG4 0x801D0 ++#define VMAU_IP_REF_C4_IFO(a) (((a) & 0xFFFF)<<0) ++#define VMAU_IP_REF_C8_IFO(a) (((a) & 0xFFFF)<<16) ++ ++#define REG_VMAU_IPRED_CFG5 0x801D4 ++#define VMAU_IP_REF_C16_IFO(a) (((a) & 0xFFFF)<<0) ++#define VMAU_IP_REF_CUV_IFO(a) (((a) & 0xFFFF)<<16) ++ ++#define REG_VMAU_MEML 0x84000 ++ ++#define REG_VMAU_QT 0x88000 ++ ++#define REG_VMAU_CTX_CFBC 0x80174 ++ ++/******************************************** ++ DBLK (deblock) ++*********************************************/ ++#define REG_DBLK_DHA 0x70000 ++ ++#define REG_DBLK_CFG 0x7005C ++#define DBLK_CFG_ALPHA(a) (((a) & 0x1F)<<0) ++#define DBLK_CFG_BETA(a) (((a) & 0x1F)<<8) ++#define DBLK_CFG_NO_LFT(a) (((a) & 0x1)<<17) ++ ++#define REG_DBLK_TRIG 0x70060 ++#define DBLK_RUN 0x1 ++#define DBLK_STOP 0x2 ++#define DBLK_RESET 0x4 ++#define DBLK_SLICE_RUN 0x8 ++ ++#define REG_DBLK_CTRL 0x70064 ++#define DBLK_CTRL(expand, rotate, loop_filter) \ ++( ((expand) & 0x1)<<4 | \ ++ ((rotate) & 0x3)<<1 | \ ++ ((loop_filter) & 0x1)<<0 \ ++) ++ ++#define REG_DBLK_VTR 0x70068 ++#define DBLK_FMT_H264 0x1 ++#define DBLK_FMT_RV9 0x2 ++#define DBLK_FMT_VC1 0x3 ++#define DBLK_FMT_MPEG2 0x4 ++#define DBLK_FMT_MPEG4 0x5 ++#define DBLK_FMT_VP8 0x6 ++#define DBLK_FRM_I 0x0 ++#define DBLK_FRM_P 0x1 ++#define DBLK_FRM_B 0x2 ++#define DBLK_VTR(beta, alpha, vp8_spl, vp8_kf, \ ++ frm_typ, video_fmt) \ ++( ((beta) & 0xFF)<<24 | \ ++ ((alpha) & 0xFF)<<16 | \ ++ ((vp8_spl) & 0x1)<<9 | \ ++ ((vp8_kf) & 0x1)<<5 | \ ++ ((frm_typ) & 0x3)<<3 | \ ++ ((video_fmt) & 0x7)<<0 \ ++) ++ ++#define REG_DBLK_FSTA 0x7006C ++ ++#define REG_DBLK_GSTA 0x70070 ++#define DBLK_STAT_DOEND (0x1<<0) ++ ++#define REG_DBLK_GSIZE 0x70074 ++#define DBLK_GSIZE(mb_height, mb_width) \ ++( ((mb_height) & 0xFFFF)<<16 | \ ++ ((mb_width) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GENDA 0x70078 ++ ++#define REG_DBLK_GPOS 0x7007C ++#define DBLK_GPOS(first_mby, first_mbx) \ ++( ((first_mby) & 0xFFFF)<<16 | \ ++ ((first_mbx) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GPIC_STR 0x70080 ++#define DBLK_GPIC_STR(dst_strd_c, dst_strd_y) \ ++( ((dst_strd_c) & 0xFFFF)<<16 | \ ++ ((dst_strd_y) & 0xFFFF)<<0 \ ++) ++ ++#define REG_DBLK_GPIC_YA 0x70084 ++ ++#define REG_DBLK_GPIC_CA 0x70088 ++ ++#define REG_DBLK_GP_ENDA 0x7008C ++ ++#define REG_DBLK_SLICE_ENDA 0x70090 ++ ++#define REG_DBLK_BLK_CTRL 0x70094 ++ ++#define REG_DBLK_BLK_FIFO 0x70098 ++ ++#define REG_DBLK_MOS_CFG 0x70240 ++#define REG_DBLK_MOS_ADDR 0x70244 ++#define DBLK_MOS_BASE_ADDR VPU_BASE + 0xC7000 ++#define REG_DBLK_MOS_CRC 0x70248 ++/******************************************** ++ SDE (stream parser/encoding) ++*********************************************/ ++#define REG_SDE_STAT 0x90000 ++#define SDE_STAT_BSEND (0x1<<1) ++ ++#define REG_SDE_SL_CTRL 0x90004 ++#define SDE_SLICE_INIT (0x1<<1) ++#define SDE_MB_RUN (0x1<<0) ++ ++#define REG_SDE_SL_GEOM 0x90008 ++#define SDE_SL_GEOM(mb_height, mb_width, \ ++ first_mby, first_mbx) \ ++( ((mb_height) & 0xFF)<<24 | \ ++ ((mb_width) & 0xFF)<<16 | \ ++ ((first_mby) & 0xFF)<<8 | \ ++ ((first_mbx) & 0xFF)<<0 \ ++) ++ ++#define REG_SDE_GL_CTRL 0x9000C ++#define SDE_BP(mby, mbx) \ ++( ((mby) & 0xFF)<<24 | \ ++ ((mbx) & 0xFF)<<16 \ ++) ++#define SDE_MODE_AUTO (0x0<<4) ++#define SDE_MODE_STEP (0x1<<4) ++#define SDE_MODE_DEBUG (0x2<<4) ++#define SDE_EN (0x1<<0) ++ ++#define REG_SDE_CODEC_ID 0x90010 ++#define SDE_FMT_H264_DEC (0x1<<0) ++#define SDE_FMT_H264_ENC (0x1<<1) ++#define SDE_FMT_VP8_DEC (0x1<<2) ++#define SDE_FMT_VC1_DEC (0x1<<3) ++#define SDE_FMT_MPEG2_DEC (0x1<<4) ++#define SDE_FMT_VP8_ENC (0x1<<5) ++ ++#define REG_SDE_CFG0 0x90014 ++#define REG_SDE_CFG1 0x90018 ++#define REG_SDE_CFG2 0x9001C ++#define REG_SDE_CFG3 0x90020 ++#define REG_SDE_CFG4 0x90024 ++#define REG_SDE_CFG5 0x90028 ++#define REG_SDE_CFG6 0x9002C ++#define REG_SDE_CFG7 0x90030 ++#define REG_SDE_CFG8 0x90034 ++#define REG_SDE_CFG9 0x90038 ++#define REG_SDE_CFG10 0x9003C ++#define REG_SDE_CFG11 0x90040 ++#define REG_SDE_CFG12 0x90044 ++#define REG_SDE_CFG13 0x90048 ++#define REG_SDE_CFG14 0x9004C ++#define REG_SDE_CFG15 0x90050 ++ ++#define REG_SDE_CTX_TBL 0x92000 ++#define REG_SDE_CQP_TBL 0x93800 ++ ++/**************************************************************** ++ JPGC (jpeg codec) ++*****************************************************************/ ++#define REG_JPGC_TRIG 0xE0000 ++#define REG_JPGC_GLBI 0xE0004 ++#define REG_JPGC_STAT 0xE0008 ++#define JPGC_STAT_ENDF (0x1<<31) ++#define REG_JPGC_BSA 0xE000C ++#define REG_JPGC_P0A 0xE0010 ++#define REG_JPGC_P1A 0xE0014 ++#define REG_JPGC_P2A 0xE0018 ++#define REG_JPGC_P3A 0xE001C ++#define REG_JPGC_NMCU 0xE0028 ++#define REG_JPGC_NRSM 0xE002C ++#define REG_JPGC_P0C 0xE0030 ++#define REG_JPGC_P1C 0xE0034 ++#define REG_JPGC_P2C 0xE0038 ++#define REG_JPGC_P3C 0xE003C ++#define REG_JPGC_WIDTH 0xE0040 ++#define REG_JPGC_MCUS 0xE0064 ++#define REG_JPGC_ZIGM0 0xE1000 ++#define REG_JPGC_ZIGM1 0xE1100 ++#define REG_JPGC_HUFB 0xE1200 ++#define REG_JPGC_HUFM 0xE1300 ++#define REG_JPGC_QMEM 0xE1400 ++#define REG_JPGC_HUFE 0xE1800 ++#define REG_JPGC_HUFS 0xE1800 ++ ++#define JPGC_CORE_OPEN (0x1<<0) ++#define JPGC_BS_TRIG (0x1<<1) ++#define JPGC_PP_TRIG (0x1<<2) ++#define JPGC_TERM (0x1<<3) ++#define JPGC_RSTER_MD (0x1<<8) ++ ++/**************************************************************** ++ ODMA ++*****************************************************************/ ++ ++#define REG_ODMA_TRIG 0x60000 ++#define REG_ODMA_CTRL 0x60004 ++#define REG_ODMA_BDYA 0x60008 ++#define REG_ODMA_BDCA 0x6000C ++#define REG_ODMA_BSTR 0x60010 ++#define REG_ODMA_HDYA 0x60014 ++#define REG_ODMA_HDCA 0x60018 ++#define REG_ODMA_SPYA 0x6001C ++#define REG_ODMA_SPCA 0x60020 ++ ++#define ODMA_REC_STRDY(y) (((y) & 0xFFFF)<<16) ++#define ODMA_REC_STRDC(c) (((c) & 0xFFFF)<<0) ++ ++/**************************************************************** ++ JRFD ++*****************************************************************/ ++ ++#define REG_JRFD_TRIG 0x10000 ++#define REG_JRFD_CTRL 0x10004 ++#define REG_JRFD_HDYA 0x10008 ++#define REG_JRFD_HDCA 0x1000C ++#define REG_JRFD_HSTR 0x10010 ++#define REG_JRFD_BDYA 0x10014 ++#define REG_JRFD_BDCA 0x10018 ++#define REG_JRFD_BSTR 0x1001C ++#define REG_JRFD_MHDY 0x10020 ++#define REG_JRFD_MHDC 0x10024 ++#define REG_JRFD_MBDY 0x10028 ++#define REG_JRFD_MBDC 0x1002C ++ ++#define JRFD_BODY_STRDY(y) (((y) & 0xFFFF)<<16) ++#define JRFD_BODY_STRDC(c) (((c) & 0xFFFF)<<0) ++ ++/**************************************************************** ++ IFA ++*****************************************************************/ ++#define REG_IFA_CTRL 0xB0000 ++#define REG_IFA_FRM_SIZE 0xB0004 ++#define REG_IFA_RAWY_BA 0xB0008 ++#define REG_IFA_RAWC_BA 0xB000C ++#define REG_IFA_RAW_STR 0xB0010 ++#define REG_IFA_REFY_BA0 0xB0014 ++#define REG_IFA_REFC_BA0 0xB0018 ++#define REG_IFA_THRD_Y 0xB001C ++#define REG_IFA_THRD_C 0xB0020 ++#define REG_IFA_REFY_BA1 0xB0030 ++#define REG_IFA_REFC_BA1 0xB0034 ++ ++#define IFA_CTRL_INIT ( 0x1 << 0 ) ++#define IFA_CTRL_UV_EN(a) ( (a&0x1) << 1 ) ++#define IFA_CTRL_RRS_SY(a) ( (a&0x3) << 2 ) ++#define IFA_CTRL_RRS_SC(a) ( (a&0x1) << 4 ) ++#define IFA_CTRL_DDR_DW(a) ( (a&0x1) << 5 ) ++#define IFA_CTRL_RRS_EN(a) ( (a&0x1) << 6 ) ++#define IFA_CTRL_DUMP_EN(a) ( (a&0x1) << 7 ) ++#define IFA_CTRL_REF_BIDX(a) ( (a&0xff) << 8 ) ++#define IFA_CTRL_CGE (0x1<<16) //1 mean close clk-gate, 0 default open ++#define IFA_CTRL_RAW_TYPE(a) ( (a&0x1) << 17 ) ++ ++#define IFA_FRM_W(a) ( (a&0xFFF) << 0 ) ++#define IFA_FRM_H(a) ( (a&0xFFF) << 16 ) ++ ++#define IFA_STR_Y(a) ( (a&0xFFFF) << 0 ) ++#define IFA_STR_C(a) ( (a&0xFFFF) << 16 ) ++ ++#define IFA_THRD_U(a) ( (a&0x3FFF) << 0 ) ++#define IFA_THRD_V(a) ( (a&0x3FFF) << 16 ) ++ ++ ++/**************************************************************** ++ VPU tables ++*****************************************************************/ ++ ++/******************************************** ++ Motion interpolation programable table ++*********************************************/ ++#define IS_SKIRT 0 ++#define IS_MIRROR 1 ++ ++#define IS_BIAVG 0 ++#define IS_WT1 1 ++#define IS_WT2 2 ++#define IS_FIXWT 3 ++ ++#define IS_ILUT0 0 ++#define IS_ILUT1 2 ++#define IS_EC 1 ++ ++#define IS_TCS 1 ++#define NOT_TCS 0 ++#define IS_SCS 1 ++#define NOT_SCS 0 ++#define IS_HLDGL 1 ++#define NOT_HLDGL 0 ++#define IS_AVSDGL 1 ++#define NOT_AVSDGL 0 ++ ++#define INTP_HDIR 0 ++#define INTP_VDIR 1 ++ ++enum IntpID { ++ MPEG_HPEL = 0, ++ MPEG_QPEL, ++ H264_QPEL, ++ H264_EPEL, ++ RV8_TPEL, ++ RV9_QPEL, ++ RV9_CPEL, ++ WMV2_QPEL, ++ VC1_QPEL, ++ AVS_QPEL, ++ VP6_QPEL, ++ VP8_QPEL, ++ VP8_EPEL, ++ VP8_BIL, ++ VP8_FPEL, /*full-pixel for chroma*/ ++ HEVC_QPEL, ++ HEVC_EPEL, ++}; ++ ++enum PosID { ++ H0V0 = 0, ++ H1V0, ++ H2V0, ++ H3V0, ++ H0V1, ++ H1V1, ++ H2V1, ++ H3V1, ++ H0V2, ++ H1V2, ++ H2V2, ++ H3V2, ++ H0V3, ++ H1V3, ++ H2V3, ++ H3V3, ++}; ++ ++enum TapTYP { ++ TAP2 = 0, ++ TAP4, ++ TAP6, ++ TAP8, ++}; ++ ++enum SPelSFT { ++ HPEL = 0, ++ QPEL, ++ EPEL, ++}; ++ ++typedef struct IntpFMT_t{ ++ char tap; ++ char intp_pkg[2]; ++ char hldgl; ++ char avsdgl; ++ char intp[2]; ++ char intp_dir[2]; ++ char intp_coef[2][8]; ++ char intp_rnd[2]; ++ char intp_sft[2]; ++ char intp_sintp[2]; ++ char intp_srnd[2]; ++ char intp_sbias[2]; ++}IntpFMT_t; ++ ++//__place_k0_data__ ++//static char AryFMT[] = { ++// IS_SKIRT, IS_MIRROR, IS_SKIRT, IS_SKIRT, ++// IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, ++// IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, ++// IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, IS_SKIRT, ++//}; ++// ++//__place_k0_data__ ++//static char SubPel[] = { ++// HPEL, QPEL, QPEL, EPEL, ++// QPEL, QPEL, QPEL, QPEL, ++// QPEL, QPEL, QPEL, QPEL, ++// EPEL, HPEL, QPEL, QPEL, EPEL ++//}; ++ ++__place_k0_data__ ++static IntpFMT_t IntpFMT[][16] = { ++ { ++ /************* MPEG_HPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0} }, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ }, ++ ++ { ++ /************* MPEG_QPEL ***************/ ++ {/*H0V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1},{0},}, ++ {/*intp_rnd*/15, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H1V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H3V3*/ ++ TAP8, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 3, -6, 20, 20, -6, 3, -1}, {-1, 3, -6, 20, 20, -6, 3, -1},}, ++ {/*intp_rnd*/15, 15}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/1, 1}, ++ {/*intp_srnd*/1, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* H264_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {IS_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {IS_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {IS_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 10}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H3V3*/ ++ TAP6, {IS_TCS, IS_SCS}, IS_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* H264_EPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/0}, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/0}, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* RV8_TPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0}, {-1, 12, 6, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0}, {-1, 12, 6, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 12, 6, -1, 0, 0, 0, 0}, {-1, 6, 12, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 6, 12, -1, 0, 0, 0, 0}, {-1, 6, 12, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 0}, //{0,128} ++ {/*intp_sft*/0, 8}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* RV9_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 32}, ++ {/*intp_sft*/5, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0}, {1, -5, 52, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/16, 0}, ++ {/*intp_sft*/5, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 16}, ++ {/*intp_sft*/6, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 16}, ++ {/*intp_sft*/5, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0}, {1, -5, 20, 20, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 16}, ++ {/*intp_sft*/6, 5}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -5, 20, 52, -5, 1, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 52, 20, -5, 1, 0, 0}, {1, -5, 20, 52, -5, 1, 0, 0},}, ++ {/*intp_rnd*/32, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -5, 20, 20, -5, 1, 0, 0}, {1, -5, 20, 52, -5, 1, 0, 0},}, ++ {/*intp_rnd*/16, 32}, ++ {/*intp_sft*/5, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 2}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* RV9_CPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0}, {3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 1}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0}, {1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 7}, ++ {/*intp_sft*/0, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 4}, ++ {/*intp_sft*/0, 3}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0}, {1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 1}, ++ {/*intp_sft*/0, 2}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* WMV2_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/1, 0}, ++ {/*intp_srnd*/1, 0}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/8, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* VC1_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/8, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/31, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 8}, ++ {/*intp_sft*/6, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-4, 53, 18, -3, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/7, 0}, ++ {/*intp_sft*/4, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 32}, ++ {/*intp_sft*/4, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 8}, ++ {/*intp_sft*/4, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-1, 9, 9, -1, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/7, 32}, ++ {/*intp_sft*/4, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/31, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-4, 53, 18, -3, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-1, 9, 9, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 8}, ++ {/*intp_sft*/6, 4}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {NOT_TCS, IS_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_VDIR, INTP_HDIR}, ++ {/*intp_coef*/{-3, 18, 53, -4, 0, 0, 0, 0}, {-3, 18, 53, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/31, 32}, ++ {/*intp_sft*/6, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* AVS_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -1, 5, 5, -1, 0, 0, 0}, {-1, -2, 96, 42, -7, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, -2, 96, 42, -7, 0, 0, 0}, {0, -1, 5, 5, -1, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, 5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0}, {0, -1, 5, 5, -1, 0, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0, -7, 42, 96, -2, -1, 0, 0}, {0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/0, 1}, ++ }, ++ {/*H2V3*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, -1, 5, 5, -1, 0, 0, 0}, {0, -7, 42, 96, -2, -1, 0, 0},}, ++ {/*intp_rnd*/64, 0}, //{0,512} ++ {/*intp_sft*/0, 10}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, IS_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 5, 5, -1, 0, 0, 0, 0}, {-1, 5, -5, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/0, 32}, ++ {/*intp_sft*/0, 6}, ++ {/*intp_sintp*/0, 1}, ++ {/*intp_srnd*/0, 1}, ++ {/*intp_sbias*/1, 1}, ++ }, ++ }, ++ ++ { ++ /************* VP6_QPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-4, 109, 24, -1, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-4, 68, 68, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 109, 24, -1, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 68, 68, -4, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 24, 109, -4, 0, 0, 0, 0}, {-1, 24, 109, -4, 0, 0, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_QPEL ***************/ ++ {/*H0V0*/ ++ TAP6, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {2, -11, 108, 36, -8, 1, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {3, -16, 77, 77, -16, 3, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0},{0},}, ++ {/*intp_rnd*/64, 0}, ++ {/*intp_sft*/7, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{2, -11, 108, 36, -8, 1, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, -16, 77, 77, -16, 3, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP6, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, -8, 36, 108, -11, 2, 0, 0}, {1, -8, 36, 108, -11, 2, 0, 0},}, ++ {/*intp_rnd*/64, 64}, ++ {/*intp_sft*/7, 7}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_EPEL ***************/ ++ {/*H0V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/0}, ++ {/*H2V0*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 0}, ++ {/*intp_sft*/3, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/0}, ++ {/*H2V2*/ ++ TAP2, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/4, 4}, ++ {/*intp_sft*/3, 3}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* VP8_BIL ***************/ ++ {/*H0V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V0*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 2}, ++ {/*intp_sft*/1, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V1*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{3, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/1, 0}, ++ {/*intp_sft*/1, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 1}, ++ {/*intp_sft*/2, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 1}, ++ {/*intp_sft*/1, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V2*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{1, 1, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 1}, ++ {/*intp_sft*/2, 1}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H0V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/2, 0}, ++ {/*intp_sft*/2, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{3, 1, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H2V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 1, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/1, 2}, ++ {/*intp_sft*/1, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H3V3*/ ++ TAP2, {IS_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{1, 3, 0, 0, 0, 0, 0, 0},{1, 3, 0, 0, 0, 0, 0, 0},}, ++ {/*intp_rnd*/2, 2}, ++ {/*intp_sft*/2, 2}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ }, ++ ++ { ++ /************* VP8_FPEL ***************/ ++ {/*H0V0*/0}, ++ {/*H1V0*/0}, ++ {/*H2V0*/0}, ++ {/*H3V0*/0}, ++ {/*H0V1*/0}, ++ {/*H1V1*/0}, ++ {/*H2V1*/0}, ++ {/*H3V1*/0}, ++ {/*H0V2*/0}, ++ {/*H1V2*/0}, ++ {/*H2V2*/0}, ++ {/*H3V2*/0}, ++ {/*H0V3*/0}, ++ {/*H1V3*/0}, ++ {/*H2V3*/0}, ++ {/*H3V3*/0}, ++ }, ++ ++ { ++ /************* HEVC_QPEL ***************/ ++ {/*H0V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 4, -10, 58, 17, -5, 1, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{-1, 4, -11, 40, 40, -11, 4, -1},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, 0}, ++ {/*intp_coef*/{0, 1, -5, 17, 58, -10, 4, -1},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V1*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 4, -10, 58, 17, -5, 1, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V1*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -10, 58, 17, -5, 1, 0},{-1, 4, -10, 58, 17, -5, 1, 0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V1*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -11, 40, 40, -11, 4, -1},{-1, 4, -10, 58, 17, -5, 1, 0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V1*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, 1, -5, 17, 58, -10, 4, -1},{-1, 4, -10, 58, 17, -5, 1, 0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{-1, 4, -11, 40, 40, -11, 4, -1},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -10, 58, 17, -5, 1, 0},{-1, 4, -11, 40, 40, -11, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -11, 40, 40, -11, 4, -1},{-1, 4, -11, 40, 40, -11, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, 1, -5, 17, 58, -10, 4, -1},{-1, 4, -11, 40, 40, -11, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_VDIR, 0}, ++ {/*intp_coef*/{0, 1, -5, 17, 58, -10, 4, -1},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -10, 58, 17, -5, 1, 0},{0, 1, -5, 17, 58, -10, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-1, 4, -11, 40, 40, -11, 4, -1},{0, 1, -5, 17, 58, -10, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP8, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 1}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{0, 1, -5, 17, 58, -10, 4, -1},{0, 1, -5, 17, 58, -10, 4, -1},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/0, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++ { ++ /************* HEVC_EPEL ***************/ ++ {/*H0V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0}, ++ {/*intp_coef*/{1, 0, 0, 0, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0}, ++ {/*intp_srnd*/0}, ++ {/*intp_sbias*/0}, ++ }, ++ {/*H1V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-2, 58, 10, -2, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 54, 16, -2, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-6, 46, 28, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H4V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 36, 36, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H5V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-4, 28, 46, -6, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H6V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-2, 16, 54, -4, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H7V0*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/1, 0}, {INTP_HDIR, INTP_VDIR}, ++ {/*intp_coef*/{-2, 10, 58, -2, 0, 0, 0, 0},{0},}, ++ {/*intp_rnd*/32, 0}, ++ {/*intp_sft*/6, 12}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V2*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H0V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H1V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H2V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ {/*H3V3*/ ++ TAP4, {NOT_TCS, NOT_SCS}, NOT_HLDGL, NOT_AVSDGL, ++ {/*intp*/0, 0}, {0, 0}, ++ {/*intp_coef*/{0},{0},}, ++ {/*intp_rnd*/0, 0}, ++ {/*intp_sft*/0, 0}, ++ {/*intp_sintp*/0, 0}, ++ {/*intp_srnd*/0, 0}, ++ {/*intp_sbias*/0, 0}, ++ }, ++ }, ++ ++}; ++ ++#endif /*__HELIX_H__*/ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.c +new file mode 100644 +index 000000000..66b093f2a +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.c +@@ -0,0 +1,51 @@ ++#include "helix_jpeg_dec.h" ++ ++void JPEGD_SliceInit(_JPEGD_SliceInfo *s) ++{ ++ unsigned int i; ++ volatile unsigned int *chn = (volatile unsigned int *)s->des_va; ++ ++ GEN_VDMA_ACFG(chn, TCSM_FLUSH, 0, 0x0); ++ ++ /* Open clock configuration */ ++ GEN_VDMA_ACFG(chn, REG_JPGC_GLBI, 0, OPEN_CLOCK); ++ ++ /************************************************** ++ Huffman Encode Table configuration ++ *************************************************/ ++ for(i=0; ihuffmin++) ); ++ for(i=0; ihuffbase++)); ++ for(i=0; ihuffsymb++)); ++ /************************************************** ++ Quantization Table configuration ++ *************************************************/ ++ for(i=0; iqmem++)); ++ ++ /************************************************** ++ REGs configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_JPGC_STAT, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_JPGC_BSA, 0,(uint32_t)s->bsa); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P0A,0, (uint32_t)s->p0a); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P1A, 0,(uint32_t)s->p1a ); ++ GEN_VDMA_ACFG(chn,REG_JPGC_NMCU,0, s->nmcu); ++ GEN_VDMA_ACFG(chn,REG_JPGC_NRSM,0, s->nrsm); ++ GEN_VDMA_ACFG(chn,REG_JPGC_WIDTH,0, s->width); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P0C,0, s->pxc[0]);/* component 0 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++ GEN_VDMA_ACFG(chn,REG_JPGC_P1C,0, s->pxc[1]); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P2C,0, s->pxc[2]); ++ GEN_VDMA_ACFG(chn,REG_JPGC_P3C,0, s->pxc[3]); ++ ++ GEN_VDMA_ACFG(chn,REG_JPGC_GLBI,0, (YUV420PVH /*P0V|P0H*/| ++ JPGC_NCOL /*NCOL*/ | ++ JPGC_DEC/*DE*/ | ++ JPGC_EN /*ENABLE*/) ); ++ ++ GEN_VDMA_ACFG(chn,REG_JPGC_TRIG,VDMA_ACFG_TERM,JPGC_BS_TRIG|JPGC_PP_TRIG | JPGC_CORE_OPEN); ++ ++ ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.h +new file mode 100644 +index 000000000..bdaa6dbc1 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_dec.h +@@ -0,0 +1,72 @@ ++/**************************************************************** ++*****************************************************************/ ++ ++#ifndef __JZM_JPEG_DEC_H__ ++#define __JZM_JPEG_DEC_H__ ++#include "helix.h" ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#define printf printk ++#endif ++ ++ ++#define JPGC_EN (0x1) /* JPGC enable signal */ ++ ++#define YUV420P0C (0x30) /* component 0 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P1C (0x03) /* component 1 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P2C (0x03) /* component 2 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P3C (0xf0) /* component 3 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++ ++#define YUV420PVH (0x0a<<16) /* component vertical/horizontal size of MCU:P3H P3V P2H P2V P1H P1V P0H P0V */ ++#define JPGC_RSM (0x1<<2) /* JPGC rstart marker enable signal */ ++#define JPGC_SPEC (0x0<<1) /* YUV420 mode */ ++#define JPGC_UNIV (0x1<<1) /* YUV444 or YUV422 mode */ ++#define JPGC_DEC (0x1<<3) /* JPGC decode signal: 1 (decode); 0(encode) */ ++#define OPEN_CLOCK (0x1) /* open the core clock */ ++#define JPGC_NCOL (0x2<<4) /* color numbers of a MCU minus 1,it always 2 for YUV color space */ ++#define STAT_CLEAN (0x0) /* clean the STAT register */ ++#define CORE_RST (0x1<<6) /* JPGC core reset ,high active */ ++#define JPGC_EFE (0x1<<8) /* JPGC EFE source */ ++#define VRAM_RAWY_BA (VPU_BASE | 0xF0000) ++#define VRAM_RAWC_BA (VRAM_RAWY_BA + 256) ++ ++#if 0 ++/* JPEG Decode quantization table select level */ ++typedef enum { ++ LOW_QUALITY, ++ MEDIUMS_QUALITY, ++ HIGH_QUALITY ++} QUANT_QUALITY; ++#endif ++ ++#define HUFFMIN_LEN 16 ++#define HUFFBASE_LEN 64 ++#define HUFFSYMB_LEN 336 ++#define QMEM_LEN 256 ++ ++/* ++ _JPEGD_SliceInfo: ++ JPEG Decoder Slice Level Information ++ */ ++typedef struct{ ++ uint32_t *des_va, des_pa; ++ uint32_t bsa; /* bitstream buffer address */ ++ uint32_t p0a, p1a; /* componet 0-3 plane buffer address */ ++ uint8_t nrsm; /* Re-Sync-Marker gap number */ ++ uint32_t nmcu; /* number of MCU minus one */ ++ uint32_t width; /* yuv nv12 frame width, bit15: 1,NV12, 0,TILE .(1 << 15) | (mb_width - 1)*/ ++ int *huffmin ; ++ int *huffbase ; ++ int *huffsymb ; ++ int *qmem ; ++ uint32_t pxc[4]; /* component 0~3 config info */ ++ ++}_JPEGD_SliceInfo; ++ ++ ++ ++void JPEGD_SliceInit(_JPEGD_SliceInfo *s); ++#endif// __JZM_JPEG_ENC_H__ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.c +new file mode 100644 +index 000000000..59550079a +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.c +@@ -0,0 +1,241 @@ ++#include "helix_jpeg_enc.h" ++ ++__place_k0_data__ ++uint32_t huffenc[HUFNUM][HUFFENC_LEN] = { ++ {0x100, 0x101, 0x204, 0x30b, 0x41a, 0x678, 0x7f8, 0x9f6, ++ 0xf82, 0xf83, 0x30c, 0x41b, 0x679, 0x8f6, 0xaf6, 0xf84, ++ 0xf85, 0xf86, 0xf87, 0xf88, 0x41c, 0x7f9, 0x9f7, 0xbf4, ++ 0xf89, 0xf8a, 0xf8b, 0xf8c, 0xf8d, 0xf8e, 0x53a, 0x8f7, ++ 0xbf5, 0xf8f, 0xf90, 0xf91, 0xf92, 0xf93, 0xf94, 0xf95, ++ 0x53b, 0x9f8, 0xf96, 0xf97, 0xf98, 0xf99, 0xf9a, 0xf9b, ++ 0xf9c, 0xf9d, 0x67a, 0xaf7, 0xf9e, 0xf9f, 0xfa0, 0xfa1, ++ 0xfa2, 0xfa3, 0xfa4, 0xfa5, 0x67b, 0xbf6, 0xfa6, 0xfa7, ++ 0xfa8, 0xfa9, 0xfaa, 0xfab, 0xfac, 0xfad, 0x7fa, 0xbf7, ++ 0xfae, 0xfaf, 0xfb0, 0xfb1, 0xfb2, 0xfb3, 0xfb4, 0xfb5, ++ 0x8f8, 0xec0, 0xfb6, 0xfb7, 0xfb8, 0xfb9, 0xfba, 0xfbb, ++ 0xfbc, 0xfbd, 0x8f9, 0xfbe, 0xfbf, 0xfc0, 0xfc1, 0xfc2, ++ 0xfc3, 0xfc4, 0xfc5, 0xfc6, 0x8fa, 0xfc7, 0xfc8, 0xfc9, ++ 0xfca, 0xfcb, 0xfcc, 0xfcd, 0xfce, 0xfcf, 0x9f9, 0xfd0, ++ 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, 0xfd8, ++ 0x9fa, 0xfd9, 0xfda, 0xfdb, 0xfdc, 0xfdd, 0xfde, 0xfdf, ++ 0xfe0, 0xfe1, 0xaf8, 0xfe2, 0xfe3, 0xfe4, 0xfe5, 0xfe6, ++ 0xfe7, 0xfe8, 0xfe9, 0xfea, 0xfeb, 0xfec, 0xfed, 0xfee, ++ 0xfef, 0xff0, 0xff1, 0xff2, 0xff3, 0xff4, 0xff5, 0xff6, ++ 0xff7, 0xff8, 0xff9, 0xffa, 0xffb, 0xffc, 0xffd, 0xffe, ++ 0x30a, 0xaf9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, ++ 0xfd0, 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, ++ 0x101, 0x204, 0x30a, 0x418, 0x419, 0x538, 0x678, 0x8f4, ++ 0x9f6, 0xbf4, 0x30b, 0x539, 0x7f6, 0x8f5, 0xaf6, 0xbf5, ++ 0xf88, 0xf89, 0xf8a, 0xf8b, 0x41a, 0x7f7, 0x9f7, 0xbf6, ++ 0xec2, 0xf8c, 0xf8d, 0xf8e, 0xf8f, 0xf90, 0x41b, 0x7f8, ++ 0x9f8, 0xbf7, 0xf91, 0xf92, 0xf93, 0xf94, 0xf95, 0xf96, ++ 0x53a, 0x8f6, 0xf97, 0xf98, 0xf99, 0xf9a, 0xf9b, 0xf9c, ++ 0xf9d, 0xf9e, 0x53b, 0x9f9, 0xf9f, 0xfa0, 0xfa1, 0xfa2, ++ 0xfa3, 0xfa4, 0xfa5, 0xfa6, 0x679, 0xaf7, 0xfa7, 0xfa8, ++ 0xfa9, 0xfaa, 0xfab, 0xfac, 0xfad, 0xfae, 0x67a, 0xaf8, ++ 0xfaf, 0xfb0, 0xfb1, 0xfb2, 0xfb3, 0xfb4, 0xfb5, 0xfb6, ++ 0x7f9, 0xfb7, 0xfb8, 0xfb9, 0xfba, 0xfbb, 0xfbc, 0xfbd, ++ 0xfbe, 0xfbf, 0x8f7, 0xfc0, 0xfc1, 0xfc2, 0xfc3, 0xfc4, ++ 0xfc5, 0xfc6, 0xfc7, 0xfc8, 0x8f8, 0xfc9, 0xfca, 0xfcb, ++ 0xfcc, 0xfcd, 0xfce, 0xfcf, 0xfd0, 0xfd1, 0x8f9, 0xfd2, ++ 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, 0xfd8, 0xfd9, 0xfda, ++ 0x8fa, 0xfdb, 0xfdc, 0xfdd, 0xfde, 0xfdf, 0xfe0, 0xfe1, ++ 0xfe2, 0xfe3, 0xaf9, 0xfe4, 0xfe5, 0xfe6, 0xfe7, 0xfe8, ++ 0xfe9, 0xfea, 0xfeb, 0xfec, 0xde0, 0xfed, 0xfee, 0xfef, ++ 0xff0, 0xff1, 0xff2, 0xff3, 0xff4, 0xff5, 0xec3, 0xff6, ++ 0xff7, 0xff8, 0xff9, 0xffa, 0xffb, 0xffc, 0xffd, 0xffe, ++ 0x100, 0x9fa, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, ++ 0xfd0, 0xfd1, 0xfd2, 0xfd3, 0xfd4, 0xfd5, 0xfd6, 0xfd7, ++ 0x100, 0x202, 0x203, 0x204, 0x205, 0x206, 0x30e, 0x41e, ++ 0x53e, 0x67e, 0x7fe, 0x8fe, 0xfff, 0xfff, 0xfff, 0xfff, ++ 0x100, 0x101, 0x102, 0x206, 0x30e, 0x41e, 0x53e, 0x67e, ++ 0x7fe, 0x8fe, 0x9fe, 0xafe, 0xfff, 0xfff, 0xfff, 0xfff} ++}; ++ ++__place_k0_data__ ++uint32_t qmem[QTNUM][QMEM_LEN] = { ++ //normal quantization table ++ {0x0100, 0x0155, 0x0155, 0x0a49, 0x0155, 0x0b33, 0x0100, 0x0a49, ++ 0x0a49, 0x0a49, 0x09c7, 0x09c7, 0x0100, 0x00cd, 0x0955, 0x08cd, ++ 0x093b, 0x0955, 0x12e9, 0x12e9, 0x0955, 0x251f, 0x11c7, 0x11af, ++ 0x0911, 0x08cd, 0x1a35, 0x113b, 0x2421, 0x1111, 0x1a35, 0x113b, ++ 0x1a49, 0x1a49, 0x0880, 0x19c7, 0x10b2, 0x10d2, 0x0880, 0x10f1, ++ 0x10ba, 0x10ea, 0x1a49, 0x1a49, 0x10cd, 0x1095, 0x231f, 0x10ba, ++ 0x1955, 0x229d, 0x193b, 0x193b, 0x193b, 0x2421, 0x10d2, 0x223f, ++ 0x2219, 0x2249, 0x10a4, 0x1911, 0x10b2, 0x2d05, 0x193b, 0x10a4, ++ 0x09c7, 0x09c7, 0x09c7, 0x0955, 0x12e9, 0x0955, 0x1155, 0x093b, ++ 0x093b, 0x1155, 0x10a4, 0x23e1, 0x1a49, 0x23e1, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, 0x10a4, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, ++ //finer quantization table ++ {0x0155, 0x0200, 0x0200, 0x0b33, 0x0200, 0x0200, 0x0155, 0x0b33, ++ 0x0b33, 0x0b33, 0x0155, 0x0155, 0x0155, 0x0155, 0x0100, 0x093b, ++ 0x09c7, 0x0100, 0x0a49, 0x0a49, 0x0100, 0x0911, 0x12e9, 0x0955, ++ 0x09c7, 0x093b, 0x11c7, 0x0080, 0x11af, 0x11af, 0x11c7, 0x0080, ++ 0x11c7, 0x08f1, 0x08cd, 0x08ba, 0x1a49, 0x1155, 0x08cd, 0x08c3, ++ 0x1a5f, 0x08c3, 0x08f1, 0x11c7, 0x251f, 0x23e1, 0x251f, 0x1a5f, ++ 0x1a35, 0x1111, 0x0880, 0x0880, 0x0880, 0x11af, 0x1155, 0x10ea, ++ 0x19bb, 0x10f1, 0x2421, 0x19bb, 0x1a49, 0x2421, 0x0880, 0x1111, ++ 0x0155, 0x0155, 0x0155, 0x0100, 0x0a49, 0x0100, 0x0911, 0x09c7, ++ 0x09c7, 0x0911, 0x1111, 0x08c3, 0x11c7, 0x08c3, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, ++ //finest quantization table ++ {0x02ab, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x02ab, 0x0400, ++ 0x0400, 0x0400, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x0b33, ++ 0x0200, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x0155, 0x0200, 0x0b33, ++ 0x0200, 0x0b33, 0x0a49, 0x0155, 0x0a49, 0x0a49, 0x0a49, 0x0155, ++ 0x0a49, 0x0155, 0x0a49, 0x0100, 0x00cd, 0x09c7, 0x0a49, 0x0100, ++ 0x00cd, 0x0100, 0x0155, 0x0a49, 0x09c7, 0x0955, 0x09c7, 0x00cd, ++ 0x00cd, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x0a49, 0x09c7, 0x0955, ++ 0x093b, 0x0955, 0x12e9, 0x093b, 0x00cd, 0x12e9, 0x12e9, 0x12e9, ++ 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x02ab, 0x0155, 0x0200, ++ 0x0200, 0x0155, 0x12e9, 0x0100, 0x0a49, 0x0100, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, 0x12e9, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000} ++}; ++ ++ ++void JPEGE_SliceInit(_JPEGE_SliceInfo *s) ++{ ++ unsigned int i; ++ volatile unsigned int *chn = (volatile unsigned int *)s->des_va; ++ ++ GEN_VDMA_ACFG(chn, TCSM_FLUSH, 0, 0x0); ++ ++ /* Open clock configuration */ ++ GEN_VDMA_ACFG(chn, REG_JPGC_GLBI, 0, OPEN_CLOCK); ++ ++ /************************************************** ++ Huffman Encode Table configuration ++ *************************************************/ ++ for(i=0; ihuffenc_sel][i]); ++ ++ /************************************************** ++ Quantization Table configuration ++ *************************************************/ ++ for(i=0; iql_sel][i]); ++ ++ /************************************************** ++ REGs configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_JPGC_STAT, 0, STAT_CLEAN); ++ GEN_VDMA_ACFG(chn, REG_JPGC_BSA, 0, s->bsa); ++ ++ if(s->raw_format) { /* NV12 or NV21 */ ++ GEN_VDMA_ACFG(chn, REG_JPGC_P0A, 0, VRAM_RAWY_BA); ++ } else {/* TILE */ ++ GEN_VDMA_ACFG(chn, REG_JPGC_P0A, 0, s->p0a); ++ GEN_VDMA_ACFG(chn, REG_JPGC_P1A, 0, s->p1a); ++ } ++ ++ GEN_VDMA_ACFG(chn, REG_JPGC_NMCU, 0, s->nmcu); ++ GEN_VDMA_ACFG(chn, REG_JPGC_NRSM, 0, s->nrsm); ++ ++ GEN_VDMA_ACFG(chn, REG_JPGC_P0C, 0, YUV420P0C); ++ GEN_VDMA_ACFG(chn, REG_JPGC_P1C, 0, YUV420P1C); ++ GEN_VDMA_ACFG(chn, REG_JPGC_P2C, 0, YUV420P2C); ++ ++ if(s->raw_format) { ++ GEN_VDMA_ACFG(chn, REG_JPGC_GLBI, 0, (YUV420PVH | ++ JPGC_NCOL | ++ JPGC_SPEC /* MODE */ | ++ JPGC_EFE | ++ JPGC_EN)); ++ ++ GEN_VDMA_ACFG(chn, REG_JPGC_TRIG, 0, JPGC_BS_TRIG | JPGC_PP_TRIG | JPGC_CORE_OPEN); ++ ++ }else{ ++ GEN_VDMA_ACFG(chn, REG_JPGC_GLBI, 0, (YUV420PVH | ++ JPGC_NCOL | ++ JPGC_SPEC /* MODE */ | ++ JPGC_EN)); ++ ++ GEN_VDMA_ACFG(chn, REG_JPGC_TRIG, VDMA_ACFG_TERM, JPGC_BS_TRIG | JPGC_PP_TRIG | JPGC_CORE_OPEN); ++ } ++ ++ ++ /************************************************** ++ EFE configuration ++ *************************************************/ ++ if(s->raw_format) { ++ GEN_VDMA_ACFG(chn, REG_EFE_GEOM, 0, (EFE_JPGC_LST_MBY(s->mb_height-1) | ++ EFE_JPGC_LST_MBX(s->mb_width-1) ) ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWY_SBA, 0, s->raw[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWU_SBA, 0, s->raw[1]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWV_SBA, 0, s->raw[2]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAW_STRD, 0, (EFE_RAW_STRDY(s->stride[0]) | ++ EFE_RAW_STRDC(s->stride[1]) ) ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_RAW_DBA, 0, VRAM_RAWY_BA); ++ GEN_VDMA_ACFG(chn, REG_EFE_CTRL, VDMA_ACFG_TERM, (EFE_PLANE_NV12 | ++ EFE_ID_JPEG | ++ EFE_EN | ++ (s->raw_format)| ++ EFE_RUN) ); ++ } ++ ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.h +new file mode 100644 +index 000000000..48fbbbc11 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_jpeg_enc.h +@@ -0,0 +1,81 @@ ++/**************************************************************** ++*****************************************************************/ ++ ++#ifndef __JZM_JPEG_ENC_H__ ++#define __JZM_JPEG_ENC_H__ ++#include "helix.h" ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#define printf printk ++#endif ++ ++#define HUFFENC_LEN (384) /* Huffman encoder table lenth */ ++#define QMEM_LEN (256) /* Quantization table lenth */ ++#define HUFNUM (1) /* Huffman encode table number */ ++#define QTNUM (3) /* Quantization table number */ ++#define YUV420P0C (0x30) /* component 0 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P1C (0x07) /* component 1 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420P2C (0x07) /* component 2 configure information NBLK<<4| QT<<2| HA<<1| HD */ ++#define YUV420PVH (0x0a<<16) /* component vertical/horizontal size of MCU:P3H P3V P2H P2V P1H P1V P0H P0V */ ++#define JPGC_RSM (0x1<<2) /* JPGC rstart marker enable signal */ ++#define JPGC_SPEC (0x0<<1) /* YUV420 mode */ ++#define JPGC_UNIV (0x1<<1) /* YUV444 or YUV422 mode */ ++#define JPGC_EN (0x1) /* JPGC enable signal */ ++#define OPEN_CLOCK (0x1) /* open the core clock */ ++#define JPGC_NCOL (0x2<<4) /* color numbers of a MCU minus 1,it always 2 for YUV color space */ ++#define STAT_CLEAN (0x0) /* clean the STAT register */ ++#define CORE_RST (0x1<<6) /* JPGC core reset ,high active */ ++#define JPGC_EFE (0x1<<8) /* JPGC EFE source */ ++#define VRAM_RAWY_BA (VPU_BASE | 0xF0000) ++#define VRAM_RAWC_BA (VRAM_RAWY_BA + 256) ++ ++#if 0 ++/* JPEG encode quantization table select level */ ++typedef enum { ++ LOW_QUALITY, ++ MEDIUMS_QUALITY, ++ HIGH_QUALITY ++} QUANT_QUALITY; ++#endif ++ ++/* ++ _JPEGE_SliceInfo: ++ JPEG Encoder Slice Level Information ++ */ ++ ++typedef struct _JPEGE_SliceInfo { ++ uint32_t *des_va, des_pa; ++ uint8_t ncol; /* number of color/components of a MCU minus one */ ++ uint8_t rsm; /* Re-sync-marker enable */ ++ uint32_t bsa; /* bitstream buffer address */ ++ uint32_t p0a, p1a; /* componet 0-3 plane buffer address */ ++ uint8_t nrsm; /* Re-Sync-Marker gap number */ ++ uint32_t nmcu; /* number of MCU minus one */ ++ uint32_t raw[3]; /*{rawy, rawu, rawv} or {rawy, rawc, N/C}*/ ++ uint32_t stride[2]; /*{stride_y, stride_c}, only used in raster raw*/ ++ uint32_t mb_height; ++ uint32_t mb_width; ++ uint8_t raw_format; ++ ++ /* Quantization level select,0-2 level */ ++ int ql_sel; ++ uint8_t huffenc_sel; /* Huffman ENC Table select */ ++}_JPEGE_SliceInfo; ++ ++ ++__place_k0_data__ ++extern uint32_t huffenc[HUFNUM][HUFFENC_LEN]; ++ ++__place_k0_data__ ++extern uint32_t qmem[QTNUM][QMEM_LEN]; ++ ++/* ++ JPEGE_SliceInit(_JPEGE_SliceInfo *s) ++ @param s: slice information structure ++ */ ++ ++void JPEGE_SliceInit(_JPEGE_SliceInfo *s); ++#endif// __JZM_JPEG_ENC_H__ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.c +new file mode 100644 +index 000000000..a98315e35 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.c +@@ -0,0 +1,1647 @@ ++#include "helix_x264_enc.h" ++#define MB_WID ((s->frame_width + 15) / 16) ++#define MB_HEI ((s->frame_height + 15) / 16) ++__place_k0_data__ ++static uint32_t lps_range[64] = { ++ 0xeeceaefc, 0xe1c3a5fc, 0xd6b99cfc, 0xcbb094f2, ++ 0xc1a78ce4, 0xb79e85da, 0xad967ece, 0xa48e78c4, ++ 0x9c8772ba, 0x94806cb0, 0x8c7966a6, 0x8573619e, ++ 0x7e6d5c96, 0x7867578e, 0x72625386, 0x6c5d4e80, ++ 0x66584a78, 0x61544672, 0x5c4f436c, 0x574b3f66, ++ 0x53473c62, 0x4e43395c, 0x4a403658, 0x463d3352, ++ 0x4339304e, 0x3f362e4a, 0x3c342b46, 0x39312942, ++ 0x362e273e, 0x332c253c, 0x30292338, 0x2e272136, ++ 0x2b251f32, 0x29231d30, 0x27211c2c, 0x251f1a2a, ++ 0x231e1928, 0x211c1826, 0x1f1b1624, 0x1d191522, ++ 0x1c181420, 0x1a17131e, 0x1915121c, 0x1714111a, ++ 0x16131018, 0x15120f18, 0x14110e16, 0x13100d14, ++ 0x120f0c14, 0x110e0c12, 0x100d0b12, 0x0f0d0a10, ++ 0x0e0c0a10, 0x0d0b090e, 0x0c0a090e, 0x0c0a080c, ++ 0x0b09070c, 0x0a09070a, 0x0a08070a, 0x0908060a, ++ 0x09070608, 0x08070508, 0x07060508, 0x00000000, ++}; ++ ++ ++ ++#define C_SPE_ADD_MB_NUM 3 ++void BUF_SHARE_CFG(_H264E_SliceInfo *s, uint32_t *buf_addr_group, uint8_t *buf_ref_mby_size, uint8_t *buf_odma_spe_flag, uint8_t *buf_odma_alg_flag) ++{ ++ int beyond_size = (s->buf_share_size + 1) * 64; ++ ++ int c_pxl_space = (s->mb_width*16)*(s->mb_height*8); ++ int y_space = (s->mb_width*16)*(s->mb_height*16+beyond_size); ++ int c_space = (s->mb_width*16)*(s->mb_height*8+(beyond_size/2)); ++ int y_every_space = (s->mb_width*16)*beyond_size; ++ int c_every_space = (s->mb_width*16)*(beyond_size/2); ++ ++ int mb_total = s->mb_width * s->mb_height; ++ ++ int spe_frm = 0; ++ int spe_ad_flag = 0; ++ int spe_mi_flag = 0; ++ int last_spe_ad_flag = 0; ++ int last_spe_mi_flag = 0; ++ int c_ofst_addr_n = ((s->frame_idx)*c_every_space)/c_space; ++ int last_c_ofst_addr_n = ((s->frame_idx-1)*c_every_space)/c_space; ++ ++ if(mb_total%2){ ++ //spe_frm = 1; ++ } ++ ++ //buf_beyond_yaddr ++ buf_addr_group[0] = s->fb[0][0] + y_space; ++ //buf_beyond_caddr ++ buf_addr_group[1] = spe_frm ? s->fb[0][1] + c_space + (128*C_SPE_ADD_MB_NUM) : s->fb[0][1] + c_space; ++ int tmp_beyond_caddr = spe_frm ? s->fb[0][1] + c_space + 128 : s->fb[0][1] + c_space; ++ ++ //calc last frame addr ++ int last_y_ofst_addr = s->frame_idx == 0 ? 0 : ((s->frame_idx-1)*y_every_space)%y_space; ++ int last_y_tmp_addr = last_y_ofst_addr ? (buf_addr_group[0] - last_y_ofst_addr) : s->fb[0][0]; ++ ++ int last_c_ofst_addr = s->frame_idx == 0 ? 0 : ((s->frame_idx-1)*c_every_space)%c_space; ++ int last_c_tmp_addr = last_c_ofst_addr ? (tmp_beyond_caddr - last_c_ofst_addr) : s->fb[0][1]; ++ ++ if(spe_frm & last_c_tmp_addr != s->fb[0][1]){ ++ if(last_c_ofst_addr_n%2){ ++ last_c_tmp_addr -= 256; ++ last_spe_mi_flag = 1; ++ } ++ ++ if(last_c_tmp_addr%256){ ++ last_c_tmp_addr += 128; ++ last_spe_ad_flag = 1; ++ } ++ ++ if((last_c_tmp_addr + c_every_space > buf_addr_group[1]) & last_spe_mi_flag){ ++ last_c_tmp_addr += 256; ++ } ++ } ++ ++ ++ //refy_addr_ba0 ++ buf_addr_group[4] = s->frame_idx == 0 ? s->fb[0][0] : last_y_tmp_addr; ++ //refy_addr_ba1 ++ buf_addr_group[5] = s->fb[0][0]; ++ //refc_addr_ba0 ++ buf_addr_group[6] = s->frame_idx == 0 ? s->fb[0][1] : last_c_tmp_addr; ++ //refc_addr_ba1 ++ buf_addr_group[7] = s->fb[0][1]; ++ //ref_mby_size ++ *buf_ref_mby_size = !s->buf_share_en ? 0xff : ((buf_addr_group[0] - buf_addr_group[4])/(s->mb_width*16))/16 - 1; ++ ++ ++ int y_ofst_addr = (s->frame_idx*y_every_space)%y_space; ++ int y_tmp_addr = y_ofst_addr ? (buf_addr_group[0] - y_ofst_addr) : s->fb[0][0]; ++ //buf_start_yaddr ++ buf_addr_group[2] = s->frame_idx == 0 ? s->fb[0][0] : y_tmp_addr; ++ ++ int c_ofst_addr = (s->frame_idx*c_every_space)%c_space; ++ int c_tmp_addr = c_ofst_addr ? (tmp_beyond_caddr - c_ofst_addr) : s->fb[0][1]; ++ //buf_start_caddr ++ buf_addr_group[3] = s->frame_idx == 0 ? s->fb[0][1] : c_tmp_addr; ++ ++ int spe_flag = 1; ++ if(spe_frm & buf_addr_group[3] != s->fb[0][1]){ ++ if(c_ofst_addr_n%2){ ++ buf_addr_group[3] -= 256; ++ spe_mi_flag = 1; ++ } ++ ++ if(buf_addr_group[3]%256){ ++ buf_addr_group[3] += 128; ++ spe_ad_flag = 1; ++ } ++ ++ if((buf_addr_group[3] + c_every_space > buf_addr_group[1]) & spe_mi_flag){ ++ buf_addr_group[3] += 256; ++ spe_flag = 0; ++ } ++ ++ } ++ ++ *buf_odma_spe_flag = spe_flag; ++ ++ int alg_flag = 0; ++ int c_pxl_space_row = s->mb_width*16*8; ++ if(((buf_addr_group[1] - (128*C_SPE_ADD_MB_NUM)) - buf_addr_group[3])% c_pxl_space_row == 0 ) ++ alg_flag = 1; ++ ++ *buf_odma_alg_flag = alg_flag; ++} ++ ++ ++ ++void H264E_SliceInit(_H264E_SliceInfo *s) ++{ ++ unsigned int i, j/*, tmp = 0*/; ++ volatile unsigned int *chn = (volatile unsigned int *)s->des_va; ++ ++ GEN_VDMA_ACFG(chn, TCSM_FLUSH, 0, 0); ++ ++ ++ /************************************************** ++ buf share cfg ++ *************************************************/ ++ ++ uint32_t buf_addr_group[8]; ++ uint8_t buf_ref_mby_size; ++ uint8_t buf_odma_spe_flag; ++ uint8_t buf_odma_alg_flag; ++ ++ BUF_SHARE_CFG(s, buf_addr_group, &buf_ref_mby_size, &buf_odma_spe_flag, &buf_odma_alg_flag); ++ ++ uint32_t buf_beyond_yaddr = buf_addr_group[0]; ++ uint32_t buf_beyond_caddr = buf_addr_group[1]; ++ uint32_t buf_start_yaddr = buf_addr_group[2]; ++ uint32_t buf_start_caddr = buf_addr_group[3]; ++ uint32_t refy_addr_ba0 = buf_addr_group[4]; ++ uint32_t refy_addr_ba1 = buf_addr_group[5]; ++ uint32_t refc_addr_ba0 = buf_addr_group[6]; ++ uint32_t refc_addr_ba1 = buf_addr_group[7]; ++ uint8_t ref_mby_size = buf_ref_mby_size; ++ uint8_t odma_spe_flag = buf_odma_spe_flag; ++ uint8_t odma_alg_flag = buf_odma_alg_flag; ++ ++ if(0){ ++ printf("[BUF_SHARE] frame_idx: %d, y_start: 0x%x, y_base: 0x%x, y_beyond: 0x%x, spe_flag: %d, alg_flag: %d\n", ++ s->frame_idx,buf_addr_group[2],s->fb[0][0],buf_addr_group[0],odma_spe_flag,odma_alg_flag); ++ printf(" c_start: 0x%x, c_base: 0x%x, c_beyond: 0x%x\n", ++ buf_addr_group[3],s->fb[0][1],buf_addr_group[1]); ++ printf(" ifa_y0: 0x%x, ifa_y1: 0x%x, ifa_c0: 0x%x, ifa_c1: 0x%x, mby: %d\n", ++ buf_addr_group[4],buf_addr_group[5],buf_addr_group[6],buf_addr_group[7],buf_ref_mby_size); ++ } ++ ++ /************************************************** ++ EFE configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_EFE_GEOM, 0, (EFE_FST_MBY(s->first_mby) | ++ EFE_LST_MBY(s->last_mby) | ++ EFE_LST_MBX(MB_WID-1)) ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_COEF_BA, 0, VRAM_MAU_RESA); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWY_SBA, 0, s->raw[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWU_SBA, 0, s->raw[1]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAWV_SBA, 0, s->raw[2]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAW_STRD, 0, (EFE_RAW_STRDY(s->stride[0]) | ++ EFE_RAW_STRDC(s->stride[1]) ) ); ++ GEN_VDMA_ACFG(chn, REG_EFE_TOPMV_BA, 0, VRAM_TOPMV_BA); ++ GEN_VDMA_ACFG(chn, REG_EFE_TOPPA_BA, 0, VRAM_TOPPA_BA); ++ GEN_VDMA_ACFG(chn, REG_EFE_MECHN_BA, 0, VRAM_ME_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_EFE_MAUCHN_BA, 0, VRAM_MAU_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_EFE_DBLKCHN_BA, 0, VRAM_DBLK_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_EFE_SDECHN_BA, 0, VRAM_SDE_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_EFE_RAW_DBA, 0, VRAM_RAWY_BA); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_MAX_QP, 0, s->max_qp); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_BASE_INFO0, 0, ++ (( (s->roi_info[3].roi_qp & 0x3F) <<2 | ++ (s->roi_info[3].roi_md & 0x1) <<1 | ++ (s->roi_info[3].roi_en & 0x1) <<0 ) << 24) | ++ (( (s->roi_info[2].roi_qp & 0x3F) <<2 | ++ (s->roi_info[2].roi_md & 0x1) <<1 | ++ (s->roi_info[2].roi_en & 0x1) <<0 ) << 16) | ++ (( (s->roi_info[1].roi_qp & 0x3F) <<2 | ++ (s->roi_info[1].roi_md & 0x1) <<1 | ++ (s->roi_info[1].roi_en & 0x1) <<0 ) << 8) | ++ (( (s->roi_info[0].roi_qp & 0x3F) <<2 | ++ (s->roi_info[0].roi_md & 0x1) <<1 | ++ (s->roi_info[0].roi_en & 0x1) <<0 ) << 0) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_BASE_INFO1, 0, ++ (( (s->roi_info[7].roi_qp & 0x3F) <<2 | ++ (s->roi_info[7].roi_md & 0x1) <<1 | ++ (s->roi_info[7].roi_en & 0x1) <<0 ) << 24) | ++ (( (s->roi_info[6].roi_qp & 0x3F) <<2 | ++ (s->roi_info[6].roi_md & 0x1) <<1 | ++ (s->roi_info[6].roi_en & 0x1) <<0 ) << 16) | ++ (( (s->roi_info[5].roi_qp & 0x3F) <<2 | ++ (s->roi_info[5].roi_md & 0x1) <<1 | ++ (s->roi_info[5].roi_en & 0x1) <<0 ) << 8) | ++ (( (s->roi_info[4].roi_qp & 0x3F) <<2 | ++ (s->roi_info[4].roi_md & 0x1) <<1 | ++ (s->roi_info[4].roi_en & 0x1) <<0 ) << 0) ++ ); ++ ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO0, 0, ++ ( (s->roi_info[0].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[0].roi_umby & 0xFF) << 16 | ++ (s->roi_info[0].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[0].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO1, 0, ++ ( (s->roi_info[1].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[1].roi_umby & 0xFF) << 16 | ++ (s->roi_info[1].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[1].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO2, 0, ++ ( (s->roi_info[2].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[2].roi_umby & 0xFF) << 16 | ++ (s->roi_info[2].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[2].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO3, 0, ++ ( (s->roi_info[3].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[3].roi_umby & 0xFF) << 16 | ++ (s->roi_info[3].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[3].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO4, 0, ++ ( (s->roi_info[4].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[4].roi_umby & 0xFF) << 16 | ++ (s->roi_info[4].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[4].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO5, 0, ++ ( (s->roi_info[5].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[5].roi_umby & 0xFF) << 16 | ++ (s->roi_info[5].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[5].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO6, 0, ++ ( (s->roi_info[6].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[6].roi_umby & 0xFF) << 16 | ++ (s->roi_info[6].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[6].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_ROI_POS_INFO7, 0, ++ ( (s->roi_info[7].roi_bmby & 0xFF) << 24 | ++ (s->roi_info[7].roi_umby & 0xFF) << 16 | ++ (s->roi_info[7].roi_rmbx & 0xFF) << 8 | ++ (s->roi_info[7].roi_lmbx & 0xFF) << 0 ) ++ ); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QP_GEN_TAB, 0, ( (VRAM_QP_TAB_BA & 0xFFFFF) | ++ ((s->qp_tab_len & 0x7FF) << 20) | ++ (s->qp_tab_mode & 0x1)<<31) ); ++ /* ++ for(i=0; iqp_tab_len;i++){ ++ GEN_VDMA_ACFG(chn, VRAM_QP_TAB_BA+i*4, 0, *(s->qp_tab+i)); ++ } ++ */ ++ GEN_VDMA_ACFG(chn, REG_EFE_CQP_OFST, 0, (s->cqp_offset & 0x1F)); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SSAD, 0, 0); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_DCS, 0, ++ ( EFE_DCS_EN(s->daisy_chain_en) | ++ EFE_DCS_OTH(s->curr_thread_id) | ++ EFE_DCS_RT(4) ) ++ ); ++ /* ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CTRL , 0, (s->sas_en << 0 | ++ s->crp_en << 1 | ++ s->sas_mthd << 2 | ++ 0 << 3 | ++ s->rc_bu_level << 4 | ++ s->rc_wait_en << 7 | ++ s->base_qp << 8 | ++ s->rc_mb_level << 14 | ++ s->min_qp << 16 | ++ s->qp_tab_en << 22 | ++ s->mbrc_qpg_sel << 23 | // 0 : only mbrc_ofst valid; 1: both mbrc_ofst and qpg_ofst valid ++ s->max_qp << 24 | ++ s->mbrc_enable << 30 | ++ s->mbrc_wait << 31 )); ++ */ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CTRL , 0, (s->sas_en << 0 | ++ s->crp_en << 1 | ++ s->sas_mthd << 2 | ++ 0 << 3 | ++ s->rc_bu_level << 4 | ++ s->rc_bu_wait_en << 7 | ++ s->base_qp << 8 | ++ s->rc_mb_level << 14 | ++ s->min_qp << 16 | ++ s->qp_tab_en << 22 | ++ s->mbrc_qpg_sel << 23 |//0:mb_rc effect, 1:mb_rc + qpg effect ++ s->max_qp << 24 | ++ s->rc_mb_wait_en << 30 | ++ (s->rc_mb_en & 0x1) << 31 ));//mb_rc_en ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG0, 0, ((s->qpg_flt_thd[0] & 0x7) << 0 | ++ (s->qpg_flt_thd[1] & 0x7) << 4 | ++ (s->qpg_flt_thd[2] & 0xF) << 8 | ++ (s->qpg_flt_thd[3] & 0x7) << 12 | ++ (s->qpg_flt_thd[4] & 0x7) << 16 )); ++ ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG1 , 0, (s->qpg_mb_thd[0] << 0 | ++ s->qpg_mb_thd[1] << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG2 , 0, (s->qpg_mb_thd[2] << 0 | ++ s->qpg_mb_thd[3] << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG3 , 0, (s->qpg_mb_thd[4] << 0 | ++ s->qpg_mb_thd[5] << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG4 , 0, (s->qpg_mb_thd[6] << 0 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG5 , 0, ((s->qpg_mbqp_ofst[0] & 0x3F) << 0 | ++ (s->qpg_mbqp_ofst[1] & 0x3F) << 8 | ++ (s->qpg_mbqp_ofst[2] & 0x3F) << 16 | ++ (s->qpg_mbqp_ofst[3] & 0x3F) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_QPG_CFG6 , 0, ((s->qpg_mbqp_ofst[4] & 0x3F) << 0 | ++ (s->qpg_mbqp_ofst[5] & 0x3F) << 8 | ++ (s->qpg_mbqp_ofst[6] & 0x3F) << 16 | ++ (s->qpg_mbqp_ofst[7] & 0x3F) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG0 , 0, ((s->force_i16 & 0x1) << 0 | ++ (s->refresh_en & 0x1) << 1 | ++ (s->refresh_mode & 0x1) << 2 | ++ (s->refresh_bias & 0x7) << 3 | ++ (s->sas_eigen_en & 0x1) << 6 | ++ (s->crp_eigen_en & 0x1) << 7 | ++ (s->sas_eigen_dump & 0x1) << 8 | ++ (s->crp_eigen_dump & 0x1) << 9 | ++ (s->cplx_thd_sel & 0x1) << 10 | ++ (s->diff_cplx_sel & 0x1) << 11 | ++ (s->diff_thd_sel & 0x3) << 12 | ++ (s->mb_mode_use & 0x1) << 14 | ++ (s->rrs_en & 0x1) << 15 | ++ (s->refresh_cplx_thd & 0xFF) << 16 | ++ (s->i16dc_cplx_thd & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG1 , 0, ((s->i16dc_qp_base & 0x3F) << 0 | ++ (s->i16dc_qp_sel & 0x1) << 6 | ++ (s->i16_qp_base & 0x3F) << 8 | ++ (s->i16_qp_sel & 0x1) << 14 | ++ (s->diff_qp_base[0] & 0x3F) << 16 | ++ (s->diff_qp_sel[0] & 0x1) << 22 | ++ (s->diff_qp_base[1] & 0x3F) << 24 | ++ (s->diff_qp_sel[1] & 0x1) << 30 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG2 , 0, ((s->cplx_thd_idx[0] & 0x7) << 0 | ++ (s->cplx_thd_idx[1] & 0x7) << 3 | ++ (s->cplx_thd_idx[2] & 0x7) << 6 | ++ (s->cplx_thd_idx[3] & 0x7) << 9 | ++ (s->cplx_thd_idx[4] & 0x7) << 12 | ++ (s->cplx_thd_idx[5] & 0x7) << 15 | ++ (s->cplx_thd_idx[6] & 0x7) << 18 | ++ (s->cplx_thd_idx[7] & 0x7) << 21 | ++ (s->cplx_thd_idx[8] & 0x7) << 24 | ++ (s->cplx_thd_idx[9] & 0x7) << 27 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG3 , 0, ((s->cplx_thd_idx[10] & 0x7) << 0 | ++ (s->cplx_thd_idx[11] & 0x7) << 3 | ++ (s->cplx_thd_idx[12] & 0x7) << 6 | ++ (s->cplx_thd_idx[13] & 0x7) << 9 | ++ (s->cplx_thd_idx[14] & 0x7) << 12 | ++ (s->cplx_thd_idx[15] & 0x7) << 15 | ++ (s->cplx_thd_idx[16] & 0x7) << 18 | ++ (s->cplx_thd_idx[17] & 0x7) << 21 | ++ (s->cplx_thd_idx[18] & 0x7) << 24 | ++ (s->cplx_thd_idx[19] & 0x7) << 27 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG4 , 0, ((s->cplx_thd_idx[20] & 0x7) << 0 | ++ (s->cplx_thd_idx[21] & 0x7) << 3 | ++ (s->cplx_thd_idx[22] & 0x7) << 6 | ++ (s->cplx_thd_idx[23] & 0x7) << 9 | ++ (s->diff_cplx_thd & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG5 , 0, ((s->cplx_thd[0] & 0xFF) << 0 | ++ (s->cplx_thd[1] & 0xFF) << 8 | ++ (s->cplx_thd[2] & 0xFF) << 16 | ++ (s->cplx_thd[3] & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_EIGEN_CFG6 , 0, ((s->cplx_thd[4] & 0xFF) << 0 | ++ (s->cplx_thd[5] & 0xFF) << 8 | ++ (s->cplx_thd[6] & 0xFF) << 16 | ++ (s->cplx_thd[7] & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_DIFFY_CFG , 0, ((s->diff_thd_base[0] & 0xFFFF) << 0 | ++ (s->diff_thd_ofst[0] & 0xFFFF) << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_DIFFU_CFG , 0, ((s->diff_thd_base[1] & 0xFFFF) << 0 | ++ (s->diff_thd_ofst[1] & 0xFFFF) << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_DIFFV_CFG , 0, ((s->diff_thd_base[2] & 0xFFFF) << 0 | ++ (s->diff_thd_ofst[2] & 0xFFFF) << 16 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_CTRL , 0, ((s->skin_dt_en & 0x1) << 0 | ++ (s->skin_lvl & 0x3) << 1 | ++ (s->ncu_mov_en & 0x1) << 3 | ++ (s->skin_cnt_thd & 0x7F) << 8 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PTHD0 , 0, ((s->skin_pxlu_thd[0][0] & 0xFF) << 0 | ++ (s->skin_pxlu_thd[0][1] & 0xFF) << 8 | ++ (s->skin_pxlv_thd[0][0] & 0xFF) << 16 | ++ (s->skin_pxlv_thd[0][1] & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PTHD1 , 0, ((s->skin_pxlu_thd[1][0] & 0xFF) << 0 | ++ (s->skin_pxlu_thd[1][1] & 0xFF) << 8 | ++ (s->skin_pxlv_thd[1][0] & 0xFF) << 16 | ++ (s->skin_pxlv_thd[1][1] & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PTHD2 , 0, ((s->skin_pxlu_thd[2][0] & 0xFF) << 0 | ++ (s->skin_pxlu_thd[2][1] & 0xFF) << 8 | ++ (s->skin_pxlv_thd[2][0] & 0xFF) << 16 | ++ (s->skin_pxlv_thd[2][1] & 0xFF) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_QP_OFST , 0, ((s->skin_qp_ofst[0] & 0x3F) << 0 | ++ (s->skin_qp_ofst[1] & 0x3F) << 8 | ++ (s->skin_qp_ofst[2] & 0x3F) << 16 | ++ (s->skin_qp_ofst[3] & 0x3F) << 24 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PARAM0 , 0, ((s->mult_factor[0] & 0xF) << 0 | ++ (s->shift_factor[0][0] & 0x7) << 4 | ++ (s->shift_factor[0][1] & 0x7) << 8 | ++ (s->skin_ofst[1] & 0x3FF) << 11 | ++ (s->skin_ofst[0] & 0x3FF) << 21 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PARAM1 , 0, ((s->mult_factor[1] & 0xF) << 0 | ++ (s->shift_factor[1][0] & 0x7) << 8 | ++ (s->shift_factor[1][1] & 0x7) << 12 | ++ (s->shift_factor[1][2] & 0x7) << 16 | ++ (s->skin_ofst[2] & 0x3FF) << 20 )); ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_SKIN_PARAM2 , 0, ((s->mult_factor[2] & 0xF) << 0 | ++ (s->shift_factor[2][0] & 0x7) << 8 | ++ (s->shift_factor[2][1] & 0x7) << 12 | ++ (s->shift_factor[2][2] & 0x7) << 16 | ++ (s->skin_ofst[3] & 0x3FF) << 20 )); ++ ++ /************************************************** ++ RC configuration ++ *************************************************/ ++ if(s->rc_mb_en){ //rate ctrl ++ //fprintf(stderr,"s->rc_bu_wait_en:%d\n",s->rc_bu_wait_en); ++ //fprintf(stderr,"s->last_bu_size:%d, s->rc_bu_size:%d\n",s->last_bu_size, s->rc_bu_size); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BINFO1, 0, EFE_RC_BU_LSIZE(s->last_bu_size) | EFE_RC_BU_SIZE(s->rc_bu_size)); ++ //fprintf(stderr,"s->tar_bs_thd[0]:%d, s->tar_bs_thd[1]:%d\n",s->tar_bs_thd[0],s->tar_bs_thd[1]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_GP0THD, 0, ((s->tar_bs_thd[0] & 0xFFFF) << 0 | ++ (s->tar_bs_thd[1] & 0xFFFF) << 16)); ++ //fprintf(stderr,"s->tar_bs_thd[2]:%d, s->tar_bs_thd[3]:%d\n",s->tar_bs_thd[2],s->tar_bs_thd[3]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_GP1THD, 0, ((s->tar_bs_thd[2] & 0xFFFF) << 0 | ++ (s->tar_bs_thd[3] & 0xFFFF) << 16)); ++ //fprintf(stderr,"s->tar_bs_thd[4]:%d, s->tar_bs_thd[5]:%d\n",s->tar_bs_thd[4],s->tar_bs_thd[5]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_GP2THD, 0, ((s->tar_bs_thd[4] & 0xFFFF) << 0 | ++ (s->tar_bs_thd[5] & 0xFFFF) << 16)); ++ //fprintf(stderr,"s->rc_frm_tbs:%d\n",s->rc_frm_tbs & 0x7FFFFFFF); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_TBS, 0, s->rc_frm_tbs & 0x7FFFFFFF); ++ //fprintf(stderr,"s->bu_alg0_qpo[2]:%d, s->bu_alg0_qpo[1]:%d, s->bu_alg0_qpo[0]:%d\n",s->bu_alg0_qpo[2], s->bu_alg0_qpo[1], s->bu_alg0_qpo[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BNQA0, 0, EFE_RC_QPO_CFG(0, s->bu_alg0_qpo[2], s->bu_alg0_qpo[1], s->bu_alg0_qpo[0])); ++ //fprintf(stderr,"s->bu_alg0_qpo[5]:%d, s->bu_alg0_qpo[4]:%d, s->bu_alg0_qpo[3]:%d\n",s->bu_alg0_qpo[5], s->bu_alg0_qpo[4], s->bu_alg0_qpo[3]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BPQA0, 0, EFE_RC_QPO_CFG(0, s->bu_alg0_qpo[5], s->bu_alg0_qpo[4], s->bu_alg0_qpo[3])); ++ //fprintf(stderr,"s->bu_alg1_qpo[2]:%d, s->bu_alg1_qpo[1]:%d, s->bu_alg1_qpo[0]:%d\n",s->bu_alg1_qpo[2], s->bu_alg1_qpo[1], s->bu_alg1_qpo[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BNQA1, 0, EFE_RC_QPO_CFG(0, s->bu_alg1_qpo[2], s->bu_alg1_qpo[1], s->bu_alg1_qpo[0])); ++ //fprintf(stderr,"s->bu_alg1_qpo[5]:%d, s->bu_alg1_qpo[4]:%d, s->bu_alg1_qpo[3]:%d\n",s->bu_alg1_qpo[5], s->bu_alg1_qpo[4], s->bu_alg1_qpo[3]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BPQA1, 0, EFE_RC_QPO_CFG(0, s->bu_alg1_qpo[5], s->bu_alg1_qpo[4], s->bu_alg1_qpo[3])); ++ //fprintf(stderr,"s->mb_cs_qpo[2]:%d, s->mb_cs_qpo[1]:%d, s->mb_cs_qpo[0]:%d\n",s->mb_cs_qpo[2], s->mb_cs_qpo[1], s->mb_cs_qpo[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MNQCS, 0, EFE_RC_QPO_CFG(0, s->mb_cs_qpo[2], s->mb_cs_qpo[1], s->mb_cs_qpo[0])); ++ //fprintf(stderr,"s->mb_cs_qpo[6]:%d, s->mb_cs_qpo[5]:%d, s->mb_cs_qpo[4]:%d, s->mb_cs_qpo[3]:%d\n", ++ //s->mb_cs_qpo[6], s->mb_cs_qpo[5], s->mb_cs_qpo[4], s->mb_cs_qpo[3]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MPQCS, 0, EFE_RC_QPO_CFG(s->mb_cs_qpo[6], s->mb_cs_qpo[5], s->mb_cs_qpo[4], s->mb_cs_qpo[3])); ++ //fprintf(stderr,"s->mb_top_bs_qpo[1]:%d, s->mb_top_bs_qpo[0]:%d\n",s->mb_top_bs_qpo[1], s->mb_top_bs_qpo[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MTBQ, 0, EFE_RC_QPO_CFG(0, 0, s->mb_top_bs_qpo[1], s->mb_top_bs_qpo[0])); ++ //fprintf(stderr,"s->mb_rinfo_qpo[1]:%d, s->mb_rinfo_qpo[0]:%d\n",s->mb_rinfo_qpo[1], s->mb_rinfo_qpo[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MRFQ, 0, EFE_RC_QPO_CFG(0, 0, s->mb_rinfo_qpo[1], s->mb_rinfo_qpo[0])); ++ //fprintf(stderr,"s->mb_target_avg_bs[1]:%d, s->mb_target_avg_bs[0]:%d\n",s->mb_target_avg_bs[1], s->mb_target_avg_bs[0]); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MAMIN, 0, s->mb_target_avg_bs[0] & 0x3FFFF); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MAMAX, 0, s->mb_target_avg_bs[1] & 0x3FFFF); ++ //fprintf(stderr,"s->rc_bu_num:%d, s->mb_gp_num:%d\n",s->rc_bu_num, s->mb_gp_num); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BBS, 0, s->avg_bu_bs & 0x7FFFFF); ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_MINFO, 0, (//EFE_RC_MAD_CFG_RDY | ++ EFE_RC_MBGP_NUM(s->mb_gp_num) | ++ (s->rc_mb_en & 0x1))); ++ char rc_slice_type = s->rc_frm_tbs ? s->frame_type : 0; ++ GEN_VDMA_ACFG(chn, REG_EFE_RC_BINFO0, 0, (EFE_RC_SLICE_TP(rc_slice_type) | ++ EFE_RC_BU_CFG(s->rc_bcfg_mode) | ++ EFE_RC_BU_NUM(s->rc_bu_num) | ++ ((s->rc_mb_en>>1) & 0x1))); ++ } ++ ++ /************************************************** ++ JRFD configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_JRFD_CTRL, 0, (((1==2)<<31) | /* 2:NV21 ,1:NV12*/ ++ (2 << 28) |//sim_lvl ++ (s->jrfd_enable << 27) | ++ (s->frame_height << 14) | ++ s->frame_width)); ++ GEN_VDMA_ACFG(chn, REG_JRFD_HDYA, 0, s->jh[1][0]); ++ GEN_VDMA_ACFG(chn, REG_JRFD_HDCA, 0, s->jh[1][1]); ++ ++ GEN_VDMA_ACFG(chn, REG_JRFD_HSTR, 0, (((s->cm_head_total & 0xffff) << 16) | (s->lm_head_total & 0xffff)) ); ++ ++ GEN_VDMA_ACFG(chn, REG_JRFD_BDYA, 0, s->fb[1][0]);//tile Y address ++ GEN_VDMA_ACFG(chn, REG_JRFD_BDCA, 0, s->fb[1][1]); //tile C address ++ ++ GEN_VDMA_ACFG(chn, REG_JRFD_BSTR, 0, ++ JRFD_BODY_STRDY(((s->frame_width+15)/16)*16) | ++ JRFD_BODY_STRDC(((s->frame_width+15)/16)*8) ); ++ ++ GEN_VDMA_ACFG(chn, REG_JRFD_MHDY, 0, s->jh[2][0]); ++ GEN_VDMA_ACFG(chn, REG_JRFD_MHDC, 0, s->jh[2][1]); ++ GEN_VDMA_ACFG(chn, REG_JRFD_MBDY, 0, s->fb[2][0]); ++ GEN_VDMA_ACFG(chn, REG_JRFD_MBDC, 0, s->fb[2][1]); ++ ++ GEN_VDMA_ACFG(chn, REG_JRFD_TRIG, 0, ((1 << 5) |//init ++ (0 << 4) //ckg low means do clock-gating ++ ));//enable_tile ++ ++ /************************************************** ++ Motion configuration ++ *************************************************/ ++ if(s->frame_type){ ++ //set CHAIN/TMV/SYNC ADDR ++ GEN_VDMA_ACFG(chn, REG_MCE_CHN_BA, 0, VRAM_ME_CHN_BASE);//chn ++ GEN_VDMA_ACFG(chn, REG_MCE_TMV_BA, 0, VRAM_TOPMV_BA);//tmv ++ GEN_VDMA_ACFG(chn, REG_MCE_CHN_SYNC, 0, VRAM_ME_DSA);//sync ++ ++ //set frame size ++ GEN_VDMA_ACFG(chn, REG_MCE_FRM_SIZE, 0, ++ MCE_FRM_SIZE_FH(s->frame_height-1) | ++ MCE_FRM_SIZE_FW(s->frame_width-1) | ++ MCE_FRM_SIZE_LRE(s->frm_re[0]) | ++ MCE_FRM_SIZE_RRE(s->frm_re[1]) | ++ MCE_FRM_SIZE_TRE(s->frm_re[2]) | ++ MCE_FRM_SIZE_BRE(s->frm_re[3]) ); ++ ++ //set frame stride ++ GEN_VDMA_ACFG(chn, REG_MCE_FRM_STRD, 0, ++ MCE_FRM_STRD_STRDC(((s->frame_width+15)/16)*16) | ++ MCE_FRM_STRD_STRDY(((s->frame_width+15)/16)*16) ); ++ ++ //set COMP_CTRL ++ GEN_VDMA_ACFG(chn, REG_MCE_COMP_CTRL, 0, ++ MCE_COMP_CTRL_CCE | ++ MCE_COMP_CTRL_CTAP(MCE_TAP_TAP2) | ++ MCE_COMP_CTRL_CSPT(MCE_SPT_BILI) | ++ MCE_COMP_CTRL_CSPP(MCE_SPP_EPEL) | ++ MCE_COMP_CTRL_YCE | ++ MCE_COMP_CTRL_YTAP(MCE_TAP_TAP6) | ++ MCE_COMP_CTRL_YSPT(MCE_SPT_AUTO) | ++ MCE_COMP_CTRL_YSPP(MCE_SPP_QPEL) ); ++ ++ //set ESTI_CTRL ++ unsigned int esti_ctrl = 0; ++ esti_ctrl |= (MCE_ESTI_CTRL_LSP(s->lambda_scale_parameter) | ++ MCE_ESTI_CTRL_SCL(s->scl)/*trbl mvp*/ | ++ MCE_ESTI_CTRL_FBG(0) | ++ MCE_ESTI_CTRL_CLMV | ++ MCE_ESTI_CTRL_MSS(s->max_sech_step_i) | ++ MCE_ESTI_CTRL_QRL(s->qpel_en) | ++ MCE_ESTI_CTRL_HRL(s->hpel_en) ); ++ ++ esti_ctrl |= MCE_ESTI_CTRL_PUE_16X16; ++ ++ GEN_VDMA_ACFG(chn, REG_MCE_ESTI_CTRL, 0, esti_ctrl); ++ ++ //set MRGI ++ unsigned int merg_info = 0; ++ GEN_VDMA_ACFG(chn, REG_MCE_MRGI, 0, merg_info); ++ ++ //set MVR ++ GEN_VDMA_ACFG(chn, REG_MCE_MVR, 0, ++ MCE_MVR_MVRY(s->max_mvry_i*4) | ++ MCE_MVR_MVRX(s->max_mvrx_i*4) ); ++ if(s->buf_share_en){ ++ GEN_VDMA_ACFG(chn, REG_MCE_REFY0, 0, refy_addr_ba0); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFC0, 0, refc_addr_ba0); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFY0_1, 0, refy_addr_ba1); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFC0_1, 0, refc_addr_ba1); ++ } ++ else { ++ GEN_VDMA_ACFG(chn, REG_MCE_REFY0, 0, s->fb[1][0]); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFC0, 0, s->fb[1][1]); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFY0_1, 0, s->fb[3][0]); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFC0_1, 0, s->fb[3][1]); ++ } ++ GEN_VDMA_ACFG(chn, REG_MCE_REFY1, 0, s->fb[2][0]); ++ GEN_VDMA_ACFG(chn, REG_MCE_REFC1, 0, s->fb[2][1]); ++ ++ GEN_VDMA_ACFG(chn, REG_MCE_SLC_SPOS, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_MCE_FSC, 0, ++ MCE_FSC_FSE(s->fs_en) | ++ MCE_FSC_FSMD(s->fs_md) | ++ MCE_FSC_PERX(s->fs_px) | ++ MCE_FSC_PERY(s->fs_py) | ++ MCE_FSC_RECX(s->fs_rx) | ++ MCE_FSC_RECY(s->fs_ry) ++ ); ++ GEN_VDMA_ACFG(chn, REG_MCE_GLB_MV, 0, MCE_GLB_MVX(s->glb_mvx) | MCE_GLB_MVY(s->glb_mvy)); ++ /**/ ++ GEN_VDMA_ACFG(chn, REG_MCE_GLB_CTRL, 0, (MCE_GLB_CTRL_FMV0(s->force_mv0_en) | ++ MCE_GLB_CTRL_MSTEP(s->me_step_en) | ++ MCE_GLB_CTRL_STEP1(s->me_step_1) | ++ MCE_GLB_CTRL_STEP0(s->me_step_0) | ++ MCE_GLB_CTRL_RBS(ref_mby_size) | ++ MCE_GLB_CTRL_FMS(s->frm_mv_size) | ++ MCE_GLB_CTRL_FRMMV(s->frm_mv_en) | ++ MCE_GLB_CTRL_GLBMV(s->glb_mv_en) | ++ MCE_GLB_CTRL_DCT8(s->dct8x8_en) | ++ MCE_GLB_CTRL_PSKIP(s->pskip_en) | MCE_GLB_CTRL_INIT | ++ MCE_GLB_CTRL_MREF(s->mref_en) | MCE_GLB_CTRL_RM(s->ref_mode) | ++ MCE_GLB_CTRL_JRFD(!s->jrfd_enable))); ++ } ++ /************************************************** ++ VMAU configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_RUN, 0, VMAU_RESET); ++ GEN_VDMA_ACFG(chn, REG_VMAU_VIDEO_TYPE, 0, (VMAU_MODE_ENC | 6<<7 ++ | VMAU_I4_MSK(0) ++ | VMAU_I16_MSK(0) ++ | VMAU_I8_MSK(0) ++ | VMAU_PT8_MSK(0) ++ | VMAU_IS_ISLICE(!s->frame_type) ++ | VMAU_PREDM_MSK(s->intra_mode_msk & 0x1ffff) ++ | VMAU_TSE(s->use_intra_in_pframe)) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_NCCHN_ADDR, 0, VRAM_MAU_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_VMAU_ENC_DONE, 0, VRAM_MAU_ENC_SYNA); ++ GEN_VDMA_ACFG(chn, REG_VMAU_DEC_DONE, 0, VRAM_MAU_DEC_SYNA); ++ GEN_VDMA_ACFG(chn, REG_VMAU_Y_GS, 0, (VMAU_FRM_WID(MB_WID*16) ++ | VMAU_FRM_HEI(MB_HEI*16)) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_CTR, 0, (VMAU_CTRL_TO_DBLK ++ | VMAU_CTRL_FIFO_M ++ | VMAU_LAMBDA_THRETH((s->intra_mode_msk >> 17) & 0x3) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_DEADZONE, 0, ( VMAU_DEADZONE0_IY(s->deadzone[0]) ++ | VMAU_DEADZONE1_PY(s->deadzone[1]) ++ | VMAU_DEADZONE2_IC(s->deadzone[2]) ++ | VMAU_DEADZONE3_PC(s->deadzone[3]) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_DEADZONE1, 0, ((s->deadzone[4] & 0x3f) << 0 | ++ (s->deadzone[5] & 0x3f) << 6 | ++ (s->deadzone[6] & 0x3f) << 12 | ++ (s->deadzone[7] & 0x3f) << 18 | ++ (s->deadzone[8] & 0x3f) << 24)); ++ GEN_VDMA_ACFG(chn, REG_VMAU_TOP_BASE, 0, VRAM_TOPPA_BA ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG0, 0, ( VMAU_MD_SLICE_I(!s->frame_type) ++ | VMAU_MD_SLICE_P(s->frame_type) ++ | VMAU_MD_I4_DIS(0) ++ | VMAU_MD_I16_DIS(0) ++ | VMAU_MD_PSKIP_DIS(0) ++ | VMAU_MD_P_L0_DIS(0) ++ | VMAU_MD_I8_DIS(0) ++ | VMAU_MD_PT8_DIS(0) ++ | VMAU_MD_DREF_EN(s->mref_en) ++ | VMAU_MD_DCT8_EN(s->dct8x8_en) ++ | VMAU_MD_FRM_REDGE(MB_WID - 1) ++ | VMAU_MD_FRM_BEDGE(MB_HEI - 1) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG1, 0, ( VMAU_IPMY_BIAS_EN(s->intra_lambda_y_bias_en) ++ | VMAU_IPMC_BIAS_EN(s->intra_lambda_c_bias_en) ++ | VMAU_COST_BIAS_EN(s->cost_bias_en) ++ | VMAU_CSSE_BIAS_EN(s->chroma_sse_bias_en) ++ | VMAU_JMLAMBDA2_EN(s->jm_lambda2_en) ++ | VMAU_INTER_NEI_EN(s->inter_nei_en) ++ | VMAU_SKIP_BIAS_EN(s->skip_bias_en) ++ | VMAU_LMD_BIAS_EN(s->sse_lambda_bias_en) ++ | VMAU_INFO_EN(s->info_en) ++ | VMAU_DCM_EN(s->dcm_en) ++ | VMAU_MVDS_ALL(s->mvd_sum_all) ++ | VMAU_MVDS_ABS(s->mvd_sum_abs) ++ | VMAU_MVS_ALL(s->mv_sum_all) ++ | VMAU_MVS_ABS(s->mv_sum_abs) ++ | VMAU_P_L0_BIAS(s->cost_bias_p_l0) ++ | VMAU_PSKIP_BIAS(s->cost_bias_p_skip) ++ | VMAU_I4_BIAS(s->cost_bias_i_4x4) ++ | VMAU_I16_BIAS(s->cost_bias_i_16x16) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG2, 0, ( VMAU_IPM_BIAS_0(s->intra_lambda_bias_0) ++ | VMAU_IPM_BIAS_1(s->intra_lambda_bias_1) ++ | VMAU_IPM_BIAS_2(s->intra_lambda_bias_2) ++ | VMAU_IPM_BIAS_QP0(s->intra_lambda_bias_qp0) ++ | VMAU_IPM_BIAS_QP1(s->intra_lambda_bias_qp1) ++ | VMAU_MD_FBC_EP(s->fbc_ep) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG3, 0, ( VMAU_CSSE_BIAS_0(s->chroma_sse_bias_0) ++ | VMAU_CSSE_BIAS_1(s->chroma_sse_bias_1) ++ | VMAU_CSSE_BIAS_2(s->chroma_sse_bias_2) ++ | VMAU_CSSE_BIAS_QP0(s->chroma_sse_bias_qp0) ++ | VMAU_CSSE_BIAS_QP1(s->chroma_sse_bias_qp1) ++ | VMAU_LMD_BIAS(s->sse_lambda_bias) ++ | VMAU_PL0_FS_DIS(s->p_skip_pl0f_dis) ++ | VMAU_PT8_FS_DIS(s->p_skip_pt8f_dis) ++ | VMAU_PL0_COST_MAX(s->p_l0_dis) ++ | VMAU_PT8_COST_MAX(s->p_t8_dis) ++ ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG4, 0, ( VMAU_YSSE_THR(s->ysse_thr) ++ | VMAU_I8_BIAS(s->cost_bias_i_8x8) ++ | VMAU_PT8_BIAS(s->cost_bias_p_t8) ++ ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG5, 0, ( VMAU_CSSE_THR(s->csse_thr) ++ | VMAU_CQP_OFFSET(s->cqp_offset) ++ | VMAU_I4_COST_MAX(s->i_4x4_dis) ++ | VMAU_I8_COST_MAX(s->i_8x8_dis) ++ | VMAU_I16_COST_MAX(s->i_16x16_dis) ++ ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG6, 0, ( VMAU_DCM_PARAM(s->dcm_param) ++ | VMAU_SDE_PRIOR(s->sde_prior) ++ | VMAU_DB_PRIOR(s->db_prior) ++ ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG7, 0, ( VMAU_CFG_SIZE_X(s->cfg_size_x) ++ | VMAU_CFG_SIZE_Y(s->cfg_size_y) ++ | VMAU_CFG_IW_THR(s->cfg_iw_thr) ++ | VMAU_CFG_BASEQP(s->base_qp) ++ | VMAU_CFG_ALPHA(s->alpha_c0_offset) ++ | VMAU_PS_COST_MAX(s->p_skip_dis) ++ ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG8, 0, ( VMAU_CFG_MVR_THR1(s->cfg_mvr_thr1) ++ | VMAU_CFG_MVR_THR2(s->cfg_mvr_thr2) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG9, 0, ( VMAU_CFG_MVR_THR3(s->cfg_mvr_thr3) ++ | VMAU_CFG_BETA(s->beta_offset) ++ ) ); ++ ++ /* eigen leverages mode decision */ ++ int set_modectrl_bit0 = s->mb_mode_use & 0x1; ++ int set_modectrl_bit2 = s->rrs_en || s->force_i16 || s->refresh_en; ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_CFG11, 0, ( VMAU_CFG_MD_RBIAS(s->refresh_bias) ++ | VMAU_CFG_MD_RBIAS_EN(1) ++ | VMAU_CFG_MD_PCDC_N0(s->mode_ctrl >> 3 & 7) ++ | VMAU_CFG_MD_IFA_VLD(set_modectrl_bit2) ++ | VMAU_CFG_MD_SLV_VLD(0) ++ | VMAU_CFG_MD_SET_VLD((s->mode_ctrl & 0x2) || set_modectrl_bit0) ++ ) ); ++ ++ GEN_VDMA_ACFG(chn, REG_VMAU_ACMASK, 0, (s->acmask_mode<<14) + 2 ); /* 2 for TEST: rd file */ ++ ++ for (j = 0; j < 40; ++j) ++ GEN_VDMA_ACFG(chn, REG_VMAU_MD_MODE, 0, s->mode_ctrl_param[j] ); ++ ++ for (j = 0; j < 42; j++) ++ GEN_VDMA_ACFG(chn, REG_VMAU_CTX, 0, s->state[ j<10 ? ( !s->frame_type ? j+3 : j+14 ) ++ : j<22 ? j-10+73 ++ : j<28 ? j-22+64 : j-28+40 ] ); ++ ++ for( j = 0; j < 225; j++) ++ GEN_VDMA_ACFG(chn, REG_VMAU_CTX_CFBC, 0, s->state[ j<4 ? j+85 : //LUMA_DC_SIGNCG ++ j<19 ? j-4+105 : //LUMA_DC_SIGN ++ j<34 ? j-19+166 : //LUMA_DC_LAST ++ j<44 ? j-34+227 : //LUMA_DC_LEVEL ++ j<48 ? j-44+89 : //LUMA_AC_SIGNCG ++ j<62 ? j-48+120 : //LUMA_AC_SIGN ++ j<76 ? j-62+181 : //LUMA_AC_LAST ++ j<86 ? j-76+237 : //LUMA_AC_LEVEL ++ j<90 ? j-86+93 : //LUMA_44_SIGNCG ++ j<105 ? j-90+134 : //LUMA_44_SIGN ++ j<120 ? j-105+195 : //LUMA_44_LAST ++ j<130 ? j-120+247 : //LUMA_44_LEVEL ++ j<134 ? j-130+97 : //CHROMA_DC_SIGNCG ++ j<137 ? j-134+149 : //CHROMA_DC_SIGN ++ j<140 ? j-137+210 : //CHROMA_DC_LAST ++ j<149 ? j-140+257 : //CHROMA_DC_LEVEL ++ j<153 ? j-149+101 : //CHROMA_AC_SIGNCG ++ j<167 ? j-153+152 : //CHROMA_AC_SIGN ++ j<181 ? j-167+213 : //CHROMA_AC_LAST ++ j<191 ? j-181+266 : //CHROMA_AC_LEVEL ++ j<206 ? j-191+402 : //LUMA_88_SIGN ++ j<215 ? j-206+417 : //LUMA_88_LAST ++ j-215+426 //LUMA_88_LEVEL ++ ] ); ++ ++ ++ ++#if 0 ++ for(j=0; j<4; j++){ ++ for(i=0; i<4; i++){ ++ GEN_VDMA_ACFG(chn, REG_VMAU_QT+tmp, 0, *(int *)(&s->scaling_list[j][i*4]) ); ++ tmp += 4; ++ } ++ } ++ for(j=0; j<4; j++){ ++ for (i=0; i<8; i++){ ++ int tmp0 = (1ULL << 8) / s->scaling_list[j][2*i]; ++ int tmp1 = (1ULL << 8) / s->scaling_list[j][2*i+1]; ++ GEN_VDMA_ACFG(chn, REG_VMAU_QT+tmp, 0, ((tmp0 & 0xFFFF) | (tmp1<<16)) ); ++ tmp += 4; ++ } ++ } ++#endif ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG0, 0, (VMAU_IP_MD_VAL(s->force_i16dc) | ++ VMAU_IP_REF_NEB_4(s->ref_neb_4) | ++ VMAU_IP_REF_NEB_8(s->ref_neb_8) | ++ VMAU_IP_REF_PRD_C(s->pri_uv) | ++ VMAU_IP_REF_PRD_16(s->pri_16) | ++ VMAU_IP_REF_PRD_8(s->pri_8) | ++ VMAU_IP_REF_PRD_4(s->pri_4) | ++ VMAU_IP_REF_C4_EN(s->c_4_en) | ++ VMAU_IP_REF_C8_EN(s->c_8_en) | ++ VMAU_IP_REF_C16_EN(s->c_16_en) | ++ VMAU_IP_REF_CUV_EN(s->c_uv_en) | ++ VMAU_IP_REF_LMD4_EN(s->lamb_4_en) | ++ VMAU_IP_REF_LMD8_EN(s->lamb_8_en) | ++ VMAU_IP_REF_LMD16_EN(s->lamb_16_en) | ++ VMAU_IP_REF_LMDUV_EN(s->lamb_uv_en) | ++ VMAU_IP_REF_BIT4_EN(s->bit_4_en) | ++ VMAU_IP_REF_BIT8_EN(s->bit_8_en) | ++ VMAU_IP_REF_BIT16_EN(s->bit_16_en) | ++ VMAU_IP_REF_BITUV_EN(s->bit_uv_en) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG1, 0, (VMAU_IP_REF_4_BIT0(s->bit_4[0]) | ++ VMAU_IP_REF_4_BIT1(s->bit_4[1]) | ++ VMAU_IP_REF_4_BIT2(s->bit_4[2]) | ++ VMAU_IP_REF_4_BIT3(s->bit_4[3]) | ++ VMAU_IP_REF_8_BIT0(s->bit_8[0]) | ++ VMAU_IP_REF_8_BIT1(s->bit_8[1]) | ++ VMAU_IP_REF_8_BIT2(s->bit_8[2]) | ++ VMAU_IP_REF_8_BIT3(s->bit_8[3]) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG2, 0, (VMAU_IP_REF_C_BIT0(s->bit_uv[0]) | ++ VMAU_IP_REF_C_BIT1(s->bit_uv[1]) | ++ VMAU_IP_REF_C_BIT2(s->bit_uv[2]) | ++ VMAU_IP_REF_C_BIT3(s->bit_uv[3]) | ++ VMAU_IP_REF_16_BIT0(s->bit_16[0]) | ++ VMAU_IP_REF_16_BIT1(s->bit_16[1]) | ++ VMAU_IP_REF_16_BIT2(s->bit_16[2]) | ++ VMAU_IP_REF_16_BIT3(s->bit_16[3]) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG3, 0, (VMAU_IP_REF_LMDUV_IFO(s->lambda_infouv) | ++ VMAU_IP_REF_LMD16_IFO(s->lambda_info16) | ++ VMAU_IP_REF_LMD8_IFO(s->lambda_info8) | ++ VMAU_IP_REF_LMD4_IFO(s->lambda_info4) | ++ VMAU_IP_REF_NEB_4REF(s->ref_4) | ++ VMAU_IP_REF_NEB_8REF(s->ref_8) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG4, 0, (VMAU_IP_REF_C4_IFO((s->const_4[0]<<0) | ++ (s->const_4[1]<<4) | ++ (s->const_4[2]<<8) | ++ (s->const_4[3]<<12) ) | ++ VMAU_IP_REF_C8_IFO((s->const_8[0]<<0) | ++ (s->const_8[1]<<4) | ++ (s->const_8[2]<<8) | ++ (s->const_8[3]<<12) ) ) ); ++ GEN_VDMA_ACFG(chn, REG_VMAU_IPRED_CFG5, 0, (VMAU_IP_REF_C16_IFO((s->const_16[0]<<0) | ++ (s->const_16[1]<<4) | ++ (s->const_16[2]<<8) | ++ (s->const_16[3]<<12) ) | ++ VMAU_IP_REF_CUV_IFO((s->const_uv[0]<<0) | ++ (s->const_uv[1]<<4) | ++ (s->const_uv[2]<<8) | ++ (s->const_uv[3]<<12) ) ) ); ++ ++ ++ if (1) { //configure scalinglist8 ++ uint8_t scaling_list_z[2][64]; ++ int kk, jj; ++ for (kk = 0; kk < 2; kk++) { ++ for (jj = 0; jj < 64; jj++) { ++ int jj_x = jj%8; //0 ~ 7 ++ int jj_y = jj/8; //0 ~ 7 ++ int jj_xx = jj_x%4; //0~3 ++ int jj_xy = jj_x/4; //0~1 ++ int jj_yx = jj_y%4; //0~3 ++ int jj_yy = jj_y/4; //0~1 ++ int zz = 16 * (jj_yy*2 + jj_xy) + 4*jj_yx + jj_xx; ++ scaling_list_z[kk][zz] = s->scaling_list8[kk][jj]; ++ } ++ } ++ int ofst = 0 ; ++ for (kk = 0; kk < 2; kk++) { ++ for (jj = 0; jj < 32; jj++) { ++#ifdef __KERNEL__ ++ unsigned long long t = 1ULL << 12; ++ do_div(t, scaling_list_z[kk][2*jj + 0]); ++ int t0 = (int)t; ++ ++ t = 1ULL << 12; ++ do_div(t, scaling_list_z[kk][2*jj + 1]); ++ int t1 = (int)t; ++#else ++ int t0 = (1ULL << 12)/scaling_list_z[kk][2*jj+0]; ++ int t1 = (1ULL << 12)/scaling_list_z[kk][2*jj+1]; ++#endif ++ int tt = ((t0 & 0xfff) | ++ (t1 & 0xfff) << 12); ++ GEN_VDMA_ACFG(chn, (VPU_BASE | 0x80800) + ofst, 0, tt ); ++ ++ ofst += 4; ++ } ++ } ++ for (kk = 0; kk < 2; kk++) { ++ for (jj = 0; jj < 16; jj++) { ++ int t0 = scaling_list_z[kk][4*jj+0]; ++ int t1 = scaling_list_z[kk][4*jj+1]; ++ int t2 = scaling_list_z[kk][4*jj+2]; ++ int t3 = scaling_list_z[kk][4*jj+3]; ++ int tt = ((t0 & 0x3f) | ++ (t1 & 0x3f) << 6 | ++ (t2 & 0x3f) << 12 | ++ (t3 & 0x3f) << 18); ++ GEN_VDMA_ACFG(chn, (VPU_BASE | 0x80800) + ofst, 0, tt ); ++ ofst += 4; ++ } ++ } ++ } ++ ++ GEN_VDMA_ACFG(chn, REG_VMAU_GBL_RUN, 0, VMAU_RUN ); ++ ++ /************************************************** ++ DBLK configuration ++ *************************************************/ ++#if 0 ++ GEN_VDMA_ACFG(chn, REG_DBLK_TRIG, 0, DBLK_RESET); ++ GEN_VDMA_ACFG(chn, REG_DBLK_DHA, 0, VRAM_DBLK_CHN_BASE); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GENDA, 0, VRAM_DBLK_CHN_SYNA); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GSIZE, 0, DBLK_GSIZE(MB_HEI, MB_WID) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPOS, 0, DBLK_GPOS(s->first_mby, 0) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_CTRL, 0, DBLK_CTRL(0, s->rotate, s->deblock) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_YA, 0, s->fb[0][0]/* - (MB_WID+3)*256*/); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_CA, 0, s->fb[0][1]/* - (MB_WID+3)*128*/); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GP_ENDA, 0, VRAM_DBLK_DOUT_SYNA); ++ GEN_VDMA_ACFG(chn, REG_DBLK_GPIC_STR, 0, DBLK_GPIC_STR(MB_WID*128, MB_WID*256) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_VTR, 0, DBLK_VTR(s->beta_offset, s->alpha_c0_offset, 0, 0, ++ s->frame_type, DBLK_FMT_H264) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_TRIG, 0, DBLK_SLICE_RUN); ++ //mosaic ++ GEN_VDMA_ACFG(chn, REG_DBLK_MOS_CFG, 0, ( ((s->mos_sthd[1] & 0xF) << 28) | ++ ((s->mos_sthd[0] & 0xF) << 24) | ++ ((s->mos_gthd[1] & 0xFF) << 16) | ++ ((s->mos_gthd[0] & 0xFF) << 8) | ++ (s->mosaic_en & 0x1) ) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_MOS_ADDR, 0, DBLK_MOS_BASE_ADDR); ++#else ++ GEN_VDMA_ACFG(chn, REG_DBLK_CFG, 0, ( DBLK_CFG_ALPHA(s->alpha_c0_offset + 12) ++ | DBLK_CFG_BETA(s->beta_offset + 12) ++ | DBLK_CFG_NO_LFT(!s->deblock) ) ); ++ GEN_VDMA_ACFG(chn, REG_DBLK_TRIG, 0, DBLK_SLICE_RUN); ++#endif ++ /************************************************** ++ SDE configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_SDE_STAT, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SDE_GL_CTRL, 0, (SDE_MODE_STEP | SDE_EN) ); ++ GEN_VDMA_ACFG(chn, REG_SDE_SL_GEOM, 0, SDE_SL_GEOM(MB_HEI, MB_WID, ++ s->first_mby, 0) ); ++ GEN_VDMA_ACFG(chn, REG_SDE_CODEC_ID, 0, SDE_FMT_H264_ENC); ++ //slice_info0 {desp_link_en[1], auto_syn_en[0]} ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG0, 0, 0x3); ++ //slice_info1 {qp[8], slice_type[0]} ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG1, 0, ((s->qp << 8) | ++ (s->bs_head_en << 20) |//rbsp enable ++ (s->bs_rbsp_en << 7) |//rbsp enable ++ (s->mref_en << 6) | /*dual-ref enable*/ ++ (s->dct8x8_en << 5) | /*dct8x8 enable*/ ++ (s->skip_en << 4) | ++ (s->frame_type + 1)) ); ++ //desp_addr ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG2, 0, VRAM_SDE_CHN_BASE); ++ //sync_addr ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG3, 0, VRAM_SDE_SYNA); ++ //bs_addr ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG4, 0, s->bs); ++ //context table ++ for(i=0; i<460; i++){ ++ int idx = s->state[i]; ++ if(idx <= 63) ++ idx = 63 - idx; ++ else ++ idx -= 64; ++ GEN_VDMA_ACFG(chn, REG_SDE_CTX_TBL+i*4, 0, ++ (lps_range[idx] | ((s->state[i]>>6) & 0x1)) ); ++ } ++ //init sync ++ GEN_VDMA_ACFG(chn, REG_SDE_SL_CTRL, 0, SDE_SLICE_INIT); ++ /************************************************** ++ EMC init ++ *************************************************/ ++ char use_ddr_slow_mode=0; ++ if((((s->frame_width+15)/16)-1)>32) ++ use_ddr_slow_mode = 0; ++ else ++ use_ddr_slow_mode = 1; ++ ++ GEN_VDMA_ACFG(chn, REG_EMC_FRM_SIZE, 0, ++ (0x0) << 20 | //bs_full intc before slice end ++ (s->bs_size_en) << 19 | //bs space ctrl by bs_size ++ use_ddr_slow_mode << 18 | //ddr use slow mode ++ (s->qp_tab_en & 0x1) << 17 | //qp table en ++ //(s->i_4x4_dis & 0x1) << 16 | //4x4 close ++ (((s->frame_height+15)/16)-1) << 8 | ++ (((s->frame_width+15)/16)-1) ); ++ GEN_VDMA_ACFG(chn, REG_EMC_BS_ADDR, 0, VDMA_ACFG_DHA(s->emc_bs_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_DBLK_ADDR, 0, VDMA_ACFG_DHA(s->emc_dblk_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_RECON_ADDR, 0, VDMA_ACFG_DHA(s->emc_recon_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_MV_ADDR, 0, VDMA_ACFG_DHA(s->emc_mv_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_SE_ADDR, 0, VDMA_ACFG_DHA(s->emc_se_pa)); ++ ++ ++ if((s->rc_mb_en & 0x1) && s->frame_type){//mb_rc+bu_rc or only mb_rc ++ for(i=0;imb_gp_num;i++){ ++ ++ int mb_gp_wth = (s->mb_width + 1) / 2; ++ int mb_gp_wth_for_bu = mb_gp_wth << (s->rc_bu_level - 1); ++ uint32_t r_idx = i; ++ uint32_t bdry_2algn = (s->mb_width % 2) == 0; ++ uint32_t mb_rinfo0_valid = 1; ++ uint32_t mb_rinfo1_valid = !bdry_2algn && ((r_idx % mb_gp_wth) == (mb_gp_wth-1)) ? 0 : 1; ++ uint32_t bu_rinfo_valid = (r_idx % mb_gp_wth_for_bu) == (mb_gp_wth_for_bu-1) ? 1 : 0; ++ uint32_t bu_rinfo_idx = r_idx / mb_gp_wth_for_bu; ++ uint32_t bdry_n2algn_num; ++ if(bdry_2algn) ++ bdry_n2algn_num = 0; ++ else ++ bdry_n2algn_num = r_idx / ((s->mb_width+1)/2); ++ ++ uint32_t mb_ref_info0 = s->mb_ref_info[r_idx*2 - bdry_n2algn_num] & 0x7fff; ++ uint32_t mb_ref_info1 = s->mb_ref_info[r_idx*2+1 - bdry_n2algn_num] & 0x7fff; ++ uint32_t mb_rinfo0 = (mb_rinfo0_valid<<15) | mb_ref_info0; ++ uint32_t mb_rinfo1 = (mb_rinfo1_valid<<31) | (mb_ref_info1<<16); ++ uint32_t bu_rinfo = (bu_rinfo_valid<<31) | (s->bu_ref_info[bu_rinfo_idx] & 0x7fffffff); ++ //fprintf(stderr,"i:%d,mb_ref_info0:0x%x,mb_ref_info1:0x%x,s->bu_ref_info:0x%x\n",i,mb_ref_info0,mb_ref_info1,s->bu_ref_info[bu_rinfo_idx] & 0x7fffffff); ++ //fprintf(stderr,"s->mb_width:%d, mb_gp_wth:%d, s->rc_bu_level:%d, mb_gp_wth_for_bu:%d, r_idx:%d\n",s->mb_width, mb_gp_wth, s->rc_bu_level, mb_gp_wth_for_bu, r_idx); ++ //fprintf(stderr,"mb_rinfo0:0x%x,mb_rinfo1:0x%x,bu_rinfo:0x%x\n",mb_rinfo0,mb_rinfo1,bu_rinfo); ++ s->emc_rc_va[i*2] = mb_rinfo1 | mb_rinfo0; ++ s->emc_rc_va[i*2+1] = bu_rinfo; ++ //fprintf(stderr,"s->emc_rc_va[%d]:0x%x,s->emc_rc_va[%d]:0x%x\n",i*2,s->emc_rc_va[i*2],i*2+1,s->emc_rc_va[i*2+1]); ++ } ++ GEN_VDMA_ACFG(chn, REG_EMC_RC_RADDR, 0, VDMA_ACFG_DHA(s->emc_rc_pa)); ++ }else if((s->rc_mb_en & 0x2) && s->frame_type){//only bu_rc ++ for(i=0;irc_bu_num;i++){ ++ uint32_t bu_rinfo = (1<<31) | (s->bu_ref_info[i] & 0x7fffffff); ++ s->emc_rc_va[i*2+1] = bu_rinfo; ++ } ++ GEN_VDMA_ACFG(chn, REG_EMC_RC_RADDR, 0, VDMA_ACFG_DHA(s->emc_rc_pa)); ++ } ++ if(s->rc_mb_en) ++ GEN_VDMA_ACFG(chn, REG_EMC_RC_WADDR, 0, VDMA_ACFG_DHA(s->emc_rc_pa)); ++ ++ if(s->qp_tab_en){ ++ for(i=0;iqp_tab_len;i++) ++ s->emc_qpt_va[i] = s->qp_tab[i]; ++ } ++ if(s->ncu_mov_en){ ++ for(i=0;incu_move_len;i++) ++ s->emc_ncu_va[i] = s->ncu_move_info[i]; ++ } ++ ++ if(s->mb_mode_use){ ++ int mb_mode_len = (s->mb_width * s->mb_height + 1) / 2; ++ for(i=0;iemc_mod_va[i] = s->mb_mode_info[i]; ++ } ++ ++ ++ //rintf(stderr,"s->emc_qpt_va[0]=%x\n",s->emc_qpt_va[0]); ++ //rintf(stderr,"s->emc_qpt_va[1]=%x\n",s->emc_qpt_va[1]); ++ //rintf(stderr,"s->emc_qpt_va[2]=%x\n",s->emc_qpt_va[2]); ++ GEN_VDMA_ACFG(chn, REG_EMC_QPT_ADDR, 0, VDMA_ACFG_DHA(s->emc_qpt_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_CPX_ADDR, 0, VDMA_ACFG_DHA(s->emc_cpx_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_MOD_ADDR, 0, VDMA_ACFG_DHA(s->emc_mod_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_NCU_ADDR, 0, VDMA_ACFG_DHA(s->emc_ncu_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_SAD_ADDR, 0, VDMA_ACFG_DHA(s->emc_sad_pa)); ++ GEN_VDMA_ACFG(chn, REG_EMC_BS_SIZE, 0, s->bs_size); ++ GEN_VDMA_ACFG(chn, REG_EMC_SLV_INIT, 0, 0x1); ++ /************************************************** ++ TOPMV/TOPPA init ++ *************************************************/ ++/* for(i=0; i<256; i++){ */ ++/* write_reg(VRAM_TOPMV_BA+i*4, 0); */ ++/* write_reg(VRAM_TOPPA_BA+i*4, 0); */ ++/* } */ ++ ++ /************************************************** ++ SCH configuration ++ *************************************************/ ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHG0, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHG1, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE1, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE2, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE3, 0, 0); ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHE4, 0, 0); ++ ++#if 1 ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, (SCH_CH4_GS1 | SCH_CH4_PCH(0) | ++ SCH_CH3_GS1 | SCH_CH3_PCH(0) | ++ SCH_CH2_GS0 | SCH_CH2_PE | SCH_CH2_PCH(0) | ++ SCH_CH1_GS0 | SCH_CH1_PCH(0) | ++ (s->frame_type & 0x1)<<2 ) ); ++ ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, (SCH_CH4_HID(HID_SDE) | SCH_CH3_HID(HID_DBLK) | ++ SCH_CH2_HID(HID_VMAU) | SCH_CH1_HID(HID_MCE) | ++ SCH_DEPTH(SCH_FIFO_DEPTH) | ++ SCH_BND_G0F2 | ++ (s->frame_type & 0x1)<<0 ) ); ++#else ++ GEN_VDMA_ACFG(chn, REG_SCH_SCHC, 0, (SCH_CH4_GS1 | SCH_CH4_PE | SCH_CH4_PCH(0) | ++ SCH_CH3_GS1 | SCH_CH3_PE | SCH_CH3_PCH(0) | ++ SCH_CH2_GS0 | SCH_CH2_PE | SCH_CH2_PCH(0) | ++ SCH_CH1_GS0 | SCH_CH1_PCH(0) | ++ (s->frame_type & 0x1)<<2 ) ); ++ ++ GEN_VDMA_ACFG(chn, REG_SCH_BND, 0, (SCH_CH4_HID(HID_SDE) | SCH_CH3_HID(HID_DBLK) | ++ SCH_CH2_HID(HID_VMAU) | SCH_CH1_HID(HID_MCE) | ++ SCH_DEPTH(SCH_FIFO_DEPTH) | ++ SCH_BND_G1F4 | SCH_BND_G1F3 | ++ SCH_BND_G0F4 | SCH_BND_G0F3 | SCH_BND_G0F2 | ++ (s->frame_type & 0x1)<<0 ) ); ++#endif ++ ++ /************************************************** ++ ODMA configuration ++ *************************************************/ ++ //when buf share is new addr(dynamic), else old addr(static) ++ paddr_t odma_y_addr = s->buf_share_en ? buf_start_yaddr : s->fb[0][0]; ++ paddr_t odma_c_addr = s->buf_share_en ? buf_start_caddr : s->fb[0][1]; ++ //when buf share is base addr, else head addr ++ paddr_t odma_com_addr0 = s->buf_share_en ? s->fb[0][0] : s->jh[0][0]; ++ paddr_t odma_com_addr1 = s->buf_share_en ? s->fb[0][1] : s->jh[0][1]; ++ //when buf share is beyond addr, else head spe addr ++ paddr_t odma_com_addr2 = s->buf_share_en ? buf_beyond_yaddr : s->spe_y_addr; ++ paddr_t odma_com_addr3 = s->buf_share_en ? buf_beyond_caddr : s->spe_c_addr; ++ ++ GEN_VDMA_ACFG(chn, REG_ODMA_CTRL, 0, (odma_spe_flag << 31 | ++ (s->buf_share_en << 30) |//buf share ++ (odma_alg_flag << 29) | ++ (s->jrfc_enable << 28) |//compress_flag ++ (s->frame_height << 14) | ++ s->frame_width)); ++ ++ GEN_VDMA_ACFG(chn, REG_ODMA_BDYA, 0, odma_y_addr); ++ GEN_VDMA_ACFG(chn, REG_ODMA_BDCA, 0, odma_c_addr); ++ ++ GEN_VDMA_ACFG(chn, REG_ODMA_BSTR, 0, ++ ODMA_REC_STRDY(((s->frame_width+15)/16)*16) | ++ ODMA_REC_STRDC(((s->frame_width+15)/16)*8) ); ++ ++ ++ GEN_VDMA_ACFG(chn, REG_ODMA_HDYA, 0, odma_com_addr0); ++ GEN_VDMA_ACFG(chn, REG_ODMA_HDCA, 0, odma_com_addr1); ++ GEN_VDMA_ACFG(chn, REG_ODMA_SPYA, 0, odma_com_addr2); ++ GEN_VDMA_ACFG(chn, REG_ODMA_SPCA, 0, odma_com_addr3); ++ ++ ++ GEN_VDMA_ACFG(chn, REG_ODMA_TRIG, 0, ++ ((0 << 6) | //0 is crc en ++ (1 << 5) | //init ++ (0 << 4) //ckg low means do clock-gating ++ )); ++ ++ ++ /************************************************** ++ IFA configuration ++ *************************************************/ ++ ++ GEN_VDMA_ACFG(chn, REG_IFA_FRM_SIZE, 0, (IFA_FRM_W(s->frame_width-1) | ++ IFA_FRM_H(s->frame_height-1) ) ); ++ GEN_VDMA_ACFG(chn, REG_IFA_RAWY_BA, 0, s->raw[0]); ++ GEN_VDMA_ACFG(chn, REG_IFA_RAWC_BA, 0, s->raw[1]); ++ if(s->buf_share_en){ ++ GEN_VDMA_ACFG(chn, REG_IFA_REFY_BA0, 0, refy_addr_ba0); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFC_BA0, 0, refc_addr_ba0); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFY_BA1, 0, refy_addr_ba1); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFC_BA1, 0, refc_addr_ba1); ++ } ++ else { ++ GEN_VDMA_ACFG(chn, REG_IFA_REFY_BA0, 0, s->fb[1][0]); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFC_BA0, 0, s->fb[1][1]); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFY_BA1, 0, s->fb[3][0]); ++ GEN_VDMA_ACFG(chn, REG_IFA_REFC_BA1, 0, s->fb[3][1]); ++ } ++ ++ GEN_VDMA_ACFG(chn, REG_IFA_RAW_STR, 0, (IFA_STR_Y(s->stride[0]) | ++ IFA_STR_C(s->stride[1]) ) ); ++ GEN_VDMA_ACFG(chn, REG_IFA_THRD_Y, 0, s->rrs_thrd_y); ++ GEN_VDMA_ACFG(chn, REG_IFA_THRD_C, 0, (IFA_THRD_U(s->rrs_thrd_u) | ++ IFA_THRD_V(s->rrs_thrd_v) ) ); ++ GEN_VDMA_ACFG(chn, REG_IFA_CTRL, 0, (IFA_CTRL_RAW_TYPE(s->raw_format == EFE_PLANE_NV12) | ++ IFA_CTRL_REF_BIDX(ref_mby_size) | ++ IFA_CTRL_RRS_EN(s->rrs_en) | ++ IFA_CTRL_DUMP_EN(s->rrs_dump_en) | ++ IFA_CTRL_DDR_DW(!s->jrfd_enable) | ++ IFA_CTRL_RRS_SC(s->rrs_size_c) | ++ IFA_CTRL_RRS_SY(s->rrs_size_y) | ++ IFA_CTRL_UV_EN(s->rrs_uv_en) | ++ IFA_CTRL_INIT ) ); ++ ++ //sde slice header ++ if(s->bs_head_en){ ++ //printf("bs_head_rest\n"); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG5, 0, 0x1); ++ //slice header lenth ++ //printf("s->bs_head_len=0x%x\n",s->bs_head_len-1); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG6, 0, s->bs_head_len-1); ++ for(i=0; i<(s->bs_head_len+3)/4; i++){ ++ //printf("s->bs_head_va[%x]=%x\n",i,s->bs_head_va[i]); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG7, 0, s->bs_head_va[i]); ++ } ++ //printf("bs_head_work\n"); ++ GEN_VDMA_ACFG(chn, REG_SDE_CFG5, 0, 0x2); ++ } ++ //efe start ++ uint8_t align8_flag = (s->frame_height & 0xF) != 0; ++ ++ GEN_VDMA_ACFG(chn, REG_EFE_CTRL, VDMA_ACFG_TERM, (EFE_TSE(s->use_intra_in_pframe) | ++ EFE_FMVP(s->use_fast_mvp) | ++ (0/*s->size_mode*/ << 29) | ++ s->raw_format | ++ EFE_X264_QP(s->qp) | ++ EFE_HALN8_FLAG(align8_flag) | ++ EFE_STEP_MODE(s->step_mode) | ++ EFE_DBLK_EN | ++ EFE_SLICE_TYPE(s->frame_type) | ++ EFE_EN | EFE_RUN) ); ++} ++ ++#ifndef __KERNEL__ ++#define printk printf ++#endif ++ ++void H264E_DumpInfo(_H264E_SliceInfo *s) ++{ ++ printk(" emc_qpt_va : %p\n",s->emc_qpt_va); ++ printk(" emc_rc_va : %p\n",s->emc_rc_va); ++ printk(" emc_cpx_va : %p\n",s->emc_cpx_va); ++ printk(" emc_mod_va : %p\n",s->emc_mod_va); ++ printk(" emc_ncu_va : %p\n",s->emc_ncu_va); ++ printk(" emc_sad_va : %p\n",s->emc_sad_va); ++ printk(" mb_mode_info : %p\n",s->mb_mode_info); ++ ++ printk("s->des_va = 0x%08x\n", (unsigned int)s->des_va); ++ printk("s->des_pa = 0x%08x\n", (unsigned int)s->des_pa); ++ // printk("s->emc_bs_va = 0x%08x\n", s->emc_bs_va); ++ printk("s->emc_bs_pa = 0x%08x\n", s->emc_bs_pa); ++ ++ /*x2000 add*/ ++ printk(" bs_head_en = %d\n", s->bs_head_en); ++ printk(" bs_head_va = 0x%08x\n", (unsigned int)s->bs_head_va); ++ printk(" bs_head_len = 0x%d\n", (unsigned int)s->bs_head_len); ++ printk(" bs_rbsp_en = %d\n", s->bs_rbsp_en); ++ ++ printk(" stride[0] = %d\n", s->stride[0]); ++ printk(" stride[1] = %d\n", s->stride[1]); ++ printk(" state = 0x%08x\n", (unsigned int)s->state); ++ printk(" raw[0] = 0x%08x\n", s->raw[0]); ++ printk(" raw[1] = 0x%08x\n", s->raw[1]); ++ printk(" raw[2] = 0x%08x\n", s->raw[2]); ++ printk(" fb[0][0] = 0x%08x\n", s->fb[0][0]); ++ printk(" fb[0][1] = 0x%08x\n", s->fb[0][1]); ++ printk(" fb[1][0] = 0x%08x\n", s->fb[1][0]); ++ printk(" fb[1][1] = 0x%08x\n", s->fb[1][1]); ++ printk(" fb[2][0] = 0x%08x\n", s->fb[2][0]); ++ printk(" fb[2][1] = 0x%08x\n", s->fb[2][1]); ++ printk(" jh[0][0] = 0x%08x\n", s->jh[0][0]); ++ printk(" jh[0][1] = 0x%08x\n", s->jh[0][1]); ++ printk(" jh[1][0] = 0x%08x\n", s->jh[1][0]); ++ printk(" jh[1][1] = 0x%08x\n", s->jh[1][1]); ++ printk(" jh[2][0] = 0x%08x\n", s->jh[2][0]); ++ printk(" jh[2][1] = 0x%08x\n", s->jh[2][1]); ++ printk(" spe_y_addr = 0x%08x\n", s->spe_y_addr); ++ printk(" spe_c_addr = 0x%08x\n", s->spe_c_addr); ++ printk(" emc_recon_pa= 0x%08x\n", s->emc_recon_pa); ++ printk(" emc_qpt_pa = 0x%08x\n", s->emc_qpt_pa); ++ printk(" emc_mv_pa = 0x%08x\n", s->emc_mv_pa); ++ printk(" emc_se_pa = 0x%08x\n", s->emc_se_pa); ++ printk(" emc_rc_pa = 0x%08x\n", s->emc_rc_pa); ++ printk(" emc_cpx_pa = 0x%08x\n", s->emc_cpx_pa); ++ printk(" emc_mod_pa = 0x%08x\n", s->emc_mod_pa); ++ printk(" emc_ncu_pa = 0x%08x\n", s->emc_ncu_pa); ++ printk(" emc_sad_pa = 0x%08x\n", s->emc_sad_pa); ++ /* 1. rc output [11]*/ ++ { ++ printk(" frame_type : %d\n",s->frame_type); ++ printk(" mb_width : %d\n",s->mb_width); ++ printk(" mb_height : %d\n",s->mb_height); ++ printk(" frame_width : %d\n",s->frame_width); ++ printk(" frame_height : %d\n",s->frame_height); ++ printk(" first_mby : %d\n",s->first_mby); ++ printk(" last_mby : %d\n",s->last_mby); ++ printk(" qp : %d\n",s->qp); ++ printk(" base_qp : %d\n",s->base_qp); ++ printk(" max_qp : %d\n",s->max_qp); ++ printk(" min_qp : %d\n",s->min_qp); ++ } ++ /* 2. motion cfg [25]*/ ++ { ++ printk(" frm_re[0] : %d\n",s->frm_re[0]); ++ printk(" frm_re[1] : %d\n",s->frm_re[1]); ++ printk(" frm_re[2] : %d\n",s->frm_re[2]); ++ printk(" frm_re[3] : %d\n",s->frm_re[3]); ++ printk(" pskip_en : %d\n",s->pskip_en); ++ printk(" mref_en : %d\n",s->mref_en); ++ printk(" scl : %d\n",s->scl); ++ printk(" hpel_en : %d\n",s->hpel_en); ++ printk(" qpel_en : %d\n",s->qpel_en); ++ printk(" ref_mode : %d\n",s->ref_mode); ++ printk(" max_sech_step_i : %d\n",s->max_sech_step_i); ++ printk(" max_mvrx_i : %d\n",s->max_mvrx_i); ++ printk(" max_mvry_i : %d\n",s->max_mvry_i); ++ printk(" lambda_scale_parameter : %d\n",s->lambda_scale_parameter); ++ printk(" fs_en : %d\n",s->fs_en); ++ printk(" fs_md : %d\n",s->fs_md); ++ printk(" fs_px : %d\n",s->fs_px); ++ printk(" fs_py : %d\n",s->fs_py); ++ printk(" fs_rx : %d\n",s->fs_rx); ++ printk(" fs_ry : %d\n",s->fs_ry); ++ printk(" frm_mv_en : %d\n",s->frm_mv_en); ++ printk(" frm_mv_size : %d\n",s->frm_mv_size); ++ printk(" glb_mv_en : %d\n",s->glb_mv_en); ++ printk(" glb_mvx : %d\n",s->glb_mvx); ++ printk(" glb_mvy : %d\n",s->glb_mvy); ++ printk(" me_step_en : %d\n",s->me_step_en); ++ printk(" me_step_0 : %d\n",s->me_step_0); ++ printk(" me_step_1 : %d\n",s->me_step_1); ++ } ++ /* 3. quant cfg [4]*/ ++ { ++ int i=0,j=0; ++ printk(" dct8x8_en : %d\n",s->dct8x8_en); ++ for (i=0;i<4;i++) ++ for (j=0;j<16;j++) ++ printk(" scaling_list[%d][%d] : %d\n",i,j,s->scaling_list[i][j]); ++ for (i=0;i<2;i++) ++ for (j=0;j<64;j++) ++ printk(" scaling_list8[%d][%d] : %d\n",i,j,s->scaling_list8[i][j]); ++ for (i=0;i<9;i++) ++ printk(" deadzone[%d] : %d\n",i,s->deadzone[i]); ++ } ++ ++ /* 4. loop filter cfg [4]*/ ++ { ++ printk(" deblock : %d\n",s->deblock); ++ printk(" rotate : %d\n",s->rotate); ++ printk(" alpha_c0_offset : %d\n",s->alpha_c0_offset); ++ printk(" beta_offset : %d\n",s->beta_offset); ++ } ++ /* 5. do not douch, default value [56]*/ ++ { ++ printk(" acmask_mode : %d\n",s->acmask_mode); ++ printk(" intra_mode_msk : %d\n",s->intra_mode_msk); ++ printk(" i_4x4_dis : %d\n",s->i_4x4_dis); ++ printk(" i_8x8_dis : %d\n",s->i_8x8_dis); ++ printk(" i_16x16_dis : %d\n",s->i_16x16_dis); ++ printk(" p_l0_dis : %d\n",s->p_l0_dis); ++ printk(" p_t8_dis : %d\n",s->p_t8_dis); ++ printk(" p_skip_dis : %d\n",s->p_skip_dis); ++ printk(" p_skip_pl0f_dis : %d\n",s->p_skip_pl0f_dis); ++ printk(" p_skip_pt8f_dis : %d\n",s->p_skip_pt8f_dis); ++ ++ printk(" cost_bias_en : %d\n",s->cost_bias_en); ++ printk(" cost_bias_i_4x4 : %d\n",s->cost_bias_i_4x4); ++ printk(" cost_bias_i_8x8 : %d\n",s->cost_bias_i_8x8); ++ printk(" cost_bias_i_16x16 : %d\n",s->cost_bias_i_16x16); ++ printk(" cost_bias_p_l0 : %d\n",s->cost_bias_p_l0); ++ printk(" cost_bias_p_t8 : %d\n",s->cost_bias_p_t8); ++ printk(" cost_bias_p_skip : %d\n",s->cost_bias_p_skip); ++ ++ printk(" intra_lambda_y_bias_en : %d\n",s->intra_lambda_y_bias_en); ++ printk(" intra_lambda_c_bias_en : %d\n",s->intra_lambda_c_bias_en); ++ printk(" intra_lambda_bias_qp0 : %d\n",s->intra_lambda_bias_qp0); ++ printk(" intra_lambda_bias_qp1 : %d\n",s->intra_lambda_bias_qp1); ++ printk(" intra_lambda_bias_0 : %d\n",s->intra_lambda_bias_0); ++ printk(" intra_lambda_bias_1 : %d\n",s->intra_lambda_bias_1); ++ printk(" intra_lambda_bias_2 : %d\n",s->intra_lambda_bias_2); ++ ++ printk(" chroma_sse_bias_en : %d\n",s->chroma_sse_bias_en); ++ printk(" chroma_sse_bias_qp0 : %d\n",s->chroma_sse_bias_qp0); ++ printk(" chroma_sse_bias_qp1 : %d\n",s->chroma_sse_bias_qp1); ++ printk(" chroma_sse_bias_0 : %d\n",s->chroma_sse_bias_0); ++ printk(" chroma_sse_bias_1 : %d\n",s->chroma_sse_bias_1); ++ printk(" chroma_sse_bias_2 : %d\n",s->chroma_sse_bias_2); ++ ++ printk(" sse_lambda_bias_en : %d\n",s->sse_lambda_bias_en); ++ printk(" sse_lambda_bias : %d\n",s->sse_lambda_bias); ++ printk(" fbc_ep : %d\n",s->fbc_ep); ++ printk(" jm_lambda2_en : %d\n",s->jm_lambda2_en); ++ printk(" inter_nei_en : %d\n",s->inter_nei_en); ++ printk(" skip_bias_en : %d\n",s->skip_bias_en); ++ ++ printk(" ysse_thr : %d\n",s->ysse_thr); ++ printk(" csse_thr : %d\n",s->csse_thr); ++ printk(" dcm_en : %d\n",s->dcm_en); ++ printk(" dcm_param : %d\n",s->dcm_param); ++ printk(" sde_prior : %d\n",s->sde_prior); ++ printk(" db_prior : %d\n",s->db_prior); ++ ++ printk(" use_intra_in_pframe : %d\n",s->use_intra_in_pframe); ++ printk(" use_fast_mvp : %d\n",s->use_fast_mvp); ++ printk(" skip_en : %d\n",s->skip_en); ++ printk(" cqp_offset : %d\n",s->cqp_offset); ++ ++ printk(" daisy_chain_en : %d\n",s->daisy_chain_en); ++ printk(" curr_thread_id : %d\n",s->curr_thread_id); ++ printk(" qp_tab_mode : %d\n",s->qp_tab_mode); ++ printk(" bs_size_en : %d\n",s-> bs_size_en); ++ printk(" bs_size : %d\n",s->bs_size); ++ printk(" raw_format : %d\n",s->raw_format); ++ ++ printk(" size_mode : %d\n",s->size_mode); ++ printk(" step_mode : %d\n",s->step_mode); ++ printk(" mode_ctrl : %d\n",s->mode_ctrl); ++ int i=0; ++ for (i=0;i<40;i++) ++ printk("mode_ctrl_param[%d] : %d\n",i,s->mode_ctrl_param[i]); ++ ++ } ++ /* 6. select hardware output mode [11]*/ ++ { ++ printk(" info_en : %d\n",s->info_en); ++ printk(" mvd_sum_all : %d\n",s->mvd_sum_all); ++ printk(" mvd_sum_abs : %d\n",s->mvd_sum_abs); ++ printk(" mv_sum_all : %d\n",s->mv_sum_all); ++ printk(" mv_sum_abs : %d\n",s->mv_sum_abs); ++ ++ ++ printk(" cfg_size_x : %d\n",s->cfg_size_x); ++ printk(" cfg_size_y : %d\n",s->cfg_size_y); ++ printk(" cfg_iw_thr : %d\n",s->cfg_iw_thr); ++ ++ printk(" cfg_mvr_thr1 : %d\n",s->cfg_mvr_thr1); ++ printk(" cfg_mvr_thr2 : %d\n",s->cfg_mvr_thr2); ++ printk(" cfg_mvr_thr3 : %d\n",s->cfg_mvr_thr3); ++ } ++ /* 7. ipred bit&lambda ctrl [33]*/ ++ { ++ printk(" mb_mode_val : %d\n",s->mb_mode_val); ++ printk(" bit_16_en : %d\n",s->bit_16_en); ++ printk(" bit_8_en : %d\n",s->bit_8_en); ++ printk(" bit_4_en : %d\n",s->bit_4_en); ++ printk(" bit_uv_en : %d\n",s->bit_uv_en); ++ printk(" lamb_16_en : %d\n",s->lamb_16_en); ++ printk(" lamb_8_en : %d\n",s->lamb_8_en); ++ printk(" lamb_4_en : %d\n",s->lamb_4_en); ++ printk(" lamb_uv_en : %d\n",s->lamb_uv_en); ++ printk(" lamb_uv_en : %d\n",s->c_16_en); ++ printk(" c_8_en : %d\n",s->c_8_en); ++ printk(" c_4_en : %d\n",s->c_4_en); ++ printk(" c_uv_en : %d\n",s->c_uv_en); ++ printk(" pri_16 : %d\n",s->pri_16); ++ printk(" pri_8 : %d\n",s->pri_8); ++ printk(" pri_4 : %d\n",s->pri_4); ++ printk(" pri_uv : %d\n",s->pri_uv); ++ printk(" ref_neb_4 : %d\n",s->ref_neb_4); ++ printk(" ref_neb_8 : %d\n",s->ref_neb_8); ++ printk(" lambda_info16 : %d\n",s->lambda_info16); ++ printk(" lambda_info8 : %d\n",s->lambda_info8); ++ printk(" lambda_info4 : %d\n",s->lambda_info4); ++ printk(" lambda_infouv : %d\n",s->lambda_infouv); ++ printk(" ref_4 : %d\n",s->ref_4); ++ printk(" ref_8 : %d\n",s->ref_8); ++ ++ int i=0; ++ for (i=0;i<4;i++) ++ printk(" bit_16[%d] : %d\n",i,s->bit_16[i]); ++ for (i=0;i<4;i++) ++ printk(" bit_uv[%d] : %d\n",i,s->bit_uv[i]); ++ for (i=0;i<4;i++) ++ printk(" bit_4[%d] : %d\n",i,s->bit_4[i]); ++ for (i=0;i<4;i++) ++ printk(" bit_8[%d] : %d\n",i,s->bit_8[i]); ++ for (i=0;i<4;i++) ++ printk(" const_16[%d] : %d\n",i,s->const_16[i]); ++ for (i=0;i<4;i++) ++ printk(" const_uv[%d] : %d\n",i,s->const_uv[i]); ++ for (i=0;i<4;i++) ++ printk(" const_4[%d] : %d\n",i,s->const_4[i]); ++ for (i=0;i<4;i++) ++ printk(" const_8[%d] : %d\n",i,s->const_8[i]); ++ } ++ /* 9. jrfc,jrfd [5]*/ ++ { ++ printk(" jrfcd_flag : %d\n",s->jrfcd_flag); ++ printk(" jrfc_enable : %d\n",s->jrfc_enable); ++ printk(" jrfd_enable : %d\n",s->jrfd_enable); ++ printk(" lm_head_total : %d\n",s->lm_head_total); ++ printk(" cm_head_total : %d\n",s->cm_head_total); ++ } ++ /* 10. eigen cfg for mosaic, color error [42]*/ ++ { ++ printk(" mb_mode_use : %d\n",s->mb_mode_use); ++ printk(" force_i16dc : %d\n",s->force_i16dc);//ipred ++ printk(" force_i16 : %d\n",s->force_i16); ++ printk(" refresh_en : %d\n",s->refresh_en); ++ printk(" refresh_mode : %d\n",s->refresh_mode); ++ printk(" refresh_bias : %d\n",s->refresh_bias); ++ printk(" refresh_cplx_thd : %d\n",s->refresh_cplx_thd); ++ printk(" cplx_thd_sel : %d\n",s->cplx_thd_sel); ++ printk(" diff_cplx_sel : %d\n",s->diff_cplx_sel); ++ printk(" diff_thd_sel : %d\n",s->diff_thd_sel); ++ printk(" i16dc_cplx_thd : %d\n",s->i16dc_cplx_thd); ++ printk(" i16dc_qp_base : %d\n",s->i16dc_qp_base); ++ printk(" i16dc_qp_sel : %d\n",s->i16dc_qp_sel); ++ printk(" i16_qp_base : %d\n",s->i16_qp_base); ++ printk(" i16_qp_sel : %d\n",s->i16_qp_sel); ++ printk(" diff_cplx_thd : %d\n",s->diff_cplx_thd); ++ ++ int i=0; ++ for (i=0;i<2;i++) ++ printk(" diff_qp_base[%d] : %d\n",i,s->diff_qp_base[i]); ++ for (i=0;i<2;i++) ++ printk(" diff_qp_sel[%d] : %d\n",i,s->diff_qp_sel[i]); ++ for (i=0;i<24;i++) ++ printk(" cplx_thd_idx[%d] : %d\n",i,s->cplx_thd_idx[i]); ++ for (i=0;i<8;i++) ++ printk(" cplx_thd[%d] : %d\n",i,s->cplx_thd[i]); ++ for (i=0;i<3;i++) ++ printk(" diff_thd_base[%d] : %d\n",i,s->diff_thd_base[i]); ++ for (i=0;i<3;i++) ++ printk(" diff_thd_ofst[%d] : %d\n",i,s->diff_thd_ofst[i]); ++ printk(" sas_eigen_en : %d\n",s->sas_eigen_en); ++ printk(" crp_eigen_en : %d\n",s->crp_eigen_en); ++ printk(" sas_eigen_dump : %d\n",s->sas_eigen_dump); ++ printk(" crp_eigen_dump : %d\n",s->crp_eigen_dump); ++ printk(" rrs_en : %d\n",s->rrs_en); ++ printk(" rrs_dump_en : %d\n",s->rrs_dump_en); ++ printk(" rrs_uv_en : %d\n",s->rrs_uv_en); ++ printk(" rrs_size_y : %d\n",s->rrs_size_y); ++ printk(" rrs_size_c : %d\n",s->rrs_size_c); ++ printk(" rrs_thrd_y : %d\n",s->rrs_thrd_y); ++ printk(" rrs_thrd_u : %d\n",s->rrs_thrd_u); ++ printk(" rrs_thrd_v : %d\n",s->rrs_thrd_v); ++ } ++ /* 11. skin judge cfg [14]*/ ++ { ++ printk(" skin_dt_en : %d\n",s->skin_dt_en); ++ printk(" skin_lvl : %d\n",s->skin_lvl); ++ printk(" skin_cnt_thd : %d\n",s->skin_cnt_thd); ++ printk(" ncu_mov_en : %d\n",s->ncu_mov_en); ++ printk(" ncu_move_len : %d\n",s->ncu_move_len); ++ if (s->ncu_move_info == NULL) ++ printk(" ncu_move_info is NULL \n"); ++ else ++ printk(" ncu_move_info : %p\n",s->ncu_move_info); ++ printk(" buf_share_en : %d\n",s->buf_share_en); ++ printk(" buf_share_size : %d\n",s->buf_share_size); ++ printk(" frame_idx : %d\n",s->frame_idx); ++ printk(" is_first_Pframe : %d\n",s->is_first_Pframe); ++ int i=0,j=0; ++ for (i=0;i<3;i++) ++ for (j=0;j<2;j++) ++ printk(" skin_pxlu_thd[%d][%d] : %d\n",i,j,s->skin_pxlu_thd[i][j]); ++ for (i=0;i<3;i++) ++ for (j=0;j<2;j++) ++ printk(" skin_pxlv_thd[%d][%d] : %d\n",i,j,s->skin_pxlv_thd[i][j]); ++ for (i=0;i<4;i++) ++ printk(" skin_qp_ofst[%d] : %d\n",i,s->skin_qp_ofst[i]); ++ for (i=0;i<3;i++) ++ printk(" mult_factor[%d] : %d\n",i,s->mult_factor[i]); ++ for (i=0;i<3;i++) ++ for (j=0;j<3;j++) ++ printk(" shift_factor[%d][%d] : %d\n",i,j,s->shift_factor[i][j]); ++ for (i=0;i<4;i++) ++ printk(" skin_ofst[%d] : %d\n",i,s->skin_ofst[i]); ++ } ++ /* 12.qpg */ ++ { ++ /* qp map */ ++ printk(" qp_tab_en : %d\n",s->qp_tab_en); ++ printk(" qp_tab_len : %d\n",s->qp_tab_len); ++ if (s->qp_tab == NULL) ++ printk(" qp_tab is NULL"); ++ else ++ printk(" qp_tab : %p\n", s->qp_tab); ++ int i=0; ++ for (i=0;i<8;i++) { ++ printk("roi_en[%d] : %d\n",i,s->roi_info[i].roi_en); ++ printk("roi_md[%d] : %d\n",i,s->roi_info[i].roi_md); ++ printk("roi_qp[%d] : %d\n",i,s->roi_info[i].roi_qp); ++ printk("roi_lmbx[%d] : %d\n",i,s->roi_info[i].roi_lmbx); ++ printk("roi_rmbx[%d] : %d\n",i,s->roi_info[i].roi_rmbx); ++ printk("roi_umby[%d] : %d\n",i,s->roi_info[i].roi_umby); ++ printk("roi_bmby[%d] : %d\n",i,s->roi_info[i].roi_bmby); ++ } ++ /* qp cplx */ ++ printk(" sas_en : %d\n",s->sas_en); ++ printk(" crp_en : %d\n",s->crp_en); ++ printk(" sas_mthd : %d\n",s->sas_mthd); ++ for (i=0;i<7;i++) ++ printk(" qpg_mb_thd[%d] : %d\n", i,s->qpg_mb_thd[i]); ++ for (i=0;i<8;i++) ++ printk(" qpg_mbqp_ofst[%d] : %d\n", i,s->qpg_mbqp_ofst[i]); ++ for (i=0;i<5;i++) ++ printk(" qpg_flt_thd[%d] : %d\n", i,s->qpg_flt_thd[i]); ++ printk(" mbrc_qpg_sel : %d\n",s->mbrc_qpg_sel); ++ /* bu rc */ ++ printk(" rc_mb_en : %d\n",s->rc_mb_en); ++ printk(" rc_bu_wait_en : %d\n",s->rc_bu_wait_en); ++ printk(" rc_mb_wait_en : %d\n",s->rc_mb_wait_en); ++ printk(" rc_bu_num : %d\n",s->rc_bu_num); ++ printk(" rc_bu_size : %d\n",s->rc_bu_size); ++ printk(" rc_bu_level : %d\n",s->rc_bu_level); ++ printk(" rc_mb_level : %d\n",s->rc_mb_level); ++ if (s->mb_ref_info == NULL) ++ printk(" mb_ref_info is NULL"); ++ else ++ printk(" mb_ref_info : %p\n", s->mb_ref_info); ++ if (s->bu_ref_info == NULL) ++ printk(" bu_ref_info is NULL"); ++ else ++ printk(" bu_ref_info : %p\n", s->bu_ref_info); ++ printk(" rc_frm_tbs : %d\n",s->rc_frm_tbs); ++ printk(" avg_bu_bs : %d\n",s->avg_bu_bs); ++ for (i=0;i<6;i++) ++ printk(" tar_bs_thd[%d] : %d\n",s->tar_bs_thd[i]); ++ for (i=0;i<6;i++) ++ printk(" tar_bs_thd[%d] : %d\n",s->bu_alg0_qpo[i]); ++ for (i=0;i<6;i++) ++ printk(" bu_alg1_qpo[%d] : %d\n",s->bu_alg1_qpo[i]); ++ for (i=0;i<7;i++) ++ printk(" mb_cs_qpo[%d] : %d\n",s->mb_cs_qpo[i]); ++ for (i=0;i<2;i++) ++ printk(" mb_top_bs_qpo[%d] : %d\n",s->mb_top_bs_qpo[i]); ++ for (i=0;i<2;i++) ++ printk(" mb_rinfo_qpo[%d] : %d\n",s->mb_rinfo_qpo[i]); ++ for (i=0;i<2;i++) ++ printk(" mb_target_avg_bs[%d] : %d\n",s->mb_target_avg_bs[i]); ++ printk(" mb_gp_num : %d\n",s->mb_gp_num); ++ printk(" last_bu_size : %d\n",s->last_bu_size); ++ printk(" rc_bcfg_mode : %d\n",s->rc_bcfg_mode); ++ } ++ ++} ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.h +new file mode 100644 +index 000000000..bbb342163 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/api/helix_x264_enc.h +@@ -0,0 +1,418 @@ ++/**************************************************************** ++*****************************************************************/ ++ ++#ifndef __JZM_X264_ENC_H__ ++#define __JZM_X264_ENC_H__ ++#include "helix.h" ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#define printf printk ++ ++#else ++#include ++#include ++ ++#endif ++ ++#define SCH_FIFO_DEPTH 16 ++ ++/************************************************************ ++ CHN Space Allocation ++ ************************************************************/ ++#define VRAM_DUMMY (VPU_BASE | 0xFFFFC) ++ ++#define VRAM_MAU_RESA (VPU_BASE | 0xC0000) //residual address ++#define VRAM_MAU_RES_SIZE (SCH_FIFO_DEPTH*256*4) ++ ++#define VRAM_RAWY_BA (VPU_BASE | 0xF0000) ++#define VRAM_RAWC_BA (VRAM_RAWY_BA + 256) ++#define VRAM_RAW_SIZE (SCH_FIFO_DEPTH*128*4) ++ ++#define VRAM_TOPPA_BA (VRAM_MAU_RESA+VRAM_MAU_RES_SIZE) //recover address ++#define VRAM_TOPMV_BA (VRAM_TOPPA_BA+VPU_MAX_MB_WIDTH*8) ++ ++#define VRAM_MAU_CHN_BASE (VRAM_TOPMV_BA+VPU_MAX_MB_WIDTH*4) ++#define VRAM_MAU_CHN_SIZE (SCH_FIFO_DEPTH*16*4) ++#define VRAM_DBLK_CHN_BASE (VRAM_MAU_CHN_BASE + VRAM_MAU_CHN_SIZE) ++#define VRAM_DBLK_CHN_SIZE (SCH_FIFO_DEPTH*16*4) ++#define VRAM_ME_CHN_BASE (VRAM_DBLK_CHN_BASE + VRAM_DBLK_CHN_SIZE) ++#define VRAM_ME_CHN_SIZE (SCH_FIFO_DEPTH*8*4) ++#define VRAM_SDE_CHN_BASE (VRAM_ME_CHN_BASE + VRAM_ME_CHN_SIZE) ++#define VRAM_SDE_CHN_SIZE (SCH_FIFO_DEPTH*8*4) ++#define VRAM_QP_TAB_BA (VRAM_SDE_CHN_BASE + VRAM_SDE_CHN_SIZE) ++ ++#define VRAM_ME_DSA DSA_SCH_CH1 ++#define VRAM_MAU_DEC_SYNA DSA_SCH_CH2 ++#define VRAM_DBLK_CHN_SYNA DSA_SCH_CH3 ++#define VRAM_SDE_SYNA DSA_SCH_CH4 ++ ++#define VRAM_MAU_ENC_SYNA VRAM_DUMMY ++#define VRAM_DBLK_DOUT_SYNA VRAM_DUMMY ++ ++#define VRAM_ME_MVPA (VPU_BASE | REG_EFE_MVRP) ++ ++#define EMC_SIZE (1 << 21) ++#define DBLK_SIZE (1 << 20) ++#define RECON_SIZE (1 << 18) ++#define MV_SIZE (1 << 11) ++#define SE_SIZE (1 << 11) ++#define QPT_SIZE (1<<14) ++#define RC_SIZE (1<<15) ++#define CPX_SIZE (1<<17) ++#define MOD_SIZE (1<<15) ++#define SAD_SIZE (1<<17) ++#define ENCU_SIZE (1<<13) ++#define BEYOND_MAX_SIZE 64*3 ++ ++typedef unsigned int paddr_t; ++ ++#define __ALN32__ __attribute__ ((aligned(4))) ++ ++typedef struct ROI_info{ ++ uint8_t roi_en; ++ uint8_t roi_md; ++ int8_t roi_qp; ++ uint8_t roi_lmbx; ++ uint8_t roi_rmbx; ++ uint8_t roi_umby; ++ uint8_t roi_bmby; ++} roi_info_t; ++ ++/* ++ _H264E_SliceInfo: ++ H264 Encoder Slice Level Information ++ */ ++typedef struct _H264E_SliceInfo { ++ /*basic*/ ++ uint8_t frame_type; ++ uint8_t mb_width; ++ uint8_t mb_height; ++ uint8_t first_mby; ++ uint8_t last_mby; //for multi-slice ++ ++ /* motion */ ++ int frame_width; ++ int frame_height; ++ uint8_t frm_re[4]; ++ uint8_t pskip_en; ++ uint8_t force_mv0_en; ++ uint8_t mref_en; ++ uint8_t dct8x8_en; ++ uint8_t scl; ++ uint8_t hpel_en; ++ uint8_t qpel_en; ++ uint8_t ref_mode; ++ uint32_t max_sech_step_i; ++ uint32_t max_mvrx_i; ++ uint32_t max_mvry_i; ++ uint8_t lambda_scale_parameter; ++ uint8_t fs_en; //fs function enable ++ uint32_t fs_md; //fs step mode, 0: 1, 1: 3 ++ uint8_t fs_px; //fs period x ++ uint8_t fs_py; //fs period y ++ uint8_t fs_rx; //fs range x, must be multiples of 3 ++ uint8_t fs_ry; //fs range y, must be multiples of 3 ++ uint8_t frm_mv_en; //add a frame level mv ++ uint8_t frm_mv_size; //mv enable after x mb, x=2^(size+8) ++ uint8_t glb_mv_en; //global mv enable ++ int glb_mvx; //global mvx value ++ int glb_mvy; //global mvy value ++ uint8_t me_step_en; //auto-modify max step number ++ uint8_t me_step_0; //step number threshold 0 ++ uint8_t me_step_1; //step number threshold 1 ++ /*vmau scaling list*/ ++ uint8_t __ALN32__ scaling_list[4][16]; ++ uint8_t __ALN32__ scaling_list8[2][64]; ++ int deadzone[9]; ++ uint32_t acmask_mode; ++ ++ uint32_t intra_mode_msk; ++ ++ uint8_t i_4x4_dis; ++ uint8_t i_8x8_dis; ++ uint8_t i_16x16_dis; ++ uint8_t p_l0_dis; ++ uint8_t p_t8_dis; ++ uint8_t p_skip_dis; ++ uint8_t p_skip_pl0f_dis; ++ uint8_t p_skip_pt8f_dis; ++ ++ uint8_t cost_bias_en; ++ uint8_t cost_bias_i_4x4; ++ uint8_t cost_bias_i_8x8; ++ uint8_t cost_bias_i_16x16; ++ uint8_t cost_bias_p_l0; ++ uint8_t cost_bias_p_t8; ++ uint8_t cost_bias_p_skip; ++ ++ uint8_t intra_lambda_y_bias_en; ++ uint8_t intra_lambda_c_bias_en; ++ uint8_t intra_lambda_bias_qp0; ++ uint8_t intra_lambda_bias_qp1; ++ uint8_t intra_lambda_bias_0; ++ uint8_t intra_lambda_bias_1; ++ uint8_t intra_lambda_bias_2; ++ ++ uint8_t chroma_sse_bias_en; ++ uint8_t chroma_sse_bias_qp0; ++ uint8_t chroma_sse_bias_qp1; ++ uint8_t chroma_sse_bias_0; ++ uint8_t chroma_sse_bias_1; ++ uint8_t chroma_sse_bias_2; ++ ++ uint8_t sse_lambda_bias_en; ++ uint8_t sse_lambda_bias; ++ ++ uint8_t fbc_ep; ++ uint8_t jm_lambda2_en; ++ uint8_t inter_nei_en; ++ uint8_t skip_bias_en; ++ ++ uint8_t info_en; ++ uint8_t mvd_sum_all; ++ uint8_t mvd_sum_abs; ++ uint8_t mv_sum_all; ++ uint8_t mv_sum_abs; ++ ++ uint32_t ysse_thr; ++ uint32_t csse_thr; ++ ++ uint8_t cfg_size_x; ++ uint8_t cfg_size_y; ++ uint16_t cfg_iw_thr; ++ ++ uint16_t cfg_mvr_thr1; ++ uint32_t cfg_mvr_thr2; ++ uint32_t cfg_mvr_thr3; ++ ++ uint8_t dcm_en; ++ uint32_t dcm_param; ++ ++ uint8_t sde_prior; ++ uint8_t db_prior; ++ /*ipred bit&lambda ctrl*/ ++ uint8_t mb_mode_val; ++ uint8_t bit_16_en; ++ uint8_t bit_8_en; ++ uint8_t bit_4_en; ++ uint8_t bit_uv_en; ++ uint8_t lamb_16_en; ++ uint8_t lamb_8_en; ++ uint8_t lamb_4_en; ++ uint8_t lamb_uv_en; ++ uint8_t c_16_en; ++ uint8_t c_8_en; ++ uint8_t c_4_en; ++ uint8_t c_uv_en; ++ uint8_t pri_16; ++ uint8_t pri_8; ++ uint8_t pri_4; ++ uint8_t pri_uv; ++ uint8_t ref_neb_4; ++ uint8_t ref_neb_8; ++ uint8_t bit_16[4]; ++ uint8_t bit_uv[4]; ++ uint8_t bit_4[4]; ++ uint8_t bit_8[4]; ++ uint8_t lambda_info16; ++ uint8_t lambda_info8; ++ uint8_t lambda_info4; ++ uint8_t lambda_infouv; ++ uint8_t ref_4; ++ uint8_t ref_8; ++ uint8_t const_16[4]; ++ uint8_t const_uv[4]; ++ uint8_t const_4[4]; ++ uint8_t const_8[4]; ++ ++ /*loop filter*/ ++ uint8_t deblock; ++ uint8_t rotate; ++ int8_t alpha_c0_offset; ++ int8_t beta_offset; ++ ++ /*cabac*/ ++ uint8_t *state; ++ paddr_t bs; /*BS output address*/ ++ uint8_t bs_rbsp_en; /*BS rbsp enable*/ ++ uint8_t bs_head_en; /*read BS header enable*/ ++ uint8_t bs_head_len; /*read BS header lenth*/ ++ paddr_t *bs_head_va; /*read BS header data addr*/ ++ paddr_t bs_head_pa; /*read BS header data addr*/ ++ uint8_t qp; ++ uint8_t bs_size_en; ++ uint32_t bs_size; ++ ++ uint8_t skip_en; ++ int8_t cqp_offset; ++ /*mode decision*/ ++ uint8_t use_intra_in_pframe; ++ uint8_t use_fast_mvp; ++ ++ uint8_t mode_ctrl; ++ uint32_t mode_ctrl_param[40]; ++ ++ /*frame buffer address: all of the buffers should be 256byte aligned!*/ ++ paddr_t fb[3][2]; /*{curr, ref}{tile_y, tile_c}*/ ++ paddr_t raw[3]; /*{rawy, rawu, rawv} or {rawy, rawc, N/C}*/ ++ int stride[2]; /*{stride_y, stride_c}, only used in raster raw*/ ++ ++ /* RAW plane format */ ++ uint8_t raw_format; ++ ++ uint8_t size_mode; ++ uint8_t step_mode; ++ /*descriptor address*/ ++ paddr_t *des_va, des_pa; ++ paddr_t emc_bs_pa; ++ paddr_t *emc_dblk_va,emc_dblk_pa; ++ paddr_t *emc_recon_va,emc_recon_pa; ++ paddr_t *emc_mv_va,emc_mv_pa; ++ paddr_t *emc_se_va,emc_se_pa; ++ paddr_t *emc_qpt_va, emc_qpt_pa; ++ paddr_t *emc_rc_va, emc_rc_pa; ++ paddr_t *emc_cpx_va, emc_cpx_pa; ++ paddr_t *emc_mod_va, emc_mod_pa; ++ paddr_t *emc_ncu_va, emc_ncu_pa; ++ paddr_t *emc_sad_va, emc_sad_pa; ++ ++ /*TLB address*/ ++ paddr_t tlba; ++ ++ /* ROI info */ ++ roi_info_t roi_info[8]; ++ uint8_t base_qp; ++ uint8_t max_qp; ++ uint8_t min_qp; ++ ++ uint8_t qp_tab_mode; ++ uint8_t qp_tab_en; ++ uint32_t qp_tab_len; ++ uint32_t *qp_tab; ++ uint8_t sas_en; ++ uint8_t crp_en; ++ uint8_t sas_mthd; ++ uint16_t qpg_mb_thd[7]; ++ int8_t qpg_mbqp_ofst[8]; ++ uint8_t qpg_flt_thd[5]; ++ uint8_t mbrc_qpg_sel; //whether use crp/sas qp offset or not, when MB rate control enable. ++ ++ /* rate ctrl */ ++ uint8_t rc_mb_en; ++ uint8_t rc_bu_wait_en;// efe chn wait rc qp offset en ++ uint8_t rc_mb_wait_en;// efe chn wait rc qp offset en ++ uint8_t rc_bu_num;// total basic unit number ++ uint16_t rc_bu_size;// mb number in a basic unit ++ uint8_t rc_bu_level;// 1:1line 2:2line 3:4line 4:8line 5:16line 6:32line 7:64line ++ uint8_t rc_mb_level;// 0:skip 1mb, 1:skip 2mb, 2:skip 4mb, 3:skip 8mb ++ int32_t *mb_ref_info; ++ int32_t *bu_ref_info; ++ uint32_t rc_frm_tbs; ++ uint32_t avg_bu_bs; ++ uint16_t tar_bs_thd[6]; ++ int8_t bu_alg0_qpo[6]; ++ int8_t bu_alg1_qpo[6]; ++ int8_t mb_cs_qpo[7]; ++ int8_t mb_top_bs_qpo[2]; ++ int8_t mb_rinfo_qpo[2]; ++ uint16_t mb_target_avg_bs[2]; ++ uint16_t mb_gp_num; ++ uint16_t last_bu_size; ++ uint8_t rc_bcfg_mode; ++ ++ //mosaic ++ uint8_t mosaic_en; ++ uint8_t mos_gthd[2]; ++ uint8_t mos_sthd[2]; ++ /* VPU Daisy Chain setting */ ++ uint8_t daisy_chain_en; ++ uint8_t curr_thread_id; ++ ++ //odma,jrfc,jrfd ++ uint8_t jrfcd_flag; ++ uint8_t jrfc_enable; ++ uint8_t jrfd_enable; ++ uint32_t lm_head_total; ++ uint32_t cm_head_total; ++ paddr_t jh[3][2]; /*head addr {curr, ref0, ref1}{y, c}*/ ++ paddr_t spe_y_addr; ++ paddr_t spe_c_addr; ++ ++ //eigen cfg ++ uint8_t mb_mode_use; ++ uint32_t *mb_mode_info; ++ uint8_t force_i16dc;//ipred ++ uint8_t force_i16; ++ uint8_t refresh_en; ++ uint8_t refresh_mode; ++ uint8_t refresh_bias; ++ uint8_t refresh_cplx_thd; ++ uint8_t cplx_thd_sel; ++ uint8_t diff_cplx_sel; ++ uint8_t diff_thd_sel; ++ uint8_t i16dc_cplx_thd; ++ uint8_t i16dc_qp_base; ++ uint8_t i16dc_qp_sel; ++ uint8_t i16_qp_base; ++ uint8_t i16_qp_sel; ++ uint8_t diff_cplx_thd; ++ uint8_t diff_qp_base[2]; ++ uint8_t diff_qp_sel[2]; ++ uint8_t cplx_thd_idx[24]; ++ uint8_t cplx_thd[8]; ++ uint16_t diff_thd_base[3]; ++ uint16_t diff_thd_ofst[3]; ++ uint8_t sas_eigen_en; ++ uint8_t crp_eigen_en; ++ uint8_t sas_eigen_dump; ++ uint8_t crp_eigen_dump; ++ //ifa ++ uint8_t rrs_en; ++ uint8_t rrs_dump_en; ++ uint8_t rrs_uv_en; ++ uint8_t rrs_size_y; //0: 4, 1: 8, 2: 12, 3: 16 ++ uint8_t rrs_size_c; //0: 4, 1: 8 ++ uint16_t rrs_thrd_y; //threshold ++ uint16_t rrs_thrd_u; ++ uint16_t rrs_thrd_v; ++ ++ //skin ++ uint8_t skin_dt_en; ++ uint8_t skin_lvl; ++ uint8_t skin_cnt_thd; ++ uint8_t skin_pxlu_thd[3][2]; ++ uint8_t skin_pxlv_thd[3][2]; ++ int8_t skin_qp_ofst[4]; ++ uint8_t mult_factor[3]; ++ uint8_t shift_factor[3][3];//[0][]:0.4, [1][]:0.6, [2][]: 5.1 ++ uint16_t skin_ofst[4];//[0]: 1.5, [1]:0.4, [2]:0.6, [3]: 5.1 ++ uint8_t ncu_mov_en; ++ uint32_t ncu_move_len; ++ uint32_t *ncu_move_info; ++ //buf-share ++ uint8_t buf_share_en; ++ uint8_t buf_share_size; ++ uint32_t frame_idx; ++ uint8_t is_first_Pframe; ++}_H264E_SliceInfo; ++ ++typedef struct _H264E_SliceInfo H264E_SliceInfo_t; ++ ++ ++/* ++ H264E_SliceInit(_H264E_SliceInfo *s) ++ @param s: slice information structure ++ */ ++void H264E_SliceInit(_H264E_SliceInfo *s); ++void H264E_DumpInfo(_H264E_SliceInfo *s); ++ ++ ++/* ++ default _H264_SliceInfo. ++*/ ++extern _H264E_SliceInfo default_H264E_Sliceinfo; ++ ++#endif /*__JZM_H264E_H__*/ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/default_sliceinfo.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/default_sliceinfo.c +new file mode 100644 +index 000000000..8a0b85675 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/default_sliceinfo.c +@@ -0,0 +1,362 @@ ++#include "api/helix_x264_enc.h" ++ ++_H264E_SliceInfo default_H264E_Sliceinfo = { ++ .frame_type = 1, ++ .mb_width = 22, ++ .mb_height = 18, ++ .first_mby = 0, ++ .last_mby = 17, ++ .frame_width = 352, ++ .frame_height = 288, ++ ++ .frm_re = {0x00, 0x00, 0x00, 0x00}, ++ .pskip_en = 1, ++ .mref_en = 0, ++ .dct8x8_en = 0, ++ .scl = 0x03, ++ .hpel_en = 0x01, ++ .qpel_en = 0x01, ++ .ref_mode = 0x01, ++ .max_sech_step_i = 0x3f, ++ .max_mvrx_i = 0x1f4, ++ .max_mvry_i = 0x1f4, ++ .lambda_scale_parameter = 0x08, ++ .fs_en = 0x00, ++ .fs_md = 0x00, ++ .fs_px = 0x00, ++ .fs_py = 0x00, ++ .fs_rx = -1, ++ .fs_ry = -1, ++ .frm_mv_en = 0x00, ++ .frm_mv_size = 0x00, ++ .glb_mv_en = 0x00, ++ .glb_mvx = 0, ++ .glb_mvy = 0, ++ .me_step_en = 0x0, ++ .me_step_0 = 0x0, ++ .me_step_1 = 0x0, ++ .scaling_list = { ++ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, }, ++ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, }, ++ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, }, ++ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, }, ++ }, ++ .scaling_list8 = { ++ {0x06, 0x0a, 0x0d, 0x10, 0x12, 0x16, 0x18, 0x1a, 0x0a, 0x0b, 0x10, 0x12, 0x16, 0x18, 0x1a, 0x1c, 0x0d, 0x10, 0x12, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x10, 0x12, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x12, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x23, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x23, 0x25, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x23, 0x25, 0x27, 0x1a, 0x1c, 0x1e, 0x20, 0x23, 0x25, 0x27, 0x29, }, ++ {0x09, 0x0d, 0x0f, 0x11, 0x13, 0x15, 0x16, 0x18, 0x0d, 0x0d, 0x11, 0x13, 0x15, 0x16, 0x18, 0x19, 0x0f, 0x11, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1b, 0x11, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x13, 0x15, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e, 0x15, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e, 0x20, 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e, 0x20, 0x21, 0x18, 0x19, 0x1b, 0x1c, 0x1e, 0x20, 0x21, 0x23, }, ++ }, ++ ++ .deadzone = { 0x00000015, 0x0000000b, 0x00000015, 0x0000000b, 0x00000015, 0x0000000b, 0x00000015, 0x00000015, 0x0000000b}, ++ .acmask_mode = 0x000095ea, ++ .intra_mode_msk = 0x0, ++ .i_4x4_dis = 0x0, ++ .i_8x8_dis = 0x0, ++ .i_16x16_dis = 0x0, ++ .p_l0_dis = 0x0, ++ .p_t8_dis = 0x0, ++ .p_skip_dis = 0x0, ++ .p_skip_pl0f_dis = 0x0, ++ .p_skip_pt8f_dis = 0x0, ++ .cost_bias_en = 0x0, ++ .cost_bias_i_4x4 = 0x0, ++ .cost_bias_i_8x8 = 0x0, ++ .cost_bias_i_16x16 = 0x0, ++ .cost_bias_p_l0 = 0x0, ++ .cost_bias_p_t8 = 0x0, ++ .cost_bias_p_skip = 0x0, ++ .intra_lambda_y_bias_en = 0x0, ++ .intra_lambda_c_bias_en = 0x0, ++ .intra_lambda_bias_qp0 = 0x0, ++ .intra_lambda_bias_qp1 = 0x0, ++ .intra_lambda_bias_0 = 0x0, ++ .intra_lambda_bias_1 = 0x0, ++ .intra_lambda_bias_2 = 0x0, ++ .chroma_sse_bias_en = 0x0, ++ .chroma_sse_bias_qp0 = 0x0, ++ .chroma_sse_bias_qp1 = 0x0, ++ .chroma_sse_bias_0 = 0x0, ++ .chroma_sse_bias_1 = 0x0, ++ .chroma_sse_bias_2 = 0x0, ++ .sse_lambda_bias_en = 0x0, ++ .sse_lambda_bias = 0x0, ++ .fbc_ep = 0xcc, ++ .jm_lambda2_en = 0x0, ++ .inter_nei_en = 0x0, ++ .skip_bias_en = 0x0, ++ .info_en = 0x1, ++ .mvd_sum_all = 0x0, ++ .mvd_sum_abs = 0x0, ++ .mv_sum_all = 0x0, ++ .mv_sum_abs = 0x0, ++ .ysse_thr = 0x0, ++ .csse_thr = 0x0, ++ .cfg_size_x = 0x4, ++ .cfg_size_y = 0x4, ++ .cfg_iw_thr = 0x0, ++ .cfg_mvr_thr1 = 0x0, ++ .cfg_mvr_thr2 = 0x0, ++ .cfg_mvr_thr3 = 0x0, ++ .dcm_en = 0x0, ++ .dcm_param = 0x4304, ++ .sde_prior = 0x5, ++ .db_prior = 0x5, ++ .mb_mode_val = 0x1, ++ .bit_16_en = 0x0, ++ .bit_8_en = 0x1, ++ .bit_4_en = 0x1, ++ .bit_uv_en = 0x0, ++ .lamb_16_en = 0x0, ++ .lamb_8_en = 0x0, ++ .lamb_4_en = 0x0, ++ .lamb_uv_en = 0x0, ++ .c_16_en = 0x0, ++ .c_8_en = 0x0, ++ .c_4_en = 0x0, ++ .c_uv_en = 0x0, ++ .pri_16 = 0x0, ++ .pri_8 = 0x0, ++ .pri_4 = 0x0, ++ .pri_uv = 0x0, ++ .ref_neb_4 = 0x1, ++ .ref_neb_8 = 0x1, ++ .bit_16 = {0,0,0,0}, ++ .bit_uv = {0,0,0,0}, ++ .bit_4 = {4,4,4,4}, ++ .bit_8 = {4,4,4,4}, ++ .lambda_info16 = 0x0, ++ .lambda_info8 = 0x0, ++ .lambda_info4 = 0x0, ++ .lambda_infouv = 0x0, ++ .ref_4 = 0x4, ++ .ref_8 = 0x3, ++ .const_16 = {0,0,0,0}, ++ .const_uv = {0,0,0,0}, ++ .const_4 = {0,0,0,0}, ++ .const_8 = {0,0,0,0}, ++ .deblock = 1, ++ .rotate = 0, ++ .alpha_c0_offset = 0, ++ .beta_offset = 0, ++ .state = 0xf7edfc94, ++ .bs = 0x00000000, ++ .qp = 0x26, ++ .bs_size_en = 0x1, ++ .bs_size = 0x800, ++ .skip_en = 1, ++ .cqp_offset = 0, ++ .use_intra_in_pframe = 0x1, ++ .use_fast_mvp = 0x0, ++ .mode_ctrl = 0x0, ++ .mode_ctrl_param = {0}, ++ .fb = {{0,0},{0,0},{0,0}}, ++ .raw = {0,0,0}, ++ .stride = {0,0}, ++ .raw_format = 8, ++ .size_mode = 0, ++ .step_mode = 0, ++ .des_va = 0, ++ .des_pa = 0, ++ .emc_bs_pa = 0, ++ .emc_dblk_pa = 0, ++// .emc_bs_va = 0, ++ .emc_dblk_va = 0, ++ .emc_recon_va = 0, ++ .emc_mv_va = 0, ++ .emc_se_va = 0, ++ .emc_recon_va = 0, ++ .emc_recon_pa = 0, ++ .emc_mv_pa = 0, ++ .emc_se_pa = 0, ++ .emc_qpt_va = 0, ++ .emc_qpt_pa = 0, ++ .emc_rc_va = 0, ++ .emc_rc_pa = 0, ++ .emc_cpx_va = 0, ++ .emc_cpx_pa = 0, ++ .emc_mod_va = 0, ++ .emc_mod_pa = 0, ++ .emc_ncu_va = 0, ++ .emc_ncu_pa = 0, ++ .emc_sad_va = 0, ++ .emc_sad_pa = 0, ++ .tlba = 0, ++ .roi_info = { ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ {0,0,0,0,0,0,0}, ++ }, ++ .base_qp = 38, ++ .max_qp = 51, ++ .min_qp = 26, ++ .qp_tab_mode = 0, ++ .qp_tab_en = 0, ++ .qp_tab_len = 0, ++ .qp_tab = NULL, ++ .sas_en = 0, ++ .crp_en = 0, ++ .sas_mthd = 0, ++ .qpg_mb_thd = {0,0,0,0,0,0,0}, ++ .qpg_mbqp_ofst = {0,0,0,0,0,0,0}, ++ .qpg_flt_thd = {0,0,0,0,0}, ++ .mbrc_qpg_sel = 0, ++ .rc_mb_en = 0, ++ .rc_bu_wait_en = 0, ++ .rc_mb_wait_en = 0, ++ .rc_bu_num = 0x00000012, ++ .rc_bu_size = 0x00000016, ++ .rc_bu_level = 1, ++ .rc_mb_level = 2, ++ .mb_ref_info = NULL, ++ .bu_ref_info = NULL, ++ .rc_frm_tbs = 1000, ++ .avg_bu_bs = 55, ++ .tar_bs_thd = {500, 1000, 1500, 2000, 2500, 3000}, ++ .bu_alg0_qpo = {1,2,3,4,5,6}, ++ .bu_alg1_qpo = {1,1,1,1,1,1}, ++ .mb_cs_qpo = {-3,-2,-1,0,1,2,3}, ++ .mb_top_bs_qpo = {-1, 1}, ++ .mb_rinfo_qpo = {-1, 1}, ++ .mb_target_avg_bs = {2,2}, ++ .mb_gp_num = 198, ++ .last_bu_size = 22, ++ .rc_bcfg_mode = 0, ++ .mosaic_en = 0, ++ .mos_gthd = {1,4}, ++ .mos_sthd = {8,6}, ++ .daisy_chain_en = 0, ++ .curr_thread_id = 5, ++ .jrfcd_flag = 0, ++ .jrfc_enable = 0, ++ .jrfd_enable = 0, ++ .lm_head_total = 0, ++ .cm_head_total = 0, ++ .jh = {{0,0}, {0,0}, {0,0}}, ++ .spe_y_addr = 0, ++ .spe_c_addr = 0, ++ .mb_mode_use = 0, ++ .mb_mode_info = NULL, ++ .force_i16dc = 1, ++ .force_i16 = 1, ++ .refresh_en = 0, ++ .refresh_mode = 0, ++ .refresh_bias = 10, ++ .refresh_cplx_thd = 4, ++ .cplx_thd_sel = 0, ++ .diff_cplx_sel = 0, ++ .diff_thd_sel = 0, ++ .i16dc_cplx_thd = 3, ++ .i16dc_qp_base = 33, ++ .i16dc_qp_sel = 0, ++ .i16_qp_base = 28, ++ .i16_qp_sel = 0, ++ .diff_cplx_thd = 10, ++ .diff_qp_base = {33,33}, ++ .diff_qp_sel = {0, 0}, ++ .cplx_thd_idx = { ++ 0, /*cplx_thd_idx[0]*/ ++ 0, /*cplx_thd_idx[1]*/ ++ 1, /*cplx_thd_idx[2]*/ ++ 1, /*cplx_thd_idx[3]*/ ++ 1, /*cplx_thd_idx[4]*/ ++ 1, /*cplx_thd_idx[5]*/ ++ 1, /*cplx_thd_idx[6]*/ ++ 2, /*cplx_thd_idx[7]*/ ++ 2, /*cplx_thd_idx[8]*/ ++ 2, /*cplx_thd_idx[9]*/ ++ 2, /*cplx_thd_idx[10]*/ ++ 2, /*cplx_thd_idx[11]*/ ++ 2, /*cplx_thd_idx[12]*/ ++ 2, /*cplx_thd_idx[13]*/ ++ 2, /*cplx_thd_idx[14]*/ ++ 2, /*cplx_thd_idx[15]*/ ++ 2, /*cplx_thd_idx[16]*/ ++ 2, /*cplx_thd_idx[17]*/ ++ 2, /*cplx_thd_idx[18]*/ ++ 2, /*cplx_thd_idx[19]*/ ++ 3, /*cplx_thd_idx[20]*/ ++ 3, /*cplx_thd_idx[21]*/ ++ 3, /*cplx_thd_idx[22]*/ ++ 3, /*cplx_thd_idx[23]*/ ++ }, ++ ++ .cplx_thd = { ++ 0, /*cplx_thd[0]*/ ++ 5, /*cplx_thd[1]*/ ++ 10, /*cplx_thd[2]*/ ++ 15, /*cplx_thd[3]*/ ++ 0, /*cplx_thd[4]*/ ++ 0, /*cplx_thd[5]*/ ++ 0, /*cplx_thd[6]*/ ++ 0, /*cplx_thd[7]*/ ++ }, ++ ++ .diff_thd_base = { ++ 384, /*diff_thd_base[0]*/ ++ 96, /*diff_thd_base[1]*/ ++ 96, /*diff_thd_base[2]*/ ++ }, ++ ++ .diff_thd_ofst = { ++ 48, /*diff_thd_ofst[0]*/ ++ 12, /*diff_thd_ofst[1]*/ ++ 12, /*diff_thd_ofst[2]*/ ++ }, ++ .sas_eigen_en = 0, ++ .crp_eigen_en = 0, ++ .sas_eigen_dump = 0, ++ .crp_eigen_dump = 0, ++ .rrs_en = 0, ++ .rrs_dump_en = 1, ++ .rrs_uv_en = 0, ++ .rrs_size_y = 16, ++ .rrs_size_c = 8, ++ .rrs_thrd_y = 624, ++ .rrs_thrd_u = 156, ++ .rrs_thrd_v = 156, ++ .skin_dt_en = 0, ++ .skin_lvl = 0, ++ .skin_cnt_thd = 20, ++ .skin_pxlu_thd = { ++ {100, 130, }, ++ {40, 110, }, ++ {120, 160, }, ++ }, ++ .skin_pxlv_thd = { ++ {140, 175, }, ++ {120, 155, }, ++ {165, 225, }, ++ }, ++ .skin_qp_ofst = { ++ -8, /*skin_qp_ofst[0]*/ ++ -4, /*skin_qp_ofst[1]*/ ++ -2, /*skin_qp_ofst[2]*/ ++ 1, /*skin_qp_ofst[3]*/ ++ }, ++ .mult_factor = { ++ 3, /*mult_factor[0]*/ ++ 9, /*mult_factor[1]*/ ++ 5, /*mult_factor[2]*/ ++ }, ++ .shift_factor = { ++ {3, 5, 8, }, ++ {4, 5, 6, }, ++ {4, 5, 6, }, ++ }, ++ .skin_ofst = { ++ 97, /*skin_ofst[0]*/ ++ 183, /*skin_ofst[1]*/ ++ 271, /*skin_ofst[2]*/ ++ 884, /*skin_ofst[3]*/ ++ }, ++ .ncu_mov_en = 0, ++ .ncu_move_len = 0, ++ .ncu_move_info = NULL, ++ .buf_share_en = 0, ++ .buf_share_size = 0, ++ .frame_idx = 2, ++}; +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e.c +new file mode 100644 +index 000000000..3cb4aaf1d +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e.c +@@ -0,0 +1,1408 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* This program is free software; you can redistribute it and/or modify ++* it under the terms of the GNU General Public License version 2 as ++* published by the Free Software Foundation. ++* ++* This program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++*/ ++#include ++#include ++#include ++ ++#include "api/helix_x264_enc.h" ++ ++#include "h264enc/common.h" ++#include "h264enc/set.h" ++#include "h264e.h" ++#include "helix_drv.h" ++ ++ ++static uint8_t cqm_8iy_tab[64] = { ++ 6+10,10+10,13+10,16+10,18+10,23+10,25+10,27+10, ++ 10+10,11+10,16+10,18+10,23+10,25+10,27+10,29+10, ++ 13+10,16+10,18+10,23+10,25+10,27+10,29+10,31+10, ++ 16+10,18+10,23+10,25+10,27+10,29+10,31+10,33+10, ++ 18+10,23+10,25+10,27+10,29+10,31+10,33+10,36+10, ++ 23+10,25+10,27+10,29+10,31+10,33+10,36+10,38+10, ++ 25+10,27+10,29+10,31+10,33+10,36+10,38+10,40+10, ++ 27+10,29+10,31+10,33+10,36+10,38+10,40+10,42+10 ++}; ++static uint8_t cqm_8py_tab[64] = { ++ 9+10,13+10,15+10,17+10,19+10,21+10,22+10,24+10, ++ 13+10,13+10,17+10,19+10,21+10,22+10,24+10,25+10, ++ 15+10,17+10,19+10,21+10,22+10,24+10,25+10,27+10, ++ 17+10,19+10,21+10,22+10,24+10,25+10,27+10,28+10, ++ 19+10,21+10,22+10,24+10,25+10,27+10,28+10,30+10, ++ 21+10,22+10,24+10,25+10,27+10,28+10,30+10,32+10, ++ 22+10,24+10,25+10,27+10,28+10,30+10,32+10,33+10, ++ 24+10,25+10,27+10,28+10,30+10,32+10,33+10,35+10 ++}; ++ ++ ++/* static int rc_deadzone[9] = {0x1d,0x12,0x15,0xb,0x1d,0x12,0x1d,0x15,0xb}; */ ++static uint16_t rc_skin_ofst[4] = {97, 183, 271, 884};//[0]: 1.5, [1]:0.4, [2]:0.6, [3]: 5.1 ++static uint8_t rc_mult_factor[3] = {3,9,5}; ++//static int8_t rc_skin_qp_ofst[4] = {-3, -2, -1, 0}; ++static int8_t rc_skin_qp_ofst[4] = {-6, -4, -2, 0}; ++static uint8_t rc_skin_pxlu_thd[3][2] = {{100, 120},{50, 100},{120, 150}}; ++static uint8_t rc_skin_pxlv_thd[3][2] = {{140, 175},{125, 140},{175, 225}}; ++static uint8_t rc_shift_factor[3][3] = {{3,5,8},{4,5,6},{4,5,6}};//[0][]:0.4, [1][]:0.6, [2][]: 5.1 ++ ++ ++static unsigned add_sps_pps_iframe = 1; ++module_param(add_sps_pps_iframe, uint, S_IRUGO | S_IWUSR); ++ ++/*TODO: export to high level ????*/ ++int h264e_set_params(struct h264e_ctx *ctx, unsigned id, unsigned int val) ++{ ++ int ret = 0; ++ ++ ++ return ret; ++} ++ ++int h264e_get_params(struct h264e_ctx *ctx, int id) ++{ ++ unsigned int val = 0; ++ ++ return val; ++} ++ ++int h264e_set_fmt(struct h264e_ctx *ctx, int width, int height, int format) ++{ ++ struct h264e_params *p = &ctx->p; ++ int ret = 0; ++ ++ ++ p->width = width; ++ p->height = height; ++ switch(format) { ++ case HELIX_NV12_MODE: ++ case HELIX_NV21_MODE: ++ case HELIX_TILE_MODE: ++ case HELIX_420P_MODE: ++ p->format = format; ++ break; ++ default: ++ pr_err("Unsupported pix fmt: %x\n", format); ++ ret = -EINVAL; ++ break; ++ } ++ ++ ctx->framesize = width * height; ++ ++ return ret; ++} ++ ++//to profile_idc ++static int __maybe_unused v4l2_profile(int i_profile_idc) ++{ ++ switch (i_profile_idc) { ++ case PROFILE_BASELINE: return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; ++ case PROFILE_MAIN: return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; ++ case PROFILE_HIGH10: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10; ++ case PROFILE_HIGH422: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422; ++ case PROFILE_HIGH444_PREDICTIVE: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE; ++ default: return -EINVAL; ++ } ++ ++} ++ ++static int __maybe_unused h264e_profile_idc(int v4l2_profile) ++{ ++ switch (v4l2_profile) { ++ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: return PROFILE_BASELINE; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: return PROFILE_MAIN; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: return PROFILE_HIGH10; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: return PROFILE_HIGH422; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: return PROFILE_HIGH444_PREDICTIVE; ++ default: return -EINVAL; ++ } ++} ++ ++static int __maybe_unused v4l2_h264_level(int i_level_idc) ++{ ++ switch (i_level_idc) { ++ case 10: return V4L2_MPEG_VIDEO_H264_LEVEL_1_0; ++ case 9: return V4L2_MPEG_VIDEO_H264_LEVEL_1B; ++ case 11: return V4L2_MPEG_VIDEO_H264_LEVEL_1_1; ++ case 12: return V4L2_MPEG_VIDEO_H264_LEVEL_1_2; ++ case 13: return V4L2_MPEG_VIDEO_H264_LEVEL_1_3; ++ case 20: return V4L2_MPEG_VIDEO_H264_LEVEL_2_0; ++ case 21: return V4L2_MPEG_VIDEO_H264_LEVEL_2_1; ++ case 22: return V4L2_MPEG_VIDEO_H264_LEVEL_2_2; ++ case 30: return V4L2_MPEG_VIDEO_H264_LEVEL_3_0; ++ case 31: return V4L2_MPEG_VIDEO_H264_LEVEL_3_1; ++ case 32: return V4L2_MPEG_VIDEO_H264_LEVEL_3_2; ++ case 40: return V4L2_MPEG_VIDEO_H264_LEVEL_4_0; ++ case 41: return V4L2_MPEG_VIDEO_H264_LEVEL_4_1; ++ default: return -EINVAL; ++ } ++} ++ ++static int h264e_level_idc(int level) ++{ ++ switch (level) { ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: return 10; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1B: return 9; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: return 11; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: return 12; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: return 13; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: return 20; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: return 21; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: return 22; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: return 30; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: return 31; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: return 32; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: return 40; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: return 41; ++ default: return -EINVAL; ++ } ++} ++ ++/* ----------------------------- Picture Parameter Sets ---------------*/ ++static void h264e_sps_init(struct h264e_ctx *ctx, h264_sps_t *sps, int i_id) ++{ ++ struct h264e_params *p = &ctx->p; ++ int max_frame_num = 1; ++ ++ sps->i_id = i_id; ++ sps->i_mb_width = C_ALIGN(p->width, 16) / 16; ++ sps->i_mb_height = C_ALIGN(p->height, 16) / 16; ++ sps->i_chroma_format_idc = CHROMA_420; ++ sps->b_qpprime_y_zero_transform_bypass = 0; ++ sps->i_profile_idc = h264e_profile_idc(p->h264_profile); ++ sps->b_constraint_set0 = sps->i_profile_idc == PROFILE_BASELINE; ++ sps->b_constraint_set1 = sps->i_profile_idc <= PROFILE_MAIN; ++ sps->b_constraint_set2 = 0; ++ sps->b_constraint_set3 = 0; ++ ++ sps->i_level_idc = h264e_level_idc(p->h264_level); ++ if((sps->i_level_idc == 9) && (sps->i_profile_idc == PROFILE_BASELINE || sps->i_profile_idc == PROFILE_MAIN)) { ++ sps->b_constraint_set0 = 1; /* level 1b with Baseline or Main profile is signalled via constraint_set3 */ ++ sps->i_level_idc = 11; ++ } ++ ++ ++ sps->i_num_ref_frames = p->max_ref_pic; ++ sps->vui.i_num_reorder_frames = 0; ++ sps->vui.i_max_dec_frame_buffering = sps->i_num_ref_frames; ++ ++ sps->i_log2_max_frame_num = 4; ++ while((1 << sps->i_log2_max_frame_num) <= max_frame_num) ++ sps->i_log2_max_frame_num++; ++ ++ sps->i_poc_type = 2; ++ ++ if(sps->i_poc_type == 0) { ++ } ++ ++ sps->b_vui = 0; ++ ++ sps->b_gaps_in_frame_num_value_allowed = 0; ++ sps->b_frame_mbs_only = 1; ++ if(!sps->b_frame_mbs_only) ++ sps->i_mb_height = (sps->i_mb_height + 1) & ~1; ++ sps->b_mb_adaptive_frame_field = p->interlaced; ++ sps->b_direct8x8_inference = 1; ++ sps->b_crop = 0; ++ ++// h264_sps_init_reconfigurable(sps, sw); ++ ++ ++ sps->vui.b_overscan_info_present = 0; ++ sps->vui.b_overscan_info = 0; ++ ++ sps->i_cqm_preset = 0; ++ sps->b_avcintra = 0; ++ ++} ++ ++static void h264e_pps_init(struct h264e_ctx *ctx, h264_pps_t *pps, int i_id, h264_sps_t *sps) ++{ ++ struct h264e_params *p = &ctx->p; ++ ++ pps->i_id = i_id; ++ pps->i_sps_id = sps->i_id; ++ pps->b_cabac = p->i_cabac; ++ ++ pps->b_pic_order = 0; ++ pps->i_num_slice_groups = 1; /* base & main profile.*/ ++ ++ pps->i_num_ref_idx_l0_default_active = p->max_ref_pic; ++ pps->i_num_ref_idx_l1_default_active = 1; ++ ++ pps->b_weighted_pred = 0; ++ pps->b_weighted_bipred = 0; ++ ++ pps->i_pic_init_qp = 0; ++ pps->i_pic_init_qs = 26; ++ ++ pps->i_chroma_qp_index_offset = 0; ++ pps->b_deblocking_filter_control = 0; ++ pps->b_constrained_intra_pred = 0; ++ pps->b_redundant_pic_cnt = 0; ++ ++ pps->b_transform_8x8_mode = p->h264_8x8_transform; ++} ++ ++ ++static int encapsulate_nal(bs_t *s, int s_off, char *dst, int i_type, int i_ref_idc) ++{ ++ ++ uint8_t *src = s->p_start + s_off; ++ uint8_t *end = src + (bs_pos(s) / 8); ++ char *orig_dst = dst; ++ ++ /* prefix */ ++ *dst++ = 0x00; ++ *dst++ = 0x00; ++ *dst++ = 0x00; ++ *dst++ = 0x01; ++ ++ /* nal header */ ++ *dst++ = (0 << 7) | (i_ref_idc << 5) | (i_type); ++ ++ if(src < end) *dst++ = *src++; ++ if(src < end) *dst++ = *src++; ++ while( src < end ) ++ { ++ if( src[0] <= 0x03 && !src[-2] && !src[-1] ) { ++ *dst++ = 0x03; ++ } ++ *dst++ = *src++; ++ } ++ ++ return dst - orig_dst; ++} ++ ++/** ++* @h264e_generate_headers generate sps/pps headers according to params. ++* and store the header until encoder closed. ++* @ctx h264e_ctx. ++* ++* @Return 0 ++*/ ++int h264e_generate_headers(struct h264e_ctx *ctx) ++{ ++ /* used to encode header for tmp.*/ ++ char *bs_tmp = NULL; ++ char *bs_header = ctx->bs_header; ++ bs_t bs; ++ int bs_size = 0; ++ h264_sps_t *sps = NULL; ++ h264_pps_t *pps = NULL; ++ ++ bs_tmp = kzalloc(MAX_BS_HEADER_SIZE, GFP_KERNEL); ++ if(!bs_tmp) { ++ return -ENOMEM; ++ } ++ ++ sps = &ctx->sps; ++ pps = &ctx->pps; ++ ++ h264e_sps_init(ctx, sps, 0); ++ h264e_pps_init(ctx, pps, 0, sps); ++ ++ /* 1. encode sps */ ++ bs_init(&bs, bs_tmp, MAX_BS_HEADER_SIZE); ++ h264e_sps_write(&bs, sps); ++ ++ bs_size = encapsulate_nal(&bs, 0, bs_header, NAL_SPS, NAL_PRIORITY_HIGHEST); ++ ++ ctx->bs_header_size += bs_size; ++ bs_header += bs_size; ++ ++ /* 2. encode pps */ ++ bs_init(&bs, bs_tmp, MAX_BS_HEADER_SIZE); ++ h264e_pps_write(&bs, sps, pps); ++ ++ bs_size = encapsulate_nal(&bs, 0, bs_header, NAL_PPS, NAL_PRIORITY_HIGHEST); ++ ctx->bs_header_size += bs_size; ++ bs_header += bs_size; ++ ++ ++ if(ctx->bs_header_size > (MAX_BS_HEADER_SIZE - 512)) { ++ pr_warn("bs_header buffer almost overflow!\n"); ++ } ++ ++ /* 3. encode sei */ ++ ++ /* 4. encode more */ ++ ++ /* release temp buffer. */ ++ kfree(bs_tmp); ++ return 0; ++} ++ ++static int h264e_slice_init(struct h264e_ctx * ctx, int i_nal_type) ++{ ++ if(i_nal_type == NAL_SLICE_IDR) { ++ ++ h264e_slice_header_init(&ctx->sh, &ctx->sps, &ctx->pps, ctx->p.i_idr_pic_id, ctx->i_frame, ctx->p.i_qp); ++ ctx->p.i_idr_pic_id ^= 1; ++ } else { ++ h264e_slice_header_init(&ctx->sh, &ctx->sps, &ctx->pps, -1, ctx->i_frame, ctx->p.p_qp); ++ ++ ctx->sh.i_num_ref_idx_l0_active = 1; ++ ctx->sh.i_num_ref_idx_l1_active = 1; ++ } ++ ++ return 0; ++} ++ ++#if 0 ++void H264E_DumpInfo(_H264E_SliceInfo *s) ++{ ++ printk(" emc_qpt_va : %p\n",s->emc_qpt_va); ++ printk(" emc_rc_va : %p\n",s->emc_rc_va); ++ printk(" emc_cpx_va : %p\n",s->emc_cpx_va); ++ printk(" emc_mod_va : %p\n",s->emc_mod_va); ++ printk(" emc_ncu_va : %p\n",s->emc_ncu_va); ++ printk(" emc_sad_va : %p\n",s->emc_sad_va); ++ printk(" mb_mode_info : %p\n",s->mb_mode_info); ++ ++ printk("s->des_va = 0x%08x\n", (unsigned int)s->des_va); ++ printk("s->des_pa = 0x%08x\n", (unsigned int)s->des_pa); ++ // printk("s->emc_bs_va = 0x%08x\n", s->emc_bs_va); ++ printk("s->emc_bs_pa = 0x%08x\n", s->emc_bs_pa); ++ ++ /*x2000 add*/ ++ printk(" bs_head_en = %d\n", s->bs_head_en); ++ printk(" bs_head_va = 0x%08x\n", (unsigned int)s->bs_head_va); ++ printk(" bs_head_len = 0x%d\n", (unsigned int)s->bs_head_len); ++ printk(" bs_rbsp_en = %d\n", s->bs_rbsp_en); ++ ++ printk(" stride[0] = %d\n", s->stride[0]); ++ printk(" stride[1] = %d\n", s->stride[1]); ++ printk(" state = 0x%08x\n", (unsigned int)s->state); ++ printk(" raw[0] = 0x%08x\n", s->raw[0]); ++ printk(" raw[1] = 0x%08x\n", s->raw[1]); ++ printk(" raw[2] = 0x%08x\n", s->raw[2]); ++ printk(" fb[0][0] = 0x%08x\n", s->fb[0][0]); ++ printk(" fb[0][1] = 0x%08x\n", s->fb[0][1]); ++ printk(" fb[1][0] = 0x%08x\n", s->fb[1][0]); ++ printk(" fb[1][1] = 0x%08x\n", s->fb[1][1]); ++ printk(" fb[2][0] = 0x%08x\n", s->fb[2][0]); ++ printk(" fb[2][1] = 0x%08x\n", s->fb[2][1]); ++ printk(" jh[0][0] = 0x%08x\n", s->jh[0][0]); ++ printk(" jh[0][1] = 0x%08x\n", s->jh[0][1]); ++ printk(" jh[1][0] = 0x%08x\n", s->jh[1][0]); ++ printk(" jh[1][1] = 0x%08x\n", s->jh[1][1]); ++ printk(" jh[2][0] = 0x%08x\n", s->jh[2][0]); ++ printk(" jh[2][1] = 0x%08x\n", s->jh[2][1]); ++ printk(" spe_y_addr = 0x%08x\n", s->spe_y_addr); ++ printk(" spe_c_addr = 0x%08x\n", s->spe_c_addr); ++ printk(" emc_recon_pa= 0x%08x\n", s->emc_recon_pa); ++ printk(" emc_qpt_pa = 0x%08x\n", s->emc_qpt_pa); ++ printk(" emc_mv_pa = 0x%08x\n", s->emc_mv_pa); ++ printk(" emc_se_pa = 0x%08x\n", s->emc_se_pa); ++ printk(" emc_rc_pa = 0x%08x\n", s->emc_rc_pa); ++ printk(" emc_cpx_pa = 0x%08x\n", s->emc_cpx_pa); ++ printk(" emc_mod_pa = 0x%08x\n", s->emc_mod_pa); ++ printk(" emc_ncu_pa = 0x%08x\n", s->emc_ncu_pa); ++ printk(" emc_sad_pa = 0x%08x\n", s->emc_sad_pa); ++ /* 1. rc output [11]*/ ++ { ++ printk(" frame_type : %d\n",s->frame_type); ++ printk(" mb_width : %d\n",s->mb_width); ++ printk(" mb_height : %d\n",s->mb_height); ++ printk(" frame_width : %d\n",s->frame_width); ++ printk(" frame_height : %d\n",s->frame_height); ++ printk(" first_mby : %d\n",s->first_mby); ++ printk(" last_mby : %d\n",s->last_mby); ++ printk(" qp : %d\n",s->qp); ++ printk(" base_qp : %d\n",s->base_qp); ++ printk(" max_qp : %d\n",s->max_qp); ++ printk(" min_qp : %d\n",s->min_qp); ++ } ++ /* 2. motion cfg [25]*/ ++ { ++ printk(" frm_re[0] : %d\n",s->frm_re[0]); ++ printk(" frm_re[1] : %d\n",s->frm_re[1]); ++ printk(" frm_re[2] : %d\n",s->frm_re[2]); ++ printk(" frm_re[3] : %d\n",s->frm_re[3]); ++ printk(" pskip_en : %d\n",s->pskip_en); ++ printk(" mref_en : %d\n",s->mref_en); ++ printk(" scl : %d\n",s->scl); ++ printk(" hpel_en : %d\n",s->hpel_en); ++ printk(" qpel_en : %d\n",s->qpel_en); ++ printk(" ref_mode : %d\n",s->ref_mode); ++ printk(" max_sech_step_i : %d\n",s->max_sech_step_i); ++ printk(" max_mvrx_i : %d\n",s->max_mvrx_i); ++ printk(" max_mvry_i : %d\n",s->max_mvry_i); ++ printk(" lambda_scale_parameter : %d\n",s->lambda_scale_parameter); ++ printk(" fs_en : %d\n",s->fs_en); ++ printk(" fs_md : %d\n",s->fs_md); ++ printk(" fs_px : %d\n",s->fs_px); ++ printk(" fs_py : %d\n",s->fs_py); ++ printk(" fs_rx : %d\n",s->fs_rx); ++ printk(" fs_ry : %d\n",s->fs_ry); ++ printk(" frm_mv_en : %d\n",s->frm_mv_en); ++ printk(" frm_mv_size : %d\n",s->frm_mv_size); ++ printk(" glb_mv_en : %d\n",s->glb_mv_en); ++ printk(" glb_mvx : %d\n",s->glb_mvx); ++ printk(" glb_mvy : %d\n",s->glb_mvy); ++ printk(" me_step_en : %d\n",s->me_step_en); ++ printk(" me_step_0 : %d\n",s->me_step_0); ++ printk(" me_step_1 : %d\n",s->me_step_1); ++ } ++ /* 3. quant cfg [4]*/ ++ { ++ int i=0,j=0; ++ printk(" dct8x8_en : %d\n",s->dct8x8_en); ++ for (i=0;i<4;i++) ++ for (j=0;j<16;j++) ++ printk(" scaling_list[%d][%d] : %d\n",i,j,s->scaling_list[i][j]); ++ for (i=0;i<2;i++) ++ for (j=0;j<64;j++) ++ printk(" scaling_list8[%d][%d] : %d\n",i,j,s->scaling_list8[i][j]); ++ for (i=0;i<9;i++) ++ printk(" deadzone[%d] : %d\n",i,s->deadzone[i]); ++ } ++ ++ /* 4. loop filter cfg [4]*/ ++ { ++ printk(" deblock : %d\n",s->deblock); ++ printk(" rotate : %d\n",s->rotate); ++ printk(" alpha_c0_offset : %d\n",s->alpha_c0_offset); ++ printk(" beta_offset : %d\n",s->beta_offset); ++ } ++ /* 5. do not douch, default value [56]*/ ++ { ++ printk(" acmask_mode : %d\n",s->acmask_mode); ++ printk(" intra_mode_msk : %d\n",s->intra_mode_msk); ++ printk(" i_4x4_dis : %d\n",s->i_4x4_dis); ++ printk(" i_8x8_dis : %d\n",s->i_8x8_dis); ++ printk(" i_16x16_dis : %d\n",s->i_16x16_dis); ++ printk(" p_l0_dis : %d\n",s->p_l0_dis); ++ printk(" p_t8_dis : %d\n",s->p_t8_dis); ++ printk(" p_skip_dis : %d\n",s->p_skip_dis); ++ printk(" p_skip_pl0f_dis : %d\n",s->p_skip_pl0f_dis); ++ printk(" p_skip_pt8f_dis : %d\n",s->p_skip_pt8f_dis); ++ ++ printk(" cost_bias_en : %d\n",s->cost_bias_en); ++ printk(" cost_bias_i_4x4 : %d\n",s->cost_bias_i_4x4); ++ printk(" cost_bias_i_8x8 : %d\n",s->cost_bias_i_8x8); ++ printk(" cost_bias_i_16x16 : %d\n",s->cost_bias_i_16x16); ++ printk(" cost_bias_p_l0 : %d\n",s->cost_bias_p_l0); ++ printk(" cost_bias_p_t8 : %d\n",s->cost_bias_p_t8); ++ printk(" cost_bias_p_skip : %d\n",s->cost_bias_p_skip); ++ ++ printk(" intra_lambda_y_bias_en : %d\n",s->intra_lambda_y_bias_en); ++ printk(" intra_lambda_c_bias_en : %d\n",s->intra_lambda_c_bias_en); ++ printk(" intra_lambda_bias_qp0 : %d\n",s->intra_lambda_bias_qp0); ++ printk(" intra_lambda_bias_qp1 : %d\n",s->intra_lambda_bias_qp1); ++ printk(" intra_lambda_bias_0 : %d\n",s->intra_lambda_bias_0); ++ printk(" intra_lambda_bias_1 : %d\n",s->intra_lambda_bias_1); ++ printk(" intra_lambda_bias_2 : %d\n",s->intra_lambda_bias_2); ++ ++ printk(" chroma_sse_bias_en : %d\n",s->chroma_sse_bias_en); ++ printk(" chroma_sse_bias_qp0 : %d\n",s->chroma_sse_bias_qp0); ++ printk(" chroma_sse_bias_qp1 : %d\n",s->chroma_sse_bias_qp1); ++ printk(" chroma_sse_bias_0 : %d\n",s->chroma_sse_bias_0); ++ printk(" chroma_sse_bias_1 : %d\n",s->chroma_sse_bias_1); ++ printk(" chroma_sse_bias_2 : %d\n",s->chroma_sse_bias_2); ++ ++ printk(" sse_lambda_bias_en : %d\n",s->sse_lambda_bias_en); ++ printk(" sse_lambda_bias : %d\n",s->sse_lambda_bias); ++ printk(" fbc_ep : %d\n",s->fbc_ep); ++ printk(" jm_lambda2_en : %d\n",s->jm_lambda2_en); ++ printk(" inter_nei_en : %d\n",s->inter_nei_en); ++ printk(" skip_bias_en : %d\n",s->skip_bias_en); ++ ++ printk(" ysse_thr : %d\n",s->ysse_thr); ++ printk(" csse_thr : %d\n",s->csse_thr); ++ printk(" dcm_en : %d\n",s->dcm_en); ++ printk(" dcm_param : %d\n",s->dcm_param); ++ printk(" sde_prior : %d\n",s->sde_prior); ++ printk(" db_prior : %d\n",s->db_prior); ++ ++ printk(" use_intra_in_pframe : %d\n",s->use_intra_in_pframe); ++ printk(" use_fast_mvp : %d\n",s->use_fast_mvp); ++ printk(" skip_en : %d\n",s->skip_en); ++ printk(" cqp_offset : %d\n",s->cqp_offset); ++ ++ printk(" daisy_chain_en : %d\n",s->daisy_chain_en); ++ printk(" curr_thread_id : %d\n",s->curr_thread_id); ++ printk(" qp_tab_mode : %d\n",s->qp_tab_mode); ++ printk(" bs_size_en : %d\n",s-> bs_size_en); ++ printk(" bs_size : %d\n",s->bs_size); ++ printk(" raw_format : %d\n",s->raw_format); ++ ++ printk(" size_mode : %d\n",s->size_mode); ++ printk(" step_mode : %d\n",s->step_mode); ++ printk(" mode_ctrl : %d\n",s->mode_ctrl); ++ int i=0; ++ for (i=0;i<40;i++) ++ printk("mode_ctrl_param[%d] : %d\n",i,s->mode_ctrl_param[i]); ++ ++ } ++ /* 6. select hardware output mode [11]*/ ++ { ++ printk(" info_en : %d\n",s->info_en); ++ printk(" mvd_sum_all : %d\n",s->mvd_sum_all); ++ printk(" mvd_sum_abs : %d\n",s->mvd_sum_abs); ++ printk(" mv_sum_all : %d\n",s->mv_sum_all); ++ printk(" mv_sum_abs : %d\n",s->mv_sum_abs); ++ ++ ++ printk(" cfg_size_x : %d\n",s->cfg_size_x); ++ printk(" cfg_size_y : %d\n",s->cfg_size_y); ++ printk(" cfg_iw_thr : %d\n",s->cfg_iw_thr); ++ ++ printk(" cfg_mvr_thr1 : %d\n",s->cfg_mvr_thr1); ++ printk(" cfg_mvr_thr2 : %d\n",s->cfg_mvr_thr2); ++ printk(" cfg_mvr_thr3 : %d\n",s->cfg_mvr_thr3); ++ } ++ /* 7. ipred bit&lambda ctrl [33]*/ ++ { ++ printk(" mb_mode_val : %d\n",s->mb_mode_val); ++ printk(" bit_16_en : %d\n",s->bit_16_en); ++ printk(" bit_8_en : %d\n",s->bit_8_en); ++ printk(" bit_4_en : %d\n",s->bit_4_en); ++ printk(" bit_uv_en : %d\n",s->bit_uv_en); ++ printk(" lamb_16_en : %d\n",s->lamb_16_en); ++ printk(" lamb_8_en : %d\n",s->lamb_8_en); ++ printk(" lamb_4_en : %d\n",s->lamb_4_en); ++ printk(" lamb_uv_en : %d\n",s->lamb_uv_en); ++ printk(" lamb_uv_en : %d\n",s->c_16_en); ++ printk(" c_8_en : %d\n",s->c_8_en); ++ printk(" c_4_en : %d\n",s->c_4_en); ++ printk(" c_uv_en : %d\n",s->c_uv_en); ++ printk(" pri_16 : %d\n",s->pri_16); ++ printk(" pri_8 : %d\n",s->pri_8); ++ printk(" pri_4 : %d\n",s->pri_4); ++ printk(" pri_uv : %d\n",s->pri_uv); ++ printk(" ref_neb_4 : %d\n",s->ref_neb_4); ++ printk(" ref_neb_8 : %d\n",s->ref_neb_8); ++ printk(" lambda_info16 : %d\n",s->lambda_info16); ++ printk(" lambda_info8 : %d\n",s->lambda_info8); ++ printk(" lambda_info4 : %d\n",s->lambda_info4); ++ printk(" lambda_infouv : %d\n",s->lambda_infouv); ++ printk(" ref_4 : %d\n",s->ref_4); ++ printk(" ref_8 : %d\n",s->ref_8); ++ ++ int i=0; ++ for (i=0;i<4;i++) ++ printk(" bit_16[%d] : %d\n",i,s->bit_16[i]); ++ for (i=0;i<4;i++) ++ printk(" bit_uv[%d] : %d\n",i,s->bit_uv[i]); ++ for (i=0;i<4;i++) ++ printk(" bit_4[%d] : %d\n",i,s->bit_4[i]); ++ for (i=0;i<4;i++) ++ printk(" bit_8[%d] : %d\n",i,s->bit_8[i]); ++ for (i=0;i<4;i++) ++ printk(" const_16[%d] : %d\n",i,s->const_16[i]); ++ for (i=0;i<4;i++) ++ printk(" const_uv[%d] : %d\n",i,s->const_uv[i]); ++ for (i=0;i<4;i++) ++ printk(" const_4[%d] : %d\n",i,s->const_4[i]); ++ for (i=0;i<4;i++) ++ printk(" const_8[%d] : %d\n",i,s->const_8[i]); ++ } ++ /* 9. jrfc,jrfd [5]*/ ++ { ++ printk(" jrfcd_flag : %d\n",s->jrfcd_flag); ++ printk(" jrfc_enable : %d\n",s->jrfc_enable); ++ printk(" jrfd_enable : %d\n",s->jrfd_enable); ++ printk(" lm_head_total : %d\n",s->lm_head_total); ++ printk(" cm_head_total : %d\n",s->cm_head_total); ++ } ++ /* 10. eigen cfg for mosaic, color error [42]*/ ++ { ++ printk(" mb_mode_use : %d\n",s->mb_mode_use); ++ printk(" force_i16dc : %d\n",s->force_i16dc);//ipred ++ printk(" force_i16 : %d\n",s->force_i16); ++ printk(" refresh_en : %d\n",s->refresh_en); ++ printk(" refresh_mode : %d\n",s->refresh_mode); ++ printk(" refresh_bias : %d\n",s->refresh_bias); ++ printk(" refresh_cplx_thd : %d\n",s->refresh_cplx_thd); ++ printk(" cplx_thd_sel : %d\n",s->cplx_thd_sel); ++ printk(" diff_cplx_sel : %d\n",s->diff_cplx_sel); ++ printk(" diff_thd_sel : %d\n",s->diff_thd_sel); ++ printk(" i16dc_cplx_thd : %d\n",s->i16dc_cplx_thd); ++ printk(" i16dc_qp_base : %d\n",s->i16dc_qp_base); ++ printk(" i16dc_qp_sel : %d\n",s->i16dc_qp_sel); ++ printk(" i16_qp_base : %d\n",s->i16_qp_base); ++ printk(" i16_qp_sel : %d\n",s->i16_qp_sel); ++ printk(" diff_cplx_thd : %d\n",s->diff_cplx_thd); ++ ++ int i=0; ++ for (i=0;i<2;i++) ++ printk(" diff_qp_base[%d] : %d\n",i,s->diff_qp_base[i]); ++ for (i=0;i<2;i++) ++ printk(" diff_qp_sel[%d] : %d\n",i,s->diff_qp_sel[i]); ++ for (i=0;i<24;i++) ++ printk(" cplx_thd_idx[%d] : %d\n",i,s->cplx_thd_idx[i]); ++ for (i=0;i<8;i++) ++ printk(" cplx_thd[%d] : %d\n",i,s->cplx_thd[i]); ++ for (i=0;i<3;i++) ++ printk(" diff_thd_base[%d] : %d\n",i,s->diff_thd_base[i]); ++ for (i=0;i<3;i++) ++ printk(" diff_thd_ofst[%d] : %d\n",i,s->diff_thd_ofst[i]); ++ printk(" sas_eigen_en : %d\n",s->sas_eigen_en); ++ printk(" crp_eigen_en : %d\n",s->crp_eigen_en); ++ printk(" sas_eigen_dump : %d\n",s->sas_eigen_dump); ++ printk(" crp_eigen_dump : %d\n",s->crp_eigen_dump); ++ printk(" rrs_en : %d\n",s->rrs_en); ++ printk(" rrs_dump_en : %d\n",s->rrs_dump_en); ++ printk(" rrs_uv_en : %d\n",s->rrs_uv_en); ++ printk(" rrs_size_y : %d\n",s->rrs_size_y); ++ printk(" rrs_size_c : %d\n",s->rrs_size_c); ++ printk(" rrs_thrd_y : %d\n",s->rrs_thrd_y); ++ printk(" rrs_thrd_u : %d\n",s->rrs_thrd_u); ++ printk(" rrs_thrd_v : %d\n",s->rrs_thrd_v); ++ } ++ /* 11. skin judge cfg [14]*/ ++ { ++ printk(" skin_dt_en : %d\n",s->skin_dt_en); ++ printk(" skin_lvl : %d\n",s->skin_lvl); ++ printk(" skin_cnt_thd : %d\n",s->skin_cnt_thd); ++ printk(" ncu_mov_en : %d\n",s->ncu_mov_en); ++ printk(" ncu_move_len : %d\n",s->ncu_move_len); ++ if (s->ncu_move_info == NULL) ++ printk(" ncu_move_info is NULL \n"); ++ else ++ printk(" ncu_move_info : %p\n",s->ncu_move_info); ++ printk(" buf_share_en : %d\n",s->buf_share_en); ++ printk(" buf_share_size : %d\n",s->buf_share_size); ++ printk(" frame_idx : %d\n",s->frame_idx); ++ printk(" is_first_Pframe : %d\n",s->is_first_Pframe); ++ int i=0,j=0; ++ for (i=0;i<3;i++) ++ for (j=0;j<2;j++) ++ printk(" skin_pxlu_thd[%d][%d] : %d\n",i,j,s->skin_pxlu_thd[i][j]); ++ for (i=0;i<3;i++) ++ for (j=0;j<2;j++) ++ printk(" skin_pxlv_thd[%d][%d] : %d\n",i,j,s->skin_pxlv_thd[i][j]); ++ for (i=0;i<4;i++) ++ printk(" skin_qp_ofst[%d] : %d\n",i,s->skin_qp_ofst[i]); ++ for (i=0;i<3;i++) ++ printk(" mult_factor[%d] : %d\n",i,s->mult_factor[i]); ++ for (i=0;i<3;i++) ++ for (j=0;j<3;j++) ++ printk(" shift_factor[%d][%d] : %d\n",i,j,s->shift_factor[i][j]); ++ for (i=0;i<4;i++) ++ printk(" skin_ofst[%d] : %d\n",i,s->skin_ofst[i]); ++ } ++ /* 12.qpg */ ++ { ++ /* qp map */ ++ printk(" qp_tab_en : %d\n",s->qp_tab_en); ++ printk(" qp_tab_len : %d\n",s->qp_tab_len); ++ if (s->qp_tab == NULL) ++ printk(" qp_tab is NULL"); ++ else ++ printk(" qp_tab : %p\n", s->qp_tab); ++ int i=0; ++ for (i=0;i<8;i++) { ++ printk("roi_en[%d] : %d\n",i,s->roi_info[i].roi_en); ++ printk("roi_md[%d] : %d\n",i,s->roi_info[i].roi_md); ++ printk("roi_qp[%d] : %d\n",i,s->roi_info[i].roi_qp); ++ printk("roi_lmbx[%d] : %d\n",i,s->roi_info[i].roi_lmbx); ++ printk("roi_rmbx[%d] : %d\n",i,s->roi_info[i].roi_rmbx); ++ printk("roi_umby[%d] : %d\n",i,s->roi_info[i].roi_umby); ++ printk("roi_bmby[%d] : %d\n",i,s->roi_info[i].roi_bmby); ++ } ++ /* qp cplx */ ++ printk(" sas_en : %d\n",s->sas_en); ++ printk(" crp_en : %d\n",s->crp_en); ++ printk(" sas_mthd : %d\n",s->sas_mthd); ++ for (i=0;i<7;i++) ++ printk(" qpg_mb_thd[%d] : %d\n", i,s->qpg_mb_thd[i]); ++ for (i=0;i<8;i++) ++ printk(" qpg_mbqp_ofst[%d] : %d\n", i,s->qpg_mbqp_ofst[i]); ++ for (i=0;i<5;i++) ++ printk(" qpg_flt_thd[%d] : %d\n", i,s->qpg_flt_thd[i]); ++ printk(" mbrc_qpg_sel : %d\n",s->mbrc_qpg_sel); ++ /* bu rc */ ++ printk(" rc_mb_en : %d\n",s->rc_mb_en); ++ printk(" rc_bu_wait_en : %d\n",s->rc_bu_wait_en); ++ printk(" rc_mb_wait_en : %d\n",s->rc_mb_wait_en); ++ printk(" rc_bu_num : %d\n",s->rc_bu_num); ++ printk(" rc_bu_size : %d\n",s->rc_bu_size); ++ printk(" rc_bu_level : %d\n",s->rc_bu_level); ++ printk(" rc_mb_level : %d\n",s->rc_mb_level); ++ if (s->mb_ref_info == NULL) ++ printk(" mb_ref_info is NULL"); ++ else ++ printk(" mb_ref_info : %p\n", s->mb_ref_info); ++ if (s->bu_ref_info == NULL) ++ printk(" bu_ref_info is NULL"); ++ else ++ printk(" bu_ref_info : %p\n", s->bu_ref_info); ++ printk(" rc_frm_tbs : %d\n",s->rc_frm_tbs); ++ printk(" avg_bu_bs : %d\n",s->avg_bu_bs); ++ for (i=0;i<6;i++) ++ printk(" tar_bs_thd[%d] : %d\n",s->tar_bs_thd[i]); ++ for (i=0;i<6;i++) ++ printk(" tar_bs_thd[%d] : %d\n",s->bu_alg0_qpo[i]); ++ for (i=0;i<6;i++) ++ printk(" bu_alg1_qpo[%d] : %d\n",s->bu_alg1_qpo[i]); ++ for (i=0;i<7;i++) ++ printk(" mb_cs_qpo[%d] : %d\n",s->mb_cs_qpo[i]); ++ for (i=0;i<2;i++) ++ printk(" mb_top_bs_qpo[%d] : %d\n",s->mb_top_bs_qpo[i]); ++ for (i=0;i<2;i++) ++ printk(" mb_rinfo_qpo[%d] : %d\n",s->mb_rinfo_qpo[i]); ++ for (i=0;i<2;i++) ++ printk(" mb_target_avg_bs[%d] : %d\n",s->mb_target_avg_bs[i]); ++ printk(" mb_gp_num : %d\n",s->mb_gp_num); ++ printk(" last_bu_size : %d\n",s->last_bu_size); ++ printk(" rc_bcfg_mode : %d\n",s->rc_bcfg_mode); ++ } ++ ++} ++#endif ++ ++ ++static int h264e_fill_slice_info(struct h264e_ctx *ctx, unsigned int sh_size_in_bits) ++{ ++ int i = 0; ++ int ret = 0; ++ unsigned char bmap[3][3] = { ++ {0, 2, 1}, ++ {1, 0, 2}, ++ {2, 1, 0} ++ }; ++ ++ unsigned char *bufidx = bmap[ctx->i_frame % 3]; ++ H264E_SliceInfo_t *s = ctx->s; ++ ++ ++ h264_sps_t *sps = &ctx->sps; ++ h264_pps_t *pps = &ctx->pps; ++ ++ /* 1. rc output [11] */ ++ { ++ s->mb_width = sps->i_mb_width; ++ s->mb_height = sps->i_mb_height; ++ ++ s->frame_type = ctx->sh.i_type == M_SLICE_TYPE_I ? 0:1; ++ s->first_mby = 0; ++ s->last_mby = s->mb_height - 1; ++ s->frame_width = ctx->p.width; ++ s->frame_height = ctx->p.height; ++ s->qp = ctx->sh.i_type == M_SLICE_TYPE_I ? ctx->p.i_qp : ctx->p.p_qp; ++ s->base_qp = s->qp; ++ s->max_qp = ctx->p.h264_max_qp; ++ s->min_qp = ctx->p.h264_min_qp; ++ ++ ++ s->bs_head_en = 1; /*X2000 new add, fix value*/ ++ s->bs_head_va = (paddr_t *)ctx->slice_header; ++ s->bs_head_len = (sh_size_in_bits + 7) / 8; ++ s->bs_rbsp_en = 1; ++ } ++ ++ /*2. motion cfg [25]*/ ++ { ++ s->frm_re[0] = 0;/*sipe->frm_re0A;*/ ++ s->frm_re[1] = 0;/*sipe->frm_re1A;*/ ++ s->frm_re[2] = 0;/*sipe->frm_re2A;*/ ++ s->frm_re[3] = 0;/*sipe->frm_re3A;*/ ++ ++ s->pskip_en = 1; ++ s->mref_en = 0; ++ s->scl = 3;/*sipe->scl;*/ ++ s->hpel_en = 1;/*sipe->hpel_en;*/ ++ s->qpel_en = 1;/*sipe->qpel_en;*/ ++ s->ref_mode = 1; ++ s->max_sech_step_i = 63;/*sipe->max_sech_step_i;*/ ++ s->max_mvrx_i = 255;/*sipe->max_mvrx_i;*/ //FixMe, for the buf_share_size is 3 when bufshare function opened ++ s->max_mvry_i = 255;/*sipe->max_mvry_i;*/ //FixMe, for the buf_share_size is 3 when bufshare function opened ++ s->lambda_scale_parameter = 8; ++ ++ if(s->mb_width > 50 && s->mb_height > 38) { ++ s->fs_en = 1;/*sipe->fs_en;*/ ++ s->fs_md = 0;/*sipe->fs_md;*/ ++ s->fs_px = 3;/*sipe->fs_px;*/ ++ s->fs_py = 3;/*sipe->fs_py;*/ ++ s->fs_rx = 8;/*sipe->fs_rx;*/ ++ s->fs_ry = 8;/*sipe->fs_ry;*/ ++ } else { ++ s->fs_en = 0;/*sipe->fs_en;*/ ++ s->fs_md = 0;/*sipe->fs_md;*/ ++ s->fs_px = 0;/*sipe->fs_px;*/ ++ s->fs_py = 0;/*sipe->fs_py;*/ ++ s->fs_rx = 0;/*sipe->fs_rx;*/ ++ s->fs_ry = 0;/*sipe->fs_ry;*/ ++ } ++ ++ s->frm_mv_en = 1;/*sipe->frm_mv_en;*/ ++ s->frm_mv_size = 3;/*sipe->frm_mv_size;*/ ++ s->glb_mv_en = 1;/*sipe->glb_mv_en;*/ ++#if 0 ++ if((frm->mvCnt & 0xffff) == 0 || ((frm->mvCnt >> 16) & 0xffff) == 0) { ++ s->glb_mvx = 0; ++ s->glb_mvy = 0; ++ } else { ++ s->glb_mvx = frm->mvxSum / (frm->mvCnt & 0xffff); ++ s->glb_mvy = frm->mvySum / ((frm->mvCnt >> 16) & 0xffff); ++ } ++#endif ++ s->me_step_en = 1; /*sipe->me_step_en;*/ ++ s->me_step_0 = 8; /*sipe->me_step_0;*/ ++ s->me_step_1 = 10;/*sipe->me_step_1;*/ ++ } ++ ++ /*3. quant cfg [4]*/ ++ { ++ s->dct8x8_en = 0; ++ memset(s->scaling_list, 0x10, sizeof(s->scaling_list)); ++ memcpy(s->scaling_list8[0], cqm_8iy_tab, sizeof(uint8_t) * 64); ++ memcpy(s->scaling_list8[1], cqm_8py_tab, sizeof(uint8_t) * 64); ++ ++ s->deadzone[0] = 0x15; ++ s->deadzone[1] = 0x0b; ++ s->deadzone[2] = 0x15; ++ s->deadzone[3] = 0x0b; ++ s->deadzone[4] = 0x15; ++ s->deadzone[5] = 0x0b; ++ s->deadzone[6] = 0x15; ++ s->deadzone[7] = 0x15; ++ s->deadzone[8] = 0x0b; ++ } ++ ++ /*4.loop filter cfg [4] */ ++ { ++ s->deblock = ctx->p.deblock; ++ s->rotate = 0; ++ s->alpha_c0_offset = 0; ++ s->beta_offset = 0; ++ } ++ ++ /*5.*/ ++ { ++ s->acmask_mode = 0x3fffe; /*sipe->acmask_mode;*/ ++ s->intra_mode_msk = 0; ++ s->i_4x4_dis = 0; ++ s->i_8x8_dis = 0; ++ s->i_16x16_dis = 0; ++ s->p_l0_dis = 0; ++ s->p_t8_dis = 0; ++ s->p_skip_dis = 0; ++ s->p_skip_pl0f_dis = 0; ++ s->p_skip_pt8f_dis = 0; ++ ++ s->cost_bias_en = 0; ++ s->cost_bias_i_4x4 = 0; ++ s->cost_bias_i_8x8 = 0; ++ s->cost_bias_i_16x16 = 0; ++ s->cost_bias_p_l0 = 0; ++ s->cost_bias_p_t8 = 0; ++ s->cost_bias_p_skip = 0; ++ ++ s->intra_lambda_y_bias_en = 0; ++ s->intra_lambda_c_bias_en = 0; ++ s->intra_lambda_bias_qp0 = 0; ++ s->intra_lambda_bias_qp1 = 0; ++ s->intra_lambda_bias_0 = 0; ++ s->intra_lambda_bias_1 = 0; ++ s->intra_lambda_bias_2 = 0; ++ ++ s->chroma_sse_bias_en = 0; ++ s->chroma_sse_bias_qp0 = 0; ++ s->chroma_sse_bias_qp1 = 0; ++ s->chroma_sse_bias_0 = 0; ++ s->chroma_sse_bias_1 = 0; ++ s->chroma_sse_bias_2 = 0; ++ ++ s->sse_lambda_bias_en = 0; ++ s->sse_lambda_bias = 0; ++ s->fbc_ep = 204; ++ s->jm_lambda2_en = 0; /*sipe->jm_lambda2_en;*/ ++ s->inter_nei_en = 0; /*sipe->inter_nei_en;*/ ++ s->skip_bias_en = 0; /*sipe->skip_bias_en;*/ ++ s->ysse_thr = 0; ++ s->csse_thr = 0; ++ s->dcm_en = 0; /*sipe->dcm_en;*/ ++ s->dcm_param = 0x4304; /*sipe->dcm_param;*/ ++ s->sde_prior = 5; ++ s->db_prior = 5; ++ ++ s->use_intra_in_pframe = 1;/*sipe->use_intra_in_pframe;*/ ++ s->use_fast_mvp = 1; ++ ++ s->skip_en = 1; ++ s->cqp_offset = 0;/*sipe->cqp_offset;*/ ++ ++ s->daisy_chain_en = 0; ++ s->curr_thread_id = 0; ++ s->qp_tab_mode = 0; ++ ++ s->bs_size_en = 1; ++ s->bs_size = 1024; ++ s->raw_format = 8; ++ s->size_mode = 0; ++ s->step_mode = 0; ++ s->mode_ctrl = 0; ++ ++ memset(s->mode_ctrl_param, 0, sizeof(s->mode_ctrl_param)); ++ ++ } ++ ++ /* 6. select hardware output mode [11]*/ ++ { ++ s->info_en = 1; ++ s->mvd_sum_all = 0; ++ s->mvd_sum_abs = 0; ++ s->mv_sum_all = 1; ++ s->mv_sum_abs = 1; ++ ++ s->cfg_size_x = 1; ++ s->cfg_size_y = 1; ++ s->cfg_iw_thr = 0; ++ ++ s->cfg_mvr_thr1 = 0; ++ s->cfg_mvr_thr2 = 0; ++ s->cfg_mvr_thr3 = 0; ++ } ++ ++ /* 7. ipred bit&lambda ctrl [33]*/ ++ { ++ s->mb_mode_val = 1; ++ s->bit_16_en = 0; ++ s->bit_8_en = 1; ++ s->bit_4_en = 1; ++ s->bit_uv_en = 0; ++ s->lamb_16_en = 0; ++ s->lamb_8_en = 0; ++ s->lamb_4_en = 0; ++ s->lamb_uv_en = 0; ++ s->c_16_en = 0; ++ s->c_8_en = 0; ++ s->c_4_en = 0; ++ s->c_uv_en = 0; ++ s->pri_16 = 0; ++ s->pri_8 = 0; ++ s->pri_4 = 0; ++ s->pri_uv = 0; ++ s->ref_neb_4 = 1; ++ s->ref_neb_8 = 1; ++ s->lambda_info16 = 0; ++ s->lambda_info8 = 0; ++ s->lambda_info4 = 0; ++ s->lambda_infouv = 0; ++ s->ref_4 = 4; ++ s->ref_8 = 3; ++ memset(s->bit_16, 0, sizeof(s->bit_16)); ++ memset(s->bit_uv, 0, sizeof(s->bit_uv)); ++ for (i = 0; i < 4; ++i) ++ s->bit_4[i] = 4; ++ for (i = 0; i < 4; ++i) ++ s->bit_8[i] = 4; ++ memset(s->const_16, 0, sizeof(s->const_16)); ++ memset(s->const_uv, 0, sizeof(s->const_uv)); ++ memset(s->const_4, 0, sizeof(s->const_4)); ++ memset(s->const_8, 0, sizeof(s->const_8)); ++ } ++ ++ ++ /* 9. jrfc,jrfd [5]*/ ++ { ++ s->jrfcd_flag = 0; ++ s->jrfc_enable = 0; ++ s->jrfd_enable = 0; ++ s->lm_head_total = ((ctx->p.width+31) >> 5) * ((ctx->p.height+15) >> 4); ++ s->cm_head_total = ((ctx->p.width+63) >> 6) * ((ctx->p.height+15) >> 4); ++ } ++ ++ ++ /* 10. eigen cfg for mosaic, color error [42]*/ ++ { ++ //x264_sinfo_eigenValue_cfg(rc,p,s); ++ } ++ ++ /*11. skin judge cfg[14]*/ ++ { ++ /*TODO.*/ ++ s->skin_dt_en = 0; //sipe->skin_dt_en; ++ s->skin_lvl = 0; //sipe->skin_lvl; ++ s->skin_cnt_thd = 20; //sipe->skin_cnt_thd; ++ s->ncu_mov_en = 0; ++ s->ncu_move_len = 20; ++ s->ncu_move_info = NULL; ++ s->buf_share_en = 0; ++ s->buf_share_size = 0; ++ s->frame_idx = 0; ++ //s->is_first_Pframe = 0; ++ ++ memcpy(s->skin_pxlu_thd, rc_skin_pxlu_thd, sizeof(s->skin_pxlu_thd)); ++ memcpy(s->skin_pxlv_thd, rc_skin_pxlv_thd, sizeof(s->skin_pxlv_thd)); ++ memcpy(s->skin_qp_ofst, rc_skin_qp_ofst, sizeof(s->skin_qp_ofst)); ++ memcpy(s->mult_factor, rc_mult_factor, sizeof(s->mult_factor)); ++ memcpy(s->shift_factor, rc_shift_factor, sizeof(s->shift_factor)); ++ memcpy(s->skin_ofst, rc_skin_ofst, sizeof(s->skin_ofst)); ++ } ++ ++ /* 12.qpg */ ++ { ++ //h264_get_mb_qp(p,s); ++ } ++ ++ s->state = ctx->cb.state; ++ s->raw_format = ctx->p.format; ++ ++ s->stride[0] = s->frame_width; ++ s->stride[1] = s->raw_format == HELIX_420P_MODE ? ++ s->frame_width / 2 : s->frame_width; ++ for(i = 0; i < ctx->frame->num_planes; i++) { ++ s->raw[i] = ctx->frame->fb_addr[i].pa; ++ } ++ ++ for(i = 0; i < 3; i++) { ++ s->fb[i][0] = ctx->fb[bufidx[i]].yaddr_pa; ++ s->fb[i][1] = ctx->fb[bufidx[i]].caddr_pa; ++ } ++ ++ s->des_va = ctx->desc; ++ s->des_pa = ctx->desc_pa; ++ ++ s->emc_bs_pa = ctx->bs->pa; ++ ++ s->emc_dblk_va = ctx->emc_buf; ++ s->emc_recon_va = s->emc_dblk_va + DBLK_SIZE; ++ s->emc_mv_va = s->emc_recon_va + RECON_SIZE; ++ s->emc_se_va = s->emc_mv_va + MV_SIZE; ++ s->emc_qpt_va = s->emc_se_va + SE_SIZE; ++ s->emc_rc_va = s->emc_qpt_va + QPT_SIZE; ++ s->emc_cpx_va = s->emc_rc_va + RC_SIZE; ++ s->emc_mod_va = s->emc_cpx_va + CPX_SIZE; ++ s->emc_sad_va = s->emc_mod_va + MOD_SIZE; ++ s->emc_ncu_va = s->emc_sad_va + SAD_SIZE; ++ ++ s->emc_dblk_pa = ctx->emc_buf_pa; ++ s->emc_recon_pa = s->emc_dblk_pa + DBLK_SIZE; ++ s->emc_mv_pa = s->emc_recon_pa + RECON_SIZE; ++ s->emc_se_pa = s->emc_mv_pa + MV_SIZE; ++ s->emc_qpt_pa = s->emc_se_pa + SE_SIZE; ++ s->emc_rc_pa = s->emc_qpt_pa + QPT_SIZE; ++ s->emc_cpx_pa = s->emc_rc_pa + RC_SIZE; ++ s->emc_mod_pa = s->emc_cpx_pa + CPX_SIZE; ++ s->emc_sad_pa = s->emc_mod_pa + MOD_SIZE; ++ s->emc_ncu_pa = s->emc_sad_pa + SAD_SIZE; ++ ++ ++ H264E_SliceInit(s); ++// H264E_DumpInfo(s); ++ ++ dma_cache_sync(NULL, ctx->desc, ctx->vdma_chain_len, DMA_TO_DEVICE); ++ ++ return ret; ++} ++ ++static int h264e_encode_slice(struct h264e_ctx *ctx, int force_idr, int *keyframe) ++{ ++ int idr = 0; ++ int i_nal_type = 0; ++ int i_nal_ref_idc = 0; ++ bs_t bs; ++ int ret = 0; ++ unsigned int encoded_header_size = 0; ++ ++ /*decide I/P Frame*/ ++ if(!(ctx->i_frame % ctx->p.gop_size) || force_idr) { ++ ctx->i_frame = 0; ++ idr = 1; ++ } ++ ++ /* only I/P support.*/ ++ if(idr) { ++ i_nal_type = NAL_SLICE_IDR; ++ i_nal_ref_idc = NAL_PRIORITY_HIGHEST; ++ ctx->sh.i_type = M_SLICE_TYPE_I; ++ *keyframe = 1; ++ } else { ++ i_nal_type = NAL_SLICE; ++ i_nal_ref_idc = NAL_PRIORITY_HIGH; ++ ctx->sh.i_type = M_SLICE_TYPE_P; ++ *keyframe = 0; ++ } ++ ++ if(*keyframe && add_sps_pps_iframe) { ++ /* insert sps/pps.*/ ++ encoded_header_size = h264e_encode_headers(ctx, ctx->bs); ++ ctx->bs->va += encoded_header_size; ++ ctx->bs->pa += encoded_header_size; ++ } ++ ++ bs_init(&bs, ctx->slice_header, MAX_SLICE_HEADER_SIZE); ++ ++ ret = h264e_slice_init(ctx, i_nal_type); ++ if(ret < 0) ++ return ret; ++ ++ /*1. nal_header*/ ++ bs_write(&bs, 8, 0x00); ++ bs_write(&bs, 8, 0xFF); ++ bs_write(&bs, 8, 0x00); ++ bs_write(&bs, 8, 0x01); ++ /* nal header */ ++ bs_write(&bs, 8, (0 << 7 | (i_nal_ref_idc << 5) | (i_nal_type))); ++ ++ /*2. slice_header, */ ++ h264e_slice_header_write(&bs, &ctx->sh, i_nal_ref_idc); ++ ++ ++ if(ctx->p.i_cabac) { ++ bs_align_1(&bs); ++ h264_cabac_context_init(&ctx->cb, ctx->sh.i_type, ctx->sh.i_qp_delta, ctx->sh.i_cabac_init_idc); ++ } ++ ++ unsigned int slice_header_size = bs_pos(&bs); ++ unsigned int slice_header_len = (slice_header_size + 7) / 8; ++ h264e_fill_slice_info(ctx, slice_header_size); ++ ++ //print_hex_dump(KERN_INFO, "sl_header@", DUMP_PREFIX_ADDRESS, 16, 1, ctx->slice_header, 64, 1); ++ ++ ret = ingenic_vpu_start(ctx->priv); ++ if(ret < 0) { ++ return ret; ++ } ++ ++ //print_hex_dump(KERN_INFO, "bs@", DUMP_PREFIX_ADDRESS, 16, 1, ctx->bs->va, ctx->r_bs_len, 1); ++ ++ ctx->encoded_bs_len = encoded_header_size + ctx->r_bs_len + ctx->r_rbsp_len + slice_header_len; ++ ++ unsigned char *xp = (unsigned char *)((unsigned long)ctx->bs->va | 0xa0000000); ++ xp[0] = 0x00; ++ xp[1] = 0x00; ++ xp[2] = 0x00; ++ ++ //printk("-----------%s, %d, vpu ctx->r_bs_len: %d, ctx->r_rbsp_len: %d, ctx->encoded_bs_len: %d\n", __func__, __LINE__, ctx->r_bs_len, ctx->r_rbsp_len, ctx->encoded_bs_len); ++ ++ ctx->i_frame++; ++ ctx->frameindex++; ++ ++ return ret; ++} ++ ++/* add 0xff nal .*/ ++static int h264e_filler_nal(int size, char *p) ++{ ++ if (size < 6) ++ return -EINVAL; ++ ++ p[0] = 0x00; ++ p[1] = 0x00; ++ p[2] = 0x00; ++ p[3] = 0x01; ++ p[4] = 0x0c; ++ memset(p + 5, 0xff, size - 6); ++ /* Add rbsp stop bit and trailing at the end */ ++ p[size - 1] = 0x80; ++ ++ return 0; ++} ++ ++static int h264e_padding(int size, char *p) ++{ ++ int ret = 0; ++ ++ if(size == 0) ++ return 0; ++ ++ ret = h264e_filler_nal(size, p); ++ if(ret < 0) ++ return ret; ++ ++ return size; ++} ++ ++int h264e_encode_headers(struct h264e_ctx *ctx, struct ingenic_vcodec_mem *bs) ++{ ++ int ret = 0; ++ unsigned int align = 0; ++ ++ if(ctx->encoded_bs_len != 0) { ++ pr_info("set encoded_bs_len to 0 before encode!\n"); ++ } ++ ++ memcpy(bs->va, ctx->bs_header, ctx->bs_header_size); ++ ++ if(ctx->p.h264_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME) { ++ ++ /*align to 256*/ ++ align = (ctx->bs_header_size + 255) / 256 * 256; ++ ++ ret = h264e_padding(align - ctx->bs_header_size, bs->va + ctx->bs_header_size); ++ ctx->encoded_bs_len = align; ++ } else { ++ ctx->encoded_bs_len = ctx->bs_header_size; ++ } ++ ++ ret = ctx->encoded_bs_len; ++ ++ return ret; ++} ++ ++int h264e_encode(struct h264e_ctx *ctx, struct video_frame_buffer *frame, ++ struct ingenic_vcodec_mem *bs, int force_idr, int *keyframe) ++{ ++ int ret = 0; ++ ctx->frame = frame; ++ ctx->bs = bs; ++ ++ ret = h264e_encode_slice(ctx, force_idr, keyframe); ++ ++ /* output bistream */ ++ ++ return ret; ++} ++ ++ ++ ++/* start streaming.*/ ++int h264e_alloc_workbuf(struct h264e_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ int allocate_fb = 0; ++ int ret = 0; ++ int i = 0; ++ ++ ctx->bs_header = kzalloc(MAX_BS_HEADER_SIZE, GFP_KERNEL); ++ if(!ctx->bs_header) { ++ pr_err("Failed to alloc memory for bs_header\n"); ++ return -ENOMEM; ++ } ++ ctx->bs_header_size = 0; ++ ++ ++ ctx->desc = dma_alloc_noncoherent(venc_ctx->dev->dev, ctx->vdma_chain_len, &ctx->desc_pa, GFP_KERNEL); ++ if(!ctx->desc) { ++ pr_err("Failed to alloc vpu desc buffer!\n"); ++ ret = -ENOMEM; ++ goto err_desc; ++ } ++ ++ ++ /* init yaddr. */ ++ for(i = 0; i < 3; i++) { ++ ctx->fb[i].yaddr = NULL; ++ ctx->fb[i].caddr = NULL; ++ } ++ ++ for(i = 0; i < 3; i++) { ++ ctx->fb[i].yaddr = dma_alloc_coherent(venc_ctx->dev->dev, ctx->framesize, &ctx->fb[i].yaddr_pa, GFP_KERNEL); ++ ctx->fb[i].caddr = dma_alloc_coherent(venc_ctx->dev->dev, ctx->framesize/2, &ctx->fb[i].caddr_pa, GFP_KERNEL); ++ ++ allocate_fb = i; ++ if(!ctx->fb[i].yaddr || !ctx->fb[i].caddr) { ++ ret = -ENOMEM; ++ goto err_fb; ++ } ++ } ++ ++ ctx->emc_buf = dma_alloc_coherent(venc_ctx->dev->dev, EMC_SIZE, &ctx->emc_buf_pa, GFP_KERNEL); ++ if(!ctx->emc_buf) { ++ pr_err("Failed to alloc vpu emc_buf!\n"); ++ ret = -ENOMEM; ++ goto err_emc_buf; ++ } ++ ++ return ret; ++ ++err_emc_buf: ++err_fb: ++ for(i = 0; i < 3; i++) { ++ if(ctx->fb[i].yaddr) { ++ dma_free_coherent(venc_ctx->dev->dev, ctx->framesize, ctx->fb[i].yaddr, ctx->fb[i].yaddr_pa); ++ } ++ if(ctx->fb[i].caddr) { ++ dma_free_coherent(venc_ctx->dev->dev, ctx->framesize/2, ctx->fb[i].caddr, ctx->fb[i].caddr_pa); ++ } ++ ++ } ++ ++ dma_free_noncoherent(venc_ctx->dev->dev, ctx->vdma_chain_len, ctx->desc, ctx->desc_pa); ++err_desc: ++ kfree(ctx->bs_header); ++ ctx->bs_header = NULL; ++ ++ return ret; ++} ++ ++/* stop streaming.*/ ++int h264e_free_workbuf(struct h264e_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ int i; ++ ++ if(ctx->bs_header) { ++ kfree(ctx->bs_header); ++ ctx->bs_header = NULL; ++ } ++ dma_free_noncoherent(venc_ctx->dev->dev, ctx->vdma_chain_len, ctx->desc, ctx->desc_pa); ++ dma_free_coherent(venc_ctx->dev->dev, EMC_SIZE, ctx->emc_buf, ctx->emc_buf_pa); ++ ++ for(i = 0; i < 3; i++) { ++ dma_free_coherent(venc_ctx->dev->dev, ctx->framesize, ctx->fb[i].yaddr, ctx->fb[i].yaddr_pa); ++ dma_free_coherent(venc_ctx->dev->dev, ctx->framesize/2, ctx->fb[i].caddr, ctx->fb[i].caddr_pa); ++ } ++ return 0; ++} ++ ++int h264e_encoder_init(struct h264e_ctx *ctx) ++{ ++ struct h264e_params *p = NULL; ++ H264E_SliceInfo_t *s = NULL; ++ ++ s = kzalloc(sizeof(H264E_SliceInfo_t), GFP_KERNEL); ++ if(!s) { ++ return -ENOMEM; ++ } ++ ++ p = &ctx->p; ++ ctx->s = s; ++ ++ ctx->vdma_chain_len = 40960 + 256; ++ ctx->frameindex = 0; ++ ctx->i_frame = 0; ++ ++ p->height = 240; ++ p->width = 160; ++ p->max_ref_pic = 1; ++ p->gop_size = 50; ++ p->i_idr_pic_id = 0; ++ p->i_global_qp = 30; ++ p->h264_profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; ++ p->h264_level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0; ++ p->i_cabac = 1; ++ p->interlaced = 0; ++ p->h264_8x8_transform = 0; ++ p->h264_hdr_mode = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME; ++ p->h264_min_qp = 0; ++ p->h264_max_qp = 51; ++ p->i_qp = 30; ++ p->p_qp = 30; ++ p->deblock = 0; ++ ++ h264_cabac_init(); ++ ++ return 0; ++} ++ ++int h264e_encoder_deinit(struct h264e_ctx *ctx) ++{ ++ if(!ctx) ++ return 0; ++ ++ if(ctx->s) ++ kfree(ctx->s); ++ return 0; ++} ++ ++void h264e_set_priv(struct h264e_ctx *ctx, void *data) ++{ ++ ctx->priv = data; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e.h +new file mode 100644 +index 000000000..8dbec650c +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e.h +@@ -0,0 +1,134 @@ ++#ifndef __H264E_H__ ++#define __H264E_H__ ++ ++#include "api/helix_x264_enc.h" ++ ++#include "h264enc/common.h" ++#include "helix_buf.h" ++ ++/** ++* @bitrate, set by V4L2_CID_MPEG_VIDEO_BITRATE. ++* @gop_size, group of picture when h264 encoding. ++*/ ++struct h264e_params { ++ ++ /* params modify by s_ctrl*/ ++ uint32_t bitrate; ++ uint32_t framerate; ++ int h264_hdr_mode; ++#if 0 ++ uint8_t h264_intra_qp; ++ uint8_t h264_inter_qp; ++#endif ++ uint8_t i_qp; ++ uint8_t p_qp; ++ uint8_t h264_min_qp; ++ uint8_t h264_max_qp; ++ uint8_t h264_profile; ++ uint8_t h264_level; ++ uint8_t gop_size; ++ uint8_t frame_rc_enable; ++ uint8_t mb_rc_enable; ++ uint8_t num_bframe; ++ uint8_t interlaced; ++ uint8_t max_ref_pic; ++ uint8_t h264_8x8_transform; ++ ++ uint8_t i_cabac; /*is cabac entropy?*/ ++ ++ int i_idr_pic_id; ++ int i_global_qp; ++ ++ uint8_t deblock; ++ ++ ++ ++ int height; ++ int width; ++ int format; ++ ++}; ++ ++ ++#define MAX_BS_HEADER_SIZE 1024 /* maybe enough for header only.*/ ++#define MAX_SLICE_HEADER_SIZE 128 /* 128bytes of slice header bs.*/ ++ ++struct h264e_ctx { ++ unsigned char *bs_header; /* buffer to store sps/pps/sei headers. */ ++ unsigned int bs_header_size; /* buffer size. */ ++ ++ unsigned char slice_header[128]; /*store slice buffer.*/ ++ ++ int vdma_chain_len; ++ unsigned int framesize; ++ /*æ ¹æ®height,width分é…çš„,*/ ++ struct h264_ref_tile fb[3]; /*å‚考body buffer.按frame申请*/ ++ struct h264_ref_tile jh[3]; /*å‚考header buffer.按frame申请*/ ++ ++ unsigned int *emc_buf; /* 128KBytes固定空间*/ ++ dma_addr_t emc_buf_pa; ++ ++ unsigned int *desc; /* descriptor, 40960+256, 固定大å°*/ ++ dma_addr_t desc_pa; ++ ++ ++ struct video_frame_buffer *frame; /* input picture frame. */ ++ struct ingenic_vcodec_mem *bs; /* output slice data. exclude slice header? */ ++ struct ingenic_vcodec_mem bs_tmp_buf; /* temperary buf for now., used to store vpu output buffer. then memory cp to userspace. */ ++ ++ unsigned int src_crc; /*Debug*/ ++ ++ ++ h264_sps_t sps; ++ h264_pps_t pps; ++ h264_slice_header_t sh; ++ h264_cabac_t cb; /*cabac state*/ ++ ++ int i_frame; /* (i_frame + 1) % gop_size */ ++ ++ /* modify after encode frame*/ ++ unsigned long frameindex; ++ unsigned int status; ++ unsigned int r_bs_len; /*result bs len.*/ ++ unsigned int r_rbsp_len; /*0x03 的个数.*/ ++ unsigned int encoded_bs_len; /* encoded bs_len */ ++ ++ struct h264e_params p; ++ H264E_SliceInfo_t *s; ++ ++ void *priv; ++}; ++ ++#define EMC_SIZE (1<<19) ++#define DBLK_SIZE (0) ++#define RECON_SIZE (0) ++#define MV_SIZE (1 << 11) ++#define SE_SIZE (1 << 11) ++#define QPT_SIZE (1<<14) ++#define RC_SIZE (1<<15) ++#define CPX_SIZE (1<<17) ++#define MOD_SIZE (1<<15) ++#define SAD_SIZE (1<<17) ++#define ENCU_SIZE (1<<13) ++#define BEYOND_MAX_SIZE 64*3 ++ ++ ++ ++extern int h264e_generate_headers(struct h264e_ctx *ctx); ++ ++extern int h264e_encode_headers(struct h264e_ctx *ctx, struct ingenic_vcodec_mem *bs); ++ ++extern int h264e_encode(struct h264e_ctx *ctx, struct video_frame_buffer *frame, struct ingenic_vcodec_mem *bs, int force_idr, int *keyframe); ++ ++extern int h264e_set_fmt(struct h264e_ctx *ctx, int width, int height, int format); ++extern int h264e_alloc_workbuf(struct h264e_ctx *ctx); ++ ++extern int h264e_free_workbuf(struct h264e_ctx *ctx); ++ ++extern int h264e_encoder_init(struct h264e_ctx *ctx); ++ ++extern int h264e_encoder_deinit(struct h264e_ctx *ctx); ++ ++extern void h264e_set_priv(struct h264e_ctx *ctx, void *data); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc.c +new file mode 100644 +index 000000000..da25a5d31 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc.c +@@ -0,0 +1,664 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* This program is free software; you can redistribute it and/or modify ++* it under the terms of the GNU General Public License version 2 as ++* published by the Free Software Foundation. ++* ++* This program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++*/ ++#include ++#include ++#include ++#include ++#include ++ ++#include "api/helix_x264_enc.h" ++#include "h264enc/common.h" ++#include "h264enc/set.h" ++#include "h264e_rc_nl.h" ++#include "h264e_rc.h" ++#include "helix_drv.h" ++ ++static unsigned add_sps_pps_iframe = 1; ++module_param(add_sps_pps_iframe, uint, S_IRUGO | S_IWUSR); ++ ++#define MAX_REF_FRAMES 1 ++#define NUM_WORK_BUFFERS (MAX_REF_FRAMES + 1) ++ ++#if NUM_WORK_BUFFERS > 2 ++ ++#error "Multi refrence encoding not support Yet, NUM_WORK_BUFFERS should be 2." ++ ++#endif ++ ++/*TODO: export to high level ????*/ ++int h264e_set_params(struct h264e_ctx *ctx, unsigned id, unsigned int val) ++{ ++ int ret = 0; ++ ++ ++ return ret; ++} ++ ++int h264e_get_params(struct h264e_ctx *ctx, int id) ++{ ++ unsigned int val = 0; ++ ++ return val; ++} ++ ++int h264e_set_fmt(struct h264e_ctx *ctx, int width, int height, int format) ++{ ++ struct h264e_params *p = &ctx->p; ++ unsigned int align_w = width; ++ unsigned int align_h = height; ++ ++ int ret = 0; ++ ++ ++ p->width = width; ++ p->height = height; ++ switch(format) { ++ case HELIX_NV12_MODE: ++ case HELIX_NV21_MODE: ++ case HELIX_TILE_MODE: ++ case HELIX_420P_MODE: ++ p->format = format; ++ break; ++ default: ++ pr_err("Unsupported pix fmt: %x\n", format); ++ ret = -EINVAL; ++ break; ++ } ++ ++ align_w = ALIGN(width, 16); ++ align_h = ALIGN(height, 16); ++ ++ ctx->framesize = align_w * align_h; ++ ++ h264e_nl_rc_video_cfg(ctx, &ctx->p); ++ ++ return ret; ++} ++ ++//to profile_idc ++static int __maybe_unused v4l2_profile(int i_profile_idc) ++{ ++ switch (i_profile_idc) { ++ case PROFILE_BASELINE: return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; ++ case PROFILE_MAIN: return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; ++ case PROFILE_HIGH10: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10; ++ case PROFILE_HIGH422: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422; ++ case PROFILE_HIGH444_PREDICTIVE: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE; ++ default: return -EINVAL; ++ } ++ ++} ++ ++static int __maybe_unused h264e_profile_idc(int v4l2_profile) ++{ ++ switch (v4l2_profile) { ++ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: return PROFILE_BASELINE; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: return PROFILE_MAIN; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: return PROFILE_HIGH10; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: return PROFILE_HIGH422; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: return PROFILE_HIGH444_PREDICTIVE; ++ default: return -EINVAL; ++ } ++} ++ ++static int __maybe_unused v4l2_h264_level(int i_level_idc) ++{ ++ switch (i_level_idc) { ++ case 10: return V4L2_MPEG_VIDEO_H264_LEVEL_1_0; ++ case 9: return V4L2_MPEG_VIDEO_H264_LEVEL_1B; ++ case 11: return V4L2_MPEG_VIDEO_H264_LEVEL_1_1; ++ case 12: return V4L2_MPEG_VIDEO_H264_LEVEL_1_2; ++ case 13: return V4L2_MPEG_VIDEO_H264_LEVEL_1_3; ++ case 20: return V4L2_MPEG_VIDEO_H264_LEVEL_2_0; ++ case 21: return V4L2_MPEG_VIDEO_H264_LEVEL_2_1; ++ case 22: return V4L2_MPEG_VIDEO_H264_LEVEL_2_2; ++ case 30: return V4L2_MPEG_VIDEO_H264_LEVEL_3_0; ++ case 31: return V4L2_MPEG_VIDEO_H264_LEVEL_3_1; ++ case 32: return V4L2_MPEG_VIDEO_H264_LEVEL_3_2; ++ case 40: return V4L2_MPEG_VIDEO_H264_LEVEL_4_0; ++ case 41: return V4L2_MPEG_VIDEO_H264_LEVEL_4_1; ++ default: return -EINVAL; ++ } ++} ++ ++static int h264e_level_idc(int level) ++{ ++ switch (level) { ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: return 10; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1B: return 9; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: return 11; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: return 12; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: return 13; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: return 20; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: return 21; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: return 22; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: return 30; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: return 31; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: return 32; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: return 40; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: return 41; ++ default: return -EINVAL; ++ } ++} ++ ++/* ----------------------------- Picture Parameter Sets ---------------*/ ++static void h264e_sps_init(struct h264e_ctx *ctx, h264_sps_t *sps, int i_id) ++{ ++ struct h264e_params *p = &ctx->p; ++ int max_frame_num = 1; ++ ++ sps->i_id = i_id; ++ sps->i_mb_width = C_ALIGN(p->width, 16) / 16; ++ sps->i_mb_height = C_ALIGN(p->height, 16) / 16; ++ sps->i_chroma_format_idc = CHROMA_420; ++ sps->b_qpprime_y_zero_transform_bypass = 0; ++ sps->i_profile_idc = h264e_profile_idc(p->h264_profile); ++ sps->b_constraint_set0 = sps->i_profile_idc == PROFILE_BASELINE; ++ sps->b_constraint_set1 = sps->i_profile_idc <= PROFILE_MAIN; ++ sps->b_constraint_set2 = 0; ++ sps->b_constraint_set3 = 0; ++ ++ sps->i_level_idc = h264e_level_idc(p->h264_level); ++ if((sps->i_level_idc == 9) && (sps->i_profile_idc == PROFILE_BASELINE || sps->i_profile_idc == PROFILE_MAIN)) { ++ sps->b_constraint_set0 = 1; /* level 1b with Baseline or Main profile is signalled via constraint_set3 */ ++ sps->i_level_idc = 11; ++ } ++ ++ ++ sps->i_num_ref_frames = p->max_ref_pic; ++ sps->vui.i_num_reorder_frames = 0; ++ sps->vui.i_max_dec_frame_buffering = sps->i_num_ref_frames; ++ ++ sps->i_log2_max_frame_num = 4; ++ while((1 << sps->i_log2_max_frame_num) <= max_frame_num) ++ sps->i_log2_max_frame_num++; ++ ++ sps->i_poc_type = 2; ++ ++ if(sps->i_poc_type == 0) { ++ } ++ ++ sps->b_vui = 0; ++ ++ sps->b_gaps_in_frame_num_value_allowed = 0; ++ sps->b_frame_mbs_only = 1; ++ if(!sps->b_frame_mbs_only) ++ sps->i_mb_height = (sps->i_mb_height + 1) & ~1; ++ sps->b_mb_adaptive_frame_field = p->interlaced; ++ sps->b_direct8x8_inference = 1; ++ sps->crop.i_left = 0; ++ sps->crop.i_right = sps->i_mb_width * 16 - p->width; ++ sps->crop.i_top = 0; ++ sps->crop.i_bottom = sps->i_mb_height * 16 - p->height; ++ ++ if(sps->crop.i_right || sps->crop.i_bottom) { ++ sps->b_crop = 1; ++ } else { ++ sps->b_crop = 0; ++ } ++ ++// h264_sps_init_reconfigurable(sps, sw); ++ ++ ++ sps->vui.b_overscan_info_present = 0; ++ sps->vui.b_overscan_info = 0; ++ ++ sps->i_cqm_preset = 0; ++ sps->b_avcintra = 0; ++ ++} ++ ++static void h264e_pps_init(struct h264e_ctx *ctx, h264_pps_t *pps, int i_id, h264_sps_t *sps) ++{ ++ struct h264e_params *p = &ctx->p; ++ ++ pps->i_id = i_id; ++ pps->i_sps_id = sps->i_id; ++ pps->b_cabac = sps->i_profile_idc < PROFILE_MAIN ? 0 : p->i_cabac; ++ ++ pps->b_pic_order = 0; ++ pps->i_num_slice_groups = 1; /* base & main profile.*/ ++ ++ pps->i_num_ref_idx_l0_default_active = p->max_ref_pic; ++ pps->i_num_ref_idx_l1_default_active = 1; ++ ++ pps->b_weighted_pred = 0; ++ pps->b_weighted_bipred = 0; ++ ++ pps->i_pic_init_qp = 26; ++ pps->i_pic_init_qs = 26; ++ ++ pps->i_chroma_qp_index_offset = 0; ++ pps->b_deblocking_filter_control = 0; ++ pps->b_constrained_intra_pred = 0; ++ pps->b_redundant_pic_cnt = 0; ++ ++ pps->b_transform_8x8_mode = p->h264_8x8_transform; ++} ++ ++ ++static int encapsulate_nal(bs_t *s, int s_off, char *dst, int i_type, int i_ref_idc) ++{ ++ ++ uint8_t *src = s->p_start + s_off; ++ uint8_t *end = src + (bs_pos(s) / 8); ++ char *orig_dst = dst; ++ ++ /* prefix */ ++ *dst++ = 0x00; ++ *dst++ = 0x00; ++ *dst++ = 0x00; ++ *dst++ = 0x01; ++ ++ /* nal header */ ++ *dst++ = (0 << 7) | (i_ref_idc << 5) | (i_type); ++ ++ if(src < end) *dst++ = *src++; ++ if(src < end) *dst++ = *src++; ++ while( src < end ) ++ { ++ if( src[0] <= 0x03 && !src[-2] && !src[-1] ) { ++ *dst++ = 0x03; ++ } ++ *dst++ = *src++; ++ } ++ ++ return dst - orig_dst; ++} ++ ++/** ++* @h264e_generate_headers generate sps/pps headers according to params. ++* and store the header until encoder closed. ++* @ctx h264e_ctx. ++* ++* @Return 0 ++*/ ++int h264e_generate_headers(struct h264e_ctx *ctx, int is_stream_on) ++{ ++ /* used to encode header for tmp.*/ ++ char *bs_tmp = NULL; ++ char *bs_header = ctx->bs_header; ++ bs_t bs; ++ int bs_size = 0; ++ h264_sps_t *sps = NULL; ++ h264_pps_t *pps = NULL; ++ ctx->bs_header_size = 0; ++ ++ bs_tmp = kzalloc(MAX_BS_HEADER_SIZE, GFP_KERNEL); ++ if(!bs_tmp) { ++ return -ENOMEM; ++ } ++ ++ sps = &ctx->sps; ++ pps = &ctx->pps; ++ ++ h264e_sps_init(ctx, sps, 0); ++ h264e_pps_init(ctx, pps, 0, sps); ++ ++ /* 1. encode sps */ ++ bs_init(&bs, bs_tmp, MAX_BS_HEADER_SIZE); ++ h264e_sps_write(&bs, sps); ++ ++ bs_size = encapsulate_nal(&bs, 0, bs_header, NAL_SPS, NAL_PRIORITY_HIGHEST); ++ ++ ctx->bs_header_size += bs_size; ++ bs_header += bs_size; ++ ++ /* 2. encode pps */ ++ bs_init(&bs, bs_tmp, MAX_BS_HEADER_SIZE); ++ h264e_pps_write(&bs, sps, pps); ++ ++ bs_size = encapsulate_nal(&bs, 0, bs_header, NAL_PPS, NAL_PRIORITY_HIGHEST); ++ ctx->bs_header_size += bs_size; ++ bs_header += bs_size; ++ ++ ++ if(ctx->bs_header_size > (MAX_BS_HEADER_SIZE)) { ++ pr_warn("bs_header buffer almost overflow!\n"); ++ } ++ ++ /* 3. encode sei */ ++ ++ /* 4. encode more */ ++ ++ if(is_stream_on) { ++ ++ struct nl_header_info h_info; ++ ++ memcpy(&h_info.pps, pps, sizeof(h264_pps_t)); ++ memcpy(&h_info.sps, sps, sizeof(h264_sps_t)); ++ ++ h264e_nl_setup_headers(ctx, &h_info); ++ } ++ ++ /* release temp buffer. */ ++ kfree(bs_tmp); ++ return 0; ++} ++ ++/* add 0xff nal .*/ ++static int h264e_filler_nal(int size, char *p) ++{ ++ if (size < 6) ++ return -EINVAL; ++ ++ p[0] = 0x00; ++ p[1] = 0x00; ++ p[2] = 0x00; ++ p[3] = 0x01; ++ p[4] = 0x0c; ++ memset(p + 5, 0xff, size - 6); ++ /* Add rbsp stop bit and trailing at the end */ ++ p[size - 1] = 0x80; ++ ++ return 0; ++} ++ ++static int h264e_padding(int size, char *p) ++{ ++ int ret = 0; ++ ++ if(size == 0) ++ return 0; ++ ++ ret = h264e_filler_nal(size, p); ++ if(ret < 0) ++ return ret; ++ ++ return size; ++} ++ ++int h264e_encode_headers(struct h264e_ctx *ctx, struct ingenic_vcodec_mem *bs) ++{ ++ int ret = 0; ++ unsigned int align = 0; ++ ++ if(ctx->encoded_bs_len != 0) { ++ pr_info("set encoded_bs_len to 0 before encode!\n"); ++ } ++ ++ memcpy(bs->va, ctx->bs_header, ctx->bs_header_size); ++ ++ /*align to 256*/ ++ align = (ctx->bs_header_size + 255) / 256 * 256; ++ ret = h264e_padding(align - ctx->bs_header_size, bs->va + ctx->bs_header_size); ++ ctx->encoded_bs_len = align; ++ ++ ret = ctx->encoded_bs_len; ++ ++ return ret; ++} ++ ++void xhexdump(unsigned char *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) { ++ if ((i % 16) == 0) ++ printf("%s%08x: ", i ? "\n" : "", ++ (unsigned int)&buf[i]); ++ printf("%02x ", buf[i]); ++ } ++ printf("\n"); ++} ++ ++ ++int h264e_encode(struct h264e_ctx *ctx, struct video_frame_buffer *frame, ++ struct ingenic_vcodec_mem *bs_mem, int force_idr, int *keyframe) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ unsigned int slice_header_size = 0; ++ unsigned int slice_header_len = 0; ++ int idr = 0; ++ int i_nal_type = 0; ++ int i_nal_ref_idc = 0; ++ bs_t bs; ++ int ret = 0; ++ int i = 0; ++#if 0 ++ unsigned char bmap[3][3] = { ++ {0, 2, 1}, ++ {1, 0, 2}, ++ {2, 1, 0} ++ }; ++#endif ++ ++ unsigned char bmap[2][2] = { ++ {0, 1}, ++ {1, 0}, ++ }; ++ unsigned int encoded_header_size = 0; ++ ++ struct h264e_frame_start_params p; ++ ++ memset(&p, 0, sizeof(struct h264e_frame_start_params)); ++ ++ ctx->frame = frame; ++ ctx->bs = bs_mem; ++ ++ if(!(ctx->i_frame % ctx->p.gop_size) || force_idr) { ++ ctx->i_frame = 0; ++ idr = 1; ++ } ++ ++ unsigned char *bufidx = bmap[ctx->i_frame % NUM_WORK_BUFFERS]; ++ ++ p.bIFrmReq = idr; ++ if(idr) { ++ p.frmSkipType = 0; ++ } else { ++ p.frmSkipType = 1; ++ } ++ ++ p.raw_format = ctx->p.format; ++ for(i = 0; i < ctx->frame->num_planes; i++) { ++ p.raw[i] = ctx->frame->fb_addr[i].pa; ++ } ++ ++ for(i = 0; i < NUM_WORK_BUFFERS; i++) { ++ p.fb[i][0] = ctx->fb[bufidx[i]].yaddr_pa; ++ p.fb[i][1] = ctx->fb[bufidx[i]].caddr_pa; ++ } ++ ++ p.stride[0] = ctx->p.width; ++ p.stride[1] = p.raw_format == HELIX_420P_MODE ? ++ ctx->p.width / 2 : ctx->p.width; ++ ++ if(idr) { ++ *keyframe = idr; ++ if(*keyframe && add_sps_pps_iframe) { ++ /* insert sps/pps.*/ ++ encoded_header_size = h264e_encode_headers(ctx, ctx->bs); ++ ctx->bs->va += encoded_header_size; ++ ctx->bs->pa += encoded_header_size; ++ } ++ ++ } ++ ++ p.emc_bs_pa = ctx->bs->pa; ++ p.emc_dblk_pa = ctx->emc_buf_pa; ++ ++ h264e_nl_rc_frame_start(ctx, &p); ++ ++ dma_sync_single_for_device(venc_ctx->dev->dev, ctx->desc_pa, ctx->vdma_chain_len, DMA_TO_DEVICE); ++ ++ /*2. å¯åŠ¨ç¼–ç å™¨ç¡¬ä»¶ï¼Œå¼€å§‹ç¼–ç */ ++ ret = ingenic_vpu_start(ctx->priv); ++ if(ret < 0) { ++ return ret; ++ } ++ ++ //print_hex_dump(KERN_INFO, "bs@", DUMP_PREFIX_ADDRESS, 16, 1, ctx->bs->va, 64, 1); ++ ++ ++ ctx->encoded_bs_len = encoded_header_size + ctx->r_bs_len + ctx->r_rbsp_len + p.slice_header_len; ++ ++ unsigned char *xp = (unsigned char *)((unsigned long)ctx->bs->va | 0xa0000000); ++ xp[0] = 0x00; ++ xp[1] = 0x00; ++ xp[2] = 0x00; ++ ++ ++ struct h264e_frame_end_params ep; ++ ep.u32FrmActBs = ctx->r_bs_len * 8; ++ h264e_nl_rc_frame_end(ctx, &ep); ++ ++ ++ //printk("ctx->encoded_bs_len: %d\n", ctx->encoded_bs_len); ++ ++ ctx->i_frame++; ++ ++ return ret; ++} ++ ++ ++ ++/* start streaming.*/ ++int h264e_alloc_workbuf(struct h264e_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ int allocate_fb = 0; ++ int ret = 0; ++ int i = 0; ++ ++ ++ ++ /* init yaddr. */ ++ for(i = 0; i < 3; i++) { ++ ctx->fb[i].yaddr = NULL; ++ ctx->fb[i].caddr = NULL; ++ } ++ ++ for(i = 0; i < NUM_WORK_BUFFERS; i++) { ++ ctx->fb[i].yaddr = dma_alloc_coherent(venc_ctx->dev->dev, ctx->framesize, &ctx->fb[i].yaddr_pa, GFP_KERNEL); ++ ctx->fb[i].caddr = dma_alloc_coherent(venc_ctx->dev->dev, ctx->framesize/2, &ctx->fb[i].caddr_pa, GFP_KERNEL); ++ ++ allocate_fb = i; ++ if(!ctx->fb[i].yaddr || !ctx->fb[i].caddr) { ++ ret = -ENOMEM; ++ goto err_fb; ++ } ++ } ++ ++ return ret; ++ ++err_emc_buf: ++err_fb: ++ for(i = 0; i < NUM_WORK_BUFFERS; i++) { ++ if(ctx->fb[i].yaddr) { ++ dma_free_coherent(venc_ctx->dev->dev, ctx->framesize, ctx->fb[i].yaddr, ctx->fb[i].yaddr_pa); ++ } ++ if(ctx->fb[i].caddr) { ++ dma_free_coherent(venc_ctx->dev->dev, ctx->framesize/2, ctx->fb[i].caddr, ctx->fb[i].caddr_pa); ++ } ++ ++ } ++ ++ return ret; ++} ++ ++/* stop streaming.*/ ++int h264e_free_workbuf(struct h264e_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ int i; ++ ++ for(i = 0; i < NUM_WORK_BUFFERS; i++) { ++ dma_free_coherent(venc_ctx->dev->dev, ctx->framesize, ctx->fb[i].yaddr, ctx->fb[i].yaddr_pa); ++ dma_free_coherent(venc_ctx->dev->dev, ctx->framesize/2, ctx->fb[i].caddr, ctx->fb[i].caddr_pa); ++ } ++ return 0; ++} ++ ++int h264e_encoder_init(struct h264e_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ struct h264e_params *p = NULL; ++ int ret = 0; ++ ++ ctx->emc_buf = dma_alloc_coherent(venc_ctx->dev->dev, EMC_SIZE, &ctx->emc_buf_pa, GFP_KERNEL); ++ if(!ctx->emc_buf) { ++ pr_err("Failed to alloc vpu emc_buf!\n"); ++ ret = -ENOMEM; ++ goto err_emc_buf; ++ } ++ ++ ++ ++ p = &ctx->p; ++ ++ ctx->vdma_chain_len = 40960 + 256; ++ ctx->frameindex = 0; ++ ctx->i_frame = 0; ++ ++ p->height = 240; ++ p->width = 160; ++ p->max_ref_pic = 1; ++ p->i_idr_pic_id = 0; ++ p->i_global_qp = 30; ++ p->i_cabac = 1; ++ p->interlaced = 0; ++ p->h264_8x8_transform = 0; ++ p->deblock = 0; ++// p->h264_hdr_mode = 1; ++ ++ ctx->desc = dma_alloc_noncoherent(venc_ctx->dev->dev, ctx->vdma_chain_len, &ctx->desc_pa, DMA_BIDIRECTIONAL, GFP_KERNEL); ++ if(!ctx->desc) { ++ pr_err("Failed to alloc vpu desc buffer!\n"); ++ ret = -ENOMEM; ++ goto err_desc; ++ } ++ ++ struct nl_ctx_info info; ++ ++ info.emc_buf_paddr = (unsigned int)ctx->emc_buf_pa; ++ info.desc_paddr = (unsigned int)ctx->desc_pa; ++ info.rc_mode = p->rc_mode; ++ ++ ret = h264e_nl_init_ctx(ctx, &info); ++ ++ return ret; ++err_desc: ++err_emc_buf: ++ ++ return ret; ++} ++ ++int h264e_encoder_deinit(struct h264e_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ if(!ctx) ++ return 0; ++ ++ if(ctx->emc_buf) { ++ dma_free_coherent(venc_ctx->dev->dev, EMC_SIZE, ctx->emc_buf, ctx->emc_buf_pa); ++ ctx->emc_buf = NULL; ++ } ++ ++ if(ctx->desc) { ++ dma_free_noncoherent(venc_ctx->dev->dev, ctx->vdma_chain_len, ctx->desc, ctx->desc_pa, DMA_BIDIRECTIONAL); ++ ctx->desc = NULL; ++ } ++ ++ h264e_nl_free_ctx(ctx); ++ ++ return 0; ++} ++ ++void h264e_set_priv(struct h264e_ctx *ctx, void *data) ++{ ++ ctx->priv = data; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc.h +new file mode 100644 +index 000000000..a9d3a5a59 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc.h +@@ -0,0 +1,85 @@ ++#ifndef __H264E_H__ ++#define __H264E_H__ ++ ++ ++#include "h264enc/common.h" ++#include "h264enc/set.h" ++#include "h264e_rc_proto.h" ++ ++#include "helix_buf.h" ++ ++ ++ ++#define MAX_BS_HEADER_SIZE 256 /* maybe enough for header only.*/ ++#define MAX_SLICE_HEADER_SIZE 128 /* 128bytes of slice header bs.*/ ++ ++struct h264e_ctx { ++ unsigned char bs_header[MAX_BS_HEADER_SIZE]; /* buffer to store sps/pps/sei headers. */ ++ unsigned int bs_header_size; /* buffer size. */ ++ ++ unsigned char slice_header[128]; /*store slice buffer.*/ ++ ++ int vdma_chain_len; ++ unsigned int framesize; ++ /*æ ¹æ®height,width分é…çš„,*/ ++ struct h264_ref_tile fb[3]; /*å‚考body buffer.按frame申请*/ ++ struct h264_ref_tile jh[3]; /*å‚考header buffer.按frame申请*/ ++ ++ unsigned int *emc_buf; /* 128KBytes固定空间*/ ++ dma_addr_t emc_buf_pa; ++ ++ unsigned int *desc; /* descriptor, 40960+256, 固定大å°*/ ++ dma_addr_t desc_pa; ++ ++ ++ struct video_frame_buffer *frame; /* input picture frame. */ ++ struct ingenic_vcodec_mem *bs; /* output slice data. exclude slice header? */ ++ struct ingenic_vcodec_mem bs_tmp_buf; /* temperary buf for now., used to store vpu output buffer. then memory cp to userspace. */ ++ ++ unsigned int src_crc; /*Debug*/ ++ ++ ++ h264_sps_t sps; ++ h264_pps_t pps; ++ h264_slice_header_t sh; ++ h264_cabac_t cb; /*cabac state*/ ++ ++ int i_frame; /* (i_frame + 1) % gop_size */ ++ ++ /* modify after encode frame*/ ++ unsigned long frameindex; ++ unsigned int status; ++ unsigned int r_bs_len; /*result bs len.*/ ++ unsigned int r_rbsp_len; /*0x03 的个数.*/ ++ unsigned int encoded_bs_len; /* encoded bs_len */ ++ ++ struct h264e_params p; ++ unsigned int pid; /*netlink port*/ ++#define H264E_MAX_NL_MSG 1024 ++ unsigned char recved_msg[H264E_MAX_NL_MSG]; /* netlink received msg.*/ ++ struct completion msg_complete; ++ ++ void *priv; ++}; ++ ++extern int h264e_generate_headers(struct h264e_ctx *ctx, int is_stream_on); ++ ++extern int h264e_encode_headers(struct h264e_ctx *ctx, struct ingenic_vcodec_mem *bs); ++ ++extern int h264e_encode(struct h264e_ctx *ctx, struct video_frame_buffer *frame, struct ingenic_vcodec_mem *bs, int force_idr, int *keyframe); ++ ++extern int h264e_set_fmt(struct h264e_ctx *ctx, int width, int height, int format); ++extern int h264e_alloc_workbuf(struct h264e_ctx *ctx); ++ ++extern int h264e_free_workbuf(struct h264e_ctx *ctx); ++ ++extern int h264e_encoder_init(struct h264e_ctx *ctx); ++ ++extern int h264e_encoder_deinit(struct h264e_ctx *ctx); ++ ++extern void h264e_set_priv(struct h264e_ctx *ctx, void *data); ++ ++ ++extern int h264e_netlink_test(void); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_nl.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_nl.c +new file mode 100644 +index 000000000..dcfc9fce3 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_nl.c +@@ -0,0 +1,285 @@ ++#include ++#include ++ ++#include "h264e_rc.h" ++#include "h264e_rc_nl.h" ++ ++ ++ ++ ++static struct sock *nl_sk; ++static DEFINE_MUTEX(netlink_mutex); ++static int h264e_rc_server_online = 0; ++ ++//static DECLARE_COMPLETION(msg_complete); ++ ++static int h264e_netlink_send_msg(struct h264e_ctx *ctx, void *buf, unsigned int len) ++{ ++ struct sk_buff *skb = NULL; ++ struct nlmsghdr *nlh; ++ int ret = 0; ++ int timeout = 0; ++ ++ ++ skb = nlmsg_new(len, GFP_ATOMIC); ++ if(!skb) { ++ pr_err("nlmsg_new error!\n"); ++ return -ENOMEM; ++ } ++ ++ nlh = nlmsg_put(skb, ctx->pid, 0, 0, len, 0); ++ if(!nlh) { ++ kfree(skb); ++ pr_err("nlmsg_put error!\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(nlmsg_data(nlh), buf, len); ++ ++ ++ /*wait for completion.*/ ++ ++ reinit_completion(&ctx->msg_complete); ++ ++ ret = netlink_unicast(nl_sk, skb, ctx->pid, 0); ++ ++ timeout = wait_for_completion_timeout(&ctx->msg_complete, msecs_to_jiffies(30)); ++ if(!timeout) { ++ printk("h264e nl send msg timeout!\n"); ++ return -ETIMEDOUT; ++ } ++ ++#if 0 ++ //return netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT); ++ while(!wait_msg_recv) { ++ msleep(1); ++ } ++#endif ++ ++ return ret; ++} ++ ++static int h264e_netlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack) ++{ ++ ++ struct h264e_nl_msg *msg = NLMSG_DATA(nlh); ++ struct h264e_ctx *ctx = NULL; ++ ++ switch (nlh->nlmsg_type) { ++ default: ++ // pr_err("unknown nlmsg_type\n"); ++ break; ++ } ++ ++ switch (msg->cmd) { ++ case VPU_CMD_SERVER_ONLINE: ++ h264e_rc_server_online = 1; ++ break; ++ case VPU_CMD_SERVER_OFFLINE: ++ h264e_rc_server_online = 0; ++ break; ++ ++ default: ++ break; ++ } ++ ++ ctx = (struct h264e_ctx *)msg->ctx_id; ++ ++ if(ctx) { ++ if((nlh->nlmsg_len - NLMSG_HDRLEN) > H264E_MAX_NL_MSG) { ++ printk("recved msg too long: %d, max: %d\n", nlh->nlmsg_len, H264E_MAX_NL_MSG); ++ } else { ++ memcpy(ctx->recved_msg, NLMSG_DATA(nlh), nlh->nlmsg_len - NLMSG_HDRLEN); ++ } ++ ++ complete(&ctx->msg_complete); ++ } ++ ++ ++ return 0; ++} ++ ++static void h264e_netlink_rcv(struct sk_buff *skb) ++{ ++ mutex_lock(&netlink_mutex); ++ netlink_rcv_skb(skb, &h264e_netlink_rcv_msg); ++ mutex_unlock(&netlink_mutex); ++} ++ ++static int start_h264e_server(void) ++{ ++#if 0 ++ const char *server = "/usr/bin/h264e-nl-server" ++ static const char *argv[MAX_INIT_ARGS+2] = { "/usr/bin/h264e-nl-server", NULL, }; ++#endif ++ ++ if(h264e_rc_server_online) { ++ return 0; ++ } ++ ++ ++#if 0 ++ return do_execve(getname_kernel(), ++ (const char __user *const __user *)argv_init, ++ (const char __user *const __user *)envp_init); ++#endif ++ ++ /*kernel start h264e_rc_server.*/ ++ ++ /*wait for h264e_rc_server_online = 1.*/ ++ return 0; ++} ++ ++int h264e_netlink_test(void) ++{ ++ struct netlink_kernel_cfg nl_cfg = { ++ .input = h264e_netlink_rcv, ++ }; ++ ++ ++ nl_sk = netlink_kernel_create(&init_net, NETLINK_H264_ENCODER, &nl_cfg); ++ if(!nl_sk) { ++ printk("failed to create netlink\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++ ++/*调用远程的创建上下文.*/ ++int h264e_nl_init_ctx(struct h264e_ctx *ctx, struct nl_ctx_info *info) ++{ ++ /*远端主è¦å¤„ç†çš„内容.*/ ++ int id = 0; ++ unsigned int msg_len = sizeof(struct h264e_nl_msg) + sizeof(struct nl_ctx_info); ++ ++ if(!h264e_rc_server_online) { ++ printk("h264e server not online\n"); ++ return -EINVAL; ++ } ++ ++ struct h264e_nl_msg *msg = kmalloc(msg_len, GFP_KERNEL); ++ ++#if 0 ++ if(!netlink_has_listeners(nl_sk, 1)) { ++ printk("h264e netlink has no listeners, start server first!\n"); ++ return -EINVAL; ++ } ++#endif ++ ++ ctx->pid = NETLINK_H264_PORT; ++ init_completion(&ctx->msg_complete); ++ ++ msg->ctx_id = ctx; /*以ctx的地å€ä½œä¸ºctx_id*/ ++ msg->cmd = VPU_CMD_CREATE_CTX; ++ memcpy(msg->buf, info, sizeof(struct nl_ctx_info)); ++ ++ h264e_netlink_send_msg(ctx, msg, msg_len); ++ ++ ++ /*wait done.*/ ++ ++ kfree(msg); ++ ++ /*return values. */ ++ msg = (struct h264e_nl_msg *)ctx->recved_msg; ++ ++ return msg->ret_val; ++} ++ ++/*é‡Šæ”¾è¿œç«¯çš„ä¸Šä¸‹æ–‡å¥æŸ„.*/ ++int h264e_nl_free_ctx(struct h264e_ctx *ctx) ++{ ++ ++ struct h264e_nl_msg msg; ++ ++ ++ msg.ctx_id = ctx; ++ msg.cmd = VPU_CMD_FREE_CTX; ++ ++ h264e_netlink_send_msg(ctx, &msg, sizeof(struct h264e_nl_msg)); ++ ++ return 0; ++} ++ ++int h264e_nl_setup_headers(struct h264e_ctx *ctx, struct nl_header_info *info) ++{ ++ unsigned int msg_len = sizeof(struct h264e_nl_msg) + sizeof(struct nl_header_info); ++ struct h264e_nl_msg *msg = NULL; ++ ++ if(!h264e_rc_server_online) { ++ printk("%s, %d h264e server not online\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ ++ ++ msg = kmalloc(msg_len, GFP_KERNEL); ++ msg->ctx_id = ctx; ++ msg->cmd = VPU_CMD_SETUP_HEADERS; ++ ++ ++ memcpy(msg->buf, info, sizeof(struct nl_header_info)); ++ ++ h264e_netlink_send_msg(ctx, msg, msg_len); ++ ++ kfree(msg); ++ ++ ++ return 0; ++} ++ ++int h264e_nl_rc_video_cfg(struct h264e_ctx *ctx, struct h264e_params *p) ++{ ++ unsigned int msg_len = sizeof(struct h264e_nl_msg) + sizeof(struct h264e_params); ++ struct h264e_nl_msg *msg = kmalloc(msg_len, GFP_KERNEL); ++ ++ msg->ctx_id = ctx; ++ msg->cmd = VPU_CMD_RC_VIDEO_CFG; ++ ++ memcpy(msg->buf, p, sizeof(struct h264e_params)); ++ ++ h264e_netlink_send_msg(ctx, msg, msg_len); ++ ++ ++ kfree(msg); ++ return 0; ++} ++ ++int h264e_nl_rc_frame_start(struct h264e_ctx *ctx, struct h264e_frame_start_params *p) ++{ ++ unsigned int msg_len = sizeof(struct h264e_nl_msg) + sizeof(struct h264e_frame_start_params); ++ struct h264e_nl_msg *msg = kmalloc(msg_len, GFP_KERNEL); ++ ++ msg->ctx_id = ctx; ++ msg->cmd = VPU_CMD_RC_FRAME_START; ++ ++ memcpy(msg->buf, p, sizeof(struct h264e_frame_start_params)); ++ h264e_netlink_send_msg(ctx, msg, msg_len); ++ /*wait.*/ ++ ++ kfree(msg); ++ ++ /*return values. */ ++ msg = (struct h264e_nl_msg *)ctx->recved_msg; ++ memcpy(p, msg->buf, sizeof(struct h264e_frame_start_params)); ++ ++ return 0; ++} ++ ++int h264e_nl_rc_frame_end(struct h264e_ctx *ctx, struct h264e_frame_end_params *p) ++{ ++ unsigned int msg_len = sizeof(struct h264e_nl_msg) + sizeof(struct h264e_frame_end_params); ++ struct h264e_nl_msg *msg = kmalloc(msg_len, GFP_KERNEL); ++ ++ msg->ctx_id = ctx; ++ msg->cmd = VPU_CMD_RC_FRAME_END; ++ ++ memcpy(msg->buf, p, sizeof(struct h264e_frame_end_params)); ++ h264e_netlink_send_msg(ctx, msg, msg_len); ++ ++ /*wait.*/ ++ ++ kfree(msg); ++ return 0; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_nl.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_nl.h +new file mode 100644 +index 000000000..666a9e301 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_nl.h +@@ -0,0 +1,16 @@ ++#ifndef __H264E_RC_NL_H__ ++#define __H264E_RC_NL_H__ ++ ++ ++#include "h264e_rc_proto.h" ++#include "h264e_rc.h" ++ ++ ++int h264e_nl_init_ctx(struct h264e_ctx *ctx, struct nl_ctx_info *info); ++int h264e_nl_free_ctx(struct h264e_ctx *ctx); ++int h264e_nl_setup_headers(struct h264e_ctx *ctx, struct nl_header_info *info); ++int h264e_nl_rc_video_cfg(struct h264e_ctx *ctx, struct h264e_params *p); ++int h264e_nl_rc_frame_start(struct h264e_ctx *ctx, struct h264e_frame_start_params *p); ++int h264e_nl_rc_frame_end(struct h264e_ctx *ctx, struct h264e_frame_end_params *p); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_proto.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_proto.h +new file mode 100644 +index 000000000..e80a7898a +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264e_rc_proto.h +@@ -0,0 +1,113 @@ ++#ifndef __H264E_RC_PROTO_H__ ++#define __H264E_RC_PROTO_H__ ++ ++ ++/* 创建ctx时,内核æä¾›çš„地å€ä¿¡æ¯. */ ++struct nl_ctx_info { ++ unsigned int vpu_rc_paddr; /*内核申请的VPU_RC_S 的物ç†åœ°å€.*/ ++ unsigned int slice_info_paddr; /*内核申请的Sliceinfo_t 的物ç†åœ°å€.*/ ++ unsigned int emc_buf_paddr; /*内核申请的emc_buf的物ç†åœ°å€.*/ ++ unsigned int desc_paddr; /*内核申请的dma buf的物ç†åœ°å€.*/ ++ uint8_t rc_mode; ++}; ++ ++struct nl_header_info { ++ h264_pps_t pps; ++ h264_sps_t sps; ++}; ++ ++/** ++* @bitrate, set by V4L2_CID_MPEG_VIDEO_BITRATE. ++* @gop_size, group of picture when h264 encoding. ++* ++* used by kernel and app. params across kernel and app. for video_cfg. ++*/ ++struct h264e_params { ++ ++ /* params modify by s_ctrl*/ ++ uint32_t bitrate; ++ uint32_t framerate; ++ int h264_hdr_mode; ++#if 0 ++ uint8_t h264_intra_qp; ++ uint8_t h264_inter_qp; ++#endif ++ uint8_t i_qp; ++ uint8_t p_qp; ++ uint8_t h264_min_qp; ++ uint8_t h264_max_qp; ++ uint8_t h264_profile; ++ uint8_t h264_level; ++ uint8_t gop_size; ++ uint8_t frame_rc_enable; ++ uint8_t mb_rc_enable; ++ uint8_t num_bframe; ++ uint8_t interlaced; ++ uint8_t max_ref_pic; ++ uint8_t h264_8x8_transform; ++ uint8_t rc_mode; ++ ++ uint8_t i_cabac; /*is cabac entropy?*/ ++ ++ int i_idr_pic_id; ++ int i_global_qp; ++ ++ uint8_t deblock; ++ ++ int height; ++ int width; ++ int format; ++ ++}; ++ ++struct h264e_frame_start_params { ++ unsigned int bIFrmReq; ++ unsigned int frmSkipType; ++ ++ ++ /* Slice info. */ ++ //unsigned int des_pa; ++ unsigned int raw_format; ++ unsigned int emc_bs_pa; ++ unsigned int emc_dblk_pa; ++ ++ /* VPU input buffer address. */ ++ unsigned int raw[3]; ++ unsigned int fb[3][2]; ++ unsigned int stride[2]; ++ ++ unsigned int slice_header_len; /*TO kernel.*/ ++}; ++ ++struct h264e_frame_end_params { ++ unsigned int u32FrmActBs; ++}; ++ ++enum { ++ VPU_CMD_CREATE_CTX = 1, ++ VPU_CMD_FREE_CTX, ++ VPU_CMD_SETUP_HEADERS, ++ VPU_CMD_EPRC_SET_DEFAULT, ++ VPU_CMD_RC_VIDEO_CFG, ++ VPU_CMD_RC_FRAME_START, ++ VPU_CMD_RC_FRAME_END, ++ VPU_CMD_SERVER_ONLINE, /*From server to kernel*/ ++ VPU_CMD_SERVER_OFFLINE, /*From server to kernel*/ ++}; ++ ++struct h264e_nl_msg { ++ unsigned int ctx_id; /*当å‰msg对应的ctx id. 当命令为VPU_CMD_CREATE_CTX 时,此值由应用serverå¡«å…….*/ ++ unsigned int cmd; /*当å‰msg对应的调用命令.*/ ++ int ret_val; ++ ++ unsigned char buf[0]; /*Dynamic malloc buffer.*/ ++}; ++ ++ ++#define NETLINK_H264_ENCODER 30 ++#define MAXPALOAD 64 ++ ++#define NETLINK_H264_PORT 0x26402640 ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/bitstream.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/bitstream.h +new file mode 100644 +index 000000000..4fbe594a5 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/bitstream.h +@@ -0,0 +1,242 @@ ++#ifndef __BITSTREAM_H__ ++#define __BITSTREAM_H__ ++ ++typedef struct { ++ uint8_t *p_start; ++ uint8_t *p; ++ uint8_t *p_end; ++ ++ uintptr_t cur_bits; ++ int i_left; ++ int i_bits_encoded; ++} bs_t; ++ ++ ++ ++ ++/* Unions for type-punning. ++ * Mn: load or store n bits, aligned, native-endian ++ * CPn: copy n bits, aligned, native-endian ++ * we don't use memcpy for CPn because memcpy's args aren't assumed to be aligned */ ++typedef union { uint16_t i; uint8_t c[2]; } h264_union16_t; ++typedef union { uint32_t i; uint16_t b[2]; uint8_t c[4]; } h264_union32_t; ++typedef union { uint64_t i; uint32_t a[2]; uint16_t b[4]; uint8_t c[8]; } h264_union64_t; ++typedef struct { uint64_t i[2]; } h264_uint128_t; ++typedef union { h264_uint128_t i; uint64_t a[2]; uint32_t b[4]; uint16_t c[8]; uint8_t d[16]; } h264_union128_t; ++#define M16(src) (((h264_union16_t*)(src))->i) ++#define M32(src) (((h264_union32_t*)(src))->i) ++#define M64(src) (((h264_union64_t*)(src))->i) ++#define M128(src) (((h264_union128_t*)(src))->i) ++#define M128_ZERO ((h264_uint128_t){{0,0}}) ++#define CP16(dst,src) M16(dst) = M16(src) ++#define CP32(dst,src) M32(dst) = M32(src) ++#define CP64(dst,src) M64(dst) = M64(src) ++#define CP128(dst,src) M128(dst) = M128(src) ++ ++ ++ ++ ++/* ++ p_data必须按WORD地å€å¯¹é½ã€‚ ++*/ ++static inline void bs_init(bs_t *s, void *p_data, int i_data) ++{ ++ s->p = s->p_start = (uint8_t *)p_data; ++ s->p_end = (uint8_t *)p_data + i_data; ++ s->i_left = WORD_SIZE * 8; ++ s->cur_bits = endian_fix32(M32(s->p)); ++ s->cur_bits >>= 32; ++} ++ ++static inline int bs_pos(bs_t *s) ++{ ++ return (8 * (s->p - s->p_start) + (WORD_SIZE*8) - s->i_left); ++} ++ ++static inline void bs_flush(bs_t *s) ++{ ++ M32( s->p ) = endian_fix32( s->cur_bits << (s->i_left&31) ); ++ s->p += WORD_SIZE - (s->i_left >> 3); ++ s->i_left = WORD_SIZE*8; ++} ++ ++static inline void bs_realign(bs_t *s) ++{ ++ int offset = ((intptr_t)s->p & 3); ++ if( offset ) ++ { ++ s->p = (uint8_t*)s->p - offset; ++ s->i_left = (WORD_SIZE - offset)*8; ++ s->cur_bits = endian_fix32( M32(s->p) ); ++ s->cur_bits >>= (4-offset)*8; ++ } ++} ++ ++static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits ) ++{ ++ if( i_count < s->i_left ) ++ { ++ s->cur_bits = (s->cur_bits << i_count) | i_bits; ++ s->i_left -= i_count; ++ } ++ else ++ { ++ i_count -= s->i_left; ++ s->cur_bits = (s->cur_bits << s->i_left) | (i_bits >> i_count); ++ M32( s->p ) = endian_fix( s->cur_bits ); ++ s->p += 4; ++ s->cur_bits = i_bits; ++ s->i_left = 32 - i_count; ++ } ++} ++ ++ ++/* Special case to eliminate branch in normal bs_write. */ ++/* Golomb never writes an even-size code, so this is only used in slice headers. */ ++static inline void bs_write32( bs_t *s, uint32_t i_bits ) ++{ ++ bs_write( s, 16, i_bits >> 16 ); ++ bs_write( s, 16, i_bits ); ++} ++ ++static inline void bs_write1( bs_t *s, uint32_t i_bit ) ++{ ++ s->cur_bits <<= 1; ++ s->cur_bits |= i_bit; ++ s->i_left--; ++ if( s->i_left == WORD_SIZE*8-32 ) ++ { ++ M32( s->p ) = endian_fix32( s->cur_bits ); ++ s->p += 4; ++ s->i_left = WORD_SIZE*8; ++ } ++} ++ ++static inline void bs_align_0( bs_t *s ) ++{ ++ bs_write( s, s->i_left&7, 0 ); ++ bs_flush( s ); ++} ++static inline void bs_align_1( bs_t *s ) ++{ ++ bs_write( s, s->i_left&7, (1 << (s->i_left&7)) - 1 ); ++ bs_flush( s ); ++} ++static inline void bs_align_10( bs_t *s ) ++{ ++ if( s->i_left&7 ) ++ bs_write( s, s->i_left&7, 1 << ( (s->i_left&7) - 1 ) ); ++ bs_flush( s ); ++} ++ ++/* golomb functions */ ++ ++static const uint8_t x264_ue_size_tab[256] = ++{ ++ 1, 1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, ++ 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, ++ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, ++ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, ++ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, ++ 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, ++}; ++ ++static inline void bs_write_ue_big( bs_t *s, unsigned int val ) ++{ ++ int size = 0; ++ int tmp = ++val; ++ if( tmp >= 0x10000 ) ++ { ++ size = 32; ++ tmp >>= 16; ++ } ++ if( tmp >= 0x100 ) ++ { ++ size += 16; ++ tmp >>= 8; ++ } ++ size += x264_ue_size_tab[tmp]; ++ bs_write( s, size>>1, 0 ); ++ bs_write( s, (size>>1)+1, val ); ++} ++ ++/* Only works on values under 255. */ ++static inline void bs_write_ue( bs_t *s, int val ) ++{ ++ bs_write( s, x264_ue_size_tab[val+1], val+1 ); ++} ++static inline void bs_write_se( bs_t *s, int val ) ++{ ++ int size = 0; ++ /* Faster than (val <= 0 ? -val*2+1 : val*2) */ ++ /* 4 instructions on x86, 3 on ARM */ ++ int tmp = 1 - val*2; ++ if( tmp < 0 ) tmp = val*2; ++ val = tmp; ++ ++ if( tmp >= 0x100 ) ++ { ++ size = 16; ++ tmp >>= 8; ++ } ++ size += x264_ue_size_tab[tmp]; ++ bs_write( s, size, val ); ++} ++ ++static inline void bs_write_te( bs_t *s, int x, int val ) ++{ ++ if( x == 1 ) ++ bs_write1( s, 1^val ); ++ else //if( x > 1 ) ++ bs_write_ue( s, val ); ++} ++ ++static inline void bs_rbsp_trailing( bs_t *s ) ++{ ++ bs_write1( s, 1 ); ++ bs_write( s, s->i_left&7, 0 ); ++} ++ ++static inline int bs_size_ue( unsigned int val ) ++{ ++ return x264_ue_size_tab[val+1]; ++} ++ ++static inline int bs_size_ue_big( unsigned int val ) ++{ ++ if( val < 255 ) ++ return x264_ue_size_tab[val+1]; ++ else ++ return x264_ue_size_tab[(val+1)>>8] + 16; ++} ++ ++static inline int bs_size_se( int val ) ++{ ++ int tmp = 1 - val*2; ++ if( tmp < 0 ) tmp = val*2; ++ if( tmp < 256 ) ++ return x264_ue_size_tab[tmp]; ++ else ++ return x264_ue_size_tab[tmp>>8]+16; ++} ++ ++static inline int bs_size_te( int x, int val ) ++{ ++ if( x == 1 ) ++ return 1; ++ else //if( x > 1 ) ++ return x264_ue_size_tab[val+1]; ++} ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.c +new file mode 100644 +index 000000000..df2d12f9f +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.c +@@ -0,0 +1,1334 @@ ++#include "common.h" ++ ++static const int8_t h264_cabac_context_init_I[1024][2] = ++{ ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28,127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 unused for I */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, ++ ++ /* 24- 39 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ ++ /* 40 - 53 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, ++ ++ /* 54 - 59 */ ++ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, ++ { 0, 0 }, { 0, 0 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 -> 87 */ ++ { 0, 11 }, { 1, 55 }, { 0, 69 }, { -17, 127 }, ++ { -13, 102 },{ 0, 82 }, { -7, 74 }, { -21, 107 }, ++ { -27, 127 },{ -31, 127 },{ -24, 127 }, { -18, 95 }, ++ { -27, 127 },{ -21, 114 },{ -30, 127 }, { -17, 123 }, ++ { -12, 115 },{ -16, 122 }, ++ ++ /* 88 -> 104 */ ++ { -11, 115 },{ -12, 63 }, { -2, 68 }, { -15, 84 }, ++ { -13, 104 },{ -3, 70 }, { -8, 93 }, { -10, 90 }, ++ { -30, 127 },{ -1, 74 }, { -6, 97 }, { -7, 91 }, ++ { -20, 127 },{ -4, 56 }, { -5, 82 }, { -7, 76 }, ++ { -22, 125 }, ++ ++ /* 105 -> 135 */ ++ { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, ++ { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, ++ { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, ++ { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, ++ { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, ++ { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, ++ { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, ++ { 14, 62 }, { -13, 108 },{ -15, 100 }, ++ ++ /* 136 -> 165 */ ++ { -13, 101 },{ -13, 91 }, { -12, 94 }, { -10, 88 }, ++ { -16, 84 }, { -10, 86 }, { -7, 83 }, { -13, 87 }, ++ { -19, 94 }, { 1, 70 }, { 0, 72 }, { -5, 74 }, ++ { 18, 59 }, { -8, 102 }, { -15, 100 }, { 0, 95 }, ++ { -4, 75 }, { 2, 72 }, { -11, 75 }, { -3, 71 }, ++ { 15, 46 }, { -13, 69 }, { 0, 62 }, { 0, 65 }, ++ { 21, 37 }, { -15, 72 }, { 9, 57 }, { 16, 54 }, ++ { 0, 62 }, { 12, 72 }, ++ ++ /* 166 -> 196 */ ++ { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, ++ { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, ++ { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, ++ { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, ++ { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, ++ { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, ++ { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, ++ { 0, 89 }, { 26, -19 }, { 22, -17 }, ++ ++ /* 197 -> 226 */ ++ { 26, -17 }, { 30, -25 }, { 28, -20 }, { 33, -23 }, ++ { 37, -27 }, { 33, -23 }, { 40, -28 }, { 38, -17 }, ++ { 33, -11 }, { 40, -15 }, { 41, -6 }, { 38, 1 }, ++ { 41, 17 }, { 30, -6 }, { 27, 3 }, { 26, 22 }, ++ { 37, -16 }, { 35, -4 }, { 38, -8 }, { 38, -3 }, ++ { 37, 3 }, { 38, 5 }, { 42, 0 }, { 35, 16 }, ++ { 39, 22 }, { 14, 48 }, { 27, 37 }, { 21, 60 }, ++ { 12, 68 }, { 2, 97 }, ++ ++ /* 227 -> 251 */ ++ { -3, 71 }, { -6, 42 }, { -5, 50 }, { -3, 54 }, ++ { -2, 62 }, { 0, 58 }, { 1, 63 }, { -2, 72 }, ++ { -1, 74 }, { -9, 91 }, { -5, 67 }, { -5, 27 }, ++ { -3, 39 }, { -2, 44 }, { 0, 46 }, { -16, 64 }, ++ { -8, 68 }, { -10, 78 }, { -6, 77 }, { -10, 86 }, ++ { -12, 92 }, { -15, 55 }, { -10, 60 }, { -6, 62 }, ++ { -4, 65 }, ++ ++ /* 252 -> 275 */ ++ { -12, 73 }, { -8, 76 }, { -7, 80 }, { -9, 88 }, ++ { -17, 110 },{ -11, 97 }, { -20, 84 }, { -11, 79 }, ++ { -6, 73 }, { -4, 74 }, { -13, 86 }, { -13, 96 }, ++ { -11, 97 }, { -19, 117 },{ -8, 78 }, { -5, 33 }, ++ { -4, 48 }, { -2, 53 }, { -3, 62 }, { -13, 71 }, ++ { -10, 79 }, { -12, 86 }, { -13, 90 }, { -14, 97 }, ++ ++ /* 276 a bit special (not used, h264_cabac_encode_bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 -> 307 */ ++ { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, ++ { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, ++ { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, ++ { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, ++ { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, ++ { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, ++ { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, ++ { 9, 64 }, { -12, 104 },{ -11, 97 }, ++ ++ /* 308 -> 337 */ ++ { -16, 96 }, { -7, 88 }, { -8, 85 }, { -7, 85 }, ++ { -9, 85 }, { -13, 88 }, { 4, 66 }, { -3, 77 }, ++ { -3, 76 }, { -6, 76 }, { 10, 58 }, { -1, 76 }, ++ { -1, 83 }, { -7, 99 }, { -14, 95 }, { 2, 95 }, ++ { 0, 76 }, { -5, 74 }, { 0, 70 }, { -11, 75 }, ++ { 1, 68 }, { 0, 65 }, { -14, 73 }, { 3, 62 }, ++ { 4, 62 }, { -1, 68 }, { -13, 75 }, { 11, 55 }, ++ { 5, 64 }, { 12, 70 }, ++ ++ /* 338 -> 368 */ ++ { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, ++ { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, ++ { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, ++ { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, ++ { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, ++ { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, ++ { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, ++ { -12, 109 },{ 36, -35 }, { 36, -34 }, ++ ++ /* 369 -> 398 */ ++ { 32, -26 }, { 37, -30 }, { 44, -32 }, { 34, -18 }, ++ { 34, -15 }, { 40, -15 }, { 33, -7 }, { 35, -5 }, ++ { 33, 0 }, { 38, 2 }, { 33, 13 }, { 23, 35 }, ++ { 13, 58 }, { 29, -3 }, { 26, 0 }, { 22, 30 }, ++ { 31, -7 }, { 35, -15 }, { 34, -3 }, { 34, 3 }, ++ { 36, -1 }, { 34, 5 }, { 32, 11 }, { 35, 5 }, ++ { 34, 12 }, { 39, 11 }, { 30, 29 }, { 34, 26 }, ++ { 29, 39 }, { 19, 66 }, ++ ++ /* 399 -> 435 */ ++ { 31, 21 }, { 31, 31 }, { 25, 50 }, ++ { -17, 120 }, { -20, 112 }, { -18, 114 }, { -11, 85 }, ++ { -15, 92 }, { -14, 89 }, { -26, 71 }, { -15, 81 }, ++ { -14, 80 }, { 0, 68 }, { -14, 70 }, { -24, 56 }, ++ { -23, 68 }, { -24, 50 }, { -11, 74 }, { 23, -13 }, ++ { 26, -13 }, { 40, -15 }, { 49, -14 }, { 44, 3 }, ++ { 45, 6 }, { 44, 34 }, { 33, 54 }, { 19, 82 }, ++ { -3, 75 }, { -1, 23 }, { 1, 34 }, { 1, 43 }, ++ { 0, 54 }, { -2, 55 }, { 0, 61 }, { 1, 64 }, ++ { 0, 68 }, { -9, 92 }, ++ ++ /* 436 -> 459 */ ++ { -14, 106 }, { -13, 97 }, { -15, 90 }, { -12, 90 }, ++ { -18, 88 }, { -10, 73 }, { -9, 79 }, { -14, 86 }, ++ { -10, 73 }, { -10, 70 }, { -10, 69 }, { -5, 66 }, ++ { -9, 64 }, { -5, 58 }, { 2, 59 }, { 21, -10 }, ++ { 24, -11 }, { 28, -8 }, { 28, -1 }, { 29, 3 }, ++ { 29, 9 }, { 35, 20 }, { 29, 36 }, { 14, 67 }, ++ ++ /* 460 -> 1024 */ ++ { -17, 123 }, { -12, 115 }, { -16, 122 }, { -11, 115 }, ++ { -12, 63 }, { -2, 68 }, { -15, 84 }, { -13, 104 }, ++ { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, ++ { -17, 123 }, { -12, 115 }, { -16, 122 }, { -11, 115 }, ++ { -12, 63 }, { -2, 68 }, { -15, 84 }, { -13, 104 }, ++ { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, ++ { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, ++ { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, ++ { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, ++ { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, ++ { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, ++ { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, ++ { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, ++ { 14, 62 }, { -13, 108 }, { -15, 100 }, { -13, 101 }, ++ { -13, 91 }, { -12, 94 }, { -10, 88 }, { -16, 84 }, ++ { -10, 86 }, { -7, 83 }, { -13, 87 }, { -19, 94 }, ++ { 1, 70 }, { 0, 72 }, { -5, 74 }, { 18, 59 }, ++ { -7, 93 }, { -11, 87 }, { -3, 77 }, { -5, 71 }, ++ { -4, 63 }, { -4, 68 }, { -12, 84 }, { -7, 62 }, ++ { -7, 65 }, { 8, 61 }, { 5, 56 }, { -2, 66 }, ++ { 1, 64 }, { 0, 61 }, { -2, 78 }, { 1, 50 }, ++ { 7, 52 }, { 10, 35 }, { 0, 44 }, { 11, 38 }, ++ { 1, 45 }, { 0, 46 }, { 5, 44 }, { 31, 17 }, ++ { 1, 51 }, { 7, 50 }, { 28, 19 }, { 16, 33 }, ++ { 14, 62 }, { -13, 108 }, { -15, 100 }, { -13, 101 }, ++ { -13, 91 }, { -12, 94 }, { -10, 88 }, { -16, 84 }, ++ { -10, 86 }, { -7, 83 }, { -13, 87 }, { -19, 94 }, ++ { 1, 70 }, { 0, 72 }, { -5, 74 }, { 18, 59 }, ++ { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, ++ { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, ++ { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, ++ { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, ++ { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, ++ { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, ++ { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, ++ { 0, 89 }, { 26, -19 }, { 22, -17 }, { 26, -17 }, ++ { 30, -25 }, { 28, -20 }, { 33, -23 }, { 37, -27 }, ++ { 33, -23 }, { 40, -28 }, { 38, -17 }, { 33, -11 }, ++ { 40, -15 }, { 41, -6 }, { 38, 1 }, { 41, 17 }, ++ { 24, 0 }, { 15, 9 }, { 8, 25 }, { 13, 18 }, ++ { 15, 9 }, { 13, 19 }, { 10, 37 }, { 12, 18 }, ++ { 6, 29 }, { 20, 33 }, { 15, 30 }, { 4, 45 }, ++ { 1, 58 }, { 0, 62 }, { 7, 61 }, { 12, 38 }, ++ { 11, 45 }, { 15, 39 }, { 11, 42 }, { 13, 44 }, ++ { 16, 45 }, { 12, 41 }, { 10, 49 }, { 30, 34 }, ++ { 18, 42 }, { 10, 55 }, { 17, 51 }, { 17, 46 }, ++ { 0, 89 }, { 26, -19 }, { 22, -17 }, { 26, -17 }, ++ { 30, -25 }, { 28, -20 }, { 33, -23 }, { 37, -27 }, ++ { 33, -23 }, { 40, -28 }, { 38, -17 }, { 33, -11 }, ++ { 40, -15 }, { 41, -6 }, { 38, 1 }, { 41, 17 }, ++ { -17, 120 }, { -20, 112 }, { -18, 114 }, { -11, 85 }, ++ { -15, 92 }, { -14, 89 }, { -26, 71 }, { -15, 81 }, ++ { -14, 80 }, { 0, 68 }, { -14, 70 }, { -24, 56 }, ++ { -23, 68 }, { -24, 50 }, { -11, 74 }, { -14, 106 }, ++ { -13, 97 }, { -15, 90 }, { -12, 90 }, { -18, 88 }, ++ { -10, 73 }, { -9, 79 }, { -14, 86 }, { -10, 73 }, ++ { -10, 70 }, { -10, 69 }, { -5, 66 }, { -9, 64 }, ++ { -5, 58 }, { 2, 59 }, { 23, -13 }, { 26, -13 }, ++ { 40, -15 }, { 49, -14 }, { 44, 3 }, { 45, 6 }, ++ { 44, 34 }, { 33, 54 }, { 19, 82 }, { 21, -10 }, ++ { 24, -11 }, { 28, -8 }, { 28, -1 }, { 29, 3 }, ++ { 29, 9 }, { 35, 20 }, { 29, 36 }, { 14, 67 }, ++ { -3, 75 }, { -1, 23 }, { 1, 34 }, { 1, 43 }, ++ { 0, 54 }, { -2, 55 }, { 0, 61 }, { 1, 64 }, ++ { 0, 68 }, { -9, 92 }, { -17, 120 }, { -20, 112 }, ++ { -18, 114 }, { -11, 85 }, { -15, 92 }, { -14, 89 }, ++ { -26, 71 }, { -15, 81 }, { -14, 80 }, { 0, 68 }, ++ { -14, 70 }, { -24, 56 }, { -23, 68 }, { -24, 50 }, ++ { -11, 74 }, { -14, 106 }, { -13, 97 }, { -15, 90 }, ++ { -12, 90 }, { -18, 88 }, { -10, 73 }, { -9, 79 }, ++ { -14, 86 }, { -10, 73 }, { -10, 70 }, { -10, 69 }, ++ { -5, 66 }, { -9, 64 }, { -5, 58 }, { 2, 59 }, ++ { 23, -13 }, { 26, -13 }, { 40, -15 }, { 49, -14 }, ++ { 44, 3 }, { 45, 6 }, { 44, 34 }, { 33, 54 }, ++ { 19, 82 }, { 21, -10 }, { 24, -11 }, { 28, -8 }, ++ { 28, -1 }, { 29, 3 }, { 29, 9 }, { 35, 20 }, ++ { 29, 36 }, { 14, 67 }, { -3, 75 }, { -1, 23 }, ++ { 1, 34 }, { 1, 43 }, { 0, 54 }, { -2, 55 }, ++ { 0, 61 }, { 1, 64 }, { 0, 68 }, { -9, 92 }, ++ { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, ++ { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, ++ { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, ++ { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, ++ { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, ++ { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, ++ { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, ++ { 9, 64 }, { -12, 104 }, { -11, 97 }, { -16, 96 }, ++ { -7, 88 }, { -8, 85 }, { -7, 85 }, { -9, 85 }, ++ { -13, 88 }, { 4, 66 }, { -3, 77 }, { -3, 76 }, ++ { -6, 76 }, { 10, 58 }, { -1, 76 }, { -1, 83 }, ++ { -6, 93 }, { -6, 84 }, { -8, 79 }, { 0, 66 }, ++ { -1, 71 }, { 0, 62 }, { -2, 60 }, { -2, 59 }, ++ { -5, 75 }, { -3, 62 }, { -4, 58 }, { -9, 66 }, ++ { -1, 79 }, { 0, 71 }, { 3, 68 }, { 10, 44 }, ++ { -7, 62 }, { 15, 36 }, { 14, 40 }, { 16, 27 }, ++ { 12, 29 }, { 1, 44 }, { 20, 36 }, { 18, 32 }, ++ { 5, 42 }, { 1, 48 }, { 10, 62 }, { 17, 46 }, ++ { 9, 64 }, { -12, 104 }, { -11, 97 }, { -16, 96 }, ++ { -7, 88 }, { -8, 85 }, { -7, 85 }, { -9, 85 }, ++ { -13, 88 }, { 4, 66 }, { -3, 77 }, { -3, 76 }, ++ { -6, 76 }, { 10, 58 }, { -1, 76 }, { -1, 83 }, ++ { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, ++ { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, ++ { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, ++ { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, ++ { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, ++ { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, ++ { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, ++ { -12, 109 }, { 36, -35 }, { 36, -34 }, { 32, -26 }, ++ { 37, -30 }, { 44, -32 }, { 34, -18 }, { 34, -15 }, ++ { 40, -15 }, { 33, -7 }, { 35, -5 }, { 33, 0 }, ++ { 38, 2 }, { 33, 13 }, { 23, 35 }, { 13, 58 }, ++ { 15, 6 }, { 6, 19 }, { 7, 16 }, { 12, 14 }, ++ { 18, 13 }, { 13, 11 }, { 13, 15 }, { 15, 16 }, ++ { 12, 23 }, { 13, 23 }, { 15, 20 }, { 14, 26 }, ++ { 14, 44 }, { 17, 40 }, { 17, 47 }, { 24, 17 }, ++ { 21, 21 }, { 25, 22 }, { 31, 27 }, { 22, 29 }, ++ { 19, 35 }, { 14, 50 }, { 10, 57 }, { 7, 63 }, ++ { -2, 77 }, { -4, 82 }, { -3, 94 }, { 9, 69 }, ++ { -12, 109 }, { 36, -35 }, { 36, -34 }, { 32, -26 }, ++ { 37, -30 }, { 44, -32 }, { 34, -18 }, { 34, -15 }, ++ { 40, -15 }, { 33, -7 }, { 35, -5 }, { 33, 0 }, ++ { 38, 2 }, { 33, 13 }, { 23, 35 }, { 13, 58 }, ++ { -3, 71 }, { -6, 42 }, { -5, 50 }, { -3, 54 }, ++ { -2, 62 }, { 0, 58 }, { 1, 63 }, { -2, 72 }, ++ { -1, 74 }, { -9, 91 }, { -5, 67 }, { -5, 27 }, ++ { -3, 39 }, { -2, 44 }, { 0, 46 }, { -16, 64 }, ++ { -8, 68 }, { -10, 78 }, { -6, 77 }, { -10, 86 }, ++ { -12, 92 }, { -15, 55 }, { -10, 60 }, { -6, 62 }, ++ { -4, 65 }, { -12, 73 }, { -8, 76 }, { -7, 80 }, ++ { -9, 88 }, { -17, 110 }, { -3, 71 }, { -6, 42 }, ++ { -5, 50 }, { -3, 54 }, { -2, 62 }, { 0, 58 }, ++ { 1, 63 }, { -2, 72 }, { -1, 74 }, { -9, 91 }, ++ { -5, 67 }, { -5, 27 }, { -3, 39 }, { -2, 44 }, ++ { 0, 46 }, { -16, 64 }, { -8, 68 }, { -10, 78 }, ++ { -6, 77 }, { -10, 86 }, { -12, 92 }, { -15, 55 }, ++ { -10, 60 }, { -6, 62 }, { -4, 65 }, { -12, 73 }, ++ { -8, 76 }, { -7, 80 }, { -9, 88 }, { -17, 110 }, ++ { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, ++ { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 }, ++ { -3, 70 }, { -8, 93 }, { -10, 90 }, { -30, 127 } ++}; ++ ++static const int8_t h264_cabac_context_init_PB[3][1024][2] = ++{ ++ /* i_cabac_init_idc == 0 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 23, 33 }, { 23, 2 }, { 21, 0 }, { 1, 9 }, ++ { 0, 49 }, { -37, 118 }, { 5, 57 }, { -13, 78 }, ++ { -11, 65 }, { 1, 62 }, { 12, 49 }, { -4, 73 }, ++ { 17, 50 }, ++ ++ /* 24 - 39 */ ++ { 18, 64 }, { 9, 43 }, { 29, 0 }, { 26, 67 }, ++ { 16, 90 }, { 9, 104 }, { -46, 127 }, { -20, 104 }, ++ { 1, 67 }, { -13, 78 }, { -11, 65 }, { 1, 62 }, ++ { -6, 86 }, { -17, 95 }, { -6, 61 }, { 9, 45 }, ++ ++ /* 40 - 53 */ ++ { -3, 69 }, { -6, 81 }, { -11, 96 }, { 6, 55 }, ++ { 7, 67 }, { -5, 86 }, { 2, 88 }, { 0, 58 }, ++ { -3, 76 }, { -10, 94 }, { 5, 54 }, { 4, 69 }, ++ { -3, 81 }, { 0, 88 }, ++ ++ /* 54 - 59 */ ++ { -7, 67 }, { -5, 74 }, { -4, 74 }, { -5, 80 }, ++ { -7, 72 }, { 1, 58 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 87 */ ++ { 0, 45 }, { -4, 78 }, { -3, 96 }, { -27, 126 }, ++ { -28, 98 }, { -25, 101 }, { -23, 67 }, { -28, 82 }, ++ { -20, 94 }, { -16, 83 }, { -22, 110 }, { -21, 91 }, ++ { -18, 102 }, { -13, 93 }, { -29, 127 }, { -7, 92 }, ++ { -5, 89 }, { -7, 96 }, { -13, 108 }, { -3, 46 }, ++ { -1, 65 }, { -1, 57 }, { -9, 93 }, { -3, 74 }, ++ { -9, 92 }, { -8, 87 }, { -23, 126 }, { 5, 54 }, ++ { 6, 60 }, { 6, 59 }, { 6, 69 }, { -1, 48 }, ++ { 0, 68 }, { -4, 69 }, { -8, 88 }, ++ ++ /* 105 -> 165 */ ++ { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, ++ { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, ++ { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, ++ { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, ++ { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, ++ { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, ++ { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, ++ { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, ++ { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, ++ { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, ++ { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, ++ { 3, 64 }, { 1, 61 }, { 9, 63 }, { 7, 50 }, ++ { 16, 39 }, { 5, 44 }, { 4, 52 }, { 11, 48 }, ++ { -5, 60 }, { -1, 59 }, { 0, 59 }, { 22, 33 }, ++ { 5, 44 }, { 14, 43 }, { -1, 78 }, { 0, 60 }, ++ { 9, 69 }, ++ ++ /* 166 - 226 */ ++ { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, ++ { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, ++ { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, ++ { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, ++ { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, ++ { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, ++ { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, ++ { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, ++ { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, ++ { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, ++ { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, ++ { 1, 67 }, { 5, 59 }, { 9, 67 }, { 16, 30 }, ++ { 18, 32 }, { 18, 35 }, { 22, 29 }, { 24, 31 }, ++ { 23, 38 }, { 18, 43 }, { 20, 41 }, { 11, 63 }, ++ { 9, 59 }, { 9, 64 }, { -1, 94 }, { -2, 89 }, ++ { -9, 108 }, ++ ++ /* 227 - 275 */ ++ { -6, 76 }, { -2, 44 }, { 0, 45 }, { 0, 52 }, ++ { -3, 64 }, { -2, 59 }, { -4, 70 }, { -4, 75 }, ++ { -8, 82 }, { -17, 102 }, { -9, 77 }, { 3, 24 }, ++ { 0, 42 }, { 0, 48 }, { 0, 55 }, { -6, 59 }, ++ { -7, 71 }, { -12, 83 }, { -11, 87 }, { -30, 119 }, ++ { 1, 58 }, { -3, 29 }, { -1, 36 }, { 1, 38 }, ++ { 2, 43 }, { -6, 55 }, { 0, 58 }, { 0, 64 }, ++ { -3, 74 }, { -10, 90 }, { 0, 70 }, { -4, 29 }, ++ { 5, 31 }, { 7, 42 }, { 1, 59 }, { -2, 58 }, ++ { -3, 72 }, { -3, 81 }, { -11, 97 }, { 0, 58 }, ++ { 8, 5 }, { 10, 14 }, { 14, 18 }, { 13, 27 }, ++ { 2, 40 }, { 0, 58 }, { -3, 70 }, { -6, 79 }, ++ { -8, 85 }, ++ ++ /* 276 a bit special (not used, h264_cabac_encode_bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, ++ { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, ++ { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, ++ { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, ++ { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, ++ { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, ++ { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, ++ { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, ++ { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, ++ { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, ++ { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, ++ { -2, 69 }, { -2, 59 }, { 6, 70 }, { 10, 44 }, ++ { 9, 31 }, { 12, 43 }, { 3, 53 }, { 14, 34 }, ++ { 10, 38 }, { -3, 52 }, { 13, 40 }, { 17, 32 }, ++ { 7, 44 }, { 7, 38 }, { 13, 50 }, { 10, 57 }, ++ { 26, 43 }, ++ ++ /* 338 - 398 */ ++ { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, ++ { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, ++ { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, ++ { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, ++ { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, ++ { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, ++ { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, ++ { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, ++ { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, ++ { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, ++ { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, ++ { 8, 60 }, { 6, 63 }, { 17, 65 }, { 21, 24 }, ++ { 23, 20 }, { 26, 23 }, { 27, 32 }, { 28, 23 }, ++ { 28, 24 }, { 23, 40 }, { 24, 32 }, { 28, 29 }, ++ { 23, 42 }, { 19, 57 }, { 22, 53 }, { 22, 61 }, ++ { 11, 86 }, ++ ++ /* 399 -> 435 */ ++ { 12, 40 }, { 11, 51 }, { 14, 59 }, ++ { -4, 79 }, { -7, 71 }, { -5, 69 }, { -9, 70 }, ++ { -8, 66 }, { -10, 68 }, { -19, 73 }, { -12, 69 }, ++ { -16, 70 }, { -15, 67 }, { -20, 62 }, { -19, 70 }, ++ { -16, 66 }, { -22, 65 }, { -20, 63 }, { 9, -2 }, ++ { 26, -9 }, { 33, -9 }, { 39, -7 }, { 41, -2 }, ++ { 45, 3 }, { 49, 9 }, { 45, 27 }, { 36, 59 }, ++ { -6, 66 }, { -7, 35 }, { -7, 42 }, { -8, 45 }, ++ { -5, 48 }, { -12, 56 }, { -6, 60 }, { -5, 62 }, ++ { -8, 66 }, { -8, 76 }, ++ ++ /* 436 -> 459 */ ++ { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, ++ { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, ++ { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, ++ { -14, 66 }, { 0, 59 }, { 2, 59 }, { 21, -13 }, ++ { 33, -14 }, { 39, -7 }, { 46, -2 }, { 51, 2 }, ++ { 60, 6 }, { 61, 17 }, { 55, 34 }, { 42, 62 }, ++ ++ /* 460 - 1024 */ ++ { -7, 92 }, { -5, 89 }, { -7, 96 }, { -13, 108 }, ++ { -3, 46 }, { -1, 65 }, { -1, 57 }, { -9, 93 }, ++ { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, ++ { -7, 92 }, { -5, 89 }, { -7, 96 }, { -13, 108 }, ++ { -3, 46 }, { -1, 65 }, { -1, 57 }, { -9, 93 }, ++ { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, ++ { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, ++ { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, ++ { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, ++ { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, ++ { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, ++ { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, ++ { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, ++ { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, ++ { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, ++ { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, ++ { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, ++ { -2, 85 }, { -6, 78 }, { -1, 75 }, { -7, 77 }, ++ { 2, 54 }, { 5, 50 }, { -3, 68 }, { 1, 50 }, ++ { 6, 42 }, { -4, 81 }, { 1, 63 }, { -4, 70 }, ++ { 0, 67 }, { 2, 57 }, { -2, 76 }, { 11, 35 }, ++ { 4, 64 }, { 1, 61 }, { 11, 35 }, { 18, 25 }, ++ { 12, 24 }, { 13, 29 }, { 13, 36 }, { -10, 93 }, ++ { -7, 73 }, { -2, 73 }, { 13, 46 }, { 9, 49 }, ++ { -7, 100 }, { 9, 53 }, { 2, 53 }, { 5, 53 }, ++ { -2, 61 }, { 0, 56 }, { 0, 56 }, { -13, 63 }, ++ { -5, 60 }, { -1, 62 }, { 4, 57 }, { -6, 69 }, ++ { 4, 57 }, { 14, 39 }, { 4, 51 }, { 13, 68 }, ++ { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, ++ { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, ++ { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, ++ { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, ++ { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, ++ { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, ++ { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, ++ { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, ++ { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, ++ { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, ++ { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, ++ { 11, 28 }, { 2, 40 }, { 3, 44 }, { 0, 49 }, ++ { 0, 46 }, { 2, 44 }, { 2, 51 }, { 0, 47 }, ++ { 4, 39 }, { 2, 62 }, { 6, 46 }, { 0, 54 }, ++ { 3, 54 }, { 2, 58 }, { 4, 63 }, { 6, 51 }, ++ { 6, 57 }, { 7, 53 }, { 6, 52 }, { 6, 55 }, ++ { 11, 45 }, { 14, 36 }, { 8, 53 }, { -1, 82 }, ++ { 7, 55 }, { -3, 78 }, { 15, 46 }, { 22, 31 }, ++ { -1, 84 }, { 25, 7 }, { 30, -7 }, { 28, 3 }, ++ { 28, 4 }, { 32, 0 }, { 34, -1 }, { 30, 6 }, ++ { 30, 6 }, { 32, 9 }, { 31, 19 }, { 26, 27 }, ++ { 26, 30 }, { 37, 20 }, { 28, 34 }, { 17, 70 }, ++ { -4, 79 }, { -7, 71 }, { -5, 69 }, { -9, 70 }, ++ { -8, 66 }, { -10, 68 }, { -19, 73 }, { -12, 69 }, ++ { -16, 70 }, { -15, 67 }, { -20, 62 }, { -19, 70 }, ++ { -16, 66 }, { -22, 65 }, { -20, 63 }, { -5, 85 }, ++ { -6, 81 }, { -10, 77 }, { -7, 81 }, { -17, 80 }, ++ { -18, 73 }, { -4, 74 }, { -10, 83 }, { -9, 71 }, ++ { -9, 67 }, { -1, 61 }, { -8, 66 }, { -14, 66 }, ++ { 0, 59 }, { 2, 59 }, { 9, -2 }, { 26, -9 }, ++ { 33, -9 }, { 39, -7 }, { 41, -2 }, { 45, 3 }, ++ { 49, 9 }, { 45, 27 }, { 36, 59 }, { 21, -13 }, ++ { 33, -14 }, { 39, -7 }, { 46, -2 }, { 51, 2 }, ++ { 60, 6 }, { 61, 17 }, { 55, 34 }, { 42, 62 }, ++ { -6, 66 }, { -7, 35 }, { -7, 42 }, { -8, 45 }, ++ { -5, 48 }, { -12, 56 }, { -6, 60 }, { -5, 62 }, ++ { -8, 66 }, { -8, 76 }, { -4, 79 }, { -7, 71 }, ++ { -5, 69 }, { -9, 70 }, { -8, 66 }, { -10, 68 }, ++ { -19, 73 }, { -12, 69 }, { -16, 70 }, { -15, 67 }, ++ { -20, 62 }, { -19, 70 }, { -16, 66 }, { -22, 65 }, ++ { -20, 63 }, { -5, 85 }, { -6, 81 }, { -10, 77 }, ++ { -7, 81 }, { -17, 80 }, { -18, 73 }, { -4, 74 }, ++ { -10, 83 }, { -9, 71 }, { -9, 67 }, { -1, 61 }, ++ { -8, 66 }, { -14, 66 }, { 0, 59 }, { 2, 59 }, ++ { 9, -2 }, { 26, -9 }, { 33, -9 }, { 39, -7 }, ++ { 41, -2 }, { 45, 3 }, { 49, 9 }, { 45, 27 }, ++ { 36, 59 }, { 21, -13 }, { 33, -14 }, { 39, -7 }, ++ { 46, -2 }, { 51, 2 }, { 60, 6 }, { 61, 17 }, ++ { 55, 34 }, { 42, 62 }, { -6, 66 }, { -7, 35 }, ++ { -7, 42 }, { -8, 45 }, { -5, 48 }, { -12, 56 }, ++ { -6, 60 }, { -5, 62 }, { -8, 66 }, { -8, 76 }, ++ { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, ++ { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, ++ { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, ++ { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, ++ { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, ++ { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, ++ { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, ++ { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, ++ { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, ++ { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, ++ { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, ++ { -13, 106 }, { -16, 106 }, { -10, 87 }, { -21, 114 }, ++ { -18, 110 }, { -14, 98 }, { -22, 110 }, { -21, 106 }, ++ { -18, 103 }, { -21, 107 }, { -23, 108 }, { -26, 112 }, ++ { -10, 96 }, { -12, 95 }, { -5, 91 }, { -9, 93 }, ++ { -22, 94 }, { -5, 86 }, { 9, 67 }, { -4, 80 }, ++ { -10, 85 }, { -1, 70 }, { 7, 60 }, { 9, 58 }, ++ { 5, 61 }, { 12, 50 }, { 15, 50 }, { 18, 49 }, ++ { 17, 54 }, { 10, 41 }, { 7, 46 }, { -1, 51 }, ++ { 7, 49 }, { 8, 52 }, { 9, 41 }, { 6, 47 }, ++ { 2, 55 }, { 13, 41 }, { 10, 44 }, { 6, 50 }, ++ { 5, 53 }, { 13, 49 }, { 4, 63 }, { 6, 64 }, ++ { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, ++ { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, ++ { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, ++ { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, ++ { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, ++ { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, ++ { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, ++ { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, ++ { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, ++ { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, ++ { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, ++ { 14, 11 }, { 11, 14 }, { 9, 11 }, { 18, 11 }, ++ { 21, 9 }, { 23, -2 }, { 32, -15 }, { 32, -15 }, ++ { 34, -21 }, { 39, -23 }, { 42, -33 }, { 41, -31 }, ++ { 46, -28 }, { 38, -12 }, { 21, 29 }, { 45, -24 }, ++ { 53, -45 }, { 48, -26 }, { 65, -43 }, { 43, -19 }, ++ { 39, -10 }, { 30, 9 }, { 18, 26 }, { 20, 27 }, ++ { 0, 57 }, { -14, 82 }, { -5, 75 }, { -19, 97 }, ++ { -35, 125 }, { 27, 0 }, { 28, 0 }, { 31, -4 }, ++ { 27, 6 }, { 34, 8 }, { 30, 10 }, { 24, 22 }, ++ { 33, 19 }, { 22, 32 }, { 26, 31 }, { 21, 41 }, ++ { 26, 44 }, { 23, 47 }, { 16, 65 }, { 14, 71 }, ++ { -6, 76 }, { -2, 44 }, { 0, 45 }, { 0, 52 }, ++ { -3, 64 }, { -2, 59 }, { -4, 70 }, { -4, 75 }, ++ { -8, 82 }, { -17, 102 }, { -9, 77 }, { 3, 24 }, ++ { 0, 42 }, { 0, 48 }, { 0, 55 }, { -6, 59 }, ++ { -7, 71 }, { -12, 83 }, { -11, 87 }, { -30, 119 }, ++ { 1, 58 }, { -3, 29 }, { -1, 36 }, { 1, 38 }, ++ { 2, 43 }, { -6, 55 }, { 0, 58 }, { 0, 64 }, ++ { -3, 74 }, { -10, 90 }, { -6, 76 }, { -2, 44 }, ++ { 0, 45 }, { 0, 52 }, { -3, 64 }, { -2, 59 }, ++ { -4, 70 }, { -4, 75 }, { -8, 82 }, { -17, 102 }, ++ { -9, 77 }, { 3, 24 }, { 0, 42 }, { 0, 48 }, ++ { 0, 55 }, { -6, 59 }, { -7, 71 }, { -12, 83 }, ++ { -11, 87 }, { -30, 119 }, { 1, 58 }, { -3, 29 }, ++ { -1, 36 }, { 1, 38 }, { 2, 43 }, { -6, 55 }, ++ { 0, 58 }, { 0, 64 }, { -3, 74 }, { -10, 90 }, ++ { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, ++ { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 }, ++ { -3, 74 }, { -9, 92 }, { -8, 87 }, { -23, 126 } ++ }, ++ ++ /* i_cabac_init_idc == 1 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 22, 25 }, { 34, 0 }, { 16, 0 }, { -2, 9 }, ++ { 4, 41 }, { -29, 118 }, { 2, 65 }, { -6, 71 }, ++ { -13, 79 }, { 5, 52 }, { 9, 50 }, { -3, 70 }, ++ { 10, 54 }, ++ ++ /* 24 - 39 */ ++ { 26, 34 }, { 19, 22 }, { 40, 0 }, { 57, 2 }, ++ { 41, 36 }, { 26, 69 }, { -45, 127 }, { -15, 101 }, ++ { -4, 76 }, { -6, 71 }, { -13, 79 }, { 5, 52 }, ++ { 6, 69 }, { -13, 90 }, { 0, 52 }, { 8, 43 }, ++ ++ /* 40 - 53 */ ++ { -2, 69 },{ -5, 82 },{ -10, 96 },{ 2, 59 }, ++ { 2, 75 },{ -3, 87 },{ -3, 100 },{ 1, 56 }, ++ { -3, 74 },{ -6, 85 },{ 0, 59 },{ -3, 81 }, ++ { -7, 86 },{ -5, 95 }, ++ ++ /* 54 - 59 */ ++ { -1, 66 },{ -1, 77 },{ 1, 70 },{ -2, 86 }, ++ { -5, 72 },{ 0, 61 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 104 */ ++ { 13, 15 }, { 7, 51 }, { 2, 80 }, { -39, 127 }, ++ { -18, 91 }, { -17, 96 }, { -26, 81 }, { -35, 98 }, ++ { -24, 102 }, { -23, 97 }, { -27, 119 }, { -24, 99 }, ++ { -21, 110 }, { -18, 102 }, { -36, 127 }, { 0, 80 }, ++ { -5, 89 }, { -7, 94 }, { -4, 92 }, { 0, 39 }, ++ { 0, 65 }, { -15, 84 }, { -35, 127 }, { -2, 73 }, ++ { -12, 104 }, { -9, 91 }, { -31, 127 }, { 3, 55 }, ++ { 7, 56 }, { 7, 55 }, { 8, 61 }, { -3, 53 }, ++ { 0, 68 }, { -7, 74 }, { -9, 88 }, ++ ++ /* 105 -> 165 */ ++ { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, ++ { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, ++ { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, ++ { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, ++ { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, ++ { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, ++ { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, ++ { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, ++ { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, ++ { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, ++ { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, ++ { -4, 71 }, { 0, 58 }, { 7, 61 }, { 9, 41 }, ++ { 18, 25 }, { 9, 32 }, { 5, 43 }, { 9, 47 }, ++ { 0, 44 }, { 0, 51 }, { 2, 46 }, { 19, 38 }, ++ { -4, 66 }, { 15, 38 }, { 12, 42 }, { 9, 34 }, ++ { 0, 89 }, ++ ++ /* 166 - 226 */ ++ { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, ++ { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, ++ { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, ++ { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, ++ { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, ++ { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, ++ { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, ++ { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, ++ { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, ++ { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, ++ { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, ++ { 0, 75 }, { 2, 72 }, { 8, 77 }, { 14, 35 }, ++ { 18, 31 }, { 17, 35 }, { 21, 30 }, { 17, 45 }, ++ { 20, 42 }, { 18, 45 }, { 27, 26 }, { 16, 54 }, ++ { 7, 66 }, { 16, 56 }, { 11, 73 }, { 10, 67 }, ++ { -10, 116 }, ++ ++ /* 227 - 275 */ ++ { -23, 112 }, { -15, 71 }, { -7, 61 }, { 0, 53 }, ++ { -5, 66 }, { -11, 77 }, { -9, 80 }, { -9, 84 }, ++ { -10, 87 }, { -34, 127 }, { -21, 101 }, { -3, 39 }, ++ { -5, 53 }, { -7, 61 }, { -11, 75 }, { -15, 77 }, ++ { -17, 91 }, { -25, 107 }, { -25, 111 }, { -28, 122 }, ++ { -11, 76 }, { -10, 44 }, { -10, 52 }, { -10, 57 }, ++ { -9, 58 }, { -16, 72 }, { -7, 69 }, { -4, 69 }, ++ { -5, 74 }, { -9, 86 }, { 2, 66 }, { -9, 34 }, ++ { 1, 32 }, { 11, 31 }, { 5, 52 }, { -2, 55 }, ++ { -2, 67 }, { 0, 73 }, { -8, 89 }, { 3, 52 }, ++ { 7, 4 }, { 10, 8 }, { 17, 8 }, { 16, 19 }, ++ { 3, 37 }, { -1, 61 }, { -5, 73 }, { -1, 70 }, ++ { -4, 78 }, ++ ++ /* 276 a bit special (not used, h264_cabac_encode_bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, ++ { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, ++ { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, ++ { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, ++ { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, ++ { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, ++ { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, ++ { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, ++ { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, ++ { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, ++ { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, ++ { -1, 70 }, { -9, 72 }, { 14, 60 }, { 16, 37 }, ++ { 0, 47 }, { 18, 35 }, { 11, 37 }, { 12, 41 }, ++ { 10, 41 }, { 2, 48 }, { 12, 41 }, { 13, 41 }, ++ { 0, 59 }, { 3, 50 }, { 19, 40 }, { 3, 66 }, ++ { 18, 50 }, ++ ++ /* 338 - 398 */ ++ { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, ++ { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, ++ { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, ++ { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, ++ { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, ++ { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, ++ { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, ++ { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, ++ { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, ++ { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, ++ { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, ++ { 12, 48 }, { 11, 49 }, { 26, 45 }, { 22, 22 }, ++ { 23, 22 }, { 27, 21 }, { 33, 20 }, { 26, 28 }, ++ { 30, 24 }, { 27, 34 }, { 18, 42 }, { 25, 39 }, ++ { 18, 50 }, { 12, 70 }, { 21, 54 }, { 14, 71 }, ++ { 11, 83 }, ++ ++ /* 399 -> 435 */ ++ { 25, 32 }, { 21, 49 }, { 21, 54 }, ++ { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, ++ { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, ++ { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, ++ { -14, 66 }, { 0, 59 }, { 2, 59 }, { 17, -10 }, ++ { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, ++ { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, ++ { -5, 71 }, { 0, 24 }, { -1, 36 }, { -2, 42 }, ++ { -2, 52 }, { -9, 57 }, { -6, 63 }, { -4, 65 }, ++ { -4, 67 }, { -7, 82 }, ++ ++ /* 436 -> 459 */ ++ { -3, 81 }, { -3, 76 }, { -7, 72 }, { -6, 78 }, ++ { -12, 72 }, { -14, 68 }, { -3, 70 }, { -6, 76 }, ++ { -5, 66 }, { -5, 62 }, { 0, 57 }, { -4, 61 }, ++ { -9, 60 }, { 1, 54 }, { 2, 58 }, { 17, -10 }, ++ { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, ++ { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, ++ ++ /* 460 - 1024 */ ++ { 0, 80 }, { -5, 89 }, { -7, 94 }, { -4, 92 }, ++ { 0, 39 }, { 0, 65 }, { -15, 84 }, { -35, 127 }, ++ { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, ++ { 0, 80 }, { -5, 89 }, { -7, 94 }, { -4, 92 }, ++ { 0, 39 }, { 0, 65 }, { -15, 84 }, { -35, 127 }, ++ { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, ++ { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, ++ { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, ++ { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, ++ { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, ++ { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, ++ { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, ++ { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, ++ { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, ++ { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, ++ { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, ++ { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, ++ { -13, 103 }, { -13, 91 }, { -9, 89 }, { -14, 92 }, ++ { -8, 76 }, { -12, 87 }, { -23, 110 }, { -24, 105 }, ++ { -10, 78 }, { -20, 112 }, { -17, 99 }, { -78, 127 }, ++ { -70, 127 }, { -50, 127 }, { -46, 127 }, { -4, 66 }, ++ { -5, 78 }, { -4, 71 }, { -8, 72 }, { 2, 59 }, ++ { -1, 55 }, { -7, 70 }, { -6, 75 }, { -8, 89 }, ++ { -34, 119 }, { -3, 75 }, { 32, 20 }, { 30, 22 }, ++ { -44, 127 }, { 0, 54 }, { -5, 61 }, { 0, 58 }, ++ { -1, 60 }, { -3, 61 }, { -8, 67 }, { -25, 84 }, ++ { -14, 74 }, { -5, 65 }, { 5, 52 }, { 2, 57 }, ++ { 0, 61 }, { -9, 69 }, { -11, 70 }, { 18, 55 }, ++ { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, ++ { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, ++ { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, ++ { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, ++ { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, ++ { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, ++ { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, ++ { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, ++ { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, ++ { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, ++ { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, ++ { 4, 45 }, { 10, 28 }, { 10, 31 }, { 33, -11 }, ++ { 52, -43 }, { 18, 15 }, { 28, 0 }, { 35, -22 }, ++ { 38, -25 }, { 34, 0 }, { 39, -18 }, { 32, -12 }, ++ { 102, -94 }, { 0, 0 }, { 56, -15 }, { 33, -4 }, ++ { 29, 10 }, { 37, -5 }, { 51, -29 }, { 39, -9 }, ++ { 52, -34 }, { 69, -58 }, { 67, -63 }, { 44, -5 }, ++ { 32, 7 }, { 55, -29 }, { 32, 1 }, { 0, 0 }, ++ { 27, 36 }, { 33, -25 }, { 34, -30 }, { 36, -28 }, ++ { 38, -28 }, { 38, -27 }, { 34, -18 }, { 35, -16 }, ++ { 34, -14 }, { 32, -8 }, { 37, -6 }, { 35, 0 }, ++ { 30, 10 }, { 28, 18 }, { 26, 25 }, { 29, 41 }, ++ { -5, 85 }, { -6, 81 }, { -10, 77 }, { -7, 81 }, ++ { -17, 80 }, { -18, 73 }, { -4, 74 }, { -10, 83 }, ++ { -9, 71 }, { -9, 67 }, { -1, 61 }, { -8, 66 }, ++ { -14, 66 }, { 0, 59 }, { 2, 59 }, { -3, 81 }, ++ { -3, 76 }, { -7, 72 }, { -6, 78 }, { -12, 72 }, ++ { -14, 68 }, { -3, 70 }, { -6, 76 }, { -5, 66 }, ++ { -5, 62 }, { 0, 57 }, { -4, 61 }, { -9, 60 }, ++ { 1, 54 }, { 2, 58 }, { 17, -10 }, { 32, -13 }, ++ { 42, -9 }, { 49, -5 }, { 53, 0 }, { 64, 3 }, ++ { 68, 10 }, { 66, 27 }, { 47, 57 }, { 17, -10 }, ++ { 32, -13 }, { 42, -9 }, { 49, -5 }, { 53, 0 }, ++ { 64, 3 }, { 68, 10 }, { 66, 27 }, { 47, 57 }, ++ { -5, 71 }, { 0, 24 }, { -1, 36 }, { -2, 42 }, ++ { -2, 52 }, { -9, 57 }, { -6, 63 }, { -4, 65 }, ++ { -4, 67 }, { -7, 82 }, { -5, 85 }, { -6, 81 }, ++ { -10, 77 }, { -7, 81 }, { -17, 80 }, { -18, 73 }, ++ { -4, 74 }, { -10, 83 }, { -9, 71 }, { -9, 67 }, ++ { -1, 61 }, { -8, 66 }, { -14, 66 }, { 0, 59 }, ++ { 2, 59 }, { -3, 81 }, { -3, 76 }, { -7, 72 }, ++ { -6, 78 }, { -12, 72 }, { -14, 68 }, { -3, 70 }, ++ { -6, 76 }, { -5, 66 }, { -5, 62 }, { 0, 57 }, ++ { -4, 61 }, { -9, 60 }, { 1, 54 }, { 2, 58 }, ++ { 17, -10 }, { 32, -13 }, { 42, -9 }, { 49, -5 }, ++ { 53, 0 }, { 64, 3 }, { 68, 10 }, { 66, 27 }, ++ { 47, 57 }, { 17, -10 }, { 32, -13 }, { 42, -9 }, ++ { 49, -5 }, { 53, 0 }, { 64, 3 }, { 68, 10 }, ++ { 66, 27 }, { 47, 57 }, { -5, 71 }, { 0, 24 }, ++ { -1, 36 }, { -2, 42 }, { -2, 52 }, { -9, 57 }, ++ { -6, 63 }, { -4, 65 }, { -4, 67 }, { -7, 82 }, ++ { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, ++ { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, ++ { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, ++ { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, ++ { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, ++ { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, ++ { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, ++ { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, ++ { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, ++ { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, ++ { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, ++ { -21, 126 }, { -23, 124 }, { -20, 110 }, { -26, 126 }, ++ { -25, 124 }, { -17, 105 }, { -27, 121 }, { -27, 117 }, ++ { -17, 102 }, { -26, 117 }, { -27, 116 }, { -33, 122 }, ++ { -10, 95 }, { -14, 100 }, { -8, 95 }, { -17, 111 }, ++ { -28, 114 }, { -6, 89 }, { -2, 80 }, { -4, 82 }, ++ { -9, 85 }, { -8, 81 }, { -1, 72 }, { 5, 64 }, ++ { 1, 67 }, { 9, 56 }, { 0, 69 }, { 1, 69 }, ++ { 7, 69 }, { -7, 69 }, { -6, 67 }, { -16, 77 }, ++ { -2, 64 }, { 2, 61 }, { -6, 67 }, { -3, 64 }, ++ { 2, 57 }, { -3, 65 }, { -3, 66 }, { 0, 62 }, ++ { 9, 51 }, { -1, 66 }, { -2, 71 }, { -2, 75 }, ++ { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, ++ { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, ++ { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, ++ { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, ++ { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, ++ { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, ++ { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, ++ { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, ++ { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, ++ { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, ++ { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, ++ { 19, -6 }, { 18, -6 }, { 14, 0 }, { 26, -12 }, ++ { 31, -16 }, { 33, -25 }, { 33, -22 }, { 37, -28 }, ++ { 39, -30 }, { 42, -30 }, { 47, -42 }, { 45, -36 }, ++ { 49, -34 }, { 41, -17 }, { 32, 9 }, { 69, -71 }, ++ { 63, -63 }, { 66, -64 }, { 77, -74 }, { 54, -39 }, ++ { 52, -35 }, { 41, -10 }, { 36, 0 }, { 40, -1 }, ++ { 30, 14 }, { 28, 26 }, { 23, 37 }, { 12, 55 }, ++ { 11, 65 }, { 37, -33 }, { 39, -36 }, { 40, -37 }, ++ { 38, -30 }, { 46, -33 }, { 42, -30 }, { 40, -24 }, ++ { 49, -29 }, { 38, -12 }, { 40, -10 }, { 38, -3 }, ++ { 46, -5 }, { 31, 20 }, { 29, 30 }, { 25, 44 }, ++ { -23, 112 }, { -15, 71 }, { -7, 61 }, { 0, 53 }, ++ { -5, 66 }, { -11, 77 }, { -9, 80 }, { -9, 84 }, ++ { -10, 87 }, { -34, 127 }, { -21, 101 }, { -3, 39 }, ++ { -5, 53 }, { -7, 61 }, { -11, 75 }, { -15, 77 }, ++ { -17, 91 }, { -25, 107 }, { -25, 111 }, { -28, 122 }, ++ { -11, 76 }, { -10, 44 }, { -10, 52 }, { -10, 57 }, ++ { -9, 58 }, { -16, 72 }, { -7, 69 }, { -4, 69 }, ++ { -5, 74 }, { -9, 86 }, { -23, 112 }, { -15, 71 }, ++ { -7, 61 }, { 0, 53 }, { -5, 66 }, { -11, 77 }, ++ { -9, 80 }, { -9, 84 }, { -10, 87 }, { -34, 127 }, ++ { -21, 101 }, { -3, 39 }, { -5, 53 }, { -7, 61 }, ++ { -11, 75 }, { -15, 77 }, { -17, 91 }, { -25, 107 }, ++ { -25, 111 }, { -28, 122 }, { -11, 76 }, { -10, 44 }, ++ { -10, 52 }, { -10, 57 }, { -9, 58 }, { -16, 72 }, ++ { -7, 69 }, { -4, 69 }, { -5, 74 }, { -9, 86 }, ++ { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, ++ { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 }, ++ { -2, 73 }, { -12, 104 }, { -9, 91 }, { -31, 127 } ++ }, ++ ++ /* i_cabac_init_idc == 2 */ ++ { ++ /* 0 - 10 */ ++ { 20, -15 }, { 2, 54 }, { 3, 74 }, { 20, -15 }, ++ { 2, 54 }, { 3, 74 }, { -28, 127 }, { -23, 104 }, ++ { -6, 53 }, { -1, 54 }, { 7, 51 }, ++ ++ /* 11 - 23 */ ++ { 29, 16 }, { 25, 0 }, { 14, 0 }, { -10, 51 }, ++ { -3, 62 }, { -27, 99 }, { 26, 16 }, { -4, 85 }, ++ { -24, 102 }, { 5, 57 }, { 6, 57 }, { -17, 73 }, ++ { 14, 57 }, ++ ++ /* 24 - 39 */ ++ { 20, 40 }, { 20, 10 }, { 29, 0 }, { 54, 0 }, ++ { 37, 42 }, { 12, 97 }, { -32, 127 }, { -22, 117 }, ++ { -2, 74 }, { -4, 85 }, { -24, 102 }, { 5, 57 }, ++ { -6, 93 }, { -14, 88 }, { -6, 44 }, { 4, 55 }, ++ ++ /* 40 - 53 */ ++ { -11, 89 },{ -15, 103 },{ -21, 116 },{ 19, 57 }, ++ { 20, 58 },{ 4, 84 },{ 6, 96 },{ 1, 63 }, ++ { -5, 85 },{ -13, 106 },{ 5, 63 },{ 6, 75 }, ++ { -3, 90 },{ -1, 101 }, ++ ++ /* 54 - 59 */ ++ { 3, 55 },{ -4, 79 },{ -2, 75 },{ -12, 97 }, ++ { -7, 50 },{ 1, 60 }, ++ ++ /* 60 - 69 */ ++ { 0, 41 }, { 0, 63 }, { 0, 63 }, { 0, 63 }, ++ { -9, 83 }, { 4, 86 }, { 0, 97 }, { -7, 72 }, ++ { 13, 41 }, { 3, 62 }, ++ ++ /* 70 - 104 */ ++ { 7, 34 }, { -9, 88 }, { -20, 127 }, { -36, 127 }, ++ { -17, 91 }, { -14, 95 }, { -25, 84 }, { -25, 86 }, ++ { -12, 89 }, { -17, 91 }, { -31, 127 }, { -14, 76 }, ++ { -18, 103 }, { -13, 90 }, { -37, 127 }, { 11, 80 }, ++ { 5, 76 }, { 2, 84 }, { 5, 78 }, { -6, 55 }, ++ { 4, 61 }, { -14, 83 }, { -37, 127 }, { -5, 79 }, ++ { -11, 104 }, { -11, 91 }, { -30, 127 }, { 0, 65 }, ++ { -2, 79 }, { 0, 72 }, { -4, 92 }, { -6, 56 }, ++ { 3, 68 }, { -8, 71 }, { -13, 98 }, ++ ++ /* 105 -> 165 */ ++ { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, ++ { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, ++ { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, ++ { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, ++ { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, ++ { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, ++ { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, ++ { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, ++ { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, ++ { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, ++ { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, ++ { 3, 65 }, { -7, 69 }, { 8, 77 }, { -10, 66 }, ++ { 3, 62 }, { -3, 68 }, { -20, 81 }, { 0, 30 }, ++ { 1, 7 }, { -3, 23 }, { -21, 74 }, { 16, 66 }, ++ { -23, 124 }, { 17, 37 }, { 44, -18 }, { 50, -34 }, ++ { -22, 127 }, ++ ++ /* 166 - 226 */ ++ { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, ++ { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, ++ { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, ++ { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, ++ { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, ++ { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, ++ { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, ++ { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, ++ { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, ++ { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, ++ { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, ++ { 20, 34 }, { 19, 31 }, { 27, 44 }, { 19, 16 }, ++ { 15, 36 }, { 15, 36 }, { 21, 28 }, { 25, 21 }, ++ { 30, 20 }, { 31, 12 }, { 27, 16 }, { 24, 42 }, ++ { 0, 93 }, { 14, 56 }, { 15, 57 }, { 26, 38 }, ++ { -24, 127 }, ++ ++ /* 227 - 275 */ ++ { -24, 115 }, { -22, 82 }, { -9, 62 }, { 0, 53 }, ++ { 0, 59 }, { -14, 85 }, { -13, 89 }, { -13, 94 }, ++ { -11, 92 }, { -29, 127 }, { -21, 100 }, { -14, 57 }, ++ { -12, 67 }, { -11, 71 }, { -10, 77 }, { -21, 85 }, ++ { -16, 88 }, { -23, 104 }, { -15, 98 }, { -37, 127 }, ++ { -10, 82 }, { -8, 48 }, { -8, 61 }, { -8, 66 }, ++ { -7, 70 }, { -14, 75 }, { -10, 79 }, { -9, 83 }, ++ { -12, 92 }, { -18, 108 }, { -4, 79 }, { -22, 69 }, ++ { -16, 75 }, { -2, 58 }, { 1, 58 }, { -13, 78 }, ++ { -9, 83 }, { -4, 81 }, { -13, 99 }, { -13, 81 }, ++ { -6, 38 }, { -13, 62 }, { -6, 58 }, { -2, 59 }, ++ { -16, 73 }, { -10, 76 }, { -13, 86 }, { -9, 83 }, ++ { -10, 87 }, ++ ++ /* 276 a bit special (not used, h264_cabac_encode_bypass is used instead) */ ++ { 0, 0 }, ++ ++ /* 277 - 337 */ ++ { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, ++ { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, ++ { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, ++ { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, ++ { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, ++ { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, ++ { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, ++ { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, ++ { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, ++ { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, ++ { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, ++ { -2, 76 }, { -18, 86 }, { 12, 70 }, { 5, 64 }, ++ { -12, 70 }, { 11, 55 }, { 5, 56 }, { 0, 69 }, ++ { 2, 65 }, { -6, 74 }, { 5, 54 }, { 7, 54 }, ++ { -6, 76 }, { -11, 82 }, { -2, 77 }, { -2, 77 }, ++ { 25, 42 }, ++ ++ /* 338 - 398 */ ++ { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, ++ { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, ++ { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, ++ { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, ++ { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, ++ { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, ++ { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, ++ { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, ++ { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, ++ { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, ++ { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, ++ { 18, 31 }, { 19, 26 }, { 36, 24 }, { 24, 23 }, ++ { 27, 16 }, { 24, 30 }, { 31, 29 }, { 22, 41 }, ++ { 22, 42 }, { 16, 60 }, { 15, 52 }, { 14, 60 }, ++ { 3, 78 }, { -16, 123 }, { 21, 53 }, { 22, 56 }, ++ { 25, 61 }, ++ ++ /* 399 -> 435 */ ++ { 21, 33 }, { 19, 50 }, { 17, 61 }, ++ { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, ++ { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, ++ { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, ++ { -14, 59 }, { -9, 52 }, { -11, 68 }, { 9, -2 }, ++ { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, ++ { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, ++ { -9, 71 }, { -7, 37 }, { -8, 44 }, { -11, 49 }, ++ { -10, 56 }, { -12, 59 }, { -8, 63 }, { -9, 67 }, ++ { -6, 68 }, { -10, 79 }, ++ ++ /* 436 -> 459 */ ++ { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, ++ { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, ++ { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, ++ { -14, 59 }, { -9, 52 }, { -11, 68 }, { 9, -2 }, ++ { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, ++ { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, ++ ++ /* 460 - 1024 */ ++ { 11, 80 }, { 5, 76 }, { 2, 84 }, { 5, 78 }, ++ { -6, 55 }, { 4, 61 }, { -14, 83 }, { -37, 127 }, ++ { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, ++ { 11, 80 }, { 5, 76 }, { 2, 84 }, { 5, 78 }, ++ { -6, 55 }, { 4, 61 }, { -14, 83 }, { -37, 127 }, ++ { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, ++ { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, ++ { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, ++ { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, ++ { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, ++ { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, ++ { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, ++ { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, ++ { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, ++ { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, ++ { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, ++ { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, ++ { -4, 86 }, { -12, 88 }, { -5, 82 }, { -3, 72 }, ++ { -4, 67 }, { -8, 72 }, { -16, 89 }, { -9, 69 }, ++ { -1, 59 }, { 5, 66 }, { 4, 57 }, { -4, 71 }, ++ { -2, 71 }, { 2, 58 }, { -1, 74 }, { -4, 44 }, ++ { -1, 69 }, { 0, 62 }, { -7, 51 }, { -4, 47 }, ++ { -6, 42 }, { -3, 41 }, { -6, 53 }, { 8, 76 }, ++ { -9, 78 }, { -11, 83 }, { 9, 52 }, { 0, 67 }, ++ { -5, 90 }, { 1, 67 }, { -15, 72 }, { -5, 75 }, ++ { -8, 80 }, { -21, 83 }, { -21, 64 }, { -13, 31 }, ++ { -25, 64 }, { -29, 94 }, { 9, 75 }, { 17, 63 }, ++ { -8, 74 }, { -5, 35 }, { -2, 27 }, { 13, 91 }, ++ { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, ++ { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, ++ { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, ++ { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, ++ { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, ++ { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, ++ { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, ++ { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, ++ { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, ++ { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, ++ { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, ++ { 4, 39 }, { 0, 42 }, { 7, 34 }, { 11, 29 }, ++ { 8, 31 }, { 6, 37 }, { 7, 42 }, { 3, 40 }, ++ { 8, 33 }, { 13, 43 }, { 13, 36 }, { 4, 47 }, ++ { 3, 55 }, { 2, 58 }, { 6, 60 }, { 8, 44 }, ++ { 11, 44 }, { 14, 42 }, { 7, 48 }, { 4, 56 }, ++ { 4, 52 }, { 13, 37 }, { 9, 49 }, { 19, 58 }, ++ { 10, 48 }, { 12, 45 }, { 0, 69 }, { 20, 33 }, ++ { 8, 63 }, { 35, -18 }, { 33, -25 }, { 28, -3 }, ++ { 24, 10 }, { 27, 0 }, { 34, -14 }, { 52, -44 }, ++ { 39, -24 }, { 19, 17 }, { 31, 25 }, { 36, 29 }, ++ { 24, 33 }, { 34, 15 }, { 30, 20 }, { 22, 73 }, ++ { -3, 78 }, { -8, 74 }, { -9, 72 }, { -10, 72 }, ++ { -18, 75 }, { -12, 71 }, { -11, 63 }, { -5, 70 }, ++ { -17, 75 }, { -14, 72 }, { -16, 67 }, { -8, 53 }, ++ { -14, 59 }, { -9, 52 }, { -11, 68 }, { -3, 78 }, ++ { -8, 74 }, { -9, 72 }, { -10, 72 }, { -18, 75 }, ++ { -12, 71 }, { -11, 63 }, { -5, 70 }, { -17, 75 }, ++ { -14, 72 }, { -16, 67 }, { -8, 53 }, { -14, 59 }, ++ { -9, 52 }, { -11, 68 }, { 9, -2 }, { 30, -10 }, ++ { 31, -4 }, { 33, -1 }, { 33, 7 }, { 31, 12 }, ++ { 37, 23 }, { 31, 38 }, { 20, 64 }, { 9, -2 }, ++ { 30, -10 }, { 31, -4 }, { 33, -1 }, { 33, 7 }, ++ { 31, 12 }, { 37, 23 }, { 31, 38 }, { 20, 64 }, ++ { -9, 71 }, { -7, 37 }, { -8, 44 }, { -11, 49 }, ++ { -10, 56 }, { -12, 59 }, { -8, 63 }, { -9, 67 }, ++ { -6, 68 }, { -10, 79 }, { -3, 78 }, { -8, 74 }, ++ { -9, 72 }, { -10, 72 }, { -18, 75 }, { -12, 71 }, ++ { -11, 63 }, { -5, 70 }, { -17, 75 }, { -14, 72 }, ++ { -16, 67 }, { -8, 53 }, { -14, 59 }, { -9, 52 }, ++ { -11, 68 }, { -3, 78 }, { -8, 74 }, { -9, 72 }, ++ { -10, 72 }, { -18, 75 }, { -12, 71 }, { -11, 63 }, ++ { -5, 70 }, { -17, 75 }, { -14, 72 }, { -16, 67 }, ++ { -8, 53 }, { -14, 59 }, { -9, 52 }, { -11, 68 }, ++ { 9, -2 }, { 30, -10 }, { 31, -4 }, { 33, -1 }, ++ { 33, 7 }, { 31, 12 }, { 37, 23 }, { 31, 38 }, ++ { 20, 64 }, { 9, -2 }, { 30, -10 }, { 31, -4 }, ++ { 33, -1 }, { 33, 7 }, { 31, 12 }, { 37, 23 }, ++ { 31, 38 }, { 20, 64 }, { -9, 71 }, { -7, 37 }, ++ { -8, 44 }, { -11, 49 }, { -10, 56 }, { -12, 59 }, ++ { -8, 63 }, { -9, 67 }, { -6, 68 }, { -10, 79 }, ++ { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, ++ { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, ++ { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, ++ { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, ++ { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, ++ { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, ++ { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, ++ { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, ++ { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, ++ { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, ++ { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, ++ { -22, 127 }, { -25, 127 }, { -25, 120 }, { -27, 127 }, ++ { -19, 114 }, { -23, 117 }, { -25, 118 }, { -26, 117 }, ++ { -24, 113 }, { -28, 118 }, { -31, 120 }, { -37, 124 }, ++ { -10, 94 }, { -15, 102 }, { -10, 99 }, { -13, 106 }, ++ { -50, 127 }, { -5, 92 }, { 17, 57 }, { -5, 86 }, ++ { -13, 94 }, { -12, 91 }, { -2, 77 }, { 0, 71 }, ++ { -1, 73 }, { 4, 64 }, { -7, 81 }, { 5, 64 }, ++ { 15, 57 }, { 1, 67 }, { 0, 68 }, { -10, 67 }, ++ { 1, 68 }, { 0, 77 }, { 2, 64 }, { 0, 68 }, ++ { -5, 78 }, { 7, 55 }, { 5, 59 }, { 2, 65 }, ++ { 14, 54 }, { 15, 44 }, { 5, 60 }, { 2, 70 }, ++ { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, ++ { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, ++ { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, ++ { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, ++ { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, ++ { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, ++ { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, ++ { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, ++ { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, ++ { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, ++ { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, ++ { 17, -13 }, { 16, -9 }, { 17, -12 }, { 27, -21 }, ++ { 37, -30 }, { 41, -40 }, { 42, -41 }, { 48, -47 }, ++ { 39, -32 }, { 46, -40 }, { 52, -51 }, { 46, -41 }, ++ { 52, -39 }, { 43, -19 }, { 32, 11 }, { 61, -55 }, ++ { 56, -46 }, { 62, -50 }, { 81, -67 }, { 45, -20 }, ++ { 35, -2 }, { 28, 15 }, { 34, 1 }, { 39, 1 }, ++ { 30, 17 }, { 20, 38 }, { 18, 45 }, { 15, 54 }, ++ { 0, 79 }, { 36, -16 }, { 37, -14 }, { 37, -17 }, ++ { 32, 1 }, { 34, 15 }, { 29, 15 }, { 24, 25 }, ++ { 34, 22 }, { 31, 16 }, { 35, 18 }, { 31, 28 }, ++ { 33, 41 }, { 36, 28 }, { 27, 47 }, { 21, 62 }, ++ { -24, 115 }, { -22, 82 }, { -9, 62 }, { 0, 53 }, ++ { 0, 59 }, { -14, 85 }, { -13, 89 }, { -13, 94 }, ++ { -11, 92 }, { -29, 127 }, { -21, 100 }, { -14, 57 }, ++ { -12, 67 }, { -11, 71 }, { -10, 77 }, { -21, 85 }, ++ { -16, 88 }, { -23, 104 }, { -15, 98 }, { -37, 127 }, ++ { -10, 82 }, { -8, 48 }, { -8, 61 }, { -8, 66 }, ++ { -7, 70 }, { -14, 75 }, { -10, 79 }, { -9, 83 }, ++ { -12, 92 }, { -18, 108 }, { -24, 115 }, { -22, 82 }, ++ { -9, 62 }, { 0, 53 }, { 0, 59 }, { -14, 85 }, ++ { -13, 89 }, { -13, 94 }, { -11, 92 }, { -29, 127 }, ++ { -21, 100 }, { -14, 57 }, { -12, 67 }, { -11, 71 }, ++ { -10, 77 }, { -21, 85 }, { -16, 88 }, { -23, 104 }, ++ { -15, 98 }, { -37, 127 }, { -10, 82 }, { -8, 48 }, ++ { -8, 61 }, { -8, 66 }, { -7, 70 }, { -14, 75 }, ++ { -10, 79 }, { -9, 83 }, { -12, 92 }, { -18, 108 }, ++ { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, ++ { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 }, ++ { -5, 79 }, { -11, 104 }, { -11, 91 }, { -30, 127 } ++ } ++}; ++ ++const uint8_t h264_cabac_range_lps[64][4] = ++{ ++ { 2, 2, 2, 2}, { 6, 7, 8, 9}, { 6, 7, 9, 10}, { 6, 8, 9, 11}, ++ { 7, 8, 10, 11}, { 7, 9, 10, 12}, { 7, 9, 11, 12}, { 8, 9, 11, 13}, ++ { 8, 10, 12, 14}, { 9, 11, 12, 14}, { 9, 11, 13, 15}, { 10, 12, 14, 16}, ++ { 10, 12, 15, 17}, { 11, 13, 15, 18}, { 11, 14, 16, 19}, { 12, 14, 17, 20}, ++ { 12, 15, 18, 21}, { 13, 16, 19, 22}, { 14, 17, 20, 23}, { 14, 18, 21, 24}, ++ { 15, 19, 22, 25}, { 16, 20, 23, 27}, { 17, 21, 25, 28}, { 18, 22, 26, 30}, ++ { 19, 23, 27, 31}, { 20, 24, 29, 33}, { 21, 26, 30, 35}, { 22, 27, 32, 37}, ++ { 23, 28, 33, 39}, { 24, 30, 35, 41}, { 26, 31, 37, 43}, { 27, 33, 39, 45}, ++ { 29, 35, 41, 48}, { 30, 37, 43, 50}, { 32, 39, 46, 53}, { 33, 41, 48, 56}, ++ { 35, 43, 51, 59}, { 37, 45, 54, 62}, { 39, 48, 56, 65}, { 41, 50, 59, 69}, ++ { 43, 53, 63, 72}, { 46, 56, 66, 76}, { 48, 59, 69, 80}, { 51, 62, 73, 85}, ++ { 53, 65, 77, 89}, { 56, 69, 81, 94}, { 59, 72, 86, 99}, { 62, 76, 90, 104}, ++ { 66, 80, 95, 110}, { 69, 85, 100, 116}, { 73, 89, 105, 122}, { 77, 94, 111, 128}, ++ { 81, 99, 117, 135}, { 85, 104, 123, 142}, { 90, 110, 130, 150}, { 95, 116, 137, 158}, ++ {100, 122, 144, 166}, {105, 128, 152, 175}, {111, 135, 160, 185}, {116, 142, 169, 195}, ++ {123, 150, 178, 205}, {128, 158, 187, 216}, {128, 167, 197, 227}, {128, 176, 208, 240} ++}; ++ ++const uint8_t h264_cabac_transition[128][2] = ++{ ++ { 0, 0}, { 1, 1}, { 2, 50}, { 51, 3}, { 2, 50}, { 51, 3}, { 4, 52}, { 53, 5}, ++ { 6, 52}, { 53, 7}, { 8, 52}, { 53, 9}, { 10, 54}, { 55, 11}, { 12, 54}, { 55, 13}, ++ { 14, 54}, { 55, 15}, { 16, 56}, { 57, 17}, { 18, 56}, { 57, 19}, { 20, 56}, { 57, 21}, ++ { 22, 58}, { 59, 23}, { 24, 58}, { 59, 25}, { 26, 60}, { 61, 27}, { 28, 60}, { 61, 29}, ++ { 30, 60}, { 61, 31}, { 32, 62}, { 63, 33}, { 34, 62}, { 63, 35}, { 36, 64}, { 65, 37}, ++ { 38, 66}, { 67, 39}, { 40, 66}, { 67, 41}, { 42, 66}, { 67, 43}, { 44, 68}, { 69, 45}, ++ { 46, 68}, { 69, 47}, { 48, 70}, { 71, 49}, { 50, 72}, { 73, 51}, { 52, 72}, { 73, 53}, ++ { 54, 74}, { 75, 55}, { 56, 74}, { 75, 57}, { 58, 76}, { 77, 59}, { 60, 78}, { 79, 61}, ++ { 62, 78}, { 79, 63}, { 64, 80}, { 81, 65}, { 66, 82}, { 83, 67}, { 68, 82}, { 83, 69}, ++ { 70, 84}, { 85, 71}, { 72, 84}, { 85, 73}, { 74, 88}, { 89, 75}, { 76, 88}, { 89, 77}, ++ { 78, 90}, { 91, 79}, { 80, 90}, { 91, 81}, { 82, 94}, { 95, 83}, { 84, 94}, { 95, 85}, ++ { 86, 96}, { 97, 87}, { 88, 96}, { 97, 89}, { 90, 100}, {101, 91}, { 92, 100}, {101, 93}, ++ { 94, 102}, {103, 95}, { 96, 104}, {105, 97}, { 98, 104}, {105, 99}, {100, 108}, {109, 101}, ++ {102, 108}, {109, 103}, {104, 110}, {111, 105}, {106, 112}, {113, 107}, {108, 114}, {115, 109}, ++ {110, 116}, {117, 111}, {112, 118}, {119, 113}, {114, 118}, {119, 115}, {116, 122}, {123, 117}, ++ {118, 122}, {123, 119}, {120, 124}, {125, 121}, {122, 126}, {127, 123}, {124, 127}, {126, 125} ++}; ++ ++const uint8_t h264_cabac_renorm_shift[64] = ++{ ++ 6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2, ++ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ++}; ++ ++/* -ln2(probability) */ ++const uint16_t h264_cabac_entropy[128] = ++{ ++ C_FIX8(0.0273), C_FIX8(5.7370), C_FIX8(0.0288), C_FIX8(5.6618), ++ C_FIX8(0.0303), C_FIX8(5.5866), C_FIX8(0.0320), C_FIX8(5.5114), ++ C_FIX8(0.0337), C_FIX8(5.4362), C_FIX8(0.0355), C_FIX8(5.3610), ++ C_FIX8(0.0375), C_FIX8(5.2859), C_FIX8(0.0395), C_FIX8(5.2106), ++ C_FIX8(0.0416), C_FIX8(5.1354), C_FIX8(0.0439), C_FIX8(5.0602), ++ C_FIX8(0.0463), C_FIX8(4.9851), C_FIX8(0.0488), C_FIX8(4.9099), ++ C_FIX8(0.0515), C_FIX8(4.8347), C_FIX8(0.0543), C_FIX8(4.7595), ++ C_FIX8(0.0572), C_FIX8(4.6843), C_FIX8(0.0604), C_FIX8(4.6091), ++ C_FIX8(0.0637), C_FIX8(4.5339), C_FIX8(0.0671), C_FIX8(4.4588), ++ C_FIX8(0.0708), C_FIX8(4.3836), C_FIX8(0.0747), C_FIX8(4.3083), ++ C_FIX8(0.0788), C_FIX8(4.2332), C_FIX8(0.0832), C_FIX8(4.1580), ++ C_FIX8(0.0878), C_FIX8(4.0828), C_FIX8(0.0926), C_FIX8(4.0076), ++ C_FIX8(0.0977), C_FIX8(3.9324), C_FIX8(0.1032), C_FIX8(3.8572), ++ C_FIX8(0.1089), C_FIX8(3.7820), C_FIX8(0.1149), C_FIX8(3.7068), ++ C_FIX8(0.1214), C_FIX8(3.6316), C_FIX8(0.1282), C_FIX8(3.5565), ++ C_FIX8(0.1353), C_FIX8(3.4813), C_FIX8(0.1429), C_FIX8(3.4061), ++ C_FIX8(0.1510), C_FIX8(3.3309), C_FIX8(0.1596), C_FIX8(3.2557), ++ C_FIX8(0.1686), C_FIX8(3.1805), C_FIX8(0.1782), C_FIX8(3.1053), ++ C_FIX8(0.1884), C_FIX8(3.0301), C_FIX8(0.1992), C_FIX8(2.9549), ++ C_FIX8(0.2107), C_FIX8(2.8797), C_FIX8(0.2229), C_FIX8(2.8046), ++ C_FIX8(0.2358), C_FIX8(2.7294), C_FIX8(0.2496), C_FIX8(2.6542), ++ C_FIX8(0.2642), C_FIX8(2.5790), C_FIX8(0.2798), C_FIX8(2.5038), ++ C_FIX8(0.2964), C_FIX8(2.4286), C_FIX8(0.3142), C_FIX8(2.3534), ++ C_FIX8(0.3331), C_FIX8(2.2782), C_FIX8(0.3532), C_FIX8(2.2030), ++ C_FIX8(0.3748), C_FIX8(2.1278), C_FIX8(0.3979), C_FIX8(2.0527), ++ C_FIX8(0.4226), C_FIX8(1.9775), C_FIX8(0.4491), C_FIX8(1.9023), ++ C_FIX8(0.4776), C_FIX8(1.8271), C_FIX8(0.5082), C_FIX8(1.7519), ++ C_FIX8(0.5412), C_FIX8(1.6767), C_FIX8(0.5768), C_FIX8(1.6015), ++ C_FIX8(0.6152), C_FIX8(1.5263), C_FIX8(0.6568), C_FIX8(1.4511), ++ C_FIX8(0.7020), C_FIX8(1.3759), C_FIX8(0.7513), C_FIX8(1.3008), ++ C_FIX8(0.8050), C_FIX8(1.2256), C_FIX8(0.8638), C_FIX8(1.1504), ++ C_FIX8(0.9285), C_FIX8(1.0752), C_FIX8(1.0000), C_FIX8(1.0000) ++}; ++ ++uint8_t h264_cabac_contexts[4][QP_MAX_SPEC+1][1024]; ++ ++void h264_cabac_init(void) ++{ ++ int i = 0, j = 0, qp = 0; ++ int ctx_count = 460; ++ for( i = 0; i < 4; i++ ) ++ { ++ const int8_t (*cabac_context_init)[1024][2] = i == 0 ? &h264_cabac_context_init_I ++ : &h264_cabac_context_init_PB[i-1]; ++ for( qp = 0; qp <= QP_MAX_SPEC; qp++ ) ++ for( j = 0; j < ctx_count; j++ ) ++ { ++ h264_cabac_contexts[i][qp][j] = c_clip3( (((*cabac_context_init)[j][0] * qp) >> 4) + (*cabac_context_init)[j][1], 1, 126 ); ++ } ++ } ++} ++ ++/***************************************************************************** ++ * ++ *****************************************************************************/ ++void h264_cabac_context_init(h264_cabac_t *cb, int i_slice_type, int i_qp, int i_model ) ++{ ++ memcpy( cb->state, h264_cabac_contexts[i_slice_type == M_SLICE_TYPE_I ? 0 : i_model + 1][i_qp], 460); ++} ++ ++#if 0 ++void h264_cabac_encode_init_core( h264_cabac_t *cb ) ++{ ++ cb->i_low = 0; ++ cb->i_range = 0x01FE; ++ cb->i_queue = -9; // the first bit will be shifted away and not written ++ cb->i_bytes_outstanding = 0; ++} ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.h +new file mode 100644 +index 000000000..046039199 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/cabac.h +@@ -0,0 +1,28 @@ ++#ifndef __CABAC_H__ ++#define __CABAC_H__ ++ ++#include "common.h" ++ ++typedef struct ++{ ++ /* state */ ++ int i_low; ++ int i_range; ++ ++ uint8_t *p_start; ++ uint8_t *p; ++ uint8_t *p_end; ++ ++ /* context */ ++ uint8_t state[1024]; ++ ++} h264_cabac_t; ++ ++extern void h264_cabac_init(void); ++extern void h264_cabac_context_init(h264_cabac_t *cb, int i_slice_type, int i_qp, int i_model ); ++ ++ ++ ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.c +new file mode 100644 +index 000000000..04ee83639 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.c +@@ -0,0 +1,11 @@ ++#include "common.h" ++ ++ ++ ++int c_clip3(int v, int i_min, int i_max) ++{ ++ return ((v < i_min) ? i_min : ((v > i_max) ? i_max : v)); ++} ++ ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.h +new file mode 100644 +index 000000000..2fba2c09c +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/common.h +@@ -0,0 +1,58 @@ ++#ifndef __H264ENC_COMMON_H__ ++#define __H264ENC_COMMON_H__ ++ ++#ifdef __KERNEL__ ++#include ++#include ++#else ++ ++#include ++#include ++#include ++#endif ++ ++#include "osdep.h" ++#include "bitstream.h" ++#include "set.h" ++#include "slice.h" ++#include "cabac.h" ++#include "nal.h" ++ ++#define C_MIN(a,b) ((a)<(b) ? (a) : (b)) ++#define C_MAX(a,b) ((a)>(b) ? (a) : (b)) ++#define C_MIN3(a,b,c) C_MIN((a),C_MIN((b),(c))) ++#define C_MAX3(a,b,c) C_MAX((a),C_MAX((b),(c))) ++#define C_MIN4(a,b,c,d) C_MIN((a),C_MIN3((b),(c),(d))) ++#define C_MAX4(a,b,c,d) C_MAX((a),C_MAX3((b),(c),(d))) ++#define C_XCHG(type,a,b) do{ type t = a; a = b; b = t; } while(0) ++#define C_FIX8(f) ((int)(f*(1<<8)+.5)) ++#define C_ALIGN(x,a) (((x)+((a)-1))&~((a)-1)) ++#define ARRAY_ELEMS(a) ((sizeof(a))/(sizeof(a[0]))) ++ ++ ++extern int c_clip3(int v, int i_min, int i_max); ++ ++enum profile_e ++{ ++ PROFILE_BASELINE = 66, ++ PROFILE_MAIN = 77, ++ PROFILE_HIGH = 100, ++ PROFILE_HIGH10 = 110, ++ PROFILE_HIGH422 = 122, ++ PROFILE_HIGH444_PREDICTIVE = 244, ++}; ++ ++ ++enum chroma_format_e ++{ ++ CHROMA_400 = 0, ++ CHROMA_420 = 1, ++ CHROMA_422 = 2, ++ CHROMA_444 = 3, ++}; ++ ++ ++ ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/nal.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/nal.h +new file mode 100644 +index 000000000..3cd24317e +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/nal.h +@@ -0,0 +1,59 @@ ++#ifndef __H264_NAL_H__ ++#define __H264_NAL_H__ ++ ++ ++/**************************************************************************** ++ * NAL structure and functions ++ ****************************************************************************/ ++ ++enum nal_unit_type_e ++{ ++ NAL_UNKNOWN = 0, ++ NAL_SLICE = 1, ++ NAL_SLICE_DPA = 2, ++ NAL_SLICE_DPB = 3, ++ NAL_SLICE_DPC = 4, ++ NAL_SLICE_IDR = 5, /* ref_idc != 0 */ ++ NAL_SEI = 6, /* ref_idc == 0 */ ++ NAL_SPS = 7, ++ NAL_PPS = 8, ++ NAL_AUD = 9, ++ NAL_FILLER = 12, ++ /* ref_idc == 0 for 6,9,10,11,12 */ ++}; ++ ++enum nal_priority_e ++{ ++ NAL_PRIORITY_DISPOSABLE = 0, ++ NAL_PRIORITY_LOW = 1, ++ NAL_PRIORITY_HIGH = 2, ++ NAL_PRIORITY_HIGHEST = 3, ++}; ++ ++ ++/* The data within the payload is already NAL-encapsulated; the ref_idc and type ++ * are merely in the struct for easy access by the calling application. ++ * All data returned in an h264_nal_t, including the data in p_payload, is no longer ++ * valid after the next call to h264_encoder_encode. Thus it must be used or copied ++ * before calling h264_encoder_encode or h264_encoder_headers again. */ ++typedef struct h264_nal_t ++{ ++ int i_ref_idc; /* nal_priority_e */ ++ int i_type; /* nal_unit_type_e */ ++ int b_long_startcode; ++ int i_first_mb; /* If this NAL is a slice, the index of the first MB in the slice. */ ++ int i_last_mb; /* If this NAL is a slice, the index of the last MB in the slice. */ ++ ++ /* Size of payload (including any padding) in bytes. */ ++ int i_payload; ++ /* If param->b_annexb is set, Annex-B bytestream with startcode. ++ * Otherwise, startcode is replaced with a 4-byte size. ++ * This size is the size used in mp4/similar muxing; it is equal to i_payload-4 */ ++ uint8_t *p_payload; ++ ++ /* Size of padding in bytes. */ ++ int i_padding; ++} h264_nal_t; ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/osdep.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/osdep.h +new file mode 100644 +index 000000000..3c22b6af4 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/osdep.h +@@ -0,0 +1,39 @@ ++#ifndef __OSDEP_H__ ++#define __OSDEP_H__ ++ ++#define WORD_SIZE sizeof(void *) /*4 Bytes*/ ++ ++ ++#ifdef __KERNEL__ ++typedef long intptr_t; ++ ++typedef unsigned char uint8_t; ++typedef unsigned short uint16_t; ++typedef unsigned int uint32_t; ++typedef unsigned long long uint64_t; ++#endif ++ ++ ++static inline uint32_t endian_fix32( uint32_t x ) ++{ ++ return (x<<24) + ((x<<8)&0xff0000) + ((x>>8)&0xff00) + (x>>24); ++ ++} ++static inline uint64_t endian_fix64( uint64_t x ) ++{ ++ return endian_fix32(x>>32) + ((uint64_t)endian_fix32(x)<<32); ++} ++static inline intptr_t endian_fix( intptr_t x ) ++{ ++ return WORD_SIZE == 8 ? endian_fix64(x) : endian_fix32(x); ++} ++static inline uint16_t endian_fix16( uint16_t x ) ++{ ++ return (x<<8)|(x>>8); ++} ++ ++ ++ ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.c +new file mode 100644 +index 000000000..bea400d06 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.c +@@ -0,0 +1,141 @@ ++#ifdef __KERNEL__ ++#include ++#else ++ ++#define printk printf ++#endif ++#include "common.h" ++ ++void dump_sps(h264_sps_t *sps) ++{ ++ printk("---sps->i_profile_idc %d\n", sps->i_profile_idc); ++ printk("---sps->b_constraint_set0 %d\n", sps->b_constraint_set0); ++ printk("---sps->b_constraint_set1 %d\n", sps->b_constraint_set1); ++ printk("---sps->b_constraint_set2 %d\n", sps->b_constraint_set2); ++ printk("---sps->b_constraint_set3 %d\n", sps->b_constraint_set3); ++ ++ printk("---sps->i_level_idc %d\n", sps->i_level_idc); ++ printk("---sps->i_id %d\n", sps->i_id); ++ printk("---sps->i_num_ref_frames %d\n", sps->i_num_ref_frames); ++ printk("---sps->i_mb_width %d\n", sps->i_mb_width); ++ printk("---sps->i_mb_height %d\n", sps->i_mb_height); ++} ++ ++void dump_pps(h264_pps_t *pps) ++{ ++ printk("---pps->i_sps_id %d\n", pps->i_sps_id); ++ printk("---pps->b_cabac %d\n", pps->b_cabac); ++ printk("---pps->i_num_slice_groups %d\n", pps->i_num_slice_groups); ++} ++ ++void h264e_sps_write(bs_t *s, h264_sps_t *sps) ++{ ++ bs_realign(s); ++ bs_write(s, 8, sps->i_profile_idc); ++ ++ bs_write1(s, sps->b_constraint_set0); ++ bs_write1(s, sps->b_constraint_set1); ++ bs_write1(s, sps->b_constraint_set2); ++ bs_write1(s, sps->b_constraint_set3); ++ ++ bs_write(s, 4, 0); //reserved_zero_4bits; /* equal to 0*/ ++ bs_write(s, 8, sps->i_level_idc); ++ bs_write_ue(s, sps->i_id); ++ ++ bs_write_ue(s, sps->i_log2_max_frame_num - 4); // log2_max_frame_num_minus4; ++ bs_write_ue(s, sps->i_poc_type); // pic_order_cnt_type; ++ if(sps->i_poc_type == 0) ++ bs_write_ue(s, sps->i_log2_max_poc_lsb - 4); ++ ++ bs_write_ue( s, sps->i_num_ref_frames ); ++ bs_write1( s, sps->b_gaps_in_frame_num_value_allowed ); ++ bs_write_ue( s, sps->i_mb_width - 1 ); /*pic_width_in_mbs_minus1*/ ++ bs_write_ue( s, (sps->i_mb_height >> !sps->b_frame_mbs_only) - 1); ++ bs_write1( s, sps->b_frame_mbs_only ); ++ ++ if( !sps->b_frame_mbs_only ) ++ bs_write1( s, sps->b_mb_adaptive_frame_field ); ++ bs_write1( s, sps->b_direct8x8_inference ); ++ ++ bs_write1( s, sps->b_crop ); ++ if( sps->b_crop ) ++ { ++ int h_shift = sps->i_chroma_format_idc == CHROMA_420 || sps->i_chroma_format_idc == CHROMA_422; ++ int v_shift = sps->i_chroma_format_idc == CHROMA_420; ++ bs_write_ue( s, sps->crop.i_left >> h_shift ); ++ bs_write_ue( s, sps->crop.i_right >> h_shift ); ++ bs_write_ue( s, sps->crop.i_top >> v_shift ); ++ bs_write_ue( s, sps->crop.i_bottom >> v_shift ); ++ } ++ ++ bs_write1( s, sps->b_vui ); ++ if(sps->b_vui) { ++ } ++ ++ bs_rbsp_trailing( s ); ++ bs_flush( s ); ++} ++ ++void h264e_pps_write(bs_t *s, h264_sps_t *sps, h264_pps_t *pps) ++{ ++ bs_realign(s); ++ bs_write_ue(s, pps->i_id); ++ bs_write_ue(s, pps->i_sps_id); ++ ++ bs_write1(s, pps->b_cabac); ++ bs_write1(s, pps->b_pic_order); ++ bs_write_ue(s, pps->i_num_slice_groups - 1); ++ ++ bs_write_ue(s, pps->i_num_ref_idx_l0_default_active - 1); ++ bs_write_ue(s, pps->i_num_ref_idx_l1_default_active - 1); ++ bs_write1(s, pps->b_weighted_pred); ++ bs_write(s, 2, pps->b_weighted_bipred); ++ ++ bs_write_se(s, pps->i_pic_init_qp - 26); ++ bs_write_se(s, pps->i_pic_init_qs - 26); ++ bs_write_se(s, pps->i_chroma_qp_index_offset); ++ ++ bs_write1(s, pps->b_deblocking_filter_control); ++ bs_write1(s, pps->b_constrained_intra_pred); ++ bs_write1(s, pps->b_redundant_pic_cnt); ++ ++ if(pps->b_transform_8x8_mode) { ++ ++ bs_write1(s, pps->b_transform_8x8_mode); ++ bs_write1(s, 0); ++ ++ bs_write_se(s, pps->i_chroma_qp_index_offset); ++ ++ } ++ ++ bs_rbsp_trailing(s); ++ bs_flush(s); ++} ++ ++ ++void h264e_sei_write(bs_t *s, uint8_t *payload, int payload_size, int payload_type) ++{ ++ int i; ++ bs_realign( s ); ++ for( i = 0; i <= payload_type-255; i += 255 ) ++ bs_write( s, 8, 255 ); ++ bs_write( s, 8, payload_type-i ); ++ ++ for( i = 0; i <= payload_size-255; i += 255 ) ++ bs_write( s, 8, 255 ); ++ bs_write( s, 8, payload_size-i ); ++ ++ for( i = 0; i < payload_size; i++ ) ++ bs_write( s, 8, payload[i] ); ++ ++ bs_rbsp_trailing( s ); ++ bs_flush( s ); ++} ++ ++int h264e_sei_version_write(bs_t *s) ++{ ++ return 0; ++} ++ ++ ++ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.h +new file mode 100644 +index 000000000..dbcac827f +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/set.h +@@ -0,0 +1,150 @@ ++#ifndef H264_SET_H ++#define H264_SET_H ++ ++#include "bitstream.h" ++ ++typedef struct ++{ ++ int i_id; ++ ++ int i_profile_idc; ++ int i_level_idc; ++ ++ int b_constraint_set0; ++ int b_constraint_set1; ++ int b_constraint_set2; ++ int b_constraint_set3; ++ ++ int i_log2_max_frame_num; ++ ++ int i_poc_type; ++ /* poc 0 */ ++ int i_log2_max_poc_lsb; ++ ++ int i_num_ref_frames; ++ int b_gaps_in_frame_num_value_allowed; ++ int i_mb_width; ++ int i_mb_height; ++ int b_frame_mbs_only; ++ int b_mb_adaptive_frame_field; ++ int b_direct8x8_inference; ++ ++ int b_crop; ++ struct ++ { ++ int i_left; ++ int i_right; ++ int i_top; ++ int i_bottom; ++ } crop; ++ ++ int b_vui; ++ struct ++ { ++ int b_aspect_ratio_info_present; ++ int i_sar_width; ++ int i_sar_height; ++ ++ int b_overscan_info_present; ++ int b_overscan_info; ++ ++ int b_signal_type_present; ++ int i_vidformat; ++ int b_fullrange; ++ int b_color_description_present; ++ int i_colorprim; ++ int i_transfer; ++ int i_colmatrix; ++ ++ int b_chroma_loc_info_present; ++ int i_chroma_loc_top; ++ int i_chroma_loc_bottom; ++ ++ int b_timing_info_present; ++ uint32_t i_num_units_in_tick; ++ uint32_t i_time_scale; ++ int b_fixed_frame_rate; ++ ++ int b_nal_hrd_parameters_present; ++ int b_vcl_hrd_parameters_present; ++ ++ struct ++ { ++ int i_cpb_cnt; ++ int i_bit_rate_scale; ++ int i_cpb_size_scale; ++ int i_bit_rate_value; ++ int i_cpb_size_value; ++ int i_bit_rate_unscaled; ++ int i_cpb_size_unscaled; ++ int b_cbr_hrd; ++ ++ int i_initial_cpb_removal_delay_length; ++ int i_cpb_removal_delay_length; ++ int i_dpb_output_delay_length; ++ int i_time_offset_length; ++ } hrd; ++ ++ int b_pic_struct_present; ++ int b_bitstream_restriction; ++ int b_motion_vectors_over_pic_boundaries; ++ int i_max_bytes_per_pic_denom; ++ int i_max_bits_per_mb_denom; ++ int i_log2_max_mv_length_horizontal; ++ int i_log2_max_mv_length_vertical; ++ int i_num_reorder_frames; ++ int i_max_dec_frame_buffering; ++ ++ /* FIXME to complete */ ++ } vui; ++ ++ int b_qpprime_y_zero_transform_bypass; ++ int i_chroma_format_idc; ++ ++ int b_avcintra; ++ int i_cqm_preset; ++ const uint8_t *scaling_list[8]; /* could be 12, but we don't allow separate Cb/Cr lists */ ++ ++} h264_sps_t; ++ ++typedef struct ++{ ++ int i_id; ++ int i_sps_id; ++ ++ int b_cabac; ++ ++ int b_pic_order; ++ int i_num_slice_groups; ++ ++ int i_num_ref_idx_l0_default_active; ++ int i_num_ref_idx_l1_default_active; ++ ++ int b_weighted_pred; ++ int b_weighted_bipred; ++ ++ int i_pic_init_qp; ++ int i_pic_init_qs; ++ ++ int i_chroma_qp_index_offset; ++ ++ int b_deblocking_filter_control; ++ int b_constrained_intra_pred; ++ int b_redundant_pic_cnt; ++ ++ int b_transform_8x8_mode; ++ ++} h264_pps_t; ++ ++ ++ ++extern void h264e_sps_write(bs_t *s, h264_sps_t *sps); ++ ++extern void h264e_pps_write(bs_t *s, h264_sps_t *sps, h264_pps_t *pps); ++ ++extern void h264e_sei_write(bs_t *s, uint8_t *payload, int payload_size, int payload_type); ++ ++extern int h264e_sei_version_write(bs_t *s); ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.c +new file mode 100644 +index 000000000..ce8cdcf8f +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.c +@@ -0,0 +1,162 @@ ++#include "cabac.h" ++#include "slice.h" ++ ++#ifdef __KERNEL__ ++#include ++ ++#define printf printk ++#endif ++ ++ ++ ++void xdump_slice_header(h264_slice_header_t *sh) ++{ ++ printf("sh->i_type : %d\n", sh->i_type); ++ printf("sh->i_first_mb : %d\n", sh->i_first_mb); ++ printf("sh->i_last_mb : %d\n", sh->i_last_mb); ++ printf("sh->i_pps_id : %d\n", sh->i_pps_id); ++ printf("sh->i_frame_num : %d\n", sh->i_frame_num); ++ printf("sh->b_mbaff : %d\n", sh->b_mbaff); ++ printf("sh->b_field_pic : %d\n", sh->b_field_pic); ++ printf("sh->b_bottom_field : %d\n", sh->b_bottom_field); ++ printf("sh->i_idr_pic_id : %d\n", sh->i_idr_pic_id); ++ printf("sh->i_poc : %d\n", sh->i_poc); ++ printf("sh->i_delta_poc_bottom : %d\n", sh->i_delta_poc_bottom); ++ printf("sh->i_delta_poc[0]: : %d\n", sh->i_delta_poc[0]); ++ printf("sh->i_delta_poc[1]: : %d\n", sh->i_delta_poc[1]); ++ printf("sh->b_direct_spatial_mv_pred : %d\n", sh->b_direct_spatial_mv_pred); ++ printf("sh->b_num_ref_idx_override : %d\n", sh->b_num_ref_idx_override); ++ printf("sh->i_num_ref_idx_l0_active : %d\n", sh->i_num_ref_idx_l0_active); ++ printf("sh->i_num_ref_idx_l1_active : %d\n", sh->i_num_ref_idx_l1_active); ++ ++ ++ printf("sh->i_cabac_init_idc : %d\n", sh->i_cabac_init_idc); ++ printf("sh->i_qp : %d\n", sh->i_qp); ++ printf("sh->i_qp_delta : %d\n", sh->i_qp_delta); ++ printf("sh->b_sp_for_swidth : %d\n", sh->b_sp_for_swidth); ++ printf("sh->i_qs_delta : %d\n", sh->i_qs_delta); ++ ++ ++} ++ ++void h264e_slice_header_init(h264_slice_header_t *sh, ++ h264_sps_t *sps, h264_pps_t *pps, ++ int i_idr_pic_id, int i_frame, int i_qp) ++{ ++ sh->sps = sps; ++ sh->pps = pps; ++ ++ sh->i_first_mb = 0; ++ sh->i_last_mb = sps->i_mb_width * sps->i_mb_height - 1; ++ sh->i_pps_id = pps->i_id; ++ sh->i_frame_num = i_frame; ++ ++ sh->b_mbaff = 0; ++ sh->b_field_pic = 0; ++ sh->b_bottom_field = 0; ++ ++ sh->i_idr_pic_id = i_idr_pic_id; ++ ++ sh->i_poc = 0; ++ sh->i_delta_poc_bottom = 0; ++ sh->i_delta_poc[0] = 0; ++ sh->i_delta_poc[1] = 0; ++ ++ ++ sh->i_redundant_pic_cnt = 0; ++ ++ sh->b_num_ref_idx_override = 0; ++ sh->i_num_ref_idx_l0_active = 1; ++ sh->i_num_ref_idx_l1_active = 1; ++ ++ sh->b_ref_pic_list_reordering[0] = 0; ++ sh->b_ref_pic_list_reordering[1] = 0; ++ ++ ++ sh->i_cabac_init_idc = 0; ++ ++ sh->i_qp = SPEC_QP(i_qp); ++ sh->i_qp_delta = sh->i_qp - pps->i_pic_init_qp; ++ ++ sh->b_sp_for_swidth = 0; ++ sh->i_qs_delta = 0; ++ ++ sh->i_disable_deblocking_filter_idc = 1; ++ sh->i_alpha_c0_offset = 0; ++ sh->i_beta_offset = 0; ++} ++ ++ ++void h264e_slice_header_write(bs_t *s, h264_slice_header_t *sh, int i_nal_ref_idc) ++{ ++ /*Do not support mbaff*/ ++ bs_write_ue(s, sh->i_first_mb); ++ bs_write_ue(s, sh->i_type + 5); ++ bs_write_ue(s, sh->i_pps_id); ++ bs_write(s, sh->sps->i_log2_max_frame_num, sh->i_frame_num & ((1 << sh->sps->i_log2_max_frame_num) - 1)); ++ ++ /*mbs only*/ ++ ++ if(sh->i_idr_pic_id >= 0) ++ bs_write_ue(s, sh->i_idr_pic_id); ++ ++ ++ if(sh->i_type == M_SLICE_TYPE_P || sh->i_type == M_SLICE_TYPE_B) { ++ bs_write1(s, sh->b_num_ref_idx_override); ++ if(sh->b_num_ref_idx_override) { ++ bs_write_ue(s, sh->i_num_ref_idx_l0_active - 1); ++ if(sh->i_type == M_SLICE_TYPE_B) ++ bs_write_ue(s, sh->i_num_ref_idx_l1_active - 1); ++ } ++ ++ } ++ ++ if(sh->i_type != M_SLICE_TYPE_I) { ++ bs_write1(s, sh->b_ref_pic_list_reordering[0]); ++ if(sh->b_ref_pic_list_reordering[0]) { ++ int i; ++ for(i = 0; i < sh->i_num_ref_idx_l0_active; i++) { ++ bs_write_ue(s, sh->ref_pic_list_order[0][i].idc); ++ bs_write_ue(s, sh->ref_pic_list_order[0][i].arg); ++ } ++ ++ bs_write_ue(s, 3); ++ } ++ } ++ ++ if(i_nal_ref_idc != 0) { ++ if(sh->i_idr_pic_id >= 0) { ++ bs_write1(s, 0); ++ bs_write1(s, 0); ++ } else { ++ bs_write1( s, sh->i_mmco_command_count > 0 ); /* adaptive_ref_pic_marking_mode_flag */ ++ if( sh->i_mmco_command_count > 0 ) ++ { ++ int i = 0; ++ for(i = 0; i < sh->i_mmco_command_count; i++ ) ++ { ++ bs_write_ue( s, 1 ); /* mark short term ref as unused */ ++ bs_write_ue( s, sh->mmco[i].i_difference_of_pic_nums - 1 ); ++ } ++ bs_write_ue( s, 0 ); /* end command list */ ++ } ++ ++ } ++ ++ } ++ ++ if( sh->pps->b_cabac && sh->i_type != M_SLICE_TYPE_I ) ++ bs_write_ue( s, sh->i_cabac_init_idc ); ++ ++ bs_write_se( s, sh->i_qp_delta ); /* slice qp delta */ ++ ++ if( sh->pps->b_deblocking_filter_control ) ++ { ++ bs_write_ue( s, sh->i_disable_deblocking_filter_idc ); ++ if( sh->i_disable_deblocking_filter_idc != 1 ) ++ { ++ bs_write_se( s, sh->i_alpha_c0_offset >> 1 ); ++ bs_write_se( s, sh->i_beta_offset >> 1 ); ++ } ++ } ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.h +new file mode 100644 +index 000000000..c4fdb929f +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/h264enc/slice.h +@@ -0,0 +1,99 @@ ++#ifndef __H264_SLICE_H__ ++#define __H264_SLICE_H__ ++ ++#include "common.h" ++ ++enum slice_type_e ++{ ++ M_SLICE_TYPE_P = 0, ++ M_SLICE_TYPE_B = 1, ++ M_SLICE_TYPE_I = 2, ++}; ++ ++ ++ ++ ++#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) ++#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) ++ ++#define QP_MAX_SPEC (51) ++ ++#define X264_REF_MAX 1 ++#define SPEC_QP(x) MIN((x), QP_MAX_SPEC) ++ ++ ++typedef struct ++{ ++ h264_sps_t *sps; ++ h264_pps_t *pps; ++ ++ int i_type; ++ int i_first_mb; ++ int i_last_mb; ++ ++ int i_pps_id; ++ ++ int i_frame_num; ++ ++ int b_mbaff; ++ int b_field_pic; ++ int b_bottom_field; ++ ++ int i_idr_pic_id; /* -1 if nal_type != 5 */ ++ ++ int i_poc; ++ int i_delta_poc_bottom; ++ ++ int i_delta_poc[2]; ++ int i_redundant_pic_cnt; ++ ++ int b_direct_spatial_mv_pred; ++ ++ int b_num_ref_idx_override; ++ int i_num_ref_idx_l0_active; ++ int i_num_ref_idx_l1_active; ++ ++ int b_ref_pic_list_reordering[2]; ++ struct ++ { ++ int idc; ++ int arg; ++ } ref_pic_list_order[2][X264_REF_MAX]; ++ ++#if 0 ++ /* 使用默认的加æƒé¢„测 */ ++ /* P-frame weighting */ ++ int b_weighted_pred; ++ x264_weight_t weight[X264_REF_MAX*2][3]; ++#endif ++ int i_mmco_remove_from_end; ++ int i_mmco_command_count; ++ struct /* struct for future expansion */ ++ { ++ int i_difference_of_pic_nums; ++ int i_poc; ++ } mmco[X264_REF_MAX]; ++ ++ int i_cabac_init_idc; ++ ++ int i_qp; ++ int i_qp_delta; ++ int b_sp_for_swidth; ++ int i_qs_delta; ++ ++ /* deblocking filter */ ++ int i_disable_deblocking_filter_idc; ++ int i_alpha_c0_offset; ++ int i_beta_offset; ++} h264_slice_header_t; ++ ++ ++extern void h264e_slice_header_init(h264_slice_header_t *sh, ++ h264_sps_t *sps, h264_pps_t *pps, ++ int i_idr_pic_id, int i_frame, int i_qp); ++ ++extern void h264e_slice_header_write(bs_t *s, h264_slice_header_t *sh, int i_nal_ref_idc); ++ ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_buf.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_buf.h +new file mode 100644 +index 000000000..b977e0071 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_buf.h +@@ -0,0 +1,45 @@ ++#ifndef __HELIX_BUF_H__ ++#define __HELIX_BUF_H__ ++ ++enum helix_raw_format { ++ HELIX_TILE_MODE = 0, ++ HELIX_420P_MODE = 4, ++ HELIX_NV12_MODE = 8, ++ HELIX_NV21_MODE = 12, ++}; ++ ++ ++/* JPEG encode quantization table select level */ ++typedef enum { ++ LOW_QUALITY, ++ MEDIUMS_QUALITY, ++ HIGH_QUALITY ++} QUANT_QUALITY; ++ ++ ++struct h264_ref_tile { ++ unsigned int *yaddr; ++ unsigned int *caddr; ++ ++ dma_addr_t yaddr_pa; ++ dma_addr_t caddr_pa; ++}; ++ ++ ++/* basic memory description. */ ++struct ingenic_vcodec_mem { ++ size_t size; ++ void *va; ++ dma_addr_t pa; ++}; ++ ++struct video_frame_buffer { ++ struct ingenic_vcodec_mem fb_addr[3];// MAX_PLANES. ++ int num_planes; ++}; ++ ++ ++ ++extern int ingenic_vpu_start(void *priv); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_drv.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_drv.c +new file mode 100644 +index 000000000..dd7d70547 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_drv.c +@@ -0,0 +1,550 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* This program is free software; you can redistribute it and/or modify ++* it under the terms of the GNU General Public License version 2 as ++* published by the Free Software Foundation. ++* ++* This program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "helix_drv.h" ++#include "helix_ops.h" ++ ++static int vpu_on(struct ingenic_venc_dev *dev); ++static int vpu_off(struct ingenic_venc_dev *dev); ++ ++struct ingenic_venc_dev *g_dev = NULL; ++ ++ ++static int fops_vcodec_open(struct file *file) ++{ ++ struct ingenic_venc_dev *dev = video_drvdata(file); ++ struct ingenic_venc_ctx *ctx = NULL; ++ int ret = 0; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if(!ctx) ++ return -ENOMEM; ++ ++ mutex_lock(&dev->dev_mutex); ++ ++ if (!dev->id_counter) { ++ vpu_on(dev); ++ } ++ ++ ctx->id = dev->id_counter++; ++ v4l2_fh_init(&ctx->fh, video_devdata(file)); ++ file->private_data = &ctx->fh; ++ v4l2_fh_add(&ctx->fh); ++ //INIT_LIST_HEAD(&ctx->list); ++ ctx->dev = dev; ++ init_waitqueue_head(&ctx->queue); ++ ++ ingenic_vcodec_enc_init_default_params(ctx); ++ ++ ret = ingenic_vcodec_enc_ctrls_setup(ctx); ++ if(ret) { ++ dev_err(ctx->dev->dev, "Failed to setup ctrls() %d\n", ret); ++ goto err_ctrls_setup; ++ } ++ ++ ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_enc, ctx, &ingenic_vcodec_enc_queue_init); ++ if(IS_ERR((__force void *)ctx->m2m_ctx)) { ++ ret = PTR_ERR((__force void *)ctx->m2m_ctx); ++ ++ goto err_m2m_ctx_init; ++ } ++ ++ ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ dev_info(ctx->dev->dev, "Create instance [%d]@%p m2m_ctx=%p\n", ++ ctx->id, ctx, ctx->m2m_ctx); ++ ++ ++ dev_info(ctx->dev->dev, "%s vcodec [%d]\n", dev_name(dev->dev), ctx->id); ++ ++ return ret; ++err_m2m_ctx_init: ++ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); ++err_ctrls_setup: ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ kfree(ctx); ++ mutex_unlock(&dev->dev_mutex); ++ return ret; ++} ++ ++static int fops_vcodec_release(struct file *file) ++{ ++ ++ struct ingenic_venc_dev *dev = video_drvdata(file); ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(file->private_data); ++ ++ dev_info(ctx->dev->dev, "[%d] encoder release\n", ctx->id); ++ ++ mutex_lock(&dev->dev_mutex); ++ ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ v4l2_ctrl_handler_free(&ctx->ctrl_hdl); ++ v4l2_m2m_ctx_release(ctx->m2m_ctx); ++ ingenic_vcodec_enc_deinit_default_params(ctx); ++ ++ if (!(--dev->id_counter)) { ++ vpu_off(dev); ++ } ++ ++ kfree(ctx); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ return 0; ++} ++ ++static unsigned int fops_vcodec_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ struct ingenic_venc_dev *dev = video_drvdata(file); ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(file->private_data); ++ unsigned int ret = 0; ++ ++ if(mutex_lock_interruptible(&dev->dev_mutex)) { ++ return -ERESTARTSYS; ++ } ++ ++ ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); ++ ++ mutex_unlock(&dev->dev_mutex); ++ ++ return ret; ++} ++ ++static int fops_vcodec_mmap(struct file *file, ++ struct vm_area_struct *vma) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(file->private_data); ++ ++ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); ++} ++ ++static const struct v4l2_file_operations ingenic_venc_fops = { ++ .owner = THIS_MODULE, ++ .open = fops_vcodec_open, ++ .release = fops_vcodec_release, ++ .poll = fops_vcodec_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = fops_vcodec_mmap, ++}; ++ ++ ++#define vpu_readl(dev, offset) \ ++ readl(dev->reg_base + (offset)) ++ ++#define vpu_writel(dev, offset, data) \ ++ writel((data), dev->reg_base + (offset)) ++ ++static void inline vpu_clear_bits(struct ingenic_venc_dev *dev, unsigned int offset, unsigned int bits) ++{ ++ unsigned int val = vpu_readl(dev, offset); ++ val &= ~bits; ++ vpu_writel(dev, offset, val); ++} ++ ++ ++static irqreturn_t ingenic_vpu_irq(int irq, void *priv) ++{ ++ struct ingenic_venc_dev *dev = (struct ingenic_venc_dev *)priv; ++ struct ingenic_venc_ctx *ctx = dev->curr_ctx; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ ++ unsigned long flags; ++ ++ unsigned int efe_stat; ++ unsigned int sch_stat; ++ ++ spin_lock_irqsave(&dev->spinlock, flags); ++ ++ ctx->int_cond = 1; ++ ++ efe_stat = vpu_readl(dev, REG_EFE_STAT); ++ sch_stat = vpu_readl(dev, REG_SCH_STAT); ++ ++ /* disable all interrupts. */ ++ vpu_clear_bits(dev, REG_SCH_GLBC, 0x3f << 16); ++ if(sch_stat & SCH_STAT_ENDF){ ++ ++ if(sch_stat & SCH_STAT_JPGEND) { ++ ++ jpge_ctx->bslen = vpu_readl(dev, REG_JPGC_STAT) & 0xffffff; ++ ++ vpu_clear_bits(dev, REG_JPGC_STAT, JPGC_STAT_ENDF); ++ } else if(sch_stat & SCH_STAT_ENDF) { ++ h264e_ctx->r_bs_len = vpu_readl(dev, REG_SDE_CFG9); ++ h264e_ctx->r_rbsp_len = vpu_readl(dev, REG_SDE_CFG10); ++ h264e_ctx->encoded_bs_len = h264e_ctx->r_bs_len; ++ ++ vpu_clear_bits(dev, REG_SDE_STAT, SDE_STAT_BSEND); ++ vpu_clear_bits(dev, REG_DBLK_GSTA, DBLK_STAT_DOEND); ++ /*wakeup ...*/ ++ } else if(sch_stat & SCH_STAT_TIMEOUT){ ++ dev_err(ctx->dev->dev, "Sch h264 Timeout !\n"); ++ } else { ++ /*Error handling ...!*/ ++ ++ dev_err(ctx->dev->dev, "stat error %x\n", sch_stat); ++ /*wakeup ...*/ ++ } ++ ++ } ++ ctx->int_status = sch_stat; ++ spin_unlock_irqrestore(&dev->spinlock, flags); ++ ++ wake_up_interruptible(&ctx->queue); ++ ++ ++ return IRQ_HANDLED; ++} ++ ++ ++static void vpu_dump_regs(struct ingenic_venc_dev *dev) ++{ ++ ++ /* EMC */ ++ dev_info(dev->dev, "REG_EMC_FRM_SIZE : %d\n", vpu_readl(dev, REG_EMC_FRM_SIZE)); ++ dev_info(dev->dev, "REG_EMC_BS_ADDR : 0x%x\n", vpu_readl(dev, REG_EMC_BS_ADDR)); ++ dev_info(dev->dev, "REG_EMC_DBLK_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_DBLK_ADDR)); ++ dev_info(dev->dev, "REG_EMC_RECON_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_RECON_ADDR)); ++ dev_info(dev->dev, "REG_EMC_MV_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_MV_ADDR)); ++ dev_info(dev->dev, "REG_EMC_SE_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_SE_ADDR)); ++ dev_info(dev->dev, "REG_EMC_QPT_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_QPT_ADDR)); ++ dev_info(dev->dev, "REG_EMC_RC_RADDR: 0x%x\n", vpu_readl(dev, REG_EMC_RC_RADDR)); ++ dev_info(dev->dev, "REG_EMC_MOS_ADDR: 0x%x\n", vpu_readl(dev, REG_EMC_MOS_ADDR)); ++ dev_info(dev->dev, "REG_EMC_SLV_INIT: 0x%x\n", vpu_readl(dev, REG_EMC_SLV_INIT)); ++ dev_info(dev->dev, "REG_EMC_BS_SIZE: 0x%x\n", vpu_readl(dev, REG_EMC_BS_SIZE)); ++ dev_info(dev->dev, "REG_EMC_BS_STAT: 0x%x\n", vpu_readl(dev, REG_EMC_BS_STAT)); ++} ++ ++#define REG_VPU_STATUS ( *(volatile unsigned int*)0xb3200034 ) ++#define REG_VPU_LOCK ( *(volatile unsigned int*)0xb329004c ) ++#define REG_VPUCDR ( *(volatile unsigned int*)0xb0000030 ) ++#define REG_CPM_VPU_SWRST ( *(volatile unsigned int*)0xb00000c4 ) ++#define REG_VPU_TLBBASE (*(volatile unsigned int *)(0x30 + 0xb3200000)) ++#define CPM_VPU_SR (0x1<<31) ++#define CPM_VPU_STP (0x1<<30) ++#define CPM_VPU_ACK (0x1<<29) ++ ++#if 0 ++static int vpu_reset(struct ingenic_venc_dev *dev) ++{ ++ int timeout = 0xffffff; ++ ++ REG_CPM_VPU_SWRST |= CPM_VPU_STP; ++ while(!(REG_CPM_VPU_SWRST & CPM_VPU_ACK) && --timeout) ++ ; ++ ++ if(!timeout) { ++ printk("wait reset timeout!\n"); ++ } ++ ++ REG_CPM_VPU_SWRST = ((REG_CPM_VPU_SWRST | CPM_VPU_SR) & ~CPM_VPU_STP); ++ REG_CPM_VPU_SWRST = (REG_CPM_VPU_SWRST & ~CPM_VPU_SR & ~CPM_VPU_STP); ++ REG_VPU_LOCK = 0; ++ ++ return 0; ++} ++#endif ++/*global clk on.*/ ++static int vpu_on(struct ingenic_venc_dev *dev) ++{ ++ clk_prepare_enable(dev->clk_gate); ++ __asm__ __volatile__ ( ++ "mfc0 $2, $16, 7 \n\t" ++ "ori $2, $2, 0x340 \n\t" ++ "andi $2, $2, 0x3ff \n\t" ++ "mtc0 $2, $16, 7 \n\t" ++ "nop \n\t"); ++ ++ return 0; ++} ++ ++static int vpu_off(struct ingenic_venc_dev *dev) ++{ ++ clk_disable_unprepare(dev->clk_gate); ++ ++ return 0; ++} ++ ++#define VPU_RUN_TIMEOUT_MS (3000) ++int ingenic_vpu_start(void *priv) ++{ ++ struct ingenic_venc_ctx *ctx = (struct ingenic_venc_ctx *)priv; ++ struct ingenic_venc_dev *dev = ctx->dev; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct jpgd_ctx *jpgd_ctx = &ctx->jpgd_ctx; ++ unsigned int sch_glbc = 0; ++ unsigned int des_pa; ++ unsigned long flags; ++ int timeout = 0xffff; ++ int ret = 0; ++ ++ /* TODO: add lock.*/ ++ dev->curr_ctx = ctx; ++ ++ if(ctx->codec_id == CODEC_ID_H264E) { ++ des_pa = h264e_ctx->desc_pa; ++ } else if(ctx->codec_id == CODEC_ID_JPGE) { ++ des_pa = jpge_ctx->desc_pa; ++ } else if(ctx->codec_id == CODEC_ID_JPGD) { ++ des_pa = jpgd_ctx->desc_pa; ++ } ++ ++ vpu_on(dev); ++ ++ spin_lock_irqsave(&dev->spinlock, flags); ++ ctx->int_cond = 0; ++ ++ /*X2000 RESET*/ ++ /* vpu reset ... */ ++ vpu_writel(dev, REG_CFGC_SW_RESET, CFGC_SW_RESET_RST); ++ while(!(vpu_readl(dev, REG_CFGC_SW_RESET) & CFGC_SW_RESET_EARB_EMPT) && --timeout); ++ if(!timeout) { ++ dev_err(ctx->dev->dev, "%s, vpu_reset timeout!\n", __func__); ++ spin_unlock_irqrestore(&dev->spinlock, flags); ++ return -EINVAL; ++ } ++ ++ sch_glbc = SCH_GLBC_HIAXI | SCH_INTE_ACFGERR | SCH_INTE_BSERR | ++ SCH_INTE_ENDF | SCH_INTE_TLBERR | SCH_INTE_BSFULL; ++ ++ ++ /* type jpege, jpegd, h264e.*/ ++ vpu_writel(dev, REG_SCH_GLBC, sch_glbc); ++ ++ /*trigger start.*/ ++ vpu_writel(dev, REG_CFGC_ACM_CTRL, VDMA_ACFG_DHA(des_pa) | VDMA_ACFG_RUN); ++ ++ /* wait event time out ... */ ++ spin_unlock_irqrestore(&dev->spinlock, flags); ++ ++ ret = wait_event_interruptible_timeout(ctx->queue, ctx->int_cond, msecs_to_jiffies(VPU_RUN_TIMEOUT_MS)); ++ if(!ret) { ++ dev_err(ctx->dev->dev, "wait vpu run timeout!\n"); ++ dev_err(ctx->dev->dev, "efe_stat %x, sch_stat %x\n", vpu_readl(dev, REG_EFE_STAT), vpu_readl(dev, REG_SCH_STAT)); ++ ++ vpu_dump_regs(dev); ++ ret = -ETIMEDOUT; ++ } else if(ret == -ERESTARTSYS) { ++ dev_err(ctx->dev->dev, "vpu interrupted by a signal!\n"); ++ ++ } ++ ++ vpu_off(dev); ++ ++ return ret; ++} ++ ++int ingenic_vpu_stop(struct ingenic_venc_dev *dev) ++{ ++ return 0; ++} ++ ++static int ingeic_vcodec_probe(struct platform_device *pdev) ++{ ++ struct ingenic_venc_dev *dev; ++ struct video_device *vfd_enc; ++ int ret; ++ ++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); ++ if(!dev) ++ return -ENOMEM; ++ ++ ingenic_venc_dev_set(dev); ++ ++ dev->dev = &pdev->dev; ++ dev->plat_dev = pdev; ++ ++ /*io,clk,irq*/ ++ ++ dev->reg_base = of_iomap(pdev->dev.of_node, 0);; ++ if(IS_ERR(dev->reg_base)) { ++ ret = -ENODEV; ++ goto err_ioremap; ++ } ++ /*TODO: clk pm ...*/ ++ dev->irq = platform_get_irq(pdev, 0); ++ ret = devm_request_irq(&pdev->dev, dev->irq, ingenic_vpu_irq, 0, pdev->name, dev); ++ if(ret ) { ++ dev_err(&pdev->dev, "Failed to request vpu irq!\n"); ++ goto err_irq; ++ } ++ ++ /*clk_gate, power*/ ++ dev->clk_gate = clk_get(&pdev->dev, "power_helix"); ++ if (IS_ERR(dev->clk_gate)) { ++ ret = PTR_ERR(dev->clk_gate); ++ goto err_get_clk_gate; ++ } ++ ++#if 0 ++ dev->clk = clk_get(dev->dev,"cgu_vpu"); ++ if (IS_ERR(dev->clk)) { ++ ret = PTR_ERR(dev->clk); ++ goto err_get_clk_cgu; ++ } ++ ++ clk_set_rate(dev->clk, 300000000); ++#endif ++ ++ ++ ++ spin_lock_init(&dev->spinlock); ++ mutex_init(&dev->dev_mutex); ++ ++ dev->alloc_ctx = ingenic_vb2_dma_contig_init_ctx(&pdev->dev); ++ if(IS_ERR(dev->alloc_ctx)) { ++ ret = -ENOMEM; ++ goto err_ctx; ++ } ++ ++ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", "ingenic-v4l2-helix"); ++ ++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ if(ret) { ++ dev_err(&pdev->dev, "Failed to register v4l2_dev\n"); ++ goto err_v4l2; ++ } ++ ++ vfd_enc = video_device_alloc(); ++ if(!vfd_enc) { ++ dev_err(&pdev->dev, "Failed to alloc video device!\n"); ++ ret = -ENOMEM; ++ goto err_vdev; ++ } ++ ++ ++ vfd_enc->fops = &ingenic_venc_fops; ++ vfd_enc->ioctl_ops = &ingenic_venc_ioctl_ops; ++ vfd_enc->release = video_device_release; ++ vfd_enc->lock = &dev->dev_mutex; ++ vfd_enc->v4l2_dev = &dev->v4l2_dev; ++ vfd_enc->vfl_dir = VFL_DIR_M2M; ++ ++ snprintf(vfd_enc->name, sizeof(vfd_enc->name), "%s", INGENIC_VCODEC_ENC_NAME); ++ ++ video_set_drvdata(vfd_enc, dev); ++ dev->vfd_enc = vfd_enc; ++ platform_set_drvdata(pdev, dev); ++ ++ dev->m2m_dev_enc = v4l2_m2m_init(&ingenic_venc_m2m_ops); ++ if(IS_ERR((__force void *)dev->m2m_dev_enc)) { ++ dev_err(&pdev->dev, "Failed to init m2m device!\n"); ++ ret = PTR_ERR((__force void *)dev->m2m_dev_enc); ++ goto err_m2m; ++ } ++ ++ dev->encode_workqueue = alloc_ordered_workqueue(INGENIC_VCODEC_ENC_NAME, ++ WQ_MEM_RECLAIM | WQ_FREEZABLE); ++ if(!dev->encode_workqueue) { ++ dev_err(&pdev->dev, "Failed to create encode workqueue\n"); ++ ret = -EINVAL; ++ goto err_workq; ++ } ++ ++ ++ vfd_enc->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; ++ ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, INGENIC_HELIX_VIDEO_NR); ++ if(ret) { ++ dev_err(&pdev->dev, "Failed to register video device!\n"); ++ goto err_video_reg; ++ } ++ ++ ret = of_reserved_mem_device_init(dev->dev); ++ if(ret) ++ dev_warn(&pdev->dev, "failed to init reserved mem\n"); ++ ++ h264e_netlink_test(); ++ ++ dev_info(&pdev->dev, "encoder(helix) registered as /dev/video%d\n", ++ vfd_enc->num); ++ ++ return 0; ++err_reserved_mem_init: ++err_video_reg: ++err_workq: ++err_m2m: ++err_vdev: ++err_v4l2: ++err_ctx: ++err_get_clk_cgu: ++err_get_clk_gate: ++err_irq: ++err_ioremap: ++ return ret; ++} ++ ++static int ingeic_vcodec_remove(struct platform_device *pdev) ++{ ++ ++ return 0; ++} ++ ++static const struct of_device_id helix_of_match[] = { ++ { .compatible = "ingenic,x2000-helix"}, ++ { .compatible = "ingenic,m300-helix"}, ++ {}, ++}; ++ ++static struct platform_driver ingenic_vcodec_driver = { ++ .probe = ingeic_vcodec_probe, ++ .remove = ingeic_vcodec_remove, ++ .driver = { ++ .name = INGENIC_VCODEC_ENC_NAME, ++ .of_match_table = helix_of_match, ++ }, ++}; ++ ++static int __init helix_driver_init(void) ++{ ++ return platform_driver_register(&ingenic_vcodec_driver); ++} ++ ++static void __exit helix_driver_exit(void) ++{ ++ platform_driver_unregister(&ingenic_vcodec_driver); ++} ++module_init(helix_driver_init); ++module_exit(helix_driver_exit); ++ ++ ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Ingenic Video Codec v4l2 encoder driver."); +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_drv.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_drv.h +new file mode 100644 +index 000000000..22aacb139 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_drv.h +@@ -0,0 +1,177 @@ ++#ifndef __INGENIC_HELIX_DRV_H__ ++#define __INGENIC_HELIX_DRV_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++//#include "api/helix_x264_enc.h" ++//#include "api/helix_jpeg_enc.h" ++#include "api/helix.h" ++#include "helix_buf.h" ++ ++#include "h264e_rc.h" ++#include "jpge.h" ++#include "jpgd.h" ++ ++ ++#define INGENIC_VCODEC_ENC_NAME "helix-venc" ++#define INGENIC_VCODEC_MAX_PLANES 3 ++ ++ ++enum ingenic_fmt_type { ++ INGENIC_FMT_FRAME = 0, ++ INGENIC_FMT_ENC = 1, ++ INGENIC_FMT_DEC = 2, ++}; ++ ++struct ingenic_video_fmt { ++ u32 fourcc; ++ enum ingenic_fmt_type type; ++ u32 num_planes; ++ enum helix_raw_format format; ++}; ++ ++struct ingenic_codec_framesizes { ++ u32 fourcc; ++ struct v4l2_frmsize_stepwise stepwise; ++}; ++ ++struct ingenic_video_buf { ++ struct vb2_v4l2_buffer vb; ++ struct list_head list; ++ ++ struct video_frame_buffer buf; ++}; ++ ++ ++enum ingenic_q_type { ++ INGENIC_Q_DATA_SRC = 0, ++ INGENIC_Q_DATA_DST = 1, ++}; ++ ++/* Queue Data. */ ++struct ingenic_venc_q_data { ++ unsigned int visible_width; ++ unsigned int visible_height; ++ unsigned int coded_width; ++ unsigned int coded_height; ++ enum v4l2_field field; ++ unsigned int bytesperline[INGENIC_VCODEC_MAX_PLANES]; ++ unsigned int sizeimage[INGENIC_VCODEC_MAX_PLANES]; ++ struct ingenic_video_fmt *fmt; ++ ++ ++}; ++ ++/* ++ when ctx is created, IDLE ++ when start_streaming, START, ++ when abort, ABORT, ++*/ ++ ++enum ingenic_venc_state { ++ INGENIC_STATE_IDLE = 0, ++ INGENIC_STATE_HEADER, ++ INGENIC_STATE_RUNNING, ++ INGENIC_STATE_ABORT, ++}; ++ ++/* v4l2 set parm to sw_parm, */ ++/* sw_parm api to sliceinfo. */ ++/* Sliceinfo to dma desc. */ ++ ++/* helix_ctrl_if_start. */ ++ ++struct ingenic_venc_ctx { ++ struct ingenic_venc_dev *dev; ++ ++ struct v4l2_fh fh; ++ struct v4l2_m2m_ctx *m2m_ctx; ++ ++ ++ struct v4l2_ctrl_handler ctrl_hdl; ++ ++ int id; ++ ++ int capture_stopped; ++ int output_stopped; ++ ++ struct ingenic_venc_q_data q_data[2]; ++ enum ingenic_venc_state state; ++ ++ wait_queue_head_t queue; ++ ++ int int_cond; ++ int int_status; ++ ++ struct work_struct encode_work; ++ enum v4l2_colorspace colorspace; ++ //enum v4l2_ycbcr_encoding ycbcr_enc; ++ //enum v4l2_quantization quantization; ++ //enum v4l2_xfer_func xfer_func; ++ ++ int codec_id; ++#define CODEC_ID_H264E 1 ++#define CODEC_ID_JPGE 2 ++#define CODEC_ID_JPGD 3 ++ union { ++ struct h264e_ctx h264e_ctx; ++ struct jpge_ctx jpge_ctx; ++ struct jpgd_ctx jpgd_ctx; ++ }; ++ ++}; ++ ++ ++struct ingenic_venc_dev { ++ ++ struct v4l2_device v4l2_dev; ++ struct video_device *vfd_enc; ++ struct device *dev; ++ ++ struct v4l2_m2m_dev *m2m_dev_enc; ++ struct platform_device *plat_dev; ++ ++ struct mutex dev_mutex; ++ struct workqueue_struct *encode_workqueue; ++ ++ spinlock_t spinlock; ++ ++ struct ingenic_venc_ctx *curr_ctx; ++ struct vb2_dc_conf *alloc_ctx; ++ ++ int id_counter; ++ ++ void __iomem *reg_base; ++ int irq; ++ struct clk *clk_gate; ++ struct clk *clk; ++}; ++ ++ ++static inline struct ingenic_venc_ctx *fh_to_ctx(struct v4l2_fh *fh) ++{ ++ return container_of(fh, struct ingenic_venc_ctx, fh); ++} ++ ++static inline struct ingenic_venc_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) ++{ ++ return container_of(ctrl->handler, struct ingenic_venc_ctx, ctrl_hdl); ++} ++ ++/* 内核全局g_dev.*/ ++extern struct ingenic_venc_dev *g_dev; ++static inline void ingenic_venc_dev_set(struct ingenic_venc_dev *dev) ++{ ++ g_dev = dev; ++} ++static inline struct ingenic_venc_dev *ingenic_venc_dev_get(void) ++{ ++ return g_dev; ++} ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_ops.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_ops.c +new file mode 100644 +index 000000000..4b26f5b65 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_ops.c +@@ -0,0 +1,1354 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* This program is free software; you can redistribute it and/or modify ++* it under the terms of the GNU General Public License version 2 as ++* published by the Free Software Foundation. ++* ++* This program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++*/ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "helix_drv.h" ++#include "helix_ops.h" ++ ++#include "api/helix.h" ++ ++#include "h264e_rc.h" ++#include "jpge.h" ++#include "jpgd.h" ++ ++ ++#define fh_to_ctx(__fh) container_of(__fh, struct ingenic_venc_ctx, fh) ++#define NUM_SUPPORTED_FRAMESIZE 3 ++ ++#define INGENIC_VENC_MIN_W 160U ++#define INGENIC_VENC_MIN_H 120U ++#define INGENIC_VENC_MAX_W 2560U ++#define INGENIC_VENC_MAX_H 2048U ++ ++#define MAX_SUPPORT_FRAME_BUFFERS 3 ++ ++ ++ ++#define pixelformat_str(a) a >> 0, a >> 8, a >> 16, a >> 24 ++ ++ ++static struct ingenic_video_fmt ingenic_video_formats[] = { ++ /* output */ ++ { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 2, ++ .format = HELIX_NV12_MODE, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 2, ++ .format = HELIX_NV21_MODE, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_YUV420, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 3, ++ .format = HELIX_420P_MODE, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_JPEG, ++ .type = INGENIC_FMT_DEC, ++ .num_planes = 1, ++ }, ++ /*capture*/ ++ /* video encoder idx */ ++ { ++ .fourcc = V4L2_PIX_FMT_H264, ++ .type = INGENIC_FMT_ENC, ++ .num_planes = 1, ++ }, ++ { ++ .fourcc = V4L2_PIX_FMT_JPEG, ++ .type = INGENIC_FMT_ENC, ++ .num_planes = 1, ++ }, ++ { /* jpeg decoder */ ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .type = INGENIC_FMT_FRAME, ++ .num_planes = 2, ++ .format = HELIX_NV12_MODE, ++ }, ++ ++}; ++ ++#define NUM_FORMATS ARRAY_SIZE(ingenic_video_formats) ++#define OUT_FMT_IDX 0 ++#define CAP_FMT_IDX (ARRAY_SIZE(ingenic_video_formats) - 4) ++ ++static const struct ingenic_codec_framesizes ingenic_venc_framesizes[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_H264, ++ .stepwise = { INGENIC_VENC_MIN_W, INGENIC_VENC_MAX_W, 16, ++ INGENIC_VENC_MIN_H, INGENIC_VENC_MAX_H, 16}, ++ }, ++}; ++ ++static struct ingenic_venc_q_data *ingenic_venc_get_q_data(struct ingenic_venc_ctx *ctx, ++ enum v4l2_buf_type type); ++ ++ ++static int vidioc_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct ingenic_venc_ctx *ctx = ctrl_to_ctx(ctrl); ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct h264e_params *h264_p = &h264e_ctx->p; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct jpge_params *jpge_p = &jpge_ctx->p; ++ int ret = 0; ++ ++ switch(ctrl->id) { ++ case V4L2_CID_MPEG_VIDEO_BITRATE: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_BITRATE val = %d\n", ctrl->val); ++ h264_p->bitrate = ctrl->val; ++ break; ++#if 0 ++ case V4L2_CID_MPEG_VIDEO_B_FRAMES: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_B_FRAMES val = %d\n", ctrl->val); ++ break; ++#endif ++ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP val = %d\n", ctrl->val); ++ h264_p->i_qp = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP val = %d\n", ctrl->val); ++ h264_p->p_qp = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE val = %d\n", ctrl->val); ++ h264_p->frame_rc_enable = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_H264_MIN_QP val = %d\n", ctrl->val); ++ h264_p->h264_min_qp = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_H264_MAX_QP val = %d\n", ctrl->val); ++ h264_p->h264_max_qp = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_HEADER_MODE: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_HEADER_MODE val = %d\n", ctrl->val); ++ h264_p->h264_hdr_mode = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE val = %d\n", ctrl->val); ++ h264_p->mb_rc_enable = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_H264_PROFILE: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_H264_PROFILE val = %d\n", ctrl->val); ++ h264_p->h264_profile = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_H264_LEVEL: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_H264_LEVEL val = %d\n", ctrl->val); ++ h264_p->h264_level = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_BITRATE_MODE val = %d\n", ctrl->val); ++ h264_p->rc_mode = ctrl->val; ++ break; ++ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_H264_I_PERIOD val = %d\n", ctrl->val); ++ break; ++ ++ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: ++ dev_dbg(ctx->dev->dev, "V4L2_CID_MPEG_VIDEO_GOP_SIZE val = %d\n", ctrl->val); ++ h264_p->gop_size = ctrl->val; ++ break; ++ ++ case V4L2_CID_JPEG_COMPRESSION_QUALITY: ++ dev_info(ctx->dev->dev, "V4L2_CID_JPEG_COMPRESSION_QUALITY = %d\n", ctrl->val); ++ jpge_p->compr_quality = ctrl->val; ++ break; ++ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++ ++} ++ ++static const struct v4l2_ctrl_ops ingenic_venc_ctrl_ops = { ++ .s_ctrl = vidioc_s_ctrl, ++}; ++ ++static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) ++{ ++ struct ingenic_video_fmt *fmt; ++ int i,j = 0; ++ ++ int start_index = output_queue ? OUT_FMT_IDX : CAP_FMT_IDX; ++ ++ for(i = start_index; i < NUM_FORMATS; i++) { ++ ++ if(j == f->index) { ++ fmt = &ingenic_video_formats[i]; ++ f->pixelformat = fmt->fourcc; ++ memset(f->reserved, 0, sizeof(f->reserved)); ++ return 0; ++ } ++ ++ j++; ++ } ++ ++ return -EINVAL; ++} ++ ++ ++static int vidioc_enum_framesizes(struct file *file, void *fh, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ int i = 0; ++ if(fsize->index != 0) ++ return -EINVAL; ++ ++ for(i = 0; i < NUM_SUPPORTED_FRAMESIZE; i++) { ++ if(fsize->pixel_format != ingenic_venc_framesizes[i].fourcc) ++ continue; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; ++ fsize->stepwise = ingenic_venc_framesizes[i].stepwise; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return vidioc_enum_fmt(f, false); ++} ++static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ return vidioc_enum_fmt(f, true); ++} ++ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ strlcpy(cap->driver, INGENIC_VCODEC_ENC_NAME, sizeof(cap->driver)); ++ strlcpy(cap->bus_info, "vpu-helix", sizeof(cap->bus_info)); ++ strlcpy(cap->card, "vpu-helix", sizeof(cap->card)); ++ ++ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | ++ V4L2_CAP_VIDEO_CAPTURE_MPLANE | ++ V4L2_CAP_VIDEO_OUTPUT_MPLANE; ++ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; ++ ++ return 0; ++} ++ ++ ++static int vidioc_s_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *a) ++{ ++ if(a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static ssize_t ++h264e_encoded_headers(struct ingenic_venc_ctx *ctx) ++{ ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct ingenic_venc_q_data *q_data_src; ++ struct ingenic_venc_q_data *q_data_dst; ++ int ret = 0; ++ ++ q_data_src = ingenic_venc_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); ++ q_data_dst = ingenic_venc_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ ++ ret = h264e_set_fmt(h264e_ctx, q_data_src->coded_width, ++ q_data_src->coded_height, q_data_src->fmt->format); ++ if(ret < 0) { ++ return ret; ++ } ++ ++ ret = h264e_generate_headers(h264e_ctx, 0); ++ if(ret < 0) ++ return ret; ++ ++ return h264e_ctx->bs_header_size; ++} ++ ++struct h264_header { ++ unsigned int size; ++ unsigned char header; ++}; ++ ++static int vidioc_g_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *a) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_venc_q_data *q_data; ++ struct ingenic_video_fmt *fmt; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct h264_header *h = (struct h264_header *)a->parm.raw_data; ++ unsigned int *size = 0; ++ ++ if(ctx->codec_id == CODEC_ID_H264E) { ++ h264e_encoded_headers(ctx); ++ ++ h->size = h264e_ctx->bs_header_size; ++ memcpy(&h->header, h264e_ctx->bs_header, h264e_ctx->bs_header_size); ++ } ++ return 0; ++} ++ ++static struct ingenic_venc_q_data *ingenic_venc_get_q_data(struct ingenic_venc_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ if(V4L2_TYPE_IS_OUTPUT(type)) ++ return &ctx->q_data[INGENIC_Q_DATA_SRC]; ++ ++ return &ctx->q_data[INGENIC_Q_DATA_DST]; ++} ++ ++static struct ingenic_video_fmt *ingenic_venc_find_format(struct v4l2_format *f, int isout) ++{ ++ struct ingenic_video_fmt *fmt; ++ int i; ++ int start_index = isout ? OUT_FMT_IDX : CAP_FMT_IDX; ++ ++ for(i = start_index; i < NUM_FORMATS; i++) { ++ fmt = &ingenic_video_formats[i]; ++ if(fmt->fourcc == f->fmt.pix_mp.pixelformat) ++ return fmt; ++ } ++ ++ return NULL; ++} ++ ++static int vidioc_try_fmt(struct v4l2_format *f, struct ingenic_video_fmt *fmt) ++{ ++ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; ++ int i; ++ ++ pix_fmt_mp->field = V4L2_FIELD_NONE; ++ ++ if(fmt->type == INGENIC_FMT_FRAME) { ++ int tmp_w, tmp_h; ++ ++ pix_fmt_mp->height = clamp(pix_fmt_mp->height, ++ INGENIC_VENC_MIN_H, ++ INGENIC_VENC_MAX_H); ++ pix_fmt_mp->width = clamp(pix_fmt_mp->width, ++ INGENIC_VENC_MIN_W, ++ INGENIC_VENC_MAX_W); ++ ++#if 1 ++ tmp_w = ALIGN(pix_fmt_mp->width, 16); ++ tmp_h = pix_fmt_mp->height; ++ /*tmp_h = ALIGN(pix_fmt_mp->height, 16);*/ ++ pr_info("tmp_w %d tmp_h %d, w %d h %d\n", ++ tmp_w, tmp_h, ++ pix_fmt_mp->width, ++ pix_fmt_mp->height); ++#else ++ tmp_w = pix_fmt_mp->width; ++ tmp_h = pix_fmt_mp->height; ++#endif ++ pix_fmt_mp->num_planes = fmt->num_planes; ++ pix_fmt_mp->plane_fmt[0].sizeimage = ++ tmp_w * tmp_h; ++ ++ pix_fmt_mp->plane_fmt[0].bytesperline = tmp_w; ++ ++ if(pix_fmt_mp->num_planes == 2) { ++ pix_fmt_mp->plane_fmt[1].sizeimage = ++ tmp_w * tmp_h / 2; ++ pix_fmt_mp->plane_fmt[2].sizeimage = 0; ++ ++ pix_fmt_mp->plane_fmt[1].bytesperline = tmp_w; ++ pix_fmt_mp->plane_fmt[2].bytesperline = 0; ++ } else if(pix_fmt_mp->num_planes == 3) { ++ pix_fmt_mp->plane_fmt[1].sizeimage = ++ pix_fmt_mp->plane_fmt[2].sizeimage = ++ (tmp_w * tmp_h) / 4; ++ ++ pix_fmt_mp->plane_fmt[1].bytesperline = ++ pix_fmt_mp->plane_fmt[2].bytesperline = ++ tmp_w / 2; ++ } ++ ++ } else { ++ pix_fmt_mp->num_planes = 1; ++ pix_fmt_mp->plane_fmt[0].bytesperline = 0; ++ ++ /*restrict output bs buffer size, max width * height. ++ sizeimage can be set by userspace. ++ */ ++ if(pix_fmt_mp->plane_fmt[0].sizeimage) { ++ pix_fmt_mp->plane_fmt[0].sizeimage = min(pix_fmt_mp->plane_fmt[0].sizeimage , pix_fmt_mp->width * pix_fmt_mp->height * 3 / 4); ++ } else { ++ pix_fmt_mp->plane_fmt[0].sizeimage = pix_fmt_mp->width * pix_fmt_mp->height * 3 / 4; ++ } ++ } ++ ++ for(i = 0; i < pix_fmt_mp->num_planes; i++) { ++ memset(&(pix_fmt_mp->plane_fmt[i].reserved[0]), 0x0, ++ sizeof(pix_fmt_mp->plane_fmt[0].reserved)); ++ } ++ ++// pix_fmt_mp->flags = 0; ++ ++ memset(&pix_fmt_mp->reserved, 0x0, ++ sizeof(pix_fmt_mp->reserved)); ++ ++ return 0; ++} ++ ++static int vidioc_s_fmt_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_venc_q_data *q_data; ++ struct ingenic_video_fmt *fmt; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ int i, ret; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if(!vq) { ++ dev_err(ctx->dev->dev, "failed to get cap vq !\n"); ++ return -EINVAL; ++ } ++ ++ if(vb2_is_busy(vq)) { ++ dev_err(ctx->dev->dev, "cap vq is busy!\n"); ++ return -EINVAL; ++ } ++ ++ q_data = ingenic_venc_get_q_data(ctx, f->type); ++ if(!q_data) { ++ dev_err(ctx->dev->dev, "fail to get cap q data!\n"); ++ return -EINVAL; ++ } ++ ++ ++ fmt = ingenic_venc_find_format(f, 0); ++ if(!fmt) { ++ /* change to the first support cap format.*/ ++ f->fmt.pix.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ /* if buf type MPLANE, use pix_mp ..*/ ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ fmt = ingenic_venc_find_format(f, 0); ++ } ++ ++ ++ q_data->fmt = fmt; ++ ++ ret = vidioc_try_fmt(f, q_data->fmt); ++ if(ret) ++ return ret; ++ ++ q_data->coded_width = f->fmt.pix_mp.width; ++ q_data->coded_height = f->fmt.pix_mp.height; ++ q_data->field = f->fmt.pix_mp.field; ++ ++ for(i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ struct v4l2_plane_pix_format *plane_fmt; ++ ++ plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; ++ q_data->bytesperline[i] = plane_fmt->bytesperline; ++ q_data->sizeimage[i] = plane_fmt->sizeimage; ++ } ++ ++ /* init hw interface. */ ++ if(f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_H264) { ++ ctx->codec_id = CODEC_ID_H264E; ++ ++ h264e_set_priv(h264e_ctx, ctx); ++ ret = h264e_encoder_init(h264e_ctx); ++ ++ } else if(f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_JPEG) { ++ ctx->codec_id = CODEC_ID_JPGE; ++ ++ jpeg_encoder_set_priv(jpge_ctx, ctx); ++ ret = jpeg_encoder_init(jpge_ctx); ++ ++ } ++ ++ return ret; ++} ++ ++ ++static int vidioc_s_fmt_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_venc_q_data *q_data; ++ struct ingenic_video_fmt *fmt; ++ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; ++ struct jpgd_ctx *jpgd_ctx = &ctx->jpgd_ctx; ++ int ret, i; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if(!vq) { ++ dev_err(ctx->dev->dev, "fail to get out vq!\n"); ++ return -EINVAL; ++ } ++ if(vb2_is_busy(vq)) { ++ dev_err(ctx->dev->dev, "out vq is busy!\n"); ++ return -EINVAL; ++ } ++ ++ q_data = ingenic_venc_get_q_data(ctx, f->type); ++ if(!q_data) { ++ dev_err(ctx->dev->dev, "failed to get out q_data!\n"); ++ return -EINVAL; ++ } ++ ++ ++ dev_dbg(ctx->dev->dev, "s_fmt_out f->fmt %x, %c%c%c%c \n", f->fmt.pix_mp.pixelformat, pixelformat_str(f->fmt.pix_mp.pixelformat)); ++ fmt = ingenic_venc_find_format(f, 1); ++ if(!fmt) { ++ /* change to the first support cap format.*/ ++ f->fmt.pix.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ fmt = ingenic_venc_find_format(f, 1); ++ } ++ ++ ++ pix_fmt_mp->height = clamp(pix_fmt_mp->height, ++ INGENIC_VENC_MIN_H, ++ INGENIC_VENC_MAX_H); ++ pix_fmt_mp->width = clamp(pix_fmt_mp->width, ++ INGENIC_VENC_MIN_W, ++ INGENIC_VENC_MAX_W); ++ ++ q_data->visible_width = f->fmt.pix_mp.width; ++ q_data->visible_height = f->fmt.pix_mp.height; ++ q_data->fmt = fmt; ++ ret = vidioc_try_fmt(f, q_data->fmt); ++ if (ret) ++ return ret; ++ ++ q_data->coded_width = f->fmt.pix_mp.width; ++ q_data->coded_height = f->fmt.pix_mp.height; ++ ++ dev_dbg(ctx->dev->dev, "s_fmt_out q_data->coded_width: %d, q_data->coded_height: %d\n", ++ q_data->coded_width, q_data->coded_height); ++ ++ q_data->field = f->fmt.pix_mp.field; ++ ctx->colorspace = f->fmt.pix_mp.colorspace; ++ //ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; ++ //ctx->quantization = f->fmt.pix_mp.quantization; ++ //ctx->xfer_func = f->fmt.pix_mp.xfer_func; ++ ++ ++ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { ++ struct v4l2_plane_pix_format *plane_fmt; ++ ++ plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; ++ q_data->bytesperline[i] = plane_fmt->bytesperline; ++ q_data->sizeimage[i] = plane_fmt->sizeimage; ++ } ++ ++ if(f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_JPEG) { ++ ctx->codec_id = CODEC_ID_JPGD; ++ ++ jpeg_decoder_set_priv(jpgd_ctx, ctx); ++ jpeg_decoder_init(jpgd_ctx); ++ } ++ ++ ++ return 0; ++} ++ ++static int vidioc_g_fmt(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ struct vb2_queue *vq; ++ struct ingenic_venc_q_data *q_data; ++ int i; ++ ++ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ ++ q_data = ingenic_venc_get_q_data(ctx, f->type); ++ ++ pix->width = q_data->coded_width; ++ pix->height = q_data->coded_height; ++ pix->pixelformat = q_data->fmt->fourcc; ++ pix->field = q_data->field; ++ pix->num_planes = q_data->fmt->num_planes; ++ for (i = 0; i < pix->num_planes; i++) { ++ pix->plane_fmt[i].bytesperline = q_data->bytesperline[i]; ++ pix->plane_fmt[i].sizeimage = q_data->sizeimage[i]; ++ memset(&(pix->plane_fmt[i].reserved[0]), 0x0, ++ sizeof(pix->plane_fmt[i].reserved)); ++ } ++ ++// pix->flags = 0; ++ pix->colorspace = ctx->colorspace; ++// pix->ycbcr_enc = ctx->ycbcr_enc; ++// pix->quantization = ctx->quantization; ++// pix->xfer_func = ctx->xfer_func; ++ ++ ++ dev_dbg(ctx->dev->dev, "g_fmt f->type %d\n", f->type); ++ dev_dbg(ctx->dev->dev, "pixel_format = %x, %c%c%c%c\n", pix->pixelformat, pixelformat_str(pix->pixelformat)); ++ dev_dbg(ctx->dev->dev, "pix->num_planes %d\n", pix->num_planes); ++ ++ return 0; ++} ++ ++ ++static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct ingenic_video_fmt *fmt; ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ fmt = ingenic_venc_find_format(f, 0); ++ if (!fmt) { ++ f->fmt.pix.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[CAP_FMT_IDX].fourcc; ++ fmt = ingenic_venc_find_format(f, 0); ++ } ++ f->fmt.pix_mp.colorspace = ctx->colorspace; ++ //f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; ++ //f->fmt.pix_mp.quantization = ctx->quantization; ++ //f->fmt.pix_mp.xfer_func = ctx->xfer_func; ++ ++ return vidioc_try_fmt(f, fmt); ++} ++ ++static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ ++ struct ingenic_video_fmt *fmt; ++ ++ fmt = ingenic_venc_find_format(f, 1); ++ if (!fmt) { ++ f->fmt.pix.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ f->fmt.pix_mp.pixelformat = ingenic_video_formats[OUT_FMT_IDX].fourcc; ++ fmt = ingenic_venc_find_format(f, 1); ++ } ++ if (!f->fmt.pix_mp.colorspace) { ++ f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; ++ // f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; ++ // f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; ++ // f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; ++ } ++ ++ return vidioc_try_fmt(f, fmt); ++} ++ ++static int vidioc_g_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ // TODO ++ ++ return 0; ++} ++ ++static int vidioc_s_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ //TODO ++ return 0; ++} ++ ++ ++static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ if(ctx->state == INGENIC_STATE_ABORT) { ++ return -EIO; ++ } ++ ++ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); ++} ++ ++static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); ++} ++ ++static int vidioc_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); ++} ++ ++static int vidioc_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type type) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); ++} ++ ++static int vidioc_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *reqbufs) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); ++ ++} ++ ++static int vidioc_querybuf(struct file *file, void *priv, ++ struct v4l2_buffer *buf) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); ++ ++} ++ ++static int vidioc_expbuf(struct file *file, void *priv, ++ struct v4l2_exportbuffer *eb) ++{ ++ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); ++} ++ ++static int vidioc_create_bufs(struct file *file, void *priv, ++ struct v4l2_create_buffers *create) ++{ ++ struct ingenic_venc_ctx *ctx = fh_to_ctx(priv); ++ ++ return v4l2_m2m_create_bufs(file, ctx->m2m_ctx, create); ++} ++static int vidioc_prepare_buf(struct file *file, void *fh, struct v4l2_buffer *b) ++{ ++ return 0; ++} ++ ++const struct v4l2_ioctl_ops ingenic_venc_ioctl_ops = { ++ ++ .vidioc_streamon = vidioc_streamon, ++ .vidioc_streamoff = vidioc_streamoff, ++ ++ .vidioc_reqbufs = vidioc_reqbufs, ++ .vidioc_querybuf = vidioc_querybuf, ++ .vidioc_qbuf = vidioc_qbuf, ++ .vidioc_dqbuf = vidioc_dqbuf, ++ ++ .vidioc_querycap = vidioc_querycap, ++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap_mplane, ++ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out_mplane, ++ .vidioc_enum_framesizes = vidioc_enum_framesizes, ++ ++ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, ++ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, ++ .vidioc_expbuf = vidioc_expbuf, ++ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++ ++ .vidioc_s_parm = vidioc_s_parm, ++ .vidioc_g_parm = vidioc_g_parm, ++ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap, ++ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out, ++ ++ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, ++ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, ++ ++ .vidioc_create_bufs = vidioc_create_bufs, ++ .vidioc_prepare_buf = vidioc_prepare_buf, ++ ++ .vidioc_g_selection = vidioc_g_selection, ++ .vidioc_s_selection = vidioc_s_selection, ++}; ++ ++ ++static int vb2ops_venc_queue_setup(struct vb2_queue *vq, ++ unsigned int *nbuffers, ++ unsigned int *nplanes, ++ unsigned int sizes[], ++ struct device *alloc_ctxs[]) ++{ ++ struct ingenic_venc_ctx *ctx = vb2_get_drv_priv(vq); ++ struct ingenic_venc_q_data *q_data; ++ int i; ++ ++ q_data = ingenic_venc_get_q_data(ctx, vq->type); ++ if(q_data == NULL) ++ return -EINVAL; ++ ++ if(*nplanes) { ++ for(i = 0; i < *nplanes; i++) { ++ if(vq->memory != VB2_MEMORY_USERPTR){ ++ q_data->sizeimage[i] = q_data->sizeimage[i]/q_data->coded_height * ALIGN(q_data->coded_height, 16); ++ sizes[i]= sizes[i] / q_data->coded_height * ALIGN(q_data->coded_height, 16); ++ } ++ if(sizes[i] < q_data->sizeimage[i]) { ++ return -EINVAL; ++ } ++ } ++ } else { ++ *nplanes = q_data->fmt->num_planes; ++ for (i = 0; i < *nplanes; i++) { ++ sizes[i] = q_data->sizeimage[i]; ++ alloc_ctxs[i] = ctx->dev->dev; ++ } ++ } ++ ++ ++ dev_dbg(ctx->dev->dev, "*nplanes %d, sizes[0] %d\n", *nplanes, sizes[0]); ++ for(i = 0; i<*nplanes ; i++) { ++ dev_dbg(ctx->dev->dev, "plane %d, sizes[%d] %d, type %d\n", i, i, sizes[i], vq->type); ++ } ++ ++ if(*nbuffers > MAX_SUPPORT_FRAME_BUFFERS) ++ *nbuffers = MAX_SUPPORT_FRAME_BUFFERS; ++ ++ return 0; ++} ++ ++static int vb2ops_venc_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct ingenic_venc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct ingenic_venc_q_data *q_data; ++ int i; ++ ++ q_data = ingenic_venc_get_q_data(ctx, vb->vb2_queue->type); ++ ++ for(i = 0; i < q_data->fmt->num_planes; i++) { ++ if(vb2_plane_size(vb, i) > q_data->sizeimage[i]) { ++ ++ dev_err(ctx->dev->dev, "Failed to prepare buf!\n"); ++ ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static void vb2ops_venc_buf_queue(struct vb2_buffer *vb) ++{ ++ struct ingenic_venc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ ++ v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); ++ return; ++} ++ ++ ++static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct ingenic_venc_ctx *ctx = vb2_get_drv_priv(q); ++ struct ingenic_venc_q_data *q_data_src; ++ struct ingenic_venc_q_data *q_data_dst; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct jpgd_ctx *jpgd_ctx = &ctx->jpgd_ctx; ++ int ret = 0; ++ ++ if(V4L2_TYPE_IS_OUTPUT(q->type)) { ++ ctx->output_stopped = 0; ++ } else { ++ ctx->capture_stopped = 0; ++ } ++ ++ if(ctx->output_stopped || ctx->capture_stopped) ++ return 0; ++ ++ q_data_src = ingenic_venc_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); ++ q_data_dst = ingenic_venc_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ ++ if(ctx->codec_id == CODEC_ID_H264E) { ++ dev_info(ctx->dev->dev, "h264 start streaming \n"); ++ ret = h264e_set_fmt(h264e_ctx, q_data_src->coded_width, ++ q_data_src->coded_height, q_data_src->fmt->format); ++ if(ret < 0) { ++ return ret; ++ } ++ ret = h264e_alloc_workbuf(h264e_ctx); ++ if(ret < 0) { ++ dev_err(ctx->dev->dev, "h264e failed to alloc work buffer!\n"); ++ return ret; ++ } ++ ctx->state = INGENIC_STATE_HEADER; ++ ++ ret = h264e_generate_headers(h264e_ctx, 1); ++ if(ret < 0) ++ return ret; ++ ++ } else if(ctx->codec_id == CODEC_ID_JPGE) { ++ dev_info(ctx->dev->dev, "jpge start streaming \n"); ++ ++ ret = jpeg_encoder_set_fmt(jpge_ctx, q_data_src->coded_width, ++ q_data_src->coded_height, q_data_src->fmt->format); ++ if(ret < 0) { ++ return ret; ++ } ++ ret = jpeg_encoder_alloc_workbuf(jpge_ctx); ++ if(ret < 0) { ++ dev_err(ctx->dev->dev, "jpge failed to alloc work buffer!\n"); ++ return ret; ++ } ++ ctx->state = INGENIC_STATE_RUNNING; ++ ++ } else if(ctx->codec_id == CODEC_ID_JPGD) { ++ dev_info(ctx->dev->dev, "jpgd start streaming \n"); ++ ++ ret = jpeg_decoder_set_fmt(jpgd_ctx, q_data_dst->coded_width, ++ q_data_dst->coded_height, q_data_dst->fmt->format); ++ if(ret < 0) { ++ return ret; ++ } ++ ret = jpeg_decoder_alloc_workbuf(jpgd_ctx); ++ if(ret < 0) { ++ dev_err(ctx->dev->dev, "jpgd failed to alloc work buffer!\n"); ++ return ret; ++ } ++ ctx->state = INGENIC_STATE_RUNNING; ++ ++ } else { ++ dev_info(ctx->dev->dev, "Invalid Codec ID: %d\n", ctx->codec_id); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void vb2ops_venc_stop_streaming(struct vb2_queue *q) ++{ ++ ++ struct ingenic_venc_ctx *ctx = vb2_get_drv_priv(q); ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ struct ingenic_venc_q_data *q_data_src; ++ struct ingenic_venc_q_data *q_data_dst; ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct jpgd_ctx *jpgd_ctx = &ctx->jpgd_ctx; ++ ++// if(q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ++ ++ /* KERNEL 3.10 .*/ ++ while((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { ++ dst_buf->vb2_buf.planes[0].bytesused = 0; ++ dst_buf->flags |= V4L2_BUF_FLAG_DONE; ++// ktime_get_real_ts64(&dst_buf->vb2_buf.timestamp); ++ dst_buf->vb2_buf.timestamp = ktime_get(); ++ /*ä¿è¯ä¸¤ä¸ªçš„æ—¶é—´æˆ³ä¸ä¸€æ ·.*/ ++ dst_buf->vb2_buf.timestamp = ktime_add_ns(dst_buf->vb2_buf.timestamp, 10); ++ /* work around, return buffer to userspace with 0 byteused. */ ++ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); ++ } ++// } else { ++ while((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) { ++ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); ++ } ++// } ++ ++ if(q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ++ ctx->capture_stopped = 1; ++ else ++ ctx->output_stopped = 1; ++ ++ if((ctx->capture_stopped && ctx->output_stopped) == 0) { ++ return; ++ } ++ ++ q_data_src = ingenic_venc_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); ++ q_data_dst = ingenic_venc_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ ++ switch(ctx->codec_id) { ++ case CODEC_ID_H264E: ++ dev_info(ctx->dev->dev, "h264 stop streaming !\n"); ++ h264e_free_workbuf(h264e_ctx); ++ break; ++ case CODEC_ID_JPGE: ++ dev_info(ctx->dev->dev, "jpge stop streaming !\n"); ++ jpeg_encoder_free_workbuf(jpge_ctx); ++ break; ++ case CODEC_ID_JPGD: ++ dev_info(ctx->dev->dev, "jpgd stop streaming !\n"); ++ jpeg_decoder_free_workbuf(jpgd_ctx); ++ break; ++ default: ++ break; ++ } ++ ++ ctx->state = INGENIC_STATE_IDLE; ++ return; ++} ++ ++static const struct vb2_ops ingenic_venc_vb2_ops = { ++ .queue_setup = vb2ops_venc_queue_setup, ++ .buf_prepare = vb2ops_venc_buf_prepare, ++ .buf_queue = vb2ops_venc_buf_queue, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++ .start_streaming = vb2ops_venc_start_streaming, ++ .stop_streaming = vb2ops_venc_stop_streaming, ++}; ++ ++static void ingenic_venc_worker(struct work_struct *work) ++{ ++ ++ struct ingenic_venc_ctx *ctx = container_of(work, struct ingenic_venc_ctx, encode_work); ++ struct ingenic_venc_dev *dev = ctx->dev; ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ struct ingenic_video_buf *src_video_buf, *dst_video_buf; ++ ++ struct video_frame_buffer *src_frame = NULL; ++ struct video_frame_buffer *dst_frame = NULL; ++ ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct jpgd_ctx *jpgd_ctx = &ctx->jpgd_ctx; ++ int force_idr = 0; ++ int keyframe = 0; ++ ++ int i = 0; ++ int ret = 0; ++ ++ ++ src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); ++ src_video_buf = container_of(src_buf, struct ingenic_video_buf, vb); ++ src_frame = &src_video_buf->buf; ++ ++ memset(src_frame, 0, sizeof(src_frame)); ++ src_frame->num_planes = src_buf->vb2_buf.num_planes; ++ for(i = 0; i < src_buf->vb2_buf.num_planes; i++) { ++ src_frame->fb_addr[i].pa = ingenic_vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, i); ++ if (src_buf->vb2_buf.memory == VB2_MEMORY_USERPTR) ++ src_frame->fb_addr[i].va = phys_to_virt(src_frame->fb_addr[i].pa); ++ else ++ src_frame->fb_addr[i].va = vb2_plane_vaddr(&src_buf->vb2_buf, i); ++ ++ src_frame->fb_addr[i].size = vb2_get_plane_payload(&src_buf->vb2_buf, i); ++ ++#if 0 ++ printk("---va %x, length %d, bytesused %d\n", vb2_plane_vaddr(src_buf, i), ++ (size_t)src_buf->vb2_buf.planes[i].length, ++ src_buf->vb2_buf.planes[i].bytesused); ++ ++ print_hex_dump(KERN_INFO, "input", DUMP_PREFIX_ADDRESS, 16, 1, src_frame->fb_addr[i].va, 64, 1); ++#endif ++ } ++ ++ dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ dst_buf->vb2_buf.planes[0].bytesused = 0; ++ dst_video_buf = container_of(dst_buf, struct ingenic_video_buf, vb); ++ dst_frame = &dst_video_buf->buf; ++ dst_frame->num_planes = dst_buf->vb2_buf.num_planes; ++ ++ if(ctx->state == INGENIC_STATE_HEADER) { ++ ++ if(ctx->codec_id != CODEC_ID_H264E) { ++ dev_err(ctx->dev->dev, "invalid state!\n"); ++ ctx->state = INGENIC_STATE_ABORT; ++ return; ++ } ++ dst_frame->fb_addr[0].pa = ingenic_vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); ++ if (dst_buf->vb2_buf.memory == VB2_MEMORY_USERPTR) ++ dst_frame->fb_addr[0].va = phys_to_virt(dst_frame->fb_addr[0].pa); ++ else ++ dst_frame->fb_addr[0].va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); ++ ++ h264e_ctx->encoded_bs_len = 0; ++ ret = h264e_encode_headers(h264e_ctx, &dst_frame->fb_addr[0]); ++ if(ret < 0) { ++ ctx->state = INGENIC_STATE_ABORT; ++ return; ++ } ++#if 0 //TODO: ++ if(h264e_ctx->p.h264_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME) { ++ dst_frame->fb_addr[0].va += h264e_ctx->encoded_bs_len; ++ dst_frame->fb_addr[0].pa += h264e_ctx->encoded_bs_len; ++ dst_buf->vb2_buf.planes[0].bytesused = h264e_ctx->encoded_bs_len; ++ } else { ++ ++ dst_buf->vb2_buf.planes[0].bytesused = h264e_ctx->encoded_bs_len; ++ dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; ++ dst_buf->timecode = src_buf->timecode; ++ ++ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); ++ ++ dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); ++ if(!dst_buf) { ++ dev_err(ctx->dev->dev, "Failed to get dst buf!\n"); ++ ctx->state = INGENIC_STATE_ABORT; ++ return; ++ } ++ ++ dst_frame->fb_addr[0].pa = ingenic_vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); ++ if (dst_buf->vb2_buf.memory == VB2_MEMORY_USERPTR) ++ dst_frame->fb_addr[0].va = phys_to_virt(dst_frame->fb_addr[0].pa); ++ else ++ dst_frame->fb_addr[0].va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); ++ ++ dst_buf->vb2_buf.planes[0].bytesused = 0; ++ } ++#endif ++ ++ ctx->state = INGENIC_STATE_RUNNING; ++ } else { ++ for(i = 0; i < dst_buf->vb2_buf.num_planes; i++) { ++ dst_frame->fb_addr[i].pa = ingenic_vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, i); ++ if (dst_buf->vb2_buf.memory == VB2_MEMORY_USERPTR) ++ dst_frame->fb_addr[i].va = phys_to_virt(dst_frame->fb_addr[i].pa); ++ else ++ dst_frame->fb_addr[i].va = vb2_plane_vaddr(&dst_buf->vb2_buf, i); ++ } ++ //bs_buf->size = (size_t)dst_buf->vb2_buf.planes[0].length; ++ } ++ ++ switch(ctx->codec_id) { ++ case CODEC_ID_H264E: ++ h264e_ctx->encoded_bs_len = 0; ++ if(src_buf->flags & V4L2_BUF_FLAG_KEYFRAME) { ++ force_idr = 1; ++ } ++ ++ ret = h264e_encode(h264e_ctx, src_frame, &dst_frame->fb_addr[0], force_idr, &keyframe); ++ ++ if(keyframe) { ++ dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; ++ } else { ++ dst_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; ++ } ++ dst_buf->vb2_buf.planes[0].bytesused += h264e_ctx->encoded_bs_len; /* returned bs size. */ ++ if(dst_buf->vb2_buf.planes[0].bytesused > dst_buf->vb2_buf.planes[0].length) { ++ dev_err(dev->dev, "[dangerous] vpu output bs length too large, system will crash!! encoded_bs_len: %d\n", ++ h264e_ctx->encoded_bs_len); ++ ctx->state = INGENIC_STATE_ABORT; ++ } ++ break; ++ case CODEC_ID_JPGE: ++ ++ ret = jpeg_encoder_encode(jpge_ctx, src_frame, &dst_frame->fb_addr[0]); ++ if(ret < 0) { ++ ctx->state = INGENIC_STATE_ABORT; ++ } ++ ++ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, jpge_ctx->bslen); ++ ++ //dst_buf->vb2_buf.planes[0].bytesused = jpge_ctx->bslen; ++ break; ++ case CODEC_ID_JPGD: ++ /*src bs? dst raw? */ ++ ret = jpeg_decoder_decode(jpgd_ctx, &src_frame->fb_addr[0], dst_frame); ++ if(ret < 0) { ++ ctx->state = INGENIC_STATE_ABORT; ++ } ++ ++ break; ++ default: ++ break; ++ } ++ ++ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); ++ ++ dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; ++ dst_buf->timecode = src_buf->timecode; ++ dst_buf->sequence = src_buf->sequence; ++ ++// printk("dst_buf->timestamp.tv_sec: %ld, dst_buf->timestamp.tv_usec: %ld, sequence: %d, bytesused: %d\n", dst_buf->timestamp.tv_sec, dst_buf->timestamp.tv_usec, dst_buf->sequence, vb2_get_plane_payload(&dst_buf->vb2_buf, 0)); ++ ++ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); ++ ++ v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx); ++} ++ ++static void m2mops_venc_device_run(void * priv) ++{ ++ struct ingenic_venc_ctx *ctx = priv; ++ struct ingenic_venc_dev *dev = ctx->dev; ++ ++ queue_work(dev->encode_workqueue, &ctx->encode_work); ++} ++ ++static int m2mops_venc_job_ready(void *m2m_priv) ++{ ++ struct ingenic_venc_ctx *ctx = m2m_priv; ++ ++ if(ctx->state == INGENIC_STATE_ABORT || ctx->state == INGENIC_STATE_IDLE) { ++ dev_info(ctx->dev->dev, "job not ready, ctx->state %d\n", ctx->state); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static void m2mops_venc_job_abort(void *priv) ++{ ++ struct ingenic_venc_ctx *ctx = priv; ++ ++ ctx->state = INGENIC_STATE_ABORT; ++} ++ ++const struct v4l2_m2m_ops ingenic_venc_m2m_ops = { ++ .device_run = m2mops_venc_device_run, ++ .job_ready = m2mops_venc_job_ready, ++ .job_abort = m2mops_venc_job_abort, ++}; ++ ++ ++ ++int ingenic_vcodec_enc_init_default_params(struct ingenic_venc_ctx *ctx) ++{ ++ ++ int ret = 0; ++ ++ ++ ctx->capture_stopped = 1; ++ ctx->output_stopped = 1; ++ ++ //ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; ++ //ctx->fh.m2m_ctx = ctx->m2m_ctx; ++ ctx->fh.ctrl_handler = &ctx->ctrl_hdl; ++ INIT_WORK(&ctx->encode_work, ingenic_venc_worker); ++ ++ return ret; ++} ++ ++int ingenic_vcodec_enc_deinit_default_params(struct ingenic_venc_ctx *ctx) ++{ ++ ++ struct h264e_ctx *h264e_ctx = &ctx->h264e_ctx; ++ struct jpge_ctx *jpge_ctx = &ctx->jpge_ctx; ++ struct jpgd_ctx *jpgd_ctx = &ctx->jpgd_ctx; ++ ++ switch(ctx->codec_id) { ++ case CODEC_ID_H264E: ++ h264e_encoder_deinit(h264e_ctx); ++ break; ++ case CODEC_ID_JPGE: ++ jpeg_encoder_deinit(jpge_ctx); ++ break; ++ case CODEC_ID_JPGD: ++ jpeg_decoder_deinit(jpgd_ctx); ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++#define INGENIC_MAX_CTRLS_HINT 20 ++int ingenic_vcodec_enc_ctrls_setup(struct ingenic_venc_ctx *ctx) ++{ ++ const struct v4l2_ctrl_ops *ops = &ingenic_venc_ctrl_ops; ++ struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl; ++ ++ v4l2_ctrl_handler_init(handler, INGENIC_MAX_CTRLS_HINT); ++ ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_JPEG_COMPRESSION_QUALITY, ++ 0, 2, 1, 1); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE, ++ 1, 4000000, 1, 4000000); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, ++ 0, 51, 1, 30); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, ++ 0, 51, 1, 30); ++// v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_B_FRAMES, ++// 0, 2, 1, 0); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, ++ 0, 1, 1, 1); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_MAX_QP, ++ 0, 51, 1, 40); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_MIN_QP, ++ 0, 51, 1, 10); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, ++ 0, 65535, 1, 0); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, ++ 0, 65535, 1, 50); ++ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, ++ 0, 1, 1, 0); ++ v4l2_ctrl_new_std_menu(handler, ops, ++ V4L2_CID_MPEG_VIDEO_HEADER_MODE, ++ V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, ++ 0, V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); ++ v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, ++ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, ++ 0, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN); ++ v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, ++ V4L2_MPEG_VIDEO_H264_LEVEL_4_2, ++ 0, V4L2_MPEG_VIDEO_H264_LEVEL_3_0); ++ v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE_MODE, ++ V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, ++ 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); ++ if (handler->error) { ++ dev_err(ctx->dev->dev, "Init control handler fail %d\n", ++ handler->error); ++ return handler->error; ++ } ++ ++ v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); ++ ++ return 0; ++} ++ ++int ingenic_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) ++{ ++ struct ingenic_venc_ctx *ctx = priv; ++ int ret = 0; ++ ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ++ src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; ++ src_vq->drv_priv = ctx; ++ src_vq->buf_struct_size = sizeof(struct ingenic_video_buf); ++ src_vq->ops = &ingenic_venc_vb2_ops; ++ src_vq->mem_ops = &ingenic_vb2_dma_contig_memops; ++ src_vq->lock = &ctx->dev->dev_mutex; ++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ src_vq->dev = ctx->dev->dev; ++ ++ ret = vb2_queue_init(src_vq); ++ if(ret) ++ return ret; ++ ++ ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; ++ dst_vq->drv_priv = ctx; ++ dst_vq->buf_struct_size = sizeof(struct ingenic_video_buf); ++ dst_vq->ops = &ingenic_venc_vb2_ops; ++ dst_vq->mem_ops = &ingenic_vb2_dma_contig_memops; ++ dst_vq->lock = &ctx->dev->dev_mutex; ++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ dst_vq->dev = ctx->dev->dev; ++ ++ return vb2_queue_init(dst_vq); ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_ops.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_ops.h +new file mode 100644 +index 000000000..7eb7d8627 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/helix_ops.h +@@ -0,0 +1,17 @@ ++#ifndef __INGENIC_HELIX_OPS_H__ ++#define __INGENIC_HELIX_OPS_H__ ++ ++ ++extern const struct v4l2_ioctl_ops ingenic_venc_ioctl_ops; ++extern const struct v4l2_m2m_ops ingenic_venc_m2m_ops; ++ ++ ++ ++int ingenic_vcodec_enc_init_default_params(struct ingenic_venc_ctx *ctx); ++int ingenic_vcodec_enc_deinit_default_params(struct ingenic_venc_ctx *ctx); ++ ++int ingenic_vcodec_enc_ctrls_setup(struct ingenic_venc_ctx *ctx); ++int ingenic_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq); ++ ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpgd.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpgd.c +new file mode 100644 +index 000000000..c7d56bd50 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpgd.c +@@ -0,0 +1,569 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* This program is free software; you can redistribute it and/or modify ++* it under the terms of the GNU General Public License version 2 as ++* published by the Free Software Foundation. ++* ++* This program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++*/ ++ ++#include ++#include ++ ++ ++#include "helix_buf.h" ++#include "helix_drv.h" ++#include "jpgd.h" ++ ++static void __maybe_unused dump_slice_info(_JPEGD_SliceInfo *s) ++{ ++ printk("s->des_va: %08x\n", (unsigned int)s->des_va); ++ printk("s->des_pa: %08x\n", s->des_pa); ++ printk("s->bsa: %08x\n", s->bsa); ++ printk("s->p0a: %08x\n", s->p0a); ++ printk("s->p1a: %08x\n", s->p1a); ++ printk("s->nrsm: %d\n", s->nrsm); ++ printk("s->nmcu: %d\n", s->nmcu); ++ printk("s->pxc[0]: %x\n", s->pxc[0]); ++ printk("s->pxc[1]: %x\n", s->pxc[1]); ++ printk("s->pxc[2]: %x\n", s->pxc[2]); ++ printk("s->pxc[3]: %x\n", s->pxc[3]); ++} ++ ++static int jpgd_fill_slice_info(struct jpgd_ctx *ctx) ++{ ++ struct jpgd_params *p = &ctx->p; ++ _JPEGD_SliceInfo *s = ctx->s; ++ int ret = 0; ++ ++ s->des_va = ctx->desc; ++ s->des_pa = ctx->desc_pa; ++ s->bsa = ctx->bs->pa; ++ s->p0a = ctx->frame->fb_addr[0].pa; ++ s->p1a = ctx->frame->fb_addr[1].pa; ++ s->nrsm = 0; ++ s->nmcu = ((p->height + 15) / 16) * ((p->width + 15) / 16) - 1; ++ s->huffmin = p->huffmin; ++ s->huffbase = p->hea; ++ s->huffsymb = p->heb; ++ s->qmem = (int *)p->qt; ++ ++ if(p->format == HELIX_NV12_MODE) { ++ s->width = 1 << 15 | ((p->width + 15) / 16 - 1); ++ } ++ s->pxc[0] = p->pxc[0]; ++ s->pxc[1] = p->pxc[1]; ++ s->pxc[2] = p->pxc[2]; ++ s->pxc[3] = p->pxc[3]; ++ ++ return ret; ++} ++ ++/* decode header info to params ??*/ ++static int jpgd_decode_header(struct jpgd_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ struct ingenic_vcodec_mem *bs = ctx->bs; ++ struct jpgd_params *p = &ctx->p; ++ unsigned char *pbuf = bs->va; ++ int bslen = bs->size; ++ unsigned char *bsend = bs->va + bs->size; ++ ++ int hbase, hb, abase, bbase, dc, ht; ++ int i,j,n,v,c,nrst,nm,code,hid; ++ ++ int ncol; ++ int l[16]; ++ int nblk[4] = {0}; ++ int qt_sel[4] = {0}; ++ int ha_sel[4] = {0}; ++ int hd_sel[4] = {0}; ++ int is_sos = 0; ++ ++ unsigned char *dst_bs = bs->va; ++ unsigned char *dst_bslen = 0; ++ unsigned int min0, min1, min2, min3; ++ ++ nrst = nm = ncol = 0; ++ /* init default table ?*/ ++ for(i = 0; i < 384; i++) { ++ p->huffenc[i] = 0xfff; ++ } ++ for(i = 168, j = 0xfd0; i < 176; i++, j++) { ++ p->huffenc[i] = j; ++ } ++ for(i = 344, j = 0xfd0; i < 352; i++, j++) { ++ p->huffenc[i] = j; ++ } ++ ++ for(i=162;i<174;i++) ++ p->heb[i]=0; ++ ++ for(i=0;i<4;i++) ++ for(j=0;j<64;j++) ++ p->qt[i][j] = 0; ++ ++ while(1) { ++ ++ if(is_sos || pbuf >= bsend) { ++ break; ++ } ++ ++ c = *pbuf++; ++ if(c != 0xff) ++ continue; ++ ++ ++ while((c = *pbuf++) == 0xff); ++ if(c == 0) { ++ /* not a marker */ ++ continue; ++ } ++marker: ++ switch(c) { ++ case 0xc0 : // Baseline (0, 0) ++ case 0xc1 : // Ext. Sequential, Huffman (0, 0) ++ case 0xc2 : // Progressive, Huffman (1, 0) ++ case 0xc3 : // Lossless, Huffman ++ case 0xc5 : // Differential Sequential, Huffman ++ case 0xc6 : // Differential Progressive, Huffman ++ case 0xc7 : // Differential Lossless, Huffman ++ case 0xc9 : // Extended Sequential, Arithmetic (0, 1) ++ case 0xca : // Progressive, Arithmetic (1, 1) ++ case 0xcb : // Lossless, Huffman ++ case 0xcd : // Differential Sequential, Arithmetic ++ case 0xce : // Differential Progressive, Arithmetic ++ case 0xcf : // Differential Lossless, Arithmetic ++ ++ pbuf += 3; ++ p->height = (*pbuf++ << 8) | *pbuf++; ++ p->width = (*pbuf++ << 8) | *pbuf++; ++ ncol = *pbuf++; ++ ++ for(i = 0; i < ncol; i++) { ++ pbuf++; ++ nblk[i] = *pbuf++; ++ qt_sel[i] = *pbuf++; ++ } ++ break; ++ case 0xc4 : ++ /* DHT marker detected */ ++ /* Get the lenght of the marker segment */ ++ // Lh : HT length (16b) ++ n = (*pbuf++ << 8) | *pbuf++; ++ ++ /* reduce 2 ?*/ ++ n -= 2; ++ ++ while(n) { ++ /* Get the type of table */ ++ v= *pbuf++; // Tc & Th ++ // Tc : Table class (4b) ++ // 0 = DC or lossless table ++ // 1 = AC table ++ // Th : HT destination identifier ++ // - specifies 1 of 4 possible destinations at the decoder into ++ // which HT shall be installed. ++ ++ /* Reduce marker segment byte count */ ++ n--; ++ ++ hid = v>>4 ? 2 : 0; ++ hid |= v&15 ? 1 : 0; ++ switch(hid){ ++ case 1: ++ hbase = 368; ++ break; ++ case 2: ++ hbase = 0; ++ break; ++ case 3: ++ hbase = 176; ++ break; ++ default : ++ hbase = 352; ++ break; ++ } ++ if((v>>4)) ++ abase = 0; ++ else ++ abase = 1; ++ ++ dc = abase; ++ ht = v&15; ++ abase |=ht<<1; ++ switch(abase){ ++ case 1 : ++ case 3 : ++ bbase = 162; ++ break; ++ case 2 : ++ bbase = 174; ++ break; ++ default : ++ bbase = 0; ++ break; ++ } ++ abase <<= 4; ++ ++ /* Memory initialization */ ++ for(i = abase; i < abase+16; i++) ++ p->hea[i] = 255; ++ /* Get the number of codes for each length */ ++ // Lj : # of Huffman codes of length i ++ // - specifies the # of Huffman codes for each of 16 possible lengths ++ // allowed by spec. BITS ++ for(i = 0; i < 16; i++) { ++ l[i] = *pbuf++; ++ } ++ /* Reduce marker segment byte count */ ++ n -= 16; ++ code = 0; ++ for(i=0; i<16; i++,abase++) { ++ p->min[abase] = code; ++ p->hea[abase] = bbase - code; ++ if(l[i]) { ++ // Vi,j : associated with each Huffman code ++ // - specifies, for each i the value associated with each Huffman code ++ // of length i. HUFFVAL ++ for(j=0; jhuffenc[hbase+v]= (i<<8) | (code&0xff); ++ v &= 15; ++ if(ht) ++ v <<= 4; ++ p->heb[bbase] |= v; ++ } else{ ++ if(v == 0) ++ hb = 160; ++ else if(v == 0xf0) ++ hb = 161; ++ else ++ hb = (v>>4)*10 + (v&0xf) - 1; ++ p->huffenc[hbase+hb] = (i<<8) | (code&0xff); ++ p->heb[bbase] = v; ++ } ++ code++; ++ } ++ ++ } ++ code <<= 1; ++ } ++ } ++ break; ++ case 0xc8 : ++ break; ++ ++ case 0xcc : ++ break; ++ /* M_RST0 ~ M_RST7, ignore? */ ++ case 0xd0 : ++ case 0xd1 : ++ case 0xd2 : ++ case 0xd3 : ++ case 0xd4 : ++ case 0xd5 : ++ case 0xd6 : ++ case 0xd7 : ++ break; ++ /* M_SOI */ ++ case 0xd8 : ++ break; ++ /* M_EOI */ ++ case 0xd9 : ++ *dst_bs++ = 0xff; ++ dst_bslen++; ++ *dst_bs++ = 0xd9; ++ dst_bslen++; ++ break; ++ /* M_SOS */ ++ case 0xda : ++ pbuf += 2; ++ n= *pbuf++; //Ns (# of image components) ++ ++ for(i=0;i>4; ++ hd_sel[i] = hd_sel[i] & 0x3; ++ } ++ pbuf++; //Ss ++ pbuf++; //Se ++ pbuf++; //Ah&Al ++ /* TODO... */ ++ /* BS left can be decoded by vpu.*/ ++ is_sos = 1; ++ ++ break; ++ case 0xdb : ++ // Lq : QT Length (16b) ++ v = (*pbuf++ << 8) | *pbuf++; ++ int len = v-2; ++ while (len > 0) { ++ int prec; ++ v = *pbuf++; ++ // Pq : QT element precision (4b) ++ // - specifies the precision of the Qk values. ++ // 0 indicates 8-bits Qk values. ++ // 1 indicates 16-bits Qk values ++ prec = v >> 4; ++ // Tq : QT destination identifier (4b) ++ // - specifies one of 4 possible destnations at the decoder into ++ // which the QT shall be installed. ++ n = v&15; ++ if(n > 3){ ++ /*ijpegd_log(h, C_LOG_DEBUG, "error QT\n");*/ ++ } ++ for(i=0;i<64;i++) { ++ // Qk: Quantization table element ++ // k is the index in the zigzag ordering of the DCT coeff ++ // JPC only do 8-bit Qk! (ie, Pq shall be 0) ++ if(prec){ ++ p->qt[n][i] = (*pbuf++ << 8) | *pbuf++; ++ } else { ++ p->qt[n][i] = (*pbuf++); ++ } ++ } ++ len -= 64+1; ++ if(prec) { ++ len -= 64; ++ } ++ } ++ break; ++ case 0xdd : ++ // Lr : restart interval segment length (16b) ++ // - specifies the length of the paramenters in the DRI segment ++ pbuf += 2; ++ // Ri : restart interval (16b) ++ // - specifies the number of MCU in the restart interval. ++ nrst = (*pbuf++ << 8) | *pbuf++; ++ break; ++ case 0xe0 :/* All these markers are ignored */ ++ case 0xe1 : ++ case 0xe2 : ++ case 0xe3 : ++ case 0xe4 : ++ case 0xe5 : ++ case 0xe6 : ++ case 0xe7 : ++ case 0xe8 : ++ case 0xe9 : ++ case 0xea : ++ case 0xeb : ++ case 0xec : ++ case 0xed : ++ case 0xee : ++ case 0xef : ++ case 0xf0 : ++ case 0xf1 : ++ case 0xf2 : ++ case 0xf3 : ++ case 0xf4 : ++ case 0xf5 : ++ case 0xf6 : ++ case 0xf7 : ++ case 0xf8 : ++ case 0xf9 : ++ case 0xfa : ++ case 0xfb : ++ case 0xfc : ++ case 0xfd : ++ case 0xfe : ++ v = (*pbuf++ << 8) | *pbuf++; ++ v-=2; ++ pbuf += v; ++ break; ++ default : ++ break; ++ } ++ ++ } ++ ++ for(i = 0; i < 64;) { ++ v = p->min[i++]&1; ++ v <<= 2; ++ v |= p->min[i++]&3; ++ v <<= 3; ++ v |= p->min[i++]&7; ++ min3 = (v>>2) & 0xF; ++ //ijpegd_log(h, C_LOG_DEBUG, fpo,"%x",v>>2); ++ v <<= 4; ++ v |= p->min[i++]&15; ++ v <<= 5; ++ v |= p->min[i++]&31; ++ v <<= 6; ++ v |= p->min[i++]&63; ++ v <<=7; ++ v |= p->min[i++]&127; ++ v <<=8; ++ v |=p->min[i++]&255; ++ min2 = v & 0xFFFFFFFF; ++ //ijpegd_log(h, C_LOG_DEBUG, fpo,"%08x",v); ++ v = p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ //ijpegd_log(h, C_LOG_DEBUG, fpo,"%08x",v); ++ min1 = v & 0xFFFFFFFF; ++ v = p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ v <<= 8; ++ v |= p->min[i++]&255; ++ min0 = v & 0xFFFFFFFF; ++ ++ ++ p->huffmin[i / 4 - 4] = min0; ++ p->huffmin[i / 4 - 3] = min1; ++ p->huffmin[i / 4 - 2] = min2; ++ p->huffmin[i / 4 - 1] = min3; ++ } ++ ++ /* huffbase */ ++ for(i = 0; i < 64; i++) {// hea ++ p->hea[i] = p->hea[i] & 0x1FF; ++ } ++ /* huffsymb */ ++ for(i = 0; i < 336; i++) { ++ p->heb[i] = p->heb[i] & 0xFF; ++ } ++ ++ for(i = 0; i < 4; i++) { ++ p->pxc[i] = (nblk[i] & 0x3) * ((nblk[i] & 0x30) >> 4) - 1; ++ p->pxc[i] = (p->pxc[i] & 0xf) << 4; ++ p->pxc[i] |= qt_sel[i] << 2 | ++ ((ha_sel[i] & 0x1) << 1) | ++ ((hd_sel[i] & 0x1) << 0); ++ } ++ ++ ctx->header_size = pbuf - (unsigned char *)bs->va; ++ ++ memcpy(bs->va, pbuf, bslen - ctx->header_size); ++ dma_sync_single_for_device(venc_ctx->dev->dev, bs->pa, bslen - ctx->header_size, DMA_TO_DEVICE); ++ ++ return 0; ++} ++ ++int jpeg_decoder_decode(struct jpgd_ctx *ctx, struct ingenic_vcodec_mem *bs, struct video_frame_buffer *frame) ++{ ++ int ret = 0; ++ ++ ctx->frame = frame; ++ ctx->bs = bs; ++ ++ ret = jpgd_decode_header(ctx); ++ ++ jpgd_fill_slice_info(ctx); ++ //dump_slice_info(ctx->s); ++ ++ JPEGD_SliceInit(ctx->s); ++ ++ ret = ingenic_vpu_start(ctx->priv); ++ if(ret < 0) { ++ return ret; ++ } ++ ++ return ret; ++} ++ ++ ++int jpeg_decoder_set_fmt(struct jpgd_ctx *ctx, int width, int height, int format) ++{ ++ struct jpgd_params *p = &ctx->p; ++ int ret = 0; ++ ++ switch(format) { ++ case HELIX_NV12_MODE: ++ case HELIX_TILE_MODE: ++ p->format = format; ++ break; ++ default: ++ pr_err("Unsupported pix fmt: %x\n", format); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++ ++int jpeg_decoder_alloc_workbuf(struct jpgd_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ struct jpgd_params *p = &ctx->p; ++ int ret = 0; ++ ++ ctx->desc = dma_alloc_coherent(venc_ctx->dev->dev, ctx->vdma_chain_len, &ctx->desc_pa, GFP_KERNEL); ++ if(!ctx->desc) { ++ pr_err("Failed to alloc desc memory!\n"); ++ ret = -ENOMEM; ++ goto err_desc; ++ } ++ ++ ++ return ret; ++err_desc: ++ return ret; ++} ++int jpeg_decoder_free_workbuf(struct jpgd_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ dma_free_coherent(venc_ctx->dev->dev, ctx->vdma_chain_len, ctx->desc, ctx->desc_pa); ++ ++ return 0; ++} ++ ++ ++int jpeg_decoder_init(struct jpgd_ctx *ctx) ++{ ++ struct jpgd_params *p = NULL; ++ _JPEGD_SliceInfo *s = NULL; ++ ++ ++ s = kzalloc(sizeof(_JPEGD_SliceInfo), GFP_KERNEL); ++ if(!s) { ++ return -ENOMEM; ++ } ++ ++ p = &ctx->p; ++ ctx->s = s; ++ ctx->vdma_chain_len = 40960 + 256; ++ ++ return 0; ++} ++ ++ ++int jpeg_decoder_deinit(struct jpgd_ctx *ctx) ++{ ++ if(!ctx) ++ return 0; ++ ++ if(ctx->s) { ++ kfree(ctx->s); ++ } ++ ++ ++ return 0; ++} ++ ++void jpeg_decoder_set_priv(struct jpgd_ctx *ctx, void *data) ++{ ++ ctx->priv = data; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpgd.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpgd.h +new file mode 100644 +index 000000000..143fb9ea5 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpgd.h +@@ -0,0 +1,54 @@ ++#ifndef __JPGD_H__ ++#define __JPGD_H__ ++ ++ ++#include "api/helix_jpeg_dec.h" ++ ++struct jpgd_params { ++ int hea[64]; ++ int heb[336]; ++ int huffmin[64]; ++ int qt[4][64]; ++ ++ int huffenc[384]; ++ int min[64]; ++ unsigned int pxc[4]; /* component x config */ ++ ++ int width; ++ int height; ++ int format; /*input format?*/ ++}; ++ ++struct jpgd_ctx { ++ int vdma_chain_len; ++ ++ unsigned int *desc; ++ dma_addr_t desc_pa; ++ ++ struct video_frame_buffer *frame; /* raw frame.*/ ++ struct ingenic_vcodec_mem *bs; /* output bs.*/ ++ ++ unsigned int header_size; /*jpg header*/ ++ unsigned int bslen; /*decoder output bslen*/ ++ ++ struct jpgd_params p; ++ _JPEGD_SliceInfo *s; ++ void *priv; ++}; ++ ++ ++extern int jpeg_decoder_decode(struct jpgd_ctx *ctx, struct ingenic_vcodec_mem *bs, struct video_frame_buffer *frame); ++ ++extern int jpeg_decoder_set_fmt(struct jpgd_ctx *ctx, int width, int height, int format); ++ ++extern int jpeg_decoder_alloc_workbuf(struct jpgd_ctx *ctx); ++ ++extern int jpeg_decoder_free_workbuf(struct jpgd_ctx *ctx); ++ ++extern int jpeg_decoder_init(struct jpgd_ctx *ctx); ++ ++extern int jpeg_decoder_deinit(struct jpgd_ctx *ctx); ++ ++extern void jpeg_decoder_set_priv(struct jpgd_ctx *ctx, void *data); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge.c b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge.c +new file mode 100644 +index 000000000..b23fd46e6 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge.c +@@ -0,0 +1,330 @@ ++/* ++* Copyright© 2014 Ingenic Semiconductor Co.,Ltd ++* ++* Author: qipengzhen ++* ++* This program is free software; you can redistribute it and/or modify ++* it under the terms of the GNU General Public License version 2 as ++* published by the Free Software Foundation. ++* ++* This program is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++* GNU General Public License for more details. ++* ++*/ ++ ++ ++#include ++#include ++ ++ ++#include "helix_buf.h" ++#include "helix_drv.h" ++ ++#include "jpge.h" ++ ++#include "jpge/ht.h" ++#include "jpge/qt.h" ++#include "jpge/head.h" ++ ++static void __maybe_unused dump_slice_info(_JPEGE_SliceInfo *s) ++{ ++ printk("s->des_va: %08x\n", (unsigned int)s->des_va); ++ printk("s->des_pa: %08x\n", s->des_pa); ++ printk("s->ncol: %d\n", s->ncol); ++ printk("s->rsm: %d\n", s->rsm); ++ printk("s->bsa: %08x\n", s->bsa); ++ printk("s->p0a: %08x\n", s->p0a); ++ printk("s->p1a: %08x\n", s->p1a); ++ printk("s->nrsm: %d\n", s->nrsm); ++ printk("s->raw[0]: %08x\n", s->raw[0]); ++ printk("s->raw[1]: %08x\n", s->raw[1]); ++ printk("s->raw[2]: %08x\n", s->raw[2]); ++ printk("s->stride[0]: %d\n", s->stride[0]); ++ printk("s->stride[1]: %d\n", s->stride[1]); ++ printk("s->mb_height: %d\n", s->mb_height); ++ printk("s->mb_width: %d\n", s->mb_width); ++ printk("s->nmcu: %d\n", s->nmcu); ++ printk("s->raw_format: %d(%s)\n", s->raw_format, ++ s->raw_format == 8 ? "NV12" : ++ s->raw_format == 12 ? "NV21" : ++ s->raw_format == 0 ? "TILE(unsupported)" : "invalid"); ++ printk("s->ql_sel: %d(%s)\n", s->ql_sel, ++ s->ql_sel == LOW_QUALITY ? "low_quality": ++ s->ql_sel == MEDIUMS_QUALITY ? "mediums_quality": ++ s->ql_sel == HIGH_QUALITY ? "high_quality" : "invld"); ++ printk("s->huffenc_sel: %d\n", s->huffenc_sel); ++} ++ ++static int jpge_fill_slice_info(struct jpge_ctx *ctx) ++{ ++ struct jpge_params *p = &ctx->p; ++ _JPEGE_SliceInfo *s = ctx->s; ++ int ret = 0; ++ ++ s->des_va = ctx->desc; ++ s->des_pa = ctx->desc_pa; ++ ++ s->ncol = 2; /* unused? */ ++ s->rsm = 0; ++ s->bsa = ctx->bs->pa + ctx->header_size; ++ s->p0a = 0; ++ s->p1a = 0; ++ s->nrsm = 0; ++ ++ s->raw[0] = ctx->frame->fb_addr[0].pa; /*Y*/ ++ s->raw[1] = ctx->frame->fb_addr[1].pa; /*U for 420p or UV for nv12*/ ++ s->raw[2] = ctx->frame->fb_addr[2].pa; /*V for 420p*/ ++ ++ s->stride[0] = s->stride[1] = p->width; ++ ++ s->mb_height = (p->height + 15) / 16; ++ s->mb_width = p->width / 16; ++ s->nmcu = s->mb_height * s->mb_width - 1; ++ s->raw_format = p->format; ++ s->ql_sel = p->compr_quality; ++ s->huffenc_sel = 0; /*only one huffenc table?*/ ++ ++ return ret; ++} ++ ++static int jpge_gen_header(struct jpge_ctx *ctx) ++{ ++ struct ingenic_vcodec_mem *bs = ctx->bs; ++ struct jpge_params *p = &ctx->p; ++ int ql_sel = p->compr_quality; ++ char *pbuf = bs->va; ++ char *ptr = NULL; ++ int i,j; ++ int header_size; ++ int padsize; ++ ++ /* SOI 文件开始 */ ++ *pbuf++ = 0xff; ++ *pbuf++ = M_SOI; ++ ++ /* DQT -- 0 */ ++ *pbuf++ = 0xff; ++ *pbuf++ = M_DQT; ++ *pbuf++ = 0x0; ++ *pbuf++ = 0x43; ++ *pbuf++ = 0x0; ++ ++ ptr = (char *)&qt[ql_sel][0]; ++ for(i = 0; i < 64; i++) ++ *pbuf++ = *ptr++; ++ ++ /* DQT -- 1*/ ++ *pbuf++ = 0xff; ++ *pbuf++ = M_DQT; ++ *pbuf++ = 0; ++ *pbuf++ = 0x43; ++ *pbuf++ = 0x01; ++ for(i = 0; i < 64; i++) { ++ *pbuf++ = *ptr++; ++ } ++ ++ /* SOF */ ++ *pbuf++ = 0xff; ++ *pbuf++ = M_SOF0; ++ *pbuf++ = 0x0; ++ *pbuf++ = 0x11; //Lf = 17 ++ *pbuf++ = 8; //8bit sample ++ *pbuf++ = (p->height & 0xff00) >> 8; //Y=height ++ *pbuf++ = p->height & 0xff; ++ *pbuf++ = (p->width & 0xff00) >> 8; //X=width ++ *pbuf++ = p->width & 0xff; ++ *pbuf++ = 3; //Nf=3, number of component, Y U V ++ *pbuf++ = 1; //采样系数, Component Y 设置. ++ *pbuf++ = 0x22; //Hori:2 Vertical:2 水平采样系数和垂直采样系数. ++ *pbuf++ = 0x00; //使用é‡åŒ–表0. ++ *pbuf++ = 2; //Component Cb. ++ *pbuf++ = 0x11; //H:1 V:1 ++ *pbuf++ = 0x1; //使用é‡åŒ–表1. ++ *pbuf++ = 3; //Component Cr. ++ *pbuf++ = 0x11; //H:1 V:1 ++ *pbuf++ = 0x1; //使用é‡åŒ–表1. ++ ++ /* DHT -- lumia DC/AC, Chromia DC/AC */ ++ for(j = 0; j < 4; j++) { ++ *pbuf++ = 0xff; ++ *pbuf++ = M_DHT; ++ *pbuf++ = (ht_size[j] & 0xff00) >> 8; //ht_size ++ *pbuf++ = ht_size[j] & 0xff; ++ *pbuf++ = dht_sel[j]; //dht_sel; ? ++ for(i = 0; i < 16; i++) { ++ *pbuf++ = ht_len[j][i]; ++ } ++ ++ for(i = 0; i < 16; i++) { ++ int m; ++ for(m = 0; m < ht_len[j][i]; m++) { ++ *pbuf++ = ht_val[j][i][m]; ++ } ++ } ++ } ++ ++ ++ /*添加0xff,å¡«å……header到256字节对é½. 已知SOS 段14字节*/ ++ header_size = pbuf - (char *)bs->va + 14; ++ padsize = 256 - header_size % 256; ++ ++ memset(pbuf, 0xff, padsize); ++ pbuf += padsize; ++ ++ //header_size = (header_size + 255) / 256 * 256; // align to 256; ++ ++ /* SOS */ ++ *pbuf++ = 0xff; ++ *pbuf++ = M_SOS; ++ //Ls = 12 ++ *pbuf++ = 0x0; ++ *pbuf++ = 0xC; ++ //Ns ++ *pbuf++ = 0x3; ++ //Cs1 - Y ++ *pbuf++ = 0x1; ++ //Td, Ta ++ *pbuf++ = 0x00; ++ //Cs2 - U ++ *pbuf++ = 0x2; ++ //Td, Ta ++ *pbuf++ = 0x11; ++ //Cs3 - V ++ *pbuf++ = 0x3; ++ //Td, Ta ++ *pbuf++ = 0x11; ++ //Ss ++ *pbuf++ = 0x00; ++ //Se ++ *pbuf++ = 0x3f; ++ //Ah, Al ++ *pbuf++ = 0x0; ++ ++ ctx->header_size = pbuf - (char *)bs->va; ++ return 0; ++} ++ ++int jpeg_encoder_encode(struct jpge_ctx *ctx, struct video_frame_buffer *frame, struct ingenic_vcodec_mem *bs) ++{ ++ int ret = 0; ++ char *pbuf = NULL; ++ ++ ctx->frame = frame; ++ bs->va = (unsigned long)bs->va | 0xa0000000; //使用uncache地å€ç”Ÿæˆå¤´ä¿¡æ¯.影哿•ˆçއ. ++ ctx->bs = bs; ++ ++ ret = jpge_gen_header(ctx); ++ ++ jpge_fill_slice_info(ctx); ++ //dump_slice_info(ctx->s); ++ ++ JPEGE_SliceInit(ctx->s); ++ ++ ret = ingenic_vpu_start(ctx->priv); ++ if(ret < 0) { ++ return ret; ++ } ++ ++ /* Modify bslen. ++ total bslen = header_size + vpu encoded bslen. ++ */ ++ ctx->bslen = ctx->header_size + ctx->bslen; ++ ++ pbuf = bs->va + ctx->bslen; ++ /* EOI */ ++ *pbuf++ = 0xff; ++ *pbuf++ = 0xd9; ++ ++ ctx->bslen += 2; ++ ++ return ret; ++} ++ ++ ++int jpeg_encoder_set_fmt(struct jpge_ctx *ctx, int width, int height, int format) ++{ ++ struct jpge_params *p = &ctx->p; ++ int ret = 0; ++ ++ p->width = width; ++ p->height = height; ++ ++ switch(format) { ++ case HELIX_NV12_MODE: ++ case HELIX_NV21_MODE: ++ p->format = format; ++ break; ++ default: ++ pr_err("Unsupported pix fmt: %x\n", format); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++ ++int jpeg_encoder_alloc_workbuf(struct jpge_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ int ret = 0; ++ ++ ctx->desc = dma_alloc_coherent(venc_ctx->dev->dev, ctx->vdma_chain_len, &ctx->desc_pa, GFP_KERNEL); ++ if(!ctx->desc) { ++ pr_err("Failed to alloc desc memory!\n"); ++ ret = -ENOMEM; ++ goto err_desc; ++ } ++ ++ ++ return ret; ++err_desc: ++ return ret; ++} ++ ++int jpeg_encoder_free_workbuf(struct jpge_ctx *ctx) ++{ ++ struct ingenic_venc_ctx *venc_ctx = ctx->priv; ++ dma_free_coherent(venc_ctx->dev->dev, ctx->vdma_chain_len, ctx->desc, ctx->desc_pa); ++ ++ return 0; ++} ++ ++ ++int jpeg_encoder_init(struct jpge_ctx *ctx) ++{ ++ struct jpge_params *p = NULL; ++ _JPEGE_SliceInfo *s = NULL; ++ ++ s = kzalloc(sizeof(_JPEGE_SliceInfo), GFP_KERNEL); ++ if(!s) { ++ return -ENOMEM; ++ } ++ ++ p = &ctx->p; ++ ctx->s = s; ++ ctx->vdma_chain_len = 40960 + 256; ++ ++ return 0; ++} ++ ++ ++int jpeg_encoder_deinit(struct jpge_ctx *ctx) ++{ ++ if(!ctx) ++ return 0; ++ ++ if(ctx->s) { ++ kfree(ctx->s); ++ } ++ ++ ++ return 0; ++} ++ ++void jpeg_encoder_set_priv(struct jpge_ctx *ctx, void *data) ++{ ++ ctx->priv = data; ++} +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge.h +new file mode 100644 +index 000000000..d8d1a4f65 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge.h +@@ -0,0 +1,46 @@ ++#ifndef __JPGE_H__ ++#define __JPGE_H__ ++ ++#include "api/helix_jpeg_enc.h" ++ ++struct jpge_params { ++ int compr_quality; ++ ++ int width; ++ int height; ++ int format; /*input format?*/ ++}; ++ ++struct jpge_ctx { ++ int vdma_chain_len; ++ ++ unsigned int *desc; ++ dma_addr_t desc_pa; ++ ++ struct video_frame_buffer *frame; /* raw frame.*/ ++ struct ingenic_vcodec_mem *bs; /* output bs.*/ ++ ++ unsigned int header_size; /*jpg header*/ ++ unsigned int bslen; /*encoder output bslen*/ ++ ++ struct jpge_params p; ++ _JPEGE_SliceInfo *s; ++ void *priv; ++}; ++ ++ ++extern int jpeg_encoder_encode(struct jpge_ctx *ctx, struct video_frame_buffer *frame, struct ingenic_vcodec_mem *bs); ++ ++extern int jpeg_encoder_set_fmt(struct jpge_ctx *ctx, int width, int height, int format); ++ ++extern int jpeg_encoder_alloc_workbuf(struct jpge_ctx *ctx); ++ ++extern int jpeg_encoder_free_workbuf(struct jpge_ctx *ctx); ++ ++extern int jpeg_encoder_init(struct jpge_ctx *ctx); ++ ++extern int jpeg_encoder_deinit(struct jpge_ctx *ctx); ++ ++extern void jpeg_encoder_set_priv(struct jpge_ctx *ctx, void *data); ++ ++#endif +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/head.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/head.h +new file mode 100644 +index 000000000..17d1188b9 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/head.h +@@ -0,0 +1,72 @@ ++#ifndef __HEAD_H__ ++#define __HEAD_H__ ++ ++char dht_sel[] = {0x00, 0x10, 0x01, 0x11}; ++ ++typedef enum { /* JPEG marker codes */ ++ M_SOF0 = 0xc0, ++ M_SOF1 = 0xc1, ++ M_SOF2 = 0xc2, ++ M_SOF3 = 0xc3, ++ ++ M_SOF5 = 0xc5, ++ M_SOF6 = 0xc6, ++ M_SOF7 = 0xc7, ++ ++ M_JPG = 0xc8, ++ M_SOF9 = 0xc9, ++ M_SOF10 = 0xca, ++ M_SOF11 = 0xcb, ++ ++ M_SOF13 = 0xcd, ++ M_SOF14 = 0xce, ++ M_SOF15 = 0xcf, ++ ++ M_DHT = 0xc4, ++ ++ M_DAC = 0xcc, ++ ++ M_RST0 = 0xd0, ++ M_RST1 = 0xd1, ++ M_RST2 = 0xd2, ++ M_RST3 = 0xd3, ++ M_RST4 = 0xd4, ++ M_RST5 = 0xd5, ++ M_RST6 = 0xd6, ++ M_RST7 = 0xd7, ++ ++ M_SOI = 0xd8, ++ M_EOI = 0xd9, ++ M_SOS = 0xda, ++ M_DQT = 0xdb, ++ M_DNL = 0xdc, ++ M_DRI = 0xdd, ++ M_DHP = 0xde, ++ M_EXP = 0xdf, ++ ++ M_APP0 = 0xe0, ++ M_APP1 = 0xe1, ++ M_APP2 = 0xe2, ++ M_APP3 = 0xe3, ++ M_APP4 = 0xe4, ++ M_APP5 = 0xe5, ++ M_APP6 = 0xe6, ++ M_APP7 = 0xe7, ++ M_APP8 = 0xe8, ++ M_APP9 = 0xe9, ++ M_APP10 = 0xea, ++ M_APP11 = 0xeb, ++ M_APP12 = 0xec, ++ M_APP13 = 0xed, ++ M_APP14 = 0xee, ++ M_APP15 = 0xef, ++ ++ M_JPG0 = 0xf0, ++ M_JPG13 = 0xfd, ++ M_COM = 0xfe, ++ ++ M_TEM = 0x01, ++ ++ M_ERROR = 0x100 ++} JPEG_MARKER; ++#endif /* __HEAD_H__ */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/ht.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/ht.h +new file mode 100644 +index 000000000..addf25528 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/ht.h +@@ -0,0 +1,90 @@ ++#ifndef __HT_H__ ++#define __HT_H__ ++unsigned int ht_size[4] = {31, 181, 31, 181, }; ++ ++unsigned char ht_len[4][16] = { ++ {0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, }, ++ {0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125, }, ++ {0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, }, ++ {0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119, }, ++}; ++ ++unsigned char ht_val[4][16][256] = { ++ { {0}, ++ {0x00, }, ++ {0x01, 0x02, 0x03, 0x04, 0x05, }, ++ {0x06, }, ++ {0x07, }, ++ {0x08, }, ++ {0x09, }, ++ {0x0a, }, ++ {0x0b, }, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ }, ++ { {0}, ++ {0x01, 0x02, }, ++ {0x03, }, ++ {0x00, 0x04, 0x11, }, ++ {0x05, 0x12, 0x21, }, ++ {0x31, 0x41, }, ++ {0x06, 0x13, 0x51, 0x61, }, ++ {0x07, 0x22, 0x71, }, ++ {0x14, 0x32, 0x81, 0x91, 0xa1, }, ++ {0x08, 0x23, 0x42, 0xb1, 0xc1, }, ++ {0x15, 0x52, 0xd1, 0xf0, }, ++ {0x24, 0x33, 0x62, 0x72, }, ++ {0}, ++ {0}, ++ {0x82, }, ++ {0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, ++ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, ++ 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, ++ 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, }, ++ }, ++ { {0}, ++ {0x00, 0x01, 0x02, }, ++ {0x03, }, ++ {0x04, }, ++ {0x05, }, ++ {0x06, }, ++ {0x07, }, ++ {0x08, }, ++ {0x09, }, ++ {0x0a, }, ++ {0x0b, }, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ {0}, ++ }, ++ { {0}, ++ {0x00, 0x01, }, ++ {0x02, }, ++ {0x03, 0x11, }, ++ {0x04, 0x05, 0x21, 0x31, }, ++ {0x06, 0x12, 0x41, 0x51, }, ++ {0x07, 0x61, 0x71, }, ++ {0x13, 0x22, 0x32, 0x81, }, ++ {0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, }, ++ {0x09, 0x23, 0x33, 0x52, 0xf0, }, ++ {0x15, 0x62, 0x72, 0xd1, }, ++ {0x0a, 0x16, 0x24, 0x34, }, ++ {0}, ++ {0xe1, }, ++ {0x25, 0xf1, }, ++ {0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, ++ 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, ++ 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, ++ 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, ++ 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, }, ++ }, ++}; ++#endif /* __HT_H__ */ +diff --git a/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/qt.h b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/qt.h +new file mode 100644 +index 000000000..255abcd97 +--- /dev/null ++++ b/module_drivers/drivers/media/platform/ingenic-vcodec/helix/jpge/qt.h +@@ -0,0 +1,58 @@ ++unsigned char qt[3][128] = { ++ { ++ 0x08,0x06,0x06,0x07,0x06,0x05,0x08,0x07, ++ 0x07,0x07,0x09,0x09,0x08,0x0a,0x0c,0x14, ++ 0x0d,0x0c,0x0b,0x0b,0x0c,0x19,0x12,0x13, ++ 0x0f,0x14,0x1d,0x1a,0x1f,0x1e,0x1d,0x1a, ++ 0x1c,0x1c,0x20,0x24,0x2e,0x27,0x20,0x22, ++ 0x2c,0x23,0x1c,0x1c,0x28,0x37,0x29,0x2c, ++ 0x30,0x31,0x34,0x34,0x34,0x1f,0x27,0x39, ++ 0x3d,0x38,0x32,0x3c,0x2e,0x33,0x34,0x32, ++ 0x09,0x09,0x09,0x0c,0x0b,0x0c,0x18,0x0d, ++ 0x0d,0x18,0x32,0x21,0x1c,0x21,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, ++ }, ++ ++ { ++ 0x06, 0x04, 0x04, 0x05, 0x04, 0x04, 0x06, 0x05, ++ 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x08, 0x0d, ++ 0x09, 0x08, 0x07, 0x07, 0x08, 0x0f, 0x0b, 0x0c, ++ 0x09, 0x0d, 0x12, 0x10, 0x13, 0x13, 0x12, 0x10, ++ 0x12, 0x11, 0x14, 0x16, 0x1c, 0x18, 0x14, 0x15, ++ 0x1b, 0x15, 0x11, 0x12, 0x19, 0x21, 0x19, 0x1b, ++ 0x1d, 0x1e, 0x20, 0x20, 0x20, 0x13, 0x18, 0x23, ++ 0x25, 0x22, 0x1f, 0x25, 0x1c, 0x1f, 0x20, 0x1e, ++ 0x06, 0x06, 0x06, 0x08, 0x07, 0x08, 0x0f, 0x09, ++ 0x09, 0x0f, 0x1e, 0x15, 0x12, 0x15, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, ++ }, ++ ++ { ++ 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, ++ 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x05, ++ 0x04, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x05, ++ 0x04, 0x05, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, ++ 0x07, 0x06, 0x07, 0x08, 0x0a, 0x09, 0x07, 0x08, ++ 0x0a, 0x08, 0x06, 0x07, 0x09, 0x0c, 0x09, 0x0a, ++ 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x07, 0x09, 0x0c, ++ 0x0d, 0x0c, 0x0b, 0x0d, 0x0a, 0x0b, 0x0b, 0x0b, ++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, ++ 0x04, 0x06, 0x0b, 0x08, 0x07, 0x08, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, ++ } ++}; +diff --git a/module_drivers/drivers/media/v4l2-core/Kconfig b/module_drivers/drivers/media/v4l2-core/Kconfig +new file mode 100644 +index 000000000..43af1cb6a +--- /dev/null ++++ b/module_drivers/drivers/media/v4l2-core/Kconfig +@@ -0,0 +1,12 @@ ++config VIDEOBUF2_DMA_CONTIG_INGENIC ++ tristate ++ depends on HAS_DMA ++ select VIDEOBUF2_CORE ++ select VIDEOBUF2_MEMOPS ++ select DMA_SHARED_BUFFER ++ ++ ++config CAMERA_RESERVE_KB_SIZE ++ int "Reserve memory for camera noncoherent memory. Unit:KByte" ++ default 0 ++ depends on VIDEOBUF2_DMA_CONTIG_INGENIC +diff --git a/module_drivers/drivers/media/v4l2-core/Makefile b/module_drivers/drivers/media/v4l2-core/Makefile +new file mode 100644 +index 000000000..ab7b95dd2 +--- /dev/null ++++ b/module_drivers/drivers/media/v4l2-core/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG_INGENIC) += videobuf2-dma-contig-ingenic.o +diff --git a/module_drivers/drivers/media/v4l2-core/videobuf2-dma-contig-ingenic.c b/module_drivers/drivers/media/v4l2-core/videobuf2-dma-contig-ingenic.c +new file mode 100644 +index 000000000..b2674e58c +--- /dev/null ++++ b/module_drivers/drivers/media/v4l2-core/videobuf2-dma-contig-ingenic.c +@@ -0,0 +1,893 @@ ++/* ++ * videobuf2-dma-contig.c - DMA contig memory allocator for videobuf2 ++ * ++ * Copyright (C) 2010 Samsung Electronics ++ * ++ * Author: Pawel Osciak ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++struct reserve_memmg{ ++ struct list_head list; ++ long start; ++ long size; ++ ++}; ++struct vb2_dc_conf { ++ struct device *dev; ++ void *reserve_addr; ++ dma_addr_t reserve_phy_addr; ++ unsigned long reserve_size; ++ struct list_head top; ++}; ++ ++struct vb2_dc_buf { ++ struct device *dev; ++ void *vaddr; ++ unsigned long size; ++ dma_addr_t dma_addr; ++ enum dma_data_direction dma_dir; ++ struct sg_table *dma_sgt; ++ struct frame_vector *vec; ++ ++ /* MMAP related */ ++ struct vb2_vmarea_handler handler; ++ atomic_t refcount; ++ struct sg_table *sgt_base; ++ ++ /* DMABUF related */ ++ struct dma_buf_attachment *db_attach; ++ struct reserve_memmg *rsvmem; ++}; ++ ++/*********************************************/ ++/* scatterlist table functions */ ++/*********************************************/ ++ ++ ++static void vb2_dc_sgt_foreach_page(struct sg_table *sgt, ++ void (*cb)(struct page *pg)) ++{ ++ struct scatterlist *s; ++ unsigned int i; ++ ++ for_each_sg(sgt->sgl, s, sgt->orig_nents, i) { ++ struct page *page = sg_page(s); ++ unsigned int n_pages = PAGE_ALIGN(s->offset + s->length) ++ >> PAGE_SHIFT; ++ unsigned int j; ++ ++ for (j = 0; j < n_pages; ++j, ++page) ++ cb(page); ++ } ++} ++ ++static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt) ++{ ++ struct scatterlist *s; ++ dma_addr_t expected = sg_dma_address(sgt->sgl); ++ unsigned int i; ++ unsigned long size = 0; ++ ++ for_each_sg(sgt->sgl, s, sgt->nents, i) { ++ if (sg_dma_address(s) != expected) ++ break; ++ expected = sg_dma_address(s) + sg_dma_len(s); ++ size += sg_dma_len(s); ++ } ++ return size; ++} ++ ++/*********************************************/ ++/* callbacks for all buffers */ ++/*********************************************/ ++ ++static void *vb2_dc_cookie(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ ++ return &buf->dma_addr; ++} ++ ++static void *vb2_dc_vaddr(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ ++ if (!buf->vaddr && buf->db_attach) ++ buf->vaddr = dma_buf_vmap(buf->db_attach->dmabuf); ++ ++ return buf->vaddr; ++} ++ ++static unsigned int vb2_dc_num_users(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ ++ return atomic_read(&buf->refcount); ++} ++ ++static void vb2_dc_prepare(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ struct sg_table *sgt = buf->dma_sgt; ++ ++ /* DMABUF exporter will flush the cache for us */ ++ //if (!sgt || buf->db_attach) ++ if (buf->db_attach) ++ return; ++ if(!sgt) ++ { ++// dma_sync_single_for_device(buf->dev,(unsigned long)buf->vaddr,buf->size,buf->dma_dir); ++ dma_sync_single_for_device(buf->dev,(unsigned long)buf->dma_addr,buf->size,buf->dma_dir); ++ }else { ++ dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); ++ } ++} ++ ++static void vb2_dc_finish(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ struct sg_table *sgt = buf->dma_sgt; ++ ++ /* DMABUF exporter will flush the cache for us */ ++ //if (!sgt || buf->db_attach) ++ if(buf->db_attach) ++ return; ++ if(!sgt) ++ dma_sync_single_for_device(buf->dev,(unsigned long)buf->dma_addr,buf->size,buf->dma_dir); ++ else ++ dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); ++} ++ ++/*********************************************/ ++/* callbacks for MMAP buffers */ ++/*********************************************/ ++static void vb2_dc_put(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ if (!atomic_dec_and_test(&buf->refcount)) ++ return; ++ ++ if (buf->sgt_base) { ++ sg_free_table(buf->sgt_base); ++ kfree(buf->sgt_base); ++ } ++ ++ if(buf->rsvmem) ++ { ++ list_del(&buf->rsvmem->list); ++ vfree(buf->rsvmem); ++ }else ++ dma_free_noncoherent(buf->dev, buf->size, buf->vaddr, buf->dma_addr, DMA_BIDIRECTIONAL); ++ ++ ++ ++ put_device(buf->dev); ++ kfree(buf); ++} ++ ++static struct reserve_memmg* reserve_mem_alloc(struct vb2_dc_conf *conf,int size) ++{ ++ struct reserve_memmg *pos,*next,*alloc_list = NULL; ++ ++ list_for_each_entry(pos,&conf->top,list){ ++ if(!list_is_last(&pos->list,&conf->top)) ++ { ++ next = list_entry(pos->list.next,struct reserve_memmg,list); ++ //printk("-->pos: %ld next: %ld\n",pos->start,next->start); ++ if(next->start - (pos->start + pos->size) >= size){ ++ alloc_list = vzalloc(sizeof(struct reserve_memmg)); ++ alloc_list->start = pos->start + pos->size; ++ alloc_list->size = size; ++ list_add(&alloc_list->list,&pos->list); ++ printk("->alloc: %ld\n",alloc_list->start); ++ return alloc_list; ++ } ++ }else break; ++ } ++ if(list_empty(&conf->top)) ++ { ++ if(conf->reserve_size < size){ ++ return 0; ++ } ++ alloc_list = vzalloc(sizeof(struct reserve_memmg)); ++ alloc_list->start = 0; ++ alloc_list->size = size; ++ list_add(&alloc_list->list,&conf->top); ++ printk("first alloc: %ld\n",alloc_list->start); ++ }else{ ++ if(conf->reserve_size - (pos->start + pos->size) < size) ++ return 0; ++ alloc_list = vzalloc(sizeof(struct reserve_memmg)); ++ ++ alloc_list->start = pos->start + pos->size; ++ alloc_list->size = size; ++ list_add_tail(&alloc_list->list,&conf->top); ++ printk("tail alloc: %ld\n",alloc_list->start); ++ } ++ return alloc_list; ++ ++} ++static void *vb2_dc_alloc(struct device *dev, unsigned long attrs, ++ unsigned long size, ++ enum dma_data_direction dma_dir, gfp_t gfp_flags) ++{ ++ struct vb2_dc_buf *buf; ++ ++ buf = kzalloc(sizeof *buf, GFP_KERNEL); ++ if (!buf) ++ return ERR_PTR(-ENOMEM); ++ ++#if 0 ++ if(conf->reserve_size > 0){ ++ struct reserve_memmg* m; ++ m = reserve_mem_alloc(conf,size); ++ if(m) ++ { ++ buf->vaddr = m->start + conf->reserve_addr; ++ buf->dma_addr = m->start + (unsigned long)conf->reserve_phy_addr; ++ buf->rsvmem = m; ++ printk("alloc addr %p\n",buf->vaddr); ++ } ++ } ++#endif ++ if(!buf->vaddr) ++ { ++ buf->vaddr = dma_alloc_noncoherent(dev, size, &buf->dma_addr, DMA_BIDIRECTIONAL, ++ GFP_KERNEL | gfp_flags); ++ if (!buf->vaddr) { ++ dev_err(dev, "dma_alloc_noncoherent of size %ld failed\n", size); ++ kfree(buf); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ /* Prevent the device from being released while the buffer is used */ ++ buf->dev = get_device(dev); ++ buf->size = size; ++ buf->dma_dir = dma_dir; ++ ++ buf->handler.refcount = (refcount_t *)&buf->refcount; ++ buf->handler.put = vb2_dc_put; ++ buf->handler.arg = buf; ++ ++ atomic_inc(&buf->refcount); ++ ++ return buf; ++} ++ ++int dma_common_mmap_cached(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size) ++{ ++ int ret = -ENXIO; ++#ifdef CONFIG_MMU ++ unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; ++ unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; ++ unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr)); ++ unsigned long off = vma->vm_pgoff; ++ ++// vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; ++// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_WA; /* Write-Acceleration */ ++ pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; ++// pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; ++// printk(KERN_DEBUG "__videobuf_mmap_mapper() vma->vm_page_prot=%x cpu_addr:%p\n", vma->vm_page_prot,cpu_addr); ++ ++ //if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) ++ // return ret; ++ ++ if (off < count && user_count <= (count - off)) { ++ ret = remap_pfn_range(vma, vma->vm_start, ++ pfn + off, ++ user_count << PAGE_SHIFT, ++ vma->vm_page_prot); ++ } ++#endif /* CONFIG_MMU */ ++ ++ return ret; ++} ++ ++static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ int ret; ++ ++ if (!buf) { ++ printk(KERN_ERR "No buffer to map\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * dma_mmap_* uses vm_pgoff as in-buffer offset, but we want to ++ * map whole buffer ++ */ ++ vma->vm_pgoff = 0; ++ ++ /* ret = dma_mmap_coherent(buf->dev, vma, buf->vaddr, */ ++ /* buf->dma_addr, buf->size); */ ++ ret = dma_common_mmap_cached(buf->dev, vma, buf->vaddr, ++ buf->dma_addr, buf->size); ++ ++ if (ret) { ++ pr_err("Remapping memory failed, error: %d\n", ret); ++ return ret; ++ } ++ ++ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; ++ vma->vm_private_data = &buf->handler; ++ vma->vm_ops = &vb2_common_vm_ops; ++ ++ vma->vm_ops->open(vma); ++ ++ pr_debug("%s: mapped dma addr 0x%08lx at 0x%08lx, size %ld\n", ++ __func__, (unsigned long)buf->dma_addr, vma->vm_start, ++ buf->size); ++ ++ return 0; ++} ++ ++/*********************************************/ ++/* DMABUF ops for exporters */ ++/*********************************************/ ++ ++struct vb2_dc_attachment { ++ struct sg_table sgt; ++ enum dma_data_direction dma_dir; ++}; ++ ++static int vb2_dc_dmabuf_ops_attach(struct dma_buf *dbuf, struct dma_buf_attachment *dbuf_attach) ++{ ++ struct vb2_dc_attachment *attach; ++ unsigned int i; ++ struct scatterlist *rd, *wr; ++ struct sg_table *sgt; ++ struct vb2_dc_buf *buf = dbuf->priv; ++ int ret; ++ ++ attach = kzalloc(sizeof(*attach), GFP_KERNEL); ++ if (!attach) ++ return -ENOMEM; ++ ++ sgt = &attach->sgt; ++ /* Copy the buf->base_sgt scatter list to the attachment, as we can't ++ * map the same scatter list to multiple attachments at the same time. ++ */ ++ ret = sg_alloc_table(sgt, buf->sgt_base->orig_nents, GFP_KERNEL); ++ if (ret) { ++ kfree(attach); ++ return -ENOMEM; ++ } ++ ++ rd = buf->sgt_base->sgl; ++ wr = sgt->sgl; ++ for (i = 0; i < sgt->orig_nents; ++i) { ++ sg_set_page(wr, sg_page(rd), rd->length, rd->offset); ++ rd = sg_next(rd); ++ wr = sg_next(wr); ++ } ++ ++ attach->dma_dir = DMA_NONE; ++ dbuf_attach->priv = attach; ++ ++ return 0; ++} ++ ++static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf, ++ struct dma_buf_attachment *db_attach) ++{ ++ struct vb2_dc_attachment *attach = db_attach->priv; ++ struct sg_table *sgt; ++ ++ if (!attach) ++ return; ++ ++ sgt = &attach->sgt; ++ ++ /* release the scatterlist cache */ ++ if (attach->dma_dir != DMA_NONE) ++ dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, ++ attach->dma_dir); ++ sg_free_table(sgt); ++ kfree(attach); ++ db_attach->priv = NULL; ++} ++ ++static struct sg_table *vb2_dc_dmabuf_ops_map( ++ struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir) ++{ ++ struct vb2_dc_attachment *attach = db_attach->priv; ++ /* stealing dmabuf mutex to serialize map/unmap operations */ ++ struct mutex *lock = &db_attach->dmabuf->lock; ++ struct sg_table *sgt; ++ ++ mutex_lock(lock); ++ ++ sgt = &attach->sgt; ++ /* return previously mapped sg table */ ++ if (attach->dma_dir == dma_dir) { ++ mutex_unlock(lock); ++ return sgt; ++ } ++ ++ /* release any previous cache */ ++ if (attach->dma_dir != DMA_NONE) { ++ dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, ++ attach->dma_dir); ++ attach->dma_dir = DMA_NONE; ++ } ++ ++ /* mapping to the client with new direction */ ++ sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, ++ dma_dir); ++ if (!sgt->nents) { ++ pr_err("failed to map scatterlist\n"); ++ mutex_unlock(lock); ++ return ERR_PTR(-EIO); ++ } ++ ++ attach->dma_dir = dma_dir; ++ ++ mutex_unlock(lock); ++ ++ return sgt; ++} ++ ++static void vb2_dc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach, ++ struct sg_table *sgt, enum dma_data_direction dma_dir) ++{ ++ /* nothing to be done here */ ++} ++ ++static void vb2_dc_dmabuf_ops_release(struct dma_buf *dbuf) ++{ ++ /* drop reference obtained in vb2_dc_get_dmabuf */ ++ vb2_dc_put(dbuf->priv); ++} ++ ++static void *vb2_dc_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum) ++{ ++ struct vb2_dc_buf *buf = dbuf->priv; ++ ++ return buf->vaddr + pgnum * PAGE_SIZE; ++} ++ ++static void *vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf) ++{ ++ struct vb2_dc_buf *buf = dbuf->priv; ++ ++ return buf->vaddr; ++} ++ ++static int vb2_dc_dmabuf_ops_mmap(struct dma_buf *dbuf, ++ struct vm_area_struct *vma) ++{ ++ return vb2_dc_mmap(dbuf->priv, vma); ++} ++ ++static struct dma_buf_ops vb2_dc_dmabuf_ops = { ++ .attach = vb2_dc_dmabuf_ops_attach, ++ .detach = vb2_dc_dmabuf_ops_detach, ++ .map_dma_buf = vb2_dc_dmabuf_ops_map, ++ .unmap_dma_buf = vb2_dc_dmabuf_ops_unmap, ++ .vmap = vb2_dc_dmabuf_ops_vmap, ++ .mmap = vb2_dc_dmabuf_ops_mmap, ++ .release = vb2_dc_dmabuf_ops_release, ++}; ++ ++static struct sg_table *vb2_dc_get_base_sgt(struct vb2_dc_buf *buf) ++{ ++ int ret; ++ struct sg_table *sgt; ++ ++ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) { ++ dev_err(buf->dev, "failed to alloc sg table\n"); ++ return NULL; ++ } ++ ++ ret = dma_get_sgtable(buf->dev, sgt, buf->vaddr, buf->dma_addr, ++ buf->size); ++ if (ret < 0) { ++ dev_err(buf->dev, "failed to get scatterlist from DMA API\n"); ++ kfree(sgt); ++ return NULL; ++ } ++ ++ return sgt; ++} ++ ++static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ struct dma_buf *dbuf; ++ DEFINE_DMA_BUF_EXPORT_INFO(exp_info); ++ ++ exp_info.ops = &vb2_dc_dmabuf_ops; ++ exp_info.size = buf->size; ++ exp_info.flags = flags; ++ exp_info.priv = buf; ++ ++ if (!buf->sgt_base) ++ buf->sgt_base = vb2_dc_get_base_sgt(buf); ++ ++ if (WARN_ON(!buf->sgt_base)) ++ return NULL; ++ ++ dbuf = dma_buf_export(&exp_info); ++ if (IS_ERR(dbuf)) ++ return NULL; ++ ++ /* dmabuf keeps reference to vb2 buffer */ ++ atomic_inc(&buf->refcount); ++ ++ return dbuf; ++} ++ ++/*********************************************/ ++/* callbacks for USERPTR buffers */ ++/*********************************************/ ++ ++static void vb2_dc_put_userptr(void *buf_priv) ++{ ++ struct vb2_dc_buf *buf = buf_priv; ++ struct sg_table *sgt = buf->dma_sgt; ++ int i; ++ struct page **pages; ++ ++ if (sgt) { ++ unsigned long attrs = 0; ++ ++ attrs = DMA_ATTR_SKIP_CPU_SYNC; ++ /* ++ * No need to sync to CPU, it's already synced to the CPU ++ * since the finish() memop will have been called before this. ++ */ ++ dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, ++ buf->dma_dir, attrs); ++ pages = frame_vector_pages(buf->vec); ++ /* sgt should exist only if vector contains pages... */ ++ BUG_ON(IS_ERR(pages)); ++ for (i = 0; i < frame_vector_count(buf->vec); i++) ++ set_page_dirty_lock(pages[i]); ++ sg_free_table(sgt); ++ kfree(sgt); ++ } ++ vb2_destroy_framevec(buf->vec); ++ kfree(buf); ++} ++ ++/* ++ * For some kind of reserved memory there might be no struct page available, ++ * so all that can be done to support such 'pages' is to try to convert ++ * pfn to dma address or at the last resort just assume that ++ * dma address == physical address (like it has been assumed in earlier version ++ * of videobuf2-dma-contig ++ */ ++ ++#ifdef __arch_pfn_to_dma ++static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn) ++{ ++ return (dma_addr_t)__arch_pfn_to_dma(dev, pfn); ++} ++#elif defined(__pfn_to_bus) ++static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn) ++{ ++ return (dma_addr_t)__pfn_to_bus(pfn); ++} ++#elif defined(__pfn_to_phys) ++static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn) ++{ ++ return (dma_addr_t)__pfn_to_phys(pfn); ++} ++#else ++static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn) ++{ ++ /* really, we cannot do anything better at this point */ ++ return (dma_addr_t)(pfn) << PAGE_SHIFT; ++} ++#endif ++ ++static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr, ++ unsigned long size, enum dma_data_direction dma_dir) ++{ ++ struct vb2_dc_buf *buf; ++ struct frame_vector *vec; ++ unsigned long offset; ++ int n_pages, i; ++ int ret = 0; ++ struct sg_table *sgt; ++ unsigned long contig_size; ++ unsigned long dma_align = dma_get_cache_alignment(); ++ unsigned long attrs = 0; ++ ++ attrs = DMA_ATTR_SKIP_CPU_SYNC; ++ ++ /* Only cache aligned DMA transfers are reliable */ ++ if (!IS_ALIGNED(vaddr | size, dma_align)) { ++ pr_debug("user data must be aligned to %lu bytes\n", dma_align); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ if (!size) { ++ pr_debug("size is zero\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ buf = kzalloc(sizeof *buf, GFP_KERNEL); ++ if (!buf) ++ return ERR_PTR(-ENOMEM); ++ ++ buf->dev = dev; ++ buf->dma_dir = dma_dir; ++ ++ offset = vaddr & ~PAGE_MASK; ++ vec = vb2_create_framevec(vaddr, size); ++ if (IS_ERR(vec)) { ++ ret = PTR_ERR(vec); ++ goto fail_buf; ++ } ++ buf->vec = vec; ++ n_pages = frame_vector_count(vec); ++ ret = frame_vector_to_pages(vec); ++ if (ret < 0) { ++ unsigned long *nums = frame_vector_pfns(vec); ++ ++ /* ++ * Failed to convert to pages... Check the memory is physically ++ * contiguous and use direct mapping ++ */ ++ for (i = 1; i < n_pages; i++) ++ if (nums[i-1] + 1 != nums[i]) ++ goto fail_pfnvec; ++ buf->dma_addr = vb2_dc_pfn_to_dma(buf->dev, nums[0]); ++ goto out; ++ } ++ ++ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) { ++ pr_err("failed to allocate sg table\n"); ++ ret = -ENOMEM; ++ goto fail_pfnvec; ++ } ++ ++ ret = sg_alloc_table_from_pages(sgt, frame_vector_pages(vec), n_pages, ++ offset, size, GFP_KERNEL); ++ if (ret) { ++ pr_err("failed to initialize sg table\n"); ++ goto fail_sgt; ++ } ++ ++ /* ++ * No need to sync to the device, this will happen later when the ++ * prepare() memop is called. ++ */ ++ sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, ++ buf->dma_dir, attrs); ++ if (sgt->nents <= 0) { ++ pr_err("failed to map scatterlist\n"); ++ ret = -EIO; ++ goto fail_sgt_init; ++ } ++ ++ contig_size = vb2_dc_get_contiguous_size(sgt); ++ if (contig_size < size) { ++ pr_err("contiguous mapping is too small %lu/%lu\n", ++ contig_size, size); ++ ret = -EFAULT; ++ goto fail_map_sg; ++ } ++ ++ buf->dma_addr = sg_dma_address(sgt->sgl); ++ buf->dma_sgt = sgt; ++out: ++ buf->size = size; ++ ++ return buf; ++ ++fail_map_sg: ++ dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, ++ buf->dma_dir, attrs); ++ ++fail_sgt_init: ++ sg_free_table(sgt); ++ ++fail_sgt: ++ kfree(sgt); ++ ++fail_pfnvec: ++ vb2_destroy_framevec(vec); ++ ++fail_buf: ++ kfree(buf); ++ ++ return ERR_PTR(ret); ++} ++ ++/*********************************************/ ++/* callbacks for DMABUF buffers */ ++/*********************************************/ ++ ++static int vb2_dc_map_dmabuf(void *mem_priv) ++{ ++ struct vb2_dc_buf *buf = mem_priv; ++ struct sg_table *sgt; ++ unsigned long contig_size; ++ ++ if (WARN_ON(!buf->db_attach)) { ++ pr_err("trying to pin a non attached buffer\n"); ++ return -EINVAL; ++ } ++ ++ if (WARN_ON(buf->dma_sgt)) { ++ pr_err("dmabuf buffer is already pinned\n"); ++ return 0; ++ } ++ ++ /* get the associated scatterlist for this buffer */ ++ sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); ++ if (IS_ERR(sgt)) { ++ pr_err("Error getting dmabuf scatterlist\n"); ++ return -EINVAL; ++ } ++ ++ /* checking if dmabuf is big enough to store contiguous chunk */ ++ contig_size = vb2_dc_get_contiguous_size(sgt); ++ if (contig_size < buf->size) { ++ pr_err("contiguous chunk is too small %lu/%lu b\n", ++ contig_size, buf->size); ++ dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); ++ return -EFAULT; ++ } ++ ++ buf->dma_addr = sg_dma_address(sgt->sgl); ++ buf->dma_sgt = sgt; ++ buf->vaddr = NULL; ++ ++ return 0; ++} ++ ++static void vb2_dc_unmap_dmabuf(void *mem_priv) ++{ ++ struct vb2_dc_buf *buf = mem_priv; ++ struct sg_table *sgt = buf->dma_sgt; ++ ++ if (WARN_ON(!buf->db_attach)) { ++ pr_err("trying to unpin a not attached buffer\n"); ++ return; ++ } ++ ++ if (WARN_ON(!sgt)) { ++ pr_err("dmabuf buffer is already unpinned\n"); ++ return; ++ } ++ ++ if (buf->vaddr) { ++ dma_buf_vunmap(buf->db_attach->dmabuf, buf->vaddr); ++ buf->vaddr = NULL; ++ } ++ dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); ++ ++ buf->dma_addr = 0; ++ buf->dma_sgt = NULL; ++} ++ ++static void vb2_dc_detach_dmabuf(void *mem_priv) ++{ ++ struct vb2_dc_buf *buf = mem_priv; ++ ++ /* if vb2 works correctly you should never detach mapped buffer */ ++ if (WARN_ON(buf->dma_addr)) ++ vb2_dc_unmap_dmabuf(buf); ++ ++ /* detach this attachment */ ++ dma_buf_detach(buf->db_attach->dmabuf, buf->db_attach); ++ kfree(buf); ++} ++ ++static void *vb2_dc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, ++ unsigned long size, enum dma_data_direction dma_dir) ++{ ++ struct vb2_dc_buf *buf; ++ struct dma_buf_attachment *dba; ++ ++ if (dbuf->size < size) ++ return ERR_PTR(-EFAULT); ++ ++ buf = kzalloc(sizeof(*buf), GFP_KERNEL); ++ if (!buf) ++ return ERR_PTR(-ENOMEM); ++ ++ buf->dev = dev; ++ /* create attachment for the dmabuf with the user device */ ++ dba = dma_buf_attach(dbuf, buf->dev); ++ if (IS_ERR(dba)) { ++ pr_err("failed to attach dmabuf\n"); ++ kfree(buf); ++ return dba; ++ } ++ ++ buf->dma_dir = dma_dir; ++ buf->size = size; ++ buf->db_attach = dba; ++ ++ return buf; ++} ++ ++/*********************************************/ ++/* DMA CONTIG exported functions */ ++/*********************************************/ ++ ++const struct vb2_mem_ops ingenic_vb2_dma_contig_memops = { ++ .alloc = vb2_dc_alloc, ++ .put = vb2_dc_put, ++ .get_dmabuf = vb2_dc_get_dmabuf, ++ .cookie = vb2_dc_cookie, ++ .vaddr = vb2_dc_vaddr, ++ .mmap = vb2_dc_mmap, ++ .get_userptr = vb2_dc_get_userptr, ++ .put_userptr = vb2_dc_put_userptr, ++ .prepare = vb2_dc_prepare, ++ .finish = vb2_dc_finish, ++ .map_dmabuf = vb2_dc_map_dmabuf, ++ .unmap_dmabuf = vb2_dc_unmap_dmabuf, ++ .attach_dmabuf = vb2_dc_attach_dmabuf, ++ .detach_dmabuf = vb2_dc_detach_dmabuf, ++ .num_users = vb2_dc_num_users, ++}; ++EXPORT_SYMBOL_GPL(ingenic_vb2_dma_contig_memops); ++ ++static int reserve_size = CONFIG_CAMERA_RESERVE_KB_SIZE; //unit: kb. ++static int __init set_camera_reserve(char *str) ++{ ++ reserve_size = simple_strtoul(str, &str, 0); ++ return 1; ++} ++ ++__setup("camera_reserve", set_camera_reserve); ++ ++ ++void *ingenic_vb2_dma_contig_init_ctx(struct device *dev) ++{ ++ struct vb2_dc_conf *conf; ++ ++ conf = kzalloc(sizeof *conf, GFP_KERNEL); ++ if (!conf) ++ return ERR_PTR(-ENOMEM); ++ ++ conf->dev = dev; ++ if(reserve_size > 0){ ++ conf->reserve_addr = dma_alloc_noncoherent(dev, reserve_size * 1024, &conf->reserve_phy_addr, DMA_BIDIRECTIONAL, GFP_KERNEL); ++ if(conf->reserve_addr) ++ conf->reserve_size = reserve_size * 1024; ++ printk("camera reserve memory size %dKByte Addr:%p\n",reserve_size,conf->reserve_addr); ++ } ++ ++ INIT_LIST_HEAD(&conf->top); ++ return conf; ++} ++EXPORT_SYMBOL_GPL(ingenic_vb2_dma_contig_init_ctx); ++ ++void ingenic_vb2_dma_contig_cleanup_ctx(void *alloc_ctx) ++{ ++ if (!IS_ERR_OR_NULL(alloc_ctx)) ++ kfree(alloc_ctx); ++} ++EXPORT_SYMBOL_GPL(ingenic_vb2_dma_contig_cleanup_ctx); ++ ++MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); ++MODULE_AUTHOR("Pawel Osciak "); ++MODULE_LICENSE("GPL"); +diff --git a/module_drivers/drivers/mfd/Kconfig b/module_drivers/drivers/mfd/Kconfig +new file mode 100644 +index 000000000..4e365ce9c +--- /dev/null ++++ b/module_drivers/drivers/mfd/Kconfig +@@ -0,0 +1,75 @@ ++config MFD_INGENIC_SADC_V13 ++ tristate "[SADC] Support for the Ingenic SADC core" ++ select MFD_CORE ++ depends on MACH_XBURST || MACH_XBURST2 ++ help ++ Say yes here if you want support for the SADC unit in the Ingenic SoC. ++ This driver is necessary for Ingenic_battery driver. ++ ++config MFD_INGENIC_SADC_AUX ++ tristate "[SADC] Support for the Ingenic SADC AUX" ++ select MFD_CORE ++ depends on MACH_XBURST || MACH_XBURST2 ++ help ++ Say yes here if you want support for the SADC unit in the Ingenic SoC. ++ This driver is necessary for ingenic_battery driver. ++if MFD_INGENIC_SADC_AUX ++ config SADC_AUX_VERF_3V3 ++ bool "Ingenic sadc aux reference voltage 3.3V." ++ depends on SOC_X1600 ++ default y ++ help ++ Select ingenic sadc reference voltage. ++ ++ config SADC_AUX_VERF_1V8 ++ bool "Ingenic sadc aux reference voltage 1.8V." ++ depends on SOC_X2000_V12 || SOC_M300 || SOC_X2100 || SOC_X2500 ++ default y ++ help ++ Select ingenic sadc reference voltage. ++ ++ ++ config SADC_AUX_12BIT ++ bool "ingenic sadc aux 12bit" ++ depends on SOC_X2500 || SOC_X1600 ++ default y ++ ++ config SADC_AUX_10BIT ++ bool "ingenic sadc aux 10bit" ++ depends on SOC_X2000_V12 || SOC_M300 || SOC_X2100 ++ default y ++endif ++ ++config MFD_INGENIC_TCU ++ bool "[TCU] Ingenic tcu driver" ++ select MFD_CORE ++ select GENERIC_IRQ_CHIP ++ depends on SOC_X2000_V12 || SOC_X2000 || SOC_M300 || SOC_X2100 || SOC_X1600 ++ help ++ Say yes here if you want support for the TCU unit in the ingenic SoC. ++ This driver is necessary for ingenic pwm or counter. ++ ++config MFD_INGENIC_TCU_V1 ++ bool "[TCU] Ingenic tcu driver v1" ++ select MFD_CORE ++ select GENERIC_IRQ_CHIP ++ depends on SOC_X2500 ++ default n ++ help ++ Say yes here if you want support for the TCU unit in the ingenic SoC. ++ This driver is necessary for ingenic pwm or counter. ++ ++ ++config MFD_RICOH619 ++ bool "Ricoh RC5T619 Power Management system device" ++ depends on I2C=y ++ select MFD_CORE ++ select REGMAP_I2C ++ help ++ Select this option to get support for the RICOH619 Power ++ Management system device. ++ This driver provides common support for accessing the device ++ through i2c interface. The device supports multiple sub-devices ++ like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey. ++ Additional drivers must be enabled in order to use the ++ different functionality of the device. +diff --git a/module_drivers/drivers/mfd/Makefile b/module_drivers/drivers/mfd/Makefile +new file mode 100644 +index 000000000..925a35cce +--- /dev/null ++++ b/module_drivers/drivers/mfd/Makefile +@@ -0,0 +1,5 @@ ++obj-$(CONFIG_MFD_RICOH619) += ricoh619.o ricoh619-irq.o ++obj-$(CONFIG_MFD_INGENIC_SADC_V13) += ingenic_adc_v13.o ++obj-$(CONFIG_MFD_INGENIC_SADC_AUX) += ingenic_adc_aux.o ++obj-$(CONFIG_MFD_INGENIC_TCU) += ingenic-tcu.o ++obj-$(CONFIG_MFD_INGENIC_TCU_V1) += ingenic-tcu_v1.o +diff --git a/module_drivers/drivers/mfd/ingenic-tcu.c b/module_drivers/drivers/mfd/ingenic-tcu.c +new file mode 100644 +index 000000000..d6b935539 +--- /dev/null ++++ b/module_drivers/drivers/mfd/ingenic-tcu.c +@@ -0,0 +1,908 @@ ++/* ++ * ingenic_tcu.c - ingenic Soc TCU MFD driver. ++ * ++ * Copyright (C) 2020 Ingenic Semiconductor Co., Ltd. ++ * Written by wssong . ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define NR_TCU_CHNS TCU_NR_IRQS ++ ++#define DE_WARNING 0 ++ ++ ++static inline void ingenic_tcu_full_mask(struct ingenic_tcu_chn *tcu_chn); ++static inline void ingenic_tcu_half_mask(struct ingenic_tcu_chn *tcu_chn); ++ ++static struct ingenic_tcu_chn g_tcu_chn[NR_TCU_CHNS] = {{0}}; ++ ++/*Timer Counter Enable/Disable Register*/ ++static inline void ingenic_tcu_set_enable(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TESR, 1 << tcu_chn->index); ++} ++ ++static inline void ingenic_tcu_set_disable(struct ingenic_tcu_chn *tcu_chn) ++{ ++ u32 tcsr; ++ ++ spin_lock(&tcu_chn->tcu->lock); ++ ingenic_tcu_full_mask(tcu_chn); ++ ingenic_tcu_half_mask(tcu_chn); ++ tcu_writel(tcu_chn->tcu, TCU_TECR, 1 << tcu_chn->index); ++ if ((tcu_chn->capture_num & CAPTURE_LOOP_FLAGS) != 0) { ++ tcsr = tcu_readl(tcu_chn->tcu,CHN_CAP(tcu_chn->index)) & ~CAP_NUM_MSK; ++ tcu_writel(tcu_chn->tcu,CHN_CAP(tcu_chn->index),tcsr); ++ } ++ ++ tcu_chn->en_flag = 0; ++ spin_unlock(&tcu_chn->tcu->lock); ++} ++ ++/*Timer Stop Set/Clr Register*/ ++static inline void ingenic_tcu_set_stop(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TSSR, 1 << tcu_chn->index); ++} ++ ++static inline void ingenic_tcu_clr_stop(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TSCR, 1 << tcu_chn->index); ++} ++ ++/*Timer Mast Register set/clr operation and flag clr operation (full)*/ ++static inline void ingenic_tcu_full_mask(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TMSR, 1 << tcu_chn->index); ++} ++ ++static inline void ingenic_tcu_full_unmask(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TMCR, 1 << tcu_chn->index); ++} ++ ++static inline void ingenic_tcu_clear_full_flag(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TFCR, 1 << tcu_chn->index); ++} ++ ++/*Timer Mast Register set/clr operation and flag clr operation (half)*/ ++static inline void ingenic_tcu_half_mask(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TMSR, 1 << (tcu_chn->index + 16)); ++} ++ ++static inline void ingenic_tcu_half_unmask(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TMCR, 1 << (tcu_chn->index + 16)); ++} ++ ++static inline void ingenic_tcu_clear_half_flag(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_writel(tcu_chn->tcu, TCU_TFCR, 1 << (tcu_chn->index + 16)); ++} ++ ++/*Timer Control Register select the TCNT count clock frequency*/ ++static inline void ingenic_tcu_set_prescale(struct ingenic_tcu_chn *tcu_chn, enum tcu_prescale prescale) ++{ ++ u32 tcsr = tcu_chn_readl(tcu_chn, CHN_TCSR) & ~CSR_DIV_MSK; ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcsr | (prescale << 3)); ++} ++ ++/*Timer Counter clear to zero*/ ++static inline void ingenic_tcu_clear_tcnt(struct ingenic_tcu_chn *tcu_chn) ++{ ++ tcu_chn_writel(tcu_chn, CHN_TCNT, 0); ++} ++ ++/*Timer Data FULL/HALF Register*/ ++static inline void ingenic_tcu_set_chn_full(struct ingenic_tcu_chn *tcu_chn, unsigned int value) ++{ ++ tcu_chn_writel(tcu_chn, CHN_TDFR, value); ++} ++ ++static inline void ingenic_tcu_set_chn_half(struct ingenic_tcu_chn *tcu_chn, unsigned int value) ++{ ++ tcu_chn_writel(tcu_chn, CHN_TDHR, value); ++} ++ ++/*Timer Control Register set count mode */ ++static inline void ingenic_tcu_set_count_mode(struct ingenic_tcu_chn *tcu_chn, enum tcu_count_mode count_mode) ++{ ++ u32 tcsr = tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(CSR_CM_MSK); ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcsr | count_mode << 22); ++} ++ ++/*Timer control set pos and neg*/ ++static inline void ingenic_tcu_set_pos(struct ingenic_tcu_chn *tcu_chn,unsigned int offset) ++{ ++ u32 tcsr; ++ if (offset > 15 && offset < 22){ ++ tcsr = tcu_chn_readl(tcu_chn,CHN_TCSR) | TCU_CONTROL_BIT(offset); ++ tcu_chn_writel(tcu_chn,CHN_TCSR, tcsr); ++ } ++} ++ ++static inline void ingenic_tcu_set_neg(struct ingenic_tcu_chn *tcu_chn,unsigned int offset) ++{ ++ u32 tcsr; ++ if (offset > 15 && offset < 22){ ++ tcsr = tcu_chn_readl(tcu_chn,CHN_TCSR) | TCU_CONTROL_BIT(offset); ++ tcu_chn_writel(tcu_chn,CHN_TCSR, tcsr); ++ } ++ ++} ++ ++static inline void ingenic_tcu_set_pos_neg(struct ingenic_tcu_chn *tcu_chn,unsigned int offset,unsigned int offset1) ++{ ++ ingenic_tcu_set_pos(tcu_chn,offset); ++ ingenic_tcu_set_neg(tcu_chn,offset1); ++} ++ ++static inline void ingenic_tcu_clr_pos_neg(struct ingenic_tcu_chn *tcu_chn,unsigned int bit) ++{ ++ u32 tcsr = tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(TCU_CONTROL_BIT(bit) | TCU_CONTROL_BIT((bit + 1))); ++ tcu_chn_writel(tcu_chn,CHN_TCSR,tcsr); ++} ++ ++/*Timer control config signal pos and neg*/ ++static inline void ingenic_tcu_config_sig_pos_neg(struct ingenic_tcu_chn *tcu_chn, enum tcu_clksrc clksrc) ++{ ++ switch(clksrc){ ++ case TCU_CLKSRC_EXT : ++ ingenic_tcu_clr_pos_neg(tcu_chn ,CLK_POS); ++ switch(tcu_chn->sig_ext){ ++ case SIG_NEG_EN : ++ ingenic_tcu_set_neg(tcu_chn,CLK_NEG); ++ break; ++ case SIG_POS_EN : ++ ingenic_tcu_set_pos(tcu_chn,CLK_POS); ++ break; ++ case SIG_POS_NEG_EN : ++ ingenic_tcu_set_pos_neg(tcu_chn,CLK_POS,CLK_NEG); ++ break; ++ default : ++ break; ++ } ++ break; ++ case TCU_CLKSRC_GPIO0 : ++ ingenic_tcu_clr_pos_neg(tcu_chn,GPIO0_POS); ++ switch(tcu_chn->sig_gpio0){ ++ case SIG_NEG_EN : ++ ingenic_tcu_set_neg(tcu_chn,GPIO0_NEG); ++ break; ++ case SIG_POS_EN : ++ ingenic_tcu_set_pos(tcu_chn,GPIO0_POS); ++ break; ++ case SIG_POS_NEG_EN : ++ ingenic_tcu_set_pos_neg(tcu_chn,GPIO0_NEG,GPIO0_POS); ++ break; ++ default : ++ break; ++ } ++ break; ++ case TCU_CLKSRC_GPIO1 : ++ ingenic_tcu_clr_pos_neg(tcu_chn,GPIO1_POS); ++ switch(tcu_chn->sig_gpio1){ ++ case SIG_NEG_EN : ++ ingenic_tcu_set_neg(tcu_chn,GPIO1_NEG); ++ break; ++ case SIG_POS_EN : ++ ingenic_tcu_set_pos(tcu_chn,GPIO1_POS); ++ break; ++ case SIG_POS_NEG_EN : ++ ingenic_tcu_set_pos_neg(tcu_chn,GPIO1_POS,GPIO1_NEG); ++ break; ++ default : ++ break; ++ } ++ break; ++ default : ++ break; ++ } ++} ++ ++/*Timer Control Register select timer clock input and counting mode pos or neg*/ ++static inline void ingenic_tcu_set_clksrc(struct ingenic_tcu_chn *tcu_chn, enum tcu_clksrc ext, enum tcu_clksrc gpio0,enum tcu_clksrc gpio1) ++{ ++ u32 tcsr; ++ ingenic_tcu_config_sig_pos_neg(tcu_chn, ext); ++ ingenic_tcu_config_sig_pos_neg(tcu_chn, gpio0); ++ ingenic_tcu_config_sig_pos_neg(tcu_chn, gpio1); ++ tcsr = tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(ONE_BIT_OFFSET(2) | ONE_BIT_OFFSET(6) |ONE_BIT_OFFSET(7)); ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcsr | ext | gpio0 | gpio1); ++} ++ ++static inline void ingenic_tcu_set_shutdown(struct ingenic_tcu_chn *tcu_chn) ++{ ++ if(tcu_chn->shutdown_mode) { ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcu_chn_readl(tcu_chn, CHN_TCSR) | (TCU_CONTROL_BIT(15))); ++ }else { ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(TCU_CONTROL_BIT(15))); ++ } ++} ++ ++static inline void ingenic_tcu_irq_mode(struct ingenic_tcu_chn *tcu_chn) ++{ ++ switch (tcu_chn->irq_type) { ++ case NULL_IRQ_MODE : ++ ingenic_tcu_full_mask(tcu_chn); ++ ingenic_tcu_half_mask(tcu_chn); ++ break; ++ case FULL_IRQ_MODE : ++ ingenic_tcu_full_unmask(tcu_chn); ++ ingenic_tcu_half_mask(tcu_chn); ++ break; ++ case HALF_IRQ_MODE : ++ ingenic_tcu_full_mask(tcu_chn); ++ ingenic_tcu_half_unmask(tcu_chn); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ ingenic_tcu_full_unmask(tcu_chn); ++ ingenic_tcu_half_unmask(tcu_chn); ++ break; ++ default: ++ break; ++ } ++} ++ ++/*config gate work mode */ ++static inline void ingenic_tcu_config_gate_mode(struct ingenic_tcu_chn *tcu_chn) ++{ ++ u32 tcsr; ++ if (tcu_chn->gate_pola){ ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcu_chn_readl(tcu_chn, CHN_TCSR) | (TCU_CONTROL_BIT(14))); ++ }else{ ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(TCU_CONTROL_BIT(14))); ++ } ++ tcsr = tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(CSR_GATE_MSK); ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcsr | tcu_chn->gate_sel << 11); ++} ++ ++/*config direction work mode*/ ++static inline void ingenic_tcu_config_direction_mode(struct ingenic_tcu_chn *tcu_chn) ++{ ++ u32 tcsr; ++ if(tcu_chn->dir_pola){ ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcu_chn_readl(tcu_chn, CHN_TCSR) | (TCU_CONTROL_BIT(13))); ++ }else{ ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(TCU_CONTROL_BIT(13))); ++ } ++ tcsr = tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(CSR_DIR_MSK); ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcsr | tcu_chn->dir_sel << 8); ++} ++ ++/*config quadrature work mode*/ ++static inline void ingenic_tcu_config_quadrature_mode(struct ingenic_tcu_chn *tcu_chn) ++{ ++ u32 tcsr; ++ if(tcu_chn->dir_pola){ ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcu_chn_readl(tcu_chn, CHN_TCSR) | (TCU_CONTROL_BIT(13))); ++ }else{ ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(TCU_CONTROL_BIT(13))); ++ } ++ tcu_chn->clk_ext = TCU_CLKSRC_EXT; ++ tcu_chn->clk_gpio0 = TCU_CLKSRC_GPIO0; ++ tcu_chn->clk_gpio1 = TCU_CLKSRC_GPIO1; ++ tcu_chn->dir_sel = DIR_SEL_GPIO_QUA; ++ tcu_chn->sig_gpio0 = SIG_POS_NEG_EN; ++ tcu_chn->sig_gpio1 = SIG_POS_NEG_EN; ++ tcsr = tcu_chn_readl(tcu_chn, CHN_TCSR) & ~(CSR_DIR_MSK); ++ tcu_chn_writel(tcu_chn, CHN_TCSR, tcsr | tcu_chn->dir_sel << 8); ++ ++} ++ ++/*config pos work mode*/ ++static inline void ingenic_tcu_config_pos_mode(struct ingenic_tcu_chn *tcu_chn) ++{ ++ u32 tcsr; ++ if (tcu_chn->pos_sel > 0 && tcu_chn->pos_sel < 4){ ++ tcsr = tcu_readl(tcu_chn->tcu,CHN_CAP(tcu_chn->index)) & ~(CAP_SEL_MSK); ++ tcu_writel(tcu_chn->tcu,CHN_CAP(tcu_chn->index),tcsr | tcu_chn->pos_sel << 16); ++ } ++} ++ ++/*config capture work mode*/ ++static inline void ingenic_tcu_config_capture_mode(struct ingenic_tcu_chn *tcu_chn) ++{ ++ u32 tcsr; ++ if (tcu_chn->capture_sel >= 0 && tcu_chn->capture_sel < 3){ ++ tcsr = tcu_readl(tcu_chn->tcu,CHN_CAP(tcu_chn->index)) & ~(CAP_SEL_MSK | CAP_NUM_MSK); ++ tcu_writel(tcu_chn->tcu,CHN_CAP(tcu_chn->index),tcsr | tcu_chn->capture_sel << 16 | tcu_chn->capture_num ); ++ } ++} ++ ++/*config filter work mode*/ ++static inline void ingenic_tcu_config_filter_mode(struct ingenic_tcu_chn *tcu_chn) ++{ ++ u32 tcsr; ++ tcsr = tcu_readl(tcu_chn->tcu,CHN_FIL_VAL(tcu_chn->index)) & ~(FIL_VAL_GPIO1_MSK | FIL_VAL_GPIO0_MSK); ++ tcu_writel(tcu_chn->tcu,CHN_FIL_VAL(tcu_chn->index),tcsr | tcu_chn->fil_a_num | tcu_chn->fil_b_num << 16 ); ++} ++ ++/*Choose a working mode*/ ++static inline void ingenic_tcu_sel_work_mode(struct ingenic_tcu_chn *tcu_chn) ++{ ++ switch(tcu_chn->mode_sel){ ++ case GENERAL_MODE : ++ break; ++ case GATE_MODE : ++ ingenic_tcu_config_gate_mode(tcu_chn); ++ break; ++ case DIRECTION_MODE : ++ ingenic_tcu_config_direction_mode(tcu_chn); ++ break; ++ case QUADRATURE_MODE : ++ ingenic_tcu_config_quadrature_mode(tcu_chn); ++ break; ++ case POS_MODE : ++ ingenic_tcu_config_pos_mode(tcu_chn); ++ break; ++ case CAPTURE_MODE : ++ ingenic_tcu_config_capture_mode(tcu_chn); ++ break; ++ case FILTER_MODE : ++ ingenic_tcu_config_filter_mode(tcu_chn); ++ break; ++ default : ++ break; ++ } ++ ++} ++ ++void sws_pr_debug(struct ingenic_tcu_chn *tcu_chn) ++{ ++ static int count = 0; ++ count ++; ++ printk("\n\n----------------------------------------count N0.%d----------------------------------------------------\n\n",count); ++ printk("-stop-----addr-%08x-value-%08x-----------\n",(unsigned int)(tcu_chn->tcu->iomem + TCU_TSR),tcu_readl(tcu_chn->tcu,TCU_TSR)); ++ printk("-mask-----addr-%08x-value-%08x-----------\n",(unsigned int)(tcu_chn->tcu->iomem + TCU_TMR),tcu_readl(tcu_chn->tcu,TCU_TMR)); ++ printk("-enable---addr-%08x-value-%08x-----------\n",(unsigned int)(tcu_chn->tcu->iomem + TCU_TER),tcu_readl(tcu_chn->tcu,TCU_TER)); ++ printk("-flag-----addr-%08x-value-%08x-----------\n",(unsigned int)(tcu_chn->tcu->iomem + TCU_TFR),tcu_readl(tcu_chn->tcu,TCU_TFR)); ++ printk("-Control--addr-%08x-value-%08x-----------\n",(unsigned int)(tcu_chn->tcu->iomem + tcu_chn->reg_base + CHN_TCSR),tcu_chn_readl(tcu_chn,CHN_TCSR)); ++ printk("-full-----addr-%08x-value-%08x-----------\n",(unsigned int)(tcu_chn->tcu->iomem + tcu_chn->reg_base + CHN_TDFR),tcu_chn_readl(tcu_chn,CHN_TDFR)); ++ printk("-half- -addr-%08x-value-%08x-----------\n",(unsigned int)(tcu_chn->tcu->iomem + tcu_chn->reg_base + CHN_TDHR),tcu_chn_readl(tcu_chn,CHN_TDHR)); ++ printk("-TCNT-----addr-%08x-value-%08x-----------\n",(unsigned int)(tcu_chn->tcu->iomem + tcu_chn->reg_base + CHN_TCNT),tcu_chn_readl(tcu_chn,CHN_TCNT)); ++ printk("-CAP reg_base-------value-%08x-----------\n",tcu_readl(tcu_chn->tcu,CHN_CAP(tcu_chn->index))); ++ printk("-CAP_VAL register---value-%08x-----------\n",tcu_readl(tcu_chn->tcu,CHN_CAP_VAL(tcu_chn->index))); ++} ++EXPORT_SYMBOL_GPL(sws_pr_debug); ++ ++ ++void ingenic_tcu_clear_irq_flag(struct ingenic_tcu_chn *tcu_chn) ++{ ++ ingenic_tcu_clear_full_flag(tcu_chn); ++ ingenic_tcu_clear_half_flag(tcu_chn); ++} ++ ++EXPORT_SYMBOL_GPL(ingenic_tcu_clear_irq_flag); ++ ++void ingenic_tcu_config_chn(struct ingenic_tcu_chn *tcu_chn) ++{ ++ ++ spin_lock(&tcu_chn->tcu->lock); ++ /* Clear IRQ flag */ ++ ingenic_tcu_clear_irq_flag(tcu_chn); ++ ++ /* Config IRQ */ ++ ingenic_tcu_irq_mode(tcu_chn); ++ ++ /*select work mode*/ ++ ingenic_tcu_sel_work_mode(tcu_chn); ++ ++ /*full num and half num*/ ++ ingenic_tcu_set_chn_full(tcu_chn,tcu_chn->full_num); ++ ingenic_tcu_set_chn_half(tcu_chn,tcu_chn->half_num); ++ ++ /*TCNT clear to 0*/ ++ ingenic_tcu_clear_tcnt(tcu_chn); ++ ++ /* shutdown mode */ ++ ingenic_tcu_set_shutdown(tcu_chn); ++ ++ /* prescale */ ++ if(!(tcu_readl(tcu_chn->tcu,TCU_TER) & (1 << tcu_chn->index))) ++ ingenic_tcu_set_prescale(tcu_chn, tcu_chn->prescale); ++ ++ /* clk source */ ++ ingenic_tcu_set_clksrc(tcu_chn, tcu_chn->clk_ext, tcu_chn->clk_gpio0,tcu_chn->clk_gpio1); ++ ++ /*select counter mode*/ ++ ingenic_tcu_set_count_mode(tcu_chn,tcu_chn->count_mode); ++ spin_unlock(&tcu_chn->tcu->lock); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_config_chn); ++ ++#if DE_WARNING ++static void ingenic_tcu_irq_mask(void) ++{ ++ unsigned long flags; ++ ++ int id ; ++ for(id = 0; id < NR_TCU_CHNS; id++){ ++ if(g_tcu_chn[id].en_flag){ ++ spin_lock_irqsave(&g_tcu_chn[id].tcu->lock, flags); ++ switch (g_tcu_chn[id].irq_type) { ++ case FULL_IRQ_MODE : ++ ingenic_tcu_full_mask(&g_tcu_chn[id]); ++ break; ++ case HALF_IRQ_MODE : ++ ingenic_tcu_half_mask(&g_tcu_chn[id]); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ ingenic_tcu_full_mask(&g_tcu_chn[id]); ++ ingenic_tcu_half_mask(&g_tcu_chn[id]); ++ break; ++ default: ++ break; ++ } ++ spin_unlock_irqrestore(&g_tcu_chn[id].tcu->lock, flags); ++ } ++ } ++} ++#endif ++ ++#if DE_WARNING ++static void ingenic_tcu_irq_unmask(void) ++{ ++ unsigned long flags; ++ int id ; ++ for(id = 0; id < NR_TCU_CHNS; id++){ ++ if(g_tcu_chn[id].en_flag){ ++ spin_lock_irqsave(&g_tcu_chn[id].tcu->lock, flags); ++ switch (g_tcu_chn[id].irq_type) { ++ case FULL_IRQ_MODE : ++ ingenic_tcu_full_unmask(&g_tcu_chn[id]); ++ break; ++ case HALF_IRQ_MODE : ++ ingenic_tcu_half_unmask(&g_tcu_chn[id]); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ ingenic_tcu_full_unmask(&g_tcu_chn[id]); ++ ingenic_tcu_half_unmask(&g_tcu_chn[id]); ++ break; ++ default: ++ break; ++ } ++ spin_unlock_irqrestore(&g_tcu_chn[id].tcu->lock, flags); ++ } ++ } ++} ++#endif ++ ++static void ingenic_tcu_irq_ack(struct ingenic_tcu *tcu) ++{ ++ unsigned long flags; ++ unsigned long tmp; ++ int id ; ++ int i; ++ int times = timeout; ++ ++ for(id = 0; id < NR_TCU_CHNS; id++){ ++ if(g_tcu_chn[id].en_flag){ ++ spin_lock_irqsave(&g_tcu_chn[id].tcu->lock, flags); ++ switch (g_tcu_chn[id].irq_type) { ++ case FULL_IRQ_MODE : ++ ingenic_tcu_clear_full_flag(&g_tcu_chn[id]); ++ break; ++ case HALF_IRQ_MODE : ++ ingenic_tcu_clear_half_flag(&g_tcu_chn[id]); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ ingenic_tcu_clear_full_flag(&g_tcu_chn[id]); ++ ingenic_tcu_clear_half_flag(&g_tcu_chn[id]); ++ break; ++ default: ++ break; ++ } ++ ++ if(g_tcu_chn[id].gpio_trigger) { ++ tmp = ingenic_tcu_store_flag_st(tcu); ++ i = 0; ++ while(tmp) { ++ if(tmp & (1 << i)) { ++ tmp &= ~(1 << i); ++ ingenic_tcu_store_flag_clr(&g_tcu_chn[i]); ++ printk("%d %d %d\n",__LINE__, i ,ingenic_tcu_store_val(&g_tcu_chn[i])); ++ } ++ ++ if (times-- == 0) ++ break; ++ i++; ++ } ++ } ++ spin_unlock_irqrestore(&g_tcu_chn[id].tcu->lock, flags); ++ } ++ } ++} ++ ++/*This is a simple configuration test demo*/ ++static void ingenic_tcu_config_attr(int id,enum tcu_mode_sel mode_sel) ++{ ++ int i = 0; ++ g_tcu_chn[id].mode_sel = mode_sel; ++ g_tcu_chn[id].irq_type = FULL_IRQ_MODE; ++ g_tcu_chn[id].full_num = 0xffff; ++ g_tcu_chn[id].half_num = 0x5000; ++ g_tcu_chn[id].prescale = TCU_PRESCALE_1; ++ ++ g_tcu_chn[id].count_value = 0; ++ g_tcu_chn[id].shutdown_mode = 0; ++ g_tcu_chn[id].en_flag = 1; ++ ++ /*In order to facilitate testing, ++ * it has no practical significance.*/ ++ switch(g_tcu_chn[id].mode_sel){ ++ case GENERAL_MODE: ++ /*Enable external clock to use rising edge counting , result TCNT != 0*/ ++ g_tcu_chn[id].clk_ext = TCU_CLKSRC_EXT; ++ g_tcu_chn[id].sig_ext = SIG_POS_EN; ++ break; ++ case GATE_MODE: ++ /*gate signal hold on 0,counter start when control signal is 1,result TCNT == 0*/ ++ g_tcu_chn[id].gate_sel = GATE_SEL_HZ; ++ g_tcu_chn[id].gate_pola = GATE_POLA_HIGH; ++ g_tcu_chn[id].clk_ext = TCU_CLKSRC_EXT; ++ g_tcu_chn[id].sig_ext = SIG_POS_EN; ++ break; ++ case DIRECTION_MODE: ++ /*use gpio0 with direction signa. counter sub when control signal is 1.result TCNT add and sub */ ++ g_tcu_chn[id].clk_gpio0 = TCU_CLKSRC_GPIO0; ++ g_tcu_chn[id].dir_sel = DIR_SEL_GPIO0; ++ g_tcu_chn[id].dir_pola = DIR_POLA_HIGH; ++ g_tcu_chn[id].clk_ext = TCU_CLKSRC_EXT; ++ g_tcu_chn[id].sig_ext = SIG_POS_EN; ++ break; ++ case POS_MODE: ++ /*TCNT is cleared on the rising edge of gpio0.*/ ++ g_tcu_chn[id].clk_ext = TCU_CLKSRC_EXT; ++ g_tcu_chn[id].sig_ext = SIG_POS_EN; ++ /*gpio0 pos clear count*/ ++ g_tcu_chn[id].clk_gpio0 = TCU_CLKSRC_GPIO0; ++ g_tcu_chn[id].sig_gpio0 = SIG_POS_EN; ++ g_tcu_chn[id].capture_sel = GPIO0_POS_CLR; ++ break; ++ case CAPTURE_MODE: ++ /*Use ext_clk to capture the duty cycle of gpio0, result CAP_VAL register have value*/ ++ g_tcu_chn[id].clk_ext = TCU_CLKSRC_EXT; ++ g_tcu_chn[id].sig_ext = SIG_POS_EN; ++ g_tcu_chn[id].clk_gpio0 = TCU_CLKSRC_GPIO0; ++ g_tcu_chn[id].capture_sel = CAPTURE_GPIO0; ++ g_tcu_chn[id].capture_num = 0xa0; ++ break; ++ case FILTER_MODE: ++ /*for easy test set max*/ ++ g_tcu_chn[id].clk_gpio0 = TCU_CLKSRC_GPIO0; ++ g_tcu_chn[id].sig_gpio0 = SIG_POS_EN; ++ g_tcu_chn[id].fil_a_num = 0x3ff; ++ g_tcu_chn[id].fil_b_num = 0x3ff; ++ break; ++ default: ++ break; ++ } ++ ++ if(g_tcu_chn[id].gpio_trigger) { ++ ingenic_tcu_store_mask_set(&g_tcu_chn[id]); ++ ingenic_tcu_store_neg_enable(&g_tcu_chn[id]); ++ ingenic_tcu_store_enable(&g_tcu_chn[id]); ++ ingenic_tcu_store_mask_clr(&g_tcu_chn[id]); ++ } ++ ++ ingenic_tcu_config_chn(&g_tcu_chn[id]); ++ ingenic_tcu_enable_counter(&g_tcu_chn[id]); ++ ingenic_tcu_start_counter(&g_tcu_chn[id]); ++ ++ if(!g_tcu_chn[id].gpio_trigger) { ++ for(i = 0; i < 20 ;i++) ++ sws_pr_debug(&g_tcu_chn[id]); ++ } ++} ++ ++ ++static irqreturn_t ingenic_tcu_interrupt(int irq, void *dev_id) ++{ ++ struct ingenic_tcu *tcu = (struct ingenic_tcu *)(dev_id); ++ if(tcu_readl(tcu,TCU_TFR) & TCU_FLAG_RD){ ++ }else{ ++ ingenic_tcu_irq_ack(tcu); ++ } ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t ingenic_tcu_trigger_interrupt(int irq, void *dev_id) ++{ ++ struct ingenic_tcu *tcu = (struct ingenic_tcu *)(dev_id); ++ unsigned long flags; ++ unsigned long tmp; ++ int i; ++ int times = timeout; ++ ++ spin_lock_irqsave(&tcu->lock, flags); ++ tmp = ingenic_tcu_store_flag_st(tcu); ++ i = 0; ++ while(tmp) { ++ if(tmp & (1 << i)) { ++ tmp &= ~(1 << i); ++ ingenic_tcu_store_flag_clr(&g_tcu_chn[i]); ++ printk("%d %d %d\n",__LINE__, i ,ingenic_tcu_store_val(&g_tcu_chn[i])); ++ } ++ ++ if (times-- == 0) ++ break; ++ ++ i++; ++ } ++ spin_unlock_irqrestore(&tcu->lock, flags); ++ ++ return IRQ_HANDLED; ++} ++ ++static ssize_t tcu_show_enable(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int i; ++ int ret = 0; ++ ret += sprintf(buf + ret, "\nmode_sel :\n"); ++ ret += sprintf(buf + ret, "0:GENERAL_MODE 1:GATE_MODE 2:DIRECTION_MODE 3:QUADRATURE_MODE\n"); ++ ret += sprintf(buf + ret, "4:POS_MODE 5:CAPTURE_MODE 6:FILTER_MODE\n\n"); ++ ret += sprintf(buf + ret, "####################example####################\n"); ++ ret += sprintf(buf + ret, "## echo channel_id mode_sel gpio_trigger > enable \n"); ++ ret += sprintf(buf + ret, "## echo channel_id > disable \n\n"); ++ for (i = 0; i < NR_TCU_CHNS ; i++) { ++ if(g_tcu_chn[i].en_flag) ++ ret += sprintf(buf + ret, "channel: %02d enable\n", i); ++ else ++ ret += sprintf(buf + ret, "channel: %02d disable\n", i); ++ } ++ return ret; ++} ++ ++static ssize_t tcu_store_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int channel_id; ++ int mode_id; ++ enum tcu_mode_sel mode_sel; ++ const char *str = buf; ++ int ret_count = 0; ++ ++ while (!isxdigit(*str)) { ++ str++; ++ if(++ret_count >= count) ++ return count; ++ } ++ channel_id = simple_strtoul(str, (char **)&str, 10); ++ ++ while (!isxdigit(*str)) { ++ str++; ++ if(++ret_count >= count) ++ return count; ++ } ++ mode_id = simple_strtoul(str, (char **)&str, 10); ++ ++ while (!isxdigit(*str)) { ++ str++; ++ if(++ret_count >= count) ++ g_tcu_chn[channel_id].gpio_trigger = 0; ++ } ++ g_tcu_chn[channel_id].gpio_trigger = simple_strtoul(str, (char **)&str, 10); ++ ++ switch(mode_id){ ++ case 0: mode_sel = GENERAL_MODE; ++ break; ++ case 1: mode_sel = GATE_MODE; ++ break; ++ case 2: mode_sel = DIRECTION_MODE; ++ break; ++ case 3: mode_sel = QUADRATURE_MODE; ++ break; ++ case 4: mode_sel = POS_MODE; ++ break; ++ case 5: mode_sel = CAPTURE_MODE; ++ break; ++ case 6: mode_sel = FILTER_MODE; ++ break; ++ default: mode_sel = GENERAL_MODE; ++ break; ++ } ++ ++ if(channel_id >= 0 && channel_id < 8){ ++ if(g_tcu_chn[channel_id].en_flag){ ++ printk("channel %d already enable \n",channel_id); ++ return -1; ++ } ++ ++ printk("mode_id = %d \n",mode_id); ++ ingenic_tcu_config_attr(channel_id,mode_sel); ++ }else ++ printk("Please select the correct channel 0 ~ 7 range.\n"); ++ return count; ++} ++ ++static ssize_t tcu_store_disable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int id; ++ const char *str = buf; ++ int ret_count = 0; ++ ++ while (!isxdigit(*str)) { ++ str++; ++ if(++ret_count >= count) ++ return count; ++ } ++ ++ id = simple_strtoul(str, (char **)&str, 10); ++ ++ if(id >= 0 && id < 8){ ++ if(!g_tcu_chn[id].en_flag){ ++ printk("channel %d already disable \n",id); ++ return -1; ++ } ++ ++ if(g_tcu_chn[id].gpio_trigger) { ++ ingenic_tcu_store_mask_clr(&g_tcu_chn[id]); ++ ingenic_tcu_store_neg_disable(&g_tcu_chn[id]); ++ ingenic_tcu_store_disable(&g_tcu_chn[id]); ++ } ++ ingenic_tcu_set_disable(&g_tcu_chn[id]); ++ }else ++ printk("Please select the correct channel 0 ~ 7 range.\n"); ++ return count; ++} ++ ++ ++static struct device_attribute tcu_device_attributes[] = { ++ __ATTR(enable, S_IRUGO|S_IWUSR, tcu_show_enable, tcu_store_enable), ++ __ATTR(disable, S_IRUGO|S_IWUSR, tcu_show_enable, tcu_store_disable), ++}; ++ ++ ++static int ingenic_tcu_probe(struct platform_device *pdev) ++{ ++ struct ingenic_tcu *tcu; ++ int i, ret = 0; ++ ++ tcu = kmalloc(sizeof(struct ingenic_tcu), GFP_KERNEL); ++ if (!tcu) { ++ dev_err(&pdev->dev, "Failed to allocate driver struct\n"); ++ return -ENOMEM; ++ } ++ ++ tcu->irq = platform_get_irq(pdev, 0); ++ if (tcu->irq < 0) { ++ dev_err(&pdev->dev, "Failed to get platform irq\n"); ++ ret = tcu->irq; ++ goto err_free; ++ } ++ ++ tcu->irq_trigger = platform_get_irq(pdev, 1); ++ if (tcu->irq_trigger < 0) { ++ dev_err(&pdev->dev, "not support irq trigger function\n"); ++ ret = tcu->irq_trigger; ++ } else { ++ ret = request_irq(tcu->irq_trigger,ingenic_tcu_trigger_interrupt, ++ IRQF_SHARED | IRQF_TRIGGER_LOW,"ingenic-tcu-tri-interrupt",tcu); ++ ++ if (ret) { ++ dev_err(&pdev->dev, "request_irq failed !! %d-\n",tcu->irq_trigger); ++ } ++ } ++ ++ tcu->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!tcu->res) { ++ dev_err(&pdev->dev, "No iomem resource\n"); ++ ret = -ENXIO; ++ goto err_ioremap; ++ } ++ ++ tcu->clk = devm_clk_get(&pdev->dev,"gate_tcu"); ++ clk_prepare_enable(tcu->clk); ++ ++ tcu->iomem = ioremap(tcu->res->start, resource_size(tcu->res)); ++ if (!tcu->iomem) ++ goto err_mfd_add; ++ ++ spin_lock_init(&tcu->lock); ++ ++ ret = request_irq(tcu->irq,ingenic_tcu_interrupt, ++ IRQF_SHARED | IRQF_TRIGGER_LOW,"ingenic-tcu-interrupt",tcu); ++ if (ret) { ++ dev_err(&pdev->dev, "request_irq failed !! %d-\n",tcu->irq); ++ goto err_mfd_add; ++ } ++ ++ platform_set_drvdata(pdev, tcu); ++ ++ for (i = 0; i < NR_TCU_CHNS; i++) { ++ g_tcu_chn[i].index = i; ++ g_tcu_chn[i].capture_num = 0; ++ g_tcu_chn[i].count_value = 0; ++ g_tcu_chn[i].fil_a_num = 0; ++ g_tcu_chn[i].fil_b_num = 0; ++ g_tcu_chn[i].reg_base = TCU_FULL0 + i * TCU_CHN_OFFSET; ++ g_tcu_chn[i].irq_type = NULL_IRQ_MODE; ++ g_tcu_chn[i].clk_ext = TCU_CLKSRC_NULL; ++ g_tcu_chn[i].clk_gpio0 = TCU_CLKSRC_NULL; ++ g_tcu_chn[i].clk_gpio1 = TCU_CLKSRC_NULL; ++ g_tcu_chn[i].prescale = TCU_PRESCALE_64; ++ g_tcu_chn[i].shutdown_mode = 0; ++ g_tcu_chn[i].count_mode = COUNT_MODE_FCZ; ++ g_tcu_chn[i].mode_sel = GENERAL_MODE; ++ g_tcu_chn[i].gate_pola = GATE_POLA_LOW; ++ g_tcu_chn[i].gate_sel = GATE_SEL_HZ; ++ g_tcu_chn[i].dir_sel = DIR_SEL_HH; ++ g_tcu_chn[i].dir_pola = DIR_POLA_LOW; ++ g_tcu_chn[i].en_flag = 0; ++ g_tcu_chn[i].tcu = tcu; ++ g_tcu_chn[i].gpio_trigger = 0; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(tcu_device_attributes); i++) { ++ ret = device_create_file(&pdev->dev, &tcu_device_attributes[i]); ++ if (ret) ++ dev_warn(&pdev->dev, "attribute %d create failed", i); ++ } ++ printk("ingenic TCU driver register completed\n"); ++ return 0; ++ ++err_mfd_add: ++ iounmap(tcu->iomem); ++err_ioremap: ++ release_resource(tcu->res); ++err_free: ++ kfree(tcu); ++ return ret; ++} ++ ++static int ingenic_tcu_remove(struct platform_device *pdev) ++{ ++ struct ingenic_tcu *tcu = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(tcu->clk); ++ iounmap(tcu->iomem); ++ release_resource(tcu->res); ++ platform_set_drvdata(pdev, NULL); ++ free_irq(tcu->irq,tcu); ++ kfree(tcu); ++ ++ return 0; ++} ++static const struct of_device_id tcu_match[] = { ++ { .compatible = "ingenic,tcu", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, tcu_match); ++ ++static struct platform_driver ingenic_tcu_driver = { ++ .probe = ingenic_tcu_probe, ++ .remove = ingenic_tcu_remove, ++ .driver = { ++ .name = "ingenic-tcu", ++ .of_match_table = tcu_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_tcu_driver); ++ ++MODULE_AUTHOR("wssong "); ++MODULE_DESCRIPTION("Ingenic TCU driver"); ++MODULE_ALIAS("platform:x2000_v2-tcu"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/mfd/ingenic-tcu_v1.c b/module_drivers/drivers/mfd/ingenic-tcu_v1.c +new file mode 100644 +index 000000000..76b6c6f42 +--- /dev/null ++++ b/module_drivers/drivers/mfd/ingenic-tcu_v1.c +@@ -0,0 +1,942 @@ ++/* ++ * ingenic-tcu.c - Inegnic Soc TCU MFD driver. ++ * ++ * Copyright (C) 2015 Ingenic Semiconductor Co., Ltd. ++ * Written by bo.liu . ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++#include ++#include ++#include ++ ++#define WDT_TDR (0x00) /* rw, 32, 0x???????? */ ++#define WDT_TCER (0x04) /* rw, 32, 0x???????? */ ++#define WDT_TCNT (0x08) /* rw, 32, 0x???????? */ ++#define WDT_TCSR (0x0c) /* rw, 32, 0x???????? */ ++ ++#define TCU_TSTR (0xF0) /* Timer Status Register,Only Used In Tcu2 Mode */ ++#define TCU_TSTSR (0xF4) /* Timer Status Set Register */ ++#define TCU_TSTCR (0xF8) /* Timer Status Clear Register */ ++#define TCU_TSR (0x1C) /* Timer Stop Register */ ++#define TCU_TSSR (0x2C) /* Timer Stop Set Register */ ++#define TCU_TSCR (0x3C) /* Timer Stop Clear Register */ ++#define TCU_TER (0x10) /* Timer Counter Enable Register */ ++#define TCU_TESR (0x14) /* Timer Counter Enable Set Register */ ++#define TCU_TECR (0x18) /* Timer Counter Enable Clear Register */ ++#define TCU_TFR (0x20) /* Timer Flag Register */ ++#define TCU_TFSR (0x24) /* Timer Flag Set Register */ ++#define TCU_TFCR (0x28) /* Timer Flag Clear Register */ ++#define TCU_TMR (0x30) /* Timer Mask Register */ ++#define TCU_TMSR (0x34) /* Timer Mask Set Register */ ++#define TCU_TMCR (0x38) /* Timer Mask Clear Register */ ++ ++#define CH_TDFR(n) (0x40 + (n)*0x10) /* Timer Data Full Reg */ ++#define CH_TDHR(n) (0x44 + (n)*0x10) /* Timer Data Half Reg */ ++#define CH_TCNT(n) (0x48 + (n)*0x10) /* Timer Counter Reg */ ++#define CH_TCSR(n) (0x4C + (n)*0x10) /* Timer Control Reg */ ++ ++#define TCSR_PWM_BYPASS (1 << 11) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_CNT_CLRZ (1 << 10) /* clear counter to 0, only used in TCU2 mode */ ++#define TCSR_PWM_SD (1 << 9) /* shut down the pwm output only used in TCU1 mode */ ++#define TCSR_PWM_HIGH (1 << 8) /* selects an initial output level for pwm output */ ++#define TCSR_PWM_EN (1 << 7) /* pwm pin output enable */ ++#define TCSR_PWM_IN (1 << 6) /* pwm pin output enable */ ++ ++struct ingenic_tcu { ++ void __iomem *base; ++ struct device *dev; ++ struct clk *clk; ++ struct device_node *np; ++ struct irq_domain *irq_domain; ++ struct mfd_cell * tcu_cells; ++ struct ingenic_tcu_chn *tcu_chn; ++ ++ char idmap[32]; ++ int channel_mask; ++ int irq_tcu0; ++ int irq_tcu1; ++ int irq_tcu2; ++ int channel_num; ++ int channel_irq_num; ++ spinlock_t lock; ++}; ++ ++#define TCU_DEBUG 0 ++ ++static struct ingenic_tcu *tcu; ++ ++static inline int tcu_readl(struct ingenic_tcu *tcu, unsigned int reg_addr) ++{ ++ return readl(tcu->base + reg_addr); ++} ++static inline void tcu_writel(struct ingenic_tcu *tcu, unsigned int reg_addr, ++ unsigned int val) ++{ ++ writel(val, tcu->base + reg_addr); ++} ++#if TCU_DEBUG ++static void tcu_dump(int id) ++{ ++ printk("====================================channel %d===================================\n", id); ++ ++ if(id == 16){ ++ printk("tcu_readl(WDT_TDR %x) = %x\n", (unsigned int)(tcu->base + WDT_TDR), tcu_readl(tcu, WDT_TDR)); ++ printk("tcu_readl(WDT_TCER %x) = %x\n", (unsigned int)(tcu->base + WDT_TCER), tcu_readl(tcu, WDT_TCER)); ++ printk("tcu_readl(WDT_TCNT %x) = %x\n", (unsigned int)(tcu->base + WDT_TCNT), tcu_readl(tcu, WDT_TCNT)); ++ printk("tcu_readl(WDT_TCSR %x) = %x\n", (unsigned int)(tcu->base + WDT_TCSR), tcu_readl(tcu, WDT_TCSR)); ++ printk("tcu_readl(TCU_TSR %x) = %x\n", (unsigned int)(tcu->base + TCU_TSR), tcu_readl(tcu, TCU_TSR)); ++ return; ++ } ++ ++ printk("tcu_readl(CH_TDFR(id) %x) = %x\n", (unsigned int)(tcu->base + CH_TDFR(id)), tcu_readl(tcu, CH_TDFR(id))); ++ printk("tcu_readl(CH_TDHR(id) %x) = %x\n", (unsigned int)(tcu->base + CH_TDHR(id)), tcu_readl(tcu, CH_TDHR(id))); ++ printk("tcu_readl(CH_TCNT(id) %x) = %x\n", (unsigned int)(tcu->base + CH_TCNT(id)), tcu_readl(tcu, CH_TCNT(id))); ++ printk("tcu_readl(CH_TCSR(id) %x) = %x\n", (unsigned int)(tcu->base + CH_TCSR(id)), tcu_readl(tcu, CH_TCSR(id))); ++ ++ printk("tcu_readl(TCU_TSTR %x) = %x\n", (unsigned int)(tcu->base + TCU_TSTR), tcu_readl(tcu, TCU_TSTR)); ++ printk("tcu_readl(TCU_TSR %x) = %x\n", (unsigned int)(tcu->base + TCU_TSR), tcu_readl(tcu, TCU_TSR)); ++ printk("tcu_readl(TCU_TER %x) = %x\n", (unsigned int)(tcu->base + TCU_TER), tcu_readl(tcu, TCU_TER)); ++ printk("tcu_readl(TCU_TFR %x) = %x\n", (unsigned int)(tcu->base + TCU_TFR), tcu_readl(tcu, TCU_TFR)); ++ printk("tcu_readl(TCU_TMR %x) = %x\n", (unsigned int)(tcu->base + TCU_TMR), tcu_readl(tcu, TCU_TMR)); ++ printk("=======================================================================\n"); ++} ++#endif ++ ++static inline void tcu_mask_full_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TMSR, 1 << id); ++} ++static inline void tcu_unmask_full_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TMCR, 1 << id); ++} ++static inline void tcu_clear_full_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TFCR, 1 << id); ++} ++static inline void tcu_mask_half_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TMSR, 1 << (id + 16)); ++} ++static inline void tcu_unmask_half_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TMCR, 1 << (id + 16)); ++} ++static inline void tcu_clear_half_irq(int id) ++{ ++ tcu_writel(tcu, TCU_TFCR, 1 << (id + 16)); ++} ++ ++void tcu_enable_counter(int id) ++{ ++ tcu_writel(tcu, TCU_TESR, BIT(id)); ++} ++EXPORT_SYMBOL_GPL(tcu_enable_counter); ++ ++void tcu_disable_counter(int id) ++{ ++ int index = tcu->idmap[id]; ++ struct ingenic_tcu_chn *chn = &tcu->tcu_chn[index]; ++ tcu_writel(tcu, TCU_TECR, BIT(id)); ++ if (chn->cib.mode == TCU_MODE2) { ++ int timeout = 5000; ++ while ((tcu_readl(tcu, TCU_TSTR) & (1 << id)) || (timeout--)); ++ if(!timeout){ ++ dev_err(tcu->dev, "channel %d:the reset of counter is not finished now\n", id); ++ } ++ } ++} ++EXPORT_SYMBOL_GPL(tcu_disable_counter); ++ ++void tcu_start_counter(int id) ++{ ++ tcu_writel(tcu, TCU_TSCR, BIT(id)); ++} ++EXPORT_SYMBOL_GPL(tcu_start_counter); ++ ++void tcu_stop_counter(int id) ++{ ++ tcu_writel(tcu, TCU_TSSR, BIT(id)); ++} ++EXPORT_SYMBOL_GPL(tcu_stop_counter); ++ ++void tcu_set_counter(int id, unsigned int val) ++{ ++ tcu_writel(tcu, CH_TCNT(id), val); ++} ++EXPORT_SYMBOL_GPL(tcu_set_counter); ++ ++int tcu_get_counter(int id) ++{ ++ return tcu_readl(tcu, CH_TCNT(id)); ++} ++EXPORT_SYMBOL_GPL(tcu_get_counter); ++ ++static inline void tcu_disable_all_channel(void) ++{ ++ /* Timer irqs are unmasked by default, mask them */ ++ tcu_writel(tcu, TCU_TMSR, 0x00ff00ff); ++ /* Stop all timer counter */ ++ tcu_writel(tcu, TCU_TECR, 0x000080ff); ++ /* Disable all timer clocks except for those used as system timers */ ++ tcu_writel(tcu, TCU_TSSR, 0x000000ff); ++} ++ ++static int tcu_pwm_output_enable(int id) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val |= TCSR_PWM_EN; ++ tcu_writel(tcu, CH_TCSR(id), val); ++ ++ return 0; ++} ++ ++static void tcu_pwm_output_disable(int id) ++{ ++ unsigned int val; ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val &= ~TCSR_PWM_EN; ++ tcu_writel(tcu, CH_TCSR(id), val); ++} ++ ++static int tcu_pwm_bypass_enable(int id) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ if(val & TCU_CLKSRC_PCK) { ++ dev_err(tcu->dev, "TCU %d pwm bypass is not support clk source pck\n", id); ++ return -ENXIO; ++ } ++ val |= TCSR_PWM_BYPASS; ++ tcu_writel(tcu, CH_TCSR(id), val); ++ ++ return 0; ++} ++ ++static int tcu_pwm_bypass_disable(int id) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val &= ~TCSR_PWM_BYPASS; ++ tcu_writel(tcu, CH_TCSR(id), val); ++ ++ return 0; ++} ++ ++static void tcu_clear_counter_to_zero(int id) ++{ ++ int index = tcu->idmap[id]; ++ struct ingenic_tcu_chn *chn = &tcu->tcu_chn[index]; ++ if (chn->cib.mode == TCU_MODE2) { ++ unsigned int val = tcu_readl(tcu, CH_TCSR(id)); ++ tcu_writel(tcu, CH_TCSR(id), (val | TCSR_CNT_CLRZ)); ++ } ++ ++ tcu_writel(tcu, CH_TCNT(id), 0); ++} ++ ++static void set_tcu_full_half_value(int id, unsigned int full_num, ++ unsigned int half_num) ++{ ++ tcu_writel(tcu, CH_TDFR(id), full_num); ++ tcu_writel(tcu, CH_TDHR(id), half_num); ++} ++ ++static void tcu_set_pwm_shutdown(int id, unsigned int shutdown) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ if (shutdown) ++ val |= TCSR_PWM_SD; ++ else ++ val &= ~TCSR_PWM_SD; ++ tcu_writel(tcu, CH_TCSR(id), val); ++} ++ ++static void tcu_set_start_state(int id) ++{ ++ /*fix this*/ ++ /*tcu_disable_counter(id);*/ ++ tcu_start_counter(id); ++ ++ /* TCSR just keep, which will be update follow process ++ in function ingenic_tcu_config ++ tcu_writel(tcu, CH_TCSR(id), 0); ++ */ ++} ++ ++static void tcu_pwm_input_enable(int id) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val |= TCSR_PWM_IN; ++ tcu_writel(tcu, CH_TCSR(id), val); ++} ++ ++static void tcu_pwm_input_disable(int id) ++{ ++ unsigned int val; ++ ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val &= ~TCSR_PWM_IN; ++ tcu_writel(tcu, CH_TCSR(id), val); ++} ++ ++static int tcu_clock_enable(struct platform_device *pdev) ++{ ++ if (!(tcu->channel_mask & BIT(pdev->id))) { ++ dev_err(&pdev->dev, ++ "current tcu channel %d busy\n",pdev->id); ++ return -EINVAL; ++ } ++ ++ if(pdev->id != 16) ++ tcu_enable_counter(pdev->id); ++ ++ tcu_start_counter(pdev->id); ++ tcu->channel_mask &= ~(BIT(pdev->id)); ++ return 0; ++} ++ ++static int tcu_clock_disable(struct platform_device *pdev) ++{ ++ struct ingenic_tcu *tcu = dev_get_drvdata(pdev->dev.parent); ++ int id = pdev->id; ++ int index = tcu->idmap[id]; ++ struct ingenic_tcu_chn *chn = &tcu->tcu_chn[index]; ++ ++ if(id != 16) { ++ switch (chn->irq_type) { ++ case FULL_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ tcu_clear_full_irq(id); ++ break; ++ case HALF_IRQ_MODE : ++ tcu_unmask_half_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ tcu_unmask_half_irq(id); ++ tcu_clear_full_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ default : ++ break; ++ } ++ if(chn->is_count_clear) { ++ unsigned long flags; ++ ++ tcu_disable_counter(id); ++ spin_lock_irqsave(&tcu->lock, flags); ++ tcu_clear_counter_to_zero(id); ++ spin_unlock_irqrestore(&tcu->lock, flags); ++ } ++ } ++ tcu_stop_counter(id); ++ tcu->channel_mask |= BIT(pdev->id); ++ return 0; ++} ++ ++int ingenic_tcu_counter_begin(struct ingenic_tcu_chn *chn) ++{ ++ int ret = 0; ++ ++ if (chn->is_pwm) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tcu->lock, flags); ++ tcu_pwm_output_enable(chn->cib.id); ++ spin_unlock_irqrestore(&tcu->lock, flags); ++ } ++ tcu_enable_counter(chn->cib.id); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_counter_begin); ++ ++void ingenic_tcu_counter_stop(struct ingenic_tcu_chn *chn) ++{ ++ if (chn->is_pwm) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tcu->lock, flags); ++ tcu_pwm_output_disable(chn->cib.id); ++ spin_unlock_irqrestore(&tcu->lock, flags); ++ } ++ ++ tcu_disable_counter(chn->cib.id); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_counter_stop); ++ ++void ingenic_tcu_set_period(int id, uint16_t period) ++{ ++ tcu_writel(tcu, CH_TDFR(id), period); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_set_period); ++ ++void ingenic_tcu_set_duty(int id, uint16_t duty) ++{ ++ tcu_writel(tcu, CH_TDHR(id), duty); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_set_duty); ++ ++void ingenic_tcu_set_prescale(int id, enum tcu_prescale prescale) ++{ ++ unsigned int val; ++ /* unsigned long flags; */ ++ ++ //spin_lock_irqsave(&tcu->lock, flags); ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val &= ~(0x7 << 3); ++ val |= (prescale << 3); ++ tcu_writel(tcu, CH_TCSR(id), val); ++ //spin_unlock_irqrestore(&tcu->lock, flags); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_set_prescale); ++ ++void ingenic_tcu_set_pwm_output_init_level(int id, int level) ++{ ++ unsigned int val; ++ /* unsigned long flags; */ ++ ++ //spin_lock_irqsave(&tcu->lock, flags); ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ if (level) ++ val |= (TCSR_PWM_HIGH); ++ else ++ val &= ~(TCSR_PWM_HIGH); ++ tcu_writel(tcu, CH_TCSR(id), val); ++ //spin_unlock_irqrestore(&tcu->lock, flags); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_set_pwm_output_init_level); ++ ++void ingenic_tcu_set_clksrc(int id, enum tcu_clksrc src) ++{ ++ unsigned int val; ++ /* unsigned long flags; */ ++ ++ //spin_lock_irqsave(&tcu->lock, flags); ++ val = tcu_readl(tcu, CH_TCSR(id)); ++ val &= ~0x7; ++ val |= src; ++ tcu_writel(tcu, CH_TCSR(id), val); ++ ++ //spin_unlock_irqrestore(&tcu->lock, flags); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_set_clksrc); ++ ++int ingenic_tcu_get_count(int id) ++{ ++ if(id == 1 || id == 2) { ++ int i = 0; ++ int tmp = 0; ++ ++ while ((tmp == 0) && (i < 5)) { ++ tmp = tcu_readl(tcu, TCU_TSTR) & (1 << (id + 16)); ++ i++; ++ } ++ if (tmp == 0) ++ return -EINVAL; ++ } ++ return tcu_get_counter(id); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_get_count); ++ ++void ingenic_tcu_channel_to_virq(struct ingenic_tcu_chn *chn) ++{ ++ int index; ++ ++ if(chn->cib.id == 5) { ++ chn->virq[0] = tcu->irq_tcu1; ++ return; ++ } ++ if(chn->cib.id == 15) { ++ chn->virq[0] = tcu->irq_tcu0; ++ return; ++ } ++ index = chn->cib.id * 2; ++ ++ switch (chn->irq_type) { ++ case FULL_IRQ_MODE : ++ chn->virq[0] = irq_create_mapping(tcu->irq_domain, index); ++ break; ++ case HALF_IRQ_MODE : ++ chn->virq[1] = irq_create_mapping(tcu->irq_domain, index + 1); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ chn->virq[0] = irq_create_mapping(tcu->irq_domain, index); ++ chn->virq[1] = irq_create_mapping(tcu->irq_domain, index + 1); ++ break; ++ default: ++ break; ++ } ++ ++ if(chn->virq[0] < 0 || chn->virq[1] < 0) ++ return; ++ ++ if(chn->virq[0]) ++ irq_set_chip_data(chn->virq[0], chn); ++ ++ if(chn->virq[1]) ++ irq_set_chip_data(chn->virq[1], chn); ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_channel_to_virq); ++ ++void ingenic_watchdog_set_count(unsigned int value) ++{ ++ tcu_writel(tcu, WDT_TCNT, value); ++} ++EXPORT_SYMBOL_GPL(ingenic_watchdog_set_count); ++ ++void ingenic_watchdog_config(unsigned int tcsr_val, unsigned int timeout_value) ++{ ++ tcu_writel(tcu, WDT_TCER, 0); ++ tcu_writel(tcu, WDT_TCSR, tcsr_val); ++ tcu_writel(tcu, WDT_TDR, timeout_value); ++ tcu_writel(tcu, WDT_TCNT, 0); ++ tcu_writel(tcu, WDT_TCER, 1); ++} ++EXPORT_SYMBOL_GPL(ingenic_watchdog_config); ++ ++static inline void tcu_disable_current_channel(int id) ++{ ++ /* Stop current timer counter */ ++ tcu_disable_counter(id); ++ /* Disable current timer clocks except for those used as system timers */ ++ tcu_stop_counter(id); ++} ++ ++struct mfd_cell *request_cell(int id) ++{ ++ int i; ++ if (!(tcu->channel_mask & BIT(id))) { ++ dev_err(tcu->dev, ++ "current tcu channel %d busy\n",id); ++ return NULL; ++ } ++ ++ tcu_disable_current_channel(id); ++ i = tcu->idmap[id]; ++ tcu->channel_mask &= ~(BIT(id)); ++ ++ return &(tcu->tcu_cells[i]); ++} ++EXPORT_SYMBOL_GPL(request_cell); ++ ++void free_cell(int id) ++{ ++ tcu->channel_mask |= BIT(id); ++} ++EXPORT_SYMBOL_GPL(free_cell); ++ ++static int check_pwm_is_availabl(struct ingenic_tcu_chn *chn) ++{ ++ int id = chn->cib.id; ++ if(id != 15) { ++ if(chn->is_pwm && !(chn->cib.func & PWM_FUNC)) { ++ dev_err(tcu->dev, "channel %d not support pwm function\n", id); ++ return -1; ++ } else if(!chn->is_pwm && !(chn->cib.func & TRACKBALL_FUNC)) { ++ dev_err(tcu->dev, "channel %d not support trackball function\n", id); ++ return -1; ++ } ++ if(chn->pwm_in_en && !chn->cib.pwmin) { ++ dev_err(tcu->dev, "channel %d not support pwm in function\n", id); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++int ingenic_tcu_config(struct ingenic_tcu_chn *chn) ++{ ++ unsigned long flags; ++ int id = chn->cib.id; ++ ++ if(check_pwm_is_availabl(chn) < 0) ++ return -1; ++ /* ++ tcu lock should be used to lock all tcu register update. ++ example: led-pwm work thread and pwm suspend maybe update TSR ++ at the same time. ++ */ ++ spin_lock_irqsave(&tcu->lock, flags); ++ tcu_set_start_state(id); ++ ++ tcu_clear_full_irq(id); ++ tcu_clear_half_irq(id); ++ ++ switch (chn->irq_type) { ++ case NULL_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ tcu_mask_half_irq(id); ++ tcu_clear_full_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ case FULL_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ tcu_mask_half_irq(id); ++ tcu_clear_full_irq(id); ++ break; ++ case HALF_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ tcu_unmask_half_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ tcu_unmask_half_irq(id); ++ tcu_clear_full_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ default : ++ break; ++ } ++ ++ ingenic_tcu_set_pwm_output_init_level(id, chn->init_level); ++ if(chn->cib.mode == TCU_MODE1) { ++ tcu_set_pwm_shutdown(id, chn->shutdown_mode); ++ } ++ ++ if (chn->is_pwm) { ++ /* ++ configure just do configuer, pwm should ++ be enable through pwm_enable interface. ++ This is standard usage of pwm interface. ++ */ ++ if(chn->pwm_bapass_mode) { ++ if(chn->clk_src == TCU_CLKSRC_PCK) { ++ dev_err(tcu->dev, "the current version can not bypass pclk\n"); ++ } ++ tcu_pwm_bypass_enable(id); ++ } else { ++ tcu_pwm_bypass_disable(id); ++ } ++ } else { ++ tcu_pwm_output_disable(id); ++ } ++ ++ ingenic_tcu_set_prescale(id, chn->clk_div); ++ set_tcu_full_half_value(id, chn->full_num, chn->half_num); ++ if (chn->pwm_in_en) ++ tcu_pwm_input_enable(id); ++ else ++ tcu_pwm_input_disable(id); ++ ingenic_tcu_set_clksrc(id, chn->clk_src); ++ tcu_clear_counter_to_zero(id); ++ ++ spin_unlock_irqrestore(&tcu->lock, flags); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_tcu_config); ++ ++static void tcu_irq_mask(struct irq_data *data) ++{ ++ struct ingenic_tcu_chn *chn = irq_data_get_irq_chip_data(data); ++ int id = chn->cib.id; ++ ++ switch (chn->irq_type) { ++ case FULL_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ break; ++ case HALF_IRQ_MODE : ++ tcu_mask_half_irq(id); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ tcu_mask_half_irq(id); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void tcu_irq_unmask(struct irq_data *data) ++{ ++ struct ingenic_tcu_chn *chn = irq_data_get_irq_chip_data(data); ++ int id = chn->cib.id; ++ ++ switch (chn->irq_type) { ++ case FULL_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ break; ++ case HALF_IRQ_MODE : ++ tcu_unmask_half_irq(id); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ tcu_unmask_full_irq(id); ++ tcu_unmask_half_irq(id); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void tcu_mask_and_ack_irq(struct irq_data *data) ++{ ++ struct ingenic_tcu_chn *chn = irq_data_get_irq_chip_data(data); ++ int id = chn->cib.id; ++ ++ switch (chn->irq_type) { ++ case FULL_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ tcu_clear_full_irq(id); ++ break; ++ case HALF_IRQ_MODE : ++ tcu_mask_half_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ case FULL_HALF_IRQ_MODE : ++ tcu_mask_full_irq(id); ++ tcu_mask_half_irq(id); ++ tcu_clear_full_irq(id); ++ tcu_clear_half_irq(id); ++ break; ++ default : ++ break; ++ } ++} ++ ++static struct irq_chip tcu_irq_chip = { ++ .name = "ingenic-tcu_v1", ++ .irq_disable = tcu_mask_and_ack_irq, ++ .irq_enable = tcu_irq_unmask, ++ .irq_unmask = tcu_irq_unmask, ++ .irq_mask = tcu_irq_mask, ++ .irq_mask_ack = tcu_mask_and_ack_irq, ++}; ++ ++static int tcu2_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) ++{ ++ struct ingenic_tcu *tcu = d->host_data; ++ ++ irq_set_chip_data(virq, tcu); ++ irq_set_chip_and_handler(virq, &tcu_irq_chip, handle_level_irq); ++ return 0; ++} ++ ++static const struct irq_domain_ops tcu2_irq_domain_ops = { ++ .map = tcu2_irq_domain_map, ++ .xlate = irq_domain_xlate_onetwocell, ++}; ++ ++static void tcu_irq_demux(struct irq_desc *desc) ++{ ++ struct ingenic_tcu *tcu = irq_desc_get_handler_data(desc); ++ unsigned long pend, mask, tcu2_pend = 0; ++ ++ pend = readl(tcu->base + TCU_TFR); ++ mask = readl(tcu->base + TCU_TMR) | (1 << 5 | 1 << (5 + 16)); ++ ++ pend = pend & ~(mask); ++ while(pend) { ++ struct ingenic_tcu_chn *chn; ++ int index; ++ ++ tcu2_pend = ffs(pend) - 1; ++ index = tcu->idmap[tcu2_pend]; ++ chn = &tcu->tcu_chn[index]; ++ if ((pend & 0xffff)){ ++ generic_handle_irq(chn->virq[FULL_BIT]); ++ } else { ++ generic_handle_irq(chn->virq[HALF_BIT]); ++ } ++ pend &= ~(1 << tcu2_pend); ++ } ++} ++ ++static int __init setup_tcu_irq(struct ingenic_tcu *tcu) ++{ ++ irq_set_chip_and_handler(tcu->irq_tcu0, &tcu_irq_chip, handle_level_irq); ++ irq_set_chip_and_handler(tcu->irq_tcu1, &tcu_irq_chip, handle_level_irq); ++ ++ tcu->irq_domain = irq_domain_add_linear(tcu->np, tcu->channel_irq_num, &tcu2_irq_domain_ops, (void *)tcu); ++ if(!tcu->irq_domain) { ++ pr_err("Failed to add tcu irq into irq domain\n"); ++ return -ENOMEM; ++ } ++ irq_set_chained_handler_and_data(tcu->irq_tcu2, tcu_irq_demux, tcu); ++ ++ return 0; ++} ++ ++static int init_mfd_cells(struct ingenic_tcu *tcu, struct mfd_cell *cells) ++{ ++ struct device_node *child; ++ int i = 0, ret; ++ ++ for_each_child_of_node(tcu->np, child) { ++ const char *tmp = NULL; ++ int id; ++ struct ingenic_tcu_chn *chn = &tcu->tcu_chn[i]; ++ ++ ret = of_property_read_u32(child, "ingenic,channel-info", &chn->chn_info); ++ if (ret < 0) { ++ dev_err(tcu->dev, "Cannot get ingenic,channel-info\n"); ++ return -ENOENT; ++ } ++ ret = of_property_read_string(child, "compatible", &tmp); ++ if (ret < 0) { ++ dev_err(tcu->dev, "Cannot get compatible string\n"); ++ return -ENOENT; ++ } ++ ++ id = chn->cib.id; ++ tcu->idmap[id] = i; ++ tcu->channel_mask |= BIT(id); ++ chn->enable = tcu_start_counter; ++ chn->disable = tcu_stop_counter; ++ cells[i].id = id; ++ cells[i].name = tmp; ++ cells[i].pdata_size = sizeof(struct ingenic_tcu_chn); ++ cells[i].of_compatible = tmp; ++ cells[i].platform_data = chn; ++ cells[i].enable = tcu_clock_enable; ++ cells[i].disable = tcu_clock_disable; ++ i ++; ++ } ++ /* for(i = 0; i < tcu->channel_num; i++) { */ ++ /* printk("id = %d, name = %s, of_com = %s\n", cells[i].id, cells[i].name, cells[i].of_compatible); */ ++ /* } */ ++ return 0; ++} ++static int ingenic_tcu_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ int ret = 0; ++ ++ tcu = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_tcu), GFP_KERNEL); ++ if (!tcu) { ++ dev_err(&pdev->dev, "Failed to allocate driver structure\n"); ++ return -ENOMEM; ++ } ++ ++ tcu->np = pdev->dev.of_node; ++ tcu->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); ++ return -ENOENT; ++ } ++ tcu->base = ioremap(res->start, resource_size(res)); ++ if (tcu->base == NULL) { ++ dev_err(&pdev->dev, "Cannot map IO\n"); ++ return -ENXIO; ++ } ++ tcu->irq_tcu0 = of_irq_get_byname(tcu->np, "tcu_int0"); ++ if (tcu->irq_tcu0 < 0) { ++ dev_err(tcu->dev, "int0:unable to get IRQ from DT, %d\n", tcu->irq_tcu0); ++ return -ENXIO; ++ } ++ tcu->irq_tcu1 = of_irq_get_byname(tcu->np, "tcu_int1"); ++ if (tcu->irq_tcu1 < 0) { ++ dev_err(tcu->dev, "int1:unable to get IRQ from DT, %d\n", tcu->irq_tcu1); ++ return -ENXIO; ++ } ++ tcu->irq_tcu2 = of_irq_get_byname(tcu->np, "tcu_int2"); ++ if (tcu->irq_tcu2 < 0) { ++ dev_err(tcu->dev, "int2:unable to get IRQ from DT, %d\n", tcu->irq_tcu2); ++ return -ENXIO; ++ } ++ ++ tcu->clk = devm_clk_get(tcu->dev,"gate_tcu"); ++ clk_prepare_enable(tcu->clk); ++ ++ tcu->channel_num = of_get_child_count(tcu->np); ++ tcu->tcu_chn = devm_kzalloc(tcu->dev, sizeof(struct ingenic_tcu_chn) * tcu->channel_num, ++ GFP_KERNEL); ++ if (!tcu->tcu_chn) { ++ dev_err(tcu->dev, "Failed to allocate driver structure tcu_channel\n"); ++ return -ENOMEM; ++ } ++ tcu->channel_irq_num = (tcu->channel_num - 1) * 2; ++ ++ setup_tcu_irq(tcu); ++ ++ spin_lock_init(&tcu->lock); ++ platform_set_drvdata(pdev, tcu); ++ ++ tcu->tcu_cells = devm_kzalloc(tcu->dev, sizeof(struct mfd_cell) * tcu->channel_num, ++ GFP_KERNEL); ++ if (!tcu->tcu_cells) { ++ dev_err(tcu->dev, "Failed to allocate driver structure cells\n"); ++ return -ENOMEM; ++ } ++ ++ init_mfd_cells(tcu, tcu->tcu_cells); ++ ++ ret = mfd_add_devices(&pdev->dev, 0, tcu->tcu_cells, ++ tcu->channel_num, res, tcu->irq_tcu0, NULL); ++ ++ dev_info(&pdev->dev, "Ingenic TCU driver register completed ret = %d\n", ret); ++ ++ return 0; ++} ++ ++static int ingenic_tcu_remove(struct platform_device *pdev) ++{ ++ struct ingenic_tcu *tcu = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(tcu->clk); ++ ++ mfd_remove_devices(&pdev->dev); ++ ++ irq_set_handler_data(tcu->irq_tcu0, NULL); ++ irq_set_chained_handler(tcu->irq_tcu0, NULL); ++ ++ irq_set_handler_data(tcu->irq_tcu1, NULL); ++ irq_set_chained_handler(tcu->irq_tcu1, NULL); ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ devm_kfree(&pdev->dev, tcu); ++ ++ return 0; ++} ++ ++static const struct of_device_id tcu_match[] = { ++ { .compatible = "ingenic,x2500-tcu", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, tcu_match); ++ ++static struct platform_driver ingenic_tcu_driver = { ++ .probe = ingenic_tcu_probe, ++ .remove = ingenic_tcu_remove, ++ .driver = { ++ .name = "ingenic-tcu_v1", ++ .of_match_table = tcu_match, ++ }, ++}; ++ ++module_platform_driver(ingenic_tcu_driver); ++ ++MODULE_DESCRIPTION("ingenic SoC TCU driver"); ++MODULE_AUTHOR("bo.liu "); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ingenic-tcu"); +diff --git a/module_drivers/drivers/mfd/ingenic_adc_aux.c b/module_drivers/drivers/mfd/ingenic_adc_aux.c +new file mode 100644 +index 000000000..dcb56467b +--- /dev/null ++++ b/module_drivers/drivers/mfd/ingenic_adc_aux.c +@@ -0,0 +1,362 @@ ++/** ++ * drivers/mfd/ingenic-adc-aux.c ++ * ++ * aux1 aux2 channels voltage sample interface for Ingenic SoC ++ * ++ * Copyright(C)2012 Ingenic Semiconductor Co., LTD. ++ * http://www.ingenic.cn ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /*for vfree*/ ++#include ++ ++#include ++ ++#ifdef CONFIG_SADC_AUX_VERF_3V3 ++static unsigned int VREF_ADC = 3300; ++#else ++static unsigned int VREF_ADC = 1800; ++#endif ++ ++#ifdef CONFIG_SADC_AUX_12BIT ++#define AUXCONST 4096 ++#define AUX_VOLT_LOW 0xfff ++#define AUX_VOLT_HIGH 0xfff0000 ++#else ++#define AUXCONST 1024 ++#define AUX_VOLT_LOW 0x3ff ++#define AUX_VOLT_HIGH 0x3ff0000 ++#endif ++ ++#define ADC_MAGIC_NUMBER 'A' ++#define ADC_ENABLE _IO(ADC_MAGIC_NUMBER, 11) ++#define ADC_DISABLE _IO(ADC_MAGIC_NUMBER, 22) ++#define ADC_SET_VREF _IOW(ADC_MAGIC_NUMBER, 33, unsigned int) ++ ++#ifndef BITS_H2L ++#define BITS_H2L(msb, lsb) ((0xFFFFFFFF >> (32-((msb)-(lsb)+1))) << (lsb)) ++#endif ++ ++/** ++ * * INIT_COMPLETION - reinitialize a completion structure ++ * * @x: completion structure to be reinitialized ++ * * ++ * * This macro should be used to reinitialize a completion structure so it can ++ * * be reused. This is especially important after complete_all() is used. ++ * */ ++#define INIT_COMPLETION(x) ((x).done = 0) ++ ++ ++struct ingenic_adc_aux { ++ struct platform_device *pdev; ++ ++ struct resource *mem; ++ void __iomem *base; ++ ++ int irq; ++ ++ const struct mfd_cell *cell; ++ ++ unsigned int voltage; ++ ++ struct completion read_completion; ++ ++ struct miscdevice mdev; ++}; ++ ++ ++enum aux_ch { ++ SADC_AUX0, ++ SADC_AUX1, ++ SADC_AUX2, ++ SADC_AUX3, ++ SADC_AUX4, ++ SADC_AUX5, ++}; ++extern int ingenic_adc_set_config(struct device *dev, uint32_t mask, uint32_t val); ++ ++static irqreturn_t ingenic_ingenic_adc_aux_irq_handler(int irq, void *devid) ++{ ++ struct ingenic_adc_aux *ingenic_adc_aux = (struct ingenic_adc_aux *)devid; ++ ++ complete(&ingenic_adc_aux->read_completion); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ingenic_adc_aux_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ //struct ingenic_adc_aux *adc_aux = platform_get_drvdata(pdev); ++ //adc_aux->cell->disable(pdev); ++ return 0; ++} ++ ++static int ingenic_adc_aux_resume(struct platform_device *pdev) ++{ ++ //struct ingenic_adc_aux *adc_aux = platform_get_drvdata(pdev); ++ //adc_aux->cell->enable(pdev); ++ return 0; ++} ++ ++int ingenic_adc_aux_sample_volt(enum aux_ch channels,struct ingenic_adc_aux *ingenic_adc_aux) ++{ ++ unsigned long tmp; ++ unsigned int sadc_volt = 0; ++ ++ if (!ingenic_adc_aux) { ++ printk("ingenic_adc_aux is null ! return\n"); ++ return -EINVAL; ++ } ++ ++ INIT_COMPLETION(ingenic_adc_aux->read_completion); ++ ++ ingenic_adc_aux->cell->enable(ingenic_adc_aux->pdev); ++ enable_irq(ingenic_adc_aux->irq); ++ ++restart: ++ tmp = wait_for_completion_interruptible_timeout(&ingenic_adc_aux->read_completion, HZ); ++ if (tmp > 0) { ++ if( (channels == 0) || (channels ==2 ) ) ++ sadc_volt = readl(ingenic_adc_aux->base) & AUX_VOLT_LOW; ++ else ++ sadc_volt = (readl(ingenic_adc_aux->base - 2) & AUX_VOLT_HIGH) >> 16; ++ } else if(tmp == -ERESTARTSYS){ ++ goto restart; ++ } ++ else { ++ sadc_volt = tmp ? tmp : -ETIMEDOUT; ++ } ++ ++ if (sadc_volt < 0) { ++ printk("ingenic_adc_aux read value error!!\n"); ++ disable_irq(ingenic_adc_aux->irq); ++ ingenic_adc_aux->cell->disable(ingenic_adc_aux->pdev); ++ return -EIO; ++ } ++ ++ disable_irq(ingenic_adc_aux->irq); ++ ingenic_adc_aux->cell->disable(ingenic_adc_aux->pdev); ++ ++ sadc_volt = sadc_volt * VREF_ADC / AUXCONST; ++ ++ return sadc_volt; ++} ++ ++ ++int ingenic_adc_aux_open(struct inode *inode, struct file *filp) ++{ ++ //struct miscdevice *dev = filp->private_data; ++ //struct ingenic_adc_aux *axu = container_of(dev, struct ingenic_adc_aux, mdev); ++ return 0; ++} ++ ++int ingenic_adc_aux_release(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} ++ ++ssize_t ingenic_adc_aux_read(struct file *filp, char *buf, size_t len, loff_t *off) ++{ ++ unsigned int sadc_val = 0; ++ struct miscdevice *dev = filp->private_data; ++ struct ingenic_adc_aux *aux = container_of(dev, struct ingenic_adc_aux, mdev); ++ ++ sadc_val = ingenic_adc_aux_sample_volt(aux->pdev->id,aux); ++ if (sadc_val < 0) { ++ printk("ingenic_adc_aux read value error !!\n"); ++ return -EINVAL; ++ } ++ ++ if(copy_to_user(buf, &sadc_val, sizeof(int))) { ++ return -EFAULT; ++ } ++ ++ return sizeof(int); ++} ++ ++static long ingenic_adc_aux_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ struct miscdevice *dev = filp->private_data; ++ struct ingenic_adc_aux *adc_aux = container_of(dev, struct ingenic_adc_aux, mdev); ++ ++ if(_IOC_TYPE(cmd) == ADC_MAGIC_NUMBER) { ++ switch (cmd) { ++ case ADC_ENABLE: ++ ret = adc_aux->cell->enable(adc_aux->pdev); ++ break; ++ case ADC_DISABLE: ++ ret = adc_aux->cell->disable(adc_aux->pdev); ++ break; ++ case ADC_SET_VREF: ++ VREF_ADC = *(unsigned int *)arg; ++ printk("VREF_ADC=%d\n",VREF_ADC); ++ break; ++ default: ++ ret = -1; ++ printk("%s:unsupported ioctl cmd\n",__func__); ++ } ++ } ++ ++ ++ return ret; ++} ++ ++struct file_operations ingenic_adc_aux_fops= { ++ .owner= THIS_MODULE, ++ .open= ingenic_adc_aux_open, ++ .release= ingenic_adc_aux_release, ++ .read= ingenic_adc_aux_read, ++ .unlocked_ioctl= ingenic_adc_aux_ioctl, ++}; ++ ++extern int key_fun_init(struct ingenic_adc_aux *ingenic_adc_aux); ++static int ingenic_adc_aux_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ char aux_name[20]; ++ ++ struct ingenic_adc_aux *ingenic_adc_aux = NULL; ++ ++ ingenic_adc_aux = kzalloc(sizeof(*ingenic_adc_aux), GFP_KERNEL); ++ if (!ingenic_adc_aux) { ++ dev_err(&pdev->dev, "Failed to allocate driver structre\n"); ++ return -ENOMEM; ++ } ++ ++ ingenic_adc_aux->cell = mfd_get_cell(pdev); ++ if (!ingenic_adc_aux->cell) { ++ ret = -ENOENT; ++ dev_err(&pdev->dev, "Failed to get mfd cell for ingenic_adc_aux!\n"); ++ goto err_free; ++ } ++ ++ ingenic_adc_aux->irq = platform_get_irq(pdev, 0); ++ if (ingenic_adc_aux->irq < 0) { ++ ret = ingenic_adc_aux->irq; ++ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); ++ goto err_free; ++ } ++ ++ ingenic_adc_aux->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!ingenic_adc_aux->mem) { ++ ret = -ENOENT; ++ dev_err(&pdev->dev, "Failed to get platform mmio resource\n"); ++ goto err_free; ++ } ++ ++ ingenic_adc_aux->mem = request_mem_region(ingenic_adc_aux->mem->start, ++ resource_size(ingenic_adc_aux->mem), pdev->name); ++ if (!ingenic_adc_aux->mem) { ++ ret = -EBUSY; ++ dev_err(&pdev->dev, "Failed to request mmio memory region\n"); ++ goto err_free; ++ } ++ ++ ingenic_adc_aux->base = ioremap(ingenic_adc_aux->mem->start,resource_size(ingenic_adc_aux->mem)); ++ if (!ingenic_adc_aux->base) { ++ ret = -EBUSY; ++ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); ++ goto err_free; ++ } ++ ++ ingenic_adc_aux->pdev = pdev; ++ ingenic_adc_aux->mdev.minor = MISC_DYNAMIC_MINOR; ++ sprintf(aux_name, "ingenic_adc_aux_%d", pdev->id); ++ ingenic_adc_aux->mdev.name = aux_name; ++ ingenic_adc_aux->mdev.fops = &ingenic_adc_aux_fops; ++ ++ ret = misc_register(&ingenic_adc_aux->mdev); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "misc_register failed\n"); ++ goto err_free; ++ } ++ ++ init_completion(&ingenic_adc_aux->read_completion); ++ ++ ret = request_irq(ingenic_adc_aux->irq, ingenic_ingenic_adc_aux_irq_handler, 0, pdev->name, ingenic_adc_aux); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to request irq %d\n", ret); ++ goto err_free; ++ } ++ ++ disable_irq(ingenic_adc_aux->irq); ++ ++ platform_set_drvdata(pdev, ingenic_adc_aux); ++ ++#ifdef CONFIG_ADC_BASED_KEY_FUN ++ if (!strncmp(aux_name, "ingenic_adc_aux_1", strlen("ingenic_adc_aux_1"))) ++ key_fun_init(ingenic_adc_aux); ++#endif ++ ++ printk("ingenic sadc aux%d probe success\n", pdev->id); ++ return 0; ++ ++err_free : ++ kfree(ingenic_adc_aux); ++ return ret; ++ ++} ++ ++static int ingenic_adc_aux_remove(struct platform_device *pdev) ++{ ++ struct ingenic_adc_aux *ingenic_adc_aux = platform_get_drvdata(pdev); ++ ++ misc_deregister(&ingenic_adc_aux->mdev); ++ free_irq(ingenic_adc_aux->irq, ingenic_adc_aux); ++ iounmap(ingenic_adc_aux->base); ++ release_mem_region(ingenic_adc_aux->mem->start,resource_size(ingenic_adc_aux->mem)); ++ kfree(ingenic_adc_aux); ++ ++ return 0; ++} ++ ++static struct platform_driver ingenic_adc_aux_driver = { ++ .probe = ingenic_adc_aux_probe, ++ .remove = ingenic_adc_aux_remove, ++ .driver = { ++ .name = "ingenic-aux", ++ .owner = THIS_MODULE, ++ }, ++ .suspend = ingenic_adc_aux_suspend, ++ .resume = ingenic_adc_aux_resume, ++}; ++ ++static int __init ingenic_adc_aux_init(void) ++{ ++ platform_driver_register(&ingenic_adc_aux_driver); ++ ++ return 0; ++} ++ ++static void __exit ingenic_adc_aux_exit(void) ++{ ++ platform_driver_unregister(&ingenic_adc_aux_driver); ++} ++ ++module_init(ingenic_adc_aux_init); ++module_exit(ingenic_adc_aux_exit); ++ ++MODULE_ALIAS("platform: ingenic ingenic_adc_aux"); ++MODULE_AUTHOR("Guo Xu"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ingenic adc aux sample driver"); +diff --git a/module_drivers/drivers/mfd/ingenic_adc_v13.c b/module_drivers/drivers/mfd/ingenic_adc_v13.c +new file mode 100644 +index 000000000..84d080927 +--- /dev/null ++++ b/module_drivers/drivers/mfd/ingenic_adc_v13.c +@@ -0,0 +1,517 @@ ++/* drivers/mfd/ingenic_adc.c ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ * http://www.ingenic.com ++ * Sun Jiwei ++ * ingenic4780 SOC ADC device core ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the 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 driver is designed to control the usage of the ADC block between ++ * the touchscreen and any other drivers that may need to use it, such as ++ * the hwmon driver. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define INGENIC_REG_ADC_ENABLE 0x00 ++#define INGENIC_REG_ADC_CTRL 0x08 ++#define INGENIC_REG_ADC_STATUS 0x0c ++ ++#define INGENIC_REG_ADC_AUX_BASE 0x10 ++#define INGENIC_REG_ADC_CLKDIV 0x20 ++/* ++ *the following registeres is for touchscreen ++ */ ++#define CLKDIV 120 ++#define CLKDIV_US 2 ++#define CLKDIV_MS 200 ++ ++#define INGENIC_ADC_IRQ_NUM 8 ++ ++static const struct of_device_id sadc_match[]; ++ ++struct ingenic_adc_priv { ++ unsigned int aux_channels; ++}; ++ ++struct ingenic_adc { ++ struct resource *mem; ++ void __iomem *base; ++ ++ int irq; ++ int irq_base; ++ struct irq_domain *irq_domain; ++ struct device_node *np; ++ struct resource *aux_res_ptr; ++ struct mfd_cell *adc_cells; ++ ++ struct clk *clk; ++ atomic_t clk_ref; ++ ++ spinlock_t lock; ++ const struct ingenic_adc_priv *priv;/*soc data*/ ++}; ++ ++static inline void ingenic_adc_irq_set_masked(struct ingenic_adc *adc, int irq, ++ bool masked) ++{ ++ unsigned long flags; ++ uint8_t val; ++ ++ irq -= adc->irq_base; ++ ++ spin_lock_irqsave(&adc->lock, flags); ++ ++ val = readb(adc->base + INGENIC_REG_ADC_CTRL); ++ if (masked) { ++ val |= BIT(irq); ++ } ++ else { ++ val &= ~BIT(irq); ++ } ++ writeb(val, adc->base + INGENIC_REG_ADC_CTRL); ++ ++ spin_unlock_irqrestore(&adc->lock, flags); ++} ++ ++static void ingenic_adc_irq_mask(struct irq_data *data) ++{ ++ struct ingenic_adc *adc = irq_data_get_irq_chip_data(data); ++ ingenic_adc_irq_set_masked(adc, data->irq, true); ++} ++ ++static void ingenic_adc_irq_unmask(struct irq_data *data) ++{ ++ struct ingenic_adc *adc = irq_data_get_irq_chip_data(data); ++ ingenic_adc_irq_set_masked(adc, data->irq, false); ++} ++ ++static void ingenic_adc_irq_ack(struct irq_data *data) ++{ ++ struct ingenic_adc *adc = irq_data_get_irq_chip_data(data); ++ unsigned int irq = data->irq - adc->irq_base; ++ writeb(BIT(irq), adc->base + INGENIC_REG_ADC_STATUS); ++} ++ ++static struct irq_chip ingenic_adc_irq_chip = { ++ .name = "ingenic-adc", ++ .irq_mask = ingenic_adc_irq_mask, ++ .irq_disable = ingenic_adc_irq_mask, ++ .irq_unmask = ingenic_adc_irq_unmask, ++ .irq_ack = ingenic_adc_irq_ack, ++}; ++ ++static void ingenic_adc_irq_demux(struct irq_desc *desc) ++{ ++ struct ingenic_adc *adc = irq_desc_get_handler_data(desc); ++ uint8_t status; ++ unsigned int i; ++ ++ status = readb(adc->base + INGENIC_REG_ADC_STATUS); ++ ++ for (i = 0; i < adc->priv->aux_channels; i++) { ++ if (status & BIT(i)) { ++ generic_handle_irq(irq_find_mapping(adc->irq_domain, i)); ++ } ++ } ++} ++ ++ ++static inline void ingenic_adc_enable(struct ingenic_adc *adc) ++{ ++ uint16_t val; ++ ++ if (atomic_inc_return(&adc->clk_ref) == 1) { ++ val = readw(adc->base + INGENIC_REG_ADC_ENABLE); ++ val &= ~BIT(15); ++ writew(val, adc->base + INGENIC_REG_ADC_ENABLE); ++ msleep(5); ++ } ++} ++ ++static inline void ingenic_adc_disable(struct ingenic_adc *adc) ++{ ++ uint16_t val; ++ ++ if (atomic_dec_return(&adc->clk_ref) == 0) { ++ val = readw(adc->base + INGENIC_REG_ADC_ENABLE); ++ val |= BIT(15); ++ writew(val, adc->base + INGENIC_REG_ADC_ENABLE); ++ } ++} ++ ++static inline void ingenic_adc_set_enabled(struct ingenic_adc *adc, int engine, ++ bool enabled) ++{ ++ unsigned long flags; ++ uint16_t val; ++ ++ spin_lock_irqsave(&adc->lock, flags); ++ ++ val = readw(adc->base + INGENIC_REG_ADC_ENABLE); ++ if (enabled) { ++ val |= BIT(engine); ++ } ++ else { ++ val &= ~BIT(engine); ++ } ++ writew(val, adc->base + INGENIC_REG_ADC_ENABLE); ++ ++ spin_unlock_irqrestore(&adc->lock, flags); ++} ++ ++static int ingenic_adc_cell_enable(struct platform_device *pdev) ++{ ++ struct ingenic_adc *adc = dev_get_drvdata(pdev->dev.parent); ++ ++ ingenic_adc_enable(adc); ++ ingenic_adc_set_enabled(adc, pdev->id, true); ++ ++ return 0; ++} ++ ++static int ingenic_adc_cell_disable(struct platform_device *pdev) ++{ ++ struct ingenic_adc *adc = dev_get_drvdata(pdev->dev.parent); ++ ++ ingenic_adc_set_enabled(adc, pdev->id, false); ++ ingenic_adc_disable(adc); ++ ++ return 0; ++} ++ ++ ++int adc_write_reg(struct device *dev ,uint8_t addr_offset,uint32_t mask,uint32_t val) ++{ ++ struct ingenic_adc *adc = dev_get_drvdata(dev); ++ unsigned long flags; ++ uint32_t value; ++ if(!adc) ++ return -ENODEV; ++ spin_lock_irqsave(&adc->lock,flags); ++ ++ value = readl(adc->base + addr_offset); ++ value &= ~mask; ++ value |= val; ++ writel(value,adc->base + addr_offset); ++ spin_unlock_irqrestore(&adc->lock,flags); ++ return 0; ++} ++uint32_t adc_read_reg(struct device *dev,uint8_t addr_offset) ++{ ++ struct ingenic_adc *adc = dev_get_drvdata(dev); ++ unsigned long flags; ++ uint32_t ret; ++ if(!adc) ++ return -ENODEV; ++ spin_lock_irqsave(&adc->lock,flags); ++ ret = readl(adc->base + addr_offset); ++ spin_unlock_irqrestore(&adc->lock,flags); ++ return ret; ++} ++ ++ ++static void ingenic_adc_clk_div(struct ingenic_adc *adc, const unsigned char clkdiv, ++ const unsigned char clkdiv_us, const unsigned short clkdiv_ms) ++{ ++ unsigned int val; ++ ++ val = clkdiv | (clkdiv_us << 8) | (clkdiv_ms << 16); ++ writel(val, adc->base + INGENIC_REG_ADC_CLKDIV); ++} ++ ++static int ingenic_alloc_aux_resources(struct ingenic_adc *adc) ++{ ++ struct resource *r = NULL; ++ unsigned int i = 0; ++ ++ adc->aux_res_ptr = kzalloc(sizeof(struct resource) * adc->priv->aux_channels * 2, GFP_KERNEL); ++ if(!adc->aux_res_ptr) { ++ return -ENOMEM; ++ } ++ ++ for(i = 0; i < adc->priv->aux_channels; i++) { ++ r = &adc->aux_res_ptr[i * 2]; ++ r[0].start = i; ++ r[0].flags = IORESOURCE_IRQ; ++ r[1].start = INGENIC_REG_ADC_AUX_BASE + 2 * i; ++ r[1].end = INGENIC_REG_ADC_AUX_BASE + 2 * i + 1; ++ r[1].flags = IORESOURCE_MEM; ++ } ++ return 0; ++} ++ ++static int ingenic_alloc_adc_cells(struct ingenic_adc *adc) ++{ ++ unsigned int i; ++ ++ adc->adc_cells = kzalloc(sizeof(struct mfd_cell) * adc->priv->aux_channels, GFP_KERNEL); ++ if(!adc->adc_cells) { ++ return -ENOMEM; ++ } ++ ++ for(i = 0; i < adc->priv->aux_channels; i++) { ++ adc->adc_cells[i].id = i; ++ adc->adc_cells[i].name = "ingenic-aux"; ++ adc->adc_cells[i].num_resources = 2; ++ adc->adc_cells[i].resources = &adc->aux_res_ptr[i * 2]; ++ adc->adc_cells[i].enable = ingenic_adc_cell_enable; ++ adc->adc_cells[i].disable = ingenic_adc_cell_disable; ++ } ++ return 0; ++} ++ ++static int adc_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) ++{ ++ struct ingenic_adc *adc = d->host_data; ++ if(hw == 0) { ++ adc->irq_base = virq; ++ } ++ irq_set_chip_data(virq, adc); ++ irq_set_chip_and_handler(virq, &ingenic_adc_irq_chip, handle_level_irq); ++ return 0; ++} ++ ++static const struct irq_domain_ops ingenic_adc_irq_domain_ops = { ++ .map = adc_irq_domain_map, ++ .xlate = irq_domain_xlate_onetwocell, ++}; ++ ++static int setup_adc_irq(struct ingenic_adc *adc, struct device_node *np) ++{ ++ int i, ret; ++ ++ adc->irq = irq_of_parse_and_map(np, 0); ++ if (!adc->irq) ++ return -EINVAL; ++ ++ adc->irq_domain = irq_domain_add_linear(np, adc->priv->aux_channels, &ingenic_adc_irq_domain_ops, (void *)adc); ++ if (!adc->irq_domain) ++ return -ENOMEM; ++ ++ for(i = 0; i < adc->priv->aux_channels; i++) { ++ ret = irq_create_mapping(adc->irq_domain, i); ++ if(ret < 0) { ++ return -1; ++ } ++ } ++ irq_set_handler_data(adc->irq, adc); ++ irq_set_chained_handler(adc->irq, ingenic_adc_irq_demux); ++ ++ return 0; ++} ++ ++ ++static int ingenic_adc_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct ingenic_adc *adc; ++ struct device_node *np; ++ struct resource *mem_base; ++ const struct of_device_id *match; ++ unsigned char clkdiv, clkdiv_us; ++ unsigned short clkdiv_ms; ++ ++ np = pdev->dev.of_node; ++ ++ adc = kmalloc(sizeof(*adc), GFP_KERNEL); ++ if (!adc) { ++ dev_err(&pdev->dev, "Failed to allocate driver structre\n"); ++ return -ENOMEM; ++ } ++ ++ match = of_match_node(sadc_match, pdev->dev.of_node); ++ if (!match) ++ return -ENODEV; ++ ++ adc->priv = match->data; ++ ++ adc->irq = platform_get_irq(pdev, 0); ++ if (adc->irq < 0) { ++ ret = adc->irq; ++ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); ++ goto err_free; ++ } ++ ++ mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!mem_base) { ++ ret = -ENOENT; ++ dev_err(&pdev->dev, "Failed to get platform mmio resource"); ++ goto err_free; ++ } ++ ++ adc->mem = request_mem_region(mem_base->start, INGENIC_REG_ADC_STATUS, pdev->name); ++ if (!adc->mem) { ++ ret = -EBUSY; ++ dev_err(&pdev->dev, "Failed to request mmio memory region\n"); ++ goto err_free; ++ } ++ ++ adc->base = ioremap(adc->mem->start, resource_size(adc->mem)); ++ if (!adc->base) { ++ ret = -EBUSY; ++ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); ++ goto err_release_mem_region; ++ } ++ ++ adc->clk = clk_get(&pdev->dev, "gate_sadc"); ++ if (IS_ERR(adc->clk)) { ++ ret = PTR_ERR(adc->clk); ++ dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); ++ goto err_iounmap; ++ } ++ ++ ret = ingenic_alloc_aux_resources(adc); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to allocate aux resources: %d\n", ret); ++ goto err_free; ++ } ++ ++ ret = ingenic_alloc_adc_cells(adc); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to allocate adc cells: %d\n", ret); ++ goto err_free; ++ } ++ ++ ret = setup_adc_irq(adc, np); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to setup adc irq: %d\n", ret); ++ goto err_free; ++ } ++ ++ spin_lock_init(&adc->lock); ++ atomic_set(&adc->clk_ref, 0); ++ ++ platform_set_drvdata(pdev, adc); ++ ++ clk_prepare_enable(adc->clk); ++ ++ writew(0x8000, adc->base + INGENIC_REG_ADC_ENABLE); ++ writew(0xffff, adc->base + INGENIC_REG_ADC_CTRL); ++ ++ clkdiv = CLKDIV - 1; ++ clkdiv_us = CLKDIV_US - 1; ++ clkdiv_ms = CLKDIV_MS - 1; ++ ++ ingenic_adc_clk_div(adc, clkdiv, clkdiv_us, clkdiv_ms); ++ ++ ret = mfd_add_devices(&pdev->dev, 0, adc->adc_cells, adc->priv->aux_channels, mem_base, adc->irq_base, NULL); ++ if (ret < 0) { ++ goto err_clk_put; ++ } ++ ++ printk("ingenic SADC driver registeres over!\n"); ++ ++ return 0; ++ ++err_clk_put: ++ clk_put(adc->clk); ++err_iounmap: ++ platform_set_drvdata(pdev, NULL); ++ iounmap(adc->base); ++err_release_mem_region: ++ release_mem_region(adc->mem->start, resource_size(adc->mem)); ++err_free: ++ kfree(adc->aux_res_ptr); ++ kfree(adc->adc_cells); ++ kfree(adc); ++ ++ return ret; ++} ++ ++static int ingenic_adc_remove(struct platform_device *pdev) ++{ ++ struct ingenic_adc *adc = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(adc->clk); ++ mfd_remove_devices(&pdev->dev); ++ ++ irq_set_handler_data(adc->irq, NULL); ++ irq_set_chained_handler(adc->irq, NULL); ++ ++ iounmap(adc->base); ++ release_mem_region(adc->mem->start, resource_size(adc->mem)); ++ ++ clk_put(adc->clk); ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ kfree(adc->aux_res_ptr); ++ kfree(adc->adc_cells); ++ kfree(adc); ++ ++ return 0; ++} ++ ++ ++static const struct ingenic_adc_priv x1600_adc_priv[] = { ++ {.aux_channels = 4,}, ++}; ++static const struct ingenic_adc_priv x2000_adc_priv[] = { ++ {.aux_channels = 6,}, ++}; ++static const struct ingenic_adc_priv x2500_adc_priv[] = { ++ {.aux_channels = 4,}, ++}; ++static const struct ingenic_adc_priv x2100_adc_priv[] = { ++ {.aux_channels = 6,}, ++}; ++static const struct ingenic_adc_priv m300_adc_priv[] = { ++ {.aux_channels = 6,}, ++}; ++ ++static const struct of_device_id sadc_match[] = { ++ { .compatible = "ingenic,x2000-sadc",.data = (void*)&x2000_adc_priv}, ++ { .compatible = "ingenic,x2500-sadc",.data = (void*)&x2500_adc_priv}, ++ { .compatible = "ingenic,x1600-sadc",.data = (void*)&x1600_adc_priv}, ++ { .compatible = "ingenic,x2100-sadc",.data = (void*)&x2100_adc_priv}, ++ { .compatible = "ingenic,m300-sadc",.data = (void*)&m300_adc_priv}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sadc_match); ++ ++struct platform_driver ingenic_adc_driver = { ++ .probe = ingenic_adc_probe, ++ .remove = ingenic_adc_remove, ++ .driver = { ++ .name = "ingenic-adc", ++ .owner = THIS_MODULE, ++ .of_match_table = sadc_match, ++ }, ++}; ++ ++static int __init ingenic_adc_init(void) ++{ ++ return platform_driver_register(&ingenic_adc_driver); ++} ++module_init(ingenic_adc_init); ++ ++static void __exit ingenic_adc_exit(void) ++{ ++ platform_driver_unregister(&ingenic_adc_driver); ++} ++module_exit(ingenic_adc_exit); ++ ++MODULE_DESCRIPTION("ingenic SOC ADC driver"); ++MODULE_AUTHOR("Guo Xu"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:T15-adc"); +diff --git a/module_drivers/drivers/mfd/ricoh619-irq.c b/module_drivers/drivers/mfd/ricoh619-irq.c +new file mode 100644 +index 000000000..f29a72b9b +--- /dev/null ++++ b/module_drivers/drivers/mfd/ricoh619-irq.c +@@ -0,0 +1,565 @@ ++/* ++ * Interrupt driver for RICOH619 power management chip. ++ * ++ * Copyright (C) 2020 Ingenic Semiconductor Co., Ltd. ++ * Author: cljiang ++ * ++ * Based on code ++ * drivers/mfd/ricoh619-irq.c ++ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. ++ * Author: Laxman dewangan ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 . ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum int_type { ++ SYS_INT = 0x1, ++ DCDC_INT = 0x2, ++ RTC_INT = 0x4, ++ ADC_INT = 0x8, ++ GPIO_INT = 0x10, ++ CHG_INT = 0x40, ++}; ++ ++struct ricoh619_irq_st { ++ struct device *dev; ++ struct regmap *regmap; ++ int gpio_base; ++ struct gpio_chip gpio_chip; ++ int irq_base; ++ /* struct irq_chip irq_chip; */ ++ int chip_irq; ++ struct mutex irq_lock; ++ unsigned long group_irq_en[MAX_MAIN_INTERRUPT]; ++ ++ /* For main interrupt bits in INTC */ ++ u8 intc_inten_cache; ++ u8 intc_inten_reg; ++ ++ /* For group interrupt bits and address */ ++ u8 irq_en_cache[MAX_INTERRUPT_MASKS]; ++ u8 irq_en_reg[MAX_INTERRUPT_MASKS]; ++ ++ /* For gpio edge */ ++ u8 gpedge_cache[MAX_GPEDGE_REG]; ++ u8 gpedge_reg[MAX_GPEDGE_REG]; ++ ++ int bank_num; ++}; ++ ++struct ricoh619_irq_data { ++ u8 int_type; ++ u8 master_bit; ++ u8 int_en_bit; ++ u8 mask_reg_index; ++ int grp_index; ++}; ++ ++#define RICOH619_IRQ(_int_type, _master_bit, _grp_index, _int_bit, _mask_ind) \ ++ { \ ++ .int_type = _int_type, \ ++ .master_bit = _master_bit, \ ++ .grp_index = _grp_index, \ ++ .int_en_bit = _int_bit, \ ++ .mask_reg_index = _mask_ind, \ ++ } ++static struct ricoh619_irq_st *ricoh619 = NULL; ++ ++static const struct ricoh619_irq_data ricoh619_irqs[RICOH619_NR_IRQS] = { ++ [RICOH619_IRQ_POWER_ON] = RICOH619_IRQ(SYS_INT, 0, 0, 0, 0), ++ [RICOH619_IRQ_EXTIN] = RICOH619_IRQ(SYS_INT, 0, 1, 1, 0), ++ [RICOH619_IRQ_PRE_VINDT] = RICOH619_IRQ(SYS_INT, 0, 2, 2, 0), ++ [RICOH619_IRQ_PREOT] = RICOH619_IRQ(SYS_INT, 0, 3, 3, 0), ++ [RICOH619_IRQ_POWER_OFF] = RICOH619_IRQ(SYS_INT, 0, 4, 4, 0), ++ [RICOH619_IRQ_NOE_OFF] = RICOH619_IRQ(SYS_INT, 0, 5, 5, 0), ++ [RICOH619_IRQ_WD] = RICOH619_IRQ(SYS_INT, 0, 6, 6, 0), ++ ++ [RICOH619_IRQ_DC1LIM] = RICOH619_IRQ(DCDC_INT, 1, 0, 0, 1), ++ [RICOH619_IRQ_DC2LIM] = RICOH619_IRQ(DCDC_INT, 1, 1, 1, 1), ++ [RICOH619_IRQ_DC3LIM] = RICOH619_IRQ(DCDC_INT, 1, 2, 2, 1), ++ [RICOH619_IRQ_DC4LIM] = RICOH619_IRQ(DCDC_INT, 1, 3, 3, 1), ++ [RICOH619_IRQ_DC5LIM] = RICOH619_IRQ(DCDC_INT, 1, 4, 4, 1), ++ ++ [RICOH619_IRQ_CTC] = RICOH619_IRQ(RTC_INT, 2, 0, 0, 2), ++ [RICOH619_IRQ_DALE] = RICOH619_IRQ(RTC_INT, 2, 1, 6, 2), ++ ++ [RICOH619_IRQ_ILIMLIR] = RICOH619_IRQ(ADC_INT, 3, 0, 0, 3), ++ [RICOH619_IRQ_VBATLIR] = RICOH619_IRQ(ADC_INT, 3, 1, 1, 3), ++ [RICOH619_IRQ_VADPLIR] = RICOH619_IRQ(ADC_INT, 3, 2, 2, 3), ++ [RICOH619_IRQ_VUSBLIR] = RICOH619_IRQ(ADC_INT, 3, 3, 3, 3), ++ [RICOH619_IRQ_VSYSLIR] = RICOH619_IRQ(ADC_INT, 3, 4, 4, 3), ++ [RICOH619_IRQ_VTHMLIR] = RICOH619_IRQ(ADC_INT, 3, 5, 5, 3), ++ [RICOH619_IRQ_AIN1LIR] = RICOH619_IRQ(ADC_INT, 3, 6, 6, 3), ++ [RICOH619_IRQ_AIN0LIR] = RICOH619_IRQ(ADC_INT, 3, 7, 7, 3), ++ ++ [RICOH619_IRQ_ILIMHIR] = RICOH619_IRQ(ADC_INT, 3, 8, 0, 4), ++ [RICOH619_IRQ_VBATHIR] = RICOH619_IRQ(ADC_INT, 3, 9, 1, 4), ++ [RICOH619_IRQ_VADPHIR] = RICOH619_IRQ(ADC_INT, 3, 10, 2, 4), ++ [RICOH619_IRQ_VUSBHIR] = RICOH619_IRQ(ADC_INT, 3, 11, 3, 4), ++ [RICOH619_IRQ_VSYSHIR] = RICOH619_IRQ(ADC_INT, 3, 12, 4, 4), ++ [RICOH619_IRQ_VTHMHIR] = RICOH619_IRQ(ADC_INT, 3, 13, 5, 4), ++ [RICOH619_IRQ_AIN1HIR] = RICOH619_IRQ(ADC_INT, 3, 14, 6, 4), ++ [RICOH619_IRQ_AIN0HIR] = RICOH619_IRQ(ADC_INT, 3, 15, 7, 4), ++ ++ [RICOH619_IRQ_ADC_ENDIR] = RICOH619_IRQ(ADC_INT, 3, 16, 0, 5), ++ ++ [RICOH619_IRQ_GPIO0] = RICOH619_IRQ(GPIO_INT, 4, 0, 0, 6), ++ [RICOH619_IRQ_GPIO1] = RICOH619_IRQ(GPIO_INT, 4, 1, 1, 6), ++ [RICOH619_IRQ_GPIO2] = RICOH619_IRQ(GPIO_INT, 4, 2, 2, 6), ++ [RICOH619_IRQ_GPIO3] = RICOH619_IRQ(GPIO_INT, 4, 3, 3, 6), ++ [RICOH619_IRQ_GPIO4] = RICOH619_IRQ(GPIO_INT, 4, 4, 4, 6), ++ ++ [RICOH619_IRQ_FVADPDETSINT] = RICOH619_IRQ(CHG_INT, 6, 0, 0, 8), ++ [RICOH619_IRQ_FVUSBDETSINT] = RICOH619_IRQ(CHG_INT, 6, 1, 1, 8), ++ [RICOH619_IRQ_FVADPLVSINT] = RICOH619_IRQ(CHG_INT, 6, 2, 2, 8), ++ [RICOH619_IRQ_FVUSBLVSINT] = RICOH619_IRQ(CHG_INT, 6, 3, 3, 8), ++ [RICOH619_IRQ_FWVADPSINT] = RICOH619_IRQ(CHG_INT, 6, 4, 4, 8), ++ [RICOH619_IRQ_FWVUSBSINT] = RICOH619_IRQ(CHG_INT, 6, 5, 5, 8), ++ ++ [RICOH619_IRQ_FONCHGINT] = RICOH619_IRQ(CHG_INT, 6, 6, 0, 9), ++ [RICOH619_IRQ_FCHGCMPINT] = RICOH619_IRQ(CHG_INT, 6, 7, 1, 9), ++ [RICOH619_IRQ_FBATOPENINT] = RICOH619_IRQ(CHG_INT, 6, 8, 2, 9), ++ [RICOH619_IRQ_FSLPMODEINT] = RICOH619_IRQ(CHG_INT, 6, 9, 3, 9), ++ [RICOH619_IRQ_FBTEMPJTA1INT] = RICOH619_IRQ(CHG_INT, 6, 10, 4, 9), ++ [RICOH619_IRQ_FBTEMPJTA2INT] = RICOH619_IRQ(CHG_INT, 6, 11, 5, 9), ++ [RICOH619_IRQ_FBTEMPJTA3INT] = RICOH619_IRQ(CHG_INT, 6, 12, 6, 9), ++ [RICOH619_IRQ_FBTEMPJTA4INT] = RICOH619_IRQ(CHG_INT, 6, 13, 7, 9), ++ ++ [RICOH619_IRQ_FCURTERMINT] = RICOH619_IRQ(CHG_INT, 6, 14, 0, 10), ++ [RICOH619_IRQ_FVOLTERMINT] = RICOH619_IRQ(CHG_INT, 6, 15, 1, 10), ++ [RICOH619_IRQ_FICRVSINT] = RICOH619_IRQ(CHG_INT, 6, 16, 2, 10), ++ [RICOH619_IRQ_FPOOR_CHGCURINT] = RICOH619_IRQ(CHG_INT, 6, 17, 3, 10), ++ [RICOH619_IRQ_FOSCFDETINT1] = RICOH619_IRQ(CHG_INT, 6, 18, 4, 10), ++ [RICOH619_IRQ_FOSCFDETINT2] = RICOH619_IRQ(CHG_INT, 6, 19, 5, 10), ++ [RICOH619_IRQ_FOSCFDETINT3] = RICOH619_IRQ(CHG_INT, 6, 20, 6, 10), ++ [RICOH619_IRQ_FOSCMDETINT] = RICOH619_IRQ(CHG_INT, 6, 21, 7, 10), ++ ++ [RICOH619_IRQ_FDIEOFFINT] = RICOH619_IRQ(CHG_INT, 6, 22, 0, 11), ++ [RICOH619_IRQ_FDIEERRINT] = RICOH619_IRQ(CHG_INT, 6, 23, 1, 11), ++ [RICOH619_IRQ_FBTEMPERRINT] = RICOH619_IRQ(CHG_INT, 6, 24, 2, 11), ++ [RICOH619_IRQ_FVBATOVINT] = RICOH619_IRQ(CHG_INT, 6, 25, 3, 11), ++ [RICOH619_IRQ_FTTIMOVINT] = RICOH619_IRQ(CHG_INT, 6, 26, 4, 11), ++ [RICOH619_IRQ_FRTIMOVINT] = RICOH619_IRQ(CHG_INT, 6, 27, 5, 11), ++ [RICOH619_IRQ_FVADPOVSINT] = RICOH619_IRQ(CHG_INT, 6, 28, 6, 11), ++ [RICOH619_IRQ_FVUSBOVSINT] = RICOH619_IRQ(CHG_INT, 6, 29, 7, 11), ++ ++ [RICOH619_IRQ_FGCDET] = RICOH619_IRQ(CHG_INT, 6, 30, 0, 12), ++ [RICOH619_IRQ_FPCDET] = RICOH619_IRQ(CHG_INT, 6, 31, 1, 12), ++ [RICOH619_IRQ_FWARN_ADP] = RICOH619_IRQ(CHG_INT, 6, 32, 3, 12), ++}; ++ ++static int gpedge_add[] = { ++ RICOH619_GPEDGE1, ++ RICOH619_GPEDGE2, ++}; ++ ++static int irq_en_add[] = { ++ RICOH619_PWRIREN, ++ RICOH619_DCIREN, ++ RICOH619_RTCCNT1, ++ RICOH619_EN_ADCIR1, ++ RICOH619_EN_ADCIR2, ++ RICOH619_EN_ADCIR3, ++ RICOH619_EN_GPIR, ++ RICOH619_EN_GPIR, ++ RICOH619_CHGCTRL_IRFMASK, ++ RICOH619_CHGSTAT_IRFMASK1, ++ RICOH619_CHGSTAT_IRFMASK2, ++ RICOH619_CHGERR_IRFMASK, ++ RICOH619_CHGEXTIF_IRFMASK, ++}; ++ ++static int irq_mon_add[] = { ++ RICOH619_PWRIRQ, /* RICOH619_INT_MON_SYS, */ ++ RICOH619_DCIRQ, /* RICOH619_INT_MON_DCDC, */ ++ RICOH619_RTCCNT2, /* RICOH619_INT_MON_RTC, */ ++ RICOH619_IR_ADC1, ++ RICOH619_IR_ADC2, ++ RICOH619_IR_ADC3, ++ RICOH619_IR_GPR, ++ RICOH619_IR_GPF, ++ RICOH619_CHGCTRL_IRR, /* RICOH619_INT_MON_CHGCTR, */ ++ RICOH619_CHGSTAT_IRR1, /* RICOH619_INT_MON_CHGSTS1, */ ++ RICOH619_CHGSTAT_IRR2, /* RICOH619_INT_MON_CHGSTS2, */ ++ RICOH619_CHGERR_IRR, /* RICOH619_INT_MON_CHGERR */ ++ RICOH619_CHGEXTIF_IRR, /* RICOH619_INT_MON_CHGEXTIF */ ++}; ++ ++static int irq_clr_add[] = { ++ RICOH619_PWRIRQ, ++ RICOH619_DCIRQ, ++ RICOH619_RTCCNT2, ++ RICOH619_IR_ADC1, ++ RICOH619_IR_ADC2, ++ RICOH619_IR_ADC3, ++ RICOH619_IR_GPR, ++ RICOH619_IR_GPF, ++ RICOH619_CHGCTRL_IRR, ++ RICOH619_CHGSTAT_IRR1, ++ RICOH619_CHGSTAT_IRR2, ++ RICOH619_CHGERR_IRR, ++ RICOH619_CHGEXTIF_IRR, ++}; ++static int main_int_type[] = { ++ SYS_INT, ++ DCDC_INT, ++ RTC_INT, ++ ADC_INT, ++ ADC_INT, ++ ADC_INT, ++ GPIO_INT, ++ GPIO_INT, ++ CHG_INT, ++ CHG_INT, ++ CHG_INT, ++ CHG_INT, ++ CHG_INT, ++}; ++ ++ ++static irqreturn_t ricoh619_irq_thread_handler(int virq, void *data) ++{ ++ struct ricoh619_irq_st *ricoh619 = data; ++ u8 int_sts[MAX_INTERRUPT_MASKS]; ++ u8 master_int; ++ int i; ++ int ret; ++ unsigned int rtc_int_sts = 0; ++ ++ /* printk("PMU: %s: irq=%d\n", __func__, irq); */ ++ /* disable_irq_nosync(irq); */ ++ /* Clear the status */ ++ for (i = 0; i < MAX_INTERRUPT_MASKS; i++) ++ int_sts[i] = 0; ++ ++ ret = ricoh61x_read(ricoh619->dev, RICOH619_INTMON, ++ &master_int); ++ //printk(KERN_DEBUG "PMU1: %s: master_int=0x%x\n", __func__, master_int); ++ if (ret < 0) { ++ dev_err(ricoh619->dev, "Error in reading reg 0x%02x " ++ "error: %d\n", RICOH619_INTMON, ret); ++ return IRQ_HANDLED; ++ } ++ ++ for (i = 0; i < MAX_INTERRUPT_MASKS; ++i) { ++ /* Even if INTC_INTMON register = 1, INT signal might not ++ * output because INTC_INTMON register indicates only interrupt ++ * facter level. ++ * So remove the following procedure ++ */ ++ if (!(master_int & main_int_type[i])) ++ continue; ++ ++ ret = ricoh61x_read(ricoh619->dev, ++ irq_mon_add[i], &int_sts[i]); ++ //printk(KERN_DEBUG "PMU2: %s: int_sts[%d]=0x%x\n", ++ // __func__, i, int_sts[i]); ++ if (ret < 0) { ++ dev_err(ricoh619->dev, "Error in reading reg 0x%02x " ++ "error: %d\n", irq_mon_add[i], ret); ++ int_sts[i] = 0; ++ continue; ++ } ++ if (!int_sts[i]) ++ continue; ++ ++ if (main_int_type[i] & RTC_INT) { ++ /* Changes status bit position ++ from RTCCNT2 to RTCCNT1 */ ++ rtc_int_sts = 0; ++ if (int_sts[i] & 0x1) ++ rtc_int_sts |= BIT(6); ++ if (int_sts[i] & 0x4) ++ rtc_int_sts |= BIT(0); ++ } ++ ++ if(irq_clr_add[i] == RICOH619_RTCCNT2) ++ { ++ int_sts[i] &= ~0x85; ++ ret = ricoh61x_write(ricoh619->dev, ++ irq_clr_add[i], int_sts[i]); ++ if (ret < 0) { ++ dev_err(ricoh619->dev, "Error in writing reg 0x%02x " ++ "error: %d\n", irq_clr_add[i], ret); ++ } ++ } ++ else ++ { ++ ret = ricoh61x_write(ricoh619->dev, ++ irq_clr_add[i], ~int_sts[i]); ++ if (ret < 0) { ++ dev_err(ricoh619->dev, "Error in writing reg 0x%02x " ++ "error: %d\n", irq_clr_add[i], ret); ++ } ++ } ++ ++ /* Mask Charger Interrupt */ ++ if (main_int_type[i] & CHG_INT) { ++ if (int_sts[i]) ++ ret = ricoh61x_write(ricoh619->dev, ++ irq_en_add[i], 0xff); ++ if (ret < 0) { ++ dev_err(ricoh619->dev, ++ "Error in write reg 0x%02x error: %d\n", ++ irq_en_add[i], ret); ++ } ++ } ++ /* Mask ADC Interrupt */ ++ if (main_int_type[i] & ADC_INT) { ++ if (int_sts[i]) ++ ret = ricoh61x_write(ricoh619->dev, ++ irq_en_add[i], 0); ++ if (ret < 0) { ++ dev_err(ricoh619->dev, ++ "Error in write reg 0x%02x error: %d\n", ++ irq_en_add[i], ret); ++ } ++ } ++ ++ if (main_int_type[i] & RTC_INT) ++ int_sts[i] = rtc_int_sts; ++ ++ } ++ ++ /* Merge gpio interrupts for rising and falling case*/ ++ int_sts[6] |= int_sts[7]; ++ ++ /* Call interrupt handler if enabled */ ++ for (i = 0; i < RICOH619_NR_IRQS; ++i) { ++ const struct ricoh619_irq_data *data = &ricoh619_irqs[i]; ++ if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) && ++ (ricoh619->group_irq_en[data->master_bit] & ++ (1 << data->grp_index))) ++ handle_nested_irq(ricoh619->irq_base + i); ++ } ++ ++ //printk(KERN_DEBUG "PMU: %s: out\n", __func__); ++ return IRQ_HANDLED; ++ ++ ++ return IRQ_HANDLED; ++} ++ ++static void ricoh619_irq_lock(struct irq_data *irq_data) ++{ ++ struct ricoh619_irq_st *ricoh619 = irq_data_get_irq_chip_data(irq_data); ++ ++ mutex_lock(&ricoh619->irq_lock); ++} ++ ++static void ricoh619_irq_unmask(struct irq_data *irq_data) ++{ ++ struct ricoh619_irq_st *ricoh619 = irq_data_get_irq_chip_data(irq_data); ++ unsigned int __irq = irq_data->irq - ricoh619->irq_base; ++ const struct ricoh619_irq_data *data = &ricoh619_irqs[__irq]; ++ ++ ricoh619->group_irq_en[data->master_bit] |= (1 << data->grp_index); ++ if (ricoh619->group_irq_en[data->master_bit]) ++ ricoh619->intc_inten_reg |= 1 << data->master_bit; ++ ++ if (data->master_bit == 6) /* if Charger */ ++ ricoh619->irq_en_reg[data->mask_reg_index] ++ &= ~(1 << data->int_en_bit); ++ else ++ ricoh619->irq_en_reg[data->mask_reg_index] ++ |= 1 << data->int_en_bit; ++} ++ ++static void ricoh619_irq_mask(struct irq_data *irq_data) ++{ ++ struct ricoh619_irq_st *ricoh619 = irq_data_get_irq_chip_data(irq_data); ++ unsigned int __irq = irq_data->irq - ricoh619->irq_base; ++ const struct ricoh619_irq_data *data = &ricoh619_irqs[__irq]; ++ ++ ricoh619->group_irq_en[data->master_bit] &= ~(1 << data->grp_index); ++ if (!ricoh619->group_irq_en[data->master_bit]) ++ ricoh619->intc_inten_reg &= ~(1 << data->master_bit); ++ ++ if (data->master_bit == 6) /* if Charger */ ++ ricoh619->irq_en_reg[data->mask_reg_index] ++ |= 1 << data->int_en_bit; ++ else ++ ricoh619->irq_en_reg[data->mask_reg_index] ++ &= ~(1 << data->int_en_bit); ++} ++ ++static void ricoh619_irq_sync_unlock(struct irq_data *irq_data) ++{ ++ struct ricoh619_irq_st *ricoh619 = irq_data_get_irq_chip_data(irq_data); ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(ricoh619->gpedge_reg); i++) { ++ if (ricoh619->gpedge_reg[i] != ricoh619->gpedge_cache[i]) { ++ if (!WARN_ON(ricoh61x_write(ricoh619->dev, ++ gpedge_add[i], ++ ricoh619->gpedge_reg[i]))) ++ ricoh619->gpedge_cache[i] = ++ ricoh619->gpedge_reg[i]; ++ } ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(ricoh619->irq_en_reg); i++) { ++ if (ricoh619->irq_en_reg[i] != ricoh619->irq_en_cache[i]) { ++ if (!WARN_ON(ricoh61x_write(ricoh619->dev, ++ irq_en_add[i], ++ ricoh619->irq_en_reg[i]))) ++ ricoh619->irq_en_cache[i] = ++ ricoh619->irq_en_reg[i]; ++ } ++ } ++ ++ if (ricoh619->intc_inten_reg != ricoh619->intc_inten_cache) { ++ if (!WARN_ON(ricoh61x_write(ricoh619->dev, ++ RICOH619_INTEN, ricoh619->intc_inten_reg))) ++ ricoh619->intc_inten_cache = ricoh619->intc_inten_reg; ++ } ++ ++ mutex_unlock(&ricoh619->irq_lock); ++} ++ ++static int ricoh619_irq_set_type(struct irq_data *irq_data, unsigned int type) ++{ ++ struct ricoh619_irq_st *ricoh619 = irq_data_get_irq_chip_data(irq_data); ++ unsigned int __irq = irq_data->irq - ricoh619->irq_base; ++ const struct ricoh619_irq_data *data = &ricoh619_irqs[__irq]; ++ int val = 0; ++ int gpedge_index; ++ int gpedge_bit_pos; ++ ++ if (data->int_type & GPIO_INT) { ++ gpedge_index = data->int_en_bit / 4; ++ gpedge_bit_pos = data->int_en_bit % 4; ++ ++ if (type & IRQ_TYPE_EDGE_FALLING) ++ val |= 0x2; ++ ++ if (type & IRQ_TYPE_EDGE_RISING) ++ val |= 0x1; ++ ++ ricoh619->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos); ++ ricoh619->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos); ++ ricoh619_irq_unmask(irq_data); ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int ricoh619_irq_set_wake(struct irq_data *irq_data, unsigned int on) ++{ ++ struct ricoh619_irq_st *ricoh619 = irq_data_get_irq_chip_data(irq_data); ++ return irq_set_irq_wake(ricoh619->chip_irq, on); /* i2c->irq */ ++} ++#else ++#define ricoh619_irq_set_wake NULL ++#endif ++ ++static struct irq_chip ricoh619_irq_chip = { ++ .name = "ricoh619", ++ .irq_mask = ricoh619_irq_mask, ++ .irq_unmask = ricoh619_irq_unmask, ++ .irq_bus_lock = ricoh619_irq_lock, ++ .irq_bus_sync_unlock = ricoh619_irq_sync_unlock, ++ .irq_set_type = ricoh619_irq_set_type, ++ .irq_set_wake = ricoh619_irq_set_wake, ++}; ++ ++ ++int ricoh619_irq_init(struct i2c_client *i2c, struct regmap *regmap) ++{ ++ int ret, i; ++ unsigned int flags; ++ unsigned int irq_gpio_num; ++ unsigned int irq_base = IRQ_RESERVED_BASE; ++ unsigned char reg_data = 0; ++ ++ ++ printk("%s: %d\n", __func__, __LINE__); ++ //i2c->irq = irq_of_parse_and_map(i2c->dev.of_node, 0); ++ irq_gpio_num = of_get_named_gpio_flags(i2c->dev.of_node, "ingenic,irq-gpio", 0, &flags); ++ if (!irq_gpio_num) ++ return 0; ++ ++ i2c->irq = gpio_to_irq(irq_gpio_num); ++ ++ ricoh619 = devm_kzalloc(&i2c->dev, sizeof(struct ricoh619_irq_st), GFP_KERNEL); ++ if (!ricoh619) ++ return -ENOMEM; ++ ++ mutex_init(&ricoh619->irq_lock); ++ ricoh619->regmap = regmap; ++ ++ regmap_write(ricoh619->regmap, RICOH619_INTEN, 0); ++ regmap_write(ricoh619->regmap, RICOH619_INTPOL, 0); ++ ++ ++ for (i = 0; i < MAX_INTERRUPT_MASKS; i++) { ++ if (irq_clr_add[i] != RICOH619_RTCCNT2) { ++ ret = ricoh61x_write(&i2c->dev, ++ irq_clr_add[i], 0); ++ if (ret < 0) ++ dev_err(&i2c->dev, "Error in writing reg 0x%02x " ++ "error: %d\n", irq_clr_add[i], ret); ++ } else { ++ ret = ricoh61x_read(&i2c->dev, ++ RICOH619_RTCCNT2, ®_data); ++ if (ret < 0) ++ dev_err(&i2c->dev, "Error in reading reg 0x%02x " ++ "error: %d\n", RICOH619_RTCCNT2, ret); ++ reg_data &= 0xf0; ++ ret = ricoh61x_write(&i2c->dev, ++ RICOH619_RTCCNT2, reg_data); ++ if (ret < 0) ++ dev_err(&i2c->dev, "Error in writing reg 0x%02x " ++ "error: %d\n", RICOH619_RTCCNT2, ret); ++ } ++ } ++ ++ ++ ++ for (i = 0; i < RICOH619_NR_IRQS; i++) { ++ int __irq = i + irq_base; ++ irq_set_chip_data(__irq, ricoh619); ++ irq_set_chip_and_handler(__irq, &ricoh619_irq_chip, ++ handle_simple_irq); ++ irq_set_nested_thread(__irq, 1); ++#ifdef CONFIG_ARM ++ set_irq_flags(__irq, IRQF_VALID); ++#endif ++ } ++ ++ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, ricoh619_irq_thread_handler, IRQ_TYPE_EDGE_FALLING|IRQF_ONESHOT, ++ i2c->name, ricoh619); ++ if (ret) { ++ dev_err(&i2c->dev, "irq request failed: %d\n", ret); ++ return ret; ++ } ++ ++ ricoh619->chip_irq = i2c->irq; ++ ricoh619->irq_base = irq_base; ++ ricoh619->dev = &i2c->dev; ++ ++ return 0; ++} ++ ++void ricoh619_irq_deinit(void) ++{ ++ regmap_write(ricoh619->regmap, RICOH619_INTEN, 0); ++ disable_irq(ricoh619->chip_irq); ++} +diff --git a/module_drivers/drivers/mfd/ricoh619.c b/module_drivers/drivers/mfd/ricoh619.c +new file mode 100644 +index 000000000..28e1a8a2d +--- /dev/null ++++ b/module_drivers/drivers/mfd/ricoh619.c +@@ -0,0 +1,727 @@ ++/* ++ * Core driver access RICOH619 power management chip. ++ * ++ * Copyright (C) 2020 Ingenic Semiconductor Co., Ltd. ++ * Author: cljiang ++ * ++ * Based on code ++ * drivers/mfd/ricoh619.c ++ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. ++ * Author: Laxman dewangan ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 . ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++typedef struct{ ++ int temp; ++ unsigned int R; ++}R_T; ++ ++static R_T sheet[] ={ ++ {-40, 188500}, ++ {-39, 178600}, ++ {-38, 169200}, ++ {-37, 160400}, ++ {-36, 152100}, ++ {-35, 144300}, ++ {-34, 136900}, ++ {-33, 130000}, ++ {-32, 123400}, ++ {-31, 117200}, ++ {-30, 111300}, ++ {-29, 105800}, ++ {-28, 100600}, ++ {-27, 95640}, ++ {-26, 90970}, ++ {-25, 86560}, ++ {-24, 82380}, ++ {-23, 78430}, ++ {-22, 74690}, ++ {-21, 71140}, ++ {-20, 67790}, ++ {-19, 64610}, ++ {-18, 61600}, ++ {-17, 58740}, ++ {-16, 56030}, ++ {-15, 53460}, ++ {-14, 51030}, ++ {-13, 48710}, ++ {-12, 46520}, ++ {-11, 44430}, ++ {-10, 42450}, ++ {-9, 40570}, ++ {-8, 38780}, ++ {-7, 37080}, ++ {-6, 35460}, ++ {-5, 33930}, ++ {-4, 32460}, ++ {-3, 31070}, ++ {-2, 29750}, ++ {-1, 28490}, ++ {0, 27280}, ++ {1, 26140}, ++ {2, 25050}, ++ {3, 24010}, ++ {4, 23020}, ++ {5, 22070}, ++ {6, 21170}, ++ {7, 20310}, ++ {8, 19490}, ++ {9, 18710}, ++ {10, 17960}, ++ {11, 17250}, ++ {12, 16570}, ++ {13, 15910}, ++ {14, 15290}, ++ {15, 14700}, ++ {16, 14130}, ++ {17, 13590}, ++ {18, 13070}, ++ {19, 12570}, ++ {20, 12090}, ++ {21, 11640}, ++ {22, 11200}, ++ {23, 10780}, ++ {24, 10380}, ++ {25, 10000}, ++ {26, 9633}, ++ {27, 9282}, ++ {28, 8945}, ++ {29, 8622}, ++ {30, 8312}, ++ {31, 8015}, ++ {32, 7730}, ++ {33, 7456}, ++ {34, 7194}, ++ {35, 6942}, ++ {36, 6700}, ++ {37, 6468}, ++ {38, 6245}, ++ {39, 6031}, ++ {40, 5826}, ++ {41, 5628}, ++ {42, 5438}, ++ {43, 5255}, ++ {44, 5080}, ++ {45, 4911}, ++ {46, 4749}, ++ {47, 4592}, ++ {48, 4442}, ++ {49, 4297}, ++ {50, 4158}, ++ {51, 4024}, ++ {52, 3895}, ++ {53, 3771}, ++ {54, 3651}, ++ {55, 3536}, ++ {56, 3425}, ++ {57, 3318}, ++ {58, 3215}, ++ {59, 3115}, ++ {60, 3019}, ++ {61, 2927}, ++ {62, 2837}, ++ {63, 2751}, ++ {64, 2668}, ++ {65, 2588}, ++ {66, 2511}, ++ {67, 2436}, ++ {68, 2364}, ++ {69, 2295}, ++ {70, 2227}, ++ {71, 2163}, ++ {72, 2100}, ++ {73, 2039}, ++ {74, 1981}, ++ {75, 1924}, ++ {76, 1869}, ++ {77, 1817}, ++ {78, 1765}, ++ {79, 1716}, ++ {80, 1668}, ++ {81, 1622}, ++ {82, 1577}, ++ {83, 1534}, ++ {84, 1492}, ++ {85, 1451}, ++ {86, 1412}, ++ {87, 1374}, ++ {88, 1337}, ++ {89, 1302}, ++ {90, 1267}, ++ {91, 1234}, ++ {92, 1201}, ++ {93, 1170}, ++ {94, 1139}, ++ {95, 1110}, ++ {96, 1081}, ++ {97, 1054}, ++ {98, 1027}, ++ {99, 1001}, ++ {100, 975}, ++ {101, 951}, ++ {102, 927}, ++ {103, 904}, ++ {104, 881}, ++ {105, 860}, ++ {106, 838}, ++ {107, 818}, ++ {108, 798}, ++ {109, 779}, ++ {110, 760}, ++}; ++ ++static unsigned int abs_subtract_val(int val_1, int val_2) ++{ ++ if(val_1 > val_2) ++ return (val_1 - val_2); ++ else ++ return (val_2 - val_1); ++} ++ ++static int temp_foreach_sheet(unsigned int R) ++{ ++ int index = 0; ++ int i = 0; ++ int num = sizeof(sheet) / sizeof(R_T); ++ unsigned int abs = abs_subtract_val(R , sheet[0].R); ++ int tmp; ++ for(i = 1;i < num;i++){ ++ tmp = abs_subtract_val(R , sheet[i].R); ++ if(tmp < abs){ ++ index = i; ++ abs = tmp; ++ if(tmp < 10) ++ break; ++ } ++ } ++ return (int)sheet[index].temp; ++} ++ ++ ++static struct i2c_client *ricoh619_i2c = NULL; ++static struct mutex ricoh61x_io_lock; ++ ++static const struct mfd_cell ricoh619_cells[] = { ++ { .name = "ricoh619-regulator" }, ++ { .name = "ricoh619-battery"}, ++ /*{ .name = "ricoh619-wdt" }, ++ { .name = "ricoh619-pinctrl" }, ++ { .name = "ricoh619-pm" }, */ ++}; ++ ++static bool ricoh619_reg_hole(unsigned int reg) ++{ ++#define RICOH619_REG_SINGLE_HOLE_NUM 16 ++ unsigned char single_hole[RICOH619_REG_SINGLE_HOLE_NUM] = { ++ 0x4, 0x8, 0x2b, 0x43, 0x49, 0x4b, 0x62, 0x63, 0x67, 0x8b, ++ 0x8f, 0x99, 0x9a, 0x9b, 0x9f, 0xb2, }; ++ int i; ++ ++ for (i = 0; i < RICOH619_REG_SINGLE_HOLE_NUM; i++) ++ if ((unsigned char)reg == single_hole[i]) ++ return true; ++ if (reg > RICOH619_MAX_REG) ++ return true; ++#undef RICOH619_REG_SINGLE_HOLE_NUM ++ return false; ++} ++ ++static bool ricoh619_opable_reg(struct device *dev, unsigned int reg) ++{ ++ return !ricoh619_reg_hole(reg); ++} ++ ++static bool ricoh619_volatile_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case RICOH619_WATCHDOGCNT: ++ case RICOH619_DCIRQ: ++ case RICOH619_IR_GPR: ++ case RICOH619_IR_GPF: ++ case RICOH619_MON_IOIN: ++ case RICOH619_INTMON: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static struct reg_default ricoh619_reg_default[RICOH619_REG_NUM]; ++static const struct regmap_config ricoh619_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .volatile_reg = ricoh619_volatile_reg, ++ .writeable_reg = ricoh619_opable_reg, ++ .readable_reg = ricoh619_opable_reg, ++ .max_register = RICOH619_MAX_REG, ++ .reg_defaults = ricoh619_reg_default, ++ .num_reg_defaults = ARRAY_SIZE(ricoh619_reg_default), ++ .cache_type = REGCACHE_RBTREE, ++}; ++static inline int set_bank_ricoh61x(struct device *dev, int bank) ++{ ++ int ret = 0; ++ ++ /*if (bank != (bank & 1))*/ ++ /*return -EINVAL;*/ ++ /*if (bank == ricoh61x->bank_num)*/ ++ /*return 0;*/ ++ /*ret = __ricoh61x_write(to_i2c_client(dev), RICOH61x_REG_BANKSEL, bank);*/ ++ /*if (!ret)*/ ++ /*ricoh61x->bank_num = bank;*/ ++ return ret; ++} ++ ++static int __ricoh619_reg_read(struct i2c_client *i2c, u8 reg) ++{ ++ return i2c_smbus_read_byte_data(i2c, reg); ++} ++ ++static inline int __ricoh61x_bulk_reads(struct i2c_client *client, u8 reg, ++ int len, uint8_t *val) ++{ ++ int ret; ++ int i; ++ ++ ret = i2c_smbus_read_i2c_block_data(client, reg, len, val); ++ if (ret < 0) { ++ dev_err(&client->dev, "failed reading from 0x%02x\n", reg); ++ return ret; ++ } ++ for (i = 0; i < len; ++i) { ++ dev_dbg(&client->dev, "ricoh61x: reg read reg=%x, val=%x\n", ++ reg + i, *(val + i)); ++ } ++ return 0; ++} ++ ++int ricoh61x_read(struct device* dev, u8 reg, uint8_t* val) ++{ ++ int ret; ++ mutex_lock(&ricoh61x_io_lock); ++ if(ricoh619_i2c){ ++ *val = __ricoh619_reg_read(ricoh619_i2c, reg); ++ ret = 0; ++ }else{ ++ ret = -1; ++ } ++ mutex_unlock(&ricoh61x_io_lock); ++ return ret; ++} ++EXPORT_SYMBOL(ricoh61x_read); ++ ++int ricoh61x_bulk_reads(struct device *dev, u8 reg, u8 len, uint8_t *val) ++{ ++ int ret = 0; ++ mutex_lock(&ricoh61x_io_lock); ++ ret = set_bank_ricoh61x(dev, 0); ++ if (!ret) ++ ret = __ricoh61x_bulk_reads(ricoh619_i2c, reg, len, val); ++ mutex_unlock(&ricoh61x_io_lock); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ricoh61x_bulk_reads); ++int ricoh61x_bulk_reads_bank1(struct device *dev, u8 reg, u8 len, uint8_t *val) ++{ ++ int ret = 0; ++ ++ mutex_lock(&ricoh61x_io_lock); ++ ret = set_bank_ricoh61x(dev, 1); ++ if (!ret) ++ ret = __ricoh61x_bulk_reads(ricoh619_i2c, reg, len, val); ++ mutex_unlock(&ricoh61x_io_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ricoh61x_bulk_reads_bank1); ++static inline int __ricoh61x_bulk_writes(struct i2c_client *client, u8 reg, ++ int len, uint8_t *val) ++{ ++ int ret; ++ int i; ++ ++ for (i = 0; i < len; ++i) { ++ dev_dbg(&client->dev, "ricoh61x: reg write reg=%x, val=%x\n", ++ reg + i, *(val + i)); ++ } ++ 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; ++ } ++ return 0; ++} ++ ++int ricoh61x_bulk_writes_bank1(struct device *dev, u8 reg, u8 len, uint8_t *val) ++{ ++ int ret = 0; ++ ++ mutex_lock(&ricoh61x_io_lock); ++ ret = set_bank_ricoh61x(dev, 1); ++ if (!ret) ++ ret = __ricoh61x_bulk_writes(to_i2c_client(dev), reg, len, val); ++ mutex_unlock(&ricoh61x_io_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ricoh61x_bulk_writes_bank1); ++static int __ricoh619_reg_write(struct i2c_client *i2c, u8 reg, u8 val) ++{ ++ return i2c_smbus_write_byte_data(i2c, reg, val); ++} ++ ++int ricoh61x_write(struct device* dev, u8 reg, uint8_t val) ++{ ++ int ret; ++ mutex_lock(&ricoh61x_io_lock); ++ if(ricoh619_i2c) ++ ret = __ricoh619_reg_write(ricoh619_i2c, reg, val); ++ else ++ ret = -1; ++ mutex_unlock(&ricoh61x_io_lock); ++ return ret; ++} ++EXPORT_SYMBOL(ricoh61x_write); ++static inline int __ricoh61x_read(struct i2c_client *client, ++ u8 reg, uint8_t *val) ++{ ++ int ret; ++ ++ ret = i2c_smbus_read_byte_data(client, reg); ++ if (ret < 0) { ++ dev_err(&client->dev, "failed reading at 0x%02x\n", reg); ++ return ret; ++ } ++ ++ *val = (uint8_t)ret; ++ dev_dbg(&client->dev, "ricoh61x: reg read reg=%x, val=%x\n", ++ reg, *val); ++ return 0; ++} ++ ++int ricoh61x_read_bank1(struct device *dev, u8 reg, uint8_t *val) ++{ ++ int ret = 0; ++ ++ mutex_lock(&ricoh61x_io_lock); ++ ret = set_bank_ricoh61x(dev, 1); ++ if (!ret) ++ ret = __ricoh61x_read(to_i2c_client(dev), reg, val); ++ mutex_unlock(&ricoh61x_io_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ricoh61x_read_bank1); ++int ricoh61x_bulk_writes(struct device *dev, u8 reg, u8 len, uint8_t *val) ++{ ++ int ret = 0; ++ ++ mutex_lock(&ricoh61x_io_lock); ++ ret = set_bank_ricoh61x(dev, 0); ++ if (!ret) ++ ret = __ricoh61x_bulk_writes(to_i2c_client(dev), reg, len, val); ++ mutex_unlock(&ricoh61x_io_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ricoh61x_bulk_writes); ++ ++int ricoh61x_set_bits(struct device *dev, u8 reg, uint8_t bit_mask) ++{ ++ uint8_t reg_val; ++ int ret = 0; ++ ++ mutex_lock(&ricoh61x_io_lock); ++ if(ricoh619_i2c){ ++ reg_val = __ricoh619_reg_read(ricoh619_i2c, reg); ++ ++ if ((reg_val & bit_mask) != bit_mask) { ++ reg_val |= bit_mask; ++ ret = __ricoh619_reg_write(ricoh619_i2c, reg, ++ reg_val); ++ } ++ } ++ mutex_unlock(&ricoh61x_io_lock); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ricoh61x_set_bits); ++ ++int ricoh61x_clr_bits(struct device *dev, u8 reg, uint8_t bit_mask) ++{ ++ uint8_t reg_val; ++ int ret = 0; ++ ++ mutex_lock(&ricoh61x_io_lock); ++ if(ricoh619_i2c){ ++ reg_val = __ricoh619_reg_read(ricoh619_i2c, reg); ++ if (reg_val & bit_mask) { ++ reg_val &= ~bit_mask; ++ ret = __ricoh619_reg_write(ricoh619_i2c, reg, ++ reg_val); ++ } ++ } ++ mutex_unlock(&ricoh61x_io_lock); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ricoh61x_clr_bits); ++ ++int ricoh61x_write_bank1(struct device *dev, u8 reg, uint8_t val) ++{ ++ int ret = 0; ++ ++ mutex_lock(&ricoh61x_io_lock); ++ ret = __ricoh619_reg_write(ricoh619_i2c, reg, val); ++ mutex_unlock(&ricoh61x_io_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(ricoh61x_write_bank1); ++ ++ ++static void ricoh619_reg_default_init(struct i2c_client *i2c) ++{ ++ unsigned int reg, def; ++ int i; ++ ++ for (i = 0, reg = 0; i < RICOH619_REG_NUM && ++ reg <= RICOH619_MAX_REG; reg++) { ++ if (ricoh619_reg_hole(reg) || ++ ricoh619_volatile_reg(NULL, reg)) ++ continue; ++ ricoh619_reg_default[i].reg = reg; ++ def = __ricoh619_reg_read(i2c, (u8)reg); ++ if (def < 0) { ++ dev_warn(&i2c->dev, "register %x read failed: %d\n", reg, def); ++ ricoh619_reg_default[i++].def = 0; ++ } else{ ++ ricoh619_reg_default[i++].def = def; ++// printk("ricoh619: reg: 0x%x , val: 0x%x\n", ricoh619_reg_default[i-1].reg, ricoh619_reg_default[i-1].def); ++ } ++ } ++} ++ ++static int battery_ntc_R_val(int thermbat_val) ++{ ++ thermbat_val *= 10; ++#define R493 10000 ++#define VCHGREGA 2500 ++ if(thermbat_val > 0) ++ return thermbat_val * R493 / (VCHGREGA - thermbat_val); ++ else ++ return 0; ++} ++ ++static void config_xxzA926_info(struct i2c_client *i2c) ++{ ++ unsigned int reg_val; ++ struct regulator *reg = devm_regulator_get(&i2c->dev, "ldo3_2v8"); ++ regulator_set_voltage(reg, 2800000, 2800000); ++ regulator_enable(reg); ++ ++ ++ reg = devm_regulator_get(&i2c->dev, "DC1_0v9"); ++ regulator_set_voltage(reg, 900000, 900000); ++ regulator_enable(reg); ++ ++ /*regulator_enable(reg);*/ ++ reg = devm_regulator_get(&i2c->dev, "DC5_1v2"); ++ regulator_set_voltage(reg, 1200000, 1200000); ++ regulator_enable(reg); ++ printk("cljiang======================RICOH619_DC5CTL = 0x%x\n", __ricoh619_reg_read(i2c, RICOH619_DC5CTL)); ++ printk("cljiang======================RICOH619_DC5DAC = 0x%x\n", __ricoh619_reg_read(i2c, RICOH619_DC5DAC)); ++ ++ reg = devm_regulator_get(&i2c->dev, "ldortc2_0v9"); ++ regulator_set_voltage(reg, 900000, 900000); ++ regulator_enable(reg); ++ ++ /*Full-charging Voltage*/ ++ reg_val = __ricoh619_reg_read(i2c, RICOH619_BATSET2); ++ printk("cljiang======================RICOH619_BATSET2 = 0x%x\n", reg_val); ++ reg_val &= 0x84; ++ reg_val |= 0x44; /*full-Charging volt 4.35v, Re-Charging volt 4.1v*/ ++ __ricoh619_reg_write(i2c, RICOH619_BATSET2, reg_val); ++ printk("cljiang======================set RICOH619_BATSET2 = 0x%x\n", __ricoh619_reg_read(i2c, RICOH619_BATSET2)); ++ ++ /*Over Voltage*/ ++ reg_val = __ricoh619_reg_read(i2c, RICOH619_BATSET1); ++ reg_val &= 0xEF; ++ reg_val |= 0x10; ++ __ricoh619_reg_write(i2c, RICOH619_BATSET1, reg_val); ++ printk("cljiang======================set RICOH619_BATSET1 = 0x%x\n", __ricoh619_reg_read(i2c, RICOH619_BATSET1)); ++ ++ ++ /*Charging current*/ ++ /*limited ADP*/ ++ __ricoh619_reg_write(i2c, RICOH619_REGISET1, 0x13); /* 2000ma*/ ++ printk("cljiang======================RICOH619_REGISET1 = 0x%x\n", __ricoh619_reg_read(i2c, RICOH619_REGISET1)); ++ ++ /*limited USB */ ++ printk("cljiang======================RICOH619_REGISET1 = 0x%x\n", __ricoh619_reg_read(i2c, RICOH619_REGISET1)); ++ reg_val = __ricoh619_reg_read(i2c, RICOH619_REGISET2); ++ reg_val &= 0xE0; ++ reg_val |= 0x0E;/*1500ma*/ ++ __ricoh619_reg_write(i2c, RICOH619_REGISET2, reg_val); ++ printk("cljiang======================RICOH619_REGISET2 = 0x%x\n", __ricoh619_reg_read(i2c, RICOH619_REGISET2)); ++ ++ /*Charge Current Setting*/ ++ reg_val = __ricoh619_reg_read(i2c, RICOH619_CHGISET); ++ printk("cljiang======================RICOH619_CHGISET = 0x%x\n", reg_val); ++ reg_val &= 0xE0; ++ reg_val |= 0x0B;/*1200ma*/ ++ __ricoh619_reg_write(i2c, RICOH619_CHGISET, reg_val); ++ printk("cljiang======================RICOH619_CHGISET = 0x%x\n", __ricoh619_reg_read(i2c, RICOH619_CHGISET)); ++ ++ ++ /*power off press timer*/ ++ reg_val = __ricoh619_reg_read(i2c, RICOH619_PWRONTIMSET); ++ reg_val &= 0x8F; ++ reg_val |= 0x50; /*8 sec*/ ++ __ricoh619_reg_write(i2c, RICOH619_PWRONTIMSET, reg_val); ++ ++ ++ /*battery temperature measure*/ ++ /*enable VTHMSEL bit*/ ++ reg_val = __ricoh619_reg_read(i2c, RICOH619_ADCCNT1); ++ reg_val &= 0xDF; ++ reg_val |= 0x20; ++ __ricoh619_reg_write(i2c, RICOH619_ADCCNT1, reg_val); ++ ++ /*set ADRQ auto-mode*/ ++ reg_val = __ricoh619_reg_read(i2c, RICOH619_ADCCNT3); ++ reg_val &= 0xCF; ++ reg_val |= 0x20; /*auto-mode*/ ++ __ricoh619_reg_write(i2c, RICOH619_ADCCNT3, reg_val); ++ ++ ++ ++ udelay(100000); ++ /*read voltage*/ ++ printk("cljiang======================VTHMDATAH: %d, VTHMDATAL: %d\n", __ricoh619_reg_read(i2c, RICOH619_VTHMDATAH), ++ __ricoh619_reg_read(i2c, RICOH619_VTHMDATAL)); ++ printk("cljiang======================Resistance = %d\n", battery_ntc_R_val(__ricoh619_reg_read(i2c, RICOH619_VTHMDATAH))); ++ printk("cljiang======================temperature = %d\n", temp_foreach_sheet(188600)); ++ ++ /*charger insertion logic*/ ++ reg_val = __ricoh619_reg_read(i2c, RICOH619_PONHIS); ++ printk("cljiang======================RICOH619_PONHIS = 0x%x\n", reg_val); ++#if 0 ++ if(reg_val & 0x4){ ++ /*power off*/ ++ __ricoh619_reg_write(i2c, RICOH619_SLPCNT, 0x1); ++ } ++#endif ++ ++} ++static int ricoh619_i2c_probe(struct i2c_client *i2c, ++ const struct i2c_device_id *id) ++{ ++ struct regmap *regmap = NULL; ++ int ret; ++printk("jimgao test ricoh619_i2c_probe=======IIIIIIIIIIIIIII=====\n"); ++ ricoh619_i2c = i2c; ++ mutex_init(&ricoh61x_io_lock); ++ ++ ricoh619_reg_default_init(i2c); ++ ++ regmap = devm_regmap_init_i2c(i2c, &ricoh619_regmap_config); ++ if (IS_ERR(regmap)) { ++ ret = PTR_ERR(regmap); ++ dev_err(&i2c->dev, "regmap init failed: %d\n", ret); ++ return ret; ++ } ++ i2c_set_clientdata(i2c, regmap); ++ ++ ret = ricoh619_irq_init(i2c, regmap); ++ if (ret) ++ return ret; ++ ++ ++ ret = mfd_add_devices(&i2c->dev, -1, ricoh619_cells, ++ ARRAY_SIZE(ricoh619_cells), NULL, 0, NULL); ++ if (ret) { ++ dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret); ++ goto out_irq_domain_remove; ++ } ++ ++ dev_info(&i2c->dev, "%s success\n", __func__); ++ ++ config_xxzA926_info(i2c); ++ ++ ++ return 0; ++ ++out_irq_domain_remove: ++ ricoh619_irq_deinit(); ++ return ret; ++} ++ ++static int ricoh619_i2c_remove(struct i2c_client *i2c) ++{ ++ mfd_remove_devices(&i2c->dev); ++ return 0; ++} ++ ++static const struct of_device_id ricoh619_of_match[] = { ++ { .compatible = "ricoh,rn5t619" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ricoh619_of_match); ++ ++static const struct i2c_device_id rc5t619_i2c_id[] = { ++ {.name = "rc5t619", .driver_data = 0}, ++ {} ++}; ++ ++ ++static struct i2c_driver ricoh619_i2c_driver = { ++ .driver = { ++ .name = "ricoh619", ++ .of_match_table = of_match_ptr(ricoh619_of_match), ++ }, ++ .probe = ricoh619_i2c_probe, ++ .remove = ricoh619_i2c_remove, ++ .id_table = rc5t619_i2c_id, ++}; ++ ++static int __init ricoh619_i2c_init(void) ++{ ++ int ret = -ENODEV; ++ ++ ret = i2c_add_driver(&ricoh619_i2c_driver); ++ if (ret != 0) ++ pr_err("Failed to register I2C driver: %d\n", ret); ++ return ret; ++} ++subsys_initcall(ricoh619_i2c_init); ++ ++static void __exit ricoh619_i2c_exit(void) ++{ ++ i2c_del_driver(&ricoh619_i2c_driver); ++} ++ ++module_exit(ricoh619_i2c_exit); ++ ++MODULE_DESCRIPTION("Ricoh RICOH619 MFD driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/module_drivers/drivers/misc/Kconfig b/module_drivers/drivers/misc/Kconfig +new file mode 100644 +index 000000000..9f3238273 +--- /dev/null ++++ b/module_drivers/drivers/misc/Kconfig +@@ -0,0 +1,41 @@ ++config INGENIC_RSA ++ bool "[RSA] JZ RSA Driver" ++ depends on SOC_X2000 || SOC_X2100 || SOC_M300 || SOC_X2500 ++ help ++ this driver is used to Encrypt/Decrypt by RSA. ++ default n ++ ++config LINUX_PMEM ++ bool "Linux pmem allocator" ++ default n ++ ++config PMEM_RESERVE_SIZE ++ string "reserve size" ++ depends on LINUX_PMEM ++ default 0M ++ help ++ set this like 16M, 4096K, 100000[B], 0x5000(B). ++ ++config INGENIC_EFUSE_V2 ++ bool "[Efuse] Ingenic Efuse v2 Driver" ++ depends on SOC_X1600 ++ default n ++ ++config INGENIC_EFUSE_V2_WRITABLE ++ bool "[Efuse] Ingenic Efuse V2 Writable" ++ depends on INGENIC_EFUSE_V2 ++ default n ++ ++ ++config INGENIC_EFUSE_X2000 ++ bool "[Efuse] Ingenic Efuse X2000 Driver" ++ depends on SOC_X2000 || SOC_X2100 || SOC_M300 ++ default n ++ ++config BCM_4345C5_RFKILL ++ tristate "Bluetooth power control driver for BCM-4345C5 module" ++ depends on RFKILL && (MMC_SDHCI_INGENIC || INGENIC_MMC_MMC0 || INGENIC_MMC_MMC1) ++ default n ++ help ++ Creates an rfkill entry in sysfs for power control of Bluetooth ++ bcm-xxxx chips. +diff --git a/module_drivers/drivers/misc/Makefile b/module_drivers/drivers/misc/Makefile +new file mode 100644 +index 000000000..0b4f89c27 +--- /dev/null ++++ b/module_drivers/drivers/misc/Makefile +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_LINUX_PMEM) += linux_pmem.o ++obj-$(CONFIG_INGENIC_RSA) += ingenic_rsa.o ++obj-$(CONFIG_INGENIC_EFUSE_X2000) += ingenic_efuse_x2000.o ++obj-$(CONFIG_INGENIC_EFUSE_V2) += ingenic_efuse_v2.o ++obj-$(CONFIG_RMEM) += rmem.o ++obj-$(CONFIG_BCM_4345C5_RFKILL) += bt_power_bluesleep.o +diff --git a/module_drivers/drivers/misc/bt_power_bluesleep.c b/module_drivers/drivers/misc/bt_power_bluesleep.c +new file mode 100644 +index 000000000..eee7a4c54 +--- /dev/null ++++ b/module_drivers/drivers/misc/bt_power_bluesleep.c +@@ -0,0 +1,311 @@ ++/* ++ * Description: ++ * Bluetooth power driver with rfkill interface ,work in with bluesleep.c , version of running consume. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++/*#include */ ++/*#include */ ++#include ++#include ++ ++#define DEV_NAME "bt_power" ++ ++struct bt_rfkill_platform_data { ++ struct rfkill *rfkill; /* for driver only */ ++ void (*restore_pin_status)(int); ++ void (*set_pin_status)(int); ++}; ++ ++static struct bt_rfkill_platform_data pdata; ++#if 1 ++#define DBG_MSG(fmt, ...) printk(fmt, ##__VA_ARGS__) ++#else ++#define DBG_MSG(fmt, ...) ++#endif ++ ++int bt_power_state = 0; ++static int bt_power_control(int enable); ++static int bt_rst_n ; ++static int bt_reg_on; ++static int bt_wake; ++unsigned bt_wake_irq; ++static DEFINE_MUTEX(bt_power_lock); ++#if defined CONFIG_KP_AXP ++static struct regulator *bt_regulator = NULL; ++#endif ++ ++extern void rtc32k_enable(void); ++extern void rtc32k_disable(void); ++ ++/* For compile only, remove later */ ++#define RFKILL_STATE_SOFT_BLOCKED 0 ++#define RFKILL_STATE_UNBLOCKED 1 ++ ++static void bt_enable_power(void) ++{ ++ gpio_set_value(bt_reg_on, 1); ++} ++ ++static void bt_disable_power(void) ++{ ++ gpio_set_value(bt_reg_on, 0); ++} ++ ++static int bt_power_control(int enable) ++{ ++ if (enable == bt_power_state)// == 0 ++ return 0; ++ ++#if defined CONFIG_KP_AXP ++ if(bt_regulator == NULL) { ++ bt_regulator = regulator_get(NULL, "wlreg_on"); ++ if (bt_regulator == NULL) { ++ printk(("%s regulator is null\n", __FUNCTION__)); ++ return -1; ++ } ++ } ++#endif ++ ++ switch (enable) { ++ case RFKILL_STATE_SOFT_BLOCKED://0 ++ rtc32k_disable(); ++ bt_disable_power(); ++ mdelay(1000); ++ if (pdata.set_pin_status != NULL){ ++ (*pdata.set_pin_status)(enable); ++ printk("set_pin_status is defined\n"); ++ }else{ ++ printk("set_pin_status is not defined\n"); ++ } ++#if defined CONFIG_KP_AXP ++ if(regulator_disable(bt_regulator) < 0) ++ return -1; ++#endif ++ break; ++ case RFKILL_STATE_UNBLOCKED://1 ++#if defined CONFIG_KP_AXP ++ if(regulator_enable(bt_regulator) < 0) ++ return -1; ++#endif ++ if (pdata.restore_pin_status != NULL){ ++ (*pdata.restore_pin_status)(enable); ++ }else{ ++ rtc32k_enable(); ++ printk("restore_pin_status is not defined\n"); ++ } ++ rtc32k_enable(); ++ if (bt_rst_n > 0){ ++ gpio_direction_output(bt_rst_n,0); ++ } ++ bt_enable_power(); ++ mdelay(300); ++ if(bt_rst_n > 0){ ++ gpio_set_value(bt_rst_n,1); ++ } ++ break; ++ default: ++ break; ++ } ++ ++ bt_power_state = enable; ++ ++ return 0; ++} ++ ++static bool first_called = true; ++ ++static int bt_rfkill_set_block(void *data, bool blocked) ++{ ++ int ret; ++ ++ if (!first_called) { ++ mutex_lock(&bt_power_lock); ++ ret = bt_power_control(blocked ? 0 : 1); ++ mutex_unlock(&bt_power_lock); ++ } else { ++ first_called = false; ++ return 0; ++ } ++ ++ return ret; ++} ++ ++static const struct rfkill_ops bt_rfkill_ops = { ++ .set_block = bt_rfkill_set_block, ++}; ++ ++static int bt_power_rfkill_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ enum of_gpio_flags flags; ++ int ret = -ENOMEM; ++ ++ bt_rst_n = of_get_named_gpio_flags(np, "ingenic,rst-n-gpio", 0, &flags); ++ if(!gpio_is_valid(bt_rst_n)) { ++ bt_rst_n = -1; ++ } ++ bt_reg_on = of_get_named_gpio_flags(np, "ingenic,reg-on-gpio", 0, &flags); ++ if(!gpio_is_valid(bt_reg_on)) { ++ bt_reg_on = -1; ++ } ++ bt_wake = of_get_named_gpio_flags(np, "ingenic,wake-gpio", 0, &flags); ++ if(!gpio_is_valid(bt_wake)) { ++ bt_wake = -1; ++ } ++ ++ pdata.restore_pin_status = NULL; ++ pdata.set_pin_status = NULL; ++ pdata.rfkill = rfkill_alloc("bluetooth", &pdev->dev, RFKILL_TYPE_BLUETOOTH, ++ &bt_rfkill_ops, NULL); ++ ++ if (!pdata.rfkill) { ++ goto exit; ++ } ++ ++ ret = rfkill_register(pdata.rfkill); ++ if (ret) { ++ rfkill_destroy(pdata.rfkill); ++ return ret; ++ } else { ++ platform_set_drvdata(pdev, pdata.rfkill); ++ } ++exit: ++ return ret; ++} ++ ++static void bt_power_rfkill_remove(struct platform_device *pdev) ++{ ++ pdata.rfkill = platform_get_drvdata(pdev); ++ if (pdata.rfkill) ++ rfkill_unregister(pdata.rfkill); ++ ++ platform_set_drvdata(pdev, NULL); ++} ++ ++static irqreturn_t bt_wake_host_cb(int i, void *data) ++{ ++ return IRQ_HANDLED; ++} ++ ++static int bluesleep_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ ++ if(bt_wake >= 0) ++ enable_irq_wake(bt_wake_irq); ++ ++ return 0; ++} ++ ++static int bluesleep_resume(struct platform_device *pdev) ++{ ++ if(bt_wake >= 0) ++ disable_irq_wake(bt_wake_irq); ++ ++ return 0; ++} ++static int __init_or_module bt_power_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ret = bt_power_rfkill_probe(pdev); ++ if (ret) { ++ return ret; ++ } ++ ++ if(bt_rst_n > 0){ ++ ret = gpio_request(bt_rst_n,"bt_rst_n"); ++ if(unlikely(ret)){ ++ return ret; ++ } ++ } ++ ++ if (bt_reg_on > 0){ ++ ret = gpio_request(bt_reg_on,"bt_reg_on"); ++ if(unlikely(ret)){ ++ gpio_free(bt_rst_n); ++ return ret; ++ } ++ gpio_direction_output(bt_reg_on, 0); ++ } ++ ++ if(bt_wake >= 0){ ++ ret = gpio_request(bt_wake,"bt_wake"); ++ if(unlikely(ret)){ ++ printk("bt_wake request failed\n"); ++ return ret; ++ } ++ } ++ ++ ret = gpio_direction_input(bt_wake); ++ if (ret < 0) { ++ pr_err("gpio-keys: failed to configure input" ++ " direction for GPIO %d, error %d\n", ++ bt_wake, ret); ++ return ret; ++ } ++ ++ bt_wake_irq = gpio_to_irq(bt_wake); ++ if (bt_wake_irq < 0) { ++ printk("couldn't find host_wake irq\n"); ++ return -1; ++ } ++ ret = request_irq(bt_wake_irq, bt_wake_host_cb, ++ /*IRQF_DISABLED |*/ IRQF_TRIGGER_RISING, ++ "bluetooth bthostwake", NULL); ++ if (ret < 0) { ++ printk("Couldn't acquire BT_HOST_WAKE IRQ err (%d)\n", ret); ++ return -1; ++ } ++ ++ if(bt_rst_n > 0){ ++ gpio_direction_output(bt_rst_n,1); ++ } ++ return 0; ++} ++ ++static int bt_power_remove(struct platform_device *pdev) ++{ ++ int ret; ++ ++ bt_power_rfkill_remove(pdev); ++ ++ mutex_lock(&bt_power_lock); ++ bt_power_state = 0; ++ ret = bt_power_control(bt_power_state); ++ mutex_unlock(&bt_power_lock); ++ ++ return ret; ++} ++ ++static const struct of_device_id bt_power_match[] = { ++ {.compatible = "ingenic,bt_power",}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, bt_power_match); ++static struct platform_driver bt_power_driver = { ++ .probe = bt_power_probe, ++ .remove = bt_power_remove, ++ .suspend = bluesleep_suspend, ++ .resume = bluesleep_resume, ++ .driver = { ++ .name = DEV_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(bt_power_match), ++ }, ++}; ++ ++module_platform_driver(bt_power_driver); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Bluetooth power control driver"); ++MODULE_VERSION("1.0"); +diff --git a/module_drivers/drivers/misc/hamming.c b/module_drivers/drivers/misc/hamming.c +new file mode 100644 +index 000000000..b2ef71f6d +--- /dev/null ++++ b/module_drivers/drivers/misc/hamming.c +@@ -0,0 +1,374 @@ ++ ++static int checkbit(unsigned int *s,unsigned int *d,int ss,int ds,int bsz) ++{ ++ int sg32,sb32,dg32,db32; ++ ++ while(bsz > 0){ ++ sg32 = ss / 32; ++ sb32 = ss % 32; ++ dg32 = ds / 32; ++ db32 = ds % 32; ++ if( ++ ((s[sg32] >> sb32) & 1) != ++ ((d[dg32] >> db32) & 1) ++ ) ++ break; ++ ss++; ++ ds++; ++ bsz--; ++ } ++ return bsz; ++} ++ ++static int dump(unsigned int *s,int st,int en) ++{ ++ int i; ++ ++ for(i = st;i < en;i++){ ++ ++ if((i - st) % 32 == 0){ ++ printk("\n"); ++ }else if((i - st) % 8 == 0){ ++ printk(" "); ++ } ++ ++ if(s[i / 32] & (1 << (i % 32))) ++ printk("1"); ++ else ++ printk("0"); ++ ++ } ++ printk("\n"); ++ return 0; ++} ++ ++static int dumphex(unsigned int *s,int sz) ++{ ++ int i; ++ ++ for(i = 0;i < sz;i++){ ++ printk("%08x\n",s[i]); ++ } ++ return 0; ++} ++ ++ ++// bits + k = 2^k - 1. ++// result k. ++static int cal_k(int bits) ++{ ++ int k = 0; ++ unsigned int cur = 1; ++ while(cur - 1 < bits + k){ ++ cur <<= 1; ++ k++; ++ } ++ return k; ++} ++ ++/** ++ * @brief bitcpy ++ * ++ * copy bit from *s buffer to *d buffer. ++ * ++ * @param s source buffer. ++ * @param d target buffer. ++ * @param ss start position of source buffer. ++ * @param ds start position of target buffer. ++ * @param bsz bit count of copy. ++ */ ++static void bitcpy(const unsigned int *s,unsigned int *d, ++ const int ss,const int ds,int bsz) ++{ ++ int ss_int = ss / 32; ++ int ss_bit = ss % 32; ++ ++ int ds_int = ds / 32; ++ int ds_bit = ds % 32; ++#define MMIN(a,b) (a) > (b) ? (b) : (a) ++ while(bsz != 0){ ++ unsigned int src,dst,bmsk; ++ int min = MMIN(32 - ss_bit,32 - ds_bit); ++ min = MMIN(min,bsz); ++ bmsk = 0xffffffff >> (32 - min); ++ src = s[ss_int] >> ss_bit; ++ src &= bmsk; ++ ++ dst = d[ds_int]; ++ dst &= ~(bmsk << ds_bit); ++ dst |= src << ds_bit; ++ ++ d[ds_int] = dst; ++ ds_bit += min; ++ if(ds_bit >= 32){ ++ ds_int++; ++ ds_bit = 0; ++ } ++ ss_bit += min; ++ if(ss_bit >= 32){ ++ ss_int++; ++ ss_bit = 0; ++ } ++// printk("bsz = %d min = %d\n",bsz,min); ++ bsz -= min; ++ } ++} ++ ++/** ++ * @brief bit32_cal_xor ++ * ++ * The data is xor to 64bit by 32bit unit. ++ * ++ * @param s The Data buffer. ++ * @param bitsz The data's bit count. ++ * @return length Remained data bit count. ++ */ ++static int bit32_cal_xor(const unsigned int *s,int bitsz,unsigned int *d) ++{ ++ int j; ++ if(bitsz > 64){ ++ unsigned int bit32 = s[0]; ++ for(j = 32;j < bitsz / 32 * 32;j+=32){ ++ bit32 ^= s[j / 32]; ++ } ++ d[0] = bit32; ++ if(bitsz % 32) ++ d[1] = s[j/32]; ++ ++ return 32 + (bitsz % 32); ++ }else if(bitsz > 32){ ++ d[0] = s[0]; ++ d[1] = s[1]; ++ }else ++ d[0] = s[0]; ++ return bitsz; ++} ++/** ++ * @brief bit_index_cal_xor ++ * ++ * Calibrate general data hamming and Maximin size is 32bit. ++ * ++ * @param d 32bit data buffer. ++ * @param bitsz bit size. ++ * @param index k value. ++ * @param xor head result. ++ * @return xor result. ++ */ ++static int bit_index_cal_xor(const unsigned int *d,int bitsz,int index,unsigned int xor) ++{ ++ int sz = bitsz; ++ int gap = (1 << index); ++ int j,i; ++ int pre_g = 0; ++ unsigned int bit32; ++ j = gap - 1; ++ bit32 = d[pre_g]; ++ while(j < sz){ ++ for(i = 0;i < (1 << index);i++){ ++ int g = (j + i) / 32; ++ int b = (j + i) % 32; ++ if(g != pre_g){ ++ pre_g = g; ++ bit32 = d[pre_g]; ++ } ++ xor ^= (bit32 >> b) & 1; ++ } ++ gap += 2 * (1 << index); ++ j += 2 * (1 << index); ++ } ++ return xor; ++} ++ ++/** ++ * @brief bit_cal_xor_first ++ * ++ * Get the highest position of the POS location. ++ * ++ * @param s data buffer. ++ * @param pos bit position. ++ * @return 31'b bit ++ */ ++static unsigned int get_highest_bit(const unsigned int *s,int pos) ++{ ++ unsigned int xor; ++ unsigned int bit32 = s[pos / 32]; ++ xor = bit32 >> 31; ++ return xor; ++} ++ ++/** ++ * @brief bit_cal_xor ++ * ++ * XOR value of calculated data. ++ * ++ * @param s data buffer. ++ * @param s calculated bit width. ++ * @param pos bit position. ++ * @param xor previous xor value. ++ * @return XOR value. ++ */ ++static unsigned int bit_cal_xor(const unsigned int *s,int bitsz,int pos,unsigned int xor) ++{ ++ unsigned int bit32 = s[pos / 32]; ++ int bitpos = pos % 32; ++ int i; ++// printk("--bitsz = %d pos = %d\n",bitsz,pos); ++ if(bitpos){ ++ int endpos = bitsz > (32 - bitpos) ? 32 : bitsz + bitpos; ++ int sz = endpos - bitpos; ++ for(i = bitpos;i < endpos;i++){ ++ xor ^= (bit32 >> i) & 1; ++ } ++ bitsz -= sz; ++ pos += sz; ++ } ++ if(bitsz > 32){ ++ for(i = 32;i < bitsz / 32 * 32;i += 32){ ++ bit32 ^= s[(pos + i)/32]; ++ } ++ pos += i; ++ for(i = 0;i < 32;i++){ ++ xor ^= (bit32 >> i) & 1; ++ } ++ bitsz = bitsz % 32; ++ } ++ if(bitsz) ++ bit32 = s[pos/32]; ++ ++ for(i = 0;i < bitsz;i++){ ++ xor ^= (bit32 >> i) & 1; ++ } ++ return xor; ++} ++ ++/** ++ * @brief cal_xor_ge32 ++ * ++ * Calculate XOR values of segments larger than or equal to 32bit data. ++ * ++ * @param d data buffer. ++ * @param dsz bit width of data buffer. ++ * @param segments interval. ++ * @return Xor value. ++ */ ++static int cal_xor_ge32(const unsigned int *d,int dsz,int index,int xor) ++{ ++ int i; ++ int step = 1 << index; ++ int min; ++ for(i = step - 1;i < dsz;i += step * 2){ ++ xor ^= get_highest_bit(d,i); ++ min = dsz - i - 1 > step - 1 ? step - 1 : dsz - i - 1; ++ if(min > 0) ++ xor = bit_cal_xor(d, min, i + 1, xor); ++ } ++ return xor; ++} ++ ++int encode(unsigned int *s,int bits,unsigned int *d) ++{ ++ int k = cal_k(bits); ++ int i,j,p; ++ int bitsz; ++ unsigned int xor = 0; ++ i = 0; ++ p = 0; ++ j = 0; ++ bits += k; ++ ++ while(j < bits){ ++ int curindex,bsz; ++ curindex = (1 << p); ++ if(j + 1 != curindex){ ++ bsz = (curindex - j - 1); ++ if((bits - j) < bsz){ ++ bsz = bits - j; ++ } ++ bitcpy(s,d,i,j,bsz); ++ i += bsz; ++ j += bsz; ++ }else{ ++ unsigned int dst; ++ unsigned int msk = 1 << (j % 32); ++ dst = d[j / 32]; ++ dst &= ~msk; ++ d[j / 32] = dst; ++ j++; ++ p++; ++ } ++ } ++// dump(d,0,bits); ++ ++ // cal xor. ++ bitsz = bit32_cal_xor(d,bits,s); ++// dump(s,0,bits); ++// dump(d,0,bits); ++ ++ i = 0; ++ while((1 << i) < bits){ ++ if(i < 5){ ++ xor = bit_index_cal_xor(s,bitsz,i,0); ++// dump(d,0,bits); ++ }else{ ++ xor = cal_xor_ge32(d,bits,i,0); ++// dump(d,0,bits); ++ } ++ p = (1 << i) - 1; ++ i++; ++ d[p / 32] &= ~(1 << (p % 32)); ++ d[p / 32] |= (xor << (p % 32)); ++ } ++ return bits; ++} ++ ++int decode(unsigned int *s,int bits,unsigned int *d) ++{ ++ int i,p,j; ++ int xor = 0; ++ int errbit = 0; ++ int bitsz; ++ ++ bitsz = bit32_cal_xor(s,bits,d); ++ ++ i = 0; ++ while((1 << i) < bits) ++ { ++ if(i < 5){ ++ xor = bit_index_cal_xor(d,bitsz,i,0); ++ }else ++ xor = cal_xor_ge32(s,bits,i,0); ++ errbit |= xor << i; ++ i++; ++ } ++ ++ if(errbit > 0){ ++ errbit = errbit - 1; ++ xor = 1 << (errbit % 32); ++ s[errbit / 32] ^= xor; ++ s[errbit / 32] ^= 0; ++ } ++ ++ i = 0; ++ p = 0; ++ j = 0; ++ while(j < bits){ ++ int curindex,bsz; ++ curindex = (1 << p); ++ if(j + 1 != curindex){ ++ bsz = (curindex - j - 1); ++ if((bits - j) < bsz){ ++ bsz = bits - j; ++ } ++ bitcpy(s,d,j,i,bsz); ++ i += bsz; ++ j += bsz; ++ }else{ ++ j++; ++ p++; ++ } ++ } ++ ++// dump(d,0,bits); ++ return i; ++} ++ +diff --git a/module_drivers/drivers/misc/ingenic_efuse_v2.c b/module_drivers/drivers/misc/ingenic_efuse_v2.c +new file mode 100644 +index 000000000..911dfdfca +--- /dev/null ++++ b/module_drivers/drivers/misc/ingenic_efuse_v2.c +@@ -0,0 +1,745 @@ ++/* ++ * linux/drivers/misc/ingenic_efuse_v2.c - Ingenic efuse driver ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ * Author: . ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#define DEBUG ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++ ++#define DRV_NAME "ingenic-efuse" ++ ++#define CMD_WRITE _IOR('E', 100, unsigned int) ++#define CMD_READ _IOR('E', 101, unsigned int) ++ ++struct efuse_wr_info { ++ uint32_t seg_id; ++ uint8_t *data; ++}; ++ ++struct board_gpio { ++ short gpio; ++ short level; ++}; ++ ++struct jz_efuse { ++ struct device *dev; ++ struct miscdevice mdev; ++ struct efuse_wr_info *wr_info; ++ struct mutex lock; ++ void __iomem *iomem; ++#ifdef CONFIG_INGENIC_EFUSE_V2_WRITABLE ++ struct timer_list vddq_protect_timer; ++ struct board_gpio avd_efuse_en; ++#endif ++}; ++ ++static struct jz_efuse *efuse; ++static struct seg_info info; ++ ++static uint32_t efuse_readl(uint32_t reg_off) ++{ ++ return readl(efuse->iomem + reg_off); ++} ++ ++static void efuse_writel(uint32_t val, uint32_t reg_off) ++{ ++ writel(val, efuse->iomem + reg_off); ++} ++ ++#ifdef CONFIG_INGENIC_EFUSE_V2_WRITABLE ++static void efuse_vddq_set_timer(struct timer_list *t) ++{ ++ struct jz_efuse *efuse_test = from_timer(efuse, t, vddq_protect_timer); ++ gpio_direction_output(efuse->avd_efuse_en.gpio, !efuse->avd_efuse_en.level); ++} ++ ++static void efuse_vddq_set(unsigned long on) ++{ ++ if(on){ ++ mod_timer(&efuse->vddq_protect_timer, jiffies + msecs_to_jiffies(800)); ++ } ++ gpio_direction_output(efuse->avd_efuse_en.gpio, on); ++} ++#else ++static void efuse_vddq_set(unsigned long on) {} ++#endif ++ ++static int efuse_open(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} ++ ++static int efuse_release(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} ++ ++static void otp_r(uint32_t addr, uint32_t blen) ++{ ++ unsigned int val; ++ int n; ++ ++ efuse_writel(0, EFUSE_CTRL); ++ ++ for(n = 0; n < 8; n++) ++ efuse_writel(0, EFUSE_DATA(n)); ++ ++ /* set read address and data length */ ++ val = addr << EFUSE_CTRL_ADDR | (blen - 1) << EFUSE_CTRL_LEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ /* enable read */ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_RDEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ dev_dbg(efuse->dev,"efuse ctrl regval=0x%x\n",val); ++ /* wait read done status */ ++ while(!(efuse_readl(EFUSE_STATE) & EFUSE_STA_RD_DONE)); ++} ++ ++static int jz_efuse_read(struct seg_info *info, uint8_t *buf) ++{ ++ int i; ++ unsigned int *data = (volatile unsigned int *)(efuse->iomem + EFUSE_DATA(0)); ++ unsigned byte_len = (info->bit_num >> 3); ++ ++ dev_dbg(efuse->dev,"segment name: %s\nsegment addr: 0x%02x\nbyte num: %d\nbit num: %d\n", ++ info->seg_name, info->offset_address, byte_len, info->bit_num); ++ ++ otp_r(info->offset_address, byte_len); ++ ++ dev_dbg(efuse->dev, "efuse read data:\n"); ++ for(i = 0; i < 8; i++ ) ++ dev_dbg(efuse->dev,"0x%08x\n", data[i]); ++ ++ memcpy(buf, data, 32); ++ ++ /* clear read done status */ ++ efuse_writel(0, EFUSE_STATE); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(jz_efuse_read); ++ ++static void otp_w(uint32_t addr, uint32_t blen) ++{ ++ unsigned int val; ++ ++ efuse_writel(0, EFUSE_CTRL); ++ ++ /* set write Programming address and data length */ ++ val = addr << EFUSE_CTRL_ADDR | (blen - 1) << EFUSE_CTRL_LEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ /* Programming EFUSE enable */ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_PGEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ /* Connect VDDQ pin from 2.5V */ ++ efuse_vddq_set(1); ++ mdelay(1); ++ ++ /* enable write */ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_WREN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ /* wait write done status */ ++ while(!(efuse_readl(EFUSE_STATE) & EFUSE_STA_WR_DONE)); ++ ++ /* Disconnect VDDQ pin from 2.5V. */ ++ efuse_vddq_set(0); ++ mdelay(1); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val &= ~(EFUSE_CTRL_PGEN); ++ efuse_writel(val, EFUSE_CTRL); ++} ++ ++static int jz_efuse_write(struct seg_info *info, uint8_t *buf) ++{ ++ int i; ++ unsigned int *data = (volatile unsigned int *)(efuse->iomem + EFUSE_DATA(0)); ++ unsigned int byte_len = (info->bit_num >> 3); ++ unsigned int regval = 0; ++ ++ dev_dbg(efuse->dev,"segment name: %s\nsegment addr: 0x%02x\nbyte num: %d\nbit num: %d\n", ++ info->seg_name, info->offset_address, byte_len, info->bit_num); ++ ++ if(info->seg_id != PRT) { ++ regval = efuse_readl(EFUSE_STATE); ++ if(info->prt_bit & regval) { ++ dev_err(efuse->dev, "segment[%s] has been protected!\n", info->seg_name); ++ return -1; ++ } ++ } ++ ++ memset(data, 0, 4 * 8); ++ memcpy(data, buf, 32); ++ dev_dbg(efuse->dev, "efuse write data:\n"); ++ for(i = 0; i < 8; i++) ++ dev_dbg(efuse->dev,"%08x\n", data[i]); ++ ++ otp_w(info->offset_address, byte_len); ++ ++ return 0; ++} ++ ++ ++static long efuse_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ struct miscdevice *dev = filp->private_data; ++ struct jz_efuse *efuse = container_of(dev, struct jz_efuse, mdev); ++ int ret = 0; ++ ++ mutex_lock(&efuse->lock); ++ efuse->wr_info = (struct efuse_wr_info *)arg; ++ ++ if(efuse->wr_info->seg_id > ARRAY_SIZE(seg_info_array)) { ++ dev_err(efuse->dev, "unknow segment id!\n"); ++ goto exit; ++ } ++ ++ info = seg_info_array[efuse->wr_info->seg_id]; ++ switch (cmd) { ++ case CMD_READ: ++ ret = jz_efuse_read(&info, efuse->wr_info->data); ++ break; ++ case CMD_WRITE: ++ ret = jz_efuse_write(&info, efuse->wr_info->data); ++ break; ++ default: ++ dev_err(efuse->dev, "unknow cmd!\n"); ++ break; ++ } ++exit: ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static struct file_operations efuse_misc_fops = { ++ .open = efuse_open, ++ .release = efuse_release, ++ .unlocked_ioctl = efuse_ioctl, ++}; ++ ++ ++static int set_efuse_timing(struct device *dev) ++{ ++ struct clk *h2clk; ++ struct clk *devclk; ++ unsigned long rate; ++ uint32_t val, ns; ++ int i, rd_strobe, wr_strobe; ++ uint32_t rd_adj, wr_adj; ++ int flag = 0; ++ ++ h2clk = devm_clk_get(dev, "div_ahb2"); ++ if (IS_ERR(h2clk)) { ++ dev_err(efuse->dev, "get h2clk rate fail!\n"); ++ return -1; ++ } ++ ++ devclk = devm_clk_get(dev, "gate_efuse"); ++ if (IS_ERR(devclk)) { ++ dev_err(efuse->dev, "get efuse clk rate fail!\n"); ++ return -1; ++ } ++ clk_prepare_enable(devclk); ++ ++ rate = clk_get_rate(h2clk); ++ ns = 1000000000 / rate; ++ printk("rate = %lu, ns = %d\n", rate, ns); ++ ++ ++ for(i = 0; i < 0x4; i++) ++ if((( i + 1) * ns ) > 7) ++ break; ++ if(i == 0x4) { ++ dev_err(efuse->dev, "get efuse cfg rd_adj fail!\n"); ++ return -1; ++ } ++ rd_adj = wr_adj = i; ++ ++ for(i = 0; i < 0x8; i++) ++ if(((rd_adj + i + 5) * ns ) > 35) ++ break; ++ if(i == 0x8) { ++ dev_err(efuse->dev, "get efuse cfg rd_strobe fail!\n"); ++ return -1; ++ } ++ rd_strobe = i; ++ ++ for(i = 0; i < 0x7ff; i++) { ++ val = (wr_adj + i + 1666) * ns; ++ if(val > 11 * 1000) { ++ val = (wr_adj - i + 1666) * ns; ++ flag = 1; ++ } ++ if(val > 9 * 1000 && val < 11 * 1000) ++ break; ++ } ++ if(i >= 0x7ff) { ++ dev_err(efuse->dev, "get efuse cfg wd_strobe fail!\n"); ++ return -1; ++ } ++ ++ if(flag) ++ i |= 1 << 11; ++ ++ wr_strobe = i; ++ ++ dev_info(efuse->dev, "rd_adj = %d | rd_strobe = %d | " ++ "wr_adj = %d | wr_strobe = %d\n", rd_adj, rd_strobe, ++ wr_adj, wr_strobe); ++ ++ /*set configer register*/ ++ val = rd_adj << EFUSE_CFG_RD_ADJ | rd_strobe << EFUSE_CFG_RD_STROBE; ++ val |= wr_adj << EFUSE_CFG_WR_ADJ | wr_strobe; ++ efuse_writel(val, EFUSE_CFG); ++ ++ clk_put(h2clk); ++ ++ return 0; ++} ++ ++static int show_segment(uint32_t seg_id, char *buf) ++{ ++ int ret = 0; ++ int i = 0; ++ unsigned char val[32] = {0}; ++ char *last = NULL; ++ info = seg_info_array[seg_id]; ++ last = (char *)val + info.bit_num / 8 - 1; ++ ++ jz_efuse_read(&info, val); ++ for(i = 0; i < info.bit_num / 8; i++) ++ ret += snprintf(buf + (i * 2), 3, "%02x", *((uint8_t *)last - i)); ++ strcat(buf, "\n"); ++ ++ return ret + 1; ++} ++ ++static ssize_t chipid_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(CHIPID, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t cutid_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(CUTID, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t trim0_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(TRIM0, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t trim1_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(TRIM1, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t trim2_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(TRIM2, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t trim3_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(TRIM3, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t socinfo_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(SOCINFO, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t hideblk_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(HIDEBLK, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t prt_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(PRT, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static void store_segment(uint32_t seg_id, const char *buf, int len) ++{ ++ int i = 0; ++ unsigned char val[32] = {0}; ++ char tmp[9] = {'\0'}; ++ char *last = (char *)buf + (len - 1); ++ int bit_num = (len - 1) * 4; ++ int byte_len = (len - 1) / 2; ++ info = seg_info_array[seg_id]; ++ ++ memset(val, 0, 32); ++ ++ if (bit_num == info.bit_num) { ++ for (i = 0; i < byte_len; i++) { ++ memcpy(tmp, last - ((i + 1) * 2), 2); ++ sscanf(tmp, "%02hhx", &val[i]); ++ printk("%02x\n", val[i]); ++ } ++ ++ jz_efuse_write(&info, val); ++ } else { ++ printk("%s segment size is %d bits!\n", info.seg_name, info.bit_num); ++ } ++} ++ ++static ssize_t chipid_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(CHIPID, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t cutid_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(CUTID, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t trim0_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(TRIM0, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t trim1_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(TRIM1, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t trim2_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(TRIM2, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t trim3_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(TRIM3, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t socinfo_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(SOCINFO, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t hideblk_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(HIDEBLK, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t prt_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(PRT, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++ ++static DEVICE_ATTR(chipid, S_IRUGO|S_IWUSR, chipid_show, chipid_store); ++static DEVICE_ATTR(cutid, S_IRUGO|S_IWUSR, cutid_show, cutid_store); ++static DEVICE_ATTR(trim0, S_IRUGO|S_IWUSR, trim0_show, trim0_store); ++static DEVICE_ATTR(trim1, S_IRUGO|S_IWUSR, trim1_show, trim1_store); ++static DEVICE_ATTR(trim2, S_IRUGO|S_IWUSR, trim2_show, trim2_store); ++static DEVICE_ATTR(trim3, S_IRUGO|S_IWUSR, trim3_show, trim3_store); ++static DEVICE_ATTR(socinfo, S_IRUGO|S_IWUSR, socinfo_show, socinfo_store); ++static DEVICE_ATTR(hideblk, S_IRUGO|S_IWUSR, hideblk_show, hideblk_store); ++static DEVICE_ATTR(prt, S_IRUGO|S_IWUSR, prt_show, prt_store); ++static DEVICE_ATTR(chipkey, S_IRUGO|S_IWUSR, NULL, NULL); ++static DEVICE_ATTR(userkey, S_IRUGO|S_IWUSR, NULL, NULL); ++static DEVICE_ATTR(nku, S_IRUGO|S_IWUSR, NULL, NULL); ++ ++static struct attribute *efuse_rw_attrs[] = { ++ &dev_attr_chipid.attr, ++ &dev_attr_cutid.attr, ++ &dev_attr_trim0.attr, ++ &dev_attr_trim1.attr, ++ &dev_attr_trim2.attr, ++ &dev_attr_trim3.attr, ++ &dev_attr_socinfo.attr, ++ &dev_attr_hideblk.attr, ++ &dev_attr_prt.attr, ++ &dev_attr_chipkey.attr, ++ &dev_attr_userkey.attr, ++ &dev_attr_nku.attr, ++ NULL, ++}; ++ ++const char efuse_group_name[] = "efuse_rw"; ++static struct attribute_group efuse_rw_attr_group = { ++ .name = efuse_group_name, ++ .attrs = efuse_rw_attrs, ++}; ++ ++ ++#ifdef CONFIG_INGENIC_EFUSE_V2_WRITABLE ++static int of_avd_efuse(struct device *dev) ++{ ++ struct jz_efuse *efuse = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++#if 1 ++ efuse->avd_efuse_en.gpio = of_get_named_gpio_flags(np, "ingenic,efuse-en-gpio", 0, &flags); ++ if(!gpio_is_valid(efuse->avd_efuse_en.gpio)) { ++ ret = efuse->avd_efuse_en.gpio; ++ dev_err(dev, "efuse_en gpio invalid! %d\n", ret); ++ return ret; ++ } ++ ++ ret = devm_gpio_request(dev, efuse->avd_efuse_en.gpio, "efuse-en"); ++ if(ret < 0) { ++ dev_err(dev, "efuse_en gpio request failed! %d\n", ret); ++ return ret; ++ } ++ efuse->avd_efuse_en.level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++#else ++ efuse->pmu_efuse_en = regulator_get(NULL, "LDO2_1V8"); ++ if(!efuse->pmu_efuse_en) { ++ dev_err(dev, "get efuse regulator failed\n"); ++ return -1; ++ } ++#endif ++ return 0; ++} ++#endif ++ ++static int jz_efuse_probe(struct platform_device *pdev) ++{ ++ struct resource *res = NULL; ++ int ret = 0; ++ ++ efuse = devm_kzalloc(&pdev->dev, sizeof(struct jz_efuse), GFP_KERNEL); ++ if (!efuse) { ++ printk("efuse malloc failed!\n"); ++ return -ENOMEM; ++ } ++ ++ mutex_init(&efuse->lock); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (IS_ERR_OR_NULL(res)) { ++ dev_err(&pdev->dev, "get efuse resource failed!\n"); ++ ret = -ENXIO; ++ goto err_free_efuse; ++ } ++ ++ efuse->iomem = devm_ioremap(&pdev->dev, res->start, resource_size(res)); ++ if (IS_ERR_OR_NULL(efuse->iomem)) { ++ dev_err(&pdev->dev, "efuse ioremap failed!\n"); ++ ret = -EBUSY; ++ goto err_free_efuse; ++ } ++ ++ efuse->dev = &pdev->dev; ++ efuse->wr_info = NULL; ++ efuse->mdev.minor = MISC_DYNAMIC_MINOR; ++ efuse->mdev.name = DRV_NAME; ++ efuse->mdev.fops = &efuse_misc_fops; ++ ++ ret = misc_register(&efuse->mdev); ++ if (ret < 0) { ++ dev_err(efuse->dev, "efuse misc_register failed\n"); ++ ret = -EINVAL; ++ goto err_free_efuse_io; ++ } ++ platform_set_drvdata(pdev, efuse); ++#ifdef CONFIG_INGENIC_EFUSE_V2_WRITABLE ++ ret = of_avd_efuse(efuse->dev); ++ if (ret < 0) { ++ goto err_free_efuse_io; ++ } ++ ++ dev_info(efuse->dev, "setup vddq_protect_timer!\n"); ++ timer_setup(&efuse->vddq_protect_timer, efuse_vddq_set_timer, 0); ++ add_timer(&efuse->vddq_protect_timer); ++ ++#endif ++ ret = set_efuse_timing(efuse->dev); ++ if(ret) { ++ dev_err(efuse->dev, "efuse timing setting failed!\n"); ++ ret = -EINVAL; ++ goto err_free_efuse_io; ++ } ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &efuse_rw_attr_group); ++ if (ret) { ++ dev_err(efuse->dev, "device create sysfs group failed\n"); ++ ret = -EINVAL; ++ goto err_free_efuse_io; ++ } ++ ++ ++ dev_info(efuse->dev, "efuse probe success.\n"); ++ return 0; ++ ++ ++err_free_efuse_io: ++ iounmap(efuse->iomem); ++err_free_efuse: ++ kfree(efuse); ++ ++ return ret; ++} ++ ++ ++static int jz_efuse_remove(struct platform_device *dev) ++{ ++ struct jz_efuse *efuse = platform_get_drvdata(dev); ++ ++ misc_deregister(&efuse->mdev); ++#ifdef CONFIG_INGENIC_EFUSE_V2_WRITABLE ++ dev_info(efuse->dev, "del vddq_protect_timer!\n"); ++ del_timer(&efuse->vddq_protect_timer); ++#endif ++ iounmap(efuse->iomem); ++ kfree(efuse); ++ ++ return 0; ++} ++ ++static const struct of_device_id efuse_of_match[] = { ++ { .compatible = "ingenic,x1600-efuse"}, ++ {}, ++}; ++ ++static struct platform_driver jz_efuse_driver = { ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(efuse_of_match), ++ }, ++ .probe = jz_efuse_probe, ++ .remove = jz_efuse_remove, ++}; ++ ++static int __init jz_efuse_init(void) ++{ ++ return platform_driver_register(&jz_efuse_driver); ++} ++ ++static void __exit jz_efuse_exit(void) ++{ ++ platform_driver_unregister(&jz_efuse_driver); ++} ++ ++ ++module_init(jz_efuse_init); ++module_exit(jz_efuse_exit); ++ ++MODULE_DESCRIPTION("efuse v2 driver"); ++MODULE_AUTHOR("zhxiao "); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION("20210823"); +diff --git a/module_drivers/drivers/misc/ingenic_efuse_x2000.c b/module_drivers/drivers/misc/ingenic_efuse_x2000.c +new file mode 100644 +index 000000000..1ec9e467e +--- /dev/null ++++ b/module_drivers/drivers/misc/ingenic_efuse_x2000.c +@@ -0,0 +1,1128 @@ ++/* ++ * linux/drivers/misc/ingenic_efuse_x2000.c - Ingenic efuse driver ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ * Author: . ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#define DEBUG ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "hamming.c" ++ ++ ++#define DRV_NAME "ingenic-efuse" ++ ++#define CMD_WRITE _IOR('E', 100, unsigned int) ++#define CMD_READ _IOR('E', 101, unsigned int) ++ ++struct efuse_wr_info { ++ uint32_t seg_id; ++ uint32_t *data; ++}; ++ ++struct board_gpio { ++ short gpio; ++ short level; ++}; ++ ++struct jz_efuse { ++ struct device *dev; ++ struct miscdevice mdev; ++ struct efuse_wr_info *wr_info; ++ struct mutex lock; ++ void __iomem *iomem; ++#ifdef CONFIG_INGENIC_EFUSE_WRITABLE ++ struct timer_list vddq_protect_timer; ++// struct regulator *pmu_efuse_en; ++ struct board_gpio avd_efuse_en; ++#endif ++}; ++ ++static struct jz_efuse *efuse; ++static struct seg_info info; ++ ++static uint32_t efuse_readl(uint32_t reg_off) ++{ ++ return readl(efuse->iomem + reg_off); ++} ++ ++static void efuse_writel(uint32_t val, uint32_t reg_off) ++{ ++ writel(val, efuse->iomem + reg_off); ++} ++ ++#ifdef CONFIG_INGENIC_EFUSE_WRITABLE ++static void efuse_vddq_set(unsigned long on) ++{ ++ if(on){ ++ mod_timer(&efuse->vddq_protect_timer, jiffies + HZ); ++ } ++ gpio_direction_output(efuse->avd_efuse_en.gpio, !on); ++} ++#else ++static void efuse_vddq_set(unsigned long on) {} ++#endif ++ ++static int efuse_open(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} ++ ++static int efuse_release(struct inode *inode, struct file *filp) ++{ ++ return 0; ++} ++ ++static void otp_r(uint32_t addr, uint32_t wlen) ++{ ++ unsigned int val; ++ int n; ++ ++ efuse_writel(0, EFUSE_CTRL); ++ ++ for(n = 0; n < 8; n++) ++ efuse_writel(0, EFUSE_DATA(n)); ++ ++ /* set read address and data length */ ++ val = addr << EFUSE_CTRL_ADDR | (wlen - 1) << EFUSE_CTRL_LEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val &= ~EFUSE_CTRL_PD; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ /* enable read */ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_RDEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ dev_dbg(efuse->dev,"efuse ctrl regval=0x%x\n",val); ++ /* wait read done status */ ++ while(!(efuse_readl(EFUSE_STATE) & EFUSE_STA_RD_DONE)); ++ ++ efuse_writel(0, EFUSE_CTRL); ++ efuse_writel(EFUSE_CTRL_PD, EFUSE_CTRL); ++} ++ ++void rir_w(uint32_t addr, uint32_t value) ++{ ++ unsigned int val; ++ ++ efuse_writel(value, EFUSE_DATA(0)); ++ efuse_writel(0, EFUSE_CTRL); ++ ++ val = addr << EFUSE_CTRL_ADDR | 0 << EFUSE_CTRL_LEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val &= ~EFUSE_CTRL_PD; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_PS | EFUSE_CTRL_RWL; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_PGEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ efuse_vddq_set(1); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_WREN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ /* wait write done status */ ++ while(!(efuse_readl(EFUSE_STATE) & EFUSE_STA_WR_DONE)); ++ ++ efuse_vddq_set(0); ++ ++ efuse_writel(0, EFUSE_CTRL); ++ efuse_writel(EFUSE_CTRL_PD, EFUSE_CTRL); ++} ++ ++static void rir_r(void) ++{ ++ unsigned int val; ++ ++ efuse_writel(0, EFUSE_CTRL); ++ efuse_writel(0, EFUSE_DATA(0)); ++ efuse_writel(0, EFUSE_DATA(1)); ++ ++ /* set rir read address and data length */ ++ val = 0x1f << EFUSE_CTRL_ADDR | 0x1 << EFUSE_CTRL_LEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val &= ~EFUSE_CTRL_PD; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val &= ~EFUSE_CTRL_PS; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_RWL; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_RDEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ /* wait read done status */ ++ while(!(efuse_readl(EFUSE_STATE) & EFUSE_STA_RD_DONE)); ++ ++ efuse_writel(0, EFUSE_CTRL); ++ efuse_writel(EFUSE_CTRL_PD, EFUSE_CTRL); ++ ++ dev_dbg(efuse->dev, "RIR0=0x%08x\n", efuse_readl(EFUSE_DATA(0))); ++ dev_dbg(efuse->dev, "RIR1=0x%08x\n", efuse_readl(EFUSE_DATA(1))); ++} ++ ++static int rir_op(uint32_t value, uint32_t flag) ++{ ++ unsigned int addr = 0, rf_addr = 0; ++ unsigned int fb_disable = 0; ++ unsigned int ret1, ret2; ++ int rir_num = 0; ++ ++ if(value == 0) ++ return -1; ++ ++ rir_r(); ++ ret1 = efuse_readl(EFUSE_DATA(0)); ++ ret2 = efuse_readl(EFUSE_DATA(1)); ++ ++ if((ret1 & 0xFFFF) && (ret1 & (0xFFFF << 16)) && ++ (ret2 & 0xFFFF) && (ret2 & (0xFFFF << 16))) { ++ if(flag == 1) { ++ fb_disable = 0x1 << 31; ++ rf_addr = 0x20; ++ rir_w(rf_addr, fb_disable); ++ } ++ dev_err(efuse->dev, "not redundancy bits!\n"); ++ return -1; ++ } ++ ++ if(((ret1 & (0xFFFF)) && (ret1 & (0xFFFF << 16)))) { ++ addr = 0x20; ++ if(ret2 & 0xFFFF) { ++ value = value << 16; ++ rir_num = 4; ++ } else { ++ rir_num = 3; ++ } ++ } else { ++ addr = 0; ++ if(ret1 & 0xFFFF) { ++ value = value << 16; ++ rir_num = 2; ++ } else { ++ rir_num = 1; ++ } ++ } ++ ++ if(flag == 1) { ++ switch(rir_num) { ++ case 2: ++ fb_disable = 0x1 << 15; ++ rf_addr = 0x0; ++ break; ++ case 3: ++ fb_disable = 0x1 << 31; ++ rf_addr = 0x0; ++ break; ++ case 4: ++ fb_disable = 0x1 << 15; ++ rf_addr = 0x20; ++ break; ++ default: ++ dev_err(efuse->dev, "not rir %d!\n", rir_num); ++ return -1; ++ } ++ ++ rir_w(rf_addr, fb_disable); ++ } ++ ++ rir_w(addr, value); ++ ++ return 0; ++} ++ ++static int rir_check(struct seg_info *info, uint32_t woffs, uint32_t val) ++{ ++ unsigned int rval, errbits; ++ ++ rir_r(); ++ otp_r(info->word_address + woffs, 1); ++ ++ rval = efuse_readl(EFUSE_DATA(0)); ++ if(woffs == 0) ++ rval &= 0xffffffff << info->begin_align * 8; ++ else if(woffs == info->word_num - 1) ++ rval &= 0xffffffff >> info->end_align* 8; ++ ++ dev_info(efuse->dev, "%08x ^ %08x\n", rval, val); ++ errbits = rval ^ val; ++ ++ return errbits; ++} ++ ++static int rir_repair(struct seg_info *info, uint32_t *buf) ++{ ++ unsigned int errbits, rir_data, repair_result, repair_fail; ++ int ret, n, ebit; ++ ++ for(n = 0; n < info->word_num; n++) { ++ errbits = rir_check(info, n, buf[n]); ++ dev_dbg(efuse->dev, "addr=%x, errbits=0x%08x\n", info->word_address + n, errbits); ++ ++ while((ebit = ffs(errbits)) > 0) { ++ rir_data = 0x1 << EFUSE_RIR_RF; ++ rir_data |= (buf[n] & ebit) << EFUSE_RIR_DATA; ++ rir_data |= (info->word_address + n + ((ebit + info->begin_align * 8) << 6)) << EFUSE_RIR_ADDR; ++// rir_data &= 0 << EFUSE_RIR_DISABLE; ++ ++ ret = rir_op(rir_data, 0); ++ if(ret) { ++ dev_err(efuse->dev, "rir repair failed!\n"); ++ return -1; ++ } ++ ++ do { ++ repair_result = rir_check(info, n, buf[n]); ++ repair_fail = repair_result & (0x1 << ebit); ++ if(repair_fail) { ++ ret = rir_op(rir_data, 1); ++ if(ret) { ++ dev_err(efuse->dev, "rir repair failed!\n"); ++ return -1; ++ } ++ } ++ } while(repair_fail); ++ errbits &= 0 << ebit; ++ } ++ } ++ ++ return 0; ++} ++ ++static void rir_disable_all(void) ++{ ++ rir_r(); ++ rir_w(0x0, (1 << 15)); ++ rir_w(0x0, (1 << 31)); ++ rir_w(0x20, (1 << 15)); ++ rir_w(0x20, (1 << 31)); ++} ++ ++static int jz_efuse_read(struct seg_info *info, uint32_t *buf) ++{ ++ uint32_t val; ++ uint32_t rbuf[8] = {0}; ++ uint32_t hamming_buf[8] = {0}; ++ uint32_t byte_num = 0; ++ uint32_t half_bit_num = 0; ++ uint32_t half_byte_num = 0; ++ uint32_t half_bit_align = 0; ++ uint32_t hamming_bit_num = 0; ++ int n, ret; ++ ++ dev_dbg(efuse->dev,"segment name: %s\nsegment addr: 0x%02x\nbegin align: %d\nend align: %d\n" ++ "word num: %d\nbit num: %d\nverify mode: %d\n", ++ info->seg_name, info->word_address, info->begin_align, info->end_align, ++ info->word_num, info->bit_num, info->verify_mode); ++ ++ rir_r(); ++ otp_r(info->word_address, info->word_num); ++ ++ dev_dbg(efuse->dev, "efuse read data:\n"); ++ for(n = 0; n < info->word_num; n++) { ++ val = efuse_readl(EFUSE_DATA(n)); ++ dev_dbg(efuse->dev, "%08x\n", val); ++ if(n == 0) ++ rbuf[n] = val & (0xffffffff << info->begin_align * 8); ++ if(n == info->word_num - 1) ++ rbuf[n] = val & (0xffffffff >> info->end_align * 8); ++ else ++ rbuf[n] = val; ++ } ++ ++ byte_num = info->bit_num / 8; ++ byte_num += info->bit_num % 8 ? 1 : 0; ++ ++ switch(info->verify_mode) { ++ case HAMMING: ++ hamming_bit_num = info->bit_num + cal_k(info->bit_num); ++// dump(rbuf, 0, hamming_bit_num); ++ decode((unsigned int *)((char *)rbuf + info->begin_align), ++ hamming_bit_num, hamming_buf); ++ memcpy((char *)buf, (char *)hamming_buf, byte_num); ++ break; ++ case DOUBLE: ++ half_bit_num = info->bit_num / 2; ++ half_byte_num = half_bit_num / 8; ++ half_bit_align = half_bit_num % 8; ++// dump((unsigned int *)((char *)rbuf + info->begin_align), 0, half_bit_num); ++// dump((unsigned int *)((char *)rbuf + info->begin_align + half_byte_num), half_bit_align, half_bit_num + half_bit_align); ++ ret = checkbit((unsigned int *)((char *)rbuf + info->begin_align), ++ (unsigned int *)((char *)rbuf + info->begin_align + half_byte_num), ++ 0, half_bit_align, half_bit_num); ++ if(ret){ ++ dev_err(efuse->dev, "double verify failed!\n"); ++ return -1; ++ } ++ memcpy((char *)buf, ((char *)rbuf + info->begin_align), byte_num); ++ break; ++ case NONE: ++ default: ++ memcpy((char *)buf, ((char *)rbuf + info->begin_align), byte_num); ++ break; ++ } ++ ++ /* clear read done status */ ++ efuse_writel(0, EFUSE_STATE); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(jz_efuse_read); ++ ++ ++static void otp_w(uint32_t addr, uint32_t wlen) ++{ ++ unsigned int val; ++ ++ efuse_writel(0, EFUSE_CTRL); ++ ++ /* set write Programming address and data length */ ++ val = addr << EFUSE_CTRL_ADDR | (wlen - 1) << EFUSE_CTRL_LEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val &= ~EFUSE_CTRL_PD; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_PS; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ /* Programming EFUSE enable */ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_PGEN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ /* Connect VDDQ pin from 1.8V */ ++ efuse_vddq_set(1); ++ ++ /* enable write */ ++ val = efuse_readl(EFUSE_CTRL); ++ val |= EFUSE_CTRL_WREN; ++ efuse_writel(val, EFUSE_CTRL); ++ ++ /* wait write done status */ ++ while(!(efuse_readl(EFUSE_STATE) & EFUSE_STA_WR_DONE)); ++ ++ /* Disconnect VDDQ pin from 1.8V. */ ++ efuse_vddq_set(0); ++ ++ efuse_writel(0, EFUSE_CTRL); ++ efuse_writel(EFUSE_CTRL_PD, EFUSE_CTRL); ++} ++ ++static int jz_efuse_write(struct seg_info *info, uint32_t *buf) ++{ ++ unsigned int val[8] = {0}; ++ unsigned char *pbuf = (unsigned char *)val; ++ unsigned char *sbuf = (unsigned char *)buf; ++ uint32_t regval = 0; ++ uint32_t byte_num = 0; ++ uint32_t half_bit_num = 0; ++ uint32_t half_byte_num = 0; ++ uint32_t half_bit_align = 0; ++ uint32_t hamming_bit_num = 0; ++ int ret = 0; ++ int n = 0; ++ ++ ++ dev_dbg(efuse->dev,"segment name: %s\nsegment addr: 0x%02x\nbegin align: %d\nend align: %d\n" ++ "word num: %d\nbit num: %d\nverify mode: %d\n", ++ info->seg_name, info->word_address, info->begin_align, info->end_align, ++ info->word_num, info->bit_num, info->verify_mode); ++ ++ if(info->seg_id != PRT) { ++ regval = efuse_readl(EFUSE_STATE); ++ if(info->prt_bit & regval) { ++ dev_err(efuse->dev, "segment[%s] has been protected!\n", info->seg_name); ++ return -1; ++ } ++ } ++ ++ byte_num = info->bit_num / 8; ++ byte_num += info->bit_num % 8 ? 1 : 0; ++ ++ switch(info->verify_mode) { ++ case HAMMING: ++ hamming_bit_num = info->bit_num + cal_k(info->bit_num); ++// dumphex(buf, info->word_num); ++ encode(buf, info->bit_num, (unsigned int *)(pbuf + info->begin_align)); ++// dump((unsigned int *)pbuf, 0, hamming_bit_num + info->begin_align * 8); ++// dumphex((unsigned int *)(pbuf + info->begin_align), info->word_num); ++ break; ++ case DOUBLE: ++ half_bit_num = info->bit_num / 2; ++ half_byte_num = half_bit_num / 8; ++ half_bit_align = half_bit_num % 8; ++ dump(buf, 0, half_bit_num); ++ dump((unsigned int *)(sbuf + half_byte_num), half_bit_align, half_bit_num + half_bit_align); ++ ret = checkbit(buf,(unsigned int *)(sbuf + half_byte_num), 0, half_bit_align, half_bit_num); ++ if(ret){ ++ dev_err(efuse->dev, "double verify failed!\n"); ++ return -1; ++ } ++ memcpy(pbuf + info->begin_align, (char *)buf, byte_num); ++ break; ++ case NONE: ++ default: ++ memcpy(pbuf + info->begin_align, (char *)buf, byte_num); ++ break; ++ } ++ ++ dev_dbg(efuse->dev, "efuse write data:\n"); ++ for(n = 0; n < info->word_num; n++) { ++ dev_dbg(efuse->dev,"%08x\n", val[n]); ++ efuse_writel(val[n], EFUSE_DATA(n)); ++ } ++ ++ otp_w(info->word_address, info->word_num); ++ ++ if(info->verify_mode == HAMMING) { ++ ret = rir_repair(info, val); ++ if(ret < 0){ ++ dev_err(efuse->dev, "hamming verify failed!\n"); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++static long efuse_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ struct miscdevice *dev = filp->private_data; ++ struct jz_efuse *efuse = container_of(dev, struct jz_efuse, mdev); ++ int ret = 0; ++ ++ ++ mutex_lock(&efuse->lock); ++ efuse->wr_info = (struct efuse_wr_info *)arg; ++ ++ if(efuse->wr_info->seg_id > ARRAY_SIZE(seg_info_array)) { ++ dev_err(efuse->dev, "unknow segment id!\n"); ++ goto exit; ++ } ++ ++ ++ info = seg_info_array[efuse->wr_info->seg_id]; ++ switch (cmd) { ++ case CMD_READ: ++ ret = jz_efuse_read(&info, efuse->wr_info->data); ++ break; ++ case CMD_WRITE: ++ ret = jz_efuse_write(&info, efuse->wr_info->data); ++ break; ++ default: ++ dev_err(efuse->dev, "unknow cmd!\n"); ++ break; ++ } ++exit: ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static struct file_operations efuse_misc_fops = { ++ .open = efuse_open, ++ .release = efuse_release, ++ .unlocked_ioctl = efuse_ioctl, ++}; ++ ++ ++static int set_efuse_timing(struct device *dev) ++{ ++ struct clk *h2clk; ++ struct clk *devclk; ++ unsigned long rate; ++ uint32_t val, ns; ++ int i, rd_strobe, wr_strobe; ++ uint32_t rd_adj, wr_adj; ++ int flag = 0; ++ ++ h2clk = devm_clk_get(dev, "div_ahb2"); ++ if (IS_ERR(h2clk)) { ++ dev_err(efuse->dev, "get h2clk rate fail!\n"); ++ return -1; ++ } ++ ++ devclk = devm_clk_get(dev, "gate_efuse"); ++ if (IS_ERR(devclk)) { ++ dev_err(efuse->dev, "get efuse clk rate fail!\n"); ++ return -1; ++ } ++ clk_prepare_enable(devclk); ++ ++ rate = clk_get_rate(h2clk); ++ ns = 1000000000 / rate; ++ printk("rate = %lu, ns = %d\n", rate, ns); ++ ++ ++ for(i = 0; i < 0x4; i++) ++ if((( i + 1) * ns ) > 2) ++ break; ++ if(i == 0x4) { ++ dev_err(efuse->dev, "get efuse cfg rd_adj fail!\n"); ++ return -1; ++ } ++ rd_adj = wr_adj = i; ++ ++ for(i = 0; i < 0x8; i++) ++ if(((rd_adj + i + 30) * ns ) > 100) ++ break; ++ if(i == 0x8) { ++ dev_err(efuse->dev, "get efuse cfg rd_strobe fail!\n"); ++ return -1; ++ } ++ rd_strobe = i; ++ ++ for(i = 0; i < 0x3ff; i++) { ++ val = (wr_adj + i + 3000) * ns; ++ if(val > 13 * 1000) { ++ val = (wr_adj - i + 3000) * ns; ++ flag = 1; ++ } ++ if(val > 11 * 1000 && val < 13 * 1000) ++ break; ++ } ++ if(i >= 0x3ff) { ++ dev_err(efuse->dev, "get efuse cfg wd_strobe fail!\n"); ++ return -1; ++ } ++ ++ if(flag) ++ i |= 1 << 10; ++ ++ wr_strobe = i; ++ ++ dev_info(efuse->dev, "rd_adj = %d | rd_strobe = %d | " ++ "wr_adj = %d | wr_strobe = %d\n", rd_adj, rd_strobe, ++ wr_adj, wr_strobe); ++ ++ /*set configer register*/ ++ val = rd_adj << EFUSE_CFG_RD_ADJ | rd_strobe << EFUSE_CFG_RD_STROBE; ++ val |= wr_adj << EFUSE_CFG_WR_ADJ | wr_strobe; ++ efuse_writel(val, EFUSE_CFG); ++ ++ clk_put(h2clk); ++ ++ return 0; ++} ++ ++int jz_efuse_read_chipd(uint32_t *chipid){ ++ int ret = 0,i; ++ uint32_t val[8] = {0}; ++ ++ mutex_init(&efuse->lock); ++ info = seg_info_array[CHIPID]; ++ for(i = (info.bit_num / 8/4 -1); i >=0 ; i--){ ++ chipid[(info.bit_num / 8/4 -1) - i] = val[i]; ++ } ++ printk("chipid :%08X %08X %08X %08X\n",chipid[3],chipid[2],chipid[1],chipid[0]); ++ ret = info.bit_num / 8/4; ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++EXPORT_SYMBOL(jz_efuse_read_chipd); ++ ++static int show_segment(uint32_t seg_id, char *buf) ++{ ++ int ret = 0; ++ int i = 0; ++ uint32_t val[8] = {0}; ++ char *ptr; ++ char *last = NULL; ++ info = seg_info_array[seg_id]; ++ last = (char *)val + info.bit_num / 8 - 1; ++ ++ jz_efuse_read(&info, val); ++ if(seg_id == CHIPID){ ++ ptr = buf; ++ *ptr=0; ++ for(i = (info.bit_num / 8/4 -1); i >=0 ; i--) { ++ sprintf(ptr,"%08x", val[i]); ++ if(i>0){ ++ strcat(buf, " "); ++ ptr = buf + strlen(buf); ++ } ++ } ++ strcat(buf, "\n"); ++ ret = strlen(buf); ++ printk("chipid :%s\n",buf); ++ }else { ++ for(i = 0; i < info.bit_num / 8; i++) ++ ret += snprintf(buf + (i * 2), 3, "%02x", *((uint8_t *)last - i)); ++ strcat(buf, "\n"); ++ } ++ ++ return ret + 1; ++} ++ ++static ssize_t chipid_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(CHIPID, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t custid0_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(CUSTID0, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t custid1_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(CUSTID1, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t custid2_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(CUSTID2, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t trim0_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(TRIM0, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t trim1_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(TRIM1, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t trim2_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(TRIM2, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t socinfo_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(SOCINFO, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t prt_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(PRT, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static ssize_t hideblk_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = 0; ++ mutex_init(&efuse->lock); ++ ret = show_segment(HIDEBLK, buf); ++ mutex_unlock(&efuse->lock); ++ return ret; ++} ++ ++static void store_segment(uint32_t seg_id, const char *buf, int len) ++{ ++ int i = 0; ++ uint32_t val[8] = {0}; ++ uint32_t tmpval = 0; ++ char tmp[9] = {'\0'}; ++ char *last = (char *)buf + (len - 1); ++ int bit_num = (len - 1) * 4; ++ int word_num =(len - 1) / 8; ++ int remain_num = (len - 1) % 8; ++ info = seg_info_array[seg_id]; ++ ++ if (bit_num == info.bit_num) { ++ for (i = 0; i < word_num; i++) { ++ memcpy(tmp, last - ((i + 1) * 8), 8); ++ sscanf(tmp, "%08x", &val[i]); ++ printk("%08x\n", val[i]); ++ ++ } ++ ++ if (remain_num > 0) { ++ memcpy(tmp, buf, remain_num); ++ sscanf(tmp, "%08x", &tmpval); ++ tmpval &= (0xffffffff << (8 - remain_num) * 4); ++ tmpval >>= ((8 - remain_num) * 4); ++ val[word_num] = tmpval; ++ printk("%08x\n", val[word_num]); ++ ++ } ++ jz_efuse_write(&info, val); ++ } else { ++ printk("%s segment size is %d bits!\n", info.seg_name, info.bit_num); ++ } ++} ++ ++static ssize_t chipid_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(CHIPID, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t custid0_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(CUSTID0, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t custid1_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(CUSTID1, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t custid2_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(CUSTID2, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t trim0_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(TRIM0, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t trim1_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(TRIM1, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t trim2_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(TRIM2, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t socinfo_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(SOCINFO, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t prt_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(PRT, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++static ssize_t hideblk_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++ mutex_init(&efuse->lock); ++ store_segment(HIDEBLK, buf, n); ++ mutex_unlock(&efuse->lock); ++ return n; ++} ++ ++ ++static DEVICE_ATTR(chipid, S_IRUGO|S_IWUSR, chipid_show, chipid_store); ++static DEVICE_ATTR(custid0, S_IRUGO|S_IWUSR, custid0_show, custid0_store); ++static DEVICE_ATTR(custid1, S_IRUGO|S_IWUSR, custid1_show, custid1_store); ++static DEVICE_ATTR(custid2, S_IRUGO|S_IWUSR, custid2_show, custid2_store); ++static DEVICE_ATTR(trim0, S_IRUGO|S_IWUSR, trim0_show, trim0_store); ++static DEVICE_ATTR(trim1, S_IRUGO|S_IWUSR, trim1_show, trim1_store); ++static DEVICE_ATTR(trim2, S_IRUGO|S_IWUSR, trim2_show, trim2_store); ++static DEVICE_ATTR(socinfo, S_IRUGO|S_IWUSR, socinfo_show, socinfo_store); ++static DEVICE_ATTR(prt, S_IRUGO|S_IWUSR, prt_show, prt_store); ++static DEVICE_ATTR(hideblk, S_IRUGO|S_IWUSR, hideblk_show, hideblk_store); ++static DEVICE_ATTR(chipkey, S_IRUGO|S_IWUSR, NULL, NULL); ++static DEVICE_ATTR(userkey0,S_IRUGO|S_IWUSR, NULL, NULL); ++static DEVICE_ATTR(userkey1,S_IRUGO|S_IWUSR, NULL, NULL); ++static DEVICE_ATTR(nku, S_IRUGO|S_IWUSR, NULL, NULL); ++ ++static struct attribute *efuse_rw_attrs[] = { ++ &dev_attr_chipid.attr, ++ &dev_attr_custid0.attr, ++ &dev_attr_custid1.attr, ++ &dev_attr_custid2.attr, ++ &dev_attr_trim0.attr, ++ &dev_attr_trim1.attr, ++ &dev_attr_trim2.attr, ++ &dev_attr_socinfo.attr, ++ &dev_attr_prt.attr, ++ &dev_attr_hideblk.attr, ++ &dev_attr_chipkey.attr, ++ &dev_attr_userkey0.attr, ++ &dev_attr_userkey1.attr, ++ &dev_attr_nku.attr, ++ NULL, ++}; ++ ++const char efuse_group_name[] = "efuse_rw"; ++static struct attribute_group efuse_rw_attr_group = { ++ .name = efuse_group_name, ++ .attrs = efuse_rw_attrs, ++}; ++ ++ ++#ifdef CONFIG_INGENIC_EFUSE_WRITABLE ++static int of_avd_efuse(struct device *dev) ++{ ++ struct jz_efuse *efuse = dev_get_drvdata(dev); ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++#if 1 ++ efuse->avd_efuse_en.gpio = of_get_named_gpio_flags(np, "ingenic,efuse-en-gpio", 0, &flags); ++ if(!gpio_is_valid(efuse->avd_efuse_en.gpio)) { ++ ret = efuse->avd_efuse_en.gpio; ++ dev_err(dev, "efuse_en gpio invalid! %d\n", ret); ++ return ret; ++ } ++ ++ ret = devm_gpio_request(dev, efuse->avd_efuse_en.gpio, "efuse-en"); ++ if(ret < 0) { ++ dev_err(dev, "efuse_en gpio request failed! %d\n", ret); ++ return ret; ++ } ++ efuse->avd_efuse_en.level = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++#else ++ efuse->pmu_efuse_en = regulator_get(NULL, "LDO2_1V8"); ++ if(!efuse->pmu_efuse_en) { ++ dev_err(dev, "get efuse regulator failed\n"); ++ return -1; ++ } ++#endif ++ return 0; ++} ++#endif ++ ++static int jz_efuse_probe(struct platform_device *pdev) ++{ ++ struct resource *res = NULL; ++ int ret = 0; ++ ++ efuse = devm_kzalloc(&pdev->dev, sizeof(struct jz_efuse), GFP_KERNEL); ++ if (!efuse) { ++ printk("efuse malloc failed!\n"); ++ return -ENOMEM; ++ } ++ ++ mutex_init(&efuse->lock); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (IS_ERR_OR_NULL(res)) { ++ dev_err(&pdev->dev, "get efuse resource failed!\n"); ++ ret = -ENXIO; ++ goto err_free_efuse; ++ } ++ ++ efuse->iomem = devm_ioremap(&pdev->dev, res->start, resource_size(res)); ++ if (IS_ERR_OR_NULL(efuse->iomem)) { ++ dev_err(&pdev->dev, "efuse ioremap failed!\n"); ++ ret = -EBUSY; ++ goto err_free_efuse; ++ } ++ ++ efuse->dev = &pdev->dev; ++ efuse->wr_info = NULL; ++ efuse->mdev.minor = MISC_DYNAMIC_MINOR; ++ efuse->mdev.name = DRV_NAME; ++ efuse->mdev.fops = &efuse_misc_fops; ++ ++ ret = misc_register(&efuse->mdev); ++ if (ret < 0) { ++ dev_err(efuse->dev, "efuse misc_register failed\n"); ++ ret = -EINVAL; ++ goto err_free_efuse_io; ++ } ++ platform_set_drvdata(pdev, efuse); ++ ++#ifdef CONFIG_INGENIC_EFUSE_WRITABLE ++ dev_info(efuse->dev, "setup vddq_protect_timer!\n"); ++ setup_timer(&efuse->vddq_protect_timer, efuse_vddq_set, 0); ++ add_timer(&efuse->vddq_protect_timer); ++ ++ ret = of_avd_efuse(efuse->dev); ++ if (ret < 0) { ++ goto err_free_efuse_io; ++ } ++#endif ++ ret = set_efuse_timing(efuse->dev); ++ if(ret) { ++ dev_err(efuse->dev, "efuse timing setting failed!\n"); ++ ret = -EINVAL; ++ goto err_free_efuse_io; ++ } ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &efuse_rw_attr_group); ++ if (ret) { ++ dev_err(efuse->dev, "device create sysfs group failed\n"); ++ ret = -EINVAL; ++ goto err_free_efuse_io; ++ } ++ ++ ++ dev_info(efuse->dev, "efuse probe success.\n"); ++ return 0; ++ ++ ++err_free_efuse_io: ++ iounmap(efuse->iomem); ++err_free_efuse: ++ kfree(efuse); ++ ++ return ret; ++} ++ ++ ++static int jz_efuse_remove(struct platform_device *dev) ++{ ++ struct jz_efuse *efuse = platform_get_drvdata(dev); ++ ++ misc_deregister(&efuse->mdev); ++#ifdef CONFIG_INGENIC_EFUSE_WRITABLE ++ dev_info(efuse->dev, "del vddq_protect_timer!\n"); ++ del_timer(&efuse->vddq_protect_timer); ++#endif ++ iounmap(efuse->iomem); ++ kfree(efuse); ++ ++ return 0; ++} ++ ++static const struct of_device_id efuse_of_match[] = { ++ { .compatible = "ingenic,x2000-efuse"}, ++ { .compatible = "ingenic,m300-efuse"}, ++ {}, ++}; ++ ++static struct platform_driver jz_efuse_driver = { ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(efuse_of_match), ++ }, ++ .probe = jz_efuse_probe, ++ .remove = jz_efuse_remove, ++}; ++ ++static int __init jz_efuse_init(void) ++{ ++ return platform_driver_register(&jz_efuse_driver); ++} ++ ++static void __exit jz_efuse_exit(void) ++{ ++ platform_driver_unregister(&jz_efuse_driver); ++} ++ ++ ++module_init(jz_efuse_init); ++module_exit(jz_efuse_exit); ++ ++MODULE_DESCRIPTION("X2000_v12 efuse driver"); ++MODULE_AUTHOR("cjwang "); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION("20200312"); +diff --git a/module_drivers/drivers/misc/ingenic_rsa.c b/module_drivers/drivers/misc/ingenic_rsa.c +new file mode 100644 +index 000000000..c9d6ac7c8 +--- /dev/null ++++ b/module_drivers/drivers/misc/ingenic_rsa.c +@@ -0,0 +1,487 @@ ++/* ++ * drivers/misc/ingenic_rsa.c - Ingenic rsa driver ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ * Author: mayuanjun ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_KEY_LEN_WORD 64 ++#define DEV_NAME "rsa" ++ ++#define MCU_BOOT_DDR 0xb3422000 ++ ++#define DRV_NAME "jz-rsa" ++#define MAX_KEY_LEN_WORD 64 ++ ++struct jz_rsa { ++ struct miscdevice mdev; ++ struct device *dev; ++ ++ struct clk *clk_gate; ++ void __iomem *iomem; ++ unsigned int irq; ++ ++ bool busy; ++ ++ struct mutex mutex; ++ ++ wait_queue_head_t wq; ++ ++ unsigned int n_len; ++ unsigned int per_done; ++ unsigned int rsa_done; ++}; ++ ++struct rsa_key { ++ unsigned int *e; ++ unsigned int *n; ++ unsigned int rsa_mode; ++}; ++ ++struct rsa_data { ++ unsigned int *input; ++ unsigned int inlen; ++ unsigned int *output; ++}; ++ ++#define RSA_PERPARE_KEY 0x1 ++#define RSA_DO_CRYPT 0x2 ++ ++#define RSAC 0x0 ++#define RSAE 0x4 ++#define RSAN 0x8 ++#define RSAM 0xc ++#define RSAP 0x10 ++ ++#define RSAC_RSA_INT_M (1 << 17) ++#define RSAC_PER_INT_M (1 << 16) ++#define RSAC_RSA_2048 (1 << 7) ++#define RSAC_RSAC (1 << 6) ++#define RSAC_RSAD (1 << 5) ++#define RSAC_RSAS (1 << 4) ++#define RSAC_PERC (1 << 3) ++#define RSAC_PERD (1 << 2) ++#define RSAC_PERS (1 << 1) ++#define RSAC_EN (1 << 0) ++ ++#define mcu_boot() \ ++ do { \ ++ *(volatile unsigned int *)0xb3421030 &= ~1; \ ++ } while(0) ++ ++#define mcu_reset() \ ++ do { \ ++ *(volatile unsigned int *)0xb3421030 |= 1; \ ++ } while(0) ++ ++static int inline rsa_readl(struct jz_rsa *rsa, unsigned int offset) ++{ ++ return readl(rsa->iomem + offset); ++} ++ ++static void inline rsa_writel(struct jz_rsa *rsa, unsigned int offset, unsigned int val) ++{ ++ writel(val, rsa->iomem + offset); ++} ++ ++static int rsa_perpare_key(struct jz_rsa *rsa, struct rsa_key *rsa_key) ++{ ++ unsigned int n[MAX_KEY_LEN_WORD]; ++ unsigned int e[MAX_KEY_LEN_WORD]; ++ unsigned int keylen = rsa_key->rsa_mode/32; ++ ++ unsigned int tmp; ++ unsigned int i; ++ int ret = 0; ++ ++ mutex_lock(&rsa->mutex); ++ ++ rsa->per_done = 0; ++ rsa->n_len = keylen; ++ ++ if(copy_from_user(e, rsa_key->e, keylen * 4)) { ++ dev_err(rsa->dev, "Failed to copy rsa_key->e form user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ if(copy_from_user(n, rsa_key->n, keylen * 4)) { ++ dev_err(rsa->dev, "Failed to copy rsa_key->n form user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ tmp = rsa_readl(rsa, RSAC); ++ if(rsa_key->rsa_mode == 2048) ++ tmp |= RSAC_RSA_2048; ++ else if (rsa_key->rsa_mode == 1024) ++ tmp &= ~RSAC_RSA_2048; ++ tmp &= ~RSAC_PER_INT_M; ++ rsa_writel(rsa, RSAC, tmp); ++ ++ for(i = 0; i < keylen; i++) { ++ rsa_writel(rsa, RSAE, e[i]); ++ } ++ for(i = 0; i < keylen; i++){ ++ rsa_writel(rsa, RSAN, n[i]); ++ } ++ rsa_writel(rsa, RSAC, RSAC_PERS | rsa_readl(rsa, RSAC)); ++ ++ ret = wait_event_interruptible(rsa->wq, rsa->per_done == 1); ++ if(ret < 0) { ++ dev_err(rsa->dev, "key perpare can't wait irq\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ rsa_writel(rsa, RSAC, RSAC_PERC | rsa_readl(rsa, RSAC)); ++ rsa_writel(rsa, RSAC, ~RSAC_PERC & rsa_readl(rsa, RSAC)); ++ ++ mutex_unlock(&rsa->mutex); ++ return 0; ++ ++err: ++ mutex_unlock(&rsa->mutex); ++ return ret; ++} ++ ++static int rsa_do_crypt(struct jz_rsa *rsa, struct rsa_data *rsa_data) ++{ ++ unsigned int input[MAX_KEY_LEN_WORD]; ++ unsigned int output[MAX_KEY_LEN_WORD]; ++ unsigned int *id = rsa_data->input; ++ unsigned int *od = rsa_data->output; ++ unsigned int keylen = rsa->n_len; ++ unsigned int len = rsa_data->inlen; ++ ++ unsigned int i; ++ int ret = 0; ++ ++ mutex_lock(&rsa->mutex); ++ ++ if(len % keylen) { ++ pr_err("Data len err \n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ while(len > 0) { ++ ++ rsa->rsa_done = 0; ++ ++ if(copy_from_user(input, id, keylen * 4)) { ++ dev_err(rsa->dev, "Failed to copy rsa_data->input form user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ for(i = 0; i < keylen; i++) { ++ rsa_writel(rsa, RSAM, input[i]); ++ } ++ ++ rsa_writel(rsa, RSAC, ~RSAC_RSA_INT_M & rsa_readl(rsa, RSAC)); ++ rsa_writel(rsa, RSAC, RSAC_RSAS | rsa_readl(rsa, RSAC)); ++ ++ ret = wait_event_interruptible(rsa->wq, rsa->rsa_done == 1); ++ if(ret < 0) { ++ dev_err(rsa->dev, "rsa crypt can't wait irq\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ for(i = 0; i < keylen; i++) { ++ output[keylen -1 - i] = rsa_readl(rsa, RSAP); ++ } ++ ++ rsa_writel(rsa, RSAC, rsa_readl(rsa, RSAC) | RSAC_RSAC); ++ rsa_writel(rsa, RSAC, rsa_readl(rsa, RSAC) & ~RSAC_RSAC); ++ ++ if(copy_to_user(od, output, keylen * 4)) { ++ dev_err(rsa->dev, "Failed to copy rsa_data->input form user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ len -= keylen; ++ id += keylen; ++ od += keylen; ++ ++ } ++ ++ mutex_unlock(&rsa->mutex); ++ return 0; ++ ++err: ++ mutex_unlock(&rsa->mutex); ++ return ret; ++ ++} ++ ++static int rsa_open(struct inode *inode, struct file *flip) ++{ ++ struct miscdevice *mdev = flip->private_data; ++ struct jz_rsa *rsa = container_of(mdev, struct jz_rsa, mdev); ++ int tmp; ++ ++ mutex_lock(&rsa->mutex); ++ if(rsa->busy) { ++ dev_err(rsa->dev, "Device is busy!\n"); ++ mutex_unlock(&rsa->mutex); ++ return -EBUSY; ++ } ++ ++ rsa->busy = 1; ++ ++ rsa_writel(rsa, RSAC, RSAC_EN | rsa_readl(rsa, RSAC)); ++ ++ mutex_unlock(&rsa->mutex); ++ ++ return 0; ++} ++ ++static int rsa_release(struct inode *inode, struct file *flip) ++{ ++ struct miscdevice *mdev = flip->private_data; ++ struct jz_rsa *rsa = container_of(mdev, struct jz_rsa, mdev); ++ ++ mutex_lock(&rsa->mutex); ++ ++ rsa->busy = 0; ++ ++ rsa_writel(rsa, RSAC, ~RSAC_EN & rsa_readl(rsa, RSAC)); ++ ++ mutex_unlock(&rsa->mutex); ++ ++ return 0; ++} ++ ++static long rsa_ioctl(struct file *flip, unsigned int cmd, unsigned long args) ++{ ++ struct miscdevice *mdev = flip->private_data; ++ struct jz_rsa *rsa = container_of(mdev, struct jz_rsa, mdev); ++ struct rsa_key rsa_key; ++ struct rsa_data rsa_data; ++ int ret = 0; ++ ++ switch (cmd) { ++ case RSA_PERPARE_KEY: ++ ++ if(copy_from_user(&rsa_key, (void *)args, sizeof(struct rsa_key))) { ++ dev_err(rsa->dev, "Failed to copy rsa_key form user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ ret = rsa_perpare_key(rsa, &rsa_key); ++ ++ break; ++ case RSA_DO_CRYPT: ++ if(rsa->n_len != 32 && rsa->n_len != 64) { ++ dev_err(rsa->dev, "RSA key len err!\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ if(copy_from_user(&rsa_data, (void *)args, sizeof(struct rsa_data))) { ++ dev_err(rsa->dev, "Could not copy data from user!\n"); ++ ret = -EFAULT; ++ goto err; ++ } ++ ++ ret = rsa_do_crypt(rsa, &rsa_data); ++ if(ret < 0) { ++ dev_err(rsa->dev, "Failed to crypt data!\n"); ++ goto err; ++ } ++ ++ break; ++ default: ++ dev_err(rsa->dev, "Unsupport IO cmd: %x\n", cmd); ++ ++ } ++ ++ return 0; ++err: ++ return ret; ++} ++ ++static struct file_operations rsa_misc_fops = { ++ .owner = THIS_MODULE, ++ .open = rsa_open, ++ .release = rsa_release, ++ .unlocked_ioctl = rsa_ioctl, ++}; ++ ++static irqreturn_t rsa_irq(int irq, void *data) ++{ ++ struct jz_rsa *rsa = (struct jz_rsa *)data; ++ ++ if (rsa_readl(rsa, RSAC) & RSAC_RSAD) { ++ rsa_writel(rsa, RSAC, ~RSAC_RSAS & rsa_readl(rsa, RSAC)); ++ rsa_writel(rsa, RSAC, RSAC_RSA_INT_M | rsa_readl(rsa, RSAC)); ++ rsa->rsa_done = 1; ++ } else if (rsa_readl(rsa, RSAC) & RSAC_PERD) { ++ rsa_writel(rsa, RSAC, ~RSAC_PERS & rsa_readl(rsa, RSAC)); ++ rsa_writel(rsa, RSAC, RSAC_PER_INT_M | rsa_readl(rsa, RSAC)); ++ rsa->per_done = 1; ++ } ++ ++ wake_up(&rsa->wq); ++ ++ return IRQ_HANDLED; ++} ++ ++#define cpm_readl(o) (*(volatile unsigned int *)(o)) ++#define cpm_writel(b, o) (*(volatile unsigned int *)(o)) = (b) ++#ifdef CONFIG_SOC_X2500 ++#define CPM_RSACDR (0xb000004C) ++#else ++#define CPM_RSACDR (0xb0000050) ++#endif ++#define CPM_CLKGR0 (0xb0000020) ++static int jz_rsa_probe(struct platform_device * pdev) ++{ ++ int ret = 0; ++ struct jz_rsa *rsa; ++ struct resource *res; ++ unsigned int tmp; ++ ++ rsa = kzalloc(sizeof(struct jz_rsa), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(rsa)) { ++ pr_err("Failed to alloc mem fir jz_rsa!\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ rsa->dev = &pdev->dev; ++ ++ rsa->clk_gate = devm_clk_get(&pdev->dev, "gate_rsa"); ++ if (IS_ERR(rsa->clk_gate)) { ++ dev_err(&pdev->dev, "cannot find rsa clock\n"); ++ ret = PTR_ERR(rsa->clk_gate); ++ goto err1; ++ } ++ clk_prepare_enable(rsa->clk_gate); ++ ++ /* rsa cguclk SACLK/2 */ ++ tmp = cpm_readl(CPM_RSACDR); ++ tmp &= ~(2<<30 | 0xf | 1 << 27); ++ tmp |= 1 << 29; ++ tmp |= 2 << 0; ++ ++ cpm_writel(tmp, CPM_RSACDR); ++ while(cpm_readl(CPM_RSACDR) & (1<<28)); ++ tmp &= ~(1<<29); ++ cpm_writel(tmp, CPM_RSACDR); ++ cpm_writel(0, CPM_CLKGR0); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if(IS_ERR_OR_NULL(res)) { ++ dev_err(rsa->dev, "No iomem resource!\n"); ++ ret = -ENOMEM; ++ goto err1; ++ } ++ ++ rsa->irq = platform_get_irq(pdev, 0); ++ if(rsa->irq < 0) { ++ dev_err(&pdev->dev, "No irq resource!\n"); ++ ret = -ENOMEM; ++ goto err1; ++ } ++ ++ rsa->iomem = devm_ioremap(rsa->dev, res->start, resource_size(res)); ++ if(IS_ERR_OR_NULL(rsa->iomem)) { ++ dev_err(&pdev->dev, "Failed to remap io resources!\n"); ++ ret = -ENOMEM; ++ goto err1; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, rsa->irq, rsa_irq, IRQF_ONESHOT, dev_name(&pdev->dev), rsa); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to request irq!\n"); ++ goto err_request_irq; ++ } ++ ++ init_waitqueue_head(&rsa->wq); ++ ++ platform_set_drvdata(pdev, rsa); ++ ++ mutex_init(&rsa->mutex); ++ ++ rsa->mdev.minor = MISC_DYNAMIC_MINOR; ++ rsa->mdev.name = DEV_NAME; ++ rsa->mdev.fops = &rsa_misc_fops; ++ ret = misc_register(&rsa->mdev); ++ if(ret < 0) { ++ dev_err(&pdev->dev, "Failed to register misc driver!\n"); ++ goto err_misc_register; ++ } ++ ++ dev_info(&pdev->dev, "rsa driver probe ok!\n"); ++ ++ return 0; ++ ++err_misc_register: ++ mutex_destroy(&rsa->mutex); ++err_request_irq: ++ devm_iounmap(rsa->dev, rsa->iomem); ++err1: ++ kfree(rsa); ++err: ++ dev_err(rsa->dev, "initialization failed.\n"); ++ return ret; ++ ++} ++ ++static int jz_rsa_remove(struct platform_device *pdev) ++{ ++ struct jz_rsa *rsa = platform_get_drvdata(pdev); ++ ++ misc_deregister(&rsa->mdev); ++ devm_iounmap(rsa->dev, rsa->iomem); ++ kfree(rsa); ++ ++ return 0; ++} ++ ++static const struct of_device_id ingenic_rsa_dt_match[] = { ++ { .compatible = "ingenic,rsa", .data = NULL }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, aic_dt_match); ++ ++static struct platform_driver ingenic_rsa_driver = { ++ .probe = jz_rsa_probe, ++ .remove = jz_rsa_remove, ++ .driver = { ++ .name = "rsa", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_rsa_dt_match), ++ }, ++}; ++ ++module_platform_driver(ingenic_rsa_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("mayuanjun "); ++MODULE_DESCRIPTION("ingenic rsa driver"); +diff --git a/module_drivers/drivers/mmc/Makefile b/module_drivers/drivers/mmc/Makefile +new file mode 100644 +index 000000000..4ed51fb9a +--- /dev/null ++++ b/module_drivers/drivers/mmc/Makefile +@@ -0,0 +1 @@ ++obj-y += host/ +diff --git a/module_drivers/drivers/mmc/host/Kconfig b/module_drivers/drivers/mmc/host/Kconfig +new file mode 100644 +index 000000000..a174c55a2 +--- /dev/null ++++ b/module_drivers/drivers/mmc/host/Kconfig +@@ -0,0 +1,40 @@ ++ ++config MMC_SDHCI_INGENIC ++ tristate "Ingenic(XBurst2) MMC/SD Card Controller(MSC) support" ++ depends on SOC_X2000 || SOC_X2000_V12 || SOC_M300 || SOC_X2500 || SOC_X2100 ++ select MMC_SDHCI ++ help ++ This selects the Ingenic XBurst2 SD/MMC Card Controller MSC. ++ If you have platform with a SD/Multimedia Card slot and compact ++ with this version, say Y or M here. ++ If unsure, say N. ++ ++config MMC_INDEX_MATCH_CONTROLLER ++ tristate "MMC Index match Controller support." ++ depends on MMC_SDHCI_INGENIC || INGENIC_MMC ++ default n ++ help ++ This selects the MMC Index match Controller support.This option ++ will enable MMC index to match the controller number. If you want ++ mmcblk to correspond to the controller number,say Y or M here. ++ ++ If unsure, say N. ++ ++ ++ config INGENIC_MMC ++ tristate "Ingenic(XBurst) MMC/SD Card Controller(MSC) support" ++ depends on SOC_X1600 || SOC_X1000 || SOC_X1800 || SOC_X1021 || SOC_X1520 || SOC_X1630 ++ help ++ This selects the Ingenic XBurst SD/MMC Card Controller. ++ If you have platform with a SD/Multimedia Card slot and compact ++ with this version, say Y or M here. ++ If unsure, say N. ++ ++ config INGENIC_MMC_MMC0 ++ bool "INGENIC_MMC MMC0" ++ depends on INGENIC_MMC ++ ++ config INGENIC_MMC_MMC1 ++ bool "INGENIC_MMC MMC1" ++ depends on INGENIC_MMC ++ +diff --git a/module_drivers/drivers/mmc/host/Makefile b/module_drivers/drivers/mmc/host/Makefile +new file mode 100644 +index 000000000..1d7c567d1 +--- /dev/null ++++ b/module_drivers/drivers/mmc/host/Makefile +@@ -0,0 +1,5 @@ ++ccflags-y += -I$(srctree)/drivers/mmc/host/ ++ ++obj-$(CONFIG_MMC_SDHCI_INGENIC) += sdhci-ingenic.o ingenic_sdio.o ++obj-$(CONFIG_INGENIC_MMC_MMC0) += ingenic_mmc.o ingenic_sdio.o ++obj-$(CONFIG_INGENIC_MMC_MMC1) += ingenic_mmc.o ingenic_sdio.o +diff --git a/module_drivers/drivers/mmc/host/ingenic_mmc.c b/module_drivers/drivers/mmc/host/ingenic_mmc.c +new file mode 100644 +index 000000000..86a58b456 +--- /dev/null ++++ b/module_drivers/drivers/mmc/host/ingenic_mmc.c +@@ -0,0 +1,1815 @@ ++/* ++ * Ingenic MMC/SD Controller driver ++ * ++ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd. ++ * Written by Large Dipper . ++ * ++ * Modified by qipengzhen 2016-04-21 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ingenic_mmc.h" ++ ++/** ++ * MMC driver parameters ++ */ ++#define TIMEOUT_PERIOD 3000 /* msc operation timeout detect period */ ++#define PIO_THRESHOLD 64 /* use pio mode if data length < PIO_THRESHOLD */ ++#define CLK_RATE (CONFIG_EXTAL_CLOCK * 1000000) ++#define CLK_CTRL ++ ++#define ERROR_IFLG ( \ ++ IFLG_CRC_RES_ERR | \ ++ IFLG_CRC_READ_ERR | \ ++ IFLG_CRC_WRITE_ERR | \ ++ IFLG_TIMEOUT_RES | \ ++ IFLG_TIMEOUT_READ) ++ ++/* ++ * Error status including CRC_READ_ERROR, CRC_WRITE_ERROR, ++ * CRC_RES_ERR, TIME_OUT_RES, TIME_OUT_READ ++ */ ++#define ERROR_STAT 0x3f ++ ++#define ingenic_mmc_check_pending(host, event) \ ++ test_and_clear_bit(event, &host->pending_events) ++#define ingenic_mmc_set_pending(host, event) \ ++ set_bit(event, &host->pending_events) ++#define is_pio_mode(host) \ ++ (host->flags & (1 << INGENIC_MMC_USE_PIO)) ++#define enable_pio_mode(host) \ ++ (host->flags |= (1 << INGENIC_MMC_USE_PIO)) ++#define disable_pio_mode(host) \ ++ (host->flags &= ~(1 << INGENIC_MMC_USE_PIO)) ++ ++static LIST_HEAD(manual_list); ++ ++/*-------------------End structure and macro define------------------------*/ ++ ++#ifndef IT_IS_USED_FOR_DEBUG ++static void ingenic_mmc_dump_reg(struct ingenic_mmc_host *host) ++{ ++ dev_info(host->dev,"\nREG dump:\n" ++ "\tCTRL2\t= 0x%08X\n" ++ "\tSTAT\t= 0x%08X\n" ++ "\tCLKRT\t= 0x%08X\n" ++ "\tCMDAT\t= 0x%08X\n" ++ "\tRESTO\t= 0x%08X\n" ++ "\tRDTO\t= 0x%08X\n" ++ "\tBLKLEN\t= 0x%08X\n" ++ "\tNOB\t= 0x%08X\n" ++ "\tSNOB\t= 0x%08X\n" ++ "\tIMASK\t= 0x%08X\n" ++ "\tIFLG\t= 0x%08X\n" ++ "\tCMD\t= 0x%08X\n" ++ "\tARG\t= 0x%08X\n" ++ "\tRES\t= 0x%08X\n" ++ "\tLPM\t= 0x%08X\n" ++ "\tDMAC\t= 0x%08X\n" ++ "\tDMANDA\t= 0x%08X\n" ++ "\tDMADA\t= 0x%08X\n" ++ "\tDMALEN\t= 0x%08X\n" ++ "\tDMACMD\t= 0x%08X\n" ++ "\tRTCNT\t= 0x%08X\n" ++ "\tDEBUG\t= 0x%08X\n", ++ ++ msc_readl(host, CTRL2), ++ msc_readl(host, STAT), ++ msc_readl(host, CLKRT), ++ msc_readl(host, CMDAT), ++ msc_readl(host, RESTO), ++ msc_readl(host, RDTO), ++ msc_readl(host, BLKLEN), ++ msc_readl(host, NOB), ++ msc_readl(host, SNOB), ++ msc_readl(host, IMASK), ++ msc_readl(host, IFLG), ++ msc_readl(host, CMD), ++ msc_readl(host, ARG), ++ msc_readl(host, RES), ++ msc_readl(host, LPM), ++ msc_readl(host, DMAC), ++ msc_readl(host, DMANDA), ++ msc_readl(host, DMADA), ++ msc_readl(host, DMALEN), ++ msc_readl(host, DMACMD), ++ msc_readl(host, RTCNT), ++ msc_readl(host, DEBUG)); ++} ++#endif ++ ++/* ++ * Functional functions. ++ * ++ * These small function will be called frequently. ++ */ ++static inline void enable_msc_irq(struct ingenic_mmc_host *host, unsigned long bits) ++{ ++ unsigned long imsk; ++ ++ spin_lock_bh(&host->lock); ++ imsk = msc_readl(host, IMASK); ++ imsk &= ~bits; ++ msc_writel(host, IMASK, imsk); ++ spin_unlock_bh(&host->lock); ++} ++ ++static inline void clear_msc_irq(struct ingenic_mmc_host *host, unsigned long bits) ++{ ++ msc_writel(host, IFLG, bits); ++} ++ ++static inline void disable_msc_irq(struct ingenic_mmc_host *host, unsigned long bits) ++{ ++ unsigned long imsk; ++ ++ spin_lock_bh(&host->lock); ++ imsk = msc_readl(host, IMASK); ++ imsk |= bits; ++ msc_writel(host, IMASK, imsk); ++ spin_unlock_bh(&host->lock); ++} ++ ++static inline void ingenic_mmc_reset(struct ingenic_mmc_host *host) ++{ ++ unsigned int clkrt = msc_readl(host, CLKRT); ++ unsigned int cnt = 100 * 1000 * 1000; ++ int vl; ++ ++ msc_writel(host, CTRL, CTRL_RESET); ++ vl = msc_readl(host,CTRL); ++ vl &= ~CTRL_RESET; ++ msc_writel(host, CTRL, vl); ++ ++ while ((msc_readl(host, STAT) & STAT_IS_RESETTING) && (--cnt)); ++ WARN_ON(!cnt); ++ ++ if(host->pdata->sdio_clk) ++ msc_writel(host, CTRL, CTRL_CLOCK_START); ++ else ++ msc_writel(host, LPM, LPM_LPM); ++ ++ msc_writel(host, IMASK, 0xffffffff); ++ msc_writel(host, IFLG, 0xffffffff); ++ ++ msc_writel(host, CLKRT, clkrt); ++} ++ ++static inline void ingenic_mmc_stop_dma(struct ingenic_mmc_host *host) ++{ ++ dev_warn(host->dev, "%s\n", __func__); ++ ++ /* ++ * Theoretically, DMA can't be stopped when transfering, so we can only ++ * diable it when it is out of DMA request. ++ */ ++ msc_writel(host, DMAC, 0); ++} ++ ++static inline int request_need_stop(struct mmc_request *mrq) ++{ ++ return mrq->stop ? 1 : 0; ++} ++static inline void ingenic_mmc_clk_onoff(struct ingenic_mmc_host *host, unsigned int on) ++{ ++ if(on) { ++ clk_prepare_enable(host->clk_cgu); ++ clk_prepare_enable(host->clk_gate); ++ } else { ++ clk_disable_unprepare(host->clk_cgu); ++ clk_disable_unprepare(host->clk_gate); ++ } ++} ++static inline int check_error_status(struct ingenic_mmc_host *host, unsigned int status) ++{ ++ if (status & ERROR_STAT) { ++ dev_err(host->dev, "Error status->0x%08X: cmd=%d, state=%d\n", ++ status, host->cmd->opcode, host->state); ++ return -1; ++ } ++ return 0; ++} ++ ++static int ingenic_mmc_polling_status(struct ingenic_mmc_host *host, unsigned int status) ++{ ++ unsigned int cnt = 100 * 1000 * 1000; ++ while(!(msc_readl(host, STAT) & (status | ERROR_STAT)) \ ++ && test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags) && (--cnt)); ++ ++ if (unlikely(!cnt)) { ++ dev_err(host->dev, "polling status(0x%08X) time out, " ++ "op=%d, status=0x%08X\n", status, ++ host->cmd->opcode, msc_readl(host, STAT)); ++ return -1; ++ } ++ if (unlikely(!test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags))) { ++ dev_err(host->dev, "card remove while polling" ++ "status(0x%08X), op=%d\n", status, host->cmd->opcode); ++ return -1; ++ } ++ if (msc_readl(host, STAT) & ERROR_STAT) { ++ dev_err(host->dev, "polling status(0x%08X) error, " ++ "op=%d, status=0x%08X\n", status, ++ host->cmd->opcode, msc_readl(host, STAT)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void send_stop_command(struct ingenic_mmc_host *host) ++{ ++ struct mmc_command *stop_cmd = host->mrq->stop; ++ ++ msc_writel(host, CMD, stop_cmd->opcode); ++ msc_writel(host, ARG, stop_cmd->arg); ++ msc_writel(host, CMDAT, CMDAT_BUSY | CMDAT_RESPONSE_R1); ++ msc_writel(host, RESTO, 0xff); ++ msc_writel(host, CTRL, CTRL_START_OP); ++ ++ if (ingenic_mmc_polling_status(host, STAT_END_CMD_RES)) ++ stop_cmd->error = -EIO; ++} ++static void ingenic_mmc_command_done(struct ingenic_mmc_host *host, struct mmc_command *cmd) ++{ ++ unsigned long res; ++ ++ if ((host->cmdat & CMDAT_RESPONSE_MASK) == CMDAT_RESPONSE_R2) { ++ int i; ++ res = msc_readl(host, RES); ++ for (i = 0 ; i < 4 ; i++) { ++ cmd->resp[i] = res << 24; ++ res = msc_readl(host, RES); ++ cmd->resp[i] |= res << 8; ++ res = msc_readl(host, RES); ++ cmd->resp[i] |= res >> 8; ++ } ++ } else { ++ res = msc_readl(host, RES); ++ cmd->resp[0] = res << 24; ++ res = msc_readl(host, RES); ++ cmd->resp[0] |= res << 8; ++ res = msc_readl(host, RES); ++ cmd->resp[0] |= res & 0xff; ++ } ++ ++ clear_msc_irq(host, IFLG_END_CMD_RES); ++} ++ ++static void ingenic_mmc_data_done(struct ingenic_mmc_host *host) ++{ ++ struct mmc_data *data = host->data; ++ ++ if (data->error == 0) ++ data->bytes_xfered = (data->blocks * data->blksz); ++ else { ++ ingenic_mmc_stop_dma(host); ++ data->bytes_xfered = 0; ++ dev_err(host->dev, "error when request done\n"); ++ } ++ ++ del_timer_sync(&host->request_timer); ++ mmc_request_done(host->mmc, host->mrq); ++} ++ ++/*------------------------End functional functions-------------------------*/ ++ ++/* ++ * State machine. ++ * ++ * The state machine is the manager of the mmc_request. It's triggered by ++ * MSC interrupt and work in interrupt context. ++ */ ++static void ingenic_mmc_state_machine(struct ingenic_mmc_host *host, unsigned int status) ++{ ++ struct mmc_request *mrq = host->mrq; ++ struct mmc_data *data = host->data; ++ ++ WARN_ON(host->double_enter++); ++start: ++ dev_dbg(host->dev, "enter state: %d\n", host->state); ++ ++ switch (host->state) { ++ case STATE_IDLE: ++ dev_warn(host->dev, "WARN: enter state machine with IDLE\n"); ++ break; ++ ++ case STATE_WAITING_RESP: ++ if (!ingenic_mmc_check_pending(host, EVENT_CMD_COMPLETE)) ++ break; ++ if (unlikely(check_error_status(host, status) != 0)) { ++ host->state = STATE_ERROR; ++ clear_msc_irq(host, IFLG_CRC_RES_ERR ++ | IFLG_TIMEOUT_RES ++ | IFLG_END_CMD_RES); ++ goto start; ++ } ++ ingenic_mmc_command_done(host, mrq->cmd); ++ if (!data) { ++ host->state = STATE_IDLE; ++ del_timer_sync(&host->request_timer); ++ mmc_request_done(host->mmc, host->mrq); ++ break; ++ } ++ host->state = STATE_WAITING_DATA; ++ break; ++ ++ case STATE_WAITING_DATA: ++ if (!ingenic_mmc_check_pending(host, EVENT_DATA_COMPLETE)) ++ break; ++ if (unlikely(check_error_status(host, status) != 0)) { ++ clear_msc_irq(host, IFLG_DATA_TRAN_DONE ++ | IFLG_CRC_READ_ERR ++ | IFLG_CRC_WRITE_ERR ++ | IFLG_TIMEOUT_READ); ++ if (request_need_stop(host->mrq)) ++ send_stop_command(host); ++ host->state = STATE_ERROR; ++ goto start; ++ } ++ ++ if (request_need_stop(host->mrq)) { ++ if (likely(msc_readl(host, STAT) & STAT_AUTO_CMD12_DONE)) { ++ disable_msc_irq(host, IMASK_AUTO_CMD12_DONE); ++ clear_msc_irq(host, IFLG_AUTO_CMD12_DONE); ++ host->state = STATE_IDLE; ++ ingenic_mmc_data_done(host); ++ } else { ++ enable_msc_irq(host, IMASK_AUTO_CMD12_DONE); ++ if (msc_readl(host, STAT) & STAT_AUTO_CMD12_DONE) { ++ disable_msc_irq(host, IMASK_AUTO_CMD12_DONE); ++ clear_msc_irq(host, IFLG_AUTO_CMD12_DONE); ++ host->state = STATE_IDLE; ++ ingenic_mmc_data_done(host); ++ } else ++ host->state = STATE_SENDING_STOP; ++ } ++ } else { ++ host->state = STATE_IDLE; ++ ingenic_mmc_data_done(host); ++ } ++ break; ++ ++ case STATE_SENDING_STOP: ++ if (!ingenic_mmc_check_pending(host, EVENT_STOP_COMPLETE)) ++ break; ++ host->state = STATE_IDLE; ++ ingenic_mmc_data_done(host); ++ break; ++ ++ case STATE_ERROR: ++ if (host->state == STATE_WAITING_DATA) ++ host->data->error = -1; ++ host->cmd->error = -1; ++ ++ if (data) { ++ data->bytes_xfered = 0; ++ /* Whether should we stop DMA here? */ ++ } ++ del_timer_sync(&host->request_timer); ++ host->state = STATE_IDLE; ++ mmc_request_done(host->mmc, host->mrq); ++ break; ++ } ++ ++ dev_dbg(host->dev, "exit state: %d\n", host->state); ++ host->double_enter--; ++} ++ ++static irqreturn_t ingenic_mmc_thread_handle(int irq, void *dev_id) ++{ ++ struct ingenic_mmc_host *host = (struct ingenic_mmc_host *)dev_id; ++ unsigned int iflg, imask, pending, status; ++ ++start: ++ iflg = msc_readl(host, IFLG); ++ imask = msc_readl(host, IMASK); ++ pending = iflg & ~imask; ++ status = msc_readl(host, STAT); ++ dev_dbg(host->dev, "%s: iflg-0x%08X imask-0x%08X status-0x%08X\n", ++ __func__, iflg, imask, status); ++ ++ if (!pending) { ++ goto out; ++ } else if (pending & IFLG_SDIO) { ++ mmc_signal_sdio_irq(host->mmc); ++ goto out; ++ } else if (pending & ERROR_IFLG) { ++ unsigned int mask = ERROR_IFLG; ++ ++ dev_dbg(host->dev, "%s: iflg-0x%08X imask-0x%08X status-0x%08X\n", ++ __func__, iflg, imask, status); ++ ++ dev_dbg(host->dev, "err%d cmd%d iflg%08X status%08X\n", ++ host->state, host->cmd ? host->cmd->opcode : -1, iflg, status); ++ ++ if (host->state == STATE_WAITING_RESP) ++ mask |= IMASK_END_CMD_RES; ++ else if (host->state == STATE_WAITING_DATA) ++ mask |= IMASK_WR_ALL_DONE | IMASK_DMA_DATA_DONE; ++ ++ clear_msc_irq(host, mask); ++ disable_msc_irq(host, mask); ++ ++ /* ++ * It seems that cmd53 CRC error occurs frequently ++ * at 50mHz clk, but it disappear at 40mHz. In case of ++ * it happens, we add retry here to try to fix the error. ++ */ ++ if ((host->cmd->opcode == 53) ++ && (status & STAT_CRC_READ_ERROR)) { ++ dev_err(host->dev, "cmd53 crc error, retry.\n"); ++ host->cmd->error = -1; ++ host->cmd->retries = 1; ++ host->data->bytes_xfered = 0; ++ del_timer_sync(&host->request_timer); ++ host->state = STATE_IDLE; ++ mmc_request_done(host->mmc, host->mrq); ++ goto out; ++ } ++ host->state = STATE_ERROR; ++ ingenic_mmc_state_machine(host, status); ++ goto out; ++ ++ } else if (pending & IFLG_END_CMD_RES) { ++ ingenic_mmc_set_pending(host, EVENT_CMD_COMPLETE); ++ disable_msc_irq(host, IMASK_END_CMD_RES | \ ++ IMASK_CRC_RES_ERR | IMASK_TIME_OUT_RES); ++ ingenic_mmc_state_machine(host, status); ++ } else if (pending & IFLG_WR_ALL_DONE) { ++ ingenic_mmc_set_pending(host, EVENT_DATA_COMPLETE); ++ clear_msc_irq(host, IFLG_WR_ALL_DONE ++ | IFLG_DMAEND ++ | IFLG_DATA_TRAN_DONE ++ | IFLG_PRG_DONE); ++ disable_msc_irq(host, IMASK_WR_ALL_DONE | IMASK_CRC_WRITE_ERR); ++ ingenic_mmc_state_machine(host, status); ++ ++ } else if (pending & IFLG_DMA_DATA_DONE) { ++ ingenic_mmc_set_pending(host, EVENT_DATA_COMPLETE); ++ clear_msc_irq(host, IFLG_DATA_TRAN_DONE | IFLG_DMAEND | ++ IFLG_DMA_DATA_DONE); ++ disable_msc_irq(host, IMASK_DMA_DATA_DONE | IMASK_CRC_READ_ERR); ++ ingenic_mmc_state_machine(host, status); ++ } else if (pending & IFLG_AUTO_CMD12_DONE) { ++ ingenic_mmc_set_pending(host, EVENT_STOP_COMPLETE); ++ clear_msc_irq(host, IFLG_AUTO_CMD12_DONE); ++ disable_msc_irq(host, IMASK_AUTO_CMD12_DONE); ++ ingenic_mmc_state_machine(host, status); ++ ++ } else ++ dev_warn(host->dev, "state-%d: Nothing happens?!\n", host->state); ++ ++ /* ++ * Check if the status has already changed. If so, goto start so that ++ * we can avoid an interrupt. ++ */ ++ if (status != msc_readl(host, STAT)) { ++ goto start; ++ } ++ ++out: ++ return IRQ_HANDLED; ++} ++/*--------------------------End state machine------------------------------*/ ++ ++/* ++ * DMA handler. ++ * ++ * Descriptor DMA transfer that can handle scatter gather list directly ++ * without bounce buffer which may cause a big deal of memcpy. ++ */ ++static inline void sg_to_desc(struct scatterlist *sgentry, struct desc_hd *dhd) ++{ ++ dhd->dma_desc->da = sg_phys(sgentry); ++ dhd->dma_desc->len = sg_dma_len(sgentry); ++ dhd->dma_desc->dcmd = DMACMD_LINK; ++} ++ ++static void ingenic_mmc_submit_dma(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ int i = 0; ++ struct scatterlist *sgentry; ++ struct desc_hd *dhd = &(host->decshds[0]); ++ ++ dma_map_sg(host->dev, data->sg, data->sg_len, ++ data->flags & MMC_DATA_WRITE ++ ? DMA_TO_DEVICE : DMA_FROM_DEVICE); ++ ++ for_each_sg(data->sg, sgentry, data->sg_len, i) { ++ sg_to_desc(sgentry, dhd); ++ if ((data->sg_len - i) > 1) { ++ if (unlikely(dhd->next == NULL)) ++ dev_err(host->dev, "dhd->next == NULL\n"); ++ else { ++ dhd->dma_desc->nda = dhd->next->dma_desc_phys_addr; ++ dhd = dhd->next; ++ } ++ } ++ } ++ ++ dma_unmap_sg(host->dev, data->sg, data->sg_len, ++ data->flags & MMC_DATA_WRITE ++ ? DMA_TO_DEVICE : DMA_FROM_DEVICE); ++ ++ dhd->dma_desc->dcmd |= DMACMD_ENDI; ++ dhd->dma_desc->dcmd &= ~DMACMD_LINK; ++} ++ ++static inline unsigned int get_incr(unsigned int dma_len) ++{ ++ unsigned int incr = 0; ++ ++ BUG_ON(!dma_len); ++#if 0 ++ /* ++ * BUG here! ++ */ ++ switch (dma_len) { ++#define _CASE(S,D) case S: incr = D; break ++ _CASE(1 ... 31, 0); ++ _CASE(32 ... 63, 1); ++ default: ++ incr = 2; ++ break; ++#undef _CASE ++ } ++#else ++ incr = 2; ++#endif ++ return incr; ++} ++ ++/* #define PERFORMANCE_DMA */ ++static inline void ingenic_mmc_dma_start(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ dma_addr_t dma_addr = sg_phys(data->sg); ++ unsigned int dma_len = sg_dma_len(data->sg); ++ unsigned int dmac; ++ ++#ifdef PERFORMANCE_DMA ++ dmac = (get_incr(dma_len) << DMAC_INCR_SHF) | DMAC_DMAEN | DMAC_MODE_SEL; ++#else ++ dmac = (get_incr(dma_len) << DMAC_INCR_SHF) | DMAC_DMAEN; ++#endif ++ ++ if ((dma_addr & 0x3) || (dma_len & 0x3)) { ++ dmac |= DMAC_ALIGNEN; ++ if (dma_addr & 0x3) ++ dmac |= (dma_addr % 4) << DMAC_AOFST_SHF; ++ } ++ msc_writel(host, DMANDA, host->decshds[0].dma_desc_phys_addr); ++ msc_writel(host, DMAC, dmac); ++} ++ ++/*----------------------------End DMA handler------------------------------*/ ++ ++/* ++ * PIO transfer mode. ++ * ++ * Functions of PIO read/write mode that can handle 1, 2 or 3 bytes transfer ++ * even though the FIFO register is 32-bits width. ++ * It's better just used for test. ++ */ ++static int wait_cmd_response(struct ingenic_mmc_host *host) ++{ ++ if (ingenic_mmc_polling_status(host, STAT_END_CMD_RES) < 0) { ++ dev_err(host->dev, "PIO mode: command response error\n"); ++ return -1; ++ } ++ msc_writel(host, IFLG, IFLG_END_CMD_RES); ++ return 0; ++} ++ ++static void do_pio_read(struct ingenic_mmc_host *host, ++ unsigned int *addr, unsigned int cnt) ++{ ++ int i = 0; ++ unsigned int status = 0; ++ ++ for (i = 0; i < cnt / 4; i++) { ++ while (((status = msc_readl(host, STAT)) ++ & STAT_DATA_FIFO_EMPTY) ++ && test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)); ++ ++ if (!test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)) { ++ host->data->error = -ENOMEDIUM; ++ dev_err(host->dev, ++ "PIO mode: card remove while reading\n"); ++ return; ++ } ++ if (check_error_status(host, status)) { ++ host->data->error = -1; ++ return; ++ } ++ *addr++ = msc_readl(host, RXFIFO); ++ } ++ ++ /* ++ * These codes handle the last 1, 2 or 3 bytes transfer. ++ */ ++ if (cnt & 3) { ++ u32 n = cnt & 3; ++ u32 data = msc_readl(host, RXFIFO); ++ u8 *p = (u8 *)addr; ++ ++ while (n--) { ++ *p++ = data; ++ data >>= 8; ++ } ++ } ++} ++ ++static void do_pio_write(struct ingenic_mmc_host *host, ++ unsigned int *addr, unsigned int cnt) ++{ ++ int i = 0; ++ unsigned int status = 0; ++ ++ for (i = 0; i < (cnt / 4); i++) { ++ while (((status = msc_readl(host, STAT)) ++ & STAT_DATA_FIFO_FULL) ++ && test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)); ++ ++ if(!test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)) { ++ host->data->error = -ENOMEDIUM; ++ dev_err(host->dev, ++ "PIO mode: card remove while writing\n"); ++ break; ++ } ++ if (check_error_status(host, status)) { ++ host->data->error = -1; ++ return; ++ } ++ msc_writel(host, TXFIFO, *addr++); ++ } ++ ++ /* ++ * These codes handle the last 1, 2 or 3 bytes transfer. ++ */ ++ if (cnt & 3) { ++ u32 data = 0; ++ u8 *p = (u8 *)addr; ++ ++ for (i = 0; i < (cnt & 3); i++) ++ data |= *p++ << (8 * i); ++ ++ msc_writel(host, TXFIFO, data); ++ } ++} ++ ++static inline void pio_trans_start(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ unsigned int *addr = sg_virt(data->sg); ++ unsigned int cnt = sg_dma_len(data->sg); ++ ++ if (data->flags & MMC_DATA_WRITE) ++ do_pio_write(host, addr, cnt); ++ else ++ do_pio_read(host, addr, cnt); ++} ++ ++static void pio_trans_done(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ if (data->error == 0) ++ data->bytes_xfered = data->blocks * data->blksz; ++ else ++ data->bytes_xfered = 0; ++ ++ if (host->mrq->stop) { ++ if (ingenic_mmc_polling_status(host, STAT_AUTO_CMD12_DONE) < 0) ++ data->error = -EIO; ++ } ++ ++ if (data->flags & MMC_DATA_WRITE) { ++ if (ingenic_mmc_polling_status(host, STAT_PRG_DONE) < 0) { ++ data->error = -EIO; ++ } ++ clear_msc_irq(host, IFLG_PRG_DONE); ++ } else { ++ if (ingenic_mmc_polling_status(host, STAT_DATA_TRAN_DONE) < 0) { ++ data->error = -EIO; ++ } ++ clear_msc_irq(host, IFLG_DATA_TRAN_DONE); ++ } ++} ++ ++/*-------------------------End PIO transfer mode---------------------------*/ ++ ++/* ++ * Achieve mmc_request here. ++ */ ++static void ingenic_mmc_data_pre(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ unsigned int nob = data->blocks; ++ unsigned long cmdat,imsk; ++ ++ msc_writel(host, RDTO, 0xffffff); ++ msc_writel(host, NOB, nob); ++ msc_writel(host, BLKLEN, data->blksz); ++ cmdat = CMDAT_DATA_EN; ++ ++ msc_writel(host, CMDAT, CMDAT_DATA_EN); ++ ++ ++ if (data->flags & MMC_DATA_WRITE) { ++ cmdat |= CMDAT_WRITE_READ; ++ imsk = IMASK_WR_ALL_DONE | IMASK_CRC_WRITE_ERR; ++ } else if (data->flags & MMC_DATA_READ) { ++ cmdat &= ~CMDAT_WRITE_READ; ++ imsk = IMASK_DMA_DATA_DONE ++ | IMASK_TIME_OUT_READ ++ | IMASK_CRC_READ_ERR; ++ } else { ++ dev_err(host->dev, "data direction confused\n"); ++ BUG_ON(1); ++ } ++ host->cmdat |= cmdat; ++ ++ if (!is_pio_mode(host)) { ++ ingenic_mmc_submit_dma(host, data); ++ clear_msc_irq(host, IFLG_PRG_DONE); ++ enable_msc_irq(host, imsk); ++ } ++} ++ ++static void ingenic_mmc_data_start(struct ingenic_mmc_host *host, struct mmc_data *data) ++{ ++ if (is_pio_mode(host)) { ++ pio_trans_start(host, data); ++ pio_trans_done(host, data); ++ del_timer_sync(&host->request_timer); ++ if (!(host->pdata->pio_mode)) ++ disable_pio_mode(host); ++ mmc_request_done(host->mmc, host->mrq); ++ } else { ++ ingenic_mmc_dma_start(host, data); ++ } ++} ++ ++static void ingenic_mmc_command_start(struct ingenic_mmc_host *host, struct mmc_command *cmd) ++{ ++ unsigned long cmdat = 0; ++ unsigned long imsk; ++ ++ if (cmd->flags & MMC_RSP_BUSY) ++ cmdat |= CMDAT_BUSY; ++ if (request_need_stop(host->mrq)) ++ cmdat |= CMDAT_AUTO_CMD12; ++ ++ ++ switch (mmc_resp_type(cmd)) { ++#define _CASE(S,D) case MMC_RSP_##S: cmdat |= CMDAT_RESPONSE_##D; break ++ _CASE(R1, R1); /* r1 = r5,r6,r7 */ ++ _CASE(R1B, R1); ++ _CASE(R2, R2); ++ _CASE(R3, R3); /* r3 = r4 */ ++ default: ++ break; ++#undef _CASE ++ } ++ host->cmdat |= cmdat; ++ if (!is_pio_mode(host)) { ++ imsk = IMASK_TIME_OUT_RES | IMASK_END_CMD_RES; ++ enable_msc_irq(host, imsk); ++ host->state = STATE_WAITING_RESP; ++ } ++ msc_writel(host, CMD, cmd->opcode); ++ msc_writel(host, ARG, cmd->arg); ++ msc_writel(host, CMDAT, host->cmdat); ++ msc_writel(host, CTRL, CTRL_START_OP); ++ if (is_pio_mode(host)) { ++ if (wait_cmd_response(host) < 0) { ++ cmd->error = -ETIMEDOUT; ++ del_timer_sync(&host->request_timer); ++ mmc_request_done(host->mmc, host->mrq); ++ return; ++ } ++ ingenic_mmc_command_done(host, host->cmd); ++ if (!host->data) { ++ del_timer_sync(&host->request_timer); ++ mmc_request_done(host->mmc, host->mrq); ++ } ++ } ++} ++ ++static void ingenic_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) ++{ ++ struct ingenic_mmc_host *host = mmc_priv(mmc); ++ if (!test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)) { ++ dev_vdbg(host->dev, "No card present\n"); ++ mrq->cmd->error = -ENOMEDIUM; ++ mmc_request_done(mmc, mrq); ++ return; ++ } ++ ++ /* ++ * It means that this request may flush cache in interrupt context. ++ * It never happens in design, but we add BUG_ON here to prevent it. ++ */ ++ if ((host->state != STATE_IDLE) && (mrq->data != NULL)) { ++ dev_warn(host->dev, "operate in non-idle state\n"); ++ WARN_ON(1); ++ } ++ ++ host->mrq = mrq; ++ host->data = mrq->data; ++ host->cmd = mrq->cmd; ++ if (host->data) ++ dev_dbg(host->dev, "op:%d arg:0x%08X sz:%uk\n", ++ host->cmd->opcode, host->cmd->arg, ++ host->data->blocks >> 1); ++ else ++ dev_dbg(host->dev, "op:%d\n", host->cmd->opcode); ++ ++ host->cmdat = host->cmdat_def; ++ if(host->data) { ++ if ((host->data->sg_len == 1) ++ && (sg_dma_len(host->data->sg)) < PIO_THRESHOLD) { ++ enable_pio_mode(host); ++ } ++ ++ ingenic_mmc_data_pre(host, host->data); ++ } ++ /* ++ * We would get mmc_request_done at last, unless some terrible error ++ * occurs such as intensity rebounding of VDD, that maybe result in ++ * no action to complete the request. ++ */ ++ host->timeout_cnt = 0; ++ mod_timer(&host->request_timer, jiffies + ++ msecs_to_jiffies(TIMEOUT_PERIOD)); ++ ingenic_mmc_command_start(host, host->cmd); ++ if (host->data) { ++ ingenic_mmc_data_start(host, host->data); ++ ++ } ++ if (unlikely(test_and_clear_bit(INGENIC_MMC_CARD_NEED_INIT, &host->flags))) ++ host->cmdat_def &= ~CMDAT_INIT; ++} ++ ++static void ingenic_mmc_request_timeout(struct timer_list *t) ++{ ++ struct ingenic_mmc_host *host = from_timer(host, t, request_timer); ++ unsigned int status = msc_readl(host, STAT); ++ if (host->timeout_cnt++ < (3000 / TIMEOUT_PERIOD)) { ++ dev_warn(host->dev, "timeout %dms op:%d %s sz:%d state:%d " ++ "STAT:0x%08X DMALEN:0x%08X blks:%d/%d clk:%s\n", ++ host->timeout_cnt * TIMEOUT_PERIOD, ++ host->cmd->opcode, ++ host->data ++ ? (host->data->flags & MMC_DATA_WRITE ? "w" : "r") ++ : "", ++ host->data ? host->data->blocks << 9 : 0, ++ host->state, ++ status, ++ msc_readl(host, DMALEN), ++ msc_readl(host, SNOB), ++ msc_readl(host, NOB), ++ __clk_is_enabled(host->clk_cgu) ? "enable" : "disable"); ++ mod_timer(&host->request_timer, jiffies + ++ msecs_to_jiffies(TIMEOUT_PERIOD)); ++ return; ++ ++ } else if (host->timeout_cnt++ < (60000 / TIMEOUT_PERIOD)) { ++ mod_timer(&host->request_timer, jiffies + ++ msecs_to_jiffies(TIMEOUT_PERIOD)); ++ return; ++ } ++ ++ dev_err(host->dev, "request time out, op=%d arg=0x%08X, " ++ "sz:%dB state=%d, status=0x%08X, pending=0x%08X, nr_desc=%d\n", ++ host->cmd->opcode, host->cmd->arg, ++ host->data ? host->data->blocks << 9 : -1, ++ host->state, status, (u32)host->pending_events, ++ host->data ? host->data->sg_len : 0); ++ ingenic_mmc_dump_reg(host); ++ ++ if (host->data) { ++ int i; ++ dev_err(host->dev, "Descriptor dump:\n"); ++ for (i = 0; i < MAX_SEGS; i++) { ++ unsigned int *desc = (unsigned int *)host->decshds[i].dma_desc; ++ dev_err(host->dev, "\t%03d\t nda=%08X da=%08X len=%08X dcmd=%08X\n", ++ i, *desc, *(desc+1), *(desc+2), *(desc+3)); ++ } ++ dev_err(host->dev, "\n"); ++ } ++ ++ if (host->mrq) { ++ if (request_need_stop(host->mrq)) { ++ send_stop_command(host); ++ } ++ host->cmd->error = -ENOMEDIUM; ++ host->state = STATE_IDLE; ++ mmc_request_done(host->mmc, host->mrq); ++ } ++} ++ ++/*---------------------------End mmc_request-------------------------------*/ ++ ++/* ++ * Card insert and remove handler. ++ */ ++static irqreturn_t ingenic_mmc_detect_handler(int irq, void *dev_id) ++{ ++ struct ingenic_mmc_host *host = (struct ingenic_mmc_host *)dev_id; ++ ++ disable_irq_nosync(irq); ++ mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(200)); ++ ++ return IRQ_HANDLED; ++} ++ ++static int get_pin_status(struct ingenic_mmc_pin *pin) ++{ ++ int val; ++ ++ if(!gpio_is_valid(pin->num)) { ++ return -1; ++ } ++ val = gpio_get_value(pin->num); ++ ++ if (pin->enable_level == LOW_ENABLE) ++ return !val; ++ return val; ++} ++ ++static void set_pin_status(struct ingenic_mmc_pin *pin, int enable) ++{ ++ if(gpio_is_valid(pin->num)) { ++ return; ++ } ++ ++ if (pin->enable_level == LOW_ENABLE) ++ enable = !enable; ++ gpio_set_value(pin->num, enable); ++} ++ ++static void ingenic_mmc_detect(struct timer_list *t) ++{ ++ struct ingenic_mmc_host *host = from_timer(host, t, detect_timer); ++ bool present; ++ bool present_old; ++ static int irq_disable_count; ++ ++ present = get_pin_status(&host->pdata->gpio->cd); ++ present_old = test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ ++ if ((present != present_old) || (present_old && host->mmc->card)) { ++ if (present && present_old) ++ dev_warn(host->dev, "rapidly remove\n"); ++ else ++ dev_notice(host->dev, "card %s, state=%d\n", ++ present ? "inserted" : "removed", host->state); ++ ++ if (!present || present_old) { ++ clear_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ if(!irq_disable_count) { ++ disable_irq_nosync(host->irq); ++ irq_disable_count = 1; ++ } ++ ingenic_mmc_reset(host); ++ ++ if (host->mrq && (host->state > STATE_IDLE)) { ++ host->cmd->error = -ENOMEDIUM; ++ if (host->data) { ++ host->data->bytes_xfered = 0; ++ ingenic_mmc_stop_dma(host); ++ } ++ del_timer_sync(&host->request_timer); ++ mmc_request_done(host->mmc, host->mrq); ++ host->state = STATE_IDLE; ++ } ++ mmc_detect_change(host->mmc, 0); ++ } else { ++ if(irq_disable_count) { ++ enable_irq(host->irq); ++ irq_disable_count = 0; ++ } ++ set_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ /* ++ * spin_lock() here may case recursion, ++ * so discard the clk operation. ++ */ ++ ingenic_mmc_clk_onoff(host, 1); ++ mmc_detect_change(host->mmc, msecs_to_jiffies(1000)); ++ } ++ ++ if (!test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)) { ++ ingenic_mmc_clk_onoff(host, 0); ++ } ++ } ++ ++ enable_irq(gpio_to_irq(host->pdata->gpio->cd.num)); ++} ++ ++/** ++ * ingenic_mmc_manual_detect - insert or remove card manually ++ * @index: host->index, namely the index of the controller. ++ * @on: 1 means insert card, 0 means remove card. ++ * ++ * This functions will be called by manually card-detect driver such as ++ * wifi. To enable this mode you can set value pdata.removal = MANUAL. ++ */ ++int ingenic_mmc_manual_detect(int index, int on) ++{ ++ struct ingenic_mmc_host *host; ++ struct list_head *pos; ++ ++ list_for_each(pos, &manual_list) { ++ host = list_entry(pos, struct ingenic_mmc_host, list); ++ if (host->index == index) ++ break; ++ else ++ host = NULL; ++ } ++ ++ if(!host) { ++ printk("no manual card detect\n"); ++ return -1; ++ } ++ ++ if (on) { ++ dev_vdbg(host->dev, "card insert manually\n"); ++ set_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++#ifdef CLK_CTRL ++ ingenic_mmc_clk_onoff(host, 1); ++#endif ++ mmc_detect_change(host->mmc, 0); ++ } else { ++ dev_vdbg(host->dev, "card remove manually\n"); ++ clear_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ mmc_detect_change(host->mmc, 0); ++#ifdef CLK_CTRL ++ ingenic_mmc_clk_onoff(host, 0); ++#endif ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(ingenic_mmc_manual_detect); ++ ++/** ++ * ingenic_mmc_clk_ctrl - enable or disable msc clock gate ++ * @index: host->index, namely the index of the controller. ++ * @on: 1-enable msc clock gate, 0-disable msc clock gate. ++ */ ++int ingenic_mmc_clk_ctrl(int index, int on) ++{ ++ struct ingenic_mmc_host *host; ++ struct list_head *pos; ++ ++#ifdef CLK_CTRL ++ list_for_each(pos, &manual_list) { ++ host = list_entry(pos, struct ingenic_mmc_host, list); ++ if (host->index == index) ++ break; ++ else ++ host = NULL; ++ } ++ ++ if (!host) { ++ printk("no manual card detect\n"); ++ return -1; ++ } ++ ingenic_mmc_clk_onoff(host, on); ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(ingenic_mmc_clk_ctrl); ++ ++/* ++ * for module driver ++ */ ++int jzmmc_manual_detect(int index, int on) ++{ ++ return ingenic_mmc_manual_detect(index, on); ++} ++EXPORT_SYMBOL(jzmmc_manual_detect); ++ ++int jzmmc_clk_ctrl(int index, int on) ++{ ++ return ingenic_mmc_clk_ctrl(index, on); ++} ++EXPORT_SYMBOL(jzmmc_clk_ctrl); ++/*-------------------End card insert and remove handler--------------------*/ ++ ++/* ++ * Other mmc_ops except request. ++ */ ++static inline void ingenic_mmc_power_on(struct ingenic_mmc_host *host) ++{ ++ dev_vdbg(host->dev, "power_on\n"); ++ ++ if (!IS_ERR(host->power)) { ++ /* if(!regulator_is_enabled(host->power)) */ ++ /* regulator_enable(host->power); */ ++ ++ } else if (host->pdata->gpio) { ++ set_pin_status(&host->pdata->gpio->pwr, 1); ++ } ++} ++ ++static inline void ingenic_mmc_power_off(struct ingenic_mmc_host *host) ++{ ++ dev_vdbg(host->dev, "power_off\n"); ++ ++ if (!IS_ERR(host->power)) { ++ /* if(regulator_is_enabled(host->power)) */ ++ /* regulator_disable(host->power); */ ++ ++ } else if (host->pdata->gpio) { ++ set_pin_status(&host->pdata->gpio->pwr, 0); ++ } ++} ++ ++static int ingenic_mmc_get_read_only(struct mmc_host *mmc) ++{ ++ struct ingenic_mmc_host *host = mmc_priv(mmc); ++ int ret = 0; ++ ++ dev_vdbg(host->dev, "get card ro\n"); ++ if (host->pdata->gpio != NULL) ++ ret = get_pin_status(&host->pdata->gpio->wp); ++ ++ return ret < 0? 0 : ret; ++} ++ ++static int ingenic_mmc_get_card_detect(struct mmc_host *mmc) ++{ ++ struct ingenic_mmc_host *host = mmc_priv(mmc); ++ int ret = -1; ++ ++ dev_vdbg(host->dev, "get card present\n"); ++ if ((host->pdata->removal == NONREMOVABLE) ++ || (host->pdata->removal == MANUAL)) { ++ return test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ } ++ ++ if (host->pdata->gpio != NULL) ++ ret = get_pin_status(&host->pdata->gpio->cd); ++ ++ return ret < 0? 1 : ret; ++} ++ ++static void ingenic_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct ingenic_mmc_host *host = mmc_priv(mmc); ++ ++ /* ++ * The max bus width is set in the platformdata->capacity, ++ * MMC_CAP_4_BIT_DATA: Can the host do 4 bit transfers ++ * MMC_CAP_8_BIT_DATA: Can the host do 8 bit transfers ++ */ ++ ++ switch (ios->bus_width) { ++ case MMC_BUS_WIDTH_1: ++ host->cmdat_def &= ~CMDAT_BUS_WIDTH_MASK; ++ host->cmdat_def |= CMDAT_BUS_WIDTH_1BIT; ++ break; ++ case MMC_BUS_WIDTH_4: ++ host->cmdat_def &= ~CMDAT_BUS_WIDTH_MASK; ++ host->cmdat_def |= CMDAT_BUS_WIDTH_4BIT; ++ break; ++ case MMC_BUS_WIDTH_8: ++ host->cmdat_def &= ~CMDAT_BUS_WIDTH_MASK; ++ host->cmdat_def |= CMDAT_BUS_WIDTH_8BIT; ++ break; ++ } ++ ++ if (ios->clock) { ++ unsigned int clk_set = 0, clkrt = 0; ++ unsigned int clk_want = ios->clock; ++ unsigned int lpm = 0; ++ ++ ingenic_mmc_clk_onoff(host, 0); ++ if (clk_want > 3000000) { ++ clk_set_rate(host->clk_cgu, ios->clock); ++ } else { ++ clk_set_rate(host->clk_cgu, CLK_RATE); ++ } ++ /*clk_get_rate is permanently 24000000 on board_4785_fpga*/ ++ clk_set = clk_get_rate(host->clk_cgu); ++ ++ while (clk_want < clk_set) { ++ clkrt++; ++ clk_set >>= 1; ++ } ++ /* discard this warning on board 4785 fpga */ ++ if ((clk_want > 3000000) && clkrt) { ++ dev_err(host->dev, "CLKRT must be set to 0 " ++ "when MSC works during normal r/w: " ++ "ios->clock=%d clk_want=%d " ++ "clk_set=%d clkrt=%X,\n", ++ ios->clock, clk_want, clk_set, clkrt); ++ WARN_ON(1); ++ } ++ ++ if (clkrt > 7) { ++ dev_err(host->dev, "invalid value of CLKRT: " ++ "ios->clock=%d clk_want=%d " ++ "clk_set=%d clkrt=%X,\n", ++ ios->clock, clk_want, clk_set, clkrt); ++ WARN_ON(1); ++ return; ++ } ++ if (!clkrt) ++ dev_vdbg(host->dev, "clk_want: %u, clk_set: %luHz\n", ++ ios->clock, clk_get_rate(host->clk_cgu)); ++ ++ ingenic_mmc_clk_onoff(host, 1); ++ msc_writel(host, CLKRT, clkrt); ++ ++ /* sample immediately at clk rising edge */ ++ if (clk_set > 25000000) ++ lpm = (0x2 << LPM_DRV_SEL_SHF); ++ ++ if(host->pdata->sdio_clk) { ++ msc_writel(host, LPM, lpm); ++ msc_writel(host, CTRL, CTRL_CLOCK_START); ++ } else { ++ lpm |= LPM_LPM; ++ msc_writel(host, LPM, lpm); ++ } ++ } ++ ++ switch (ios->power_mode) { ++ case MMC_POWER_ON: ++ case MMC_POWER_UP: ++ host->cmdat_def |= CMDAT_INIT; ++ set_bit(INGENIC_MMC_CARD_NEED_INIT, &host->flags); ++ ingenic_mmc_power_on(host); ++ break; ++ case MMC_POWER_OFF: ++ ingenic_mmc_power_off(host); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void ingenic_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) ++{ ++ struct ingenic_mmc_host *host = mmc_priv(mmc); ++ ++ if (enable) { ++ enable_msc_irq(host, IMASK_SDIO); ++ } else { ++ clear_msc_irq(host, IFLG_SDIO); ++ disable_msc_irq(host, IMASK_SDIO); ++ } ++} ++ ++static const struct mmc_host_ops ingenic_mmc_ops = { ++ .request = ingenic_mmc_request, ++ .set_ios = ingenic_mmc_set_ios, ++ .get_ro = ingenic_mmc_get_read_only, ++ .get_cd = ingenic_mmc_get_card_detect, ++ .enable_sdio_irq = ingenic_mmc_enable_sdio_irq, ++}; ++ ++/*--------------------------End other mmc_ops------------------------------*/ ++static ssize_t ingenic_mmc_present_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct ingenic_mmc_host *host = dev_get_drvdata(dev); ++ ssize_t count = 0; ++ ++ if (test_bit(INGENIC_MMC_CARD_PRESENT, &host->flags)) ++ count = sprintf(buf, "Y\n"); ++ else ++ count = sprintf(buf, "N\n"); ++ ++ return count; ++} ++ ++static ssize_t ingenic_mmc_present_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ingenic_mmc_pdata *pdata = dev->platform_data; ++ struct ingenic_mmc_host *host = dev_get_drvdata(dev); ++ ++ if ((buf == NULL) || (pdata->removal != NONREMOVABLE)) { ++ dev_err(host->dev, "can't set present\n"); ++ return count; ++ } ++ ++ if (strncmp(buf, "INSERT", 6) == 0) { ++ dev_info(host->dev, "card insert via sysfs\n"); ++ set_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ mmc_detect_change(host->mmc, 0); ++ ++ } else if (strncmp(buf, "REMOVE", 6) == 0) { ++ dev_info(host->dev, "card remove via sysfs\n"); ++ clear_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ mmc_detect_change(host->mmc, 0); ++ ingenic_mmc_reset(host); ++ ++ } else { ++ dev_err(host->dev, "set present error, " ++ "the argument can't be recognised\n"); ++ } ++ ++ return count; ++} ++ ++static DEVICE_ATTR(present, S_IWUSR | S_IRUSR, ++ ingenic_mmc_present_show, ingenic_mmc_present_store); ++ ++static struct attribute *ingenic_mmc_attributes[] = { ++ &dev_attr_present.attr, ++ NULL ++}; ++ ++static const struct attribute_group ingenic_mmc_attr_group = { ++ .attrs = ingenic_mmc_attributes, ++}; ++ ++/*-------------------------End Sysfs interface-----------------------------*/ ++ ++/* ++ * Platform driver and initialization. ++ */ ++static void __init ingenic_mmc_host_init(struct ingenic_mmc_host *host, struct mmc_host *mmc) ++{ ++ struct ingenic_mmc_pdata *pdata = host->pdata; ++ ++ mmc->ops = &ingenic_mmc_ops; ++ mmc->f_min = 200000; ++ mmc->ocr_avail = pdata->ocr_avail; ++ mmc->pm_flags |= pdata->pm_flags; ++#ifdef CONFIG_MMC_BLOCK_BOUNCE ++ mmc->max_blk_count = 65535; ++ mmc->max_req_size = PAGE_SIZE * 16; ++#else ++ mmc->max_segs = MAX_SEGS; ++ mmc->max_blk_count = 4096; ++ mmc->max_req_size = 4096 * 512; ++#endif ++ mmc->max_blk_size = 512; ++ mmc->max_seg_size = mmc->max_req_size; ++ ++ host->mmc = mmc; ++ timer_setup(&host->request_timer, ingenic_mmc_request_timeout,0); ++ ++ mmc_of_parse(mmc); ++ ++ mmc_add_host(mmc); ++} ++ ++static int __init ingenic_mmc_dma_init(struct ingenic_mmc_host *host) ++{ ++ struct sdma_desc *next_desc; ++ unsigned char i = 0; ++ void *desc_mem; ++ void __iomem *desc; ++ ++ desc_mem = (struct sdma_desc *)get_zeroed_page(GFP_KERNEL); ++ if (desc_mem == NULL) { ++ dev_err(host->dev, "get DMA descriptor memory error\n"); ++ return -ENODEV; ++ } ++ ++ desc = devm_ioremap(host->dev, virt_to_phys(desc_mem), PAGE_SIZE); ++ if (desc == NULL) { ++ dev_err(host->dev, "remap descriptor memory error\n"); ++ kfree(desc_mem); ++ return -ENODEV; ++ } ++ ++ host->decshds[0].dma_desc = (struct sdma_desc*)desc; ++ next_desc = host->decshds[0].dma_desc; ++ ++ for (i = 0; i < MAX_SEGS; ++i) { ++ struct desc_hd *dhd = &host->decshds[i]; ++ dhd->dma_desc = next_desc; ++ dhd->dma_desc_phys_addr = CPHYSADDR((unsigned long)dhd->dma_desc); ++ next_desc += 1; ++ dhd->next = dhd + 1; ++ } ++ host->decshds[MAX_SEGS - 1].next = NULL; ++ return 0; ++} ++ ++static int __init ingenic_mmc_msc_init(struct ingenic_mmc_host *host) ++{ ++ ingenic_mmc_reset(host); ++ host->cmdat_def = CMDAT_RTRG_EQUALT_16 | CMDAT_TTRG_LESS_16 | \ ++ CMDAT_BUS_WIDTH_1BIT; ++ ++ return devm_request_threaded_irq(host->dev, host->irq, NULL, ++ ingenic_mmc_thread_handle, IRQF_ONESHOT, dev_name(host->dev), host); ++} ++static void ingenic_mmc_get_gpio(struct device_node *np, ++ struct ingenic_mmc_pin *pin, char *gpioname) ++{ ++ int gpio; ++ enum of_gpio_flags flags; ++ ++ pin->num = -EBUSY; ++ gpio = of_get_named_gpio_flags(np, gpioname, 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ pin->num = gpio; ++ pin->enable_level = ++ (flags == OF_GPIO_ACTIVE_LOW ? LOW_ENABLE : HIGH_ENABLE); ++ } ++ printk("mmc gpio %s num:%d en-level: %d\n", ++ gpioname, pin->num, pin->enable_level); ++} ++static void ingenic_mmc_init_gpio(struct ingenic_mmc_pin *pin, char *gpioname, int dir) ++{ ++ if(gpio_is_valid(pin->num)) { ++ if (gpio_request_one(pin->num, dir, gpioname)) { ++ pr_info("%s no detect pin available\n", gpioname); ++ pin->num = -EBUSY; ++ } ++ } ++} ++ ++static int __init ingenic_mmc_gpio_init(struct ingenic_mmc_host *host) ++{ ++ struct card_gpio *card_gpio = host->pdata->gpio; ++ int ret = 0, dir; ++ ++ ingenic_mmc_init_gpio(&card_gpio->cd, "mmc_detect", GPIOF_DIR_IN); ++ ingenic_mmc_init_gpio(&card_gpio->wp, "mmc_wp", GPIOF_DIR_IN); ++ ingenic_mmc_init_gpio(&card_gpio->rst, "mmc_rst", GPIOF_DIR_OUT); ++ dir = card_gpio->pwr.enable_level ? GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH; ++ ingenic_mmc_init_gpio(&card_gpio->pwr, "mmc_pwr", dir); ++ ++ switch (host->pdata->removal) { ++ case NONREMOVABLE: ++ break; ++ case REMOVABLE: ++ if (gpio_is_valid(card_gpio->cd.num)) { ++ timer_setup(&host->detect_timer, ingenic_mmc_detect,0); ++ ret = devm_request_irq(host->dev, gpio_to_irq(card_gpio->cd.num), ++ ingenic_mmc_detect_handler, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, ++ "mmc-insert-detect", host); ++ if (ret) { ++ dev_err(host->dev, "request detect irq-%d fail\n", ++ gpio_to_irq(card_gpio->cd.num)); ++ break; ++ } ++ ++ if(!timer_pending(&host->detect_timer)){ ++ disable_irq_nosync(gpio_to_irq(card_gpio->cd.num)); ++ mod_timer(&host->detect_timer, jiffies); ++ } ++ } else { ++ dev_err(host->dev, "card-detect pin must be valid " ++ "when host->pdata->removal = 1, errno=%d\n", ++ card_gpio->cd.num); ++ } ++ ++ break; ++ case MANUAL: ++ list_add(&(host->list), &manual_list); ++ break; ++ default: ++ set_bit(INGENIC_MMC_CARD_PRESENT, &host->flags); ++ break; ++ } ++ ++ return ret; ++} ++ ++static void ingenic_mmc_gpio_deinit(struct ingenic_mmc_host *host) ++{ ++ struct card_gpio *card_gpio = host->pdata->gpio; ++ ++ if (card_gpio) { ++ if(gpio_is_valid(card_gpio->cd.num)) { ++ gpio_free(card_gpio->cd.num); ++ } ++ if(gpio_is_valid(card_gpio->wp.num)) { ++ gpio_free(card_gpio->wp.num); ++ } ++ if(gpio_is_valid(card_gpio->pwr.num)) { ++ gpio_free(card_gpio->pwr.num); ++ } ++ if(gpio_is_valid(card_gpio->rst.num)) { ++ gpio_free(card_gpio->rst.num); ++ } ++ } ++} ++ ++static void mmc_get_clk_name_v1(int id, char *cgu_name, char *gate_name) ++{ ++ sprintf(cgu_name, "cgu_msc%d", id); ++ sprintf(gate_name, "gate_msc%d", id); ++} ++ ++static void mmc_get_clk_name_v2(int id, char *cgu_name, char *gate_name) ++{ ++ sprintf(cgu_name, "div_msc%d", id); ++ sprintf(gate_name, "gate_msc%d", id); ++} ++ ++static struct ingenic_mmc_priv ingenic_mmc_priv = { ++ .get_clk_name = mmc_get_clk_name_v1, ++}; ++ ++static struct ingenic_mmc_priv x1600_mmc_priv = { ++ .get_clk_name = mmc_get_clk_name_v2, ++}; ++ ++static const struct of_device_id mmc_ingenic_of_match[] = { ++ {.compatible = "ingenic,mmc", .data = &ingenic_mmc_priv}, ++ {.compatible = "ingenic,x1600-mmc", .data = &x1600_mmc_priv}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mmc_ingenic_of_match); ++ ++static struct ingenic_mmc_pdata *of_get_mmc_ingenic_pdata(struct device *dev) ++{ ++ struct ingenic_mmc_pdata *pdata; ++ struct device_node *np = dev->of_node; ++ struct card_gpio *card_gpio; ++ ++ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) ++ return NULL; /* out of memory */ ++ ++ card_gpio = devm_kzalloc(dev, sizeof(struct card_gpio), GFP_KERNEL); ++ if(!card_gpio) ++ return NULL; ++ ingenic_mmc_get_gpio(np, &card_gpio->rst, "ingneic,rst-gpios"); ++ ingenic_mmc_get_gpio(np, &card_gpio->wp, "ingneic,wp-gpios"); ++ ingenic_mmc_get_gpio(np, &card_gpio->pwr, "ingneic,pwr-gpios"); ++ ingenic_mmc_get_gpio(np, &card_gpio->cd, "ingneic,cd-gpios"); ++ pdata->gpio = card_gpio; ++ ++ if(of_property_read_bool(np, "pio-mode")) { ++ pdata->pio_mode = 1; ++ } ++ ++ { ++ unsigned int val; ++ if(!(of_property_read_u32(np, "ingenic,sdio_clk", &val))) ++ pdata->sdio_clk = val; ++ } ++ ++ if(of_property_read_bool(np, "ingenic,removal-dontcare")) { ++ pdata->removal = DONTCARE; ++ } else if(of_property_read_bool(np, "ingenic,removal-nonremovable")) { ++ pdata->removal = NONREMOVABLE; ++ } else if(of_property_read_bool(np, "ingenic,removal-removable")) { ++ pdata->removal = REMOVABLE; ++ } else if(of_property_read_bool(np, "ingenic,removal-manual")) { ++ pdata->removal = MANUAL; ++ }; ++ ++ mmc_of_parse_voltage(np, &pdata->ocr_avail); ++ ++ return pdata; ++} ++ ++static int mmc_ingenic_probe(struct platform_device *pdev) ++{ ++ struct ingenic_mmc_pdata *pdata; ++ struct resource *regs; ++ struct ingenic_mmc_host *host = NULL; ++ struct mmc_host *mmc; ++ struct ingenic_mmc_priv *priv; ++ struct of_device_id *of_device_id; ++ int ret = 0; ++ char clk_cgu_name[16]; ++ char clk_gate_name[16]; ++ ++ pdata = of_get_mmc_ingenic_pdata(&pdev->dev); ++ if(IS_ERR(pdata)) { ++ dev_err(&pdev->dev, "Platform Data is missing!\n"); ++ return PTR_ERR(pdata); ++ } ++ mmc = mmc_alloc_host(sizeof(struct ingenic_mmc_host), &pdev->dev); ++ if (!mmc) ++ return -ENOMEM; ++ ++ host = mmc_priv(mmc); ++ ++ of_device_id = of_match_node(mmc_ingenic_of_match, pdev->dev.of_node); ++ priv = of_device_id->data; ++ ++ ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "mmc"); ++ host->index = pdev->id; ++ priv->get_clk_name(host->index, clk_cgu_name, clk_gate_name); ++ host->clk_cgu = devm_clk_get(&pdev->dev, clk_cgu_name); ++ if(!host->clk_cgu) { ++ dev_err(&pdev->dev, "Failed to Get MSC clk!\n"); ++ return PTR_ERR(host->clk_cgu); ++ } ++ host->clk_gate = devm_clk_get(&pdev->dev, clk_gate_name); ++ if(!host->clk_gate) { ++ dev_err(&pdev->dev, "Failed to Get PWC MSC clk!\n"); ++ return PTR_ERR(host->clk_gate); ++ } ++ ++ clk_set_rate(host->clk_cgu, CLK_RATE); ++ if(clk_get_rate(host->clk_cgu) > CLK_RATE) { ++ dev_err(&pdev->dev, "Failed to Set MSC clk %ld!\n", clk_get_rate(host->clk_cgu)); ++ goto err_clk_get_rate; ++ } ++ ingenic_mmc_clk_onoff(host, 1); ++ ++ host->dev = &pdev->dev; ++ host->pdata = pdata; ++ ++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!regs) { ++ dev_err(&pdev->dev, "No iomem resource\n"); ++ return -ENXIO; ++ } ++ host->iomem = devm_ioremap_resource(&pdev->dev, regs); ++ if (!host->iomem) ++ goto err_ioremap; ++ ++ host->irq = platform_get_irq(pdev, 0); ++ if (host->irq < 0) { ++ dev_err(&pdev->dev, "No irq resource\n"); ++ return host->irq; ++ } ++ ++ /* host->power = regulator_get(host->dev, "cpu_mem12"); */ ++ /* if (IS_ERR(host->power)) { */ ++ /* dev_warn(host->dev, "vmmc regulator missing\n"); */ ++ /* } */ ++ if (host->pdata->pio_mode) ++ set_bit(INGENIC_MMC_USE_PIO, &host->flags); ++ ++ if (!test_bit(INGENIC_MMC_USE_PIO, &host->flags)) { ++ ret = ingenic_mmc_dma_init(host); ++ if (ret < 0) ++ goto err_dma_init; ++ } ++ ++ spin_lock_init(&host->lock); ++ if (pdata->sdio_clk) { ++ ingenic_sdio_wlan_init(&pdev->dev, host->index); ++ } ++ ++ ret = ingenic_mmc_msc_init(host); ++ if (ret < 0) ++ goto err_msc_init; ++ ++ ingenic_mmc_host_init(host, mmc); ++ ++ ret = ingenic_mmc_gpio_init(host); ++ if (ret < 0) ++ goto err_gpio_init; ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &ingenic_mmc_attr_group); ++ if (ret < 0) ++ goto err_sysfs_create; ++ ++ platform_set_drvdata(pdev, host); ++ ++ dev_info(host->dev, "register success!\n"); ++ return 0; ++ ++err_sysfs_create: ++ ingenic_mmc_gpio_deinit(host); ++err_gpio_init: ++ free_irq(host->irq, host); ++err_msc_init: ++ devm_iounmap(&pdev->dev, (void __iomem *)host->decshds[0].dma_desc); ++err_dma_init: ++ devm_iounmap(&pdev->dev, host->iomem); ++err_ioremap: ++ mmc_free_host(mmc); ++ clk_disable_unprepare(host->clk_cgu); ++err_clk_get_rate: ++ clk_put(host->clk_cgu); ++ clk_put(host->clk_gate); ++ dev_err(host->dev, "mmc probe error\n"); ++ return ret; ++} ++ ++static int __exit mmc_ingenic_remove(struct platform_device *pdev) ++{ ++ struct ingenic_mmc_host *host = platform_get_drvdata(pdev); ++ ++ platform_set_drvdata(pdev, NULL); ++ mmc_remove_host(host->mmc); ++ mmc_free_host(host->mmc); ++ sysfs_remove_group(&pdev->dev.kobj, &ingenic_mmc_attr_group); ++ ++ ingenic_mmc_power_off(host); ++ if (host->pdata->removal == REMOVABLE) ++ free_irq(gpio_to_irq(host->pdata->gpio->cd.num), host); ++ ++ free_irq(host->irq, host); ++ ingenic_mmc_gpio_deinit(host); ++ devm_iounmap(&pdev->dev, (void __iomem *)host->decshds[0].dma_desc); ++ /* regulator_put(host->power); */ ++ ingenic_mmc_clk_onoff(host, 0); ++ ++ clk_put(host->clk_cgu); ++ clk_put(host->clk_gate); ++ iounmap(host->iomem); ++ kfree(host); ++ ++ return 0; ++} ++ ++static void mmc_ingenic_shutdown(struct platform_device *pdev) ++{ ++ struct ingenic_mmc_host *host = platform_get_drvdata(pdev); ++ struct card_gpio *card_gpio = host->pdata->gpio; ++ ++ /* ++ * Remove host when shutdown to avoid illegal request, ++ * but don't remove sdio_host in case of the SDIO device driver ++ * can't handle bus remove correctly. ++ */ ++ dev_vdbg(host->dev, "shutdown\n"); ++ if(host->mmc->card && !mmc_card_sdio(host->mmc->card)) { ++ if(gpio_is_valid(card_gpio->rst.num)) { ++ gpio_direction_output(card_gpio->rst.num, 0); ++ } else { ++ mmc_remove_host(host->mmc); ++ } ++ } ++ ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int mmc_ingenic_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct ingenic_mmc_host *host = platform_get_drvdata(pdev); ++ int ret = 0; ++ ++ ingenic_mmc_clk_onoff(host, 0); ++ /* if (host->mmc->card && host->mmc->card->type != MMC_TYPE_SDIO) { */ ++ /* ret = mmc_suspend_host(host->mmc); */ ++ /* } */ ++ return ret; ++} ++ ++static int mmc_ingenic_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct ingenic_mmc_host *host = platform_get_drvdata(pdev); ++ int ret = 0; ++ ingenic_mmc_clk_onoff(host, 1); ++ /* if (host->mmc->card && host->mmc->card->type != MMC_TYPE_SDIO) { */ ++ /* ret = mmc_resume_host(host->mmc); */ ++ /* } */ ++ return ret; ++} ++#else ++#define mmc_ingenic_suspend NULL ++#define mmc_ingenic_resume NULL ++#endif ++static SIMPLE_DEV_PM_OPS(mmc_ingenic_pm_ops, mmc_ingenic_suspend, ++ mmc_ingenic_resume); ++ ++static struct platform_driver mmc_ingenic_driver = { ++ .driver = { ++ .name = "ingenic,mmc", ++ .owner = THIS_MODULE, ++ .pm = &mmc_ingenic_pm_ops, ++ .of_match_table = of_match_ptr(mmc_ingenic_of_match), ++ }, ++ .probe = mmc_ingenic_probe, ++ .remove = mmc_ingenic_remove, ++ .shutdown = mmc_ingenic_shutdown, ++}; ++ ++module_platform_driver(mmc_ingenic_driver); ++ ++MODULE_DESCRIPTION("Multimedia Card Interface driver, MMC version 1.2"); ++MODULE_AUTHOR("bo.liu "); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION("20170222"); +diff --git a/module_drivers/drivers/mmc/host/ingenic_mmc.h b/module_drivers/drivers/mmc/host/ingenic_mmc.h +new file mode 100644 +index 000000000..b8d0748f7 +--- /dev/null ++++ b/module_drivers/drivers/mmc/host/ingenic_mmc.h +@@ -0,0 +1,158 @@ ++#ifndef __INGENIC_MMC_H__ ++#define __INGENIC_MMC_H__ ++ ++#include "ingenic_mmc_reg.h" ++#include ++enum { ++ DONTCARE = 0, ++ NONREMOVABLE, ++ REMOVABLE, ++ MANUAL, ++}; ++ ++enum { ++ EVENT_CMD_COMPLETE = 0, ++ EVENT_TRANS_COMPLETE, ++ EVENT_DMA_COMPLETE, ++ EVENT_DATA_COMPLETE, ++ EVENT_STOP_COMPLETE, ++ EVENT_ERROR, ++}; ++ ++enum ingenic_mmc_state { ++ STATE_IDLE = 0, ++ STATE_WAITING_RESP, ++ STATE_WAITING_DATA, ++ STATE_SENDING_STOP, ++ STATE_ERROR, ++}; ++ ++struct sdma_desc { ++ volatile u32 nda; ++ volatile u32 da; ++ volatile u32 len; ++ volatile u32 dcmd; ++}; ++ ++struct desc_hd { ++ struct sdma_desc *dma_desc; ++ dma_addr_t dma_desc_phys_addr; ++ struct desc_hd *next; ++}; ++ ++#define LOW_ENABLE 0 ++#define HIGH_ENABLE 1 ++struct ingenic_mmc_pin { ++ short num; ++ short enable_level; ++}; ++ ++struct card_gpio { ++ struct ingenic_mmc_pin wp; ++ struct ingenic_mmc_pin cd; ++ struct ingenic_mmc_pin pwr; ++ struct ingenic_mmc_pin rst; ++}; ++ ++/** ++ * struct ingenic_mmc_platform_data is a struct which defines board MSC informations ++ * @removal: This shows the card slot's type: ++ * REMOVABLE/IRREMOVABLE/MANUAL (Tablet card/Phone card/build-in SDIO). ++ * @sdio_clk: SDIO device's clock can't use Low-Power-Mode. ++ * @ocr_mask: This one shows the voltage that host provide. ++ * @capacity: Shows the host's speed capacity and bus width. ++ * @max_freq: The max freqency of mmc host. ++ * ++ * @recovery_info: Informations that Android recovery mode uses. ++ * @gpio: Slot's gpio information including pins of write-protect, card-detect and power. ++ * @pio_mode: Indicate that whether the MSC host use PIO mode. ++ * @private_init: Board private initial function, mostly for SDIO devices. ++ */ ++struct ingenic_mmc_pdata { ++ unsigned short removal; ++ unsigned short sdio_clk; ++ unsigned int ocr_avail; ++ unsigned int capacity; ++ unsigned int pm_flags; ++ struct card_gpio *gpio; ++ unsigned int pio_mode; ++ int (*private_init)(void); ++}; ++ ++/** ++ * struct ingenic_mmc_host - Ingenic MMC/SD Controller host structure ++ * @pdata: The platform data. ++ * @dev: The mmc device pointer. ++ * @irq: Interrupt of MSC. ++ * @clk: Main Clk of MSC, including cgu and clk gate. ++ * @pwc_clk: Power of MSC module, MSC register can be access when pwc_clk on. ++ * @power: Power regulator of SD/MMC attached to SD slot. ++ * @mrq: mmc_request pointer which includes all the information ++ * of the current request, or NULL when the host is idle. ++ * @cmd: Command information of mmc_request. ++ * @data: Data information of mmc_request, or NULL when mrq without ++ * data request. ++ * @mmc: The mmc_host representing this slot. ++ * @pending_events: Bitmask of events flagged by the interrupt handler ++ * to be processed by the state machine. ++ * @iomem: Pointer to MSC registers. ++ * @detect_timer: Timer used for debouncing card insert interrupts. ++ * @request_timer: Timer used for preventing request time out. ++ * @flags: Random state bits associated with the slot. ++ * @cmdat: Variable for MSC_CMDAT register. ++ * @cmdat_def: Defalt CMDAT register value for every request. ++ * @gpio: Information of gpio including cd, wp and pwr. ++ * @index: Number of each MSC host. ++ * @decshds[]: Descriptor DMA information structure. ++ * @state: It's the state for request. ++ * @list: List head for manually detect card such as wifi. ++ * @lock: Lock the registers operation. ++ * @double_enter: Prevent state machine reenter. ++ * @timeout_cnt: The count of timeout second. ++ */ ++#define MAX_SEGS 128 /* max count of sg */ ++#define INGENIC_MMC_CARD_PRESENT 0 ++#define INGENIC_MMC_CARD_NEED_INIT 1 ++#define INGENIC_MMC_USE_PIO 2 ++ ++struct ingenic_mmc_host { ++ void __iomem *iomem; ++ struct device *dev; ++ struct clk *clk_cgu; ++ struct clk *clk_gate; ++ struct regulator *power; ++ struct mmc_request *mrq; ++ struct mmc_command *cmd; ++ struct mmc_data *data; ++ struct mmc_host *mmc; ++ struct timer_list detect_timer; ++ struct timer_list request_timer; ++ struct tasklet_struct tasklet; ++ struct list_head list; ++ struct ingenic_mmc_pdata *pdata; ++ struct desc_hd decshds[MAX_SEGS]; ++ enum ingenic_mmc_state state; ++ spinlock_t lock; ++ unsigned long pending_events; ++ unsigned long flags; ++ unsigned int cmdat; ++ unsigned int cmdat_def; ++ unsigned int index; ++ unsigned int double_enter; ++ int timeout_cnt; ++ int irq; ++}; ++ ++struct ingenic_mmc_priv { ++ void (*get_clk_name)(int id, char *cgu_name, char *gate_name); ++}; ++ ++/* Register access macros */ ++#define msc_readl(port,reg) \ ++ __raw_readl((port)->iomem + MSC_##reg) ++#define msc_writel(port,reg,value) \ ++ __raw_writel((value), (port)->iomem + MSC_##reg) ++int ingenic_sdio_wlan_init(struct device *dev, int index); ++int ingenic_mmc_clk_ctrl(int index, int on); ++int ingenic_mmc_manual_detect(int index, int on); ++#endif /* __INGENIC_MMC_H__ */ +diff --git a/module_drivers/drivers/mmc/host/ingenic_mmc_reg.h b/module_drivers/drivers/mmc/host/ingenic_mmc_reg.h +new file mode 100644 +index 000000000..5068fb431 +--- /dev/null ++++ b/module_drivers/drivers/mmc/host/ingenic_mmc_reg.h +@@ -0,0 +1,232 @@ ++#ifndef __INGENIC_MMC_REG_H__ ++#define __INGENIC_MMC_REG_H__ ++#define MMC_BOOT_AREA_PROTECTED (0x1234) /* Can not modified the area protected */ ++#define MMC_BOOT_AREA_OPENED (0x4321) /* Can modified the area protected */ ++ ++#define MSC_CTRL 0x000 ++#define MSC_STAT 0x004 ++#define MSC_CLKRT 0x008 ++#define MSC_CMDAT 0x00C ++#define MSC_RESTO 0x010 ++#define MSC_RDTO 0x014 ++#define MSC_BLKLEN 0x018 ++#define MSC_NOB 0x01C ++#define MSC_SNOB 0x020 ++#define MSC_IMASK 0x024 ++#define MSC_IFLG 0x028 ++#define MSC_CMD 0x02C ++#define MSC_ARG 0x030 ++#define MSC_RES 0x034 ++#define MSC_RXFIFO 0x038 ++#define MSC_TXFIFO 0x03C ++#define MSC_LPM 0x040 ++#define MSC_DMAC 0x044 ++#define MSC_DMANDA 0x048 ++#define MSC_DMADA 0x04C ++#define MSC_DMALEN 0x050 ++#define MSC_DMACMD 0x054 ++#define MSC_CTRL2 0x058 ++#define MSC_RTCNT 0x05C ++#define MSC_DEBUG 0x0FC ++ ++/* MSC Clock and Control Register (MSC_CTRL) */ ++#define CTRL_SEND_CCSD (1 << 15) /*send command completion signal disable to ceata */ ++#define CTRL_SEND_AS_CCSD (1 << 14) /*send internally generated stop after sending ccsd */ ++#define CTRL_EXIT_MULTIPLE (1 << 7) ++#define CTRL_EXIT_TRANSFER (1 << 6) ++#define CTRL_START_READWAIT (1 << 5) ++#define CTRL_STOP_READWAIT (1 << 4) ++#define CTRL_RESET (1 << 3) ++#define CTRL_START_OP (1 << 2) ++#define CTRL_CLOCK_SHF 0 ++#define CTRL_CLOCK_MASK (0x3 << CTRL_CLOCK_SHF) ++#define CTRL_CLOCK_STOP (0x1 << CTRL_CLOCK_SHF) /* Stop MMC/SD clock */ ++#define CTRL_CLOCK_START (0x2 << CTRL_CLOCK_SHF) /* Start MMC/SD clock */ ++ ++/* MSC Control 2 Register (MSC_CTRL2) */ ++#define CTRL2_PIP_SHF 24 ++#define CTRL2_PIP_MASK (0x1f << CTRL2_PIP_SHF) ++#define CTRL2_RST_EN (1 << 23) ++#define CTRL2_STPRM (1 << 4) ++#define CTRL2_SVC (1 << 3) ++#define CTRL2_SMS_SHF 0 ++#define CTRL2_SMS_MASK (0x7 << CTRL2_SMS_SHF) ++#define CTRL2_SMS_DEFSPD (0x0 << CTRL2_SMS_SHF) ++#define CTRL2_SMS_HISPD (0x1 << CTRL2_SMS_SHF) ++#define CTRL2_SMS_SDR12 (0x2 << CTRL2_SMS_SHF) ++#define CTRL2_SMS_SDR25 (0x3 << CTRL2_SMS_SHF) ++#define CTRL2_SMS_SDR50 (0x4 << CTRL2_SMS_SHF) ++ ++/* MSC Status Register (MSC_STAT) */ ++#define STAT_AUTO_CMD12_DONE (1 << 31) ++#define STAT_AUTO_CMD23_DONE (1 << 30) ++#define STAT_SVS (1 << 29) ++#define STAT_PIN_LEVEL_SHF 24 ++#define STAT_PIN_LEVEL_MASK (0x1f << STAT_PIN_LEVEL_SHF) ++#define STAT_BCE (1 << 20) ++#define STAT_BDE (1 << 19) ++#define STAT_BAE (1 << 18) ++#define STAT_BAR (1 << 17) ++#define STAT_IS_RESETTING (1 << 15) ++#define STAT_SDIO_INT_ACTIVE (1 << 14) ++#define STAT_PRG_DONE (1 << 13) ++#define STAT_DATA_TRAN_DONE (1 << 12) ++#define STAT_END_CMD_RES (1 << 11) ++#define STAT_DATA_FIFO_AFULL (1 << 10) ++#define STAT_IS_READWAIT (1 << 9) ++#define STAT_CLK_EN (1 << 8) ++#define STAT_DATA_FIFO_FULL (1 << 7) ++#define STAT_DATA_FIFO_EMPTY (1 << 6) ++#define STAT_CRC_RES_ERR (1 << 5) ++#define STAT_CRC_READ_ERROR (1 << 4) ++#define STAT_CRC_WRITE_ERROR_SHF 2 ++#define STAT_CRC_WRITE_ERROR_MASK (0x3 << STAT_CRC_WRITE_ERROR_SHF) ++#define STAT_CRC_WRITE_ERROR_NO (0 << STAT_CRC_WRITE_ERROR_SHF) ++#define STAT_CRC_WRITE_ERROR (1 << STAT_CRC_WRITE_ERROR_SHF) ++#define STAT_CRC_WRITE_ERROR_NOSTS (2 << STAT_CRC_WRITE_ERROR_SHF) ++#define STAT_TIME_OUT_RES (1 << 1) ++#define STAT_TIME_OUT_READ (1 << 0) ++ ++/* MSC Bus Clock Control Register (MSC_CLKRT) */ ++#define CLKRT_CLK_RATE_SHF 0 ++#define CLKRT_CLK_RATE_MASK (0x7 << CLKRT_CLK_RATE_SHF) ++#define CLKRT_CLK_RATE_DIV_1 (0x0 << CLKRT_CLK_RATE_SHF) /* CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_2 (0x1 << CLKRT_CLK_RATE_SHF) /* 1/2 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_4 (0x2 << CLKRT_CLK_RATE_SHF) /* 1/4 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_8 (0x3 << CLKRT_CLK_RATE_SHF) /* 1/8 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_16 (0x4 << CLKRT_CLK_RATE_SHF) /* 1/16 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_32 (0x5 << CLKRT_CLK_RATE_SHF) /* 1/32 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_64 (0x6 << CLKRT_CLK_RATE_SHF) /* 1/64 of CLK_SRC */ ++#define CLKRT_CLK_RATE_DIV_128 (0x7 << CLKRT_CLK_RATE_SHF) /* 1/128 of CLK_SRC */ ++ ++/* MSC Command Sequence Control Register (MSC_CMDAT) */ ++#define CMDAT_CCS_EXPECTED (1 << 31) /* interrupts are enabled in ce-ata */ ++#define CMDAT_READ_CEATA (1 << 30) ++#define CMDAT_DIS_BOOT (1 << 27) ++#define CMDAT_ENB_BOOT (1 << 26) ++#define CMDAT_EXP_BOOT_ACK (1 << 25) ++#define CMDAT_BOOT_MODE (1 << 24) ++#define CMDAT_AUTO_CMD23 (1 << 18) ++#define CMDAT_SDIO_PRDT (1 << 17) /* exact 2 cycle */ ++#define CMDAT_AUTO_CMD12 (1 << 16) ++#define CMDAT_RTRG_SHF 14 ++#define CMDAT_RTRG_EQUALT_16 (0x0 << CMDAT_RTRG_SHF) /*reset value*/ ++#define CMDAT_RTRG_EQUALT_32 (0x1 << CMDAT_RTRG_SHF) ++#define CMDAT_RTRG_EQUALT_64 (0x2 << CMDAT_RTRG_SHF) ++#define CMDAT_RTRG_EQUALT_96 (0x3 << CMDAT_RTRG_SHF) ++#define CMDAT_TTRG_SHF 12 ++#define CMDAT_TTRG_LESS_16 (0x0 << CMDAT_TTRG_SHF) /*reset value*/ ++#define CMDAT_TTRG_LESS_32 (0x1 << CMDAT_TTRG_SHF) ++#define CMDAT_TTRG_LESS_64 (0x2 << CMDAT_TTRG_SHF) ++#define CMDAT_TTRG_LESS_96 (0x3 << CMDAT_TTRG_SHF) ++#define CMDAT_IO_ABORT (1 << 11) ++#define CMDAT_BUS_WIDTH_SHF 9 ++#define CMDAT_BUS_WIDTH_MASK (0x3 << CMDAT_BUS_WIDTH_SHF) ++#define CMDAT_BUS_WIDTH_1BIT (0x0 << CMDAT_BUS_WIDTH_SHF) /* 1-bit data bus */ ++#define CMDAT_BUS_WIDTH_4BIT (0x2 << CMDAT_BUS_WIDTH_SHF) /* 4-bit data bus */ ++#define CMDAT_BUS_WIDTH_8BIT (0x3 << CMDAT_BUS_WIDTH_SHF) /* 8-bit data bus */ ++#define CMDAT_INIT (1 << 7) ++#define CMDAT_BUSY (1 << 6) ++#define CMDAT_STREAM_BLOCK (1 << 5) ++#define CMDAT_WRITE_READ (1 << 4) ++#define CMDAT_DATA_EN (1 << 3) ++#define CMDAT_RESPONSE_SHF 0 ++#define CMDAT_RESPONSE_MASK (0x7 << CMDAT_RESPONSE_SHF) ++#define CMDAT_RESPONSE_NONE (0x0 << CMDAT_RESPONSE_SHF) /* No response */ ++#define CMDAT_RESPONSE_R1 (0x1 << CMDAT_RESPONSE_SHF) /* Format R1 and R1b */ ++#define CMDAT_RESPONSE_R2 (0x2 << CMDAT_RESPONSE_SHF) /* Format R2 */ ++#define CMDAT_RESPONSE_R3 (0x3 << CMDAT_RESPONSE_SHF) /* Format R3 */ ++#define CMDAT_RESPONSE_R4 (0x4 << CMDAT_RESPONSE_SHF) /* Format R4 */ ++#define CMDAT_RESPONSE_R5 (0x5 << CMDAT_RESPONSE_SHF) /* Format R5 */ ++#define CMDAT_RESPONSE_R6 (0x6 << CMDAT_RESPONSE_SHF) /* Format R6 */ ++#define CMDAT_RESRONSE_R7 (0x7 << CMDAT_RESPONSE_SHF) /* Format R7 */ ++ ++/* MSC Interrupts Mask Register (MSC_IMASK) */ ++#define IMASK_DMA_DATA_DONE (1 << 31) ++#define IMASK_WR_ALL_DONE (1 << 23) ++#define IMASK_AUTO_CMD23_DONE (1 << 30) ++#define IMASK_SVS (1 << 29) ++#define IMASK_PIN_LEVEL_SHF 24 ++#define IMASK_PIN_LEVEL_MASK (0x1f << IMASK_PIN_LEVEL_SHF) ++#define IMASK_BCE (1 << 20) ++#define IMASK_BDE (1 << 19) ++#define IMASK_BAE (1 << 18) ++#define IMASK_BAR (1 << 17) ++#define IMASK_DMAEND (1 << 16) ++#define IMASK_AUTO_CMD12_DONE (1 << 15) ++#define IMASK_DATA_FIFO_FULL (1 << 14) ++#define IMASK_DATA_FIFO_EMP (1 << 13) ++#define IMASK_CRC_RES_ERR (1 << 12) ++#define IMASK_CRC_READ_ERR (1 << 11) ++#define IMASK_CRC_WRITE_ERR (1 << 10) ++#define IMASK_TIME_OUT_RES (1 << 9) ++#define IMASK_TIME_OUT_READ (1 << 8) ++#define IMASK_SDIO (1 << 7) ++#define IMASK_TXFIFO_WR_REQ (1 << 6) ++#define IMASK_RXFIFO_RD_REQ (1 << 5) ++#define IMASK_END_CMD_RES (1 << 2) ++#define IMASK_PRG_DONE (1 << 1) ++#define IMASK_DATA_TRAN_DONE (1 << 0) ++ ++/* MSC Interrupts Status Register (MSC_IREG) */ ++#define IFLG_DMA_DATA_DONE (1 << 31) ++#define IFLG_WR_ALL_DONE (1 << 23) ++#define IFLG_AUTO_CMD23_DONE (1 << 30) ++#define IFLG_SVS (1 << 29) ++#define IFLG_PIN_LEVEL_SHF 24 ++#define IFLG_PIN_LEVEL_MASK (0x1f << IFLG_PIN_LEVEL_SHF) ++#define IFLG_BCE (1 << 20) ++#define IFLG_BDE (1 << 19) ++#define IFLG_BAE (1 << 18) ++#define IFLG_BAR (1 << 17) ++#define IFLG_DMAEND (1 << 16) ++#define IFLG_AUTO_CMD12_DONE (1 << 15) ++#define IFLG_DATA_FIFO_FULL (1 << 14) ++#define IFLG_DATA_FIFO_EMP (1 << 13) ++#define IFLG_CRC_RES_ERR (1 << 12) ++#define IFLG_CRC_READ_ERR (1 << 11) ++#define IFLG_CRC_WRITE_ERR (1 << 10) ++#define IFLG_TIMEOUT_RES (1 << 9) ++#define IFLG_TIMEOUT_READ (1 << 8) ++#define IFLG_SDIO (1 << 7) ++#define IFLG_TXFIFO_WR_REQ (1 << 6) ++#define IFLG_RXFIFO_RD_REQ (1 << 5) ++#define IFLG_END_CMD_RES (1 << 2) ++#define IFLG_PRG_DONE (1 << 1) ++#define IFLG_DATA_TRAN_DONE (1 << 0) ++ ++/* MSC Low Power Mode Register (MSC_LPM) */ ++#define LPM_DRV_SEL_SHF 30 ++#define LPM_DRV_SEL_MASK (0x3 << LPM_DRV_SEL_SHF) ++#define LPM_SMP_SEL (1 << 29) ++#define LPM_LPM (1 << 0) ++ ++/* MSC DMA Control Register (MSC_DMAC) */ ++#define DMAC_MODE_SEL (1 << 7) ++#define DMAC_AOFST_SHF 5 ++#define DMAC_AOFST_MASK (0x3 << DMAC_AOFST_SHF) ++#define DMAC_AOFST_0 (0 << DMAC_AOFST_SHF) ++#define DMAC_AOFST_1 (1 << DMAC_AOFST_SHF) ++#define DMAC_AOFST_2 (2 << DMAC_AOFST_SHF) ++#define DMAC_AOFST_3 (3 << DMAC_AOFST_SHF) ++#define DMAC_ALIGNEN (1 << 4) ++#define DMAC_INCR_SHF 2 ++#define DMAC_INCR_MASK (0x3 << DMAC_INCR_SHF) ++#define DMAC_INCR_16 (0 << DMAC_INCR_SHF) ++#define DMAC_INCR_32 (1 << DMAC_INCR_SHF) ++#define DMAC_INCR_64 (2 << DMAC_INCR_SHF) ++#define DMAC_DMASEL (1 << 1) ++#define DMAC_DMAEN (1 << 0) ++ ++/* MSC DMA Command Register (MSC_DMACMD) */ ++#define DMACMD_IDI_SHF 24 ++#define DMACMD_IDI_MASK (0xff << DMACMD_IDI_SHF) ++#define DMACMD_ID_SHF 16 ++#define DMACMD_ID_MASK (0xff << DMACMD_ID_SHF) ++#define DMACMD_OFFSET_SHF 9 ++#define DMACMD_OFFSET_MASK (0x3 << DMACMD_OFFSET_SHF) ++#define DMACMD_ALIGN_EN (1 << 8) ++#define DMACMD_ENDI (1 << 1) ++#define DMACMD_LINK (1 << 0) ++ ++#endif /* __INGENIC_MMC_REG_H__ */ +diff --git a/module_drivers/drivers/mmc/host/ingenic_sdio.c b/module_drivers/drivers/mmc/host/ingenic_sdio.c +new file mode 100644 +index 000000000..c60d6d6b8 +--- /dev/null ++++ b/module_drivers/drivers/mmc/host/ingenic_sdio.c +@@ -0,0 +1,275 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#if (defined(CONFIG_INGENIC_MMC_MMC0) || defined(CONFIG_INGENIC_MMC_MMC1)) ++#include "ingenic_mmc.h" ++#else ++#include "sdhci-ingenic.h" ++#endif ++ ++struct wifi_data { ++ int sdio_index; ++ /* struct wake_lock wifi_wake_lock; */ ++ /* struct regulator *wifi_vbat; */ ++ /* struct regulator *wifi_vddio; */ ++ uint wifi_reset; ++ uint wifi_reset_flags; ++ uint wifi_irq; ++ uint wifi_irq_flags; ++ struct pinctrl *pctrl; ++ atomic_t rtc32k_ref; ++ struct regulator *wlreg_on; ++ struct regulator *wl_vccio; ++ struct clk *clk; ++}; ++ ++#define RESET 0 ++#define NORMAL 1 ++ ++struct wifi_data wifi_data; ++static void rtc32k_init(struct device *dev, struct wifi_data *wdata) ++{ ++ atomic_set(&wdata->rtc32k_ref, 0); ++ wdata->pctrl = NULL; ++ wdata->clk = NULL; ++#ifdef CONFIG_RTC_DRV_PCF8563 ++ { ++ struct of_phandle_args phandle; ++ phandle.np = of_find_compatible_node(NULL, NULL, "nxp,pcf8563"); ++ if (phandle.np) { ++ wdata->clk = of_clk_get_from_provider(&phandle); ++ } ++ } ++#else ++ wdata->pctrl = devm_pinctrl_get(dev); ++#endif ++} ++void rtc32k_enable(void) ++{ ++ ++ if (atomic_inc_return(&wifi_data.rtc32k_ref) == 1) { ++ if(wifi_data.clk) ++ { ++ printk("@@ rtc.pcf8563 %s @@\n", __func__); ++ clk_prepare_enable(wifi_data.clk); ++ } ++ if(wifi_data.pctrl) ++ { ++ struct pinctrl_state *state = NULL; ++ struct pinctrl *p = wifi_data.pctrl; ++ state = pinctrl_lookup_state(p, "enable"); ++ if (!IS_ERR_OR_NULL(state)) { ++ pinctrl_select_state(p, state); ++ } ++ } ++ } ++} ++EXPORT_SYMBOL(rtc32k_enable); ++void rtc32k_disable(void) ++{ ++ if (atomic_dec_return(&wifi_data.rtc32k_ref) == 0) { ++ if(wifi_data.clk){ ++ printk("@@ rtc.pcf8563 %s @@\n", __func__); ++ clk_disable_unprepare(wifi_data.clk); ++ } ++ if(wifi_data.pctrl) { ++ struct pinctrl_state *state = NULL; ++ struct pinctrl *p = wifi_data.pctrl; ++ state = pinctrl_lookup_state(p, "disable"); ++ if (!IS_ERR_OR_NULL(state)) { ++ pinctrl_select_state(p, state); ++ } ++ } ++ } ++} ++EXPORT_SYMBOL(rtc32k_disable); ++static const struct of_device_id wlan_ingenic_of_match[] = { ++ {.compatible = "android,bcmdhd_wlan"}, ++ {.compatible = "rtk,rtl8723ds_wlan"}, ++ {}, ++}; ++ ++int wlan_regulator_get(struct device *dev) ++{ ++ int ret; ++ ++ wifi_data.wlreg_on= devm_regulator_get(dev, "wlreg_on"); ++ ++ if (IS_ERR(wifi_data.wlreg_on)) { ++ printk("wlreg_on is error %s, %s, %d\n", __FILE__, __func__, __LINE__); ++ if (PTR_ERR(wifi_data.wlreg_on) == -EPROBE_DEFER) { ++ return -EPROBE_DEFER; ++ } ++ } ++ ++ if (!IS_ERR(wifi_data.wlreg_on)) { ++ ret = regulator_enable(wifi_data.wlreg_on); ++ if (ret) { ++ dev_err(dev, "wlreg_on enable failed\n"); ++ return ret; ++ } ++ } else { ++ dev_err(dev, "wlreg_on is invalid\n"); ++ } ++ ++ wifi_data.wl_vccio = devm_regulator_get(dev, "wl_vccio"); ++ ++ if (IS_ERR(wifi_data.wl_vccio)) { ++ printk("wl_vccio is error %s, %s, %d\n", __FILE__, __func__, __LINE__); ++ if (PTR_ERR(wifi_data.wl_vccio) == -EPROBE_DEFER) { ++ return -EPROBE_DEFER; ++ } ++ } ++ ++ if (!IS_ERR(wifi_data.wl_vccio)) { ++ ret = regulator_enable(wifi_data.wl_vccio); ++ if (ret) { ++ dev_err(dev, "wl_vccio enable failed\n"); ++ return ret; ++ } ++ } else { ++ dev_err(dev, "wl_vccio is invalid\n"); ++ } ++ ++ return 0; ++} ++ ++int ingenic_sdio_wlan_init(struct device *dev, int index) ++{ ++ struct device_node *np = dev->of_node, *cnp; ++ unsigned int flags, gpio; ++ ++ for_each_child_of_node(np, cnp) { ++ if(of_device_is_compatible(cnp, "android,bcmdhd_wlan")) { ++ printk("----android,bcmdhd_wlan!\n"); ++ wifi_data.wifi_reset = of_get_named_gpio_flags(cnp, "ingenic,sdio-reset", 0, &flags); ++ wifi_data.wifi_reset_flags = flags; ++ wifi_data.wifi_irq = of_get_named_gpio_flags(cnp, "ingenic,sdio-irq", 0, &flags); ++ wifi_data.wifi_irq_flags = flags; ++ } ++ if(of_device_is_compatible(cnp, "rtk,rtl8723ds_wlan")) { ++ printk("----rtk,rtl8723ds_wlan\n"); ++ wifi_data.wifi_reset = of_get_named_gpio_flags(cnp, "ingenic,sdio-reset", 0, &flags); ++ wifi_data.wifi_reset_flags = flags; ++ wifi_data.wifi_irq = of_get_named_gpio_flags(cnp, "ingenic,sdio-irq", 0, &flags); ++ wifi_data.wifi_irq_flags = flags; ++ } ++ } ++ ++ wlan_regulator_get(dev); ++ ++ rtc32k_init(dev, &wifi_data); ++ ++ gpio = wifi_data.wifi_reset; ++ if (devm_gpio_request(dev, gpio, "wifi_reset")) { ++ printk("ERROR: no wifi_reset pin available !!\n"); ++ return -EINVAL; ++ } else { ++ gpio_direction_output(gpio, !wifi_data.wifi_reset_flags); ++ } ++ wifi_data.wifi_reset = gpio; ++ wifi_data.sdio_index = index; ++ ++ return 0; ++} ++EXPORT_SYMBOL(ingenic_sdio_wlan_init); ++ ++int ingenic_sdio_wlan_get_irq(unsigned long *flag) ++{ ++ *flag = wifi_data.wifi_irq_flags; ++ return wifi_data.wifi_irq; ++} ++EXPORT_SYMBOL(ingenic_sdio_wlan_get_irq); ++int ingenic_sdio_wlan_power_onoff(int onoff, int flag) ++{ ++ int err = 0; ++ int reset = wifi_data.wifi_reset; ++ if(!reset) ++ return -EINVAL; ++ if(onoff) { ++ printk("reset %d wlan power on:%d\n", reset, flag); ++ if (!IS_ERR(wifi_data.wlreg_on)) { ++ err = regulator_enable(wifi_data.wlreg_on); ++ if (err) { ++ printk("wifi_data.wlreg_on enable failed\n"); ++ return err; ++ } ++ } ++ if (!IS_ERR(wifi_data.wl_vccio)) { ++ err = regulator_enable(wifi_data.wl_vccio); ++ if (err) { ++ printk("wifi_data.wl_vccio enable failed\n"); ++ return err; ++ } ++ } ++ rtc32k_enable(); ++ switch(flag) { ++ case RESET: ++ ingenic_mmc_clk_ctrl(wifi_data.sdio_index, 1); ++ gpio_set_value(reset, 0); ++ msleep(10); ++ gpio_set_value(reset, 1); ++ break; ++ case NORMAL: ++ gpio_set_value(reset, 1); ++ ingenic_mmc_manual_detect(wifi_data.sdio_index, 1); ++ break; ++ } ++ } else { ++ printk("wlan power off:%d\n", flag); ++ switch(flag) { ++ case RESET: ++ gpio_set_value(reset, 0); ++ break; ++ case NORMAL: ++ gpio_set_value(reset, 0); ++ break; ++ } ++ rtc32k_disable(); ++ if (!IS_ERR(wifi_data.wlreg_on)) { ++ err = regulator_disable(wifi_data.wlreg_on); ++ if (err) { ++ printk("wifi_data.wlreg_on disable failed\n"); ++ return err; ++ } ++ } ++ if (!IS_ERR(wifi_data.wl_vccio)) { ++ err = regulator_disable(wifi_data.wl_vccio); ++ if (err) { ++ printk("wifi_data.wl_vccio disable failed\n"); ++ return err; ++ } ++ } ++ } ++ if (err < 0) { ++ printk("%s: regulator enable/disable failed", __FUNCTION__); ++ return -1; ++ } ++ return 0; ++ ++} ++EXPORT_SYMBOL(ingenic_sdio_wlan_power_onoff); +diff --git a/module_drivers/drivers/mmc/host/sdhci-ingenic.c b/module_drivers/drivers/mmc/host/sdhci-ingenic.c +new file mode 100644 +index 000000000..b917ea769 +--- /dev/null ++++ b/module_drivers/drivers/mmc/host/sdhci-ingenic.c +@@ -0,0 +1,741 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include "sdhci.h" ++#include "sdhci-ingenic.h" ++ ++#define CLK_CTRL ++/* Software redefinition caps */ ++#define CAPABILITIES1_SW 0x276dc898 ++#define CAPABILITIES2_SW 0 ++ ++static LIST_HEAD(manual_list); ++ ++#ifdef CONFIG_SOC_X2500 ++#define CPM_MSC0_CLK_R (0xB0000068) ++#define CPM_MSC1_CLK_R (0xB000006c) ++#else ++#define CPM_MSC0_CLK_R (0xB0000068) ++#define CPM_MSC1_CLK_R (0xB00000a4) ++#define CPM_MSC2_CLK_R (0xB00000a8) ++#endif ++ ++#ifdef CONFIG_FPGA_TEST ++#define MSC_CLK_H_FREQ (0x1 << 20) ++ ++static void sdhci_ingenic_fpga_clk(unsigned int clock) ++{ ++#define CPM_MSC_CLK_R CPM_MSC0_CLK_R ++//#define CPM_MSC_CLK_R CPM_MSC1_CLK_R ++ unsigned int val; ++ ++ if(500000 <= clock){ ++ val = readl((const volatile void*)CPM_MSC_CLK_R); ++ val |= MSC_CLK_H_FREQ; ++ writel(val, (void*)CPM_MSC_CLK_R); ++ } else { ++ val = readl((const volatile void*)CPM_MSC_CLK_R); ++ val &= ~MSC_CLK_H_FREQ; ++ writel(val, (void*)CPM_MSC_CLK_R); ++ } ++ printk("\tclk=%d, CPM_MSC0_CLK_R: %08x\n\n", clock, readl((const volatile void*)CPM_MSC0_CLK_R)); ++} ++#endif ++ ++static unsigned int sdhci_ingenic_get_cpm_msc(struct sdhci_host *host) ++{ ++ char msc_ioaddr[16]; ++ unsigned int cpm_msc; ++ sprintf(msc_ioaddr, "0x%x", (unsigned int)host->ioaddr); ++#ifdef CONFIG_SOC_X2500 ++ if (!strcmp(msc_ioaddr ,"0xb3450000")) ++ cpm_msc = CPM_MSC0_CLK_R; ++ if (!strcmp(msc_ioaddr ,"0xb3070000")) ++ cpm_msc = CPM_MSC1_CLK_R; ++#else ++ if (!strcmp(msc_ioaddr ,"0xb3450000")) ++ cpm_msc = CPM_MSC0_CLK_R; ++ if (!strcmp(msc_ioaddr ,"0xb3460000")) ++ cpm_msc = CPM_MSC1_CLK_R; ++ if (!strcmp(msc_ioaddr ,"0xb3490000")) ++ cpm_msc = CPM_MSC2_CLK_R; ++#endif ++ return cpm_msc; ++ ++} ++ ++/** ++ * sdhci_ingenic_msc_tuning Enable msc controller tuning ++ * ++ * Tuning rx phase ++ * */ ++static void sdhci_ingenic_en_msc_tuning(struct sdhci_host *host, unsigned int cpm_msc) ++{ ++ if (host->mmc->ios.timing & MMC_TIMING_UHS_SDR50 || ++ host->mmc->ios.timing & MMC_TIMING_UHS_SDR104 || ++ host->mmc->ios.timing & MMC_TIMING_MMC_HS400) { ++ *(volatile unsigned int*)cpm_msc &= ~(0x1 << 20); ++ } ++} ++ ++static void sdhci_ingenic_sel_rx_phase(unsigned int cpm_msc) ++{ ++ *(volatile unsigned int*)cpm_msc |= (0x1 << 20); // default ++ ++ *(volatile unsigned int*)cpm_msc &= ~(0x7 << 17); ++ *(volatile unsigned int*)cpm_msc |= (0x7 << 17); // OK RX 90 TX 270 ++} ++ ++static void sdhci_ingenic_sel_tx_phase(unsigned int cpm_msc) ++{ ++ *(volatile unsigned int*)cpm_msc &= ~(0x3 << 15); ++/* *(volatile unsigned int*)cpm_msc |= (0x2 << 15); // 180 100M OK*/ ++ *(volatile unsigned int*)cpm_msc |= (0x3 << 15); ++} ++ ++/** ++ * sdhci_ingenic_set_clock - callback on clock change ++ * @host: The SDHCI host being changed ++ * @clock: The clock rate being requested. ++ * ++ * When the card's clock is going to be changed, look at the new frequency ++ * and find the best clock source to go with it. ++*/ ++static void sdhci_ingenic_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++#ifndef CONFIG_FPGA_TEST ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host); ++ unsigned int cpm_msc = sdhci_ingenic_get_cpm_msc(host); ++ char clkname[16]; ++ ++ if (clock == 0){ ++ return ; ++ } ++ ++ sdhci_set_clock(host, clock); ++ sprintf(clkname, "mux_msc%d", sdhci_ing->pdev->id); ++ sdhci_ing->clk_mux = clk_get(NULL, clkname); ++ ++ if (clock > 400000) { ++ clk_set_parent(sdhci_ing->clk_mux, sdhci_ing->clk_mpll); ++ } else { ++ clk_set_parent(sdhci_ing->clk_mux, sdhci_ing->clk_ext); ++ *(volatile unsigned int *)0xB0000068 |= 1 << 21; ++ } ++ ++ clk_set_rate(sdhci_ing->clk_cgu, clock); ++ ++// printk("%s, set clk: %d, get_clk_rate=%ld\n", __func__, clock, clk_get_rate(sdhci_ing->clk_cgu)); ++ ++ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 || ++ host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) { ++ ++ /* RX phase selecte */ ++ if (sdhci_ing->pdata->enable_cpm_rx_tuning == 1) ++ sdhci_ingenic_sel_rx_phase(cpm_msc); ++ else ++ sdhci_ingenic_en_msc_tuning(host, cpm_msc); ++ /* TX phase selecte */ ++ if (sdhci_ing->pdata->enable_cpm_tx_tuning == 1) ++ sdhci_ingenic_sel_tx_phase(cpm_msc); ++ } ++#else //CONFIG_FPGA_TEST ++ sdhci_ingenic_fpga_clk(clock); ++#endif ++} ++ ++ ++/* I/O Driver Strength Types */ ++#define INGENIC_TYPE_0 0x0 //30 ++#define INGENIC_TYPE_1 0x1 //50 ++#define INGENIC_TYPE_2 0x2 //66 ++#define INGENIC_TYPE_3 0x3 //100 ++ ++ ++#ifndef CONFIG_SOC_X2500 ++void sdhci_ingenic_voltage_switch(struct sdhci_host *host,int voltage) ++{ ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host); ++ struct sdhci_ingenic_pdata *pdata = sdhci_ing->pdata; ++ unsigned int val; ++ ++ if (pdata->sdr_v18 < 0) ++ return; ++ ++ switch(voltage){ ++ case MMC_SIGNAL_VOLTAGE_330: ++ val = cpm_inl(CPM_EXCLK_DS) & ~(1 << 31); ++ cpm_outl(val, CPM_EXCLK_DS); ++ /*Set up hardware circuit 3V*/ ++ gpio_direction_output(sdhci_ing->pdata->sdr_v18, 0); ++ break; ++ case MMC_SIGNAL_VOLTAGE_180: ++ /*controlled SD voltage to 1.8V*/ ++ val = cpm_inl(CPM_EXCLK_DS) | (1 << 31); ++ cpm_outl(val, CPM_EXCLK_DS); ++ /*Set up hardware circuit 1.8V*/ ++ gpio_direction_output(pdata->sdr_v18, 1); ++ break; ++ default: ++ return ; ++ } ++ ++} ++#endif ++ ++void sdhci_ingenic_power_set(struct sdhci_host *host,int onoff) ++{ ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host); ++ struct sdhci_ingenic_pdata *pdata = sdhci_ing->pdata; ++ ++ if(pdata->gpio->pwr.num >= 0){ ++ if(onoff) ++ gpio_direction_output(pdata->gpio->pwr.num,pdata->gpio->pwr.enable_level); ++ else ++ gpio_direction_output(pdata->gpio->pwr.num,!pdata->gpio->pwr.enable_level); ++ } else { ++ return ; ++ } ++} ++ ++void ingenic_sdhci_hwreset(struct sdhci_host *host) ++{ ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host); ++ struct sdhci_ingenic_pdata *pdata = sdhci_ing->pdata; ++ ++ if(pdata->gpio->rst.num >= 0){ ++ gpio_direction_output(pdata->gpio->rst.num,pdata->gpio->rst.enable_level); ++ udelay(10); ++ gpio_direction_output(pdata->gpio->rst.num,!pdata->gpio->rst.enable_level); ++ usleep_range(300,500); ++ } else { ++ return ; ++ } ++ ++} ++ ++ ++#define BOUNDARY_OK(addr, len) \ ++ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) ++ ++ ++/* ++ * If DMA addr spans 128MB boundary, we split the DMA transfer into two ++ * so that each DMA transfer doesn't exceed the boundary. ++ */ ++static void ingenic_sdhci_adma_write_desc(struct sdhci_host *host, void **desc, ++ dma_addr_t addr, int len, unsigned int cmd) ++{ ++ int tmplen, offset; ++ ++ if (likely(!len || BOUNDARY_OK(addr, len))) { ++ sdhci_adma_write_desc(host, desc, addr, len, cmd); ++ return; ++ } ++ ++ offset = addr & (SZ_128M - 1); ++ tmplen = SZ_128M - offset; ++ sdhci_adma_write_desc(host, desc, addr, tmplen, cmd); ++ ++ addr += tmplen; ++ len -= tmplen; ++ sdhci_adma_write_desc(host, desc, addr, len, cmd); ++} ++ ++static struct sdhci_ops sdhci_ingenic_ops = { ++ .set_clock = sdhci_ingenic_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .reset = sdhci_reset, ++ .set_uhs_signaling = sdhci_set_uhs_signaling, ++ .power_set = sdhci_ingenic_power_set, ++ .hw_reset = ingenic_sdhci_hwreset, ++ .adma_write_desc = ingenic_sdhci_adma_write_desc, ++#ifndef CONFIG_SOC_X2500 ++ .voltage_switch = sdhci_ingenic_voltage_switch, ++#endif ++}; ++ ++ ++#ifdef CONFIG_OF ++static void ingenic_mmc_get_gpio(struct device_node *np, struct ingenic_mmc_pin *pin, char *gpioname) ++{ ++ int gpio; ++ enum of_gpio_flags flags; ++ ++ pin->num = -EBUSY; ++ gpio = of_get_named_gpio_flags(np, gpioname, 0, &flags); ++ if(gpio_is_valid(gpio)) { ++ pin->num = gpio; ++ pin->enable_level = (flags == OF_GPIO_ACTIVE_LOW ? LOW_ENABLE : HIGH_ENABLE); ++ } ++ printk("mmc gpio %s num:%d en-level: %d\n",gpioname, pin->num, pin->enable_level); ++} ++ ++static inline void ingenic_mmc_clk_onoff(struct sdhci_ingenic *ingenic_ing, unsigned int on) ++{ ++ if(on) { ++ clk_prepare_enable(ingenic_ing->clk_cgu); ++ clk_prepare_enable(ingenic_ing->clk_gate); ++ } else { ++ clk_disable_unprepare(ingenic_ing->clk_cgu); ++ clk_disable_unprepare(ingenic_ing->clk_gate); ++ } ++} ++ ++/** ++ * ingenic_mmc_manual_detect - insert or remove card manually ++ * @index: host->index, namely the index of the controller. ++ * @on: 1 means insert card, 0 means remove card. ++ * ++ * This functions will be called by manually card-detect driver such as ++ * wifi. To enable this mode you can set value pdata.removal = MANUAL. ++ */ ++int ingenic_mmc_manual_detect(int index, int on) ++{ ++ struct sdhci_ingenic *sdhci_ing; ++ struct sdhci_host *host; ++ struct list_head *pos; ++ ++ list_for_each(pos, &manual_list) { ++ sdhci_ing = list_entry(pos, struct sdhci_ingenic, list); ++ if (sdhci_ing->pdev->id == index) { ++ break; ++ } else ++ sdhci_ing = NULL; ++ } ++ ++ if(!sdhci_ing) { ++ printk("no manual card detect\n"); ++ return -1; ++ } ++ ++ host = sdhci_ing->host; ++ ++ if (on) { ++ dev_err(&sdhci_ing->pdev->dev, "card insert manually\n"); ++ set_bit(INGENIC_MMC_CARD_PRESENT, &sdhci_ing->flags); ++#ifdef CLK_CTRL ++ ingenic_mmc_clk_onoff(sdhci_ing, 1); ++#endif ++ host->flags &= ~SDHCI_DEVICE_DEAD; ++ host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; ++ mmc_detect_change(sdhci_ing->host->mmc, 0); ++ } else { ++ dev_err(&sdhci_ing->pdev->dev, "card remove manually\n"); ++ clear_bit(INGENIC_MMC_CARD_PRESENT, &sdhci_ing->flags); ++ ++ host->flags |= SDHCI_DEVICE_DEAD; ++ host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; ++ mmc_detect_change(sdhci_ing->host->mmc, 0); ++#ifdef CLK_CTRL ++ ingenic_mmc_clk_onoff(sdhci_ing, 0); ++#endif ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(ingenic_mmc_manual_detect); ++ ++/** ++ * ingenic_mmc_clk_ctrl - enable or disable msc clock gate ++ * @index: host->index, namely the index of the controller. ++ * @on: 1-enable msc clock gate, 0-disable msc clock gate. ++ */ ++int ingenic_mmc_clk_ctrl(int index, int on) ++{ ++ struct sdhci_ingenic *sdhci_ing; ++ struct list_head *pos; ++ ++#ifdef CLK_CTRL ++ list_for_each(pos, &manual_list) { ++ sdhci_ing = list_entry(pos, struct sdhci_ingenic, list); ++ if (sdhci_ing->pdev->id == index) ++ break; ++ else ++ sdhci_ing = NULL; ++ } ++ ++ if (!sdhci_ing) { ++ printk("no manual card detect\n"); ++ return -1; ++ } ++ ingenic_mmc_clk_onoff(sdhci_ing, on); ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(ingenic_mmc_clk_ctrl); ++ ++static int sdhci_ingenic_parse_dt(struct device *dev, ++ struct sdhci_host *host, ++ struct sdhci_ingenic_pdata *pdata) ++{ ++ struct device_node *np = dev->of_node; ++ struct card_gpio *card_gpio; ++ unsigned int val; ++ ++ card_gpio = devm_kzalloc(dev, sizeof(struct card_gpio), GFP_KERNEL); ++ if(!card_gpio) ++ return 0; ++ pdata->gpio = card_gpio; ++ ++ pdata->sdr_v18 = of_get_named_gpio(np, "ingenic,sdr-gpios", 0); ++ ingenic_mmc_get_gpio(np,&pdata->gpio->pwr,"ingenic,pwr-gpios"); ++ ingenic_mmc_get_gpio(np,&pdata->gpio->rst,"ingenic,rst-gpios"); ++ ++ /* assuming internal card detect that will be configured by pinctrl */ ++ pdata->cd_type = SDHCI_INGENIC_CD_INTERNAL; ++ ++ if(of_property_read_bool(np, "pio-mode")) { ++ pdata->pio_mode = 1; ++ } ++ if(of_property_read_bool(np, "enable_autocmd12")) { ++ pdata->enable_autocmd12 = 1; ++ } ++ if(of_property_read_bool(np, "enable_cpm_rx_tuning")) { ++ pdata->enable_cpm_rx_tuning = 1; ++ } ++ if(of_property_read_bool(np, "enable_cpm_tx_tuning")) { ++ pdata->enable_cpm_tx_tuning = 1; ++ } ++ ++ /* get the card detection method */ ++ if (of_get_property(np, "broken-cd", NULL)) { ++ pdata->cd_type = SDHCI_INGENIC_CD_NONE; ++ } ++ ++ if (of_get_property(np, "non-removable", NULL)) { ++ pdata->cd_type = SDHCI_INGENIC_CD_PERMANENT; ++ } ++ ++ if (of_get_property(np, "cd-inverted", NULL)) { ++ pdata->cd_type = SDHCI_INGENIC_CD_GPIO; ++ } ++ ++ if(!(of_property_read_u32(np, "ingenic,sdio_clk", &val))) ++ pdata->sdio_clk = val; ++ ++ /*set Power-On-Control Select of GPIO PE group*/ ++ if(of_property_read_bool(np, "ingenic,poc-v1.8")) { ++ pdata->poc_v18 = 1; ++ } ++ ++ /* if(of_property_read_bool(np, "ingenic,removal-dontcare")) { */ ++ /* pdata->removal = DONTCARE; */ ++ /* } else if(of_property_read_bool(np, "ingenic,removal-nonremovable")) { */ ++ /* pdata->removal = NONREMOVABLE; */ ++ /* } else if(of_property_read_bool(np, "ingenic,removal-removable")) { */ ++ /* pdata->removal = REMOVABLE; */ ++ /* } else if(of_property_read_bool(np, "ingenic,removal-manual")) { */ ++ /* pdata->removal = MANUAL; */ ++ /* }; */ ++ ++ /* mmc_of_parse_voltage(np, &pdata->ocr_avail); */ ++ ++ return 0; ++} ++#else ++static int sdhci_ingenic_parse_dt(struct device *dev, ++ struct sdhci_host *host, ++ struct sdhci_ingenic_pdata *pdata) ++{ ++ return -EINVAL; ++} ++#endif ++ ++static int sdhci_ingenic_probe(struct platform_device *pdev) ++{ ++ struct sdhci_ingenic_pdata *pdata; ++ struct device *dev = &pdev->dev; ++ struct sdhci_host *host; ++ struct sdhci_ingenic *sdhci_ing; ++ char clkname[16]; ++ int ret, irq; ++ ++ if (!pdev->dev.platform_data && !pdev->dev.of_node) { ++ dev_err(dev, "no device data specified\n"); ++ return -ENOENT; ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(dev, "no irq specified\n"); ++ return irq; ++ } ++ ++ host = sdhci_alloc_host(dev, sizeof(struct sdhci_ingenic)); ++ if (IS_ERR(host)) { ++ dev_err(dev, "sdhci_alloc_host() failed\n"); ++ return PTR_ERR(host); ++ } ++ sdhci_ing = sdhci_priv(host); ++ ++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) { ++ ret = -ENOMEM; ++ return ret; ++ } ++ ++ if (pdev->dev.of_node) { ++ ret = sdhci_ingenic_parse_dt(&pdev->dev, host, pdata); ++ if (ret) ++ return ret; ++ } else { ++ memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); ++ } ++ ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "mmc"); ++ ++ sprintf(clkname, "div_msc%d", pdev->id); ++ sdhci_ing->clk_cgu = devm_clk_get(&pdev->dev, clkname); ++ if(!sdhci_ing->clk_cgu) { ++ dev_err(&pdev->dev, "Failed to Get MSC clk!\n"); ++ return PTR_ERR(sdhci_ing->clk_cgu); ++ } ++ sprintf(clkname, "gate_msc%d", pdev->id); ++ sdhci_ing->clk_gate = devm_clk_get(&pdev->dev, clkname); ++ if(!sdhci_ing->clk_gate) { ++ dev_err(&pdev->dev, "Failed to Get PWC MSC clk!\n"); ++ return PTR_ERR(sdhci_ing->clk_gate); ++ } ++ sdhci_ing->clk_ext = clk_get(NULL, "ext"); ++ sdhci_ing->clk_mpll = clk_get(NULL, "mpll"); ++ ++ ingenic_mmc_clk_onoff(sdhci_ing, 1); ++ ++ sdhci_ing->host = host; ++ sdhci_ing->dev = &pdev->dev; ++ sdhci_ing->pdev = pdev; ++ sdhci_ing->pdata = pdata; ++ ++ host->ioaddr= of_iomap(pdev->dev.of_node, 0); ++ if (IS_ERR(host->ioaddr)) { ++ return PTR_ERR(host->ioaddr); ++ } ++ ++ platform_set_drvdata(pdev, host); ++ ++ /* sdio for WIFI init*/ ++ if (pdata->sdio_clk) { ++ ingenic_sdio_wlan_init(&pdev->dev, pdev->id); ++ list_add(&(sdhci_ing->list), &manual_list); ++ } ++ ++ if (pdata->sdr_v18 > 0 && \ ++ devm_gpio_request(dev, pdata->sdr_v18, "sdr-v18")) { ++ printk("ERROR: no sdr-v18 pin available !!\n"); ++ } ++ ++ host->hw_name = "ingenic-sdhci"; ++ host->ops = &sdhci_ingenic_ops; ++ host->quirks = 0; ++ host->irq = irq; ++ ++ /* Software redefinition caps */ ++ host->quirks |= SDHCI_QUIRK_MISSING_CAPS; ++ host->caps = CAPABILITIES1_SW; ++ host->caps1 = CAPABILITIES2_SW; ++ ++ /* not check wp */ ++ host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; ++ ++ /* Setup quirks for the controller */ ++ host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; ++ host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; ++ ++ /* Data Timeout Counter Value */ ++ //host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; ++ host->timeout_clk = 24000; //TMCLK = 24MHz ++ ++ /* This host supports the Auto CMD12 */ ++ if(pdata->enable_autocmd12) ++ host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; ++ ++ /* PIO transfer mode */ ++ if(pdata->pio_mode){ ++ host->quirks |= SDHCI_QUIRK_BROKEN_DMA; ++ host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; ++ } ++ /* TODO:SoCs need BROKEN_ADMA_ZEROLEN_DESC */ ++/* host->quirks |= SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC;*/ ++ ++ if (pdata->cd_type == SDHCI_INGENIC_CD_NONE || ++ pdata->cd_type == SDHCI_INGENIC_CD_PERMANENT) ++ host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; ++ ++ if (pdata->cd_type == SDHCI_INGENIC_CD_PERMANENT) ++ host->mmc->caps = MMC_CAP_NONREMOVABLE; ++ ++ if (pdata->pm_caps) ++ host->mmc->pm_caps |= pdata->pm_caps; ++ ++ host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR | ++ SDHCI_QUIRK_32BIT_DMA_SIZE); ++ ++ /* It supports additional host capabilities if needed */ ++ if (pdata->host_caps) ++ host->mmc->caps |= pdata->host_caps; ++ ++ if (pdata->host_caps2) ++ host->mmc->caps2 |= pdata->host_caps2; ++ ++#ifdef CONFIG_PM_RUNTIME ++ pm_runtime_enable(&pdev->dev); ++ pm_runtime_set_autosuspend_delay(&pdev->dev, 50); ++ pm_runtime_use_autosuspend(&pdev->dev); ++ pm_suspend_ignore_children(&pdev->dev, 1); ++#endif ++ ++ ret = mmc_of_parse(host->mmc); ++ if (ret) { ++ dev_err(dev, "mmc_of_parse() failed\n"); ++ pm_runtime_forbid(&pdev->dev); ++ pm_runtime_get_noresume(&pdev->dev); ++ return ret; ++ } ++ ++ sdhci_enable_v4_mode(host); ++ ret = sdhci_add_host(host); ++ if (ret) { ++ dev_err(dev, "sdhci_add_host() failed\n"); ++ pm_runtime_forbid(&pdev->dev); ++ pm_runtime_get_noresume(&pdev->dev); ++ return ret; ++ } ++ ++ /* enable card inserted and unplug wake-up system */ ++ if(host->mmc->slot.cd_irq > 0) ++ enable_irq_wake(host->mmc->slot.cd_irq); ++#ifdef CONFIG_PM_RUNTIME ++ if (pdata->cd_type != SDHCI_INGENIC_CD_INTERNAL) { ++ clk_disable_unprepare(sdhci_ing->clk_cgu); ++ /* clk_disable_unprepare(sdhci_ing->clk_gate); */ ++ } ++#endif ++ ++ return 0; ++} ++ ++static int sdhci_ingenic_remove(struct platform_device *pdev) ++{ ++ struct sdhci_host *host = platform_get_drvdata(pdev); ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host); ++ ++ if (sdhci_ing->ext_cd_irq) ++ free_irq(sdhci_ing->ext_cd_irq, sdhci_ing); ++ ++#ifdef CONFIG_PM_RUNTIME ++ if (pdata->cd_type != SDHCI_INGENIC_CD_INTERNAL){ ++ /* clk_prepare_enable(sdhci_ing->clk_gate); */ ++ clk_prepare_enable(sdhci_ing->clk_cgu); ++ } ++#endif ++ sdhci_remove_host(host, 1); ++ ++ pm_runtime_dont_use_autosuspend(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ ++ clk_disable_unprepare(sdhci_ing->clk_cgu); ++ /* clk_disable_unprepare(sdhci_ing->clk_gate); */ ++ ++ sdhci_free_host(host); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int sdhci_ingenic_suspend(struct device *dev) ++{ ++ struct sdhci_host *host = dev_get_drvdata(dev); ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host) ; ++ clk_disable_unprepare(sdhci_ing->clk_gate); ++ return sdhci_suspend_host(host); ++} ++ ++static int sdhci_ingenic_resume(struct device *dev) ++{ ++ struct sdhci_host *host = dev_get_drvdata(dev); ++ struct sdhci_ingenic *sdhci_ing = sdhci_priv(host) ; ++ clk_prepare_enable(sdhci_ing->clk_gate); ++ return sdhci_resume_host(host); ++} ++#endif ++ ++#ifdef CONFIG_PM ++static int sdhci_ingenic_runtime_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++ ++static int sdhci_ingenic_runtime_resume(struct device *dev) ++{ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_PM ++static const struct dev_pm_ops sdhci_ingenic_pmops = { ++ SET_SYSTEM_SLEEP_PM_OPS(sdhci_ingenic_suspend, sdhci_ingenic_resume) ++ SET_RUNTIME_PM_OPS(sdhci_ingenic_runtime_suspend, sdhci_ingenic_runtime_resume, ++ NULL) ++}; ++ ++#define SDHCI_INGENIC_PMOPS (&sdhci_ingenic_pmops) ++ ++#else ++#define SDHCI_INGENIC_PMOPS NULL ++#endif ++ ++ ++static struct platform_device_id sdhci_ingenic_driver_ids[] = { ++ { ++ .name = "ingenic,sdhci", ++ .driver_data = (kernel_ulong_t)NULL, ++ }, ++ { } ++}; ++MODULE_DEVICE_TABLE(platform, sdhci_ingenic_driver_ids); ++ ++#ifdef CONFIG_OF ++static const struct of_device_id sdhci_ingenic_dt_match[] = { ++ {.compatible = "ingenic,sdhci",}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sdhci_ingenic_dt_match); ++#endif ++ ++static struct platform_driver sdhci_ingenic_driver = { ++ .probe = sdhci_ingenic_probe, ++ .remove = sdhci_ingenic_remove, ++ .id_table = sdhci_ingenic_driver_ids, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "ingenic,sdhci", ++ .pm = SDHCI_INGENIC_PMOPS, ++ .of_match_table = of_match_ptr(sdhci_ingenic_dt_match), ++ }, ++}; ++ ++module_platform_driver(sdhci_ingenic_driver); ++ ++ ++MODULE_DESCRIPTION("Ingenic SDHCI (MSC) driver"); ++MODULE_AUTHOR("Large Dipper "); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION("20160808"); +diff --git a/module_drivers/drivers/mmc/host/sdhci-ingenic.h b/module_drivers/drivers/mmc/host/sdhci-ingenic.h +new file mode 100644 +index 000000000..70dde7bdc +--- /dev/null ++++ b/module_drivers/drivers/mmc/host/sdhci-ingenic.h +@@ -0,0 +1,97 @@ ++#ifndef __SDHCI_INGENIC_H__ ++#define __SDHCI_INGENIC_H__ ++ ++#include "ingenic_mmc_reg.h" ++enum cd_types { ++ SDHCI_INGENIC_CD_INTERNAL, /* use mmc internal CD line */ ++ SDHCI_INGENIC_CD_GPIO, /* use external gpio pin for CD line */ ++ SDHCI_INGENIC_CD_NONE, /* no CD line, use polling to detect card */ ++ SDHCI_INGENIC_CD_PERMANENT, /* no CD line, card permanently wired to host */ ++}; ++ ++ ++#define LOW_ENABLE 0 ++#define HIGH_ENABLE 1 ++struct ingenic_mmc_pin { ++ short num; ++ short enable_level; ++}; ++ ++struct card_gpio { ++ struct ingenic_mmc_pin wp; ++ struct ingenic_mmc_pin cd; ++ struct ingenic_mmc_pin pwr; ++ struct ingenic_mmc_pin rst; ++}; ++ ++/** ++ * struct sdhci_ingenic_platdata() - Platform device data for ingenic SDHCI ++ * @max_width: The maximum number of data bits supported. ++ * @host_caps: Standard MMC host capabilities bit field. ++ * @host_caps2: The second standard MMC host capabilities bit field. ++ * @sdr_v18: External gpio pin switch voltage from 3.3V to 1.8V ++ * @cd_type: Type of Card Detection method (see cd_types enum above) ++ * @enable_cpm_rx_tunning: Manual adjustment cpm rx tunting ++ * @enable_cpm_tx_tunning: Manual adjustment cpm tx tunting ++ * @ext_cd_gpio_invert: invert values for external CD gpio line ++ * @cfg_gpio: Configure the GPIO for a specific card bit-width ++ * ++ * Initialisation data specific to either the machine or the platform ++ * for the device driver to use or call-back when configuring gpio or ++ * card speed information. ++ */ ++struct sdhci_ingenic_pdata { ++ unsigned int host_caps; ++ unsigned int host_caps2; ++ unsigned short sdio_clk; ++ int sdr_v18; ++ unsigned int poc_v18; ++ unsigned int pm_caps; ++ enum cd_types cd_type; ++ ++ unsigned int pio_mode; ++ unsigned int enable_autocmd12; ++ ++ struct card_gpio *gpio; ++ int enable_cpm_rx_tuning; ++ int enable_cpm_tx_tuning; ++ bool ext_cd_gpio_invert; ++ ++ void (*cfg_gpio)(struct platform_device *dev, int width); ++ int (*private_init)(void); ++}; ++ ++ ++#define INGENIC_MMC_CARD_PRESENT 0 ++#define INGENIC_MMC_CARD_NEED_INIT 1 ++#define INGENIC_MMC_USE_PIO 2 ++/** ++ * struct sdhci_ingenic - INGENIC SDHCI instance ++ * @host: The SDHCI host created ++ * @pdev: The platform device we where created from. ++ * @ioarea: The resource created when we claimed the IO area. ++ * @pdata: The platform data for this controller. ++ */ ++struct sdhci_ingenic { ++ struct device *dev; ++ struct sdhci_host *host; ++ struct platform_device *pdev; ++ struct device_node *node; ++ struct sdhci_ingenic_pdata *pdata; ++ struct list_head list; ++ struct clk *clk_cgu; ++ struct clk *clk_gate; ++ struct clk *clk_ext; ++ struct clk *clk_mux; ++ struct clk *clk_mpll; ++ int cur_clk; ++ int ext_cd_irq; ++ int ext_cd_gpio; ++ unsigned long clk_rates; ++ unsigned long flags; ++}; ++ ++int ingenic_sdio_wlan_init(struct device *dev, int index); ++int ingenic_mmc_clk_ctrl(int index, int on); ++int ingenic_mmc_manual_detect(int index, int on); ++#endif /* __SDHCI_INGENIC_H__ */ +diff --git a/module_drivers/drivers/mtd/Makefile b/module_drivers/drivers/mtd/Makefile +new file mode 100644 +index 000000000..6f2dc17a3 +--- /dev/null ++++ b/module_drivers/drivers/mtd/Makefile +@@ -0,0 +1 @@ ++obj-y += devices/ +diff --git a/module_drivers/drivers/mtd/devices/Kconfig b/module_drivers/drivers/mtd/devices/Kconfig +new file mode 100644 +index 000000000..b5fb65696 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/Kconfig +@@ -0,0 +1,90 @@ ++config INGENIC_SFC ++ tristate "Ingenic series SFC driver" ++ depends on MACH_XBURST || MACH_XBURST2 ++ help ++ SFC driver for Ingenic series SoCs ++ ++if INGENIC_SFC ++ ++ ++choice ++ prompt "Select Ingenic series SFC driver version" ++ default MTD_INGENIC_SFC_V1 ++ help ++ Select the SFC driver version ++ ++config MTD_INGENIC_SFC_V1 ++ bool "Use ingenic sfc driver version 1" ++ depends on INGENIC_SFC ++ ++config MTD_INGENIC_SFC_V2 ++ bool "Use ingenic sfc driver version 2" ++ depends on INGENIC_SFC ++ ++endchoice ++ ++ ++choice ++ prompt "the SFC external memory (nor or nand)" ++ help ++ Select the SFC external memory ++ ++config MTD_INGENIC_SFC_NORFLASH ++ bool "Support ingenic sfc-nor" ++ depends on INGENIC_SFC ++ ++config MTD_INGENIC_SFC_NANDFLASH ++ bool "Support ingenic sfc-nand" ++ depends on INGENIC_SFC ++ select MTD_NAND ++ ++endchoice ++ ++ ++config INGENIC_SFCNAND_FMW ++ bool "ingenic SN and MAC read write support." ++ default n ++ depends on INGENIC_SFC && MTD_INGENIC_SFC_NANDFLASH ++ help ++ Say Y here if you want to use sn read write function. when in doubt , Say N here. ++ ++config SN_SIZE ++ int "SN space size (MB)" ++ range 1 5 ++ default 1 ++ depends on INGENIC_SFCNAND_FMW ++ ++config MAC_SIZE ++ int "MAC space size (MB)" ++ range 1 5 ++ default 1 ++ depends on INGENIC_SFCNAND_FMW ++ ++config LICENSE_SIZE ++ int "LICENSE space size (MB)" ++ range 1 5 ++ default 1 ++ depends on INGENIC_SFCNAND_FMW ++ ++ ++menuconfig INGENIC_BUILTIN_PARAMS ++ bool "Use SPI Nor Flash params built in kernel" ++ depends on MTD_INGENIC_SFC_NORFLASH ++ default n ++ help ++ Say Y here to SPI Nor Flash params built in kernel. ++ ++config INGENIC_GD25Q127C ++ bool "GD25Q127C 0xc84018" ++ depends on INGENIC_BUILTIN_PARAMS ++ ++config INGENIC_GD25Q256C ++ bool "GD25Q256C 0xc84019" ++ depends on INGENIC_BUILTIN_PARAMS ++ ++config INGENIC_GD25S512MD ++ bool "GD25S512MD 0xc84019" ++ depends on INGENIC_BUILTIN_PARAMS ++ ++ ++endif +diff --git a/module_drivers/drivers/mtd/devices/Makefile b/module_drivers/drivers/mtd/devices/Makefile +new file mode 100644 +index 000000000..29c6aed7a +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/Makefile +@@ -0,0 +1,2 @@ ++#obj-$(CONFIG_MTD_INGENIC_SFC_V1) += ingenic_sfc_v1/ ++obj-$(CONFIG_MTD_INGENIC_SFC_V2) += ingenic_sfc_v2/ +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/Makefile b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/Makefile +new file mode 100644 +index 000000000..52e8f6ea5 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/Makefile +@@ -0,0 +1,8 @@ ++# ++# linux/drivers/mtd/devices/ingenic_sfc_v2/Makefile ++# ++ ++obj-$(CONFIG_INGENIC_BUILTIN_PARAMS) += nor_device/ ++ ++ccflags-y += -I$(srctree)/drivers/mtd/nand/raw ++obj-y += ingenic_sfc_common.o ingenic_sfc_nand.o nand_device/ ingenic_sfc_nor.o ingenic_sfc_ops.o ingenic_sfc_drv.o +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/fmw.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/fmw.h +new file mode 100644 +index 000000000..00d29fa56 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/fmw.h +@@ -0,0 +1,72 @@ ++#ifndef __FMW_H__ ++#define __FMW_H__ ++ ++#define FMW_BUF_LEN 512 ++ ++#define CONFIG_SN_FLASH_SIZE (CONFIG_SN_SIZE * 1024 * 1024) ++#define CONFIG_MAC_FLASH_SIZE (CONFIG_MAC_SIZE * 1024 * 1024) ++#define CONFIG_LICENSE_FLASH_SIZE (CONFIG_LICENSE_SIZE * 1024 * 1024) ++ ++struct fmw_config { ++ uint32_t data_len; ++ uint32_t crc_val; ++}; ++ ++static const uint32_t crc_table[] = { ++ /* CRC polynomial 0xedb88320 */ ++ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, ++ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, ++ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, ++ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, ++ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, ++ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, ++ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, ++ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, ++ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, ++ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, ++ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, ++ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, ++ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, ++ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, ++ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, ++ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, ++ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, ++ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, ++ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, ++ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ++ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, ++ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, ++ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, ++ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, ++ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, ++ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, ++ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, ++ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, ++ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, ++ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, ++ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, ++ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, ++ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, ++ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, ++ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, ++ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, ++ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, ++ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, ++ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, ++ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ++ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, ++ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, ++ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d ++}; ++ ++static inline uint32_t local_crc32(uint32_t crc,unsigned char *buffer, uint32_t size) ++{ ++ uint32_t i; ++ for (i = 0; i < size; i++) { ++ crc = crc_table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8); ++ } ++ return crc ; ++} ++ ++#endif ++ +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.c +new file mode 100644 +index 000000000..2cbb15451 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.c +@@ -0,0 +1,957 @@ ++/* ++ * SFC controller for SPI protocol, use FIFO and DMA; ++ * ++ * Copyright (c) 2015 Ingenic ++ * Author: ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "ingenic_sfc_common.h" ++#include "spinor.h" ++ ++ ++#define SFC_REG_DEBUG ++ ++#define SFC_ASSERT(sfc, cond) do { \ ++ if (!(cond)) { \ ++ __assert(__FILE__, __LINE__, sfc, #cond); \ ++ } \ ++} while (0) ++ ++#define GET_PHYADDR(a) \ ++({ \ ++ unsigned int v; \ ++ if (unlikely((unsigned int)(a) & 0x40000000)) { \ ++ v = page_to_phys(vmalloc_to_page((const void *)(a))) | ((unsigned int)(a) & ~PAGE_MASK); \ ++ } else \ ++ v = ((unsigned int)(a) & 0x1fffffff); \ ++ v; \ ++ }) ++ ++static inline void sfc_writel(struct sfc *sfc, unsigned short offset, u32 value) ++{ ++ writel(value, sfc->iomem + offset); ++} ++ ++static inline unsigned int sfc_readl(struct sfc *sfc, unsigned short offset) ++{ ++ return readl(sfc->iomem + offset); ++} ++ ++#ifdef SFC_REG_DEBUG ++void dump_sfc_reg(struct sfc *sfc) ++{ ++ int i = 0; ++ ++ printk("\nSFC_GLB0 = %08x\n", sfc_readl(sfc, SFC_GLB0)); ++ printk("SFC_DEV_CONF = %08x\n", sfc_readl(sfc, SFC_DEV_CONF)); ++ printk("SFC_DEV_STA_EXP = %08x\n", sfc_readl(sfc, SFC_DEV_STA_EXP)); ++ printk("SFC_DEV0_STA_RT = %08x\n", sfc_readl(sfc, SFC_DEV0_STA_RT)); ++ printk("SFC_DEV_STA_MASK = %08x\n", sfc_readl(sfc, SFC_DEV_STA_MSK)); ++ for(i = 0; i < 6; i++){ ++ printk("SFC_TRAN_CONF0(%d) = %08x\n", i, sfc_readl(sfc, SFC_TRAN_CONF0(i))); ++ } ++ printk("SFC_TRAN_LEN = %08x\n", sfc_readl(sfc, SFC_TRAN_LEN)); ++ for(i = 0; i < 6; i++){ ++ printk("SFC_DEV_ADDR%d = %08x\n", i, sfc_readl(sfc, SFC_DEV_ADDR(i))); ++ printk("SFC_DEV_ADDR_PLUS%d = %08x\n", i, sfc_readl(sfc, SFC_DEV_ADDR_PLUS(i))); ++ } ++ ++ printk("SFC_MEM_ADDR = %08x\n", sfc_readl(sfc, SFC_MEM_ADDR)); ++ printk("SFC_TRIG = %08x\n", sfc_readl(sfc, SFC_TRIG)); ++ printk("SFC_SR = %08x\n", sfc_readl(sfc, SFC_SR)); ++ printk("SFC_SCR = %08x\n", sfc_readl(sfc, SFC_SCR)); ++ printk("SFC_INTC = %08x\n", sfc_readl(sfc, SFC_INTC)); ++ printk("SFC_FSM = %08x\n", sfc_readl(sfc, SFC_FSM)); ++ printk("SFC_CGE = %08x\n", sfc_readl(sfc, SFC_CGE)); ++ printk("SFC_CMD_IDX = %08x\n", sfc_readl(sfc, SFC_CMD_IDX)); ++ printk("SFC_COL_ADDR = %08x\n", sfc_readl(sfc, SFC_COL_ADDR)); ++ printk("SFC_ROW_ADDR = %08x\n", sfc_readl(sfc, SFC_ROW_ADDR)); ++ printk("SFC_STA_ADDR0 = %08x\n", sfc_readl(sfc, SFC_STA_ADDR0)); ++ printk("SFC_STA_ADDR1 = %08x\n", sfc_readl(sfc, SFC_STA_ADDR1)); ++ printk("SFC_DES_ADDR = %08x\n", sfc_readl(sfc, SFC_DES_ADDR)); ++ printk("SFC_GLB1 = %08x\n", sfc_readl(sfc, SFC_GLB1)); ++ printk("SFC_DEV1_STA_RT = %08x\n", sfc_readl(sfc, SFC_DEV1_STA_RT)); ++ for(i = 0; i < 6; i++) { ++ printk("SFC_TRAN_CONF1(%d) = %08x\n", i, sfc_readl(sfc, SFC_TRAN_CONF1(i))); ++ } ++ //printk("SFC_CDT = %08x\n", sfc_readl(sfc, SFC_CDT)); ++ //printk("SFC_DR = %08x\n", sfc_readl(sfc, SFC_RM_DR)); ++} ++ ++void dump_cdt(struct sfc *sfc) ++{ ++ struct sfc_cdt *cdt; ++ int i; ++ ++ if(sfc->iomem == NULL){ ++ printk("%s error: sfc res not init !\n", __func__); ++ return; ++ } ++ ++ cdt = sfc->iomem + 0x800; ++ ++ for(i = 0; i < 32; i++){ ++ printk("\nnum------->%d\n", i); ++ printk("link:%02x, ENDIAN:%02x, WORD_UINT:%02x, TRAN_MODE:%02x, ADDR_KIND:%02x\n", ++ (cdt[i].link >> 31) & 0x1, (cdt[i].link >> 18) & 0x1, ++ (cdt[i].link >> 16) & 0x3, (cdt[i].link >> 4) & 0xf, ++ (cdt[i].link >> 0) & 0x3 ++ ); ++ printk("CLK_MODE:%02x, ADDR_WIDTH:%02x, POLL_EN:%02x, CMD_EN:%02x,PHASE_FORMAT:%02x, DMY_BITS:%02x, DATA_EN:%02x, TRAN_CMD:%04x\n", ++ (cdt[i].xfer >> 29) & 0x7, (cdt[i].xfer >> 26) & 0x7, ++ (cdt[i].xfer >> 25) & 0x1, (cdt[i].xfer >> 24) & 0x1, ++ (cdt[i].xfer >> 23) & 0x1, (cdt[i].xfer >> 17) & 0x3f, ++ (cdt[i].xfer >> 16) & 0x1, (cdt[i].xfer >> 0) & 0xffff ++ ); ++ printk("DEV_STA_EXP:%08x\n", cdt[i].staExp); ++ printk("DEV_STA_MSK:%08x\n", cdt[i].staMsk); ++ } ++} ++ ++void dump_desc(struct sfc *sfc, uint32_t desc_num) ++{ ++ struct sfc_desc *desc = sfc->desc; ++ int i = 0; ++ ++ for(; i < desc_num; i++){ ++ printk("\nDMA Descriptor ---->num: %d, addr: 0x%08x\n", i, (unsigned int)virt_to_phys(&desc[i])); ++ printk("next_desc_addr: 0x%08x\n", desc[i].next_des_addr); ++ printk("mem_addr: 0x%08x\n", desc[i].mem_addr); ++ printk("tran_len: %d\n", desc[i].tran_len); ++ printk("link: %d\n\n", desc[i].link); ++ } ++} ++ ++void dump_sfc_debug(struct sfc *sfc) ++{ ++ pr_err("\n######################### sfc dump ###########################\n"); ++ pr_err("\nsfc reg: \n"); ++ dump_sfc_reg(sfc); ++ pr_err("\nsfc DMA Descriptor chain: \n"); ++ dump_desc(sfc, sfc->desc_max_num); ++ pr_err("\nsfc CDT table: \n"); ++ dump_cdt(sfc); ++ pr_err("\n######################### sfc dump end ###########################\n"); ++} ++ ++#endif ++ ++void __assert(const char *file, int line, struct sfc *sfc, const char *cond) ++{ ++ printk("assert %s failed in %s %d\n", cond, file, line); ++#ifdef SFC_REG_DEBUG ++ dump_sfc_debug(sfc); ++#endif ++ while(1); ++} ++ ++static int32_t sfc_stop(struct sfc *sfc) ++{ ++ int32_t timeout = 0xffff; ++ sfc_writel(sfc, SFC_TRIG, TRIG_STOP); ++ ++ while((sfc_readl(sfc, SFC_SR) & SFC_BUSY) && timeout--); ++ if(timeout < 0) ++ return -EIO; ++ return 0; ++} ++ ++static inline void sfc_init(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_TRIG, TRIG_STOP); ++ sfc_writel(sfc, SFC_DEV_CONF, 0); ++ ++ /* X1000 need set to 0,but X2000 can be set to 1*/ ++ sfc_writel(sfc, SFC_CGE, 0); ++ ++} ++ ++static inline void sfc_start(struct sfc *sfc) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_TRIG); ++ tmp |= TRIG_START; ++ sfc_writel(sfc, SFC_TRIG, tmp); ++} ++ ++static inline void sfc_flush_fifo(struct sfc *sfc) ++{ ++ unsigned int tmp; ++ tmp = sfc_readl(sfc, SFC_TRIG); ++ tmp |= TRIG_FLUSH; ++ sfc_writel(sfc, SFC_TRIG, tmp); ++} ++static inline void sfc_clear_end_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_END); ++} ++ ++static inline void sfc_clear_treq_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_TREQ); ++} ++ ++static inline void sfc_clear_rreq_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_RREQ); ++} ++ ++static inline void sfc_clear_over_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_OVER); ++} ++ ++static inline void sfc_clear_under_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, CLR_UNDER); ++} ++ ++static inline void sfc_clear_all_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_SCR, 0x1f); ++} ++ ++static inline void sfc_mask_all_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_INTC, 0x1f); ++} ++ ++static void sfc_dev_hw_init(struct sfc *sfc) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_DEV_CONF); ++ ++ /*cpha bit:0 , cpol bit:0 */ ++ tmp &= ~(DEV_CONF_CPHA | DEV_CONF_CPOL); ++ /*ce_dl bit:1, hold bit:1,wp bit:1*/ ++ tmp |= (DEV_CONF_CEDL | DEV_CONF_HOLDDL | DEV_CONF_WPDL); ++ sfc_writel(sfc, SFC_DEV_CONF, tmp); ++ ++ /* use CDT mode */ ++ printk("Enter 'CDT' mode.\n"); ++ tmp = sfc_readl(sfc, SFC_GLB0); ++ tmp |= GLB0_CDT_EN; ++ sfc_writel(sfc, SFC_GLB0, tmp); ++ ++ /* use DMA Descriptor chain mode */ ++ printk("Enter 'DMA Descriptor chain' mode.\n"); ++ tmp = sfc_readl(sfc, SFC_GLB0); ++ tmp |= GLB0_DES_EN; ++ sfc_writel(sfc, SFC_GLB0, tmp); ++} ++ ++static void sfc_threshold(struct sfc *sfc, uint32_t value) ++{ ++ uint32_t tmp = sfc_readl(sfc, SFC_GLB0); ++ tmp &= ~GLB0_THRESHOLD_MSK; ++ tmp |= value << GLB0_THRESHOLD_OFFSET; ++ sfc_writel(sfc, SFC_GLB0, tmp); ++} ++ ++static void sfc_smp_delay(struct sfc *sfc, uint32_t value) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_DEV_CONF); ++ tmp &= ~DEV_CONF_SMP_DELAY_MSK; ++ tmp |= value << DEV_CONF_SMP_DELAY_OFFSET; ++ sfc_writel(sfc, SFC_DEV_CONF, tmp); ++} ++ ++static int timing_is_valid(uint32_t *p_thold, uint32_t *p_tsetup, uint32_t *p_tsh) ++{ ++ int ret = 0; ++ ++#define THOLD_LO_VAL 0x0 ++#define THOLD_HI_VAL 0x3 ++#define TSETUP_LO_VAL 0x0 ++#define TSETUP_HI_VAL 0x3 ++#define TSH_LO_VAL 0x0 ++#define TSH_HI_VAL 0xf ++ ++ if ((*p_thold > THOLD_HI_VAL) || (*p_thold < THOLD_LO_VAL)) { ++ pr_err("ERROR: Check that the SFC timing parameter is invalid, thold:%d !\n", *p_thold); ++ *p_thold = clamp((uint32_t)*p_thold, (uint32_t)THOLD_LO_VAL, (uint32_t)THOLD_HI_VAL); ++ ret = -EINVAL; ++ } ++ ++ if ((*p_tsetup > TSETUP_HI_VAL) || (p_thold < TSETUP_LO_VAL)) { ++ pr_err("ERROR: Check that the SFC timing parameter is invalid, tsetup:%d !\n", *p_tsetup); ++ *p_tsetup = clamp((uint32_t)*p_tsetup, (uint32_t)TSETUP_LO_VAL, (uint32_t)TSETUP_HI_VAL); ++ ret = -EINVAL; ++ } ++ ++ if ((*p_tsh > TSH_HI_VAL) || (*p_tsh < TSH_LO_VAL)){ ++ pr_err("ERROR: Check that the SFC timing parameter is invalid, tsh:%d !\n", *p_tsh); ++ *p_tsh = clamp((uint32_t)*p_tsh, (uint32_t)TSH_LO_VAL, (uint32_t)TSH_HI_VAL); ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++ ++int32_t set_flash_timing(struct sfc *sfc, uint32_t t_hold, uint32_t t_setup, uint32_t t_shslrd, uint32_t t_shslwr) ++{ ++ uint32_t c_hold, c_setup, t_in, c_in; ++ uint32_t c_half_hold, c_half_setup, c_half_in; ++ uint32_t thold, tsetup, tsh; ++ uint32_t tmp; ++ unsigned long cycle; ++ unsigned long half_cycle; ++ unsigned long long ns; ++ ++ /* NOTE: 4 frequency division. */ ++ sfc->src_clk /= 4; ++ ++ ns = 1000000000ULL; ++ do_div(ns, sfc->src_clk); ++ cycle = ns; ++ half_cycle = cycle / 2; ++ ++ ++ /* Calculate the number of cycle */ ++ c_hold = t_hold / cycle; ++ c_half_hold = t_hold % cycle; ++ if(c_half_hold > half_cycle) { ++ c_half_hold = 0; ++ c_hold += 1; ++ } ++ ++ c_setup = t_setup / cycle; ++ c_half_setup = t_setup % cycle; ++ if(c_half_setup > half_cycle) { ++ c_half_setup = 0; ++ c_setup += 1; ++ } ++ ++ t_in = max(t_shslrd, t_shslwr); ++ c_in = t_in / cycle; ++ c_half_in = t_in % cycle; ++ if(c_half_in > half_cycle) { ++ c_half_in = 0; ++ c_in += 1; ++ } ++ ++ /* Calculate timing parameters */ ++ if(!c_hold && !c_half_hold) ++ thold = 0; ++ else ++ thold = (2 * c_hold) - 1 + (!!c_half_hold); ++ ++ if(!c_setup && !c_half_setup) ++ tsetup = 0; ++ else ++ tsetup = (2 * c_setup) - 1 + (!!c_half_setup); ++ ++ if(!c_in && !c_half_in) ++ tsh = 0; ++ else ++ tsh = (2 * c_in) - 1 + (!!c_half_in); ++ ++ /* Verify parameters validity */ ++ timing_is_valid(&thold, &tsetup, &tsh); ++ ++ tmp = sfc_readl(sfc, SFC_DEV_CONF); ++ tmp &= ~(DEV_CONF_THOLD_MSK | DEV_CONF_TSETUP_MSK | DEV_CONF_TSH_MSK); ++ tmp |= (thold << DEV_CONF_THOLD_OFFSET) | \ ++ (tsetup << DEV_CONF_TSETUP_OFFSET) | \ ++ (tsh << DEV_CONF_TSH_OFFSET); ++ ++ sfc_writel(sfc, SFC_DEV_CONF, tmp); ++ return 0; ++} ++ ++static void sfc_set_length(struct sfc *sfc, uint32_t value) ++{ ++ sfc_writel(sfc, SFC_TRAN_LEN, value); ++} ++ ++static inline void sfc_transfer_mode(struct sfc *sfc, uint32_t value) ++{ ++ uint32_t tmp; ++ tmp = sfc_readl(sfc, SFC_GLB0); ++ if(value == 0) ++ tmp &= ~GLB0_OP_MODE; ++ else ++ tmp |= GLB0_OP_MODE; ++ sfc_writel(sfc, SFC_GLB0, tmp); ++} ++ ++static void sfc_read_data(struct sfc *sfc, uint32_t *value) ++{ ++ *value = sfc_readl(sfc, SFC_RM_DR); ++} ++ ++static void sfc_write_data(struct sfc *sfc, uint32_t value) ++{ ++ sfc_writel(sfc, SFC_RM_DR, value); ++} ++ ++static void cpu_read_rxfifo(struct sfc *sfc, struct sfc_cdt_xfer *xfer) ++{ ++ int32_t i = 0; ++ uint32_t align_len = 0; ++ uint32_t fifo_num = 0; ++ uint32_t last_word = 0; ++ uint32_t unalign_data; ++ uint8_t *c; ++ ++ align_len = ALIGN(xfer->config.datalen, 4); ++ ++ if(((align_len - xfer->config.cur_len) / 4) > sfc->threshold) { ++ fifo_num = sfc->threshold; ++ last_word = 0; ++ } else { ++ /* last aligned THRESHOLD data*/ ++ if(xfer->config.datalen % 4) { ++ fifo_num = (align_len - xfer->config.cur_len) / 4 - 1; ++ last_word = 1; ++ } else { ++ fifo_num = (align_len - xfer->config.cur_len) / 4; ++ last_word = 0; ++ } ++ } ++ ++ if ((uint32_t)xfer->config.buf & 0x3) { ++ /* addr not align */ ++ for (i = 0; i < fifo_num; i++) { ++ sfc_read_data(sfc, &unalign_data); ++ c = xfer->config.buf; ++ c[0] = (unalign_data >> 0) & 0xff; ++ c[1] = (unalign_data >> 8) & 0xff; ++ c[2] = (unalign_data >> 16) & 0xff; ++ c[3] = (unalign_data >> 24) & 0xff; ++ ++ xfer->config.buf += 4; ++ xfer->config.cur_len += 4; ++ } ++ } else { ++ /* addr align */ ++ for (i = 0; i < fifo_num; i++) { ++ sfc_read_data(sfc, (uint32_t *)xfer->config.buf); ++ xfer->config.buf += 4; ++ xfer->config.cur_len += 4; ++ } ++ } ++ ++ /* last word */ ++ if(last_word == 1) { ++ sfc_read_data(sfc, &unalign_data); ++ c = (uint8_t *)xfer->config.buf; ++ ++ for(i = 0; i < xfer->config.datalen % 4; i++) { ++ c[i] = (unalign_data >> (i * 8)) & 0xff; ++ } ++ ++ xfer->config.buf += xfer->config.datalen % 4; ++ xfer->config.cur_len += xfer->config.datalen % 4; ++ } ++ ++} ++ ++static void cpu_write_txfifo(struct sfc *sfc, struct sfc_cdt_xfer *xfer) ++{ ++ uint32_t align_len = 0; ++ uint32_t fifo_num = 0; ++ uint32_t data = 0; ++ uint32_t i; ++ uint32_t nbytes = xfer->config.datalen % 4; ++ ++ align_len = xfer->config.datalen / 4 * 4; ++ ++ if (((align_len - xfer->config.cur_len) / 4) >= sfc->threshold) { ++ fifo_num = sfc->threshold; ++ nbytes = 0; ++ } else { ++ fifo_num = (align_len - xfer->config.cur_len) / 4; ++ } ++ ++ if ((uint32_t)xfer->config.buf & 0x3) { ++ /* addr not align */ ++ for(i = 0; i < fifo_num; i++) { ++ data = xfer->config.buf[3] << 24 | xfer->config.buf[2] << 16 | xfer->config.buf[1] << 8 | xfer->config.buf[0]; ++ sfc_write_data(sfc, data); ++ xfer->config.buf += 4; ++ xfer->config.cur_len += 4; ++ } ++ } else { ++ /* addr align */ ++ for(i = 0; i < fifo_num; i++) { ++ sfc_write_data(sfc, *(uint32_t *)xfer->config.buf); ++ xfer->config.buf += 4; ++ xfer->config.cur_len += 4; ++ } ++ } ++ ++ if(nbytes) { ++ data = 0; ++ for(i = 0; i < nbytes; i++) ++ data |= xfer->config.buf[i] << i * 8; ++ sfc_write_data(sfc, data); ++ xfer->config.cur_len += nbytes; ++ } ++ ++} ++ ++uint32_t sfc_get_sta_rt0(struct sfc *sfc) ++{ ++ return sfc_readl(sfc, SFC_DEV0_STA_RT); ++} ++ ++ ++static void sfc_enable_all_intc(struct sfc *sfc) ++{ ++ sfc_writel(sfc, SFC_INTC, 0); ++} ++ ++static void sfc_set_mem_addr(struct sfc *sfc, unsigned int addr) ++{ ++ sfc_writel(sfc, SFC_MEM_ADDR, addr); ++} ++ ++static void sfc_set_desc_addr(struct sfc *sfc, unsigned int addr) ++{ ++ sfc_writel(sfc, SFC_DES_ADDR, addr); ++} ++ ++void *sfc_get_paddr(void *vaddr) ++{ ++ unsigned long paddr; ++ unsigned int pfn = 0; ++ unsigned int page_offset = 0; ++ ++ if (is_vmalloc_addr(vaddr)) { ++ pfn = vmalloc_to_pfn(vaddr); ++ page_offset = (unsigned int)vaddr & (PAGE_SIZE - 1); ++ paddr = (pfn << 12) + page_offset; ++ } else { ++ paddr = virt_to_phys(vaddr); ++ } ++ ++ return (void *)paddr; ++} ++ ++int32_t create_sfc_desc(struct sfc *sfc, unsigned char *vaddr, size_t len) ++{ ++ struct sfc_desc *desc = sfc->desc; ++ uint32_t ualign_size, off_len, last_len, step_len, page_num; ++ int current_pfn = 0, next_pfn = 0; ++ int32_t i = 0, j = 0; ++ ++ ualign_size = (unsigned int)vaddr & (PAGE_SIZE - 1); ++ off_len = PAGE_SIZE - ualign_size; ++ ++ if(is_vmalloc_addr(vaddr) && (len > off_len)){ ++ page_num = (len - off_len) >> (ffs(PAGE_SIZE) - 1); ++ last_len = (len - off_len) & (PAGE_SIZE - 1); ++ current_pfn = vmalloc_to_pfn(vaddr); ++ ++ desc[i].next_des_addr = 0; ++ desc[i].mem_addr = (unsigned int)sfc_get_paddr((void *)vaddr); ++ desc[i].tran_len = off_len; ++ desc[i].link = 1; ++ ++ vaddr += off_len; ++ step_len = PAGE_SIZE; ++ ++ /* case 1. Handle physical address discontinuity */ ++ do{ ++ if(!page_num){ ++ if(last_len) ++ step_len = last_len; ++ else{ ++ break; ++ } ++ } ++ ++ next_pfn = vmalloc_to_pfn(vaddr); ++ if((current_pfn + 1) != next_pfn){ ++ if(++i > (sfc->desc_max_num - 1)){ ++ dev_err(sfc->dev, "%s The number of descriptors exceeds the maximum limit.\n", __func__); ++ return -ENOMEM; ++ } ++ ++ desc[i-1].next_des_addr = (unsigned int)sfc_get_paddr((void *)&desc[i]); ++ ++ desc[i].next_des_addr = 0; ++ desc[i].mem_addr = (unsigned int)sfc_get_paddr((void *)vaddr); ++ desc[i].tran_len = step_len; ++ desc[i].link = 1; ++ }else{ ++ desc[i].tran_len += step_len; ++ } ++ ++ ++ if(page_num){ ++ current_pfn = next_pfn; ++ vaddr += step_len; ++ } ++ }while(page_num--); ++ }else{ ++ /* case 2. Physical Address Continuity and only need one descriptor */ ++ desc[i].next_des_addr = 0; ++ desc[i].mem_addr = (unsigned int)sfc_get_paddr((void *)vaddr); ++ desc[i].tran_len = len; ++ } ++ ++ /* last descriptor is not link */ ++ desc[i].link = 0; ++ ++ return i; ++} ++ ++int request_sfc_desc(struct sfc *sfc, int desc_max_num) ++{ ++ sfc->desc = (struct sfc_desc *)dma_alloc_coherent(sfc->dev, ++ sizeof(struct sfc_desc) * desc_max_num, &sfc->desc_pyaddr, GFP_KERNEL); ++ if (IS_ERR_OR_NULL(sfc->desc)) { ++ return -ENOMEM; ++ } ++ sfc->desc_max_num = desc_max_num; ++ ++ return 0; ++} ++ ++void free_sfc_desc(struct sfc *sfc) ++{ ++ return dma_free_coherent(sfc->dev, sizeof(struct sfc_desc) * sfc->desc_max_num, sfc->desc, sfc->desc_pyaddr); ++} ++ ++#define SFC_TRANSFER_TIMEOUT 3000 //3000ms for timeout ++static int32_t sfc_start_transfer(struct sfc *sfc) ++{ ++ int32_t err; ++ sfc_clear_all_intc(sfc); ++ sfc_enable_all_intc(sfc); ++ sfc_start(sfc); ++ err = wait_for_completion_timeout(&sfc->done, msecs_to_jiffies(SFC_TRANSFER_TIMEOUT)); ++ if (!err) { ++#ifdef SFC_REG_DEBUG ++ dump_sfc_debug(sfc); ++#endif ++ sfc_mask_all_intc(sfc); ++ sfc_clear_all_intc(sfc); ++ ++ sfc_stop(sfc); ++ sfc_flush_fifo(sfc); ++ ++ printk("line:%d Timeout for ACK from SFC device\n",__LINE__); ++ return -ETIMEDOUT; ++ } ++ return 0; ++} ++ ++void write_cdt(struct sfc *sfc, struct sfc_cdt *cdt, uint16_t start_index, uint16_t end_index) ++{ ++ uint32_t cdt_num, cdt_size; ++ ++ cdt_num = end_index - start_index + 1; ++ cdt_size = sizeof(struct sfc_cdt); ++ ++ memcpy((void *)sfc->iomem + SFC_CDT + (start_index * cdt_size), (void *)cdt + (start_index * cdt_size), cdt_num * cdt_size); ++ printk("create CDT index: %d ~ %d, index number:%d.\n", start_index, end_index, cdt_num); ++} ++ ++static void sfc_set_index(struct sfc *sfc, unsigned short index) ++{ ++ ++ uint32_t tmp = sfc_readl(sfc, SFC_CMD_IDX); ++ tmp &= ~CMD_IDX_MSK; ++ tmp |= index; ++ sfc_writel(sfc, SFC_CMD_IDX, tmp); ++} ++ ++static void sfc_set_dataen(struct sfc *sfc, uint8_t dataen) ++{ ++ ++ uint32_t tmp = sfc_readl(sfc, SFC_CMD_IDX); ++ tmp &= ~CDT_DATAEN_MSK; ++ tmp |= (dataen << CDT_DATAEN_OFF); ++ sfc_writel(sfc, SFC_CMD_IDX, tmp); ++} ++ ++static void sfc_set_datadir(struct sfc *sfc, uint8_t datadir) ++{ ++ ++ uint32_t tmp = sfc_readl(sfc, SFC_CMD_IDX); ++ tmp &= ~CDT_DIR_MSK; ++ tmp |= (datadir << CDT_DIR_OFF); ++ sfc_writel(sfc, SFC_CMD_IDX, tmp); ++} ++ ++ ++int sfc_sync_cdt(struct sfc *sfc, struct sfc_cdt_xfer *xfer) ++{ ++ /*0.reset transfer length*/ ++ sfc_set_length(sfc, 0); ++ ++ /*1. set index*/ ++ sfc_set_index(sfc, xfer->cmd_index); ++ ++ /*2. set addr*/ ++ sfc_writel(sfc, SFC_COL_ADDR, xfer->columnaddr); ++ sfc_writel(sfc, SFC_ROW_ADDR, xfer->rowaddr); ++ sfc_writel(sfc, SFC_STA_ADDR0, xfer->staaddr0); ++ sfc_writel(sfc, SFC_STA_ADDR1, xfer->staaddr1); ++ ++ /*3. config data*/ ++ sfc_set_dataen(sfc, xfer->dataen); ++ if(xfer->dataen){ ++ sfc_set_datadir(sfc, xfer->config.data_dir); ++ sfc_transfer_mode(sfc, xfer->config.ops_mode); ++ sfc_set_length(sfc, xfer->config.datalen); ++ ++ /* Memory address for DMA when do not use DMA descriptor */ ++ sfc_set_mem_addr(sfc, 0); ++ ++ if(xfer->config.ops_mode == DMA_OPS){ ++ if(xfer->config.data_dir == GLB0_TRAN_DIR_READ){ ++ dma_sync_single_for_device(sfc->dev, (dma_addr_t)(sfc_get_paddr((void *)xfer->config.buf)), xfer->config.datalen, DMA_FROM_DEVICE); ++ }else{ ++ dma_sync_single_for_device(sfc->dev, (dma_addr_t)(sfc_get_paddr((void *)xfer->config.buf)), xfer->config.datalen, DMA_TO_DEVICE); ++ } ++ /* Set Descriptor address for DMA */ ++ sfc_set_desc_addr(sfc, virt_to_phys(sfc->desc)); ++ } ++ sfc->xfer = xfer; ++ } ++ ++ return sfc_start_transfer(sfc); ++ ++} ++ ++static irqreturn_t ingenic_sfc_pio_irq_callback(int32_t irq, void *dev) ++{ ++ struct sfc *sfc = dev; ++ uint32_t val; ++ uint8_t err_flag = 0; ++ ++ val = sfc_readl(sfc, SFC_SR) & 0x1f; ++ ++ spin_lock(&sfc->spin_lock); ++ ++ if(val & CLR_RREQ) { ++ sfc_clear_rreq_intc(sfc); ++ cpu_read_rxfifo(sfc, sfc->xfer); ++ } else if(val & CLR_TREQ) { ++ sfc_clear_treq_intc(sfc); ++ cpu_write_txfifo(sfc, sfc->xfer); ++ } else if(val & CLR_OVER) { ++ sfc_clear_over_intc(sfc); ++ pr_err("sfc OVER !\n"); ++ err_flag = 1; ++ } else if(val & CLR_UNDER) { ++ sfc_clear_under_intc(sfc); ++ pr_err("sfc UNDR !\n"); ++ err_flag = 1; ++ } else if(val & CLR_END) { ++ sfc_mask_all_intc(sfc); ++ sfc_clear_end_intc(sfc); ++ sfc->retry_count = 0; ++ complete(&sfc->done); ++ } ++ ++ if (err_flag) { ++#ifdef SFC_REG_DEBUG ++ dump_sfc_debug(sfc); ++#endif ++ if (sfc->retry_count > 0) { ++ sfc->retry_count--; ++ } else if (sfc->retry_count == 0){ ++ sfc->retry_count = RETRY_COUNT; ++ } ++ ++ sfc_clear_all_intc(sfc); ++ sfc_mask_all_intc(sfc); ++ complete(&sfc->done); ++ } ++ ++ spin_unlock(&sfc->spin_lock); ++ return IRQ_HANDLED; ++} ++ ++static void ingenic_sfc_init_setup(struct sfc *sfc) ++{ ++ sfc_init(sfc); ++ sfc_threshold(sfc, sfc->threshold); ++ sfc_dev_hw_init(sfc); ++ ++ sfc_transfer_mode(sfc, SLAVE_MODE); ++} ++ ++int32_t sfc_clk_set_init(struct sfc *sfc) ++{ ++ struct sfc_flash *flash = dev_get_drvdata(sfc->dev); ++ if(flash->sfc_init_frequency) ++ sfc->src_clk = flash->sfc_init_frequency; ++ else ++ sfc->src_clk = 200000000; ++ ++ ++ /* set clock rate */ ++ clk_set_rate(sfc->clk, sfc->src_clk); ++ ++ /* sample delay */ ++ if(sfc->src_clk >= 200000000){ ++ sfc_smp_delay(sfc, DEV_CONF_SMP_DELAY_180); ++ } ++ ++ return 0; ++} ++ ++int32_t sfc_clk_set_highspeed(struct sfc *sfc) ++{ ++ struct sfc_flash *flash = dev_get_drvdata(sfc->dev); ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ ++ if(nor_info->quad_succeed) ++ sfc->src_clk = flash->sfc_max_frequency; ++ else { ++ sfc->src_clk = flash->sfc_max_frequency; ++ if (sfc->src_clk > 200000000) { ++ printk("clk freq too hight! set to 200M\n"); ++ sfc->src_clk = 200000000; ++ } ++ } ++ ++ /* set clock rate */ ++ clk_set_rate(sfc->clk, sfc->src_clk); ++ ++ /* sample delay */ ++ if(sfc->src_clk >= 200000000){ ++ sfc_smp_delay(sfc, DEV_CONF_SMP_DELAY_180); ++ } ++ ++ return 0; ++} ++ ++ ++struct sfc *sfc_res_init(struct platform_device *pdev) ++{ ++ struct device_node* np = pdev->dev.of_node; ++ struct ingenic_sfc_info *pdata_params; ++ struct sfc *sfc; ++ struct resource *res; ++ int32_t err = 0; ++ ++ pdata_params = devm_kzalloc(&pdev->dev, sizeof(struct ingenic_sfc_info), GFP_KERNEL); ++ if(!pdata_params){ ++ printk("ERROR: %s %d devm_kzalloc() error !\n",__func__,__LINE__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ sfc = devm_kzalloc(&pdev->dev, sizeof(struct sfc), GFP_KERNEL); ++ if (!sfc) { ++ printk("ERROR: %s %d devm_kzalloc() error !\n",__func__,__LINE__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ sfc->dev = &pdev->dev; ++ ++ err = of_property_read_u32(np, "ingenic,spiflash_param_offset", (unsigned int *)&pdata_params->param_offset); ++ if (err < 0) { ++ dev_err(&pdev->dev, "No dts param_offset, use default.\n"); ++ pdata_params->param_offset = -EINVAL; ++ } ++ ++ err = of_property_read_u8(np, "ingenic,use_ofpart_info", &pdata_params->use_ofpart_info); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Cannot get sfc use_ofpart_info\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ err = platform_device_add_data(pdev, pdata_params, sizeof(struct ingenic_sfc_info)); ++ if(err){ ++ printk("ERROR: %s %d error !\n",__func__,__LINE__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* find and map our resources */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ sfc->iomem = devm_ioremap_resource(&pdev->dev, res); ++ if (sfc->iomem == NULL) { ++ dev_err(&pdev->dev, "Cannot map IO\n"); ++ return ERR_PTR(-ENXIO); ++ } ++ ++ sfc->clk = devm_clk_get(&pdev->dev, "div_sfc"); ++ if (IS_ERR(sfc->clk)) { ++ dev_err(&pdev->dev, "Cannot get div_sfc clock\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ sfc->clk_gate = devm_clk_get(&pdev->dev, "gate_sfc"); ++ if (IS_ERR(sfc->clk_gate)) { ++ dev_err(&pdev->dev, "Cannot get sfc clock\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ err = sfc_clk_set_init(sfc); ++ if (err) { ++ return ERR_PTR(-ENOENT); ++ } ++ ++ if(clk_prepare_enable(sfc->clk)) { ++ dev_err(&pdev->dev, "cgu clk error\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ if(clk_prepare_enable(sfc->clk_gate)) { ++ dev_err(&pdev->dev, "gate clk error\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ /* SFC parameter initialization */ ++ sfc->threshold = THRESHOLD; ++ sfc->retry_count = 0; ++ ++ /* request SFC irq */ ++ sfc->irq = platform_get_irq(pdev, 0); ++ if (sfc->irq < 0) { ++ dev_err(&pdev->dev, "No IRQ specified\n"); ++ return ERR_PTR(-ENOENT); ++ } ++ ++ err = devm_request_irq(&pdev->dev, sfc->irq, ingenic_sfc_pio_irq_callback, 0, pdev->name, sfc); ++ if (err) { ++ dev_err(&pdev->dev, "Cannot claim IRQ\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ /* SFC controller initializations for SFC */ ++ ingenic_sfc_init_setup(sfc); ++ spin_lock_init(&sfc->spin_lock); ++ init_completion(&sfc->done); ++ return sfc; ++} +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.h +new file mode 100644 +index 000000000..05d2921a3 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_common.h +@@ -0,0 +1,36 @@ ++#ifndef ingenic_SFC_COMMON_H ++#define ingenic_SFC_COMMON_H ++#include ++#include ++#include ++#include ++#include ++#include "sfc.h" ++#include "sfc_flash.h" ++ ++ ++void dump_sfc_reg(struct sfc *sfc); ++void dump_cdt(struct sfc *sfc); ++void dump_desc(struct sfc *sfc, uint32_t desc_num); ++ ++void *sfc_get_paddr(void *); ++int request_sfc_desc(struct sfc *sfc, int desc_max_num); ++void free_sfc_desc(struct sfc *sfc); ++int32_t create_sfc_desc(struct sfc *, unsigned char *, size_t); ++int sfc_sync_cdt(struct sfc *sfc, struct sfc_cdt_xfer *xfer); ++struct sfc *sfc_res_init(struct platform_device *); ++void sfc_res_deinit(struct sfc *sfc); ++uint32_t sfc_get_sta_rt(struct sfc *); ++void write_cdt(struct sfc *sfc, struct sfc_cdt *cdt, uint16_t start_index, uint16_t end_index); ++ ++int32_t set_flash_timing(struct sfc *, uint32_t, uint32_t, uint32_t, uint32_t); ++int32_t sfc_clk_set_highspeed(struct sfc *); ++ ++void __assert(const char *file, int line, struct sfc *sfc, const char *cond) ++ __attribute__ ((__noreturn__)); ++ ++ ++#define RETRY_COUNT 3 ++ ++#endif ++ +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_drv.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_drv.c +new file mode 100644 +index 000000000..22c827265 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_drv.c +@@ -0,0 +1,280 @@ ++/* ++ * SFC controller for SPI protocol, use FIFO and DMA; ++ * ++ * Copyright (c) 2015 Ingenic ++ * Author: ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic_sfc_drv.h" ++#include "sfc.h" ++#include "sfc_flash.h" ++#include "ingenic_sfc_common.h" ++ ++ ++#define is_nor_type(a) ((a[0]==0x55) && (a[1]==0xaa) && (a[2]==0x55) && (a[3]==0xaa)) ++#define is_nand_type(a) ((a[0]==0x55) && (a[1]==0xaa) && (a[2]==0x55) && (a[3]==0x00)) ++ ++unsigned int flash_type = -1; ++static int __init flash_type_get(char *str) ++{ ++ if(!strcmp(str,"nand")) ++ flash_type = NAND; ++ if(!strcmp(str,"nor")) ++ flash_type = NOR; ++ return 0; ++} ++early_param("flashtype", flash_type_get); ++ ++static const struct of_device_id ingenic_sfc_match[]; ++ ++static int __init ingenic_sfc_probe(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash; ++ int ret = 0; ++ const struct of_device_id *of_match; ++ struct sfc_data *data = NULL; ++ ++ flash = kzalloc(sizeof(struct sfc_flash), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(flash)) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, flash); ++ flash->dev = &pdev->dev; ++ ++ of_match = of_match_node( ingenic_sfc_match, pdev->dev.of_node); ++ if(IS_ERR_OR_NULL(of_match)) ++ { ++ kfree(flash); ++ return -ENODEV; ++ } ++ ++ data = (struct sfc_data *)of_match->data; ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "ingenic,sfc-init-frequency", (unsigned int *)&flash->sfc_init_frequency); ++ if (ret < 0) { ++ dev_err(flash->dev, "Cannot get sfc init frequency\n"); ++ } ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "ingenic,sfc-max-frequency", (unsigned int *)&flash->sfc_max_frequency); ++ if (ret < 0) { ++ dev_err(flash->dev, "Cannot get sfc max frequency\n"); ++ kfree(flash); ++ return -ENOENT; ++ } ++ ++ flash->sfc = sfc_res_init(pdev); ++ if(IS_ERR(flash->sfc)) { ++ dev_err(flash->dev, "sfc control init error!\n"); ++ kfree(flash); ++ return PTR_ERR(flash->sfc); ++ } ++ ++ flash->pdata_params = pdev->dev.platform_data; ++ ++ mutex_init(&flash->lock); ++ ++ if(flash_type == -1){ /*flash type is not declared in bootargs */ ++ flash_type = data->flash_type_auto_detect(pdev); ++ } ++ ++ switch(flash_type) ++ { ++ case NAND: ++ ret = ingenic_sfc_nand_probe(flash); ++ break; ++ case NOR: ++ ret = ingenic_sfc_nor_probe(flash); ++ break; ++ default: ++ dev_err(&pdev->dev, "unknown flash type"); ++ ret = -EINVAL; ++ } ++ if(ret){ ++ kfree(flash); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int __exit ingenic_sfc_remove(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_put(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ clk_put(sfc->clk); ++ free_irq(sfc->irq, flash); ++ iounmap(sfc->iomem); ++ release_mem_region(sfc->ioarea->start, resource_size(sfc->ioarea)); ++ platform_set_drvdata(pdev, NULL); ++ free_sfc_desc(sfc); ++ ++ if(flash_type == NAND){ ++ dma_free_coherent(flash->dev, flash->mtd.writesize, flash->sfc->tmp_buffer, flash->sfc->tbuff_pyaddr); ++#ifdef CONFIG_INGENIC_SFCNAND_FMW ++ sysfs_remove_group(&pdev->dev.kobj, flash->attr_group); ++#endif ++ } else if(flash_type == NOR) ++ sysfs_remove_group(&pdev->dev.kobj, flash->attr_group); ++ else{ ++ dev_err(&pdev->dev, "unknown flash type!\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++ ++static int ingenic_sfc_suspend(struct platform_device *pdev, pm_message_t msg) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ ++ /* 1.Memory power OFF */ ++ /*(*(volatile unsigned int *)0xb00000f8) |= (1 << 26);*/ ++ ++ /* 2.Irq OFF */ ++ disable_irq(sfc->irq); ++ ++ /* 3.Clk OFF */ ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ ++ return 0; ++} ++ ++static int ingenic_sfc_resume(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ ++ /* 1.Clk ON */ ++ clk_prepare_enable(sfc->clk); ++ clk_prepare_enable(sfc->clk_gate); ++ ++ /* 2.Irq ON */ ++ enable_irq(sfc->irq); ++ ++ /* 3.Memory power ON */ ++ /*(*(volatile unsigned int *)0xb00000f8) &= ~(1 << 26);*/ ++ ++ flash->create_cdt_table(flash->sfc, flash->flash_info, DEFAULT_CDT | UPDATE_CDT); ++ ++ return 0; ++} ++ ++void ingenic_sfc_shutdown(struct platform_device *pdev) ++{ ++ struct sfc_flash *flash = platform_get_drvdata(pdev); ++ struct sfc *sfc = flash->sfc; ++ ++ disable_irq(sfc->irq); ++ clk_disable_unprepare(sfc->clk_gate); ++ clk_disable_unprepare(sfc->clk); ++ return ; ++} ++ ++int flash_type_auto_detect_from_tcsm(struct platform_device *pdev) ++{ ++ volatile unsigned char *t; ++ int ret; ++ ++ t = (volatile unsigned char *)(0xb2401005); ++ ++ if (is_nand_type(t)) ++ ret = NAND; ++ else if (is_nor_type(t)) ++ ret = NOR; ++ else ++ ret = -EINVAL; ++ ++ return ret; ++} ++ ++int flash_type_auto_detect_from_ddr(struct platform_device *pdev) ++{ ++ volatile unsigned char *t; ++ int ret; ++ ++ t = (volatile unsigned char *)(0x80001005); ++ ++ if (is_nand_type(t)) ++ ret = NAND; ++ else if (is_nor_type(t)) ++ ret = NOR; ++ else ++ ret = -EINVAL; ++ ++ return ret; ++} ++ ++struct sfc_data x2000_sfc_priv = { ++ .flash_type_auto_detect = flash_type_auto_detect_from_tcsm, ++}; ++ ++struct sfc_data m300_sfc_priv = { ++ .flash_type_auto_detect = flash_type_auto_detect_from_tcsm, ++}; ++ ++struct sfc_data x2500_sfc_priv = { ++ .flash_type_auto_detect = flash_type_auto_detect_from_ddr, ++}; ++ ++struct sfc_data x1600_sfc_priv = { ++ .flash_type_auto_detect = flash_type_auto_detect_from_ddr, ++}; ++ ++static const struct of_device_id ingenic_sfc_match[] = { ++ { .compatible = "ingenic,x2000-sfc", ++ .data = &x2000_sfc_priv, }, ++ { .compatible = "ingenic,m300-sfc", ++ .data = &m300_sfc_priv, }, ++ { .compatible = "ingenic,x2500-sfc", ++ .data = &x2500_sfc_priv, }, ++ { .compatible = "ingenic,x1600-sfc", ++ .data = &x1600_sfc_priv, }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ingenic_sfc_match); ++ ++static struct platform_driver ingenic_sfc_drv = { ++ .driver = { ++ .name = "ingenic-sfc", ++ .owner = THIS_MODULE, ++ .of_match_table = ingenic_sfc_match, ++ }, ++ .remove = __exit_p(ingenic_sfc_remove), ++ .suspend = ingenic_sfc_suspend, ++ .resume = ingenic_sfc_resume, ++ .shutdown = ingenic_sfc_shutdown, ++}; ++module_platform_driver_probe(ingenic_sfc_drv, ingenic_sfc_probe); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("INGENIC SFC Driver"); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_drv.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_drv.h +new file mode 100644 +index 000000000..30c02f515 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_drv.h +@@ -0,0 +1,18 @@ ++#ifndef __INGENIC_SFC_H ++#define __INGENIC_SFC_H ++ ++#include "sfc_flash.h" ++ ++enum flash_type { ++ NAND, ++ NOR, ++}; ++ ++struct sfc_data { ++ int (*flash_type_auto_detect)(struct platform_device *pdev); ++}; ++ ++int ingenic_sfc_nand_probe(struct sfc_flash *flash); ++int ingenic_sfc_nor_probe(struct sfc_flash *flash); ++ ++#endif +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nand.c +new file mode 100644 +index 000000000..0f366dcd5 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nand.c +@@ -0,0 +1,1433 @@ ++/* ++ * SFC controller for SPI protocol, use FIFO and DMA; ++ * ++ * Copyright (c) 2015 Ingenic ++ * Author: ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sfc_flash.h" ++#include "spinand.h" ++#include "ingenic_sfc_common.h" ++#include "./nand_device/nand_common.h" ++#include "internals.h" ++#include "ingenic_sfc_drv.h" ++ ++ ++#ifdef CONFIG_INGENIC_SFCNAND_FMW ++#include "fmw.h" ++ ++struct sfc_flash *fmw_flash = NULL; ++EXPORT_SYMBOL_GPL(fmw_flash); ++#endif ++ ++#define STATUS_SUSPND (1<<0) ++#define to_ingenic_spi_nand(mtd_info) container_of(mtd_info, struct sfc_flash, mtd) ++ ++/* ++ * below is the informtion about nand ++ * that user should modify according to nand spec ++ * */ ++ ++static LIST_HEAD(nand_list); ++ ++void dump_flash_info(struct sfc_flash *flash) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_base_param *param = &nand_info->param; ++ struct mtd_partition *partition = nand_info->partition.partition; ++ uint8_t num_partition = nand_info->partition.num_partition; ++ ++ printk("id_manufactory = 0x%02x\n", nand_info->id_manufactory); ++ printk("id_device = 0x%02x\n", nand_info->id_device); ++ ++ printk("pagesize = %d\n", param->pagesize); ++ printk("blocksize = %d\n", param->blocksize); ++ printk("oobsize = %d\n", param->oobsize); ++ printk("flashsize = %d\n", param->flashsize); ++ ++ printk("tHOLD = %d\n", param->tHOLD); ++ printk("tSETUP = %d\n", param->tSETUP); ++ printk("tSHSL_R = %d\n", param->tSHSL_R); ++ printk("tSHSL_W = %d\n", param->tSHSL_W); ++ ++ printk("ecc_max = %d\n", param->ecc_max); ++ printk("need_quad = %d\n", param->need_quad); ++ ++ while(num_partition--) { ++ printk("partition(%d) name=%s\n", num_partition, partition[num_partition].name); ++ printk("partition(%d) size = 0x%llx\n", num_partition, partition[num_partition].size); ++ printk("partition(%d) offset = 0x%llx\n", num_partition, partition[num_partition].offset); ++ printk("partition(%d) mask_flags = 0x%x\n", num_partition, partition[num_partition].mask_flags); ++ } ++ return; ++} ++ ++static int badblk_check(int len, unsigned char *buf) ++{ ++ int j; ++ unsigned char *check_buf = buf; ++ ++ for(j = 0; j < len; j++){ ++ if(check_buf[j] != 0xff){ ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static int32_t sfcnand_do_read(struct sfc_flash *flash, struct flash_address *flash_address, u_char *buffer, size_t len) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_ops *ops = nand_info->ops; ++ struct sfc_cdt_xfer xfer; ++ int32_t ret = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ if(nand_info->param.need_quad){ ++ xfer.cmd_index = NAND_QUAD_READ_TO_CACHE; ++ }else{ ++ xfer.cmd_index = NAND_STANDARD_READ_TO_CACHE; ++ } ++ ++ /* set addr */ ++ xfer.rowaddr = flash_address->pageaddr; ++ ++ if(nand_info->param.plane_select){ ++ xfer.columnaddr = CONVERT_COL_ADDR(flash_address->pageaddr, flash_address->columnaddr); ++ }else{ ++ xfer.columnaddr = flash_address->columnaddr; ++ } ++ ++ xfer.staaddr0 = SPINAND_ADDR_STATUS; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = flash_address->ops_mode; ++ xfer.config.buf = buffer; ++ ++retry: ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ /* if underrun, retry read */ ++ if (flash->sfc->retry_count > 0) { ++ dev_warn(flash->dev,"SFC retry transfer! %s %s %d\n",__FILE__,__func__,__LINE__); ++ goto retry; ++ } ++ ++ /* get status to check nand ecc status */ ++ ret = ops->get_feature(flash, GET_ECC_STATUS); ++ ++ if(xfer.config.ops_mode == DMA_OPS) { ++ dma_sync_single_for_device(flash->dev, (dma_addr_t)(sfc_get_paddr((void *)xfer.config.buf)), xfer.config.datalen, DMA_FROM_DEVICE); ++ } ++ ++ return ret; ++} ++ ++static int32_t sfcnand_do_write(struct sfc_flash *flash, u_char *buffer, struct flash_address *flash_address, size_t len) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_ops *ops = nand_info->ops; ++ struct sfc_cdt_xfer xfer; ++ int32_t ret = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ if(nand_info->param.need_quad){ ++ xfer.cmd_index = NAND_QUAD_WRITE_ENABLE; ++ }else{ ++ xfer.cmd_index = NAND_STANDARD_WRITE_ENABLE; ++ } ++ ++ /* set addr */ ++ xfer.rowaddr = flash_address->pageaddr; ++ ++ if(nand_info->param.plane_select){ ++ xfer.columnaddr = CONVERT_COL_ADDR(flash_address->pageaddr, flash_address->columnaddr); ++ }else{ ++ xfer.columnaddr = flash_address->columnaddr; ++ } ++ ++ xfer.staaddr0 = SPINAND_ADDR_STATUS; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_WRITE; ++ xfer.config.ops_mode = flash_address->ops_mode; ++ xfer.config.buf = buffer; ++ ++retry: ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ /* if overrun, retry write */ ++ if (flash->sfc->retry_count > 0) { ++ dev_warn(flash->dev,"SFC retry transfer! %s %s %d\n",__FILE__,__func__,__LINE__); ++ goto retry; ++ } ++ ++ /* get status to be sure nand write completed */ ++ ret = ops->get_feature(flash, GET_WRITE_STATUS); ++ ++ return ret; ++} ++ ++static int32_t sfcnand_do_erase(struct sfc_flash *flash, uint32_t pageaddr) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_ops *ops = nand_info->ops; ++ struct sfc_cdt_xfer xfer; ++ int32_t ret = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NAND_ERASE_WRITE_ENABLE; ++ ++ /* set addr */ ++ xfer.rowaddr = pageaddr; ++ xfer.staaddr0 = SPINAND_ADDR_STATUS; ++ ++ /* set transfer config */ ++ xfer.dataen = DISABLE; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ /* get status to be sure nand write completed */ ++ ret = ops->get_feature(flash, GET_ERASE_STATUS); ++ if(ret){ ++ dev_err(flash->dev, "Erase error, get state error ! %s %s %d \n",__FILE__,__func__,__LINE__); ++ } ++ ++ return ret; ++} ++ ++ ++static int ingenic_sfcnand_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t addr = (uint32_t)instr->addr; ++ uint32_t end; ++ int32_t ret; ++ ++ if(addr % mtd->erasesize) { ++ dev_err(flash->dev, "ERROR:%s line %d eraseaddr no align\n", __func__,__LINE__); ++ return -EINVAL; ++ } ++ end = addr + instr->len; ++ mutex_lock(&flash->lock); ++ while (addr < end) { ++ if((ret = sfcnand_do_erase(flash, addr / mtd->writesize))) { ++ dev_err(flash->dev, "spi nand erase error blk id %d !\n",addr / mtd->erasesize); ++ goto erase_exit; ++ } ++ addr += mtd->erasesize; ++ } ++ ++erase_exit: ++ mutex_unlock(&flash->lock); ++ return ret; ++} ++ ++static int ingenic_sfcnand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t pagesize = mtd->writesize; ++ uint32_t pageaddr; ++ uint32_t columnaddr; ++ uint32_t rlen; ++ size_t align_len; ++ u_char* pbuf; ++ struct flash_address flash_address; ++ int32_t ret = 0, reterr = 0, ret_eccvalue = 0; ++ ++ while(len) { ++ pageaddr = (uint32_t)from / pagesize; ++ columnaddr = (uint32_t)from % pagesize; ++ rlen = min_t(uint32_t, len, pagesize - columnaddr); ++ ++ /* align length */ ++ align_len = ALIGN(rlen, 4); ++ ++ /* create DMA Descriptors */ ++ if (align_len != rlen) { ++ align_len -= 4; ++ pbuf = flash->sfc->tmp_buffer; ++ } else { ++ pbuf = buf; ++ } ++ ++ if (align_len > 0) { ++ flash_address.pageaddr = pageaddr; ++ flash_address.columnaddr = columnaddr; ++ flash_address.ops_mode = DMA_OPS; ++ ++ ret = create_sfc_desc(flash->sfc, pbuf, align_len); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ reterr = ret; ++ goto read_exit; ++ } ++ ++ /* DMA Descriptors read */ ++ ret = sfcnand_do_read(flash, &flash_address, buf, align_len); ++ if(ret < 0) { ++ dev_err(flash->dev, "%s %s %d: sfcnand_do_read error, ret = %d, \ ++ pageaddr = %u, columnaddr = %u, rlen = %u\n", ++ __FILE__, __func__, __LINE__, ++ ret, pageaddr, columnaddr, align_len); ++ reterr = ret; ++ if(ret == -EIO) ++ break; ++ } else if (ret > 0) { ++ dev_dbg(flash->dev, "%s %s %d: sfcnand_do_read, ecc value = %d, \ ++ pageaddr = %u, columnaddr = %u, rlen = %u\n", ++ __FILE__, __func__, __LINE__, ++ ret, pageaddr, columnaddr, align_len); ++ ret_eccvalue = ret; ++ } ++ } ++ ++ if (align_len != rlen) { ++ ++ if (align_len > 0) { ++ memcpy(buf, pbuf, align_len); ++ } ++ ++ flash_address.pageaddr = pageaddr; ++ flash_address.columnaddr = columnaddr + align_len; ++ flash_address.ops_mode = CPU_OPS; ++ ++ ret = sfcnand_do_read(flash, &flash_address, (u_char *)buf + align_len, rlen - align_len); ++ if(ret < 0) { ++ dev_err(flash->dev, "%s %s %d: sfcnand_do_read error, ret = %d, \ ++ pageaddr = %u, columnaddr = %u, rlen = %u\n", ++ __FILE__, __func__, __LINE__, ++ ret, flash_address.pageaddr, flash_address.columnaddr, rlen - align_len); ++ reterr = ret; ++ if(ret == -EIO) ++ break; ++ } else if (ret > 0) { ++ dev_dbg(flash->dev, "%s %s %d: sfcnand_do_read, ecc value = %d, \ ++ pageaddr = %u, columnaddr = %u, rlen = %u\n", ++ __FILE__, __func__, __LINE__, ++ ret, flash_address.pageaddr, flash_address.columnaddr, rlen - align_len); ++ ret_eccvalue = ret; ++ } ++ ++ } ++ ++ len -= rlen; ++ from += rlen; ++ buf += rlen; ++ *retlen += rlen; ++ } ++ ++read_exit: ++ return reterr ? reterr : (ret_eccvalue ? ret_eccvalue : ret); ++} ++ ++static int ingenic_sfcnand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t pagesize = mtd->writesize; ++ uint32_t pageaddr; ++ uint32_t columnaddr; ++ uint32_t wlen; ++ struct flash_address flash_address; ++ int32_t ret; ++ ++ while(len) { ++ pageaddr = (uint32_t)to / pagesize; ++ columnaddr = (uint32_t)to % pagesize; ++ wlen = min_t(uint32_t, pagesize - columnaddr, len); ++ ++ flash_address.pageaddr = pageaddr; ++ flash_address.columnaddr = columnaddr; ++ flash_address.ops_mode = DMA_OPS; ++ ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash->sfc, (unsigned char *)buf, wlen); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ goto write_exit; ++ } ++ ++ /* DMA Descriptors write */ ++ if((ret = sfcnand_do_write(flash, (u_char *)buf, &flash_address, wlen))) { ++ dev_err(flash->dev, "%s %s %d : spi nand write fail, ret = %d, \ ++ pageaddr = %u, columnaddr = %u, wlen = %u\n", ++ __FILE__, __func__, __LINE__, ret, ++ pageaddr, columnaddr, wlen); ++ break; ++ } ++ *retlen += wlen; ++ len -= wlen; ++ to += wlen; ++ buf += wlen; ++ } ++ ++write_exit: ++ return ret; ++} ++ ++static int ingenic_sfcnand_write_oob(struct mtd_info *mtd, loff_t addr, struct mtd_oob_ops *ops) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t oob_addr = (uint32_t)addr; ++ struct flash_address flash_address; ++ int32_t ret; ++ ++ mutex_lock(&flash->lock); ++ ++ if(ops->datbuf) { ++ ret = ingenic_sfcnand_write(mtd, addr, ops->len, &ops->retlen, ops->datbuf); ++ } ++ if (ops->oobbuf) { ++ flash_address.pageaddr = oob_addr / mtd->writesize; ++ flash_address.columnaddr = mtd->writesize; ++ flash_address.ops_mode = DMA_OPS; ++ ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash->sfc, (unsigned char *)ops->oobbuf, ops->ooblen); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ goto write_oob_exit; ++ } ++ ++ if((ret = sfcnand_do_write(flash, ops->oobbuf, &flash_address, ops->ooblen))) { ++ dev_err(flash->dev, "spi nand write oob error %s %s %d \n",__FILE__,__func__,__LINE__); ++ goto write_oob_exit; ++ } ++ ops->oobretlen = ops->ooblen; ++ } ++ ++write_oob_exit: ++ mutex_unlock(&flash->lock); ++ return ret; ++} ++ ++static int32_t ingenic_sfcnand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_nand(mtd); ++ uint32_t addr = (uint32_t)from; ++ int32_t ret = 0, ret_eccvalue = 0; ++ struct flash_address flash_address; ++ ++ mutex_lock(&flash->lock); ++ if(ops->datbuf) { ++ ret = ingenic_sfcnand_read(mtd, from, ops->len, &ops->retlen, ops->datbuf); ++ } ++ ++ if(ops->oobbuf) { ++ flash_address.pageaddr = addr / mtd->writesize; ++ flash_address.columnaddr = mtd->writesize + ops->ooboffs; ++ flash_address.ops_mode = DMA_OPS; ++ ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash->sfc, (unsigned char *)ops->oobbuf, ops->ooblen); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ goto read_oob_exit; ++ } ++ ++ ret = sfcnand_do_read(flash, &flash_address, ops->oobbuf, ops->ooblen); ++ if(ret < 0) ++ dev_err(flash->dev, "%s %s %d : spi nand read oob error ,ret= %d\n", __FILE__, __func__, __LINE__, ret); ++ ++ if(ret != -EIO) ++ ops->oobretlen = ops->ooblen; ++ ++ } ++ ++read_oob_exit: ++ mutex_unlock(&flash->lock); ++ ++ return ret ? ret : ret_eccvalue; ++} ++ ++static int ingenic_sfcnand_chip_block_markbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct nand_chip *chip = mtd->priv; ++ uint8_t buf[2] = { 0, 0 }; ++ int ret = 0, i = 0; ++ int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); ++ ++ /* Write bad block marker to OOB */ ++ if (write_oob) { ++ struct mtd_oob_ops ops; ++ loff_t wr_ofs = ofs; ++ ops.datbuf = NULL; ++ ops.oobbuf = buf; ++ ops.ooboffs = chip->badblockpos; ++ if (chip->options & NAND_BUSWIDTH_16) { ++ ops.ooboffs &= ~0x01; ++ ops.len = ops.ooblen = 2; ++ } else { ++ ops.len = ops.ooblen = 1; ++ } ++ ops.mode = MTD_OPS_PLACE_OOB; ++ ++ /* Write to first/last page(s) if necessary */ ++ if (chip->bbt_options & NAND_BBM_LASTPAGE) ++ wr_ofs += mtd->erasesize - mtd->writesize; ++ do { ++ ret = ingenic_sfcnand_write_oob(mtd, wr_ofs, &ops); ++ if (ret) ++ return ret; ++ wr_ofs += mtd->writesize; ++ i++; ++ } while ((chip->bbt_options & (NAND_BBM_FIRSTPAGE || NAND_BBM_SECONDPAGE)) && i < 2); ++ } ++ /* Update flash-based bad block table */ ++ if (chip->bbt_options & NAND_BBT_USE_FLASH) { ++ ret = nand_markbad_bbt(chip, ofs); ++ } ++ ++ return ret; ++} ++ ++static int ingenic_sfcnand_block_bad_check(struct mtd_info *mtd, loff_t ofs) ++{ ++ int check_len = 1; ++ unsigned char check_buf[2] = {0x0}; ++ struct nand_chip *chip = (struct nand_chip *)mtd->priv; ++ struct mtd_oob_ops ops; ++ ++ memset(&ops, 0, sizeof(ops)); ++ if (chip->options & NAND_BUSWIDTH_16) ++ check_len = 2; ++ ++ ops.oobbuf = check_buf; ++ ops.ooblen = check_len; ++ ingenic_sfcnand_read_oob(mtd, ofs, &ops); ++ if(badblk_check(check_len, check_buf)) ++ return 1; ++ return 0; ++} ++ ++static int ingenic_sfcnand_block_isbab(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct nand_chip *chip = mtd->priv; ++ if(!chip->bbt) { ++ return ingenic_sfcnand_block_bad_check(mtd, ofs); ++ } ++ return nand_isbad_bbt(chip, ofs, 0); ++} ++ ++static int ingenic_sfcnand_block_markbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ int ret = ingenic_sfcnand_block_isbab(mtd, ofs); ++ if(ret > 0) { ++ /* If it was bad already, return success and do nothing */ ++ return 0; ++ } ++ return ingenic_sfcnand_chip_block_markbad(mtd, ofs); ++} ++ ++static int ingenic_sfc_nand_set_feature(struct sfc_flash *flash, uint8_t addr, uint32_t val) ++{ ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NAND_SET_FEATURE; ++ ++ /* set addr */ ++ xfer.staaddr0 = addr; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_WRITE; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)&val; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int ingenic_sfc_nand_get_feature(struct sfc_flash *flash, uint8_t addr, uint8_t *val) ++{ ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NAND_GET_FEATURE; ++ ++ /* set addr */ ++ xfer.staaddr0 = addr; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)val; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int32_t __init ingenic_sfc_nand_dev_init(struct sfc_flash *flash) ++{ ++ int32_t ret; ++ /*release protect*/ ++ uint8_t feature = 0; ++ if((ret = ingenic_sfc_nand_set_feature(flash, SPINAND_ADDR_PROTECT, feature))) ++ goto exit; ++ ++ if((ret = ingenic_sfc_nand_get_feature(flash, SPINAND_ADDR_FEATURE, &feature))) ++ goto exit; ++ ++ feature |= (1 << 4) | (1 << 3) | (1 << 0); ++ if((ret = ingenic_sfc_nand_set_feature(flash, SPINAND_ADDR_FEATURE, feature))) ++ goto exit; ++ ++ return 0; ++exit: ++ return ret; ++} ++ ++static int32_t __init ingenic_sfc_nand_try_id(struct sfc_flash *flash) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_device *nand_device; ++ struct sfc_cdt_xfer xfer; ++ uint8_t id_buf[2] = {0}; ++ unsigned short index[2] = {NAND_TRY_ID, NAND_TRY_ID_DMY}; ++ uint8_t i = 0; ++ struct device_id_struct *device_id = NULL; ++ int32_t id_count = 0; ++ ++ for(i = 0; i < 2; i++){ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = index[i]; ++ ++ /* set addr */ ++ xfer.rowaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = sizeof(id_buf); ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = id_buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ dev_info(flash->dev, "id_manufactory = %x, id_device %x\n", id_buf[0], id_buf[1]); ++ list_for_each_entry(nand_device, &nand_list, list) { ++ if(nand_device->id_manufactory == id_buf[0]) { ++ device_id = nand_device->id_device_list; ++ id_count = nand_device->id_device_count; ++ while(id_count--) { ++ if(device_id->id_device == id_buf[1]) { ++ nand_info->id_manufactory = id_buf[0]; ++ nand_info->id_device = id_buf[1]; ++ nand_info->param = *device_id->param; ++ goto found_param; ++ } ++ device_id++; ++ } ++ } ++ } ++ } ++ ++ if(!nand_info->id_manufactory && !nand_info->id_device) { ++ dev_err(flash->dev, " ERROR!: don`t support this nand manufactory, please add nand driver.\n"); ++ return -ENODEV; ++ } ++ ++found_param: ++ dev_info(flash->dev, "Found Supported device, id_manufactory = 0x%02x, id_device = 0x%02x\n", nand_info->id_manufactory, nand_info->id_device); ++ ++ /* fill manufactory special operation and cdt params */ ++ nand_info->ops = &nand_device->ops; ++ nand_info->cdt_params = nand_info->ops->get_cdt_params(flash, nand_info->id_device); ++ ++ if (!nand_info->ops->get_feature) { ++ if (!nand_info->ops->deal_ecc_status) { ++ dev_err(flash->dev,"ERROR:xxx_nand.c \"get_feature()\" and \"deal_ecc_status()\" not define.\n"); ++ return -ENODEV; ++ } else { ++ nand_info->ops->get_feature = nand_common_get_feature; ++ printk("use nand common get feature interface!\n"); ++ } ++ } else { ++ printk("use nand private get feature interface!\n"); ++ } ++ ++ return 0; ++} ++ ++static int32_t __init nand_partition_param_copy(struct sfc_flash *flash, struct ingenic_sfcnand_burner_param *burn_param) { ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ int i = 0, count = 5, ret; ++ size_t retlen = 0; ++ ++ /* partition param copy */ ++ nand_info->partition.num_partition = burn_param->partition_num; ++ ++ burn_param->partition = kzalloc(nand_info->partition.num_partition * sizeof(struct ingenic_sfcnand_partition), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(burn_param->partition)) { ++ dev_err(flash->dev, "alloc partition space failed!\n"); ++ return -ENOMEM; ++ } ++ ++ nand_info->partition.partition = kzalloc(nand_info->partition.num_partition * sizeof(struct mtd_partition), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(nand_info->partition.partition)) { ++ dev_err(flash->dev, "alloc partition space failed!\n"); ++ kfree(burn_param->partition); ++ return -ENOMEM; ++ } ++ ++partition_retry_read: ++ ret = ingenic_sfcnand_read(&flash->mtd, flash->param_offset + sizeof(*burn_param) - sizeof(burn_param->partition), ++ nand_info->partition.num_partition * sizeof(struct ingenic_sfcnand_partition), ++ &retlen, (u_char *)burn_param->partition); ++ ++ if((ret < 0) && count--) ++ goto partition_retry_read; ++ if(count < 0) { ++ dev_err(flash->dev, "read nand partition failed!\n"); ++ kfree(burn_param->partition); ++ kfree(nand_info->partition.partition); ++ return -EIO; ++ } ++ ++ for(i = 0; i < burn_param->partition_num; i++) { ++ nand_info->partition.partition[i].name = burn_param->partition[i].name; ++ nand_info->partition.partition[i].size = burn_param->partition[i].size; ++ nand_info->partition.partition[i].offset = burn_param->partition[i].offset; ++ nand_info->partition.partition[i].mask_flags = burn_param->partition[i].mask_flags; ++ } ++ return 0; ++} ++ ++static struct ingenic_sfcnand_burner_param *burn_param; ++static int32_t __init flash_part_from_chip(struct sfc_flash *flash) { ++ ++ int32_t ret = 0, retlen = 0, count = 5; ++ ++ burn_param = kzalloc(sizeof(struct ingenic_sfcnand_burner_param), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(burn_param)) { ++ dev_err(flash->dev, "alloc burn_param space error!\n"); ++ return -ENOMEM; ++ } ++ ++ count = 5; ++param_retry_read: ++ ret = ingenic_sfcnand_read(&flash->mtd, flash->param_offset, ++ sizeof(struct ingenic_sfcnand_burner_param), &retlen, (u_char *)burn_param); ++ if((ret < 0) && count--) ++ goto param_retry_read; ++ if(count < 0) { ++ dev_err(flash->dev, "read nand base param failed!\n"); ++ ret = -EIO; ++ goto failed; ++ } ++ ++ if(burn_param->magic_num != SPINAND_MAGIC_NUM) { ++ dev_info(flash->dev, "NOTICE: this flash haven`t param, magic_num:%x\n", burn_param->magic_num); ++ ret = -EINVAL; ++ goto failed; ++ } ++ ++ if(nand_partition_param_copy(flash, burn_param)) { ++ ret = -ENOMEM; ++ goto failed; ++ } ++ ++ return 0; ++failed: ++ kfree(burn_param); ++ return ret; ++ ++} ++ ++ ++static int32_t __init ingenic_sfcnand_partition(struct sfc_flash *flash) { ++ int32_t ret = 0; ++ if((ret = flash_part_from_chip(flash))) { ++ dev_err(flash->dev, "read partition from flash failed!\n"); ++ } ++ return ret; ++} ++ ++int ingenic_sfcnand_register(struct ingenic_sfcnand_device *flash) { ++ list_add_tail(&flash->list, &nand_list); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_sfcnand_register); ++ ++/* ++ *MK_CMD(cdt, cmd, LINK, ADDRMODE, DATA_EN) ++ *MK_ST(cdt, st, LINK, ADDRMODE, ADDR_WIDTH, POLL_EN, DATA_EN, TRAN_MODE) ++ */ ++static void params_to_cdt(cdt_params_t *params, struct sfc_cdt *cdt) ++{ ++ /* 6. nand standard read */ ++ MK_CMD(cdt[NAND_STANDARD_READ_TO_CACHE], params->r_to_cache, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NAND_STANDARD_READ_GET_FEATURE], params->oip, 1, STA_ADDR0, 1, ENABLE, DISABLE, TM_STD_SPI); ++ MK_CMD(cdt[NAND_STANDARD_READ_FROM_CACHE], params->standard_r, 0, COL_ADDR, ENABLE); ++ ++ /* 7. nand quad read */ ++ MK_CMD(cdt[NAND_QUAD_READ_TO_CACHE], params->r_to_cache, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NAND_QUAD_READ_GET_FEATURE], params->oip, 1, STA_ADDR0, 1, ENABLE, DISABLE, TM_STD_SPI); ++ MK_CMD(cdt[NAND_QUAD_READ_FROM_CACHE], params->quad_r, 0, COL_ADDR, ENABLE); ++ ++ /* 8. nand standard write */ ++ MK_CMD(cdt[NAND_STANDARD_WRITE_ENABLE], params->w_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NAND_STANDARD_WRITE_TO_CACHE], params->standard_w_cache, 1, COL_ADDR, ENABLE); ++ MK_CMD(cdt[NAND_STANDARD_WRITE_EXEC], params->w_exec, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NAND_STANDARD_WRITE_GET_FEATURE], params->oip, 0, STA_ADDR0, 1, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 9. nand quad write */ ++ MK_CMD(cdt[NAND_QUAD_WRITE_ENABLE], params->w_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NAND_QUAD_WRITE_TO_CACHE], params->quad_w_cache, 1, COL_ADDR, ENABLE); ++ MK_CMD(cdt[NAND_QUAD_WRITE_EXEC], params->w_exec, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NAND_QUAD_WRITE_GET_FEATURE], params->oip, 0, STA_ADDR0, 1, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 10. block erase */ ++ MK_CMD(cdt[NAND_ERASE_WRITE_ENABLE], params->w_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NAND_BLOCK_ERASE], params->b_erase, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NAND_ERASE_GET_FEATURE], params->oip, 0, STA_ADDR0, 1, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 11. ecc status read */ ++ MK_CMD(cdt[NAND_ECC_STATUS_READ], params->ecc_r, 0, DEFAULT_ADDRMODE, ENABLE); ++ ++} ++ ++static void nand_create_cdt_table(struct sfc *sfc, void *flash_info, uint32_t flag) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash_info; ++ cdt_params_t *cdt_params; ++ struct sfc_cdt sfc_cdt[INDEX_MAX_NUM]; ++ ++ memset(sfc_cdt, 0, sizeof(sfc_cdt)); ++ if(flag & DEFAULT_CDT){ ++ ++ /* 1. reset */ ++ sfc_cdt[NAND_RESET].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NAND_RESET].xfer = CMD_XFER(0, DISABLE, 0, DISABLE, SPINAND_CMD_RESET); ++ sfc_cdt[NAND_RESET].staExp = 0; ++ sfc_cdt[NAND_RESET].staMsk = 0; ++ ++ /* 2. try id */ ++ sfc_cdt[NAND_TRY_ID].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NAND_TRY_ID].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINAND_CMD_RDID); ++ sfc_cdt[NAND_TRY_ID].staExp = 0; ++ sfc_cdt[NAND_TRY_ID].staMsk = 0; ++ ++ /* 3. try id with dummy */ ++ /* ++ * There are some NAND flash, try ID operation requires 8-bit dummy value to be all 0, ++ * so use 1 byte address instead of dummy here. ++ */ ++ sfc_cdt[NAND_TRY_ID_DMY].link = CMD_LINK(0, ROW_ADDR, TM_STD_SPI); ++ sfc_cdt[NAND_TRY_ID_DMY].xfer = CMD_XFER(1, DISABLE, 0, ENABLE, SPINAND_CMD_RDID); ++ sfc_cdt[NAND_TRY_ID_DMY].staExp = 0; ++ sfc_cdt[NAND_TRY_ID_DMY].staMsk = 0; ++ ++ /* 4. set feature */ ++ sfc_cdt[NAND_SET_FEATURE].link = CMD_LINK(0, STA_ADDR0, TM_STD_SPI); ++ sfc_cdt[NAND_SET_FEATURE].xfer = CMD_XFER(1, DISABLE, 0, ENABLE, SPINAND_CMD_SET_FEATURE); ++ sfc_cdt[NAND_SET_FEATURE].staExp = 0; ++ sfc_cdt[NAND_SET_FEATURE].staMsk = 0; ++ ++ /* 5. get feature */ ++ sfc_cdt[NAND_GET_FEATURE].link = CMD_LINK(0, STA_ADDR0, TM_STD_SPI); ++ sfc_cdt[NAND_GET_FEATURE].xfer = CMD_XFER(1, DISABLE, 0, ENABLE, SPINAND_CMD_GET_FEATURE); ++ sfc_cdt[NAND_GET_FEATURE].staExp = 0; ++ sfc_cdt[NAND_GET_FEATURE].staMsk = 0; ++ ++ if (!(flag & UPDATE_CDT)){ ++ /* first create cdt table (default)*/ ++ write_cdt(sfc, sfc_cdt, NAND_RESET, NAND_GET_FEATURE); ++ return; ++ } ++ } ++ ++ if(flag & UPDATE_CDT){ ++ cdt_params = nand_info->cdt_params; ++ params_to_cdt(cdt_params, sfc_cdt); ++ ++ /* second create cdt table */ ++ if (!(flag & DEFAULT_CDT)) { ++ /* second create cdt table (update)*/ ++ write_cdt(sfc, sfc_cdt, NAND_STANDARD_READ_TO_CACHE, NAND_ECC_STATUS_READ); ++ } else { ++ /* create full cdt table (default && update)*/ ++ write_cdt(sfc, sfc_cdt, NAND_RESET, NAND_ECC_STATUS_READ); ++ } ++ } ++ //dump_cdt(sfc); ++} ++ ++ ++static int request_sfc_buffer(struct sfc_flash *flash) ++{ ++ struct sfc *sfc = flash->sfc; ++ sfc->tmp_buffer = (uint8_t *)dma_alloc_coherent(flash->dev, ++ sizeof(uint8_t) * flash->mtd.writesize, &sfc->tbuff_pyaddr, GFP_KERNEL); ++ if (IS_ERR_OR_NULL(sfc->tmp_buffer)) { ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_INGENIC_SFCNAND_FMW ++ ++static int32_t read_fmw_config(struct mtd_info *mtd, ++ struct fmw_config *fmw_config, loff_t offset, size_t len, size_t part_size) ++{ ++ loff_t flash_off = offset; ++ int i, ret, retlen; ++ ++ for (i = 0; i < part_size / mtd->erasesize; i++) { ++ ret = ingenic_sfcnand_read(mtd, offset, len, &retlen, (uint8_t *)fmw_config); ++ if(ret >= 0 && fmw_config->data_len != 0 && fmw_config->crc_val != -1) ++ break; ++ ++ flash_off += mtd->erasesize; ++ } ++ ++ if(fmw_config->data_len == -1 || ++ fmw_config->crc_val == -1 || ++ fmw_config->data_len >= FMW_BUF_LEN) { ++ printk("%s %s %d: flash don`t save mac value!\n", ++ __FILE__, __func__, __LINE__); ++ return -ENODATA; ++ } ++ ++ if(i == part_size / mtd->erasesize) { ++ printk("%s %s %d:flash all blocks ecc error!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int32_t read_fmw(struct mtd_info *mtd, ++ uint8_t *buf, loff_t offset, size_t part_size) ++{ ++ size_t config_len = sizeof(struct fmw_config); ++ struct fmw_config fmw_config; ++ int32_t i, retlen; ++ int32_t ret = 0; ++ ++ ret = read_fmw_config(mtd, &fmw_config, offset, config_len, part_size); ++ if(ret) { ++ printk("%s %s %d:read sn config failed!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ offset += sizeof(struct fmw_config); ++ ++ for (i = 0; i < part_size / mtd->erasesize; i++) { ++ ret = ingenic_sfcnand_read(mtd, offset, fmw_config.data_len, &retlen, buf); ++ if(ret < 0) { ++ offset += mtd->erasesize; ++ continue; ++ } ++ ++ if(local_crc32(0xffffffff, buf, fmw_config.data_len) == fmw_config.crc_val) ++ break; ++ offset += mtd->erasesize; ++ } ++ ++ if(i == part_size / mtd->erasesize) { ++ printk("%s %s %d: sn flash all blocks ecc error!\n", ++ __FILE__, __func__, __LINE__); ++ return -EIO; ++ } ++ ++ return ret; ++} ++ ++static int32_t buf_compare(const uint8_t *wbuf, uint8_t *rbuf, uint32_t len) { ++ ++ int32_t i = 0; ++ for(i = 0; i < len; i++) { ++ if(wbuf[i] != rbuf[i]) { ++ printk("compare err:wbuf = 0x%02x, rbuf= 0x%02x\n", ++ wbuf[i], rbuf[i]); ++ return -EIO; ++ } ++ } ++ return 0; ++} ++ ++static int32_t write_fmw_to_flash(struct mtd_info *mtd, ++ const uint8_t *wbuf, loff_t offset, size_t len, size_t part_size) ++{ ++ uint8_t *rbuf; ++ int32_t retry_count = 5; ++ int32_t ret, retlen; ++ ++w_retry: ++ ret = ingenic_sfcnand_write(mtd, offset, len, &retlen, wbuf); ++ if(ret < 0) { ++ if(retry_count--) ++ goto w_retry; ++ if(retry_count < 0) { ++ printk("%s %s %d:write flash failed! ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ return -EIO; ++ } ++ } ++ ++ retry_count = 5; ++ retlen = 0; ++ rbuf = kzalloc(len, GFP_KERNEL); ++ if(!rbuf) { ++ printk("alloc mem failed!\n"); ++ return -ENOMEM; ++ } ++ ++r_retry: ++ ret = ingenic_sfcnand_read(mtd, offset, len, &retlen, (uint8_t *)rbuf); ++ if(ret < 0) { ++ if(retry_count--) ++ goto r_retry; ++ if(retry_count < 0) { ++ printk("%s %s %d:read flash failed! ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ goto failed; ++ } ++ } ++ ++ if(buf_compare(wbuf, rbuf, len)) { ++ printk("%s %s %d: buf compare err!\n", ++ __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ goto failed; ++ } ++ kfree(rbuf); ++ return 0; ++ ++failed: ++ kfree(rbuf); ++ return ret; ++} ++ ++static int32_t write_fmw(struct mtd_info *mtd, ++ const uint8_t *buf, loff_t offset, size_t len, size_t part_size) ++{ ++ uint8_t i; ++ uint8_t errcount = 0; ++ int32_t ret = 0; ++ ++ struct erase_info instr = { ++ .addr = offset, ++ .len = mtd->erasesize, ++ }; ++ ++ for(i = 0; i < part_size / mtd->erasesize; i++) { ++ ingenic_sfcnand_erase(mtd, &instr); ++ instr.addr += instr.len; ++ } ++ ++ for(i = 0; i < part_size / mtd->erasesize; i++) { ++ ret = write_fmw_to_flash(mtd, buf, offset, len, CONFIG_SN_FLASH_SIZE / 2); ++ if(ret) { ++ printk("%s %s %d:write data failed! errcount = %d\n", ++ __FILE__, __func__, __LINE__, errcount++); ++ } ++ offset += mtd->erasesize; ++ } ++ ++ if(errcount == part_size / mtd->erasesize) { ++ printk("all blk write failed!\n"); ++ return -EIO; ++ } ++ ++ return ret; ++} ++ ++static ssize_t nand_sn_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ uint8_t *rbuf; ++ int32_t ret; ++ size_t part_size = CONFIG_SN_FLASH_SIZE; ++ loff_t offset = mtd->size + CONFIG_MAC_FLASH_SIZE; ++ ++ rbuf = kzalloc(FMW_BUF_LEN, GFP_KERNEL); ++ if(!rbuf) { ++ printk("%s %s %d: alloc fmw buf error.\n", __FILE__,__func__,__LINE__); ++ return -ENOMEM; ++ } ++ ++ ret = read_fmw(mtd, rbuf, offset, part_size); ++ if(ret) { ++ printk("%s %s %d: sn_read failed, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ return ret; ++ } ++ ++ ret = sprintf(buf, "%s\n", rbuf); ++ ++ kfree(rbuf); ++ return ret; ++} ++ ++static ssize_t nand_sn_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++#if 0 ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ loff_t offset = mtd->size + CONFIG_MAC_FLASH_SIZE; ++ int32_t ret; ++ ++ ret = write_fmw(mtd, buf, offset, n, CONFIG_SN_FLASH_SIZE); ++ if (ret) { ++ printk("sn firmware write failed!\n"); ++ ret = -EIO; ++ } ++#endif ++ printk("The write firmware function is disabled.\n"); ++ ++ return n; ++} ++ ++static ssize_t nand_mac_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ uint8_t *rbuf; ++ size_t part_size = CONFIG_MAC_FLASH_SIZE; ++ loff_t offset = mtd->size; ++ int32_t ret; ++ ++ rbuf = kzalloc(FMW_BUF_LEN, GFP_KERNEL); ++ if(!rbuf) { ++ printk("%s %s %d: alloc fmw buf error.\n", __FILE__,__func__,__LINE__); ++ return -ENOMEM; ++ } ++ ++ ++ ret = read_fmw(mtd, rbuf, offset, part_size); ++ if(ret) { ++ printk("%s %s %d: sn_read failed, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ return ret; ++ } ++ ++ ret = sprintf(buf, "%s\n", rbuf); ++ ++ kfree(rbuf); ++ return ret; ++} ++ ++static ssize_t nand_mac_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++#if 0 ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ loff_t offset = mtd->size; ++ int32_t ret; ++ ++ ret = write_fmw(mtd, buf, offset, n, CONFIG_MAC_FLASH_SIZE); ++ if (ret) { ++ printk("sn firmware write failed!\n"); ++ ret = -EIO; ++ } ++#endif ++ printk("The write firmware function is disabled.\n"); ++ ++ return n; ++} ++ ++static ssize_t nand_license_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ uint8_t *rbuf; ++ size_t part_size = CONFIG_LICENSE_FLASH_SIZE; ++ loff_t offset = mtd->size + CONFIG_SN_FLASH_SIZE + CONFIG_MAC_FLASH_SIZE; ++ int32_t ret; ++ ++ rbuf = kzalloc(FMW_BUF_LEN, GFP_KERNEL); ++ if(!rbuf) { ++ printk("%s %s %d: alloc fmw buf error.\n", __FILE__,__func__,__LINE__); ++ return -ENOMEM; ++ } ++ ++ ret = read_fmw(mtd, rbuf, offset, part_size); ++ if(ret) { ++ printk("%s %s %d: sn_read failed, ret = %d\n", ++ __FILE__, __func__, __LINE__, ret); ++ return ret; ++ } ++ ++ ret = sprintf(buf, "%s\n", rbuf); ++ ++ kfree(rbuf); ++ return ret; ++} ++ ++static ssize_t nand_license_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t n) ++{ ++#if 0 ++ struct mtd_info *mtd = &fmw_flash->mtd; ++ loff_t offset = mtd->size + CONFIG_MAC_FLASH_SIZE + CONFIG_SN_FLASH_SIZE; ++ int32_t ret; ++ ++ ret = write_fmw(mtd, buf, offset, n, CONFIG_LICENSE_FLASH_SIZE); ++ if (ret) { ++ printk("sn firmware write failed!\n"); ++ ret = -EIO; ++ } ++#endif ++ printk(KERN_ERR "The write firmware function is disabled.\n"); ++ ++ return n; ++} ++ ++static DEVICE_ATTR(nand_sn, S_IRUGO|S_IWUSR, nand_sn_show, nand_sn_store); ++static DEVICE_ATTR(nand_mac, S_IRUGO|S_IWUSR, nand_mac_show, nand_mac_store); ++static DEVICE_ATTR(nand_license, S_IRUGO|S_IWUSR, nand_license_show, nand_license_store); ++ ++static struct attribute *nand_fmw_attrs[] = { ++ &dev_attr_nand_sn.attr, ++ &dev_attr_nand_mac.attr, ++ &dev_attr_nand_license.attr, ++ NULL, ++}; ++ ++const char nand_group_name[] = "nand_fmw"; ++static struct attribute_group nand_fmw_attr_group = { ++ .name = nand_group_name, ++ .attrs = nand_fmw_attrs, ++}; ++#endif ++ ++ ++ ++int ingenic_sfc_nand_probe(struct sfc_flash *flash) ++{ ++ const char *ingenic_probe_types[] = {"cmdlinepart", "ofpart", NULL}; ++ struct nand_chip *chip; ++ struct ingenic_sfcnand_flashinfo *nand_info; ++ int32_t ret; ++ ++ chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); ++ if (IS_ERR_OR_NULL(chip)) { ++ return -ENOMEM; ++ } ++ nand_info = kzalloc(sizeof(struct ingenic_sfcnand_flashinfo), GFP_KERNEL); ++ if(IS_ERR_OR_NULL(nand_info)) { ++ kfree(chip); ++ return -ENOMEM; ++ } ++ ++ flash->flash_info = nand_info; ++ ++ if(flash->pdata_params->param_offset > 0) { ++ flash->param_offset = flash->pdata_params->param_offset; ++ } else { ++ flash->param_offset = SPIFLASH_PARAMER_OFFSET; ++ } ++ ++#define THOLD 5 ++#define TSETUP 5 ++#define TSHSL_R 100 ++#define TSHSL_W 100 ++ ++ set_flash_timing(flash->sfc, THOLD, TSETUP, TSHSL_R, TSHSL_W); ++ ++ /* request DMA Descriptor space */ ++ ret = request_sfc_desc(flash->sfc, DESC_MAX_NUM); ++ if(ret){ ++ dev_err(flash->dev, "Failure to request DMA descriptor space!\n"); ++ ret = -ENOMEM; ++ goto free_base; ++ } ++ ++ /* Try creating default CDT table */ ++ flash->create_cdt_table = nand_create_cdt_table; ++ flash->create_cdt_table(flash->sfc, flash->flash_info ,DEFAULT_CDT); ++ ++ if((ret = ingenic_sfc_nand_dev_init(flash))) { ++ dev_err(flash->dev, "nand device init failed!\n"); ++ goto free_dma_desc; ++ } ++ ++ if((ret = ingenic_sfc_nand_try_id(flash))) { ++ dev_err(flash->dev, "try device id failed\n"); ++ goto free_dma_desc; ++ } ++ ++ /* Update to private CDT table */ ++ flash->create_cdt_table(flash->sfc, flash->flash_info, UPDATE_CDT); ++ ++ /* Update sfc rate */ ++ if((ret = sfc_clk_set_highspeed(flash->sfc))) { ++ dev_err(flash->dev, "set sfc rate failed\n"); ++ goto free_dma_desc; ++ } ++ ++ set_flash_timing(flash->sfc, nand_info->param.tHOLD, ++ nand_info->param.tSETUP, nand_info->param.tSHSL_R, nand_info->param.tSHSL_W); ++ flash->mtd.name = "sfc_nand"; ++ flash->mtd.owner = THIS_MODULE; ++ flash->mtd.type = MTD_NANDFLASH; ++ flash->mtd.flags |= MTD_CAP_NANDFLASH; ++ flash->mtd.erasesize = nand_info->param.blocksize; ++ flash->mtd.writesize = nand_info->param.pagesize; ++#ifndef CONFIG_INGENIC_SFCNAND_FMW ++ flash->mtd.size = nand_info->param.flashsize; ++#else ++ flash->mtd.size = nand_info->param.flashsize - CONFIG_SN_FLASH_SIZE - CONFIG_MAC_FLASH_SIZE - CONFIG_LICENSE_FLASH_SIZE; ++#endif ++ flash->mtd.oobsize = nand_info->param.oobsize; ++ flash->mtd.writebufsize = flash->mtd.writesize; ++ flash->mtd.bitflip_threshold = flash->mtd.ecc_strength = nand_info->param.ecc_max - 1; ++ ++ chip->badblockbits = 8; ++ chip->bbt_erase_shift = chip->phys_erase_shift = ffs(flash->mtd.erasesize) - 1; ++ chip->data_buf = kzalloc(nand_info->param.pagesize + nand_info->param.oobsize, GFP_KERNEL); ++ if(IS_ERR_OR_NULL(chip->data_buf)) { ++ dev_err(flash->dev, "alloc nand buffer->databuf failed\n"); ++ ret = -ENOMEM; ++ kfree(chip->data_buf); ++ goto free_dma_desc; ++ } ++ ++ flash->chip = chip; ++ flash->mtd.priv = chip; ++ flash->mtd._erase = ingenic_sfcnand_erase; ++ flash->mtd._read_oob = ingenic_sfcnand_read_oob; ++ flash->mtd._write_oob = ingenic_sfcnand_write_oob; ++ flash->mtd._block_isbad = ingenic_sfcnand_block_isbab; ++ flash->mtd._block_markbad = ingenic_sfcnand_block_markbad; ++ ++ /* request Temporary buffer space */ ++ ret = request_sfc_buffer(flash); ++ if(ret){ ++ dev_err(flash->dev, "Failure to request Temporary Buffer space!\n"); ++ ret = -ENOMEM; ++ goto free_chip_buffers; ++ } ++ ++ flash->dev->of_node = NULL; ++ if (!flash->pdata_params->use_ofpart_info) { ++ /* use burner partitions */ ++ if((ret = ingenic_sfcnand_partition(flash))) { ++ if(ret == -EINVAL) ++ return 0; ++ dev_err(flash->dev, "read flash partition failed!\n"); ++ goto free_all; ++ } ++ ret = mtd_device_parse_register(&flash->mtd, ingenic_probe_types, NULL, ++ nand_info->partition.partition, nand_info->partition.num_partition); ++ } else { ++ ++ /* use ofpart partitions */ ++ flash->dev->of_node = of_get_child_by_name(flash->dev->of_node, "nandflash"); ++ if (flash->dev->of_node < 0) { ++ dev_err(flash->dev, "Cannot get 'nandflash' node from dtb!\n"); ++ flash->dev->of_node = NULL; ++ } ++ ret = mtd_device_parse_register(&flash->mtd, ingenic_probe_types, &flash->ppdata, NULL, 0); ++ } ++ ++ if (ret) { ++ kfree(nand_info->partition.partition); ++ if(!flash->pdata_params->use_ofpart_info) { ++ kfree(burn_param->partition); ++ kfree(burn_param); ++ } ++ ret = -ENODEV; ++ goto free_all; ++ } ++ ++#ifdef CONFIG_INGENIC_SFCNAND_FMW ++ fmw_flash = flash; ++ ++ flash->attr_group = &nand_fmw_attr_group; ++ ret = sysfs_create_group(&flash->dev->kobj, flash->attr_group); ++ if (ret) { ++ dev_err(flash->dev, "device create sysfs group failed\n"); ++ ret = -EINVAL; ++ goto free_all; ++ } ++#endif ++ ++ return 0; ++ ++free_all: ++ dma_free_coherent(flash->dev, flash->mtd.writesize, flash->sfc->tmp_buffer, flash->sfc->tbuff_pyaddr); ++ ++free_chip_buffers: ++ kfree(chip->data_buf); ++ ++free_dma_desc: ++ free_sfc_desc(flash->sfc); ++ ++free_base: ++ kfree(chip); ++ kfree(nand_info); ++ return ret; ++} ++ +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nor.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nor.c +new file mode 100644 +index 000000000..57065c5c0 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_nor.c +@@ -0,0 +1,1000 @@ ++/* ++ * SFC controller for SPI protocol, use FIFO and DMA; ++ * ++ * Copyright (c) 2015 Ingenic ++ * Author: ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "sfc_flash.h" ++#include "spinor.h" ++#include "ingenic_sfc_common.h" ++#include "ingenic_sfc_drv.h" ++ ++//#define DEBUG_CLONER_PARAMS ++ ++#define STATUS_SUSPND (1<<0) ++ ++#define MULTI_DIE_FLASH_NUM 1 ++ ++static LIST_HEAD(nor_list); ++ ++struct sfc_flash *to_ingenic_spi_norflash(struct mtd_info *mtd_info) ++{ ++ return container_of(mtd_info, struct sfc_flash, mtd); ++} ++ ++#define ACTIVE_DIE(flash, addr) \ ++({ \ ++ uint8_t die_id = addr >> nor_info->die_shift; \ ++ if (die_id != nor_info->current_die_id) { \ ++ sfc_active_die(flash, die_id); \ ++ nor_info->current_die_id = die_id; \ ++ } \ ++ if (die_id) \ ++ addr = addr & ((1 << nor_info->die_shift) - 1); \ ++ addr; \ ++}) \ ++ ++static int sfc_die_select(struct sfc_flash *flash, uint8_t die_id) ++{ ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ xfer.cmd_index = NOR_DIE_SELECT; ++ ++ /* set addr */ ++ xfer.rowaddr = 0; ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_WRITE; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = &die_id; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int sfc_read_active_die_id(struct sfc_flash *flash, uint8_t *value) ++{ ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ xfer.cmd_index = NOR_READ_ACTIVE_DIE_ID; ++ ++ /* set addr */ ++ xfer.rowaddr = 0; ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = value; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int sfc_active_die(struct sfc_flash *flash, uint8_t die_id) ++{ ++ uint8_t die_id_read; ++ ++ sfc_die_select(flash, die_id); ++ do { ++ sfc_read_active_die_id(flash, &die_id_read); ++ }while(die_id != die_id_read); ++ ++ return 0; ++} ++ ++int32_t sfc_nor_reset(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ xfer.cmd_index = NOR_RESET_ENABLE; ++ ++ /* set addr */ ++ xfer.rowaddr = 0; ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = DISABLE; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ udelay(100); ++ return 0; ++} ++ ++int sfc_nor_read_id(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ unsigned char buf[3]; ++ unsigned int chip_id = 0; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ xfer.cmd_index = NOR_READ_ID; ++ ++ /* set addr */ ++ xfer.rowaddr = 0; ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 3; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ chip_id = ((buf[0] & 0xff) << 16) | ((buf[1] & 0xff) << 8) | (buf[2] & 0xff); ++ ++ return chip_id; ++} ++ ++static unsigned int sfc_do_read(struct sfc_flash *flash, unsigned int addr, unsigned char *buf, size_t len) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ if (nor_info->quad_succeed) { ++ xfer.cmd_index = NOR_READ_QUAD; ++ } else { ++ xfer.cmd_index = NOR_READ_STANDARD; ++ } ++ ++ /* active die */ ++ if (nor_info->die_num > 1) ++ addr = ACTIVE_DIE(flash, addr); ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ xfer.rowaddr = addr; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = DMA_OPS; ++ xfer.config.buf = buf; ++ ++retry: ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ /* if underrun, retry read */ ++ if (flash->sfc->retry_count > 0) { ++ dev_warn(flash->dev,"SFC retry transfer! %s %s %d\n",__FILE__,__func__,__LINE__); ++ goto retry; ++ } ++ ++ if(xfer.config.ops_mode == DMA_OPS) { ++ dma_sync_single_for_device(flash->dev, (dma_addr_t)(sfc_get_paddr((void *)buf)), len, DMA_FROM_DEVICE); ++ } ++ ++ return len; ++} ++ ++static unsigned int sfc_do_write(struct sfc_flash *flash, unsigned int addr, const unsigned char *buf, size_t len) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ if (nor_info->quad_succeed) { ++ xfer.cmd_index = NOR_WRITE_QUAD_ENABLE; ++ } else { ++ xfer.cmd_index = NOR_WRITE_STANDARD_ENABLE; ++ } ++ ++ /* active die */ ++ if (nor_info->die_num > 1) ++ addr = ACTIVE_DIE(flash, addr); ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ xfer.rowaddr = addr; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_WRITE; ++ xfer.config.ops_mode = DMA_OPS; ++ xfer.config.buf = (uint8_t *)buf; ++ ++retry: ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ /* if overrun, retry write */ ++ if (flash->sfc->retry_count > 0) { ++ dev_warn(flash->dev,"SFC retry transfer! %s %s %d\n",__FILE__,__func__,__LINE__); ++ goto retry; ++ } ++ ++ return len; ++} ++ ++static int sfc_do_erase(struct sfc_flash *flash, uint32_t addr) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct sfc_cdt_xfer xfer; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set Index */ ++ xfer.cmd_index = NOR_ERASE_WRITE_ENABLE; ++ ++ /* active die */ ++ if (nor_info->die_num > 1) ++ addr = ACTIVE_DIE(flash, addr); ++ ++ /* set addr */ ++ xfer.rowaddr = addr; ++ ++ /* set transfer config */ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int sfc_read(struct sfc_flash *flash, loff_t from, size_t len, unsigned char *buf) ++{ ++ int32_t ret; ++ ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash->sfc, buf, len); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ return ret; ++ } ++ ++ //dump_desc(flash->sfc, ret); ++ ++ /* DMA Descriptors read */ ++ ret = sfc_do_read(flash, (unsigned int)from, buf, len); ++ ++ return ret; ++} ++ ++static int sfc_write(struct sfc_flash *flash, loff_t to, size_t len, const unsigned char *buf) ++{ ++ int32_t ret; ++ ++ /* create DMA Descriptors */ ++ ret = create_sfc_desc(flash->sfc, (unsigned char *)buf, len); ++ if(ret < 0){ ++ dev_err(flash->dev, "%s create descriptors error. -%d\n", __func__, ret); ++ return ret; ++ } ++ ++ //dump_desc(flash->sfc, ret); ++ ++ /* DMA Descriptors write */ ++ ret = sfc_do_write(flash, (unsigned int)to, buf, len); ++ ++ return ret; ++} ++ ++static int ingenic_spi_norflash_read(struct mtd_info *mtd, loff_t from, size_t len,size_t *retlen, unsigned char *buf) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_norflash(mtd); ++ ++ mutex_lock(&flash->lock); ++ *retlen = sfc_read(flash, from, len, buf); ++ mutex_unlock(&flash->lock); ++ ++ return 0; ++} ++ ++static int ingenic_spi_norflash_write(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t *retlen, const unsigned char *buf) ++{ ++ u32 page_offset, actual_len; ++ struct sfc_flash *flash = to_ingenic_spi_norflash(mtd); ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ int ret; ++ ++ mutex_lock(&flash->lock); ++ ++ page_offset = to & (spi_nor_info->page_size - 1); ++ /* do all the bytes fit onto one page? */ ++ if (page_offset + len <= spi_nor_info->page_size) { ++ ret = sfc_write(flash, (unsigned int)to, len, buf); ++ *retlen = ret; ++ } else { ++ u32 i; ++ ++ /* the size of data remaining on the first page */ ++ actual_len = spi_nor_info->page_size - page_offset; ++ ret = sfc_write(flash, (unsigned int)to, actual_len, buf); ++ *retlen += ret; ++ ++ /* write everything in flash->page_size chunks */ ++ for (i = actual_len; i < len; i += mtd->writesize) { ++ actual_len = len - i; ++ if (actual_len >= mtd->writesize) ++ actual_len = mtd->writesize; ++ ++ ret = sfc_write(flash, (unsigned int)to + i, actual_len, buf + i); ++ *retlen += ret; ++ } ++ } ++ mutex_unlock(&flash->lock); ++ return 0; ++} ++ ++static int ingenic_spi_norflash_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct sfc_flash *flash = to_ingenic_spi_norflash(mtd); ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ uint32_t addr, end; ++ int ret; ++ ++ mutex_lock(&flash->lock); ++ ++ addr = (instr->addr & (mtd->erasesize - 1)); ++ if (addr) { ++ dev_err(flash->dev, "%s eraseaddr no align\n", __func__); ++ mutex_unlock(&flash->lock); ++ return -EINVAL; ++ } ++ end = (instr->len & (mtd->erasesize - 1)); ++ if (end) { ++ dev_err(flash->dev,"%s erasesize no align\n", __func__); ++ mutex_unlock(&flash->lock); ++ return -EINVAL; ++ } ++ addr = (uint32_t)instr->addr; ++ end = addr + (uint32_t)instr->len; ++ ++ while (addr < end) { ++ ret = sfc_do_erase(flash, addr); ++ if (ret) { ++ dev_err(flash->dev,"erase error !\n"); ++ mutex_unlock(&flash->lock); ++ return ret; ++ } ++ addr += spi_nor_info->erase_size; ++ } ++ mutex_unlock(&flash->lock); ++ ++ return 0; ++} ++ ++#ifndef CONFIG_INGENIC_BUILTIN_PARAMS ++static int32_t ingenic_spi_norflash_read_params(struct sfc_flash *flash, loff_t from, size_t len, uint8_t *buf) ++{ ++ struct sfc_cdt_xfer xfer; ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ xfer.cmd_index = NOR_READ_STANDARD; ++ ++ xfer.columnaddr = 0; ++ xfer.rowaddr = from; ++ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++#endif ++ ++#ifdef DEBUG_CLONER_PARAMS ++static void dump_cloner_params(struct burner_params *params) ++{ ++ struct spi_nor_info *spi_nor_info; ++ ++ spi_nor_info = ¶ms->spi_nor_info; ++ ++ printk("name=%s\n", spi_nor_info->name); ++ printk("id=0x%x\n", spi_nor_info->id); ++ ++ printk("read_standard->cmd=0x%x\n", spi_nor_info->read_standard.cmd); ++ printk("read_standard->dummy=0x%x\n", spi_nor_info->read_standard.dummy_byte); ++ printk("read_standard->addr_nbyte=0x%x\n", spi_nor_info->read_standard.addr_nbyte); ++ printk("read_standard->transfer_mode=0x%x\n", spi_nor_info->read_standard.transfer_mode); ++ ++ printk("read_quad->cmd=0x%x\n", spi_nor_info->read_quad.cmd); ++ printk("read_quad->dummy=0x%x\n", spi_nor_info->read_quad.dummy_byte); ++ printk("read_quad->addr_nbyte=0x%x\n", spi_nor_info->read_quad.addr_nbyte); ++ printk("read_quad->transfer_mode=0x%x\n", spi_nor_info->read_quad.transfer_mode); ++ ++ printk("write_standard->cmd=0x%x\n", spi_nor_info->write_standard.cmd); ++ printk("write_standard->dummy=0x%x\n", spi_nor_info->write_standard.dummy_byte); ++ printk("write_standard->addr_nbyte=0x%x\n", spi_nor_info->write_standard.addr_nbyte); ++ printk("write_standard->transfer_mode=0x%x\n", spi_nor_info->write_standard.transfer_mode); ++ ++ printk("write_quad->cmd=0x%x\n", spi_nor_info->write_quad.cmd); ++ printk("write_quad->dummy=0x%x\n", spi_nor_info->write_quad.dummy_byte); ++ printk("write_quad->addr_nbyte=0x%x\n", spi_nor_info->write_quad.addr_nbyte); ++ printk("write_quad->transfer_mode=0x%x\n", spi_nor_info->write_quad.transfer_mode); ++ ++ printk("sector_erase->cmd=0x%x\n", spi_nor_info->sector_erase.cmd); ++ printk("sector_erase->dummy=0x%x\n", spi_nor_info->sector_erase.dummy_byte); ++ printk("sector_erase->addr_nbyte=0x%x\n", spi_nor_info->sector_erase.addr_nbyte); ++ printk("sector_erase->transfer_mode=0x%x\n", spi_nor_info->sector_erase.transfer_mode); ++ ++ printk("wr_en->cmd=0x%x\n", spi_nor_info->wr_en.cmd); ++ printk("wr_en->dummy=0x%x\n", spi_nor_info->wr_en.dummy_byte); ++ printk("wr_en->addr_nbyte=0x%x\n", spi_nor_info->wr_en.addr_nbyte); ++ printk("wr_en->transfer_mode=0x%x\n", spi_nor_info->wr_en.transfer_mode); ++ ++ printk("en4byte->cmd=0x%x\n", spi_nor_info->en4byte.cmd); ++ printk("en4byte->dummy=0x%x\n", spi_nor_info->en4byte.dummy_byte); ++ printk("en4byte->addr_nbyte=0x%x\n", spi_nor_info->en4byte.addr_nbyte); ++ printk("en4byte->transfer_mode=0x%x\n", spi_nor_info->en4byte.transfer_mode); ++ ++ printk("quad_set->cmd=0x%x\n", spi_nor_info->quad_set.cmd); ++ printk("quad_set->bit_shift=0x%x\n", spi_nor_info->quad_set.bit_shift); ++ printk("quad_set->mask=0x%x\n", spi_nor_info->quad_set.mask); ++ printk("quad_set->val=0x%x\n", spi_nor_info->quad_set.val); ++ printk("quad_set->len=0x%x\n", spi_nor_info->quad_set.len); ++ printk("quad_set->dummy=0x%x\n", spi_nor_info->quad_set.dummy); ++ ++ printk("quad_get->cmd=0x%x\n", spi_nor_info->quad_get.cmd); ++ printk("quad_get->bit_shift=0x%x\n", spi_nor_info->quad_get.bit_shift); ++ printk("quad_get->mask=0x%x\n", spi_nor_info->quad_get.mask); ++ printk("quad_get->val=0x%x\n", spi_nor_info->quad_get.val); ++ printk("quad_get->len=0x%x\n", spi_nor_info->quad_get.len); ++ printk("quad_get->dummy=0x%x\n", spi_nor_info->quad_get.dummy); ++ ++ printk("busy->cmd=0x%x\n", spi_nor_info->busy.cmd); ++ printk("busy->bit_shift=0x%x\n", spi_nor_info->busy.bit_shift); ++ printk("busy->mask=0x%x\n", spi_nor_info->busy.mask); ++ printk("busy->val=0x%x\n", spi_nor_info->busy.val); ++ printk("busy->len=0x%x\n", spi_nor_info->busy.len); ++ printk("busy->dummy=0x%x\n", spi_nor_info->busy.dummy); ++ ++ printk("quad_ops_mode=%d\n", spi_nor_info->quad_ops_mode); ++ printk("addr_ops_mode=%d\n", spi_nor_info->addr_ops_mode); ++ ++ printk("tCHSH=%d\n", spi_nor_info->tCHSH); ++ printk("tSLCH=%d\n", spi_nor_info->tSLCH); ++ printk("tSHSL_RD=%d\n", spi_nor_info->tSHSL_RD); ++ printk("tSHSL_WR=%d\n", spi_nor_info->tSHSL_WR); ++ ++ printk("chip_size=%d\n", spi_nor_info->chip_size); ++ printk("page_size=%d\n", spi_nor_info->page_size); ++ printk("erase_size=%d\n", spi_nor_info->erase_size); ++ ++ printk("chip_erase_cmd=0x%x\n", spi_nor_info->chip_erase_cmd); ++} ++#endif ++ ++#ifndef CONFIG_INGENIC_BUILTIN_PARAMS ++static struct burner_params *burner_params = NULL; ++#endif ++ ++static int ingenic_spi_norflash_get_params(struct sfc_flash *flash) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ ++#ifndef CONFIG_INGENIC_BUILTIN_PARAMS ++ int32_t ret, err = 0; ++#else ++ int chip_id; ++ struct builtin_params builtin_params; ++ struct nor_params_node *nor_device; ++#endif ++ ++ ++#ifndef CONFIG_INGENIC_BUILTIN_PARAMS ++ dev_info(flash->dev, "Use burner params.\n"); ++ burner_params = kzalloc(sizeof(struct burner_params), GFP_KERNEL); ++ if (!burner_params) { ++ dev_err(flash->dev, "Failed to alloc mem for params\n"); ++ err = -ENOMEM; ++ goto err_params; ++ } ++ ++ ret = ingenic_spi_norflash_read_params(flash, SPIFLASH_PARAMER_OFFSET, sizeof(struct burner_params), (uint8_t *)burner_params); ++ if (ret) { ++ dev_err(flash->dev, "Failed to read params (burned by Burner)\n"); ++ err = -EINVAL; ++ goto err_read_params; ++ } ++ //add crc check for params ++ dev_info(flash->dev, "magic is 0x%x version is 0x%x\n", burner_params->magic, burner_params->version); ++ nor_info->nor_flash_info = NULL; ++ if (burner_params->magic == NOR_MAGIC) { ++ if (burner_params->version == NOR_VERSION) { ++ nor_info->nor_flash_info = &burner_params->spi_nor_info; ++ nor_info->norflash_partitions = &burner_params->norflash_partitions; ++ nor_info->nor_pri_data = &burner_params->nor_pri_data; ++ } ++ } ++ ++#else ++ ++ dev_info(flash->dev, "Use builtin params.\n"); ++ chip_id = sfc_nor_read_id(flash); ++ if (chip_id < 0) { ++ dev_err(flash->dev, "Failed to read chip id !\n"); ++ return -EINVAL; ++ } ++ dev_info(flash->dev, "chip_id: 0x%x\n", chip_id); ++ ++ list_for_each_entry(nor_device, &nor_list, list) { ++ if(nor_device->nor_device_info.id == chip_id) { ++ builtin_params.spi_nor_info = &nor_device->nor_device_info; ++ break; ++ } ++ } ++ ++ if (!builtin_params.spi_nor_info) { ++ dev_err(flash->dev, "ERROR: do support this device, id = 0x%x\n", chip_id); ++ return -ENODEV; ++ } ++ ++ get_nor_builtin_params(flash, &builtin_params); ++ ++ dev_info(flash->dev, "magic is 0x%x version is 0x%x\n", builtin_params.magic, builtin_params.version); ++ nor_info->nor_flash_info = NULL; ++ if (builtin_params.magic == NOR_MAGIC) { ++ if (builtin_params.version == NOR_VERSION) { ++ nor_info->nor_flash_info = builtin_params.spi_nor_info; ++ nor_info->nor_pri_data = builtin_params.nor_pri_data; ++ } ++ } ++#endif ++ ++ ++#ifndef CONFIG_INGENIC_BUILTIN_PARAMS ++ if ((!nor_info->nor_flash_info) || (!nor_info->norflash_partitions)) { ++ printk("WARNING : cannot get nor flash params or partitions !!!\n"); ++ err = -EINVAL; ++ goto err_read_params; ++ } ++ ++#ifdef DEBUG_CLONER_PARAMS ++ dump_cloner_params(burner_params); ++#endif ++ return 0; ++ ++err_read_params: ++ kfree(burner_params); ++err_params: ++ return err; ++#else ++ ++ if (!nor_info->nor_flash_info) { ++ printk("WARNING : cannot get nor flash params !!!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++#endif ++} ++static ssize_t sfc_nor_partition_offset_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf,"0x%x\n", SPIFLASH_PARAMER_OFFSET + sizeof(int) * 2 + sizeof(struct spi_nor_info)); ++} ++ ++static DEVICE_ATTR(sfc_nor_partition_offset, S_IRUGO | S_IWUSR, ++ sfc_nor_partition_offset_show, ++ NULL); ++ ++static ssize_t sfc_nor_params_offset_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf,"0x%x\n",SPIFLASH_PARAMER_OFFSET); ++} ++ ++static DEVICE_ATTR(sfc_nor_params_offset, S_IRUGO | S_IWUSR, ++ sfc_nor_params_offset_show, ++ NULL); ++ ++/*add your attr in here*/ ++static struct attribute *sfc_norflash_info_attributes[] = { ++ &dev_attr_sfc_nor_partition_offset.attr, ++ &dev_attr_sfc_nor_params_offset.attr, ++ NULL ++}; ++ ++static struct attribute_group sfc_norflash_info_attr_group = { ++ .attrs = sfc_norflash_info_attributes ++}; ++ ++int ingenic_sfcnor_register(struct nor_params_node *flash) { ++ list_add_tail(&flash->list, &nor_list); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ingenic_sfcnor_register); ++ ++/* ++ *MK_CMD(cdt, cmd, LINK, ADDRMODE, DATA_EN) ++ *MK_ST(cdt, st, LINK, ADDRMODE, ADDR_WIDTH, POLL_EN, DATA_EN, TRAN_MODE) ++ */ ++static void params_to_cdt(struct spi_nor_info *params, struct sfc_cdt *cdt) ++{ ++ ++ /* 4.nor singleRead */ ++ MK_CMD(cdt[NOR_READ_STANDARD], params->read_standard, 0, ROW_ADDR, ENABLE); ++ ++ /* 5.nor quadRead */ ++ MK_CMD(cdt[NOR_READ_QUAD], params->read_quad, 0, ROW_ADDR, ENABLE); ++ ++ /* 6. nor writeStandard */ ++ MK_CMD(cdt[NOR_WRITE_STANDARD_ENABLE], params->wr_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NOR_WRITE_STANDARD], params->write_standard, 1, ROW_ADDR, ENABLE); ++ MK_ST(cdt[NOR_WRITE_STANDARD_FINISH], params->busy, 0, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 7. nor writeQuad */ ++ MK_CMD(cdt[NOR_WRITE_QUAD_ENABLE], params->wr_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NOR_WRITE_QUAD], params->write_quad, 1, ROW_ADDR, ENABLE); ++ MK_ST(cdt[NOR_WRITE_QUAD_FINISH], params->busy, 0, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 8. nor erase */ ++ MK_CMD(cdt[NOR_ERASE_WRITE_ENABLE], params->wr_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_CMD(cdt[NOR_ERASE], params->sector_erase, 1, ROW_ADDR, DISABLE); ++ MK_ST(cdt[NOR_ERASE_FINISH], params->busy, 0, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ /* 9. quad mode */ ++ if(params->quad_ops_mode){ ++ MK_CMD(cdt[NOR_QUAD_SET_ENABLE], params->wr_en, 1, DEFAULT_ADDRMODE, DISABLE); ++ MK_ST(cdt[NOR_QUAD_SET], params->quad_set, 1, DEFAULT_ADDRMODE, 0, DISABLE, ENABLE, TM_STD_SPI); //disable poll, enable data ++ ++ MK_ST(cdt[NOR_QUAD_FINISH], params->busy, 1, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ ++ MK_ST(cdt[NOR_QUAD_GET], params->quad_get, 0, DEFAULT_ADDRMODE, 0, ENABLE, DISABLE, TM_STD_SPI); ++ } ++ ++ /* 10. nor write ENABLE */ ++ MK_CMD(cdt[NOR_WRITE_ENABLE], params->wr_en, 0, DEFAULT_ADDRMODE, DISABLE); ++ ++ /* 11. entry 4byte mode */ ++ MK_CMD(cdt[NOR_EN_4BYTE], params->en4byte, 0, DEFAULT_ADDRMODE, DISABLE); ++ ++ /* 12. die select */ ++ cdt[NOR_DIE_SELECT].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ cdt[NOR_DIE_SELECT].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINOR_OP_DIE_SEL); ++ cdt[NOR_DIE_SELECT].staExp = 0; ++ cdt[NOR_DIE_SELECT].staMsk = 0; ++ ++ /* 13. read active die ID */ ++ cdt[NOR_READ_ACTIVE_DIE_ID].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ cdt[NOR_READ_ACTIVE_DIE_ID].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINOR_OP_READ_DIE_ID); ++ cdt[NOR_READ_ACTIVE_DIE_ID].staExp = 0; ++ cdt[NOR_READ_ACTIVE_DIE_ID].staMsk = 0; ++ ++ ++} ++ ++static void nor_create_cdt_table(struct sfc *sfc, void *flash_info, uint32_t flag) ++{ ++ struct spinor_flashinfo *nor_info = flash_info; ++ struct sfc_cdt sfc_cdt[INDEX_MAX_NUM]; ++ ++ memset(sfc_cdt, 0, sizeof(sfc_cdt)); ++ ++ if(flag & DEFAULT_CDT){ ++ ++ /* 1.nor reset */ ++ sfc_cdt[NOR_RESET_ENABLE].link = CMD_LINK(1, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_RESET_ENABLE].xfer = CMD_XFER(0, DISABLE, 0, DISABLE, SPINOR_OP_RSTEN); ++ sfc_cdt[NOR_RESET_ENABLE].staExp = 0; ++ sfc_cdt[NOR_RESET_ENABLE].staMsk = 0; ++ ++ sfc_cdt[NOR_RESET].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_RESET].xfer = CMD_XFER(0, DISABLE, 0, DISABLE, SPINOR_OP_RST); ++ sfc_cdt[NOR_RESET].staExp = 0; ++ sfc_cdt[NOR_RESET].staMsk = 0; ++ ++ ++ /* 2.nor read id */ ++ sfc_cdt[NOR_READ_ID].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_READ_ID].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINOR_OP_RDID); ++ sfc_cdt[NOR_READ_ID].staExp = 0; ++ sfc_cdt[NOR_READ_ID].staMsk = 0; ++ ++ ++ /* 3. nor get status */ ++ sfc_cdt[NOR_GET_STATUS].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_GET_STATUS].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINOR_OP_RDSR); ++ sfc_cdt[NOR_GET_STATUS].staExp = 0; ++ sfc_cdt[NOR_GET_STATUS].staMsk = 0; ++ ++ sfc_cdt[NOR_GET_STATUS_1].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_GET_STATUS_1].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINOR_OP_RDSR_1); ++ sfc_cdt[NOR_GET_STATUS_1].staExp = 0; ++ sfc_cdt[NOR_GET_STATUS_1].staMsk = 0; ++ ++ sfc_cdt[NOR_GET_STATUS_2].link = CMD_LINK(0, DEFAULT_ADDRMODE, TM_STD_SPI); ++ sfc_cdt[NOR_GET_STATUS_2].xfer = CMD_XFER(0, DISABLE, 0, ENABLE, SPINOR_OP_RDSR_2); ++ sfc_cdt[NOR_GET_STATUS_2].staExp = 0; ++ sfc_cdt[NOR_GET_STATUS_2].staMsk = 0; ++ ++ if (!(flag & UPDATE_CDT)) { ++ /* 4.nor singleRead */ ++ sfc_cdt[NOR_READ_STANDARD].link = CMD_LINK(0, ROW_ADDR, TM_STD_SPI); ++ sfc_cdt[NOR_READ_STANDARD].xfer = CMD_XFER(DEFAULT_ADDRSIZE, DISABLE, 0, ENABLE, SPINOR_OP_READ); ++ sfc_cdt[NOR_READ_STANDARD].staExp = 0; ++ sfc_cdt[NOR_READ_STANDARD].staMsk = 0; ++ ++ /* first create cdt table (default)*/ ++ write_cdt(sfc, sfc_cdt, NOR_RESET_ENABLE, NOR_READ_STANDARD); ++ return; ++ } ++ } ++ ++ ++ if(flag & UPDATE_CDT){ ++ ++ params_to_cdt(nor_info->nor_flash_info, sfc_cdt); ++ ++ if (!(flag & DEFAULT_CDT)) { ++ /* second create cdt table (update)*/ ++ write_cdt(sfc, sfc_cdt, NOR_READ_STANDARD, NOR_READ_ACTIVE_DIE_ID); ++ } else { ++ /* create full cdt table (default && update)*/ ++ write_cdt(sfc, sfc_cdt, NOR_RESET_ENABLE, NOR_READ_ACTIVE_DIE_ID); ++ } ++ } ++ //dump_cdt(sfc); ++ return; ++} ++ ++ ++static struct multi_die_flash die_flash[MULTI_DIE_FLASH_NUM] = { ++ [0] = {0xc84019, 2, "GD25S512MD"}, ++}; ++ ++int ingenic_sfc_nor_probe(struct sfc_flash *flash) ++{ ++ struct mtd_partition *ingenic_mtd_partition; ++ const char *ingenic_probe_types[] = {"cmdlinepart", "ofpart", NULL}; ++ int num_partition_info = 0; ++ int err = 0,ret = 0; ++ struct spinor_flashinfo *nor_info; ++ int i; ++ int tchsh; ++ int tslch; ++ int tshsl_rd; ++ int tshsl_wr; ++ uint32_t die_size; ++ ++ nor_info = kzalloc(sizeof(*nor_info), GFP_KERNEL); ++ if(!nor_info) { ++ dev_err(flash->dev, "alloc nor_info failed!\n"); ++ return -ENOMEM; ++ } ++ flash->flash_info = nor_info; ++ ++ set_flash_timing(flash->sfc, DEF_TCHSH, DEF_TSLCH, DEF_TSHSL_R, DEF_TSHSL_W); ++ ++ /* request DMA Descriptor space */ ++ ret = request_sfc_desc(flash->sfc, DESC_MAX_NUM); ++ if(ret){ ++ dev_err(flash->dev, "Failure to request DMA descriptor space!\n"); ++ ret = -ENOMEM; ++ goto err_sfc_desc_request; ++ } ++ ++ /* try creating default CDT table */ ++ flash->create_cdt_table = nor_create_cdt_table; ++ flash->create_cdt_table(flash->sfc, flash->flash_info, DEFAULT_CDT); ++ ++ ret = sfc_nor_reset(flash); ++ if(ret) { ++ dev_warn(flash->dev, "Failed to reset nor flash, Try to go on\n"); ++ } ++ ++ ret = ingenic_spi_norflash_get_params(flash); ++ if (ret) { ++ ret = -ENODEV; ++ dev_err(flash->dev, "Failed to match correct nor flash device!\n"); ++ goto err_match_device; ++ } ++ ++ /* Update to private CDT table */ ++ flash->create_cdt_table(flash->sfc, flash->flash_info, UPDATE_CDT); ++ ++ /* Update sfc rate */ ++ if((ret = sfc_clk_set_highspeed(flash->sfc))) { ++ dev_err(flash->dev, "set sfc rate failed\n"); ++ goto err_match_device; ++ } ++ ++#ifndef CONFIG_INGENIC_BUILTIN_PARAMS ++ num_partition_info = nor_info->norflash_partitions->num_partition_info; ++ ingenic_mtd_partition = (struct mtd_partition*)kzalloc(sizeof(struct mtd_partition) * num_partition_info, GFP_KERNEL); ++ if (!ingenic_mtd_partition) { ++ ret = -ENOMEM; ++ dev_err(flash->dev, "Failed to alloc mem for ingenic_mtd_partition\n"); ++ goto err_alloc_partition; ++ } ++ ++ for (i = 0; i < num_partition_info; i++) { ++ ingenic_mtd_partition[i].name = nor_info->norflash_partitions->nor_partition[i].name; ++ ingenic_mtd_partition[i].offset = nor_info->norflash_partitions->nor_partition[i].offset; ++ ++ if (nor_info->norflash_partitions->nor_partition[i].size == -1) { ++ ingenic_mtd_partition[i].size = MTDPART_SIZ_FULL; ++ } else { ++ ingenic_mtd_partition[i].size = nor_info->norflash_partitions->nor_partition[i].size; ++ } ++ ++ if (nor_info->norflash_partitions->nor_partition[i].mask_flags & NORFLASH_PART_RO) { //have problem!!! ++ ingenic_mtd_partition[i].mask_flags = MTD_CAP_RAM; ++ } else { ++ ingenic_mtd_partition[i].mask_flags = MTD_CAP_ROM; ++ } ++ ++ } ++#endif ++ ++ flash->mtd.name = "sfc_mtd"; ++ flash->mtd.owner = THIS_MODULE; ++ flash->mtd.type = MTD_NORFLASH; ++ flash->mtd.flags = MTD_CAP_NORFLASH; ++ flash->mtd.erasesize = nor_info->nor_pri_data->fs_erase_size; ++ flash->mtd.writesize = nor_info->nor_flash_info->page_size; ++ flash->mtd.size = nor_info->nor_flash_info->chip_size; ++ flash->mtd._erase = ingenic_spi_norflash_erase; ++ flash->mtd._read = ingenic_spi_norflash_read; ++ flash->mtd._write = ingenic_spi_norflash_write; ++ ++ tchsh = nor_info->nor_flash_info->tCHSH; ++ tslch = nor_info->nor_flash_info->tSLCH; ++ tshsl_rd = nor_info->nor_flash_info->tSHSL_RD; ++ tshsl_wr = nor_info->nor_flash_info->tSHSL_WR; ++ set_flash_timing(flash->sfc, tchsh, tslch, tshsl_rd, tshsl_wr); ++ ++ sfc_nor_get_special_ops(flash); ++ ++ if (nor_info->nor_pri_data->uk_quad) { ++ if (nor_info->nor_flash_ops->set_quad_mode) { ++ ret = nor_info->nor_flash_ops->set_quad_mode(flash); ++ if (ret < 0) { ++ nor_info->quad_succeed = 0; ++ dev_info(flash->dev, "set quad mode error !\n"); ++ } else { ++ nor_info->quad_succeed = 1; ++ dev_info(flash->dev, "nor flash quad mode is set, now use quad mode!\n"); ++ } ++ } ++ } ++ ++ /* Multi Die support */ ++ nor_info->die_num = 1; ++ for (i = 0; i < MULTI_DIE_FLASH_NUM; i++) { ++ if(!(strcmp(die_flash[i].flash_name, nor_info->nor_flash_info->name))) { ++ nor_info->die_num = die_flash[i].die_num; ++ die_size = nor_info->nor_flash_info->chip_size / nor_info->die_num; ++ nor_info->die_shift = ffs(die_size) - 1; ++ nor_info->current_die_id = 0; ++ ++ printk("Flash :%s support multi die, die number:%d\n", die_flash[i].flash_name, die_flash[i].die_num); ++ break; ++ } ++ } ++ ++ ++ /* if nor flash size is greater than 16M, use 4byte mode */ ++ if(flash->mtd.size > NOR_SIZE_16M) { ++ if (nor_info->nor_flash_ops->set_4byte_mode) { ++ nor_info->nor_flash_ops->set_4byte_mode(flash); ++ } ++ } ++ ++ /* ++ * partiton parser: 1.cmdlinepart 2.device tree 3.flash burner ++ */ ++ flash->dev->of_node = NULL; ++ if (flash->pdata_params->use_ofpart_info) { ++ flash->dev->of_node = of_get_child_by_name(flash->dev->of_node, "norflash"); ++ if (flash->dev->of_node < 0) { ++ dev_err(flash->dev, "Cannot get 'norflash' node from dtb!\n"); ++ flash->dev->of_node = NULL; ++ } ++ } ++ ++ ret = mtd_device_parse_register(&flash->mtd, ingenic_probe_types, &flash->ppdata, ingenic_mtd_partition, num_partition_info); ++ if (ret) { ++ ret = -ENODEV; ++ dev_err(flash->dev, "Failed to parse register!\n"); ++ goto err_parse_register; ++ } ++ ++ flash->attr_group = &sfc_norflash_info_attr_group; ++ ret = sysfs_create_group(&flash->dev->kobj, flash->attr_group); ++ if (err) { ++ dev_err(flash->dev, "failed to register sysfs\n"); ++ ret = -EIO; ++ goto err_create_group; ++ } ++ ++ dev_info(flash->dev,"SPI NOR MTD LOAD OK\n"); ++ return 0; ++ ++err_create_group: ++ mtd_device_unregister(&flash->mtd); ++err_parse_register: ++ kfree(ingenic_mtd_partition); ++#ifndef CONFIG_INGENIC_BUILTIN_PARAMS ++err_alloc_partition: ++ kfree(burner_params); ++#endif ++err_match_device: ++err_sfc_desc_request: ++ free_sfc_desc(flash->sfc); ++ kfree(nor_info); ++ return ret; ++ ++} ++ +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_ops.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_ops.c +new file mode 100644 +index 000000000..63dc8babf +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/ingenic_sfc_ops.c +@@ -0,0 +1,225 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "spinor.h" ++#include "ingenic_sfc_common.h" ++ ++int get_status(struct sfc_flash *flash, int command, int len) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ struct spi_nor_st_info *quad_get; ++ struct spi_nor_st_info *busy; ++ struct sfc_cdt_xfer xfer; ++ static unsigned char buf[32]; ++ unsigned int val = 0, i = 0, ret = 0; ++ ++ busy = &spi_nor_info->busy; ++ quad_get = &spi_nor_info->quad_get; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ memset(buf, 0, sizeof(buf)); ++ ++ /* set index */ ++ if(command == busy->cmd) ++ xfer.cmd_index = NOR_GET_STATUS; ++ else if(command == quad_get->cmd) ++ xfer.cmd_index = NOR_GET_STATUS_1; ++ else ++ xfer.cmd_index = NOR_GET_STATUS_2; ++ ++ /* set addr */ ++ xfer.rowaddr = 0; ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ printk("sfc_sync error! %s %s %d\n", __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ } ++ ++ for(i = 0; i < len; i++) { ++ val |= buf[i] << (i * 8); ++ } ++ ++ return val; ++} ++ ++/* do nothing to set quad mode, use cmd directly */ ++static int set_quad_mode_cmd(struct sfc_flash *flash) ++{ ++ return 0; ++} ++ ++/* write nor flash status register QE bit to set quad mode */ ++static int set_quad_mode_reg(struct sfc_flash *flash) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ struct spi_nor_st_info *quad_set; ++ struct spi_nor_st_info *quad_get; ++ struct spi_nor_st_info *busy; ++ unsigned int data; ++ struct sfc_cdt_xfer xfer; ++ int ret = 0; ++ ++ busy = &spi_nor_info->busy; ++ quad_set = &spi_nor_info->quad_set; ++ quad_get = &spi_nor_info->quad_get; ++ data = (quad_set->val & quad_set->mask) << quad_set->bit_shift; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NOR_QUAD_SET_ENABLE; ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ xfer.rowaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = quad_set->len; ++ xfer.config.data_dir = GLB0_TRAN_DIR_WRITE; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)&data; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ printk("sfc_sync error! %s %s %d\n", __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ ++static int write_enable(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ int32_t ret = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NOR_WRITE_ENABLE; ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = DISABLE; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ printk("sfc_sync error! %s %s %d\n", __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ ++static int enter_4byte(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ int32_t ret = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /* set index */ ++ xfer.cmd_index = NOR_EN_4BYTE; ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = DISABLE; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ printk("sfc_sync error! %s %s %d\n", __FILE__, __func__, __LINE__); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ ++/* send 4byte command to enter 4byte mode */ ++static int set_4byte_mode_normal(struct sfc_flash *flash) ++{ ++ int ret; ++ ret = enter_4byte(flash); ++ if (ret) { ++ dev_err(flash->dev, "enter 4byte mode failed\n"); ++ } ++ return ret; ++} ++ ++/** ++ * 1.send write enable command ++ * 2.send 4byte command to enter 4byte mode ++ **/ ++static int set_4byte_mode_wren(struct sfc_flash *flash) ++{ ++ int ret; ++ ret = write_enable(flash); ++ if (ret) { ++ dev_err(flash->dev, "enter 4byte mode failed\n"); ++ return ret; ++ } ++ ++ ret = enter_4byte(flash); ++ if (ret) { ++ dev_err(flash->dev, "enter 4byte mode failed\n"); ++ } ++ return ret; ++} ++ ++ ++static struct spi_nor_flash_ops nor_flash_ops; ++ ++static int noop(struct sfc_flash *flash) ++{ ++ return 0; ++} ++ ++int sfc_nor_get_special_ops(struct sfc_flash *flash) ++{ ++ struct spinor_flashinfo *nor_info = flash->flash_info; ++ struct spi_nor_info *spi_nor_info = nor_info->nor_flash_info; ++ ++ switch (spi_nor_info->quad_ops_mode) { ++ case 0: ++ nor_flash_ops.set_quad_mode = set_quad_mode_cmd; ++ break; ++ case 1: ++ nor_flash_ops.set_quad_mode = set_quad_mode_reg; ++ break; ++ default: ++ nor_flash_ops.set_quad_mode = noop; ++ break; ++ } ++ ++ switch (spi_nor_info->addr_ops_mode) { ++ case 0: ++ nor_flash_ops.set_4byte_mode = set_4byte_mode_normal; ++ break; ++ case 1: ++ nor_flash_ops.set_4byte_mode = set_4byte_mode_wren; ++ break; ++ default: ++ nor_flash_ops.set_4byte_mode = noop; ++ break; ++ } ++ ++ nor_info->nor_flash_ops = &nor_flash_ops; ++ ++ return 0; ++} ++ +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/Makefile b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/Makefile +new file mode 100644 +index 000000000..1c8209140 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/Makefile +@@ -0,0 +1,2 @@ ++obj-y += ato_nand.o gd_nand.o mxic_nand.o xtx_nand.o dosilicon_nand.o foresee_nand.o xtx_mid0b_nand.o zetta_nand.o xtx_mid2c_nand.o fm_nand.o yhy_nand.o toshiba_nand.o issi_nand.o xcsp_nand.o ++obj-y += nand_common.o +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/ato_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/ato_nand.c +new file mode 100644 +index 000000000..8962155cb +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/ato_nand.c +@@ -0,0 +1,101 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define ATO_DEVICES_NUM 1 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 30 ++#define TSHSL_W 30 ++ ++#define TRD 25 ++#define TPP 500 ++#define TBE 3 ++ ++static struct ingenic_sfcnand_device *ato_nand; ++ ++static struct ingenic_sfcnand_base_param ato25d1ga_param = { ++ ++ .pagesize = 2 * 1024, ++ .oobsize = 64, ++ .blocksize = 2 * 1024 * 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0,//0x3, ++ .need_quad = 1, ++ ++}; ++ ++static struct device_id_struct device_id[ATO_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x12, "ATO25D1GA", &ato25d1ga_param), ++}; ++ ++ ++static cdt_params_t *ato_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(ato_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0x12: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &ato_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ switch(device_id) { ++ case 0x12: ++ return 0; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ return -EIO; //notice!!! ++ } ++ return ret; ++} ++ ++ ++static int __init ato_nand_init(void) { ++ ++ ato_nand = kzalloc(sizeof(*ato_nand), GFP_KERNEL); ++ if(!ato_nand) { ++ pr_err("alloc ato_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ ato_nand->id_manufactory = 0x9B; ++ ato_nand->id_device_list = device_id; ++ ato_nand->id_device_count = ATO_DEVICES_NUM; ++ ++ ato_nand->ops.get_cdt_params = ato_get_cdt_params; ++ ato_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ ato_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(ato_nand); ++} ++ ++fs_initcall(ato_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/dosilicon_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/dosilicon_nand.c +new file mode 100644 +index 000000000..ff1cdaadc +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/dosilicon_nand.c +@@ -0,0 +1,217 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define DOSILICON_DEVICES_NUM 5 ++#define THOLD 5 ++#define TSETUP 5 ++#define TSHSL_R 100 ++#define TSHSL_W 100 ++ ++#define TRD 90 ++#define TPP 700 ++#define TBE 10 ++ ++struct ingenic_sfcnand_device *dosilicon_nand; ++ ++static struct ingenic_sfcnand_base_param dosilicon_param[DOSILICON_DEVICES_NUM] = { ++ [0] = { ++ /*DS35Q1GAXXX*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 70, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*DS35Q2GAXXX*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 90, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [2] = { ++ /*DS35Q2GBXXX*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 120, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [3] = { ++ /*DS35M1GAXXX*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 80, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [4] = { ++ /*DS35Q2GAXXX-1V8*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 90, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++}; ++ ++static struct device_id_struct device_id[DOSILICON_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x71, "DS35Q1GAXXX", &dosilicon_param[0]), ++ DEVICE_ID_STRUCT(0x72, "DS35Q2GAXXX", &dosilicon_param[1]), ++ DEVICE_ID_STRUCT(0xF2, "DS35Q2GBXXX", &dosilicon_param[2]), ++ DEVICE_ID_STRUCT(0x21, "DS35M1GAXXX", &dosilicon_param[3]), ++ DEVICE_ID_STRUCT(0x22, "DS35Q2GAXXX-1V8", &dosilicon_param[4]), ++}; ++ ++ ++static cdt_params_t *dosilicon_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(dosilicon_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0x71: ++ case 0x72: ++ case 0xF2: ++ case 0x21: ++ case 0x22: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &dosilicon_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0x71: ++ case 0x72: ++ case 0x21: ++ case 0x22: ++ switch((ecc_status >> 0x4) & 0x3) { ++ case 0x0: ++ case 0x1: ++ ret = 0; ++ break; ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ default: ++ printk("it is flash Unknown state, device_id: 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ break; ++ case 0xF2: ++ switch((ecc_status >> 4) & 0x7) { ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0; ++ break; ++ } ++ break; ++ ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ return ret; ++} ++ ++ ++static int dosilicon_nand_init(void) { ++ ++ dosilicon_nand = kzalloc(sizeof(*dosilicon_nand), GFP_KERNEL); ++ if(!dosilicon_nand) { ++ pr_err("alloc dosilicon_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ dosilicon_nand->id_manufactory = 0xE5; ++ dosilicon_nand->id_device_list = device_id; ++ dosilicon_nand->id_device_count = DOSILICON_DEVICES_NUM; ++ ++ dosilicon_nand->ops.get_cdt_params = dosilicon_get_cdt_params; ++ dosilicon_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ dosilicon_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(dosilicon_nand); ++} ++ ++fs_initcall(dosilicon_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/fm_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/fm_nand.c +new file mode 100644 +index 000000000..62c98a7a6 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/fm_nand.c +@@ -0,0 +1,126 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define FM_DEVICES_NUM 2 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 80 ++#define TSHSL_W 80 ++ ++#define TRD 100 ++#define TPP 900 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_device *fm_nand; ++static struct ingenic_sfcnand_base_param fm_param[FM_DEVICES_NUM] = { ++ [0] = { ++ /*FM25S01A*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x1, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*FM25S02A*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024 * 2, ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x1, ++ .need_quad = 1, ++ }, ++}; ++ ++static struct device_id_struct device_id[FM_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xE4, "FM25S01A", &fm_param[0]), ++ DEVICE_ID_STRUCT(0xE5, "FM25S02A", &fm_param[1]), ++}; ++ ++static cdt_params_t *fm_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(fm_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0xE4: ++ case 0xE5: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &fm_nand->cdt_params; ++} ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0xE4: ++ case 0xE5: ++ switch((ret = ((ecc_status >> 4) & 0x3))) { ++ case 0x0 ... 0x1: ++ ret = 0; ++ break; ++ default: ++ ret = -EBADMSG; ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ ++ } ++ return ret; ++} ++ ++static int __init fm_nand_init(void) { ++ fm_nand = kzalloc(sizeof(*fm_nand), GFP_KERNEL); ++ if(!fm_nand) { ++ pr_err("alloc fm_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ fm_nand->id_manufactory = 0xA1; ++ fm_nand->id_device_list = device_id; ++ fm_nand->id_device_count = FM_DEVICES_NUM; ++ ++ fm_nand->ops.get_cdt_params = fm_get_cdt_params; ++ fm_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ fm_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(fm_nand); ++} ++fs_initcall(fm_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/foresee_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/foresee_nand.c +new file mode 100644 +index 000000000..470d485cf +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/foresee_nand.c +@@ -0,0 +1,145 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define FS_DEVICES_NUM 2 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 180 ++#define TPP 400 ++#define TBE 3 ++ ++static struct ingenic_sfcnand_device *fs_nand; ++ ++static struct ingenic_sfcnand_base_param fs_param[FS_DEVICES_NUM] = { ++ ++ [0] = { ++ /*FS35ND01G*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*FS35SQA001G*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 60, ++ .tPP = 700, ++ .tBE = 10, ++ ++ .plane_select = 0, ++ .ecc_max = 0x1, ++ .need_quad = 1, ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[FS_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xA1, "FS35ND01G", &fs_param[0]), ++ DEVICE_ID_STRUCT(0x71, "F35SQA001G",&fs_param[1]), ++}; ++ ++ ++static cdt_params_t *fs_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(fs_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0xA1: ++ break; ++ case 0x71: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &fs_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0xA1: ++ switch((ret = ((ecc_status >> 4) & 0x7))) { ++ case 0x0 ... 0x4: ++ break; ++ default: ++ ret = -EBADMSG; ++ } ++ break; ++ case 0x71: ++ switch((ret = ((ecc_status >> 4) & 0x3))) { ++ case 0x0 ... 0x1: ++ break; ++ default: ++ ret = -EBADMSG; ++ } ++ break; ++ ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ ++ } ++ return ret; ++ ++} ++ ++ ++static int fs_nand_init(void) { ++ ++ fs_nand = kzalloc(sizeof(*fs_nand), GFP_KERNEL); ++ if(!fs_nand) { ++ pr_err("alloc fs_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ fs_nand->id_manufactory = 0xCD; ++ fs_nand->id_device_list = device_id; ++ fs_nand->id_device_count = FS_DEVICES_NUM; ++ ++ fs_nand->ops.get_cdt_params = fs_get_cdt_params; ++ fs_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ fs_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(fs_nand); ++} ++ ++fs_initcall(fs_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/gd_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/gd_nand.c +new file mode 100644 +index 000000000..4d920036b +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/gd_nand.c +@@ -0,0 +1,435 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define GD_DEVICES_NUM 11 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 80 ++#define TRD_4G 120 ++#define TPP 700 ++#define TBE 5 ++ ++#define TRD_Q5 50 ++#define TPP_Q5 600 ++ ++static struct ingenic_sfcnand_device *gd_nand; ++ ++static struct ingenic_sfcnand_base_param gd_param[GD_DEVICES_NUM] = { ++ ++ [0] = { ++ /*GD5F1GQ4UB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*GD5F2GQ4UB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [2] = { ++ /*GD5F4GQ4UB*/ ++ .pagesize = 4 * 1024, ++ .blocksize = 4 * 1024 * 64, ++ .oobsize = 256, ++ .flashsize = 4 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD_4G, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [3] = { ++ /*GD5F1GQ4UC*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [4] = { ++ /*GD5F2GQ4UC*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [5] = { ++ /*GD5F4GQ4UC*/ ++ .pagesize = 4 * 1024, ++ .blocksize = 4 * 1024 * 64, ++ .oobsize = 256, ++ .flashsize = 4 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD_4G, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ ++ [6] = { ++ /*GD5F1GQ4RF9IG*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ ++ [7] = { ++ /*GD5F4GQ6UE*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 4096, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [8] = { ++ /*GD5F2GQ5UE*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD_Q5, ++ .tPP = TPP_Q5, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [9] = { ++ /*GD5F1GQ5UE*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD_Q5, ++ .tPP = TPP_Q5, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ ++ [10] = { ++ /*GD5F2GM7UE*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 120, ++ .tPP = TPP_Q5, ++ .tBE = 10, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[GD_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xD1, "GD5F1GQ4UB",&gd_param[0]), ++ DEVICE_ID_STRUCT(0xD2, "GD5F2GQ4UB",&gd_param[1]), ++ DEVICE_ID_STRUCT(0xD4, "GD5F4GQ4UB",&gd_param[2]), ++ DEVICE_ID_STRUCT(0xB1, "GD5F1GQ4UC",&gd_param[3]), ++ DEVICE_ID_STRUCT(0xB2, "GD5F2GQ4UC",&gd_param[4]), ++ DEVICE_ID_STRUCT(0xB4, "GD5F4GQ4UC",&gd_param[5]), ++ DEVICE_ID_STRUCT(0xA1, "GD5F1GQ4RF",&gd_param[6]), ++ DEVICE_ID_STRUCT(0x55, "GD5F4GQ6UE",&gd_param[7]), ++ DEVICE_ID_STRUCT(0x52, "GD5F2GQ5UE",&gd_param[8]), ++ DEVICE_ID_STRUCT(0x51, "GD5F1GQ5UE",&gd_param[9]), ++ DEVICE_ID_STRUCT(0x92, "GD5F2GM7UE",&gd_param[10]), ++}; ++ ++ ++static cdt_params_t *gd_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(gd_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0xB1 ... 0xB4: ++ case 0xA1: ++ gd_nand->cdt_params.standard_r.addr_nbyte = 3; ++ gd_nand->cdt_params.quad_r.addr_nbyte = 3; ++ break; ++ case 0x92: ++ case 0xD1 ... 0xD4: ++ case 0x51 ... 0x55: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &gd_nand->cdt_params; ++} ++ ++ ++static int32_t gd_get_f0_register_value(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ uint32_t buf = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /*set index*/ ++ xfer.cmd_index = NAND_GET_FEATURE; ++ ++ /* set addr */ ++ xfer.staaddr0 = 0xf0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)&buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)){ ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ return buf; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0xA1: ++ case 0xB1 ... 0xB4: ++ switch((ecc_status >> 4) & 0x7) { ++ case 0x7: ++ ret = -EBADMSG; ++ break; ++ case 0x6: ++ ret = 0x8; ++ break; ++ case 0x5: ++ ret = 0x7; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ case 0xD1 ... 0xD4: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x3: ++ ret = 0x8; ++ break; ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ case 0x1: ++ if((ret = gd_get_f0_register_value(flash)) < 0) ++ return ret; ++ if(((ret >> 4) & 0x3) == 0x3) ++ ret = 0x7; ++ break; ++ default: ++ ret = 0; ++ break; ++ } ++ break; ++ case 0x51: ++ case 0x55: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x3: ++ case 0x0: ++ ret = 0x0; ++ break; ++ case 0x1: ++ ret = 0x4; ++ break; ++ default: ++ ret = -EBADMSG; ++ } ++ break; ++ case 0x52: ++ case 0x92: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x1: ++ if((ret = gd_get_f0_register_value(flash)) < 0) ++ return ret; ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x0: ++ ret = 0x1; ++ break; ++ case 0x1: ++ ret = 0x2; ++ break; ++ case 0x2: ++ ret = 0x3; ++ break; ++ case 0x3: ++ ret = 0x4; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0x0; ++ break; ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err,it maybe don`t support this device, please check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ } ++ return ret; ++} ++ ++ ++static int __init gd_nand_init(void) { ++ ++ gd_nand = kzalloc(sizeof(*gd_nand), GFP_KERNEL); ++ if(!gd_nand) { ++ pr_err("alloc gd_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ gd_nand->id_manufactory = 0xC8; ++ gd_nand->id_device_list = device_id; ++ gd_nand->id_device_count = GD_DEVICES_NUM; ++ ++ gd_nand->ops.get_cdt_params = gd_get_cdt_params; ++ gd_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ gd_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(gd_nand); ++} ++ ++fs_initcall(gd_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/issi_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/issi_nand.c +new file mode 100644 +index 000000000..8b040093e +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/issi_nand.c +@@ -0,0 +1,104 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define ISSI_DEVICES_NUM 1 ++#define THOLD 5 ++#define TSETUP 5 ++#define TSHSL_R 100 ++#define TSHSL_W 100 ++ ++#define TRD 100 ++#define TPP 400 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_device *issi_nand; ++static struct ingenic_sfcnand_base_param issi_param[ISSI_DEVICES_NUM] = { ++ [0] = { ++ /*IS37SML01G1*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x1, ++ .need_quad = 1, ++ }, ++}; ++ ++static struct device_id_struct device_id[ISSI_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x21, "IS37SML01G1", &issi_param[0]), ++}; ++static cdt_params_t *issi_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(issi_nand->cdt_params); ++ switch(device_id) { ++ case 0x21: ++ break; ++ default: ++ dev_err(flash->dev,"device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ return &issi_nand->cdt_params; ++} ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ switch(device_id) { ++ case 0x21: ++ switch((ecc_status >> 0x4) & 0x3) { ++ case 0x0: ++ case 0x1: ++ ret = 0; ++ break; ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = -EIO; ++ break; ++ } ++ break; ++ default: ++ dev_warn(flash->dev,"device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ return ret; ++} ++ ++static int __init issi_nand_init(void) { ++ ++ issi_nand = kzalloc(sizeof(*issi_nand), GFP_KERNEL); ++ if(!issi_nand) { ++ pr_err("alloc issi_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ issi_nand->id_manufactory = 0xc8; ++ issi_nand->id_device_list = device_id; ++ issi_nand->id_device_count = ISSI_DEVICES_NUM; ++ issi_nand->ops.get_cdt_params = issi_get_cdt_params; ++ issi_nand->ops.deal_ecc_status = deal_ecc_status; ++ /* use private get feature interface, please define it in this document */ ++ issi_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(issi_nand); ++} ++ ++fs_initcall(issi_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/mxic_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/mxic_nand.c +new file mode 100644 +index 000000000..3dce024b6 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/mxic_nand.c +@@ -0,0 +1,239 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define MXIC_DEVICES_NUM 4 ++#define MXIC_CMD_GET_ECC 0x7c ++#define THOLD 4 ++#define TSETUP 4 ++#define TSHSL_R 100 ++#define TSHSL_W 100 ++ ++#define TRD 70 ++#define TPP 600 ++#define TBE 4 ++ ++static struct ingenic_sfcnand_device *mxic_nand; ++ ++static struct ingenic_sfcnand_base_param mxic_param[MXIC_DEVICES_NUM] = { ++ [0] = { ++ /*MX35LF1GE4AB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*MX35LF2GE4AB*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [2] = { ++ /*MX35LF2GE4AD*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 70, ++ .tPP = 760, ++ .tBE = 6, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [3] = { ++ /*MX35LF4GE4AD*/ ++ .pagesize = 4 * 1024, ++ .blocksize = 4 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 4 * 1024 * 64 * 2048, ++ ++ .tHOLD = THOLD, ++ .tSETUP = TSETUP, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 110, ++ .tPP = 800, ++ .tBE = 6, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++}; ++ ++static struct device_id_struct device_id[MXIC_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x12, "MX35LF1GE4AB", &mxic_param[0]), ++ DEVICE_ID_STRUCT(0x22, "MX35LF2GE4AB", &mxic_param[1]), ++ DEVICE_ID_STRUCT(0x26, "MX35LF2GE4AD", &mxic_param[2]), ++ DEVICE_ID_STRUCT(0x37, "MX35LF4GE4AD", &mxic_param[3]), ++}; ++ ++ ++static cdt_params_t *mxic_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(mxic_nand->cdt_params); ++ ++ /* ecc status read */ ++ CMD_INFO(mxic_nand->cdt_params.ecc_r, MXIC_CMD_GET_ECC, 8, 0, TM_STD_SPI); ++ ++ switch(device_id) { ++ case 0x12: ++ case 0x22: ++ case 0x26: ++ case 0x37: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &mxic_nand->cdt_params; ++} ++ ++ ++static int32_t get_ecc_value(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ uint32_t buf = 0; ++ int8_t count = 5; ++ ++try_read_again: ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /*set index*/ ++ xfer.cmd_index = NAND_ECC_STATUS_READ; ++ ++ /* set addr */ ++ xfer.columnaddr = 0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)&buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer) && count--){ ++ goto try_read_again; ++ } ++ ++ if(count < 0) ++ return -EIO; ++ ++ return buf & 0xf; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0x12: ++ case 0x22: ++ switch((ecc_status >> 0x4) & 0x3) { ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ case 0x1: ++ if((ret = get_ecc_value(flash)) > 0x4) ++ ret = -EBADMSG; ++ break; ++ case 0x0: ++ ret = 0; ++ break; ++ default: ++ dev_err(flash->dev, "it is flash Unknown state, device_id: 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ break; ++ case 0x26: ++ case 0x37: ++ switch((ecc_status >> 0x4) & 0x3) { ++ case 0x0: ++ ret = 0; ++ break; ++ case 0x1: ++ if((ret = get_ecc_value(flash)) > 0x8) ++ ret = -EBADMSG; ++ break; ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ default: ++ dev_err(flash->dev, "it is flash Unknown state, device_id: 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ break; ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ return ret; ++} ++ ++static int __init mxic_nand_init(void) { ++ ++ mxic_nand = kzalloc(sizeof(*mxic_nand), GFP_KERNEL); ++ if(!mxic_nand) { ++ pr_err("alloc mxic_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ mxic_nand->id_manufactory = 0xC2; ++ mxic_nand->id_device_list = device_id; ++ mxic_nand->id_device_count = MXIC_DEVICES_NUM; ++ ++ mxic_nand->ops.get_cdt_params = mxic_get_cdt_params; ++ mxic_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ mxic_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(mxic_nand); ++} ++ ++fs_initcall(mxic_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.c +new file mode 100644 +index 000000000..0708128b8 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.c +@@ -0,0 +1,66 @@ ++#include ++#include ++#include "../sfc.h" ++#include "../spinand.h" ++#include "../spinand_cmd.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++/* ++ * Note: the deal_ecc_status() function needs to be defined in xxx_nand.c ++ */ ++int32_t nand_common_get_feature(struct sfc_flash *flash, uint8_t flag) ++{ ++ struct ingenic_sfcnand_flashinfo *nand_info = flash->flash_info; ++ struct ingenic_sfcnand_ops *ops = nand_info->ops; ++ uint8_t device_id = nand_info->id_device; ++ struct sfc_cdt_xfer xfer; ++ uint8_t ecc_status = 0; ++ int32_t ret = 0; ++ ++retry: ++ ecc_status = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /*set index*/ ++ xfer.cmd_index = NAND_GET_FEATURE; ++ ++ /* set addr */ ++ xfer.staaddr0 = SPINAND_ADDR_STATUS; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = &ecc_status; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)) { ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ ++ if(ecc_status & SPINAND_IS_BUSY) ++ goto retry; ++ ++ switch(flag) { ++ case GET_WRITE_STATUS: ++ if(ecc_status & (0x1 << 3)) ++ ret = -EIO; ++ break; ++ ++ case GET_ERASE_STATUS: ++ if(ecc_status & (0x1 << 2)) ++ ret = -EIO; ++ break; ++ ++ case GET_ECC_STATUS: ++ ret = ops->deal_ecc_status(flash, device_id, ecc_status); ++ break; ++ default: ++ dev_err(flash->dev,"flag value is error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(nand_common_get_feature); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.h +new file mode 100644 +index 000000000..f0a143aef +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/nand_common.h +@@ -0,0 +1,74 @@ ++#ifndef __NAND_COMMON_H ++#define __NAND_COMMON_H ++#include ++#include "../sfc.h" ++#include "../sfc_flash.h" ++#include "../spinand.h" ++ ++#define GET_WRITE_STATUS 1 ++#define GET_ECC_STATUS 2 ++#define GET_ERASE_STATUS 3 ++ ++/* page number of convert plane */ ++#define NAND_PLANE_PAGES 64 ++ ++/* select plane to convert columnaddr */ ++#define CONVERT_COL_ADDR(pageaddr, columnaddr) ({ \ ++ uint32_t plane_flag = (pageaddr >> (ffs(NAND_PLANE_PAGES) - 1)) & 0x1; \ ++ if (plane_flag) { \ ++ columnaddr = columnaddr | ( plane_flag << 12); \ ++ } \ ++ columnaddr; \ ++}) ++ ++#define DEVICE_ID_STRUCT(id, name_string, parameter) { \ ++ .id_device = id, \ ++ .name = name_string, \ ++ .param = parameter, \ ++} ++ ++#define CMD_INFO(_CMD, COMMAND, DUMMY_BIT, ADDR_LEN, TRANSFER_MODE) { \ ++ _CMD.cmd = COMMAND; \ ++ _CMD.dummy_byte = DUMMY_BIT; \ ++ _CMD.addr_nbyte = ADDR_LEN; \ ++ _CMD.transfer_mode = TRANSFER_MODE; \ ++} ++ ++#define ST_INFO(_ST, COMMAND, BIT_SHIFT, MASK, VAL, LEN, DUMMY_BIT) { \ ++ _ST.cmd = COMMAND; \ ++ _ST.bit_shift = BIT_SHIFT; \ ++ _ST.mask = MASK; \ ++ _ST.val = VAL; \ ++ _ST.len = LEN; \ ++ _ST.dummy = DUMMY_BIT; \ ++} ++ ++/* ++ * cdt params ++ */ ++#define CDT_PARAMS_INIT(cdt_params) { \ ++ /* read to cache */ \ ++ CMD_INFO(cdt_params.r_to_cache, SPINAND_CMD_PARD, 0, 3, TM_STD_SPI); \ ++ /* standard read from cache */ \ ++ CMD_INFO(cdt_params.standard_r, SPINAND_CMD_FRCH, 8, 2, TM_STD_SPI); \ ++ /* quad read from cache*/ \ ++ CMD_INFO(cdt_params.quad_r, SPINAND_CMD_RDCH_X4, 8, 2, TM_QI_QO_SPI); \ ++ /* standard write to cache*/ \ ++ CMD_INFO(cdt_params.standard_w_cache, SPINAND_CMD_PRO_LOAD, 0, 2, TM_STD_SPI); \ ++ /* quad write to cache*/ \ ++ CMD_INFO(cdt_params.quad_w_cache, SPINAND_CMD_PRO_LOAD_X4, 0, 2, TM_QI_QO_SPI); \ ++ /* write exec */ \ ++ CMD_INFO(cdt_params.w_exec, SPINAND_CMD_PRO_EN, 0, 3, TM_STD_SPI); \ ++ /* block erase */ \ ++ CMD_INFO(cdt_params.b_erase, SPINAND_CMD_ERASE_128K, 0, 3, TM_STD_SPI); \ ++ /* write enable */ \ ++ CMD_INFO(cdt_params.w_en, SPINAND_CMD_WREN, 0, 0, TM_STD_SPI); \ ++ \ ++ /* get frature wait oip not busy */ \ ++ ST_INFO(cdt_params.oip, SPINAND_CMD_GET_FEATURE, 0, 0x1, 0x0, 1, 0); \ ++} ++ ++ ++int32_t nand_common_get_feature(struct sfc_flash *flash, uint8_t flag); ++ ++#endif +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/toshiba_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/toshiba_nand.c +new file mode 100644 +index 000000000..797c90842 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/toshiba_nand.c +@@ -0,0 +1,102 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define TOSHIBA_DEVICES_NUM 1 ++#define TSETUP 3 ++#define THOLD 3 ++#define TSHSL_R 100 ++#define TSHSL_W 100 ++ ++#define TRD 300 ++#define TPP 600 ++#define TBE 7 ++ ++static struct ingenic_sfcnand_device *toshiba_nand; ++static struct ingenic_sfcnand_base_param toshiba_param[TOSHIBA_DEVICES_NUM] = { ++ ++ [0] = { ++ /*TC58CVG2S0HRAIJ */ ++ .pagesize = 4 * 1024, ++ .blocksize = 4 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 4 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++}; ++ ++static struct device_id_struct device_id[TOSHIBA_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xed, "TC58CVG2S0HRAIJ", &toshiba_param[0]), ++}; ++static cdt_params_t *toshiba_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(toshiba_nand->cdt_params); ++ switch(device_id) { ++ case 0xed: ++ break; ++ default: ++ dev_err(flash->dev,"device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ return &toshiba_nand->cdt_params; ++} ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ switch(device_id) { ++ case 0xed: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x00: ++ ret = 0; ++ break; ++ case 0x01: ++ ret = 0x1; ++ break; ++ case 0x11: ++ ret = 0x11; ++ break; ++ default: ++ ret = -EBADMSG; ++ break; ++ } ++ break; ++ default: ++ dev_warn(flash->dev,"device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ return ret; ++} ++ ++static int toshiba_nand_init(void) { ++ toshiba_nand = kzalloc(sizeof(*toshiba_nand), GFP_KERNEL); ++ if(!toshiba_nand) { ++ pr_err("alloc toshiba_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ toshiba_nand->id_manufactory = 0x98; ++ toshiba_nand->id_device_list = device_id; ++ toshiba_nand->id_device_count = TOSHIBA_DEVICES_NUM; ++ toshiba_nand->ops.get_cdt_params = toshiba_get_cdt_params; ++ toshiba_nand->ops.deal_ecc_status = deal_ecc_status; ++ toshiba_nand->ops.get_feature = NULL; ++ return ingenic_sfcnand_register(toshiba_nand); ++} ++fs_initcall(toshiba_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xcsp_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xcsp_nand.c +new file mode 100644 +index 000000000..561a192cf +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xcsp_nand.c +@@ -0,0 +1,197 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define XCSP_DEVICES_NUM 3 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 120 ++#define TPP 600 ++#define TBE 8 ++ ++static struct ingenic_sfcnand_device *xcsp_nand; ++ ++static struct ingenic_sfcnand_base_param xcsp_param[XCSP_DEVICES_NUM] = { ++ ++ [0] = { ++ /*XCSP1AAWH */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*XCSP2AAWH */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [2] = { ++ /*XCSP4AAWH */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 4096, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++}; ++ ++static struct device_id_struct device_id[XCSP_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x01, "XCSP1AAWH ", &xcsp_param[0]), ++ DEVICE_ID_STRUCT(0xa1, "XCSP2AAWH ", &xcsp_param[1]), ++ DEVICE_ID_STRUCT(0xb1, "XCSP4AAWH ", &xcsp_param[2]), ++}; ++ ++ ++static cdt_params_t *xcsp_nand_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(xcsp_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0x01: ++ case 0xa1: ++ case 0xb1: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ return &xcsp_nand->cdt_params; ++} ++ ++static int32_t xcsp_get_f0_register_value(struct sfc_flash *flash) ++{ ++ struct sfc_cdt_xfer xfer; ++ uint32_t buf = 0; ++ ++ memset(&xfer, 0, sizeof(xfer)); ++ ++ /*set index*/ ++ xfer.cmd_index = NAND_GET_FEATURE; ++ ++ /* set addr */ ++ xfer.staaddr0 = 0xf0; ++ ++ /* set transfer config */ ++ xfer.dataen = ENABLE; ++ xfer.config.datalen = 1; ++ xfer.config.data_dir = GLB0_TRAN_DIR_READ; ++ xfer.config.ops_mode = CPU_OPS; ++ xfer.config.buf = (uint8_t *)&buf; ++ ++ if(sfc_sync_cdt(flash->sfc, &xfer)){ ++ dev_err(flash->dev,"sfc_sync_cdt error ! %s %s %d\n",__FILE__,__func__,__LINE__); ++ return -EIO; ++ } ++ return buf; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0x01: ++ case 0xa1: ++ case 0xb1: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x0: ++ if((ret = xcsp_get_f0_register_value(flash)) < 0) ++ return ret; ++ ret = (ret >> 4) & 0x3; ++ break; ++ case 0x1: ++ if((ret = xcsp_get_f0_register_value(flash)) < 0) ++ return ret; ++ ret = ((ret >> 4) & 0x3) + 0x4; ++ break; ++ case 0x2: ++ if((ret = xcsp_get_f0_register_value(flash)) < 0) ++ return ret; ++ if(((ret >> 4) & 0x3) == 0) ++ ret = 0x8; ++ else ++ ret = -EBADMSG; ++ break; ++ case 0x3: ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0; ++ break; ++ } ++ break; ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ return ret; ++} ++ ++ ++static int xcsp_nand_init(void) { ++ ++ xcsp_nand = kzalloc(sizeof(*xcsp_nand), GFP_KERNEL); ++ if(!xcsp_nand) { ++ pr_err("alloc xcsp_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ xcsp_nand->id_manufactory = 0x9c; ++ xcsp_nand->id_device_list = device_id; ++ xcsp_nand->id_device_count = XCSP_DEVICES_NUM; ++ xcsp_nand->ops.get_cdt_params = xcsp_nand_get_cdt_params; ++ xcsp_nand->ops.deal_ecc_status = deal_ecc_status; ++ xcsp_nand->ops.get_feature = NULL; ++ return ingenic_sfcnand_register(xcsp_nand); ++} ++ ++fs_initcall(xcsp_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid0b_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid0b_nand.c +new file mode 100644 +index 000000000..faaeebb75 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid0b_nand.c +@@ -0,0 +1,234 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define XTX_MID0B_DEVICES_NUM 4 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 260 ++#define TPP 350 ++#define TBE 3 ++ ++static struct ingenic_sfcnand_device *xtx_mid0b_nand; ++ ++static struct ingenic_sfcnand_base_param xtx_mid0b_param[XTX_MID0B_DEVICES_NUM] = { ++ ++ [0] = { ++ /*XT26G01A */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ ++ [1] = { ++ /*XT26G02B */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ ++ [2] = { ++ /*XT26G01C */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 150, ++ .tPP = 450, ++ .tBE = 4, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ ++ [3] = { ++ /*XT26G02C */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = 125, ++ .tPP = 350, ++ .tBE = 3, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++}; ++ ++static struct device_id_struct device_id[XTX_MID0B_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xE1, "XT26G01A ", &xtx_mid0b_param[0]), ++ DEVICE_ID_STRUCT(0xF2, "XT26G02B ", &xtx_mid0b_param[1]), ++ DEVICE_ID_STRUCT(0x11, "XT26G01C ", &xtx_mid0b_param[2]), ++ DEVICE_ID_STRUCT(0x12, "XT26G02C ", &xtx_mid0b_param[3]), ++}; ++ ++ ++static cdt_params_t *xtx_mid0b_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(xtx_mid0b_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0xE1: ++ case 0xF2: ++ case 0x11: ++ case 0x12: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &xtx_mid0b_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0xE1: ++ switch((ecc_status >> 2) & 0xf) { ++ case 0x12: ++ case 0x8: ++ ret = -EBADMSG; ++ break; ++ case 0x0 ... 0x7: ++ default: ++ ret = 0; ++ break; ++ } ++ break; ++ ++ case 0xF2: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x02: ++ ret = -EBADMSG; ++ break; ++ case 0x03: ++ ret = 0x8; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ ++ case 0x11: ++ case 0x12: ++ switch((ecc_status >> 4) & 0xf) { ++ case 0x01: ++ ret = 0x1; ++ break; ++ case 0x02: ++ ret = 0x2; ++ break; ++ case 0x03: ++ ret = 0x3; ++ break; ++ case 0x04: ++ ret = 0x4; ++ break; ++ case 0x05: ++ ret = 0x5; ++ break; ++ case 0x06: ++ ret = 0x6; ++ break; ++ case 0x07: ++ ret = 0x7; ++ break; ++ case 0x08: ++ ret = 0x8; ++ break; ++ case 0x0f: ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0; ++ break; ++ } ++ break; ++ ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ ++ } ++ return ret; ++} ++ ++ ++static int xtx_mid0b_nand_init(void) { ++ ++ xtx_mid0b_nand = kzalloc(sizeof(*xtx_mid0b_nand), GFP_KERNEL); ++ if(!xtx_mid0b_nand) { ++ pr_err("alloc xtx_mid0b_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ xtx_mid0b_nand->id_manufactory = 0x0B; ++ xtx_mid0b_nand->id_device_list = device_id; ++ xtx_mid0b_nand->id_device_count = XTX_MID0B_DEVICES_NUM; ++ ++ xtx_mid0b_nand->ops.get_cdt_params = xtx_mid0b_get_cdt_params; ++ xtx_mid0b_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ xtx_mid0b_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(xtx_mid0b_nand); ++} ++ ++fs_initcall(xtx_mid0b_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid2c_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid2c_nand.c +new file mode 100644 +index 000000000..9faffa3ae +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_mid2c_nand.c +@@ -0,0 +1,124 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define XTX_MID2C_DEVICES_NUM 1 ++#define TSETUP 4 ++#define THOLD 4 ++#define TSHSL_R 30 ++#define TSHSL_W 30 ++ ++#define TRD 70 ++#define TPP 600 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_device *xtx_mid2c_nand; ++ ++static struct ingenic_sfcnand_base_param xtx_mid2c_param[XTX_MID2C_DEVICES_NUM] = { ++ ++ [0] = { ++ /*XT26G02E */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[XTX_MID2C_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x24, "XT26G02E ", &xtx_mid2c_param[0]), ++}; ++ ++ ++static cdt_params_t *xtx_mid2c_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(xtx_mid2c_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0x24: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &xtx_mid2c_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0x24: ++ switch((ecc_status >> 4) & 0x7) { ++ case 0x5: ++ ret = 8; ++ break; ++ case 0x3: ++ ret = 6; ++ break; ++ case 0x2: ++ ret = -EBADMSG; ++ break; ++ case 0x1: ++ ret = 3; ++ break; ++ default: ++ ret = 0; ++ break; ++ } ++ break; ++ ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ ++ } ++ return ret; ++} ++ ++ ++static int xtx_mid2c_nand_init(void) { ++ ++ xtx_mid2c_nand = kzalloc(sizeof(*xtx_mid2c_nand), GFP_KERNEL); ++ if(!xtx_mid2c_nand) { ++ pr_err("alloc xtx_mid2c_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ xtx_mid2c_nand->id_manufactory = 0x2C; ++ xtx_mid2c_nand->id_device_list = device_id; ++ xtx_mid2c_nand->id_device_count = XTX_MID2C_DEVICES_NUM; ++ ++ xtx_mid2c_nand->ops.get_cdt_params = xtx_mid2c_get_cdt_params; ++ xtx_mid2c_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ xtx_mid2c_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(xtx_mid2c_nand); ++} ++ ++fs_initcall(xtx_mid2c_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_nand.c +new file mode 100644 +index 000000000..0343145e0 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/xtx_nand.c +@@ -0,0 +1,161 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define XTX_DEVICES_NUM 3 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 20 ++ ++#define TRD 240 ++#define TPP 1400 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_device *xtx_nand; ++ ++static struct ingenic_sfcnand_base_param xtx_param[XTX_DEVICES_NUM] = { ++ ++ [0] = { ++ /*PN26G01AW*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*PN26G02AW */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ [2] = { ++ /*PN26Q01AW */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x8, ++ .need_quad = 1, ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[XTX_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0xE1, "PN26G01AW", &xtx_param[0]), ++ DEVICE_ID_STRUCT(0xE2, "PN26G02AW", &xtx_param[1]), ++ DEVICE_ID_STRUCT(0xC1, "PN26Q01AW", &xtx_param[2]), ++}; ++ ++ ++static cdt_params_t *xtx_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(xtx_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0xE1: ++ case 0xE2: ++ case 0xC1: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &xtx_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0xE1 ... 0xE2: ++ case 0xC1: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x02: ++ ret = -EBADMSG; ++ break; ++ case 0x03: ++ ret = 0x8; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ ++ } ++ return ret; ++} ++ ++ ++static int __init xtx_nand_init(void) { ++ ++ xtx_nand = kzalloc(sizeof(*xtx_nand), GFP_KERNEL); ++ if(!xtx_nand) { ++ pr_err("alloc xtx_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ xtx_nand->id_manufactory = 0xA1; ++ xtx_nand->id_device_list = device_id; ++ xtx_nand->id_device_count = XTX_DEVICES_NUM; ++ ++ xtx_nand->ops.get_cdt_params = xtx_get_cdt_params; ++ xtx_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ xtx_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(xtx_nand); ++} ++ ++fs_initcall(xtx_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/yhy_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/yhy_nand.c +new file mode 100644 +index 000000000..ab580dadd +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/yhy_nand.c +@@ -0,0 +1,122 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define YHY_MIDC9_DEVICES_NUM 2 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 20 ++#define TSHSL_W 50 ++ ++#define TRD 200 ++#define TPP 800 ++#define TBE 10 ++ ++static struct ingenic_sfcnand_device *yhy_midc9_nand; ++static struct ingenic_sfcnand_base_param yhy_midc9_param[YHY_MIDC9_DEVICES_NUM] = { ++ ++ [0] = { ++ /*HYF1GQ4U */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x1, ++ .need_quad = 1, ++ }, ++ ++ [1] = { ++ /*HYF2GQ4U */ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 128, ++ .flashsize = 2 * 1024 * 64 * 2048, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .ecc_max = 0x1, ++ .need_quad = 1, ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[YHY_MIDC9_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x21, "HYF1GQ4U", &yhy_midc9_param[0]), ++ DEVICE_ID_STRUCT(0x52, "HYF2GQ4U", &yhy_midc9_param[1]), ++}; ++static cdt_params_t *yhy_midc9_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(yhy_midc9_nand->cdt_params); ++ switch(device_id) { ++ case 0x21: ++ case 0x52: ++ break; ++ default: ++ dev_err(flash->dev,"device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ return &yhy_midc9_nand->cdt_params; ++} ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ switch(device_id) { ++ case 0x21: ++ case 0x52: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x00: ++ ret = 0; ++ break; ++ case 0x01: ++ ret = 0x1; ++ break; ++ default: ++ ret = -EBADMSG; ++ } ++ break; ++ default: ++ dev_warn(flash->dev,"device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; ++ } ++ return ret; ++} ++ ++static int yhy_midc9_nand_init(void) { ++ yhy_midc9_nand = kzalloc(sizeof(*yhy_midc9_nand), GFP_KERNEL); ++ if(!yhy_midc9_nand) { ++ pr_err("alloc yhy_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ yhy_midc9_nand->id_manufactory = 0xC9; ++ yhy_midc9_nand->id_device_list = device_id; ++ yhy_midc9_nand->id_device_count = YHY_MIDC9_DEVICES_NUM; ++ yhy_midc9_nand->ops.get_cdt_params = yhy_midc9_get_cdt_params; ++ yhy_midc9_nand->ops.deal_ecc_status = deal_ecc_status; ++ yhy_midc9_nand->ops.get_feature = NULL; ++ return ingenic_sfcnand_register(yhy_midc9_nand); ++} ++fs_initcall(yhy_midc9_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/zetta_nand.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/zetta_nand.c +new file mode 100644 +index 000000000..d4f067b5e +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nand_device/zetta_nand.c +@@ -0,0 +1,139 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinand.h" ++#include "../ingenic_sfc_common.h" ++#include "nand_common.h" ++ ++#define ZETTA_DEVICES_NUM 2 ++#define TSETUP 5 ++#define THOLD 5 ++#define TSHSL_R 100 ++#define TSHSL_W 100 ++ ++#define TRD 70 ++#define TPP 320 ++#define TBE 2 ++ ++static struct ingenic_sfcnand_device *zetta_nand; ++ ++static struct ingenic_sfcnand_base_param zetta_param[ZETTA_DEVICES_NUM] = { ++ ++ [0] = { ++ /*ZD35Q1GA*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 0, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ [1] = { ++ /*ZD35Q1GA*/ ++ .pagesize = 2 * 1024, ++ .blocksize = 2 * 1024 * 64, ++ .oobsize = 64, ++ .flashsize = 2 * 1024 * 64 * 1024, ++ ++ .tSETUP = TSETUP, ++ .tHOLD = THOLD, ++ .tSHSL_R = TSHSL_R, ++ .tSHSL_W = TSHSL_W, ++ ++ .tRD = TRD, ++ .tPP = TPP, ++ .tBE = TBE, ++ ++ .plane_select = 1, ++ .ecc_max = 0x4, ++ .need_quad = 1, ++ }, ++ ++}; ++ ++static struct device_id_struct device_id[ZETTA_DEVICES_NUM] = { ++ DEVICE_ID_STRUCT(0x71, "ZD35Q1GA", &zetta_param[0]), ++ DEVICE_ID_STRUCT(0x72, "ZD35Q2GA", &zetta_param[1]), ++}; ++ ++ ++static cdt_params_t *zetta_get_cdt_params(struct sfc_flash *flash, uint8_t device_id) ++{ ++ CDT_PARAMS_INIT(zetta_nand->cdt_params); ++ ++ switch(device_id) { ++ case 0x71: ++ case 0x72: ++ break; ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", device_id); ++ return NULL; ++ } ++ ++ return &zetta_nand->cdt_params; ++} ++ ++ ++static inline int deal_ecc_status(struct sfc_flash *flash, uint8_t device_id, uint8_t ecc_status) ++{ ++ int ret = 0; ++ ++ switch(device_id) { ++ case 0x71: ++ case 0x72: ++ switch((ecc_status >> 4) & 0x3) { ++ case 0x01: ++ ret = 0x4; ++ break; ++ case 0x02: ++ ret = -EBADMSG; ++ break; ++ default: ++ ret = 0; ++ } ++ break; ++ ++ default: ++ dev_warn(flash->dev, "device_id err, it maybe don`t support this device, check your device id: device_id = 0x%02x\n", device_id); ++ ret = -EIO; //notice!!! ++ } ++ return ret; ++} ++ ++ ++static int zetta_nand_init(void) ++{ ++ zetta_nand = kzalloc(sizeof(*zetta_nand), GFP_KERNEL); ++ if(!zetta_nand) { ++ pr_err("alloc zetta_nand struct fail\n"); ++ return -ENOMEM; ++ } ++ ++ zetta_nand->id_manufactory = 0xBA; ++ zetta_nand->id_device_list = device_id; ++ zetta_nand->id_device_count = ZETTA_DEVICES_NUM; ++ ++ zetta_nand->ops.get_cdt_params = zetta_get_cdt_params; ++ zetta_nand->ops.deal_ecc_status = deal_ecc_status; ++ ++ /* use private get feature interface, please define it in this document */ ++ zetta_nand->ops.get_feature = NULL; ++ ++ return ingenic_sfcnand_register(zetta_nand); ++} ++ ++fs_initcall(zetta_nand_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/Makefile b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/Makefile +new file mode 100644 +index 000000000..1a6683390 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/Makefile +@@ -0,0 +1 @@ ++obj-y += nor_device.o +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/nor_device.c b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/nor_device.c +new file mode 100644 +index 000000000..88e283104 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/nor_device.c +@@ -0,0 +1,157 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../spinor.h" ++#include "../ingenic_sfc_common.h" ++#include "nor_device.h" ++ ++ ++#define NOR_DEVICES_NUM 3 ++ ++/* base params */ ++static struct nor_params_node nor_params_node[NOR_DEVICES_NUM] = { ++ ++#ifdef CONFIG_INGENIC_GD25Q127C ++ /*GD25Q128C*/ ++ [0] = { ++ .nor_device_info.name = "GD25Q127C", ++ .nor_device_info.id = 0xc84018, ++ ++ .nor_device_info.tCHSH = 5, ++ .nor_device_info.tSLCH = 5, ++ .nor_device_info.tSHSL_RD = 20, ++ .nor_device_info.tSHSL_WR = 50, ++ ++ .nor_device_info.chip_size = 16777216, ++ .nor_device_info.page_size = 256, ++ .nor_device_info.erase_size = 32768, ++ ++ .nor_device_info.quad_ops_mode = 1, ++ .nor_device_info.addr_ops_mode = 0, ++ }, ++#endif ++ ++#ifdef CONFIG_INGENIC_GD25Q256C ++ /*GD25Q256C*/ ++ [1] = { ++ .nor_device_info.name = "GD25Q256C", ++ .nor_device_info.id = 0xc84019, ++ ++ .nor_device_info.tCHSH = 5, ++ .nor_device_info.tSLCH = 5, ++ .nor_device_info.tSHSL_RD = 20, ++ .nor_device_info.tSHSL_WR = 50, ++ ++ .nor_device_info.chip_size = 33554432, ++ .nor_device_info.page_size = 256, ++ .nor_device_info.erase_size = 32768, ++ ++ .nor_device_info.quad_ops_mode = 1, ++ .nor_device_info.addr_ops_mode = 0, ++ }, ++#endif ++ ++#ifdef CONFIG_INGENIC_GD25S512MD ++ /*GD25S512MD*/ ++ [2] = { ++ .nor_device_info.name = "GD25S512MD", ++ .nor_device_info.id = 0xc84019, ++ ++ .nor_device_info.tCHSH = 5, ++ .nor_device_info.tSLCH = 8, ++ .nor_device_info.tSHSL_RD = 20, ++ .nor_device_info.tSHSL_WR = 20, ++ ++ .nor_device_info.chip_size = 67108864, ++ .nor_device_info.page_size = 256, ++ .nor_device_info.erase_size = 32768, ++ ++ .nor_device_info.quad_ops_mode = 1, ++ .nor_device_info.addr_ops_mode = 0, ++ }, ++#endif ++ ++}; ++ ++/* cdt params */ ++static struct spi_nor_info *get_cdt_params(struct sfc_flash *flash, struct spi_nor_info *nor_device_info) ++{ ++ switch(nor_device_info->id) { ++ case 0xc84018: ++ if(!(strcmp(nor_device_info->name, "GD25Q127C"))) { ++ CDT_PARAMS_INIT_COMMON(nor_device_info, 3); ++ /* quad set 0x31 1 1 1 1 0 */ ++ ST_INFO(nor_device_info->quad_set, SPINOR_OP_WRSR_1, 1, 1, 1, 1, TM_STD_SPI); ++ /* quad get 0x35 1 1 1 1 0 */ ++ ST_INFO(nor_device_info->quad_get, SPINOR_OP_RDSR_1, 1, 1, 1, 1, TM_STD_SPI); ++ break; ++ } ++ case 0xc84019: ++ if(!(strcmp(nor_device_info->name, "GD25Q256C"))) { ++ CDT_PARAMS_INIT_COMMON(nor_device_info, 4); ++ /* entry 4byte 0xb7 0 0 0 */ ++ CMD_INFO(nor_device_info->en4byte, SPINOR_OP_EN4B, 0, 0, TM_STD_SPI); ++ /* quad set 0x01 6 1 1 1 0 */ ++ ST_INFO(nor_device_info->quad_set, SPINOR_OP_WRSR, 6, 1, 1, 1, TM_STD_SPI); ++ /* quad get 0x05 6 1 1 1 0 */ ++ ST_INFO(nor_device_info->quad_get, SPINOR_OP_RDSR, 6, 1, 1, 1, TM_STD_SPI); ++ break; ++ } ++ if(!(strcmp(nor_device_info->name, "GD25S512MD"))) { ++ CDT_PARAMS_INIT_SPECIAL(nor_device_info); ++ /* quad set 0x31 1 1 1 1 0 */ ++ ST_INFO(nor_device_info->quad_set, SPINOR_OP_WRSR_1, 1, 1, 1, 1, TM_STD_SPI); ++ /* quad get 0x35 1 1 1 1 0 */ ++ ST_INFO(nor_device_info->quad_get, SPINOR_OP_RDSR_1, 1, 1, 1, 1, TM_STD_SPI); ++ break; ++ } ++ default: ++ dev_err(flash->dev, "device_id err, please check your device id: device_id = 0x%02x\n", nor_device_info->id); ++ return NULL; ++ } ++ ++ return nor_device_info; ++} ++ ++ ++static struct nor_private_data private_data = { ++ .fs_erase_size = 32768, ++ .uk_quad = 1, ++}; ++ ++struct builtin_params *get_nor_builtin_params(struct sfc_flash *flash, struct builtin_params *params) ++{ ++ /* private params */ ++ params->magic = NOR_MAGIC; ++ params->version = NOR_VERSION; ++ params->nor_pri_data = &private_data; ++ ++ /* cdt params */ ++ params->spi_nor_info = get_cdt_params(flash, params->spi_nor_info); ++ ++ return params; ++} ++ ++ ++static int __init nor_device_init(void) { ++ ++ int i, count = 0; ++ for(i = 0; i < NOR_DEVICES_NUM; i++) { ++ if (nor_params_node[i].nor_device_info.id) { ++ ingenic_sfcnor_register(&nor_params_node[i]); ++ count++; ++ } ++ } ++ ++ if (!count) { ++ pr_err("Register SPI Nor Flash params fail !\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++fs_initcall(nor_device_init); +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/nor_device.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/nor_device.h +new file mode 100644 +index 000000000..ce6c884c2 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/nor_device/nor_device.h +@@ -0,0 +1,66 @@ ++#ifndef __NOR_DEVICE_H ++#define __NOR_DEVICE_H ++#include ++#include "../sfc.h" ++#include "../sfc_flash.h" ++#include "../spinor.h" ++ ++ ++#define CMD_INFO(_CMD, COMMAND, DUMMY_BIT, ADDR_LEN, TRANSFER_MODE) { \ ++ _CMD.cmd = COMMAND; \ ++ _CMD.dummy_byte = DUMMY_BIT; \ ++ _CMD.addr_nbyte = ADDR_LEN; \ ++ _CMD.transfer_mode = TRANSFER_MODE; \ ++} ++ ++#define ST_INFO(_ST, COMMAND, BIT_SHIFT, MASK, VAL, LEN, DUMMY_BIT) { \ ++ _ST.cmd = COMMAND; \ ++ _ST.bit_shift = BIT_SHIFT; \ ++ _ST.mask = MASK; \ ++ _ST.val = VAL; \ ++ _ST.len = LEN; \ ++ _ST.dummy = DUMMY_BIT; \ ++} ++ ++/* ++ * create default cdt params ++ */ ++#define CDT_PARAMS_INIT_COMMON(cdt_params, addr_bytes) { \ ++ /* read standard 0x03 0 3/4 0 */ \ ++ CMD_INFO(cdt_params->read_standard, SPINOR_OP_READ, 0, addr_bytes, TM_STD_SPI); \ ++ /* read quad 0x6b 8 3/4 5 */ \ ++ CMD_INFO(cdt_params->read_quad, SPINOR_OP_READ_1_1_4, 8, addr_bytes, TM_QI_QO_SPI); \ ++ /* write standard 0x02 0 3/4 0 */ \ ++ CMD_INFO(cdt_params->write_standard, SPINOR_OP_PP, 0, addr_bytes, TM_STD_SPI); \ ++ /* write quad 0x32 0 3/4 5 */ \ ++ CMD_INFO(cdt_params->write_quad, SPINOR_OP_QPP, 0, addr_bytes, TM_QI_QO_SPI); \ ++ /* erase sector 0x52 0 3/4 0 */ \ ++ CMD_INFO(cdt_params->sector_erase, SPINOR_OP_BE_32K, 0, addr_bytes, TM_STD_SPI); \ ++ /* write enable 0x06 0 0 0 */ \ ++ CMD_INFO(cdt_params->wr_en, SPINOR_OP_WREN, 0, 0, TM_STD_SPI); \ ++ \ ++ /* wait oip not busy 0x05 0 1 0 1 0 */ \ ++ ST_INFO(cdt_params->busy, SPINOR_OP_RDSR, 0, 1, 0, 1, 0); \ ++} ++ ++#define CDT_PARAMS_INIT_SPECIAL(cdt_params) { \ ++ /* read standard 0x13 0 4 0 */ \ ++ CMD_INFO(cdt_params->read_standard, SPINOR_OP_READ4, 0, 4, TM_STD_SPI); \ ++ /* read quad 0x6c 8 4 5 */ \ ++ CMD_INFO(cdt_params->read_quad, SPINOR_OP_READ4_1_1_4, 8, 4, TM_QI_QO_SPI); \ ++ /* write standard 0x12 0 4 0 */ \ ++ CMD_INFO(cdt_params->write_standard, SPINOR_OP_PP_4B, 0, 4, TM_STD_SPI); \ ++ /* write quad 0x34 0 4 5 */ \ ++ CMD_INFO(cdt_params->write_quad, SPINOR_OP_QPP_4B, 0, 4, TM_QI_QO_SPI); \ ++ /* erase sector 0x5c 0 4 0 */ \ ++ CMD_INFO(cdt_params->sector_erase, SPINOR_OP_BE_32K_4B, 0, 4, TM_STD_SPI); \ ++ /* entry 4byte 0xb7 0 0 0 */ \ ++ CMD_INFO(cdt_params->en4byte, SPINOR_OP_EN4B, 0, 0, TM_STD_SPI); \ ++ /* write enable 0x06 0 0 0 */ \ ++ CMD_INFO(cdt_params->wr_en, SPINOR_OP_WREN, 0, 0, TM_STD_SPI); \ ++ \ ++ /* wait oip not busy 0x05 0 1 0 1 0 */ \ ++ ST_INFO(cdt_params->busy, SPINOR_OP_RDSR, 0, 1, 0, 1, 0); \ ++} ++ ++#endif +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/sfc.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/sfc.h +new file mode 100644 +index 000000000..3528eb3bd +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/sfc.h +@@ -0,0 +1,116 @@ ++#ifndef __SFC_H ++#define __SFC_H ++ ++#include ++#include ++#include ++#include ++ ++ ++struct sfc{ ++ struct device *dev; ++ void __iomem *iomem; ++ struct resource *ioarea; ++ int irq; ++ struct clk *clk; ++ struct clk *clk_gate; ++ unsigned long src_clk; ++ struct completion done; ++ spinlock_t spin_lock; ++ uint32_t threshold; ++ irqreturn_t (*irq_callback)(struct sfc *); ++ unsigned long phys; ++ ++ struct sfc_cdt_xfer *xfer; ++ ++ struct sfc_desc *desc; ++ dma_addr_t desc_pyaddr; ++ uint32_t desc_max_num; ++ ++ uint8_t *tmp_buffer; ++ dma_addr_t tbuff_pyaddr; ++ ++ uint32_t retry_count; ++}; ++ ++struct data_config { ++ ++ uint32_t datalen; ++ uint32_t cur_len; ++ uint8_t data_dir; ++ uint8_t ops_mode; ++ uint8_t *buf; ++}; ++ ++struct sfc_cdt_xfer { ++ ++ unsigned short cmd_index; ++ uint8_t dataen; ++ struct data_config config; ++ ++ struct { ++ uint32_t columnaddr; ++ uint32_t rowaddr; ++ uint32_t staaddr0; ++ uint32_t staaddr1; ++ }; ++ ++}; ++ ++struct sfc_desc { ++ unsigned int next_des_addr; ++ unsigned int mem_addr; ++ unsigned int tran_len; ++ unsigned int link; ++}; ++ ++enum{ ++ COL_ADDR, ++ ROW_ADDR, ++ STA_ADDR0, ++ STA_ADDR1, ++}; ++ ++ ++/* ++ * create cdt table ++ */ ++struct sfc_cdt{ ++ uint32_t link; ++ uint32_t xfer; ++ uint32_t staExp; ++ uint32_t staMsk; ++}; ++ ++#define CMD_XFER(ADDR_WIDTH, POLL_EN, DMY_BITS, DATA_EN, CMD) ( \ ++ (ADDR_WIDTH << TRAN_CONF0_ADDR_WIDTH_OFFSET) \ ++ | (POLL_EN << TRAN_CONF0_POLL_OFFSET) \ ++ | (TRAN_CONF0_CMDEN) \ ++ | (0 << TRAN_CONF0_FMAT_OFFSET) \ ++ | (DMY_BITS << TRAN_CONF0_DMYBITS_OFFSET) \ ++ | (DATA_EN << TRAN_CONF0_DATEEN_OFFSET) \ ++ | CMD \ ++ ) ++ ++#define CMD_LINK(LINK, ADDRMODE, TRAN_MODE) ( \ ++ (LINK << 31) | (TRAN_MODE << TRAN_CONF1_TRAN_MODE_OFFSET) | (ADDRMODE) \ ++ ) ++ ++#define MK_CMD(cdt, cmd_info, LINK, ADDRMODE, DATA_EN) { \ ++ cdt.link = CMD_LINK(LINK, ADDRMODE, cmd_info.transfer_mode); \ ++ cdt.xfer = CMD_XFER(cmd_info.addr_nbyte, DISABLE, cmd_info.dummy_byte, DATA_EN, cmd_info.cmd); \ ++ cdt.staExp = 0; \ ++ cdt.staMsk = 0; \ ++} ++ ++#define MK_ST(cdt, st_info, LINK, ADDRMODE, ADDR_WIDTH, POLL_EN, DATA_EN, TRAN_MODE) { \ ++ cdt.link = CMD_LINK(LINK, ADDRMODE, TRAN_MODE); \ ++ cdt.xfer = CMD_XFER(ADDR_WIDTH, POLL_EN, st_info.dummy, DATA_EN, st_info.cmd); \ ++ cdt.staExp = (st_info.val << st_info.bit_shift); \ ++ cdt.staMsk = (st_info.mask << st_info.bit_shift); \ ++} ++ ++ ++#endif ++ ++ +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/sfc_flash.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/sfc_flash.h +new file mode 100644 +index 000000000..7da74297d +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/sfc_flash.h +@@ -0,0 +1,33 @@ ++#ifndef __SFC_FLASH_H ++#define __SFC_FLASH_H ++#include ++#include ++#include ++#include ++#include "sfc.h" ++ ++struct sfc_flash { ++ ++ struct sfc *sfc; ++ void *flash_info; ++ struct device* dev; ++ struct mtd_info mtd; ++ struct mtd_part_parser_data ppdata; ++ struct mutex lock; ++ unsigned long sfc_init_frequency; ++ unsigned long sfc_max_frequency; ++ int param_offset; //param_offset. ++ struct nand_chip *chip; ++ struct ingenic_sfc_info *pdata_params; ++ void (*create_cdt_table)(struct sfc *,void *, uint32_t); ++ struct attribute_group *attr_group; ++}; ++ ++struct ingenic_sfc_info { ++ ++ uint8_t use_ofpart_info; /* use device tree partiton flag */ ++ int param_offset; /* param_offset */ ++ struct device_node *part_node; /* flash node */ ++}; ++ ++#endif +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinand.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinand.h +new file mode 100644 +index 000000000..01a29a93a +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinand.h +@@ -0,0 +1,187 @@ ++#ifndef __SPINAND_H ++#define __SPINAND_H ++#include ++#include "sfc_flash.h" ++#include "spinand_cmd.h" ++ ++#define SPIFLASH_PARAMER_OFFSET 0x5800 ++#define SPINAND_MAGIC_NUM 0x646e616e ++ ++/* the max number of DMA Descriptor */ ++#define DESC_MAX_NUM 2 ++ ++struct ingenic_sfcnand_base_param { ++ uint32_t pagesize; ++ uint32_t blocksize; ++ uint32_t oobsize; ++ uint32_t flashsize; ++ ++ uint16_t tHOLD; ++ uint16_t tSETUP; ++ uint16_t tSHSL_R; ++ uint16_t tSHSL_W; ++ ++ uint16_t tRD; ++ uint16_t tPP; ++ uint16_t tBE; ++ ++ /* ++ * Indicates that NAND flash has a serial plane structure, ++ * needs to convert the plane by changing the column address ++ */ ++ uint8_t plane_select; ++ ++ uint8_t ecc_max; ++ uint8_t need_quad; ++}; ++ ++struct flash_address { ++ uint32_t pageaddr; ++ uint32_t columnaddr; ++ uint8_t ops_mode; ++}; ++ ++struct ingenic_sfcnand_partition_param { ++ struct mtd_partition *partition; ++ uint8_t num_partition; ++}; ++ ++struct device_id_struct { ++ uint8_t id_device; ++ char *name; ++ struct ingenic_sfcnand_base_param *param; ++}; ++ ++struct spi_nand_cmd_info { ++ unsigned short cmd; ++ unsigned char dummy_byte; ++ unsigned char addr_nbyte; ++ unsigned char transfer_mode; ++ ++}; ++ ++struct spi_nand_st_info { ++ unsigned short cmd; ++ unsigned char bit_shift; ++ unsigned char mask; ++ unsigned char val; ++ unsigned char len; //length of byte to operate from register ++ unsigned char dummy; ++}; ++ ++struct ingenic_sfcnand_cdt_params { ++ /* general cmd info */ ++ struct spi_nand_cmd_info r_to_cache; ++ struct spi_nand_cmd_info standard_r; ++ struct spi_nand_cmd_info quad_r; ++ struct spi_nand_cmd_info standard_w_cache; ++ struct spi_nand_cmd_info quad_w_cache; ++ struct spi_nand_cmd_info w_exec; ++ struct spi_nand_cmd_info b_erase; ++ struct spi_nand_cmd_info w_en; ++ struct spi_nand_cmd_info ecc_r; ++ ++ /* status polling cmd info */ ++ struct spi_nand_st_info oip; ++}; ++typedef struct ingenic_sfcnand_cdt_params cdt_params_t; ++ ++struct ingenic_sfcnand_ops { ++ cdt_params_t *(*get_cdt_params)(struct sfc_flash *, uint8_t); ++ int (*deal_ecc_status)(struct sfc_flash *, uint8_t, uint8_t); ++ int32_t (*get_feature)(struct sfc_flash *, uint8_t); ++}; ++ ++struct ingenic_sfcnand_device { ++ uint8_t id_manufactory; ++ struct device_id_struct *id_device_list; ++ uint8_t id_device_count; ++ ++ struct ingenic_sfcnand_ops ops; ++ cdt_params_t cdt_params; ++ ++ struct list_head list; ++}; ++ ++struct ingenic_sfcnand_flashinfo { ++ uint8_t id_manufactory; ++ uint8_t id_device; ++ ++ struct ingenic_sfcnand_base_param param; ++ struct ingenic_sfcnand_partition_param partition; ++ struct ingenic_sfcnand_ops *ops; ++ cdt_params_t *cdt_params; ++}; ++ ++struct ingenic_sfcnand_partition { ++ char name[32]; /* identifier string */ ++ uint32_t size; /* partition size */ ++ uint32_t offset; /* offset within the master MTD space */ ++ uint32_t mask_flags; /* master MTD flags to mask out for this partition */ ++ uint32_t manager_mode; /* manager_mode mtd or ubi */ ++}; ++ ++struct ingenic_sfcnand_burner_param { ++ uint32_t magic_num; ++ int32_t partition_num; ++ struct ingenic_sfcnand_partition *partition; ++}; ++ ++int32_t ingenic_sfcnand_register(struct ingenic_sfcnand_device *flash); ++ ++ ++/* SFC CDT Maximum INDEX number */ ++#define INDEX_MAX_NUM 32 ++ ++/* SFC CDT INDEX */ ++enum { ++ /* 1. reset */ ++ NAND_RESET, ++ ++ /* 2. try id */ ++ NAND_TRY_ID, ++ ++ /* 3. try id with dummy */ ++ NAND_TRY_ID_DMY, ++ ++ /* 4. set feature */ ++ NAND_SET_FEATURE, ++ ++ /* 5. get feature */ ++ NAND_GET_FEATURE, ++ ++ /* 6. nand standard read */ ++ NAND_STANDARD_READ_TO_CACHE, ++ NAND_STANDARD_READ_GET_FEATURE, ++ NAND_STANDARD_READ_FROM_CACHE, ++ ++ /* 7. nand quad read */ ++ NAND_QUAD_READ_TO_CACHE, ++ NAND_QUAD_READ_GET_FEATURE, ++ NAND_QUAD_READ_FROM_CACHE, ++ ++ /* 8. nand standard write */ ++ NAND_STANDARD_WRITE_ENABLE, ++ NAND_STANDARD_WRITE_TO_CACHE, ++ NAND_STANDARD_WRITE_EXEC, ++ NAND_STANDARD_WRITE_GET_FEATURE, ++ ++ /* 9. nand quad write */ ++ NAND_QUAD_WRITE_ENABLE, ++ NAND_QUAD_WRITE_TO_CACHE, ++ NAND_QUAD_WRITE_EXEC, ++ NAND_QUAD_WRITE_GET_FEATURE, ++ ++ /* 10. block erase */ ++ NAND_ERASE_WRITE_ENABLE, ++ NAND_BLOCK_ERASE, ++ NAND_ERASE_GET_FEATURE, ++ ++ /* 11. ecc status read */ ++ NAND_ECC_STATUS_READ, ++ ++ /* index count */ ++ NAND_MAX_INDEX, ++}; ++ ++#endif +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinand_cmd.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinand_cmd.h +new file mode 100644 +index 000000000..f0b31f27d +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinand_cmd.h +@@ -0,0 +1,30 @@ ++#ifndef __SPINAND_CMD_H ++#define __SPINAND_CMD_H ++ ++#define SPINAND_CMD_RDID 0x9f /* read spi nand id */ ++#define SPINAND_CMD_WREN 0x06 /* spi nand write enable */ ++#define SPINAND_CMD_PRO_LOAD 0x02 /* program load */ ++#define SPINAND_CMD_PRO_LOAD_X4 0x32 /* program load fast*/ ++#define SPINAND_CMD_PRO_EN 0x10 /* program load execute */ ++#define SPINAND_CMD_PARD 0x13 /* read page data to spi nand cache */ ++#define SPINAND_CMD_PLRd 0x84 /* program load random data */ ++#define SPINAND_CMD_PLRd_X4 0xc4 /* program load random data x4*/ ++#define SPINAND_CMD_RDCH 0x03 /* read from spi nand cache */ ++#define SPINAND_CMD_RDCH_X4 0x6b /* read from spi nand cache */ ++#define SPINAND_CMD_FRCH 0x0b /* fast read from spi nand cache */ ++#define SPINAND_CMD_FRCH_IO 0xeb /* for Quad I/O SPI mode */ ++#define SPINAND_CMD_ERASE_128K 0xd8 /* erase spi nand block 128K */ ++#define SPINAND_CMD_GET_FEATURE 0x0f /* get spi nand feature */ ++#define SPINAND_CMD_SET_FEATURE 0x1f /* set spi nand feature */ ++#define SPINAND_CMD_RESET 0xff /* reset nand flash device */ ++ ++ ++#define SPINAND_ADDR_PROTECT 0xa0 /* protect addr */ ++#define SPINAND_ADDR_STATUS 0xc0 /* get feature status addr */ ++#define SPINAND_ADDR_FEATURE 0xb0 /* set feature addr */ ++ ++#define SPINAND_IS_BUSY (1 << 0) /* PROGRAM EXECUTE, PAGE READ, BLOCK ERASE, or RESET command executing */ ++#define SPINAND_OP_BL_128K (128 * 1024) ++ ++ ++#endif +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinor.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinor.h +new file mode 100644 +index 000000000..e2f397e6b +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinor.h +@@ -0,0 +1,205 @@ ++#ifndef __SPINOR_H ++#define __SPINOR_H ++#include "sfc_flash.h" ++#include "spinor_cmd.h" ++ ++#define SPIFLASH_PARAMER_OFFSET 0x5800 ++#define NOR_MAJOR_VERSION_NUMBER 2 ++#define NOR_MINOR_VERSION_NUMBER 0 ++#define NOR_REVERSION_NUMBER 0 ++#define NOR_VERSION (NOR_MAJOR_VERSION_NUMBER | (NOR_MINOR_VERSION_NUMBER << 8) | (NOR_REVERSION_NUMBER << 16)) ++ ++ ++#define SIZEOF_NAME 32 ++ ++#define NOR_MAGIC 0x726f6e //ascii "nor" ++#define NOR_PART_NUM 10 ++#define NORFLASH_PART_RW 0 ++#define NORFLASH_PART_WO 1 ++#define NORFLASH_PART_RO 2 ++ ++/* the max number of DMA Descriptor */ ++#define DESC_MAX_NUM 64 ++ ++ ++struct spi_nor_cmd_info { ++ unsigned short cmd; ++ unsigned char dummy_byte; ++ unsigned char addr_nbyte; ++ unsigned char transfer_mode; ++ ++}; ++ ++struct spi_nor_st_info { ++ unsigned short cmd; ++ unsigned char bit_shift; ++ unsigned char mask; ++ unsigned char val; ++ unsigned char len; //length of byte to operate from register ++ unsigned char dummy; ++}; ++ ++struct spi_nor_info { ++ unsigned char name[32]; ++ unsigned int id; ++ ++ struct spi_nor_cmd_info read_standard; ++ struct spi_nor_cmd_info read_quad; ++ ++ struct spi_nor_cmd_info write_standard; ++ struct spi_nor_cmd_info write_quad; ++ ++ struct spi_nor_cmd_info sector_erase; ++ ++ struct spi_nor_cmd_info wr_en; ++ struct spi_nor_cmd_info en4byte; ++ struct spi_nor_st_info quad_set; ++ struct spi_nor_st_info quad_get; ++ struct spi_nor_st_info busy; ++ ++ unsigned short quad_ops_mode; ++ unsigned short addr_ops_mode; ++ ++ unsigned int tCHSH; //hold ++ unsigned int tSLCH; //setup ++ unsigned int tSHSL_RD; //interval ++ unsigned int tSHSL_WR; ++ ++ unsigned int chip_size; ++ unsigned int page_size; ++ unsigned int erase_size; ++ ++ unsigned char chip_erase_cmd; ++}; ++ ++struct nor_partition { ++ char name[32]; ++ uint32_t size; ++ uint32_t offset; ++ uint32_t mask_flags;//bit 0-1 mask the partiton RW mode, 0:RW 1:W 2:R ++ uint32_t manager_mode; ++}; ++ ++struct norflash_partitions { ++ struct nor_partition nor_partition[NOR_PART_NUM]; ++ uint32_t num_partition_info; ++}; ++ ++struct nor_private_data { ++ unsigned int fs_erase_size; ++ unsigned char uk_quad; ++}; ++ ++ ++struct burner_params { ++ uint32_t magic; ++ uint32_t version; ++ struct spi_nor_info spi_nor_info; ++ struct norflash_partitions norflash_partitions; ++ struct nor_private_data nor_pri_data; ++}; ++ ++struct nor_params_node { ++ struct spi_nor_info nor_device_info; ++ struct list_head list; ++}; ++ ++struct builtin_params { ++ uint32_t magic; ++ uint32_t version; ++ struct spi_nor_info *spi_nor_info; ++ struct nor_private_data *nor_pri_data; ++}; ++ ++struct spi_nor_flash_ops { ++ int (*set_4byte_mode)(struct sfc_flash *flash); ++ int (*set_quad_mode)(struct sfc_flash *flash); ++}; ++ ++struct spinor_flashinfo { ++ ++ uint8_t current_die_id; ++ uint32_t die_shift; ++ uint32_t die_num; ++ int quad_succeed; ++ struct spi_nor_flash_ops *nor_flash_ops; ++ struct spi_nor_info *nor_flash_info; ++ struct spi_nor_cmd_info *cur_r_cmd; ++ struct spi_nor_cmd_info *cur_w_cmd; ++ struct norflash_partitions *norflash_partitions; ++ struct nor_private_data *nor_pri_data; ++ ++}; ++ ++struct multi_die_flash { ++ uint32_t flash_id; ++ uint32_t die_num; ++ char* flash_name; ++}; ++ ++int ingenic_sfcnor_register(struct nor_params_node *); ++struct builtin_params *get_nor_builtin_params(struct sfc_flash *, struct builtin_params *); ++int32_t sfc_nor_get_special_ops(struct sfc_flash *); ++ ++/* SFC CDT Maximum INDEX number */ ++#define INDEX_MAX_NUM 32 ++ ++enum { ++ /* 1. nor reset */ ++ NOR_RESET_ENABLE, ++ NOR_RESET, ++ ++ /* 2. nor read id */ ++ NOR_READ_ID, ++ ++ /* 3. nor get status */ ++ NOR_GET_STATUS, ++ NOR_GET_STATUS_1, ++ NOR_GET_STATUS_2, ++ ++ /* 4. nor singleRead */ ++ NOR_READ_STANDARD, ++ ++ /* 5. nor quadRead */ ++ NOR_READ_QUAD, ++ ++ /* 6. nor writeStandard */ ++ NOR_WRITE_STANDARD_ENABLE, ++ NOR_WRITE_STANDARD, ++ NOR_WRITE_STANDARD_FINISH, ++ ++ /* 7. nor writeQuad */ ++ NOR_WRITE_QUAD_ENABLE, ++ NOR_WRITE_QUAD, ++ NOR_WRITE_QUAD_FINISH, ++ ++ /* 8. nor erase */ ++ NOR_ERASE_WRITE_ENABLE, ++ NOR_ERASE, ++ NOR_ERASE_FINISH, ++ ++ /* 9. quad mode */ ++ NOR_QUAD_SET_ENABLE, ++ NOR_QUAD_SET, ++ NOR_QUAD_FINISH, ++ NOR_QUAD_GET, ++ ++ /* 10. nor write ENABLE */ ++ NOR_WRITE_ENABLE, ++ ++ /* 11. entry 4byte mode */ ++ NOR_EN_4BYTE, ++ ++ /* 13. active die */ ++ NOR_DIE_SELECT, ++ ++ /* 14. read die id */ ++ NOR_READ_ACTIVE_DIE_ID, ++ ++ /* index count */ ++ NOR_MAX_INDEX, ++}; ++ ++ ++#endif ++ +diff --git a/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinor_cmd.h b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinor_cmd.h +new file mode 100644 +index 000000000..d6063f1a4 +--- /dev/null ++++ b/module_drivers/drivers/mtd/devices/ingenic_sfc_v2/spinor_cmd.h +@@ -0,0 +1,84 @@ ++#ifndef __SPINOR_CMD_H ++#define __SPINOR_CMD_H ++ ++/* Flash opcodes. */ ++#define SPINOR_OP_RSTEN 0x66 /* reset enable */ ++#define SPINOR_OP_RST 0x99 /* reset */ ++#define SPINOR_OP_WREN 0x06 /* Write enable */ ++#define SPINOR_OP_RDSR 0x05 /* Read status register */ ++#define SPINOR_OP_RDSR_1 0x35 /* Read status1 register */ ++#define SPINOR_OP_RDSR_2 0x15 /* Read status2 register */ ++#define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */ ++#define SPINOR_OP_WRSR_1 0x31 /* Write status1 register 1 byte */ ++#define SPINOR_OP_WRSR_2 0x11 /* Write status2 register 1 byte */ ++#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */ ++#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */ ++#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */ ++#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */ ++#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */ ++#define SPINOR_OP_QPP 0x32 /* Page program (up to 256 bytes) */ ++#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */ ++#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ ++#define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */ ++#define SPINOR_OP_CHIP_ERASE 0xc7 /* Erase whole flash chip */ ++#define SPINOR_OP_SE 0xd8 /* Sector erase (usually 64KiB) */ ++#define SPINOR_OP_RDID 0x9f /* Read JEDEC ID */ ++#define SPINOR_OP_RDCR 0x35 /* Read configuration register */ ++#define SPINOR_OP_RDFSR 0x70 /* Read flag status register */ ++#define SPINOR_OP_DIE_SEL 0xc2 /* Software Die Select */ ++#define SPINOR_OP_READ_DIE_ID 0xf8 /* Read Active Die ID */ ++ ++/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ ++#define SPINOR_OP_READ4 0x13 /* Read data bytes (low frequency) */ ++#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */ ++#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */ ++#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */ ++#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */ ++#define SPINOR_OP_QPP_4B 0x34 /* Page program (up to 256 bytes) */ ++#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */ ++#define SPINOR_OP_BE_32K_4B 0x5c /* Erase 32KiB block */ ++ ++/* Used for SST flashes only. */ ++#define SPINOR_OP_BP 0x02 /* Byte program */ ++#define SPINOR_OP_WRDI 0x04 /* Write disable */ ++#define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */ ++ ++/* Used for Macronix and Winbond flashes. */ ++#define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ ++#define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ ++ ++/* Used for Spansion flashes only. */ ++#define SPINOR_OP_BRWR 0x17 /* Bank register write */ ++ ++/* Status Register bits. */ ++#define SR_WIP 1 /* Write in progress */ ++#define SR_WEL 2 /* Write enable latch */ ++#define SR_SQE (1 << 1) /* QUAD MODE enable */ ++/* meaning of other SR_* bits may differ between vendors */ ++#define SR_BP0 4 /* Block protect 0 */ ++#define SR_BP1 8 /* Block protect 1 */ ++#define SR_BP2 0x10 /* Block protect 2 */ ++#define SR_SRWD 0x80 /* SR write protect */ ++ ++#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ ++ ++/* Flag Status Register bits */ ++#define FSR_READY 0x80 ++ ++/* Configuration Register bits. */ ++#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */ ++ ++ ++#define CMD_WREN 0x06 /* Write Enable */ ++#define CMD_EN4B 0xB7 ++#define CMD_EX4B 0xE9 ++/* nor cmd entry deep power down and Release from Deep Power-Down and Read Device ID */ ++#define CMD_DP (0xB9) ++#define CMD_RDP (0xAB) ++ ++ ++#define BUFFER_SIZE PAGE_SIZE ++ ++#define NOR_SIZE_16M 0x1000000 ++ ++#endif +diff --git a/module_drivers/drivers/net/Makefile b/module_drivers/drivers/net/Makefile +new file mode 100644 +index 000000000..94ab82927 +--- /dev/null ++++ b/module_drivers/drivers/net/Makefile +@@ -0,0 +1,3 @@ ++obj-y += ethernet/ ++obj-y += wireless/ ++#obj-y += can/ +diff --git a/module_drivers/drivers/net/ethernet/Makefile b/module_drivers/drivers/net/ethernet/Makefile +new file mode 100644 +index 000000000..10e2febc6 +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/Makefile +@@ -0,0 +1 @@ ++obj-y += ingenic/ +diff --git a/module_drivers/drivers/net/ethernet/ingenic/Kconfig b/module_drivers/drivers/net/ethernet/ingenic/Kconfig +new file mode 100644 +index 000000000..10fc5cbed +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/ingenic/Kconfig +@@ -0,0 +1,46 @@ ++config INGENIC_MAC ++ tristate "ingenic on-chip MAC support" ++ select CRC32 ++ select MII ++ help ++ This is the driver for INGENIC on-chip mac device. ++ ++config INGENIC_MAC_DMA_INTERFACES ++ bool "Ingenic mac dma interfaces" ++ depends on INGENIC_MAC ++ help ++ This is for MAC Dma interfaces selection ++choice ++ prompt "Ingenic mac dma bus interfaces" ++ depends on INGENIC_MAC_DMA_INTERFACES ++ ++config INGENIC_MAC_AXI_BUS ++ bool "MAC_AXI_BUS" ++ help ++ Select for mac dma AXI bus ++ ++config INGENIC_MAC_AHB_BUS ++ bool "MAC_AHB_BUS" ++ help ++ Select for mac dma AHB bus ++endchoice ++ ++config INGENIC_GMAC_USE_HWSTAMP ++ bool "Use IEEE 1588 hwstamp" ++ depends on INGENIC_MAC ++ select PTP_1588_CLOCK ++ help ++ To support the IEEE 1588 Precision Time Protocol (PTP) ++ ++config INGENIC_GMAC_MUTUAL_TRANS ++ bool "Dual core mutex transmission" ++ depends on INGENIC_MAC ++ help ++ Dual core mutex transmission for cache bumps ++ ++config INGENIC_GMAC_RX_DESC_COUNT ++ int "Ingenic gmac receive descriptor number[80..10240]" ++ depends on INGENIC_MAC ++ default 512 ++ help ++ Ingenic gmac receive descriptor number +diff --git a/module_drivers/drivers/net/ethernet/ingenic/Makefile b/module_drivers/drivers/net/ethernet/ingenic/Makefile +new file mode 100644 +index 000000000..d72badfeb +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/ingenic/Makefile +@@ -0,0 +1,31 @@ ++ ++#################################################### ++# Explanation for EXTRA_FLAGS ++# -DDEBUG => Enable the debug trace for driver ++# -DIPC_OFFLOAD => Enables the IP and TCP checksum offloading feature in HW (IPV4 only) ++# -DENH_DESC => Enables Enhanced Descriptors ++# -DENH_DESC_8W => Enable Enhanced Descriptors of 8words or else Descriptor will be of 4words. ++#################################################### ++ ++ ++#with the below flags enables Debug messages ++ ++#EXTRA_CFLAGS += -DDEBUG ++#EXTRA_CFLAGS +=-DDEBUG -DIPC_OFFLOAD ++#EXTRA_CFLAGS += -DDEBUG -DIPC_OFFLOAD ++#EXTRA_CFLAGS += -DIPC_OFFLOAD ++ ++ ++#Enhanced Descriptor ++#EXTRA_CFLAGS += -DENH_DESC ++#EXTRA_CFLAGS += -DENH_DESC -DIPC_OFFLOAD ++EXTRA_CFLAGS += -DENH_DESC -DENH_DESC_8W ++#EXTRA_CFLAGS += -DDEBUG -DENH_DESC -DENH_DESC_8W ++#EXTRA_CFLAGS += -DDEBUG -DENH_DESC -DENH_DESC_8W -DIPC_OFFLOAD ++#EXTRA_CFLAGS += -DENH_DESC -DENH_DESC_8W -DIPC_OFFLOAD ++#EXTRA_CFLAGS += -DENH_DESC -DENH_DESC_8W -DAVB_SUPPORT -DDEBUG ++#EXTRA_CFLAGS += -DENH_DESC -DENH_DESC_8W -DAVB_SUPPORT ++#EXTRA_CFLAGS += -DENH_DESC -DENH_DESC_8W ++ ++obj-$(CONFIG_INGENIC_MAC) += mac.o ++mac-objs := synopGMAC_plat.o synopGMAC_Dev.o ethtool.o ingenic_mac.o +diff --git a/module_drivers/drivers/net/ethernet/ingenic/ethtool.c b/module_drivers/drivers/net/ethernet/ingenic/ethtool.c +new file mode 100644 +index 000000000..fc76b9526 +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/ingenic/ethtool.c +@@ -0,0 +1,284 @@ ++/* Intel PRO/1000 Linux driver ++ * Copyright(c) 1999 - 2015 Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * The full GNU General Public License is included in this distribution in ++ * the file called "COPYING". ++ * ++ */ ++ ++/* ethtool support for ingenic_mac */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ingenic_mac.h" ++ ++struct ingenic_mac_reg ++{ ++ u32 addr; ++ char * name; ++}; ++ ++static struct ingenic_mac_reg mac[] = ++{ ++ { 0x0000, " Config" }, ++ { 0x0004, " Frame Filter" }, ++ { 0x0008, " MAC HT High" }, ++ { 0x000C, " MAC HT Low" }, ++ { 0x0010, " GMII Addr" }, ++ { 0x0014, " GMII Data" }, ++ { 0x0018, " Flow Control" }, ++ { 0x001C, " VLAN Tag" }, ++ { 0x0020, " GMAC Version" }, ++ { 0x0024, " GMAC Debug " }, ++ { 0x0028, "Remote Wake-Up Frame Filter" }, ++ { 0x002C, " PMT Control and Status" }, ++ { 0x0030, " LPI Control and status" }, ++ { 0x0034, " LPI Timers Control" }, ++ { 0x0038, " Interrupt Status" }, ++ { 0x003c, " Interrupt Mask" }, ++ { 0x0040, " MAC Addr0 High" }, ++ { 0x0044, " MAC Addr0 Low" }, ++ { 0x0048, " MAC Addr1 High" }, ++ { 0x004c, " MAC Addr1 Low" }, ++ { 0x0100, " MMC Ctrl Reg " }, ++ { 0x010c, " MMC Intr Msk(rx)" }, ++ { 0x0110, " MMC Intr Msk(tx)" }, ++ { 0x0200, " MMC Intr Msk(rx ipc)" }, ++ { 0x0700, " Timestamp control" }, ++ { 0x0704, " Sub-Second Increment" }, ++ { 0x0708, " Seconds" }, ++ { 0x070c, " Nanoseconds" }, ++ { 0x0710, " Update seconds" }, ++ { 0x0714, " Update Nanoseconds" }, ++ { 0x0718, " Adjust frequency" }, ++ { 0x0738, " AVMAC Ctrl Reg" }, ++ { 0x00D8, " RGMII C/S Reg" }, ++ { 0, 0 } ++}; ++static struct ingenic_mac_reg dma0[] = ++{ ++ { 0x0000, "[CH0] CSR0 Bus Mode" }, ++ { 0x0004, "[CH0] CSR1 TxPlDmnd" }, ++ { 0x0008, "[CH0] CSR2 RxPlDmnd" }, ++ { 0x000C, "[CH0] CSR3 Rx Base" }, ++ { 0x0010, "[CH0] CSR4 Tx Base" }, ++ { 0x0014, "[CH0] CSR5 Status" }, ++ { 0x0018, "[CH0] CSR6 Control" }, ++ { 0x001C, "[CH0] CSR7 Int Enable" }, ++ { 0x0020, "[CH0] CSR8 Missed Fr." }, ++ { 0x0028, "[CH0] CSR10 AXI Mode." }, ++ { 0x0024, "[CH0] Recv Intr Wd.Tm." }, ++ { 0x0028, "[CH0] AXI Bus Mode " }, ++ { 0x002c, "[CH0] AHB or AXI Status" }, ++ { 0x0048, "[CH0] CSR18 Tx Desc " }, ++ { 0x004C, "[CH0] CSR19 Rx Desc " }, ++ { 0x0050, "[CH0] CSR20 Tx Buffer" }, ++ { 0x0054, "[CH0] CSR21 Rx Buffer" }, ++ { 0x0058, "CSR22 HWCFG " }, ++ { 0, 0 } ++}; ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_dma_regs(synopGMACdevice *gmacdev) ++{ ++ struct ingenic_mac_reg *reg = dma0; ++ ++ printk("======================DMA Regs start===================\n"); ++ while(reg->name) { ++ printk("===>%s:\t0x%08x\n", reg->name, synopGMACReadReg((u32 *)gmacdev->DmaBase,reg->addr)); ++ reg++; ++ } ++ printk("======================DMA Regs end===================\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_mac_regs(synopGMACdevice *gmacdev) ++{ ++ struct ingenic_mac_reg *reg = mac; ++ ++ printk("======================MAC Regs start===================\n"); ++ while(reg->name) { ++ printk("===>%s:\t0x%08x\n", reg->name, synopGMACReadReg((u32 *)gmacdev->MacBase,reg->addr)); ++ reg++; ++ } ++ printk("======================MAC Regs end===================\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_phy_regs(struct ingenic_mac_local *lp) { ++ u16 phy[] = {0, 1, 4, 5, 6, 9, 10, 15, 16, 17, 18, 20, 21, 24, 0x1c}; ++ ++ u16 data[sizeof(phy) / sizeof(u16)]; ++ int i; ++ ++ printk("======================PHY Regs start===================\n"); ++ printk("\n-------->PHY dump: %08x\n", lp->phydev->phy_id); ++ for (i = 0; i < sizeof(phy) / sizeof(u16); i++) ++ data[i] = lp->mii_bus->read(lp->mii_bus, lp->phydev->mdio.addr, phy[i]); ++ ++ for (i = 0; i < sizeof(phy) / sizeof(u16); i++) ++ printk("PHY reg%d, value %04x\n", phy[i], data[i]); ++ printk("======================PHY Regs end===================\n"); ++ ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_all_regs(struct net_device *netdev) { ++ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ ingenic_mac_dump_phy_regs(lp); ++ ingenic_mac_dump_dma_regs(gmacdev); ++ ingenic_mac_dump_mac_regs(gmacdev); ++ ++} ++ ++static void ingenic_get_drvinfo(struct net_device *netdev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ strlcpy(drvinfo->driver, INGENIC_MAC_DRV_NAME,sizeof(drvinfo->driver)); ++ strlcpy(drvinfo->version, INGENIC_MAC_DRV_VERSION,sizeof(drvinfo->version)); ++} ++ ++static int ingenic_get_regs_len(struct net_device __always_unused *netdev) ++{ ++ return 0; ++} ++ ++static void ingenic_get_regs(struct net_device *netdev, ++ struct ethtool_regs *regs, void *p) ++{ ++ pm_runtime_get_sync(netdev->dev.parent); ++ ingenic_mac_dump_all_regs(netdev); ++ pm_runtime_put_sync(netdev->dev.parent); ++} ++ ++static void ingenic_get_pauseparam(struct net_device *ndev, ++ struct ethtool_pauseparam *pp) ++{ ++ const struct ingenic_mac_local *lp = netdev_priv(ndev); ++ ++ pp->autoneg = lp->flowcontrol.autoneg; ++ pp->tx_pause = lp->flowcontrol.tx; ++ pp->rx_pause = lp->flowcontrol.rx; ++} ++ ++static int ingenic_set_pauseparam(struct net_device *ndev, ++ struct ethtool_pauseparam *pp) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(ndev); ++ int ret = 0; ++ ++ lp->flowcontrol.autoneg = pp->autoneg; ++ if (pp->autoneg) { ++ linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, lp->phydev->advertising); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, lp->phydev->advertising); ++ } else { ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, lp->phydev->advertising); ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, lp->phydev->advertising); ++ lp->flowcontrol.rx = pp->rx_pause; ++ lp->flowcontrol.tx = pp->tx_pause; ++ } ++ ++ if (netif_running(ndev)) ++ ret = phy_start_aneg(lp->phydev); ++ ++ return ret; ++} ++ ++ ++static int ingenic_set_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *ec) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ ++ /* Check not supported parameters */ ++ if ((ec->rx_max_coalesced_frames) || (ec->rx_coalesce_usecs_irq) || ++ (ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) || ++ (ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) || ++ (ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) || ++ (ec->rx_max_coalesced_frames_low) || (ec->tx_coalesce_usecs_high) || ++ (ec->tx_max_coalesced_frames_low) || (ec->pkt_rate_high) || ++ (ec->tx_coalesce_usecs_low) || (ec->rx_coalesce_usecs_high) || ++ (ec->rx_max_coalesced_frames_high) || ++ (ec->tx_max_coalesced_frames_irq) || ++ (ec->stats_block_coalesce_usecs) || ++ (ec->tx_max_coalesced_frames) || ++ (ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval)) ++ return -EOPNOTSUPP; ++ ++ if (ec->tx_coalesce_usecs > INGENIC_TX_MAX_COALESCE_USECS || ++ ec->tx_coalesce_usecs < INGENIC_TX_MIN_COALESCE_USECS) ++ return -EINVAL; ++ if (ec->rx_coalesce_usecs > INGENIC_RX_MAX_COALESCE_USECS || ++ ec->rx_coalesce_usecs < INGENIC_RX_MIN_COALESCE_USECS) ++ return -EINVAL; ++ ++ lp->tx_coalesce_usecs = ec->tx_coalesce_usecs; ++ lp->rx_coalesce_usecs = ec->rx_coalesce_usecs; ++ ++ return 0; ++} ++ ++static int ingenic_get_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *ec) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ ++ ec->tx_coalesce_usecs = lp->tx_coalesce_usecs; ++ ec->rx_coalesce_usecs = lp->rx_coalesce_usecs; ++ ++ return 0; ++} ++static u32 ingenic_get_msglevel(struct net_device *ndev) ++{ ++ const struct ingenic_mac_local *lp = netdev_priv(ndev); ++ ++ return lp->msg_enable; ++} ++ ++static void ingenic_set_msglevel(struct net_device *ndev, u32 msglevel) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(ndev); ++ ++ lp->msg_enable = msglevel; ++} ++ ++static const struct ethtool_ops ingenic_mac_ethtool_ops = { ++ ++ .set_link_ksettings = phy_ethtool_set_link_ksettings, ++ .get_link_ksettings = phy_ethtool_get_link_ksettings, ++ .get_drvinfo = ingenic_get_drvinfo, ++ .get_regs_len = ingenic_get_regs_len, ++ .get_regs = ingenic_get_regs, ++ .get_link = ethtool_op_get_link, ++ .get_pauseparam = ingenic_get_pauseparam, ++ .set_pauseparam = ingenic_set_pauseparam, ++ .get_coalesce = ingenic_get_coalesce, ++ .set_coalesce = ingenic_set_coalesce, ++ .get_msglevel = ingenic_get_msglevel, ++ .set_msglevel = ingenic_set_msglevel, ++ .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS ++ | ETHTOOL_COALESCE_RX_MAX_FRAMES ++ | ETHTOOL_COALESCE_TX_USECS ++ | ETHTOOL_COALESCE_TX_MAX_FRAMES, ++}; ++ ++void ingenic_mac_set_ethtool_ops(struct net_device *netdev) ++{ ++ netdev->ethtool_ops = &ingenic_mac_ethtool_ops; ++} +diff --git a/module_drivers/drivers/net/ethernet/ingenic/ingenic_mac.c b/module_drivers/drivers/net/ethernet/ingenic/ingenic_mac.c +new file mode 100644 +index 000000000..f7eddcbcb +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/ingenic/ingenic_mac.c +@@ -0,0 +1,3424 @@ ++/* ++ * ingenic On-Chip MAC Driver ++ * ++ * Copyright (C) 2010 - 2011 Ingenic Semiconductor Inc. ++ * ++ * Licensed under the GPL-2 or later. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ingenic_mac.h" ++#include ++ ++MODULE_AUTHOR("Lutts Wolf "); ++MODULE_VERSION(INGENIC_MAC_DRV_VERSION); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION(INGENIC_MAC_DRV_DESC); ++MODULE_ALIAS("platform:"INGENIC_MAC_DRV_NAME); ++ ++#define COPYBREAK_DEFAULT 256 ++static unsigned int copybreak __read_mostly = COPYBREAK_DEFAULT; ++module_param(copybreak, uint, 0644); ++MODULE_PARM_DESC(copybreak, "Maximum size of packet that is copied to a new buffer on receive"); ++ ++int debug_enable = 0; ++module_param(debug_enable, int, 0644); ++MODULE_PARM_DESC(debug_enable, "ingenic mac TR(x) debug level (0=none,...,16=all)"); ++ ++int msg_level = 0; ++module_param(msg_level, int, 0644); ++MODULE_PARM_DESC(msg_level, "ingenic mac msg debug level (0=none,...,15=all)"); ++ ++#define INGENIC_MAC_RX_BUFFER_WRITE 16 /* Must be power of 2 */ ++#define MAX_TIMEOUT_CNT 5000 ++ ++/* Generate the bit field mask from msb to lsb */ ++#define BITS_H2L(msb, lsb) ((0xFFFFFFFF >> (32-((msb)-(lsb)+1))) << (lsb)) ++ ++static int inline ingenic_mac_clean_tx_irq(struct ingenic_mac_local *lp); ++static const struct of_device_id ingenic_mac_dt_match[]; ++ ++static int ingenic_mac_phy_hwrst(struct platform_device *pdev, bool init) ++{ ++ struct net_device *ndev = platform_get_drvdata(pdev); ++ struct ingenic_mac_local *lp = netdev_priv(ndev); ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ enum of_gpio_flags flags; ++ int ret = 0; ++ struct pinctrl *p = pinctrl_get(dev); ++ struct pinctrl_state *state = NULL; ++ ++ if (IS_ERR_OR_NULL(p)) { ++ dev_warn(&pdev->dev, "can not get pinctrl\n"); ++ return 0; ++ } ++ ++ if (init) ++ lp->reset_gpio = -ENODEV; ++ ++ if (!(lp->reset_gpio < 0)) ++ goto hw_reset; ++ ++ lp->reset_gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags); ++ if (lp->reset_gpio < 0) ++ goto out; ++ ret = devm_gpio_request(dev, lp->reset_gpio, "mac-hw-rst"); ++ if (ret) { ++ lp->reset_gpio = ret; ++ dev_err(dev, "ingenic mac-hw-rst gpio request failed errno(%d)\n", ret); ++ goto out; ++ } ++ lp->reset_lvl = flags & OF_GPIO_ACTIVE_LOW ? 0 : 1; ++ ++#define DEFAULT_RESET_DELAY_MS 10 ++ ret = of_property_read_u32(np, "ingenic,rst-delay-ms", &lp->reset_delay_ms); ++ if (ret < 0) ++ lp->reset_delay_ms = DEFAULT_RESET_DELAY_MS; ++#undef DEFAULT_RESET_DELAY_MS ++ ++ ++#define DEFAULT_RESET_MS 10 ++ ret = of_property_read_u32(np, "ingenic,rst-ms", &lp->reset_ms); ++ if (ret < 0) ++ lp->reset_ms = DEFAULT_RESET_MS; ++#undef DEFAULT_RESET_MS ++ ++hw_reset: ++ state = pinctrl_lookup_state(p, "reset"); ++ if (!IS_ERR_OR_NULL(state)) ++ pinctrl_select_state(p, state); ++ ++ gpio_direction_output(lp->reset_gpio, lp->reset_lvl); ++ if (in_atomic()) ++ mdelay(lp->reset_ms); ++ else ++ msleep(lp->reset_ms); ++ gpio_direction_output(lp->reset_gpio, !lp->reset_lvl); ++ ++ state = pinctrl_lookup_state(p, PINCTRL_STATE_DEFAULT); ++ if (!IS_ERR_OR_NULL(state)) ++ pinctrl_select_state(p, state); ++ ++ if (in_atomic()) ++ mdelay(lp->reset_delay_ms); ++ else ++ msleep(lp->reset_delay_ms); ++out: ++ pinctrl_put(p); ++ return ret; ++} ++ ++ ++static void ingenic_set_mdc_rate(struct ingenic_mac_local *lp) ++{ ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ unsigned int rate; ++ unsigned int div_val; ++ ++ rate = clk_get_rate(lp->clk_gate)/1000000; ++ if(rate > 250) ++ div_val = GmiiCsrClk5; ++ else if(rate > 150) ++ div_val = GmiiCsrClk4; ++ else if(rate > 100) ++ div_val = GmiiCsrClk1; ++ else if(rate > 60) ++ div_val = GmiiCsrClk0; ++ else if(rate > 35) ++ div_val = GmiiCsrClk3; ++ else if(rate > 20) ++ div_val = GmiiCsrClk2; ++ else ++ div_val = GmiiCsrClk5; ++ ++ synopGMAC_set_mdc_clk_div(gmacdev, div_val); ++ gmacdev->ClockDivMdc = synopGMAC_get_mdc_clk_div(gmacdev); ++} ++ ++static inline unsigned char str2hexnum(unsigned char c) ++{ ++ if (c >= '0' && c <= '9') ++ return c - '0'; ++ if (c >= 'a' && c <= 'f') ++ return c - 'a' + 10; ++ if (c >= 'A' && c <= 'F') ++ return c - 'A' + 10; ++ ++ return 0; /* foo */ ++} ++ ++static inline void str2eaddr(unsigned char *ea, unsigned char *str) ++{ ++ int i; ++ ++ for (i = 0; i < 6; i++) { ++ unsigned char num; ++ ++ if ((*str == '.') || (*str == ':')) ++ str++; ++ num = str2hexnum(*str++) << 4; ++ num |= str2hexnum(*str++); ++ ea[i] = num; ++ } ++} ++ ++static int bootargs_ethaddr[2] = {0,}; ++static unsigned char ethaddr_hex[2][6]; ++ ++static int __init ethernet_mac0_addr_setup(char *str) ++{ ++ if (!str) { ++ printk("ethaddr not set in command line\n"); ++ return -1; ++ } ++ bootargs_ethaddr[0] = 1; ++ str2eaddr(ethaddr_hex[0], str); ++ ++ return 0; ++} ++ ++static int __init ethernet_mac1_addr_setup(char *str) ++{ ++ if (!str) { ++ printk("ethaddr not set in command line\n"); ++ return -1; ++ } ++ bootargs_ethaddr[1] = 1; ++ str2eaddr(ethaddr_hex[1], str); ++ ++ return 0; ++} ++ ++__setup("ethaddr=", ethernet_mac0_addr_setup); ++__setup("ethaddr1=", ethernet_mac1_addr_setup); ++ ++ ++/* debug routines */ ++__attribute__((__unused__)) static void ingenic_mac_dump_pkt_data(unsigned char *data, int len) { ++ int i = 0; ++ printk("\t0x0000: "); ++ for (i = 0; i < len; i++) { ++ printk("%02x", data[i]); ++ ++ if (i % 2) ++ printk(" "); ++ ++ if ( (i != 0) && ((i % 16) == 15) ) ++ printk("\n\t0x%04x: ", i+1); ++ } ++ printk("\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_skb_data(struct sk_buff *skb) { ++ printk("\n\n===================================\n"); ++ printk("head = 0x%08x, data = 0x%08x, tail = 0x%08x, end = 0x%08x\n", ++ (unsigned int)(skb->head), (unsigned int)(skb->data), ++ (unsigned int)(skb->tail), (unsigned int)(skb->end)); ++ printk("len = %d\n", skb->len); ++ ingenic_mac_dump_pkt_data(skb->data, skb->len); ++ printk("\n=====================================\n"); ++} ++ ++struct ingenic_mac_reg ++{ ++ u32 addr; ++ char * name; ++}; ++ ++static struct ingenic_mac_reg mac[] = ++{ ++ { 0x0000, " Config" }, ++ { 0x0004, " Frame Filter" }, ++ { 0x0008, " MAC HT High" }, ++ { 0x000C, " MAC HT Low" }, ++ { 0x0010, " GMII Addr" }, ++ { 0x0014, " GMII Data" }, ++ { 0x0018, " Flow Control" }, ++ { 0x001C, " VLAN Tag" }, ++ { 0x0020, " GMAC Version" }, ++ { 0x0024, " GMAC Debug " }, ++ { 0x0028, "Remote Wake-Up Frame Filter" }, ++ { 0x002C, " PMT Control and Status" }, ++ { 0x0030, " LPI Control and status" }, ++ { 0x0034, " LPI Timers Control" }, ++ { 0x0038, " Interrupt Status" }, ++ { 0x003c, " Interrupt Mask" }, ++ { 0x0040, " MAC Addr0 High" }, ++ { 0x0044, " MAC Addr0 Low" }, ++ { 0x0048, " MAC Addr1 High" }, ++ { 0x004c, " MAC Addr1 Low" }, ++ { 0x0100, " MMC Ctrl Reg " }, ++ { 0x010c, " MMC Intr Msk(rx)" }, ++ { 0x0110, " MMC Intr Msk(tx)" }, ++ { 0x0200, " MMC Intr Msk(rx ipc)" }, ++ { 0x0700, " Timestamp control" }, ++ { 0x0704, " Sub-Second Increment" }, ++ { 0x0708, " Seconds" }, ++ { 0x070c, " Nanoseconds" }, ++ { 0x0710, " Update seconds" }, ++ { 0x0714, " Update Nanoseconds" }, ++ { 0x0718, " Adjust frequency" }, ++ { 0x0738, " AVMAC Ctrl Reg" }, ++ { 0x00D8, " RGMII C/S Reg" }, ++ { 0, 0 } ++}; ++static struct ingenic_mac_reg dma0[] = ++{ ++ { 0x0000, "[CH0] CSR0 Bus Mode" }, ++ { 0x0004, "[CH0] CSR1 TxPlDmnd" }, ++ { 0x0008, "[CH0] CSR2 RxPlDmnd" }, ++ { 0x000C, "[CH0] CSR3 Rx Base" }, ++ { 0x0010, "[CH0] CSR4 Tx Base" }, ++ { 0x0014, "[CH0] CSR5 Status" }, ++ { 0x0018, "[CH0] CSR6 Control" }, ++ { 0x001C, "[CH0] CSR7 Int Enable" }, ++ { 0x0020, "[CH0] CSR8 Missed Fr." }, ++ { 0x0028, "[CH0] CSR10 AXI Mode." }, ++ { 0x0024, "[CH0] Recv Intr Wd.Tm." }, ++ { 0x0028, "[CH0] AXI Bus Mode " }, ++ { 0x002c, "[CH0] AHB or AXI Status" }, ++ { 0x0048, "[CH0] CSR18 Tx Desc " }, ++ { 0x004C, "[CH0] CSR19 Rx Desc " }, ++ { 0x0050, "[CH0] CSR20 Tx Buffer" }, ++ { 0x0054, "[CH0] CSR21 Rx Buffer" }, ++ { 0x0058, "CSR22 HWCFG " }, ++ { 0, 0 } ++}; ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_dma_regs(synopGMACdevice *gmacdev, const char *func, int line) ++{ ++ struct ingenic_mac_reg *reg = dma0; ++ ++ printk("======================DMA Regs start===================\n"); ++ while(reg->name) { ++ printk("===>%s:\t0x%08x\n", reg->name, synopGMACReadReg((u32 *)gmacdev->DmaBase,reg->addr)); ++ reg++; ++ } ++ printk("======================DMA Regs end===================\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_mac_regs(synopGMACdevice *gmacdev, const char *func, int line) ++{ ++ struct ingenic_mac_reg *reg = mac; ++ ++ printk("======================MAC Regs start===================\n"); ++ while(reg->name) { ++ printk("===>%s:\t0x%08x\n", reg->name, synopGMACReadReg((u32 *)gmacdev->MacBase,reg->addr)); ++ reg++; ++ } ++ printk("======================MAC Regs end===================\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_all_regs(synopGMACdevice *gmacdev, const char *func, int line) { ++ ingenic_mac_dump_dma_regs(gmacdev, func, line); ++ ingenic_mac_dump_mac_regs(gmacdev, func, line); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_dma_buffer_info(struct ingenic_mac_buffer *buffer_info) { ++ printk("\tbuffer_info(%p):\n", buffer_info); ++ printk("\t\tskb = %p\n", buffer_info->skb); ++ printk("\t\tdma = 0x%08x\n", buffer_info->dma); ++ printk("\t\tlen = %u\n", buffer_info->length); ++ printk("\t\ttrans = %d\n", buffer_info->transfering); ++ printk("\t\tinvalid = %d\n", buffer_info->invalid); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_dma_desc(DmaDesc *desc) { ++ printk("\tdma desc(%p):\n", desc); ++ printk("\t\tstatus = 0x%08x\n", desc->status); ++ printk("\t\tbuffer1 = 0x%08x\n", desc->buffer1); ++ printk("\t\tlength = %u\n", desc->length); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_dma_desc2(DmaDesc *desc, struct ingenic_mac_buffer *buffer_info) { ++ printk("desc: %p, status: 0x%08x buf1: 0x%08x dma: 0x%08x len: %u bi: %p skb: %p trans: %d inv: %d\n", ++ desc, desc->status, desc->buffer1, buffer_info->dma, desc->length, ++ buffer_info, buffer_info->skb, buffer_info->transfering, buffer_info->invalid); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_rx_desc(struct ingenic_mac_local *lp) { ++ int i = 0; ++ printk("\n===================rx====================\n"); ++ printk("count = %d, next_to_use = %d next_to_clean = %d\n", ++ lp->rx_ring.count, lp->rx_ring.next_to_use, lp->rx_ring.next_to_clean); ++ for (i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->rx_ring.desc + i; ++ struct ingenic_mac_buffer *b = lp->rx_ring.buffer_info + i; ++ ++#if 0 ++ printk("desc %d:\n", i); ++ ingenic_mac_dump_dma_desc(desc); ++ ingenic_mac_dump_dma_buffer_info(b); ++#endif ++ ingenic_mac_dump_dma_desc2(desc, b); ++ } ++ printk("\n=========================================\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_tx_desc(struct ingenic_mac_local *lp) { ++ int i = 0; ++ printk("\n===================tx====================\n"); ++ printk("count = %d, next_to_use = %d next_to_clean = %d\n", ++ lp->tx_ring.count, lp->tx_ring.next_to_use, lp->tx_ring.next_to_clean); ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->tx_ring.desc + i; ++ struct ingenic_mac_buffer *b = lp->tx_ring.buffer_info + i; ++ ++#if 0 ++ printk("desc %d:\n", i); ++ ingenic_mac_dump_dma_desc(desc); ++ ingenic_mac_dump_dma_buffer_info(b); ++#endif ++ ingenic_mac_dump_dma_desc2(desc, b); ++ } ++ printk("\n=========================================\n"); ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_dump_all_desc(struct ingenic_mac_local *lp) { ++ ingenic_mac_dump_rx_desc(lp); ++ ingenic_mac_dump_tx_desc(lp); ++} ++ ++__attribute__((__unused__)) static int get_rx_index_by_desc(struct ingenic_mac_local *lp, DmaDesc *desc) { ++ int i = 0; ++ ++ for (i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ if ( (lp->rx_ring.desc + i) == desc) ++ return i; ++ } ++ ++ BUG_ON(i == INGENIC_MAC_RX_DESC_COUNT); ++ return -1; ++} ++ ++__attribute__((__unused__)) static void ingenic_mac_phy_dump(struct ingenic_mac_local *lp) { ++ u16 phy[] = {0, 1, 4, 5, 6, 9, 10, 15, 16, 17, 18, 20, 21, 24, 0x1c}; ++ ++ u16 data[sizeof(phy) / sizeof(u16)]; ++ int i; ++ ++ printk("\n-------->PHY dump: %08X\n", lp->phydev->phy_id); ++ for (i = 0; i < sizeof(phy) / sizeof(u16); i++) ++ data[i] = lp->mii_bus->read(lp->mii_bus, lp->phydev->mdio.addr, phy[i]); ++ ++ for (i = 0; i < sizeof(phy) / sizeof(u16); i++) ++ printk("PHY reg%d, value %04X\n", phy[i], data[i]); ++} ++ ++#ifdef CONFIG_INGENIC_GMAC_USE_HWSTAMP ++#define PTP_REF_FREQUENCY (50000000) ++#define PTP_CURRENT_FREQUENCY (75000000) ++#define ingenic_mac_hwtstamp_is_none(cfg) ((cfg) == HWTSTAMP_FILTER_NONE) ++static int ingenic_mac_hwtstamp_ioctl(struct net_device *netdev, ++ struct ifreq *ifr, int cmd) ++{ ++ struct hwtstamp_config config; ++ struct timespec64 curr_t; ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ ++ if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) ++ return -EFAULT; ++ ++ ++ /* reserved for future extensions */ ++ if (config.flags) ++ return -EINVAL; ++ ++ if ((config.tx_type != HWTSTAMP_TX_OFF) && ++ (config.tx_type != HWTSTAMP_TX_ON)) ++ return -ERANGE; ++ ++ switch (config.rx_filter) { ++ case HWTSTAMP_FILTER_NONE: ++ /* ++ * Dont allow any timestamping ++ */ ++ synopGMAC_TS_mac_addr_filt_enable(gmacdev); ++ synopGMAC_TS_all_frames_disable(gmacdev); ++ break; ++ case HWTSTAMP_FILTER_ALL: ++ /* ++ * time stamp any incoming packet ++ */ ++ synopGMAC_TS_mac_addr_filt_disable(gmacdev); ++ synopGMAC_TS_all_frames_enable(gmacdev); ++ break; ++ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: ++ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: ++ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: ++ synopGMAC_TS_pkt_snoop_ver1(gmacdev); ++ synopGMAC_TS_set_clk_type(gmacdev, GmacTSEtoEClk); ++ synopGMAC_TS_all_frames_disable(gmacdev); ++ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; ++ break; ++ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: ++ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: ++ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: ++ synopGMAC_TS_IPV4_enable(gmacdev); ++ synopGMAC_TS_pkt_snoop_ver2(gmacdev); ++ synopGMAC_TS_set_clk_type(gmacdev, GmacTSBouClk); ++ synopGMAC_TS_all_frames_disable(gmacdev); ++// synopGMAC_TS_ptp_over_ethernet_enable(gmacdev); ++ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; ++ break; ++ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: ++ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: ++ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: ++ synopGMAC_TS_all_frames_enable(gmacdev); ++ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; ++ break; ++ default: ++ return -ERANGE; ++ } ++ ++ if (config.tx_type == HWTSTAMP_TX_OFF && ++ ingenic_mac_hwtstamp_is_none(config.rx_filter)) { ++ synopGMAC_TS_disable(lp->gmacdev); ++ } else { ++ synopGMAC_multicast_enable(gmacdev); ++ synopGMAC_TS_disable(lp->gmacdev); ++ synopGMAC_TS_digital_rollover_enable(lp->gmacdev); ++ synopGMAC_TS_subsecond_init(lp->gmacdev, (1000000000ULL)/PTP_REF_FREQUENCY); ++ synopGMAC_TS_addend_update(lp->gmacdev, lp->ptp_addend); ++ synopGMAC_TS_enable(lp->gmacdev); ++ ktime_get_coarse_real_ts64(&curr_t); ++ synopGMAC_TS_timestamp_init(lp->gmacdev, curr_t.tv_sec, curr_t.tv_nsec); ++ } ++ ++ lp->stamp_cfg = config; ++ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? ++ -EFAULT : 0; ++} ++ ++void ingenic_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb, int index) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ struct ingenic_mac_tx_ring *tx_ring = &lp->tx_ring; ++ DmaDesc *desc; ++ ++ desc = INGENIC_MAC_TX_DESC(*tx_ring, index); ++ ++ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { ++ int timeout_cnt = MAX_TIMEOUT_CNT; ++ ++ /* When doing time stamping, keep the connection to the socket ++ * a while longer ++ */ ++ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; ++ ++ /* ++ * The timestamping is done at the EMAC module's MII/RMII interface ++ * when the module sees the Start of Frame of an event message packet. This ++ * interface is the closest possible place to the physical Ethernet transmission ++ * medium, providing the best timing accuracy. ++ */ ++ while ((synopGMAC_is_desc_owned_by_dma(desc)) && (--timeout_cnt)) ++ udelay(1); ++ if (timeout_cnt == 0) ++ netdev_err(netdev, "timestamp the TX packet failed\n"); ++ else { ++ struct skb_shared_hwtstamps shhwtstamps; ++ u32 nsec, sec; ++ nsec = desc->timestamplow; ++ sec = desc->timestamphigh; ++ memset(&shhwtstamps, 0, sizeof(shhwtstamps)); ++ shhwtstamps.hwtstamp = ktime_set(sec, nsec); ++ skb_tstamp_tx(skb, &shhwtstamps); ++ } ++ } ++} ++ ++static void ingenic_rx_hwtstamp(struct net_device *netdev, struct sk_buff *skb, int index) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ struct ingenic_mac_rx_ring *rx_ring = &lp->rx_ring; ++ struct skb_shared_hwtstamps *shhwtstamps; ++ DmaDesc *desc; ++ unsigned int nsec, sec; ++ ++ ++ if (ingenic_mac_hwtstamp_is_none(lp->stamp_cfg.rx_filter)) ++ return; ++ ++ desc = INGENIC_MAC_RX_DESC(*rx_ring, index); ++ if((desc->extstatus >> 8) & 0xf) { ++ shhwtstamps = skb_hwtstamps(skb); ++ nsec = desc->timestamplow; ++ sec = desc->timestamphigh; ++ memset(shhwtstamps, 0, sizeof(shhwtstamps)); ++ shhwtstamps->hwtstamp = ktime_set(sec, nsec); ++ } ++} ++ ++static int ingenic_mac_hwtstamp_init(struct net_device *netdev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ struct platform_device *pdev = lp->pdev; ++ u64 addend; ++ int err; ++ ++ lp->cgu_ptp = devm_clk_get(&pdev->dev, "div_macptp"); ++ if (IS_ERR(lp->cgu_ptp)) { ++ err = PTR_ERR(lp->cgu_ptp); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__,"cgu_ptp"); ++ return err; ++ } ++ ++ if ((err = clk_prepare_enable(lp->cgu_ptp)) < 0) { ++ dev_err(&pdev->dev, "Enable gmac ptp clk failed\n"); ++ return err; ++ } ++ if((err = clk_set_rate(lp->cgu_ptp, PTP_CURRENT_FREQUENCY)) < 0) { ++ dev_err(&pdev->dev, "Set cgu_ptp clk rate faild\n"); ++ return err; ++ } ++ ++ lp->ptp_freq = clk_get_rate(lp->cgu_ptp); ++ dev_info(&pdev->dev, "ptp clock frequency = %d\n", lp->ptp_freq); ++ ++ addend = (1ULL << 32) * (PTP_REF_FREQUENCY); ++ lp->ptp_addend = div_u64(addend, lp->ptp_freq); ++ ++ ++ /* Initialize hwstamp config */ ++ lp->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE; ++ lp->stamp_cfg.tx_type = HWTSTAMP_TX_OFF; ++ ++ return 0; ++} ++ ++/* PTP Hardware Clock operations */ ++static int ingenic_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) ++{ ++ u64 adj, mult; ++ u64 addend; ++ u32 diff; ++ int neg_adj = 0; ++ unsigned long flags; ++ int ret = 0; ++ struct ingenic_mac_local *lp = ++ container_of(ptp, struct ingenic_mac_local, caps); ++ ++ if (ppb < 0) { ++ neg_adj = 1; ++ ppb = -ppb; ++ } ++ mult = lp->ptp_addend; ++ adj = mult; ++ adj *= ppb; ++ diff = div_u64(adj, 1000000000ULL); ++ addend = neg_adj ? mult - diff : mult + diff; ++ if(addend > 0xffffffff) { ++ printk("gmac ptp addend out of range\n"); ++ return 0; ++ } ++ spin_lock_irqsave(&lp->phc_lock, flags); ++ synopGMAC_TS_fine_update(lp->gmacdev); ++ ret = synopGMAC_TS_addend_update(lp->gmacdev, addend); ++ spin_unlock_irqrestore(&lp->phc_lock, flags); ++ ++ return ret; ++} ++ ++static int ingenic_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) ++{ ++ unsigned long flags; ++ struct ingenic_mac_local *lp = ++ container_of(ptp, struct ingenic_mac_local, caps); ++ u32 nsec, sec; ++ u16 hsec; ++ ++ spin_lock_irqsave(&lp->phc_lock, flags); ++ synopGMAC_TS_read_timestamp(lp->gmacdev, &hsec, &sec, &nsec); ++ ts->tv_sec = sec; ++ ts->tv_nsec = nsec; ++ spin_unlock_irqrestore(&lp->phc_lock, flags); ++ ++ return 0; ++} ++ ++static int ingenic_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) ++{ ++ unsigned long flags; ++ unsigned long fine; ++ struct ingenic_mac_local *lp = ++ container_of(ptp, struct ingenic_mac_local, caps); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int ret; ++ ++ struct timespec64 ts = ns_to_timespec64(delta); ++ ++ spin_lock_irqsave(&lp->phc_lock, flags); ++ fine = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacTSControl) & GmacTSCFUPDT; ++ synopGMAC_TS_coarse_update(gmacdev); ++ if(ts.tv_sec < 0) { ++ ret = synopGMAC_TS_timestamp_update(gmacdev, ts.tv_sec*(-1), 0x80000000); ++ ret = synopGMAC_TS_timestamp_update(gmacdev, 0, ts.tv_nsec); ++ } else ++ ret = synopGMAC_TS_timestamp_update(gmacdev, ts.tv_sec, ts.tv_nsec); ++ if(fine) ++ synopGMAC_TS_fine_update(gmacdev); ++ spin_unlock_irqrestore(&lp->phc_lock, flags); ++ ++ return ret; ++} ++ ++ ++static int ingenic_ptp_settime(struct ptp_clock_info *ptp, ++ const struct timespec64 *ts) ++{ ++ unsigned long flags; ++ u32 nsec = ts->tv_nsec; ++ u32 sec = (u32)ts->tv_sec; ++ int ret; ++ struct ingenic_mac_local *lp = ++ container_of(ptp, struct ingenic_mac_local, caps); ++ ++ spin_lock_irqsave(&lp->phc_lock, flags); ++ ret = synopGMAC_TS_timestamp_init(lp->gmacdev, sec, nsec); ++ spin_unlock_irqrestore(&lp->phc_lock, flags); ++ ++ return ret; ++} ++ ++static int ingenic_ptp_enable(struct ptp_clock_info *ptp, ++ struct ptp_clock_request *rq, int on) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static struct ptp_clock_info ingenic_ptp_caps = { ++ .owner = THIS_MODULE, ++ .name = "ingenic ptp", ++ .max_adj = 500000000, ++ .n_alarm = 0, ++ .n_ext_ts = 0, ++ .n_per_out = 0, ++ .pps = 0, ++ .adjfreq = ingenic_ptp_adjfreq, ++ .adjtime = ingenic_ptp_adjtime, ++ .gettime64 = ingenic_ptp_gettime, ++ .settime64 = ingenic_ptp_settime, ++ .enable = ingenic_ptp_enable, ++}; ++ ++static int ingenic_phc_init(struct net_device *netdev, struct device *dev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ int ret; ++ ++ lp->caps = ingenic_ptp_caps; ++ ret = ingenic_mac_hwtstamp_init(netdev); ++ if(ret) ++ return ret; ++ ++ lp->clock = ptp_clock_register(&lp->caps, dev); ++ if (IS_ERR(lp->clock)) ++ return PTR_ERR(lp->clock); ++ ++ lp->phc_index = ptp_clock_index(lp->clock); ++ spin_lock_init(&lp->phc_lock); ++ ++ return 0; ++} ++ ++static void ingenic_phc_release(struct ingenic_mac_local *lp) ++{ ++ struct platform_device *pdev = lp->pdev; ++ devm_clk_put(&pdev->dev, lp->cgu_ptp); ++ ptp_clock_unregister(lp->clock); ++} ++ ++static int ingenic_mac_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ ++ if(lp->clock) { ++ info->phc_index = ptp_clock_index(lp->clock); ++ } else { ++ info->phc_index = -1; ++ } ++ ++ info->so_timestamping = ++ SOF_TIMESTAMPING_TX_HARDWARE | ++ SOF_TIMESTAMPING_RX_HARDWARE | ++ SOF_TIMESTAMPING_RAW_HARDWARE; ++ ++ info->tx_types = ++ (1 << HWTSTAMP_TX_OFF) | ++ (1 << HWTSTAMP_TX_ON); ++ ++ info->rx_filters = ++ (1 << HWTSTAMP_FILTER_NONE) | ++ (1 << HWTSTAMP_FILTER_ALL) | ++ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | ++ (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | ++ (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT); ++ ++ ++ return 0; ++} ++ ++#else ++# define ingenic_mac_hwtstamp_is_none(cfg) 0 ++# define ingenic_mac_hwtstamp_init(ndev) ++# define ingenic_mac_hwtstamp_ioctl(netdev, ifr, cmd) (-EOPNOTSUPP) ++# define ingenic_rx_hwtstamp(netdev, skb, rx_desc_i) ++# define ingenic_tx_hwtstamp(netdev, skb, first) ++# define ingenic_phc_init(ndev, dev) ++# define ingenic_phc_release(lp) ++#endif ++ ++#if 0 ++static void ingenic_start_rx_coalesce_timer(struct ingenic_mac_local *lp) ++{ ++ unsigned long ns = lp->rx_coalesce_usecs * NSEC_PER_USEC / 2; ++ ++ /* allow timer to fire after half the time at the earliest */ ++ hrtimer_start_range_ns(&lp->rx_coalesce_timer, ns_to_ktime(ns), ++ ns, HRTIMER_MODE_PINNED); ++} ++ ++enum hrtimer_restart ingenic_rx_coalesce_timer_done(struct hrtimer *hrtimer) ++{ ++ struct ingenic_mac_local *lp; ++ synopGMACdevice *gmacdev; ++ u32 data; ++ ++ lp = container_of(hrtimer, struct ingenic_mac_local, rx_coalesce_timer); ++ gmacdev = lp->gmacdev; ++ ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus); ++ data &= DmaIntRxNormMask; ++ if(data && napi_schedule_prep(&lp->napi)) { ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaStatus, data); ++ __napi_schedule(&lp->napi); ++ } else { ++ synopGMAC_enable_interrupt(gmacdev, DmaIntEnable); ++ } ++ ++ return HRTIMER_NORESTART; ++} ++#endif ++ ++static void ingenic_start_tx_coalesce_timer(struct ingenic_mac_local *lp) ++{ ++ unsigned long ns = lp->tx_coalesce_usecs * NSEC_PER_USEC / 2; ++ ++ /* allow timer to fire after half the time at the earliest */ ++ hrtimer_start_range_ns(&lp->tx_coalesce_timer, ns_to_ktime(ns), ++ ns, HRTIMER_MODE_REL); ++} ++ ++enum hrtimer_restart ingenic_tx_coalesce_timer_done(struct hrtimer *hrtimer) ++{ ++ struct ingenic_mac_tx_ring *tx_ring; ++ struct ingenic_mac_local *lp; ++ unsigned long ns; ++ int tx_num; ++ ++ lp = container_of(hrtimer, struct ingenic_mac_local, tx_coalesce_timer); ++ ns = lp->tx_coalesce_usecs * NSEC_PER_USEC / 2; ++ tx_ring = &lp->tx_ring; ++ ++ tx_num = ingenic_mac_clean_tx_irq(lp); ++ ++ if(unlikely(INGENIC_MAC_DESC_UNUSED(tx_ring) < (tx_ring->count-1))) { ++ hrtimer_start_range_ns(&lp->tx_coalesce_timer, ns_to_ktime(ns), ++ ns, HRTIMER_MODE_REL); ++ } ++ return HRTIMER_NORESTART; ++} ++ ++static void ingenic_mac_restart_rx_dma(struct ingenic_mac_local *lp) { ++ synopGMAC_enable_dma_rx(lp->gmacdev); ++} ++ ++static void ingenic_mac_alloc_rx_buffers(struct ingenic_mac_local *lp, int cleaned_count, ++ int restart_dma) { ++ int i = 0; ++ struct ingenic_mac_buffer *buffer_info; ++ struct sk_buff *skb; ++ struct ingenic_mac_rx_ring *rx_ring = &lp->rx_ring; ++ DmaDesc *rx_desc; ++ ++ i = rx_ring->next_to_use; ++ rx_desc = INGENIC_MAC_RX_DESC(*rx_ring, i); ++ buffer_info = &rx_ring->buffer_info[i]; ++ ++ while (cleaned_count--) { ++ skb = buffer_info->skb; ++ if (skb) { ++ skb_trim(skb, 0); ++ goto map_skb; ++ } ++ ++ if(lp->id == 0) ++ skb = napi_alloc_skb(&lp->napi, lp->netdev->mtu + ETHERNET_HEADER + ETHERNET_CRC); ++ else ++ skb = netdev_alloc_skb_ip_align(lp->netdev, lp->netdev->mtu + ETHERNET_HEADER + ETHERNET_CRC); ++ if (unlikely(!skb)) { ++ /* Better luck next round */ ++ lp->alloc_rx_buff_failed++; ++ break; ++ } ++ ++ buffer_info->skb = skb; ++ buffer_info->length = skb_tailroom(skb); ++map_skb: ++ buffer_info->dma = dma_map_single(&lp->netdev->dev, ++ skb->data, skb_tailroom(skb), ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(&lp->netdev->dev, buffer_info->dma)) { ++ dev_err(&lp->netdev->dev, "Rx DMA map failed\n"); ++ lp->alloc_rx_buff_failed++; ++ break; ++ } ++ ++ rx_desc->length |= ((skb_tailroom(skb) <buffer1 = cpu_to_le32(buffer_info->dma); ++ ++ /* clr invalid first, then start transfer */ ++ buffer_info->invalid = 0; ++ ++ /* start transfer */ ++ rx_desc->status = DescOwnByDma | DescRxEXTsts; ++ ++ /* next */ ++ if (unlikely(++i == rx_ring->count)) ++ i = 0; ++ ++ wmb(); ++ ++ rx_desc = INGENIC_MAC_RX_DESC(*rx_ring, i); ++ buffer_info = &rx_ring->buffer_info[i]; ++ } ++ ++ if (likely(rx_ring->next_to_use != i)) { ++ rx_ring->next_to_use = i; ++ /* sanity check: ensure next_to_use is not used */ ++ rx_desc->status &= ~DescOwnByDma; ++ buffer_info->invalid = 1; ++ wmb(); ++ ++ /* assure that if there's any buffer space, dma is enabled */ ++ if (likely(restart_dma)) ++ ingenic_mac_restart_rx_dma(lp); ++ } ++} ++ ++static int desc_list_init_rx(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int i; ++ int size; ++ ++ /* rx init */ ++ lp->rx_ring.count = INGENIC_MAC_RX_DESC_COUNT; ++ ++ size = lp->rx_ring.count * sizeof(struct ingenic_mac_buffer); ++ lp->rx_ring.buffer_info = vmalloc(size); ++ if (!lp->rx_ring.buffer_info) { ++ printk(KERN_ERR "Unable to allocate memory for the receive descriptor ring\n"); ++ return -ENOMEM; ++ } ++ memset(lp->rx_ring.buffer_info, 0, size); ++ ++ lp->rx_ring.desc = dma_alloc_noncoherent(&lp->netdev->dev, ++ lp->rx_ring.count * sizeof(DmaDesc), ++ &lp->rx_ring.dma, DMA_BIDIRECTIONAL, GFP_KERNEL); ++ ++ if (lp->rx_ring.desc == NULL) { ++ vfree(lp->rx_ring.buffer_info); ++ lp->rx_ring.buffer_info = NULL; ++ return -ENOMEM; ++ } ++ ++ dma_cache_wback_inv((unsigned long)lp->rx_ring.desc, ++ lp->rx_ring.count * sizeof(DmaDesc)); ++ ++ /* we always use uncached address for descriptors */ ++ lp->rx_ring.desc = (DmaDesc *)CKSEG1ADDR(lp->rx_ring.desc); ++ ++ for (i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->rx_ring.desc + i; ++ ++ synopGMAC_rx_desc_init_ring(desc, i == (INGENIC_MAC_RX_DESC_COUNT - 1)); ++ } ++ ++ lp->rx_ring.next_to_use = lp->rx_ring.next_to_clean = 0; ++ ingenic_mac_alloc_rx_buffers(lp, INGENIC_MAC_DESC_UNUSED(&lp->rx_ring), 0); ++ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase,DmaRxBaseAddr, lp->rx_ring.dma); ++ ++ return 0; ++} ++ ++static void desc_list_free_rx(struct ingenic_mac_local *lp) { ++ struct ingenic_mac_buffer *b; ++ int i = 0; ++ ++ if (lp->rx_ring.desc) ++ dma_free_noncoherent(&lp->netdev->dev, ++ lp->rx_ring.count * sizeof(DmaDesc), ++ (void *)CKSEG0ADDR(lp->rx_ring.desc), ++ lp->rx_ring.dma, DMA_BIDIRECTIONAL); ++ ++ if (lp->rx_ring.buffer_info) { ++ b = lp->rx_ring.buffer_info; ++ ++ for(i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ if (b[i].skb) { ++ if (b[i].dma) { ++ dma_unmap_single(&lp->netdev->dev, b[i].dma, ++ b[i].length, DMA_FROM_DEVICE); ++ b[i].dma = 0; ++ } ++ ++ dev_kfree_skb_any(b[i].skb); ++ b[i].skb = NULL; ++ b[i].time_stamp = 0; ++ } ++ } ++ } ++ vfree(lp->rx_ring.buffer_info); ++ lp->rx_ring.buffer_info = NULL; ++ lp->rx_ring.next_to_use = lp->rx_ring.next_to_clean = 0; ++} ++ ++/* must be called from interrupt handler */ ++static void ingenic_mac_take_desc_ownership_rx(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int i = 0; ++ ++ /* must called with interrupts disabled */ ++ BUG_ON(synopGMAC_get_interrupt_mask(gmacdev)); ++ ++ for (i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->rx_ring.desc + i; ++ struct ingenic_mac_buffer *b = lp->rx_ring.buffer_info + i; ++ ++ if (!b->invalid) { ++ synopGMAC_take_desc_ownership(desc); ++ } ++ } ++ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase,DmaRxBaseAddr, lp->rx_ring.dma); ++} ++ ++/* MUST ensure that rx is stopped ans rx_dma is disabled */ ++static void desc_list_reinit_rx(struct ingenic_mac_local *lp) { ++ DmaDesc *desc; ++ int i = 0; ++ ++ //TODO: BUG_ON(!ingenic_mac_rx_dma_stopped()); ++ ++ for (i = 0; i < INGENIC_MAC_RX_DESC_COUNT; i++) { ++ desc = lp->rx_ring.desc + i; ++ ++ /* owned by DMA, can fill data */ ++ synopGMAC_rx_desc_init_ring(desc, i == (INGENIC_MAC_RX_DESC_COUNT - 1)); ++ } ++ ++ lp->rx_ring.next_to_use = lp->rx_ring.next_to_clean = 0; ++ ingenic_mac_alloc_rx_buffers(lp, INGENIC_MAC_DESC_UNUSED(&lp->rx_ring), 0); ++ ++ synopGMACWriteReg((u32 *)lp->gmacdev->DmaBase,DmaRxBaseAddr, lp->rx_ring.dma); ++} ++ ++static int desc_list_init_tx(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int i; ++ int size; ++ ++ /* tx init */ ++ lp->tx_ring.count = INGENIC_MAC_TX_DESC_COUNT; ++ ++ size = lp->tx_ring.count * sizeof(struct ingenic_mac_buffer); ++ lp->tx_ring.buffer_info = vmalloc(size); ++ if (!lp->tx_ring.buffer_info) { ++ printk(KERN_ERR"Unable to allocate memory for the receive descriptor ring\n"); ++ return -ENOMEM; ++ } ++ memset(lp->tx_ring.buffer_info, 0, size); ++ ++ lp->tx_ring.desc = dma_alloc_noncoherent(&lp->netdev->dev, ++ lp->tx_ring.count * sizeof(DmaDesc), ++ &lp->tx_ring.dma, DMA_BIDIRECTIONAL, GFP_KERNEL); ++ ++ if (lp->tx_ring.desc == NULL) { ++ vfree(lp->tx_ring.buffer_info); ++ lp->tx_ring.buffer_info = NULL; ++ return -ENOMEM; ++ } ++ ++ dma_cache_wback_inv((unsigned long)lp->tx_ring.desc, ++ lp->tx_ring.count * sizeof(DmaDesc)); ++ ++ /* we always use uncached address for descriptors */ ++ lp->tx_ring.desc = (DmaDesc *)CKSEG1ADDR(lp->tx_ring.desc); ++ ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->tx_ring.desc + i; ++ ++ synopGMAC_tx_desc_init_ring(desc, i == (INGENIC_MAC_TX_DESC_COUNT - 1)); ++ } ++ ++ lp->tx_ring.next_to_use = lp->tx_ring.next_to_clean = 0; ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase,DmaTxBaseAddr,(u32)lp->tx_ring.dma); ++ return 0; ++} ++ ++__attribute__((__unused__)) static int get_tx_index_by_desc(struct ingenic_mac_local *lp, DmaDesc *desc) { ++ int i = 0; ++ ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ if ( (lp->tx_ring.desc + i) == desc) ++ return i; ++ } ++ ++ BUG_ON(i == INGENIC_MAC_TX_DESC_COUNT); ++ return -1; ++} ++ ++static void ingenic_mac_unmap_and_free_tx_resource(struct ingenic_mac_local *lp, ++ struct ingenic_mac_buffer *buffer_info) ++{ ++ buffer_info->transfering = 0; ++ ++ if (buffer_info->skb) { ++ if (buffer_info->dma) { ++ if (buffer_info->mapped_as_page) ++ dma_unmap_page(&lp->netdev->dev, buffer_info->dma, ++ buffer_info->length, DMA_TO_DEVICE); ++ else ++ dma_unmap_single(&lp->netdev->dev, buffer_info->dma, ++ buffer_info->length, DMA_TO_DEVICE); ++ buffer_info->dma = 0; ++ } ++ dev_kfree_skb_any(buffer_info->skb); ++ buffer_info->skb = NULL; ++ } ++ buffer_info->time_stamp = 0; ++} ++ ++static void desc_list_free_tx(struct ingenic_mac_local *lp) { ++ struct ingenic_mac_buffer *b; ++ int i = 0; ++ ++ if (lp->tx_ring.desc) ++ dma_free_noncoherent(&lp->netdev->dev, ++ lp->tx_ring.count * sizeof(DmaDesc), ++ (void *)CKSEG0ADDR(lp->tx_ring.desc), ++ lp->tx_ring.dma, DMA_BIDIRECTIONAL); ++ ++ if (lp->tx_ring.buffer_info) { ++ b = lp->tx_ring.buffer_info; ++ ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ // panic("===>ahha, testing! please do not goes here(%s:%d)!!!\n", __func__, __LINE__); ++ ingenic_mac_unmap_and_free_tx_resource(lp, b + i); ++ } ++ ++ } ++ vfree(lp->tx_ring.buffer_info); ++ lp->tx_ring.buffer_info = NULL; ++ lp->tx_ring.next_to_use = lp->tx_ring.next_to_clean = 0; ++} ++ ++/* must called in interrupt handler */ ++static void ingenic_mac_take_desc_ownership_tx(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int i = 0; ++ ++ /* must called with interrupts disabled */ ++ BUG_ON(synopGMAC_get_interrupt_mask(gmacdev)); ++ ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ DmaDesc *desc = lp->tx_ring.desc + i; ++ struct ingenic_mac_buffer *b = lp->tx_ring.buffer_info + i; ++ ++ if (!b->invalid) { ++ synopGMAC_take_desc_ownership(desc); ++ } ++ } ++} ++ ++/* must assure that tx transfer are stopped and tx_dma is disabled */ ++static void desc_list_reinit_tx(struct ingenic_mac_local *lp) { ++ int i = 0; ++ DmaDesc *desc; ++ struct ingenic_mac_buffer *b; ++ ++ //TODO: BUG_ON(!ingenic_mac_tx_dma_stopped()); ++ ++ for (i = 0; i < INGENIC_MAC_TX_DESC_COUNT; i++) { ++ desc = lp->tx_ring.desc + i; ++ b = lp->tx_ring.buffer_info + i; ++ ++ /* owned by CPU, no valid data */ ++ synopGMAC_tx_desc_init_ring(desc, i == (INGENIC_MAC_TX_DESC_COUNT - 1)); ++ ++ ingenic_mac_unmap_and_free_tx_resource(lp, b); ++ } ++ ++ lp->tx_ring.next_to_use = lp->tx_ring.next_to_clean = 0; ++} ++ ++static void desc_list_free(struct ingenic_mac_local *lp) ++{ ++ desc_list_free_rx(lp); ++ desc_list_free_tx(lp); ++} ++ ++static void desc_list_reinit(struct ingenic_mac_local *lp) { ++ desc_list_reinit_rx(lp); ++ desc_list_reinit_tx(lp); ++} ++ ++static int desc_list_init(struct ingenic_mac_local *lp) ++{ ++ if (desc_list_init_rx(lp) < 0) ++ goto init_error; ++ ++ if (desc_list_init_tx(lp) < 0) ++ goto init_error; ++ ++ return 0; ++ ++init_error: ++ desc_list_free(lp); ++ printk(KERN_ERR INGENIC_MAC_DRV_NAME ": kmalloc failed\n"); ++ return -ENOMEM; ++} ++ ++static int ingenic_gmac_clk_set_rate(struct ingenic_mac_local *lp, unsigned int rate) ++{ ++ struct clk *clk = lp->clk_tx; ++ struct clk *parent = NULL; ++ unsigned int prate = 0; ++ ++ ++ if(rate <= 2500000) { ++ /*set parent to EPLL*/ ++ parent = clk_get(NULL, "epll"); ++ prate = clk_get_rate(parent); ++ ++ if((prate % rate) || ((prate / rate) > 256)) { ++ if(netif_msg_link(lp)){ ++ printk("WARNING, can not set rate:%d epll rate is:%d\n", rate, prate); ++ printk("set macphy parent rate epll 300M \n"); ++ } ++ clk_set_rate(parent, 300000000); ++ } ++ ++ clk_set_parent(clk_get_parent(clk), parent); ++ clk_set_rate(clk, rate); ++ } else { ++ parent = clk_get_parent(clk); ++ prate = clk_get_rate(parent); ++ ++ if((prate % rate) || ((prate / rate) > 256)) { ++ if(netif_msg_link(lp)){ ++ printk("WARNING, can not set rate:%d parent rate is:%d\n", rate, prate); ++ printk("set macphy parent is mpll\n"); ++ } ++ parent = clk_get(NULL, "mpll"); ++ prate = clk_get_rate(parent); ++ clk_set_parent(clk_get_parent(clk), parent); ++ if((prate % rate) || ((prate / rate) > 256)) { ++ printk("### ERROR, %s %s %d\n", __FILE__, __func__, __LINE__); ++ printk("### ERROR, mpll rate is:%d can not set rate:%d\n", prate, rate); ++ printk("### ERROR, please check out mpll, then set an appropriate value\n"); ++ } ++ } ++ ++ clk_set_rate(clk, rate); ++ } ++ ++ return 0; ++} ++ ++static void ingenic_mac_set_rx_flowcontrol(struct ingenic_mac_local *lp, bool enable) ++{ ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&lp->hw_lock, flags); ++ ++ if (enable){ ++ synopGMAC_rx_flow_control_enable(gmacdev); ++ }else{ ++ synopGMAC_rx_flow_control_disable(gmacdev); ++ } ++ spin_unlock_irqrestore(&lp->hw_lock, flags); ++} ++ ++static void ingenic_mac_set_tx_flowcontrol(struct ingenic_mac_local *lp, bool enable) ++{ ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&lp->hw_lock, flags); ++ ++ if (enable){ ++ synopGMAC_tx_flow_control_enable(gmacdev); ++ }else{ ++ synopGMAC_tx_flow_control_disable(gmacdev); ++ } ++ spin_unlock_irqrestore(&lp->hw_lock, flags); ++} ++ ++/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/ ++static void ingenic_mac_adjust_link(struct net_device *dev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ struct phy_device *phydev = lp->phydev; ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ unsigned long flags; ++ int new_state = 0; ++ ++ if (netif_msg_link(lp)){ ++ printk("===>ajust link, new_duplex = %d, new_speed = %d, new_link = %d phydev->link = %d phydev->state = %d\n",\ ++ lp->old_duplex, lp->old_speed, lp->old_link, phydev->link, phydev->state); ++ } ++ ++ spin_lock_irqsave(&lp->link_lock, flags); ++ ++ if (phydev->link) { ++ /* Now we make sure that we can be in full duplex mode. ++ * If not, we operate in half-duplex mode. */ ++ if (phydev->duplex != lp->old_duplex) { ++ new_state = 1; ++ lp->old_duplex = phydev->duplex; ++ } ++ ++ if (phydev->speed != lp->old_speed) { ++ new_state = 1; ++ lp->old_speed = phydev->speed; ++ } ++ ++ if (phydev->duplex) { ++ synopGMAC_set_full_duplex(gmacdev); ++ //synopGMAC_rx_own_enable(gmacdev); ++ //synopGMAC_set_Inter_Frame_Gap(gmacdev, GmacInterFrameGap7); ++ } else { ++ synopGMAC_set_half_duplex(gmacdev); ++ //synopGMAC_rx_own_disable(gmacdev); ++ //synopGMAC_set_Inter_Frame_Gap(gmacdev, GmacInterFrameGap4); ++ } ++ ++ switch (phydev->speed) { ++ case 1000: ++ synopGMAC_select_speed1000(gmacdev); ++ if(lp->interface == RGMII) ++ ingenic_gmac_clk_set_rate(lp, 125000000); ++ break; ++ case 100: ++ synopGMAC_select_speed100(gmacdev); ++ if(lp->interface == RGMII) ++ ingenic_gmac_clk_set_rate(lp, 25000000); ++ break; ++ case 10: ++ synopGMAC_select_speed10(gmacdev); ++ if(lp->interface == RGMII) ++ ingenic_gmac_clk_set_rate(lp, 2500000); ++ break; ++ default: ++ printk(KERN_ERR "GMAC PHY speed NOT match!\n"); ++ synopGMAC_select_speed100(gmacdev); ++ } ++ ++ if (lp->flowcontrol.autoneg) { ++ lp->flowcontrol.rx = phydev->pause || ++ phydev->asym_pause; ++ lp->flowcontrol.tx = phydev->pause || ++ phydev->asym_pause; ++ } ++ ++ if(lp->flowcontrol.rx || lp->flowcontrol.tx){ ++ phydev->pause = 1; ++ }else{ ++ phydev->pause = 0; ++ } ++ ++ if (lp->flowcontrol.rx != lp->flowcontrol.rx_current) { ++ if (netif_msg_link(lp)) ++ printk("set rx flow to %d\n",lp->flowcontrol.rx); ++ ingenic_mac_set_rx_flowcontrol(lp, lp->flowcontrol.rx); ++ lp->flowcontrol.rx_current = lp->flowcontrol.rx; ++ } ++ if (lp->flowcontrol.tx != lp->flowcontrol.tx_current) { ++ if (netif_msg_link(lp)) ++ printk("set tx flow to %d\n",lp->flowcontrol.tx); ++ ingenic_mac_set_tx_flowcontrol(lp, lp->flowcontrol.tx); ++ lp->flowcontrol.tx_current = lp->flowcontrol.tx; ++ } ++ ++ ++ if (!lp->old_link) { ++ new_state = 1; ++ lp->old_link = 1; ++ netif_carrier_on(dev); ++ } ++ } else if (lp->old_link) { ++ new_state = 1; ++ lp->old_link = 0; ++ lp->old_speed = 0; ++ lp->old_duplex = -1; ++ netif_carrier_off(dev); ++ } ++ ++ if (new_state) ++ phy_print_status(phydev); ++ ++ if (netif_msg_link(lp)){ ++ printk("===>ajust link, new_duplex = %d, new_speed = %d, new_link = %d phydev->link = %d phydev->state = %d\n",\ ++ lp->old_duplex, lp->old_speed, lp->old_link, phydev->link, phydev->state); ++ } ++ ++ spin_unlock_irqrestore(&lp->link_lock, flags); ++ ++} ++ ++/*half speed features*/ ++static const int half_speed_features_array[] = { ++ ++ ETHTOOL_LINK_MODE_10baseT_Half_BIT, ++ ETHTOOL_LINK_MODE_100baseT_Half_BIT, ++ ETHTOOL_LINK_MODE_1000baseT_Half_BIT, ++}; ++/*full speed features*/ ++static const int full_speed_features_array[] = { ++ ++ ETHTOOL_LINK_MODE_10baseT_Full_BIT, ++ ETHTOOL_LINK_MODE_100baseT_Full_BIT, ++ ETHTOOL_LINK_MODE_1000baseT_Full_BIT, ++}; ++/*autoneg features*/ ++static const int autoneg_features_array[] = { ++ ++ ETHTOOL_LINK_MODE_Autoneg_BIT, ++}; ++/*pause features*/ ++static const int pause_features_array[] = { ++ ++ ETHTOOL_LINK_MODE_Pause_BIT, ++ ETHTOOL_LINK_MODE_Asym_Pause_BIT, ++}; ++/*physics interface features*/ ++static const int physics_interface_features_array[] = { ++ ++ ETHTOOL_LINK_MODE_TP_BIT, ++ //ETHTOOL_LINK_MODE_AUI_BIT, ++ ETHTOOL_LINK_MODE_MII_BIT, ++ //ETHTOOL_LINK_MODE_FIBRE_BIT, ++ //ETHTOOL_LINK_MODE_BNC_BIT, ++}; ++ ++__ETHTOOL_DECLARE_LINK_MODE_MASK(local_supported) __ro_after_init; ++__ETHTOOL_DECLARE_LINK_MODE_MASK(local_advertising) __ro_after_init; ++ ++static inline void linkmode_clear_bit_array(const int *array, int array_size, unsigned long *addr) ++{ ++ int i; ++ for (i = 0; i < array_size; i++) ++ linkmode_clear_bit(array[i], addr); ++} ++ ++static int mii_probe(struct net_device *dev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ struct phy_device *phydev = NULL; ++ int phy_interface; ++ ++ phydev = phy_find_first(lp->mii_bus); ++ if (!phydev) { ++ printk(KERN_ERR "%s: no PHY found\n", dev->name); ++ return -ENXIO; ++ } ++ ++ if(lp->interface == RMII) ++ phy_interface = PHY_INTERFACE_MODE_RMII; ++ else if(lp->interface == RGMII) ++ phy_interface = PHY_INTERFACE_MODE_RGMII; ++ else if(lp->interface == GMII) ++ phy_interface = PHY_INTERFACE_MODE_GMII; ++ else ++ phy_interface = PHY_INTERFACE_MODE_MII; ++ ++ phydev = phy_connect(dev, dev_name(&phydev->mdio.dev), &ingenic_mac_adjust_link, ++ phy_interface); ++ if (IS_ERR(phydev)) { ++ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); ++ return PTR_ERR(phydev); ++ } ++ ++ ++ /* Add features not supported by driver*/ ++ linkmode_zero(local_supported); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, local_supported); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, local_supported); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, local_supported); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, local_supported); ++ linkmode_or(phydev->supported, phydev->supported, local_supported); ++ ++ /* Mask with MAC supported features */ ++ linkmode_zero(local_supported); ++ linkmode_set_bit_array(half_speed_features_array, ARRAY_SIZE(half_speed_features_array), local_supported); ++ linkmode_set_bit_array(full_speed_features_array, ARRAY_SIZE(full_speed_features_array), local_supported); ++ linkmode_set_bit_array(autoneg_features_array, ARRAY_SIZE(autoneg_features_array), local_supported); ++ linkmode_set_bit_array(pause_features_array, ARRAY_SIZE(pause_features_array), local_supported); ++ linkmode_set_bit_array(physics_interface_features_array, ARRAY_SIZE(physics_interface_features_array), local_supported); ++ linkmode_and(phydev->supported, phydev->supported, local_supported); ++ ++ /* Configure the advertising feature according to the supported feature*/ ++ linkmode_copy(phydev->advertising, phydev->supported); ++ ++ /* Remove any features not supported by the controller */ ++ phy_set_max_speed(phydev, SPEED_1000); ++ phy_support_asym_pause(phydev); ++ ++ phy_attached_info(phydev); ++ ++ /*setting dts force gmac configure*/ ++ if(lp->dts_ctl.force){ ++ ++ /*1.dts autoneg configuration*/ ++ if(lp->dts_ctl.autoneg == 0){ //autoneg off ++ ++ phydev->autoneg = AUTONEG_DISABLE; ++ linkmode_clear_bit_array(half_speed_features_array, ARRAY_SIZE(half_speed_features_array), phydev->advertising); ++ linkmode_clear_bit_array(full_speed_features_array, ARRAY_SIZE(full_speed_features_array), phydev->advertising); ++ linkmode_clear_bit_array(autoneg_features_array, ARRAY_SIZE(autoneg_features_array), phydev->advertising); ++ ++ }else if(lp->dts_ctl.autoneg == 1){ //autoneg on ++ ++ phydev->autoneg = AUTONEG_ENABLE; ++ linkmode_clear_bit_array(half_speed_features_array, ARRAY_SIZE(half_speed_features_array), phydev->advertising); ++ linkmode_clear_bit_array(full_speed_features_array, ARRAY_SIZE(full_speed_features_array), phydev->advertising); ++ } ++ ++ /*2.dts duplex and speed configuration*/ ++ phydev->speed = lp->dts_ctl.speed; ++ if(lp->dts_ctl.duplex == 1){ ++ ++ phydev->duplex = DUPLEX_FULL; ++ switch (phydev->speed) { ++ case 1000: ++ linkmode_set_bit(SUPPORTED_1000baseT_Full, phydev->advertising); ++ break; ++ case 100: ++ linkmode_set_bit(SUPPORTED_100baseT_Full, phydev->advertising); ++ break; ++ case 10: ++ linkmode_set_bit(SUPPORTED_10baseT_Full, phydev->advertising); ++ break; ++ default: ++ break; ++ } ++ ++ }else if(lp->dts_ctl.duplex == 2){ ++ ++ phydev->duplex = DUPLEX_HALF; ++ switch (phydev->speed) { ++ case 1000: ++ linkmode_set_bit(SUPPORTED_1000baseT_Full, phydev->advertising); ++ break; ++ case 100: ++ linkmode_set_bit(SUPPORTED_100baseT_Full, phydev->advertising); ++ break; ++ case 10: ++ linkmode_set_bit(SUPPORTED_10baseT_Full, phydev->advertising); ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ ++ lp->old_link = 0; ++ lp->old_speed = 0; ++ lp->old_duplex = -1; ++ lp->phydev = phydev; ++ ++ //ingenic_mac_phy_dump(lp); ++ ++ return 0; ++} ++ ++/** ++ * ingenic_mac_update_stats - Update the board statistics counters ++ * @lp: board private structure ++ **/ ++ ++void ingenic_mac_update_stats(struct ingenic_mac_local *lp) ++{ ++ if ((lp->old_link == 0) || (lp->old_speed == 0) || (lp->old_duplex == -1)) ++ return; ++ ++#if 0 ++ //spin_lock_irqsave(&lp->stats_lock, flags); ++ //spin_lock(&lp->stats_lock); ++ ++ /* Fill out the OS statistics structure */ ++ lp->net_stats.multicast = REG32(MAC_STAT_RMCA); ++ lp->net_stats.collisions = REG32(MAC_STAT_RBCA); ++ ++ /* Rx Errors */ ++ ++ /* RLEC on some newer hardware can be incorrect so build ++ * our own version based on RUC and ROC */ ++ lp->net_stats.rx_errors = lp->stats.rxerrc + ++ lp->stats.crcerrs + lp->stats.algnerrc + ++ lp->stats.ruc + lp->stats.roc + ++ lp->stats.cexterr; ++ lp->net_stats.rx_length_errors = REG32(MAC_STAT_RFLR); ++ lp->net_stats.rx_crc_errors = REG32(MAC_STAT_RFCS); ++ lp->net_stats.rx_frame_errors = REG32(MAC_STAT_RALN); ++ lp->net_stats.rx_missed_errors = lp->stats.mpc; ++ ++ /* Tx Errors */ ++ lp->stats.txerrc = lp->stats.ecol + lp->stats.latecol; ++ lp->net_stats.tx_errors = lp->stats.txerrc; ++ lp->net_stats.tx_aborted_errors = lp->stats.ecol; ++ lp->net_stats.tx_window_errors = lp->stats.latecol; ++ lp->net_stats.tx_carrier_errors = lp->stats.tncrs; ++ if (hw->bad_tx_carr_stats_fd && ++ lp->link_duplex == FULL_DUPLEX) { ++ lp->net_stats.tx_carrier_errors = 0; ++ lp->stats.tncrs = 0; ++ } ++ ++ /* Tx Dropped needs to be maintained elsewhere */ ++ ++ /* Phy Stats */ ++ if (hw->media_type == e1000_media_type_copper) { ++ if ((lp->link_speed == SPEED_1000) && ++ (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { ++ phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; ++ lp->phy_stats.idle_errors += phy_tmp; ++ } ++ ++ if ((hw->mac_type <= e1000_82546) && ++ (hw->phy_type == e1000_phy_m88) && ++ !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp)) ++ lp->phy_stats.receive_errors += phy_tmp; ++ } ++ ++ /* Management Stats */ ++ if (hw->has_smbus) { ++ lp->stats.mgptc += er32(MGTPTC); ++ lp->stats.mgprc += er32(MGTPRC); ++ lp->stats.mgpdc += er32(MGTPDC); ++ } ++ ++ //spin_unlock_irqrestore(&lp->stats_lock, flags); ++ //spin_unlock(&lp->stats_lock); ++#endif ++} ++ ++/** ++ * ingenic_mac_watchdog - Timer Call-back ++ * @data: pointer to lp cast into an unsigned long ++ **/ ++static void ingenic_mac_watchdog(struct timer_list *t) { ++ struct ingenic_mac_local *lp = from_timer(lp, t, watchdog_timer); ++ ++ ingenic_mac_update_stats(lp); ++ ++ mod_timer(&lp->watchdog_timer, round_jiffies(jiffies + 5 * HZ)); ++} ++ ++static int __ingenic_mac_maybe_stop_tx(struct net_device *netdev, int size) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ struct ingenic_mac_tx_ring *tx_ring = &lp->tx_ring; ++ ++ netif_stop_queue(netdev); ++ smp_mb(); ++ ++ /* We need to check again in a case another CPU has just ++ * made room available. */ ++ if (likely(INGENIC_MAC_DESC_UNUSED(tx_ring) < size)) ++ return -EBUSY; ++ ++ /* A reprieve! */ ++ netif_start_queue(netdev); ++ ++lp->restart_queue; ++ return 0; ++} ++ ++static int ingenic_mac_maybe_stop_tx(struct net_device *netdev, ++ struct ingenic_mac_tx_ring *tx_ring, int size) ++{ ++ if (likely(INGENIC_MAC_DESC_UNUSED(tx_ring) >= size)) ++ return 0; ++ return __ingenic_mac_maybe_stop_tx(netdev, size); ++} ++ ++static int ingenic_mac_tx_map(struct ingenic_mac_local *lp, ++ struct ingenic_mac_tx_ring *tx_ring, ++ struct sk_buff *skb) ++{ ++ struct net_device *pdev = lp->netdev; ++ struct ingenic_mac_buffer *buffer_info; ++ unsigned int len = skb_headlen(skb); ++ unsigned int offset = 0, count = 0, i; ++ unsigned int f, segs; ++ unsigned int nr_frags = skb_shinfo(skb)->nr_frags; ++ ++ i = tx_ring->next_to_use; ++ ++ buffer_info = &tx_ring->buffer_info[i]; ++ buffer_info->length = len; ++ buffer_info->time_stamp = jiffies; ++ buffer_info->dma = dma_map_single(&pdev->dev, ++ skb->data + offset, ++ len, DMA_TO_DEVICE); ++ buffer_info->mapped_as_page = false; ++ if (dma_mapping_error(&pdev->dev, buffer_info->dma)) ++ goto dma_error; ++ segs = skb_shinfo(skb)->gso_segs ? : 1; ++ tx_ring->buffer_info[i].skb = skb; ++ tx_ring->buffer_info[i].segs = segs; ++ count++; ++ ++ for (f = 0; f < nr_frags; f++) { ++ const skb_frag_t *frag; ++ ++// struct page *p; ++ frag = &skb_shinfo(skb)->frags[f]; ++ len = frag->bv_len; ++ offset = frag->bv_offset; ++ i++; ++ if (i == tx_ring->count) ++ i = 0; ++ buffer_info = &tx_ring->buffer_info[i]; ++ buffer_info->length = len; ++ buffer_info->time_stamp = jiffies; ++ buffer_info->dma = dma_map_page(&pdev->dev, (struct page *)frag, offset, len, DMA_TO_DEVICE); ++ ++ buffer_info->mapped_as_page = true; ++ if (dma_mapping_error(&pdev->dev, buffer_info->dma)) ++ goto dma_unwind; ++ segs = skb_shinfo(skb)->gso_segs ? : 1; ++ tx_ring->buffer_info[i].skb = skb; ++ tx_ring->buffer_info[i].segs = segs; ++ tx_ring->buffer_info[i].transfering = 1; ++ ++ count++; ++ } ++ ++ ++ return count; ++dma_unwind: ++ dev_err(&pdev->dev, "Tx DMA map failed at dma_unwind\n"); ++ while(count-- > 0) { ++ i--; ++ if (i == 0) { ++ i = tx_ring->count; ++ } ++ buffer_info = &tx_ring->buffer_info[i]; ++ if (buffer_info->dma) { ++ if (buffer_info->mapped_as_page) ++ dma_unmap_page(&pdev->dev, buffer_info->dma, ++ buffer_info->length, DMA_TO_DEVICE); ++ else ++ dma_unmap_single(&pdev->dev, buffer_info->dma, ++ buffer_info->length, DMA_TO_DEVICE); ++ buffer_info->dma = 0; ++ } ++ if (buffer_info->skb) { ++ dev_kfree_skb_any(buffer_info->skb); ++ buffer_info->skb = NULL; ++ } ++ buffer_info->time_stamp = 0; ++ } ++ ++dma_error: ++ dev_err(&pdev->dev, "Tx DMA map failed at dma_error\n"); ++ buffer_info->dma = 0; ++ return -ENOMEM; ++} ++ ++static void ingenic_mac_restart_tx_dma(struct ingenic_mac_local *lp) { ++ /* TODO: clear error status bits if any */ ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ u32 data; ++ ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); ++ if (data & DmaTxStart) { ++ synopGMAC_resume_dma_tx(gmacdev); ++ } else { ++ synopGMAC_enable_dma_tx(gmacdev); ++ } ++ ++ /* ensure irq is enabled */ ++// synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++} ++ ++static void ingenic_mac_tx_queue(struct ingenic_mac_local *lp, ++ struct ingenic_mac_tx_ring *tx_ring) ++{ ++ DmaDesc *tx_desc = NULL; ++ struct ingenic_mac_buffer *buffer_info; ++ unsigned int i; ++ ++ i = tx_ring->next_to_use; ++ ++ buffer_info = &tx_ring->buffer_info[i]; ++ tx_desc = INGENIC_MAC_TX_DESC(*tx_ring, i); ++ ++ tx_desc->length |= (((cpu_to_le32(buffer_info->length) <buffer1 = cpu_to_le32(buffer_info->dma); ++ tx_desc->buffer2 = 0; ++ tx_desc->status |= (DescTxFirst | DescTxLast | DescTxIntEnable); //ENH_DESC ++ tx_desc->status |= DescOwnByDma;//ENH_DESC ++ if (unlikely(skb_shinfo(buffer_info->skb)->tx_flags & SKBTX_HW_TSTAMP)) { ++ tx_desc->status |= DescTxEnableTimestamp; ++ tx_desc->timestamphigh = 0; ++ tx_desc->timestamplow = 0; ++ } ++ ++ wmb(); ++ ++ buffer_info->transfering = 1; ++ ++ if (unlikely(++i == tx_ring->count)) i = 0; ++ tx_ring->next_to_use = i; ++ ++ wmb(); ++ ingenic_mac_restart_tx_dma(lp); ++} ++ ++static int ingenic_mac_hard_start_xmit(struct sk_buff *skb, ++ struct net_device *netdev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ struct ingenic_mac_tx_ring *tx_ring; ++ unsigned int first; ++ int count = 1; ++ int tx_num; ++ ++ tx_ring = &lp->tx_ring; ++ ++#if 0 ++ /* this can be cacelled for we should support it */ ++ if (unlikely(skb->len <= 0)) { ++ printk(JZMAC_DRV_NAME ": WARNING: skb->len < 0\n"); ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++#endif ++ ++ /* this can be cacelled for we should support it*/ ++ /* ++ if (skb_shinfo(skb)->nr_frags) { ++ printk(JZMAC_DRV_NAME ": WARNING: fragment packet do not handled!!!\n"); ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++ */ ++ ++ /* need: count + 2 desc gap to keep tail from touching ++ * head, otherwise try next time */ ++ if (unlikely(ingenic_mac_maybe_stop_tx(netdev, tx_ring, count + 2))) ++ return NETDEV_TX_BUSY; ++ ++ first = tx_ring->next_to_use; ++ count = ingenic_mac_tx_map(lp, tx_ring, skb); ++ ++ if (likely(count)) { ++ ingenic_mac_tx_queue(lp, tx_ring); ++ /* Make sure there is space in the ring for the next send.*/ ++ ingenic_mac_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2); ++#ifdef CONFIG_INGENIC_GMAC_USE_HWSTAMP ++ ingenic_tx_hwtstamp(netdev, skb, first); ++#endif ++ } else { ++ dev_kfree_skb_any(skb); ++ tx_ring->buffer_info[first].time_stamp = 0; ++ tx_ring->next_to_use = first; ++ } ++ ++ if(INGENIC_MAC_DESC_USED(tx_ring) > 16) { ++ hrtimer_cancel(&lp->tx_coalesce_timer); ++ tx_num = ingenic_mac_clean_tx_irq(lp); ++ ++ if(INGENIC_MAC_DESC_UNUSED(tx_ring) < (tx_ring->count-1)) { ++ ingenic_start_tx_coalesce_timer(lp); ++ } ++ } else if(!hrtimer_is_queued(&lp->tx_coalesce_timer)){ ++ ingenic_start_tx_coalesce_timer(lp); ++ } ++ ++ return NETDEV_TX_OK; ++} ++ ++static int ingenic_mac_clean_tx_irq(struct ingenic_mac_local *lp) { ++ struct net_device *netdev = lp->netdev; ++ struct ingenic_mac_buffer *buffer_info; ++ struct ingenic_mac_tx_ring *tx_ring = &lp->tx_ring; ++ DmaDesc *desc; ++ unsigned int i; ++ unsigned int count = 0; ++ unsigned int total_tx_bytes=0, total_tx_packets=0; ++ ++ i = tx_ring->next_to_clean; ++ desc = INGENIC_MAC_TX_DESC(*tx_ring, i); ++ buffer_info = &tx_ring->buffer_info[i]; ++ ++ while (buffer_info->transfering && ++ !synopGMAC_is_desc_owned_by_dma(desc) && ++ (count < tx_ring->count)) { ++ ++ buffer_info->transfering = 0; ++ count++; ++ ++ if(synopGMAC_is_desc_valid(desc->status)){ ++ total_tx_packets ++; ++ total_tx_bytes += buffer_info->length; ++ } ++ ++ ingenic_mac_unmap_and_free_tx_resource(lp, buffer_info); ++ synopGMAC_tx_desc_init_ring(desc, i == (tx_ring->count - 1)); ++ ++ i++; ++ if (unlikely(i == tx_ring->count)) i = 0; ++ ++ desc = INGENIC_MAC_TX_DESC(*tx_ring, i); ++ buffer_info = &tx_ring->buffer_info[i]; ++ } ++ ++ tx_ring->next_to_clean = i; ++ ++#define TX_WAKE_THRESHOLD 16 ++ if (unlikely(count && netif_carrier_ok(netdev) && ++ INGENIC_MAC_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) { ++ /* Make sure that anybody stopping the queue after this ++ * sees the new next_to_clean. ++ */ ++ smp_mb(); ++ if (netif_queue_stopped(netdev)) { ++ netif_wake_queue(netdev); ++ ++lp->restart_queue; ++ } ++ } ++ ++ lp->net_stats.tx_bytes += total_tx_bytes; ++ lp->net_stats.tx_packets += total_tx_packets; ++ ++ return count; ++} ++ ++static bool inline ingenic_mac_clean_rx_irq(struct ingenic_mac_local *lp, ++ int *work_done, int work_to_do) { ++ ++ struct net_device *netdev = lp->netdev; ++ struct ingenic_mac_rx_ring *rx_ring = &lp->rx_ring; ++ DmaDesc *rx_desc; ++ struct ingenic_mac_buffer *buffer_info; ++ u32 length; ++ unsigned int i; ++ int cleaned_count = 0; ++ unsigned int total_rx_bytes=0, total_rx_packets=0; ++ ++ i = rx_ring->next_to_clean; ++ rx_desc = INGENIC_MAC_RX_DESC(*rx_ring, i); ++ buffer_info = &rx_ring->buffer_info[i]; ++ ++ /* except the slot not used, if transfer done, buffer_info->invalid is always 0 */ ++ while ((!synopGMAC_is_desc_owned_by_dma(rx_desc)) && (!buffer_info->invalid)) { ++ struct sk_buff *skb; ++ ++ if (*work_done >= work_to_do) ++ break; ++ (*work_done)++; ++ rmb(); /* read descriptor and rx_buffer_info after status DD */ ++ ++ buffer_info->invalid = 1; ++ skb = buffer_info->skb; ++ buffer_info->skb = NULL; /* cleaned */ ++ ++ cleaned_count++; ++ ++ dma_unmap_single(&lp->netdev->dev, ++ buffer_info->dma, buffer_info->length, ++ DMA_FROM_DEVICE); ++ buffer_info->dma = 0; ++ ++ if(!synopGMAC_is_rx_desc_valid(rx_desc->status)) { ++ /* save the skb in buffer_info as good */ ++ dev_kfree_skb_any(skb); ++// printk("====>invalid pkt 0x%x\n",rx_desc->status); ++ goto invalid_pkt; ++ } ++ ++ length = synopGMAC_get_rx_desc_frame_length(rx_desc->status); ++// synopGMAC_rx_desc_init_ring(rx_desc, rx_desc_i == (rx_ring->count - 1)); ++#if 0 ++ printk("============================================\n"); ++ ingenic_mac_dump_pkt_data((unsigned char *)CKSEG1ADDR(buffer_info->dma), ++ length - 4); ++ printk("============================================\n"); ++#endif ++ ++ ++ /* adjust length to remove Ethernet CRC, this must be ++ * done after the TBI_ACCEPT workaround above */ ++ length -= 4; ++ ++ /* probably a little skewed due to removing CRC */ ++ total_rx_bytes += length; ++ total_rx_packets++; ++ ++ /* code added for copybreak, this should improve ++ * performance for small packets with large amounts ++ * of reassembly being done in the stack */ ++ ++#ifdef CONFIG_INGENIC_GMAC_USE_HWSTAMP ++ ingenic_rx_hwtstamp(netdev, skb, i); ++#endif ++ ++ prefetch(skb->data - NET_IP_ALIGN); ++ skb_put(skb, length); ++ skb->protocol = eth_type_trans(skb, netdev); ++ ++ //ingenic_mac_dump_skb_data(skb); ++// netif_receive_skb(skb); ++ napi_gro_receive(&lp->napi, skb); ++ ++invalid_pkt: ++ rx_desc->status = 0; ++ /* return some buffers to hardware, one at a time is too slow */ ++ if (unlikely(cleaned_count >= INGENIC_MAC_RX_BUFFER_WRITE)) { ++ ingenic_mac_alloc_rx_buffers(lp, cleaned_count, 1); ++ cleaned_count = 0; ++ } ++ /* use prefetched values */ ++ if (++i == rx_ring->count) i = 0; ++ ++ rx_desc = INGENIC_MAC_RX_DESC(*rx_ring, i); ++ buffer_info = &rx_ring->buffer_info[i]; ++ prefetch(rx_desc); ++ } ++ ++ rx_ring->next_to_clean = i; ++ ++ cleaned_count = INGENIC_MAC_DESC_UNUSED(rx_ring); ++ if (cleaned_count) ++ ingenic_mac_alloc_rx_buffers(lp, cleaned_count, 1); ++ ++ lp->net_stats.rx_bytes += total_rx_bytes; ++ lp->net_stats.rx_packets += total_rx_packets; ++ ++ return 0; ++} ++ ++ ++#ifdef CONFIG_INGENIC_GMAC_MUTUAL_TRANS ++static spinlock_t napi_poll_lock; ++static spinlock_t record_lock; ++static struct ingenic_mac_local *lp_record[2]; ++static atomic_t record[2] = {0}; ++static atomic_t enter; ++#endif ++/** ++ * ingenic_mac_clean - NAPI Rx polling callback ++ **/ ++static int ingenic_mac_clean(struct napi_struct *napi, int budget) { ++ struct ingenic_mac_local *lp = container_of(napi, struct ingenic_mac_local, napi); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int rx_num = 0; ++ ++#ifdef CONFIG_INGENIC_GMAC_MUTUAL_TRANS ++ int id; ++ if(!spin_trylock(&napi_poll_lock)){ ++ spin_lock(&record_lock); ++ if(atomic_read(&enter)) { ++ spin_unlock(&record_lock); ++ spin_lock(&napi_poll_lock); ++ } else { ++ atomic_set(&record[lp->id], 1); ++ napi_complete(napi); ++ spin_unlock(&record_lock); ++ return rx_num; ++ } ++ } ++ atomic_set(&enter, 0); ++#else ++ spin_lock(&lp->napi_poll_lock); ++#endif ++ ++ ingenic_mac_clean_rx_irq(lp, &rx_num, budget); ++ ++#ifdef CONFIG_INGENIC_GMAC_MUTUAL_TRANS ++ spin_lock(&record_lock); ++ atomic_set(&enter, 1); ++ id = (lp->id+1)%2; ++ if(atomic_read(&record[id]) == 1) { ++ atomic_set(&record[id], 0); ++ if (likely(napi_schedule_prep(&lp_record[id]->napi))) { ++ __napi_schedule(&lp_record[id]->napi); ++ } ++ } ++ spin_unlock(&record_lock); ++#endif ++ ++ if((lp->wake_irq_num < lp->net_stats.rx_packets)) { ++ lp->wake_irq_num = lp->net_stats.rx_packets + INGENIC_WAKE_IRQ_NUM; ++ napi_complete(napi); ++ synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++ rx_num = (rx_num == budget) ? (rx_num-1) : rx_num; ++ goto end; ++ } ++ ++ if (rx_num < budget) { ++ napi_complete(napi); ++ synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++ //ingenic_start_rx_coalesce_timer(lp); ++ } ++ ++end: ++#ifdef CONFIG_INGENIC_GMAC_MUTUAL_TRANS ++ spin_unlock(&napi_poll_lock); ++#else ++ spin_unlock(&lp->napi_poll_lock); ++#endif ++ return rx_num; ++} ++ ++/* interrupt routine to handle rx and error signal */ ++static irqreturn_t ingenic_mac_interrupt(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ u32 interrupt,dma_status_reg; ++ u32 mac_interrupt_status; ++ u32 rgmii_interrupt_status; ++ u32 lpi_interrupt_status; ++ ++ /* Read the Dma interrupt status to know whether the interrupt got generated by our device or not*/ ++ dma_status_reg = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus); ++ mac_interrupt_status = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacInterruptStatus); ++ ++ //printk("===>enter %s:%d DmaStatus = 0x%08x\n", __func__, __LINE__, dma_status_reg); ++ if(dma_status_reg == 0) ++ return IRQ_NONE; ++ ++ synopGMAC_disable_interrupt_all(gmacdev); ++ ++ ++ if(dma_status_reg & GmacPmtIntr){ ++ dev_err(&netdev->dev, "%s:: Interrupt due to PMT module\n",__FUNCTION__); ++ //synopGMAC_linux_powerup_mac(gmacdev); ++ } ++ ++ if(dma_status_reg & GmacMmcIntr){ ++ dev_err(&netdev->dev, "%s:: Interrupt due to MMC module\n",__FUNCTION__); ++ dev_err(&netdev->dev, "%s:: synopGMAC_rx_int_status = %08x\n", ++ __FUNCTION__,synopGMAC_read_mmc_rx_int_status(gmacdev)); ++ dev_err(&netdev->dev, "%s:: synopGMAC_tx_int_status = %08x\n", ++ __FUNCTION__,synopGMAC_read_mmc_tx_int_status(gmacdev)); ++ } ++ ++ if(dma_status_reg & GmacLineIntfIntr){ ++ if (mac_interrupt_status & GmacRgmiiIntSts) { ++ rgmii_interrupt_status = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacRGMIIControl); ++ dev_dbg(&netdev->dev, "%s:Interrupts to RGMII/SGMII: 0x%08x\n",__FUNCTION__,rgmii_interrupt_status); ++ } else ++ dev_err(&netdev->dev, "%s:: Interrupt due to GMAC LINE module\n",__FUNCTION__); ++ } ++ ++ if(dma_status_reg & GmacLPIIntr){ ++ if (mac_interrupt_status & GmacLPIIS) { ++ lpi_interrupt_status = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacLPICtrlSts); ++ dev_dbg(&netdev->dev, "%s:Interrupts to LPI: 0x%08x\n",__FUNCTION__,lpi_interrupt_status); ++ } else ++ dev_err(&netdev->dev, "%s:: Interrupt due to GMAC LPI module\n",__FUNCTION__); ++ } ++ ++ /* Now lets handle the DMA interrupts*/ ++ interrupt = synopGMAC_get_interrupt_type(gmacdev); ++ dev_dbg(&netdev->dev, "%s:Interrupts to be handled: 0x%08x\n",__FUNCTION__,interrupt); ++ ++ ++ if(interrupt & synopGMACDmaError){ ++ dev_err(&netdev->dev, "%s::Fatal Bus Error Inetrrupt Seen\n",__FUNCTION__); ++ /* do nothing here, let tx_timeout to handle it */ ++ } ++ ++ if(interrupt & synopGMACDmaRxAbnormal){ ++ dev_dbg(&netdev->dev, "%s::Abnormal Rx Interrupt Seen\n",__FUNCTION__); ++ synopGMAC_resume_dma_rx(gmacdev); ++ } ++ ++ if(interrupt & synopGMACDmaRxStopped){ ++ // Receiver gone in to stopped state ++ // why Rx Stopped? no enough descriptor? but why no enough descriptor need cause an interrupt? ++ // we have no enough descriptor because we can't handle packets that fast, isn't it? ++ // So I think if DmaRxStopped Interrupt can disabled ++ dev_info(&netdev->dev, "%s::Receiver stopped seeing Rx interrupts\n",__FUNCTION__); ++ ++// synopGMAC_enable_dma_rx(gmacdev); ++ } ++ ++ if(interrupt & synopGMACDmaTxAbnormal){ ++ dev_dbg(&netdev->dev, "%s::Abnormal Tx Interrupt Seen\n",__FUNCTION__); ++ } ++ ++ if(interrupt & synopGMACDmaTxStopped){ ++ dev_info(&netdev->dev, "%s::Transmitter stopped sending the packets\n",__FUNCTION__); ++// synopGMAC_disable_dma_tx(gmacdev); ++// ingenic_mac_dump_all_desc(lp); ++// ingenic_mac_take_desc_ownership_tx(lp); ++// synopGMAC_enable_dma_tx(gmacdev); ++ } ++ ++ if (likely(napi_schedule_prep(&lp->napi))) { ++ dev_dbg(&netdev->dev, "enter %s:%d, call __napi_schedule\n", __func__, __LINE__); ++ //hrtimer_cancel(&lp->rx_coalesce_timer); ++ __napi_schedule(&lp->napi); ++ } else { ++ /* this really should not happen! if it does it is basically a ++ * bug, but not a hard error, so enable ints and continue */ ++ synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* MAC control and configuration */ ++ ++static void ingenic_mac_stop_activity(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ synopGMAC_disable_interrupt_all(gmacdev); ++ ++ // Disable the Dma in rx path ++ synopGMAC_disable_dma_rx(gmacdev); ++ ingenic_mac_take_desc_ownership_rx(lp); ++ //msleep(100); // Allow any pending buffer to be read by host ++ //synopGMAC_rx_disable(gmacdev); ++ ++ synopGMAC_disable_dma_tx(gmacdev); ++ ingenic_mac_take_desc_ownership_tx(lp); ++ //msleep(100); // allow any pending transmission to complete ++ // Disable the Mac for both tx and rx ++ //synopGMAC_tx_disable(gmacdev); ++} ++ ++static void ingenic_mac_disable(struct ingenic_mac_local *lp) { ++ /* First ensure that the upper network stack is stopped */ ++ /* can be netif_tx_disable when NETIF_F_LLTX is removed */ ++ netif_stop_queue(lp->netdev); /* tx */ ++ napi_disable(&lp->napi); /* rx */ ++ ++ ingenic_mac_stop_activity(lp); ++ ++ spin_lock(&lp->napi_poll_lock); ++ desc_list_reinit(lp); ++ spin_unlock(&lp->napi_poll_lock); ++} ++ ++static void ingenic_mac_init(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ /* ++ * disable the watchdog and gab to receive frames up to 16384 bytes ++ * to adjust IP protocol ++ */ ++ synopGMAC_wd_disable(gmacdev); ++ synopGMAC_jab_disable(gmacdev); ++ ++ /* cancel to set Frame Burst Enable for now we use duplex mode */ ++ //synopGMAC_frame_burst_enable(gmacdev); ++ ++ /* set jumbo to allow to receive Jumbo frames of 9,018 bytes */ ++ //synopGMAC_jumbo_frame_disable(gmacdev); ++ synopGMAC_jumbo_frame_enable(gmacdev); ++ ++ /* for we try to use duplex */ ++ synopGMAC_rx_own_disable(gmacdev); ++ synopGMAC_loopback_off(gmacdev); ++ /* default to full duplex, I think this will be the common case */ ++ synopGMAC_set_full_duplex(gmacdev); ++ /* here retry enabe may useless */ ++ synopGMAC_retry_enable(gmacdev); ++ synopGMAC_pad_crc_strip_disable(gmacdev); ++ synopGMAC_back_off_limit(gmacdev,GmacBackoffLimit0); ++ synopGMAC_deferral_check_disable(gmacdev); ++ synopGMAC_tx_enable(gmacdev); ++ synopGMAC_rx_enable(gmacdev); ++ ++ /* default to 100M, I think this will be the common case */ ++ synopGMAC_select_mii(gmacdev); ++ synopGMAC_select_speed100(gmacdev); ++ ++ /* Frame Filter Configuration */ ++ synopGMAC_frame_filter_enable(gmacdev); ++ synopGMAC_set_pass_control(gmacdev,GmacPassControl0); ++ synopGMAC_broadcast_enable(gmacdev); ++ synopGMAC_src_addr_filter_disable(gmacdev); ++ synopGMAC_multicast_enable(gmacdev); ++ synopGMAC_dst_addr_filter_normal(gmacdev); ++ synopGMAC_multicast_hash_filter_disable(gmacdev); ++ synopGMAC_promisc_disable(gmacdev); ++ synopGMAC_unicast_hash_filter_disable(gmacdev); ++ ++ /*Flow Control Configuration*/ ++ synopGMAC_unicast_pause_frame_detect_disable(gmacdev); ++ synopGMAC_pause_control(gmacdev); // This enables the pause control in Full duplex mode of operation ++ lp->flowcontrol.tx = 0; ++ lp->flowcontrol.rx = 1; ++ lp->flowcontrol.autoneg = 0; ++} ++ ++static void ingenic_mac_configure(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++#ifdef ENH_DESC_8W ++#ifndef CONFIG_INGENIC_MAC_AXI_BUS ++ synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip2 | DmaDescriptor8Words | DmaFixedBurstEnable | 0x02000000); //pbl32 incr with rxthreshold 128 and Desc is 8 Words ++#else ++ synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip1 | DmaDescriptor8Words); ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaAxiMode, synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaAxiMode) | (0x1 << 31)); ++#endif ++#else ++ /* pbl32 incr with rxthreshold 128 */ ++ synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip2); ++#endif ++ /* DmaRxThreshCtrl128 is ok for the RX FIFO is configured to 256 Bytes */ ++ synopGMAC_dma_control_init(gmacdev,DmaStoreAndForward |DmaTxSecondFrame|DmaRxThreshCtrl128); ++ ++ /*Initialize the mac interface*/ ++ ++ ingenic_mac_init(lp); ++ ++#ifdef IPC_OFFLOAD ++ /*IPC Checksum offloading is enabled for this driver. Should only be used if Full Ip checksumm offload engine is configured in the hardware*/ ++ synopGMAC_enable_rx_chksum_offload(gmacdev); //Enable the offload engine in the receive path ++ synopGMAC_rx_tcpip_chksum_drop_enable(gmacdev); // This is default configuration, DMA drops the packets if error in encapsulated ethernet payload ++ // The FEF bit in DMA control register is configured to 0 indicating DMA to drop the errored frames. ++ /*Inform the Linux Networking stack about the hardware capability of checksum offloading*/ ++ netdev->features = NETIF_F_HW_CSUM; ++#endif ++ ++ synopGMAC_clear_interrupt(gmacdev); ++ /* ++ Disable the interrupts generated by MMC and IPC counters. ++ If these are not disabled ISR should be modified accordingly to handle these interrupts. ++ */ ++ synopGMAC_disable_mmc_tx_interrupt(gmacdev, 0xFFFFFFFF); ++ synopGMAC_disable_mmc_rx_interrupt(gmacdev, 0xFFFFFFFF); ++ synopGMAC_disable_mmc_ipc_rx_interrupt(gmacdev, 0xFFFFFFFF); ++} ++ ++/* ++ * Enable Interrupts, Receive, and Transmit(The same sequence as ingenic_mac_open, only a bit different) ++ */ ++static void ingenic_mac_enable(struct ingenic_mac_local *lp) { ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ ingenic_mac_configure(lp); ++ ++ napi_enable(&lp->napi); ++ synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++ /* we only enable rx here */ ++ synopGMAC_enable_dma_rx(gmacdev); ++ /* We can accept TX packets again */ ++ lp->netdev->_tx->trans_start = jiffies; ++ netif_wake_queue(lp->netdev); ++} ++ ++static void ingenic_mac_reinit_locked(struct ingenic_mac_local *lp) ++{ ++ WARN_ON(in_interrupt()); ++ ingenic_mac_disable(lp); ++ ingenic_mac_enable(lp); ++} ++ ++/* Our watchdog timed out. Called by the networking layer */ ++static void ingenic_mac_tx_timeout(struct net_device *dev, unsigned int txqueue) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ ++ /* Do the reset outside of interrupt context */ ++ lp->tx_timeout_count++; ++ schedule_work(&lp->reset_task); ++} ++ ++static void ingenic_mac_reset_task(struct work_struct *work) ++{ ++ struct ingenic_mac_local *lp = ++ container_of(work, struct ingenic_mac_local, reset_task); ++ ++ ingenic_mac_reinit_locked(lp); ++} ++ ++static void setup_mac_addr(synopGMACdevice *gmacdev, u8 *mac_addr) { ++ synopGMAC_set_mac_addr(gmacdev, ++ GmacAddr0High,GmacAddr0Low, ++ mac_addr); ++} ++ ++static int ingenic_mac_set_mac_address(struct net_device *dev, void *p) { ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ ++ struct sockaddr *addr = p; ++ if (netif_running(dev)) ++ return -EBUSY; ++ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); ++ setup_mac_addr(gmacdev, dev->dev_addr); ++ return 0; ++} ++ ++/* ++ * Open and Initialize the interface ++ * ++ * Set up everything, reset the card, etc.. ++ */ ++static int ingenic_mac_open(struct net_device *dev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ int retval; ++ ++ pr_debug("%s: %s\n", dev->name, __func__); ++ if (ingenic_mac_phy_hwrst(lp->pdev, false)) { ++ return -ENODEV; ++ } ++ ++ retval = phy_read(lp->phydev, MII_BMCR); ++ retval &= ~(1 << 11); ++ phy_write(lp->phydev, MII_BMCR, retval); ++ ++ /* ++ * Check that the address is valid. If its not, refuse ++ * to bring the device up. The user must specify an ++ * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx ++ */ ++ if (!is_valid_ether_addr(dev->dev_addr)) { ++ printk(KERN_WARNING INGENIC_MAC_DRV_NAME ": no valid ethernet hw addr\n"); ++ return -EINVAL; ++ } ++ ++ phy_write(lp->phydev, MII_BMCR, BMCR_RESET | phy_read(lp->phydev, MII_BMCR)); ++ while(phy_read(lp->phydev, MII_BMCR) & BMCR_RESET); ++ phy_start(lp->phydev); ++ ++ if (synopGMAC_reset(gmacdev) < 0) { ++ printk("func:%s, synopGMAC_reset failed\n", __func__); ++ phy_stop(lp->phydev); ++ return -1; ++ } ++ ++ /* init MDC CLK */ ++ ingenic_set_mdc_rate(lp); ++ ++ /* initial rx and tx list */ ++ retval = desc_list_init(lp); ++ ++ if (retval) ++ return retval; ++ ++ setup_mac_addr(gmacdev, dev->dev_addr); ++ ingenic_mac_configure(lp); ++ ++ //ingenic_mac_dump_all_regs(gmacdev, __func__, __LINE__); ++ ++ napi_enable(&lp->napi); ++ ++ /* we are ready, reset GMAC and enable interrupts */ ++ synopGMAC_enable_interrupt(gmacdev,DmaIntEnable); ++ /* we only enable rx here */ ++ synopGMAC_enable_dma_rx(gmacdev); ++ ++ lp->wake_irq_num = lp->net_stats.rx_packets + INGENIC_WAKE_IRQ_NUM; ++ ++ /* We can accept TX packets again */ ++ lp->netdev->_tx->trans_start = jiffies; ++ netif_start_queue(dev); ++ ++ return 0; ++} ++ ++/* ++ * this makes the board clean up everything that it can ++ * and not talk to the outside world. Caused by ++ * an 'ifconfig ethX down' ++ */ ++static int ingenic_mac_close(struct net_device *dev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ ++ synopGMAC_clear_interrupt(gmacdev); ++ synopGMAC_disable_interrupt_all(gmacdev); ++ ingenic_mac_disable(lp); ++ ++ netif_carrier_off(dev); ++ ++ phy_stop(lp->phydev); ++ phy_write(lp->phydev, MII_BMCR, BMCR_PDOWN); ++ ++ /* free the rx/tx buffers */ ++ desc_list_free(lp); ++ return 0; ++} ++ ++static void ingenic_mac_change_rx_flags(struct net_device *dev, int flags) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ if (dev->flags & IFF_PROMISC) { ++ /* Accept any kinds of packets */ ++ synopGMAC_promisc_enable(gmacdev); ++ // synopGMAC_frame_filter_disable(gmacdev); ++ printk("%s: Enter promisc mode!\n",dev->name); ++ }else{ ++ synopGMAC_promisc_disable(gmacdev); ++ } ++} ++ ++static struct net_device_stats *ingenic_mac_get_stats(struct net_device *netdev) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ ++ /* only return the current stats */ ++ return &lp->net_stats; ++} ++ ++static int ingenic_mac_change_mtu(struct net_device *netdev, int new_mtu) { ++ int running = netif_running(netdev); ++ int err; ++ ++ if (new_mtu < MIN_ETHERNET_PAYLOAD || new_mtu > JUMBO_FRAME_PAYLOAD) ++ return -EINVAL; ++ ++ if (running) ++ ingenic_mac_close(netdev); ++ ++ netdev_info(netdev, "MTU change from %d to %d\n", netdev->mtu, new_mtu); ++ netdev->mtu = new_mtu; ++ ++ if (running) ++ err = ingenic_mac_open(netdev); ++ ++ return err; ++} ++ ++static int ingenic_mac_do_ioctl(struct net_device *netdev, struct ifreq *ifr, s32 cmd) { ++ struct ingenic_mac_local *lp = netdev_priv(netdev); ++ ++ if (!netif_running(netdev)) { ++ printk("error : it is not in netif_running\n"); ++ return -EINVAL; ++ } ++ ++ if(!(lp->phydev->link)) ++ return 0; ++ ++ switch (cmd) { ++ case SIOCSHWTSTAMP: ++ return ingenic_mac_hwtstamp_ioctl(netdev, ifr, cmd); ++ default: ++ return generic_mii_ioctl(&lp->mii, if_mii(ifr), cmd, NULL); ++ } ++} ++ ++static const struct net_device_ops ingenic_mac_netdev_ops = { ++ .ndo_open = ingenic_mac_open, ++ .ndo_stop = ingenic_mac_close, ++ .ndo_start_xmit = ingenic_mac_hard_start_xmit, ++ .ndo_change_rx_flags = ingenic_mac_change_rx_flags, ++ .ndo_get_stats = ingenic_mac_get_stats, ++ .ndo_set_mac_address = ingenic_mac_set_mac_address, ++ .ndo_tx_timeout = ingenic_mac_tx_timeout, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_change_mtu = ingenic_mac_change_mtu, ++ .ndo_do_ioctl = ingenic_mac_do_ioctl, ++}; ++ ++/* Read an off-chip register in a PHY through the MDC/MDIO port */ ++static int ingenic_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum) ++{ ++ u16 data = 0; ++ struct ingenic_mac_local *lp = bus->priv; ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ s32 status; ++ if(lp->no_phy_connect){ ++ return (int)lp->virt_phy.reg[regnum]; ++ } else { ++ status = synopGMAC_read_phy_reg(gmacdev, phy_addr, regnum, &data); ++ if (status) ++ data = 0; ++ return (int)data; ++ } ++} ++/* Write an off-chip register in a PHY through the MDC/MDIO port */ ++static int ingenic_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value) ++{ ++ struct ingenic_mac_local *lp = bus->priv; ++ synopGMACdevice *gmacdev = lp->gmacdev; ++ u16 tmp,force_op,autoneg_op; ++ if(lp->no_phy_connect){ ++ /* 0x0 Basic mode control reg*/ ++ if(regnum == MII_BMCR){ ++ ++ tmp = lp->virt_phy.reg[MII_BMCR]; ++ /*down_op :maintain the register value when ifconfig ethx down operation*/ ++ if(!(value & BMCR_PDOWN)){ ++ tmp &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX); ++ tmp |= value; ++ ++ /*force_op :configure other registers according to BCMR register after forced operation*/ ++ force_op = (value & (BMCR_SPEED1000 | BMCR_SPEED100)); ++ switch(force_op){ ++ case BMCR_SPEED1000: ++ lp->virt_phy.reg[MII_ADVERTISE] &= ~(ADVERTISE_ALL); ++ lp->virt_phy.reg[MII_LPA] &= ~(ADVERTISE_ALL); ++ lp->virt_phy.reg[MII_BMSR] |= BMSR_ESTATEN; ++ ++ if(value & BMCR_FULLDPLX){ ++ lp->virt_phy.reg[MII_CTRL1000] = ADVERTISE_1000FULL; ++ lp->virt_phy.reg[MII_STAT1000] = LPA_1000FULL; ++ } else { ++ lp->virt_phy.reg[MII_CTRL1000] = ADVERTISE_1000HALF; ++ lp->virt_phy.reg[MII_STAT1000] = LPA_1000HALF; ++ } ++ break; ++ ++ case BMCR_SPEED100: ++ lp->virt_phy.reg[MII_BMSR] &= ~(BMSR_ESTATEN); ++ lp->virt_phy.reg[MII_CTRL1000] &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); ++ lp->virt_phy.reg[MII_STAT1000] &= ~(LPA_1000FULL | LPA_1000HALF); ++ ++ if(value & BMCR_FULLDPLX){ ++ lp->virt_phy.reg[MII_ADVERTISE] &= ~(ADVERTISE_ALL); ++ lp->virt_phy.reg[MII_ADVERTISE] |= ADVERTISE_100FULL; ++ lp->virt_phy.reg[MII_LPA] &= ~(ADVERTISE_ALL); ++ lp->virt_phy.reg[MII_LPA] |= LPA_100FULL; ++ } else { ++ ++ lp->virt_phy.reg[MII_ADVERTISE] &= ~(ADVERTISE_ALL); ++ lp->virt_phy.reg[MII_ADVERTISE] |= ADVERTISE_100HALF; ++ lp->virt_phy.reg[MII_LPA] &= ~(ADVERTISE_ALL); ++ lp->virt_phy.reg[MII_LPA] |= LPA_100HALF; ++ } ++ break; ++ ++ case 0x0: ++ lp->virt_phy.reg[MII_BMSR] &= ~(BMSR_ESTATEN); ++ lp->virt_phy.reg[MII_CTRL1000] &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); ++ lp->virt_phy.reg[MII_STAT1000] &= ~(LPA_1000FULL | LPA_1000HALF); ++ ++ if(value & BMCR_FULLDPLX){ ++ lp->virt_phy.reg[MII_ADVERTISE] &= ~(ADVERTISE_ALL); ++ lp->virt_phy.reg[MII_ADVERTISE] |= ADVERTISE_10FULL; ++ lp->virt_phy.reg[MII_LPA] &= ~(ADVERTISE_ALL); ++ lp->virt_phy.reg[MII_LPA] |= LPA_10FULL; ++ } else { ++ lp->virt_phy.reg[MII_ADVERTISE] &= ~(ADVERTISE_ALL); ++ lp->virt_phy.reg[MII_ADVERTISE] |= ADVERTISE_10HALF; ++ lp->virt_phy.reg[MII_LPA] &= ~(ADVERTISE_ALL); ++ lp->virt_phy.reg[MII_LPA] |= LPA_10HALF; ++ } ++ ++ default: ++ break; ++ ++ } ++ } ++ tmp &= ~(BMCR_RESET | BMCR_PDOWN);/*clean reset bit*/ ++ lp->virt_phy.reg[MII_BMCR] = tmp; ++ } ++ ++ /* 0x4 Advertisement control reg*/ ++ if((regnum == MII_ADVERTISE)) ++ { ++ tmp = lp->virt_phy.reg[MII_ADVERTISE]; ++ tmp &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); ++ tmp |= value; ++ lp->virt_phy.reg[MII_ADVERTISE] = tmp; ++ ++ tmp = lp->virt_phy.reg[MII_LPA]; ++ tmp &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); ++ tmp |= value; ++ lp->virt_phy.reg[MII_LPA] = tmp; ++ ++ /* 0x1 Basic mode status reg*/ ++ tmp = lp->virt_phy.reg[MII_BMSR]; ++ tmp |= BMSR_ESTATEN; ++ if(lp->virt_phy.reg[MII_ADVERTISE] & ADVERTISE_ALL){ ++ tmp &= ~(BMSR_ESTATEN); /*1000M need extended*/ ++ } ++ lp->virt_phy.reg[MII_BMSR] = tmp; ++ ++ /* 0x9 1000BASE-T control reg*/ ++ if(lp->virt_phy.reg[MII_ADVERTISE] & ADVERTISE_ALL){ ++ lp->virt_phy.reg[MII_CTRL1000] &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); ++ } ++ ++ /* 0xa 1000BASE-T status reg*/ ++ if(lp->virt_phy.reg[MII_LPA] & ADVERTISE_ALL){ ++ lp->virt_phy.reg[MII_STAT1000] &= ~(LPA_1000FULL | LPA_1000HALF); ++ } ++ ++ /*autoneg_op :update BMCR register since negotiation operation*/ ++ autoneg_op = (value & ADVERTISE_ALL); ++ if(autoneg_op){ ++ tmp = lp->virt_phy.reg[MII_BMCR]; ++ tmp &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX); ++ switch(autoneg_op){ ++ case ADVERTISE_100FULL: ++ tmp |= (BMCR_SPEED100 | BMCR_FULLDPLX); ++ break; ++ case ADVERTISE_100HALF: ++ tmp |= BMCR_SPEED100; ++ break; ++ case ADVERTISE_10FULL: ++ tmp |= BMCR_FULLDPLX; ++ break; ++ case ADVERTISE_10HALF: ++ tmp |= 0; ++ break; ++ default: ++ break; ++ ++ } ++ lp->virt_phy.reg[MII_BMCR] = tmp; ++ } ++ } ++ /* 0x9 1000BASE-T control reg*/ ++ if(regnum == MII_CTRL1000){ ++ lp->virt_phy.reg[MII_CTRL1000] = value; ++ /* 0xa 1000BASE-T status reg*/ ++ lp->virt_phy.reg[MII_STAT1000] = value << 2; ++ ++ /*autoneg_op :update BMCR register since negotiation operation*/ ++ autoneg_op = (value & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)); ++ if(autoneg_op){ ++ tmp = lp->virt_phy.reg[MII_BMCR]; ++ tmp &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX); ++ switch(autoneg_op){ ++ case ADVERTISE_1000FULL: ++ tmp |= (BMCR_SPEED1000 | BMCR_FULLDPLX); ++ break; ++ case ADVERTISE_1000HALF: ++ tmp |= BMCR_SPEED1000; ++ break; ++ default: ++ break; ++ ++ } ++ lp->virt_phy.reg[MII_BMCR] = tmp; ++ } ++ } ++ ++ return 0; ++ } else { ++ return synopGMAC_write_phy_reg(gmacdev, phy_addr, regnum, value); ++ } ++} ++ ++static int ingenic_mdiobus_reset(struct mii_bus *bus) ++{ ++ return 0; ++} ++ ++static int ingenic_mdio_phy_read(struct net_device *dev, int phy_id, int location) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ return ingenic_mdiobus_read(lp->mii_bus, phy_id, location); ++} ++ ++static void ingenic_mdio_phy_write(struct net_device *dev, int phy_id, int location, int value) ++{ ++ struct ingenic_mac_local *lp = netdev_priv(dev); ++ ++ ingenic_mdiobus_write(lp->mii_bus, phy_id, location, value); ++} ++ ++static int ingenic_mac_interface_init(struct ingenic_mac_local *lp) ++{ ++ struct platform_device *pdev = lp->pdev; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ unsigned int rx_clk_delay = 0; ++ unsigned int tx_clk_delay = 0; ++ unsigned int cpm_mphyc; ++ unsigned int data; ++ unsigned int val; ++ int err; ++ ++ switch(lp->interface) { ++ case RMII: ++ case MII: ++ case GMII: ++ break; ++ case RGMII: ++ break; ++ default: ++ dev_err(dev, "Gmac interface mode err!\n"); ++ return -EINVAL; ++ } ++ ++ err = of_property_read_u32(np, "ingenic,mode-reg", &cpm_mphyc); ++ if (err < 0) { ++ dev_err(dev, "Gmac get interface mode register failed!\n"); ++ return err; ++ } ++ ++ if(lp->interface==RGMII) { ++ err = of_property_read_u32(np, "ingenic,rx-clk-delay", &rx_clk_delay); ++ if (err < 0) { ++ dev_info(dev, "Gmac rgmii set origin rx-clk\n"); ++ } ++ ++ err = of_property_read_u32(np, "ingenic,tx-clk-delay", &tx_clk_delay); ++ if (err < 0) { ++ dev_info(dev, "Gmac rgmii set origin tx-clk\n"); ++ } ++ } ++ ++ /* Set gmac interface mode */ ++ if(lp->interface==RMII || lp->interface==RGMII) ++ val = lp->interface; ++ else ++ val = 0; ++ ++ data = *(volatile unsigned int *)cpm_mphyc; ++ if(tx_clk_delay > 0 && tx_clk_delay <= 128) ++ data = (data & ~(0x7f << 12)) | ((tx_clk_delay-1) << 12) | (0x1 << 19); ++ if(rx_clk_delay > 0 && rx_clk_delay <= 128) ++ data = (data & ~(0x7f << 4)) | ((rx_clk_delay-1) << 4) | (0x1 << 11); ++ *(volatile unsigned int *)cpm_mphyc = (data & ~0x7) | val; ++ ++ return 0; ++} ++ ++static int ingenic_mac_virtual_phy_init(struct ingenic_mac_local *lp) ++{ ++ u16 tmp = 0; ++ /* 0x0 Basic mode control reg*/ ++ tmp = (lp->interface == RMII)?(BMCR_SPEED100 | BMCR_FULLDPLX):(BMCR_SPEED1000 | BMCR_FULLDPLX); ++ ++ if(lp->dts_ctl.duplex == 1){ ++ tmp |= BMCR_FULLDPLX; ++ }else if(lp->dts_ctl.duplex == 2){ ++ tmp &= ~BMCR_FULLDPLX; ++ } ++ ++ if(lp->dts_ctl.speed == 1000){ ++ tmp |= BMCR_SPEED1000; ++ }else if(lp->dts_ctl.speed == 100){ ++ tmp |= BMCR_SPEED100; ++ }else if(lp->dts_ctl.speed == 10){ ++ tmp &= ~(BMCR_SPEED1000 | BMCR_SPEED100); ++ } ++ lp->virt_phy.reg[MII_BMCR] = tmp; ++ ++ /* 0x1 Basic mode status reg*/ ++ lp->virt_phy.reg[MII_BMSR] = BMSR_LSTATUS | BMSR_ANEGCAPABLE | BMSR_ANEGCOMPLETE | BMSR_100FULL |\ ++ BMSR_100HALF | BMSR_10FULL | BMSR_10HALF | BMSR_ESTATEN; ++ ++ /* 0x2 PHYS ID 1 reg*/ ++ lp->virt_phy.reg[MII_PHYSID1] = 0x5555; ++ ++ /* 0x3 PHYS ID 2 reg*/ ++ lp->virt_phy.reg[MII_PHYSID2] = (lp->id & 0xffff); ++ ++ /* 0x4 Advertisement control reg*/ ++ tmp = ADVERTISE_LPACK | ADVERTISE_PAUSE_CAP; ++ if(lp->dts_ctl.duplex == 1){ ++ if(lp->dts_ctl.speed == 100){ ++ tmp |= ADVERTISE_100FULL; ++ }else if(lp->dts_ctl.speed == 10){ ++ tmp |= ADVERTISE_10FULL; ++ } ++ }else if(lp->dts_ctl.duplex == 2){ ++ if(lp->dts_ctl.speed == 100){ ++ tmp |= ADVERTISE_100HALF; ++ }else if(lp->dts_ctl.speed == 10){ ++ tmp |= ADVERTISE_10HALF; ++ } ++ } ++ lp->virt_phy.reg[MII_ADVERTISE] = tmp; ++ ++ /* 0x5 Link partner ability reg*/ ++ tmp = LPA_LPACK | LPA_PAUSE_CAP; ++ if(lp->dts_ctl.duplex == 1){ ++ if(lp->dts_ctl.speed == 100){ ++ tmp |= LPA_100FULL; ++ }else if(lp->dts_ctl.speed == 10){ ++ tmp |= LPA_10FULL; ++ } ++ }else if(lp->dts_ctl.duplex == 2){ ++ if(lp->dts_ctl.speed == 100){ ++ tmp |= LPA_100HALF; ++ }else if(lp->dts_ctl.speed == 10){ ++ tmp |= LPA_10HALF; ++ } ++ } ++ lp->virt_phy.reg[MII_LPA] = tmp; ++ ++ /* 0x9 1000BASE-T control reg*/ ++ if(lp->dts_ctl.speed == 1000){ ++ if(lp->dts_ctl.duplex == 1){ ++ tmp = ADVERTISE_1000FULL; ++ }else if(lp->dts_ctl.duplex == 2){ ++ tmp = ADVERTISE_1000HALF; ++ } ++ } ++ lp->virt_phy.reg[MII_CTRL1000] = tmp; ++ ++ /* 0xa 1000BASE-T status reg*/ ++ if(lp->dts_ctl.speed == 1000){ ++ if(lp->dts_ctl.duplex == 1){ ++ tmp = LPA_1000FULL; ++ }else if(lp->dts_ctl.duplex == 2){ ++ tmp = LPA_1000HALF; ++ } ++ } ++ lp->virt_phy.reg[MII_STAT1000] = tmp; ++ ++ /* 0xf Extended status reg*/ ++ lp->virt_phy.reg[MII_ESTATUS] = ESTATUS_1000_TFULL | ESTATUS_1000_THALF; ++ ++ return 0; ++} ++ ++static ssize_t mac_reg_dump(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct net_device *net_dev = dev_get_drvdata(dev); ++ struct ingenic_mac_local *lp = netdev_priv(net_dev); ++ ++ ingenic_mac_dump_all_regs(lp->gmacdev, __func__, __LINE__); ++ ++ return 0; ++} ++ ++static DEVICE_ATTR(mac_reg_dump, S_IRUGO|S_IWUSR, mac_reg_dump, NULL); ++static struct attribute *mac_debug_attrs[] = { ++ &dev_attr_mac_reg_dump.attr, ++ NULL, ++}; ++ ++const char mac_group_name[] = "debug"; ++static struct attribute_group mac_debug_attr_group = { ++ .name = mac_group_name, ++ .attrs = mac_debug_attrs, ++}; ++ ++static int get_param_from_dts(struct ingenic_mac_local *lp) ++{ ++ struct platform_device *pdev = lp->pdev; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ unsigned int mode; ++ unsigned int force; ++ unsigned int autoneg; ++ unsigned int speed; ++ unsigned int duplex; ++ int rc; ++ ++ rc = of_property_read_u32(np, "ingenic,mac-mode", &mode); ++ if (rc < 0) { ++ dev_err(&pdev->dev, "Get mac-mode value failed\n"); ++ return rc; ++ }else{ ++ lp->interface = mode; ++ } ++ ++ rc = of_property_read_u32(np, "ingenic,mac-force", &force); ++ if (rc < 0) ++ lp->dts_ctl.force = 0; ++ else ++ lp->dts_ctl.force = force; ++ ++ rc = of_property_read_u32(np, "ingenic,mac-autoneg", &autoneg); ++ if (rc < 0) ++ lp->dts_ctl.autoneg = 0; ++ else ++ lp->dts_ctl.autoneg = autoneg; ++ ++ rc = of_property_read_u32(np, "ingenic,mac-speed", &speed); ++ if (rc < 0) ++ lp->dts_ctl.speed = 0; ++ else ++ lp->dts_ctl.speed = speed; ++ ++ rc = of_property_read_u32(np, "ingenic,mac-duplex", &duplex); ++ if (rc < 0) ++ lp->dts_ctl.duplex = 0; ++ else ++ lp->dts_ctl.duplex = duplex; ++ ++ if (of_property_read_bool(pdev->dev.of_node, "ingenic,no_phy_connect")) ++ lp->no_phy_connect = true; ++ else ++ lp->no_phy_connect = false; ++ ++ return 0; ++} ++ ++static int ingenic_mac_probe(struct platform_device *pdev) ++{ ++ synopGMACdevice *gmacdev; ++ struct resource *r_mem = NULL; ++ struct net_device *ndev = NULL; ++ struct device_node *child = NULL; ++ struct ingenic_mac_local *lp; ++ const struct of_device_id *match; ++ const struct ingenic_gmac_priv *priv; ++ struct mii_bus *miibus; ++ char clk_gate_name[16]; ++ char clk_cgu_name[16]; ++ unsigned int phy_clk_freq; ++ int rc = 0, i; ++ ++ r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!r_mem) { ++ dev_err(&pdev->dev, "no IO resource defined.\n"); ++ return -ENXIO; ++ } ++ ++ gmacdev = devm_kzalloc(&pdev->dev, sizeof (synopGMACdevice), GFP_KERNEL); ++ if(!gmacdev) ++ return -ENOMEM; ++ ++ ndev = alloc_etherdev(sizeof(struct ingenic_mac_local)); ++ if (!ndev) { ++ dev_err(&pdev->dev, "Cannot allocate net device!\n"); ++ return -ENOMEM; ++ } ++ pdev->id = of_alias_get_id(pdev->dev.of_node, "mac"); ++ SET_NETDEV_DEV(ndev, &pdev->dev); ++ platform_set_drvdata(pdev, ndev); ++ lp = netdev_priv(ndev); ++ lp->netdev = ndev; ++ lp->pdev = pdev; ++ lp->gmacdev = gmacdev; ++ lp->id = pdev->id; ++ lp->interface = RMII; ++ lp->netdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); ++ lp->netdev->dev.dma_mask = &lp->netdev->dev.coherent_dma_mask; ++ lp->msg_enable = netif_msg_init(msg_level, INGENIC_MAC_MSG_DEFAULT); ++ ++ match = of_match_node(ingenic_mac_dt_match, pdev->dev.of_node); ++ if (!match) { ++ rc = -ENODEV; ++ goto err_out_free_netdev; ++ } ++ priv = match->data; ++ ++ lp->baseaddr = devm_ioremap_resource(&pdev->dev, r_mem); ++ if (IS_ERR(lp->baseaddr)) { ++ dev_err(&pdev->dev, "failed to map baseaddress.\n"); ++ rc = PTR_ERR(lp->baseaddr); ++ goto err_out_free_netdev; ++ } ++ ++ gmacdev->DmaBase = (u32)lp->baseaddr + DMABASE; ++ gmacdev->MacBase = (u32)lp->baseaddr + MACBASE; ++ ++ rc = get_param_from_dts(lp); ++ if(rc < 0){ ++ goto err_out_free_netdev; ++ } ++ ++ if(lp->no_phy_connect){ ++ rc = ingenic_mac_virtual_phy_init(lp); ++ if (rc < 0) { ++ dev_err(&pdev->dev, "virtual phy init failed\n"); ++ goto err_out_free_netdev; ++ } ++ } ++ ++ if(priv->support_multi_if) { ++ rc = ingenic_mac_interface_init(lp); ++ if (rc < 0) { ++ dev_err(&pdev->dev, "Interface init failed\n"); ++ goto err_out_free_netdev; ++ } ++ } ++ ++ priv->get_clk_name(lp, clk_gate_name, clk_cgu_name); ++ lp->clk_gate = devm_clk_get(&pdev->dev, clk_gate_name); ++ if (IS_ERR(lp->clk_gate)) { ++ rc = PTR_ERR(lp->clk_gate); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__,clk_gate_name); ++ goto err_out_free_netdev; ++ } ++ lp->clk_cgu = devm_clk_get(&pdev->dev, clk_cgu_name); ++ if (IS_ERR(lp->clk_cgu)) { ++ rc = PTR_ERR(lp->clk_cgu); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__,clk_cgu_name); ++ goto err_out_clk_gate_put; ++ } ++ ++ if ((rc = clk_prepare_enable(lp->clk_gate)) < 0) { ++ dev_err(&pdev->dev, "Enable gmac gate clk failed\n"); ++ goto err_out_clk_cgu_put; ++ } ++ ++ rc = of_property_read_u32(pdev->dev.of_node, "ingenic,phy-clk-freq", &phy_clk_freq); ++ if (rc < 0) { ++ phy_clk_freq = 50000000; ++ } ++ ++ if (clk_set_rate(lp->clk_cgu, phy_clk_freq) || (clk_prepare_enable(lp->clk_cgu))) { ++ dev_err(&pdev->dev, "Set cgu_mac clk rate faild\n"); ++ rc = -ENODEV; ++ goto err_out_clk_gate_disable; ++ } ++ ++ if(lp->interface == RGMII) { ++ char clk_name[16]; ++ sprintf(clk_name, "div_mactxphy%d", pdev->id); ++ lp->clk_tx = devm_clk_get(&pdev->dev, clk_name); ++ if (IS_ERR(lp->clk_tx)) { ++ rc = PTR_ERR(lp->clk_tx); ++ dev_err(&pdev->dev, "%s:can't get clk %s\n", __func__,clk_name); ++ goto err_out_clk_cgu_disable; ++ } ++ if (clk_set_rate(lp->clk_tx, 125000000) || (clk_prepare_enable(lp->clk_tx))) { ++ dev_err(&pdev->dev, "Set tx clk rate faild\n"); ++ rc = -ENODEV; ++ goto err_out_clk_tx_put; ++ } ++ } ++ ++ if (ingenic_mac_phy_hwrst(pdev, true)) { ++ rc = -ENODEV; ++ goto err_out_clk_tx_disable; ++ } ++ ++ synopGMAC_disable_interrupt_all(gmacdev); ++ ++ if (!!(child = of_get_child_by_name(pdev->dev.of_node, "mdio-gpio")) && ++ of_device_is_available(child)) { ++ if (!(lp->mii_pdev = of_platform_device_create(child, NULL, &pdev->dev))) { ++ rc = -ENODEV; ++ goto err_out_clk_cgu_disable; ++ } ++ lp->use_mdio_goio = true; ++ lp->mii_bus = platform_get_drvdata(lp->mii_pdev); ++ } else { ++ lp->use_mdio_goio = false; ++ if (!(miibus = devm_mdiobus_alloc(&pdev->dev))) { ++ rc = -ENOMEM; ++ goto err_out_clk_cgu_disable; ++ } ++ miibus->priv = lp; ++ miibus->read = ingenic_mdiobus_read; ++ miibus->write = ingenic_mdiobus_write; ++ miibus->reset = ingenic_mdiobus_reset; ++ miibus->parent = &pdev->dev; ++ miibus->name = "ingenic_mii_bus"; ++ snprintf(miibus->id, MII_BUS_ID_SIZE, "%d", lp->id); ++ for (i = 0; i < PHY_MAX_ADDR; ++i) ++ miibus->irq[i] = PHY_POLL; ++ ++ /* init MDC CLK */ ++ ingenic_set_mdc_rate(lp); ++ ++ rc = mdiobus_register(miibus); ++ if (rc) { ++ dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); ++ goto err_out_clk_cgu_disable; ++ } ++ lp->mii_bus = miibus; ++ } ++ ++ /*Lets read the version of ip in to device structure*/ ++ synopGMAC_read_version(gmacdev); ++ ++ /* configure MAC address */ ++ if (bootargs_ethaddr[pdev->id]) { ++ for (i=0; i<6; i++) { ++ ndev->dev_addr[i] = ethaddr_hex[pdev->id][i]; ++ } ++ } else { ++ random_ether_addr(ndev->dev_addr); ++ } ++ setup_mac_addr(gmacdev, ndev->dev_addr); ++ ++ rc = mii_probe(ndev); ++ if (rc) { ++ dev_err(&pdev->dev, "MII Probe failed!\n"); ++ goto err_out_miibus_unregister; ++ } ++ ++ /* Fill in the fields of the device structure with ethernet values. */ ++ ether_setup(ndev); ++ ++ ndev->netdev_ops = &ingenic_mac_netdev_ops; ++ ingenic_mac_set_ethtool_ops(ndev); ++ ++ ndev->watchdog_timeo = 2 * HZ; ++ ++ lp->mii.phy_id = lp->phydev->mdio.addr; ++ lp->mii.phy_id_mask = 0x1f; ++ lp->mii.reg_num_mask = 0x1f; ++ lp->mii.dev = ndev; ++ lp->mii.mdio_read = ingenic_mdio_phy_read; ++ lp->mii.mdio_write = ingenic_mdio_phy_write; ++ lp->mii.supports_gmii = mii_check_gmii_support(&lp->mii); ++ ++ timer_setup(&lp->watchdog_timer, ingenic_mac_watchdog, 0); ++ ++ netif_napi_add(ndev, &lp->napi, ingenic_mac_clean, 32); ++ ++#if 0 ++ hrtimer_init(&lp->rx_coalesce_timer, CLOCK_MONOTONIC, HRTIMER_MODE_PINNED); ++ lp->rx_coalesce_usecs = 200; ++ lp->rx_coalesce_timer.function = ingenic_rx_coalesce_timer_done; ++#endif ++ ++ hrtimer_init(&lp->tx_coalesce_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ lp->tx_coalesce_usecs = 300; ++ lp->tx_coalesce_timer.function = ingenic_tx_coalesce_timer_done; ++ ++ spin_lock_init(&lp->link_lock); ++ spin_lock_init(&lp->napi_poll_lock); ++ spin_lock_init(&lp->hw_lock); ++#ifdef CONFIG_INGENIC_GMAC_MUTUAL_TRANS ++ spin_lock_init(&napi_poll_lock); ++ spin_lock_init(&record_lock); ++ lp_record[lp->id] = lp; ++#endif ++ ++ INIT_WORK(&lp->reset_task, ingenic_mac_reset_task); ++ ++ /* register irq handler */ ++ rc = platform_get_irq(pdev, 0); ++ if (rc < 0) ++ goto err_out_miibus_unregister; ++ ++ rc = devm_request_irq(&pdev->dev, rc, ingenic_mac_interrupt, 0, dev_name(&pdev->dev), ndev); ++ if (rc) { ++ dev_err(&pdev->dev, "Cannot request ingenic MAC IRQ!\n"); ++ rc = -EBUSY; ++ goto err_out_miibus_unregister; ++ } ++ ++#ifdef CONFIG_INGENIC_GMAC_USE_HWSTAMP ++ rc = ingenic_phc_init(ndev, &pdev->dev); ++ if (rc) { ++ dev_err(&pdev->dev, "Cannot register PHC device!\n"); ++ goto err_out_miibus_unregister; ++ } ++#endif ++ ++ sprintf(ndev->name, "eth%d", lp->id); ++ rc = register_netdev(ndev); ++ if (rc) { ++ dev_err(&pdev->dev, "Cannot register net device!\n"); ++ goto err_out_miibus_unregister; ++ } ++ ++ sysfs_create_group(&(pdev->dev.kobj), &mac_debug_attr_group); ++ ++ dev_info(&pdev->dev, "%s, Version %s\n", INGENIC_MAC_DRV_DESC, INGENIC_MAC_DRV_VERSION); ++ return 0; ++ ++err_out_miibus_unregister: ++ if (lp->use_mdio_goio) ++ platform_device_unregister(lp->mii_pdev); ++ else ++ mdiobus_unregister(lp->mii_bus); ++err_out_clk_tx_disable: ++ if(lp->interface == RGMII) ++ clk_disable_unprepare(lp->clk_tx); ++err_out_clk_tx_put: ++ if(lp->interface == RGMII) ++ devm_clk_put(&pdev->dev, lp->clk_tx); ++err_out_clk_cgu_disable: ++ clk_disable_unprepare(lp->clk_cgu); ++err_out_clk_gate_disable: ++ clk_disable_unprepare(lp->clk_gate); ++err_out_clk_cgu_put: ++ devm_clk_put(&pdev->dev, lp->clk_cgu); ++err_out_clk_gate_put: ++ devm_clk_put(&pdev->dev, lp->clk_gate); ++err_out_free_netdev: ++ platform_set_drvdata(pdev, NULL); ++ free_netdev(ndev); ++ return rc; ++} ++ ++static int ingenic_mac_remove(struct platform_device *pdev) ++{ ++ struct net_device *ndev = platform_get_drvdata(pdev); ++ struct ingenic_mac_local *lp = netdev_priv(ndev); ++ ++ unregister_netdev(ndev); ++ ++ if (lp->use_mdio_goio) ++ platform_device_unregister(lp->mii_pdev); ++ else ++ mdiobus_unregister(lp->mii_bus); ++ ++ clk_disable_unprepare(lp->clk_cgu); ++ ++ clk_disable_unprepare(lp->clk_gate); ++ ++#ifdef CONFIG_INGENIC_GMAC_USE_HWSTAMP ++ ingenic_phc_release(lp); ++#endif ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ free_netdev(ndev); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ingenic_mac_suspend(struct platform_device *pdev, pm_message_t mesg) ++{ ++ struct net_device *net_dev = platform_get_drvdata(pdev); ++ struct ingenic_mac_local *lp = netdev_priv(net_dev); ++ ++ if (netif_running(net_dev)) ++ ingenic_mac_close(net_dev); ++ ++ clk_disable_unprepare(lp->clk_cgu); ++ ++ clk_disable_unprepare(lp->clk_gate); ++ ++ if(lp->interface == RGMII) ++ clk_disable_unprepare(lp->clk_tx); ++ ++ return 0; ++} ++ ++static int ingenic_mac_resume(struct platform_device *pdev) ++{ ++ struct net_device *net_dev = platform_get_drvdata(pdev); ++ struct ingenic_mac_local *lp = netdev_priv(net_dev); ++ ++ clk_prepare_enable(lp->clk_gate); ++ clk_prepare_enable(lp->clk_cgu); ++ if(lp->interface == RGMII) ++ clk_prepare_enable(lp->clk_tx); ++ ++ if (netif_running(net_dev)) ++ ingenic_mac_open(net_dev); ++ ++ return 0; ++} ++#else ++#define ingenic_mac_suspend NULL ++#define ingenic_mac_resume NULL ++#endif /* CONFIG_PM */ ++ ++void get_clk_name_v1(struct ingenic_mac_local *lp, char *gate_name, char *cgu_name) ++{ ++ sprintf(gate_name, "gate_mac"); ++ sprintf(cgu_name, "cgu_mac"); ++} ++ ++void get_clk_name_v2(struct ingenic_mac_local *lp, char *gate_name, char *cgu_name) ++{ ++ struct platform_device *pdev = lp->pdev; ++ sprintf(gate_name, "gate_gmac%d", pdev->id); ++ sprintf(cgu_name, "div_macphy"); ++} ++ ++void get_clk_name_v3(struct ingenic_mac_local *lp, char *gate_name, char *cgu_name) ++{ ++ sprintf(gate_name, "gate_gmac"); ++ sprintf(cgu_name, "div_macphy"); ++} ++struct ingenic_gmac_priv x1000_priv = { ++ .support_multi_if = 0, ++ .get_clk_name = get_clk_name_v1, ++}; ++ ++struct ingenic_gmac_priv x1021_priv = { ++ .support_multi_if = 0, ++ .get_clk_name = get_clk_name_v1, ++}; ++ ++struct ingenic_gmac_priv x1630_priv = { ++ .support_multi_if = 0, ++ .get_clk_name = get_clk_name_v1, ++}; ++ ++struct ingenic_gmac_priv x2000_priv = { ++ .support_multi_if = 1, ++ .get_clk_name = get_clk_name_v2, ++}; ++ ++struct ingenic_gmac_priv x2500_priv = { ++ .support_multi_if = 0, ++ .get_clk_name = get_clk_name_v3, ++}; ++ ++struct ingenic_gmac_priv m300_priv = { ++ .support_multi_if = 1, ++ .get_clk_name = get_clk_name_v2, ++}; ++ ++struct ingenic_gmac_priv x1600_priv = { ++ .support_multi_if = 0, ++ .get_clk_name = get_clk_name_v2, ++}; ++ ++static const struct of_device_id ingenic_mac_dt_match[] = { ++ { .compatible = "ingenic,x1000-mac", .data = &x1000_priv }, ++ { .compatible = "ingenic,x1021-mac", .data = &x1021_priv }, ++ { .compatible = "ingenic,x1630-mac", .data = &x1630_priv }, ++ { .compatible = "ingenic,x2000-mac", .data = &x2000_priv }, ++ { .compatible = "ingenic,x2500-mac", .data = &x2500_priv }, ++ { .compatible = "ingenic,m300-mac", .data = &m300_priv }, ++ { .compatible = "ingenic,x1600-mac", .data = &x1600_priv }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, ingenic_mac_dt_match); ++ ++static struct platform_driver ingenic_mac_driver = { ++ .driver = { ++ .name = INGENIC_MAC_DRV_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(ingenic_mac_dt_match), ++ }, ++ .probe = ingenic_mac_probe, ++ .remove = ingenic_mac_remove, ++ .resume = ingenic_mac_resume, ++ .suspend = ingenic_mac_suspend, ++}; ++module_platform_driver(ingenic_mac_driver) +diff --git a/module_drivers/drivers/net/ethernet/ingenic/ingenic_mac.h b/module_drivers/drivers/net/ethernet/ingenic/ingenic_mac.h +new file mode 100644 +index 000000000..405f81ec0 +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/ingenic/ingenic_mac.h +@@ -0,0 +1,194 @@ ++#ifndef __INGENIC_MAC_H__ ++#define __INGENIC_MAC_H__ ++ ++ ++#include ++#include ++#include ++#include ++#include "synopGMAC_Dev.h" ++ ++/* wrapper around a pointer to a socket buffer, ++ * so a DMA handle can be stored along with the buffer */ ++struct ingenic_mac_buffer { ++ struct sk_buff *skb; ++ dma_addr_t dma; ++ unsigned long time_stamp; ++ u16 length; ++ volatile u8 transfering; /* used by tx */ ++ volatile u8 invalid; /* used by rx */ ++ u16 mapped_as_page; ++ unsigned int segs; ++}; ++ ++#define INGENIC_MAC_DRV_NAME "dwc-mac" ++#define INGENIC_MAC_DRV_VERSION "1.0" ++#define INGENIC_MAC_DRV_DESC "Ingenic on-chip Ethernet MAC driver" ++ ++#define INGENIC_MAC_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP) ++ ++ ++/* TX/RX descriptor defines */ ++#define INGENIC_MAC_TX_DESC_COUNT 128 ++#define INGENIC_MAC_MAX_TXD 256 ++#define INGENIC_MAC_MIN_TXD 80 ++ ++#define INGENIC_MAC_RX_DESC_COUNT CONFIG_INGENIC_GMAC_RX_DESC_COUNT ++#define INGENIC_MAC_MAX_RXD 10240 ++#define INGENIC_MAC_MIN_RXD 80 ++ ++#define INGENIC_RX_MAX_COALESCE_USECS 200 ++#define INGENIC_RX_MIN_COALESCE_USECS 100 ++#define INGENIC_TX_MAX_COALESCE_USECS 2000 ++#define INGENIC_TX_MIN_COALESCE_USECS 200 ++ ++#define INGENIC_WAKE_IRQ_NUM 20000 ++ ++struct ingenic_mac_tx_ring { ++ /* pointer to the descriptor ring memory */ ++ DmaDesc *desc; ++ /* physical address of the descriptor ring */ ++ dma_addr_t dma; ++ /* number of descriptors in the ring */ ++ unsigned int count; ++ /* next descriptor to associate a buffer with */ ++ unsigned int next_to_use; ++ /* next descriptor to check for trans done status */ ++ unsigned int next_to_clean; ++ /* array of buffer information structs */ ++ struct ingenic_mac_buffer *buffer_info; ++}; ++ ++struct ingenic_mac_rx_ring { ++ /* pointer to the descriptor ring memory */ ++ DmaDesc *desc; ++ /* physical address of the descriptor ring */ ++ dma_addr_t dma; ++ /* number of descriptors in the ring */ ++ unsigned int count; ++ /* next descriptor to associate a buffer with */ ++ unsigned int next_to_use; ++ /* next descriptor to check for DD status bit */ ++ unsigned int next_to_clean; ++ /* array of buffer information structs */ ++ struct ingenic_mac_buffer *buffer_info; ++}; ++ ++#define INGENIC_MAC_DESC_UNUSED(R) \ ++ ((((R)->next_to_clean > (R)->next_to_use) \ ++ ? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1) ++ ++#define INGENIC_MAC_DESC_USED(R) (((R)->count - 1) - INGENIC_MAC_DESC_UNUSED(R)) ++ ++#define INGENIC_MAC_GET_DESC(R, i) (&(((DmaDesc *)((R).desc))[i])) ++#define INGENIC_MAC_RX_DESC(R, i) INGENIC_MAC_GET_DESC(R, i) ++#define INGENIC_MAC_TX_DESC(R, i) INGENIC_MAC_GET_DESC(R, i) ++ ++struct ingenic_mac_flowcontrol { ++ int autoneg; ++ int rx; ++ int rx_current; ++ int tx; ++ int tx_current; ++}; ++ ++struct ingenic_mac_dts_control { ++ unsigned int force; ++ unsigned int autoneg; ++ unsigned int speed; ++ unsigned int duplex; ++}; ++ ++struct virtual_phy{ ++ u16 reg[MII_NCONFIG + 1]; ++}; ++ ++struct ingenic_mac_local { ++ struct clk *clk_gate; ++ struct clk *clk_cgu; ++ struct clk *clk_tx; ++ void __iomem *baseaddr; ++ ++ struct ingenic_mac_tx_ring tx_ring; ++ unsigned int restart_queue; ++ u32 tx_timeout_count; ++ ++ struct timer_list watchdog_timer; ++ struct ingenic_mac_rx_ring rx_ring; ++ ++ struct napi_struct napi; ++ spinlock_t napi_poll_lock; ++ ++ struct net_device *netdev; ++ struct platform_device *pdev; ++ struct net_device_stats net_stats; ++ ++ spinlock_t stats_lock; ++ ++ atomic_t tx_fifo_used; ++ ++ unsigned char Mac[6]; /* MAC address of the board */ ++ spinlock_t link_lock; ++ ++ /* MII and PHY stuffs */ ++ int old_link; ++ int old_speed; ++ int old_duplex; ++ ++ bool no_phy_connect; ++ struct phy_device *phydev; ++ struct mii_bus *mii_bus; ++ bool use_mdio_goio; ++ struct platform_device *mii_pdev; ++ ++ u32 alloc_rx_buff_failed; ++ ++ struct work_struct reset_task; ++ struct mii_if_info mii; ++ ++ u32 msg_enable; ++ struct ingenic_mac_flowcontrol flowcontrol; ++ /* Spinlock for register read-modify-writes. */ ++ spinlock_t hw_lock; ++ ++ /*power*/ ++ int pwr_gpio; ++ u32 pwr_lvl; ++ ++ /*hw reset*/ ++ u32 reset_ms; ++ u32 reset_delay_ms; ++ int reset_gpio; ++ u32 reset_lvl; ++ int id; ++ ++ synopGMACdevice *gmacdev; ++ unsigned int interface; ++ struct ingenic_mac_dts_control dts_ctl; ++ struct virtual_phy virt_phy; ++ ++ int rx_coalesce_usecs; ++ struct hrtimer rx_coalesce_timer; ++ int tx_coalesce_usecs; ++ struct hrtimer tx_coalesce_timer; ++ unsigned long wake_irq_num; ++ ++#ifdef CONFIG_INGENIC_GMAC_USE_HWSTAMP ++ struct hwtstamp_config stamp_cfg; ++ struct ptp_clock_info caps; ++ struct ptp_clock *clock; ++ struct clk *cgu_ptp; ++ int phc_index; ++ u32 ptp_addend; ++ u32 ptp_freq; ++ spinlock_t phc_lock; ++#endif ++}; ++ ++struct ingenic_gmac_priv { ++ unsigned int support_multi_if; ++ void (*get_clk_name)(struct ingenic_mac_local *lp, char *gate_name, char *cgu_name); ++}; ++ ++void ingenic_mac_set_ethtool_ops(struct net_device *netdev); ++#endif /* __INGENIC_MAC_H__ */ +diff --git a/module_drivers/drivers/net/ethernet/ingenic/readme b/module_drivers/drivers/net/ethernet/ingenic/readme +new file mode 100644 +index 000000000..a9228c7f5 +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/ingenic/readme +@@ -0,0 +1,26 @@ ++*************************************README*************************************** ++ ++ ++********************************************************************************** ++ ++This is a README file for the sample device driver software for Synopsys Universal ++GMAC IP. The files listed below are available in this directory. ++ ++./README (this file) ++./synopGMAC_banner.h ++./synopGMAC_plat.c ++./synopGMAC_plat.h ++./synopGMAC_Dev.c ++./synopGMAC_Dev.h ++./synopGMAC_network_interface.c ++./synopGMAC_network_interface.h ++./synopGMAC_Host.c ++./synopGMAC_Host.h ++./Makefile ++./synopGMAC_Debug.c ++./synopGMAC_driver_ug.pdf ++ ++The User Guide (synopGMAC_driver_ug.pdf) provides details about driver architecture, flow ++diagrams and driver APIs. Please refer to compilation subsection of chapter 1 to compile ++the driver and the debug utility. The same section explains how to use the kernel module ++in Linux platform. +diff --git a/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_Dev.c b/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_Dev.c +new file mode 100644 +index 000000000..4a951391f +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_Dev.c +@@ -0,0 +1,3839 @@ ++/* =================================================================================== ++ * Copyright (c) <2009> Synopsys, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy of ++ * this software annotated with this license and associated documentation files ++ * (the "Software"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ++ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE ++ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * =================================================================================== */ ++ ++/** \file ++ * This file defines the synopsys GMAC device dependent functions. ++ * Most of the operations on the GMAC device are available in this file. ++ * Functions for initiliasing and accessing MAC/DMA/PHY registers and the DMA descriptors ++ * are encapsulated in this file. The functions are platform/host/OS independent. ++ * These functions in turn use the low level device dependent (HAL) functions to ++ * access the register space. ++ * \internal ++ * ------------------------REVISION HISTORY--------------------------------- ++ * Synopsys 01/Aug/2007 Created ++ */ ++#include "synopGMAC_Dev.h" ++ ++/** ++ * Function to set the MDC clock for mdio transactiona ++ * ++ * @param[in] pointer to device structure. ++ * @param[in] clk divider value. ++ * \return Reuturns 0 on success else return the error value. ++ */ ++s32 synopGMAC_set_mdc_clk_div(synopGMACdevice *gmacdev,u32 clk_div_val) ++{ ++ u32 orig_data; ++ int times = 100; ++ while(((orig_data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacGmiiAddr)) & GmiiBusy) && (times-- > 0)) { ++ printk("===>PHY busy!\n"); ++ } ++ orig_data &= (~ GmiiCsrClkMask); ++ orig_data |= clk_div_val; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiAddr ,orig_data); ++ return 0; ++} ++ ++/** ++ * Returns the current MDC divider value programmed in the ip. ++ * ++ * @param[in] pointer to device structure. ++ * @param[in] clk divider value. ++ * \return Returns the MDC divider value read. ++ */ ++u32 synopGMAC_get_mdc_clk_div(synopGMACdevice *gmacdev) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacGmiiAddr); ++ data &= GmiiCsrClkMask; ++ return data; ++} ++ ++/** ++ * struct GmiiCsrDiv ++ */ ++typedef struct GmiiCisrDivStruct { ++ u32 CsrClkDiv; ++ u32 CsrRegValue; ++} GmiiCsrDiv; ++ ++/** ++ * GmacCsrDivArray ++ * ++ * Note: ++ * GmacCsrDivArray is descending order baseed on ++ * GmacCsrDivArray.CsrClkDiv. ++ */ ++static GmiiCsrDiv GmacCsrDivArray[] = { ++ { 124, GmiiCsrClk5 }, /* sysclk is 250-300 MHz */ ++ { 102, GmiiCsrClk4 }, /* sysclk is 150-250 MHz */ ++ { 62, GmiiCsrClk1 }, /* sysclk is 100-150 MHz */ ++ { 42, GmiiCsrClk0 }, /* sysclk is 60-100 MHz */ ++ { 26, GmiiCsrClk3 }, /* sysclk is 35-60 MHz */ ++ { 16, GmiiCsrClk2 }, /* sysclk is 20-35 MHz */ ++ { 14, 0x00000034 }, ++ { 12, 0x00000030 }, ++ { 10, 0x0000002C }, ++ { 8, 0x00000028 }, ++ { 6, 0x00000024 }, ++ { 4, 0x00000020 }, ++}; ++ ++/** ++ * Function to Calculate the GMIIAddressRegister.CR[5:2] right value ++ * @sysclk[in] ++ * @max_mdcclk[in] ++ * \return Returns 0xFFFFFFFF on out of band else return a rigth value. ++ */ ++u32 synopGMAC_calculate_mdc_clk_csr(u32 sysclk, u32 max_mdcclk) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(GmacCsrDivArray); i++) { ++ if (sysclk > max_mdcclk * GmacCsrDivArray[i].CsrClkDiv) ++ return i ? GmacCsrDivArray[i - 1].CsrRegValue : ~(u32)0; ++ } ++ ++ return GmacCsrDivArray[i - 1].CsrRegValue; ++} ++ ++ ++/** ++ * Function to read the Phy register. The access to phy register ++ * is a slow process as the data is moved accross MDI/MDO interface ++ * @param[in] pointer to Register Base (It is the mac base in our case) . ++ * @param[in] PhyBase register is the index of one of supported 32 PHY devices. ++ * @param[in] Register offset is the index of one of the 32 phy register. ++ * @param[out] u16 data read from the respective phy register (only valid iff return value is 0). ++ * \return Returns 0 on success else return the error status. ++ */ ++s32 synopGMAC_read_phy_reg(synopGMACdevice *gmacdev, u32 PhyBase, u32 RegOffset, u16 * data) ++{ ++ u32 addr = 0; ++ u32 loop_variable = 0; ++ u32 *RegBase = (u32 *)gmacdev->MacBase; ++ int times = 100; ++ ++ while((synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy) && (times-- > 0)) { ++ printk("===>PHY busy!\n"); ++ } ++ ++ addr = ((PhyBase << GmiiDevShift) & GmiiDevMask) | ((RegOffset << GmiiRegShift) & GmiiRegMask); ++ addr = addr | (gmacdev->ClockDivMdc) | GmiiBusy; //Gmii busy bit ++ ++ // printk("====>PHY: addr = 0x%08x\n", addr); ++ ++ synopGMACWriteReg(RegBase,GmacGmiiAddr,addr); //write the address from where the data to be read in GmiiGmiiAddr register of synopGMAC ip ++ ++ for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){ //Wait till the busy bit gets cleared with in a certain amount of time ++ if (!(synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy)){ ++ break; ++ } ++ plat_delay(DEFAULT_DELAY_VARIABLE); ++ } ++ if(loop_variable < DEFAULT_LOOP_VARIABLE) { ++ *data = (u16)(synopGMACReadReg(RegBase,GmacGmiiData) & 0xFFFF); ++ // printk("======>PHY: data = 0x%04x\n", *data); ++ } else{ ++ printk("====>Error::: PHY not responding Busy bit didnot get cleared !!!!!!\n"); ++ return -ESYNOPGMACPHYERR; ++ } ++ return -ESYNOPGMACNOERR; ++} ++ ++/** ++ * Function to write to the Phy register. The access to phy register ++ * is a slow process as the data is moved accross MDI/MDO interface ++ * @param[in] pointer to Register Base (It is the mac base in our case) . ++ * @param[in] PhyBase register is the index of one of supported 32 PHY devices. ++ * @param[in] Register offset is the index of one of the 32 phy register. ++ * @param[in] data to be written to the respective phy register. ++ * \return Returns 0 on success else return the error status. ++ */ ++s32 synopGMAC_write_phy_reg(synopGMACdevice *gmacdev, u32 PhyBase, u32 RegOffset, u16 data) ++{ ++ u32 addr; ++ u32 loop_variable; ++ u32 *RegBase = (u32 *)gmacdev->MacBase; ++ int times = 100; ++ ++ while((synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy) && (times-- > 0)) { ++ printk("===>PHY busy!\n"); ++ } ++ synopGMACWriteReg(RegBase,GmacGmiiData,data); // write the data in to GmacGmiiData register of synopGMAC ip ++ addr = ((PhyBase << GmiiDevShift) & GmiiDevMask) | ((RegOffset << GmiiRegShift) & GmiiRegMask) | GmiiWrite; ++ ++ addr = addr | (gmacdev->ClockDivMdc) | GmiiBusy ; //set Gmii clk to 20-35 Mhz and Gmii busy bit ++ ++ times = 100; ++ while((synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy) && (times-- > 0)) { ++ printk("===>PHY busy!\n"); ++ } ++ synopGMACWriteReg(RegBase,GmacGmiiAddr,addr); ++ for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){ ++ if (!(synopGMACReadReg(RegBase,GmacGmiiAddr) & GmiiBusy)){ ++ break; ++ } ++ plat_delay(DEFAULT_DELAY_VARIABLE); ++ } ++ ++ if(loop_variable < DEFAULT_LOOP_VARIABLE){ ++ return -ESYNOPGMACNOERR; ++ } ++ else{ ++ TR("Error::: PHY not responding Busy bit didnot get cleared !!!!!!\n"); ++ return -ESYNOPGMACPHYERR; ++ } ++} ++ ++/** ++ * Function to configure the phy in loopback mode. ++ * ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] enable or disable the loopback. ++ * \return 0 on success else return the error status. ++ * \note Don't get confused with mac loop-back synopGMAC_loopback_on(synopGMACdevice *) ++ * and synopGMAC_loopback_off(synopGMACdevice *) functions. ++ */ ++s32 synopGMAC_phy_loopback(synopGMACdevice *gmacdev, bool loopback) ++{ ++ s32 status = -ESYNOPGMACNOERR; ++ if(loopback) ++ status = synopGMAC_write_phy_reg(gmacdev, gmacdev->PhyBase, PHY_CONTROL_REG, Mii_Loopback); ++ else ++ status = synopGMAC_write_phy_reg(gmacdev, gmacdev->PhyBase, PHY_CONTROL_REG, Mii_NoLoopback); ++ ++ return status; ++} ++ ++ ++ ++/** ++ * Function to read the GMAC IP Version and populates the same in device data structure. ++ * @param[in] pointer to synopGMACdevice. ++ * \return Always return 0. ++ */ ++ ++s32 synopGMAC_read_version (synopGMACdevice * gmacdev) ++{ ++ u32 data = 0; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacVersion ); ++ gmacdev->Version = data; ++ TR("The data read from %08x is %08x\n",(gmacdev->MacBase+GmacVersion),data); ++ return 0; ++} ++ ++#include ++ ++/** ++ * Function to reset the GMAC core. ++ * This reests the DMA and GMAC core. After reset all the registers holds their respective reset value ++ * @param[in] pointer to synopGMACdevice. ++ * \return 0 on success else return the error status. ++ */ ++s32 synopGMAC_reset (synopGMACdevice * gmacdev) ++{ ++ u32 data = 0; ++ int cnt = 0; ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaBusMode ,DmaResetOn); ++ plat_delay(DEFAULT_LOOP_VARIABLE); ++ ++ while (1) { ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaBusMode); ++ TR("DATA after Reset = %08x\n",data); ++ if (data & DmaResetOn) { ++ if (cnt > 500) { ++ return -1; ++ } ++ if (cnt%100 == 0) { ++ printk("Bus Mode Reg after reset: 0x%08x, cnt=%d\n", data, cnt); ++ } ++ ++ msleep(10); ++ cnt ++; ++ } else { ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++/** ++ * Function to program DMA bus mode register. ++ * ++ * The Bus Mode register is programmed with the value given. The bits to be set are ++ * bit wise or'ed and sent as the second argument to this function. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] the data to be programmed. ++ * \return 0 on success else return the error status. ++ */ ++s32 synopGMAC_dma_bus_mode_init(synopGMACdevice * gmacdev, u32 init_value ) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaBusMode ,init_value); ++ TR("bus_mode after init: 0x%08x\n", synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaBusMode)); ++ return 0; ++ ++} ++ ++/** ++ * Function to program DMA Control register. ++ * ++ * The Dma Control register is programmed with the value given. The bits to be set are ++ * bit wise or'ed and sent as the second argument to this function. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] the data to be programmed. ++ * \return 0 on success else return the error status. ++ */ ++s32 synopGMAC_dma_control_init(synopGMACdevice * gmacdev, u32 init_value) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl, init_value); ++ return 0; ++} ++ ++ ++/*Gmac configuration functions*/ ++ ++/** ++ * Enable the watchdog timer on the receiver. ++ * When enabled, Gmac enables Watchdog timer, and GMAC allows no more than ++ * 2048 bytes of data (10,240 if Jumbo frame enabled). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_wd_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacWatchdog); ++ return; ++} ++/** ++ * Disable the watchdog timer on the receiver. ++ * When disabled, Gmac disabled watchdog timer, and can receive frames up to ++ * 16,384 bytes. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_wd_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacWatchdog); ++ return; ++} ++ ++/** ++ * Enables the Jabber frame support. ++ * When cleared, GMAC enables jabber timer. It cuts of transmitter if application ++ * sends more than 2048 bytes of data (10240 if Jumbo frame enabled). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_jab_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacJabber); ++ return; ++} ++/* ++ * Disables the Jabber frame support. ++ * When set, GMAC disabled the jabber timer, and can transfer 16,384 byte frames. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_jab_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacJabber); ++ return; ++} ++ ++/** ++ * Enables Frame bursting (Only in Half Duplex Mode). ++ * When enabled, GMAC allows frame bursting in GMII Half Duplex mode. ++ * Reserved in 10/100 and Full-Duplex configurations. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_frame_burst_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacFrameBurst); ++ return; ++} ++/** ++ * Disables Frame bursting. ++ * When Disabled, frame bursting is not supported. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_frame_burst_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacFrameBurst); ++ return; ++} ++ ++/** ++ * Enable Jumbo frame support. ++ * When Enabled GMAC supports jumbo frames of 9018/9022(VLAN tagged). ++ * Giant frame error is not reported in receive frame status. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_jumbo_frame_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacJumboFrame); ++ return; ++} ++ ++/** ++ * Disable Jumbo frame support. ++ * When Disabled GMAC does not supports jumbo frames. ++ * Giant frame error is reported in receive frame status. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_jumbo_frame_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacJumboFrame); ++ return; ++} ++ ++/** ++ * ++ */ ++void synopGMAC_set_Inter_Frame_Gap(synopGMACdevice * gmacdev, u32 value) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacConfig); ++ data &= (~GmacInterFrameGap); ++ data |= value; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacConfig, data); ++ return; ++} ++ ++/** ++ * Disable Carrier sense. ++ * When Disabled GMAC ignores CRS signal during frame transmission ++ * in half duplex mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++ ++void synopGMAC_disable_crs(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDisableCrs); ++ return; ++} ++ ++ ++ ++/** ++ * Selects the GMII port. ++ * When called GMII (1000Mbps) port is selected (programmable only in 10/100/1000 Mbps configuration). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_select_gmii(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacMiiGmii); ++ return; ++} ++/** ++ * Selects the MII port. ++ * When called MII (10/100Mbps) port is selected (programmable only in 10/100/1000 Mbps configuration). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_select_mii(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacSelectMii); ++ return; ++} ++ ++/** ++ * Select the Speed 1000 Mbps ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_select_speed1000(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacMiiGmii); ++ return; ++} ++ ++ ++/** ++ * Select the Speed 100 Mbps ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_select_speed100(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacFESpeed100 | GmacSelectMii); ++ return; ++} ++ ++/** ++ * Select the Speed 10 Mbps ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_select_speed10(synopGMACdevice * gmacdev) ++{ ++ u32 regVal; ++ regVal = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacConfig); ++ regVal |= GmacSelectMii; ++ regVal &= (~GmacFESpeed100); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacConfig, regVal); ++ return; ++} ++ ++/** ++ * Enables Receive Own bit (Only in Half Duplex Mode). ++ * When enaled GMAC receives all the packets given by phy while transmitting. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_own_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRxOwn); ++ return; ++} ++/** ++ * Disables Receive Own bit (Only in Half Duplex Mode). ++ * When enaled GMAC disables the reception of frames when gmii_txen_o is asserted. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_own_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRxOwn); ++ return; ++} ++ ++/** ++ * Sets the GMAC in loopback mode. ++ * When on GMAC operates in loop-back mode at GMII/MII. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note (G)MII Receive clock is required for loopback to work properly, as transmit clock is ++ * not looped back internally. ++ */ ++void synopGMAC_loopback_on(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacLoopback); ++ return; ++} ++/** ++ * Sets the GMAC in Normal mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_loopback_off(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacLoopback); ++ return; ++} ++ ++/** ++ * Sets the GMAC core in Full-Duplex mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_set_full_duplex(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDuplex); ++ return; ++} ++/** ++ * Sets the GMAC core in Half-Duplex mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_set_half_duplex(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDuplex); ++ return; ++} ++ ++/** ++ * GMAC tries retransmission (Only in Half Duplex mode). ++ * If collision occurs on the GMII/MII, GMAC attempt retries based on the ++ * back off limit configured. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note This function is tightly coupled with synopGMAC_back_off_limit(synopGMACdev *, u32). ++ */ ++void synopGMAC_retry_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRetry); ++ return; ++} ++/** ++ * GMAC tries only one transmission (Only in Half Duplex mode). ++ * If collision occurs on the GMII/MII, GMAC will ignore the current frami ++ * transmission and report a frame abort with excessive collision in tranmit frame status. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_retry_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRetry); ++ return; ++} ++ ++/** ++ * GMAC strips the Pad/FCS field of incoming frames. ++ * This is true only if the length field value is less than or equal to ++ * 1500 bytes. All received frames with length field greater than or equal to ++ * 1501 bytes are passed to the application without stripping the Pad/FCS field. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_pad_crc_strip_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacPadCrcStrip); ++ return; ++} ++/** ++ * GMAC doesnot strips the Pad/FCS field of incoming frames. ++ * GMAC will pass all the incoming frames to Host unmodified. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_pad_crc_strip_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacPadCrcStrip); ++ return; ++} ++/** ++ * GMAC programmed with the back off limit value. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note This function is tightly coupled with synopGMAC_retry_enable(synopGMACdevice * gmacdev) ++ */ ++void synopGMAC_back_off_limit(synopGMACdevice * gmacdev, u32 value) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacConfig); ++ data &= (~GmacBackoffLimit); ++ data |= value; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacConfig,data); ++ return; ++} ++ ++/** ++ * Enables the Deferral check in GMAC (Only in Half Duplex mode) ++ * GMAC issues a Frame Abort Status, along with the excessive deferral error bit set in the ++ * transmit frame status when transmit state machine is deferred for more than ++ * - 24,288 bit times in 10/100Mbps mode ++ * - 155,680 bit times in 1000Mbps mode or Jumbo frame mode in 10/100Mbps operation. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note Deferral begins when transmitter is ready to transmit, but is prevented because of ++ * an active CRS (carrier sense) ++ */ ++void synopGMAC_deferral_check_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDeferralCheck); ++ return; ++} ++/** ++ * Disables the Deferral check in GMAC (Only in Half Duplex mode). ++ * GMAC defers until the CRS signal goes inactive. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_deferral_check_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacDeferralCheck); ++ return; ++} ++/** ++ * Enable the reception of frames on GMII/MII. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRx); ++ return; ++} ++/** ++ * Disable the reception of frames on GMII/MII. ++ * GMAC receive state machine is disabled after completion of reception of current frame. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacRx); ++ return; ++} ++/** ++ * Enable the transmission of frames on GMII/MII. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacConfig, GmacTx); ++ return; ++} ++/** ++ * Disable the transmission of frames on GMII/MII. ++ * GMAC transmit state machine is disabled after completion of transmission of current frame. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacConfig, GmacTx); ++ return; ++} ++ ++ ++/*Receive frame filter configuration functions*/ ++ ++/** ++ * Enables reception of all the frames to application. ++ * GMAC passes all the frames received to application irrespective of whether they ++ * pass SA/DA address filtering or not. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_frame_filter_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacFilter); ++ return; ++} ++/** ++ * Disables reception of all the frames to application. ++ * GMAC passes only those received frames to application which ++ * pass SA/DA address filtering. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_frame_filter_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacFilter); ++ return; ++} ++ ++/** ++ * Populates the Hash High register with the data supplied. ++ * This function is called when the Hash filtering is to be enabled. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] data to be written to hash table high register. ++ * \return void. ++ */ ++void synopGMAC_write_hash_table_high(synopGMACdevice * gmacdev, u32 data) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacHashHigh,data); ++ return; ++} ++ ++/** ++ * Populates the Hash Low register with the data supplied. ++ * This function is called when the Hash filtering is to be enabled. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] data to be written to hash table low register. ++ * \return void. ++ */ ++void synopGMAC_write_hash_table_low(synopGMACdevice * gmacdev, u32 data) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacHashLow,data); ++ return; ++} ++ ++/** ++ * Enables Hash or Perfect filter (only if Hash filter is enabled in H/W). ++ * Only frames matching either perfect filtering or Hash Filtering as per HMC and HUC ++ * configuration are sent to application. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_hash_perfect_filter_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacHashPerfectFilter); ++ return; ++} ++ ++/** ++ * Enables only Hash(only if Hash filter is enabled in H/W). ++ * Only frames matching Hash Filtering as per HMC and HUC ++ * configuration are sent to application. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_Hash_filter_only_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacHashPerfectFilter); ++ return; ++} ++ ++/** ++ * Enables Source address filtering. ++ * When enabled source address filtering is performed. Only frames matching SA filtering are passed to application with ++ * SAMatch bit of RxStatus is set. GMAC drops failed frames. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ * \note This function is overriden by synopGMAC_frame_filter_disable(synopGMACdevice *) ++ */ ++void synopGMAC_src_addr_filter_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacSrcAddrFilter); ++ return; ++} ++/** ++ * Disables Source address filtering. ++ * When disabled GMAC forwards the received frames with updated SAMatch bit in RxStatus. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_src_addr_filter_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacSrcAddrFilter); ++ return; ++} ++/** ++ * Enables Inverse Destination address filtering. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_dst_addr_filter_inverse(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacDestAddrFilterNor); ++ return; ++} ++/** ++ * Enables the normal Destination address filtering. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_dst_addr_filter_normal(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacDestAddrFilterNor); ++ return; ++} ++ ++/** ++ * Enables forwarding of control frames. ++ * When set forwards all the control frames (incl. unicast and multicast PAUSE frames). ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ * \note Depends on RFE of FlowControlRegister[2] ++ */ ++void synopGMAC_set_pass_control(synopGMACdevice * gmacdev,u32 passcontrol) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacFrameFilter); ++ data &= (~GmacPassControl); ++ data |= passcontrol; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacFrameFilter,data); ++ return; ++} ++ ++/** ++ * Enables Broadcast frames. ++ * When enabled Address filtering module passes all incoming broadcast frames. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_broadcast_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacBroadcast); ++ return; ++} ++/** ++ * Disable Broadcast frames. ++ * When disabled Address filtering module filters all incoming broadcast frames. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_broadcast_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacBroadcast); ++ return; ++} ++ ++/** ++ * Enables Multicast frames. ++ * When enabled all multicast frames are passed. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_multicast_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacMulticastFilter); ++ return; ++} ++/** ++ * Disable Multicast frames. ++ * When disabled multicast frame filtering depends on HMC bit. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_multicast_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacMulticastFilter); ++ return; ++} ++ ++/** ++ * Enables multicast hash filtering. ++ * When enabled GMAC performs teh destination address filtering according to the hash table. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_multicast_hash_filter_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacMcastHashFilter); ++ return; ++} ++/** ++ * Disables multicast hash filtering. ++ * When disabled GMAC performs perfect destination address filtering for multicast frames, it compares ++ * DA field with the value programmed in DA register. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_multicast_hash_filter_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacMcastHashFilter); ++ return; ++} ++ ++/** ++ * Enables promiscous mode. ++ * When enabled Address filter modules pass all incoming frames regardless of their Destination ++ * and source addresses. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_promisc_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacPromiscuousMode); ++ return; ++} ++/** ++ * Clears promiscous mode. ++ * When called the GMAC falls back to normal operation from promiscous mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_promisc_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacPromiscuousMode); ++ return; ++} ++ ++ ++/** ++ * Enables unicast hash filtering. ++ * When enabled GMAC performs the destination address filtering of unicast frames according to the hash table. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_unicast_hash_filter_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacUcastHashFilter); ++ return; ++} ++/** ++ * Disables multicast hash filtering. ++ * When disabled GMAC performs perfect destination address filtering for unicast frames, it compares ++ * DA field with the value programmed in DA register. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_unicast_hash_filter_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFrameFilter, GmacUcastHashFilter); ++ return; ++} ++ ++/*Flow control configuration functions*/ ++ ++/** ++ * Enables detection of pause frames with stations unicast address. ++ * When enabled GMAC detects the pause frames with stations unicast address in addition to the ++ * detection of pause frames with unique multicast address. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_unicast_pause_frame_detect_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacUnicastPauseFrame); ++ return; ++} ++/** ++ * Disables detection of pause frames with stations unicast address. ++ * When disabled GMAC only detects with the unique multicast address (802.3x). ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_unicast_pause_frame_detect_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacUnicastPauseFrame); ++ return; ++} ++/** ++ * Rx flow control enable. ++ * When Enabled GMAC will decode the rx pause frame and disable the tx for a specified time. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_rx_flow_control_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacRxFlowControl); ++ return; ++} ++/** ++ * Rx flow control disable. ++ * When disabled GMAC will not decode pause frame. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_rx_flow_control_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacRxFlowControl); ++ return; ++} ++/** ++ * Tx flow control enable. ++ * When Enabled ++ * - In full duplex GMAC enables flow control operation to transmit pause frames. ++ * - In Half duplex GMAC enables the back pressure operation ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_tx_flow_control_enable(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacTxFlowControl); ++ return; ++} ++ ++/** ++ * Tx flow control disable. ++ * When Disabled ++ * - In full duplex GMAC will not transmit any pause frames. ++ * - In Half duplex GMAC disables the back pressure feature. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_tx_flow_control_disable(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacTxFlowControl); ++ return; ++} ++ ++/** ++ * Initiate Flowcontrol operation. ++ * When Set ++ * - In full duplex GMAC initiates pause control frame. ++ * - In Half duplex GMAC initiates back pressure function. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_tx_activate_flow_control(synopGMACdevice * gmacdev) ++{ ++ //In case of full duplex check for this bit to b'0. if it is read as b'1 indicates that ++ //control frame transmission is in progress. ++ if(gmacdev->Speed == FULLDUPLEX){ ++ if(!synopGMACCheckBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure)) ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure); ++ } ++ else{ //if half duplex mode ++ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure); ++ } ++ ++ return; ++} ++ ++/** ++ * stops Flowcontrol operation. ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_tx_deactivate_flow_control(synopGMACdevice * gmacdev) ++{ ++ //In full duplex this bit is automatically cleared after transmitting a pause control frame. ++ if(gmacdev->Speed == HALFDUPLEX){ ++ synopGMACSetBits((u32 *)gmacdev->MacBase, GmacFlowControl, GmacFlowControlBackPressure); ++ } ++ return; ++} ++ ++/** ++ * This enables the pause frame generation after programming the appropriate registers. ++ * presently activation is set at 3k and deactivation set at 4k. These may have to tweaked ++ * if found any issues ++ * @param[in] pointer to synopGMACdevice. ++ * \return void. ++ */ ++void synopGMAC_pause_control(synopGMACdevice *gmacdev) ++{ ++ u32 omr_reg; ++ u32 mac_flow_control_reg; ++ omr_reg = synopGMACReadReg((u32 *)gmacdev->DmaBase,DmaControl); ++ omr_reg |= DmaRxFlowCtrlAct3K | DmaRxFlowCtrlDeact4K |DmaEnHwFlowCtrl; ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl, omr_reg); ++ ++ mac_flow_control_reg = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacFlowControl); ++ mac_flow_control_reg |= GmacRxFlowControl | GmacTxFlowControl | 0xFFFF0000; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacFlowControl,mac_flow_control_reg); ++ ++ return; ++ ++} ++ ++/** ++ * Example mac initialization sequence. ++ * This function calls the initialization routines to initialize the GMAC register. ++ * One can change the functions invoked here to have different configuration as per the requirement ++ * @param[in] pointer to synopGMACdevice. ++ * \return Returns 0 on success. ++ */ ++s32 synopGMAC_mac_init(synopGMACdevice * gmacdev) ++{ ++ u32 PHYreg; ++ ++ printk("=====>enter %s:%d\n", __func__, __LINE__); ++ ++ if(gmacdev->DuplexMode == FULLDUPLEX){ ++ printk("=====>full duplex\n"); ++ ++ synopGMAC_wd_enable(gmacdev); ++ //synopGMAC_jab_enable(gmacdev); ++ synopGMAC_frame_burst_enable(gmacdev); ++ synopGMAC_jumbo_frame_disable(gmacdev); ++ synopGMAC_rx_own_enable(gmacdev); ++ synopGMAC_loopback_off(gmacdev); ++ synopGMAC_set_full_duplex(gmacdev); ++ synopGMAC_retry_enable(gmacdev); ++ synopGMAC_pad_crc_strip_disable(gmacdev); ++ synopGMAC_back_off_limit(gmacdev,GmacBackoffLimit0); ++ synopGMAC_deferral_check_disable(gmacdev); ++ synopGMAC_tx_enable(gmacdev); ++ synopGMAC_rx_enable(gmacdev); ++ ++ if(gmacdev->Speed == SPEED1000) { ++ printk("=====>1000M\n"); ++ synopGMAC_select_gmii(gmacdev); ++ } else { ++ printk("=====>100M\n"); ++ synopGMAC_select_mii(gmacdev); ++ } ++ ++ /*Frame Filter Configuration*/ ++ synopGMAC_frame_filter_enable(gmacdev); ++ synopGMAC_set_pass_control(gmacdev,GmacPassControl0); ++ synopGMAC_broadcast_enable(gmacdev); ++ synopGMAC_src_addr_filter_disable(gmacdev); ++ synopGMAC_multicast_disable(gmacdev); ++ synopGMAC_dst_addr_filter_normal(gmacdev); ++ synopGMAC_multicast_hash_filter_disable(gmacdev); ++ synopGMAC_promisc_disable(gmacdev); ++ synopGMAC_unicast_hash_filter_disable(gmacdev); ++ ++ /*Flow Control Configuration*/ ++ synopGMAC_unicast_pause_frame_detect_disable(gmacdev); ++#if 0 ++ synopGMAC_rx_flow_control_enable(gmacdev); ++ synopGMAC_tx_flow_control_enable(gmacdev); ++#else ++ synopGMAC_rx_flow_control_disable(gmacdev); ++ synopGMAC_tx_flow_control_disable(gmacdev); ++#endif ++ } ++ else{//for Half Duplex configuration ++ printk("====>half duplex\n"); ++ ++ synopGMAC_wd_enable(gmacdev); ++ synopGMAC_jab_enable(gmacdev); ++ synopGMAC_frame_burst_enable(gmacdev); ++ synopGMAC_jumbo_frame_disable(gmacdev); ++ synopGMAC_rx_own_enable(gmacdev); ++ synopGMAC_loopback_off(gmacdev); ++ synopGMAC_set_half_duplex(gmacdev); ++ synopGMAC_retry_enable(gmacdev); ++ synopGMAC_pad_crc_strip_disable(gmacdev); ++ synopGMAC_back_off_limit(gmacdev,GmacBackoffLimit0); ++ synopGMAC_deferral_check_disable(gmacdev); ++ synopGMAC_tx_enable(gmacdev); ++ synopGMAC_rx_enable(gmacdev); ++ ++ if(gmacdev->Speed == SPEED1000) ++ synopGMAC_select_gmii(gmacdev); ++ else ++ synopGMAC_select_mii(gmacdev); ++ ++ /*Frame Filter Configuration*/ ++ synopGMAC_frame_filter_enable(gmacdev); ++ synopGMAC_set_pass_control(gmacdev,GmacPassControl0); ++ synopGMAC_broadcast_enable(gmacdev); ++ synopGMAC_src_addr_filter_disable(gmacdev); ++ synopGMAC_multicast_disable(gmacdev); ++ synopGMAC_dst_addr_filter_normal(gmacdev); ++ synopGMAC_multicast_hash_filter_disable(gmacdev); ++ synopGMAC_promisc_disable(gmacdev); ++ synopGMAC_unicast_hash_filter_disable(gmacdev); ++ ++ /*Flow Control Configuration*/ ++ synopGMAC_unicast_pause_frame_detect_disable(gmacdev); ++ synopGMAC_rx_flow_control_disable(gmacdev); ++ synopGMAC_tx_flow_control_disable(gmacdev); ++ ++ /*To set PHY register to enable CRS on Transmit*/ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiAddr, GmiiBusy | 0x00000408); ++ PHYreg = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacGmiiData); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiData, PHYreg | 0x00000800); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacGmiiAddr, GmiiBusy | 0x0000040a); ++ } ++ return 0; ++} ++ ++s32 synopGMAC_search_phy (synopGMACdevice * gmacdev) { ++ int phy_id = 0; ++ u16 data; ++ s32 status = -ESYNOPGMACNOERR; ++ ++ for (phy_id = 0; phy_id < 32; phy_id++) { ++ status = synopGMAC_read_phy_reg(gmacdev, phy_id, PHY_STATUS_REG, &data); ++ if ( (!status) && (data != 0xffff)) { ++ if((data & Mii_AutoNegCmplt) != 0){ ++ printk("====>phy %d Autonegotiation Complete\n", phy_id); ++ break; ++ } ++ } ++ } ++ ++ return (phy_id < 32) ? phy_id : -ESYNOPGMACPHYERR; ++} ++ ++/** ++ * Checks and initialze phy. ++ * This function checks whether the phy initialization is complete. ++ * @param[in] pointer to synopGMACdevice. ++ * \return 0 if success else returns the error number. ++ */ ++#if 0 ++s32 synopGMAC_check_phy_init (synopGMACdevice * gmacdev) ++{ ++ //u32 addr; ++ u16 data; ++ s32 status = -ESYNOPGMACNOERR; ++ s32 loop_count; ++ ++ loop_count = DEFAULT_LOOP_VARIABLE; ++ while(loop_count-- > 0) ++ { ++ ++ status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_STATUS_REG, &data); ++ if(status) ++ return status; ++ ++ if((data & Mii_AutoNegCmplt) != 0){ ++ TR("Autonegotiation Complete\n"); ++ break; ++ } ++ } ++ ++ status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_SPECIFIC_STATUS_REG, &data); ++ if(status) ++ return status; ++ ++ if((data & Mii_phy_status_link_up) == 0){ ++ TR("No Link\n"); ++ gmacdev->LinkState = LINKDOWN; ++ return -ESYNOPGMACPHYERR; ++ } ++ else{ ++ gmacdev->LinkState = LINKUP; ++ TR("Link UP\n"); ++ } ++ ++ status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_SPECIFIC_STATUS_REG, &data); ++ if(status) ++ return status; ++ ++ ++ ++ gmacdev->DuplexMode = (data & Mii_phy_status_full_duplex) ? FULLDUPLEX: HALFDUPLEX ; ++ TR("Link is up in %s mode\n",(gmacdev->DuplexMode == FULLDUPLEX) ? "FULL DUPLEX": "HALF DUPLEX"); ++ ++ /*if not set to Master configuration in case of Half duplex mode set it manually as Master*/ ++ if(gmacdev->DuplexMode == HALFDUPLEX){ ++ printk("=========>enter %s:%d\n", __func__, __LINE__); ++ status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_CONTROL_REG, &data); ++ if(status) ++ return status; ++ ++ status = synopGMAC_write_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_CONTROL_REG, data | Mii_Manual_Master_Config ); ++ if(status) ++ return status; ++ } ++ ++ status = synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase,gmacdev->PhyBase,PHY_SPECIFIC_STATUS_REG, &data); ++ if(status) ++ return status; ++ if(data & Mii_phy_status_speed_1000) ++ gmacdev->Speed = SPEED1000; ++ else if(data & Mii_phy_status_speed_100) ++ gmacdev->Speed = SPEED100; ++ else ++ gmacdev->Speed = SPEED10; ++ ++ if(gmacdev->Speed == SPEED1000) ++ TR("Link is with 1000M Speed \n"); ++ if(gmacdev->Speed == SPEED100) ++ TR("Link is with 100M Speed \n"); ++ if(gmacdev->Speed == SPEED10) ++ TR("Link is with 10M Speed \n"); ++ ++ return -ESYNOPGMACNOERR; ++} ++#else ++s32 synopGMAC_check_phy_init (synopGMACdevice * gmacdev) { ++ gmacdev->LinkState = LINKUP; ++ gmacdev->DuplexMode = FULLDUPLEX; ++ gmacdev->Speed = SPEED100; ++ ++ return -ESYNOPGMACNOERR; ++} ++#endif ++ ++/** ++ * Sets the Mac address in to GMAC register. ++ * This function sets the MAC address to the MAC register in question. ++ * @param[in] pointer to synopGMACdevice to populate mac dma and phy addresses. ++ * @param[in] Register offset for Mac address high ++ * @param[in] Register offset for Mac address low ++ * @param[in] buffer containing mac address to be programmed. ++ * \return 0 upon success. Error code upon failure. ++ */ ++s32 synopGMAC_set_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr) ++{ ++ u32 data; ++ ++ data = (MacAddr[5] << 8) | MacAddr[4]; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,MacHigh,data); ++ data = (MacAddr[3] << 24) | (MacAddr[2] << 16) | (MacAddr[1] << 8) | MacAddr[0] ; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,MacLow,data); ++ return 0; ++} ++ ++ ++/** ++ * Get the Mac address in to the address specified. ++ * The mac register contents are read and written to buffer passed. ++ * @param[in] pointer to synopGMACdevice to populate mac dma and phy addresses. ++ * @param[in] Register offset for Mac address high ++ * @param[in] Register offset for Mac address low ++ * @param[out] buffer containing the device mac address. ++ * \return 0 upon success. Error code upon failure. ++ */ ++s32 synopGMAC_get_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr) ++{ ++ u32 data; ++ ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase,MacHigh); ++ MacAddr[5] = (data >> 8) & 0xff; ++ MacAddr[4] = (data) & 0xff; ++ ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase,MacLow); ++ MacAddr[3] = (data >> 24) & 0xff; ++ MacAddr[2] = (data >> 16) & 0xff; ++ MacAddr[1] = (data >> 8 ) & 0xff; ++ MacAddr[0] = (data ) & 0xff; ++ ++ return 0; ++} ++ ++ ++/** ++ * Attaches the synopGMAC device structure to the hardware. ++ * Device structure is populated with MAC/DMA and PHY base addresses. ++ * @param[in] pointer to synopGMACdevice to populate mac dma and phy addresses. ++ * @param[in] GMAC IP mac base address. ++ * @param[in] GMAC IP dma base address. ++ * @param[in] GMAC IP phy base address. ++ * \return 0 upon success. Error code upon failure. ++ * \note This is important function. No kernel api provided by Synopsys ++ */ ++ ++s32 synopGMAC_attach (synopGMACdevice * gmacdev, u32 macBase, u32 dmaBase, u32 phyBase) ++{ ++ u8 mac_addr0[6] = DEFAULT_MAC_ADDRESS; ++ /*Make sure the Device data strucure is cleared before we proceed further*/ ++ memset((void *) gmacdev,0,sizeof(synopGMACdevice)); ++ /*Populate the mac and dma base addresses*/ ++ gmacdev->MacBase = macBase; ++ gmacdev->DmaBase = dmaBase; ++ gmacdev->PhyBase = phyBase; ++ ++ printk("=======>MacBase = 0x%08x, DmaBase = 0x%08x PhyBase = 0x%08x\n", ++ gmacdev->MacBase, gmacdev->DmaBase, gmacdev->PhyBase); ++ ++ /* Program/flash in the station/IP's Mac address */ ++ synopGMAC_set_mac_addr(gmacdev,GmacAddr0High,GmacAddr0Low, mac_addr0); ++ ++ return 0; ++} ++ ++ ++ ++/** ++ * Initialize the rx descriptors for ring or chain mode operation. ++ * - Status field is initialized to 0. ++ * - EndOfRing set for the last descriptor. ++ * - buffer1 and buffer2 set to 0 for ring mode of operation. (note) ++ * - data1 and data2 set to 0. (note) ++ * @param[in] pointer to DmaDesc structure. ++ * @param[in] whether end of ring ++ * \return void. ++ * \note Initialization of the buffer1, buffer2, data1,data2 and status are not done here. This only initializes whether one wants to use this descriptor ++ * in chain mode or ring mode. For chain mode of operation the buffer2 and data2 are programmed before calling this function. ++ */ ++void synopGMAC_rx_desc_init_ring(DmaDesc *desc, bool last_ring_desc) ++{ ++ desc->status = 0; ++ desc->length = last_ring_desc ? RxDescEndOfRing : 0; ++ desc->buffer1 = 0; ++ desc->buffer2 = 0; ++ desc->data1 = 0; ++ desc->data2 = 0; ++ return; ++} ++/** ++ * Initialize the tx descriptors for ring or chain mode operation. ++ * - Status field is initialized to 0. ++ * - EndOfRing set for the last descriptor. ++ * - buffer1 and buffer2 set to 0 for ring mode of operation. (note) ++ * - data1 and data2 set to 0. (note) ++ * @param[in] pointer to DmaDesc structure. ++ * @param[in] whether end of ring ++ * \return void. ++ * \note Initialization of the buffer1, buffer2, data1,data2 and status are not done here. This only initializes whether one wants to use this descriptor ++ * in chain mode or ring mode. For chain mode of operation the buffer2 and data2 are programmed before calling this function. ++ */ ++void synopGMAC_tx_desc_init_ring(DmaDesc *desc, bool last_ring_desc) ++{ ++#ifdef ENH_DESC ++ desc->status = last_ring_desc? TxDescEndOfRing : 0; ++ desc->length = 0; ++#else ++ desc->length = last_ring_desc? TxDescEndOfRing : 0; ++#endif ++ desc->buffer1 = 0; ++ desc->buffer2 = 0; ++ desc->data1 = 0; ++ desc->data2 = 0; ++ return; ++} ++ ++ ++ ++/** ++ * Initialize the rx descriptors for chain mode of operation. ++ * - Status field is initialized to 0. ++ * - EndOfRing set for the last descriptor. ++ * - buffer1 and buffer2 set to 0. ++ * - data1 and data2 set to 0. ++ * @param[in] pointer to DmaDesc structure. ++ * @param[in] whether end of ring ++ * \return void. ++ */ ++ ++void synopGMAC_rx_desc_init_chain(DmaDesc * desc) ++{ ++ desc->status = 0; ++ desc->length = RxDescChain; ++ desc->buffer1 = 0; ++ desc->data1 = 0; ++ return; ++} ++/** ++ * Initialize the rx descriptors for chain mode of operation. ++ * - Status field is initialized to 0. ++ * - EndOfRing set for the last descriptor. ++ * - buffer1 and buffer2 set to 0. ++ * - data1 and data2 set to 0. ++ * @param[in] pointer to DmaDesc structure. ++ * @param[in] whether end of ring ++ * \return void. ++ */ ++void synopGMAC_tx_desc_init_chain(DmaDesc * desc) ++{ ++#ifdef ENH_DESC ++ desc->status = TxDescChain; ++ desc->length = 0; ++#else ++ desc->length = TxDescChain; ++#endif ++ desc->buffer1 = 0; ++ desc->data1 = 0; ++ return; ++} ++ ++ ++s32 synopGMAC_init_tx_rx_desc_queue(synopGMACdevice *gmacdev) ++{ ++ s32 i; ++ for(i =0; i < gmacdev -> TxDescCount; i++){ ++ synopGMAC_tx_desc_init_ring(gmacdev->TxDesc + i, i == gmacdev->TxDescCount-1); ++ } ++ TR("At line %d\n",__LINE__); ++ for(i =0; i < gmacdev -> RxDescCount; i++){ ++ synopGMAC_rx_desc_init_ring(gmacdev->RxDesc + i, i == gmacdev->RxDescCount-1); ++ } ++ ++ gmacdev->TxNext = 0; ++ gmacdev->TxBusy = 0; ++ gmacdev->RxNext = 0; ++ gmacdev->RxBusy = 0; ++ ++ return -ESYNOPGMACNOERR; ++} ++/** ++ * Programs the DmaRxBaseAddress with the Rx descriptor base address. ++ * Rx Descriptor's base address is available in the gmacdev structure. This function progrms the ++ * Dma Rx Base address with the starting address of the descriptor ring or chain. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_init_rx_desc_base(synopGMACdevice *gmacdev) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase,DmaRxBaseAddr,(u32)gmacdev->RxDescDma); ++ return; ++} ++ ++/** ++ * Programs the DmaTxBaseAddress with the Tx descriptor base address. ++ * Tx Descriptor's base address is available in the gmacdev structure. This function progrms the ++ * Dma Tx Base address with the starting address of the descriptor ring or chain. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_init_tx_desc_base(synopGMACdevice *gmacdev) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase,DmaTxBaseAddr,(u32)gmacdev->TxDescDma); ++ return; ++} ++ ++ ++/** ++ * Makes the Dma as owner for this descriptor. ++ * This function sets the own bit of status field of the DMA descriptor, ++ * indicating the DMA is the owner for this descriptor. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns void. ++ */ ++void synopGMAC_set_owner_dma(DmaDesc *desc) ++{ ++ desc->status |= DescOwnByDma; ++} ++ ++/** ++ * set tx descriptor to indicate SOF. ++ * This Descriptor contains the start of ethernet frame. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns void. ++ */ ++void synopGMAC_set_desc_sof(DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status |= DescTxFirst;//ENH_DESC ++#else ++ desc->length |= DescTxFirst; ++#endif ++ ++} ++ ++/** ++ * set tx descriptor to indicate EOF. ++ * This descriptor contains the End of ethernet frame. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns void. ++ */ ++void synopGMAC_set_desc_eof(DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status |= DescTxLast;//ENH_DESC ++#else ++ desc->length |= DescTxLast; ++#endif ++} ++ ++ ++/** ++ * checks whether this descriptor contains start of frame. ++ * This function is to check whether the descriptor's data buffer ++ * contains a fresh ethernet frame? ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if SOF in current descriptor, else returns fail. ++ */ ++bool synopGMAC_is_sof_in_rx_desc(DmaDesc *desc) ++{ ++ return ((desc->status & DescRxFirst) == DescRxFirst); ++} ++ ++/** ++ * checks whether this descriptor contains end of frame. ++ * This function is to check whether the descriptor's data buffer ++ * contains end of ethernet frame? ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if SOF in current descriptor, else returns fail. ++ */ ++bool synopGMAC_is_eof_in_rx_desc(DmaDesc *desc) ++{ ++ return ((desc->status & DescRxLast) == DescRxLast); ++} ++ ++/** ++ * checks whether destination address filter failed in the rx frame. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if Failed, false if not. ++ */ ++bool synopGMAC_is_da_filter_failed(DmaDesc *desc) ++{ ++ return ((desc->status & DescDAFilterFail) == DescDAFilterFail); ++} ++ ++/** ++ * checks whether source address filter failed in the rx frame. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if Failed, false if not. ++ */ ++bool synopGMAC_is_sa_filter_failed(DmaDesc *desc) ++{ ++ return ((desc->status & DescSAFilterFail) == DescSAFilterFail); ++} ++ ++/** ++ * Checks whether the descriptor is owned by DMA. ++ * If descriptor is owned by DMA then the OWN bit is set to 1. This API is same for both ring and chain mode. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if Dma owns descriptor and false if not. ++ */ ++bool synopGMAC_is_desc_owned_by_dma(DmaDesc *desc) ++{ ++ return ((desc->status & DescOwnByDma) == DescOwnByDma ); ++} ++ ++/** ++ * returns the byte length of received frame including CRC. ++ * This returns the no of bytes received in the received ethernet frame including CRC(FCS). ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns the length of received frame lengths in bytes. ++ */ ++u32 synopGMAC_get_rx_desc_frame_length(u32 status) ++{ ++ return ((status & DescFrameLengthMask) >> DescFrameLengthShift); ++} ++ ++/** ++ * Checks whether the descriptor is valid ++ * if no errors such as CRC/Receive Error/Watchdog Timeout/Late collision/Giant Frame/Overflow/Descriptor ++ * error the descritpor is said to be a valid descriptor. ++ * @param[in] pointer to DmaDesc structure. ++ * \return True if desc valid. false if error. ++ */ ++bool synopGMAC_is_desc_valid(u32 status) ++{ ++ return ((status & DescError) == 0); ++} ++ ++/** ++ * Checks whether the descriptor is empty. ++ * If the buffer1 and buffer2 lengths are zero in ring mode descriptor is empty. ++ * In chain mode buffer2 length is 0 but buffer2 itself contains the next descriptor address. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if descriptor is empty, false if not empty. ++ */ ++bool synopGMAC_is_desc_empty(DmaDesc *desc) ++{ ++ //if both the buffer1 length and buffer2 length are zero desc is empty ++ return(((desc->length & DescSize1Mask) == 0) && ((desc->length & DescSize2Mask) == 0) ); ++} ++ ++ ++/** ++ * Checks whether the rx descriptor is valid. ++ * if rx descripor is not in error and complete frame is available in the same descriptor ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if no error and first and last desc bits are set, otherwise it returns false. ++ */ ++bool synopGMAC_is_rx_desc_valid(u32 status) ++{ ++ return ((status & DescError) == 0) && ((status & DescRxFirst) == DescRxFirst) && ((status & DescRxLast) == DescRxLast); ++} ++ ++/** ++ * Checks whether the tx is aborted due to collisions. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if collisions, else returns false. ++ */ ++bool synopGMAC_is_tx_aborted(u32 status) ++{ ++ return (((status & DescTxLateCollision) == DescTxLateCollision) | ((status & DescTxExcCollisions) == DescTxExcCollisions)); ++ ++} ++ ++/** ++ * Checks whether the tx carrier error. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if carrier error occured, else returns falser. ++ */ ++bool synopGMAC_is_tx_carrier_error(u32 status) ++{ ++ return (((status & DescTxLostCarrier) == DescTxLostCarrier) | ((status & DescTxNoCarrier) == DescTxNoCarrier)); ++} ++ ++ ++/** ++ * Gives the transmission collision count. ++ * returns the transmission collision count indicating number of collisions occured before the frame was transmitted. ++ * Make sure to check excessive collision didnot happen to ensure the count is valid. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns the count value of collision. ++ */ ++u32 synopGMAC_get_tx_collision_count(u32 status) ++{ ++ return ((status & DescTxCollMask) >> DescTxCollShift); ++} ++u32 synopGMAC_is_exc_tx_collisions(u32 status) ++{ ++ return ((status & DescTxExcCollisions) == DescTxExcCollisions); ++} ++ ++ ++/** ++ * Check for damaged frame due to overflow or collision. ++ * Retruns true if rx frame was damaged due to buffer overflow in MTL or late collision in half duplex mode. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if error else returns false. ++ */ ++bool synopGMAC_is_rx_frame_damaged(u32 status) ++{ ++ //bool synopGMAC_dma_rx_collisions(u32 status) ++ return (((status & DescRxDamaged) == DescRxDamaged) | ((status & DescRxCollision) == DescRxCollision)); ++} ++ ++/** ++ * Check for damaged frame due to collision. ++ * Retruns true if rx frame was damaged due to late collision in half duplex mode. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if error else returns false. ++ */ ++bool synopGMAC_is_rx_frame_collision(u32 status) ++{ ++ //bool synopGMAC_dma_rx_collisions(u32 status) ++ return ((status & DescRxCollision) == DescRxCollision); ++} ++ ++/** ++ * Check for receive CRC error. ++ * Retruns true if rx frame CRC error occured. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if error else returns false. ++ */ ++bool synopGMAC_is_rx_crc(u32 status) ++{ ++ //u32 synopGMAC_dma_rx_crc(u32 status) ++ return ((status & DescRxCrc) == DescRxCrc); ++} ++ ++/** ++ * Indicates rx frame has non integer multiple of bytes. (odd nibbles). ++ * Retruns true if dribbling error in rx frame. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if error else returns false. ++ */ ++bool synopGMAC_is_frame_dribbling_errors(u32 status) ++{ ++ //u32 synopGMAC_dma_rx_frame_errors(u32 status) ++ return ((status & DescRxDribbling) == DescRxDribbling); ++} ++ ++/** ++ * Indicates error in rx frame length. ++ * Retruns true if received frame length doesnot match with the length field ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if error else returns false. ++ */ ++bool synopGMAC_is_rx_frame_length_errors(u32 status) ++{ ++ //u32 synopGMAC_dma_rx_length_errors(u32 status) ++ return((status & DescRxLengthError) == DescRxLengthError); ++} ++ ++/** ++ * Checks whether this rx descriptor is last rx descriptor. ++ * This returns true if it is last descriptor either in ring mode or in chain mode. ++ * @param[in] pointer to devic structure. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if it is last descriptor, false if not. ++ * \note This function should not be called before initializing the descriptor using synopGMAC_desc_init(). ++ */ ++bool synopGMAC_is_last_rx_desc(synopGMACdevice * gmacdev,DmaDesc *desc) ++{ ++ //bool synopGMAC_is_last_desc(DmaDesc *desc) ++ return (((desc->length & RxDescEndOfRing) == RxDescEndOfRing) || ((u32)gmacdev->RxDesc == desc->data2)); ++} ++ ++/** ++ * Checks whether this tx descriptor is last tx descriptor. ++ * This returns true if it is last descriptor either in ring mode or in chain mode. ++ * @param[in] pointer to devic structure. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if it is last descriptor, false if not. ++ * \note This function should not be called before initializing the descriptor using synopGMAC_desc_init(). ++ */ ++bool synopGMAC_is_last_tx_desc(synopGMACdevice * gmacdev,DmaDesc *desc) ++{ ++ //bool synopGMAC_is_last_desc(DmaDesc *desc) ++#ifdef ENH_DESC ++ return (((desc->status & TxDescEndOfRing) == TxDescEndOfRing) || ((u32)gmacdev->TxDesc == desc->data2)); ++#else ++ return (((desc->length & TxDescEndOfRing) == TxDescEndOfRing) || ((u32)gmacdev->TxDesc == desc->data2)); ++#endif ++} ++ ++/** ++ * Checks whether this rx descriptor is in chain mode. ++ * This returns true if it is this descriptor is in chain mode. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if chain mode is set, false if not. ++ */ ++bool synopGMAC_is_rx_desc_chained(DmaDesc * desc) ++{ ++ return((desc->length & RxDescChain) == RxDescChain); ++} ++ ++/** ++ * Checks whether this tx descriptor is in chain mode. ++ * This returns true if it is this descriptor is in chain mode. ++ * @param[in] pointer to DmaDesc structure. ++ * \return returns true if chain mode is set, false if not. ++ */ ++bool synopGMAC_is_tx_desc_chained(DmaDesc * desc) ++{ ++#ifdef ENH_DESC ++ return((desc->status & TxDescChain) == TxDescChain); ++#else ++ return((desc->length & TxDescChain) == TxDescChain); ++#endif ++} ++ ++/** ++ * Driver Api to get the descriptor field information. ++ * This returns the status, dma-able address of buffer1, the length of buffer1, virtual address of buffer1 ++ * dma-able address of buffer2, length of buffer2, virtural adddress of buffer2. ++ * @param[in] pointer to DmaDesc structure. ++ * @param[out] pointer to status field fo descriptor. ++ * @param[out] dma-able address of buffer1. ++ * @param[out] length of buffer1. ++ * @param[out] virtual address of buffer1. ++ * @param[out] dma-able address of buffer2. ++ * @param[out] length of buffer2. ++ * @param[out] virtual address of buffer2. ++ * \return returns void. ++ */ ++void synopGMAC_get_desc_data(DmaDesc * desc, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2) ++{ ++ ++ if(Status != 0) ++ *Status = desc->status; ++ ++ if(Buffer1 != 0) ++ *Buffer1 = desc->buffer1; ++ if(Length1 != 0) ++ *Length1 = (desc->length & DescSize1Mask) >> DescSize1Shift; ++ if(Data1 != 0) ++ *Data1 = desc->data1; ++ ++ if(Buffer2 != 0) ++ *Buffer2 = desc->buffer2; ++ if(Length2 != 0) ++ *Length2 = (desc->length & DescSize2Mask) >> DescSize2Shift; ++ if(Data1 != 0) ++ *Data2 = desc->data2; ++ ++ return; ++ ++} ++#ifdef AVB_SUPPORT ++void synopGMAC_set_desc_data(DmaDesc *txdesc, u32 Status, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2) ++{ ++ TR("s:%08x B1:%08x L1:%08x D1: %08x B2: %08x L2: %08x D2: %08x\n",Status,Buffer1,Length1,Data1,Buffer2,Length2,Data2); ++ ++ txdesc->length = (((Length1 <status |= (DescTxFirst | DescTxLast | DescTxIntEnable | Status ); //ENH_DESC ++#else ++ txdesc->length |= (DescTxFirst | DescTxLast | DescTxIntEnable ); //Its always assumed that complete data will fit in to one descriptor ++#endif ++ ++ txdesc->buffer1 = Buffer1; ++ txdesc->data1 = Data1; ++ ++ txdesc->buffer2 = Buffer2; ++ txdesc->data2 = Data2; ++ ++#ifdef ENH_DESC ++ txdesc->status |= DescOwnByDma;//ENH_DESC ++#else ++ txdesc->status = DescOwnByDma; ++#endif ++} ++#endif ++ ++#ifdef ENH_DESC_8W ++/** ++ * This function is defined two times. Once when the code is compiled for ENHANCED DESCRIPTOR SUPPORT and Once for Normal descriptor ++ * Get the index and address of Tx desc. ++ * This api is same for both ring mode and chain mode. ++ * This function tracks the tx descriptor the DMA just closed after the transmission of data from this descriptor is ++ * over. This returns the descriptor fields to the caller. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[out] status field of the descriptor. ++ * @param[out] Dma-able buffer1 pointer. ++ * @param[out] length of buffer1 (Max is 2048). ++ * @param[out] virtual pointer for buffer1. ++ * @param[out] Dma-able buffer2 pointer. ++ * @param[out] length of buffer2 (Max is 2048). ++ * @param[out] virtual pointer for buffer2. ++ * @param[out] u32 data indicating whether the descriptor is in ring mode or chain mode. ++ * \return returns present tx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_get_tx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2, ++ u32 * Ext_Status, u32 * Time_Stamp_High, u32 * Time_Stamp_Low) ++{ ++ u32 txover = gmacdev->TxBusy; ++ DmaDesc * txdesc = gmacdev->TxBusyDesc; ++ ++ if(synopGMAC_is_desc_owned_by_dma(txdesc)) ++ return -1; ++ if(synopGMAC_is_desc_empty(txdesc)) ++ return -1; ++ ++ (gmacdev->BusyTxDesc)--; //busy tx descriptor is reduced by one as it will be handed over to Processor now ++ ++ if(Status != 0) ++ *Status = txdesc->status; ++ ++ if(Ext_Status != 0) ++ *Ext_Status = txdesc->extstatus; ++ if(Time_Stamp_High != 0) ++ *Time_Stamp_High = txdesc->timestamphigh; ++ if(Time_Stamp_Low != 0) ++ *Time_Stamp_High = txdesc->timestamplow; ++ ++ if(Buffer1 != 0) ++ *Buffer1 = txdesc->buffer1; ++ if(Length1 != 0) ++ *Length1 = (txdesc->length & DescSize1Mask) >> DescSize1Shift; ++ if(Data1 != 0) ++ *Data1 = txdesc->data1; ++ ++ if(Buffer2 != 0) ++ *Buffer2 = txdesc->buffer2; ++ if(Length2 != 0) ++ *Length2 = (txdesc->length & DescSize2Mask) >> DescSize2Shift; ++ if(Data1 != 0) ++ *Data2 = txdesc->data2; ++ ++ gmacdev->TxBusy = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? 0 : txover + 1; ++ ++ if(synopGMAC_is_tx_desc_chained(txdesc)){ ++ gmacdev->TxBusyDesc = (DmaDesc *)txdesc->data2; ++ synopGMAC_tx_desc_init_chain(txdesc); ++ } ++ else{ ++ gmacdev->TxBusyDesc = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? gmacdev->TxDesc : (txdesc + 1); ++ synopGMAC_tx_desc_init_ring(txdesc, synopGMAC_is_last_tx_desc(gmacdev,txdesc)); ++ } ++ TR("(get)%02d %08x %08x %08x %08x %08x %08x %08x\n",txover,(u32)txdesc,txdesc->status,txdesc->length,txdesc->buffer1,txdesc->buffer2,txdesc->data1,txdesc->data2); ++ ++ return txover; ++} ++#else ++ ++/** ++ * Get the index and address of Tx desc. ++ * This api is same for both ring mode and chain mode. ++ * This function tracks the tx descriptor the DMA just closed after the transmission of data from this descriptor is ++ * over. This returns the descriptor fields to the caller. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[out] status field of the descriptor. ++ * @param[out] Dma-able buffer1 pointer. ++ * @param[out] length of buffer1 (Max is 2048). ++ * @param[out] virtual pointer for buffer1. ++ * @param[out] Dma-able buffer2 pointer. ++ * @param[out] length of buffer2 (Max is 2048). ++ * @param[out] virtual pointer for buffer2. ++ * @param[out] u32 data indicating whether the descriptor is in ring mode or chain mode. ++ * \return returns present tx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_get_tx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2 ) ++{ ++ u32 txover = gmacdev->TxBusy; ++ DmaDesc * txdesc = gmacdev->TxBusyDesc; ++ ++ if(synopGMAC_is_desc_owned_by_dma(txdesc)) ++ return -1; ++ if(synopGMAC_is_desc_empty(txdesc)) ++ return -1; ++ ++ (gmacdev->BusyTxDesc)--; //busy tx descriptor is reduced by one as it will be handed over to Processor now ++ ++ if(Status != 0) ++ *Status = txdesc->status; ++ ++ if(Buffer1 != 0) ++ *Buffer1 = txdesc->buffer1; ++ if(Length1 != 0) ++ *Length1 = (txdesc->length & DescSize1Mask) >> DescSize1Shift; ++ if(Data1 != 0) ++ *Data1 = txdesc->data1; ++ ++ if(Buffer2 != 0) ++ *Buffer2 = txdesc->buffer2; ++ if(Length2 != 0) ++ *Length2 = (txdesc->length & DescSize2Mask) >> DescSize2Shift; ++ if(Data1 != 0) ++ *Data2 = txdesc->data2; ++ ++ gmacdev->TxBusy = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? 0 : txover + 1; ++ ++ if(synopGMAC_is_tx_desc_chained(txdesc)){ ++ gmacdev->TxBusyDesc = (DmaDesc *)txdesc->data2; ++ synopGMAC_tx_desc_init_chain(txdesc); ++ } ++ else{ ++ gmacdev->TxBusyDesc = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? gmacdev->TxDesc : (txdesc + 1); ++ synopGMAC_tx_desc_init_ring(txdesc, synopGMAC_is_last_tx_desc(gmacdev,txdesc)); ++ } ++ TR("(get)%02d %08x %08x %08x %08x %08x %08x %08x\n",txover,(u32)txdesc,txdesc->status,txdesc->length,txdesc->buffer1,txdesc->buffer2,txdesc->data1,txdesc->data2); ++ ++ return txover; ++} ++ ++#endif ++/** ++ * Populate the tx desc structure with the buffer address. ++ * Once the driver has a packet ready to be transmitted, this function is called with the ++ * valid dma-able buffer addresses and their lengths. This function populates the descriptor ++ * and make the DMA the owner for the descriptor. This function also controls whetther Checksum ++ * offloading to be done in hardware or not. ++ * This api is same for both ring mode and chain mode. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Dma-able buffer1 pointer. ++ * @param[in] length of buffer1 (Max is 2048). ++ * @param[in] virtual pointer for buffer1. ++ * @param[in] Dma-able buffer2 pointer. ++ * @param[in] length of buffer2 (Max is 2048). ++ * @param[in] virtual pointer for buffer2. ++ * @param[in] u32 data indicating whether the descriptor is in ring mode or chain mode. ++ * @param[in] u32 indicating whether the checksum offloading in HW/SW. ++ * \return returns present tx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_set_tx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2,u32 offload_needed) ++{ ++ u32 txnext = gmacdev->TxNext; ++ DmaDesc * txdesc = gmacdev->TxNextDesc; ++ if(!synopGMAC_is_desc_empty(txdesc)) ++ return -1; ++ ++ (gmacdev->BusyTxDesc)++; //busy tx descriptor is incremented by one as it will be handed over to DMA ++ ++ if(synopGMAC_is_tx_desc_chained(txdesc)){ ++ txdesc->length |= ((Length1 <status |= (DescTxFirst | DescTxLast | DescTxIntEnable); //ENH_DESC ++#else ++ txdesc->length |= (DescTxFirst | DescTxLast | DescTxIntEnable); //Its always assumed that complete data will fit in to one descriptor ++#endif ++ ++ txdesc->buffer1 = Buffer1; ++ txdesc->data1 = Data1; ++ ++ if(offload_needed){ ++ /* ++ Make sure that the OS you are running supports the IP and TCP checkusm offloaidng, ++ before calling any of the functions given below. ++ */ ++ synopGMAC_tx_checksum_offload_ipv4hdr(gmacdev, txdesc); ++ synopGMAC_tx_checksum_offload_tcponly(gmacdev, txdesc); ++ // synopGMAC_tx_checksum_offload_tcp_pseudo(gmacdev, txdesc); ++ } ++#ifdef ENH_DESC ++ txdesc->status |= DescOwnByDma;//ENH_DESC ++#else ++ txdesc->status = DescOwnByDma; ++#endif ++ ++ gmacdev->TxNext = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? 0 : txnext + 1; ++ gmacdev->TxNextDesc = (DmaDesc *)txdesc->data2; ++ } ++ else{ ++ txdesc->length |= (((Length1 <status |= (DescTxFirst | DescTxLast | DescTxIntEnable); //ENH_DESC ++#else ++ txdesc->length |= (DescTxFirst | DescTxLast | DescTxIntEnable); //Its always assumed that complete data will fit in to one descriptor ++#endif ++ ++ txdesc->buffer1 = Buffer1; ++ txdesc->data1 = Data1; ++ ++ txdesc->buffer2 = Buffer2; ++ txdesc->data2 = Data2; ++ ++ if(offload_needed){ ++ /* ++ Make sure that the OS you are running supports the IP and TCP checkusm offloaidng, ++ before calling any of the functions given below. ++ */ ++ synopGMAC_tx_checksum_offload_ipv4hdr(gmacdev, txdesc); ++ synopGMAC_tx_checksum_offload_tcponly(gmacdev, txdesc); ++ // synopGMAC_tx_checksum_offload_tcp_pseudo(gmacdev, txdesc); ++ } ++#ifdef ENH_DESC ++ txdesc->status |= DescOwnByDma;//ENH_DESC ++#else ++ txdesc->status = DescOwnByDma; ++#endif ++ ++ gmacdev->TxNext = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? 0 : txnext + 1; ++ gmacdev->TxNextDesc = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? gmacdev->TxDesc : (txdesc + 1); ++ } ++ ++ ++ TR("(set)%02d %08x %08x %08x %08x %08x %08x %08x\n",txnext,(u32)txdesc,txdesc->status,txdesc->length,txdesc->buffer1,txdesc->buffer2,txdesc->data1,txdesc->data2); ++ return txnext; ++} ++#ifdef ENH_DESC_8W ++/** ++ * Prepares the descriptor to receive packets. ++ * The descriptor is allocated with the valid buffer addresses (sk_buff address) and the length fields ++ * and handed over to DMA by setting the ownership. After successful return from this function the ++ * descriptor is added to the receive descriptor pool/queue. ++ * This api is same for both ring mode and chain mode. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Dma-able buffer1 pointer. ++ * @param[in] length of buffer1 (Max is 2048). ++ * @param[in] Dma-able buffer2 pointer. ++ * @param[in] length of buffer2 (Max is 2048). ++ * @param[in] u32 data indicating whether the descriptor is in ring mode or chain mode. ++ * \return returns present rx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_set_rx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2) ++{ ++ u32 rxnext = gmacdev->RxNext; ++ DmaDesc * rxdesc = gmacdev->RxNextDesc; ++ ++ if(!synopGMAC_is_desc_empty(rxdesc)) ++ return -1; ++ ++ ++ if(synopGMAC_is_rx_desc_chained(rxdesc)){ ++ rxdesc->length |= ((Length1 <buffer1 = Buffer1; ++ rxdesc->data1 = Data1; ++ ++ rxdesc->extstatus = 0; ++ rxdesc->reserved1 = 0; ++ rxdesc->timestamplow = 0; ++ rxdesc->timestamphigh = 0; ++ ++ if((rxnext % MODULO_INTERRUPT) !=0) ++ rxdesc->length |= RxDisIntCompl; ++ ++ rxdesc->status = DescOwnByDma; ++ ++ gmacdev->RxNext = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ gmacdev->RxNextDesc = (DmaDesc *)rxdesc->data2; ++ } ++ else{ ++ rxdesc->length |= (((Length1 <buffer1 = Buffer1; ++ rxdesc->data1 = Data1; ++ ++ rxdesc->extstatus = 0; ++ rxdesc->reserved1 = 0; ++ rxdesc->timestamplow = 0; ++ rxdesc->timestamphigh = 0; ++ ++ rxdesc->buffer2 = Buffer2; ++ rxdesc->data2 = Data2; ++ ++ if((rxnext % MODULO_INTERRUPT) !=0) ++ rxdesc->length |= RxDisIntCompl; ++ ++ rxdesc->status = DescOwnByDma; ++ ++ gmacdev->RxNext = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ gmacdev->RxNextDesc = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? gmacdev->RxDesc : (rxdesc + 1); ++ } ++ TR("%02d %08x %08x %08x %08x %08x %08x %08x\n",rxnext,(u32)rxdesc,rxdesc->status,rxdesc->length,rxdesc->buffer1,rxdesc->buffer2,rxdesc->data1,rxdesc->data2); ++ ++ (gmacdev->BusyRxDesc)++; //One descriptor will be given to Hardware. So busy count incremented by one ++ return rxnext; ++} ++ ++#else ++/** ++ * Prepares the descriptor to receive packets. ++ * The descriptor is allocated with the valid buffer addresses (sk_buff address) and the length fields ++ * and handed over to DMA by setting the ownership. After successful return from this function the ++ * descriptor is added to the receive descriptor pool/queue. ++ * This api is same for both ring mode and chain mode. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Dma-able buffer1 pointer. ++ * @param[in] length of buffer1 (Max is 2048). ++ * @param[in] Dma-able buffer2 pointer. ++ * @param[in] length of buffer2 (Max is 2048). ++ * @param[in] u32 data indicating whether the descriptor is in ring mode or chain mode. ++ * \return returns present rx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_set_rx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2) ++{ ++ u32 rxnext = gmacdev->RxNext; ++ DmaDesc * rxdesc = gmacdev->RxNextDesc; ++ ++ if(!synopGMAC_is_desc_empty(rxdesc)) ++ return -1; ++ ++ if(synopGMAC_is_rx_desc_chained(rxdesc)){ ++ rxdesc->length |= ((Length1 <buffer1 = Buffer1; ++ rxdesc->data1 = Data1; ++ ++ if((rxnext % MODULO_INTERRUPT) !=0) ++ rxdesc->length |= RxDisIntCompl; ++ ++ rxdesc->status = DescOwnByDma; ++ ++ gmacdev->RxNext = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ gmacdev->RxNextDesc = (DmaDesc *)rxdesc->data2; ++ } ++ else{ ++ rxdesc->length |= (((Length1 <buffer1 = Buffer1; ++ rxdesc->data1 = Data1; ++ ++ rxdesc->buffer2 = Buffer2; ++ rxdesc->data2 = Data2; ++ ++ if((rxnext % MODULO_INTERRUPT) !=0) ++ rxdesc->length |= RxDisIntCompl; ++ ++ rxdesc->status = DescOwnByDma; ++ ++ gmacdev->RxNext = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ gmacdev->RxNextDesc = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? gmacdev->RxDesc : (rxdesc + 1); ++ } ++ TR("%s: %02d %08x %08x %08x %08x %08x %08x %08x\n", ++ __func__, rxnext,(u32)rxdesc,rxdesc->status,rxdesc->length,rxdesc->buffer1,rxdesc->buffer2,rxdesc->data1,rxdesc->data2); ++ (gmacdev->BusyRxDesc)++; //One descriptor will be given to Hardware. So busy count incremented by one ++ return rxnext; ++} ++ ++#endif ++#ifdef ENH_DESC_8W ++/** ++ * This function is defined two times. Once when the code is compiled for ENHANCED DESCRIPTOR SUPPORT and Once for Normal descriptor ++ * Get back the descriptor from DMA after data has been received. ++ * When the DMA indicates that the data is received (interrupt is generated), this function should be ++ * called to get the descriptor and hence the data buffers received. With successful return from this ++ * function caller gets the descriptor fields for processing. check the parameters to understand the ++ * fields returned.` ++ * @param[in] pointer to synopGMACdevice. ++ * @param[out] pointer to hold the status of DMA. ++ * @param[out] Dma-able buffer1 pointer. ++ * @param[out] pointer to hold length of buffer1 (Max is 2048). ++ * @param[out] virtual pointer for buffer1. ++ * @param[out] Dma-able buffer2 pointer. ++ * @param[out] pointer to hold length of buffer2 (Max is 2048). ++ * @param[out] virtual pointer for buffer2. ++ * \return returns present rx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_get_rx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2, ++ u32 * Ext_Status, u32 * Time_Stamp_High, u32 * Time_Stamp_Low) ++{ ++ u32 rxnext = gmacdev->RxBusy; // index of descriptor the DMA just completed. May be useful when data ++ //is spread over multiple buffers/descriptors ++ DmaDesc * rxdesc = gmacdev->RxBusyDesc; ++ if(synopGMAC_is_desc_owned_by_dma(rxdesc)) ++ return -1; ++ if(synopGMAC_is_desc_empty(rxdesc)) ++ return -1; ++ ++ ++ if(Status != 0) ++ *Status = rxdesc->status;// send the status of this descriptor ++ ++ if(Ext_Status != 0) ++ *Ext_Status = rxdesc->extstatus; ++ if(Time_Stamp_High != 0) ++ *Time_Stamp_High = rxdesc->timestamphigh; ++ if(Time_Stamp_Low != 0) ++ *Time_Stamp_Low = rxdesc->timestamplow; ++ ++ if(Length1 != 0) ++ *Length1 = (rxdesc->length & DescSize1Mask) >> DescSize1Shift; ++ if(Buffer1 != 0) ++ *Buffer1 = rxdesc->buffer1; ++ if(Data1 != 0) ++ *Data1 = rxdesc->data1; ++ ++ if(Length2 != 0) ++ *Length2 = (rxdesc->length & DescSize2Mask) >> DescSize2Shift; ++ if(Buffer2 != 0) ++ *Buffer2 = rxdesc->buffer2; ++ if(Data1 != 0) ++ *Data2 = rxdesc->data2; ++ ++ gmacdev->RxBusy = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ ++ if(synopGMAC_is_rx_desc_chained(rxdesc)){ ++ gmacdev->RxBusyDesc = (DmaDesc *)rxdesc->data2; ++ synopGMAC_rx_desc_init_chain(rxdesc); ++ //synopGMAC_desc_init_chain(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc),0,0); ++ } ++ else{ ++ gmacdev->RxBusyDesc = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? gmacdev->RxDesc : (rxdesc + 1); ++ synopGMAC_rx_desc_init_ring(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc)); ++ } ++ TR("%02d %08x %08x %08x %08x %08x %08x %08x\n",rxnext,(u32)rxdesc,rxdesc->status,rxdesc->length,rxdesc->buffer1,rxdesc->buffer2,rxdesc->data1,rxdesc->data2); ++ (gmacdev->BusyRxDesc)--; //busy tx descriptor is reduced by one as it will be handed over to Processor now ++ return(rxnext); ++ ++} ++#else ++ ++/** ++ * Get back the descriptor from DMA after data has been received. ++ * When the DMA indicates that the data is received (interrupt is generated), this function should be ++ * called to get the descriptor and hence the data buffers received. With successful return from this ++ * function caller gets the descriptor fields for processing. check the parameters to understand the ++ * fields returned.` ++ * @param[in] pointer to synopGMACdevice. ++ * @param[out] pointer to hold the status of DMA. ++ * @param[out] Dma-able buffer1 pointer. ++ * @param[out] pointer to hold length of buffer1 (Max is 2048). ++ * @param[out] virtual pointer for buffer1. ++ * @param[out] Dma-able buffer2 pointer. ++ * @param[out] pointer to hold length of buffer2 (Max is 2048). ++ * @param[out] virtual pointer for buffer2. ++ * \return returns present rx descriptor index on success. Negative value if error. ++ */ ++s32 synopGMAC_get_rx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2) ++{ ++ u32 rxnext = gmacdev->RxBusy; // index of descriptor the DMA just completed. May be useful when data ++ //is spread over multiple buffers/descriptors ++ DmaDesc * rxdesc = gmacdev->RxBusyDesc; ++ if(synopGMAC_is_desc_owned_by_dma(rxdesc)) ++ return -1; ++ if(synopGMAC_is_desc_empty(rxdesc)) ++ return -1; ++ ++ ++ if(Status != 0) ++ *Status = rxdesc->status;// send the status of this descriptor ++ ++ if(Length1 != 0) ++ *Length1 = (rxdesc->length & DescSize1Mask) >> DescSize1Shift; ++ if(Buffer1 != 0) ++ *Buffer1 = rxdesc->buffer1; ++ if(Data1 != 0) ++ *Data1 = rxdesc->data1; ++ ++ if(Length2 != 0) ++ *Length2 = (rxdesc->length & DescSize2Mask) >> DescSize2Shift; ++ if(Buffer2 != 0) ++ *Buffer2 = rxdesc->buffer2; ++ if(Data1 != 0) ++ *Data2 = rxdesc->data2; ++ ++ gmacdev->RxBusy = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1; ++ ++ if(synopGMAC_is_rx_desc_chained(rxdesc)){ ++ gmacdev->RxBusyDesc = (DmaDesc *)rxdesc->data2; ++ synopGMAC_rx_desc_init_chain(rxdesc); ++ //synopGMAC_desc_init_chain(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc),0,0); ++ } ++ else{ ++ gmacdev->RxBusyDesc = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? gmacdev->RxDesc : (rxdesc + 1); ++ synopGMAC_rx_desc_init_ring(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc)); ++ } ++ TR("%02d %08x %08x %08x %08x %08x %08x %08x\n",rxnext,(u32)rxdesc,rxdesc->status,rxdesc->length,rxdesc->buffer1,rxdesc->buffer2,rxdesc->data1,rxdesc->data2); ++ (gmacdev->BusyRxDesc)--; //This returns one descriptor to processor. So busy count will be decremented by one ++ ++ return(rxnext); ++ ++} ++ ++#endif ++ ++/** ++ * Clears all the pending interrupts. ++ * If the Dma status register is read then all the interrupts gets cleared ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_clear_interrupt(synopGMACdevice *gmacdev) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus); ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaStatus ,data); ++} ++ ++/** ++ * Returns the all unmasked interrupt status after reading the DmaStatus register. ++ * @param[in] pointer to synopGMACdevice. ++ * \return 0 upon success. Error code upon failure. ++ */ ++u32 synopGMAC_get_interrupt_type(synopGMACdevice *gmacdev) ++{ ++ u32 data; ++ u32 interrupts = 0; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus); ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaStatus ,data); //This is the appropriate location to clear the interrupts ++ TR("DMA status reg is %08x\n",data); ++ if(data & DmaIntErrorMask) interrupts |= synopGMACDmaError; ++ if(data & DmaIntRxNormMask) interrupts |= synopGMACDmaRxNormal; ++ if(data & DmaIntRxAbnMask) interrupts |= synopGMACDmaRxAbnormal; ++ if(data & DmaIntRxStoppedMask) interrupts |= synopGMACDmaRxStopped; ++ if(data & DmaIntTxNormMask) interrupts |= synopGMACDmaTxNormal; ++ if(data & DmaIntTxAbnMask) interrupts |= synopGMACDmaTxAbnormal; ++ if(data & DmaIntTxStoppedMask) interrupts |= synopGMACDmaTxStopped; ++#ifdef AVB_SUPPORT ++ if(data & DmaSlotCounterIntr) interrupts |= synopGMADmaSlotCounter; ++#endif ++ ++ return interrupts; ++} ++ ++/** ++ * Returns the interrupt mask. ++ * @param[in] pointer to synopGMACdevice. ++ * \return 0 upon success. Error code upon failure. ++ */ ++u32 synopGMAC_get_interrupt_mask(synopGMACdevice *gmacdev) ++{ ++ return(synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaInterrupt)); ++} ++ ++/** ++ * Enable all the interrupts. ++ * Enables the DMA interrupt as specified by the bit mask. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] bit mask of interrupts to be enabled. ++ * \return returns void. ++ */ ++void synopGMAC_enable_interrupt(synopGMACdevice *gmacdev, u32 interrupts) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaInterrupt, interrupts); ++ return; ++} ++ ++ ++/** ++ * Disable all the interrupts. ++ * Disables all DMA interrupts. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note This function disabled all the interrupts, if you want to disable a particular interrupt then ++ * use synopGMAC_disable_interrupt(). ++ */ ++void synopGMAC_disable_interrupt_all(synopGMACdevice *gmacdev) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaInterrupt, DmaIntDisable); ++ return; ++} ++ ++/** ++ * Disable interrupt according to the bitfield supplied. ++ * Disables only those interrupts specified in the bit mask in second argument. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] bit mask for interrupts to be disabled. ++ * \return returns void. ++ */ ++void synopGMAC_disable_interrupt(synopGMACdevice *gmacdev, u32 interrupts) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaInterrupt, interrupts); ++ return; ++} ++/** ++ * Enable the DMA Reception. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_enable_dma_rx(synopGMACdevice * gmacdev) ++{ ++ // synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaControl, DmaRxStart); ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); ++ data |= DmaRxStart; ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); ++ ++} ++ ++/** ++ * Enable the DMA Transmission. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_enable_dma_tx(synopGMACdevice * gmacdev) ++{ ++ // synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaControl, DmaTxStart); ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); ++ data |= DmaTxStart; ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); ++ ++} ++ ++/** ++ * Resumes the DMA Transmission. ++ * the DmaTxPollDemand is written. (the data writeen could be anything). ++ * This forces the DMA to resume transmission. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_resume_dma_tx(synopGMACdevice * gmacdev) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaTxPollDemand, 0); ++ ++} ++/** ++ * Resumes the DMA Reception. ++ * the DmaRxPollDemand is written. (the data writeen could be anything). ++ * This forces the DMA to resume reception. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_resume_dma_rx(synopGMACdevice * gmacdev) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaRxPollDemand, 0); ++ ++} ++/** ++ * Take ownership of this Descriptor. ++ * The function is same for both the ring mode and the chain mode DMA structures. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_take_desc_ownership(DmaDesc * desc) ++{ ++ if(desc){ ++ desc->status &= ~DescOwnByDma; //Clear the DMA own bit ++ // desc->status |= DescError; // Set the error to indicate this descriptor is bad ++ } ++} ++ ++/** ++ * Take ownership of all the rx Descriptors. ++ * This function is called when there is fatal error in DMA transmission. ++ * When called it takes the ownership of all the rx descriptor in rx descriptor pool/queue from DMA. ++ * The function is same for both the ring mode and the chain mode DMA structures. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note Make sure to disable the transmission before calling this function, otherwise may result in racing situation. ++ */ ++void synopGMAC_take_desc_ownership_rx(synopGMACdevice * gmacdev) ++{ ++ s32 i; ++ DmaDesc *desc; ++ desc = gmacdev->RxDesc; ++ for(i = 0; i < gmacdev->RxDescCount; i++){ ++ if(synopGMAC_is_rx_desc_chained(desc)){ //This descriptor is in chain mode ++ ++ synopGMAC_take_desc_ownership(desc); ++ desc = (DmaDesc *)desc->data2; ++ } ++ else{ ++ synopGMAC_take_desc_ownership(desc + i); ++ } ++ } ++} ++ ++/** ++ * Take ownership of all the rx Descriptors. ++ * This function is called when there is fatal error in DMA transmission. ++ * When called it takes the ownership of all the tx descriptor in tx descriptor pool/queue from DMA. ++ * The function is same for both the ring mode and the chain mode DMA structures. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ * \note Make sure to disable the transmission before calling this function, otherwise may result in racing situation. ++ */ ++void synopGMAC_take_desc_ownership_tx(synopGMACdevice * gmacdev) ++{ ++ s32 i; ++ DmaDesc *desc; ++ desc = gmacdev->TxDesc; ++ for(i = 0; i < gmacdev->TxDescCount; i++){ ++ if(synopGMAC_is_tx_desc_chained(desc)){ //This descriptor is in chain mode ++ synopGMAC_take_desc_ownership(desc); ++ desc = (DmaDesc *)desc->data2; ++ } ++ else{ ++ synopGMAC_take_desc_ownership(desc + i); ++ } ++ } ++ ++} ++ ++/** ++ * Disable the DMA for Transmission. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++ ++void synopGMAC_disable_dma_tx(synopGMACdevice * gmacdev) ++{ ++ // synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaControl, DmaTxStart); ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); ++ data &= (~DmaTxStart); ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); ++} ++/** ++ * Disable the DMA for Reception. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_disable_dma_rx(synopGMACdevice * gmacdev) ++{ ++ // synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaControl, DmaRxStart); ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaControl); ++ data &= (~DmaRxStart); ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaControl ,data); ++} ++ ++ ++ ++/*******************PMT APIs***************************************/ ++ ++ ++ ++ ++/** ++ * Enables the assertion of PMT interrupt. ++ * This enables the assertion of PMT interrupt due to Magic Pkt or Wakeup frame ++ * reception. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_pmt_int_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++ return; ++} ++/** ++ * Disables the assertion of PMT interrupt. ++ * This disables the assertion of PMT interrupt due to Magic Pkt or Wakeup frame ++ * reception. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_pmt_int_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++ return; ++} ++/** ++ * Enables the power down mode of GMAC. ++ * This function puts the Gmac in power down mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_power_down_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtPowerDown); ++ return; ++} ++/** ++ * Disables the powerd down setting of GMAC. ++ * If the driver wants to bring up the GMAC from powerdown mode, even though the magic packet or the ++ * wake up frames received from the network, this function should be called. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_power_down_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtPowerDown); ++ return; ++} ++/** ++ * Enables the pmt interrupt generation in powerdown mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_enable_pmt_interrupt(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++} ++/** ++ * Disables the pmt interrupt generation in powerdown mode. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_disable_pmt_interrupt(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++} ++/** ++ * Enables GMAC to look for Magic packet. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_magic_packet_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtMagicPktEnable); ++ return; ++} ++ ++/** ++ * Enables GMAC to look for wake up frame. ++ * Wake up frame is defined by the user. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_wakeup_frame_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtWakeupFrameEnable); ++ return; ++} ++ ++/** ++ * Enables wake-up frame filter to handle unicast packets. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_pmt_unicast_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtGlobalUnicast); ++ return; ++} ++/** ++ * Checks whether the packet received is a magic packet?. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns True if magic packet received else returns false. ++ */ ++bool synopGMAC_is_magic_packet_received(synopGMACdevice *gmacdev) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus); ++ return((data & GmacPmtMagicPktReceived) == GmacPmtMagicPktReceived); ++} ++/** ++ * Checks whether the packet received is a wakeup frame?. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns true if wakeup frame received else returns false. ++ */ ++bool synopGMAC_is_wakeup_frame_received(synopGMACdevice *gmacdev) ++{ ++ u32 data; ++ data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus); ++ return((data & GmacPmtWakeupFrameReceived) == GmacPmtWakeupFrameReceived); ++} ++ ++/** ++ * Populates the remote wakeup frame registers. ++ * Consecutive 8 writes to GmacWakeupAddr writes the wakeup frame filter registers. ++ * Before commensing a new write, frame filter pointer is reset to 0x0000. ++ * A small delay is introduced to allow frame filter pointer reset operation. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] pointer to frame filter contents array. ++ * \return returns void. ++ */ ++void synopGMAC_write_wakeup_frame_register(synopGMACdevice *gmacdev, u32 * filter_contents) ++{ ++ s32 i; ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacPmtCtrlStatus,GmacPmtFrmFilterPtrReset); ++ plat_delay(10); ++ for(i =0; iMacBase, GmacWakeupAddr, *(filter_contents + i)); ++ return; ++ ++} ++/*******************PMT APIs***************************************/ ++/*******************MMC APIs***************************************/ ++ ++/** ++ * Freezes the MMC counters. ++ * This function call freezes the MMC counters. None of the MMC counters are updated ++ * due to any tx or rx frames until synopGMAC_mmc_counters_resume is called. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_stop(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterFreeze); ++ return; ++} ++/** ++ * Resumes the MMC counter updation. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_resume(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterFreeze); ++ return; ++} ++/** ++ * Configures the MMC in Self clearing mode. ++ * Programs MMC interface so that counters are cleared when the counters are read. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_set_selfclear(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterResetOnRead); ++ return; ++} ++/** ++ * Configures the MMC in non-Self clearing mode. ++ * Programs MMC interface so that counters are cleared when the counters are read. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_reset_selfclear(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterResetOnRead); ++ return; ++} ++/** ++ * Configures the MMC to stop rollover. ++ * Programs MMC interface so that counters will not rollover after reaching maximum value. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_disable_rollover(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterStopRollover); ++ return; ++} ++/** ++ * Configures the MMC to rollover. ++ * Programs MMC interface so that counters will rollover after reaching maximum value. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_mmc_counters_enable_rollover(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcCntrl,GmacMmcCounterStopRollover); ++ return; ++} ++ ++/** ++ * Read the MMC Counter. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] the counter to be read. ++ * \return returns the read count value. ++ */ ++u32 synopGMAC_read_mmc_counter(synopGMACdevice *gmacdev, u32 counter) ++{ ++ return( synopGMACReadReg((u32 *)gmacdev->MacBase,counter)); ++} ++/** ++ * Read the MMC Rx interrupt status. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns the Rx interrupt status. ++ */ ++u32 synopGMAC_read_mmc_rx_int_status(synopGMACdevice *gmacdev) ++{ ++ return( synopGMACReadReg((u32 *)gmacdev->MacBase,GmacMmcIntrRx)); ++} ++/** ++ * Read the MMC Tx interrupt status. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns the Tx interrupt status. ++ */ ++u32 synopGMAC_read_mmc_tx_int_status(synopGMACdevice *gmacdev) ++{ ++ return( synopGMACReadReg((u32 *)gmacdev->MacBase,GmacMmcIntrTx)); ++} ++/** ++ * Disable the MMC Tx interrupt. ++ * The MMC tx interrupts are masked out as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] tx interrupt bit mask for which interrupts needs to be disabled. ++ * \return returns void. ++ */ ++void synopGMAC_disable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcIntrMaskTx,mask); ++ return; ++} ++/** ++ * Enable the MMC Tx interrupt. ++ * The MMC tx interrupts are enabled as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] tx interrupt bit mask for which interrupts needs to be enabled. ++ * \return returns void. ++ */ ++void synopGMAC_enable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcIntrMaskTx,mask); ++} ++/** ++ * Disable the MMC Rx interrupt. ++ * The MMC rx interrupts are masked out as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] rx interrupt bit mask for which interrupts needs to be disabled. ++ * \return returns void. ++ */ ++void synopGMAC_disable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcIntrMaskRx,mask); ++ return; ++} ++/** ++ * Enable the MMC Rx interrupt. ++ * The MMC rx interrupts are enabled as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] rx interrupt bit mask for which interrupts needs to be enabled. ++ * \return returns void. ++ */ ++void synopGMAC_enable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcIntrMaskRx,mask); ++ return; ++} ++/** ++ * Disable the MMC ipc rx checksum offload interrupt. ++ * The MMC ipc rx checksum offload interrupts are masked out as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] rx interrupt bit mask for which interrupts needs to be disabled. ++ * \return returns void. ++ */ ++void synopGMAC_disable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacMmcRxIpcIntrMask,mask); ++ return; ++} ++/** ++ * Enable the MMC ipc rx checksum offload interrupt. ++ * The MMC ipc rx checksum offload interrupts are enabled as per the mask specified. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] rx interrupt bit mask for which interrupts needs to be enabled. ++ * \return returns void. ++ */ ++void synopGMAC_enable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacMmcRxIpcIntrMask,mask); ++ return; ++} ++/*******************MMC APIs***************************************/ ++/*******************Ip checksum offloading APIs***************************************/ ++ ++/** ++ * Enables the ip checksum offloading in receive path. ++ * When set GMAC calculates 16 bit 1's complement of all received ethernet frame payload. ++ * It also checks IPv4 Header checksum is correct. GMAC core appends the 16 bit checksum calculated ++ * for payload of IP datagram and appends it to Ethernet frame transferred to the application. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_enable_rx_chksum_offload(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacRxIpcOffload); ++ return; ++} ++/** ++ * Disable the ip checksum offloading in receive path. ++ * Ip checksum offloading is disabled in the receive path. ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_disable_rx_Ipchecksum_offload(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacConfig,GmacRxIpcOffload); ++} ++/** ++ * Instruct the DMA to drop the packets fails tcp ip checksum. ++ * This is to instruct the receive DMA engine to drop the recevied packet if they ++ * fails the tcp/ip checksum in hardware. Valid only when full checksum offloading is enabled(type-2). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_tcpip_chksum_drop_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase,DmaControl,DmaDisableDropTcpCs); ++ return; ++} ++/** ++ * Instruct the DMA not to drop the packets even if it fails tcp ip checksum. ++ * This is to instruct the receive DMA engine to allow the packets even if recevied packet ++ * fails the tcp/ip checksum in hardware. Valid only when full checksum offloading is enabled(type-2). ++ * @param[in] pointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_rx_tcpip_chksum_drop_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase,DmaControl,DmaDisableDropTcpCs); ++ return; ++} ++ ++/** ++ * When the Enhanced Descriptor is enabled then the bit 0 of RDES0 indicates whether the ++ * Extended Status is available (RDES4). Time Stamp feature and the Checksum Offload Engine2 ++ * makes use of this extended status to provide the status of the received packet. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns TRUE or FALSE ++ */ ++#ifdef ENH_DESC_8W ++ ++/** ++ * This function indicates whether extended status is available in the RDES0. ++ * Any function which accesses the fields of extended status register must ensure a check on this has been made ++ * This is valid only for Enhanced Descriptor. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns TRUE or FALSE. ++ */ ++bool synopGMAC_is_ext_status(synopGMACdevice *gmacdev,u32 status) // extended status present indicates that the RDES4 need to be probed ++{ ++ return((status & DescRxEXTsts ) != 0 ); // if extstatus set then it returns 1 ++} ++/** ++ * This function returns true if the IP header checksum bit is set in the extended status. ++ * Valid only when enhaced status available is set in RDES0 bit 0. ++ * This is valid only for Enhanced Descriptor. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns TRUE or FALSE. ++ */ ++bool synopGMAC_ES_is_IP_header_error(synopGMACdevice *gmacdev,u32 ext_status) // IP header (IPV4) checksum error ++{ ++ return((ext_status & DescRxIpHeaderError) != 0 ); // if IPV4 header error return 1 ++} ++/** ++ * This function returns true if the Checksum is bypassed in the hardware. ++ * Valid only when enhaced status available is set in RDES0 bit 0. ++ * This is valid only for Enhanced Descriptor. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns TRUE or FALSE. ++ */ ++bool synopGMAC_ES_is_rx_checksum_bypassed(synopGMACdevice *gmacdev,u32 ext_status) // Hardware engine bypassed the checksum computation/checking ++{ ++ return((ext_status & DescRxChkSumBypass ) != 0 ); // if checksum offloading bypassed return 1 ++} ++/** ++ * This function returns true if payload checksum error is set in the extended status. ++ * Valid only when enhaced status available is set in RDES0 bit 0. ++ * This is valid only for Enhanced Descriptor. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns TRUE or FALSE. ++ */ ++bool synopGMAC_ES_is_IP_payload_error(synopGMACdevice *gmacdev,u32 ext_status) // IP payload checksum is in error (UDP/TCP/ICMP checksum error) ++{ ++ return((ext_status & DescRxIpPayloadError) != 0 ); // if IP payload error return 1 ++} ++#endif ++ ++ ++ ++/** ++ * Decodes the Rx Descriptor status to various checksum error conditions. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns decoded enum (u32) indicating the status. ++ */ ++u32 synopGMAC_is_rx_checksum_error(synopGMACdevice *gmacdev, u32 status) ++{ ++ if (((status & DescRxChkBit5) == 0) && ((status & DescRxChkBit7) == 0) && ((status & DescRxChkBit0) == 0)) ++ return RxLenLT600; ++ else if(((status & DescRxChkBit5) == 0) && ((status & DescRxChkBit7) == 0) && ((status & DescRxChkBit0) != 0)) ++ return RxIpHdrPayLoadChkBypass; ++ else if(((status & DescRxChkBit5) == 0) && ((status & DescRxChkBit7) != 0) && ((status & DescRxChkBit0) != 0)) ++ return RxChkBypass; ++ else if(((status & DescRxChkBit5) != 0) && ((status & DescRxChkBit7) == 0) && ((status & DescRxChkBit0) == 0)) ++ return RxNoChkError; ++ else if(((status & DescRxChkBit5) != 0) && ((status & DescRxChkBit7) == 0) && ((status & DescRxChkBit0) != 0)) ++ return RxPayLoadChkError; ++ else if(((status & DescRxChkBit5) != 0) && ((status & DescRxChkBit7) != 0) && ((status & DescRxChkBit0) == 0)) ++ return RxIpHdrChkError; ++ else if(((status & DescRxChkBit5) != 0) && ((status & DescRxChkBit7) != 0) && ((status & DescRxChkBit0) != 0)) ++ return RxIpHdrPayLoadChkError; ++ else ++ return RxIpHdrPayLoadRes; ++} ++/** ++ * Checks if any Ipv4 header checksum error in the frame just transmitted. ++ * This serves as indication that error occureed in the IPv4 header checksum insertion. ++ * The sent out frame doesnot carry any ipv4 header checksum inserted by the hardware. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns true if error in ipv4 header checksum, else returns false. ++ */ ++bool synopGMAC_is_tx_ipv4header_checksum_error(synopGMACdevice *gmacdev, u32 status) ++{ ++ return((status & DescTxIpv4ChkError) == DescTxIpv4ChkError); ++} ++ ++ ++/** ++ * Checks if any payload checksum error in the frame just transmitted. ++ * This serves as indication that error occureed in the payload checksum insertion. ++ * The sent out frame doesnot carry any payload checksum inserted by the hardware. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] u32 status field of the corresponding descriptor. ++ * \return returns true if error in ipv4 header checksum, else returns false. ++ */ ++bool synopGMAC_is_tx_payload_checksum_error(synopGMACdevice *gmacdev, u32 status) ++{ ++ return((status & DescTxPayChkError) == DescTxPayChkError); ++} ++/** ++ * The check summ offload engine is bypassed in the tx path. ++ * Checksum is not computed in the Hardware. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_checksum_offload_bypass(synopGMACdevice *gmacdev, DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status = (desc->length & (~DescTxCisMask));//ENH_DESC ++#else ++ desc->length = (desc->length & (~DescTxCisMask)); ++#endif ++ ++} ++/** ++ * The check summ offload engine is enabled to do only IPV4 header checksum. ++ * IPV4 header Checksum is computed in the Hardware. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_checksum_offload_ipv4hdr(synopGMACdevice *gmacdev, DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status = ((desc->status & (~DescTxCisMask)) | DescTxCisIpv4HdrCs);//ENH_DESC ++#else ++ desc->length = ((desc->length & (~DescTxCisMask)) | DescTxCisIpv4HdrCs); ++#endif ++ ++} ++ ++/** ++ * The check summ offload engine is enabled to do TCPIP checsum assuming Pseudo header is available. ++ * Hardware computes the tcp ip checksum assuming pseudo header checksum is computed in software. ++ * Ipv4 header checksum is also inserted. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_checksum_offload_tcponly(synopGMACdevice *gmacdev, DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status = ((desc->status & (~DescTxCisMask)) | DescTxCisTcpOnlyCs);//ENH_DESC ++#else ++ desc->length = ((desc->length & (~DescTxCisMask)) | DescTxCisTcpOnlyCs); ++#endif ++ ++} ++/** ++ * The check summ offload engine is enabled to do complete checksum computation. ++ * Hardware computes the tcp ip checksum including the pseudo header checksum. ++ * Here the tcp payload checksum field should be set to 0000. ++ * Ipv4 header checksum is also inserted. ++ * @param[in] pointer to synopGMACdevice. ++ * @param[in] Pointer to tx descriptor for which ointer to synopGMACdevice. ++ * \return returns void. ++ */ ++void synopGMAC_tx_checksum_offload_tcp_pseudo(synopGMACdevice *gmacdev, DmaDesc *desc) ++{ ++#ifdef ENH_DESC ++ desc->status = ((desc->length & (~DescTxCisMask)) | DescTxCisTcpPseudoCs); ++#else ++ desc->length = ((desc->length & (~DescTxCisMask)) | DescTxCisTcpPseudoCs); ++#endif ++ ++} ++/*******************Ip checksum offloading APIs***************************************/ ++ ++ ++ ++ ++ ++/*******************IEEE 1588 Timestamping API***************************************/ ++ ++ ++/* ++ * At this time the driver supports the IEEE time stamping feature when the Enhanced Descriptors are enabled. ++ * For normal descriptor and the IEEE time stamp (version 1), driver support is not proviced ++ * Please make sure you have enabled the Advanced timestamp feature in the hardware and the driver should ++ * be compiled with the ADV_TME_STAMP feature. ++ * Some of the APIs provided here may not be valid for all configurations. Please make sure you call the ++ * API with due care. ++ */ ++ ++/** ++ * This function enables the timestamping. This enables the timestamping for transmit and receive frames. ++ * When disabled timestamp is not added to tx and receive frames and timestamp generator is suspended. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSENA); ++ return; ++} ++/** ++ * This function disables the timestamping. ++ * When disabled timestamp is not added to tx and receive frames and timestamp generator is suspended. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl, GmacTSENA); ++ return; ++} ++ ++ ++/** ++ * Enable the interrupt to get timestamping interrupt. ++ * This enables the host to get the interrupt when (1) system time is greater or equal to the ++ * target time high and low register or (2) there is a overflow in th esecond register. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_int_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++ return; ++} ++ ++/** ++ * Disable the interrupt to get timestamping interrupt. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_int_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacInterruptMask,GmacPmtIntMask); ++ return; ++} ++ ++/** ++ * Enable MAC address for PTP frame filtering. ++ * When enabled, uses MAC address (apart from MAC address 0) to filter the PTP frames when ++ * PTP is sent directly over Ethernet. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_mac_addr_filt_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSENMACADDR); ++ return; ++} ++ ++/** ++ * Disables MAC address for PTP frame filtering. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_mac_addr_filt_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSENMACADDR); ++ return; ++} ++ ++ ++/** ++ * Selet the type of clock mode for PTP. ++ * Please note to use one of the follwoing as the clk_type argument. ++ * GmacTSOrdClk = 0x00000000, 00=> Ordinary clock ++ * GmacTSBouClk = 0x00010000, 01=> Boundary clock ++ * GmacTSEtoEClk = 0x00020000, 10=> End-to-End transparent clock ++ * GmacTSPtoPClk = 0x00030000, 11=> P-to-P transparent clock ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] u32 value representing one of the above clk value ++ * \return returns void ++ */ ++void synopGMAC_TS_set_clk_type(synopGMACdevice *gmacdev, u32 clk_type) ++{ ++ u32 clkval; ++ clkval = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSControl); //set the mdc clock to the user defined value ++ clkval = clkval | clk_type; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSControl,clkval); ++ return; ++} ++ ++/** ++ * Enable Snapshot for messages relevant to Master. ++ * When enabled, snapshot is taken for messages relevant to master mode only, else snapshot is taken for messages relevant ++ * to slave node. ++ * Valid only for Ordinary clock and Boundary clock ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_master_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSMSTRENA); ++ return; ++} ++/** ++ * Disable Snapshot for messages relevant to Master. ++ * When disabled, snapshot is taken for messages relevant ++ * to slave node. ++ * Valid only for Ordinary clock and Boundary clock ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_master_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSMSTRENA); ++ return; ++} ++/** ++ * Enable Snapshot for Event messages. ++ * When enabled, snapshot is taken for event messages only (SYNC, Delay_Req, Pdelay_Req or Pdelay_Resp) ++ * When disabled, snapshot is taken for all messages except Announce, Management and Signaling. ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_event_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSEVNTENA); ++ return; ++} ++/** ++ * Disable Snapshot for Event messages. ++ * When disabled, snapshot is taken for all messages except Announce, Management and Signaling. ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_event_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSEVNTENA); ++ return; ++} ++ ++/** ++ * Enable time stamp snapshot for IPV4 frames. ++ * When enabled, time stamp snapshot is taken for IPV4 frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_IPV4_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPV4ENA); ++ return; ++} ++/** ++ * Disable time stamp snapshot for IPV4 frames. ++ * When disabled, time stamp snapshot is not taken for IPV4 frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_IPV4_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPV4ENA); ++ return; ++} // Only for "Advanced Time Stamp" ++/** ++ * Enable time stamp snapshot for IPV6 frames. ++ * When enabled, time stamp snapshot is taken for IPV6 frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_IPV6_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPV6ENA); ++ return; ++} ++/** ++ * Disable time stamp snapshot for IPV6 frames. ++ * When disabled, time stamp snapshot is not taken for IPV6 frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_IPV6_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPV6ENA); ++ return; ++} ++ ++/** ++ * Enable time stamp snapshot for PTP over Ethernet frames. ++ * When enabled, time stamp snapshot is taken for PTP over Ethernet frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_ptp_over_ethernet_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPENA); ++ return; ++} ++/** ++ * Disable time stamp snapshot for PTP over Ethernet frames. ++ * When disabled, time stamp snapshot is not taken for PTP over Ethernet frames ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_ptp_over_ethernet_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSIPENA); ++ return; ++} ++ ++ ++/** ++ * Snoop PTP packet for version 2 format ++ * When set the PTP packets are snooped using the version 2 format. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_pkt_snoop_ver2(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSVER2ENA); ++ return; ++} ++/** ++ * Snoop PTP packet for version 2 format ++ * When set the PTP packets are snooped using the version 2 format. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_pkt_snoop_ver1(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSVER2ENA); ++ return; ++} ++ ++/** ++ * Timestamp digital rollover ++ * When set the timestamp low register rolls over after 0x3B9A_C9FF value. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_digital_rollover_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSCTRLSSR); ++ return; ++} ++/** ++ * Timestamp binary rollover ++ * When set the timestamp low register rolls over after 0x7FFF_FFFF value. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_binary_rollover_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSCTRLSSR); ++ return; ++} ++/** ++ * Enable Time Stamp for All frames ++ * When set the timestamp snap shot is enabled for all frames received by the core. ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_all_frames_enable(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSENALL); ++ return; ++} ++/** ++ * Disable Time Stamp for All frames ++ * When reset the timestamp snap shot is not enabled for all frames received by the core. ++ * Reserved when "Advanced Time Stamp" is not selected ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_all_frames_disable(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSENALL); ++ return; ++} ++/** ++ * Addend Register Update ++ * This function loads the contents of Time stamp addend register with the supplied 32 value. ++ * This is reserved function when only coarse correction option is selected ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] 32 bit addend value ++ * \return returns 0 for Success or else Failure ++ */ ++s32 synopGMAC_TS_addend_update(synopGMACdevice *gmacdev, u32 addend_value) ++{ ++ u32 loop_variable; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSAddend,addend_value);// Load the addend_value in to Addend register ++ for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){ //Wait till the busy bit gets cleared with in a certain amount of time ++ if(!((synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSControl)) & GmacTSADDREG)){ // if it is cleared then break ++ break; ++ } ++ plat_delay(DEFAULT_DELAY_VARIABLE); ++ } ++ if(loop_variable < DEFAULT_LOOP_VARIABLE) ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSADDREG); ++ else{ ++ TR("Error::: The TSADDREG bit is not getting cleared !!!!!!\n"); ++ return -ESYNOPGMACPHYERR; ++ } ++ return -ESYNOPGMACNOERR; ++ ++} ++/** ++ * time stamp Update ++ * This function updates (adds/subtracts) with the value specified in the Timestamp High Update and ++ * Timestamp Low Update register. ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] Timestamp High Update value ++ * @param[in] Timestamp Low Update value ++ * \return returns 0 for Success or else Failure ++ */ ++s32 synopGMAC_TS_timestamp_update(synopGMACdevice *gmacdev, u32 high_value, u32 low_value) ++{ ++ u32 loop_variable; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSHighUpdate,high_value);// Load the high value to Timestamp High register ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSLowUpdate,low_value);// Load the high value to Timestamp High register ++ for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){ //Wait till the busy bit gets cleared with in a certain amount of time ++ if(!((synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSControl)) & GmacTSUPDT)){ // if it is cleared then break ++ break; ++ } ++ plat_delay(DEFAULT_DELAY_VARIABLE); ++ } ++ if(loop_variable < DEFAULT_LOOP_VARIABLE) ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSUPDT); ++ else{ ++ TR("Error::: The TSADDREG bit is not getting cleared !!!!!!\n"); ++ return -ESYNOPGMACPHYERR; ++ } ++ return -ESYNOPGMACNOERR; ++} ++ ++/** ++ * time stamp Initialize ++ * This function Loads/Initializes h the value specified in the Timestamp High Update and ++ * Timestamp Low Update register. ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] Timestamp High Load value ++ * @param[in] Timestamp Low Load value ++ * \return returns 0 for Success or else Failure ++ */ ++s32 synopGMAC_TS_timestamp_init(synopGMACdevice *gmacdev, u32 high_value, u32 low_value) ++{ ++ u32 loop_variable; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSHighUpdate,high_value);// Load the high value to Timestamp High register ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSLowUpdate,low_value);// Load the high value to Timestamp High register ++ for(loop_variable = 0; loop_variable < DEFAULT_LOOP_VARIABLE; loop_variable++){ //Wait till the busy bit gets cleared with in a certain amount of time ++ if(!((synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSControl)) & GmacTSINT)){ // if it is cleared then break ++ break; ++ } ++ plat_delay(DEFAULT_DELAY_VARIABLE); ++ } ++ if(loop_variable < DEFAULT_LOOP_VARIABLE) ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSINT); ++ else{ ++ TR("Error::: The TSADDREG bit is not getting cleared !!!!!!\n"); ++ return -ESYNOPGMACPHYERR; ++ } ++ return -ESYNOPGMACNOERR; ++} ++ ++/** ++ * Time Stamp Update Coarse ++ * When reset the timestamp update is done using coarse method. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_coarse_update(synopGMACdevice *gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSCFUPDT); ++ return; ++} ++/** ++ * Time Stamp Update Fine ++ * When reset the timestamp update is done using Fine method. ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_fine_update(synopGMACdevice *gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->MacBase,GmacTSControl,GmacTSCFUPDT); ++ return; ++} ++ ++/** ++ * Load the Sub Second Increment value in to Sub Second increment register ++ * @param[in] pointer to synopGMACdevice ++ * \return returns void ++ */ ++void synopGMAC_TS_subsecond_init(synopGMACdevice *gmacdev, u32 sub_sec_inc_value) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSSubSecIncr,(sub_sec_inc_value & GmacSSINCMsk)); ++ return; ++} ++/** ++ * Reads the time stamp contents in to the respective pointers ++ * These registers are readonly. ++ * This function returns the 48 bit time stamp assuming Version 2 timestamp with higher word is selected. ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] pointer to hold 16 higher bit second register contents ++ * @param[in] pointer to hold 32 bit second register contents ++ * @param[in] pointer to hold 32 bit subnanosecond register contents ++ * \return returns void ++ * \note Please note that since the atomic access to the timestamp registers is not possible, ++ * the contents read may be different from the actual time stamp. ++ */ ++void synopGMAC_TS_read_timestamp(synopGMACdevice *gmacdev, u16 * higher_sec_val, u32 * sec_val, u32 * sub_sec_val) ++{ ++ * higher_sec_val = (u16)(synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSHighWord) & GmacTSHighWordMask); ++ * sec_val = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSHigh); ++ * sub_sec_val = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSLow); ++ return; ++} ++/** ++ * Loads the time stamp higher sec value from the value supplied ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] 16 higher bit second register contents passed as 32 bit value ++ * \return returns void ++ */ ++void synopGMAC_TS_load_timestamp_higher_val(synopGMACdevice *gmacdev, u32 higher_sec_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSHighWord, (higher_sec_val & GmacTSHighWordMask)); ++ return; ++} ++/** ++ * Reads the time stamp higher sec value to respective pointers ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] pointer to hold 16 higher bit second register contents ++ * \return returns void ++ */ ++void synopGMAC_TS_read_timestamp_higher_val(synopGMACdevice *gmacdev, u16 * higher_sec_val) ++{ ++ * higher_sec_val = (u16)(synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSHighWord) & GmacTSHighWordMask); ++ return; ++} ++/** ++ * Load the Target time stamp registers ++ * This function Loads the target time stamp registers with the values proviced ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] target Timestamp High value ++ * @param[in] target Timestamp Low value ++ * \return returns 0 for Success or else Failure ++ */ ++void synopGMAC_TS_load_target_timestamp(synopGMACdevice *gmacdev, u32 sec_val, u32 sub_sec_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSTargetTimeHigh,sec_val); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase,GmacTSTargetTimeLow,sub_sec_val); ++ return; ++} ++/** ++ * Reads the Target time stamp registers ++ * This function Loads the target time stamp registers with the values proviced ++ * @param[in] pointer to synopGMACdevice ++ * @param[in] pointer to hold target Timestamp High value ++ * @param[in] pointer to hold target Timestamp Low value ++ * \return returns 0 for Success or else Failure ++ */ ++void synopGMAC_TS_read_target_timestamp(synopGMACdevice *gmacdev, u32 * sec_val, u32 * sub_sec_val) ++{ ++ * sec_val = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSTargetTimeHigh); ++ * sub_sec_val = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacTSTargetTimeLow); ++ return; ++} ++ ++#ifdef AVB_SUPPORT ++void synopGMACsetAvType(synopGMACdevice *gmacdev, u32 avtype) ++{ ++ u32 orig_data; ++ orig_data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacAvMacCtrl); ++ orig_data &= (~ GmacAvTypeMask); ++ orig_data |= avtype; ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacAvMacCtrl ,orig_data); ++} ++ ++void synopGMACsetAvPrio(synopGMACdevice * gmacdev,u8 priority){ //set the Avpriority tag ++ u32 orig_data; ++ orig_data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacAvMacCtrl); ++ orig_data &= (~ GmacAvPrio); ++ orig_data |= (priority << 16); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacAvMacCtrl ,orig_data); ++ ++} ++void synopGMACsetAvCtrlCh(synopGMACdevice * gmacdev,u8 channel) ++{//set the Av control Channel ++ u32 orig_data; ++ orig_data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacAvMacCtrl); ++ orig_data &= (~ GmacAvCtrlCh); ++ orig_data |= (channel << 24); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacAvMacCtrl ,orig_data); ++ ++} ++void synopGMACsetAvPTPCh (synopGMACdevice * gmacdev,u8 channel) ++{//set the Av control Channel ++ u32 orig_data; ++ orig_data = synopGMACReadReg((u32 *)gmacdev->MacBase,GmacAvMacCtrl); ++ orig_data &= (~ GmacPtpCh); ++ orig_data |= (channel << 24); ++ synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacAvMacCtrl ,orig_data); ++ ++} ++ ++void synopGMACsetTxRxPrioPolicy(synopGMACdevice * gmacdev,u8 policy) ++{ //0=>RR 1=>Strict priority ++ if(policy) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaArbitrationStrict); ++ else ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaArbitrationStrict); ++} ++void synopGMACsetTxRxPrio(synopGMACdevice * gmacdev,u8 tx_has_high_prio) ++{ //0=>RR 1=>Strict priority ++ if(tx_has_high_prio) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaTxRxPrio ); ++ else ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaTxRxPrio ); ++} ++void synopGMACsetTxRxPrioRatio(synopGMACdevice * gmacdev,u8 tx_rx_prio_ratio) ++{ //0=>RR 1=>Strict prioriyt ++ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaPriorityRatio41); ++ if(tx_rx_prio_ratio == 0) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaPriorityRatio11); ++ if(tx_rx_prio_ratio == 1) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaPriorityRatio21); ++ if(tx_rx_prio_ratio == 2) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaPriorityRatio31); ++ if(tx_rx_prio_ratio == 3) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaPriorityRatio41); ++} ++void synopGMACsetChPrioWts(synopGMACdevice * gmacdev,u8 weights) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaBusMode , DmaChannelPrioWt); ++ if(weights == 1) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode, DmaChannelPrio1); ++ if(weights == 2) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode, DmaChannelPrio2); ++ if(weights == 3) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode, DmaChannelPrio3); ++ if(weights == 4) ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaBusMode, DmaChannelPrio4); ++} ++ ++void synopGMACAvbEnSlot(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaSlotFnCtrlSts , EnaSlot); ++} ++void synopGMACAvbDisSlot (synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaSlotFnCtrlSts , EnaSlot); ++} ++void synopGMACAvbEnAdvSlotInt(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaSlotFnCtrlSts , AdvSlotInt ); ++} ++void synopGMACAvbDisAdvSlotInt(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaSlotFnCtrlSts , AdvSlotInt ); ++} ++void synopGMACAvbSetSlotCount(synopGMACdevice * gmacdev, u8 slotcount) ++{ ++ u32 orig_data; ++ orig_data = synopGMACReadReg((u32 *)gmacdev->DmaBase,DmaChannelCtrl); ++ orig_data &= (~ ChannelSlotCount); ++ if(slotcount == 1 ) ++ orig_data |= 0x00000000; ++ if(slotcount == 2 ) ++ orig_data |= 0x00000010; ++ if(slotcount == 4 ) ++ orig_data |= 0x00000020; ++ if(slotcount == 8 ) ++ orig_data |= 0x00000030; ++ if(slotcount == 16 ) ++ orig_data |= 0x00000040; ++ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, DmaChannelCtrl,orig_data); ++ ++ TR("CH1 SLOT COUNT = %08x\n",synopGMACReadReg((u32 *)gmacdev->DmaBase,DmaChannelCtrl)); ++ ++} ++ ++void synopGMACAvbEnSlotInterrupt(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelSlotIntEn); ++} ++void synopGMACAvbDisSlotInterrupt(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelSlotIntEn); ++} ++void synopGMACAvbEnableCrSh(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelCreditShDis); ++} ++void synopGMACAvbDisableCrSh(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelCreditShDis); ++} ++void synopGMACAvbEnableCrControl(synopGMACdevice * gmacdev) ++{ ++ synopGMACSetBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelCreditCtrl); ++} ++void synopGMACAvbDisableCrControl(synopGMACdevice * gmacdev) ++{ ++ synopGMACClearBits((u32 *)gmacdev->DmaBase, DmaChannelCtrl, ChannelCreditCtrl); ++} ++ ++void synopGMACsetAvbSendSlope(synopGMACdevice * gmacdev,u32 sendslope_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, SendSlopeCredit,(ChannelSendSlCr & sendslope_val )); ++} ++void synopGMACsetAvbIdleSlope(synopGMACdevice * gmacdev,u32 idleslope_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, IdleSlopeCredit,(ChannelIdleSlCr & idleslope_val )); ++} ++void synopGMACsetAvbHiCredit(synopGMACdevice * gmacdev,u32 hicredit_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, HighCredit ,(ChannelHiCr & hicredit_val)); ++} ++void synopGMACsetAvbLoCredit(synopGMACdevice * gmacdev,u32 locredit_val) ++{ ++ synopGMACWriteReg((u32 *)gmacdev->DmaBase, LoCredit ,(ChannelLoCr & locredit_val)); ++} ++#endif +diff --git a/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_Dev.h b/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_Dev.h +new file mode 100644 +index 000000000..08f7c1238 +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_Dev.h +@@ -0,0 +1,2011 @@ ++/* =================================================================================== ++ * Copyright (c) <2009> Synopsys, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy of ++ * this software annotated with this license and associated documentation files ++ * (the "Software"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ++ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE ++ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * =================================================================================== */ ++ ++/**\file ++ * This file defines the function prototypes for the Synopsys GMAC device and the ++ * Marvell 88E1011/88E1011S integrated 10/100/1000 Gigabit Ethernet Transceiver. ++ * Since the phy register mapping are standardised, the phy register map and the ++ * bit definitions remain the same for other phy as well. ++ * This also defines some of the Ethernet related parmeters. ++ * \internal ++ * -----------------------------REVISION HISTORY------------------------------------ ++ * Synopsys 01/Aug/2007 Created ++ */ ++ ++ ++#ifndef SYNOP_GMAC_DEV_H ++#define SYNOP_GMAC_DEV_H 1 ++ ++#include "synopGMAC_plat.h" ++ ++/*SynopGMAC can support up to 32 phys*/ ++ ++enum GMACPhyBase ++{ ++ PHY0 = 0, //The device can support 32 phys, but we use first phy only ++ PHY31 = 31, ++}; ++ ++#define DEFAULT_PHY_BASE (PHY0 + 16) //We use First Phy ++#define MACBASE 0x0000 // The Mac Base address offset is 0x0000 ++#define DMABASE 0x1000 // Dma base address starts with an offset 0x1000 ++ ++#ifdef AVB_SUPPORT ++#define DMABASE_CH0 DMABASE // DMA base address for Channel 0 ++#define DMABASE_CH1 0x1100 // DMA base address for Channel 1 ++#define DMABASE_CH2 0x1200 // DMA base address for Channel 2 ++ ++#define ETHERNET_HEADER_AVB 18 //6 byte Dest addr, 6 byte Src addr, 2 byte length/type ++ ++#endif ++ ++ ++//#define TRANSMIT_DESC_SIZE 256 //Tx Descriptors needed in the Descriptor pool/queue ++//#define RECEIVE_DESC_SIZE 256 //Rx Descriptors needed in the Descriptor pool/queue ++#define TRANSMIT_DESC_SIZE 12//256 //Tx Descriptors needed in the Descriptor pool/queue ++#define RECEIVE_DESC_SIZE 12//256 //Rx Descriptors needed in the Descriptor pool/queue ++ ++#define ETHERNET_HEADER 14 //6 byte Dest addr, 6 byte Src addr, 2 byte length/type ++#define ETHERNET_CRC 4 //Ethernet CRC ++#define ETHERNET_EXTRA 2 //Only God knows about this????? ++#define ETHERNET_PACKET_COPY 250 // Maximum length when received data is copied on to a new skb ++#define ETHERNET_PACKET_EXTRA 18 // Preallocated length for the rx packets is MTU + ETHERNET_PACKET_EXTRA ++#define VLAN_TAG 4 //optional 802.1q VLAN Tag ++#define MIN_ETHERNET_PAYLOAD 46 //Minimum Ethernet payload size ++#define MAX_ETHERNET_PAYLOAD 1500 //Maximum Ethernet payload size ++#define JUMBO_FRAME_PAYLOAD 9000 //Jumbo frame payload size ++ ++#define TX_BUF_SIZE ETHERNET_HEADER + ETHERNET_CRC + MAX_ETHERNET_PAYLOAD + VLAN_TAG ++ ++ ++// This is the IP's phy address. This is unique address for every MAC in the universe ++#define DEFAULT_MAC_ADDRESS {0x00, 0x55, 0x7B, 0xB5, 0x7D, 0xF7} ++ ++/* ++ DMA Descriptor Structure ++ The structure is common for both receive and transmit descriptors ++ The descriptor is of 4 words, but our structrue contains 6 words where ++ last two words are to hold the virtual address of the network buffer pointers ++ for driver's use ++ From the GMAC core release 3.50a onwards, the Enhanced Descriptor structure got changed. ++ The descriptor (both transmit and receive) are of 8 words each rather the 4 words of normal ++ descriptor structure. ++ Whenever IEEE 1588 Timestamping is enabled TX/RX DESC6 provides the lower 32 bits of Timestamp value and ++ TX/RX DESC7 provides the upper 32 bits of Timestamp value ++ In addition to this whenever extended status bit is set (RX DESC0 bit 0), RX DESC4 contains the extended status information ++ */ ++ ++#define MODULO_INTERRUPT 1 // if it is set to 1, interrupt is available for all the descriptors or else interrupt is available only for ++// descriptor whose index%MODULO_INTERRUPT is zero ++#ifdef ENH_DESC_8W ++typedef struct DmaDescStruct ++{ ++ u32 status; /* Status */ ++ u32 length; /* Buffer 1 and Buffer 2 length */ ++ u32 buffer1; /* Network Buffer 1 pointer (Dma-able) */ ++ u32 buffer2; /* Network Buffer 2 pointer or next descriptor pointer (Dma-able)in chain structure */ ++ /* This data below is used only by driver */ ++ u32 extstatus; /* Extended status of a Rx Descriptor */ ++ u32 reserved1; /* Reserved word */ ++ u32 timestamplow; /* Lower 32 bits of the 64 bit timestamp value */ ++ u32 timestamphigh; /* Higher 32 bits of the 64 bit timestamp value */ ++ u32 data1; /* This holds virtual address of buffer1, not used by DMA */ ++ u32 data2; /* This holds virtual address of buffer2, not used by DMA */ ++}__packed __aligned(8) DmaDesc; ++#else ++typedef struct DmaDescStruct ++{ ++ u32 status; /* Status */ ++ u32 length; /* Buffer 1 and Buffer 2 length */ ++ u32 buffer1; /* Network Buffer 1 pointer (Dma-able) */ ++ u32 buffer2; /* Network Buffer 2 pointer or next descriptor pointer (Dma-able)in chain structure */ ++ /* This data below is used only by driver */ ++ u32 data1; /* This holds virtual address of buffer1, not used by DMA */ ++ u32 data2; /* This holds virtual address of buffer2, not used by DMA */ ++}__packed __aligned(8) DmaDesc; ++#endif ++ ++enum DescMode ++{ ++ RINGMODE = 0x00000001, ++ CHAINMODE = 0x00000002, ++}; ++ ++enum BufferMode ++{ ++ SINGLEBUF = 0x00000001, ++ DUALBUF = 0x00000002, ++}; ++ ++/* synopGMAC device data */ ++ ++typedef struct synopGMACDeviceStruct ++{ ++ u32 MacBase; /* base address of MAC registers */ ++ u32 DmaBase; /* base address of DMA registers */ ++ u32 PhyBase; /* PHY device address on MII interface */ ++ u32 Version; /* Gmac Revision version */ ++ ++ ++ dma_addr_t TxDescDma; /* Dma-able address of first tx descriptor either in ring or chain mode, this is used by the GMAC device*/ ++ dma_addr_t RxDescDma; /* Dma-albe address of first rx descriptor either in ring or chain mode, this is used by the GMAC device*/ ++ DmaDesc *TxDesc; /* start address of TX descriptors ring or chain, this is used by the driver */ ++ DmaDesc *RxDesc; /* start address of RX descriptors ring or chain, this is used by the driver */ ++ ++ u32 BusyTxDesc; /* Number of Tx Descriptors owned by DMA at any given time*/ ++ u32 BusyRxDesc; /* Number of Rx Descriptors owned by DMA at any given time*/ ++ ++ u32 RxDescCount; /* number of rx descriptors in the tx descriptor queue/pool */ ++ u32 TxDescCount; /* number of tx descriptors in the rx descriptor queue/pool */ ++ ++ u32 TxBusy; /* index of the tx descriptor owned by DMA, is obtained by synopGMAC_get_tx_qptr() */ ++ u32 TxNext; /* index of the tx descriptor next available with driver, given to DMA by synopGMAC_set_tx_qptr() */ ++ u32 RxBusy; /* index of the rx descriptor owned by DMA, obtained by synopGMAC_get_rx_qptr() */ ++ u32 RxNext; /* index of the rx descriptor next available with driver, given to DMA by synopGMAC_set_rx_qptr() */ ++ ++ DmaDesc * TxBusyDesc; /* Tx Descriptor address corresponding to the index TxBusy */ ++ DmaDesc * TxNextDesc; /* Tx Descriptor address corresponding to the index TxNext */ ++ DmaDesc * RxBusyDesc; /* Rx Descriptor address corresponding to the index TxBusy */ ++ DmaDesc * RxNextDesc; /* Rx Descriptor address corresponding to the index RxNext */ ++ ++ ++ /*Phy related stuff*/ ++ u32 ClockDivMdc; /* Clock divider value programmed in the hardware */ ++ /* The status of the link */ ++ u32 LinkState; /* Link status as reported by the Marvel Phy */ ++ u32 DuplexMode; /* Duplex mode of the Phy */ ++ u32 Speed; /* Speed of the Phy */ ++ u32 LoopBackMode; /* Loopback status of the Phy */ ++ ++} synopGMACdevice; ++ ++#ifdef AVB_SUPPORT ++typedef struct AVBStruct ++{ ++ u8 ChSelMask; /* This gives which DMA channel is enabled and which is disabled ++ Bit0 for Ch0 ++ Bit1 for Ch1 ++ Bit2 for Ch2 ++ */ ++ u8 DurationOfExp; /* Duration for which experiment should be conducted in minutes - Default 2 Minutes */ ++ ++ u8 AvControlCh; /* channel on which AV control channel must be received (Not used)*/ ++ u8 PTPCh; /* Channel on which PTP packets must be received (Not Used)*/ ++ u8 PrioTagForAV; /* Used when more than One channel enabled in Rx path (Not Used) ++ for only CH1 Enabled: ++ Frames sith Priority > Value programmed, frames sent to CH1 ++ Frames with priority < Value programmed are sent to CH0 ++ For both CH1 and CH2 Enabled: ++ Frames sith Priority > Value programmed, frames sent to CH2 ++ Frames with priority < Value programmed are sent to CH1 ++ */ ++ ++ u16 AvType; /* AV Ethernet Type to be programmed for Core to identify AV type */ ++ ++ u8 Ch1PrioWts; ++ u8 Ch1Bw; ++ u32 Ch1_frame_size; ++ u8 Ch1_EnableSlotCheck; /* Enable checking of slot numbers programmed in the Tx Desc*/ ++ u8 Ch1_AdvSlotInterval; /* When Set Data fetched for current slot and for next 2 slots in advance ++ When reset data fetched for current slot and in advance for next slot*/ ++ ++ u8 Ch1CrSh; /* When set Enables the credit based traffic shaping. Now works with Strict priority style*/ ++ u8 Ch1SlotCount; /* Over which transmiteed bits per slot needs to be computed (Only for Credit based shaping) */ ++ u32 Ch1AvgBitsPerSlot; /* Average bits per slot reported by core once in Ch1SlotCount * 125 micro seconds */ ++ u32 Ch1AvgBitsPerSlotAccL; /* No of Avg Bits per slot on Channel1*/ ++ u32 Ch1AvgBitsPerSlotAccH; /* No of Avg Bits per slot on Channel1*/ ++ u32 Ch1AvgBitsNoOfInterrupts; /* Total Number of interrupts over which AvbBits are accumulated*/ ++ ++ u8 Ch1CreditControl; /* Will be zero (Not used) */ ++ ++ u8 Ch1_tx_rx_prio_policy; // Should Ch1 use Strict or RR policy ++ u8 Ch1_use_tx_high_prio; // Should Ch1 Tx have High priority over Rx ++ u8 Ch1_tx_rx_prio_ratio; // For Round Robin what is the ratio between tx-rx or rx-tx ++ ++ u8 Ch1_tx_desc_slot_no_start; ++ u8 Ch1_tx_desc_slot_no_skip; ++ ++ u32 Ch1SendSlope; ++ u32 Ch1IdleSlope; ++ u32 Ch1HiCredit; ++ u32 Ch1LoCredit; ++ ++ u32 Ch1FramecountTx; /* No of Frames Transmitted on Channel 1 */ ++ u32 Ch1FramecountRx; /* No of Frames Received on Channel 1 */ ++ ++ u8 Ch2PrioWts; ++ u8 Ch2Bw; ++ u32 Ch2_frame_size; ++ u8 Ch2_EnableSlotCheck; /* Enable checking of slot numbers programmed in the Tx Desc*/ ++ u8 Ch2_AdvSlotInterval; /* When Set Data fetched for current slot and for next 2 slots in advance ++ When reset data fetched for current slot and in advance for next slot*/ ++ u8 Ch2CrSh; /* When set Enables the credit based traffic shaping. Now works with Strict priority style*/ ++ u8 Ch2SlotCount; /* Over which transmiteed bits per slot needs to be computed (Only for Credit based shaping) */ ++ u32 Ch2AvgBitsPerSlot; /* Average bits per slot reported by core once in Ch2SlotCount * 125 micro seconds */ ++ u32 Ch2AvgBitsPerSlotAccL; /* No of Avg Bits per slot on Channel2*/ ++ u32 Ch2AvgBitsPerSlotAccH; /* No of Avg Bits per slot on Channel2*/ ++ u32 Ch2AvgBitsNoOfInterrupts; /* Total Number of interrupts over which AvbBits are accumulated*/ ++ ++ u8 Ch2CreditControl; /* Will be zero at present*/ ++ ++ u8 Ch2_tx_rx_prio_policy; // Should Ch1 use Strict or RR policy ++ u8 Ch2_use_tx_high_prio; // Should Ch1 Tx have High priority over Rx ++ u8 Ch2_tx_rx_prio_ratio; // For Round Robin what is the ratio between tx-rx or rx-tx ++ ++ ++ u8 Ch2_tx_desc_slot_no_start; ++ u8 Ch2_tx_desc_slot_no_skip; ++ ++ u32 Ch2SendSlope; ++ u32 Ch2IdleSlope; ++ u32 Ch2HiCredit; ++ u32 Ch2LoCredit; ++ ++ u32 Ch2FramecountTx; /* No of Frames Transmitted on Channel 2 */ ++ u32 Ch2FramecountRx; /* No of Frames Received on Channel 2 */ ++ ++ u8 Ch0PrioWts; ++ u8 Ch0_tx_rx_prio_policy; // Should Ch1 use Strict or RR policy ++ u8 Ch0_use_tx_high_prio; // Should Ch1 Tx have High priority over Rx ++ u8 Ch0_tx_rx_prio_ratio; // For Round Robin what is the ratio between tx-rx or rx-tx ++ ++ u32 Ch0_frame_size; ++ u32 Ch0FramecountTx; /* No of Frames Transmitted on Channel 0 */ ++ u32 Ch0FramecountRx; /* No of Frames Received on Channel 0 */ ++ ++} synopGMACavbStruct; ++#endif ++ ++/* Below is "88E1011/88E1011S Integrated 10/100/1000 Gigabit Ethernet Transceiver" ++ * Register and their layouts. This Phy has been used in the Dot Aster GMAC Phy daughter. ++ * Since the Phy register map is standard, this map hardly changes to a different Ppy ++ */ ++ ++enum MiiRegisters ++{ ++ PHY_CONTROL_REG = 0x0000, /*Control Register*/ ++ PHY_STATUS_REG = 0x0001, /*Status Register */ ++ PHY_ID_HI_REG = 0x0002, /*PHY Identifier High Register*/ ++ PHY_ID_LOW_REG = 0x0003, /*PHY Identifier High Register*/ ++ PHY_AN_ADV_REG = 0x0004, /*Auto-Negotiation Advertisement Register*/ ++ PHY_LNK_PART_ABl_REG = 0x0005, /*Link Partner Ability Register (Base Page)*/ ++ PHY_AN_EXP_REG = 0x0006, /*Auto-Negotiation Expansion Register*/ ++ PHY_AN_NXT_PAGE_TX_REG = 0x0007, /*Next Page Transmit Register*/ ++ PHY_LNK_PART_NXT_PAGE_REG = 0x0008, /*Link Partner Next Page Register*/ ++ PHY_1000BT_CTRL_REG = 0x0009, /*1000BASE-T Control Register*/ ++ PHY_1000BT_STATUS_REG = 0x000a, /*1000BASE-T Status Register*/ ++ PHY_SPECIFIC_CTRL_REG = 0x0010, /*Phy specific control register*/ ++ PHY_SPECIFIC_STATUS_REG = 0x0011, /*Phy specific status register*/ ++ PHY_INTERRUPT_ENABLE_REG = 0x0012, /*Phy interrupt enable register*/ ++ PHY_INTERRUPT_STATUS_REG = 0x0013, /*Phy interrupt status register*/ ++ PHY_EXT_PHY_SPC_CTRL = 0x0014, /*Extended Phy specific control*/ ++ PHY_RX_ERR_COUNTER = 0x0015, /*Receive Error Counter*/ ++ PHY_EXT_ADDR_CBL_DIAG = 0x0016, /*Extended address for cable diagnostic register*/ ++ PHY_LED_CONTROL = 0x0018, /*LED Control*/ ++ PHY_MAN_LED_OVERIDE = 0x0019, /*Manual LED override register*/ ++ PHY_EXT_PHY_SPC_CTRL2 = 0x001a, /*Extended Phy specific control 2*/ ++ PHY_EXT_PHY_SPC_STATUS = 0x001b, /*Extended Phy specific status*/ ++ PHY_CBL_DIAG_REG = 0x001c, /*Cable diagnostic registers*/ ++}; ++ ++ ++/* This is Control register layout. Control register is of 16 bit wide. ++*/ ++ ++enum Mii_GEN_CTRL ++{ /* Description bits R/W default value */ ++ Mii_reset = 0x8000, ++ Mii_Speed_10 = 0x0000, /* 10 Mbps 6:13 RW */ ++ Mii_Speed_100 = 0x2000, /* 100 Mbps 6:13 RW */ ++ Mii_Speed_1000 = 0x0040, /* 1000 Mbit/s 6:13 RW */ ++ ++ Mii_Duplex = 0x0100, /* Full Duplex mode 8 RW */ ++ ++ Mii_Manual_Master_Config = 0x0800, /* Manual Master Config 11 RW */ ++ ++ Mii_Loopback = 0x4000, /* Enable Loop back 14 RW */ ++ Mii_NoLoopback = 0x0000, /* Enable Loop back 14 RW */ ++}; ++ ++enum Mii_Phy_Status ++{ ++ Mii_phy_status_speed_10 = 0x0000, ++ Mii_phy_status_speed_100 = 0x4000, ++ Mii_phy_status_speed_1000 = 0x8000, ++ ++ Mii_phy_status_full_duplex = 0x2000, ++ Mii_phy_status_half_duplex = 0x0000, ++ ++ Mii_phy_status_link_up = 0x0400, ++}; ++/* This is Status register layout. Status register is of 16 bit wide. ++*/ ++enum Mii_GEN_STATUS ++{ ++ Mii_AutoNegCmplt = 0x0020, /* Autonegotiation completed 5 RW */ ++ Mii_Link = 0x0004, /* Link status 2 RW */ ++}; ++ ++enum Mii_Link_Status ++{ ++ LINKDOWN = 0, ++ LINKUP = 1, ++}; ++ ++enum Mii_Duplex_Mode ++{ ++ HALFDUPLEX = 1, ++ FULLDUPLEX = 2, ++}; ++enum Mii_Link_Speed ++{ ++ SPEED10 = 1, ++ SPEED100 = 2, ++ SPEED1000 = 3, ++}; ++ ++enum Mii_Loop_Back ++{ ++ NOLOOPBACK = 0, ++ LOOPBACK = 1, ++}; ++ ++ ++ ++/********************************************************** ++ * GMAC registers Map ++ * For Pci based system address is BARx + GmacRegisterBase ++ * For any other system translation is done accordingly ++ **********************************************************/ ++enum GmacRegisters ++{ ++ GmacConfig = 0x0000, /* Mac config Register */ ++ GmacFrameFilter = 0x0004, /* Mac frame filtering controls */ ++ GmacHashHigh = 0x0008, /* Multi-cast hash table high */ ++ GmacHashLow = 0x000C, /* Multi-cast hash table low */ ++ GmacGmiiAddr = 0x0010, /* GMII address Register(ext. Phy) */ ++ GmacGmiiData = 0x0014, /* GMII data Register(ext. Phy) */ ++ GmacFlowControl = 0x0018, /* Flow control Register */ ++ GmacVlan = 0x001C, /* VLAN tag Register (IEEE 802.1Q) */ ++ ++ GmacVersion = 0x0020, /* GMAC Core Version Register */ ++ GmacWakeupAddr = 0x0028, /* GMAC wake-up frame filter adrress reg */ ++ GmacPmtCtrlStatus = 0x002C, /* PMT control and status register */ ++ ++#ifdef LPI_SUPPORT ++ GmacLPICtrlSts = 0x0030, /* LPI (low power idle) Control and Status Register */ ++ GmacLPITimerCtrl = 0x0034, /* LPI timer control register */ ++#endif ++ ++ GmacInterruptStatus = 0x0038, /* Mac Interrupt ststus register */ ++ GmacInterruptMask = 0x003C, /* Mac Interrupt Mask register */ ++ ++ GmacAddr0High = 0x0040, /* Mac address0 high Register */ ++ GmacAddr0Low = 0x0044, /* Mac address0 low Register */ ++ GmacAddr1High = 0x0048, /* Mac address1 high Register */ ++ GmacAddr1Low = 0x004C, /* Mac address1 low Register */ ++ GmacAddr2High = 0x0050, /* Mac address2 high Register */ ++ GmacAddr2Low = 0x0054, /* Mac address2 low Register */ ++ GmacAddr3High = 0x0058, /* Mac address3 high Register */ ++ GmacAddr3Low = 0x005C, /* Mac address3 low Register */ ++ GmacAddr4High = 0x0060, /* Mac address4 high Register */ ++ GmacAddr4Low = 0x0064, /* Mac address4 low Register */ ++ GmacAddr5High = 0x0068, /* Mac address5 high Register */ ++ GmacAddr5Low = 0x006C, /* Mac address5 low Register */ ++ GmacAddr6High = 0x0070, /* Mac address6 high Register */ ++ GmacAddr6Low = 0x0074, /* Mac address6 low Register */ ++ GmacAddr7High = 0x0078, /* Mac address7 high Register */ ++ GmacAddr7Low = 0x007C, /* Mac address7 low Register */ ++ GmacAddr8High = 0x0080, /* Mac address8 high Register */ ++ GmacAddr8Low = 0x0084, /* Mac address8 low Register */ ++ GmacAddr9High = 0x0088, /* Mac address9 high Register */ ++ GmacAddr9Low = 0x008C, /* Mac address9 low Register */ ++ GmacAddr10High = 0x0090, /* Mac address10 high Register */ ++ GmacAddr10Low = 0x0094, /* Mac address10 low Register */ ++ GmacAddr11High = 0x0098, /* Mac address11 high Register */ ++ GmacAddr11Low = 0x009C, /* Mac address11 low Register */ ++ GmacAddr12High = 0x00A0, /* Mac address12 high Register */ ++ GmacAddr12Low = 0x00A4, /* Mac address12 low Register */ ++ GmacAddr13High = 0x00A8, /* Mac address13 high Register */ ++ GmacAddr13Low = 0x00AC, /* Mac address13 low Register */ ++ GmacAddr14High = 0x00B0, /* Mac address14 high Register */ ++ GmacAddr14Low = 0x00B4, /* Mac address14 low Register */ ++ GmacAddr15High = 0x00B8, /* Mac address15 high Register */ ++ GmacAddr15Low = 0x00BC, /* Mac address15 low Register */ ++ ++ GmacRGMIIControl = 0x00D8, /* SGMII/RGMII/SMII Control and Status Register */ ++ ++ /*Time Stamp Register Map*/ ++ GmacTSControl = 0x0700, /* Controls the Timestamp update logic : only when IEEE 1588 time stamping is enabled in corekit */ ++ ++ GmacTSSubSecIncr = 0x0704, /* 8 bit value by which sub second register is incremented : only when IEEE 1588 time stamping without external timestamp input */ ++ ++ GmacTSHigh = 0x0708, /* 32 bit seconds(MS) : only when IEEE 1588 time stamping without external timestamp input */ ++ GmacTSLow = 0x070C, /* 32 bit nano seconds(MS) : only when IEEE 1588 time stamping without external timestamp input */ ++ ++ GmacTSHighUpdate = 0x0710, /* 32 bit seconds(MS) to be written/added/subtracted : only when IEEE 1588 time stamping without external timestamp input */ ++ GmacTSLowUpdate = 0x0714, /* 32 bit nano seconds(MS) to be writeen/added/subtracted : only when IEEE 1588 time stamping without external timestamp input */ ++ ++ GmacTSAddend = 0x0718, /* Used by Software to readjust the clock frequency linearly : only when IEEE 1588 time stamping without external timestamp input */ ++ ++ GmacTSTargetTimeHigh = 0x071C, /* 32 bit seconds(MS) to be compared with system time : only when IEEE 1588 time stamping without external timestamp input */ ++ GmacTSTargetTimeLow = 0x0720, /* 32 bit nano seconds(MS) to be compared with system time : only when IEEE 1588 time stamping without external timestamp input */ ++ ++ GmacTSHighWord = 0x0724, /* Time Stamp Higher Word Register (Version 2 only); only lower 16 bits are valid */ ++ //GmacTSHighWordUpdate = 0x072C, /* Time Stamp Higher Word Update Register (Version 2 only); only lower 16 bits are valid */ ++ ++ GmacTSStatus = 0x0728, /* Time Stamp Status Register */ ++#ifdef AVB_SUPPORT ++ GmacAvMacCtrl = 0x0738, /* AV mac control Register */ ++#endif ++ ++}; ++ ++/********************************************************** ++ * GMAC Network interface registers ++ * This explains the Register's Layout ++ ++ * FES is Read only by default and is enabled only when Tx ++ * Config Parameter is enabled for RGMII/SGMII interface ++ * during CoreKit Config. ++ ++ * DM is Read only with value 1'b1 in Full duplex only Config ++ **********************************************************/ ++ ++/* GmacConfig = 0x0000, Mac config Register Layout */ ++enum GmacConfigReg ++{ ++ /* Bit description Bits R/W Reset value */ ++ GmacWatchdog = 0x00800000, ++ GmacWatchdogDisable = 0x00800000, /* (WD)Disable watchdog timer on Rx 23 RW */ ++ GmacWatchdogEnable = 0x00000000, /* Enable watchdog timer 0 */ ++ ++ GmacJabber = 0x00400000, ++ GmacJabberDisable = 0x00400000, /* (JD)Disable jabber timer on Tx 22 RW */ ++ GmacJabberEnable = 0x00000000, /* Enable jabber timer 0 */ ++ ++ GmacFrameBurst = 0x00200000, ++ GmacFrameBurstEnable = 0x00200000, /* (BE)Enable frame bursting during Tx 21 RW */ ++ GmacFrameBurstDisable = 0x00000000, /* Disable frame bursting 0 */ ++ ++ GmacJumboFrame = 0x00100000, ++ GmacJumboFrameEnable = 0x00100000, /* (JE)Enable jumbo frame for Tx 20 RW */ ++ GmacJumboFrameDisable = 0x00000000, /* Disable jumbo frame 0 */ ++ ++ GmacInterFrameGap = 0x000E0000, ++ GmacInterFrameGap7 = 0x000E0000, /* (IFG) Config7 - 40 bit times 19:17 RW */ ++ GmacInterFrameGap6 = 0x000C0000, /* (IFG) Config6 - 48 bit times */ ++ GmacInterFrameGap5 = 0x000A0000, /* (IFG) Config5 - 56 bit times */ ++ GmacInterFrameGap4 = 0x00080000, /* (IFG) Config4 - 64 bit times */ ++ GmacInterFrameGap3 = 0x00040000, /* (IFG) Config3 - 72 bit times */ ++ GmacInterFrameGap2 = 0x00020000, /* (IFG) Config2 - 80 bit times */ ++ GmacInterFrameGap1 = 0x00010000, /* (IFG) Config1 - 88 bit times */ ++ GmacInterFrameGap0 = 0x00000000, /* (IFG) Config0 - 96 bit times 000 */ ++ ++ GmacDisableCrs = 0x00010000, ++ GmacMiiGmii = 0x00008000, ++ GmacSelectMii = 0x00008000, /* (PS)Port Select-MII mode 15 RW */ ++ GmacSelectGmii = 0x00000000, /* GMII mode 0 */ ++ ++ GmacFESpeed100 = 0x00004000, /*(FES)Fast Ethernet speed 100Mbps 14 RW */ ++ GmacFESpeed10 = 0x00000000, /* 10Mbps 0 */ ++ ++ GmacRxOwn = 0x00002000, ++ GmacDisableRxOwn = 0x00002000, /* (DO)Disable receive own packets 13 RW */ ++ GmacEnableRxOwn = 0x00000000, /* Enable receive own packets 0 */ ++ ++ GmacLoopback = 0x00001000, ++ GmacLoopbackOn = 0x00001000, /* (LM)Loopback mode for GMII/MII 12 RW */ ++ GmacLoopbackOff = 0x00000000, /* Normal mode 0 */ ++ ++ GmacDuplex = 0x00000800, ++ GmacFullDuplex = 0x00000800, /* (DM)Full duplex mode 11 RW */ ++ GmacHalfDuplex = 0x00000000, /* Half duplex mode 0 */ ++ ++ GmacRxIpcOffload = 0x00000400, /*IPC checksum offload 10 RW 0 */ ++ ++ GmacRetry = 0x00000200, ++ GmacRetryDisable = 0x00000200, /* (DR)Disable Retry 9 RW */ ++ GmacRetryEnable = 0x00000000, /* Enable retransmission as per BL 0 */ ++ ++ GmacLinkUp = 0x00000100, /* (LUD)Link UP 8 RW */ ++ GmacLinkDown = 0x00000100, /* Link Down 0 */ ++ ++ GmacPadCrcStrip = 0x00000080, ++ GmacPadCrcStripEnable = 0x00000080, /* (ACS) Automatic Pad/Crc strip enable 7 RW */ ++ GmacPadCrcStripDisable = 0x00000000, /* Automatic Pad/Crc stripping disable 0 */ ++ ++ GmacBackoffLimit = 0x00000060, ++ GmacBackoffLimit3 = 0x00000060, /* (BL)Back-off limit in HD mode 6:5 RW */ ++ GmacBackoffLimit2 = 0x00000040, /* */ ++ GmacBackoffLimit1 = 0x00000020, /* */ ++ GmacBackoffLimit0 = 0x00000000, /* 00 */ ++ ++ GmacDeferralCheck = 0x00000010, ++ GmacDeferralCheckEnable = 0x00000010, /* (DC)Deferral check enable in HD mode 4 RW */ ++ GmacDeferralCheckDisable = 0x00000000, /* Deferral check disable 0 */ ++ ++ GmacTx = 0x00000008, ++ GmacTxEnable = 0x00000008, /* (TE)Transmitter enable 3 RW */ ++ GmacTxDisable = 0x00000000, /* Transmitter disable 0 */ ++ ++ GmacRx = 0x00000004, ++ GmacRxEnable = 0x00000004, /* (RE)Receiver enable 2 RW */ ++ GmacRxDisable = 0x00000000, /* Receiver disable 0 */ ++}; ++ ++/* GmacFrameFilter = 0x0004, Mac frame filtering controls Register Layout*/ ++enum GmacFrameFilterReg ++{ ++ GmacFilter = 0x80000000, ++ GmacFilterOff = 0x80000000, /* (RA)Receive all incoming packets 31 RW */ ++ GmacFilterOn = 0x00000000, /* Receive filtered packets only 0 */ ++ ++ GmacHashPerfectFilter = 0x00000400, /*Hash or Perfect Filter enable 10 RW 0 */ ++ ++ GmacSrcAddrFilter = 0x00000200, ++ GmacSrcAddrFilterEnable = 0x00000200, /* (SAF)Source Address Filter enable 9 RW */ ++ GmacSrcAddrFilterDisable = 0x00000000, /* 0 */ ++ ++ GmacSrcInvaAddrFilter = 0x00000100, ++ GmacSrcInvAddrFilterEn = 0x00000100, /* (SAIF)Inv Src Addr Filter enable 8 RW */ ++ GmacSrcInvAddrFilterDis = 0x00000000, /* 0 */ ++ ++ GmacPassControl = 0x000000C0, ++ GmacPassControl3 = 0x000000C0, /* (PCS)Forwards ctrl frms that pass AF 7:6 RW */ ++ GmacPassControl2 = 0x00000080, /* Forwards all control frames */ ++ GmacPassControl1 = 0x00000040, /* Does not pass control frames */ ++ GmacPassControl0 = 0x00000000, /* Does not pass control frames 00 */ ++ ++ GmacBroadcast = 0x00000020, ++ GmacBroadcastDisable = 0x00000020, /* (DBF)Disable Rx of broadcast frames 5 RW */ ++ GmacBroadcastEnable = 0x00000000, /* Enable broadcast frames 0 */ ++ ++ GmacMulticastFilter = 0x00000010, ++ GmacMulticastFilterOff = 0x00000010, /* (PM) Pass all multicast packets 4 RW */ ++ GmacMulticastFilterOn = 0x00000000, /* Pass filtered multicast packets 0 */ ++ ++ GmacDestAddrFilter = 0x00000008, ++ GmacDestAddrFilterInv = 0x00000008, /* (DAIF)Inverse filtering for DA 3 RW */ ++ GmacDestAddrFilterNor = 0x00000000, /* Normal filtering for DA 0 */ ++ ++ GmacMcastHashFilter = 0x00000004, ++ GmacMcastHashFilterOn = 0x00000004, /* (HMC)perfom multicast hash filtering 2 RW */ ++ GmacMcastHashFilterOff = 0x00000000, /* perfect filtering only 0 */ ++ ++ GmacUcastHashFilter = 0x00000002, ++ GmacUcastHashFilterOn = 0x00000002, /* (HUC)Unicast Hash filtering only 1 RW */ ++ GmacUcastHashFilterOff = 0x00000000, /* perfect filtering only 0 */ ++ ++ GmacPromiscuousMode = 0x00000001, ++ GmacPromiscuousModeOn = 0x00000001, /* Receive all frames 0 RW */ ++ GmacPromiscuousModeOff = 0x00000000, /* Receive filtered packets only 0 */ ++}; ++ ++ ++/*GmacGmiiAddr = 0x0010, GMII address Register(ext. Phy) Layout */ ++enum GmacGmiiAddrReg ++{ ++ GmiiDevMask = 0x0000F800, /* (PA)GMII device address 15:11 RW 0x00 */ ++ GmiiDevShift = 11, ++ ++ GmiiRegMask = 0x000007C0, /* (GR)GMII register in selected Phy 10:6 RW 0x00 */ ++ GmiiRegShift = 6, ++ ++ GmiiCsrClkMask = 0x0000001C, /*CSR Clock bit Mask 4:2 */ ++ GmiiCsrClk5 = 0x00000014, /* (CR)CSR Clock Range 250-300 MHz 4:2 RW 000 */ ++ GmiiCsrClk4 = 0x00000010, /* 150-250 MHz */ ++ GmiiCsrClk3 = 0x0000000C, /* 35-60 MHz */ ++ GmiiCsrClk2 = 0x00000008, /* 20-35 MHz */ ++ GmiiCsrClk1 = 0x00000004, /* 100-150 MHz */ ++ GmiiCsrClk0 = 0x00000000, /* 60-100 MHz */ ++ ++ GmiiWrite = 0x00000002, /* (GW)Write to register 1 RW */ ++ GmiiRead = 0x00000000, /* Read from register 0 */ ++ ++ GmiiBusy = 0x00000001, /* (GB)GMII interface is busy 0 RW 0 */ ++}; ++ ++/* GmacGmiiData = 0x0014, GMII data Register(ext. Phy) Layout */ ++enum GmacGmiiDataReg ++{ ++ GmiiDataMask = 0x0000FFFF, /* (GD)GMII Data 15:0 RW 0x0000 */ ++}; ++ ++ ++/*GmacFlowControl = 0x0018, Flow control Register Layout */ ++enum GmacFlowControlReg ++{ ++ GmacPauseTimeMask = 0xFFFF0000, /* (PT) PAUSE TIME field in the control frame 31:16 RW 0x0000 */ ++ GmacPauseTimeShift = 16, ++ ++ GmacPauseLowThresh = 0x00000030, ++ GmacPauseLowThresh3 = 0x00000030, /* (PLT)thresh for pause tmr 256 slot time 5:4 RW */ ++ GmacPauseLowThresh2 = 0x00000020, /* 144 slot time */ ++ GmacPauseLowThresh1 = 0x00000010, /* 28 slot time */ ++ GmacPauseLowThresh0 = 0x00000000, /* 4 slot time 000 */ ++ ++ GmacUnicastPauseFrame = 0x00000008, ++ GmacUnicastPauseFrameOn = 0x00000008, /* (UP)Detect pause frame with unicast addr. 3 RW */ ++ GmacUnicastPauseFrameOff = 0x00000000, /* Detect only pause frame with multicast addr. 0 */ ++ ++ GmacRxFlowControl = 0x00000004, ++ GmacRxFlowControlEnable = 0x00000004, /* (RFE)Enable Rx flow control 2 RW */ ++ GmacRxFlowControlDisable = 0x00000000, /* Disable Rx flow control 0 */ ++ ++ GmacTxFlowControl = 0x00000002, ++ GmacTxFlowControlEnable = 0x00000002, /* (TFE)Enable Tx flow control 1 RW */ ++ GmacTxFlowControlDisable = 0x00000000, /* Disable flow control 0 */ ++ ++ GmacFlowControlBackPressure= 0x00000001, ++ GmacSendPauseFrame = 0x00000001, /* (FCB/PBA)send pause frm/Apply back pressure 0 RW 0 */ ++}; ++ ++/* GmacInterruptStatus = 0x0038, Mac Interrupt ststus register */ ++enum GmacInterruptStatusBitDefinition ++{ ++ GmacLPIIS = 0x00000400, /* set if int generated in LPI Interrupt Status */ ++ GmacTSIntSts = 0x00000200, /* set if int generated due to TS (Read Time Stamp Status Register to know details)*/ ++ GmacMmcRxChksumOffload = 0x00000080, /* set if int generated in MMC RX CHECKSUM OFFLOAD int register */ ++ GmacMmcTxIntSts = 0x00000040, /* set if int generated in MMC TX Int register */ ++ GmacMmcRxIntSts = 0x00000020, /* set if int generated in MMC RX Int register */ ++ GmacMmcIntSts = 0x00000010, /* set if any of the above bit [7:5] is set */ ++ GmacPmtIntSts = 0x00000008, /* set whenver magic pkt/wake-on-lan frame is received */ ++ GmacPcsAnComplete = 0x00000004, /* set when AN is complete in TBI/RTBI/SGMIII phy interface */ ++ GmacPcsLnkStsChange = 0x00000002, /* set if any lnk status change in TBI/RTBI/SGMII interface */ ++ GmacRgmiiIntSts = 0x00000001, /* set if any change in lnk status of RGMII interface */ ++ ++}; ++ ++/* GmacInterruptMask = 0x003C, Mac Interrupt Mask register */ ++enum GmacInterruptMaskBitDefinition ++{ ++ GmacTSIntMask = 0x00000200, /* when set disables the time stamp interrupt generation */ ++ GmacPmtIntMask = 0x00000008, /* when set Disables the assertion of PMT interrupt */ ++ GmacPcsAnIntMask = 0x00000004, /* When set disables the assertion of PCS AN complete interrupt */ ++ GmacPcsLnkStsIntMask = 0x00000002, /* when set disables the assertion of PCS lnk status change interrupt */ ++ GmacRgmiiIntMask = 0x00000001, /* when set disables the assertion of RGMII int */ ++}; ++ ++/********************************************************** ++ * GMAC DMA registers ++ * For Pci based system address is BARx + GmaDmaBase ++ * For any other system translation is done accordingly ++ **********************************************************/ ++ ++enum DmaRegisters ++{ ++ DmaBusMode = 0x0000, /* CSR0 - Bus Mode Register */ ++ DmaTxPollDemand = 0x0004, /* CSR1 - Transmit Poll Demand Register */ ++ DmaRxPollDemand = 0x0008, /* CSR2 - Receive Poll Demand Register */ ++ DmaRxBaseAddr = 0x000C, /* CSR3 - Receive Descriptor list base address */ ++ DmaTxBaseAddr = 0x0010, /* CSR4 - Transmit Descriptor list base address */ ++ DmaStatus = 0x0014, /* CSR5 - Dma status Register */ ++ DmaControl = 0x0018, /* CSR6 - Dma Operation Mode Register */ ++ DmaInterrupt = 0x001C, /* CSR7 - Interrupt enable */ ++ DmaMissedFr = 0x0020, /* CSR8 - Missed Frame & Buffer overflow Counter */ ++ DmaAxiMode = 0x0028, /* CSR10 -AXI Bus Mode Register */ ++ DmaTxCurrDesc = 0x0048, /* - Current host Tx Desc Register */ ++ DmaRxCurrDesc = 0x004C, /* - Current host Rx Desc Register */ ++ DmaTxCurrAddr = 0x0050, /* CSR20 - Current host transmit buffer address */ ++ DmaRxCurrAddr = 0x0054, /* CSR21 - Current host receive buffer address */ ++ ++#ifdef AVB_SUPPORT ++ HwFeature = 0x0058, /* Hardware Feature Register */ ++ ++ DmaSlotFnCtrlSts = 0x0030, /* Slot function control and status register */ ++ ++ DmaChannelCtrl = 0x0060, /* Channel Control register only for Channel1 and Channel2 */ ++ DmaChannelAvSts = 0x0064, /* Channel Status register only for Channel1 and Channel2 */ ++ IdleSlopeCredit = 0x0068, /* Idle slope credit register */ ++ SendSlopeCredit = 0x006C, /* Send slope credit register */ ++ HighCredit = 0x0070, /* High Credit register */ ++ LoCredit = 0x0074, /* Lo Credit Register */ ++#endif ++ ++}; ++ ++/********************************************************** ++ * DMA Engine registers Layout ++ **********************************************************/ ++ ++/*DmaBusMode = 0x0000, CSR0 - Bus Mode */ ++enum DmaBusModeReg ++{ ++ /* Bit description Bits R/W Reset value */ ++#ifdef AVB_SUPPORT ++ DmaChannelPrioWt = 0x30000000, /* Channel priority weight mask 29:28 RW 0 */ ++ DmaChannelPrio1 = 0x00000000, /* Channel priority weight 1 29:28 RW 0 */ ++ DmaChannelPrio2 = 0x10000000, /* Channel priority weight 2 29:28 RW 0 */ ++ DmaChannelPrio3 = 0x20000000, /* Channel priority weight 3 29:28 RW 0 */ ++ DmaChannelPrio4 = 0x30000000, /* Channel priority weight 4 29:28 RW 0 */ ++ ++ DmaTxRxPrio = 0x08000000, /* When set indicates Tx Dma has more priority 27 RW 0 */ ++ ++ DmaPriorityRatio11 = 0x00000000, /* (PR)TX:RX DMA priority ratio 1:1 15:14 RW 00 */ ++ DmaPriorityRatio21 = 0x00004000, /* (PR)TX:RX DMA priority ratio 2:1 */ ++ DmaPriorityRatio31 = 0x00008000, /* (PR)TX:RX DMA priority ratio 3:1 */ ++ DmaPriorityRatio41 = 0x0000C000, /* (PR)TX:RX DMA priority ratio 4:1 */ ++ ++ DmaArbitration = 0x00000002, /* Dma Arbitration decides whether strict prio or RR 1 RW 0 */ ++ DmaArbitrationStrict = 0x00000002, /* Dma Arbitration decides whether strict prio or RR 1 RW 0 */ ++ DmaArbitrationRR = 0x00000000, /* Dma Arbitration decides whether strict prio or RR 0 RW 0 */ ++#endif ++ ++ ++ DmaFixedBurstEnable = 0x00010000, /* (FB)Fixed Burst SINGLE, INCR4, INCR8 or INCR16 16 RW */ ++ DmaFixedBurstDisable = 0x00000000, /* SINGLE, INCR 0 */ ++ ++ DmaTxPriorityRatio11 = 0x00000000, /* (PR)TX:RX DMA priority ratio 1:1 15:14 RW 00 */ ++ DmaTxPriorityRatio21 = 0x00004000, /* (PR)TX:RX DMA priority ratio 2:1 */ ++ DmaTxPriorityRatio31 = 0x00008000, /* (PR)TX:RX DMA priority ratio 3:1 */ ++ DmaTxPriorityRatio41 = 0x0000C000, /* (PR)TX:RX DMA priority ratio 4:1 */ ++ ++ DmaBurstLengthx8 = 0x01000000, /* When set mutiplies the PBL by 8 24 RW 0 */ ++ ++ DmaBurstLength256 = 0x01002000, /*(DmaBurstLengthx8 | DmaBurstLength32) = 256 [24]:13:8 */ ++ DmaBurstLength128 = 0x01001000, /*(DmaBurstLengthx8 | DmaBurstLength16) = 128 [24]:13:8 */ ++ DmaBurstLength64 = 0x01000800, /*(DmaBurstLengthx8 | DmaBurstLength8) = 64 [24]:13:8 */ ++ DmaBurstLength32 = 0x00002000, /* (PBL) programmable Dma burst length = 32 13:8 RW */ ++ DmaBurstLength16 = 0x00001000, /* Dma burst length = 16 */ ++ DmaBurstLength8 = 0x00000800, /* Dma burst length = 8 */ ++ DmaBurstLength4 = 0x00000400, /* Dma burst length = 4 */ ++ DmaBurstLength2 = 0x00000200, /* Dma burst length = 2 */ ++ DmaBurstLength1 = 0x00000100, /* Dma burst length = 1 */ ++ DmaBurstLength0 = 0x00000000, /* Dma burst length = 0 0x00 */ ++ ++ DmaDescriptor8Words = 0x00000080, /* Enh Descriptor works 1=> 8 word descriptor 7 0 */ ++ DmaDescriptor4Words = 0x00000000, /* Enh Descriptor works 0=> 4 word descriptor 7 0 */ ++ ++ DmaDescriptorSkip16 = 0x00000040, /* (DSL)Descriptor skip length (no.of dwords) 6:2 RW */ ++ DmaDescriptorSkip8 = 0x00000020, /* between two unchained descriptors */ ++ DmaDescriptorSkip4 = 0x00000010, /* */ ++ DmaDescriptorSkip2 = 0x00000008, /* */ ++ DmaDescriptorSkip1 = 0x00000004, /* */ ++ DmaDescriptorSkip0 = 0x00000000, /* 0x00 */ ++ ++ DmaArbitRr = 0x00000000, /* (DA) DMA RR arbitration 1 RW 0 */ ++ DmaArbitPr = 0x00000002, /* Rx has priority over Tx */ ++ ++ DmaResetOn = 0x00000001, /* (SWR)Software Reset DMA engine 0 RW */ ++ DmaResetOff = 0x00000000, /* 0 */ ++}; ++ ++ ++/*DmaStatus = 0x0014, CSR5 - Dma status Register */ ++enum DmaStatusReg ++{ ++ /*Bit 28 27 and 26 indicate whether the interrupt due to PMT GMACMMC or GMAC LINE Remaining bits are DMA interrupts*/ ++ ++#ifdef AVB_SUPPORT ++ DmaSlotCounterIntr = 0x40000000, /* For Ch1 and Ch2 AVB slot interrupt status 31 RW 0 */ ++#endif ++#ifdef LPI_SUPPORT ++ GmacLPIIntr = 0x40000000, /* GMC LPI interrupt 31 RO 0 */ ++#endif ++ ++ GmacPmtIntr = 0x10000000, /* (GPI)Gmac subsystem interrupt 28 RO 0 */ ++ GmacMmcIntr = 0x08000000, /* (GMI)Gmac MMC subsystem interrupt 27 RO 0 */ ++ GmacLineIntfIntr = 0x04000000, /* Line interface interrupt 26 RO 0 */ ++ ++ DmaErrorBit2 = 0x02000000, /* (EB)Error bits 0-data buffer, 1-desc. access 25 RO 0 */ ++ DmaErrorBit1 = 0x01000000, /* (EB)Error bits 0-write trnsf, 1-read transfr 24 RO 0 */ ++ DmaErrorBit0 = 0x00800000, /* (EB)Error bits 0-Rx DMA, 1-Tx DMA 23 RO 0 */ ++ ++ DmaTxState = 0x00700000, /* (TS)Transmit process state 22:20 RO */ ++ DmaTxStopped = 0x00000000, /* Stopped - Reset or Stop Tx Command issued 000 */ ++ DmaTxFetching = 0x00100000, /* Running - fetching the Tx descriptor */ ++ DmaTxWaiting = 0x00200000, /* Running - waiting for status */ ++ DmaTxReading = 0x00300000, /* Running - reading the data from host memory */ ++ DmaTxSuspended = 0x00600000, /* Suspended - Tx Descriptor unavailabe */ ++ DmaTxClosing = 0x00700000, /* Running - closing Rx descriptor */ ++ ++ DmaRxState = 0x000E0000, /* (RS)Receive process state 19:17 RO */ ++ DmaRxStopped = 0x00000000, /* Stopped - Reset or Stop Rx Command issued 000 */ ++ DmaRxFetching = 0x00020000, /* Running - fetching the Rx descriptor */ ++ DmaRxWaiting = 0x00060000, /* Running - waiting for packet */ ++ DmaRxSuspended = 0x00080000, /* Suspended - Rx Descriptor unavailable */ ++ DmaRxClosing = 0x000A0000, /* Running - closing descriptor */ ++ DmaRxQueuing = 0x000E0000, /* Running - queuing the recieve frame into host memory */ ++ ++ DmaIntNormal = 0x00010000, /* (NIS)Normal interrupt summary 16 RW 0 */ ++ DmaIntAbnormal = 0x00008000, /* (AIS)Abnormal interrupt summary 15 RW 0 */ ++ ++ DmaIntEarlyRx = 0x00004000, /* Early receive interrupt (Normal) RW 0 */ ++ DmaIntBusError = 0x00002000, /* Fatal bus error (Abnormal) RW 0 */ ++ DmaIntEarlyTx = 0x00000400, /* Early transmit interrupt (Abnormal) RW 0 */ ++ DmaIntRxWdogTO = 0x00000200, /* Receive Watchdog Timeout (Abnormal) RW 0 */ ++ DmaIntRxStopped = 0x00000100, /* Receive process stopped (Abnormal) RW 0 */ ++ DmaIntRxNoBuffer = 0x00000080, /* Receive buffer unavailable (Abnormal) RW 0 */ ++ DmaIntRxCompleted = 0x00000040, /* Completion of frame reception (Normal) RW 0 */ ++ DmaIntTxUnderflow = 0x00000020, /* Transmit underflow (Abnormal) RW 0 */ ++ DmaIntRcvOverflow = 0x00000010, /* Receive Buffer overflow interrupt RW 0 */ ++ DmaIntTxJabberTO = 0x00000008, /* Transmit Jabber Timeout (Abnormal) RW 0 */ ++ DmaIntTxNoBuffer = 0x00000004, /* Transmit buffer unavailable (Normal) RW 0 */ ++ DmaIntTxStopped = 0x00000002, /* Transmit process stopped (Abnormal) RW 0 */ ++ DmaIntTxCompleted = 0x00000001, /* Transmit completed (Normal) RW 0 */ ++}; ++ ++/*DmaControl = 0x0018, CSR6 - Dma Operation Mode Register */ ++enum DmaControlReg ++{ ++ DmaDisableDropTcpCs = 0x04000000, /* (DT) Dis. drop. of tcp/ip CS error frames 26 RW 0 */ ++ ++ DmaStoreAndForward = 0x00200000, /* (SF)Store and forward 21 RW 0 */ ++ DmaFlushTxFifo = 0x00100000, /* (FTF)Tx FIFO controller is reset to default 20 RW 0 */ ++ ++ DmaTxThreshCtrl = 0x0001C000, /* (TTC)Controls thre Threh of MTL tx Fifo 16:14 RW */ ++ DmaTxThreshCtrl16 = 0x0001C000, /* (TTC)Controls thre Threh of MTL tx Fifo 16 16:14 RW */ ++ DmaTxThreshCtrl24 = 0x00018000, /* (TTC)Controls thre Threh of MTL tx Fifo 24 16:14 RW */ ++ DmaTxThreshCtrl32 = 0x00014000, /* (TTC)Controls thre Threh of MTL tx Fifo 32 16:14 RW */ ++ DmaTxThreshCtrl40 = 0x00010000, /* (TTC)Controls thre Threh of MTL tx Fifo 40 16:14 RW */ ++ DmaTxThreshCtrl256 = 0x0000c000, /* (TTC)Controls thre Threh of MTL tx Fifo 256 16:14 RW */ ++ DmaTxThreshCtrl192 = 0x00008000, /* (TTC)Controls thre Threh of MTL tx Fifo 192 16:14 RW */ ++ DmaTxThreshCtrl128 = 0x00004000, /* (TTC)Controls thre Threh of MTL tx Fifo 128 16:14 RW */ ++ DmaTxThreshCtrl64 = 0x00000000, /* (TTC)Controls thre Threh of MTL tx Fifo 64 16:14 RW 000 */ ++ ++ DmaTxStart = 0x00002000, /* (ST)Start/Stop transmission 13 RW 0 */ ++ ++ DmaRxFlowCtrlDeact = 0x00401800, /* (RFD)Rx flow control deact. threhold [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact1K = 0x00000000, /* (RFD)Rx flow control deact. threhold (1kbytes) [22]:12:11 RW 00 */ ++ DmaRxFlowCtrlDeact2K = 0x00000800, /* (RFD)Rx flow control deact. threhold (2kbytes) [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact3K = 0x00001000, /* (RFD)Rx flow control deact. threhold (3kbytes) [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact4K = 0x00001800, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact5K = 0x00400000, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact6K = 0x00400800, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ ++ DmaRxFlowCtrlDeact7K = 0x00401000, /* (RFD)Rx flow control deact. threhold (4kbytes) [22]:12:11 RW */ ++ ++ DmaRxFlowCtrlAct = 0x00800600, /* (RFA)Rx flow control Act. threhold [23]:10:09 RW */ ++ DmaRxFlowCtrlAct1K = 0x00000000, /* (RFA)Rx flow control Act. threhold (1kbytes) [23]:10:09 RW 00 */ ++ DmaRxFlowCtrlAct2K = 0x00000200, /* (RFA)Rx flow control Act. threhold (2kbytes) [23]:10:09 RW */ ++ DmaRxFlowCtrlAct3K = 0x00000400, /* (RFA)Rx flow control Act. threhold (3kbytes) [23]:10:09 RW */ ++ DmaRxFlowCtrlAct4K = 0x00000600, /* (RFA)Rx flow control Act. threhold (4kbytes) [23]:10:09 RW */ ++ DmaRxFlowCtrlAct5K = 0x00800000, /* (RFA)Rx flow control Act. threhold (5kbytes) [23]:10:09 RW */ ++ DmaRxFlowCtrlAct6K = 0x00800200, /* (RFA)Rx flow control Act. threhold (6kbytes) [23]:10:09 RW */ ++ DmaRxFlowCtrlAct7K = 0x00800400, /* (RFA)Rx flow control Act. threhold (7kbytes) [23]:10:09 RW */ ++ ++ DmaRxThreshCtrl = 0x00000018, /* (RTC)Controls thre Threh of MTL rx Fifo 4:3 RW */ ++ DmaRxThreshCtrl64 = 0x00000000, /* (RTC)Controls thre Threh of MTL tx Fifo 64 4:3 RW */ ++ DmaRxThreshCtrl32 = 0x00000008, /* (RTC)Controls thre Threh of MTL tx Fifo 32 4:3 RW */ ++ DmaRxThreshCtrl96 = 0x00000010, /* (RTC)Controls thre Threh of MTL tx Fifo 96 4:3 RW */ ++ DmaRxThreshCtrl128 = 0x00000018, /* (RTC)Controls thre Threh of MTL tx Fifo 128 4:3 RW */ ++ ++ DmaEnHwFlowCtrl = 0x00000100, /* (EFC)Enable HW flow control 8 RW */ ++ DmaDisHwFlowCtrl = 0x00000000, /* Disable HW flow control 0 */ ++ ++ DmaFwdErrorFrames = 0x00000080, /* (FEF)Forward error frames 7 RW 0 */ ++ DmaFwdUnderSzFrames = 0x00000040, /* (FUF)Forward undersize frames 6 RW 0 */ ++ DmaTxSecondFrame = 0x00000004, /* (OSF)Operate on second frame 4 RW 0 */ ++ DmaRxStart = 0x00000002, /* (SR)Start/Stop reception 1 RW 0 */ ++}; ++ ++ ++/*DmaInterrupt = 0x001C, CSR7 - Interrupt enable Register Layout */ ++enum DmaInterruptReg ++{ ++ DmaIeNormal = DmaIntNormal , /* Normal interrupt enable RW 0 */ ++ DmaIeAbnormal = DmaIntAbnormal , /* Abnormal interrupt enable RW 0 */ ++ ++ DmaIeEarlyRx = DmaIntEarlyRx , /* Early receive interrupt enable RW 0 */ ++ DmaIeBusError = DmaIntBusError , /* Fatal bus error enable RW 0 */ ++ DmaIeEarlyTx = DmaIntEarlyTx , /* Early transmit interrupt enable RW 0 */ ++ DmaIeRxWdogTO = DmaIntRxWdogTO , /* Receive Watchdog Timeout enable RW 0 */ ++ DmaIeRxStopped = DmaIntRxStopped , /* Receive process stopped enable RW 0 */ ++ DmaIeRxNoBuffer = DmaIntRxNoBuffer , /* Receive buffer unavailable enable RW 0 */ ++ DmaIeRxCompleted = DmaIntRxCompleted, /* Completion of frame reception enable RW 0 */ ++ DmaIeTxUnderflow = DmaIntTxUnderflow, /* Transmit underflow enable RW 0 */ ++ ++ DmaIeRxOverflow = DmaIntRcvOverflow, /* Receive Buffer overflow interrupt RW 0 */ ++ DmaIeTxJabberTO = DmaIntTxJabberTO , /* Transmit Jabber Timeout enable RW 0 */ ++ DmaIeTxNoBuffer = DmaIntTxNoBuffer , /* Transmit buffer unavailable enable RW 0 */ ++ DmaIeTxStopped = DmaIntTxStopped , /* Transmit process stopped enable RW 0 */ ++ DmaIeTxCompleted = DmaIntTxCompleted, /* Transmit completed enable RW 0 */ ++}; ++ ++#ifdef AVB_SUPPORT ++/*DmaSlotFnCtrlSts = 0x0030, Slot function control and status register */ ++enum DmaSlotFnCtrlStsReg ++{ ++ SlotNum = 0x000F0000, /* Current Slot Number 19:16 R0 0 */ ++ AdvSlotInt = 0x00000002, /* Advance the slot interval for data fetch 1 RW 0 */ ++ EnaSlot = 0x00000001, /* Enable checking of Slot number 0 RW 0 */ ++}; ++ ++/* DmaChannelCtrl = 0x0060, Channel Control register only for Channel1 and Channel2 */ ++enum DmaChannelCtrlReg ++{ ++ ChannelSlotIntEn = 0x00020000, /* Channel Slot Interrupt Enable 16 RW 0 */ ++ ChannelSlotCount = 0x00000070, /* Channel Slot Count 6:4 RW 0 */ ++ ChannelCreditCtrl = 0x00000002, /* Channel Credit Control 1 RW 0 */ ++ ChannelCreditShDis = 0x00000001, /* Channel Credit based shaping disable 0 RW 0 */ ++}; ++ ++/* DmaChannelSts = 0x0064, Channel Status register only for Channel1 and Channel2 */ ++enum DmaChannelStsReg ++{ ++ ChannelAvBitsPerSlot = 0x0000FFFF, /* Channel Average Bits per slot 16:0 RO 0 */ ++}; ++ ++/* IdleSlopeCredit = 0x0068, Idle slope credit register */ ++enum IdleSlopeCreditReg ++{ ++ ChannelIdleSlCr = 0x00003FFF, /*Channel Idle Slope Credit 13:0 RW 0 */ ++}; ++ ++/*SendSlopeCredit = 0x006C, Send slope credit register */ ++enum SendSlopeCreditReg ++{ ++ ChannelSendSlCr = 0x00003FFF, /*Channel Send Slope Credit 13:0 RW 0 */ ++}; ++ ++/* HighCredit = 0x0070, High Credit register */ ++enum HighCreditReg ++{ ++ ChannelHiCr = 0x1FFFFFFF, /*Channel Hi Credit 28:0 RW 0 */ ++}; ++ ++/* LoCredit = 0x0074, Lo Credit Register */ ++enum LoCreditReg ++{ ++ ChannelLoCr = 0x1FFFFFFF, /* Channel Lo Credit 28:0 RW 0 */ ++}; ++/*DmaChannelAvSts */ ++enum DmaChannelAvStsReg ++{ ++ ChannelAvgBitsPerSlotMsk = 0x0001FFFF, ++}; ++#endif ++ ++/********************************************************** ++ * DMA Engine descriptors ++ **********************************************************/ ++#ifdef ENH_DESC ++/* ++ **********Enhanced Descritpor structure to support 8K buffer per buffer **************************** ++ ++ DmaRxBaseAddr = 0x000C, CSR3 - Receive Descriptor list base address ++ DmaRxBaseAddr is the pointer to the first Rx Descriptors. the Descriptor format in Little endian with a ++ 32 bit Data bus is as shown below ++ ++ Similarly ++ DmaTxBaseAddr = 0x0010, CSR4 - Transmit Descriptor list base address ++ DmaTxBaseAddr is the pointer to the first Rx Descriptors. the Descriptor format in Little endian with a ++ 32 bit Data bus is as shown below ++ -------------------------------------------------------------------------- ++ RDES0 |OWN (31)| Status | ++ -------------------------------------------------------------------------- ++ RDES1 | Ctrl | Res | Byte Count Buffer 2 | Ctrl | Res | Byte Count Buffer 1 | ++ -------------------------------------------------------------------------- ++ RDES2 | Buffer 1 Address | ++ -------------------------------------------------------------------------- ++ RDES3 | Buffer 2 Address / Next Descriptor Address | ++ -------------------------------------------------------------------------- ++ ++ -------------------------------------------------------------------------- ++ TDES0 |OWN (31)| Ctrl | Res | Ctrl | Res | Status | ++ -------------------------------------------------------------------------- ++ TDES1 | Res | Byte Count Buffer 2 | Res | Byte Count Buffer 1 | ++ -------------------------------------------------------------------------- ++ TDES2 | Buffer 1 Address | ++ -------------------------------------------------------------------------- ++ TDES3 | Buffer 2 Address / Next Descriptor Address | ++ -------------------------------------------------------------------------- ++ ++*/ ++ ++enum DmaDescriptorStatus /* status word of DMA descriptor */ ++{ ++ ++ DescOwnByDma = 0x80000000, /* (OWN)Descriptor is owned by DMA engine 31 RW */ ++ ++ DescDAFilterFail = 0x40000000, /* (AFM)Rx - DA Filter Fail for the rx frame 30 */ ++ ++ DescFrameLengthMask = 0x3FFF0000, /* (FL)Receive descriptor frame length 29:16 */ ++ DescFrameLengthShift = 16, ++ ++ DescError = 0x00008000, /* (ES)Error summary bit - OR of the follo. bits: 15 */ ++ /* DE || OE || IPC || LC || RWT || RE || CE */ ++ DescRxTruncated = 0x00004000, /* (DE)Rx - no more descriptors for receive frame 14 */ ++ DescSAFilterFail = 0x00002000, /* (SAF)Rx - SA Filter Fail for the received frame 13 */ ++ DescRxLengthError = 0x00001000, /* (LE)Rx - frm size not matching with len field 12 */ ++ DescRxDamaged = 0x00000800, /* (OE)Rx - frm was damaged due to buffer overflow 11 */ ++ DescRxVLANTag = 0x00000400, /* (VLAN)Rx - received frame is a VLAN frame 10 */ ++ DescRxFirst = 0x00000200, /* (FS)Rx - first descriptor of the frame 9 */ ++ DescRxLast = 0x00000100, /* (LS)Rx - last descriptor of the frame 8 */ ++ DescRxLongFrame = 0x00000080, /* (Giant Frame)Rx - frame is longer than 1518/1522 7 */ ++ DescRxCollision = 0x00000040, /* (LC)Rx - late collision occurred during reception 6 */ ++ DescRxFrameEther = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ ++ DescRxWatchdog = 0x00000010, /* (RWT)Rx - watchdog timer expired during reception 4 */ ++ DescRxMiiError = 0x00000008, /* (RE)Rx - error reported by MII interface 3 */ ++ DescRxDribbling = 0x00000004, /* (DE)Rx - frame contains non int multiple of 8 bits 2 */ ++ DescRxCrc = 0x00000002, /* (CE)Rx - CRC error 1 */ ++ // DescRxMacMatch = 0x00000001, /* (RX MAC Address) Rx mac address reg(1 to 15)match 0 */ ++ ++ DescRxEXTsts = 0x00000001, /* Extended Status Available (RDES4) 0 */ ++ ++ DescTxIntEnable = 0x40000000, /* (IC)Tx - interrupt on completion 30 */ ++ DescTxLast = 0x20000000, /* (LS)Tx - Last segment of the frame 29 */ ++ DescTxFirst = 0x10000000, /* (FS)Tx - First segment of the frame 28 */ ++ DescTxDisableCrc = 0x08000000, /* (DC)Tx - Add CRC disabled (first segment only) 27 */ ++ DescTxDisablePadd = 0x04000000, /* (DP)disable padding, added by - reyaz 26 */ ++ DescTxEnableTimestamp = 0x02000000, /* (TTSE) Transmit Timestamp Enable 25 */ ++ ++ DescTxCisMask = 0x00c00000, /* Tx checksum offloading control mask 23:22 */ ++ DescTxCisBypass = 0x00000000, /* Checksum bypass */ ++ DescTxCisIpv4HdrCs = 0x00400000, /* IPv4 header checksum */ ++ DescTxCisTcpOnlyCs = 0x00800000, /* TCP/UDP/ICMP checksum. Pseudo header checksum is assumed to be present */ ++ DescTxCisTcpPseudoCs = 0x00c00000, /* TCP/UDP/ICMP checksum fully in hardware including pseudo header */ ++ ++ TxDescEndOfRing = 0x00200000, /* (TER)End of descriptors ring 21 */ ++ TxDescChain = 0x00100000, /* (TCH)Second buffer address is chain address 20 */ ++ ++ DescRxChkBit0 = 0x00000001, /*() Rx - Rx Payload Checksum Error 0 */ ++ DescRxChkBit7 = 0x00000080, /* (IPC CS ERROR)Rx - Ipv4 header checksum error 7 */ ++ DescRxChkBit5 = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ ++ ++ DescRxTSavail = 0x00000080, /* Time stamp available 7 */ ++ DescRxFrameType = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ ++ ++ DescTxIpv4ChkError = 0x00010000, /* (IHE) Tx Ip header error 16 */ ++ DescTxTimeout = 0x00004000, /* (JT)Tx - Transmit jabber timeout 14 */ ++ DescTxFrameFlushed = 0x00002000, /* (FF)Tx - DMA/MTL flushed the frame due to SW flush 13 */ ++ DescTxPayChkError = 0x00001000, /* (PCE) Tx Payload checksum Error 12 */ ++ DescTxLostCarrier = 0x00000800, /* (LC)Tx - carrier lost during tramsmission 11 */ ++ DescTxNoCarrier = 0x00000400, /* (NC)Tx - no carrier signal from the tranceiver 10 */ ++ DescTxLateCollision = 0x00000200, /* (LC)Tx - transmission aborted due to collision 9 */ ++ DescTxExcCollisions = 0x00000100, /* (EC)Tx - transmission aborted after 16 collisions 8 */ ++ DescTxVLANFrame = 0x00000080, /* (VF)Tx - VLAN-type frame 7 */ ++ ++ DescTxCollMask = 0x00000078, /* (CC)Tx - Collision count 6:3 */ ++ DescTxCollShift = 3, ++ ++ DescTxExcDeferral = 0x00000004, /* (ED)Tx - excessive deferral 2 */ ++ DescTxUnderflow = 0x00000002, /* (UF)Tx - late data arrival from the memory 1 */ ++ DescTxDeferred = 0x00000001, /* (DB)Tx - frame transmision deferred 0 */ ++ ++ /* ++ This explains the RDES1/TDES1 bits layout ++ -------------------------------------------------------------------- ++ RDES1/TDES1 | Control Bits | Byte Count Buffer 2 | Byte Count Buffer 1 | ++ -------------------------------------------------------------------- ++ ++*/ ++ // DmaDescriptorLength length word of DMA descriptor ++ ++ ++ RxDisIntCompl = 0x80000000, /* (Disable Rx int on completion) 31 */ ++ RxDescEndOfRing = 0x00008000, /* (TER)End of descriptors ring 15 */ ++ RxDescChain = 0x00004000, /* (TCH)Second buffer address is chain address 14 */ ++ ++ ++ DescSize2Mask = 0x1FFF0000, /* (TBS2) Buffer 2 size 28:16 */ ++ DescSize2Shift = 16, ++ DescSize1Mask = 0x00001FFF, /* (TBS1) Buffer 1 size 12:0 */ ++ DescSize1Shift = 0, ++ ++ ++ /* ++ This explains the RDES4 Extended Status bits layout ++ -------------------------------------------------------------------- ++ RDES4 | Extended Status | ++ -------------------------------------------------------------------- ++ */ ++ ++#ifdef AVB_SUPPORT ++ DescRxVlanPrioVal = 0x001C0000, /* Gives the VLAN Priority Value 20:18 */ ++ DescRxVlanPrioShVal = 18, /* Gives the shift value to get priority value in LS bits */ ++ ++ DescRxAvTagPktRx = 0x00020000, /* Indicates AV tagged Packet is received 17 */ ++ DescRxAvPktRx = 0x00010000, /* Indicates AV Packet received 16 */ ++ ++#endif ++ ++ DescRxPtpAvail = 0x00004000, /* PTP snapshot available 14 */ ++ DescRxPtpVer = 0x00002000, /* When set indicates IEEE1584 Version 2 (else Ver1) 13 */ ++ DescRxPtpFrameType = 0x00001000, /* PTP frame type Indicates PTP sent over ethernet 12 */ ++ DescRxPtpMessageType = 0x00000F00, /* Message Type 11:8 */ ++ DescRxPtpNo = 0x00000000, /* 0000 => No PTP message received */ ++ DescRxPtpSync = 0x00000100, /* 0001 => Sync (all clock types) received */ ++ DescRxPtpFollowUp = 0x00000200, /* 0010 => Follow_Up (all clock types) received */ ++ DescRxPtpDelayReq = 0x00000300, /* 0011 => Delay_Req (all clock types) received */ ++ DescRxPtpDelayResp = 0x00000400, /* 0100 => Delay_Resp (all clock types) received */ ++ DescRxPtpPdelayReq = 0x00000500, /* 0101 => Pdelay_Req (in P to P tras clk) or Announce in Ord and Bound clk */ ++ DescRxPtpPdelayResp = 0x00000600, /* 0110 => Pdealy_Resp(in P to P trans clk) or Management in Ord and Bound clk */ ++ DescRxPtpPdelayRespFP = 0x00000700, /* 0111 => Pdealy_Resp_Follow_Up (in P to P trans clk) or Signaling in Ord and Bound clk */ ++ DescRxPtpIPV6 = 0x00000080, /* Received Packet is in IPV6 Packet 7 */ ++ DescRxPtpIPV4 = 0x00000040, /* Received Packet is in IPV4 Packet 6 */ ++ ++ DescRxChkSumBypass = 0x00000020, /* When set indicates checksum offload engine 5 ++ is bypassed */ ++ DescRxIpPayloadError = 0x00000010, /* When set indicates 16bit IP payload CS is in error 4 */ ++ DescRxIpHeaderError = 0x00000008, /* When set indicates 16bit IPV4 header CS is in 3 ++ error or IP datagram version is not consistent ++ with Ethernet type value */ ++ DescRxIpPayloadType = 0x00000007, /* Indicate the type of payload encapsulated 2:0 ++ in IPdatagram processed by COE (Rx) */ ++ DescRxIpPayloadUnknown= 0x00000000, /* Unknown or didnot process IP payload */ ++ DescRxIpPayloadUDP = 0x00000001, /* UDP */ ++ DescRxIpPayloadTCP = 0x00000002, /* TCP */ ++ DescRxIpPayloadICMP = 0x00000003, /* ICMP */ ++ ++}; ++ ++#else ++/* ++ ++ ********** Default Descritpor structure **************************** ++ DmaRxBaseAddr = 0x000C, CSR3 - Receive Descriptor list base address ++ DmaRxBaseAddr is the pointer to the first Rx Descriptors. the Descriptor format in Little endian with a ++ 32 bit Data bus is as shown below ++ ++ Similarly ++ DmaTxBaseAddr = 0x0010, CSR4 - Transmit Descriptor list base address ++ DmaTxBaseAddr is the pointer to the first Rx Descriptors. the Descriptor format in Little endian with a ++ 32 bit Data bus is as shown below ++ -------------------------------------------------------------------- ++ RDES0/TDES0 |OWN (31)| Status | ++ -------------------------------------------------------------------- ++ RDES1/TDES1 | Control Bits | Byte Count Buffer 2 | Byte Count Buffer 1 | ++ -------------------------------------------------------------------- ++ RDES2/TDES2 | Buffer 1 Address | ++ -------------------------------------------------------------------- ++ RDES3/TDES3 | Buffer 2 Address / Next Descriptor Address | ++ -------------------------------------------------------------------- ++ */ ++enum DmaDescriptorStatus /* status word of DMA descriptor */ ++{ ++ DescOwnByDma = 0x80000000, /* (OWN)Descriptor is owned by DMA engine 31 RW */ ++ ++ DescDAFilterFail = 0x40000000, /* (AFM)Rx - DA Filter Fail for the rx frame 30 */ ++ ++ DescFrameLengthMask = 0x3FFF0000, /* (FL)Receive descriptor frame length 29:16 */ ++ DescFrameLengthShift = 16, ++ ++ DescError = 0x00008000, /* (ES)Error summary bit - OR of the follo. bits: 15 */ ++ /* DE || OE || IPC || LC || RWT || RE || CE */ ++ DescRxTruncated = 0x00004000, /* (DE)Rx - no more descriptors for receive frame 14 */ ++ DescSAFilterFail = 0x00002000, /* (SAF)Rx - SA Filter Fail for the received frame 13 */ ++ DescRxLengthError = 0x00001000, /* (LE)Rx - frm size not matching with len field 12 */ ++ DescRxDamaged = 0x00000800, /* (OE)Rx - frm was damaged due to buffer overflow 11 */ ++ DescRxVLANTag = 0x00000400, /* (VLAN)Rx - received frame is a VLAN frame 10 */ ++ DescRxFirst = 0x00000200, /* (FS)Rx - first descriptor of the frame 9 */ ++ DescRxLast = 0x00000100, /* (LS)Rx - last descriptor of the frame 8 */ ++ DescRxLongFrame = 0x00000080, /* (Giant Frame)Rx - frame is longer than 1518/1522 7 */ ++ DescRxCollision = 0x00000040, /* (LC)Rx - late collision occurred during reception 6 */ ++ DescRxFrameEther = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ ++ DescRxWatchdog = 0x00000010, /* (RWT)Rx - watchdog timer expired during reception 4 */ ++ DescRxMiiError = 0x00000008, /* (RE)Rx - error reported by MII interface 3 */ ++ DescRxDribbling = 0x00000004, /* (DE)Rx - frame contains non int multiple of 8 bits 2 */ ++ DescRxCrc = 0x00000002, /* (CE)Rx - CRC error 1 */ ++ DescRxMacMatch = 0x00000001, /* (RX MAC Address) Rx mac address reg(1 to 15)match 0 */ ++ ++ //Rx Descriptor Checksum Offload engine (type 2) encoding ++ //DescRxPayChkError = 0x00000001, /* () Rx - Rx Payload Checksum Error 0 */ ++ //DescRxIpv4ChkError = 0x00000080, /* (IPC CS ERROR)Rx - Ipv4 header checksum error 7 */ ++ ++ DescRxChkBit0 = 0x00000001, /*() Rx - Rx Payload Checksum Error 0 */ ++ DescRxChkBit7 = 0x00000080, /* (IPC CS ERROR)Rx - Ipv4 header checksum error 7 */ ++ DescRxChkBit5 = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ ++ ++ DescTxIpv4ChkError = 0x00010000, /* (IHE) Tx Ip header error 16 */ ++ DescTxTimeout = 0x00004000, /* (JT)Tx - Transmit jabber timeout 14 */ ++ DescTxFrameFlushed = 0x00002000, /* (FF)Tx - DMA/MTL flushed the frame due to SW flush 13 */ ++ DescTxPayChkError = 0x00001000, /* (PCE) Tx Payload checksum Error 12 */ ++ DescTxLostCarrier = 0x00000800, /* (LC)Tx - carrier lost during tramsmission 11 */ ++ DescTxNoCarrier = 0x00000400, /* (NC)Tx - no carrier signal from the tranceiver 10 */ ++ DescTxLateCollision = 0x00000200, /* (LC)Tx - transmission aborted due to collision 9 */ ++ DescTxExcCollisions = 0x00000100, /* (EC)Tx - transmission aborted after 16 collisions 8 */ ++ DescTxVLANFrame = 0x00000080, /* (VF)Tx - VLAN-type frame 7 */ ++ ++ DescTxCollMask = 0x00000078, /* (CC)Tx - Collision count 6:3 */ ++ DescTxCollShift = 3, ++ ++ DescTxExcDeferral = 0x00000004, /* (ED)Tx - excessive deferral 2 */ ++ DescTxUnderflow = 0x00000002, /* (UF)Tx - late data arrival from the memory 1 */ ++ DescTxDeferred = 0x00000001, /* (DB)Tx - frame transmision deferred 0 */ ++ ++ /* ++ This explains the RDES1/TDES1 bits layout ++ -------------------------------------------------------------------- ++ RDES1/TDES1 | Control Bits | Byte Count Buffer 2 | Byte Count Buffer 1 | ++ -------------------------------------------------------------------- ++ ++*/ ++ //DmaDescriptorLength length word of DMA descriptor ++ ++ DescTxIntEnable = 0x80000000, /* (IC)Tx - interrupt on completion 31 */ ++ DescTxLast = 0x40000000, /* (LS)Tx - Last segment of the frame 30 */ ++ DescTxFirst = 0x20000000, /* (FS)Tx - First segment of the frame 29 */ ++ DescTxDisableCrc = 0x04000000, /* (DC)Tx - Add CRC disabled (first segment only) 26 */ ++ ++ RxDisIntCompl = 0x80000000, /* (Disable Rx int on completion) 31 */ ++ RxDescEndOfRing = 0x02000000, /* (TER)End of descriptors ring */ ++ RxDescChain = 0x01000000, /* (TCH)Second buffer address is chain address 24 */ ++ ++ DescTxDisablePadd = 0x00800000, /* (DP)disable padding, added by - reyaz 23 */ ++ ++ TxDescEndOfRing = 0x02000000, /* (TER)End of descriptors ring */ ++ TxDescChain = 0x01000000, /* (TCH)Second buffer address is chain address 24 */ ++ ++ DescSize2Mask = 0x003FF800, /* (TBS2) Buffer 2 size 21:11 */ ++ DescSize2Shift = 11, ++ DescSize1Mask = 0x000007FF, /* (TBS1) Buffer 1 size 10:0 */ ++ DescSize1Shift = 0, ++ ++ ++ DescTxCisMask = 0x18000000, /* Tx checksum offloading control mask 28:27 */ ++ DescTxCisBypass = 0x00000000, /* Checksum bypass */ ++ DescTxCisIpv4HdrCs = 0x08000000, /* IPv4 header checksum */ ++ DescTxCisTcpOnlyCs = 0x10000000, /* TCP/UDP/ICMP checksum. Pseudo header checksum is assumed to be present */ ++ DescTxCisTcpPseudoCs = 0x18000000, /* TCP/UDP/ICMP checksum fully in hardware including pseudo header */ ++}; ++#endif ++ ++// Rx Descriptor COE type2 encoding ++enum RxDescCOEEncode ++{ ++ RxLenLT600 = 0, /* Bit(5:7:0)=>0 IEEE 802.3 type frame Length field is Lessthan 0x0600 */ ++ RxIpHdrPayLoadChkBypass = 1, /* Bit(5:7:0)=>1 Payload & Ip header checksum bypassed (unsuppported payload) */ ++ RxIpHdrPayLoadRes = 2, /* Bit(5:7:0)=>2 Reserved */ ++ RxChkBypass = 3, /* Bit(5:7:0)=>3 Neither IPv4 nor IPV6. So checksum bypassed */ ++ RxNoChkError = 4, /* Bit(5:7:0)=>4 No IPv4/IPv6 Checksum error detected */ ++ RxPayLoadChkError = 5, /* Bit(5:7:0)=>5 Payload checksum error detected for Ipv4/Ipv6 frames */ ++ RxIpHdrChkError = 6, /* Bit(5:7:0)=>6 Ip header checksum error detected for Ipv4 frames */ ++ RxIpHdrPayLoadChkError = 7, /* Bit(5:7:0)=>7 Payload & Ip header checksum error detected for Ipv4/Ipv6 frames */ ++}; ++ ++/********************************************************** ++ * DMA engine interrupt handling functions ++ **********************************************************/ ++ ++enum synopGMACDmaIntEnum /* Intrerrupt types */ ++{ ++ synopGMACDmaRxNormal = 0x01, /* normal receiver interrupt */ ++ synopGMACDmaRxAbnormal = 0x02, /* abnormal receiver interrupt */ ++ synopGMACDmaRxStopped = 0x04, /* receiver stopped */ ++ synopGMACDmaTxNormal = 0x08, /* normal transmitter interrupt */ ++ synopGMACDmaTxAbnormal = 0x10, /* abnormal transmitter interrupt */ ++ synopGMACDmaTxStopped = 0x20, /* transmitter stopped */ ++ synopGMACDmaError = 0x80, /* Dma engine error */ ++ ++#ifdef AVB_SUPPORT ++ synopGMADmaSlotCounter = 0x40, /* Dma SlotCounter interrupt mask for Channel1 and Channel2*/ ++#endif ++}; ++ ++ ++/********************************************************** ++ * Initial register values ++ **********************************************************/ ++enum InitialRegisters ++{ ++ /* Full-duplex mode with perfect filter on */ ++ GmacConfigInitFdx1000 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable ++ | GmacSelectGmii | GmacEnableRxOwn | GmacLoopbackOff ++ | GmacFullDuplex | GmacRetryEnable | GmacPadCrcStripDisable ++ | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, ++ ++ /* Full-duplex mode with perfect filter on */ ++ GmacConfigInitFdx110 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable ++ | GmacSelectMii | GmacEnableRxOwn | GmacLoopbackOff ++ | GmacFullDuplex | GmacRetryEnable | GmacPadCrcStripDisable ++ | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, ++ ++ /* Full-duplex mode */ ++ // CHANGED: Pass control config, dest addr filter normal, added source address filter, multicast & unicast ++ // Hash filter. ++ /* = GmacFilterOff | GmacPassControlOff | GmacBroadcastEnable */ ++ GmacFrameFilterInitFdx = GmacFilterOn | GmacPassControl0 | GmacBroadcastEnable | GmacSrcAddrFilterDisable ++ | GmacMulticastFilterOn | GmacDestAddrFilterNor | GmacMcastHashFilterOff ++ | GmacPromiscuousModeOff | GmacUcastHashFilterOff, ++ ++ /* Full-duplex mode */ ++ GmacFlowControlInitFdx = GmacUnicastPauseFrameOff | GmacRxFlowControlEnable | GmacTxFlowControlEnable, ++ ++ /* Full-duplex mode */ ++ GmacGmiiAddrInitFdx = GmiiCsrClk2, ++ ++ ++ /* Half-duplex mode with perfect filter on */ ++ // CHANGED: Removed Endian configuration, added single bit config for PAD/CRC strip, ++ /*| GmacSelectMii | GmacLittleEndian | GmacDisableRxOwn | GmacLoopbackOff*/ ++ GmacConfigInitHdx1000 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable ++ | GmacSelectGmii | GmacDisableRxOwn | GmacLoopbackOff ++ | GmacHalfDuplex | GmacRetryEnable | GmacPadCrcStripDisable ++ | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, ++ ++ /* Half-duplex mode with perfect filter on */ ++ GmacConfigInitHdx110 = GmacWatchdogEnable | GmacJabberEnable | GmacFrameBurstEnable | GmacJumboFrameDisable ++ | GmacSelectMii | GmacDisableRxOwn | GmacLoopbackOff ++ | GmacHalfDuplex | GmacRetryEnable | GmacPadCrcStripDisable ++ | GmacBackoffLimit0 | GmacDeferralCheckDisable | GmacTxEnable | GmacRxEnable, ++ ++ /* Half-duplex mode */ ++ GmacFrameFilterInitHdx = GmacFilterOn | GmacPassControl0 | GmacBroadcastEnable | GmacSrcAddrFilterDisable ++ | GmacMulticastFilterOn | GmacDestAddrFilterNor | GmacMcastHashFilterOff ++ | GmacUcastHashFilterOff| GmacPromiscuousModeOff, ++ ++ /* Half-duplex mode */ ++ GmacFlowControlInitHdx = GmacUnicastPauseFrameOff | GmacRxFlowControlDisable | GmacTxFlowControlDisable, ++ ++ /* Half-duplex mode */ ++ GmacGmiiAddrInitHdx = GmiiCsrClk2, ++ ++ ++ ++ /********************************************** ++ *DMA configurations ++ **********************************************/ ++ ++ DmaBusModeInit = DmaFixedBurstEnable | DmaBurstLength8 | DmaDescriptorSkip2 | DmaResetOff | 0x02000000, ++ // DmaBusModeInit = DmaFixedBurstEnable | DmaBurstLength8 | DmaDescriptorSkip4 | DmaResetOff, ++ ++ /* 1000 Mb/s mode */ ++ DmaControlInit1000 = DmaStoreAndForward,// | DmaTxSecondFrame , ++ ++ /* 100 Mb/s mode */ ++ DmaControlInit100 = DmaStoreAndForward, ++ ++ /* 10 Mb/s mode */ ++ DmaControlInit10 = DmaStoreAndForward, ++ ++ /* Interrupt groups */ ++ DmaIntErrorMask = DmaIntBusError, /* Error */ ++ DmaIntRxAbnMask = DmaIntRxNoBuffer, /* receiver abnormal interrupt */ ++ DmaIntRxNormMask = DmaIntRxCompleted, /* receiver normal interrupt */ ++ DmaIntRxStoppedMask = DmaIntRxStopped, /* receiver stopped */ ++ DmaIntTxAbnMask = DmaIntTxUnderflow, /* transmitter abnormal interrupt */ ++ DmaIntTxNormMask = DmaIntTxCompleted, /* transmitter normal interrupt */ ++ DmaIntTxStoppedMask = DmaIntTxStopped, /* transmitter stopped */ ++ ++#if 0 ++ DmaIntEnable = DmaIeNormal | DmaIeAbnormal | DmaIntErrorMask ++ | DmaIntRxAbnMask | DmaIntRxNormMask | DmaIntRxStoppedMask ++ | DmaIntTxAbnMask | DmaIntTxNormMask | DmaIntTxStoppedMask, ++#else ++ DmaIntEnable = DmaIeNormal | DmaIntErrorMask ++ | DmaIntRxNormMask | DmaIntRxStoppedMask ++// | DmaIntTxNormMask | DmaIntTxStoppedMask, ++ | DmaIntTxStoppedMask, ++#endif ++ DmaIntDisable = 0, ++}; ++ ++ ++/********************************************************** ++ * Mac Management Counters (MMC) ++ **********************************************************/ ++ ++enum MMC_ENABLE ++{ ++ GmacMmcCntrl = 0x0100, /* mmc control for operating mode of MMC */ ++ GmacMmcIntrRx = 0x0104, /* maintains interrupts generated by rx counters */ ++ GmacMmcIntrTx = 0x0108, /* maintains interrupts generated by tx counters */ ++ GmacMmcIntrMaskRx = 0x010C, /* mask for interrupts generated from rx counters */ ++ GmacMmcIntrMaskTx = 0x0110, /* mask for interrupts generated from tx counters */ ++}; ++enum MMC_TX ++{ ++ GmacMmcTxOctetCountGb = 0x0114, /*Bytes Tx excl. of preamble and retried bytes (Good or Bad) */ ++ GmacMmcTxFrameCountGb = 0x0118, /*Frames Tx excl. of retried frames (Good or Bad) */ ++ GmacMmcTxBcFramesG = 0x011C, /*Broadcast Frames Tx (Good) */ ++ GmacMmcTxMcFramesG = 0x0120, /*Multicast Frames Tx (Good) */ ++ ++ GmacMmcTx64OctetsGb = 0x0124, /*Tx with len 64 bytes excl. of pre and retried (Good or Bad) */ ++ GmacMmcTx65To127OctetsGb = 0x0128, /*Tx with len >64 bytes <=127 excl. of pre and retried (Good or Bad) */ ++ GmacMmcTx128To255OctetsGb = 0x012C, /*Tx with len >128 bytes <=255 excl. of pre and retried (Good or Bad) */ ++ GmacMmcTx256To511OctetsGb = 0x0130, /*Tx with len >256 bytes <=511 excl. of pre and retried (Good or Bad) */ ++ GmacMmcTx512To1023OctetsGb = 0x0134, /*Tx with len >512 bytes <=1023 excl. of pre and retried (Good or Bad) */ ++ GmacMmcTx1024ToMaxOctetsGb = 0x0138, /*Tx with len >1024 bytes <=MaxSize excl. of pre and retried (Good or Bad) */ ++ ++ GmacMmcTxUcFramesGb = 0x013C, /*Unicast Frames Tx (Good or Bad) */ ++ GmacMmcTxMcFramesGb = 0x0140, /*Multicast Frames Tx (Good and Bad) */ ++ GmacMmcTxBcFramesGb = 0x0144, /*Broadcast Frames Tx (Good and Bad) */ ++ GmacMmcTxUnderFlowError = 0x0148, /*Frames aborted due to Underflow error */ ++ GmacMmcTxSingleColG = 0x014C, /*Successfully Tx Frames after singel collision in Half duplex mode */ ++ GmacMmcTxMultiColG = 0x0150, /*Successfully Tx Frames after more than singel collision in Half duplex mode */ ++ GmacMmcTxDeferred = 0x0154, /*Successfully Tx Frames after a deferral in Half duplex mode */ ++ GmacMmcTxLateCol = 0x0158, /*Frames aborted due to late collision error */ ++ GmacMmcTxExessCol = 0x015C, /*Frames aborted due to excessive (16) collision errors */ ++ GmacMmcTxCarrierError = 0x0160, /*Frames aborted due to carrier sense error (No carrier or Loss of carrier) */ ++ GmacMmcTxOctetCountG = 0x0164, /*Bytes Tx excl. of preamble and retried bytes (Good) */ ++ GmacMmcTxFrameCountG = 0x0168, /*Frames Tx (Good) */ ++ GmacMmcTxExessDef = 0x016C, /*Frames aborted due to excessive deferral errors (deferred for more than 2 max-sized frame times)*/ ++ ++ GmacMmcTxPauseFrames = 0x0170, /*Number of good pause frames Tx. */ ++ GmacMmcTxVlanFramesG = 0x0174, /*Number of good Vlan frames Tx excl. retried frames */ ++}; ++enum MMC_RX ++{ ++ GmacMmcRxFrameCountGb = 0x0180, /*Frames Rx (Good or Bad) */ ++ GmacMmcRxOctetCountGb = 0x0184, /*Bytes Rx excl. of preamble and retried bytes (Good or Bad) */ ++ GmacMmcRxOctetCountG = 0x0188, /*Bytes Rx excl. of preamble and retried bytes (Good) */ ++ GmacMmcRxBcFramesG = 0x018C, /*Broadcast Frames Rx (Good) */ ++ GmacMmcRxMcFramesG = 0x0190, /*Multicast Frames Rx (Good) */ ++ ++ GmacMmcRxCrcError = 0x0194, /*Number of frames received with CRC error */ ++ GmacMmcRxAlignError = 0x0198, /*Number of frames received with alignment (dribble) error. Only in 10/100mode */ ++ GmacMmcRxRuntError = 0x019C, /*Number of frames received with runt (<64 bytes and CRC error) error */ ++ GmacMmcRxJabberError = 0x01A0, /*Number of frames rx with jabber (>1518/1522 or >9018/9022 and CRC) */ ++ GmacMmcRxUnderSizeG = 0x01A4, /*Number of frames received with <64 bytes without any error */ ++ GmacMmcRxOverSizeG = 0x01A8, /*Number of frames received with >1518/1522 bytes without any error */ ++ ++ GmacMmcRx64OctetsGb = 0x01AC, /*Rx with len 64 bytes excl. of pre and retried (Good or Bad) */ ++ GmacMmcRx65To127OctetsGb = 0x01B0, /*Rx with len >64 bytes <=127 excl. of pre and retried (Good or Bad) */ ++ GmacMmcRx128To255OctetsGb = 0x01B4, /*Rx with len >128 bytes <=255 excl. of pre and retried (Good or Bad) */ ++ GmacMmcRx256To511OctetsGb = 0x01B8, /*Rx with len >256 bytes <=511 excl. of pre and retried (Good or Bad) */ ++ GmacMmcRx512To1023OctetsGb = 0x01BC, /*Rx with len >512 bytes <=1023 excl. of pre and retried (Good or Bad) */ ++ GmacMmcRx1024ToMaxOctetsGb = 0x01C0, /*Rx with len >1024 bytes <=MaxSize excl. of pre and retried (Good or Bad) */ ++ ++ GmacMmcRxUcFramesG = 0x01C4, /*Unicast Frames Rx (Good) */ ++ GmacMmcRxLengthError = 0x01C8, /*Number of frames received with Length type field != frame size */ ++ GmacMmcRxOutOfRangeType = 0x01CC, /*Number of frames received with length field != valid frame size */ ++ ++ GmacMmcRxPauseFrames = 0x01D0, /*Number of good pause frames Rx. */ ++ GmacMmcRxFifoOverFlow = 0x01D4, /*Number of missed rx frames due to FIFO overflow */ ++ GmacMmcRxVlanFramesGb = 0x01D8, /*Number of good Vlan frames Rx */ ++ ++ GmacMmcRxWatchdobError = 0x01DC, /*Number of frames rx with error due to watchdog timeout error */ ++}; ++enum MMC_IP_RELATED ++{ ++ GmacMmcRxIpcIntrMask = 0x0200, /*Maintains the mask for interrupt generated from rx IPC statistic counters */ ++ GmacMmcRxIpcIntr = 0x0208, /*Maintains the interrupt that rx IPC statistic counters generate */ ++ ++ GmacMmcRxIpV4FramesG = 0x0210, /*Good IPV4 datagrams received */ ++ GmacMmcRxIpV4HdrErrFrames = 0x0214, /*Number of IPV4 datagrams received with header errors */ ++ GmacMmcRxIpV4NoPayFrames = 0x0218, /*Number of IPV4 datagrams received which didnot have TCP/UDP/ICMP payload */ ++ GmacMmcRxIpV4FragFrames = 0x021C, /*Number of IPV4 datagrams received with fragmentation */ ++ GmacMmcRxIpV4UdpChkDsblFrames = 0x0220, /*Number of IPV4 datagrams received that had a UDP payload checksum disabled */ ++ ++ GmacMmcRxIpV6FramesG = 0x0224, /*Good IPV6 datagrams received */ ++ GmacMmcRxIpV6HdrErrFrames = 0x0228, /*Number of IPV6 datagrams received with header errors */ ++ GmacMmcRxIpV6NoPayFrames = 0x022C, /*Number of IPV6 datagrams received which didnot have TCP/UDP/ICMP payload */ ++ ++ GmacMmcRxUdpFramesG = 0x0230, /*Number of good IP datagrams with good UDP payload */ ++ GmacMmcRxUdpErrorFrames = 0x0234, /*Number of good IP datagrams with UDP payload having checksum error */ ++ ++ GmacMmcRxTcpFramesG = 0x0238, /*Number of good IP datagrams with good TDP payload */ ++ GmacMmcRxTcpErrorFrames = 0x023C, /*Number of good IP datagrams with TCP payload having checksum error */ ++ ++ GmacMmcRxIcmpFramesG = 0x0240, /*Number of good IP datagrams with good Icmp payload */ ++ GmacMmcRxIcmpErrorFrames = 0x0244, /*Number of good IP datagrams with Icmp payload having checksum error */ ++ ++ GmacMmcRxIpV4OctetsG = 0x0250, /*Good IPV4 datagrams received excl. Ethernet hdr,FCS,Pad,Ip Pad bytes */ ++ GmacMmcRxIpV4HdrErrorOctets = 0x0254, /*Number of bytes in IPV4 datagram with header errors */ ++ GmacMmcRxIpV4NoPayOctets = 0x0258, /*Number of bytes in IPV4 datagram with no TCP/UDP/ICMP payload */ ++ GmacMmcRxIpV4FragOctets = 0x025C, /*Number of bytes received in fragmented IPV4 datagrams */ ++ GmacMmcRxIpV4UdpChkDsblOctets = 0x0260, /*Number of bytes received in UDP segment that had UDP checksum disabled */ ++ ++ GmacMmcRxIpV6OctetsG = 0x0264, /*Good IPV6 datagrams received excl. Ethernet hdr,FCS,Pad,Ip Pad bytes */ ++ GmacMmcRxIpV6HdrErrorOctets = 0x0268, /*Number of bytes in IPV6 datagram with header errors */ ++ GmacMmcRxIpV6NoPayOctets = 0x026C, /*Number of bytes in IPV6 datagram with no TCP/UDP/ICMP payload */ ++ ++ GmacMmcRxUdpOctetsG = 0x0270, /*Number of bytes in IP datagrams with good UDP payload */ ++ GmacMmcRxUdpErrorOctets = 0x0274, /*Number of bytes in IP datagrams with UDP payload having checksum error */ ++ ++ GmacMmcRxTcpOctetsG = 0x0278, /*Number of bytes in IP datagrams with good TDP payload */ ++ GmacMmcRxTcpErrorOctets = 0x027C, /*Number of bytes in IP datagrams with TCP payload having checksum error */ ++ ++ GmacMmcRxIcmpOctetsG = 0x0280, /*Number of bytes in IP datagrams with good Icmp payload */ ++ GmacMmcRxIcmpErrorOctets = 0x0284, /*Number of bytes in IP datagrams with Icmp payload having checksum error */ ++}; ++ ++ ++enum MMC_CNTRL_REG_BIT_DESCRIPTIONS ++{ ++ GmacMmcCounterFreeze = 0x00000008, /* when set MMC counters freeze to current value */ ++ GmacMmcCounterResetOnRead = 0x00000004, /* when set MMC counters will be reset to 0 after read */ ++ GmacMmcCounterStopRollover = 0x00000002, /* when set counters will not rollover after max value */ ++ GmacMmcCounterReset = 0x00000001, /* when set all counters wil be reset (automatically cleared after 1 clk) */ ++ ++}; ++ ++enum MMC_RX_INTR_MASK_AND_STATUS_BIT_DESCRIPTIONS ++{ ++ GmacMmcRxWDInt = 0x00800000, /* set when rxwatchdog error reaches half of max value */ ++ GmacMmcRxVlanInt = 0x00400000, /* set when GmacMmcRxVlanFramesGb counter reaches half of max value */ ++ GmacMmcRxFifoOverFlowInt = 0x00200000, /* set when GmacMmcRxFifoOverFlow counter reaches half of max value */ ++ GmacMmcRxPauseFrameInt = 0x00100000, /* set when GmacMmcRxPauseFrames counter reaches half of max value */ ++ GmacMmcRxOutOfRangeInt = 0x00080000, /* set when GmacMmcRxOutOfRangeType counter reaches half of max value */ ++ GmacMmcRxLengthErrorInt = 0x00040000, /* set when GmacMmcRxLengthError counter reaches half of max value */ ++ GmacMmcRxUcFramesInt = 0x00020000, /* set when GmacMmcRxUcFramesG counter reaches half of max value */ ++ GmacMmcRx1024OctInt = 0x00010000, /* set when GmacMmcRx1024ToMaxOctetsGb counter reaches half of max value */ ++ GmacMmcRx512OctInt = 0x00008000, /* set when GmacMmcRx512To1023OctetsGb counter reaches half of max value */ ++ GmacMmcRx256OctInt = 0x00004000, /* set when GmacMmcRx256To511OctetsGb counter reaches half of max value */ ++ GmacMmcRx128OctInt = 0x00002000, /* set when GmacMmcRx128To255OctetsGb counter reaches half of max value */ ++ GmacMmcRx65OctInt = 0x00001000, /* set when GmacMmcRx65To127OctetsG counter reaches half of max value */ ++ GmacMmcRx64OctInt = 0x00000800, /* set when GmacMmcRx64OctetsGb counter reaches half of max value */ ++ GmacMmcRxOverSizeInt = 0x00000400, /* set when GmacMmcRxOverSizeG counter reaches half of max value */ ++ GmacMmcRxUnderSizeInt = 0x00000200, /* set when GmacMmcRxUnderSizeG counter reaches half of max value */ ++ GmacMmcRxJabberErrorInt = 0x00000100, /* set when GmacMmcRxJabberError counter reaches half of max value */ ++ GmacMmcRxRuntErrorInt = 0x00000080, /* set when GmacMmcRxRuntError counter reaches half of max value */ ++ GmacMmcRxAlignErrorInt = 0x00000040, /* set when GmacMmcRxAlignError counter reaches half of max value */ ++ GmacMmcRxCrcErrorInt = 0x00000020, /* set when GmacMmcRxCrcError counter reaches half of max value */ ++ GmacMmcRxMcFramesInt = 0x00000010, /* set when GmacMmcRxMcFramesG counter reaches half of max value */ ++ GmacMmcRxBcFramesInt = 0x00000008, /* set when GmacMmcRxBcFramesG counter reaches half of max value */ ++ GmacMmcRxOctetGInt = 0x00000004, /* set when GmacMmcRxOctetCountG counter reaches half of max value */ ++ GmacMmcRxOctetGbInt = 0x00000002, /* set when GmacMmcRxOctetCountGb counter reaches half of max value */ ++ GmacMmcRxFrameInt = 0x00000001, /* set when GmacMmcRxFrameCountGb counter reaches half of max value */ ++}; ++ ++enum MMC_TX_INTR_MASK_AND_STATUS_BIT_DESCRIPTIONS ++{ ++ ++ GmacMmcTxVlanInt = 0x01000000, /* set when GmacMmcTxVlanFramesG counter reaches half of max value */ ++ GmacMmcTxPauseFrameInt = 0x00800000, /* set when GmacMmcTxPauseFrames counter reaches half of max value */ ++ GmacMmcTxExessDefInt = 0x00400000, /* set when GmacMmcTxExessDef counter reaches half of max value */ ++ GmacMmcTxFrameInt = 0x00200000, /* set when GmacMmcTxFrameCount counter reaches half of max value */ ++ GmacMmcTxOctetInt = 0x00100000, /* set when GmacMmcTxOctetCountG counter reaches half of max value */ ++ GmacMmcTxCarrierErrorInt = 0x00080000, /* set when GmacMmcTxCarrierError counter reaches half of max value */ ++ GmacMmcTxExessColInt = 0x00040000, /* set when GmacMmcTxExessCol counter reaches half of max value */ ++ GmacMmcTxLateColInt = 0x00020000, /* set when GmacMmcTxLateCol counter reaches half of max value */ ++ GmacMmcTxDeferredInt = 0x00010000, /* set when GmacMmcTxDeferred counter reaches half of max value */ ++ GmacMmcTxMultiColInt = 0x00008000, /* set when GmacMmcTxMultiColG counter reaches half of max value */ ++ GmacMmcTxSingleCol = 0x00004000, /* set when GmacMmcTxSingleColG counter reaches half of max value */ ++ GmacMmcTxUnderFlowErrorInt = 0x00002000, /* set when GmacMmcTxUnderFlowError counter reaches half of max value */ ++ GmacMmcTxBcFramesGbInt = 0x00001000, /* set when GmacMmcTxBcFramesGb counter reaches half of max value */ ++ GmacMmcTxMcFramesGbInt = 0x00000800, /* set when GmacMmcTxMcFramesGb counter reaches half of max value */ ++ GmacMmcTxUcFramesInt = 0x00000400, /* set when GmacMmcTxUcFramesGb counter reaches half of max value */ ++ GmacMmcTx1024OctInt = 0x00000200, /* set when GmacMmcTx1024ToMaxOctetsGb counter reaches half of max value */ ++ GmacMmcTx512OctInt = 0x00000100, /* set when GmacMmcTx512To1023OctetsGb counter reaches half of max value */ ++ GmacMmcTx256OctInt = 0x00000080, /* set when GmacMmcTx256To511OctetsGb counter reaches half of max value */ ++ GmacMmcTx128OctInt = 0x00000040, /* set when GmacMmcTx128To255OctetsGb counter reaches half of max value */ ++ GmacMmcTx65OctInt = 0x00000020, /* set when GmacMmcTx65To127OctetsGb counter reaches half of max value */ ++ GmacMmcTx64OctInt = 0x00000010, /* set when GmacMmcTx64OctetsGb counter reaches half of max value */ ++ GmacMmcTxMcFramesInt = 0x00000008, /* set when GmacMmcTxMcFramesG counter reaches half of max value */ ++ GmacMmcTxBcFramesInt = 0x00000004, /* set when GmacMmcTxBcFramesG counter reaches half of max value */ ++ GmacMmcTxFrameGbInt = 0x00000002, /* set when GmacMmcTxFrameCountGb counter reaches half of max value */ ++ GmacMmcTxOctetGbInt = 0x00000001, /* set when GmacMmcTxOctetCountGb counter reaches half of max value */ ++ ++}; ++ ++ ++/********************************************************** ++ * Power Management (PMT) Block ++ **********************************************************/ ++ ++/** ++ * PMT supports the reception of network (remote) wake-up frames and Magic packet frames. ++ * It generates interrupts for wake-up frames and Magic packets received by GMAC. ++ * PMT sits in Rx path and is enabled with remote wake-up frame enable and Magic packet enable. ++ * These enable are in PMT control and Status register and are programmed by apllication. ++ * ++ * When power down mode is enabled in PMT, all rx frames are dropped by the core. Core comes ++ * out of power down mode only when either Magic packe tor a Remote wake-up frame is received ++ * and the corresponding detection is enabled. ++ * ++ * Driver need not be modified to support this feature. Only Api to put the device in to power ++ * down mode is sufficient ++ */ ++ ++#define WAKEUP_REG_LENGTH 8 /*This is the reg length for wake up register configuration*/ ++ ++enum GmacPmtCtrlStatusBitDefinition ++{ ++ GmacPmtFrmFilterPtrReset = 0x80000000, /* when set remote wake-up frame filter register pointer to 3'b000 */ ++ GmacPmtGlobalUnicast = 0x00000200, /* When set enables any unicast packet to be a wake-up frame */ ++ GmacPmtWakeupFrameReceived = 0x00000040, /* Wake up frame received */ ++ GmacPmtMagicPktReceived = 0x00000020, /* Magic Packet received */ ++ GmacPmtWakeupFrameEnable = 0x00000004, /* Wake-up frame enable */ ++ GmacPmtMagicPktEnable = 0x00000002, /* Magic packet enable */ ++ GmacPmtPowerDown = 0x00000001, /* Power Down */ ++}; ++ ++ ++ ++ ++/********************************************************** ++ * IEEE 1588-2008 Precision Time Protocol (PTP) Support ++ **********************************************************/ ++enum PTPMessageType ++{ ++ SYNC = 0x0, ++ Delay_Req = 0x1, ++ Pdelay_Req = 0x2, ++ Pdelay_Resp = 0x3, ++ Follow_up = 0x8, ++ Delay_Resp = 0x9, ++ Pdelay_Resp_Follow_Up = 0xA, ++ Announce = 0xB, ++ Signaling = 0xC, ++ Management = 0xD, ++}; ++ ++ ++ ++typedef struct TimeStampStruct ++{ ++ u32 TSversion; /* PTP Version 1 or PTP version2 */ ++ u32 TSmessagetype; /* Message type associated with this time stamp */ ++ ++ u16 TShighest16; /* Highest 16 bit time stamp value, Valid onley when ADV_TIME_HIGH_WORD configured in corekit */ ++ u32 TSupper32; /* Most significant 32 bit time stamp value */ ++ u32 TSlower32; /* Least Significat 32 bit time stamp value */ ++ ++} TimeStamp; ++ ++ ++/** ++ * IEEE 1588-2008 is the optional module to support Ethernet frame time stamping. ++ * Sixty four (+16) bit time stamps are given in each frames transmit and receive status. ++ * The driver assumes the following ++ * 1. "IEEE 1588 Time Stamping" "TIME_STAMPING"is ENABLED in corekit ++ * 2. "IEEE 1588 External Time Stamp Input Enable" "EXT_TIME_STAMPING" is DISABLED in corekit ++ * 3. "IEEE 1588 Advanced Time Stamp support" "ADV_TIME_STAMPING" is ENABLED in corekit ++ * 4. "IEEE 1588 Higher Word Register Enable" "ADV_TIME_HIGH_WORD" is ENABLED in corekit ++ */ ++ ++/* GmacTSControl = 0x0700, Controls the Timestamp update logic : only when IEEE 1588 time stamping is enabled in corekit */ ++enum GmacTSControlReg ++{ ++ GmacTSENMACADDR = 0x00040000, /* Enable Mac Addr for PTP filtering 18 RW 0 */ ++ ++ GmacTSCLKTYPE = 0x00030000, /* Select the type of clock node 17:16 RW 00 */ ++ /* ++ TSCLKTYPE TSMSTRENA TSEVNTENA Messages for wihich TS snapshot is taken ++ 00/01 X 0 SYNC, FOLLOW_UP, DELAY_REQ, DELAY_RESP ++ 00/01 1 0 DELAY_REQ ++ 00/01 0 1 SYNC ++ 10 NA 0 SYNC, FOLLOW_UP, DELAY_REQ, DELAY_RESP ++ 10 NA 1 SYNC, FOLLOW_UP ++ 11 NA 0 SYNC, FOLLOW_UP, DELAY_REQ, DELAY_RESP, PDELAY_REQ, PDELAY_RESP ++ 11 NA 1 SYNC, PDELAY_REQ, PDELAY_RESP ++ */ ++ GmacTSOrdClk = 0x00000000, /* 00=> Ordinary clock*/ ++ GmacTSBouClk = 0x00010000, /* 01=> Boundary clock*/ ++ GmacTSEtoEClk = 0x00020000, /* 10=> End-to-End transparent clock*/ ++ GmacTSPtoPClk = 0x00030000, /* 11=> P-to-P transparent clock*/ ++ ++ GmacTSMSTRENA = 0x00008000, /* Ena TS Snapshot for Master Messages 15 RW 0 */ ++ GmacTSEVNTENA = 0x00004000, /* Ena TS Snapshot for Event Messages 14 RW 0 */ ++ GmacTSIPV4ENA = 0x00002000, /* Ena TS snapshot for IPv4 13 RW 1 */ ++ GmacTSIPV6ENA = 0x00001000, /* Ena TS snapshot for IPv6 12 RW 0 */ ++ GmacTSIPENA = 0x00000800, /* Ena TS snapshot for PTP over E'net 11 RW 0 */ ++ GmacTSVER2ENA = 0x00000400, /* Ena PTP snooping for version 2 10 RW 0 */ ++ ++ GmacTSCTRLSSR = 0x00000200, /* Digital or Binary Rollover 9 RW 0 */ ++ ++ GmacTSENALL = 0x00000100, /* Enable TS fro all frames (Ver2 only) 8 RW 0 */ ++ ++ GmacTSADDREG = 0x00000020, /* Addend Register Update 5 RW_SC 0 */ ++ GmacTSUPDT = 0x00000008, /* Time Stamp Update 3 RW_SC 0 */ ++ GmacTSINT = 0x00000004, /* Time Atamp Initialize 2 RW_SC 0 */ ++ ++ GmacTSTRIG = 0x00000010, /* Time stamp interrupt Trigger Enable 4 RW_SC 0 */ ++ ++ GmacTSCFUPDT = 0x00000002, /* Time Stamp Fine/Coarse 1 RW 0 */ ++ GmacTSCUPDTCoarse = 0x00000000, /* 0=> Time Stamp update method is coarse */ ++ GmacTSCUPDTFine = 0x00000002, /* 1=> Time Stamp update method is fine */ ++ ++ GmacTSENA = 0x00000001, /* Time Stamp Enable 0 RW 0 */ ++}; ++ ++ ++/* GmacTSSubSecIncr = 0x0704, 8 bit value by which sub second register is incremented : only when IEEE 1588 time stamping without external timestamp input */ ++enum GmacTSSubSecIncrReg ++{ ++ GmacSSINCMsk = 0x000000FF, /* Only Lower 8 bits are valid bits 7:0 RW 00 */ ++}; ++ ++/* GmacTSLow = 0x070C, Indicates whether the timestamp low count is positive or negative; for Adv timestamp it is always zero */ ++enum GmacTSSign ++{ ++ GmacTSSign = 0x80000000, /* PSNT 31 RW 0 */ ++ GmacTSPositive = 0x00000000, ++ GmacTSNegative = 0x80000000, ++}; ++ ++/*GmacTargetTimeLow = 0x0718, 32 bit nano seconds(MS) to be compared with system time : only when IEEE 1588 time stamping without external timestamp input */ ++enum GmacTSLowReg ++{ ++ GmacTSDecThr = 0x3B9AC9FF, /*when TSCTRLSSR is set the max value for GmacTargetTimeLowReg and GmacTimeStampLow register is 0x3B9AC9FF at 1ns precision */ ++}; ++ ++/* GmacTSHighWord = 0x0724, Time Stamp Higher Word Register (Version 2 only); only lower 16 bits are valid */ ++enum GmacTSHighWordReg ++{ ++ GmacTSHighWordMask = 0x0000FFFF, /* Time Stamp Higher work register has only lower 16 bits valid */ ++}; ++/*GmacTSStatus = 0x0728, Time Stamp Status Register */ ++enum GmacTSStatusReg ++{ ++ GmacTSTargTimeReached = 0x00000002, /* Time Stamp Target Time Reached 1 RO 0 */ ++ GmacTSSecondsOverflow = 0x00000001, /* Time Stamp Seconds Overflow 0 RO 0 */ ++}; ++ ++/* GmacAvMacCtrl = 0x0738, AV mac control Register */ ++#ifdef AVB_SUPPORT ++enum GmacAvMacCtrlReg ++{ ++ GmacAvCtrlCh = 0x03000000, /* Channel on which AV control packets to be received 25:24 RW 0 */ ++ GmacPtpCh = 0x00180000, /* Channel on which PTP packets to be received 20:19 RW 0 */ ++ GmacAvPrio = 0x00070000, /* Priority tag value for AV Packets 18:16 RW 4 */ ++ GmacAvTypeMask = 0x0000FFFF, /* Ethernet Type value to be used for comparing and detecting AV packet 15:0 RW 0 */ ++}; ++#endif ++ ++/********************************************************** ++ * Time stamp related functions ++ **********************************************************/ ++void synopGMAC_TS_enable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_disable(synopGMACdevice *gmacdev); ++ ++void synopGMAC_TS_int_enable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_int_disable(synopGMACdevice *gmacdev); ++ ++void synopGMAC_TS_mac_addr_filt_enable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_mac_addr_filt_disable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_set_clk_type(synopGMACdevice *gmacdev, u32 clk_type); ++void synopGMAC_TS_master_enable(synopGMACdevice *gmacdev); // Only for Ordinary clock and Boundary clock and "Advanced Time Stamp" ++void synopGMAC_TS_master_disable(synopGMACdevice *gmacdev); // Only for Ordinary clock and Boundary clock and "Advanced Time Stamp" ++void synopGMAC_TS_event_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_event_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_IPV4_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_IPV4_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_IPV6_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_IPV6_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_ptp_over_ethernet_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_ptp_over_ethernet_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_pkt_snoop_ver2(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_pkt_snoop_ver1(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++ ++void synopGMAC_TS_digital_rollover_enable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_binary_rollover_enable(synopGMACdevice *gmacdev); ++void synopGMAC_TS_all_frames_enable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++void synopGMAC_TS_all_frames_disable(synopGMACdevice *gmacdev); // Only for "Advanced Time Stamp" ++ ++s32 synopGMAC_TS_addend_update(synopGMACdevice *gmacdev, u32 addend_value); ++s32 synopGMAC_TS_timestamp_update(synopGMACdevice *gmacdev, u32 high_value, u32 low_value); ++s32 synopGMAC_TS_timestamp_init(synopGMACdevice *gmacdev, u32 high_value, u32 low_value); ++ ++void synopGMAC_TS_coarse_update(synopGMACdevice *gmacdev); // Only if "fine correction" enabled ++void synopGMAC_TS_fine_update(synopGMACdevice *gmacdev); // Only if "fine correction" enabled ++ ++void synopGMAC_TS_subsecond_init(synopGMACdevice *gmacdev, u32 sub_sec_inc_val); // Update should happen making use of subsecond mask ++void synopGMAC_TS_read_timestamp(synopGMACdevice *gmacdev, u16 * higher_sec_val, ++ u32 * sec_val, u32 * sub_sec_val); // Reads the timestamp low,high and higher(Ver2) registers in the the struct pointer; readonly contents ++void synopGMAC_TS_load_target_timestamp(synopGMACdevice *gmacdev, u32 sec_val, u32 sub_sec_val); //Loads the timestamp target register with the values provided ++ ++void synopGMAC_TS_load_timestamp_higher_val(synopGMACdevice *gmacdev, u32 higher_sec_val); ++void synopGMAC_TS_read_timestamp_higher_val(synopGMACdevice *gmacdev, u16 * higher_sec_val); ++void synopGMAC_TS_read_target_timestamp(synopGMACdevice *gmacdev, u32 * sec_val, u32 * sub_sec_val); //Read the target time stamp register contents ++ ++ ++/********************************************************** ++ * Common functions ++ **********************************************************/ ++s32 synopGMAC_set_mdc_clk_div(synopGMACdevice *gmacdev,u32 clk_div_val); ++u32 synopGMAC_get_mdc_clk_div(synopGMACdevice *gmacdev); ++u32 synopGMAC_calculate_mdc_clk_csr(u32 sysclk, u32 max_mdcclk); ++s32 synopGMAC_read_phy_reg(synopGMACdevice *gmacdev, u32 PhyBase, u32 RegOffset, u16 * data); ++s32 synopGMAC_write_phy_reg(synopGMACdevice *gmacdev, u32 PhyBase, u32 RegOffset, u16 data); ++s32 synopGMAC_phy_loopback(synopGMACdevice *gmacdev, bool loopback); ++s32 synopGMAC_read_version (synopGMACdevice * gmacdev) ; ++s32 synopGMAC_reset (synopGMACdevice * gmacdev ); ++s32 synopGMAC_dma_bus_mode_init(synopGMACdevice * gmacdev, u32 init_value ); ++s32 synopGMAC_dma_control_init(synopGMACdevice * gmacdev, u32 init_value); ++void synopGMAC_wd_enable(synopGMACdevice * gmacdev); ++void synopGMAC_wd_disable(synopGMACdevice * gmacdev); ++void synopGMAC_jab_enable(synopGMACdevice * gmacdev); ++void synopGMAC_jab_disable(synopGMACdevice * gmacdev); ++void synopGMAC_frame_burst_enable(synopGMACdevice * gmacdev); ++void synopGMAC_frame_burst_disable(synopGMACdevice * gmacdev); ++void synopGMAC_jumbo_frame_enable(synopGMACdevice * gmacdev); ++void synopGMAC_jumbo_frame_disable(synopGMACdevice * gmacdev); ++void synopGMAC_set_Inter_Frame_Gap(synopGMACdevice * gmacdev, u32 value); ++void synopGMAC_select_gmii(synopGMACdevice * gmacdev); ++void synopGMAC_select_mii(synopGMACdevice * gmacdev); ++void synopGMAC_select_speed1000(synopGMACdevice * gmacdev); ++void synopGMAC_select_speed100(synopGMACdevice * gmacdev); ++void synopGMAC_select_speed10(synopGMACdevice * gmacdev); ++void synopGMAC_rx_own_enable(synopGMACdevice * gmacdev); ++void synopGMAC_rx_own_disable(synopGMACdevice * gmacdev); ++void synopGMAC_loopback_on(synopGMACdevice * gmacdev); ++void synopGMAC_loopback_off(synopGMACdevice * gmacdev); ++void synopGMAC_set_full_duplex(synopGMACdevice * gmacdev); ++void synopGMAC_set_half_duplex(synopGMACdevice * gmacdev); ++void synopGMAC_retry_enable(synopGMACdevice * gmacdev); ++void synopGMAC_retry_disable(synopGMACdevice * gmacdev); ++void synopGMAC_pad_crc_strip_enable(synopGMACdevice * gmacdev); ++void synopGMAC_pad_crc_strip_disable(synopGMACdevice * gmacdev); ++void synopGMAC_back_off_limit(synopGMACdevice * gmacdev, u32 value); ++void synopGMAC_deferral_check_enable(synopGMACdevice * gmacdev); ++void synopGMAC_deferral_check_disable(synopGMACdevice * gmacdev); ++void synopGMAC_rx_enable(synopGMACdevice * gmacdev); ++void synopGMAC_rx_disable(synopGMACdevice * gmacdev); ++void synopGMAC_tx_enable(synopGMACdevice * gmacdev); ++void synopGMAC_tx_disable(synopGMACdevice * gmacdev); ++void synopGMAC_frame_filter_enable(synopGMACdevice * gmacdev); ++void synopGMAC_frame_filter_disable(synopGMACdevice * gmacdev); ++void synopGMAC_write_hash_table_high(synopGMACdevice * gmacdev, u32 data); ++void synopGMAC_write_hash_table_low(synopGMACdevice * gmacdev, u32 data); ++void synopGMAC_hash_perfect_filter_enable(synopGMACdevice * gmacdev); ++void synopGMAC_Hash_filter_only_enable(synopGMACdevice * gmacdev); ++void synopGMAC_src_addr_filter_enable(synopGMACdevice * gmacdev); ++void synopGMAC_src_addr_filter_disable(synopGMACdevice * gmacdev); ++void synopGMAC_dst_addr_filter_inverse(synopGMACdevice * gmacdev); ++void synopGMAC_dst_addr_filter_normal(synopGMACdevice * gmacdev); ++void synopGMAC_set_pass_control(synopGMACdevice * gmacdev,u32 passcontrol); ++void synopGMAC_broadcast_enable(synopGMACdevice * gmacdev); ++void synopGMAC_broadcast_disable(synopGMACdevice * gmacdev); ++void synopGMAC_multicast_enable(synopGMACdevice * gmacdev); ++void synopGMAC_multicast_disable(synopGMACdevice * gmacdev); ++void synopGMAC_multicast_hash_filter_enable(synopGMACdevice * gmacdev); ++void synopGMAC_multicast_hash_filter_disable(synopGMACdevice * gmacdev); ++void synopGMAC_promisc_enable(synopGMACdevice * gmacdev); ++void synopGMAC_promisc_disable(synopGMACdevice * gmacdev); ++void synopGMAC_unicast_hash_filter_enable(synopGMACdevice * gmacdev); ++void synopGMAC_unicast_hash_filter_disable(synopGMACdevice * gmacdev); ++void synopGMAC_unicast_pause_frame_detect_enable(synopGMACdevice * gmacdev); ++void synopGMAC_unicast_pause_frame_detect_disable(synopGMACdevice * gmacdev); ++void synopGMAC_rx_flow_control_enable(synopGMACdevice * gmacdev); ++void synopGMAC_rx_flow_control_disable(synopGMACdevice * gmacdev); ++void synopGMAC_tx_flow_control_enable(synopGMACdevice * gmacdev); ++void synopGMAC_tx_flow_control_disable(synopGMACdevice * gmacdev); ++void synopGMAC_tx_activate_flow_control(synopGMACdevice * gmacdev); ++void synopGMAC_tx_deactivate_flow_control(synopGMACdevice * gmacdev); ++void synopGMAC_pause_control(synopGMACdevice *gmacdev); ++s32 synopGMAC_mac_init(synopGMACdevice * gmacdev); ++s32 synopGMAC_search_phy (synopGMACdevice * gmacdev); ++s32 synopGMAC_check_phy_init (synopGMACdevice * gmacdev); ++s32 synopGMAC_set_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr); ++s32 synopGMAC_get_mac_addr(synopGMACdevice *gmacdev, u32 MacHigh, u32 MacLow, u8 *MacAddr); ++s32 synopGMAC_attach (synopGMACdevice * gmacdev, u32 macBase, u32 dmaBase, u32 phyBase); ++void synopGMAC_rx_desc_init_ring(DmaDesc *desc, bool last_ring_desc); ++void synopGMAC_tx_desc_init_ring(DmaDesc *desc, bool last_ring_desc); ++void synopGMAC_rx_desc_init_chain(DmaDesc * desc); ++void synopGMAC_tx_desc_init_chain(DmaDesc * desc); ++s32 synopGMAC_init_tx_rx_desc_queue(synopGMACdevice *gmacdev); ++void synopGMAC_init_rx_desc_base(synopGMACdevice *gmacdev); ++void synopGMAC_init_tx_desc_base(synopGMACdevice *gmacdev); ++void synopGMAC_set_owner_dma(DmaDesc *desc); ++void synopGMAC_set_desc_sof(DmaDesc *desc); ++void synopGMAC_set_desc_eof(DmaDesc *desc); ++bool synopGMAC_is_sof_in_rx_desc(DmaDesc *desc); ++bool synopGMAC_is_eof_in_rx_desc(DmaDesc *desc); ++bool synopGMAC_is_da_filter_failed(DmaDesc *desc); ++bool synopGMAC_is_sa_filter_failed(DmaDesc *desc); ++bool synopGMAC_is_desc_owned_by_dma(DmaDesc *desc); ++u32 synopGMAC_get_rx_desc_frame_length(u32 status); ++bool synopGMAC_is_desc_valid(u32 status); ++bool synopGMAC_is_desc_empty(DmaDesc *desc); ++bool synopGMAC_is_rx_desc_valid(u32 status); ++bool synopGMAC_is_tx_aborted(u32 status); ++bool synopGMAC_is_tx_carrier_error(u32 status); ++u32 synopGMAC_get_tx_collision_count(u32 status); ++u32 synopGMAC_is_exc_tx_collisions(u32 status); ++bool synopGMAC_is_rx_frame_damaged(u32 status); ++bool synopGMAC_is_rx_frame_collision(u32 status); ++bool synopGMAC_is_rx_crc(u32 status); ++bool synopGMAC_is_frame_dribbling_errors(u32 status); ++bool synopGMAC_is_rx_frame_length_errors(u32 status); ++bool synopGMAC_is_last_rx_desc(synopGMACdevice * gmacdev,DmaDesc *desc); ++bool synopGMAC_is_last_tx_desc(synopGMACdevice * gmacdev,DmaDesc *desc); ++bool synopGMAC_is_rx_desc_chained(DmaDesc * desc); ++bool synopGMAC_is_tx_desc_chained(DmaDesc * desc); ++void synopGMAC_get_desc_data(DmaDesc * desc, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2); ++#ifdef ENH_DESC_8W ++s32 synopGMAC_get_tx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2, ++ u32 * Ext_Status, u32 * Time_Stamp_High, u32 * Time_Stamp_low); ++#else ++s32 synopGMAC_get_tx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2 ); ++#endif ++s32 synopGMAC_set_tx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2,u32 offload_needed); ++s32 synopGMAC_set_rx_qptr(synopGMACdevice * gmacdev, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2); ++#ifdef ENH_DESC_8W ++s32 synopGMAC_get_rx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2, ++ u32 * Ext_Status, u32 * Time_Stamp_High, u32 * Time_Stamp_low); ++#else ++s32 synopGMAC_get_rx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2); ++#endif ++void synopGMAC_clear_interrupt(synopGMACdevice *gmacdev); ++u32 synopGMAC_get_interrupt_type(synopGMACdevice *gmacdev); ++u32 synopGMAC_get_interrupt_mask(synopGMACdevice *gmacdev); ++void synopGMAC_enable_interrupt(synopGMACdevice *gmacdev, u32 interrupts); ++void synopGMAC_disable_interrupt_all(synopGMACdevice *gmacdev); ++void synopGMAC_disable_interrupt(synopGMACdevice *gmacdev, u32 interrupts); ++void synopGMAC_enable_dma_rx(synopGMACdevice * gmacdev); ++void synopGMAC_enable_dma_tx(synopGMACdevice * gmacdev); ++void synopGMAC_resume_dma_tx(synopGMACdevice * gmacdev); ++void synopGMAC_resume_dma_rx(synopGMACdevice * gmacdev); ++void synopGMAC_take_desc_ownership(DmaDesc * desc); ++void synopGMAC_take_desc_ownership_rx(synopGMACdevice * gmacdev); ++void synopGMAC_take_desc_ownership_tx(synopGMACdevice * gmacdev); ++void synopGMAC_disable_dma_tx(synopGMACdevice * gmacdev); ++void synopGMAC_disable_dma_rx(synopGMACdevice * gmacdev); ++/******Following APIs are valid only for Enhanced Descriptor from 3.50a release onwards*******/ ++bool synopGMAC_is_ext_status(synopGMACdevice *gmacdev,u32 status); ++bool synopGMAC_ES_is_IP_header_error(synopGMACdevice *gmacdev,u32 ext_status); ++bool synopGMAC_ES_is_rx_checksum_bypassed(synopGMACdevice *gmacdev,u32 ext_status); ++bool synopGMAC_ES_is_IP_payload_error(synopGMACdevice *gmacdev,u32 ext_status); ++/*******************PMT APIs***************************************/ ++void synopGMAC_pmt_int_enable(synopGMACdevice *gmacdev); ++void synopGMAC_pmt_int_disable(synopGMACdevice *gmacdev); ++void synopGMAC_power_down_enable(synopGMACdevice *gmacdev); ++void synopGMAC_power_down_disable(synopGMACdevice *gmacdev); ++void synopGMAC_enable_pmt_interrupt(synopGMACdevice *gmacdev); ++void synopGMAC_disable_pmt_interrupt(synopGMACdevice *gmacdev); ++void synopGMAC_magic_packet_enable(synopGMACdevice *gmacdev); ++void synopGMAC_wakeup_frame_enable(synopGMACdevice *gmacdev); ++void synopGMAC_pmt_unicast_enable(synopGMACdevice *gmacdev); ++bool synopGMAC_is_magic_packet_received(synopGMACdevice *gmacdev); ++bool synopGMAC_is_wakeup_frame_received(synopGMACdevice *gmacdev); ++void synopGMAC_write_wakeup_frame_register(synopGMACdevice *gmacdev, u32 * filter_contents); ++/*******************MMC APIs***************************************/ ++void synopGMAC_mmc_counters_stop(synopGMACdevice *gmacdev); ++void synopGMAC_mmc_counters_resume(synopGMACdevice *gmacdev); ++void synopGMAC_mmc_counters_set_selfclear(synopGMACdevice *gmacdev); ++void synopGMAC_mmc_counters_reset_selfclear(synopGMACdevice *gmacdev); ++void synopGMAC_mmc_counters_disable_rollover(synopGMACdevice *gmacdev); ++void synopGMAC_mmc_counters_enable_rollover(synopGMACdevice *gmacdev); ++u32 synopGMAC_read_mmc_counter(synopGMACdevice *gmacdev, u32 counter); ++u32 synopGMAC_read_mmc_rx_int_status(synopGMACdevice *gmacdev); ++u32 synopGMAC_read_mmc_tx_int_status(synopGMACdevice *gmacdev); ++void synopGMAC_disable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++void synopGMAC_enable_mmc_tx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++void synopGMAC_disable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++void synopGMAC_enable_mmc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++void synopGMAC_enable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++void synopGMAC_disable_mmc_ipc_rx_interrupt(synopGMACdevice *gmacdev, u32 mask); ++/*******************Ip checksum offloading APIs***************************************/ ++void synopGMAC_enable_rx_chksum_offload(synopGMACdevice *gmacdev); ++void synopGMAC_disable_rx_Ipchecksum_offload(synopGMACdevice *gmacdev); ++void synopGMAC_rx_tcpip_chksum_drop_enable(synopGMACdevice *gmacdev); ++void synopGMAC_rx_tcpip_chksum_drop_disable(synopGMACdevice *gmacdev); ++u32 synopGMAC_is_rx_checksum_error(synopGMACdevice *gmacdev, u32 status); ++bool synopGMAC_is_tx_ipv4header_checksum_error(synopGMACdevice *gmacdev, u32 status); ++bool synopGMAC_is_tx_payload_checksum_error(synopGMACdevice *gmacdev, u32 status); ++void synopGMAC_tx_checksum_offload_bypass(synopGMACdevice *gmacdev, DmaDesc *desc); ++void synopGMAC_tx_checksum_offload_ipv4hdr(synopGMACdevice *gmacdev, DmaDesc *desc); ++void synopGMAC_tx_checksum_offload_tcponly(synopGMACdevice *gmacdev, DmaDesc *desc); ++void synopGMAC_tx_checksum_offload_tcp_pseudo(synopGMACdevice *gmacdev, DmaDesc *desc); ++#ifdef AVB_SUPPORT ++void synopGMACsetAvType(synopGMACdevice *gmacdev, u32 avtype); ++void synopGMACsetAvPrio(synopGMACdevice * gmacdev,u8 priority); ++void synopGMACsetAvCtrlCh(synopGMACdevice * gmacdev,u8 channel); ++void synopGMACsetAvPTPCh (synopGMACdevice * gmacdev,u8 channel); ++void synopGMACsetTxRxPrioPolicy(synopGMACdevice * gmacdev,u8 policy); ++void synopGMACsetTxRxPrio(synopGMACdevice * gmacdev,u8 tx_has_high_prio); ++void synopGMACsetTxRxPrioRatio(synopGMACdevice * gmacdev,u8 tx_rx_prio_ratio); ++void synopGMACsetChPrioWts(synopGMACdevice * gmacdev,u8 weights); ++void synopGMACAvbEnSlot(synopGMACdevice * gmacdev); ++void synopGMACAvbDisSlot (synopGMACdevice * gmacdev); ++void synopGMACAvbEnAdvSlotInt(synopGMACdevice * gmacdev); ++void synopGMACAvbDisAdvSlotInt(synopGMACdevice * gmacdev); ++void synopGMACAvbSetSlotCount(synopGMACdevice * gmacdev, u8 slotcount); ++void synopGMACAvbEnSlotInterrupt(synopGMACdevice * gmacdev); ++void synopGMACAvbDisSlotInterrupt(synopGMACdevice * gmacdev); ++void synopGMACAvbEnableCrSh(synopGMACdevice * gmacdev); ++void synopGMACAvbDisableCrSh(synopGMACdevice * gmacdev); ++void synopGMACAvbEnableCrControl(synopGMACdevice * gmacdev); ++void synopGMACAvbDisableCrControl(synopGMACdevice * gmacdev); ++void synopGMACsetAvbSendSlope(synopGMACdevice * gmacdev,u32 sendslope_val); ++void synopGMACsetAvbIdleSlope(synopGMACdevice * gmacdev,u32 idleslope_val); ++void synopGMACsetAvbHiCredit(synopGMACdevice * gmacdev,u32 hicredit_val); ++void synopGMACsetAvbLoCredit(synopGMACdevice * gmacdev,u32 locredit_val); ++ ++void synopGMAC_set_desc_data(DmaDesc *txdesc, u32 Status, u32 Buffer1, u32 Length1, u32 Data1, u32 Buffer2, u32 Length2, u32 Data2); ++#endif ++ ++ ++#endif /* End of file */ +diff --git a/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_plat.c b/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_plat.c +new file mode 100644 +index 000000000..d46736f8c +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_plat.c +@@ -0,0 +1,94 @@ ++/* =================================================================================== ++ * Copyright (c) <2009> Synopsys, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy of ++ * this software annotated with this license and associated documentation files ++ * (the "Software"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ++ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE ++ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * =================================================================================== */ ++ ++/**\file ++ * This file defines the wrapper for the platform/OS related functions ++ * The function definitions needs to be modified according to the platform ++ * and the Operating system used. ++ * This file should be handled with greatest care while porting the driver ++ * to a different platform running different operating system other than ++ * Linux 2.6.xx. ++ * \internal ++ * ----------------------------REVISION HISTORY----------------------------- ++ * Synopsys 01/Aug/2007 Created ++ */ ++ ++#include "synopGMAC_plat.h" ++ ++/** ++ * This is a wrapper function for Memory allocation routine. In linux Kernel ++ * it it kmalloc function ++ * @param[in] bytes in bytes to allocate ++ */ ++ ++void *plat_alloc_memory(u32 bytes) ++{ ++ return kmalloc((size_t)bytes, GFP_KERNEL); ++} ++ ++/** ++ * This is a wrapper function for consistent dma-able Memory allocation routine. ++ * @param[in] bytes in bytes to allocate ++ */ ++ ++void *plat_alloc_consistent_dmaable_memory(struct device *dev, u32 size, u32 *addr) ++{ ++ return dma_alloc_coherent(dev, size, addr, GFP_ATOMIC); ++} ++ ++/** ++ * This is a wrapper function for freeing consistent dma-able Memory. ++ * @param[in] bytes in bytes to allocate ++ */ ++ ++void plat_free_consistent_dmaable_memory(struct device *dev, u32 size, void * addr,u32 dma_addr) ++{ ++ dma_free_coherent(dev, size, addr, dma_addr); ++} ++ ++ ++ ++/** ++ * This is a wrapper function for Memory free routine. In linux Kernel ++ * it it kfree function ++ * @param[in] buffer pointer to be freed ++ */ ++void plat_free_memory(void *buffer) ++{ ++ kfree(buffer); ++ return ; ++} ++ ++ ++/** ++ * This is a wrapper function for platform dependent delay ++ * Take care while passing the argument to this function ++ * @param[in] buffer pointer to be freed ++ */ ++void plat_delay(u32 delay) ++{ ++ while (delay--); ++ return; ++} ++ ++ ++ +diff --git a/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_plat.h b/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_plat.h +new file mode 100644 +index 000000000..a69319e80 +--- /dev/null ++++ b/module_drivers/drivers/net/ethernet/ingenic/synopGMAC_plat.h +@@ -0,0 +1,211 @@ ++/* =================================================================================== ++ * Copyright (c) <2009> Synopsys, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy of ++ * this software annotated with this license and associated documentation files ++ * (the "Software"), to deal in the Software without restriction, including without ++ * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ++ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ++ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE ++ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * =================================================================================== */ ++ ++/**\file ++ * This file serves as the wrapper for the platform/OS dependent functions ++ * It is needed to modify these functions accordingly based on the platform and the ++ * OS. Whenever the synopsys GMAC driver ported on to different platform, this file ++ * should be handled at most care. ++ * The corresponding function definitions for non-inline functions are available in ++ * synopGMAC_plat.c file. ++ * \internal ++ * -------------------------------------REVISION HISTORY--------------------------- ++ * Synopsys 01/Aug/2007 Created ++ */ ++ ++ ++#ifndef SYNOP_GMAC_PLAT_H ++#define SYNOP_GMAC_PLAT_H 1 ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TR0(fmt, args...) printk(KERN_CRIT "SynopGMAC: " fmt, ##args) ++ ++extern int debug_enable; ++ ++#if 0 ++#ifdef DEBUG ++#undef TR ++# define TR(fmt, args...) printk(KERN_CRIT "SynopGMAC: " fmt, ##args) ++#else ++# define TR(fmt, args...) /* not debugging: nothing */ ++#endif ++#endif ++ ++#define TR(fmt, args...) \ ++ do { \ ++ if (debug_enable) { \ ++ printk(KERN_CRIT "SynopGMAC: " fmt, ##args); \ ++ } \ ++ } while(0) ++ ++#if 0 ++typedef int bool; ++enum synopGMAC_boolean ++ { ++ false = 0, ++ true = 1 ++ }; ++#endif ++ ++#if (defined(CONFIG_SOC_X2000) || defined(CONFIG_SOC_M300) || defined(CONFIG_SOC_X2100) || defined(CONFIG_SOC_X2500) || defined(CONFIG_SOC_X1600)) ++#define LPI_SUPPORT ++#endif ++ ++#define DEFAULT_DELAY_VARIABLE 10 ++#define DEFAULT_LOOP_VARIABLE 10000 ++ ++/* There are platform related endian conversions ++ * ++ */ ++ ++#define LE32_TO_CPU __le32_to_cpu ++#define BE32_TO_CPU __be32_to_cpu ++#define CPU_TO_LE32 __cpu_to_le32 ++ ++/* Error Codes */ ++#define ESYNOPGMACNOERR 0 ++#define ESYNOPGMACNOMEM 1 ++#define ESYNOPGMACPHYERR 2 ++#define ESYNOPGMACBUSY 3 ++ ++struct Network_interface_data ++{ ++ u32 unit; ++ u32 addr; ++ u32 data; ++}; ++ ++ ++/** ++ * These are the wrapper function prototypes for OS/platform related routines ++ */ ++ ++void * plat_alloc_memory(u32 ); ++void plat_free_memory(void *); ++ ++void * plat_alloc_consistent_dmaable_memory(struct device *, u32, u32 *); ++void plat_free_consistent_dmaable_memory (struct device *, u32, void *, u32); ++ ++void plat_delay(u32); ++ ++ ++/** ++ * The Low level function to read register contents from Hardware. ++ * ++ * @param[in] pointer to the base of register map ++ * @param[in] Offset from the base ++ * \return Returns the register contents ++ */ ++static u32 __inline__ synopGMACReadReg(u32 *RegBase, u32 RegOffset) ++{ ++ ++ u32 addr = (u32)RegBase + RegOffset; ++ u32 data = readl((void *)addr); ++ //printk("=====>%s: RegBase = 0x%08x RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, (u32)RegBase, RegOffset, data ); ++ return data; ++} ++ ++/** ++ * The Low level function to write to a register in Hardware. ++ * ++ * @param[in] pointer to the base of register map ++ * @param[in] Offset from the base ++ * @param[in] Data to be written ++ * \return void ++ */ ++static void __inline__ synopGMACWriteReg(u32 *RegBase, u32 RegOffset, u32 RegData) ++{ ++ ++ u32 addr = (u32)RegBase + RegOffset; ++ //printk("=====>%s RegBase = 0x%08x RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__,(u32) RegBase, RegOffset, RegData ); ++ writel(RegData,(void *)addr); ++ //*((volatile unsigned int *)addr) = RegData; ++ return; ++} ++ ++/** ++ * The Low level function to set bits of a register in Hardware. ++ * ++ * @param[in] pointer to the base of register map ++ * @param[in] Offset from the base ++ * @param[in] Bit mask to set bits to logical 1 ++ * \return void ++ */ ++static void __inline__ synopGMACSetBits(u32 *RegBase, u32 RegOffset, u32 BitPos) ++{ ++ u32 addr = (u32)RegBase + RegOffset; ++ u32 data = readl((void *)addr); ++ data |= BitPos; ++// TR("%s !!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, RegOffset, data ); ++ writel(data,(void *)addr); ++// TR("%s !!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, RegOffset, data ); ++ return; ++} ++ ++ ++/** ++ * The Low level function to clear bits of a register in Hardware. ++ * ++ * @param[in] pointer to the base of register map ++ * @param[in] Offset from the base ++ * @param[in] Bit mask to clear bits to logical 0 ++ * \return void ++ */ ++static void __inline__ synopGMACClearBits(u32 *RegBase, u32 RegOffset, u32 BitPos) ++{ ++ u32 addr = (u32)RegBase + RegOffset; ++ u32 data = readl((void *)addr); ++ data &= (~BitPos); ++// TR("%s !!!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, RegOffset, data ); ++ writel(data,(void *)addr); ++// TR("%s !!!!!!!!!!!!! RegOffset = 0x%08x RegData = 0x%08x\n", __FUNCTION__, RegOffset, data ); ++ return; ++} ++ ++/** ++ * The Low level function to Check the setting of the bits. ++ * ++ * @param[in] pointer to the base of register map ++ * @param[in] Offset from the base ++ * @param[in] Bit mask to set bits to logical 1 ++ * \return returns TRUE if set to '1' returns FALSE if set to '0'. Result undefined there are no bit set in the BitPos argument. ++ * ++ */ ++static bool __inline__ synopGMACCheckBits(u32 *RegBase, u32 RegOffset, u32 BitPos) ++{ ++ u32 addr = (u32)RegBase + RegOffset; ++ u32 data = readl((void *)addr); ++ data &= BitPos; ++ if(data) return true; ++ else return false; ++ ++} ++ ++ ++#endif +diff --git a/module_drivers/drivers/net/wireless/Kconfig b/module_drivers/drivers/net/wireless/Kconfig +new file mode 100644 +index 000000000..fe6b1103b +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/Kconfig +@@ -0,0 +1,2 @@ ++source "module_drivers/drivers/net/wireless/bcmdhd/Kconfig" ++source "module_drivers/drivers/net/wireless/realtek/rtl8723ds/Kconfig" +diff --git a/module_drivers/drivers/net/wireless/Makefile b/module_drivers/drivers/net/wireless/Makefile +new file mode 100644 +index 000000000..65455a54f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/Makefile +@@ -0,0 +1,4 @@ ++obj-$(CONFIG_BCMDHD) += bcmdhd/ ++obj-y += realtek/ ++ ++ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/Kconfig b/module_drivers/drivers/net/wireless/bcmdhd/Kconfig +new file mode 100644 +index 000000000..fffcee200 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/Kconfig +@@ -0,0 +1,60 @@ ++config BCMDHD ++ tristate "Broadcom FullMAC wireless cards support" ++ help ++ This module adds support for wireless adapters based on ++ Broadcom FullMAC chipset. ++ ++config BCMDHD_FW_PATH ++ depends on BCMDHD ++ string "Firmware path" ++ default "/system/etc/firmware/fw_bcmdhd.bin" ++ help ++ Path to the firmware file. ++ ++config BCMDHD_NVRAM_PATH ++ depends on BCMDHD ++ string "NVRAM path" ++ default "/system/etc/firmware/nvram.txt" ++ help ++ Path to the calibration file. ++ ++config BCMDHD_WEXT ++ bool "Enable WEXT support" ++ depends on BCMDHD && CFG80211 = n ++ select WIRELESS_EXT ++ select WEXT_PRIV ++ help ++ Enables WEXT support ++ ++choice ++ prompt "Enable Chip Interface" ++ depends on BCMDHD ++ help ++ Enable Chip Interface. ++config BCMDHD_SDIO ++ bool "SDIO bus interface support" ++ depends on BCMDHD && MMC ++config BCMDHD_PCIE ++ bool "PCIe bus interface support" ++ depends on BCMDHD && PCI ++config BCMDHD_USB ++ bool "USB bus interface support" ++ depends on BCMDHD && USB ++endchoice ++ ++choice ++ depends on BCMDHD && BCMDHD_SDIO ++ prompt "Interrupt type" ++ help ++ Interrupt type ++config BCMDHD_OOB ++ depends on BCMDHD && BCMDHD_SDIO ++ bool "Out-of-Band Interrupt" ++ help ++ Interrupt from WL_HOST_WAKE. ++config BCMDHD_SDIO_IRQ ++ depends on BCMDHD && BCMDHD_SDIO ++ bool "In-Band Interrupt" ++ help ++ Interrupt from SDIO DAT[1] ++endchoice +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/Makefile b/module_drivers/drivers/net/wireless/bcmdhd/Makefile +new file mode 100644 +index 000000000..31c21657c +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/Makefile +@@ -0,0 +1,169 @@ ++# bcmdhd ++ ++MODULE_NAME := bcmdhd ++#CONFIG_BCMDHD := m ++#CONFIG_BCMDHD_SDIO := y ++#CONFIG_BCMDHD_PCIE := y ++#CONFIG_BCMDHD_USB := y ++ ++#CONFIG_BCMDHD_OOB := y ++#CONFIG_BCMDHD_CUSB := y ++CONFIG_BCMDHD_PROPTXSTATUS := y ++#CONFIG_DHD_USE_STATIC_BUF := y ++#CONFIG_VTS_SUPPORT := y ++ ++CONFIG_MACH_PLATFORM := y ++#CONFIG_BCMDHD_DTS := y ++ ++DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ ++ -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ ++ -DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DBCMDBG -DGET_OTP_MAC_ENABLE \ ++ -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY \ ++ -DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DDHDTCPACK_SUPPRESS \ ++ -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT \ ++ -DMULTIPLE_SUPPLICANT -DTSQ_MULTIPLIER -DMFP -DDHD_8021X_DUMP \ ++ -DWL_EXT_IAPSTA -DWL_ESCAN -DCCODE_LIST \ ++ -DENABLE_INSMOD_NO_FW_LOAD \ ++ -I$(srctree)/$(src) -I$(srctree)/$(src)/include ++ ++DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \ ++ dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o \ ++ dhd_common.o dhd_ip.o dhd_linux_wq.o dhd_custom_gpio.o \ ++ bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o bcmxtlv.o \ ++ dhd_debug_linux.o dhd_debug.o dhd_mschdbg.o hnd_pktq.o hnd_pktpool.o \ ++ dhd_config.o dhd_ccode.o wl_event.o wl_android_ext.o wl_escan.o ++ ++ifneq ($(CONFIG_WIRELESS_EXT),) ++ DHDOFILES += wl_iw.o ++ DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW ++endif ++ifneq ($(CONFIG_CFG80211),) ++ DHDOFILES += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o ++ DHDOFILES += dhd_cfg80211.o ++ DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF ++ DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS ++ DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7 ++ DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL ++ DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES ++ DHDCFLAGS += -DESCAN_RESULT_PATCH -DESCAN_BUF_OVERFLOW_MGMT ++ DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST ++ DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8 ++ DHDCFLAGS += -DWL_VIRTUAL_APSTA ++ DHDCFLAGS += -DPNO_SUPPORT -DEXPLICIT_DISCIF_CLEANUP ++# DHDCFLAGS += -DWL_SAE ++endif ++ ++#BCMDHD_SDIO ++ifneq ($(CONFIG_BCMDHD_SDIO),) ++DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR \ ++ -DSDTEST -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256 \ ++ -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DRXFRAME_THREAD \ ++ -DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS \ ++ -DBCMSDIO_RXLIM_POST -DCONSOLE_DPC ++ifeq ($(CONFIG_BCMDHD_OOB),y) ++ DHDCFLAGS += -DOOB_INTR_ONLY -DCUSTOMER_OOB -DHW_OOB ++ifeq ($(CONFIG_BCMDHD_DISABLE_WOWLAN),y) ++ DHDCFLAGS += -DDISABLE_WOWLAN ++endif ++else ++ DHDCFLAGS += -DSDIO_ISR_THREAD ++endif ++DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \ ++ dhd_sdio.o dhd_cdc.o dhd_wlfc.o ++endif ++ ++#BCMDHD_PCIE ++ifneq ($(CONFIG_BCMDHD_PCIE),) ++DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1 \ ++ -DDONGLE_ENABLE_ISOLATION ++DHDCFLAGS += -DDHD_LB -DDHD_LB_RXP -DDHD_LB_STATS #-DDHD_LB_TXP ++ifeq ($(CONFIG_BCMDHD_OOB),y) ++ DHDCFLAGS += -DCUSTOMER_OOB -DBCMPCIE_OOB_HOST_WAKE ++endif ++ifneq ($(CONFIG_PCI_MSI),) ++ DHDCFLAGS += -DDHD_USE_MSI ++endif ++DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o \ ++ dhd_msgbuf.o ++endif ++ ++#BCMDHD_USB ++ifneq ($(CONFIG_BCMDHD_USB),) ++DHDCFLAGS += -DUSBOS_TX_THREAD -DBCMDBUS -DBCMTRXV2 -DDBUS_USB_LOOPBACK \ ++ -DBDC ++DHDCFLAGS += -DBCM_REQUEST_FW -DEXTERNAL_FW_PATH ++#DHDCFLAGS :=$(filter-out -DENABLE_INSMOD_NO_FW_LOAD,$(DHDCFLAGS)) ++ifneq ($(CONFIG_BCMDHD_CUSB),) ++ DHDCFLAGS += -DBCMUSBDEV_COMPOSITE ++ DHDCFLAGS :=$(filter-out -DENABLE_INSMOD_NO_FW_LOAD,$(DHDCFLAGS)) ++endif ++DHDOFILES += dbus.o dbus_usb.o dbus_usb_linux.o dhd_cdc.o dhd_wlfc.o ++endif ++ ++#PROPTXSTATUS ++ifeq ($(CONFIG_BCMDHD_PROPTXSTATUS),y) ++ifneq ($(CONFIG_BCMDHD_USB),) ++ DHDCFLAGS += -DPROP_TXSTATUS ++endif ++ifneq ($(CONFIG_BCMDHD_SDIO),) ++ DHDCFLAGS += -DPROP_TXSTATUS ++endif ++ifneq ($(CONFIG_CFG80211),) ++ DHDCFLAGS += -DPROP_TXSTATUS_VSDB ++endif ++endif ++ ++#VTS_SUPPORT ++ifeq ($(CONFIG_VTS_SUPPORT),y) ++ifneq ($(CONFIG_CFG80211),) ++DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT -DLINKSTAT_SUPPORT \ ++ -DCUSTOM_COUNTRY_CODE \ ++ -DDEBUGABILITY -DDBG_PKT_MON -DDHD_FW_COREDUMP \ ++ -DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT -DDHD_WAKE_STATUS ++DHDOFILES += dhd_rtt.o bcm_app_utils.o ++endif ++endif ++ ++# MESH support for kernel 3.10 later ++ifeq ($(CONFIG_WL_MESH),y) ++ DHDCFLAGS += -DWLMESH ++ifneq ($(CONFIG_CFG80211),) ++ DHDCFLAGS += -DWLMESH_CFG80211 ++endif ++ifneq ($(CONFIG_BCMDHD_PCIE),) ++ DHDCFLAGS += -DBCM_HOST_BUF -DDMA_HOST_BUFFER_LEN=0x80000 ++endif ++ DHDCFLAGS += -DDHD_UPDATE_INTF_MAC ++ DHDCFLAGS :=$(filter-out -DDHD_FW_COREDUMP,$(DHDCFLAGS)) ++ DHDCFLAGS :=$(filter-out -DSET_RANDOM_MAC_SOFTAP,$(DHDCFLAGS)) ++endif ++ ++obj-$(CONFIG_BCMDHD) += $(MODULE_NAME).o ++$(MODULE_NAME)-objs += $(DHDOFILES) ++ ++ifeq ($(CONFIG_MACH_PLATFORM),y) ++ DHDOFILES += dhd_gpio.o ++ifeq ($(CONFIG_BCMDHD_DTS),y) ++ DHDCFLAGS += -DCONFIG_DTS ++else ++ DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT ++endif ++ DHDCFLAGS += -DCUSTOMER_HW_INGENIC ++# DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI ++endif ++ ++ifeq ($(CONFIG_BCMDHD_AG),y) ++ DHDCFLAGS += -DBAND_AG ++endif ++ ++ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y) ++ obj-m += dhd_static_buf.o ++ DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF ++ DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF ++ DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP ++endif ++ ++EXTRA_CFLAGS = $(DHDCFLAGS) ++ifeq ($(CONFIG_BCMDHD),m) ++EXTRA_LDFLAGS += --strip-debug ++endif +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/README b/module_drivers/drivers/net/wireless/bcmdhd/README +new file mode 100644 +index 000000000..4b292ae0f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/README +@@ -0,0 +1,2 @@ ++版本更新: ++当å‰ç‰ˆæœ¬ bcmdhd.1.579.77.41.x +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/aiutils.c b/module_drivers/drivers/net/wireless/bcmdhd/aiutils.c +new file mode 100644 +index 000000000..f88b12336 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/aiutils.c +@@ -0,0 +1,1810 @@ ++/* ++ * Misc utility routines for accessing chip-specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: aiutils.c 625027 2016-03-15 08:20:18Z $ ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "siutils_priv.h" ++#include ++ ++#define BCM5357_DMP() (0) ++#define BCM53573_DMP() (0) ++#define BCM4707_DMP() (0) ++#define PMU_DMP() (0) ++#define GCI_DMP() (0) ++#define remap_coreid(sih, coreid) (coreid) ++#define remap_corerev(sih, corerev) (corerev) ++ ++/* EROM parsing */ ++ ++static uint32 ++get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) ++{ ++ uint32 ent; ++ uint inv = 0, nom = 0; ++ uint32 size = 0; ++ ++ while (TRUE) { ++ ent = R_REG(si_osh(sih), *eromptr); ++ (*eromptr)++; ++ ++ if (mask == 0) ++ break; ++ ++ if ((ent & ER_VALID) == 0) { ++ inv++; ++ continue; ++ } ++ ++ if (ent == (ER_END | ER_VALID)) ++ break; ++ ++ if ((ent & mask) == match) ++ break; ++ ++ /* escape condition related EROM size if it has invalid values */ ++ size += sizeof(*eromptr); ++ if (size >= ER_SZ_MAX) { ++ SI_ERROR(("Failed to find end of EROM marker\n")); ++ break; ++ } ++ ++ nom++; ++ } ++ ++ SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); ++ if (inv + nom) { ++ SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom)); ++ } ++ return ent; ++} ++ ++static uint32 ++get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, ++ uint32 *sizel, uint32 *sizeh) ++{ ++ uint32 asd, sz, szd; ++ ++ BCM_REFERENCE(ad); ++ ++ asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); ++ if (((asd & ER_TAG1) != ER_ADD) || ++ (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || ++ ((asd & AD_ST_MASK) != st)) { ++ /* This is not what we want, "push" it back */ ++ (*eromptr)--; ++ return 0; ++ } ++ *addrl = asd & AD_ADDR_MASK; ++ if (asd & AD_AG32) ++ *addrh = get_erom_ent(sih, eromptr, 0, 0); ++ else ++ *addrh = 0; ++ *sizeh = 0; ++ sz = asd & AD_SZ_MASK; ++ if (sz == AD_SZ_SZD) { ++ szd = get_erom_ent(sih, eromptr, 0, 0); ++ *sizel = szd & SD_SZ_MASK; ++ if (szd & SD_SG32) ++ *sizeh = get_erom_ent(sih, eromptr, 0, 0); ++ } 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; ++} ++ ++ ++/* parse the enumeration rom to identify all cores */ ++void ++ai_scan(si_t *sih, void *regs, uint devid) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ chipcregs_t *cc = (chipcregs_t *)regs; ++ uint32 erombase, *eromptr, *eromlim; ++ axi_wrapper_t * axi_wrapper = sii->axi_wrapper; ++ ++ BCM_REFERENCE(devid); ++ ++ erombase = R_REG(sii->osh, &cc->eromptr); ++ ++ switch (BUSTYPE(sih->bustype)) { ++ case SI_BUS: ++ eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); ++ break; ++ ++ case PCI_BUS: ++ /* Set wrappers address */ ++ sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); ++ ++ /* Now point the window at the erom */ ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); ++ eromptr = regs; ++ break; ++ ++#ifdef BCMSDIO ++ case SPI_BUS: ++ case SDIO_BUS: ++ eromptr = (uint32 *)(uintptr)erombase; ++ break; ++#endif /* BCMSDIO */ ++ ++ case PCMCIA_BUS: ++ default: ++ SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype)); ++ ASSERT(0); ++ return; ++ } ++ eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); ++ sii->axi_num_wrappers = 0; ++ ++ SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", ++ OSL_OBFUSCATE_BUF(regs), erombase, ++ OSL_OBFUSCATE_BUF(eromptr), OSL_OBFUSATE_BUF(eromlim))); ++ while (eromptr < eromlim) { ++ uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; ++ uint32 mpd, asd, addrl, addrh, sizel, sizeh; ++ uint i, j, idx; ++ bool br; ++ ++ br = FALSE; ++ ++ /* 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)); ++ return; ++ } ++ ++ cib = get_erom_ent(sih, &eromptr, 0, 0); ++ ++ if ((cib & ER_TAG) != ER_CI) { ++ SI_ERROR(("CIA not followed by CIB\n")); ++ goto error; ++ } ++ ++ cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; ++ mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; ++ crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; ++ nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; ++ nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; ++ nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; ++ nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; ++ ++#ifdef BCMDBG_SI ++ 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, OSL_OBFUSCATE_BUF(eromptr - 1), nmw, nsw, nmp, nsp)); ++#else ++ BCM_REFERENCE(crev); ++#endif ++ ++ if (CHIPID(sih->chip) == BCM4347_CHIP_ID) { ++ /* 4347 has more entries for ARM core ++ * This should apply to all chips but crashes on router ++ * This is a temp fix to be further analyze ++ */ ++ if (nsp == 0) ++ continue; ++ } else { ++ /* Include Default slave wrapper for timeout monitoring */ ++ if ((nsp == 0) || ++#if !defined(AXI_TIMEOUTS) && !defined(BCM_BACKPLANE_TIMEOUT) ++ ((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || ++#endif /* !defined(AXI_TIMEOUTS) && !defined(BCM_BACKPLANE_TIMEOUT) */ ++ FALSE) { ++ continue; ++ } ++ } ++ ++ if ((nmw + nsw == 0)) { ++ /* A component which is not a core */ ++ if (cid == OOB_ROUTER_CORE_ID) { ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, ++ &addrl, &addrh, &sizel, &sizeh); ++ if (asd != 0) { ++ sii->oob_router = addrl; ++ } ++ } ++ if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID && ++ cid != PMU_CORE_ID && cid != GCI_CORE_ID) ++ continue; ++ } ++ ++ idx = sii->numcores; ++ ++ cores_info->cia[idx] = cia; ++ cores_info->cib[idx] = cib; ++ cores_info->coreid[idx] = remap_coreid(sih, cid); ++ ++ 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)); ++ 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: ++ * the main register space for the core ++ */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); ++ if (asd == 0) { ++ do { ++ /* Try again to see if it is a bridge */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd != 0) ++ br = TRUE; ++ else { ++ if (br == TRUE) { ++ break; ++ } ++ else if ((addrh != 0) || (sizeh != 0) || ++ (sizel != SI_CORE_SIZE)) { ++ SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 =" ++ "0x%x\n", addrh, sizeh, sizel)); ++ SI_ERROR(("First Slave ASD for" ++ "core 0x%04x malformed " ++ "(0x%08x)\n", cid, asd)); ++ goto error; ++ } ++ } ++ } while (1); ++ } ++ cores_info->coresba[idx] = addrl; ++ cores_info->coresba_size[idx] = sizel; ++ /* Get any more ASDs in port 0 */ ++ j = 1; ++ do { ++ asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { ++ cores_info->coresba2[idx] = addrl; ++ cores_info->coresba2_size[idx] = sizel; ++ } ++ j++; ++ } while (asd != 0); ++ ++ /* Go through the ASDs for other slave ports */ ++ for (i = 1; i < nsp; i++) { ++ j = 0; ++ do { ++ asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ ++ if (asd == 0) ++ break; ++ j++; ++ } while (1); ++ if (j == 0) { ++ SI_ERROR((" SP %d has no address descriptors\n", i)); ++ goto error; ++ } ++ } ++ ++ /* Now get master wrappers */ ++ for (i = 0; i < nmw; i++) { ++ asd = 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)); ++ goto error; ++ } ++ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { ++ SI_ERROR(("Master wrapper %d is not 4KB\n", i)); ++ goto error; ++ } ++ if (i == 0) ++ cores_info->wrapba[idx] = addrl; ++ else if (i == 1) ++ cores_info->wrapba2[idx] = addrl; ++ ++ ++ ASSERT(sii->axi_num_wrappers < SI_MAX_AXI_WRAPPERS); ++ axi_wrapper[sii->axi_num_wrappers].mfg = mfg; ++ axi_wrapper[sii->axi_num_wrappers].cid = cid; ++ axi_wrapper[sii->axi_num_wrappers].rev = crev; ++ axi_wrapper[sii->axi_num_wrappers].wrapper_type = AI_MASTER_WRAPPER; ++ axi_wrapper[sii->axi_num_wrappers].wrapper_addr = addrl; ++ sii->axi_num_wrappers++; ++ SI_VMSG(("MASTER WRAPPER: %d, mfg:%x, cid:%x, rev:%x, addr:%x, size:%x\n", ++ sii->axi_num_wrappers, mfg, cid, crev, addrl, sizel)); ++ } ++ ++ /* And finally slave wrappers */ ++ for (i = 0; i < nsw; i++) { ++ uint fwp = (nsp == 1) ? 0 : 1; ++ asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh, ++ &sizel, &sizeh); ++ ++ /* cache APB bridge wrapper address for set/clear timeout */ ++ if ((mfg == MFGID_ARM) && (cid == APB_BRIDGE_ID)) { ++ ASSERT(sii->num_br < SI_MAXBR); ++ sii->br_wrapba[sii->num_br++] = addrl; ++ } ++ ++ if (asd == 0) { ++ SI_ERROR(("Missing descriptor for SW %d\n", i)); ++ goto error; ++ } ++ if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { ++ SI_ERROR(("Slave wrapper %d is not 4KB\n", i)); ++ goto error; ++ } ++ if ((nmw == 0) && (i == 0)) ++ cores_info->wrapba[idx] = addrl; ++ else if ((nmw == 0) && (i == 1)) ++ cores_info->wrapba2[idx] = addrl; ++ ++ /* Include all slave wrappers to the list to ++ * enable and monitor watchdog timeouts ++ */ ++ ++ ASSERT(sii->axi_num_wrappers < SI_MAX_AXI_WRAPPERS); ++ axi_wrapper[sii->axi_num_wrappers].mfg = mfg; ++ axi_wrapper[sii->axi_num_wrappers].cid = cid; ++ axi_wrapper[sii->axi_num_wrappers].rev = crev; ++ axi_wrapper[sii->axi_num_wrappers].wrapper_type = AI_SLAVE_WRAPPER; ++ axi_wrapper[sii->axi_num_wrappers].wrapper_addr = addrl; ++ sii->axi_num_wrappers++; ++ ++ SI_VMSG(("SLAVE WRAPPER: %d, mfg:%x, cid:%x, rev:%x, addr:%x, size:%x\n", ++ sii->axi_num_wrappers, mfg, cid, crev, addrl, sizel)); ++ } ++ ++ ++#ifndef BCM_BACKPLANE_TIMEOUT ++ /* Don't record bridges */ ++ if (br) ++ continue; ++#endif ++ ++ /* Done with core */ ++ sii->numcores++; ++ } ++ ++ SI_ERROR(("Reached end of erom without finding END\n")); ++ ++error: ++ sii->numcores = 0; ++ return; ++} ++ ++#define AI_SETCOREIDX_MAPSIZE(coreid) \ ++ (((coreid) == NS_CCB_CORE_ID) ? 15 * SI_CORE_SIZE : SI_CORE_SIZE) ++ ++/* This function changes the logical "focus" to the indicated core. ++ * Return the current core's virtual address. ++ */ ++static volatile void * ++_ai_setcoreidx(si_t *sih, uint coreidx, uint use_wrap2) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint32 addr, wrap, wrap2; ++ volatile void *regs; ++ ++ if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) ++ return (NULL); ++ ++ addr = cores_info->coresba[coreidx]; ++ wrap = cores_info->wrapba[coreidx]; ++ wrap2 = cores_info->wrapba2[coreidx]; ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ /* No need to disable interrupts while entering/exiting APB bridge core */ ++ if ((cores_info->coreid[coreidx] != APB_BRIDGE_CORE_ID) && ++ (cores_info->coreid[sii->curidx] != APB_BRIDGE_CORE_ID)) ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ { ++ /* ++ * If the user has provided an interrupt mask enabled function, ++ * then assert interrupts are disabled before switching the core. ++ */ ++ ASSERT((sii->intrsenabled_fn == NULL) || ++ !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); ++ } ++ ++ switch (BUSTYPE(sih->bustype)) { ++ case SI_BUS: ++ /* map new one */ ++ if (!cores_info->regs[coreidx]) { ++ cores_info->regs[coreidx] = REG_MAP(addr, ++ AI_SETCOREIDX_MAPSIZE(cores_info->coreid[coreidx])); ++ ASSERT(GOODREGS(cores_info->regs[coreidx])); ++ } ++ sii->curmap = regs = cores_info->regs[coreidx]; ++ if (!cores_info->wrappers[coreidx] && (wrap != 0)) { ++ cores_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); ++ ASSERT(GOODREGS(cores_info->wrappers[coreidx])); ++ } ++ if (!cores_info->wrappers2[coreidx] && (wrap2 != 0)) { ++ cores_info->wrappers2[coreidx] = REG_MAP(wrap2, SI_CORE_SIZE); ++ ASSERT(GOODREGS(cores_info->wrappers2[coreidx])); ++ } ++ if (use_wrap2) ++ sii->curwrap = cores_info->wrappers2[coreidx]; ++ else ++ sii->curwrap = cores_info->wrappers[coreidx]; ++ break; ++ ++ case PCI_BUS: ++#ifdef BCM_BACKPLANE_TIMEOUT ++ /* No need to set the BAR0 if core is APB Bridge. ++ * This is to reduce 2 PCI writes while checkng for errlog ++ */ ++ if (cores_info->coreid[coreidx] != APB_BRIDGE_CORE_ID) ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ { ++ /* point bar0 window */ ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); ++ } ++ ++ regs = sii->curmap; ++ /* point bar0 2nd 4KB window to the primary wrapper */ ++ if (use_wrap2) ++ wrap = wrap2; ++ if (PCIE_GEN2(sii)) ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap); ++ else ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap); ++ break; ++ ++#ifdef BCMSDIO ++ case SPI_BUS: ++ case SDIO_BUS: ++ sii->curmap = regs = (void *)((uintptr)addr); ++ if (use_wrap2) ++ sii->curwrap = (void *)((uintptr)wrap2); ++ else ++ sii->curwrap = (void *)((uintptr)wrap); ++ break; ++#endif /* BCMSDIO */ ++ ++ case PCMCIA_BUS: ++ default: ++ ASSERT(0); ++ regs = NULL; ++ break; ++ } ++ ++ sii->curmap = regs; ++ sii->curidx = coreidx; ++ ++ return regs; ++} ++ ++volatile void * ++ai_setcoreidx(si_t *sih, uint coreidx) ++{ ++ return _ai_setcoreidx(sih, coreidx, 0); ++} ++ ++volatile void * ++ai_setcoreidx_2ndwrap(si_t *sih, uint coreidx) ++{ ++ return _ai_setcoreidx(sih, coreidx, 1); ++} ++ ++void ++ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ chipcregs_t *cc = NULL; ++ uint32 erombase, *eromptr, *eromlim; ++ uint i, j, cidx; ++ uint32 cia, cib, nmp, nsp; ++ uint32 asd, addrl, addrh, sizel, sizeh; ++ ++ for (i = 0; i < sii->numcores; i++) { ++ if (cores_info->coreid[i] == CC_CORE_ID) { ++ cc = (chipcregs_t *)cores_info->regs[i]; ++ break; ++ } ++ } ++ if (cc == NULL) ++ goto error; ++ ++ erombase = R_REG(sii->osh, &cc->eromptr); ++ eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); ++ eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); ++ ++ cidx = sii->curidx; ++ cia = cores_info->cia[cidx]; ++ cib = cores_info->cib[cidx]; ++ ++ nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; ++ nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; ++ ++ /* scan for cores */ ++ while (eromptr < eromlim) { ++ if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && ++ (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { ++ break; ++ } ++ } ++ ++ /* skip master ports */ ++ for (i = 0; i < nmp; i++) ++ get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); ++ ++ /* Skip ASDs in port 0 */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); ++ if (asd == 0) { ++ /* Try again to see if it is a bridge */ ++ asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, ++ &sizel, &sizeh); ++ } ++ ++ j = 1; ++ do { ++ asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ j++; ++ } while (asd != 0); ++ ++ /* Go through the ASDs for other slave ports */ ++ for (i = 1; i < nsp; i++) { ++ j = 0; ++ do { ++ asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, ++ &sizel, &sizeh); ++ if (asd == 0) ++ break; ++ ++ if (!asidx--) { ++ *addr = addrl; ++ *size = sizel; ++ return; ++ } ++ j++; ++ } while (1); ++ ++ if (j == 0) { ++ SI_ERROR((" SP %d has no address descriptors\n", i)); ++ break; ++ } ++ } ++ ++error: ++ *size = 0; ++ return; ++} ++ ++/* Return the number of address spaces in current core */ ++int ++ai_numaddrspaces(si_t *sih) ++{ ++ ++ BCM_REFERENCE(sih); ++ ++ return 2; ++} ++ ++/* Return the address of the nth address space in the current core */ ++uint32 ++ai_addrspace(si_t *sih, uint asidx) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint cidx; ++ ++ cidx = sii->curidx; ++ ++ if (asidx == 0) ++ return cores_info->coresba[cidx]; ++ else if (asidx == 1) ++ return cores_info->coresba2[cidx]; ++ else { ++ SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", ++ __FUNCTION__, asidx)); ++ return 0; ++ } ++} ++ ++/* Return the size of the nth address space in the current core */ ++uint32 ++ai_addrspacesize(si_t *sih, uint asidx) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint cidx; ++ ++ cidx = sii->curidx; ++ ++ if (asidx == 0) ++ return cores_info->coresba_size[cidx]; ++ else if (asidx == 1) ++ return cores_info->coresba2_size[cidx]; ++ else { ++ SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", ++ __FUNCTION__, asidx)); ++ return 0; ++ } ++} ++ ++uint ++ai_flag(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ aidmp_t *ai; ++ ++ if (BCM5357_DMP()) { ++ SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); ++ return sii->curidx; ++ } ++ if (BCM4707_DMP()) { ++ SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", ++ __FUNCTION__)); ++ return sii->curidx; ++ } ++ if (BCM53573_DMP()) { ++ SI_ERROR(("%s: Attempting to read DMP registers on 53573\n", __FUNCTION__)); ++ return sii->curidx; ++ } ++#ifdef REROUTE_OOBINT ++ if (PMU_DMP()) { ++ SI_ERROR(("%s: Attempting to read PMU DMP registers\n", ++ __FUNCTION__)); ++ return PMU_OOB_BIT; ++ } ++#else ++ if (PMU_DMP()) { ++ uint idx, flag; ++ idx = sii->curidx; ++ ai_setcoreidx(sih, SI_CC_IDX); ++ flag = ai_flag_alt(sih); ++ ai_setcoreidx(sih, idx); ++ return flag; ++ } ++#endif /* REROUTE_OOBINT */ ++ ++ ai = sii->curwrap; ++ ASSERT(ai != NULL); ++ ++ return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); ++} ++ ++uint ++ai_flag_alt(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ aidmp_t *ai; ++ ++ if (BCM5357_DMP()) { ++ SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); ++ return sii->curidx; ++ } ++ if (BCM4707_DMP()) { ++ SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", ++ __FUNCTION__)); ++ return sii->curidx; ++ } ++#ifdef REROUTE_OOBINT ++ if (PMU_DMP()) { ++ SI_ERROR(("%s: Attempting to read PMU DMP registers\n", ++ __FUNCTION__)); ++ return PMU_OOB_BIT; ++ } ++#endif /* REROUTE_OOBINT */ ++ ++ ai = sii->curwrap; ++ ++ return ((R_REG(sii->osh, &ai->oobselouta30) >> AI_OOBSEL_1_SHIFT) & AI_OOBSEL_MASK); ++} ++ ++void ++ai_setint(si_t *sih, int siflag) ++{ ++ BCM_REFERENCE(sih); ++ BCM_REFERENCE(siflag); ++ ++} ++ ++uint ++ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint32 *map = (uint32 *) sii->curwrap; ++ ++ if (mask || val) { ++ uint32 w = R_REG(sii->osh, map+(offset/4)); ++ w &= ~mask; ++ w |= val; ++ W_REG(sii->osh, map+(offset/4), w); ++ } ++ ++ return (R_REG(sii->osh, map+(offset/4))); ++} ++ ++uint ++ai_corevendor(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint32 cia; ++ ++ cia = cores_info->cia[sii->curidx]; ++ return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); ++} ++ ++uint ++ai_corerev(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint32 cib; ++ ++ ++ cib = cores_info->cib[sii->curidx]; ++ return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); ++} ++ ++bool ++ai_iscoreup(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ aidmp_t *ai; ++ ++ ai = sii->curwrap; ++ ++ return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && ++ ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); ++} ++ ++/* ++ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, ++ * switch back to the original core, and return the new value. ++ * ++ * When using the silicon backplane, no fiddling with interrupts or core switches is needed. ++ * ++ * Also, when using pci/pcie, we can optimize away the core switching for pci registers ++ * and (on newer pci cores) chipcommon registers. ++ */ ++uint ++ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ++{ ++ uint origidx = 0; ++ volatile uint32 *r = NULL; ++ uint w; ++ uint intr_val = 0; ++ bool fast = FALSE; ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ ++ ++ ASSERT(GOODIDX(coreidx)); ++ ASSERT(regoff < SI_CORE_SIZE); ++ ASSERT((val & ~mask) == 0); ++ ++ if (coreidx >= SI_MAXCORES) ++ return 0; ++ ++ if (BUSTYPE(sih->bustype) == SI_BUS) { ++ /* If internal bus, we can always get at everything */ ++ fast = TRUE; ++ /* map if does not exist */ ++ if (!cores_info->regs[coreidx]) { ++ cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], ++ SI_CORE_SIZE); ++ ASSERT(GOODREGS(cores_info->regs[coreidx])); ++ } ++ r = (volatile uint32 *)((volatile uchar *)cores_info->regs[coreidx] + regoff); ++ } else if (BUSTYPE(sih->bustype) == PCI_BUS) { ++ /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ ++ ++ if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { ++ /* Chipc registers are mapped at 12KB */ ++ ++ fast = TRUE; ++ r = (volatile uint32 *)((volatile 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 = (volatile uint32 *)((volatile char *)sii->curmap + ++ PCI_16KB0_PCIREGS_OFFSET + regoff); ++ else ++ r = (volatile uint32 *)((volatile char *)sii->curmap + ++ ((regoff >= SBCONFIGOFF) ? ++ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + ++ regoff); ++ } ++ } ++ ++ if (!fast) { ++ INTR_OFF(sii, intr_val); ++ ++ /* save current core index */ ++ origidx = si_coreidx(&sii->pub); ++ ++ /* switch core */ ++ r = (volatile uint32*) ((volatile uchar*) ai_setcoreidx(&sii->pub, coreidx) + ++ regoff); ++ } ++ ASSERT(r != NULL); ++ ++ /* mask and set */ ++ if (mask || val) { ++ w = (R_REG(sii->osh, r) & ~mask) | val; ++ W_REG(sii->osh, r, w); ++ } ++ ++ /* readback */ ++ w = R_REG(sii->osh, r); ++ ++ if (!fast) { ++ /* restore core index */ ++ if (origidx != coreidx) ++ ai_setcoreidx(&sii->pub, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++ } ++ ++ return (w); ++} ++ ++/* ++ * If there is no need for fiddling with interrupts or core switches (typically silicon ++ * back plane registers, pci registers and chipcommon registers), this function ++ * returns the register offset on this core to a mapped address. This address can ++ * be used for W_REG/R_REG directly. ++ * ++ * For accessing registers that would need a core switch, this function will return ++ * NULL. ++ */ ++volatile uint32 * ++ai_corereg_addr(si_t *sih, uint coreidx, uint regoff) ++{ ++ volatile uint32 *r = NULL; ++ bool fast = FALSE; ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ ++ ++ ASSERT(GOODIDX(coreidx)); ++ ASSERT(regoff < SI_CORE_SIZE); ++ ++ if (coreidx >= SI_MAXCORES) ++ return 0; ++ ++ if (BUSTYPE(sih->bustype) == SI_BUS) { ++ /* If internal bus, we can always get at everything */ ++ fast = TRUE; ++ /* map if does not exist */ ++ if (!cores_info->regs[coreidx]) { ++ cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], ++ SI_CORE_SIZE); ++ ASSERT(GOODREGS(cores_info->regs[coreidx])); ++ } ++ r = (volatile uint32 *)((volatile uchar *)cores_info->regs[coreidx] + regoff); ++ } else if (BUSTYPE(sih->bustype) == PCI_BUS) { ++ /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ ++ ++ if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { ++ /* Chipc registers are mapped at 12KB */ ++ ++ fast = TRUE; ++ r = (volatile uint32 *)((volatile 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 = (volatile uint32 *)((volatile char *)sii->curmap + ++ PCI_16KB0_PCIREGS_OFFSET + regoff); ++ else ++ r = (volatile uint32 *)((volatile char *)sii->curmap + ++ ((regoff >= SBCONFIGOFF) ? ++ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + ++ regoff); ++ } ++ } ++ ++ if (!fast) { ++ ASSERT(sii->curidx == coreidx); ++ r = (volatile uint32*) ((volatile uchar*)sii->curmap + regoff); ++ } ++ ++ return (r); ++} ++ ++void ++ai_core_disable(si_t *sih, uint32 bits) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ volatile uint32 dummy; ++ uint32 status; ++ aidmp_t *ai; ++ ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ /* if core is already in reset, just return */ ++ if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) { ++ return; ++ } ++ ++ /* ensure there are no pending backplane operations */ ++ SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); ++ ++ /* if pending backplane ops still, try waiting longer */ ++ if (status != 0) { ++ /* 300usecs was sufficient to allow backplane ops to clear for big hammer */ ++ /* during driver load we may need more time */ ++ SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); ++ /* if still pending ops, continue on and try disable anyway */ ++ /* this is in big hammer path, so don't call wl_reinit in this case... */ ++ } ++ ++ W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); ++ dummy = R_REG(sii->osh, &ai->resetctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ ++ W_REG(sii->osh, &ai->ioctrl, bits); ++ dummy = R_REG(sii->osh, &ai->ioctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(10); ++} ++ ++/* reset and re-enable a core ++ * inputs: ++ * bits - core specific bits that are set during and after reset sequence ++ * resetbits - core specific bits that are set only during reset sequence ++ */ ++static void ++_ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ aidmp_t *ai; ++ volatile uint32 dummy; ++ uint loop_counter = 10; ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ /* if core is already out of reset, just return */ ++ ++ /* ensure there are no pending backplane operations */ ++ SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); ++ ++ ++ /* put core into reset state */ ++ W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); ++ OSL_DELAY(10); ++ ++ /* ensure there are no pending backplane operations */ ++ SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); ++ ++ W_REG(sii->osh, &ai->ioctrl, (bits | resetbits | SICF_FGC | SICF_CLOCK_EN)); ++ dummy = R_REG(sii->osh, &ai->ioctrl); ++ BCM_REFERENCE(dummy); ++ ++ /* ensure there are no pending backplane operations */ ++ SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); ++ ++ ++ while (R_REG(sii->osh, &ai->resetctrl) != 0 && --loop_counter != 0) { ++ /* ensure there are no pending backplane operations */ ++ SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); ++ ++ ++ /* take core out of reset */ ++ W_REG(sii->osh, &ai->resetctrl, 0); ++ ++ /* ensure there are no pending backplane operations */ ++ SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); ++ } ++ ++ ++ W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); ++ dummy = R_REG(sii->osh, &ai->ioctrl); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++} ++ ++void ++ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint idx = sii->curidx; ++ ++ if (cores_info->wrapba2[idx] != 0) { ++ ai_setcoreidx_2ndwrap(sih, idx); ++ _ai_core_reset(sih, bits, resetbits); ++ ai_setcoreidx(sih, idx); ++ } ++ ++ _ai_core_reset(sih, bits, resetbits); ++} ++ ++void ++ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ aidmp_t *ai; ++ uint32 w; ++ ++ if (BCM5357_DMP()) { ++ SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", ++ __FUNCTION__)); ++ return; ++ } ++ if (BCM4707_DMP()) { ++ SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", ++ __FUNCTION__)); ++ return; ++ } ++ if (PMU_DMP()) { ++ SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", ++ __FUNCTION__)); ++ return; ++ } ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ ASSERT((val & ~mask) == 0); ++ ++ if (mask || val) { ++ w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); ++ W_REG(sii->osh, &ai->ioctrl, w); ++ } ++} ++ ++uint32 ++ai_core_cflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ aidmp_t *ai; ++ uint32 w; ++ ++ if (BCM5357_DMP()) { ++ SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", ++ __FUNCTION__)); ++ return 0; ++ } ++ if (BCM4707_DMP()) { ++ SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", ++ __FUNCTION__)); ++ return 0; ++ } ++ ++ if (PMU_DMP()) { ++ SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", ++ __FUNCTION__)); ++ return 0; ++ } ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ ASSERT((val & ~mask) == 0); ++ ++ if (mask || val) { ++ w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); ++ W_REG(sii->osh, &ai->ioctrl, w); ++ } ++ ++ return R_REG(sii->osh, &ai->ioctrl); ++} ++ ++uint32 ++ai_core_sflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ aidmp_t *ai; ++ uint32 w; ++ ++ if (BCM5357_DMP()) { ++ SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n", ++ __FUNCTION__)); ++ return 0; ++ } ++ if (BCM4707_DMP()) { ++ SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", ++ __FUNCTION__)); ++ return 0; ++ } ++ if (PMU_DMP()) { ++ SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", ++ __FUNCTION__)); ++ return 0; ++ } ++ ++ ASSERT(GOODREGS(sii->curwrap)); ++ ai = sii->curwrap; ++ ++ ASSERT((val & ~mask) == 0); ++ ASSERT((mask & ~SISF_CORE_BITS) == 0); ++ ++ if (mask || val) { ++ w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); ++ W_REG(sii->osh, &ai->iostatus, w); ++ } ++ ++ return R_REG(sii->osh, &ai->iostatus); ++} ++ ++#if defined(BCMDBG_PHYDUMP) ++/* print interesting aidmp registers */ ++void ++ai_dumpregs(si_t *sih, struct bcmstrbuf *b) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ osl_t *osh; ++ aidmp_t *ai; ++ uint i; ++ uint32 prev_value = 0; ++ axi_wrapper_t * axi_wrapper = sii->axi_wrapper; ++ uint32 cfg_reg = 0; ++ uint bar0_win_offset = 0; ++ ++ osh = sii->osh; ++ ++ ++ /* Save and restore wrapper access window */ ++ if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { ++ if (PCIE_GEN2(sii)) { ++ cfg_reg = PCIE2_BAR0_CORE2_WIN2; ++ bar0_win_offset = PCIE2_BAR0_CORE2_WIN2_OFFSET; ++ } else { ++ cfg_reg = PCI_BAR0_WIN2; ++ bar0_win_offset = PCI_BAR0_WIN2_OFFSET; ++ } ++ ++ prev_value = OSL_PCI_READ_CONFIG(osh, cfg_reg, 4); ++ ++ if (prev_value == ID32_INVALID) { ++ SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__, prev_value)); ++ return; ++ } ++ } ++ ++ bcm_bprintf(b, "ChipNum:%x, ChipRev;%x, BusType:%x, BoardType:%x, BoardVendor:%x\n\n", ++ sih->chip, sih->chiprev, sih->bustype, sih->boardtype, sih->boardvendor); ++ ++ for (i = 0; i < sii->axi_num_wrappers; i++) { ++ ++ if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { ++ /* Set BAR0 window to bridge wapper base address */ ++ OSL_PCI_WRITE_CONFIG(osh, ++ cfg_reg, 4, axi_wrapper[i].wrapper_addr); ++ ++ ai = (aidmp_t *) ((volatile uint8*)sii->curmap + bar0_win_offset); ++ } else { ++ ai = (aidmp_t *)(uintptr) axi_wrapper[i].wrapper_addr; ++ } ++ ++ bcm_bprintf(b, "core 0x%x: core_rev:%d, %s_WR ADDR:%x \n", axi_wrapper[i].cid, ++ axi_wrapper[i].rev, ++ axi_wrapper[i].wrapper_type == AI_SLAVE_WRAPPER ? "SLAVE" : "MASTER", ++ axi_wrapper[i].wrapper_addr); ++ ++ /* BCM5357_DMP() */ ++ if (((CHIPID(sih->chip) == BCM5357_CHIP_ID) || ++ (CHIPID(sih->chip) == BCM4749_CHIP_ID)) && ++ (sih->chippkg == BCM5357_PKG_ID) && ++ (axi_wrapper[i].cid == USB20H_CORE_ID)) { ++ bcm_bprintf(b, "Skipping usb20h in 5357\n"); ++ continue; ++ } ++ ++ /* BCM4707_DMP() */ ++ if (BCM4707_CHIP(CHIPID(sih->chip)) && ++ (axi_wrapper[i].cid == NS_CCB_CORE_ID)) { ++ bcm_bprintf(b, "Skipping chipcommonb in 4707\n"); ++ continue; ++ } ++ ++ bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x " ++ "ioctrlwidth 0x%x iostatuswidth 0x%x\n" ++ "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n" ++ "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x " ++ "errlogaddrlo 0x%x errlogaddrhi 0x%x\n" ++ "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n" ++ "intstatus 0x%x config 0x%x itcr 0x%x\n\n", ++ R_REG(osh, &ai->ioctrlset), ++ R_REG(osh, &ai->ioctrlclear), ++ R_REG(osh, &ai->ioctrl), ++ R_REG(osh, &ai->iostatus), ++ R_REG(osh, &ai->ioctrlwidth), ++ R_REG(osh, &ai->iostatuswidth), ++ R_REG(osh, &ai->resetctrl), ++ R_REG(osh, &ai->resetstatus), ++ R_REG(osh, &ai->resetreadid), ++ R_REG(osh, &ai->resetwriteid), ++ R_REG(osh, &ai->errlogctrl), ++ R_REG(osh, &ai->errlogdone), ++ R_REG(osh, &ai->errlogstatus), ++ R_REG(osh, &ai->errlogaddrlo), ++ R_REG(osh, &ai->errlogaddrhi), ++ R_REG(osh, &ai->errlogid), ++ R_REG(osh, &ai->errloguser), ++ R_REG(osh, &ai->errlogflags), ++ R_REG(osh, &ai->intstatus), ++ R_REG(osh, &ai->config), ++ R_REG(osh, &ai->itcr)); ++ } ++ ++ /* Restore the initial wrapper space */ ++ if (prev_value && cfg_reg) { ++ OSL_PCI_WRITE_CONFIG(osh, cfg_reg, 4, prev_value); ++ } ++ ++} ++#endif ++ ++ ++void ++ai_enable_backplane_timeouts(si_t *sih) ++{ ++#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) ++ si_info_t *sii = SI_INFO(sih); ++ aidmp_t *ai; ++ uint32 i; ++ axi_wrapper_t * axi_wrapper = sii->axi_wrapper; ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ uint32 prev_value = 0; ++ osl_t *osh = sii->osh; ++ uint32 cfg_reg = 0; ++ uint32 offset = 0; ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++ if ((sii->axi_num_wrappers == 0) || ++#ifdef BCM_BACKPLANE_TIMEOUT ++ (!PCIE(sii)) || ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ FALSE) { ++ SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n", ++ __FUNCTION__, sii->axi_num_wrappers, PCIE(sii), ++ BUSTYPE(sii->pub.bustype), sii->pub.buscoretype)); ++ return; ++ } ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ /* Save and restore the wrapper access window */ ++ if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { ++ if (PCIE_GEN1(sii)) { ++ cfg_reg = PCI_BAR0_WIN2; ++ offset = PCI_BAR0_WIN2_OFFSET; ++ } else if (PCIE_GEN2(sii)) { ++ cfg_reg = PCIE2_BAR0_CORE2_WIN2; ++ offset = PCIE2_BAR0_CORE2_WIN2_OFFSET; ++ } ++ else { ++ osl_panic("!PCIE_GEN1 && !PCIE_GEN2\n"); ++ } ++ ++ prev_value = OSL_PCI_READ_CONFIG(osh, cfg_reg, 4); ++ if (prev_value == ID32_INVALID) { ++ SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__, prev_value)); ++ return; ++ } ++ } ++ ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++ for (i = 0; i < sii->axi_num_wrappers; ++i) { ++ ++ if (axi_wrapper[i].wrapper_type != AI_SLAVE_WRAPPER) { ++ SI_VMSG(("SKIP ENABLE BPT: MFG:%x, CID:%x, ADDR:%x\n", ++ axi_wrapper[i].mfg, ++ axi_wrapper[i].cid, ++ axi_wrapper[i].wrapper_addr)); ++ continue; ++ } ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { ++ /* Set BAR0_CORE2_WIN2 to wapper base address */ ++ OSL_PCI_WRITE_CONFIG(osh, ++ cfg_reg, 4, axi_wrapper[i].wrapper_addr); ++ ++ /* set AI to BAR0 + Offset corresponding to Gen1 or gen2 */ ++ ai = (aidmp_t *) ((uint8*)sii->curmap + offset); ++ } ++ else ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ { ++ ai = (aidmp_t *)(uintptr) axi_wrapper[i].wrapper_addr; ++ } ++ ++ W_REG(sii->osh, &ai->errlogctrl, (1 << AIELC_TO_ENAB_SHIFT) | ++ ((AXI_TO_VAL << AIELC_TO_EXP_SHIFT) & AIELC_TO_EXP_MASK)); ++ ++ SI_VMSG(("ENABLED BPT: MFG:%x, CID:%x, ADDR:%x, ERR_CTRL:%x\n", ++ axi_wrapper[i].mfg, ++ axi_wrapper[i].cid, ++ axi_wrapper[i].wrapper_addr, ++ R_REG(sii->osh, &ai->errlogctrl))); ++ } ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ /* Restore the initial wrapper space */ ++ if (prev_value) { ++ OSL_PCI_WRITE_CONFIG(osh, cfg_reg, 4, prev_value); ++ } ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ ++} ++ ++#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) ++ ++/* slave error is ignored, so account for those cases */ ++static uint32 si_ignore_errlog_cnt = 0; ++ ++static bool ++ai_ignore_errlog(si_info_t *sii, uint32 lo_addr, uint32 hi_addr, uint32 err_axi_id, uint32 errsts) ++{ ++ uint32 axi_id; ++ ++ /* ignore the BT slave errors if the errlog is to chipcommon addr 0x190 */ ++ switch (CHIPID(sii->pub.chip)) { ++ case BCM4350_CHIP_ID: ++ axi_id = BCM4350_BT_AXI_ID; ++ break; ++ case BCM4345_CHIP_ID: ++ axi_id = BCM4345_BT_AXI_ID; ++ break; ++ default: ++ return FALSE; ++ } ++ ++ /* AXI ID check */ ++ if ((err_axi_id & AI_ERRLOGID_AXI_ID_MASK) != axi_id) ++ return FALSE; ++ ++ /* slave errors */ ++ if ((errsts & AIELS_TIMEOUT_MASK) != AIELS_SLAVE_ERR) ++ return FALSE; ++ ++ /* chipc reg 0x190 */ ++ if ((hi_addr != BT_CC_SPROM_BADREG_HI) || (lo_addr != BT_CC_SPROM_BADREG_LO)) ++ return FALSE; ++ ++ return TRUE; ++} ++#endif /* defined (AXI_TIMEOUTS) || defined (BCM_BACKPLANE_TIMEOUT) */ ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ ++/* Function to return the APB bridge details corresponding to the core */ ++bool ++ai_get_apb_bridge(si_t * sih, uint32 coreidx, uint32 *apb_id, uint32 * apb_coreuinit) ++{ ++ uint i; ++ uint32 core_base, core_end; ++ si_info_t *sii = SI_INFO(sih); ++ static uint32 coreidx_cached = 0, apb_id_cached = 0, apb_coreunit_cached = 0; ++ uint32 tmp_coreunit = 0; ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ ++ if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) ++ return FALSE; ++ ++ /* Most of the time apb bridge query will be for d11 core. ++ * Maintain the last cache and return if found rather than iterating the table ++ */ ++ if (coreidx_cached == coreidx) { ++ *apb_id = apb_id_cached; ++ *apb_coreuinit = apb_coreunit_cached; ++ return TRUE; ++ } ++ ++ core_base = cores_info->coresba[coreidx]; ++ core_end = core_base + cores_info->coresba_size[coreidx]; ++ ++ for (i = 0; i < sii->numcores; i++) { ++ if (cores_info->coreid[i] == APB_BRIDGE_ID) { ++ uint32 apb_base; ++ uint32 apb_end; ++ ++ apb_base = cores_info->coresba[i]; ++ apb_end = apb_base + cores_info->coresba_size[i]; ++ ++ if ((core_base >= apb_base) && ++ (core_end <= apb_end)) { ++ /* Current core is attached to this APB bridge */ ++ *apb_id = apb_id_cached = APB_BRIDGE_ID; ++ *apb_coreuinit = apb_coreunit_cached = tmp_coreunit; ++ coreidx_cached = coreidx; ++ return TRUE; ++ } ++ /* Increment the coreunit */ ++ tmp_coreunit++; ++ } ++ } ++ ++ return FALSE; ++} ++ ++uint32 ++ai_clear_backplane_to_fast(si_t *sih, void * addr) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ void * curmap = sii->curmap; ++ bool core_reg = FALSE; ++ ++ /* Use fast path only for core register access */ ++ if ((addr >= curmap) && (addr < (curmap + SI_CORE_SIZE))) { ++ /* address being accessed is within current core reg map */ ++ core_reg = TRUE; ++ } ++ ++ if (core_reg) { ++ uint32 apb_id, apb_coreuinit; ++ ++ if (ai_get_apb_bridge(sih, si_coreidx(&sii->pub), ++ &apb_id, &apb_coreuinit) == TRUE) { ++ /* Found the APB bridge corresponding to current core, ++ * Check for bus errors in APB wrapper ++ */ ++ return ai_clear_backplane_to_per_core(sih, ++ apb_id, apb_coreuinit, NULL); ++ } ++ } ++ ++ /* Default is to poll for errors on all slave wrappers */ ++ return si_clear_backplane_to(sih); ++} ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) ++/* ++ * API to clear the back plane timeout per core. ++ * Caller may passs optional wrapper address. If present this will be used as ++ * the wrapper base address. If wrapper base address is provided then caller ++ * must provide the coreid also. ++ * If both coreid and wrapper is zero, then err status of current bridge ++ * will be verified. ++ */ ++uint32 ++ai_clear_backplane_to_per_core(si_t *sih, uint coreid, uint coreunit, void * wrap) ++{ ++ int ret = AXI_WRAP_STS_NONE; ++ aidmp_t *ai = NULL; ++ uint32 errlog_status = 0; ++ si_info_t *sii = SI_INFO(sih); ++ uint32 errlog_lo = 0, errlog_hi = 0, errlog_id = 0, errlog_flags = 0; ++ uint32 current_coreidx = si_coreidx(sih); ++ uint32 target_coreidx = si_findcoreidx(sih, coreid, coreunit); ++ ++#if defined(BCM_BACKPLANE_TIMEOUT) ++ si_axi_error_t * axi_error = &sih->err_info->axi_error[sih->err_info->count]; ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ bool restore_core = FALSE; ++ ++ if ((sii->axi_num_wrappers == 0) || ++#ifdef BCM_BACKPLANE_TIMEOUT ++ (!PCIE(sii)) || ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ FALSE) { ++ SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n", ++ __FUNCTION__, sii->axi_num_wrappers, PCIE(sii), ++ BUSTYPE(sii->pub.bustype), sii->pub.buscoretype)); ++ return AXI_WRAP_STS_NONE; ++ } ++ ++ if (wrap != NULL) { ++ ai = (aidmp_t *)wrap; ++ } else if (coreid && (target_coreidx != current_coreidx)) { ++ ++ if (ai_setcoreidx(sih, target_coreidx) == NULL) { ++ /* Unable to set the core */ ++ SI_PRINT(("Set Code Failed: coreid:%x, unit:%d, target_coreidx:%d\n", ++ coreid, coreunit, target_coreidx)); ++ errlog_lo = target_coreidx; ++ ret = AXI_WRAP_STS_SET_CORE_FAIL; ++ goto end; ++ } ++ ++ restore_core = TRUE; ++ ai = (aidmp_t *)si_wrapperregs(sih); ++ } else { ++ /* Read error status of current wrapper */ ++ ai = (aidmp_t *)si_wrapperregs(sih); ++ ++ /* Update CoreID to current Code ID */ ++ coreid = si_coreid(sih); ++ } ++ ++ /* read error log status */ ++ errlog_status = R_REG(sii->osh, &ai->errlogstatus); ++ ++ if (errlog_status == ID32_INVALID) { ++ /* Do not try to peek further */ ++ SI_PRINT(("%s, errlogstatus:%x - Slave Wrapper:%x\n", ++ __FUNCTION__, errlog_status, coreid)); ++ ret = AXI_WRAP_STS_WRAP_RD_ERR; ++ errlog_lo = (uint32)&ai->errlogstatus; ++ goto end; ++ } ++ ++ if ((errlog_status & AIELS_TIMEOUT_MASK) != 0) { ++ uint32 tmp; ++ uint32 count = 0; ++ /* set ErrDone to clear the condition */ ++ W_REG(sii->osh, &ai->errlogdone, AIELD_ERRDONE_MASK); ++ ++ /* SPINWAIT on errlogstatus timeout status bits */ ++ while ((tmp = R_REG(sii->osh, &ai->errlogstatus)) & AIELS_TIMEOUT_MASK) { ++ ++ if (tmp == ID32_INVALID) { ++ SI_PRINT(("%s: prev errlogstatus:%x, errlogstatus:%x\n", ++ __FUNCTION__, errlog_status, tmp)); ++ ret = AXI_WRAP_STS_WRAP_RD_ERR; ++ errlog_lo = (uint32)&ai->errlogstatus; ++ goto end; ++ } ++ /* ++ * Clear again, to avoid getting stuck in the loop, if a new error ++ * is logged after we cleared the first timeout ++ */ ++ W_REG(sii->osh, &ai->errlogdone, AIELD_ERRDONE_MASK); ++ ++ count++; ++ OSL_DELAY(10); ++ if ((10 * count) > AI_REG_READ_TIMEOUT) { ++ errlog_status = tmp; ++ break; ++ } ++ } ++ ++ errlog_lo = R_REG(sii->osh, &ai->errlogaddrlo); ++ errlog_hi = R_REG(sii->osh, &ai->errlogaddrhi); ++ errlog_id = R_REG(sii->osh, &ai->errlogid); ++ errlog_flags = R_REG(sii->osh, &ai->errlogflags); ++ ++ /* we are already in the error path, so OK to check for the slave error */ ++ if (ai_ignore_errlog(sii, errlog_lo, errlog_hi, errlog_id, ++ errlog_status)) { ++ si_ignore_errlog_cnt++; ++ goto end; ++ } ++ ++ /* only reset APB Bridge on timeout (not slave error, or dec error) */ ++ switch (errlog_status & AIELS_TIMEOUT_MASK) { ++ case AIELS_SLAVE_ERR: ++ SI_PRINT(("AXI slave error")); ++ ret = AXI_WRAP_STS_SLAVE_ERR; ++ break; ++ ++ case AIELS_TIMEOUT: ++ /* reset APB Bridge */ ++ OR_REG(sii->osh, &ai->resetctrl, AIRC_RESET); ++ /* sync write */ ++ (void)R_REG(sii->osh, &ai->resetctrl); ++ /* clear Reset bit */ ++ AND_REG(sii->osh, &ai->resetctrl, ~(AIRC_RESET)); ++ /* sync write */ ++ (void)R_REG(sii->osh, &ai->resetctrl); ++ SI_PRINT(("AXI timeout")); ++ ret = AXI_WRAP_STS_TIMEOUT; ++ break; ++ ++ case AIELS_DECODE: ++ SI_PRINT(("AXI decode error")); ++ ret = AXI_WRAP_STS_DECODE_ERR; ++ break; ++ default: ++ ASSERT(0); /* should be impossible */ ++ } ++ ++ SI_PRINT(("\tCoreID: %x\n", coreid)); ++ SI_PRINT(("\t errlog: lo 0x%08x, hi 0x%08x, id 0x%08x, flags 0x%08x" ++ ", status 0x%08x\n", ++ errlog_lo, errlog_hi, errlog_id, errlog_flags, ++ errlog_status)); ++ } ++ ++end: ++ ++#if defined(BCM_BACKPLANE_TIMEOUT) ++ if (axi_error && (ret != AXI_WRAP_STS_NONE)) { ++ axi_error->error = ret; ++ axi_error->coreid = coreid; ++ axi_error->errlog_lo = errlog_lo; ++ axi_error->errlog_hi = errlog_hi; ++ axi_error->errlog_id = errlog_id; ++ axi_error->errlog_flags = errlog_flags; ++ axi_error->errlog_status = errlog_status; ++ sih->err_info->count++; ++ ++ if (sih->err_info->count == SI_MAX_ERRLOG_SIZE) { ++ sih->err_info->count = SI_MAX_ERRLOG_SIZE - 1; ++ SI_PRINT(("AXI Error log overflow\n")); ++ } ++ } ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++ if (restore_core) { ++ if (ai_setcoreidx(sih, current_coreidx) == NULL) { ++ /* Unable to set the core */ ++ return ID32_INVALID; ++ } ++ } ++ ++ return ret; ++} ++#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ ++ ++/* ++ * This API polls all slave wrappers for errors and returns bit map of ++ * all reported errors. ++ * return - bit map of ++ * AXI_WRAP_STS_NONE ++ * AXI_WRAP_STS_TIMEOUT ++ * AXI_WRAP_STS_SLAVE_ERR ++ * AXI_WRAP_STS_DECODE_ERR ++ * AXI_WRAP_STS_PCI_RD_ERR ++ * AXI_WRAP_STS_WRAP_RD_ERR ++ * AXI_WRAP_STS_SET_CORE_FAIL ++ * On timeout detection, correspondign bridge will be reset to ++ * unblock the bus. ++ * Error reported in each wrapper can be retrieved using the API ++ * si_get_axi_errlog_info() ++ */ ++uint32 ++ai_clear_backplane_to(si_t *sih) ++{ ++ uint32 ret = 0; ++#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) ++ ++ si_info_t *sii = SI_INFO(sih); ++ aidmp_t *ai; ++ uint32 i; ++ axi_wrapper_t * axi_wrapper = sii->axi_wrapper; ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ uint32 prev_value = 0; ++ osl_t *osh = sii->osh; ++ uint32 cfg_reg = 0; ++ uint32 offset = 0; ++ ++ if ((sii->axi_num_wrappers == 0) || (!PCIE(sii))) ++#else ++ if (sii->axi_num_wrappers == 0) ++#endif ++ { ++ SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n", ++ __FUNCTION__, sii->axi_num_wrappers, PCIE(sii), ++ BUSTYPE(sii->pub.bustype), sii->pub.buscoretype)); ++ return AXI_WRAP_STS_NONE; ++ } ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ /* Save and restore wrapper access window */ ++ if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { ++ if (PCIE_GEN1(sii)) { ++ cfg_reg = PCI_BAR0_WIN2; ++ offset = PCI_BAR0_WIN2_OFFSET; ++ } else if (PCIE_GEN2(sii)) { ++ cfg_reg = PCIE2_BAR0_CORE2_WIN2; ++ offset = PCIE2_BAR0_CORE2_WIN2_OFFSET; ++ } ++ else { ++ osl_panic("!PCIE_GEN1 && !PCIE_GEN2\n"); ++ } ++ ++ prev_value = OSL_PCI_READ_CONFIG(osh, cfg_reg, 4); ++ ++ if (prev_value == ID32_INVALID) { ++ si_axi_error_t * axi_error = ++ &sih->err_info->axi_error[sih->err_info->count]; ++ SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__, prev_value)); ++ ++ axi_error->error = ret = AXI_WRAP_STS_PCI_RD_ERR; ++ axi_error->errlog_lo = cfg_reg; ++ sih->err_info->count++; ++ ++ if (sih->err_info->count == SI_MAX_ERRLOG_SIZE) { ++ sih->err_info->count = SI_MAX_ERRLOG_SIZE - 1; ++ SI_PRINT(("AXI Error log overflow\n")); ++ } ++ ++ return ret; ++ } ++ } ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++ for (i = 0; i < sii->axi_num_wrappers; ++i) { ++ uint32 tmp; ++ ++ if (axi_wrapper[i].wrapper_type != AI_SLAVE_WRAPPER) { ++ continue; ++ } ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ ++ if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { ++ /* Set BAR0_CORE2_WIN2 to bridge wapper base address */ ++ OSL_PCI_WRITE_CONFIG(osh, ++ cfg_reg, 4, axi_wrapper[i].wrapper_addr); ++ ++ /* set AI to BAR0 + Offset corresponding to Gen1 or gen2 */ ++ ai = (aidmp_t *) ((uint8*)sii->curmap + offset); ++ } ++ else ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ { ++ ai = (aidmp_t *)(uintptr) axi_wrapper[i].wrapper_addr; ++ } ++ ++ tmp = ai_clear_backplane_to_per_core(sih, axi_wrapper[i].cid, 0, (void*)ai); ++ ++ ret |= tmp; ++ } ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ /* Restore the initial wrapper space */ ++ if (prev_value) { ++ OSL_PCI_WRITE_CONFIG(osh, cfg_reg, 4, prev_value); ++ } ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ ++ ++ return ret; ++} ++ ++uint ++ai_num_slaveports(si_t *sih, uint coreidx) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint32 cib; ++ ++ cib = cores_info->cib[coreidx]; ++ return ((cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT); ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcm_app_utils.c b/module_drivers/drivers/net/wireless/bcmdhd/bcm_app_utils.c +new file mode 100644 +index 000000000..a5a7a5b23 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcm_app_utils.c +@@ -0,0 +1,1015 @@ ++/* ++ * Misc utility routines used by kernel or app-level. ++ * Contents are wifi-specific, used by any kernel or app-level ++ * software that might want wifi things as it grows. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcm_app_utils.c 623866 2016-03-09 11:58:34Z $ ++ */ ++ ++#include ++ ++#ifdef BCMDRIVER ++#include ++#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) ++#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) ++#else /* BCMDRIVER */ ++#include ++#include ++#include ++#include ++#ifndef ASSERT ++#define ASSERT(exp) ++#endif ++#endif /* BCMDRIVER */ ++#include ++ ++#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) ++#include /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ ++#endif ++ ++#include ++#include ++#include ++ ++#ifndef BCMDRIVER ++/* Take an array of measurments representing a single channel over time and return ++ a summary. Currently implemented as a simple average but could easily evolve ++ into more cpomplex alogrithms. ++*/ ++cca_congest_channel_req_t * ++cca_per_chan_summary(cca_congest_channel_req_t *input, cca_congest_channel_req_t *avg, bool percent) ++{ ++ int sec; ++ cca_congest_t totals; ++ ++ totals.duration = 0; ++ totals.congest_ibss = 0; ++ totals.congest_obss = 0; ++ totals.interference = 0; ++ avg->num_secs = 0; ++ ++ for (sec = 0; sec < input->num_secs; sec++) { ++ if (input->secs[sec].duration) { ++ totals.duration += input->secs[sec].duration; ++ totals.congest_ibss += input->secs[sec].congest_ibss; ++ totals.congest_obss += input->secs[sec].congest_obss; ++ totals.interference += input->secs[sec].interference; ++ avg->num_secs++; ++ } ++ } ++ avg->chanspec = input->chanspec; ++ ++ if (!avg->num_secs || !totals.duration) ++ return (avg); ++ ++ if (percent) { ++ avg->secs[0].duration = totals.duration / avg->num_secs; ++ avg->secs[0].congest_ibss = totals.congest_ibss * 100/totals.duration; ++ avg->secs[0].congest_obss = totals.congest_obss * 100/totals.duration; ++ avg->secs[0].interference = totals.interference * 100/totals.duration; ++ } else { ++ avg->secs[0].duration = totals.duration / avg->num_secs; ++ avg->secs[0].congest_ibss = totals.congest_ibss / avg->num_secs; ++ avg->secs[0].congest_obss = totals.congest_obss / avg->num_secs; ++ avg->secs[0].interference = totals.interference / avg->num_secs; ++ } ++ ++ return (avg); ++} ++ ++static void ++cca_info(uint8 *bitmap, int num_bits, int *left, int *bit_pos) ++{ ++ int i; ++ for (*left = 0, i = 0; i < num_bits; i++) { ++ if (isset(bitmap, i)) { ++ (*left)++; ++ *bit_pos = i; ++ } ++ } ++} ++ ++static uint8 ++spec_to_chan(chanspec_t chspec) ++{ ++ uint8 center_ch, edge, primary, sb; ++ ++ center_ch = CHSPEC_CHANNEL(chspec); ++ ++ if (CHSPEC_BW_LE20(chspec)) { ++ return center_ch; ++ } else { ++ /* the lower edge of the wide channel is half the bw from ++ * the center channel. ++ */ ++ if (CHSPEC_IS40(chspec)) { ++ edge = center_ch - CH_20MHZ_APART; ++ } else { ++ /* must be 80MHz (until we support more) */ ++ ASSERT(CHSPEC_IS80(chspec)); ++ edge = center_ch - CH_40MHZ_APART; ++ } ++ ++ /* find the channel number of the lowest 20MHz primary channel */ ++ primary = edge + CH_10MHZ_APART; ++ ++ /* select the actual subband */ ++ sb = (chspec & WL_CHANSPEC_CTL_SB_MASK) >> WL_CHANSPEC_CTL_SB_SHIFT; ++ primary = primary + sb * CH_20MHZ_APART; ++ ++ return primary; ++ } ++} ++ ++/* ++ Take an array of measumrements representing summaries of different channels. ++ Return a recomended channel. ++ Interference is evil, get rid of that first. ++ Then hunt for lowest Other bss traffic. ++ Don't forget that channels with low duration times may not have accurate readings. ++ For the moment, do not overwrite input array. ++*/ ++int ++cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer) ++{ ++ uint8 *bitmap = NULL; /* 38 Max channels needs 5 bytes = 40 */ ++ int i, left, winner, ret_val = 0; ++ uint32 min_obss = 1 << 30; ++ uint bitmap_sz; ++ ++ bitmap_sz = CEIL(num_chans, NBBY); ++ bitmap = (uint8 *)malloc(bitmap_sz); ++ if (bitmap == NULL) { ++ printf("unable to allocate memory\n"); ++ return BCME_NOMEM; ++ } ++ ++ memset(bitmap, 0, bitmap_sz); ++ /* Initially, all channels are up for consideration */ ++ for (i = 0; i < num_chans; i++) { ++ if (input[i]->chanspec) ++ setbit(bitmap, i); ++ } ++ cca_info(bitmap, num_chans, &left, &i); ++ if (!left) { ++ ret_val = CCA_ERRNO_TOO_FEW; ++ goto f_exit; ++ } ++ ++ /* Filter for 2.4 GHz Band */ ++ if (flags & CCA_FLAG_2G_ONLY) { ++ for (i = 0; i < num_chans; i++) { ++ if (!CHSPEC_IS2G(input[i]->chanspec)) ++ clrbit(bitmap, i); ++ } ++ } ++ cca_info(bitmap, num_chans, &left, &i); ++ if (!left) { ++ ret_val = CCA_ERRNO_BAND; ++ goto f_exit; ++ } ++ ++ /* Filter for 5 GHz Band */ ++ if (flags & CCA_FLAG_5G_ONLY) { ++ for (i = 0; i < num_chans; i++) { ++ if (!CHSPEC_IS5G(input[i]->chanspec)) ++ clrbit(bitmap, i); ++ } ++ } ++ cca_info(bitmap, num_chans, &left, &i); ++ if (!left) { ++ ret_val = CCA_ERRNO_BAND; ++ goto f_exit; ++ } ++ ++ /* Filter for Duration */ ++ if (!(flags & CCA_FLAG_IGNORE_DURATION)) { ++ for (i = 0; i < num_chans; i++) { ++ if (input[i]->secs[0].duration < CCA_THRESH_MILLI) ++ clrbit(bitmap, i); ++ } ++ } ++ cca_info(bitmap, num_chans, &left, &i); ++ if (!left) { ++ ret_val = CCA_ERRNO_DURATION; ++ goto f_exit; ++ } ++ ++ /* Filter for 1 6 11 on 2.4 Band */ ++ if (flags & CCA_FLAGS_PREFER_1_6_11) { ++ int tmp_channel = spec_to_chan(input[i]->chanspec); ++ int is2g = CHSPEC_IS2G(input[i]->chanspec); ++ for (i = 0; i < num_chans; i++) { ++ if (is2g && tmp_channel != 1 && tmp_channel != 6 && tmp_channel != 11) ++ clrbit(bitmap, i); ++ } ++ } ++ cca_info(bitmap, num_chans, &left, &i); ++ if (!left) { ++ ret_val = CCA_ERRNO_PREF_CHAN; ++ goto f_exit; ++ } ++ ++ /* Toss high interference interference */ ++ if (!(flags & CCA_FLAG_IGNORE_INTERFER)) { ++ for (i = 0; i < num_chans; i++) { ++ if (input[i]->secs[0].interference > CCA_THRESH_INTERFERE) ++ clrbit(bitmap, i); ++ } ++ cca_info(bitmap, num_chans, &left, &i); ++ if (!left) { ++ ret_val = CCA_ERRNO_INTERFER; ++ goto f_exit; ++ } ++ } ++ ++ /* Now find lowest obss */ ++ winner = 0; ++ for (i = 0; i < num_chans; i++) { ++ if (isset(bitmap, i) && input[i]->secs[0].congest_obss < min_obss) { ++ winner = i; ++ min_obss = input[i]->secs[0].congest_obss; ++ } ++ } ++ *answer = input[winner]->chanspec; ++ f_exit: ++ free(bitmap); /* free the allocated memory for bitmap */ ++ return ret_val; ++} ++#endif /* !BCMDRIVER */ ++ ++/* offset of cntmember by sizeof(uint32) from the first cnt variable, txframe. */ ++#define IDX_IN_WL_CNT_VER_6_T(cntmember) \ ++ ((OFFSETOF(wl_cnt_ver_6_t, cntmember) - OFFSETOF(wl_cnt_ver_6_t, txframe)) / sizeof(uint32)) ++ ++#define IDX_IN_WL_CNT_VER_11_T(cntmember) \ ++ ((OFFSETOF(wl_cnt_ver_11_t, cntmember) - OFFSETOF(wl_cnt_ver_11_t, txframe)) \ ++ / sizeof(uint32)) ++ ++/* Exclude version and length fields */ ++#define NUM_OF_CNT_IN_WL_CNT_VER_6_T \ ++ ((sizeof(wl_cnt_ver_6_t) - 2 * sizeof(uint16)) / sizeof(uint32)) ++/* Exclude macstat cnt variables. wl_cnt_ver_6_t only has 62 macstat cnt variables. */ ++#define NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T \ ++ (NUM_OF_CNT_IN_WL_CNT_VER_6_T - (WL_CNT_MCST_VAR_NUM - 2)) ++ ++/* Exclude version and length fields */ ++#define NUM_OF_CNT_IN_WL_CNT_VER_11_T \ ++ ((sizeof(wl_cnt_ver_11_t) - 2 * sizeof(uint16)) / sizeof(uint32)) ++/* Exclude 64 macstat cnt variables. */ ++#define NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T \ ++ (NUM_OF_CNT_IN_WL_CNT_VER_11_T - WL_CNT_MCST_VAR_NUM) ++ ++/* Index conversion table from wl_cnt_ver_6_t to wl_cnt_wlc_t */ ++static const uint8 wlcntver6t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T] = { ++ IDX_IN_WL_CNT_VER_6_T(txframe), ++ IDX_IN_WL_CNT_VER_6_T(txbyte), ++ IDX_IN_WL_CNT_VER_6_T(txretrans), ++ IDX_IN_WL_CNT_VER_6_T(txerror), ++ IDX_IN_WL_CNT_VER_6_T(txctl), ++ IDX_IN_WL_CNT_VER_6_T(txprshort), ++ IDX_IN_WL_CNT_VER_6_T(txserr), ++ IDX_IN_WL_CNT_VER_6_T(txnobuf), ++ IDX_IN_WL_CNT_VER_6_T(txnoassoc), ++ IDX_IN_WL_CNT_VER_6_T(txrunt), ++ IDX_IN_WL_CNT_VER_6_T(txchit), ++ IDX_IN_WL_CNT_VER_6_T(txcmiss), ++ IDX_IN_WL_CNT_VER_6_T(txuflo), ++ IDX_IN_WL_CNT_VER_6_T(txphyerr), ++ IDX_IN_WL_CNT_VER_6_T(txphycrs), ++ IDX_IN_WL_CNT_VER_6_T(rxframe), ++ IDX_IN_WL_CNT_VER_6_T(rxbyte), ++ IDX_IN_WL_CNT_VER_6_T(rxerror), ++ IDX_IN_WL_CNT_VER_6_T(rxctl), ++ IDX_IN_WL_CNT_VER_6_T(rxnobuf), ++ IDX_IN_WL_CNT_VER_6_T(rxnondata), ++ IDX_IN_WL_CNT_VER_6_T(rxbadds), ++ IDX_IN_WL_CNT_VER_6_T(rxbadcm), ++ IDX_IN_WL_CNT_VER_6_T(rxfragerr), ++ IDX_IN_WL_CNT_VER_6_T(rxrunt), ++ IDX_IN_WL_CNT_VER_6_T(rxgiant), ++ IDX_IN_WL_CNT_VER_6_T(rxnoscb), ++ IDX_IN_WL_CNT_VER_6_T(rxbadproto), ++ IDX_IN_WL_CNT_VER_6_T(rxbadsrcmac), ++ IDX_IN_WL_CNT_VER_6_T(rxbadda), ++ IDX_IN_WL_CNT_VER_6_T(rxfilter), ++ IDX_IN_WL_CNT_VER_6_T(rxoflo), ++ IDX_IN_WL_CNT_VER_6_T(rxuflo), ++ IDX_IN_WL_CNT_VER_6_T(rxuflo) + 1, ++ IDX_IN_WL_CNT_VER_6_T(rxuflo) + 2, ++ IDX_IN_WL_CNT_VER_6_T(rxuflo) + 3, ++ IDX_IN_WL_CNT_VER_6_T(rxuflo) + 4, ++ IDX_IN_WL_CNT_VER_6_T(rxuflo) + 5, ++ IDX_IN_WL_CNT_VER_6_T(d11cnt_txrts_off), ++ IDX_IN_WL_CNT_VER_6_T(d11cnt_rxcrc_off), ++ IDX_IN_WL_CNT_VER_6_T(d11cnt_txnocts_off), ++ IDX_IN_WL_CNT_VER_6_T(dmade), ++ IDX_IN_WL_CNT_VER_6_T(dmada), ++ IDX_IN_WL_CNT_VER_6_T(dmape), ++ IDX_IN_WL_CNT_VER_6_T(reset), ++ IDX_IN_WL_CNT_VER_6_T(tbtt), ++ IDX_IN_WL_CNT_VER_6_T(txdmawar), ++ IDX_IN_WL_CNT_VER_6_T(pkt_callback_reg_fail), ++ IDX_IN_WL_CNT_VER_6_T(txfrag), ++ IDX_IN_WL_CNT_VER_6_T(txmulti), ++ IDX_IN_WL_CNT_VER_6_T(txfail), ++ IDX_IN_WL_CNT_VER_6_T(txretry), ++ IDX_IN_WL_CNT_VER_6_T(txretrie), ++ IDX_IN_WL_CNT_VER_6_T(rxdup), ++ IDX_IN_WL_CNT_VER_6_T(txrts), ++ IDX_IN_WL_CNT_VER_6_T(txnocts), ++ IDX_IN_WL_CNT_VER_6_T(txnoack), ++ IDX_IN_WL_CNT_VER_6_T(rxfrag), ++ IDX_IN_WL_CNT_VER_6_T(rxmulti), ++ IDX_IN_WL_CNT_VER_6_T(rxcrc), ++ IDX_IN_WL_CNT_VER_6_T(txfrmsnt), ++ IDX_IN_WL_CNT_VER_6_T(rxundec), ++ IDX_IN_WL_CNT_VER_6_T(tkipmicfaill), ++ IDX_IN_WL_CNT_VER_6_T(tkipcntrmsr), ++ IDX_IN_WL_CNT_VER_6_T(tkipreplay), ++ IDX_IN_WL_CNT_VER_6_T(ccmpfmterr), ++ IDX_IN_WL_CNT_VER_6_T(ccmpreplay), ++ IDX_IN_WL_CNT_VER_6_T(ccmpundec), ++ IDX_IN_WL_CNT_VER_6_T(fourwayfail), ++ IDX_IN_WL_CNT_VER_6_T(wepundec), ++ IDX_IN_WL_CNT_VER_6_T(wepicverr), ++ IDX_IN_WL_CNT_VER_6_T(decsuccess), ++ IDX_IN_WL_CNT_VER_6_T(tkipicverr), ++ IDX_IN_WL_CNT_VER_6_T(wepexcluded), ++ IDX_IN_WL_CNT_VER_6_T(txchanrej), ++ IDX_IN_WL_CNT_VER_6_T(psmwds), ++ IDX_IN_WL_CNT_VER_6_T(phywatchdog), ++ IDX_IN_WL_CNT_VER_6_T(prq_entries_handled), ++ IDX_IN_WL_CNT_VER_6_T(prq_undirected_entries), ++ IDX_IN_WL_CNT_VER_6_T(prq_bad_entries), ++ IDX_IN_WL_CNT_VER_6_T(atim_suppress_count), ++ IDX_IN_WL_CNT_VER_6_T(bcn_template_not_ready), ++ IDX_IN_WL_CNT_VER_6_T(bcn_template_not_ready_done), ++ IDX_IN_WL_CNT_VER_6_T(late_tbtt_dpc), ++ IDX_IN_WL_CNT_VER_6_T(rx1mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx2mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx5mbps5), ++ IDX_IN_WL_CNT_VER_6_T(rx6mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx9mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx11mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx12mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx18mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx24mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx36mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx48mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx54mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx108mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx162mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx216mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx270mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx324mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx378mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx432mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx486mbps), ++ IDX_IN_WL_CNT_VER_6_T(rx540mbps), ++ IDX_IN_WL_CNT_VER_6_T(rfdisable), ++ IDX_IN_WL_CNT_VER_6_T(txexptime), ++ IDX_IN_WL_CNT_VER_6_T(txmpdu_sgi), ++ IDX_IN_WL_CNT_VER_6_T(rxmpdu_sgi), ++ IDX_IN_WL_CNT_VER_6_T(txmpdu_stbc), ++ IDX_IN_WL_CNT_VER_6_T(rxmpdu_stbc), ++ IDX_IN_WL_CNT_VER_6_T(rxundec_mcst), ++ IDX_IN_WL_CNT_VER_6_T(tkipmicfaill_mcst), ++ IDX_IN_WL_CNT_VER_6_T(tkipcntrmsr_mcst), ++ IDX_IN_WL_CNT_VER_6_T(tkipreplay_mcst), ++ IDX_IN_WL_CNT_VER_6_T(ccmpfmterr_mcst), ++ IDX_IN_WL_CNT_VER_6_T(ccmpreplay_mcst), ++ IDX_IN_WL_CNT_VER_6_T(ccmpundec_mcst), ++ IDX_IN_WL_CNT_VER_6_T(fourwayfail_mcst), ++ IDX_IN_WL_CNT_VER_6_T(wepundec_mcst), ++ IDX_IN_WL_CNT_VER_6_T(wepicverr_mcst), ++ IDX_IN_WL_CNT_VER_6_T(decsuccess_mcst), ++ IDX_IN_WL_CNT_VER_6_T(tkipicverr_mcst), ++ IDX_IN_WL_CNT_VER_6_T(wepexcluded_mcst) ++}; ++ ++/* Index conversion table from wl_cnt_ver_11_t to wl_cnt_wlc_t */ ++static const uint8 wlcntver11t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T] = { ++ IDX_IN_WL_CNT_VER_11_T(txframe), ++ IDX_IN_WL_CNT_VER_11_T(txbyte), ++ IDX_IN_WL_CNT_VER_11_T(txretrans), ++ IDX_IN_WL_CNT_VER_11_T(txerror), ++ IDX_IN_WL_CNT_VER_11_T(txctl), ++ IDX_IN_WL_CNT_VER_11_T(txprshort), ++ IDX_IN_WL_CNT_VER_11_T(txserr), ++ IDX_IN_WL_CNT_VER_11_T(txnobuf), ++ IDX_IN_WL_CNT_VER_11_T(txnoassoc), ++ IDX_IN_WL_CNT_VER_11_T(txrunt), ++ IDX_IN_WL_CNT_VER_11_T(txchit), ++ IDX_IN_WL_CNT_VER_11_T(txcmiss), ++ IDX_IN_WL_CNT_VER_11_T(txuflo), ++ IDX_IN_WL_CNT_VER_11_T(txphyerr), ++ IDX_IN_WL_CNT_VER_11_T(txphycrs), ++ IDX_IN_WL_CNT_VER_11_T(rxframe), ++ IDX_IN_WL_CNT_VER_11_T(rxbyte), ++ IDX_IN_WL_CNT_VER_11_T(rxerror), ++ IDX_IN_WL_CNT_VER_11_T(rxctl), ++ IDX_IN_WL_CNT_VER_11_T(rxnobuf), ++ IDX_IN_WL_CNT_VER_11_T(rxnondata), ++ IDX_IN_WL_CNT_VER_11_T(rxbadds), ++ IDX_IN_WL_CNT_VER_11_T(rxbadcm), ++ IDX_IN_WL_CNT_VER_11_T(rxfragerr), ++ IDX_IN_WL_CNT_VER_11_T(rxrunt), ++ IDX_IN_WL_CNT_VER_11_T(rxgiant), ++ IDX_IN_WL_CNT_VER_11_T(rxnoscb), ++ IDX_IN_WL_CNT_VER_11_T(rxbadproto), ++ IDX_IN_WL_CNT_VER_11_T(rxbadsrcmac), ++ IDX_IN_WL_CNT_VER_11_T(rxbadda), ++ IDX_IN_WL_CNT_VER_11_T(rxfilter), ++ IDX_IN_WL_CNT_VER_11_T(rxoflo), ++ IDX_IN_WL_CNT_VER_11_T(rxuflo), ++ IDX_IN_WL_CNT_VER_11_T(rxuflo) + 1, ++ IDX_IN_WL_CNT_VER_11_T(rxuflo) + 2, ++ IDX_IN_WL_CNT_VER_11_T(rxuflo) + 3, ++ IDX_IN_WL_CNT_VER_11_T(rxuflo) + 4, ++ IDX_IN_WL_CNT_VER_11_T(rxuflo) + 5, ++ IDX_IN_WL_CNT_VER_11_T(d11cnt_txrts_off), ++ IDX_IN_WL_CNT_VER_11_T(d11cnt_rxcrc_off), ++ IDX_IN_WL_CNT_VER_11_T(d11cnt_txnocts_off), ++ IDX_IN_WL_CNT_VER_11_T(dmade), ++ IDX_IN_WL_CNT_VER_11_T(dmada), ++ IDX_IN_WL_CNT_VER_11_T(dmape), ++ IDX_IN_WL_CNT_VER_11_T(reset), ++ IDX_IN_WL_CNT_VER_11_T(tbtt), ++ IDX_IN_WL_CNT_VER_11_T(txdmawar), ++ IDX_IN_WL_CNT_VER_11_T(pkt_callback_reg_fail), ++ IDX_IN_WL_CNT_VER_11_T(txfrag), ++ IDX_IN_WL_CNT_VER_11_T(txmulti), ++ IDX_IN_WL_CNT_VER_11_T(txfail), ++ IDX_IN_WL_CNT_VER_11_T(txretry), ++ IDX_IN_WL_CNT_VER_11_T(txretrie), ++ IDX_IN_WL_CNT_VER_11_T(rxdup), ++ IDX_IN_WL_CNT_VER_11_T(txrts), ++ IDX_IN_WL_CNT_VER_11_T(txnocts), ++ IDX_IN_WL_CNT_VER_11_T(txnoack), ++ IDX_IN_WL_CNT_VER_11_T(rxfrag), ++ IDX_IN_WL_CNT_VER_11_T(rxmulti), ++ IDX_IN_WL_CNT_VER_11_T(rxcrc), ++ IDX_IN_WL_CNT_VER_11_T(txfrmsnt), ++ IDX_IN_WL_CNT_VER_11_T(rxundec), ++ IDX_IN_WL_CNT_VER_11_T(tkipmicfaill), ++ IDX_IN_WL_CNT_VER_11_T(tkipcntrmsr), ++ IDX_IN_WL_CNT_VER_11_T(tkipreplay), ++ IDX_IN_WL_CNT_VER_11_T(ccmpfmterr), ++ IDX_IN_WL_CNT_VER_11_T(ccmpreplay), ++ IDX_IN_WL_CNT_VER_11_T(ccmpundec), ++ IDX_IN_WL_CNT_VER_11_T(fourwayfail), ++ IDX_IN_WL_CNT_VER_11_T(wepundec), ++ IDX_IN_WL_CNT_VER_11_T(wepicverr), ++ IDX_IN_WL_CNT_VER_11_T(decsuccess), ++ IDX_IN_WL_CNT_VER_11_T(tkipicverr), ++ IDX_IN_WL_CNT_VER_11_T(wepexcluded), ++ IDX_IN_WL_CNT_VER_11_T(txchanrej), ++ IDX_IN_WL_CNT_VER_11_T(psmwds), ++ IDX_IN_WL_CNT_VER_11_T(phywatchdog), ++ IDX_IN_WL_CNT_VER_11_T(prq_entries_handled), ++ IDX_IN_WL_CNT_VER_11_T(prq_undirected_entries), ++ IDX_IN_WL_CNT_VER_11_T(prq_bad_entries), ++ IDX_IN_WL_CNT_VER_11_T(atim_suppress_count), ++ IDX_IN_WL_CNT_VER_11_T(bcn_template_not_ready), ++ IDX_IN_WL_CNT_VER_11_T(bcn_template_not_ready_done), ++ IDX_IN_WL_CNT_VER_11_T(late_tbtt_dpc), ++ IDX_IN_WL_CNT_VER_11_T(rx1mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx2mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx5mbps5), ++ IDX_IN_WL_CNT_VER_11_T(rx6mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx9mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx11mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx12mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx18mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx24mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx36mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx48mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx54mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx108mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx162mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx216mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx270mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx324mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx378mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx432mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx486mbps), ++ IDX_IN_WL_CNT_VER_11_T(rx540mbps), ++ IDX_IN_WL_CNT_VER_11_T(rfdisable), ++ IDX_IN_WL_CNT_VER_11_T(txexptime), ++ IDX_IN_WL_CNT_VER_11_T(txmpdu_sgi), ++ IDX_IN_WL_CNT_VER_11_T(rxmpdu_sgi), ++ IDX_IN_WL_CNT_VER_11_T(txmpdu_stbc), ++ IDX_IN_WL_CNT_VER_11_T(rxmpdu_stbc), ++ IDX_IN_WL_CNT_VER_11_T(rxundec_mcst), ++ IDX_IN_WL_CNT_VER_11_T(tkipmicfaill_mcst), ++ IDX_IN_WL_CNT_VER_11_T(tkipcntrmsr_mcst), ++ IDX_IN_WL_CNT_VER_11_T(tkipreplay_mcst), ++ IDX_IN_WL_CNT_VER_11_T(ccmpfmterr_mcst), ++ IDX_IN_WL_CNT_VER_11_T(ccmpreplay_mcst), ++ IDX_IN_WL_CNT_VER_11_T(ccmpundec_mcst), ++ IDX_IN_WL_CNT_VER_11_T(fourwayfail_mcst), ++ IDX_IN_WL_CNT_VER_11_T(wepundec_mcst), ++ IDX_IN_WL_CNT_VER_11_T(wepicverr_mcst), ++ IDX_IN_WL_CNT_VER_11_T(decsuccess_mcst), ++ IDX_IN_WL_CNT_VER_11_T(tkipicverr_mcst), ++ IDX_IN_WL_CNT_VER_11_T(wepexcluded_mcst), ++ IDX_IN_WL_CNT_VER_11_T(dma_hang), ++ IDX_IN_WL_CNT_VER_11_T(reinit), ++ IDX_IN_WL_CNT_VER_11_T(pstatxucast), ++ IDX_IN_WL_CNT_VER_11_T(pstatxnoassoc), ++ IDX_IN_WL_CNT_VER_11_T(pstarxucast), ++ IDX_IN_WL_CNT_VER_11_T(pstarxbcmc), ++ IDX_IN_WL_CNT_VER_11_T(pstatxbcmc), ++ IDX_IN_WL_CNT_VER_11_T(cso_passthrough), ++ IDX_IN_WL_CNT_VER_11_T(cso_normal), ++ IDX_IN_WL_CNT_VER_11_T(chained), ++ IDX_IN_WL_CNT_VER_11_T(chainedsz1), ++ IDX_IN_WL_CNT_VER_11_T(unchained), ++ IDX_IN_WL_CNT_VER_11_T(maxchainsz), ++ IDX_IN_WL_CNT_VER_11_T(currchainsz), ++ IDX_IN_WL_CNT_VER_11_T(pciereset), ++ IDX_IN_WL_CNT_VER_11_T(cfgrestore), ++ IDX_IN_WL_CNT_VER_11_T(reinitreason), ++ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 1, ++ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 2, ++ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 3, ++ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 4, ++ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 5, ++ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 6, ++ IDX_IN_WL_CNT_VER_11_T(reinitreason) + 7, ++ IDX_IN_WL_CNT_VER_11_T(rxrtry), ++ IDX_IN_WL_CNT_VER_11_T(rxmpdu_mu), ++ IDX_IN_WL_CNT_VER_11_T(txbar), ++ IDX_IN_WL_CNT_VER_11_T(rxbar), ++ IDX_IN_WL_CNT_VER_11_T(txpspoll), ++ IDX_IN_WL_CNT_VER_11_T(rxpspoll), ++ IDX_IN_WL_CNT_VER_11_T(txnull), ++ IDX_IN_WL_CNT_VER_11_T(rxnull), ++ IDX_IN_WL_CNT_VER_11_T(txqosnull), ++ IDX_IN_WL_CNT_VER_11_T(rxqosnull), ++ IDX_IN_WL_CNT_VER_11_T(txassocreq), ++ IDX_IN_WL_CNT_VER_11_T(rxassocreq), ++ IDX_IN_WL_CNT_VER_11_T(txreassocreq), ++ IDX_IN_WL_CNT_VER_11_T(rxreassocreq), ++ IDX_IN_WL_CNT_VER_11_T(txdisassoc), ++ IDX_IN_WL_CNT_VER_11_T(rxdisassoc), ++ IDX_IN_WL_CNT_VER_11_T(txassocrsp), ++ IDX_IN_WL_CNT_VER_11_T(rxassocrsp), ++ IDX_IN_WL_CNT_VER_11_T(txreassocrsp), ++ IDX_IN_WL_CNT_VER_11_T(rxreassocrsp), ++ IDX_IN_WL_CNT_VER_11_T(txauth), ++ IDX_IN_WL_CNT_VER_11_T(rxauth), ++ IDX_IN_WL_CNT_VER_11_T(txdeauth), ++ IDX_IN_WL_CNT_VER_11_T(rxdeauth), ++ IDX_IN_WL_CNT_VER_11_T(txprobereq), ++ IDX_IN_WL_CNT_VER_11_T(rxprobereq), ++ IDX_IN_WL_CNT_VER_11_T(txprobersp), ++ IDX_IN_WL_CNT_VER_11_T(rxprobersp), ++ IDX_IN_WL_CNT_VER_11_T(txaction), ++ IDX_IN_WL_CNT_VER_11_T(rxaction), ++ IDX_IN_WL_CNT_VER_11_T(ampdu_wds), ++ IDX_IN_WL_CNT_VER_11_T(txlost), ++ IDX_IN_WL_CNT_VER_11_T(txdatamcast), ++ IDX_IN_WL_CNT_VER_11_T(txdatabcast) ++}; ++ ++/* Index conversion table from wl_cnt_ver_11_t to ++ * either wl_cnt_ge40mcst_v1_t or wl_cnt_lt40mcst_v1_t ++ */ ++static const uint8 wlcntver11t_to_wlcntXX40mcstv1t[WL_CNT_MCST_VAR_NUM] = { ++ IDX_IN_WL_CNT_VER_11_T(txallfrm), ++ IDX_IN_WL_CNT_VER_11_T(txrtsfrm), ++ IDX_IN_WL_CNT_VER_11_T(txctsfrm), ++ IDX_IN_WL_CNT_VER_11_T(txackfrm), ++ IDX_IN_WL_CNT_VER_11_T(txdnlfrm), ++ IDX_IN_WL_CNT_VER_11_T(txbcnfrm), ++ IDX_IN_WL_CNT_VER_11_T(txfunfl), ++ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 1, ++ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 2, ++ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 3, ++ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 4, ++ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 5, ++ IDX_IN_WL_CNT_VER_11_T(txfbw), ++ IDX_IN_WL_CNT_VER_11_T(txmpdu), ++ IDX_IN_WL_CNT_VER_11_T(txtplunfl), ++ IDX_IN_WL_CNT_VER_11_T(txphyerror), ++ IDX_IN_WL_CNT_VER_11_T(pktengrxducast), ++ IDX_IN_WL_CNT_VER_11_T(pktengrxdmcast), ++ IDX_IN_WL_CNT_VER_11_T(rxfrmtoolong), ++ IDX_IN_WL_CNT_VER_11_T(rxfrmtooshrt), ++ IDX_IN_WL_CNT_VER_11_T(rxinvmachdr), ++ IDX_IN_WL_CNT_VER_11_T(rxbadfcs), ++ IDX_IN_WL_CNT_VER_11_T(rxbadplcp), ++ IDX_IN_WL_CNT_VER_11_T(rxcrsglitch), ++ IDX_IN_WL_CNT_VER_11_T(rxstrt), ++ IDX_IN_WL_CNT_VER_11_T(rxdfrmucastmbss), ++ IDX_IN_WL_CNT_VER_11_T(rxmfrmucastmbss), ++ IDX_IN_WL_CNT_VER_11_T(rxcfrmucast), ++ IDX_IN_WL_CNT_VER_11_T(rxrtsucast), ++ IDX_IN_WL_CNT_VER_11_T(rxctsucast), ++ IDX_IN_WL_CNT_VER_11_T(rxackucast), ++ IDX_IN_WL_CNT_VER_11_T(rxdfrmocast), ++ IDX_IN_WL_CNT_VER_11_T(rxmfrmocast), ++ IDX_IN_WL_CNT_VER_11_T(rxcfrmocast), ++ IDX_IN_WL_CNT_VER_11_T(rxrtsocast), ++ IDX_IN_WL_CNT_VER_11_T(rxctsocast), ++ IDX_IN_WL_CNT_VER_11_T(rxdfrmmcast), ++ IDX_IN_WL_CNT_VER_11_T(rxmfrmmcast), ++ IDX_IN_WL_CNT_VER_11_T(rxcfrmmcast), ++ IDX_IN_WL_CNT_VER_11_T(rxbeaconmbss), ++ IDX_IN_WL_CNT_VER_11_T(rxdfrmucastobss), ++ IDX_IN_WL_CNT_VER_11_T(rxbeaconobss), ++ IDX_IN_WL_CNT_VER_11_T(rxrsptmout), ++ IDX_IN_WL_CNT_VER_11_T(bcntxcancl), ++ IDX_IN_WL_CNT_VER_11_T(rxnodelim), ++ IDX_IN_WL_CNT_VER_11_T(rxf0ovfl), ++ IDX_IN_WL_CNT_VER_11_T(rxf1ovfl), ++ IDX_IN_WL_CNT_VER_11_T(rxf2ovfl), ++ IDX_IN_WL_CNT_VER_11_T(txsfovfl), ++ IDX_IN_WL_CNT_VER_11_T(pmqovfl), ++ IDX_IN_WL_CNT_VER_11_T(rxcgprqfrm), ++ IDX_IN_WL_CNT_VER_11_T(rxcgprsqovfl), ++ IDX_IN_WL_CNT_VER_11_T(txcgprsfail), ++ IDX_IN_WL_CNT_VER_11_T(txcgprssuc), ++ IDX_IN_WL_CNT_VER_11_T(prs_timeout), ++ IDX_IN_WL_CNT_VER_11_T(rxnack), ++ IDX_IN_WL_CNT_VER_11_T(frmscons), ++ IDX_IN_WL_CNT_VER_11_T(txnack), ++ IDX_IN_WL_CNT_VER_11_T(rxback), ++ IDX_IN_WL_CNT_VER_11_T(txback), ++ IDX_IN_WL_CNT_VER_11_T(bphy_rxcrsglitch), ++ IDX_IN_WL_CNT_VER_11_T(rxdrop20s), ++ IDX_IN_WL_CNT_VER_11_T(rxtoolate), ++ IDX_IN_WL_CNT_VER_11_T(bphy_badplcp) ++}; ++ ++/* For mcst offsets that were not used. (2 Pads) */ ++#define INVALID_MCST_IDX ((uint8)(-1)) ++/* Index conversion table from wl_cnt_ver_11_t to wl_cnt_v_le10_mcst_t */ ++static const uint8 wlcntver11t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = { ++ IDX_IN_WL_CNT_VER_11_T(txallfrm), ++ IDX_IN_WL_CNT_VER_11_T(txrtsfrm), ++ IDX_IN_WL_CNT_VER_11_T(txctsfrm), ++ IDX_IN_WL_CNT_VER_11_T(txackfrm), ++ IDX_IN_WL_CNT_VER_11_T(txdnlfrm), ++ IDX_IN_WL_CNT_VER_11_T(txbcnfrm), ++ IDX_IN_WL_CNT_VER_11_T(txfunfl), ++ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 1, ++ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 2, ++ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 3, ++ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 4, ++ IDX_IN_WL_CNT_VER_11_T(txfunfl) + 5, ++ IDX_IN_WL_CNT_VER_11_T(txfbw), ++ INVALID_MCST_IDX, ++ IDX_IN_WL_CNT_VER_11_T(txtplunfl), ++ IDX_IN_WL_CNT_VER_11_T(txphyerror), ++ IDX_IN_WL_CNT_VER_11_T(pktengrxducast), ++ IDX_IN_WL_CNT_VER_11_T(pktengrxdmcast), ++ IDX_IN_WL_CNT_VER_11_T(rxfrmtoolong), ++ IDX_IN_WL_CNT_VER_11_T(rxfrmtooshrt), ++ IDX_IN_WL_CNT_VER_11_T(rxinvmachdr), ++ IDX_IN_WL_CNT_VER_11_T(rxbadfcs), ++ IDX_IN_WL_CNT_VER_11_T(rxbadplcp), ++ IDX_IN_WL_CNT_VER_11_T(rxcrsglitch), ++ IDX_IN_WL_CNT_VER_11_T(rxstrt), ++ IDX_IN_WL_CNT_VER_11_T(rxdfrmucastmbss), ++ IDX_IN_WL_CNT_VER_11_T(rxmfrmucastmbss), ++ IDX_IN_WL_CNT_VER_11_T(rxcfrmucast), ++ IDX_IN_WL_CNT_VER_11_T(rxrtsucast), ++ IDX_IN_WL_CNT_VER_11_T(rxctsucast), ++ IDX_IN_WL_CNT_VER_11_T(rxackucast), ++ IDX_IN_WL_CNT_VER_11_T(rxdfrmocast), ++ IDX_IN_WL_CNT_VER_11_T(rxmfrmocast), ++ IDX_IN_WL_CNT_VER_11_T(rxcfrmocast), ++ IDX_IN_WL_CNT_VER_11_T(rxrtsocast), ++ IDX_IN_WL_CNT_VER_11_T(rxctsocast), ++ IDX_IN_WL_CNT_VER_11_T(rxdfrmmcast), ++ IDX_IN_WL_CNT_VER_11_T(rxmfrmmcast), ++ IDX_IN_WL_CNT_VER_11_T(rxcfrmmcast), ++ IDX_IN_WL_CNT_VER_11_T(rxbeaconmbss), ++ IDX_IN_WL_CNT_VER_11_T(rxdfrmucastobss), ++ IDX_IN_WL_CNT_VER_11_T(rxbeaconobss), ++ IDX_IN_WL_CNT_VER_11_T(rxrsptmout), ++ IDX_IN_WL_CNT_VER_11_T(bcntxcancl), ++ INVALID_MCST_IDX, ++ IDX_IN_WL_CNT_VER_11_T(rxf0ovfl), ++ IDX_IN_WL_CNT_VER_11_T(rxf1ovfl), ++ IDX_IN_WL_CNT_VER_11_T(rxf2ovfl), ++ IDX_IN_WL_CNT_VER_11_T(txsfovfl), ++ IDX_IN_WL_CNT_VER_11_T(pmqovfl), ++ IDX_IN_WL_CNT_VER_11_T(rxcgprqfrm), ++ IDX_IN_WL_CNT_VER_11_T(rxcgprsqovfl), ++ IDX_IN_WL_CNT_VER_11_T(txcgprsfail), ++ IDX_IN_WL_CNT_VER_11_T(txcgprssuc), ++ IDX_IN_WL_CNT_VER_11_T(prs_timeout), ++ IDX_IN_WL_CNT_VER_11_T(rxnack), ++ IDX_IN_WL_CNT_VER_11_T(frmscons), ++ IDX_IN_WL_CNT_VER_11_T(txnack), ++ IDX_IN_WL_CNT_VER_11_T(rxback), ++ IDX_IN_WL_CNT_VER_11_T(txback), ++ IDX_IN_WL_CNT_VER_11_T(bphy_rxcrsglitch), ++ IDX_IN_WL_CNT_VER_11_T(rxdrop20s), ++ IDX_IN_WL_CNT_VER_11_T(rxtoolate), ++ IDX_IN_WL_CNT_VER_11_T(bphy_badplcp) ++}; ++ ++ ++/* Index conversion table from wl_cnt_ver_6_t to wl_cnt_v_le10_mcst_t */ ++static const uint8 wlcntver6t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = { ++ IDX_IN_WL_CNT_VER_6_T(txallfrm), ++ IDX_IN_WL_CNT_VER_6_T(txrtsfrm), ++ IDX_IN_WL_CNT_VER_6_T(txctsfrm), ++ IDX_IN_WL_CNT_VER_6_T(txackfrm), ++ IDX_IN_WL_CNT_VER_6_T(txdnlfrm), ++ IDX_IN_WL_CNT_VER_6_T(txbcnfrm), ++ IDX_IN_WL_CNT_VER_6_T(txfunfl), ++ IDX_IN_WL_CNT_VER_6_T(txfunfl) + 1, ++ IDX_IN_WL_CNT_VER_6_T(txfunfl) + 2, ++ IDX_IN_WL_CNT_VER_6_T(txfunfl) + 3, ++ IDX_IN_WL_CNT_VER_6_T(txfunfl) + 4, ++ IDX_IN_WL_CNT_VER_6_T(txfunfl) + 5, ++ IDX_IN_WL_CNT_VER_6_T(txfbw), ++ INVALID_MCST_IDX, ++ IDX_IN_WL_CNT_VER_6_T(txtplunfl), ++ IDX_IN_WL_CNT_VER_6_T(txphyerror), ++ IDX_IN_WL_CNT_VER_6_T(pktengrxducast), ++ IDX_IN_WL_CNT_VER_6_T(pktengrxdmcast), ++ IDX_IN_WL_CNT_VER_6_T(rxfrmtoolong), ++ IDX_IN_WL_CNT_VER_6_T(rxfrmtooshrt), ++ IDX_IN_WL_CNT_VER_6_T(rxinvmachdr), ++ IDX_IN_WL_CNT_VER_6_T(rxbadfcs), ++ IDX_IN_WL_CNT_VER_6_T(rxbadplcp), ++ IDX_IN_WL_CNT_VER_6_T(rxcrsglitch), ++ IDX_IN_WL_CNT_VER_6_T(rxstrt), ++ IDX_IN_WL_CNT_VER_6_T(rxdfrmucastmbss), ++ IDX_IN_WL_CNT_VER_6_T(rxmfrmucastmbss), ++ IDX_IN_WL_CNT_VER_6_T(rxcfrmucast), ++ IDX_IN_WL_CNT_VER_6_T(rxrtsucast), ++ IDX_IN_WL_CNT_VER_6_T(rxctsucast), ++ IDX_IN_WL_CNT_VER_6_T(rxackucast), ++ IDX_IN_WL_CNT_VER_6_T(rxdfrmocast), ++ IDX_IN_WL_CNT_VER_6_T(rxmfrmocast), ++ IDX_IN_WL_CNT_VER_6_T(rxcfrmocast), ++ IDX_IN_WL_CNT_VER_6_T(rxrtsocast), ++ IDX_IN_WL_CNT_VER_6_T(rxctsocast), ++ IDX_IN_WL_CNT_VER_6_T(rxdfrmmcast), ++ IDX_IN_WL_CNT_VER_6_T(rxmfrmmcast), ++ IDX_IN_WL_CNT_VER_6_T(rxcfrmmcast), ++ IDX_IN_WL_CNT_VER_6_T(rxbeaconmbss), ++ IDX_IN_WL_CNT_VER_6_T(rxdfrmucastobss), ++ IDX_IN_WL_CNT_VER_6_T(rxbeaconobss), ++ IDX_IN_WL_CNT_VER_6_T(rxrsptmout), ++ IDX_IN_WL_CNT_VER_6_T(bcntxcancl), ++ INVALID_MCST_IDX, ++ IDX_IN_WL_CNT_VER_6_T(rxf0ovfl), ++ IDX_IN_WL_CNT_VER_6_T(rxf1ovfl), ++ IDX_IN_WL_CNT_VER_6_T(rxf2ovfl), ++ IDX_IN_WL_CNT_VER_6_T(txsfovfl), ++ IDX_IN_WL_CNT_VER_6_T(pmqovfl), ++ IDX_IN_WL_CNT_VER_6_T(rxcgprqfrm), ++ IDX_IN_WL_CNT_VER_6_T(rxcgprsqovfl), ++ IDX_IN_WL_CNT_VER_6_T(txcgprsfail), ++ IDX_IN_WL_CNT_VER_6_T(txcgprssuc), ++ IDX_IN_WL_CNT_VER_6_T(prs_timeout), ++ IDX_IN_WL_CNT_VER_6_T(rxnack), ++ IDX_IN_WL_CNT_VER_6_T(frmscons), ++ IDX_IN_WL_CNT_VER_6_T(txnack), ++ IDX_IN_WL_CNT_VER_6_T(rxback), ++ IDX_IN_WL_CNT_VER_6_T(txback), ++ IDX_IN_WL_CNT_VER_6_T(bphy_rxcrsglitch), ++ IDX_IN_WL_CNT_VER_6_T(rxdrop20s), ++ IDX_IN_WL_CNT_VER_6_T(rxtoolate), ++ IDX_IN_WL_CNT_VER_6_T(bphy_badplcp) ++}; ++ ++/* copy wlc layer counters from old type cntbuf to wl_cnt_wlc_t type. */ ++static int ++wl_copy_wlccnt(uint16 cntver, uint32 *dst, uint32 *src, uint8 src_max_idx) ++{ ++ uint i; ++ if (dst == NULL || src == NULL) { ++ return BCME_ERROR; ++ } ++ ++ /* Init wlccnt with invalid value. Unchanged value will not be printed out */ ++ for (i = 0; i < (sizeof(wl_cnt_wlc_t) / sizeof(uint32)); i++) { ++ dst[i] = INVALID_CNT_VAL; ++ } ++ ++ if (cntver == WL_CNT_VERSION_6) { ++ for (i = 0; i < NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T; i++) { ++ if (wlcntver6t_to_wlcntwlct[i] >= src_max_idx) { ++ /* src buffer does not have counters from here */ ++ break; ++ } ++ dst[i] = src[wlcntver6t_to_wlcntwlct[i]]; ++ } ++ } else { ++ for (i = 0; i < NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T; i++) { ++ if (wlcntver11t_to_wlcntwlct[i] >= src_max_idx) { ++ /* src buffer does not have counters from here */ ++ break; ++ } ++ dst[i] = src[wlcntver11t_to_wlcntwlct[i]]; ++ } ++ } ++ return BCME_OK; ++} ++ ++/* copy macstat counters from old type cntbuf to wl_cnt_v_le10_mcst_t type. */ ++static int ++wl_copy_macstat_upto_ver10(uint16 cntver, uint32 *dst, uint32 *src) ++{ ++ uint i; ++ ++ if (dst == NULL || src == NULL) { ++ return BCME_ERROR; ++ } ++ ++ if (cntver == WL_CNT_VERSION_6) { ++ for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) { ++ if (wlcntver6t_to_wlcntvle10mcstt[i] == INVALID_MCST_IDX) { ++ /* This mcst counter does not exist in wl_cnt_ver_6_t */ ++ dst[i] = INVALID_CNT_VAL; ++ } else { ++ dst[i] = src[wlcntver6t_to_wlcntvle10mcstt[i]]; ++ } ++ } ++ } else { ++ for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) { ++ if (wlcntver11t_to_wlcntvle10mcstt[i] == INVALID_MCST_IDX) { ++ /* This mcst counter does not exist in wl_cnt_ver_11_t */ ++ dst[i] = INVALID_CNT_VAL; ++ } else { ++ dst[i] = src[wlcntver11t_to_wlcntvle10mcstt[i]]; ++ } ++ } ++ } ++ return BCME_OK; ++} ++ ++static int ++wl_copy_macstat_ver11(uint32 *dst, uint32 *src) ++{ ++ uint i; ++ ++ if (dst == NULL || src == NULL) { ++ return BCME_ERROR; ++ } ++ ++ for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) { ++ dst[i] = src[wlcntver11t_to_wlcntXX40mcstv1t[i]]; ++ } ++ return BCME_OK; ++} ++ ++/** ++ * Translate non-xtlv 'wl counters' IOVar buffer received by old driver/FW to xtlv format. ++ * Parameters: ++ * cntbuf: pointer to non-xtlv 'wl counters' IOVar buffer received by old driver/FW. ++ * Newly translated xtlv format is written to this pointer. ++ * buflen: length of the "cntbuf" without any padding. ++ * corerev: chip core revision of the driver/FW. ++ */ ++int ++wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf, int buflen, uint32 corerev) ++{ ++ wl_cnt_wlc_t *wlccnt = NULL; ++ uint32 *macstat = NULL; ++ xtlv_desc_t xtlv_desc[3]; ++ uint16 mcst_xtlv_id; ++ int res = BCME_OK; ++ wl_cnt_info_t *cntinfo = cntbuf; ++ void *xtlvbuf_p = cntinfo->data; ++ uint16 ver = cntinfo->version; ++ uint16 xtlvbuflen = (uint16)buflen; ++ uint16 src_max_idx; ++#ifdef BCMDRIVER ++ osl_t *osh = ctx; ++#else ++ BCM_REFERENCE(ctx); ++#endif ++ ++ if (ver >= WL_CNT_VERSION_XTLV) { ++ /* Already in xtlv format. */ ++ goto exit; ++ } ++ ++#ifdef BCMDRIVER ++ wlccnt = MALLOC(osh, sizeof(*wlccnt)); ++ macstat = MALLOC(osh, WL_CNT_MCST_STRUCT_SZ); ++#else ++ wlccnt = (wl_cnt_wlc_t *)malloc(sizeof(*wlccnt)); ++ macstat = (uint32 *)malloc(WL_CNT_MCST_STRUCT_SZ); ++#endif ++ if (!wlccnt || !macstat) { ++ printf("%s: malloc fail!\n", __FUNCTION__); ++ res = BCME_NOMEM; ++ goto exit; ++ } ++ ++ /* Check if the max idx in the struct exceeds the boundary of uint8 */ ++ if (NUM_OF_CNT_IN_WL_CNT_VER_6_T > ((uint8)(-1) + 1) || ++ NUM_OF_CNT_IN_WL_CNT_VER_11_T > ((uint8)(-1) + 1)) { ++ printf("wlcntverXXt_to_wlcntwlct and src_max_idx need" ++ " to be of uint16 instead of uint8\n"); ++ res = BCME_ERROR; ++ goto exit; ++ } ++ ++ /* Exclude version and length fields in either wlc_cnt_ver_6_t or wlc_cnt_ver_11_t */ ++ src_max_idx = (cntinfo->datalen - OFFSETOF(wl_cnt_info_t, data)) / sizeof(uint32); ++ if (src_max_idx > (uint8)(-1)) { ++ printf("wlcntverXXt_to_wlcntwlct and src_max_idx need" ++ " to be of uint16 instead of uint8\n" ++ "Try updating wl utility to the latest.\n"); ++ src_max_idx = (uint8)(-1); ++ } ++ ++ /* Copy wlc layer counters to wl_cnt_wlc_t */ ++ res = wl_copy_wlccnt(ver, (uint32 *)wlccnt, (uint32 *)cntinfo->data, (uint8)src_max_idx); ++ if (res != BCME_OK) { ++ printf("wl_copy_wlccnt fail!\n"); ++ goto exit; ++ } ++ ++ /* Copy macstat counters to wl_cnt_wlc_t */ ++ if (ver == WL_CNT_VERSION_11) { ++ res = wl_copy_macstat_ver11(macstat, (uint32 *)cntinfo->data); ++ if (res != BCME_OK) { ++ printf("wl_copy_macstat_ver11 fail!\n"); ++ goto exit; ++ } ++ if (corerev >= 40) { ++ mcst_xtlv_id = WL_CNT_XTLV_GE40_UCODE_V1; ++ } else { ++ mcst_xtlv_id = WL_CNT_XTLV_LT40_UCODE_V1; ++ } ++ } else { ++ res = wl_copy_macstat_upto_ver10(ver, macstat, (uint32 *)cntinfo->data); ++ if (res != BCME_OK) { ++ printf("wl_copy_macstat_upto_ver10 fail!\n"); ++ goto exit; ++ } ++ mcst_xtlv_id = WL_CNT_XTLV_CNTV_LE10_UCODE; ++ } ++ ++ xtlv_desc[0].type = WL_CNT_XTLV_WLC; ++ xtlv_desc[0].len = sizeof(*wlccnt); ++ xtlv_desc[0].ptr = wlccnt; ++ ++ xtlv_desc[1].type = mcst_xtlv_id; ++ xtlv_desc[1].len = WL_CNT_MCST_STRUCT_SZ; ++ xtlv_desc[1].ptr = macstat; ++ ++ xtlv_desc[2].type = 0; ++ xtlv_desc[2].len = 0; ++ xtlv_desc[2].ptr = NULL; ++ ++ memset(cntbuf, 0, buflen); ++ ++ res = bcm_pack_xtlv_buf_from_mem(&xtlvbuf_p, &xtlvbuflen, ++ xtlv_desc, BCM_XTLV_OPTION_ALIGN32); ++ cntinfo->datalen = (buflen - xtlvbuflen); ++exit: ++#ifdef BCMDRIVER ++ if (wlccnt) { ++ MFREE(osh, wlccnt, sizeof(*wlccnt)); ++ } ++ if (macstat) { ++ MFREE(osh, macstat, WL_CNT_MCST_STRUCT_SZ); ++ } ++#else ++ if (wlccnt) { ++ free(wlccnt); ++ } ++ if (macstat) { ++ free(macstat); ++ } ++#endif ++ return res; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmevent.c b/module_drivers/drivers/net/wireless/bcmdhd/bcmevent.c +new file mode 100644 +index 000000000..1e44ad7d4 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmevent.c +@@ -0,0 +1,385 @@ ++/* ++ * bcmevent read-only data shared by kernel or app layers ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmevent.c 707287 2017-06-27 06:44:29Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include <802.11.h> ++ ++/* Table of event name strings for UIs and debugging dumps */ ++typedef struct { ++ uint event; ++ const char *name; ++} bcmevent_name_str_t; ++ ++/* Use the actual name for event tracing */ ++#define BCMEVENT_NAME(_event) {(_event), #_event} ++ ++static const bcmevent_name_str_t bcmevent_names[] = { ++ BCMEVENT_NAME(WLC_E_SET_SSID), ++ BCMEVENT_NAME(WLC_E_JOIN), ++ BCMEVENT_NAME(WLC_E_START), ++ BCMEVENT_NAME(WLC_E_AUTH), ++ BCMEVENT_NAME(WLC_E_AUTH_IND), ++ BCMEVENT_NAME(WLC_E_DEAUTH), ++ BCMEVENT_NAME(WLC_E_DEAUTH_IND), ++ BCMEVENT_NAME(WLC_E_ASSOC), ++ BCMEVENT_NAME(WLC_E_ASSOC_IND), ++ BCMEVENT_NAME(WLC_E_REASSOC), ++ BCMEVENT_NAME(WLC_E_REASSOC_IND), ++ BCMEVENT_NAME(WLC_E_DISASSOC), ++ BCMEVENT_NAME(WLC_E_DISASSOC_IND), ++ BCMEVENT_NAME(WLC_E_QUIET_START), ++ BCMEVENT_NAME(WLC_E_QUIET_END), ++ BCMEVENT_NAME(WLC_E_BEACON_RX), ++ BCMEVENT_NAME(WLC_E_LINK), ++ BCMEVENT_NAME(WLC_E_MIC_ERROR), ++ BCMEVENT_NAME(WLC_E_NDIS_LINK), ++ BCMEVENT_NAME(WLC_E_ROAM), ++ BCMEVENT_NAME(WLC_E_TXFAIL), ++ BCMEVENT_NAME(WLC_E_PMKID_CACHE), ++ BCMEVENT_NAME(WLC_E_RETROGRADE_TSF), ++ BCMEVENT_NAME(WLC_E_PRUNE), ++ BCMEVENT_NAME(WLC_E_AUTOAUTH), ++ BCMEVENT_NAME(WLC_E_EAPOL_MSG), ++ BCMEVENT_NAME(WLC_E_SCAN_COMPLETE), ++ BCMEVENT_NAME(WLC_E_ADDTS_IND), ++ BCMEVENT_NAME(WLC_E_DELTS_IND), ++ BCMEVENT_NAME(WLC_E_BCNSENT_IND), ++ BCMEVENT_NAME(WLC_E_BCNRX_MSG), ++ BCMEVENT_NAME(WLC_E_BCNLOST_MSG), ++ BCMEVENT_NAME(WLC_E_ROAM_PREP), ++ BCMEVENT_NAME(WLC_E_PFN_NET_FOUND), ++ BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE), ++ BCMEVENT_NAME(WLC_E_PFN_NET_LOST), ++ BCMEVENT_NAME(WLC_E_JOIN_START), ++ BCMEVENT_NAME(WLC_E_ROAM_START), ++ BCMEVENT_NAME(WLC_E_ASSOC_START), ++#if defined(IBSS_PEER_DISCOVERY_EVENT) ++ BCMEVENT_NAME(WLC_E_IBSS_ASSOC), ++#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */ ++ BCMEVENT_NAME(WLC_E_RADIO), ++ BCMEVENT_NAME(WLC_E_PSM_WATCHDOG), ++ BCMEVENT_NAME(WLC_E_PROBREQ_MSG), ++ BCMEVENT_NAME(WLC_E_SCAN_CONFIRM_IND), ++ BCMEVENT_NAME(WLC_E_PSK_SUP), ++ BCMEVENT_NAME(WLC_E_COUNTRY_CODE_CHANGED), ++ BCMEVENT_NAME(WLC_E_EXCEEDED_MEDIUM_TIME), ++ BCMEVENT_NAME(WLC_E_ICV_ERROR), ++ BCMEVENT_NAME(WLC_E_UNICAST_DECODE_ERROR), ++ BCMEVENT_NAME(WLC_E_MULTICAST_DECODE_ERROR), ++ BCMEVENT_NAME(WLC_E_TRACE), ++ BCMEVENT_NAME(WLC_E_IF), ++#ifdef WLP2P ++ BCMEVENT_NAME(WLC_E_P2P_DISC_LISTEN_COMPLETE), ++#endif ++ BCMEVENT_NAME(WLC_E_RSSI), ++ BCMEVENT_NAME(WLC_E_PFN_SCAN_COMPLETE), ++ BCMEVENT_NAME(WLC_E_EXTLOG_MSG), ++ BCMEVENT_NAME(WLC_E_ACTION_FRAME), ++ BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX), ++ BCMEVENT_NAME(WLC_E_ACTION_FRAME_COMPLETE), ++#ifdef BCMWAPI_WAI ++ BCMEVENT_NAME(WLC_E_WAI_STA_EVENT), ++ BCMEVENT_NAME(WLC_E_WAI_MSG), ++#endif /* BCMWAPI_WAI */ ++ BCMEVENT_NAME(WLC_E_ESCAN_RESULT), ++ BCMEVENT_NAME(WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE), ++#ifdef WLP2P ++ BCMEVENT_NAME(WLC_E_PROBRESP_MSG), ++ BCMEVENT_NAME(WLC_E_P2P_PROBREQ_MSG), ++#endif ++#ifdef PROP_TXSTATUS ++ BCMEVENT_NAME(WLC_E_FIFO_CREDIT_MAP), ++#endif ++ BCMEVENT_NAME(WLC_E_WAKE_EVENT), ++ BCMEVENT_NAME(WLC_E_DCS_REQUEST), ++ BCMEVENT_NAME(WLC_E_RM_COMPLETE), ++#ifdef WLMEDIA_HTSF ++ BCMEVENT_NAME(WLC_E_HTSFSYNC), ++#endif ++ BCMEVENT_NAME(WLC_E_OVERLAY_REQ), ++ BCMEVENT_NAME(WLC_E_CSA_COMPLETE_IND), ++ BCMEVENT_NAME(WLC_E_EXCESS_PM_WAKE_EVENT), ++ BCMEVENT_NAME(WLC_E_PFN_SCAN_NONE), ++ BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE), ++#ifdef SOFTAP ++ BCMEVENT_NAME(WLC_E_GTK_PLUMBED), ++#endif ++ BCMEVENT_NAME(WLC_E_ASSOC_REQ_IE), ++ BCMEVENT_NAME(WLC_E_ASSOC_RESP_IE), ++ BCMEVENT_NAME(WLC_E_BEACON_FRAME_RX), ++#ifdef WLTDLS ++ BCMEVENT_NAME(WLC_E_TDLS_PEER_EVENT), ++#endif /* WLTDLS */ ++ BCMEVENT_NAME(WLC_E_NATIVE), ++#ifdef WLPKTDLYSTAT ++ BCMEVENT_NAME(WLC_E_PKTDELAY_IND), ++#endif /* WLPKTDLYSTAT */ ++ BCMEVENT_NAME(WLC_E_SERVICE_FOUND), ++ BCMEVENT_NAME(WLC_E_GAS_FRAGMENT_RX), ++ BCMEVENT_NAME(WLC_E_GAS_COMPLETE), ++ BCMEVENT_NAME(WLC_E_P2PO_ADD_DEVICE), ++ BCMEVENT_NAME(WLC_E_P2PO_DEL_DEVICE), ++#ifdef WLWNM ++ BCMEVENT_NAME(WLC_E_WNM_STA_SLEEP), ++#endif /* WLWNM */ ++#if defined(WL_PROXDETECT) ++ BCMEVENT_NAME(WLC_E_PROXD), ++#endif ++ BCMEVENT_NAME(WLC_E_CCA_CHAN_QUAL), ++ BCMEVENT_NAME(WLC_E_BSSID), ++#ifdef PROP_TXSTATUS ++ BCMEVENT_NAME(WLC_E_BCMC_CREDIT_SUPPORT), ++#endif ++ BCMEVENT_NAME(WLC_E_PSTA_PRIMARY_INTF_IND), ++ BCMEVENT_NAME(WLC_E_TXFAIL_THRESH), ++#ifdef GSCAN_SUPPORT ++ BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT), ++ BCMEVENT_NAME(WLC_E_PFN_SSID_EXT), ++#endif /* GSCAN_SUPPORT */ ++#ifdef WLBSSLOAD_REPORT ++ BCMEVENT_NAME(WLC_E_BSS_LOAD), ++#endif ++#if defined(BT_WIFI_HANDOVER) || defined(WL_TBOW) ++ BCMEVENT_NAME(WLC_E_BT_WIFI_HANDOVER_REQ), ++#endif ++#ifdef WLFBT ++ BCMEVENT_NAME(WLC_E_FBT_AUTH_REQ_IND), ++#endif /* WLFBT */ ++ BCMEVENT_NAME(WLC_E_AUTHORIZED), ++ BCMEVENT_NAME(WLC_E_PROBREQ_MSG_RX), ++ BCMEVENT_NAME(WLC_E_CSA_START_IND), ++ BCMEVENT_NAME(WLC_E_CSA_DONE_IND), ++ BCMEVENT_NAME(WLC_E_CSA_FAILURE_IND), ++ BCMEVENT_NAME(WLC_E_RMC_EVENT), ++ BCMEVENT_NAME(WLC_E_DPSTA_INTF_IND), ++ BCMEVENT_NAME(WLC_E_ALLOW_CREDIT_BORROW), ++ BCMEVENT_NAME(WLC_E_MSCH), ++ BCMEVENT_NAME(WLC_E_ULP), ++ BCMEVENT_NAME(WLC_E_PSK_AUTH), ++ BCMEVENT_NAME(WLC_E_SDB_TRANSITION), ++}; ++ ++ ++const char *bcmevent_get_name(uint event_type) ++{ ++ /* note: first coded this as a static const but some ++ * ROMs already have something called event_name so ++ * changed it so we don't have a variable for the ++ * 'unknown string ++ */ ++ const char *event_name = NULL; ++ ++ uint idx; ++ for (idx = 0; idx < (uint)ARRAYSIZE(bcmevent_names); idx++) { ++ ++ if (bcmevent_names[idx].event == event_type) { ++ event_name = bcmevent_names[idx].name; ++ break; ++ } ++ } ++ ++ /* if we find an event name in the array, return it. ++ * otherwise return unknown string. ++ */ ++ return ((event_name) ? event_name : "Unknown Event"); ++} ++ ++void ++wl_event_to_host_order(wl_event_msg_t * evt) ++{ ++ /* Event struct members passed from dongle to host are stored in network ++ * byte order. Convert all members to host-order. ++ */ ++ evt->event_type = ntoh32(evt->event_type); ++ evt->flags = ntoh16(evt->flags); ++ evt->status = ntoh32(evt->status); ++ evt->reason = ntoh32(evt->reason); ++ evt->auth_type = ntoh32(evt->auth_type); ++ evt->datalen = ntoh32(evt->datalen); ++ evt->version = ntoh16(evt->version); ++} ++ ++void ++wl_event_to_network_order(wl_event_msg_t * evt) ++{ ++ /* Event struct members passed from dongle to host are stored in network ++ * byte order. Convert all members to host-order. ++ */ ++ evt->event_type = hton32(evt->event_type); ++ evt->flags = hton16(evt->flags); ++ evt->status = hton32(evt->status); ++ evt->reason = hton32(evt->reason); ++ evt->auth_type = hton32(evt->auth_type); ++ evt->datalen = hton32(evt->datalen); ++ evt->version = hton16(evt->version); ++} ++ ++/* ++ * Validate if the event is proper and if valid copy event header to event. ++ * If proper event pointer is passed, to just validate, pass NULL to event. ++ * ++ * Return values are ++ * BCME_OK - It is a BRCM event or BRCM dongle event ++ * BCME_NOTFOUND - Not BRCM, not an event, may be okay ++ * BCME_BADLEN - Bad length, should not process, just drop ++ */ ++int ++is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, ++ bcm_event_msg_u_t *out_event) ++{ ++ uint16 evlen = 0; /* length in bcmeth_hdr */ ++ uint16 subtype; ++ uint16 usr_subtype; ++ bcm_event_t *bcm_event; ++ uint8 *pktend; ++ uint8 *evend; ++ int err = BCME_OK; ++ uint32 data_len = 0; /* data length in bcm_event */ ++ ++ pktend = (uint8 *)pktdata + pktlen; ++ bcm_event = (bcm_event_t *)pktdata; ++ ++ /* only care about 16-bit subtype / length versions */ ++ if ((uint8 *)&bcm_event->bcm_hdr < pktend) { ++ uint8 short_subtype = *(uint8 *)&bcm_event->bcm_hdr; ++ if (!(short_subtype & 0x80)) { ++ err = BCME_NOTFOUND; ++ goto done; ++ } ++ } ++ ++ /* must have both ether_header and bcmeth_hdr */ ++ if (pktlen < OFFSETOF(bcm_event_t, event)) { ++ err = BCME_BADLEN; ++ goto done; ++ } ++ ++ /* check length in bcmeth_hdr */ ++ ++ /* temporary - header length not always set properly. When the below ++ * !BCMDONGLEHOST is in all branches that use trunk DHD, the code ++ * under BCMDONGLEHOST can be removed. ++ */ ++ evlen = (uint16)(pktend - (uint8 *)&bcm_event->bcm_hdr.version); ++ evend = (uint8 *)&bcm_event->bcm_hdr.version + evlen; ++ if (evend != pktend) { ++ err = BCME_BADLEN; ++ goto done; ++ } ++ ++ /* match on subtype, oui and usr subtype for BRCM events */ ++ subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.subtype); ++ if (subtype != BCMILCP_SUBTYPE_VENDOR_LONG) { ++ err = BCME_NOTFOUND; ++ goto done; ++ } ++ ++ if (bcmp(BRCM_OUI, &bcm_event->bcm_hdr.oui[0], DOT11_OUI_LEN)) { ++ err = BCME_NOTFOUND; ++ goto done; ++ } ++ ++ /* if it is a bcm_event or bcm_dngl_event_t, validate it */ ++ usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype); ++ switch (usr_subtype) { ++ case BCMILCP_BCM_SUBTYPE_EVENT: ++ /* check that header length and pkt length are sufficient */ ++ if ((pktlen < sizeof(bcm_event_t)) || ++ (evend < ((uint8 *)bcm_event + sizeof(bcm_event_t)))) { ++ err = BCME_BADLEN; ++ goto done; ++ } ++ ++ /* ensure data length in event is not beyond the packet. */ ++ data_len = ntoh32_ua((void *)&bcm_event->event.datalen); ++ if ((sizeof(bcm_event_t) + data_len + ++ BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD) != pktlen) { ++ err = BCME_BADLEN; ++ goto done; ++ } ++ ++ if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) { ++ err = BCME_NOTFOUND; ++ goto done; ++ } ++ ++ if (out_event) { ++ /* ensure BRCM event pkt aligned */ ++ memcpy(&out_event->event, &bcm_event->event, sizeof(wl_event_msg_t)); ++ } ++ ++ break; ++ ++ case BCMILCP_BCM_SUBTYPE_DNGLEVENT: ++#if defined(DNGL_EVENT_SUPPORT) ++ if ((pktlen < sizeof(bcm_dngl_event_t)) || ++ (evend < ((uint8 *)bcm_event + sizeof(bcm_dngl_event_t)))) { ++ err = BCME_BADLEN; ++ goto done; ++ } ++ ++ /* ensure data length in event is not beyond the packet. */ ++ data_len = ntoh16_ua((void *)&((bcm_dngl_event_t *)pktdata)->dngl_event.datalen); ++ if ((sizeof(bcm_dngl_event_t) + data_len + ++ BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD) != pktlen) { ++ err = BCME_BADLEN; ++ goto done; ++ } ++ ++ if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) { ++ err = BCME_NOTFOUND; ++ goto done; ++ } ++ ++ if (out_event) { ++ /* ensure BRCM dngl event pkt aligned */ ++ memcpy(&out_event->dngl_event, &((bcm_dngl_event_t *)pktdata)->dngl_event, ++ sizeof(bcm_dngl_event_msg_t)); ++ } ++ ++ break; ++#else ++ err = BCME_UNSUPPORTED; ++ break; ++#endif ++ ++ default: ++ err = BCME_NOTFOUND; ++ goto done; ++ } ++ ++ BCM_REFERENCE(data_len); ++done: ++ return err; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh.c b/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh.c +new file mode 100644 +index 000000000..a4144efe3 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh.c +@@ -0,0 +1,847 @@ ++/* ++ * BCMSDH interface glue ++ * implement bcmsdh API for SDIOH driver ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdh.c 671319 2016-11-21 14:27:29Z $ ++ */ ++ ++/** ++ * @file bcmsdh.c ++ */ ++ ++/* ****************** BCMSDH Interface Functions *************************** */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include /* BRCM API for SDIO clients (such as wl, dhd) */ ++#include /* common SDIO/controller interface */ ++#include /* SDIO device core hardware definitions. */ ++#include /* SDIO Device and Protocol Specs */ ++ ++#if defined(BT_OVER_SDIO) ++#include ++#endif /* defined (BT_OVER_SDIO) */ ++ ++#define SDIOH_API_ACCESS_RETRY_LIMIT 2 ++const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; ++ ++/* local copy of bcm sd handler */ ++bcmsdh_info_t * l_bcmsdh = NULL; ++ ++#if defined(BT_OVER_SDIO) ++struct sdio_func *func_f3 = NULL; ++static f3intr_handler processf3intr = NULL; ++static dhd_hang_notification process_dhd_hang_notification = NULL; ++static dhd_hang_state_t g_dhd_hang_state = NO_HANG_STATE; ++#endif /* defined (BT_OVER_SDIO) */ ++ ++ ++#if defined(OOB_INTR_ONLY) && defined(HW_OOB) || defined(FORCE_WOWLAN) ++extern int ++sdioh_enable_hw_oob_intr(void *sdioh, bool enable); ++ ++void ++bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) ++{ ++ sdioh_enable_hw_oob_intr(sdh->sdioh, enable); ++} ++#endif ++ ++#if defined(BT_OVER_SDIO) ++void bcmsdh_btsdio_process_hang_state(dhd_hang_state_t new_state) ++{ ++ bool state_change = false; ++ ++ BCMSDH_ERROR(("%s: DHD hang state changed - [%d] -> [%d]\n", ++ __FUNCTION__, g_dhd_hang_state, new_state)); ++ ++ if (g_dhd_hang_state == new_state) ++ return; ++ ++ switch (g_dhd_hang_state) { ++ case NO_HANG_STATE: ++ if (HANG_START_STATE == new_state) ++ state_change = true; ++ break; ++ ++ case HANG_START_STATE: ++ if (HANG_RECOVERY_STATE == new_state || ++ NO_HANG_STATE == new_state) ++ state_change = true; ++ break; ++ ++ case HANG_RECOVERY_STATE: ++ if (NO_HANG_STATE == new_state) ++ state_change = true; ++ break; ++ ++ default: ++ BCMSDH_ERROR(("%s: Unhandled Hang state\n", __FUNCTION__)); ++ break; ++ } ++ ++ if (!state_change) { ++ BCMSDH_ERROR(("%s: Hang state cannot be changed\n", __FUNCTION__)); ++ return; ++ } ++ ++ g_dhd_hang_state = new_state; ++} ++ ++void bcmsdh_btsdio_process_f3_intr(void) ++{ ++ if (processf3intr && (g_dhd_hang_state == NO_HANG_STATE)) ++ processf3intr(func_f3); ++} ++ ++void bcmsdh_btsdio_process_dhd_hang_notification(bool wifi_recovery_completed) ++{ ++ bcmsdh_btsdio_process_hang_state(HANG_START_STATE); ++ ++ if (process_dhd_hang_notification) ++ process_dhd_hang_notification(func_f3, wifi_recovery_completed); ++ ++ /* WiFi was off, so HANG_RECOVERY_STATE is not needed */ ++ if (wifi_recovery_completed) ++ bcmsdh_btsdio_process_hang_state(NO_HANG_STATE); ++ else { ++ bcmsdh_btsdio_process_hang_state(HANG_RECOVERY_STATE); ++ } ++} ++ ++void bcmsdh_btsdio_interface_init(struct sdio_func *func, ++ f3intr_handler f3intr_fun, dhd_hang_notification hang_notification) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)l_bcmsdh; ++ BCMSDH_INFO(("%s: func %p \n", __FUNCTION__, func)); ++ func_f3 = func; ++ processf3intr = f3intr_fun; ++ sdioh_sdmmc_card_enable_func_f3(bcmsdh->sdioh, func); ++ process_dhd_hang_notification = hang_notification; ++ ++} EXPORT_SYMBOL(bcmsdh_btsdio_interface_init); ++#endif /* defined (BT_OVER_SDIO) */ ++ ++/* Attach BCMSDH layer to SDIO Host Controller Driver ++ * ++ * @param osh OSL Handle. ++ * @param cfghdl Configuration Handle. ++ * @param regsva Virtual address of controller registers. ++ * @param irq Interrupt number of SDIO controller. ++ * ++ * @return bcmsdh_info_t Handle to BCMSDH context. ++ */ ++bcmsdh_info_t * ++bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva) ++{ ++ bcmsdh_info_t *bcmsdh; ++ ++ if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) { ++ BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); ++ return NULL; ++ } ++ bzero((char *)bcmsdh, sizeof(bcmsdh_info_t)); ++ bcmsdh->sdioh = sdioh; ++ bcmsdh->osh = osh; ++ bcmsdh->init_success = TRUE; ++ *regsva = SI_ENUM_BASE; ++ ++ bcmsdh_force_sbwad_calc(bcmsdh, FALSE); ++ ++ /* Report the BAR, to fix if needed */ ++ bcmsdh->sbwad = SI_ENUM_BASE; ++ ++ /* save the handler locally */ ++ l_bcmsdh = bcmsdh; ++ ++ return bcmsdh; ++} ++ ++int ++bcmsdh_detach(osl_t *osh, void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (bcmsdh != NULL) { ++ MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t)); ++ } ++ ++ l_bcmsdh = NULL; ++ ++ return 0; ++} ++ ++int ++bcmsdh_iovar_op(void *sdh, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set); ++} ++ ++bool ++bcmsdh_intr_query(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ bool on; ++ ++ ASSERT(bcmsdh); ++ status = sdioh_interrupt_query(bcmsdh->sdioh, &on); ++ if (SDIOH_API_SUCCESS(status)) ++ return FALSE; ++ else ++ return on; ++} ++ ++int ++bcmsdh_intr_enable(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_intr_disable(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_intr_dereg(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh); ++ ++ status = sdioh_interrupt_deregister(bcmsdh->sdioh); ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++#if defined(DHD_DEBUG) ++bool ++bcmsdh_intr_pending(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ ASSERT(sdh); ++ return sdioh_interrupt_pending(bcmsdh->sdioh); ++} ++#endif ++ ++ ++int ++bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh) ++{ ++ ASSERT(sdh); ++ ++ /* don't support yet */ ++ return BCME_UNSUPPORTED; ++} ++ ++/** ++ * Read from SDIO Configuration Space ++ * @param sdh SDIO Host context. ++ * @param func_num Function number to read from. ++ * @param addr Address to read from. ++ * @param err Error return. ++ * @return value read from SDIO configuration space. ++ */ ++uint8 ++bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ int32 retry = 0; ++#endif ++ uint8 data = 0; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ do { ++ if (retry) /* wait for 1 ms till bus get settled down */ ++ OSL_DELAY(1000); ++#endif ++ status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); ++#endif ++ if (err) ++ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, ++ fnc_num, addr, data)); ++ ++ return data; ++} EXPORT_SYMBOL(bcmsdh_cfg_read); ++ ++void ++bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ int32 retry = 0; ++#endif ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ do { ++ if (retry) /* wait for 1 ms till bus get settled down */ ++ OSL_DELAY(1000); ++#endif ++ status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data); ++#ifdef SDIOH_API_ACCESS_RETRY_LIMIT ++ } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); ++#endif ++ if (err) ++ *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR; ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__, ++ fnc_num, addr, data)); ++} EXPORT_SYMBOL(bcmsdh_cfg_write); ++ ++uint32 ++bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint32 data = 0; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num, ++ addr, &data, 4); ++ ++ if (err) ++ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, ++ fnc_num, addr, data)); ++ ++ return data; ++} ++ ++void ++bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num, ++ addr, &data, 4); ++ ++ if (err) ++ *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num, ++ addr, data)); ++} ++ ++ ++int ++bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ uint8 *tmp_buf, *tmp_ptr; ++ uint8 *ptr; ++ bool ascii = func & ~0xf; ++ func &= 0x7; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ASSERT(cis); ++ ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT); ++ ++ status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length); ++ ++ if (ascii) { ++ /* Move binary bits to tmp and format them into the provided buffer. */ ++ if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) { ++ BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__)); ++ return BCME_NOMEM; ++ } ++ bcopy(cis, tmp_buf, length); ++ for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) { ++ ptr += snprintf((char*)ptr, (cis + length - ptr - 4), ++ "%.2x ", *tmp_ptr & 0xff); ++ if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0) ++ ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n"); ++ } ++ MFREE(bcmsdh->osh, tmp_buf, length); ++ } ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_cisaddr_read(void *sdh, uint func, uint8 *cisd, uint32 offset) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ func &= 0x7; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ASSERT(cisd); ++ ++ status = sdioh_cisaddr_read(bcmsdh->sdioh, func, cisd, offset); ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++ ++int ++bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set) ++{ ++ int err = 0; ++ uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK; ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (bar0 != bcmsdh->sbwad || force_set) { ++ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, ++ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, ++ (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, ++ (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); ++ ++ if (!err) ++ bcmsdh->sbwad = bar0; ++ else ++ /* invalidate cached window var */ ++ bcmsdh->sbwad = 0; ++ ++ } ++ ++ return err; ++} ++ ++uint32 ++bcmsdh_reg_read(void *sdh, uintptr addr, uint size) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint32 word = 0; ++ ++ BCMSDH_INFO(("%s:fun = 1, addr = 0x%x\n", __FUNCTION__, (unsigned int)addr)); ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)) { ++ bcmsdh->regfail = TRUE; // terence 20130621: prevent dhd_dpc in dead lock ++ return 0xFFFFFFFF; ++ } ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ if (size == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, ++ SDIOH_READ, SDIO_FUNC_1, addr, &word, size); ++ ++ bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); ++ ++ BCMSDH_INFO(("uint32data = 0x%x\n", word)); ++ ++ /* if ok, return appropriately masked word */ ++ if (SDIOH_API_SUCCESS(status)) { ++ switch (size) { ++ case sizeof(uint8): ++ return (word & 0xff); ++ case sizeof(uint16): ++ return (word & 0xffff); ++ case sizeof(uint32): ++ return word; ++ default: ++ bcmsdh->regfail = TRUE; ++ ++ } ++ } ++ ++ /* otherwise, bad sdio access or invalid size */ ++ BCMSDH_ERROR(("%s: error reading addr 0x%x size %d\n", ++ __FUNCTION__, (unsigned int)addr, size)); ++ return 0xFFFFFFFF; ++} ++ ++uint32 ++bcmsdh_reg_write(void *sdh, uintptr addr, uint size, uint32 data) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ int err = 0; ++ ++ BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", ++ __FUNCTION__, (unsigned int)addr, size*8, data)); ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ ASSERT(bcmsdh->init_success); ++ ++ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, bcmsdh->force_sbwad_calc))) { ++ bcmsdh->regfail = TRUE; // terence 20130621: ++ return err; ++ } ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ if (size == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1, ++ addr, &data, size); ++ bcmsdh->regfail = !(SDIOH_API_SUCCESS(status)); ++ ++ if (SDIOH_API_SUCCESS(status)) ++ return 0; ++ ++ BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n", ++ __FUNCTION__, data, (unsigned int)addr, size)); ++ return 0xFFFFFFFF; ++} ++ ++bool ++bcmsdh_regfail(void *sdh) ++{ ++ return ((bcmsdh_info_t *)sdh)->regfail; ++} ++ ++int ++bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint incr_fix; ++ uint width; ++ int err = 0; ++ ++ ASSERT(bcmsdh); ++ ASSERT(bcmsdh->init_success); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", ++ __FUNCTION__, fn, addr, nbytes)); ++ ++ /* Async not implemented yet */ ++ ASSERT(!(flags & SDIO_REQ_ASYNC)); ++ if (flags & SDIO_REQ_ASYNC) ++ return BCME_UNSUPPORTED; ++ ++ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) ++ return err; ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ ++ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; ++ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; ++ if (width == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, ++ SDIOH_READ, fn, addr, width, nbytes, buf, pkt); ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR); ++} ++ ++int ++bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ uint incr_fix; ++ uint width; ++ int err = 0; ++ ++ ASSERT(bcmsdh); ++ ASSERT(bcmsdh->init_success); ++ ++ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n", ++ __FUNCTION__, fn, addr, nbytes)); ++ ++ /* Async not implemented yet */ ++ ASSERT(!(flags & SDIO_REQ_ASYNC)); ++ if (flags & SDIO_REQ_ASYNC) ++ return BCME_UNSUPPORTED; ++ ++ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))) ++ return err; ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ ++ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; ++ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; ++ if (width == 4) ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix, ++ SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt); ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ SDIOH_API_RC status; ++ ++ ASSERT(bcmsdh); ++ ASSERT(bcmsdh->init_success); ++ ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0); ++ ++ addr &= SBSDIO_SB_OFT_ADDR_MASK; ++ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; ++ ++ status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC, ++ (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, ++ addr, 4, nbytes, buf, NULL); ++ ++ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR); ++} ++ ++int ++bcmsdh_abort(void *sdh, uint fn) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_abort(bcmsdh->sdioh, fn); ++} ++ ++int ++bcmsdh_start(void *sdh, int stage) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_start(bcmsdh->sdioh, stage); ++} ++ ++int ++bcmsdh_stop(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_stop(bcmsdh->sdioh); ++} ++ ++int ++bcmsdh_waitlockfree(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_waitlockfree(bcmsdh->sdioh); ++} ++ ++int ++bcmsdh_query_device(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0; ++ return (bcmsdh->vendevid); ++} ++ ++uint ++bcmsdh_query_iofnum(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ return (sdioh_query_iofnum(bcmsdh->sdioh)); ++} ++ ++int ++bcmsdh_reset(bcmsdh_info_t *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ return sdioh_sdio_reset(bcmsdh->sdioh); ++} ++ ++void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh) ++{ ++ ASSERT(sdh); ++ return sdh->sdioh; ++} ++ ++/* Function to pass device-status bits to DHD. */ ++uint32 ++bcmsdh_get_dstatus(void *sdh) ++{ ++ return 0; ++} ++uint32 ++bcmsdh_cur_sbwad(void *sdh) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ ++ return (bcmsdh->sbwad); ++} ++ ++/* example usage: if force is TRUE, forces the bcmsdhsdio_set_sbaddr_window to ++ * calculate sbwad always instead of caching. ++ */ ++void ++bcmsdh_force_sbwad_calc(void *sdh, bool force) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ ++ if (!bcmsdh) ++ bcmsdh = l_bcmsdh; ++ bcmsdh->force_sbwad_calc = force; ++} ++ ++void ++bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev) ++{ ++ return; ++} ++ ++ ++int ++bcmsdh_sleep(void *sdh, bool enab) ++{ ++#ifdef SDIOH_SLEEP_ENABLED ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_sleep(sd, enab); ++#else ++ return BCME_UNSUPPORTED; ++#endif ++} ++ ++int ++bcmsdh_gpio_init(void *sdh) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpio_init(sd); ++} ++ ++bool ++bcmsdh_gpioin(void *sdh, uint32 gpio) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpioin(sd, gpio); ++} ++ ++int ++bcmsdh_gpioouten(void *sdh, uint32 gpio) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpioouten(sd, gpio); ++} ++ ++int ++bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab) ++{ ++ bcmsdh_info_t *p = (bcmsdh_info_t *)sdh; ++ sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh); ++ ++ return sdioh_gpioout(sd, gpio, enab); ++} ++ ++uint ++bcmsdh_set_mode(void *sdh, uint mode) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; ++ return (sdioh_set_mode(bcmsdh->sdioh, mode)); ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +new file mode 100644 +index 000000000..fd6b757cd +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +@@ -0,0 +1,517 @@ ++/* ++ * SDIO access interface for drivers - linux specific (pci only) ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdh_linux.c 672609 2016-11-29 07:00:46Z $ ++ */ ++ ++/** ++ * @file bcmsdh_linux.c ++ */ ++ ++#define __UNDEF_NO_VERSION__ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++extern void dhdsdio_isr(void * args); ++#include ++#include ++#include ++#if defined(CONFIG_ARCH_ODIN) ++#include ++#endif /* defined(CONFIG_ARCH_ODIN) */ ++#include ++ ++/* driver info, initialized when bcmsdh_register is called */ ++static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL}; ++ ++typedef enum { ++ DHD_INTR_INVALID = 0, ++ DHD_INTR_INBAND, ++ DHD_INTR_HWOOB, ++ DHD_INTR_SWOOB ++} DHD_HOST_INTR_TYPE; ++ ++/* the BCMSDH module comprises the generic part (bcmsdh.c) and OS specific layer (e.g. ++ * bcmsdh_linux.c). Put all OS specific variables (e.g. irq number and flags) here rather ++ * than in the common structure bcmsdh_info. bcmsdh_info only keeps a handle (os_ctx) to this ++ * structure. ++ */ ++typedef struct bcmsdh_os_info { ++ DHD_HOST_INTR_TYPE intr_type; ++ int oob_irq_num; /* valid when hardware or software oob in use */ ++ unsigned long oob_irq_flags; /* valid when hardware or software oob in use */ ++ bool oob_irq_registered; ++ bool oob_irq_enabled; ++ bool oob_irq_wake_enabled; ++ spinlock_t oob_irq_spinlock; ++ bcmsdh_cb_fn_t oob_irq_handler; ++ void *oob_irq_handler_context; ++ void *context; /* context returned from upper layer */ ++ void *sdioh; /* handle to lower layer (sdioh) */ ++ void *dev; /* handle to the underlying device */ ++ bool dev_wake_enabled; ++} bcmsdh_os_info_t; ++ ++/* debugging macros */ ++#define SDLX_ERR(x) printf x ++#define SDLX_MSG(x) printf x ++ ++/** ++ * Checks to see if vendor and device IDs match a supported SDIO Host Controller. ++ */ ++bool ++bcmsdh_chipmatch(uint16 vendor, uint16 device) ++{ ++ /* Add other vendors and devices as required */ ++ ++#ifdef BCMSDIOH_STD ++ /* Check for Arasan host controller */ ++ if (vendor == VENDOR_SI_IMAGE) { ++ return (TRUE); ++ } ++ /* Check for BRCM 27XX Standard host controller */ ++ if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) { ++ return (TRUE); ++ } ++ /* Check for BRCM Standard host controller */ ++ if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) { ++ return (TRUE); ++ } ++ /* Check for TI PCIxx21 Standard host controller */ ++ if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) { ++ return (TRUE); ++ } ++ if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) { ++ return (TRUE); ++ } ++ /* Ricoh R5C822 Standard SDIO Host */ ++ if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) { ++ return (TRUE); ++ } ++ /* JMicron Standard SDIO Host */ ++ if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) { ++ return (TRUE); ++ } ++ ++#endif /* BCMSDIOH_STD */ ++#ifdef BCMSDIOH_SPI ++ /* This is the PciSpiHost. */ ++ if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) { ++ printf("Found PCI SPI Host Controller\n"); ++ return (TRUE); ++ } ++ ++#endif /* BCMSDIOH_SPI */ ++ ++ return (FALSE); ++} ++ ++void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type, ++ uint bus_num, uint slot_num) ++{ ++ ulong regs; ++ bcmsdh_info_t *bcmsdh; ++ uint32 vendevid; ++ bcmsdh_os_info_t *bcmsdh_osinfo = NULL; ++ ++ bcmsdh = bcmsdh_attach(osh, sdioh, ®s); ++ if (bcmsdh == NULL) { ++ SDLX_ERR(("%s: bcmsdh_attach failed\n", __FUNCTION__)); ++ goto err; ++ } ++ bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t)); ++ if (bcmsdh_osinfo == NULL) { ++ SDLX_ERR(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__)); ++ goto err; ++ } ++ bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t)); ++ bcmsdh->os_cxt = bcmsdh_osinfo; ++ bcmsdh_osinfo->sdioh = sdioh; ++ bcmsdh_osinfo->dev = dev; ++ osl_set_bus_handle(osh, bcmsdh); ++ ++#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ if (dev && device_init_wakeup(dev, true) == 0) ++ bcmsdh_osinfo->dev_wake_enabled = TRUE; ++#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ ++ ++#if defined(OOB_INTR_ONLY) ++ spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock); ++ /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */ ++ bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info, ++ &bcmsdh_osinfo->oob_irq_flags); ++ if (bcmsdh_osinfo->oob_irq_num < 0) { ++ SDLX_ERR(("%s: Host OOB irq is not defined\n", __FUNCTION__)); ++ goto err; ++ } ++#endif /* defined(BCMLXSDMMC) */ ++ ++ /* Read the vendor/device ID from the CIS */ ++ vendevid = bcmsdh_query_device(bcmsdh); ++ /* try to attach to the target device */ ++ bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num, ++ slot_num, 0, bus_type, (void *)regs, osh, bcmsdh); ++ if (bcmsdh_osinfo->context == NULL) { ++ SDLX_ERR(("%s: device attach failed\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ return bcmsdh; ++ ++ /* error handling */ ++err: ++ if (bcmsdh != NULL) ++ bcmsdh_detach(osh, bcmsdh); ++ if (bcmsdh_osinfo != NULL) ++ MFREE(osh, bcmsdh_osinfo, sizeof(bcmsdh_os_info_t)); ++ return NULL; ++} ++ ++int bcmsdh_remove(bcmsdh_info_t *bcmsdh) ++{ ++ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; ++ ++#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ if (bcmsdh_osinfo->dev) ++ device_init_wakeup(bcmsdh_osinfo->dev, false); ++ bcmsdh_osinfo->dev_wake_enabled = FALSE; ++#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ ++ ++ drvinfo.remove(bcmsdh_osinfo->context); ++ MFREE(bcmsdh->osh, bcmsdh->os_cxt, sizeof(bcmsdh_os_info_t)); ++ bcmsdh_detach(bcmsdh->osh, bcmsdh); ++ ++ return 0; ++} ++ ++#ifdef DHD_WAKE_STATUS ++int bcmsdh_get_total_wake(bcmsdh_info_t *bcmsdh) ++{ ++ return bcmsdh->total_wake_count; ++} ++ ++int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag) ++{ ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; ++ unsigned long flags; ++#endif ++ int ret = 0; ++ ++#if defined(OOB_INTR_ONLY) ++ spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags); ++ ++ ret = bcmsdh->pkt_wake; ++ bcmsdh->total_wake_count += flag; ++ bcmsdh->pkt_wake = flag; ++ ++ spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags); ++#endif ++ return ret; ++} ++#endif /* DHD_WAKE_STATUS */ ++ ++int bcmsdh_suspend(bcmsdh_info_t *bcmsdh) ++{ ++ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; ++ ++ if (drvinfo.suspend && drvinfo.suspend(bcmsdh_osinfo->context)) ++ return -EBUSY; ++ return 0; ++} ++ ++int bcmsdh_resume(bcmsdh_info_t *bcmsdh) ++{ ++ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; ++ ++ if (drvinfo.resume) ++ return drvinfo.resume(bcmsdh_osinfo->context); ++ return 0; ++} ++ ++extern int bcmsdh_register_client_driver(void); ++extern void bcmsdh_unregister_client_driver(void); ++extern int sdio_func_reg_notify(void* semaphore); ++extern void sdio_func_unreg_notify(void); ++ ++#if defined(BCMLXSDMMC) ++int bcmsdh_reg_sdio_notify(void* semaphore) ++{ ++ return sdio_func_reg_notify(semaphore); ++} ++ ++void bcmsdh_unreg_sdio_notify(void) ++{ ++ sdio_func_unreg_notify(); ++} ++#endif /* defined(BCMLXSDMMC) */ ++ ++int ++bcmsdh_register(bcmsdh_driver_t *driver) ++{ ++ int error = 0; ++ ++ drvinfo = *driver; ++ SDLX_MSG(("%s: register client driver\n", __FUNCTION__)); ++ error = bcmsdh_register_client_driver(); ++ if (error) ++ SDLX_ERR(("%s: failed %d\n", __FUNCTION__, error)); ++ ++ return error; ++} ++ ++void ++bcmsdh_unregister(void) ++{ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++ if (bcmsdh_pci_driver.node.next == NULL) ++ return; ++#endif ++ ++ bcmsdh_unregister_client_driver(); ++} ++ ++void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh) ++{ ++#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; ++ pm_stay_awake(bcmsdh_osinfo->dev); ++#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ ++} ++ ++void bcmsdh_dev_relax(bcmsdh_info_t *bcmsdh) ++{ ++#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; ++ pm_relax(bcmsdh_osinfo->dev); ++#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ ++} ++ ++bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh) ++{ ++ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; ++ ++ return bcmsdh_osinfo->dev_wake_enabled; ++} ++ ++#if defined(OOB_INTR_ONLY) ++void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable) ++{ ++ unsigned long flags; ++ bcmsdh_os_info_t *bcmsdh_osinfo; ++ ++ if (!bcmsdh) ++ return; ++ ++ bcmsdh_osinfo = bcmsdh->os_cxt; ++ spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags); ++ if (bcmsdh_osinfo->oob_irq_enabled != enable) { ++ if (enable) ++ enable_irq(bcmsdh_osinfo->oob_irq_num); ++ else ++ disable_irq_nosync(bcmsdh_osinfo->oob_irq_num); ++ bcmsdh_osinfo->oob_irq_enabled = enable; ++ } ++ spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags); ++} ++ ++static irqreturn_t wlan_oob_irq(int irq, void *dev_id) ++{ ++ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id; ++ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; ++ ++ bcmsdh_oob_intr_set(bcmsdh, FALSE); ++ bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context); ++ ++ return IRQ_HANDLED; ++} ++ ++int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler, ++ void* oob_irq_handler_context) ++{ ++ int err = 0; ++ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; ++ ++ if (bcmsdh_osinfo->oob_irq_registered) { ++ SDLX_ERR(("%s: irq is already registered\n", __FUNCTION__)); ++ return -EBUSY; ++ } ++#ifdef HW_OOB ++ SDLX_MSG(("%s: HW_OOB irq=%d flags=0x%X\n", __FUNCTION__, ++ (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags)); ++#else ++ SDLX_MSG(("%s: SW_OOB irq=%d flags=0x%X\n", __FUNCTION__, ++ (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags)); ++#endif ++ bcmsdh_osinfo->oob_irq_handler = oob_irq_handler; ++ bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context; ++ bcmsdh_osinfo->oob_irq_enabled = TRUE; ++ bcmsdh_osinfo->oob_irq_registered = TRUE; ++#if defined(CONFIG_ARCH_ODIN) ++ err = odin_gpio_sms_request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq, ++ bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh); ++#else ++ err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq, ++ bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh); ++#endif /* defined(CONFIG_ARCH_ODIN) */ ++ if (err) { ++ SDLX_ERR(("%s: request_irq failed with %d\n", __FUNCTION__, err)); ++ bcmsdh_osinfo->oob_irq_enabled = FALSE; ++ bcmsdh_osinfo->oob_irq_registered = FALSE; ++ return err; ++ } ++ ++#if defined(DISABLE_WOWLAN) ++ SDLX_MSG(("%s: disable_irq_wake\n", __FUNCTION__)); ++ bcmsdh_osinfo->oob_irq_wake_enabled = FALSE; ++#else ++ err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num); ++ if (err) ++ SDLX_ERR(("%s: enable_irq_wake failed with %d\n", __FUNCTION__, err)); ++ else ++ bcmsdh_osinfo->oob_irq_wake_enabled = TRUE; ++#endif ++ ++ return 0; ++} ++ ++void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh) ++{ ++ int err = 0; ++ bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; ++ ++ SDLX_MSG(("%s: Enter\n", __FUNCTION__)); ++ if (!bcmsdh_osinfo->oob_irq_registered) { ++ SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__)); ++ return; ++ } ++ if (bcmsdh_osinfo->oob_irq_wake_enabled) { ++ err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num); ++ if (!err) ++ bcmsdh_osinfo->oob_irq_wake_enabled = FALSE; ++ } ++ if (bcmsdh_osinfo->oob_irq_enabled) { ++ disable_irq(bcmsdh_osinfo->oob_irq_num); ++ bcmsdh_osinfo->oob_irq_enabled = FALSE; ++ } ++ free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh); ++ bcmsdh_osinfo->oob_irq_registered = FALSE; ++} ++#endif ++ ++/* Module parameters specific to each host-controller driver */ ++ ++extern uint sd_msglevel; /* Debug message level */ ++module_param(sd_msglevel, uint, 0); ++ ++extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */ ++module_param(sd_power, uint, 0); ++ ++extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */ ++module_param(sd_clock, uint, 0); ++ ++extern uint sd_divisor; /* Divisor (-1 means external clock) */ ++module_param(sd_divisor, uint, 0); ++ ++extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */ ++module_param(sd_sdmode, uint, 0); ++ ++extern uint sd_hiok; /* Ok to use hi-speed mode */ ++module_param(sd_hiok, uint, 0); ++ ++extern uint sd_f2_blocksize; ++module_param(sd_f2_blocksize, int, 0); ++ ++extern uint sd_f1_blocksize; ++module_param(sd_f1_blocksize, int, 0); ++ ++#ifdef BCMSDIOH_STD ++extern int sd_uhsimode; ++module_param(sd_uhsimode, int, 0); ++extern uint sd_tuning_period; ++module_param(sd_tuning_period, uint, 0); ++extern int sd_delay_value; ++module_param(sd_delay_value, uint, 0); ++ ++/* SDIO Drive Strength for UHSI mode specific to SDIO3.0 */ ++extern char dhd_sdiod_uhsi_ds_override[2]; ++module_param_string(dhd_sdiod_uhsi_ds_override, dhd_sdiod_uhsi_ds_override, 2, 0); ++ ++#endif ++ ++#ifdef BCMSDH_MODULE ++EXPORT_SYMBOL(bcmsdh_attach); ++EXPORT_SYMBOL(bcmsdh_detach); ++EXPORT_SYMBOL(bcmsdh_intr_query); ++EXPORT_SYMBOL(bcmsdh_intr_enable); ++EXPORT_SYMBOL(bcmsdh_intr_disable); ++EXPORT_SYMBOL(bcmsdh_intr_reg); ++EXPORT_SYMBOL(bcmsdh_intr_dereg); ++ ++#if defined(DHD_DEBUG) ++EXPORT_SYMBOL(bcmsdh_intr_pending); ++#endif ++ ++#if defined(BT_OVER_SDIO) ++EXPORT_SYMBOL(bcmsdh_btsdio_interface_init); ++#endif /* defined (BT_OVER_SDIO) */ ++ ++EXPORT_SYMBOL(bcmsdh_devremove_reg); ++EXPORT_SYMBOL(bcmsdh_cfg_read); ++EXPORT_SYMBOL(bcmsdh_cfg_write); ++EXPORT_SYMBOL(bcmsdh_cis_read); ++EXPORT_SYMBOL(bcmsdh_reg_read); ++EXPORT_SYMBOL(bcmsdh_reg_write); ++EXPORT_SYMBOL(bcmsdh_regfail); ++EXPORT_SYMBOL(bcmsdh_send_buf); ++EXPORT_SYMBOL(bcmsdh_recv_buf); ++ ++EXPORT_SYMBOL(bcmsdh_rwdata); ++EXPORT_SYMBOL(bcmsdh_abort); ++EXPORT_SYMBOL(bcmsdh_query_device); ++EXPORT_SYMBOL(bcmsdh_query_iofnum); ++EXPORT_SYMBOL(bcmsdh_iovar_op); ++EXPORT_SYMBOL(bcmsdh_register); ++EXPORT_SYMBOL(bcmsdh_unregister); ++EXPORT_SYMBOL(bcmsdh_chipmatch); ++EXPORT_SYMBOL(bcmsdh_reset); ++EXPORT_SYMBOL(bcmsdh_waitlockfree); ++ ++EXPORT_SYMBOL(bcmsdh_get_dstatus); ++EXPORT_SYMBOL(bcmsdh_cfg_read_word); ++EXPORT_SYMBOL(bcmsdh_cfg_write_word); ++EXPORT_SYMBOL(bcmsdh_cur_sbwad); ++EXPORT_SYMBOL(bcmsdh_chipinfo); ++ ++#endif /* BCMSDH_MODULE */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +new file mode 100644 +index 000000000..0aa5d960c +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +@@ -0,0 +1,1774 @@ ++/* ++ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdh_sdmmc.c 710913 2017-07-14 10:17:51Z $ ++ */ ++#include ++ ++#include ++#include ++#include ++#include ++#include /* SDIO Device and Protocol Specs */ ++#include /* Standard SDIO Host Controller Specification */ ++#include /* bcmsdh to/from specific controller APIs */ ++#include /* ioctl/iovars */ ++ ++#include ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 0)) ++#include ++void ++mmc_host_clk_hold(struct mmc_host *host) ++{ ++ BCM_REFERENCE(host); ++ return; ++} ++ ++void ++mmc_host_clk_release(struct mmc_host *host) ++{ ++ BCM_REFERENCE(host); ++ return; ++} ++#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 8)) ++#include ++#else ++#include ++#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 0)) */ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++#include ++extern volatile bool dhd_mmc_suspend; ++#endif ++#include "bcmsdh_sdmmc.h" ++ ++#ifndef BCMSDH_MODULE ++extern int sdio_function_init(void); ++extern void sdio_function_cleanup(void); ++#endif /* BCMSDH_MODULE */ ++ ++#if !defined(OOB_INTR_ONLY) ++static void IRQHandler(struct sdio_func *func); ++static void IRQHandlerF2(struct sdio_func *func); ++#endif /* !defined(OOB_INTR_ONLY) */ ++static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); ++#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE) ++extern int sdio_reset_comm(struct mmc_card *card); ++#endif ++#ifdef GLOBAL_SDMMC_INSTANCE ++extern PBCMSDH_SDMMC_INSTANCE gInstance; ++#endif ++ ++#define DEFAULT_SDIO_F2_BLKSIZE 512 ++#ifndef CUSTOM_SDIO_F2_BLKSIZE ++#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE ++#endif ++ ++#define DEFAULT_SDIO_F1_BLKSIZE 64 ++#ifndef CUSTOM_SDIO_F1_BLKSIZE ++#define CUSTOM_SDIO_F1_BLKSIZE DEFAULT_SDIO_F1_BLKSIZE ++#endif ++ ++#define MAX_IO_RW_EXTENDED_BLK 511 ++ ++uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ ++uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; ++uint sd_f1_blocksize = CUSTOM_SDIO_F1_BLKSIZE; ++ ++#if defined(BT_OVER_SDIO) ++uint sd_f3_blocksize = 64; ++#endif /* defined (BT_OVER_SDIO) */ ++ ++uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ ++ ++uint sd_power = 1; /* Default to SD Slot powered ON */ ++uint sd_clock = 1; /* Default to SD Clock turned ON */ ++uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ ++uint sd_msglevel = 0x01; ++uint sd_use_dma = TRUE; ++ ++#ifndef CUSTOM_RXCHAIN ++#define CUSTOM_RXCHAIN 0 ++#endif ++ ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); ++DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); ++ ++#define DMA_ALIGN_MASK 0x03 ++#define MMC_SDIO_ABORT_RETRY_LIMIT 5 ++ ++int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); ++ ++void sdmmc_set_clock_rate(sdioh_info_t *sd, uint hz); ++uint sdmmc_get_clock_rate(sdioh_info_t *sd); ++void sdmmc_set_clock_divisor(sdioh_info_t *sd, uint sd_div); ++#if defined(BT_OVER_SDIO) ++extern ++void sdioh_sdmmc_card_enable_func_f3(sdioh_info_t *sd, struct sdio_func *func) ++{ ++ sd->func[3] = func; ++ sd_info(("%s sd->func[3] %p\n", __FUNCTION__, sd->func[3])); ++} ++#endif /* defined (BT_OVER_SDIO) */ ++ ++static int ++sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) ++{ ++ int err_ret; ++ uint32 fbraddr; ++ uint8 func; ++ ++ sd_trace(("%s\n", __FUNCTION__)); ++ ++ /* Get the Card's common CIS address */ ++ sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0); ++ sd->func_cis_ptr[0] = sd->com_cis_ptr; ++ sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); ++ ++ /* Get the Card's function CIS (for each function) */ ++ for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; ++ func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { ++ sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr); ++ sd_info(("%s: Function %d CIS Ptr = 0x%x\n", ++ __FUNCTION__, 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", __FUNCTION__, sd->com_cis_ptr)); ++ ++ /* Enable Function 1 */ ++ sdio_claim_host(sd->func[1]); ++ err_ret = sdio_enable_func(sd->func[1]); ++ sdio_release_host(sd->func[1]); ++ if (err_ret) { ++ sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x\n", err_ret)); ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * Public entry points & extern's ++ */ ++extern sdioh_info_t * ++sdioh_attach(osl_t *osh, struct sdio_func *func) ++{ ++ sdioh_info_t *sd = NULL; ++ int err_ret; ++ ++ sd_trace(("%s\n", __FUNCTION__)); ++ ++ if (func == NULL) { ++ sd_err(("%s: sdio function device is NULL\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { ++ sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); ++ return NULL; ++ } ++ bzero((char *)sd, sizeof(sdioh_info_t)); ++ sd->osh = osh; ++ sd->fake_func0.num = 0; ++ sd->fake_func0.card = func->card; ++ sd->func[0] = &sd->fake_func0; ++#ifdef GLOBAL_SDMMC_INSTANCE ++ if (func->num == 2) ++ sd->func[1] = gInstance->func[1]; ++#else ++ sd->func[1] = func->card->sdio_func[0]; ++#endif ++ sd->func[2] = func->card->sdio_func[1]; ++#ifdef GLOBAL_SDMMC_INSTANCE ++ sd->func[func->num] = func; ++#endif ++ ++#if defined(BT_OVER_SDIO) ++ sd->func[3] = NULL; ++#endif /* defined (BT_OVER_SDIO) */ ++ ++ sd->num_funcs = 2; ++ sd->sd_blockmode = TRUE; ++ sd->use_client_ints = TRUE; ++ sd->client_block_size[0] = 64; ++ sd->use_rxchain = CUSTOM_RXCHAIN; ++ if (sd->func[1] == NULL || sd->func[2] == NULL) { ++ sd_err(("%s: func 1 or 2 is null \n", __FUNCTION__)); ++ goto fail; ++ } ++ sdio_set_drvdata(sd->func[1], sd); ++ ++ sdio_claim_host(sd->func[1]); ++ sd->client_block_size[1] = sd_f1_blocksize; ++ err_ret = sdio_set_block_size(sd->func[1], sd_f1_blocksize); ++ sdio_release_host(sd->func[1]); ++ if (err_ret) { ++ sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize(%d)\n", err_ret)); ++ goto fail; ++ } ++ ++ sdio_claim_host(sd->func[2]); ++ sd->client_block_size[2] = sd_f2_blocksize; ++ printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize); ++ err_ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); ++ sdio_release_host(sd->func[2]); ++ if (err_ret) { ++ sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d(%d)\n", ++ sd_f2_blocksize, err_ret)); ++ goto fail; ++ } ++ ++ sd->sd_clk_rate = sdmmc_get_clock_rate(sd); ++ printf("%s: sd clock rate = %u\n", __FUNCTION__, sd->sd_clk_rate); ++ sdioh_sdmmc_card_enablefuncs(sd); ++ ++ sd_trace(("%s: Done\n", __FUNCTION__)); ++ return sd; ++ ++fail: ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return NULL; ++} ++ ++ ++extern SDIOH_API_RC ++sdioh_detach(osl_t *osh, sdioh_info_t *sd) ++{ ++ sd_trace(("%s\n", __FUNCTION__)); ++ ++ if (sd) { ++ ++ /* Disable Function 2 */ ++ if (sd->func[2]) { ++ sdio_claim_host(sd->func[2]); ++ sdio_disable_func(sd->func[2]); ++ sdio_release_host(sd->func[2]); ++ } ++ ++ /* Disable Function 1 */ ++ if (sd->func[1]) { ++ sdio_claim_host(sd->func[1]); ++ sdio_disable_func(sd->func[1]); ++ sdio_release_host(sd->func[1]); ++ } ++ ++ sd->func[1] = NULL; ++ sd->func[2] = NULL; ++ ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ } ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++#if defined(OOB_INTR_ONLY) && defined(HW_OOB) ++ ++extern SDIOH_API_RC ++sdioh_enable_func_intr(sdioh_info_t *sd) ++{ ++ uint8 reg; ++ int err; ++ ++ if (sd->func[0] == NULL) { ++ sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ sdio_claim_host(sd->func[0]); ++ reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); ++ if (err) { ++ sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); ++ sdio_release_host(sd->func[0]); ++ return SDIOH_API_RC_FAIL; ++ } ++ /* Enable F1 and F2 interrupts, clear master enable */ ++ reg &= ~INTR_CTL_MASTER_EN; ++ reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); ++#if defined(BT_OVER_SDIO) ++ reg |= (INTR_CTL_FUNC3_EN); ++#endif /* defined (BT_OVER_SDIO) */ ++ sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); ++ sdio_release_host(sd->func[0]); ++ ++ if (err) { ++ sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_disable_func_intr(sdioh_info_t *sd) ++{ ++ uint8 reg; ++ int err; ++ ++ if (sd->func[0] == NULL) { ++ sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ sdio_claim_host(sd->func[0]); ++ reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); ++ if (err) { ++ sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); ++ sdio_release_host(sd->func[0]); ++ return SDIOH_API_RC_FAIL; ++ } ++ reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); ++#if defined(BT_OVER_SDIO) ++ reg &= ~INTR_CTL_FUNC3_EN; ++#endif ++ /* Disable master interrupt with the last function interrupt */ ++ if (!(reg & 0xFE)) ++ reg = 0; ++ sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); ++ sdio_release_host(sd->func[0]); ++ ++ if (err) { ++ sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ ++ ++/* Configure callback to client when we recieve client interrupt */ ++extern SDIOH_API_RC ++sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) ++{ ++ sd_trace(("%s: Entering\n", __FUNCTION__)); ++ if (fn == NULL) { ++ sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__)); ++ return SDIOH_API_RC_FAIL; ++ } ++#if !defined(OOB_INTR_ONLY) ++ sd->intr_handler = fn; ++ sd->intr_handler_arg = argh; ++ sd->intr_handler_valid = TRUE; ++ ++ /* register and unmask irq */ ++ if (sd->func[2]) { ++ sdio_claim_host(sd->func[2]); ++ sdio_claim_irq(sd->func[2], IRQHandlerF2); ++ sdio_release_host(sd->func[2]); ++ } ++ ++ if (sd->func[1]) { ++ sdio_claim_host(sd->func[1]); ++ sdio_claim_irq(sd->func[1], IRQHandler); ++ sdio_release_host(sd->func[1]); ++ } ++#elif defined(HW_OOB) ++ sdioh_enable_func_intr(sd); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_interrupt_deregister(sdioh_info_t *sd) ++{ ++ sd_trace(("%s: Entering\n", __FUNCTION__)); ++ ++#if !defined(OOB_INTR_ONLY) ++ if (sd->func[1]) { ++ /* register and unmask irq */ ++ sdio_claim_host(sd->func[1]); ++ sdio_release_irq(sd->func[1]); ++ sdio_release_host(sd->func[1]); ++ } ++ ++ if (sd->func[2]) { ++ /* Claim host controller F2 */ ++ sdio_claim_host(sd->func[2]); ++ sdio_release_irq(sd->func[2]); ++ /* Release host controller F2 */ ++ sdio_release_host(sd->func[2]); ++ } ++ ++ sd->intr_handler_valid = FALSE; ++ sd->intr_handler = NULL; ++ sd->intr_handler_arg = NULL; ++#elif defined(HW_OOB) ++ if (dhd_download_fw_on_driverload) ++ sdioh_disable_func_intr(sd); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) ++{ ++ sd_trace(("%s: Entering\n", __FUNCTION__)); ++ *onoff = sd->client_intr_enabled; ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++#if defined(DHD_DEBUG) ++extern bool ++sdioh_interrupt_pending(sdioh_info_t *sd) ++{ ++ return (0); ++} ++#endif ++ ++uint ++sdioh_query_iofnum(sdioh_info_t *sd) ++{ ++ return sd->num_funcs; ++} ++ ++/* IOVar table */ ++enum { ++ IOV_MSGLEVEL = 1, ++ IOV_BLOCKMODE, ++ IOV_BLOCKSIZE, ++ IOV_DMA, ++ IOV_USEINTS, ++ IOV_NUMINTS, ++ IOV_NUMLOCALINTS, ++ IOV_HOSTREG, ++ IOV_DEVREG, ++ IOV_DIVISOR, ++ IOV_SDMODE, ++ IOV_HISPEED, ++ IOV_HCIREGS, ++ IOV_POWER, ++ IOV_CLOCK, ++ IOV_RXCHAIN ++}; ++ ++const bcm_iovar_t sdioh_iovars[] = { ++ {"sd_msglevel", IOV_MSGLEVEL, 0, 0, IOVT_UINT32, 0 }, ++ {"sd_blockmode", IOV_BLOCKMODE, 0, 0, IOVT_BOOL, 0 }, ++ {"sd_blocksize", IOV_BLOCKSIZE, 0, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ ++ {"sd_dma", IOV_DMA, 0, 0, IOVT_BOOL, 0 }, ++ {"sd_ints", IOV_USEINTS, 0, 0, IOVT_BOOL, 0 }, ++ {"sd_numints", IOV_NUMINTS, 0, 0, IOVT_UINT32, 0 }, ++ {"sd_numlocalints", IOV_NUMLOCALINTS, 0, 0, IOVT_UINT32, 0 }, ++ {"sd_divisor", IOV_DIVISOR, 0, 0, IOVT_UINT32, 0 }, ++ {"sd_power", IOV_POWER, 0, 0, IOVT_UINT32, 0 }, ++ {"sd_clock", IOV_CLOCK, 0, 0, IOVT_UINT32, 0 }, ++ {"sd_mode", IOV_SDMODE, 0, 0, IOVT_UINT32, 100}, ++ {"sd_highspeed", IOV_HISPEED, 0, 0, IOVT_UINT32, 0 }, ++ {"sd_rxchain", IOV_RXCHAIN, 0, 0, IOVT_BOOL, 0 }, ++ {NULL, 0, 0, 0, 0, 0 } ++}; ++ ++int ++sdioh_iovar_op(sdioh_info_t *si, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ const bcm_iovar_t *vi = NULL; ++ int bcmerror = 0; ++ int val_size; ++ int32 int_val = 0; ++ bool bool_val; ++ uint32 actionid; ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get must have return space; Set does not take qualifiers */ ++ ASSERT(set || (arg && len)); ++ ASSERT(!set || (!params && !plen)); ++ ++ sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); ++ ++ if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { ++ bcmerror = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 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)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ bool_val = (int_val != 0) ? TRUE : FALSE; ++ BCM_REFERENCE(bool_val); ++ ++ actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); ++ switch (actionid) { ++ case IOV_GVAL(IOV_MSGLEVEL): ++ int_val = (int32)sd_msglevel; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_MSGLEVEL): ++ sd_msglevel = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_BLOCKMODE): ++ int_val = (int32)si->sd_blockmode; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_BLOCKMODE): ++ si->sd_blockmode = (bool)int_val; ++ /* Haven't figured out how to make non-block mode with DMA */ ++ break; ++ ++ case IOV_GVAL(IOV_BLOCKSIZE): ++ if ((uint32)int_val > si->num_funcs) { ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ int_val = (int32)si->client_block_size[int_val]; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_BLOCKSIZE): ++ { ++ uint func = ((uint32)int_val >> 16); ++ uint blksize = (uint16)int_val; ++ uint maxsize; ++ ++ if (func > si->num_funcs) { ++ bcmerror = BCME_BADARG; ++ 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 = BCME_BADARG; ++ break; ++ } ++ if (!blksize) { ++ blksize = maxsize; ++ } ++ ++ /* Now set it */ ++ si->client_block_size[func] = blksize; ++ ++#ifdef USE_DYNAMIC_F2_BLKSIZE ++ if (si->func[func] == NULL) { ++ sd_err(("%s: SDIO Device not present\n", __FUNCTION__)); ++ bcmerror = BCME_NORESOURCE; ++ break; ++ } ++ sdio_claim_host(si->func[func]); ++ bcmerror = sdio_set_block_size(si->func[func], blksize); ++ if (bcmerror) ++ sd_err(("%s: Failed to set F%d blocksize to %d(%d)\n", ++ __FUNCTION__, func, blksize, bcmerror)); ++ sdio_release_host(si->func[func]); ++#endif /* USE_DYNAMIC_F2_BLKSIZE */ ++ break; ++ } ++ ++ case IOV_GVAL(IOV_RXCHAIN): ++ int_val = (int32)si->use_rxchain; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_DMA): ++ int_val = (int32)si->sd_use_dma; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DMA): ++ si->sd_use_dma = (bool)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_USEINTS): ++ int_val = (int32)si->use_client_ints; ++ bcopy(&int_val, arg, 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_DIVISOR): ++ int_val = (uint32)sd_divisor; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DIVISOR): ++ /* set the clock to divisor, if value is non-zero & power of 2 */ ++ if (int_val && !(int_val & (int_val - 1))) { ++ sd_divisor = int_val; ++ sdmmc_set_clock_divisor(si, sd_divisor); ++ } else { ++ DHD_ERROR(("%s: Invalid sd_divisor value, should be power of 2!\n", ++ __FUNCTION__)); ++ } ++ break; ++ ++ case IOV_GVAL(IOV_POWER): ++ int_val = (uint32)sd_power; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_POWER): ++ sd_power = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_CLOCK): ++ int_val = (uint32)sd_clock; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_CLOCK): ++ sd_clock = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_SDMODE): ++ int_val = (uint32)sd_sdmode; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDMODE): ++ sd_sdmode = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_HISPEED): ++ int_val = (uint32)sd_hiok; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_HISPEED): ++ sd_hiok = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_NUMINTS): ++ int_val = (int32)si->intrcount; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_NUMLOCALINTS): ++ int_val = (int32)0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++exit: ++ ++ return bcmerror; ++} ++ ++#if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN) ++ ++SDIOH_API_RC ++sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) ++{ ++ SDIOH_API_RC status; ++ uint8 data; ++ ++ if (enable) ++#ifdef HW_OOB_LOW_LEVEL ++ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; ++#else ++ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; ++#endif ++ else ++ data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ ++ ++ status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); ++ return status; ++} ++#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ ++ ++extern SDIOH_API_RC ++sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) ++{ ++ SDIOH_API_RC status; ++ /* No lock needed since sdioh_request_byte does locking */ ++ status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); ++ return status; ++} ++ ++extern SDIOH_API_RC ++sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) ++{ ++ /* No lock needed since sdioh_request_byte does locking */ ++ SDIOH_API_RC status; ++ status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); ++ return status; ++} ++ ++static int ++sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr) ++{ ++ /* read 24 bits and return valid 17 bit addr */ ++ int i; ++ uint32 scratch, regdata; ++ uint8 *ptr = (uint8 *)&scratch; ++ for (i = 0; i < 3; i++) { ++ if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) ++ sd_err(("%s: Can't read!\n", __FUNCTION__)); ++ ++ *ptr++ = (uint8) regdata; ++ regaddr++; ++ } ++ ++ /* Only the lower 17-bits are valid */ ++ scratch = ltoh32(scratch); ++ scratch &= 0x0001FFFF; ++ return (scratch); ++} ++ ++extern SDIOH_API_RC ++sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) ++{ ++ uint32 count; ++ int offset; ++ uint32 foo; ++ uint8 *cis = cisd; ++ ++ sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); ++ ++ if (!sd->func_cis_ptr[func]) { ++ bzero(cis, length); ++ sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func])); ++ ++ for (count = 0; count < length; count++) { ++ offset = sd->func_cis_ptr[func] + count; ++ if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) { ++ sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ *cis = (uint8)(foo & 0xff); ++ cis++; ++ } ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_cisaddr_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 offset) ++{ ++ uint32 foo; ++ ++ sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); ++ ++ if (!sd->func_cis_ptr[func]) { ++ sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func])); ++ ++ if (sdioh_sdmmc_card_regread (sd, 0, sd->func_cis_ptr[func]+offset, 1, &foo) < 0) { ++ sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ *cisd = (uint8)(foo & 0xff); ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) ++{ ++ int err_ret = 0; ++#if defined(MMC_SDIO_ABORT) ++ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; ++#endif ++ struct osl_timespec now, before; ++ ++ if (sd_msglevel & SDH_COST_VAL) ++ osl_do_gettimeofday(&before); ++ ++ sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); ++ ++ DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ if(rw) { /* CMD52 Write */ ++ if (func == 0) { ++ /* Can only directly write to some F0 registers. Handle F2 enable ++ * as a special case. ++ */ ++ if (regaddr == SDIOD_CCCR_IOEN) { ++#if defined(BT_OVER_SDIO) ++ do { ++ if (sd->func[3]) { ++ sd_info(("bcmsdh_sdmmc F3: *byte 0x%x\n", *byte)); ++ ++ if (*byte & SDIO_FUNC_ENABLE_3) { ++ sdio_claim_host(sd->func[3]); ++ ++ /* Set Function 3 Block Size */ ++ err_ret = sdio_set_block_size(sd->func[3], ++ sd_f3_blocksize); ++ if (err_ret) { ++ sd_err(("F3 blocksize set err%d\n", ++ err_ret)); ++ } ++ ++ /* Enable Function 3 */ ++ sd_info(("bcmsdh_sdmmc F3: enable F3 fn %p\n", ++ sd->func[3])); ++ err_ret = sdio_enable_func(sd->func[3]); ++ if (err_ret) { ++ sd_err(("bcmsdh_sdmmc: enable F3 err:%d\n", ++ err_ret)); ++ } ++ ++ sdio_release_host(sd->func[3]); ++ ++ break; ++ } else if (*byte & SDIO_FUNC_DISABLE_3) { ++ sdio_claim_host(sd->func[3]); ++ ++ /* Disable Function 3 */ ++ sd_info(("bcmsdh_sdmmc F3: disable F3 fn %p\n", ++ sd->func[3])); ++ err_ret = sdio_disable_func(sd->func[3]); ++ if (err_ret) { ++ sd_err(("bcmsdh_sdmmc: Disable F3 err:%d\n", ++ err_ret)); ++ } ++ sdio_release_host(sd->func[3]); ++ sd->func[3] = NULL; ++ ++ break; ++ } ++ } ++#endif /* defined (BT_OVER_SDIO) */ ++ if (sd->func[2]) { ++ sdio_claim_host(sd->func[2]); ++ if (*byte & SDIO_FUNC_ENABLE_2) { ++ /* Enable Function 2 */ ++ err_ret = sdio_enable_func(sd->func[2]); ++ if (err_ret) { ++ sd_err(("bcmsdh_sdmmc: enable F2 failed:%d\n", ++ err_ret)); ++ } ++ } else { ++ /* Disable Function 2 */ ++ err_ret = sdio_disable_func(sd->func[2]); ++ if (err_ret) { ++ sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d\n", ++ err_ret)); ++ } ++ } ++ sdio_release_host(sd->func[2]); ++ } ++#if defined(BT_OVER_SDIO) ++ } while (0); ++#endif /* defined (BT_OVER_SDIO) */ ++ } ++#if defined(MMC_SDIO_ABORT) ++ /* to allow abort command through F1 */ ++ else if (regaddr == SDIOD_CCCR_IOABORT) { ++ while (sdio_abort_retry--) { ++ if (sd->func[func]) { ++ sdio_claim_host(sd->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(sd->func[func], ++ *byte, regaddr, &err_ret); ++ sdio_release_host(sd->func[func]); ++ } ++ if (!err_ret) ++ break; ++ } ++ } ++#endif /* MMC_SDIO_ABORT */ ++ /* to allow abort command through F1 */ ++#if defined(SDIO_ISR_THREAD) ++ else if (regaddr == SDIOD_CCCR_INTR_EXTN) { ++ while (sdio_abort_retry--) { ++ if (sd->func[func]) { ++ sdio_claim_host(sd->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(sd->func[func], ++ *byte, regaddr, &err_ret); ++ sdio_release_host(sd->func[func]); ++ } ++ if (!err_ret) ++ break; ++ } ++ } ++#endif ++ else if (regaddr < 0xF0) { ++ sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); ++ } else { ++ /* Claim host controller, perform F0 write, and release */ ++ if (sd->func[func]) { ++ sdio_claim_host(sd->func[func]); ++ sdio_f0_writeb(sd->func[func], ++ *byte, regaddr, &err_ret); ++ sdio_release_host(sd->func[func]); ++ } ++ } ++ } else { ++ /* Claim host controller, perform Fn write, and release */ ++ if (sd->func[func]) { ++ sdio_claim_host(sd->func[func]); ++ sdio_writeb(sd->func[func], *byte, regaddr, &err_ret); ++ sdio_release_host(sd->func[func]); ++ } ++ } ++ } else { /* CMD52 Read */ ++ /* Claim host controller, perform Fn read, and release */ ++ if (sd->func[func]) { ++ sdio_claim_host(sd->func[func]); ++ if (func == 0) { ++ *byte = sdio_f0_readb(sd->func[func], regaddr, &err_ret); ++ } else { ++ *byte = sdio_readb(sd->func[func], regaddr, &err_ret); ++ } ++ sdio_release_host(sd->func[func]); ++ } ++ } ++ ++ if (err_ret) { ++ if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ))) { ++ } else { ++ sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", ++ rw ? "Write" : "Read", func, regaddr, *byte, err_ret)); ++ } ++ } ++ ++ if (sd_msglevel & SDH_COST_VAL) { ++ osl_do_gettimeofday(&now); ++ sd_cost(("%s: rw=%d len=1 cost=%lds %luus\n", __FUNCTION__, ++ rw, now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000)); ++ } ++ ++ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); ++} ++ ++uint ++sdioh_set_mode(sdioh_info_t *sd, uint mode) ++{ ++ if (mode == SDPCM_TXGLOM_CPY) ++ sd->txglom_mode = mode; ++ else if (mode == SDPCM_TXGLOM_MDESC) ++ sd->txglom_mode = mode; ++ ++ return (sd->txglom_mode); ++} ++ ++extern SDIOH_API_RC ++sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, ++ uint32 *word, uint nbytes) ++{ ++ int err_ret = SDIOH_API_RC_FAIL; ++ int err_ret2 = SDIOH_API_RC_SUCCESS; // terence 20130621: prevent dhd_dpc in dead lock ++#if defined(MMC_SDIO_ABORT) ++ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; ++#endif ++ struct osl_timespec now, before; ++ ++ if (sd_msglevel & SDH_COST_VAL) ++ osl_do_gettimeofday(&before); ++ ++ if (func == 0) { ++ sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", ++ __FUNCTION__, cmd_type, rw, func, addr, nbytes)); ++ ++ DHD_PM_RESUME_WAIT(sdioh_request_word_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ /* Claim host controller */ ++ sdio_claim_host(sd->func[func]); ++ ++ if(rw) { /* CMD52 Write */ ++ if (nbytes == 4) { ++ sdio_writel(sd->func[func], *word, addr, &err_ret); ++ } else if (nbytes == 2) { ++ sdio_writew(sd->func[func], (*word & 0xFFFF), addr, &err_ret); ++ } else { ++ sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); ++ } ++ } else { /* CMD52 Read */ ++ if (nbytes == 4) { ++ *word = sdio_readl(sd->func[func], addr, &err_ret); ++ } else if (nbytes == 2) { ++ *word = sdio_readw(sd->func[func], addr, &err_ret) & 0xFFFF; ++ } else { ++ sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); ++ } ++ } ++ ++ /* Release host controller */ ++ sdio_release_host(sd->func[func]); ++ ++ if (err_ret) { ++#if defined(MMC_SDIO_ABORT) ++ /* Any error on CMD53 transaction should abort that function using function 0. */ ++ while (sdio_abort_retry--) { ++ if (sd->func[0]) { ++ sdio_claim_host(sd->func[0]); ++ /* ++ * 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(sd->func[0], ++ func, SDIOD_CCCR_IOABORT, &err_ret2); ++ sdio_release_host(sd->func[0]); ++ } ++ if (!err_ret2) ++ break; ++ } ++ if (err_ret) ++#endif /* MMC_SDIO_ABORT */ ++ { ++ sd_err(("bcmsdh_sdmmc: Failed to %s word F%d:@0x%05x=%02x, Err: 0x%08x\n", ++ rw ? "Write" : "Read", func, addr, *word, err_ret)); ++ } ++ } ++ ++ if (sd_msglevel & SDH_COST_VAL) { ++ osl_do_gettimeofday(&now); ++ sd_cost(("%s: rw=%d, len=%d cost=%lds %luus\n", __FUNCTION__, ++ rw, nbytes, now.tv_sec-before.tv_sec, now.tv_nsec/1000 - before.tv_nsec/1000)); ++ } ++ ++ return (((err_ret == 0)&&(err_ret2 == 0)) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); ++} ++ ++#ifdef BCMSDIOH_TXGLOM ++static SDIOH_API_RC ++sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func, ++ uint addr, void *pkt) ++{ ++ bool fifo = (fix_inc == SDIOH_DATA_FIX); ++ int err_ret = 0; ++ void *pnext; ++ uint ttl_len, pkt_offset; ++ uint blk_num; ++ uint blk_size; ++ uint max_blk_count; ++ uint max_req_size; ++ struct mmc_request mmc_req; ++ struct mmc_command mmc_cmd; ++ struct mmc_data mmc_dat; ++ uint32 sg_count; ++ struct sdio_func *sdio_func = sd->func[func]; ++ struct mmc_host *host = sdio_func->card->host; ++ uint8 *localbuf = NULL; ++ uint local_plen = 0; ++ uint pkt_len = 0; ++ struct osl_timespec now, before; ++ ++ sd_trace(("%s: Enter\n", __FUNCTION__)); ++ ASSERT(pkt); ++ DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ ++ if (sd_msglevel & SDH_COST_VAL) ++ osl_do_gettimeofday(&before); ++ ++ blk_size = sd->client_block_size[func]; ++ max_blk_count = min(host->max_blk_count, (uint)MAX_IO_RW_EXTENDED_BLK); ++ max_req_size = min(max_blk_count * blk_size, host->max_req_size); ++ ++ pkt_offset = 0; ++ pnext = pkt; ++ ++ ttl_len = 0; ++ sg_count = 0; ++ if(sd->txglom_mode == SDPCM_TXGLOM_MDESC) { ++ while (pnext != NULL) { ++ ttl_len = 0; ++ sg_count = 0; ++ memset(&mmc_req, 0, sizeof(struct mmc_request)); ++ memset(&mmc_cmd, 0, sizeof(struct mmc_command)); ++ memset(&mmc_dat, 0, sizeof(struct mmc_data)); ++ sg_init_table(sd->sg_list, ARRAYSIZE(sd->sg_list)); ++ ++ /* Set up scatter-gather DMA descriptors. this loop is to find out the max ++ * data we can transfer with one command 53. blocks per command is limited by ++ * host max_req_size and 9-bit max block number. when the total length of this ++ * packet chain is bigger than max_req_size, use multiple SD_IO_RW_EXTENDED ++ * commands (each transfer is still block aligned) ++ */ ++ while (pnext != NULL && ttl_len < max_req_size) { ++ int pkt_len; ++ int sg_data_size; ++ uint8 *pdata = (uint8*)PKTDATA(sd->osh, pnext); ++ ++ ASSERT(pdata != NULL); ++ pkt_len = PKTLEN(sd->osh, pnext); ++ sd_trace(("%s[%d] data=%p, len=%d\n", __FUNCTION__, write, pdata, pkt_len)); ++ /* sg_count is unlikely larger than the array size, and this is ++ * NOT something we can handle here, but in case it happens, PLEASE put ++ * a restriction on max tx/glom count (based on host->max_segs). ++ */ ++ if (sg_count >= ARRAYSIZE(sd->sg_list)) { ++ sd_err(("%s: sg list entries exceed limit %d\n", __FUNCTION__, sg_count)); ++ return (SDIOH_API_RC_FAIL); ++ } ++ pdata += pkt_offset; ++ ++ sg_data_size = pkt_len - pkt_offset; ++ if (sg_data_size > max_req_size - ttl_len) ++ sg_data_size = max_req_size - ttl_len; ++ /* some platforms put a restriction on the data size of each scatter-gather ++ * DMA descriptor, use multiple sg buffers when xfer_size is bigger than ++ * max_seg_size ++ */ ++ if (sg_data_size > host->max_seg_size) ++ sg_data_size = host->max_seg_size; ++ sg_set_buf(&sd->sg_list[sg_count++], pdata, sg_data_size); ++ ++ ttl_len += sg_data_size; ++ pkt_offset += sg_data_size; ++ if (pkt_offset == pkt_len) { ++ pnext = PKTNEXT(sd->osh, pnext); ++ pkt_offset = 0; ++ } ++ } ++ ++ if (ttl_len % blk_size != 0) { ++ sd_err(("%s, data length %d not aligned to block size %d\n", ++ __FUNCTION__, ttl_len, blk_size)); ++ return SDIOH_API_RC_FAIL; ++ } ++ blk_num = ttl_len / blk_size; ++ mmc_dat.sg = sd->sg_list; ++ mmc_dat.sg_len = sg_count; ++ mmc_dat.blksz = blk_size; ++ mmc_dat.blocks = blk_num; ++ mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; ++ mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ ++ mmc_cmd.arg = write ? 1<<31 : 0; ++ mmc_cmd.arg |= (func & 0x7) << 28; ++ mmc_cmd.arg |= 1<<27; ++ mmc_cmd.arg |= fifo ? 0 : 1<<26; ++ mmc_cmd.arg |= (addr & 0x1FFFF) << 9; ++ mmc_cmd.arg |= blk_num & 0x1FF; ++ mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; ++ mmc_req.cmd = &mmc_cmd; ++ mmc_req.data = &mmc_dat; ++ if (!fifo) ++ addr += ttl_len; ++ ++ sdio_claim_host(sdio_func); ++ mmc_set_data_timeout(&mmc_dat, sdio_func->card); ++ mmc_wait_for_req(host, &mmc_req); ++ sdio_release_host(sdio_func); ++ ++ err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; ++ if (0 != err_ret) { ++ sd_err(("%s:CMD53 %s failed with code %d\n", ++ __FUNCTION__, write ? "write" : "read", err_ret)); ++ return SDIOH_API_RC_FAIL; ++ } ++ } ++ } else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) { ++ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { ++ ttl_len += PKTLEN(sd->osh, pnext); ++ } ++ /* Claim host controller */ ++ sdio_claim_host(sd->func[func]); ++ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { ++ uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext); ++ pkt_len = PKTLEN(sd->osh, pnext); ++ ++ if (!localbuf) { ++ localbuf = (uint8 *)MALLOC(sd->osh, ttl_len); ++ if (localbuf == NULL) { ++ sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n", ++ __FUNCTION__, (write) ? "TX" : "RX")); ++ goto txglomfail; ++ } ++ } ++ ++ bcopy(buf, (localbuf + local_plen), pkt_len); ++ local_plen += pkt_len; ++ if (PKTNEXT(sd->osh, pnext)) ++ continue; ++ ++ buf = localbuf; ++ pkt_len = local_plen; ++txglomfail: ++ /* Align Patch */ ++ if (!write || pkt_len < 32) ++ pkt_len = (pkt_len + 3) & 0xFFFFFFFC; ++ else if (pkt_len % blk_size) ++ pkt_len += blk_size - (pkt_len % blk_size); ++ ++ if ((write) && (!fifo)) ++ err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, pkt_len); ++ else if (write) ++ err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, pkt_len); ++ else if (fifo) ++ err_ret = sdio_readsb(sd->func[func], buf, addr, pkt_len); ++ else ++ err_ret = sdio_memcpy_fromio(sd->func[func], buf, addr, pkt_len); ++ ++ if (err_ret) ++ sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n", ++ __FUNCTION__, ++ (write) ? "TX" : "RX", ++ pnext, sg_count, addr, pkt_len, err_ret)); ++ else ++ sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n", ++ __FUNCTION__, ++ (write) ? "TX" : "RX", ++ pnext, sg_count, addr, pkt_len)); ++ ++ if (!fifo) ++ addr += pkt_len; ++ sg_count ++; ++ } ++ sdio_release_host(sd->func[func]); ++ } else { ++ sd_err(("%s: set to wrong glom mode %d\n", __FUNCTION__, sd->txglom_mode)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ if (localbuf) ++ MFREE(sd->osh, localbuf, ttl_len); ++ ++ if (sd_msglevel & SDH_COST_VAL) { ++ osl_do_gettimeofday(&now); ++ sd_cost(("%s: rw=%d, ttl_len=%d, cost=%lds %luus\n", __FUNCTION__, ++ write, ttl_len, now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000)); ++ } ++ ++ sd_trace(("%s: Exit\n", __FUNCTION__)); ++ return SDIOH_API_RC_SUCCESS; ++} ++#endif /* BCMSDIOH_TXGLOM */ ++ ++static SDIOH_API_RC ++sdioh_buffer_tofrom_bus(sdioh_info_t *sd, uint fix_inc, uint write, uint func, ++ uint addr, uint8 *buf, uint len) ++{ ++ bool fifo = (fix_inc == SDIOH_DATA_FIX); ++ int err_ret = 0; ++ struct osl_timespec now, before; ++ ++ sd_trace(("%s: Enter\n", __FUNCTION__)); ++ ASSERT(buf); ++ ++ if (sd_msglevel & SDH_COST_VAL) ++ osl_do_gettimeofday(&before); ++ ++ /* NOTE: ++ * For all writes, each packet length is aligned to 32 (or 4) ++ * bytes in dhdsdio_txpkt_preprocess, and for glom the last packet length ++ * is aligned to block boundary. If you want to align each packet to ++ * a custom size, please do it in dhdsdio_txpkt_preprocess, NOT here ++ * ++ * For reads, the alignment is doen in sdioh_request_buffer. ++ * ++ */ ++ sdio_claim_host(sd->func[func]); ++ ++ if ((write) && (!fifo)) ++ err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); ++ else if (write) ++ err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); ++ else if (fifo) ++ err_ret = sdio_readsb(sd->func[func], buf, addr, len); ++ else ++ err_ret = sdio_memcpy_fromio(sd->func[func], buf, addr, len); ++ ++ sdio_release_host(sd->func[func]); ++ ++ if (err_ret) ++ sd_err(("%s: %s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=%d\n", __FUNCTION__, ++ (write) ? "TX" : "RX", buf, addr, len, err_ret)); ++ else ++ sd_trace(("%s: %s xfr'd %p, addr=0x%05x, len=%d\n", __FUNCTION__, ++ (write) ? "TX" : "RX", buf, addr, len)); ++ ++ sd_trace(("%s: Exit\n", __FUNCTION__)); ++ ++ if (sd_msglevel & SDH_COST_VAL) { ++ osl_do_gettimeofday(&now); ++ sd_cost(("%s: rw=%d, len=%d cost=%lds %luus\n", __FUNCTION__, ++ write, len, now.tv_sec-before.tv_sec, now.tv_nsec/1000 - before.tv_nsec/1000)); ++ } ++ ++ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); ++} ++ ++ ++/* ++ * This function takes a buffer or packet, and fixes everything up so that in the ++ * end, a DMA-able packet is created. ++ * ++ * A buffer does not have an associated packet pointer, and may or may not be aligned. ++ * A packet may consist of a single packet, or a packet chain. If it is a packet chain, ++ * then all the packets in the chain must be properly aligned. If the packet data is not ++ * aligned, then there may only be one packet, and in this case, it is copied to a new ++ * aligned packet. ++ * ++ */ ++extern SDIOH_API_RC ++sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, ++ uint addr, uint reg_width, uint buf_len, uint8 *buffer, void *pkt) ++{ ++ SDIOH_API_RC status; ++ void *tmppkt; ++ struct osl_timespec now, before; ++ ++ sd_trace(("%s: Enter\n", __FUNCTION__)); ++ DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); ++ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); ++ ++ if (sd_msglevel & SDH_COST_VAL) ++ osl_do_gettimeofday(&before); ++ ++ if (pkt) { ++#ifdef BCMSDIOH_TXGLOM ++ /* packet chain, only used for tx/rx glom, all packets length ++ * are aligned, total length is a block multiple ++ */ ++ if (PKTNEXT(sd->osh, pkt)) ++ return sdioh_request_packet_chain(sd, fix_inc, write, func, addr, pkt); ++#endif /* BCMSDIOH_TXGLOM */ ++ /* non-glom mode, ignore the buffer parameter and use the packet pointer ++ * (this shouldn't happen) ++ */ ++ buffer = PKTDATA(sd->osh, pkt); ++ buf_len = PKTLEN(sd->osh, pkt); ++ } ++ ++ ASSERT(buffer); ++ ++ /* buffer and length are aligned, use it directly so we can avoid memory copy */ ++ if (((ulong)buffer & DMA_ALIGN_MASK) == 0 && (buf_len & DMA_ALIGN_MASK) == 0) ++ return sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, buffer, buf_len); ++ ++ sd_trace(("%s: [%d] doing memory copy buf=%p, len=%d\n", ++ __FUNCTION__, write, buffer, buf_len)); ++ ++ /* otherwise, a memory copy is needed as the input buffer is not aligned */ ++ tmppkt = PKTGET_STATIC(sd->osh, buf_len + DEFAULT_SDIO_F2_BLKSIZE, write ? TRUE : FALSE); ++ if (tmppkt == NULL) { ++ sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, buf_len)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ if (write) ++ bcopy(buffer, PKTDATA(sd->osh, tmppkt), buf_len); ++ ++ status = sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, ++ PKTDATA(sd->osh, tmppkt), ROUNDUP(buf_len, (DMA_ALIGN_MASK+1))); ++ ++ if (!write) ++ bcopy(PKTDATA(sd->osh, tmppkt), buffer, buf_len); ++ ++ PKTFREE_STATIC(sd->osh, tmppkt, write ? TRUE : FALSE); ++ ++ if (sd_msglevel & SDH_COST_VAL) { ++ osl_do_gettimeofday(&now); ++ sd_cost(("%s: len=%d cost=%lds %luus\n", __FUNCTION__, ++ buf_len, now.tv_sec-before.tv_sec, now.tv_nsec/1000 - before.tv_nsec/1000)); ++ } ++ ++ return status; ++} ++ ++/* this function performs "abort" for both of host & device */ ++extern int ++sdioh_abort(sdioh_info_t *sd, uint func) ++{ ++#if defined(MMC_SDIO_ABORT) ++ char t_func = (char) func; ++#endif /* defined(MMC_SDIO_ABORT) */ ++ sd_trace(("%s: Enter\n", __FUNCTION__)); ++ ++#if defined(MMC_SDIO_ABORT) ++ /* issue abort cmd52 command through F1 */ ++ sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); ++#endif /* defined(MMC_SDIO_ABORT) */ ++ ++ sd_trace(("%s: Exit\n", __FUNCTION__)); ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++/* Reset and re-initialize the device */ ++int sdioh_sdio_reset(sdioh_info_t *si) ++{ ++ sd_trace(("%s: Enter\n", __FUNCTION__)); ++ sd_trace(("%s: Exit\n", __FUNCTION__)); ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++/* Disable device interrupt */ ++void ++sdioh_sdmmc_devintr_off(sdioh_info_t *sd) ++{ ++ sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); ++ sd->intmask &= ~CLIENT_INTR; ++} ++ ++/* Enable device interrupt */ ++void ++sdioh_sdmmc_devintr_on(sdioh_info_t *sd) ++{ ++ sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); ++ sd->intmask |= CLIENT_INTR; ++} ++ ++/* Read client card reg */ ++int ++sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) ++{ ++ ++ if ((func == 0) || (regsize == 1)) { ++ uint8 temp = 0; ++ ++ sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); ++ *data = temp; ++ *data &= 0xff; ++ sd_data(("%s: byte read data=0x%02x\n", ++ __FUNCTION__, *data)); ++ } else { ++ if (sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize)) { ++ return BCME_SDIO_ERROR; ++ } ++ ++ if (regsize == 2) ++ *data &= 0xffff; ++ ++ sd_data(("%s: word read data=0x%08x\n", ++ __FUNCTION__, *data)); ++ } ++ ++ return SUCCESS; ++} ++ ++#if !defined(OOB_INTR_ONLY) ++/* bcmsdh_sdmmc interrupt handler */ ++static void IRQHandler(struct sdio_func *func) ++{ ++ sdioh_info_t *sd; ++ ++ sd = sdio_get_drvdata(func); ++ ++ ASSERT(sd != NULL); ++ sdio_release_host(sd->func[0]); ++ ++ if (sd->use_client_ints) { ++ sd->intrcount++; ++ ASSERT(sd->intr_handler); ++ ASSERT(sd->intr_handler_arg); ++ (sd->intr_handler)(sd->intr_handler_arg); ++ } else { ++ sd_err(("bcmsdh_sdmmc: ***IRQHandler\n")); ++ ++ sd_err(("%s: Not ready for intr: enabled %d, handler %p\n", ++ __FUNCTION__, sd->client_intr_enabled, sd->intr_handler)); ++ } ++ ++ sdio_claim_host(sd->func[0]); ++} ++ ++/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ ++static void IRQHandlerF2(struct sdio_func *func) ++{ ++ sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n")); ++} ++#endif /* !defined(OOB_INTR_ONLY) */ ++ ++#ifdef NOTUSED ++/* Write client card reg */ ++static int ++sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) ++{ ++ ++ if ((func == 0) || (regsize == 1)) { ++ uint8 temp; ++ ++ temp = data & 0xff; ++ sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); ++ sd_data(("%s: byte write data=0x%02x\n", ++ __FUNCTION__, data)); ++ } else { ++ if (regsize == 2) ++ data &= 0xffff; ++ ++ sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize); ++ ++ sd_data(("%s: word write data=0x%08x\n", ++ __FUNCTION__, data)); ++ } ++ ++ return SUCCESS; ++} ++#endif /* NOTUSED */ ++ ++int ++sdioh_start(sdioh_info_t *sd, int stage) ++{ ++ int ret; ++ ++ if (!sd) { ++ sd_err(("%s Failed, sd is NULL\n", __FUNCTION__)); ++ return (0); ++ } ++ ++ /* Need to do this stages as we can't enable the interrupt till ++ downloading of the firmware is complete, other wise polling ++ sdio access will come in way ++ */ ++ if (sd->func[0]) { ++ if (stage == 0) { ++ /* Since the power to the chip is killed, we will have ++ re enumerate the device again. Set the block size ++ and enable the fucntion 1 for in preparation for ++ downloading the code ++ */ ++ /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux ++ 2.6.27. The implementation prior to that is buggy, and needs broadcom's ++ patch for it ++ */ ++#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE) ++ if ((ret = sdio_reset_comm(sd->func[0]->card))) { ++ sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); ++ return ret; ++ } else ++#endif ++ { ++ sd->num_funcs = 2; ++ sd->sd_blockmode = TRUE; ++ sd->use_client_ints = TRUE; ++ sd->client_block_size[0] = 64; ++ ++ if (sd->func[1]) { ++ /* Claim host controller */ ++ sdio_claim_host(sd->func[1]); ++ ++ sd->client_block_size[1] = 64; ++ ret = sdio_set_block_size(sd->func[1], 64); ++ if (ret) { ++ sd_err(("bcmsdh_sdmmc: Failed to set F1 " ++ "blocksize(%d)\n", ret)); ++ } ++ ++ /* Release host controller F1 */ ++ sdio_release_host(sd->func[1]); ++ } ++ ++ if (sd->func[2]) { ++ /* Claim host controller F2 */ ++ sdio_claim_host(sd->func[2]); ++ ++ sd->client_block_size[2] = sd_f2_blocksize; ++ printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize); ++ ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); ++ if (ret) { ++ sd_err(("bcmsdh_sdmmc: Failed to set F2 " ++ "blocksize to %d(%d)\n", sd_f2_blocksize, ret)); ++ } ++ ++ /* Release host controller F2 */ ++ sdio_release_host(sd->func[2]); ++ } ++ ++ sdioh_sdmmc_card_enablefuncs(sd); ++ } ++ } else { ++#if !defined(OOB_INTR_ONLY) ++ sdio_claim_host(sd->func[0]); ++ if (sd->func[2]) ++ sdio_claim_irq(sd->func[2], IRQHandlerF2); ++ if (sd->func[1]) ++ sdio_claim_irq(sd->func[1], IRQHandler); ++ sdio_release_host(sd->func[0]); ++#else /* defined(OOB_INTR_ONLY) */ ++#if defined(HW_OOB) ++ sdioh_enable_func_intr(sd); ++#endif ++ bcmsdh_oob_intr_set(sd->bcmsdh, TRUE); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ } ++ } ++ else ++ sd_err(("%s Failed\n", __FUNCTION__)); ++ ++ return (0); ++} ++ ++int ++sdioh_stop(sdioh_info_t *sd) ++{ ++ /* MSM7201A Android sdio stack has bug with interrupt ++ So internaly within SDIO stack they are polling ++ which cause issue when device is turned off. So ++ unregister interrupt with SDIO stack to stop the ++ polling ++ */ ++ if (sd->func[0]) { ++#if !defined(OOB_INTR_ONLY) ++ sdio_claim_host(sd->func[0]); ++ if (sd->func[1]) ++ sdio_release_irq(sd->func[1]); ++ if (sd->func[2]) ++ sdio_release_irq(sd->func[2]); ++ sdio_release_host(sd->func[0]); ++#else /* defined(OOB_INTR_ONLY) */ ++#if defined(HW_OOB) ++ sdioh_disable_func_intr(sd); ++#endif ++ bcmsdh_oob_intr_set(sd->bcmsdh, FALSE); ++#endif /* !defined(OOB_INTR_ONLY) */ ++ } ++ else ++ sd_err(("%s Failed\n", __FUNCTION__)); ++ return (0); ++} ++ ++int ++sdioh_waitlockfree(sdioh_info_t *sd) ++{ ++ return (1); ++} ++ ++ ++SDIOH_API_RC ++sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) ++{ ++ return SDIOH_API_RC_FAIL; ++} ++ ++SDIOH_API_RC ++sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) ++{ ++ return SDIOH_API_RC_FAIL; ++} ++ ++bool ++sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) ++{ ++ return FALSE; ++} ++ ++SDIOH_API_RC ++sdioh_gpio_init(sdioh_info_t *sd) ++{ ++ return SDIOH_API_RC_FAIL; ++} ++ ++uint ++sdmmc_get_clock_rate(sdioh_info_t *sd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) ++ return 0; ++#else ++ struct sdio_func *sdio_func = sd->func[0]; ++ struct mmc_host *host = sdio_func->card->host; ++ return mmc_host_clk_rate(host); ++#endif ++} ++ ++ ++void ++sdmmc_set_clock_rate(sdioh_info_t *sd, uint hz) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) ++ return; ++#else ++ struct sdio_func *sdio_func = sd->func[0]; ++ struct mmc_host *host = sdio_func->card->host; ++ struct mmc_ios *ios = &host->ios; ++ ++ mmc_host_clk_hold(host); ++ DHD_INFO(("%s: Before change: sd clock rate is %u\n", __FUNCTION__, ios->clock)); ++ if (hz < host->f_min) { ++ DHD_ERROR(("%s: Intended rate is below min rate, setting to min\n", __FUNCTION__)); ++ hz = host->f_min; ++ } ++ ++ if (hz > host->f_max) { ++ DHD_ERROR(("%s: Intended rate exceeds max rate, setting to max\n", __FUNCTION__)); ++ hz = host->f_max; ++ } ++ ios->clock = hz; ++ host->ops->set_ios(host, ios); ++ DHD_ERROR(("%s: After change: sd clock rate is %u\n", __FUNCTION__, ios->clock)); ++ mmc_host_clk_release(host); ++#endif ++} ++ ++void ++sdmmc_set_clock_divisor(sdioh_info_t *sd, uint sd_div) ++{ ++ uint hz; ++ uint old_div = sdmmc_get_clock_rate(sd); ++ if (old_div == sd_div) { ++ return; ++ } ++ ++ hz = sd->sd_clk_rate / sd_div; ++ sdmmc_set_clock_rate(sd, hz); ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c +new file mode 100644 +index 000000000..dd5d3bab5 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c +@@ -0,0 +1,405 @@ ++/* ++ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdh_sdmmc_linux.c 644124 2016-06-17 07:59:34Z $ ++ */ ++ ++#include ++#include ++#include /* SDIO Device and Protocol Specs */ ++#include /* bcmsdh to/from specific controller APIs */ ++#include /* to get msglevel bit values */ ++ ++#include /* request_irq() */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++ ++#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_4319) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4330) ++#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4334) ++#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_4324) ++#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */ ++#if !defined(SDIO_DEVICE_ID_BROADCOM_43239) ++#define SDIO_DEVICE_ID_BROADCOM_43239 43239 ++#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ ++ ++extern void wl_cfg80211_set_parent_dev(void *dev); ++extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); ++extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); ++extern void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type, ++ uint bus_num, uint slot_num); ++extern int bcmsdh_remove(bcmsdh_info_t *bcmsdh); ++ ++int sdio_function_init(void); ++void sdio_function_cleanup(void); ++ ++#define DESCRIPTION "bcmsdh_sdmmc Driver" ++#define AUTHOR "Broadcom Corporation" ++ ++/* module param defaults */ ++static int clockoverride = 0; ++ ++module_param(clockoverride, int, 0644); ++MODULE_PARM_DESC(clockoverride, "SDIO card clock override"); ++ ++#ifdef GLOBAL_SDMMC_INSTANCE ++PBCMSDH_SDMMC_INSTANCE gInstance; ++#endif ++ ++/* Maximum number of bcmsdh_sdmmc devices supported by driver */ ++#define BCMSDH_SDMMC_MAX_DEVICES 1 ++ ++extern volatile bool dhd_mmc_suspend; ++ ++static int sdioh_probe(struct sdio_func *func) ++{ ++ int host_idx = func->card->host->index; ++ uint32 rca = func->card->rca; ++ wifi_adapter_info_t *adapter; ++ osl_t *osh = NULL; ++ sdioh_info_t *sdioh = NULL; ++ ++ sd_err(("bus num (host idx)=%d, slot num (rca)=%d\n", host_idx, rca)); ++ adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca); ++ if (adapter != NULL) { ++ sd_err(("found adapter info '%s'\n", adapter->name)); ++#ifdef BUS_POWER_RESTORE ++ adapter->sdio_func = func; ++#endif ++ } else ++ sd_err(("can't find adapter info for this chip\n")); ++ ++#ifdef WL_CFG80211 ++ wl_cfg80211_set_parent_dev(&func->dev); ++#endif ++ ++ /* allocate SDIO Host Controller state info */ ++ osh = osl_attach(&func->dev, SDIO_BUS, TRUE); ++ if (osh == NULL) { ++ sd_err(("%s: osl_attach failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ osl_static_mem_init(osh, adapter); ++ sdioh = sdioh_attach(osh, func); ++ if (sdioh == NULL) { ++ sd_err(("%s: sdioh_attach failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ sdioh->bcmsdh = bcmsdh_probe(osh, &func->dev, sdioh, adapter, SDIO_BUS, host_idx, rca); ++ if (sdioh->bcmsdh == NULL) { ++ sd_err(("%s: bcmsdh_probe failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ sdio_set_drvdata(func, sdioh); ++ return 0; ++ ++fail: ++ if (sdioh != NULL) ++ sdioh_detach(osh, sdioh); ++ if (osh != NULL) ++ osl_detach(osh); ++ return -ENOMEM; ++} ++ ++static void sdioh_remove(struct sdio_func *func) ++{ ++ sdioh_info_t *sdioh; ++ osl_t *osh; ++ ++ sdioh = sdio_get_drvdata(func); ++ if (sdioh == NULL) { ++ sd_err(("%s: error, no sdioh handler found\n", __FUNCTION__)); ++ return; ++ } ++ sd_err(("%s: Enter\n", __FUNCTION__)); ++ ++ osh = sdioh->osh; ++ bcmsdh_remove(sdioh->bcmsdh); ++ sdioh_detach(osh, sdioh); ++ osl_detach(osh); ++} ++ ++static int bcmsdh_sdmmc_probe(struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ int ret = 0; ++ ++ if (func == NULL) ++ return -EINVAL; ++ ++ sd_err(("%s: Enter num=%d\n", __FUNCTION__, func->num)); ++ sd_info(("sdio_bcmsdh: 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)); ++ ++#ifdef GLOBAL_SDMMC_INSTANCE ++ gInstance->func[func->num] = func; ++#endif ++ ++ /* 4318 doesn't have function 2 */ ++ if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) ++ ret = sdioh_probe(func); ++ ++ return ret; ++} ++ ++static void bcmsdh_sdmmc_remove(struct sdio_func *func) ++{ ++ if (func == NULL) { ++ sd_err(("%s is called with NULL SDIO function pointer\n", __FUNCTION__)); ++ return; ++ } ++ ++ sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); ++ sd_info(("sdio_bcmsdh: 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)); ++ ++ if ((func->num == 2) || (func->num == 1 && func->device == 0x4)) ++ sdioh_remove(func); ++} ++ ++/* devices we support, null terminated */ ++static const struct sdio_device_id bcmsdh_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) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, ++ { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, ++ { 0, 0, 0, 0 /* end: all zeroes */ ++ }, ++}; ++ ++MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) ++static int bcmsdh_sdmmc_suspend(struct device *pdev) ++{ ++ int err; ++ sdioh_info_t *sdioh; ++ struct sdio_func *func = dev_to_sdio_func(pdev); ++ mmc_pm_flag_t sdio_flags; ++ ++ printf("%s Enter func->num=%d\n", __FUNCTION__, func->num); ++ if (func->num != 2) ++ return 0; ++ ++ dhd_mmc_suspend = TRUE; ++ sdioh = sdio_get_drvdata(func); ++ err = bcmsdh_suspend(sdioh->bcmsdh); ++ if (err) { ++ printf("%s bcmsdh_suspend err=%d\n", __FUNCTION__, err); ++ dhd_mmc_suspend = FALSE; ++ return err; ++ } ++ ++ sdio_flags = sdio_get_host_pm_caps(func); ++ if (!(sdio_flags & MMC_PM_KEEP_POWER)) { ++ sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__)); ++ dhd_mmc_suspend = FALSE; ++ return -EINVAL; ++ } ++ ++ /* keep power while host suspended */ ++ err = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); ++ if (err) { ++ sd_err(("%s: error while trying to keep power\n", __FUNCTION__)); ++ dhd_mmc_suspend = FALSE; ++ return err; ++ } ++ smp_mb(); ++ ++ printf("%s Exit\n", __FUNCTION__); ++ return 0; ++} ++ ++static int bcmsdh_sdmmc_resume(struct device *pdev) ++{ ++ sdioh_info_t *sdioh; ++ struct sdio_func *func = dev_to_sdio_func(pdev); ++ ++ printf("%s Enter func->num=%d\n", __FUNCTION__, func->num); ++ if (func->num != 2) ++ return 0; ++ ++ dhd_mmc_suspend = FALSE; ++ sdioh = sdio_get_drvdata(func); ++ bcmsdh_resume(sdioh->bcmsdh); ++ ++ smp_mb(); ++ printf("%s Exit\n", __FUNCTION__); ++ return 0; ++} ++ ++static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = { ++ .suspend = bcmsdh_sdmmc_suspend, ++ .resume = bcmsdh_sdmmc_resume, ++}; ++#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ ++ ++#if defined(BCMLXSDMMC) ++static struct semaphore *notify_semaphore = NULL; ++ ++static int dummy_probe(struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ if (func && (func->num != 2)) { ++ return 0; ++ } ++ ++ if (notify_semaphore) ++ up(notify_semaphore); ++ return 0; ++} ++ ++static void dummy_remove(struct sdio_func *func) ++{ ++} ++ ++static struct sdio_driver dummy_sdmmc_driver = { ++ .probe = dummy_probe, ++ .remove = dummy_remove, ++ .name = "dummy_sdmmc", ++ .id_table = bcmsdh_sdmmc_ids, ++ }; ++ ++int sdio_func_reg_notify(void* semaphore) ++{ ++ notify_semaphore = semaphore; ++ return sdio_register_driver(&dummy_sdmmc_driver); ++} ++ ++void sdio_func_unreg_notify(void) ++{ ++ OSL_SLEEP(15); ++ sdio_unregister_driver(&dummy_sdmmc_driver); ++} ++ ++#endif /* defined(BCMLXSDMMC) */ ++ ++static struct sdio_driver bcmsdh_sdmmc_driver = { ++ .probe = bcmsdh_sdmmc_probe, ++ .remove = bcmsdh_sdmmc_remove, ++ .name = "bcmsdh_sdmmc", ++ .id_table = bcmsdh_sdmmc_ids, ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) ++ .drv = { ++ .pm = &bcmsdh_sdmmc_pm_ops, ++ }, ++#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ ++ }; ++ ++struct sdos_info { ++ sdioh_info_t *sd; ++ spinlock_t lock; ++}; ++ ++/* Interrupt enable/disable */ ++SDIOH_API_RC ++sdioh_interrupt_set(sdioh_info_t *sd, bool enable) ++{ ++ if (!sd) ++ return BCME_BADARG; ++ ++ sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++#ifdef BCMSDH_MODULE ++static int __init ++bcmsdh_module_init(void) ++{ ++ int error = 0; ++ error = sdio_function_init(); ++ return error; ++} ++ ++static void __exit ++bcmsdh_module_cleanup(void) ++{ ++ sdio_function_cleanup(); ++} ++ ++module_init(bcmsdh_module_init); ++module_exit(bcmsdh_module_cleanup); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION(DESCRIPTION); ++MODULE_AUTHOR(AUTHOR); ++ ++#endif /* BCMSDH_MODULE */ ++/* ++ * module init ++*/ ++int bcmsdh_register_client_driver(void) ++{ ++ return sdio_register_driver(&bcmsdh_sdmmc_driver); ++} ++ ++/* ++ * module cleanup ++*/ ++void bcmsdh_unregister_client_driver(void) ++{ ++ sdio_unregister_driver(&bcmsdh_sdmmc_driver); ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c b/module_drivers/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c +new file mode 100644 +index 000000000..b7091e598 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c +@@ -0,0 +1,252 @@ ++/* ++ * Broadcom SPI Host Controller Driver - Linux Per-port ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdspi_linux.c 514727 2014-11-12 03:02:48Z $ ++ */ ++ ++#include ++#include ++ ++#include /* bcmsdh to/from specific controller APIs */ ++#include /* to get msglevel bit values */ ++ ++#include ++#include /* SDIO Device and Protocol Specs */ ++#include /* request_irq(), free_irq() */ ++#include ++#include ++ ++extern uint sd_crc; ++module_param(sd_crc, uint, 0); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define KERNEL26 ++#endif ++ ++struct sdos_info { ++ sdioh_info_t *sd; ++ spinlock_t lock; ++ wait_queue_head_t intr_wait_queue; ++}; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define BLOCKABLE() (!in_atomic()) ++#else ++#define BLOCKABLE() (!in_interrupt()) ++#endif ++ ++/* Interrupt handler */ ++static irqreturn_t ++sdspi_isr(int irq, void *dev_id ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) ++, struct pt_regs *ptregs ++#endif ++) ++{ ++ sdioh_info_t *sd; ++ struct sdos_info *sdos; ++ bool ours; ++ ++ sd = (sdioh_info_t *)dev_id; ++ sd->local_intrcount++; ++ ++ if (!sd->card_init_done) { ++ sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq)); ++ return IRQ_RETVAL(FALSE); ++ } else { ++ ours = spi_check_client_intr(sd, NULL); ++ ++ /* For local interrupts, wake the waiting process */ ++ if (ours && sd->got_hcint) { ++ sdos = (struct sdos_info *)sd->sdos_info; ++ wake_up_interruptible(&sdos->intr_wait_queue); ++ } ++ ++ return IRQ_RETVAL(ours); ++ } ++} ++ ++ ++/* Register with Linux for interrupts */ ++int ++spi_register_irq(sdioh_info_t *sd, uint irq) ++{ ++ sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq)); ++ if (request_irq(irq, sdspi_isr, IRQF_SHARED, "bcmsdspi", sd) < 0) { ++ sd_err(("%s: request_irq() failed\n", __FUNCTION__)); ++ return ERROR; ++ } ++ return SUCCESS; ++} ++ ++/* Free Linux irq */ ++void ++spi_free_irq(uint irq, sdioh_info_t *sd) ++{ ++ free_irq(irq, sd); ++} ++ ++/* Map Host controller registers */ ++uint32 * ++spi_reg_map(osl_t *osh, uintptr addr, int size) ++{ ++ return (uint32 *)REG_MAP(addr, size); ++} ++ ++void ++spi_reg_unmap(osl_t *osh, uintptr addr, int size) ++{ ++ REG_UNMAP((void*)(uintptr)addr); ++} ++ ++int ++spi_osinit(sdioh_info_t *sd) ++{ ++ struct sdos_info *sdos; ++ ++ sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info)); ++ sd->sdos_info = (void*)sdos; ++ if (sdos == NULL) ++ return BCME_NOMEM; ++ ++ sdos->sd = sd; ++ spin_lock_init(&sdos->lock); ++ init_waitqueue_head(&sdos->intr_wait_queue); ++ return BCME_OK; ++} ++ ++void ++spi_osfree(sdioh_info_t *sd) ++{ ++ struct sdos_info *sdos; ++ ASSERT(sd && sd->sdos_info); ++ ++ sdos = (struct sdos_info *)sd->sdos_info; ++ MFREE(sd->osh, sdos, sizeof(struct sdos_info)); ++} ++ ++/* Interrupt enable/disable */ ++SDIOH_API_RC ++sdioh_interrupt_set(sdioh_info_t *sd, bool enable) ++{ ++ ulong flags; ++ struct sdos_info *sdos; ++ ++ sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling")); ++ ++ sdos = (struct sdos_info *)sd->sdos_info; ++ ASSERT(sdos); ++ ++ if (!(sd->host_init_done && sd->card_init_done)) { ++ sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { ++ sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__)); ++ return SDIOH_API_RC_FAIL; ++ } ++ ++ /* Ensure atomicity for enable/disable calls */ ++ spin_lock_irqsave(&sdos->lock, flags); ++ ++ sd->client_intr_enabled = enable; ++ if (enable && !sd->lockcount) ++ spi_devintr_on(sd); ++ else ++ spi_devintr_off(sd); ++ ++ spin_unlock_irqrestore(&sdos->lock, flags); ++ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++/* Protect against reentrancy (disable device interrupts while executing) */ ++void ++spi_lock(sdioh_info_t *sd) ++{ ++ ulong flags; ++ struct sdos_info *sdos; ++ ++ sdos = (struct sdos_info *)sd->sdos_info; ++ ASSERT(sdos); ++ ++ sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount)); ++ ++ spin_lock_irqsave(&sdos->lock, flags); ++ if (sd->lockcount) { ++ sd_err(("%s: Already locked!\n", __FUNCTION__)); ++ ASSERT(sd->lockcount == 0); ++ } ++ spi_devintr_off(sd); ++ sd->lockcount++; ++ spin_unlock_irqrestore(&sdos->lock, flags); ++} ++ ++/* Enable client interrupt */ ++void ++spi_unlock(sdioh_info_t *sd) ++{ ++ ulong flags; ++ struct sdos_info *sdos; ++ ++ sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled)); ++ ASSERT(sd->lockcount > 0); ++ ++ sdos = (struct sdos_info *)sd->sdos_info; ++ ASSERT(sdos); ++ ++ spin_lock_irqsave(&sdos->lock, flags); ++ if (--sd->lockcount == 0 && sd->client_intr_enabled) { ++ spi_devintr_on(sd); ++ } ++ spin_unlock_irqrestore(&sdos->lock, flags); ++} ++ ++void spi_waitbits(sdioh_info_t *sd, bool yield) ++{ ++#ifndef BCMSDYIELD ++ ASSERT(!yield); ++#endif ++ sd_trace(("%s: yield %d canblock %d\n", ++ __FUNCTION__, yield, BLOCKABLE())); ++ ++ /* Clear the "interrupt happened" flag and last intrstatus */ ++ sd->got_hcint = FALSE; ++ ++#ifdef BCMSDYIELD ++ if (yield && BLOCKABLE()) { ++ struct sdos_info *sdos; ++ sdos = (struct sdos_info *)sd->sdos_info; ++ /* Wait for the indication, the interrupt will be masked when the ISR fires. */ ++ wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint)); ++ } else ++#endif /* BCMSDYIELD */ ++ { ++ spi_spinbits(sd); ++ } ++ ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmspibrcm.c b/module_drivers/drivers/net/wireless/bcmdhd/bcmspibrcm.c +new file mode 100644 +index 000000000..1bbff169f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmspibrcm.c +@@ -0,0 +1,1764 @@ ++/* ++ * Broadcom BCMSDH to gSPI Protocol Conversion Layer ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmspibrcm.c 611787 2016-01-12 06:07:27Z $ ++ */ ++ ++#define HSMODE ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* SDIO device core hardware definitions. */ ++#include ++ ++#include /* bcmsdh to/from specific controller APIs */ ++#include /* ioctl/iovars */ ++#include /* SDIO Device and Protocol Specs */ ++ ++#include ++ ++ ++#include ++#include ++ ++/* these are for the older cores... for newer cores we have control for each of them */ ++#define F0_RESPONSE_DELAY 16 ++#define F1_RESPONSE_DELAY 16 ++#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY ++ ++ ++#define GSPI_F0_RESP_DELAY 0 ++#define GSPI_F1_RESP_DELAY F1_RESPONSE_DELAY ++#define GSPI_F2_RESP_DELAY 0 ++#define GSPI_F3_RESP_DELAY 0 ++ ++#define CMDLEN 4 ++ ++/* Globals */ ++#if defined(DHD_DEBUG) ++uint sd_msglevel = SDH_ERROR_VAL; ++#else ++uint sd_msglevel = 0; ++#endif ++ ++uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ ++uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ ++uint sd_f2_blocksize = 64; /* Default blocksize */ ++ ++ ++uint sd_divisor = 2; ++uint sd_power = 1; /* Default to SD Slot powered ON */ ++uint sd_clock = 1; /* Default to SD Clock turned ON */ ++uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ ++uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ ++ ++uint8 spi_outbuf[SPI_MAX_PKT_LEN]; ++uint8 spi_inbuf[SPI_MAX_PKT_LEN]; ++ ++/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits ++ * assuming we will not exceed F0 response delay > 100 bytes at 48MHz. ++ */ ++#define BUF2_PKT_LEN 128 ++uint8 spi_outbuf2[BUF2_PKT_LEN]; ++uint8 spi_inbuf2[BUF2_PKT_LEN]; ++ ++#define SPISWAP_WD4(x) bcmswap32(x); ++#define SPISWAP_WD2(x) (bcmswap16(x & 0xffff)) | \ ++ (bcmswap16((x & 0xffff0000) >> 16) << 16); ++ ++/* Prototypes */ ++static bool bcmspi_test_card(sdioh_info_t *sd); ++static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd); ++static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode); ++static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, ++ uint32 *data, uint32 datalen); ++static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, ++ int regsize, uint32 *data); ++static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, ++ int regsize, uint32 data); ++static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, ++ uint8 *data); ++static int bcmspi_driver_init(sdioh_info_t *sd); ++static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, ++ uint32 addr, int nbytes, uint32 *data); ++static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, ++ uint32 *data); ++static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer); ++static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg); ++ ++/* ++ * Public entry points & extern's ++ */ ++extern sdioh_info_t * ++sdioh_attach(osl_t *osh, void *bar0, uint irq) ++{ ++ sdioh_info_t *sd; ++ ++ sd_trace(("%s\n", __FUNCTION__)); ++ if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { ++ sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); ++ return NULL; ++ } ++ bzero((char *)sd, sizeof(sdioh_info_t)); ++ sd->osh = osh; ++ if (spi_osinit(sd) != 0) { ++ sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return NULL; ++ } ++ ++ sd->bar0 = bar0; ++ sd->irq = irq; ++ sd->intr_handler = NULL; ++ sd->intr_handler_arg = NULL; ++ sd->intr_handler_valid = FALSE; ++ ++ /* Set defaults */ ++ sd->use_client_ints = TRUE; ++ sd->sd_use_dma = FALSE; /* DMA Not supported */ ++ ++ /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit ++ * mode ++ */ ++ sd->wordlen = 2; ++ ++ ++ if (!spi_hw_attach(sd)) { ++ sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); ++ spi_osfree(sd); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return (NULL); ++ } ++ ++ if (bcmspi_driver_init(sd) != SUCCESS) { ++ sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__)); ++ spi_hw_detach(sd); ++ spi_osfree(sd); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return (NULL); ++ } ++ ++ if (spi_register_irq(sd, irq) != SUCCESS) { ++ sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); ++ spi_hw_detach(sd); ++ spi_osfree(sd); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ return (NULL); ++ } ++ ++ sd_trace(("%s: Done\n", __FUNCTION__)); ++ ++ return sd; ++} ++ ++extern SDIOH_API_RC ++sdioh_detach(osl_t *osh, sdioh_info_t *sd) ++{ ++ sd_trace(("%s\n", __FUNCTION__)); ++ if (sd) { ++ sd_err(("%s: detaching from hardware\n", __FUNCTION__)); ++ spi_free_irq(sd->irq, sd); ++ spi_hw_detach(sd); ++ spi_osfree(sd); ++ MFREE(sd->osh, sd, sizeof(sdioh_info_t)); ++ } ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++/* Configure callback to client when we recieve client interrupt */ ++extern SDIOH_API_RC ++sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) ++{ ++ sd_trace(("%s: Entering\n", __FUNCTION__)); ++#if !defined(OOB_INTR_ONLY) ++ sd->intr_handler = fn; ++ sd->intr_handler_arg = argh; ++ sd->intr_handler_valid = TRUE; ++#endif /* !defined(OOB_INTR_ONLY) */ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_interrupt_deregister(sdioh_info_t *sd) ++{ ++ sd_trace(("%s: Entering\n", __FUNCTION__)); ++#if !defined(OOB_INTR_ONLY) ++ sd->intr_handler_valid = FALSE; ++ sd->intr_handler = NULL; ++ sd->intr_handler_arg = NULL; ++#endif /* !defined(OOB_INTR_ONLY) */ ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) ++{ ++ sd_trace(("%s: Entering\n", __FUNCTION__)); ++ *onoff = sd->client_intr_enabled; ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++#if defined(DHD_DEBUG) ++extern bool ++sdioh_interrupt_pending(sdioh_info_t *sd) ++{ ++ return 0; ++} ++#endif ++ ++/* Provide dstatus bits of spi-transaction for dhd layers. */ ++extern uint32 ++sdioh_get_dstatus(sdioh_info_t *sd) ++{ ++ return sd->card_dstatus; ++} ++ ++extern void ++sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev) ++{ ++ sd->chip = chip; ++ sd->chiprev = chiprev; ++} ++ ++extern void ++sdioh_dwordmode(sdioh_info_t *sd, bool set) ++{ ++ uint8 reg = 0; ++ int status; ++ ++ if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != ++ SUCCESS) { ++ sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (set) { ++ reg |= DWORD_PKT_LEN_EN; ++ sd->dwordmode = TRUE; ++ sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */ ++ } else { ++ reg &= ~DWORD_PKT_LEN_EN; ++ sd->dwordmode = FALSE; ++ sd->client_block_size[SPI_FUNC_2] = 2048; ++ } ++ ++ if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != ++ SUCCESS) { ++ sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); ++ return; ++ } ++} ++ ++ ++uint ++sdioh_query_iofnum(sdioh_info_t *sd) ++{ ++ return sd->num_funcs; ++} ++ ++/* IOVar table */ ++enum { ++ IOV_MSGLEVEL = 1, ++ IOV_BLOCKMODE, ++ IOV_BLOCKSIZE, ++ IOV_DMA, ++ IOV_USEINTS, ++ IOV_NUMINTS, ++ IOV_NUMLOCALINTS, ++ IOV_HOSTREG, ++ IOV_DEVREG, ++ IOV_DIVISOR, ++ IOV_SDMODE, ++ IOV_HISPEED, ++ IOV_HCIREGS, ++ IOV_POWER, ++ IOV_CLOCK, ++ IOV_SPIERRSTATS, ++ IOV_RESP_DELAY_ALL ++}; ++ ++const bcm_iovar_t sdioh_iovars[] = { ++ {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, ++ {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ ++ {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, ++ {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, ++ {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, ++ {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, ++ {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, ++ {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, ++ {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, ++ {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, ++ {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, ++ {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) }, ++ {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 }, ++ {NULL, 0, 0, 0, 0 } ++}; ++ ++int ++sdioh_iovar_op(sdioh_info_t *si, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ const bcm_iovar_t *vi = NULL; ++ int bcmerror = 0; ++ int val_size; ++ int32 int_val = 0; ++ bool bool_val; ++ uint32 actionid; ++/* ++ sdioh_regs_t *regs; ++*/ ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get must have return space; Set does not take qualifiers */ ++ ASSERT(set || (arg && len)); ++ ASSERT(!set || (!params && !plen)); ++ ++ sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); ++ ++ if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { ++ bcmerror = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 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)) ++ bcopy(params, &int_val, 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 = (int32)sd_msglevel; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_MSGLEVEL): ++ sd_msglevel = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_BLOCKSIZE): ++ if ((uint32)int_val > si->num_funcs) { ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ int_val = (int32)si->client_block_size[int_val]; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_DMA): ++ int_val = (int32)si->sd_use_dma; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DMA): ++ si->sd_use_dma = (bool)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_USEINTS): ++ int_val = (int32)si->use_client_ints; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_USEINTS): ++ break; ++ ++ case IOV_GVAL(IOV_DIVISOR): ++ int_val = (uint32)sd_divisor; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DIVISOR): ++ sd_divisor = int_val; ++ if (!spi_start_clock(si, (uint16)sd_divisor)) { ++ sd_err(("%s: set clock failed\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ } ++ break; ++ ++ case IOV_GVAL(IOV_POWER): ++ int_val = (uint32)sd_power; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_POWER): ++ sd_power = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_CLOCK): ++ int_val = (uint32)sd_clock; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_CLOCK): ++ sd_clock = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_SDMODE): ++ int_val = (uint32)sd_sdmode; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDMODE): ++ sd_sdmode = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_HISPEED): ++ int_val = (uint32)sd_hiok; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_HISPEED): ++ sd_hiok = int_val; ++ ++ if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) { ++ sd_err(("%s: Failed changing highspeed mode to %d.\n", ++ __FUNCTION__, sd_hiok)); ++ bcmerror = BCME_ERROR; ++ return ERROR; ++ } ++ break; ++ ++ case IOV_GVAL(IOV_NUMINTS): ++ int_val = (int32)si->intrcount; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_NUMLOCALINTS): ++ int_val = (int32)si->local_intrcount; ++ bcopy(&int_val, arg, val_size); ++ break; ++ case IOV_GVAL(IOV_DEVREG): ++ { ++ sdreg_t *sd_ptr = (sdreg_t *)params; ++ uint8 data; ++ ++ if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ ++ int_val = (int)data; ++ bcopy(&int_val, arg, sizeof(int_val)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_DEVREG): ++ { ++ sdreg_t *sd_ptr = (sdreg_t *)params; ++ uint8 data = (uint8)sd_ptr->value; ++ ++ if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ break; ++ } ++ ++ ++ case IOV_GVAL(IOV_SPIERRSTATS): ++ { ++ bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_SPIERRSTATS): ++ { ++ bzero(&si->spierrstats, sizeof(struct spierrstats_t)); ++ break; ++ } ++ ++ case IOV_GVAL(IOV_RESP_DELAY_ALL): ++ int_val = (int32)si->resp_delay_all; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_RESP_DELAY_ALL): ++ si->resp_delay_all = (bool)int_val; ++ int_val = STATUS_ENABLE|INTR_WITH_STATUS; ++ if (si->resp_delay_all) ++ int_val |= RESP_DELAY_ALL; ++ else { ++ if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1, ++ F1_RESPONSE_DELAY) != SUCCESS) { ++ sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ } ++ ++ if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val) ++ != SUCCESS) { ++ sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ break; ++ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++exit: ++ ++ return bcmerror; ++} ++ ++extern SDIOH_API_RC ++sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) ++{ ++ SDIOH_API_RC status; ++ /* No lock needed since sdioh_request_byte does locking */ ++ status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); ++ return status; ++} ++ ++extern SDIOH_API_RC ++sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) ++{ ++ /* No lock needed since sdioh_request_byte does locking */ ++ SDIOH_API_RC status; ++ ++ if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) { ++ uint8 dummy_data; ++ status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data); ++ if (status) { ++ sd_err(("sdioh_cfg_read() failed.\n")); ++ return status; ++ } ++ } ++ ++ status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); ++ return status; ++} ++ ++extern SDIOH_API_RC ++sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) ++{ ++ uint32 count; ++ int offset; ++ uint32 cis_byte; ++ uint16 *cis = (uint16 *)cisd; ++ uint bar0 = SI_ENUM_BASE; ++ int status; ++ uint8 data; ++ ++ sd_trace(("%s: Func %d\n", __FUNCTION__, func)); ++ ++ spi_lock(sd); ++ ++ /* Set sb window address to 0x18000000 */ ++ data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK; ++ status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data); ++ if (status == SUCCESS) { ++ data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK; ++ status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data); ++ } else { ++ sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); ++ spi_unlock(sd); ++ return (BCME_ERROR); ++ } ++ if (status == SUCCESS) { ++ data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK; ++ status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data); ++ } else { ++ sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); ++ spi_unlock(sd); ++ return (BCME_ERROR); ++ } ++ ++ offset = CC_SROM_OTP; /* OTP offset in chipcommon. */ ++ for (count = 0; count < length/2; count++) { ++ if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) { ++ sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); ++ spi_unlock(sd); ++ return (BCME_ERROR); ++ } ++ ++ *cis = (uint16)cis_byte; ++ cis++; ++ offset += 2; ++ } ++ ++ spi_unlock(sd); ++ ++ return (BCME_OK); ++} ++ ++extern SDIOH_API_RC ++sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) ++{ ++ int status; ++ uint32 cmd_arg; ++ uint32 dstatus; ++ uint32 data = (uint32)(*byte); ++ ++ spi_lock(sd); ++ ++ cmd_arg = 0; ++ cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); ++ cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ ++ cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); ++ cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1); ++ cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); ++ ++ if (rw == SDIOH_READ) { ++ sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x\n", ++ __FUNCTION__, cmd_arg, func, regaddr)); ++ } else { ++ sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", ++ __FUNCTION__, cmd_arg, func, regaddr, data)); ++ } ++ ++ if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) { ++ spi_unlock(sd); ++ return status; ++ } ++ ++ if (rw == SDIOH_READ) { ++ *byte = (uint8)data; ++ sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *byte)); ++ } ++ ++ bcmspi_cmd_getdstatus(sd, &dstatus); ++ if (dstatus) ++ sd_trace(("dstatus=0x%x\n", dstatus)); ++ ++ spi_unlock(sd); ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++extern SDIOH_API_RC ++sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, ++ uint32 *word, uint nbytes) ++{ ++ int status; ++ ++ spi_lock(sd); ++ ++ if (rw == SDIOH_READ) ++ status = bcmspi_card_regread(sd, func, addr, nbytes, word); ++ else ++ status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word); ++ ++ spi_unlock(sd); ++ return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); ++} ++ ++extern SDIOH_API_RC ++sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, ++ uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) ++{ ++ int len; ++ int buflen = (int)buflen_u; ++ bool fifo = (fix_inc == SDIOH_DATA_FIX); ++ ++ spi_lock(sd); ++ ++ ASSERT(reg_width == 4); ++ ASSERT(buflen_u < (1 << 30)); ++ ASSERT(sd->client_block_size[func]); ++ ++ sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", ++ __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', ++ buflen_u, sd->r_cnt, sd->t_cnt, pkt)); ++ ++ /* Break buffer down into blocksize chunks. */ ++ while (buflen > 0) { ++ len = MIN(sd->client_block_size[func], buflen); ++ if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { ++ sd_err(("%s: bcmspi_card_buf %s failed\n", ++ __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write")); ++ spi_unlock(sd); ++ return SDIOH_API_RC_FAIL; ++ } ++ buffer += len; ++ buflen -= len; ++ if (!fifo) ++ addr += len; ++ } ++ spi_unlock(sd); ++ return SDIOH_API_RC_SUCCESS; ++} ++ ++/* This function allows write to gspi bus when another rd/wr function is deep down the call stack. ++ * Its main aim is to have simpler spi writes rather than recursive writes. ++ * e.g. When there is a need to program response delay on the fly after detecting the SPI-func ++ * this call will allow to program the response delay. ++ */ ++static int ++bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte) ++{ ++ uint32 cmd_arg; ++ uint32 datalen = 1; ++ uint32 hostlen; ++ ++ cmd_arg = 0; ++ ++ cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); ++ cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ ++ cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); ++ cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); ++ cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen); ++ ++ sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); ++ ++ ++ /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen ++ * according to the wordlen mode(16/32bit) the device is in. ++ */ ++ ASSERT(sd->wordlen == 4 || sd->wordlen == 2); ++ datalen = ROUNDUP(datalen, sd->wordlen); ++ ++ /* Start by copying command in the spi-outbuffer */ ++ if (sd->wordlen == 4) { /* 32bit spid */ ++ *(uint32 *)spi_outbuf2 = SPISWAP_WD4(cmd_arg); ++ if (datalen & 0x3) ++ datalen += (4 - (datalen & 0x3)); ++ } else if (sd->wordlen == 2) { /* 16bit spid */ ++ *(uint32 *)spi_outbuf2 = SPISWAP_WD2(cmd_arg); ++ if (datalen & 0x1) ++ datalen++; ++ } else { ++ sd_err(("%s: Host is %d bit spid, could not create SPI command.\n", ++ __FUNCTION__, 8 * sd->wordlen)); ++ return ERROR; ++ } ++ ++ /* for Write, put the data into the output buffer */ ++ if (datalen != 0) { ++ if (sd->wordlen == 4) { /* 32bit spid */ ++ *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD4(byte); ++ } else if (sd->wordlen == 2) { /* 16bit spid */ ++ *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD2(byte); ++ } ++ } ++ ++ /* +4 for cmd, +4 for dstatus */ ++ hostlen = datalen + 8; ++ hostlen += (4 - (hostlen & 0x3)); ++ spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen); ++ ++ /* Last 4bytes are dstatus. Device is configured to return status bits. */ ++ if (sd->wordlen == 4) { /* 32bit spid */ ++ sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); ++ } else if (sd->wordlen == 2) { /* 16bit spid */ ++ sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); ++ } else { ++ sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", ++ __FUNCTION__, 8 * sd->wordlen)); ++ return ERROR; ++ } ++ ++ if (sd->card_dstatus) ++ sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus)); ++ ++ return (BCME_OK); ++} ++ ++/* Program the response delay corresponding to the spi function */ ++static int ++bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay) ++{ ++ if (sd->resp_delay_all == FALSE) ++ return (BCME_OK); ++ ++ if (sd->prev_fun == func) ++ return (BCME_OK); ++ ++ if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY) ++ return (BCME_OK); ++ ++ bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay); ++ ++ /* Remember function for which to avoid reprogramming resp-delay in next iteration */ ++ sd->prev_fun = func; ++ ++ return (BCME_OK); ++ ++} ++ ++#define GSPI_RESYNC_PATTERN 0x0 ++ ++/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI. ++ * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is ++ * synchronised and all queued resuests are cancelled. ++ */ ++static int ++bcmspi_resync_f1(sdioh_info_t *sd) ++{ ++ uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0; ++ ++ ++ /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen ++ * according to the wordlen mode(16/32bit) the device is in. ++ */ ++ ASSERT(sd->wordlen == 4 || sd->wordlen == 2); ++ datalen = ROUNDUP(datalen, sd->wordlen); ++ ++ /* Start by copying command in the spi-outbuffer */ ++ *(uint32 *)spi_outbuf2 = cmd_arg; ++ ++ /* for Write, put the data into the output buffer */ ++ *(uint32 *)&spi_outbuf2[CMDLEN] = data; ++ ++ /* +4 for cmd, +4 for dstatus */ ++ spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8); ++ ++ /* Last 4bytes are dstatus. Device is configured to return status bits. */ ++ if (sd->wordlen == 4) { /* 32bit spid */ ++ sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); ++ } else if (sd->wordlen == 2) { /* 16bit spid */ ++ sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); ++ } else { ++ sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", ++ __FUNCTION__, 8 * sd->wordlen)); ++ return ERROR; ++ } ++ ++ if (sd->card_dstatus) ++ sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus)); ++ ++ return (BCME_OK); ++} ++ ++uint32 dstatus_count = 0; ++ ++static int ++bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg) ++{ ++ uint32 dstatus = sd->card_dstatus; ++ struct spierrstats_t *spierrstats = &sd->spierrstats; ++ int err = SUCCESS; ++ ++ sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus)); ++ ++ /* Store dstatus of last few gSPI transactions */ ++ spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus; ++ spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg; ++ dstatus_count++; ++ ++ if (sd->card_init_done == FALSE) ++ return err; ++ ++ if (dstatus & STATUS_DATA_NOT_AVAILABLE) { ++ spierrstats->dna++; ++ sd_trace(("Read data not available on F1 addr = 0x%x\n", ++ GFIELD(cmd_arg, SPI_REG_ADDR))); ++ /* Clear dna bit */ ++ bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE); ++ } ++ ++ if (dstatus & STATUS_UNDERFLOW) { ++ spierrstats->rdunderflow++; ++ sd_err(("FIFO underflow happened due to current F2 read command.\n")); ++ } ++ ++ if (dstatus & STATUS_OVERFLOW) { ++ spierrstats->wroverflow++; ++ sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n")); ++ bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW); ++ bcmspi_resync_f1(sd); ++ sd_err(("Recovering from F1 FIFO overflow.\n")); ++ } ++ ++ if (dstatus & STATUS_F2_INTR) { ++ spierrstats->f2interrupt++; ++ sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n")); ++ } ++ ++ if (dstatus & STATUS_F3_INTR) { ++ spierrstats->f3interrupt++; ++ sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n")); ++ } ++ ++ if (dstatus & STATUS_HOST_CMD_DATA_ERR) { ++ spierrstats->hostcmddataerr++; ++ sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n")); ++ } ++ ++ if (dstatus & STATUS_F2_PKT_AVAILABLE) { ++ spierrstats->f2pktavailable++; ++ sd_trace(("Packet is available/ready in F2 TX FIFO\n")); ++ sd_trace(("Packet length = %d\n", sd->dwordmode ? ++ ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) : ++ ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT))); ++ } ++ ++ if (dstatus & STATUS_F3_PKT_AVAILABLE) { ++ spierrstats->f3pktavailable++; ++ sd_err(("Packet is available/ready in F3 TX FIFO\n")); ++ sd_err(("Packet length = %d\n", ++ (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT)); ++ } ++ ++ return err; ++} ++ ++extern int ++sdioh_abort(sdioh_info_t *sd, uint func) ++{ ++ return 0; ++} ++ ++int ++sdioh_start(sdioh_info_t *sd, int stage) ++{ ++ return SUCCESS; ++} ++ ++int ++sdioh_stop(sdioh_info_t *sd) ++{ ++ return SUCCESS; ++} ++ ++int ++sdioh_waitlockfree(sdioh_info_t *sd) ++{ ++ return SUCCESS; ++} ++ ++ ++/* ++ * Private/Static work routines ++ */ ++static int ++bcmspi_host_init(sdioh_info_t *sd) ++{ ++ ++ /* Default power on mode */ ++ sd->sd_mode = SDIOH_MODE_SPI; ++ sd->polled_mode = TRUE; ++ sd->host_init_done = TRUE; ++ sd->card_init_done = FALSE; ++ sd->adapter_slot = 1; ++ ++ return (SUCCESS); ++} ++ ++static int ++get_client_blocksize(sdioh_info_t *sd) ++{ ++ uint32 regdata[2]; ++ int status; ++ ++ /* Find F1/F2/F3 max packet size */ ++ if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG, ++ 8, regdata)) != SUCCESS) { ++ return status; ++ } ++ ++ sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n", ++ regdata[0], regdata[1])); ++ ++ sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2; ++ sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1])); ++ ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1); ++ ++ sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2; ++ sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2])); ++ ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2); ++ ++ sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2; ++ sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3])); ++ ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3); ++ ++ return 0; ++} ++ ++static int ++bcmspi_client_init(sdioh_info_t *sd) ++{ ++ uint32 status_en_reg = 0; ++ sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); ++ ++#ifdef HSMODE ++ if (!spi_start_clock(sd, (uint16)sd_divisor)) { ++ sd_err(("spi_start_clock failed\n")); ++ return ERROR; ++ } ++#else ++ /* Start at ~400KHz clock rate for initialization */ ++ if (!spi_start_clock(sd, 128)) { ++ sd_err(("spi_start_clock failed\n")); ++ return ERROR; ++ } ++#endif /* HSMODE */ ++ ++ if (!bcmspi_host_device_init_adapt(sd)) { ++ sd_err(("bcmspi_host_device_init_adapt failed\n")); ++ return ERROR; ++ } ++ ++ if (!bcmspi_test_card(sd)) { ++ sd_err(("bcmspi_test_card failed\n")); ++ return ERROR; ++ } ++ ++ sd->num_funcs = SPI_MAX_IOFUNCS; ++ ++ get_client_blocksize(sd); ++ ++ /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */ ++ bcmspi_resync_f1(sd); ++ ++ sd->dwordmode = FALSE; ++ ++ bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg); ++ ++ sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__)); ++ status_en_reg |= INTR_WITH_STATUS; ++ ++ if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, ++ status_en_reg & 0xff) != SUCCESS) { ++ sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__)); ++ return ERROR; ++ } ++ ++#ifndef HSMODE ++ /* After configuring for High-Speed mode, set the desired clock rate. */ ++ if (!spi_start_clock(sd, 4)) { ++ sd_err(("spi_start_clock failed\n")); ++ return ERROR; ++ } ++#endif /* HSMODE */ ++ ++ /* check to see if the response delay needs to be programmed properly */ ++ { ++ uint32 f1_respdelay = 0; ++ bcmspi_card_regread(sd, 0, SPID_RESP_DELAY_F1, 1, &f1_respdelay); ++ if ((f1_respdelay == 0) || (f1_respdelay == 0xFF)) { ++ /* older sdiodevice core and has no separte resp delay for each of */ ++ sd_err(("older corerev < 4 so use the same resp delay for all funcs\n")); ++ sd->resp_delay_new = FALSE; ++ } ++ else { ++ /* older sdiodevice core and has no separte resp delay for each of */ ++ int ret_val; ++ sd->resp_delay_new = TRUE; ++ sd_err(("new corerev >= 4 so set the resp delay for each of the funcs\n")); ++ sd_trace(("resp delay for funcs f0(%d), f1(%d), f2(%d), f3(%d)\n", ++ GSPI_F0_RESP_DELAY, GSPI_F1_RESP_DELAY, ++ GSPI_F2_RESP_DELAY, GSPI_F3_RESP_DELAY)); ++ ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F0, 1, ++ GSPI_F0_RESP_DELAY); ++ if (ret_val != SUCCESS) { ++ sd_err(("%s: Unable to set response delay for F0\n", __FUNCTION__)); ++ return ERROR; ++ } ++ ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F1, 1, ++ GSPI_F1_RESP_DELAY); ++ if (ret_val != SUCCESS) { ++ sd_err(("%s: Unable to set response delay for F1\n", __FUNCTION__)); ++ return ERROR; ++ } ++ ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F2, 1, ++ GSPI_F2_RESP_DELAY); ++ if (ret_val != SUCCESS) { ++ sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); ++ return ERROR; ++ } ++ ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F3, 1, ++ GSPI_F3_RESP_DELAY); ++ if (ret_val != SUCCESS) { ++ sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); ++ return ERROR; ++ } ++ } ++ } ++ ++ ++ sd->card_init_done = TRUE; ++ ++ /* get the device rev to program the prop respdelays */ ++ ++ return SUCCESS; ++} ++ ++static int ++bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode) ++{ ++ uint32 regdata; ++ int status; ++ ++ if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG, ++ 4, ®data)) != SUCCESS) ++ return status; ++ ++ sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata)); ++ ++ ++ if (hsmode == TRUE) { ++ sd_trace(("Attempting to enable High-Speed mode.\n")); ++ ++ if (regdata & HIGH_SPEED_MODE) { ++ sd_trace(("Device is already in High-Speed mode.\n")); ++ return status; ++ } else { ++ regdata |= HIGH_SPEED_MODE; ++ sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); ++ if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, ++ 4, regdata)) != SUCCESS) { ++ return status; ++ } ++ } ++ } else { ++ sd_trace(("Attempting to disable High-Speed mode.\n")); ++ ++ if (regdata & HIGH_SPEED_MODE) { ++ regdata &= ~HIGH_SPEED_MODE; ++ sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); ++ if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, ++ 4, regdata)) != SUCCESS) ++ return status; ++ } ++ else { ++ sd_trace(("Device is already in Low-Speed mode.\n")); ++ return status; ++ } ++ } ++ spi_controller_highspeed_mode(sd, hsmode); ++ ++ return TRUE; ++} ++ ++#define bcmspi_find_curr_mode(sd) { \ ++ sd->wordlen = 2; \ ++ status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ ++ regdata &= 0xff; \ ++ if ((regdata == 0xad) || (regdata == 0x5b) || \ ++ (regdata == 0x5d) || (regdata == 0x5a)) \ ++ break; \ ++ sd->wordlen = 4; \ ++ status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ ++ regdata &= 0xff; \ ++ if ((regdata == 0xad) || (regdata == 0x5b) || \ ++ (regdata == 0x5d) || (regdata == 0x5a)) \ ++ break; \ ++ sd_trace(("Silicon testability issue: regdata = 0x%x." \ ++ " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \ ++ OSL_DELAY(100000); \ ++} ++ ++#define INIT_ADAPT_LOOP 100 ++ ++/* Adapt clock-phase-speed-bitwidth between host and device */ ++static bool ++bcmspi_host_device_init_adapt(sdioh_info_t *sd) ++{ ++ uint32 wrregdata, regdata = 0; ++ int status; ++ int i; ++ ++ /* Due to a silicon testability issue, the first command from the Host ++ * to the device will get corrupted (first bit will be lost). So the ++ * Host should poll the device with a safe read request. ie: The Host ++ * should try to read F0 addr 0x14 using the Fixed address mode ++ * (This will prevent a unintended write command to be detected by device) ++ */ ++ for (i = 0; i < INIT_ADAPT_LOOP; i++) { ++ /* If device was not power-cycled it will stay in 32bit mode with ++ * response-delay-all bit set. Alternate the iteration so that ++ * read either with or without response-delay for F0 to succeed. ++ */ ++ bcmspi_find_curr_mode(sd); ++ sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE; ++ ++ bcmspi_find_curr_mode(sd); ++ sd->dwordmode = TRUE; ++ ++ bcmspi_find_curr_mode(sd); ++ sd->dwordmode = FALSE; ++ } ++ ++ /* Bail out, device not detected */ ++ if (i == INIT_ADAPT_LOOP) ++ return FALSE; ++ ++ /* Softreset the spid logic */ ++ if ((sd->dwordmode) || (sd->wordlen == 4)) { ++ bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI); ++ bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, ®data); ++ sd_trace(("reset reg read = 0x%x\n", regdata)); ++ sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode, ++ sd->wordlen, sd->resp_delay_all)); ++ /* Restore default state after softreset */ ++ sd->wordlen = 2; ++ sd->dwordmode = FALSE; ++ } ++ ++ if (sd->wordlen == 4) { ++ if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != ++ SUCCESS) ++ return FALSE; ++ if (regdata == TEST_RO_DATA_32BIT_LE) { ++ sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n", ++ regdata)); ++ sd_trace(("Spid power was left on.\n")); ++ } else { ++ sd_err(("Spid power was left on but signature read failed." ++ " Value read = 0x%x\n", regdata)); ++ return FALSE; ++ } ++ } else { ++ sd->wordlen = 2; ++ ++#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */ ++ ++ wrregdata = (CTRL_REG_DEFAULT); ++ ++ if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) ++ return FALSE; ++ sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata)); ++ ++#ifndef HSMODE ++ wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY); ++ wrregdata &= ~HIGH_SPEED_MODE; ++ bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); ++#endif /* HSMODE */ ++ ++ for (i = 0; i < INIT_ADAPT_LOOP; i++) { ++ if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) { ++ sd_trace(("0xfeedbead was leftshifted by 1-bit.\n")); ++ if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ++ ®data)) != SUCCESS) ++ return FALSE; ++ } ++ OSL_DELAY(1000); ++ } ++ ++#if defined(CHANGE_SPI_INTR_POLARITY_ACTIVE_HIGH) ++ /* Change to host controller intr-polarity of active-high */ ++ wrregdata |= INTR_POLARITY; ++#else ++ /* Change to host controller intr-polarity of active-low */ ++ wrregdata &= ~INTR_POLARITY; ++#endif /* CHANGE_SPI_INTR_POLARITY_ACTIVE_HIGH */ ++ ++ sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n", ++ wrregdata)); ++ /* Change to 32bit mode */ ++ wrregdata |= WORD_LENGTH_32; ++ bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); ++ ++ /* Change command/data packaging in 32bit LE mode */ ++ sd->wordlen = 4; ++ ++ if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) ++ return FALSE; ++ ++ if (regdata == TEST_RO_DATA_32BIT_LE) { ++ sd_trace(("Read spid passed. Value read = 0x%x\n", regdata)); ++ sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n")); ++ } else { ++ sd_err(("Stale spid reg values read as it was kept powered. Value read =" ++ "0x%x\n", regdata)); ++ return FALSE; ++ } ++ } ++ ++ ++ return TRUE; ++} ++ ++static bool ++bcmspi_test_card(sdioh_info_t *sd) ++{ ++ uint32 regdata; ++ int status; ++ ++ if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) ++ return FALSE; ++ ++ if (regdata == (TEST_RO_DATA_32BIT_LE)) ++ sd_trace(("32bit LE regdata = 0x%x\n", regdata)); ++ else { ++ sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata)); ++ return FALSE; ++ } ++ ++ ++#define RW_PATTERN1 0xA0A1A2A3 ++#define RW_PATTERN2 0x4B5B6B7B ++ ++ regdata = RW_PATTERN1; ++ if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) ++ return FALSE; ++ regdata = 0; ++ if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) ++ return FALSE; ++ if (regdata != RW_PATTERN1) { ++ sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", ++ RW_PATTERN1, regdata)); ++ return FALSE; ++ } else ++ sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); ++ ++ regdata = RW_PATTERN2; ++ if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) ++ return FALSE; ++ regdata = 0; ++ if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) ++ return FALSE; ++ if (regdata != RW_PATTERN2) { ++ sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", ++ RW_PATTERN2, regdata)); ++ return FALSE; ++ } else ++ sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); ++ ++ return TRUE; ++} ++ ++static int ++bcmspi_driver_init(sdioh_info_t *sd) ++{ ++ sd_trace(("%s\n", __FUNCTION__)); ++ if ((bcmspi_host_init(sd)) != SUCCESS) { ++ return ERROR; ++ } ++ ++ if (bcmspi_client_init(sd) != SUCCESS) { ++ return ERROR; ++ } ++ ++ return SUCCESS; ++} ++ ++/* Read device reg */ ++static int ++bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) ++{ ++ int status; ++ uint32 cmd_arg, dstatus; ++ ++ ASSERT(regsize); ++ ++ if (func == 2) ++ sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); ++ ++ cmd_arg = 0; ++ cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); ++ cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ ++ cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); ++ cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); ++ cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); ++ ++ sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", ++ __FUNCTION__, cmd_arg, func, regaddr, regsize)); ++ ++ if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) ++ return status; ++ ++ bcmspi_cmd_getdstatus(sd, &dstatus); ++ if (dstatus) ++ sd_trace(("dstatus =0x%x\n", dstatus)); ++ ++ return SUCCESS; ++} ++ ++static int ++bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) ++{ ++ ++ int status; ++ uint32 cmd_arg; ++ uint32 dstatus; ++ ++ ASSERT(regsize); ++ ++ if (func == 2) ++ sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); ++ ++ cmd_arg = 0; ++ cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); ++ cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */ ++ cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); ++ cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); ++ cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize); ++ ++ sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", ++ __FUNCTION__, cmd_arg, func, regaddr, regsize)); ++ ++ if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) ++ return status; ++ ++ sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *data)); ++ ++ bcmspi_cmd_getdstatus(sd, &dstatus); ++ sd_trace(("dstatus =0x%x\n", dstatus)); ++ return SUCCESS; ++} ++ ++/* write a device register */ ++static int ++bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) ++{ ++ int status; ++ uint32 cmd_arg, dstatus; ++ ++ ASSERT(regsize); ++ ++ cmd_arg = 0; ++ ++ cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); ++ cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ ++ cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); ++ cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); ++ cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); ++ ++ sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d data=0x%x\n", ++ __FUNCTION__, cmd_arg, func, regaddr, regsize, data)); ++ ++ if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize)) != SUCCESS) ++ return status; ++ ++ bcmspi_cmd_getdstatus(sd, &dstatus); ++ if (dstatus) ++ sd_trace(("dstatus=0x%x\n", dstatus)); ++ ++ return SUCCESS; ++} ++ ++/* write a device register - 1 byte */ ++static int ++bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte) ++{ ++ int status; ++ uint32 cmd_arg; ++ uint32 dstatus; ++ uint32 data = (uint32)(*byte); ++ ++ cmd_arg = 0; ++ cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); ++ cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ ++ cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); ++ cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); ++ cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); ++ ++ sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", ++ __FUNCTION__, cmd_arg, func, regaddr, data)); ++ ++ if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) ++ return status; ++ ++ bcmspi_cmd_getdstatus(sd, &dstatus); ++ if (dstatus) ++ sd_trace(("dstatus =0x%x\n", dstatus)); ++ ++ return SUCCESS; ++} ++ ++void ++bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer) ++{ ++ *dstatus_buffer = sd->card_dstatus; ++} ++ ++/* 'data' is of type uint32 whereas other buffers are of type uint8 */ ++static int ++bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, ++ uint32 *data, uint32 datalen) ++{ ++ uint32 i, j; ++ uint8 resp_delay = 0; ++ int err = SUCCESS; ++ uint32 hostlen; ++ uint32 spilen = 0; ++ uint32 dstatus_idx = 0; ++ uint16 templen, buslen, len, *ptr = NULL; ++ ++ sd_trace(("spi cmd = 0x%x\n", cmd_arg)); ++ ++ /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen ++ * according to the wordlen mode(16/32bit) the device is in. ++ */ ++ if (sd->wordlen == 4) { /* 32bit spid */ ++ *(uint32 *)spi_outbuf = SPISWAP_WD4(cmd_arg); ++ if (datalen & 0x3) ++ datalen += (4 - (datalen & 0x3)); ++ } else if (sd->wordlen == 2) { /* 16bit spid */ ++ *(uint32 *)spi_outbuf = SPISWAP_WD2(cmd_arg); ++ if (datalen & 0x1) ++ datalen++; ++ if (datalen < 4) ++ datalen = ROUNDUP(datalen, 4); ++ } else { ++ sd_err(("Host is %d bit spid, could not create SPI command.\n", ++ 8 * sd->wordlen)); ++ return ERROR; ++ } ++ ++ /* for Write, put the data into the output buffer */ ++ if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) { ++ /* We send len field of hw-header always a mod16 size, both from host and dongle */ ++ if (datalen != 0) { ++ for (i = 0; i < datalen/4; i++) { ++ if (sd->wordlen == 4) { /* 32bit spid */ ++ *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = ++ SPISWAP_WD4(data[i]); ++ } else if (sd->wordlen == 2) { /* 16bit spid */ ++ *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = ++ SPISWAP_WD2(data[i]); ++ } ++ } ++ } ++ } ++ ++ /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */ ++ if ((GFIELD(cmd_arg, SPI_RW_FLAG) == 0)) { ++ int func = GFIELD(cmd_arg, SPI_FUNCTION); ++ switch (func) { ++ case 0: ++ if (sd->resp_delay_new) ++ resp_delay = GSPI_F0_RESP_DELAY; ++ else ++ resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0; ++ break; ++ case 1: ++ if (sd->resp_delay_new) ++ resp_delay = GSPI_F1_RESP_DELAY; ++ else ++ resp_delay = F1_RESPONSE_DELAY; ++ break; ++ case 2: ++ if (sd->resp_delay_new) ++ resp_delay = GSPI_F2_RESP_DELAY; ++ else ++ resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0; ++ break; ++ default: ++ ASSERT(0); ++ break; ++ } ++ /* Program response delay */ ++ if (sd->resp_delay_new == FALSE) ++ bcmspi_prog_resp_delay(sd, func, resp_delay); ++ } ++ ++ /* +4 for cmd and +4 for dstatus */ ++ hostlen = datalen + 8 + resp_delay; ++ hostlen += dstatus_idx; ++ hostlen += (4 - (hostlen & 0x3)); ++ spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen); ++ ++ /* for Read, get the data into the input buffer */ ++ if (datalen != 0) { ++ if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */ ++ for (j = 0; j < datalen/4; j++) { ++ if (sd->wordlen == 4) { /* 32bit spid */ ++ data[j] = SPISWAP_WD4(*(uint32 *)&spi_inbuf[j * 4 + ++ CMDLEN + resp_delay]); ++ } else if (sd->wordlen == 2) { /* 16bit spid */ ++ data[j] = SPISWAP_WD2(*(uint32 *)&spi_inbuf[j * 4 + ++ CMDLEN + resp_delay]); ++ } ++ } ++ } ++ } ++ ++ dstatus_idx += (datalen + CMDLEN + resp_delay); ++ /* Last 4bytes are dstatus. Device is configured to return status bits. */ ++ if (sd->wordlen == 4) { /* 32bit spid */ ++ sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf[dstatus_idx]); ++ } else if (sd->wordlen == 2) { /* 16bit spid */ ++ sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf[dstatus_idx]); ++ } else { ++ sd_err(("Host is %d bit machine, could not read SPI dstatus.\n", ++ 8 * sd->wordlen)); ++ return ERROR; ++ } ++ if (sd->card_dstatus == 0xffffffff) { ++ sd_err(("looks like not a GSPI device or device is not powered.\n")); ++ } ++ ++ err = bcmspi_update_stats(sd, cmd_arg); ++ ++ return err; ++ ++} ++ ++static int ++bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, ++ uint32 addr, int nbytes, uint32 *data) ++{ ++ int status; ++ uint32 cmd_arg; ++ bool write = rw == SDIOH_READ ? 0 : 1; ++ uint retries = 0; ++ ++ bool enable; ++ uint32 spilen; ++ ++ cmd_arg = 0; ++ ++ ASSERT(nbytes); ++ ASSERT(nbytes <= sd->client_block_size[func]); ++ ++ if (write) sd->t_cnt++; else sd->r_cnt++; ++ ++ if (func == 2) { ++ /* Frame len check limited by gSPI. */ ++ if ((nbytes > 2000) && write) { ++ sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes)); ++ } ++ /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */ ++ /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */ ++ if (write) { ++ uint32 dstatus; ++ /* check F2 ready with cached one */ ++ bcmspi_cmd_getdstatus(sd, &dstatus); ++ if ((dstatus & STATUS_F2_RX_READY) == 0) { ++ retries = WAIT_F2RXFIFORDY; ++ enable = 0; ++ while (retries-- && !enable) { ++ OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000); ++ bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4, ++ &dstatus); ++ if (dstatus & STATUS_F2_RX_READY) ++ enable = TRUE; ++ } ++ if (!enable) { ++ struct spierrstats_t *spierrstats = &sd->spierrstats; ++ spierrstats->f2rxnotready++; ++ sd_err(("F2 FIFO is not ready to receive data.\n")); ++ return ERROR; ++ } ++ sd_trace(("No of retries on F2 ready %d\n", ++ (WAIT_F2RXFIFORDY - retries))); ++ } ++ } ++ } ++ ++ /* F2 transfers happen on 0 addr */ ++ addr = (func == 2) ? 0 : addr; ++ ++ /* In pio mode buffer is read using fixed address fifo in func 1 */ ++ if ((func == 1) && (fifo)) ++ cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); ++ else ++ cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); ++ ++ cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); ++ cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr); ++ cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write); ++ spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes); ++ if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { ++ /* convert len to mod4 size */ ++ spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0); ++ cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); ++ } else ++ cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen); ++ ++ if ((func == 2) && (fifo == 1)) { ++ sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", ++ __FUNCTION__, write ? "Wr" : "Rd", func, "INCR", ++ addr, nbytes, sd->r_cnt, sd->t_cnt)); ++ } ++ ++ sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); ++ sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", ++ __FUNCTION__, write ? "Wd" : "Rd", func, "INCR", ++ addr, nbytes, sd->r_cnt, sd->t_cnt)); ++ ++ ++ if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, nbytes)) != SUCCESS) { ++ sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, ++ (write ? "write" : "read"))); ++ return status; ++ } ++ ++ /* gSPI expects that hw-header-len is equal to spi-command-len */ ++ if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) { ++ ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff)); ++ ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16))); ++ } ++ ++ if ((nbytes > 2000) && !write) { ++ sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes)); ++ } ++ ++ return SUCCESS; ++} ++ ++/* Reset and re-initialize the device */ ++int ++sdioh_sdio_reset(sdioh_info_t *si) ++{ ++ si->card_init_done = FALSE; ++ return bcmspi_client_init(si); ++} ++ ++SDIOH_API_RC ++sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) ++{ ++ return SDIOH_API_RC_FAIL; ++} ++ ++SDIOH_API_RC ++sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) ++{ ++ return SDIOH_API_RC_FAIL; ++} ++ ++bool ++sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) ++{ ++ return FALSE; ++} ++ ++SDIOH_API_RC ++sdioh_gpio_init(sdioh_info_t *sd) ++{ ++ return SDIOH_API_RC_FAIL; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmutils.c b/module_drivers/drivers/net/wireless/bcmdhd/bcmutils.c +new file mode 100644 +index 000000000..1ba8481c5 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmutils.c +@@ -0,0 +1,4106 @@ ++/* ++ * Driver O/S-independent utility routines ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmutils.c 699163 2017-05-12 05:18:23Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#ifdef BCMDRIVER ++ ++#include ++#include ++ ++#else /* !BCMDRIVER */ ++ ++#include ++#include ++#include ++ ++#if defined(BCMEXTSUP) ++#include ++#endif ++ ++#ifndef ASSERT ++#define ASSERT(exp) ++#endif ++ ++#endif /* !BCMDRIVER */ ++ ++#include ++#include ++#include ++#include ++#include ++#include <802.1d.h> ++#include <802.11.h> ++#include ++#include ++#include ++ ++/* Look-up table to calculate head room present in a number */ ++static const uint8 msb_table[] = { ++ 0, 1, 2, 2, 3, 3, 3, 3, ++ 4, 4, 4, 4, 4, 4, 4, 4, ++ 5, 5, 5, 5, 5, 5, 5, 5, ++ 5, 5, 5, 5, 5, 5, 5, 5, ++ 6, 6, 6, 6, 6, 6, 6, 6, ++ 6, 6, 6, 6, 6, 6, 6, 6, ++ 6, 6, 6, 6, 6, 6, 6, 6, ++ 6, 6, 6, 6, 6, 6, 6, 6, ++ 7, 7, 7, 7, 7, 7, 7, 7, ++ 7, 7, 7, 7, 7, 7, 7, 7, ++ 7, 7, 7, 7, 7, 7, 7, 7, ++ 7, 7, 7, 7, 7, 7, 7, 7, ++ 7, 7, 7, 7, 7, 7, 7, 7, ++ 7, 7, 7, 7, 7, 7, 7, 7, ++ 7, 7, 7, 7, 7, 7, 7, 7, ++ 7, 7, 7, 7, 7, 7, 7, 7, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++}; ++ ++void *_bcmutils_dummy_fn = NULL; ++ ++ ++ ++ ++#ifdef BCMDRIVER ++ ++ ++/* copy a pkt buffer chain into a buffer */ ++uint ++pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) ++{ ++ uint n, ret = 0; ++ ++ if (len < 0) ++ len = 4096; /* "infinite" */ ++ ++ /* skip 'offset' bytes */ ++ for (; p && offset; p = PKTNEXT(osh, p)) { ++ if (offset < (uint)PKTLEN(osh, p)) ++ break; ++ offset -= PKTLEN(osh, p); ++ } ++ ++ if (!p) ++ return 0; ++ ++ /* copy the data */ ++ for (; p && len; p = PKTNEXT(osh, p)) { ++ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); ++ bcopy(PKTDATA(osh, p) + offset, buf, n); ++ buf += n; ++ len -= n; ++ ret += n; ++ offset = 0; ++ } ++ ++ return ret; ++} ++ ++/* copy a buffer into a pkt buffer chain */ ++uint ++pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) ++{ ++ uint n, ret = 0; ++ ++ ++ /* skip 'offset' bytes */ ++ for (; p && offset; p = PKTNEXT(osh, p)) { ++ if (offset < (uint)PKTLEN(osh, p)) ++ break; ++ offset -= PKTLEN(osh, p); ++ } ++ ++ if (!p) ++ return 0; ++ ++ /* copy the data */ ++ for (; p && len; p = PKTNEXT(osh, p)) { ++ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); ++ bcopy(buf, PKTDATA(osh, p) + offset, n); ++ buf += n; ++ len -= n; ++ ret += n; ++ offset = 0; ++ } ++ ++ return ret; ++} ++ ++ ++ ++/* return total length of buffer chain */ ++uint BCMFASTPATH ++pkttotlen(osl_t *osh, void *p) ++{ ++ uint total; ++ int len; ++ ++ total = 0; ++ for (; p; p = PKTNEXT(osh, p)) { ++ len = PKTLEN(osh, p); ++ total += len; ++#ifdef BCMLFRAG ++ if (BCMLFRAG_ENAB()) { ++ if (PKTISFRAG(osh, p)) { ++ total += PKTFRAGTOTLEN(osh, p); ++ } ++ } ++#endif ++ } ++ ++ return (total); ++} ++ ++/* return the last buffer of chained pkt */ ++void * ++pktlast(osl_t *osh, void *p) ++{ ++ for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) ++ ; ++ ++ return (p); ++} ++ ++/* count segments of a chained packet */ ++uint BCMFASTPATH ++pktsegcnt(osl_t *osh, void *p) ++{ ++ uint cnt; ++ ++ for (cnt = 0; p; p = PKTNEXT(osh, p)) { ++ cnt++; ++#ifdef BCMLFRAG ++ if (BCMLFRAG_ENAB()) { ++ if (PKTISFRAG(osh, p)) { ++ cnt += PKTFRAGTOTNUM(osh, p); ++ } ++ } ++#endif ++ } ++ ++ return cnt; ++} ++ ++ ++/* count segments of a chained packet */ ++uint BCMFASTPATH ++pktsegcnt_war(osl_t *osh, void *p) ++{ ++ uint cnt; ++ uint8 *pktdata; ++ uint len, remain, align64; ++ ++ for (cnt = 0; p; p = PKTNEXT(osh, p)) { ++ cnt++; ++ len = PKTLEN(osh, p); ++ if (len > 128) { ++ pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ ++ /* Check for page boundary straddle (2048B) */ ++ if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) ++ cnt++; ++ ++ align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ ++ align64 = (64 - align64) & 0x3f; ++ len -= align64; /* bytes from aligned 64B to end */ ++ /* if aligned to 128B, check for MOD 128 between 1 to 4B */ ++ remain = len % 128; ++ if (remain > 0 && remain <= 4) ++ cnt++; /* add extra seg */ ++ } ++ } ++ ++ return cnt; ++} ++ ++uint8 * BCMFASTPATH ++pktdataoffset(osl_t *osh, void *p, uint offset) ++{ ++ uint total = pkttotlen(osh, p); ++ uint pkt_off = 0, len = 0; ++ uint8 *pdata = (uint8 *) PKTDATA(osh, p); ++ ++ if (offset > total) ++ return NULL; ++ ++ for (; p; p = PKTNEXT(osh, p)) { ++ pdata = (uint8 *) PKTDATA(osh, p); ++ pkt_off = offset - len; ++ len += PKTLEN(osh, p); ++ if (len > offset) ++ break; ++ } ++ return (uint8*) (pdata+pkt_off); ++} ++ ++ ++/* given a offset in pdata, find the pkt seg hdr */ ++void * ++pktoffset(osl_t *osh, void *p, uint offset) ++{ ++ uint total = pkttotlen(osh, p); ++ uint len = 0; ++ ++ if (offset > total) ++ return NULL; ++ ++ for (; p; p = PKTNEXT(osh, p)) { ++ len += PKTLEN(osh, p); ++ if (len > offset) ++ break; ++ } ++ return p; ++} ++ ++#endif /* BCMDRIVER */ ++ ++#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) ++const unsigned char bcm_ctype[] = { ++ ++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ ++ _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, ++ _BCM_C, /* 8-15 */ ++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ ++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ ++ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ ++ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ ++ _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ ++ _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ ++ _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, ++ _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ ++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ ++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ ++ _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ ++ _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, ++ _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ ++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ ++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ ++ _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ ++ _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, ++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ ++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, ++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, ++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, ++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ ++}; ++ ++ulong ++bcm_strtoul(const char *cp, char **endp, uint base) ++{ ++ ulong result, last_result = 0, value; ++ bool minus; ++ ++ minus = FALSE; ++ ++ while (bcm_isspace(*cp)) ++ cp++; ++ ++ if (cp[0] == '+') ++ cp++; ++ else if (cp[0] == '-') { ++ minus = TRUE; ++ cp++; ++ } ++ ++ if (base == 0) { ++ if (cp[0] == '0') { ++ if ((cp[1] == 'x') || (cp[1] == 'X')) { ++ base = 16; ++ cp = &cp[2]; ++ } else { ++ base = 8; ++ cp = &cp[1]; ++ } ++ } else ++ base = 10; ++ } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { ++ cp = &cp[2]; ++ } ++ ++ result = 0; ++ ++ while (bcm_isxdigit(*cp) && ++ (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { ++ result = result*base + value; ++ /* Detected overflow */ ++ if (result < last_result && !minus) { ++ if (endp) { ++ /* Go to the end of current number */ ++ while (bcm_isxdigit(*cp)) { ++ cp++; ++ } ++ *endp = DISCARD_QUAL(cp, char); ++ } ++ return (ulong)-1; ++ } ++ last_result = result; ++ cp++; ++ } ++ ++ if (minus) ++ result = (ulong)(-(long)result); ++ ++ if (endp) ++ *endp = DISCARD_QUAL(cp, char); ++ ++ return (result); ++} ++ ++int ++bcm_atoi(const char *s) ++{ ++ return (int)bcm_strtoul(s, NULL, 10); ++} ++ ++/* return pointer to location of substring 'needle' in 'haystack' */ ++char * ++bcmstrstr(const char *haystack, const char *needle) ++{ ++ int len, nlen; ++ int i; ++ ++ if ((haystack == NULL) || (needle == NULL)) ++ return DISCARD_QUAL(haystack, char); ++ ++ nlen = (int)strlen(needle); ++ len = (int)strlen(haystack) - nlen + 1; ++ ++ for (i = 0; i < len; i++) ++ if (memcmp(needle, &haystack[i], nlen) == 0) ++ return DISCARD_QUAL(&haystack[i], char); ++ return (NULL); ++} ++ ++char * ++bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len) ++{ ++ for (; s_len >= substr_len; s++, s_len--) ++ if (strncmp(s, substr, substr_len) == 0) ++ return DISCARD_QUAL(s, char); ++ ++ return NULL; ++} ++ ++char * ++bcmstrcat(char *dest, const char *src) ++{ ++ char *p; ++ ++ p = dest + strlen(dest); ++ ++ while ((*p++ = *src++) != '\0') ++ ; ++ ++ return (dest); ++} ++ ++char * ++bcmstrncat(char *dest, const char *src, uint size) ++{ ++ char *endp; ++ char *p; ++ ++ p = dest + strlen(dest); ++ endp = p + size; ++ ++ while (p != endp && (*p++ = *src++) != '\0') ++ ; ++ ++ return (dest); ++} ++ ++ ++/**************************************************************************** ++* Function: bcmstrtok ++* ++* Purpose: ++* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), ++* but allows strToken() to be used by different strings or callers at the same ++* time. Each call modifies '*string' by substituting a NULL character for the ++* first delimiter that is encountered, and updates 'string' to point to the char ++* after the delimiter. Leading delimiters are skipped. ++* ++* Parameters: ++* string (mod) Ptr to string ptr, updated by token. ++* delimiters (in) Set of delimiter characters. ++* tokdelim (out) Character that delimits the returned token. (May ++* be set to NULL if token delimiter is not required). ++* ++* Returns: Pointer to the next token found. NULL when no more tokens are found. ++***************************************************************************** ++*/ ++char * ++bcmstrtok(char **string, const char *delimiters, char *tokdelim) ++{ ++ unsigned char *str; ++ unsigned long map[8]; ++ int count; ++ char *nextoken; ++ ++ if (tokdelim != NULL) { ++ /* Prime the token delimiter */ ++ *tokdelim = '\0'; ++ } ++ ++ /* Clear control map */ ++ for (count = 0; count < 8; count++) { ++ map[count] = 0; ++ } ++ ++ /* Set bits in delimiter table */ ++ do { ++ map[*delimiters >> 5] |= (1 << (*delimiters & 31)); ++ } ++ while (*delimiters++); ++ ++ str = (unsigned char*)*string; ++ ++ /* Find beginning of token (skip over leading delimiters). Note that ++ * there is no token iff this loop sets str to point to the terminal ++ * null (*str == '\0') ++ */ ++ while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { ++ str++; ++ } ++ ++ nextoken = (char*)str; ++ ++ /* Find the end of the token. If it is not the end of the string, ++ * put a null there. ++ */ ++ for (; *str; str++) { ++ if (map[*str >> 5] & (1 << (*str & 31))) { ++ if (tokdelim != NULL) { ++ *tokdelim = *str; ++ } ++ ++ *str++ = '\0'; ++ break; ++ } ++ } ++ ++ *string = (char*)str; ++ ++ /* Determine if a token has been found. */ ++ if (nextoken == (char *) str) { ++ return NULL; ++ } ++ else { ++ return nextoken; ++ } ++} ++ ++ ++#define xToLower(C) \ ++ ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) ++ ++ ++/**************************************************************************** ++* Function: bcmstricmp ++* ++* Purpose: Compare to strings case insensitively. ++* ++* Parameters: s1 (in) First string to compare. ++* s2 (in) Second string to compare. ++* ++* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if ++* t1 > t2, when ignoring case sensitivity. ++***************************************************************************** ++*/ ++int ++bcmstricmp(const char *s1, const char *s2) ++{ ++ char dc, sc; ++ ++ while (*s2 && *s1) { ++ dc = xToLower(*s1); ++ sc = xToLower(*s2); ++ if (dc < sc) return -1; ++ if (dc > sc) return 1; ++ s1++; ++ s2++; ++ } ++ ++ if (*s1 && !*s2) return 1; ++ if (!*s1 && *s2) return -1; ++ return 0; ++} ++ ++ ++/**************************************************************************** ++* Function: bcmstrnicmp ++* ++* Purpose: Compare to strings case insensitively, upto a max of 'cnt' ++* characters. ++* ++* Parameters: s1 (in) First string to compare. ++* s2 (in) Second string to compare. ++* cnt (in) Max characters to compare. ++* ++* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if ++* t1 > t2, when ignoring case sensitivity. ++***************************************************************************** ++*/ ++int ++bcmstrnicmp(const char* s1, const char* s2, int cnt) ++{ ++ char dc, sc; ++ ++ while (*s2 && *s1 && cnt) { ++ dc = xToLower(*s1); ++ sc = xToLower(*s2); ++ if (dc < sc) return -1; ++ if (dc > sc) return 1; ++ s1++; ++ s2++; ++ cnt--; ++ } ++ ++ if (!cnt) return 0; ++ if (*s1 && !*s2) return 1; ++ if (!*s1 && *s2) return -1; ++ return 0; ++} ++ ++/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ ++int ++bcm_ether_atoe(const char *p, struct ether_addr *ea) ++{ ++ int i = 0; ++ char *ep; ++ ++ for (;;) { ++ ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); ++ p = ep; ++ if (!*p++ || i == 6) ++ break; ++ } ++ ++ return (i == 6); ++} ++ ++int ++bcm_atoipv4(const char *p, struct ipv4_addr *ip) ++{ ++ ++ int i = 0; ++ char *c; ++ for (;;) { ++ ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0); ++ if (*c++ != '.' || i == IPV4_ADDR_LEN) ++ break; ++ p = c; ++ } ++ return (i == IPV4_ADDR_LEN); ++} ++#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ ++ ++ ++#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) ++/* registry routine buffer preparation utility functions: ++ * parameter order is like strncpy, but returns count ++ * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) ++ */ ++ulong ++wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) ++{ ++ ulong copyct = 1; ++ ushort i; ++ ++ if (abuflen == 0) ++ return 0; ++ ++ /* wbuflen is in bytes */ ++ wbuflen /= sizeof(ushort); ++ ++ for (i = 0; i < wbuflen; ++i) { ++ if (--abuflen == 0) ++ break; ++ *abuf++ = (char) *wbuf++; ++ ++copyct; ++ } ++ *abuf = '\0'; ++ ++ return copyct; ++} ++#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ ++ ++char * ++bcm_ether_ntoa(const struct ether_addr *ea, char *buf) ++{ ++ static const char hex[] = ++ { ++ '0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' ++ }; ++ const uint8 *octet = ea->octet; ++ char *p = buf; ++ int i; ++ ++ for (i = 0; i < 6; i++, octet++) { ++ *p++ = hex[(*octet >> 4) & 0xf]; ++ *p++ = hex[*octet & 0xf]; ++ *p++ = ':'; ++ } ++ ++ *(p-1) = '\0'; ++ ++ return (buf); ++} ++ ++char * ++bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) ++{ ++ snprintf(buf, 16, "%d.%d.%d.%d", ++ ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); ++ return (buf); ++} ++ ++char * ++bcm_ipv6_ntoa(void *ipv6, char *buf) ++{ ++ /* Implementing RFC 5952 Sections 4 + 5 */ ++ /* Not thoroughly tested */ ++ uint16 tmp[8]; ++ uint16 *a = &tmp[0]; ++ char *p = buf; ++ int i, i_max = -1, cnt = 0, cnt_max = 1; ++ uint8 *a4 = NULL; ++ memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN); ++ ++ for (i = 0; i < IPV6_ADDR_LEN/2; i++) { ++ if (a[i]) { ++ if (cnt > cnt_max) { ++ cnt_max = cnt; ++ i_max = i - cnt; ++ } ++ cnt = 0; ++ } else ++ cnt++; ++ } ++ if (cnt > cnt_max) { ++ cnt_max = cnt; ++ i_max = i - cnt; ++ } ++ if (i_max == 0 && ++ /* IPv4-translated: ::ffff:0:a.b.c.d */ ++ ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || ++ /* IPv4-mapped: ::ffff:a.b.c.d */ ++ (cnt_max == 5 && a[5] == 0xffff))) ++ a4 = (uint8*) (a + 6); ++ ++ for (i = 0; i < IPV6_ADDR_LEN/2; i++) { ++ if ((uint8*) (a + i) == a4) { ++ snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); ++ break; ++ } else if (i == i_max) { ++ *p++ = ':'; ++ i += cnt_max - 1; ++ p[0] = ':'; ++ p[1] = '\0'; ++ } else { ++ if (i) ++ *p++ = ':'; ++ p += snprintf(p, 8, "%x", ntoh16(a[i])); ++ } ++ } ++ ++ return buf; ++} ++#ifdef BCMDRIVER ++ ++void ++bcm_mdelay(uint ms) ++{ ++ uint i; ++ ++ for (i = 0; i < ms; i++) { ++ OSL_DELAY(1000); ++ } ++} ++ ++ ++ ++ ++ ++#if defined(DHD_DEBUG) ++/* pretty hex print a pkt buffer chain */ ++void ++prpkt(const char *msg, osl_t *osh, void *p0) ++{ ++ void *p; ++ ++ if (msg && (msg[0] != '\0')) ++ printf("%s:\n", msg); ++ ++ for (p = p0; p; p = PKTNEXT(osh, p)) ++ prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); ++} ++#endif ++ ++/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. ++ * Also updates the inplace vlan tag if requested. ++ * For debugging, it returns an indication of what it did. ++ */ ++uint BCMFASTPATH ++pktsetprio(void *pkt, bool update_vtag) ++{ ++ struct ether_header *eh; ++ struct ethervlan_header *evh; ++ uint8 *pktdata; ++ int priority = 0; ++ int rc = 0; ++ ++ pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); ++ ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); ++ ++ eh = (struct ether_header *) pktdata; ++ ++ if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { ++ uint16 vlan_tag; ++ int vlan_prio, dscp_prio = 0; ++ ++ evh = (struct ethervlan_header *)eh; ++ ++ vlan_tag = ntoh16(evh->vlan_tag); ++ vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; ++ ++ if ((evh->ether_type == hton16(ETHER_TYPE_IP)) || ++ (evh->ether_type == hton16(ETHER_TYPE_IPV6))) { ++ uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); ++ uint8 tos_tc = IP_TOS46(ip_body); ++ dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); ++ } ++ ++ /* DSCP priority gets precedence over 802.1P (vlan tag) */ ++ if (dscp_prio != 0) { ++ priority = dscp_prio; ++ rc |= PKTPRIO_VDSCP; ++ } else { ++ priority = vlan_prio; ++ rc |= PKTPRIO_VLAN; ++ } ++ /* ++ * If the DSCP priority is not the same as the VLAN priority, ++ * then overwrite the priority field in the vlan tag, with the ++ * DSCP priority value. This is required for Linux APs because ++ * the VLAN driver on Linux, overwrites the skb->priority field ++ * with the priority value in the vlan tag ++ */ ++ if (update_vtag && (priority != vlan_prio)) { ++ vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); ++ vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; ++ evh->vlan_tag = hton16(vlan_tag); ++ rc |= PKTPRIO_UPD; ++ } ++#if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING) ++ } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { ++ priority = PRIO_8021D_NC; ++ rc = PKTPRIO_DSCP; ++#endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */ ++ } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) || ++ (eh->ether_type == hton16(ETHER_TYPE_IPV6))) { ++ uint8 *ip_body = pktdata + sizeof(struct ether_header); ++ uint8 tos_tc = IP_TOS46(ip_body); ++ uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; ++ switch (dscp) { ++ case DSCP_EF: ++ priority = PRIO_8021D_VO; ++ break; ++ case DSCP_AF31: ++ case DSCP_AF32: ++ case DSCP_AF33: ++ priority = PRIO_8021D_CL; ++ break; ++ case DSCP_AF21: ++ case DSCP_AF22: ++ case DSCP_AF23: ++ case DSCP_AF11: ++ case DSCP_AF12: ++ case DSCP_AF13: ++ priority = PRIO_8021D_EE; ++ break; ++ default: ++ priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); ++ break; ++ } ++ ++ rc |= PKTPRIO_DSCP; ++ } ++ ++ ASSERT(priority >= 0 && priority <= MAXPRIO); ++ PKTSETPRIO(pkt, priority); ++ return (rc | priority); ++} ++ ++/* lookup user priority for specified DSCP */ ++static uint8 ++dscp2up(uint8 *up_table, uint8 dscp) ++{ ++ uint8 user_priority = 255; ++ ++ /* lookup up from table if parameters valid */ ++ if (up_table != NULL && dscp < UP_TABLE_MAX) { ++ user_priority = up_table[dscp]; ++ } ++ ++ /* 255 is unused value so return up from dscp */ ++ if (user_priority == 255) { ++ user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT); ++ } ++ ++ return user_priority; ++} ++ ++/* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */ ++uint BCMFASTPATH ++pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag) ++{ ++ if (up_table) { ++ uint8 *pktdata; ++ uint pktlen; ++ uint8 dscp; ++ uint user_priority = 0; ++ uint rc = 0; ++ ++ pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); ++ pktlen = PKTLEN(OSH_NULL, pkt); ++ ++ if (pktgetdscp(pktdata, pktlen, &dscp)) { ++ rc = PKTPRIO_DSCP; ++ user_priority = dscp2up(up_table, dscp); ++ PKTSETPRIO(pkt, user_priority); ++ } ++ ++ return (rc | user_priority); ++ } else { ++ return pktsetprio(pkt, update_vtag); ++ } ++} ++ ++/* Returns TRUE and DSCP if IP header found, FALSE otherwise. ++ */ ++bool BCMFASTPATH ++pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp) ++{ ++ struct ether_header *eh; ++ struct ethervlan_header *evh; ++ uint8 *ip_body; ++ bool rc = FALSE; ++ ++ /* minimum length is ether header and IP header */ ++ if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN) ++ return FALSE; ++ ++ eh = (struct ether_header *) pktdata; ++ ++ if (eh->ether_type == HTON16(ETHER_TYPE_IP)) { ++ ip_body = pktdata + sizeof(struct ether_header); ++ *dscp = IP_DSCP46(ip_body); ++ rc = TRUE; ++ } ++ else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) { ++ evh = (struct ethervlan_header *)eh; ++ ++ /* minimum length is ethervlan header and IP header */ ++ if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN && ++ evh->ether_type == HTON16(ETHER_TYPE_IP)) { ++ ip_body = pktdata + sizeof(struct ethervlan_header); ++ *dscp = IP_DSCP46(ip_body); ++ rc = TRUE; ++ } ++ } ++ ++ return rc; ++} ++ ++/* Add to adjust the 802.1x priority */ ++void ++pktset8021xprio(void *pkt, int prio) ++{ ++ struct ether_header *eh; ++ uint8 *pktdata; ++ if(prio == PKTPRIO(pkt)) ++ return; ++ pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); ++ ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); ++ eh = (struct ether_header *) pktdata; ++ if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { ++ ASSERT(prio >= 0 && prio <= MAXPRIO); ++ PKTSETPRIO(pkt, prio); ++ } ++} ++ ++/* usr_prio range from low to high with usr_prio value */ ++static bool ++up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high) ++{ ++ int i; ++ ++ if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) { ++ return FALSE; ++ } ++ ++ for (i = low; i <= high; i++) { ++ up_table[i] = usr_prio; ++ } ++ ++ return TRUE; ++} ++ ++/* set user priority table */ ++int BCMFASTPATH ++wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie) ++{ ++ uint8 len; ++ ++ if (up_table == NULL || qos_map_ie == NULL) { ++ return BCME_ERROR; ++ } ++ ++ /* clear table to check table was set or not */ ++ memset(up_table, 0xff, UP_TABLE_MAX); ++ ++ /* length of QoS Map IE must be 16+n*2, n is number of exceptions */ ++ if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID && ++ (len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH && ++ (len % 2) == 0) { ++ uint8 *except_ptr = (uint8 *)qos_map_ie->data; ++ uint8 except_len = len - QOS_MAP_FIXED_LENGTH; ++ uint8 *range_ptr = except_ptr + except_len; ++ int i; ++ ++ /* fill in ranges */ ++ for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) { ++ uint8 low = range_ptr[i]; ++ uint8 high = range_ptr[i + 1]; ++ if (low == 255 && high == 255) { ++ continue; ++ } ++ ++ if (!up_table_set(up_table, i / 2, low, high)) { ++ /* clear the table on failure */ ++ memset(up_table, 0xff, UP_TABLE_MAX); ++ return BCME_ERROR; ++ } ++ } ++ ++ /* update exceptions */ ++ for (i = 0; i < except_len; i += 2) { ++ uint8 dscp = except_ptr[i]; ++ uint8 usr_prio = except_ptr[i+1]; ++ ++ /* exceptions with invalid dscp/usr_prio are ignored */ ++ up_table_set(up_table, usr_prio, dscp, dscp); ++ } ++ } ++ ++ return BCME_OK; ++} ++ ++/* The 0.5KB string table is not removed by compiler even though it's unused */ ++ ++static char bcm_undeferrstr[32]; ++static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; ++ ++/* Convert the error codes into related error strings */ ++const char * ++bcmerrorstr(int bcmerror) ++{ ++ /* check if someone added a bcmerror code but forgot to add errorstring */ ++ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); ++ ++ if (bcmerror > 0 || bcmerror < BCME_LAST) { ++ snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); ++ return bcm_undeferrstr; ++ } ++ ++ ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); ++ ++ return bcmerrorstrtable[-bcmerror]; ++} ++ ++ ++/* iovar table lookup */ ++/* could mandate sorted tables and do a binary search */ ++const bcm_iovar_t* ++bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) ++{ ++ const bcm_iovar_t *vi; ++ const char *lookup_name; ++ ++ /* skip any ':' delimited option prefixes */ ++ lookup_name = strrchr(name, ':'); ++ if (lookup_name != NULL) ++ lookup_name++; ++ else ++ lookup_name = name; ++ ++ ASSERT(table != NULL); ++ ++ 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 */ ++} ++ ++int ++bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) ++{ ++ int bcmerror = 0; ++ BCM_REFERENCE(arg); ++ ++ /* 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 int32 sized args at the ioctl interface */ ++ if (len < (int)sizeof(int)) { ++ bcmerror = BCME_BUFTOOSHORT; ++ } ++ break; ++ ++ case IOVT_BUFFER: ++ /* buffer must meet minimum length requirement */ ++ if (len < vi->minlen) { ++ bcmerror = BCME_BUFTOOSHORT; ++ } ++ break; ++ ++ case IOVT_VOID: ++ if (!set) { ++ /* Cannot return nil... */ ++ bcmerror = BCME_UNSUPPORTED; ++ } else if (len) { ++ /* Set is an action w/o parameters */ ++ bcmerror = BCME_BUFTOOLONG; ++ } ++ break; ++ ++ default: ++ /* unknown type for length check in iovar info */ ++ ASSERT(0); ++ bcmerror = BCME_UNSUPPORTED; ++ } ++ ++ return bcmerror; ++} ++ ++#endif /* BCMDRIVER */ ++ ++#ifdef BCM_OBJECT_TRACE ++ ++#define BCM_OBJECT_MERGE_SAME_OBJ 0 ++ ++/* some place may add / remove the object to trace list for Linux: */ ++/* add: osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */ ++/* remove: osl_pktfree dev_kfree_skb netif_rx */ ++ ++#define BCM_OBJDBG_COUNT (1024 * 100) ++static spinlock_t dbgobj_lock; ++#define BCM_OBJDBG_LOCK_INIT() spin_lock_init(&dbgobj_lock) ++#define BCM_OBJDBG_LOCK_DESTROY() ++#define BCM_OBJDBG_LOCK spin_lock_irqsave ++#define BCM_OBJDBG_UNLOCK spin_unlock_irqrestore ++ ++#define BCM_OBJDBG_ADDTOHEAD 0 ++#define BCM_OBJDBG_ADDTOTAIL 1 ++ ++#define BCM_OBJDBG_CALLER_LEN 32 ++struct bcm_dbgobj { ++ struct bcm_dbgobj *prior; ++ struct bcm_dbgobj *next; ++ uint32 flag; ++ void *obj; ++ uint32 obj_sn; ++ uint32 obj_state; ++ uint32 line; ++ char caller[BCM_OBJDBG_CALLER_LEN]; ++}; ++ ++static struct bcm_dbgobj *dbgobj_freehead = NULL; ++static struct bcm_dbgobj *dbgobj_freetail = NULL; ++static struct bcm_dbgobj *dbgobj_objhead = NULL; ++static struct bcm_dbgobj *dbgobj_objtail = NULL; ++ ++static uint32 dbgobj_sn = 0; ++static int dbgobj_count = 0; ++static struct bcm_dbgobj bcm_dbg_objs[BCM_OBJDBG_COUNT]; ++ ++void ++bcm_object_trace_init(void) ++{ ++ int i = 0; ++ BCM_OBJDBG_LOCK_INIT(); ++ memset(&bcm_dbg_objs, 0x00, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT); ++ dbgobj_freehead = &bcm_dbg_objs[0]; ++ dbgobj_freetail = &bcm_dbg_objs[BCM_OBJDBG_COUNT - 1]; ++ ++ for (i = 0; i < BCM_OBJDBG_COUNT; ++i) { ++ bcm_dbg_objs[i].next = (i == (BCM_OBJDBG_COUNT - 1)) ? ++ dbgobj_freehead : &bcm_dbg_objs[i + 1]; ++ bcm_dbg_objs[i].prior = (i == 0) ? ++ dbgobj_freetail : &bcm_dbg_objs[i - 1]; ++ } ++} ++ ++void ++bcm_object_trace_deinit(void) ++{ ++ if (dbgobj_objhead || dbgobj_objtail) { ++ printf("%s: not all objects are released\n", __FUNCTION__); ++ ASSERT(0); ++ } ++ BCM_OBJDBG_LOCK_DESTROY(); ++} ++ ++static void ++bcm_object_rm_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail, ++ struct bcm_dbgobj *dbgobj) ++{ ++ if ((dbgobj == *head) && (dbgobj == *tail)) { ++ *head = NULL; ++ *tail = NULL; ++ } else if (dbgobj == *head) { ++ *head = (*head)->next; ++ } else if (dbgobj == *tail) { ++ *tail = (*tail)->prior; ++ } ++ dbgobj->next->prior = dbgobj->prior; ++ dbgobj->prior->next = dbgobj->next; ++} ++ ++static void ++bcm_object_add_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail, ++ struct bcm_dbgobj *dbgobj, int addtotail) ++{ ++ if (!(*head) && !(*tail)) { ++ *head = dbgobj; ++ *tail = dbgobj; ++ dbgobj->next = dbgobj; ++ dbgobj->prior = dbgobj; ++ } else if ((*head) && (*tail)) { ++ (*tail)->next = dbgobj; ++ (*head)->prior = dbgobj; ++ dbgobj->next = *head; ++ dbgobj->prior = *tail; ++ if (addtotail == BCM_OBJDBG_ADDTOTAIL) ++ *tail = dbgobj; ++ else ++ *head = dbgobj; ++ } else { ++ ASSERT(0); /* can't be this case */ ++ } ++} ++ ++static INLINE void ++bcm_object_movetoend(struct bcm_dbgobj **head, struct bcm_dbgobj **tail, ++ struct bcm_dbgobj *dbgobj, int movetotail) ++{ ++ if ((*head) && (*tail)) { ++ if (movetotail == BCM_OBJDBG_ADDTOTAIL) { ++ if (dbgobj != (*tail)) { ++ bcm_object_rm_list(head, tail, dbgobj); ++ bcm_object_add_list(head, tail, dbgobj, movetotail); ++ } ++ } else { ++ if (dbgobj != (*head)) { ++ bcm_object_rm_list(head, tail, dbgobj); ++ bcm_object_add_list(head, tail, dbgobj, movetotail); ++ } ++ } ++ } else { ++ ASSERT(0); /* can't be this case */ ++ } ++} ++ ++void ++bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line) ++{ ++ struct bcm_dbgobj *dbgobj; ++ unsigned long flags; ++ ++ BCM_REFERENCE(flags); ++ BCM_OBJDBG_LOCK(&dbgobj_lock, flags); ++ ++ if (opt == BCM_OBJDBG_ADD_PKT || ++ opt == BCM_OBJDBG_ADD) { ++ dbgobj = dbgobj_objtail; ++ while (dbgobj) { ++ if (dbgobj->obj == obj) { ++ printf("%s: obj %p allocated from %s(%d)," ++ " allocate again from %s(%d)\n", ++ __FUNCTION__, dbgobj->obj, ++ dbgobj->caller, dbgobj->line, ++ caller, line); ++ ASSERT(0); ++ goto EXIT; ++ } ++ dbgobj = dbgobj->prior; ++ if (dbgobj == dbgobj_objtail) ++ break; ++ } ++ ++#if BCM_OBJECT_MERGE_SAME_OBJ ++ dbgobj = dbgobj_freetail; ++ while (dbgobj) { ++ if (dbgobj->obj == obj) { ++ goto FREED_ENTRY_FOUND; ++ } ++ dbgobj = dbgobj->prior; ++ if (dbgobj == dbgobj_freetail) ++ break; ++ } ++#endif /* BCM_OBJECT_MERGE_SAME_OBJ */ ++ ++ dbgobj = dbgobj_freehead; ++#if BCM_OBJECT_MERGE_SAME_OBJ ++FREED_ENTRY_FOUND: ++#endif /* BCM_OBJECT_MERGE_SAME_OBJ */ ++ if (!dbgobj) { ++ printf("%s: already got %d objects ?????????????????????\n", ++ __FUNCTION__, BCM_OBJDBG_COUNT); ++ ASSERT(0); ++ goto EXIT; ++ } ++ ++ bcm_object_rm_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj); ++ dbgobj->obj = obj; ++ strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN); ++ dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0'; ++ dbgobj->line = line; ++ dbgobj->flag = 0; ++ if (opt == BCM_OBJDBG_ADD_PKT) { ++ dbgobj->obj_sn = dbgobj_sn++; ++ dbgobj->obj_state = 0; ++ /* first 4 bytes is pkt sn */ ++ if (((unsigned long)PKTTAG(obj)) & 0x3) ++ printf("pkt tag address not aligned by 4: %p\n", PKTTAG(obj)); ++ *(uint32*)PKTTAG(obj) = dbgobj->obj_sn; ++ } ++ bcm_object_add_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj, ++ BCM_OBJDBG_ADDTOTAIL); ++ ++ dbgobj_count++; ++ ++ } else if (opt == BCM_OBJDBG_REMOVE) { ++ dbgobj = dbgobj_objtail; ++ while (dbgobj) { ++ if (dbgobj->obj == obj) { ++ if (dbgobj->flag) { ++ printf("%s: rm flagged obj %p flag 0x%08x from %s(%d)\n", ++ __FUNCTION__, obj, dbgobj->flag, caller, line); ++ } ++ bcm_object_rm_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj); ++ memset(dbgobj->caller, 0x00, BCM_OBJDBG_CALLER_LEN); ++ strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN); ++ dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0'; ++ dbgobj->line = line; ++ bcm_object_add_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj, ++ BCM_OBJDBG_ADDTOTAIL); ++ dbgobj_count--; ++ goto EXIT; ++ } ++ dbgobj = dbgobj->prior; ++ if (dbgobj == dbgobj_objtail) ++ break; ++ } ++ ++ dbgobj = dbgobj_freetail; ++ while (dbgobj && dbgobj->obj) { ++ if (dbgobj->obj == obj) { ++ printf("%s: obj %p already freed from from %s(%d)," ++ " try free again from %s(%d)\n", ++ __FUNCTION__, obj, ++ dbgobj->caller, dbgobj->line, ++ caller, line); ++ //ASSERT(0); /* release same obj more than one time? */ ++ goto EXIT; ++ } ++ dbgobj = dbgobj->prior; ++ if (dbgobj == dbgobj_freetail) ++ break; ++ } ++ ++ printf("%s: ################### release none-existing obj %p from %s(%d)\n", ++ __FUNCTION__, obj, caller, line); ++ //ASSERT(0); /* release same obj more than one time? */ ++ ++ } ++ ++EXIT: ++ BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags); ++ return; ++} ++ ++void ++bcm_object_trace_upd(void *obj, void *obj_new) ++{ ++ struct bcm_dbgobj *dbgobj; ++ unsigned long flags; ++ ++ BCM_REFERENCE(flags); ++ BCM_OBJDBG_LOCK(&dbgobj_lock, flags); ++ ++ dbgobj = dbgobj_objtail; ++ while (dbgobj) { ++ if (dbgobj->obj == obj) { ++ dbgobj->obj = obj_new; ++ if (dbgobj != dbgobj_objtail) { ++ bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, ++ dbgobj, BCM_OBJDBG_ADDTOTAIL); ++ } ++ goto EXIT; ++ } ++ dbgobj = dbgobj->prior; ++ if (dbgobj == dbgobj_objtail) ++ break; ++ } ++ ++EXIT: ++ BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags); ++ return; ++} ++ ++void ++bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn, ++ const char *caller, int line) ++{ ++ struct bcm_dbgobj *dbgobj; ++ unsigned long flags; ++ ++ BCM_REFERENCE(flags); ++ BCM_OBJDBG_LOCK(&dbgobj_lock, flags); ++ ++ dbgobj = dbgobj_objtail; ++ while (dbgobj) { ++ if ((dbgobj->obj == obj) && ++ ((!chksn) || (dbgobj->obj_sn == sn))) { ++ if (dbgobj != dbgobj_objtail) { ++ bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, ++ dbgobj, BCM_OBJDBG_ADDTOTAIL); ++ } ++ goto EXIT; ++ } ++ dbgobj = dbgobj->prior; ++ if (dbgobj == dbgobj_objtail) ++ break; ++ } ++ ++ dbgobj = dbgobj_freetail; ++ while (dbgobj) { ++ if ((dbgobj->obj == obj) && ++ ((!chksn) || (dbgobj->obj_sn == sn))) { ++ printf("%s: (%s:%d) obj %p (sn %d state %d) was freed from %s(%d)\n", ++ __FUNCTION__, caller, line, ++ dbgobj->obj, dbgobj->obj_sn, dbgobj->obj_state, ++ dbgobj->caller, dbgobj->line); ++ goto EXIT; ++ } ++ else if (dbgobj->obj == NULL) { ++ break; ++ } ++ dbgobj = dbgobj->prior; ++ if (dbgobj == dbgobj_freetail) ++ break; ++ } ++ ++ printf("%s: obj %p not found, check from %s(%d), chksn %s, sn %d\n", ++ __FUNCTION__, obj, caller, line, chksn ? "yes" : "no", sn); ++ dbgobj = dbgobj_objtail; ++ while (dbgobj) { ++ printf("%s: (%s:%d) obj %p sn %d was allocated from %s(%d)\n", ++ __FUNCTION__, caller, line, ++ dbgobj->obj, dbgobj->obj_sn, dbgobj->caller, dbgobj->line); ++ dbgobj = dbgobj->prior; ++ if (dbgobj == dbgobj_objtail) ++ break; ++ } ++ ++EXIT: ++ BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags); ++ return; ++} ++ ++void ++bcm_object_feature_set(void *obj, uint32 type, uint32 value) ++{ ++ struct bcm_dbgobj *dbgobj; ++ unsigned long flags; ++ ++ BCM_REFERENCE(flags); ++ BCM_OBJDBG_LOCK(&dbgobj_lock, flags); ++ ++ dbgobj = dbgobj_objtail; ++ while (dbgobj) { ++ if (dbgobj->obj == obj) { ++ if (type == BCM_OBJECT_FEATURE_FLAG) { ++ if (value & BCM_OBJECT_FEATURE_CLEAR) ++ dbgobj->flag &= ~(value); ++ else ++ dbgobj->flag |= (value); ++ } else if (type == BCM_OBJECT_FEATURE_PKT_STATE) { ++ dbgobj->obj_state = value; ++ } ++ if (dbgobj != dbgobj_objtail) { ++ bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, ++ dbgobj, BCM_OBJDBG_ADDTOTAIL); ++ } ++ goto EXIT; ++ } ++ dbgobj = dbgobj->prior; ++ if (dbgobj == dbgobj_objtail) ++ break; ++ } ++ ++ printf("%s: obj %p not found in active list\n", __FUNCTION__, obj); ++ ASSERT(0); ++ ++EXIT: ++ BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags); ++ return; ++} ++ ++int ++bcm_object_feature_get(void *obj, uint32 type, uint32 value) ++{ ++ int rtn = 0; ++ struct bcm_dbgobj *dbgobj; ++ unsigned long flags; ++ ++ BCM_REFERENCE(flags); ++ BCM_OBJDBG_LOCK(&dbgobj_lock, flags); ++ ++ dbgobj = dbgobj_objtail; ++ while (dbgobj) { ++ if (dbgobj->obj == obj) { ++ if (type == BCM_OBJECT_FEATURE_FLAG) { ++ rtn = (dbgobj->flag & value) & (~BCM_OBJECT_FEATURE_CLEAR); ++ } ++ if (dbgobj != dbgobj_objtail) { ++ bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, ++ dbgobj, BCM_OBJDBG_ADDTOTAIL); ++ } ++ goto EXIT; ++ } ++ dbgobj = dbgobj->prior; ++ if (dbgobj == dbgobj_objtail) ++ break; ++ } ++ ++ printf("%s: obj %p not found in active list\n", __FUNCTION__, obj); ++ ASSERT(0); ++ ++EXIT: ++ BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags); ++ return rtn; ++} ++ ++#endif /* BCM_OBJECT_TRACE */ ++ ++uint8 * ++bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst) ++{ ++ uint8 *new_dst = dst; ++ bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst; ++ ++ /* dst buffer should always be valid */ ++ ASSERT(dst); ++ ++ /* data len must be within valid range */ ++ ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)); ++ ++ /* source data buffer pointer should be valid, unless datalen is 0 ++ * meaning no data with this TLV ++ */ ++ ASSERT((data != NULL) || (datalen == 0)); ++ ++ /* only do work if the inputs are valid ++ * - must have a dst to write to AND ++ * - datalen must be within range AND ++ * - the source data pointer must be non-NULL if datalen is non-zero ++ * (this last condition detects datalen > 0 with a NULL data pointer) ++ */ ++ if ((dst != NULL) && ++ ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) && ++ ((data != NULL) || (datalen == 0))) { ++ ++ /* write type, len fields */ ++ dst_tlv->id = (uint8)type; ++ dst_tlv->len = (uint8)datalen; ++ ++ /* if data is present, copy to the output buffer and update ++ * pointer to output buffer ++ */ ++ if (datalen > 0) { ++ ++ memcpy(dst_tlv->data, data, datalen); ++ } ++ ++ /* update the output destination poitner to point past ++ * the TLV written ++ */ ++ new_dst = dst + BCM_TLV_HDR_SIZE + datalen; ++ } ++ ++ return (new_dst); ++} ++ ++uint8 * ++bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen) ++{ ++ uint8 *new_dst = dst; ++ ++ if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) { ++ ++ /* if len + tlv hdr len is more than destlen, don't do anything ++ * just return the buffer untouched ++ */ ++ if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) { ++ ++ new_dst = bcm_write_tlv(type, data, datalen, dst); ++ } ++ } ++ ++ return (new_dst); ++} ++ ++uint8 * ++bcm_copy_tlv(const void *src, uint8 *dst) ++{ ++ uint8 *new_dst = dst; ++ const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; ++ uint totlen; ++ ++ ASSERT(dst && src); ++ if (dst && src) { ++ ++ totlen = BCM_TLV_HDR_SIZE + src_tlv->len; ++ memcpy(dst, src_tlv, totlen); ++ new_dst = dst + totlen; ++ } ++ ++ return (new_dst); ++} ++ ++ ++uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen) ++{ ++ uint8 *new_dst = dst; ++ const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; ++ ++ ASSERT(src); ++ if (src) { ++ if (bcm_valid_tlv(src_tlv, dst_maxlen)) { ++ new_dst = bcm_copy_tlv(src, dst); ++ } ++ } ++ ++ return (new_dst); ++} ++ ++ ++#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) ++/******************************************************************************* ++ * 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 uint8 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 ++}; ++ ++#define CRC_INNER_LOOP(n, c, x) \ ++ (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] ++ ++uint8 ++hndcrc8( ++ uint8 *pdata, /* pointer to array of data to process */ ++ uint nbytes, /* number of input data bytes to process */ ++ uint8 crc /* either CRC8_INIT_VALUE or previous return value */ ++) ++{ ++ /* hard code the crc loop instead of using CRC_INNER_LOOP macro ++ * to avoid the undefined and unnecessary (uint8 >> 8) operation. ++ */ ++ while (nbytes-- > 0) ++ crc = crc8_table[(crc ^ *pdata++) & 0xff]; ++ ++ return crc; ++} ++ ++/******************************************************************************* ++ * crc16 ++ * ++ * Computes a crc16 over the input data using the polynomial: ++ * ++ * x^16 + x^12 +x^5 + 1 ++ * ++ * The caller provides the initial value (either CRC16_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 CRC16_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 uint16 crc16_table[256] = { ++ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, ++ 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, ++ 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, ++ 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, ++ 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, ++ 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, ++ 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, ++ 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, ++ 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, ++ 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, ++ 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, ++ 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, ++ 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, ++ 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, ++ 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, ++ 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, ++ 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, ++ 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, ++ 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, ++ 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, ++ 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, ++ 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, ++ 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, ++ 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, ++ 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, ++ 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, ++ 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, ++ 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, ++ 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, ++ 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, ++ 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, ++ 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 ++}; ++ ++uint16 ++hndcrc16( ++ uint8 *pdata, /* pointer to array of data to process */ ++ uint nbytes, /* number of input data bytes to process */ ++ uint16 crc /* either CRC16_INIT_VALUE or previous return value */ ++) ++{ ++ while (nbytes-- > 0) ++ CRC_INNER_LOOP(16, crc, *pdata++); ++ return crc; ++} ++ ++static const uint32 crc32_table[256] = { ++ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, ++ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, ++ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, ++ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, ++ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, ++ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, ++ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, ++ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, ++ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, ++ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, ++ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, ++ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, ++ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, ++ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, ++ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, ++ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, ++ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, ++ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, ++ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, ++ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, ++ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, ++ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, ++ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, ++ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, ++ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, ++ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, ++ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, ++ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, ++ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, ++ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, ++ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, ++ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, ++ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, ++ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, ++ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, ++ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, ++ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, ++ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, ++ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, ++ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, ++ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, ++ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, ++ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, ++ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, ++ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, ++ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, ++ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, ++ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, ++ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, ++ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, ++ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, ++ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, ++ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, ++ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, ++ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, ++ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, ++ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, ++ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, ++ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, ++ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, ++ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, ++ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, ++ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, ++ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D ++}; ++ ++/* ++ * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if ++ * accumulating over multiple pieces. ++ */ ++uint32 ++hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) ++{ ++ uint8 *pend; ++ pend = pdata + nbytes; ++ while (pdata < pend) ++ CRC_INNER_LOOP(32, crc, *pdata++); ++ ++ return crc; ++} ++ ++#ifdef notdef ++#define CLEN 1499 /* CRC Length */ ++#define CBUFSIZ (CLEN+4) ++#define CNBUFS 5 /* # of bufs */ ++ ++void ++testcrc32(void) ++{ ++ uint j, k, l; ++ uint8 *buf; ++ uint len[CNBUFS]; ++ uint32 crcr; ++ uint32 crc32tv[CNBUFS] = ++ {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; ++ ++ ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); ++ ++ /* step through all possible alignments */ ++ for (l = 0; l <= 4; l++) { ++ for (j = 0; j < CNBUFS; j++) { ++ len[j] = CLEN; ++ for (k = 0; k < len[j]; k++) ++ *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; ++ } ++ ++ for (j = 0; j < CNBUFS; j++) { ++ crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); ++ ASSERT(crcr == crc32tv[j]); ++ } ++ } ++ ++ MFREE(buf, CBUFSIZ*CNBUFS); ++ return; ++} ++#endif /* notdef */ ++ ++/* ++ * Advance from the current 1-byte tag/1-byte length/variable-length value ++ * triple, to the next, returning a pointer to the next. ++ * If the current or next TLV is invalid (does not fit in given buffer length), ++ * NULL is returned. ++ * *buflen is not modified if the TLV elt parameter is invalid, or is decremented ++ * by the TLV parameter's length if it is valid. ++ */ ++bcm_tlv_t * ++bcm_next_tlv(bcm_tlv_t *elt, int *buflen) ++{ ++ int len; ++ ++ /* validate current elt */ ++ if (!bcm_valid_tlv(elt, *buflen)) { ++ return NULL; ++ } ++ ++ /* advance to next elt */ ++ len = elt->len; ++ elt = (bcm_tlv_t*)(elt->data + len); ++ *buflen -= (TLV_HDR_LEN + len); ++ ++ /* validate next elt */ ++ if (!bcm_valid_tlv(elt, *buflen)) { ++ return NULL; ++ } ++ ++ return elt; ++} ++ ++/* ++ * 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 ++ */ ++bcm_tlv_t * ++bcm_parse_tlvs(void *buf, int buflen, uint key) ++{ ++ bcm_tlv_t *elt; ++ int totlen; ++ ++ if ((elt = (bcm_tlv_t*)buf) == NULL) { ++ return NULL; ++ } ++ totlen = buflen; ++ ++ /* find tagged parameter */ ++ while (totlen >= TLV_HDR_LEN) { ++ int len = elt->len; ++ ++ /* validate remaining totlen */ ++ if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { ++ ++ return (elt); ++ } ++ ++ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); ++ totlen -= (len + TLV_HDR_LEN); ++ } ++ ++ return NULL; ++} ++ ++bcm_tlv_t * ++bcm_parse_tlvs_dot11(void *buf, int buflen, uint key, bool id_ext) ++{ ++ bcm_tlv_t *elt; ++ int totlen; ++ ++ elt = (bcm_tlv_t*)buf; ++ totlen = buflen; ++ ++ /* find tagged parameter */ ++ while (totlen >= TLV_HDR_LEN) { ++ int len = elt->len; ++ ++ do { ++ /* validate remaining totlen */ ++ if (totlen < (int)(len + TLV_HDR_LEN)) ++ break; ++ ++ if (id_ext) { ++ if (!DOT11_MNG_IE_ID_EXT_MATCH(elt, key)) ++ break; ++ } else if (elt->id != key) { ++ break; ++ } ++ ++ return (elt); ++ } while (0); ++ ++ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); ++ totlen -= (len + TLV_HDR_LEN); ++ } ++ ++ return NULL; ++} ++ ++/* ++ * 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 ++ * return NULL if not found or length field < min_varlen ++ */ ++bcm_tlv_t * ++bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen) ++{ ++ bcm_tlv_t * ret; ++ ret = bcm_parse_tlvs(buf, buflen, key); ++ if (ret == NULL || ret->len < min_bodylen) { ++ return NULL; ++ } ++ return ret; ++} ++ ++/* ++ * 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. Stop parsing when we see an element whose ID is greater ++ * than the target key. ++ */ ++bcm_tlv_t * ++bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) ++{ ++ bcm_tlv_t *elt; ++ int totlen; ++ ++ elt = (bcm_tlv_t*)buf; ++ totlen = buflen; ++ ++ /* find tagged parameter */ ++ while (totlen >= TLV_HDR_LEN) { ++ uint id = elt->id; ++ int len = elt->len; ++ ++ /* Punt if we start seeing IDs > than target key */ ++ if (id > key) { ++ return (NULL); ++ } ++ ++ /* validate remaining totlen */ ++ if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { ++ return (elt); ++ } ++ ++ elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); ++ totlen -= (len + TLV_HDR_LEN); ++ } ++ return NULL; ++} ++#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ ++ ++#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ ++ defined(DHD_DEBUG) ++int ++bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len) ++{ ++ int i, slen = 0; ++ uint32 bit, mask; ++ const char *name; ++ mask = bd->mask; ++ if (len < 2 || !buf) ++ return 0; ++ ++ buf[0] = '\0'; ++ ++ for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) { ++ bit = bd->bitfield[i].bit; ++ if ((flags & mask) == bit) { ++ if (len > (int)strlen(name)) { ++ slen = strlen(name); ++ strncpy(buf, name, slen+1); ++ } ++ break; ++ } ++ } ++ return slen; ++} ++ ++int ++bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) ++{ ++ int i; ++ char* p = buf; ++ char hexstr[16]; ++ int slen = 0, nlen = 0; ++ uint32 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, " "); ++ } ++ ++ /* indicate the str was too short */ ++ if (flags != 0) { ++ p += snprintf(p, 2, ">"); ++ } ++ ++ return (int)(p - buf); ++} ++#endif ++ ++/* print bytes formatted as hex to a string. return the resulting string length */ ++int ++bcm_format_hex(char *str, const void *bytes, int len) ++{ ++ int i; ++ char *p = str; ++ const uint8 *src = (const uint8*)bytes; ++ ++ for (i = 0; i < len; i++) { ++ p += snprintf(p, 3, "%02X", *src); ++ src++; ++ } ++ return (int)(p - str); ++} ++ ++/* pretty hex print a contiguous buffer */ ++void ++prhex(const char *msg, volatile uchar *buf, uint nbytes) ++{ ++ char line[128], *p; ++ int len = sizeof(line); ++ int nchar; ++ uint i; ++ ++ if (msg && (msg[0] != '\0')) ++ printf("%s:\n", msg); ++ ++ p = line; ++ for (i = 0; i < nbytes; i++) { ++ if (i % 16 == 0) { ++ nchar = snprintf(p, len, " %04x: ", i); /* line prefix */ ++ p += nchar; ++ len -= nchar; ++ } ++ if (len > 0) { ++ nchar = snprintf(p, len, "%02x ", buf[i]); ++ p += nchar; ++ len -= nchar; ++ } ++ ++ if (i % 16 == 15) { ++ printf("%s\n", line); /* flush line */ ++ p = line; ++ len = sizeof(line); ++ } ++ } ++ ++ /* flush last partial line */ ++ if (p != line) ++ printf("%s\n", line); ++} ++ ++static const char *crypto_algo_names[] = { ++ "NONE", ++ "WEP1", ++ "TKIP", ++ "WEP128", ++ "AES_CCM", ++ "AES_OCB_MSDU", ++ "AES_OCB_MPDU", ++ "NALG", ++ "UNDEF", ++ "UNDEF", ++ "UNDEF", ++ "UNDEF" ++ "PMK", ++ "BIP", ++ "AES_GCM", ++ "AES_CCM256", ++ "AES_GCM256", ++ "BIP_CMAC256", ++ "BIP_GMAC", ++ "BIP_GMAC256", ++ "UNDEF" ++}; ++ ++const char * ++bcm_crypto_algo_name(uint algo) ++{ ++ return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; ++} ++ ++ ++char * ++bcm_chipname(uint chipid, char *buf, uint len) ++{ ++ const char *fmt; ++ ++ fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; ++ snprintf(buf, len, fmt, chipid); ++ return buf; ++} ++ ++/* Produce a human-readable string for boardrev */ ++char * ++bcm_brev_str(uint32 brev, char *buf) ++{ ++ if (brev < 0x100) ++ snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); ++ else ++ snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); ++ ++ return (buf); ++} ++ ++#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ ++ ++/* dump large strings to console */ ++void ++printbig(char *buf) ++{ ++ uint len, max_len; ++ char c; ++ ++ len = (uint)strlen(buf); ++ ++ max_len = BUFSIZE_TODUMP_ATONCE; ++ ++ while (len > max_len) { ++ c = buf[max_len]; ++ buf[max_len] = '\0'; ++ printf("%s", buf); ++ buf[max_len] = c; ++ ++ buf += max_len; ++ len -= max_len; ++ } ++ /* print the remaining string */ ++ printf("%s\n", buf); ++ return; ++} ++ ++/* routine to dump fields in a fileddesc structure */ ++uint ++bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, ++ char *buf, uint32 bufsize) ++{ ++ uint filled_len; ++ int len; ++ struct fielddesc *cur_ptr; ++ ++ filled_len = 0; ++ cur_ptr = fielddesc_array; ++ ++ while (bufsize > 1) { ++ if (cur_ptr->nameandfmt == NULL) ++ break; ++ len = snprintf(buf, bufsize, cur_ptr->nameandfmt, ++ read_rtn(arg0, arg1, cur_ptr->offset)); ++ /* check for snprintf overflow or error */ ++ if (len < 0 || (uint32)len >= bufsize) ++ len = bufsize - 1; ++ buf += len; ++ bufsize -= len; ++ filled_len += len; ++ cur_ptr++; ++ } ++ return filled_len; ++} ++ ++uint ++bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint buflen) ++{ ++ uint len; ++ ++ len = (uint)strlen(name) + 1; ++ ++ if ((len + datalen) > buflen) ++ return 0; ++ ++ strncpy(buf, name, buflen); ++ ++ /* append data onto the end of the name string */ ++ if (data && datalen != 0) { ++ memcpy(&buf[len], data, datalen); ++ len += datalen; ++ } ++ ++ return len; ++} ++ ++/* 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 uint16. ++ */ ++ ++#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 uint16 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 ++}; ++ ++uint16 ++bcm_qdbm_to_mw(uint8 qdbm) ++{ ++ uint factor = 1; ++ int idx = qdbm - QDBM_OFFSET; ++ ++ if (idx >= QDBM_TABLE_LEN) { ++ /* clamp to max uint16 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); ++} ++ ++uint8 ++bcm_mw_to_qdbm(uint16 mw) ++{ ++ uint8 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 += (uint8)offset; ++ ++ return (qdbm); ++} ++ ++ ++uint ++bcm_bitcount(uint8 *bitmap, uint length) ++{ ++ uint bitcount = 0, i; ++ uint8 tmp; ++ for (i = 0; i < length; i++) { ++ tmp = bitmap[i]; ++ while (tmp) { ++ bitcount++; ++ tmp &= (tmp - 1); ++ } ++ } ++ return bitcount; ++} ++ ++#if defined(BCMDRIVER) || defined(WL_UNITTEST) ++ ++/* triggers bcm_bprintf to print to kernel log */ ++bool bcm_bprintf_bypass = FALSE; ++ ++/* Initialization of bcmstrbuf structure */ ++void ++bcm_binit(struct bcmstrbuf *b, char *buf, uint size) ++{ ++ b->origsize = b->size = size; ++ b->origbuf = b->buf = buf; ++} ++ ++/* Buffer sprintf wrapper to guard against buffer overflow */ ++int ++bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) ++{ ++ va_list ap; ++ int r; ++ ++ va_start(ap, fmt); ++ ++ r = vsnprintf(b->buf, b->size, fmt, ap); ++ if (bcm_bprintf_bypass == TRUE) { ++ printf("%s", b->buf); ++ goto exit; ++ } ++ ++ /* Non Ansi C99 compliant returns -1, ++ * Ansi compliant return r >= b->size, ++ * bcmstdlib returns 0, handle all ++ */ ++ /* r == 0 is also the case when strlen(fmt) is zero. ++ * typically the case when "" is passed as argument. ++ */ ++ if ((r == -1) || (r >= (int)b->size)) { ++ b->size = 0; ++ } else { ++ b->size -= r; ++ b->buf += r; ++ } ++ ++exit: ++ va_end(ap); ++ ++ return r; ++} ++ ++void ++bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len) ++{ ++ int i; ++ ++ if (msg != NULL && msg[0] != '\0') ++ bcm_bprintf(b, "%s", msg); ++ for (i = 0; i < len; i ++) ++ bcm_bprintf(b, "%02X", buf[i]); ++ if (newline) ++ bcm_bprintf(b, "\n"); ++} ++ ++void ++bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) ++{ ++ int i; ++ ++ for (i = 0; i < num_bytes; i++) { ++ num[i] += amount; ++ if (num[i] >= amount) ++ break; ++ amount = 1; ++ } ++} ++ ++int ++bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) ++{ ++ int i; ++ ++ for (i = nbytes - 1; i >= 0; i--) { ++ if (arg1[i] != arg2[i]) ++ return (arg1[i] - arg2[i]); ++ } ++ return 0; ++} ++ ++void ++bcm_print_bytes(const char *name, const uchar *data, int len) ++{ ++ int i; ++ int per_line = 0; ++ ++ printf("%s: %d \n", name ? name : "", len); ++ for (i = 0; i < len; i++) { ++ printf("%02x ", *data++); ++ per_line++; ++ if (per_line == 16) { ++ per_line = 0; ++ printf("\n"); ++ } ++ } ++ printf("\n"); ++} ++ ++/* Look for vendor-specific IE with specified OUI and optional type */ ++bcm_tlv_t * ++bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len) ++{ ++ bcm_tlv_t *ie; ++ uint8 ie_len; ++ ++ ie = (bcm_tlv_t*)tlvs; ++ ++ /* make sure we are looking at a valid IE */ ++ if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) { ++ return NULL; ++ } ++ ++ /* Walk through the IEs looking for an OUI match */ ++ do { ++ ie_len = ie->len; ++ if ((ie->id == DOT11_MNG_PROPR_ID) && ++ (ie_len >= (DOT11_OUI_LEN + type_len)) && ++ !bcmp(ie->data, voui, DOT11_OUI_LEN)) ++ { ++ /* compare optional type */ ++ if (type_len == 0 || ++ !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) { ++ return (ie); /* a match */ ++ } ++ } ++ } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL); ++ ++ return NULL; ++} ++ ++#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ ++ defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) ++#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) ++ ++int ++bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) ++{ ++ uint i, c; ++ char *p = buf; ++ char *endp = buf + SSID_FMT_BUF_LEN; ++ ++ if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; ++ ++ for (i = 0; i < ssid_len; i++) { ++ c = (uint)ssid[i]; ++ if (c == '\\') { ++ *p++ = '\\'; ++ *p++ = '\\'; ++ } else if (bcm_isprint((uchar)c)) { ++ *p++ = (char)c; ++ } else { ++ p += snprintf(p, (endp - p), "\\x%02X", c); ++ } ++ } ++ *p = '\0'; ++ ASSERT(p < endp); ++ ++ return (int)(p - buf); ++} ++#endif ++ ++#endif /* BCMDRIVER || WL_UNITTEST */ ++ ++/* ++ * ProcessVars:Takes a buffer of "=\n" lines read from a file and ending in a NUL. ++ * also accepts nvram files which are already in the format of =\0\=\0 ++ * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs. ++ * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs. ++*/ ++ ++unsigned int ++process_nvram_vars(char *varbuf, unsigned int len) ++{ ++ char *dp; ++ bool findNewline; ++ int column; ++ unsigned int buf_len, n; ++ unsigned int pad = 0; ++ char nv_ver[128]; ++ ++ dp = varbuf; ++ ++ findNewline = FALSE; ++ column = 0; ++ ++ // terence 20130914: print out NVRAM version ++ if (varbuf[0] == '#') { ++ memset(nv_ver, 0x00, sizeof(nv_ver)); ++ for (n=1; n> 16; ++ a0 = a & 0xffff; ++ b1 = b >> 16; ++ b0 = b & 0xffff; ++ ++ r0 = a0 * b0; ++ FORMALIZE(r0); ++ ++ t = (a1 * b0) << 16; ++ FORMALIZE(t); ++ ++ r0 += t; ++ FORMALIZE(r0); ++ ++ t = (a0 * b1) << 16; ++ FORMALIZE(t); ++ ++ r0 += t; ++ FORMALIZE(r0); ++ ++ FORMALIZE(c); ++ ++ r0 += c; ++ FORMALIZE(r0); ++ ++ r0 |= (cc % 2) ? 0x80000000 : 0; ++ r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2); ++ ++ *r_high = r1; ++ *r_low = r0; ++} ++ ++/* calculate a / b */ ++void ++bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b) ++{ ++ uint32 a1 = a_high, a0 = a_low, r0 = 0; ++ ++ if (b < 2) ++ return; ++ ++ while (a1 != 0) { ++ r0 += (0xffffffff / b) * a1; ++ bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0); ++ } ++ ++ r0 += a0 / b; ++ *r = r0; ++} ++ ++#ifndef setbit /* As in the header file */ ++#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS ++/* Set bit in byte array. */ ++void ++setbit(void *array, uint bit) ++{ ++ ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY); ++} ++ ++/* Clear bit in byte array. */ ++void ++clrbit(void *array, uint bit) ++{ ++ ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY)); ++} ++ ++/* Test if bit is set in byte array. */ ++bool ++isset(const void *array, uint bit) ++{ ++ return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))); ++} ++ ++/* Test if bit is clear in byte array. */ ++bool ++isclr(const void *array, uint bit) ++{ ++ return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0); ++} ++#endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */ ++#endif /* setbit */ ++ ++void ++set_bitrange(void *array, uint start, uint end, uint maxbit) ++{ ++ uint startbyte = start/NBBY; ++ uint endbyte = end/NBBY; ++ uint i, startbytelastbit, endbytestartbit; ++ ++ if (end >= start) { ++ if (endbyte - startbyte > 1) ++ { ++ startbytelastbit = (startbyte+1)*NBBY - 1; ++ endbytestartbit = endbyte*NBBY; ++ for (i = startbyte+1; i < endbyte; i++) ++ ((uint8 *)array)[i] = 0xFF; ++ for (i = start; i <= startbytelastbit; i++) ++ setbit(array, i); ++ for (i = endbytestartbit; i <= end; i++) ++ setbit(array, i); ++ } else { ++ for (i = start; i <= end; i++) ++ setbit(array, i); ++ } ++ } ++ else { ++ set_bitrange(array, start, maxbit, maxbit); ++ set_bitrange(array, 0, end, maxbit); ++ } ++} ++ ++void ++bcm_bitprint32(const uint32 u32arg) ++{ ++ int i; ++ for (i = NBITS(uint32) - 1; i >= 0; i--) { ++ if (isbitset(u32arg, i)) { ++ printf("1"); ++ } else { ++ printf("0"); ++ } ++ ++ if ((i % NBBY) == 0) printf(" "); ++ } ++ printf("\n"); ++} ++ ++/* calculate checksum for ip header, tcp / udp header / data */ ++uint16 ++bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum) ++{ ++ while (len > 1) { ++ sum += (buf[0] << 8) | buf[1]; ++ buf += 2; ++ len -= 2; ++ } ++ ++ if (len > 0) { ++ sum += (*buf) << 8; ++ } ++ ++ while (sum >> 16) { ++ sum = (sum & 0xffff) + (sum >> 16); ++ } ++ ++ return ((uint16)~sum); ++} ++#if defined(BCMDRIVER) && !defined(_CFEZ_) ++/* ++ * Hierarchical Multiword bitmap based small id allocator. ++ * ++ * Multilevel hierarchy bitmap. (maximum 2 levels) ++ * First hierarchy uses a multiword bitmap to identify 32bit words in the ++ * second hierarchy that have at least a single bit set. Each bit in a word of ++ * the second hierarchy represents a unique ID that may be allocated. ++ * ++ * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed. ++ * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word ++ * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs. ++ * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non ++ * non-zero bitmap word carrying at least one free ID. ++ * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations. ++ * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID ++ * ++ * Design Notes: ++ * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many ++ * bits are computed each time on allocation and deallocation, requiring 4 ++ * array indexed access and 3 arithmetic operations. When not defined, a runtime ++ * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed. ++ * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation. ++ * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may ++ * be used by defining BCM_MWBMAP_USE_CNTSETBITS. ++ * ++ * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array ++ * size is fixed. No intention to support larger than 4K indice allocation. ID ++ * allocators for ranges smaller than 4K will have a wastage of only 12Bytes ++ * with savings in not having to use an indirect access, had it been dynamically ++ * allocated. ++ */ ++#define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */ ++ ++#define BCM_MWBMAP_BITS_WORD (NBITS(uint32)) ++#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD) ++#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD) ++#define BCM_MWBMAP_SHIFT_OP (5) ++#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1)) ++#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP) ++#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP) ++ ++/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */ ++#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl)) ++#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr)) ++ ++#if defined(BCM_MWBMAP_DEBUG) ++#define BCM_MWBMAP_AUDIT(mwb) \ ++ do { \ ++ ASSERT((mwb != NULL) && \ ++ (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \ ++ bcm_mwbmap_audit(mwb); \ ++ } while (0) ++#define MWBMAP_ASSERT(exp) ASSERT(exp) ++#define MWBMAP_DBG(x) printf x ++#else /* !BCM_MWBMAP_DEBUG */ ++#define BCM_MWBMAP_AUDIT(mwb) do {} while (0) ++#define MWBMAP_ASSERT(exp) do {} while (0) ++#define MWBMAP_DBG(x) ++#endif /* !BCM_MWBMAP_DEBUG */ ++ ++ ++typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */ ++ uint16 wmaps; /* Total number of words in free wd bitmap */ ++ uint16 imaps; /* Total number of words in free id bitmap */ ++ int32 ifree; /* Count of free indices. Used only in audits */ ++ uint16 total; /* Total indices managed by multiword bitmap */ ++ ++ void * magic; /* Audit handle parameter from user */ ++ ++ uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */ ++#if !defined(BCM_MWBMAP_USE_CNTSETBITS) ++ int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */ ++#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ ++ uint32 id_bitmap[0]; /* Second level bitmap */ ++} bcm_mwbmap_t; ++ ++/* Incarnate a hierarchical multiword bitmap based small index allocator. */ ++struct bcm_mwbmap * ++bcm_mwbmap_init(osl_t *osh, uint32 items_max) ++{ ++ struct bcm_mwbmap * mwbmap_p; ++ uint32 wordix, size, words, extra; ++ ++ /* Implementation Constraint: Uses 32bit word bitmap */ ++ MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U); ++ MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U); ++ MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX)); ++ MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U); ++ ++ ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX); ++ ++ /* Determine the number of words needed in the multiword bitmap */ ++ extra = BCM_MWBMAP_MODOP(items_max); ++ words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U); ++ ++ /* Allocate runtime state of multiword bitmap */ ++ /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */ ++ size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words); ++ mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size); ++ if (mwbmap_p == (bcm_mwbmap_t *)NULL) { ++ ASSERT(0); ++ goto error1; ++ } ++ memset(mwbmap_p, 0, size); ++ ++ /* Initialize runtime multiword bitmap state */ ++ mwbmap_p->imaps = (uint16)words; ++ mwbmap_p->ifree = (int32)items_max; ++ mwbmap_p->total = (uint16)items_max; ++ ++ /* Setup magic, for use in audit of handle */ ++ mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p); ++ ++ /* Setup the second level bitmap of free indices */ ++ /* Mark all indices as available */ ++ for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) { ++ mwbmap_p->id_bitmap[wordix] = (uint32)(~0U); ++#if !defined(BCM_MWBMAP_USE_CNTSETBITS) ++ mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD; ++#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ } ++ ++ /* Ensure that extra indices are tagged as un-available */ ++ if (extra) { /* fixup the free ids in last bitmap and wd_count */ ++ uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1]; ++ *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ ++#if !defined(BCM_MWBMAP_USE_CNTSETBITS) ++ mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */ ++#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ } ++ ++ /* Setup the first level bitmap hierarchy */ ++ extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps); ++ words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U); ++ ++ mwbmap_p->wmaps = (uint16)words; ++ ++ for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++) ++ mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U); ++ if (extra) { ++ uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1]; ++ *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ ++ } ++ ++ return mwbmap_p; ++ ++error1: ++ return BCM_MWBMAP_INVALID_HDL; ++} ++ ++/* Release resources used by multiword bitmap based small index allocator. */ ++void ++bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) ++{ ++ bcm_mwbmap_t * mwbmap_p; ++ ++ BCM_MWBMAP_AUDIT(mwbmap_hdl); ++ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); ++ ++ MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap) ++ + (sizeof(uint32) * mwbmap_p->imaps)); ++ return; ++} ++ ++/* Allocate a unique small index using a multiword bitmap index allocator. */ ++uint32 BCMFASTPATH ++bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl) ++{ ++ bcm_mwbmap_t * mwbmap_p; ++ uint32 wordix, bitmap; ++ ++ BCM_MWBMAP_AUDIT(mwbmap_hdl); ++ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); ++ ++ /* Start with the first hierarchy */ ++ for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) { ++ ++ bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */ ++ ++ if (bitmap != 0U) { ++ ++ uint32 count, bitix, *bitmap_p; ++ ++ bitmap_p = &mwbmap_p->wd_bitmap[wordix]; ++ ++ /* clear all except trailing 1 */ ++ bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); ++ MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == ++ bcm_count_leading_zeros(bitmap)); ++ bitix = (BCM_MWBMAP_BITS_WORD - 1) ++ - bcm_count_leading_zeros(bitmap); /* use asm clz */ ++ wordix = BCM_MWBMAP_MULOP(wordix) + bitix; ++ ++ /* Clear bit if wd count is 0, without conditional branch */ ++#if defined(BCM_MWBMAP_USE_CNTSETBITS) ++ count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1; ++#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ mwbmap_p->wd_count[wordix]--; ++ count = mwbmap_p->wd_count[wordix]; ++ MWBMAP_ASSERT(count == ++ (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1)); ++#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ MWBMAP_ASSERT(count >= 0); ++ ++ /* clear wd_bitmap bit if id_map count is 0 */ ++ bitmap = (count == 0) << bitix; ++ ++ MWBMAP_DBG(( ++ "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d", ++ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count)); ++ ++ *bitmap_p ^= bitmap; ++ ++ /* Use bitix in the second hierarchy */ ++ bitmap_p = &mwbmap_p->id_bitmap[wordix]; ++ ++ bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */ ++ MWBMAP_ASSERT(bitmap != 0U); ++ ++ /* clear all except trailing 1 */ ++ bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); ++ MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == ++ bcm_count_leading_zeros(bitmap)); ++ bitix = BCM_MWBMAP_MULOP(wordix) ++ + (BCM_MWBMAP_BITS_WORD - 1) ++ - bcm_count_leading_zeros(bitmap); /* use asm clz */ ++ ++ mwbmap_p->ifree--; /* decrement system wide free count */ ++ MWBMAP_ASSERT(mwbmap_p->ifree >= 0); ++ ++ MWBMAP_DBG(( ++ "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d", ++ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, ++ mwbmap_p->ifree)); ++ ++ *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */ ++ ++ return bitix; ++ } ++ } ++ ++ ASSERT(mwbmap_p->ifree == 0); ++ ++ return BCM_MWBMAP_INVALID_IDX; ++} ++ ++/* Force an index at a specified position to be in use */ ++void ++bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) ++{ ++ bcm_mwbmap_t * mwbmap_p; ++ uint32 count, wordix, bitmap, *bitmap_p; ++ ++ BCM_MWBMAP_AUDIT(mwbmap_hdl); ++ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); ++ ++ ASSERT(bitix < mwbmap_p->total); ++ ++ /* Start with second hierarchy */ ++ wordix = BCM_MWBMAP_DIVOP(bitix); ++ bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix)); ++ bitmap_p = &mwbmap_p->id_bitmap[wordix]; ++ ++ ASSERT((*bitmap_p & bitmap) == bitmap); ++ ++ mwbmap_p->ifree--; /* update free count */ ++ ASSERT(mwbmap_p->ifree >= 0); ++ ++ MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d", ++ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, ++ mwbmap_p->ifree)); ++ ++ *bitmap_p ^= bitmap; /* mark as in use */ ++ ++ /* Update first hierarchy */ ++ bitix = wordix; ++ ++ wordix = BCM_MWBMAP_DIVOP(bitix); ++ bitmap_p = &mwbmap_p->wd_bitmap[wordix]; ++ ++#if defined(BCM_MWBMAP_USE_CNTSETBITS) ++ count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); ++#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ mwbmap_p->wd_count[bitix]--; ++ count = mwbmap_p->wd_count[bitix]; ++ MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); ++#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ MWBMAP_ASSERT(count >= 0); ++ ++ bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix); ++ ++ MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d", ++ BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap, ++ (*bitmap_p) ^ bitmap, count)); ++ ++ *bitmap_p ^= bitmap; /* mark as in use */ ++ ++ return; ++} ++ ++/* Free a previously allocated index back into the multiword bitmap allocator */ ++void BCMFASTPATH ++bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) ++{ ++ bcm_mwbmap_t * mwbmap_p; ++ uint32 wordix, bitmap, *bitmap_p; ++ ++ BCM_MWBMAP_AUDIT(mwbmap_hdl); ++ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); ++ ++ ASSERT(bitix < mwbmap_p->total); ++ ++ /* Start with second level hierarchy */ ++ wordix = BCM_MWBMAP_DIVOP(bitix); ++ bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); ++ bitmap_p = &mwbmap_p->id_bitmap[wordix]; ++ ++ ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */ ++ ++ mwbmap_p->ifree++; /* update free count */ ++ ASSERT(mwbmap_p->ifree <= mwbmap_p->total); ++ ++ MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d", ++ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, ++ mwbmap_p->ifree)); ++ ++ *bitmap_p |= bitmap; /* mark as available */ ++ ++ /* Now update first level hierarchy */ ++ ++ bitix = wordix; ++ ++ wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */ ++ bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); ++ bitmap_p = &mwbmap_p->wd_bitmap[wordix]; ++ ++#if !defined(BCM_MWBMAP_USE_CNTSETBITS) ++ mwbmap_p->wd_count[bitix]++; ++#endif ++ ++#if defined(BCM_MWBMAP_DEBUG) ++ { ++ uint32 count; ++#if defined(BCM_MWBMAP_USE_CNTSETBITS) ++ count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); ++#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ count = mwbmap_p->wd_count[bitix]; ++ MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); ++#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ ++ MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD); ++ ++ MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d", ++ bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count)); ++ } ++#endif /* BCM_MWBMAP_DEBUG */ ++ ++ *bitmap_p |= bitmap; ++ ++ return; ++} ++ ++/* Fetch the toal number of free indices in the multiword bitmap allocator */ ++uint32 ++bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl) ++{ ++ bcm_mwbmap_t * mwbmap_p; ++ ++ BCM_MWBMAP_AUDIT(mwbmap_hdl); ++ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); ++ ++ ASSERT(mwbmap_p->ifree >= 0); ++ ++ return mwbmap_p->ifree; ++} ++ ++/* Determine whether an index is inuse or free */ ++bool ++bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) ++{ ++ bcm_mwbmap_t * mwbmap_p; ++ uint32 wordix, bitmap; ++ ++ BCM_MWBMAP_AUDIT(mwbmap_hdl); ++ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); ++ ++ ASSERT(bitix < mwbmap_p->total); ++ ++ wordix = BCM_MWBMAP_DIVOP(bitix); ++ bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); ++ ++ return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U); ++} ++ ++/* Debug dump a multiword bitmap allocator */ ++void ++bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl) ++{ ++ uint32 ix, count; ++ bcm_mwbmap_t * mwbmap_p; ++ ++ BCM_MWBMAP_AUDIT(mwbmap_hdl); ++ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); ++ ++ printf("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p, ++ mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total); ++ for (ix = 0U; ix < mwbmap_p->wmaps; ix++) { ++ printf("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix]); ++ bcm_bitprint32(mwbmap_p->wd_bitmap[ix]); ++ printf("\n"); ++ } ++ for (ix = 0U; ix < mwbmap_p->imaps; ix++) { ++#if defined(BCM_MWBMAP_USE_CNTSETBITS) ++ count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]); ++#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ count = mwbmap_p->wd_count[ix]; ++ MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix])); ++#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ printf("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count); ++ bcm_bitprint32(mwbmap_p->id_bitmap[ix]); ++ printf("\n"); ++ } ++ ++ return; ++} ++ ++/* Audit a hierarchical multiword bitmap */ ++void ++bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) ++{ ++ bcm_mwbmap_t * mwbmap_p; ++ uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p; ++ ++ mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); ++ ++ for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) { ++ ++ bitmap_p = &mwbmap_p->wd_bitmap[wordix]; ++ ++ for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) { ++ if ((*bitmap_p) & (1 << bitix)) { ++ idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix; ++#if defined(BCM_MWBMAP_USE_CNTSETBITS) ++ count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]); ++#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ count = mwbmap_p->wd_count[idmap_ix]; ++ ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix])); ++#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ ++ ASSERT(count != 0U); ++ free_cnt += count; ++ } ++ } ++ } ++ ++ ASSERT((int)free_cnt == mwbmap_p->ifree); ++} ++/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */ ++ ++/* Simple 16bit Id allocator using a stack implementation. */ ++typedef struct id16_map { ++ uint32 failures; /* count of failures */ ++ void *dbg; /* debug placeholder */ ++ uint16 total; /* total number of ids managed by allocator */ ++ uint16 start; /* start value of 16bit ids to be managed */ ++ int stack_idx; /* index into stack of available ids */ ++ uint16 stack[0]; /* stack of 16 bit ids */ ++} id16_map_t; ++ ++#define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \ ++ (sizeof(uint16) * (items))) ++ ++#if defined(BCM_DBG) ++ ++/* Uncomment BCM_DBG_ID16 to debug double free */ ++/* #define BCM_DBG_ID16 */ ++ ++typedef struct id16_map_dbg { ++ uint16 total; ++ bool avail[0]; ++} id16_map_dbg_t; ++#define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \ ++ (sizeof(bool) * (items))) ++#define ID16_MAP_MSG(x) print x ++#else ++#define ID16_MAP_MSG(x) ++#endif /* BCM_DBG */ ++ ++void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */ ++id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16) ++{ ++ uint16 idx, val16; ++ id16_map_t * id16_map; ++ ++ ASSERT(total_ids > 0); ++ ++ /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map ++ * with random values. ++ */ ++ ASSERT((start_val16 == ID16_UNDEFINED) || ++ (start_val16 + total_ids) < ID16_INVALID); ++ ++ id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids)); ++ if (id16_map == NULL) { ++ return NULL; ++ } ++ ++ id16_map->total = total_ids; ++ id16_map->start = start_val16; ++ id16_map->failures = 0; ++ id16_map->dbg = NULL; ++ ++ /* ++ * Populate stack with 16bit id values, commencing with start_val16. ++ * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map. ++ */ ++ id16_map->stack_idx = -1; ++ ++ if (id16_map->start != ID16_UNDEFINED) { ++ val16 = start_val16; ++ ++ for (idx = 0; idx < total_ids; idx++, val16++) { ++ id16_map->stack_idx = idx; ++ id16_map->stack[id16_map->stack_idx] = val16; ++ } ++ } ++ ++#if defined(BCM_DBG) && defined(BCM_DBG_ID16) ++ if (id16_map->start != ID16_UNDEFINED) { ++ id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids)); ++ ++ if (id16_map->dbg) { ++ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; ++ ++ id16_map_dbg->total = total_ids; ++ for (idx = 0; idx < total_ids; idx++) { ++ id16_map_dbg->avail[idx] = TRUE; ++ } ++ } ++ } ++#endif /* BCM_DBG && BCM_DBG_ID16 */ ++ ++ return (void *)id16_map; ++} ++ ++void * /* Destruct an id16 allocator instance */ ++id16_map_fini(osl_t *osh, void * id16_map_hndl) ++{ ++ uint16 total_ids; ++ id16_map_t * id16_map; ++ ++ if (id16_map_hndl == NULL) ++ return NULL; ++ ++ id16_map = (id16_map_t *)id16_map_hndl; ++ ++ total_ids = id16_map->total; ++ ASSERT(total_ids > 0); ++ ++#if defined(BCM_DBG) && defined(BCM_DBG_ID16) ++ if (id16_map->dbg) { ++ MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids)); ++ id16_map->dbg = NULL; ++ } ++#endif /* BCM_DBG && BCM_DBG_ID16 */ ++ ++ id16_map->total = 0; ++ MFREE(osh, id16_map, ID16_MAP_SZ(total_ids)); ++ ++ return NULL; ++} ++ ++void ++id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16) ++{ ++ uint16 idx, val16; ++ id16_map_t * id16_map; ++ ++ ASSERT(total_ids > 0); ++ /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map ++ * with random values. ++ */ ++ ASSERT((start_val16 == ID16_UNDEFINED) || ++ (start_val16 + total_ids) < ID16_INVALID); ++ ++ id16_map = (id16_map_t *)id16_map_hndl; ++ if (id16_map == NULL) { ++ return; ++ } ++ ++ id16_map->total = total_ids; ++ id16_map->start = start_val16; ++ id16_map->failures = 0; ++ ++ /* Populate stack with 16bit id values, commencing with start_val16 */ ++ id16_map->stack_idx = -1; ++ ++ if (id16_map->start != ID16_UNDEFINED) { ++ val16 = start_val16; ++ ++ for (idx = 0; idx < total_ids; idx++, val16++) { ++ id16_map->stack_idx = idx; ++ id16_map->stack[id16_map->stack_idx] = val16; ++ } ++ } ++ ++#if defined(BCM_DBG) && defined(BCM_DBG_ID16) ++ if (id16_map->start != ID16_UNDEFINED) { ++ if (id16_map->dbg) { ++ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; ++ ++ id16_map_dbg->total = total_ids; ++ for (idx = 0; idx < total_ids; idx++) { ++ id16_map_dbg->avail[idx] = TRUE; ++ } ++ } ++ } ++#endif /* BCM_DBG && BCM_DBG_ID16 */ ++} ++ ++uint16 BCMFASTPATH /* Allocate a unique 16bit id */ ++id16_map_alloc(void * id16_map_hndl) ++{ ++ uint16 val16; ++ id16_map_t * id16_map; ++ ++ ASSERT(id16_map_hndl != NULL); ++ ++ id16_map = (id16_map_t *)id16_map_hndl; ++ ++ ASSERT(id16_map->total > 0); ++ ++ if (id16_map->stack_idx < 0) { ++ id16_map->failures++; ++ return ID16_INVALID; ++ } ++ ++ val16 = id16_map->stack[id16_map->stack_idx]; ++ id16_map->stack_idx--; ++ ++#if defined(BCM_DBG) && defined(BCM_DBG_ID16) ++ ASSERT((id16_map->start == ID16_UNDEFINED) || ++ (val16 < (id16_map->start + id16_map->total))); ++ ++ if (id16_map->dbg) { /* Validate val16 */ ++ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; ++ ++ ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE); ++ id16_map_dbg->avail[val16 - id16_map->start] = FALSE; ++ } ++#endif /* BCM_DBG && BCM_DBG_ID16 */ ++ ++ return val16; ++} ++ ++ ++void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */ ++id16_map_free(void * id16_map_hndl, uint16 val16) ++{ ++ id16_map_t * id16_map; ++ ++ ASSERT(id16_map_hndl != NULL); ++ ++ id16_map = (id16_map_t *)id16_map_hndl; ++ ++#if defined(BCM_DBG) && defined(BCM_DBG_ID16) ++ ASSERT((id16_map->start == ID16_UNDEFINED) || ++ (val16 < (id16_map->start + id16_map->total))); ++ ++ if (id16_map->dbg) { /* Validate val16 */ ++ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; ++ ++ ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE); ++ id16_map_dbg->avail[val16 - id16_map->start] = TRUE; ++ } ++#endif /* BCM_DBG && BCM_DBG_ID16 */ ++ ++ id16_map->stack_idx++; ++ id16_map->stack[id16_map->stack_idx] = val16; ++} ++ ++uint32 /* Returns number of failures to allocate an unique id16 */ ++id16_map_failures(void * id16_map_hndl) ++{ ++ ASSERT(id16_map_hndl != NULL); ++ return ((id16_map_t *)id16_map_hndl)->failures; ++} ++ ++bool ++id16_map_audit(void * id16_map_hndl) ++{ ++ int idx; ++ int insane = 0; ++ id16_map_t * id16_map; ++ ++ ASSERT(id16_map_hndl != NULL); ++ ++ id16_map = (id16_map_t *)id16_map_hndl; ++ ++ ASSERT(id16_map->stack_idx >= -1); ++ ASSERT(id16_map->stack_idx < (int)id16_map->total); ++ ++ if (id16_map->start == ID16_UNDEFINED) ++ goto done; ++ ++ for (idx = 0; idx <= id16_map->stack_idx; idx++) { ++ ASSERT(id16_map->stack[idx] >= id16_map->start); ++ ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total)); ++ ++#if defined(BCM_DBG) && defined(BCM_DBG_ID16) ++ if (id16_map->dbg) { ++ uint16 val16 = id16_map->stack[idx]; ++ if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) { ++ insane |= 1; ++ ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n", ++ id16_map_hndl, idx, val16)); ++ } ++ } ++#endif /* BCM_DBG && BCM_DBG_ID16 */ ++ } ++ ++#if defined(BCM_DBG) && defined(BCM_DBG_ID16) ++ if (id16_map->dbg) { ++ uint16 avail = 0; /* Audit available ids counts */ ++ for (idx = 0; idx < id16_map_dbg->total; idx++) { ++ if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE) ++ avail++; ++ } ++ if (avail && (avail != (id16_map->stack_idx + 1))) { ++ insane |= 1; ++ ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n", ++ id16_map_hndl, avail, id16_map->stack_idx)); ++ } ++ } ++#endif /* BCM_DBG && BCM_DBG_ID16 */ ++ ++done: ++ /* invoke any other system audits */ ++ return (!!insane); ++} ++/* END: Simple id16 allocator */ ++ ++ ++#endif ++ ++/* calculate a >> b; and returns only lower 32 bits */ ++void ++bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b) ++{ ++ uint32 a1 = a_high, a0 = a_low, r0 = 0; ++ ++ if (b == 0) { ++ r0 = a_low; ++ *r = r0; ++ return; ++ } ++ ++ if (b < 32) { ++ a0 = a0 >> b; ++ a1 = a1 & ((1 << b) - 1); ++ a1 = a1 << (32 - b); ++ r0 = a0 | a1; ++ *r = r0; ++ return; ++ } else { ++ r0 = a1 >> (b - 32); ++ *r = r0; ++ return; ++ } ++ ++} ++ ++/* calculate a + b where a is a 64 bit number and b is a 32 bit number */ ++void ++bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset) ++{ ++ uint32 r1_lo = *r_lo; ++ (*r_lo) += offset; ++ if (*r_lo < r1_lo) ++ (*r_hi) ++; ++} ++ ++/* calculate a - b where a is a 64 bit number and b is a 32 bit number */ ++void ++bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset) ++{ ++ uint32 r1_lo = *r_lo; ++ (*r_lo) -= offset; ++ if (*r_lo > r1_lo) ++ (*r_hi) --; ++} ++ ++/* Does unsigned 64 bit fixed point multiplication */ ++uint64 ++fp_mult_64(uint64 val1, uint64 val2, uint8 nf1, uint8 nf2, uint8 nf_res) ++{ ++ uint64 mult_out_tmp, mult_out, rnd_val; ++ uint8 shift_amt; ++ ++ shift_amt = nf1 + nf2 - nf_res; ++ /* 0.5 in 1.0.shift_amt */ ++ rnd_val = bcm_shl_64(1, (shift_amt - 1)); ++ rnd_val = (shift_amt == 0) ? 0 : rnd_val; ++ mult_out_tmp = (uint64)((uint64)val1 * (uint64)val2) + (uint64)rnd_val; ++ mult_out = bcm_shr_64(mult_out_tmp, shift_amt); ++ ++ return mult_out; ++} ++ ++ ++/* Does unsigned 64 bit by 32 bit fixed point division */ ++uint8 ++fp_div_64(uint64 num, uint32 den, uint8 nf_num, uint8 nf_den, uint32 *div_out) ++{ ++ uint8 shift_amt1, shift_amt2, shift_amt, nf_res, hd_rm_nr, hd_rm_dr; ++ uint32 num_hi, num_lo; ++ uint64 num_scale; ++ ++ /* Worst case shift possible */ ++ hd_rm_nr = fp_calc_head_room_64(num); ++ hd_rm_dr = fp_calc_head_room_32(den); ++ ++ /* (Nr / Dr) <= 2^32 */ ++ shift_amt1 = hd_rm_nr - hd_rm_dr - 1; ++ /* Shift <= 32 + N2 - N1 */ ++ shift_amt2 = 31 + nf_den - nf_num; ++ shift_amt = MINIMUM(shift_amt1, shift_amt2); ++ ++ /* Scale numerator */ ++ num_scale = bcm_shl_64(num, shift_amt); ++ ++ /* Do division */ ++ num_hi = (uint32)((uint64)num_scale >> 32) & MASK_32_BITS; ++ num_lo = (uint32)(num_scale & MASK_32_BITS); ++ bcm_uint64_divide(div_out, num_hi, num_lo, den); ++ ++ /* Result format */ ++ nf_res = nf_num - nf_den + shift_amt; ++ return nf_res; ++} ++ ++/* Finds the number of bits available for shifting in unsigned 64 bit number */ ++uint8 ++fp_calc_head_room_64(uint64 num) ++{ ++ uint8 n_room_bits = 0, msb_pos; ++ uint32 num_hi, num_lo, x; ++ ++ num_hi = (uint32)((uint64)num >> 32) & MASK_32_BITS; ++ num_lo = (uint32)(num & MASK_32_BITS); ++ ++ if (num_hi > 0) { ++ x = num_hi; ++ n_room_bits = 0; ++ } else { ++ x = num_lo; ++ n_room_bits = 32; ++ } ++ ++ msb_pos = (x >> 16) ? ((x >> 24) ? (24 + msb_table[(x >> 24) & MASK_8_BITS]) ++ : (16 + msb_table[(x >> 16) & MASK_8_BITS])) ++ : ((x >> 8) ? (8 + msb_table[(x >> 8) & MASK_8_BITS]) ++ : msb_table[x & MASK_8_BITS]); ++ ++ return (n_room_bits + 32 - msb_pos); ++} ++ ++/* Finds the number of bits available for shifting in unsigned 32 bit number */ ++uint8 ++fp_calc_head_room_32(uint32 x) ++{ ++ uint8 msb_pos; ++ ++ msb_pos = (x >> 16) ? ((x >> 24) ? (24 + msb_table[(x >> 24) & MASK_8_BITS]) ++ : (16 + msb_table[(x >> 16) & MASK_8_BITS])) ++ : ((x >> 8) ? (8 + msb_table[(x >> 8) & MASK_8_BITS]) ++ : msb_table[x & MASK_8_BITS]); ++ ++ return (32 - msb_pos); ++} ++ ++/* Does unsigned 64 bit fixed point floor */ ++uint32 ++fp_floor_64(uint64 num, uint8 floor_pos) ++{ ++ uint32 floor_out; ++ ++ floor_out = (uint32)bcm_shr_64(num, floor_pos); ++ ++ return floor_out; ++} ++ ++/* Does unsigned 32 bit fixed point floor */ ++uint32 ++fp_floor_32(uint32 num, uint8 floor_pos) ++{ ++ return num >> floor_pos; ++} ++ ++/* Does unsigned 64 bit fixed point rounding */ ++uint32 ++fp_round_64(uint64 num, uint8 rnd_pos) ++{ ++ uint64 rnd_val, rnd_out_tmp; ++ uint32 rnd_out; ++ ++ /* 0.5 in 1.0.rnd_pos */ ++ rnd_val = bcm_shl_64(1, (rnd_pos - 1)); ++ rnd_val = (rnd_pos == 0) ? 0 : rnd_val; ++ rnd_out_tmp = num + rnd_val; ++ rnd_out = (uint32)bcm_shr_64(rnd_out_tmp, rnd_pos); ++ ++ return rnd_out; ++} ++ ++/* Does unsigned 32 bit fixed point rounding */ ++uint32 ++fp_round_32(uint32 num, uint8 rnd_pos) ++{ ++ uint32 rnd_val, rnd_out_tmp; ++ ++ /* 0.5 in 1.0.rnd_pos */ ++ rnd_val = 1 << (rnd_pos - 1); ++ rnd_val = (rnd_pos == 0) ? 0 : rnd_val; ++ rnd_out_tmp = num + rnd_val; ++ return (rnd_out_tmp >> rnd_pos); ++} ++ ++/* Does unsigned fixed point ceiling */ ++uint32 ++fp_ceil_64(uint64 num, uint8 ceil_pos) ++{ ++ uint64 ceil_val, ceil_out_tmp; ++ uint32 ceil_out; ++ ++ /* 0.999 in 1.0.rnd_pos */ ++ ceil_val = bcm_shl_64(1, ceil_pos) - 1; ++ ceil_out_tmp = num + ceil_val; ++ ceil_out = (uint32)bcm_shr_64(ceil_out_tmp, ceil_pos); ++ ++ return ceil_out; ++} ++ ++/* Does left shift of unsigned 64 bit number */ ++uint64 ++bcm_shl_64(uint64 input, uint8 shift_amt) ++{ ++ uint32 in_hi, in_lo; ++ uint32 masked_lo = 0; ++ uint32 mask; ++ uint64 shl_out; ++ ++ if (shift_amt == 0) { ++ return input; ++ } ++ ++ /* Get hi and lo part */ ++ in_hi = (uint32)((uint64)input >> 32) & MASK_32_BITS; ++ in_lo = (uint32)(input & MASK_32_BITS); ++ ++ if (shift_amt < 32) { ++ /* Extract bit which belongs to hi part after shifting */ ++ mask = ((uint32)~0) << (32 - shift_amt); ++ masked_lo = (in_lo & mask) >> (32 - shift_amt); ++ ++ /* Shift hi and lo and prepare output */ ++ in_hi = (in_hi << shift_amt) | masked_lo; ++ in_lo = in_lo << shift_amt; ++ } else { ++ /* Extract bit which belongs to hi part after shifting */ ++ shift_amt = shift_amt - 32; ++ ++ /* Shift hi and lo and prepare output */ ++ in_hi = in_lo << shift_amt; ++ in_lo = 0; ++ } ++ ++ shl_out = (((uint64)in_hi << 32) | in_lo); ++ return shl_out; ++} ++ ++/* Does right shift of unsigned 64 bit number */ ++uint64 ++bcm_shr_64(uint64 input, uint8 shift_amt) ++{ ++ uint32 in_hi, in_lo; ++ uint32 masked_hi = 0; ++ uint32 mask; ++ uint64 shr_out; ++ ++ if (shift_amt == 0) { ++ return input; ++ } ++ ++ /* Get hi and lo part */ ++ in_hi = (uint32)((uint64)input >> 32) & MASK_32_BITS; ++ in_lo = (uint32)(input & MASK_32_BITS); ++ ++ if (shift_amt < 32) { ++ /* Extract bit which belongs to lo part after shifting */ ++ mask = (1 << shift_amt) - 1; ++ masked_hi = in_hi & mask; ++ ++ /* Shift hi and lo and prepare output */ ++ in_hi = (uint32)in_hi >> shift_amt; ++ in_lo = ((uint32)in_lo >> shift_amt) | (masked_hi << (32 - shift_amt)); ++ } else { ++ shift_amt = shift_amt - 32; ++ in_lo = in_hi >> shift_amt; ++ in_hi = 0; ++ } ++ ++ shr_out = (((uint64)in_hi << 32) | in_lo); ++ return shr_out; ++} ++ ++#ifdef DEBUG_COUNTER ++#if (OSL_SYSUPTIME_SUPPORT == TRUE) ++void counter_printlog(counter_tbl_t *ctr_tbl) ++{ ++ uint32 now; ++ ++ if (!ctr_tbl->enabled) ++ return; ++ ++ now = OSL_SYSUPTIME(); ++ ++ if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) { ++ uint8 i = 0; ++ printf("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print); ++ ++ for (i = 0; i < ctr_tbl->needed_cnt; i++) { ++ printf(" %u", ctr_tbl->cnt[i]); ++ } ++ printf("\n"); ++ ++ ctr_tbl->prev_log_print = now; ++ bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint)); ++ } ++} ++#else ++/* OSL_SYSUPTIME is not supported so no way to get time */ ++#define counter_printlog(a) do {} while (0) ++#endif /* OSL_SYSUPTIME_SUPPORT == TRUE */ ++#endif /* DEBUG_COUNTER */ ++ ++#if defined(BCMDRIVER) && !defined(_CFEZ_) ++void ++dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size) ++{ ++ uint32 mem_size; ++ mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); ++ if (pool) ++ MFREE(osh, pool, mem_size); ++} ++dll_pool_t * ++dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size) ++{ ++ uint32 mem_size, i; ++ dll_pool_t * dll_pool_p; ++ dll_t * elem_p; ++ ++ ASSERT(elem_size > sizeof(dll_t)); ++ ++ mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); ++ ++ if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, mem_size)) == NULL) { ++ printf("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n", ++ elems_max, elem_size); ++ ASSERT(0); ++ return dll_pool_p; ++ } ++ ++ dll_init(&dll_pool_p->free_list); ++ dll_pool_p->elems_max = elems_max; ++ dll_pool_p->elem_size = elem_size; ++ ++ elem_p = dll_pool_p->elements; ++ for (i = 0; i < elems_max; i++) { ++ dll_append(&dll_pool_p->free_list, elem_p); ++ elem_p = (dll_t *)((uintptr)elem_p + elem_size); ++ } ++ ++ dll_pool_p->free_count = elems_max; ++ ++ return dll_pool_p; ++} ++ ++ ++void * ++dll_pool_alloc(dll_pool_t * dll_pool_p) ++{ ++ dll_t * elem_p; ++ ++ if (dll_pool_p->free_count == 0) { ++ ASSERT(dll_empty(&dll_pool_p->free_list)); ++ return NULL; ++ } ++ ++ elem_p = dll_head_p(&dll_pool_p->free_list); ++ dll_delete(elem_p); ++ dll_pool_p->free_count -= 1; ++ ++ return (void *)elem_p; ++} ++ ++void ++dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p) ++{ ++ dll_t * node_p = (dll_t *)elem_p; ++ dll_prepend(&dll_pool_p->free_list, node_p); ++ dll_pool_p->free_count += 1; ++} ++ ++ ++void ++dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p) ++{ ++ dll_t * node_p = (dll_t *)elem_p; ++ dll_append(&dll_pool_p->free_list, node_p); ++ dll_pool_p->free_count += 1; ++} ++ ++#endif ++ ++/* calculate partial checksum */ ++static uint32 ++ip_cksum_partial(uint32 sum, uint8 *val8, uint32 count) ++{ ++ uint32 i; ++ uint16 *val16 = (uint16 *)val8; ++ ++ ASSERT(val8 != NULL); ++ /* partial chksum calculated on 16-bit values */ ++ ASSERT((count % 2) == 0); ++ ++ count /= 2; ++ ++ for (i = 0; i < count; i++) { ++ sum += *val16++; ++ } ++ return sum; ++} ++ ++/* calculate IP checksum */ ++static uint16 ++ip_cksum(uint32 sum, uint8 *val8, uint32 count) ++{ ++ uint16 *val16 = (uint16 *)val8; ++ ++ ASSERT(val8 != NULL); ++ ++ while (count > 1) { ++ sum += *val16++; ++ count -= 2; ++ } ++ /* add left-over byte, if any */ ++ if (count > 0) { ++ sum += (*(uint8 *)val16); ++ } ++ ++ /* fold 32-bit sum to 16 bits */ ++ sum = (sum >> 16) + (sum & 0xffff); ++ sum += (sum >> 16); ++ return ((uint16)~sum); ++} ++ ++/* calculate IPv4 header checksum ++ * - input ip points to IP header in network order ++ * - output cksum is in network order ++ */ ++uint16 ++ipv4_hdr_cksum(uint8 *ip, int ip_len) ++{ ++ uint32 sum = 0; ++ uint8 *ptr = ip; ++ ++ ASSERT(ip != NULL); ++ ASSERT(ip_len >= IPV4_MIN_HEADER_LEN); ++ ++ /* partial cksum skipping the hdr_chksum field */ ++ sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct ipv4_hdr, hdr_chksum)); ++ ptr += OFFSETOF(struct ipv4_hdr, hdr_chksum) + 2; ++ ++ /* return calculated chksum */ ++ return ip_cksum(sum, ptr, ip_len - OFFSETOF(struct ipv4_hdr, src_ip)); ++} ++ ++/* calculate TCP header checksum using partial sum */ ++static uint16 ++tcp_hdr_chksum(uint32 sum, uint8 *tcp_hdr, uint16 tcp_len) ++{ ++ uint8 *ptr = tcp_hdr; ++ ++ ASSERT(tcp_hdr != NULL); ++ ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); ++ ++ /* partial TCP cksum skipping the chksum field */ ++ sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct bcmtcp_hdr, chksum)); ++ ptr += OFFSETOF(struct bcmtcp_hdr, chksum) + 2; ++ ++ /* return calculated chksum */ ++ return ip_cksum(sum, ptr, tcp_len - OFFSETOF(struct bcmtcp_hdr, urg_ptr)); ++} ++ ++struct tcp_pseudo_hdr { ++ uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ ++ uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ ++ uint8 zero; ++ uint8 prot; ++ uint16 tcp_size; ++}; ++ ++/* calculate IPv4 TCP header checksum ++ * - input ip and tcp points to IP and TCP header in network order ++ * - output cksum is in network order ++ */ ++uint16 ++ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len) ++{ ++ struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)ip; ++ struct tcp_pseudo_hdr tcp_ps; ++ uint32 sum = 0; ++ ++ ASSERT(ip != NULL); ++ ASSERT(tcp != NULL); ++ ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); ++ ++ /* pseudo header cksum */ ++ memset(&tcp_ps, 0, sizeof(tcp_ps)); ++ memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN); ++ memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN); ++ tcp_ps.zero = 0; ++ tcp_ps.prot = ip_hdr->prot; ++ tcp_ps.tcp_size = hton16(tcp_len); ++ sum = ip_cksum_partial(sum, (uint8 *)&tcp_ps, sizeof(tcp_ps)); ++ ++ /* return calculated TCP header chksum */ ++ return tcp_hdr_chksum(sum, tcp, tcp_len); ++} ++ ++struct ipv6_pseudo_hdr { ++ uint8 saddr[IPV6_ADDR_LEN]; ++ uint8 daddr[IPV6_ADDR_LEN]; ++ uint16 payload_len; ++ uint8 zero; ++ uint8 next_hdr; ++}; ++ ++/* calculate IPv6 TCP header checksum ++ * - input ipv6 and tcp points to IPv6 and TCP header in network order ++ * - output cksum is in network order ++ */ ++uint16 ++ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len) ++{ ++ struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)ipv6; ++ struct ipv6_pseudo_hdr ipv6_pseudo; ++ uint32 sum = 0; ++ ++ ASSERT(ipv6 != NULL); ++ ASSERT(tcp != NULL); ++ ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); ++ ++ /* pseudo header cksum */ ++ memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo)); ++ memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr, ++ sizeof(ipv6_pseudo.saddr)); ++ memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr, ++ sizeof(ipv6_pseudo.daddr)); ++ ipv6_pseudo.payload_len = ipv6_hdr->payload_len; ++ ipv6_pseudo.next_hdr = ipv6_hdr->nexthdr; ++ sum = ip_cksum_partial(sum, (uint8 *)&ipv6_pseudo, sizeof(ipv6_pseudo)); ++ ++ /* return calculated TCP header chksum */ ++ return tcp_hdr_chksum(sum, tcp, tcp_len); ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_channels.c b/module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_channels.c +new file mode 100644 +index 000000000..40fc3f757 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_channels.c +@@ -0,0 +1,1349 @@ ++/* ++ * Misc utility routines used by kernel or app-level. ++ * Contents are wifi-specific, used by any kernel or app-level ++ * software that might want wifi things as it grows. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmwifi_channels.c 612483 2016-01-14 03:44:27Z $ ++ */ ++ ++#include ++#include ++#include ++ ++#ifdef BCMDRIVER ++#include ++#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) ++#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) ++#else ++#include ++#include ++#include ++#ifndef ASSERT ++#define ASSERT(exp) ++#endif ++#endif /* BCMDRIVER */ ++ ++#include ++ ++#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) ++#include /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ ++#endif ++ ++/* Definitions for D11AC capable Chanspec type */ ++ ++/* Chanspec ASCII representation with 802.11ac capability: ++ * [ 'g'] ['/' []['/'<1st80channel>'-'<2nd80channel>]] ++ * ++ * : ++ * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. ++ * Default value is 2g if channel <= 14, otherwise 5g. ++ * : ++ * channel number of the 5MHz, 10MHz, 20MHz channel, ++ * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel. ++ * : ++ * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20. ++ * : ++ * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower. ++ * ++ * For 2.4GHz band 40MHz channels, the same primary channel may be the ++ * upper sideband for one 40MHz channel, and the lower sideband for an ++ * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel ++ * is being specified. ++ * ++ * For 40MHz in the 5GHz band and all channel bandwidths greater than ++ * 40MHz, the U/L specificaion is not allowed since the channels are ++ * non-overlapping and the primary sub-band is derived from its ++ * position in the wide bandwidth channel. ++ * ++ * <1st80Channel>: ++ * <2nd80Channel>: ++ * Required for 80+80, otherwise not allowed. ++ * Specifies the center channel of the first and second 80MHz band. ++ * ++ * In its simplest form, it is a 20MHz channel number, with the implied band ++ * of 2.4GHz if channel number <= 14, and 5GHz otherwise. ++ * ++ * To allow for backward compatibility with scripts, the old form for ++ * 40MHz channels is also allowed: ++ * ++ * : ++ * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz ++ * : ++ * "U" for upper, "L" for lower (or lower case "u" "l") ++ * ++ * 5 GHz Examples: ++ * Chanspec BW Center Ch Channel Range Primary Ch ++ * 5g8 20MHz 8 - - ++ * 52 20MHz 52 - - ++ * 52/40 40MHz 54 52-56 52 ++ * 56/40 40MHz 54 52-56 56 ++ * 52/80 80MHz 58 52-64 52 ++ * 56/80 80MHz 58 52-64 56 ++ * 60/80 80MHz 58 52-64 60 ++ * 64/80 80MHz 58 52-64 64 ++ * 52/160 160MHz 50 36-64 52 ++ * 36/160 160MGz 50 36-64 36 ++ * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36 ++ * ++ * 2 GHz Examples: ++ * Chanspec BW Center Ch Channel Range Primary Ch ++ * 2g8 20MHz 8 - - ++ * 8 20MHz 8 - - ++ * 6 20MHz 6 - - ++ * 6/40l 40MHz 8 6-10 6 ++ * 6l 40MHz 8 6-10 6 ++ * 6/40u 40MHz 4 2-6 6 ++ * 6u 40MHz 4 2-6 6 ++ */ ++ ++/* bandwidth ASCII string */ ++static const char *wf_chspec_bw_str[] = ++{ ++ "5", ++ "10", ++ "20", ++ "40", ++ "80", ++ "160", ++ "80+80", ++#ifdef WL11ULB ++ "2.5" ++#else /* WL11ULB */ ++ "na" ++#endif /* WL11ULB */ ++}; ++ ++static const uint8 wf_chspec_bw_mhz[] = ++{5, 10, 20, 40, 80, 160, 160}; ++ ++#define WF_NUM_BW \ ++ (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) ++ ++/* 40MHz channels in 5GHz band */ ++static const uint8 wf_5g_40m_chans[] = ++{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; ++#define WF_NUM_5G_40M_CHANS \ ++ (sizeof(wf_5g_40m_chans)/sizeof(uint8)) ++ ++/* 80MHz channels in 5GHz band */ ++static const uint8 wf_5g_80m_chans[] = ++{42, 58, 106, 122, 138, 155}; ++#define WF_NUM_5G_80M_CHANS \ ++ (sizeof(wf_5g_80m_chans)/sizeof(uint8)) ++ ++/* 160MHz channels in 5GHz band */ ++static const uint8 wf_5g_160m_chans[] = ++{50, 114}; ++#define WF_NUM_5G_160M_CHANS \ ++ (sizeof(wf_5g_160m_chans)/sizeof(uint8)) ++ ++/* opclass and channel information for US. Table E-1 */ ++static const uint16 opclass_data[] = { ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), ++ 0, ++ 0, ++ 0, ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), ++ (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), ++ (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), ++ (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), ++}; ++ ++/* convert bandwidth from chanspec to MHz */ ++static uint ++bw_chspec_to_mhz(chanspec_t chspec) ++{ ++ uint bw; ++ ++ bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; ++ return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); ++} ++ ++/* bw in MHz, return the channel count from the center channel to the ++ * the channel at the edge of the band ++ */ ++static uint8 ++center_chan_to_edge(uint bw) ++{ ++ /* edge channels separated by BW - 10MHz on each side ++ * delta from cf to edge is half of that, ++ * MHz to channel num conversion is 5MHz/channel ++ */ ++ return (uint8)(((bw - 20) / 2) / 5); ++} ++ ++/* return channel number of the low edge of the band ++ * given the center channel and BW ++ */ ++static uint8 ++channel_low_edge(uint center_ch, uint bw) ++{ ++ return (uint8)(center_ch - center_chan_to_edge(bw)); ++} ++ ++/* return side band number given center channel and control channel ++ * return -1 on error ++ */ ++static int ++channel_to_sb(uint center_ch, uint ctl_ch, uint bw) ++{ ++ uint lowest = channel_low_edge(center_ch, bw); ++ uint sb; ++ ++ if ((ctl_ch - lowest) % 4) { ++ /* bad ctl channel, not mult 4 */ ++ return -1; ++ } ++ ++ sb = ((ctl_ch - lowest) / 4); ++ ++ /* sb must be a index to a 20MHz channel in range */ ++ if (sb >= (bw / 20)) { ++ /* ctl_ch must have been too high for the center_ch */ ++ return -1; ++ } ++ ++ return sb; ++} ++ ++/* return control channel given center channel and side band */ ++static uint8 ++channel_to_ctl_chan(uint center_ch, uint bw, uint sb) ++{ ++ return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); ++} ++ ++/* return index of 80MHz channel from channel number ++ * return -1 on error ++ */ ++static int ++channel_80mhz_to_id(uint ch) ++{ ++ uint i; ++ for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { ++ if (ch == wf_5g_80m_chans[i]) ++ return i; ++ } ++ ++ return -1; ++} ++ ++/* wrapper function for wf_chspec_ntoa. In case of an error it puts ++ * the original chanspec in the output buffer, prepended with "invalid". ++ * Can be directly used in print routines as it takes care of null ++ */ ++char * ++wf_chspec_ntoa_ex(chanspec_t chspec, char *buf) ++{ ++ if (wf_chspec_ntoa(chspec, buf) == NULL) ++ snprintf(buf, CHANSPEC_STR_LEN, "invalid 0x%04x", chspec); ++ return buf; ++} ++ ++/* given a chanspec and a string buffer, format the chanspec as a ++ * string, and return the original pointer a. ++ * Min buffer length must be CHANSPEC_STR_LEN. ++ * On error return NULL ++ */ ++char * ++wf_chspec_ntoa(chanspec_t chspec, char *buf) ++{ ++ const char *band; ++ uint ctl_chan; ++ ++ if (wf_chspec_malformed(chspec)) ++ return NULL; ++ ++ band = ""; ++ ++ /* check for non-default band spec */ ++ if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || ++ (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) ++ band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; ++ ++ /* ctl channel */ ++ ctl_chan = wf_chspec_ctlchan(chspec); ++ ++ /* bandwidth and ctl sideband */ ++ if (CHSPEC_IS20(chspec)) { ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); ++ } else if (!CHSPEC_IS8080(chspec)) { ++ const char *bw; ++ const char *sb = ""; ++ ++ bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; ++ ++#ifdef CHANSPEC_NEW_40MHZ_FORMAT ++ /* ctl sideband string if needed for 2g 40MHz */ ++ if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { ++ sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; ++ } ++ ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); ++#else ++ /* ctl sideband string instead of BW for 40MHz */ ++ if (CHSPEC_IS40(chspec)) { ++ sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); ++ } else { ++ snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); ++ } ++#endif /* CHANSPEC_NEW_40MHZ_FORMAT */ ++ ++ } else { ++ /* 80+80 */ ++ uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; ++ uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; ++ ++ /* convert to channel number */ ++ chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; ++ chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; ++ ++ /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ ++ snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); ++ } ++ ++ return (buf); ++} ++ ++static int ++read_uint(const char **p, unsigned int *num) ++{ ++ unsigned long val; ++ char *endp = NULL; ++ ++ val = strtoul(*p, &endp, 10); ++ /* if endp is the initial pointer value, then a number was not read */ ++ if (endp == *p) ++ return 0; ++ ++ /* advance the buffer pointer to the end of the integer string */ ++ *p = endp; ++ /* return the parsed integer */ ++ *num = (unsigned int)val; ++ ++ return 1; ++} ++ ++/* given a chanspec string, convert to a chanspec. ++ * On error return 0 ++ */ ++chanspec_t ++wf_chspec_aton(const char *a) ++{ ++ chanspec_t chspec; ++ uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; ++ uint num, ctl_ch; ++ uint ch1, ch2; ++ char c, sb_ul = '\0'; ++ int i; ++ ++ bw = 20; ++ chspec_sb = 0; ++ chspec_ch = ch1 = ch2 = 0; ++ ++ /* parse channel num or band */ ++ if (!read_uint(&a, &num)) ++ return 0; ++ /* if we are looking at a 'g', then the first number was a band */ ++ c = tolower((int)a[0]); ++ if (c == 'g') { ++ a++; /* consume the char */ ++ ++ /* band must be "2" or "5" */ ++ if (num == 2) ++ chspec_band = WL_CHANSPEC_BAND_2G; ++ else if (num == 5) ++ chspec_band = WL_CHANSPEC_BAND_5G; ++ else ++ return 0; ++ ++ /* read the channel number */ ++ if (!read_uint(&a, &ctl_ch)) ++ return 0; ++ ++ c = tolower((int)a[0]); ++ } ++ else { ++ /* first number is channel, use default for band */ ++ ctl_ch = num; ++ chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); ++ } ++ ++ if (c == '\0') { ++ /* default BW of 20MHz */ ++ chspec_bw = WL_CHANSPEC_BW_20; ++ goto done_read; ++ } ++ ++ a ++; /* consume the 'u','l', or '/' */ ++ ++ /* check 'u'/'l' */ ++ if (c == 'u' || c == 'l') { ++ sb_ul = c; ++ chspec_bw = WL_CHANSPEC_BW_40; ++ goto done_read; ++ } ++ ++ /* next letter must be '/' */ ++ if (c != '/') ++ return 0; ++ ++ /* read bandwidth */ ++ if (!read_uint(&a, &bw)) ++ return 0; ++ ++ /* convert to chspec value */ ++ if (bw == 2) { ++ chspec_bw = WL_CHANSPEC_BW_2P5; ++ } else if (bw == 5) { ++ chspec_bw = WL_CHANSPEC_BW_5; ++ } else if (bw == 10) { ++ chspec_bw = WL_CHANSPEC_BW_10; ++ } else if (bw == 20) { ++ chspec_bw = WL_CHANSPEC_BW_20; ++ } else if (bw == 40) { ++ chspec_bw = WL_CHANSPEC_BW_40; ++ } else if (bw == 80) { ++ chspec_bw = WL_CHANSPEC_BW_80; ++ } else if (bw == 160) { ++ chspec_bw = WL_CHANSPEC_BW_160; ++ } else { ++ return 0; ++ } ++ ++ /* So far we have g/ ++ * Can now be followed by u/l if bw = 40, ++ * or '+80' if bw = 80, to make '80+80' bw, ++ * or '.5' if bw = 2.5 to make '2.5' bw . ++ */ ++ ++ c = tolower((int)a[0]); ++ ++ /* if we have a 2g/40 channel, we should have a l/u spec now */ ++ if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { ++ if (c == 'u' || c == 'l') { ++ a ++; /* consume the u/l char */ ++ sb_ul = c; ++ goto done_read; ++ } ++ } ++ ++ /* check for 80+80 */ ++ if (c == '+') { ++ /* 80+80 */ ++ const char plus80[] = "80/"; ++ ++ /* must be looking at '+80/' ++ * check and consume this string. ++ */ ++ chspec_bw = WL_CHANSPEC_BW_8080; ++ ++ a ++; /* consume the char '+' */ ++ ++ /* consume the '80/' string */ ++ for (i = 0; i < 3; i++) { ++ if (*a++ != plus80[i]) { ++ return 0; ++ } ++ } ++ ++ /* read primary 80MHz channel */ ++ if (!read_uint(&a, &ch1)) ++ return 0; ++ ++ /* must followed by '-' */ ++ if (a[0] != '-') ++ return 0; ++ a ++; /* consume the char */ ++ ++ /* read secondary 80MHz channel */ ++ if (!read_uint(&a, &ch2)) ++ return 0; ++ } else if (c == '.') { ++ /* 2.5 */ ++ /* must be looking at '.5' ++ * check and consume this string. ++ */ ++ chspec_bw = WL_CHANSPEC_BW_2P5; ++ ++ a ++; /* consume the char '.' */ ++ ++ /* consume the '5' string */ ++ if (*a++ != '5') { ++ return 0; ++ } ++ } ++ ++done_read: ++ /* skip trailing white space */ ++ while (a[0] == ' ') { ++ a ++; ++ } ++ ++ /* must be end of string */ ++ if (a[0] != '\0') ++ return 0; ++ ++ /* Now have all the chanspec string parts read; ++ * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. ++ * chspec_band and chspec_bw are chanspec values. ++ * Need to convert ctl_ch, sb_ul, and ch1,ch2 into ++ * a center channel (or two) and sideband. ++ */ ++ ++ /* if a sb u/l string was given, just use that, ++ * guaranteed to be bw = 40 by sting parse. ++ */ ++ if (sb_ul != '\0') { ++ if (sb_ul == 'l') { ++ chspec_ch = UPPER_20_SB(ctl_ch); ++ chspec_sb = WL_CHANSPEC_CTL_SB_LLL; ++ } else if (sb_ul == 'u') { ++ chspec_ch = LOWER_20_SB(ctl_ch); ++ chspec_sb = WL_CHANSPEC_CTL_SB_LLU; ++ } ++ } ++ /* if the bw is 20, center and sideband are trivial */ ++ else if (BW_LE20(chspec_bw)) { ++ chspec_ch = ctl_ch; ++ chspec_sb = WL_CHANSPEC_CTL_SB_NONE; ++ } ++ /* if the bw is 40/80/160, not 80+80, a single method ++ * can be used to to find the center and sideband ++ */ ++ else if (chspec_bw != WL_CHANSPEC_BW_8080) { ++ /* figure out ctl sideband based on ctl channel and bandwidth */ ++ const uint8 *center_ch = NULL; ++ int num_ch = 0; ++ int sb = -1; ++ ++ if (chspec_bw == WL_CHANSPEC_BW_40) { ++ center_ch = wf_5g_40m_chans; ++ num_ch = WF_NUM_5G_40M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_80) { ++ center_ch = wf_5g_80m_chans; ++ num_ch = WF_NUM_5G_80M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_160) { ++ center_ch = wf_5g_160m_chans; ++ num_ch = WF_NUM_5G_160M_CHANS; ++ } else { ++ return 0; ++ } ++ ++ for (i = 0; i < num_ch; i ++) { ++ sb = channel_to_sb(center_ch[i], ctl_ch, bw); ++ if (sb >= 0) { ++ chspec_ch = center_ch[i]; ++ chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; ++ break; ++ } ++ } ++ ++ /* check for no matching sb/center */ ++ if (sb < 0) { ++ return 0; ++ } ++ } ++ /* Otherwise, bw is 80+80. Figure out channel pair and sb */ ++ else { ++ int ch1_id = 0, ch2_id = 0; ++ int sb; ++ ++ /* look up the channel ID for the specified channel numbers */ ++ ch1_id = channel_80mhz_to_id(ch1); ++ ch2_id = channel_80mhz_to_id(ch2); ++ ++ /* validate channels */ ++ if (ch1_id < 0 || ch2_id < 0) ++ return 0; ++ ++ /* combine 2 channel IDs in channel field of chspec */ ++ chspec_ch = (((uint)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | ++ ((uint)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); ++ ++ /* figure out primary 20 MHz sideband */ ++ ++ /* is the primary channel contained in the 1st 80MHz channel? */ ++ sb = channel_to_sb(ch1, ctl_ch, bw); ++ if (sb < 0) { ++ /* no match for primary channel 'ctl_ch' in segment0 80MHz channel */ ++ return 0; ++ } ++ ++ chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; ++ } ++ ++ chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); ++ ++ if (wf_chspec_malformed(chspec)) ++ return 0; ++ ++ return chspec; ++} ++ ++/* ++ * 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 ++wf_chspec_malformed(chanspec_t chanspec) ++{ ++ uint chspec_bw = CHSPEC_BW(chanspec); ++ uint chspec_ch = CHSPEC_CHANNEL(chanspec); ++ ++ /* must be 2G or 5G band */ ++ if (CHSPEC_IS2G(chanspec)) { ++ /* must be valid bandwidth */ ++ if (!BW_LE40(chspec_bw)) { ++ return TRUE; ++ } ++ } else if (CHSPEC_IS5G(chanspec)) { ++ if (chspec_bw == WL_CHANSPEC_BW_8080) { ++ uint ch1_id, ch2_id; ++ ++ /* channel IDs in 80+80 must be in range */ ++ ch1_id = CHSPEC_CHAN1(chanspec); ++ ch2_id = CHSPEC_CHAN2(chanspec); ++ if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) ++ return TRUE; ++ ++ } else if (BW_LE160(chspec_bw)) { ++ if (chspec_ch > MAXCHANNEL) { ++ return TRUE; ++ } ++ } else { ++ /* invalid bandwidth */ ++ return TRUE; ++ } ++ } else { ++ /* must be 2G or 5G band */ ++ return TRUE; ++ } ++ ++ /* side band needs to be consistent with bandwidth */ ++ if (BW_LE20(chspec_bw)) { ++ if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_40) { ++ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_80 || ++ chspec_bw == WL_CHANSPEC_BW_8080) { ++ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) ++ return TRUE; ++ } ++ else if (chspec_bw == WL_CHANSPEC_BW_160) { ++ ASSERT(CHSPEC_CTL_SB(chanspec) <= WL_CHANSPEC_CTL_SB_UUU); ++ } ++ return FALSE; ++} ++ ++/* ++ * Verify the chanspec specifies a valid channel according to 802.11. ++ * RETURNS: TRUE if the chanspec is a valid 802.11 channel ++ */ ++bool ++wf_chspec_valid(chanspec_t chanspec) ++{ ++ uint chspec_bw = CHSPEC_BW(chanspec); ++ uint chspec_ch = CHSPEC_CHANNEL(chanspec); ++ ++ if (wf_chspec_malformed(chanspec)) ++ return FALSE; ++ ++ if (CHSPEC_IS2G(chanspec)) { ++ /* must be valid bandwidth and channel range */ ++ if (BW_LE20(chspec_bw)) { ++ if (chspec_ch >= 1 && chspec_ch <= 14) ++ return TRUE; ++ } else if (chspec_bw == WL_CHANSPEC_BW_40) { ++ if (chspec_ch >= 3 && chspec_ch <= 11) ++ return TRUE; ++ } ++ } else if (CHSPEC_IS5G(chanspec)) { ++ if (chspec_bw == WL_CHANSPEC_BW_8080) { ++ uint16 ch1, ch2; ++ ++ ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; ++ ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; ++ ++ /* the two channels must be separated by more than 80MHz by VHT req */ ++ if ((ch2 > ch1 + CH_80MHZ_APART) || ++ (ch1 > ch2 + CH_80MHZ_APART)) ++ return TRUE; ++ } else { ++ const uint8 *center_ch; ++ uint num_ch, i; ++ ++ if (BW_LE40(chspec_bw)) { ++ center_ch = wf_5g_40m_chans; ++ num_ch = WF_NUM_5G_40M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_80) { ++ center_ch = wf_5g_80m_chans; ++ num_ch = WF_NUM_5G_80M_CHANS; ++ } else if (chspec_bw == WL_CHANSPEC_BW_160) { ++ center_ch = wf_5g_160m_chans; ++ num_ch = WF_NUM_5G_160M_CHANS; ++ } else { ++ /* invalid bandwidth */ ++ return FALSE; ++ } ++ ++ /* check for a valid center channel */ ++ if (BW_LE20(chspec_bw)) { ++ /* We don't have an array of legal 20MHz 5G channels, but they are ++ * each side of the legal 40MHz channels. Check the chanspec ++ * channel against either side of the 40MHz channels. ++ */ ++ for (i = 0; i < num_ch; i ++) { ++ if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || ++ chspec_ch == (uint)UPPER_20_SB(center_ch[i])) ++ break; /* match found */ ++ } ++ ++ if (i == num_ch) { ++ /* check for channel 165 which is not the side band ++ * of 40MHz 5G channel ++ */ ++ if (chspec_ch == 165) ++ i = 0; ++ ++ /* check for legacy JP channels on failure */ ++ if (chspec_ch == 34 || chspec_ch == 38 || ++ chspec_ch == 42 || chspec_ch == 46) ++ i = 0; ++ } ++ } else { ++ /* check the chanspec channel to each legal channel */ ++ for (i = 0; i < num_ch; i ++) { ++ if (chspec_ch == center_ch[i]) ++ break; /* match found */ ++ } ++ } ++ ++ if (i < num_ch) { ++ /* match found */ ++ return TRUE; ++ } ++ } ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * This function returns the channel number that control traffic is being sent on, for 20MHz ++ * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ ++ * sideband depending on the chanspec selected ++ */ ++uint8 ++wf_chspec_ctlchan(chanspec_t chspec) ++{ ++ uint center_chan; ++ uint bw_mhz; ++ uint sb; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ /* Is there a sideband ? */ ++ if (CHSPEC_BW_LE20(chspec)) { ++ return CHSPEC_CHANNEL(chspec); ++ } else { ++ sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; ++ ++ if (CHSPEC_IS8080(chspec)) { ++ /* For an 80+80 MHz channel, the sideband 'sb' field is an 80 MHz sideband ++ * (LL, LU, UL, LU) for the 80 MHz frequency segment 0. ++ */ ++ uint chan_id = CHSPEC_CHAN1(chspec); ++ ++ bw_mhz = 80; ++ ++ /* convert from channel index to channel number */ ++ center_chan = wf_5g_80m_chans[chan_id]; ++ } ++ else { ++ bw_mhz = bw_chspec_to_mhz(chspec); ++ center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; ++ } ++ ++ return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); ++ } ++} ++ ++/* given a chanspec, return the bandwidth string */ ++const char * ++wf_chspec_to_bw_str(chanspec_t chspec) ++{ ++ return wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)]; ++} ++ ++/* ++ * This function returns the chanspec of the control channel of a given chanspec ++ */ ++chanspec_t ++wf_chspec_ctlchspec(chanspec_t chspec) ++{ ++ chanspec_t ctl_chspec = chspec; ++ uint8 ctl_chan; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ /* Is there a sideband ? */ ++ if (!CHSPEC_BW_LE20(chspec)) { ++ ctl_chan = wf_chspec_ctlchan(chspec); ++ ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; ++ ctl_chspec |= CHSPEC_BAND(chspec); ++ } ++ return ctl_chspec; ++} ++ ++/* return chanspec given control channel and bandwidth ++ * return 0 on error ++ */ ++uint16 ++wf_channel2chspec(uint ctl_ch, uint bw) ++{ ++ uint16 chspec; ++ const uint8 *center_ch = NULL; ++ int num_ch = 0; ++ int sb = -1; ++ int i = 0; ++ ++ chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); ++ ++ chspec |= bw; ++ ++ if (bw == WL_CHANSPEC_BW_40) { ++ center_ch = wf_5g_40m_chans; ++ num_ch = WF_NUM_5G_40M_CHANS; ++ bw = 40; ++ } else if (bw == WL_CHANSPEC_BW_80) { ++ center_ch = wf_5g_80m_chans; ++ num_ch = WF_NUM_5G_80M_CHANS; ++ bw = 80; ++ } else if (bw == WL_CHANSPEC_BW_160) { ++ center_ch = wf_5g_160m_chans; ++ num_ch = WF_NUM_5G_160M_CHANS; ++ bw = 160; ++ } else if (BW_LE20(bw)) { ++ chspec |= ctl_ch; ++ return chspec; ++ } else { ++ return 0; ++ } ++ ++ for (i = 0; i < num_ch; i ++) { ++ sb = channel_to_sb(center_ch[i], ctl_ch, bw); ++ if (sb >= 0) { ++ chspec |= center_ch[i]; ++ chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); ++ break; ++ } ++ } ++ ++ /* check for no matching sb/center */ ++ if (sb < 0) { ++ return 0; ++ } ++ ++ return chspec; ++} ++ ++/* ++ * This function returns the chanspec for the primary 40MHz of an 80MHz channel. ++ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using ++ * as the primary 20MHz channel. ++ */ ++extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) ++{ ++ chanspec_t chspec40 = chspec; ++ uint center_chan; ++ uint sb; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ ++ /* if the chanspec is > 80MHz, use the helper routine to find the primary 80 MHz channel */ ++ if (CHSPEC_IS8080(chspec) || CHSPEC_IS160(chspec)) { ++ chspec = wf_chspec_primary80_chspec(chspec); ++ } ++ ++ /* determine primary 40 MHz sub-channel of an 80 MHz chanspec */ ++ if (CHSPEC_IS80(chspec)) { ++ center_chan = CHSPEC_CHANNEL(chspec); ++ sb = CHSPEC_CTL_SB(chspec); ++ ++ if (sb < WL_CHANSPEC_CTL_SB_UL) { ++ /* Primary 40MHz is on lower side */ ++ center_chan -= CH_20MHZ_APART; ++ /* sideband bits are the same for LL/LU and L/U */ ++ } else { ++ /* Primary 40MHz is on upper side */ ++ center_chan += CH_20MHZ_APART; ++ /* sideband bits need to be adjusted by UL offset */ ++ sb -= WL_CHANSPEC_CTL_SB_UL; ++ } ++ ++ /* Create primary 40MHz chanspec */ ++ chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | ++ sb | center_chan); ++ } ++ ++ return chspec40; ++} ++ ++/* ++ * 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 ++wf_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; ++} ++ ++/* ++ * Return the center frequency in MHz of the given channel and base frequency. ++ * The channel number is interpreted relative to the given base frequency. ++ * ++ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. ++ * The base frequency is specified as (start_factor * 500 kHz). ++ * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G ++ * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands. ++ * The channel range of [1, 14] is only checked for a start_factor of ++ * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2). ++ * Odd start_factors produce channels on .5 MHz boundaries, in which case ++ * the answer is rounded down to an integral MHz. ++ * -1 is returned for an out of range channel. ++ * ++ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 ++ */ ++int ++wf_channel2mhz(uint ch, uint start_factor) ++{ ++ int freq; ++ ++ if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || ++ (ch > 200)) ++ freq = -1; ++ else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) ++ freq = 2484; ++ else ++ freq = ch * 5 + start_factor / 2; ++ ++ return freq; ++} ++ ++static const uint16 sidebands[] = { ++ WL_CHANSPEC_CTL_SB_LLL, WL_CHANSPEC_CTL_SB_LLU, ++ WL_CHANSPEC_CTL_SB_LUL, WL_CHANSPEC_CTL_SB_LUU, ++ WL_CHANSPEC_CTL_SB_ULL, WL_CHANSPEC_CTL_SB_ULU, ++ WL_CHANSPEC_CTL_SB_UUL, WL_CHANSPEC_CTL_SB_UUU ++}; ++ ++/* ++ * Returns the chanspec 80Mhz channel corresponding to the following input ++ * parameters ++ * ++ * primary_channel - primary 20Mhz channel ++ * center_channel - center frequecny of the 80Mhz channel ++ * ++ * The center_channel can be one of {42, 58, 106, 122, 138, 155} ++ * ++ * returns INVCHANSPEC in case of error ++ */ ++chanspec_t ++wf_chspec_80(uint8 center_channel, uint8 primary_channel) ++{ ++ ++ chanspec_t chanspec = INVCHANSPEC; ++ chanspec_t chanspec_cur; ++ uint i; ++ ++ for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) { ++ chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]); ++ if (primary_channel == wf_chspec_ctlchan(chanspec_cur)) { ++ chanspec = chanspec_cur; ++ break; ++ } ++ } ++ /* If the loop ended early, we are good, otherwise we did not ++ * find a 80MHz chanspec with the given center_channel that had a primary channel ++ *matching the given primary_channel. ++ */ ++ return chanspec; ++} ++ ++/* ++ * Returns the 80+80 chanspec corresponding to the following input parameters ++ * ++ * primary_20mhz - Primary 20 MHz channel ++ * chan0 - center channel number of one frequency segment ++ * chan1 - center channel number of the other frequency segment ++ * ++ * Parameters chan0 and chan1 are channel numbers in {42, 58, 106, 122, 138, 155}. ++ * The primary channel must be contained in one of the 80MHz channels. This routine ++ * will determine which frequency segment is the primary 80 MHz segment. ++ * ++ * Returns INVCHANSPEC in case of error. ++ * ++ * Refer to IEEE802.11ac section 22.3.14 "Channelization". ++ */ ++chanspec_t ++wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan0, uint8 chan1) ++{ ++ int sb = 0; ++ uint16 chanspec = 0; ++ int chan0_id = 0, chan1_id = 0; ++ int seg0, seg1; ++ ++ chan0_id = channel_80mhz_to_id(chan0); ++ chan1_id = channel_80mhz_to_id(chan1); ++ ++ /* make sure the channel numbers were valid */ ++ if (chan0_id == -1 || chan1_id == -1) ++ return INVCHANSPEC; ++ ++ /* does the primary channel fit with the 1st 80MHz channel ? */ ++ sb = channel_to_sb(chan0, primary_20mhz, 80); ++ if (sb >= 0) { ++ /* yes, so chan0 is frequency segment 0, and chan1 is seg 1 */ ++ seg0 = chan0_id; ++ seg1 = chan1_id; ++ } else { ++ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ ++ sb = channel_to_sb(chan1, primary_20mhz, 80); ++ if (sb < 0) { ++ /* no match for ctl_ch to either 80MHz center channel */ ++ return INVCHANSPEC; ++ } ++ /* swapped, so chan1 is frequency segment 0, and chan0 is seg 1 */ ++ seg0 = chan1_id; ++ seg1 = chan0_id; ++ } ++ ++ chanspec = ((seg0 << WL_CHANSPEC_CHAN1_SHIFT) | ++ (seg1 << WL_CHANSPEC_CHAN2_SHIFT) | ++ (sb << WL_CHANSPEC_CTL_SB_SHIFT) | ++ WL_CHANSPEC_BW_8080 | ++ WL_CHANSPEC_BAND_5G); ++ ++ return chanspec; ++} ++ ++/* ++ * This function returns the 80Mhz channel for the given id. ++ */ ++static uint8 ++wf_chspec_get80Mhz_ch(uint8 chan_80Mhz_id) ++{ ++ if (chan_80Mhz_id < WF_NUM_5G_80M_CHANS) ++ return wf_5g_80m_chans[chan_80Mhz_id]; ++ ++ return 0; ++} ++ ++/* ++ * Returns the primary 80 Mhz channel for the provided chanspec ++ * ++ * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved ++ * ++ * returns -1 in case the provided channel is 20/40 Mhz chanspec ++ */ ++ ++uint8 ++wf_chspec_primary80_channel(chanspec_t chanspec) ++{ ++ uint8 primary80_chan; ++ ++ if (CHSPEC_IS80(chanspec)) { ++ primary80_chan = CHSPEC_CHANNEL(chanspec); ++ } ++ else if (CHSPEC_IS8080(chanspec)) { ++ /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */ ++ primary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); ++ } ++ else if (CHSPEC_IS160(chanspec)) { ++ uint8 center_chan = CHSPEC_CHANNEL(chanspec); ++ uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT; ++ ++ /* based on the sb value primary 80 channel can be retrieved ++ * if sb is in range 0 to 3 the lower band is the 80Mhz primary band ++ */ ++ if (sb < 4) { ++ primary80_chan = center_chan - CH_40MHZ_APART; ++ } ++ /* if sb is in range 4 to 7 the upper band is the 80Mhz primary band */ ++ else ++ { ++ primary80_chan = center_chan + CH_40MHZ_APART; ++ } ++ } ++ else { ++ /* for 20 and 40 Mhz */ ++ primary80_chan = -1; ++ } ++ return primary80_chan; ++} ++ ++/* ++ * Returns the secondary 80 Mhz channel for the provided chanspec ++ * ++ * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved ++ * ++ * returns -1 in case the provided channel is 20/40/80 Mhz chanspec ++ */ ++uint8 ++wf_chspec_secondary80_channel(chanspec_t chanspec) ++{ ++ uint8 secondary80_chan; ++ ++ if (CHSPEC_IS8080(chanspec)) { ++ secondary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); ++ } ++ else if (CHSPEC_IS160(chanspec)) { ++ uint8 center_chan = CHSPEC_CHANNEL(chanspec); ++ uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT; ++ ++ /* based on the sb value secondary 80 channel can be retrieved ++ * if sb is in range 0 to 3 upper band is the secondary 80Mhz band ++ */ ++ if (sb < 4) { ++ secondary80_chan = center_chan + CH_40MHZ_APART; ++ } ++ /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */ ++ else ++ { ++ secondary80_chan = center_chan - CH_40MHZ_APART; ++ } ++ } ++ else { ++ /* for 20, 40, and 80 Mhz */ ++ secondary80_chan = -1; ++ } ++ return secondary80_chan; ++} ++ ++/* ++ * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. ++ * ++ * chanspec - Input chanspec for which the primary 80Mhz chanspec has to be retreived ++ * ++ * returns the input chanspec in case the provided chanspec is an 80 MHz chanspec ++ * returns INVCHANSPEC in case the provided channel is 20/40 MHz chanspec ++ */ ++chanspec_t ++wf_chspec_primary80_chspec(chanspec_t chspec) ++{ ++ chanspec_t chspec80; ++ uint center_chan; ++ uint sb; ++ ++ ASSERT(!wf_chspec_malformed(chspec)); ++ if (CHSPEC_IS80(chspec)) { ++ chspec80 = chspec; ++ } ++ else if (CHSPEC_IS8080(chspec)) { ++ ++ /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */ ++ center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec)); ++ ++ sb = CHSPEC_CTL_SB(chspec); ++ ++ /* Create primary 80MHz chanspec */ ++ chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); ++ } ++ else if (CHSPEC_IS160(chspec)) { ++ center_chan = CHSPEC_CHANNEL(chspec); ++ sb = CHSPEC_CTL_SB(chspec); ++ ++ if (sb < WL_CHANSPEC_CTL_SB_ULL) { ++ /* Primary 80MHz is on lower side */ ++ center_chan -= CH_40MHZ_APART; ++ } ++ else { ++ /* Primary 80MHz is on upper side */ ++ center_chan += CH_40MHZ_APART; ++ sb -= WL_CHANSPEC_CTL_SB_ULL; ++ } ++ /* Create primary 80MHz chanspec */ ++ chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); ++ } ++ else { ++ chspec80 = INVCHANSPEC; ++ } ++ ++ return chspec80; ++} ++ ++#ifdef WL11AC_80P80 ++uint8 ++wf_chspec_channel(chanspec_t chspec) ++{ ++ if (CHSPEC_IS8080(chspec)) { ++ return wf_chspec_primary80_channel(chspec); ++ } ++ else { ++ return ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)); ++ } ++} ++#endif /* WL11AC_80P80 */ ++ ++/* This routine returns the chanspec for a given operating class and ++ * channel number ++ */ ++chanspec_t ++wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel) ++{ ++ chanspec_t chanspec = 0; ++ uint16 opclass_info = 0; ++ uint16 lookupindex = 0; ++ switch (opclass) { ++ case 115: ++ lookupindex = 1; ++ break; ++ case 124: ++ lookupindex = 3; ++ break; ++ case 125: ++ lookupindex = 5; ++ break; ++ case 81: ++ lookupindex = 12; ++ break; ++ case 116: ++ lookupindex = 22; ++ break; ++ case 119: ++ lookupindex = 23; ++ break; ++ case 126: ++ lookupindex = 25; ++ break; ++ case 83: ++ lookupindex = 32; ++ break; ++ case 84: ++ lookupindex = 33; ++ break; ++ default: ++ lookupindex = 12; ++ } ++ ++ if (lookupindex < 33) { ++ opclass_info = opclass_data[lookupindex-1]; ++ } ++ else { ++ opclass_info = opclass_data[11]; ++ } ++ chanspec = opclass_info | (uint16)channel; ++ return chanspec; ++} ++ ++/* This routine returns the opclass for a given chanspec */ ++int ++wf_channel_create_opclass_frm_chspec(chanspec_t chspec) ++{ ++ BCM_REFERENCE(chspec); ++ /* TODO: Implement this function ! */ ++ return 12; /* opclass 12 for basic 2G channels */ ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_channels.h b/module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_channels.h +new file mode 100644 +index 000000000..28c6e2739 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_channels.h +@@ -0,0 +1,645 @@ ++/* ++ * Misc utility routines for WL and Apps ++ * This header file housing the define and function prototype use by ++ * both the wl driver, tools & Apps. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmwifi_channels.h 612483 2016-01-14 03:44:27Z $ ++ */ ++ ++#ifndef _bcmwifi_channels_h_ ++#define _bcmwifi_channels_h_ ++ ++ ++/* A chanspec holds the channel number, band, bandwidth and control sideband */ ++typedef uint16 chanspec_t; ++ ++/* channel defines */ ++#define CH_UPPER_SB 0x01 ++#define CH_LOWER_SB 0x02 ++#define CH_EWA_VALID 0x04 ++#define CH_80MHZ_APART 16 ++#define CH_40MHZ_APART 8 ++#define CH_20MHZ_APART 4 ++#define CH_10MHZ_APART 2 ++#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */ ++#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ ++ ++/* maximum # channels the s/w supports */ ++#define MAXCHANNEL 224 /* max # supported channels. The max channel no is above, ++ * this is that + 1 rounded up to a multiple of NBBY (8). ++ * DO NOT MAKE it > 255: channels are uint8's all over ++ */ ++#define MAXCHANNEL_NUM (MAXCHANNEL - 1) /* max channel number */ ++ ++/* channel bitvec */ ++typedef struct { ++ uint8 vec[MAXCHANNEL/8]; /* bitvec of channels */ ++} chanvec_t; ++ ++/* make sure channel num is within valid range */ ++#define CH_NUM_VALID_RANGE(ch_num) ((ch_num) > 0 && (ch_num) <= MAXCHANNEL_NUM) ++ ++#define CHSPEC_CTLOVLP(sp1, sp2, sep) \ ++ (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep)) ++ ++/* All builds use the new 11ac ratespec/chanspec */ ++#undef D11AC_IOTYPES ++#define D11AC_IOTYPES ++ ++#define WL_CHANSPEC_CHAN_MASK 0x00ff ++#define WL_CHANSPEC_CHAN_SHIFT 0 ++#define WL_CHANSPEC_CHAN1_MASK 0x000f ++#define WL_CHANSPEC_CHAN1_SHIFT 0 ++#define WL_CHANSPEC_CHAN2_MASK 0x00f0 ++#define WL_CHANSPEC_CHAN2_SHIFT 4 ++ ++#define WL_CHANSPEC_CTL_SB_MASK 0x0700 ++#define WL_CHANSPEC_CTL_SB_SHIFT 8 ++#define WL_CHANSPEC_CTL_SB_LLL 0x0000 ++#define WL_CHANSPEC_CTL_SB_LLU 0x0100 ++#define WL_CHANSPEC_CTL_SB_LUL 0x0200 ++#define WL_CHANSPEC_CTL_SB_LUU 0x0300 ++#define WL_CHANSPEC_CTL_SB_ULL 0x0400 ++#define WL_CHANSPEC_CTL_SB_ULU 0x0500 ++#define WL_CHANSPEC_CTL_SB_UUL 0x0600 ++#define WL_CHANSPEC_CTL_SB_UUU 0x0700 ++#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL ++#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU ++#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL ++#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU ++#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL ++#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU ++#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL ++#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU ++#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL ++ ++#define WL_CHANSPEC_BW_MASK 0x3800 ++#define WL_CHANSPEC_BW_SHIFT 11 ++#define WL_CHANSPEC_BW_5 0x0000 ++#define WL_CHANSPEC_BW_10 0x0800 ++#define WL_CHANSPEC_BW_20 0x1000 ++#define WL_CHANSPEC_BW_40 0x1800 ++#define WL_CHANSPEC_BW_80 0x2000 ++#define WL_CHANSPEC_BW_160 0x2800 ++#define WL_CHANSPEC_BW_8080 0x3000 ++#define WL_CHANSPEC_BW_2P5 0x3800 ++ ++#define WL_CHANSPEC_BAND_MASK 0xc000 ++#define WL_CHANSPEC_BAND_SHIFT 14 ++#define WL_CHANSPEC_BAND_2G 0x0000 ++#define WL_CHANSPEC_BAND_3G 0x4000 ++#define WL_CHANSPEC_BAND_4G 0x8000 ++#define WL_CHANSPEC_BAND_5G 0xc000 ++#define INVCHANSPEC 255 ++#define MAX_CHANSPEC 0xFFFF ++ ++#define WL_CHANNEL_BAND(ch) (((ch) <= CH_MAX_2G_CHANNEL) ? \ ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G) ++ ++/* 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 LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0) ++#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \ ++ ((channel) + 3 * CH_10MHZ_APART) : 0) ++#define LU_20_SB(channel) LOWER_20_SB(channel) ++#define UL_20_SB(channel) UPPER_20_SB(channel) ++ ++#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) ++#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) ++#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) ++#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ ++ (((channel) <= CH_MAX_2G_CHANNEL) ? \ ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) ++#define CH2P5MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_2P5 | \ ++ (((channel) <= CH_MAX_2G_CHANNEL) ? \ ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) ++#define CH5MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_5 | \ ++ (((channel) <= CH_MAX_2G_CHANNEL) ? \ ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) ++#define CH10MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_10 | \ ++ (((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 CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ++ ((channel) | (ctlsb) | \ ++ WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) ++#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ ++ ((channel) | (ctlsb) | \ ++ WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) ++#define CHBW_CHSPEC(bw, channel) (chanspec_t)((chanspec_t)(channel) | (bw) | \ ++ (((channel) <= CH_MAX_2G_CHANNEL) ? \ ++ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) ++ ++/* simple MACROs to get different fields of chanspec */ ++#ifdef WL11AC_80P80 ++#define CHSPEC_CHANNEL(chspec) wf_chspec_channel(chspec) ++#else ++#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) ++#endif ++#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT ++#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT ++#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) ++#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) ++#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) ++ ++#ifdef WL11N_20MHZONLY ++#ifdef WL11ULB ++#define CHSPEC_IS2P5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_2P5) ++#define CHSPEC_IS5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_5) ++#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) ++#else ++#define CHSPEC_IS2P5(chspec) 0 ++#define CHSPEC_IS5(chspec) 0 ++#define CHSPEC_IS10(chspec) 0 ++#endif ++#define CHSPEC_IS20(chspec) 1 ++#define CHSPEC_IS20_2G(chspec) ((((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) && \ ++ CHSPEC_IS2G(chspec)) ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) 0 ++#endif ++#ifndef CHSPEC_IS80 ++#define CHSPEC_IS80(chspec) 0 ++#endif ++#ifndef CHSPEC_IS160 ++#define CHSPEC_IS160(chspec) 0 ++#endif ++#ifndef CHSPEC_IS8080 ++#define CHSPEC_IS8080(chspec) 0 ++#endif ++#define BW_LE20(bw) TRUE ++#define CHSPEC_ISLE20(chspec) TRUE ++#else /* !WL11N_20MHZONLY */ ++ ++#define CHSPEC_IS2P5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_2P5) ++#define CHSPEC_IS5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_5) ++#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) ++#define CHSPEC_IS20_5G(chspec) ((((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) && \ ++ CHSPEC_IS5G(chspec)) ++#ifndef CHSPEC_IS40 ++#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) ++#endif ++#ifndef CHSPEC_IS80 ++#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) ++#endif ++#ifndef CHSPEC_IS160 ++#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) ++#endif ++#ifndef CHSPEC_IS8080 ++#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) ++#endif ++ ++#ifdef WL11ULB ++#define BW_LT20(bw) (((bw) == WL_CHANSPEC_BW_2P5) || \ ++ ((bw) == WL_CHANSPEC_BW_5) || \ ++ ((bw) == WL_CHANSPEC_BW_10)) ++#define CHSPEC_BW_LT20(chspec) (BW_LT20(CHSPEC_BW(chspec))) ++/* This MACRO is strictly to avoid abandons in existing code with ULB feature and is in no way ++ * optimial to use. Should be replaced with CHSPEC_BW_LE() instead ++ */ ++#define BW_LE20(bw) (((bw) == WL_CHANSPEC_BW_2P5) || \ ++ ((bw) == WL_CHANSPEC_BW_5) || \ ++ ((bw) == WL_CHANSPEC_BW_10) || \ ++ ((bw) == WL_CHANSPEC_BW_20)) ++#define CHSPEC_ISLE20(chspec) (BW_LE20(CHSPEC_BW(chspec))) ++ ++#else /* WL11ULB */ ++#define BW_LE20(bw) ((bw) == WL_CHANSPEC_BW_20) ++#define CHSPEC_ISLE20(chspec) (CHSPEC_IS20(chspec)) ++#endif /* WL11ULB */ ++#endif /* !WL11N_20MHZONLY */ ++ ++#define BW_LE40(bw) (BW_LE20(bw) || ((bw) == WL_CHANSPEC_BW_40)) ++#define BW_LE80(bw) (BW_LE40(bw) || ((bw) == WL_CHANSPEC_BW_80)) ++#define BW_LE160(bw) (BW_LE80(bw) || ((bw) == WL_CHANSPEC_BW_160)) ++#define CHSPEC_BW_LE20(chspec) (BW_LE20(CHSPEC_BW(chspec))) ++#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_UPPER(chspec) \ ++ ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ ++ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) ++#define CHSPEC_SB_LOWER(chspec) \ ++ ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ ++ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) ++#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) ++ ++/** ++ * Number of chars needed for wf_chspec_ntoa() destination character buffer. ++ */ ++#define CHANSPEC_STR_LEN 20 ++ ++ ++#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\ ++ CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080) ++ ++/* BW inequality comparisons, LE (<=), GE (>=), LT (<), GT (>), comparisons can be made ++* as simple numeric comparisons, with the exception that 160 is the same BW as 80+80, ++* but have different numeric values; (WL_CHANSPEC_BW_160 < WL_CHANSPEC_BW_8080). ++* ++* The LT/LE/GT/GE macros check first checks whether both chspec bandwidth and bw are 160 wide. ++* If both chspec bandwidth and bw is not 160 wide, then the comparison is made. ++*/ ++#ifdef WL11ULB ++#define CHSPEC_BW_GE(chspec, bw) \ ++ (((CHSPEC_IS_BW_160_WIDE(chspec) &&\ ++ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ ++ (CHSPEC_BW(chspec) >= (bw))) && \ ++ (!(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5 && (bw) != WL_CHANSPEC_BW_2P5))) ++#else /* WL11ULB */ ++#define CHSPEC_BW_GE(chspec, bw) \ ++ ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ ++ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ ++ (CHSPEC_BW(chspec) >= (bw))) ++#endif /* WL11ULB */ ++ ++#ifdef WL11ULB ++#define CHSPEC_BW_LE(chspec, bw) \ ++ (((CHSPEC_IS_BW_160_WIDE(chspec) &&\ ++ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ ++ (CHSPEC_BW(chspec) <= (bw))) || \ ++ (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5)) ++#else /* WL11ULB */ ++#define CHSPEC_BW_LE(chspec, bw) \ ++ ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ ++ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ ++ (CHSPEC_BW(chspec) <= (bw))) ++#endif /* WL11ULB */ ++ ++#ifdef WL11ULB ++#define CHSPEC_BW_GT(chspec, bw) \ ++ ((!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ ++ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ ++ (CHSPEC_BW(chspec) > (bw))) && \ ++ (CHSPEC_BW(chspec) != WL_CHANSPEC_BW_2P5)) ++#else /* WL11ULB */ ++#define CHSPEC_BW_GT(chspec, bw) \ ++ (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ ++ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ ++ (CHSPEC_BW(chspec) > (bw))) ++#endif /* WL11ULB */ ++ ++#ifdef WL11ULB ++#define CHSPEC_BW_LT(chspec, bw) \ ++ ((!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ ++ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ ++ (CHSPEC_BW(chspec) < (bw))) || \ ++ ((CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5 && (bw) != WL_CHANSPEC_BW_2P5))) ++#else /* WL11ULB */ ++#define CHSPEC_BW_LT(chspec, bw) \ ++ (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ ++ ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ ++ (CHSPEC_BW(chspec) < (bw))) ++#endif /* WL11ULB */ ++ ++/* Legacy Chanspec defines ++ * These are the defines for the previous format of the chanspec_t ++ */ ++#define WL_LCHANSPEC_CHAN_MASK 0x00ff ++#define WL_LCHANSPEC_CHAN_SHIFT 0 ++ ++#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 ++#define WL_LCHANSPEC_CTL_SB_SHIFT 8 ++#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 ++#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 ++#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 ++ ++#define WL_LCHANSPEC_BW_MASK 0x0C00 ++#define WL_LCHANSPEC_BW_SHIFT 10 ++#define WL_LCHANSPEC_BW_10 0x0400 ++#define WL_LCHANSPEC_BW_20 0x0800 ++#define WL_LCHANSPEC_BW_40 0x0C00 ++ ++#define WL_LCHANSPEC_BAND_MASK 0xf000 ++#define WL_LCHANSPEC_BAND_SHIFT 12 ++#define WL_LCHANSPEC_BAND_5G 0x1000 ++#define WL_LCHANSPEC_BAND_2G 0x2000 ++ ++#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) ++#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) ++#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) ++#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) ++#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) ++#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) ++#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) ++#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) ++#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) ++ ++#define LCHSPEC_SB_UPPER(chspec) \ ++ ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \ ++ (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) ++#define LCHSPEC_SB_LOWER(chspec) \ ++ ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \ ++ (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) ++ ++#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) ++ ++#define CH20MHZ_LCHSPEC(channel) \ ++ (chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \ ++ WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ ++ WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G)) ++ ++/* ++ * WF_CHAN_FACTOR_* constants are used to calculate channel frequency ++ * given a channel number. ++ * chan_freq = chan_factor * 500Mhz + chan_number * 5 ++ */ ++ ++/** ++ * Channel Factor for the starting frequence of 2.4 GHz channels. ++ * The value corresponds to 2407 MHz. ++ */ ++#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ ++ ++/** ++ * Channel Factor for the starting frequence of 5 GHz channels. ++ * The value corresponds to 5000 MHz. ++ */ ++#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ ++ ++/** ++ * Channel Factor for the starting frequence of 4.9 GHz channels. ++ * The value corresponds to 4000 MHz. ++ */ ++#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ ++ ++#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ ++ ++/** ++ * No of sub-band vlaue of the specified Mhz chanspec ++ */ ++#define WF_NUM_SIDEBANDS_40MHZ 2 ++#define WF_NUM_SIDEBANDS_80MHZ 4 ++#define WF_NUM_SIDEBANDS_8080MHZ 4 ++#define WF_NUM_SIDEBANDS_160MHZ 8 ++ ++/** ++ * Convert chanspec to ascii string ++ * ++ * @param chspec chanspec format ++ * @param buf ascii string of chanspec ++ * ++ * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes ++ * Original chanspec in case of error ++ * ++ * @see CHANSPEC_STR_LEN ++ */ ++extern char * wf_chspec_ntoa_ex(chanspec_t chspec, char *buf); ++ ++/** ++ * Convert chanspec to ascii string ++ * ++ * @param chspec chanspec format ++ * @param buf ascii string of chanspec ++ * ++ * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes ++ * NULL in case of error ++ * ++ * @see CHANSPEC_STR_LEN ++ */ ++extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); ++ ++/** ++ * Convert ascii string to chanspec ++ * ++ * @param a pointer to input string ++ * ++ * @return >= 0 if successful or 0 otherwise ++ */ ++extern chanspec_t wf_chspec_aton(const char *a); ++ ++/** ++ * Verify the chanspec fields are valid. ++ * ++ * Verify the chanspec is using a legal set field values, i.e. that the chanspec ++ * specified a band, bw, ctl_sb and channel and that the combination could be ++ * legal given some set of circumstances. ++ * ++ * @param chanspec input chanspec to verify ++ * ++ * @return TRUE if the chanspec is malformed, FALSE if it looks good. ++ */ ++extern bool wf_chspec_malformed(chanspec_t chanspec); ++ ++/** ++ * Verify the chanspec specifies a valid channel according to 802.11. ++ * ++ * @param chanspec input chanspec to verify ++ * ++ * @return TRUE if the chanspec is a valid 802.11 channel ++ */ ++extern bool wf_chspec_valid(chanspec_t chanspec); ++ ++/** ++ * Return the primary (control) channel. ++ * ++ * This function returns the channel number of the primary 20MHz channel. For ++ * 20MHz channels this is just the channel number. For 40MHz or wider channels ++ * it is the primary 20MHz channel specified by the chanspec. ++ * ++ * @param chspec input chanspec ++ * ++ * @return Returns the channel number of the primary 20MHz channel ++ */ ++extern uint8 wf_chspec_ctlchan(chanspec_t chspec); ++ ++/* ++ * Return the bandwidth string. ++ * ++ * This function returns the bandwidth string for the passed chanspec. ++ * ++ * @param chspec input chanspec ++ * ++ * @return Returns the bandwidth string ++ */ ++extern const char *wf_chspec_to_bw_str(chanspec_t chspec); ++ ++/** ++ * Return the primary (control) chanspec. ++ * ++ * This function returns the chanspec of the primary 20MHz channel. For 20MHz ++ * channels this is just the chanspec. For 40MHz or wider channels it is the ++ * chanspec of the primary 20MHZ channel specified by the chanspec. ++ * ++ * @param chspec input chanspec ++ * ++ * @return Returns the chanspec of the primary 20MHz channel ++ */ ++extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); ++ ++/** ++ * Return a channel number corresponding to a frequency. ++ * ++ * This function returns the chanspec for the primary 40MHz of an 80MHz channel. ++ * The control sideband specifies the same 20MHz channel that the 80MHz channel is using ++ * as the primary 20MHz channel. ++ */ ++extern chanspec_t wf_chspec_primary40_chspec(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 ++ * ++ * @param freq frequency in MHz ++ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz ++ * ++ * @return Returns a channel number ++ * ++ * @see WF_CHAN_FACTOR_2_4_G ++ * @see WF_CHAN_FACTOR_5_G ++ */ ++extern int wf_mhz2channel(uint freq, uint start_factor); ++ ++/** ++ * Return the center frequency in MHz of the given channel and base frequency. ++ * ++ * Return the center frequency in MHz of the given channel and base frequency. ++ * The channel number is interpreted relative to the given base frequency. ++ * ++ * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. ++ * 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 channel range of [1, 14] is only checked for a start_factor of ++ * WF_CHAN_FACTOR_2_4_G (4814). ++ * Odd start_factors produce channels on .5 MHz boundaries, in which case ++ * the answer is rounded down to an integral MHz. ++ * -1 is returned for an out of range channel. ++ * ++ * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 ++ * ++ * @param channel input channel number ++ * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz ++ * ++ * @return Returns a frequency in MHz ++ * ++ * @see WF_CHAN_FACTOR_2_4_G ++ * @see WF_CHAN_FACTOR_5_G ++ */ ++extern int wf_channel2mhz(uint channel, uint start_factor); ++ ++/** ++ * Returns the chanspec 80Mhz channel corresponding to the following input ++ * parameters ++ * ++ * primary_channel - primary 20Mhz channel ++ * center_channel - center frequecny of the 80Mhz channel ++ * ++ * The center_channel can be one of {42, 58, 106, 122, 138, 155} ++ * ++ * returns INVCHANSPEC in case of error ++ */ ++extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel); ++ ++/** ++ * Convert ctl chan and bw to chanspec ++ * ++ * @param ctl_ch channel ++ * @param bw bandwidth ++ * ++ * @return > 0 if successful or 0 otherwise ++ * ++ */ ++extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); ++ ++extern uint wf_channel2freq(uint channel); ++extern uint wf_freq2channel(uint freq); ++ ++/* ++ * Returns the 80+80 MHz chanspec corresponding to the following input parameters ++ * ++ * primary_20mhz - Primary 20 MHz channel ++ * chan0_80MHz - center channel number of one frequency segment ++ * chan1_80MHz - center channel number of the other frequency segment ++ * ++ * Parameters chan0_80MHz and chan1_80MHz are channel numbers in {42, 58, 106, 122, 138, 155}. ++ * The primary channel must be contained in one of the 80MHz channels. This routine ++ * will determine which frequency segment is the primary 80 MHz segment. ++ * ++ * Returns INVCHANSPEC in case of error. ++ * ++ * Refer to IEEE802.11ac section 22.3.14 "Channelization". ++ */ ++extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz, ++ uint8 chan0_80Mhz, uint8 chan1_80Mhz); ++ ++/* ++ * Returns the primary 80 Mhz channel for the provided chanspec ++ * ++ * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved ++ * ++ * returns -1 in case the provided channel is 20/40 Mhz chanspec ++ */ ++extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec); ++ ++/* ++ * Returns the secondary 80 Mhz channel for the provided chanspec ++ * ++ * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved ++ * ++ * returns -1 in case the provided channel is 20/40 Mhz chanspec ++ */ ++extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec); ++ ++/* ++ * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. ++ */ ++extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec); ++ ++#ifdef WL11AC_80P80 ++/* ++ * This function returns the centre chanel for the given chanspec. ++ * In case of 80+80 chanspec it returns the primary 80 Mhz centre channel ++ */ ++extern uint8 wf_chspec_channel(chanspec_t chspec); ++#endif ++extern chanspec_t wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel); ++extern int wf_channel_create_opclass_frm_chspec(chanspec_t chspec); ++#endif /* _bcmwifi_channels_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_rates.h b/module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_rates.h +new file mode 100644 +index 000000000..542055df3 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmwifi_rates.h +@@ -0,0 +1,793 @@ ++/* ++ * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmwifi_rates.h 612483 2016-01-14 03:44:27Z $ ++ */ ++ ++#ifndef _bcmwifi_rates_h_ ++#define _bcmwifi_rates_h_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++ ++#define WL_RATESET_SZ_DSSS 4 ++#define WL_RATESET_SZ_OFDM 8 ++#define WL_RATESET_SZ_VHT_MCS 10 ++#define WL_RATESET_SZ_VHT_MCS_P 12 ++ ++#if defined(WLPROPRIETARY_11N_RATES) ++#define WL_RATESET_SZ_HT_MCS WL_RATESET_SZ_VHT_MCS ++#else ++#define WL_RATESET_SZ_HT_MCS 8 ++#endif ++ ++#define WL_RATESET_SZ_HT_IOCTL 8 /* MAC histogram, compatibility with wl utility */ ++ ++#define WL_TX_CHAINS_MAX 4 ++ ++#define WL_RATE_DISABLED (-128) /* Power value corresponding to unsupported rate */ ++ ++/* Transmit channel bandwidths */ ++typedef enum wl_tx_bw { ++ WL_TX_BW_20, ++ WL_TX_BW_40, ++ WL_TX_BW_80, ++ WL_TX_BW_20IN40, ++ WL_TX_BW_20IN80, ++ WL_TX_BW_40IN80, ++ WL_TX_BW_160, ++ WL_TX_BW_20IN160, ++ WL_TX_BW_40IN160, ++ WL_TX_BW_80IN160, ++ WL_TX_BW_ALL, ++ WL_TX_BW_8080, ++ WL_TX_BW_8080CHAN2, ++ WL_TX_BW_20IN8080, ++ WL_TX_BW_40IN8080, ++ WL_TX_BW_80IN8080, ++ WL_TX_BW_2P5, ++ WL_TX_BW_5, ++ WL_TX_BW_10 ++} wl_tx_bw_t; ++ ++ ++/* ++ * Transmit modes. ++ * Not all modes are listed here, only those required for disambiguation. e.g. SPEXP is not listed ++ */ ++typedef enum wl_tx_mode { ++ WL_TX_MODE_NONE, ++ WL_TX_MODE_STBC, ++ WL_TX_MODE_CDD, ++ WL_TX_MODE_TXBF, ++ WL_NUM_TX_MODES ++} wl_tx_mode_t; ++ ++ ++/* Number of transmit chains */ ++typedef enum wl_tx_chains { ++ WL_TX_CHAINS_1 = 1, ++ WL_TX_CHAINS_2, ++ WL_TX_CHAINS_3, ++ WL_TX_CHAINS_4 ++} wl_tx_chains_t; ++ ++ ++/* Number of transmit streams */ ++typedef enum wl_tx_nss { ++ WL_TX_NSS_1 = 1, ++ WL_TX_NSS_2, ++ WL_TX_NSS_3, ++ WL_TX_NSS_4 ++} wl_tx_nss_t; ++ ++ ++/* This enum maps each rate to a CLM index */ ++ ++typedef enum clm_rates { ++ /************ ++ * 1 chain * ++ ************ ++ */ ++ ++ /* 1 Stream */ ++ WL_RATE_1X1_DSSS_1 = 0, ++ WL_RATE_1X1_DSSS_2 = 1, ++ WL_RATE_1X1_DSSS_5_5 = 2, ++ WL_RATE_1X1_DSSS_11 = 3, ++ ++ WL_RATE_1X1_OFDM_6 = 4, ++ WL_RATE_1X1_OFDM_9 = 5, ++ WL_RATE_1X1_OFDM_12 = 6, ++ WL_RATE_1X1_OFDM_18 = 7, ++ WL_RATE_1X1_OFDM_24 = 8, ++ WL_RATE_1X1_OFDM_36 = 9, ++ WL_RATE_1X1_OFDM_48 = 10, ++ WL_RATE_1X1_OFDM_54 = 11, ++ ++ WL_RATE_1X1_MCS0 = 12, ++ WL_RATE_1X1_MCS1 = 13, ++ WL_RATE_1X1_MCS2 = 14, ++ WL_RATE_1X1_MCS3 = 15, ++ WL_RATE_1X1_MCS4 = 16, ++ WL_RATE_1X1_MCS5 = 17, ++ WL_RATE_1X1_MCS6 = 18, ++ WL_RATE_1X1_MCS7 = 19, ++ WL_RATE_P_1X1_MCS87 = 20, ++ WL_RATE_P_1X1_MCS88 = 21, ++ ++ WL_RATE_1X1_VHT0SS1 = 12, ++ WL_RATE_1X1_VHT1SS1 = 13, ++ WL_RATE_1X1_VHT2SS1 = 14, ++ WL_RATE_1X1_VHT3SS1 = 15, ++ WL_RATE_1X1_VHT4SS1 = 16, ++ WL_RATE_1X1_VHT5SS1 = 17, ++ WL_RATE_1X1_VHT6SS1 = 18, ++ WL_RATE_1X1_VHT7SS1 = 19, ++ WL_RATE_1X1_VHT8SS1 = 20, ++ WL_RATE_1X1_VHT9SS1 = 21, ++ WL_RATE_P_1X1_VHT10SS1 = 22, ++ WL_RATE_P_1X1_VHT11SS1 = 23, ++ ++ ++ /************ ++ * 2 chains * ++ ************ ++ */ ++ ++ /* 1 Stream expanded + 1 */ ++ WL_RATE_1X2_DSSS_1 = 24, ++ WL_RATE_1X2_DSSS_2 = 25, ++ WL_RATE_1X2_DSSS_5_5 = 26, ++ WL_RATE_1X2_DSSS_11 = 27, ++ ++ WL_RATE_1X2_CDD_OFDM_6 = 28, ++ WL_RATE_1X2_CDD_OFDM_9 = 29, ++ WL_RATE_1X2_CDD_OFDM_12 = 30, ++ WL_RATE_1X2_CDD_OFDM_18 = 31, ++ WL_RATE_1X2_CDD_OFDM_24 = 32, ++ WL_RATE_1X2_CDD_OFDM_36 = 33, ++ WL_RATE_1X2_CDD_OFDM_48 = 34, ++ WL_RATE_1X2_CDD_OFDM_54 = 35, ++ ++ WL_RATE_1X2_CDD_MCS0 = 36, ++ WL_RATE_1X2_CDD_MCS1 = 37, ++ WL_RATE_1X2_CDD_MCS2 = 38, ++ WL_RATE_1X2_CDD_MCS3 = 39, ++ WL_RATE_1X2_CDD_MCS4 = 40, ++ WL_RATE_1X2_CDD_MCS5 = 41, ++ WL_RATE_1X2_CDD_MCS6 = 42, ++ WL_RATE_1X2_CDD_MCS7 = 43, ++ WL_RATE_P_1X2_CDD_MCS87 = 44, ++ WL_RATE_P_1X2_CDD_MCS88 = 45, ++ ++ WL_RATE_1X2_VHT0SS1 = 36, ++ WL_RATE_1X2_VHT1SS1 = 37, ++ WL_RATE_1X2_VHT2SS1 = 38, ++ WL_RATE_1X2_VHT3SS1 = 39, ++ WL_RATE_1X2_VHT4SS1 = 40, ++ WL_RATE_1X2_VHT5SS1 = 41, ++ WL_RATE_1X2_VHT6SS1 = 42, ++ WL_RATE_1X2_VHT7SS1 = 43, ++ WL_RATE_1X2_VHT8SS1 = 44, ++ WL_RATE_1X2_VHT9SS1 = 45, ++ WL_RATE_P_1X2_VHT10SS1 = 46, ++ WL_RATE_P_1X2_VHT11SS1 = 47, ++ ++ /* 2 Streams */ ++ WL_RATE_2X2_STBC_MCS0 = 48, ++ WL_RATE_2X2_STBC_MCS1 = 49, ++ WL_RATE_2X2_STBC_MCS2 = 50, ++ WL_RATE_2X2_STBC_MCS3 = 51, ++ WL_RATE_2X2_STBC_MCS4 = 52, ++ WL_RATE_2X2_STBC_MCS5 = 53, ++ WL_RATE_2X2_STBC_MCS6 = 54, ++ WL_RATE_2X2_STBC_MCS7 = 55, ++ WL_RATE_P_2X2_STBC_MCS87 = 56, ++ WL_RATE_P_2X2_STBC_MCS88 = 57, ++ ++ WL_RATE_2X2_STBC_VHT0SS1 = 48, ++ WL_RATE_2X2_STBC_VHT1SS1 = 49, ++ WL_RATE_2X2_STBC_VHT2SS1 = 50, ++ WL_RATE_2X2_STBC_VHT3SS1 = 51, ++ WL_RATE_2X2_STBC_VHT4SS1 = 52, ++ WL_RATE_2X2_STBC_VHT5SS1 = 53, ++ WL_RATE_2X2_STBC_VHT6SS1 = 54, ++ WL_RATE_2X2_STBC_VHT7SS1 = 55, ++ WL_RATE_2X2_STBC_VHT8SS1 = 56, ++ WL_RATE_2X2_STBC_VHT9SS1 = 57, ++ WL_RATE_P_2X2_STBC_VHT10SS1 = 58, ++ WL_RATE_P_2X2_STBC_VHT11SS1 = 59, ++ ++ WL_RATE_2X2_SDM_MCS8 = 60, ++ WL_RATE_2X2_SDM_MCS9 = 61, ++ WL_RATE_2X2_SDM_MCS10 = 62, ++ WL_RATE_2X2_SDM_MCS11 = 63, ++ WL_RATE_2X2_SDM_MCS12 = 64, ++ WL_RATE_2X2_SDM_MCS13 = 65, ++ WL_RATE_2X2_SDM_MCS14 = 66, ++ WL_RATE_2X2_SDM_MCS15 = 67, ++ WL_RATE_P_2X2_SDM_MCS99 = 68, ++ WL_RATE_P_2X2_SDM_MCS100 = 69, ++ ++ WL_RATE_2X2_VHT0SS2 = 60, ++ WL_RATE_2X2_VHT1SS2 = 61, ++ WL_RATE_2X2_VHT2SS2 = 62, ++ WL_RATE_2X2_VHT3SS2 = 63, ++ WL_RATE_2X2_VHT4SS2 = 64, ++ WL_RATE_2X2_VHT5SS2 = 65, ++ WL_RATE_2X2_VHT6SS2 = 66, ++ WL_RATE_2X2_VHT7SS2 = 67, ++ WL_RATE_2X2_VHT8SS2 = 68, ++ WL_RATE_2X2_VHT9SS2 = 69, ++ WL_RATE_P_2X2_VHT10SS2 = 70, ++ WL_RATE_P_2X2_VHT11SS2 = 71, ++ ++ /**************************** ++ * TX Beamforming, 2 chains * ++ **************************** ++ */ ++ ++ /* 1 Stream expanded + 1 */ ++ WL_RATE_1X2_TXBF_OFDM_6 = 72, ++ WL_RATE_1X2_TXBF_OFDM_9 = 73, ++ WL_RATE_1X2_TXBF_OFDM_12 = 74, ++ WL_RATE_1X2_TXBF_OFDM_18 = 75, ++ WL_RATE_1X2_TXBF_OFDM_24 = 76, ++ WL_RATE_1X2_TXBF_OFDM_36 = 77, ++ WL_RATE_1X2_TXBF_OFDM_48 = 78, ++ WL_RATE_1X2_TXBF_OFDM_54 = 79, ++ ++ WL_RATE_1X2_TXBF_MCS0 = 80, ++ WL_RATE_1X2_TXBF_MCS1 = 81, ++ WL_RATE_1X2_TXBF_MCS2 = 82, ++ WL_RATE_1X2_TXBF_MCS3 = 83, ++ WL_RATE_1X2_TXBF_MCS4 = 84, ++ WL_RATE_1X2_TXBF_MCS5 = 85, ++ WL_RATE_1X2_TXBF_MCS6 = 86, ++ WL_RATE_1X2_TXBF_MCS7 = 87, ++ WL_RATE_P_1X2_TXBF_MCS87 = 88, ++ WL_RATE_P_1X2_TXBF_MCS88 = 89, ++ ++ WL_RATE_1X2_TXBF_VHT0SS1 = 80, ++ WL_RATE_1X2_TXBF_VHT1SS1 = 81, ++ WL_RATE_1X2_TXBF_VHT2SS1 = 82, ++ WL_RATE_1X2_TXBF_VHT3SS1 = 83, ++ WL_RATE_1X2_TXBF_VHT4SS1 = 84, ++ WL_RATE_1X2_TXBF_VHT5SS1 = 85, ++ WL_RATE_1X2_TXBF_VHT6SS1 = 86, ++ WL_RATE_1X2_TXBF_VHT7SS1 = 87, ++ WL_RATE_1X2_TXBF_VHT8SS1 = 88, ++ WL_RATE_1X2_TXBF_VHT9SS1 = 89, ++ WL_RATE_P_1X2_TXBF_VHT10SS1 = 90, ++ WL_RATE_P_1X2_TXBF_VHT11SS1 = 91, ++ ++ /* 2 Streams */ ++ WL_RATE_2X2_TXBF_SDM_MCS8 = 92, ++ WL_RATE_2X2_TXBF_SDM_MCS9 = 93, ++ WL_RATE_2X2_TXBF_SDM_MCS10 = 94, ++ WL_RATE_2X2_TXBF_SDM_MCS11 = 95, ++ WL_RATE_2X2_TXBF_SDM_MCS12 = 96, ++ WL_RATE_2X2_TXBF_SDM_MCS13 = 97, ++ WL_RATE_2X2_TXBF_SDM_MCS14 = 98, ++ WL_RATE_2X2_TXBF_SDM_MCS15 = 99, ++ WL_RATE_P_2X2_TXBF_SDM_MCS99 = 100, ++ WL_RATE_P_2X2_TXBF_SDM_MCS100 = 101, ++ ++ WL_RATE_2X2_TXBF_VHT0SS2 = 92, ++ WL_RATE_2X2_TXBF_VHT1SS2 = 93, ++ WL_RATE_2X2_TXBF_VHT2SS2 = 94, ++ WL_RATE_2X2_TXBF_VHT3SS2 = 95, ++ WL_RATE_2X2_TXBF_VHT4SS2 = 96, ++ WL_RATE_2X2_TXBF_VHT5SS2 = 97, ++ WL_RATE_2X2_TXBF_VHT6SS2 = 98, ++ WL_RATE_2X2_TXBF_VHT7SS2 = 99, ++ WL_RATE_2X2_TXBF_VHT8SS2 = 100, ++ WL_RATE_2X2_TXBF_VHT9SS2 = 101, ++ WL_RATE_P_2X2_TXBF_VHT10SS2 = 102, ++ WL_RATE_P_2X2_TXBF_VHT11SS2 = 103, ++ ++ ++ /************ ++ * 3 chains * ++ ************ ++ */ ++ ++ /* 1 Stream expanded + 2 */ ++ WL_RATE_1X3_DSSS_1 = 104, ++ WL_RATE_1X3_DSSS_2 = 105, ++ WL_RATE_1X3_DSSS_5_5 = 106, ++ WL_RATE_1X3_DSSS_11 = 107, ++ ++ WL_RATE_1X3_CDD_OFDM_6 = 108, ++ WL_RATE_1X3_CDD_OFDM_9 = 109, ++ WL_RATE_1X3_CDD_OFDM_12 = 110, ++ WL_RATE_1X3_CDD_OFDM_18 = 111, ++ WL_RATE_1X3_CDD_OFDM_24 = 112, ++ WL_RATE_1X3_CDD_OFDM_36 = 113, ++ WL_RATE_1X3_CDD_OFDM_48 = 114, ++ WL_RATE_1X3_CDD_OFDM_54 = 115, ++ ++ WL_RATE_1X3_CDD_MCS0 = 116, ++ WL_RATE_1X3_CDD_MCS1 = 117, ++ WL_RATE_1X3_CDD_MCS2 = 118, ++ WL_RATE_1X3_CDD_MCS3 = 119, ++ WL_RATE_1X3_CDD_MCS4 = 120, ++ WL_RATE_1X3_CDD_MCS5 = 121, ++ WL_RATE_1X3_CDD_MCS6 = 122, ++ WL_RATE_1X3_CDD_MCS7 = 123, ++ WL_RATE_P_1X3_CDD_MCS87 = 124, ++ WL_RATE_P_1X3_CDD_MCS88 = 125, ++ ++ WL_RATE_1X3_VHT0SS1 = 116, ++ WL_RATE_1X3_VHT1SS1 = 117, ++ WL_RATE_1X3_VHT2SS1 = 118, ++ WL_RATE_1X3_VHT3SS1 = 119, ++ WL_RATE_1X3_VHT4SS1 = 120, ++ WL_RATE_1X3_VHT5SS1 = 121, ++ WL_RATE_1X3_VHT6SS1 = 122, ++ WL_RATE_1X3_VHT7SS1 = 123, ++ WL_RATE_1X3_VHT8SS1 = 124, ++ WL_RATE_1X3_VHT9SS1 = 125, ++ WL_RATE_P_1X3_VHT10SS1 = 126, ++ WL_RATE_P_1X3_VHT11SS1 = 127, ++ ++ /* 2 Streams expanded + 1 */ ++ WL_RATE_2X3_STBC_MCS0 = 128, ++ WL_RATE_2X3_STBC_MCS1 = 129, ++ WL_RATE_2X3_STBC_MCS2 = 130, ++ WL_RATE_2X3_STBC_MCS3 = 131, ++ WL_RATE_2X3_STBC_MCS4 = 132, ++ WL_RATE_2X3_STBC_MCS5 = 133, ++ WL_RATE_2X3_STBC_MCS6 = 134, ++ WL_RATE_2X3_STBC_MCS7 = 135, ++ WL_RATE_P_2X3_STBC_MCS87 = 136, ++ WL_RATE_P_2X3_STBC_MCS88 = 137, ++ ++ WL_RATE_2X3_STBC_VHT0SS1 = 128, ++ WL_RATE_2X3_STBC_VHT1SS1 = 129, ++ WL_RATE_2X3_STBC_VHT2SS1 = 130, ++ WL_RATE_2X3_STBC_VHT3SS1 = 131, ++ WL_RATE_2X3_STBC_VHT4SS1 = 132, ++ WL_RATE_2X3_STBC_VHT5SS1 = 133, ++ WL_RATE_2X3_STBC_VHT6SS1 = 134, ++ WL_RATE_2X3_STBC_VHT7SS1 = 135, ++ WL_RATE_2X3_STBC_VHT8SS1 = 136, ++ WL_RATE_2X3_STBC_VHT9SS1 = 137, ++ WL_RATE_P_2X3_STBC_VHT10SS1 = 138, ++ WL_RATE_P_2X3_STBC_VHT11SS1 = 139, ++ ++ WL_RATE_2X3_SDM_MCS8 = 140, ++ WL_RATE_2X3_SDM_MCS9 = 141, ++ WL_RATE_2X3_SDM_MCS10 = 142, ++ WL_RATE_2X3_SDM_MCS11 = 143, ++ WL_RATE_2X3_SDM_MCS12 = 144, ++ WL_RATE_2X3_SDM_MCS13 = 145, ++ WL_RATE_2X3_SDM_MCS14 = 146, ++ WL_RATE_2X3_SDM_MCS15 = 147, ++ WL_RATE_P_2X3_SDM_MCS99 = 148, ++ WL_RATE_P_2X3_SDM_MCS100 = 149, ++ ++ WL_RATE_2X3_VHT0SS2 = 140, ++ WL_RATE_2X3_VHT1SS2 = 141, ++ WL_RATE_2X3_VHT2SS2 = 142, ++ WL_RATE_2X3_VHT3SS2 = 143, ++ WL_RATE_2X3_VHT4SS2 = 144, ++ WL_RATE_2X3_VHT5SS2 = 145, ++ WL_RATE_2X3_VHT6SS2 = 146, ++ WL_RATE_2X3_VHT7SS2 = 147, ++ WL_RATE_2X3_VHT8SS2 = 148, ++ WL_RATE_2X3_VHT9SS2 = 149, ++ WL_RATE_P_2X3_VHT10SS2 = 150, ++ WL_RATE_P_2X3_VHT11SS2 = 151, ++ ++ /* 3 Streams */ ++ WL_RATE_3X3_SDM_MCS16 = 152, ++ WL_RATE_3X3_SDM_MCS17 = 153, ++ WL_RATE_3X3_SDM_MCS18 = 154, ++ WL_RATE_3X3_SDM_MCS19 = 155, ++ WL_RATE_3X3_SDM_MCS20 = 156, ++ WL_RATE_3X3_SDM_MCS21 = 157, ++ WL_RATE_3X3_SDM_MCS22 = 158, ++ WL_RATE_3X3_SDM_MCS23 = 159, ++ WL_RATE_P_3X3_SDM_MCS101 = 160, ++ WL_RATE_P_3X3_SDM_MCS102 = 161, ++ ++ WL_RATE_3X3_VHT0SS3 = 152, ++ WL_RATE_3X3_VHT1SS3 = 153, ++ WL_RATE_3X3_VHT2SS3 = 154, ++ WL_RATE_3X3_VHT3SS3 = 155, ++ WL_RATE_3X3_VHT4SS3 = 156, ++ WL_RATE_3X3_VHT5SS3 = 157, ++ WL_RATE_3X3_VHT6SS3 = 158, ++ WL_RATE_3X3_VHT7SS3 = 159, ++ WL_RATE_3X3_VHT8SS3 = 160, ++ WL_RATE_3X3_VHT9SS3 = 161, ++ WL_RATE_P_3X3_VHT10SS3 = 162, ++ WL_RATE_P_3X3_VHT11SS3 = 163, ++ ++ ++ /**************************** ++ * TX Beamforming, 3 chains * ++ **************************** ++ */ ++ ++ /* 1 Stream expanded + 2 */ ++ WL_RATE_1X3_TXBF_OFDM_6 = 164, ++ WL_RATE_1X3_TXBF_OFDM_9 = 165, ++ WL_RATE_1X3_TXBF_OFDM_12 = 166, ++ WL_RATE_1X3_TXBF_OFDM_18 = 167, ++ WL_RATE_1X3_TXBF_OFDM_24 = 168, ++ WL_RATE_1X3_TXBF_OFDM_36 = 169, ++ WL_RATE_1X3_TXBF_OFDM_48 = 170, ++ WL_RATE_1X3_TXBF_OFDM_54 = 171, ++ ++ WL_RATE_1X3_TXBF_MCS0 = 172, ++ WL_RATE_1X3_TXBF_MCS1 = 173, ++ WL_RATE_1X3_TXBF_MCS2 = 174, ++ WL_RATE_1X3_TXBF_MCS3 = 175, ++ WL_RATE_1X3_TXBF_MCS4 = 176, ++ WL_RATE_1X3_TXBF_MCS5 = 177, ++ WL_RATE_1X3_TXBF_MCS6 = 178, ++ WL_RATE_1X3_TXBF_MCS7 = 179, ++ WL_RATE_P_1X3_TXBF_MCS87 = 180, ++ WL_RATE_P_1X3_TXBF_MCS88 = 181, ++ ++ WL_RATE_1X3_TXBF_VHT0SS1 = 172, ++ WL_RATE_1X3_TXBF_VHT1SS1 = 173, ++ WL_RATE_1X3_TXBF_VHT2SS1 = 174, ++ WL_RATE_1X3_TXBF_VHT3SS1 = 175, ++ WL_RATE_1X3_TXBF_VHT4SS1 = 176, ++ WL_RATE_1X3_TXBF_VHT5SS1 = 177, ++ WL_RATE_1X3_TXBF_VHT6SS1 = 178, ++ WL_RATE_1X3_TXBF_VHT7SS1 = 179, ++ WL_RATE_1X3_TXBF_VHT8SS1 = 180, ++ WL_RATE_1X3_TXBF_VHT9SS1 = 181, ++ WL_RATE_P_1X3_TXBF_VHT10SS1 = 182, ++ WL_RATE_P_1X3_TXBF_VHT11SS1 = 183, ++ ++ /* 2 Streams expanded + 1 */ ++ WL_RATE_2X3_TXBF_SDM_MCS8 = 184, ++ WL_RATE_2X3_TXBF_SDM_MCS9 = 185, ++ WL_RATE_2X3_TXBF_SDM_MCS10 = 186, ++ WL_RATE_2X3_TXBF_SDM_MCS11 = 187, ++ WL_RATE_2X3_TXBF_SDM_MCS12 = 188, ++ WL_RATE_2X3_TXBF_SDM_MCS13 = 189, ++ WL_RATE_2X3_TXBF_SDM_MCS14 = 190, ++ WL_RATE_2X3_TXBF_SDM_MCS15 = 191, ++ WL_RATE_P_2X3_TXBF_SDM_MCS99 = 192, ++ WL_RATE_P_2X3_TXBF_SDM_MCS100 = 193, ++ ++ WL_RATE_2X3_TXBF_VHT0SS2 = 184, ++ WL_RATE_2X3_TXBF_VHT1SS2 = 185, ++ WL_RATE_2X3_TXBF_VHT2SS2 = 186, ++ WL_RATE_2X3_TXBF_VHT3SS2 = 187, ++ WL_RATE_2X3_TXBF_VHT4SS2 = 188, ++ WL_RATE_2X3_TXBF_VHT5SS2 = 189, ++ WL_RATE_2X3_TXBF_VHT6SS2 = 190, ++ WL_RATE_2X3_TXBF_VHT7SS2 = 191, ++ WL_RATE_2X3_TXBF_VHT8SS2 = 192, ++ WL_RATE_2X3_TXBF_VHT9SS2 = 193, ++ WL_RATE_P_2X3_TXBF_VHT10SS2 = 194, ++ WL_RATE_P_2X3_TXBF_VHT11SS2 = 195, ++ ++ /* 3 Streams */ ++ WL_RATE_3X3_TXBF_SDM_MCS16 = 196, ++ WL_RATE_3X3_TXBF_SDM_MCS17 = 197, ++ WL_RATE_3X3_TXBF_SDM_MCS18 = 198, ++ WL_RATE_3X3_TXBF_SDM_MCS19 = 199, ++ WL_RATE_3X3_TXBF_SDM_MCS20 = 200, ++ WL_RATE_3X3_TXBF_SDM_MCS21 = 201, ++ WL_RATE_3X3_TXBF_SDM_MCS22 = 202, ++ WL_RATE_3X3_TXBF_SDM_MCS23 = 203, ++ WL_RATE_P_3X3_TXBF_SDM_MCS101 = 204, ++ WL_RATE_P_3X3_TXBF_SDM_MCS102 = 205, ++ ++ WL_RATE_3X3_TXBF_VHT0SS3 = 196, ++ WL_RATE_3X3_TXBF_VHT1SS3 = 197, ++ WL_RATE_3X3_TXBF_VHT2SS3 = 198, ++ WL_RATE_3X3_TXBF_VHT3SS3 = 199, ++ WL_RATE_3X3_TXBF_VHT4SS3 = 200, ++ WL_RATE_3X3_TXBF_VHT5SS3 = 201, ++ WL_RATE_3X3_TXBF_VHT6SS3 = 202, ++ WL_RATE_3X3_TXBF_VHT7SS3 = 203, ++ WL_RATE_3X3_TXBF_VHT8SS3 = 204, ++ WL_RATE_3X3_TXBF_VHT9SS3 = 205, ++ WL_RATE_P_3X3_TXBF_VHT10SS3 = 206, ++ WL_RATE_P_3X3_TXBF_VHT11SS3 = 207, ++ ++ ++ /************ ++ * 4 chains * ++ ************ ++ */ ++ ++ /* 1 Stream expanded + 3 */ ++ WL_RATE_1X4_DSSS_1 = 208, ++ WL_RATE_1X4_DSSS_2 = 209, ++ WL_RATE_1X4_DSSS_5_5 = 210, ++ WL_RATE_1X4_DSSS_11 = 211, ++ ++ WL_RATE_1X4_CDD_OFDM_6 = 212, ++ WL_RATE_1X4_CDD_OFDM_9 = 213, ++ WL_RATE_1X4_CDD_OFDM_12 = 214, ++ WL_RATE_1X4_CDD_OFDM_18 = 215, ++ WL_RATE_1X4_CDD_OFDM_24 = 216, ++ WL_RATE_1X4_CDD_OFDM_36 = 217, ++ WL_RATE_1X4_CDD_OFDM_48 = 218, ++ WL_RATE_1X4_CDD_OFDM_54 = 219, ++ ++ WL_RATE_1X4_CDD_MCS0 = 220, ++ WL_RATE_1X4_CDD_MCS1 = 221, ++ WL_RATE_1X4_CDD_MCS2 = 222, ++ WL_RATE_1X4_CDD_MCS3 = 223, ++ WL_RATE_1X4_CDD_MCS4 = 224, ++ WL_RATE_1X4_CDD_MCS5 = 225, ++ WL_RATE_1X4_CDD_MCS6 = 226, ++ WL_RATE_1X4_CDD_MCS7 = 227, ++ WL_RATE_P_1X4_CDD_MCS87 = 228, ++ WL_RATE_P_1X4_CDD_MCS88 = 229, ++ ++ WL_RATE_1X4_VHT0SS1 = 220, ++ WL_RATE_1X4_VHT1SS1 = 221, ++ WL_RATE_1X4_VHT2SS1 = 222, ++ WL_RATE_1X4_VHT3SS1 = 223, ++ WL_RATE_1X4_VHT4SS1 = 224, ++ WL_RATE_1X4_VHT5SS1 = 225, ++ WL_RATE_1X4_VHT6SS1 = 226, ++ WL_RATE_1X4_VHT7SS1 = 227, ++ WL_RATE_1X4_VHT8SS1 = 228, ++ WL_RATE_1X4_VHT9SS1 = 229, ++ WL_RATE_P_1X4_VHT10SS1 = 230, ++ WL_RATE_P_1X4_VHT11SS1 = 231, ++ ++ /* 2 Streams expanded + 2 */ ++ WL_RATE_2X4_STBC_MCS0 = 232, ++ WL_RATE_2X4_STBC_MCS1 = 233, ++ WL_RATE_2X4_STBC_MCS2 = 234, ++ WL_RATE_2X4_STBC_MCS3 = 235, ++ WL_RATE_2X4_STBC_MCS4 = 236, ++ WL_RATE_2X4_STBC_MCS5 = 237, ++ WL_RATE_2X4_STBC_MCS6 = 238, ++ WL_RATE_2X4_STBC_MCS7 = 239, ++ WL_RATE_P_2X4_STBC_MCS87 = 240, ++ WL_RATE_P_2X4_STBC_MCS88 = 241, ++ ++ WL_RATE_2X4_STBC_VHT0SS1 = 232, ++ WL_RATE_2X4_STBC_VHT1SS1 = 233, ++ WL_RATE_2X4_STBC_VHT2SS1 = 234, ++ WL_RATE_2X4_STBC_VHT3SS1 = 235, ++ WL_RATE_2X4_STBC_VHT4SS1 = 236, ++ WL_RATE_2X4_STBC_VHT5SS1 = 237, ++ WL_RATE_2X4_STBC_VHT6SS1 = 238, ++ WL_RATE_2X4_STBC_VHT7SS1 = 239, ++ WL_RATE_2X4_STBC_VHT8SS1 = 240, ++ WL_RATE_2X4_STBC_VHT9SS1 = 241, ++ WL_RATE_P_2X4_STBC_VHT10SS1 = 242, ++ WL_RATE_P_2X4_STBC_VHT11SS1 = 243, ++ ++ WL_RATE_2X4_SDM_MCS8 = 244, ++ WL_RATE_2X4_SDM_MCS9 = 245, ++ WL_RATE_2X4_SDM_MCS10 = 246, ++ WL_RATE_2X4_SDM_MCS11 = 247, ++ WL_RATE_2X4_SDM_MCS12 = 248, ++ WL_RATE_2X4_SDM_MCS13 = 249, ++ WL_RATE_2X4_SDM_MCS14 = 250, ++ WL_RATE_2X4_SDM_MCS15 = 251, ++ WL_RATE_P_2X4_SDM_MCS99 = 252, ++ WL_RATE_P_2X4_SDM_MCS100 = 253, ++ ++ WL_RATE_2X4_VHT0SS2 = 244, ++ WL_RATE_2X4_VHT1SS2 = 245, ++ WL_RATE_2X4_VHT2SS2 = 246, ++ WL_RATE_2X4_VHT3SS2 = 247, ++ WL_RATE_2X4_VHT4SS2 = 248, ++ WL_RATE_2X4_VHT5SS2 = 249, ++ WL_RATE_2X4_VHT6SS2 = 250, ++ WL_RATE_2X4_VHT7SS2 = 251, ++ WL_RATE_2X4_VHT8SS2 = 252, ++ WL_RATE_2X4_VHT9SS2 = 253, ++ WL_RATE_P_2X4_VHT10SS2 = 254, ++ WL_RATE_P_2X4_VHT11SS2 = 255, ++ ++ /* 3 Streams expanded + 1 */ ++ WL_RATE_3X4_SDM_MCS16 = 256, ++ WL_RATE_3X4_SDM_MCS17 = 257, ++ WL_RATE_3X4_SDM_MCS18 = 258, ++ WL_RATE_3X4_SDM_MCS19 = 259, ++ WL_RATE_3X4_SDM_MCS20 = 260, ++ WL_RATE_3X4_SDM_MCS21 = 261, ++ WL_RATE_3X4_SDM_MCS22 = 262, ++ WL_RATE_3X4_SDM_MCS23 = 263, ++ WL_RATE_P_3X4_SDM_MCS101 = 264, ++ WL_RATE_P_3X4_SDM_MCS102 = 265, ++ ++ WL_RATE_3X4_VHT0SS3 = 256, ++ WL_RATE_3X4_VHT1SS3 = 257, ++ WL_RATE_3X4_VHT2SS3 = 258, ++ WL_RATE_3X4_VHT3SS3 = 259, ++ WL_RATE_3X4_VHT4SS3 = 260, ++ WL_RATE_3X4_VHT5SS3 = 261, ++ WL_RATE_3X4_VHT6SS3 = 262, ++ WL_RATE_3X4_VHT7SS3 = 263, ++ WL_RATE_3X4_VHT8SS3 = 264, ++ WL_RATE_3X4_VHT9SS3 = 265, ++ WL_RATE_P_3X4_VHT10SS3 = 266, ++ WL_RATE_P_3X4_VHT11SS3 = 267, ++ ++ ++ /* 4 Streams */ ++ WL_RATE_4X4_SDM_MCS24 = 268, ++ WL_RATE_4X4_SDM_MCS25 = 269, ++ WL_RATE_4X4_SDM_MCS26 = 270, ++ WL_RATE_4X4_SDM_MCS27 = 271, ++ WL_RATE_4X4_SDM_MCS28 = 272, ++ WL_RATE_4X4_SDM_MCS29 = 273, ++ WL_RATE_4X4_SDM_MCS30 = 274, ++ WL_RATE_4X4_SDM_MCS31 = 275, ++ WL_RATE_P_4X4_SDM_MCS103 = 276, ++ WL_RATE_P_4X4_SDM_MCS104 = 277, ++ ++ WL_RATE_4X4_VHT0SS4 = 268, ++ WL_RATE_4X4_VHT1SS4 = 269, ++ WL_RATE_4X4_VHT2SS4 = 270, ++ WL_RATE_4X4_VHT3SS4 = 271, ++ WL_RATE_4X4_VHT4SS4 = 272, ++ WL_RATE_4X4_VHT5SS4 = 273, ++ WL_RATE_4X4_VHT6SS4 = 274, ++ WL_RATE_4X4_VHT7SS4 = 275, ++ WL_RATE_4X4_VHT8SS4 = 276, ++ WL_RATE_4X4_VHT9SS4 = 277, ++ WL_RATE_P_4X4_VHT10SS4 = 278, ++ WL_RATE_P_4X4_VHT11SS4 = 279, ++ ++ ++ /**************************** ++ * TX Beamforming, 4 chains * ++ **************************** ++ */ ++ ++ /* 1 Stream expanded + 3 */ ++ WL_RATE_1X4_TXBF_OFDM_6 = 280, ++ WL_RATE_1X4_TXBF_OFDM_9 = 281, ++ WL_RATE_1X4_TXBF_OFDM_12 = 282, ++ WL_RATE_1X4_TXBF_OFDM_18 = 283, ++ WL_RATE_1X4_TXBF_OFDM_24 = 284, ++ WL_RATE_1X4_TXBF_OFDM_36 = 285, ++ WL_RATE_1X4_TXBF_OFDM_48 = 286, ++ WL_RATE_1X4_TXBF_OFDM_54 = 287, ++ ++ WL_RATE_1X4_TXBF_MCS0 = 288, ++ WL_RATE_1X4_TXBF_MCS1 = 289, ++ WL_RATE_1X4_TXBF_MCS2 = 290, ++ WL_RATE_1X4_TXBF_MCS3 = 291, ++ WL_RATE_1X4_TXBF_MCS4 = 292, ++ WL_RATE_1X4_TXBF_MCS5 = 293, ++ WL_RATE_1X4_TXBF_MCS6 = 294, ++ WL_RATE_1X4_TXBF_MCS7 = 295, ++ WL_RATE_P_1X4_TXBF_MCS87 = 296, ++ WL_RATE_P_1X4_TXBF_MCS88 = 297, ++ ++ WL_RATE_1X4_TXBF_VHT0SS1 = 288, ++ WL_RATE_1X4_TXBF_VHT1SS1 = 289, ++ WL_RATE_1X4_TXBF_VHT2SS1 = 290, ++ WL_RATE_1X4_TXBF_VHT3SS1 = 291, ++ WL_RATE_1X4_TXBF_VHT4SS1 = 292, ++ WL_RATE_1X4_TXBF_VHT5SS1 = 293, ++ WL_RATE_1X4_TXBF_VHT6SS1 = 294, ++ WL_RATE_1X4_TXBF_VHT7SS1 = 295, ++ WL_RATE_1X4_TXBF_VHT8SS1 = 296, ++ WL_RATE_1X4_TXBF_VHT9SS1 = 297, ++ WL_RATE_P_1X4_TXBF_VHT10SS1 = 298, ++ WL_RATE_P_1X4_TXBF_VHT11SS1 = 299, ++ ++ /* 2 Streams expanded + 2 */ ++ WL_RATE_2X4_TXBF_SDM_MCS8 = 300, ++ WL_RATE_2X4_TXBF_SDM_MCS9 = 301, ++ WL_RATE_2X4_TXBF_SDM_MCS10 = 302, ++ WL_RATE_2X4_TXBF_SDM_MCS11 = 303, ++ WL_RATE_2X4_TXBF_SDM_MCS12 = 304, ++ WL_RATE_2X4_TXBF_SDM_MCS13 = 305, ++ WL_RATE_2X4_TXBF_SDM_MCS14 = 306, ++ WL_RATE_2X4_TXBF_SDM_MCS15 = 307, ++ WL_RATE_P_2X4_TXBF_SDM_MCS99 = 308, ++ WL_RATE_P_2X4_TXBF_SDM_MCS100 = 309, ++ ++ WL_RATE_2X4_TXBF_VHT0SS2 = 300, ++ WL_RATE_2X4_TXBF_VHT1SS2 = 301, ++ WL_RATE_2X4_TXBF_VHT2SS2 = 302, ++ WL_RATE_2X4_TXBF_VHT3SS2 = 303, ++ WL_RATE_2X4_TXBF_VHT4SS2 = 304, ++ WL_RATE_2X4_TXBF_VHT5SS2 = 305, ++ WL_RATE_2X4_TXBF_VHT6SS2 = 306, ++ WL_RATE_2X4_TXBF_VHT7SS2 = 307, ++ WL_RATE_2X4_TXBF_VHT8SS2 = 308, ++ WL_RATE_2X4_TXBF_VHT9SS2 = 309, ++ WL_RATE_P_2X4_TXBF_VHT10SS2 = 310, ++ WL_RATE_P_2X4_TXBF_VHT11SS2 = 311, ++ ++ /* 3 Streams expanded + 1 */ ++ WL_RATE_3X4_TXBF_SDM_MCS16 = 312, ++ WL_RATE_3X4_TXBF_SDM_MCS17 = 313, ++ WL_RATE_3X4_TXBF_SDM_MCS18 = 314, ++ WL_RATE_3X4_TXBF_SDM_MCS19 = 315, ++ WL_RATE_3X4_TXBF_SDM_MCS20 = 316, ++ WL_RATE_3X4_TXBF_SDM_MCS21 = 317, ++ WL_RATE_3X4_TXBF_SDM_MCS22 = 318, ++ WL_RATE_3X4_TXBF_SDM_MCS23 = 319, ++ WL_RATE_P_3X4_TXBF_SDM_MCS101 = 320, ++ WL_RATE_P_3X4_TXBF_SDM_MCS102 = 321, ++ ++ WL_RATE_3X4_TXBF_VHT0SS3 = 312, ++ WL_RATE_3X4_TXBF_VHT1SS3 = 313, ++ WL_RATE_3X4_TXBF_VHT2SS3 = 314, ++ WL_RATE_3X4_TXBF_VHT3SS3 = 315, ++ WL_RATE_3X4_TXBF_VHT4SS3 = 316, ++ WL_RATE_3X4_TXBF_VHT5SS3 = 317, ++ WL_RATE_3X4_TXBF_VHT6SS3 = 318, ++ WL_RATE_3X4_TXBF_VHT7SS3 = 319, ++ WL_RATE_P_3X4_TXBF_VHT8SS3 = 320, ++ WL_RATE_P_3X4_TXBF_VHT9SS3 = 321, ++ WL_RATE_P_3X4_TXBF_VHT10SS3 = 322, ++ WL_RATE_P_3X4_TXBF_VHT11SS3 = 323, ++ ++ /* 4 Streams */ ++ WL_RATE_4X4_TXBF_SDM_MCS24 = 324, ++ WL_RATE_4X4_TXBF_SDM_MCS25 = 325, ++ WL_RATE_4X4_TXBF_SDM_MCS26 = 326, ++ WL_RATE_4X4_TXBF_SDM_MCS27 = 327, ++ WL_RATE_4X4_TXBF_SDM_MCS28 = 328, ++ WL_RATE_4X4_TXBF_SDM_MCS29 = 329, ++ WL_RATE_4X4_TXBF_SDM_MCS30 = 330, ++ WL_RATE_4X4_TXBF_SDM_MCS31 = 331, ++ WL_RATE_P_4X4_TXBF_SDM_MCS103 = 332, ++ WL_RATE_P_4X4_TXBF_SDM_MCS104 = 333, ++ ++ WL_RATE_4X4_TXBF_VHT0SS4 = 324, ++ WL_RATE_4X4_TXBF_VHT1SS4 = 325, ++ WL_RATE_4X4_TXBF_VHT2SS4 = 326, ++ WL_RATE_4X4_TXBF_VHT3SS4 = 327, ++ WL_RATE_4X4_TXBF_VHT4SS4 = 328, ++ WL_RATE_4X4_TXBF_VHT5SS4 = 329, ++ WL_RATE_4X4_TXBF_VHT6SS4 = 330, ++ WL_RATE_4X4_TXBF_VHT7SS4 = 331, ++ WL_RATE_P_4X4_TXBF_VHT8SS4 = 332, ++ WL_RATE_P_4X4_TXBF_VHT9SS4 = 333, ++ WL_RATE_P_4X4_TXBF_VHT10SS4 = 334, ++ WL_RATE_P_4X4_TXBF_VHT11SS4 = 335 ++ ++} clm_rates_t; ++ ++/* Number of rate codes */ ++#define WL_NUMRATES 336 ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif /* _bcmwifi_rates_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/bcmxtlv.c b/module_drivers/drivers/net/wireless/bcmdhd/bcmxtlv.c +new file mode 100644 +index 000000000..d6bef6fa2 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/bcmxtlv.c +@@ -0,0 +1,457 @@ ++/* ++ * Driver O/S-independent utility routines ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmxtlv.c 628611 2016-03-31 17:53:25Z $ ++ */ ++ ++#include ++ ++#include ++#include ++ ++#include ++ ++#ifdef BCMDRIVER ++#include ++#else /* !BCMDRIVER */ ++ #include /* AS!!! */ ++#include ++#include ++#include ++#ifndef ASSERT ++#define ASSERT(exp) ++#endif ++INLINE void* MALLOCZ(void *o, size_t s) { BCM_REFERENCE(o); return calloc(1, s); } ++INLINE void MFREE(void *o, void *p, size_t s) { BCM_REFERENCE(o); BCM_REFERENCE(s); free(p); } ++#endif /* !BCMDRIVER */ ++ ++#include ++#include ++ ++static INLINE int bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts) ++{ ++ return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + BCM_XTLV_HDR_SIZE, 4) ++ : (dlen + BCM_XTLV_HDR_SIZE)); ++} ++ ++bcm_xtlv_t * ++bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts) ++{ ++ int sz; ++ /* advance to next elt */ ++ sz = BCM_XTLV_SIZE(elt, opts); ++ elt = (bcm_xtlv_t*)((uint8 *)elt + sz); ++ *buflen -= sz; ++ ++ /* validate next elt */ ++ if (!bcm_valid_xtlv(elt, *buflen, opts)) ++ return NULL; ++ ++ return elt; ++} ++ ++int ++bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, bcm_xtlv_opts_t opts) ++{ ++ if (!tlv_buf || !buf || !len) ++ return BCME_BADARG; ++ ++ tlv_buf->opts = opts; ++ tlv_buf->size = len; ++ tlv_buf->head = buf; ++ tlv_buf->buf = buf; ++ return BCME_OK; ++} ++ ++uint16 ++bcm_xtlv_buf_len(bcm_xtlvbuf_t *tbuf) ++{ ++ if (tbuf == NULL) return 0; ++ return (uint16)(tbuf->buf - tbuf->head); ++} ++uint16 ++bcm_xtlv_buf_rlen(bcm_xtlvbuf_t *tbuf) ++{ ++ if (tbuf == NULL) return 0; ++ return tbuf->size - bcm_xtlv_buf_len(tbuf); ++} ++uint8 * ++bcm_xtlv_buf(bcm_xtlvbuf_t *tbuf) ++{ ++ if (tbuf == NULL) return NULL; ++ return tbuf->buf; ++} ++uint8 * ++bcm_xtlv_head(bcm_xtlvbuf_t *tbuf) ++{ ++ if (tbuf == NULL) return NULL; ++ return tbuf->head; ++} ++int ++bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const void *data, uint16 dlen) ++{ ++ bcm_xtlv_t *xtlv; ++ int size; ++ ++ if (tbuf == NULL) ++ return BCME_BADARG; ++ size = bcm_xtlv_size_for_data(dlen, tbuf->opts); ++ if (bcm_xtlv_buf_rlen(tbuf) < size) ++ return BCME_NOMEM; ++ xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); ++ xtlv->id = htol16(type); ++ xtlv->len = htol16(dlen); ++ memcpy(xtlv->data, data, dlen); ++ tbuf->buf += size; ++ return BCME_OK; ++} ++int ++bcm_xtlv_put_8(bcm_xtlvbuf_t *tbuf, uint16 type, const int8 data) ++{ ++ bcm_xtlv_t *xtlv; ++ int size; ++ ++ if (tbuf == NULL) ++ return BCME_BADARG; ++ size = bcm_xtlv_size_for_data(1, tbuf->opts); ++ if (bcm_xtlv_buf_rlen(tbuf) < size) ++ return BCME_NOMEM; ++ xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); ++ xtlv->id = htol16(type); ++ xtlv->len = htol16(sizeof(data)); ++ xtlv->data[0] = data; ++ tbuf->buf += size; ++ return BCME_OK; ++} ++int ++bcm_xtlv_put_16(bcm_xtlvbuf_t *tbuf, uint16 type, const int16 data) ++{ ++ bcm_xtlv_t *xtlv; ++ int size; ++ ++ if (tbuf == NULL) ++ return BCME_BADARG; ++ size = bcm_xtlv_size_for_data(2, tbuf->opts); ++ if (bcm_xtlv_buf_rlen(tbuf) < size) ++ return BCME_NOMEM; ++ ++ xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); ++ xtlv->id = htol16(type); ++ xtlv->len = htol16(sizeof(data)); ++ htol16_ua_store(data, xtlv->data); ++ tbuf->buf += size; ++ return BCME_OK; ++} ++int ++bcm_xtlv_put_32(bcm_xtlvbuf_t *tbuf, uint16 type, const int32 data) ++{ ++ bcm_xtlv_t *xtlv; ++ int size; ++ ++ if (tbuf == NULL) ++ return BCME_BADARG; ++ size = bcm_xtlv_size_for_data(4, tbuf->opts); ++ if (bcm_xtlv_buf_rlen(tbuf) < size) ++ return BCME_NOMEM; ++ xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); ++ xtlv->id = htol16(type); ++ xtlv->len = htol16(sizeof(data)); ++ htol32_ua_store(data, xtlv->data); ++ tbuf->buf += size; ++ return BCME_OK; ++} ++ ++/* ++ * upacks xtlv record from buf checks the type ++ * copies data to callers buffer ++ * advances tlv pointer to next record ++ * caller's resposible for dst space check ++ */ ++int ++bcm_unpack_xtlv_entry(uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst, ++ bcm_xtlv_opts_t opts) ++{ ++ bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf; ++ uint16 len; ++ uint16 type; ++ ++ ASSERT(ptlv); ++ /* tlv headr is always packed in LE order */ ++ len = ltoh16(ptlv->len); ++ type = ltoh16(ptlv->id); ++ if (len == 0) { ++ /* z-len tlv headers: allow, but don't process */ ++ printf("z-len, skip unpack\n"); ++ } else { ++ if ((type != xpct_type) || ++ (len > xpct_len)) { ++ printf("xtlv_unpack Error: found[type:%d,len:%d] != xpct[type:%d,len:%d]\n", ++ type, len, xpct_type, xpct_len); ++ return BCME_BADARG; ++ } ++ /* copy tlv record to caller's buffer */ ++ memcpy(dst, ptlv->data, ptlv->len); ++ } ++ *tlv_buf = (uint8*)(*tlv_buf) + BCM_XTLV_SIZE(ptlv, opts); ++ return BCME_OK; ++} ++ ++/* ++ * packs user data into tlv record ++ * advances tlv pointer to next xtlv slot ++ * buflen is used for tlv_buf space check ++ */ ++int ++bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src, ++ bcm_xtlv_opts_t opts) ++{ ++ bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf; ++ int size; ++ ++ ASSERT(ptlv); ++ ASSERT(src); ++ ++ size = bcm_xtlv_size_for_data(len, opts); ++ ++ /* copy data from tlv buffer to dst provided by user */ ++ if (size > *buflen) { ++ printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n", ++ size, *buflen); ++ return BCME_BADLEN; ++ } ++ ptlv->id = htol16(type); ++ ptlv->len = htol16(len); ++ ++ /* copy callers data */ ++ memcpy(ptlv->data, src, len); ++ ++ /* advance callers pointer to tlv buff */ ++ *tlv_buf = (uint8*)(*tlv_buf) + size; ++ /* decrement the len */ ++ *buflen -= (uint16)size; ++ return BCME_OK; ++} ++ ++/* ++ * unpack all xtlv records from the issue a callback ++ * to set function one call per found tlv record ++ */ ++int ++bcm_unpack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, ++ bcm_xtlv_unpack_cbfn_t *cbfn) ++{ ++ uint16 len; ++ uint16 type; ++ int res = BCME_OK; ++ int size; ++ bcm_xtlv_t *ptlv; ++ int sbuflen = buflen; ++ ++ ASSERT(!buflen || tlv_buf); ++ ASSERT(!buflen || cbfn); ++ ++ while (sbuflen >= (int)BCM_XTLV_HDR_SIZE) { ++ ptlv = (bcm_xtlv_t *)tlv_buf; ++ ++ /* tlv header is always packed in LE order */ ++ len = ltoh16(ptlv->len); ++ type = ltoh16(ptlv->id); ++ ++ size = bcm_xtlv_size_for_data(len, opts); ++ ++ sbuflen -= size; ++ /* check for possible buffer overrun */ ++ if (sbuflen < 0) ++ break; ++ ++ if ((res = cbfn(ctx, ptlv->data, type, len)) != BCME_OK) ++ break; ++ tlv_buf = (uint8*)tlv_buf + size; ++ } ++ return res; ++} ++ ++int ++bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, ++ bcm_pack_xtlv_next_info_cbfn_t get_next, bcm_pack_xtlv_pack_next_cbfn_t pack_next, ++ int *outlen) ++{ ++ int res = BCME_OK; ++ uint16 tlv_id; ++ uint16 tlv_len; ++ uint8 *startp; ++ uint8 *endp; ++ uint8 *buf; ++ bool more; ++ int size; ++ ++ ASSERT(get_next && pack_next); ++ ++ buf = (uint8 *)tlv_buf; ++ startp = buf; ++ endp = (uint8 *)buf + buflen; ++ more = TRUE; ++ while (more && (buf < endp)) { ++ more = get_next(ctx, &tlv_id, &tlv_len); ++ size = bcm_xtlv_size_for_data(tlv_len, opts); ++ if ((buf + size) > endp) { ++ res = BCME_BUFTOOSHORT; ++ goto done; ++ } ++ ++ htol16_ua_store(tlv_id, buf); ++ htol16_ua_store(tlv_len, buf + sizeof(tlv_id)); ++ pack_next(ctx, tlv_id, tlv_len, buf + BCM_XTLV_HDR_SIZE); ++ buf += size; ++ } ++ ++ if (more) ++ res = BCME_BUFTOOSHORT; ++ ++done: ++ if (outlen) { ++ *outlen = (int)(buf - startp); ++ } ++ return res; ++} ++ ++/* ++ * pack xtlv buffer from memory according to xtlv_desc_t ++ */ ++int ++bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items, ++ bcm_xtlv_opts_t opts) ++{ ++ int res = BCME_OK; ++ uint8 *ptlv = (uint8 *)*tlv_buf; ++ ++ while (items->type != 0) { ++ if ((items->len > 0) && (res = bcm_pack_xtlv_entry(&ptlv, ++ buflen, items->type, ++ items->len, items->ptr, opts) != BCME_OK)) { ++ break; ++ } ++ items++; ++ } ++ *tlv_buf = ptlv; /* update the external pointer */ ++ return res; ++} ++ ++/* ++ * unpack xtlv buffer to memory according to xtlv_desc_t ++ * ++ */ ++int ++bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items, bcm_xtlv_opts_t opts) ++{ ++ int res = BCME_OK; ++ bcm_xtlv_t *elt; ++ ++ elt = bcm_valid_xtlv((bcm_xtlv_t *)tlv_buf, *buflen, opts) ? (bcm_xtlv_t *)tlv_buf : NULL; ++ if (!elt || !items) { ++ res = BCME_BADARG; ++ return res; ++ } ++ ++ for (; elt != NULL && res == BCME_OK; elt = bcm_next_xtlv(elt, buflen, opts)) { ++ /* find matches in desc_t items */ ++ xtlv_desc_t *dst_desc = items; ++ uint16 len = ltoh16(elt->len); ++ ++ while (dst_desc->type != 0) { ++ if (ltoh16(elt->id) == dst_desc->type) { ++ if (len != dst_desc->len) { ++ res = BCME_BADLEN; ++ } else { ++ memcpy(dst_desc->ptr, elt->data, len); ++ } ++ break; ++ } ++ dst_desc++; ++ } ++ } ++ ++ if (res == BCME_OK && *buflen != 0) ++ res = BCME_BUFTOOSHORT; ++ ++ return res; ++} ++ ++/* ++ * return data pointer of a given ID from xtlv buffer. ++ * If the specified xTLV ID is found, on return *data_len_out will contain ++ * the the data length of the xTLV ID. ++ */ ++void * ++bcm_get_data_from_xtlv_buf(uint8 *tlv_buf, uint16 buflen, uint16 id, ++ uint16 *datalen_out, bcm_xtlv_opts_t opts) ++{ ++ void *retptr = NULL; ++ uint16 type, len; ++ int size; ++ bcm_xtlv_t *ptlv; ++ int sbuflen = buflen; ++ ++ while (sbuflen >= (int)BCM_XTLV_HDR_SIZE) { ++ ptlv = (bcm_xtlv_t *)tlv_buf; ++ ++ /* tlv header is always packed in LE order */ ++ type = ltoh16(ptlv->id); ++ len = ltoh16(ptlv->len); ++ size = bcm_xtlv_size_for_data(len, opts); ++ ++ sbuflen -= size; ++ /* check for possible buffer overrun */ ++ if (sbuflen < 0) { ++ printf("%s %d: Invalid sbuflen %d\n", ++ __FUNCTION__, __LINE__, sbuflen); ++ break; ++ } ++ ++ if (id == type) { ++ retptr = ptlv->data; ++ if (datalen_out) { ++ *datalen_out = len; ++ } ++ break; ++ } ++ tlv_buf += size; ++ } ++ ++ return retptr; ++} ++ ++int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts) ++{ ++ int size; /* entire size of the XTLV including header, data, and optional padding */ ++ int len; /* XTLV's value real length wthout padding */ ++ ++ len = BCM_XTLV_LEN(elt); ++ ++ size = bcm_xtlv_size_for_data(len, opts); ++ ++ return size; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dbus.c b/module_drivers/drivers/net/wireless/bcmdhd/dbus.c +new file mode 100644 +index 000000000..8e2102fe1 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dbus.c +@@ -0,0 +1,2904 @@ ++/** @file dbus.c ++ * ++ * Hides details of USB / SDIO / SPI interfaces and OS details. It is intended to shield details and ++ * provide the caller with one common bus interface for all dongle devices. In practice, it is only ++ * used for USB interfaces. DBUS is not a protocol, but an abstraction layer. ++ * ++ * Copyright (C) 1999-2016, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dbus.c 553311 2015-04-29 10:23:08Z $ ++ */ ++ ++ ++#include "osl.h" ++#include "dbus.h" ++#include ++#include ++#include ++#include ++#ifdef PROP_TXSTATUS /* a form of flow control between host and dongle */ ++#include ++#endif ++#include ++ ++#if defined(BCM_REQUEST_FW) ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++ ++ ++#if defined(BCM_REQUEST_FW) ++#ifndef VARS_MAX ++#define VARS_MAX 8192 ++#endif ++#endif ++ ++#ifdef DBUS_USB_LOOPBACK ++extern bool is_loopback_pkt(void *buf); ++extern int matches_loopback_pkt(void *buf); ++#endif ++ ++/** General info for all BUS types */ ++typedef struct dbus_irbq { ++ dbus_irb_t *head; ++ dbus_irb_t *tail; ++ int cnt; ++} dbus_irbq_t; ++ ++/** ++ * This private structure dhd_bus_t is also declared in dbus_usb_linux.c. ++ * All the fields must be consistent in both declarations. ++ */ ++typedef struct dhd_bus { ++ dbus_pub_t pub; /* MUST BE FIRST */ ++ dhd_pub_t *dhd; ++ ++ void *cbarg; ++ dbus_callbacks_t *cbs; /* callbacks to higher level, e.g. dhd_linux.c */ ++ void *bus_info; ++ dbus_intf_t *drvintf; /* callbacks to lower level, e.g. dbus_usb.c or dbus_usb_linux.c */ ++ uint8 *fw; ++ int fwlen; ++ uint32 errmask; ++ int rx_low_watermark; /* avoid rx overflow by filling rx with free IRBs */ ++ int tx_low_watermark; ++ bool txoff; ++ bool txoverride; /* flow control related */ ++ bool rxoff; ++ bool tx_timer_ticking; ++ ++ ++ dbus_irbq_t *rx_q; ++ dbus_irbq_t *tx_q; ++ ++ uint8 *nvram; ++ int nvram_len; ++ uint8 *image; /* buffer for combine fw and nvram */ ++ int image_len; ++ uint8 *orig_fw; ++ int origfw_len; ++ int decomp_memsize; ++ dbus_extdl_t extdl; ++ int nvram_nontxt; ++#if defined(BCM_REQUEST_FW) ++ void *firmware; ++ void *nvfile; ++#endif ++ char *fw_path; /* module_param: path to firmware image */ ++ char *nv_path; /* module_param: path to nvram vars file */ ++} dhd_bus_t; ++ ++struct exec_parms { ++ union { ++ /* Can consolidate same params, if need be, but this shows ++ * group of parameters per function ++ */ ++ struct { ++ dbus_irbq_t *q; ++ dbus_irb_t *b; ++ } qenq; ++ ++ struct { ++ dbus_irbq_t *q; ++ } qdeq; ++ }; ++}; ++ ++#define EXEC_RXLOCK(info, fn, a) \ ++ info->drvintf->exec_rxlock(dhd_bus->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a)) ++ ++#define EXEC_TXLOCK(info, fn, a) \ ++ info->drvintf->exec_txlock(dhd_bus->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a)) ++ ++/* ++ * Callbacks common for all BUS ++ */ ++static void dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb); ++static void dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status); ++static void dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status); ++static void dbus_if_errhandler(void *handle, int err); ++static void dbus_if_ctl_complete(void *handle, int type, int status); ++static void dbus_if_state_change(void *handle, int state); ++static void *dbus_if_pktget(void *handle, uint len, bool send); ++static void dbus_if_pktfree(void *handle, void *p, bool send); ++static struct dbus_irb *dbus_if_getirb(void *cbarg, bool send); ++static void dbus_if_rxerr_indicate(void *handle, bool on); ++ ++void * dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, ++ uint16 bus_no, uint16 slot, uint32 hdrlen); ++void dhd_dbus_disconnect_cb(void *arg); ++void dbus_detach(dhd_bus_t *pub); ++ ++/** functions in this file that are called by lower DBUS levels, e.g. dbus_usb.c */ ++static dbus_intf_callbacks_t dbus_intf_cbs = { ++ dbus_if_send_irb_timeout, ++ dbus_if_send_irb_complete, ++ dbus_if_recv_irb_complete, ++ dbus_if_errhandler, ++ dbus_if_ctl_complete, ++ dbus_if_state_change, ++ NULL, /* isr */ ++ NULL, /* dpc */ ++ NULL, /* watchdog */ ++ dbus_if_pktget, ++ dbus_if_pktfree, ++ dbus_if_getirb, ++ dbus_if_rxerr_indicate ++}; ++ ++/* ++ * Need global for probe() and disconnect() since ++ * attach() is not called at probe and detach() ++ * can be called inside disconnect() ++ */ ++static dbus_intf_t *g_busintf = NULL; ++static probe_cb_t probe_cb = NULL; ++static disconnect_cb_t disconnect_cb = NULL; ++static void *probe_arg = NULL; ++static void *disc_arg = NULL; ++ ++#if defined(BCM_REQUEST_FW) ++int8 *nonfwnvram = NULL; /* stand-alone multi-nvram given with driver load */ ++int nonfwnvramlen = 0; ++#endif /* #if defined(BCM_REQUEST_FW) */ ++ ++static void* q_enq(dbus_irbq_t *q, dbus_irb_t *b); ++static void* q_enq_exec(struct exec_parms *args); ++static dbus_irb_t*q_deq(dbus_irbq_t *q); ++static void* q_deq_exec(struct exec_parms *args); ++static int dbus_tx_timer_init(dhd_bus_t *dhd_bus); ++static int dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout); ++static int dbus_tx_timer_stop(dhd_bus_t *dhd_bus); ++static int dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size_irb); ++static int dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb); ++static int dbus_rxirbs_fill(dhd_bus_t *dhd_bus); ++static int dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info); ++static void dbus_disconnect(void *handle); ++static void *dbus_probe(void *arg, const char *desc, uint32 bustype, ++ uint16 bus_no, uint16 slot, uint32 hdrlen); ++ ++#if defined(BCM_REQUEST_FW) ++extern char * dngl_firmware; ++extern unsigned int dngl_fwlen; ++#ifndef EXTERNAL_FW_PATH ++static int dbus_get_nvram(dhd_bus_t *dhd_bus); ++static int dbus_jumbo_nvram(dhd_bus_t *dhd_bus); ++static int dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev); ++static int dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen, ++uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len); ++#endif /* !EXTERNAL_FW_PATH */ ++extern int dbus_zlib_decomp(dhd_bus_t *dhd_bus); ++extern void *dbus_zlib_calloc(int num, int size); ++extern void dbus_zlib_free(void *ptr); ++#endif ++ ++/* function */ ++void ++dbus_flowctrl_tx(void *dbi, bool on) ++{ ++ dhd_bus_t *dhd_bus = dbi; ++ ++ if (dhd_bus == NULL) ++ return; ++ ++ DBUSTRACE(("%s on %d\n", __FUNCTION__, on)); ++ ++ if (dhd_bus->txoff == on) ++ return; ++ ++ dhd_bus->txoff = on; ++ ++ if (dhd_bus->cbs && dhd_bus->cbs->txflowcontrol) ++ dhd_bus->cbs->txflowcontrol(dhd_bus->cbarg, on); ++} ++ ++/** ++ * if lower level DBUS signaled a rx error, more free rx IRBs should be allocated or flow control ++ * should kick in to make more free rx IRBs available. ++ */ ++static void ++dbus_if_rxerr_indicate(void *handle, bool on) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; ++ ++ DBUSTRACE(("%s, on %d\n", __FUNCTION__, on)); ++ ++ if (dhd_bus == NULL) ++ return; ++ ++ if (dhd_bus->txoverride == on) ++ return; ++ ++ dhd_bus->txoverride = on; /* flow control */ ++ ++ if (!on) ++ dbus_rxirbs_fill(dhd_bus); ++ ++} ++ ++/** q_enq()/q_deq() are executed with protection via exec_rxlock()/exec_txlock() */ ++static void* ++q_enq(dbus_irbq_t *q, dbus_irb_t *b) ++{ ++ ASSERT(q->tail != b); ++ ASSERT(b->next == NULL); ++ b->next = NULL; ++ if (q->tail) { ++ q->tail->next = b; ++ q->tail = b; ++ } else ++ q->head = q->tail = b; ++ ++ q->cnt++; ++ ++ return b; ++} ++ ++static void* ++q_enq_exec(struct exec_parms *args) ++{ ++ return q_enq(args->qenq.q, args->qenq.b); ++} ++ ++static dbus_irb_t* ++q_deq(dbus_irbq_t *q) ++{ ++ dbus_irb_t *b; ++ ++ b = q->head; ++ if (b) { ++ q->head = q->head->next; ++ b->next = NULL; ++ ++ if (q->head == NULL) ++ q->tail = q->head; ++ ++ q->cnt--; ++ } ++ return b; ++} ++ ++static void* ++q_deq_exec(struct exec_parms *args) ++{ ++ return q_deq(args->qdeq.q); ++} ++ ++/** ++ * called during attach phase. Status @ Dec 2012: this function does nothing since for all of the ++ * lower DBUS levels dhd_bus->drvintf->tx_timer_init is NULL. ++ */ ++static int ++dbus_tx_timer_init(dhd_bus_t *dhd_bus) ++{ ++ if (dhd_bus && dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_init) ++ return dhd_bus->drvintf->tx_timer_init(dhd_bus->bus_info); ++ else ++ return DBUS_ERR; ++} ++ ++static int ++dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout) ++{ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ if (dhd_bus->tx_timer_ticking) ++ return DBUS_OK; ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_start) { ++ if (dhd_bus->drvintf->tx_timer_start(dhd_bus->bus_info, timeout) == DBUS_OK) { ++ dhd_bus->tx_timer_ticking = TRUE; ++ return DBUS_OK; ++ } ++ } ++ ++ return DBUS_ERR; ++} ++ ++static int ++dbus_tx_timer_stop(dhd_bus_t *dhd_bus) ++{ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ if (!dhd_bus->tx_timer_ticking) ++ return DBUS_OK; ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_stop) { ++ if (dhd_bus->drvintf->tx_timer_stop(dhd_bus->bus_info) == DBUS_OK) { ++ dhd_bus->tx_timer_ticking = FALSE; ++ return DBUS_OK; ++ } ++ } ++ ++ return DBUS_ERR; ++} ++ ++/** called during attach phase. */ ++static int ++dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size_irb) ++{ ++ int i; ++ dbus_irb_t *irb; ++ ++ ASSERT(q); ++ ASSERT(dhd_bus); ++ ++ for (i = 0; i < nq; i++) { ++ /* MALLOC dbus_irb_tx or dbus_irb_rx, but cast to simple dbus_irb_t linkedlist */ ++ irb = (dbus_irb_t *) MALLOC(dhd_bus->pub.osh, size_irb); ++ if (irb == NULL) { ++ ASSERT(irb); ++ return DBUS_ERR; ++ } ++ bzero(irb, size_irb); ++ ++ /* q_enq() does not need to go through EXEC_xxLOCK() during init() */ ++ q_enq(q, irb); ++ } ++ ++ return DBUS_OK; ++} ++ ++/** called during detach phase or when attach failed */ ++static int ++dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb) ++{ ++ dbus_irb_t *irb; ++ ++ ASSERT(q); ++ ASSERT(dhd_bus); ++ ++ /* q_deq() does not need to go through EXEC_xxLOCK() ++ * during deinit(); all callbacks are stopped by this time ++ */ ++ while ((irb = q_deq(q)) != NULL) { ++ MFREE(dhd_bus->pub.osh, irb, size_irb); ++ } ++ ++ if (q->cnt) ++ DBUSERR(("deinit: q->cnt=%d > 0\n", q->cnt)); ++ return DBUS_OK; ++} ++ ++/** multiple code paths require the rx queue to be filled with more free IRBs */ ++static int ++dbus_rxirbs_fill(dhd_bus_t *dhd_bus) ++{ ++ int err = DBUS_OK; ++ ++ ++ dbus_irb_rx_t *rxirb; ++ struct exec_parms args; ++ ++ ASSERT(dhd_bus); ++ if (dhd_bus->pub.busstate != DBUS_STATE_UP) { ++ DBUSERR(("dbus_rxirbs_fill: DBUS not up \n")); ++ return DBUS_ERR; ++ } else if (!dhd_bus->drvintf || (dhd_bus->drvintf->recv_irb == NULL)) { ++ /* Lower edge bus interface does not support recv_irb(). ++ * No need to pre-submit IRBs in this case. ++ */ ++ return DBUS_ERR; ++ } ++ ++ /* The dongle recv callback is freerunning without lock. So multiple callbacks(and this ++ * refill) can run in parallel. While the rxoff condition is triggered outside, ++ * below while loop has to check and abort posting more to avoid RPC rxq overflow. ++ */ ++ args.qdeq.q = dhd_bus->rx_q; ++ while ((!dhd_bus->rxoff) && ++ (rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) { ++ err = dhd_bus->drvintf->recv_irb(dhd_bus->bus_info, rxirb); ++ if (err == DBUS_ERR_RXDROP || err == DBUS_ERR_RXFAIL) { ++ /* Add the the free rxirb back to the queue ++ * and wait till later ++ */ ++ bzero(rxirb, sizeof(dbus_irb_rx_t)); ++ args.qenq.q = dhd_bus->rx_q; ++ args.qenq.b = (dbus_irb_t *) rxirb; ++ EXEC_RXLOCK(dhd_bus, q_enq_exec, &args); ++ break; ++ } else if (err != DBUS_OK) { ++ int i = 0; ++ while (i++ < 100) { ++ DBUSERR(("%s :: memory leak for rxirb note?\n", __FUNCTION__)); ++ } ++ } ++ } ++ return err; ++} /* dbus_rxirbs_fill */ ++ ++/** called when the DBUS interface state changed. */ ++void ++dbus_flowctrl_rx(dbus_pub_t *pub, bool on) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ if (dhd_bus == NULL) ++ return; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus->rxoff == on) ++ return; ++ ++ dhd_bus->rxoff = on; ++ ++ if (dhd_bus->pub.busstate == DBUS_STATE_UP) { ++ if (!on) { ++ /* post more irbs, resume rx if necessary */ ++ dbus_rxirbs_fill(dhd_bus); ++ if (dhd_bus && dhd_bus->drvintf->recv_resume) { ++ dhd_bus->drvintf->recv_resume(dhd_bus->bus_info); ++ } ++ } else { ++ /* ??? cancell posted irbs first */ ++ ++ if (dhd_bus && dhd_bus->drvintf->recv_stop) { ++ dhd_bus->drvintf->recv_stop(dhd_bus->bus_info); ++ } ++ } ++ } ++} ++ ++/** ++ * Several code paths in this file want to send a buffer to the dongle. This function handles both ++ * sending of a buffer or a pkt. ++ */ ++static int ++dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int err = DBUS_OK; ++ dbus_irb_tx_t *txirb = NULL; ++ int txirb_pending; ++ struct exec_parms args; ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus->pub.busstate == DBUS_STATE_UP || ++ dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { ++ args.qdeq.q = dhd_bus->tx_q; ++ if (dhd_bus->drvintf) ++ txirb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args); ++ ++ if (txirb == NULL) { ++ DBUSERR(("Out of tx dbus_bufs\n")); ++ return DBUS_ERR; ++ } ++ ++ if (pkt != NULL) { ++ txirb->pkt = pkt; ++ txirb->buf = NULL; ++ txirb->len = 0; ++ } else if (buf != NULL) { ++ txirb->pkt = NULL; ++ txirb->buf = buf; ++ txirb->len = len; ++ } else { ++ ASSERT(0); /* Should not happen */ ++ } ++ txirb->info = info; ++ txirb->arg = NULL; ++ txirb->retry_count = 0; ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->send_irb) { ++ /* call lower DBUS level send_irb function */ ++ err = dhd_bus->drvintf->send_irb(dhd_bus->bus_info, txirb); ++ if (err == DBUS_ERR_TXDROP) { ++ /* tx fail and no completion routine to clean up, reclaim irb NOW */ ++ DBUSERR(("%s: send_irb failed, status = %d\n", __FUNCTION__, err)); ++ bzero(txirb, sizeof(dbus_irb_tx_t)); ++ args.qenq.q = dhd_bus->tx_q; ++ args.qenq.b = (dbus_irb_t *) txirb; ++ EXEC_TXLOCK(dhd_bus, q_enq_exec, &args); ++ } else { ++ dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL); ++ txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt; ++ if (txirb_pending > (dhd_bus->tx_low_watermark * 3)) { ++ dbus_flowctrl_tx(dhd_bus, TRUE); ++ } ++ } ++ } ++ } else { ++ err = DBUS_ERR_TXFAIL; ++ DBUSTRACE(("%s: bus down, send_irb failed\n", __FUNCTION__)); ++ } ++ ++ return err; ++} /* dbus_send_irb */ ++ ++#if defined(BCM_REQUEST_FW) ++ ++/** ++ * Before downloading a firmware image into the dongle, the validity of the image must be checked. ++ */ ++static int ++check_file(osl_t *osh, unsigned char *headers) ++{ ++ struct trx_header *trx; ++ int actual_len = -1; ++ ++ /* Extract trx header */ ++ trx = (struct trx_header *)headers; ++ if (ltoh32(trx->magic) != TRX_MAGIC) { ++ printf("Error: trx bad hdr %x\n", ltoh32(trx->magic)); ++ return -1; ++ } ++ ++ headers += SIZEOF_TRX(trx); ++ ++ /* TRX V1: get firmware len */ ++ /* TRX V2: get firmware len and DSG/CFG lengths */ ++ if (ltoh32(trx->flag_version) & TRX_UNCOMP_IMAGE) { ++ actual_len = ltoh32(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]) + ++ SIZEOF_TRX(trx); ++#ifdef BCMTRXV2 ++ if (ISTRX_V2(trx)) { ++ actual_len += ltoh32(trx->offsets[TRX_OFFSETS_DSG_LEN_IDX]) + ++ ltoh32(trx->offsets[TRX_OFFSETS_CFG_LEN_IDX]); ++ } ++#endif ++ return actual_len; ++ } else { ++ printf("compressed image\n"); ++ } ++ ++ return -1; ++} ++ ++#ifdef EXTERNAL_FW_PATH ++static int ++dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) ++{ ++ int bcmerror = -1, i; ++ uint len, total_len; ++ void *nv_image = NULL, *fw_image = NULL; ++ char *nv_memblock = NULL, *fw_memblock = NULL; ++ char *bufp; ++ bool file_exists; ++ uint8 nvram_words_pad = 0; ++ uint memblock_size = 2048; ++ uint8 *memptr; ++ int actual_fwlen; ++ struct trx_header *hdr; ++ uint32 img_offset = 0; ++ int offset = 0; ++ ++ /* For Get nvram */ ++ file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); ++ if (file_exists) { ++ nv_image = dhd_os_open_image(pnv_path); ++ if (nv_image == NULL) { ++ printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path); ++ goto err; ++ } ++ } ++ nv_memblock = MALLOC(dhd_bus->pub.osh, MAX_NVRAMBUF_SIZE); ++ if (nv_memblock == NULL) { ++ DBUSERR(("%s: Failed to allocate memory %d bytes\n", ++ __FUNCTION__, MAX_NVRAMBUF_SIZE)); ++ goto err; ++ } ++ len = dhd_os_get_image_block(nv_memblock, MAX_NVRAMBUF_SIZE, nv_image); ++ if (len > 0 && len < MAX_NVRAMBUF_SIZE) { ++ bufp = (char *)nv_memblock; ++ bufp[len] = 0; ++ dhd_bus->nvram_len = process_nvram_vars(bufp, len); ++ if (dhd_bus->nvram_len % 4) ++ nvram_words_pad = 4 - dhd_bus->nvram_len % 4; ++ } else { ++ DBUSERR(("%s: error reading nvram file: %d\n", __FUNCTION__, len)); ++ bcmerror = DBUS_ERR_NVRAM; ++ goto err; ++ } ++ if (nv_image) { ++ dhd_os_close_image(nv_image); ++ nv_image = NULL; ++ } ++ ++ /* For Get first block of fw to calculate total_len */ ++ file_exists = ((pfw_path != NULL) && (pfw_path[0] != '\0')); ++ if (file_exists) { ++ fw_image = dhd_os_open_image(pfw_path); ++ if (fw_image == NULL) { ++ printf("%s: Open fw file failed %s\n", __FUNCTION__, pfw_path); ++ goto err; ++ } ++ } ++ memptr = fw_memblock = MALLOC(dhd_bus->pub.osh, memblock_size); ++ if (fw_memblock == NULL) { ++ DBUSERR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, ++ memblock_size)); ++ goto err; ++ } ++ len = dhd_os_get_image_block((char*)memptr, memblock_size, fw_image); ++ if ((actual_fwlen = check_file(dhd_bus->pub.osh, memptr)) <= 0) { ++ DBUSERR(("%s: bad firmware format!\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ total_len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad; ++ dhd_bus->image = MALLOC(dhd_bus->pub.osh, total_len); ++ dhd_bus->image_len = total_len; ++ if (dhd_bus->image == NULL) { ++ DBUSERR(("%s: malloc failed!\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ /* Step1: Copy trx header + firmwre */ ++ memptr = fw_memblock; ++ do { ++ if (len < 0) { ++ DBUSERR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); ++ bcmerror = BCME_ERROR; ++ goto err; ++ } ++ bcopy(memptr, dhd_bus->image+offset, len); ++ offset += len; ++ } while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, fw_image))); ++ /* Step2: Copy NVRAM + pad */ ++ hdr = (struct trx_header *)dhd_bus->image; ++ img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX]; ++ bcopy(nv_memblock, (uint8 *)(dhd_bus->image + img_offset), ++ dhd_bus->nvram_len); ++ img_offset += dhd_bus->nvram_len; ++ if (nvram_words_pad) { ++ bzero(&dhd_bus->image[img_offset], nvram_words_pad); ++ img_offset += nvram_words_pad; ++ } ++#ifdef BCMTRXV2 ++ /* Step3: Copy DSG/CFG for V2 */ ++ if (ISTRX_V2(hdr) && ++ (hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] || ++ hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) { ++ DBUSERR(("%s: fix me\n", __FUNCTION__)); ++ } ++#endif /* BCMTRXV2 */ ++ /* Step4: update TRX header for nvram size */ ++ hdr = (struct trx_header *)dhd_bus->image; ++ hdr->len = htol32(total_len); ++ /* Pass the actual fw len */ ++ hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] = ++ htol32(dhd_bus->nvram_len + nvram_words_pad); ++ /* Calculate CRC over header */ ++ hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version, ++ SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version), ++ CRC32_INIT_VALUE); ++ ++ /* Calculate CRC over data */ ++ for (i = SIZEOF_TRX(hdr); i < total_len; ++i) ++ hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32); ++ hdr->crc32 = htol32(hdr->crc32); ++ ++ bcmerror = DBUS_OK; ++ ++err: ++ if (fw_memblock) ++ MFREE(dhd_bus->pub.osh, fw_memblock, MAX_NVRAMBUF_SIZE); ++ if (fw_image) ++ dhd_os_close_image(fw_image); ++ if (nv_memblock) ++ MFREE(dhd_bus->pub.osh, nv_memblock, MAX_NVRAMBUF_SIZE); ++ if (nv_image) ++ dhd_os_close_image(nv_image); ++ ++ return bcmerror; ++} ++ ++/** ++ * during driver initialization ('attach') or after PnP 'resume', firmware needs to be loaded into ++ * the dongle ++ */ ++static int ++dbus_do_download(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) ++{ ++ int err = DBUS_OK; ++ ++ err = dbus_get_fw_nvram(dhd_bus, pfw_path, pnv_path); ++ if (err) { ++ DBUSERR(("dbus_do_download: fail to get nvram %d\n", err)); ++ return err; ++ } ++ ++ if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) { ++ err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info, ++ dhd_bus->image, dhd_bus->image_len); ++ if (err == DBUS_OK) { ++ err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info); ++ } ++ } else ++ err = DBUS_ERR; ++ ++ if (dhd_bus->image) { ++ MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len); ++ dhd_bus->image = NULL; ++ dhd_bus->image_len = 0; ++ } ++ ++ return err; ++} /* dbus_do_download */ ++#else ++ ++/** ++ * It is easy for the user to pass one jumbo nvram file to the driver than a set of smaller files. ++ * The 'jumbo nvram' file format is essentially a set of nvram files. Before commencing firmware ++ * download, the dongle needs to be probed so that the correct nvram contents within the jumbo nvram ++ * file is selected. ++ */ ++static int ++dbus_jumbo_nvram(dhd_bus_t *dhd_bus) ++{ ++ int8 *nvram = NULL; ++ int nvram_len = 0; ++ int ret = DBUS_OK; ++ uint16 boardrev = 0xFFFF; ++ uint16 boardtype = 0xFFFF; ++ ++ /* read the otp for boardrev & boardtype ++ * if boardtype/rev are present in otp ++ * select nvram data for that boardtype/rev ++ */ ++ dbus_otp(dhd_bus, &boardtype, &boardrev); ++ ++ ret = dbus_select_nvram(dhd_bus, dhd_bus->extdl.vars, dhd_bus->extdl.varslen, ++ boardtype, boardrev, &nvram, &nvram_len); ++ ++ if (ret == DBUS_JUMBO_BAD_FORMAT) ++ return DBUS_ERR_NVRAM; ++ else if (ret == DBUS_JUMBO_NOMATCH && ++ (boardtype != 0xFFFF || boardrev != 0xFFFF)) { ++ DBUSERR(("No matching NVRAM for boardtype 0x%02x boardrev 0x%02x\n", ++ boardtype, boardrev)); ++ return DBUS_ERR_NVRAM; ++ } ++ dhd_bus->nvram = nvram; ++ dhd_bus->nvram_len = nvram_len; ++ ++ return DBUS_OK; ++} ++ ++/** before commencing fw download, the correct NVRAM image to download has to be picked */ ++static int ++dbus_get_nvram(dhd_bus_t *dhd_bus) ++{ ++ int len, i; ++ struct trx_header *hdr; ++ int actual_fwlen; ++ uint32 img_offset = 0; ++ ++ dhd_bus->nvram_len = 0; ++ if (dhd_bus->extdl.varslen) { ++ if (DBUS_OK != dbus_jumbo_nvram(dhd_bus)) ++ return DBUS_ERR_NVRAM; ++ DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len)); ++ } ++#if defined(BCM_REQUEST_FW) ++ else if (nonfwnvram) { ++ dhd_bus->nvram = nonfwnvram; ++ dhd_bus->nvram_len = nonfwnvramlen; ++ DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len)); ++ } ++#endif ++ if (dhd_bus->nvram) { ++ uint8 nvram_words_pad = 0; ++ /* Validate the format/length etc of the file */ ++ if ((actual_fwlen = check_file(dhd_bus->pub.osh, dhd_bus->fw)) <= 0) { ++ DBUSERR(("%s: bad firmware format!\n", __FUNCTION__)); ++ return DBUS_ERR_NVRAM; ++ } ++ ++ if (!dhd_bus->nvram_nontxt) { ++ /* host supplied nvram could be in .txt format ++ * with all the comments etc... ++ */ ++ dhd_bus->nvram_len = process_nvram_vars(dhd_bus->nvram, ++ dhd_bus->nvram_len); ++ } ++ if (dhd_bus->nvram_len % 4) ++ nvram_words_pad = 4 - dhd_bus->nvram_len % 4; ++ ++ len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad; ++ dhd_bus->image = MALLOC(dhd_bus->pub.osh, len); ++ dhd_bus->image_len = len; ++ if (dhd_bus->image == NULL) { ++ DBUSERR(("%s: malloc failed!\n", __FUNCTION__)); ++ return DBUS_ERR_NVRAM; ++ } ++ hdr = (struct trx_header *)dhd_bus->fw; ++ /* Step1: Copy trx header + firmwre */ ++ img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX]; ++ bcopy(dhd_bus->fw, dhd_bus->image, img_offset); ++ /* Step2: Copy NVRAM + pad */ ++ bcopy(dhd_bus->nvram, (uint8 *)(dhd_bus->image + img_offset), ++ dhd_bus->nvram_len); ++ img_offset += dhd_bus->nvram_len; ++ if (nvram_words_pad) { ++ bzero(&dhd_bus->image[img_offset], ++ nvram_words_pad); ++ img_offset += nvram_words_pad; ++ } ++#ifdef BCMTRXV2 ++ /* Step3: Copy DSG/CFG for V2 */ ++ if (ISTRX_V2(hdr) && ++ (hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] || ++ hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) { ++ ++ bcopy(dhd_bus->fw + SIZEOF_TRX(hdr) + ++ hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX] + ++ hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX], ++ dhd_bus->image + img_offset, ++ hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] + ++ hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]); ++ ++ img_offset += hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] + ++ hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]; ++ } ++#endif /* BCMTRXV2 */ ++ /* Step4: update TRX header for nvram size */ ++ hdr = (struct trx_header *)dhd_bus->image; ++ hdr->len = htol32(len); ++ /* Pass the actual fw len */ ++ hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] = ++ htol32(dhd_bus->nvram_len + nvram_words_pad); ++ /* Calculate CRC over header */ ++ hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version, ++ SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version), ++ CRC32_INIT_VALUE); ++ ++ /* Calculate CRC over data */ ++ for (i = SIZEOF_TRX(hdr); i < len; ++i) ++ hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32); ++ hdr->crc32 = htol32(hdr->crc32); ++ } else { ++ dhd_bus->image = dhd_bus->fw; ++ dhd_bus->image_len = (uint32)dhd_bus->fwlen; ++ } ++ ++ return DBUS_OK; ++} /* dbus_get_nvram */ ++ ++/** ++ * during driver initialization ('attach') or after PnP 'resume', firmware needs to be loaded into ++ * the dongle ++ */ ++static int ++dbus_do_download(dhd_bus_t *dhd_bus) ++{ ++ int err = DBUS_OK; ++#ifndef BCM_REQUEST_FW ++ int decomp_override = 0; ++#endif ++#ifdef BCM_REQUEST_FW ++ uint16 boardrev = 0xFFFF, boardtype = 0xFFFF; ++ int8 *temp_nvram; ++ int temp_len; ++#endif ++ ++#if defined(BCM_REQUEST_FW) ++ dhd_bus->firmware = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid, ++ dhd_bus->pub.attrib.chiprev, &dhd_bus->fw, &dhd_bus->fwlen, ++ DBUS_FIRMWARE, 0, 0); ++ if (!dhd_bus->firmware) ++ return DBUS_ERR; ++#endif ++ ++ dhd_bus->image = dhd_bus->fw; ++ dhd_bus->image_len = (uint32)dhd_bus->fwlen; ++ ++#ifndef BCM_REQUEST_FW ++ if (UNZIP_ENAB(dhd_bus) && !decomp_override) { ++ err = dbus_zlib_decomp(dhd_bus); ++ if (err) { ++ DBUSERR(("dbus_attach: fw decompress fail %d\n", err)); ++ return err; ++ } ++ } ++#endif ++ ++#if defined(BCM_REQUEST_FW) ++ /* check if firmware is appended with nvram file */ ++ err = dbus_otp(dhd_bus, &boardtype, &boardrev); ++ /* check if nvram is provided as separte file */ ++ nonfwnvram = NULL; ++ nonfwnvramlen = 0; ++ dhd_bus->nvfile = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid, ++ dhd_bus->pub.attrib.chiprev, (void *)&temp_nvram, &temp_len, ++ DBUS_NVFILE, boardtype, boardrev); ++ if (dhd_bus->nvfile) { ++ int8 *tmp = MALLOC(dhd_bus->pub.osh, temp_len); ++ if (tmp) { ++ bcopy(temp_nvram, tmp, temp_len); ++ nonfwnvram = tmp; ++ nonfwnvramlen = temp_len; ++ } else { ++ err = DBUS_ERR; ++ goto fail; ++ } ++ } ++#endif /* defined(BCM_REQUEST_FW) */ ++ ++ err = dbus_get_nvram(dhd_bus); ++ if (err) { ++ DBUSERR(("dbus_do_download: fail to get nvram %d\n", err)); ++ return err; ++ } ++ ++ ++ if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) { ++ err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info, ++ dhd_bus->image, dhd_bus->image_len); ++ ++ if (err == DBUS_OK) ++ err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info); ++ } else ++ err = DBUS_ERR; ++ ++ if (dhd_bus->nvram) { ++ MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len); ++ dhd_bus->image = dhd_bus->fw; ++ dhd_bus->image_len = (uint32)dhd_bus->fwlen; ++ } ++ ++#ifndef BCM_REQUEST_FW ++ if (UNZIP_ENAB(dhd_bus) && (!decomp_override) && dhd_bus->orig_fw) { ++ MFREE(dhd_bus->pub.osh, dhd_bus->fw, dhd_bus->decomp_memsize); ++ dhd_bus->image = dhd_bus->fw = dhd_bus->orig_fw; ++ dhd_bus->image_len = dhd_bus->fwlen = dhd_bus->origfw_len; ++ } ++#endif ++ ++#if defined(BCM_REQUEST_FW) ++fail: ++ if (dhd_bus->firmware) { ++ dbus_release_fw_nvfile(dhd_bus->firmware); ++ dhd_bus->firmware = NULL; ++ } ++ if (dhd_bus->nvfile) { ++ dbus_release_fw_nvfile(dhd_bus->nvfile); ++ dhd_bus->nvfile = NULL; ++ } ++ if (nonfwnvram) { ++ MFREE(dhd_bus->pub.osh, nonfwnvram, nonfwnvramlen); ++ nonfwnvram = NULL; ++ nonfwnvramlen = 0; ++ } ++#endif ++ return err; ++} /* dbus_do_download */ ++#endif /* EXTERNAL_FW_PATH */ ++#endif ++ ++/** required for DBUS deregistration */ ++static void ++dbus_disconnect(void *handle) ++{ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (disconnect_cb) ++ disconnect_cb(disc_arg); ++} ++ ++/** ++ * This function is called when the sent irb times out without a tx response status. ++ * DBUS adds reliability by resending timed out IRBs DBUS_TX_RETRY_LIMIT times. ++ */ ++static void ++dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; ++ ++ if ((dhd_bus == NULL) || (dhd_bus->drvintf == NULL) || (txirb == NULL)) { ++ return; ++ } ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ return; ++ ++} /* dbus_if_send_irb_timeout */ ++ ++/** ++ * When lower DBUS level signals that a send IRB completed, either successful or not, the higher ++ * level (e.g. dhd_linux.c) has to be notified, and transmit flow control has to be evaluated. ++ */ ++static void BCMFASTPATH ++dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; ++ int txirb_pending; ++ struct exec_parms args; ++ void *pktinfo; ++ ++ if ((dhd_bus == NULL) || (txirb == NULL)) { ++ return; ++ } ++ ++ DBUSTRACE(("%s: status = %d\n", __FUNCTION__, status)); ++ ++ dbus_tx_timer_stop(dhd_bus); ++ ++ /* re-queue BEFORE calling send_complete which will assume that this irb ++ is now available. ++ */ ++ pktinfo = txirb->info; ++ bzero(txirb, sizeof(dbus_irb_tx_t)); ++ args.qenq.q = dhd_bus->tx_q; ++ args.qenq.b = (dbus_irb_t *) txirb; ++ EXEC_TXLOCK(dhd_bus, q_enq_exec, &args); ++ ++ if (dhd_bus->pub.busstate != DBUS_STATE_DOWN) { ++ if ((status == DBUS_OK) || (status == DBUS_ERR_NODEVICE)) { ++ if (dhd_bus->cbs && dhd_bus->cbs->send_complete) ++ dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, ++ status); ++ ++ if (status == DBUS_OK) { ++ txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt; ++ if (txirb_pending) ++ dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL); ++ if ((txirb_pending < dhd_bus->tx_low_watermark) && ++ dhd_bus->txoff && !dhd_bus->txoverride) { ++ dbus_flowctrl_tx(dhd_bus, OFF); ++ } ++ } ++ } else { ++ DBUSERR(("%s: %d WARNING freeing orphan pkt %p\n", __FUNCTION__, __LINE__, ++ pktinfo)); ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC) ++ if (pktinfo) ++ if (dhd_bus->cbs && dhd_bus->cbs->send_complete) ++ dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, ++ status); ++#else ++ dbus_if_pktfree(dhd_bus, (void*)pktinfo, TRUE); ++#endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC) */ ++ } ++ } else { ++ DBUSERR(("%s: %d WARNING freeing orphan pkt %p\n", __FUNCTION__, __LINE__, ++ pktinfo)); ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC) ++ if (pktinfo) ++ if (dhd_bus->cbs && dhd_bus->cbs->send_complete) ++ dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, ++ status); ++#else ++ dbus_if_pktfree(dhd_bus, (void*)pktinfo, TRUE); ++#endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) defined(BCM_RPC_TOC) */ ++ } ++} /* dbus_if_send_irb_complete */ ++ ++/** ++ * When lower DBUS level signals that a receive IRB completed, either successful or not, the higher ++ * level (e.g. dhd_linux.c) has to be notified, and fresh free receive IRBs may have to be given ++ * to lower levels. ++ */ ++static void BCMFASTPATH ++dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; ++ int rxirb_pending; ++ struct exec_parms args; ++ ++ if ((dhd_bus == NULL) || (rxirb == NULL)) { ++ return; ++ } ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ if (dhd_bus->pub.busstate != DBUS_STATE_DOWN && ++ dhd_bus->pub.busstate != DBUS_STATE_SLEEP) { ++ if (status == DBUS_OK) { ++ if ((rxirb->buf != NULL) && (rxirb->actual_len > 0)) { ++#ifdef DBUS_USB_LOOPBACK ++ if (is_loopback_pkt(rxirb->buf)) { ++ matches_loopback_pkt(rxirb->buf); ++ } else ++#endif ++ if (dhd_bus->cbs && dhd_bus->cbs->recv_buf) { ++ dhd_bus->cbs->recv_buf(dhd_bus->cbarg, rxirb->buf, ++ rxirb->actual_len); ++ } ++ } else if (rxirb->pkt != NULL) { ++ if (dhd_bus->cbs && dhd_bus->cbs->recv_pkt) ++ dhd_bus->cbs->recv_pkt(dhd_bus->cbarg, rxirb->pkt); ++ } else { ++ ASSERT(0); /* Should not happen */ ++ } ++ ++ rxirb_pending = dhd_bus->pub.nrxq - dhd_bus->rx_q->cnt - 1; ++ if ((rxirb_pending <= dhd_bus->rx_low_watermark) && ++ !dhd_bus->rxoff) { ++ DBUSTRACE(("Low watermark so submit more %d <= %d \n", ++ dhd_bus->rx_low_watermark, rxirb_pending)); ++ dbus_rxirbs_fill(dhd_bus); ++ } else if (dhd_bus->rxoff) ++ DBUSTRACE(("rx flow controlled. not filling more. cut_rxq=%d\n", ++ dhd_bus->rx_q->cnt)); ++ } else if (status == DBUS_ERR_NODEVICE) { ++ DBUSERR(("%s: %d status = %d, buf %p\n", __FUNCTION__, __LINE__, status, ++ rxirb->buf)); ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) ++ if (rxirb->buf) { ++ PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf); ++ PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE); ++ } ++#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */ ++ } else { ++ if (status != DBUS_ERR_RXZLP) ++ DBUSERR(("%s: %d status = %d, buf %p\n", __FUNCTION__, __LINE__, ++ status, rxirb->buf)); ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) ++ if (rxirb->buf) { ++ PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf); ++ PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE); ++ } ++#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */ ++ } ++ } else { ++ DBUSTRACE(("%s: DBUS down, ignoring recv callback. buf %p\n", __FUNCTION__, ++ rxirb->buf)); ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) ++ if (rxirb->buf) { ++ PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf); ++ PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE); ++ } ++#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */ ++ } ++ if (dhd_bus->rx_q != NULL) { ++ bzero(rxirb, sizeof(dbus_irb_rx_t)); ++ args.qenq.q = dhd_bus->rx_q; ++ args.qenq.b = (dbus_irb_t *) rxirb; ++ EXEC_RXLOCK(dhd_bus, q_enq_exec, &args); ++ } else ++ MFREE(dhd_bus->pub.osh, rxirb, sizeof(dbus_irb_tx_t)); ++} /* dbus_if_recv_irb_complete */ ++ ++/** ++ * Accumulate errors signaled by lower DBUS levels and signal them to higher (e.g. dhd_linux.c) ++ * level. ++ */ ++static void ++dbus_if_errhandler(void *handle, int err) ++{ ++ dhd_bus_t *dhd_bus = handle; ++ uint32 mask = 0; ++ ++ if (dhd_bus == NULL) ++ return; ++ ++ switch (err) { ++ case DBUS_ERR_TXFAIL: ++ dhd_bus->pub.stats.tx_errors++; ++ mask |= ERR_CBMASK_TXFAIL; ++ break; ++ case DBUS_ERR_TXDROP: ++ dhd_bus->pub.stats.tx_dropped++; ++ mask |= ERR_CBMASK_TXFAIL; ++ break; ++ case DBUS_ERR_RXFAIL: ++ dhd_bus->pub.stats.rx_errors++; ++ mask |= ERR_CBMASK_RXFAIL; ++ break; ++ case DBUS_ERR_RXDROP: ++ dhd_bus->pub.stats.rx_dropped++; ++ mask |= ERR_CBMASK_RXFAIL; ++ break; ++ default: ++ break; ++ } ++ ++ if (dhd_bus->cbs && dhd_bus->cbs->errhandler && (dhd_bus->errmask & mask)) ++ dhd_bus->cbs->errhandler(dhd_bus->cbarg, err); ++} ++ ++/** ++ * When lower DBUS level signals control IRB completed, higher level (e.g. dhd_linux.c) has to be ++ * notified. ++ */ ++static void ++dbus_if_ctl_complete(void *handle, int type, int status) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus == NULL) { ++ DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (dhd_bus->pub.busstate != DBUS_STATE_DOWN) { ++ if (dhd_bus->cbs && dhd_bus->cbs->ctl_complete) ++ dhd_bus->cbs->ctl_complete(dhd_bus->cbarg, type, status); ++ } ++} ++ ++/** ++ * Rx related functionality (flow control, posting of free IRBs to rx queue) is dependent upon the ++ * bus state. When lower DBUS level signals a change in the interface state, take appropriate action ++ * and forward the signaling to the higher (e.g. dhd_linux.c) level. ++ */ ++static void ++dbus_if_state_change(void *handle, int state) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; ++ int old_state; ++ ++ if (dhd_bus == NULL) ++ return; ++ ++ if (dhd_bus->pub.busstate == state) ++ return; ++ old_state = dhd_bus->pub.busstate; ++ if (state == DBUS_STATE_DISCONNECT) { ++ DBUSERR(("DBUS disconnected\n")); ++ } ++ ++ /* Ignore USB SUSPEND while not up yet */ ++ if (state == DBUS_STATE_SLEEP && old_state != DBUS_STATE_UP) ++ return; ++ ++ DBUSTRACE(("dbus state change from %d to to %d\n", old_state, state)); ++ ++ /* Don't update state if it's PnP firmware re-download */ ++ if (state != DBUS_STATE_PNP_FWDL) ++ dhd_bus->pub.busstate = state; ++ else ++ dbus_flowctrl_rx(handle, FALSE); ++ if (state == DBUS_STATE_SLEEP) ++ dbus_flowctrl_rx(handle, TRUE); ++ if (state == DBUS_STATE_UP) { ++ dbus_rxirbs_fill(dhd_bus); ++ dbus_flowctrl_rx(handle, FALSE); ++ } ++ ++ if (dhd_bus->cbs && dhd_bus->cbs->state_change) ++ dhd_bus->cbs->state_change(dhd_bus->cbarg, state); ++} ++ ++/** Forward request for packet from lower DBUS layer to higher layer (e.g. dhd_linux.c) */ ++static void * ++dbus_if_pktget(void *handle, uint len, bool send) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; ++ void *p = NULL; ++ ++ if (dhd_bus == NULL) ++ return NULL; ++ ++ if (dhd_bus->cbs && dhd_bus->cbs->pktget) ++ p = dhd_bus->cbs->pktget(dhd_bus->cbarg, len, send); ++ else ++ ASSERT(0); ++ ++ return p; ++} ++ ++/** Forward request to free packet from lower DBUS layer to higher layer (e.g. dhd_linux.c) */ ++static void ++dbus_if_pktfree(void *handle, void *p, bool send) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; ++ ++ if (dhd_bus == NULL) ++ return; ++ ++ if (dhd_bus->cbs && dhd_bus->cbs->pktfree) ++ dhd_bus->cbs->pktfree(dhd_bus->cbarg, p, send); ++ else ++ ASSERT(0); ++} ++ ++/** Lower DBUS level requests either a send or receive IRB */ ++static struct dbus_irb* ++dbus_if_getirb(void *cbarg, bool send) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) cbarg; ++ struct exec_parms args; ++ struct dbus_irb *irb; ++ ++ if ((dhd_bus == NULL) || (dhd_bus->pub.busstate != DBUS_STATE_UP)) ++ return NULL; ++ ++ if (send == TRUE) { ++ args.qdeq.q = dhd_bus->tx_q; ++ irb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args); ++ } else { ++ args.qdeq.q = dhd_bus->rx_q; ++ irb = EXEC_RXLOCK(dhd_bus, q_deq_exec, &args); ++ } ++ ++ return irb; ++} ++ ++/** ++ * Called as part of DBUS bus registration. Calls back into higher level (e.g. dhd_linux.c) probe ++ * function. ++ */ ++static void * ++dbus_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, ++ uint16 slot, uint32 hdrlen) ++{ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ if (probe_cb) { ++ disc_arg = probe_cb(probe_arg, desc, bustype, bus_no, slot, hdrlen); ++ return disc_arg; ++ } ++ ++ return (void *)DBUS_ERR; ++} ++ ++/** ++ * As part of initialization, higher level (e.g. dhd_linux.c) requests DBUS to prepare for ++ * action. ++ */ ++int ++dhd_bus_register(void) ++{ ++ int err; ++ ++ DBUSTRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ probe_cb = dhd_dbus_probe_cb; ++ disconnect_cb = dhd_dbus_disconnect_cb; ++ probe_arg = NULL; ++ ++ err = dbus_bus_register(0xa5c, 0x48f, dbus_probe, /* call lower DBUS level register function */ ++ dbus_disconnect, NULL, &g_busintf, NULL, NULL); ++ ++ /* Device not detected */ ++ if (err == DBUS_ERR_NODEVICE) ++ err = DBUS_OK; ++ ++ return err; ++} ++ ++dhd_pub_t *g_pub = NULL; ++void ++dhd_bus_unregister(void) ++{ ++ int ret; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ DHD_MUTEX_LOCK(); ++ if (g_pub) { ++ g_pub->dhd_remove = TRUE; ++ if (!g_pub->bus) { ++ dhd_dbus_disconnect_cb(g_pub->bus); ++ } ++ } ++ probe_cb = NULL; ++ DHD_MUTEX_UNLOCK(); ++ ret = dbus_bus_deregister(); ++ disconnect_cb = NULL; ++ probe_arg = NULL; ++} ++ ++/** As part of initialization, data structures have to be allocated and initialized */ ++dhd_bus_t * ++dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, dhd_pub_t *pub, ++ dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh) ++{ ++ dhd_bus_t *dhd_bus; ++ int err; ++ ++ if ((g_busintf == NULL) || (g_busintf->attach == NULL) || (cbs == NULL)) ++ return NULL; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if ((nrxq <= 0) || (ntxq <= 0)) ++ return NULL; ++ ++ dhd_bus = MALLOC(osh, sizeof(dhd_bus_t)); ++ if (dhd_bus == NULL) { ++ DBUSERR(("%s: malloc failed %zu\n", __FUNCTION__, sizeof(dhd_bus_t))); ++ return NULL; ++ } ++ ++ bzero(dhd_bus, sizeof(dhd_bus_t)); ++ ++ /* BUS-specific driver interface (at a lower DBUS level) */ ++ dhd_bus->drvintf = g_busintf; ++ dhd_bus->cbarg = pub; ++ dhd_bus->cbs = cbs; ++ ++ dhd_bus->pub.sh = sh; ++ dhd_bus->pub.osh = osh; ++ dhd_bus->pub.rxsize = rxsize; ++ ++ dhd_bus->pub.nrxq = nrxq; ++ dhd_bus->rx_low_watermark = nrxq / 2; /* keep enough posted rx urbs */ ++ dhd_bus->pub.ntxq = ntxq; ++ dhd_bus->tx_low_watermark = ntxq / 4; /* flow control when too many tx urbs posted */ ++ ++ dhd_bus->tx_q = MALLOC(osh, sizeof(dbus_irbq_t)); ++ if (dhd_bus->tx_q == NULL) ++ goto error; ++ else { ++ bzero(dhd_bus->tx_q, sizeof(dbus_irbq_t)); ++ err = dbus_irbq_init(dhd_bus, dhd_bus->tx_q, ntxq, sizeof(dbus_irb_tx_t)); ++ if (err != DBUS_OK) ++ goto error; ++ } ++ ++ dhd_bus->rx_q = MALLOC(osh, sizeof(dbus_irbq_t)); ++ if (dhd_bus->rx_q == NULL) ++ goto error; ++ else { ++ bzero(dhd_bus->rx_q, sizeof(dbus_irbq_t)); ++ err = dbus_irbq_init(dhd_bus, dhd_bus->rx_q, nrxq, sizeof(dbus_irb_rx_t)); ++ if (err != DBUS_OK) ++ goto error; ++ } ++ ++ ++ dhd_bus->bus_info = (void *)g_busintf->attach(&dhd_bus->pub, ++ dhd_bus, &dbus_intf_cbs); ++ if (dhd_bus->bus_info == NULL) ++ goto error; ++ ++ dbus_tx_timer_init(dhd_bus); ++ ++#if defined(BCM_REQUEST_FW) ++ /* Need to copy external image for re-download */ ++ if (extdl && extdl->fw && (extdl->fwlen > 0)) { ++ dhd_bus->extdl.fw = MALLOC(osh, extdl->fwlen); ++ if (dhd_bus->extdl.fw) { ++ bcopy(extdl->fw, dhd_bus->extdl.fw, extdl->fwlen); ++ dhd_bus->extdl.fwlen = extdl->fwlen; ++ } ++ } ++ ++ if (extdl && extdl->vars && (extdl->varslen > 0)) { ++ dhd_bus->extdl.vars = MALLOC(osh, extdl->varslen); ++ if (dhd_bus->extdl.vars) { ++ bcopy(extdl->vars, dhd_bus->extdl.vars, extdl->varslen); ++ dhd_bus->extdl.varslen = extdl->varslen; ++ } ++ } ++#endif ++ ++ return (dhd_bus_t *)dhd_bus; ++ ++error: ++ DBUSERR(("%s: Failed\n", __FUNCTION__)); ++ dbus_detach(dhd_bus); ++ return NULL; ++} /* dbus_attach */ ++ ++void ++dbus_detach(dhd_bus_t *pub) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ osl_t *osh; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus == NULL) ++ return; ++ ++ dbus_tx_timer_stop(dhd_bus); ++ ++ osh = pub->pub.osh; ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->detach) ++ dhd_bus->drvintf->detach((dbus_pub_t *)dhd_bus, dhd_bus->bus_info); ++ ++ if (dhd_bus->tx_q) { ++ dbus_irbq_deinit(dhd_bus, dhd_bus->tx_q, sizeof(dbus_irb_tx_t)); ++ MFREE(osh, dhd_bus->tx_q, sizeof(dbus_irbq_t)); ++ dhd_bus->tx_q = NULL; ++ } ++ ++ if (dhd_bus->rx_q) { ++ dbus_irbq_deinit(dhd_bus, dhd_bus->rx_q, sizeof(dbus_irb_rx_t)); ++ MFREE(osh, dhd_bus->rx_q, sizeof(dbus_irbq_t)); ++ dhd_bus->rx_q = NULL; ++ } ++ ++ ++ if (dhd_bus->extdl.fw && (dhd_bus->extdl.fwlen > 0)) { ++ MFREE(osh, dhd_bus->extdl.fw, dhd_bus->extdl.fwlen); ++ dhd_bus->extdl.fw = NULL; ++ dhd_bus->extdl.fwlen = 0; ++ } ++ ++ if (dhd_bus->extdl.vars && (dhd_bus->extdl.varslen > 0)) { ++ MFREE(osh, dhd_bus->extdl.vars, dhd_bus->extdl.varslen); ++ dhd_bus->extdl.vars = NULL; ++ dhd_bus->extdl.varslen = 0; ++ } ++ ++ MFREE(osh, dhd_bus, sizeof(dhd_bus_t)); ++} /* dbus_detach */ ++ ++int dbus_dlneeded(dhd_bus_t *pub) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int dlneeded = DBUS_ERR; ++ ++ if (!dhd_bus) { ++ DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); ++ return DBUS_ERR; ++ } ++ ++ DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate)); ++ ++ if (dhd_bus->drvintf->dlneeded) { ++ dlneeded = dhd_bus->drvintf->dlneeded(dhd_bus->bus_info); ++ } ++ printf("%s: dlneeded=%d\n", __FUNCTION__, dlneeded); ++ ++ /* dlneeded > 0: need to download ++ * dlneeded = 0: downloaded ++ * dlneeded < 0: bus error*/ ++ return dlneeded; ++} ++ ++#if defined(BCM_REQUEST_FW) ++int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int err = DBUS_OK; ++ ++ if (!dhd_bus) { ++ DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); ++ return DBUS_ERR; ++ } ++ ++ DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate)); ++ ++ dhd_bus->pub.busstate = DBUS_STATE_DL_PENDING; ++#ifdef EXTERNAL_FW_PATH ++ err = dbus_do_download(dhd_bus, pfw_path, pnv_path); ++#else ++ err = dbus_do_download(dhd_bus); ++#endif /* EXTERNAL_FW_PATH */ ++ if (err == DBUS_OK) { ++ dhd_bus->pub.busstate = DBUS_STATE_DL_DONE; ++ } else { ++ DBUSERR(("%s: download failed (%d)\n", __FUNCTION__, err)); ++ } ++ ++ return err; ++} ++#endif ++ ++/** ++ * higher layer requests us to 'up' the interface to the dongle. Prerequisite is that firmware (not ++ * bootloader) must be active in the dongle. ++ */ ++int ++dbus_up(struct dhd_bus *pub) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int err = DBUS_OK; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus == NULL) { ++ DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); ++ return DBUS_ERR; ++ } ++ ++ if ((dhd_bus->pub.busstate == DBUS_STATE_DL_DONE) || ++ (dhd_bus->pub.busstate == DBUS_STATE_DOWN) || ++ (dhd_bus->pub.busstate == DBUS_STATE_SLEEP)) { ++ if (dhd_bus->drvintf && dhd_bus->drvintf->up) { ++ err = dhd_bus->drvintf->up(dhd_bus->bus_info); ++ ++ if (err == DBUS_OK) { ++ dbus_rxirbs_fill(dhd_bus); ++ } ++ } ++ } else ++ err = DBUS_ERR; ++ ++ return err; ++} ++ ++/** higher layer requests us to 'down' the interface to the dongle. */ ++int ++dbus_down(dbus_pub_t *pub) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ dbus_tx_timer_stop(dhd_bus); ++ ++ if (dhd_bus->pub.busstate == DBUS_STATE_UP || ++ dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { ++ if (dhd_bus->drvintf && dhd_bus->drvintf->down) ++ return dhd_bus->drvintf->down(dhd_bus->bus_info); ++ } ++ ++ return DBUS_ERR; ++} ++ ++int ++dbus_shutdown(dbus_pub_t *pub) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->shutdown) ++ return dhd_bus->drvintf->shutdown(dhd_bus->bus_info); ++ ++ return DBUS_OK; ++} ++ ++int ++dbus_stop(struct dhd_bus *pub) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ if (dhd_bus->pub.busstate == DBUS_STATE_UP || ++ dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { ++ if (dhd_bus->drvintf && dhd_bus->drvintf->stop) ++ return dhd_bus->drvintf->stop(dhd_bus->bus_info); ++ } ++ ++ return DBUS_ERR; ++} ++ ++int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf) ++{ ++ return dbus_send_pkt(dbus, pktbuf, pktbuf /* pktinfo */); ++} ++ ++int ++dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info) ++{ ++ return dbus_send_irb(pub, buf, len, NULL, info); ++} ++ ++int ++dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info) ++{ ++ return dbus_send_irb(pub, NULL, 0, pkt, info); ++} ++ ++int ++dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ if (dhd_bus == NULL) { ++ DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); ++ return DBUS_ERR; ++ } ++ ++ if (dhd_bus->pub.busstate == DBUS_STATE_UP || ++ dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { ++ if (dhd_bus->drvintf && dhd_bus->drvintf->send_ctl) ++ return dhd_bus->drvintf->send_ctl(dhd_bus->bus_info, buf, len); ++ } else { ++ DBUSERR(("%s: bustate=%d\n", __FUNCTION__, dhd_bus->pub.busstate)); ++ } ++ ++ return DBUS_ERR; ++} ++ ++int ++dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ if ((dhd_bus == NULL) || (buf == NULL)) ++ return DBUS_ERR; ++ ++ if (dhd_bus->pub.busstate == DBUS_STATE_UP || ++ dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { ++ if (dhd_bus->drvintf && dhd_bus->drvintf->recv_ctl) ++ return dhd_bus->drvintf->recv_ctl(dhd_bus->bus_info, buf, len); ++ } ++ ++ return DBUS_ERR; ++} ++ ++/** Only called via RPC (Dec 2012) */ ++int ++dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ dbus_irb_rx_t *rxirb; ++ struct exec_parms args; ++ int status; ++ ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ args.qdeq.q = dhd_bus->rx_q; ++ if (dhd_bus->pub.busstate == DBUS_STATE_UP) { ++ if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) { ++ if ((rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) { ++ status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info, ++ rxirb, ep_idx); ++ if (status == DBUS_ERR_RXDROP) { ++ bzero(rxirb, sizeof(dbus_irb_rx_t)); ++ args.qenq.q = dhd_bus->rx_q; ++ args.qenq.b = (dbus_irb_t *) rxirb; ++ EXEC_RXLOCK(dhd_bus, q_enq_exec, &args); ++ } ++ } ++ } ++ } ++ ++ return DBUS_ERR; ++} ++ ++/** only called by dhd_cdc.c (Dec 2012) */ ++int ++dbus_poll_intr(dbus_pub_t *pub) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ int status = DBUS_ERR; ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ if (dhd_bus->pub.busstate == DBUS_STATE_UP) { ++ if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) { ++ status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info, ++ NULL, 0xff); ++ } ++ } ++ return status; ++} ++ ++/** called by nobody (Dec 2012) */ ++void * ++dbus_pktget(dbus_pub_t *pub, int len) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ if ((dhd_bus == NULL) || (len < 0)) ++ return NULL; ++ ++ return PKTGET(dhd_bus->pub.osh, len, TRUE); ++} ++ ++/** called by nobody (Dec 2012) */ ++void ++dbus_pktfree(dbus_pub_t *pub, void* pkt) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ if ((dhd_bus == NULL) || (pkt == NULL)) ++ return; ++ ++ PKTFREE(dhd_bus->pub.osh, pkt, TRUE); ++} ++ ++/** called by nobody (Dec 2012) */ ++int ++dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ if ((dhd_bus == NULL) || (stats == NULL)) ++ return DBUS_ERR; ++ ++ bcopy(&dhd_bus->pub.stats, stats, sizeof(dbus_stats_t)); ++ ++ return DBUS_OK; ++} ++ ++int ++dbus_get_attrib(dhd_bus_t *pub, dbus_attrib_t *attrib) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int err = DBUS_ERR; ++ ++ if ((dhd_bus == NULL) || (attrib == NULL)) ++ return DBUS_ERR; ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->get_attrib) { ++ err = dhd_bus->drvintf->get_attrib(dhd_bus->bus_info, ++ &dhd_bus->pub.attrib); ++ } ++ ++ bcopy(&dhd_bus->pub.attrib, attrib, sizeof(dbus_attrib_t)); ++ return err; ++} ++ ++int ++dbus_get_device_speed(dbus_pub_t *pub) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ ++ if (dhd_bus == NULL) ++ return INVALID_SPEED; ++ ++ return (dhd_bus->pub.device_speed); ++} ++ ++int ++dbus_set_config(dbus_pub_t *pub, dbus_config_t *config) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int err = DBUS_ERR; ++ ++ if ((dhd_bus == NULL) || (config == NULL)) ++ return DBUS_ERR; ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->set_config) { ++ err = dhd_bus->drvintf->set_config(dhd_bus->bus_info, ++ config); ++ ++ if ((config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) && ++ (!err) && ++ (dhd_bus->pub.busstate == DBUS_STATE_UP)) { ++ dbus_rxirbs_fill(dhd_bus); ++ } ++ } ++ ++ return err; ++} ++ ++int ++dbus_get_config(dbus_pub_t *pub, dbus_config_t *config) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int err = DBUS_ERR; ++ ++ if ((dhd_bus == NULL) || (config == NULL)) ++ return DBUS_ERR; ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->get_config) { ++ err = dhd_bus->drvintf->get_config(dhd_bus->bus_info, ++ config); ++ } ++ ++ return err; ++} ++ ++int ++dbus_set_errmask(dbus_pub_t *pub, uint32 mask) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int err = DBUS_OK; ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ dhd_bus->errmask = mask; ++ return err; ++} ++ ++int ++dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int err = DBUS_ERR; ++ bool fwdl = FALSE; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ if (dhd_bus->pub.busstate == DBUS_STATE_UP) { ++ return DBUS_OK; ++ } ++ ++ ++ ++ if (dhd_bus->drvintf->pnp) { ++ err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, ++ DBUS_PNP_RESUME); ++ } ++ ++ if (dhd_bus->drvintf->recv_needed) { ++ if (dhd_bus->drvintf->recv_needed(dhd_bus->bus_info)) { ++ /* Refill after sleep/hibernate */ ++ dbus_rxirbs_fill(dhd_bus); ++ } ++ } ++ ++ ++ if (fw_reload) ++ *fw_reload = fwdl; ++ ++ return err; ++} /* dbus_pnp_resume */ ++ ++int ++dbus_pnp_sleep(dbus_pub_t *pub) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int err = DBUS_ERR; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ dbus_tx_timer_stop(dhd_bus); ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) { ++ err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, ++ DBUS_PNP_SLEEP); ++ } ++ ++ return err; ++} ++ ++int ++dbus_pnp_disconnect(dbus_pub_t *pub) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; ++ int err = DBUS_ERR; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ dbus_tx_timer_stop(dhd_bus); ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) { ++ err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, ++ DBUS_PNP_DISCONNECT); ++ } ++ ++ return err; ++} ++ ++int ++dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ dhd_bus_t *dhd_bus = (dhd_bus_t *) dhdp->bus; ++ int err = DBUS_ERR; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (dhd_bus == NULL) ++ return DBUS_ERR; ++ ++ if (dhd_bus->drvintf && dhd_bus->drvintf->iovar_op) { ++ err = dhd_bus->drvintf->iovar_op(dhd_bus->bus_info, ++ name, params, plen, arg, len, set); ++ } ++ ++ return err; ++} ++ ++ ++void * ++dhd_dbus_txq(const dbus_pub_t *pub) ++{ ++ return NULL; ++} ++ ++uint ++dhd_dbus_hdrlen(const dbus_pub_t *pub) ++{ ++ return 0; ++} ++ ++void * ++dbus_get_devinfo(dbus_pub_t *pub) ++{ ++ return pub->dev_info; ++} ++ ++#if defined(BCM_REQUEST_FW) && !defined(EXTERNAL_FW_PATH) ++static int ++dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev) ++{ ++ uint32 value = 0; ++ uint8 *cis; ++ uint16 *otpinfo; ++ uint32 i; ++ bool standard_cis = TRUE; ++ uint8 tup, tlen; ++ bool btype_present = FALSE; ++ bool brev_present = FALSE; ++ int ret; ++ int devid; ++ uint16 btype = 0; ++ uint16 brev = 0; ++ uint32 otp_size = 0, otp_addr = 0, otp_sw_rgn = 0; ++ ++ if (dhd_bus == NULL || dhd_bus->drvintf == NULL || ++ dhd_bus->drvintf->readreg == NULL) ++ return DBUS_ERR; ++ ++ devid = dhd_bus->pub.attrib.devid; ++ ++ if ((devid == BCM43234_CHIP_ID) || (devid == BCM43235_CHIP_ID) || ++ (devid == BCM43236_CHIP_ID)) { ++ ++ otp_size = BCM_OTP_SIZE_43236; ++ otp_sw_rgn = BCM_OTP_SW_RGN_43236; ++ otp_addr = BCM_OTP_ADDR_43236; ++ ++ } else { ++ return DBUS_ERR_NVRAM; ++ } ++ ++ cis = MALLOC(dhd_bus->pub.osh, otp_size * 2); ++ if (cis == NULL) ++ return DBUS_ERR; ++ ++ otpinfo = (uint16 *) cis; ++ ++ for (i = 0; i < otp_size; i++) { ++ ++ ret = dhd_bus->drvintf->readreg(dhd_bus->bus_info, ++ otp_addr + ((otp_sw_rgn + i) << 1), 2, &value); ++ ++ if (ret != DBUS_OK) { ++ MFREE(dhd_bus->pub.osh, cis, otp_size * 2); ++ return ret; ++ } ++ otpinfo[i] = (uint16) value; ++ } ++ ++ for (i = 0; i < (otp_size << 1); ) { ++ ++ if (standard_cis) { ++ tup = cis[i++]; ++ if (tup == CISTPL_NULL || tup == CISTPL_END) ++ tlen = 0; ++ else ++ tlen = cis[i++]; ++ } else { ++ if (cis[i] == CISTPL_NULL || cis[i] == CISTPL_END) { ++ tlen = 0; ++ tup = cis[i]; ++ } else { ++ tlen = cis[i]; ++ tup = CISTPL_BRCM_HNBU; ++ } ++ ++i; ++ } ++ ++ if (tup == CISTPL_END || (i + tlen) >= (otp_size << 1)) { ++ break; ++ } ++ ++ switch (tup) { ++ ++ case CISTPL_BRCM_HNBU: ++ ++ switch (cis[i]) { ++ ++ case HNBU_BOARDTYPE: ++ ++ btype = (uint16) ((cis[i + 2] << 8) + cis[i + 1]); ++ btype_present = TRUE; ++ DBUSTRACE(("%s: HNBU_BOARDTYPE = 0x%2x\n", __FUNCTION__, ++ (uint32)btype)); ++ break; ++ ++ case HNBU_BOARDREV: ++ ++ if (tlen == 2) ++ brev = (uint16) cis[i + 1]; ++ else ++ brev = (uint16) ((cis[i + 2] << 8) + cis[i + 1]); ++ brev_present = TRUE; ++ DBUSTRACE(("%s: HNBU_BOARDREV = 0x%2x\n", __FUNCTION__, ++ (uint32)*boardrev)); ++ break; ++ ++ case HNBU_HNBUCIS: ++ DBUSTRACE(("%s: HNBU_HNBUCIS\n", __FUNCTION__)); ++ tlen++; ++ standard_cis = FALSE; ++ break; ++ } ++ break; ++ } ++ ++ i += tlen; ++ } ++ ++ MFREE(dhd_bus->pub.osh, cis, otp_size * 2); ++ ++ if (btype_present == TRUE && brev_present == TRUE) { ++ *boardtype = btype; ++ *boardrev = brev; ++ DBUSERR(("otp boardtype = 0x%2x boardrev = 0x%2x\n", ++ *boardtype, *boardrev)); ++ ++ return DBUS_OK; ++ } ++ else ++ return DBUS_ERR; ++} /* dbus_otp */ ++ ++static int ++dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen, ++uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len) ++{ ++ /* Multi board nvram file format is contenation of nvram info with \r ++ * The file format for two contatenated set is ++ * \nBroadcom Jumbo Nvram file\nfirst_set\nsecond_set\nthird_set\n ++ */ ++ uint8 *nvram_start = NULL, *nvram_end = NULL; ++ uint8 *nvram_start_prev = NULL, *nvram_end_prev = NULL; ++ uint16 btype = 0, brev = 0; ++ int len = 0; ++ char *field; ++ ++ *nvram = NULL; ++ *nvram_len = 0; ++ ++ if (strncmp(BCM_JUMBO_START, jumbonvram, strlen(BCM_JUMBO_START))) { ++ /* single nvram file in the native format */ ++ DBUSTRACE(("%s: Non-Jumbo NVRAM File \n", __FUNCTION__)); ++ *nvram = jumbonvram; ++ *nvram_len = jumbolen; ++ return DBUS_OK; ++ } else { ++ DBUSTRACE(("%s: Jumbo NVRAM File \n", __FUNCTION__)); ++ } ++ ++ /* sanity test the end of the config sets for proper ending */ ++ if (jumbonvram[jumbolen - 1] != BCM_JUMBO_NVRAM_DELIMIT || ++ jumbonvram[jumbolen - 2] != '\0') { ++ DBUSERR(("%s: Bad Jumbo NVRAM file format\n", __FUNCTION__)); ++ return DBUS_JUMBO_BAD_FORMAT; ++ } ++ ++ dhd_bus->nvram_nontxt = DBUS_NVRAM_NONTXT; ++ ++ nvram_start = jumbonvram; ++ ++ while (*nvram_start != BCM_JUMBO_NVRAM_DELIMIT && len < jumbolen) { ++ ++ /* consume the first file info line ++ * \nBroadcom Jumbo Nvram file\nfile1\n ... ++ */ ++ len ++; ++ nvram_start ++; ++ } ++ ++ nvram_end = nvram_start; ++ ++ /* search for "boardrev=0xabcd" and "boardtype=0x1234" information in ++ * the concatenated nvram config files /sets ++ */ ++ ++ while (len < jumbolen) { ++ ++ if (*nvram_end == '\0') { ++ /* end of a config set is marked by multiple null characters */ ++ len ++; ++ nvram_end ++; ++ DBUSTRACE(("%s: NULL chr len = %d char = 0x%x\n", __FUNCTION__, ++ len, *nvram_end)); ++ continue; ++ ++ } else if (*nvram_end == BCM_JUMBO_NVRAM_DELIMIT) { ++ ++ /* config set delimiter is reached */ ++ /* check if next config set is present or not ++ * return if next config is not present ++ */ ++ ++ /* start search the next config set */ ++ nvram_start_prev = nvram_start; ++ nvram_end_prev = nvram_end; ++ ++ nvram_end ++; ++ nvram_start = nvram_end; ++ btype = brev = 0; ++ DBUSTRACE(("%s: going to next record len = %d " ++ "char = 0x%x \n", __FUNCTION__, len, *nvram_end)); ++ len ++; ++ if (len >= jumbolen) { ++ ++ *nvram = nvram_start_prev; ++ *nvram_len = (int)(nvram_end_prev - nvram_start_prev); ++ ++ DBUSTRACE(("%s: no more len = %d nvram_end = 0x%p", ++ __FUNCTION__, len, nvram_end)); ++ ++ return DBUS_JUMBO_NOMATCH; ++ ++ } else { ++ continue; ++ } ++ ++ } else { ++ ++ DBUSTRACE(("%s: config str = %s\n", __FUNCTION__, nvram_end)); ++ ++ if (bcmp(nvram_end, "boardtype", strlen("boardtype")) == 0) { ++ ++ field = strchr(nvram_end, '='); ++ field++; ++ btype = (uint16)bcm_strtoul(field, NULL, 0); ++ ++ DBUSTRACE(("%s: btype = 0x%x boardtype = 0x%x \n", __FUNCTION__, ++ btype, boardtype)); ++ } ++ ++ if (bcmp(nvram_end, "boardrev", strlen("boardrev")) == 0) { ++ ++ field = strchr(nvram_end, '='); ++ field++; ++ brev = (uint16)bcm_strtoul(field, NULL, 0); ++ ++ DBUSTRACE(("%s: brev = 0x%x boardrev = 0x%x \n", __FUNCTION__, ++ brev, boardrev)); ++ } ++ if (btype == boardtype && brev == boardrev) { ++ /* locate nvram config set end - ie.find '\r' char */ ++ while (*nvram_end != BCM_JUMBO_NVRAM_DELIMIT) ++ nvram_end ++; ++ *nvram = nvram_start; ++ *nvram_len = (int) (nvram_end - nvram_start); ++ DBUSTRACE(("found len = %d nvram_start = 0x%p " ++ "nvram_end = 0x%p\n", *nvram_len, nvram_start, nvram_end)); ++ return DBUS_OK; ++ } ++ ++ len += (strlen(nvram_end) + 1); ++ nvram_end += (strlen(nvram_end) + 1); ++ } ++ } ++ return DBUS_JUMBO_NOMATCH; ++} /* dbus_select_nvram */ ++ ++#endif ++ ++#define DBUS_NRXQ 50 ++#define DBUS_NTXQ 100 ++ ++static void ++dhd_dbus_send_complete(void *handle, void *info, int status) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)handle; ++ void *pkt = info; ++ ++ if ((dhd == NULL) || (pkt == NULL)) { ++ DBUSERR(("dhd or pkt is NULL\n")); ++ return; ++ } ++ ++ if (status == DBUS_OK) { ++ dhd->dstats.tx_packets++; ++ } else { ++ DBUSERR(("TX error=%d\n", status)); ++ dhd->dstats.tx_errors++; ++ } ++#ifdef PROP_TXSTATUS ++ if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) && ++ (dhd_wlfc_txcomplete(dhd, pkt, status == 0) != WLFC_UNSUPPORTED)) { ++ return; ++ } ++#endif /* PROP_TXSTATUS */ ++ PKTFREE(dhd->osh, pkt, TRUE); ++} ++ ++static void ++dhd_dbus_recv_pkt(void *handle, void *pkt) ++{ ++ uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; ++ uint reorder_info_len; ++ uint pkt_count; ++ dhd_pub_t *dhd = (dhd_pub_t *)handle; ++ int ifidx = 0; ++ ++ if (dhd == NULL) { ++ DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ /* If the protocol uses a data header, check and remove it */ ++ if (dhd_prot_hdrpull(dhd, &ifidx, pkt, reorder_info_buf, ++ &reorder_info_len) != 0) { ++ DBUSERR(("rx protocol error\n")); ++ PKTFREE(dhd->osh, pkt, FALSE); ++ dhd->rx_errors++; ++ return; ++ } ++ ++ if (reorder_info_len) { ++ /* Reordering info from the firmware */ ++ dhd_process_pkt_reorder_info(dhd, reorder_info_buf, reorder_info_len, ++ &pkt, &pkt_count); ++ if (pkt_count == 0) ++ return; ++ } ++ else { ++ pkt_count = 1; ++ } ++ dhd_rx_frame(dhd, ifidx, pkt, pkt_count, 0); ++} ++ ++static void ++dhd_dbus_recv_buf(void *handle, uint8 *buf, int len) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)handle; ++ void *pkt; ++ ++ if (dhd == NULL) { ++ DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if ((pkt = PKTGET(dhd->osh, len, FALSE)) == NULL) { ++ DBUSERR(("PKTGET (rx) failed=%d\n", len)); ++ return; ++ } ++ ++ bcopy(buf, PKTDATA(dhd->osh, pkt), len); ++ dhd_dbus_recv_pkt(dhd, pkt); ++} ++ ++static void ++dhd_dbus_txflowcontrol(void *handle, bool onoff) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)handle; ++ bool wlfc_enabled = FALSE; ++ ++ if (dhd == NULL) { ++ DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++#ifdef PROP_TXSTATUS ++ wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, onoff, !onoff) != WLFC_UNSUPPORTED); ++#endif ++ ++ if (!wlfc_enabled) { ++ dhd_txflowcontrol(dhd, ALL_INTERFACES, onoff); ++ } ++} ++ ++static void ++dhd_dbus_errhandler(void *handle, int err) ++{ ++} ++ ++static void ++dhd_dbus_ctl_complete(void *handle, int type, int status) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)handle; ++ ++ if (dhd == NULL) { ++ DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (type == DBUS_CBCTL_READ) { ++ if (status == DBUS_OK) ++ dhd->rx_ctlpkts++; ++ else ++ dhd->rx_ctlerrs++; ++ } else if (type == DBUS_CBCTL_WRITE) { ++ if (status == DBUS_OK) ++ dhd->tx_ctlpkts++; ++ else ++ dhd->tx_ctlerrs++; ++ } ++ ++ dhd_prot_ctl_complete(dhd); ++} ++ ++static void ++dhd_dbus_state_change(void *handle, int state) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)handle; ++ ++ if (dhd == NULL) { ++ DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ switch (state) { ++ ++ case DBUS_STATE_DL_NEEDED: ++ DBUSERR(("%s: firmware request cannot be handled\n", __FUNCTION__)); ++ break; ++ case DBUS_STATE_DOWN: ++ DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__)); ++ dhd->busstate = DHD_BUS_DOWN; ++ break; ++ case DBUS_STATE_UP: ++ DBUSTRACE(("%s: DBUS is up\n", __FUNCTION__)); ++ dhd->busstate = DHD_BUS_DATA; ++ break; ++ default: ++ break; ++ } ++ ++ DBUSERR(("%s: DBUS current state=%d\n", __FUNCTION__, state)); ++} ++ ++static void * ++dhd_dbus_pktget(void *handle, uint len, bool send) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)handle; ++ void *p = NULL; ++ ++ if (dhd == NULL) { ++ DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ if (send == TRUE) { ++ dhd_os_sdlock_txq(dhd); ++ p = PKTGET(dhd->osh, len, TRUE); ++ dhd_os_sdunlock_txq(dhd); ++ } else { ++ dhd_os_sdlock_rxq(dhd); ++ p = PKTGET(dhd->osh, len, FALSE); ++ dhd_os_sdunlock_rxq(dhd); ++ } ++ ++ return p; ++} ++ ++static void ++dhd_dbus_pktfree(void *handle, void *p, bool send) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)handle; ++ ++ if (dhd == NULL) { ++ DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (send == TRUE) { ++#ifdef PROP_TXSTATUS ++ if (DHD_PKTTAG_WLFCPKT(PKTTAG(p)) && ++ (dhd_wlfc_txcomplete(dhd, p, FALSE) != WLFC_UNSUPPORTED)) { ++ return; ++ } ++#endif /* PROP_TXSTATUS */ ++ ++ dhd_os_sdlock_txq(dhd); ++ PKTFREE(dhd->osh, p, TRUE); ++ dhd_os_sdunlock_txq(dhd); ++ } else { ++ dhd_os_sdlock_rxq(dhd); ++ PKTFREE(dhd->osh, p, FALSE); ++ dhd_os_sdunlock_rxq(dhd); ++ } ++} ++ ++ ++static dbus_callbacks_t dhd_dbus_cbs = { ++ dhd_dbus_send_complete, ++ dhd_dbus_recv_buf, ++ dhd_dbus_recv_pkt, ++ dhd_dbus_txflowcontrol, ++ dhd_dbus_errhandler, ++ dhd_dbus_ctl_complete, ++ dhd_dbus_state_change, ++ dhd_dbus_pktget, ++ dhd_dbus_pktfree ++}; ++ ++uint ++dhd_bus_chip(struct dhd_bus *bus) ++{ ++ ASSERT(bus != NULL); ++ return bus->pub.attrib.devid; ++} ++ ++uint ++dhd_bus_chiprev(struct dhd_bus *bus) ++{ ++ ASSERT(bus); ++ ASSERT(bus != NULL); ++ return bus->pub.attrib.chiprev; ++} ++ ++void ++dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ bcm_bprintf(strbuf, "Bus USB\n"); ++} ++ ++void ++dhd_bus_clearcounts(dhd_pub_t *dhdp) ++{ ++} ++ ++int ++dhd_bus_txdata(struct dhd_bus *bus, void *pktbuf) ++{ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ if (bus->txoff) { ++ DBUSTRACE(("txoff\n")); ++ return BCME_EPERM; ++ } ++ return dbus_send_txdata(&bus->pub, pktbuf); ++} ++ ++static void ++dhd_dbus_advertise_bus_cleanup(dhd_pub_t *dhdp) ++{ ++ unsigned long flags; ++ int timeleft; ++ ++ DHD_LINUX_GENERAL_LOCK(dhdp, flags); ++ dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS; ++ DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); ++ ++ timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); ++ if ((timeleft == 0) || (timeleft == 1)) { ++ DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", ++ __FUNCTION__, dhdp->dhd_bus_busy_state)); ++ ASSERT(0); ++ } ++ ++ return; ++} ++ ++static void ++dhd_dbus_advertise_bus_remove(dhd_pub_t *dhdp) ++{ ++ unsigned long flags; ++ int timeleft; ++ ++ DHD_LINUX_GENERAL_LOCK(dhdp, flags); ++ dhdp->busstate = DHD_BUS_REMOVE; ++ DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); ++ ++ timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); ++ if ((timeleft == 0) || (timeleft == 1)) { ++ DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", ++ __FUNCTION__, dhdp->dhd_bus_busy_state)); ++ ASSERT(0); ++ } ++ ++ return; ++} ++ ++int ++dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) ++{ ++ int bcmerror = 0; ++ unsigned long flags; ++ wifi_adapter_info_t *adapter = (wifi_adapter_info_t *)dhdp->adapter; ++ ++ if (flag == TRUE) { ++ if (!dhdp->dongle_reset) { ++ DBUSERR(("%s: == Power OFF ==\n", __FUNCTION__)); ++ dhd_dbus_advertise_bus_cleanup(dhdp); ++ dhd_os_wd_timer(dhdp, 0); ++#if !defined(IGNORE_ETH0_DOWN) ++ /* Force flow control as protection when stop come before ifconfig_down */ ++ dhd_txflowcontrol(dhdp, ALL_INTERFACES, ON); ++#endif /* !defined(IGNORE_ETH0_DOWN) */ ++ dbus_stop(dhdp->bus); ++ ++ dhdp->dongle_reset = TRUE; ++ dhdp->up = FALSE; ++ ++ DHD_LINUX_GENERAL_LOCK(dhdp, flags); ++ dhdp->busstate = DHD_BUS_DOWN; ++ DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); ++ wifi_clr_adapter_status(adapter, WIFI_STATUS_FW_READY); ++ ++ printf("%s: WLAN OFF DONE\n", __FUNCTION__); ++ /* App can now remove power from device */ ++ } else ++ bcmerror = BCME_ERROR; ++ } else { ++ /* App must have restored power to device before calling */ ++ printf("\n\n%s: == WLAN ON ==\n", __FUNCTION__); ++ if (dhdp->dongle_reset) { ++ /* Turn on WLAN */ ++ DHD_MUTEX_UNLOCK(); ++ wait_event_interruptible_timeout(adapter->status_event, ++ wifi_get_adapter_status(adapter, WIFI_STATUS_FW_READY), ++ msecs_to_jiffies(DHD_FW_READY_TIMEOUT)); ++ DHD_MUTEX_LOCK(); ++ bcmerror = dbus_up(dhdp->bus); ++ if (bcmerror == BCME_OK) { ++ dhdp->dongle_reset = FALSE; ++ dhdp->up = TRUE; ++#if !defined(IGNORE_ETH0_DOWN) ++ /* Restore flow control */ ++ dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF); ++#endif ++ dhd_os_wd_timer(dhdp, dhd_watchdog_ms); ++ ++ DBUSTRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); ++ } else { ++ DBUSERR(("%s: failed to dbus_up with code %d\n", __FUNCTION__, bcmerror)); ++ } ++ } ++ } ++ ++#ifdef PKT_STATICS ++ memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t)); ++#endif ++ return bcmerror; ++} ++ ++void ++dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, ++ char *pnv_path, char *pclm_path, char *pconf_path) ++{ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (bus == NULL) { ++ DBUSERR(("%s: bus is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ bus->fw_path = pfw_path; ++ bus->nv_path = pnv_path; ++ bus->dhd->clm_path = pclm_path; ++ bus->dhd->conf_path = pconf_path; ++ ++ dhd_conf_set_path_params(bus->dhd, bus->fw_path, bus->nv_path); ++ ++} ++ ++/* ++ * hdrlen is space to reserve in pkt headroom for DBUS ++ */ ++void * ++dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, ++ uint16 bus_no, uint16 slot, uint32 hdrlen) ++{ ++ osl_t *osh = NULL; ++ dhd_bus_t *bus = NULL; ++ dhd_pub_t *pub = NULL; ++ uint rxsz; ++ int dlneeded = 0; ++ wifi_adapter_info_t *adapter = NULL; ++ ++ DBUSTRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ adapter = dhd_wifi_platform_get_adapter(bustype, bus_no, slot); ++ ++ if (!g_pub) { ++ /* Ask the OS interface part for an OSL handle */ ++ if (!(osh = osl_attach(NULL, bustype, TRUE))) { ++ DBUSERR(("%s: OSL attach failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* Attach to the dhd/OS interface */ ++ if (!(pub = dhd_attach(osh, bus, hdrlen, adapter))) { ++ DBUSERR(("%s: dhd_attach failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ } else { ++ pub = g_pub; ++ osh = pub->osh; ++ } ++ ++ if (pub->bus) { ++ DBUSERR(("%s: wrong probe\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ rxsz = dhd_get_rxsz(pub); ++ bus = dbus_attach(osh, rxsz, DBUS_NRXQ, DBUS_NTXQ, pub, &dhd_dbus_cbs, NULL, NULL); ++ if (bus) { ++ pub->bus = bus; ++ bus->dhd = pub; ++ ++ dlneeded = dbus_dlneeded(bus); ++ if (dlneeded >= 0) { ++ if (!g_pub) { ++ dhd_conf_reset(pub); ++ dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev); ++ dhd_conf_preinit(pub); ++ } ++ } ++ ++ if (g_pub || dhd_download_fw_on_driverload) { ++ if (dlneeded == 0) { ++ wifi_set_adapter_status(adapter, WIFI_STATUS_FW_READY); ++#ifdef BCM_REQUEST_FW ++ } else if (dlneeded > 0) { ++ dhd_set_path(bus->dhd); ++ if (dbus_download_firmware(bus, bus->fw_path, bus->nv_path) != DBUS_OK) ++ goto fail; ++#endif ++ } else { ++ goto fail; ++ } ++ } ++ } else { ++ DBUSERR(("%s: dbus_attach failed\n", __FUNCTION__)); ++ } ++ ++ if (!g_pub) { ++ /* Ok, finish the attach to the OS network interface */ ++ if (dhd_register_if(pub, 0, TRUE) != 0) { ++ DBUSERR(("%s: dhd_register_if failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ pub->hang_report = TRUE; ++#if defined(MULTIPLE_SUPPLICANT) ++ wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe ++#endif ++ g_pub = pub; ++ } ++ ++ DBUSTRACE(("%s: Exit\n", __FUNCTION__)); ++ wifi_clr_adapter_status(adapter, WIFI_STATUS_DETTACH); ++ wifi_set_adapter_status(adapter, WIFI_STATUS_ATTACH); ++ wake_up_interruptible(&adapter->status_event); ++ /* This is passed to dhd_dbus_disconnect_cb */ ++ return bus; ++ ++fail: ++ if (pub && pub->bus) { ++ dbus_detach(pub->bus); ++ pub->bus = NULL; ++ } ++ /* Release resources in reverse order */ ++ if (!g_pub) { ++ if (pub) { ++ dhd_detach(pub); ++ dhd_free(pub); ++ } ++ if (osh) { ++ osl_detach(osh); ++ } ++ } ++ ++ printf("%s: Failed\n", __FUNCTION__); ++ return NULL; ++} ++ ++void ++dhd_dbus_disconnect_cb(void *arg) ++{ ++ dhd_bus_t *bus = (dhd_bus_t *)arg; ++ dhd_pub_t *pub = g_pub; ++ osl_t *osh; ++ wifi_adapter_info_t *adapter = NULL; ++ ++ adapter = (wifi_adapter_info_t *)pub->adapter; ++ ++ if (pub && !pub->dhd_remove && bus == NULL) { ++ DBUSERR(("%s: bus is NULL\n", __FUNCTION__)); ++ return; ++ } ++ if (!adapter) { ++ DBUSERR(("%s: adapter is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ printf("%s: Enter dhd_remove=%d on %s\n", __FUNCTION__, ++ pub->dhd_remove, adapter->name); ++ if (!pub->dhd_remove) { ++ /* Advertise bus remove during rmmod */ ++ dhd_dbus_advertise_bus_remove(bus->dhd); ++ dbus_detach(pub->bus); ++ pub->bus = NULL; ++ wifi_clr_adapter_status(adapter, WIFI_STATUS_ATTACH); ++ wifi_set_adapter_status(adapter, WIFI_STATUS_DETTACH); ++ wake_up_interruptible(&adapter->status_event); ++ } else { ++ osh = pub->osh; ++ dhd_detach(pub); ++ if (pub->bus) { ++ dbus_detach(pub->bus); ++ pub->bus = NULL; ++ } ++ dhd_free(pub); ++ g_pub = NULL; ++ if (MALLOCED(osh)) { ++ DBUSERR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); ++ } ++ osl_detach(osh); ++ } ++ ++ DBUSTRACE(("%s: Exit\n", __FUNCTION__)); ++} ++ ++#ifdef LINUX_EXTERNAL_MODULE_DBUS ++ ++static int __init ++bcm_dbus_module_init(void) ++{ ++ printf("Inserting bcm_dbus module \n"); ++ return 0; ++} ++ ++static void __exit ++bcm_dbus_module_exit(void) ++{ ++ printf("Removing bcm_dbus module \n"); ++ return; ++} ++ ++EXPORT_SYMBOL(dbus_pnp_sleep); ++EXPORT_SYMBOL(dbus_get_devinfo); ++EXPORT_SYMBOL(dbus_detach); ++EXPORT_SYMBOL(dbus_get_attrib); ++EXPORT_SYMBOL(dbus_down); ++EXPORT_SYMBOL(dbus_pnp_resume); ++EXPORT_SYMBOL(dbus_set_config); ++EXPORT_SYMBOL(dbus_flowctrl_rx); ++EXPORT_SYMBOL(dbus_up); ++EXPORT_SYMBOL(dbus_get_device_speed); ++EXPORT_SYMBOL(dbus_send_pkt); ++EXPORT_SYMBOL(dbus_recv_ctl); ++EXPORT_SYMBOL(dbus_attach); ++ ++MODULE_LICENSE("GPL"); ++ ++module_init(bcm_dbus_module_init); ++module_exit(bcm_dbus_module_exit); ++ ++#endif /* #ifdef LINUX_EXTERNAL_MODULE_DBUS */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dbus_usb.c b/module_drivers/drivers/net/wireless/bcmdhd/dbus_usb.c +new file mode 100644 +index 000000000..8a496dd1e +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dbus_usb.c +@@ -0,0 +1,1172 @@ ++/* ++ * Dongle BUS interface for USB, OS independent ++ * ++ * Copyright (C) 1999-2016, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dbus_usb.c 565557 2015-06-22 19:29:44Z $ ++ */ ++ ++/** ++ * @file @brief ++ * This file contains DBUS code that is USB, but not OS specific. DBUS is a Broadcom proprietary ++ * host specific abstraction layer. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++uint dbus_msglevel = DBUS_ERROR_VAL; ++module_param(dbus_msglevel, int, 0); ++ ++ ++#define USB_DLIMAGE_RETRY_TIMEOUT 3000 /* retry Timeout */ ++#define USB_SFLASH_DLIMAGE_SPINWAIT 150 /* in unit of ms */ ++#define USB_SFLASH_DLIMAGE_LIMIT 2000 /* spinwait limit (ms) */ ++#define POSTBOOT_ID 0xA123 /* ID to detect if dongle has boot up */ ++#define USB_RESETCFG_SPINWAIT 1 /* wait after resetcfg (ms) */ ++#define USB_DEV_ISBAD(u) (u->pub->attrib.devid == 0xDEAD) ++#define USB_DLGO_SPINWAIT 100 /* wait after DL_GO (ms) */ ++#define TEST_CHIP 0x4328 ++ ++typedef struct { ++ dbus_pub_t *pub; ++ ++ void *cbarg; ++ dbus_intf_callbacks_t *cbs; /** callbacks into higher DBUS level (dbus.c) */ ++ dbus_intf_t *drvintf; ++ void *usbosl_info; ++ uint32 rdlram_base_addr; ++ uint32 rdlram_size; ++} usb_info_t; ++ ++/* ++ * Callbacks common to all USB ++ */ ++static void dbus_usb_disconnect(void *handle); ++static void dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb); ++static void dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status); ++static void dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status); ++static void dbus_usb_errhandler(void *handle, int err); ++static void dbus_usb_ctl_complete(void *handle, int type, int status); ++static void dbus_usb_state_change(void *handle, int state); ++static struct dbus_irb* dbus_usb_getirb(void *handle, bool send); ++static void dbus_usb_rxerr_indicate(void *handle, bool on); ++#if !defined(BCM_REQUEST_FW) ++static int dbus_usb_resetcfg(usb_info_t *usbinfo); ++#endif ++static int dbus_usb_iovar_op(void *bus, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++static int dbus_iovar_process(usb_info_t* usbinfo, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++static int dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, ++ const char *name, void *params, int plen, void *arg, int len, int val_size); ++static int dhdusb_downloadvars(usb_info_t *bus, void *arg, int len); ++ ++static int dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen); ++static int dbus_usb_dlstart(void *bus, uint8 *fw, int len); ++static int dbus_usb_dlneeded(void *bus); ++static int dbus_usb_dlrun(void *bus); ++static int dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo); ++ ++ ++/* OS specific */ ++extern bool dbus_usbos_dl_cmd(void *info, uint8 cmd, void *buffer, int buflen); ++extern int dbus_usbos_wait(void *info, uint16 ms); ++extern int dbus_write_membytes(usb_info_t *usbinfo, bool set, uint32 address, ++ uint8 *data, uint size); ++extern bool dbus_usbos_dl_send_bulk(void *info, void *buffer, int len); ++extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size); ++ ++/** ++ * These functions are called by the lower DBUS level (dbus_usb_os.c) to notify this DBUS level ++ * (dbus_usb.c) of an event. ++ */ ++static dbus_intf_callbacks_t dbus_usb_intf_cbs = { ++ dbus_usb_send_irb_timeout, ++ dbus_usb_send_irb_complete, ++ dbus_usb_recv_irb_complete, ++ dbus_usb_errhandler, ++ dbus_usb_ctl_complete, ++ dbus_usb_state_change, ++ NULL, /* isr */ ++ NULL, /* dpc */ ++ NULL, /* watchdog */ ++ NULL, /* dbus_if_pktget */ ++ NULL, /* dbus_if_pktfree */ ++ dbus_usb_getirb, ++ dbus_usb_rxerr_indicate ++}; ++ ++/* IOVar table */ ++enum { ++ IOV_SET_DOWNLOAD_STATE = 1, ++ IOV_DBUS_MSGLEVEL, ++ IOV_MEMBYTES, ++ IOV_VARS, ++ IOV_LOOPBACK_TX ++}; ++ ++const bcm_iovar_t dhdusb_iovars[] = { ++ {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, ++ {"dbus_msglevel", IOV_DBUS_MSGLEVEL, 0, IOVT_UINT32, 0 }, ++ {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, ++ {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, ++ {"usb_lb_txfer", IOV_LOOPBACK_TX, 0, IOVT_BUFFER, 2 * sizeof(int) }, ++ {NULL, 0, 0, 0, 0 } ++}; ++ ++/* ++ * Need global for probe() and disconnect() since ++ * attach() is not called at probe and detach() ++ * can be called inside disconnect() ++ */ ++static probe_cb_t probe_cb = NULL; ++static disconnect_cb_t disconnect_cb = NULL; ++static void *probe_arg = NULL; ++static void *disc_arg = NULL; ++static dbus_intf_t *g_dbusintf = NULL; ++static dbus_intf_t dbus_usb_intf; /** functions called by higher layer DBUS into lower layer */ ++ ++/* ++ * dbus_intf_t common to all USB ++ * These functions override dbus_usb_.c. ++ */ ++static void *dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs); ++static void dbus_usb_detach(dbus_pub_t *pub, void *info); ++static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype, ++ uint16 bus_no, uint16 slot, uint32 hdrlen); ++ ++/* functions */ ++ ++/** ++ * As part of DBUS initialization/registration, the higher level DBUS (dbus.c) needs to know what ++ * lower level DBUS functions to call (in both dbus_usb.c and dbus_usb_os.c). ++ */ ++static void * ++dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, ++ uint16 slot, uint32 hdrlen) ++{ ++ DBUSTRACE(("%s(): \n", __FUNCTION__)); ++ if (probe_cb) { ++ ++ if (g_dbusintf != NULL) { ++ /* First, initialize all lower-level functions as default ++ * so that dbus.c simply calls directly to dbus_usb_os.c. ++ */ ++ bcopy(g_dbusintf, &dbus_usb_intf, sizeof(dbus_intf_t)); ++ ++ /* Second, selectively override functions we need, if any. */ ++ dbus_usb_intf.attach = dbus_usb_attach; ++ dbus_usb_intf.detach = dbus_usb_detach; ++ dbus_usb_intf.iovar_op = dbus_usb_iovar_op; ++ dbus_usb_intf.dlstart = dbus_usb_dlstart; ++ dbus_usb_intf.dlneeded = dbus_usb_dlneeded; ++ dbus_usb_intf.dlrun = dbus_usb_dlrun; ++ } ++ ++ disc_arg = probe_cb(probe_arg, "DBUS USB", USB_BUS, bus_no, slot, hdrlen); ++ return disc_arg; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * On return, *intf contains this or lower-level DBUS functions to be called by higher ++ * level (dbus.c) ++ */ ++int ++dbus_bus_register(int vid, int pid, probe_cb_t prcb, ++ disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) ++{ ++ int err; ++ ++ DBUSTRACE(("%s(): \n", __FUNCTION__)); ++ probe_cb = prcb; ++ disconnect_cb = discb; ++ probe_arg = prarg; ++ ++ *intf = &dbus_usb_intf; ++ ++ err = dbus_bus_osl_register(vid, pid, dbus_usb_probe, ++ dbus_usb_disconnect, NULL, &g_dbusintf, param1, param2); ++ ++ ASSERT(g_dbusintf); ++ return err; ++} ++ ++int ++dbus_bus_deregister() ++{ ++ DBUSTRACE(("%s(): \n", __FUNCTION__)); ++ return dbus_bus_osl_deregister(); ++} ++ ++/** initialization consists of registration followed by 'attach'. */ ++void * ++dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) ++{ ++ usb_info_t *usb_info; ++ ++ DBUSTRACE(("%s(): \n", __FUNCTION__)); ++ ++ if ((g_dbusintf == NULL) || (g_dbusintf->attach == NULL)) ++ return NULL; ++ ++ /* Sanity check for BUS_INFO() */ ++ ASSERT(OFFSETOF(usb_info_t, pub) == 0); ++ ++ usb_info = MALLOC(pub->osh, sizeof(usb_info_t)); ++ if (usb_info == NULL) ++ return NULL; ++ ++ bzero(usb_info, sizeof(usb_info_t)); ++ ++ usb_info->pub = pub; ++ usb_info->cbarg = cbarg; ++ usb_info->cbs = cbs; ++ ++ usb_info->usbosl_info = (dbus_pub_t *)g_dbusintf->attach(pub, ++ usb_info, &dbus_usb_intf_cbs); ++ if (usb_info->usbosl_info == NULL) { ++ MFREE(pub->osh, usb_info, sizeof(usb_info_t)); ++ return NULL; ++ } ++ ++ /* Save USB OS-specific driver entry points */ ++ usb_info->drvintf = g_dbusintf; ++ ++ pub->bus = usb_info; ++#if !defined(BCM_REQUEST_FW) ++ if (!dbus_usb_resetcfg(usb_info)) { ++ usb_info->pub->busstate = DBUS_STATE_DL_DONE; ++ } ++#endif ++ /* Return Lower layer info */ ++ return (void *) usb_info->usbosl_info; ++} ++ ++void ++dbus_usb_detach(dbus_pub_t *pub, void *info) ++{ ++ usb_info_t *usb_info = (usb_info_t *) pub->bus; ++ osl_t *osh = pub->osh; ++ ++ if (usb_info == NULL) ++ return; ++ ++ if (usb_info->drvintf && usb_info->drvintf->detach) ++ usb_info->drvintf->detach(pub, usb_info->usbosl_info); ++ ++ MFREE(osh, usb_info, sizeof(usb_info_t)); ++} ++ ++void ++dbus_usb_disconnect(void *handle) ++{ ++ DBUSTRACE(("%s(): \n", __FUNCTION__)); ++ if (disconnect_cb) ++ disconnect_cb(disc_arg); ++} ++ ++/** ++ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be ++ * notified. ++ */ ++static void ++dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb) ++{ ++ usb_info_t *usb_info = (usb_info_t *) handle; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (usb_info == NULL) ++ return; ++ ++ if (usb_info->cbs && usb_info->cbs->send_irb_timeout) ++ usb_info->cbs->send_irb_timeout(usb_info->cbarg, txirb); ++} ++ ++/** ++ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be ++ * notified. ++ */ ++static void ++dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status) ++{ ++ usb_info_t *usb_info = (usb_info_t *) handle; ++ ++ if (usb_info == NULL) ++ return; ++ ++ if (usb_info->cbs && usb_info->cbs->send_irb_complete) ++ usb_info->cbs->send_irb_complete(usb_info->cbarg, txirb, status); ++} ++ ++/** ++ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be ++ * notified. ++ */ ++static void ++dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status) ++{ ++ usb_info_t *usb_info = (usb_info_t *) handle; ++ ++ if (usb_info == NULL) ++ return; ++ ++ if (usb_info->cbs && usb_info->cbs->recv_irb_complete) ++ usb_info->cbs->recv_irb_complete(usb_info->cbarg, rxirb, status); ++} ++ ++/** Lower DBUS level (dbus_usb_os.c) requests a free IRB. Pass this on to the higher DBUS level. */ ++static struct dbus_irb* ++dbus_usb_getirb(void *handle, bool send) ++{ ++ usb_info_t *usb_info = (usb_info_t *) handle; ++ ++ if (usb_info == NULL) ++ return NULL; ++ ++ if (usb_info->cbs && usb_info->cbs->getirb) ++ return usb_info->cbs->getirb(usb_info->cbarg, send); ++ ++ return NULL; ++} ++ ++/** ++ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be ++ * notified. ++ */ ++static void ++dbus_usb_rxerr_indicate(void *handle, bool on) ++{ ++ usb_info_t *usb_info = (usb_info_t *) handle; ++ ++ if (usb_info == NULL) ++ return; ++ ++ if (usb_info->cbs && usb_info->cbs->rxerr_indicate) ++ usb_info->cbs->rxerr_indicate(usb_info->cbarg, on); ++} ++ ++/** ++ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be ++ * notified. ++ */ ++static void ++dbus_usb_errhandler(void *handle, int err) ++{ ++ usb_info_t *usb_info = (usb_info_t *) handle; ++ ++ if (usb_info == NULL) ++ return; ++ ++ if (usb_info->cbs && usb_info->cbs->errhandler) ++ usb_info->cbs->errhandler(usb_info->cbarg, err); ++} ++ ++/** ++ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be ++ * notified. ++ */ ++static void ++dbus_usb_ctl_complete(void *handle, int type, int status) ++{ ++ usb_info_t *usb_info = (usb_info_t *) handle; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (usb_info == NULL) { ++ DBUSERR(("%s: usb_info is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (usb_info->cbs && usb_info->cbs->ctl_complete) ++ usb_info->cbs->ctl_complete(usb_info->cbarg, type, status); ++} ++ ++/** ++ * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be ++ * notified. ++ */ ++static void ++dbus_usb_state_change(void *handle, int state) ++{ ++ usb_info_t *usb_info = (usb_info_t *) handle; ++ ++ if (usb_info == NULL) ++ return; ++ ++ if (usb_info->cbs && usb_info->cbs->state_change) ++ usb_info->cbs->state_change(usb_info->cbarg, state); ++} ++ ++/** called by higher DBUS level (dbus.c) */ ++static int ++dbus_usb_iovar_op(void *bus, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ int err = DBUS_OK; ++ ++ err = dbus_iovar_process((usb_info_t*)bus, name, params, plen, arg, len, set); ++ return err; ++} ++ ++/** process iovar request from higher DBUS level */ ++static int ++dbus_iovar_process(usb_info_t* usbinfo, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ const bcm_iovar_t *vi = NULL; ++ int bcmerror = 0; ++ int val_size; ++ uint32 actionid; ++ ++ DBUSTRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get MUST have return space */ ++ ASSERT(set || (arg && len)); ++ ++ /* Set does NOT take qualifiers */ ++ ASSERT(!set || (!params && !plen)); ++ ++ /* Look up var locally; if not found pass to host driver */ ++ if ((vi = bcm_iovar_lookup(dhdusb_iovars, name)) == NULL) { ++ /* Not Supported */ ++ bcmerror = BCME_UNSUPPORTED; ++ DBUSTRACE(("%s: IOVAR %s is not supported\n", name, __FUNCTION__)); ++ goto exit; ++ ++ } ++ ++ DBUSTRACE(("%s: %s %s, len %d plen %d\n", __FUNCTION__, ++ 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 = dbus_usb_doiovar(usbinfo, vi, actionid, ++ name, params, plen, arg, len, val_size); ++ ++exit: ++ return bcmerror; ++} /* dbus_iovar_process */ ++ ++static int ++dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, ++ void *params, int plen, void *arg, int len, int val_size) ++{ ++ int bcmerror = 0; ++ int32 int_val = 0; ++ int32 int_val2 = 0; ++ bool bool_val = 0; ++ ++ DBUSTRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", ++ __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) ++ goto exit; ++ ++ if (plen >= (int)sizeof(int_val)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ if (plen >= (int)sizeof(int_val) * 2) ++ bcopy((void*)((uintptr)params + sizeof(int_val)), &int_val2, sizeof(int_val2)); ++ ++ bool_val = (int_val != 0) ? TRUE : FALSE; ++ ++ switch (actionid) { ++ ++ case IOV_SVAL(IOV_MEMBYTES): ++ case IOV_GVAL(IOV_MEMBYTES): ++ { ++ uint32 address; ++ uint size, dsize; ++ uint8 *data; ++ ++ bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); ++ ++ ASSERT(plen >= 2*sizeof(int)); ++ ++ address = (uint32)int_val; ++ BCM_REFERENCE(address); ++ bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); ++ size = (uint)int_val; ++ ++ /* Do some validation */ ++ dsize = set ? plen - (2 * sizeof(int)) : len; ++ if (dsize < size) { ++ DBUSTRACE(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", ++ __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ DBUSTRACE(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, ++ (set ? "write" : "read"), size, address)); ++ ++ /* Generate the actual data pointer */ ++ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; ++ ++ /* Call to do the transfer */ ++ bcmerror = dbus_usb_dl_writeimage(BUS_INFO(bus, usb_info_t), data, size); ++ } ++ break; ++ ++ ++ case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): ++ ++ if (bool_val == TRUE) { ++ bcmerror = dbus_usb_dlneeded(bus); ++ dbus_usb_rdl_dwnld_state(BUS_INFO(bus, usb_info_t)); ++ } else { ++ usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); ++ bcmerror = dbus_usb_dlrun(bus); ++ usbinfo->pub->busstate = DBUS_STATE_DL_DONE; ++ } ++ break; ++ ++ case IOV_SVAL(IOV_VARS): ++ bcmerror = dhdusb_downloadvars(BUS_INFO(bus, usb_info_t), arg, len); ++ break; ++ ++ case IOV_GVAL(IOV_DBUS_MSGLEVEL): ++ int_val = (int32)dbus_msglevel; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DBUS_MSGLEVEL): ++ dbus_msglevel = int_val; ++ break; ++ ++#ifdef DBUS_USB_LOOPBACK ++ case IOV_SVAL(IOV_LOOPBACK_TX): ++ bcmerror = dbus_usbos_loopback_tx(BUS_INFO(bus, usb_info_t), int_val, ++ int_val2); ++ break; ++#endif ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ ++exit: ++ return bcmerror; ++} /* dbus_usb_doiovar */ ++ ++/** higher DBUS level (dbus.c) wants to set NVRAM variables in dongle */ ++static int ++dhdusb_downloadvars(usb_info_t *bus, void *arg, int len) ++{ ++ int bcmerror = 0; ++ uint32 varsize; ++ uint32 varaddr; ++ uint32 varsizew; ++ ++ if (!len) { ++ bcmerror = BCME_BUFTOOSHORT; ++ goto err; ++ } ++ ++ /* RAM size is not set. Set it at dbus_usb_dlneeded */ ++ if (!bus->rdlram_size) ++ bcmerror = BCME_ERROR; ++ ++ /* Even if there are no vars are to be written, we still need to set the ramsize. */ ++ varsize = len ? ROUNDUP(len, 4) : 0; ++ varaddr = (bus->rdlram_size - 4) - varsize; ++ ++ /* Write the vars list */ ++ DBUSTRACE(("WriteVars: @%x varsize=%d\n", varaddr, varsize)); ++ bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, (varaddr + bus->rdlram_base_addr), ++ arg, varsize); ++ ++ /* adjust to the user specified RAM */ ++ DBUSTRACE(("Usable memory size: %d\n", bus->rdlram_size)); ++ DBUSTRACE(("Vars are at %d, orig varsize is %d\n", varaddr, varsize)); ++ ++ varsize = ((bus->rdlram_size - 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 = htol32(varsizew); ++ } ++ ++ DBUSTRACE(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); ++ ++ /* Write the length token to the last word */ ++ bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, ((bus->rdlram_size - 4) + ++ bus->rdlram_base_addr), (uint8*)&varsizew, 4); ++err: ++ return bcmerror; ++} /* dbus_usb_doiovar */ ++ ++#if !defined(BCM_REQUEST_FW) ++/** ++ * After downloading firmware into dongle and starting it, we need to know if the firmware is ++ * indeed up and running. ++ */ ++static int ++dbus_usb_resetcfg(usb_info_t *usbinfo) ++{ ++ void *osinfo; ++ bootrom_id_t id; ++ uint16 waittime = 0; ++ ++ uint32 starttime = 0; ++ uint32 endtime = 0; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (usbinfo == NULL) ++ return DBUS_ERR; ++ ++ osinfo = usbinfo->usbosl_info; ++ ASSERT(osinfo); ++ ++ /* Give dongle chance to boot */ ++ dbus_usbos_wait(osinfo, USB_SFLASH_DLIMAGE_SPINWAIT); ++ waittime = USB_SFLASH_DLIMAGE_SPINWAIT; ++ while (waittime < USB_DLIMAGE_RETRY_TIMEOUT) { ++ ++ starttime = OSL_SYSUPTIME(); ++ ++ id.chip = 0xDEAD; /* Get the ID */ ++ dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t)); ++ id.chip = ltoh32(id.chip); ++ ++ endtime = OSL_SYSUPTIME(); ++ waittime += (endtime - starttime); ++ ++ if (id.chip == POSTBOOT_ID) ++ break; ++ } ++ ++ if (id.chip == POSTBOOT_ID) { ++ DBUSERR(("%s: download done. Bootup time = %d ms postboot chip 0x%x/rev 0x%x\n", ++ __FUNCTION__, waittime, id.chip, id.chiprev)); ++ ++ dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t)); ++ ++ dbus_usbos_wait(osinfo, USB_RESETCFG_SPINWAIT); ++ return DBUS_OK; ++ } else { ++ DBUSERR(("%s: Cannot talk to Dongle. Wait time = %d ms. Firmware is not UP \n", ++ __FUNCTION__, waittime)); ++ return DBUS_ERR; ++ } ++ ++ return DBUS_OK; ++} ++#endif ++ ++/** before firmware download, the dongle has to be prepared to receive the fw image */ ++static int ++dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo) ++{ ++ void *osinfo = usbinfo->usbosl_info; ++ rdl_state_t state; ++ int err = DBUS_OK; ++ ++ /* 1) Prepare USB boot loader for runtime image */ ++ dbus_usbos_dl_cmd(osinfo, DL_START, &state, sizeof(rdl_state_t)); ++ ++ state.state = ltoh32(state.state); ++ state.bytes = ltoh32(state.bytes); ++ ++ /* 2) Check we are in the Waiting state */ ++ if (state.state != DL_WAITING) { ++ DBUSERR(("%s: Failed to DL_START\n", __FUNCTION__)); ++ err = DBUS_ERR; ++ goto fail; ++ } ++ ++fail: ++ return err; ++} ++ ++/** ++ * Dongle contains bootcode in ROM but firmware is (partially) contained in dongle RAM. Therefore, ++ * firmware has to be downloaded into dongle RAM. ++ */ ++static int ++dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen) ++{ ++ osl_t *osh = usbinfo->pub->osh; ++ void *osinfo = usbinfo->usbosl_info; ++ unsigned int sendlen, sent, dllen; ++ char *bulkchunk = NULL, *dlpos; ++ rdl_state_t state; ++ int err = DBUS_OK; ++ bootrom_id_t id; ++ uint16 wait, wait_time; ++ uint32 dl_trunk_size = RDL_CHUNK; ++ ++ if (BCM4350_CHIP(usbinfo->pub->attrib.devid)) ++ dl_trunk_size = RDL_CHUNK_MAX; ++ ++ while (!bulkchunk) { ++ bulkchunk = MALLOC(osh, dl_trunk_size); ++ if (dl_trunk_size == RDL_CHUNK) ++ break; ++ if (!bulkchunk) { ++ dl_trunk_size /= 2; ++ if (dl_trunk_size < RDL_CHUNK) ++ dl_trunk_size = RDL_CHUNK; ++ } ++ } ++ ++ if (bulkchunk == NULL) { ++ err = DBUS_ERR; ++ goto fail; ++ } ++ ++ sent = 0; ++ dlpos = fw; ++ dllen = fwlen; ++ ++ /* Get chip id and rev */ ++ id.chip = usbinfo->pub->attrib.devid; ++ id.chiprev = usbinfo->pub->attrib.chiprev; ++ ++ DBUSTRACE(("enter %s: fwlen=%d\n", __FUNCTION__, fwlen)); ++ ++ dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t)); ++ ++ /* 3) Load the image */ ++ while ((sent < dllen)) { ++ /* Wait until the usb device reports it received all the bytes we sent */ ++ ++ if (sent < dllen) { ++ if ((dllen-sent) < dl_trunk_size) ++ sendlen = dllen-sent; ++ else ++ sendlen = dl_trunk_size; ++ ++ /* simply avoid having to send a ZLP by ensuring we never have an even ++ * multiple of 64 ++ */ ++ if (!(sendlen % 64)) ++ sendlen -= 4; ++ ++ /* send data */ ++ memcpy(bulkchunk, dlpos, sendlen); ++ if (!dbus_usbos_dl_send_bulk(osinfo, bulkchunk, sendlen)) { ++ err = DBUS_ERR; ++ goto fail; ++ } ++ ++ dlpos += sendlen; ++ sent += sendlen; ++ DBUSTRACE(("%s: sendlen %d\n", __FUNCTION__, sendlen)); ++ } ++ ++ wait = 0; ++ wait_time = USB_SFLASH_DLIMAGE_SPINWAIT; ++ while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, ++ sizeof(rdl_state_t))) { ++ if ((id.chip == 43236) && (id.chiprev == 0)) { ++ DBUSERR(("%s: 43236a0 SFlash delay, waiting for dongle crc check " ++ "completion!!!\n", __FUNCTION__)); ++ dbus_usbos_wait(osinfo, wait_time); ++ wait += wait_time; ++ if (wait >= USB_SFLASH_DLIMAGE_LIMIT) { ++ DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); ++ err = DBUS_ERR; ++ goto fail; ++ break; ++ } ++ } else { ++ DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); ++ err = DBUS_ERR; ++ goto fail; ++ } ++ } ++ ++ state.state = ltoh32(state.state); ++ state.bytes = ltoh32(state.bytes); ++ ++ /* restart if an error is reported */ ++ if ((state.state == DL_BAD_HDR) || (state.state == DL_BAD_CRC)) { ++ DBUSERR(("%s: Bad Hdr or Bad CRC\n", __FUNCTION__)); ++ err = DBUS_ERR; ++ goto fail; ++ } ++ ++ } ++fail: ++ if (bulkchunk) ++ MFREE(osh, bulkchunk, dl_trunk_size); ++ ++ return err; ++} /* dbus_usb_dl_writeimage */ ++ ++/** Higher level DBUS layer (dbus.c) requests this layer to download image into dongle */ ++static int ++dbus_usb_dlstart(void *bus, uint8 *fw, int len) ++{ ++ usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); ++ int err; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (usbinfo == NULL) ++ return DBUS_ERR; ++ ++ if (USB_DEV_ISBAD(usbinfo)) ++ return DBUS_ERR; ++ ++ err = dbus_usb_rdl_dwnld_state(usbinfo); ++ ++ if (DBUS_OK == err) { ++ err = dbus_usb_dl_writeimage(usbinfo, fw, len); ++ if (err == DBUS_OK) ++ usbinfo->pub->busstate = DBUS_STATE_DL_DONE; ++ else ++ usbinfo->pub->busstate = DBUS_STATE_DL_PENDING; ++ } else ++ usbinfo->pub->busstate = DBUS_STATE_DL_PENDING; ++ ++ return err; ++} ++ ++static bool ++dbus_usb_update_chipinfo(usb_info_t *usbinfo, uint32 chip) ++{ ++ bool retval = TRUE; ++ /* based on the CHIP Id, store the ram size which is needed for NVRAM download. */ ++ switch (chip) { ++ ++ case 0x4319: ++ usbinfo->rdlram_size = RDL_RAM_SIZE_4319; ++ usbinfo->rdlram_base_addr = RDL_RAM_BASE_4319; ++ break; ++ ++ case 0x4329: ++ usbinfo->rdlram_size = RDL_RAM_SIZE_4329; ++ usbinfo->rdlram_base_addr = RDL_RAM_BASE_4329; ++ break; ++ ++ case 43234: ++ case 43235: ++ case 43236: ++ usbinfo->rdlram_size = RDL_RAM_SIZE_43236; ++ usbinfo->rdlram_base_addr = RDL_RAM_BASE_43236; ++ break; ++ ++ case 0x4328: ++ usbinfo->rdlram_size = RDL_RAM_SIZE_4328; ++ usbinfo->rdlram_base_addr = RDL_RAM_BASE_4328; ++ break; ++ ++ case 0x4322: ++ usbinfo->rdlram_size = RDL_RAM_SIZE_4322; ++ usbinfo->rdlram_base_addr = RDL_RAM_BASE_4322; ++ break; ++ ++ case 0x4360: ++ case 0xAA06: ++ usbinfo->rdlram_size = RDL_RAM_SIZE_4360; ++ usbinfo->rdlram_base_addr = RDL_RAM_BASE_4360; ++ break; ++ ++ case 43242: ++ case 43243: ++ usbinfo->rdlram_size = RDL_RAM_SIZE_43242; ++ usbinfo->rdlram_base_addr = RDL_RAM_BASE_43242; ++ break; ++ ++ case 43143: ++ usbinfo->rdlram_size = RDL_RAM_SIZE_43143; ++ usbinfo->rdlram_base_addr = RDL_RAM_BASE_43143; ++ break; ++ ++ case 0x4350: ++ case 43556: ++ case 43558: ++ case 43569: ++ usbinfo->rdlram_size = RDL_RAM_SIZE_4350; ++ usbinfo->rdlram_base_addr = RDL_RAM_BASE_4350; ++ break; ++ ++ case POSTBOOT_ID: ++ break; ++ ++ default: ++ DBUSERR(("%s: Chip 0x%x Ram size is not known\n", __FUNCTION__, chip)); ++ retval = FALSE; ++ break; ++ ++ } ++ ++ return retval; ++} /* dbus_usb_update_chipinfo */ ++ ++/** higher DBUS level (dbus.c) wants to know if firmware download is required. */ ++static int ++dbus_usb_dlneeded(void *bus) ++{ ++ usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); ++ void *osinfo; ++ bootrom_id_t id; ++ int dl_needed = 1; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (usbinfo == NULL) ++ return DBUS_ERR; ++ ++ osinfo = usbinfo->usbosl_info; ++ ASSERT(osinfo); ++ ++ /* Check if firmware downloaded already by querying runtime ID */ ++ id.chip = 0xDEAD; ++ dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t)); ++ ++ id.chip = ltoh32(id.chip); ++ id.chiprev = ltoh32(id.chiprev); ++ ++ if (FALSE == dbus_usb_update_chipinfo(usbinfo, id.chip)) { ++ dl_needed = DBUS_ERR; ++ goto exit; ++ } ++ ++ DBUSERR(("%s: chip 0x%x rev 0x%x\n", __FUNCTION__, id.chip, id.chiprev)); ++ if (id.chip == POSTBOOT_ID) { ++ /* This code is needed to support two enumerations on USB1.1 scenario */ ++ DBUSERR(("%s: Firmware already downloaded\n", __FUNCTION__)); ++ ++ dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t)); ++ dl_needed = DBUS_OK; ++ if (usbinfo->pub->busstate == DBUS_STATE_DL_PENDING) ++ usbinfo->pub->busstate = DBUS_STATE_DL_DONE; ++ } else { ++ usbinfo->pub->attrib.devid = id.chip; ++ usbinfo->pub->attrib.chiprev = id.chiprev; ++ } ++ ++exit: ++ return dl_needed; ++} ++ ++/** After issuing firmware download, higher DBUS level (dbus.c) wants to start the firmware. */ ++static int ++dbus_usb_dlrun(void *bus) ++{ ++ usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); ++ void *osinfo; ++ rdl_state_t state; ++ int err = DBUS_OK; ++ ++ DBUSTRACE(("%s\n", __FUNCTION__)); ++ ++ if (usbinfo == NULL) ++ return DBUS_ERR; ++ ++ if (USB_DEV_ISBAD(usbinfo)) ++ return DBUS_ERR; ++ ++ osinfo = usbinfo->usbosl_info; ++ ASSERT(osinfo); ++ ++ /* Check we are runnable */ ++ dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t)); ++ ++ state.state = ltoh32(state.state); ++ state.bytes = ltoh32(state.bytes); ++ ++ /* Start the image */ ++ if (state.state == DL_RUNNABLE) { ++ DBUSTRACE(("%s: Issue DL_GO\n", __FUNCTION__)); ++ dbus_usbos_dl_cmd(osinfo, DL_GO, &state, sizeof(rdl_state_t)); ++ ++ if (usbinfo->pub->attrib.devid == TEST_CHIP) ++ dbus_usbos_wait(osinfo, USB_DLGO_SPINWAIT); ++ ++// dbus_usb_resetcfg(usbinfo); ++ /* The Donlge may go for re-enumeration. */ ++ } else { ++ DBUSERR(("%s: Dongle not runnable\n", __FUNCTION__)); ++ err = DBUS_ERR; ++ } ++ ++ return err; ++} ++ ++/** ++ * As preparation for firmware download, higher DBUS level (dbus.c) requests the firmware image ++ * to be used for the type of dongle detected. Directly called by dbus.c (so not via a callback ++ * construction) ++ */ ++void ++dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp) ++{ ++ usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); ++ unsigned int devid; ++ unsigned int crev; ++ ++ devid = usbinfo->pub->attrib.devid; ++ crev = usbinfo->pub->attrib.chiprev; ++ ++ *fw = NULL; ++ *fwlen = 0; ++ ++ switch (devid) { ++ case BCM43236_CHIP_ID: ++ case BCM43235_CHIP_ID: ++ case BCM43234_CHIP_ID: ++ case BCM43238_CHIP_ID: { ++ if (crev == 3 || crev == 2 || crev == 1) { ++#ifdef EMBED_IMAGE_43236b ++ *fw = (uint8 *)dlarray_43236b; ++ *fwlen = sizeof(dlarray_43236b); ++ ++#endif ++ } ++ } break; ++ case BCM4360_CHIP_ID: ++ case BCM4352_CHIP_ID: ++ case BCM43526_CHIP_ID: ++#ifdef EMBED_IMAGE_43526a ++ if (crev <= 2) { ++ *fw = (uint8 *)dlarray_43526a; ++ *fwlen = sizeof(dlarray_43526a); ++ } ++#endif ++#ifdef EMBED_IMAGE_43526b ++ if (crev > 2) { ++ *fw = (uint8 *)dlarray_43526b; ++ *fwlen = sizeof(dlarray_43526b); ++ } ++#endif ++ break; ++ ++ case BCM43242_CHIP_ID: ++#ifdef EMBED_IMAGE_43242a0 ++ *fw = (uint8 *)dlarray_43242a0; ++ *fwlen = sizeof(dlarray_43242a0); ++#endif ++ break; ++ ++ case BCM43143_CHIP_ID: ++#ifdef EMBED_IMAGE_43143a0 ++ *fw = (uint8 *)dlarray_43143a0; ++ *fwlen = sizeof(dlarray_43143a0); ++#endif ++#ifdef EMBED_IMAGE_43143b0 ++ *fw = (uint8 *)dlarray_43143b0; ++ *fwlen = sizeof(dlarray_43143b0); ++#endif ++ break; ++ ++ case BCM4350_CHIP_ID: ++ case BCM4354_CHIP_ID: ++ case BCM43556_CHIP_ID: ++ case BCM43558_CHIP_ID: ++ case BCM43566_CHIP_ID: ++ case BCM43568_CHIP_ID: ++ case BCM43570_CHIP_ID: ++ case BCM4358_CHIP_ID: ++#ifdef EMBED_IMAGE_4350a0 ++ if (crev == 0) { ++ *fw = (uint8 *)dlarray_4350a0; ++ *fwlen = sizeof(dlarray_4350a0); ++ } ++#endif ++#ifdef EMBED_IMAGE_4350b0 ++ if (crev == 1) { ++ *fw = (uint8 *)dlarray_4350b0; ++ *fwlen = sizeof(dlarray_4350b0); ++ } ++#endif ++#ifdef EMBED_IMAGE_4350b1 ++ if (crev == 2) { ++ *fw = (uint8 *)dlarray_4350b1; ++ *fwlen = sizeof(dlarray_4350b1); ++ } ++#endif ++#ifdef EMBED_IMAGE_43556b1 ++ if (crev == 2) { ++ *fw = (uint8 *)dlarray_43556b1; ++ *fwlen = sizeof(dlarray_43556b1); ++ } ++#endif ++#ifdef EMBED_IMAGE_4350c0 ++ if (crev == 3) { ++ *fw = (uint8 *)dlarray_4350c0; ++ *fwlen = sizeof(dlarray_4350c0); ++ } ++#endif /* EMBED_IMAGE_4350c0 */ ++#ifdef EMBED_IMAGE_4350c1 ++ if (crev == 4) { ++ *fw = (uint8 *)dlarray_4350c1; ++ *fwlen = sizeof(dlarray_4350c1); ++ } ++#endif /* EMBED_IMAGE_4350c1 */ ++ break; ++ case BCM43569_CHIP_ID: ++#ifdef EMBED_IMAGE_43569a0 ++ if (crev == 0) { ++ *fw = (uint8 *)dlarray_43569a0; ++ *fwlen = sizeof(dlarray_43569a0); ++ } ++#endif /* EMBED_IMAGE_43569a0 */ ++ break; ++ default: ++#ifdef EMBED_IMAGE_GENERIC ++ *fw = (uint8 *)dlarray; ++ *fwlen = sizeof(dlarray); ++#endif ++ break; ++ } ++} /* dbus_bus_fw_get */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dbus_usb_linux.c b/module_drivers/drivers/net/wireless/bcmdhd/dbus_usb_linux.c +new file mode 100644 +index 000000000..10927d894 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dbus_usb_linux.c +@@ -0,0 +1,3403 @@ ++/* ++ * Dongle BUS interface ++ * USB Linux Implementation ++ * ++ * Copyright (C) 1999-2016, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dbus_usb_linux.c 564663 2015-06-18 02:34:42Z $ ++ */ ++ ++/** ++ * @file @brief ++ * This file contains DBUS code that is USB *and* OS (Linux) specific. DBUS is a Broadcom ++ * proprietary host specific abstraction layer. ++ */ ++ ++#include ++#include ++ ++/** ++ * DBUS_LINUX_RXDPC is created for router platform performance tuning. A separate thread is created ++ * to handle USB RX and avoid the call chain getting too long and enhance cache hit rate. ++ * ++ * DBUS_LINUX_RXDPC setting is in wlconfig file. ++ */ ++ ++/* ++ * If DBUS_LINUX_RXDPC is off, spin_lock_bh() for CTFPOOL in ++ * linux_osl.c has to be changed to spin_lock_irqsave() because ++ * PKTGET/PKTFREE are no longer in bottom half. ++ * ++ * Right now we have another queue rpcq in wl_linux.c. Maybe we ++ * can eliminate that one to reduce the overhead. ++ * ++ * Enabling 2nd EP and DBUS_LINUX_RXDPC causing traffic from ++ * both EP's to be queued in the same rx queue. If we want ++ * RXDPC to work with 2nd EP. The EP for RPC call return ++ * should bypass the dpc and go directly up. ++ */ ++ ++/* #define DBUS_LINUX_RXDPC */ ++ ++/* Dbus histogram for ntxq, nrxq, dpc parameter tuning */ ++/* #define DBUS_LINUX_HIST */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(USBOS_THREAD) || defined(USBOS_TX_THREAD) ++ ++/** ++ * The usb-thread is designed to provide currency on multiprocessors and SMP linux kernels. On the ++ * dual cores platform, the WLAN driver, without threads, executed only on CPU0. The driver consumed ++ * almost of 100% on CPU0, while CPU1 remained idle. The behavior was observed on Broadcom's STB. ++ * ++ * The WLAN driver consumed most of CPU0 and not CPU1 because tasklets/queues, software irq, and ++ * hardware irq are executing from CPU0, only. CPU0 became the system's bottle-neck. TPUT is lower ++ * and system's responsiveness is slower. ++ * ++ * To improve system responsiveness and TPUT usb-thread was implemented. The system's threads could ++ * be scheduled to run on any core. One core could be processing data in the usb-layer and the other ++ * core could be processing data in the wl-layer. ++ * ++ * For further info see [WlThreadAndUsbThread] Twiki. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#endif /* USBOS_THREAD || USBOS_TX_THREAD */ ++ ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define KERNEL26 ++#endif ++ ++/** ++ * Starting with the 3.10 kernel release, dynamic PM support for USB is present whenever ++ * the kernel was built with CONFIG_PM_RUNTIME enabled. The CONFIG_USB_SUSPEND option has ++ * been eliminated. ++ */ ++#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)) && defined(CONFIG_USB_SUSPEND)) \ ++ || ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) && defined(CONFIG_PM_RUNTIME)) ++/* For USB power management support, see Linux kernel: Documentation/usb/power-management.txt */ ++#define USB_SUSPEND_AVAILABLE ++#endif ++ ++/* Define alternate fw/nvram paths used in Android */ ++#ifdef OEM_ANDROID ++#define CONFIG_ANDROID_BCMDHD_FW_PATH "broadcom/dhd/firmware/fw.bin.trx" ++#define CONFIG_ANDROID_BCMDHD_NVRAM_PATH "broadcom/dhd/nvrams/nvm.txt" ++#endif /* OEM_ANDROID */ ++ ++static inline int usb_submit_urb_linux(struct urb *urb) ++{ ++ ++#ifdef BCM_MAX_URB_LEN ++ if (urb && (urb->transfer_buffer_length > BCM_MAX_URB_LEN)) { ++ DBUSERR(("URB transfer length=%d exceeded %d ra=%p\n", urb->transfer_buffer_length, ++ BCM_MAX_URB_LEN, __builtin_return_address(0))); ++ return DBUS_ERR; ++ } ++#endif ++ ++#ifdef KERNEL26 ++ return usb_submit_urb(urb, GFP_ATOMIC); ++#else ++ return usb_submit_urb(urb); ++#endif ++ ++} ++ ++#define USB_SUBMIT_URB(urb) usb_submit_urb_linux(urb) ++ ++#ifdef KERNEL26 ++ ++#define USB_ALLOC_URB() usb_alloc_urb(0, GFP_ATOMIC) ++#define USB_UNLINK_URB(urb) (usb_kill_urb(urb)) ++#define USB_FREE_URB(urb) (usb_free_urb(urb)) ++#define USB_REGISTER() usb_register(&dbus_usbdev) ++#define USB_DEREGISTER() usb_deregister(&dbus_usbdev) ++ ++#ifdef USB_SUSPEND_AVAILABLE ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) ++#define USB_AUTOPM_SET_INTERFACE(intf) usb_autopm_set_interface(intf) ++#else ++#define USB_ENABLE_AUTOSUSPEND(udev) usb_enable_autosuspend(udev) ++#define USB_DISABLE_AUTOSUSPEND(udev) usb_disable_autosuspend(udev) ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ ++ ++#define USB_AUTOPM_GET_INTERFACE(intf) usb_autopm_get_interface(intf) ++#define USB_AUTOPM_PUT_INTERFACE(intf) usb_autopm_put_interface(intf) ++#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) usb_autopm_get_interface_async(intf) ++#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) usb_autopm_put_interface_async(intf) ++#define USB_MARK_LAST_BUSY(dev) usb_mark_last_busy(dev) ++ ++#else /* USB_SUSPEND_AVAILABLE */ ++ ++#define USB_AUTOPM_GET_INTERFACE(intf) do {} while (0) ++#define USB_AUTOPM_PUT_INTERFACE(intf) do {} while (0) ++#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) do {} while (0) ++#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) do {} while (0) ++#define USB_MARK_LAST_BUSY(dev) do {} while (0) ++#endif /* USB_SUSPEND_AVAILABLE */ ++ ++#define USB_CONTROL_MSG(dev, pipe, request, requesttype, value, index, data, size, timeout) \ ++ usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), \ ++ (data), (size), (timeout)) ++#define USB_BULK_MSG(dev, pipe, data, len, actual_length, timeout) \ ++ usb_bulk_msg((dev), (pipe), (data), (len), (actual_length), (timeout)) ++#define USB_BUFFER_ALLOC(dev, size, mem, dma) usb_buffer_alloc(dev, size, mem, dma) ++#define USB_BUFFER_FREE(dev, size, data, dma) usb_buffer_free(dev, size, data, dma) ++ ++#ifdef WL_URB_ZPKT ++#define URB_QUEUE_BULK URB_ZERO_PACKET ++#else ++#define URB_QUEUE_BULK 0 ++#endif /* WL_URB_ZPKT */ ++ ++#define CALLBACK_ARGS struct urb *urb, struct pt_regs *regs ++#define CALLBACK_ARGS_DATA urb, regs ++#define CONFIGDESC(usb) (&((usb)->actconfig)->desc) ++#define IFPTR(usb, idx) ((usb)->actconfig->interface[idx]) ++#define IFALTS(usb, idx) (IFPTR((usb), (idx))->altsetting[0]) ++#define IFDESC(usb, idx) IFALTS((usb), (idx)).desc ++#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[ep]).desc ++ ++#else /* KERNEL26 */ ++ ++#define USB_ALLOC_URB() usb_alloc_urb(0) ++#define USB_UNLINK_URB(urb) usb_unlink_urb(urb) ++#define USB_FREE_URB(urb) (usb_free_urb(urb)) ++#define USB_REGISTER() usb_register(&dbus_usbdev) ++#define USB_DEREGISTER() usb_deregister(&dbus_usbdev) ++#define USB_AUTOPM_GET_INTERFACE(intf) do {} while (0) ++#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) do {} while (0) ++#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) do {} while (0) ++#define USB_MARK_LAST_BUSY(dev) do {} while (0) ++ ++#define USB_CONTROL_MSG(dev, pipe, request, requesttype, value, index, data, size, timeout) \ ++ usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), \ ++ (data), (size), (timeout)) ++#define USB_BUFFER_ALLOC(dev, size, mem, dma) kmalloc(size, mem) ++#define USB_BUFFER_FREE(dev, size, data, dma) kfree(data) ++ ++#ifdef WL_URB_ZPKT ++#define URB_QUEUE_BULK USB_QUEUE_BULK|URB_ZERO_PACKET ++#else ++#define URB_QUEUE_BULK 0 ++#endif /* WL_URB_ZPKT */ ++ ++#define CALLBACK_ARGS struct urb *urb ++#define CALLBACK_ARGS_DATA urb ++#define CONFIGDESC(usb) ((usb)->actconfig) ++#define IFPTR(usb, idx) (&(usb)->actconfig->interface[idx]) ++#define IFALTS(usb, idx) ((usb)->actconfig->interface[idx].altsetting[0]) ++#define IFDESC(usb, idx) IFALTS((usb), (idx)) ++#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[ep]) ++ ++ ++#endif /* KERNEL26 */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++#define USB_SPEED_SUPER 5 ++#endif /* #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) */ ++ ++#define CONTROL_IF 0 ++#define BULK_IF 0 ++ ++#ifdef BCMUSBDEV_COMPOSITE ++#define USB_COMPIF_MAX 4 ++ ++#define USB_CLASS_WIRELESS 0xe0 ++#define USB_CLASS_MISC 0xef ++#define USB_SUBCLASS_COMMON 0x02 ++#define USB_PROTO_IAD 0x01 ++#define USB_PROTO_VENDOR 0xff ++ ++#define USB_QUIRK_NO_SET_INTF 0x04 /* device does not support set_interface */ ++#endif /* BCMUSBDEV_COMPOSITE */ ++ ++#define USB_SYNC_WAIT_TIMEOUT 300 /* ms */ ++ ++/* Private data kept in skb */ ++#define SKB_PRIV(skb, idx) (&((void **)skb->cb)[idx]) ++#define SKB_PRIV_URB(skb) (*(struct urb **)SKB_PRIV(skb, 0)) ++ ++#ifndef DBUS_USB_RXQUEUE_BATCH_ADD ++/* items to add each time within limit */ ++#define DBUS_USB_RXQUEUE_BATCH_ADD 8 ++#endif ++ ++#ifndef DBUS_USB_RXQUEUE_LOWER_WATERMARK ++/* add a new batch req to rx queue when waiting item count reduce to this number */ ++#define DBUS_USB_RXQUEUE_LOWER_WATERMARK 4 ++#endif ++ ++enum usbos_suspend_state { ++ USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow suspend */ ++ USBOS_SUSPEND_STATE_SUSPEND_PENDING, /* Device is idle, can be suspended */ ++ /* Wating PM to suspend */ ++ USBOS_SUSPEND_STATE_SUSPENDED /* Device suspended */ ++}; ++ ++enum usbos_request_state { ++ USBOS_REQUEST_STATE_UNSCHEDULED = 0, /* USB TX request not scheduled */ ++ USBOS_REQUEST_STATE_SCHEDULED, /* USB TX request given to TX thread */ ++ USBOS_REQUEST_STATE_SUBMITTED /* USB TX request submitted */ ++}; ++ ++typedef struct { ++ uint32 notification; ++ uint32 reserved; ++} intr_t; ++ ++typedef struct { ++ dbus_pub_t *pub; ++ ++ void *cbarg; ++ dbus_intf_callbacks_t *cbs; ++ ++ /* Imported */ ++ struct usb_device *usb; /* USB device pointer from OS */ ++ struct urb *intr_urb; /* URB for interrupt endpoint */ ++ struct list_head req_rxfreeq; ++ struct list_head req_txfreeq; ++ struct list_head req_rxpostedq; /* Posted down to USB driver for RX */ ++ struct list_head req_txpostedq; /* Posted down to USB driver for TX */ ++ spinlock_t rxfree_lock; /* Lock for rx free list */ ++ spinlock_t txfree_lock; /* Lock for tx free list */ ++ spinlock_t rxposted_lock; /* Lock for rx posted list */ ++ spinlock_t txposted_lock; /* Lock for tx posted list */ ++ uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; /* Pipe numbers for USB I/O */ ++ uint rxbuf_len; ++ ++ struct list_head req_rxpendingq; /* RXDPC: Pending for dpc to send up */ ++ spinlock_t rxpending_lock; /* RXDPC: Lock for rx pending list */ ++ long dpc_pid; ++ struct semaphore dpc_sem; ++ struct completion dpc_exited; ++ int rxpending; ++ ++ struct urb *ctl_urb; ++ int ctl_in_pipe, ctl_out_pipe; ++ struct usb_ctrlrequest ctl_write; ++ struct usb_ctrlrequest ctl_read; ++ struct semaphore ctl_lock; /* Lock for CTRL transfers via tx_thread */ ++#ifdef USBOS_TX_THREAD ++ enum usbos_request_state ctl_state; ++#endif /* USBOS_TX_THREAD */ ++ ++ spinlock_t rxlock; /* Lock for rxq management */ ++ spinlock_t txlock; /* Lock for txq management */ ++ ++ int intr_size; /* Size of interrupt message */ ++ int interval; /* Interrupt polling interval */ ++ intr_t intr; /* Data buffer for interrupt endpoint */ ++ ++ int maxps; ++ atomic_t txposted; ++ atomic_t rxposted; ++ atomic_t txallocated; ++ atomic_t rxallocated; ++ bool rxctl_deferrespok; /* Get a response for setup from dongle */ ++ ++ wait_queue_head_t wait; ++ bool waitdone; ++ int sync_urb_status; ++ ++ struct urb *blk_urb; /* Used for downloading embedded image */ ++ ++#ifdef USBOS_THREAD ++ spinlock_t ctrl_lock; ++ spinlock_t usbos_list_lock; ++ struct list_head usbos_list; ++ struct list_head usbos_free_list; ++ atomic_t usbos_list_cnt; ++ wait_queue_head_t usbos_queue_head; ++ struct task_struct *usbos_kt; ++#endif /* USBOS_THREAD */ ++ ++#ifdef USBOS_TX_THREAD ++ spinlock_t usbos_tx_list_lock; ++ struct list_head usbos_tx_list; ++ wait_queue_head_t usbos_tx_queue_head; ++ struct task_struct *usbos_tx_kt; ++#endif /* USBOS_TX_THREAD */ ++ ++ struct dma_pool *qtd_pool; /* QTD pool for USB optimization only */ ++ int tx_ep, rx_ep, rx2_ep; /* EPs for USB optimization */ ++ struct usb_device *usb_device; /* USB device for optimization */ ++} usbos_info_t; ++ ++typedef struct urb_req { ++ void *pkt; ++ int buf_len; ++ struct urb *urb; ++ void *arg; ++ usbos_info_t *usbinfo; ++ struct list_head urb_list; ++} urb_req_t; ++ ++#ifdef USBOS_THREAD ++typedef struct usbos_list_entry { ++ struct list_head list; /* must be first */ ++ void *urb_context; ++ int urb_length; ++ int urb_status; ++} usbos_list_entry_t; ++ ++static void* dbus_usbos_thread_init(usbos_info_t *usbos_info); ++static void dbus_usbos_thread_deinit(usbos_info_t *usbos_info); ++static void dbus_usbos_dispatch_schedule(CALLBACK_ARGS); ++static int dbus_usbos_thread_func(void *data); ++#endif /* USBOS_THREAD */ ++ ++#ifdef USBOS_TX_THREAD ++void* dbus_usbos_tx_thread_init(usbos_info_t *usbos_info); ++void dbus_usbos_tx_thread_deinit(usbos_info_t *usbos_info); ++int dbus_usbos_tx_thread_func(void *data); ++#endif /* USBOS_TX_THREAD */ ++ ++/* Shared Function prototypes */ ++bool dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen); ++int dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms); ++bool dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len); ++int dbus_write_membytes(usbos_info_t *usbinfo, bool set, uint32 address, uint8 *data, uint size); ++ ++/* Local function prototypes */ ++static void dbus_usbos_send_complete(CALLBACK_ARGS); ++static void dbus_usbos_recv_complete(CALLBACK_ARGS); ++static int dbus_usbos_errhandler(void *bus, int err); ++static int dbus_usbos_state_change(void *bus, int state); ++static void dbusos_stop(usbos_info_t *usbos_info); ++ ++#ifdef KERNEL26 ++static int dbus_usbos_probe(struct usb_interface *intf, const struct usb_device_id *id); ++static void dbus_usbos_disconnect(struct usb_interface *intf); ++#if defined(USB_SUSPEND_AVAILABLE) ++static int dbus_usbos_resume(struct usb_interface *intf); ++static int dbus_usbos_suspend(struct usb_interface *intf, pm_message_t message); ++/* at the moment, used for full dongle host driver only */ ++static int dbus_usbos_reset_resume(struct usb_interface *intf); ++#endif /* USB_SUSPEND_AVAILABLE */ ++#else /* KERNEL26 */ ++static void *dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum, ++ const struct usb_device_id *id); ++static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr); ++#endif /* KERNEL26 */ ++ ++ ++/** ++ * have to disable missing-field-initializers warning as last element {} triggers it ++ * and different versions of kernel have different number of members so it is impossible ++ * to specify the initializer. BTW issuing the warning here is bug og GCC as universal ++ * zero {0} specified in C99 standard as correct way of initialization of struct to all zeros ++ */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ ++ 4 && __GNUC_MINOR__ >= 6)) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wmissing-field-initializers" ++#endif ++ ++static struct usb_device_id devid_table[] = { ++ { USB_DEVICE(BCM_DNGL_VID, 0x0000) }, /* Configurable via register() */ ++#if defined(BCM_REQUEST_FW) ++ { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4328) }, ++ { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4322) }, ++ { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4319) }, ++ { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43236) }, ++ { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43143) }, ++ { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43242) }, ++ { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4360) }, ++ { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4350) }, ++ { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43569) }, ++#endif ++#ifdef EXTENDED_VID_PID ++ EXTENDED_VID_PID, ++#endif /* EXTENDED_VID_PID */ ++ { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BDC_PID) }, /* Default BDC */ ++ { } ++}; ++ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ ++ 4 && __GNUC_MINOR__ >= 6)) ++#pragma GCC diagnostic pop ++#endif ++ ++MODULE_DEVICE_TABLE(usb, devid_table); ++ ++/** functions called by the Linux kernel USB subsystem */ ++static struct usb_driver dbus_usbdev = { ++ name: "dbus_usbdev", ++ probe: dbus_usbos_probe, ++ disconnect: dbus_usbos_disconnect, ++ id_table: devid_table, ++#if defined(USB_SUSPEND_AVAILABLE) ++ suspend: dbus_usbos_suspend, ++ resume: dbus_usbos_resume, ++ reset_resume: dbus_usbos_reset_resume, ++ /* Linux USB core will allow autosuspend for devices bound to this driver */ ++ supports_autosuspend: 1 ++#endif /* USB_SUSPEND_AVAILABLE */ ++}; ++ ++/** ++ * This stores USB info during Linux probe callback since attach() is not called yet at this point ++ */ ++typedef struct { ++ void *usbos_info; ++ struct usb_device *usb; /* USB device pointer from OS */ ++ uint rx_pipe; /* Pipe numbers for USB I/O */ ++ uint tx_pipe; /* Pipe numbers for USB I/O */ ++ uint intr_pipe; /* Pipe numbers for USB I/O */ ++ uint rx_pipe2; /* Pipe numbers for USB I/O */ ++ int intr_size; /* Size of interrupt message */ ++ int interval; /* Interrupt polling interval */ ++ bool dldone; ++ int vid; ++ int pid; ++ bool dereged; ++ bool disc_cb_done; ++ DEVICE_SPEED device_speed; ++ enum usbos_suspend_state suspend_state; ++ struct usb_interface *intf; ++} probe_info_t; ++ ++/* ++ * USB Linux dbus_intf_t ++ */ ++static void *dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs); ++static void dbus_usbos_intf_detach(dbus_pub_t *pub, void *info); ++static int dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb); ++static int dbus_usbos_intf_recv_irb(void *bus, dbus_irb_rx_t *rxirb); ++static int dbus_usbos_intf_recv_irb_from_ep(void *bus, dbus_irb_rx_t *rxirb, uint32 ep_idx); ++static int dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb); ++static int dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len); ++static int dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len); ++static int dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib); ++static int dbus_usbos_intf_up(void *bus); ++static int dbus_usbos_intf_down(void *bus); ++static int dbus_usbos_intf_stop(void *bus); ++static int dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value); ++extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size); ++int dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data); ++static int dbus_usbos_intf_set_config(void *bus, dbus_config_t *config); ++static bool dbus_usbos_intf_recv_needed(void *bus); ++static void *dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args); ++static void *dbus_usbos_intf_exec_txlock(void *bus, exec_cb_t cb, struct exec_parms *args); ++#ifdef BCMUSBDEV_COMPOSITE ++static int dbus_usbos_intf_wlan(struct usb_device *usb); ++#endif /* BCMUSBDEV_COMPOSITE */ ++ ++/** functions called by dbus_usb.c */ ++static dbus_intf_t dbus_usbos_intf = { ++ .attach = dbus_usbos_intf_attach, ++ .detach = dbus_usbos_intf_detach, ++ .up = dbus_usbos_intf_up, ++ .down = dbus_usbos_intf_down, ++ .send_irb = dbus_usbos_intf_send_irb, ++ .recv_irb = dbus_usbos_intf_recv_irb, ++ .cancel_irb = dbus_usbos_intf_cancel_irb, ++ .send_ctl = dbus_usbos_intf_send_ctl, ++ .recv_ctl = dbus_usbos_intf_recv_ctl, ++ .get_stats = NULL, ++ .get_attrib = dbus_usbos_intf_get_attrib, ++ .remove = NULL, ++ .resume = NULL, ++ .suspend = NULL, ++ .stop = dbus_usbos_intf_stop, ++ .reset = NULL, ++ .pktget = NULL, ++ .pktfree = NULL, ++ .iovar_op = NULL, ++ .dump = NULL, ++ .set_config = dbus_usbos_intf_set_config, ++ .get_config = NULL, ++ .device_exists = NULL, ++ .dlneeded = NULL, ++ .dlstart = NULL, ++ .dlrun = NULL, ++ .recv_needed = dbus_usbos_intf_recv_needed, ++ .exec_rxlock = dbus_usbos_intf_exec_rxlock, ++ .exec_txlock = dbus_usbos_intf_exec_txlock, ++ ++ .tx_timer_init = NULL, ++ .tx_timer_start = NULL, ++ .tx_timer_stop = NULL, ++ ++ .sched_dpc = NULL, ++ .lock = NULL, ++ .unlock = NULL, ++ .sched_probe_cb = NULL, ++ ++ .shutdown = NULL, ++ ++ .recv_stop = NULL, ++ .recv_resume = NULL, ++ ++ .recv_irb_from_ep = dbus_usbos_intf_recv_irb_from_ep, ++ .readreg = dbus_usbos_readreg ++}; ++ ++static probe_info_t g_probe_info; ++static probe_cb_t probe_cb = NULL; ++static disconnect_cb_t disconnect_cb = NULL; ++static void *probe_arg = NULL; ++static void *disc_arg = NULL; ++ ++ ++ ++static volatile int loopback_rx_cnt, loopback_tx_cnt; ++int loopback_size; ++bool is_loopback_pkt(void *buf); ++int matches_loopback_pkt(void *buf); ++ ++/** ++ * multiple code paths in this file dequeue a URB request, this function makes sure that it happens ++ * in a concurrency save manner. Don't call this from a sleepable process context. ++ */ ++static urb_req_t * BCMFASTPATH ++dbus_usbos_qdeq(struct list_head *urbreq_q, spinlock_t *lock) ++{ ++ unsigned long flags; ++ urb_req_t *req; ++ ++ ASSERT(urbreq_q != NULL); ++ ++ spin_lock_irqsave(lock, flags); ++ ++ if (list_empty(urbreq_q)) { ++ req = NULL; ++ } else { ++ ASSERT(urbreq_q->next != NULL); ++ ASSERT(urbreq_q->next != urbreq_q); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ req = list_entry(urbreq_q->next, urb_req_t, urb_list); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ list_del_init(&req->urb_list); ++ } ++ ++ spin_unlock_irqrestore(lock, flags); ++ ++ return req; ++} ++ ++static void BCMFASTPATH ++dbus_usbos_qenq(struct list_head *urbreq_q, urb_req_t *req, spinlock_t *lock) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(lock, flags); ++ ++ list_add_tail(&req->urb_list, urbreq_q); ++ ++ spin_unlock_irqrestore(lock, flags); ++} ++ ++/** ++ * multiple code paths in this file remove a URB request from a list, this function makes sure that ++ * it happens in a concurrency save manner. Don't call this from a sleepable process context. ++ * Is quite similar to dbus_usbos_qdeq(), I wonder why this function is needed. ++ */ ++static void ++dbus_usbos_req_del(urb_req_t *req, spinlock_t *lock) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(lock, flags); ++ ++ list_del_init(&req->urb_list); ++ ++ spin_unlock_irqrestore(lock, flags); ++} ++ ++ ++/** ++ * Driver requires a pool of URBs to operate. This function is called during ++ * initialization (attach phase), allocates a number of URBs, and puts them ++ * on the free (req_rxfreeq and req_txfreeq) queue ++ */ ++static int ++dbus_usbos_urbreqs_alloc(usbos_info_t *usbos_info, uint32 count, bool is_rx) ++{ ++ int i; ++ int allocated = 0; ++ int err = DBUS_OK; ++ ++ for (i = 0; i < count; i++) { ++ urb_req_t *req; ++ ++ req = MALLOC(usbos_info->pub->osh, sizeof(urb_req_t)); ++ if (req == NULL) { ++ DBUSERR(("%s: MALLOC req failed\n", __FUNCTION__)); ++ err = DBUS_ERR_NOMEM; ++ goto fail; ++ } ++ bzero(req, sizeof(urb_req_t)); ++ ++ req->urb = USB_ALLOC_URB(); ++ if (req->urb == NULL) { ++ DBUSERR(("%s: USB_ALLOC_URB req->urb failed\n", __FUNCTION__)); ++ err = DBUS_ERR_NOMEM; ++ goto fail; ++ } ++ ++ INIT_LIST_HEAD(&req->urb_list); ++ ++ if (is_rx) { ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) ++ /* don't allocate now. Do it on demand */ ++ req->pkt = NULL; ++#else ++ /* pre-allocate buffers never to be released */ ++ req->pkt = MALLOC(usbos_info->pub->osh, usbos_info->rxbuf_len); ++ if (req->pkt == NULL) { ++ DBUSERR(("%s: MALLOC req->pkt failed\n", __FUNCTION__)); ++ err = DBUS_ERR_NOMEM; ++ goto fail; ++ } ++#endif ++ req->buf_len = usbos_info->rxbuf_len; ++ dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); ++ } else { ++ req->buf_len = 0; ++ dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); ++ } ++ allocated++; ++ continue; ++ ++fail: ++ if (req) { ++ if (is_rx && req->pkt) { ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) ++ /* req->pkt is NULL in "NOCOPY" mode */ ++#else ++ MFREE(usbos_info->pub->osh, req->pkt, req->buf_len); ++#endif ++ } ++ if (req->urb) { ++ USB_FREE_URB(req->urb); ++ } ++ MFREE(usbos_info->pub->osh, req, sizeof(urb_req_t)); ++ } ++ break; ++ } ++ ++ atomic_add(allocated, is_rx ? &usbos_info->rxallocated : &usbos_info->txallocated); ++ ++ if (is_rx) { ++ DBUSTRACE(("%s: add %d (total %d) rx buf, each has %d bytes\n", __FUNCTION__, ++ allocated, atomic_read(&usbos_info->rxallocated), usbos_info->rxbuf_len)); ++ } else { ++ DBUSTRACE(("%s: add %d (total %d) tx req\n", __FUNCTION__, ++ allocated, atomic_read(&usbos_info->txallocated))); ++ } ++ ++ return err; ++} /* dbus_usbos_urbreqs_alloc */ ++ ++/** Typically called during detach or when attach failed. Don't call until all URBs unlinked */ ++static int ++dbus_usbos_urbreqs_free(usbos_info_t *usbos_info, bool is_rx) ++{ ++ int rtn = 0; ++ urb_req_t *req; ++ struct list_head *req_q; ++ spinlock_t *lock; ++ ++ if (is_rx) { ++ req_q = &usbos_info->req_rxfreeq; ++ lock = &usbos_info->rxfree_lock; ++ } else { ++ req_q = &usbos_info->req_txfreeq; ++ lock = &usbos_info->txfree_lock; ++ } ++ while ((req = dbus_usbos_qdeq(req_q, lock)) != NULL) { ++ ++ if (is_rx) { ++ if (req->pkt) { ++ /* We do MFREE instead of PKTFREE because the pkt has been ++ * converted to native already ++ */ ++ MFREE(usbos_info->pub->osh, req->pkt, req->buf_len); ++ req->pkt = NULL; ++ req->buf_len = 0; ++ } ++ } else { ++ /* sending req should not be assigned pkt buffer */ ++ ASSERT(req->pkt == NULL); ++ } ++ ++ if (req->urb) { ++ USB_FREE_URB(req->urb); ++ req->urb = NULL; ++ } ++ MFREE(usbos_info->pub->osh, req, sizeof(urb_req_t)); ++ ++ rtn++; ++ } ++ return rtn; ++} /* dbus_usbos_urbreqs_free */ ++ ++/** ++ * called by Linux kernel on URB completion. Upper DBUS layer (dbus_usb.c) has to be notified of ++ * send completion. ++ */ ++void ++dbus_usbos_send_complete(CALLBACK_ARGS) ++{ ++ urb_req_t *req = urb->context; ++ dbus_irb_tx_t *txirb = req->arg; ++ usbos_info_t *usbos_info = req->usbinfo; ++ unsigned long flags; ++ int status = DBUS_OK; ++ int txposted; ++ ++ USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); ++ ++ spin_lock_irqsave(&usbos_info->txlock, flags); ++ ++ dbus_usbos_req_del(req, &usbos_info->txposted_lock); ++ txposted = atomic_dec_return(&usbos_info->txposted); ++ if (unlikely (txposted < 0)) { ++ DBUSERR(("%s ERROR: txposted is negative (%d)!!\n", __FUNCTION__, txposted)); ++ } ++ spin_unlock_irqrestore(&usbos_info->txlock, flags); ++ ++ if (unlikely (urb->status)) { ++ status = DBUS_ERR_TXFAIL; ++ DBUSTRACE(("txfail status %d\n", urb->status)); ++ } ++ ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) ++ /* sending req should not be assigned pkt buffer */ ++ ASSERT(req->pkt == NULL); ++#endif ++ /* txirb should always be set, except for ZLP. ZLP is reusing this callback function. */ ++ if (txirb != NULL) { ++ if (txirb->send_buf != NULL) { ++ MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); ++ txirb->send_buf = NULL; ++ req->buf_len = 0; ++ } ++ if (likely (usbos_info->cbarg && usbos_info->cbs)) { ++ if (likely (usbos_info->cbs->send_irb_complete != NULL)) ++ usbos_info->cbs->send_irb_complete(usbos_info->cbarg, txirb, status); ++ } ++ } ++ ++ dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); ++} /* dbus_usbos_send_complete */ ++ ++/** ++ * In order to receive USB traffic from the dongle, we need to supply the Linux kernel with a free ++ * URB that is going to contain received data. ++ */ ++static int BCMFASTPATH ++dbus_usbos_recv_urb_submit(usbos_info_t *usbos_info, dbus_irb_rx_t *rxirb, uint32 ep_idx) ++{ ++ urb_req_t *req; ++ int ret = DBUS_OK; ++ unsigned long flags; ++ void *p; ++ uint rx_pipe; ++ int rxposted; ++ ++ BCM_REFERENCE(rxposted); ++ ++ if (!(req = dbus_usbos_qdeq(&usbos_info->req_rxfreeq, &usbos_info->rxfree_lock))) { ++ DBUSTRACE(("%s No free URB!\n", __FUNCTION__)); ++ return DBUS_ERR_RXDROP; ++ } ++ ++ spin_lock_irqsave(&usbos_info->rxlock, flags); ++ ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) ++ req->pkt = rxirb->pkt = PKTGET(usbos_info->pub->osh, req->buf_len, FALSE); ++ if (!rxirb->pkt) { ++ DBUSERR(("%s: PKTGET failed\n", __FUNCTION__)); ++ dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); ++ ret = DBUS_ERR_RXDROP; ++ goto fail; ++ } ++ /* consider the packet "native" so we don't count it as MALLOCED in the osl */ ++ PKTTONATIVE(usbos_info->pub->osh, req->pkt); ++ rxirb->buf = NULL; ++ p = PKTDATA(usbos_info->pub->osh, req->pkt); ++#else ++ if (req->buf_len != usbos_info->rxbuf_len) { ++ ASSERT(req->pkt); ++ MFREE(usbos_info->pub->osh, req->pkt, req->buf_len); ++ DBUSTRACE(("%s: replace rx buff: old len %d, new len %d\n", __FUNCTION__, ++ req->buf_len, usbos_info->rxbuf_len)); ++ req->buf_len = 0; ++ req->pkt = MALLOC(usbos_info->pub->osh, usbos_info->rxbuf_len); ++ if (req->pkt == NULL) { ++ DBUSERR(("%s: MALLOC req->pkt failed\n", __FUNCTION__)); ++ ret = DBUS_ERR_NOMEM; ++ goto fail; ++ } ++ req->buf_len = usbos_info->rxbuf_len; ++ } ++ rxirb->buf = req->pkt; ++ p = rxirb->buf; ++#endif /* defined(BCM_RPC_NOCOPY) */ ++ rxirb->buf_len = req->buf_len; ++ req->usbinfo = usbos_info; ++ req->arg = rxirb; ++ if (ep_idx == 0) { ++ rx_pipe = usbos_info->rx_pipe; ++ } else { ++ rx_pipe = usbos_info->rx_pipe2; ++ ASSERT(usbos_info->rx_pipe2); ++ } ++ /* Prepare the URB */ ++ usb_fill_bulk_urb(req->urb, usbos_info->usb, rx_pipe, ++ p, ++ rxirb->buf_len, ++ (usb_complete_t)dbus_usbos_recv_complete, req); ++ req->urb->transfer_flags |= URB_QUEUE_BULK; ++ ++ if ((ret = USB_SUBMIT_URB(req->urb))) { ++ DBUSERR(("%s USB_SUBMIT_URB failed. status %d\n", __FUNCTION__, ret)); ++ dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); ++ ret = DBUS_ERR_RXFAIL; ++ goto fail; ++ } ++ rxposted = atomic_inc_return(&usbos_info->rxposted); ++ ++ dbus_usbos_qenq(&usbos_info->req_rxpostedq, req, &usbos_info->rxposted_lock); ++fail: ++ spin_unlock_irqrestore(&usbos_info->rxlock, flags); ++ return ret; ++} /* dbus_usbos_recv_urb_submit */ ++ ++ ++/** ++ * Called by worked thread when a 'receive URB' completed or Linux kernel when it returns a URB to ++ * this driver. ++ */ ++static void BCMFASTPATH ++dbus_usbos_recv_complete_handle(urb_req_t *req, int len, int status) ++{ ++ dbus_irb_rx_t *rxirb = req->arg; ++ usbos_info_t *usbos_info = req->usbinfo; ++ unsigned long flags; ++ int rxallocated, rxposted; ++ int dbus_status = DBUS_OK; ++ bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0; ++ ++ spin_lock_irqsave(&usbos_info->rxlock, flags); ++ dbus_usbos_req_del(req, &usbos_info->rxposted_lock); ++ rxposted = atomic_dec_return(&usbos_info->rxposted); ++ rxallocated = atomic_read(&usbos_info->rxallocated); ++ spin_unlock_irqrestore(&usbos_info->rxlock, flags); ++ ++ if ((rxallocated < usbos_info->pub->nrxq) && (!status) && ++ (rxposted == DBUS_USB_RXQUEUE_LOWER_WATERMARK)) { ++ DBUSTRACE(("%s: need more rx buf: rxallocated %d rxposted %d!\n", ++ __FUNCTION__, rxallocated, rxposted)); ++ dbus_usbos_urbreqs_alloc(usbos_info, ++ MIN(DBUS_USB_RXQUEUE_BATCH_ADD, ++ usbos_info->pub->nrxq - rxallocated), TRUE); ++ } ++ ++ /* Handle errors */ ++ if (status) { ++ /* ++ * Linux 2.4 disconnect: -ENOENT or -EILSEQ for CRC error; rmmod: -ENOENT ++ * Linux 2.6 disconnect: -EPROTO, rmmod: -ESHUTDOWN ++ */ ++ if ((status == -ENOENT && (!killed))|| status == -ESHUTDOWN) { ++ /* NOTE: unlink() can not be called from URB callback(). ++ * Do not call dbusos_stop() here. ++ */ ++ DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status)); ++ dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); ++ } else if (status == -EPROTO) { ++ DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status)); ++ } else if (killed && (status == -EHOSTUNREACH || status == -ENOENT)) { ++ /* Device is suspended */ ++ } else { ++ DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status)); ++ dbus_usbos_errhandler(usbos_info, DBUS_ERR_RXFAIL); ++ } ++ ++ /* On error, don't submit more URBs yet */ ++ rxirb->buf = NULL; ++ rxirb->actual_len = 0; ++ dbus_status = DBUS_ERR_RXFAIL; ++ goto fail; ++ } ++ ++ /* Make the skb represent the received urb */ ++ rxirb->actual_len = len; ++ ++ if (rxirb->actual_len < sizeof(uint32)) { ++ DBUSTRACE(("small pkt len %d, process as ZLP\n", rxirb->actual_len)); ++ dbus_status = DBUS_ERR_RXZLP; ++ } ++ ++fail: ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) ++ /* detach the packet from the queue */ ++ req->pkt = NULL; ++#endif /* BCM_RPC_NOCOPY || BCM_RPC_RXNOCOPY */ ++ ++ if (usbos_info->cbarg && usbos_info->cbs) { ++ if (usbos_info->cbs->recv_irb_complete) { ++ usbos_info->cbs->recv_irb_complete(usbos_info->cbarg, rxirb, dbus_status); ++ } ++ } ++ ++ dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); ++ ++ /* Mark the interface as busy to reset USB autosuspend timer */ ++ USB_MARK_LAST_BUSY(usbos_info->usb); ++} /* dbus_usbos_recv_complete_handle */ ++ ++/** called by Linux kernel when it returns a URB to this driver */ ++static void ++dbus_usbos_recv_complete(CALLBACK_ARGS) ++{ ++#ifdef USBOS_THREAD ++ dbus_usbos_dispatch_schedule(CALLBACK_ARGS_DATA); ++#else /* !USBOS_THREAD */ ++ dbus_usbos_recv_complete_handle(urb->context, urb->actual_length, urb->status); ++#endif /* USBOS_THREAD */ ++} ++ ++ ++/** ++ * If Linux notifies our driver that a control read or write URB has completed, we should notify ++ * the DBUS layer above us (dbus_usb.c in this case). ++ */ ++static void ++dbus_usbos_ctl_complete(usbos_info_t *usbos_info, int type, int urbstatus) ++{ ++ int status = DBUS_ERR; ++ ++ if (usbos_info == NULL) ++ return; ++ ++ switch (urbstatus) { ++ case 0: ++ status = DBUS_OK; ++ break; ++ case -EINPROGRESS: ++ case -ENOENT: ++ default: ++#ifdef INTR_EP_ENABLE ++ DBUSERR(("%s:%d fail status %d bus:%d susp:%d intr:%d ctli:%d ctlo:%d\n", ++ __FUNCTION__, type, urbstatus, ++ usbos_info->pub->busstate, g_probe_info.suspend_state, ++ usbos_info->intr_urb_submitted, usbos_info->ctlin_urb_submitted, ++ usbos_info->ctlout_urb_submitted)); ++#else ++ DBUSERR(("%s: failed with status %d\n", __FUNCTION__, urbstatus)); ++ status = DBUS_ERR; ++ break; ++#endif /* INTR_EP_ENABLE */ ++ } ++ ++ if (usbos_info->cbarg && usbos_info->cbs) { ++ if (usbos_info->cbs->ctl_complete) ++ usbos_info->cbs->ctl_complete(usbos_info->cbarg, type, status); ++ } ++} ++ ++/** called by Linux */ ++static void ++dbus_usbos_ctlread_complete(CALLBACK_ARGS) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *)urb->context; ++ ++ ASSERT(urb); ++ usbos_info = (usbos_info_t *)urb->context; ++ ++ dbus_usbos_ctl_complete(usbos_info, DBUS_CBCTL_READ, urb->status); ++ ++#ifdef USBOS_THREAD ++ if (usbos_info->rxctl_deferrespok) { ++ usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | ++ USB_RECIP_INTERFACE; ++ usbos_info->ctl_read.bRequest = 1; ++ } ++#endif ++ ++ up(&usbos_info->ctl_lock); ++ ++ USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); ++} ++ ++/** called by Linux */ ++static void ++dbus_usbos_ctlwrite_complete(CALLBACK_ARGS) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *)urb->context; ++ ++ ASSERT(urb); ++ usbos_info = (usbos_info_t *)urb->context; ++ ++ dbus_usbos_ctl_complete(usbos_info, DBUS_CBCTL_WRITE, urb->status); ++ ++#ifdef USBOS_TX_THREAD ++ usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; ++#endif /* USBOS_TX_THREAD */ ++ ++ up(&usbos_info->ctl_lock); ++ ++ USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); ++} ++ ++#ifdef INTR_EP_ENABLE ++/** called by Linux */ ++static void ++dbus_usbos_intr_complete(CALLBACK_ARGS) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *)urb->context; ++ bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0; ++ ++ if (usbos_info == NULL || usbos_info->pub == NULL) ++ return; ++ if ((urb->status == -ENOENT && (!killed)) || urb->status == -ESHUTDOWN || ++ urb->status == -ENODEV) { ++ dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); ++ } ++ ++ if (usbos_info->pub->busstate == DBUS_STATE_DOWN) { ++ DBUSERR(("%s: intr cb when DBUS down, ignoring\n", __FUNCTION__)); ++ return; ++ } ++ dbus_usbos_ctl_complete(usbos_info, DBUS_CBINTR_POLL, urb->status); ++} ++#endif /* INTR_EP_ENABLE */ ++ ++/** ++ * when the bus is going to sleep or halt, the Linux kernel requires us to take ownership of our ++ * URBs again. Multiple code paths in this file require a list of URBs to be cancelled in a ++ * concurrency save manner. ++ */ ++static void ++dbus_usbos_unlink(struct list_head *urbreq_q, spinlock_t *lock) ++{ ++ urb_req_t *req; ++ ++ /* dbus_usbos_recv_complete() adds req back to req_freeq */ ++ while ((req = dbus_usbos_qdeq(urbreq_q, lock)) != NULL) { ++ ASSERT(req->urb != NULL); ++ USB_UNLINK_URB(req->urb); ++ } ++} ++ ++/** multiple code paths in this file require the bus to stop */ ++static void ++dbus_usbos_cancel_all_urbs(usbos_info_t *usbos_info) ++{ ++ int rxposted, txposted; ++ ++ DBUSTRACE(("%s: unlink all URBs\n", __FUNCTION__)); ++ ++#ifdef USBOS_TX_THREAD ++ usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; ++ ++ /* Yield the CPU to TX thread so all pending requests are submitted */ ++ while (!list_empty(&usbos_info->usbos_tx_list)) { ++ wake_up_interruptible(&usbos_info->usbos_tx_queue_head); ++ OSL_SLEEP(10); ++ } ++#endif /* USBOS_TX_THREAD */ ++ ++ /* tell Linux kernel to cancel a single intr, ctl and blk URB */ ++ if (usbos_info->intr_urb) ++ USB_UNLINK_URB(usbos_info->intr_urb); ++ if (usbos_info->ctl_urb) ++ USB_UNLINK_URB(usbos_info->ctl_urb); ++ if (usbos_info->blk_urb) ++ USB_UNLINK_URB(usbos_info->blk_urb); ++ ++ dbus_usbos_unlink(&usbos_info->req_txpostedq, &usbos_info->txposted_lock); ++ dbus_usbos_unlink(&usbos_info->req_rxpostedq, &usbos_info->rxposted_lock); ++ ++ /* Wait until the callbacks for all submitted URBs have been called, because the ++ * handler needs to know is an USB suspend is in progress. ++ */ ++ SPINWAIT((atomic_read(&usbos_info->txposted) != 0 || ++ atomic_read(&usbos_info->rxposted) != 0), 10000); ++ ++ txposted = atomic_read(&usbos_info->txposted); ++ rxposted = atomic_read(&usbos_info->rxposted); ++ if (txposted != 0 || rxposted != 0) { ++ DBUSERR(("%s ERROR: REQs posted, rx=%d tx=%d!\n", ++ __FUNCTION__, rxposted, txposted)); ++ } ++} /* dbus_usbos_cancel_all_urbs */ ++ ++/** multiple code paths require the bus to stop */ ++static void ++dbusos_stop(usbos_info_t *usbos_info) ++{ ++ urb_req_t *req; ++ int rxposted; ++ req = NULL; ++ BCM_REFERENCE(req); ++ ++ ASSERT(usbos_info); ++ ++ dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); ++ ++ dbus_usbos_cancel_all_urbs(usbos_info); ++ ++#ifdef USBOS_THREAD ++ /* yield the CPU to rx packet thread */ ++ while (1) { ++ if (atomic_read(&usbos_info->usbos_list_cnt) <= 0) break; ++ wake_up_interruptible(&usbos_info->usbos_queue_head); ++ OSL_SLEEP(3); ++ } ++#endif /* USBOS_THREAD */ ++ ++ rxposted = atomic_read(&usbos_info->rxposted); ++ if (rxposted > 0) { ++ DBUSERR(("%s ERROR: rx REQs posted=%d in stop!\n", __FUNCTION__, ++ rxposted)); ++ } ++ ++ ASSERT(atomic_read(&usbos_info->txposted) == 0 && rxposted == 0); ++ ++} /* dbusos_stop */ ++ ++#if defined(USB_SUSPEND_AVAILABLE) ++ ++/** ++ * Linux kernel sports a 'USB auto suspend' feature. See: http://lwn.net/Articles/373550/ ++ * The suspend method is called by the Linux kernel to warn the driver that the device is going to ++ * be suspended. If the driver returns a negative error code, the suspend will be aborted. If the ++ * driver returns 0, it must cancel all outstanding URBs (usb_kill_urb()) and not submit any more. ++ */ ++static int ++dbus_usbos_suspend(struct usb_interface *intf, ++ pm_message_t message) ++{ ++ DBUSERR(("%s suspend state: %d\n", __FUNCTION__, g_probe_info.suspend_state)); ++ /* DHD for full dongle model */ ++ g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPEND_PENDING; ++ dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_SLEEP); ++ dbus_usbos_cancel_all_urbs((usbos_info_t*)g_probe_info.usbos_info); ++ g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPENDED; ++ ++ return 0; ++} ++ ++/** ++ * The resume method is called to tell the driver that the device has been resumed and the driver ++ * can return to normal operation. URBs may once more be submitted. ++ */ ++static int dbus_usbos_resume(struct usb_interface *intf) ++{ ++ DBUSERR(("%s Device resumed\n", __FUNCTION__)); ++ ++ dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_UP); ++ g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; ++ return 0; ++} ++ ++/** ++* This function is directly called by the Linux kernel, when the suspended device has been reset ++* instead of being resumed ++*/ ++static int dbus_usbos_reset_resume(struct usb_interface *intf) ++{ ++ DBUSERR(("%s Device reset resumed\n", __FUNCTION__)); ++ ++ /* The device may have lost power, so a firmware download may be required */ ++ dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_DL_NEEDED); ++ g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; ++ return 0; ++} ++ ++#endif /* USB_SUSPEND_AVAILABLE */ ++ ++/** ++ * Called by Linux kernel at initialization time, kernel wants to know if our driver will accept the ++ * caller supplied USB interface. Note that USB drivers are bound to interfaces, and not to USB ++ * devices. ++ */ ++#ifdef KERNEL26 ++#define DBUS_USBOS_PROBE() static int dbus_usbos_probe(struct usb_interface *intf, const struct usb_device_id *id) ++#define DBUS_USBOS_DISCONNECT() static void dbus_usbos_disconnect(struct usb_interface *intf) ++#else ++#define DBUS_USBOS_PROBE() static void * dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum, const struct usb_device_id *id) ++#define DBUS_USBOS_DISCONNECT() static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr) ++#endif /* KERNEL26 */ ++ ++DBUS_USBOS_PROBE() ++{ ++ int ep; ++ struct usb_endpoint_descriptor *endpoint; ++ int ret = 0; ++#ifdef KERNEL26 ++ struct usb_device *usb = interface_to_usbdev(intf); ++#else ++ int claimed = 0; ++#endif ++ int num_of_eps; ++#ifdef BCMUSBDEV_COMPOSITE ++ int wlan_if = -1; ++ bool intr_ep = FALSE; ++#endif /* BCMUSBDEV_COMPOSITE */ ++ wifi_adapter_info_t *adapter; ++ ++ DHD_MUTEX_LOCK(); ++ ++ DBUSERR(("%s: bus num(busnum)=%d, slot num (portnum)=%d\n", __FUNCTION__, ++ usb->bus->busnum, usb->portnum)); ++ adapter = dhd_wifi_platform_attach_adapter(USB_BUS, usb->bus->busnum, ++ usb->portnum, WIFI_STATUS_POWER_ON); ++ if (adapter == NULL) { ++ DBUSERR(("%s: can't find adapter info for this chip\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++#ifdef BCMUSBDEV_COMPOSITE ++ wlan_if = dbus_usbos_intf_wlan(usb); ++#ifdef KERNEL26 ++ if ((wlan_if >= 0) && (IFPTR(usb, wlan_if) == intf)) ++#else ++ if (wlan_if == ifnum) ++#endif /* KERNEL26 */ ++ { ++#endif /* BCMUSBDEV_COMPOSITE */ ++ g_probe_info.usb = usb; ++ g_probe_info.dldone = TRUE; ++#ifdef BCMUSBDEV_COMPOSITE ++ } else { ++ DBUSTRACE(("dbus_usbos_probe: skip probe for non WLAN interface\n")); ++ ret = BCME_UNSUPPORTED; ++ goto fail; ++ } ++#endif /* BCMUSBDEV_COMPOSITE */ ++ ++#ifdef KERNEL26 ++ g_probe_info.intf = intf; ++#endif /* KERNEL26 */ ++ ++#ifdef BCMUSBDEV_COMPOSITE ++ if (IFDESC(usb, wlan_if).bInterfaceNumber > USB_COMPIF_MAX) ++#else ++ if (IFDESC(usb, CONTROL_IF).bInterfaceNumber) ++#endif /* BCMUSBDEV_COMPOSITE */ ++ { ++ ret = -1; ++ goto fail; ++ } ++ if (id != NULL) { ++ g_probe_info.vid = id->idVendor; ++ g_probe_info.pid = id->idProduct; ++ } ++ ++#ifdef KERNEL26 ++ usb_set_intfdata(intf, &g_probe_info); ++#endif ++ ++ /* Check that the device supports only one configuration */ ++ if (usb->descriptor.bNumConfigurations != 1) { ++ ret = -1; ++ goto fail; ++ } ++ ++ if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) { ++#ifdef BCMUSBDEV_COMPOSITE ++ if ((usb->descriptor.bDeviceClass != USB_CLASS_MISC) && ++ (usb->descriptor.bDeviceClass != USB_CLASS_WIRELESS)) { ++#endif /* BCMUSBDEV_COMPOSITE */ ++ ret = -1; ++ goto fail; ++#ifdef BCMUSBDEV_COMPOSITE ++ } ++#endif /* BCMUSBDEV_COMPOSITE */ ++ } ++ ++ /* ++ * Only the BDC interface configuration is supported: ++ * Device class: USB_CLASS_VENDOR_SPEC ++ * if0 class: USB_CLASS_VENDOR_SPEC ++ * if0/ep0: control ++ * if0/ep1: bulk in ++ * if0/ep2: bulk out (ok if swapped with bulk in) ++ */ ++ if (CONFIGDESC(usb)->bNumInterfaces != 1) { ++#ifdef BCMUSBDEV_COMPOSITE ++ if (CONFIGDESC(usb)->bNumInterfaces > USB_COMPIF_MAX) { ++#endif /* BCMUSBDEV_COMPOSITE */ ++ ret = -1; ++ goto fail; ++#ifdef BCMUSBDEV_COMPOSITE ++ } ++#endif /* BCMUSBDEV_COMPOSITE */ ++ } ++ ++ /* Check interface */ ++#ifndef KERNEL26 ++#ifdef BCMUSBDEV_COMPOSITE ++ if (usb_interface_claimed(IFPTR(usb, wlan_if))) ++#else ++ if (usb_interface_claimed(IFPTR(usb, CONTROL_IF))) ++#endif /* BCMUSBDEV_COMPOSITE */ ++ { ++ ret = -1; ++ goto fail; ++ } ++#endif /* !KERNEL26 */ ++ ++#ifdef BCMUSBDEV_COMPOSITE ++ if ((IFDESC(usb, wlan_if).bInterfaceClass != USB_CLASS_VENDOR_SPEC || ++ IFDESC(usb, wlan_if).bInterfaceSubClass != 2 || ++ IFDESC(usb, wlan_if).bInterfaceProtocol != 0xff) && ++ (IFDESC(usb, wlan_if).bInterfaceClass != USB_CLASS_MISC || ++ IFDESC(usb, wlan_if).bInterfaceSubClass != USB_SUBCLASS_COMMON || ++ IFDESC(usb, wlan_if).bInterfaceProtocol != USB_PROTO_IAD)) ++#else ++ if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC || ++ IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 || ++ IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) ++#endif /* BCMUSBDEV_COMPOSITE */ ++ { ++#ifdef BCMUSBDEV_COMPOSITE ++ DBUSERR(("%s: invalid control interface: class %d, subclass %d, proto %d\n", ++ __FUNCTION__, ++ IFDESC(usb, wlan_if).bInterfaceClass, ++ IFDESC(usb, wlan_if).bInterfaceSubClass, ++ IFDESC(usb, wlan_if).bInterfaceProtocol)); ++#else ++ DBUSERR(("%s: invalid control interface: class %d, subclass %d, proto %d\n", ++ __FUNCTION__, ++ IFDESC(usb, CONTROL_IF).bInterfaceClass, ++ IFDESC(usb, CONTROL_IF).bInterfaceSubClass, ++ IFDESC(usb, CONTROL_IF).bInterfaceProtocol)); ++#endif /* BCMUSBDEV_COMPOSITE */ ++ ret = -1; ++ goto fail; ++ } ++ ++ /* Check control endpoint */ ++#ifdef BCMUSBDEV_COMPOSITE ++ endpoint = &IFEPDESC(usb, wlan_if, 0); ++#else ++ endpoint = &IFEPDESC(usb, CONTROL_IF, 0); ++#endif /* BCMUSBDEV_COMPOSITE */ ++ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) { ++#ifdef BCMUSBDEV_COMPOSITE ++ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != ++ USB_ENDPOINT_XFER_BULK) { ++#endif /* BCMUSBDEV_COMPOSITE */ ++ DBUSERR(("%s: invalid control endpoint %d\n", ++ __FUNCTION__, endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)); ++ ret = -1; ++ goto fail; ++#ifdef BCMUSBDEV_COMPOSITE ++ } ++#endif /* BCMUSBDEV_COMPOSITE */ ++ } ++ ++#ifdef BCMUSBDEV_COMPOSITE ++ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { ++#endif /* BCMUSBDEV_COMPOSITE */ ++ g_probe_info.intr_pipe = ++ usb_rcvintpipe(usb, endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); ++#ifdef BCMUSBDEV_COMPOSITE ++ intr_ep = TRUE; ++ } ++#endif /* BCMUSBDEV_COMPOSITE */ ++ ++#ifndef KERNEL26 ++ /* Claim interface */ ++#ifdef BCMUSBDEV_COMPOSITE ++ usb_driver_claim_interface(&dbus_usbdev, IFPTR(usb, wlan_if), &g_probe_info); ++#else ++ usb_driver_claim_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF), &g_probe_info); ++#endif /* BCMUSBDEV_COMPOSITE */ ++ claimed = 1; ++#endif /* !KERNEL26 */ ++ g_probe_info.rx_pipe = 0; ++ g_probe_info.rx_pipe2 = 0; ++ g_probe_info.tx_pipe = 0; ++#ifdef BCMUSBDEV_COMPOSITE ++ if (intr_ep) ++ ep = 1; ++ else ++ ep = 0; ++ num_of_eps = IFDESC(usb, wlan_if).bNumEndpoints - 1; ++#else ++ num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1; ++#endif /* BCMUSBDEV_COMPOSITE */ ++ ++ if ((num_of_eps != 2) && (num_of_eps != 3)) { ++#ifdef BCMUSBDEV_COMPOSITE ++ if (num_of_eps > 7) ++#endif /* BCMUSBDEV_COMPOSITE */ ++ ASSERT(0); ++ } ++ /* Check data endpoints and get pipes */ ++#ifdef BCMUSBDEV_COMPOSITE ++ for (; ep <= num_of_eps; ep++) ++#else ++ for (ep = 1; ep <= num_of_eps; ep++) ++#endif /* BCMUSBDEV_COMPOSITE */ ++ { ++#ifdef BCMUSBDEV_COMPOSITE ++ endpoint = &IFEPDESC(usb, wlan_if, ep); ++#else ++ endpoint = &IFEPDESC(usb, BULK_IF, ep); ++#endif /* BCMUSBDEV_COMPOSITE */ ++ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != ++ USB_ENDPOINT_XFER_BULK) { ++ DBUSERR(("%s: invalid data endpoint %d\n", ++ __FUNCTION__, ep)); ++ ret = -1; ++ goto fail; ++ } ++ ++ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { ++ /* direction: dongle->host */ ++ if (!g_probe_info.rx_pipe) { ++ g_probe_info.rx_pipe = usb_rcvbulkpipe(usb, ++ (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)); ++ } else { ++ g_probe_info.rx_pipe2 = usb_rcvbulkpipe(usb, ++ (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)); ++ } ++ ++ } else ++ g_probe_info.tx_pipe = usb_sndbulkpipe(usb, (endpoint->bEndpointAddress & ++ USB_ENDPOINT_NUMBER_MASK)); ++ } ++ ++ /* Allocate interrupt URB and data buffer */ ++ /* RNDIS says 8-byte intr, our old drivers used 4-byte */ ++#ifdef BCMUSBDEV_COMPOSITE ++ g_probe_info.intr_size = (IFEPDESC(usb, wlan_if, 0).wMaxPacketSize == 16) ? 8 : 4; ++ g_probe_info.interval = IFEPDESC(usb, wlan_if, 0).bInterval; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)) ++ usb->quirks |= USB_QUIRK_NO_SET_INTF; ++#endif ++#else ++ g_probe_info.intr_size = (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == 16) ? 8 : 4; ++ g_probe_info.interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval; ++#endif /* BCMUSBDEV_COMPOSITE */ ++ ++#ifndef KERNEL26 ++ /* usb_fill_int_urb does the interval decoding in 2.6 */ ++ if (usb->speed == USB_SPEED_HIGH) ++ g_probe_info.interval = 1 << (g_probe_info.interval - 1); ++#endif ++ if (usb->speed == USB_SPEED_SUPER) { ++ g_probe_info.device_speed = SUPER_SPEED; ++ DBUSERR(("super speed device detected\n")); ++ } else if (usb->speed == USB_SPEED_HIGH) { ++ g_probe_info.device_speed = HIGH_SPEED; ++ DBUSERR(("high speed device detected\n")); ++ } else { ++ g_probe_info.device_speed = FULL_SPEED; ++ DBUSERR(("full speed device detected\n")); ++ } ++ if (g_probe_info.dereged == FALSE && probe_cb) { ++ disc_arg = probe_cb(probe_arg, "", USB_BUS, usb->bus->busnum, usb->portnum, 0); ++ } ++ ++ g_probe_info.disc_cb_done = FALSE; ++ ++#ifdef KERNEL26 ++ intf->needs_remote_wakeup = 1; ++#endif /* KERNEL26 */ ++ DHD_MUTEX_UNLOCK(); ++ ++ /* Success */ ++#ifdef KERNEL26 ++ return DBUS_OK; ++#else ++ usb_inc_dev_use(usb); ++ return &g_probe_info; ++#endif ++ ++fail: ++ printf("%s: Exit ret=%d\n", __FUNCTION__, ret); ++#ifdef BCMUSBDEV_COMPOSITE ++ if (ret != BCME_UNSUPPORTED) ++#endif /* BCMUSBDEV_COMPOSITE */ ++ DBUSERR(("%s: failed with errno %d\n", __FUNCTION__, ret)); ++#ifndef KERNEL26 ++ if (claimed) ++#ifdef BCMUSBDEV_COMPOSITE ++ usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, wlan_if)); ++#else ++ usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF)); ++#endif /* BCMUSBDEV_COMPOSITE */ ++#endif /* !KERNEL26 */ ++ ++ DHD_MUTEX_UNLOCK(); ++#ifdef KERNEL26 ++ usb_set_intfdata(intf, NULL); ++ return ret; ++#else ++ return NULL; ++#endif ++} /* dbus_usbos_probe */ ++ ++/** Called by Linux kernel, is the counter part of dbus_usbos_probe() */ ++DBUS_USBOS_DISCONNECT() ++{ ++#ifdef KERNEL26 ++ struct usb_device *usb = interface_to_usbdev(intf); ++ probe_info_t *probe_usb_init_data = usb_get_intfdata(intf); ++#else ++ probe_info_t *probe_usb_init_data = (probe_info_t *) ptr; ++#endif ++ usbos_info_t *usbos_info; ++ ++ DHD_MUTEX_LOCK(); ++ ++ DBUSERR(("%s: bus num(busnum)=%d, slot num (portnum)=%d\n", __FUNCTION__, ++ usb->bus->busnum, usb->portnum)); ++ ++ if (probe_usb_init_data) { ++ usbos_info = (usbos_info_t *) probe_usb_init_data->usbos_info; ++ if (usbos_info) { ++ if ((probe_usb_init_data->dereged == FALSE) && disconnect_cb && disc_arg) { ++ disconnect_cb(disc_arg); ++ disc_arg = NULL; ++ probe_usb_init_data->disc_cb_done = TRUE; ++ } ++ } ++ } ++ ++ if (usb) { ++#ifndef KERNEL26 ++#ifdef BCMUSBDEV_COMPOSITE ++ usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, wlan_if)); ++#else ++ usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF)); ++#endif /* BCMUSBDEV_COMPOSITE */ ++ usb_dec_dev_use(usb); ++#endif /* !KERNEL26 */ ++ } ++ DHD_MUTEX_UNLOCK(); ++} /* dbus_usbos_disconnect */ ++ ++#define LOOPBACK_PKT_START 0xBABE1234 ++ ++bool is_loopback_pkt(void *buf) ++{ ++ ++ uint32 *buf_ptr = (uint32 *) buf; ++ ++ if (*buf_ptr == LOOPBACK_PKT_START) ++ return TRUE; ++ return FALSE; ++ ++} ++ ++int matches_loopback_pkt(void *buf) ++{ ++ int i, j; ++ unsigned char *cbuf = (unsigned char *) buf; ++ ++ for (i = 4; i < loopback_size; i++) { ++ if (cbuf[i] != (i % 256)) { ++ printf("%s: mismatch at i=%d %d : ", __FUNCTION__, i, cbuf[i]); ++ for (j = i; ((j < i+ 16) && (j < loopback_size)); j++) { ++ printf("%d ", cbuf[j]); ++ } ++ printf("\n"); ++ return 0; ++ } ++ } ++ loopback_rx_cnt++; ++ return 1; ++} ++ ++int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) usbos_info_ptr; ++ unsigned char *buf; ++ int j; ++ void* p = NULL; ++ int rc, last_rx_cnt; ++ int tx_failed_cnt; ++ int max_size = 1650; ++ int usb_packet_size = 512; ++ int min_packet_size = 10; ++ ++ if (size % usb_packet_size == 0) { ++ size = size - 1; ++ DBUSERR(("%s: overriding size=%d \n", __FUNCTION__, size)); ++ } ++ ++ if (size < min_packet_size) { ++ size = min_packet_size; ++ DBUSERR(("%s: overriding size=%d\n", __FUNCTION__, min_packet_size)); ++ } ++ if (size > max_size) { ++ size = max_size; ++ DBUSERR(("%s: overriding size=%d\n", __FUNCTION__, max_size)); ++ } ++ ++ loopback_tx_cnt = 0; ++ loopback_rx_cnt = 0; ++ tx_failed_cnt = 0; ++ loopback_size = size; ++ ++ while (loopback_tx_cnt < cnt) { ++ uint32 *x; ++ int pkt_size = loopback_size; ++ ++ p = PKTGET(usbos_info->pub->osh, pkt_size, TRUE); ++ if (p == NULL) { ++ DBUSERR(("%s:%d Failed to allocate packet sz=%d\n", ++ __FUNCTION__, __LINE__, pkt_size)); ++ return BCME_ERROR; ++ } ++ x = (uint32*) PKTDATA(usbos_info->pub->osh, p); ++ *x = LOOPBACK_PKT_START; ++ buf = (unsigned char*) x; ++ for (j = 4; j < pkt_size; j++) { ++ buf[j] = j % 256; ++ } ++ rc = dbus_send_buf(usbos_info->pub, buf, pkt_size, p); ++ if (rc != BCME_OK) { ++ DBUSERR(("%s:%d Freeing packet \n", __FUNCTION__, __LINE__)); ++ PKTFREE(usbos_info->pub->osh, p, TRUE); ++ dbus_usbos_wait(usbos_info, 1); ++ tx_failed_cnt++; ++ } else { ++ loopback_tx_cnt++; ++ tx_failed_cnt = 0; ++ } ++ if (tx_failed_cnt == 5) { ++ DBUSERR(("%s : Failed to send loopback packets cnt=%d loopback_tx_cnt=%d\n", ++ __FUNCTION__, cnt, loopback_tx_cnt)); ++ break; ++ } ++ } ++ printf("Transmitted %d loopback packets of size %d\n", loopback_tx_cnt, loopback_size); ++ ++ last_rx_cnt = loopback_rx_cnt; ++ while (loopback_rx_cnt < loopback_tx_cnt) { ++ dbus_usbos_wait(usbos_info, 1); ++ if (loopback_rx_cnt <= last_rx_cnt) { ++ DBUSERR(("%s: Matched rx cnt stuck at %d \n", __FUNCTION__, last_rx_cnt)); ++ return BCME_ERROR; ++ } ++ last_rx_cnt = loopback_rx_cnt; ++ } ++ printf("Received %d loopback packets of size %d\n", loopback_tx_cnt, loopback_size); ++ ++ return BCME_OK; ++} /* dbus_usbos_loopback_tx */ ++ ++/** ++ * Higher layer (dbus_usb.c) wants to transmit an I/O Request Block ++ * @param[in] txirb txirb->pkt, if non-zero, contains a single or a chain of packets ++ */ ++static int ++dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ urb_req_t *req, *req_zlp = NULL; ++ int ret = DBUS_OK; ++ unsigned long flags; ++ void *pkt; ++ uint32 buffer_length; ++ uint8 *buf; ++ ++ if ((usbos_info == NULL) || !usbos_info->tx_pipe) { ++ return DBUS_ERR; ++ } ++ ++ if (txirb->pkt != NULL) { ++ buffer_length = pkttotlen(usbos_info->pub->osh, txirb->pkt); ++ /* In case of multiple packets the values below may be overwritten */ ++ txirb->send_buf = NULL; ++ buf = PKTDATA(usbos_info->pub->osh, txirb->pkt); ++ } else { /* txirb->buf != NULL */ ++ ASSERT(txirb->buf != NULL); ++ ASSERT(txirb->send_buf == NULL); ++ buffer_length = txirb->len; ++ buf = txirb->buf; ++ } ++ ++ if (!(req = dbus_usbos_qdeq(&usbos_info->req_txfreeq, &usbos_info->txfree_lock))) { ++ DBUSERR(("%s No free URB!\n", __FUNCTION__)); ++ return DBUS_ERR_TXDROP; ++ } ++ ++ /* If not using standard Linux kernel functionality for handling Zero Length Packet(ZLP), ++ * the dbus needs to generate ZLP when length is multiple of MaxPacketSize. ++ */ ++#ifndef WL_URB_ZPKT ++ if (!(buffer_length % usbos_info->maxps)) { ++ if (!(req_zlp = ++ dbus_usbos_qdeq(&usbos_info->req_txfreeq, &usbos_info->txfree_lock))) { ++ DBUSERR(("%s No free URB for ZLP!\n", __FUNCTION__)); ++ dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); ++ return DBUS_ERR_TXDROP; ++ } ++ ++ /* No txirb, so that dbus_usbos_send_complete can differentiate between ++ * DATA and ZLP. ++ */ ++ req_zlp->arg = NULL; ++ req_zlp->usbinfo = usbos_info; ++ req_zlp->buf_len = 0; ++ ++ usb_fill_bulk_urb(req_zlp->urb, usbos_info->usb, usbos_info->tx_pipe, NULL, ++ 0, (usb_complete_t)dbus_usbos_send_complete, req_zlp); ++ ++ req_zlp->urb->transfer_flags |= URB_QUEUE_BULK; ++ } ++#endif /* !WL_URB_ZPKT */ ++ ++#ifndef USBOS_TX_THREAD ++ /* Disable USB autosuspend until this request completes, request USB resume if needed. ++ * Because this call runs asynchronously, there is no guarantee the bus is resumed before ++ * the URB is submitted, and the URB might be dropped. Use USBOS_TX_THREAD to avoid ++ * this. ++ */ ++ USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf); ++#endif /* !USBOS_TX_THREAD */ ++ ++ spin_lock_irqsave(&usbos_info->txlock, flags); ++ ++ req->arg = txirb; ++ req->usbinfo = usbos_info; ++ req->buf_len = 0; ++ ++ /* Prepare the URB */ ++ if (txirb->pkt != NULL) { ++ uint32 pktlen; ++ uint8 *transfer_buf; ++ ++ /* For multiple packets, allocate contiguous buffer and copy packet data to it */ ++ if (PKTNEXT(usbos_info->pub->osh, txirb->pkt)) { ++ transfer_buf = MALLOC(usbos_info->pub->osh, buffer_length); ++ if (!transfer_buf) { ++ ret = DBUS_ERR_TXDROP; ++ DBUSERR(("fail to alloc to usb buffer\n")); ++ goto fail; ++ } ++ ++ pkt = txirb->pkt; ++ txirb->send_buf = transfer_buf; ++ req->buf_len = buffer_length; ++ ++ while (pkt) { ++ pktlen = PKTLEN(usbos_info->pub->osh, pkt); ++ bcopy(PKTDATA(usbos_info->pub->osh, pkt), transfer_buf, pktlen); ++ transfer_buf += pktlen; ++ pkt = PKTNEXT(usbos_info->pub->osh, pkt); ++ } ++ ++ ASSERT(((uint8 *) txirb->send_buf + buffer_length) == transfer_buf); ++ ++ /* Overwrite buf pointer with pointer to allocated contiguous transfer_buf ++ */ ++ buf = txirb->send_buf; ++ } ++ } ++ ++ usb_fill_bulk_urb(req->urb, usbos_info->usb, usbos_info->tx_pipe, buf, ++ buffer_length, (usb_complete_t)dbus_usbos_send_complete, req); ++ ++ req->urb->transfer_flags |= URB_QUEUE_BULK; ++ ++#ifdef USBOS_TX_THREAD ++ /* Enqueue TX request, the TX thread will resume the bus if needed and submit ++ * it asynchronously ++ */ ++ dbus_usbos_qenq(&usbos_info->usbos_tx_list, req, &usbos_info->usbos_tx_list_lock); ++ if (req_zlp != NULL) { ++ dbus_usbos_qenq(&usbos_info->usbos_tx_list, req_zlp, ++ &usbos_info->usbos_tx_list_lock); ++ } ++ spin_unlock_irqrestore(&usbos_info->txlock, flags); ++ ++ wake_up_interruptible(&usbos_info->usbos_tx_queue_head); ++ return DBUS_OK; ++#else ++ if ((ret = USB_SUBMIT_URB(req->urb))) { ++ ret = DBUS_ERR_TXDROP; ++ goto fail; ++ } ++ ++ dbus_usbos_qenq(&usbos_info->req_txpostedq, req, &usbos_info->txposted_lock); ++ atomic_inc(&usbos_info->txposted); ++ ++ if (req_zlp != NULL) { ++ if ((ret = USB_SUBMIT_URB(req_zlp->urb))) { ++ DBUSERR(("failed to submit ZLP URB!\n")); ++ ASSERT(0); ++ ret = DBUS_ERR_TXDROP; ++ goto fail2; ++ } ++ ++ dbus_usbos_qenq(&usbos_info->req_txpostedq, req_zlp, &usbos_info->txposted_lock); ++ /* Also increment txposted for zlp packet, as it will be decremented in ++ * dbus_usbos_send_complete() ++ */ ++ atomic_inc(&usbos_info->txposted); ++ } ++ ++ spin_unlock_irqrestore(&usbos_info->txlock, flags); ++ return DBUS_OK; ++#endif /* USBOS_TX_THREAD */ ++ ++fail: ++ if (txirb->send_buf != NULL) { ++ MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); ++ txirb->send_buf = NULL; ++ req->buf_len = 0; ++ } ++ dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); ++#ifndef USBOS_TX_THREAD ++fail2: ++#endif ++ if (req_zlp != NULL) { ++ dbus_usbos_qenq(&usbos_info->req_txfreeq, req_zlp, &usbos_info->txfree_lock); ++ } ++ ++ spin_unlock_irqrestore(&usbos_info->txlock, flags); ++ ++#ifndef USBOS_TX_THREAD ++ USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); ++#endif /* !USBOS_TX_THREAD */ ++ ++ return ret; ++} /* dbus_usbos_intf_send_irb */ ++ ++/** Higher layer (dbus_usb.c) recycles a received (and used) packet. */ ++static int ++dbus_usbos_intf_recv_irb(void *bus, dbus_irb_rx_t *rxirb) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ int ret = DBUS_OK; ++ ++ if (usbos_info == NULL) ++ return DBUS_ERR; ++ ++ ret = dbus_usbos_recv_urb_submit(usbos_info, rxirb, 0); ++ return ret; ++} ++ ++static int ++dbus_usbos_intf_recv_irb_from_ep(void *bus, dbus_irb_rx_t *rxirb, uint32 ep_idx) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ int ret = DBUS_OK; ++ ++ if (usbos_info == NULL) ++ return DBUS_ERR; ++ ++#ifdef INTR_EP_ENABLE ++ /* By specifying the ep_idx value of 0xff, the cdc layer is asking to ++ * submit an interrupt URB ++ */ ++ if (rxirb == NULL && ep_idx == 0xff) { ++ /* submit intr URB */ ++ if ((ret = USB_SUBMIT_URB(usbos_info->intr_urb)) < 0) { ++ DBUSERR(("%s intr USB_SUBMIT_URB failed, status %d\n", ++ __FUNCTION__, ret)); ++ } ++ return ret; ++ } ++#else ++ if (rxirb == NULL) { ++ return DBUS_ERR; ++ } ++#endif /* INTR_EP_ENABLE */ ++ ++ ret = dbus_usbos_recv_urb_submit(usbos_info, rxirb, ep_idx); ++ return ret; ++} ++ ++/** Higher layer (dbus_usb.c) want to cancel an IRB */ ++static int ++dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ ++ if (usbos_info == NULL) ++ return DBUS_ERR; ++ ++ return DBUS_ERR; ++} ++ ++/** Only one CTL transfer can be pending at any time. This function may block. */ ++static int ++dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ uint16 size; ++#ifndef USBOS_TX_THREAD ++ int status; ++#endif /* USBOS_TX_THREAD */ ++ ++ if ((usbos_info == NULL) || (buf == NULL) || (len == 0)) ++ return DBUS_ERR; ++ ++ if (usbos_info->ctl_urb == NULL) ++ return DBUS_ERR; ++ ++ /* Block until a pending CTL transfer has completed */ ++ if (down_interruptible(&usbos_info->ctl_lock) != 0) { ++ return DBUS_ERR_TXCTLFAIL; ++ } ++ ++#ifdef USBOS_TX_THREAD ++ ASSERT(usbos_info->ctl_state == USBOS_REQUEST_STATE_UNSCHEDULED); ++#else ++ /* Disable USB autosuspend until this request completes, request USB resume if needed. ++ * Because this call runs asynchronously, there is no guarantee the bus is resumed before ++ * the URB is submitted, and the URB might be dropped. Use USBOS_TX_THREAD to avoid ++ * this. ++ */ ++ USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf); ++#endif /* USBOS_TX_THREAD */ ++ ++ size = len; ++ usbos_info->ctl_write.wLength = cpu_to_le16p(&size); ++ usbos_info->ctl_urb->transfer_buffer_length = size; ++ ++ usb_fill_control_urb(usbos_info->ctl_urb, ++ usbos_info->usb, ++ usb_sndctrlpipe(usbos_info->usb, 0), ++ (unsigned char *) &usbos_info->ctl_write, ++ buf, size, (usb_complete_t)dbus_usbos_ctlwrite_complete, usbos_info); ++ ++#ifdef USBOS_TX_THREAD ++ /* Enqueue CTRL request for transmission by the TX thread. The ++ * USB bus will first be resumed if needed. ++ */ ++ usbos_info->ctl_state = USBOS_REQUEST_STATE_SCHEDULED; ++ wake_up_interruptible(&usbos_info->usbos_tx_queue_head); ++#else ++ status = USB_SUBMIT_URB(usbos_info->ctl_urb); ++ if (status < 0) { ++ DBUSERR(("%s: usb_submit_urb failed %d\n", __FUNCTION__, status)); ++ up(&usbos_info->ctl_lock); ++ ++ USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); ++ ++ return DBUS_ERR_TXCTLFAIL; ++ } ++#endif /* USBOS_TX_THREAD */ ++ ++ return DBUS_OK; ++} /* dbus_usbos_intf_send_ctl */ ++ ++/** This function does not seem to be called by anyone, including dbus_usb.c */ ++static int ++dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ int status; ++ uint16 size; ++ ++ if ((usbos_info == NULL) || (buf == NULL) || (len == 0)) ++ return DBUS_ERR; ++ ++ if (usbos_info->ctl_urb == NULL) ++ return DBUS_ERR; ++ ++ /* Block until a pending CTRL transfer has completed */ ++ if (down_interruptible(&usbos_info->ctl_lock) != 0) { ++ return DBUS_ERR_TXCTLFAIL; ++ } ++ ++ /* Disable USB autosuspend until this request completes, request USB resume if needed. */ ++ USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf); ++ ++ size = len; ++ usbos_info->ctl_read.wLength = cpu_to_le16p(&size); ++ usbos_info->ctl_urb->transfer_buffer_length = size; ++ ++ if (usbos_info->rxctl_deferrespok) { ++ /* BMAC model */ ++ usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR | ++ USB_RECIP_INTERFACE; ++ usbos_info->ctl_read.bRequest = DL_DEFER_RESP_OK; ++ } else { ++ /* full dongle model */ ++ usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | ++ USB_RECIP_INTERFACE; ++ usbos_info->ctl_read.bRequest = 1; ++ } ++ ++ usb_fill_control_urb(usbos_info->ctl_urb, ++ usbos_info->usb, ++ usb_rcvctrlpipe(usbos_info->usb, 0), ++ (unsigned char *) &usbos_info->ctl_read, ++ buf, size, (usb_complete_t)dbus_usbos_ctlread_complete, usbos_info); ++ ++ status = USB_SUBMIT_URB(usbos_info->ctl_urb); ++ if (status < 0) { ++ DBUSERR(("%s: usb_submit_urb failed %d\n", __FUNCTION__, status)); ++ up(&usbos_info->ctl_lock); ++ ++ USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); ++ ++ return DBUS_ERR_RXCTLFAIL; ++ } ++ ++ return DBUS_OK; ++} ++ ++static int ++dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ ++ if ((usbos_info == NULL) || (attrib == NULL)) ++ return DBUS_ERR; ++ ++ attrib->bustype = DBUS_USB; ++ attrib->vid = g_probe_info.vid; ++ attrib->pid = g_probe_info.pid; ++ attrib->devid = 0x4322; ++ ++ attrib->nchan = 1; ++ ++ /* MaxPacketSize for USB hi-speed bulk out is 512 bytes ++ * and 64-bytes for full-speed. ++ * When sending pkt > MaxPacketSize, Host SW breaks it ++ * up into multiple packets. ++ */ ++ attrib->mtu = usbos_info->maxps; ++ ++ return DBUS_OK; ++} ++ ++/** Called by higher layer (dbus_usb.c) when it wants to 'up' the USB interface to the dongle */ ++static int ++dbus_usbos_intf_up(void *bus) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ uint16 ifnum; ++#ifdef BCMUSBDEV_COMPOSITE ++ int wlan_if = 0; ++#endif ++ if (usbos_info == NULL) ++ return DBUS_ERR; ++ ++ if (usbos_info->usb == NULL) ++ return DBUS_ERR; ++ ++#if defined(INTR_EP_ENABLE) ++ /* full dongle use intr EP, bmac doesn't use it */ ++ if (usbos_info->intr_urb) { ++ int ret; ++ ++ usb_fill_int_urb(usbos_info->intr_urb, usbos_info->usb, ++ usbos_info->intr_pipe, &usbos_info->intr, ++ usbos_info->intr_size, (usb_complete_t)dbus_usbos_intr_complete, ++ usbos_info, usbos_info->interval); ++ ++ if ((ret = USB_SUBMIT_URB(usbos_info->intr_urb))) { ++ DBUSERR(("%s USB_SUBMIT_URB failed with status %d\n", __FUNCTION__, ret)); ++ return DBUS_ERR; ++ } ++ } ++#endif ++ ++ if (usbos_info->ctl_urb) { ++ usbos_info->ctl_in_pipe = usb_rcvctrlpipe(usbos_info->usb, 0); ++ usbos_info->ctl_out_pipe = usb_sndctrlpipe(usbos_info->usb, 0); ++ ++#ifdef BCMUSBDEV_COMPOSITE ++ wlan_if = dbus_usbos_intf_wlan(usbos_info->usb); ++ ifnum = cpu_to_le16(IFDESC(usbos_info->usb, wlan_if).bInterfaceNumber); ++#else ++ ifnum = cpu_to_le16(IFDESC(usbos_info->usb, CONTROL_IF).bInterfaceNumber); ++#endif /* BCMUSBDEV_COMPOSITE */ ++ /* CTL Write */ ++ usbos_info->ctl_write.bRequestType = ++ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; ++ usbos_info->ctl_write.bRequest = 0; ++ usbos_info->ctl_write.wValue = cpu_to_le16(0); ++ usbos_info->ctl_write.wIndex = cpu_to_le16p(&ifnum); ++ ++ /* CTL Read */ ++ usbos_info->ctl_read.bRequestType = ++ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; ++ usbos_info->ctl_read.bRequest = 1; ++ usbos_info->ctl_read.wValue = cpu_to_le16(0); ++ usbos_info->ctl_read.wIndex = cpu_to_le16p(&ifnum); ++ } ++ ++ /* Success, indicate usbos_info is fully up */ ++ dbus_usbos_state_change(usbos_info, DBUS_STATE_UP); ++ ++ return DBUS_OK; ++} /* dbus_usbos_intf_up */ ++ ++static int ++dbus_usbos_intf_down(void *bus) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ ++ if (usbos_info == NULL) ++ return DBUS_ERR; ++ ++ dbusos_stop(usbos_info); ++ return DBUS_OK; ++} ++ ++static int ++dbus_usbos_intf_stop(void *bus) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ ++ if (usbos_info == NULL) ++ return DBUS_ERR; ++ ++ dbusos_stop(usbos_info); ++ return DBUS_OK; ++} ++ ++ ++/** Called by higher layer (dbus_usb.c) */ ++static int ++dbus_usbos_intf_set_config(void *bus, dbus_config_t *config) ++{ ++ int err = DBUS_ERR; ++ usbos_info_t* usbos_info = bus; ++ ++ if (config->config_id == DBUS_CONFIG_ID_RXCTL_DEFERRES) { ++ usbos_info->rxctl_deferrespok = config->rxctl_deferrespok; ++ err = DBUS_OK; ++ } else if (config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) { ++ /* DBUS_CONFIG_ID_AGGR_LIMIT shouldn't be called after probe stage */ ++ ASSERT(disc_arg == NULL); ++ ASSERT(config->aggr_param.maxrxsf > 0); ++ ASSERT(config->aggr_param.maxrxsize > 0); ++ if (config->aggr_param.maxrxsize > usbos_info->rxbuf_len) { ++ int state = usbos_info->pub->busstate; ++ dbus_usbos_unlink(&usbos_info->req_rxpostedq, &usbos_info->rxposted_lock); ++ while (atomic_read(&usbos_info->rxposted)) { ++ DBUSTRACE(("%s rxposted is %d, delay 1 ms\n", __FUNCTION__, ++ atomic_read(&usbos_info->rxposted))); ++ dbus_usbos_wait(usbos_info, 1); ++ } ++ usbos_info->rxbuf_len = config->aggr_param.maxrxsize; ++ dbus_usbos_state_change(usbos_info, state); ++ } ++ err = DBUS_OK; ++ } ++ ++ return err; ++} ++ ++ ++/** Called by dbus_usb.c when it wants to download firmware into the dongle */ ++bool ++dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen) ++{ ++ int transferred; ++ int index = 0; ++ char *tmpbuf; ++ ++ if ((usbinfo == NULL) || (buffer == NULL) || (buflen == 0)) ++ return FALSE; ++ ++ tmpbuf = (char *) MALLOC(usbinfo->pub->osh, buflen); ++ if (!tmpbuf) { ++ DBUSERR(("%s: Unable to allocate memory \n", __FUNCTION__)); ++ return FALSE; ++ } ++ ++#ifdef BCM_REQUEST_FW ++ if (cmd == DL_GO) { ++ index = 1; ++ } ++#endif ++ ++ /* Disable USB autosuspend until this request completes, request USB resume if needed. */ ++ USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); ++ ++ transferred = USB_CONTROL_MSG(usbinfo->usb, usb_rcvctrlpipe(usbinfo->usb, 0), ++ cmd, (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE), ++ 0, index, ++ (void*) tmpbuf, buflen, USB_CTRL_EP_TIMEOUT); ++ if (transferred == buflen) { ++ memcpy(buffer, tmpbuf, buflen); ++ } else { ++ DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred)); ++ } ++ ++ USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); ++ ++ MFREE(usbinfo->pub->osh, tmpbuf, buflen); ++ return (transferred == buflen); ++} ++ ++/** ++ * Called by dbus_usb.c when it wants to download a buffer into the dongle (e.g. as part of the ++ * download process, when writing nvram variables). ++ */ ++int ++dbus_write_membytes(usbos_info_t* usbinfo, bool set, uint32 address, uint8 *data, uint size) ++{ ++ hwacc_t hwacc; ++ int write_bytes = 4; ++ int status; ++ int retval = 0; ++ ++ DBUSTRACE(("Enter:%s\n", __FUNCTION__)); ++ ++ /* Read is not supported */ ++ if (set == 0) { ++ DBUSERR(("Currently read is not supported!!\n")); ++ return -1; ++ } ++ ++ USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); ++ ++ hwacc.cmd = DL_CMD_WRHW; ++ hwacc.addr = address; ++ ++ DBUSTRACE(("Address:%x size:%d", hwacc.addr, size)); ++ do { ++ if (size >= 4) { ++ write_bytes = 4; ++ } else if (size >= 2) { ++ write_bytes = 2; ++ } else { ++ write_bytes = 1; ++ } ++ ++ hwacc.len = write_bytes; ++ ++ while (size >= write_bytes) { ++ hwacc.data = *((unsigned int*)data); ++ ++ status = USB_CONTROL_MSG(usbinfo->usb, usb_sndctrlpipe(usbinfo->usb, 0), ++ DL_WRHW, (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE), ++ 1, 0, (char *)&hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT); ++ ++ if (status < 0) { ++ retval = -1; ++ DBUSERR((" Ctrl write hwacc failed w/status %d @ address:%x \n", ++ status, hwacc.addr)); ++ goto err; ++ } ++ ++ hwacc.addr += write_bytes; ++ data += write_bytes; ++ size -= write_bytes; ++ } ++ } while (size > 0); ++ ++err: ++ USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); ++ ++ return retval; ++} ++ ++int ++dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value) ++{ ++ usbos_info_t *usbinfo = (usbos_info_t *) bus; ++ int ret = DBUS_OK; ++ int transferred; ++ uint32 cmd; ++ hwacc_t hwacc; ++ ++ if (usbinfo == NULL) ++ return DBUS_ERR; ++ ++ if (datalen == 1) ++ cmd = DL_RDHW8; ++ else if (datalen == 2) ++ cmd = DL_RDHW16; ++ else ++ cmd = DL_RDHW32; ++ ++ USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); ++ ++ transferred = USB_CONTROL_MSG(usbinfo->usb, usb_rcvctrlpipe(usbinfo->usb, 0), ++ cmd, (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE), ++ (uint16)(regaddr), (uint16)(regaddr >> 16), ++ (void *) &hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT); ++ ++ if (transferred >= sizeof(hwacc_t)) { ++ *value = hwacc.data; ++ } else { ++ DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred)); ++ ret = DBUS_ERR; ++ } ++ ++ USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); ++ ++ return ret; ++} ++ ++int ++dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data) ++{ ++ usbos_info_t *usbinfo = (usbos_info_t *) bus; ++ int ret = DBUS_OK; ++ int transferred; ++ uint32 cmd = DL_WRHW; ++ hwacc_t hwacc; ++ ++ if (usbinfo == NULL) ++ return DBUS_ERR; ++ ++ USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); ++ ++ hwacc.cmd = DL_WRHW; ++ hwacc.addr = regaddr; ++ hwacc.data = data; ++ hwacc.len = datalen; ++ ++ transferred = USB_CONTROL_MSG(usbinfo->usb, usb_sndctrlpipe(usbinfo->usb, 0), ++ cmd, (USB_DIR_OUT| USB_TYPE_VENDOR | USB_RECIP_INTERFACE), ++ 1, 0, ++ (void *) &hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT); ++ ++ if (transferred != sizeof(hwacc_t)) { ++ DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred)); ++ ret = DBUS_ERR; ++ } ++ ++ USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); ++ ++ return ret; ++} ++ ++int ++dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ if (in_interrupt()) ++ mdelay(ms); ++ else ++ msleep_interruptible(ms); ++#else ++ wait_ms(ms); ++#endif ++ return DBUS_OK; ++} ++ ++/** Called by dbus_usb.c as part of the firmware download process */ ++bool ++dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len) ++{ ++ bool ret = TRUE; ++ int status; ++ int transferred = 0; ++ ++ if (usbinfo == NULL) ++ return DBUS_ERR; ++ ++ USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); ++ ++ status = USB_BULK_MSG(usbinfo->usb, usbinfo->tx_pipe, ++ buffer, len, ++ &transferred, USB_BULK_EP_TIMEOUT); ++ ++ if (status < 0) { ++ DBUSERR(("%s: usb_bulk_msg failed %d\n", __FUNCTION__, status)); ++ ret = FALSE; ++ } ++ ++ USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); ++ ++ return ret; ++} ++ ++static bool ++dbus_usbos_intf_recv_needed(void *bus) ++{ ++ return FALSE; ++} ++ ++/** ++ * Higher layer (dbus_usb.c) wants to execute a function on the condition that the rx spin lock has ++ * been acquired. ++ */ ++static void* ++dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ void *ret; ++ unsigned long flags; ++ ++ if (usbos_info == NULL) ++ return NULL; ++ ++ spin_lock_irqsave(&usbos_info->rxlock, flags); ++ ret = cb(args); ++ spin_unlock_irqrestore(&usbos_info->rxlock, flags); ++ ++ return ret; ++} ++ ++static void* ++dbus_usbos_intf_exec_txlock(void *bus, exec_cb_t cb, struct exec_parms *args) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ void *ret; ++ unsigned long flags; ++ ++ if (usbos_info == NULL) ++ return NULL; ++ ++ spin_lock_irqsave(&usbos_info->txlock, flags); ++ ret = cb(args); ++ spin_unlock_irqrestore(&usbos_info->txlock, flags); ++ ++ return ret; ++} ++ ++/** ++ * if an error condition was detected in this module, the higher DBUS layer (dbus_usb.c) has to ++ * be notified. ++ */ ++int ++dbus_usbos_errhandler(void *bus, int err) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ ++ if (usbos_info == NULL) ++ return DBUS_ERR; ++ ++ if (usbos_info->cbarg && usbos_info->cbs) { ++ if (usbos_info->cbs->errhandler) ++ usbos_info->cbs->errhandler(usbos_info->cbarg, err); ++ } ++ ++ return DBUS_OK; ++} ++ ++/** ++ * if a change in bus state was detected in this module, the higher DBUS layer (dbus_usb.c) has to ++ * be notified. ++ */ ++int ++dbus_usbos_state_change(void *bus, int state) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) bus; ++ ++ if (usbos_info == NULL) ++ return DBUS_ERR; ++ ++ if (usbos_info->cbarg && usbos_info->cbs) { ++ if (usbos_info->cbs->state_change) ++ usbos_info->cbs->state_change(usbos_info->cbarg, state); ++ } ++ ++ usbos_info->pub->busstate = state; ++ return DBUS_OK; ++} ++ ++int ++dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, ++ disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) ++{ ++ bzero(&g_probe_info, sizeof(probe_info_t)); ++ ++ probe_cb = prcb; ++ disconnect_cb = discb; ++ probe_arg = prarg; ++ ++ devid_table[0].idVendor = vid; ++ devid_table[0].idProduct = pid; ++ ++ *intf = &dbus_usbos_intf; ++ ++ USB_REGISTER(); ++ ++ return DBUS_ERR_NODEVICE; ++} ++ ++int ++dbus_bus_osl_deregister() ++{ ++ g_probe_info.dereged = TRUE; ++ ++ DHD_MUTEX_LOCK(); ++ if (disconnect_cb && disc_arg && (g_probe_info.disc_cb_done == FALSE)) { ++ disconnect_cb(disc_arg); ++ disc_arg = NULL; ++ } ++ DHD_MUTEX_UNLOCK(); ++ ++ USB_DEREGISTER(); ++ ++ return DBUS_OK; ++} ++ ++void * ++dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) ++{ ++ usbos_info_t *usbos_info; ++ ++ if (g_probe_info.dldone == FALSE) { ++ DBUSERR(("%s: err device not downloaded!\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ /* Sanity check for BUS_INFO() */ ++ ASSERT(OFFSETOF(usbos_info_t, pub) == 0); ++ ++ usbos_info = MALLOC(pub->osh, sizeof(usbos_info_t)); ++ if (usbos_info == NULL) ++ return NULL; ++ ++ bzero(usbos_info, sizeof(usbos_info_t)); ++ ++ usbos_info->pub = pub; ++ usbos_info->cbarg = cbarg; ++ usbos_info->cbs = cbs; ++ ++ /* Needed for disconnect() */ ++ g_probe_info.usbos_info = usbos_info; ++ ++ /* Update USB Info */ ++ usbos_info->usb = g_probe_info.usb; ++ usbos_info->rx_pipe = g_probe_info.rx_pipe; ++ usbos_info->rx_pipe2 = g_probe_info.rx_pipe2; ++ usbos_info->tx_pipe = g_probe_info.tx_pipe; ++ usbos_info->intr_pipe = g_probe_info.intr_pipe; ++ usbos_info->intr_size = g_probe_info.intr_size; ++ usbos_info->interval = g_probe_info.interval; ++ usbos_info->pub->device_speed = g_probe_info.device_speed; ++ if (usbos_info->rx_pipe2) { ++ usbos_info->pub->attrib.has_2nd_bulk_in_ep = 1; ++ } else { ++ usbos_info->pub->attrib.has_2nd_bulk_in_ep = 0; ++ } ++ ++ if (usbos_info->tx_pipe) ++ usbos_info->maxps = usb_maxpacket(usbos_info->usb, ++ usbos_info->tx_pipe, usb_pipeout(usbos_info->tx_pipe)); ++ ++ INIT_LIST_HEAD(&usbos_info->req_rxfreeq); ++ INIT_LIST_HEAD(&usbos_info->req_txfreeq); ++ INIT_LIST_HEAD(&usbos_info->req_rxpostedq); ++ INIT_LIST_HEAD(&usbos_info->req_txpostedq); ++ spin_lock_init(&usbos_info->rxfree_lock); ++ spin_lock_init(&usbos_info->txfree_lock); ++ spin_lock_init(&usbos_info->rxposted_lock); ++ spin_lock_init(&usbos_info->txposted_lock); ++ spin_lock_init(&usbos_info->rxlock); ++ spin_lock_init(&usbos_info->txlock); ++ ++ atomic_set(&usbos_info->rxposted, 0); ++ atomic_set(&usbos_info->txposted, 0); ++ ++ ++#ifdef USB_DISABLE_INT_EP ++ usbos_info->intr_urb = NULL; ++#else ++ if (!(usbos_info->intr_urb = USB_ALLOC_URB())) { ++ DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__)); ++ goto fail; ++ } ++#endif ++ ++ if (!(usbos_info->ctl_urb = USB_ALLOC_URB())) { ++ DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ init_waitqueue_head(&usbos_info->wait); ++ ++ if (!(usbos_info->blk_urb = USB_ALLOC_URB())) { /* for embedded image downloading */ ++ DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ usbos_info->rxbuf_len = (uint)usbos_info->pub->rxsize; ++ ++ ++ ++ atomic_set(&usbos_info->txallocated, 0); ++ if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info, ++ usbos_info->pub->ntxq, FALSE)) { ++ goto fail; ++ } ++ ++ atomic_set(&usbos_info->rxallocated, 0); ++ if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info, ++ MIN(DBUS_USB_RXQUEUE_BATCH_ADD, usbos_info->pub->nrxq), ++ TRUE)) { ++ goto fail; ++ } ++ ++ sema_init(&usbos_info->ctl_lock, 1); ++ ++#ifdef USBOS_THREAD ++ if (dbus_usbos_thread_init(usbos_info) == NULL) ++ goto fail; ++#endif /* USBOS_THREAD */ ++ ++#ifdef USBOS_TX_THREAD ++ if (dbus_usbos_tx_thread_init(usbos_info) == NULL) ++ goto fail; ++#endif /* USBOS_TX_THREAD */ ++ ++ pub->dev_info = g_probe_info.usb; ++ ++ ++ return (void *) usbos_info; ++fail: ++ if (usbos_info->intr_urb) { ++ USB_FREE_URB(usbos_info->intr_urb); ++ usbos_info->intr_urb = NULL; ++ } ++ ++ if (usbos_info->ctl_urb) { ++ USB_FREE_URB(usbos_info->ctl_urb); ++ usbos_info->ctl_urb = NULL; ++ } ++ ++#if defined(BCM_REQUEST_FW) ++ if (usbos_info->blk_urb) { ++ USB_FREE_URB(usbos_info->blk_urb); ++ usbos_info->blk_urb = NULL; ++ } ++#endif ++ ++ dbus_usbos_urbreqs_free(usbos_info, TRUE); ++ atomic_set(&usbos_info->rxallocated, 0); ++ dbus_usbos_urbreqs_free(usbos_info, FALSE); ++ atomic_set(&usbos_info->txallocated, 0); ++ ++ g_probe_info.usbos_info = NULL; ++ ++ MFREE(pub->osh, usbos_info, sizeof(usbos_info_t)); ++ return NULL; ++} /* dbus_usbos_intf_attach */ ++ ++void ++dbus_usbos_intf_detach(dbus_pub_t *pub, void *info) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *) info; ++ osl_t *osh = pub->osh; ++ ++ if (usbos_info == NULL) { ++ return; ++ } ++ ++#ifdef USBOS_TX_THREAD ++ dbus_usbos_tx_thread_deinit(usbos_info); ++#endif /* USBOS_TX_THREAD */ ++ ++ /* Must unlink all URBs prior to driver unload; ++ * otherwise an URB callback can occur after driver ++ * has been de-allocated and rmmod'd ++ */ ++ dbusos_stop(usbos_info); ++ ++ if (usbos_info->intr_urb) { ++ USB_FREE_URB(usbos_info->intr_urb); ++ usbos_info->intr_urb = NULL; ++ } ++ ++ if (usbos_info->ctl_urb) { ++ USB_FREE_URB(usbos_info->ctl_urb); ++ usbos_info->ctl_urb = NULL; ++ } ++ ++ if (usbos_info->blk_urb) { ++ USB_FREE_URB(usbos_info->blk_urb); ++ usbos_info->blk_urb = NULL; ++ } ++ ++ dbus_usbos_urbreqs_free(usbos_info, TRUE); ++ atomic_set(&usbos_info->rxallocated, 0); ++ dbus_usbos_urbreqs_free(usbos_info, FALSE); ++ atomic_set(&usbos_info->txallocated, 0); ++ ++#ifdef USBOS_THREAD ++ dbus_usbos_thread_deinit(usbos_info); ++#endif /* USBOS_THREAD */ ++ ++ g_probe_info.usbos_info = NULL; ++ MFREE(osh, usbos_info, sizeof(usbos_info_t)); ++} /* dbus_usbos_intf_detach */ ++ ++ ++#ifdef USBOS_TX_THREAD ++ ++void* ++dbus_usbos_tx_thread_init(usbos_info_t *usbos_info) ++{ ++ spin_lock_init(&usbos_info->usbos_tx_list_lock); ++ INIT_LIST_HEAD(&usbos_info->usbos_tx_list); ++ init_waitqueue_head(&usbos_info->usbos_tx_queue_head); ++ ++ usbos_info->usbos_tx_kt = kthread_create(dbus_usbos_tx_thread_func, ++ usbos_info, "usb-tx-thread"); ++ ++ if (IS_ERR(usbos_info->usbos_tx_kt)) { ++ DBUSERR(("Thread Creation failed\n")); ++ return (NULL); ++ } ++ ++ usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; ++ wake_up_process(usbos_info->usbos_tx_kt); ++ ++ return (usbos_info->usbos_tx_kt); ++} ++ ++void ++dbus_usbos_tx_thread_deinit(usbos_info_t *usbos_info) ++{ ++ urb_req_t *req; ++ ++ if (usbos_info->usbos_tx_kt) { ++ wake_up_interruptible(&usbos_info->usbos_tx_queue_head); ++ kthread_stop(usbos_info->usbos_tx_kt); ++ } ++ ++ /* Move pending requests to free queue so they can be freed */ ++ while ((req = dbus_usbos_qdeq( ++ &usbos_info->usbos_tx_list, &usbos_info->usbos_tx_list_lock)) != NULL) { ++ dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); ++ } ++} ++ ++/** ++ * Allow USB in-band resume to block by submitting CTRL and DATA URBs on a separate thread. ++ */ ++int ++dbus_usbos_tx_thread_func(void *data) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *)data; ++ urb_req_t *req; ++ dbus_irb_tx_t *txirb; ++ int ret; ++ unsigned long flags; ++ ++#ifdef WL_THREADNICE ++ set_user_nice(current, WL_THREADNICE); ++#endif ++ ++ while (1) { ++ /* Wait until there are URBs to submit */ ++ wait_event_interruptible_timeout( ++ usbos_info->usbos_tx_queue_head, ++ !list_empty(&usbos_info->usbos_tx_list) || ++ usbos_info->ctl_state == USBOS_REQUEST_STATE_SCHEDULED, ++ 100); ++ ++ if (kthread_should_stop()) ++ break; ++ ++ /* Submit CTRL URB if needed */ ++ if (usbos_info->ctl_state == USBOS_REQUEST_STATE_SCHEDULED) { ++ ++ /* Disable USB autosuspend until this request completes. If the ++ * interface was suspended, this call blocks until it has been resumed. ++ */ ++ USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); ++ ++ usbos_info->ctl_state = USBOS_REQUEST_STATE_SUBMITTED; ++ ++ ret = USB_SUBMIT_URB(usbos_info->ctl_urb); ++ if (ret != 0) { ++ DBUSERR(("%s CTRL USB_SUBMIT_URB failed, status %d\n", ++ __FUNCTION__, ret)); ++ ++ usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; ++ up(&usbos_info->ctl_lock); ++ ++ USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); ++ } ++ } ++ ++ /* Submit all available TX URBs */ ++ while ((req = dbus_usbos_qdeq(&usbos_info->usbos_tx_list, ++ &usbos_info->usbos_tx_list_lock)) != NULL) { ++ ++ /* Disable USB autosuspend until this request completes. If the ++ * interface was suspended, this call blocks until it has been resumed. ++ */ ++ USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); ++ ++ spin_lock_irqsave(&usbos_info->txlock, flags); ++ ++ ret = USB_SUBMIT_URB(req->urb); ++ if (ret == 0) { ++ /* URB submitted successfully */ ++ dbus_usbos_qenq(&usbos_info->req_txpostedq, req, ++ &usbos_info->txposted_lock); ++ atomic_inc(&usbos_info->txposted); ++ } else { ++ /* Submitting the URB failed. */ ++ DBUSERR(("%s TX USB_SUBMIT_URB failed, status %d\n", ++ __FUNCTION__, ret)); ++ ++ USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); ++ } ++ ++ spin_unlock_irqrestore(&usbos_info->txlock, flags); ++ ++ if (ret != 0) { ++ /* Cleanup and notify higher layers */ ++ dbus_usbos_qenq(&usbos_info->req_txfreeq, req, ++ &usbos_info->txfree_lock); ++ ++ txirb = req->arg; ++ if (txirb->send_buf) { ++ MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); ++ txirb->send_buf = NULL; ++ req->buf_len = 0; ++ } ++ ++ if (likely (usbos_info->cbarg && usbos_info->cbs)) { ++ if (likely (usbos_info->cbs->send_irb_complete != NULL)) ++ usbos_info->cbs->send_irb_complete( ++ usbos_info->cbarg, txirb, DBUS_ERR_TXDROP); ++ } ++ } ++ } ++ } ++ ++ return 0; ++} /* dbus_usbos_tx_thread_func */ ++ ++#endif /* USBOS_TX_THREAD */ ++ ++#ifdef USBOS_THREAD ++ ++/** ++ * Increase system performance by creating a USB thread that runs parallel to other system ++ * activity. ++ */ ++static void* ++dbus_usbos_thread_init(usbos_info_t *usbos_info) ++{ ++ usbos_list_entry_t *entry; ++ unsigned long flags, ii; ++ ++ spin_lock_init(&usbos_info->usbos_list_lock); ++ spin_lock_init(&usbos_info->ctrl_lock); ++ INIT_LIST_HEAD(&usbos_info->usbos_list); ++ INIT_LIST_HEAD(&usbos_info->usbos_free_list); ++ init_waitqueue_head(&usbos_info->usbos_queue_head); ++ atomic_set(&usbos_info->usbos_list_cnt, 0); ++ ++ ++ for (ii = 0; ii < (usbos_info->pub->nrxq + usbos_info->pub->ntxq); ii++) { ++ entry = MALLOC(usbos_info->pub->osh, sizeof(usbos_list_entry_t)); ++ if (entry) { ++ spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); ++ list_add_tail((struct list_head*) entry, &usbos_info->usbos_free_list); ++ spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); ++ } else { ++ DBUSERR(("Failed to create list\n")); ++ } ++ } ++ ++ usbos_info->usbos_kt = kthread_create(dbus_usbos_thread_func, ++ usbos_info, "usb-thread"); ++ ++ if (IS_ERR(usbos_info->usbos_kt)) { ++ DBUSERR(("Thread Creation failed\n")); ++ return (NULL); ++ } ++ ++ wake_up_process(usbos_info->usbos_kt); ++ ++ return (usbos_info->usbos_kt); ++} ++ ++static void ++dbus_usbos_thread_deinit(usbos_info_t *usbos_info) ++{ ++ struct list_head *cur, *next; ++ usbos_list_entry_t *entry; ++ unsigned long flags; ++ ++ if (usbos_info->usbos_kt) { ++ wake_up_interruptible(&usbos_info->usbos_queue_head); ++ kthread_stop(usbos_info->usbos_kt); ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_safe(cur, next, &usbos_info->usbos_list) ++ { ++ entry = list_entry(cur, struct usbos_list_entry, list); ++ /* detach this entry from the list and then free the entry */ ++ spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); ++ list_del(cur); ++ MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t)); ++ spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); ++ } ++ ++ list_for_each_safe(cur, next, &usbos_info->usbos_free_list) ++ { ++ entry = list_entry(cur, struct usbos_list_entry, list); ++ /* detach this entry from the list and then free the entry */ ++ spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); ++ list_del(cur); ++ MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t)); ++ spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++} ++ ++/** Process completed URBs in a worker thread */ ++static int ++dbus_usbos_thread_func(void *data) ++{ ++ usbos_info_t *usbos_info = (usbos_info_t *)data; ++ usbos_list_entry_t *entry; ++ struct list_head *cur, *next; ++ unsigned long flags; ++ ++#ifdef WL_THREADNICE ++ set_user_nice(current, WL_THREADNICE); ++#endif ++ ++ while (1) { ++ /* If the list is empty, then go to sleep */ ++ wait_event_interruptible_timeout ++ (usbos_info->usbos_queue_head, ++ atomic_read(&usbos_info->usbos_list_cnt) > 0, ++ 100); ++ ++ if (kthread_should_stop()) ++ break; ++ ++ spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); ++ ++ /* For each entry on the list, process it. Remove the entry from ++ * the list when done. ++ */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_safe(cur, next, &usbos_info->usbos_list) ++ { ++ urb_req_t *req; ++ int len; ++ int stat; ++ usbos_info_t *usbos_info_local; ++ ++ entry = list_entry(cur, struct usbos_list_entry, list); ++ if (entry == NULL) ++ break; ++ ++ req = entry->urb_context; ++ len = entry->urb_length; ++ stat = entry->urb_status; ++ usbos_info_local = req->usbinfo; ++ ++ /* detach this entry from the list and attach it to the free list */ ++ list_del_init(cur); ++ spin_unlock_irqrestore(&usbos_info_local->usbos_list_lock, flags); ++ ++ dbus_usbos_recv_complete_handle(req, len, stat); ++ ++ spin_lock_irqsave(&usbos_info_local->usbos_list_lock, flags); ++ ++ list_add_tail(cur, &usbos_info_local->usbos_free_list); ++ ++ atomic_dec(&usbos_info_local->usbos_list_cnt); ++ } ++ ++ spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); ++ ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ ++ return 0; ++} /* dbus_usbos_thread_func */ ++ ++/** Called on Linux calling URB callback, see dbus_usbos_recv_complete() */ ++static void ++dbus_usbos_dispatch_schedule(CALLBACK_ARGS) ++{ ++ urb_req_t *req = urb->context; ++ usbos_info_t *usbos_info = req->usbinfo; ++ usbos_list_entry_t *entry; ++ unsigned long flags; ++ struct list_head *cur; ++ ++ spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); ++ ++ cur = usbos_info->usbos_free_list.next; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ entry = list_entry(cur, struct usbos_list_entry, list); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ ++ /* detach this entry from the free list and prepare it insert it to use list */ ++ list_del_init(cur); ++ ++ if (entry) { ++ entry->urb_context = urb->context; ++ entry->urb_length = urb->actual_length; ++ entry->urb_status = urb->status; ++ ++ atomic_inc(&usbos_info->usbos_list_cnt); ++ list_add_tail(cur, &usbos_info->usbos_list); ++ } else { ++ DBUSERR(("!!!!!!OUT OF MEMORY!!!!!!!\n")); ++ } ++ ++ spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); ++ ++ /* thread */ ++ wake_up_interruptible(&usbos_info->usbos_queue_head); ++} /* dbus_usbos_dispatch_schedule */ ++ ++#endif /* USBOS_THREAD */ ++ ++ ++ ++ ++#ifdef BCM_REQUEST_FW ++ ++struct request_fw_context { ++ const struct firmware *firmware; ++ struct semaphore lock; ++}; ++ ++/* ++ * Callback for dbus_request_firmware(). ++ */ ++static void ++dbus_request_firmware_done(const struct firmware *firmware, void *ctx) ++{ ++ struct request_fw_context *context = (struct request_fw_context*)ctx; ++ ++ /* Store the received firmware handle in the context and wake requester */ ++ context->firmware = firmware; ++ up(&context->lock); ++} ++ ++/* ++ * Send a firmware request and wait for completion. ++ * ++ * The use of the asynchronous version of request_firmware() is needed to avoid ++ * kernel oopses when we just come out of system hibernate. ++ */ ++static int ++dbus_request_firmware(const char *name, const struct firmware **firmware) ++{ ++ struct request_fw_context *context; ++ int ret; ++ ++ context = kzalloc(sizeof(*context), GFP_KERNEL); ++ if (!context) ++ return -ENOMEM; ++ ++ sema_init(&context->lock, 0); ++ ++ ret = request_firmware_nowait(THIS_MODULE, true, name, &g_probe_info.usb->dev, ++ GFP_KERNEL, context, dbus_request_firmware_done); ++ if (ret) { ++ kfree(context); ++ return ret; ++ } ++ ++ /* Wait for completion */ ++ if (down_interruptible(&context->lock) != 0) { ++ kfree(context); ++ return -ERESTARTSYS; ++ } ++ ++ *firmware = context->firmware; ++ kfree(context); ++ ++ return *firmware != NULL ? 0 : -ENOENT; ++} ++ ++static void * ++dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev) ++{ ++ const struct firmware *firmware = NULL; ++#ifndef OEM_ANDROID ++ s8 *device_id = NULL; ++ s8 *chip_rev = ""; ++#endif /* OEM_ANDROID */ ++ s8 file_name[64]; ++ int ret; ++ ++#ifndef OEM_ANDROID ++ switch (devid) { ++ case BCM4350_CHIP_ID: ++ case BCM4354_CHIP_ID: ++ case BCM43556_CHIP_ID: ++ case BCM43558_CHIP_ID: ++ case BCM43566_CHIP_ID: ++ case BCM43568_CHIP_ID: ++ case BCM43570_CHIP_ID: ++ case BCM4358_CHIP_ID: ++ device_id = "4350"; ++ break; ++ case BCM43143_CHIP_ID: ++ device_id = "43143"; ++ break; ++ case BCM43234_CHIP_ID: ++ case BCM43235_CHIP_ID: ++ case BCM43236_CHIP_ID: ++ device_id = "43236"; ++ break; ++ case BCM43242_CHIP_ID: ++ device_id = "43242"; ++ break; ++ case BCM43238_CHIP_ID: ++ device_id = "43238"; ++ break; ++ case BCM43526_CHIP_ID: ++ device_id = "43526"; ++ break; ++ case BCM43569_CHIP_ID: ++ device_id = "43569"; ++ switch (chiprev) { ++ case 0: ++ chip_rev = "a0"; ++ break; ++ case 2: ++ chip_rev = "a2"; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ DBUSERR(("unsupported device %x\n", devid)); ++ return NULL; ++ } ++ ++ /* Load firmware */ ++ snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-firmware.bin", device_id, chip_rev); ++#else ++ snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_FW_PATH); ++#endif /* OEM_ANDROID */ ++ ++ ret = dbus_request_firmware(file_name, &firmware); ++ if (ret) { ++ DBUSERR(("fail to request firmware %s\n", file_name)); ++ return NULL; ++ } ++ ++ *fwlen = firmware->size; ++ *fw = (uint8 *)firmware->data; ++ return (void *)firmware; ++ ++} ++ ++static void * ++dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev) ++{ ++ const struct firmware *firmware = NULL; ++#ifndef OEM_ANDROID ++ s8 *device_id = NULL; ++ s8 *chip_rev = ""; ++#endif /* OEM_ANDROID */ ++ s8 file_name[64]; ++ int ret; ++ ++#ifndef OEM_ANDROID ++ switch (devid) { ++ case BCM4350_CHIP_ID: ++ case BCM4354_CHIP_ID: ++ case BCM43556_CHIP_ID: ++ case BCM43558_CHIP_ID: ++ case BCM43566_CHIP_ID: ++ case BCM43568_CHIP_ID: ++ case BCM43570_CHIP_ID: ++ case BCM4358_CHIP_ID: ++ device_id = "4350"; ++ break; ++ case BCM43143_CHIP_ID: ++ device_id = "43143"; ++ break; ++ case BCM43234_CHIP_ID: ++ device_id = "43234"; ++ break; ++ case BCM43235_CHIP_ID: ++ device_id = "43235"; ++ break; ++ case BCM43236_CHIP_ID: ++ device_id = "43236"; ++ break; ++ case BCM43238_CHIP_ID: ++ device_id = "43238"; ++ break; ++ case BCM43242_CHIP_ID: ++ device_id = "43242"; ++ break; ++ case BCM43526_CHIP_ID: ++ device_id = "43526"; ++ break; ++ case BCM43569_CHIP_ID: ++ device_id = "43569"; ++ switch (chiprev) { ++ case 0: ++ chip_rev = "a0"; ++ break; ++ case 2: ++ chip_rev = "a2"; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ DBUSERR(("unsupported device %x\n", devid)); ++ return NULL; ++ } ++ ++ /* Load board specific nvram file */ ++ snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-%2x-%2x.nvm", ++ device_id, chip_rev, boardtype, boardrev); ++#else ++ snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_NVRAM_PATH); ++#endif /* OEM_ANDROID */ ++ ++ ret = dbus_request_firmware(file_name, &firmware); ++ if (ret) { ++ DBUSERR(("fail to request nvram %s\n", file_name)); ++ ++#ifndef OEM_ANDROID ++ /* Load generic nvram file */ ++ snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s.nvm", ++ device_id, chip_rev); ++ ++ ret = dbus_request_firmware(file_name, &firmware); ++#endif /* OEM_ANDROID */ ++ ++ if (ret) { ++ DBUSERR(("fail to request nvram %s\n", file_name)); ++ return NULL; ++ } ++ } ++ ++ *fwlen = firmware->size; ++ *fw = (uint8 *)firmware->data; ++ return (void *)firmware; ++} ++ ++void * ++dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype, ++ uint16 boardrev) ++{ ++ switch (type) { ++ case DBUS_FIRMWARE: ++ return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev); ++ case DBUS_NVFILE: ++ return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev); ++ default: ++ return NULL; ++ } ++} ++ ++void ++dbus_release_fw_nvfile(void *firmware) ++{ ++ release_firmware((struct firmware *)firmware); ++} ++#endif /* BCM_REQUEST_FW */ ++ ++#ifdef BCMUSBDEV_COMPOSITE ++/** ++ * For a composite device the interface order is not guaranteed, scan the device struct for the WLAN ++ * interface. ++ */ ++static int ++dbus_usbos_intf_wlan(struct usb_device *usb) ++{ ++ int i, num_of_eps, ep, intf_wlan = -1; ++ int num_intf = CONFIGDESC(usb)->bNumInterfaces; ++ struct usb_endpoint_descriptor *endpoint; ++ ++ for (i = 0; i < num_intf; i++) { ++ if (IFDESC(usb, i).bInterfaceClass != USB_CLASS_VENDOR_SPEC) ++ continue; ++ num_of_eps = IFDESC(usb, i).bNumEndpoints; ++ ++ for (ep = 0; ep < num_of_eps; ep++) { ++ endpoint = &IFEPDESC(usb, i, ep); ++ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == ++ USB_ENDPOINT_XFER_BULK) { ++ intf_wlan = i; ++ break; ++ } ++ } ++ if (ep < num_of_eps) ++ break; ++ } ++ ++ return intf_wlan; ++} ++#endif /* BCMUSBDEV_COMPOSITE */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd.h +new file mode 100644 +index 000000000..c434ab4e0 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd.h +@@ -0,0 +1,2594 @@ ++/* ++ * Header file describing the internal (inter-module) DHD interfaces. ++ * ++ * Provides type definitions and function prototypes used to link the ++ * DHD OS, bus, and protocol modules. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd.h 711448 2017-07-18 08:27:03Z $ ++ */ ++ ++/**************** ++ * Common types * ++ */ ++ ++#ifndef _dhd_h_ ++#define _dhd_h_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) ++#include ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) ++#include ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */ ++/* The kernel threading is sdio-specific */ ++struct task_struct; ++struct sched_param; ++#if defined(BT_OVER_SDIO) ++#include ++#endif /* defined (BT_OVER_SDIO) */ ++int setScheduler(struct task_struct *p, int policy, struct sched_param *param); ++int get_scheduler_policy(struct task_struct *p); ++#define MAX_EVENT 16 ++ ++#define ALL_INTERFACES 0xff ++ ++#include ++#include ++#include ++#if defined(DUMP_IOCTL_IOV_LIST) || defined(DHD_DEBUG) ++#include ++#endif /* DUMP_IOCTL_IOV_LIST || DHD_DEBUG */ ++#include ++ ++#if defined(BCMWDF) ++#include ++#include ++#endif /* (BCMWDF) */ ++ ++#ifdef DEBUG_DPC_THREAD_WATCHDOG ++#define MAX_RESCHED_CNT 600 ++#endif /* DEBUG_DPC_THREAD_WATCHDOG */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) && LINUX_VERSION_CODE < \ ++ KERNEL_VERSION(3, 18, 0) || defined(CONFIG_BCMDHD_VENDOR_EXT)) ++#define WL_VENDOR_EXT_SUPPORT ++#endif /* 3.18 > KERNEL_VER >= 3.14 || defined(CONFIG_BCMDHD_VENDOR_EXT) */ ++ ++#if defined(KEEP_ALIVE) ++/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ ++#define KEEP_ALIVE_PERIOD 55000 ++#define NULL_PKT_STR "null_pkt" ++#endif /* KEEP_ALIVE */ ++ ++/* Forward decls */ ++struct dhd_bus; ++struct dhd_prot; ++struct dhd_info; ++struct dhd_ioctl; ++struct dhd_dbg; ++struct dhd_ts; ++ ++/* The level of bus communication with the dongle */ ++enum dhd_bus_state { ++ DHD_BUS_DOWN, /* Not ready for frame transfers */ ++ DHD_BUS_LOAD, /* Download access only (CPU reset) */ ++ DHD_BUS_DATA, /* Ready for frame transfers */ ++ DHD_BUS_SUSPEND, /* Bus has been suspended */ ++ DHD_BUS_DOWN_IN_PROGRESS, /* Bus going Down */ ++ DHD_BUS_REMOVE, /* Bus has been removed */ ++}; ++ ++/* ++ * Bit fields to Indicate clean up process that wait till they are finished. ++ * Future synchronizable processes can add their bit filed below and update ++ * their functionalities accordingly ++ */ ++#define DHD_BUS_BUSY_IN_TX 0x01 ++#define DHD_BUS_BUSY_IN_SEND_PKT 0x02 ++#define DHD_BUS_BUSY_IN_DPC 0x04 ++#define DHD_BUS_BUSY_IN_WD 0x08 ++#define DHD_BUS_BUSY_IN_IOVAR 0x10 ++#define DHD_BUS_BUSY_IN_DHD_IOVAR 0x20 ++#define DHD_BUS_BUSY_SUSPEND_IN_PROGRESS 0x40 ++#define DHD_BUS_BUSY_RESUME_IN_PROGRESS 0x80 ++#define DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS 0x100 ++#define DHD_BUS_BUSY_RPM_SUSPEND_DONE 0x200 ++#define DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS 0x400 ++#define DHD_BUS_BUSY_RPM_ALL (DHD_BUS_BUSY_RPM_SUSPEND_DONE | \ ++ DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS | \ ++ DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS) ++#define DHD_BUS_BUSY_IN_CHECKDIED 0x800 ++ ++#define DHD_BUS_BUSY_SET_IN_TX(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_TX ++#define DHD_BUS_BUSY_SET_IN_SEND_PKT(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_SEND_PKT ++#define DHD_BUS_BUSY_SET_IN_DPC(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_DPC ++#define DHD_BUS_BUSY_SET_IN_WD(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_WD ++#define DHD_BUS_BUSY_SET_IN_IOVAR(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_IOVAR ++#define DHD_BUS_BUSY_SET_IN_DHD_IOVAR(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_DHD_IOVAR ++#define DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_SUSPEND_IN_PROGRESS ++#define DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_RESUME_IN_PROGRESS ++#define DHD_BUS_BUSY_SET_RPM_SUSPEND_IN_PROGRESS(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS ++#define DHD_BUS_BUSY_SET_RPM_SUSPEND_DONE(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_RPM_SUSPEND_DONE ++#define DHD_BUS_BUSY_SET_RPM_RESUME_IN_PROGRESS(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS ++#define DHD_BUS_BUSY_SET_IN_CHECKDIED(dhdp) \ ++ (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_CHECKDIED ++ ++#define DHD_BUS_BUSY_CLEAR_IN_TX(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_TX ++#define DHD_BUS_BUSY_CLEAR_IN_SEND_PKT(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_SEND_PKT ++#define DHD_BUS_BUSY_CLEAR_IN_DPC(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_DPC ++#define DHD_BUS_BUSY_CLEAR_IN_WD(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_WD ++#define DHD_BUS_BUSY_CLEAR_IN_IOVAR(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_IOVAR ++#define DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_DHD_IOVAR ++#define DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_SUSPEND_IN_PROGRESS ++#define DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RESUME_IN_PROGRESS ++#define DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_IN_PROGRESS(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS ++#define DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_DONE(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RPM_SUSPEND_DONE ++#define DHD_BUS_BUSY_CLEAR_RPM_RESUME_IN_PROGRESS(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS ++#define DHD_BUS_BUSY_CLEAR_IN_CHECKDIED(dhdp) \ ++ (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_CHECKDIED ++ ++#define DHD_BUS_BUSY_CHECK_IN_TX(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_TX) ++#define DHD_BUS_BUSY_CHECK_IN_SEND_PKT(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_SEND_PKT) ++#define DHD_BUS_BUSY_CHECK_IN_DPC(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_DPC) ++#define DHD_BUS_BUSY_CHECK_IN_WD(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_WD) ++#define DHD_BUS_BUSY_CHECK_IN_IOVAR(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_IOVAR) ++#define DHD_BUS_BUSY_CHECK_IN_DHD_IOVAR(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_DHD_IOVAR) ++#define DHD_BUS_BUSY_CHECK_SUSPEND_IN_PROGRESS(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_SUSPEND_IN_PROGRESS) ++#define DHD_BUS_BUSY_CHECK_RESUME_IN_PROGRESS(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_RESUME_IN_PROGRESS) ++#define DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS) ++#define DHD_BUS_BUSY_CHECK_RPM_SUSPEND_DONE(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_SUSPEND_DONE) ++#define DHD_BUS_BUSY_CHECK_RPM_RESUME_IN_PROGRESS(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS) ++#define DHD_BUS_BUSY_CHECK_RPM_ALL(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_ALL) ++#define DHD_BUS_BUSY_CHECK_IN_CHECKDIED(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_CHECKDIED) ++#define DHD_BUS_BUSY_CHECK_IDLE(dhdp) \ ++ ((dhdp)->dhd_bus_busy_state == 0) ++ ++#define DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp) \ ++ ((dhdp)->busstate == DHD_BUS_SUSPEND || DHD_BUS_BUSY_CHECK_SUSPEND_IN_PROGRESS(dhdp) || \ ++ DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(dhdp)) ++ ++#define DHD_BUS_CHECK_ANY_SUSPEND_IN_PROGRESS(dhdp) \ ++ (DHD_BUS_BUSY_CHECK_SUSPEND_IN_PROGRESS(dhdp) || \ ++ DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(dhdp)) ++ ++#define DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp) \ ++ ((dhdp)->busstate == DHD_BUS_DOWN || (dhdp)->busstate == DHD_BUS_DOWN_IN_PROGRESS || \ ++ (dhdp)->busstate == DHD_BUS_REMOVE) ++ ++#define DHD_BUS_CHECK_REMOVE(dhdp) \ ++ ((dhdp)->busstate == DHD_BUS_REMOVE) ++ ++/* Macro to print Ethernet Address as String ++ * expects both arguements as (char *) ++ */ ++#define DHD_MAC_TO_STR(mac, str) (snprintf(str, ETHER_ADDR_STR_LEN, \ ++ "%02x:%02x:%02x:%02x:%02x:%02x\n", \ ++ (uchar)mac[0]&0xff, \ ++ (uchar)mac[1]&0xff, \ ++ (uchar)mac[2]&0xff, \ ++ (uchar)mac[3]&0xff, \ ++ (uchar)mac[4]&0xff, \ ++ (uchar)mac[5]&0xff)) ++ ++ ++/* Download Types */ ++typedef enum download_type { ++ FW, ++ NVRAM, ++ CLM_BLOB ++} download_type_t; ++ ++ ++/* For supporting multiple interfaces */ ++#define DHD_MAX_IFS 16 ++#define DHD_DEL_IF -0xE ++#define DHD_BAD_IF -0xF ++#define DHD_EVENT_IF 0xFFFF /* Hack i/f to handle events from INFO Ring */ ++ ++enum dhd_op_flags { ++/* Firmware requested operation mode */ ++ DHD_FLAG_STA_MODE = (1 << (0)), /* STA only */ ++ DHD_FLAG_HOSTAP_MODE = (1 << (1)), /* SOFTAP only */ ++ DHD_FLAG_P2P_MODE = (1 << (2)), /* P2P Only */ ++ /* STA + P2P */ ++ DHD_FLAG_CONCURR_SINGLE_CHAN_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_P2P_MODE), ++ /* STA + SoftAP */ ++ DHD_FLAG_CONCURR_STA_HOSTAP_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_HOSTAP_MODE), ++ DHD_FLAG_CONCURR_MULTI_CHAN_MODE = (1 << (4)), /* STA + P2P */ ++ /* Current P2P mode for P2P connection */ ++ DHD_FLAG_P2P_GC_MODE = (1 << (5)), ++ DHD_FLAG_P2P_GO_MODE = (1 << (6)), ++ DHD_FLAG_MBSS_MODE = (1 << (7)), /* MBSS in future */ ++ DHD_FLAG_IBSS_MODE = (1 << (8)), ++ DHD_FLAG_MFG_MODE = (1 << (9)), ++ DHD_FLAG_RSDB_MODE = (1 << (10)), ++ DHD_FLAG_MP2P_MODE = (1 << (11)) ++}; ++ ++#define DHD_OPMODE_SUPPORTED(dhd, opmode_flag) \ ++ (dhd ? ((((dhd_pub_t *)dhd)->op_mode) & opmode_flag) : -1) ++ ++/* Max sequential TX/RX Control timeouts to set HANG event */ ++#ifndef MAX_CNTL_TX_TIMEOUT ++#define MAX_CNTL_TX_TIMEOUT 2 ++#endif /* MAX_CNTL_TX_TIMEOUT */ ++#ifndef MAX_CNTL_RX_TIMEOUT ++#define MAX_CNTL_RX_TIMEOUT 1 ++#endif /* MAX_CNTL_RX_TIMEOUT */ ++ ++#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */ ++#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */ ++#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ ++#define DHD_SCAN_HOME_TIME 45 /* ms: Embedded default Home time setting from DHD */ ++#define DHD_SCAN_HOME_AWAY_TIME 100 /* ms: Embedded default Home Away time setting from DHD */ ++ ++#ifndef POWERUP_MAX_RETRY ++#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */ ++#endif ++#ifndef POWERUP_WAIT_MS ++#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */ ++#endif ++/* ++ * MAX_NVRAMBUF_SIZE determines the size of the Buffer in the DHD that holds ++ * the NVRAM data. That is the size of the buffer pointed by bus->vars ++ * This also needs to be increased to 16K to support NVRAM size higher than 8K ++ */ ++#define MAX_NVRAMBUF_SIZE (16 * 1024) /* max nvram buf size */ ++#define MAX_CLM_BUF_SIZE (48 * 1024) /* max clm blob size */ ++#ifdef DHD_DEBUG ++#define DHD_JOIN_MAX_TIME_DEFAULT 10000 /* ms: Max time out for joining AP */ ++#define DHD_SCAN_DEF_TIMEOUT 10000 /* ms: Max time out for scan in progress */ ++#endif ++ ++#ifndef CONFIG_BCMDHD_CLM_PATH ++#define CONFIG_BCMDHD_CLM_PATH "/system/etc/wifi/bcmdhd_clm.blob" ++#endif /* CONFIG_BCMDHD_CLM_PATH */ ++#define WL_CCODE_NULL_COUNTRY "#n" ++ ++#define FW_VER_STR_LEN 128 ++#define CLM_VER_STR_LEN 128 ++#define BUS_API_REV_STR_LEN 128 ++extern char bus_api_revision[]; ++ ++enum dhd_bus_wake_state { ++ WAKE_LOCK_OFF, ++ WAKE_LOCK_PRIV, ++ WAKE_LOCK_DPC, ++ WAKE_LOCK_IOCTL, ++ WAKE_LOCK_DOWNLOAD, ++ WAKE_LOCK_TMOUT, ++ WAKE_LOCK_WATCHDOG, ++ WAKE_LOCK_LINK_DOWN_TMOUT, ++ WAKE_LOCK_PNO_FIND_TMOUT, ++ WAKE_LOCK_SOFTAP_SET, ++ WAKE_LOCK_SOFTAP_STOP, ++ WAKE_LOCK_SOFTAP_START, ++ WAKE_LOCK_SOFTAP_THREAD ++}; ++ ++#ifdef PCIE_INB_DW ++enum dhd_bus_ds_state { ++ DW_DEVICE_DS_INVALID = -1, ++ DW_DEVICE_DS_DEV_SLEEP = 0, ++ DW_DEVICE_DS_DEV_SLEEP_PEND, ++ DW_DEVICE_DS_DISABLED_WAIT, ++ DW_DEVICE_DS_DEV_WAKE, ++ DW_DEVICE_DS_ACTIVE, ++ DW_DEVICE_HOST_SLEEP_WAIT, ++ DW_DEVICE_HOST_SLEEP, ++ DW_DEVICE_HOST_WAKE_WAIT, ++ DW_DEVICE_DS_D3_INFORM_WAIT ++}; ++#endif /* PCIE_INB_DW */ ++ ++enum dhd_prealloc_index { ++ DHD_PREALLOC_PROT = 0, ++ DHD_PREALLOC_RXBUF = 1, ++ DHD_PREALLOC_DATABUF = 2, ++ DHD_PREALLOC_OSL_BUF = 3, ++ DHD_PREALLOC_SKB_BUF = 4, ++#if defined(STATIC_WL_PRIV_STRUCT) ++ DHD_PREALLOC_WIPHY_ESCAN0 = 5, ++#endif /* STATIC_WL_PRIV_STRUCT */ ++ DHD_PREALLOC_DHD_INFO = 7, ++ DHD_PREALLOC_DHD_WLFC_INFO = 8, ++ DHD_PREALLOC_IF_FLOW_LKUP = 9, ++ /* 10 */ ++ DHD_PREALLOC_MEMDUMP_RAM = 11, ++ DHD_PREALLOC_DHD_WLFC_HANGER = 12, ++ DHD_PREALLOC_PKTID_MAP = 13, ++ DHD_PREALLOC_PKTID_MAP_IOCTL = 14, ++ DHD_PREALLOC_DHD_LOG_DUMP_BUF = 15, ++ DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX = 16, ++ DHD_PREALLOC_DHD_PKTLOG_DUMP_BUF = 17, ++ DHD_PREALLOC_STAT_REPORT_BUF = 18, ++ DHD_PREALLOC_WL_ESCAN = 19, ++ DHD_PREALLOC_FW_VERBOSE_RING = 20, ++ DHD_PREALLOC_FW_EVENT_RING = 21, ++ DHD_PREALLOC_DHD_EVENT_RING = 22, ++ DHD_PREALLOC_NAN_EVENT_RING = 23 ++}; ++ ++enum dhd_dongledump_mode { ++ DUMP_DISABLED = 0, ++ DUMP_MEMONLY, ++ DUMP_MEMFILE, ++ DUMP_MEMFILE_BUGON, ++ DUMP_MEMFILE_MAX ++}; ++ ++enum dhd_dongledump_type { ++ DUMP_TYPE_RESUMED_ON_TIMEOUT = 1, ++ DUMP_TYPE_D3_ACK_TIMEOUT, ++ DUMP_TYPE_DONGLE_TRAP, ++ DUMP_TYPE_MEMORY_CORRUPTION, ++ DUMP_TYPE_PKTID_AUDIT_FAILURE, ++ DUMP_TYPE_PKTID_INVALID, ++ DUMP_TYPE_SCAN_TIMEOUT, ++ DUMP_TYPE_JOIN_TIMEOUT, ++ DUMP_TYPE_SCAN_BUSY, ++ DUMP_TYPE_BY_SYSDUMP, ++ DUMP_TYPE_BY_LIVELOCK, ++ DUMP_TYPE_AP_LINKUP_FAILURE, ++ DUMP_TYPE_AP_ABNORMAL_ACCESS, ++ DUMP_TYPE_CFG_VENDOR_TRIGGERED, ++ DUMP_TYPE_RESUMED_ON_TIMEOUT_TX, ++ DUMP_TYPE_RESUMED_ON_TIMEOUT_RX, ++ DUMP_TYPE_RESUMED_ON_INVALID_RING_RDWR, ++ DUMP_TYPE_DONGLE_HOST_EVENT, ++ DUMP_TYPE_RESUMED_UNKNOWN, ++ DUMP_TYPE_TRANS_ID_MISMATCH, ++ DUMP_TYPE_HANG_ON_IFACE_OP_FAIL, ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ DUMP_TYPE_READ_SHM_FAIL ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++}; ++ ++enum dhd_hang_reason { ++ HANG_REASON_MASK = 0x8000, ++ HANG_REASON_IOCTL_RESP_TIMEOUT = 0x8001, ++ HANG_REASON_DONGLE_TRAP = 0x8002, ++ HANG_REASON_D3_ACK_TIMEOUT = 0x8003, ++ HANG_REASON_BUS_DOWN = 0x8004, ++ HANG_REASON_MSGBUF_LIVELOCK = 0x8006, ++ HANG_REASON_IFACE_OP_FAILURE = 0x8007, ++ HANG_REASON_HT_AVAIL_ERROR = 0x8008, ++ HANG_REASON_PCIE_RC_LINK_UP_FAIL = 0x8009, ++ HANG_REASON_PCIE_PKTID_ERROR = 0x800A, ++ HANG_REASON_PCIE_LINK_DOWN = 0x8805, ++ HANG_REASON_INVALID_EVENT_OR_DATA = 0x8806, ++ HANG_REASON_UNKNOWN = 0x8807, ++ HANG_REASON_MAX = 0x8808 ++}; ++ ++enum dhd_rsdb_scan_features { ++ /* Downgraded scan feature for AP active */ ++ RSDB_SCAN_DOWNGRADED_AP_SCAN = 0x01, ++ /* Downgraded scan feature for P2P Discovery */ ++ RSDB_SCAN_DOWNGRADED_P2P_DISC_SCAN = 0x02, ++ /* Enable channel pruning for ROAM SCAN */ ++ RSDB_SCAN_DOWNGRADED_CH_PRUNE_ROAM = 0x10, ++ /* Enable channel pruning for any SCAN */ ++ RSDB_SCAN_DOWNGRADED_CH_PRUNE_ALL = 0x20 ++}; ++ ++/* Packet alignment for most efficient SDIO (can change based on platform) */ ++#ifndef DHD_SDALIGN ++#define DHD_SDALIGN 32 ++#endif ++ ++/** ++ * DMA-able buffer parameters ++ * - dmaaddr_t is 32bits on a 32bit host. ++ * dhd_dma_buf::pa may not be used as a sh_addr_t, bcm_addr64_t or uintptr ++ * - dhd_dma_buf::_alloced is ONLY for freeing a DMA-able buffer. ++ */ ++typedef struct dhd_dma_buf { ++ void *va; /* virtual address of buffer */ ++ uint32 len; /* user requested buffer length */ ++ dmaaddr_t pa; /* physical address of buffer */ ++ void *dmah; /* dma mapper handle */ ++ void *secdma; /* secure dma sec_cma_info handle */ ++ uint32 _alloced; /* actual size of buffer allocated with align and pad */ ++} dhd_dma_buf_t; ++ ++/* host reordering packts logic */ ++/* followed the structure to hold the reorder buffers (void **p) */ ++typedef struct reorder_info { ++ void **p; ++ uint8 flow_id; ++ uint8 cur_idx; ++ uint8 exp_idx; ++ uint8 max_idx; ++ uint8 pend_pkts; ++} reorder_info_t; ++ ++#ifdef DHDTCPACK_SUPPRESS ++ ++enum { ++ /* TCPACK suppress off */ ++ TCPACK_SUP_OFF, ++ /* Replace TCPACK in txq when new coming one has higher ACK number. */ ++ TCPACK_SUP_REPLACE, ++ /* TCPACK_SUP_REPLACE + delayed TCPACK TX unless ACK to PSH DATA. ++ * This will give benefits to Half-Duplex bus interface(e.g. SDIO) that ++ * 1. we are able to read TCP DATA packets first from the bus ++ * 2. TCPACKs that don't need to hurry delivered remains longer in TXQ so can be suppressed. ++ */ ++ TCPACK_SUP_DELAYTX, ++ TCPACK_SUP_HOLD, ++ TCPACK_SUP_LAST_MODE ++}; ++ ++#ifdef BCMSDIO ++#define TCPACK_SUP_DEFAULT TCPACK_SUP_DELAYTX ++#elif defined(BCMPCIE) ++#define TCPACK_SUP_DEFAULT TCPACK_SUP_HOLD ++#else ++#define TCPACK_SUP_DEFAULT TCPACK_SUP_OFF ++#endif /* BCMSDIO */ ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++#if defined(TRAFFIC_MGMT_DWM) ++#define DHD_DWM_TBL_SIZE 57 ++/* DSCP WMM AC Mapping macros and structures */ ++#define DHD_TRF_MGMT_DWM_FILTER_BIT 0x8 ++#define DHD_TRF_MGMT_DWM_PRIO_BITS 0x7 ++#define DHD_TRF_MGMT_DWM_FAVORED_BIT 0x10 ++#define DHD_TRF_MGMT_DWM_PRIO(dwm_tbl_entry) ((dwm_tbl_entry) & DHD_TRF_MGMT_DWM_PRIO_BITS) ++#define DHD_TRF_MGMT_DWM_IS_FAVORED_SET(dwm_tbl_entry) \ ++ ((dwm_tbl_entry) & DHD_TRF_MGMT_DWM_FAVORED_BIT) ++#define DHD_TRF_MGMT_DWM_SET_FAVORED(dwm_tbl_entry) \ ++ ((dwm_tbl_entry) |= DHD_TRF_MGMT_DWM_FAVORED_BIT) ++#define DHD_TRF_MGMT_DWM_IS_FILTER_SET(dwm_tbl_entry) \ ++ ((dwm_tbl_entry) & DHD_TRF_MGMT_DWM_FILTER_BIT) ++#define DHD_TRF_MGMT_DWM_SET_FILTER(dwm_tbl_entry) \ ++ ((dwm_tbl_entry) |= DHD_TRF_MGMT_DWM_FILTER_BIT) ++ ++typedef struct { ++ uint8 dhd_dwm_enabled; ++ uint8 dhd_dwm_tbl[DHD_DWM_TBL_SIZE]; ++} dhd_trf_mgmt_dwm_tbl_t; ++#endif ++ ++#define DHD_NULL_CHK_AND_RET(cond) \ ++ if (!cond) { \ ++ DHD_ERROR(("%s " #cond " is NULL\n", __FUNCTION__)); \ ++ return; \ ++ } ++ ++#define DHD_NULL_CHK_AND_RET_VAL(cond, value) \ ++ if (!cond) { \ ++ DHD_ERROR(("%s " #cond " is NULL\n", __FUNCTION__)); \ ++ return value; \ ++ } ++ ++#define DHD_NULL_CHK_AND_GOTO(cond, label) \ ++ if (!cond) { \ ++ DHD_ERROR(("%s " #cond " is NULL\n", __FUNCTION__)); \ ++ goto label; \ ++ } ++ ++/* ++ * Accumulating the queue lengths of all flowring queues in a parent object, ++ * to assert flow control, when the cummulative queue length crosses an upper ++ * threshold defined on a parent object. Upper threshold may be maintained ++ * at a station level, at an interface level, or at a dhd instance. ++ * ++ * cumm_ctr_t abstraction: ++ * cumm_ctr_t abstraction may be enhanced to use an object with a hysterisis ++ * pause on/off threshold callback. ++ * All macros use the address of the cummulative length in the parent objects. ++ * ++ * BCM_GMAC3 builds use a single perimeter lock, as opposed to a per queue lock. ++ * Cummulative counters in parent objects may be updated without spinlocks. ++ * ++ * In non BCM_GMAC3, if a cummulative queue length is desired across all flows ++ * belonging to either of (a station, or an interface or a dhd instance), then ++ * an atomic operation is required using an atomic_t cummulative counters or ++ * using a spinlock. BCM_ROUTER_DHD uses the Linux atomic_t construct. ++ */ ++ ++/* Cummulative length not supported. */ ++typedef uint32 cumm_ctr_t; ++#define DHD_CUMM_CTR_PTR(clen) ((cumm_ctr_t*)(clen)) ++#define DHD_CUMM_CTR(clen) *(DHD_CUMM_CTR_PTR(clen)) /* accessor */ ++#define DHD_CUMM_CTR_READ(clen) DHD_CUMM_CTR(clen) /* read access */ ++#define DHD_CUMM_CTR_INIT(clen) \ ++ ASSERT(DHD_CUMM_CTR_PTR(clen) != DHD_CUMM_CTR_PTR(NULL)); ++#define DHD_CUMM_CTR_INCR(clen) \ ++ ASSERT(DHD_CUMM_CTR_PTR(clen) != DHD_CUMM_CTR_PTR(NULL)); ++#define DHD_CUMM_CTR_DECR(clen) \ ++ ASSERT(DHD_CUMM_CTR_PTR(clen) != DHD_CUMM_CTR_PTR(NULL)); ++ ++#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) ++struct tdls_peer_node { ++ uint8 addr[ETHER_ADDR_LEN]; ++ struct tdls_peer_node *next; ++}; ++typedef struct tdls_peer_node tdls_peer_node_t; ++typedef struct { ++ tdls_peer_node_t *node; ++ uint8 tdls_peer_count; ++} tdls_peer_tbl_t; ++#endif /* defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */ ++ ++#ifdef DHD_LOG_DUMP ++/* below structure describe ring buffer. */ ++struct dhd_log_dump_buf ++{ ++ spinlock_t lock; ++ unsigned int enable; ++ unsigned int wraparound; ++ unsigned long max; ++ unsigned int remain; ++ char* present; ++ char* front; ++ char* buffer; ++}; ++ ++#define DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE 256 ++extern void dhd_log_dump_write(int type, const char *fmt, ...); ++extern char *dhd_log_dump_get_timestamp(void); ++#endif /* DHD_LOG_DUMP */ ++ ++#if defined(CUSTOMER_HW2) ++#define DHD_COMMON_DUMP_PATH "/data/misc/wifi/" ++#else ++#define DHD_COMMON_DUMP_PATH "/installmedia/" ++#endif ++ ++struct cntry_locales_custom { ++ char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */ ++ char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */ ++ int32 custom_locale_rev; /* Custom local revisin default -1 */ ++}; ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++typedef struct timeout_info { ++ void *scan_timer_lock; ++ void *join_timer_lock; ++ void *cmd_timer_lock; ++ void *bus_timer_lock; ++ uint32 scan_timeout_val; ++ uint32 join_timeout_val; ++ uint32 cmd_timeout_val; ++ uint32 bus_timeout_val; ++ bool scan_timer_active; ++ bool join_timer_active; ++ bool cmd_timer_active; ++ bool bus_timer_active; ++ osl_timer_t *scan_timer; ++ osl_timer_t *join_timer; ++ osl_timer_t *cmd_timer; ++ osl_timer_t *bus_timer; ++ uint16 cmd_request_id; ++ uint32 cmd; ++ uint32 cmd_join_error; ++} timeout_info_t; ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++#ifdef HOFFLOAD_MODULES ++/* Metadata structure containing module information */ ++struct module_metadata { ++ void *data; /* module data */ ++ uint32_t size; /* module size */ ++ u64 data_addr; /* address of module data in host */ ++}; ++#endif ++ ++#ifdef DMAMAP_STATS ++typedef struct dmamap_stats { ++ uint64 txdata; ++ uint64 txdata_sz; ++ uint64 rxdata; ++ uint64 rxdata_sz; ++ uint64 ioctl_rx; ++ uint64 ioctl_rx_sz; ++ uint64 event_rx; ++ uint64 event_rx_sz; ++ uint64 info_rx; ++ uint64 info_rx_sz; ++ uint64 tsbuf_rx; ++ uint64 tsbuf_rx_sz; ++} dma_stats_t; ++#endif /* DMAMAP_STATS */ ++ ++/* Common structure for module and instance linkage */ ++typedef struct dhd_pub { ++ /* Linkage ponters */ ++ osl_t *osh; /* OSL handle */ ++ struct dhd_bus *bus; /* Bus module handle */ ++ struct dhd_prot *prot; /* Protocol module handle */ ++ struct dhd_info *info; /* Info module handle */ ++ struct dhd_dbg *dbg; /* Debugability module handle */ ++ ++ /* to NDIS developer, the structure dhd_common is redundant, ++ * please do NOT merge it back from other branches !!! ++ */ ++ ++#ifdef BCMDBUS ++ struct dbus_pub *dbus; ++#endif /* BCMDBUS */ ++ ++ /* Internal dhd items */ ++ bool up; /* Driver up/down (to OS) */ ++#ifdef WL_CFG80211 ++ spinlock_t up_lock; /* Synchronization with CFG80211 down */ ++#endif /* WL_CFG80211 */ ++ bool txoff; /* Transmit flow-controlled */ ++ bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */ ++ enum dhd_bus_state busstate; ++ uint dhd_bus_busy_state; /* Bus busy state */ ++ uint hdrlen; /* Total DHD header length (proto + bus) */ ++ uint maxctl; /* Max size rxctl request from proto to bus */ ++ uint rxsz; /* Rx buffer size bus module should use */ ++ uint8 wme_dp; /* wme discard priority */ ++ ++ /* Dongle media info */ ++ bool iswl; /* Dongle-resident driver is wl */ ++ ulong drv_version; /* Version of dongle-resident driver */ ++ struct ether_addr mac; /* MAC address obtained from dongle */ ++ dngl_stats_t dstats; /* Stats for dongle-based data */ ++ ++ /* Additional stats for the bus level */ ++ ulong tx_packets; /* Data packets sent to dongle */ ++ ulong tx_dropped; /* Data packets dropped in dhd */ ++ ulong tx_multicast; /* Multicast data packets sent to dongle */ ++ ulong tx_errors; /* Errors in sending data to dongle */ ++ ulong tx_ctlpkts; /* Control packets sent to dongle */ ++ ulong tx_ctlerrs; /* Errors sending control frames to dongle */ ++ ulong rx_packets; /* Packets sent up the network interface */ ++ ulong rx_multicast; /* Multicast packets sent up the network interface */ ++ ulong rx_errors; /* Errors processing rx data packets */ ++ ulong rx_ctlpkts; /* Control frames processed from dongle */ ++ ulong rx_ctlerrs; /* Errors in processing rx control frames */ ++ ulong rx_dropped; /* Packets dropped locally (no memory) */ ++ ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ ++ ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ ++ ulong rx_pktgetfail; /* Number of PKTGET failures in DHD on RX */ ++ ulong tx_pktgetfail; /* Number of PKTGET failures in DHD on TX */ ++ ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ ++ ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ ++ ulong fc_packets; /* Number of flow control pkts recvd */ ++ ++#ifdef DMAMAP_STATS ++ /* DMA Mapping statistics */ ++ dma_stats_t dma_stats; ++#endif /* DMAMAP_STATS */ ++ ++ /* Last error return */ ++ int bcmerror; ++ uint tickcnt; ++ ++ /* Last error from dongle */ ++ int dongle_error; ++ ++ uint8 country_code[WLC_CNTRY_BUF_SZ]; ++ ++ /* Suspend disable flag and "in suspend" flag */ ++ int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ ++ int in_suspend; /* flag set to 1 when early suspend called */ ++#ifdef PNO_SUPPORT ++ int pno_enable; /* pno status : "1" is pno enable */ ++ int pno_suspend; /* pno suspend status : "1" is pno suspended */ ++#endif /* PNO_SUPPORT */ ++ /* DTIM skip value, default 0(or 1) means wake each DTIM ++ * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3) ++ */ ++ int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */ ++#ifdef PKT_FILTER_SUPPORT ++ int early_suspended; /* Early suspend status */ ++ int dhcp_in_progress; /* DHCP period */ ++#endif ++ ++ /* Pkt filter defination */ ++ char * pktfilter[100]; ++ int pktfilter_count; ++ ++ wl_country_t dhd_cspec; /* Current Locale info */ ++#ifdef CUSTOM_COUNTRY_CODE ++ uint dhd_cflags; ++#endif /* CUSTOM_COUNTRY_CODE */ ++#if defined(DHD_BLOB_EXISTENCE_CHECK) ++ bool is_blob; /* Checking for existance of Blob file */ ++#endif /* DHD_BLOB_EXISTENCE_CHECK */ ++ bool force_country_change; ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ int op_mode; /* STA, HostAPD, WFD, SoftAP */ ++ ++/* Set this to 1 to use a seperate interface (p2p0) for p2p operations. ++ * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework ++ * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile ++ */ ++/* #define WL_ENABLE_P2P_IF 1 */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ ++ struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ ++#endif ++ ++#ifdef PROP_TXSTATUS ++ bool wlfc_enabled; ++ int wlfc_mode; ++ void* wlfc_state; ++ /* ++ Mode in which the dhd flow control shall operate. Must be set before ++ traffic starts to the device. ++ 0 - Do not do any proptxtstatus flow control ++ 1 - Use implied credit from a packet status ++ 2 - Use explicit credit ++ 3 - Only AMPDU hostreorder used. no wlfc. ++ */ ++ uint8 proptxstatus_mode; ++ bool proptxstatus_txoff; ++ bool proptxstatus_module_ignore; ++ bool proptxstatus_credit_ignore; ++ bool proptxstatus_txstatus_ignore; ++ ++ bool wlfc_rxpkt_chk; ++#ifdef LIMIT_BORROW ++ bool wlfc_borrow_allowed; ++#endif /* LIMIT_BORROW */ ++ /* ++ * implement below functions in each platform if needed. ++ */ ++ /* platform specific function whether to skip flow control */ ++ bool (*skip_fc)(void * dhdp, uint8 ifx); ++ /* platform specific function for wlfc_enable and wlfc_deinit */ ++ void (*plat_init)(void *dhd); ++ void (*plat_deinit)(void *dhd); ++#ifdef DHD_WLFC_THREAD ++ bool wlfc_thread_go; ++ struct task_struct* wlfc_thread; ++ wait_queue_head_t wlfc_wqhead; ++#endif /* DHD_WLFC_THREAD */ ++#endif /* PROP_TXSTATUS */ ++#ifdef PNO_SUPPORT ++ void *pno_state; ++#endif ++#ifdef RTT_SUPPORT ++ void *rtt_state; ++ bool rtt_supported; ++#endif ++ bool dongle_isolation; ++ bool is_pcie_watchdog_reset; ++ bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ ++ bool iovar_timeout_occured; /* flag to indicate iovar resumed on timeout */ ++#ifdef PCIE_FULL_DONGLE ++ bool d3ack_timeout_occured; /* flag to indicate d3ack resumed on timeout */ ++#endif /* PCIE_FULL_DONGLE */ ++#ifdef BT_OVER_SDIO ++ bool is_bt_recovery_required; ++#endif ++ int hang_was_sent; ++ int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ ++ int txcnt_timeout; /* counter txcnt timeout to send HANG */ ++#ifdef BCMPCIE ++ int d3ackcnt_timeout; /* counter d3ack timeout to send HANG */ ++#endif /* BCMPCIE */ ++ bool hang_report; /* enable hang report by default */ ++ uint16 hang_reason; /* reason codes for HANG event */ ++#if defined(DHD_HANG_SEND_UP_TEST) ++ uint req_hang_type; ++#endif /* DHD_HANG_SEND_UP_TEST */ ++#if defined(CONFIG_BCM_DETECT_CONSECUTIVE_HANG) ++ uint hang_counts; ++#endif /* CONFIG_BCM_DETECT_CONSECUTIVE_HANG */ ++#ifdef WLMEDIA_HTSF ++ uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ ++#endif ++#ifdef WLTDLS ++ bool tdls_enable; ++#endif ++ struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; ++ #define WLC_IOCTL_MAXBUF_FWCAP 512 ++ char fw_capabilities[WLC_IOCTL_MAXBUF_FWCAP]; ++ #define MAXSKBPEND 1024 ++ void *skbbuf[MAXSKBPEND]; ++ uint32 store_idx; ++ uint32 sent_idx; ++#ifdef DHDTCPACK_SUPPRESS ++ uint8 tcpack_sup_mode; /* TCPACK suppress mode */ ++ void *tcpack_sup_module; /* TCPACK suppress module */ ++ uint32 tcpack_sup_ratio; ++ uint32 tcpack_sup_delay; ++#endif /* DHDTCPACK_SUPPRESS */ ++#if defined(ARP_OFFLOAD_SUPPORT) ++ uint32 arp_version; ++#endif ++#ifdef DEBUG_DPC_THREAD_WATCHDOG ++ bool dhd_bug_on; ++#endif /* DEBUG_DPC_THREAD_WATCHDOG */ ++#ifdef CUSTOM_SET_CPUCORE ++ struct task_struct * current_dpc; ++ struct task_struct * current_rxf; ++ int chan_isvht80; ++#endif /* CUSTOM_SET_CPUCORE */ ++ ++ ++ void *sta_pool; /* pre-allocated pool of sta objects */ ++ void *staid_allocator; /* allocator of sta indexes */ ++#ifdef PCIE_FULL_DONGLE ++ bool flow_rings_inited; /* set this flag after initializing flow rings */ ++#endif /* PCIE_FULL_DONGLE */ ++ void *flowid_allocator; /* unique flowid allocator */ ++ void *flow_ring_table; /* flow ring table, include prot and bus info */ ++ void *if_flow_lkup; /* per interface flowid lkup hash table */ ++ void *flowid_lock; /* per os lock for flowid info protection */ ++ void *flowring_list_lock; /* per os lock for flowring list protection */ ++ uint32 num_flow_rings; ++ cumm_ctr_t cumm_ctr; /* cumm queue length placeholder */ ++ cumm_ctr_t l2cumm_ctr; /* level 2 cumm queue length placeholder */ ++ uint32 d2h_sync_mode; /* D2H DMA completion sync mode */ ++ uint8 flow_prio_map[NUMPRIO]; ++ uint8 flow_prio_map_type; ++ char enable_log[MAX_EVENT]; ++ bool dma_d2h_ring_upd_support; ++ bool dma_h2d_ring_upd_support; ++ bool dma_ring_upd_overwrite; /* host overwrites support setting */ ++ ++ bool idma_enable; ++ uint idma_inited; ++ bool idma_retention_ds; /* Implicit DMA memory retention */ ++ ++ bool ifrm_enable; /* implicit frm enable */ ++ uint ifrm_inited; /* implicit frm init */ ++ ++#ifdef DHD_WMF ++ bool wmf_ucast_igmp; ++#ifdef DHD_IGMP_UCQUERY ++ bool wmf_ucast_igmp_query; ++#endif ++#ifdef DHD_UCAST_UPNP ++ bool wmf_ucast_upnp; ++#endif ++#endif /* DHD_WMF */ ++#if defined(TRAFFIC_MGMT_DWM) ++ dhd_trf_mgmt_dwm_tbl_t dhd_tm_dwm_tbl; ++#endif ++#ifdef DHD_L2_FILTER ++ unsigned long l2_filter_cnt; /* for L2_FILTER ARP table timeout */ ++#endif /* DHD_L2_FILTER */ ++#ifdef DHD_SSSR_DUMP ++ bool sssr_inited; ++ sssr_reg_info_t sssr_reg_info; ++ uint8 *sssr_mempool; ++ uint *sssr_d11_before[MAX_NUM_D11CORES]; ++ uint *sssr_d11_after[MAX_NUM_D11CORES]; ++ bool sssr_d11_outofreset[MAX_NUM_D11CORES]; ++ uint *sssr_vasip_buf_before; ++ uint *sssr_vasip_buf_after; ++#endif /* DHD_SSSR_DUMP */ ++ uint8 *soc_ram; ++ uint32 soc_ram_length; ++ uint32 memdump_type; ++#ifdef DHD_FW_COREDUMP ++ uint32 memdump_enabled; ++ bool memdump_success; ++#endif /* DHD_FW_COREDUMP */ ++#ifdef PCIE_FULL_DONGLE ++#ifdef WLTDLS ++ tdls_peer_tbl_t peer_tbl; ++#endif /* WLTDLS */ ++ uint8 tx_in_progress; ++#endif /* PCIE_FULL_DONGLE */ ++#ifdef DHD_ULP ++ void *dhd_ulp; ++#endif ++#ifdef CACHE_FW_IMAGES ++ char *cached_fw; ++ int cached_fw_length; ++ char *cached_nvram; ++ int cached_nvram_length; ++ char *cached_clm; ++ int cached_clm_length; ++#endif ++#ifdef WLTDLS ++ uint32 tdls_mode; ++#endif ++#ifdef GSCAN_SUPPORT ++ bool lazy_roam_enable; ++#endif ++#if defined(PKT_FILTER_SUPPORT) && defined(APF) ++ bool apf_set; ++#endif /* PKT_FILTER_SUPPORT && APF */ ++#ifdef DHD_WET ++ void *wet_info; ++#endif ++ bool h2d_phase_supported; ++ bool force_dongletrap_on_bad_h2d_phase; ++ uint32 dongle_trap_data; ++ bool cto_enable; /* enable PCIE CTO Prevention and recovery */ ++ uint32 cto_threshold; /* PCIE CTO timeout threshold */ ++ bool fw_download_done; ++ trap_t last_trap_info; /* trap info from the last trap */ ++ uint8 rand_mac_oui[DOT11_OUI_LEN]; ++#ifdef DHD_LOSSLESS_ROAMING ++ uint8 dequeue_prec_map; ++ uint8 prio_8021x; ++#endif ++#ifdef REPORT_FATAL_TIMEOUTS ++ timeout_info_t *timeout_info; ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ /* timesync link */ ++ struct dhd_ts *ts; ++ bool d2h_hostrdy_supported; ++#if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING) ++ bool d11_tx_status; ++#endif /* DBG_PKT_MON || DHD_PKT_LOGGING */ ++ uint16 ndo_version; /* ND offload version supported */ ++#ifdef NDO_CONFIG_SUPPORT ++ bool ndo_enable; /* ND offload feature enable */ ++ bool ndo_host_ip_overflow; /* # of host ip addr exceed FW capacity */ ++ uint32 ndo_max_host_ip; /* # of host ip addr supported by FW */ ++#endif /* NDO_CONFIG_SUPPORT */ ++#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) ++ uint8 log_capture_enable; ++#endif /* DHD_EFI && DHD_LOG_DUMP */ ++ bool max_dtim_enable; /* use MAX bcn_li_dtim value in suspend mode */ ++#ifdef PCIE_OOB ++ bool d2h_no_oob_dw; ++#endif /* PCIE_OOB */ ++#ifdef PCIE_INB_DW ++ bool d2h_inband_dw; ++ enum dhd_bus_ds_state ds_state; ++#endif /* PCIE_INB_DW */ ++#ifdef CUSTOM_SET_ANTNPM ++ uint32 mimo_ant_set; ++#endif /* CUSTOM_SET_ANTNPM */ ++#ifdef CUSTOM_SET_OCLOFF ++ bool ocl_off; ++#endif /* CUSTOM_SET_OCLOFF */ ++#ifdef HOFFLOAD_MODULES ++ struct module_metadata hmem; ++#endif ++ bool wbtext_support; ++#ifdef DUMP_IOCTL_IOV_LIST ++ /* dump iovar list */ ++ dll_t dump_iovlist_head; ++ uint8 dump_iovlist_len; ++#endif /* DUMP_IOCTL_IOV_LIST */ ++#ifdef DHD_DEBUG ++/* memwaste feature */ ++ dll_t mw_list_head; /* memwaste list head */ ++ uint32 mw_id; /* memwaste list unique id */ ++#endif /* DHD_DEBUG */ ++#ifdef WLTDLS ++ spinlock_t tdls_lock; ++#endif /* WLTDLS */ ++#ifdef WLADPS_SEAK_AP_WAR ++ uint32 disabled_adps; ++#endif /* WLADPS_SEAK_AP_WAR */ ++ bool ext_trap_data_supported; ++ uint32 *extended_trap_data; ++#ifdef DHD_PKT_LOGGING ++ struct dhd_pktlog *pktlog; ++#endif /* DHD_PKT_LOGGING */ ++#if defined(STAT_REPORT) ++ void *stat_report_info; ++#endif ++ char *clm_path; /* module_param: path to clm vars file */ ++ char *conf_path; /* module_param: path to config vars file */ ++ struct dhd_conf *conf; /* Bus module handle */ ++ void *adapter; /* adapter information, interrupt, fw path etc. */ ++ void *event_params; ++#ifdef BCMDBUS ++ bool dhd_remove; ++#endif /* BCMDBUS */ ++#ifdef WL_ESCAN ++ struct wl_escan_info *escan; ++#endif ++#if defined(WL_WIRELESS_EXT) ++ void *wext_info; ++#endif ++#ifdef WL_EXT_IAPSTA ++ void *iapsta_params; ++#endif ++ int hostsleep; ++#ifdef SENDPROB ++ bool recv_probereq; ++#endif ++} dhd_pub_t; ++ ++typedef struct { ++ uint rxwake; ++ uint rcwake; ++#ifdef DHD_WAKE_RX_STATUS ++ uint rx_bcast; ++ uint rx_arp; ++ uint rx_mcast; ++ uint rx_multi_ipv6; ++ uint rx_icmpv6; ++ uint rx_icmpv6_ra; ++ uint rx_icmpv6_na; ++ uint rx_icmpv6_ns; ++ uint rx_multi_ipv4; ++ uint rx_multi_other; ++ uint rx_ucast; ++#endif /* DHD_WAKE_RX_STATUS */ ++#ifdef DHD_WAKE_EVENT_STATUS ++ uint rc_event[WLC_E_LAST]; ++#endif /* DHD_WAKE_EVENT_STATUS */ ++} wake_counts_t; ++ ++#if defined(PCIE_FULL_DONGLE) ++ ++/* Packet Tag for PCIE Full Dongle DHD */ ++typedef struct dhd_pkttag_fd { ++ uint16 flowid; /* Flowring Id */ ++ uint16 dataoff; /* start of packet */ ++ uint16 dma_len; /* pkt len for DMA_MAP/UNMAP */ ++ dmaaddr_t pa; /* physical address */ ++ void *dmah; /* dma mapper handle */ ++ void *secdma; /* secure dma sec_cma_info handle */ ++} dhd_pkttag_fd_t; ++ ++/* Packet Tag for DHD PCIE Full Dongle */ ++#define DHD_PKTTAG_FD(pkt) ((dhd_pkttag_fd_t *)(PKTTAG(pkt))) ++ ++#define DHD_PKT_GET_FLOWID(pkt) ((DHD_PKTTAG_FD(pkt))->flowid) ++#define DHD_PKT_SET_FLOWID(pkt, pkt_flowid) \ ++ DHD_PKTTAG_FD(pkt)->flowid = (uint16)(pkt_flowid) ++ ++#define DHD_PKT_GET_DATAOFF(pkt) ((DHD_PKTTAG_FD(pkt))->dataoff) ++#define DHD_PKT_SET_DATAOFF(pkt, pkt_dataoff) \ ++ DHD_PKTTAG_FD(pkt)->dataoff = (uint16)(pkt_dataoff) ++ ++#define DHD_PKT_GET_DMA_LEN(pkt) ((DHD_PKTTAG_FD(pkt))->dma_len) ++#define DHD_PKT_SET_DMA_LEN(pkt, pkt_dma_len) \ ++ DHD_PKTTAG_FD(pkt)->dma_len = (uint16)(pkt_dma_len) ++ ++#define DHD_PKT_GET_PA(pkt) ((DHD_PKTTAG_FD(pkt))->pa) ++#define DHD_PKT_SET_PA(pkt, pkt_pa) \ ++ DHD_PKTTAG_FD(pkt)->pa = (dmaaddr_t)(pkt_pa) ++ ++#define DHD_PKT_GET_DMAH(pkt) ((DHD_PKTTAG_FD(pkt))->dmah) ++#define DHD_PKT_SET_DMAH(pkt, pkt_dmah) \ ++ DHD_PKTTAG_FD(pkt)->dmah = (void *)(pkt_dmah) ++ ++#define DHD_PKT_GET_SECDMA(pkt) ((DHD_PKTTAG_FD(pkt))->secdma) ++#define DHD_PKT_SET_SECDMA(pkt, pkt_secdma) \ ++ DHD_PKTTAG_FD(pkt)->secdma = (void *)(pkt_secdma) ++#endif /* PCIE_FULL_DONGLE */ ++ ++#if defined(BCMWDF) ++typedef struct { ++ dhd_pub_t *dhd_pub; ++} dhd_workitem_context_t; ++ ++WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(dhd_workitem_context_t, dhd_get_dhd_workitem_context) ++#endif /* (BCMWDF) */ ++ ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++ ++ #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); ++ #define _DHD_PM_RESUME_WAIT(a, b) do {\ ++ int retry = 0; \ ++ SMP_RD_BARRIER_DEPENDS(); \ ++ while (dhd_mmc_suspend && retry++ != b) { \ ++ SMP_RD_BARRIER_DEPENDS(); \ ++ wait_event_interruptible_timeout(a, !dhd_mmc_suspend, 1); \ ++ } \ ++ } while (0) ++ #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) ++ #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) ++ #define DHD_PM_RESUME_RETURN_ERROR(a) do { \ ++ if (dhd_mmc_suspend) { \ ++ printf("%s[%d]: mmc is still in suspend state!!!\n", \ ++ __FUNCTION__, __LINE__); \ ++ return a; \ ++ } \ ++ } while (0) ++ #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) ++ ++ #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); ++ #define SPINWAIT_SLEEP(a, exp, us) do { \ ++ uint countdown = (us) + 9999; \ ++ while ((exp) && (countdown >= 10000)) { \ ++ wait_event_interruptible_timeout(a, FALSE, 1); \ ++ countdown -= 10000; \ ++ } \ ++ } while (0) ++ ++ #else ++ ++ #define DHD_PM_RESUME_WAIT_INIT(a) ++ #define DHD_PM_RESUME_WAIT(a) ++ #define DHD_PM_RESUME_WAIT_FOREVER(a) ++ #define DHD_PM_RESUME_RETURN_ERROR(a) ++ #define DHD_PM_RESUME_RETURN ++ ++ #define DHD_SPINWAIT_SLEEP_INIT(a) ++ #define SPINWAIT_SLEEP(a, exp, us) do { \ ++ uint countdown = (us) + 9; \ ++ while ((exp) && (countdown >= 10)) { \ ++ OSL_DELAY(10); \ ++ countdown -= 10; \ ++ } \ ++ } while (0) ++ ++ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++ ++#ifndef OSL_SLEEP ++#define OSL_SLEEP(ms) OSL_DELAY(ms*1000) ++#endif /* OSL_SLEEP */ ++ ++#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ ++ ++#ifdef PNO_SUPPORT ++int dhd_pno_clean(dhd_pub_t *dhd); ++#endif /* PNO_SUPPORT */ ++ ++#ifdef HOFFLOAD_MODULES ++void dhd_linux_get_modfw_address(dhd_pub_t *dhd); ++#endif ++ ++/* ++ * Wake locks are an Android power management concept. They are used by applications and services ++ * to request CPU resources. ++ */ ++extern int dhd_os_wake_lock(dhd_pub_t *pub); ++extern int dhd_os_wake_unlock(dhd_pub_t *pub); ++extern int dhd_os_wake_lock_waive(dhd_pub_t *pub); ++extern int dhd_os_wake_lock_restore(dhd_pub_t *pub); ++extern void dhd_event_wake_lock(dhd_pub_t *pub); ++extern void dhd_event_wake_unlock(dhd_pub_t *pub); ++extern void dhd_pm_wake_lock_timeout(dhd_pub_t *pub, int val); ++extern void dhd_pm_wake_unlock(dhd_pub_t *pub); ++extern void dhd_txfl_wake_lock_timeout(dhd_pub_t *pub, int val); ++extern void dhd_txfl_wake_unlock(dhd_pub_t *pub); ++extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); ++extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); ++extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); ++extern int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub); ++extern int dhd_os_wd_wake_lock(dhd_pub_t *pub); ++extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub); ++extern void dhd_os_wake_lock_init(struct dhd_info *dhd); ++extern void dhd_os_wake_lock_destroy(struct dhd_info *dhd); ++#ifdef DHD_USE_SCAN_WAKELOCK ++extern void dhd_os_scan_wake_lock_timeout(dhd_pub_t *pub, int val); ++extern void dhd_os_scan_wake_unlock(dhd_pub_t *pub); ++#endif /* BCMPCIE_SCAN_WAKELOCK */ ++ ++inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_init(&dhdp->wl_softap_lock); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++} ++ ++inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_lock(&dhdp->wl_softap_lock); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++} ++ ++inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_unlock(&dhdp->wl_softap_lock); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++} ++ ++#define PRINT_CALL_INFO(str) ++#define PRINT_CALL_INFO_TIMEOUT(str, val) ++#define DHD_OS_WAKE_LOCK(pub) \ ++ do { \ ++ PRINT_CALL_INFO("call wakelock"); \ ++ dhd_os_wake_lock(pub); \ ++ } while (0) ++#define DHD_OS_WAKE_UNLOCK(pub) \ ++ do { \ ++ PRINT_CALL_INFO("call wake_unlock"); \ ++ dhd_os_wake_unlock(pub); \ ++ } while (0) ++#define DHD_EVENT_WAKE_LOCK(pub) \ ++ do { \ ++ PRINT_CALL_INFO("call event_wake lock"); \ ++ dhd_event_wake_lock(pub); \ ++ } while (0) ++#define DHD_EVENT_WAKE_UNLOCK(pub) \ ++ do { \ ++ PRINT_CALL_INFO("call event_wake unlock"); \ ++ dhd_event_wake_unlock(pub); \ ++ } while (0) ++#define DHD_PM_WAKE_LOCK_TIMEOUT(pub, val) \ ++ do { \ ++ PRINT_CALL_INFO("call pm_wake_timeout enable"); \ ++ dhd_pm_wake_lock_timeout(pub, val); \ ++ } while (0) ++#define DHD_PM_WAKE_UNLOCK(pub) \ ++ do { \ ++ PRINT_CALL_INFO("call pm_wake unlock"); \ ++ dhd_pm_wake_unlock(pub); \ ++ } while (0) ++#define DHD_TXFL_WAKE_LOCK_TIMEOUT(pub, val) \ ++ do { \ ++ PRINT_CALL_INFO("call pm_wake_timeout enable"); \ ++ dhd_txfl_wake_lock_timeout(pub, val); \ ++ } while (0) ++#define DHD_TXFL_WAKE_UNLOCK(pub) \ ++ do { \ ++ PRINT_CALL_INFO("call pm_wake unlock"); \ ++ dhd_txfl_wake_unlock(pub); \ ++ } while (0) ++#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) \ ++ do { \ ++ PRINT_CALL_INFO("call wake_lock_timeout"); \ ++ dhd_os_wake_lock_timeout(pub); \ ++ } while (0) ++#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ ++ do { \ ++ PRINT_CALL_INFO_TIMEOUT("call wake_lock_rx_timeout_enable", val); \ ++ dhd_os_wake_lock_rx_timeout_enable(pub, val); \ ++ } while (0) ++#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ ++ do { \ ++ PRINT_CALL_INFO_TIMEOUT("call wake_lock_ctrl_timeout_enable", val); \ ++ dhd_os_wake_lock_ctrl_timeout_enable(pub, val); \ ++ } while (0) ++#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \ ++ do { \ ++ PRINT_CALL_INFO("call wake_lock_ctrl_timeout_cancel"); \ ++ dhd_os_wake_lock_ctrl_timeout_cancel(pub); \ ++ } while (0) ++#define DHD_OS_WAKE_LOCK_WAIVE(pub) \ ++ do { \ ++ PRINT_CALL_INFO("call wake_lock_waive"); \ ++ dhd_os_wake_lock_waive(pub); \ ++ } while (0) ++#define DHD_OS_WAKE_LOCK_RESTORE(pub) \ ++ do { \ ++ PRINT_CALL_INFO("call wake_lock_restore"); \ ++ dhd_os_wake_lock_restore(pub); \ ++ } while (0) ++#define DHD_OS_WAKE_LOCK_INIT(dhd) \ ++ do { \ ++ PRINT_CALL_INFO("call wake_lock_init"); \ ++ dhd_os_wake_lock_init(dhd); \ ++ } while (0) ++#define DHD_OS_WAKE_LOCK_DESTROY(dhd) \ ++ do { \ ++ PRINT_CALL_INFO("call wake_lock_destroy"); \ ++ dhd_os_wake_lock_destroy(dhd); \ ++ } while (0) ++ ++#define DHD_OS_WD_WAKE_LOCK(pub) dhd_os_wd_wake_lock(pub) ++#define DHD_OS_WD_WAKE_UNLOCK(pub) dhd_os_wd_wake_unlock(pub) ++ ++#ifdef DHD_USE_SCAN_WAKELOCK ++#ifdef DHD_DEBUG_SCAN_WAKELOCK ++#define PRINT_SCAN_CALL(str) printf("%s: %s %d\n", \ ++ str, __FUNCTION__, __LINE__) ++#else ++#define PRINT_SCAN_CALL(str) ++#endif /* DHD_DEBUG_SCAN_WAKELOCK */ ++#define DHD_OS_SCAN_WAKE_LOCK_TIMEOUT(pub, val) \ ++ do { \ ++ PRINT_SCAN_CALL("call wake_lock_scan"); \ ++ dhd_os_scan_wake_lock_timeout(pub, val); \ ++ } while (0) ++#define DHD_OS_SCAN_WAKE_UNLOCK(pub) \ ++ do { \ ++ PRINT_SCAN_CALL("call wake_unlock_scan"); \ ++ dhd_os_scan_wake_unlock(pub); \ ++ } while (0) ++#else ++#define DHD_OS_SCAN_WAKE_LOCK_TIMEOUT(pub, val) ++#define DHD_OS_SCAN_WAKE_UNLOCK(pub) ++#endif /* DHD_USE_SCAN_WAKELOCK */ ++ ++#ifdef BCMPCIE_OOB_HOST_WAKE ++#define OOB_WAKE_LOCK_TIMEOUT 500 ++extern void dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val); ++extern void dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub); ++#define DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(pub, val) dhd_os_oob_irq_wake_lock_timeout(pub, val) ++#define DHD_OS_OOB_IRQ_WAKE_UNLOCK(pub) dhd_os_oob_irq_wake_unlock(pub) ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ ++#define DHD_PACKET_TIMEOUT_MS 500 ++#define DHD_EVENT_TIMEOUT_MS 1500 ++#define SCAN_WAKE_LOCK_TIMEOUT 10000 ++#define MAX_TX_TIMEOUT 500 ++ ++/* Enum for IOCTL recieved status */ ++typedef enum dhd_ioctl_recieved_status ++{ ++ IOCTL_WAIT = 0, ++ IOCTL_RETURN_ON_SUCCESS, ++ IOCTL_RETURN_ON_TRAP, ++ IOCTL_RETURN_ON_BUS_STOP, ++ IOCTL_RETURN_ON_ERROR ++} dhd_ioctl_recieved_status_t; ++ ++/* interface operations (register, remove) should be atomic, use this lock to prevent race ++ * condition among wifi on/off and interface operation functions ++ */ ++void dhd_net_if_lock(struct net_device *dev); ++void dhd_net_if_unlock(struct net_device *dev); ++#if defined(MULTIPLE_SUPPLICANT) ++extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && defined(MULTIPLE_SUPPLICANT) ++extern struct mutex _dhd_mutex_lock_; ++#define DHD_MUTEX_IS_LOCK_RETURN() \ ++ if (mutex_is_locked(&_dhd_mutex_lock_) != 0) { \ ++ printf("%s : probe is already running! return.\n", __FUNCTION__); \ ++ return 0; \ ++ } ++#define DHD_MUTEX_LOCK() \ ++ do { \ ++ if (mutex_is_locked(&_dhd_mutex_lock_) == 0) { \ ++ printf("%s : no mutex held. set lock\n", __FUNCTION__); \ ++ } else { \ ++ printf("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__); \ ++ } \ ++ mutex_lock(&_dhd_mutex_lock_); \ ++ } while (0) ++#define DHD_MUTEX_UNLOCK() \ ++ do { \ ++ mutex_unlock(&_dhd_mutex_lock_); \ ++ printf("%s : the lock is released.\n", __FUNCTION__); \ ++ } while (0) ++#else ++#define DHD_MUTEX_IS_LOCK_RETURN(a) do {} while (0) ++#define DHD_MUTEX_LOCK(a) do {} while (0) ++#define DHD_MUTEX_UNLOCK(a) do {} while (0) ++#endif ++ ++typedef enum dhd_attach_states ++{ ++ DHD_ATTACH_STATE_INIT = 0x0, ++ DHD_ATTACH_STATE_NET_ALLOC = 0x1, ++ DHD_ATTACH_STATE_DHD_ALLOC = 0x2, ++ DHD_ATTACH_STATE_ADD_IF = 0x4, ++ DHD_ATTACH_STATE_PROT_ATTACH = 0x8, ++ DHD_ATTACH_STATE_WL_ATTACH = 0x10, ++ DHD_ATTACH_STATE_THREADS_CREATED = 0x20, ++ DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, ++ DHD_ATTACH_STATE_CFG80211 = 0x80, ++ DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, ++ DHD_ATTACH_TIMESYNC_ATTACH_DONE = 0x200, ++ DHD_ATTACH_LOGTRACE_INIT = 0x400, ++ DHD_ATTACH_STATE_LB_ATTACH_DONE = 0x800, ++ DHD_ATTACH_STATE_DONE = 0x1000 ++} dhd_attach_states_t; ++ ++/* Value -1 means we are unsuccessful in creating the kthread. */ ++#define DHD_PID_KT_INVALID -1 ++/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ ++#define DHD_PID_KT_TL_INVALID -2 ++ ++/* ++ * Exported from dhd OS modules (dhd_linux/dhd_ndis) ++ */ ++ ++/* Indication from bus module regarding presence/insertion of dongle. ++ * Return dhd_pub_t pointer, used as handle to OS module in later calls. ++ * Returned structure should have bus and prot pointers filled in. ++ * bus_hdrlen specifies required headroom for bus module header. ++ */ ++extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen ++#ifdef BCMDBUS ++ , void *adapter ++#endif ++); ++#if defined(WLP2P) && defined(WL_CFG80211) ++/* To allow attach/detach calls corresponding to p2p0 interface */ ++extern int dhd_attach_p2p(dhd_pub_t *); ++extern int dhd_detach_p2p(dhd_pub_t *); ++#endif /* WLP2P && WL_CFG80211 */ ++extern int dhd_register_if(dhd_pub_t *dhdp, int idx, bool need_rtnl_lock); ++ ++/* Indication from bus module regarding removal/absence of dongle */ ++extern void dhd_detach(dhd_pub_t *dhdp); ++extern void dhd_free(dhd_pub_t *dhdp); ++extern void dhd_clear(dhd_pub_t *dhdp); ++ ++/* Indication from bus module to change flow-control state */ ++extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); ++ ++/* Store the status of a connection attempt for later retrieval by an iovar */ ++extern void dhd_store_conn_status(uint32 event, uint32 status, uint32 reason); ++ ++extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); ++ ++extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); ++ ++/* Return pointer to interface name */ ++extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); ++ ++#ifdef DHD_UCODE_DOWNLOAD ++/* Returns the ucode path */ ++extern char *dhd_get_ucode_path(dhd_pub_t *dhdp); ++#endif /* DHD_UCODE_DOWNLOAD */ ++ ++/* Request scheduling of the bus dpc */ ++extern void dhd_sched_dpc(dhd_pub_t *dhdp); ++ ++/* Notify tx completion */ ++extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); ++ ++#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */ ++#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */ ++#define WIFI_FEATURE_HOTSPOT 0x0004 /* Support for GAS/ANQP */ ++#define WIFI_FEATURE_P2P 0x0008 /* Wifi-Direct */ ++#define WIFI_FEATURE_SOFT_AP 0x0010 /* Soft AP */ ++#define WIFI_FEATURE_GSCAN 0x0020 /* Google-Scan APIs */ ++#define WIFI_FEATURE_NAN 0x0040 /* Neighbor Awareness Networking */ ++#define WIFI_FEATURE_D2D_RTT 0x0080 /* Device-to-device RTT */ ++#define WIFI_FEATURE_D2AP_RTT 0x0100 /* Device-to-AP RTT */ ++#define WIFI_FEATURE_BATCH_SCAN 0x0200 /* Batched Scan (legacy) */ ++#define WIFI_FEATURE_PNO 0x0400 /* Preferred network offload */ ++#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 /* Support for two STAs */ ++#define WIFI_FEATURE_TDLS 0x1000 /* Tunnel directed link setup */ ++#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 /* Support for TDLS off channel */ ++#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */ ++#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA Concurrency */ ++#define WIFI_FEATURE_LINKSTAT 0x10000 /* Support for Linkstats */ ++#define WIFI_FEATURE_LOGGER 0x20000 /* WiFi Logger */ ++#define WIFI_FEATURE_HAL_EPNO 0x40000 /* WiFi PNO enhanced */ ++#define WIFI_FEATURE_RSSI_MONITOR 0x80000 /* RSSI Monitor */ ++#define WIFI_FEATURE_MKEEP_ALIVE 0x100000 /* WiFi mkeep_alive */ ++#define WIFI_FEATURE_CONFIG_NDO 0x200000 /* ND offload configure */ ++#define WIFI_FEATURE_TX_TRANSMIT_POWER 0x400000 /* Capture Tx transmit power levels */ ++#define WIFI_FEATURE_INVALID 0xFFFFFFFF /* Invalid Feature */ ++ ++#define MAX_FEATURE_SET_CONCURRRENT_GROUPS 3 ++ ++extern int dhd_dev_get_feature_set(struct net_device *dev); ++extern int dhd_dev_get_feature_set_matrix(struct net_device *dev, int num); ++extern int dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui); ++#ifdef CUSTOM_FORCE_NODFS_FLAG ++extern int dhd_dev_set_nodfs(struct net_device *dev, uint nodfs); ++#endif /* CUSTOM_FORCE_NODFS_FLAG */ ++ ++#ifdef NDO_CONFIG_SUPPORT ++#ifndef NDO_MAX_HOST_IP_ENTRIES ++#define NDO_MAX_HOST_IP_ENTRIES 10 ++#endif /* NDO_MAX_HOST_IP_ENTRIES */ ++extern int dhd_dev_ndo_cfg(struct net_device *dev, u8 enable); ++extern int dhd_dev_ndo_update_inet6addr(struct net_device * dev); ++#endif /* NDO_CONFIG_SUPPORT */ ++extern int dhd_set_rand_mac_oui(dhd_pub_t *dhd); ++#ifdef GSCAN_SUPPORT ++extern int dhd_dev_set_lazy_roam_cfg(struct net_device *dev, ++ wlc_roam_exp_params_t *roam_param); ++extern int dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable); ++extern int dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, ++ wl_bssid_pref_cfg_t *bssid_pref, uint32 flush); ++extern int dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, ++ uint32 len, uint32 flush); ++extern int dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *whitelist, ++ uint32 len, uint32 flush); ++#endif /* GSCAN_SUPPORT */ ++ ++/* OS independent layer functions */ ++extern void dhd_os_dhdiovar_lock(dhd_pub_t *pub); ++extern void dhd_os_dhdiovar_unlock(dhd_pub_t *pub); ++extern int dhd_os_proto_block(dhd_pub_t * pub); ++extern int dhd_os_proto_unblock(dhd_pub_t * pub); ++extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition); ++extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); ++extern unsigned int dhd_os_get_ioctl_resp_timeout(void); ++extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); ++extern void dhd_os_ioctl_resp_lock(dhd_pub_t * pub); ++extern void dhd_os_ioctl_resp_unlock(dhd_pub_t * pub); ++#ifdef PCIE_FULL_DONGLE ++extern void dhd_wakeup_ioctl_event(dhd_pub_t *pub, dhd_ioctl_recieved_status_t reason); ++#else ++static INLINE void dhd_wakeup_ioctl_event(dhd_pub_t *pub, dhd_ioctl_recieved_status_t reason) ++{ printf("%s is NOT implemented for SDIO", __FUNCTION__); return; } ++#endif ++#ifdef SHOW_LOGTRACE ++extern int dhd_os_read_file(void *file, char *buf, uint32 size); ++extern int dhd_os_seek_file(void *file, int64 offset); ++#endif /* SHOW_LOGTRACE */ ++ ++extern void ++dhd_pcie_dump_core_regs(dhd_pub_t * pub, uint32 index, uint32 first_addr, uint32 last_addr); ++extern void wl_dhdpcie_dump_regs(void * context); ++ ++#define DHD_OS_IOCTL_RESP_LOCK(x) ++#define DHD_OS_IOCTL_RESP_UNLOCK(x) ++ ++ ++extern int dhd_os_get_image_block(char * buf, int len, void * image); ++extern int dhd_os_get_image_size(void * image); ++#if defined(BT_OVER_SDIO) ++extern int dhd_os_gets_image(dhd_pub_t *pub, char *str, int len, void *image); ++extern void dhdsdio_bus_usr_cnt_inc(dhd_pub_t *pub); ++extern void dhdsdio_bus_usr_cnt_dec(dhd_pub_t *pub); ++#endif /* (BT_OVER_SDIO) */ ++extern void * dhd_os_open_image(char * filename); ++extern void dhd_os_close_image(void * image); ++extern void dhd_os_wd_timer(void *bus, uint wdtick); ++#ifdef DHD_PCIE_RUNTIMEPM ++extern void dhd_os_runtimepm_timer(void *bus, uint tick); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++extern void dhd_os_sdlock(dhd_pub_t * pub); ++extern void dhd_os_sdunlock(dhd_pub_t * pub); ++extern void dhd_os_sdlock_txq(dhd_pub_t * pub); ++extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); ++extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); ++extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); ++extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); ++extern void dhd_os_tracelog(const char *format, ...); ++#ifdef DHDTCPACK_SUPPRESS ++extern unsigned long dhd_os_tcpacklock(dhd_pub_t *pub); ++extern void dhd_os_tcpackunlock(dhd_pub_t *pub, unsigned long flags); ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++extern int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr); ++extern int dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff); ++extern int dhd_custom_get_mac_address(void *adapter, unsigned char *buf); ++#if defined(CUSTOM_COUNTRY_CODE) ++extern void get_customized_country_code(void *adapter, char *country_iso_code, ++ wl_country_t *cspec, u32 flags); ++#else ++extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec); ++#endif /* CUSTOM_COUNTRY_CODE */ ++extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); ++extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); ++extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); ++extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); ++extern int dhd_os_send_hang_message(dhd_pub_t *dhdp); ++extern void dhd_set_version_info(dhd_pub_t *pub, char *fw); ++extern bool dhd_os_check_if_up(dhd_pub_t *pub); ++extern int dhd_os_check_wakelock(dhd_pub_t *pub); ++extern int dhd_os_check_wakelock_all(dhd_pub_t *pub); ++extern int dhd_get_instance(dhd_pub_t *pub); ++#ifdef CUSTOM_SET_CPUCORE ++extern void dhd_set_cpucore(dhd_pub_t *dhd, int set); ++#endif /* CUSTOM_SET_CPUCORE */ ++ ++#if defined(KEEP_ALIVE) ++extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); ++#endif /* KEEP_ALIVE */ ++ ++#if defined(DHD_FW_COREDUMP) ++void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size); ++#endif /* DHD_FW_COREDUMP */ ++ ++void dhd_schedule_sssr_dump(dhd_pub_t *dhdp); ++ ++#ifdef SUPPORT_AP_POWERSAVE ++extern int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable); ++#endif /* SUPPORT_AP_POWERSAVE */ ++ ++#ifdef PKT_FILTER_SUPPORT ++#define DHD_UNICAST_FILTER_NUM 0 ++#define DHD_BROADCAST_FILTER_NUM 1 ++#define DHD_MULTICAST4_FILTER_NUM 2 ++#define DHD_MULTICAST6_FILTER_NUM 3 ++#define DHD_MDNS_FILTER_NUM 4 ++#define DHD_ARP_FILTER_NUM 5 ++#define DHD_BROADCAST_ARP_FILTER_NUM 6 ++#define DHD_IP4BCAST_DROP_FILTER_NUM 7 ++#define DISCARD_IPV4_MCAST "102 1 6 IP4_H:16 0xf0 0xe0" ++#define DISCARD_IPV6_MCAST "103 1 6 IP6_H:24 0xff 0xff" ++extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val); ++extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); ++extern int dhd_packet_filter_add_remove(dhd_pub_t *dhdp, int add_remove, int num); ++extern int net_os_enable_packet_filter(struct net_device *dev, int val); ++extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); ++extern int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val); ++#endif /* PKT_FILTER_SUPPORT */ ++ ++ ++#if defined(BCMPCIE) ++extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bcn_interval); ++#else ++extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); ++#endif /* OEM_ANDROID && BCMPCIE */ ++ ++extern bool dhd_support_sta_mode(dhd_pub_t *dhd); ++extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); ++ ++#ifdef RSSI_MONITOR_SUPPORT ++extern int dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, ++ int8 max_rssi, int8 min_rssi); ++#endif /* RSSI_MONITOR_SUPPORT */ ++ ++#ifdef DHDTCPACK_SUPPRESS ++extern int dhd_dev_set_tcpack_sup_mode_cfg(struct net_device *dev, uint8 enable); ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++#define DHD_RSSI_MONITOR_EVT_VERSION 1 ++typedef struct { ++ uint8 version; ++ int8 cur_rssi; ++ struct ether_addr BSSID; ++} dhd_rssi_monitor_evt_t; ++ ++typedef struct { ++ uint32 limit; /* Expiration time (usec) */ ++ uint32 increment; /* Current expiration increment (usec) */ ++ uint32 elapsed; /* Current elapsed time (usec) */ ++ uint32 tick; /* O/S tick time (usec) */ ++} dhd_timeout_t; ++ ++#ifdef SHOW_LOGTRACE ++typedef struct { ++ int num_fmts; ++ char **fmts; ++ char *raw_fmts; ++ char *raw_sstr; ++ uint32 fmts_size; ++ uint32 raw_fmts_size; ++ uint32 raw_sstr_size; ++ uint32 ramstart; ++ uint32 rodata_start; ++ uint32 rodata_end; ++ char *rom_raw_sstr; ++ uint32 rom_raw_sstr_size; ++ uint32 rom_ramstart; ++ uint32 rom_rodata_start; ++ uint32 rom_rodata_end; ++} dhd_event_log_t; ++#endif /* SHOW_LOGTRACE */ ++ ++#ifdef KEEP_ALIVE ++extern int dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, uint8 mkeep_alive_id, uint8 *ip_pkt, ++ uint16 ip_pkt_len, uint8* src_mac_addr, uint8* dst_mac_addr, uint32 period_msec); ++extern int dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, uint8 mkeep_alive_id); ++#endif /* KEEP_ALIVE */ ++ ++#if defined(PKT_FILTER_SUPPORT) && defined(APF) ++/* ++ * As per Google's current implementation, there will be only one APF filter. ++ * Therefore, userspace doesn't bother about filter id and because of that ++ * DHD has to manage the filter id. ++ */ ++#define PKT_FILTER_APF_ID 200 ++#define DHD_APF_LOCK(ndev) dhd_apf_lock(ndev) ++#define DHD_APF_UNLOCK(ndev) dhd_apf_unlock(ndev) ++ ++extern void dhd_apf_lock(struct net_device *dev); ++extern void dhd_apf_unlock(struct net_device *dev); ++extern int dhd_dev_apf_get_version(struct net_device *ndev, uint32 *version); ++extern int dhd_dev_apf_get_max_len(struct net_device *ndev, uint32 *max_len); ++extern int dhd_dev_apf_add_filter(struct net_device *ndev, u8* program, ++ uint32 program_len); ++extern int dhd_dev_apf_enable_filter(struct net_device *ndev); ++extern int dhd_dev_apf_disable_filter(struct net_device *ndev); ++extern int dhd_dev_apf_delete_filter(struct net_device *ndev); ++#endif /* PKT_FILTER_SUPPORT && APF */ ++ ++extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); ++extern int dhd_timeout_expired(dhd_timeout_t *tmo); ++ ++extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); ++extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); ++extern struct net_device * dhd_idx2net(void *pub, int ifidx); ++extern int net_os_send_hang_message(struct net_device *dev); ++extern int net_os_send_hang_message_reason(struct net_device *dev, const char *string_num); ++extern bool dhd_wowl_cap(void *bus); ++extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, uint pktlen, ++ wl_event_msg_t *, void **data_ptr, void *); ++extern int wl_process_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, uint pktlen, ++ wl_event_msg_t *, void **data_ptr, void *); ++extern void wl_event_to_host_order(wl_event_msg_t * evt); ++extern int wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu); ++extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); ++extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, ++ int ifindex); ++extern int dhd_wl_ioctl_get_intiovar(dhd_pub_t *dhd_pub, char *name, uint *pval, ++ int cmd, uint8 set, int ifidx); ++extern int dhd_wl_ioctl_set_intiovar(dhd_pub_t *dhd_pub, char *name, uint val, ++ int cmd, uint8 set, int ifidx); ++extern void dhd_common_init(osl_t *osh); ++ ++extern int dhd_do_driver_init(struct net_device *net); ++extern int dhd_event_ifadd(struct dhd_info *dhd, struct wl_event_data_if *ifevent, ++ char *name, uint8 *mac); ++extern int dhd_event_ifdel(struct dhd_info *dhd, struct wl_event_data_if *ifevent, ++ char *name, uint8 *mac); ++extern int dhd_event_ifchange(struct dhd_info *dhd, struct wl_event_data_if *ifevent, ++ char *name, uint8 *mac); ++#ifdef DHD_UPDATE_INTF_MAC ++extern int dhd_op_if_update(dhd_pub_t *dhdpub, int ifidx); ++#endif /* DHD_UPDATE_INTF_MAC */ ++extern struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, const char *name, ++ uint8 *mac, uint8 bssidx, bool need_rtnl_lock, const char *dngl_name); ++extern int dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock); ++extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); ++extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); ++extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx); ++extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); ++ ++/* Send packet to dongle via data channel */ ++extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); ++ ++/* send up locally generated event */ ++extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); ++/* Send event to host */ ++extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); ++#ifdef LOG_INTO_TCPDUMP ++extern void dhd_sendup_log(dhd_pub_t *dhdp, void *data, int len); ++#endif /* LOG_INTO_TCPDUMP */ ++extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); ++extern uint dhd_bus_status(dhd_pub_t *dhdp); ++extern int dhd_bus_start(dhd_pub_t *dhdp); ++extern int dhd_bus_suspend(dhd_pub_t *dhdpub); ++extern int dhd_bus_resume(dhd_pub_t *dhdpub, int stage); ++extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); ++extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); ++extern bool dhd_is_associated(dhd_pub_t *dhd, uint8 ifidx, int *retval); ++#if defined(BCMSDIO) || defined(BCMPCIE) ++extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); ++extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); ++extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp); ++#endif /* defined(BCMSDIO) || defined(BCMPCIE) */ ++int dhd_bus_get_fw_mode(dhd_pub_t *dhdp); ++ ++#if defined(KEEP_ALIVE) ++extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); ++#endif /* KEEP_ALIVE */ ++ ++/* OS spin lock API */ ++extern void *dhd_os_spin_lock_init(osl_t *osh); ++extern void dhd_os_spin_lock_deinit(osl_t *osh, void *lock); ++extern unsigned long dhd_os_spin_lock(void *lock); ++void dhd_os_spin_unlock(void *lock, unsigned long flags); ++ ++#ifdef DHD_EFI ++extern int dhd_os_ds_enter_wait(dhd_pub_t * pub, uint * condition); ++extern int dhd_os_ds_enter_wake(dhd_pub_t * pub); ++#else ++static INLINE int dhd_os_ds_enter_wait(dhd_pub_t * pub, uint * condition) ++{ printf("%s is Not supported for this platform", __FUNCTION__); return 0; } ++static INLINE int dhd_os_ds_enter_wake(dhd_pub_t * pub) ++{ return 0; } ++#endif /* DHD_EFI */ ++ ++#ifdef PCIE_INB_DW ++extern int dhd_os_ds_exit_wait(dhd_pub_t * pub, uint * condition); ++extern int dhd_os_ds_exit_wake(dhd_pub_t * pub); ++#endif /* PCIE_INB_DW */ ++extern int dhd_os_busbusy_wake(dhd_pub_t * pub); ++extern int dhd_os_busbusy_wait_condition(dhd_pub_t *pub, uint *var, uint condition); ++extern int dhd_os_busbusy_wait_negation(dhd_pub_t * pub, uint * condition); ++extern int dhd_os_d3ack_wait(dhd_pub_t * pub, uint * condition); ++extern int dhd_os_d3ack_wake(dhd_pub_t * pub); ++ ++/* ++ * Manage sta objects in an interface. Interface is identified by an ifindex and ++ * sta(s) within an interfaces are managed using a MacAddress of the sta. ++ */ ++struct dhd_sta; ++extern bool dhd_sta_associated(dhd_pub_t *dhdp, uint32 bssidx, uint8 *mac); ++extern struct dhd_sta *dhd_find_sta(void *pub, int ifidx, void *ea); ++extern struct dhd_sta *dhd_findadd_sta(void *pub, int ifidx, void *ea); ++extern void dhd_del_all_sta(void *pub, int ifidx); ++extern void dhd_del_sta(void *pub, int ifidx, void *ea); ++extern int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx); ++extern int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val); ++#if defined(BCM_GMAC3) ++extern int dhd_set_dev_def(dhd_pub_t *dhdp, uint32 idx, int val); ++#endif ++extern int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx); ++extern struct net_device *dhd_linux_get_primary_netdev(dhd_pub_t *dhdp); ++ ++extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); ++int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, ++ char *res_buf, uint res_len, int set); ++extern int dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, ++ uint cmd_len, char **resptr, uint resp_len); ++ ++#ifdef DHD_MCAST_REGEN ++extern int dhd_get_mcast_regen_bss_enable(dhd_pub_t *dhdp, uint32 idx); ++extern int dhd_set_mcast_regen_bss_enable(dhd_pub_t *dhdp, uint32 idx, int val); ++#endif ++typedef enum cust_gpio_modes { ++ WLAN_RESET_ON, ++ WLAN_RESET_OFF, ++ WLAN_POWER_ON, ++ WLAN_POWER_OFF ++} cust_gpio_modes_t; ++ ++typedef struct dmaxref_mem_map { ++ dhd_dma_buf_t *srcmem; ++ dhd_dma_buf_t *dstmem; ++} dmaxref_mem_map_t; ++ ++extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); ++extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); ++/* ++ * Insmod parameters for debug/test ++ */ ++ ++/* Watchdog timer interval */ ++extern uint dhd_watchdog_ms; ++extern bool dhd_os_wd_timer_enabled(void *bus); ++#ifdef DHD_PCIE_RUNTIMEPM ++extern uint dhd_runtimepm_ms; ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++/* Console output poll interval */ ++extern uint dhd_console_ms; ++extern uint android_msg_level; ++extern uint config_msg_level; ++extern uint sd_msglevel; ++extern uint dump_msg_level; ++#ifdef BCMDBUS ++extern uint dbus_msglevel; ++#endif /* BCMDBUS */ ++#ifdef WL_WIRELESS_EXT ++extern uint iw_msg_level; ++#endif ++#ifdef WL_CFG80211 ++extern uint wl_dbg_level; ++#endif ++ ++extern uint dhd_slpauto; ++ ++/* Use interrupts */ ++extern uint dhd_intr; ++ ++/* Use polling */ ++extern uint dhd_poll; ++ ++/* ARP offload agent mode */ ++extern uint dhd_arp_mode; ++ ++/* ARP offload enable */ ++extern uint dhd_arp_enable; ++ ++/* Pkt filte enable control */ ++extern uint dhd_pkt_filter_enable; ++ ++/* Pkt filter init setup */ ++extern uint dhd_pkt_filter_init; ++ ++/* Pkt filter mode control */ ++extern uint dhd_master_mode; ++ ++/* Roaming mode control */ ++extern uint dhd_roam_disable; ++ ++/* Roaming mode control */ ++extern uint dhd_radio_up; ++ ++/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ ++extern int dhd_idletime; ++#ifdef DHD_USE_IDLECOUNT ++#define DHD_IDLETIME_TICKS 5 ++#else ++#define DHD_IDLETIME_TICKS 1 ++#endif /* DHD_USE_IDLECOUNT */ ++ ++/* SDIO Drive Strength */ ++extern uint dhd_sdiod_drive_strength; ++ ++/* triggers bcm_bprintf to print to kernel log */ ++extern bool bcm_bprintf_bypass; ++ ++/* Override to force tx queueing all the time */ ++extern uint dhd_force_tx_queueing; ++ ++/* Default bcn_timeout value is 4 */ ++#define DEFAULT_BCN_TIMEOUT_VALUE 4 ++#ifndef CUSTOM_BCN_TIMEOUT_SETTING ++#define CUSTOM_BCN_TIMEOUT_SETTING DEFAULT_BCN_TIMEOUT_VALUE ++#endif ++ ++/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ ++#define DEFAULT_KEEP_ALIVE_VALUE 55000 /* msec */ ++#ifndef CUSTOM_KEEP_ALIVE_SETTING ++#define CUSTOM_KEEP_ALIVE_SETTING DEFAULT_KEEP_ALIVE_VALUE ++#endif /* DEFAULT_KEEP_ALIVE_VALUE */ ++ ++#define NULL_PKT_STR "null_pkt" ++ ++/* hooks for custom glom setting option via Makefile */ ++#define DEFAULT_GLOM_VALUE -1 ++#ifndef CUSTOM_GLOM_SETTING ++#define CUSTOM_GLOM_SETTING DEFAULT_GLOM_VALUE ++#endif ++#define WL_AUTO_ROAM_TRIGGER -75 ++/* hooks for custom Roaming Trigger setting via Makefile */ ++#define DEFAULT_ROAM_TRIGGER_VALUE -75 /* dBm default roam trigger all band */ ++#define DEFAULT_ROAM_TRIGGER_SETTING -1 ++#ifndef CUSTOM_ROAM_TRIGGER_SETTING ++#define CUSTOM_ROAM_TRIGGER_SETTING DEFAULT_ROAM_TRIGGER_VALUE ++#endif ++ ++/* hooks for custom Roaming Romaing setting via Makefile */ ++#define DEFAULT_ROAM_DELTA_VALUE 10 /* dBm default roam delta all band */ ++#define DEFAULT_ROAM_DELTA_SETTING -1 ++#ifndef CUSTOM_ROAM_DELTA_SETTING ++#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE ++#endif ++ ++/* hooks for custom PNO Event wake lock to guarantee enough time ++ for the Platform to detect Event before system suspended ++*/ ++#define DEFAULT_PNO_EVENT_LOCK_xTIME 2 /* multiplay of DHD_PACKET_TIMEOUT_MS */ ++#ifndef CUSTOM_PNO_EVENT_LOCK_xTIME ++#define CUSTOM_PNO_EVENT_LOCK_xTIME DEFAULT_PNO_EVENT_LOCK_xTIME ++#endif ++/* hooks for custom dhd_dpc_prio setting option via Makefile */ ++#define DEFAULT_DHP_DPC_PRIO 1 ++#ifndef CUSTOM_DPC_PRIO_SETTING ++#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO ++#endif ++ ++#ifndef CUSTOM_LISTEN_INTERVAL ++#define CUSTOM_LISTEN_INTERVAL LISTEN_INTERVAL ++#endif /* CUSTOM_LISTEN_INTERVAL */ ++ ++#define DEFAULT_SUSPEND_BCN_LI_DTIM 3 ++#ifndef CUSTOM_SUSPEND_BCN_LI_DTIM ++#define CUSTOM_SUSPEND_BCN_LI_DTIM DEFAULT_SUSPEND_BCN_LI_DTIM ++#endif ++ ++#ifndef BCN_TIMEOUT_IN_SUSPEND ++#define BCN_TIMEOUT_IN_SUSPEND 6 /* bcn timeout value in suspend mode */ ++#endif ++ ++#ifndef CUSTOM_RXF_PRIO_SETTING ++#define CUSTOM_RXF_PRIO_SETTING MAX((CUSTOM_DPC_PRIO_SETTING - 1), 1) ++#endif ++ ++#define DEFAULT_WIFI_TURNOFF_DELAY 0 ++#define WIFI_TURNOFF_DELAY DEFAULT_WIFI_TURNOFF_DELAY ++ ++#define DEFAULT_WIFI_TURNON_DELAY 200 ++#ifndef WIFI_TURNON_DELAY ++#define WIFI_TURNON_DELAY DEFAULT_WIFI_TURNON_DELAY ++#endif /* WIFI_TURNON_DELAY */ ++ ++#ifdef BCMSDIO ++#define DEFAULT_DHD_WATCHDOG_INTERVAL_MS 10 /* msec */ ++#else ++#define DEFAULT_DHD_WATCHDOG_INTERVAL_MS 0 /* msec */ ++#endif ++#ifndef CUSTOM_DHD_WATCHDOG_MS ++#define CUSTOM_DHD_WATCHDOG_MS DEFAULT_DHD_WATCHDOG_INTERVAL_MS ++#endif /* DEFAULT_DHD_WATCHDOG_INTERVAL_MS */ ++ ++#define DEFAULT_ASSOC_RETRY_MAX 3 ++#ifndef CUSTOM_ASSOC_RETRY_MAX ++#define CUSTOM_ASSOC_RETRY_MAX DEFAULT_ASSOC_RETRY_MAX ++#endif /* DEFAULT_ASSOC_RETRY_MAX */ ++ ++#if defined(BCMSDIO) || defined(DISABLE_FRAMEBURST) ++#define DEFAULT_FRAMEBURST_SET 0 ++#else ++#define DEFAULT_FRAMEBURST_SET 1 ++#endif /* BCMSDIO */ ++ ++#ifndef CUSTOM_FRAMEBURST_SET ++#define CUSTOM_FRAMEBURST_SET DEFAULT_FRAMEBURST_SET ++#endif /* CUSTOM_FRAMEBURST_SET */ ++ ++#ifdef WLTDLS ++#ifndef CUSTOM_TDLS_IDLE_MODE_SETTING ++#define CUSTOM_TDLS_IDLE_MODE_SETTING 60000 /* 60sec to tear down TDLS of not active */ ++#endif ++#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_HIGH ++#define CUSTOM_TDLS_RSSI_THRESHOLD_HIGH -70 /* rssi threshold for establishing TDLS link */ ++#endif ++#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_LOW ++#define CUSTOM_TDLS_RSSI_THRESHOLD_LOW -80 /* rssi threshold for tearing down TDLS link */ ++#endif ++#endif /* WLTDLS */ ++ ++#if defined(VSDB) || defined(ROAM_ENABLE) ++#define DEFAULT_BCN_TIMEOUT 8 ++#else ++#define DEFAULT_BCN_TIMEOUT 4 ++#endif ++ ++#ifndef CUSTOM_BCN_TIMEOUT ++#define CUSTOM_BCN_TIMEOUT DEFAULT_BCN_TIMEOUT ++#endif ++ ++#define MAX_DTIM_SKIP_BEACON_INTERVAL 100 /* max allowed associated AP beacon for DTIM skip */ ++#ifndef MAX_DTIM_ALLOWED_INTERVAL ++#define MAX_DTIM_ALLOWED_INTERVAL 600 /* max allowed total beacon interval for DTIM skip */ ++#endif ++ ++#ifndef MIN_DTIM_FOR_ROAM_THRES_EXTEND ++#define MIN_DTIM_FOR_ROAM_THRES_EXTEND 600 /* minimum dtim interval to extend roam threshold */ ++#endif ++ ++#define NO_DTIM_SKIP 1 ++#ifdef SDTEST ++/* Echo packet generator (SDIO), pkts/s */ ++extern uint dhd_pktgen; ++ ++/* Echo packet len (0 => sawtooth, max 1800) */ ++extern uint dhd_pktgen_len; ++#define MAX_PKTGEN_LEN 1800 ++#endif ++ ++ ++/* optionally set by a module_param_string() */ ++#define MOD_PARAM_PATHLEN 2048 ++#define MOD_PARAM_INFOLEN 512 ++#define MOD_PARAM_SRLEN 64 ++ ++#ifdef SOFTAP ++extern char fw_path2[MOD_PARAM_PATHLEN]; ++#endif ++ ++#ifdef DHD_LEGACY_FILE_PATH ++#define PLATFORM_PATH "/data/" ++#elif defined(PLATFORM_SLP) ++#define PLATFORM_PATH "/opt/etc/" ++#else ++#define PLATFORM_PATH "/data/misc/conn/" ++#endif /* DHD_LEGACY_FILE_PATH */ ++ ++/* Flag to indicate if we should download firmware on driver load */ ++extern uint dhd_download_fw_on_driverload; ++#ifndef BCMDBUS ++extern int allow_delay_fwdl; ++#endif /* !BCMDBUS */ ++ ++extern int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost); ++extern int dhd_write_file(const char *filepath, char *buf, int buf_len); ++extern int dhd_read_file(const char *filepath, char *buf, int buf_len); ++extern int dhd_write_file_and_check(const char *filepath, char *buf, int buf_len); ++ ++#ifdef READ_MACADDR ++extern int dhd_set_macaddr_from_file(dhd_pub_t *dhdp); ++#else ++static INLINE int dhd_set_macaddr_from_file(dhd_pub_t *dhdp) { return 0; } ++#endif /* READ_MACADDR */ ++#ifdef WRITE_MACADDR ++extern int dhd_write_macaddr(struct ether_addr *mac); ++#else ++static INLINE int dhd_write_macaddr(struct ether_addr *mac) { return 0; } ++#endif /* WRITE_MACADDR */ ++static INLINE int dhd_check_module_cid(dhd_pub_t *dhdp) { return 0; } ++#ifdef GET_MAC_FROM_OTP ++extern int dhd_check_module_mac(dhd_pub_t *dhdp); ++#else ++static INLINE int dhd_check_module_mac(dhd_pub_t *dhdp) { return 0; } ++#endif /* GET_MAC_FROM_OTP */ ++ ++#if defined(READ_MACADDR) || defined(WRITE_MACADDR) || defined(GET_MAC_FROM_OTP) ++#define DHD_USE_CISINFO ++#endif ++ ++#ifdef DHD_USE_CISINFO ++int dhd_read_cis(dhd_pub_t *dhdp); ++void dhd_clear_cis(dhd_pub_t *dhdp); ++#else ++static INLINE int dhd_read_cis(dhd_pub_t *dhdp) { return 0; } ++static INLINE void dhd_clear_cis(dhd_pub_t *dhdp) { } ++#endif /* DHD_USE_CISINFO */ ++ ++#define IBSS_COALESCE_DEFAULT 1 ++#define IBSS_INITIAL_SCAN_ALLOWED_DEFAULT 1 ++ ++ ++extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); ++extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); ++ ++#define IFLOCK_INIT(lock) *lock = 0 ++#define IFLOCK(lock) while (InterlockedCompareExchange((lock), 1, 0)) \ ++ NdisStallExecution(1); ++#define IFUNLOCK(lock) InterlockedExchange((lock), 0) ++#define IFLOCK_FREE(lock) ++#define FW_SUPPORTED(dhd, capa) ((strstr(dhd->fw_capabilities, " " #capa " ") != NULL)) ++#ifdef ARP_OFFLOAD_SUPPORT ++#define MAX_IPV4_ENTRIES 8 ++void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); ++void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); ++ ++/* dhd_commn arp offload wrapers */ ++void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx); ++void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx); ++int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx); ++void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#ifdef WLTDLS ++int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac); ++int dhd_tdls_set_mode(dhd_pub_t *dhd, bool wfd_mode); ++#ifdef PCIE_FULL_DONGLE ++int dhd_tdls_update_peer_info(dhd_pub_t *dhdp, wl_event_msg_t *event); ++int dhd_tdls_event_handler(dhd_pub_t *dhd_pub, wl_event_msg_t *event); ++int dhd_free_tdls_peer_list(dhd_pub_t *dhd_pub); ++#endif /* PCIE_FULL_DONGLE */ ++#endif /* WLTDLS */ ++ ++/* Neighbor Discovery Offload Support */ ++extern int dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable); ++int dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipaddr, int idx); ++int dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx); ++ ++/* Enhanced ND offload support */ ++uint16 dhd_ndo_get_version(dhd_pub_t *dhdp); ++int dhd_ndo_add_ip_with_type(dhd_pub_t *dhdp, char *ipv6addr, uint8 type, int idx); ++int dhd_ndo_remove_ip_by_addr(dhd_pub_t *dhdp, char *ipv6addr, int idx); ++int dhd_ndo_remove_ip_by_type(dhd_pub_t *dhdp, uint8 type, int idx); ++int dhd_ndo_unsolicited_na_filter_enable(dhd_pub_t *dhdp, int enable); ++ ++/* ioctl processing for nl80211 */ ++int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, struct dhd_ioctl *ioc, void *data_buf); ++ ++void dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path, ++ char *pclm_path, char *pconf_path); ++void dhd_set_bus_state(void *bus, uint32 state); ++ ++/* Remove proper pkts(either one no-frag pkt or whole fragmented pkts) */ ++typedef int (*f_droppkt_t)(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ); ++extern bool dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn); ++ ++#ifdef PROP_TXSTATUS ++int dhd_os_wlfc_block(dhd_pub_t *pub); ++int dhd_os_wlfc_unblock(dhd_pub_t *pub); ++extern const uint8 prio2fifo[]; ++#endif /* PROP_TXSTATUS */ ++ ++int dhd_os_socram_dump(struct net_device *dev, uint32 *dump_size); ++int dhd_os_get_socram_dump(struct net_device *dev, char **buf, uint32 *size); ++int dhd_common_socram_dump(dhd_pub_t *dhdp); ++ ++int dhd_os_get_version(struct net_device *dev, bool dhd_ver, char **buf, uint32 size); ++ ++uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail); ++void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size); ++ ++#if defined(CONFIG_DHD_USE_STATIC_BUF) ++#define DHD_OS_PREALLOC(dhdpub, section, size) dhd_os_prealloc(dhdpub, section, size, FALSE) ++#define DHD_OS_PREFREE(dhdpub, addr, size) dhd_os_prefree(dhdpub, addr, size) ++#else ++#define DHD_OS_PREALLOC(dhdpub, section, size) MALLOC(dhdpub->osh, size) ++#define DHD_OS_PREFREE(dhdpub, addr, size) MFREE(dhdpub->osh, addr, size) ++#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ ++ ++#ifdef USE_WFA_CERT_CONF ++enum { ++ SET_PARAM_BUS_TXGLOM_MODE, ++ SET_PARAM_ROAMOFF, ++#ifdef USE_WL_FRAMEBURST ++ SET_PARAM_FRAMEBURST, ++#endif /* USE_WL_FRAMEBURST */ ++#ifdef USE_WL_TXBF ++ SET_PARAM_TXBF, ++#endif /* USE_WL_TXBF */ ++#ifdef PROP_TXSTATUS ++ SET_PARAM_PROPTX, ++ SET_PARAM_PROPTXMODE, ++#endif /* PROP_TXSTATUS */ ++ PARAM_LAST_VALUE ++}; ++extern int sec_get_param_wfa_cert(dhd_pub_t *dhd, int mode, uint* read_val); ++#endif /* USE_WFA_CERT_CONF */ ++ ++#define dhd_add_flowid(pub, ifidx, ac_prio, ea, flowid) do {} while (0) ++#define dhd_del_flowid(pub, ifidx, flowid) do {} while (0) ++bool dhd_wet_chainable(dhd_pub_t *dhdp); ++ ++extern unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub); ++extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags); ++ ++/** Miscellaenous DHD Spin Locks */ ++ ++/* Disable router 3GMAC bypass path perimeter lock */ ++#define DHD_PERIM_LOCK(dhdp) do {} while (0) ++#define DHD_PERIM_UNLOCK(dhdp) do {} while (0) ++#define DHD_PERIM_LOCK_ALL(processor_id) do {} while (0) ++#define DHD_PERIM_UNLOCK_ALL(processor_id) do {} while (0) ++ ++/* Enable DHD general spin lock/unlock */ ++#define DHD_GENERAL_LOCK(dhdp, flags) \ ++ (flags) = dhd_os_general_spin_lock(dhdp) ++#define DHD_GENERAL_UNLOCK(dhdp, flags) \ ++ dhd_os_general_spin_unlock((dhdp), (flags)) ++ ++/* Enable DHD timer spin lock/unlock */ ++#define DHD_TIMER_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) ++#define DHD_TIMER_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, (flags)) ++ ++/* Enable DHD flowring spin lock/unlock */ ++#define DHD_FLOWRING_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) ++#define DHD_FLOWRING_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) ++ ++/* Enable DHD common flowring info spin lock/unlock */ ++#define DHD_FLOWID_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) ++#define DHD_FLOWID_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) ++ ++/* Enable DHD common flowring list spin lock/unlock */ ++#define DHD_FLOWRING_LIST_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) ++#define DHD_FLOWRING_LIST_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) ++ ++#define DHD_SPIN_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) ++#define DHD_SPIN_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) ++ ++#define DHD_BUS_INB_DW_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) ++#define DHD_BUS_INB_DW_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) ++ ++/* Enable DHD TDLS peer list spin lock/unlock */ ++#ifdef WLTDLS ++#define DHD_TDLS_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) ++#define DHD_TDLS_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) ++#endif /* WLTDLS */ ++ ++#ifdef DBG_PKT_MON ++/* Enable DHD PKT MON spin lock/unlock */ ++#define DHD_PKT_MON_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) ++#define DHD_PKT_MON_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, (flags)) ++#endif /* DBG_PKT_MON */ ++ ++#define DHD_LINUX_GENERAL_LOCK(dhdp, flags) DHD_GENERAL_LOCK(dhdp, flags) ++#define DHD_LINUX_GENERAL_UNLOCK(dhdp, flags) DHD_GENERAL_UNLOCK(dhdp, flags) ++ ++extern void dhd_dump_to_kernelog(dhd_pub_t *dhdp); ++ ++#ifdef BCMDBUS ++extern uint dhd_get_rxsz(dhd_pub_t *pub); ++extern void dhd_set_path(dhd_pub_t *pub); ++extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); ++extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); ++#endif /* BCMDBUS */ ++ ++#ifdef DHD_L2_FILTER ++extern int dhd_get_parp_status(dhd_pub_t *dhdp, uint32 idx); ++extern int dhd_set_parp_status(dhd_pub_t *dhdp, uint32 idx, int val); ++extern int dhd_get_dhcp_unicast_status(dhd_pub_t *dhdp, uint32 idx); ++extern int dhd_set_dhcp_unicast_status(dhd_pub_t *dhdp, uint32 idx, int val); ++extern int dhd_get_block_ping_status(dhd_pub_t *dhdp, uint32 idx); ++extern int dhd_set_block_ping_status(dhd_pub_t *dhdp, uint32 idx, int val); ++extern int dhd_get_grat_arp_status(dhd_pub_t *dhdp, uint32 idx); ++extern int dhd_set_grat_arp_status(dhd_pub_t *dhdp, uint32 idx, int val); ++#endif /* DHD_L2_FILTER */ ++ ++ ++typedef struct wl_io_pport { ++ dhd_pub_t *dhd_pub; ++ uint ifidx; ++} wl_io_pport_t; ++ ++typedef struct wl_evt_pport { ++ dhd_pub_t *dhd_pub; ++ int *ifidx; ++ void *pktdata; ++ uint data_len; ++ void **data_ptr; ++ void *raw_event; ++} wl_evt_pport_t; ++ ++extern void *dhd_pub_shim(dhd_pub_t *dhd_pub); ++#ifdef DHD_FW_COREDUMP ++void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length); ++#endif /* DHD_FW_COREDUMP */ ++ ++#if defined(SET_RPS_CPUS) ++int dhd_rps_cpus_enable(struct net_device *net, int enable); ++int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len); ++void custom_rps_map_clear(struct netdev_rx_queue *queue); ++#define PRIMARY_INF 0 ++#define VIRTUAL_INF 1 ++#if defined(CONFIG_MACH_UNIVERSAL5433) || defined(CONFIG_MACH_UNIVERSAL7420) || \ ++ defined(CONFIG_SOC_EXYNOS8890) ++#define RPS_CPUS_MASK "10" ++#define RPS_CPUS_MASK_P2P "10" ++#define RPS_CPUS_MASK_IBSS "10" ++#define RPS_CPUS_WLAN_CORE_ID 4 ++#else ++#define RPS_CPUS_MASK "6" ++#define RPS_CPUS_MASK_P2P "6" ++#define RPS_CPUS_MASK_IBSS "6" ++#endif /* CONFIG_MACH_UNIVERSAL5433 || CONFIG_MACH_UNIVERSAL7420 || CONFIG_SOC_EXYNOS8890 */ ++#endif ++ ++int dhd_get_download_buffer(dhd_pub_t *dhd, char *file_path, download_type_t component, ++ char ** buffer, int *length); ++ ++void dhd_free_download_buffer(dhd_pub_t *dhd, void *buffer, int length); ++ ++int dhd_download_blob(dhd_pub_t *dhd, unsigned char *image, ++ uint32 len, char *iovar); ++ ++int dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path); ++ ++#ifdef SHOW_LOGTRACE ++int dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, ++ dhd_event_log_t *event_log); ++int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart, ++ uint32 *rodata_start, uint32 *rodata_end); ++#ifdef PCIE_FULL_DONGLE ++int dhd_event_logtrace_infobuf_pkt_process(dhd_pub_t *dhdp, void *pktbuf, ++ dhd_event_log_t *event_data); ++#endif /* PCIE_FULL_DONGLE */ ++#endif /* SHOW_LOGTRACE */ ++ ++#define dhd_is_device_removed(x) FALSE ++#define dhd_os_ind_firmware_stall(x) ++ ++#if defined(DHD_FW_COREDUMP) ++extern void dhd_get_memdump_info(dhd_pub_t *dhd); ++#endif /* defined(DHD_FW_COREDUMP) */ ++#ifdef BCMASSERT_LOG ++extern void dhd_get_assert_info(dhd_pub_t *dhd); ++#else ++static INLINE void dhd_get_assert_info(dhd_pub_t *dhd) { } ++#endif /* BCMASSERT_LOG */ ++ ++#define DMAXFER_FREE(dhdp, dmap) dhd_schedule_dmaxfer_free(dhdp, dmap); ++ ++#if defined(PCIE_FULL_DONGLE) ++extern void dmaxfer_free_prev_dmaaddr(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap); ++void dhd_schedule_dmaxfer_free(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap); ++#endif /* PCIE_FULL_DONGLE */ ++ ++#define DHD_LB_STATS_NOOP do { /* noop */ } while (0) ++#if defined(DHD_LB_STATS) ++#include ++extern void dhd_lb_stats_init(dhd_pub_t *dhd); ++extern void dhd_lb_stats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); ++extern void dhd_lb_stats_update_napi_histo(dhd_pub_t *dhdp, uint32 count); ++extern void dhd_lb_stats_update_txc_histo(dhd_pub_t *dhdp, uint32 count); ++extern void dhd_lb_stats_update_rxc_histo(dhd_pub_t *dhdp, uint32 count); ++extern void dhd_lb_stats_txc_percpu_cnt_incr(dhd_pub_t *dhdp); ++extern void dhd_lb_stats_rxc_percpu_cnt_incr(dhd_pub_t *dhdp); ++#define DHD_LB_STATS_INIT(dhdp) dhd_lb_stats_init(dhdp) ++#define DHD_LB_STATS_DEINIT(dhdp) dhd_lb_stats_deinit(dhdp) ++/* Reset is called from common layer so it takes dhd_pub_t as argument */ ++#define DHD_LB_STATS_RESET(dhdp) dhd_lb_stats_init(dhdp) ++#define DHD_LB_STATS_CLR(x) (x) = 0U ++#define DHD_LB_STATS_INCR(x) (x) = (x) + 1 ++#define DHD_LB_STATS_ADD(x, c) (x) = (x) + (c) ++#define DHD_LB_STATS_PERCPU_ARR_INCR(x) \ ++ { \ ++ int cpu = get_cpu(); put_cpu(); \ ++ DHD_LB_STATS_INCR(x[cpu]); \ ++ } ++#define DHD_LB_STATS_UPDATE_NAPI_HISTO(dhdp, x) dhd_lb_stats_update_napi_histo(dhdp, x) ++#define DHD_LB_STATS_UPDATE_TXC_HISTO(dhdp, x) dhd_lb_stats_update_txc_histo(dhdp, x) ++#define DHD_LB_STATS_UPDATE_RXC_HISTO(dhdp, x) dhd_lb_stats_update_rxc_histo(dhdp, x) ++#define DHD_LB_STATS_TXC_PERCPU_CNT_INCR(dhdp) dhd_lb_stats_txc_percpu_cnt_incr(dhdp) ++#define DHD_LB_STATS_RXC_PERCPU_CNT_INCR(dhdp) dhd_lb_stats_rxc_percpu_cnt_incr(dhdp) ++#else /* !DHD_LB_STATS */ ++#define DHD_LB_STATS_INIT(dhdp) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_DEINIT(dhdp) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_RESET(dhdp) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_CLR(x) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_INCR(x) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_ADD(x, c) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_PERCPU_ARR_INCR(x) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_UPDATE_NAPI_HISTO(dhd, x) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_UPDATE_TXC_HISTO(dhd, x) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_UPDATE_RXC_HISTO(dhd, x) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_TXC_PERCPU_CNT_INCR(dhdp) DHD_LB_STATS_NOOP ++#define DHD_LB_STATS_RXC_PERCPU_CNT_INCR(dhdp) DHD_LB_STATS_NOOP ++#endif /* !DHD_LB_STATS */ ++ ++#ifdef DHD_SSSR_DUMP ++#define DHD_SSSR_MEMPOOL_SIZE (1024 * 1024) /* 1MB size */ ++extern int dhd_sssr_mempool_init(dhd_pub_t *dhd); ++extern void dhd_sssr_mempool_deinit(dhd_pub_t *dhd); ++extern int dhd_sssr_dump_init(dhd_pub_t *dhd); ++extern void dhd_sssr_dump_deinit(dhd_pub_t *dhd); ++#define DHD_SSSR_MEMPOOL_INIT(dhdp) dhd_sssr_mempool_init(dhdp) ++#define DHD_SSSR_MEMPOOL_DEINIT(dhdp) dhd_sssr_mempool_deinit(dhdp) ++#define DHD_SSSR_DUMP_INIT(dhdp) dhd_sssr_dump_init(dhdp) ++#define DHD_SSSR_DUMP_DEINIT(dhdp) dhd_sssr_dump_deinit(dhdp) ++#else ++#define DHD_SSSR_MEMPOOL_INIT(dhdp) do { /* noop */ } while (0) ++#define DHD_SSSR_MEMPOOL_DEINIT(dhdp) do { /* noop */ } while (0) ++#define DHD_SSSR_DUMP_INIT(dhdp) do { /* noop */ } while (0) ++#define DHD_SSSR_DUMP_DEINIT(dhdp) do { /* noop */ } while (0) ++#endif /* DHD_SSSR_DUMP */ ++ ++#ifdef SHOW_LOGTRACE ++void dhd_get_read_buf_ptr(dhd_pub_t *dhd_pub, trace_buf_info_t *read_buf_info); ++#endif /* SHOW_LOGTRACE */ ++ ++#ifdef BCMPCIE ++extern int dhd_prot_debug_info_print(dhd_pub_t *dhd); ++#else ++#define dhd_prot_debug_info_print(x) ++#endif /* BCMPCIE */ ++ ++extern bool dhd_prot_is_cmpl_ring_empty(dhd_pub_t *dhd, void *prot_info); ++ ++bool dhd_fw_download_status(dhd_pub_t * dhd_pub); ++ ++/* Bitmask used for Join Timeout */ ++#define WLC_SSID_MASK 0x01 ++#define WLC_WPA_MASK 0x02 ++ ++extern int dhd_start_join_timer(dhd_pub_t *pub); ++extern int dhd_stop_join_timer(dhd_pub_t *pub); ++extern int dhd_start_scan_timer(dhd_pub_t *pub); ++extern int dhd_stop_scan_timer(dhd_pub_t *pub); ++extern int dhd_start_cmd_timer(dhd_pub_t *pub); ++extern int dhd_stop_cmd_timer(dhd_pub_t *pub); ++extern int dhd_start_bus_timer(dhd_pub_t *pub); ++extern int dhd_stop_bus_timer(dhd_pub_t *pub); ++extern uint16 dhd_get_request_id(dhd_pub_t *pub); ++extern int dhd_set_request_id(dhd_pub_t *pub, uint16 id, uint32 cmd); ++extern void dhd_set_join_error(dhd_pub_t *pub, uint32 mask); ++extern void dhd_clear_join_error(dhd_pub_t *pub, uint32 mask); ++extern void dhd_get_scan_to_val(dhd_pub_t *pub, uint32 *to_val); ++extern void dhd_set_scan_to_val(dhd_pub_t *pub, uint32 to_val); ++extern void dhd_get_join_to_val(dhd_pub_t *pub, uint32 *to_val); ++extern void dhd_set_join_to_val(dhd_pub_t *pub, uint32 to_val); ++extern void dhd_get_cmd_to_val(dhd_pub_t *pub, uint32 *to_val); ++extern void dhd_set_cmd_to_val(dhd_pub_t *pub, uint32 to_val); ++extern void dhd_get_bus_to_val(dhd_pub_t *pub, uint32 *to_val); ++extern void dhd_set_bus_to_val(dhd_pub_t *pub, uint32 to_val); ++extern int dhd_start_timesync_timer(dhd_pub_t *pub); ++extern int dhd_stop_timesync_timer(dhd_pub_t *pub); ++ ++#ifdef DHD_PKTID_AUDIT_ENABLED ++void dhd_pktid_error_handler(dhd_pub_t *dhdp); ++#endif /* DHD_PKTID_AUDIT_ENABLED */ ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++extern bool dhd_runtimepm_state(dhd_pub_t *dhd); ++extern bool dhd_runtime_bus_wake(struct dhd_bus *bus, bool wait, void *func_addr); ++extern bool dhdpcie_runtime_bus_wake(dhd_pub_t *dhdp, bool wait, void *func_addr); ++extern void dhdpcie_block_runtime_pm(dhd_pub_t *dhdp); ++extern bool dhdpcie_is_resume_done(dhd_pub_t *dhdp); ++extern void dhd_runtime_pm_disable(dhd_pub_t *dhdp); ++extern void dhd_runtime_pm_enable(dhd_pub_t *dhdp); ++/* Disable the Runtime PM and wake up if the bus is already in suspend */ ++#define DHD_DISABLE_RUNTIME_PM(dhdp) \ ++do { \ ++ dhd_runtime_pm_disable(dhdp); \ ++} while (0); ++ ++/* Enable the Runtime PM */ ++#define DHD_ENABLE_RUNTIME_PM(dhdp) \ ++do { \ ++ dhd_runtime_pm_enable(dhdp); \ ++} while (0); ++#else ++#define DHD_DISABLE_RUNTIME_PM(dhdp) ++#define DHD_ENABLE_RUNTIME_PM(dhdp) ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++/* ++ * Enable this macro if you want to track the calls to wake lock ++ * This records can be printed using the following command ++ * cat /sys/bcm-dhd/wklock_trace ++ * DHD_TRACE_WAKE_LOCK supports over linux 2.6.0 version ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++#undef DHD_TRACE_WAKE_LOCK ++#endif /* KERNEL_VER < KERNEL_VERSION(2, 6, 0) */ ++ ++#if defined(DHD_TRACE_WAKE_LOCK) ++void dhd_wk_lock_stats_dump(dhd_pub_t *dhdp); ++#endif ++ ++extern bool dhd_query_bus_erros(dhd_pub_t *dhdp); ++ ++extern void init_dhd_timeouts(dhd_pub_t *pub); ++extern void deinit_dhd_timeouts(dhd_pub_t *pub); ++ ++typedef enum timeout_resons { ++ DHD_REASON_COMMAND_TO, ++ DHD_REASON_JOIN_TO, ++ DHD_REASON_SCAN_TO, ++ DHD_REASON_OQS_TO ++} timeout_reasons_t; ++ ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++extern int dhd_bus_set_device_wake(struct dhd_bus *bus, bool val); ++#endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ ++ ++#ifdef DHD_EFI ++extern void dhd_schedule_reset(dhd_pub_t *dhdp); ++#else ++static INLINE void dhd_schedule_reset(dhd_pub_t *dhdp) {;} ++#endif ++ ++#ifdef ENABLE_TEMP_THROTTLING ++#ifndef TEMP_THROTTLE_CONTROL_BIT ++#define TEMP_THROTTLE_CONTROL_BIT 0xd ++#endif ++#endif /* ENABLE_TEMP_THROTTLING */ ++ ++int dhd_send_msg_to_daemon(struct sk_buff *skb, void *data, int size); ++#ifdef REPORT_FATAL_TIMEOUTS ++void dhd_send_trap_to_fw_for_timeout(dhd_pub_t * pub, timeout_reasons_t reason); ++#endif ++ ++#if defined(CONFIG_64BIT) ++#define DHD_SUPPORT_64BIT ++#elif defined(DHD_EFI) ++#define DHD_SUPPORT_64BIT ++/* by default disabled for other platforms, can enable appropriate macro to enable 64 bit support */ ++#endif /* (linux || LINUX) && CONFIG_64BIT */ ++ ++#ifdef SET_PCIE_IRQ_CPU_CORE ++extern void dhd_set_irq_cpucore(dhd_pub_t *dhdp, int set); ++extern void set_irq_cpucore(unsigned int irq, int set); ++#endif /* SET_PCIE_IRQ_CPU_CORE */ ++#if defined(DHD_HANG_SEND_UP_TEST) ++extern void dhd_make_hang_with_reason(struct net_device *dev, const char *string_num); ++#endif /* DHD_HANG_SEND_UP_TEST */ ++ ++#if defined(DHD_BLOB_EXISTENCE_CHECK) ++extern void dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path); ++#endif /* DHD_BLOB_EXISTENCE_CHECK */ ++ ++#ifdef DHD_WAKE_STATUS ++wake_counts_t* dhd_get_wakecount(dhd_pub_t *dhdp); ++#endif /* DHD_WAKE_STATUS */ ++ ++#ifdef BCM_ASLR_HEAP ++extern uint32 dhd_get_random_number(void); ++#endif /* BCM_ASLR_HEAP */ ++#endif /* _dhd_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_bus.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_bus.h +new file mode 100644 +index 000000000..aa5ba6c14 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_bus.h +@@ -0,0 +1,298 @@ ++/* ++ * Header file describing the internal (inter-module) DHD interfaces. ++ * ++ * Provides type definitions and function prototypes used to link the ++ * DHD OS, bus, and protocol modules. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_bus.h 698895 2017-05-11 02:55:17Z $ ++ */ ++ ++#ifndef _dhd_bus_h_ ++#define _dhd_bus_h_ ++ ++extern int dbus_up(struct dhd_bus *pub); ++extern int dbus_stop(struct dhd_bus *pub); ++extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len); ++extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len); ++/* ++ * Exported from dhd bus module (dhd_usb, dhd_sdio) ++ */ ++ ++/* Indicate (dis)interest in finding dongles. */ ++extern int dhd_bus_register(void); ++extern void dhd_bus_unregister(void); ++ ++/* Download firmware image and nvram image */ ++extern int dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ++ char *fw_path, char *nv_path, char *clm_path, char *conf_path); ++#if defined(BT_OVER_SDIO) ++extern int dhd_bus_download_btfw(struct dhd_bus *bus, osl_t *osh, char *btfw_path); ++#endif /* defined (BT_OVER_SDIO) */ ++ ++/* Stop bus module: clear pending frames, disable data flow */ ++extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); ++ ++/* Initialize bus module: prepare for communication w/dongle */ ++extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); ++ ++/* Get the Bus Idle Time */ ++extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime); ++ ++/* Set the Bus Idle Time */ ++extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time); ++ ++/* Size of Extended Trap data Buffer */ ++#ifdef BCMPCIE ++#define BCMPCIE_EXT_TRAP_DATA_MAXLEN 4096 ++#endif ++ ++/* Send a data frame to the dongle. Callee disposes of txp. */ ++#ifdef BCMPCIE ++extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx); ++#else ++extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); ++#endif ++ ++extern struct device * dhd_bus_to_dev(struct dhd_bus *bus); ++ ++/* Send/receive a control message to/from the dongle. ++ * Expects caller to enforce a single outstanding transaction. ++ */ ++extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen); ++extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); ++ ++/* Watchdog timer function */ ++extern bool dhd_bus_watchdog(dhd_pub_t *dhd); ++ ++extern int dhd_bus_oob_intr_register(dhd_pub_t *dhdp); ++extern void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp); ++extern void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable); ++extern void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub); ++extern void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub); ++extern bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub); ++ ++/* Device console input function */ ++extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); ++#ifdef CONSOLE_DPC ++extern int dhd_bus_txcons(dhd_pub_t *dhd, uchar *msg, uint msglen); ++#endif ++ ++/* Deferred processing for the bus, return TRUE requests reschedule */ ++extern bool dhd_bus_dpc(struct dhd_bus *bus); ++extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); ++ ++ ++/* Check for and handle local prot-specific iovar commands */ ++extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Add bus dump output to a buffer */ ++extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); ++ ++/* Clear any bus counters */ ++extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); ++ ++/* return the dongle chipid */ ++extern uint dhd_bus_chip(struct dhd_bus *bus); ++ ++/* return the dongle chiprev */ ++extern uint dhd_bus_chiprev(struct dhd_bus *bus); ++ ++/* Set user-specified nvram parameters. */ ++extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params); ++ ++extern void *dhd_bus_pub(struct dhd_bus *bus); ++extern void *dhd_bus_txq(struct dhd_bus *bus); ++extern const void *dhd_bus_sih(struct dhd_bus *bus); ++extern uint dhd_bus_hdrlen(struct dhd_bus *bus); ++#ifdef BCMSDIO ++extern void dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val); ++/* return sdio io status */ ++extern uint8 dhd_bus_is_ioready(struct dhd_bus *bus); ++#else ++#define dhd_bus_set_dotxinrx(a, b) do {} while (0) ++#endif ++ ++#define DHD_SET_BUS_STATE_DOWN(_bus) do { \ ++ (_bus)->dhd->busstate = DHD_BUS_DOWN; \ ++} while (0) ++ ++/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ ++extern int dhd_bus_reg_sdio_notify(void* semaphore); ++extern void dhd_bus_unreg_sdio_notify(void); ++extern void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable); ++extern int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, ++ uint32 *slot_num); ++ ++#if defined(DHD_FW_COREDUMP) && (defined(BCMPCIE) || defined(BCMSDIO)) ++extern int dhd_bus_mem_dump(dhd_pub_t *dhd); ++#else ++#define dhd_bus_mem_dump(x) ++#endif /* DHD_FW_COREDUMP && (BCMPCIE || BCMSDIO) */ ++ ++#ifdef BCMPCIE ++enum { ++ /* Scratch buffer confiuguration update */ ++ D2H_DMA_SCRATCH_BUF, ++ D2H_DMA_SCRATCH_BUF_LEN, ++ ++ /* DMA Indices array buffers for: H2D WR and RD, and D2H WR and RD */ ++ H2D_DMA_INDX_WR_BUF, /* update H2D WR dma indices buf base addr to dongle */ ++ H2D_DMA_INDX_RD_BUF, /* update H2D RD dma indices buf base addr to dongle */ ++ D2H_DMA_INDX_WR_BUF, /* update D2H WR dma indices buf base addr to dongle */ ++ D2H_DMA_INDX_RD_BUF, /* update D2H RD dma indices buf base addr to dongle */ ++ ++ /* DHD sets/gets WR or RD index, in host's H2D and D2H DMA indices buffer */ ++ H2D_DMA_INDX_WR_UPD, /* update H2D WR index in H2D WR dma indices buf */ ++ H2D_DMA_INDX_RD_UPD, /* update H2D RD index in H2D RD dma indices buf */ ++ D2H_DMA_INDX_WR_UPD, /* update D2H WR index in D2H WR dma indices buf */ ++ D2H_DMA_INDX_RD_UPD, /* update D2H RD index in D2H RD dma indices buf */ ++ ++ /* DHD Indices array buffers and update for: H2D flow ring WR */ ++ H2D_IFRM_INDX_WR_BUF, /* update H2D WR dma indices buf base addr to dongle */ ++ H2D_IFRM_INDX_WR_UPD, /* update H2D WR dma indices buf base addr to dongle */ ++ ++ /* H2D and D2H Mailbox data update */ ++ H2D_MB_DATA, ++ D2H_MB_DATA, ++ ++ /* (Common) MsgBuf Ring configuration update */ ++ RING_BUF_ADDR, /* update ring base address to dongle */ ++ RING_ITEM_LEN, /* update ring item size to dongle */ ++ RING_MAX_ITEMS, /* update ring max items to dongle */ ++ ++ /* Update of WR or RD index, for a MsgBuf Ring */ ++ RING_RD_UPD, /* update ring read index from/to dongle */ ++ RING_WR_UPD, /* update ring write index from/to dongle */ ++ ++ TOTAL_LFRAG_PACKET_CNT, ++ MAX_HOST_RXBUFS, ++ HOST_API_VERSION, ++ DNGL_TO_HOST_TRAP_ADDR, ++#ifdef HOFFLOAD_MODULES ++ WRT_HOST_MODULE_ADDR ++#endif ++}; ++ ++typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32); ++typedef void (*dhd_mb_ring_2_t) (struct dhd_bus *, uint32, bool); ++extern void dhd_bus_cmn_writeshared(struct dhd_bus *bus, void * data, uint32 len, uint8 type, ++ uint16 ringid); ++extern void dhd_bus_ringbell(struct dhd_bus *bus, uint32 value); ++extern void dhd_bus_ringbell_2(struct dhd_bus *bus, uint32 value, bool devwake); ++extern void dhd_bus_cmn_readshared(struct dhd_bus *bus, void* data, uint8 type, uint16 ringid); ++extern uint32 dhd_bus_get_sharedflags(struct dhd_bus *bus); ++extern void dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count); ++extern void dhd_bus_start_queue(struct dhd_bus *bus); ++extern void dhd_bus_stop_queue(struct dhd_bus *bus); ++extern dhd_mb_ring_t dhd_bus_get_mbintr_fn(struct dhd_bus *bus); ++extern dhd_mb_ring_2_t dhd_bus_get_mbintr_2_fn(struct dhd_bus *bus); ++extern void dhd_bus_write_flow_ring_states(struct dhd_bus *bus, ++ void * data, uint16 flowid); ++extern void dhd_bus_read_flow_ring_states(struct dhd_bus *bus, ++ void * data, uint8 flowid); ++extern int dhd_bus_flow_ring_create_request(struct dhd_bus *bus, void *flow_ring_node); ++extern void dhd_bus_clean_flow_ring(struct dhd_bus *bus, void *flow_ring_node); ++extern void dhd_bus_flow_ring_create_response(struct dhd_bus *bus, uint16 flow_id, int32 status); ++extern int dhd_bus_flow_ring_delete_request(struct dhd_bus *bus, void *flow_ring_node); ++extern void dhd_bus_flow_ring_delete_response(struct dhd_bus *bus, uint16 flowid, uint32 status); ++extern int dhd_bus_flow_ring_flush_request(struct dhd_bus *bus, void *flow_ring_node); ++extern void dhd_bus_flow_ring_flush_response(struct dhd_bus *bus, uint16 flowid, uint32 status); ++extern uint32 dhd_bus_max_h2d_queues(struct dhd_bus *bus); ++extern int dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs); ++extern void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val); ++ ++#ifdef IDLE_TX_FLOW_MGMT ++extern void dhd_bus_flow_ring_resume_response(struct dhd_bus *bus, uint16 flowid, int32 status); ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++ ++extern int dhdpcie_bus_clock_start(struct dhd_bus *bus); ++extern int dhdpcie_bus_clock_stop(struct dhd_bus *bus); ++extern int dhdpcie_bus_enable_device(struct dhd_bus *bus); ++extern int dhdpcie_bus_disable_device(struct dhd_bus *bus); ++extern int dhdpcie_bus_alloc_resource(struct dhd_bus *bus); ++extern void dhdpcie_bus_free_resource(struct dhd_bus *bus); ++extern bool dhdpcie_bus_dongle_attach(struct dhd_bus *bus); ++extern int dhd_bus_release_dongle(struct dhd_bus *bus); ++extern int dhd_bus_request_irq(struct dhd_bus *bus); ++extern int dhdpcie_get_pcieirq(struct dhd_bus *bus, unsigned int *irq); ++ ++extern void dhdpcie_cto_init(struct dhd_bus *bus, bool enable); ++ ++ ++#ifdef DHD_FW_COREDUMP ++extern struct dhd_bus *g_dhd_bus; ++extern int dhd_dongle_mem_dump(void); ++#endif /* DHD_FW_COREDUMP */ ++ ++#ifdef IDLE_TX_FLOW_MGMT ++extern void dhd_bus_idle_tx_ring_suspend(dhd_pub_t *dhd, uint16 flow_ring_id); ++#endif /* IDLE_TX_FLOW_MGMT */ ++extern void dhd_bus_handle_mb_data(struct dhd_bus *bus, uint32 d2h_mb_data); ++#endif /* BCMPCIE */ ++ ++/* dump the device trap informtation */ ++extern void dhd_bus_dump_trap_info(struct dhd_bus *bus, struct bcmstrbuf *b); ++ ++/* Function to set default min res mask */ ++extern bool dhd_bus_set_default_min_res_mask(struct dhd_bus *bus); ++ ++/* Function to reset PMU registers */ ++extern void dhd_bus_pmu_reg_reset(dhd_pub_t *dhdp); ++ ++#ifdef DHD_ULP ++extern void dhd_bus_ulp_disable_console(dhd_pub_t *dhdp); ++extern void dhd_bus_ucode_download(struct dhd_bus *bus); ++#endif /* DHD_ULP */ ++extern int dhd_bus_readwrite_bp_addr(dhd_pub_t *dhdp, uint addr, uint size, uint* data, bool read); ++ ++#ifdef BT_OVER_SDIO ++/* ++ * SDIO layer clock control functions exposed to be called from other layers. ++ * This is required especially in the case where the BUS is shared between ++ * BT and SDIO and we have to control the clock. The callers of this function ++ * are expected to hold the sdlock ++ */ ++int __dhdsdio_clk_enable(struct dhd_bus *bus, bus_owner_t owner, int can_wait); ++int __dhdsdio_clk_disable(struct dhd_bus *bus, bus_owner_t owner, int can_wait); ++void dhdsdio_reset_bt_use_count(struct dhd_bus *bus); ++#endif /* BT_OVER_SDIO */ ++#ifdef BCMPCIE ++extern void dhd_bus_dump_console_buffer(struct dhd_bus *bus); ++#else ++#define dhd_bus_dump_console_buffer(x) ++#endif /* BCMPCIE */ ++ ++extern uint16 dhd_get_chipid(dhd_pub_t *dhd); ++ ++extern int dhd_get_idletime(dhd_pub_t *dhd); ++ ++#ifdef DHD_WAKE_STATUS ++extern wake_counts_t* dhd_bus_get_wakecount(dhd_pub_t *dhd); ++extern int dhd_bus_get_bus_wake(dhd_pub_t * dhd); ++#endif /* DHD_WAKE_STATUS */ ++#endif /* _dhd_bus_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_buzzz.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_buzzz.h +new file mode 100644 +index 000000000..e349a3f45 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_buzzz.h +@@ -0,0 +1,37 @@ ++#ifndef _DHD_BUZZZ_H_INCLUDED_ ++#define _DHD_BUZZZ_H_INCLUDED_ ++ ++/* ++ * Broadcom logging system - Empty implementaiton ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id$ ++ */ ++ ++#define dhd_buzzz_attach() do { /* noop */ } while (0) ++#define dhd_buzzz_detach() do { /* noop */ } while (0) ++#define dhd_buzzz_panic(x) do { /* noop */ } while (0) ++#define BUZZZ_LOG(ID, N, ARG...) do { /* noop */ } while (0) ++ ++#endif /* _DHD_BUZZZ_H_INCLUDED_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_ccode.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_ccode.c +new file mode 100644 +index 000000000..abf71ccd7 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_ccode.c +@@ -0,0 +1,234 @@ ++ ++#ifdef CCODE_LIST ++#ifdef CONFIG_COMPAT ++#include ++#endif /* COMFIG_COMPAT */ ++#include ++#include ++ ++#ifdef BCMSDIO ++#define CCODE_43438 ++#define CCODE_43455C0 ++#define CCODE_43456C5 ++#endif ++#if defined(BCMSDIO) || defined(BCMPCIE) ++#define CCODE_4356A2 ++#define CCODE_4359C0 ++#endif ++#ifdef BCMDBUS ++#define CCODE_4358U ++#endif ++ ++#ifdef BCMSDIO ++#ifdef CCODE_43438 ++const char ccode_43438[] = "RU/13"; ++#else ++const char ccode_43438 = ""; ++#endif ++ ++#ifdef CCODE_43455C0 ++const char ccode_43455c0[] = \ ++"AE/6 AG/2 AI/1 AL/2 AS/12 AT/4 AU/6 AW/2 AZ/2 "\ ++"BA/2 BD/1 BE/4 BG/4 BH/4 BM/12 BN/4 BR/2 BS/2 BY/3 "\ ++"CA/2 CA/31 CH/4 CN/38 CO/17 CR/17 CY/4 CZ/4 "\ ++"DE/3 DE/7 DK/4 "\ ++"EC/21 EE/4 EG/13 ES/4 ET/2 "\ ++"FI/4 FR/5 "\ ++"GB/1 GB/6 GD/2 GF/2 GP/2 GR/4 GT/1 GU/30 "\ ++"HK/2 HR/4 HU/4 "\ ++"ID/1 IE/5 IL/14 IN/3 IS/4 IT/4 "\ ++"JO/3 JP/45 JP/58 "\ ++"KH/2 KR/45 KR/48 KR/49 KR/70 KR/71 KR/96 KW/5 KY/3 "\ ++"LA/2 LB/5 LI/4 LK/1 LS/2 LT/4 LU/3 LV/4 "\ ++"MA/2 MC/1 MD/2 ME/2 MK/2 MN/1 MQ/2 MR/2 MT/4 MU/2 MV/3 MW/1 MX/44 MY/3 "\ ++"NI/2 NL/4 NO/4 NZ/4 "\ ++"OM/4 "\ ++"PA/17 PE/20 PH/5 PL/4 PR/38 PT/4 PY/2 "\ ++"Q2/993 "\ ++"RE/2 RO/4 RS/2 RU/13 "\ ++"SE/4 SI/4 SK/4 SV/25 "\ ++"TH/5 TN/1 TR/7 TT/3 TW/1 "\ ++"UA/8 US/988 "\ ++"VA/2 VE/3 VG/2 VN/4 "\ ++"XZ/11 "\ ++"YT/2 "\ ++"ZA/6"; ++#else ++const char ccode_43455c0[] = ""; ++#endif ++ ++#ifdef CCODE_43456C5 ++const char ccode_43456c5[] = \ ++"AE/6 AG/2 AI/1 AL/2 AS/12 AT/4 AU/6 AW/2 AZ/2 "\ ++"BA/2 BD/1 BE/4 BG/4 BH/4 BM/12 BN/4 BR/4 BS/2 BY/3 "\ ++"CA/2 CH/4 CN/38 CO/17 CR/17 CY/4 CZ/4 "\ ++"DE/7 DK/4 "\ ++"EC/21 EE/4 EG/13 ES/4 ET/2 "\ ++"FI/4 FR/5 "\ ++"GB/6 GD/2 GF/2 GP/2 GR/4 GT/1 GU/30 "\ ++"HK/2 HR/4 HU/4 "\ ++"ID/1 IE/5 IL/14 IN/3 IS/4 IT/4 "\ ++"JO/3 JP/58 "\ ++"KH/2 KR/96 KW/5 KY/3 "\ ++"LA/2 LB/5 LI/4 LK/1 LS/2 LT/4 LU/3 LV/4 "\ ++"MA/2 MC/1 MD/2 ME/2 MK/2 MN/1 MQ/2 MR/2 MT/4 MU/2 MV/3 MW/1 MX/44 MY/3 "\ ++"NI/2 NL/4 NO/4 NZ/4 "\ ++"OM/4 "\ ++"PA/17 PE/20 PH/5 PL/4 PR/38 PT/4 PY/2 "\ ++"Q2/993 "\ ++"RE/2 RO/4 RS/2 RU/13 "\ ++"SE/4 SI/4 SK/4 SV/25 "\ ++"TH/5 TN/1 TR/7 TT/3 TW/65 "\ ++"UA/8 US/988 "\ ++"VA/2 VE/3 VG/2 VN/4 "\ ++"XZ/11 "\ ++"YT/2 "\ ++"ZA/6"; ++#else ++const char ccode_43456c5[] = ""; ++#endif ++#endif ++ ++#ifdef CCODE_4356A2 ++const char ccode_4356a2[] = \ ++"AE/6 AG/2 AI/1 AL/2 AN/2 AR/21 AS/12 AT/4 AU/6 AW/2 AZ/2 "\ ++"BA/2 BD/2 BE/4 BG/4 BH/4 BM/12 BN/4 BR/4 BS/2 BY/3 "\ ++"CA/31 CH/4 CN/38 CO/17 CR/17 CY/4 CZ/4 "\ ++"DE/7 DK/4 DZ/1 "\ ++"EC/21 EE/4 ES/4 ET/2 "\ ++"FI/4 FR/5 "\ ++"GB/6 GD/2 GF/2 GP/2 GR/4 GT/1 GU/12 "\ ++"HK/2 HR/4 HU/4 "\ ++"ID/13 IE/5 IL/7 IN/28 IS/4 IT/4 "\ ++"JO/3 JP/58 "\ ++"KH/2 KR/57 KW/5 KY/3 "\ ++"LA/2 LB/5 LI/4 LK/1 LS/2 LT/4 LU/3 LV/4 "\ ++"MA/2 MC/1 MD/2 ME/2 MK/2 MN/1 MO/2 MR/2 MT/4 MQ/2 MU/2 MV/3 MW/1 MX/20 MY/16 "\ ++"NI/2 NL/4 NO/4 NP/3 NZ/4 "\ ++"OM/4 "\ ++"PA/17 PE/20 PG/2 PH/5 PL/4 PR/20 PT/4 PY/2 "\ ++"RE/2 RO/4 RS/2 RU/986 "\ ++"SE/4 SG/4 SG/19 SI/4 SK/4 SN/2 SV/19 "\ ++"TH/9 TN/1 TR/7 TT/3 TW/1 "\ ++"UA/8 UG/2 US/1 UY/1 "\ ++"VA/2 UA/16 VE/3 VG/2 VI/13 VN/4 "\ ++"XZ/11 "\ ++"YT/2 "\ ++"ZM/2 "\ ++"E0/32"; ++#else ++const char ccode_4356a2[] = ""; ++#endif ++ ++#ifdef CCODE_4359C0 ++const char ccode_4359c0[] = \ ++"AD/1 AE/6 AG/2 AI/1 AL/3 AS/12 AT/21 AU/6 AW/2 AZ/8 "\ ++"BA/4 BD/1 BE/19 BG/18 BH/4 BM/12 BN/4 BR/2 BS/2 BY/3 "\ ++"CN/38 CO/17 CR/17 CY/18 CZ/18 "\ ++"DE/30 DK/19 "\ ++"E0/32 EC/21 EE/18 EG/13 ES/21 ET/2 "\ ++"FI/19 FR/21 "\ ++"GB/996 GD/2 GE/1 GF/2 GP/2 GR/18 GT/1 GU/30 "\ ++"HK/2 HR/18 HU/18 "\ ++"ID/1 IE/21 IL/14 IN/3 IS/17 IT/20 "\ ++"JO/3 JP/967 "\ ++"KH/2 KR/70 KW/5 KY/3 "\ ++"LA/2 LB/5 LI/17 LI/4 LK/1 LS/2 LT/18 LU/18 LV/18 "\ ++"MA/2 MC/2 MD/3 ME/5 MK/4 MN/1 MQ/2 MR/2 MT/18 MU/2 MV/3 MW/1 MX/44 MY/3 "\ ++"NI/2 NL/19 NO/18 NZ/4 "\ ++"OM/4 "\ ++"PA/17 PE/20 PH/5 PL/18 PR/38 PT/20 PY/2 "\ ++"Q1/947 Q2/993 "\ ++"RE/2 RO/18 RS/4 RU/986 "\ ++"SE/19 SI/18 SK/18 SM/1 SV/25 "\ ++"TH/5 TN/1 TR/18 TT/3 TW/1 "\ ++"UA/16 US/988 "\ ++"VA/3 VE/3 VG/2 VN/4 "\ ++"XZ/11 "\ ++"YT/2 "\ ++"ZA/6"; ++#else ++const char ccode_4359c0[] = ""; ++#endif ++ ++#ifdef CCODE_4358U ++const char ccode_4358u[] = \ ++"BE/4 BR/4 CA/2 CH/4 CN/38 CY/4 DE/7 DK/4 ES/4 "\ ++"FI/4 FR/5 GB/6 GR/4 HK/2 HU/4 IE/5 IL/7 IS/4 "\ ++"IT/4 JP/72 KE/0 MY/3 NL/4 PT/4 SA/5 SE/4 SG/0 "\ ++"SZ/0 TH/5 TR/7 TW/230 US/0 VN/4"; ++#else ++const char ccode_4358u[] = ""; ++#endif ++ ++typedef struct ccode_list_map_t { ++ uint chip; ++ uint chiprev; ++ const char *ccode_list; ++ const char *ccode_ww; ++} ccode_list_map_t; ++ ++extern const char ccode_43438[]; ++extern const char ccode_43455c0[]; ++extern const char ccode_43456c5[]; ++extern const char ccode_4356a2[]; ++extern const char ccode_4359c0[]; ++extern const char ccode_4358u[]; ++ ++const ccode_list_map_t ccode_list_map[] = { ++ /* ChipID Chiprev ccode */ ++#ifdef BCMSDIO ++ {BCM43430_CHIP_ID, 0, ccode_43438, ""}, ++ {BCM43430_CHIP_ID, 1, ccode_43438, ""}, ++ {BCM4345_CHIP_ID, 6, ccode_43455c0, "XZ/11"}, ++ {BCM43454_CHIP_ID, 6, ccode_43455c0, "XZ/11"}, ++ {BCM4345_CHIP_ID, 9, ccode_43456c5, "XZ/11"}, ++ {BCM43454_CHIP_ID, 9, ccode_43456c5, "XZ/11"}, ++ {BCM4354_CHIP_ID, 2, ccode_4356a2, "XZ/11"}, ++ {BCM4356_CHIP_ID, 2, ccode_4356a2, "XZ/11"}, ++ {BCM4371_CHIP_ID, 2, ccode_4356a2, "XZ/11"}, ++ {BCM4359_CHIP_ID, 9, ccode_4359c0, "XZ/11"}, ++#endif ++#ifdef BCMPCIE ++ {BCM4354_CHIP_ID, 2, ccode_4356a2, "XZ/11"}, ++ {BCM4356_CHIP_ID, 2, ccode_4356a2, "XZ/11"}, ++ {BCM4359_CHIP_ID, 9, ccode_4359c0, "XZ/11"}, ++#endif ++#ifdef BCMDBUS ++ {BCM43569_CHIP_ID, 2, ccode_4358u, "XW/0"}, ++#endif ++}; ++ ++int ++dhd_ccode_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec) ++{ ++ int bcmerror = -1, i; ++ uint chip = dhd->conf->chip, chiprev = dhd->conf->chiprev; ++ const char *ccode_list = NULL, *ccode_ww = NULL; ++ char *pch; ++ ++ for (i=0; ichip == chip && row->chiprev == chiprev) { ++ ccode_list = row->ccode_list; ++ ccode_ww = row->ccode_ww; ++ break; ++ } ++ } ++ ++ if (ccode_list) { ++ pch = strstr(ccode_list, cspec->ccode); ++ if (pch) { ++ cspec->rev = (int)simple_strtol(pch+strlen(cspec->ccode)+1, NULL, 0); ++ bcmerror = 0; ++ } ++ } ++ ++ if (bcmerror && ccode_ww && strlen(ccode_ww)>=4) { ++ memcpy(cspec->ccode, ccode_ww, 2); ++ cspec->rev = (int)simple_strtol(ccode_ww+3, NULL, 0); ++ } ++ ++ return bcmerror; ++} ++#endif +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_cdc.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_cdc.c +new file mode 100644 +index 000000000..21286dded +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_cdc.c +@@ -0,0 +1,962 @@ ++/* ++ * DHD Protocol Module for CDC and BDC. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_cdc.c 699163 2017-05-12 05:18:23Z $ ++ * ++ * BDC is like CDC, except it includes a header for data packets to convey ++ * packet priority over the bus, and flags (e.g. to indicate checksum status ++ * for dongle offload.) ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++#ifdef BCMDBUS ++#include ++#endif /* BCMDBUS */ ++ ++#ifdef DHD_ULP ++#include ++#endif /* DHD_ULP */ ++ ++ ++#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ ++#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE ++ * defined in dhd_sdio.c (amount of header tha might be added) ++ * plus any space that might be needed for alignment padding. ++ */ ++#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for ++ * round off at the end of buffer ++ */ ++ ++typedef struct dhd_prot { ++ uint16 reqid; ++ uint8 pending; ++ uint32 lastcmd; ++#ifdef BCMDBUS ++ uint ctl_completed; ++#endif /* BCMDBUS */ ++ uint8 bus_header[BUS_HEADER_LEN]; ++ cdc_ioctl_t msg; ++ unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; ++} dhd_prot_t; ++ ++static int ++dhdcdc_msg(dhd_pub_t *dhd) ++{ ++#ifdef BCMDBUS ++ int timeout = 0; ++#endif /* BCMDBUS */ ++ int err = 0; ++ dhd_prot_t *prot = dhd->prot; ++ int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ DHD_OS_WAKE_LOCK(dhd); ++ ++ /* 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 ++ * is actually sent to the dongle ++ */ ++ if (len > CDC_MAX_MSG_SIZE) ++ len = CDC_MAX_MSG_SIZE; ++ ++ /* Send request */ ++#ifdef BCMDBUS ++ DHD_OS_IOCTL_RESP_LOCK(dhd); ++ prot->ctl_completed = FALSE; ++ err = dbus_send_ctl(dhd->bus, (void *)&prot->msg, len); ++ if (err) { ++ DHD_ERROR(("dbus_send_ctl error=%d\n", err)); ++ DHD_OS_IOCTL_RESP_UNLOCK(dhd); ++ DHD_OS_WAKE_UNLOCK(dhd); ++ return err; ++ } ++#else ++ err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); ++#endif /* BCMDBUS */ ++ ++#ifdef BCMDBUS ++ timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed); ++ if ((!timeout) || (!prot->ctl_completed)) { ++ DHD_ERROR(("Txctl timeout %d ctl_completed %d\n", ++ timeout, prot->ctl_completed)); ++ DHD_ERROR(("Txctl wait timed out\n")); ++ err = -1; ++ } ++ DHD_OS_IOCTL_RESP_UNLOCK(dhd); ++#endif /* BCMDBUS */ ++#if defined(BCMDBUS) && defined(INTR_EP_ENABLE) ++ /* If the ctl write is successfully completed, wait for an acknowledgement ++ * that indicates that it is now ok to do ctl read from the dongle ++ */ ++ if (err != -1) { ++ DHD_OS_IOCTL_RESP_LOCK(dhd); ++ prot->ctl_completed = FALSE; ++ if (dbus_poll_intr(dhd->dbus)) { ++ DHD_ERROR(("dbus_poll_intr not submitted\n")); ++ } else { ++ /* interrupt polling is sucessfully submitted. Wait for dongle to send ++ * interrupt ++ */ ++ timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed); ++ if (!timeout) { ++ DHD_ERROR(("intr poll wait timed out\n")); ++ } ++ } ++ DHD_OS_IOCTL_RESP_UNLOCK(dhd); ++ } ++#endif /* defined(BCMDBUS) && defined(INTR_EP_ENABLE) */ ++ DHD_OS_WAKE_UNLOCK(dhd); ++ return err; ++} ++ ++static int ++dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) ++{ ++#ifdef BCMDBUS ++ int timeout = 0; ++#endif /* BCMDBUS */ ++ int ret; ++ int cdc_len = len + sizeof(cdc_ioctl_t); ++ dhd_prot_t *prot = dhd->prot; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ do { ++#ifdef BCMDBUS ++ DHD_OS_IOCTL_RESP_LOCK(dhd); ++ prot->ctl_completed = FALSE; ++ ret = dbus_recv_ctl(dhd->bus, (uchar*)&prot->msg, cdc_len); ++ if (ret) { ++ DHD_ERROR(("dbus_recv_ctl error=0x%x(%d)\n", ret, ret)); ++ DHD_OS_IOCTL_RESP_UNLOCK(dhd); ++ goto done; ++ } ++ timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed); ++ if ((!timeout) || (!prot->ctl_completed)) { ++ DHD_ERROR(("Rxctl timeout %d ctl_completed %d\n", ++ timeout, prot->ctl_completed)); ++ ret = -1; ++ DHD_OS_IOCTL_RESP_UNLOCK(dhd); ++ ++ goto done; ++ } ++ DHD_OS_IOCTL_RESP_UNLOCK(dhd); ++ ++ ret = cdc_len; ++#else ++ ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); ++#endif /* BCMDBUS */ ++ if (ret < 0) ++ break; ++ } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); ++ ++#ifdef BCMDBUS ++done: ++#endif /* BCMDBUS */ ++ return ret; ++} ++ ++static int ++dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ cdc_ioctl_t *msg = &prot->msg; ++ int ret = 0, retries = 0; ++ uint32 id, flags = 0; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); ++ ++ ++ /* Respond "bcmerror" and "bcmerrorstr" with local cache */ ++ if (cmd == WLC_GET_VAR && buf) ++ { ++ if (!strcmp((char *)buf, "bcmerrorstr")) ++ { ++ strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN); ++ goto done; ++ } ++ else if (!strcmp((char *)buf, "bcmerror")) ++ { ++ *(int *)buf = dhd->dongle_error; ++ goto done; ++ } ++ } ++ ++ memset(msg, 0, sizeof(cdc_ioctl_t)); ++ ++ msg->cmd = htol32(cmd); ++ msg->len = htol32(len); ++ msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); ++ CDC_SET_IF_IDX(msg, ifidx); ++ /* add additional action bits */ ++ action &= WL_IOCTL_ACTION_MASK; ++ msg->flags |= (action << CDCF_IOC_ACTION_SHIFT); ++ msg->flags = htol32(msg->flags); ++ ++ if (buf) ++ memcpy(prot->buf, buf, len); ++ ++ if ((ret = dhdcdc_msg(dhd)) < 0) { ++ if (!dhd->hang_was_sent) ++ DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret)); ++ goto done; ++ } ++ ++retry: ++ /* wait for interrupt and get first fragment */ ++ if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) ++ goto done; ++ ++ flags = ltoh32(msg->flags); ++ id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; ++ ++ if ((id < prot->reqid) && (++retries < RETRIES)) ++ goto retry; ++ if (id != prot->reqid) { ++ DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", ++ dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ /* Copy info buffer */ ++ if (buf) ++ { ++ if (ret < (int)len) ++ len = ret; ++ memcpy(buf, (void*) prot->buf, len); ++ } ++ ++ /* Check the ERROR flag */ ++ if (flags & CDCF_IOC_ERROR) ++ { ++ ret = ltoh32(msg->status); ++ /* Cache error from dongle */ ++ dhd->dongle_error = ret; ++ } ++ ++done: ++ return ret; ++} ++ ++ ++static int ++dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ cdc_ioctl_t *msg = &prot->msg; ++ int ret = 0; ++ uint32 flags, id; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); ++ ++ if (dhd->busstate == DHD_BUS_DOWN) { ++ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); ++ return -EIO; ++ } ++ ++ /* don't talk to the dongle if fw is about to be reloaded */ ++ if (dhd->hang_was_sent) { ++ DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n", ++ __FUNCTION__)); ++ return -EIO; ++ } ++ ++ if (cmd == WLC_SET_PM) { ++ DHD_TRACE_HW4(("%s: SET PM to %d\n", __FUNCTION__, buf ? *(char *)buf : 0)); ++ } ++ ++ memset(msg, 0, sizeof(cdc_ioctl_t)); ++ ++ msg->cmd = htol32(cmd); ++ msg->len = htol32(len); ++ msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); ++ CDC_SET_IF_IDX(msg, ifidx); ++ /* add additional action bits */ ++ action &= WL_IOCTL_ACTION_MASK; ++ msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET; ++ msg->flags = htol32(msg->flags); ++ ++ if (buf) ++ memcpy(prot->buf, buf, len); ++ ++#ifdef DHD_ULP ++ if (buf && (!strncmp(buf, "ulp", sizeof("ulp")))) { ++ /* force all the writes after this point to NOT to use cached sbwad value */ ++ dhd_ulp_disable_cached_sbwad(dhd); ++ } ++#endif /* DHD_ULP */ ++ ++ if ((ret = dhdcdc_msg(dhd)) < 0) { ++ DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret)); ++ goto done; ++ } ++ ++ if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) ++ goto done; ++ ++ flags = ltoh32(msg->flags); ++ id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; ++ ++ if (id != prot->reqid) { ++ DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", ++ dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++#ifdef DHD_ULP ++ /* For ulp prototyping temporary */ ++ if ((ret = dhd_ulp_check_ulp_request(dhd, buf)) < 0) ++ goto done; ++#endif /* DHD_ULP */ ++ ++ /* Check the ERROR flag */ ++ if (flags & CDCF_IOC_ERROR) ++ { ++ ret = ltoh32(msg->status); ++ /* Cache error from dongle */ ++ dhd->dongle_error = ret; ++ } ++ ++done: ++ return ret; ++} ++ ++#ifdef BCMDBUS ++int ++dhd_prot_ctl_complete(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot; ++ ++ if (dhd == NULL) ++ return BCME_ERROR; ++ ++ prot = dhd->prot; ++ ++ ASSERT(prot); ++ DHD_OS_IOCTL_RESP_LOCK(dhd); ++ prot->ctl_completed = TRUE; ++ dhd_os_ioctl_resp_wake(dhd); ++ DHD_OS_IOCTL_RESP_UNLOCK(dhd); ++ return 0; ++} ++#endif /* BCMDBUS */ ++ ++int ++dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ int ret = -1; ++ uint8 action; ++ static int error_cnt = 0; ++ ++ if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { ++ DHD_ERROR(("%s : bus is down. we have nothing to do - bs: %d, has: %d\n", ++ __FUNCTION__, dhd->busstate, dhd->hang_was_sent)); ++ goto done; ++ } ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ ASSERT(len <= WLC_IOCTL_MAXLEN); ++ ++ if (len > WLC_IOCTL_MAXLEN) ++ goto done; ++ ++ if (prot->pending == TRUE) { ++ DHD_ERROR(("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 == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { ++ DHD_TRACE(("iovar cmd=%s\n", buf ? (char*)buf : "\0")); ++ } ++ goto done; ++ } ++ ++ prot->pending = TRUE; ++ prot->lastcmd = ioc->cmd; ++ action = ioc->set; ++ if (action & WL_IOCTL_ACTION_SET) ++ ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); ++ else { ++ ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); ++ if (ret > 0) ++ ioc->used = ret - sizeof(cdc_ioctl_t); ++ } ++ // terence 20130805: send hang event to wpa_supplicant ++ if (ret == -EIO) { ++ error_cnt++; ++ if (error_cnt > 2) ++ ret = -ETIMEDOUT; ++ } else ++ error_cnt = 0; ++ ++ /* Too many programs assume ioctl() returns 0 on success */ ++ if (ret >= 0) ++ ret = 0; ++ else { ++ cdc_ioctl_t *msg = &prot->msg; ++ ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */ ++ } ++ ++ /* Intercept the wme_dp ioctl here */ ++ if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { ++ int slen, val = 0; ++ ++ slen = strlen("wme_dp") + 1; ++ if (len >= (int)(slen + sizeof(int))) ++ bcopy(((char *)buf + slen), &val, sizeof(int)); ++ dhd->wme_dp = (uint8) ltoh32(val); ++ } ++ ++ prot->pending = FALSE; ++ ++done: ++ ++ return ret; ++} ++ ++int ++dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ return BCME_UNSUPPORTED; ++} ++ ++void ++dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ if (!dhdp || !dhdp->prot) { ++ return; ++ } ++ ++ bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); ++#ifdef PROP_TXSTATUS ++ dhd_wlfc_dump(dhdp, strbuf); ++#endif ++} ++ ++/* The FreeBSD PKTPUSH could change the packet buf pinter ++ so we need to make it changable ++*/ ++#define PKTBUF pktbuf ++void ++dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) ++{ ++#ifdef BDC ++ struct bdc_header *h; ++#endif /* BDC */ ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++#ifdef BDC ++ /* Push BDC header used to convey priority for buses that don't */ ++ ++ PKTPUSH(dhd->osh, PKTBUF, BDC_HEADER_LEN); ++ ++ h = (struct bdc_header *)PKTDATA(dhd->osh, PKTBUF); ++ ++ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); ++ if (PKTSUMNEEDED(PKTBUF)) ++ h->flags |= BDC_FLAG_SUM_NEEDED; ++ ++ ++ h->priority = (PKTPRIO(PKTBUF) & BDC_PRIORITY_MASK); ++ h->flags2 = 0; ++ h->dataOffset = 0; ++#endif /* BDC */ ++ BDC_SET_IF_IDX(h, ifidx); ++} ++#undef PKTBUF /* Only defined in the above routine */ ++ ++uint ++dhd_prot_hdrlen(dhd_pub_t *dhd, void *PKTBUF) ++{ ++ uint hdrlen = 0; ++#ifdef BDC ++ /* Length of BDC(+WLFC) headers pushed */ ++ hdrlen = BDC_HEADER_LEN + (((struct bdc_header *)PKTBUF)->dataOffset * 4); ++#endif ++ return hdrlen; ++} ++ ++int ++dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, ++ uint *reorder_info_len) ++{ ++#ifdef BDC ++ struct bdc_header *h; ++#endif ++ uint8 data_offset = 0; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++#ifdef BDC ++ if (reorder_info_len) ++ *reorder_info_len = 0; ++ /* Pop BDC header used to convey priority for buses that don't */ ++ ++ if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) { ++ DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN)); ++ return BCME_ERROR; ++ } ++ ++ h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); ++ ++ if (!ifidx) { ++ /* for tx packet, skip the analysis */ ++ data_offset = h->dataOffset; ++ PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); ++ goto exit; ++ } ++ ++ *ifidx = BDC_GET_IF_IDX(h); ++ ++ if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { ++ DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n", ++ dhd_ifname(dhd, *ifidx), h->flags)); ++ if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1) ++ h->dataOffset = 0; ++ else ++ return BCME_ERROR; ++ } ++ ++ if (h->flags & BDC_FLAG_SUM_GOOD) { ++ DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n", ++ dhd_ifname(dhd, *ifidx), h->flags)); ++ PKTSETSUMGOOD(pktbuf, TRUE); ++ } ++ ++ PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); ++ data_offset = h->dataOffset; ++ PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); ++#endif /* BDC */ ++ ++ ++#ifdef PROP_TXSTATUS ++ if (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf))) { ++ /* ++ - parse txstatus only for packets that came from the firmware ++ */ ++ dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2), ++ reorder_buf_info, reorder_info_len); ++ ++#ifdef BCMDBUS ++#ifndef DHD_WLFC_THREAD ++ dhd_wlfc_commit_packets(dhd, ++ (f_commitpkt_t)dhd_bus_txdata, dhd->bus, NULL, FALSE); ++#endif /* DHD_WLFC_THREAD */ ++#endif /* BCMDBUS */ ++ } ++#endif /* PROP_TXSTATUS */ ++ ++exit: ++ PKTPULL(dhd->osh, pktbuf, (data_offset << 2)); ++ return 0; ++} ++ ++ ++int ++dhd_prot_attach(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *cdc; ++ ++ if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) { ++ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ memset(cdc, 0, sizeof(dhd_prot_t)); ++ ++ /* ensure that the msg buf directly follows the cdc msg struct */ ++ if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) { ++ DHD_ERROR(("dhd_prot_t is not correctly defined\n")); ++ goto fail; ++ } ++ ++ dhd->prot = cdc; ++#ifdef BDC ++ dhd->hdrlen += BDC_HEADER_LEN; ++#endif ++ dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN; ++ return 0; ++ ++fail: ++ if (cdc != NULL) ++ DHD_OS_PREFREE(dhd, cdc, sizeof(dhd_prot_t)); ++ return BCME_NOMEM; ++} ++ ++/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ ++void ++dhd_prot_detach(dhd_pub_t *dhd) ++{ ++#ifdef PROP_TXSTATUS ++ dhd_wlfc_deinit(dhd); ++#endif ++ DHD_OS_PREFREE(dhd, dhd->prot, sizeof(dhd_prot_t)); ++ dhd->prot = NULL; ++} ++ ++void ++dhd_prot_dstats(dhd_pub_t *dhd) ++{ ++ /* copy bus stats */ ++ ++ dhd->dstats.tx_packets = dhd->tx_packets; ++ dhd->dstats.tx_errors = dhd->tx_errors; ++ dhd->dstats.rx_packets = dhd->rx_packets; ++ dhd->dstats.rx_errors = dhd->rx_errors; ++ dhd->dstats.rx_dropped = dhd->rx_dropped; ++ dhd->dstats.multicast = dhd->rx_multicast; ++ return; ++} ++ ++int ++dhd_sync_with_dongle(dhd_pub_t *dhd) ++{ ++ int ret = 0; ++ wlc_rev_info_t revinfo; ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++#ifdef DHD_FW_COREDUMP ++ /* Check the memdump capability */ ++ dhd_get_memdump_info(dhd); ++#endif /* DHD_FW_COREDUMP */ ++ ++#ifdef BCMASSERT_LOG ++ dhd_get_assert_info(dhd); ++#endif /* BCMASSERT_LOG */ ++ ++ /* Get the device rev info */ ++ memset(&revinfo, 0, sizeof(revinfo)); ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); ++ if (ret < 0) ++ goto done; ++#if defined(BCMDBUS) ++ if (dhd_download_fw_on_driverload) { ++ dhd_conf_reset(dhd); ++ dhd_conf_set_chiprev(dhd, revinfo.chipnum, revinfo.chiprev); ++ dhd_conf_preinit(dhd); ++ dhd_conf_read_config(dhd, dhd->conf_path); ++ } ++#endif /* BCMDBUS */ ++ ++ ++ DHD_SSSR_DUMP_INIT(dhd); ++ ++ dhd_process_cid_mac(dhd, TRUE); ++ ret = dhd_preinit_ioctls(dhd); ++ dhd_process_cid_mac(dhd, FALSE); ++ ++ /* Always assumes wl for now */ ++ dhd->iswl = TRUE; ++ ++done: ++ return ret; ++} ++ ++int dhd_prot_init(dhd_pub_t *dhd) ++{ ++ return BCME_OK; ++} ++ ++void ++dhd_prot_stop(dhd_pub_t *dhd) ++{ ++/* Nothing to do for CDC */ ++} ++ ++ ++static void ++dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt, ++ uint32 *pkt_count, void **pplast, uint8 start, uint8 end) ++{ ++ void *plast = NULL, *p; ++ uint32 pkt_cnt = 0; ++ ++ if (ptr->pend_pkts == 0) { ++ DHD_REORDER(("%s: no packets in reorder queue \n", __FUNCTION__)); ++ *pplast = NULL; ++ *pkt_count = 0; ++ *pkt = NULL; ++ return; ++ } ++ do { ++ p = (void *)(ptr->p[start]); ++ ptr->p[start] = NULL; ++ ++ if (p != NULL) { ++ if (plast == NULL) ++ *pkt = p; ++ else ++ PKTSETNEXT(osh, plast, p); ++ ++ plast = p; ++ pkt_cnt++; ++ } ++ start++; ++ if (start > ptr->max_idx) ++ start = 0; ++ } while (start != end); ++ *pplast = plast; ++ *pkt_count = pkt_cnt; ++ ptr->pend_pkts -= (uint8)pkt_cnt; ++} ++ ++int ++dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, ++ void **pkt, uint32 *pkt_count) ++{ ++ uint8 flow_id, max_idx, cur_idx, exp_idx; ++ struct reorder_info *ptr; ++ uint8 flags; ++ void *cur_pkt, *plast = NULL; ++ uint32 cnt = 0; ++ ++ if (pkt == NULL) { ++ if (pkt_count != NULL) ++ *pkt_count = 0; ++ return 0; ++ } ++ ++ flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET]; ++ flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET]; ++ ++ DHD_REORDER(("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags, ++ reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET], ++ reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET], ++ reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET])); ++ ++ /* validate flags and flow id */ ++ if (flags == 0xFF) { ++ DHD_ERROR(("%s: invalid flags...so ignore this packet\n", __FUNCTION__)); ++ *pkt_count = 1; ++ return 0; ++ } ++ ++ cur_pkt = *pkt; ++ *pkt = NULL; ++ ++ ptr = dhd->reorder_bufs[flow_id]; ++ if (flags & WLHOST_REORDERDATA_DEL_FLOW) { ++ uint32 buf_size = sizeof(struct reorder_info); ++ ++ DHD_REORDER(("%s: Flags indicating to delete a flow id %d\n", ++ __FUNCTION__, flow_id)); ++ ++ if (ptr == NULL) { ++ DHD_REORDER(("%s: received flags to cleanup, but no flow (%d) yet\n", ++ __FUNCTION__, flow_id)); ++ *pkt_count = 1; ++ *pkt = cur_pkt; ++ return 0; ++ } ++ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ ptr->exp_idx, ptr->exp_idx); ++ /* set it to the last packet */ ++ if (plast) { ++ PKTSETNEXT(dhd->osh, plast, cur_pkt); ++ cnt++; ++ } ++ else { ++ if (cnt != 0) { ++ DHD_ERROR(("%s: del flow: something fishy, pending packets %d\n", ++ __FUNCTION__, cnt)); ++ } ++ *pkt = cur_pkt; ++ cnt = 1; ++ } ++ buf_size += ((ptr->max_idx + 1) * sizeof(void *)); ++ MFREE(dhd->osh, ptr, buf_size); ++ dhd->reorder_bufs[flow_id] = NULL; ++ *pkt_count = cnt; ++ return 0; ++ } ++ /* all the other cases depend on the existance of the reorder struct for that flow id */ ++ if (ptr == NULL) { ++ uint32 buf_size_alloc = sizeof(reorder_info_t); ++ max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; ++ ++ buf_size_alloc += ((max_idx + 1) * sizeof(void*)); ++ /* allocate space to hold the buffers, index etc */ ++ ++ DHD_REORDER(("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n", ++ __FUNCTION__, buf_size_alloc, flow_id, max_idx)); ++ ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc); ++ if (ptr == NULL) { ++ DHD_ERROR(("%s: Malloc failed to alloc buffer\n", __FUNCTION__)); ++ *pkt_count = 1; ++ return 0; ++ } ++ bzero(ptr, buf_size_alloc); ++ dhd->reorder_bufs[flow_id] = ptr; ++ ptr->p = (void *)(ptr+1); ++ ptr->max_idx = max_idx; ++ } ++ if (flags & WLHOST_REORDERDATA_NEW_HOLE) { ++ DHD_REORDER(("%s: new hole, so cleanup pending buffers\n", __FUNCTION__)); ++ if (ptr->pend_pkts) { ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ ptr->exp_idx, ptr->exp_idx); ++ ptr->pend_pkts = 0; ++ } ++ ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; ++ ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; ++ ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; ++ ptr->p[ptr->cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ *pkt_count = cnt; ++ } ++ else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) { ++ cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; ++ exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; ++ ++ ++ if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) { ++ /* still in the current hole */ ++ /* enqueue the current on the buffer chain */ ++ if (ptr->p[cur_idx] != NULL) { ++ DHD_REORDER(("%s: HOLE: ERROR buffer pending..free it\n", ++ __FUNCTION__)); ++ PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); ++ ptr->p[cur_idx] = NULL; ++ } ++ ptr->p[cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ ptr->cur_idx = cur_idx; ++ DHD_REORDER(("%s: fill up a hole..pending packets is %d\n", ++ __FUNCTION__, ptr->pend_pkts)); ++ *pkt_count = 0; ++ *pkt = NULL; ++ } ++ else if (ptr->exp_idx == cur_idx) { ++ /* got the right one ..flush from cur to exp and update exp */ ++ DHD_REORDER(("%s: got the right one now, cur_idx is %d\n", ++ __FUNCTION__, cur_idx)); ++ if (ptr->p[cur_idx] != NULL) { ++ DHD_REORDER(("%s: Error buffer pending..free it\n", ++ __FUNCTION__)); ++ PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); ++ ptr->p[cur_idx] = NULL; ++ } ++ ptr->p[cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ ++ ptr->cur_idx = cur_idx; ++ ptr->exp_idx = exp_idx; ++ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ cur_idx, exp_idx); ++ *pkt_count = cnt; ++ DHD_REORDER(("%s: freeing up buffers %d, still pending %d\n", ++ __FUNCTION__, cnt, ptr->pend_pkts)); ++ } ++ else { ++ uint8 end_idx; ++ bool flush_current = FALSE; ++ /* both cur and exp are moved now .. */ ++ DHD_REORDER(("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n", ++ __FUNCTION__, flow_id, ptr->cur_idx, cur_idx, ++ ptr->exp_idx, exp_idx)); ++ if (flags & WLHOST_REORDERDATA_FLUSH_ALL) ++ end_idx = ptr->exp_idx; ++ else ++ end_idx = exp_idx; ++ ++ /* flush pkts first */ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ++ ptr->exp_idx, end_idx); ++ ++ if (cur_idx == ptr->max_idx) { ++ if (exp_idx == 0) ++ flush_current = TRUE; ++ } else { ++ if (exp_idx == cur_idx + 1) ++ flush_current = TRUE; ++ } ++ if (flush_current) { ++ if (plast) ++ PKTSETNEXT(dhd->osh, plast, cur_pkt); ++ else ++ *pkt = cur_pkt; ++ cnt++; ++ } ++ else { ++ ptr->p[cur_idx] = cur_pkt; ++ ptr->pend_pkts++; ++ } ++ ptr->exp_idx = exp_idx; ++ ptr->cur_idx = cur_idx; ++ *pkt_count = cnt; ++ } ++ } ++ else { ++ uint8 end_idx; ++ /* no real packet but update to exp_seq...that means explicit window move */ ++ exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; ++ ++ DHD_REORDER(("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n", ++ __FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx)); ++ if (flags & WLHOST_REORDERDATA_FLUSH_ALL) ++ end_idx = ptr->exp_idx; ++ else ++ end_idx = exp_idx; ++ ++ dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx); ++ if (plast) ++ PKTSETNEXT(dhd->osh, plast, cur_pkt); ++ else ++ *pkt = cur_pkt; ++ cnt++; ++ *pkt_count = cnt; ++ /* set the new expected idx */ ++ ptr->exp_idx = exp_idx; ++ } ++ return 0; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +new file mode 100644 +index 000000000..d01e76801 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +@@ -0,0 +1,269 @@ ++/* ++ * Linux cfg80211 driver - Dongle Host Driver (DHD) related ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_cfg80211.c 699163 2017-05-12 05:18:23Z $ ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef PKT_FILTER_SUPPORT ++#include ++#include ++#endif ++ ++#ifdef PKT_FILTER_SUPPORT ++extern uint dhd_pkt_filter_enable; ++extern uint dhd_master_mode; ++extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); ++#endif ++ ++static int dhd_dongle_up = FALSE; ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static s32 wl_dongle_up(struct net_device *ndev); ++static s32 wl_dongle_down(struct net_device *ndev); ++ ++/** ++ * Function implementations ++ */ ++ ++s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg) ++{ ++ dhd_dongle_up = FALSE; ++ return 0; ++} ++ ++s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg) ++{ ++ dhd_dongle_up = FALSE; ++ return 0; ++} ++ ++s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg) ++{ ++ struct net_device *ndev; ++ s32 err = 0; ++ ++ WL_TRACE(("In\n")); ++ if (!dhd_dongle_up) { ++ WL_ERR(("Dongle is already down\n")); ++ return err; ++ } ++ ++ ndev = bcmcfg_to_prmry_ndev(cfg); ++ wl_dongle_down(ndev); ++ dhd_dongle_up = FALSE; ++ return 0; ++} ++ ++s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); ++ dhd->op_mode |= val; ++ WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode)); ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd->arp_version == 1) { ++ /* IF P2P is enabled, disable arpoe */ ++ dhd_arp_offload_set(dhd, 0); ++ dhd_arp_offload_enable(dhd, false); ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++ return 0; ++} ++ ++s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); ++ dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE); ++ WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode)); ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd->arp_version == 1) { ++ /* IF P2P is disabled, enable arpoe back for STA mode. */ ++ dhd_arp_offload_set(dhd, dhd_arp_mode); ++ dhd_arp_offload_enable(dhd, true); ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++ return 0; ++} ++ ++struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, const char *name, ++ uint8 *mac, uint8 bssidx, const char *dngl_name) ++{ ++ return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE, dngl_name); ++} ++ ++int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, ++ int ifidx, struct net_device* ndev, bool rtnl_lock_reqd) ++{ ++ return dhd_register_if(cfg->pub, ifidx, rtnl_lock_reqd); ++} ++ ++int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, ++ int ifidx, struct net_device* ndev, bool rtnl_lock_reqd) ++{ ++ return dhd_remove_if(cfg->pub, ifidx, rtnl_lock_reqd); ++} ++ ++struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev) ++{ ++ if (ndev) { ++ if (ndev->ieee80211_ptr) { ++ kfree(ndev->ieee80211_ptr); ++ ndev->ieee80211_ptr = NULL; ++ } ++ free_netdev(ndev); ++ return NULL; ++ } ++ ++ return ndev; ++} ++ ++void dhd_netdev_free(struct net_device *ndev) ++{ ++#ifdef WL_CFG80211 ++ ndev = dhd_cfg80211_netdev_free(ndev); ++#endif ++ if (ndev) ++ free_netdev(ndev); ++} ++ ++static s32 ++wl_dongle_up(struct net_device *ndev) ++{ ++ s32 err = 0; ++ u32 local_up = 0; ++ ++ err = wldev_ioctl_set(ndev, WLC_UP, &local_up, sizeof(local_up)); ++ if (unlikely(err)) { ++ WL_ERR(("WLC_UP error (%d)\n", err)); ++ } ++ return err; ++} ++ ++static s32 ++wl_dongle_down(struct net_device *ndev) ++{ ++ s32 err = 0; ++ u32 local_down = 0; ++ ++ err = wldev_ioctl_set(ndev, WLC_DOWN, &local_down, sizeof(local_down)); ++ if (unlikely(err)) { ++ WL_ERR(("WLC_DOWN error (%d)\n", err)); ++ } ++ return err; ++} ++ ++ ++s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) ++{ ++#ifndef DHD_SDALIGN ++#define DHD_SDALIGN 32 ++#endif ++ struct net_device *ndev; ++ s32 err = 0; ++ ++ WL_TRACE(("In\n")); ++ if (dhd_dongle_up) { ++ WL_ERR(("Dongle is already up\n")); ++ return err; ++ } ++ ++ ndev = bcmcfg_to_prmry_ndev(cfg); ++ ++ err = wl_dongle_up(ndev); ++ if (unlikely(err)) { ++ WL_ERR(("wl_dongle_up failed\n")); ++ goto default_conf_out; ++ } ++ dhd_dongle_up = true; ++ ++default_conf_out: ++ ++ return err; ++ ++} ++ ++int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev, ++ const struct bcm_nlmsg_hdr *nlioc, void *buf) ++{ ++ struct net_device *ndev = NULL; ++ dhd_pub_t *dhd; ++ dhd_ioctl_t ioc = { 0, NULL, 0, 0, 0, 0, 0}; ++ int ret = 0; ++ int8 index; ++ ++ WL_TRACE(("entry: cmd = %d\n", nlioc->cmd)); ++ ++ dhd = cfg->pub; ++ DHD_OS_WAKE_LOCK(dhd); ++ ++ /* send to dongle only if we are not waiting for reload already */ ++ if (dhd->hang_was_sent) { ++ WL_ERR(("HANG was sent up earlier\n")); ++ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS); ++ DHD_OS_WAKE_UNLOCK(dhd); ++ return OSL_ERROR(BCME_DONGLE_DOWN); ++ } ++ ++ ndev = wdev_to_wlc_ndev(wdev, cfg); ++ index = dhd_net2idx(dhd->info, ndev); ++ if (index == DHD_BAD_IF) { ++ WL_ERR(("Bad ifidx from wdev:%p\n", wdev)); ++ ret = BCME_ERROR; ++ goto done; ++ } ++ ++ ioc.cmd = nlioc->cmd; ++ ioc.len = nlioc->len; ++ ioc.set = nlioc->set; ++ ioc.driver = nlioc->magic; ++ ioc.buf = buf; ++ ret = dhd_ioctl_process(dhd, index, &ioc, buf); ++ if (ret) { ++ WL_TRACE(("dhd_ioctl_process return err %d\n", ret)); ++ ret = OSL_ERROR(ret); ++ goto done; ++ } ++ ++done: ++ DHD_OS_WAKE_UNLOCK(dhd); ++ return ret; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_cfg80211.h +new file mode 100644 +index 000000000..20923ce5f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_cfg80211.h +@@ -0,0 +1,54 @@ ++/* ++ * Linux cfg80211 driver - Dongle Host Driver (DHD) related ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_cfg80211.h 612483 2016-01-14 03:44:27Z $ ++ */ ++ ++ ++#ifndef __DHD_CFG80211__ ++#define __DHD_CFG80211__ ++ ++#include ++#include ++#include ++ ++#ifndef WL_ERR ++#define WL_ERR CFG80211_ERR ++#endif ++#ifndef WL_TRACE ++#define WL_TRACE CFG80211_TRACE ++#endif ++ ++s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg); ++s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg); ++s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg); ++s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val); ++s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg); ++s32 dhd_config_dongle(struct bcm_cfg80211 *cfg); ++int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg, ++ struct wireless_dev *wdev, const struct bcm_nlmsg_hdr *nlioc, void *data); ++ ++#endif /* __DHD_CFG80211__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_common.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_common.c +new file mode 100644 +index 000000000..c2ddbf1ab +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_common.c +@@ -0,0 +1,6076 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), common DHD core. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_common.c 710862 2017-07-14 07:43:59Z $ ++ */ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef PCIE_FULL_DONGLE ++#include ++#endif /* PCIE_FULL_DONGLE */ ++ ++#ifdef SHOW_LOGTRACE ++#include ++#endif /* SHOW_LOGTRACE */ ++ ++#ifdef BCMPCIE ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef WL_CFG80211 ++#include ++#endif ++#ifdef PNO_SUPPORT ++#include ++#elif defined(WL_WIRELESS_EXT) ++#include ++#endif ++#ifdef RTT_SUPPORT ++#include ++#endif ++ ++#ifdef DNGL_EVENT_SUPPORT ++#include ++#endif ++ ++#define htod32(i) (i) ++#define htod16(i) (i) ++#define dtoh32(i) (i) ++#define dtoh16(i) (i) ++#define htodchanspec(i) (i) ++#define dtohchanspec(i) (i) ++ ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++ ++#ifdef DHD_WMF ++#include ++#include ++#endif /* DHD_WMF */ ++ ++#ifdef DHD_L2_FILTER ++#include ++#endif /* DHD_L2_FILTER */ ++ ++#ifdef DHD_PSTA ++#include ++#endif /* DHD_PSTA */ ++#ifdef DHD_TIMESYNC ++#include ++#endif /* DHD_TIMESYNC */ ++ ++#ifdef DHD_WET ++#include ++#endif /* DHD_WET */ ++ ++#if defined(BCMEMBEDIMAGE) && defined(DHD_EFI) ++#include ++#endif ++ ++#ifdef WLMEDIA_HTSF ++extern void htsf_update(struct dhd_info *dhd, void *data); ++#endif ++ ++extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, ++ bcm_event_msg_u_t *out_event); ++ ++/* By default all logs are enabled */ ++int dhd_msg_level = DHD_ERROR_VAL | DHD_MSGTRACE_VAL | DHD_FWLOG_VAL; ++ ++ ++#if defined(WL_WLC_SHIM) ++#include ++#else ++#endif /* WL_WLC_SHIM */ ++ ++#ifdef DHD_ULP ++#include ++#endif /* DHD_ULP */ ++ ++#ifdef DHD_DEBUG ++#include ++#endif /* DHD_DEBUG */ ++ ++#ifdef SOFTAP ++char fw_path2[MOD_PARAM_PATHLEN]; ++extern bool softap_enabled; ++#endif ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++/* Default timeout value in ms */ ++#define SCAN_TIMEOUT_DEFAULT 1 ++#define JOIN_TIMEOUT_DEFAULT 7500 ++#ifdef DHD_EFI ++#define BUS_TIMEOUT_DEFAULT 8000000 /* 800ms, in units of 100ns */ ++#define CMD_TIMEOUT_DEFAULT 15000000 /* 1.5sec, in units of 100ns */ ++#else ++#define BUS_TIMEOUT_DEFAULT 800 ++#define CMD_TIMEOUT_DEFAULT 1200 ++#endif /* DHD_EFI */ ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++#ifdef SHOW_LOGTRACE ++#define BYTES_AHEAD_NUM 11 /* address in map file is before these many bytes */ ++#define READ_NUM_BYTES 1000 /* read map file each time this No. of bytes */ ++#define GO_BACK_FILE_POS_NUM_BYTES 100 /* set file pos back to cur pos */ ++static char *ramstart_str = "text_start"; /* string in mapfile has addr ramstart */ ++static char *rodata_start_str = "rodata_start"; /* string in mapfile has addr rodata start */ ++static char *rodata_end_str = "rodata_end"; /* string in mapfile has addr rodata end */ ++#define RAMSTART_BIT 0x01 ++#define RDSTART_BIT 0x02 ++#define RDEND_BIT 0x04 ++#define ALL_MAP_VAL (RAMSTART_BIT | RDSTART_BIT | RDEND_BIT) ++#endif /* SHOW_LOGTRACE */ ++ ++/* Last connection success/failure status */ ++uint32 dhd_conn_event; ++uint32 dhd_conn_status; ++uint32 dhd_conn_reason; ++ ++extern int dhd_iscan_request(void * dhdp, uint16 action); ++extern void dhd_ind_scan_confirm(void *h, bool status); ++extern int dhd_iscan_in_progress(void *h); ++void dhd_iscan_lock(void); ++void dhd_iscan_unlock(void); ++extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); ++#if !defined(AP) && defined(WLP2P) ++extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); ++#endif ++ ++extern int dhd_socram_dump(struct dhd_bus *bus); ++ ++#ifdef DNGL_EVENT_SUPPORT ++static void dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, ++ bcm_dngl_event_msg_t *dngl_event, size_t pktlen); ++static int dngl_host_event(dhd_pub_t *dhdp, void *pktdata, bcm_dngl_event_msg_t *dngl_event, ++ size_t pktlen); ++#endif /* DNGL_EVENT_SUPPORT */ ++ ++#define MAX_CHUNK_LEN 1408 /* 8 * 8 * 22 */ ++ ++bool ap_cfg_running = FALSE; ++bool ap_fw_loaded = FALSE; ++ ++/* Version string to report */ ++#ifdef DHD_DEBUG ++#ifndef SRCBASE ++#define SRCBASE "drivers/net/wireless/bcmdhd" ++#endif ++#define DHD_COMPILED "\nCompiled in " SRCBASE ++#endif /* DHD_DEBUG */ ++ ++#define CHIPID_MISMATCH 8 ++ ++#if defined(DHD_DEBUG) ++const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR; ++#else ++const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR; ++#endif ++char fw_version[FW_VER_STR_LEN] = "\0"; ++char clm_version[CLM_VER_STR_LEN] = "\0"; ++ ++char bus_api_revision[BUS_API_REV_STR_LEN] = "\0"; ++ ++void dhd_set_timer(void *bus, uint wdtick); ++ ++#if defined(TRAFFIC_MGMT_DWM) ++static int traffic_mgmt_add_dwm_filter(dhd_pub_t *dhd, ++ trf_mgmt_filter_list_t * trf_mgmt_filter_list, int len); ++#endif ++ ++/* IOVar table */ ++enum { ++ IOV_VERSION = 1, ++ IOV_WLMSGLEVEL, ++ IOV_MSGLEVEL, ++ IOV_BCMERRORSTR, ++ IOV_BCMERROR, ++ IOV_WDTICK, ++ IOV_DUMP, ++ IOV_CLEARCOUNTS, ++ IOV_LOGDUMP, ++ IOV_LOGCAL, ++ IOV_LOGSTAMP, ++ IOV_GPIOOB, ++ IOV_IOCTLTIMEOUT, ++ IOV_CONS, ++ IOV_DCONSOLE_POLL, ++#if defined(DHD_DEBUG) ++ IOV_DHD_JOIN_TIMEOUT_DBG, ++ IOV_SCAN_TIMEOUT, ++ IOV_MEM_DEBUG, ++#endif /* defined(DHD_DEBUG) */ ++#ifdef PROP_TXSTATUS ++ IOV_PROPTXSTATUS_ENABLE, ++ IOV_PROPTXSTATUS_MODE, ++ IOV_PROPTXSTATUS_OPT, ++ IOV_PROPTXSTATUS_MODULE_IGNORE, ++ IOV_PROPTXSTATUS_CREDIT_IGNORE, ++ IOV_PROPTXSTATUS_TXSTATUS_IGNORE, ++ IOV_PROPTXSTATUS_RXPKT_CHK, ++#endif /* PROP_TXSTATUS */ ++ IOV_BUS_TYPE, ++#ifdef WLMEDIA_HTSF ++ IOV_WLPKTDLYSTAT_SZ, ++#endif ++ IOV_CHANGEMTU, ++ IOV_HOSTREORDER_FLOWS, ++#ifdef DHDTCPACK_SUPPRESS ++ IOV_TCPACK_SUPPRESS, ++#endif /* DHDTCPACK_SUPPRESS */ ++#ifdef DHD_WMF ++ IOV_WMF_BSS_ENAB, ++ IOV_WMF_UCAST_IGMP, ++ IOV_WMF_MCAST_DATA_SENDUP, ++#ifdef WL_IGMP_UCQUERY ++ IOV_WMF_UCAST_IGMP_QUERY, ++#endif /* WL_IGMP_UCQUERY */ ++#ifdef DHD_UCAST_UPNP ++ IOV_WMF_UCAST_UPNP, ++#endif /* DHD_UCAST_UPNP */ ++ IOV_WMF_PSTA_DISABLE, ++#endif /* DHD_WMF */ ++#if defined(TRAFFIC_MGMT_DWM) ++ IOV_TRAFFIC_MGMT_DWM, ++#endif ++ IOV_AP_ISOLATE, ++#ifdef DHD_L2_FILTER ++ IOV_DHCP_UNICAST, ++ IOV_BLOCK_PING, ++ IOV_PROXY_ARP, ++ IOV_GRAT_ARP, ++#endif /* DHD_L2_FILTER */ ++ IOV_DHD_IE, ++#ifdef DHD_PSTA ++ IOV_PSTA, ++#endif /* DHD_PSTA */ ++#ifdef DHD_WET ++ IOV_WET, ++ IOV_WET_HOST_IPV4, ++ IOV_WET_HOST_MAC, ++#endif /* DHD_WET */ ++ IOV_CFG80211_OPMODE, ++ IOV_ASSERT_TYPE, ++ IOV_LMTEST, ++#ifdef DHD_MCAST_REGEN ++ IOV_MCAST_REGEN_BSS_ENABLE, ++#endif ++#ifdef SHOW_LOGTRACE ++ IOV_DUMP_TRACE_LOG, ++#endif /* SHOW_LOGTRACE */ ++#ifdef REPORT_FATAL_TIMEOUTS ++ IOV_SCAN_TO, ++ IOV_JOIN_TO, ++ IOV_CMD_TO, ++ IOV_OQS_TO, ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ IOV_DONGLE_TRAP_TYPE, ++ IOV_DONGLE_TRAP_INFO, ++ IOV_BPADDR, ++ IOV_LAST, ++#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) ++ IOV_LOG_CAPTURE_ENABLE, ++ IOV_LOG_DUMP ++#endif /* DHD_EFI && DHD_LOG_DUMP */ ++}; ++ ++const bcm_iovar_t dhd_iovars[] = { ++ {"version", IOV_VERSION, 0, 0, IOVT_BUFFER, sizeof(dhd_version) }, ++ {"wlmsglevel", IOV_WLMSGLEVEL, 0, 0, IOVT_UINT32, 0 }, ++#ifdef DHD_DEBUG ++ {"msglevel", IOV_MSGLEVEL, 0, 0, IOVT_UINT32, 0 }, ++ {"mem_debug", IOV_MEM_DEBUG, 0, 0, IOVT_BUFFER, 0 }, ++#endif /* DHD_DEBUG */ ++ {"bcmerrorstr", IOV_BCMERRORSTR, 0, 0, IOVT_BUFFER, BCME_STRLEN }, ++ {"bcmerror", IOV_BCMERROR, 0, 0, IOVT_INT8, 0 }, ++ {"wdtick", IOV_WDTICK, 0, 0, IOVT_UINT32, 0 }, ++ {"dump", IOV_DUMP, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, ++ {"cons", IOV_CONS, 0, 0, IOVT_BUFFER, 0 }, ++ {"dconpoll", IOV_DCONSOLE_POLL, 0, 0, IOVT_UINT32, 0 }, ++ {"clearcounts", IOV_CLEARCOUNTS, 0, 0, IOVT_VOID, 0 }, ++ {"gpioob", IOV_GPIOOB, 0, 0, IOVT_UINT32, 0 }, ++ {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, 0, IOVT_UINT32, 0 }, ++#ifdef PROP_TXSTATUS ++ {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, 0, IOVT_BOOL, 0 }, ++ /* ++ set the proptxtstatus operation mode: ++ 0 - Do not do any proptxtstatus flow control ++ 1 - Use implied credit from a packet status ++ 2 - Use explicit credit ++ */ ++ {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, 0, IOVT_UINT32, 0 }, ++ {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, 0, IOVT_UINT32, 0 }, ++ {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, 0, IOVT_BOOL, 0 }, ++ {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, 0, IOVT_BOOL, 0 }, ++ {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, 0, IOVT_BOOL, 0 }, ++ {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, 0, IOVT_BOOL, 0 }, ++#endif /* PROP_TXSTATUS */ ++ {"bustype", IOV_BUS_TYPE, 0, 0, IOVT_UINT32, 0}, ++#ifdef WLMEDIA_HTSF ++ {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, 0, IOVT_UINT8, 0 }, ++#endif ++ {"changemtu", IOV_CHANGEMTU, 0, 0, IOVT_UINT32, 0 }, ++ {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, 0, IOVT_BUFFER, ++ (WLHOST_REORDERDATA_MAXFLOWS + 1) }, ++#ifdef DHDTCPACK_SUPPRESS ++ {"tcpack_suppress", IOV_TCPACK_SUPPRESS, 0, 0, IOVT_UINT8, 0 }, ++#endif /* DHDTCPACK_SUPPRESS */ ++#ifdef DHD_WMF ++ {"wmf_bss_enable", IOV_WMF_BSS_ENAB, 0, 0, IOVT_BOOL, 0 }, ++ {"wmf_ucast_igmp", IOV_WMF_UCAST_IGMP, 0, 0, IOVT_BOOL, 0 }, ++ {"wmf_mcast_data_sendup", IOV_WMF_MCAST_DATA_SENDUP, 0, 0, IOVT_BOOL, 0 }, ++#ifdef WL_IGMP_UCQUERY ++ {"wmf_ucast_igmp_query", IOV_WMF_UCAST_IGMP_QUERY, (0), 0, IOVT_BOOL, 0 }, ++#endif /* WL_IGMP_UCQUERY */ ++#ifdef DHD_UCAST_UPNP ++ {"wmf_ucast_upnp", IOV_WMF_UCAST_UPNP, (0), 0, IOVT_BOOL, 0 }, ++#endif /* DHD_UCAST_UPNP */ ++ {"wmf_psta_disable", IOV_WMF_PSTA_DISABLE, (0), 0, IOVT_BOOL, 0 }, ++#endif /* DHD_WMF */ ++#if defined(TRAFFIC_MGMT_DWM) ++ {"trf_mgmt_filters_add", IOV_TRAFFIC_MGMT_DWM, (0), 0, IOVT_BUFFER, 0}, ++#endif ++#ifdef DHD_L2_FILTER ++ {"dhcp_unicast", IOV_DHCP_UNICAST, (0), 0, IOVT_BOOL, 0 }, ++#endif /* DHD_L2_FILTER */ ++ {"ap_isolate", IOV_AP_ISOLATE, (0), 0, IOVT_BOOL, 0}, ++#ifdef DHD_L2_FILTER ++ {"block_ping", IOV_BLOCK_PING, (0), 0, IOVT_BOOL, 0}, ++ {"proxy_arp", IOV_PROXY_ARP, (0), 0, IOVT_BOOL, 0}, ++ {"grat_arp", IOV_GRAT_ARP, (0), 0, IOVT_BOOL, 0}, ++#endif /* DHD_L2_FILTER */ ++ {"dhd_ie", IOV_DHD_IE, (0), 0, IOVT_BUFFER, 0}, ++#ifdef DHD_PSTA ++ /* PSTA/PSR Mode configuration. 0: DIABLED 1: PSTA 2: PSR */ ++ {"psta", IOV_PSTA, 0, 0, IOVT_UINT32, 0}, ++#endif /* DHD PSTA */ ++#ifdef DHD_WET ++ /* WET Mode configuration. 0: DIABLED 1: WET */ ++ {"wet", IOV_WET, 0, 0, IOVT_UINT32, 0}, ++ {"wet_host_ipv4", IOV_WET_HOST_IPV4, 0, 0, IOVT_UINT32, 0}, ++ {"wet_host_mac", IOV_WET_HOST_MAC, 0, 0, IOVT_BUFFER, 0}, ++#endif /* DHD WET */ ++ {"op_mode", IOV_CFG80211_OPMODE, 0, 0, IOVT_UINT32, 0 }, ++ {"assert_type", IOV_ASSERT_TYPE, (0), 0, IOVT_UINT32, 0}, ++ {"lmtest", IOV_LMTEST, 0, 0, IOVT_UINT32, 0 }, ++#ifdef DHD_MCAST_REGEN ++ {"mcast_regen_bss_enable", IOV_MCAST_REGEN_BSS_ENABLE, 0, 0, IOVT_BOOL, 0}, ++#endif ++#ifdef SHOW_LOGTRACE ++ {"dump_trace_buf", IOV_DUMP_TRACE_LOG, 0, 0, IOVT_BUFFER, sizeof(trace_buf_info_t) }, ++#endif /* SHOW_LOGTRACE */ ++#ifdef REPORT_FATAL_TIMEOUTS ++ {"scan_timeout", IOV_SCAN_TO, 0, 0, IOVT_UINT32, 0 }, ++ {"join_timeout", IOV_JOIN_TO, 0, 0, IOVT_UINT32, 0 }, ++ {"cmd_timeout", IOV_CMD_TO, 0, 0, IOVT_UINT32, 0 }, ++ {"oqs_timeout", IOV_OQS_TO, 0, 0, IOVT_UINT32, 0 }, ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ {"trap_type", IOV_DONGLE_TRAP_TYPE, 0, 0, IOVT_UINT32, 0 }, ++ {"trap_info", IOV_DONGLE_TRAP_INFO, 0, 0, IOVT_BUFFER, sizeof(trap_t) }, ++#ifdef DHD_DEBUG ++ {"bpaddr", IOV_BPADDR, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++#endif /* DHD_DEBUG */ ++#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) ++ {"log_capture_enable", IOV_LOG_CAPTURE_ENABLE, 0, 0, IOVT_UINT8, 0}, ++ {"log_dump", IOV_LOG_DUMP, 0, 0, IOVT_UINT8, 0}, ++#endif /* DHD_EFI && DHD_LOG_DUMP */ ++ {NULL, 0, 0, 0, 0, 0 } ++}; ++ ++#define DHD_IOVAR_BUF_SIZE 128 ++ ++bool ++dhd_query_bus_erros(dhd_pub_t *dhdp) ++{ ++ bool ret = FALSE; ++ ++ if (dhdp->dongle_reset) { ++ DHD_ERROR(("%s: Dongle Reset occurred, cannot proceed\n", ++ __FUNCTION__)); ++ ret = TRUE; ++ } ++ ++ if (dhdp->dongle_trap_occured) { ++ DHD_ERROR(("%s: FW TRAP has occurred, cannot proceed\n", ++ __FUNCTION__)); ++ ret = TRUE; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ dhdp->hang_reason = HANG_REASON_DONGLE_TRAP; ++ dhd_os_send_hang_message(dhdp); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ ++ } ++ ++ if (dhdp->iovar_timeout_occured) { ++ DHD_ERROR(("%s: Resumed on timeout for previous IOVAR, cannot proceed\n", ++ __FUNCTION__)); ++ ret = TRUE; ++ } ++ ++#ifdef PCIE_FULL_DONGLE ++ if (dhdp->d3ack_timeout_occured) { ++ DHD_ERROR(("%s: Resumed on timeout for previous D3ACK, cannot proceed\n", ++ __FUNCTION__)); ++ ret = TRUE; ++ } ++#endif /* PCIE_FULL_DONGLE */ ++ ++ return ret; ++} ++ ++#ifdef DHD_SSSR_DUMP ++int ++dhd_sssr_mempool_init(dhd_pub_t *dhd) ++{ ++ dhd->sssr_mempool = (uint8 *) MALLOCZ(dhd->osh, DHD_SSSR_MEMPOOL_SIZE); ++ if (dhd->sssr_mempool == NULL) { ++ DHD_ERROR(("%s: MALLOC of sssr_mempool failed\n", ++ __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ return BCME_OK; ++} ++ ++void ++dhd_sssr_mempool_deinit(dhd_pub_t *dhd) ++{ ++ if (dhd->sssr_mempool) { ++ MFREE(dhd->osh, dhd->sssr_mempool, DHD_SSSR_MEMPOOL_SIZE); ++ dhd->sssr_mempool = NULL; ++ } ++} ++ ++int ++dhd_get_sssr_reg_info(dhd_pub_t *dhd) ++{ ++ int ret = BCME_ERROR; ++ ++ DHD_ERROR(("%s: get sssr_reg_info\n", __FUNCTION__)); ++ /* get sssr_reg_info from firmware */ ++ memset((void *)&dhd->sssr_reg_info, 0, sizeof(dhd->sssr_reg_info)); ++ if (bcm_mkiovar("sssr_reg_info", 0, 0, (char *)&dhd->sssr_reg_info, ++ sizeof(dhd->sssr_reg_info))) { ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, &dhd->sssr_reg_info, ++ sizeof(dhd->sssr_reg_info), FALSE, 0)) < 0) { ++ DHD_ERROR(("%s: dhd_wl_ioctl_cmd failed (error=%d)\n", __FUNCTION__, ret)); ++ } ++ } else { ++ DHD_ERROR(("%s: bcm_mkiovar failed\n", __FUNCTION__)); ++ } ++ ++ return ret; ++} ++ ++uint32 ++dhd_get_sssr_bufsize(dhd_pub_t *dhd) ++{ ++ int i; ++ uint32 sssr_bufsize = 0; ++ /* Init all pointers to NULL */ ++ for (i = 0; i < MAX_NUM_D11CORES; i++) { ++ sssr_bufsize += dhd->sssr_reg_info.mac_regs[i].sr_size; ++ } ++ sssr_bufsize += dhd->sssr_reg_info.vasip_regs.vasip_sr_size; ++ ++ /* Double the size as different dumps will be saved before and after SR */ ++ sssr_bufsize = 2 * sssr_bufsize; ++ ++ return sssr_bufsize; ++} ++ ++int ++dhd_sssr_dump_init(dhd_pub_t *dhd) ++{ ++ int i; ++ uint32 sssr_bufsize; ++ uint32 mempool_used = 0; ++ ++ dhd->sssr_inited = FALSE; ++ ++ /* check if sssr mempool is allocated */ ++ if (dhd->sssr_mempool == NULL) { ++ DHD_ERROR(("%s: sssr_mempool is not allocated\n", ++ __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ /* Get SSSR reg info */ ++ if (dhd_get_sssr_reg_info(dhd) != BCME_OK) { ++ DHD_ERROR(("%s: dhd_get_sssr_reg_info failed\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ /* Validate structure version */ ++ if (dhd->sssr_reg_info.version != SSSR_REG_INFO_VER) { ++ DHD_ERROR(("%s: dhd->sssr_reg_info.version (%d : %d) mismatch\n", ++ __FUNCTION__, (int)dhd->sssr_reg_info.version, SSSR_REG_INFO_VER)); ++ return BCME_ERROR; ++ } ++ ++ /* Validate structure length */ ++ if (dhd->sssr_reg_info.length != sizeof(dhd->sssr_reg_info)) { ++ DHD_ERROR(("%s: dhd->sssr_reg_info.length (%d : %d) mismatch\n", ++ __FUNCTION__, (int)dhd->sssr_reg_info.length, ++ (int)sizeof(dhd->sssr_reg_info))); ++ return BCME_ERROR; ++ } ++ ++ /* validate fifo size */ ++ sssr_bufsize = dhd_get_sssr_bufsize(dhd); ++ if (sssr_bufsize > DHD_SSSR_MEMPOOL_SIZE) { ++ DHD_ERROR(("%s: sssr_bufsize(%d) is greater than sssr_mempool(%d)\n", ++ __FUNCTION__, (int)sssr_bufsize, DHD_SSSR_MEMPOOL_SIZE)); ++ return BCME_ERROR; ++ } ++ ++ /* init all pointers to NULL */ ++ for (i = 0; i < MAX_NUM_D11CORES; i++) { ++ dhd->sssr_d11_before[i] = NULL; ++ dhd->sssr_d11_after[i] = NULL; ++ } ++ dhd->sssr_vasip_buf_before = NULL; ++ dhd->sssr_vasip_buf_after = NULL; ++ ++ /* Allocate memory */ ++ for (i = 0; i < MAX_NUM_D11CORES; i++) { ++ if (dhd->sssr_reg_info.mac_regs[i].sr_size) { ++ dhd->sssr_d11_before[i] = (uint32 *)(dhd->sssr_mempool + mempool_used); ++ mempool_used += dhd->sssr_reg_info.mac_regs[i].sr_size; ++ ++ dhd->sssr_d11_after[i] = (uint32 *)(dhd->sssr_mempool + mempool_used); ++ mempool_used += dhd->sssr_reg_info.mac_regs[i].sr_size; ++ } ++ } ++ ++ if (dhd->sssr_reg_info.vasip_regs.vasip_sr_size) { ++ dhd->sssr_vasip_buf_before = (uint32 *)(dhd->sssr_mempool + mempool_used); ++ mempool_used += dhd->sssr_reg_info.vasip_regs.vasip_sr_size; ++ ++ dhd->sssr_vasip_buf_after = (uint32 *)(dhd->sssr_mempool + mempool_used); ++ mempool_used += dhd->sssr_reg_info.vasip_regs.vasip_sr_size; ++ } ++ ++ dhd->sssr_inited = TRUE; ++ ++ return BCME_OK; ++ ++} ++ ++void ++dhd_sssr_dump_deinit(dhd_pub_t *dhd) ++{ ++ int i; ++ ++ dhd->sssr_inited = FALSE; ++ /* init all pointers to NULL */ ++ for (i = 0; i < MAX_NUM_D11CORES; i++) { ++ dhd->sssr_d11_before[i] = NULL; ++ dhd->sssr_d11_after[i] = NULL; ++ } ++ dhd->sssr_vasip_buf_before = NULL; ++ dhd->sssr_vasip_buf_after = NULL; ++ ++ return; ++} ++ ++#endif /* DHD_SSSR_DUMP */ ++ ++#ifdef DHD_FW_COREDUMP ++void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length) ++{ ++ if (!dhd_pub->soc_ram) { ++#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) ++ dhd_pub->soc_ram = (uint8*)DHD_OS_PREALLOC(dhd_pub, ++ DHD_PREALLOC_MEMDUMP_RAM, length); ++#else ++ dhd_pub->soc_ram = (uint8*) MALLOC(dhd_pub->osh, length); ++#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ ++ } ++ ++ if (dhd_pub->soc_ram == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory for fw crash snap shot.\n", ++ __FUNCTION__)); ++ dhd_pub->soc_ram_length = 0; ++ } else { ++ memset(dhd_pub->soc_ram, 0, length); ++ dhd_pub->soc_ram_length = length; ++ } ++ ++ /* soc_ram free handled in dhd_{free,clear} */ ++ return dhd_pub->soc_ram; ++} ++#endif /* DHD_FW_COREDUMP */ ++ ++/* to NDIS developer, the structure dhd_common is redundant, ++ * please do NOT merge it back from other branches !!! ++ */ ++ ++int ++dhd_common_socram_dump(dhd_pub_t *dhdp) ++{ ++#ifdef BCMDBUS ++ return 0; ++#else ++ return dhd_socram_dump(dhdp->bus); ++#endif /* BCMDBUS */ ++} ++ ++static int ++dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) ++{ ++ char eabuf[ETHER_ADDR_STR_LEN]; ++ ++ struct bcmstrbuf b; ++ struct bcmstrbuf *strbuf = &b; ++ ++ if (!dhdp || !dhdp->prot || !buf) { ++ return BCME_ERROR; ++ } ++ ++ bcm_binit(strbuf, buf, buflen); ++ ++ /* Base DHD info */ ++ bcm_bprintf(strbuf, "%s\n", dhd_version); ++ bcm_bprintf(strbuf, "\n"); ++ bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", ++ dhdp->up, dhdp->txoff, dhdp->busstate); ++ bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n", ++ dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); ++ bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", ++ dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); ++ bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt); ++ ++ bcm_bprintf(strbuf, "dongle stats:\n"); ++ bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n", ++ dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, ++ dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); ++ bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n", ++ dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, ++ dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); ++ bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast); ++ ++ bcm_bprintf(strbuf, "bus stats:\n"); ++ bcm_bprintf(strbuf, "tx_packets %lu tx_dropped %lu tx_multicast %lu tx_errors %lu\n", ++ dhdp->tx_packets, dhdp->tx_dropped, dhdp->tx_multicast, dhdp->tx_errors); ++ bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n", ++ dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); ++ bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n", ++ dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); ++ bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n", ++ dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); ++ bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n", ++ dhdp->rx_readahead_cnt, dhdp->tx_realloc); ++ bcm_bprintf(strbuf, "tx_pktgetfail %lu rx_pktgetfail %lu\n", ++ dhdp->tx_pktgetfail, dhdp->rx_pktgetfail); ++ bcm_bprintf(strbuf, "\n"); ++ ++#ifdef DMAMAP_STATS ++ /* Add DMA MAP info */ ++ bcm_bprintf(strbuf, "DMA MAP stats: \n"); ++ bcm_bprintf(strbuf, "txdata: %lu size: %luK, rxdata: %lu size: %luK\n", ++ dhdp->dma_stats.txdata, KB(dhdp->dma_stats.txdata_sz), ++ dhdp->dma_stats.rxdata, KB(dhdp->dma_stats.rxdata_sz)); ++#ifndef IOCTLRESP_USE_CONSTMEM ++ bcm_bprintf(strbuf, "IOCTL RX: %lu size: %luK ,", ++ dhdp->dma_stats.ioctl_rx, KB(dhdp->dma_stats.ioctl_rx_sz)); ++#endif /* !IOCTLRESP_USE_CONSTMEM */ ++ bcm_bprintf(strbuf, "EVENT RX: %lu size: %luK, INFO RX: %lu size: %luK, " ++ "TSBUF RX: %lu size %luK\n", ++ dhdp->dma_stats.event_rx, KB(dhdp->dma_stats.event_rx_sz), ++ dhdp->dma_stats.info_rx, KB(dhdp->dma_stats.info_rx_sz), ++ dhdp->dma_stats.tsbuf_rx, KB(dhdp->dma_stats.tsbuf_rx_sz)); ++ bcm_bprintf(strbuf, "Total : %luK \n", ++ KB(dhdp->dma_stats.txdata_sz + dhdp->dma_stats.rxdata_sz + ++ dhdp->dma_stats.ioctl_rx_sz + dhdp->dma_stats.event_rx_sz + ++ dhdp->dma_stats.tsbuf_rx_sz)); ++#endif /* DMAMAP_STATS */ ++ ++ /* Add any prot info */ ++ dhd_prot_dump(dhdp, strbuf); ++ bcm_bprintf(strbuf, "\n"); ++ ++ /* Add any bus info */ ++ dhd_bus_dump(dhdp, strbuf); ++ ++ ++#if defined(DHD_LB_STATS) ++ dhd_lb_stats_dump(dhdp, strbuf); ++#endif /* DHD_LB_STATS */ ++#ifdef DHD_WET ++ if (dhd_get_wet_mode(dhdp)) { ++ bcm_bprintf(strbuf, "Wet Dump:\n"); ++ dhd_wet_dump(dhdp, strbuf); ++ } ++#endif /* DHD_WET */ ++ return (!strbuf->size ? BCME_BUFTOOSHORT : 0); ++} ++ ++void ++dhd_dump_to_kernelog(dhd_pub_t *dhdp) ++{ ++ char buf[512]; ++ ++ DHD_ERROR(("F/W version: %s\n", fw_version)); ++ bcm_bprintf_bypass = TRUE; ++ dhd_dump(dhdp, buf, sizeof(buf)); ++ bcm_bprintf_bypass = FALSE; ++} ++ ++int ++dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifidx) ++{ ++ wl_ioctl_t ioc; ++ ++ ioc.cmd = cmd; ++ ioc.buf = arg; ++ ioc.len = len; ++ ioc.set = set; ++ ++ return dhd_wl_ioctl(dhd_pub, ifidx, &ioc, arg, len); ++} ++ ++int ++dhd_wl_ioctl_get_intiovar(dhd_pub_t *dhd_pub, char *name, uint *pval, ++ int cmd, uint8 set, int ifidx) ++{ ++ char iovbuf[WLC_IOCTL_SMLEN]; ++ int ret = -1; ++ ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ if (bcm_mkiovar(name, NULL, 0, iovbuf, sizeof(iovbuf))) { ++ ret = dhd_wl_ioctl_cmd(dhd_pub, cmd, iovbuf, sizeof(iovbuf), set, ifidx); ++ if (!ret) { ++ *pval = ltoh32(*((uint*)iovbuf)); ++ } else { ++ DHD_ERROR(("%s: get int iovar %s failed, ERR %d\n", ++ __FUNCTION__, name, ret)); ++ } ++ } else { ++ DHD_ERROR(("%s: mkiovar %s failed\n", ++ __FUNCTION__, name)); ++ } ++ ++ return ret; ++} ++ ++int ++dhd_wl_ioctl_set_intiovar(dhd_pub_t *dhd_pub, char *name, uint val, ++ int cmd, uint8 set, int ifidx) ++{ ++ char iovbuf[WLC_IOCTL_SMLEN] = {0}; ++ int ret = -1; ++ int lval = htol32(val); ++ uint len; ++ ++ len = bcm_mkiovar(name, (char*)&lval, sizeof(lval), iovbuf, sizeof(iovbuf)); ++ ++ if (len) { ++ ret = dhd_wl_ioctl_cmd(dhd_pub, cmd, iovbuf, len, set, ifidx); ++ if (ret) { ++ DHD_ERROR(("%s: set int iovar %s failed, ERR %d\n", ++ __FUNCTION__, name, ret)); ++ } ++ } else { ++ DHD_ERROR(("%s: mkiovar %s failed\n", ++ __FUNCTION__, name)); ++ } ++ ++ return ret; ++} ++ ++int ++dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len) ++{ ++ int ret = BCME_ERROR; ++ unsigned long flags; ++#ifdef DUMP_IOCTL_IOV_LIST ++ dhd_iov_li_t *iov_li; ++#endif /* DUMP_IOCTL_IOV_LIST */ ++ int hostsleep_set = 0; ++ int hostsleep_val = 0; ++ ++#ifdef KEEPIF_ON_DEVICE_RESET ++ if (ioc->cmd == WLC_GET_VAR) { ++ dbus_config_t config; ++ config.general_param = 0; ++ if (!strcmp(buf, "wowl_activate")) { ++ config.general_param = 2; /* 1 (TRUE) after decreased by 1 */ ++ } else if (!strcmp(buf, "wowl_clear")) { ++ config.general_param = 1; /* 0 (FALSE) after decreased by 1 */ ++ } ++ if (config.general_param) { ++ config.config_id = DBUS_CONFIG_ID_KEEPIF_ON_DEVRESET; ++ config.general_param--; ++ dbus_set_config(dhd_pub->dbus, &config); ++ } ++ } ++#endif /* KEEPIF_ON_DEVICE_RESET */ ++ ++ if (dhd_os_proto_block(dhd_pub)) ++ { ++#ifdef DHD_LOG_DUMP ++ int slen, i, val, rem, lval, min_len; ++ char *pval, *pos, *msg; ++ char tmp[64]; ++ ++ /* WLC_GET_VAR */ ++ if (ioc->cmd == WLC_GET_VAR) { ++ min_len = MIN(sizeof(tmp) - 1, strlen(buf)); ++ memset(tmp, 0, sizeof(tmp)); ++ bcopy(buf, tmp, min_len); ++ tmp[min_len] = '\0'; ++ } ++#endif /* DHD_LOG_DUMP */ ++ DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); ++ if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd_pub)) { ++#ifdef DHD_EFI ++ DHD_INFO(("%s: returning as busstate=%d\n", ++ __FUNCTION__, dhd_pub->busstate)); ++#else ++ DHD_ERROR(("%s: returning as busstate=%d\n", ++ __FUNCTION__, dhd_pub->busstate)); ++#endif /* DHD_EFI */ ++ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); ++ dhd_os_proto_unblock(dhd_pub); ++ return -ENODEV; ++ } ++ DHD_BUS_BUSY_SET_IN_IOVAR(dhd_pub); ++ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++ dhdpcie_runtime_bus_wake(dhd_pub, TRUE, dhd_wl_ioctl); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); ++ if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhd_pub)) { ++ DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", ++ __FUNCTION__, dhd_pub->busstate, dhd_pub->dhd_bus_busy_state)); ++ DHD_BUS_BUSY_CLEAR_IN_IOVAR(dhd_pub); ++ dhd_os_busbusy_wake(dhd_pub); ++ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); ++ dhd_os_proto_unblock(dhd_pub); ++ return -ENODEV; ++ } ++ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); ++ ++#if defined(WL_WLC_SHIM) ++ { ++ struct wl_shim_node *shim = dhd_pub_shim(dhd_pub); ++ ++ wl_io_pport_t io_pport; ++ io_pport.dhd_pub = dhd_pub; ++ io_pport.ifidx = ifidx; ++ ++ ret = wl_shim_ioctl(shim, ioc, len, &io_pport); ++ if (ret != BCME_OK) { ++ DHD_TRACE(("%s: wl_shim_ioctl(%d) ERR %d\n", ++ __FUNCTION__, ioc->cmd, ret)); ++ } ++ } ++#else ++#ifdef DUMP_IOCTL_IOV_LIST ++ if (ioc->cmd != WLC_GET_MAGIC && ioc->cmd != WLC_GET_VERSION && buf) { ++ if (!(iov_li = MALLOC(dhd_pub->osh, sizeof(*iov_li)))) { ++ DHD_ERROR(("iovar dump list item allocation Failed\n")); ++ } else { ++ iov_li->cmd = ioc->cmd; ++ bcopy((char *)buf, iov_li->buff, strlen((char *)buf)+1); ++ dhd_iov_li_append(dhd_pub, &dhd_pub->dump_iovlist_head, ++ &iov_li->list); ++ } ++ } ++#endif /* DUMP_IOCTL_IOV_LIST */ ++ if (dhd_conf_check_hostsleep(dhd_pub, ioc->cmd, ioc->buf, len, ++ &hostsleep_set, &hostsleep_val, &ret)) ++ goto exit; ++ ret = dhd_prot_ioctl(dhd_pub, ifidx, ioc, buf, len); ++ dhd_conf_get_hostsleep(dhd_pub, hostsleep_set, hostsleep_val, ret); ++#ifdef DUMP_IOCTL_IOV_LIST ++ if (ret == -ETIMEDOUT) { ++ DHD_ERROR(("Last %d issued commands: Latest one is at bottom.\n", ++ IOV_LIST_MAX_LEN)); ++ dhd_iov_li_print(&dhd_pub->dump_iovlist_head); ++ } ++#endif /* DUMP_IOCTL_IOV_LIST */ ++#endif /* defined(WL_WLC_SHIM) */ ++#ifdef DHD_LOG_DUMP ++ if (ioc->cmd == WLC_GET_VAR || ioc->cmd == WLC_SET_VAR) { ++ lval = 0; ++ slen = strlen(buf) + 1; ++ msg = (char*)buf; ++ if (len >= slen + sizeof(lval)) { ++ if (ioc->cmd == WLC_GET_VAR) { ++ msg = tmp; ++ lval = *(int*)buf; ++ } else { ++ min_len = MIN(ioc->len - slen, sizeof(int)); ++ bcopy((msg + slen), &lval, min_len); ++ } ++ } ++ DHD_ERROR_MEM(("%s: cmd: %d, msg: %s, val: 0x%x, len: %d, set: %d\n", ++ ioc->cmd == WLC_GET_VAR ? "WLC_GET_VAR" : "WLC_SET_VAR", ++ ioc->cmd, msg, lval, ioc->len, ioc->set)); ++ } else { ++ slen = ioc->len; ++ if (buf != NULL) { ++ val = *(int*)buf; ++ pval = (char*)buf; ++ pos = tmp; ++ rem = sizeof(tmp); ++ memset(tmp, 0, sizeof(tmp)); ++ for (i = 0; i < slen; i++) { ++ if (rem <= 3) { ++ /* At least 2 byte required + 1 byte(NULL) */ ++ break; ++ } ++ pos += snprintf(pos, rem, "%02x ", pval[i]); ++ rem = sizeof(tmp) - (int)(pos - tmp); ++ } ++ /* Do not dump for WLC_GET_MAGIC and WLC_GET_VERSION */ ++ if (ioc->cmd != WLC_GET_MAGIC && ioc->cmd != WLC_GET_VERSION) ++ DHD_ERROR_MEM(("WLC_IOCTL: cmd: %d, val: %d(%s), " ++ "len: %d, set: %d\n", ++ ioc->cmd, val, tmp, ioc->len, ioc->set)); ++ } else { ++ DHD_ERROR_MEM(("WLC_IOCTL: cmd: %d, buf is NULL\n", ioc->cmd)); ++ } ++ } ++#endif /* DHD_LOG_DUMP */ ++ if (ret && dhd_pub->up) { ++ /* Send hang event only if dhd_open() was success */ ++ dhd_os_check_hang(dhd_pub, ifidx, ret); ++ } ++ ++ if (ret == -ETIMEDOUT && !dhd_pub->up) { ++ DHD_ERROR(("%s: 'resumed on timeout' error is " ++ "occurred before the interface does not" ++ " bring up\n", __FUNCTION__)); ++ dhd_pub->busstate = DHD_BUS_DOWN; ++ } ++ ++exit: ++ DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); ++ DHD_BUS_BUSY_CLEAR_IN_IOVAR(dhd_pub); ++ dhd_os_busbusy_wake(dhd_pub); ++ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); ++ ++ dhd_os_proto_unblock(dhd_pub); ++ ++ } ++ ++ return ret; ++} ++ ++uint wl_get_port_num(wl_io_pport_t *io_pport) ++{ ++ return 0; ++} ++ ++/* Get bssidx from iovar params ++ * Input: dhd_pub - pointer to dhd_pub_t ++ * params - IOVAR params ++ * Output: idx - BSS index ++ * val - ponter to the IOVAR arguments ++ */ ++static int ++dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, const char *params, uint32 *idx, const char **val) ++{ ++ char *prefix = "bsscfg:"; ++ uint32 bssidx; ++ ++ if (!(strncmp(params, prefix, strlen(prefix)))) { ++ /* per bss setting should be prefixed with 'bsscfg:' */ ++ const char *p = params + strlen(prefix); ++ ++ /* Skip Name */ ++ while (*p != '\0') ++ p++; ++ /* consider null */ ++ p = p + 1; ++ bcopy(p, &bssidx, sizeof(uint32)); ++ /* Get corresponding dhd index */ ++ bssidx = dhd_bssidx2idx(dhd_pub, htod32(bssidx)); ++ ++ if (bssidx >= DHD_MAX_IFS) { ++ DHD_ERROR(("%s Wrong bssidx provided\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ /* skip bss idx */ ++ p += sizeof(uint32); ++ *val = p; ++ *idx = bssidx; ++ } else { ++ DHD_ERROR(("%s: bad parameter for per bss iovar\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ return BCME_OK; ++} ++ ++#if defined(DHD_DEBUG) && defined(BCMDBUS) ++/* USB Device console input function */ ++int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen) ++{ ++ DHD_TRACE(("%s \n", __FUNCTION__)); ++ ++ return dhd_iovar(dhd, 0, "cons", msg, msglen, NULL, 0, TRUE); ++ ++} ++#endif /* DHD_DEBUG && BCMDBUS */ ++ ++#ifdef DHD_DEBUG ++int ++dhd_mem_debug(dhd_pub_t *dhd, char *msg, uint msglen) ++{ ++ unsigned long int_arg = 0; ++ char *p; ++ char *end_ptr = NULL; ++ dhd_dbg_mwli_t *mw_li; ++ dll_t *item, *next; ++ /* check if mwalloc, mwquery or mwfree was supplied arguement with space */ ++ p = bcmstrstr(msg, " "); ++ if (p != NULL) { ++ /* space should be converted to null as separation flag for firmware */ ++ *p = '\0'; ++ /* store the argument in int_arg */ ++ int_arg = bcm_strtoul(p+1, &end_ptr, 10); ++ } ++ ++ if (!p && !strcmp(msg, "query")) { ++ /* lets query the list inetrnally */ ++ if (dll_empty(dll_head_p(&dhd->mw_list_head))) { ++ DHD_ERROR(("memwaste list is empty, call mwalloc < size > to allocate\n")); ++ /* reset the id */ ++ dhd->mw_id = 0; ++ } else { ++ for (item = dll_head_p(&dhd->mw_list_head); ++ !dll_end(&dhd->mw_list_head, item); item = next) { ++ next = dll_next_p(item); ++ mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list); ++ DHD_ERROR(("item: \n", mw_li->id, mw_li->size)); ++ } ++ } ++ } else if (p && end_ptr && (*end_ptr == '\0') && !strcmp(msg, "alloc")) { ++ int32 alloc_handle; ++ /* convert size into KB and append as integer */ ++ *((int32 *)(p+1)) = int_arg*1024; ++ *(p+1+sizeof(int32)) = '\0'; ++ ++ /* recalculated length -> 5 bytes for "alloc" + 4 bytes for size + ++ *1 bytes for null caracter ++ */ ++ msglen = strlen(msg) + sizeof(int32) + 1; ++ if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, msg, msglen, FALSE, 0) < 0) { ++ DHD_ERROR(("IOCTL failed for memdebug alloc\n")); ++ } ++ ++ /* returned allocated handle from dongle, basically address of the allocated unit */ ++ alloc_handle = *((int32 *)msg); ++ ++ /* add a node in the list with tuple */ ++ if (alloc_handle == 0) { ++ DHD_ERROR(("Reuqested size could not be allocated\n")); ++ } else if (!(mw_li = MALLOC(dhd->osh, sizeof(*mw_li)))) { ++ DHD_ERROR(("mw list item allocation Failed\n")); ++ } else { ++ mw_li->id = dhd->mw_id++; ++ mw_li->handle = alloc_handle; ++ mw_li->size = int_arg; ++ /* append the node in the list */ ++ dll_append(&dhd->mw_list_head, &mw_li->list); ++ } ++ } else if (p && end_ptr && (*end_ptr == '\0') && !strcmp(msg, "free")) { ++ /* inform dongle to free wasted chunk */ ++ int handle = 0; ++ int size = 0; ++ for (item = dll_head_p(&dhd->mw_list_head); ++ !dll_end(&dhd->mw_list_head, item); item = next) { ++ next = dll_next_p(item); ++ mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list); ++ ++ if (mw_li->id == (int)int_arg) { ++ handle = mw_li->handle; ++ size = mw_li->size; ++ dll_delete(item); ++ MFREE(dhd->osh, mw_li, sizeof(*mw_li)); ++ } ++ } ++ if (handle) { ++ int len; ++ /* append the free handle and the chunk size in first 8 bytes ++ * after the command and null character ++ */ ++ *((int32 *)(p+1)) = handle; ++ *((int32 *)((p+1)+sizeof(int32))) = size; ++ /* append null as terminator */ ++ *(p+1+2*sizeof(int32)) = '\0'; ++ /* recalculated length -> 4 bytes for "free" + 8 bytes for hadnle and size ++ * + 1 bytes for null caracter ++ */ ++ len = strlen(msg) + 2*sizeof(int32) + 1; ++ /* send iovar to free the chunk */ ++ if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, msg, len, FALSE, 0) < 0) { ++ DHD_ERROR(("IOCTL failed for memdebug free\n")); ++ } ++ } else { ++ DHD_ERROR(("specified id does not exist\n")); ++ } ++ } else { ++ /* for all the wrong argument formats */ ++ return BCME_BADARG; ++ } ++ return 0; ++} ++ ++extern void ++dhd_mw_list_delete(dhd_pub_t *dhd, dll_t *list_head) ++{ ++ dll_t *item; ++ dhd_dbg_mwli_t *mw_li; ++ while (!(dll_empty(list_head))) { ++ item = dll_head_p(list_head); ++ mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list); ++ dll_delete(item); ++ MFREE(dhd->osh, mw_li, sizeof(*mw_li)); ++ } ++} ++#endif /* DHD_DEBUG */ ++ ++#ifdef PKT_STATICS ++extern pkt_statics_t tx_statics; ++extern void dhdsdio_txpktstatics(void); ++#endif ++ ++static int ++dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, ++ void *params, int plen, void *arg, int len, int val_size) ++{ ++ int bcmerror = 0; ++ int32 int_val = 0; ++ uint32 dhd_ver_len, bus_api_rev_len; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) ++ goto exit; ++ ++ if (plen >= (int)sizeof(int_val)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ switch (actionid) { ++ case IOV_GVAL(IOV_VERSION): ++ /* Need to have checked buffer length */ ++ dhd_ver_len = strlen(dhd_version); ++ bus_api_rev_len = strlen(bus_api_revision); ++ if (dhd_ver_len) ++ bcm_strncpy_s((char*)arg, dhd_ver_len, dhd_version, dhd_ver_len); ++ if (bus_api_rev_len) ++ bcm_strncat_s((char*)arg + dhd_ver_len, bus_api_rev_len, bus_api_revision, ++ bus_api_rev_len); ++#ifdef PKT_STATICS ++ memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t)); ++#endif ++ break; ++ ++ case IOV_GVAL(IOV_WLMSGLEVEL): ++ printf("android_msg_level=0x%x\n", android_msg_level); ++ printf("config_msg_level=0x%x\n", config_msg_level); ++#if defined(WL_WIRELESS_EXT) ++ int_val = (int32)iw_msg_level; ++ bcopy(&int_val, arg, val_size); ++ printf("iw_msg_level=0x%x\n", iw_msg_level); ++#endif ++#ifdef WL_CFG80211 ++ int_val = (int32)wl_dbg_level; ++ bcopy(&int_val, arg, val_size); ++ printf("cfg_msg_level=0x%x\n", wl_dbg_level); ++#endif ++ break; ++ ++ case IOV_SVAL(IOV_WLMSGLEVEL): ++ if (int_val & DHD_ANDROID_VAL) { ++ android_msg_level = (uint)(int_val & 0xFFFF); ++ printf("android_msg_level=0x%x\n", android_msg_level); ++ } ++ if (int_val & DHD_CONFIG_VAL) { ++ config_msg_level = (uint)(int_val & 0xFFFF); ++ printf("config_msg_level=0x%x\n", config_msg_level); ++ } ++#if defined(WL_WIRELESS_EXT) ++ if (int_val & DHD_IW_VAL) { ++ iw_msg_level = (uint)(int_val & 0xFFFF); ++ printf("iw_msg_level=0x%x\n", iw_msg_level); ++ } ++#endif ++#ifdef WL_CFG80211 ++ if (int_val & DHD_CFG_VAL) { ++ wl_cfg80211_enable_trace((u32)(int_val & 0xFFFF)); ++ } ++#endif ++ break; ++ ++ case IOV_GVAL(IOV_MSGLEVEL): ++ int_val = (int32)dhd_msg_level; ++ bcopy(&int_val, arg, val_size); ++#ifdef PKT_STATICS ++ dhdsdio_txpktstatics(); ++#endif ++ break; ++ ++ case IOV_SVAL(IOV_MSGLEVEL): ++ dhd_msg_level = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_BCMERRORSTR): ++ bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); ++ ((char *)arg)[BCME_STRLEN - 1] = 0x00; ++ break; ++ ++ case IOV_GVAL(IOV_BCMERROR): ++ int_val = (int32)dhd_pub->bcmerror; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++#ifndef BCMDBUS ++ case IOV_GVAL(IOV_WDTICK): ++ int_val = (int32)dhd_watchdog_ms; ++ bcopy(&int_val, arg, val_size); ++ break; ++#endif /* !BCMDBUS */ ++ ++ case IOV_SVAL(IOV_WDTICK): ++ if (!dhd_pub->up) { ++ bcmerror = BCME_NOTUP; ++ break; ++ } ++ ++ if (CUSTOM_DHD_WATCHDOG_MS == 0 && int_val == 0) { ++ dhd_watchdog_ms = (uint)int_val; ++ } ++ ++ dhd_os_wd_timer(dhd_pub, (uint)int_val); ++ break; ++ ++ case IOV_GVAL(IOV_DUMP): ++ bcmerror = dhd_dump(dhd_pub, arg, len); ++ break; ++ ++#ifndef BCMDBUS ++ case IOV_GVAL(IOV_DCONSOLE_POLL): ++ int_val = (int32)dhd_console_ms; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DCONSOLE_POLL): ++ dhd_console_ms = (uint)int_val; ++ break; ++ ++ case IOV_SVAL(IOV_CONS): ++ if (len > 0) { ++#ifdef CONSOLE_DPC ++ bcmerror = dhd_bus_txcons(dhd_pub, arg, len - 1); ++#else ++ bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); ++#endif ++ } ++ break; ++#endif /* !BCMDBUS */ ++ ++ case IOV_SVAL(IOV_CLEARCOUNTS): ++ dhd_pub->tx_packets = dhd_pub->rx_packets = 0; ++ dhd_pub->tx_errors = dhd_pub->rx_errors = 0; ++ dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; ++ dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; ++ dhd_pub->tx_dropped = 0; ++ dhd_pub->rx_dropped = 0; ++ dhd_pub->tx_pktgetfail = 0; ++ dhd_pub->rx_pktgetfail = 0; ++ dhd_pub->rx_readahead_cnt = 0; ++ dhd_pub->tx_realloc = 0; ++ dhd_pub->wd_dpc_sched = 0; ++ memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); ++ dhd_bus_clearcounts(dhd_pub); ++#ifdef PROP_TXSTATUS ++ /* clear proptxstatus related counters */ ++ dhd_wlfc_clear_counts(dhd_pub); ++#endif /* PROP_TXSTATUS */ ++#if defined(DHD_LB_STATS) ++ DHD_LB_STATS_RESET(dhd_pub); ++#endif /* DHD_LB_STATS */ ++ break; ++ ++ ++ case IOV_GVAL(IOV_IOCTLTIMEOUT): { ++ int_val = (int32)dhd_os_get_ioctl_resp_timeout(); ++ bcopy(&int_val, arg, sizeof(int_val)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_IOCTLTIMEOUT): { ++ if (int_val <= 0) ++ bcmerror = BCME_BADARG; ++ else ++ dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); ++ break; ++ } ++ ++#ifdef PROP_TXSTATUS ++ case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): { ++ bool wlfc_enab = FALSE; ++ bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); ++ if (bcmerror != BCME_OK) ++ goto exit; ++ int_val = wlfc_enab ? 1 : 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): { ++ bool wlfc_enab = FALSE; ++ bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); ++ if (bcmerror != BCME_OK) ++ goto exit; ++ ++ /* wlfc is already set as desired */ ++ if (wlfc_enab == (int_val == 0 ? FALSE : TRUE)) ++ goto exit; ++ ++ if (int_val == TRUE) ++ bcmerror = dhd_wlfc_init(dhd_pub); ++ else ++ bcmerror = dhd_wlfc_deinit(dhd_pub); ++ ++ break; ++ } ++ case IOV_GVAL(IOV_PROPTXSTATUS_MODE): ++ bcmerror = dhd_wlfc_get_mode(dhd_pub, &int_val); ++ if (bcmerror != BCME_OK) ++ goto exit; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_PROPTXSTATUS_MODE): ++ dhd_wlfc_set_mode(dhd_pub, int_val); ++ break; ++ ++ case IOV_GVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): ++ bcmerror = dhd_wlfc_get_module_ignore(dhd_pub, &int_val); ++ if (bcmerror != BCME_OK) ++ goto exit; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): ++ dhd_wlfc_set_module_ignore(dhd_pub, int_val); ++ break; ++ ++ case IOV_GVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): ++ bcmerror = dhd_wlfc_get_credit_ignore(dhd_pub, &int_val); ++ if (bcmerror != BCME_OK) ++ goto exit; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): ++ dhd_wlfc_set_credit_ignore(dhd_pub, int_val); ++ break; ++ ++ case IOV_GVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): ++ bcmerror = dhd_wlfc_get_txstatus_ignore(dhd_pub, &int_val); ++ if (bcmerror != BCME_OK) ++ goto exit; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): ++ dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val); ++ break; ++ ++ case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK): ++ bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val); ++ if (bcmerror != BCME_OK) ++ goto exit; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK): ++ dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val); ++ break; ++ ++#endif /* PROP_TXSTATUS */ ++ ++ case IOV_GVAL(IOV_BUS_TYPE): ++ /* The dhd application queries the driver to check if its usb or sdio. */ ++#ifdef BCMDBUS ++ int_val = BUS_TYPE_USB; ++#endif /* BCMDBUS */ ++#ifdef BCMSDIO ++ int_val = BUS_TYPE_SDIO; ++#endif ++#ifdef PCIE_FULL_DONGLE ++ int_val = BUS_TYPE_PCIE; ++#endif ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ ++#ifdef WLMEDIA_HTSF ++ case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): ++ int_val = dhd_pub->htsfdlystat_sz; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): ++ dhd_pub->htsfdlystat_sz = int_val & 0xff; ++ printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); ++ break; ++#endif ++ case IOV_SVAL(IOV_CHANGEMTU): ++ int_val &= 0xffff; ++ bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); ++ break; ++ ++ case IOV_GVAL(IOV_HOSTREORDER_FLOWS): ++ { ++ uint i = 0; ++ uint8 *ptr = (uint8 *)arg; ++ uint8 count = 0; ++ ++ ptr++; ++ for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { ++ if (dhd_pub->reorder_bufs[i] != NULL) { ++ *ptr = dhd_pub->reorder_bufs[i]->flow_id; ++ ptr++; ++ count++; ++ } ++ } ++ ptr = (uint8 *)arg; ++ *ptr = count; ++ break; ++ } ++#ifdef DHDTCPACK_SUPPRESS ++ case IOV_GVAL(IOV_TCPACK_SUPPRESS): { ++ int_val = (uint32)dhd_pub->tcpack_sup_mode; ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_TCPACK_SUPPRESS): { ++ bcmerror = dhd_tcpack_suppress_set(dhd_pub, (uint8)int_val); ++ break; ++ } ++#endif /* DHDTCPACK_SUPPRESS */ ++#ifdef DHD_WMF ++ case IOV_GVAL(IOV_WMF_BSS_ENAB): { ++ uint32 bssidx; ++ dhd_wmf_t *wmf; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ wmf = dhd_wmf_conf(dhd_pub, bssidx); ++ int_val = wmf->wmf_enable ? 1 :0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_WMF_BSS_ENAB): { ++ /* Enable/Disable WMF */ ++ uint32 bssidx; ++ dhd_wmf_t *wmf; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ ASSERT(val); ++ bcopy(val, &int_val, sizeof(uint32)); ++ wmf = dhd_wmf_conf(dhd_pub, bssidx); ++ if (wmf->wmf_enable == int_val) ++ break; ++ if (int_val) { ++ /* Enable WMF */ ++ if (dhd_wmf_instance_add(dhd_pub, bssidx) != BCME_OK) { ++ DHD_ERROR(("%s: Error in creating WMF instance\n", ++ __FUNCTION__)); ++ break; ++ } ++ if (dhd_wmf_start(dhd_pub, bssidx) != BCME_OK) { ++ DHD_ERROR(("%s: Failed to start WMF\n", __FUNCTION__)); ++ break; ++ } ++ wmf->wmf_enable = TRUE; ++ } else { ++ /* Disable WMF */ ++ wmf->wmf_enable = FALSE; ++ dhd_wmf_stop(dhd_pub, bssidx); ++ dhd_wmf_instance_del(dhd_pub, bssidx); ++ } ++ break; ++ } ++ case IOV_GVAL(IOV_WMF_UCAST_IGMP): ++ int_val = dhd_pub->wmf_ucast_igmp ? 1 : 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ case IOV_SVAL(IOV_WMF_UCAST_IGMP): ++ if (dhd_pub->wmf_ucast_igmp == int_val) ++ break; ++ ++ if (int_val >= OFF && int_val <= ON) ++ dhd_pub->wmf_ucast_igmp = int_val; ++ else ++ bcmerror = BCME_RANGE; ++ break; ++ case IOV_GVAL(IOV_WMF_MCAST_DATA_SENDUP): ++ int_val = dhd_wmf_mcast_data_sendup(dhd_pub, 0, FALSE, FALSE); ++ bcopy(&int_val, arg, val_size); ++ break; ++ case IOV_SVAL(IOV_WMF_MCAST_DATA_SENDUP): ++ dhd_wmf_mcast_data_sendup(dhd_pub, 0, TRUE, int_val); ++ break; ++ ++#ifdef WL_IGMP_UCQUERY ++ case IOV_GVAL(IOV_WMF_UCAST_IGMP_QUERY): ++ int_val = dhd_pub->wmf_ucast_igmp_query ? 1 : 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ case IOV_SVAL(IOV_WMF_UCAST_IGMP_QUERY): ++ if (dhd_pub->wmf_ucast_igmp_query == int_val) ++ break; ++ ++ if (int_val >= OFF && int_val <= ON) ++ dhd_pub->wmf_ucast_igmp_query = int_val; ++ else ++ bcmerror = BCME_RANGE; ++ break; ++#endif /* WL_IGMP_UCQUERY */ ++#ifdef DHD_UCAST_UPNP ++ case IOV_GVAL(IOV_WMF_UCAST_UPNP): ++ int_val = dhd_pub->wmf_ucast_upnp ? 1 : 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ case IOV_SVAL(IOV_WMF_UCAST_UPNP): ++ if (dhd_pub->wmf_ucast_upnp == int_val) ++ break; ++ ++ if (int_val >= OFF && int_val <= ON) ++ dhd_pub->wmf_ucast_upnp = int_val; ++ else ++ bcmerror = BCME_RANGE; ++ break; ++#endif /* DHD_UCAST_UPNP */ ++ ++ case IOV_GVAL(IOV_WMF_PSTA_DISABLE): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ int_val = dhd_get_wmf_psta_disable(dhd_pub, bssidx); ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_WMF_PSTA_DISABLE): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ ASSERT(val); ++ bcopy(val, &int_val, sizeof(uint32)); ++ dhd_set_wmf_psta_disable(dhd_pub, bssidx, int_val); ++ break; ++ } ++#endif /* DHD_WMF */ ++ ++#if defined(TRAFFIC_MGMT_DWM) ++ case IOV_SVAL(IOV_TRAFFIC_MGMT_DWM): { ++ trf_mgmt_filter_list_t *trf_mgmt_filter_list = ++ (trf_mgmt_filter_list_t *)(arg); ++ bcmerror = traffic_mgmt_add_dwm_filter(dhd_pub, trf_mgmt_filter_list, len); ++ } ++ break; ++#endif ++ ++#ifdef DHD_L2_FILTER ++ case IOV_GVAL(IOV_DHCP_UNICAST): { ++ uint32 bssidx; ++ const char *val; ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: IOV_DHCP_UNICAST: bad parameterand name = %s\n", ++ __FUNCTION__, name)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ int_val = dhd_get_dhcp_unicast_status(dhd_pub, bssidx); ++ memcpy(arg, &int_val, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_DHCP_UNICAST): { ++ uint32 bssidx; ++ const char *val; ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: IOV_DHCP_UNICAST: bad parameterand name = %s\n", ++ __FUNCTION__, name)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ memcpy(&int_val, val, sizeof(int_val)); ++ bcmerror = dhd_set_dhcp_unicast_status(dhd_pub, bssidx, int_val ? 1 : 0); ++ break; ++ } ++ case IOV_GVAL(IOV_BLOCK_PING): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: IOV_BLOCK_PING: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ int_val = dhd_get_block_ping_status(dhd_pub, bssidx); ++ memcpy(arg, &int_val, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_BLOCK_PING): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: IOV_BLOCK_PING: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ memcpy(&int_val, val, sizeof(int_val)); ++ bcmerror = dhd_set_block_ping_status(dhd_pub, bssidx, int_val ? 1 : 0); ++ break; ++ } ++ case IOV_GVAL(IOV_PROXY_ARP): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: IOV_PROXY_ARP: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ int_val = dhd_get_parp_status(dhd_pub, bssidx); ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_PROXY_ARP): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: IOV_PROXY_ARP: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ bcopy(val, &int_val, sizeof(int_val)); ++ ++ /* Issue a iovar request to WL to update the proxy arp capability bit ++ * in the Extended Capability IE of beacons/probe responses. ++ */ ++ bcmerror = dhd_iovar(dhd_pub, bssidx, "proxy_arp_advertise", val, sizeof(int_val), ++ NULL, 0, TRUE); ++ if (bcmerror == BCME_OK) { ++ dhd_set_parp_status(dhd_pub, bssidx, int_val ? 1 : 0); ++ } ++ break; ++ } ++ case IOV_GVAL(IOV_GRAT_ARP): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: IOV_GRAT_ARP: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ int_val = dhd_get_grat_arp_status(dhd_pub, bssidx); ++ memcpy(arg, &int_val, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_GRAT_ARP): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: IOV_GRAT_ARP: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ memcpy(&int_val, val, sizeof(int_val)); ++ bcmerror = dhd_set_grat_arp_status(dhd_pub, bssidx, int_val ? 1 : 0); ++ break; ++ } ++#endif /* DHD_L2_FILTER */ ++ case IOV_SVAL(IOV_DHD_IE): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: dhd ie: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ break; ++ } ++ case IOV_GVAL(IOV_AP_ISOLATE): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ int_val = dhd_get_ap_isolate(dhd_pub, bssidx); ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_AP_ISOLATE): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ ASSERT(val); ++ bcopy(val, &int_val, sizeof(uint32)); ++ dhd_set_ap_isolate(dhd_pub, bssidx, int_val); ++ break; ++ } ++#ifdef DHD_PSTA ++ case IOV_GVAL(IOV_PSTA): { ++ int_val = dhd_get_psta_mode(dhd_pub); ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_PSTA): { ++ if (int_val >= DHD_MODE_PSTA_DISABLED && int_val <= DHD_MODE_PSR) { ++ dhd_set_psta_mode(dhd_pub, int_val); ++ } else { ++ bcmerror = BCME_RANGE; ++ } ++ break; ++ } ++#endif /* DHD_PSTA */ ++#ifdef DHD_WET ++ case IOV_GVAL(IOV_WET): ++ int_val = dhd_get_wet_mode(dhd_pub); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_WET): ++ if (int_val == 0 || int_val == 1) { ++ dhd_set_wet_mode(dhd_pub, int_val); ++ /* Delete the WET DB when disabled */ ++ if (!int_val) { ++ dhd_wet_sta_delete_list(dhd_pub); ++ } ++ } else { ++ bcmerror = BCME_RANGE; ++ } ++ break; ++ case IOV_SVAL(IOV_WET_HOST_IPV4): ++ dhd_set_wet_host_ipv4(dhd_pub, params, plen); ++ break; ++ case IOV_SVAL(IOV_WET_HOST_MAC): ++ dhd_set_wet_host_mac(dhd_pub, params, plen); ++ break; ++#endif /* DHD_WET */ ++#ifdef DHD_MCAST_REGEN ++ case IOV_GVAL(IOV_MCAST_REGEN_BSS_ENABLE): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: mcast_regen_bss_enable: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ int_val = dhd_get_mcast_regen_bss_enable(dhd_pub, bssidx); ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_MCAST_REGEN_BSS_ENABLE): { ++ uint32 bssidx; ++ const char *val; ++ ++ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { ++ DHD_ERROR(("%s: mcast_regen_bss_enable: bad parameter\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ break; ++ } ++ ++ ASSERT(val); ++ bcopy(val, &int_val, sizeof(uint32)); ++ dhd_set_mcast_regen_bss_enable(dhd_pub, bssidx, int_val); ++ break; ++ } ++#endif /* DHD_MCAST_REGEN */ ++ ++ case IOV_GVAL(IOV_CFG80211_OPMODE): { ++ int_val = (int32)dhd_pub->op_mode; ++ bcopy(&int_val, arg, sizeof(int_val)); ++ break; ++ } ++ case IOV_SVAL(IOV_CFG80211_OPMODE): { ++ if (int_val <= 0) ++ bcmerror = BCME_BADARG; ++ else ++ dhd_pub->op_mode = int_val; ++ break; ++ } ++ ++ case IOV_GVAL(IOV_ASSERT_TYPE): ++ int_val = g_assert_type; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_ASSERT_TYPE): ++ g_assert_type = (uint32)int_val; ++ break; ++ ++ ++#if !defined(MACOSX_DHD) ++ case IOV_GVAL(IOV_LMTEST): { ++ *(uint32 *)arg = (uint32)lmtest; ++ break; ++ } ++ ++ case IOV_SVAL(IOV_LMTEST): { ++ uint32 val = *(uint32 *)arg; ++ if (val > 50) ++ bcmerror = BCME_BADARG; ++ else { ++ lmtest = (uint)val; ++ DHD_ERROR(("%s: lmtest %s\n", ++ __FUNCTION__, (lmtest == FALSE)? "OFF" : "ON")); ++ } ++ break; ++ } ++#endif ++ ++#ifdef SHOW_LOGTRACE ++ case IOV_GVAL(IOV_DUMP_TRACE_LOG): { ++ trace_buf_info_t *trace_buf_info; ++ ++ trace_buf_info = (trace_buf_info_t *)MALLOC(dhd_pub->osh, ++ sizeof(trace_buf_info_t)); ++ if (trace_buf_info != NULL) { ++ dhd_get_read_buf_ptr(dhd_pub, trace_buf_info); ++ memcpy((void*)arg, (void*)trace_buf_info, sizeof(trace_buf_info_t)); ++ MFREE(dhd_pub->osh, trace_buf_info, sizeof(trace_buf_info_t)); ++ } else { ++ DHD_ERROR(("Memory allocation Failed\n")); ++ bcmerror = BCME_NOMEM; ++ } ++ break; ++ } ++#endif /* SHOW_LOGTRACE */ ++#ifdef REPORT_FATAL_TIMEOUTS ++ case IOV_GVAL(IOV_SCAN_TO): { ++ dhd_get_scan_to_val(dhd_pub, (uint32 *)&int_val); ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_SCAN_TO): { ++ dhd_set_scan_to_val(dhd_pub, (uint32)int_val); ++ break; ++ } ++ case IOV_GVAL(IOV_JOIN_TO): { ++ dhd_get_join_to_val(dhd_pub, (uint32 *)&int_val); ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_JOIN_TO): { ++ dhd_set_join_to_val(dhd_pub, (uint32)int_val); ++ break; ++ } ++ case IOV_GVAL(IOV_CMD_TO): { ++ dhd_get_cmd_to_val(dhd_pub, (uint32 *)&int_val); ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_CMD_TO): { ++ dhd_set_cmd_to_val(dhd_pub, (uint32)int_val); ++ break; ++ } ++ case IOV_GVAL(IOV_OQS_TO): { ++ dhd_get_bus_to_val(dhd_pub, (uint32 *)&int_val); ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ case IOV_SVAL(IOV_OQS_TO): { ++ dhd_set_bus_to_val(dhd_pub, (uint32)int_val); ++ break; ++ } ++#endif /* REPORT_FATAL_TIMEOUTS */ ++#ifdef DHD_DEBUG ++#if defined(BCMSDIO) || defined(BCMPCIE) ++ case IOV_GVAL(IOV_DONGLE_TRAP_TYPE): ++ if (dhd_pub->dongle_trap_occured) ++ int_val = ltoh32(dhd_pub->last_trap_info.type); ++ else ++ int_val = 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_DONGLE_TRAP_INFO): ++ { ++ struct bcmstrbuf strbuf; ++ bcm_binit(&strbuf, arg, len); ++ if (dhd_pub->dongle_trap_occured == FALSE) { ++ bcm_bprintf(&strbuf, "no trap recorded\n"); ++ break; ++ } ++ dhd_bus_dump_trap_info(dhd_pub->bus, &strbuf); ++ break; ++ } ++ ++ case IOV_GVAL(IOV_BPADDR): ++ { ++ sdreg_t sdreg; ++ uint32 addr, size; ++ ++ memcpy(&sdreg, params, sizeof(sdreg)); ++ ++ addr = sdreg.offset; ++ size = sdreg.func; ++ ++ bcmerror = dhd_bus_readwrite_bp_addr(dhd_pub, addr, size, ++ (uint *)&int_val, TRUE); ++ ++ memcpy(arg, &int_val, sizeof(int32)); ++ ++ break; ++ } ++ ++ case IOV_SVAL(IOV_BPADDR): ++ { ++ sdreg_t sdreg; ++ uint32 addr, size; ++ ++ memcpy(&sdreg, params, sizeof(sdreg)); ++ ++ addr = sdreg.offset; ++ size = sdreg.func; ++ ++ bcmerror = dhd_bus_readwrite_bp_addr(dhd_pub, addr, size, ++ (uint *)&sdreg.value, ++ FALSE); ++ ++ break; ++ } ++#endif /* BCMSDIO || BCMPCIE */ ++ case IOV_SVAL(IOV_MEM_DEBUG): ++ if (len > 0) { ++ bcmerror = dhd_mem_debug(dhd_pub, arg, len - 1); ++ } ++ break; ++#endif /* DHD_DEBUG */ ++#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) ++ case IOV_GVAL(IOV_LOG_CAPTURE_ENABLE): ++ { ++ int_val = dhd_pub->log_capture_enable; ++ bcopy(&int_val, arg, val_size); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_LOG_CAPTURE_ENABLE): ++ { ++ dhd_pub->log_capture_enable = (uint8)int_val; ++ break; ++ } ++ ++ case IOV_GVAL(IOV_LOG_DUMP): ++ { ++ dhd_prot_debug_info_print(dhd_pub); ++ dhd_bus_mem_dump(dhd_pub); ++ break; ++ } ++#endif /* DHD_EFI && DHD_LOG_DUMP */ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ ++exit: ++ DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); ++ return bcmerror; ++} ++ ++/* Store the status of a connection attempt for later retrieval by an iovar */ ++void ++dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) ++{ ++ /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID ++ * because an encryption/rsn mismatch results in both events, and ++ * the important information is in the WLC_E_PRUNE. ++ */ ++ if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && ++ dhd_conn_event == WLC_E_PRUNE)) { ++ dhd_conn_event = event; ++ dhd_conn_status = status; ++ dhd_conn_reason = reason; ++ } ++} ++ ++bool ++dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) ++{ ++ void *p; ++ int eprec = -1; /* precedence to evict from */ ++ bool discard_oldest; ++ ++ /* Fast case, precedence queue is not full and we are also not ++ * exceeding total queue length ++ */ ++ if (!pktq_pfull(q, prec) && !pktq_full(q)) { ++ pktq_penq(q, prec, pkt); ++ return TRUE; ++ } ++ ++ /* Determine precedence from which to evict packet, if any */ ++ if (pktq_pfull(q, prec)) ++ eprec = prec; ++ else if (pktq_full(q)) { ++ p = pktq_peek_tail(q, &eprec); ++ ASSERT(p); ++ if (eprec > prec || eprec < 0) ++ return FALSE; ++ } ++ ++ /* Evict if needed */ ++ if (eprec >= 0) { ++ /* Detect queueing to unconfigured precedence */ ++ ASSERT(!pktq_pempty(q, eprec)); ++ discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); ++ if (eprec == prec && !discard_oldest) ++ return FALSE; /* refuse newer (incoming) packet */ ++ /* Evict packet according to discard policy */ ++ p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); ++ ASSERT(p); ++#ifdef DHDTCPACK_SUPPRESS ++ if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { ++ DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", ++ __FUNCTION__, __LINE__)); ++ dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); ++ } ++#endif /* DHDTCPACK_SUPPRESS */ ++ PKTFREE(dhdp->osh, p, TRUE); ++ } ++ ++ /* Enqueue */ ++ p = pktq_penq(q, prec, pkt); ++ ASSERT(p); ++ ++ return TRUE; ++} ++ ++/* ++ * Functions to drop proper pkts from queue: ++ * If one pkt in queue is non-fragmented, drop first non-fragmented pkt only ++ * If all pkts in queue are all fragmented, find and drop one whole set fragmented pkts ++ * If can't find pkts matching upper 2 cases, drop first pkt anyway ++ */ ++bool ++dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn) ++{ ++ struct pktq_prec *q = NULL; ++ void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL, *prev_first = NULL; ++ pkt_frag_t frag_info; ++ ++ ASSERT(dhdp && pq); ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ p = q->head; ++ ++ if (p == NULL) ++ return FALSE; ++ ++ while (p) { ++ frag_info = pkt_frag_info(dhdp->osh, p); ++ if (frag_info == DHD_PKT_FRAG_NONE) { ++ break; ++ } else if (frag_info == DHD_PKT_FRAG_FIRST) { ++ if (first) { ++ /* No last frag pkt, use prev as last */ ++ last = prev; ++ break; ++ } else { ++ first = p; ++ prev_first = prev; ++ } ++ } else if (frag_info == DHD_PKT_FRAG_LAST) { ++ if (first) { ++ last = p; ++ break; ++ } ++ } ++ ++ prev = p; ++ p = PKTLINK(p); ++ } ++ ++ if ((p == NULL) || ((frag_info != DHD_PKT_FRAG_NONE) && !(first && last))) { ++ /* Not found matching pkts, use oldest */ ++ prev = NULL; ++ p = q->head; ++ frag_info = 0; ++ } ++ ++ if (frag_info == DHD_PKT_FRAG_NONE) { ++ first = last = p; ++ prev_first = prev; ++ } ++ ++ p = first; ++ while (p) { ++ next = PKTLINK(p); ++ q->len--; ++ pq->len--; ++ ++ PKTSETLINK(p, NULL); ++ ++ if (fn) ++ fn(dhdp, prec, p, TRUE); ++ ++ if (p == last) ++ break; ++ ++ p = next; ++ } ++ ++ if (prev_first == NULL) { ++ if ((q->head = next) == NULL) ++ q->tail = NULL; ++ } else { ++ PKTSETLINK(prev_first, next); ++ if (!next) ++ q->tail = prev_first; ++ } ++ ++ return TRUE; ++} ++ ++static int ++dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ int bcmerror = 0; ++ int val_size; ++ const bcm_iovar_t *vi = NULL; ++ uint32 actionid; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get MUST have return space */ ++ ASSERT(set || (arg && len)); ++ ++ /* Set does NOT take qualifiers */ ++ ASSERT(!set || (!params && !plen)); ++ ++ if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { ++ bcmerror = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, ++ 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 = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); ++ ++exit: ++ return bcmerror; ++} ++ ++int ++dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen) ++{ ++ int bcmerror = 0; ++ unsigned long flags; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (!buf) { ++ return BCME_BADARG; ++ } ++ ++ dhd_os_dhdiovar_lock(dhd_pub); ++ switch (ioc->cmd) { ++ case DHD_GET_MAGIC: ++ if (buflen < sizeof(int)) ++ bcmerror = BCME_BUFTOOSHORT; ++ else ++ *(int*)buf = DHD_IOCTL_MAGIC; ++ break; ++ ++ case DHD_GET_VERSION: ++ if (buflen < sizeof(int)) ++ bcmerror = BCME_BUFTOOSHORT; ++ else ++ *(int*)buf = DHD_IOCTL_VERSION; ++ break; ++ ++ case DHD_GET_VAR: ++ case DHD_SET_VAR: ++ { ++ char *arg; ++ uint arglen; ++ ++ DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); ++ if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd_pub)) { ++ /* In platforms like FC19, the FW download is done via IOCTL ++ * and should not return error for IOCTLs fired before FW ++ * Download is done ++ */ ++ if (dhd_fw_download_status(dhd_pub)) { ++ DHD_ERROR(("%s: returning as busstate=%d\n", ++ __FUNCTION__, dhd_pub->busstate)); ++ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); ++ dhd_os_dhdiovar_unlock(dhd_pub); ++ return -ENODEV; ++ } ++ } ++ DHD_BUS_BUSY_SET_IN_DHD_IOVAR(dhd_pub); ++ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++ dhdpcie_runtime_bus_wake(dhd_pub, TRUE, dhd_ioctl); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); ++ if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhd_pub)) { ++ /* If Suspend/Resume is tested via pcie_suspend IOVAR ++ * then continue to execute the IOVAR, return from here for ++ * other IOVARs, also include pciecfgreg and devreset to go ++ * through. ++ */ ++#ifdef DHD_EFI ++ if (bcmstricmp((char *)buf, "pcie_suspend") && ++ bcmstricmp((char *)buf, "pciecfgreg") && ++ bcmstricmp((char *)buf, "devreset") && ++ bcmstricmp((char *)buf, "sdio_suspend") && ++ bcmstricmp((char *)buf, "control_signal")) ++#else ++ if (bcmstricmp((char *)buf, "pcie_suspend") && ++ bcmstricmp((char *)buf, "pciecfgreg") && ++ bcmstricmp((char *)buf, "devreset") && ++ bcmstricmp((char *)buf, "sdio_suspend")) ++#endif /* DHD_EFI */ ++ { ++ DHD_ERROR(("%s: bus is in suspend(%d)" ++ "or suspending(0x%x) state\n", ++ __FUNCTION__, dhd_pub->busstate, ++ dhd_pub->dhd_bus_busy_state)); ++ DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub); ++ dhd_os_busbusy_wake(dhd_pub); ++ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); ++ dhd_os_dhdiovar_unlock(dhd_pub); ++ return -ENODEV; ++ } ++ } ++ /* During devreset ioctl, we call dhdpcie_advertise_bus_cleanup, ++ * which will wait for all the busy contexts to get over for ++ * particular time and call ASSERT if timeout happens. As during ++ * devreset ioctal, we made DHD_BUS_BUSY_SET_IN_DHD_IOVAR, ++ * to avoid ASSERT, clear the IOCTL busy state. "devreset" ioctl is ++ * not used in Production platforms but only used in FC19 setups. ++ */ ++ if (!bcmstricmp((char *)buf, "devreset")) { ++ DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub); ++ } ++ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); ++ ++ /* scan past the name to any arguments */ ++ for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) ++ ; ++ ++ if (*arg) { ++ bcmerror = BCME_BUFTOOSHORT; ++ goto unlock_exit; ++ } ++ ++ /* account for the NUL terminator */ ++ arg++, arglen--; ++ /* call with the appropriate arguments */ ++ if (ioc->cmd == DHD_GET_VAR) { ++ bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, ++ buf, buflen, IOV_GET); ++ } else { ++ bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, ++ arg, arglen, IOV_SET); ++ } ++ if (bcmerror != BCME_UNSUPPORTED) { ++ goto unlock_exit; ++ } ++ ++ /* not in generic table, try protocol module */ ++ if (ioc->cmd == DHD_GET_VAR) { ++ bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, ++ arglen, buf, buflen, IOV_GET); ++ } else { ++ bcmerror = dhd_prot_iovar_op(dhd_pub, buf, ++ NULL, 0, arg, arglen, IOV_SET); ++ } ++ if (bcmerror != BCME_UNSUPPORTED) { ++ goto unlock_exit; ++ } ++ ++ /* if still not found, try bus module */ ++ if (ioc->cmd == DHD_GET_VAR) { ++ bcmerror = dhd_bus_iovar_op(dhd_pub, buf, ++ arg, arglen, buf, buflen, IOV_GET); ++ } else { ++ bcmerror = dhd_bus_iovar_op(dhd_pub, buf, ++ NULL, 0, arg, arglen, IOV_SET); ++ } ++ if (bcmerror != BCME_UNSUPPORTED) { ++ goto unlock_exit; ++ } ++ ++#ifdef DHD_TIMESYNC ++ /* check TS module */ ++ if (ioc->cmd == DHD_GET_VAR) ++ bcmerror = dhd_timesync_iovar_op(dhd_pub->ts, buf, arg, ++ arglen, buf, buflen, IOV_GET); ++ else ++ bcmerror = dhd_timesync_iovar_op(dhd_pub->ts, buf, ++ NULL, 0, arg, arglen, IOV_SET); ++#endif /* DHD_TIMESYNC */ ++ } ++ goto unlock_exit; ++ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ } ++ dhd_os_dhdiovar_unlock(dhd_pub); ++ return bcmerror; ++ ++unlock_exit: ++ DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); ++ DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub); ++ dhd_os_busbusy_wake(dhd_pub); ++ DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); ++ dhd_os_dhdiovar_unlock(dhd_pub); ++ return bcmerror; ++} ++ ++#ifdef SHOW_EVENTS ++static void ++wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, ++ void *raw_event_ptr, char *eventmask) ++{ ++ uint i, status, reason; ++ bool group = FALSE, flush_txq = FALSE, link = FALSE; ++ bool host_data = FALSE; /* prints event data after the case when set */ ++ const char *auth_str; ++ const char *event_name; ++ uchar *buf; ++ char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; ++ uint event_type, flags, auth_type, datalen; ++ ++ event_type = ntoh32(event->event_type); ++ flags = ntoh16(event->flags); ++ status = ntoh32(event->status); ++ reason = ntoh32(event->reason); ++ BCM_REFERENCE(reason); ++ auth_type = ntoh32(event->auth_type); ++ datalen = ntoh32(event->datalen); ++ ++ /* debug dump of event messages */ ++ snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x", ++ (uchar)event->addr.octet[0]&0xff, ++ (uchar)event->addr.octet[1]&0xff, ++ (uchar)event->addr.octet[2]&0xff, ++ (uchar)event->addr.octet[3]&0xff, ++ (uchar)event->addr.octet[4]&0xff, ++ (uchar)event->addr.octet[5]&0xff); ++ ++ event_name = bcmevent_get_name(event_type); ++ BCM_REFERENCE(event_name); ++ ++ if (flags & WLC_EVENT_MSG_LINK) ++ link = TRUE; ++ if (flags & WLC_EVENT_MSG_GROUP) ++ group = TRUE; ++ if (flags & WLC_EVENT_MSG_FLUSHTXQ) ++ flush_txq = TRUE; ++ ++ switch (event_type) { ++ case WLC_E_START: ++ case WLC_E_DEAUTH: ++ case WLC_E_DISASSOC: ++ DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); ++ break; ++ ++ case WLC_E_ASSOC_IND: ++ case WLC_E_REASSOC_IND: ++ ++ DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); ++ break; ++ ++ case WLC_E_ASSOC: ++ case WLC_E_REASSOC: ++ if (status == WLC_E_STATUS_SUCCESS) { ++ DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf)); ++ } else if (status == WLC_E_STATUS_TIMEOUT) { ++ DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf)); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", ++ event_name, eabuf, (int)reason)); ++ } else { ++ DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n", ++ event_name, eabuf, (int)status)); ++ } ++ break; ++ ++ case WLC_E_DEAUTH_IND: ++ case WLC_E_DISASSOC_IND: ++ DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); ++ break; ++ ++ case WLC_E_AUTH: ++ case WLC_E_AUTH_IND: ++ if (auth_type == DOT11_OPEN_SYSTEM) ++ auth_str = "Open System"; ++ else if (auth_type == DOT11_SHARED_KEY) ++ auth_str = "Shared Key"; ++ else { ++ snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type); ++ auth_str = err_msg; ++ } ++ ++ if (event_type == WLC_E_AUTH_IND) { ++ DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str)); ++ } else if (status == WLC_E_STATUS_SUCCESS) { ++ DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", ++ event_name, eabuf, auth_str)); ++ } else if (status == WLC_E_STATUS_TIMEOUT) { ++ DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", ++ event_name, eabuf, auth_str)); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", ++ event_name, eabuf, auth_str, (int)reason)); ++ } ++ BCM_REFERENCE(auth_str); ++ ++ break; ++ ++ case WLC_E_JOIN: ++ case WLC_E_ROAM: ++ case WLC_E_SET_SSID: ++ if (status == WLC_E_STATUS_SUCCESS) { ++ DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); ++#ifdef REPORT_FATAL_TIMEOUTS ++ dhd_clear_join_error(dhd_pub, WLC_SSID_MASK); ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ } else { ++#ifdef REPORT_FATAL_TIMEOUTS ++ dhd_set_join_error(dhd_pub, WLC_SSID_MASK); ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ if (status == WLC_E_STATUS_FAIL) { ++ DHD_EVENT(("MACEVENT: %s, failed\n", event_name)); ++ } else if (status == WLC_E_STATUS_NO_NETWORKS) { ++ DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name)); ++ } else { ++ DHD_EVENT(("MACEVENT: %s, unexpected status %d\n", ++ event_name, (int)status)); ++ } ++ } ++ break; ++ ++ case WLC_E_BEACON_RX: ++ if (status == WLC_E_STATUS_SUCCESS) { ++ DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); ++ } else if (status == WLC_E_STATUS_FAIL) { ++ DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name)); ++ } else { ++ DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status)); ++ } ++ break; ++ ++ case WLC_E_LINK: ++ DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN")); ++ BCM_REFERENCE(link); ++ break; ++ ++ case WLC_E_MIC_ERROR: ++ DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", ++ event_name, eabuf, group, flush_txq)); ++ BCM_REFERENCE(group); ++ BCM_REFERENCE(flush_txq); ++ break; ++ ++ case WLC_E_ICV_ERROR: ++ case WLC_E_UNICAST_DECODE_ERROR: ++ case WLC_E_MULTICAST_DECODE_ERROR: ++ DHD_EVENT(("MACEVENT: %s, MAC %s\n", ++ event_name, eabuf)); ++ break; ++ ++ case WLC_E_TXFAIL: ++ DHD_EVENT(("MACEVENT: %s, RA %s status %d\n", event_name, eabuf, status)); ++ break; ++ ++ case WLC_E_ASSOC_REQ_IE: ++ case WLC_E_ASSOC_RESP_IE: ++ case WLC_E_PMKID_CACHE: ++ DHD_EVENT(("MACEVENT: %s\n", event_name)); ++ break; ++ ++ case WLC_E_SCAN_COMPLETE: ++ DHD_EVENT(("MACEVENT: %s\n", event_name)); ++#ifdef REPORT_FATAL_TIMEOUTS ++ dhd_stop_scan_timer(dhd_pub); ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ break; ++ case WLC_E_RSSI_LQM: ++ case WLC_E_PFN_NET_FOUND: ++ case WLC_E_PFN_NET_LOST: ++ case WLC_E_PFN_SCAN_COMPLETE: ++ case WLC_E_PFN_SCAN_NONE: ++ case WLC_E_PFN_SCAN_ALLGONE: ++ case WLC_E_PFN_GSCAN_FULL_RESULT: ++ case WLC_E_PFN_SSID_EXT: ++ DHD_EVENT(("PNOEVENT: %s\n", event_name)); ++ break; ++ ++ case WLC_E_PSK_SUP: ++ case WLC_E_PRUNE: ++ DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", ++ event_name, (int)status, (int)reason)); ++#ifdef REPORT_FATAL_TIMEOUTS ++ if ((status == WLC_E_STATUS_SUCCESS || status == WLC_E_STATUS_UNSOLICITED) && ++ (reason == WLC_E_SUP_OTHER)) { ++ dhd_clear_join_error(dhd_pub, WLC_WPA_MASK); ++ } else { ++ dhd_set_join_error(dhd_pub, WLC_WPA_MASK); ++ } ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ break; ++ ++#ifdef WIFI_ACT_FRAME ++ case WLC_E_ACTION_FRAME: ++ DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf)); ++ break; ++#endif /* WIFI_ACT_FRAME */ ++ ++#ifdef SHOW_LOGTRACE ++ case WLC_E_TRACE: ++ DHD_EVENT(("MACEVENT: %s Logtrace\n", event_name)); ++ dhd_dbg_trace_evnt_handler(dhd_pub, event_data, raw_event_ptr, datalen); ++ break; ++#endif /* SHOW_LOGTRACE */ ++ ++ case WLC_E_RSSI: ++ DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); ++ break; ++ ++ case WLC_E_SERVICE_FOUND: ++ case WLC_E_P2PO_ADD_DEVICE: ++ case WLC_E_P2PO_DEL_DEVICE: ++ DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); ++ break; ++ ++#ifdef BT_WIFI_HANDOBER ++ case WLC_E_BT_WIFI_HANDOVER_REQ: ++ DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); ++ break; ++#endif ++ ++ case WLC_E_CCA_CHAN_QUAL: ++ if (datalen) { ++ buf = (uchar *) event_data; ++ DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d, " ++ "channel 0x%02x \n", event_name, event_type, eabuf, (int)status, ++ (int)reason, (int)auth_type, *(buf + 4))); ++ } ++ break; ++ case WLC_E_ESCAN_RESULT: ++ { ++ DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d \n", ++ event_name, event_type, eabuf, (int)status)); ++ } ++ break; ++ case WLC_E_PSK_AUTH: ++ DHD_EVENT(("MACEVENT: %s, RA %s status %d Reason:%d\n", ++ event_name, eabuf, status, reason)); ++ break; ++ case WLC_E_IF: ++ { ++ struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data; ++ BCM_REFERENCE(ifevent); ++ ++ DHD_EVENT(("MACEVENT: %s, opcode:0x%d ifidx:%d\n", ++ event_name, ifevent->opcode, ifevent->ifidx)); ++ break; ++ } ++ ++#ifdef SHOW_LOGTRACE ++ case WLC_E_MSCH: ++ { ++ wl_mschdbg_event_handler(dhd_pub, raw_event_ptr, reason, event_data, datalen); ++ break; ++ } ++#endif /* SHOW_LOGTRACE */ ++ ++ default: ++ DHD_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 message level is set to bytes or host_data is set */ ++ if ((DHD_BYTES_ON() || (host_data == TRUE)) && DHD_EVENT_ON() && datalen) { ++ buf = (uchar *) event_data; ++ BCM_REFERENCE(buf); ++ DHD_EVENT((" data (%d) : ", datalen)); ++ for (i = 0; i < datalen; i++) { ++ DHD_EVENT((" 0x%02x ", buf[i])); ++ } ++ DHD_EVENT(("\n")); ++ } ++} ++#endif /* SHOW_EVENTS */ ++ ++#ifdef DNGL_EVENT_SUPPORT ++/* Check whether packet is a BRCM dngl event pkt. If it is, process event data. */ ++int ++dngl_host_event(dhd_pub_t *dhdp, void *pktdata, bcm_dngl_event_msg_t *dngl_event, size_t pktlen) ++{ ++ bcm_dngl_event_t *pvt_data = (bcm_dngl_event_t *)pktdata; ++ ++ dngl_host_event_process(dhdp, pvt_data, dngl_event, pktlen); ++ return BCME_OK; ++} ++ ++void ++dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, ++ bcm_dngl_event_msg_t *dngl_event, size_t pktlen) ++{ ++ uint8 *p = (uint8 *)(event + 1); ++ uint16 type = ntoh16_ua((void *)&dngl_event->event_type); ++ uint16 datalen = ntoh16_ua((void *)&dngl_event->datalen); ++ uint16 version = ntoh16_ua((void *)&dngl_event->version); ++ ++ DHD_EVENT(("VERSION:%d, EVENT TYPE:%d, DATALEN:%d\n", version, type, datalen)); ++ if (datalen > (pktlen - sizeof(bcm_dngl_event_t) + ETHER_TYPE_LEN)) { ++ return; ++ } ++ if (version != BCM_DNGL_EVENT_MSG_VERSION) { ++ DHD_ERROR(("%s:version mismatch:%d:%d\n", __FUNCTION__, ++ version, BCM_DNGL_EVENT_MSG_VERSION)); ++ return; ++ } ++ switch (type) { ++ case DNGL_E_SOCRAM_IND: ++ { ++ bcm_dngl_socramind_t *socramind_ptr = (bcm_dngl_socramind_t *)p; ++ uint16 tag = ltoh32(socramind_ptr->tag); ++ uint16 taglen = ltoh32(socramind_ptr->length); ++ p = (uint8 *)socramind_ptr->value; ++ DHD_EVENT(("Tag:%d Len:%d Datalen:%d\n", tag, taglen, datalen)); ++ switch (tag) { ++ case SOCRAM_IND_ASSERT_TAG: ++ { ++ /* ++ * The payload consists of - ++ * null terminated function name padded till 32 bit boundary + ++ * Line number - (32 bits) ++ * Caller address (32 bits) ++ */ ++ char *fnname = (char *)p; ++ if (datalen < (ROUNDUP(strlen(fnname) + 1, sizeof(uint32)) + ++ sizeof(uint32) * 2)) { ++ DHD_ERROR(("Wrong length:%d\n", datalen)); ++ return; ++ } ++ DHD_EVENT(("ASSRT Function:%s ", p)); ++ p += ROUNDUP(strlen(p) + 1, sizeof(uint32)); ++ DHD_EVENT(("Line:%d ", *(uint32 *)p)); ++ p += sizeof(uint32); ++ DHD_EVENT(("Caller Addr:0x%x\n", *(uint32 *)p)); ++ break; ++ } ++ case SOCRAM_IND_TAG_HEALTH_CHECK: ++ { ++ bcm_dngl_healthcheck_t *dngl_hc = (bcm_dngl_healthcheck_t *)p; ++ DHD_EVENT(("SOCRAM_IND_HEALTHCHECK_TAG:%d Len:%d\n", ++ ltoh32(dngl_hc->top_module_tag), ltoh32(dngl_hc->top_module_len))); ++ if (DHD_EVENT_ON()) { ++ prhex("HEALTHCHECK", p, ltoh32(dngl_hc->top_module_len)); ++ } ++ p = (uint8 *)dngl_hc->value; ++ ++ switch (ltoh32(dngl_hc->top_module_tag)) { ++ case HEALTH_CHECK_TOP_LEVEL_MODULE_PCIEDEV_RTE: ++ { ++ bcm_dngl_pcie_hc_t *pcie_hc; ++ pcie_hc = (bcm_dngl_pcie_hc_t *)p; ++ BCM_REFERENCE(pcie_hc); ++ if (ltoh32(dngl_hc->top_module_len) < ++ sizeof(bcm_dngl_pcie_hc_t)) { ++ DHD_ERROR(("Wrong length:%d\n", ++ ltoh32(dngl_hc->top_module_len))); ++ return; ++ } ++ DHD_EVENT(("%d:PCIE HC error:%d flag:0x%x," ++ " control:0x%x\n", ++ ltoh32(pcie_hc->version), ++ ltoh32(pcie_hc->pcie_err_ind_type), ++ ltoh32(pcie_hc->pcie_flag), ++ ltoh32(pcie_hc->pcie_control_reg))); ++ break; ++ } ++ default: ++ DHD_ERROR(("%s:Unknown module TAG:%d\n", ++ __FUNCTION__, ++ ltoh32(dngl_hc->top_module_tag))); ++ break; ++ } ++ break; ++ } ++ default: ++ DHD_ERROR(("%s:Unknown TAG", __FUNCTION__)); ++ if (p && DHD_EVENT_ON()) { ++ prhex("SOCRAMIND", p, taglen); ++ } ++ break; ++ } ++ break; ++ } ++ default: ++ DHD_ERROR(("%s:Unknown DNGL Event Type:%d", __FUNCTION__, type)); ++ if (p && DHD_EVENT_ON()) { ++ prhex("SOCRAMIND", p, datalen); ++ } ++ break; ++ } ++#ifdef DHD_FW_COREDUMP ++ dhdp->memdump_type = DUMP_TYPE_DONGLE_HOST_EVENT; ++#endif /* DHD_FW_COREDUMP */ ++#ifndef BCMDBUS ++ if (dhd_socram_dump(dhdp->bus)) { ++ DHD_ERROR(("%s: socram dump failed\n", __FUNCTION__)); ++ } else { ++ /* Notify framework */ ++ dhd_dbg_send_urgent_evt(dhdp, p, datalen); ++ } ++#endif /* !BCMDBUS */ ++} ++#endif /* DNGL_EVENT_SUPPORT */ ++ ++/* Stub for now. Will become real function as soon as shim ++ * is being integrated to Android, Linux etc. ++ */ ++int ++wl_event_process_default(wl_event_msg_t *event, struct wl_evt_pport *evt_pport) ++{ ++ return BCME_OK; ++} ++ ++int ++wl_event_process(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, ++ uint pktlen, void **data_ptr, void *raw_event) ++{ ++ wl_evt_pport_t evt_pport; ++ wl_event_msg_t event; ++ bcm_event_msg_u_t evu; ++ int ret; ++ ++ /* make sure it is a BRCM event pkt and record event data */ ++ ret = wl_host_event_get_data(pktdata, pktlen, &evu); ++ if (ret != BCME_OK) { ++ return ret; ++ } ++ ++ memcpy(&event, &evu.event, sizeof(wl_event_msg_t)); ++ ++ /* convert event from network order to host order */ ++ wl_event_to_host_order(&event); ++ ++ /* record event params to evt_pport */ ++ evt_pport.dhd_pub = dhd_pub; ++ evt_pport.ifidx = ifidx; ++ evt_pport.pktdata = pktdata; ++ evt_pport.data_ptr = data_ptr; ++ evt_pport.raw_event = raw_event; ++ evt_pport.data_len = pktlen; ++ ++#if defined(WL_WLC_SHIM) && defined(WL_WLC_SHIM_EVENTS) ++ { ++ struct wl_shim_node *shim = dhd_pub_shim(dhd_pub); ++ if (shim) { ++ ret = wl_shim_event_process(shim, &event, &evt_pport); ++ } else { ++ /* events can come even before shim is initialized ++ (when waiting for "wlc_ver" response) ++ * handle them in a non-shim way. ++ */ ++ DHD_ERROR(("%s: Events coming before shim initialization!\n", ++ __FUNCTION__)); ++ ret = wl_event_process_default(&event, &evt_pport); ++ } ++ } ++#else ++ ret = wl_event_process_default(&event, &evt_pport); ++#endif /* WL_WLC_SHIM && WL_WLC_SHIM_EVENTS */ ++ ++ return ret; ++} ++ ++/* Check whether packet is a BRCM event pkt. If it is, record event data. */ ++int ++wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu) ++{ ++ int ret; ++ ++ ret = is_wlc_event_frame(pktdata, pktlen, 0, evu); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s: Invalid event frame, err = %d\n", ++ __FUNCTION__, ret)); ++ } ++ ++ return ret; ++} ++ ++int ++wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen, ++ wl_event_msg_t *event, void **data_ptr, void *raw_event) ++{ ++ bcm_event_t *pvt_data = (bcm_event_t *)pktdata; ++ bcm_event_msg_u_t evu; ++ uint8 *event_data; ++ uint32 type, status, datalen; ++ uint16 flags; ++ uint evlen; ++ int ret; ++ uint16 usr_subtype; ++ char macstr[ETHER_ADDR_STR_LEN]; ++ ++ BCM_REFERENCE(macstr); ++ ++ ret = wl_host_event_get_data(pktdata, pktlen, &evu); ++ if (ret != BCME_OK) { ++ return ret; ++ } ++ ++ usr_subtype = ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype); ++ switch (usr_subtype) { ++ case BCMILCP_BCM_SUBTYPE_EVENT: ++ memcpy(event, &evu.event, sizeof(wl_event_msg_t)); ++ *data_ptr = &pvt_data[1]; ++ break; ++ case BCMILCP_BCM_SUBTYPE_DNGLEVENT: ++#ifdef DNGL_EVENT_SUPPORT ++ /* If it is a DNGL event process it first */ ++ if (dngl_host_event(dhd_pub, pktdata, &evu.dngl_event, pktlen) == BCME_OK) { ++ /* ++ * Return error purposely to prevent DNGL event being processed ++ * as BRCM event ++ */ ++ return BCME_ERROR; ++ } ++#endif /* DNGL_EVENT_SUPPORT */ ++ return BCME_NOTFOUND; ++ default: ++ return BCME_NOTFOUND; ++ } ++ ++ /* start wl_event_msg process */ ++ event_data = *data_ptr; ++ type = ntoh32_ua((void *)&event->event_type); ++ flags = ntoh16_ua((void *)&event->flags); ++ status = ntoh32_ua((void *)&event->status); ++ datalen = ntoh32_ua((void *)&event->datalen); ++ evlen = datalen + sizeof(bcm_event_t); ++ ++ switch (type) { ++#ifdef PROP_TXSTATUS ++ case WLC_E_FIFO_CREDIT_MAP: ++ dhd_wlfc_enable(dhd_pub); ++ dhd_wlfc_FIFOcreditmap_event(dhd_pub, event_data); ++ WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " ++ "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], ++ event_data[2], ++ event_data[3], event_data[4], event_data[5])); ++ break; ++ ++ case WLC_E_BCMC_CREDIT_SUPPORT: ++ dhd_wlfc_BCMCCredit_support_event(dhd_pub); ++ break; ++#ifdef LIMIT_BORROW ++ case WLC_E_ALLOW_CREDIT_BORROW: ++ dhd_wlfc_disable_credit_borrow_event(dhd_pub, event_data); ++ break; ++#endif /* LIMIT_BORROW */ ++#endif /* PROP_TXSTATUS */ ++ ++ ++ case WLC_E_ULP: ++#ifdef DHD_ULP ++ { ++ wl_ulp_event_t *ulp_evt = (wl_ulp_event_t *)event_data; ++ ++ /* Flush and disable console messages */ ++ if (ulp_evt->ulp_dongle_action == WL_ULP_DISABLE_CONSOLE) { ++#ifdef DHD_ULP_NOT_USED ++ dhd_bus_ulp_disable_console(dhd_pub); ++#endif /* DHD_ULP_NOT_USED */ ++ } ++ if (ulp_evt->ulp_dongle_action == WL_ULP_UCODE_DOWNLOAD) { ++ dhd_bus_ucode_download(dhd_pub->bus); ++ } ++ } ++#endif /* DHD_ULP */ ++ break; ++ case WLC_E_TDLS_PEER_EVENT: ++#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) ++ { ++ dhd_tdls_event_handler(dhd_pub, event); ++ } ++#endif ++ break; ++ ++ case WLC_E_IF: ++ { ++ struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data; ++ ++ /* Ignore the event if NOIF is set */ ++ if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) { ++ DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n")); ++ return (BCME_UNSUPPORTED); ++ } ++#ifdef PCIE_FULL_DONGLE ++ dhd_update_interface_flow_info(dhd_pub, ifevent->ifidx, ++ ifevent->opcode, ifevent->role); ++#endif ++#ifdef PROP_TXSTATUS ++ { ++ uint8* ea = pvt_data->eth.ether_dhost; ++ WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " ++ "[%02x:%02x:%02x:%02x:%02x:%02x]\n", ++ ifevent->ifidx, ++ ((ifevent->opcode == WLC_E_IF_ADD) ? "ADD":"DEL"), ++ ((ifevent->role == 0) ? "STA":"AP "), ++ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); ++ (void)ea; ++ ++ if (ifevent->opcode == WLC_E_IF_CHANGE) ++ dhd_wlfc_interface_event(dhd_pub, ++ eWLFC_MAC_ENTRY_ACTION_UPDATE, ++ ifevent->ifidx, ifevent->role, ea); ++ else ++ dhd_wlfc_interface_event(dhd_pub, ++ ((ifevent->opcode == WLC_E_IF_ADD) ? ++ eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), ++ ifevent->ifidx, ifevent->role, ea); ++ ++ /* dhd already has created an interface by default, for 0 */ ++ if (ifevent->ifidx == 0) ++ break; ++ } ++#endif /* PROP_TXSTATUS */ ++ ++ if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { ++ if (ifevent->opcode == WLC_E_IF_ADD) { ++ if (dhd_event_ifadd(dhd_pub->info, ifevent, event->ifname, ++ event->addr.octet)) { ++ ++ DHD_ERROR(("%s: dhd_event_ifadd failed ifidx: %d %s\n", ++ __FUNCTION__, ifevent->ifidx, event->ifname)); ++ return (BCME_ERROR); ++ } ++ } else if (ifevent->opcode == WLC_E_IF_DEL) { ++#ifdef PCIE_FULL_DONGLE ++ /* Delete flowrings unconditionally for i/f delete */ ++ dhd_flow_rings_delete(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info, ++ event->ifname)); ++#endif /* PCIE_FULL_DONGLE */ ++ dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname, ++ event->addr.octet); ++ /* Return ifidx (for vitual i/f, it will be > 0) ++ * so that no other operations on deleted interface ++ * are carried out ++ */ ++ ret = ifevent->ifidx; ++ goto exit; ++ } else if (ifevent->opcode == WLC_E_IF_CHANGE) { ++#ifdef WL_CFG80211 ++ dhd_event_ifchange(dhd_pub->info, ifevent, event->ifname, ++ event->addr.octet); ++#endif /* WL_CFG80211 */ ++ } ++ } else { ++#if !defined(PROP_TXSTATUS) && !defined(PCIE_FULL_DONGLE) && defined(WL_CFG80211) ++ DHD_INFO(("%s: Invalid ifidx %d for %s\n", ++ __FUNCTION__, ifevent->ifidx, event->ifname)); ++#endif /* !PROP_TXSTATUS && !PCIE_FULL_DONGLE && WL_CFG80211 */ ++ } ++ /* send up the if event: btamp user needs it */ ++ *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); ++ /* push up to external supp/auth */ ++ dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); ++ break; ++ } ++ ++#ifdef WLMEDIA_HTSF ++ case WLC_E_HTSFSYNC: ++ htsf_update(dhd_pub->info, event_data); ++ break; ++#endif /* WLMEDIA_HTSF */ ++ case WLC_E_NDIS_LINK: ++ break; ++ case WLC_E_PFN_NET_FOUND: ++ case WLC_E_PFN_SCAN_ALLGONE: /* share with WLC_E_PFN_BSSID_NET_LOST */ ++ case WLC_E_PFN_NET_LOST: ++ break; ++#if defined(PNO_SUPPORT) ++ case WLC_E_PFN_BSSID_NET_FOUND: ++ case WLC_E_PFN_BEST_BATCHING: ++ dhd_pno_event_handler(dhd_pub, event, (void *)event_data); ++ break; ++#endif ++#if defined(RTT_SUPPORT) ++ case WLC_E_PROXD: ++ dhd_rtt_event_handler(dhd_pub, event, (void *)event_data); ++ break; ++#endif /* RTT_SUPPORT */ ++ /* These are what external supplicant/authenticator wants */ ++ case WLC_E_ASSOC_IND: ++ case WLC_E_AUTH_IND: ++ case WLC_E_REASSOC_IND: ++ dhd_findadd_sta(dhd_pub, ++ dhd_ifname2idx(dhd_pub->info, event->ifname), ++ &event->addr.octet); ++ break; ++#ifndef BCMDBUS ++#if defined(DHD_FW_COREDUMP) ++ case WLC_E_PSM_WATCHDOG: ++ DHD_ERROR(("%s: WLC_E_PSM_WATCHDOG event received : \n", __FUNCTION__)); ++ if (dhd_socram_dump(dhd_pub->bus) != BCME_OK) { ++ DHD_ERROR(("%s: socram dump ERROR : \n", __FUNCTION__)); ++ } ++ break; ++#endif ++#endif /* !BCMDBUS */ ++#ifdef DHD_WMF ++ case WLC_E_PSTA_PRIMARY_INTF_IND: ++ dhd_update_psta_interface_for_sta(dhd_pub, event->ifname, ++ (void *)(event->addr.octet), (void*) event_data); ++ break; ++#endif ++ case WLC_E_LINK: ++#ifdef PCIE_FULL_DONGLE ++ DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", ++ __FUNCTION__, type, flags, status)); ++ if (dhd_update_interface_link_status(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info, ++ event->ifname), (uint8)flags) != BCME_OK) { ++ DHD_ERROR(("%s: dhd_update_interface_link_status Failed.\n", ++ __FUNCTION__)); ++ break; ++ } ++ if (!flags) { ++ DHD_ERROR(("%s: Deleting all STA from assoc list and flowrings.\n", ++ __FUNCTION__)); ++ /* Delete all sta and flowrings */ ++ dhd_del_all_sta(dhd_pub, dhd_ifname2idx(dhd_pub->info, event->ifname)); ++ dhd_flow_rings_delete(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info, ++ event->ifname)); ++ } ++ /* fall through */ ++#endif /* PCIE_FULL_DONGLE */ ++ case WLC_E_DEAUTH: ++ case WLC_E_DEAUTH_IND: ++ case WLC_E_DISASSOC: ++ case WLC_E_DISASSOC_IND: ++#ifdef PCIE_FULL_DONGLE ++ if (type != WLC_E_LINK) { ++ uint8 ifindex = (uint8)dhd_ifname2idx(dhd_pub->info, event->ifname); ++ uint8 role = dhd_flow_rings_ifindex2role(dhd_pub, ifindex); ++ uint8 del_sta = TRUE; ++#ifdef WL_CFG80211 ++ if (role == WLC_E_IF_ROLE_STA && ++ !wl_cfg80211_is_roam_offload(dhd_idx2net(dhd_pub, ifindex)) && ++ !wl_cfg80211_is_event_from_connected_bssid( ++ dhd_idx2net(dhd_pub, ifindex), event, *ifidx)) { ++ del_sta = FALSE; ++ } ++#endif /* WL_CFG80211 */ ++ DHD_EVENT(("%s: Link event %d, flags %x, status %x, role %d, del_sta %d\n", ++ __FUNCTION__, type, flags, status, role, del_sta)); ++ ++ if (del_sta) { ++ DHD_MAC_TO_STR((event->addr.octet), macstr); ++ DHD_EVENT(("%s: Deleting STA %s\n", __FUNCTION__, macstr)); ++ ++ dhd_del_sta(dhd_pub, dhd_ifname2idx(dhd_pub->info, ++ event->ifname), &event->addr.octet); ++ /* Delete all flowrings for STA and P2P Client */ ++ if (role == WLC_E_IF_ROLE_STA || role == WLC_E_IF_ROLE_P2P_CLIENT) { ++ dhd_flow_rings_delete(dhd_pub, ifindex); ++ } else { ++ dhd_flow_rings_delete_for_peer(dhd_pub, ifindex, ++ (char *)&event->addr.octet[0]); ++ } ++ } ++ } ++#endif /* PCIE_FULL_DONGLE */ ++ /* fall through */ ++ ++ default: ++ *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); ++#ifdef DHD_UPDATE_INTF_MAC ++ if ((WLC_E_LINK==type)&&(WLC_EVENT_MSG_LINK&flags)) { ++ dhd_event_ifchange(dhd_pub->info, ++ (struct wl_event_data_if *)event, ++ event->ifname, ++ event->addr.octet); ++ } ++#endif /* DHD_UPDATE_INTF_MAC */ ++ /* push up to external supp/auth */ ++ dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); ++ DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", ++ __FUNCTION__, type, flags, status)); ++ BCM_REFERENCE(flags); ++ BCM_REFERENCE(status); ++ ++ break; ++ } ++#if defined(STBAP) ++ /* For routers, EAPD will be working on these events. ++ * Overwrite interface name to that event is pushed ++ * to host with its registered interface name ++ */ ++ memcpy(pvt_data->event.ifname, dhd_ifname(dhd_pub, *ifidx), IFNAMSIZ); ++#endif ++ ++exit: ++ ++#ifdef SHOW_EVENTS ++ if (DHD_FWLOG_ON() || DHD_EVENT_ON()) { ++ wl_show_host_event(dhd_pub, event, ++ (void *)event_data, raw_event, dhd_pub->enable_log); ++ } ++#endif /* SHOW_EVENTS */ ++ ++ return ret; ++} ++ ++int ++wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen, ++ wl_event_msg_t *event, void **data_ptr, void *raw_event) ++{ ++ return wl_process_host_event(dhd_pub, ifidx, pktdata, pktlen, event, data_ptr, ++ raw_event); ++} ++ ++void ++dhd_print_buf(void *pbuf, int len, int bytes_per_line) ++{ ++#ifdef DHD_DEBUG ++ int i, j = 0; ++ unsigned char *buf = pbuf; ++ ++ if (bytes_per_line == 0) { ++ bytes_per_line = len; ++ } ++ ++ for (i = 0; i < len; i++) { ++ printf("%2.2x", *buf++); ++ j++; ++ if (j == bytes_per_line) { ++ printf("\n"); ++ j = 0; ++ } else { ++ printf(":"); ++ } ++ } ++ printf("\n"); ++#endif /* DHD_DEBUG */ ++} ++#ifndef strtoul ++#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) ++#endif ++ ++/* Convert user's input in hex pattern to byte-size mask */ ++int ++wl_pattern_atoh(char *src, char *dst) ++{ ++ int i; ++ if (strncmp(src, "0x", 2) != 0 && ++ strncmp(src, "0X", 2) != 0) { ++ DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); ++ return -1; ++ } ++ src = src + 2; /* Skip past 0x */ ++ if (strlen(src) % 2 != 0) { ++ DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); ++ return -1; ++ } ++ for (i = 0; *src != '\0'; i++) { ++ char num[3]; ++ bcm_strncpy_s(num, sizeof(num), src, 2); ++ num[2] = '\0'; ++ dst[i] = (uint8)strtoul(num, NULL, 16); ++ src += 2; ++ } ++ return i; ++} ++ ++#ifdef PKT_FILTER_SUPPORT ++void ++dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) ++{ ++ char *argv[8]; ++ int i = 0; ++ const char *str; ++ int buf_len; ++ int str_len; ++ char *arg_save = 0, *arg_org = 0; ++ int rc; ++ char buf[32] = {0}; ++ wl_pkt_filter_enable_t enable_parm; ++ wl_pkt_filter_enable_t * pkt_filterp; ++ ++ if (!arg) ++ return; ++ ++ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { ++ DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ arg_org = arg_save; ++ memcpy(arg_save, arg, strlen(arg) + 1); ++ ++ argv[i] = bcmstrtok(&arg_save, " ", 0); ++ ++ i = 0; ++ if (argv[i] == NULL) { ++ DHD_ERROR(("No args provided\n")); ++ goto fail; ++ } ++ ++ str = "pkt_filter_enable"; ++ str_len = strlen(str); ++ bcm_strncpy_s(buf, sizeof(buf) - 1, str, sizeof(buf) - 1); ++ buf[ sizeof(buf) - 1 ] = '\0'; ++ buf_len = str_len + 1; ++ ++ pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); ++ ++ /* Parse packet filter id. */ ++ enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); ++ if (dhd_conf_del_pkt_filter(dhd, enable_parm.id)) ++ goto fail; ++ ++ /* Parse enable/disable value. */ ++ enable_parm.enable = htod32(enable); ++ ++ buf_len += sizeof(enable_parm); ++ memcpy((char *)pkt_filterp, ++ &enable_parm, ++ sizeof(enable_parm)); ++ ++ /* Enable/disable the specified filter. */ ++ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); ++ rc = rc >= 0 ? 0 : rc; ++ if (rc) ++ DHD_ERROR(("%s: failed to %s pktfilter %s, retcode = %d\n", ++ __FUNCTION__, enable?"enable":"disable", arg, rc)); ++ else ++ DHD_TRACE(("%s: successfully %s pktfilter %s\n", ++ __FUNCTION__, enable?"enable":"disable", arg)); ++ ++ /* Contorl the master mode */ ++ rc = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_mode", ++ master_mode, WLC_SET_VAR, TRUE, 0); ++ rc = rc >= 0 ? 0 : rc; ++ if (rc) ++ DHD_TRACE(("%s: failed to set pkt_filter_mode %d, retcode = %d\n", ++ __FUNCTION__, master_mode, rc)); ++ ++fail: ++ if (arg_org) ++ MFREE(dhd->osh, arg_org, strlen(arg) + 1); ++} ++ ++/* Packet filter section: extended filters have named offsets, add table here */ ++typedef struct { ++ char *name; ++ uint16 base; ++} wl_pfbase_t; ++ ++static wl_pfbase_t basenames[] = { WL_PKT_FILTER_BASE_NAMES }; ++ ++static int ++wl_pkt_filter_base_parse(char *name) ++{ ++ uint i; ++ char *bname, *uname; ++ ++ for (i = 0; i < ARRAYSIZE(basenames); i++) { ++ bname = basenames[i].name; ++ for (uname = name; *uname; bname++, uname++) { ++ if (*bname != bcm_toupper(*uname)) { ++ break; ++ } ++ } ++ if (!*uname && !*bname) { ++ break; ++ } ++ } ++ ++ if (i < ARRAYSIZE(basenames)) { ++ return basenames[i].base; ++ } else { ++ return -1; ++ } ++} ++ ++void ++dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) ++{ ++ const char *str; ++ wl_pkt_filter_t pkt_filter; ++ wl_pkt_filter_t *pkt_filterp; ++ int buf_len; ++ int str_len; ++ int rc; ++ uint32 mask_size; ++ uint32 pattern_size; ++ char *argv[16], * buf = 0; ++ int i = 0; ++ char *arg_save = 0, *arg_org = 0; ++#define BUF_SIZE 2048 ++ ++ if (!arg) ++ return; ++ ++ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { ++ DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ arg_org = arg_save; ++ ++ if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { ++ DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ memset(buf, 0, BUF_SIZE); ++ memcpy(arg_save, arg, strlen(arg) + 1); ++ ++ if (strlen(arg) > BUF_SIZE) { ++ DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); ++ goto fail; ++ } ++ ++ argv[i] = bcmstrtok(&arg_save, " ", 0); ++ while (argv[i++]) ++ argv[i] = bcmstrtok(&arg_save, " ", 0); ++ ++ i = 0; ++ if (argv[i] == NULL) { ++ DHD_ERROR(("No args provided\n")); ++ goto fail; ++ } ++ ++ str = "pkt_filter_add"; ++ str_len = strlen(str); ++ bcm_strncpy_s(buf, BUF_SIZE, str, str_len); ++ buf[ str_len ] = '\0'; ++ buf_len = str_len + 1; ++ ++ pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); ++ ++ /* Parse packet filter id. */ ++ pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); ++ if (dhd_conf_del_pkt_filter(dhd, pkt_filter.id)) ++ goto fail; ++ ++ if (argv[++i] == NULL) { ++ DHD_ERROR(("Polarity not provided\n")); ++ goto fail; ++ } ++ ++ /* Parse filter polarity. */ ++ pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if (argv[++i] == NULL) { ++ DHD_ERROR(("Filter type not provided\n")); ++ goto fail; ++ } ++ ++ /* Parse filter type. */ ++ pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if ((pkt_filter.type == 0) || (pkt_filter.type == 1)) { ++ if (argv[++i] == NULL) { ++ DHD_ERROR(("Offset not provided\n")); ++ goto fail; ++ } ++ ++ /* Parse pattern filter offset. */ ++ pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); ++ ++ if (argv[++i] == NULL) { ++ DHD_ERROR(("Bitmask not provided\n")); ++ goto fail; ++ } ++ ++ /* Parse pattern filter mask. */ ++ mask_size = ++ htod32(wl_pattern_atoh(argv[i], ++ (char *) pkt_filterp->u.pattern.mask_and_pattern)); ++ ++ if (argv[++i] == NULL) { ++ DHD_ERROR(("Pattern not provided\n")); ++ goto fail; ++ } ++ ++ /* Parse pattern filter pattern. */ ++ pattern_size = ++ htod32(wl_pattern_atoh(argv[i], ++ (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); ++ ++ if (mask_size != pattern_size) { ++ DHD_ERROR(("Mask and pattern not the same size\n")); ++ goto fail; ++ } ++ ++ pkt_filter.u.pattern.size_bytes = mask_size; ++ buf_len += WL_PKT_FILTER_FIXED_LEN; ++ buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); ++ ++ /* Keep-alive attributes are set in local variable (keep_alive_pkt), and ++ * then memcpy'ed into buffer (keep_alive_pktp) since there is no ++ * guarantee that the buffer is properly aligned. ++ */ ++ memcpy((char *)pkt_filterp, ++ &pkt_filter, ++ WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); ++ } else if ((pkt_filter.type == 2) || (pkt_filter.type == 6)) { ++ int list_cnt = 0; ++ char *endptr = '\0'; ++ wl_pkt_filter_pattern_listel_t *pf_el = &pkt_filterp->u.patlist.patterns[0]; ++ ++ while (argv[++i] != NULL) { ++ /* Parse pattern filter base and offset. */ ++ if (bcm_isdigit(*argv[i])) { ++ /* Numeric base */ ++ rc = strtoul(argv[i], &endptr, 0); ++ } else { ++ endptr = strchr(argv[i], ':'); ++ if (endptr) { ++ *endptr = '\0'; ++ rc = wl_pkt_filter_base_parse(argv[i]); ++ if (rc == -1) { ++ printf("Invalid base %s\n", argv[i]); ++ goto fail; ++ } ++ *endptr = ':'; ++ } else { ++ printf("Invalid [base:]offset format: %s\n", argv[i]); ++ goto fail; ++ } ++ } ++ ++ if (*endptr == ':') { ++ pkt_filter.u.patlist.patterns[0].base_offs = htod16(rc); ++ rc = strtoul(endptr + 1, &endptr, 0); ++ } else { ++ /* Must have had a numeric offset only */ ++ pkt_filter.u.patlist.patterns[0].base_offs = htod16(0); ++ } ++ ++ if (*endptr) { ++ printf("Invalid [base:]offset format: %s\n", argv[i]); ++ goto fail; ++ } ++ if (rc > 0x0000FFFF) { ++ printf("Offset too large\n"); ++ goto fail; ++ } ++ pkt_filter.u.patlist.patterns[0].rel_offs = htod16(rc); ++ ++ /* Clear match_flag (may be set in parsing which follows) */ ++ pkt_filter.u.patlist.patterns[0].match_flags = htod16(0); ++ ++ /* Parse pattern filter mask and pattern directly into ioctl buffer */ ++ if (argv[++i] == NULL) { ++ printf("Bitmask not provided\n"); ++ goto fail; ++ } ++ rc = wl_pattern_atoh(argv[i], (char*)pf_el->mask_and_data); ++ if (rc == -1) { ++ printf("Rejecting: %s\n", argv[i]); ++ goto fail; ++ } ++ mask_size = htod16(rc); ++ ++ if (argv[++i] == NULL) { ++ printf("Pattern not provided\n"); ++ goto fail; ++ } ++ ++ if (*argv[i] == '!') { ++ pkt_filter.u.patlist.patterns[0].match_flags = ++ htod16(WL_PKT_FILTER_MFLAG_NEG); ++ (argv[i])++; ++ } ++ if (*argv[i] == '\0') { ++ printf("Pattern not provided\n"); ++ goto fail; ++ } ++ rc = wl_pattern_atoh(argv[i], (char*)&pf_el->mask_and_data[rc]); ++ if (rc == -1) { ++ printf("Rejecting: %s\n", argv[i]); ++ goto fail; ++ } ++ pattern_size = htod16(rc); ++ ++ if (mask_size != pattern_size) { ++ printf("Mask and pattern not the same size\n"); ++ goto fail; ++ } ++ ++ pkt_filter.u.patlist.patterns[0].size_bytes = mask_size; ++ ++ /* Account for the size of this pattern element */ ++ buf_len += WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 2 * rc; ++ ++ /* And the pattern element fields that were put in a local for ++ * alignment purposes now get copied to the ioctl buffer. ++ */ ++ memcpy((char*)pf_el, &pkt_filter.u.patlist.patterns[0], ++ WL_PKT_FILTER_PATTERN_FIXED_LEN); ++ ++ /* Move to next element location in ioctl buffer */ ++ pf_el = (wl_pkt_filter_pattern_listel_t*) ++ ((uint8*)pf_el + WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 2 * rc); ++ ++ /* Count list element */ ++ list_cnt++; ++ } ++ ++ /* Account for initial fixed size, and copy initial fixed fields */ ++ buf_len += WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN; ++ ++ /* Update list count and total size */ ++ pkt_filter.u.patlist.list_cnt = list_cnt; ++ pkt_filter.u.patlist.PAD1[0] = 0; ++ pkt_filter.u.patlist.totsize = buf + buf_len - (char*)pkt_filterp; ++ pkt_filter.u.patlist.totsize -= WL_PKT_FILTER_FIXED_LEN; ++ ++ memcpy((char *)pkt_filterp, &pkt_filter, ++ WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN); ++ } else { ++ DHD_ERROR(("Invalid filter type %d\n", pkt_filter.type)); ++ goto fail; ++ } ++ ++ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); ++ rc = rc >= 0 ? 0 : rc; ++ ++ if (rc) ++ DHD_ERROR(("%s: failed to add pktfilter %s, retcode = %d\n", ++ __FUNCTION__, arg, rc)); ++ else ++ DHD_TRACE(("%s: successfully added pktfilter %s\n", ++ __FUNCTION__, arg)); ++ ++fail: ++ if (arg_org) ++ MFREE(dhd->osh, arg_org, strlen(arg) + 1); ++ ++ if (buf) ++ MFREE(dhd->osh, buf, BUF_SIZE); ++} ++ ++void ++dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id) ++{ ++ int ret; ++ ++ ret = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_delete", ++ id, WLC_SET_VAR, TRUE, 0); ++ if (ret < 0) { ++ DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n", ++ __FUNCTION__, id, ret)); ++ } ++ else ++ DHD_TRACE(("%s: successfully deleted pktfilter %d\n", ++ __FUNCTION__, id)); ++} ++#endif /* PKT_FILTER_SUPPORT */ ++ ++/* ========================== */ ++/* ==== ARP OFFLOAD SUPPORT = */ ++/* ========================== */ ++#ifdef ARP_OFFLOAD_SUPPORT ++void ++dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) ++{ ++ int retcode; ++ ++ retcode = dhd_wl_ioctl_set_intiovar(dhd, "arp_ol", ++ arp_mode, WLC_SET_VAR, TRUE, 0); ++ ++ retcode = retcode >= 0 ? 0 : retcode; ++ if (retcode) ++ DHD_ERROR(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", ++ __FUNCTION__, arp_mode, retcode)); ++ else ++ DHD_ARPOE(("%s: successfully set ARP offload mode to 0x%x\n", ++ __FUNCTION__, arp_mode)); ++} ++ ++void ++dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) ++{ ++ int retcode; ++ ++ retcode = dhd_wl_ioctl_set_intiovar(dhd, "arpoe", ++ arp_enable, WLC_SET_VAR, TRUE, 0); ++ ++ retcode = retcode >= 0 ? 0 : retcode; ++ if (retcode) ++ DHD_ERROR(("%s: failed to enabe ARP offload to %d, retcode = %d\n", ++ __FUNCTION__, arp_enable, retcode)); ++ else ++ DHD_ARPOE(("%s: successfully enabed ARP offload to %d\n", ++ __FUNCTION__, arp_enable)); ++ if (arp_enable) { ++ uint32 version; ++ retcode = dhd_wl_ioctl_get_intiovar(dhd, "arp_version", ++ &version, WLC_GET_VAR, FALSE, 0); ++ if (retcode) { ++ DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n", ++ __FUNCTION__, retcode)); ++ dhd->arp_version = 1; ++ } ++ else { ++ DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version)); ++ dhd->arp_version = version; ++ } ++ } ++} ++ ++void ++dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) ++{ ++ int ret = 0; ++ ++ if (dhd == NULL) return; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ ++ ret = dhd_iovar(dhd, idx, "arp_table_clear", NULL, 0, NULL, 0, TRUE); ++ if (ret < 0) ++ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); ++} ++ ++void ++dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) ++{ ++ int ret = 0; ++ ++ if (dhd == NULL) return; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ ++ ret = dhd_iovar(dhd, idx, "arp_hostip_clear", NULL, 0, NULL, 0, TRUE); ++ if (ret < 0) ++ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); ++} ++ ++void ++dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) ++{ ++ int ret; ++ ++ if (dhd == NULL) return; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ ++ ret = dhd_iovar(dhd, idx, "arp_hostip", (char *)&ipaddr, sizeof(ipaddr), ++ NULL, 0, TRUE); ++ if (ret) ++ DHD_ERROR(("%s: ARP ip addr add failed, ret = %d\n", __FUNCTION__, ret)); ++ else ++ DHD_ARPOE(("%s: sARP H ipaddr entry added \n", ++ __FUNCTION__)); ++} ++ ++int ++dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) ++{ ++ int ret, i; ++ uint32 *ptr32 = buf; ++ bool clr_bottom = FALSE; ++ ++ if (!buf) ++ return -1; ++ if (dhd == NULL) return -1; ++ if (dhd->arp_version == 1) ++ idx = 0; ++ ++ ret = dhd_iovar(dhd, idx, "arp_hostip", NULL, 0, (char *)buf, buflen, ++ FALSE); ++ if (ret) { ++ DHD_ERROR(("%s: ioctl WLC_GET_VAR error %d\n", ++ __FUNCTION__, ret)); ++ ++ return -1; ++ } ++ ++ /* clean up the buf, ascii reminder */ ++ for (i = 0; i < MAX_IPV4_ENTRIES; i++) { ++ if (!clr_bottom) { ++ if (*ptr32 == 0) ++ clr_bottom = TRUE; ++ } else { ++ *ptr32 = 0; ++ } ++ ptr32++; ++ } ++ ++ return 0; ++} ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++/* ++ * Neighbor Discovery Offload: enable NDO feature ++ * Called by ipv6 event handler when interface comes up/goes down ++ */ ++int ++dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable) ++{ ++ int retcode; ++ ++ if (dhd == NULL) ++ return -1; ++ ++ retcode = dhd_wl_ioctl_set_intiovar(dhd, "ndoe", ++ ndo_enable, WLC_SET_VAR, TRUE, 0); ++ if (retcode) ++ DHD_ERROR(("%s: failed to enabe ndo to %d, retcode = %d\n", ++ __FUNCTION__, ndo_enable, retcode)); ++ else ++ DHD_TRACE(("%s: successfully enabed ndo offload to %d\n", ++ __FUNCTION__, ndo_enable)); ++ ++ return retcode; ++} ++ ++/* ++ * Neighbor Discover Offload: enable NDO feature ++ * Called by ipv6 event handler when interface comes up ++ */ ++int ++dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx) ++{ ++ int iov_len = 0; ++ char iovbuf[DHD_IOVAR_BUF_SIZE] = {0}; ++ int retcode; ++ ++ if (dhd == NULL) ++ return -1; ++ ++ iov_len = bcm_mkiovar("nd_hostip", (char *)ipv6addr, ++ IPV6_ADDR_LEN, iovbuf, sizeof(iovbuf)); ++ if (!iov_len) { ++ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", ++ __FUNCTION__, sizeof(iovbuf))); ++ return -1; ++ } ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); ++ ++ if (retcode) ++ DHD_ERROR(("%s: ndo ip addr add failed, retcode = %d\n", ++ __FUNCTION__, retcode)); ++ else ++ DHD_TRACE(("%s: ndo ipaddr entry added \n", ++ __FUNCTION__)); ++ ++ return retcode; ++} ++ ++/* ++ * Neighbor Discover Offload: enable NDO feature ++ * Called by ipv6 event handler when interface goes down ++ */ ++int ++dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx) ++{ ++ int iov_len = 0; ++ char iovbuf[DHD_IOVAR_BUF_SIZE] = {0}; ++ int retcode; ++ ++ if (dhd == NULL) ++ return -1; ++ ++ iov_len = bcm_mkiovar("nd_hostip_clear", NULL, ++ 0, iovbuf, sizeof(iovbuf)); ++ if (!iov_len) { ++ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", ++ __FUNCTION__, sizeof(iovbuf))); ++ return -1; ++ } ++ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); ++ ++ if (retcode) ++ DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n", ++ __FUNCTION__, retcode)); ++ else ++ DHD_TRACE(("%s: ndo ipaddr entry removed \n", ++ __FUNCTION__)); ++ ++ return retcode; ++} ++ ++/* Enhanced ND offload */ ++uint16 ++dhd_ndo_get_version(dhd_pub_t *dhdp) ++{ ++ char iovbuf[DHD_IOVAR_BUF_SIZE]; ++ wl_nd_hostip_t ndo_get_ver; ++ int iov_len; ++ int retcode; ++ uint16 ver = 0; ++ ++ if (dhdp == NULL) { ++ return BCME_ERROR; ++ } ++ ++ memset(&iovbuf, 0, sizeof(iovbuf)); ++ ndo_get_ver.version = htod16(WL_ND_HOSTIP_IOV_VER); ++ ndo_get_ver.op_type = htod16(WL_ND_HOSTIP_OP_VER); ++ ndo_get_ver.length = htod32(WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16)); ++ ndo_get_ver.u.version = 0; ++ iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_get_ver, ++ WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16), iovbuf, sizeof(iovbuf)); ++ if (!iov_len) { ++ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", ++ __FUNCTION__, sizeof(iovbuf))); ++ return BCME_ERROR; ++ } ++ ++ retcode = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, iov_len, FALSE, 0); ++ if (retcode) { ++ DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode)); ++ /* ver iovar not supported. NDO version is 0 */ ++ ver = 0; ++ } else { ++ wl_nd_hostip_t *ndo_ver_ret = (wl_nd_hostip_t *)iovbuf; ++ ++ if ((dtoh16(ndo_ver_ret->version) == WL_ND_HOSTIP_IOV_VER) && ++ (dtoh16(ndo_ver_ret->op_type) == WL_ND_HOSTIP_OP_VER) && ++ (dtoh32(ndo_ver_ret->length) == WL_ND_HOSTIP_FIXED_LEN ++ + sizeof(uint16))) { ++ /* nd_hostip iovar version */ ++ ver = dtoh16(ndo_ver_ret->u.version); ++ } ++ ++ DHD_TRACE(("%s: successfully get version: %d\n", __FUNCTION__, ver)); ++ } ++ ++ return ver; ++} ++ ++int ++dhd_ndo_add_ip_with_type(dhd_pub_t *dhdp, char *ipv6addr, uint8 type, int idx) ++{ ++ char iovbuf[DHD_IOVAR_BUF_SIZE]; ++ wl_nd_hostip_t ndo_add_addr; ++ int iov_len; ++ int retcode; ++ ++ if (dhdp == NULL || ipv6addr == 0) { ++ return BCME_ERROR; ++ } ++ ++ /* wl_nd_hostip_t fixed param */ ++ ndo_add_addr.version = htod16(WL_ND_HOSTIP_IOV_VER); ++ ndo_add_addr.op_type = htod16(WL_ND_HOSTIP_OP_ADD); ++ ndo_add_addr.length = htod32(WL_ND_HOSTIP_WITH_ADDR_LEN); ++ /* wl_nd_host_ip_addr_t param for add */ ++ memcpy(&ndo_add_addr.u.host_ip.ip_addr, ipv6addr, IPV6_ADDR_LEN); ++ ndo_add_addr.u.host_ip.type = type; ++ ++ iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_add_addr, ++ WL_ND_HOSTIP_WITH_ADDR_LEN, iovbuf, sizeof(iovbuf)); ++ if (!iov_len) { ++ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", ++ __FUNCTION__, sizeof(iovbuf))); ++ return BCME_ERROR; ++ } ++ ++ retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); ++ if (retcode) { ++ DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode)); ++#ifdef NDO_CONFIG_SUPPORT ++ if (retcode == BCME_NORESOURCE) { ++ /* number of host ip addr exceeds FW capacity, Deactivate ND offload */ ++ DHD_INFO(("%s: Host IP count exceed device capacity," ++ "ND offload deactivated\n", __FUNCTION__)); ++ dhdp->ndo_host_ip_overflow = TRUE; ++ dhd_ndo_enable(dhdp, 0); ++ } ++#endif /* NDO_CONFIG_SUPPORT */ ++ } else { ++ DHD_TRACE(("%s: successfully added: %d\n", __FUNCTION__, retcode)); ++ } ++ ++ return retcode; ++} ++ ++int ++dhd_ndo_remove_ip_by_addr(dhd_pub_t *dhdp, char *ipv6addr, int idx) ++{ ++ char iovbuf[DHD_IOVAR_BUF_SIZE]; ++ wl_nd_hostip_t ndo_del_addr; ++ int iov_len; ++ int retcode; ++ ++ if (dhdp == NULL || ipv6addr == 0) { ++ return BCME_ERROR; ++ } ++ ++ /* wl_nd_hostip_t fixed param */ ++ ndo_del_addr.version = htod16(WL_ND_HOSTIP_IOV_VER); ++ ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL); ++ ndo_del_addr.length = htod32(WL_ND_HOSTIP_WITH_ADDR_LEN); ++ /* wl_nd_host_ip_addr_t param for del */ ++ memcpy(&ndo_del_addr.u.host_ip.ip_addr, ipv6addr, IPV6_ADDR_LEN); ++ ndo_del_addr.u.host_ip.type = 0; /* don't care */ ++ ++ iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_del_addr, ++ WL_ND_HOSTIP_WITH_ADDR_LEN, iovbuf, sizeof(iovbuf)); ++ if (!iov_len) { ++ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", ++ __FUNCTION__, sizeof(iovbuf))); ++ return BCME_ERROR; ++ } ++ ++ retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); ++ if (retcode) { ++ DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode)); ++ } else { ++ DHD_TRACE(("%s: successfully removed: %d\n", __FUNCTION__, retcode)); ++ } ++ ++ return retcode; ++} ++ ++int ++dhd_ndo_remove_ip_by_type(dhd_pub_t *dhdp, uint8 type, int idx) ++{ ++ char iovbuf[DHD_IOVAR_BUF_SIZE]; ++ wl_nd_hostip_t ndo_del_addr; ++ int iov_len; ++ int retcode; ++ ++ if (dhdp == NULL) { ++ return BCME_ERROR; ++ } ++ ++ /* wl_nd_hostip_t fixed param */ ++ ndo_del_addr.version = htod16(WL_ND_HOSTIP_IOV_VER); ++ if (type == WL_ND_IPV6_ADDR_TYPE_UNICAST) { ++ ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL_UC); ++ } else if (type == WL_ND_IPV6_ADDR_TYPE_ANYCAST) { ++ ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL_AC); ++ } else { ++ return BCME_BADARG; ++ } ++ ndo_del_addr.length = htod32(WL_ND_HOSTIP_FIXED_LEN); ++ ++ iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_del_addr, WL_ND_HOSTIP_FIXED_LEN, ++ iovbuf, sizeof(iovbuf)); ++ if (!iov_len) { ++ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", ++ __FUNCTION__, sizeof(iovbuf))); ++ return BCME_ERROR; ++ } ++ ++ retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); ++ if (retcode) { ++ DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode)); ++ } else { ++ DHD_TRACE(("%s: successfully removed: %d\n", __FUNCTION__, retcode)); ++ } ++ ++ return retcode; ++} ++ ++int ++dhd_ndo_unsolicited_na_filter_enable(dhd_pub_t *dhdp, int enable) ++{ ++ char iovbuf[DHD_IOVAR_BUF_SIZE]; ++ int iov_len; ++ int retcode; ++ ++ if (dhdp == NULL) { ++ return BCME_ERROR; ++ } ++ ++ iov_len = bcm_mkiovar("nd_unsolicited_na_filter", (char *)&enable, sizeof(int), ++ iovbuf, sizeof(iovbuf)); ++ if (!iov_len) { ++ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", ++ __FUNCTION__, sizeof(iovbuf))); ++ return BCME_ERROR; ++ } ++ retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0); ++ if (retcode) ++ DHD_ERROR(("%s: failed to enable Unsolicited NA filter to %d, retcode = %d\n", ++ __FUNCTION__, enable, retcode)); ++ else { ++ DHD_TRACE(("%s: successfully enabled Unsolicited NA filter to %d\n", ++ __FUNCTION__, enable)); ++ } ++ ++ return retcode; ++} ++ ++ ++/* ++ * returns = TRUE if associated, FALSE if not associated ++ */ ++bool dhd_is_associated(dhd_pub_t *dhd, uint8 ifidx, int *retval) ++{ ++ char bssid[6], zbuf[6]; ++ int ret = -1; ++ ++ bzero(bssid, 6); ++ bzero(zbuf, 6); ++ ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ++ ETHER_ADDR_LEN, FALSE, ifidx); ++ DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret)); ++ ++ if (ret == BCME_NOTASSOCIATED) { ++ DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); ++ } ++ ++ if (retval) ++ *retval = ret; ++ ++ if (ret < 0) ++ return FALSE; ++ ++ if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) == 0)) { ++ DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__)); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++/* Function to estimate possible DTIM_SKIP value */ ++#if defined(BCMPCIE) ++int ++dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bcn_interval) ++{ ++ int bcn_li_dtim = 1; /* deafult no dtim skip setting */ ++ int ret = -1; ++ int allowed_skip_dtim_cnt = 0; ++ ++ /* Check if associated */ ++ if (dhd_is_associated(dhd, 0, NULL) == FALSE) { ++ DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); ++ return bcn_li_dtim; ++ } ++ ++ if (dtim_period == NULL || bcn_interval == NULL) ++ return bcn_li_dtim; ++ ++ /* read associated AP beacon interval */ ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, ++ bcn_interval, sizeof(*bcn_interval), FALSE, 0)) < 0) { ++ DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); ++ return bcn_li_dtim; ++ } ++ ++ /* read associated AP dtim setup */ ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, ++ dtim_period, sizeof(*dtim_period), FALSE, 0)) < 0) { ++ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); ++ return bcn_li_dtim; ++ } ++ ++ /* if not assocated just return */ ++ if (*dtim_period == 0) { ++ return bcn_li_dtim; ++ } ++ ++ if (dhd->max_dtim_enable) { ++ bcn_li_dtim = ++ (int) (MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval))); ++ if (bcn_li_dtim == 0) { ++ bcn_li_dtim = 1; ++ } ++ } else { ++ /* attemp to use platform defined dtim skip interval */ ++ bcn_li_dtim = dhd->suspend_bcn_li_dtim; ++ ++ /* check if sta listen interval fits into AP dtim */ ++ if (*dtim_period > CUSTOM_LISTEN_INTERVAL) { ++ /* AP DTIM to big for our Listen Interval : no dtim skiping */ ++ bcn_li_dtim = NO_DTIM_SKIP; ++ DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", ++ __FUNCTION__, *dtim_period, CUSTOM_LISTEN_INTERVAL)); ++ return bcn_li_dtim; ++ } ++ ++ if (((*dtim_period) * (*bcn_interval) * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { ++ allowed_skip_dtim_cnt = ++ MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval)); ++ bcn_li_dtim = ++ (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; ++ } ++ ++ if ((bcn_li_dtim * (*dtim_period)) > CUSTOM_LISTEN_INTERVAL) { ++ /* Round up dtim_skip to fit into STAs Listen Interval */ ++ bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / *dtim_period); ++ DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); ++ } ++ } ++ ++ if (dhd->conf->suspend_bcn_li_dtim >= 0) ++ bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim; ++ DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", ++ __FUNCTION__, *bcn_interval, bcn_li_dtim, *dtim_period, CUSTOM_LISTEN_INTERVAL)); ++ ++ return bcn_li_dtim; ++} ++#else /* OEM_ANDROID && BCMPCIE */ ++int ++dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) ++{ ++ int bcn_li_dtim = 1; /* deafult no dtim skip setting */ ++ int ret = -1; ++ int dtim_period = 0; ++ int ap_beacon = 0; ++ int allowed_skip_dtim_cnt = 0; ++ /* Check if associated */ ++ if (dhd_is_associated(dhd, 0, NULL) == FALSE) { ++ DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); ++ goto exit; ++ } ++ ++ /* read associated AP beacon interval */ ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, ++ &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) { ++ DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); ++ goto exit; ++ } ++ ++ /* read associated ap's dtim setup */ ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, ++ &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) { ++ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); ++ goto exit; ++ } ++ ++ /* if not assocated just exit */ ++ if (dtim_period == 0) { ++ goto exit; ++ } ++ ++ if (dhd->max_dtim_enable) { ++ bcn_li_dtim = (int) (MAX_DTIM_ALLOWED_INTERVAL / (ap_beacon * dtim_period)); ++ if (bcn_li_dtim == 0) { ++ bcn_li_dtim = 1; ++ } ++ } else { ++ /* attemp to use platform defined dtim skip interval */ ++ bcn_li_dtim = dhd->suspend_bcn_li_dtim; ++ ++ /* check if sta listen interval fits into AP dtim */ ++ if (dtim_period > CUSTOM_LISTEN_INTERVAL) { ++ /* AP DTIM to big for our Listen Interval : no dtim skiping */ ++ bcn_li_dtim = NO_DTIM_SKIP; ++ DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", ++ __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL)); ++ goto exit; ++ } ++ ++ if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { ++ allowed_skip_dtim_cnt = ++ MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon); ++ bcn_li_dtim = ++ (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; ++ } ++ ++ if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) { ++ /* Round up dtim_skip to fit into STAs Listen Interval */ ++ bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period); ++ DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); ++ } ++ } ++ ++ if (dhd->conf->suspend_bcn_li_dtim >= 0) ++ bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim; ++ DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", ++ __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL)); ++ ++exit: ++ return bcn_li_dtim; ++} ++#endif /* OEM_ANDROID && BCMPCIE */ ++ ++/* Check if the mode supports STA MODE */ ++bool dhd_support_sta_mode(dhd_pub_t *dhd) ++{ ++ ++#ifdef WL_CFG80211 ++ if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) ++ return FALSE; ++ else ++#endif /* WL_CFG80211 */ ++ return TRUE; ++} ++ ++#if defined(KEEP_ALIVE) ++int dhd_keep_alive_onoff(dhd_pub_t *dhd) ++{ ++ char buf[32] = {0}; ++ const char *str; ++ wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0, 0, 0, 0, 0, {0}}; ++ wl_mkeep_alive_pkt_t *mkeep_alive_pktp; ++ int buf_len; ++ int str_len; ++ int res = -1; ++ ++ if (!dhd_support_sta_mode(dhd)) ++ return res; ++ ++ DHD_TRACE(("%s execution\n", __FUNCTION__)); ++ ++ str = "mkeep_alive"; ++ str_len = strlen(str); ++ strncpy(buf, str, sizeof(buf) - 1); ++ buf[ sizeof(buf) - 1 ] = '\0'; ++ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); ++ mkeep_alive_pkt.period_msec = dhd->conf->keep_alive_period; ++ buf_len = str_len + 1; ++ mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); ++ mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); ++ /* Setup keep alive zero for null packet generation */ ++ mkeep_alive_pkt.keep_alive_id = 0; ++ mkeep_alive_pkt.len_bytes = 0; ++ buf_len += WL_MKEEP_ALIVE_FIXED_LEN; ++ bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); ++ /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and ++ * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no ++ * guarantee that the buffer is properly aligned. ++ */ ++ memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); ++ ++ res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); ++ ++ return res; ++} ++#endif /* defined(KEEP_ALIVE) */ ++ ++#define CSCAN_TLV_TYPE_SSID_IE 'S' ++/* ++ * SSIDs list parsing from cscan tlv list ++ */ ++int ++wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left) ++{ ++ char* str; ++ int idx = 0; ++ ++ if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { ++ DHD_ERROR(("%s error paramters\n", __FUNCTION__)); ++ return -1; ++ } ++ str = *list_str; ++ while (*bytes_left > 0) { ++ ++ if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { ++ *list_str = str; ++ DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); ++ return idx; ++ } ++ ++ /* Get proper CSCAN_TLV_TYPE_SSID_IE */ ++ *bytes_left -= 1; ++ str += 1; ++ ssid[idx].rssi_thresh = 0; ++ ssid[idx].flags = 0; ++ if (str[0] == 0) { ++ /* Broadcast SSID */ ++ ssid[idx].SSID_len = 0; ++ memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); ++ *bytes_left -= 1; ++ str += 1; ++ ++ DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); ++ } ++ else if (str[0] <= DOT11_MAX_SSID_LEN) { ++ /* Get proper SSID size */ ++ ssid[idx].SSID_len = str[0]; ++ *bytes_left -= 1; ++ str += 1; ++ ++ /* Get SSID */ ++ if (ssid[idx].SSID_len > *bytes_left) { ++ DHD_ERROR(("%s out of memory range len=%d but left=%d\n", ++ __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); ++ return -1; ++ } ++ ++ memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); ++ ++ *bytes_left -= ssid[idx].SSID_len; ++ str += ssid[idx].SSID_len; ++ ssid[idx].hidden = TRUE; ++ ++ DHD_TRACE(("%s :size=%d left=%d\n", ++ (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); ++ } ++ else { ++ DHD_ERROR(("### SSID size more that %d\n", str[0])); ++ return -1; ++ } ++ ++ if (idx++ > max) { ++ DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); ++ return -1; ++ } ++ } ++ ++ *list_str = str; ++ return idx; ++} ++ ++#if defined(WL_WIRELESS_EXT) ++/* Android ComboSCAN support */ ++ ++/* ++ * data parsing from ComboScan tlv list ++*/ ++int ++wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, ++ int input_size, int *bytes_left) ++{ ++ char* str; ++ uint16 short_temp; ++ uint32 int_temp; ++ ++ if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { ++ DHD_ERROR(("%s error paramters\n", __FUNCTION__)); ++ return -1; ++ } ++ str = *list_str; ++ ++ /* Clean all dest bytes */ ++ memset(dst, 0, dst_size); ++ while (*bytes_left > 0) { ++ ++ if (str[0] != token) { ++ DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", ++ __FUNCTION__, token, str[0], *bytes_left)); ++ return -1; ++ } ++ ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (input_size == 1) { ++ memcpy(dst, str, input_size); ++ } ++ else if (input_size == 2) { ++ memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), ++ input_size); ++ } ++ else if (input_size == 4) { ++ memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), ++ input_size); ++ } ++ ++ *bytes_left -= input_size; ++ str += input_size; ++ *list_str = str; ++ return 1; ++ } ++ return 1; ++} ++ ++/* ++ * channel list parsing from cscan tlv list ++*/ ++int ++wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, ++ int channel_num, int *bytes_left) ++{ ++ char* str; ++ int idx = 0; ++ ++ if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { ++ DHD_ERROR(("%s error paramters\n", __FUNCTION__)); ++ return -1; ++ } ++ str = *list_str; ++ ++ while (*bytes_left > 0) { ++ ++ if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { ++ *list_str = str; ++ DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); ++ return idx; ++ } ++ /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (str[0] == 0) { ++ /* All channels */ ++ channel_list[idx] = 0x0; ++ } ++ else { ++ channel_list[idx] = (uint16)str[0]; ++ DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); ++ } ++ *bytes_left -= 1; ++ str += 1; ++ ++ if (idx++ > 255) { ++ DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); ++ return -1; ++ } ++ } ++ ++ *list_str = str; ++ return idx; ++} ++ ++/* Parse a comma-separated list from list_str into ssid array, starting ++ * at index idx. Max specifies size of the ssid array. Parses ssids ++ * and returns updated idx; if idx >= max not all fit, the excess have ++ * not been copied. Returns -1 on empty string, or on ssid too long. ++ */ ++int ++wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) ++{ ++ char* str, *ptr; ++ ++ if ((list_str == NULL) || (*list_str == NULL)) ++ return -1; ++ ++ for (str = *list_str; str != NULL; str = ptr) { ++ ++ /* check for next TAG */ ++ if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { ++ *list_str = str + strlen(GET_CHANNEL); ++ return idx; ++ } ++ ++ if ((ptr = strchr(str, ',')) != NULL) { ++ *ptr++ = '\0'; ++ } ++ ++ if (strlen(str) > DOT11_MAX_SSID_LEN) { ++ DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); ++ return -1; ++ } ++ ++ if (strlen(str) == 0) ++ ssid[idx].SSID_len = 0; ++ ++ if (idx < max) { ++ bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID)); ++ strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1); ++ ssid[idx].SSID_len = strlen(str); ++ } ++ idx++; ++ } ++ return idx; ++} ++ ++/* ++ * Parse channel list from iwpriv CSCAN ++ */ ++int ++wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) ++{ ++ int num; ++ int val; ++ char* str; ++ char* endptr = NULL; ++ ++ if ((list_str == NULL)||(*list_str == NULL)) ++ return -1; ++ ++ str = *list_str; ++ num = 0; ++ while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { ++ val = (int)strtoul(str, &endptr, 0); ++ if (endptr == str) { ++ printf("could not parse channel number starting at" ++ " substring \"%s\" in list:\n%s\n", ++ str, *list_str); ++ return -1; ++ } ++ str = endptr + strspn(endptr, " ,"); ++ ++ if (num == channel_num) { ++ DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", ++ channel_num, *list_str)); ++ return -1; ++ } ++ ++ channel_list[num++] = (uint16)val; ++ } ++ *list_str = str; ++ return num; ++} ++ ++#endif ++ ++#if defined(TRAFFIC_MGMT_DWM) ++static int traffic_mgmt_add_dwm_filter(dhd_pub_t *dhd, ++ trf_mgmt_filter_list_t * trf_mgmt_filter_list, int len) ++{ ++ int ret = 0; ++ uint32 i; ++ trf_mgmt_filter_t *trf_mgmt_filter; ++ uint8 dwm_tbl_entry; ++ uint32 dscp = 0; ++ uint16 dwm_filter_enabled = 0; ++ ++ ++ /* Check parameter length is adequate */ ++ if (len < (OFFSETOF(trf_mgmt_filter_list_t, filter) + ++ trf_mgmt_filter_list->num_filters * sizeof(trf_mgmt_filter_t))) { ++ ret = BCME_BUFTOOSHORT; ++ return ret; ++ } ++ ++ bzero(&dhd->dhd_tm_dwm_tbl, sizeof(dhd_trf_mgmt_dwm_tbl_t)); ++ ++ for (i = 0; i < trf_mgmt_filter_list->num_filters; i++) { ++ trf_mgmt_filter = &trf_mgmt_filter_list->filter[i]; ++ ++ dwm_filter_enabled = (trf_mgmt_filter->flags & TRF_FILTER_DWM); ++ ++ if (dwm_filter_enabled) { ++ dscp = trf_mgmt_filter->dscp; ++ if (dscp >= DHD_DWM_TBL_SIZE) { ++ ret = BCME_BADARG; ++ return ret; ++ } ++ } ++ ++ dhd->dhd_tm_dwm_tbl.dhd_dwm_enabled = 1; ++ /* set WMM AC bits */ ++ dwm_tbl_entry = (uint8) trf_mgmt_filter->priority; ++ DHD_TRF_MGMT_DWM_SET_FILTER(dwm_tbl_entry); ++ ++ /* set favored bits */ ++ if (trf_mgmt_filter->flags & TRF_FILTER_FAVORED) ++ DHD_TRF_MGMT_DWM_SET_FAVORED(dwm_tbl_entry); ++ ++ dhd->dhd_tm_dwm_tbl.dhd_dwm_tbl[dscp] = dwm_tbl_entry; ++ } ++ return ret; ++} ++#endif ++ ++/* Given filename and download type, returns a buffer pointer and length ++ * for download to f/w. Type can be FW or NVRAM. ++ * ++ */ ++int dhd_get_download_buffer(dhd_pub_t *dhd, char *file_path, download_type_t component, ++ char ** buffer, int *length) ++ ++{ ++ int ret = BCME_ERROR; ++ int len = 0; ++ int file_len; ++ void *image = NULL; ++ uint8 *buf = NULL; ++ ++ /* Point to cache if available. */ ++#ifdef CACHE_FW_IMAGES ++ if (component == FW) { ++ if (dhd->cached_fw_length) { ++ len = dhd->cached_fw_length; ++ buf = dhd->cached_fw; ++ } ++ } ++ else if (component == NVRAM) { ++ if (dhd->cached_nvram_length) { ++ len = dhd->cached_nvram_length; ++ buf = dhd->cached_nvram; ++ } ++ } ++ else if (component == CLM_BLOB) { ++ if (dhd->cached_clm_length) { ++ len = dhd->cached_clm_length; ++ buf = dhd->cached_clm; ++ } ++ } else { ++ return ret; ++ } ++#endif /* CACHE_FW_IMAGES */ ++ /* No Valid cache found on this call */ ++ if (!len) { ++ file_len = *length; ++ *length = 0; ++ ++ if (file_path) { ++ image = dhd_os_open_image(file_path); ++ if (image == NULL) { ++ printf("%s: Open image file failed %s\n", __FUNCTION__, file_path); ++ goto err; ++ } ++ } ++ ++ buf = MALLOCZ(dhd->osh, file_len); ++ if (buf == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", ++ __FUNCTION__, file_len)); ++ goto err; ++ } ++ ++ /* Download image */ ++#if defined(BCMEMBEDIMAGE) && defined(DHD_EFI) ++ if (!image) { ++ memcpy(buf, nvram_arr, sizeof(nvram_arr)); ++ len = sizeof(nvram_arr); ++ } else { ++ len = dhd_os_get_image_block((char *)buf, file_len, image); ++ if ((len <= 0 || len > file_len)) { ++ MFREE(dhd->osh, buf, file_len); ++ goto err; ++ } ++ } ++#else ++ len = dhd_os_get_image_block((char *)buf, file_len, image); ++ if ((len <= 0 || len > file_len)) { ++ MFREE(dhd->osh, buf, file_len); ++ goto err; ++ } ++#endif /* DHD_EFI */ ++ } ++ ++ ret = BCME_OK; ++ *length = len; ++ *buffer = (char *)buf; ++ ++ /* Cache if first call. */ ++#ifdef CACHE_FW_IMAGES ++ if (component == FW) { ++ if (!dhd->cached_fw_length) { ++ dhd->cached_fw = buf; ++ dhd->cached_fw_length = len; ++ } ++ } ++ else if (component == NVRAM) { ++ if (!dhd->cached_nvram_length) { ++ dhd->cached_nvram = buf; ++ dhd->cached_nvram_length = len; ++ } ++ } ++ else if (component == CLM_BLOB) { ++ if (!dhd->cached_clm_length) { ++ dhd->cached_clm = buf; ++ dhd->cached_clm_length = len; ++ } ++ } ++#endif /* CACHE_FW_IMAGES */ ++ ++err: ++ if (image) ++ dhd_os_close_image(image); ++ ++ return ret; ++} ++ ++int ++dhd_download_2_dongle(dhd_pub_t *dhd, char *iovar, uint16 flag, uint16 dload_type, ++ unsigned char *dload_buf, int len) ++{ ++ struct wl_dload_data *dload_ptr = (struct wl_dload_data *)dload_buf; ++ int err = 0; ++ int dload_data_offset; ++ static char iovar_buf[WLC_IOCTL_MEDLEN]; ++ int iovar_len; ++ ++ memset(iovar_buf, 0, sizeof(iovar_buf)); ++ ++ dload_data_offset = OFFSETOF(wl_dload_data_t, data); ++ dload_ptr->flag = (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT) | flag; ++ dload_ptr->dload_type = dload_type; ++ dload_ptr->len = htod32(len - dload_data_offset); ++ dload_ptr->crc = 0; ++ len = ROUNDUP(len, 8); ++ ++ iovar_len = bcm_mkiovar(iovar, (char *)dload_buf, ++ (uint)len, iovar_buf, sizeof(iovar_buf)); ++ if (iovar_len == 0) { ++ DHD_ERROR(("%s: insufficient buffer space passed to bcm_mkiovar for '%s' \n", ++ __FUNCTION__, iovar)); ++ return BCME_BUFTOOSHORT; ++ } ++ ++ err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovar_buf, ++ iovar_len, IOV_SET, 0); ++ ++ return err; ++} ++ ++int ++dhd_download_blob(dhd_pub_t *dhd, unsigned char *image, ++ uint32 len, char *iovar) ++{ ++ int chunk_len; ++ int size2alloc; ++ unsigned char *new_buf; ++ int err = 0, data_offset; ++ uint16 dl_flag = DL_BEGIN; ++ ++ data_offset = OFFSETOF(wl_dload_data_t, data); ++ size2alloc = data_offset + MAX_CHUNK_LEN; ++ size2alloc = ROUNDUP(size2alloc, 8); ++ ++ if ((new_buf = (unsigned char *)MALLOCZ(dhd->osh, size2alloc)) != NULL) { ++ do { ++ chunk_len = dhd_os_get_image_block((char *)(new_buf + data_offset), ++ MAX_CHUNK_LEN, image); ++ if (chunk_len < 0) { ++ DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", ++ __FUNCTION__, chunk_len)); ++ err = BCME_ERROR; ++ goto exit; ++ } ++ ++ if (len - chunk_len == 0) ++ dl_flag |= DL_END; ++ ++ err = dhd_download_2_dongle(dhd, iovar, dl_flag, DL_TYPE_CLM, ++ new_buf, data_offset + chunk_len); ++ ++ dl_flag &= ~DL_BEGIN; ++ ++ len = len - chunk_len; ++ } while ((len > 0) && (err == 0)); ++ } else { ++ err = BCME_NOMEM; ++ } ++exit: ++ if (new_buf) { ++ MFREE(dhd->osh, new_buf, size2alloc); ++ } ++ ++ return err; ++} ++ ++int ++dhd_check_current_clm_data(dhd_pub_t *dhd) ++{ ++ char iovbuf[WLC_IOCTL_SMLEN] = {0}; ++ wl_country_t *cspec; ++ int err = BCME_OK; ++ ++ bcm_mkiovar("country", NULL, 0, iovbuf, sizeof(iovbuf)); ++ err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); ++ if (err) { ++ DHD_ERROR(("%s: country code get failed\n", __FUNCTION__)); ++ return err; ++ } ++ ++ cspec = (wl_country_t *)iovbuf; ++ if ((strncmp(cspec->ccode, WL_CCODE_NULL_COUNTRY, WLC_CNTRY_BUF_SZ)) == 0) { ++ DHD_ERROR(("%s: ----- This FW is not included CLM data -----\n", ++ __FUNCTION__)); ++ return FALSE; ++ } ++ DHD_ERROR(("%s: ----- This FW is included CLM data -----\n", ++ __FUNCTION__)); ++ return TRUE; ++} ++ ++int ++dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) ++{ ++ char *clm_blob_path; ++ int len; ++ unsigned char *imgbuf = NULL; ++ int err = BCME_OK; ++ char iovbuf[WLC_IOCTL_SMLEN] = {0}; ++ int status = FALSE; ++ ++ if (clm_path && clm_path[0] != '\0') { ++ if (strlen(clm_path) > MOD_PARAM_PATHLEN) { ++ DHD_ERROR(("clm path exceeds max len\n")); ++ return BCME_ERROR; ++ } ++ clm_blob_path = clm_path; ++ DHD_TRACE(("clm path from module param:%s\n", clm_path)); ++ } else { ++ clm_blob_path = CONFIG_BCMDHD_CLM_PATH; ++ } ++ ++ /* If CLM blob file is found on the filesystem, download the file. ++ * After CLM file download or If the blob file is not present, ++ * validate the country code before proceeding with the initialization. ++ * If country code is not valid, fail the initialization. ++ */ ++ ++ imgbuf = dhd_os_open_image((char *)clm_blob_path); ++ if (imgbuf == NULL) { ++ printf("%s: Ignore clm file %s\n", __FUNCTION__, clm_path); ++#if defined(DHD_BLOB_EXISTENCE_CHECK) ++ if (dhd->is_blob) { ++ err = BCME_ERROR; ++ } else { ++ status = dhd_check_current_clm_data(dhd); ++ if (status == TRUE) { ++ err = BCME_OK; ++ } else { ++ err = BCME_ERROR; ++ } ++ } ++#endif /* DHD_BLOB_EXISTENCE_CHECK */ ++ goto exit; ++ } ++ ++ len = dhd_os_get_image_size(imgbuf); ++ ++ if ((len > 0) && (len < MAX_CLM_BUF_SIZE) && imgbuf) { ++ status = dhd_check_current_clm_data(dhd); ++ if (status == TRUE) { ++#if defined(DHD_BLOB_EXISTENCE_CHECK) ++ if (dhd->op_mode != DHD_FLAG_MFG_MODE) { ++ if (dhd->is_blob) { ++ err = BCME_ERROR; ++ } ++ goto exit; ++ } ++#else ++ DHD_ERROR(("%s: CLM already exist in F/W, " ++ "new CLM data will be added to the end of existing CLM data!\n", ++ __FUNCTION__)); ++#endif /* DHD_BLOB_EXISTENCE_CHECK */ ++ } ++ ++ /* Found blob file. Download the file */ ++ DHD_ERROR(("clm file download from %s \n", clm_blob_path)); ++ err = dhd_download_blob(dhd, imgbuf, len, "clmload"); ++ if (err) { ++ DHD_ERROR(("%s: CLM download failed err=%d\n", __FUNCTION__, err)); ++ /* Retrieve clmload_status and print */ ++ bcm_mkiovar("clmload_status", NULL, 0, iovbuf, sizeof(iovbuf)); ++ err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); ++ if (err) { ++ DHD_ERROR(("%s: clmload_status get failed err=%d \n", ++ __FUNCTION__, err)); ++ } else { ++ DHD_ERROR(("%s: clmload_status: %d \n", ++ __FUNCTION__, *((int *)iovbuf))); ++ if (*((int *)iovbuf) == CHIPID_MISMATCH) { ++ DHD_ERROR(("Chip ID mismatch error \n")); ++ } ++ } ++ err = BCME_ERROR; ++ goto exit; ++ } else { ++ DHD_INFO(("%s: CLM download succeeded \n", __FUNCTION__)); ++ } ++ } else { ++ DHD_INFO(("Skipping the clm download. len:%d memblk:%p \n", len, imgbuf)); ++ } ++ ++ /* Verify country code */ ++ status = dhd_check_current_clm_data(dhd); ++ ++ if (status != TRUE) { ++ /* Country code not initialized or CLM download not proper */ ++ DHD_ERROR(("country code not initialized\n")); ++ err = BCME_ERROR; ++ } ++exit: ++ ++ if (imgbuf) { ++ dhd_os_close_image(imgbuf); ++ } ++ ++ return err; ++} ++ ++void dhd_free_download_buffer(dhd_pub_t *dhd, void *buffer, int length) ++{ ++#ifdef CACHE_FW_IMAGES ++ return; ++#endif ++ MFREE(dhd->osh, buffer, length); ++} ++ ++#if defined(DHD_8021X_DUMP) ++#define EAP_PRINT(x, args...) \ ++ do { \ ++ if (dump_msg_level & DUMP_EAPOL_VAL) { \ ++ printk("[dhd-%s] 802_1X " x " [%s] : (%s) %s (%s)\n", ifname, ## args, \ ++ tx?"TX":"RX", tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf); \ ++ } \ ++ } while (0) ++#else ++#define EAP_PRINT(x, args...) ++#endif /* DHD_8021X_DUMP */ ++/* Parse EAPOL 4 way handshake messages */ ++void ++dhd_dump_eapol_4way_message(dhd_pub_t *dhd, char *ifname, ++ char *dump_data, bool tx) ++{ ++ unsigned char type; ++ int pair, ack, mic, kerr, req, sec, install; ++ unsigned short us_tmp, key_len; ++ char seabuf[ETHER_ADDR_STR_LEN]=""; ++ char deabuf[ETHER_ADDR_STR_LEN]=""; ++ ++ bcm_ether_ntoa((struct ether_addr *)dump_data, deabuf); ++ bcm_ether_ntoa((struct ether_addr *)(dump_data+6), seabuf); ++ ++ type = dump_data[15]; ++ if (type == 0) { ++ if ((dump_data[22] == 1) && (dump_data[18] == 1)) { ++ dhd->conf->eapol_status = EAPOL_STATUS_REQID; ++ EAP_PRINT("Request, Identity"); ++ } else if ((dump_data[22] == 1) && (dump_data[18] == 2)) { ++ dhd->conf->eapol_status = EAPOL_STATUS_RSPID; ++ EAP_PRINT("Response, Identity"); ++ } else if (dump_data[22] == 254) { ++ if (dump_data[30] == 1) { ++ dhd->conf->eapol_status = EAPOL_STATUS_WSC_START; ++ EAP_PRINT("WSC Start"); ++ } else if (dump_data[30] == 4) { ++ if (dump_data[41] == 4) { ++ dhd->conf->eapol_status = EAPOL_STATUS_WPS_M1; ++ EAP_PRINT("WPS M1"); ++ } else if (dump_data[41] == 5) { ++ dhd->conf->eapol_status = EAPOL_STATUS_WPS_M2; ++ EAP_PRINT("WPS M2"); ++ } else if (dump_data[41] == 7) { ++ dhd->conf->eapol_status = EAPOL_STATUS_WPS_M3; ++ EAP_PRINT("WPS M3"); ++ } else if (dump_data[41] == 8) { ++ dhd->conf->eapol_status = EAPOL_STATUS_WPS_M4; ++ EAP_PRINT("WPS M4"); ++ } else if (dump_data[41] == 9) { ++ dhd->conf->eapol_status = EAPOL_STATUS_WPS_M5; ++ EAP_PRINT("WPS M5"); ++ } else if (dump_data[41] == 10) { ++ dhd->conf->eapol_status = EAPOL_STATUS_WPS_M6; ++ EAP_PRINT("WPS M6"); ++ } else if (dump_data[41] == 11) { ++ dhd->conf->eapol_status = EAPOL_STATUS_WPS_M7; ++ EAP_PRINT("WPS M7"); ++ } else if (dump_data[41] == 12) { ++ dhd->conf->eapol_status = EAPOL_STATUS_WPS_M8; ++ EAP_PRINT("WPS M8"); ++ } ++ } else if (dump_data[30] == 5) { ++ dhd->conf->eapol_status = EAPOL_STATUS_WSC_DONE; ++ EAP_PRINT("WSC Done"); ++ } ++ } else { ++ EAP_PRINT("ver %d, type %d, replay %d", ++ dump_data[14], dump_data[15], dump_data[30]); ++ } ++ } ++ else if (type == 3 && dump_data[18] == 2) { ++ us_tmp = (dump_data[19] << 8) | dump_data[20]; ++ pair = 0 != (us_tmp & 0x08); ++ ack = 0 != (us_tmp & 0x80); ++ mic = 0 != (us_tmp & 0x100); ++ kerr = 0 != (us_tmp & 0x400); ++ req = 0 != (us_tmp & 0x800); ++ sec = 0 != (us_tmp & 0x200); ++ install = 0 != (us_tmp & 0x40); ++ ++ if (!req && !kerr && !sec && !mic && ack && !install && pair) { ++ dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M1; ++ EAP_PRINT("WPA2 4-way M1(0x%04x)", us_tmp); ++ } else if (!req && !kerr && !sec && mic && !ack && !install && pair) { ++ dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M2; ++ EAP_PRINT("WPA2 4-way M2(0x%04x)", us_tmp); ++ } else if (!req && !kerr && sec && mic && ack && pair) { ++ dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M3; ++ EAP_PRINT("WPA2 4-way M3(0x%04x)", us_tmp); ++ } else if (!req && !kerr && sec && mic && !ack && !install && pair) { ++ dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M4; ++ EAP_PRINT("WPA2 4-way M4(0x%04x)", us_tmp); ++ } else { ++ EAP_PRINT("ver %d, type %d, key_info 0x%x, replay %d", ++ dump_data[14], dump_data[15], us_tmp, dump_data[30]); ++ } ++ } ++ else if (type == 3 && dump_data[18] == 254) { ++ us_tmp = (dump_data[19] << 8) | dump_data[20]; ++ req = 0 != (us_tmp & 0x800); ++ kerr = 0 != (us_tmp & 0x400); ++ sec = 0 != (us_tmp & 0x200); ++ mic = 0 != (us_tmp & 0x100); ++ ack = 0 != (us_tmp & 0x80); ++ install = 0 != (us_tmp & 0x40); ++ pair = 0 != (us_tmp & 0x08); ++ key_len = (dump_data[111] << 8) | dump_data[112]; ++ ++ if (!req && !kerr && !sec && !mic && ack && !install && pair) { ++ dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M1; ++ EAP_PRINT("WPA 4-way M1(0x%04x)", us_tmp); ++ } else if (!req && !kerr && !sec && mic && !ack && !install && pair && key_len) { ++ dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M2; ++ EAP_PRINT("WPA 4-way M2(0x%04x)", us_tmp); ++ } else if (!req && !kerr && !sec && mic && ack && install && pair) { ++ dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M3; ++ EAP_PRINT("WPA 4-way M3(0x%04x)", us_tmp); ++ } else if (!req && !kerr && !sec && mic && !ack && !install && pair) { ++ dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M4; ++ EAP_PRINT("WPA 4-way M4(0x%04x)", us_tmp); ++ } else if (!req && !kerr && sec && mic && ack && !install && !pair) { ++ dhd->conf->eapol_status = EAPOL_STATUS_GROUPKEY_M1; ++ EAP_PRINT("GROUP Key M1(0x%04x)", us_tmp); ++ } else if (!req && !kerr && sec && mic && !ack && !install && !pair) { ++ dhd->conf->eapol_status = EAPOL_STATUS_GROUPKEY_M2; ++ EAP_PRINT("GROUP Key M2(0x%04x)", us_tmp); ++ } else { ++ EAP_PRINT("ver %d, type %d, key_type %d, key_info 0x%x, replay %d", ++ dump_data[14], dump_data[15], dump_data[18], us_tmp, dump_data[30]); ++ } ++ } else { ++ EAP_PRINT("ver %d, type %d, replay %d", ++ dump_data[14], dump_data[15], dump_data[30]); ++ } ++} ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++void init_dhd_timeouts(dhd_pub_t *pub) ++{ ++ pub->timeout_info = MALLOC(pub->osh, sizeof(timeout_info_t)); ++ if (pub->timeout_info == NULL) { ++ DHD_ERROR(("%s: Failed to alloc timeout_info\n", __FUNCTION__)); ++ } else { ++ DHD_INFO(("Initializing dhd_timeouts\n")); ++ pub->timeout_info->scan_timer_lock = dhd_os_spin_lock_init(pub->osh); ++ pub->timeout_info->join_timer_lock = dhd_os_spin_lock_init(pub->osh); ++ pub->timeout_info->bus_timer_lock = dhd_os_spin_lock_init(pub->osh); ++ pub->timeout_info->cmd_timer_lock = dhd_os_spin_lock_init(pub->osh); ++ pub->timeout_info->scan_timeout_val = SCAN_TIMEOUT_DEFAULT; ++ pub->timeout_info->join_timeout_val = JOIN_TIMEOUT_DEFAULT; ++ pub->timeout_info->cmd_timeout_val = CMD_TIMEOUT_DEFAULT; ++ pub->timeout_info->bus_timeout_val = BUS_TIMEOUT_DEFAULT; ++ pub->timeout_info->scan_timer_active = FALSE; ++ pub->timeout_info->join_timer_active = FALSE; ++ pub->timeout_info->cmd_timer_active = FALSE; ++ pub->timeout_info->bus_timer_active = FALSE; ++ pub->timeout_info->cmd_join_error = WLC_SSID_MASK; ++ pub->timeout_info->cmd_request_id = 0; ++ } ++} ++ ++void ++deinit_dhd_timeouts(dhd_pub_t *pub) ++{ ++ /* stop the join, scan bus, cmd timers ++ * as failing to do so may cause a kernel panic if ++ * an rmmod is done ++ */ ++ if (!pub->timeout_info) { ++ DHD_ERROR(("timeout_info pointer is NULL\n")); ++ ASSERT(0); ++ return; ++ } ++ if (dhd_stop_scan_timer(pub)) { ++ DHD_ERROR(("dhd_stop_scan_timer failed\n")); ++ ASSERT(0); ++ } ++ if (dhd_stop_bus_timer(pub)) { ++ DHD_ERROR(("dhd_stop_bus_timer failed\n")); ++ ASSERT(0); ++ } ++ if (dhd_stop_cmd_timer(pub)) { ++ DHD_ERROR(("dhd_stop_cmd_timer failed\n")); ++ ASSERT(0); ++ } ++ if (dhd_stop_join_timer(pub)) { ++ DHD_ERROR(("dhd_stop_join_timer failed\n")); ++ ASSERT(0); ++ } ++ ++ dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->scan_timer_lock); ++ dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->join_timer_lock); ++ dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->bus_timer_lock); ++ dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->cmd_timer_lock); ++ MFREE(pub->osh, pub->timeout_info, sizeof(timeout_info_t)); ++ pub->timeout_info = NULL; ++} ++ ++static void ++dhd_cmd_timeout(void *ctx) ++{ ++ dhd_pub_t *pub = (dhd_pub_t *)ctx; ++ unsigned long flags; ++ ++ if (!pub->timeout_info) { ++ DHD_ERROR(("DHD: timeout_info NULL\n")); ++ ASSERT(0); ++ return; ++ } ++ ++ DHD_TIMER_LOCK(pub->timeout_info->cmd_timer_lock, flags); ++ if (pub->timeout_info && pub->timeout_info->cmd_timer_active) { ++ DHD_ERROR(("\nERROR COMMAND TIMEOUT TO:%d\n", pub->timeout_info->cmd_timeout_val)); ++ DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags); ++#ifdef PCIE_OOB ++ /* Assert device_wake so that UART_Rx is available */ ++ if (dhd_bus_set_device_wake(pub->bus, TRUE)) { ++ DHD_ERROR(("%s: dhd_bus_set_device_wake() failed\n", __FUNCTION__)); ++ ASSERT(0); ++ } ++#endif /* PCIE_OOB */ ++ if (dhd_stop_cmd_timer(pub)) { ++ DHD_ERROR(("%s: dhd_stop_cmd_timer() failed\n", __FUNCTION__)); ++ ASSERT(0); ++ } ++ dhd_wakeup_ioctl_event(pub, IOCTL_RETURN_ON_ERROR); ++ if (!dhd_query_bus_erros(pub)) ++ dhd_send_trap_to_fw_for_timeout(pub, DHD_REASON_COMMAND_TO); ++ } else { ++ DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags); ++ } ++} ++ ++int ++dhd_start_cmd_timer(dhd_pub_t *pub) ++{ ++ int ret = BCME_OK; ++ unsigned long flags = 0; ++ uint32 cmd_to_ms; ++ ++ if (!pub->timeout_info) { ++ DHD_ERROR(("DHD: timeout_info NULL\n")); ++ ret = BCME_ERROR; ++ ASSERT(0); ++ goto exit_null; ++ } ++ DHD_TIMER_LOCK(pub->timeout_info->cmd_timer_lock, flags); ++ cmd_to_ms = pub->timeout_info->cmd_timeout_val; ++ ++ if (pub->timeout_info->cmd_timeout_val == 0) { ++ /* Disable Command timer timeout */ ++ DHD_INFO(("DHD: Command Timeout Disabled\n")); ++ goto exit; ++ } ++ if (pub->timeout_info->cmd_timer_active) { ++ DHD_ERROR(("%s:Timer already active\n", __FUNCTION__)); ++ ret = BCME_ERROR; ++ ASSERT(0); ++ } else { ++ pub->timeout_info->cmd_timer = osl_timer_init(pub->osh, ++ "cmd_timer", dhd_cmd_timeout, pub); ++ osl_timer_update(pub->osh, pub->timeout_info->cmd_timer, ++ cmd_to_ms, 0); ++ pub->timeout_info->cmd_timer_active = TRUE; ++ } ++ if (ret == BCME_OK) { ++ DHD_INFO(("%s Cmd Timer started\n", __FUNCTION__)); ++ } ++exit: ++ DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags); ++exit_null: ++ return ret; ++} ++ ++int ++dhd_stop_cmd_timer(dhd_pub_t *pub) ++{ ++ int ret = BCME_OK; ++ unsigned long flags = 0; ++ ++ if (!pub->timeout_info) { ++ DHD_ERROR(("DHD: timeout_info NULL\n")); ++ ret = BCME_ERROR; ++ ASSERT(0); ++ goto exit; ++ } ++ DHD_TIMER_LOCK(pub->timeout_info->cmd_timer_lock, flags); ++ ++ if (pub->timeout_info->cmd_timer_active) { ++ osl_timer_del(pub->osh, pub->timeout_info->cmd_timer); ++ pub->timeout_info->cmd_timer_active = FALSE; ++ } ++ else { ++ DHD_INFO(("DHD: CMD timer is not active\n")); ++ } ++ if (ret == BCME_OK) { ++ DHD_INFO(("%s Cmd Timer Stopped\n", __FUNCTION__)); ++ } ++ DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags); ++exit: ++ return ret; ++} ++ ++static int ++__dhd_stop_join_timer(dhd_pub_t *pub) ++{ ++ int ret = BCME_OK; ++ if (!pub->timeout_info) { ++ DHD_ERROR(("DHD: timeout_info NULL\n")); ++ ASSERT(0); ++ return BCME_ERROR; ++ } ++ ++ if (pub->timeout_info->join_timer_active) { ++ osl_timer_del(pub->osh, pub->timeout_info->join_timer); ++ pub->timeout_info->join_timer_active = FALSE; ++ } else { ++ DHD_INFO(("DHD: JOIN timer is not active\n")); ++ } ++ if (ret == BCME_OK) { ++ DHD_INFO(("%s: Join Timer Stopped\n", __FUNCTION__)); ++ } ++ return ret; ++} ++ ++static void ++dhd_join_timeout(void *ctx) ++{ ++ dhd_pub_t *pub = (dhd_pub_t *)ctx; ++ unsigned long flags; ++ ++ if (!pub->timeout_info) { ++ DHD_ERROR(("DHD: timeout_info NULL\n")); ++ ASSERT(0); ++ return; ++ } ++ ++ DHD_TIMER_LOCK(pub->timeout_info->join_timer_lock, flags); ++ if (pub->timeout_info->join_timer_active) { ++ DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags); ++ if (dhd_stop_join_timer(pub)) { ++ DHD_ERROR(("%s: dhd_stop_join_timer() failed\n", __FUNCTION__)); ++ ASSERT(0); ++ } ++ if (pub->timeout_info->cmd_join_error) { ++ DHD_ERROR(("\nERROR JOIN TIMEOUT TO:%d:0x%x\n", ++ pub->timeout_info->join_timeout_val, ++ pub->timeout_info->cmd_join_error)); ++#ifdef DHD_FW_COREDUMP ++ /* collect core dump and crash */ ++ pub->memdump_enabled = DUMP_MEMFILE_BUGON; ++ pub->memdump_type = DUMP_TYPE_JOIN_TIMEOUT; ++ dhd_bus_mem_dump(pub); ++#endif /* DHD_FW_COREDUMP */ ++ ++ } ++ } else { ++ DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags); ++ } ++} ++ ++int ++dhd_start_join_timer(dhd_pub_t *pub) ++{ ++ int ret = BCME_OK; ++ unsigned long flags = 0; ++ uint32 join_to_ms; ++ ++ if (!pub->timeout_info) { ++ DHD_ERROR(("DHD: timeout_info NULL\n")); ++ ret = BCME_ERROR; ++ ASSERT(0); ++ goto exit; ++ } ++ ++ join_to_ms = pub->timeout_info->join_timeout_val; ++ DHD_TIMER_LOCK(pub->timeout_info->join_timer_lock, flags); ++ if (pub->timeout_info->join_timer_active) { ++ DHD_ERROR(("%s:Stoping active timer\n", __FUNCTION__)); ++ __dhd_stop_join_timer(pub); ++ } ++ if (pub->timeout_info->join_timeout_val == 0) { ++ /* Disable Join timer timeout */ ++ DHD_INFO(("DHD: Join Timeout Disabled\n")); ++ } else { ++ pub->timeout_info->join_timer = osl_timer_init(pub->osh, ++ "join_timer", dhd_join_timeout, pub); ++ osl_timer_update(pub->osh, pub->timeout_info->join_timer, join_to_ms, 0); ++ pub->timeout_info->join_timer_active = TRUE; ++ pub->timeout_info->cmd_join_error |= WLC_SSID_MASK; ++ } ++ if (ret == BCME_OK) { ++ DHD_INFO(("%s:Join Timer started 0x%x\n", __FUNCTION__, ++ pub->timeout_info->cmd_join_error)); ++ } ++ DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags); ++exit: ++ return ret; ++} ++ ++int ++dhd_stop_join_timer(dhd_pub_t *pub) ++{ ++ int ret = BCME_OK; ++ unsigned long flags; ++ ++ DHD_TIMER_LOCK(pub->timeout_info->join_timer_lock, flags); ++ ret = __dhd_stop_join_timer(pub); ++ DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags); ++ return ret; ++} ++ ++static void ++dhd_scan_timeout(void *ctx) ++{ ++ dhd_pub_t *pub = (dhd_pub_t *)ctx; ++ unsigned long flags; ++ ++ if (pub->timeout_info == NULL) { ++ DHD_ERROR(("timeout_info pointer is NULL\n")); ++ ASSERT(0); ++ return; ++ } ++ ++ DHD_TIMER_LOCK(pub->timeout_info->scan_timer_lock, flags); ++ if (pub->timeout_info && pub->timeout_info->scan_timer_active) { ++ DHD_ERROR(("\nERROR SCAN TIMEOUT TO:%d\n", pub->timeout_info->scan_timeout_val)); ++ DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags); ++ dhd_stop_scan_timer(pub); ++ if (!dhd_query_bus_erros(pub)) ++ dhd_send_trap_to_fw_for_timeout(pub, DHD_REASON_SCAN_TO); ++ } else { ++ DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags); ++ } ++} ++ ++int ++dhd_start_scan_timer(dhd_pub_t *pub) ++{ ++ int ret = BCME_OK; ++ unsigned long flags = 0; ++ uint32 scan_to_ms; ++ ++ if (!pub->timeout_info) { ++ DHD_ERROR(("DHD: timeout_info NULL\n")); ++ ret = BCME_ERROR; ++ ASSERT(0); ++ goto exit_null; ++ } ++ DHD_TIMER_LOCK(pub->timeout_info->scan_timer_lock, flags); ++ scan_to_ms = pub->timeout_info->scan_timeout_val; ++ ++ if (pub->timeout_info->scan_timer_active) { ++ /* NOTE : New scan timeout value will be effective ++ * only once current scan is completed. ++ */ ++ DHD_ERROR(("%s:Timer already active\n", __FUNCTION__)); ++ ret = BCME_ERROR; ++ goto exit; ++ } ++ ++ if (pub->timeout_info->scan_timeout_val == 0) { ++ /* Disable Scan timer timeout */ ++ DHD_INFO(("DHD: Scan Timeout Disabled\n")); ++ } else { ++ pub->timeout_info->scan_timer = osl_timer_init(pub->osh, "scan_timer", ++ dhd_scan_timeout, pub); ++ pub->timeout_info->scan_timer_active = TRUE; ++ osl_timer_update(pub->osh, pub->timeout_info->scan_timer, scan_to_ms, 0); ++ } ++ if (ret == BCME_OK) { ++ DHD_INFO(("%s Scan Timer started\n", __FUNCTION__)); ++ } ++exit: ++ DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags); ++exit_null: ++ return ret; ++} ++ ++int ++dhd_stop_scan_timer(dhd_pub_t *pub) ++{ ++ int ret = BCME_OK; ++ unsigned long flags = 0; ++ ++ if (!pub->timeout_info) { ++ DHD_ERROR(("DHD: timeout_info NULL\n")); ++ ret = BCME_ERROR; ++ ASSERT(0); ++ goto exit; ++ } ++ DHD_TIMER_LOCK(pub->timeout_info->scan_timer_lock, flags); ++ ++ if (pub->timeout_info->scan_timer_active) { ++ osl_timer_del(pub->osh, pub->timeout_info->scan_timer); ++ pub->timeout_info->scan_timer_active = FALSE; ++ } ++ else { ++ DHD_INFO(("DHD: SCAN timer is not active\n")); ++ } ++ ++ if (ret == BCME_OK) { ++ DHD_INFO(("%s Scan Timer Stopped\n", __FUNCTION__)); ++ } ++ DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags); ++exit: ++ return ret; ++} ++ ++static void ++dhd_bus_timeout(void *ctx) ++{ ++ dhd_pub_t *pub = (dhd_pub_t *)ctx; ++ unsigned long flags; ++ ++ if (pub->timeout_info == NULL) { ++ DHD_ERROR(("timeout_info pointer is NULL\n")); ++ ASSERT(0); ++ return; ++ } ++ ++ DHD_TIMER_LOCK(pub->timeout_info->bus_timer_lock, flags); ++ if (pub->timeout_info->bus_timer_active) { ++ DHD_ERROR(("\nERROR BUS TIMEOUT TO:%d\n", pub->timeout_info->bus_timeout_val)); ++ DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags); ++#ifdef PCIE_OOB ++ /* Assert device_wake so that UART_Rx is available */ ++ if (dhd_bus_set_device_wake(pub->bus, TRUE)) { ++ DHD_ERROR(("%s: dhd_bus_set_device_wake() failed\n", __FUNCTION__)); ++ ASSERT(0); ++ } ++#endif /* PCIE_OOB */ ++ if (dhd_stop_bus_timer(pub)) { ++ DHD_ERROR(("%s: dhd_stop_bus_timer() failed\n", __FUNCTION__)); ++ ASSERT(0); ++ } ++ if (!dhd_query_bus_erros(pub)) ++ dhd_send_trap_to_fw_for_timeout(pub, DHD_REASON_OQS_TO); ++ } else { ++ DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags); ++ } ++} ++ ++int ++dhd_start_bus_timer(dhd_pub_t *pub) ++{ ++ int ret = BCME_OK; ++ unsigned long flags = 0; ++ uint32 bus_to_ms; ++ ++ if (!pub->timeout_info) { ++ DHD_ERROR(("DHD: timeout_info NULL\n")); ++ ret = BCME_ERROR; ++ ASSERT(0); ++ goto exit_null; ++ } ++ DHD_TIMER_LOCK(pub->timeout_info->bus_timer_lock, flags); ++ bus_to_ms = pub->timeout_info->bus_timeout_val; ++ ++ if (pub->timeout_info->bus_timeout_val == 0) { ++ /* Disable Bus timer timeout */ ++ DHD_INFO(("DHD: Bus Timeout Disabled\n")); ++ goto exit; ++ } ++ if (pub->timeout_info->bus_timer_active) { ++ DHD_ERROR(("%s:Timer already active\n", __FUNCTION__)); ++ ret = BCME_ERROR; ++ ASSERT(0); ++ } else { ++ pub->timeout_info->bus_timer = osl_timer_init(pub->osh, ++ "bus_timer", dhd_bus_timeout, pub); ++ pub->timeout_info->bus_timer_active = TRUE; ++ osl_timer_update(pub->osh, pub->timeout_info->bus_timer, bus_to_ms, 0); ++ } ++ if (ret == BCME_OK) { ++ DHD_INFO(("%s: BUS Timer started\n", __FUNCTION__)); ++ } ++exit: ++ DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags); ++exit_null: ++ return ret; ++} ++ ++int ++dhd_stop_bus_timer(dhd_pub_t *pub) ++{ ++ int ret = BCME_OK; ++ unsigned long flags = 0; ++ ++ if (!pub->timeout_info) { ++ DHD_ERROR(("DHD: timeout_info NULL\n")); ++ ret = BCME_ERROR; ++ ASSERT(0); ++ goto exit; ++ } ++ DHD_TIMER_LOCK(pub->timeout_info->bus_timer_lock, flags); ++ ++ if (pub->timeout_info->bus_timer_active) { ++ osl_timer_del(pub->osh, pub->timeout_info->bus_timer); ++ pub->timeout_info->bus_timer_active = FALSE; ++ } ++ else { ++ DHD_INFO(("DHD: BUS timer is not active\n")); ++ } ++ if (ret == BCME_OK) { ++ DHD_INFO(("%s: Bus Timer Stopped\n", __FUNCTION__)); ++ } ++ DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags); ++exit: ++ return ret; ++} ++ ++int ++dhd_set_request_id(dhd_pub_t *pub, uint16 id, uint32 cmd) ++{ ++ DHD_INFO(("%s: id:%d\n", __FUNCTION__, id)); ++ if (pub->timeout_info) { ++ pub->timeout_info->cmd_request_id = id; ++ pub->timeout_info->cmd = cmd; ++ return BCME_OK; ++ } else { ++ return BCME_ERROR; ++ } ++} ++ ++uint16 ++dhd_get_request_id(dhd_pub_t *pub) ++{ ++ if (pub->timeout_info) { ++ return (pub->timeout_info->cmd_request_id); ++ } else { ++ return 0; ++ } ++} ++ ++void ++dhd_set_join_error(dhd_pub_t *pub, uint32 mask) ++{ ++ DHD_INFO(("Setting join Error %d\n", mask)); ++ if (pub->timeout_info) { ++ pub->timeout_info->cmd_join_error |= mask; ++ } ++} ++ ++void ++dhd_clear_join_error(dhd_pub_t *pub, uint32 mask) ++{ ++ DHD_INFO(("clear join Error %d\n", mask)); ++ if (pub->timeout_info) { ++ pub->timeout_info->cmd_join_error &= ~mask; ++ } ++} ++ ++void ++dhd_get_scan_to_val(dhd_pub_t *pub, uint32 *to_val) ++{ ++ if (pub->timeout_info) { ++ *to_val = pub->timeout_info->scan_timeout_val; ++ } else { ++ *to_val = 0; ++ } ++} ++ ++void ++dhd_set_scan_to_val(dhd_pub_t *pub, uint32 to_val) ++{ ++ if (pub->timeout_info) { ++ DHD_INFO(("Setting TO val:%d\n", to_val)); ++ pub->timeout_info->scan_timeout_val = to_val; ++ } ++} ++ ++void ++dhd_get_join_to_val(dhd_pub_t *pub, uint32 *to_val) ++{ ++ if (pub->timeout_info) { ++ *to_val = pub->timeout_info->join_timeout_val; ++ } else { ++ *to_val = 0; ++ } ++} ++ ++void ++dhd_set_join_to_val(dhd_pub_t *pub, uint32 to_val) ++{ ++ if (pub->timeout_info) { ++ DHD_INFO(("Setting TO val:%d\n", to_val)); ++ pub->timeout_info->join_timeout_val = to_val; ++ } ++} ++ ++void ++dhd_get_cmd_to_val(dhd_pub_t *pub, uint32 *to_val) ++{ ++ if (pub->timeout_info) { ++ *to_val = pub->timeout_info->cmd_timeout_val; ++ } else { ++ *to_val = 0; ++ } ++} ++ ++void ++dhd_set_cmd_to_val(dhd_pub_t *pub, uint32 to_val) ++{ ++ if (pub->timeout_info) { ++ DHD_INFO(("Setting TO val:%d\n", to_val)); ++ pub->timeout_info->cmd_timeout_val = to_val; ++ } ++} ++ ++void ++dhd_get_bus_to_val(dhd_pub_t *pub, uint32 *to_val) ++{ ++ if (pub->timeout_info) { ++ *to_val = pub->timeout_info->bus_timeout_val; ++ } else { ++ *to_val = 0; ++ } ++} ++ ++void ++dhd_set_bus_to_val(dhd_pub_t *pub, uint32 to_val) ++{ ++ if (pub->timeout_info) { ++ DHD_INFO(("Setting TO val:%d\n", to_val)); ++ pub->timeout_info->bus_timeout_val = to_val; ++ } ++} ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++#ifdef SHOW_LOGTRACE ++int ++dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, ++ dhd_event_log_t *event_log) ++{ ++ logstr_header_t *hdr = NULL; ++ uint32 *lognums = NULL; ++ char *logstrs = NULL; ++ int ram_index = 0; ++ char **fmts; ++ int num_fmts = 0; ++ int32 i = 0; ++ ++ /* Remember header from the logstrs.bin file */ ++ hdr = (logstr_header_t *) (raw_fmts + logstrs_size - ++ sizeof(logstr_header_t)); ++ ++ if (hdr->log_magic == LOGSTRS_MAGIC) { ++ /* ++ * logstrs.bin start with header. ++ */ ++ num_fmts = hdr->rom_logstrs_offset / sizeof(uint32); ++ ram_index = (hdr->ram_lognums_offset - ++ hdr->rom_lognums_offset) / sizeof(uint32); ++ lognums = (uint32 *) &raw_fmts[hdr->rom_lognums_offset]; ++ logstrs = (char *) &raw_fmts[hdr->rom_logstrs_offset]; ++ } else { ++ /* ++ * Legacy logstrs.bin format without header. ++ */ ++ num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32); ++ if (num_fmts == 0) { ++ /* Legacy ROM/RAM logstrs.bin format: ++ * - ROM 'lognums' section ++ * - RAM 'lognums' section ++ * - ROM 'logstrs' section. ++ * - RAM 'logstrs' section. ++ * ++ * 'lognums' is an array of indexes for the strings in the ++ * 'logstrs' section. The first uint32 is 0 (index of first ++ * string in ROM 'logstrs' section). ++ * ++ * The 4324b5 is the only ROM that uses this legacy format. Use the ++ * fixed number of ROM fmtnums to find the start of the RAM ++ * 'lognums' section. Use the fixed first ROM string ("Con\n") to ++ * find the ROM 'logstrs' section. ++ */ ++ #define NUM_4324B5_ROM_FMTS 186 ++ #define FIRST_4324B5_ROM_LOGSTR "Con\n" ++ ram_index = NUM_4324B5_ROM_FMTS; ++ lognums = (uint32 *) raw_fmts; ++ num_fmts = ram_index; ++ logstrs = (char *) &raw_fmts[num_fmts << 2]; ++ while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) { ++ num_fmts++; ++ logstrs = (char *) &raw_fmts[num_fmts << 2]; ++ } ++ } else { ++ /* Legacy RAM-only logstrs.bin format: ++ * - RAM 'lognums' section ++ * - RAM 'logstrs' section. ++ * ++ * 'lognums' is an array of indexes for the strings in the ++ * 'logstrs' section. The first uint32 is an index to the ++ * start of 'logstrs'. Therefore, if this index is divided ++ * by 'sizeof(uint32)' it provides the number of logstr ++ * entries. ++ */ ++ ram_index = 0; ++ lognums = (uint32 *) raw_fmts; ++ logstrs = (char *) &raw_fmts[num_fmts << 2]; ++ } ++ } ++ fmts = MALLOC(osh, num_fmts * sizeof(char *)); ++ if (fmts == NULL) { ++ DHD_ERROR(("%s: Failed to allocate fmts memory\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ event_log->fmts_size = num_fmts * sizeof(char *); ++ ++ for (i = 0; i < num_fmts; i++) { ++ /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base ++ * (they are 0-indexed relative to 'rom_logstrs_offset'). ++ * ++ * RAM lognums are already indexed to point to the correct RAM logstrs (they ++ * are 0-indexed relative to the start of the logstrs.bin file). ++ */ ++ if (i == ram_index) { ++ logstrs = raw_fmts; ++ } ++ fmts[i] = &logstrs[lognums[i]]; ++ } ++ event_log->fmts = fmts; ++ event_log->raw_fmts_size = logstrs_size; ++ event_log->raw_fmts = raw_fmts; ++ event_log->num_fmts = num_fmts; ++ ++ return BCME_OK; ++} ++ ++int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart, uint32 *rodata_start, ++ uint32 *rodata_end) ++{ ++ char *raw_fmts = NULL; ++ uint32 read_size = READ_NUM_BYTES; ++ int error = 0; ++ char * cptr = NULL; ++ char c; ++ uint8 count = 0; ++ ++ *ramstart = 0; ++ *rodata_start = 0; ++ *rodata_end = 0; ++ ++ /* Allocate 1 byte more than read_size to terminate it with NULL */ ++ raw_fmts = MALLOC(osh, read_size + 1); ++ if (raw_fmts == NULL) { ++ DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* read ram start, rodata_start and rodata_end values from map file */ ++ while (count != ALL_MAP_VAL) ++ { ++ error = dhd_os_read_file(file, raw_fmts, read_size); ++ if (error < 0) { ++ DHD_ERROR(("%s: map file read failed err:%d \n", __FUNCTION__, ++ error)); ++ goto fail; ++ } ++ ++ /* End raw_fmts with NULL as strstr expects NULL terminated strings */ ++ raw_fmts[read_size] = '\0'; ++ ++ /* Get ramstart address */ ++ if ((cptr = strstr(raw_fmts, ramstart_str))) { ++ cptr = cptr - BYTES_AHEAD_NUM; ++ sscanf(cptr, "%x %c text_start", ramstart, &c); ++ count |= RAMSTART_BIT; ++ } ++ ++ /* Get ram rodata start address */ ++ if ((cptr = strstr(raw_fmts, rodata_start_str))) { ++ cptr = cptr - BYTES_AHEAD_NUM; ++ sscanf(cptr, "%x %c rodata_start", rodata_start, &c); ++ count |= RDSTART_BIT; ++ } ++ ++ /* Get ram rodata end address */ ++ if ((cptr = strstr(raw_fmts, rodata_end_str))) { ++ cptr = cptr - BYTES_AHEAD_NUM; ++ sscanf(cptr, "%x %c rodata_end", rodata_end, &c); ++ count |= RDEND_BIT; ++ } ++ ++ if (error < (int)read_size) { ++ /* ++ * since we reset file pos back to earlier pos by ++ * GO_BACK_FILE_POS_NUM_BYTES bytes we won't reach EOF. ++ * The reason for this is if string is spreaded across ++ * bytes, the read function should not miss it. ++ * So if ret value is less than read_size, reached EOF don't read further ++ */ ++ break; ++ } ++ memset(raw_fmts, 0, read_size); ++ /* ++ * go back to predefined NUM of bytes so that we won't miss ++ * the string and addr even if it comes as splited in next read. ++ */ ++ dhd_os_seek_file(file, -GO_BACK_FILE_POS_NUM_BYTES); ++ } ++ ++ ++fail: ++ if (raw_fmts) { ++ MFREE(osh, raw_fmts, read_size + 1); ++ raw_fmts = NULL; ++ } ++ if (count == ALL_MAP_VAL) ++ return BCME_OK; ++ else { ++ DHD_ERROR(("%s: readmap error 0X%x \n", __FUNCTION__, ++ count)); ++ return BCME_ERROR; ++ } ++ ++} ++ ++#ifdef PCIE_FULL_DONGLE ++int ++dhd_event_logtrace_infobuf_pkt_process(dhd_pub_t *dhdp, void *pktbuf, ++ dhd_event_log_t *event_data) ++{ ++ uint32 infobuf_version; ++ info_buf_payload_hdr_t *payload_hdr_ptr; ++ uint16 payload_hdr_type; ++ uint16 payload_hdr_length; ++ ++ DHD_TRACE(("%s:Enter\n", __FUNCTION__)); ++ ++ if (PKTLEN(dhdp->osh, pktbuf) < sizeof(uint32)) { ++ DHD_ERROR(("%s: infobuf too small for version field\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ infobuf_version = *((uint32 *)PKTDATA(dhdp->osh, pktbuf)); ++ PKTPULL(dhdp->osh, pktbuf, sizeof(uint32)); ++ if (infobuf_version != PCIE_INFOBUF_V1) { ++ DHD_ERROR(("%s: infobuf version %d is not PCIE_INFOBUF_V1\n", ++ __FUNCTION__, infobuf_version)); ++ goto exit; ++ } ++ ++ /* Version 1 infobuf has a single type/length (and then value) field */ ++ if (PKTLEN(dhdp->osh, pktbuf) < sizeof(info_buf_payload_hdr_t)) { ++ DHD_ERROR(("%s: infobuf too small for v1 type/length fields\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ /* Process/parse the common info payload header (type/length) */ ++ payload_hdr_ptr = (info_buf_payload_hdr_t *)PKTDATA(dhdp->osh, pktbuf); ++ payload_hdr_type = ltoh16(payload_hdr_ptr->type); ++ payload_hdr_length = ltoh16(payload_hdr_ptr->length); ++ if (payload_hdr_type != PCIE_INFOBUF_V1_TYPE_LOGTRACE) { ++ DHD_ERROR(("%s: payload_hdr_type %d is not V1_TYPE_LOGTRACE\n", ++ __FUNCTION__, payload_hdr_type)); ++ goto exit; ++ } ++ PKTPULL(dhdp->osh, pktbuf, sizeof(info_buf_payload_hdr_t)); ++ ++ /* Validate that the specified length isn't bigger than the ++ * provided data. ++ */ ++ if (payload_hdr_length > PKTLEN(dhdp->osh, pktbuf)) { ++ DHD_ERROR(("%s: infobuf logtrace length is bigger" ++ " than actual buffer data\n", __FUNCTION__)); ++ goto exit; ++ } ++ dhd_dbg_trace_evnt_handler(dhdp, PKTDATA(dhdp->osh, pktbuf), ++ event_data, payload_hdr_length); ++ ++ return BCME_OK; ++ ++exit: ++ return BCME_ERROR; ++} ++#endif /* PCIE_FULL_DONGLE */ ++#endif /* SHOW_LOGTRACE */ ++ ++#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) ++ ++/* To handle the TDLS event in the dhd_common.c ++ */ ++int dhd_tdls_event_handler(dhd_pub_t *dhd_pub, wl_event_msg_t *event) ++{ ++ int ret = BCME_OK; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ ret = dhd_tdls_update_peer_info(dhd_pub, event); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ return ret; ++} ++ ++int dhd_free_tdls_peer_list(dhd_pub_t *dhd_pub) ++{ ++ tdls_peer_node_t *cur = NULL, *prev = NULL; ++ if (!dhd_pub) ++ return BCME_ERROR; ++ cur = dhd_pub->peer_tbl.node; ++ ++ if ((dhd_pub->peer_tbl.node == NULL) && !dhd_pub->peer_tbl.tdls_peer_count) ++ return BCME_ERROR; ++ ++ while (cur != NULL) { ++ prev = cur; ++ cur = cur->next; ++ MFREE(dhd_pub->osh, prev, sizeof(tdls_peer_node_t)); ++ } ++ dhd_pub->peer_tbl.tdls_peer_count = 0; ++ dhd_pub->peer_tbl.node = NULL; ++ return BCME_OK; ++} ++#endif /* #if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */ ++ ++#ifdef DUMP_IOCTL_IOV_LIST ++void ++dhd_iov_li_append(dhd_pub_t *dhd, dll_t *list_head, dll_t *node) ++{ ++ dll_t *item; ++ dhd_iov_li_t *iov_li; ++ dhd->dump_iovlist_len++; ++ ++ if (dhd->dump_iovlist_len == IOV_LIST_MAX_LEN+1) { ++ item = dll_head_p(list_head); ++ iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list); ++ dll_delete(item); ++ MFREE(dhd->osh, iov_li, sizeof(*iov_li)); ++ dhd->dump_iovlist_len--; ++ } ++ dll_append(list_head, node); ++} ++ ++void ++dhd_iov_li_print(dll_t *list_head) ++{ ++ dhd_iov_li_t *iov_li; ++ dll_t *item, *next; ++ uint8 index = 0; ++ for (item = dll_head_p(list_head); !dll_end(list_head, item); item = next) { ++ next = dll_next_p(item); ++ iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list); ++ index++; ++ DHD_ERROR(("%d:cmd_name = %s, cmd = %d.\n", index, iov_li->buff, iov_li->cmd)); ++ } ++} ++ ++void ++dhd_iov_li_delete(dhd_pub_t *dhd, dll_t *list_head) ++{ ++ dll_t *item; ++ dhd_iov_li_t *iov_li; ++ while (!(dll_empty(list_head))) { ++ item = dll_head_p(list_head); ++ iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list); ++ dll_delete(item); ++ MFREE(dhd->osh, iov_li, sizeof(*iov_li)); ++ } ++} ++#endif /* DUMP_IOCTL_IOV_LIST */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_config.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_config.c +new file mode 100644 +index 000000000..af05a3f6d +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_config.c +@@ -0,0 +1,3851 @@ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#if defined(HW_OOB) || defined(FORCE_WOWLAN) ++#include ++#include ++#include ++#include ++#endif ++#ifdef WL_CFG80211 ++#include ++#endif ++ ++#include ++#include ++#include ++ ++/* message levels */ ++#define CONFIG_ERROR_LEVEL (1 << 0) ++#define CONFIG_TRACE_LEVEL (1 << 1) ++#define CONFIG_MSG_LEVEL (1 << 0) ++ ++uint config_msg_level = CONFIG_ERROR_LEVEL | CONFIG_MSG_LEVEL; ++uint dump_msg_level = 0; ++ ++#define CONFIG_MSG(x, args...) \ ++ do { \ ++ if (config_msg_level & CONFIG_MSG_LEVEL) { \ ++ printk(KERN_ERR "[dhd] %s : " x, __func__, ## args); \ ++ } \ ++ } while (0) ++#define CONFIG_ERROR(x, args...) \ ++ do { \ ++ if (config_msg_level & CONFIG_ERROR_LEVEL) { \ ++ printk(KERN_ERR "[dhd] CONFIG-ERROR) %s : " x, __func__, ## args); \ ++ } \ ++ } while (0) ++#define CONFIG_TRACE(x, args...) \ ++ do { \ ++ if (config_msg_level & CONFIG_TRACE_LEVEL) { \ ++ printk(KERN_INFO "[dhd] CONFIG-TRACE) %s : " x, __func__, ## args); \ ++ } \ ++ } while (0) ++ ++#define MAXSZ_BUF 4096 ++#define MAXSZ_CONFIG 8192 ++ ++#ifndef WL_CFG80211 ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++#endif ++ ++#if defined(SUSPEND_EVENT) && defined(PROP_TXSTATUS) ++#if defined(BCMSDIO) || defined(BCMDBUS) ++#include ++#endif /* BCMSDIO || BCMDBUS */ ++#endif /* SUSPEND_EVENT && PROP_TXSTATUS */ ++ ++#define MAX_EVENT_BUF_NUM 16 ++typedef struct eventmsg_buf { ++ u16 num; ++ struct { ++ u16 type; ++ bool set; ++ } event [MAX_EVENT_BUF_NUM]; ++} eventmsg_buf_t; ++ ++typedef struct cihp_name_map_t { ++ uint chip; ++ uint chiprev; ++ uint ag_type; ++ char *chip_name; ++ char *module_name; ++} cihp_name_map_t; ++ ++/* Map of WLC_E events to connection failure strings */ ++#define DONT_CARE 9999 ++const cihp_name_map_t chip_name_map[] = { ++ /* ChipID Chiprev AG ChipName ModuleName */ ++#ifdef BCMSDIO ++ {BCM43362_CHIP_ID, 0, DONT_CARE, "bcm40181a0", ""}, ++ {BCM43362_CHIP_ID, 1, DONT_CARE, "bcm40181a2", ""}, ++ {BCM4330_CHIP_ID, 4, FW_TYPE_G, "bcm40183b2", ""}, ++ {BCM4330_CHIP_ID, 4, FW_TYPE_AG, "bcm40183b2_ag", ""}, ++ {BCM43430_CHIP_ID, 0, DONT_CARE, "bcm43438a0", ""}, ++ {BCM43430_CHIP_ID, 1, DONT_CARE, "bcm43438a1", ""}, ++ {BCM43430_CHIP_ID, 2, DONT_CARE, "bcm43436b0", ""}, ++ {BCM43012_CHIP_ID, 1, FW_TYPE_G, "bcm43013b0", ""}, ++ {BCM43012_CHIP_ID, 1, FW_TYPE_AG, "bcm43013c0_ag", ""}, ++ {BCM43012_CHIP_ID, 2, DONT_CARE, "bcm43013c1_ag", ""}, ++ {BCM4334_CHIP_ID, 3, DONT_CARE, "bcm4334b1_ag", ""}, ++ {BCM43340_CHIP_ID, 2, DONT_CARE, "bcm43341b0_ag", ""}, ++ {BCM43341_CHIP_ID, 2, DONT_CARE, "bcm43341b0_ag", ""}, ++ {BCM4324_CHIP_ID, 5, DONT_CARE, "bcm43241b4_ag", ""}, ++ {BCM4335_CHIP_ID, 2, DONT_CARE, "bcm4339a0_ag", ""}, ++ {BCM4339_CHIP_ID, 1, DONT_CARE, "bcm4339a0_ag", ""}, ++ {BCM4345_CHIP_ID, 6, DONT_CARE, "bcm43455c0_ag", ""}, ++ {BCM43454_CHIP_ID, 6, DONT_CARE, "bcm43455c0_ag", ""}, ++ {BCM4345_CHIP_ID, 9, DONT_CARE, "bcm43456c5_ag", ""}, ++ {BCM43454_CHIP_ID, 9, DONT_CARE, "bcm43456c5_ag", ""}, ++ {BCM4354_CHIP_ID, 1, DONT_CARE, "bcm4354a1_ag", ""}, ++ {BCM4354_CHIP_ID, 2, DONT_CARE, "bcm4356a2_ag", ""}, ++ {BCM4356_CHIP_ID, 2, DONT_CARE, "bcm4356a2_ag", ""}, ++ {BCM4371_CHIP_ID, 2, DONT_CARE, "bcm4356a2_ag", ""}, ++ {BCM43569_CHIP_ID, 3, DONT_CARE, "bcm4358a3_ag", ""}, ++ {BCM4359_CHIP_ID, 5, DONT_CARE, "bcm4359b1_ag", ""}, ++ {BCM4359_CHIP_ID, 9, DONT_CARE, "bcm4359c0_ag", ""}, ++#endif ++#ifdef BCMPCIE ++ {BCM4354_CHIP_ID, 2, DONT_CARE, "bcm4356a2_pcie_ag", ""}, ++ {BCM4356_CHIP_ID, 2, DONT_CARE, "bcm4356a2_pcie_ag", ""}, ++ {BCM4359_CHIP_ID, 9, DONT_CARE, "bcm4359c0_pcie_ag", ""}, ++#endif ++#ifdef BCMDBUS ++ {BCM43143_CHIP_ID, 2, DONT_CARE, "bcm43143b0", ""}, ++ {BCM43242_CHIP_ID, 1, DONT_CARE, "bcm43242a1_ag", ""}, ++ {BCM43569_CHIP_ID, 2, DONT_CARE, "bcm4358u_ag", ""}, ++#endif ++}; ++ ++void ++dhd_conf_free_chip_nv_path_list(wl_chip_nv_path_list_ctrl_t *chip_nv_list) ++{ ++ CONFIG_TRACE("called\n"); ++ ++ if (chip_nv_list->m_chip_nv_path_head) { ++ CONFIG_TRACE("Free %p\n", chip_nv_list->m_chip_nv_path_head); ++ kfree(chip_nv_list->m_chip_nv_path_head); ++ } ++ chip_nv_list->count = 0; ++} ++ ++#ifdef BCMSDIO ++void ++dhd_conf_free_mac_list(wl_mac_list_ctrl_t *mac_list) ++{ ++ int i; ++ ++ CONFIG_TRACE("called\n"); ++ if (mac_list->m_mac_list_head) { ++ for (i=0; icount; i++) { ++ if (mac_list->m_mac_list_head[i].mac) { ++ CONFIG_TRACE("Free mac %p\n", mac_list->m_mac_list_head[i].mac); ++ kfree(mac_list->m_mac_list_head[i].mac); ++ } ++ } ++ CONFIG_TRACE("Free m_mac_list_head %p\n", mac_list->m_mac_list_head); ++ kfree(mac_list->m_mac_list_head); ++ } ++ mac_list->count = 0; ++} ++ ++#if defined(HW_OOB) || defined(FORCE_WOWLAN) ++void ++dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip) ++{ ++ uint32 gpiocontrol, addr; ++ ++ if (CHIPID(chip) == BCM43362_CHIP_ID) { ++ CONFIG_MSG("Enable HW OOB for 43362\n"); ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, gpiocontrol); ++ gpiocontrol = bcmsdh_reg_read(sdh, addr, 4); ++ gpiocontrol |= 0x2; ++ bcmsdh_reg_write(sdh, addr, 4, gpiocontrol); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL); ++ } ++} ++#endif ++ ++#define SBSDIO_CIS_SIZE_LIMIT 0x200 ++#define F0_BLOCK_SIZE 32 ++int ++dhd_conf_set_blksize(bcmsdh_info_t *sdh) ++{ ++ int err = 0; ++ uint fn, numfn; ++ int32 blksize = 0, cur_blksize = 0; ++ uint8 cisd; ++ ++ numfn = bcmsdh_query_iofnum(sdh); ++ ++ for (fn = 0; fn <= numfn; fn++) { ++ if (!fn) ++ blksize = F0_BLOCK_SIZE; ++ else { ++ bcmsdh_cisaddr_read(sdh, fn, &cisd, 24); ++ blksize = cisd; ++ bcmsdh_cisaddr_read(sdh, fn, &cisd, 25); ++ blksize |= cisd << 8; ++ } ++#ifdef CUSTOM_SDIO_F2_BLKSIZE ++ if (fn == 2 && blksize > CUSTOM_SDIO_F2_BLKSIZE) { ++ blksize = CUSTOM_SDIO_F2_BLKSIZE; ++ } ++#endif ++ bcmsdh_iovar_op(sdh, "sd_blocksize", &fn, sizeof(int32), ++ &cur_blksize, sizeof(int32), FALSE); ++ if (cur_blksize != blksize) { ++ CONFIG_MSG("fn=%d, blksize=%d, cur_blksize=%d\n", ++ fn, blksize, cur_blksize); ++ blksize |= (fn<<16); ++ if (bcmsdh_iovar_op(sdh, "sd_blocksize", NULL, 0, &blksize, ++ sizeof(blksize), TRUE) != BCME_OK) { ++ CONFIG_ERROR("fail on get sd_blocksize"); ++ err = -1; ++ } ++ } ++ } ++ ++ return err; ++} ++ ++void ++dhd_conf_get_otp(dhd_pub_t *dhd, bcmsdh_info_t *sdh) ++{ ++ int i, err = -1; ++ uint8 *ptr = 0, *ptpl_code = NULL; ++ unsigned char tpl_code, tpl_link='\0'; ++ uint8 mac_header[3] = {0x80, 0x07, 0x19}; ++ uint8 *cis; ++ ++ if (!(cis = MALLOC(dhd->osh, SBSDIO_CIS_SIZE_LIMIT))) { ++ CONFIG_ERROR("cis malloc failed\n"); ++ } ++ bzero(cis, SBSDIO_CIS_SIZE_LIMIT); ++ ++ if ((err = bcmsdh_cis_read(sdh, 0, cis, SBSDIO_CIS_SIZE_LIMIT))) { ++ CONFIG_ERROR("cis read err %d\n", err); ++ MFREE(dhd->osh, cis, SBSDIO_CIS_SIZE_LIMIT); ++ return; ++ } ++ ptr = cis; ++ do { ++ /* 0xff means we're done */ ++ tpl_code = *ptr; ++ ptpl_code = ptr; ++ ptr++; ++ if (tpl_code == 0xff) ++ break; ++ ++ /* null entries have no link field or data */ ++ if (tpl_code == 0x00) ++ continue; ++ ++ tpl_link = *ptr; ++ ptr++; ++ /* a size of 0xff also means we're done */ ++ if (tpl_link == 0xff) ++ break; ++ if (config_msg_level & CONFIG_TRACE_LEVEL) { ++ prhex("TPL", ptpl_code, tpl_link+2); ++ } ++ ++ if (tpl_code == 0x80 && tpl_link == 0x07 && *ptr == 0x19) { ++ memcpy(&dhd->conf->otp_mac, ptr+1, 6); ++ } ++#ifdef GET_OTP_MODULE_NAME ++ else if (tpl_code == 0x8e && *ptr == 0x41) { ++ int len = tpl_link - 1; ++ if (len <= sizeof(dhd->conf->module_name) - 1) { ++ strncpy(dhd->conf->module_name, ptr+1, len); ++ CONFIG_MSG("module_name=%s\n", dhd->conf->module_name); ++ } else { ++ CONFIG_ERROR("len is too long %d >= %d\n", ++ len, (int)sizeof(dhd->conf->module_name) - 1); ++ } ++ } ++#endif ++ ++ ptr += tpl_link; ++ } while (1); ++ ++ if (!memcmp(ðer_null, &dhd->conf->otp_mac, ETHER_ADDR_LEN)) { ++ ptr = cis; ++ /* Special OTP */ ++ if (bcmsdh_reg_read(sdh, SI_ENUM_BASE, 4) == 0x16044330) { ++ for (i=0; iconf->otp_mac, ptr+3, 6); ++ break; ++ } ++ ptr++; ++ } ++ } ++ } ++ ++ ASSERT(cis); ++ MFREE(dhd->osh, cis, SBSDIO_CIS_SIZE_LIMIT); ++} ++ ++void ++dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, char *fw_path) ++{ ++ int i, j; ++ uint8 *mac = (uint8 *)&dhd->conf->otp_mac; ++ int fw_num=0, mac_num=0; ++ uint32 oui, nic; ++ wl_mac_list_t *mac_list; ++ wl_mac_range_t *mac_range; ++ int fw_type, fw_type_new; ++ char *name_ptr; ++ ++ mac_list = dhd->conf->fw_by_mac.m_mac_list_head; ++ fw_num = dhd->conf->fw_by_mac.count; ++ if (!mac_list || !fw_num) ++ return; ++ ++ oui = (mac[0] << 16) | (mac[1] << 8) | (mac[2]); ++ nic = (mac[3] << 16) | (mac[4] << 8) | (mac[5]); ++ ++ /* find out the last '/' */ ++ i = strlen(fw_path); ++ while (i > 0) { ++ if (fw_path[i] == '/') { ++ i++; ++ break; ++ } ++ i--; ++ } ++ name_ptr = &fw_path[i]; ++ ++ if (strstr(name_ptr, "_apsta")) ++ fw_type = FW_TYPE_APSTA; ++ else if (strstr(name_ptr, "_p2p")) ++ fw_type = FW_TYPE_P2P; ++ else if (strstr(name_ptr, "_mesh")) ++ fw_type = FW_TYPE_MESH; ++ else if (strstr(name_ptr, "_es")) ++ fw_type = FW_TYPE_ES; ++ else if (strstr(name_ptr, "_mfg")) ++ fw_type = FW_TYPE_MFG; ++ else ++ fw_type = FW_TYPE_STA; ++ ++ for (i=0; i= mac_range[j].nic_start && nic <= mac_range[j].nic_end) { ++ strcpy(name_ptr, mac_list[i].name); ++ CONFIG_MSG("matched oui=0x%06X, nic=0x%06X\n", oui, nic); ++ CONFIG_MSG("fw_path=%s\n", fw_path); ++ return; ++ } ++ } ++ } ++ } ++} ++ ++void ++dhd_conf_set_nv_name_by_mac(dhd_pub_t *dhd, char *nv_path) ++{ ++ int i, j; ++ uint8 *mac = (uint8 *)&dhd->conf->otp_mac; ++ int nv_num=0, mac_num=0; ++ uint32 oui, nic; ++ wl_mac_list_t *mac_list; ++ wl_mac_range_t *mac_range; ++ char *pnv_name; ++ ++ mac_list = dhd->conf->nv_by_mac.m_mac_list_head; ++ nv_num = dhd->conf->nv_by_mac.count; ++ if (!mac_list || !nv_num) ++ return; ++ ++ oui = (mac[0] << 16) | (mac[1] << 8) | (mac[2]); ++ nic = (mac[3] << 16) | (mac[4] << 8) | (mac[5]); ++ ++ /* find out the last '/' */ ++ i = strlen(nv_path); ++ while (i > 0) { ++ if (nv_path[i] == '/') break; ++ i--; ++ } ++ pnv_name = &nv_path[i+1]; ++ ++ for (i=0; i= mac_range[j].nic_start && nic <= mac_range[j].nic_end) { ++ strcpy(pnv_name, mac_list[i].name); ++ CONFIG_MSG("matched oui=0x%06X, nic=0x%06X\n", oui, nic); ++ CONFIG_MSG("nv_path=%s\n", nv_path); ++ return; ++ } ++ } ++ } ++ } ++} ++#endif ++ ++void ++dhd_conf_free_country_list(struct dhd_conf *conf) ++{ ++ country_list_t *country = conf->country_head; ++ int count = 0; ++ ++ CONFIG_TRACE("called\n"); ++ while (country) { ++ CONFIG_TRACE("Free cspec %s\n", country->cspec.country_abbrev); ++ conf->country_head = country->next; ++ kfree(country); ++ country = conf->country_head; ++ count++; ++ } ++ CONFIG_TRACE("%d country released\n", count); ++} ++ ++void ++dhd_conf_free_mchan_list(struct dhd_conf *conf) ++{ ++ mchan_params_t *mchan = conf->mchan; ++ int count = 0; ++ ++ CONFIG_TRACE("called\n"); ++ while (mchan) { ++ CONFIG_TRACE("Free cspec %p\n", mchan); ++ conf->mchan = mchan->next; ++ kfree(mchan); ++ mchan = conf->mchan; ++ count++; ++ } ++ CONFIG_TRACE("%d mchan released\n", count); ++} ++ ++int ++dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) ++{ ++ int fw_type, ag_type; ++ uint chip, chiprev; ++ int i; ++ char *name_ptr; ++ ++ chip = dhd->conf->chip; ++ chiprev = dhd->conf->chiprev; ++ ++ if (fw_path[0] == '\0') { ++#ifdef CONFIG_BCMDHD_FW_PATH ++ bcm_strncpy_s(fw_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1); ++ if (fw_path[0] == '\0') ++#endif ++ { ++ CONFIG_MSG("firmware path is null\n"); ++ return 0; ++ } ++ } ++#ifndef FW_PATH_AUTO_SELECT ++ return DONT_CARE; ++#endif ++ ++ /* find out the last '/' */ ++ i = strlen(fw_path); ++ while (i > 0) { ++ if (fw_path[i] == '/') { ++ i++; ++ break; ++ } ++ i--; ++ } ++ name_ptr = &fw_path[i]; ++#ifdef BAND_AG ++ ag_type = FW_TYPE_AG; ++#else ++ ag_type = strstr(name_ptr, "_ag") ? FW_TYPE_AG : FW_TYPE_G; ++#endif ++ if (strstr(name_ptr, "_apsta")) ++ fw_type = FW_TYPE_APSTA; ++ else if (strstr(name_ptr, "_p2p")) ++ fw_type = FW_TYPE_P2P; ++ else if (strstr(name_ptr, "_mesh")) ++ fw_type = FW_TYPE_MESH; ++ else if (strstr(name_ptr, "_es")) ++ fw_type = FW_TYPE_ES; ++ else if (strstr(name_ptr, "_mfg")) ++ fw_type = FW_TYPE_MFG; ++ else ++ fw_type = FW_TYPE_STA; ++ ++ for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { ++ const cihp_name_map_t* row = &chip_name_map[i]; ++ if (row->chip == chip && row->chiprev == chiprev && ++ (row->ag_type == ag_type || row->ag_type == DONT_CARE)) { ++ strcpy(name_ptr, "fw_"); ++ strcat(fw_path, row->chip_name); ++#ifdef BCMUSBDEV_COMPOSITE ++ strcat(fw_path, "_cusb"); ++#endif ++ if (fw_type == FW_TYPE_APSTA) ++ strcat(fw_path, "_apsta.bin"); ++ else if (fw_type == FW_TYPE_P2P) ++ strcat(fw_path, "_p2p.bin"); ++ else if (fw_type == FW_TYPE_MESH) ++ strcat(fw_path, "_mesh.bin"); ++ else if (fw_type == FW_TYPE_ES) ++ strcat(fw_path, "_es.bin"); ++ else if (fw_type == FW_TYPE_MFG) ++ strcat(fw_path, "_mfg.bin"); ++ else ++ strcat(fw_path, ".bin"); ++ } ++ } ++ ++ dhd->conf->fw_type = fw_type; ++ ++ CONFIG_TRACE("firmware_path=%s\n", fw_path); ++ return ag_type; ++} ++ ++void ++dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path, int ag_type) ++{ ++ uint chip, chiprev; ++ int i; ++ char *name_ptr; ++ ++ chip = dhd->conf->chip; ++ chiprev = dhd->conf->chiprev; ++ ++ if (clm_path[0] == '\0') { ++ CONFIG_MSG("clm path is null\n"); ++ return; ++ } ++ ++ /* find out the last '/' */ ++ i = strlen(clm_path); ++ while (i > 0) { ++ if (clm_path[i] == '/') { ++ i++; ++ break; ++ } ++ i--; ++ } ++ name_ptr = &clm_path[i]; ++ ++ for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { ++ const cihp_name_map_t* row = &chip_name_map[i]; ++ if (row->chip == chip && row->chiprev == chiprev && ++ (row->ag_type == ag_type || row->ag_type == DONT_CARE)) { ++ strcpy(name_ptr, "clm_"); ++ strcat(clm_path, row->chip_name); ++ strcat(clm_path, ".blob"); ++ } ++ } ++ ++ CONFIG_TRACE("clm_path=%s\n", clm_path); ++} ++ ++void ++dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path, int ag_type) ++{ ++ uint chip, chiprev; ++ int i; ++ char *name_ptr; ++ ++ chip = dhd->conf->chip; ++ chiprev = dhd->conf->chiprev; ++ ++ if (nv_path[0] == '\0') { ++#ifdef CONFIG_BCMDHD_NVRAM_PATH ++ bcm_strncpy_s(nv_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1); ++ if (nv_path[0] == '\0') ++#endif ++ { ++ CONFIG_MSG("nvram path is null\n"); ++ return; ++ } ++ } ++ ++ /* find out the last '/' */ ++ i = strlen(nv_path); ++ while (i > 0) { ++ if (nv_path[i] == '/') { ++ i++; ++ break; ++ } ++ i--; ++ } ++ name_ptr = &nv_path[i]; ++ ++ for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { ++ const cihp_name_map_t* row = &chip_name_map[i]; ++ if (row->chip == chip && row->chiprev == chiprev && ++ (row->ag_type == ag_type || row->ag_type == DONT_CARE)) { ++#ifdef GET_OTP_MODULE_NAME ++ if (strlen(dhd->conf->module_name)) { ++ strcpy(name_ptr, "nvram_"); ++ strcat(name_ptr, dhd->conf->module_name); ++ } else ++#endif ++ if (strlen(row->module_name)){ ++ strcpy(name_ptr, "nvram_"); ++ strcat(name_ptr, row->module_name); ++ } else ++ continue; ++#ifdef BCMUSBDEV_COMPOSITE ++ strcat(name_ptr, "_cusb"); ++#endif ++ strcat(name_ptr, ".txt"); ++ } ++ } ++ ++ for (i=0; iconf->nv_by_chip.count; i++) { ++ if (chip==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip && ++ chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) { ++ strcpy(name_ptr, dhd->conf->nv_by_chip.m_chip_nv_path_head[i].name); ++ break; ++ } ++ } ++ ++ CONFIG_TRACE("nvram_path=%s\n", nv_path); ++} ++ ++void ++dhd_conf_copy_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_path) ++{ ++ int i; ++ ++ if (src_path[0] == '\0') { ++ CONFIG_MSG("src_path is null\n"); ++ return; ++ } else ++ strcpy(dst_path, src_path); ++ ++ /* find out the last '/' */ ++ i = strlen(dst_path); ++ while (i > 0) { ++ if (dst_path[i] == '/') { ++ i++; ++ break; ++ } ++ i--; ++ } ++ strcpy(&dst_path[i], dst_name); ++ ++ CONFIG_TRACE("dst_path=%s\n", dst_path); ++} ++ ++#ifdef CONFIG_PATH_AUTO_SELECT ++void ++dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path) ++{ ++ uint chip, chiprev; ++ int i; ++ char *name_ptr; ++ ++ chip = dhd->conf->chip; ++ chiprev = dhd->conf->chiprev; ++ ++ if (conf_path[0] == '\0') { ++ CONFIG_MSG("config path is null\n"); ++ return; ++ } ++ ++ /* find out the last '/' */ ++ i = strlen(conf_path); ++ while (i > 0) { ++ if (conf_path[i] == '/') { ++ i++; ++ break; ++ } ++ i--; ++ } ++ name_ptr = &conf_path[i]; ++ ++ for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { ++ const cihp_name_map_t* row = &chip_name_map[i]; ++ if (row->chip == chip && row->chiprev == chiprev) { ++ strcpy(name_ptr, "config_"); ++ strcat(conf_path, row->chip_name); ++ strcat(conf_path, ".txt"); ++ } ++ } ++ ++ CONFIG_TRACE("config_path=%s\n", conf_path); ++} ++#endif ++ ++void ++dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path) ++{ ++ int ag_type; ++ ++ /* External conf takes precedence if specified */ ++ dhd_conf_preinit(dhd); ++ ++ if (dhd->conf_path[0] == '\0') { ++ dhd_conf_copy_path(dhd, "config.txt", dhd->conf_path, nv_path); ++ } ++ if (dhd->clm_path[0] == '\0') { ++ dhd_conf_copy_path(dhd, "clm.blob", dhd->clm_path, fw_path); ++ } ++#ifdef CONFIG_PATH_AUTO_SELECT ++ dhd_conf_set_conf_name_by_chip(dhd, dhd->conf_path); ++#endif ++ ++ dhd_conf_read_config(dhd, dhd->conf_path); ++ ++ ag_type = dhd_conf_set_fw_name_by_chip(dhd, fw_path); ++ dhd_conf_set_nv_name_by_chip(dhd, nv_path, ag_type); ++ dhd_conf_set_clm_name_by_chip(dhd, dhd->clm_path, ag_type); ++#ifdef BCMSDIO ++ dhd_conf_set_fw_name_by_mac(dhd, fw_path); ++ dhd_conf_set_nv_name_by_mac(dhd, nv_path); ++#endif ++ ++ CONFIG_MSG("Final fw_path=%s\n", fw_path); ++ CONFIG_MSG("Final nv_path=%s\n", nv_path); ++ CONFIG_MSG("Final clm_path=%s\n", dhd->clm_path); ++ CONFIG_MSG("Final conf_path=%s\n", dhd->conf_path); ++} ++ ++int ++dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val, ++ int def, bool down) ++{ ++ int ret = -1; ++ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ ++ ++ if (val >= def) { ++ if (down) { ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0) ++ CONFIG_ERROR("WLC_DOWN setting failed %d\n", ret); ++ } ++ if (cmd == WLC_SET_VAR) { ++ CONFIG_TRACE("set %s %d\n", name, val); ++ bcm_mkiovar(name, (char *)&val, sizeof(val), iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) ++ CONFIG_ERROR("%s setting failed %d\n", name, ret); ++ } else { ++ CONFIG_TRACE("set %s %d %d\n", name, cmd, val); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0) ++ CONFIG_ERROR("%s setting failed %d\n", name, ret); ++ } ++ } ++ ++ return ret; ++} ++ ++int ++dhd_conf_set_bufiovar(dhd_pub_t *dhd, int ifidx, uint cmd, char *name, ++ char *buf, int len, bool down) ++{ ++ char iovbuf[WLC_IOCTL_SMLEN]; ++ s32 iovar_len; ++ int ret = -1; ++ ++ if (down) { ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, ifidx)) < 0) ++ CONFIG_ERROR("WLC_DOWN setting failed %d\n", ret); ++ } ++ ++ if (cmd == WLC_SET_VAR) { ++ iovar_len = bcm_mkiovar(name, buf, len, iovbuf, sizeof(iovbuf)); ++ if (iovar_len > 0) ++ ret = dhd_wl_ioctl_cmd(dhd, cmd, iovbuf, iovar_len, TRUE, ifidx); ++ else ++ ret = BCME_BUFTOOSHORT; ++ if (ret < 0) ++ CONFIG_ERROR("%s setting failed %d, len=%d\n", name, ret, len); ++ } else { ++ if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, TRUE, ifidx)) < 0) ++ CONFIG_ERROR("%s setting failed %d\n", name, ret); ++ } ++ ++ return ret; ++} ++ ++int ++dhd_conf_get_iovar(dhd_pub_t *dhd, int ifidx, int cmd, char *name, ++ char *buf, int len) ++{ ++ char iovbuf[WLC_IOCTL_SMLEN]; ++ int ret = -1; ++ ++ if (cmd == WLC_GET_VAR) { ++ if (bcm_mkiovar(name, NULL, 0, iovbuf, sizeof(iovbuf))) { ++ ret = dhd_wl_ioctl_cmd(dhd, cmd, iovbuf, sizeof(iovbuf), FALSE, ifidx); ++ if (!ret) { ++ memcpy(buf, iovbuf, len); ++ } else { ++ CONFIG_ERROR("get iovar %s failed %d\n", name, ret); ++ } ++ } else { ++ CONFIG_ERROR("mkiovar %s failed\n", name); ++ } ++ } else { ++ ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, FALSE, 0); ++ if (ret < 0) ++ CONFIG_ERROR("get iovar %s failed %d\n", name, ret); ++ } ++ ++ return ret; ++} ++ ++static int ++dhd_conf_rsdb_mode(dhd_pub_t *dhd, char *buf) ++{ ++ wl_config_t rsdb_mode_cfg = {1, 0}; ++ ++ if (buf) { ++ rsdb_mode_cfg.config = (int)simple_strtol(buf, NULL, 0); ++ CONFIG_MSG("rsdb_mode %d\n", rsdb_mode_cfg.config); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "rsdb_mode", (char *)&rsdb_mode_cfg, ++ sizeof(rsdb_mode_cfg), TRUE); ++ } ++ ++ return 0; ++} ++ ++typedef int (tpl_parse_t)(dhd_pub_t *dhd, char *buf); ++ ++typedef struct iovar_tpl_t { ++ int cmd; ++ char *name; ++ tpl_parse_t *parse; ++} iovar_tpl_t; ++ ++const iovar_tpl_t iovar_tpl_list[] = { ++ {WLC_SET_VAR, "rsdb_mode", dhd_conf_rsdb_mode}, ++}; ++ ++static int iovar_tpl_parse(const iovar_tpl_t *tpl, int tpl_count, ++ dhd_pub_t *dhd, int cmd, char *name, char *buf) ++{ ++ int i, ret = 0; ++ ++ /* look for a matching code in the table */ ++ for (i = 0; i < tpl_count; i++, tpl++) { ++ if (tpl->cmd == cmd && !strcmp(tpl->name, name)) ++ break; ++ } ++ if (i < tpl_count && tpl->parse) { ++ ret = tpl->parse(dhd, buf); ++ } else { ++ ret = -1; ++ } ++ ++ return ret; ++} ++ ++bool ++dhd_conf_set_wl_cmd(dhd_pub_t *dhd, char *data, bool down) ++{ ++ int cmd, val, ret = 0, len; ++ char name[32], *pch, *pick_tmp, *pick_tmp2, *pdata = NULL; ++ ++ /* Process wl_preinit: ++ * wl_preinit=[cmd]=[val], [cmd]=[val] ++ * Ex: wl_preinit=86=0, mpc=0 ++ */ ++ ++ if (data == NULL) ++ return FALSE; ++ ++ len = strlen(data); ++ pdata = kmalloc(len+1, GFP_KERNEL); ++ if (pdata == NULL) { ++ CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", len+1); ++ goto exit; ++ } ++ memset(pdata, 0, len+1); ++ strcpy(pdata, data); ++ ++ pick_tmp = pdata; ++ while (pick_tmp && (pick_tmp2 = bcmstrtok(&pick_tmp, ",", 0)) != NULL) { ++ pch = bcmstrtok(&pick_tmp2, "=", 0); ++ if (!pch) ++ break; ++ if (*pch == ' ') { ++ pch++; ++ } ++ memset(name, 0 , sizeof (name)); ++ cmd = (int)simple_strtol(pch, NULL, 0); ++ if (cmd == 0) { ++ cmd = WLC_SET_VAR; ++ strcpy(name, pch); ++ } ++ pch = bcmstrtok(&pick_tmp2, ",", 0); ++ if (!pch) { ++ break; ++ } ++ ret = iovar_tpl_parse(iovar_tpl_list, ARRAY_SIZE(iovar_tpl_list), ++ dhd, cmd, name, pch); ++ if (ret) { ++ val = (int)simple_strtol(pch, NULL, 0); ++ dhd_conf_set_intiovar(dhd, cmd, name, val, -1, down); ++ } ++ } ++ ++exit: ++ if (pdata) ++ kfree(pdata); ++ return true; ++} ++ ++int ++dhd_conf_get_band(dhd_pub_t *dhd) ++{ ++ int band = -1; ++ ++ if (dhd && dhd->conf) ++ band = dhd->conf->band; ++ else ++ CONFIG_ERROR("dhd or conf is NULL\n"); ++ ++ return band; ++} ++ ++int ++dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec) ++{ ++ int bcmerror = -1; ++ ++ memset(cspec, 0, sizeof(wl_country_t)); ++ bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t)); ++ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t), ++ FALSE, 0)) < 0) ++ CONFIG_ERROR("country code getting failed %d\n", bcmerror); ++ ++ return bcmerror; ++} ++ ++int ++dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec) ++{ ++ int bcmerror = -1; ++ struct dhd_conf *conf = dhd->conf; ++ country_list_t *country = conf->country_head; ++ ++#ifdef CCODE_LIST ++ bcmerror = dhd_ccode_map_country_list(dhd, cspec); ++#endif ++ ++ while (country != NULL) { ++ if (!strncmp("**", country->cspec.country_abbrev, 2)) { ++ memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ); ++ cspec->rev = country->cspec.rev; ++ bcmerror = 0; ++ break; ++ } else if (!strncmp(cspec->country_abbrev, ++ country->cspec.country_abbrev, 2)) { ++ memcpy(cspec->ccode, country->cspec.ccode, WLC_CNTRY_BUF_SZ); ++ cspec->rev = country->cspec.rev; ++ bcmerror = 0; ++ break; ++ } ++ country = country->next; ++ } ++ ++ if (!bcmerror) ++ CONFIG_MSG("%s/%d\n", cspec->ccode, cspec->rev); ++ ++ return bcmerror; ++} ++ ++int ++dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec) ++{ ++ int bcmerror = -1; ++ ++ memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t)); ++ ++ CONFIG_MSG("set country %s, revision %d\n", cspec->ccode, cspec->rev); ++ bcmerror = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "country", (char *)cspec, ++ sizeof(wl_country_t), FALSE); ++ dhd_conf_get_country(dhd, cspec); ++ CONFIG_MSG("Country code: %s (%s/%d)\n", ++ cspec->country_abbrev, cspec->ccode, cspec->rev); ++ ++ return bcmerror; ++} ++ ++int ++dhd_conf_fix_country(dhd_pub_t *dhd) ++{ ++ int bcmerror = -1; ++ int band; ++ wl_uint32_list_t *list; ++ u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; ++ wl_country_t cspec; ++ ++ if (!(dhd && dhd->conf)) { ++ return bcmerror; ++ } ++ ++ memset(valid_chan_list, 0, sizeof(valid_chan_list)); ++ list = (wl_uint32_list_t *)(void *) valid_chan_list; ++ list->count = htod32(WL_NUMCHANNELS); ++ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, valid_chan_list, ++ sizeof(valid_chan_list), FALSE, 0)) < 0) { ++ CONFIG_ERROR("get channels failed with %d\n", bcmerror); ++ } ++ ++ band = dhd_conf_get_band(dhd); ++ ++ if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G || band==-1) && ++ dtoh32(list->count)<11)) { ++ CONFIG_ERROR("bcmerror=%d, # of channels %d\n", ++ bcmerror, dtoh32(list->count)); ++ dhd_conf_map_country_list(dhd, &dhd->conf->cspec); ++ if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) { ++ strcpy(cspec.country_abbrev, "US"); ++ cspec.rev = 0; ++ strcpy(cspec.ccode, "US"); ++ dhd_conf_map_country_list(dhd, &cspec); ++ dhd_conf_set_country(dhd, &cspec); ++ } ++ } ++ ++ return bcmerror; ++} ++ ++bool ++dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel) ++{ ++ int i; ++ bool match = false; ++ ++ if (dhd && dhd->conf) { ++ if (dhd->conf->channels.count == 0) ++ return true; ++ for (i=0; iconf->channels.count; i++) { ++ if (channel == dhd->conf->channels.channel[i]) ++ match = true; ++ } ++ } else { ++ match = true; ++ CONFIG_ERROR("dhd or conf is NULL\n"); ++ } ++ ++ return match; ++} ++ ++int ++dhd_conf_set_roam(dhd_pub_t *dhd) ++{ ++ int bcmerror = -1; ++ struct dhd_conf *conf = dhd->conf; ++ ++ dhd_roam_disable = conf->roam_off; ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "roam_off", dhd->conf->roam_off, 0, FALSE); ++ ++ if (!conf->roam_off || !conf->roam_off_suspend) { ++ CONFIG_MSG("set roam_trigger %d\n", conf->roam_trigger[0]); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_TRIGGER, "WLC_SET_ROAM_TRIGGER", ++ (char *)conf->roam_trigger, sizeof(conf->roam_trigger), FALSE); ++ ++ CONFIG_MSG("set roam_scan_period %d\n", conf->roam_scan_period[0]); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_SCAN_PERIOD, "WLC_SET_ROAM_SCAN_PERIOD", ++ (char *)conf->roam_scan_period, sizeof(conf->roam_scan_period), FALSE); ++ ++ CONFIG_MSG("set roam_delta %d\n", conf->roam_delta[0]); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_ROAM_DELTA, "WLC_SET_ROAM_DELTA", ++ (char *)conf->roam_delta, sizeof(conf->roam_delta), FALSE); ++ ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "fullroamperiod", ++ dhd->conf->fullroamperiod, 1, FALSE); ++ } ++ ++ return bcmerror; ++} ++ ++void ++dhd_conf_add_to_eventbuffer(struct eventmsg_buf *ev, u16 event, bool set) ++{ ++ if (!ev || (event > WLC_E_LAST)) ++ return; ++ ++ if (ev->num < MAX_EVENT_BUF_NUM) { ++ ev->event[ev->num].type = event; ++ ev->event[ev->num].set = set; ++ ev->num++; ++ } else { ++ CONFIG_ERROR("evenbuffer doesn't support > %u events. Update" ++ " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM); ++ ASSERT(0); ++ } ++} ++ ++s32 ++dhd_conf_apply_eventbuffer(dhd_pub_t *dhd, eventmsg_buf_t *ev) ++{ ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ int i, ret = 0; ++ ++ if (!ev || (!ev->num)) ++ return -EINVAL; ++ ++ /* Read event_msgs mask */ ++ ret = dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "event_msgs", eventmask, ++ sizeof(eventmask)); ++ if (unlikely(ret)) { ++ CONFIG_ERROR("Get event_msgs error (%d)\n", ret); ++ goto exit; ++ } ++ ++ /* apply the set bits */ ++ for (i = 0; i < ev->num; i++) { ++ if (ev->event[i].set) ++ setbit(eventmask, ev->event[i].type); ++ else ++ clrbit(eventmask, ev->event[i].type); ++ } ++ ++ /* Write updated Event mask */ ++ ret = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "event_msgs", eventmask, ++ sizeof(eventmask), FALSE); ++ if (unlikely(ret)) { ++ CONFIG_ERROR("Set event_msgs error (%d)\n", ret); ++ } ++ ++exit: ++ return ret; ++} ++ ++int ++dhd_conf_enable_roam_offload(dhd_pub_t *dhd, int enable) ++{ ++ int err; ++ eventmsg_buf_t ev_buf; ++ ++ if (dhd->conf->roam_off_suspend) ++ return 0; ++ ++ err = dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "roam_offload", enable, 0, FALSE); ++ if (err) ++ return err; ++ ++ bzero(&ev_buf, sizeof(eventmsg_buf_t)); ++ dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable); ++ dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable); ++ dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable); ++ dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable); ++ dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable); ++ dhd_conf_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable); ++ err = dhd_conf_apply_eventbuffer(dhd, &ev_buf); ++ ++ CONFIG_TRACE("roam_offload %d\n", enable); ++ ++ return err; ++} ++ ++void ++dhd_conf_set_bw_cap(dhd_pub_t *dhd) ++{ ++ struct { ++ u32 band; ++ u32 bw_cap; ++ } param = {0, 0}; ++ ++ if (dhd->conf->bw_cap[0] >= 0) { ++ memset(¶m, 0, sizeof(param)); ++ param.band = WLC_BAND_2G; ++ param.bw_cap = (uint)dhd->conf->bw_cap[0]; ++ CONFIG_MSG("set bw_cap 2g 0x%x\n", param.bw_cap); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "bw_cap", (char *)¶m, ++ sizeof(param), TRUE); ++ } ++ ++ if (dhd->conf->bw_cap[1] >= 0) { ++ memset(¶m, 0, sizeof(param)); ++ param.band = WLC_BAND_5G; ++ param.bw_cap = (uint)dhd->conf->bw_cap[1]; ++ CONFIG_MSG("set bw_cap 5g 0x%x\n", param.bw_cap); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "bw_cap", (char *)¶m, ++ sizeof(param), TRUE); ++ } ++} ++ ++void ++dhd_conf_get_wme(dhd_pub_t *dhd, int ifidx, int mode, edcf_acparam_t *acp) ++{ ++ int bcmerror = -1; ++ char iovbuf[WLC_IOCTL_SMLEN]; ++ edcf_acparam_t *acparam; ++ ++ bzero(iovbuf, sizeof(iovbuf)); ++ ++ /* ++ * Get current acparams, using buf as an input buffer. ++ * Return data is array of 4 ACs of wme params. ++ */ ++ if (mode == 0) ++ bcm_mkiovar("wme_ac_sta", NULL, 0, iovbuf, sizeof(iovbuf)); ++ else ++ bcm_mkiovar("wme_ac_ap", NULL, 0, iovbuf, sizeof(iovbuf)); ++ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), ++ FALSE, ifidx)) < 0) { ++ CONFIG_ERROR("wme_ac_sta getting failed %d\n", bcmerror); ++ return; ++ } ++ memcpy((char*)acp, iovbuf, sizeof(edcf_acparam_t)*AC_COUNT); ++ ++ acparam = &acp[AC_BK]; ++ CONFIG_TRACE("BK: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n", ++ acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK, ++ acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT, ++ acparam->TXOP); ++ acparam = &acp[AC_BE]; ++ CONFIG_TRACE("BE: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n", ++ acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK, ++ acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT, ++ acparam->TXOP); ++ acparam = &acp[AC_VI]; ++ CONFIG_TRACE("VI: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n", ++ acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK, ++ acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT, ++ acparam->TXOP); ++ acparam = &acp[AC_VO]; ++ CONFIG_TRACE("VO: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n", ++ acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK, ++ acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT, ++ acparam->TXOP); ++ ++ return; ++} ++ ++void ++dhd_conf_update_wme(dhd_pub_t *dhd, int ifidx, int mode, ++ edcf_acparam_t *acparam_cur, int aci) ++{ ++ int aifsn, ecwmin, ecwmax, txop; ++ edcf_acparam_t *acp; ++ struct dhd_conf *conf = dhd->conf; ++ wme_param_t *wme; ++ ++ if (mode == 0) ++ wme = &conf->wme_sta; ++ else ++ wme = &conf->wme_ap; ++ ++ /* Default value */ ++ aifsn = acparam_cur->ACI&EDCF_AIFSN_MASK; ++ ecwmin = acparam_cur->ECW&EDCF_ECWMIN_MASK; ++ ecwmax = (acparam_cur->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT; ++ txop = acparam_cur->TXOP; ++ ++ /* Modified value */ ++ if (wme->aifsn[aci] > 0) ++ aifsn = wme->aifsn[aci]; ++ if (wme->ecwmin[aci] > 0) ++ ecwmin = wme->ecwmin[aci]; ++ if (wme->ecwmax[aci] > 0) ++ ecwmax = wme->ecwmax[aci]; ++ if (wme->txop[aci] > 0) ++ txop = wme->txop[aci]; ++ ++ if (!(wme->aifsn[aci] || wme->ecwmin[aci] || ++ wme->ecwmax[aci] || wme->txop[aci])) ++ return; ++ ++ /* Update */ ++ acp = acparam_cur; ++ acp->ACI = (acp->ACI & ~EDCF_AIFSN_MASK) | (aifsn & EDCF_AIFSN_MASK); ++ acp->ECW = ((ecwmax << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK) | (acp->ECW & EDCF_ECWMIN_MASK); ++ acp->ECW = ((acp->ECW & EDCF_ECWMAX_MASK) | (ecwmin & EDCF_ECWMIN_MASK)); ++ acp->TXOP = txop; ++ ++ CONFIG_MSG("wme_ac %s aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n", ++ mode?"ap":"sta", acp->ACI, acp->ACI&EDCF_AIFSN_MASK, ++ acp->ECW&EDCF_ECWMIN_MASK, (acp->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT, ++ acp->TXOP); ++ ++ /* ++ * Now use buf as an output buffer. ++ * Put WME acparams after "wme_ac\0" in buf. ++ * NOTE: only one of the four ACs can be set at a time. ++ */ ++ if (mode == 0) ++ dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "wme_ac_sta", (char *)acp, ++ sizeof(edcf_acparam_t), FALSE); ++ else ++ dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "wme_ac_ap", (char *)acp, ++ sizeof(edcf_acparam_t), FALSE); ++ ++} ++ ++void ++dhd_conf_set_wme(dhd_pub_t *dhd, int ifidx, int mode) ++{ ++ edcf_acparam_t acparam_cur[AC_COUNT]; ++ ++ if (dhd && dhd->conf) { ++ if (!dhd->conf->force_wme_ac) { ++ CONFIG_TRACE("force_wme_ac is not enabled %d\n", ++ dhd->conf->force_wme_ac); ++ return; ++ } ++ ++ CONFIG_TRACE("Before change:\n"); ++ dhd_conf_get_wme(dhd, ifidx, mode, acparam_cur); ++ ++ dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_BK], AC_BK); ++ dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_BE], AC_BE); ++ dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_VI], AC_VI); ++ dhd_conf_update_wme(dhd, ifidx, mode, &acparam_cur[AC_VO], AC_VO); ++ ++ CONFIG_TRACE("After change:\n"); ++ dhd_conf_get_wme(dhd, ifidx, mode, acparam_cur); ++ } else { ++ CONFIG_ERROR("dhd or conf is NULL\n"); ++ } ++ ++ return; ++} ++ ++void ++dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int p2p_mode, int miracast_mode) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ mchan_params_t *mchan = conf->mchan; ++ bool set = true; ++ ++ while (mchan != NULL) { ++ set = true; ++ set &= (mchan->bw >= 0); ++ set &= ((mchan->p2p_mode == -1) | (mchan->p2p_mode == p2p_mode)); ++ set &= ((mchan->miracast_mode == -1) | (mchan->miracast_mode == miracast_mode)); ++ if (set) { ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "mchan_bw", mchan->bw, 0, FALSE); ++ } ++ mchan = mchan->next; ++ } ++ ++ return; ++} ++ ++#ifdef PKT_FILTER_SUPPORT ++void ++dhd_conf_add_pkt_filter(dhd_pub_t *dhd) ++{ ++ int i, j; ++ char str[16]; ++#define MACS "%02x%02x%02x%02x%02x%02x" ++ ++ /* ++ * Filter in less pkt: ARP(0x0806, ID is 105), BRCM(0x886C), 802.1X(0x888E) ++ * 1) dhd_master_mode=1 ++ * 2) pkt_filter_delete=100, 102, 103, 104, 105, 106, 107 ++ * 3) pkt_filter_add=131 0 0 12 0xFFFF 0x886C, 132 0 0 12 0xFFFF 0x888E ++ * 4) magic_pkt_filter_add=141 0 1 12 ++ */ ++ for(i=0; iconf->pkt_filter_add.count; i++) { ++ dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i]; ++ CONFIG_MSG("%s\n", dhd->pktfilter[i+dhd->pktfilter_count]); ++ } ++ dhd->pktfilter_count += i; ++ ++ if (dhd->conf->magic_pkt_filter_add) { ++ strcat(dhd->conf->magic_pkt_filter_add, " 0x"); ++ strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF"); ++ for (j=0; j<16; j++) ++ strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF"); ++ strcat(dhd->conf->magic_pkt_filter_add, " 0x"); ++ strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF"); ++ sprintf(str, MACS, MAC2STRDBG(dhd->mac.octet)); ++ for (j=0; j<16; j++) ++ strncat(dhd->conf->magic_pkt_filter_add, str, 12); ++ dhd->pktfilter[dhd->pktfilter_count] = dhd->conf->magic_pkt_filter_add; ++ dhd->pktfilter_count += 1; ++ } ++} ++ ++bool ++dhd_conf_del_pkt_filter(dhd_pub_t *dhd, uint32 id) ++{ ++ int i; ++ ++ if (dhd && dhd->conf) { ++ for (i=0; iconf->pkt_filter_del.count; i++) { ++ if (id == dhd->conf->pkt_filter_del.id[i]) { ++ CONFIG_MSG("%d\n", dhd->conf->pkt_filter_del.id[i]); ++ return true; ++ } ++ } ++ return false; ++ } ++ return false; ++} ++ ++void ++dhd_conf_discard_pkt_filter(dhd_pub_t *dhd) ++{ ++ dhd->pktfilter_count = 6; ++ dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = NULL; ++ dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; ++ dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "102 0 0 0 0xFFFFFF 0x01005E"; ++ dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = "103 0 0 0 0xFFFF 0x3333"; ++ dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL; ++ /* Do not enable ARP to pkt filter if dhd_master_mode is false.*/ ++ dhd->pktfilter[DHD_ARP_FILTER_NUM] = NULL; ++ ++ /* IPv4 broadcast address XXX.XXX.XXX.255 */ ++ dhd->pktfilter[dhd->pktfilter_count] = "110 0 0 12 0xFFFF00000000000000000000000000000000000000FF 0x080000000000000000000000000000000000000000FF"; ++ dhd->pktfilter_count++; ++ /* discard IPv4 multicast address 224.0.0.0/4 */ ++ dhd->pktfilter[dhd->pktfilter_count] = "111 0 0 12 0xFFFF00000000000000000000000000000000F0 0x080000000000000000000000000000000000E0"; ++ dhd->pktfilter_count++; ++ /* discard IPv6 multicast address FF00::/8 */ ++ dhd->pktfilter[dhd->pktfilter_count] = "112 0 0 12 0xFFFF000000000000000000000000000000000000000000000000FF 0x86DD000000000000000000000000000000000000000000000000FF"; ++ dhd->pktfilter_count++; ++ /* discard Netbios pkt */ ++ dhd->pktfilter[dhd->pktfilter_count] = "121 0 0 12 0xFFFF000000000000000000FF000000000000000000000000FFFF 0x0800000000000000000000110000000000000000000000000089"; ++ dhd->pktfilter_count++; ++ ++} ++#endif /* PKT_FILTER_SUPPORT */ ++ ++int ++dhd_conf_get_pm(dhd_pub_t *dhd) ++{ ++ if (dhd && dhd->conf) { ++ return dhd->conf->pm; ++ } ++ return -1; ++} ++ ++int ++dhd_conf_check_hostsleep(dhd_pub_t *dhd, int cmd, void *buf, int len, ++ int *hostsleep_set, int *hostsleep_val, int *ret) ++{ ++ if (dhd->conf->insuspend & (NO_TXCTL_IN_SUSPEND | WOWL_IN_SUSPEND)) { ++ if (cmd == WLC_SET_VAR) { ++ char *psleep = NULL; ++ psleep = strstr(buf, "hostsleep"); ++ if (psleep) { ++ *hostsleep_set = 1; ++ memcpy(hostsleep_val, psleep+strlen("hostsleep")+1, sizeof(int)); ++ } ++ } ++ if (dhd->hostsleep && (!*hostsleep_set || *hostsleep_val)) { ++ CONFIG_TRACE("block all none hostsleep clr cmd\n"); ++ *ret = BCME_EPERM; ++ goto exit; ++ } else if (*hostsleep_set && *hostsleep_val) { ++ CONFIG_TRACE("hostsleep %d => %d\n", dhd->hostsleep, *hostsleep_val); ++ dhd->hostsleep = *hostsleep_val; ++ if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) { ++ dhd_txflowcontrol(dhd, ALL_INTERFACES, ON); ++ } ++ if (dhd->hostsleep == 2) { ++ *ret = 0; ++ goto exit; ++ } ++ } else if (dhd->hostsleep == 2 && !*hostsleep_val) { ++ CONFIG_TRACE("hostsleep %d => %d\n", dhd->hostsleep, *hostsleep_val); ++ dhd->hostsleep = *hostsleep_val; ++ if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) { ++ dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); ++ } ++ *ret = 0; ++ goto exit; ++ } ++ } ++ ++ return 0; ++exit: ++ return -1; ++} ++ ++void ++dhd_conf_get_hostsleep(dhd_pub_t *dhd, ++ int hostsleep_set, int hostsleep_val, int ret) ++{ ++ if (dhd->conf->insuspend & (NO_TXCTL_IN_SUSPEND | WOWL_IN_SUSPEND)) { ++ if (hostsleep_set) { ++ if (hostsleep_val && ret) { ++ CONFIG_TRACE("reset hostsleep %d => 0\n", dhd->hostsleep); ++ dhd->hostsleep = 0; ++ if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) { ++ dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); ++ } ++ } else if (!hostsleep_val && !ret) { ++ CONFIG_TRACE("set hostsleep %d => 0\n", dhd->hostsleep); ++ dhd->hostsleep = 0; ++ if (dhd->conf->insuspend & NO_TXDATA_IN_SUSPEND) { ++ dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); ++ } ++ } ++ } ++ } ++} ++ ++#ifdef WL_EXT_WOWL ++#define WL_WOWL_TCPFIN (1 << 26) ++typedef struct wl_wowl_pattern2 { ++ char cmd[4]; ++ wl_wowl_pattern_t wowl_pattern; ++} wl_wowl_pattern2_t; ++static int ++dhd_conf_wowl_pattern(dhd_pub_t *dhd, bool add, char *data) ++{ ++ uint buf_len = 0; ++ int id, type, polarity, offset; ++ char cmd[4]="\0", mask[128]="\0", pattern[128]="\0", mask_tmp[128]="\0", *pmask_tmp; ++ uint32 masksize, patternsize, pad_len = 0; ++ wl_wowl_pattern2_t *wowl_pattern2 = NULL; ++ char *mask_and_pattern; ++ int ret = 0, i, j, v; ++ ++ if (data) { ++ if (add) ++ strcpy(cmd, "add"); ++ else ++ strcpy(cmd, "clr"); ++ if (!strcmp(cmd, "clr")) { ++ CONFIG_TRACE("wowl_pattern clr\n"); ++ ret = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "wowl_pattern", cmd, ++ sizeof(cmd), FALSE); ++ goto exit; ++ } ++ sscanf(data, "%d %d %d %d %s %s", &id, &type, &polarity, &offset, ++ mask_tmp, pattern); ++ masksize = strlen(mask_tmp) -2; ++ CONFIG_TRACE("0 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize); ++ ++ // add pading ++ if (masksize % 16) ++ pad_len = (16 - masksize % 16); ++ for (i=0; icmd, cmd, sizeof(cmd)); ++ wowl_pattern2->wowl_pattern.id = id; ++ wowl_pattern2->wowl_pattern.type = 0; ++ wowl_pattern2->wowl_pattern.offset = offset; ++ mask_and_pattern = (char*)wowl_pattern2 + sizeof(wl_wowl_pattern2_t); ++ ++ wowl_pattern2->wowl_pattern.masksize = masksize; ++ ret = wl_pattern_atoh(mask, mask_and_pattern); ++ if (ret == -1) { ++ CONFIG_ERROR("rejecting mask=%s\n", mask); ++ goto exit; ++ } ++ ++ mask_and_pattern += wowl_pattern2->wowl_pattern.masksize; ++ wowl_pattern2->wowl_pattern.patternoffset = sizeof(wl_wowl_pattern_t) + ++ wowl_pattern2->wowl_pattern.masksize; ++ ++ wowl_pattern2->wowl_pattern.patternsize = patternsize; ++ ret = wl_pattern_atoh(pattern, mask_and_pattern); ++ if (ret == -1) { ++ CONFIG_ERROR("rejecting pattern=%s\n", pattern); ++ goto exit; ++ } ++ ++ CONFIG_TRACE("%s %d %s %s\n", cmd, offset, mask, pattern); ++ ++ ret = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "wowl_pattern", ++ (char *)wowl_pattern2, buf_len, FALSE); ++ } ++ ++exit: ++ if (wowl_pattern2) ++ kfree(wowl_pattern2); ++ return ret; ++} ++ ++static int ++dhd_conf_wowl_wakeind(dhd_pub_t *dhd, bool clear) ++{ ++ s8 iovar_buf[WLC_IOCTL_SMLEN]; ++ wl_wowl_wakeind_t *wake = NULL; ++ int ret = -1; ++ char clr[6]="clear", wakeind_str[32]="\0"; ++ ++ if (clear) { ++ CONFIG_TRACE("wowl_wakeind clear\n"); ++ ret = dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "wowl_wakeind", ++ clr, sizeof(clr), 0); ++ } else { ++ ret = dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "wowl_wakeind", ++ iovar_buf, sizeof(iovar_buf)); ++ if (!ret) { ++ wake = (wl_wowl_wakeind_t *) iovar_buf; ++ if (wake->ucode_wakeind & WL_WOWL_MAGIC) ++ strcpy(wakeind_str, "(MAGIC packet)"); ++ if (wake->ucode_wakeind & WL_WOWL_NET) ++ strcpy(wakeind_str, "(Netpattern)"); ++ if (wake->ucode_wakeind & WL_WOWL_DIS) ++ strcpy(wakeind_str, "(Disassoc/Deauth)"); ++ if (wake->ucode_wakeind & WL_WOWL_BCN) ++ strcpy(wakeind_str, "(Loss of beacon)"); ++ if (wake->ucode_wakeind & WL_WOWL_TCPKEEP_TIME) ++ strcpy(wakeind_str, "(TCPKA timeout)"); ++ if (wake->ucode_wakeind & WL_WOWL_TCPKEEP_DATA) ++ strcpy(wakeind_str, "(TCPKA data)"); ++ if (wake->ucode_wakeind & WL_WOWL_TCPFIN) ++ strcpy(wakeind_str, "(TCP FIN)"); ++ CONFIG_MSG("wakeind=0x%x %s\n", wake->ucode_wakeind, wakeind_str); ++ } ++ } ++ ++ return ret; ++} ++#endif ++ ++int ++dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period, ++ char *packet, bool bcast) ++{ ++ wl_mkeep_alive_pkt_t *mkeep_alive_pktp; ++ int ret = 0, len_bytes=0, buf_len=0; ++ char *buf = NULL, *iovar_buf = NULL; ++ uint8 *pdata; ++ ++ CONFIG_TRACE("id=%d, period=%d, packet=%s\n", id, period, packet); ++ if (period >= 0) { ++ buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); ++ if (buf == NULL) { ++ CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN); ++ goto exit; ++ } ++ iovar_buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); ++ if (iovar_buf == NULL) { ++ CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN); ++ goto exit; ++ } ++ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)buf; ++ mkeep_alive_pktp->version = htod16(WL_MKEEP_ALIVE_VERSION); ++ mkeep_alive_pktp->length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); ++ mkeep_alive_pktp->keep_alive_id = id; ++ buf_len += WL_MKEEP_ALIVE_FIXED_LEN; ++ mkeep_alive_pktp->period_msec = period; ++ if (packet && strlen(packet)) { ++ len_bytes = wl_pattern_atoh(packet, (char *)mkeep_alive_pktp->data); ++ buf_len += len_bytes; ++ if (bcast) { ++ memcpy(mkeep_alive_pktp->data, ðer_bcast, ETHER_ADDR_LEN); ++ } ++ ret = dhd_conf_get_iovar(dhd, ifidx, WLC_GET_VAR, "cur_etheraddr", ++ iovar_buf, WLC_IOCTL_SMLEN); ++ if (!ret) { ++ pdata = mkeep_alive_pktp->data; ++ memcpy(pdata+6, iovar_buf, ETHER_ADDR_LEN); ++ } ++ } ++ mkeep_alive_pktp->len_bytes = htod16(len_bytes); ++ ret = dhd_conf_set_bufiovar(dhd, ifidx, WLC_SET_VAR, "mkeep_alive", ++ buf, buf_len, FALSE); ++ } ++ ++exit: ++ if (buf) ++ kfree(buf); ++ if (iovar_buf) ++ kfree(iovar_buf); ++ return ret; ++} ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++void ++dhd_conf_set_garp(dhd_pub_t *dhd, int ifidx, uint32 ipa, bool enable) ++{ ++ int i, len = 0, total_len = WLC_IOCTL_SMLEN; ++ char *iovar_buf = NULL, *packet = NULL; ++ ++ if (!dhd->conf->garp || ifidx != 0 || !(dhd->op_mode & DHD_FLAG_STA_MODE)) ++ return; ++ ++ CONFIG_TRACE("enable=%d\n", enable); ++ ++ if (enable) { ++ iovar_buf = kmalloc(total_len, GFP_KERNEL); ++ if (iovar_buf == NULL) { ++ CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", total_len); ++ goto exit; ++ } ++ packet = kmalloc(total_len, GFP_KERNEL); ++ if (packet == NULL) { ++ CONFIG_ERROR("Failed to allocate buffer of %d bytes\n", total_len); ++ goto exit; ++ } ++ dhd_conf_get_iovar(dhd, ifidx, WLC_GET_VAR, "cur_etheraddr", iovar_buf, total_len); ++ ++ len += snprintf(packet+len, total_len, "0xffffffffffff"); ++ for (i=0; i>8)&0xff, (ipa>>16)&0xff, (ipa>>24)&0xff); ++ len += snprintf(packet+len, total_len, "ffffffffffffc0a80101000000000000000000000000000000000000"); ++ } ++ ++ dhd_conf_mkeep_alive(dhd, ifidx, 0, dhd->conf->keep_alive_period, packet, TRUE); ++ ++exit: ++ if (iovar_buf) ++ kfree(iovar_buf); ++ if (packet) ++ kfree(packet); ++ return; ++} ++#endif ++ ++uint ++dhd_conf_get_insuspend(dhd_pub_t *dhd, uint mask) ++{ ++ uint insuspend = 0; ++ ++ if (dhd->op_mode & DHD_FLAG_STA_MODE) { ++ insuspend = dhd->conf->insuspend & ++ (NO_EVENT_IN_SUSPEND | NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND | ++ ROAM_OFFLOAD_IN_SUSPEND | WOWL_IN_SUSPEND); ++ } else if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { ++ insuspend = dhd->conf->insuspend & ++ (NO_EVENT_IN_SUSPEND | NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND | ++ AP_DOWN_IN_SUSPEND | AP_FILTER_IN_SUSPEND); ++ } ++ ++ return (insuspend & mask); ++} ++ ++#ifdef SUSPEND_EVENT ++void ++dhd_conf_set_suspend_event(dhd_pub_t *dhd, int suspend) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ struct ether_addr bssid; ++ char suspend_eventmask[WL_EVENTING_MASK_LEN]; ++ wl_event_msg_t msg; ++ int pm; ++#ifdef WL_CFG80211 ++ struct net_device *net; ++#endif /* defined(WL_CFG80211) */ ++ ++ CONFIG_TRACE("Enter\n"); ++ if (suspend) { ++#ifdef PROP_TXSTATUS ++#if defined(BCMSDIO) || defined(BCMDBUS) ++ if (dhd->wlfc_enabled) { ++ dhd_wlfc_deinit(dhd); ++ conf->wlfc = TRUE; ++ } else { ++ conf->wlfc = FALSE; ++ } ++#endif /* BCMSDIO || BCMDBUS */ ++#endif /* PROP_TXSTATUS */ ++ dhd_conf_get_iovar(dhd, 0, WLC_GET_VAR, "event_msgs", ++ conf->resume_eventmask, sizeof(conf->resume_eventmask)); ++ memset(suspend_eventmask, 0, sizeof(suspend_eventmask)); ++ setbit(suspend_eventmask, WLC_E_ESCAN_RESULT); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "event_msgs", ++ suspend_eventmask, sizeof(suspend_eventmask), FALSE); ++ if (dhd->op_mode & DHD_FLAG_STA_MODE) { ++ memset(&bssid, 0, ETHER_ADDR_LEN); ++ dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, FALSE, 0); ++ if (memcmp(ðer_null, &bssid, ETHER_ADDR_LEN)) ++ memcpy(&conf->bssid_insuspend, &bssid, ETHER_ADDR_LEN); ++ else ++ memset(&conf->bssid_insuspend, 0, ETHER_ADDR_LEN); ++ } ++ } ++ else { ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "event_msgs", ++ conf->resume_eventmask, sizeof(conf->resume_eventmask), FALSE); ++ if (dhd->op_mode & DHD_FLAG_STA_MODE) { ++ if (memcmp(ðer_null, &conf->bssid_insuspend, ETHER_ADDR_LEN)) { ++ memset(&bssid, 0, ETHER_ADDR_LEN); ++ dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, ++ FALSE, 0); ++ if (memcmp(ðer_null, &bssid, ETHER_ADDR_LEN)) { ++ dhd_conf_set_intiovar(dhd, WLC_SET_PM, "WLC_SET_PM", 0, 0, FALSE); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "send_nulldata", ++ (char *)&bssid, ETHER_ADDR_LEN, FALSE); ++ OSL_SLEEP(100); ++ if (conf->pm >= 0) ++ pm = conf->pm; ++ else ++ pm = PM_FAST; ++ dhd_conf_set_intiovar(dhd, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE); ++ } else { ++ CONFIG_TRACE("send WLC_E_DEAUTH_IND event\n"); ++ bzero(&msg, sizeof(wl_event_msg_t)); ++ memcpy(&msg.addr, &conf->bssid_insuspend, ETHER_ADDR_LEN); ++ msg.event_type = hton32(WLC_E_DEAUTH_IND); ++ msg.status = 0; ++ msg.reason = hton32(DOT11_RC_DEAUTH_LEAVING); ++#if defined(WL_EXT_IAPSTA) || defined(USE_IW) ++ wl_ext_event_send(dhd->event_params, &msg, NULL); ++#endif ++#ifdef WL_CFG80211 ++ net = dhd_idx2net(dhd, 0); ++ if (net) { ++ wl_cfg80211_event(net, &msg, NULL); ++ } ++#endif /* defined(WL_CFG80211) */ ++ } ++ } ++#ifdef PROP_TXSTATUS ++#if defined(BCMSDIO) || defined(BCMDBUS) ++ if (conf->wlfc) { ++ dhd_wlfc_init(dhd); ++ dhd_conf_set_intiovar(dhd, WLC_UP, "WLC_UP", 0, 0, FALSE); ++ } ++#endif ++#endif /* PROP_TXSTATUS */ ++ } ++ } ++ ++} ++#endif ++ ++#if defined(WL_CFG80211) || defined(WL_ESCAN) ++static void ++dhd_conf_wait_event_complete(struct dhd_pub *dhd, int ifidx) ++{ ++ s32 timeout = -1; ++ ++ timeout = wait_event_interruptible_timeout(dhd->conf->event_complete, ++ wl_ext_event_complete(dhd, ifidx), msecs_to_jiffies(10000)); ++ if (timeout <= 0 || !wl_ext_event_complete(dhd, ifidx)) { ++ wl_ext_event_complete(dhd, ifidx); ++ CONFIG_ERROR("timeout\n"); ++ } ++} ++#endif ++ ++int ++dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ uint insuspend = 0; ++ int pm; ++#ifdef BCMSDIO ++ uint32 intstatus = 0; ++ int ret = 0; ++#endif ++#ifdef WL_EXT_WOWL ++ int i; ++#endif ++ ++ insuspend = dhd_conf_get_insuspend(dhd, ALL_IN_SUSPEND); ++ if (insuspend) ++ CONFIG_MSG("op_mode %d, suspend %d, suspended %d, insuspend 0x%x, suspend_mode=%d\n", ++ dhd->op_mode, suspend, conf->suspended, insuspend, conf->suspend_mode); ++ ++ if (conf->suspended == suspend || !dhd->up) { ++ return 0; ++ } ++ ++ if (suspend) { ++ if (dhd->op_mode & DHD_FLAG_STA_MODE) { ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "roam_off", ++ dhd->conf->roam_off_suspend, 0, FALSE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_li_dtim", ++ dhd->conf->suspend_bcn_li_dtim, 0, FALSE); ++ if (insuspend & ROAM_OFFLOAD_IN_SUSPEND) ++ dhd_conf_enable_roam_offload(dhd, 2); ++ } else if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { ++ if (insuspend & AP_DOWN_IN_SUSPEND) { ++ dhd_conf_set_intiovar(dhd, WLC_DOWN, "WLC_DOWN", 1, 0, FALSE); ++ } ++ } ++#if defined(WL_CFG80211) || defined(WL_ESCAN) ++ if (insuspend & (NO_EVENT_IN_SUSPEND|NO_TXCTL_IN_SUSPEND|WOWL_IN_SUSPEND)) { ++ if (conf->suspend_mode == PM_NOTIFIER) ++ dhd_conf_wait_event_complete(dhd, 0); ++ } ++#endif ++ if (insuspend & NO_TXDATA_IN_SUSPEND) { ++ dhd_txflowcontrol(dhd, ALL_INTERFACES, ON); ++ } ++#if defined(WL_CFG80211) || defined(WL_ESCAN) ++ if (insuspend & (NO_EVENT_IN_SUSPEND|NO_TXCTL_IN_SUSPEND|WOWL_IN_SUSPEND)) { ++ if (conf->suspend_mode == PM_NOTIFIER) ++ wl_ext_user_sync(dhd, 0, TRUE); ++ } ++#endif ++#ifdef SUSPEND_EVENT ++ if (insuspend & NO_EVENT_IN_SUSPEND) { ++ dhd_conf_set_suspend_event(dhd, suspend); ++ } ++#endif ++ if (dhd->op_mode & DHD_FLAG_STA_MODE) { ++ if (conf->pm_in_suspend >= 0) ++ pm = conf->pm_in_suspend; ++ else if (conf->pm >= 0) ++ pm = conf->pm; ++ else ++ pm = PM_FAST; ++ dhd_conf_set_intiovar(dhd, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE); ++ } ++ dhd_conf_set_wl_cmd(dhd, conf->wl_suspend, FALSE); ++#ifdef WL_EXT_WOWL ++ if ((insuspend & WOWL_IN_SUSPEND) && dhd_master_mode) { ++ dhd_conf_wowl_pattern(dhd, FALSE, "clr"); ++ for(i=0; ipkt_filter_add.count; i++) { ++ dhd_conf_wowl_pattern(dhd, TRUE, conf->pkt_filter_add.filter[i]); ++ } ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "wowl", conf->wowl, 0, FALSE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "wowl_activate", 1, 0, FALSE); ++ dhd_conf_wowl_wakeind(dhd, TRUE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "hostsleep", 1, 0, FALSE); ++#ifdef BCMSDIO ++ ret = dhd_bus_sleep(dhd, TRUE, &intstatus); ++ CONFIG_TRACE("ret = %d, intstatus = 0x%x\n", ret, intstatus); ++#endif ++ } else ++#endif ++ if (insuspend & NO_TXCTL_IN_SUSPEND) { ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "hostsleep", 2, 0, FALSE); ++#ifdef BCMSDIO ++ ret = dhd_bus_sleep(dhd, TRUE, &intstatus); ++ CONFIG_TRACE("ret = %d, intstatus = 0x%x\n", ret, intstatus); ++#endif ++ } ++ conf->suspended = TRUE; ++ } else { ++ if (insuspend & (WOWL_IN_SUSPEND | NO_TXCTL_IN_SUSPEND)) { ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "hostsleep", 0, 0, FALSE); ++ } ++#ifdef WL_EXT_WOWL ++ if (insuspend & WOWL_IN_SUSPEND) { ++ dhd_conf_wowl_wakeind(dhd, FALSE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "wowl_activate", 0, 0, FALSE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "wowl", 0, 0, FALSE); ++ dhd_conf_wowl_pattern(dhd, FALSE, "clr"); ++ } ++#endif ++ dhd_conf_set_wl_cmd(dhd, conf->wl_resume, FALSE); ++ dhd_conf_get_iovar(dhd, 0, WLC_GET_PM, "WLC_GET_PM", (char *)&pm, sizeof(pm)); ++ CONFIG_TRACE("PM in suspend = %d\n", pm); ++#ifdef SUSPEND_EVENT ++ if (insuspend & NO_EVENT_IN_SUSPEND) { ++ dhd_conf_set_suspend_event(dhd, suspend); ++ } ++#endif ++#if defined(WL_CFG80211) || defined(WL_ESCAN) ++ if (insuspend & (NO_EVENT_IN_SUSPEND|NO_TXCTL_IN_SUSPEND|WOWL_IN_SUSPEND)) { ++ if (conf->suspend_mode == PM_NOTIFIER) ++ wl_ext_user_sync(dhd, 0, FALSE); ++ } ++#endif ++ if (insuspend & NO_TXDATA_IN_SUSPEND) { ++ dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); ++ } ++ if (dhd->op_mode & DHD_FLAG_STA_MODE) { ++ if (insuspend & ROAM_OFFLOAD_IN_SUSPEND) ++ dhd_conf_enable_roam_offload(dhd, 0); ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_li_dtim", 0, 0, FALSE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "roam_off", ++ dhd->conf->roam_off, 0, FALSE); ++ } else if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { ++ if (insuspend & AP_DOWN_IN_SUSPEND) { ++ dhd_conf_set_intiovar(dhd, WLC_UP, "WLC_UP", 0, 0, FALSE); ++ } ++ } ++ if (dhd->op_mode & DHD_FLAG_STA_MODE) { ++ if (conf->pm >= 0) ++ pm = conf->pm; ++ else ++ pm = PM_FAST; ++ dhd_conf_set_intiovar(dhd, WLC_SET_PM, "WLC_SET_PM", pm, 0, FALSE); ++ } ++ conf->suspended = FALSE; ++ } ++ ++ return 0; ++} ++ ++#ifdef PROP_TXSTATUS ++int ++dhd_conf_get_disable_proptx(dhd_pub_t *dhd) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ int disable_proptx = -1; ++ int fw_proptx = 0; ++ ++ /* check fw proptx priority: ++ * 1st: check fw support by wl cap ++ * 2nd: 4334/43340/43341/43241 support proptx but not show in wl cap, so enable it by default ++ * if you would like to disable it, please set disable_proptx=1 in config.txt ++ * 3th: disable when proptxstatus not support in wl cap ++ */ ++ if (FW_SUPPORTED(dhd, proptxstatus)) { ++ fw_proptx = 1; ++ } else if (conf->chip == BCM4334_CHIP_ID || conf->chip == BCM43340_CHIP_ID || ++ dhd->conf->chip == BCM43340_CHIP_ID || conf->chip == BCM4324_CHIP_ID) { ++ fw_proptx = 1; ++ } else { ++ fw_proptx = 0; ++ } ++ ++ /* returned disable_proptx value: ++ * -1: disable in STA and enable in P2P(follow original dhd settings when PROP_TXSTATUS_VSDB enabled) ++ * 0: depend on fw support ++ * 1: always disable proptx ++ */ ++ if (conf->disable_proptx == 0) { ++ // check fw support as well ++ if (fw_proptx) ++ disable_proptx = 0; ++ else ++ disable_proptx = 1; ++ } else if (conf->disable_proptx >= 1) { ++ disable_proptx = 1; ++ } else { ++ // check fw support as well ++ if (fw_proptx) ++ disable_proptx = -1; ++ else ++ disable_proptx = 1; ++ } ++ ++ CONFIG_MSG("fw_proptx=%d, disable_proptx=%d\n", fw_proptx, disable_proptx); ++ ++ return disable_proptx; ++} ++#endif ++ ++uint ++pick_config_vars(char *varbuf, uint len, uint start_pos, char *pickbuf, int picklen) ++{ ++ bool findNewline, changenewline=FALSE, pick=FALSE; ++ int column; ++ uint n, pick_column=0; ++ ++ findNewline = FALSE; ++ column = 0; ++ ++ if (start_pos >= len) { ++ CONFIG_ERROR("wrong start pos\n"); ++ return 0; ++ } ++ ++ for (n = start_pos; n < len; n++) { ++ if (varbuf[n] == '\r') ++ continue; ++ if ((findNewline || changenewline) && varbuf[n] != '\n') ++ continue; ++ findNewline = FALSE; ++ if (varbuf[n] == '#') { ++ findNewline = TRUE; ++ continue; ++ } ++ if (varbuf[n] == '\\') { ++ changenewline = TRUE; ++ continue; ++ } ++ if (!changenewline && varbuf[n] == '\n') { ++ if (column == 0) ++ continue; ++ column = 0; ++ continue; ++ } ++ if (changenewline && varbuf[n] == '\n') { ++ changenewline = FALSE; ++ continue; ++ } ++ ++ if (column==0 && !pick) { // start to pick ++ pick = TRUE; ++ column++; ++ pick_column = 0; ++ } else { ++ if (pick && column==0) { // stop to pick ++ pick = FALSE; ++ break; ++ } else ++ column++; ++ } ++ if (pick) { ++ if (varbuf[n] == 0x9) ++ continue; ++ if (pick_column >= picklen) ++ break; ++ pickbuf[pick_column] = varbuf[n]; ++ pick_column++; ++ } ++ } ++ ++ return n; // return current position ++} ++ ++bool ++dhd_conf_read_chiprev(dhd_pub_t *dhd, int *chip_match, ++ char *full_param, uint len_param) ++{ ++ char *data = full_param+len_param, *pick_tmp, *pch; ++ uint chip = 0, rev = 0; ++ ++ /* Process chip, regrev: ++ * chip=[chipid], rev==[rev] ++ * Ex: chip=0x4359, rev=9 ++ */ ++ if (!strncmp("chip=", full_param, len_param)) { ++ chip = (int)simple_strtol(data, NULL, 0); ++ pick_tmp = data; ++ pch = bcmstrstr(pick_tmp, "rev="); ++ if (pch) { ++ rev = (int)simple_strtol(pch+strlen("rev="), NULL, 0); ++ } ++ if (chip == dhd->conf->chip && rev == dhd->conf->chiprev) ++ *chip_match = 1; ++ else ++ *chip_match = 0; ++ CONFIG_MSG("chip=0x%x, rev=%d, chip_match=%d\n", chip, rev, *chip_match); ++ } ++ ++ return TRUE; ++} ++ ++bool ++dhd_conf_read_log_level(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ char *data = full_param+len_param; ++ ++ if (!strncmp("dhd_msg_level=", full_param, len_param)) { ++ dhd_msg_level = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("dhd_msg_level = 0x%X\n", dhd_msg_level); ++ } ++ else if (!strncmp("dump_msg_level=", full_param, len_param)) { ++ dump_msg_level = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("dump_msg_level = 0x%X\n", dump_msg_level); ++ } ++#ifdef BCMSDIO ++ else if (!strncmp("sd_msglevel=", full_param, len_param)) { ++ sd_msglevel = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("sd_msglevel = 0x%X\n", sd_msglevel); ++ } ++#endif ++#ifdef BCMDBUS ++ else if (!strncmp("dbus_msglevel=", full_param, len_param)) { ++ dbus_msglevel = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("dbus_msglevel = 0x%X\n", dbus_msglevel); ++ } ++#endif ++ else if (!strncmp("android_msg_level=", full_param, len_param)) { ++ android_msg_level = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("android_msg_level = 0x%X\n", android_msg_level); ++ } ++ else if (!strncmp("config_msg_level=", full_param, len_param)) { ++ config_msg_level = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("config_msg_level = 0x%X\n", config_msg_level); ++ } ++#ifdef WL_CFG80211 ++ else if (!strncmp("wl_dbg_level=", full_param, len_param)) { ++ wl_dbg_level = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("wl_dbg_level = 0x%X\n", wl_dbg_level); ++ } ++#endif ++#if defined(WL_WIRELESS_EXT) ++ else if (!strncmp("iw_msg_level=", full_param, len_param)) { ++ iw_msg_level = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("iw_msg_level = 0x%X\n", iw_msg_level); ++ } ++#endif ++#if defined(DHD_DEBUG) ++ else if (!strncmp("dhd_console_ms=", full_param, len_param)) { ++ dhd_console_ms = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("dhd_console_ms = 0x%X\n", dhd_console_ms); ++ } ++#endif ++ else ++ return false; ++ ++ return true; ++} ++ ++void ++dhd_conf_read_wme_ac_value(wme_param_t *wme, char *pick, int ac_val) ++{ ++ char *pick_tmp, *pch; ++ ++ pick_tmp = pick; ++ pch = bcmstrstr(pick_tmp, "aifsn "); ++ if (pch) { ++ wme->aifsn[ac_val] = (int)simple_strtol(pch+strlen("aifsn "), NULL, 0); ++ CONFIG_MSG("ac_val=%d, aifsn=%d\n", ac_val, wme->aifsn[ac_val]); ++ } ++ pick_tmp = pick; ++ pch = bcmstrstr(pick_tmp, "ecwmin "); ++ if (pch) { ++ wme->ecwmin[ac_val] = (int)simple_strtol(pch+strlen("ecwmin "), NULL, 0); ++ CONFIG_MSG("ac_val=%d, ecwmin=%d\n", ac_val, wme->ecwmin[ac_val]); ++ } ++ pick_tmp = pick; ++ pch = bcmstrstr(pick_tmp, "ecwmax "); ++ if (pch) { ++ wme->ecwmax[ac_val] = (int)simple_strtol(pch+strlen("ecwmax "), NULL, 0); ++ CONFIG_MSG("ac_val=%d, ecwmax=%d\n", ac_val, wme->ecwmax[ac_val]); ++ } ++ pick_tmp = pick; ++ pch = bcmstrstr(pick_tmp, "txop "); ++ if (pch) { ++ wme->txop[ac_val] = (int)simple_strtol(pch+strlen("txop "), NULL, 0); ++ CONFIG_MSG("ac_val=%d, txop=0x%x\n", ac_val, wme->txop[ac_val]); ++ } ++ ++} ++ ++bool ++dhd_conf_read_wme_ac_params(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ char *data = full_param+len_param; ++ ++ // wme_ac_sta_be=aifsn 1 ecwmin 2 ecwmax 3 txop 0x5e ++ // wme_ac_sta_vo=aifsn 1 ecwmin 1 ecwmax 1 txop 0x5e ++ ++ if (!strncmp("force_wme_ac=", full_param, len_param)) { ++ conf->force_wme_ac = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("force_wme_ac = %d\n", conf->force_wme_ac); ++ } ++ else if (!strncmp("wme_ac_sta_be=", full_param, len_param)) { ++ dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_BE); ++ } ++ else if (!strncmp("wme_ac_sta_bk=", full_param, len_param)) { ++ dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_BK); ++ } ++ else if (!strncmp("wme_ac_sta_vi=", full_param, len_param)) { ++ dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_VI); ++ } ++ else if (!strncmp("wme_ac_sta_vo=", full_param, len_param)) { ++ dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_VO); ++ } ++ else if (!strncmp("wme_ac_ap_be=", full_param, len_param)) { ++ dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_BE); ++ } ++ else if (!strncmp("wme_ac_ap_bk=", full_param, len_param)) { ++ dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_BK); ++ } ++ else if (!strncmp("wme_ac_ap_vi=", full_param, len_param)) { ++ dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_VI); ++ } ++ else if (!strncmp("wme_ac_ap_vo=", full_param, len_param)) { ++ dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_VO); ++ } ++ else ++ return false; ++ ++ return true; ++} ++ ++#ifdef BCMSDIO ++bool ++dhd_conf_read_fw_by_mac(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ int i, j; ++ char *pch, *pick_tmp; ++ wl_mac_list_t *mac_list; ++ wl_mac_range_t *mac_range; ++ struct dhd_conf *conf = dhd->conf; ++ char *data = full_param+len_param; ++ ++ /* Process fw_by_mac: ++ * fw_by_mac=[fw_mac_num] \ ++ * [fw_name1] [mac_num1] [oui1-1] [nic_start1-1] [nic_end1-1] \ ++ * [oui1-1] [nic_start1-1] [nic_end1-1]... \ ++ * [oui1-n] [nic_start1-n] [nic_end1-n] \ ++ * [fw_name2] [mac_num2] [oui2-1] [nic_start2-1] [nic_end2-1] \ ++ * [oui2-1] [nic_start2-1] [nic_end2-1]... \ ++ * [oui2-n] [nic_start2-n] [nic_end2-n] \ ++ * Ex: fw_by_mac=2 \ ++ * fw_bcmdhd1.bin 2 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \ ++ * fw_bcmdhd2.bin 3 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \ ++ * 0x983B16 0x916157 0x916487 ++ */ ++ ++ if (!strncmp("fw_by_mac=", full_param, len_param)) { ++ dhd_conf_free_mac_list(&conf->fw_by_mac); ++ pick_tmp = data; ++ pch = bcmstrtok(&pick_tmp, " ", 0); ++ conf->fw_by_mac.count = (uint32)simple_strtol(pch, NULL, 0); ++ if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->fw_by_mac.count, ++ GFP_KERNEL))) { ++ conf->fw_by_mac.count = 0; ++ CONFIG_ERROR("kmalloc failed\n"); ++ } ++ CONFIG_MSG("fw_count=%d\n", conf->fw_by_mac.count); ++ conf->fw_by_mac.m_mac_list_head = mac_list; ++ for (i=0; ifw_by_mac.count; i++) { ++ pch = bcmstrtok(&pick_tmp, " ", 0); ++ strcpy(mac_list[i].name, pch); ++ pch = bcmstrtok(&pick_tmp, " ", 0); ++ mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0); ++ CONFIG_MSG("name=%s, mac_count=%d\n", ++ mac_list[i].name, mac_list[i].count); ++ if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count, ++ GFP_KERNEL))) { ++ mac_list[i].count = 0; ++ CONFIG_ERROR("kmalloc failed\n"); ++ break; ++ } ++ mac_list[i].mac = mac_range; ++ for (j=0; jconf; ++ char *data = full_param+len_param; ++ ++ /* Process nv_by_mac: ++ * [nv_by_mac]: The same format as fw_by_mac ++ */ ++ if (!strncmp("nv_by_mac=", full_param, len_param)) { ++ dhd_conf_free_mac_list(&conf->nv_by_mac); ++ pick_tmp = data; ++ pch = bcmstrtok(&pick_tmp, " ", 0); ++ conf->nv_by_mac.count = (uint32)simple_strtol(pch, NULL, 0); ++ if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->nv_by_mac.count, ++ GFP_KERNEL))) { ++ conf->nv_by_mac.count = 0; ++ CONFIG_ERROR("kmalloc failed\n"); ++ } ++ CONFIG_MSG("nv_count=%d\n", conf->nv_by_mac.count); ++ conf->nv_by_mac.m_mac_list_head = mac_list; ++ for (i=0; inv_by_mac.count; i++) { ++ pch = bcmstrtok(&pick_tmp, " ", 0); ++ strcpy(mac_list[i].name, pch); ++ pch = bcmstrtok(&pick_tmp, " ", 0); ++ mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0); ++ CONFIG_MSG("name=%s, mac_count=%d\n", ++ mac_list[i].name, mac_list[i].count); ++ if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count, ++ GFP_KERNEL))) { ++ mac_list[i].count = 0; ++ CONFIG_ERROR("kmalloc failed\n"); ++ break; ++ } ++ mac_list[i].mac = mac_range; ++ for (j=0; jconf; ++ char *data = full_param+len_param; ++ ++ /* Process nv_by_chip: ++ * nv_by_chip=[nv_chip_num] \ ++ * [chip1] [chiprev1] [nv_name1] [chip2] [chiprev2] [nv_name2] \ ++ * Ex: nv_by_chip=2 \ ++ * 43430 0 nvram_ap6212.txt 43430 1 nvram_ap6212a.txt \ ++ */ ++ if (!strncmp("nv_by_chip=", full_param, len_param)) { ++ dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip); ++ pick_tmp = data; ++ pch = bcmstrtok(&pick_tmp, " ", 0); ++ conf->nv_by_chip.count = (uint32)simple_strtol(pch, NULL, 0); ++ if (!(chip_nv_path = kmalloc(sizeof(wl_mac_list_t)*conf->nv_by_chip.count, ++ GFP_KERNEL))) { ++ conf->nv_by_chip.count = 0; ++ CONFIG_ERROR("kmalloc failed\n"); ++ } ++ CONFIG_MSG("nv_by_chip_count=%d\n", conf->nv_by_chip.count); ++ conf->nv_by_chip.m_chip_nv_path_head = chip_nv_path; ++ for (i=0; inv_by_chip.count; i++) { ++ pch = bcmstrtok(&pick_tmp, " ", 0); ++ chip_nv_path[i].chip = (uint32)simple_strtol(pch, NULL, 0); ++ pch = bcmstrtok(&pick_tmp, " ", 0); ++ chip_nv_path[i].chiprev = (uint32)simple_strtol(pch, NULL, 0); ++ pch = bcmstrtok(&pick_tmp, " ", 0); ++ strcpy(chip_nv_path[i].name, pch); ++ CONFIG_MSG("chip=0x%x, chiprev=%d, name=%s\n", ++ chip_nv_path[i].chip, chip_nv_path[i].chiprev, chip_nv_path[i].name); ++ } ++ } ++ else ++ return false; ++ ++ return true; ++} ++ ++bool ++dhd_conf_read_roam_params(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ char *data = full_param+len_param; ++ ++ if (!strncmp("roam_off=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->roam_off = 0; ++ else ++ conf->roam_off = 1; ++ CONFIG_MSG("roam_off = %d\n", conf->roam_off); ++ } ++ else if (!strncmp("roam_off_suspend=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->roam_off_suspend = 0; ++ else ++ conf->roam_off_suspend = 1; ++ CONFIG_MSG("roam_off_suspend = %d\n", conf->roam_off_suspend); ++ } ++ else if (!strncmp("roam_trigger=", full_param, len_param)) { ++ conf->roam_trigger[0] = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("roam_trigger = %d\n", conf->roam_trigger[0]); ++ } ++ else if (!strncmp("roam_scan_period=", full_param, len_param)) { ++ conf->roam_scan_period[0] = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("roam_scan_period = %d\n", conf->roam_scan_period[0]); ++ } ++ else if (!strncmp("roam_delta=", full_param, len_param)) { ++ conf->roam_delta[0] = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("roam_delta = %d\n", conf->roam_delta[0]); ++ } ++ else if (!strncmp("fullroamperiod=", full_param, len_param)) { ++ conf->fullroamperiod = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("fullroamperiod = %d\n", conf->fullroamperiod); ++ } else ++ return false; ++ ++ return true; ++} ++ ++bool ++dhd_conf_read_country(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ country_list_t *country_next = NULL, *country; ++ int i, count = 0; ++ char *pch, *pick_tmp, *pick_tmp2; ++ char *data = full_param+len_param; ++ uint len_data = strlen(data); ++ ++ /* Process country_list: ++ * country_list=[country1]:[ccode1]/[regrev1], ++ * [country2]:[ccode2]/[regrev2] \ ++ * Ex: country_list=US:US/0, TW:TW/1 ++ */ ++ if (!strncmp("ccode=", full_param, len_param)) { ++ len_data = min((uint)WLC_CNTRY_BUF_SZ, len_data); ++ memset(&conf->cspec, 0, sizeof(wl_country_t)); ++ memcpy(conf->cspec.country_abbrev, data, len_data); ++ memcpy(conf->cspec.ccode, data, len_data); ++ CONFIG_MSG("ccode = %s\n", conf->cspec.ccode); ++ } ++ else if (!strncmp("regrev=", full_param, len_param)) { ++ conf->cspec.rev = (int32)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("regrev = %d\n", conf->cspec.rev); ++ } ++ else if (!strncmp("country_list=", full_param, len_param)) { ++ dhd_conf_free_country_list(conf); ++ pick_tmp = data; ++ for (i=0; icspec.country_abbrev, pch, 2); ++ pch = bcmstrtok(&pick_tmp2, "/", 0); ++ if (!pch) { ++ kfree(country); ++ break; ++ } ++ memcpy(country->cspec.ccode, pch, 2); ++ pch = bcmstrtok(&pick_tmp2, "/", 0); ++ if (!pch) { ++ kfree(country); ++ break; ++ } ++ country->cspec.rev = (int32)simple_strtol(pch, NULL, 10); ++ count++; ++ if (!conf->country_head) { ++ conf->country_head = country; ++ country_next = country; ++ } else { ++ country_next->next = country; ++ country_next = country; ++ } ++ CONFIG_TRACE("abbrev=%s, ccode=%s, regrev=%d\n", ++ country->cspec.country_abbrev, country->cspec.ccode, country->cspec.rev); ++ } ++ CONFIG_MSG("%d country in list\n", count); ++ } ++ else ++ return false; ++ ++ return true; ++} ++ ++bool ++dhd_conf_read_mchan_params(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ int i; ++ char *pch, *pick_tmp, *pick_tmp2; ++ struct dhd_conf *conf = dhd->conf; ++ mchan_params_t *mchan_next = NULL, *mchan; ++ char *data = full_param+len_param; ++ ++ /* Process mchan_bw: ++ * mchan_bw=[val]/[any/go/gc]/[any/source/sink] ++ * Ex: mchan_bw=80/go/source, 30/gc/sink ++ */ ++ if (!strncmp("mchan_bw=", full_param, len_param)) { ++ dhd_conf_free_mchan_list(conf); ++ pick_tmp = data; ++ for (i=0; ibw = (int)simple_strtol(pch, NULL, 0); ++ if (mchan->bw < 0 || mchan->bw > 100) { ++ CONFIG_ERROR("wrong bw %d\n", mchan->bw); ++ kfree(mchan); ++ break; ++ } ++ ++ pch = bcmstrtok(&pick_tmp2, "/", 0); ++ if (!pch) { ++ kfree(mchan); ++ break; ++ } else { ++ if (bcmstrstr(pch, "any")) { ++ mchan->p2p_mode = -1; ++ } else if (bcmstrstr(pch, "go")) { ++ mchan->p2p_mode = WL_P2P_IF_GO; ++ } else if (bcmstrstr(pch, "gc")) { ++ mchan->p2p_mode = WL_P2P_IF_CLIENT; ++ } ++ } ++ pch = bcmstrtok(&pick_tmp2, "/", 0); ++ if (!pch) { ++ kfree(mchan); ++ break; ++ } else { ++ if (bcmstrstr(pch, "any")) { ++ mchan->miracast_mode = -1; ++ } else if (bcmstrstr(pch, "source")) { ++ mchan->miracast_mode = MIRACAST_SOURCE; ++ } else if (bcmstrstr(pch, "sink")) { ++ mchan->miracast_mode = MIRACAST_SINK; ++ } ++ } ++ if (!conf->mchan) { ++ conf->mchan = mchan; ++ mchan_next = mchan; ++ } else { ++ mchan_next->next = mchan; ++ mchan_next = mchan; ++ } ++ CONFIG_TRACE("mchan_bw=%d/%d/%d\n", mchan->bw,mchan->p2p_mode, ++ mchan->miracast_mode); ++ } ++ } ++ else ++ return false; ++ ++ return true; ++} ++ ++#ifdef PKT_FILTER_SUPPORT ++bool ++dhd_conf_read_pkt_filter(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ char *data = full_param+len_param; ++ char *pch, *pick_tmp; ++ int i; ++ ++ /* Process pkt filter: ++ * 1) pkt_filter_add=99 0 0 0 0x000000000000 0x000000000000 ++ * 2) pkt_filter_delete=100, 102, 103, 104, 105 ++ * 3) magic_pkt_filter_add=141 0 1 12 ++ */ ++ if (!strncmp("dhd_master_mode=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ dhd_master_mode = FALSE; ++ else ++ dhd_master_mode = TRUE; ++ CONFIG_MSG("dhd_master_mode = %d\n", dhd_master_mode); ++ } ++ else if (!strncmp("pkt_filter_add=", full_param, len_param)) { ++ pick_tmp = data; ++ pch = bcmstrtok(&pick_tmp, ",.-", 0); ++ i=0; ++ while (pch != NULL && ipkt_filter_add.filter[i][0], pch); ++ CONFIG_MSG("pkt_filter_add[%d][] = %s\n", ++ i, &conf->pkt_filter_add.filter[i][0]); ++ pch = bcmstrtok(&pick_tmp, ",.-", 0); ++ i++; ++ } ++ conf->pkt_filter_add.count = i; ++ } ++ else if (!strncmp("pkt_filter_delete=", full_param, len_param) || ++ !strncmp("pkt_filter_del=", full_param, len_param)) { ++ pick_tmp = data; ++ pch = bcmstrtok(&pick_tmp, " ,.-", 0); ++ i=0; ++ while (pch != NULL && ipkt_filter_del.id[i] = (uint32)simple_strtol(pch, NULL, 10); ++ pch = bcmstrtok(&pick_tmp, " ,.-", 0); ++ i++; ++ } ++ conf->pkt_filter_del.count = i; ++ CONFIG_MSG("pkt_filter_del id = "); ++ for (i=0; ipkt_filter_del.count; i++) ++ printf("%d ", conf->pkt_filter_del.id[i]); ++ printf("\n"); ++ } ++ else if (!strncmp("magic_pkt_filter_add=", full_param, len_param)) { ++ if (conf->magic_pkt_filter_add) { ++ kfree(conf->magic_pkt_filter_add); ++ conf->magic_pkt_filter_add = NULL; ++ } ++ if (!(conf->magic_pkt_filter_add = kmalloc(MAGIC_PKT_FILTER_LEN, GFP_KERNEL))) { ++ CONFIG_ERROR("kmalloc failed\n"); ++ } else { ++ memset(conf->magic_pkt_filter_add, 0, MAGIC_PKT_FILTER_LEN); ++ strcpy(conf->magic_pkt_filter_add, data); ++ CONFIG_MSG("magic_pkt_filter_add = %s\n", conf->magic_pkt_filter_add); ++ } ++ } ++ else ++ return false; ++ ++ return true; ++} ++#endif ++ ++#ifdef ISAM_PREINIT ++#if !defined(WL_EXT_IAPSTA) ++#error "WL_EXT_IAPSTA should be defined to enable ISAM_PREINIT" ++#endif /* !WL_EXT_IAPSTA */ ++/* ++ * isam_init=mode [sta|ap|apsta|dualap] vifname [wlan1] ++ * isam_config=ifname [wlan0|wlan1] ssid [xxx] chan [x] ++ hidden [y|n] maxassoc [x] ++ amode [open|shared|wpapsk|wpa2psk|wpawpa2psk] ++ emode [none|wep|tkip|aes|tkipaes] ++ key [xxxxx] ++ * isam_enable=ifname [wlan0|wlan1] ++*/ ++bool ++dhd_conf_read_isam(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ char *data = full_param+len_param; ++ ++ if (!strncmp("isam_init=", full_param, len_param)) { ++ sprintf(conf->isam_init, "isam_init %s", data); ++ CONFIG_MSG("isam_init=%s\n", conf->isam_init); ++ } ++ else if (!strncmp("isam_config=", full_param, len_param)) { ++ sprintf(conf->isam_config, "isam_config %s", data); ++ CONFIG_MSG("isam_config=%s\n", conf->isam_config); ++ } ++ else if (!strncmp("isam_enable=", full_param, len_param)) { ++ sprintf(conf->isam_enable, "isam_enable %s", data); ++ CONFIG_MSG("isam_enable=%s\n", conf->isam_enable); ++ } ++ else ++ return false; ++ ++ return true; ++} ++#endif ++ ++#ifdef IDHCP ++bool ++dhd_conf_read_dhcp_params(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ char *data = full_param+len_param; ++ struct ipv4_addr ipa_set; ++ ++ if (!strncmp("dhcpc_enable=", full_param, len_param)) { ++ conf->dhcpc_enable = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("dhcpc_enable = %d\n", conf->dhcpc_enable); ++ } ++ else if (!strncmp("dhcpd_enable=", full_param, len_param)) { ++ conf->dhcpd_enable = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("dhcpd_enable = %d\n", conf->dhcpd_enable); ++ } ++ else if (!strncmp("dhcpd_ip_addr=", full_param, len_param)) { ++ if (!bcm_atoipv4(data, &ipa_set)) { ++ CONFIG_ERROR("dhcpd_ip_addr adress setting failed.n"); ++ return false; ++ } ++ memcpy(&conf->dhcpd_ip_addr, &ipa_set, sizeof(struct ipv4_addr)); ++ CONFIG_MSG("dhcpd_ip_addr = %s\n", data); ++ } ++ else if (!strncmp("dhcpd_ip_mask=", full_param, len_param)) { ++ if (!bcm_atoipv4(data, &ipa_set)) { ++ CONFIG_ERROR("dhcpd_ip_mask adress setting failed\n"); ++ return false; ++ } ++ memcpy(&conf->dhcpd_ip_mask, &ipa_set, sizeof(struct ipv4_addr)); ++ CONFIG_MSG("dhcpd_ip_mask = %s\n", data); ++ } ++ else if (!strncmp("dhcpd_ip_start=", full_param, len_param)) { ++ if (!bcm_atoipv4(data, &ipa_set)) { ++ CONFIG_ERROR("dhcpd_ip_start adress setting failed\n"); ++ return false; ++ } ++ memcpy(&conf->dhcpd_ip_start, &ipa_set, sizeof(struct ipv4_addr)); ++ CONFIG_MSG("dhcpd_ip_start = %s\n", data); ++ } ++ else if (!strncmp("dhcpd_ip_end=", full_param, len_param)) { ++ if (!bcm_atoipv4(data, &ipa_set)) { ++ CONFIG_ERROR("dhcpd_ip_end adress setting failed\n"); ++ return false; ++ } ++ memcpy(&conf->dhcpd_ip_end, &ipa_set, sizeof(struct ipv4_addr)); ++ CONFIG_MSG("dhcpd_ip_end = %s\n", data); ++ } ++ else ++ return false; ++ ++ return true; ++} ++#endif ++ ++#ifdef BCMSDIO ++bool ++dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ char *data = full_param+len_param; ++ ++ if (!strncmp("dhd_doflow=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ dhd_doflow = FALSE; ++ else ++ dhd_doflow = TRUE; ++ CONFIG_MSG("dhd_doflow = %d\n", dhd_doflow); ++ } ++ else if (!strncmp("dhd_slpauto=", full_param, len_param) || ++ !strncmp("kso_enable=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ dhd_slpauto = FALSE; ++ else ++ dhd_slpauto = TRUE; ++ CONFIG_MSG("dhd_slpauto = %d\n", dhd_slpauto); ++ } ++ else if (!strncmp("use_rxchain=", full_param, len_param)) { ++ conf->use_rxchain = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("use_rxchain = %d\n", conf->use_rxchain); ++ } ++ else if (!strncmp("dhd_txminmax=", full_param, len_param)) { ++ conf->dhd_txminmax = (uint)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("dhd_txminmax = %d\n", conf->dhd_txminmax); ++ } ++ else if (!strncmp("txinrx_thres=", full_param, len_param)) { ++ conf->txinrx_thres = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("txinrx_thres = %d\n", conf->txinrx_thres); ++ } ++#if defined(HW_OOB) ++ else if (!strncmp("oob_enabled_later=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->oob_enabled_later = FALSE; ++ else ++ conf->oob_enabled_later = TRUE; ++ CONFIG_MSG("oob_enabled_later = %d\n", conf->oob_enabled_later); ++ } ++#endif ++ else if (!strncmp("dpc_cpucore=", full_param, len_param)) { ++ conf->dpc_cpucore = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("dpc_cpucore = %d\n", conf->dpc_cpucore); ++ } ++ else if (!strncmp("rxf_cpucore=", full_param, len_param)) { ++ conf->rxf_cpucore = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("rxf_cpucore = %d\n", conf->rxf_cpucore); ++ } ++#if defined(BCMSDIOH_TXGLOM) ++ else if (!strncmp("txglomsize=", full_param, len_param)) { ++ conf->txglomsize = (uint)simple_strtol(data, NULL, 10); ++ if (conf->txglomsize > SDPCM_MAXGLOM_SIZE) ++ conf->txglomsize = SDPCM_MAXGLOM_SIZE; ++ CONFIG_MSG("txglomsize = %d\n", conf->txglomsize); ++ } ++ else if (!strncmp("txglom_ext=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->txglom_ext = FALSE; ++ else ++ conf->txglom_ext = TRUE; ++ CONFIG_MSG("txglom_ext = %d\n", conf->txglom_ext); ++ if (conf->txglom_ext) { ++ if ((conf->chip == BCM43362_CHIP_ID) || (conf->chip == BCM4330_CHIP_ID)) ++ conf->txglom_bucket_size = 1680; ++ else if (conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID || ++ conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) ++ conf->txglom_bucket_size = 1684; ++ } ++ CONFIG_MSG("txglom_bucket_size = %d\n", conf->txglom_bucket_size); ++ } ++ else if (!strncmp("bus:rxglom=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->bus_rxglom = FALSE; ++ else ++ conf->bus_rxglom = TRUE; ++ CONFIG_MSG("bus:rxglom = %d\n", conf->bus_rxglom); ++ } ++ else if (!strncmp("deferred_tx_len=", full_param, len_param)) { ++ conf->deferred_tx_len = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("deferred_tx_len = %d\n", conf->deferred_tx_len); ++ } ++ else if (!strncmp("txctl_tmo_fix=", full_param, len_param)) { ++ conf->txctl_tmo_fix = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("txctl_tmo_fix = %d\n", conf->txctl_tmo_fix); ++ } ++ else if (!strncmp("tx_max_offset=", full_param, len_param)) { ++ conf->tx_max_offset = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("tx_max_offset = %d\n", conf->tx_max_offset); ++ } ++ else if (!strncmp("txglom_mode=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->txglom_mode = FALSE; ++ else ++ conf->txglom_mode = TRUE; ++ CONFIG_MSG("txglom_mode = %d\n", conf->txglom_mode); ++ } ++#if defined(SDIO_ISR_THREAD) ++ else if (!strncmp("intr_extn=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->intr_extn = FALSE; ++ else ++ conf->intr_extn = TRUE; ++ CONFIG_MSG("intr_extn = %d\n", conf->intr_extn); ++ } ++#endif ++#ifdef BCMSDIO_RXLIM_POST ++ else if (!strncmp("rxlim_en=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->rxlim_en = FALSE; ++ else ++ conf->rxlim_en = TRUE; ++ CONFIG_MSG("rxlim_en = %d\n", conf->rxlim_en); ++ } ++#endif ++#endif ++ else ++ return false; ++ ++ return true; ++} ++#endif ++ ++#ifdef BCMPCIE ++bool ++dhd_conf_read_pcie_params(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ char *data = full_param+len_param; ++ ++ if (!strncmp("bus:deepsleep_disable=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->bus_deepsleep_disable = 0; ++ else ++ conf->bus_deepsleep_disable = 1; ++ CONFIG_MSG("bus:deepsleep_disable = %d\n", conf->bus_deepsleep_disable); ++ } ++ else ++ return false; ++ ++ return true; ++} ++#endif ++ ++bool ++dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ char *data = full_param+len_param; ++ ++ if (!strncmp("deepsleep=", full_param, len_param)) { ++ if (!strncmp(data, "1", 1)) ++ conf->deepsleep = TRUE; ++ else ++ conf->deepsleep = FALSE; ++ CONFIG_MSG("deepsleep = %d\n", conf->deepsleep); ++ } ++ else if (!strncmp("PM=", full_param, len_param)) { ++ conf->pm = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("PM = %d\n", conf->pm); ++ } ++ else if (!strncmp("pm_in_suspend=", full_param, len_param)) { ++ conf->pm_in_suspend = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("pm_in_suspend = %d\n", conf->pm_in_suspend); ++ } ++ else if (!strncmp("suspend_mode=", full_param, len_param)) { ++ conf->suspend_mode = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("suspend_mode = %d\n", conf->suspend_mode); ++ if (conf->suspend_mode == PM_NOTIFIER) ++ conf->insuspend |= (NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND); ++ } ++ else if (!strncmp("suspend_bcn_li_dtim=", full_param, len_param)) { ++ conf->suspend_bcn_li_dtim = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("suspend_bcn_li_dtim = %d\n", conf->suspend_bcn_li_dtim); ++ } ++ else if (!strncmp("xmit_in_suspend=", full_param, len_param)) { ++ if (!strncmp(data, "1", 1)) ++ conf->insuspend &= ~NO_TXDATA_IN_SUSPEND; ++ else ++ conf->insuspend |= NO_TXDATA_IN_SUSPEND; ++ CONFIG_MSG("insuspend = 0x%x\n", conf->insuspend); ++ } ++ else if (!strncmp("insuspend=", full_param, len_param)) { ++ conf->insuspend = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("insuspend = 0x%x\n", conf->insuspend); ++ } ++#ifdef WL_EXT_WOWL ++ else if (!strncmp("wowl=", full_param, len_param)) { ++ conf->wowl = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("wowl = 0x%x\n", conf->wowl); ++ } ++#endif ++ else ++ return false; ++ ++ return true; ++} ++ ++#ifdef GET_CUSTOM_MAC_FROM_CONFIG ++int ++bcm_str2hex(const char *p, char *ea, int size) ++{ ++ int i = 0; ++ char *ep; ++ ++ for (;;) { ++ ea[i++] = (char) bcm_strtoul(p, &ep, 16); ++ p = ep; ++ if (!*p++ || i == size) ++ break; ++ } ++ ++ return (i == size); ++} ++#endif ++ ++bool ++dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ char *data = full_param+len_param; ++ char *pch, *pick_tmp; ++ int i; ++#ifdef GET_CUSTOM_MAC_FROM_CONFIG ++ struct ether_addr ea_addr; ++ char macpad[56]; ++#endif ++ ++ if (!strncmp("dhd_poll=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->dhd_poll = 0; ++ else ++ conf->dhd_poll = 1; ++ CONFIG_MSG("dhd_poll = %d\n", conf->dhd_poll); ++ } ++ else if (!strncmp("dhd_watchdog_ms=", full_param, len_param)) { ++ dhd_watchdog_ms = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("dhd_watchdog_ms = %d\n", dhd_watchdog_ms); ++ } ++ else if (!strncmp("band=", full_param, len_param)) { ++ /* Process band: ++ * band=a for 5GHz only and band=b for 2.4GHz only ++ */ ++ if (!strcmp(data, "b")) ++ conf->band = WLC_BAND_2G; ++ else if (!strcmp(data, "a")) ++ conf->band = WLC_BAND_5G; ++ else ++ conf->band = WLC_BAND_AUTO; ++ CONFIG_MSG("band = %d\n", conf->band); ++ } ++ else if (!strncmp("bw_cap_2g=", full_param, len_param)) { ++ conf->bw_cap[0] = (uint)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("bw_cap_2g = %d\n", conf->bw_cap[0]); ++ } ++ else if (!strncmp("bw_cap_5g=", full_param, len_param)) { ++ conf->bw_cap[1] = (uint)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("bw_cap_5g = %d\n", conf->bw_cap[1]); ++ } ++ else if (!strncmp("bw_cap=", full_param, len_param)) { ++ pick_tmp = data; ++ pch = bcmstrtok(&pick_tmp, " ,.-", 0); ++ if (pch != NULL) { ++ conf->bw_cap[0] = (uint32)simple_strtol(pch, NULL, 0); ++ CONFIG_MSG("bw_cap 2g = %d\n", conf->bw_cap[0]); ++ } ++ pch = bcmstrtok(&pick_tmp, " ,.-", 0); ++ if (pch != NULL) { ++ conf->bw_cap[1] = (uint32)simple_strtol(pch, NULL, 0); ++ CONFIG_MSG("bw_cap 5g = %d\n", conf->bw_cap[1]); ++ } ++ } ++ else if (!strncmp("channels=", full_param, len_param)) { ++ pick_tmp = data; ++ pch = bcmstrtok(&pick_tmp, " ,.-", 0); ++ i=0; ++ while (pch != NULL && ichannels.channel[i] = (uint32)simple_strtol(pch, NULL, 10); ++ pch = bcmstrtok(&pick_tmp, " ,.-", 0); ++ i++; ++ } ++ conf->channels.count = i; ++ CONFIG_MSG("channels = "); ++ for (i=0; ichannels.count; i++) ++ printf("%d ", conf->channels.channel[i]); ++ printf("\n"); ++ } ++ else if (!strncmp("keep_alive_period=", full_param, len_param)) { ++ conf->keep_alive_period = (uint)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("keep_alive_period = %d\n", conf->keep_alive_period); ++ } ++#ifdef ARP_OFFLOAD_SUPPORT ++ else if (!strncmp("garp=", full_param, len_param)) { ++ if (!strncmp(data, "0", 1)) ++ conf->garp = FALSE; ++ else ++ conf->garp = TRUE; ++ CONFIG_MSG("garp = %d\n", conf->garp); ++ } ++#endif ++ else if (!strncmp("srl=", full_param, len_param)) { ++ conf->srl = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("srl = %d\n", conf->srl); ++ } ++ else if (!strncmp("lrl=", full_param, len_param)) { ++ conf->lrl = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("lrl = %d\n", conf->lrl); ++ } ++ else if (!strncmp("bcn_timeout=", full_param, len_param)) { ++ conf->bcn_timeout= (uint)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("bcn_timeout = %d\n", conf->bcn_timeout); ++ } ++ else if (!strncmp("frameburst=", full_param, len_param)) { ++ conf->frameburst = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("frameburst = %d\n", conf->frameburst); ++ } ++ else if (!strncmp("disable_proptx=", full_param, len_param)) { ++ conf->disable_proptx = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("disable_proptx = %d\n", conf->disable_proptx); ++ } ++#ifdef DHDTCPACK_SUPPRESS ++ else if (!strncmp("tcpack_sup_mode=", full_param, len_param)) { ++ conf->tcpack_sup_mode = (uint)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("tcpack_sup_mode = %d\n", conf->tcpack_sup_mode); ++ } ++#endif ++ else if (!strncmp("pktprio8021x=", full_param, len_param)) { ++ conf->pktprio8021x = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("pktprio8021x = %d\n", conf->pktprio8021x); ++ } ++#if defined(BCMSDIO) || defined(BCMPCIE) ++ else if (!strncmp("dhd_txbound=", full_param, len_param)) { ++ dhd_txbound = (uint)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("dhd_txbound = %d\n", dhd_txbound); ++ } ++ else if (!strncmp("dhd_rxbound=", full_param, len_param)) { ++ dhd_rxbound = (uint)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("dhd_rxbound = %d\n", dhd_rxbound); ++ } ++#endif ++ else if (!strncmp("orphan_move=", full_param, len_param)) { ++ conf->orphan_move = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("orphan_move = %d\n", conf->orphan_move); ++ } ++ else if (!strncmp("tsq=", full_param, len_param)) { ++ conf->tsq = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("tsq = %d\n", conf->tsq); ++ } ++ else if (!strncmp("ctrl_resched=", full_param, len_param)) { ++ conf->ctrl_resched = (int)simple_strtol(data, NULL, 10); ++ CONFIG_MSG("ctrl_resched = %d\n", conf->ctrl_resched); ++ } ++ else if (!strncmp("in4way=", full_param, len_param)) { ++ conf->in4way = (int)simple_strtol(data, NULL, 0); ++ CONFIG_MSG("in4way = 0x%x\n", conf->in4way); ++ } ++ else if (!strncmp("wl_preinit=", full_param, len_param)) { ++ if (conf->wl_preinit) { ++ kfree(conf->wl_preinit); ++ conf->wl_preinit = NULL; ++ } ++ if (!(conf->wl_preinit = kmalloc(len_param+1, GFP_KERNEL))) { ++ CONFIG_ERROR("kmalloc failed\n"); ++ } else { ++ memset(conf->wl_preinit, 0, len_param+1); ++ strcpy(conf->wl_preinit, data); ++ CONFIG_MSG("wl_preinit = %s\n", conf->wl_preinit); ++ } ++ } ++ else if (!strncmp("wl_suspend=", full_param, len_param)) { ++ if (conf->wl_suspend) { ++ kfree(conf->wl_suspend); ++ conf->wl_suspend = NULL; ++ } ++ if (!(conf->wl_suspend = kmalloc(len_param+1, GFP_KERNEL))) { ++ CONFIG_ERROR("kmalloc failed\n"); ++ } else { ++ memset(conf->wl_suspend, 0, len_param+1); ++ strcpy(conf->wl_suspend, data); ++ CONFIG_MSG("wl_suspend = %s\n", conf->wl_suspend); ++ } ++ } ++ else if (!strncmp("wl_resume=", full_param, len_param)) { ++ if (conf->wl_resume) { ++ kfree(conf->wl_resume); ++ conf->wl_resume = NULL; ++ } ++ if (!(conf->wl_resume = kmalloc(len_param+1, GFP_KERNEL))) { ++ CONFIG_ERROR("kmalloc failed\n"); ++ } else { ++ memset(conf->wl_resume, 0, len_param+1); ++ strcpy(conf->wl_resume, data); ++ CONFIG_MSG("wl_resume = %s\n", conf->wl_resume); ++ } ++ } ++#ifdef GET_CUSTOM_MAC_FROM_CONFIG ++ else if (!strncmp("mac=", full_param, len_param)) { ++ if (!bcm_ether_atoe(data, &ea_addr)) { ++ CONFIG_ERROR("mac adress read error"); ++ return false; ++ } ++ memcpy(&conf->hw_ether, &ea_addr, ETHER_ADDR_LEN); ++ CONFIG_MSG("mac = %s\n", data); ++ } ++ else if (!strncmp("macpad=", full_param, len_param)) { ++ if (!bcm_str2hex(data, macpad, sizeof(macpad))) { ++ CONFIG_ERROR("macpad adress read error"); ++ return false; ++ } ++ memcpy(&conf->hw_ether[ETHER_ADDR_LEN], macpad, sizeof(macpad)); ++ if (config_msg_level & CONFIG_TRACE_LEVEL) { ++ printf("macpad =\n"); ++ for (i=0; ihw_ether[ETHER_ADDR_LEN+i]); ++ if ((i+1)%8 == 0) ++ printf("\n"); ++ } ++ } ++ } ++#endif ++ else ++ return false; ++ ++ return true; ++} ++ ++int ++dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path) ++{ ++ int bcmerror = -1, chip_match = -1; ++ uint len = 0, start_pos=0, end_pos=0; ++ void *image = NULL; ++ char *memblock = NULL; ++ char *bufp, *pick = NULL, *pch; ++ bool conf_file_exists; ++ uint len_param; ++ ++ conf_file_exists = ((conf_path != NULL) && (conf_path[0] != '\0')); ++ if (!conf_file_exists) { ++ CONFIG_MSG("config path %s\n", conf_path); ++ return (0); ++ } ++ ++ if (conf_file_exists) { ++ image = dhd_os_open_image(conf_path); ++ if (image == NULL) { ++ CONFIG_MSG("Ignore config file %s\n", conf_path); ++ goto err; ++ } ++ } ++ ++ memblock = MALLOC(dhd->osh, MAXSZ_CONFIG); ++ if (memblock == NULL) { ++ CONFIG_ERROR("Failed to allocate memory %d bytes\n", MAXSZ_CONFIG); ++ goto err; ++ } ++ ++ pick = MALLOC(dhd->osh, MAXSZ_BUF); ++ if (!pick) { ++ CONFIG_ERROR("Failed to allocate memory %d bytes\n", MAXSZ_BUF); ++ goto err; ++ } ++ ++ /* Read variables */ ++ if (conf_file_exists) { ++ len = dhd_os_get_image_block(memblock, MAXSZ_CONFIG, image); ++ } ++ if (len > 0 && len < MAXSZ_CONFIG) { ++ bufp = (char *)memblock; ++ bufp[len] = 0; ++ ++ while (start_pos < len) { ++ memset(pick, 0, MAXSZ_BUF); ++ end_pos = pick_config_vars(bufp, len, start_pos, pick, MAXSZ_BUF); ++ if (end_pos - start_pos >= MAXSZ_BUF) ++ CONFIG_ERROR("out of buf to read MAXSIZ_BUF=%d\n", MAXSZ_BUF); ++ start_pos = end_pos; ++ pch = strchr(pick, '='); ++ if (pch != NULL) { ++ len_param = pch-pick+1; ++ if (len_param == strlen(pick)) { ++ CONFIG_ERROR("not a right parameter %s\n", pick); ++ continue; ++ } ++ } else { ++ CONFIG_ERROR("not a right parameter %s\n", pick); ++ continue; ++ } ++ ++ dhd_conf_read_chiprev(dhd, &chip_match, pick, len_param); ++ if (!chip_match) ++ continue; ++ ++ if (dhd_conf_read_log_level(dhd, pick, len_param)) ++ continue; ++ else if (dhd_conf_read_roam_params(dhd, pick, len_param)) ++ continue; ++ else if (dhd_conf_read_wme_ac_params(dhd, pick, len_param)) ++ continue; ++#ifdef BCMSDIO ++ else if (dhd_conf_read_fw_by_mac(dhd, pick, len_param)) ++ continue; ++ else if (dhd_conf_read_nv_by_mac(dhd, pick, len_param)) ++ continue; ++#endif ++ else if (dhd_conf_read_nv_by_chip(dhd, pick, len_param)) ++ continue; ++ else if (dhd_conf_read_country(dhd, pick, len_param)) ++ continue; ++ else if (dhd_conf_read_mchan_params(dhd, pick, len_param)) ++ continue; ++#ifdef PKT_FILTER_SUPPORT ++ else if (dhd_conf_read_pkt_filter(dhd, pick, len_param)) ++ continue; ++#endif /* PKT_FILTER_SUPPORT */ ++#ifdef ISAM_PREINIT ++ else if (dhd_conf_read_isam(dhd, pick, len_param)) ++ continue; ++#endif /* ISAM_PREINIT */ ++#ifdef IDHCP ++ else if (dhd_conf_read_dhcp_params(dhd, pick, len_param)) ++ continue; ++#endif /* IDHCP */ ++#ifdef BCMSDIO ++ else if (dhd_conf_read_sdio_params(dhd, pick, len_param)) ++ continue; ++#endif /* BCMSDIO */ ++#ifdef BCMPCIE ++ else if (dhd_conf_read_pcie_params(dhd, pick, len_param)) ++ continue; ++#endif /* BCMPCIE */ ++ else if (dhd_conf_read_pm_params(dhd, pick, len_param)) ++ continue; ++ else if (dhd_conf_read_others(dhd, pick, len_param)) ++ continue; ++ else ++ continue; ++ } ++ ++ bcmerror = 0; ++ } else { ++ CONFIG_ERROR("error reading config file: %d\n", len); ++ bcmerror = BCME_SDIO_ERROR; ++ } ++ ++err: ++ if (pick) ++ MFREE(dhd->osh, pick, MAXSZ_BUF); ++ ++ if (memblock) ++ MFREE(dhd->osh, memblock, MAXSZ_CONFIG); ++ ++ if (image) ++ dhd_os_close_image(image); ++ ++ return bcmerror; ++} ++ ++int ++dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev) ++{ ++ CONFIG_MSG("chip=0x%x, chiprev=%d\n", chip, chiprev); ++ dhd->conf->chip = chip; ++ dhd->conf->chiprev = chiprev; ++ return 0; ++} ++ ++uint ++dhd_conf_get_chip(void *context) ++{ ++ dhd_pub_t *dhd = context; ++ ++ if (dhd && dhd->conf) ++ return dhd->conf->chip; ++ return 0; ++} ++ ++uint ++dhd_conf_get_chiprev(void *context) ++{ ++ dhd_pub_t *dhd = context; ++ ++ if (dhd && dhd->conf) ++ return dhd->conf->chiprev; ++ return 0; ++} ++ ++#ifdef BCMSDIO ++void ++dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ ++ if (enable) { ++#if defined(BCMSDIOH_TXGLOM_EXT) ++ if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID || ++ conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID || ++ conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) { ++ conf->txglom_mode = SDPCM_TXGLOM_CPY; ++ } ++#endif ++ // other parameters set in preinit or config.txt ++ if (conf->txglom_ext) ++ CONFIG_MSG("txglom_ext=%d, txglom_bucket_size=%d\n", ++ conf->txglom_ext, conf->txglom_bucket_size); ++ CONFIG_MSG("txglom_mode=%s\n", ++ conf->txglom_mode==SDPCM_TXGLOM_MDESC?"multi-desc":"copy"); ++ CONFIG_MSG("txglomsize=%d, deferred_tx_len=%d\n", ++ conf->txglomsize, conf->deferred_tx_len); ++ CONFIG_MSG("txinrx_thres=%d, dhd_txminmax=%d\n", ++ conf->txinrx_thres, conf->dhd_txminmax); ++ CONFIG_MSG("tx_max_offset=%d, txctl_tmo_fix=%d\n", ++ conf->tx_max_offset, conf->txctl_tmo_fix); ++ } else { ++ // clear txglom parameters ++ conf->txglom_ext = FALSE; ++ conf->txglom_bucket_size = 0; ++ conf->txglomsize = 0; ++ conf->deferred_tx_len = 0; ++ } ++ ++} ++#endif ++ ++void ++dhd_conf_postinit_ioctls(dhd_pub_t *dhd) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ char wl_preinit[] = "assoc_retry_max=20"; ++ ++ dhd_conf_set_intiovar(dhd, WLC_UP, "WLC_UP", 0, 0, FALSE); ++ dhd_conf_map_country_list(dhd, &conf->cspec); ++ dhd_conf_set_country(dhd, &conf->cspec); ++ dhd_conf_fix_country(dhd); ++ dhd_conf_get_country(dhd, &dhd->dhd_cspec); ++ ++ dhd_conf_set_intiovar(dhd, WLC_SET_BAND, "WLC_SET_BAND", conf->band, 0, FALSE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_PM, "WLC_SET_PM", conf->pm, 0, FALSE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_SRL, "WLC_SET_SRL", conf->srl, 0, FALSE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_LRL, "WLC_SET_LRL", conf->lrl, 0, FALSE); ++ dhd_conf_set_bw_cap(dhd); ++ dhd_conf_set_roam(dhd); ++ ++#if defined(BCMPCIE) ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bus:deepsleep_disable", ++ conf->bus_deepsleep_disable, 0, FALSE); ++#endif /* defined(BCMPCIE) */ ++ ++#ifdef IDHCP ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpc_enable", conf->dhcpc_enable, ++ 0, FALSE); ++ if (conf->dhcpd_enable >= 0) { ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_addr", ++ (char *)&conf->dhcpd_ip_addr, sizeof(conf->dhcpd_ip_addr), FALSE); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_mask", ++ (char *)&conf->dhcpd_ip_mask, sizeof(conf->dhcpd_ip_mask), FALSE); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_start", ++ (char *)&conf->dhcpd_ip_start, sizeof(conf->dhcpd_ip_start), FALSE); ++ dhd_conf_set_bufiovar(dhd, 0, WLC_SET_VAR, "dhcpd_ip_end", ++ (char *)&conf->dhcpd_ip_end, sizeof(conf->dhcpd_ip_end), FALSE); ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpd_enable", ++ conf->dhcpd_enable, 0, FALSE); ++ } ++#endif ++ dhd_conf_set_intiovar(dhd, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG", ++ conf->frameburst, 0, FALSE); ++ ++ dhd_conf_set_wl_cmd(dhd, wl_preinit, TRUE); ++#if defined(BCMSDIO) ++ { ++ char ampdu_mpdu[] = "ampdu_mpdu=16"; ++ dhd_conf_set_wl_cmd(dhd, ampdu_mpdu, TRUE); ++ } ++#endif ++ if (conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || ++ conf->chip == BCM4371_CHIP_ID || conf->chip == BCM4359_CHIP_ID || ++ conf->chip == BCM43569_CHIP_ID) { ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "txbf", 1, 0, FALSE); ++ } ++ dhd_conf_set_wl_cmd(dhd, conf->wl_preinit, TRUE); ++ ++#ifndef WL_CFG80211 ++ dhd_conf_set_intiovar(dhd, WLC_UP, "WLC_UP", 0, 0, FALSE); ++#endif ++ ++} ++ ++int ++dhd_conf_preinit(dhd_pub_t *dhd) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ ++ CONFIG_TRACE("Enter\n"); ++ ++#ifdef BCMSDIO ++ dhd_conf_free_mac_list(&conf->fw_by_mac); ++ dhd_conf_free_mac_list(&conf->nv_by_mac); ++#endif ++ dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip); ++ dhd_conf_free_country_list(conf); ++ dhd_conf_free_mchan_list(conf); ++ if (conf->magic_pkt_filter_add) { ++ kfree(conf->magic_pkt_filter_add); ++ conf->magic_pkt_filter_add = NULL; ++ } ++ if (conf->wl_preinit) { ++ kfree(conf->wl_preinit); ++ conf->wl_preinit = NULL; ++ } ++ if (conf->wl_suspend) { ++ kfree(conf->wl_suspend); ++ conf->wl_suspend = NULL; ++ } ++ if (conf->wl_resume) { ++ kfree(conf->wl_resume); ++ conf->wl_resume = NULL; ++ } ++ conf->band = -1; ++ memset(&conf->bw_cap, -1, sizeof(conf->bw_cap)); ++ if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) { ++ strcpy(conf->cspec.country_abbrev, "ALL"); ++ strcpy(conf->cspec.ccode, "ALL"); ++ conf->cspec.rev = 0; ++ } else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID || ++ conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || ++ conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID || ++ conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID) { ++ strcpy(conf->cspec.country_abbrev, "CN"); ++ strcpy(conf->cspec.ccode, "CN"); ++ conf->cspec.rev = 38; ++ } else { ++ strcpy(conf->cspec.country_abbrev, "CN"); ++ strcpy(conf->cspec.ccode, "CN"); ++ conf->cspec.rev = 0; ++ } ++ memset(&conf->channels, 0, sizeof(wl_channel_list_t)); ++ conf->roam_off = 1; ++ conf->roam_off_suspend = 1; ++ conf->roam_trigger[0] = -65; ++ conf->roam_trigger[1] = WLC_BAND_ALL; ++ conf->roam_scan_period[0] = 10; ++ conf->roam_scan_period[1] = WLC_BAND_ALL; ++ conf->roam_delta[0] = 10; ++ conf->roam_delta[1] = WLC_BAND_ALL; ++ conf->fullroamperiod = 20; ++ conf->keep_alive_period = 30000; ++#ifdef ARP_OFFLOAD_SUPPORT ++ conf->garp = FALSE; ++#endif ++ conf->force_wme_ac = 0; ++ memset(&conf->wme_sta, 0, sizeof(wme_param_t)); ++ memset(&conf->wme_ap, 0, sizeof(wme_param_t)); ++#ifdef PKT_FILTER_SUPPORT ++ memset(&conf->pkt_filter_add, 0, sizeof(conf_pkt_filter_add_t)); ++ memset(&conf->pkt_filter_del, 0, sizeof(conf_pkt_filter_del_t)); ++#endif ++ conf->srl = -1; ++ conf->lrl = -1; ++ conf->bcn_timeout = 16; ++ conf->disable_proptx = -1; ++ conf->dhd_poll = -1; ++#ifdef BCMSDIO ++ conf->use_rxchain = 0; ++ conf->bus_rxglom = TRUE; ++ conf->txglom_ext = FALSE; ++ conf->tx_max_offset = 0; ++ conf->txglomsize = SDPCM_DEFGLOM_SIZE; ++ conf->txctl_tmo_fix = 300; ++ conf->txglom_mode = SDPCM_TXGLOM_MDESC; ++ conf->deferred_tx_len = 0; ++ conf->dhd_txminmax = 1; ++ conf->txinrx_thres = -1; ++#if defined(SDIO_ISR_THREAD) ++ conf->intr_extn = FALSE; ++#endif ++#ifdef BCMSDIO_RXLIM_POST ++ conf->rxlim_en = TRUE; ++#endif ++#if defined(HW_OOB) ++ conf->oob_enabled_later = FALSE; ++#endif ++#endif ++#ifdef BCMPCIE ++ conf->bus_deepsleep_disable = 1; ++#endif ++ conf->dpc_cpucore = -1; ++ conf->rxf_cpucore = -1; ++ conf->frameburst = -1; ++ conf->deepsleep = FALSE; ++ conf->pm = -1; ++ conf->pm_in_suspend = -1; ++ conf->insuspend = 0; ++ conf->suspend_mode = EARLY_SUSPEND; ++ conf->suspend_bcn_li_dtim = -1; ++#ifdef WL_EXT_WOWL ++ dhd_master_mode = TRUE; ++ conf->wowl = WL_WOWL_NET|WL_WOWL_DIS|WL_WOWL_BCN; ++ conf->insuspend |= (WOWL_IN_SUSPEND | NO_TXDATA_IN_SUSPEND); ++#endif ++ if (conf->suspend_mode == PM_NOTIFIER) ++ conf->insuspend |= (NO_TXDATA_IN_SUSPEND | NO_TXCTL_IN_SUSPEND); ++ conf->suspended = FALSE; ++#ifdef SUSPEND_EVENT ++ memset(&conf->resume_eventmask, 0, sizeof(conf->resume_eventmask)); ++ memset(&conf->bssid_insuspend, 0, ETHER_ADDR_LEN); ++ conf->wlfc = FALSE; ++#endif ++#ifdef GET_CUSTOM_MAC_FROM_CONFIG ++ memset(&conf->hw_ether, 0, sizeof(conf->hw_ether)); ++#endif ++#ifdef IDHCP ++ conf->dhcpc_enable = -1; ++ conf->dhcpd_enable = -1; ++#endif ++ conf->orphan_move = 0; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) ++ conf->tsq = 10; ++#else ++ conf->tsq = 0; ++#endif ++#ifdef DHDTCPACK_SUPPRESS ++#ifdef BCMPCIE ++ conf->tcpack_sup_mode = TCPACK_SUP_DEFAULT; ++#else ++ conf->tcpack_sup_mode = TCPACK_SUP_OFF; ++#endif ++#endif ++ conf->pktprio8021x = -1; ++ conf->ctrl_resched = 2; ++ conf->in4way = NO_SCAN_IN4WAY | DONT_DELETE_GC_AFTER_WPS | WAIT_DISCONNECTED; ++#ifdef ISAM_PREINIT ++ memset(conf->isam_init, 0, sizeof(conf->isam_init)); ++ memset(conf->isam_config, 0, sizeof(conf->isam_config)); ++ memset(conf->isam_enable, 0, sizeof(conf->isam_enable)); ++#endif ++#if defined(SDIO_ISR_THREAD) ++ if (conf->chip == BCM43012_CHIP_ID || ++ conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID || ++ conf->chip == BCM43454_CHIP_ID || conf->chip == BCM4345_CHIP_ID || ++ conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || ++ conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID || ++ conf->chip == BCM4359_CHIP_ID) { ++ conf->intr_extn = TRUE; ++ } ++#endif ++ if ((conf->chip == BCM43430_CHIP_ID && conf->chiprev == 2) || ++ conf->chip == BCM43012_CHIP_ID || ++ conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID || ++ conf->chip == BCM43454_CHIP_ID || conf->chip == BCM4345_CHIP_ID || ++ conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || ++ conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID || ++ conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID) { ++#ifdef DHDTCPACK_SUPPRESS ++#ifdef BCMSDIO ++ conf->tcpack_sup_mode = TCPACK_SUP_REPLACE; ++#endif ++#endif ++#if defined(BCMSDIO) || defined(BCMPCIE) ++ dhd_rxbound = 128; ++ dhd_txbound = 64; ++#endif ++ conf->frameburst = 1; ++#ifdef BCMSDIO ++ conf->dhd_txminmax = -1; ++ conf->txinrx_thres = 128; ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) ++ conf->orphan_move = 1; ++#else ++ conf->orphan_move = 0; ++#endif ++ } ++ ++#ifdef BCMSDIO ++#if defined(BCMSDIOH_TXGLOM_EXT) ++ if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID || ++ conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID || ++ conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) { ++ conf->txglom_ext = TRUE; ++ } else { ++ conf->txglom_ext = FALSE; ++ } ++ if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) { ++ conf->txglom_bucket_size = 1680; // fixed value, don't change ++ conf->txglomsize = 6; ++ } ++ if (conf->chip == BCM4334_CHIP_ID || conf->chip == BCM43340_CHIP_ID || ++ conf->chip == BCM43341_CHIP_ID || conf->chip == BCM4324_CHIP_ID) { ++ conf->txglom_bucket_size = 1684; // fixed value, don't change ++ conf->txglomsize = 16; ++ } ++#endif ++ if (conf->txglomsize > SDPCM_MAXGLOM_SIZE) ++ conf->txglomsize = SDPCM_MAXGLOM_SIZE; ++#endif ++ init_waitqueue_head(&conf->event_complete); ++ ++ return 0; ++} ++ ++int ++dhd_conf_reset(dhd_pub_t *dhd) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ ++#ifdef BCMSDIO ++ dhd_conf_free_mac_list(&conf->fw_by_mac); ++ dhd_conf_free_mac_list(&conf->nv_by_mac); ++#endif ++ dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip); ++ dhd_conf_free_country_list(conf); ++ dhd_conf_free_mchan_list(conf); ++ if (conf->magic_pkt_filter_add) { ++ kfree(conf->magic_pkt_filter_add); ++ conf->magic_pkt_filter_add = NULL; ++ } ++ if (conf->wl_preinit) { ++ kfree(conf->wl_preinit); ++ conf->wl_preinit = NULL; ++ } ++ if (conf->wl_suspend) { ++ kfree(conf->wl_suspend); ++ conf->wl_suspend = NULL; ++ } ++ if (conf->wl_resume) { ++ kfree(conf->wl_resume); ++ conf->wl_resume = NULL; ++ } ++ memset(conf, 0, sizeof(dhd_conf_t)); ++ return 0; ++} ++ ++int ++dhd_conf_attach(dhd_pub_t *dhd) ++{ ++ dhd_conf_t *conf; ++ ++ CONFIG_TRACE("Enter\n"); ++ ++ if (dhd->conf != NULL) { ++ CONFIG_MSG("config is attached before!\n"); ++ return 0; ++ } ++ /* Allocate private bus interface state */ ++ if (!(conf = MALLOC(dhd->osh, sizeof(dhd_conf_t)))) { ++ CONFIG_ERROR("MALLOC failed\n"); ++ goto fail; ++ } ++ memset(conf, 0, sizeof(dhd_conf_t)); ++ ++ dhd->conf = conf; ++ ++ return 0; ++ ++fail: ++ if (conf != NULL) ++ MFREE(dhd->osh, conf, sizeof(dhd_conf_t)); ++ return BCME_NOMEM; ++} ++ ++void ++dhd_conf_detach(dhd_pub_t *dhd) ++{ ++ struct dhd_conf *conf = dhd->conf; ++ ++ CONFIG_TRACE("Enter\n"); ++ if (dhd->conf) { ++#ifdef BCMSDIO ++ dhd_conf_free_mac_list(&conf->fw_by_mac); ++ dhd_conf_free_mac_list(&conf->nv_by_mac); ++#endif ++ dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip); ++ dhd_conf_free_country_list(conf); ++ dhd_conf_free_mchan_list(conf); ++ if (conf->magic_pkt_filter_add) { ++ kfree(conf->magic_pkt_filter_add); ++ conf->magic_pkt_filter_add = NULL; ++ } ++ if (conf->wl_preinit) { ++ kfree(conf->wl_preinit); ++ conf->wl_preinit = NULL; ++ } ++ if (conf->wl_suspend) { ++ kfree(conf->wl_suspend); ++ conf->wl_suspend = NULL; ++ } ++ if (conf->wl_resume) { ++ kfree(conf->wl_resume); ++ conf->wl_resume = NULL; ++ } ++ MFREE(dhd->osh, conf, sizeof(dhd_conf_t)); ++ } ++ dhd->conf = NULL; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_config.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_config.h +new file mode 100644 +index 000000000..045745369 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_config.h +@@ -0,0 +1,329 @@ ++ ++#ifndef _dhd_config_ ++#define _dhd_config_ ++ ++#include ++#include ++#include ++#include ++#include <802.11.h> ++ ++#define FW_TYPE_STA 0 ++#define FW_TYPE_APSTA 1 ++#define FW_TYPE_P2P 2 ++#define FW_TYPE_MESH 3 ++#define FW_TYPE_ES 4 ++#define FW_TYPE_MFG 5 ++#define FW_TYPE_G 0 ++#define FW_TYPE_AG 1 ++ ++#define FW_PATH_AUTO_SELECT 1 ++//#define CONFIG_PATH_AUTO_SELECT ++extern char firmware_path[MOD_PARAM_PATHLEN]; ++#if defined(BCMSDIO) || defined(BCMPCIE) ++extern uint dhd_rxbound; ++extern uint dhd_txbound; ++#endif ++#ifdef BCMSDIO ++#define TXGLOM_RECV_OFFSET 8 ++extern uint dhd_doflow; ++extern uint dhd_slpauto; ++#endif ++ ++typedef struct wl_mac_range { ++ uint32 oui; ++ uint32 nic_start; ++ uint32 nic_end; ++} wl_mac_range_t; ++ ++typedef struct wl_mac_list { ++ int count; ++ wl_mac_range_t *mac; ++ char name[MOD_PARAM_PATHLEN]; ++} wl_mac_list_t; ++ ++typedef struct wl_mac_list_ctrl { ++ int count; ++ struct wl_mac_list *m_mac_list_head; ++} wl_mac_list_ctrl_t; ++ ++typedef struct wl_chip_nv_path { ++ uint chip; ++ uint chiprev; ++ char name[MOD_PARAM_PATHLEN]; ++} wl_chip_nv_path_t; ++ ++typedef struct wl_chip_nv_path_list_ctrl { ++ int count; ++ struct wl_chip_nv_path *m_chip_nv_path_head; ++} wl_chip_nv_path_list_ctrl_t; ++ ++typedef struct wl_channel_list { ++ uint32 count; ++ uint32 channel[WL_NUMCHANNELS]; ++} wl_channel_list_t; ++ ++typedef struct wmes_param { ++ int aifsn[AC_COUNT]; ++ int ecwmin[AC_COUNT]; ++ int ecwmax[AC_COUNT]; ++ int txop[AC_COUNT]; ++} wme_param_t; ++ ++#ifdef PKT_FILTER_SUPPORT ++#define DHD_CONF_FILTER_MAX 8 ++#define PKT_FILTER_LEN 300 ++#define MAGIC_PKT_FILTER_LEN 450 ++typedef struct conf_pkt_filter_add { ++ uint32 count; ++ char filter[DHD_CONF_FILTER_MAX][PKT_FILTER_LEN]; ++} conf_pkt_filter_add_t; ++ ++typedef struct conf_pkt_filter_del { ++ uint32 count; ++ uint32 id[DHD_CONF_FILTER_MAX]; ++} conf_pkt_filter_del_t; ++#endif ++ ++#define CONFIG_COUNTRY_LIST_SIZE 500 ++typedef struct country_list { ++ struct country_list *next; ++ wl_country_t cspec; ++} country_list_t; ++ ++/* mchan_params */ ++#define MCHAN_MAX_NUM 4 ++#define MIRACAST_SOURCE 1 ++#define MIRACAST_SINK 2 ++typedef struct mchan_params { ++ struct mchan_params *next; ++ int bw; ++ int p2p_mode; ++ int miracast_mode; ++} mchan_params_t; ++ ++enum in4way_flags { ++ NO_SCAN_IN4WAY = (1 << (0)), ++ NO_BTC_IN4WAY = (1 << (1)), ++ DONT_DELETE_GC_AFTER_WPS = (1 << (2)), ++ WAIT_DISCONNECTED = (1 << (3)), ++}; ++ ++enum in_suspend_flags { ++ NO_EVENT_IN_SUSPEND = (1 << (0)), ++ NO_TXDATA_IN_SUSPEND = (1 << (1)), ++ NO_TXCTL_IN_SUSPEND = (1 << (2)), ++ AP_DOWN_IN_SUSPEND = (1 << (3)), ++ ROAM_OFFLOAD_IN_SUSPEND = (1 << (4)), ++ AP_FILTER_IN_SUSPEND = (1 << (5)), ++ WOWL_IN_SUSPEND = (1 << (6)), ++ ALL_IN_SUSPEND = 0xFFFFFFFF, ++}; ++ ++enum in_suspend_mode { ++ EARLY_SUSPEND = 0, ++ PM_NOTIFIER = 1 ++}; ++ ++enum eapol_status { ++ EAPOL_STATUS_NONE = 0, ++ EAPOL_STATUS_REQID = 1, ++ EAPOL_STATUS_RSPID = 2, ++ EAPOL_STATUS_WSC_START = 3, ++ EAPOL_STATUS_WPS_M1 = 4, ++ EAPOL_STATUS_WPS_M2 = 5, ++ EAPOL_STATUS_WPS_M3 = 6, ++ EAPOL_STATUS_WPS_M4 = 7, ++ EAPOL_STATUS_WPS_M5 = 8, ++ EAPOL_STATUS_WPS_M6 = 9, ++ EAPOL_STATUS_WPS_M7 = 10, ++ EAPOL_STATUS_WPS_M8 = 11, ++ EAPOL_STATUS_WSC_DONE = 12, ++ EAPOL_STATUS_4WAY_START = 13, ++ EAPOL_STATUS_4WAY_M1 = 14, ++ EAPOL_STATUS_4WAY_M2 = 15, ++ EAPOL_STATUS_4WAY_M3 = 16, ++ EAPOL_STATUS_4WAY_M4 = 17, ++ EAPOL_STATUS_GROUPKEY_M1 = 18, ++ EAPOL_STATUS_GROUPKEY_M2 = 19, ++ EAPOL_STATUS_4WAY_DONE = 20 ++}; ++ ++typedef struct dhd_conf { ++ uint chip; ++ uint chiprev; ++#ifdef GET_OTP_MODULE_NAME ++ char module_name[16]; ++#endif ++ struct ether_addr otp_mac; ++ int fw_type; ++#ifdef BCMSDIO ++ wl_mac_list_ctrl_t fw_by_mac; ++ wl_mac_list_ctrl_t nv_by_mac; ++#endif ++ wl_chip_nv_path_list_ctrl_t nv_by_chip; ++ country_list_t *country_head; ++ int band; ++ int bw_cap[2]; ++ wl_country_t cspec; ++ wl_channel_list_t channels; ++ uint roam_off; ++ uint roam_off_suspend; ++ int roam_trigger[2]; ++ int roam_scan_period[2]; ++ int roam_delta[2]; ++ int fullroamperiod; ++ uint keep_alive_period; ++#ifdef ARP_OFFLOAD_SUPPORT ++ bool garp; ++#endif ++ int force_wme_ac; ++ wme_param_t wme_sta; ++ wme_param_t wme_ap; ++#ifdef PKT_FILTER_SUPPORT ++ conf_pkt_filter_add_t pkt_filter_add; ++ conf_pkt_filter_del_t pkt_filter_del; ++ char *magic_pkt_filter_add; ++#endif ++ int srl; ++ int lrl; ++ uint bcn_timeout; ++ int disable_proptx; ++ int dhd_poll; ++#ifdef BCMSDIO ++ int use_rxchain; ++ bool bus_rxglom; ++ bool txglom_ext; /* Only for 43362/4330/43340/43341/43241 */ ++ /* terence 20161011: ++ 1) conf->tx_max_offset = 1 to fix credict issue in adaptivity testing ++ 2) conf->tx_max_offset = 1 will cause to UDP Tx not work in rxglom supported, ++ but not happened in sw txglom ++ */ ++ int tx_max_offset; ++ uint txglomsize; ++ int txctl_tmo_fix; ++ bool txglom_mode; ++ uint deferred_tx_len; ++ /*txglom_bucket_size: ++ * 43362/4330: 1680 ++ * 43340/43341/43241: 1684 ++ */ ++ int txglom_bucket_size; ++ int txinrx_thres; ++ int dhd_txminmax; // -1=DATABUFCNT(bus) ++ bool oob_enabled_later; ++#if defined(SDIO_ISR_THREAD) ++ bool intr_extn; ++#endif ++#ifdef BCMSDIO_RXLIM_POST ++ bool rxlim_en; ++#endif ++#endif ++#ifdef BCMPCIE ++ int bus_deepsleep_disable; ++#endif ++ int dpc_cpucore; ++ int rxf_cpucore; ++ int frameburst; ++ bool deepsleep; ++ int pm; ++ int pm_in_suspend; ++ int suspend_mode; ++ int suspend_bcn_li_dtim; ++#ifdef DHDTCPACK_SUPPRESS ++ uint8 tcpack_sup_mode; ++#endif ++ int pktprio8021x; ++ uint insuspend; ++ bool suspended; ++#ifdef SUSPEND_EVENT ++ char resume_eventmask[WL_EVENTING_MASK_LEN]; ++ struct ether_addr bssid_insuspend; ++ bool wlfc; ++#endif ++#ifdef IDHCP ++ int dhcpc_enable; ++ int dhcpd_enable; ++ struct ipv4_addr dhcpd_ip_addr; ++ struct ipv4_addr dhcpd_ip_mask; ++ struct ipv4_addr dhcpd_ip_start; ++ struct ipv4_addr dhcpd_ip_end; ++#endif ++#ifdef ISAM_PREINIT ++ char isam_init[50]; ++ char isam_config[300]; ++ char isam_enable[50]; ++#endif ++ int ctrl_resched; ++ mchan_params_t *mchan; ++ char *wl_preinit; ++ char *wl_suspend; ++ char *wl_resume; ++ int tsq; ++ int orphan_move; ++ uint eapol_status; ++ uint in4way; ++#ifdef WL_EXT_WOWL ++ uint wowl; ++#endif ++#ifdef GET_CUSTOM_MAC_FROM_CONFIG ++ char hw_ether[62]; ++#endif ++ wait_queue_head_t event_complete; ++} dhd_conf_t; ++ ++#ifdef BCMSDIO ++void dhd_conf_get_otp(dhd_pub_t *dhd, bcmsdh_info_t *sdh); ++#if defined(HW_OOB) || defined(FORCE_WOWLAN) ++void dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip); ++#endif ++void dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable); ++int dhd_conf_set_blksize(bcmsdh_info_t *sdh); ++#endif ++void dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path); ++int dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val, ++ int def, bool down); ++int dhd_conf_get_band(dhd_pub_t *dhd); ++int dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec); ++int dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec); ++int dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec); ++#ifdef CCODE_LIST ++int dhd_ccode_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec); ++#endif ++int dhd_conf_fix_country(dhd_pub_t *dhd); ++bool dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel); ++void dhd_conf_set_wme(dhd_pub_t *dhd, int ifidx, int mode); ++void dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int go, int source); ++void dhd_conf_add_pkt_filter(dhd_pub_t *dhd); ++bool dhd_conf_del_pkt_filter(dhd_pub_t *dhd, uint32 id); ++void dhd_conf_discard_pkt_filter(dhd_pub_t *dhd); ++int dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path); ++int dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev); ++uint dhd_conf_get_chip(void *context); ++uint dhd_conf_get_chiprev(void *context); ++int dhd_conf_get_pm(dhd_pub_t *dhd); ++int dhd_conf_check_hostsleep(dhd_pub_t *dhd, int cmd, void *buf, int len, ++ int *hostsleep_set, int *hostsleep_val, int *ret); ++void dhd_conf_get_hostsleep(dhd_pub_t *dhd, ++ int hostsleep_set, int hostsleep_val, int ret); ++int dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period, ++ char *packet, bool bcast); ++#ifdef ARP_OFFLOAD_SUPPORT ++void dhd_conf_set_garp(dhd_pub_t *dhd, int ifidx, uint32 ipa, bool enable); ++#endif ++#ifdef PROP_TXSTATUS ++int dhd_conf_get_disable_proptx(dhd_pub_t *dhd); ++#endif ++uint dhd_conf_get_insuspend(dhd_pub_t *dhd, uint mask); ++int dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend); ++void dhd_conf_postinit_ioctls(dhd_pub_t *dhd); ++int dhd_conf_preinit(dhd_pub_t *dhd); ++int dhd_conf_reset(dhd_pub_t *dhd); ++int dhd_conf_attach(dhd_pub_t *dhd); ++void dhd_conf_detach(dhd_pub_t *dhd); ++void *dhd_get_pub(struct net_device *dev); ++int wl_pattern_atoh(char *src, char *dst); ++#ifdef BCMSDIO ++extern int dhd_bus_sleep(dhd_pub_t *dhdp, bool sleep, uint32 *intstatus); ++#endif ++#endif /* _dhd_config_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c +new file mode 100644 +index 000000000..0aa51ca97 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c +@@ -0,0 +1,299 @@ ++/* ++ * Customer code to add GPIO control during WLAN start/stop ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_custom_gpio.c 664997 2016-10-14 11:56:35Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define WL_ERROR(x) printf x ++#define WL_TRACE(x) ++ ++#if defined(OOB_INTR_ONLY) ++ ++#if defined(BCMLXSDMMC) ++extern int sdioh_mmc_irq(int irq); ++#endif /* (BCMLXSDMMC) */ ++ ++/* Customer specific Host GPIO defintion */ ++static int dhd_oob_gpio_num = -1; ++ ++module_param(dhd_oob_gpio_num, int, 0644); ++MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); ++ ++/* This function will return: ++ * 1) return : Host gpio interrupt number per customer platform ++ * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge ++ * ++ * NOTE : ++ * Customer should check his platform definitions ++ * and his Host Interrupt spec ++ * to figure out the proper setting for his platform. ++ * Broadcom provides just reference settings as example. ++ * ++ */ ++int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr) ++{ ++ int host_oob_irq = 0; ++ ++#if defined(CUSTOMER_HW2) ++ host_oob_irq = wifi_platform_get_irq_number(adapter, irq_flags_ptr); ++ ++#else ++#if defined(CUSTOM_OOB_GPIO_NUM) ++ if (dhd_oob_gpio_num < 0) { ++ dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; ++ } ++#endif /* CUSTOMER_OOB_GPIO_NUM */ ++ ++ if (dhd_oob_gpio_num < 0) { ++ WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", ++ __FUNCTION__)); ++ return (dhd_oob_gpio_num); ++ } ++ ++ WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", ++ __FUNCTION__, dhd_oob_gpio_num)); ++ ++#endif ++ ++ return (host_oob_irq); ++} ++#endif ++ ++/* Customer function to control hw specific wlan gpios */ ++int ++dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff) ++{ ++ int err = 0; ++ ++ return err; ++} ++ ++#ifdef GET_CUSTOM_MAC_ENABLE ++/* Function to get custom MAC address */ ++int ++dhd_custom_get_mac_address(void *adapter, unsigned char *buf) ++{ ++ int ret = 0; ++ ++ WL_TRACE(("%s Enter\n", __FUNCTION__)); ++ if (!buf) ++ return -EINVAL; ++ ++ /* Customer access to MAC address stored outside of DHD driver */ ++#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) ++ ret = wifi_platform_get_mac_addr(adapter, buf); ++#endif ++ ++#ifdef EXAMPLE_GET_MAC ++ /* EXAMPLE code */ ++ { ++ struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; ++ bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); ++ } ++#endif /* EXAMPLE_GET_MAC */ ++ ++ return ret; ++} ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++/* Customized Locale table : OPTIONAL feature */ ++const struct cntry_locales_custom translate_custom_table[] = { ++/* Table should be filled out based on custom platform regulatory requirement */ ++#ifdef EXAMPLE_TABLE ++ {"", "XY", 4}, /* Universal if Country code is unknown or empty */ ++ {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ ++ {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ ++ {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */ ++ {"AT", "EU", 5}, ++ {"BE", "EU", 5}, ++ {"BG", "EU", 5}, ++ {"CY", "EU", 5}, ++ {"CZ", "EU", 5}, ++ {"DK", "EU", 5}, ++ {"EE", "EU", 5}, ++ {"FI", "EU", 5}, ++ {"FR", "EU", 5}, ++ {"DE", "EU", 5}, ++ {"GR", "EU", 5}, ++ {"HU", "EU", 5}, ++ {"IE", "EU", 5}, ++ {"IT", "EU", 5}, ++ {"LV", "EU", 5}, ++ {"LI", "EU", 5}, ++ {"LT", "EU", 5}, ++ {"LU", "EU", 5}, ++ {"MT", "EU", 5}, ++ {"NL", "EU", 5}, ++ {"PL", "EU", 5}, ++ {"PT", "EU", 5}, ++ {"RO", "EU", 5}, ++ {"SK", "EU", 5}, ++ {"SI", "EU", 5}, ++ {"ES", "EU", 5}, ++ {"SE", "EU", 5}, ++ {"GB", "EU", 5}, ++ {"KR", "XY", 3}, ++ {"AU", "XY", 3}, ++ {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ ++ {"TW", "XY", 3}, ++ {"AR", "XY", 3}, ++ {"MX", "XY", 3}, ++ {"IL", "IL", 0}, ++ {"CH", "CH", 0}, ++ {"TR", "TR", 0}, ++ {"NO", "NO", 0}, ++#endif /* EXMAPLE_TABLE */ ++#if defined(CUSTOMER_HW2) ++#if defined(BCM4335_CHIP) ++ {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ ++#endif ++ {"AE", "AE", 1}, ++ {"AR", "AR", 1}, ++ {"AT", "AT", 1}, ++ {"AU", "AU", 2}, ++ {"BE", "BE", 1}, ++ {"BG", "BG", 1}, ++ {"BN", "BN", 1}, ++ {"CA", "CA", 2}, ++ {"CH", "CH", 1}, ++ {"CY", "CY", 1}, ++ {"CZ", "CZ", 1}, ++ {"DE", "DE", 3}, ++ {"DK", "DK", 1}, ++ {"EE", "EE", 1}, ++ {"ES", "ES", 1}, ++ {"FI", "FI", 1}, ++ {"FR", "FR", 1}, ++ {"GB", "GB", 1}, ++ {"GR", "GR", 1}, ++ {"HR", "HR", 1}, ++ {"HU", "HU", 1}, ++ {"IE", "IE", 1}, ++ {"IS", "IS", 1}, ++ {"IT", "IT", 1}, ++ {"ID", "ID", 1}, ++ {"JP", "JP", 8}, ++ {"KR", "KR", 24}, ++ {"KW", "KW", 1}, ++ {"LI", "LI", 1}, ++ {"LT", "LT", 1}, ++ {"LU", "LU", 1}, ++ {"LV", "LV", 1}, ++ {"MA", "MA", 1}, ++ {"MT", "MT", 1}, ++ {"MX", "MX", 1}, ++ {"NL", "NL", 1}, ++ {"NO", "NO", 1}, ++ {"PL", "PL", 1}, ++ {"PT", "PT", 1}, ++ {"PY", "PY", 1}, ++ {"RO", "RO", 1}, ++ {"SE", "SE", 1}, ++ {"SI", "SI", 1}, ++ {"SK", "SK", 1}, ++ {"TR", "TR", 7}, ++ {"TW", "TW", 1}, ++ {"IR", "XZ", 11}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ ++ {"SD", "XZ", 11}, /* Universal if Country code is SUDAN */ ++ {"SY", "XZ", 11}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ ++ {"GL", "XZ", 11}, /* Universal if Country code is GREENLAND */ ++ {"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ ++ {"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ ++ {"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */ ++#ifdef BCM4330_CHIP ++ {"RU", "RU", 1}, ++ {"US", "US", 5} ++#endif ++#endif ++}; ++ ++ ++/* Customized Locale convertor ++* input : ISO 3166-1 country abbreviation ++* output: customized cspec ++*/ ++void ++#ifdef CUSTOM_COUNTRY_CODE ++get_customized_country_code(void *adapter, char *country_iso_code, ++ wl_country_t *cspec, u32 flags) ++#else ++get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec) ++#endif /* CUSTOM_COUNTRY_CODE */ ++{ ++#if (defined(CUSTOMER_HW) || defined(CUSTOMER_HW2)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ ++ struct cntry_locales_custom *cloc_ptr; ++ ++ if (!cspec) ++ return; ++#ifdef CUSTOM_COUNTRY_CODE ++ cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code, flags); ++#else ++ cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code); ++#endif /* CUSTOM_COUNTRY_CODE */ ++ ++ if (cloc_ptr) { ++ strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); ++ cspec->rev = cloc_ptr->custom_locale_rev; ++ } ++ return; ++#else ++ int size, i; ++ ++ size = ARRAYSIZE(translate_custom_table); ++ ++ if (cspec == 0) ++ return; ++ ++ if (size == 0) ++ return; ++ ++ for (i = 0; i < size; i++) { ++ if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { ++ memcpy(cspec->ccode, ++ translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); ++ cspec->rev = translate_custom_table[i].custom_locale_rev; ++ return; ++ } ++ } ++#ifdef EXAMPLE_TABLE ++ /* if no country code matched return first universal code from translate_custom_table */ ++ memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); ++ cspec->rev = translate_custom_table[0].custom_locale_rev; ++#endif /* EXMAPLE_TABLE */ ++ return; ++#endif /* defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) */ ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_memprealloc.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_memprealloc.c +new file mode 100644 +index 000000000..1f593a488 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_memprealloc.c +@@ -0,0 +1,513 @@ ++/* ++ * Platform Dependent file for usage of Preallocted Memory ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * <> ++ * ++ * $Id: dhd_custom_memprealloc.c 707595 2017-06-28 08:28:30Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM ++ ++#define WLAN_STATIC_SCAN_BUF0 5 ++#define WLAN_STATIC_SCAN_BUF1 6 ++#define WLAN_STATIC_DHD_INFO_BUF 7 ++#define WLAN_STATIC_DHD_WLFC_BUF 8 ++#define WLAN_STATIC_DHD_IF_FLOW_LKUP 9 ++#define WLAN_STATIC_DHD_MEMDUMP_RAM 11 ++#define WLAN_STATIC_DHD_WLFC_HANGER 12 ++#define WLAN_STATIC_DHD_PKTID_MAP 13 ++#define WLAN_STATIC_DHD_PKTID_IOCTL_MAP 14 ++#define WLAN_STATIC_DHD_LOG_DUMP_BUF 15 ++#define WLAN_STATIC_DHD_LOG_DUMP_BUF_EX 16 ++#define WLAN_STATIC_DHD_PKTLOG_DUMP_BUF 17 ++#define WLAN_STATIC_STAT_REPORT_BUF 18 ++ ++#define WLAN_SCAN_BUF_SIZE (64 * 1024) ++ ++#if defined(CONFIG_64BIT) ++#define WLAN_DHD_INFO_BUF_SIZE (32 * 1024) ++#define WLAN_DHD_WLFC_BUF_SIZE (64 * 1024) ++#define WLAN_DHD_IF_FLOW_LKUP_SIZE (64 * 1024) ++#else ++#define WLAN_DHD_INFO_BUF_SIZE (32 * 1024) ++#define WLAN_DHD_WLFC_BUF_SIZE (16 * 1024) ++#define WLAN_DHD_IF_FLOW_LKUP_SIZE (20 * 1024) ++#endif /* CONFIG_64BIT */ ++#define WLAN_DHD_MEMDUMP_SIZE (1536 * 1024) ++ ++#define PREALLOC_WLAN_SEC_NUM 4 ++#define PREALLOC_WLAN_BUF_NUM 160 ++#define PREALLOC_WLAN_SECTION_HEADER 24 ++ ++#ifdef CONFIG_BCMDHD_PCIE ++#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE*1) ++#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE*2) ++#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE*4) ++ ++#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128) ++#define WLAN_SECTION_SIZE_1 0 ++#define WLAN_SECTION_SIZE_2 0 ++#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024) ++ ++#define DHD_SKB_1PAGE_BUF_NUM 0 ++#define DHD_SKB_2PAGE_BUF_NUM 128 ++#define DHD_SKB_4PAGE_BUF_NUM 0 ++ ++#else ++#define DHD_SKB_HDRSIZE 336 ++#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) ++#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) ++#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) ++ ++#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128) ++#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128) ++#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512) ++#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024) ++ ++#define DHD_SKB_1PAGE_BUF_NUM 8 ++#define DHD_SKB_2PAGE_BUF_NUM 8 ++#define DHD_SKB_4PAGE_BUF_NUM 1 ++#endif /* CONFIG_BCMDHD_PCIE */ ++ ++#define WLAN_SKB_1_2PAGE_BUF_NUM ((DHD_SKB_1PAGE_BUF_NUM) + \ ++ (DHD_SKB_2PAGE_BUF_NUM)) ++#define WLAN_SKB_BUF_NUM ((WLAN_SKB_1_2PAGE_BUF_NUM) + \ ++ (DHD_SKB_4PAGE_BUF_NUM)) ++ ++#define WLAN_MAX_PKTID_ITEMS (8192) ++#define WLAN_DHD_PKTID_MAP_HDR_SIZE (20 + 4*(WLAN_MAX_PKTID_ITEMS + 1)) ++#define WLAN_DHD_PKTID_MAP_ITEM_SIZE (32) ++#define WLAN_DHD_PKTID_MAP_SIZE ((WLAN_DHD_PKTID_MAP_HDR_SIZE) + \ ++ ((WLAN_MAX_PKTID_ITEMS+1) * WLAN_DHD_PKTID_MAP_ITEM_SIZE)) ++ ++#define WLAN_MAX_PKTID_IOCTL_ITEMS (32) ++#define WLAN_DHD_PKTID_IOCTL_MAP_HDR_SIZE (20 + 4*(WLAN_MAX_PKTID_IOCTL_ITEMS + 1)) ++#define WLAN_DHD_PKTID_IOCTL_MAP_ITEM_SIZE (32) ++#define WLAN_DHD_PKTID_IOCTL_MAP_SIZE ((WLAN_DHD_PKTID_IOCTL_MAP_HDR_SIZE) + \ ++ ((WLAN_MAX_PKTID_IOCTL_ITEMS+1) * WLAN_DHD_PKTID_IOCTL_MAP_ITEM_SIZE)) ++ ++#define DHD_LOG_DUMP_BUF_SIZE (1024 * 1024) ++#define DHD_LOG_DUMP_BUF_EX_SIZE (8 * 1024) ++ ++#define DHD_PKTLOG_DUMP_BUF_SIZE (64 * 1024) ++ ++#define DHD_STAT_REPORT_BUF_SIZE (128 * 1024) ++ ++#define WLAN_DHD_WLFC_HANGER_MAXITEMS 3072 ++#define WLAN_DHD_WLFC_HANGER_ITEM_SIZE 32 ++#define WLAN_DHD_WLFC_HANGER_SIZE ((WLAN_DHD_WLFC_HANGER_ITEM_SIZE) + \ ++ ((WLAN_DHD_WLFC_HANGER_MAXITEMS) * (WLAN_DHD_WLFC_HANGER_ITEM_SIZE))) ++ ++static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM]; ++ ++struct wlan_mem_prealloc { ++ void *mem_ptr; ++ unsigned long size; ++}; ++ ++static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = { ++ {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)}, ++ {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)}, ++ {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)}, ++ {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)} ++}; ++ ++static void *wlan_static_scan_buf0 = NULL; ++static void *wlan_static_scan_buf1 = NULL; ++static void *wlan_static_dhd_info_buf = NULL; ++static void *wlan_static_dhd_wlfc_buf = NULL; ++static void *wlan_static_if_flow_lkup = NULL; ++static void *wlan_static_dhd_memdump_ram = NULL; ++static void *wlan_static_dhd_wlfc_hanger = NULL; ++static void *wlan_static_dhd_pktid_map = NULL; ++static void *wlan_static_dhd_pktid_ioctl_map = NULL; ++static void *wlan_static_dhd_log_dump_buf = NULL; ++static void *wlan_static_dhd_log_dump_buf_ex = NULL; ++static void *wlan_static_dhd_pktlog_dump_buf = NULL; ++static void *wlan_static_stat_report_buf = NULL; ++ ++#define GET_STATIC_BUF(section, config_size, req_size, buf) ({\ ++ void *__ret; \ ++ if (req_size > config_size) {\ ++ pr_err("request " #section " size(%lu) is bigger than" \ ++ " static size(%d)\n", \ ++ req_size, config_size); \ ++ __ret = NULL; \ ++ } else { __ret = buf;} \ ++ __ret; \ ++}) ++ ++void ++*dhd_wlan_mem_prealloc(int section, unsigned long size) ++{ ++ if (section == PREALLOC_WLAN_SEC_NUM) { ++ return wlan_static_skb; ++ } ++ ++ if (section == WLAN_STATIC_SCAN_BUF0) { ++ return wlan_static_scan_buf0; ++ } ++ ++ if (section == WLAN_STATIC_SCAN_BUF1) { ++ return wlan_static_scan_buf1; ++ } ++ ++ if (section == WLAN_STATIC_DHD_INFO_BUF) { ++ if (size > WLAN_DHD_INFO_BUF_SIZE) { ++ pr_err("request DHD_INFO size(%lu) is bigger than" ++ " static size(%d).\n", size, ++ WLAN_DHD_INFO_BUF_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_info_buf; ++ } ++ ++ if (section == WLAN_STATIC_DHD_WLFC_BUF) { ++ if (size > WLAN_DHD_WLFC_BUF_SIZE) { ++ pr_err("request DHD_WLFC size(%lu) is bigger than" ++ " static size(%d).\n", ++ size, WLAN_DHD_WLFC_BUF_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_wlfc_buf; ++ } ++ ++ if (section == WLAN_STATIC_DHD_WLFC_HANGER) { ++ if (size > WLAN_DHD_WLFC_HANGER_SIZE) { ++ pr_err("request DHD_WLFC_HANGER size(%lu) is bigger than" ++ " static size(%d).\n", ++ size, WLAN_DHD_WLFC_HANGER_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_wlfc_hanger; ++ } ++ ++ if (section == WLAN_STATIC_DHD_IF_FLOW_LKUP) { ++ if (size > WLAN_DHD_IF_FLOW_LKUP_SIZE) { ++ pr_err("request DHD_WLFC size(%lu) is bigger than" ++ " static size(%d).\n", ++ size, WLAN_DHD_WLFC_BUF_SIZE); ++ return NULL; ++ } ++ return wlan_static_if_flow_lkup; ++ } ++ ++ if (section == WLAN_STATIC_DHD_MEMDUMP_RAM) { ++ if (size > WLAN_DHD_MEMDUMP_SIZE) { ++ pr_err("request DHD_MEMDUMP_RAM size(%lu) is bigger" ++ " than static size(%d).\n", ++ size, WLAN_DHD_MEMDUMP_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_memdump_ram; ++ } ++ ++ if (section == WLAN_STATIC_DHD_PKTID_MAP) { ++ if (size > WLAN_DHD_PKTID_MAP_SIZE) { ++ pr_err("request DHD_PKTID_MAP size(%lu) is bigger than" ++ " static size(%d).\n", ++ size, WLAN_DHD_PKTID_MAP_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_pktid_map; ++ } ++ ++ ++ if (section == WLAN_STATIC_DHD_PKTID_IOCTL_MAP) { ++ if (size > WLAN_DHD_PKTID_IOCTL_MAP_SIZE) { ++ pr_err("request DHD_PKTID_IOCTL_MAP size(%lu) is bigger than" ++ " static size(%d).\n", ++ size, WLAN_DHD_PKTID_IOCTL_MAP_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_pktid_ioctl_map; ++ } ++ ++ if (section == WLAN_STATIC_DHD_LOG_DUMP_BUF) { ++ if (size > DHD_LOG_DUMP_BUF_SIZE) { ++ pr_err("request DHD_LOG_DUMP_BUF size(%lu) is bigger then" ++ " static size(%d).\n", ++ size, DHD_LOG_DUMP_BUF_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_log_dump_buf; ++ } ++ ++ if (section == WLAN_STATIC_DHD_LOG_DUMP_BUF_EX) { ++ if (size > DHD_LOG_DUMP_BUF_EX_SIZE) { ++ pr_err("request DHD_LOG_DUMP_BUF_EX size(%lu) is bigger then" ++ " static size(%d).\n", ++ size, DHD_LOG_DUMP_BUF_EX_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_log_dump_buf_ex; ++ } ++ ++ if (section == WLAN_STATIC_DHD_PKTLOG_DUMP_BUF) { ++ if (size > DHD_PKTLOG_DUMP_BUF_SIZE) { ++ pr_err("request DHD_PKTLOG_DUMP_BUF size(%lu) is bigger then" ++ " static size(%d).\n", ++ size, DHD_PKTLOG_DUMP_BUF_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_pktlog_dump_buf; ++ } ++ ++ if (section == WLAN_STATIC_STAT_REPORT_BUF) { ++ return GET_STATIC_BUF(WLAN_STATIC_STAT_REPORT_BUF, ++ DHD_STAT_REPORT_BUF_SIZE, size, wlan_static_stat_report_buf); ++ } ++ ++ if ((section < 0) || (section >= PREALLOC_WLAN_SEC_NUM)) { ++ return NULL; ++ } ++ ++ if (wlan_mem_array[section].size < size) { ++ return NULL; ++ } ++ ++ return wlan_mem_array[section].mem_ptr; ++} ++EXPORT_SYMBOL(dhd_wlan_mem_prealloc); ++ ++int ++dhd_init_wlan_mem(void) ++{ ++ int i; ++ int j; ++ ++ for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) { ++ wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE); ++ if (!wlan_static_skb[i]) { ++ goto err_skb_alloc; ++ } ++ } ++ ++ for (i = DHD_SKB_1PAGE_BUF_NUM; i < WLAN_SKB_1_2PAGE_BUF_NUM; i++) { ++ wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE); ++ if (!wlan_static_skb[i]) { ++ goto err_skb_alloc; ++ } ++ } ++ ++#if !defined(CONFIG_BCMDHD_PCIE) ++ wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE); ++ if (!wlan_static_skb[i]) { ++ goto err_skb_alloc; ++ } ++#endif /* !CONFIG_BCMDHD_PCIE */ ++ ++ for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) { ++ if (wlan_mem_array[i].size > 0) { ++ wlan_mem_array[i].mem_ptr = ++ kmalloc(wlan_mem_array[i].size, GFP_KERNEL); ++ ++ if (!wlan_mem_array[i].mem_ptr) { ++ goto err_mem_alloc; ++ } ++ } ++ } ++ ++ wlan_static_scan_buf0 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL); ++ if (!wlan_static_scan_buf0) { ++ pr_err("Failed to alloc wlan_static_scan_buf0\n"); ++ goto err_mem_alloc; ++ } ++ ++ wlan_static_scan_buf1 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL); ++ if (!wlan_static_scan_buf1) { ++ pr_err("Failed to alloc wlan_static_scan_buf1\n"); ++ goto err_mem_alloc; ++ } ++ ++ wlan_static_dhd_log_dump_buf = kmalloc(DHD_LOG_DUMP_BUF_SIZE, GFP_KERNEL); ++ if (!wlan_static_dhd_log_dump_buf) { ++ pr_err("Failed to alloc wlan_static_dhd_log_dump_buf\n"); ++ goto err_mem_alloc; ++ } ++ ++ wlan_static_dhd_log_dump_buf_ex = kmalloc(DHD_LOG_DUMP_BUF_EX_SIZE, GFP_KERNEL); ++ if (!wlan_static_dhd_log_dump_buf_ex) { ++ pr_err("Failed to alloc wlan_static_dhd_log_dump_buf_ex\n"); ++ goto err_mem_alloc; ++ } ++ ++ wlan_static_dhd_info_buf = kmalloc(WLAN_DHD_INFO_BUF_SIZE, GFP_KERNEL); ++ if (!wlan_static_dhd_info_buf) { ++ pr_err("Failed to alloc wlan_static_dhd_info_buf\n"); ++ goto err_mem_alloc; ++ } ++ ++#ifdef CONFIG_BCMDHD_PCIE ++ wlan_static_if_flow_lkup = kmalloc(WLAN_DHD_IF_FLOW_LKUP_SIZE, ++ GFP_KERNEL); ++ if (!wlan_static_if_flow_lkup) { ++ pr_err("Failed to alloc wlan_static_if_flow_lkup\n"); ++ goto err_mem_alloc; ++ } ++ ++#ifdef CONFIG_BCMDHD_PREALLOC_PKTIDMAP ++ wlan_static_dhd_pktid_map = kmalloc(WLAN_DHD_PKTID_MAP_SIZE, ++ GFP_KERNEL); ++ if (!wlan_static_dhd_pktid_map) { ++ pr_err("Failed to alloc wlan_static_dhd_pktid_map\n"); ++ goto err_mem_alloc; ++ } ++ ++ wlan_static_dhd_pktid_ioctl_map = kmalloc(WLAN_DHD_PKTID_IOCTL_MAP_SIZE, ++ GFP_KERNEL); ++ if (!wlan_static_dhd_pktid_ioctl_map) { ++ pr_err("Failed to alloc wlan_static_dhd_pktid_ioctl_map\n"); ++ goto err_mem_alloc; ++ } ++#endif /* CONFIG_BCMDHD_PREALLOC_PKTIDMAP */ ++#else ++ wlan_static_dhd_wlfc_buf = kmalloc(WLAN_DHD_WLFC_BUF_SIZE, ++ GFP_KERNEL); ++ if (!wlan_static_dhd_wlfc_buf) { ++ pr_err("Failed to alloc wlan_static_dhd_wlfc_buf\n"); ++ goto err_mem_alloc; ++ } ++ ++ wlan_static_dhd_wlfc_hanger = kmalloc(WLAN_DHD_WLFC_HANGER_SIZE, ++ GFP_KERNEL); ++ if (!wlan_static_dhd_wlfc_hanger) { ++ pr_err("Failed to alloc wlan_static_dhd_wlfc_hanger\n"); ++ goto err_mem_alloc; ++ } ++#endif /* CONFIG_BCMDHD_PCIE */ ++ ++#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP ++ wlan_static_dhd_memdump_ram = kmalloc(WLAN_DHD_MEMDUMP_SIZE, GFP_KERNEL); ++ if (!wlan_static_dhd_memdump_ram) { ++ pr_err("Failed to alloc wlan_static_dhd_memdump_ram\n"); ++ goto err_mem_alloc; ++ } ++#endif /* CONFIG_BCMDHD_PREALLOC_MEMDUMP */ ++ ++ wlan_static_dhd_pktlog_dump_buf = kmalloc(DHD_PKTLOG_DUMP_BUF_SIZE, GFP_KERNEL); ++ if (!wlan_static_dhd_pktlog_dump_buf) { ++ pr_err("Failed to alloc wlan_static_dhd_pktlog_dump_buf\n"); ++ goto err_mem_alloc; ++ } ++ ++ wlan_static_stat_report_buf = kmalloc(DHD_STAT_REPORT_BUF_SIZE, GFP_KERNEL); ++ if (!wlan_static_stat_report_buf) { ++ pr_err("Failed to alloc wlan_static_stat_report_buf\n"); ++ goto err_mem_alloc; ++ } ++ ++ pr_err("%s: WIFI MEM Allocated\n", __FUNCTION__); ++ return 0; ++ ++err_mem_alloc: ++#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP ++ if (wlan_static_dhd_memdump_ram) { ++ kfree(wlan_static_dhd_memdump_ram); ++ } ++ ++#endif /* CONFIG_BCMDHD_PREALLOC_MEMDUMP */ ++ ++#ifdef CONFIG_BCMDHD_PCIE ++ if (wlan_static_if_flow_lkup) { ++ kfree(wlan_static_if_flow_lkup); ++ } ++ ++#ifdef CONFIG_BCMDHD_PREALLOC_PKTIDMAP ++ if (wlan_static_dhd_pktid_map) { ++ kfree(wlan_static_dhd_pktid_map); ++ } ++ ++ if (wlan_static_dhd_pktid_ioctl_map) { ++ kfree(wlan_static_dhd_pktid_ioctl_map); ++ } ++#endif /* CONFIG_BCMDHD_PREALLOC_PKTIDMAP */ ++#else ++ if (wlan_static_dhd_wlfc_buf) { ++ kfree(wlan_static_dhd_wlfc_buf); ++ } ++ ++ if (wlan_static_dhd_wlfc_hanger) { ++ kfree(wlan_static_dhd_wlfc_hanger); ++ } ++#endif /* CONFIG_BCMDHD_PCIE */ ++ if (wlan_static_dhd_info_buf) { ++ kfree(wlan_static_dhd_info_buf); ++ } ++ ++ if (wlan_static_dhd_log_dump_buf) { ++ kfree(wlan_static_dhd_log_dump_buf); ++ } ++ ++ if (wlan_static_dhd_log_dump_buf_ex) { ++ kfree(wlan_static_dhd_log_dump_buf_ex); ++ } ++ ++ if (wlan_static_scan_buf1) { ++ kfree(wlan_static_scan_buf1); ++ } ++ ++ if (wlan_static_scan_buf0) { ++ kfree(wlan_static_scan_buf0); ++ } ++ ++ if (wlan_static_dhd_pktlog_dump_buf) { ++ kfree(wlan_static_dhd_pktlog_dump_buf); ++ } ++ ++ if (wlan_static_stat_report_buf) { ++ kfree(wlan_static_stat_report_buf); ++ } ++ ++ pr_err("Failed to mem_alloc for WLAN\n"); ++ ++ for (j = 0; j < i; j++) { ++ kfree(wlan_mem_array[j].mem_ptr); ++ } ++ ++ i = WLAN_SKB_BUF_NUM; ++ ++err_skb_alloc: ++ pr_err("Failed to skb_alloc for WLAN\n"); ++ for (j = 0; j < i; j++) { ++ dev_kfree_skb(wlan_static_skb[j]); ++ } ++ ++ return -ENOMEM; ++} ++EXPORT_SYMBOL(dhd_init_wlan_mem); ++#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_msm.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_msm.c +new file mode 100644 +index 000000000..27399d0d0 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_custom_msm.c +@@ -0,0 +1,253 @@ ++/* ++ * Platform Dependent file for Qualcomm MSM/APQ ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * <> ++ * ++ * $Id: dhd_custom_msm.c 674523 2016-12-09 04:05:27Z $ ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998) ++#include ++#endif /* CONFIG_ARCH_MSM8996 || CONFIG_ARCH_MSM8998 */ ++ ++#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM ++extern int dhd_init_wlan_mem(void); ++extern void *dhd_wlan_mem_prealloc(int section, unsigned long size); ++#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ ++ ++#define WIFI_TURNON_DELAY 200 ++static int wlan_reg_on = -1; ++#define DHD_DT_COMPAT_ENTRY "android,bcmdhd_wlan" ++#ifdef CUSTOMER_HW2 ++#define WIFI_WL_REG_ON_PROPNAME "wl_reg_on" ++#else ++#define WIFI_WL_REG_ON_PROPNAME "wlan-en-gpio" ++#endif /* CUSTOMER_HW2 */ ++ ++#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998) ++#define MSM_PCIE_CH_NUM 0 ++#else ++#define MSM_PCIE_CH_NUM 1 ++#endif /* CONFIG_ARCH_MSM8996 || CONFIG_ARCH_MSM8998 */ ++ ++#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE ++static int wlan_host_wake_up = -1; ++static int wlan_host_wake_irq = 0; ++#ifdef CUSTOMER_HW2 ++#define WIFI_WLAN_HOST_WAKE_PROPNAME "wl_host_wake" ++#else ++#define WIFI_WLAN_HOST_WAKE_PROPNAME "wlan-host-wake-gpio" ++#endif /* CUSTOMER_HW2 */ ++#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ ++ ++int __init ++dhd_wifi_init_gpio(void) ++{ ++ char *wlan_node = DHD_DT_COMPAT_ENTRY; ++ struct device_node *root_node = NULL; ++ ++ root_node = of_find_compatible_node(NULL, NULL, wlan_node); ++ if (!root_node) { ++ WARN(1, "failed to get device node of BRCM WLAN\n"); ++ return -ENODEV; ++ } ++ ++ /* ========== WLAN_PWR_EN ============ */ ++ wlan_reg_on = of_get_named_gpio(root_node, WIFI_WL_REG_ON_PROPNAME, 0); ++ printk(KERN_INFO "%s: gpio_wlan_power : %d\n", __FUNCTION__, wlan_reg_on); ++ ++ if (gpio_request_one(wlan_reg_on, GPIOF_OUT_INIT_LOW, "WL_REG_ON")) { ++ printk(KERN_ERR "%s: Faiiled to request gpio %d for WL_REG_ON\n", ++ __FUNCTION__, wlan_reg_on); ++ } else { ++ printk(KERN_ERR "%s: gpio_request WL_REG_ON done - WLAN_EN: GPIO %d\n", ++ __FUNCTION__, wlan_reg_on); ++ } ++ ++ if (gpio_direction_output(wlan_reg_on, 1)) { ++ printk(KERN_ERR "%s: WL_REG_ON failed to pull up\n", __FUNCTION__); ++ } else { ++ printk(KERN_ERR "%s: WL_REG_ON is pulled up\n", __FUNCTION__); ++ } ++ ++ if (gpio_get_value(wlan_reg_on)) { ++ printk(KERN_INFO "%s: Initial WL_REG_ON: [%d]\n", ++ __FUNCTION__, gpio_get_value(wlan_reg_on)); ++ } ++ ++ /* Wait for WIFI_TURNON_DELAY due to power stability */ ++ msleep(WIFI_TURNON_DELAY); ++ ++#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE ++ /* ========== WLAN_HOST_WAKE ============ */ ++ wlan_host_wake_up = of_get_named_gpio(root_node, WIFI_WLAN_HOST_WAKE_PROPNAME, 0); ++ printk(KERN_INFO "%s: gpio_wlan_host_wake : %d\n", __FUNCTION__, wlan_host_wake_up); ++ ++#ifndef CUSTOMER_HW2 ++ if (gpio_request_one(wlan_host_wake_up, GPIOF_IN, "WLAN_HOST_WAKE")) { ++ printk(KERN_ERR "%s: Failed to request gpio %d for WLAN_HOST_WAKE\n", ++ __FUNCTION__, wlan_host_wake_up); ++ return -ENODEV; ++ } else { ++ printk(KERN_ERR "%s: gpio_request WLAN_HOST_WAKE done" ++ " - WLAN_HOST_WAKE: GPIO %d\n", ++ __FUNCTION__, wlan_host_wake_up); ++ } ++#endif /* !CUSTOMER_HW2 */ ++ ++ gpio_direction_input(wlan_host_wake_up); ++ wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up); ++#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ ++ ++#if defined(CONFIG_BCM4359) || defined(CONFIG_BCM4361) ++ printk(KERN_INFO "%s: Call msm_pcie_enumerate\n", __FUNCTION__); ++ msm_pcie_enumerate(MSM_PCIE_CH_NUM); ++#endif /* CONFIG_BCM4359 || CONFIG_BCM4361 */ ++ ++ return 0; ++} ++ ++int ++dhd_wlan_power(int onoff) ++{ ++ printk(KERN_INFO"------------------------------------------------"); ++ printk(KERN_INFO"------------------------------------------------\n"); ++ printk(KERN_INFO"%s Enter: power %s\n", __func__, onoff ? "on" : "off"); ++ ++ if (onoff) { ++ if (gpio_direction_output(wlan_reg_on, 1)) { ++ printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n", __FUNCTION__); ++ return -EIO; ++ } ++ if (gpio_get_value(wlan_reg_on)) { ++ printk(KERN_INFO"WL_REG_ON on-step-2 : [%d]\n", ++ gpio_get_value(wlan_reg_on)); ++ } else { ++ printk("[%s] gpio value is 0. We need reinit.\n", __func__); ++ if (gpio_direction_output(wlan_reg_on, 1)) { ++ printk(KERN_ERR "%s: WL_REG_ON is " ++ "failed to pull up\n", __func__); ++ } ++ } ++ } else { ++ if (gpio_direction_output(wlan_reg_on, 0)) { ++ printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n", __FUNCTION__); ++ return -EIO; ++ } ++ if (gpio_get_value(wlan_reg_on)) { ++ printk(KERN_INFO"WL_REG_ON on-step-2 : [%d]\n", ++ gpio_get_value(wlan_reg_on)); ++ } ++ } ++ return 0; ++} ++EXPORT_SYMBOL(dhd_wlan_power); ++ ++static int ++dhd_wlan_reset(int onoff) ++{ ++ return 0; ++} ++ ++static int ++dhd_wlan_set_carddetect(int val) ++{ ++ return 0; ++} ++ ++struct resource dhd_wlan_resources = { ++ .name = "bcmdhd_wlan_irq", ++ .start = 0, /* Dummy */ ++ .end = 0, /* Dummy */ ++ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE | ++#ifdef CONFIG_BCMDHD_PCIE ++ IORESOURCE_IRQ_HIGHEDGE, ++#else ++ IORESOURCE_IRQ_HIGHLEVEL, ++#endif /* CONFIG_BCMDHD_PCIE */ ++}; ++EXPORT_SYMBOL(dhd_wlan_resources); ++ ++struct wifi_platform_data dhd_wlan_control = { ++ .set_power = dhd_wlan_power, ++ .set_reset = dhd_wlan_reset, ++ .set_carddetect = dhd_wlan_set_carddetect, ++#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM ++ .mem_prealloc = dhd_wlan_mem_prealloc, ++#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ ++}; ++EXPORT_SYMBOL(dhd_wlan_control); ++ ++int __init ++dhd_wlan_init(void) ++{ ++ int ret; ++ ++ printk(KERN_INFO"%s: START.......\n", __FUNCTION__); ++ ret = dhd_wifi_init_gpio(); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n", ++ __FUNCTION__, ret); ++ goto fail; ++ } ++ ++#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE ++ dhd_wlan_resources.start = wlan_host_wake_irq; ++ dhd_wlan_resources.end = wlan_host_wake_irq; ++#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ ++ ++#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM ++ ret = dhd_init_wlan_mem(); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: failed to alloc reserved memory," ++ " ret=%d\n", __FUNCTION__, ret); ++ } ++#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ ++ ++fail: ++ printk(KERN_INFO"%s: FINISH.......\n", __FUNCTION__); ++ return ret; ++} ++#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998) ++#if defined(CONFIG_DEFERRED_INITCALLS) ++deferred_module_init(dhd_wlan_init); ++#else ++late_initcall(dhd_wlan_init); ++#endif /* CONFIG_DEFERRED_INITCALLS */ ++#else ++device_initcall(dhd_wlan_init); ++#endif /* CONFIG_ARCH_MSM8996 || CONFIG_ARCH_MSM8998 */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_dbg.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_dbg.h +new file mode 100644 +index 000000000..3f90c5229 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_dbg.h +@@ -0,0 +1,347 @@ ++/* ++ * Debug/trace/assert driver definitions for Dongle Host Driver. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_dbg.h 667145 2016-10-26 04:27:53Z $ ++ */ ++ ++#ifndef _dhd_dbg_ ++#define _dhd_dbg_ ++ ++ ++#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) ++extern void dhd_log_dump_print(const char *fmt, ...); ++extern void dhd_log_dump_print_drv(const char *fmt, ...); ++#endif ++ ++#if defined(DHD_DEBUG) ++ ++#ifdef DHD_LOG_DUMP ++extern void dhd_log_dump_write(int type, const char *fmt, ...); ++extern char *dhd_log_dump_get_timestamp(void); ++#ifndef _DHD_LOG_DUMP_DEFINITIONS_ ++#define _DHD_LOG_DUMP_DEFINITIONS_ ++#define DLD_BUF_TYPE_GENERAL 0 ++#define DLD_BUF_TYPE_SPECIAL 1 ++#define DHD_LOG_DUMP_WRITE(fmt, ...) dhd_log_dump_write(DLD_BUF_TYPE_GENERAL, fmt, ##__VA_ARGS__) ++#define DHD_LOG_DUMP_WRITE_EX(fmt, ...) dhd_log_dump_write(DLD_BUF_TYPE_SPECIAL, fmt, ##__VA_ARGS__) ++#endif /* !_DHD_LOG_DUMP_DEFINITIONS_ */ ++ ++#ifdef DHD_EFI ++#define DHD_ERROR(args) \ ++do { \ ++ if (dhd_msg_level & DHD_ERROR_VAL) { \ ++ printf args; \ ++ dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ dhd_log_dump_print_drv args; \ ++ } \ ++} while (0) ++#define DHD_INFO(args) \ ++do { \ ++ if (dhd_msg_level & DHD_INFO_VAL) { \ ++ printf args; \ ++ dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ dhd_log_dump_print_drv args; \ ++ } \ ++} while (0) ++#else /* DHD_EFI */ ++#define DHD_ERROR(args) \ ++do { \ ++ if (dhd_msg_level & DHD_ERROR_VAL) { \ ++ printf args; \ ++ DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \ ++ DHD_LOG_DUMP_WRITE args; \ ++ } \ ++} while (0) ++#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) ++#endif /* DHD_EFI */ ++#else /* DHD_LOG_DUMP */ ++#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) printf args;} while (0) ++#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) ++#endif /* DHD_LOG_DUMP */ ++#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0) ++ ++#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) ++#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0) ++#define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) printf args;} while (0) ++#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0) ++#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0) ++#define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) printf args;} while (0) ++#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0) ++#ifdef DHD_LOG_DUMP ++#ifndef DHD_EFI ++#define DHD_EVENT(args) \ ++do { \ ++ if (dhd_msg_level & DHD_EVENT_VAL) { \ ++ printf args; \ ++ DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \ ++ DHD_LOG_DUMP_WRITE args; \ ++ } \ ++} while (0) ++#else ++#define DHD_EVENT(args) \ ++do { \ ++ if (dhd_msg_level & DHD_EVENT_VAL) { \ ++ dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ dhd_log_dump_print args; \ ++ } \ ++} while (0) ++#endif /* !DHD_EFI */ ++#else ++#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) ++#endif /* DHD_LOG_DUMP */ ++#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0) ++#define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0) ++#define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0) ++#define DHD_PNO(args) do {if (dhd_msg_level & DHD_PNO_VAL) printf args;} while (0) ++#define DHD_RTT(args) do {if (dhd_msg_level & DHD_RTT_VAL) printf args;} while (0) ++#define DHD_PKT_MON(args) do {if (dhd_msg_level & DHD_PKT_MON_VAL) printf args;} while (0) ++#ifdef DHD_LOG_DUMP ++#ifndef DHD_EFI ++#define DHD_MSGTRACE_LOG(args) \ ++do { \ ++ if (dhd_msg_level & DHD_MSGTRACE_VAL) { \ ++ printf args; \ ++ DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \ ++ DHD_LOG_DUMP_WRITE args; \ ++ } \ ++} while (0) ++#else ++#define DHD_MSGTRACE_LOG(args) \ ++do { \ ++ if (dhd_msg_level & DHD_MSGTRACE_VAL) { \ ++ dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ dhd_log_dump_print args; \ ++ } \ ++} while (0) ++#endif /* !DHD_EFI */ ++#else ++#define DHD_MSGTRACE_LOG(args) do {if (dhd_msg_level & DHD_MSGTRACE_VAL) printf args;} while (0) ++#endif /* DHD_LOG_DUMP */ ++ ++#if defined(DHD_LOG_DUMP) && defined(DHD_EFI) ++#define DHD_FWLOG(args) DHD_MSGTRACE_LOG(args) ++#else ++ ++#define DHD_FWLOG(args) do {if (dhd_msg_level & DHD_FWLOG_VAL) printf args;} while (0) ++#endif /* DHD_LOG_DUMP & DHD_EFI */ ++#define DHD_DBGIF(args) do {if (dhd_msg_level & DHD_DBGIF_VAL) printf args;} while (0) ++ ++#ifdef DHD_LOG_DUMP ++#ifdef DHD_EFI ++#define DHD_ERROR_MEM(args) \ ++do { \ ++ if (dhd_msg_level & DHD_ERROR_VAL) { \ ++ dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ dhd_log_dump_print_drv args; \ ++ } \ ++} while (0) ++#define DHD_ERROR_EX(args) DHD_ERROR(args) ++#else ++#define DHD_ERROR_MEM(args) \ ++do { \ ++ if (dhd_msg_level & DHD_ERROR_VAL) { \ ++ if (dhd_msg_level & DHD_ERROR_MEM_VAL) { \ ++ printf args; \ ++ } \ ++ DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ DHD_LOG_DUMP_WRITE args; \ ++ } \ ++} while (0) ++#define DHD_ERROR_EX(args) \ ++do { \ ++ if (dhd_msg_level & DHD_ERROR_VAL) { \ ++ printf args; \ ++ DHD_LOG_DUMP_WRITE_EX("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ DHD_LOG_DUMP_WRITE_EX args; \ ++ } \ ++} while (0) ++#endif /* DHD_EFI */ ++#else ++#define DHD_ERROR_MEM(args) DHD_ERROR(args) ++#define DHD_ERROR_EX(args) DHD_ERROR(args) ++#endif /* DHD_LOG_DUMP */ ++ ++#ifdef CUSTOMER_HW4_DEBUG ++#define DHD_TRACE_HW4 DHD_ERROR ++#define DHD_INFO_HW4 DHD_ERROR ++#else ++#define DHD_TRACE_HW4 DHD_TRACE ++#define DHD_INFO_HW4 DHD_INFO ++#endif /* CUSTOMER_HW4_DEBUG */ ++ ++#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) ++#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) ++#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL) ++#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL) ++#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL) ++#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL) ++#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL) ++#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL) ++#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL) ++#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL) ++#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL) ++#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) ++#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL) ++#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL) ++#define DHD_NOCHECKDIED_ON() (dhd_msg_level & DHD_NOCHECKDIED_VAL) ++#define DHD_PNO_ON() (dhd_msg_level & DHD_PNO_VAL) ++#define DHD_RTT_ON() (dhd_msg_level & DHD_RTT_VAL) ++#define DHD_MSGTRACE_ON() (dhd_msg_level & DHD_MSGTRACE_VAL) ++#define DHD_FWLOG_ON() (dhd_msg_level & DHD_FWLOG_VAL) ++#define DHD_DBGIF_ON() (dhd_msg_level & DHD_DBGIF_VAL) ++#define DHD_PKT_MON_ON() (dhd_msg_level & DHD_PKT_MON_VAL) ++#define DHD_PKT_MON_DUMP_ON() (dhd_msg_level & DHD_PKT_MON_DUMP_VAL) ++ ++#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ ++ ++#if defined(DHD_EFI) ++extern void dhd_log_dump_print_drv(const char *fmt, ...); ++extern char *dhd_log_dump_get_timestamp(void); ++#define DHD_ERROR(args) \ ++do { \ ++ if (dhd_msg_level & DHD_ERROR_VAL) { \ ++ printf args; \ ++ dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ dhd_log_dump_print_drv args; \ ++ } \ ++} while (0) ++#define DHD_INFO(args) \ ++do { \ ++ if (dhd_msg_level & DHD_INFO_VAL) { \ ++ printf args; \ ++ dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ dhd_log_dump_print_drv args; \ ++ } \ ++} while (0) ++#define DHD_TRACE(args) ++#else /* DHD_EFI */ ++ ++#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) \ ++ printf args;} while (0) ++#define DHD_TRACE(args) ++#define DHD_INFO(args) ++#endif ++ ++#define DHD_DATA(args) ++#define DHD_CTL(args) ++#define DHD_TIMER(args) ++#define DHD_HDRS(args) ++#define DHD_BYTES(args) ++#define DHD_INTR(args) ++#define DHD_GLOM(args) ++ ++#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) ++#define DHD_EVENT(args) \ ++do { \ ++ if (dhd_msg_level & DHD_EVENT_VAL) { \ ++ dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ dhd_log_dump_print args; \ ++ } \ ++} while (0) ++#else ++#define DHD_EVENT(args) ++#endif /* DHD_EFI && DHD_LOG_DUMP */ ++ ++#define DHD_ISCAN(args) ++#define DHD_ARPOE(args) ++#define DHD_REORDER(args) ++#define DHD_PNO(args) ++#define DHD_RTT(args) ++#define DHD_PKT_MON(args) ++ ++#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) ++#define DHD_MSGTRACE_LOG(args) \ ++do { \ ++ if (dhd_msg_level & DHD_MSGTRACE_VAL) { \ ++ dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ dhd_log_dump_print args; \ ++ } \ ++} while (0) ++#define DHD_FWLOG(args) DHD_MSGTRACE_LOG(args) ++#else ++#define DHD_MSGTRACE_LOG(args) ++#define DHD_FWLOG(args) ++#endif /* DHD_EFI && DHD_LOG_DUMP */ ++ ++#define DHD_DBGIF(args) ++ ++#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) ++#define DHD_ERROR_MEM(args) \ ++do { \ ++ if (dhd_msg_level & DHD_ERROR_VAL) { \ ++ dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ ++ dhd_log_dump_print args; \ ++ } \ ++} while (0) ++#define DHD_ERROR_EX(args) DHD_ERROR(args) ++#else ++#define DHD_ERROR_MEM(args) DHD_ERROR(args) ++#define DHD_ERROR_EX(args) DHD_ERROR(args) ++#endif /* DHD_EFI && DHD_LOG_DUMP */ ++ ++#ifdef CUSTOMER_HW4_DEBUG ++#define DHD_TRACE_HW4 DHD_ERROR ++#define DHD_INFO_HW4 DHD_ERROR ++#else ++#define DHD_TRACE_HW4 DHD_TRACE ++#define DHD_INFO_HW4 DHD_INFO ++#endif /* CUSTOMER_HW4_DEBUG */ ++ ++#define DHD_ERROR_ON() 0 ++#define DHD_TRACE_ON() 0 ++#define DHD_INFO_ON() 0 ++#define DHD_DATA_ON() 0 ++#define DHD_CTL_ON() 0 ++#define DHD_TIMER_ON() 0 ++#define DHD_HDRS_ON() 0 ++#define DHD_BYTES_ON() 0 ++#define DHD_INTR_ON() 0 ++#define DHD_GLOM_ON() 0 ++#define DHD_EVENT_ON() 0 ++#define DHD_ISCAN_ON() 0 ++#define DHD_ARPOE_ON() 0 ++#define DHD_REORDER_ON() 0 ++#define DHD_NOCHECKDIED_ON() 0 ++#define DHD_PNO_ON() 0 ++#define DHD_RTT_ON() 0 ++#define DHD_PKT_MON_ON() 0 ++#define DHD_PKT_MON_DUMP_ON() 0 ++#define DHD_MSGTRACE_ON() 0 ++#define DHD_FWLOG_ON() 0 ++#define DHD_DBGIF_ON() 0 ++#endif ++ ++#define DHD_LOG(args) ++ ++#define DHD_BLOG(cp, size) ++ ++#define DHD_NONE(args) ++extern int dhd_msg_level; ++ ++/* Defines msg bits */ ++#include ++ ++#endif /* _dhd_dbg_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_debug.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_debug.c +new file mode 100644 +index 000000000..66e96a43c +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_debug.c +@@ -0,0 +1,2335 @@ ++/* ++ * DHD debugability support ++ * ++ * <> ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_debug.c 711908 2017-07-20 10:37:34Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#if defined(DHD_EFI) ++#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) ++#define container_of(ptr, type, member) \ ++ ((type *)((char *)(ptr) - offsetof(type, member))) ++#endif ++ ++#define DBGRING_FLUSH_THRESHOLD(ring) (ring->ring_size / 3) ++#define RING_STAT_TO_STATUS(ring, status) \ ++ do { \ ++ strncpy(status.name, ring->name, \ ++ sizeof(status.name) - 1); \ ++ status.ring_id = ring->id; \ ++ status.ring_buffer_byte_size = ring->ring_size; \ ++ status.written_bytes = ring->stat.written_bytes; \ ++ status.written_records = ring->stat.written_records; \ ++ status.read_bytes = ring->stat.read_bytes; \ ++ status.verbose_level = ring->log_level; \ ++ } while (0) ++ ++#define DHD_PKT_INFO DHD_ERROR ++struct map_table { ++ uint16 fw_id; ++ uint16 host_id; ++ char *desc; ++}; ++ ++struct map_table event_map[] = { ++ {WLC_E_AUTH, WIFI_EVENT_AUTH_COMPLETE, "AUTH_COMPLETE"}, ++ {WLC_E_ASSOC, WIFI_EVENT_ASSOC_COMPLETE, "ASSOC_COMPLETE"}, ++ {TRACE_FW_AUTH_STARTED, WIFI_EVENT_FW_AUTH_STARTED, "AUTH STARTED"}, ++ {TRACE_FW_ASSOC_STARTED, WIFI_EVENT_FW_ASSOC_STARTED, "ASSOC STARTED"}, ++ {TRACE_FW_RE_ASSOC_STARTED, WIFI_EVENT_FW_RE_ASSOC_STARTED, "REASSOC STARTED"}, ++ {TRACE_G_SCAN_STARTED, WIFI_EVENT_G_SCAN_STARTED, "GSCAN STARTED"}, ++ {WLC_E_PFN_SCAN_COMPLETE, WIFI_EVENT_G_SCAN_COMPLETE, "GSCAN COMPLETE"}, ++ {WLC_E_DISASSOC, WIFI_EVENT_DISASSOCIATION_REQUESTED, "DIASSOC REQUESTED"}, ++ {WLC_E_REASSOC, WIFI_EVENT_RE_ASSOCIATION_REQUESTED, "REASSOC REQUESTED"}, ++ {TRACE_ROAM_SCAN_STARTED, WIFI_EVENT_ROAM_REQUESTED, "ROAM REQUESTED"}, ++ {WLC_E_BEACON_FRAME_RX, WIFI_EVENT_BEACON_RECEIVED, "BEACON Received"}, ++ {TRACE_ROAM_SCAN_STARTED, WIFI_EVENT_ROAM_SCAN_STARTED, "ROAM SCAN STARTED"}, ++ {TRACE_ROAM_SCAN_COMPLETE, WIFI_EVENT_ROAM_SCAN_COMPLETE, "ROAM SCAN COMPLETED"}, ++ {TRACE_ROAM_AUTH_STARTED, WIFI_EVENT_ROAM_AUTH_STARTED, "ROAM AUTH STARTED"}, ++ {WLC_E_AUTH, WIFI_EVENT_ROAM_AUTH_COMPLETE, "ROAM AUTH COMPLETED"}, ++ {TRACE_FW_RE_ASSOC_STARTED, WIFI_EVENT_ROAM_ASSOC_STARTED, "ROAM ASSOC STARTED"}, ++ {WLC_E_ASSOC, WIFI_EVENT_ROAM_ASSOC_COMPLETE, "ROAM ASSOC COMPLETED"}, ++ {TRACE_ROAM_SCAN_COMPLETE, WIFI_EVENT_ROAM_SCAN_COMPLETE, "ROAM SCAN COMPLETED"}, ++ {TRACE_BT_COEX_BT_SCO_START, WIFI_EVENT_BT_COEX_BT_SCO_START, "BT SCO START"}, ++ {TRACE_BT_COEX_BT_SCO_STOP, WIFI_EVENT_BT_COEX_BT_SCO_STOP, "BT SCO STOP"}, ++ {TRACE_BT_COEX_BT_SCAN_START, WIFI_EVENT_BT_COEX_BT_SCAN_START, "BT COEX SCAN START"}, ++ {TRACE_BT_COEX_BT_SCAN_STOP, WIFI_EVENT_BT_COEX_BT_SCAN_STOP, "BT COEX SCAN STOP"}, ++ {TRACE_BT_COEX_BT_HID_START, WIFI_EVENT_BT_COEX_BT_HID_START, "BT HID START"}, ++ {TRACE_BT_COEX_BT_HID_STOP, WIFI_EVENT_BT_COEX_BT_HID_STOP, "BT HID STOP"}, ++ {WLC_E_EAPOL_MSG, WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED, "FW EAPOL PKT RECEIVED"}, ++ {TRACE_FW_EAPOL_FRAME_TRANSMIT_START, WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START, ++ "FW EAPOL PKT TRANSMITED"}, ++ {TRACE_FW_EAPOL_FRAME_TRANSMIT_STOP, WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP, ++ "FW EAPOL PKT TX STOPPED"}, ++ {TRACE_BLOCK_ACK_NEGOTIATION_COMPLETE, WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE, ++ "BLOCK ACK NEGO COMPLETED"}, ++}; ++ ++struct map_table event_tag_map[] = { ++ {TRACE_TAG_VENDOR_SPECIFIC, WIFI_TAG_VENDOR_SPECIFIC, "VENDOR SPECIFIC DATA"}, ++ {TRACE_TAG_BSSID, WIFI_TAG_BSSID, "BSSID"}, ++ {TRACE_TAG_ADDR, WIFI_TAG_ADDR, "ADDR_0"}, ++ {TRACE_TAG_SSID, WIFI_TAG_SSID, "SSID"}, ++ {TRACE_TAG_STATUS, WIFI_TAG_STATUS, "STATUS"}, ++ {TRACE_TAG_CHANNEL_SPEC, WIFI_TAG_CHANNEL_SPEC, "CHANSPEC"}, ++ {TRACE_TAG_WAKE_LOCK_EVENT, WIFI_TAG_WAKE_LOCK_EVENT, "WAKELOCK EVENT"}, ++ {TRACE_TAG_ADDR1, WIFI_TAG_ADDR1, "ADDR_1"}, ++ {TRACE_TAG_ADDR2, WIFI_TAG_ADDR2, "ADDR_2"}, ++ {TRACE_TAG_ADDR3, WIFI_TAG_ADDR3, "ADDR_3"}, ++ {TRACE_TAG_ADDR4, WIFI_TAG_ADDR4, "ADDR_4"}, ++ {TRACE_TAG_TSF, WIFI_TAG_TSF, "TSF"}, ++ {TRACE_TAG_IE, WIFI_TAG_IE, "802.11 IE"}, ++ {TRACE_TAG_INTERFACE, WIFI_TAG_INTERFACE, "INTERFACE"}, ++ {TRACE_TAG_REASON_CODE, WIFI_TAG_REASON_CODE, "REASON CODE"}, ++ {TRACE_TAG_RATE_MBPS, WIFI_TAG_RATE_MBPS, "RATE"}, ++}; ++ ++/* define log level per ring type */ ++struct log_level_table fw_verbose_level_map[] = { ++ {1, EVENT_LOG_TAG_PCI_ERROR, EVENT_LOG_SET_BUS, "PCI_ERROR"}, ++ {1, EVENT_LOG_TAG_PCI_WARN, EVENT_LOG_SET_BUS, "PCI_WARN"}, ++ {2, EVENT_LOG_TAG_PCI_INFO, EVENT_LOG_SET_BUS, "PCI_INFO"}, ++ {3, EVENT_LOG_TAG_PCI_DBG, EVENT_LOG_SET_BUS, "PCI_DEBUG"}, ++ {3, EVENT_LOG_TAG_BEACON_LOG, EVENT_LOG_SET_WL, "BEACON_LOG"}, ++ {2, EVENT_LOG_TAG_WL_ASSOC_LOG, EVENT_LOG_SET_WL, "ASSOC_LOG"}, ++ {2, EVENT_LOG_TAG_WL_ROAM_LOG, EVENT_LOG_SET_WL, "ROAM_LOG"}, ++ {1, EVENT_LOG_TAG_TRACE_WL_INFO, EVENT_LOG_SET_WL, "WL_INFO"}, ++ {1, EVENT_LOG_TAG_TRACE_BTCOEX_INFO, EVENT_LOG_SET_WL, "BTCOEX_INFO"}, ++#ifdef CUSTOMER_HW4_DEBUG ++ {3, EVENT_LOG_TAG_SCAN_WARN, EVENT_LOG_SET_WL, "SCAN_WARN"}, ++#else ++ {1, EVENT_LOG_TAG_SCAN_WARN, EVENT_LOG_SET_WL, "SCAN_WARN"}, ++#endif /* CUSTOMER_HW4_DEBUG */ ++ {1, EVENT_LOG_TAG_SCAN_ERROR, EVENT_LOG_SET_WL, "SCAN_ERROR"}, ++ {2, EVENT_LOG_TAG_SCAN_TRACE_LOW, EVENT_LOG_SET_WL, "SCAN_TRACE_LOW"}, ++ {2, EVENT_LOG_TAG_SCAN_TRACE_HIGH, EVENT_LOG_SET_WL, "SCAN_TRACE_HIGH"} ++}; ++ ++struct log_level_table fw_event_level_map[] = { ++ {1, EVENT_LOG_TAG_TRACE_WL_INFO, EVENT_LOG_SET_WL, "WL_INFO"}, ++ {1, EVENT_LOG_TAG_TRACE_BTCOEX_INFO, EVENT_LOG_SET_WL, "BTCOEX_INFO"}, ++#ifdef CUSTOMER_HW4_DEBUG ++ {3, EVENT_LOG_TAG_BEACON_LOG, EVENT_LOG_SET_WL, "BEACON LOG"}, ++#else ++ {2, EVENT_LOG_TAG_BEACON_LOG, EVENT_LOG_SET_WL, "BEACON LOG"}, ++#endif /* CUSTOMER_HW4_DEBUG */ ++}; ++ ++struct map_table nan_event_map[] = { ++ {TRACE_NAN_CLUSTER_STARTED, NAN_EVENT_CLUSTER_STARTED, "NAN_CLUSTER_STARTED"}, ++ {TRACE_NAN_CLUSTER_JOINED, NAN_EVENT_CLUSTER_JOINED, "NAN_CLUSTER_JOINED"}, ++ {TRACE_NAN_CLUSTER_MERGED, NAN_EVENT_CLUSTER_MERGED, "NAN_CLUSTER_MERGED"}, ++ {TRACE_NAN_ROLE_CHANGED, NAN_EVENT_ROLE_CHANGED, "NAN_ROLE_CHANGED"}, ++ {TRACE_NAN_SCAN_COMPLETE, NAN_EVENT_SCAN_COMPLETE, "NAN_SCAN_COMPLETE"}, ++ {TRACE_NAN_STATUS_CHNG, NAN_EVENT_STATUS_CHNG, "NAN_STATUS_CHNG"}, ++}; ++ ++struct log_level_table nan_event_level_map[] = { ++ {1, EVENT_LOG_TAG_NAN_ERROR, 0, "NAN_ERROR"}, ++ {2, EVENT_LOG_TAG_NAN_INFO, 0, "NAN_INFO"}, ++ {3, EVENT_LOG_TAG_NAN_DBG, 0, "NAN_DEBUG"}, ++}; ++ ++struct map_table nan_evt_tag_map[] = { ++ {TRACE_TAG_BSSID, WIFI_TAG_BSSID, "BSSID"}, ++ {TRACE_TAG_ADDR, WIFI_TAG_ADDR, "ADDR_0"}, ++}; ++ ++/* reference tab table */ ++uint ref_tag_tbl[EVENT_LOG_TAG_MAX + 1] = {0}; ++ ++typedef struct dhddbg_loglist_item { ++ dll_t list; ++ event_log_hdr_t *hdr; ++} loglist_item_t; ++ ++typedef struct dhbdbg_pending_item { ++ dll_t list; ++ dhd_dbg_ring_status_t ring_status; ++ dhd_dbg_ring_entry_t *ring_entry; ++} pending_item_t; ++ ++/* trace log entry header user space processing */ ++struct tracelog_header { ++ int magic_num; ++ int buf_size; ++ int seq_num; ++}; ++#define TRACE_LOG_MAGIC_NUMBER 0xEAE47C06 ++ ++int ++dhd_dbg_ring_pull_single(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len, ++ bool strip_header) ++{ ++ dhd_dbg_ring_t *ring; ++ dhd_dbg_ring_entry_t *r_entry; ++ uint32 rlen; ++ char *buf; ++ ++ if (!dhdp || !dhdp->dbg) { ++ return 0; ++ } ++ ++ ring = &dhdp->dbg->dbg_rings[ring_id]; ++ ++ if (ring->state != RING_ACTIVE) { ++ return 0; ++ } ++ ++ if (ring->rp == ring->wp) { ++ return 0; ++ } ++ ++ r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->rp); ++ ++ /* Boundary Check */ ++ rlen = ENTRY_LENGTH(r_entry); ++ if ((ring->rp + rlen) > ring->ring_size) { ++ DHD_ERROR(("%s: entry len %d is out of boundary of ring size %d," ++ " current ring %d[%s] - rp=%d\n", __FUNCTION__, rlen, ++ ring->ring_size, ring->id, ring->name, ring->rp)); ++ return 0; ++ } ++ ++ if (strip_header) { ++ rlen = r_entry->len; ++ buf = (char *)r_entry + DBG_RING_ENTRY_SIZE; ++ } else { ++ rlen = ENTRY_LENGTH(r_entry); ++ buf = (char *)r_entry; ++ } ++ if (rlen > buf_len) { ++ DHD_ERROR(("%s: buf len %d is too small for entry len %d\n", ++ __FUNCTION__, buf_len, rlen)); ++ DHD_ERROR(("%s: ring %d[%s] - ring size=%d, wp=%d, rp=%d\n", ++ __FUNCTION__, ring->id, ring->name, ring->ring_size, ++ ring->wp, ring->rp)); ++ ASSERT(0); ++ return 0; ++ } ++ ++ memcpy(data, buf, rlen); ++ /* update ring context */ ++ ring->rp += ENTRY_LENGTH(r_entry); ++ /* skip padding if there is one */ ++ if (ring->tail_padded && ((ring->rp + ring->rem_len) == ring->ring_size)) { ++ DHD_DBGIF(("%s: RING%d[%s] Found padding, rp=%d, wp=%d\n", ++ __FUNCTION__, ring->id, ring->name, ring->rp, ring->wp)); ++ ring->rp = 0; ++ ring->tail_padded = FALSE; ++ ring->rem_len = 0; ++ } ++ if (ring->rp >= ring->ring_size) { ++ DHD_ERROR(("%s: RING%d[%s] rp pointed out of ring boundary," ++ " rp=%d, ring_size=%d\n", __FUNCTION__, ring->id, ++ ring->name, ring->rp, ring->ring_size)); ++ ASSERT(0); ++ } ++ ring->stat.read_bytes += ENTRY_LENGTH(r_entry); ++ DHD_DBGIF(("%s RING%d[%s]read_bytes %d, wp=%d, rp=%d\n", __FUNCTION__, ++ ring->id, ring->name, ring->stat.read_bytes, ring->wp, ring->rp)); ++ ++ return rlen; ++} ++ ++int ++dhd_dbg_ring_pull(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len) ++{ ++ int32 r_len, total_r_len = 0; ++ dhd_dbg_ring_t *ring; ++ ++ if (!dhdp || !dhdp->dbg) ++ return 0; ++ ring = &dhdp->dbg->dbg_rings[ring_id]; ++ if (ring->state != RING_ACTIVE) ++ return 0; ++ ++ while (buf_len > 0) { ++ r_len = dhd_dbg_ring_pull_single(dhdp, ring_id, data, buf_len, FALSE); ++ if (r_len == 0) ++ break; ++ data = (uint8 *)data + r_len; ++ buf_len -= r_len; ++ total_r_len += r_len; ++ } ++ ++ return total_r_len; ++} ++ ++int ++dhd_dbg_ring_push(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr, void *data) ++{ ++ unsigned long flags; ++ uint32 pending_len; ++ uint32 w_len; ++ uint32 avail_size; ++ dhd_dbg_ring_t *ring; ++ dhd_dbg_ring_entry_t *w_entry, *r_entry; ++ ++ if (!dhdp || !dhdp->dbg) { ++ return BCME_BADADDR; ++ } ++ ++ ring = &dhdp->dbg->dbg_rings[ring_id]; ++ ++ if (ring->state != RING_ACTIVE) { ++ return BCME_OK; ++ } ++ ++ flags = dhd_os_spin_lock(ring->lock); ++ ++ w_len = ENTRY_LENGTH(hdr); ++ ++ if (w_len > ring->ring_size) { ++ dhd_os_spin_unlock(ring->lock, flags); ++ return BCME_ERROR; ++ } ++ ++ /* Claim the space */ ++ do { ++ avail_size = DBG_RING_CHECK_WRITE_SPACE(ring->rp, ring->wp, ring->ring_size); ++ if (avail_size <= w_len) { ++ /* Prepare the space */ ++ if (ring->rp <= ring->wp) { ++ ring->tail_padded = TRUE; ++ ring->rem_len = ring->ring_size - ring->wp; ++ DHD_DBGIF(("%s: RING%d[%s] Insuffient tail space," ++ " rp=%d, wp=%d, rem_len=%d, ring_size=%d," ++ " avail_size=%d, w_len=%d\n", __FUNCTION__, ++ ring->id, ring->name, ring->rp, ring->wp, ++ ring->rem_len, ring->ring_size, avail_size, ++ w_len)); ++ ++ /* 0 pad insufficient tail space */ ++ memset((uint8 *)ring->ring_buf + ring->wp, 0, ring->rem_len); ++ if (ring->rp == ring->wp) { ++ ring->rp = 0; ++ } ++ ring->wp = 0; ++ } else { ++ /* Not enough space for new entry, free some up */ ++ r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ++ ring->rp); ++ ring->rp += ENTRY_LENGTH(r_entry); ++ /* skip padding if there is one */ ++ if (ring->tail_padded && ++ ((ring->rp + ring->rem_len) == ring->ring_size)) { ++ DHD_DBGIF(("%s: RING%d[%s] Found padding," ++ " avail_size=%d, w_len=%d\n", __FUNCTION__, ++ ring->id, ring->name, avail_size, w_len)); ++ ring->rp = 0; ++ ring->tail_padded = FALSE; ++ ring->rem_len = 0; ++ } ++ if (ring->rp >= ring->ring_size) { ++ DHD_ERROR(("%s: RING%d[%s] rp points out of boundary," ++ " ring->rp = %d, ring->ring_size=%d\n", ++ __FUNCTION__, ring->id, ring->name, ring->rp, ++ ring->ring_size)); ++ ASSERT(0); ++ } ++ ring->stat.read_bytes += ENTRY_LENGTH(r_entry); ++ DHD_DBGIF(("%s: RING%d[%s] read_bytes %d, wp=%d, rp=%d\n", ++ __FUNCTION__, ring->id, ring->name, ring->stat.read_bytes, ++ ring->wp, ring->rp)); ++ } ++ } else { ++ break; ++ } ++ } while (TRUE); ++ ++ w_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->wp); ++ /* header */ ++ memcpy(w_entry, hdr, DBG_RING_ENTRY_SIZE); ++ w_entry->len = hdr->len; ++ /* payload */ ++ memcpy((char *)w_entry + DBG_RING_ENTRY_SIZE, data, w_entry->len); ++ /* update write pointer */ ++ ring->wp += w_len; ++ if (ring->wp >= ring->ring_size) { ++ DHD_ERROR(("%s: RING%d[%s] wp pointed out of ring boundary, " ++ "wp=%d, ring_size=%d\n", __FUNCTION__, ring->id, ++ ring->name, ring->wp, ring->ring_size)); ++ ASSERT(0); ++ } ++ /* update statistics */ ++ ring->stat.written_records++; ++ ring->stat.written_bytes += w_len; ++ DHD_DBGIF(("%s : RING%d[%s] written_records %d, written_bytes %d, read_bytes=%d," ++ " ring->threshold=%d, wp=%d, rp=%d\n", __FUNCTION__, ring->id, ring->name, ++ ring->stat.written_records, ring->stat.written_bytes, ring->stat.read_bytes, ++ ring->threshold, ring->wp, ring->rp)); ++ ++ /* Calculate current pending size */ ++ if (ring->stat.written_bytes > ring->stat.read_bytes) { ++ pending_len = ring->stat.written_bytes - ring->stat.read_bytes; ++ } else if (ring->stat.written_bytes < ring->stat.read_bytes) { ++ pending_len = 0xFFFFFFFF - ring->stat.read_bytes + ring->stat.written_bytes; ++ } else { ++ pending_len = 0; ++ } ++ ++ /* if the current pending size is bigger than threshold */ ++ if (ring->threshold > 0 && ++ (pending_len >= ring->threshold) && ring->sched_pull) { ++ dhdp->dbg->pullreq(dhdp->dbg->private, ring->id); ++ ring->sched_pull = FALSE; ++ } ++ dhd_os_spin_unlock(ring->lock, flags); ++ return BCME_OK; ++} ++ ++static int ++dhd_dbg_msgtrace_seqchk(uint32 *prev, uint32 cur) ++{ ++ /* normal case including wrap around */ ++ if ((cur == 0 && *prev == 0xFFFFFFFF) || ((cur - *prev) == 1)) { ++ goto done; ++ } else if (cur == *prev) { ++ DHD_EVENT(("%s duplicate trace\n", __FUNCTION__)); ++ return -1; ++ } else if (cur > *prev) { ++ DHD_EVENT(("%s lost %d packets\n", __FUNCTION__, cur - *prev)); ++ } else { ++ DHD_EVENT(("%s seq out of order, dhd %d, dongle %d\n", ++ __FUNCTION__, *prev, cur)); ++ } ++done: ++ *prev = cur; ++ return 0; ++} ++ ++#ifndef MACOSX_DHD ++static void ++dhd_dbg_msgtrace_msg_parser(void *event_data) ++{ ++ msgtrace_hdr_t *hdr; ++ char *data, *s; ++ static uint32 seqnum_prev = 0; ++ ++ hdr = (msgtrace_hdr_t *)event_data; ++ data = (char *)event_data + MSGTRACE_HDRLEN; ++ ++ /* There are 2 bytes available at the end of data */ ++ data[ntoh16(hdr->len)] = '\0'; ++ ++ if (ntoh32(hdr->discarded_bytes) || ntoh32(hdr->discarded_printf)) { ++ DHD_DBGIF(("WLC_E_TRACE: [Discarded traces in dongle -->" ++ "discarded_bytes %d discarded_printf %d]\n", ++ ntoh32(hdr->discarded_bytes), ++ ntoh32(hdr->discarded_printf))); ++ } ++ ++ if (dhd_dbg_msgtrace_seqchk(&seqnum_prev, ntoh32(hdr->seqnum))) ++ return; ++ ++ /* Display the trace buffer. Advance from ++ * \n to \n to avoid display big ++ * printf (issue with Linux printk ) ++ */ ++ while (*data != '\0' && (s = strstr(data, "\n")) != NULL) { ++ *s = '\0'; ++ DHD_FWLOG(("[FWLOG] %s\n", data)); ++ data = s+1; ++ } ++ if (*data) ++ DHD_FWLOG(("[FWLOG] %s", data)); ++} ++#endif /* MACOSX_DHD */ ++#ifdef SHOW_LOGTRACE ++static const uint8 * ++event_get_tlv(uint16 id, const char* tlvs, uint tlvs_len) ++{ ++ const uint8 *pos = (const uint8 *)tlvs; ++ const uint8 *end = pos + tlvs_len; ++ const tlv_log *tlv; ++ int rest; ++ ++ while (pos + 1 < end) { ++ if (pos + 4 + pos[1] > end) ++ break; ++ tlv = (const tlv_log *) pos; ++ if (tlv->tag == id) ++ return pos; ++ rest = tlv->len % 4; /* padding values */ ++ pos += 4 + tlv->len + rest; ++ } ++ return NULL; ++} ++ ++#define DATA_UNIT_FOR_LOG_CNT 4 ++/* #pragma used as a WAR to fix build failure, ++ * ignore dropping of 'const' qualifier in tlv_data assignment ++ * this pragma disables the warning only for the following function ++ */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++static int ++dhd_dbg_nan_event_handler(dhd_pub_t *dhdp, event_log_hdr_t *hdr, uint32 *data) ++{ ++ int ret = BCME_OK; ++ wl_event_log_id_ver_t nan_hdr; ++ log_nan_event_t *evt_payload; ++ uint16 evt_payload_len = 0, tot_payload_len = 0; ++ dhd_dbg_ring_entry_t msg_hdr; ++ bool evt_match = FALSE; ++ event_log_hdr_t *ts_hdr; ++ uint32 *ts_data; ++ char *tlvs, *dest_tlvs; ++ tlv_log *tlv_data; ++ int tlv_len = 0; ++ int i = 0, evt_idx = 0; ++ char eaddr_buf[ETHER_ADDR_STR_LEN]; ++ ++ BCM_REFERENCE(eaddr_buf); ++ ++ nan_hdr.t = *data; ++ DHD_DBGIF(("%s: version %u event %x\n", __FUNCTION__, nan_hdr.version, ++ nan_hdr.event)); ++ ++ if (nan_hdr.version != DIAG_VERSION) { ++ DHD_ERROR(("Event payload version %u mismatch with current version %u\n", ++ nan_hdr.version, DIAG_VERSION)); ++ return BCME_VERSION; ++ } ++ ++ /* nan event log should at least contain a wl_event_log_id_ver_t ++ * header and a arm cycle count ++ */ ++ if (hdr->count < NAN_EVENT_LOG_MIN_LENGTH) { ++ return BCME_BADLEN; ++ } ++ ++ memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t)); ++ ts_hdr = (event_log_hdr_t *)((uint8 *)data - sizeof(event_log_hdr_t)); ++ if (ts_hdr->tag == EVENT_LOG_TAG_TS) { ++ ts_data = (uint32 *)ts_hdr - ts_hdr->count; ++ msg_hdr.timestamp = (uint64)ts_data[0]; ++ msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP; ++ } ++ msg_hdr.type = DBG_RING_ENTRY_NAN_EVENT_TYPE; ++ for (i = 0; i < ARRAYSIZE(nan_event_map); i++) { ++ if (nan_event_map[i].fw_id == nan_hdr.event) { ++ evt_match = TRUE; ++ evt_idx = i; ++ break; ++ } ++ } ++ if (evt_match) { ++ DHD_DBGIF(("%s : event (%s)\n", __FUNCTION__, nan_event_map[evt_idx].desc)); ++ /* payload length for nan event data */ ++ evt_payload_len = sizeof(log_nan_event_t) + ++ (hdr->count - 2) * DATA_UNIT_FOR_LOG_CNT; ++ if ((evt_payload = MALLOC(dhdp->osh, evt_payload_len)) == NULL) { ++ DHD_ERROR(("Memory allocation failed for nan evt log (%u)\n", ++ evt_payload_len)); ++ return BCME_NOMEM; ++ } ++ evt_payload->version = NAN_EVENT_VERSION; ++ evt_payload->event = nan_event_map[evt_idx].host_id; ++ dest_tlvs = (char *)evt_payload->tlvs; ++ tot_payload_len = sizeof(log_nan_event_t); ++ tlvs = (char *)(&data[1]); ++ tlv_len = (hdr->count - 2) * DATA_UNIT_FOR_LOG_CNT; ++ for (i = 0; i < ARRAYSIZE(nan_evt_tag_map); i++) { ++ tlv_data = (tlv_log *)event_get_tlv(nan_evt_tag_map[i].fw_id, ++ tlvs, tlv_len); ++ if (tlv_data) { ++ DHD_DBGIF(("NAN evt tlv.tag(%s), tlv.len : %d, tlv.data : ", ++ nan_evt_tag_map[i].desc, tlv_data->len)); ++ memcpy(dest_tlvs, tlv_data, sizeof(tlv_log) + tlv_data->len); ++ tot_payload_len += tlv_data->len + sizeof(tlv_log); ++ switch (tlv_data->tag) { ++ case TRACE_TAG_BSSID: ++ case TRACE_TAG_ADDR: ++ DHD_DBGIF(("%s\n", ++ bcm_ether_ntoa( ++ (const struct ether_addr *)tlv_data->value, ++ eaddr_buf))); ++ break; ++ default: ++ if (DHD_DBGIF_ON()) { ++ prhex(NULL, &tlv_data->value[0], ++ tlv_data->len); ++ } ++ break; ++ } ++ dest_tlvs += tlv_data->len + sizeof(tlv_log); ++ } ++ } ++ msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_BINARY; ++ msg_hdr.len = tot_payload_len; ++ dhd_dbg_ring_push(dhdp, NAN_EVENT_RING_ID, &msg_hdr, evt_payload); ++ MFREE(dhdp->osh, evt_payload, evt_payload_len); ++ } ++ return ret; ++} ++ ++static int ++dhd_dbg_custom_evnt_handler(dhd_pub_t *dhdp, event_log_hdr_t *hdr, uint32 *data) ++{ ++ int i = 0, match_idx = 0; ++ int payload_len, tlv_len; ++ uint16 tot_payload_len = 0; ++ int ret = BCME_OK; ++ int log_level; ++ wl_event_log_id_ver_t wl_log_id; ++ dhd_dbg_ring_entry_t msg_hdr; ++ log_conn_event_t *event_data; ++ bool evt_match = FALSE; ++ event_log_hdr_t *ts_hdr; ++ uint32 *ts_data; ++ char *tlvs, *dest_tlvs; ++ tlv_log *tlv_data; ++ static uint64 ts_saved = 0; ++ char eabuf[ETHER_ADDR_STR_LEN]; ++ char chanbuf[CHANSPEC_STR_LEN]; ++ ++ BCM_REFERENCE(eabuf); ++ BCM_REFERENCE(chanbuf); ++ /* get a event type and version */ ++ wl_log_id.t = *data; ++ if (wl_log_id.version != DIAG_VERSION) ++ return BCME_VERSION; ++ ++ /* custom event log should at least contain a wl_event_log_id_ver_t ++ * header and a arm cycle count ++ */ ++ if (hdr->count < NAN_EVENT_LOG_MIN_LENGTH) { ++ return BCME_BADLEN; ++ } ++ ++ ts_hdr = (event_log_hdr_t *)((uint8 *)data - sizeof(event_log_hdr_t)); ++ if (ts_hdr->tag == EVENT_LOG_TAG_TS) { ++ ts_data = (uint32 *)ts_hdr - ts_hdr->count; ++ ts_saved = (uint64)ts_data[0]; ++ } ++ memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t)); ++ msg_hdr.timestamp = ts_saved; ++ ++ DHD_DBGIF(("Android Event ver %d, payload %d words, ts %llu\n", ++ (*data >> 16), hdr->count - 1, ts_saved)); ++ ++ /* Perform endian convertion */ ++ for (i = 0; i < hdr->count; i++) { ++ /* *(data + i) = ntoh32(*(data + i)); */ ++ DHD_DATA(("%08x ", *(data + i))); ++ } ++ DHD_DATA(("\n")); ++ msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP; ++ msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_BINARY; ++ msg_hdr.type = DBG_RING_ENTRY_EVENT_TYPE; ++ ++ /* convert the data to log_conn_event_t format */ ++ for (i = 0; i < ARRAYSIZE(event_map); i++) { ++ if (event_map[i].fw_id == wl_log_id.event) { ++ evt_match = TRUE; ++ match_idx = i; ++ break; ++ } ++ } ++ if (evt_match) { ++ log_level = dhdp->dbg->dbg_rings[FW_EVENT_RING_ID].log_level; ++ /* filter the data based on log_level */ ++ for (i = 0; i < ARRAYSIZE(fw_event_level_map); i++) { ++ if ((fw_event_level_map[i].tag == hdr->tag) && ++ (fw_event_level_map[i].log_level > log_level)) { ++ return BCME_OK; ++ } ++ } ++ DHD_DBGIF(("%s : event (%s)\n", __FUNCTION__, event_map[match_idx].desc)); ++ /* get the payload length for event data (skip : log header + timestamp) */ ++ payload_len = sizeof(log_conn_event_t) + DATA_UNIT_FOR_LOG_CNT * (hdr->count - 2); ++ event_data = MALLOC(dhdp->osh, payload_len); ++ if (!event_data) { ++ DHD_ERROR(("failed to allocate the log_conn_event_t with length(%d)\n", ++ payload_len)); ++ return BCME_NOMEM; ++ } ++ event_data->event = event_map[match_idx].host_id; ++ dest_tlvs = (char *)event_data->tlvs; ++ tot_payload_len = sizeof(log_conn_event_t); ++ tlvs = (char *)(&data[1]); ++ tlv_len = (hdr->count - 2) * DATA_UNIT_FOR_LOG_CNT; ++ for (i = 0; i < ARRAYSIZE(event_tag_map); i++) { ++ tlv_data = (tlv_log *)event_get_tlv(event_tag_map[i].fw_id, ++ tlvs, tlv_len); ++ if (tlv_data) { ++ DHD_DBGIF(("tlv.tag(%s), tlv.len : %d, tlv.data : ", ++ event_tag_map[i].desc, tlv_data->len)); ++ memcpy(dest_tlvs, tlv_data, sizeof(tlv_log) + tlv_data->len); ++ tot_payload_len += tlv_data->len + sizeof(tlv_log); ++ switch (tlv_data->tag) { ++ case TRACE_TAG_BSSID: ++ case TRACE_TAG_ADDR: ++ case TRACE_TAG_ADDR1: ++ case TRACE_TAG_ADDR2: ++ case TRACE_TAG_ADDR3: ++ case TRACE_TAG_ADDR4: ++ DHD_DBGIF(("%s\n", ++ bcm_ether_ntoa((const struct ether_addr *)tlv_data->value, ++ eabuf))); ++ break; ++ case TRACE_TAG_SSID: ++ DHD_DBGIF(("%s\n", tlv_data->value)); ++ break; ++ case TRACE_TAG_STATUS: ++ DHD_DBGIF(("%d\n", ltoh32_ua(&tlv_data->value[0]))); ++ break; ++ case TRACE_TAG_REASON_CODE: ++ DHD_DBGIF(("%d\n", ltoh16_ua(&tlv_data->value[0]))); ++ break; ++ case TRACE_TAG_RATE_MBPS: ++ DHD_DBGIF(("%d Kbps\n", ++ ltoh16_ua(&tlv_data->value[0]) * 500)); ++ break; ++ case TRACE_TAG_CHANNEL_SPEC: ++ DHD_DBGIF(("%s\n", ++ wf_chspec_ntoa( ++ ltoh16_ua(&tlv_data->value[0]), chanbuf))); ++ break; ++ default: ++ if (DHD_DBGIF_ON()) { ++ prhex(NULL, &tlv_data->value[0], tlv_data->len); ++ } ++ } ++ dest_tlvs += tlv_data->len + sizeof(tlv_log); ++ } ++ } ++ msg_hdr.len = tot_payload_len; ++ dhd_dbg_ring_push(dhdp, FW_EVENT_RING_ID, &msg_hdr, event_data); ++ MFREE(dhdp->osh, event_data, payload_len); ++ } ++ return ret; ++} ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ ++/* To identify format of types %Ns where N >= 0 is a number */ ++bool ++check_valid_string_format(char *curr_ptr) ++{ ++ char *next_ptr; ++ if ((next_ptr = bcmstrstr(curr_ptr, "s")) != NULL) { ++ /* Default %s format */ ++ if (curr_ptr == next_ptr) { ++ return TRUE; ++ } ++ ++ /* Verify each charater between '%' and 's' is a valid number */ ++ while (curr_ptr < next_ptr) { ++ if (bcm_isdigit(*curr_ptr) == FALSE) { ++ return FALSE; ++ } ++ curr_ptr++; ++ } ++ ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++#define MAX_NO_OF_ARG 16 ++#define FMTSTR_SIZE 132 ++#define ROMSTR_SIZE 200 ++#define SIZE_LOC_STR 50 ++static uint64 verboselog_ts_saved = 0; ++static void ++dhd_dbg_verboselog_handler(dhd_pub_t *dhdp, event_log_hdr_t *hdr, ++ void *raw_event_ptr) ++{ ++ event_log_hdr_t *ts_hdr; ++ uint32 *log_ptr = (uint32 *)hdr - hdr->count; ++ char fmtstr_loc_buf[ROMSTR_SIZE] = { 0 }; ++ uint32 rom_str_len = 0; ++ uint32 *ts_data; ++ ++ if (!raw_event_ptr) { ++ return; ++ } ++ ++ /* Get time stamp if it's updated */ ++ ts_hdr = (event_log_hdr_t *)((char *)log_ptr - sizeof(event_log_hdr_t)); ++ if (ts_hdr->tag == EVENT_LOG_TAG_TS) { ++ ts_data = (uint32 *)ts_hdr - ts_hdr->count; ++ verboselog_ts_saved = (uint64)ts_data[0]; ++ DHD_MSGTRACE_LOG(("EVENT_LOG_TS[0x%08x]: SYS:%08x CPU:%08x\n", ++ ts_data[ts_hdr->count - 1], ts_data[0], ts_data[1])); ++ } ++ ++ if (hdr->tag == EVENT_LOG_TAG_ROM_PRINTF) { ++ rom_str_len = (hdr->count - 1) * sizeof(uint32); ++ if (rom_str_len >= (ROMSTR_SIZE -1)) ++ rom_str_len = ROMSTR_SIZE - 1; ++ ++ /* copy all ascii data for ROM printf to local string */ ++ memcpy(fmtstr_loc_buf, log_ptr, rom_str_len); ++ /* add end of line at last */ ++ fmtstr_loc_buf[rom_str_len] = '\0'; ++ ++ DHD_MSGTRACE_LOG(("EVENT_LOG_ROM[0x%08x]: %s", ++ log_ptr[hdr->count - 1], fmtstr_loc_buf)); ++ ++ /* Add newline if missing */ ++ if (fmtstr_loc_buf[strlen(fmtstr_loc_buf) - 1] != '\n') ++ DHD_MSGTRACE_LOG(("\n")); ++ ++ return; ++ } ++ ++ if (hdr->tag == EVENT_LOG_TAG_MSCHPROFILE || hdr->tag == EVENT_LOG_TAG_MSCHPROFILE_TLV) { ++ wl_mschdbg_verboselog_handler(dhdp, raw_event_ptr, hdr->tag, log_ptr); ++ return; ++ } ++ ++ /* print the message out in a logprint */ ++ dhd_dbg_verboselog_printf(dhdp, hdr, raw_event_ptr, log_ptr); ++} ++ ++void ++dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, event_log_hdr_t *hdr, ++ void *raw_event_ptr, uint32 *log_ptr) ++{ ++ dhd_event_log_t *raw_event = (dhd_event_log_t *)raw_event_ptr; ++ uint16 count; ++ int log_level, id; ++ char fmtstr_loc_buf[ROMSTR_SIZE] = { 0 }; ++ char (*str_buf)[SIZE_LOC_STR] = NULL; ++ char *str_tmpptr = NULL; ++ uint32 addr = 0; ++ typedef union { ++ uint32 val; ++ char * addr; ++ } u_arg; ++ u_arg arg[MAX_NO_OF_ARG] = {{0}}; ++ char *c_ptr = NULL; ++ ++ BCM_REFERENCE(arg); ++ ++ if (!raw_event) { ++ return; ++ } ++ ++ /* print the message out in a logprint */ ++ if (!(raw_event->fmts) || hdr->fmt_num == 0xffff) { ++ if (dhdp->dbg) { ++ log_level = dhdp->dbg->dbg_rings[FW_VERBOSE_RING_ID].log_level; ++ for (id = 0; id < ARRAYSIZE(fw_verbose_level_map); id++) { ++ if ((fw_verbose_level_map[id].tag == hdr->tag) && ++ (fw_verbose_level_map[id].log_level > log_level)) ++ return; ++ } ++ } ++ ++ DHD_EVENT(("%d.%d EL:tag=%d len=%d fmt=0x%x", ++ (uint32)verboselog_ts_saved / 1000, ++ (uint32)verboselog_ts_saved % 1000, ++ hdr->tag, ++ hdr->count, ++ hdr->fmt_num)); ++ ++ for (count = 0; count < (hdr->count-1); count++) { ++ if (count % 8 == 0) ++ DHD_EVENT(("\n\t%08x", log_ptr[count])); ++ else ++ DHD_EVENT((" %08x", log_ptr[count])); ++ } ++ DHD_EVENT(("\n")); ++ ++ return; ++ } ++ ++ str_buf = MALLOCZ(dhdp->osh, (MAX_NO_OF_ARG * SIZE_LOC_STR)); ++ if (!str_buf) { ++ DHD_ERROR(("%s: malloc failed str_buf\n", __FUNCTION__)); ++ return; ++ } ++ ++ if ((hdr->fmt_num >> 2) < raw_event->num_fmts) { ++ if (hdr->tag == EVENT_LOG_TAG_MSCHPROFILE) { ++ snprintf(fmtstr_loc_buf, FMTSTR_SIZE, "%s", ++ raw_event->fmts[hdr->fmt_num >> 2]); ++ hdr->count++; ++ } else { ++ snprintf(fmtstr_loc_buf, FMTSTR_SIZE, "CONSOLE_E: %6d.%3d %s", ++ log_ptr[hdr->count-1]/1000, (log_ptr[hdr->count - 1] % 1000), ++ raw_event->fmts[hdr->fmt_num >> 2]); ++ } ++ c_ptr = fmtstr_loc_buf; ++ } else { ++ DHD_ERROR(("%s: fmt number out of range \n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ for (count = 0; count < (hdr->count - 1); count++) { ++ if (c_ptr != NULL) ++ if ((c_ptr = bcmstrstr(c_ptr, "%")) != NULL) ++ c_ptr++; ++ ++ if (c_ptr != NULL) { ++ if (check_valid_string_format(c_ptr)) { ++ if ((raw_event->raw_sstr) && ++ ((log_ptr[count] > raw_event->rodata_start) && ++ (log_ptr[count] < raw_event->rodata_end))) { ++ /* ram static string */ ++ addr = log_ptr[count] - raw_event->rodata_start; ++ str_tmpptr = raw_event->raw_sstr + addr; ++ memcpy(str_buf[count], str_tmpptr, ++ SIZE_LOC_STR); ++ str_buf[count][SIZE_LOC_STR-1] = '\0'; ++ arg[count].addr = str_buf[count]; ++ } else if ((raw_event->rom_raw_sstr) && ++ ((log_ptr[count] > ++ raw_event->rom_rodata_start) && ++ (log_ptr[count] < ++ raw_event->rom_rodata_end))) { ++ /* rom static string */ ++ addr = log_ptr[count] - raw_event->rom_rodata_start; ++ str_tmpptr = raw_event->rom_raw_sstr + addr; ++ memcpy(str_buf[count], str_tmpptr, ++ SIZE_LOC_STR); ++ str_buf[count][SIZE_LOC_STR-1] = '\0'; ++ arg[count].addr = str_buf[count]; ++ } else { ++ /* ++ * Dynamic string OR ++ * No data for static string. ++ * So store all string's address as string. ++ */ ++ snprintf(str_buf[count], SIZE_LOC_STR, ++ "(s)0x%x", log_ptr[count]); ++ arg[count].addr = str_buf[count]; ++ } ++ } else { ++ /* Other than string */ ++ arg[count].val = log_ptr[count]; ++ } ++ } ++ } ++ ++ /* Print FW logs */ ++ DHD_FWLOG((fmtstr_loc_buf, arg[0], arg[1], arg[2], arg[3], ++ arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], ++ arg[11], arg[12], arg[13], arg[14], arg[15])); ++ ++exit: ++ MFREE(dhdp->osh, str_buf, (MAX_NO_OF_ARG * SIZE_LOC_STR)); ++} ++ ++static void ++dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, ++ void *raw_event_ptr, uint datalen) ++{ ++ msgtrace_hdr_t *hdr; ++ char *data; ++ int id; ++ uint32 log_hdr_len = sizeof(event_log_hdr_t); ++ uint32 log_pyld_len; ++ static uint32 seqnum_prev = 0; ++ event_log_hdr_t *log_hdr; ++ bool msg_processed = FALSE; ++ uint32 *log_ptr = NULL; ++ dll_t list_head, *cur; ++ loglist_item_t *log_item; ++ int32 nan_evt_ring_log_level = 0; ++ dhd_dbg_ring_entry_t msg_hdr; ++ char *logbuf; ++ struct tracelog_header *logentry_header; ++ ++ /* log trace event consists of: ++ * msgtrace header ++ * event log block header ++ * event log payload ++ */ ++ if (datalen <= MSGTRACE_HDRLEN + EVENT_LOG_BLOCK_HDRLEN) { ++ return; ++ } ++ hdr = (msgtrace_hdr_t *)event_data; ++ data = (char *)event_data + MSGTRACE_HDRLEN; ++ datalen -= MSGTRACE_HDRLEN; ++ ++ if (dhd_dbg_msgtrace_seqchk(&seqnum_prev, ntoh32(hdr->seqnum))) ++ return; ++ ++ /* Save the whole message to event log ring */ ++ memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t)); ++ logbuf = VMALLOC(dhdp->osh, sizeof(*logentry_header) + datalen); ++ if (logbuf == NULL) ++ return; ++ logentry_header = (struct tracelog_header *)logbuf; ++ logentry_header->magic_num = TRACE_LOG_MAGIC_NUMBER; ++ logentry_header->buf_size = datalen; ++ logentry_header->seq_num = hdr->seqnum; ++ msg_hdr.type = DBG_RING_ENTRY_DATA_TYPE; ++ ++ if ((sizeof(*logentry_header) + datalen) > PAYLOAD_MAX_LEN) { ++ DHD_ERROR(("%s:Payload len=%u exceeds max len\n", __FUNCTION__, ++ ((uint)sizeof(*logentry_header) + datalen))); ++ VMFREE(dhdp->osh, logbuf, sizeof(*logentry_header) + datalen); ++ return; ++ } ++ ++ msg_hdr.len = sizeof(*logentry_header) + datalen; ++ memcpy(logbuf + sizeof(*logentry_header), data, datalen); ++ dhd_dbg_ring_push(dhdp, FW_VERBOSE_RING_ID, &msg_hdr, logbuf); ++ VMFREE(dhdp->osh, logbuf, sizeof(*logentry_header) + datalen); ++ ++ /* Print sequence number, originating set and length of received ++ * event log buffer. Refer to event log buffer structure in ++ * event_log.h ++ */ ++ DHD_MSGTRACE_LOG(("EVENT_LOG_HDR[0x%x]: Set: 0x%08x length = %d\n", ++ ltoh16(*((uint16 *)(data+2))), ltoh32(*((uint32 *)(data + 4))), ++ ltoh16(*((uint16 *)(data))))); ++ data += EVENT_LOG_BLOCK_HDRLEN; ++ datalen -= EVENT_LOG_BLOCK_HDRLEN; ++ ++ /* start parsing from the tail of packet ++ * Sameple format of a meessage ++ * 001d3c54 00000064 00000064 001d3c54 001dba08 035d6ce1 0c540639 ++ * 001d3c54 00000064 00000064 035d6d89 0c580439 ++ * 0x0c580439 -- 39 is tag, 04 is count, 580c is format number ++ * all these uint32 values comes in reverse order as group as EL data ++ * while decoding we can only parse from last to first ++ * |<- datalen ->| ++ * |----(payload and maybe more logs)----|event_log_hdr_t| ++ * data log_hdr ++ */ ++ dll_init(&list_head); ++ while (datalen > log_hdr_len) { ++ log_hdr = (event_log_hdr_t *)(data + datalen - log_hdr_len); ++ /* skip zero padding at end of frame */ ++ if (log_hdr->tag == EVENT_LOG_TAG_NULL) { ++ datalen -= log_hdr_len; ++ continue; ++ } ++ /* Check argument count, any event log should contain at least ++ * one argument (4 bytes) for arm cycle count and up to 16 ++ * arguments when the format is valid ++ */ ++ if (log_hdr->count == 0) { ++ break; ++ } ++ if ((log_hdr->count > MAX_NO_OF_ARG) && (log_hdr->fmt_num != 0xffff)) { ++ break; ++ } ++ ++ log_pyld_len = log_hdr->count * DATA_UNIT_FOR_LOG_CNT; ++ /* log data should not cross the event data boundary */ ++ if ((char *)log_hdr - data < log_pyld_len) ++ break; ++ /* skip 4 bytes time stamp packet */ ++ if (log_hdr->tag == EVENT_LOG_TAG_TS) { ++ datalen -= log_pyld_len + log_hdr_len; ++ continue; ++ } ++ if (!(log_item = MALLOC(dhdp->osh, sizeof(*log_item)))) { ++ DHD_ERROR(("%s allocating log list item failed\n", ++ __FUNCTION__)); ++ break; ++ } ++ log_item->hdr = log_hdr; ++ dll_insert(&log_item->list, &list_head); ++ datalen -= (log_pyld_len + log_hdr_len); ++ } ++ ++ while (!dll_empty(&list_head)) { ++ msg_processed = FALSE; ++ cur = dll_head_p(&list_head); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ log_item = (loglist_item_t *)container_of(cur, loglist_item_t, list); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ log_hdr = log_item->hdr; ++ log_ptr = (uint32 *)log_hdr - log_hdr->count; ++ dll_delete(cur); ++ MFREE(dhdp->osh, log_item, sizeof(*log_item)); ++ ++ /* Before DHD debugability is implemented WLC_E_TRACE had been ++ * used to carry verbose logging from firmware. We need to ++ * be able to handle those messages even without a initialized ++ * debug layer. ++ */ ++ if (dhdp->dbg) { ++ /* check the data for NAN event ring; keeping first as small table */ ++ /* process only user configured to log */ ++ nan_evt_ring_log_level = dhdp->dbg->dbg_rings[NAN_EVENT_RING_ID].log_level; ++ if (dhdp->dbg->dbg_rings[NAN_EVENT_RING_ID].log_level) { ++ for (id = 0; id < ARRAYSIZE(nan_event_level_map); id++) { ++ if (nan_event_level_map[id].tag == log_hdr->tag) { ++ /* dont process if tag log level is greater ++ * than ring log level ++ */ ++ if (nan_event_level_map[id].log_level > ++ nan_evt_ring_log_level) { ++ msg_processed = TRUE; ++ break; ++ } ++ /* In case of BCME_VERSION error, ++ * this is not NAN event type data ++ */ ++ if (dhd_dbg_nan_event_handler(dhdp, ++ log_hdr, log_ptr) != BCME_VERSION) { ++ msg_processed = TRUE; ++ } ++ break; ++ } ++ } ++ } ++ if (!msg_processed) { ++ /* check the data for event ring */ ++ for (id = 0; id < ARRAYSIZE(fw_event_level_map); id++) { ++ if (fw_event_level_map[id].tag == log_hdr->tag) { ++ /* In case of BCME_VERSION error, ++ * this is not event type data ++ */ ++ if (dhd_dbg_custom_evnt_handler(dhdp, ++ log_hdr, log_ptr) != BCME_VERSION) { ++ msg_processed = TRUE; ++ } ++ break; ++ } ++ } ++ } ++ } ++ if (!msg_processed) ++ dhd_dbg_verboselog_handler(dhdp, log_hdr, raw_event_ptr); ++ ++ } ++} ++#else /* !SHOW_LOGTRACE */ ++static INLINE void dhd_dbg_verboselog_handler(dhd_pub_t *dhdp, ++ event_log_hdr_t *hdr, void *raw_event_ptr) {}; ++static INLINE void dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, ++ void *event_data, void *raw_event_ptr, uint datalen) {}; ++#endif /* SHOW_LOGTRACE */ ++#ifndef MACOSX_DHD ++void ++dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data, ++ void *raw_event_ptr, uint datalen) ++{ ++ msgtrace_hdr_t *hdr; ++ ++ hdr = (msgtrace_hdr_t *)event_data; ++ ++ if (hdr->version != MSGTRACE_VERSION) { ++ DHD_DBGIF(("%s unsupported MSGTRACE version, dhd %d, dongle %d\n", ++ __FUNCTION__, MSGTRACE_VERSION, hdr->version)); ++ return; ++ } ++ ++ if (hdr->trace_type == MSGTRACE_HDR_TYPE_MSG) ++ dhd_dbg_msgtrace_msg_parser(event_data); ++ else if (hdr->trace_type == MSGTRACE_HDR_TYPE_LOG) ++ dhd_dbg_msgtrace_log_parser(dhdp, event_data, raw_event_ptr, datalen); ++} ++#endif /* MACOSX_DHD */ ++static int ++dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name, ++ uint32 ring_sz, int section) ++{ ++ void *buf; ++ unsigned long flags; ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ buf = DHD_OS_PREALLOC(dhdp, section, ring_sz); ++#else ++ buf = MALLOCZ(dhdp->osh, ring_sz); ++#endif ++ if (!buf) ++ return BCME_NOMEM; ++ ++ ring->lock = dhd_os_spin_lock_init(dhdp->osh); ++ ++ flags = dhd_os_spin_lock(ring->lock); ++ ring->id = id; ++ strncpy(ring->name, name, DBGRING_NAME_MAX); ++ ring->name[DBGRING_NAME_MAX - 1] = 0; ++ ring->ring_size = ring_sz; ++ ring->wp = ring->rp = 0; ++ ring->ring_buf = buf; ++ ring->threshold = DBGRING_FLUSH_THRESHOLD(ring); ++ ring->state = RING_SUSPEND; ++ ring->sched_pull = TRUE; ++ ring->rem_len = 0; ++ dhd_os_spin_unlock(ring->lock, flags); ++ ++ return BCME_OK; ++} ++ ++static void ++dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring) ++{ ++ void *buf; ++ uint32 ring_sz; ++ unsigned long flags; ++ ++ if (!ring->ring_buf) ++ return; ++ ++ flags = dhd_os_spin_lock(ring->lock); ++ ring->id = 0; ++ ring->name[0] = 0; ++ ring_sz = ring->ring_size; ++ ring->ring_size = 0; ++ ring->wp = ring->rp = 0; ++ buf = ring->ring_buf; ++ ring->ring_buf = NULL; ++ memset(&ring->stat, 0, sizeof(ring->stat)); ++ ring->threshold = 0; ++ ring->state = RING_STOP; ++ dhd_os_spin_unlock(ring->lock, flags); ++ ++ dhd_os_spin_lock_deinit(dhdp->osh, ring->lock); ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(dhdp->osh, buf, ring_sz); ++#endif ++} ++ ++uint8 ++dhd_dbg_find_sets_by_tag(uint16 tag) ++{ ++ uint i; ++ uint8 sets = 0; ++ ++ for (i = 0; i < ARRAYSIZE(fw_verbose_level_map); i++) { ++ if (fw_verbose_level_map[i].tag == tag) { ++ sets |= fw_verbose_level_map[i].sets; ++ } ++ } ++ ++ for (i = 0; i < ARRAYSIZE(fw_event_level_map); i++) { ++ if (fw_event_level_map[i].tag == tag) { ++ sets |= fw_event_level_map[i].sets; ++ } ++ } ++ ++ return sets; ++} ++ ++/* ++ * dhd_dbg_set_event_log_tag : modify the state of an event log tag ++ */ ++void ++dhd_dbg_set_event_log_tag(dhd_pub_t *dhdp, uint16 tag, uint8 set) ++{ ++ wl_el_tag_params_t pars; ++ char *cmd = "event_log_tag_control"; ++ char iovbuf[WLC_IOCTL_SMLEN] = { 0 }; ++ int ret; ++ ++ memset(&pars, 0, sizeof(pars)); ++ pars.tag = tag; ++ pars.set = dhd_dbg_find_sets_by_tag(tag); ++ pars.flags = set ? EVENT_LOG_TAG_FLAG_LOG : EVENT_LOG_TAG_FLAG_NONE; ++ ++ if (!bcm_mkiovar(cmd, (char *)&pars, sizeof(pars), iovbuf, sizeof(iovbuf))) { ++ DHD_ERROR(("%s mkiovar failed\n", __FUNCTION__)); ++ return; ++ } ++ ++ ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ if (ret) { ++ DHD_ERROR(("%s set log tag iovar failed %d\n", __FUNCTION__, ret)); ++ } ++} ++ ++int ++dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id, int log_level, int flags, uint32 threshold) ++{ ++ dhd_dbg_ring_t *ring; ++ uint8 set = 1; ++ unsigned long lock_flags; ++ int i, array_len = 0; ++ struct log_level_table *log_level_tbl = NULL; ++ if (!dhdp || !dhdp->dbg) ++ return BCME_BADADDR; ++ ++ ring = &dhdp->dbg->dbg_rings[ring_id]; ++ ++ if (ring->state == RING_STOP) ++ return BCME_UNSUPPORTED; ++ ++ lock_flags = dhd_os_spin_lock(ring->lock); ++ if (log_level == 0) ++ ring->state = RING_SUSPEND; ++ else ++ ring->state = RING_ACTIVE; ++ ring->log_level = log_level; ++ ++ ring->threshold = MIN(threshold, DBGRING_FLUSH_THRESHOLD(ring)); ++ dhd_os_spin_unlock(ring->lock, lock_flags); ++ if (log_level > 0) ++ set = TRUE; ++ ++ if (ring->id == FW_EVENT_RING_ID) { ++ log_level_tbl = fw_event_level_map; ++ array_len = ARRAYSIZE(fw_event_level_map); ++ } else if (ring->id == FW_VERBOSE_RING_ID) { ++ log_level_tbl = fw_verbose_level_map; ++ array_len = ARRAYSIZE(fw_verbose_level_map); ++ } else if (ring->id == NAN_EVENT_RING_ID) { ++ log_level_tbl = nan_event_level_map; ++ array_len = ARRAYSIZE(nan_event_level_map); ++ } ++ ++ for (i = 0; i < array_len; i++) { ++ if (log_level == 0 || (log_level_tbl[i].log_level > log_level)) { ++ /* clear the reference per ring */ ++ ref_tag_tbl[log_level_tbl[i].tag] &= ~(1 << ring_id); ++ } else { ++ /* set the reference per ring */ ++ ref_tag_tbl[log_level_tbl[i].tag] |= (1 << ring_id); ++ } ++ set = (ref_tag_tbl[log_level_tbl[i].tag])? 1 : 0; ++ DHD_DBGIF(("%s TAG(%s) is %s for the ring(%s)\n", __FUNCTION__, ++ log_level_tbl[i].desc, (set)? "SET" : "CLEAR", ring->name)); ++ dhd_dbg_set_event_log_tag(dhdp, log_level_tbl[i].tag, set); ++ } ++ return BCME_OK; ++} ++ ++/* ++* dhd_dbg_get_ring_status : get the ring status from the coresponding ring buffer ++* Return: An error code or 0 on success. ++*/ ++ ++int ++dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_status_t *dbg_ring_status) ++{ ++ int ret = BCME_OK; ++ int id = 0; ++ dhd_dbg_t *dbg; ++ dhd_dbg_ring_t *dbg_ring; ++ dhd_dbg_ring_status_t ring_status; ++ if (!dhdp || !dhdp->dbg) ++ return BCME_BADADDR; ++ dbg = dhdp->dbg; ++ ++ memset(&ring_status, 0, sizeof(dhd_dbg_ring_status_t)); ++ for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) { ++ dbg_ring = &dbg->dbg_rings[id]; ++ if (VALID_RING(dbg_ring->id) && (dbg_ring->id == ring_id)) { ++ RING_STAT_TO_STATUS(dbg_ring, ring_status); ++ *dbg_ring_status = ring_status; ++ break; ++ } ++ } ++ if (!VALID_RING(id)) { ++ DHD_ERROR(("%s : cannot find the ring_id : %d\n", __FUNCTION__, ring_id)); ++ ret = BCME_NOTFOUND; ++ } ++ return ret; ++} ++ ++/* ++* dhd_dbg_find_ring_id : return ring_id based on ring_name ++* Return: An invalid ring id for failure or valid ring id on success. ++*/ ++ ++int ++dhd_dbg_find_ring_id(dhd_pub_t *dhdp, char *ring_name) ++{ ++ int id; ++ dhd_dbg_t *dbg; ++ dhd_dbg_ring_t *ring; ++ ++ if (!dhdp || !dhdp->dbg) ++ return BCME_BADADDR; ++ ++ dbg = dhdp->dbg; ++ for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) { ++ ring = &dbg->dbg_rings[id]; ++ if (!strncmp((char *)ring->name, ring_name, sizeof(ring->name) - 1)) ++ break; ++ } ++ return id; ++} ++ ++/* ++* dhd_dbg_get_priv : get the private data of dhd dbugability module ++* Return : An NULL on failure or valid data address ++*/ ++void * ++dhd_dbg_get_priv(dhd_pub_t *dhdp) ++{ ++ if (!dhdp || !dhdp->dbg) ++ return NULL; ++ return dhdp->dbg->private; ++} ++ ++/* ++* dhd_dbg_start : start and stop All of Ring buffers ++* Return: An error code or 0 on success. ++*/ ++int ++dhd_dbg_start(dhd_pub_t *dhdp, bool start) ++{ ++ int ret = BCME_OK; ++ int ring_id; ++ dhd_dbg_t *dbg; ++ dhd_dbg_ring_t *dbg_ring; ++ if (!dhdp) ++ return BCME_BADARG; ++ dbg = dhdp->dbg; ++ ++ for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { ++ dbg_ring = &dbg->dbg_rings[ring_id]; ++ if (!start) { ++ if (VALID_RING(dbg_ring->id)) { ++ /* Initialize the information for the ring */ ++ dbg_ring->state = RING_SUSPEND; ++ dbg_ring->log_level = 0; ++ dbg_ring->rp = dbg_ring->wp = 0; ++ dbg_ring->threshold = 0; ++ memset(&dbg_ring->stat, 0, sizeof(struct ring_statistics)); ++ memset(dbg_ring->ring_buf, 0, dbg_ring->ring_size); ++ } ++ } ++ } ++ return ret; ++} ++ ++/* ++ * dhd_dbg_send_urgent_evt: send the health check evt to Upper layer ++ * ++ * Return: An error code or 0 on success. ++ */ ++ ++int ++dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len) ++{ ++ dhd_dbg_t *dbg; ++ int ret = BCME_OK; ++ if (!dhdp || !dhdp->dbg) ++ return BCME_BADADDR; ++ ++ dbg = dhdp->dbg; ++ if (dbg->urgent_notifier) { ++ dbg->urgent_notifier(dhdp, data, len); ++ } ++ return ret; ++} ++ ++#if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING) ++uint32 ++__dhd_dbg_pkt_hash(uintptr_t pkt, uint32 pktid) ++{ ++ uint32 __pkt; ++ uint32 __pktid; ++ ++ __pkt = ((int)pkt) >= 0 ? (2 * pkt) : (-2 * pkt - 1); ++ __pktid = ((int)pktid) >= 0 ? (2 * pktid) : (-2 * pktid - 1); ++ ++ return (__pkt >= __pktid ? (__pkt * __pkt + __pkt + __pktid) : ++ (__pkt + __pktid * __pktid)); ++} ++ ++#define __TIMESPEC_TO_US(ts) \ ++ (((uint32)(ts).tv_sec * USEC_PER_SEC) + ((ts).tv_nsec / NSEC_PER_USEC)) ++ ++uint32 ++__dhd_dbg_driver_ts_usec(void) ++{ ++ struct osl_timespec ts; ++ ++ osl_get_monotonic_boottime(&ts); ++ return ((uint32)(__TIMESPEC_TO_US(ts))); ++} ++ ++wifi_tx_packet_fate ++__dhd_dbg_map_tx_status_to_pkt_fate(uint16 status) ++{ ++ wifi_tx_packet_fate pkt_fate; ++ ++ switch (status) { ++ case WLFC_CTL_PKTFLAG_DISCARD: ++ pkt_fate = TX_PKT_FATE_ACKED; ++ break; ++ case WLFC_CTL_PKTFLAG_D11SUPPRESS: ++ /* intensional fall through */ ++ case WLFC_CTL_PKTFLAG_WLSUPPRESS: ++ pkt_fate = TX_PKT_FATE_FW_QUEUED; ++ break; ++ case WLFC_CTL_PKTFLAG_TOSSED_BYWLC: ++ pkt_fate = TX_PKT_FATE_FW_DROP_INVALID; ++ break; ++ case WLFC_CTL_PKTFLAG_DISCARD_NOACK: ++ pkt_fate = TX_PKT_FATE_SENT; ++ break; ++ default: ++ pkt_fate = TX_PKT_FATE_FW_DROP_OTHER; ++ break; ++ } ++ ++ return pkt_fate; ++} ++#endif /* DBG_PKT_MON || DHD_PKT_LOGGING */ ++ ++#ifdef DBG_PKT_MON ++static int ++__dhd_dbg_free_tx_pkts(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkts, ++ uint16 pkt_count) ++{ ++ uint16 count; ++ ++ DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); ++ count = 0; ++ while ((count < pkt_count) && tx_pkts) { ++ if (tx_pkts->info.pkt) ++ PKTFREE(dhdp->osh, tx_pkts->info.pkt, TRUE); ++ tx_pkts++; ++ count++; ++ } ++ ++ return BCME_OK; ++} ++ ++static int ++__dhd_dbg_free_rx_pkts(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkts, ++ uint16 pkt_count) ++{ ++ uint16 count; ++ ++ DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); ++ count = 0; ++ while ((count < pkt_count) && rx_pkts) { ++ if (rx_pkts->info.pkt) ++ PKTFREE(dhdp->osh, rx_pkts->info.pkt, TRUE); ++ rx_pkts++; ++ count++; ++ } ++ ++ return BCME_OK; ++} ++ ++void ++__dhd_dbg_dump_pkt_info(dhd_pub_t *dhdp, dhd_dbg_pkt_info_t *info) ++{ ++ if (DHD_PKT_MON_DUMP_ON()) { ++ DHD_PKT_MON(("payload type = %d\n", info->payload_type)); ++ DHD_PKT_MON(("driver ts = %u\n", info->driver_ts)); ++ DHD_PKT_MON(("firmware ts = %u\n", info->firmware_ts)); ++ DHD_PKT_MON(("packet hash = %u\n", info->pkt_hash)); ++ DHD_PKT_MON(("packet length = %zu\n", info->pkt_len)); ++ DHD_PKT_MON(("packet address = %p\n", info->pkt)); ++ DHD_PKT_MON(("packet data = \n")); ++ if (DHD_PKT_MON_ON()) { ++ prhex(NULL, PKTDATA(dhdp->osh, info->pkt), info->pkt_len); ++ } ++ } ++} ++ ++void ++__dhd_dbg_dump_tx_pkt_info(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkt, ++ uint16 count) ++{ ++ if (DHD_PKT_MON_DUMP_ON()) { ++ DHD_PKT_MON(("\nTX (count: %d)\n", ++count)); ++ DHD_PKT_MON(("packet fate = %d\n", tx_pkt->fate)); ++ __dhd_dbg_dump_pkt_info(dhdp, &tx_pkt->info); ++ } ++} ++ ++void ++__dhd_dbg_dump_rx_pkt_info(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkt, ++ uint16 count) ++{ ++ if (DHD_PKT_MON_DUMP_ON()) { ++ DHD_PKT_MON(("\nRX (count: %d)\n", ++count)); ++ DHD_PKT_MON(("packet fate = %d\n", rx_pkt->fate)); ++ __dhd_dbg_dump_pkt_info(dhdp, &rx_pkt->info); ++ } ++} ++ ++int ++dhd_dbg_attach_pkt_monitor(dhd_pub_t *dhdp, ++ dbg_mon_tx_pkts_t tx_pkt_mon, ++ dbg_mon_tx_status_t tx_status_mon, ++ dbg_mon_rx_pkts_t rx_pkt_mon) ++{ ++ ++ dhd_dbg_tx_report_t *tx_report = NULL; ++ dhd_dbg_rx_report_t *rx_report = NULL; ++ dhd_dbg_tx_info_t *tx_pkts = NULL; ++ dhd_dbg_rx_info_t *rx_pkts = NULL; ++ dhd_dbg_pkt_mon_state_t tx_pkt_state; ++ dhd_dbg_pkt_mon_state_t tx_status_state; ++ dhd_dbg_pkt_mon_state_t rx_pkt_state; ++ gfp_t kflags; ++ uint32 alloc_len; ++ int ret = BCME_OK; ++ unsigned long flags; ++ ++ DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); ++ if (!dhdp || !dhdp->dbg) { ++ DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, ++ dhdp, (dhdp ? dhdp->dbg : NULL))); ++ return -EINVAL; ++ } ++ ++ DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); ++ tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; ++ tx_status_state = dhdp->dbg->pkt_mon.tx_pkt_state; ++ rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; ++ ++ if (PKT_MON_ATTACHED(tx_pkt_state) || PKT_MON_ATTACHED(tx_status_state) || ++ PKT_MON_ATTACHED(rx_pkt_state)) { ++ DHD_PKT_MON(("%s(): packet monitor is already attached, " ++ "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n", ++ __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state)); ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ /* return success as the intention was to initialize packet monitor */ ++ return BCME_OK; ++ } ++ ++ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ ++ /* allocate and initialize tx packet monitoring */ ++ alloc_len = sizeof(*tx_report); ++ tx_report = (dhd_dbg_tx_report_t *)kzalloc(alloc_len, kflags); ++ if (unlikely(!tx_report)) { ++ DHD_ERROR(("%s(): could not allocate memory for - " ++ "dhd_dbg_tx_report_t\n", __FUNCTION__)); ++ ret = -ENOMEM; ++ goto fail; ++ } ++ ++ alloc_len = (sizeof(*tx_pkts) * MAX_FATE_LOG_LEN); ++ tx_pkts = (dhd_dbg_tx_info_t *)kzalloc(alloc_len, kflags); ++ if (unlikely(!tx_pkts)) { ++ DHD_ERROR(("%s(): could not allocate memory for - " ++ "dhd_dbg_tx_info_t\n", __FUNCTION__)); ++ ret = -ENOMEM; ++ goto fail; ++ } ++ dhdp->dbg->pkt_mon.tx_report = tx_report; ++ dhdp->dbg->pkt_mon.tx_report->tx_pkts = tx_pkts; ++ dhdp->dbg->pkt_mon.tx_pkt_mon = tx_pkt_mon; ++ dhdp->dbg->pkt_mon.tx_status_mon = tx_status_mon; ++ dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_ATTACHED; ++ dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_ATTACHED; ++ ++ /* allocate and initialze rx packet monitoring */ ++ alloc_len = sizeof(*rx_report); ++ rx_report = (dhd_dbg_rx_report_t *)kzalloc(alloc_len, kflags); ++ if (unlikely(!rx_report)) { ++ DHD_ERROR(("%s(): could not allocate memory for - " ++ "dhd_dbg_rx_report_t\n", __FUNCTION__)); ++ ret = -ENOMEM; ++ goto fail; ++ } ++ ++ alloc_len = (sizeof(*rx_pkts) * MAX_FATE_LOG_LEN); ++ rx_pkts = (dhd_dbg_rx_info_t *)kzalloc(alloc_len, kflags); ++ if (unlikely(!rx_pkts)) { ++ DHD_ERROR(("%s(): could not allocate memory for - " ++ "dhd_dbg_rx_info_t\n", __FUNCTION__)); ++ ret = -ENOMEM; ++ goto fail; ++ } ++ dhdp->dbg->pkt_mon.rx_report = rx_report; ++ dhdp->dbg->pkt_mon.rx_report->rx_pkts = rx_pkts; ++ dhdp->dbg->pkt_mon.rx_pkt_mon = rx_pkt_mon; ++ dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_ATTACHED; ++ ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ DHD_PKT_MON(("%s(): packet monitor attach succeeded\n", __FUNCTION__)); ++ return ret; ++ ++fail: ++ /* tx packet monitoring */ ++ if (tx_pkts) { ++ kfree(tx_pkts); ++ } ++ if (tx_report) { ++ kfree(tx_report); ++ } ++ dhdp->dbg->pkt_mon.tx_report = NULL; ++ dhdp->dbg->pkt_mon.tx_report->tx_pkts = NULL; ++ dhdp->dbg->pkt_mon.tx_pkt_mon = NULL; ++ dhdp->dbg->pkt_mon.tx_status_mon = NULL; ++ dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_DETACHED; ++ dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_DETACHED; ++ ++ /* rx packet monitoring */ ++ if (rx_pkts) { ++ kfree(rx_pkts); ++ } ++ if (rx_report) { ++ kfree(rx_report); ++ } ++ dhdp->dbg->pkt_mon.rx_report = NULL; ++ dhdp->dbg->pkt_mon.rx_report->rx_pkts = NULL; ++ dhdp->dbg->pkt_mon.rx_pkt_mon = NULL; ++ dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_DETACHED; ++ ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ DHD_ERROR(("%s(): packet monitor attach failed\n", __FUNCTION__)); ++ return ret; ++} ++ ++int ++dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp) ++{ ++ dhd_dbg_tx_report_t *tx_report; ++ dhd_dbg_rx_report_t *rx_report; ++ dhd_dbg_pkt_mon_state_t tx_pkt_state; ++ dhd_dbg_pkt_mon_state_t tx_status_state; ++ dhd_dbg_pkt_mon_state_t rx_pkt_state; ++ unsigned long flags; ++ ++ DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); ++ if (!dhdp || !dhdp->dbg) { ++ DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, ++ dhdp, (dhdp ? dhdp->dbg : NULL))); ++ return -EINVAL; ++ } ++ ++ DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); ++ tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; ++ tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; ++ rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; ++ ++ if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) || ++ PKT_MON_DETACHED(rx_pkt_state)) { ++ DHD_PKT_MON(("%s(): packet monitor is not yet enabled, " ++ "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n", ++ __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state)); ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ return -EINVAL; ++ } ++ ++ dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STARTING; ++ dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STARTING; ++ dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STARTING; ++ ++ tx_report = dhdp->dbg->pkt_mon.tx_report; ++ rx_report = dhdp->dbg->pkt_mon.rx_report; ++ if (!tx_report || !rx_report) { ++ DHD_PKT_MON(("%s(): tx_report=%p, rx_report=%p\n", ++ __FUNCTION__, tx_report, rx_report)); ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ return -EINVAL; ++ } ++ ++ ++ tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; ++ tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; ++ rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; ++ ++ /* Safe to free packets as state pkt_state is STARTING */ ++ __dhd_dbg_free_tx_pkts(dhdp, tx_report->tx_pkts, tx_report->pkt_pos); ++ ++ __dhd_dbg_free_rx_pkts(dhdp, rx_report->rx_pkts, rx_report->pkt_pos); ++ ++ /* reset array postion */ ++ tx_report->pkt_pos = 0; ++ tx_report->status_pos = 0; ++ dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STARTED; ++ dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STARTED; ++ ++ rx_report->pkt_pos = 0; ++ dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STARTED; ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ ++ DHD_PKT_MON(("%s(): packet monitor started\n", __FUNCTION__)); ++ return BCME_OK; ++} ++ ++int ++dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid) ++{ ++ dhd_dbg_tx_report_t *tx_report; ++ dhd_dbg_tx_info_t *tx_pkts; ++ dhd_dbg_pkt_mon_state_t tx_pkt_state; ++ uint32 pkt_hash, driver_ts; ++ uint16 pkt_pos; ++ unsigned long flags; ++ ++ if (!dhdp || !dhdp->dbg) { ++ DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, ++ dhdp, (dhdp ? dhdp->dbg : NULL))); ++ return -EINVAL; ++ } ++ ++ DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); ++ tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; ++ if (PKT_MON_STARTED(tx_pkt_state)) { ++ tx_report = dhdp->dbg->pkt_mon.tx_report; ++ pkt_pos = tx_report->pkt_pos; ++ ++ if (!PKT_MON_PKT_FULL(pkt_pos)) { ++ tx_pkts = tx_report->tx_pkts; ++ pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid); ++ driver_ts = __dhd_dbg_driver_ts_usec(); ++ ++ tx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt); ++ tx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt); ++ tx_pkts[pkt_pos].info.pkt_hash = pkt_hash; ++ tx_pkts[pkt_pos].info.driver_ts = driver_ts; ++ tx_pkts[pkt_pos].info.firmware_ts = 0U; ++ tx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II; ++ tx_pkts[pkt_pos].fate = TX_PKT_FATE_DRV_QUEUED; ++ ++ tx_report->pkt_pos++; ++ } else { ++ dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED; ++ DHD_PKT_MON(("%s(): tx pkt logging stopped, reached " ++ "max limit\n", __FUNCTION__)); ++ } ++ } ++ ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ return BCME_OK; ++} ++ ++int ++dhd_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid, ++ uint16 status) ++{ ++ dhd_dbg_tx_report_t *tx_report; ++ dhd_dbg_tx_info_t *tx_pkt; ++ dhd_dbg_pkt_mon_state_t tx_status_state; ++ wifi_tx_packet_fate pkt_fate; ++ uint32 pkt_hash, temp_hash; ++ uint16 pkt_pos, status_pos; ++ int16 count; ++ bool found = FALSE; ++ unsigned long flags; ++ ++ if (!dhdp || !dhdp->dbg) { ++ DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, ++ dhdp, (dhdp ? dhdp->dbg : NULL))); ++ return -EINVAL; ++ } ++ ++ DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); ++ tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; ++ if (PKT_MON_STARTED(tx_status_state)) { ++ tx_report = dhdp->dbg->pkt_mon.tx_report; ++ pkt_pos = tx_report->pkt_pos; ++ status_pos = tx_report->status_pos; ++ ++ if (!PKT_MON_STATUS_FULL(pkt_pos, status_pos)) { ++ pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid); ++ pkt_fate = __dhd_dbg_map_tx_status_to_pkt_fate(status); ++ ++ /* best bet (in-order tx completion) */ ++ count = status_pos; ++ tx_pkt = (((dhd_dbg_tx_info_t *)tx_report->tx_pkts) + status_pos); ++ while ((count < pkt_pos) && tx_pkt) { ++ temp_hash = tx_pkt->info.pkt_hash; ++ if (temp_hash == pkt_hash) { ++ tx_pkt->fate = pkt_fate; ++ tx_report->status_pos++; ++ found = TRUE; ++ break; ++ } ++ tx_pkt++; ++ count++; ++ } ++ ++ /* search until beginning (handles out-of-order completion) */ ++ if (!found) { ++ count = status_pos - 1; ++ tx_pkt = (((dhd_dbg_tx_info_t *)tx_report->tx_pkts) + count); ++ while ((count >= 0) && tx_pkt) { ++ temp_hash = tx_pkt->info.pkt_hash; ++ if (temp_hash == pkt_hash) { ++ tx_pkt->fate = pkt_fate; ++ tx_report->status_pos++; ++ found = TRUE; ++ break; ++ } ++ tx_pkt--; ++ count--; ++ } ++ ++ if (!found) { ++ /* still couldn't match tx_status */ ++ DHD_ERROR(("%s(): couldn't match tx_status, pkt_pos=%u, " ++ "status_pos=%u, pkt_fate=%u\n", __FUNCTION__, ++ pkt_pos, status_pos, pkt_fate)); ++ } ++ } ++ } else { ++ dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STOPPED; ++ DHD_PKT_MON(("%s(): tx_status logging stopped, reached " ++ "max limit\n", __FUNCTION__)); ++ } ++ } ++ ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ return BCME_OK; ++} ++ ++int ++dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt) ++{ ++ dhd_dbg_rx_report_t *rx_report; ++ dhd_dbg_rx_info_t *rx_pkts; ++ dhd_dbg_pkt_mon_state_t rx_pkt_state; ++ uint32 driver_ts; ++ uint16 pkt_pos; ++ unsigned long flags; ++ ++ if (!dhdp || !dhdp->dbg) { ++ DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, ++ dhdp, (dhdp ? dhdp->dbg : NULL))); ++ return -EINVAL; ++ } ++ ++ DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); ++ rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; ++ if (PKT_MON_STARTED(rx_pkt_state)) { ++ rx_report = dhdp->dbg->pkt_mon.rx_report; ++ pkt_pos = rx_report->pkt_pos; ++ ++ if (!PKT_MON_PKT_FULL(pkt_pos)) { ++ rx_pkts = rx_report->rx_pkts; ++ driver_ts = __dhd_dbg_driver_ts_usec(); ++ ++ rx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt); ++ rx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt); ++ rx_pkts[pkt_pos].info.pkt_hash = 0U; ++ rx_pkts[pkt_pos].info.driver_ts = driver_ts; ++ rx_pkts[pkt_pos].info.firmware_ts = 0U; ++ rx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II; ++ rx_pkts[pkt_pos].fate = RX_PKT_FATE_SUCCESS; ++ ++ rx_report->pkt_pos++; ++ } else { ++ dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED; ++ DHD_PKT_MON(("%s(): rx pkt logging stopped, reached " ++ "max limit\n", __FUNCTION__)); ++ } ++ } ++ ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ return BCME_OK; ++} ++ ++int ++dhd_dbg_stop_pkt_monitor(dhd_pub_t *dhdp) ++{ ++ dhd_dbg_pkt_mon_state_t tx_pkt_state; ++ dhd_dbg_pkt_mon_state_t tx_status_state; ++ dhd_dbg_pkt_mon_state_t rx_pkt_state; ++ unsigned long flags; ++ ++ DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); ++ if (!dhdp || !dhdp->dbg) { ++ DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, ++ dhdp, (dhdp ? dhdp->dbg : NULL))); ++ return -EINVAL; ++ } ++ ++ DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); ++ tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; ++ tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; ++ rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; ++ ++ if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) || ++ PKT_MON_DETACHED(rx_pkt_state)) { ++ DHD_PKT_MON(("%s(): packet monitor is not yet enabled, " ++ "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n", ++ __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state)); ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ return -EINVAL; ++ } ++ dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED; ++ dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STOPPED; ++ dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED; ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ ++ DHD_PKT_MON(("%s(): packet monitor stopped\n", __FUNCTION__)); ++ return BCME_OK; ++} ++ ++#define __COPY_TO_USER(to, from, n) \ ++ do { \ ++ int __ret; \ ++ __ret = copy_to_user((void __user *)(to), (void *)(from), \ ++ (unsigned long)(n)); \ ++ if (unlikely(__ret)) { \ ++ DHD_ERROR(("%s():%d: copy_to_user failed, ret=%d\n", \ ++ __FUNCTION__, __LINE__, __ret)); \ ++ return __ret; \ ++ } \ ++ } while (0); ++ ++int ++dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, ++ uint16 req_count, uint16 *resp_count) ++{ ++ dhd_dbg_tx_report_t *tx_report; ++ dhd_dbg_tx_info_t *tx_pkt; ++ wifi_tx_report_t *ptr; ++ compat_wifi_tx_report_t *cptr; ++ dhd_dbg_pkt_mon_state_t tx_pkt_state; ++ dhd_dbg_pkt_mon_state_t tx_status_state; ++ uint16 pkt_count, count; ++ unsigned long flags; ++ ++ DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); ++ BCM_REFERENCE(ptr); ++ BCM_REFERENCE(cptr); ++ ++ if (!dhdp || !dhdp->dbg) { ++ DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, ++ dhdp, (dhdp ? dhdp->dbg : NULL))); ++ return -EINVAL; ++ } ++ ++ DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); ++ tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; ++ tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; ++ if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state)) { ++ DHD_PKT_MON(("%s(): packet monitor is not yet enabled, " ++ "tx_pkt_state=%d, tx_status_state=%d\n", __FUNCTION__, ++ tx_pkt_state, tx_status_state)); ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ return -EINVAL; ++ } ++ ++ count = 0; ++ tx_report = dhdp->dbg->pkt_mon.tx_report; ++ tx_pkt = tx_report->tx_pkts; ++ pkt_count = MIN(req_count, tx_report->status_pos); ++ ++#ifdef CONFIG_COMPAT ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) ++ if (in_compat_syscall()) ++#else ++ if (is_compat_task()) ++#endif ++ { ++ cptr = (compat_wifi_tx_report_t *)user_buf; ++ while ((count < pkt_count) && tx_pkt && cptr) { ++ compat_wifi_tx_report_t *comp_ptr = compat_ptr((uintptr_t) cptr); ++ compat_dhd_dbg_pkt_info_t compat_tx_pkt; ++ __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count); ++ __COPY_TO_USER(&comp_ptr->fate, &tx_pkt->fate, sizeof(tx_pkt->fate)); ++ ++ compat_tx_pkt.payload_type = tx_pkt->info.payload_type; ++ compat_tx_pkt.pkt_len = tx_pkt->info.pkt_len; ++ compat_tx_pkt.driver_ts = tx_pkt->info.driver_ts; ++ compat_tx_pkt.firmware_ts = tx_pkt->info.firmware_ts; ++ compat_tx_pkt.pkt_hash = tx_pkt->info.pkt_hash; ++ __COPY_TO_USER(&comp_ptr->frame_inf.payload_type, ++ &compat_tx_pkt.payload_type, ++ OFFSETOF(compat_dhd_dbg_pkt_info_t, pkt_hash)); ++ __COPY_TO_USER(comp_ptr->frame_inf.frame_content.ethernet_ii, ++ PKTDATA(dhdp->osh, tx_pkt->info.pkt), tx_pkt->info.pkt_len); ++ ++ cptr++; ++ tx_pkt++; ++ count++; ++ } ++ } else ++#endif /* CONFIG_COMPAT */ ++ ++ { ++ ptr = (wifi_tx_report_t *)user_buf; ++ while ((count < pkt_count) && tx_pkt && ptr) { ++ __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count); ++ __COPY_TO_USER(&ptr->fate, &tx_pkt->fate, sizeof(tx_pkt->fate)); ++ __COPY_TO_USER(&ptr->frame_inf.payload_type, ++ &tx_pkt->info.payload_type, ++ OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash)); ++ __COPY_TO_USER(ptr->frame_inf.frame_content.ethernet_ii, ++ PKTDATA(dhdp->osh, tx_pkt->info.pkt), tx_pkt->info.pkt_len); ++ ++ ptr++; ++ tx_pkt++; ++ count++; ++ } ++ } ++ *resp_count = pkt_count; ++ ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ if (!pkt_count) { ++ DHD_ERROR(("%s(): no tx_status in tx completion messages, " ++ "make sure that 'd11status' is enabled in firmware, " ++ "status_pos=%u\n", __FUNCTION__, pkt_count)); ++ } ++ ++ return BCME_OK; ++} ++ ++int ++dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, ++ uint16 req_count, uint16 *resp_count) ++{ ++ dhd_dbg_rx_report_t *rx_report; ++ dhd_dbg_rx_info_t *rx_pkt; ++ wifi_rx_report_t *ptr; ++ compat_wifi_rx_report_t *cptr; ++ dhd_dbg_pkt_mon_state_t rx_pkt_state; ++ uint16 pkt_count, count; ++ unsigned long flags; ++ ++ DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); ++ BCM_REFERENCE(ptr); ++ BCM_REFERENCE(cptr); ++ ++ if (!dhdp || !dhdp->dbg) { ++ DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, ++ dhdp, (dhdp ? dhdp->dbg : NULL))); ++ return -EINVAL; ++ } ++ ++ DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); ++ rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; ++ if (PKT_MON_DETACHED(rx_pkt_state)) { ++ DHD_PKT_MON(("%s(): packet fetch is not allowed , " ++ "rx_pkt_state=%d\n", __FUNCTION__, rx_pkt_state)); ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ return -EINVAL; ++ } ++ ++ count = 0; ++ rx_report = dhdp->dbg->pkt_mon.rx_report; ++ rx_pkt = rx_report->rx_pkts; ++ pkt_count = MIN(req_count, rx_report->pkt_pos); ++ ++#ifdef CONFIG_COMPAT ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) ++ if (in_compat_syscall()) ++#else ++ if (is_compat_task()) ++#endif ++ { ++ cptr = (compat_wifi_rx_report_t *)user_buf; ++ while ((count < pkt_count) && rx_pkt && cptr) { ++ compat_wifi_rx_report_t *comp_ptr = compat_ptr((uintptr_t) cptr); ++ compat_dhd_dbg_pkt_info_t compat_rx_pkt; ++ __dhd_dbg_dump_rx_pkt_info(dhdp, rx_pkt, count); ++ __COPY_TO_USER(&comp_ptr->fate, &rx_pkt->fate, sizeof(rx_pkt->fate)); ++ ++ compat_rx_pkt.payload_type = rx_pkt->info.payload_type; ++ compat_rx_pkt.pkt_len = rx_pkt->info.pkt_len; ++ compat_rx_pkt.driver_ts = rx_pkt->info.driver_ts; ++ compat_rx_pkt.firmware_ts = rx_pkt->info.firmware_ts; ++ compat_rx_pkt.pkt_hash = rx_pkt->info.pkt_hash; ++ __COPY_TO_USER(&comp_ptr->frame_inf.payload_type, ++ &compat_rx_pkt.payload_type, ++ OFFSETOF(compat_dhd_dbg_pkt_info_t, pkt_hash)); ++ __COPY_TO_USER(comp_ptr->frame_inf.frame_content.ethernet_ii, ++ PKTDATA(dhdp->osh, rx_pkt->info.pkt), rx_pkt->info.pkt_len); ++ ++ cptr++; ++ rx_pkt++; ++ count++; ++ } ++ } else ++#endif /* CONFIG_COMPAT */ ++ { ++ ptr = (wifi_rx_report_t *)user_buf; ++ while ((count < pkt_count) && rx_pkt && ptr) { ++ __dhd_dbg_dump_rx_pkt_info(dhdp, rx_pkt, count); ++ ++ __COPY_TO_USER(&ptr->fate, &rx_pkt->fate, sizeof(rx_pkt->fate)); ++ __COPY_TO_USER(&ptr->frame_inf.payload_type, ++ &rx_pkt->info.payload_type, ++ OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash)); ++ __COPY_TO_USER(ptr->frame_inf.frame_content.ethernet_ii, ++ PKTDATA(dhdp->osh, rx_pkt->info.pkt), rx_pkt->info.pkt_len); ++ ++ ptr++; ++ rx_pkt++; ++ count++; ++ } ++ } ++ ++ *resp_count = pkt_count; ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ ++ return BCME_OK; ++} ++ ++int ++dhd_dbg_detach_pkt_monitor(dhd_pub_t *dhdp) ++{ ++ dhd_dbg_tx_report_t *tx_report; ++ dhd_dbg_rx_report_t *rx_report; ++ dhd_dbg_pkt_mon_state_t tx_pkt_state; ++ dhd_dbg_pkt_mon_state_t tx_status_state; ++ dhd_dbg_pkt_mon_state_t rx_pkt_state; ++ unsigned long flags; ++ ++ DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); ++ if (!dhdp || !dhdp->dbg) { ++ DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, ++ dhdp, (dhdp ? dhdp->dbg : NULL))); ++ return -EINVAL; ++ } ++ ++ DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); ++ tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; ++ tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; ++ rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; ++ ++ if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) || ++ PKT_MON_DETACHED(rx_pkt_state)) { ++ DHD_PKT_MON(("%s(): packet monitor is already detached, " ++ "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n", ++ __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state)); ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ return -EINVAL; ++ } ++ ++ tx_report = dhdp->dbg->pkt_mon.tx_report; ++ rx_report = dhdp->dbg->pkt_mon.rx_report; ++ ++ /* free and de-initalize tx packet monitoring */ ++ dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_DETACHED; ++ dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_DETACHED; ++ if (tx_report) { ++ if (tx_report->tx_pkts) { ++ __dhd_dbg_free_tx_pkts(dhdp, tx_report->tx_pkts, ++ tx_report->pkt_pos); ++ kfree(tx_report->tx_pkts); ++ dhdp->dbg->pkt_mon.tx_report->tx_pkts = NULL; ++ } ++ kfree(tx_report); ++ dhdp->dbg->pkt_mon.tx_report = NULL; ++ } ++ dhdp->dbg->pkt_mon.tx_pkt_mon = NULL; ++ dhdp->dbg->pkt_mon.tx_status_mon = NULL; ++ ++ /* free and de-initalize rx packet monitoring */ ++ dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_DETACHED; ++ if (rx_report) { ++ if (rx_report->rx_pkts) { ++ __dhd_dbg_free_rx_pkts(dhdp, rx_report->rx_pkts, ++ rx_report->pkt_pos); ++ kfree(rx_report->rx_pkts); ++ dhdp->dbg->pkt_mon.rx_report->rx_pkts = NULL; ++ } ++ kfree(rx_report); ++ dhdp->dbg->pkt_mon.rx_report = NULL; ++ } ++ dhdp->dbg->pkt_mon.rx_pkt_mon = NULL; ++ ++ DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); ++ DHD_PKT_MON(("%s(): packet monitor detach succeeded\n", __FUNCTION__)); ++ return BCME_OK; ++} ++#endif /* DBG_PKT_MON */ ++ ++/* ++ * dhd_dbg_attach: initialziation of dhd dbugability module ++ * ++ * Return: An error code or 0 on success. ++ */ ++int ++dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq, ++ dbg_urgent_noti_t os_urgent_notifier, void *os_priv) ++{ ++ dhd_dbg_t *dbg; ++ int ret, ring_id; ++ ++ dbg = MALLOCZ(dhdp->osh, sizeof(dhd_dbg_t)); ++ if (!dbg) ++ return BCME_NOMEM; ++ ++ ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_VERBOSE_RING_ID], FW_VERBOSE_RING_ID, ++ (uint8 *)FW_VERBOSE_RING_NAME, FW_VERBOSE_RING_SIZE, DHD_PREALLOC_FW_VERBOSE_RING); ++ if (ret) ++ goto error; ++ ++ ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_EVENT_RING_ID], FW_EVENT_RING_ID, ++ (uint8 *)FW_EVENT_RING_NAME, FW_EVENT_RING_SIZE, DHD_PREALLOC_FW_EVENT_RING); ++ if (ret) ++ goto error; ++ ++ ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DHD_EVENT_RING_ID], DHD_EVENT_RING_ID, ++ (uint8 *)DHD_EVENT_RING_NAME, DHD_EVENT_RING_SIZE, DHD_PREALLOC_DHD_EVENT_RING); ++ if (ret) ++ goto error; ++ ++ ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[NAN_EVENT_RING_ID], NAN_EVENT_RING_ID, ++ (uint8 *)NAN_EVENT_RING_NAME, NAN_EVENT_RING_SIZE, DHD_PREALLOC_NAN_EVENT_RING); ++ if (ret) ++ goto error; ++ ++ dbg->private = os_priv; ++ dbg->pullreq = os_pullreq; ++ dbg->urgent_notifier = os_urgent_notifier; ++ dhdp->dbg = dbg; ++ ++ return BCME_OK; ++ ++error: ++ for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { ++ if (VALID_RING(dbg->dbg_rings[ring_id].id)) { ++ dhd_dbg_ring_deinit(dhdp, &dbg->dbg_rings[ring_id]); ++ } ++ } ++ MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t)); ++ ++ return ret; ++} ++ ++/* ++ * dhd_dbg_detach: clean up dhd dbugability module ++ */ ++void ++dhd_dbg_detach(dhd_pub_t *dhdp) ++{ ++ int ring_id; ++ dhd_dbg_t *dbg; ++ if (!dhdp->dbg) ++ return; ++ dbg = dhdp->dbg; ++ for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { ++ if (VALID_RING(dbg->dbg_rings[ring_id].id)) { ++ dhd_dbg_ring_deinit(dhdp, &dbg->dbg_rings[ring_id]); ++ } ++ } ++ MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t)); ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_debug.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_debug.h +new file mode 100644 +index 000000000..933711371 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_debug.h +@@ -0,0 +1,868 @@ ++/* ++ * DHD debugability header file ++ * ++ * <> ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_debug.h 705824 2017-06-19 13:58:39Z $ ++ */ ++ ++#ifndef _dhd_debug_h_ ++#define _dhd_debug_h_ ++#include ++#include ++ ++enum { ++ DEBUG_RING_ID_INVALID = 0, ++ FW_VERBOSE_RING_ID, ++ FW_EVENT_RING_ID, ++ DHD_EVENT_RING_ID, ++ NAN_EVENT_RING_ID, ++ /* add new id here */ ++ DEBUG_RING_ID_MAX ++}; ++ ++enum { ++ /* Feature set */ ++ DBG_MEMORY_DUMP_SUPPORTED = (1 << (0)), /* Memory dump of FW */ ++ DBG_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), /* PKT Status */ ++ DBG_CONNECT_EVENT_SUPPORTED = (1 << (2)), /* Connectivity Event */ ++ DBG_POWER_EVENT_SUPOORTED = (1 << (3)), /* POWER of Driver */ ++ DBG_WAKE_LOCK_SUPPORTED = (1 << (4)), /* WAKE LOCK of Driver */ ++ DBG_VERBOSE_LOG_SUPPORTED = (1 << (5)), /* verbose log of FW */ ++ DBG_HEALTH_CHECK_SUPPORTED = (1 << (6)), /* monitor the health of FW */ ++ DBG_DRIVER_DUMP_SUPPORTED = (1 << (7)), /* dumps driver state */ ++ DBG_PACKET_FATE_SUPPORTED = (1 << (8)), /* tracks connection packets' fate */ ++ DBG_NAN_EVENT_SUPPORTED = (1 << (9)), /* NAN Events */ ++}; ++ ++enum { ++ /* set for binary entries */ ++ DBG_RING_ENTRY_FLAGS_HAS_BINARY = (1 << (0)), ++ /* set if 64 bits timestamp is present */ ++ DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1)) ++}; ++ ++#define DBGRING_NAME_MAX 32 ++/* firmware verbose ring, ring id 1 */ ++#define FW_VERBOSE_RING_NAME "fw_verbose" ++#define FW_VERBOSE_RING_SIZE (64 * 1024) ++/* firmware event ring, ring id 2 */ ++#define FW_EVENT_RING_NAME "fw_event" ++#define FW_EVENT_RING_SIZE (64 * 1024) ++/* DHD connection event ring, ring id 3 */ ++#define DHD_EVENT_RING_NAME "dhd_event" ++#define DHD_EVENT_RING_SIZE (64 * 1024) ++ ++/* NAN event ring, ring id 4 */ ++#define NAN_EVENT_RING_NAME "nan_event" ++#define NAN_EVENT_RING_SIZE (64 * 1024) ++ ++#define TLV_LOG_SIZE(tlv) ((tlv) ? (sizeof(tlv_log) + (tlv)->len) : 0) ++ ++#define TLV_LOG_NEXT(tlv) \ ++ ((tlv) ? ((tlv_log *)((uint8 *)tlv + TLV_LOG_SIZE(tlv))) : 0) ++ ++#define DBG_RING_STATUS_SIZE (sizeof(dhd_dbg_ring_status_t)) ++ ++#define VALID_RING(id) \ ++ ((id > DEBUG_RING_ID_INVALID) && (id < DEBUG_RING_ID_MAX)) ++ ++#ifdef DEBUGABILITY ++#define DBG_RING_ACTIVE(dhdp, ring_id) \ ++ ((dhdp)->dbg->dbg_rings[(ring_id)].state == RING_ACTIVE) ++#else ++#define DBG_RING_ACTIVE(dhdp, ring_id) 0 ++#endif /* DEBUGABILITY */ ++ ++#define TXACTIVESZ(r, w, d) (((r) <= (w)) ? ((w) - (r)) : ((d) - (r) + (w))) ++#define DBG_RING_READ_AVAIL_SPACE(w, r, d) (((w) >= (r)) ? ((w) - (r)) : ((d) - (r))) ++#define DBG_RING_WRITE_SPACE_AVAIL_CONT(r, w, d) (((w) >= (r)) ? ((d) - (w)) : ((r) - (w))) ++#define DBG_RING_WRITE_SPACE_AVAIL(r, w, d) (d - (TXACTIVESZ(r, w, d))) ++#define DBG_RING_CHECK_WRITE_SPACE(r, w, d) \ ++ MIN(DBG_RING_WRITE_SPACE_AVAIL(r, w, d), DBG_RING_WRITE_SPACE_AVAIL_CONT(r, w, d)) ++ ++enum { ++ /* driver receive association command from kernel */ ++ WIFI_EVENT_ASSOCIATION_REQUESTED = 0, ++ WIFI_EVENT_AUTH_COMPLETE, ++ WIFI_EVENT_ASSOC_COMPLETE, ++ /* received firmware event indicating auth frames are sent */ ++ WIFI_EVENT_FW_AUTH_STARTED, ++ /* received firmware event indicating assoc frames are sent */ ++ WIFI_EVENT_FW_ASSOC_STARTED, ++ /* received firmware event indicating reassoc frames are sent */ ++ WIFI_EVENT_FW_RE_ASSOC_STARTED, ++ WIFI_EVENT_DRIVER_SCAN_REQUESTED, ++ WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND, ++ WIFI_EVENT_DRIVER_SCAN_COMPLETE, ++ WIFI_EVENT_G_SCAN_STARTED, ++ WIFI_EVENT_G_SCAN_COMPLETE, ++ WIFI_EVENT_DISASSOCIATION_REQUESTED, ++ WIFI_EVENT_RE_ASSOCIATION_REQUESTED, ++ WIFI_EVENT_ROAM_REQUESTED, ++ /* received beacon from AP (event enabled only in verbose mode) */ ++ WIFI_EVENT_BEACON_RECEIVED, ++ /* firmware has triggered a roam scan (not g-scan) */ ++ WIFI_EVENT_ROAM_SCAN_STARTED, ++ /* firmware has completed a roam scan (not g-scan) */ ++ WIFI_EVENT_ROAM_SCAN_COMPLETE, ++ /* firmware has started searching for roam candidates (with reason =xx) */ ++ WIFI_EVENT_ROAM_SEARCH_STARTED, ++ /* firmware has stopped searching for roam candidates (with reason =xx) */ ++ WIFI_EVENT_ROAM_SEARCH_STOPPED, ++ WIFI_EVENT_UNUSED_0, ++ /* received channel switch anouncement from AP */ ++ WIFI_EVENT_CHANNEL_SWITCH_ANOUNCEMENT, ++ /* fw start transmit eapol frame, with EAPOL index 1-4 */ ++ WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START, ++ /* fw gives up eapol frame, with rate, success/failure and number retries */ ++ WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP, ++ /* kernel queue EAPOL for transmission in driver with EAPOL index 1-4 */ ++ WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED, ++ /* with rate, regardless of the fact that EAPOL frame is accepted or ++ * rejected by firmware ++ */ ++ WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED, ++ WIFI_EVENT_UNUSED_1, ++ /* with rate, and eapol index, driver has received */ ++ /* EAPOL frame and will queue it up to wpa_supplicant */ ++ WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED, ++ /* with success/failure, parameters */ ++ WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE, ++ WIFI_EVENT_BT_COEX_BT_SCO_START, ++ WIFI_EVENT_BT_COEX_BT_SCO_STOP, ++ /* for paging/scan etc..., when BT starts transmiting twice per BT slot */ ++ WIFI_EVENT_BT_COEX_BT_SCAN_START, ++ WIFI_EVENT_BT_COEX_BT_SCAN_STOP, ++ WIFI_EVENT_BT_COEX_BT_HID_START, ++ WIFI_EVENT_BT_COEX_BT_HID_STOP, ++ /* firmware sends auth frame in roaming to next candidate */ ++ WIFI_EVENT_ROAM_AUTH_STARTED, ++ /* firmware receive auth confirm from ap */ ++ WIFI_EVENT_ROAM_AUTH_COMPLETE, ++ /* firmware sends assoc/reassoc frame in */ ++ WIFI_EVENT_ROAM_ASSOC_STARTED, ++ /* firmware receive assoc/reassoc confirm from ap */ ++ WIFI_EVENT_ROAM_ASSOC_COMPLETE, ++ /* firmware sends stop G_SCAN */ ++ WIFI_EVENT_G_SCAN_STOP, ++ /* firmware indicates G_SCAN scan cycle started */ ++ WIFI_EVENT_G_SCAN_CYCLE_STARTED, ++ /* firmware indicates G_SCAN scan cycle completed */ ++ WIFI_EVENT_G_SCAN_CYCLE_COMPLETED, ++ /* firmware indicates G_SCAN scan start for a particular bucket */ ++ WIFI_EVENT_G_SCAN_BUCKET_STARTED, ++ /* firmware indicates G_SCAN scan completed for particular bucket */ ++ WIFI_EVENT_G_SCAN_BUCKET_COMPLETED, ++ /* Event received from firmware about G_SCAN scan results being available */ ++ WIFI_EVENT_G_SCAN_RESULTS_AVAILABLE, ++ /* Event received from firmware with G_SCAN capabilities */ ++ WIFI_EVENT_G_SCAN_CAPABILITIES, ++ /* Event received from firmware when eligible candidate is found */ ++ WIFI_EVENT_ROAM_CANDIDATE_FOUND, ++ /* Event received from firmware when roam scan configuration gets enabled or disabled */ ++ WIFI_EVENT_ROAM_SCAN_CONFIG, ++ /* firmware/driver timed out authentication */ ++ WIFI_EVENT_AUTH_TIMEOUT, ++ /* firmware/driver timed out association */ ++ WIFI_EVENT_ASSOC_TIMEOUT, ++ /* firmware/driver encountered allocation failure */ ++ WIFI_EVENT_MEM_ALLOC_FAILURE, ++ /* driver added a PNO network in firmware */ ++ WIFI_EVENT_DRIVER_PNO_ADD, ++ /* driver removed a PNO network in firmware */ ++ WIFI_EVENT_DRIVER_PNO_REMOVE, ++ /* driver received PNO networks found indication from firmware */ ++ WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND, ++ /* driver triggered a scan for PNO networks */ ++ WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED, ++ /* driver received scan results of PNO networks */ ++ WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND, ++ /* driver updated scan results from PNO candidates to cfg */ ++ WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE ++}; ++ ++enum { ++ WIFI_TAG_VENDOR_SPECIFIC = 0, /* take a byte stream as parameter */ ++ WIFI_TAG_BSSID, /* takes a 6 bytes MAC address as parameter */ ++ WIFI_TAG_ADDR, /* takes a 6 bytes MAC address as parameter */ ++ WIFI_TAG_SSID, /* takes a 32 bytes SSID address as parameter */ ++ WIFI_TAG_STATUS, /* takes an integer as parameter */ ++ WIFI_TAG_CHANNEL_SPEC, /* takes one or more wifi_channel_spec as parameter */ ++ WIFI_TAG_WAKE_LOCK_EVENT, /* takes a wake_lock_event struct as parameter */ ++ WIFI_TAG_ADDR1, /* takes a 6 bytes MAC address as parameter */ ++ WIFI_TAG_ADDR2, /* takes a 6 bytes MAC address as parameter */ ++ WIFI_TAG_ADDR3, /* takes a 6 bytes MAC address as parameter */ ++ WIFI_TAG_ADDR4, /* takes a 6 bytes MAC address as parameter */ ++ WIFI_TAG_TSF, /* take a 64 bits TSF value as parameter */ ++ WIFI_TAG_IE, ++ /* take one or more specific 802.11 IEs parameter, IEs are in turn ++ * indicated in TLV format as per 802.11 spec ++ */ ++ WIFI_TAG_INTERFACE, /* take interface name as parameter */ ++ WIFI_TAG_REASON_CODE, /* take a reason code as per 802.11 as parameter */ ++ WIFI_TAG_RATE_MBPS, /* take a wifi rate in 0.5 mbps */ ++ WIFI_TAG_REQUEST_ID, /* take an integer as parameter */ ++ WIFI_TAG_BUCKET_ID, /* take an integer as parameter */ ++ WIFI_TAG_GSCAN_PARAMS, /* takes a wifi_scan_cmd_params struct as parameter */ ++ WIFI_TAG_GSCAN_CAPABILITIES, /* takes a wifi_gscan_capabilities struct as parameter */ ++ WIFI_TAG_SCAN_ID, /* take an integer as parameter */ ++ WIFI_TAG_RSSI, /* takes s16 as parameter */ ++ WIFI_TAG_CHANNEL, /* takes u16 as parameter */ ++ WIFI_TAG_LINK_ID, /* take an integer as parameter */ ++ WIFI_TAG_LINK_ROLE, /* take an integer as parameter */ ++ WIFI_TAG_LINK_STATE, /* take an integer as parameter */ ++ WIFI_TAG_LINK_TYPE, /* take an integer as parameter */ ++ WIFI_TAG_TSCO, /* take an integer as parameter */ ++ WIFI_TAG_RSCO, /* take an integer as parameter */ ++ WIFI_TAG_EAPOL_MESSAGE_TYPE /* take an integer as parameter */ ++}; ++ ++/* NAN events */ ++typedef enum { ++ NAN_EVENT_INVALID = 0, ++ NAN_EVENT_CLUSTER_STARTED = 1, ++ NAN_EVENT_CLUSTER_JOINED = 2, ++ NAN_EVENT_CLUSTER_MERGED = 3, ++ NAN_EVENT_ROLE_CHANGED = 4, ++ NAN_EVENT_SCAN_COMPLETE = 5, ++ NAN_EVENT_STATUS_CHNG = 6, ++ /* ADD new events before this line */ ++ NAN_EVENT_MAX ++} nan_event_id_t; ++ ++typedef struct { ++ uint16 tag; ++ uint16 len; /* length of value */ ++ uint8 value[0]; ++} tlv_log; ++ ++typedef struct per_packet_status_entry { ++ uint8 flags; ++ uint8 tid; /* transmit or received tid */ ++ uint16 MCS; /* modulation and bandwidth */ ++ /* ++ * TX: RSSI of ACK for that packet ++ * RX: RSSI of packet ++ */ ++ uint8 rssi; ++ uint8 num_retries; /* number of attempted retries */ ++ uint16 last_transmit_rate; /* last transmit rate in .5 mbps */ ++ /* transmit/reeive sequence for that MPDU packet */ ++ uint16 link_layer_transmit_sequence; ++ /* ++ * TX: firmware timestamp (us) when packet is queued within firmware buffer ++ * for SDIO/HSIC or into PCIe buffer ++ * RX : firmware receive timestamp ++ */ ++ uint64 firmware_entry_timestamp; ++ /* ++ * firmware timestamp (us) when packet start contending for the ++ * medium for the first time, at head of its AC queue, ++ * or as part of an MPDU or A-MPDU. This timestamp is not updated ++ * for each retry, only the first transmit attempt. ++ */ ++ uint64 start_contention_timestamp; ++ /* ++ * fimrware timestamp (us) when packet is successfully transmitted ++ * or aborted because it has exhausted its maximum number of retries ++ */ ++ uint64 transmit_success_timestamp; ++ /* ++ * packet data. The length of packet data is determined by the entry_size field of ++ * the wifi_ring_buffer_entry structure. It is expected that first bytes of the ++ * packet, or packet headers only (up to TCP or RTP/UDP headers) will be copied into the ring ++ */ ++ uint8 *data; ++} per_packet_status_entry_t; ++ ++#define PACKED_STRUCT __attribute__ ((packed)) ++typedef struct log_conn_event { ++ uint16 event; ++ tlv_log *tlvs; ++ /* ++ * separate parameter structure per event to be provided and optional data ++ * the event_data is expected to include an official android part, with some ++ * parameter as transmit rate, num retries, num scan result found etc... ++ * as well, event_data can include a vendor proprietary part which is ++ * understood by the developer only. ++ */ ++} PACKED_STRUCT log_conn_event_t; ++ ++/* ++ * Ring buffer name for power events ring. note that power event are extremely frequents ++ * and thus should be stored in their own ring/file so as not to clobber connectivity events ++ */ ++ ++typedef struct wake_lock_event { ++ uint32 status; /* 0 taken, 1 released */ ++ uint32 reason; /* reason why this wake lock is taken */ ++ char *name; /* null terminated */ ++} wake_lock_event_t; ++ ++typedef struct wifi_power_event { ++ uint16 event; ++ tlv_log *tlvs; ++} wifi_power_event_t; ++ ++#define NAN_EVENT_VERSION 1 ++typedef struct log_nan_event { ++ uint8 version; ++ uint8 pad; ++ uint16 event; ++ tlv_log *tlvs; ++} log_nan_event_t; ++ ++/* entry type */ ++enum { ++ DBG_RING_ENTRY_EVENT_TYPE = 1, ++ DBG_RING_ENTRY_PKT_TYPE, ++ DBG_RING_ENTRY_WAKE_LOCK_EVENT_TYPE, ++ DBG_RING_ENTRY_POWER_EVENT_TYPE, ++ DBG_RING_ENTRY_DATA_TYPE, ++ DBG_RING_ENTRY_NAN_EVENT_TYPE ++}; ++ ++typedef struct dhd_dbg_ring_entry { ++ uint16 len; /* payload length excluding the header */ ++ uint8 flags; ++ uint8 type; /* Per ring specific */ ++ uint64 timestamp; /* present if has_timestamp bit is set. */ ++} PACKED_STRUCT dhd_dbg_ring_entry_t; ++ ++#define DBG_RING_ENTRY_SIZE (sizeof(dhd_dbg_ring_entry_t)) ++ ++#define ENTRY_LENGTH(hdr) ((hdr)->len + DBG_RING_ENTRY_SIZE) ++ ++#define PAYLOAD_MAX_LEN 65535 ++ ++typedef struct dhd_dbg_ring_status { ++ uint8 name[DBGRING_NAME_MAX]; ++ uint32 flags; ++ int ring_id; /* unique integer representing the ring */ ++ /* total memory size allocated for the buffer */ ++ uint32 ring_buffer_byte_size; ++ uint32 verbose_level; ++ /* number of bytes that was written to the buffer by driver */ ++ uint32 written_bytes; ++ /* number of bytes that was read from the buffer by user land */ ++ uint32 read_bytes; ++ /* number of records that was read from the buffer by user land */ ++ uint32 written_records; ++} dhd_dbg_ring_status_t; ++ ++struct log_level_table { ++ int log_level; ++ uint16 tag; ++ uint8 sets; ++ char *desc; ++}; ++ ++#ifdef DEBUGABILITY ++#define DBG_EVENT_LOG(dhdp, connect_state) \ ++{ \ ++ do { \ ++ uint16 state = connect_state; \ ++ if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) \ ++ dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID, \ ++ &state, sizeof(state)); \ ++ } while (0); \ ++} ++#else ++#define DBG_EVENT_LOG(dhdp, connect_state) ++#endif /* DEBUGABILITY */ ++ ++ ++#define MD5_PREFIX_LEN 4 ++#define MAX_FATE_LOG_LEN 32 ++ ++#define MAX_FRAME_LEN_ETHERNET 1518 ++#define MAX_FRAME_LEN_80211_MGMT 2352 /* 802.11-2012 Fig. 8-34 */ ++ ++typedef enum { ++ /* Sent over air and ACKed. */ ++ TX_PKT_FATE_ACKED, ++ ++ /* Sent over air but not ACKed. (Normal for broadcast/multicast.) */ ++ TX_PKT_FATE_SENT, ++ ++ /* Queued within firmware, but not yet sent over air. */ ++ TX_PKT_FATE_FW_QUEUED, ++ ++ /* ++ * Dropped by firmware as invalid. E.g. bad source address, ++ * bad checksum, or invalid for current state. ++ */ ++ TX_PKT_FATE_FW_DROP_INVALID, ++ ++ /* Dropped by firmware due to lack of buffer space. */ ++ TX_PKT_FATE_FW_DROP_NOBUFS, ++ ++ /* ++ * Dropped by firmware for any other reason. Includes ++ * frames that were sent by driver to firmware, but ++ * unaccounted for by firmware. ++ */ ++ TX_PKT_FATE_FW_DROP_OTHER, ++ ++ /* Queued within driver, not yet sent to firmware. */ ++ TX_PKT_FATE_DRV_QUEUED, ++ ++ /* ++ * Dropped by driver as invalid. E.g. bad source address, ++ * or invalid for current state. ++ */ ++ TX_PKT_FATE_DRV_DROP_INVALID, ++ ++ /* Dropped by driver due to lack of buffer space. */ ++ TX_PKT_FATE_DRV_DROP_NOBUFS, ++ ++ /* Dropped by driver for any other reason. */ ++ TX_PKT_FATE_DRV_DROP_OTHER, ++ ++ } wifi_tx_packet_fate; ++ ++typedef enum { ++ /* Valid and delivered to network stack (e.g., netif_rx()). */ ++ RX_PKT_FATE_SUCCESS, ++ ++ /* Queued within firmware, but not yet sent to driver. */ ++ RX_PKT_FATE_FW_QUEUED, ++ ++ /* Dropped by firmware due to host-programmable filters. */ ++ RX_PKT_FATE_FW_DROP_FILTER, ++ ++ /* ++ * Dropped by firmware as invalid. E.g. bad checksum, ++ * decrypt failed, or invalid for current state. ++ */ ++ RX_PKT_FATE_FW_DROP_INVALID, ++ ++ /* Dropped by firmware due to lack of buffer space. */ ++ RX_PKT_FATE_FW_DROP_NOBUFS, ++ ++ /* Dropped by firmware for any other reason. */ ++ RX_PKT_FATE_FW_DROP_OTHER, ++ ++ /* Queued within driver, not yet delivered to network stack. */ ++ RX_PKT_FATE_DRV_QUEUED, ++ ++ /* Dropped by driver due to filter rules. */ ++ RX_PKT_FATE_DRV_DROP_FILTER, ++ ++ /* Dropped by driver as invalid. E.g. not permitted in current state. */ ++ RX_PKT_FATE_DRV_DROP_INVALID, ++ ++ /* Dropped by driver due to lack of buffer space. */ ++ RX_PKT_FATE_DRV_DROP_NOBUFS, ++ ++ /* Dropped by driver for any other reason. */ ++ RX_PKT_FATE_DRV_DROP_OTHER, ++ ++ } wifi_rx_packet_fate; ++ ++typedef enum { ++ FRAME_TYPE_UNKNOWN, ++ FRAME_TYPE_ETHERNET_II, ++ FRAME_TYPE_80211_MGMT, ++ } frame_type; ++ ++typedef struct wifi_frame_info { ++ /* ++ * The type of MAC-layer frame that this frame_info holds. ++ * - For data frames, use FRAME_TYPE_ETHERNET_II. ++ * - For management frames, use FRAME_TYPE_80211_MGMT. ++ * - If the type of the frame is unknown, use FRAME_TYPE_UNKNOWN. ++ */ ++ frame_type payload_type; ++ ++ /* ++ * The number of bytes included in |frame_content|. If the frame ++ * contents are missing (e.g. RX frame dropped in firmware), ++ * |frame_len| should be set to 0. ++ */ ++ size_t frame_len; ++ ++ /* ++ * Host clock when this frame was received by the driver (either ++ * outbound from the host network stack, or inbound from the ++ * firmware). ++ * - The timestamp should be taken from a clock which includes time ++ * the host spent suspended (e.g. ktime_get_boottime()). ++ * - If no host timestamp is available (e.g. RX frame was dropped in ++ * firmware), this field should be set to 0. ++ */ ++ uint32 driver_timestamp_usec; ++ ++ /* ++ * Firmware clock when this frame was received by the firmware ++ * (either outbound from the host, or inbound from a remote ++ * station). ++ * - The timestamp should be taken from a clock which includes time ++ * firmware spent suspended (if applicable). ++ * - If no firmware timestamp is available (e.g. TX frame was ++ * dropped by driver), this field should be set to 0. ++ * - Consumers of |frame_info| should _not_ assume any ++ * synchronization between driver and firmware clocks. ++ */ ++ uint32 firmware_timestamp_usec; ++ ++ /* ++ * Actual frame content. ++ * - Should be provided for TX frames originated by the host. ++ * - Should be provided for RX frames received by the driver. ++ * - Optionally provided for TX frames originated by firmware. (At ++ * discretion of HAL implementation.) ++ * - Optionally provided for RX frames dropped in firmware. (At ++ * discretion of HAL implementation.) ++ * - If frame content is not provided, |frame_len| should be set ++ * to 0. ++ */ ++ union { ++ char ethernet_ii[MAX_FRAME_LEN_ETHERNET]; ++ char ieee_80211_mgmt[MAX_FRAME_LEN_80211_MGMT]; ++ } frame_content; ++} wifi_frame_info_t; ++ ++typedef struct wifi_tx_report { ++ /* ++ * Prefix of MD5 hash of |frame_inf.frame_content|. If frame ++ * content is not provided, prefix of MD5 hash over the same data ++ * that would be in frame_content, if frame content were provided. ++ */ ++ char md5_prefix[MD5_PREFIX_LEN]; ++ wifi_tx_packet_fate fate; ++ wifi_frame_info_t frame_inf; ++} wifi_tx_report_t; ++ ++typedef struct wifi_rx_report { ++ /* ++ * Prefix of MD5 hash of |frame_inf.frame_content|. If frame ++ * content is not provided, prefix of MD5 hash over the same data ++ * that would be in frame_content, if frame content were provided. ++ */ ++ char md5_prefix[MD5_PREFIX_LEN]; ++ wifi_rx_packet_fate fate; ++ wifi_frame_info_t frame_inf; ++} wifi_rx_report_t; ++ ++typedef struct compat_wifi_frame_info { ++ frame_type payload_type; ++ ++ uint32 frame_len; ++ ++ uint32 driver_timestamp_usec; ++ ++ uint32 firmware_timestamp_usec; ++ ++ union { ++ char ethernet_ii[MAX_FRAME_LEN_ETHERNET]; ++ char ieee_80211_mgmt[MAX_FRAME_LEN_80211_MGMT]; ++ } frame_content; ++} compat_wifi_frame_info_t; ++ ++ ++typedef struct compat_wifi_tx_report { ++ char md5_prefix[MD5_PREFIX_LEN]; ++ wifi_tx_packet_fate fate; ++ compat_wifi_frame_info_t frame_inf; ++} compat_wifi_tx_report_t; ++ ++typedef struct compat_wifi_rx_report { ++ char md5_prefix[MD5_PREFIX_LEN]; ++ wifi_rx_packet_fate fate; ++ compat_wifi_frame_info_t frame_inf; ++} compat_wifi_rx_report_t; ++ ++ ++/* ++ * Packet logging - internal data ++ */ ++ ++typedef enum dhd_dbg_pkt_mon_state { ++ PKT_MON_INVALID = 0, ++ PKT_MON_ATTACHED, ++ PKT_MON_STARTING, ++ PKT_MON_STARTED, ++ PKT_MON_STOPPING, ++ PKT_MON_STOPPED, ++ PKT_MON_DETACHED, ++ } dhd_dbg_pkt_mon_state_t; ++ ++typedef struct dhd_dbg_pkt_info { ++ frame_type payload_type; ++ size_t pkt_len; ++ uint32 driver_ts; ++ uint32 firmware_ts; ++ uint32 pkt_hash; ++ void *pkt; ++} dhd_dbg_pkt_info_t; ++ ++typedef struct compat_dhd_dbg_pkt_info { ++ frame_type payload_type; ++ uint32 pkt_len; ++ uint32 driver_ts; ++ uint32 firmware_ts; ++ uint32 pkt_hash; ++ void *pkt; ++} compat_dhd_dbg_pkt_info_t; ++ ++typedef struct dhd_dbg_tx_info ++{ ++ wifi_tx_packet_fate fate; ++ dhd_dbg_pkt_info_t info; ++} dhd_dbg_tx_info_t; ++ ++typedef struct dhd_dbg_rx_info ++{ ++ wifi_rx_packet_fate fate; ++ dhd_dbg_pkt_info_t info; ++} dhd_dbg_rx_info_t; ++ ++typedef struct dhd_dbg_tx_report ++{ ++ dhd_dbg_tx_info_t *tx_pkts; ++ uint16 pkt_pos; ++ uint16 status_pos; ++} dhd_dbg_tx_report_t; ++ ++typedef struct dhd_dbg_rx_report ++{ ++ dhd_dbg_rx_info_t *rx_pkts; ++ uint16 pkt_pos; ++} dhd_dbg_rx_report_t; ++ ++typedef void (*dbg_pullreq_t)(void *os_priv, const int ring_id); ++typedef void (*dbg_urgent_noti_t) (dhd_pub_t *dhdp, const void *data, const uint32 len); ++typedef int (*dbg_mon_tx_pkts_t) (dhd_pub_t *dhdp, void *pkt, uint32 pktid); ++typedef int (*dbg_mon_tx_status_t) (dhd_pub_t *dhdp, void *pkt, ++ uint32 pktid, uint16 status); ++typedef int (*dbg_mon_rx_pkts_t) (dhd_pub_t *dhdp, void *pkt); ++ ++typedef struct dhd_dbg_pkt_mon ++{ ++ dhd_dbg_tx_report_t *tx_report; ++ dhd_dbg_rx_report_t *rx_report; ++ dhd_dbg_pkt_mon_state_t tx_pkt_state; ++ dhd_dbg_pkt_mon_state_t tx_status_state; ++ dhd_dbg_pkt_mon_state_t rx_pkt_state; ++ ++ /* call backs */ ++ dbg_mon_tx_pkts_t tx_pkt_mon; ++ dbg_mon_tx_status_t tx_status_mon; ++ dbg_mon_rx_pkts_t rx_pkt_mon; ++} dhd_dbg_pkt_mon_t; ++ ++enum dbg_ring_state { ++ RING_STOP = 0, /* ring is not initialized */ ++ RING_ACTIVE, /* ring is live and logging */ ++ RING_SUSPEND /* ring is initialized but not logging */ ++}; ++ ++struct ring_statistics { ++ /* number of bytes that was written to the buffer by driver */ ++ uint32 written_bytes; ++ /* number of bytes that was read from the buffer by user land */ ++ uint32 read_bytes; ++ /* number of records that was written to the buffer by driver */ ++ uint32 written_records; ++}; ++ ++typedef struct dhd_dbg_ring { ++ int id; /* ring id */ ++ uint8 name[DBGRING_NAME_MAX]; /* name string */ ++ uint32 ring_size; /* numbers of item in ring */ ++ uint32 wp; /* write pointer */ ++ uint32 rp; /* read pointer */ ++ uint32 log_level; /* log_level */ ++ uint32 threshold; /* threshold bytes */ ++ void * ring_buf; /* pointer of actually ring buffer */ ++ void * lock; /* spin lock for ring access */ ++ struct ring_statistics stat; /* statistics */ ++ enum dbg_ring_state state; /* ring state enum */ ++ bool tail_padded; /* writer does not have enough space */ ++ uint32 rem_len; /* number of bytes from wp_pad to end */ ++ bool sched_pull; /* schedule reader immediately */ ++} dhd_dbg_ring_t; ++ ++typedef struct dhd_dbg { ++ dhd_dbg_ring_t dbg_rings[DEBUG_RING_ID_MAX]; ++ void *private; /* os private_data */ ++ dhd_dbg_pkt_mon_t pkt_mon; ++ void *pkt_mon_lock; /* spin lock for packet monitoring */ ++ dbg_pullreq_t pullreq; ++ dbg_urgent_noti_t urgent_notifier; ++} dhd_dbg_t; ++ ++#define PKT_MON_ATTACHED(state) \ ++ (((state) > PKT_MON_INVALID) && ((state) < PKT_MON_DETACHED)) ++#define PKT_MON_DETACHED(state) \ ++ (((state) == PKT_MON_INVALID) || ((state) == PKT_MON_DETACHED)) ++#define PKT_MON_STARTED(state) ((state) == PKT_MON_STARTED) ++#define PKT_MON_STOPPED(state) ((state) == PKT_MON_STOPPED) ++#define PKT_MON_NOT_OPERATIONAL(state) \ ++ (((state) != PKT_MON_STARTED) && ((state) != PKT_MON_STOPPED)) ++#define PKT_MON_SAFE_TO_FREE(state) \ ++ (((state) == PKT_MON_STARTING) || ((state) == PKT_MON_STOPPED)) ++#define PKT_MON_PKT_FULL(pkt_count) ((pkt_count) >= MAX_FATE_LOG_LEN) ++#define PKT_MON_STATUS_FULL(pkt_count, status_count) \ ++ (((status_count) >= (pkt_count)) || ((status_count) >= MAX_FATE_LOG_LEN)) ++ ++#ifdef DBG_PKT_MON ++#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid) \ ++ do { \ ++ if ((dhdp) && (dhdp)->dbg && (dhdp)->dbg->pkt_mon.tx_pkt_mon && (pkt)) { \ ++ (dhdp)->dbg->pkt_mon.tx_pkt_mon((dhdp), (pkt), (pktid)); \ ++ } \ ++ } while (0); ++#define DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, status) \ ++ do { \ ++ if ((dhdp) && (dhdp)->dbg && (dhdp)->dbg->pkt_mon.tx_status_mon && (pkt)) { \ ++ (dhdp)->dbg->pkt_mon.tx_status_mon((dhdp), (pkt), (pktid), (status)); \ ++ } \ ++ } while (0); ++#define DHD_DBG_PKT_MON_RX(dhdp, pkt) \ ++ do { \ ++ if ((dhdp) && (dhdp)->dbg && (dhdp)->dbg->pkt_mon.rx_pkt_mon && (pkt)) { \ ++ if (ntoh16((pkt)->protocol) != ETHER_TYPE_BRCM) { \ ++ (dhdp)->dbg->pkt_mon.rx_pkt_mon((dhdp), (pkt)); \ ++ } \ ++ } \ ++ } while (0); ++ ++#define DHD_DBG_PKT_MON_START(dhdp) \ ++ dhd_os_dbg_start_pkt_monitor((dhdp)); ++#define DHD_DBG_PKT_MON_STOP(dhdp) \ ++ dhd_os_dbg_stop_pkt_monitor((dhdp)); ++#else ++#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid) ++#define DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, status) ++#define DHD_DBG_PKT_MON_RX(dhdp, pkt) ++#define DHD_DBG_PKT_MON_START(dhdp) ++#define DHD_DBG_PKT_MON_STOP(dhdp) ++#endif /* DBG_PKT_MON */ ++ ++#ifdef DUMP_IOCTL_IOV_LIST ++typedef struct dhd_iov_li { ++ dll_t list; ++ uint32 cmd; ++ char buff[100]; ++} dhd_iov_li_t; ++ ++#define IOV_LIST_MAX_LEN 5 ++#endif /* DUMP_IOCTL_IOV_LIST */ ++ ++#ifdef DHD_DEBUG ++typedef struct { ++ dll_t list; ++ uint32 id; /* wasted chunk id */ ++ uint32 handle; /* wasted chunk handle */ ++ uint32 size; /* wasted chunk size */ ++} dhd_dbg_mwli_t; ++#endif /* DHD_DEBUG */ ++ ++/* dhd_dbg functions */ ++extern void dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data, ++ void *raw_event_ptr, uint datalen); ++extern int dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq, ++ dbg_urgent_noti_t os_urgent_notifier, void *os_priv); ++extern void dhd_dbg_detach(dhd_pub_t *dhdp); ++extern int dhd_dbg_start(dhd_pub_t *dhdp, bool start); ++extern int dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id, ++ int log_level, int flags, uint32 threshold); ++extern int dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id, ++ dhd_dbg_ring_status_t *dbg_ring_status); ++extern int dhd_dbg_ring_push(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr, void *data); ++extern int dhd_dbg_ring_pull(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len); ++extern int dhd_dbg_ring_pull_single(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len, ++ bool strip_header); ++extern int dhd_dbg_find_ring_id(dhd_pub_t *dhdp, char *ring_name); ++extern void *dhd_dbg_get_priv(dhd_pub_t *dhdp); ++extern int dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len); ++extern void dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, event_log_hdr_t *hdr, ++ void *raw_event_ptr, uint32 *log_ptr); ++ ++#ifdef DBG_PKT_MON ++extern int dhd_dbg_attach_pkt_monitor(dhd_pub_t *dhdp, ++ dbg_mon_tx_pkts_t tx_pkt_mon, ++ dbg_mon_tx_status_t tx_status_mon, ++ dbg_mon_rx_pkts_t rx_pkt_mon); ++extern int dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp); ++extern int dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid); ++extern int dhd_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, ++ uint32 pktid, uint16 status); ++extern int dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt); ++extern int dhd_dbg_stop_pkt_monitor(dhd_pub_t *dhdp); ++extern int dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, ++ uint16 req_count, uint16 *resp_count); ++extern int dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, ++ uint16 req_count, uint16 *resp_count); ++extern int dhd_dbg_detach_pkt_monitor(dhd_pub_t *dhdp); ++#endif /* DBG_PKT_MON */ ++ ++/* os wrapper function */ ++extern int dhd_os_dbg_attach(dhd_pub_t *dhdp); ++extern void dhd_os_dbg_detach(dhd_pub_t *dhdp); ++extern int dhd_os_dbg_register_callback(int ring_id, ++ void (*dbg_ring_sub_cb)(void *ctx, const int ring_id, const void *data, ++ const uint32 len, const dhd_dbg_ring_status_t dbg_ring_status)); ++extern int dhd_os_dbg_register_urgent_notifier(dhd_pub_t *dhdp, ++ void (*urgent_noti)(void *ctx, const void *data, const uint32 len, const uint32 fw_len)); ++ ++extern int dhd_os_start_logging(dhd_pub_t *dhdp, char *ring_name, int log_level, ++ int flags, int time_intval, int threshold); ++extern int dhd_os_reset_logging(dhd_pub_t *dhdp); ++extern int dhd_os_suppress_logging(dhd_pub_t *dhdp, bool suppress); ++ ++extern int dhd_os_get_ring_status(dhd_pub_t *dhdp, int ring_id, ++ dhd_dbg_ring_status_t *dbg_ring_status); ++extern int dhd_os_trigger_get_ring_data(dhd_pub_t *dhdp, char *ring_name); ++extern int dhd_os_push_push_ring_data(dhd_pub_t *dhdp, int ring_id, void *data, int32 data_len); ++extern int dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features); ++ ++#ifdef DBG_PKT_MON ++extern int dhd_os_dbg_attach_pkt_monitor(dhd_pub_t *dhdp); ++extern int dhd_os_dbg_start_pkt_monitor(dhd_pub_t *dhdp); ++extern int dhd_os_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, ++ uint32 pktid); ++extern int dhd_os_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, ++ uint32 pktid, uint16 status); ++extern int dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt); ++extern int dhd_os_dbg_stop_pkt_monitor(dhd_pub_t *dhdp); ++extern int dhd_os_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, ++ void __user *user_buf, uint16 req_count, uint16 *resp_count); ++extern int dhd_os_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, ++ void __user *user_buf, uint16 req_count, uint16 *resp_count); ++extern int dhd_os_dbg_detach_pkt_monitor(dhd_pub_t *dhdp); ++#endif /* DBG_PKT_MON */ ++ ++#ifdef DUMP_IOCTL_IOV_LIST ++extern void dhd_iov_li_append(dhd_pub_t *dhd, dll_t *list_head, dll_t *node); ++extern void dhd_iov_li_print(dll_t *list_head); ++extern void dhd_iov_li_delete(dhd_pub_t *dhd, dll_t *list_head); ++#endif /* DUMP_IOCTL_IOV_LIST */ ++ ++#ifdef DHD_DEBUG ++extern void dhd_mw_list_delete(dhd_pub_t *dhd, dll_t *list_head); ++#endif /* DHD_DEBUG */ ++#endif /* _dhd_debug_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_debug_linux.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_debug_linux.c +new file mode 100644 +index 000000000..ddd659407 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_debug_linux.c +@@ -0,0 +1,520 @@ ++/* ++ * DHD debugability Linux os layer ++ * ++ * <> ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_debug_linux.c 710862 2017-07-14 07:43:59Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++typedef void (*dbg_ring_send_sub_t)(void *ctx, const int ring_id, const void *data, ++ const uint32 len, const dhd_dbg_ring_status_t ring_status); ++typedef void (*dbg_urgent_noti_sub_t)(void *ctx, const void *data, ++ const uint32 len, const uint32 fw_len); ++ ++static dbg_ring_send_sub_t ring_send_sub_cb[DEBUG_RING_ID_MAX]; ++static dbg_urgent_noti_sub_t urgent_noti_sub_cb; ++typedef struct dhd_dbg_os_ring_info { ++ dhd_pub_t *dhdp; ++ int ring_id; ++ int log_level; ++ unsigned long interval; ++ struct delayed_work work; ++ uint64 tsoffset; ++} linux_dbgring_info_t; ++ ++struct log_level_table dhd_event_map[] = { ++ {1, WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED, 0, "DRIVER EAPOL TX REQ"}, ++ {1, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED, 0, "DRIVER EAPOL RX"}, ++ {2, WIFI_EVENT_DRIVER_SCAN_REQUESTED, 0, "SCAN_REQUESTED"}, ++ {2, WIFI_EVENT_DRIVER_SCAN_COMPLETE, 0, "SCAN COMPELETE"}, ++ {3, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND, 0, "SCAN RESULT FOUND"}, ++ {2, WIFI_EVENT_DRIVER_PNO_ADD, 0, "PNO ADD"}, ++ {2, WIFI_EVENT_DRIVER_PNO_REMOVE, 0, "PNO REMOVE"}, ++ {2, WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND, 0, "PNO NETWORK FOUND"}, ++ {2, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED, 0, "PNO SCAN_REQUESTED"}, ++ {1, WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND, 0, "PNO SCAN RESULT FOUND"}, ++ {1, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE, 0, "PNO SCAN COMPELETE"} ++}; ++ ++static void ++debug_data_send(dhd_pub_t *dhdp, int ring_id, const void *data, const uint32 len, ++ const dhd_dbg_ring_status_t ring_status) ++{ ++ struct net_device *ndev; ++ dbg_ring_send_sub_t ring_sub_send; ++ ndev = dhd_linux_get_primary_netdev(dhdp); ++ if (!ndev) ++ return; ++ if (ring_send_sub_cb[ring_id]) { ++ ring_sub_send = ring_send_sub_cb[ring_id]; ++ ring_sub_send(ndev, ring_id, data, len, ring_status); ++ } ++} ++ ++static void ++dhd_os_dbg_urgent_notifier(dhd_pub_t *dhdp, const void *data, const uint32 len) ++{ ++ struct net_device *ndev; ++ ndev = dhd_linux_get_primary_netdev(dhdp); ++ if (!ndev) ++ return; ++ if (urgent_noti_sub_cb) { ++ urgent_noti_sub_cb(ndev, data, len, dhdp->soc_ram_length); ++ } ++} ++ ++static void ++dbg_ring_poll_worker(struct work_struct *work) ++{ ++ struct delayed_work *d_work = to_delayed_work(work); ++ bool sched = TRUE; ++ dhd_dbg_ring_t *ring; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ linux_dbgring_info_t *ring_info = ++ container_of(d_work, linux_dbgring_info_t, work); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ dhd_pub_t *dhdp = ring_info->dhdp; ++ int ringid = ring_info->ring_id; ++ dhd_dbg_ring_status_t ring_status; ++ void *buf; ++ dhd_dbg_ring_entry_t *hdr; ++ uint32 buflen, rlen; ++ unsigned long flags; ++ ++ ring = &dhdp->dbg->dbg_rings[ringid]; ++ flags = dhd_os_spin_lock(ring->lock); ++ dhd_dbg_get_ring_status(dhdp, ringid, &ring_status); ++ ++ if (ring->wp > ring->rp) { ++ buflen = ring->wp - ring->rp; ++ } else if (ring->wp < ring->rp) { ++ buflen = ring->ring_size - ring->rp + ring->wp; ++ } else { ++ goto exit; ++ } ++ ++ if (buflen > ring->ring_size) { ++ goto exit; ++ } ++ ++ buf = MALLOCZ(dhdp->osh, buflen); ++ if (!buf) { ++ DHD_ERROR(("%s failed to allocate read buf\n", __FUNCTION__)); ++ sched = FALSE; ++ goto exit; ++ } ++ ++ rlen = dhd_dbg_ring_pull(dhdp, ringid, buf, buflen); ++ if (!ring->sched_pull) { ++ ring->sched_pull = TRUE; ++ } ++ ++ hdr = (dhd_dbg_ring_entry_t *)buf; ++ while (rlen > 0) { ++ ring_status.read_bytes += ENTRY_LENGTH(hdr); ++ /* offset fw ts to host ts */ ++ hdr->timestamp += ring_info->tsoffset; ++ debug_data_send(dhdp, ringid, hdr, ENTRY_LENGTH(hdr), ++ ring_status); ++ rlen -= ENTRY_LENGTH(hdr); ++ hdr = (dhd_dbg_ring_entry_t *)((char *)hdr + ENTRY_LENGTH(hdr)); ++ } ++ MFREE(dhdp->osh, buf, buflen); ++ ++exit: ++ if (sched) { ++ /* retrigger the work at same interval */ ++ if ((ring_status.written_bytes == ring_status.read_bytes) && ++ (ring_info->interval)) { ++ schedule_delayed_work(d_work, ring_info->interval); ++ } ++ } ++ ++ dhd_os_spin_unlock(ring->lock, flags); ++ ++ return; ++} ++ ++int ++dhd_os_dbg_register_callback(int ring_id, dbg_ring_send_sub_t callback) ++{ ++ if (!VALID_RING(ring_id)) ++ return BCME_RANGE; ++ ++ ring_send_sub_cb[ring_id] = callback; ++ return BCME_OK; ++} ++ ++int ++dhd_os_dbg_register_urgent_notifier(dhd_pub_t *dhdp, dbg_urgent_noti_sub_t urgent_noti_sub) ++{ ++ if (!dhdp || !urgent_noti_sub) ++ return BCME_BADARG; ++ urgent_noti_sub_cb = urgent_noti_sub; ++ ++ return BCME_OK; ++} ++ ++int ++dhd_os_start_logging(dhd_pub_t *dhdp, char *ring_name, int log_level, ++ int flags, int time_intval, int threshold) ++{ ++ int ret = BCME_OK; ++ int ring_id; ++ linux_dbgring_info_t *os_priv, *ring_info; ++ uint32 ms; ++ ++ ring_id = dhd_dbg_find_ring_id(dhdp, ring_name); ++ if (!VALID_RING(ring_id)) ++ return BCME_UNSUPPORTED; ++ ++ DHD_DBGIF(("%s , log_level : %d, time_intval : %d, threshod %d Bytes\n", ++ __FUNCTION__, log_level, time_intval, threshold)); ++ ++ /* change the configuration */ ++ ret = dhd_dbg_set_configuration(dhdp, ring_id, log_level, flags, threshold); ++ if (ret) { ++ DHD_ERROR(("dhd_set_configuration is failed : %d\n", ret)); ++ return ret; ++ } ++ ++ os_priv = dhd_dbg_get_priv(dhdp); ++ if (!os_priv) ++ return BCME_ERROR; ++ ring_info = &os_priv[ring_id]; ++ ring_info->log_level = log_level; ++ if (ring_id == FW_VERBOSE_RING_ID || ring_id == FW_EVENT_RING_ID) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) ++ ring_info->tsoffset = local_clock(); ++#else ++ ring_info->tsoffset = sched_clock(); ++#endif ++ if (dhd_wl_ioctl_get_intiovar(dhdp, "rte_timesync", &ms, WLC_GET_VAR, ++ FALSE, 0)) ++ DHD_ERROR(("%s rte_timesync failed\n", __FUNCTION__)); ++ do_div(ring_info->tsoffset, 1000000); ++ ring_info->tsoffset -= ms; ++ } ++ if (time_intval == 0 || log_level == 0) { ++ ring_info->interval = 0; ++ cancel_delayed_work_sync(&ring_info->work); ++ } else { ++ ring_info->interval = msecs_to_jiffies(time_intval * MSEC_PER_SEC); ++ cancel_delayed_work_sync(&ring_info->work); ++ schedule_delayed_work(&ring_info->work, ring_info->interval); ++ } ++ ++ return ret; ++} ++ ++int ++dhd_os_reset_logging(dhd_pub_t *dhdp) ++{ ++ int ret = BCME_OK; ++ int ring_id; ++ linux_dbgring_info_t *os_priv, *ring_info; ++ ++ os_priv = dhd_dbg_get_priv(dhdp); ++ if (!os_priv) ++ return BCME_ERROR; ++ ++ /* Stop all rings */ ++ for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { ++ DHD_DBGIF(("%s: Stop ring buffer %d\n", __FUNCTION__, ring_id)); ++ ++ ring_info = &os_priv[ring_id]; ++ /* cancel any pending work */ ++ cancel_delayed_work_sync(&ring_info->work); ++ /* log level zero makes stop logging on that ring */ ++ ring_info->log_level = 0; ++ ring_info->interval = 0; ++ /* change the configuration */ ++ ret = dhd_dbg_set_configuration(dhdp, ring_id, 0, 0, 0); ++ if (ret) { ++ DHD_ERROR(("dhd_set_configuration is failed : %d\n", ret)); ++ return ret; ++ } ++ } ++ return ret; ++} ++ ++#define SUPPRESS_LOG_LEVEL 1 ++int ++dhd_os_suppress_logging(dhd_pub_t *dhdp, bool suppress) ++{ ++ int ret = BCME_OK; ++ int max_log_level; ++ int enable = (suppress) ? 0 : 1; ++ linux_dbgring_info_t *os_priv; ++ ++ os_priv = dhd_dbg_get_priv(dhdp); ++ if (!os_priv) ++ return BCME_ERROR; ++ ++ max_log_level = MAX(os_priv[FW_VERBOSE_RING_ID].log_level, ++ os_priv[FW_EVENT_RING_ID].log_level); ++ if (max_log_level == SUPPRESS_LOG_LEVEL) { ++ /* suppress the logging in FW not to wake up host while device in suspend mode */ ++ ret = dhd_iovar(dhdp, 0, "logtrace", (char *)&enable, sizeof(enable), NULL, 0, ++ TRUE); ++ if (ret < 0 && (ret != BCME_UNSUPPORTED)) { ++ DHD_ERROR(("logtrace is failed : %d\n", ret)); ++ } ++ } ++ ++ return ret; ++} ++ ++int ++dhd_os_get_ring_status(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_status_t *dbg_ring_status) ++{ ++ return dhd_dbg_get_ring_status(dhdp, ring_id, dbg_ring_status); ++} ++ ++int ++dhd_os_trigger_get_ring_data(dhd_pub_t *dhdp, char *ring_name) ++{ ++ int ret = BCME_OK; ++ int ring_id; ++ linux_dbgring_info_t *os_priv, *ring_info; ++ ring_id = dhd_dbg_find_ring_id(dhdp, ring_name); ++ if (!VALID_RING(ring_id)) ++ return BCME_UNSUPPORTED; ++ os_priv = dhd_dbg_get_priv(dhdp); ++ if (os_priv) { ++ ring_info = &os_priv[ring_id]; ++ if (ring_info->interval) { ++ cancel_delayed_work_sync(&ring_info->work); ++ } ++ schedule_delayed_work(&ring_info->work, 0); ++ } else { ++ DHD_ERROR(("%s : os_priv is NULL\n", __FUNCTION__)); ++ ret = BCME_ERROR; ++ } ++ return ret; ++} ++ ++int ++dhd_os_push_push_ring_data(dhd_pub_t *dhdp, int ring_id, void *data, int32 data_len) ++{ ++ int ret = BCME_OK, i; ++ dhd_dbg_ring_entry_t msg_hdr; ++ log_conn_event_t *event_data = (log_conn_event_t *)data; ++ linux_dbgring_info_t *os_priv, *ring_info = NULL; ++ ++ if (!VALID_RING(ring_id)) ++ return BCME_UNSUPPORTED; ++ os_priv = dhd_dbg_get_priv(dhdp); ++ ++ if (os_priv) { ++ ring_info = &os_priv[ring_id]; ++ } else ++ return BCME_NORESOURCE; ++ ++ memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t)); ++ ++ if (ring_id == DHD_EVENT_RING_ID) { ++ msg_hdr.type = DBG_RING_ENTRY_EVENT_TYPE; ++ msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP; ++ msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_BINARY; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) ++ msg_hdr.timestamp = local_clock(); ++#else ++ msg_hdr.timestamp = sched_clock(); ++#endif ++ /* convert to ms */ ++ do_div(msg_hdr.timestamp, 1000000); ++ msg_hdr.len = data_len; ++ /* filter the event for higher log level with current log level */ ++ for (i = 0; i < ARRAYSIZE(dhd_event_map); i++) { ++ if ((dhd_event_map[i].tag == event_data->event) && ++ dhd_event_map[i].log_level > ring_info->log_level) { ++ return ret; ++ } ++ } ++ } ++ ret = dhd_dbg_ring_push(dhdp, ring_id, &msg_hdr, event_data); ++ if (ret) { ++ DHD_ERROR(("%s : failed to push data into the ring (%d) with ret(%d)\n", ++ __FUNCTION__, ring_id, ret)); ++ } ++ ++ return ret; ++} ++ ++#ifdef DBG_PKT_MON ++int ++dhd_os_dbg_attach_pkt_monitor(dhd_pub_t *dhdp) ++{ ++ return dhd_dbg_attach_pkt_monitor(dhdp, dhd_os_dbg_monitor_tx_pkts, ++ dhd_os_dbg_monitor_tx_status, dhd_os_dbg_monitor_rx_pkts); ++} ++ ++int ++dhd_os_dbg_start_pkt_monitor(dhd_pub_t *dhdp) ++{ ++ return dhd_dbg_start_pkt_monitor(dhdp); ++} ++ ++int ++dhd_os_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid) ++{ ++ return dhd_dbg_monitor_tx_pkts(dhdp, pkt, pktid); ++} ++ ++int ++dhd_os_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid, ++ uint16 status) ++{ ++ return dhd_dbg_monitor_tx_status(dhdp, pkt, pktid, status); ++} ++ ++int ++dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt) ++{ ++ return dhd_dbg_monitor_rx_pkts(dhdp, pkt); ++} ++ ++int ++dhd_os_dbg_stop_pkt_monitor(dhd_pub_t *dhdp) ++{ ++ return dhd_dbg_stop_pkt_monitor(dhdp); ++} ++ ++int ++dhd_os_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, ++ uint16 req_count, uint16 *resp_count) ++{ ++ return dhd_dbg_monitor_get_tx_pkts(dhdp, user_buf, req_count, resp_count); ++} ++ ++int ++dhd_os_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, ++ uint16 req_count, uint16 *resp_count) ++{ ++ return dhd_dbg_monitor_get_rx_pkts(dhdp, user_buf, req_count, resp_count); ++} ++ ++int ++dhd_os_dbg_detach_pkt_monitor(dhd_pub_t *dhdp) ++{ ++ return dhd_dbg_detach_pkt_monitor(dhdp); ++} ++#endif /* DBG_PKT_MON */ ++ ++int ++dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features) ++{ ++ int ret = BCME_OK; ++ *features = 0; ++ *features |= DBG_MEMORY_DUMP_SUPPORTED; ++ if (FW_SUPPORTED(dhdp, logtrace)) { ++ *features |= DBG_CONNECT_EVENT_SUPPORTED; ++ *features |= DBG_VERBOSE_LOG_SUPPORTED; ++ } ++ if (FW_SUPPORTED(dhdp, hchk)) { ++ *features |= DBG_HEALTH_CHECK_SUPPORTED; ++ } ++#ifdef DBG_PKT_MON ++ if (FW_SUPPORTED(dhdp, d11status)) { ++ *features |= DBG_PACKET_FATE_SUPPORTED; ++ } ++#endif /* DBG_PKT_MON */ ++ return ret; ++} ++ ++static void ++dhd_os_dbg_pullreq(void *os_priv, int ring_id) ++{ ++ linux_dbgring_info_t *ring_info; ++ ++ ring_info = &((linux_dbgring_info_t *)os_priv)[ring_id]; ++ cancel_delayed_work(&ring_info->work); ++ schedule_delayed_work(&ring_info->work, 0); ++} ++ ++int ++dhd_os_dbg_attach(dhd_pub_t *dhdp) ++{ ++ int ret = BCME_OK; ++ linux_dbgring_info_t *os_priv, *ring_info; ++ int ring_id; ++ ++ /* os_dbg data */ ++ os_priv = MALLOCZ(dhdp->osh, sizeof(*os_priv) * DEBUG_RING_ID_MAX); ++ if (!os_priv) ++ return BCME_NOMEM; ++ ++ for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ++ ring_id++) { ++ ring_info = &os_priv[ring_id]; ++ INIT_DELAYED_WORK(&ring_info->work, dbg_ring_poll_worker); ++ ring_info->dhdp = dhdp; ++ ring_info->ring_id = ring_id; ++ } ++ ++ ret = dhd_dbg_attach(dhdp, dhd_os_dbg_pullreq, dhd_os_dbg_urgent_notifier, os_priv); ++ if (ret) ++ MFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX); ++ ++ return ret; ++} ++ ++void ++dhd_os_dbg_detach(dhd_pub_t *dhdp) ++{ ++ linux_dbgring_info_t *os_priv, *ring_info; ++ int ring_id; ++ /* free os_dbg data */ ++ os_priv = dhd_dbg_get_priv(dhdp); ++ if (!os_priv) ++ return; ++ /* abort pending any job */ ++ for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { ++ ring_info = &os_priv[ring_id]; ++ if (ring_info->interval) { ++ ring_info->interval = 0; ++ cancel_delayed_work_sync(&ring_info->work); ++ } ++ } ++ MFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX); ++ ++ return dhd_dbg_detach(dhdp); ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_flowring.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_flowring.c +new file mode 100644 +index 000000000..17a9dc314 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_flowring.c +@@ -0,0 +1,1063 @@ ++/* ++ * @file Broadcom Dongle Host Driver (DHD), Flow ring specific code at top level ++ * ++ * Flow rings are transmit traffic (=propagating towards antenna) related entities ++ * ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_flowring.c 710862 2017-07-14 07:43:59Z $ ++ */ ++ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include <802.1d.h> ++#include ++#include ++#include ++ ++static INLINE int dhd_flow_queue_throttle(flow_queue_t *queue); ++ ++static INLINE uint16 dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, ++ uint8 prio, char *sa, char *da); ++ ++static INLINE uint16 dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, ++ uint8 prio, char *sa, char *da); ++ ++static INLINE int dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, ++ uint8 prio, char *sa, char *da, uint16 *flowid); ++int BCMFASTPATH dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt); ++ ++#define FLOW_QUEUE_PKT_NEXT(p) PKTLINK(p) ++#define FLOW_QUEUE_PKT_SETNEXT(p, x) PKTSETLINK((p), (x)) ++ ++#if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING) ++const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 7 }; ++#else ++const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 }; ++#endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */ ++const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ++ ++/** Queue overflow throttle. Return value: TRUE if throttle needs to be applied */ ++static INLINE int ++dhd_flow_queue_throttle(flow_queue_t *queue) ++{ ++ return DHD_FLOW_QUEUE_FULL(queue); ++} ++ ++int BCMFASTPATH ++dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt) ++{ ++ return BCME_NORESOURCE; ++} ++ ++/** Returns flow ring given a flowid */ ++flow_ring_node_t * ++dhd_flow_ring_node(dhd_pub_t *dhdp, uint16 flowid) ++{ ++ flow_ring_node_t * flow_ring_node; ++ ++ ASSERT(dhdp != (dhd_pub_t*)NULL); ++ ASSERT(flowid < dhdp->num_flow_rings); ++ ++ flow_ring_node = &(((flow_ring_node_t*)(dhdp->flow_ring_table))[flowid]); ++ ++ ASSERT(flow_ring_node->flowid == flowid); ++ return flow_ring_node; ++} ++ ++/** Returns 'backup' queue given a flowid */ ++flow_queue_t * ++dhd_flow_queue(dhd_pub_t *dhdp, uint16 flowid) ++{ ++ flow_ring_node_t * flow_ring_node; ++ ++ flow_ring_node = dhd_flow_ring_node(dhdp, flowid); ++ return &flow_ring_node->queue; ++} ++ ++/* Flow ring's queue management functions */ ++ ++/** Reinitialize a flow ring's queue. */ ++void ++dhd_flow_queue_reinit(dhd_pub_t *dhdp, flow_queue_t *queue, int max) ++{ ++ ASSERT((queue != NULL) && (max > 0)); ++ ++ queue->head = queue->tail = NULL; ++ queue->len = 0; ++ ++ /* Set queue's threshold and queue's parent cummulative length counter */ ++ ASSERT(max > 1); ++ DHD_FLOW_QUEUE_SET_MAX(queue, max); ++ DHD_FLOW_QUEUE_SET_THRESHOLD(queue, max); ++ DHD_FLOW_QUEUE_SET_CLEN(queue, &dhdp->cumm_ctr); ++ DHD_FLOW_QUEUE_SET_L2CLEN(queue, &dhdp->l2cumm_ctr); ++ ++ queue->failures = 0U; ++ queue->cb = &dhd_flow_queue_overflow; ++} ++ ++/** Initialize a flow ring's queue, called on driver initialization. */ ++void ++dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max) ++{ ++ ASSERT((queue != NULL) && (max > 0)); ++ ++ dll_init(&queue->list); ++ dhd_flow_queue_reinit(dhdp, queue, max); ++} ++ ++/** Register an enqueue overflow callback handler */ ++void ++dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb) ++{ ++ ASSERT(queue != NULL); ++ queue->cb = cb; ++} ++ ++/** ++ * Enqueue an 802.3 packet at the back of a flow ring's queue. From there, it will travel later on ++ * to the flow ring itself. ++ */ ++int BCMFASTPATH ++dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt) ++{ ++ int ret = BCME_OK; ++ ++ ASSERT(queue != NULL); ++ ++ if (dhd_flow_queue_throttle(queue)) { ++ queue->failures++; ++ ret = (*queue->cb)(queue, pkt); ++ goto done; ++ } ++ ++ if (queue->head) { ++ FLOW_QUEUE_PKT_SETNEXT(queue->tail, pkt); ++ } else { ++ queue->head = pkt; ++ } ++ ++ FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); ++ ++ queue->tail = pkt; /* at tail */ ++ ++ queue->len++; ++ /* increment parent's cummulative length */ ++ DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_CLEN_PTR(queue)); ++ /* increment grandparent's cummulative length */ ++ DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_L2CLEN_PTR(queue)); ++ ++done: ++ return ret; ++} ++ ++/** Dequeue an 802.3 packet from a flow ring's queue, from head (FIFO) */ ++void * BCMFASTPATH ++dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue) ++{ ++ void * pkt; ++ ++ ASSERT(queue != NULL); ++ ++ pkt = queue->head; /* from head */ ++ ++ if (pkt == NULL) { ++ ASSERT((queue->len == 0) && (queue->tail == NULL)); ++ goto done; ++ } ++ ++ queue->head = FLOW_QUEUE_PKT_NEXT(pkt); ++ if (queue->head == NULL) ++ queue->tail = NULL; ++ ++ queue->len--; ++ /* decrement parent's cummulative length */ ++ DHD_CUMM_CTR_DECR(DHD_FLOW_QUEUE_CLEN_PTR(queue)); ++ /* decrement grandparent's cummulative length */ ++ DHD_CUMM_CTR_DECR(DHD_FLOW_QUEUE_L2CLEN_PTR(queue)); ++ ++ FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); /* dettach packet from queue */ ++ ++done: ++ return pkt; ++} ++ ++/** Reinsert a dequeued 802.3 packet back at the head */ ++void BCMFASTPATH ++dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt) ++{ ++ if (queue->head == NULL) { ++ queue->tail = pkt; ++ } ++ ++ FLOW_QUEUE_PKT_SETNEXT(pkt, queue->head); ++ queue->head = pkt; ++ queue->len++; ++ /* increment parent's cummulative length */ ++ DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_CLEN_PTR(queue)); ++ /* increment grandparent's cummulative length */ ++ DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_L2CLEN_PTR(queue)); ++} ++ ++/** Fetch the backup queue for a flowring, and assign flow control thresholds */ ++void ++dhd_flow_ring_config_thresholds(dhd_pub_t *dhdp, uint16 flowid, ++ int queue_budget, int cumm_threshold, void *cumm_ctr, ++ int l2cumm_threshold, void *l2cumm_ctr) ++{ ++ flow_queue_t * queue; ++ ++ ASSERT(dhdp != (dhd_pub_t*)NULL); ++ ASSERT(queue_budget > 1); ++ ASSERT(cumm_threshold > 1); ++ ASSERT(cumm_ctr != (void*)NULL); ++ ASSERT(l2cumm_threshold > 1); ++ ASSERT(l2cumm_ctr != (void*)NULL); ++ ++ queue = dhd_flow_queue(dhdp, flowid); ++ ++ DHD_FLOW_QUEUE_SET_MAX(queue, queue_budget); /* Max queue length */ ++ ++ /* Set the queue's parent threshold and cummulative counter */ ++ DHD_FLOW_QUEUE_SET_THRESHOLD(queue, cumm_threshold); ++ DHD_FLOW_QUEUE_SET_CLEN(queue, cumm_ctr); ++ ++ /* Set the queue's grandparent threshold and cummulative counter */ ++ DHD_FLOW_QUEUE_SET_L2THRESHOLD(queue, l2cumm_threshold); ++ DHD_FLOW_QUEUE_SET_L2CLEN(queue, l2cumm_ctr); ++} ++ ++/** Initializes data structures of multiple flow rings */ ++int ++dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings) ++{ ++ uint32 idx; ++ uint32 flow_ring_table_sz; ++ uint32 if_flow_lkup_sz = 0; ++ void * flowid_allocator; ++ flow_ring_table_t *flow_ring_table = NULL; ++ if_flow_lkup_t *if_flow_lkup = NULL; ++ void *lock = NULL; ++ void *list_lock = NULL; ++ unsigned long flags; ++ ++ DHD_INFO(("%s\n", __FUNCTION__)); ++ ++ /* Construct a 16bit flowid allocator */ ++ flowid_allocator = id16_map_init(dhdp->osh, ++ num_flow_rings - dhdp->bus->max_cmn_rings, FLOWID_RESERVED); ++ if (flowid_allocator == NULL) { ++ DHD_ERROR(("%s: flowid allocator init failure\n", __FUNCTION__)); ++ return BCME_NOMEM; ++ } ++ ++ /* Allocate a flow ring table, comprising of requested number of rings */ ++ flow_ring_table_sz = (num_flow_rings * sizeof(flow_ring_node_t)); ++ flow_ring_table = (flow_ring_table_t *)MALLOCZ(dhdp->osh, flow_ring_table_sz); ++ if (flow_ring_table == NULL) { ++ DHD_ERROR(("%s: flow ring table alloc failure\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* Initialize flow ring table state */ ++ DHD_CUMM_CTR_INIT(&dhdp->cumm_ctr); ++ DHD_CUMM_CTR_INIT(&dhdp->l2cumm_ctr); ++ bzero((uchar *)flow_ring_table, flow_ring_table_sz); ++ for (idx = 0; idx < num_flow_rings; idx++) { ++ flow_ring_table[idx].status = FLOW_RING_STATUS_CLOSED; ++ flow_ring_table[idx].flowid = (uint16)idx; ++ flow_ring_table[idx].lock = dhd_os_spin_lock_init(dhdp->osh); ++#ifdef IDLE_TX_FLOW_MGMT ++ flow_ring_table[idx].last_active_ts = OSL_SYSUPTIME(); ++#endif /* IDLE_TX_FLOW_MGMT */ ++ if (flow_ring_table[idx].lock == NULL) { ++ DHD_ERROR(("%s: Failed to init spinlock for queue!\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ dll_init(&flow_ring_table[idx].list); ++ ++ /* Initialize the per flow ring backup queue */ ++ dhd_flow_queue_init(dhdp, &flow_ring_table[idx].queue, ++ FLOW_RING_QUEUE_THRESHOLD); ++ } ++ ++ /* Allocate per interface hash table (for fast lookup from interface to flow ring) */ ++ if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS; ++ if_flow_lkup = (if_flow_lkup_t *)DHD_OS_PREALLOC(dhdp, ++ DHD_PREALLOC_IF_FLOW_LKUP, if_flow_lkup_sz); ++ if (if_flow_lkup == NULL) { ++ DHD_ERROR(("%s: if flow lkup alloc failure\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* Initialize per interface hash table */ ++ for (idx = 0; idx < DHD_MAX_IFS; idx++) { ++ int hash_ix; ++ if_flow_lkup[idx].status = 0; ++ if_flow_lkup[idx].role = 0; ++ for (hash_ix = 0; hash_ix < DHD_FLOWRING_HASH_SIZE; hash_ix++) ++ if_flow_lkup[idx].fl_hash[hash_ix] = NULL; ++ } ++ ++ lock = dhd_os_spin_lock_init(dhdp->osh); ++ if (lock == NULL) ++ goto fail; ++ ++ list_lock = dhd_os_spin_lock_init(dhdp->osh); ++ if (list_lock == NULL) ++ goto lock_fail; ++ ++ dhdp->flow_prio_map_type = DHD_FLOW_PRIO_AC_MAP; ++ bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); ++#ifdef DHD_LOSSLESS_ROAMING ++ dhdp->dequeue_prec_map = ALLPRIO; ++#endif ++ /* Now populate into dhd pub */ ++ DHD_FLOWID_LOCK(lock, flags); ++ dhdp->num_flow_rings = num_flow_rings; ++ dhdp->flowid_allocator = (void *)flowid_allocator; ++ dhdp->flow_ring_table = (void *)flow_ring_table; ++ dhdp->if_flow_lkup = (void *)if_flow_lkup; ++ dhdp->flowid_lock = lock; ++ dhdp->flow_rings_inited = TRUE; ++ dhdp->flowring_list_lock = list_lock; ++ DHD_FLOWID_UNLOCK(lock, flags); ++ ++ DHD_INFO(("%s done\n", __FUNCTION__)); ++ return BCME_OK; ++ ++lock_fail: ++ /* deinit the spinlock */ ++ dhd_os_spin_lock_deinit(dhdp->osh, lock); ++ ++fail: ++ /* Destruct the per interface flow lkup table */ ++ if (if_flow_lkup != NULL) { ++ DHD_OS_PREFREE(dhdp, if_flow_lkup, if_flow_lkup_sz); ++ } ++ if (flow_ring_table != NULL) { ++ for (idx = 0; idx < num_flow_rings; idx++) { ++ if (flow_ring_table[idx].lock != NULL) ++ dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].lock); ++ } ++ MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz); ++ } ++ id16_map_fini(dhdp->osh, flowid_allocator); ++ ++ return BCME_NOMEM; ++} ++ ++/** Deinit Flow Ring specific data structures */ ++void dhd_flow_rings_deinit(dhd_pub_t *dhdp) ++{ ++ uint16 idx; ++ uint32 flow_ring_table_sz; ++ uint32 if_flow_lkup_sz; ++ flow_ring_table_t *flow_ring_table; ++ unsigned long flags; ++ void *lock; ++ ++ DHD_INFO(("dhd_flow_rings_deinit\n")); ++ ++ if (!(dhdp->flow_rings_inited)) { ++ DHD_ERROR(("dhd_flow_rings not initialized!\n")); ++ return; ++ } ++ ++ if (dhdp->flow_ring_table != NULL) { ++ ++ ASSERT(dhdp->num_flow_rings > 0); ++ ++ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); ++ flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; ++ dhdp->flow_ring_table = NULL; ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ for (idx = 0; idx < dhdp->num_flow_rings; idx++) { ++ if (flow_ring_table[idx].active) { ++ dhd_bus_clean_flow_ring(dhdp->bus, &flow_ring_table[idx]); ++ } ++ ASSERT(DHD_FLOW_QUEUE_EMPTY(&flow_ring_table[idx].queue)); ++ ++ /* Deinit flow ring queue locks before destroying flow ring table */ ++ if (flow_ring_table[idx].lock != NULL) { ++ dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].lock); ++ } ++ flow_ring_table[idx].lock = NULL; ++ ++ } ++ ++ /* Destruct the flow ring table */ ++ flow_ring_table_sz = dhdp->num_flow_rings * sizeof(flow_ring_table_t); ++ MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz); ++ } ++ ++ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); ++ ++ /* Destruct the per interface flow lkup table */ ++ if (dhdp->if_flow_lkup != NULL) { ++ if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS; ++ bzero((uchar *)dhdp->if_flow_lkup, if_flow_lkup_sz); ++ DHD_OS_PREFREE(dhdp, dhdp->if_flow_lkup, if_flow_lkup_sz); ++ dhdp->if_flow_lkup = NULL; ++ } ++ ++ /* Destruct the flowid allocator */ ++ if (dhdp->flowid_allocator != NULL) ++ dhdp->flowid_allocator = id16_map_fini(dhdp->osh, dhdp->flowid_allocator); ++ ++ dhdp->num_flow_rings = 0U; ++ bzero(dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); ++ ++ lock = dhdp->flowid_lock; ++ dhdp->flowid_lock = NULL; ++ ++ if (lock) { ++ DHD_FLOWID_UNLOCK(lock, flags); ++ dhd_os_spin_lock_deinit(dhdp->osh, lock); ++ } ++ ++ dhd_os_spin_lock_deinit(dhdp->osh, dhdp->flowring_list_lock); ++ dhdp->flowring_list_lock = NULL; ++ ++ ASSERT(dhdp->if_flow_lkup == NULL); ++ ASSERT(dhdp->flowid_allocator == NULL); ++ ASSERT(dhdp->flow_ring_table == NULL); ++ dhdp->flow_rings_inited = FALSE; ++} ++ ++/** Uses hash table to quickly map from ifindex to a flow ring 'role' (STA/AP) */ ++uint8 ++dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex) ++{ ++ if_flow_lkup_t *if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; ++ ASSERT(if_flow_lkup); ++ return if_flow_lkup[ifindex].role; ++} ++ ++#ifdef WLTDLS ++bool is_tdls_destination(dhd_pub_t *dhdp, uint8 *da) ++{ ++ unsigned long flags; ++ tdls_peer_node_t *cur = NULL; ++ ++ DHD_TDLS_LOCK(&dhdp->tdls_lock, flags); ++ cur = dhdp->peer_tbl.node; ++ ++ while (cur != NULL) { ++ if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { ++ DHD_TDLS_UNLOCK(&dhdp->tdls_lock, flags); ++ return TRUE; ++ } ++ cur = cur->next; ++ } ++ DHD_TDLS_UNLOCK(&dhdp->tdls_lock, flags); ++ return FALSE; ++} ++#endif /* WLTDLS */ ++ ++/** Uses hash table to quickly map from ifindex+prio+da to a flow ring id */ ++static INLINE uint16 ++dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) ++{ ++ int hash; ++ bool ismcast = FALSE; ++ flow_hash_info_t *cur; ++ if_flow_lkup_t *if_flow_lkup; ++ unsigned long flags; ++ ++ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); ++ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; ++ ++ ASSERT(if_flow_lkup); ++ ++ if ((if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) || ++ (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_WDS)) { ++#ifdef WLTDLS ++ if (dhdp->peer_tbl.tdls_peer_count && !(ETHER_ISMULTI(da)) && ++ is_tdls_destination(dhdp, da)) { ++ hash = DHD_FLOWRING_HASHINDEX(da, prio); ++ cur = if_flow_lkup[ifindex].fl_hash[hash]; ++ while (cur != NULL) { ++ if (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN)) { ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ return cur->flowid; ++ } ++ cur = cur->next; ++ } ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ return FLOWID_INVALID; ++ } ++#endif /* WLTDLS */ ++ /* For STA non TDLS dest and WDS dest flow ring id is mapped based on prio only */ ++ cur = if_flow_lkup[ifindex].fl_hash[prio]; ++ if (cur) { ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ return cur->flowid; ++ } ++ } else { ++ ++ if (ETHER_ISMULTI(da)) { ++ ismcast = TRUE; ++ hash = 0; ++ } else { ++ hash = DHD_FLOWRING_HASHINDEX(da, prio); ++ } ++ ++ cur = if_flow_lkup[ifindex].fl_hash[hash]; ++ ++ while (cur) { ++ if ((ismcast && ETHER_ISMULTI(cur->flow_info.da)) || ++ (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN) && ++ (cur->flow_info.tid == prio))) { ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ return cur->flowid; ++ } ++ cur = cur->next; ++ } ++ } ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ ++ DHD_INFO(("%s: cannot find flowid\n", __FUNCTION__)); ++ return FLOWID_INVALID; ++} /* dhd_flowid_find */ ++ ++/** Create unique Flow ID, called when a flow ring is created. */ ++static INLINE uint16 ++dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) ++{ ++ flow_hash_info_t *fl_hash_node, *cur; ++ if_flow_lkup_t *if_flow_lkup; ++ int hash; ++ uint16 flowid; ++ unsigned long flags; ++ ++ fl_hash_node = (flow_hash_info_t *) MALLOCZ(dhdp->osh, sizeof(flow_hash_info_t)); ++ if (fl_hash_node == NULL) { ++ DHD_ERROR(("%s: flow_hash_info_t memory allocation failed \n", __FUNCTION__)); ++ return FLOWID_INVALID; ++ } ++ memcpy(fl_hash_node->flow_info.da, da, sizeof(fl_hash_node->flow_info.da)); ++ ++ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); ++ ASSERT(dhdp->flowid_allocator != NULL); ++ flowid = id16_map_alloc(dhdp->flowid_allocator); ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ ++ if (flowid == FLOWID_INVALID) { ++ MFREE(dhdp->osh, fl_hash_node, sizeof(flow_hash_info_t)); ++ DHD_ERROR(("%s: cannot get free flowid \n", __FUNCTION__)); ++ return FLOWID_INVALID; ++ } ++ ++ fl_hash_node->flowid = flowid; ++ fl_hash_node->flow_info.tid = prio; ++ fl_hash_node->flow_info.ifindex = ifindex; ++ fl_hash_node->next = NULL; ++ ++ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); ++ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; ++ ++ if ((if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) || ++ (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_WDS)) { ++ /* For STA non TDLS dest and WDS dest we allocate entry based on prio only */ ++#ifdef WLTDLS ++ if (dhdp->peer_tbl.tdls_peer_count && ++ (is_tdls_destination(dhdp, da))) { ++ hash = DHD_FLOWRING_HASHINDEX(da, prio); ++ cur = if_flow_lkup[ifindex].fl_hash[hash]; ++ if (cur) { ++ while (cur->next) { ++ cur = cur->next; ++ } ++ cur->next = fl_hash_node; ++ } else { ++ if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node; ++ } ++ } else ++#endif /* WLTDLS */ ++ if_flow_lkup[ifindex].fl_hash[prio] = fl_hash_node; ++ } else { ++ ++ /* For bcast/mcast assign first slot in in interface */ ++ hash = ETHER_ISMULTI(da) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio); ++ cur = if_flow_lkup[ifindex].fl_hash[hash]; ++ if (cur) { ++ while (cur->next) { ++ cur = cur->next; ++ } ++ cur->next = fl_hash_node; ++ } else ++ if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node; ++ } ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ ++ DHD_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid)); ++ ++ return fl_hash_node->flowid; ++} /* dhd_flowid_alloc */ ++ ++/** Get flow ring ID, if not present try to create one */ ++static INLINE int ++dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, ++ uint8 prio, char *sa, char *da, uint16 *flowid) ++{ ++ uint16 id; ++ flow_ring_node_t *flow_ring_node; ++ flow_ring_table_t *flow_ring_table; ++ unsigned long flags; ++ int ret; ++ bool is_sta_assoc; ++ ++ DHD_INFO(("%s\n", __FUNCTION__)); ++ if (!dhdp->flow_ring_table) { ++ return BCME_ERROR; ++ } ++ ++ flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; ++ ++ id = dhd_flowid_find(dhdp, ifindex, prio, sa, da); ++ ++ if (id == FLOWID_INVALID) { ++ ++ if_flow_lkup_t *if_flow_lkup; ++ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; ++ ++ if (!if_flow_lkup[ifindex].status) ++ return BCME_ERROR; ++ BCM_REFERENCE(is_sta_assoc); ++#if defined(PCIE_FULL_DONGLE) ++ is_sta_assoc = dhd_sta_associated(dhdp, ifindex, (uint8 *)da); ++ DHD_ERROR(("%s: multi %x ifindex %d role %x assoc %d\n", __FUNCTION__, ++ ETHER_ISMULTI(da), ifindex, if_flow_lkup[ifindex].role, ++ is_sta_assoc)); ++ if (!ETHER_ISMULTI(da) && ++ ((if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_AP) || ++ (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_P2P_GO)) && ++ (!is_sta_assoc)) ++ return BCME_ERROR; ++#endif /* (linux || LINUX) && PCIE_FULL_DONGLE */ ++ ++ id = dhd_flowid_alloc(dhdp, ifindex, prio, sa, da); ++ if (id == FLOWID_INVALID) { ++ DHD_ERROR(("%s: alloc flowid ifindex %u status %u\n", ++ __FUNCTION__, ifindex, if_flow_lkup[ifindex].status)); ++ return BCME_ERROR; ++ } ++ ++ ASSERT(id < dhdp->num_flow_rings); ++ ++ /* register this flowid in dhd_pub */ ++ dhd_add_flowid(dhdp, ifindex, prio, da, id); ++ ++ flow_ring_node = (flow_ring_node_t *) &flow_ring_table[id]; ++ ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); ++ ++ /* Init Flow info */ ++ memcpy(flow_ring_node->flow_info.sa, sa, sizeof(flow_ring_node->flow_info.sa)); ++ memcpy(flow_ring_node->flow_info.da, da, sizeof(flow_ring_node->flow_info.da)); ++ flow_ring_node->flow_info.tid = prio; ++ flow_ring_node->flow_info.ifindex = ifindex; ++ flow_ring_node->active = TRUE; ++ flow_ring_node->status = FLOW_RING_STATUS_CREATE_PENDING; ++ ++#ifdef DEVICE_TX_STUCK_DETECT ++ flow_ring_node->tx_cmpl = flow_ring_node->tx_cmpl_prev = OSL_SYSUPTIME(); ++ flow_ring_node->stuck_count = 0; ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ ++ /* Create and inform device about the new flow */ ++ if (dhd_bus_flow_ring_create_request(dhdp->bus, (void *)flow_ring_node) ++ != BCME_OK) { ++ DHD_ERROR(("%s: create error %d\n", __FUNCTION__, id)); ++ return BCME_ERROR; ++ } ++ ++ *flowid = id; ++ return BCME_OK; ++ } else { ++ /* if the Flow id was found in the hash */ ++ ASSERT(id < dhdp->num_flow_rings); ++ ++ flow_ring_node = (flow_ring_node_t *) &flow_ring_table[id]; ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); ++ ++ /* ++ * If the flow_ring_node is in Open State or Status pending state then ++ * we can return the Flow id to the caller.If the flow_ring_node is in ++ * FLOW_RING_STATUS_PENDING this means the creation is in progress and ++ * hence the packets should be queued. ++ * ++ * If the flow_ring_node is in FLOW_RING_STATUS_DELETE_PENDING Or ++ * FLOW_RING_STATUS_CLOSED, then we should return Error. ++ * Note that if the flowing is being deleted we would mark it as ++ * FLOW_RING_STATUS_DELETE_PENDING. Now before Dongle could respond and ++ * before we mark it as FLOW_RING_STATUS_CLOSED we could get tx packets. ++ * We should drop the packets in that case. ++ * The decission to return OK should NOT be based on 'active' variable, beause ++ * active is made TRUE when a flow_ring_node gets allocated and is made ++ * FALSE when the flow ring gets removed and does not reflect the True state ++ * of the Flow ring. ++ * In case if IDLE_TX_FLOW_MGMT is defined, we have to handle two more flowring ++ * states. If the flow_ring_node's status is FLOW_RING_STATUS_SUSPENDED, the flowid ++ * is to be returned and from dhd_bus_txdata, the flowring would be resumed again. ++ * The status FLOW_RING_STATUS_RESUME_PENDING, is equivalent to ++ * FLOW_RING_STATUS_CREATE_PENDING. ++ */ ++ if (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING || ++ flow_ring_node->status == FLOW_RING_STATUS_CLOSED) { ++ *flowid = FLOWID_INVALID; ++ ret = BCME_ERROR; ++ } else { ++ *flowid = id; ++ ret = BCME_OK; ++ } ++ ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ return ret; ++ } /* Flow Id found in the hash */ ++} /* dhd_flowid_lookup */ ++ ++/** ++ * Assign existing or newly created flowid to an 802.3 packet. This flowid is later on used to ++ * select the flowring to send the packet to the dongle. ++ */ ++int BCMFASTPATH ++dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, void *pktbuf) ++{ ++ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); ++ struct ether_header *eh = (struct ether_header *)pktdata; ++ uint16 flowid; ++ ++ ASSERT(ifindex < DHD_MAX_IFS); ++ ++ if (ifindex >= DHD_MAX_IFS) { ++ return BCME_BADARG; ++ } ++ ++ if (!dhdp->flowid_allocator) { ++ DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ if (dhd_flowid_lookup(dhdp, ifindex, prio, (char *)eh->ether_shost, (char *)eh->ether_dhost, ++ &flowid) != BCME_OK) { ++ return BCME_ERROR; ++ } ++ ++ DHD_INFO(("%s: prio %d flowid %d\n", __FUNCTION__, prio, flowid)); ++ ++ /* Tag the packet with flowid */ ++ DHD_PKT_SET_FLOWID(pktbuf, flowid); ++ return BCME_OK; ++} ++ ++void ++dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid) ++{ ++ int hashix; ++ bool found = FALSE; ++ flow_hash_info_t *cur, *prev; ++ if_flow_lkup_t *if_flow_lkup; ++ unsigned long flags; ++ ++ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); ++ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; ++ ++ for (hashix = 0; hashix < DHD_FLOWRING_HASH_SIZE; hashix++) { ++ ++ cur = if_flow_lkup[ifindex].fl_hash[hashix]; ++ ++ if (cur) { ++ if (cur->flowid == flowid) { ++ found = TRUE; ++ } ++ ++ prev = NULL; ++ while (!found && cur) { ++ if (cur->flowid == flowid) { ++ found = TRUE; ++ break; ++ } ++ prev = cur; ++ cur = cur->next; ++ } ++ if (found) { ++ if (!prev) { ++ if_flow_lkup[ifindex].fl_hash[hashix] = cur->next; ++ } else { ++ prev->next = cur->next; ++ } ++ ++ /* deregister flowid from dhd_pub. */ ++ dhd_del_flowid(dhdp, ifindex, flowid); ++ ++ id16_map_free(dhdp->flowid_allocator, flowid); ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ MFREE(dhdp->osh, cur, sizeof(flow_hash_info_t)); ++ ++ return; ++ } ++ } ++ } ++ ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ DHD_ERROR(("%s: could not free flow ring hash entry flowid %d\n", ++ __FUNCTION__, flowid)); ++} /* dhd_flowid_free */ ++ ++/** ++ * Delete all Flow rings associated with the given interface. Is called when eg the dongle ++ * indicates that a wireless link has gone down. ++ */ ++void ++dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex) ++{ ++ uint32 id; ++ flow_ring_table_t *flow_ring_table; ++ ++ DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex)); ++ ++ ASSERT(ifindex < DHD_MAX_IFS); ++ if (ifindex >= DHD_MAX_IFS) ++ return; ++ ++ if (!dhdp->flow_ring_table) ++ return; ++ ++ flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; ++ for (id = 0; id < dhdp->num_flow_rings; id++) { ++ if (flow_ring_table[id].active && ++ (flow_ring_table[id].flow_info.ifindex == ifindex) && ++ (flow_ring_table[id].status == FLOW_RING_STATUS_OPEN)) { ++ dhd_bus_flow_ring_delete_request(dhdp->bus, ++ (void *) &flow_ring_table[id]); ++ } ++ } ++} ++ ++void ++dhd_flow_rings_flush(dhd_pub_t *dhdp, uint8 ifindex) ++{ ++ uint32 id; ++ flow_ring_table_t *flow_ring_table; ++ ++ DHD_INFO(("%s: ifindex %u\n", __FUNCTION__, ifindex)); ++ ++ ASSERT(ifindex < DHD_MAX_IFS); ++ if (ifindex >= DHD_MAX_IFS) ++ return; ++ ++ if (!dhdp->flow_ring_table) ++ return; ++ flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; ++ ++ for (id = 0; id <= dhdp->num_flow_rings; id++) { ++ if (flow_ring_table[id].active && ++ (flow_ring_table[id].flow_info.ifindex == ifindex) && ++ (flow_ring_table[id].status == FLOW_RING_STATUS_OPEN)) { ++ dhd_bus_flow_ring_flush_request(dhdp->bus, ++ (void *) &flow_ring_table[id]); ++ } ++ } ++} ++ ++ ++/** Delete flow ring(s) for given peer address. Related to AP/AWDL/TDLS functionality. */ ++void ++dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, char *addr) ++{ ++ uint32 id; ++ flow_ring_table_t *flow_ring_table; ++ ++ DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex)); ++ ++ ASSERT(ifindex < DHD_MAX_IFS); ++ if (ifindex >= DHD_MAX_IFS) ++ return; ++ ++ if (!dhdp->flow_ring_table) ++ return; ++ ++ flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; ++ for (id = 0; id < dhdp->num_flow_rings; id++) { ++ if (flow_ring_table[id].active && ++ (flow_ring_table[id].flow_info.ifindex == ifindex) && ++ (!memcmp(flow_ring_table[id].flow_info.da, addr, ETHER_ADDR_LEN)) && ++ (flow_ring_table[id].status == FLOW_RING_STATUS_OPEN)) { ++ DHD_ERROR(("%s: deleting flowid %d\n", ++ __FUNCTION__, flow_ring_table[id].flowid)); ++ dhd_bus_flow_ring_delete_request(dhdp->bus, ++ (void *) &flow_ring_table[id]); ++ } ++ } ++} ++ ++/** Handles interface ADD, CHANGE, DEL indications from the dongle */ ++void ++dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex, ++ uint8 op, uint8 role) ++{ ++ if_flow_lkup_t *if_flow_lkup; ++ unsigned long flags; ++ ++ ASSERT(ifindex < DHD_MAX_IFS); ++ if (ifindex >= DHD_MAX_IFS) ++ return; ++ ++ DHD_ERROR(("%s: ifindex %u op %u role is %u \n", ++ __FUNCTION__, ifindex, op, role)); ++ if (!dhdp->flowid_allocator) { ++ DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); ++ return; ++ } ++ ++ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); ++ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; ++ ++ if (op == WLC_E_IF_ADD || op == WLC_E_IF_CHANGE) { ++ ++ if_flow_lkup[ifindex].role = role; ++ ++ if (role == WLC_E_IF_ROLE_WDS) { ++ /** ++ * WDS role does not send WLC_E_LINK event after interface is up. ++ * So to create flowrings for WDS, make status as TRUE in WLC_E_IF itself. ++ * same is true while making the status as FALSE. ++ * TODO: Fix FW to send WLC_E_LINK for WDS role aswell. So that all the ++ * interfaces are handled uniformly. ++ */ ++ if_flow_lkup[ifindex].status = TRUE; ++ DHD_INFO(("%s: Mcast Flow ring for ifindex %d role is %d \n", ++ __FUNCTION__, ifindex, role)); ++ } ++ } else if ((op == WLC_E_IF_DEL) && (role == WLC_E_IF_ROLE_WDS)) { ++ if_flow_lkup[ifindex].status = FALSE; ++ DHD_INFO(("%s: cleanup all Flow rings for ifindex %d role is %d \n", ++ __FUNCTION__, ifindex, role)); ++ } ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++} ++ ++/** Handles a STA 'link' indication from the dongle */ ++int ++dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, uint8 status) ++{ ++ if_flow_lkup_t *if_flow_lkup; ++ unsigned long flags; ++ ++ ASSERT(ifindex < DHD_MAX_IFS); ++ if (ifindex >= DHD_MAX_IFS) ++ return BCME_BADARG; ++ ++ DHD_ERROR(("%s: ifindex %d status %d\n", __FUNCTION__, ifindex, status)); ++ ++ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); ++ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; ++ ++ if (status) { ++ if_flow_lkup[ifindex].status = TRUE; ++ } else { ++ if_flow_lkup[ifindex].status = FALSE; ++ } ++ ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ ++ return BCME_OK; ++} ++ ++/** Update flow priority mapping, called on IOVAR */ ++int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map) ++{ ++ uint16 flowid; ++ flow_ring_node_t *flow_ring_node; ++ ++ if (map > DHD_FLOW_PRIO_LLR_MAP) ++ return BCME_BADOPTION; ++ ++ /* Check if we need to change prio map */ ++ if (map == dhdp->flow_prio_map_type) ++ return BCME_OK; ++ ++ /* If any ring is active we cannot change priority mapping for flow rings */ ++ for (flowid = 0; flowid < dhdp->num_flow_rings; flowid++) { ++ flow_ring_node = DHD_FLOW_RING(dhdp, flowid); ++ if (flow_ring_node->active) ++ return BCME_EPERM; ++ } ++ ++ /* Inform firmware about new mapping type */ ++ if (BCME_OK != dhd_flow_prio_map(dhdp, &map, TRUE)) ++ return BCME_ERROR; ++ ++ /* update internal structures */ ++ dhdp->flow_prio_map_type = map; ++ if (dhdp->flow_prio_map_type == DHD_FLOW_PRIO_TID_MAP) ++ bcopy(prio2tid, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); ++ else ++ bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); ++ ++ return BCME_OK; ++} ++ ++/** Inform firmware on updated flow priority mapping, called on IOVAR */ ++int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set) ++{ ++ uint8 iovbuf[24] = {0}; ++ if (!set) { ++ bcm_mkiovar("bus:fl_prio_map", NULL, 0, (char*)iovbuf, sizeof(iovbuf)); ++ if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) { ++ DHD_ERROR(("%s: failed to get fl_prio_map\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ *map = iovbuf[0]; ++ return BCME_OK; ++ } ++ bcm_mkiovar("bus:fl_prio_map", (char *)map, 4, (char*)iovbuf, sizeof(iovbuf)); ++ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { ++ DHD_ERROR(("%s: failed to set fl_prio_map \n", ++ __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ return BCME_OK; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_flowring.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_flowring.h +new file mode 100644 +index 000000000..d5faf0aa8 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_flowring.h +@@ -0,0 +1,275 @@ ++/* ++ * @file Header file describing the flow rings DHD interfaces. ++ * ++ * Flow rings are transmit traffic (=propagating towards antenna) related entities. ++ * ++ * Provides type definitions and function prototypes used to create, delete and manage flow rings at ++ * high level. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_flowring.h 672438 2016-11-28 12:35:24Z $ ++ */ ++ ++ ++/**************** ++ * Common types * ++ */ ++ ++#ifndef _dhd_flowrings_h_ ++#define _dhd_flowrings_h_ ++ ++/* Max pkts held in a flow ring's backup queue */ ++#define FLOW_RING_QUEUE_THRESHOLD (2048) ++ ++/* Number of H2D common rings */ ++#define FLOW_RING_COMMON BCMPCIE_H2D_COMMON_MSGRINGS ++ ++#define FLOWID_INVALID (ID16_INVALID) ++#define FLOWID_RESERVED (FLOW_RING_COMMON) ++ ++#define FLOW_RING_STATUS_OPEN 0 ++#define FLOW_RING_STATUS_CREATE_PENDING 1 ++#define FLOW_RING_STATUS_CLOSED 2 ++#define FLOW_RING_STATUS_DELETE_PENDING 3 ++#define FLOW_RING_STATUS_FLUSH_PENDING 4 ++ ++#ifdef IDLE_TX_FLOW_MGMT ++#define FLOW_RING_STATUS_SUSPENDED 5 ++#define FLOW_RING_STATUS_RESUME_PENDING 6 ++#endif /* IDLE_TX_FLOW_MGMT */ ++#define FLOW_RING_STATUS_STA_FREEING 7 ++ ++#ifdef DHD_EFI ++#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 1600 ++#else ++#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 2048 ++#endif ++ ++#define DHD_FLOW_PRIO_AC_MAP 0 ++#define DHD_FLOW_PRIO_TID_MAP 1 ++/* Flow ring prority map for lossless roaming */ ++#define DHD_FLOW_PRIO_LLR_MAP 2 ++ ++/* Hashing a MacAddress for lkup into a per interface flow hash table */ ++#define DHD_FLOWRING_HASH_SIZE 256 ++#define DHD_FLOWRING_HASHINDEX(ea, prio) \ ++ ((((uint8 *)(ea))[3] ^ ((uint8 *)(ea))[4] ^ ((uint8 *)(ea))[5] ^ ((uint8)(prio))) \ ++ % DHD_FLOWRING_HASH_SIZE) ++ ++#define DHD_IF_ROLE(pub, idx) (((if_flow_lkup_t *)(pub)->if_flow_lkup)[idx].role) ++#define DHD_IF_ROLE_AP(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_AP) ++#define DHD_IF_ROLE_STA(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_STA) ++#define DHD_IF_ROLE_P2PGO(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_P2P_GO) ++#define DHD_IF_ROLE_WDS(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_WDS) ++#define DHD_FLOW_RING(dhdp, flowid) \ ++ (flow_ring_node_t *)&(((flow_ring_node_t *)((dhdp)->flow_ring_table))[flowid]) ++ ++struct flow_queue; ++ ++/* Flow Ring Queue Enqueue overflow callback */ ++typedef int (*flow_queue_cb_t)(struct flow_queue * queue, void * pkt); ++ ++/** ++ * Each flow ring has an associated (tx flow controlled) queue. 802.3 packets are transferred ++ * between queue and ring. A packet from the host stack is first added to the queue, and in a later ++ * stage transferred to the flow ring. Packets in the queue are dhd owned, whereas packets in the ++ * flow ring are device owned. ++ */ ++typedef struct flow_queue { ++ dll_t list; /* manage a flowring queue in a double linked list */ ++ void * head; /* first packet in the queue */ ++ void * tail; /* last packet in the queue */ ++ uint16 len; /* number of packets in the queue */ ++ uint16 max; /* maximum or min budget (used in cumm) */ ++ uint32 threshold; /* parent's cummulative length threshold */ ++ void * clen_ptr; /* parent's cummulative length counter */ ++ uint32 failures; /* enqueue failures due to queue overflow */ ++ flow_queue_cb_t cb; /* callback invoked on threshold crossing */ ++ uint32 l2threshold; /* grandparent's (level 2) cummulative length threshold */ ++ void * l2clen_ptr; /* grandparent's (level 2) cummulative length counter */ ++} flow_queue_t; ++ ++#define DHD_FLOW_QUEUE_LEN(queue) ((int)(queue)->len) ++#define DHD_FLOW_QUEUE_MAX(queue) ((int)(queue)->max) ++#define DHD_FLOW_QUEUE_THRESHOLD(queue) ((int)(queue)->threshold) ++#define DHD_FLOW_QUEUE_L2THRESHOLD(queue) ((int)(queue)->l2threshold) ++#define DHD_FLOW_QUEUE_EMPTY(queue) ((queue)->len == 0) ++#define DHD_FLOW_QUEUE_FAILURES(queue) ((queue)->failures) ++ ++#define DHD_FLOW_QUEUE_AVAIL(queue) ((int)((queue)->max - (queue)->len)) ++#define DHD_FLOW_QUEUE_FULL(queue) ((queue)->len >= (queue)->max) ++ ++#define DHD_FLOW_QUEUE_OVFL(queue, budget) \ ++ (((queue)->len) > budget) ++ ++#define DHD_FLOW_QUEUE_SET_MAX(queue, budget) \ ++ ((queue)->max) = ((budget) - 1) ++ ++/* Queue's cummulative threshold. */ ++#define DHD_FLOW_QUEUE_SET_THRESHOLD(queue, cumm_threshold) \ ++ ((queue)->threshold) = ((cumm_threshold) - 1) ++ ++/* Queue's cummulative length object accessor. */ ++#define DHD_FLOW_QUEUE_CLEN_PTR(queue) ((queue)->clen_ptr) ++ ++/* Set a queue's cumm_len point to a parent's cumm_ctr_t cummulative length */ ++#define DHD_FLOW_QUEUE_SET_CLEN(queue, parent_clen_ptr) \ ++ ((queue)->clen_ptr) = (void *)(parent_clen_ptr) ++ ++/* Queue's level 2 cummulative threshold. */ ++#define DHD_FLOW_QUEUE_SET_L2THRESHOLD(queue, l2cumm_threshold) \ ++ ((queue)->l2threshold) = ((l2cumm_threshold) - 1) ++ ++/* Queue's level 2 cummulative length object accessor. */ ++#define DHD_FLOW_QUEUE_L2CLEN_PTR(queue) ((queue)->l2clen_ptr) ++ ++/* Set a queue's level 2 cumm_len point to a grandparent's cumm_ctr_t cummulative length */ ++#define DHD_FLOW_QUEUE_SET_L2CLEN(queue, grandparent_clen_ptr) \ ++ ((queue)->l2clen_ptr) = (void *)(grandparent_clen_ptr) ++ ++/* see wlfc_proto.h for tx status details */ ++#define DHD_FLOWRING_MAXSTATUS_MSGS 5 ++#define DHD_FLOWRING_TXSTATUS_CNT_UPDATE(bus, flowid, txstatus) ++ ++/* Pkttag not compatible with PROP_TXSTATUS or WLFC */ ++typedef struct dhd_pkttag_fr { ++ uint16 flowid; ++ uint16 ifid; ++ int dataoff; ++ dmaaddr_t physaddr; ++ uint32 pa_len; ++} dhd_pkttag_fr_t; ++ ++#define DHD_PKTTAG_SET_IFID(tag, idx) ((tag)->ifid = (uint16)(idx)) ++#define DHD_PKTTAG_SET_PA(tag, pa) ((tag)->physaddr = (pa)) ++#define DHD_PKTTAG_SET_PA_LEN(tag, palen) ((tag)->pa_len = (palen)) ++#define DHD_PKTTAG_IFID(tag) ((tag)->ifid) ++#define DHD_PKTTAG_PA(tag) ((tag)->physaddr) ++#define DHD_PKTTAG_PA_LEN(tag) ((tag)->pa_len) ++ ++ ++/** each flow ring is dedicated to a tid/sa/da combination */ ++typedef struct flow_info { ++ uint8 tid; ++ uint8 ifindex; ++ char sa[ETHER_ADDR_LEN]; ++ char da[ETHER_ADDR_LEN]; ++} flow_info_t; ++ ++/** a flow ring is used for outbound (towards antenna) 802.3 packets */ ++typedef struct flow_ring_node { ++ dll_t list; /* manage a constructed flowring in a dll, must be at first place */ ++ flow_queue_t queue; /* queues packets before they enter the flow ring, flow control */ ++ bool active; ++ uint8 status; ++ /* ++ * flowid: unique ID of a flow ring, which can either be unicast or broadcast/multicast. For ++ * unicast flow rings, the flow id accelerates ARM 802.3->802.11 header translation. ++ */ ++ uint16 flowid; ++ flow_info_t flow_info; ++ void *prot_info; ++ void *lock; /* lock for flowring access protection */ ++ ++#ifdef IDLE_TX_FLOW_MGMT ++ uint64 last_active_ts; /* contains last active timestamp */ ++#endif /* IDLE_TX_FLOW_MGMT */ ++#ifdef DEVICE_TX_STUCK_DETECT ++ /* Time stamp(msec) when last time a Tx packet completion is received on this flow ring */ ++ uint32 tx_cmpl; ++ /* ++ * Holds the tx_cmpl which was read during the previous ++ * iteration of the stuck detection algo ++ */ ++ uint32 tx_cmpl_prev; ++ /* counter to decide if this particlur flow is stuck or not */ ++ uint32 stuck_count; ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ ++} flow_ring_node_t; ++ ++typedef flow_ring_node_t flow_ring_table_t; ++ ++typedef struct flow_hash_info { ++ uint16 flowid; ++ flow_info_t flow_info; ++ struct flow_hash_info *next; ++} flow_hash_info_t; ++ ++typedef struct if_flow_lkup { ++ bool status; ++ uint8 role; /* Interface role: STA/AP */ ++ flow_hash_info_t *fl_hash[DHD_FLOWRING_HASH_SIZE]; /* Lkup Hash table */ ++} if_flow_lkup_t; ++ ++static INLINE flow_ring_node_t * ++dhd_constlist_to_flowring(dll_t *item) ++{ ++ return ((flow_ring_node_t *)item); ++} ++ ++/* Exported API */ ++ ++/* Flow ring's queue management functions */ ++extern flow_ring_node_t * dhd_flow_ring_node(dhd_pub_t *dhdp, uint16 flowid); ++extern flow_queue_t * dhd_flow_queue(dhd_pub_t *dhdp, uint16 flowid); ++ ++extern void dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max); ++extern void dhd_flow_queue_reinit(dhd_pub_t *dhdp, flow_queue_t *queue, int max); ++extern void dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb); ++extern int dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt); ++extern void * dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue); ++extern void dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt); ++ ++extern void dhd_flow_ring_config_thresholds(dhd_pub_t *dhdp, uint16 flowid, ++ int queue_budget, int cumm_threshold, void *cumm_ctr, ++ int l2cumm_threshold, void *l2cumm_ctr); ++extern int dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings); ++ ++extern void dhd_flow_rings_deinit(dhd_pub_t *dhdp); ++ ++extern int dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, ++ void *pktbuf); ++ ++extern void dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid); ++ ++extern void dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex); ++extern void dhd_flow_rings_flush(dhd_pub_t *dhdp, uint8 ifindex); ++ ++extern void dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, ++ char *addr); ++ ++/* Handle Interface ADD, DEL operations */ ++extern void dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex, ++ uint8 op, uint8 role); ++ ++/* Handle a STA interface link status update */ ++extern int dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, ++ uint8 status); ++extern int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set); ++extern int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map); ++ ++extern uint8 dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex); ++#endif /* _dhd_flowrings_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_gpio.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_gpio.c +new file mode 100644 +index 000000000..d5d2b9b06 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_gpio.c +@@ -0,0 +1,360 @@ ++ ++#include ++#include ++#include ++ ++#ifdef CUSTOMER_HW_PLATFORM ++#include ++#define sdmmc_channel sdmmc_device_mmc0 ++#endif /* CUSTOMER_HW_PLATFORM */ ++ ++#if defined(BUS_POWER_RESTORE) && defined(BCMSDIO) ++#include ++#include ++#include ++#include ++#endif /* defined(BUS_POWER_RESTORE) && defined(BCMSDIO) */ ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++extern void *dhd_wlan_mem_prealloc(int section, unsigned long size); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++static int gpio_wl_reg_on = -1; // WL_REG_ON is input pin of WLAN module ++#ifdef CUSTOMER_OOB ++static int gpio_wl_host_wake = -1; // WL_HOST_WAKE is output pin of WLAN module ++#endif ++ ++#ifdef CUSTOMER_HW_INGENIC ++extern int ingenic_sdio_wlan_power_onoff(int onoff, int flag); ++extern int ingenic_sdio_wlan_get_irq(unsigned long *flag); ++#define RESET 0 ++#define NORMAL 1 ++static int poweroff_num = 0; ++static int poweron_num = 0; ++#endif ++ ++static int ++dhd_wlan_set_power(int on ++#ifdef BUS_POWER_RESTORE ++, wifi_adapter_info_t *adapter ++#endif /* BUS_POWER_RESTORE */ ++) ++{ ++ int err = 0; ++ ++ if (on) { ++ printf("======== PULL WL_REG_ON(%d) HIGH! ========\n", gpio_wl_reg_on); ++ if (gpio_wl_reg_on >= 0) { ++ err = gpio_direction_output(gpio_wl_reg_on, 1); ++ if (err) { ++ printf("%s: WL_REG_ON didn't output high\n", __FUNCTION__); ++ return -EIO; ++ } ++ } ++#ifdef CUSTOMER_HW_INGENIC ++ if (poweron_num) { ++ ingenic_sdio_wlan_power_onoff(on, RESET); ++ } else { ++ poweron_num = 1; ++ ingenic_sdio_wlan_power_onoff(on, NORMAL); ++ } ++#endif ++#if defined(BUS_POWER_RESTORE) ++#if defined(BCMSDIO) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) ++ if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) { ++ mdelay(100); ++ printf("======== mmc_power_restore_host! ========\n"); ++ mmc_power_restore_host(adapter->sdio_func->card->host); ++ } ++#elif defined(BCMPCIE) ++ if (adapter->pci_dev) { ++ mdelay(100); ++ printf("======== pci_set_power_state PCI_D0! ========\n"); ++ pci_set_power_state(adapter->pci_dev, PCI_D0); ++ if (adapter->pci_saved_state) ++ pci_load_and_free_saved_state(adapter->pci_dev, &adapter->pci_saved_state); ++ pci_restore_state(adapter->pci_dev); ++ err = pci_enable_device(adapter->pci_dev); ++ if (err < 0) ++ printf("%s: PCI enable device failed", __FUNCTION__); ++ pci_set_master(adapter->pci_dev); ++ } ++#endif /* BCMPCIE */ ++#endif /* BUS_POWER_RESTORE */ ++ /* Lets customer power to get stable */ ++ mdelay(100); ++ } else { ++#if defined(BUS_POWER_RESTORE) ++#if defined(BCMSDIO) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) ++ if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) { ++ printf("======== mmc_power_save_host! ========\n"); ++ mmc_power_save_host(adapter->sdio_func->card->host); ++ } ++#elif defined(BCMPCIE) ++ if (adapter->pci_dev) { ++ printf("======== pci_set_power_state PCI_D3hot! ========\n"); ++ pci_save_state(adapter->pci_dev); ++ adapter->pci_saved_state = pci_store_saved_state(adapter->pci_dev); ++ if (pci_is_enabled(adapter->pci_dev)) ++ pci_disable_device(adapter->pci_dev); ++ pci_set_power_state(adapter->pci_dev, PCI_D3hot); ++ } ++#endif /* BCMPCIE */ ++#endif /* BUS_POWER_RESTORE */ ++ printf("======== PULL WL_REG_ON(%d) LOW! ========\n", gpio_wl_reg_on); ++ if (gpio_wl_reg_on >= 0) { ++ err = gpio_direction_output(gpio_wl_reg_on, 0); ++ if (err) { ++ printf("%s: WL_REG_ON didn't output low\n", __FUNCTION__); ++ return -EIO; ++ } ++ } ++#ifdef CUSTOMER_HW_INGENIC ++ if (poweron_num) { ++ ingenic_sdio_wlan_power_onoff(on, RESET); ++ } else { ++ poweroff_num = 1; ++ ingenic_sdio_wlan_power_onoff(on, NORMAL); ++ } ++#endif ++ } ++ ++ return err; ++} ++ ++static int dhd_wlan_set_reset(int onoff) ++{ ++ return 0; ++} ++ ++static int dhd_wlan_set_carddetect(int present) ++{ ++ int err = 0; ++ ++#if !defined(BUS_POWER_RESTORE) ++ if (present) { ++#if defined(BCMSDIO) ++ printf("======== Card detection to detect SDIO card! ========\n"); ++#ifdef CUSTOMER_HW_PLATFORM ++ err = sdhci_force_presence_change(&sdmmc_channel, 1); ++#endif /* CUSTOMER_HW_PLATFORM */ ++#elif defined(BCMPCIE) ++ printf("======== Card detection to detect PCIE card! ========\n"); ++#endif ++ } else { ++#if defined(BCMSDIO) ++ printf("======== Card detection to remove SDIO card! ========\n"); ++#ifdef CUSTOMER_HW_PLATFORM ++ err = sdhci_force_presence_change(&sdmmc_channel, 0); ++#endif /* CUSTOMER_HW_PLATFORM */ ++#elif defined(BCMPCIE) ++ printf("======== Card detection to remove PCIE card! ========\n"); ++#endif ++ } ++#endif /* BUS_POWER_RESTORE */ ++ ++ return err; ++} ++ ++static int dhd_wlan_get_mac_addr(unsigned char *buf) ++{ ++ int err = 0; ++ ++ printf("======== %s ========\n", __FUNCTION__); ++#ifdef EXAMPLE_GET_MAC ++ /* EXAMPLE code */ ++ { ++ struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; ++ bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); ++ } ++#endif /* EXAMPLE_GET_MAC */ ++#ifdef EXAMPLE_GET_MAC_VER2 ++ /* EXAMPLE code */ ++ { ++ char macpad[56]= { ++ 0x00,0xaa,0x9c,0x84,0xc7,0xbc,0x9b,0xf6, ++ 0x02,0x33,0xa9,0x4d,0x5c,0xb4,0x0a,0x5d, ++ 0xa8,0xef,0xb0,0xcf,0x8e,0xbf,0x24,0x8a, ++ 0x87,0x0f,0x6f,0x0d,0xeb,0x83,0x6a,0x70, ++ 0x4a,0xeb,0xf6,0xe6,0x3c,0xe7,0x5f,0xfc, ++ 0x0e,0xa7,0xb3,0x0f,0x00,0xe4,0x4a,0xaf, ++ 0x87,0x08,0x16,0x6d,0x3a,0xe3,0xc7,0x80}; ++ bcopy(macpad, buf+6, sizeof(macpad)); ++ } ++#endif /* EXAMPLE_GET_MAC_VER2 */ ++ ++ return err; ++} ++ ++static struct cntry_locales_custom brcm_wlan_translate_custom_table[] = { ++ /* Table should be filled out based on custom platform regulatory requirement */ ++#ifdef EXAMPLE_TABLE ++ {"", "XT", 49}, /* Universal if Country code is unknown or empty */ ++ {"US", "US", 0}, ++#endif /* EXMAPLE_TABLE */ ++}; ++ ++#ifdef CUSTOM_FORCE_NODFS_FLAG ++struct cntry_locales_custom brcm_wlan_translate_nodfs_table[] = { ++#ifdef EXAMPLE_TABLE ++ {"", "XT", 50}, /* Universal if Country code is unknown or empty */ ++ {"US", "US", 0}, ++#endif /* EXMAPLE_TABLE */ ++}; ++#endif ++ ++static void *dhd_wlan_get_country_code(char *ccode ++#ifdef CUSTOM_FORCE_NODFS_FLAG ++ , u32 flags ++#endif ++) ++{ ++ struct cntry_locales_custom *locales; ++ int size; ++ int i; ++ ++ if (!ccode) ++ return NULL; ++ ++#ifdef CUSTOM_FORCE_NODFS_FLAG ++ if (flags & WLAN_PLAT_NODFS_FLAG) { ++ locales = brcm_wlan_translate_nodfs_table; ++ size = ARRAY_SIZE(brcm_wlan_translate_nodfs_table); ++ } else { ++#endif ++ locales = brcm_wlan_translate_custom_table; ++ size = ARRAY_SIZE(brcm_wlan_translate_custom_table); ++#ifdef CUSTOM_FORCE_NODFS_FLAG ++ } ++#endif ++ ++ for (i = 0; i < size; i++) ++ if (strcmp(ccode, locales[i].iso_abbrev) == 0) ++ return &locales[i]; ++ return NULL; ++} ++ ++struct resource dhd_wlan_resources[] = { ++ [0] = { ++ .name = "bcmdhd_wlan_irq", ++ .start = 0, /* Dummy */ ++ .end = 0, /* Dummy */ ++ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE ++ | IORESOURCE_IRQ_HIGHLEVEL, /* Dummy */ ++ }, ++}; ++ ++struct wifi_platform_data dhd_wlan_control = { ++ .set_power = dhd_wlan_set_power, ++ .set_reset = dhd_wlan_set_reset, ++ .set_carddetect = dhd_wlan_set_carddetect, ++ .get_mac_addr = dhd_wlan_get_mac_addr, ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ .mem_prealloc = dhd_wlan_mem_prealloc, ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ .get_country_code = dhd_wlan_get_country_code, ++}; ++ ++int dhd_wlan_init_gpio(void) ++{ ++ int err = 0; ++#ifdef CUSTOMER_OOB ++ int host_oob_irq = -1; ++ uint host_oob_irq_flags = 0; ++#endif ++ ++ /* Please check your schematic and fill right GPIO number which connected to ++ * WL_REG_ON and WL_HOST_WAKE. ++ */ ++ gpio_wl_reg_on = -1; ++#ifdef CUSTOMER_OOB ++ gpio_wl_host_wake = -1; ++#ifdef CUSTOMER_HW_INGENIC ++ gpio_wl_host_wake = ingenic_sdio_wlan_get_irq((unsigned long *)&host_oob_irq_flags); ++#endif ++#endif ++ ++ if (gpio_wl_reg_on >= 0) { ++ err = gpio_request(gpio_wl_reg_on, "WL_REG_ON"); ++ if (err < 0) { ++ printf("%s: gpio_request(%d) for WL_REG_ON failed\n", ++ __FUNCTION__, gpio_wl_reg_on); ++ gpio_wl_reg_on = -1; ++ } ++ } ++ ++#ifdef CUSTOMER_OOB ++ if (gpio_wl_host_wake >= 0) { ++ err = gpio_request(gpio_wl_host_wake, "bcmdhd"); ++ if (err < 0) { ++ printf("%s: gpio_request(%d) for WL_HOST_WAKE failed\n", ++ __FUNCTION__, gpio_wl_host_wake); ++ return -1; ++ } ++ err = gpio_direction_input(gpio_wl_host_wake); ++ if (err < 0) { ++ printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed\n", ++ __FUNCTION__, gpio_wl_host_wake); ++ gpio_free(gpio_wl_host_wake); ++ return -1; ++ } ++ host_oob_irq = gpio_to_irq(gpio_wl_host_wake); ++ if (host_oob_irq < 0) { ++ printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed\n", ++ __FUNCTION__, gpio_wl_host_wake); ++ gpio_free(gpio_wl_host_wake); ++ return -1; ++ } ++ } ++ ++#ifdef HW_OOB ++ if (host_oob_irq_flags & IORESOURCE_IRQ_LOWLEVEL){ ++ host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE; ++ } else if (host_oob_irq_flags & IORESOURCE_IRQ_HIGHLEVEL){ ++ host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; ++ } else if (host_oob_irq_flags & IORESOURCE_IRQ_HIGHEDGE){ ++ host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_SHAREABLE; ++ } ++#endif ++ ++ dhd_wlan_resources[0].start = dhd_wlan_resources[0].end = host_oob_irq; ++ dhd_wlan_resources[0].flags = host_oob_irq_flags; ++ printf("%s: WL_HOST_WAKE=%d, oob_irq=%d, oob_irq_flags=0x%x\n", __FUNCTION__, ++ gpio_wl_host_wake, host_oob_irq, host_oob_irq_flags); ++#endif /* CUSTOMER_OOB */ ++ printf("%s: WL_REG_ON=%d\n", __FUNCTION__, gpio_wl_reg_on); ++ ++ return 0; ++} ++ ++static void dhd_wlan_deinit_gpio(void) ++{ ++ if (gpio_wl_reg_on >= 0) { ++ printf("%s: gpio_free(WL_REG_ON %d)\n", __FUNCTION__, gpio_wl_reg_on); ++ gpio_free(gpio_wl_reg_on); ++ gpio_wl_reg_on = -1; ++ } ++#ifdef CUSTOMER_OOB ++ if (gpio_wl_host_wake >= 0) { ++ printf("%s: gpio_free(WL_HOST_WAKE %d)\n", __FUNCTION__, gpio_wl_host_wake); ++ gpio_free(gpio_wl_host_wake); ++ gpio_wl_host_wake = -1; ++ } ++#endif /* CUSTOMER_OOB */ ++} ++ ++int dhd_wlan_init_plat_data(void) ++{ ++ int err = 0; ++ ++ printf("======== %s ========\n", __FUNCTION__); ++ err = dhd_wlan_init_gpio(); ++ return err; ++} ++ ++void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter) ++{ ++ printf("======== %s ========\n", __FUNCTION__); ++ dhd_wlan_deinit_gpio(); ++} ++ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_ip.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_ip.c +new file mode 100644 +index 000000000..2089c674f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_ip.c +@@ -0,0 +1,1318 @@ ++/* ++ * IP Packet Parser Module. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_ip.c 700317 2017-05-18 15:13:29Z $ ++ */ ++#include ++#include ++ ++#include ++#include ++#include <802.3.h> ++#include ++#include ++ ++#include ++ ++#include ++ ++#ifdef DHDTCPACK_SUPPRESS ++#include ++#include ++#include ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++/* special values */ ++/* 802.3 llc/snap header */ ++static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; ++ ++pkt_frag_t pkt_frag_info(osl_t *osh, void *p) ++{ ++ uint8 *frame; ++ int length; ++ uint8 *pt; /* Pointer to type field */ ++ uint16 ethertype; ++ struct ipv4_hdr *iph; /* IP frame pointer */ ++ int ipl; /* IP frame length */ ++ uint16 iph_frag; ++ ++ ASSERT(osh && p); ++ ++ frame = PKTDATA(osh, p); ++ length = PKTLEN(osh, p); ++ ++ /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ ++ if (length < ETHER_HDR_LEN) { ++ DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length)); ++ return DHD_PKT_FRAG_NONE; ++ } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) { ++ /* Frame is Ethernet II */ ++ pt = frame + ETHER_TYPE_OFFSET; ++ } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && ++ !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { ++ pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; ++ } else { ++ DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__)); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ ethertype = ntoh16(*(uint16 *)pt); ++ ++ /* Skip VLAN tag, if any */ ++ if (ethertype == ETHER_TYPE_8021Q) { ++ pt += VLAN_TAG_LEN; ++ ++ if (pt + ETHER_TYPE_LEN > frame + length) { ++ DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length)); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ ethertype = ntoh16(*(uint16 *)pt); ++ } ++ ++ if (ethertype != ETHER_TYPE_IP) { ++ DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n", ++ __FUNCTION__, ethertype, length)); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN); ++ ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame)); ++ ++ /* We support IPv4 only */ ++ if ((ipl < IPV4_OPTIONS_OFFSET) || (IP_VER(iph) != IP_VER_4)) { ++ DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl)); ++ return DHD_PKT_FRAG_NONE; ++ } ++ ++ iph_frag = ntoh16(iph->frag); ++ ++ if (iph_frag & IPV4_FRAG_DONT) { ++ return DHD_PKT_FRAG_NONE; ++ } else if ((iph_frag & IPV4_FRAG_MORE) == 0) { ++ return DHD_PKT_FRAG_LAST; ++ } else { ++ return (iph_frag & IPV4_FRAG_OFFSET_MASK)? DHD_PKT_FRAG_CONT : DHD_PKT_FRAG_FIRST; ++ } ++} ++ ++#ifdef DHDTCPACK_SUPPRESS ++ ++typedef struct { ++ void *pkt_in_q; /* TCP ACK packet that is already in txq or DelayQ */ ++ void *pkt_ether_hdr; /* Ethernet header pointer of pkt_in_q */ ++ int ifidx; ++ uint8 supp_cnt; ++ dhd_pub_t *dhdp; ++ timer_list_compat_t timer; ++} tcpack_info_t; ++ ++typedef struct _tdata_psh_info_t { ++ uint32 end_seq; /* end seq# of a received TCP PSH DATA pkt */ ++ struct _tdata_psh_info_t *next; /* next pointer of the link chain */ ++} tdata_psh_info_t; ++ ++typedef struct { ++ struct { ++ uint8 src[IPV4_ADDR_LEN]; /* SRC ip addrs of this TCP stream */ ++ uint8 dst[IPV4_ADDR_LEN]; /* DST ip addrs of this TCP stream */ ++ } ip_addr; ++ struct { ++ uint8 src[TCP_PORT_LEN]; /* SRC tcp ports of this TCP stream */ ++ uint8 dst[TCP_PORT_LEN]; /* DST tcp ports of this TCP stream */ ++ } tcp_port; ++ tdata_psh_info_t *tdata_psh_info_head; /* Head of received TCP PSH DATA chain */ ++ tdata_psh_info_t *tdata_psh_info_tail; /* Tail of received TCP PSH DATA chain */ ++ uint32 last_used_time; /* The last time this tcpdata_info was used(in ms) */ ++} tcpdata_info_t; ++ ++/* TCPACK SUPPRESS module */ ++typedef struct { ++ int tcpack_info_cnt; ++ tcpack_info_t tcpack_info_tbl[TCPACK_INFO_MAXNUM]; /* Info of TCP ACK to send */ ++ int tcpdata_info_cnt; ++ tcpdata_info_t tcpdata_info_tbl[TCPDATA_INFO_MAXNUM]; /* Info of received TCP DATA */ ++ tdata_psh_info_t *tdata_psh_info_pool; /* Pointer to tdata_psh_info elements pool */ ++ tdata_psh_info_t *tdata_psh_info_free; /* free tdata_psh_info elements chain in pool */ ++#ifdef DHDTCPACK_SUP_DBG ++ int psh_info_enq_num; /* Number of free TCP PSH DATA info elements in pool */ ++#endif /* DHDTCPACK_SUP_DBG */ ++} tcpack_sup_module_t; ++ ++#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) ++counter_tbl_t tack_tbl = {"tcpACK", 0, 1000, 10, {0, }, 1}; ++#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ ++ ++static void ++_tdata_psh_info_pool_enq(tcpack_sup_module_t *tcpack_sup_mod, ++ tdata_psh_info_t *tdata_psh_info) ++{ ++ if ((tcpack_sup_mod == NULL) || (tdata_psh_info == NULL)) { ++ DHD_ERROR(("%s %d: ERROR %p %p\n", __FUNCTION__, __LINE__, ++ tcpack_sup_mod, tdata_psh_info)); ++ return; ++ } ++ ++ ASSERT(tdata_psh_info->next == NULL); ++ tdata_psh_info->next = tcpack_sup_mod->tdata_psh_info_free; ++ tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info; ++#ifdef DHDTCPACK_SUP_DBG ++ tcpack_sup_mod->psh_info_enq_num++; ++#endif ++} ++ ++static tdata_psh_info_t* ++_tdata_psh_info_pool_deq(tcpack_sup_module_t *tcpack_sup_mod) ++{ ++ tdata_psh_info_t *tdata_psh_info = NULL; ++ ++ if (tcpack_sup_mod == NULL) { ++ DHD_ERROR(("%s %d: ERROR %p\n", __FUNCTION__, __LINE__, ++ tcpack_sup_mod)); ++ return NULL; ++ } ++ ++ tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free; ++ if (tdata_psh_info == NULL) ++ DHD_ERROR(("%s %d: Out of tdata_disc_grp\n", __FUNCTION__, __LINE__)); ++ else { ++ tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; ++ tdata_psh_info->next = NULL; ++#ifdef DHDTCPACK_SUP_DBG ++ tcpack_sup_mod->psh_info_enq_num--; ++#endif /* DHDTCPACK_SUP_DBG */ ++ } ++ ++ return tdata_psh_info; ++} ++ ++static int _tdata_psh_info_pool_init(dhd_pub_t *dhdp, ++ tcpack_sup_module_t *tcpack_sup_mod) ++{ ++ tdata_psh_info_t *tdata_psh_info_pool = NULL; ++ uint i; ++ ++ DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); ++ ++ if (tcpack_sup_mod == NULL) ++ return BCME_ERROR; ++ ++ ASSERT(tcpack_sup_mod->tdata_psh_info_pool == NULL); ++ ASSERT(tcpack_sup_mod->tdata_psh_info_free == NULL); ++ ++ tdata_psh_info_pool = ++ MALLOC(dhdp->osh, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); ++ ++ if (tdata_psh_info_pool == NULL) ++ return BCME_NOMEM; ++ bzero(tdata_psh_info_pool, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); ++#ifdef DHDTCPACK_SUP_DBG ++ tcpack_sup_mod->psh_info_enq_num = 0; ++#endif /* DHDTCPACK_SUP_DBG */ ++ ++ /* Enqueue newly allocated tcpdata psh info elements to the pool */ ++ for (i = 0; i < TCPDATA_PSH_INFO_MAXNUM; i++) ++ _tdata_psh_info_pool_enq(tcpack_sup_mod, &tdata_psh_info_pool[i]); ++ ++ ASSERT(tcpack_sup_mod->tdata_psh_info_free != NULL); ++ tcpack_sup_mod->tdata_psh_info_pool = tdata_psh_info_pool; ++ ++ return BCME_OK; ++} ++ ++static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp, ++ tcpack_sup_module_t *tcpack_sup_mod) ++{ ++ uint i; ++ tdata_psh_info_t *tdata_psh_info; ++ ++ DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); ++ ++ if (tcpack_sup_mod == NULL) { ++ DHD_ERROR(("%s %d: ERROR tcpack_sup_mod NULL!\n", ++ __FUNCTION__, __LINE__)); ++ return; ++ } ++ ++ for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { ++ tcpdata_info_t *tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; ++ /* Return tdata_psh_info elements allocated to each tcpdata_info to the pool */ ++ while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { ++ tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; ++ tdata_psh_info->next = NULL; ++ _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); ++ } ++ tcpdata_info->tdata_psh_info_tail = NULL; ++ } ++#ifdef DHDTCPACK_SUP_DBG ++ DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", ++ __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); ++#endif /* DHDTCPACK_SUP_DBG */ ++ ++ i = 0; ++ /* Be sure we recollected all tdata_psh_info elements */ ++ while ((tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free)) { ++ tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; ++ tdata_psh_info->next = NULL; ++ i++; ++ } ++ ASSERT(i == TCPDATA_PSH_INFO_MAXNUM); ++ MFREE(dhdp->osh, tcpack_sup_mod->tdata_psh_info_pool, ++ sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); ++ tcpack_sup_mod->tdata_psh_info_pool = NULL; ++ ++ return; ++} ++ ++static void dhd_tcpack_send(ulong data) ++{ ++ tcpack_sup_module_t *tcpack_sup_mod; ++ tcpack_info_t *cur_tbl = (tcpack_info_t *)data; ++ dhd_pub_t *dhdp; ++ int ifidx; ++ void* pkt; ++ unsigned long flags; ++ ++ if (!cur_tbl) { ++ return; ++ } ++ ++ dhdp = cur_tbl->dhdp; ++ if (!dhdp) { ++ return; ++ } ++ ++ flags = dhd_os_tcpacklock(dhdp); ++ ++ tcpack_sup_mod = dhdp->tcpack_sup_module; ++ if (!tcpack_sup_mod) { ++ DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", ++ __FUNCTION__, __LINE__)); ++ dhd_os_tcpackunlock(dhdp, flags); ++ return; ++ } ++ pkt = cur_tbl->pkt_in_q; ++ ifidx = cur_tbl->ifidx; ++ if (!pkt) { ++ dhd_os_tcpackunlock(dhdp, flags); ++ return; ++ } ++ cur_tbl->pkt_in_q = NULL; ++ cur_tbl->pkt_ether_hdr = NULL; ++ cur_tbl->ifidx = 0; ++ cur_tbl->supp_cnt = 0; ++ if (--tcpack_sup_mod->tcpack_info_cnt < 0) { ++ DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n", ++ __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt)); ++ } ++ ++ dhd_os_tcpackunlock(dhdp, flags); ++ ++ dhd_sendpkt(dhdp, ifidx, pkt); ++} ++ ++int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode) ++{ ++ int ret = BCME_OK; ++ unsigned long flags; ++ tcpack_sup_module_t *tcpack_sup_module; ++ uint8 invalid_mode = FALSE; ++ int prev_mode; ++ int i = 0; ++ ++ flags = dhd_os_tcpacklock(dhdp); ++ tcpack_sup_module = dhdp->tcpack_sup_module; ++ prev_mode = dhdp->tcpack_sup_mode; ++ ++ /* Check a new mode */ ++ if (prev_mode == mode) { ++ DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode)); ++ goto exit; ++ } ++ ++ invalid_mode |= (mode >= TCPACK_SUP_LAST_MODE); ++#ifdef BCMSDIO ++ invalid_mode |= (mode == TCPACK_SUP_HOLD); ++#endif /* BCMSDIO */ ++#ifdef BCMPCIE ++ invalid_mode |= ((mode == TCPACK_SUP_REPLACE) || (mode == TCPACK_SUP_DELAYTX)); ++#endif /* BCMPCIE */ ++ ++ if (invalid_mode) { ++ DHD_ERROR(("%s %d: Invalid TCP ACK Suppress mode %d\n", ++ __FUNCTION__, __LINE__, mode)); ++ ret = BCME_BADARG; ++ goto exit; ++ } ++ ++ printf("%s: TCP ACK Suppress mode %d -> mode %d\n", ++ __FUNCTION__, dhdp->tcpack_sup_mode, mode); ++ ++ /* Pre-process routines to change a new mode as per previous mode */ ++ switch (prev_mode) { ++ case TCPACK_SUP_OFF: ++ if (tcpack_sup_module == NULL) { ++ tcpack_sup_module = MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t)); ++ if (tcpack_sup_module == NULL) { ++ DHD_ERROR(("%s[%d]: Failed to allocate the new memory for " ++ "tcpack_sup_module\n", __FUNCTION__, __LINE__)); ++ dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; ++ ret = BCME_NOMEM; ++ goto exit; ++ } ++ dhdp->tcpack_sup_module = tcpack_sup_module; ++ } ++ bzero(tcpack_sup_module, sizeof(tcpack_sup_module_t)); ++ break; ++ case TCPACK_SUP_DELAYTX: ++ if (tcpack_sup_module) { ++ /* We won't need tdata_psh_info pool and ++ * tcpddata_info_tbl anymore ++ */ ++ _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_module); ++ tcpack_sup_module->tcpdata_info_cnt = 0; ++ bzero(tcpack_sup_module->tcpdata_info_tbl, ++ sizeof(tcpdata_info_t) * TCPDATA_INFO_MAXNUM); ++ } ++ ++ /* For half duplex bus interface, tx precedes rx by default */ ++ if (dhdp->bus) { ++ dhd_bus_set_dotxinrx(dhdp->bus, TRUE); ++ } ++ ++ if (tcpack_sup_module == NULL) { ++ DHD_ERROR(("%s[%d]: tcpack_sup_module should not be NULL\n", ++ __FUNCTION__, __LINE__)); ++ dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; ++ goto exit; ++ } ++ break; ++ } ++ ++ /* Update a new mode */ ++ dhdp->tcpack_sup_mode = mode; ++ ++ /* Process for a new mode */ ++ switch (mode) { ++ case TCPACK_SUP_OFF: ++ ASSERT(tcpack_sup_module != NULL); ++ /* Clean up timer/data structure for ++ * any remaining/pending packet or timer. ++ */ ++ if (tcpack_sup_module) { ++ /* Check if previous mode is TCAPACK_SUP_HOLD */ ++ if (prev_mode == TCPACK_SUP_HOLD) { ++ for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { ++ tcpack_info_t *tcpack_info_tbl = ++ &tcpack_sup_module->tcpack_info_tbl[i]; ++ _del_timer(&tcpack_info_tbl->timer); ++ if (tcpack_info_tbl->pkt_in_q) { ++ PKTFREE(dhdp->osh, ++ tcpack_info_tbl->pkt_in_q, TRUE); ++ tcpack_info_tbl->pkt_in_q = NULL; ++ } ++ } ++ } ++ MFREE(dhdp->osh, tcpack_sup_module, sizeof(tcpack_sup_module_t)); ++ dhdp->tcpack_sup_module = NULL; ++ } else { ++ DHD_ERROR(("%s[%d]: tcpack_sup_module should not be NULL\n", ++ __FUNCTION__, __LINE__)); ++ } ++ break; ++ case TCPACK_SUP_REPLACE: ++ /* There is nothing to configure for this mode */ ++ break; ++ case TCPACK_SUP_DELAYTX: ++ ret = _tdata_psh_info_pool_init(dhdp, tcpack_sup_module); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s %d: pool init fail with %d\n", ++ __FUNCTION__, __LINE__, ret)); ++ break; ++ } ++ if (dhdp->bus) { ++ dhd_bus_set_dotxinrx(dhdp->bus, FALSE); ++ } ++ break; ++ case TCPACK_SUP_HOLD: ++ dhdp->tcpack_sup_ratio = CUSTOM_TCPACK_SUPP_RATIO; ++ dhdp->tcpack_sup_delay = CUSTOM_TCPACK_DELAY_TIME; ++ for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { ++ tcpack_info_t *tcpack_info_tbl = ++ &tcpack_sup_module->tcpack_info_tbl[i]; ++ tcpack_info_tbl->dhdp = dhdp; ++ init_timer_compat(&tcpack_info_tbl->timer, dhd_tcpack_send, tcpack_info_tbl); ++ } ++ break; ++ } ++ ++exit: ++ dhd_os_tcpackunlock(dhdp, flags); ++ return ret; ++} ++ ++void ++dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp) ++{ ++ tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; ++ int i; ++ unsigned long flags; ++ ++ if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) ++ goto exit; ++ ++ flags = dhd_os_tcpacklock(dhdp); ++ ++ if (!tcpack_sup_mod) { ++ DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", ++ __FUNCTION__, __LINE__)); ++ dhd_os_tcpackunlock(dhdp, flags); ++ goto exit; ++ } ++ ++ if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) { ++ for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { ++ if (tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q) { ++ PKTFREE(dhdp->osh, tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q, ++ TRUE); ++ tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q = NULL; ++ tcpack_sup_mod->tcpack_info_tbl[i].pkt_ether_hdr = NULL; ++ tcpack_sup_mod->tcpack_info_tbl[i].ifidx = 0; ++ tcpack_sup_mod->tcpack_info_tbl[i].supp_cnt = 0; ++ } ++ } ++ } else { ++ tcpack_sup_mod->tcpack_info_cnt = 0; ++ bzero(tcpack_sup_mod->tcpack_info_tbl, sizeof(tcpack_info_t) * TCPACK_INFO_MAXNUM); ++ } ++ ++ dhd_os_tcpackunlock(dhdp, flags); ++ ++ if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) { ++ for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { ++ _del_timer_sync(&tcpack_sup_mod->tcpack_info_tbl[i].timer); ++ } ++ } ++ ++exit: ++ return; ++} ++ ++inline int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt) ++{ ++ uint8 i; ++ tcpack_sup_module_t *tcpack_sup_mod; ++ tcpack_info_t *tcpack_info_tbl; ++ int tbl_cnt; ++ int ret = BCME_OK; ++ void *pdata; ++ uint32 pktlen; ++ unsigned long flags; ++ ++ if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) ++ goto exit; ++ ++ pdata = PKTDATA(dhdp->osh, pkt); ++ pktlen = PKTLEN(dhdp->osh, pkt) - dhd_prot_hdrlen(dhdp, pdata); ++ ++ if (pktlen < TCPACKSZMIN || pktlen > TCPACKSZMAX) { ++ DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", ++ __FUNCTION__, __LINE__, pktlen)); ++ goto exit; ++ } ++ ++ flags = dhd_os_tcpacklock(dhdp); ++ tcpack_sup_mod = dhdp->tcpack_sup_module; ++ ++ if (!tcpack_sup_mod) { ++ DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); ++ ret = BCME_ERROR; ++ dhd_os_tcpackunlock(dhdp, flags); ++ goto exit; ++ } ++ tbl_cnt = tcpack_sup_mod->tcpack_info_cnt; ++ tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; ++ ++ ASSERT(tbl_cnt <= TCPACK_INFO_MAXNUM); ++ ++ for (i = 0; i < tbl_cnt; i++) { ++ if (tcpack_info_tbl[i].pkt_in_q == pkt) { ++ DHD_TRACE(("%s %d: pkt %p sent out. idx %d, tbl_cnt %d\n", ++ __FUNCTION__, __LINE__, pkt, i, tbl_cnt)); ++ /* This pkt is being transmitted so remove the tcp_ack_info of it. */ ++ if (i < tbl_cnt - 1) { ++ bcopy(&tcpack_info_tbl[tbl_cnt - 1], ++ &tcpack_info_tbl[i], sizeof(tcpack_info_t)); ++ } ++ bzero(&tcpack_info_tbl[tbl_cnt - 1], sizeof(tcpack_info_t)); ++ if (--tcpack_sup_mod->tcpack_info_cnt < 0) { ++ DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n", ++ __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt)); ++ ret = BCME_ERROR; ++ } ++ break; ++ } ++ } ++ dhd_os_tcpackunlock(dhdp, flags); ++ ++exit: ++ return ret; ++} ++ ++static INLINE bool dhd_tcpdata_psh_acked(dhd_pub_t *dhdp, uint8 *ip_hdr, ++ uint8 *tcp_hdr, uint32 tcp_ack_num) ++{ ++ tcpack_sup_module_t *tcpack_sup_mod; ++ int i; ++ tcpdata_info_t *tcpdata_info = NULL; ++ tdata_psh_info_t *tdata_psh_info = NULL; ++ bool ret = FALSE; ++ ++ if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) ++ goto exit; ++ ++ tcpack_sup_mod = dhdp->tcpack_sup_module; ++ ++ if (!tcpack_sup_mod) { ++ DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); ++ goto exit; ++ } ++ ++ DHD_TRACE(("%s %d: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR ++ " TCP port %d %d, ack %u\n", __FUNCTION__, __LINE__, ++ IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), ++ IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), ++ ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), ++ ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), ++ tcp_ack_num)); ++ ++ for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { ++ tcpdata_info_t *tcpdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; ++ DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR ++ " TCP port %d %d\n", __FUNCTION__, __LINE__, i, ++ IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->ip_addr.src)), ++ IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->ip_addr.dst)), ++ ntoh16_ua(tcpdata_info_tmp->tcp_port.src), ++ ntoh16_ua(tcpdata_info_tmp->tcp_port.dst))); ++ ++ /* If either IP address or TCP port number does not match, skip. */ ++ if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], ++ tcpdata_info_tmp->ip_addr.dst, IPV4_ADDR_LEN) == 0 && ++ memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET], ++ tcpdata_info_tmp->ip_addr.src, IPV4_ADDR_LEN) == 0 && ++ memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], ++ tcpdata_info_tmp->tcp_port.dst, TCP_PORT_LEN) == 0 && ++ memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET], ++ tcpdata_info_tmp->tcp_port.src, TCP_PORT_LEN) == 0) { ++ tcpdata_info = tcpdata_info_tmp; ++ break; ++ } ++ } ++ ++ if (tcpdata_info == NULL) { ++ DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__, __LINE__)); ++ goto exit; ++ } ++ ++ if (tcpdata_info->tdata_psh_info_head == NULL) { ++ DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__, __LINE__)); ++ } ++ ++ while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { ++ if (IS_TCPSEQ_GE(tcp_ack_num, tdata_psh_info->end_seq)) { ++ DHD_TRACE(("%s %d: PSH ACKED! %u >= %u\n", ++ __FUNCTION__, __LINE__, tcp_ack_num, tdata_psh_info->end_seq)); ++ tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; ++ tdata_psh_info->next = NULL; ++ _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); ++ ret = TRUE; ++ } else ++ break; ++ } ++ if (tdata_psh_info == NULL) ++ tcpdata_info->tdata_psh_info_tail = NULL; ++ ++#ifdef DHDTCPACK_SUP_DBG ++ DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", ++ __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); ++#endif /* DHDTCPACK_SUP_DBG */ ++ ++exit: ++ return ret; ++} ++ ++bool ++dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt) ++{ ++ uint8 *new_ether_hdr; /* Ethernet header of the new packet */ ++ uint16 new_ether_type; /* Ethernet type of the new packet */ ++ uint8 *new_ip_hdr; /* IP header of the new packet */ ++ uint8 *new_tcp_hdr; /* TCP header of the new packet */ ++ uint32 new_ip_hdr_len; /* IP header length of the new packet */ ++ uint32 cur_framelen; ++ uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ ++ uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ ++ uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ ++ tcpack_sup_module_t *tcpack_sup_mod; ++ tcpack_info_t *tcpack_info_tbl; ++ int i; ++ bool ret = FALSE; ++ bool set_dotxinrx = TRUE; ++ unsigned long flags; ++ ++ ++ if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) ++ goto exit; ++ ++ new_ether_hdr = PKTDATA(dhdp->osh, pkt); ++ cur_framelen = PKTLEN(dhdp->osh, pkt); ++ ++ if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { ++ DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", ++ __FUNCTION__, __LINE__, cur_framelen)); ++ goto exit; ++ } ++ ++ new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; ++ ++ if (new_ether_type != ETHER_TYPE_IP) { ++ DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", ++ __FUNCTION__, __LINE__, new_ether_type)); ++ goto exit; ++ } ++ ++ DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); ++ ++ new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; ++ cur_framelen -= ETHER_HDR_LEN; ++ ++ ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); ++ ++ new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); ++ if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { ++ DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", ++ __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); ++ goto exit; ++ } ++ ++ new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; ++ cur_framelen -= new_ip_hdr_len; ++ ++ ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); ++ ++ DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); ++ ++ /* is it an ack ? Allow only ACK flag, not to suppress others. */ ++ if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { ++ DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", ++ __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); ++ goto exit; ++ } ++ ++ new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); ++ new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); ++ ++ /* This packet has TCP data, so just send */ ++ if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { ++ DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); ++ goto exit; ++ } ++ ++ ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); ++ ++ new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); ++ ++ DHD_TRACE(("%s %d: TCP ACK with zero DATA length" ++ " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", ++ __FUNCTION__, __LINE__, ++ IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), ++ IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), ++ ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), ++ ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); ++ ++ /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ ++ flags = dhd_os_tcpacklock(dhdp); ++#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) ++ counter_printlog(&tack_tbl); ++ tack_tbl.cnt[0]++; ++#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ ++ ++ tcpack_sup_mod = dhdp->tcpack_sup_module; ++ tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; ++ ++ if (!tcpack_sup_mod) { ++ DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); ++ ret = BCME_ERROR; ++ dhd_os_tcpackunlock(dhdp, flags); ++ goto exit; ++ } ++ ++ if (dhd_tcpdata_psh_acked(dhdp, new_ip_hdr, new_tcp_hdr, new_tcp_ack_num)) { ++ /* This TCPACK is ACK to TCPDATA PSH pkt, so keep set_dotxinrx TRUE */ ++#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) ++ tack_tbl.cnt[5]++; ++#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ ++ } else ++ set_dotxinrx = FALSE; ++ ++ for (i = 0; i < tcpack_sup_mod->tcpack_info_cnt; i++) { ++ void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ ++ uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; ++ uint32 old_ip_hdr_len, old_tcp_hdr_len; ++ uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ ++ ++ if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { ++ DHD_ERROR(("%s %d: Unexpected error!! cur idx %d, ttl cnt %d\n", ++ __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); ++ break; ++ } ++ ++ if (PKTDATA(dhdp->osh, oldpkt) == NULL) { ++ DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d, ttl cnt %d\n", ++ __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); ++ break; ++ } ++ ++ old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; ++ old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; ++ old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); ++ old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; ++ old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]); ++ ++ DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR ++ " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, ++ IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), ++ IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), ++ ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), ++ ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); ++ ++ /* If either of IP address or TCP port number does not match, skip. ++ * Note that src/dst addr fields in ip header are contiguous being 8 bytes in total. ++ * Also, src/dst port fields in TCP header are contiguous being 4 bytes in total. ++ */ ++ if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], ++ &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || ++ memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], ++ &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) ++ continue; ++ ++ old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); ++ ++ if (IS_TCPSEQ_GT(new_tcp_ack_num, old_tcpack_num)) { ++ /* New packet has higher TCP ACK number, so it replaces the old packet */ ++ if (new_ip_hdr_len == old_ip_hdr_len && ++ new_tcp_hdr_len == old_tcp_hdr_len) { ++ ASSERT(memcmp(new_ether_hdr, old_ether_hdr, ETHER_HDR_LEN) == 0); ++ bcopy(new_ip_hdr, old_ip_hdr, new_ip_total_len); ++ PKTFREE(dhdp->osh, pkt, FALSE); ++ DHD_TRACE(("%s %d: TCP ACK replace %u -> %u\n", ++ __FUNCTION__, __LINE__, old_tcpack_num, new_tcp_ack_num)); ++#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) ++ tack_tbl.cnt[2]++; ++#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ ++ ret = TRUE; ++ } else { ++#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) ++ tack_tbl.cnt[6]++; ++#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ ++ DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d" ++ " ACK %u -> %u\n", __FUNCTION__, __LINE__, ++ new_ip_hdr_len, old_ip_hdr_len, ++ new_tcp_hdr_len, old_tcp_hdr_len, ++ old_tcpack_num, new_tcp_ack_num)); ++ } ++ } else if (new_tcp_ack_num == old_tcpack_num) { ++ set_dotxinrx = TRUE; ++ /* TCPACK retransmission */ ++#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) ++ tack_tbl.cnt[3]++; ++#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ ++ } else { ++ DHD_TRACE(("%s %d: ACK number reverse old %u(0x%p) new %u(0x%p)\n", ++ __FUNCTION__, __LINE__, old_tcpack_num, oldpkt, ++ new_tcp_ack_num, pkt)); ++ } ++ dhd_os_tcpackunlock(dhdp, flags); ++ goto exit; ++ } ++ ++ if (i == tcpack_sup_mod->tcpack_info_cnt && i < TCPACK_INFO_MAXNUM) { ++ /* No TCPACK packet with the same IP addr and TCP port is found ++ * in tcp_ack_info_tbl. So add this packet to the table. ++ */ ++ DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", ++ __FUNCTION__, __LINE__, pkt, new_ether_hdr, ++ tcpack_sup_mod->tcpack_info_cnt)); ++ ++ tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_in_q = pkt; ++ tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_ether_hdr = new_ether_hdr; ++ tcpack_sup_mod->tcpack_info_cnt++; ++#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) ++ tack_tbl.cnt[1]++; ++#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ ++ } else { ++ ASSERT(i == tcpack_sup_mod->tcpack_info_cnt); ++ DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", ++ __FUNCTION__, __LINE__)); ++ } ++ dhd_os_tcpackunlock(dhdp, flags); ++ ++exit: ++ /* Unless TCPACK_SUP_DELAYTX, dotxinrx is alwasy TRUE, so no need to set here */ ++ if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX && set_dotxinrx) ++ dhd_bus_set_dotxinrx(dhdp->bus, TRUE); ++ ++ return ret; ++} ++ ++bool ++dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt) ++{ ++ uint8 *ether_hdr; /* Ethernet header of the new packet */ ++ uint16 ether_type; /* Ethernet type of the new packet */ ++ uint8 *ip_hdr; /* IP header of the new packet */ ++ uint8 *tcp_hdr; /* TCP header of the new packet */ ++ uint32 ip_hdr_len; /* IP header length of the new packet */ ++ uint32 cur_framelen; ++ uint16 ip_total_len; /* Total length of IP packet for the new packet */ ++ uint32 tcp_hdr_len; /* TCP header length of the new packet */ ++ uint32 tcp_seq_num; /* TCP sequence number of the new packet */ ++ uint16 tcp_data_len; /* TCP DATA length that excludes IP and TCP headers */ ++ uint32 end_tcp_seq_num; /* TCP seq number of the last byte in the new packet */ ++ tcpack_sup_module_t *tcpack_sup_mod; ++ tcpdata_info_t *tcpdata_info = NULL; ++ tdata_psh_info_t *tdata_psh_info; ++ ++ int i; ++ bool ret = FALSE; ++ unsigned long flags; ++ ++ if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) ++ goto exit; ++ ++ ether_hdr = PKTDATA(dhdp->osh, pkt); ++ cur_framelen = PKTLEN(dhdp->osh, pkt); ++ ++ ether_type = ether_hdr[12] << 8 | ether_hdr[13]; ++ ++ if (ether_type != ETHER_TYPE_IP) { ++ DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", ++ __FUNCTION__, __LINE__, ether_type)); ++ goto exit; ++ } ++ ++ DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, ether_type)); ++ ++ ip_hdr = ether_hdr + ETHER_HDR_LEN; ++ cur_framelen -= ETHER_HDR_LEN; ++ ++ ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); ++ ++ ip_hdr_len = IPV4_HLEN(ip_hdr); ++ if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) { ++ DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", ++ __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr))); ++ goto exit; ++ } ++ ++ tcp_hdr = ip_hdr + ip_hdr_len; ++ cur_framelen -= ip_hdr_len; ++ ++ ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); ++ ++ DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); ++ ++ ip_total_len = ntoh16_ua(&ip_hdr[IPV4_PKTLEN_OFFSET]); ++ tcp_hdr_len = 4 * TCP_HDRLEN(tcp_hdr[TCP_HLEN_OFFSET]); ++ ++ /* This packet is mere TCP ACK, so do nothing */ ++ if (ip_total_len == ip_hdr_len + tcp_hdr_len) { ++ DHD_TRACE(("%s %d: Do nothing for no data TCP ACK\n", __FUNCTION__, __LINE__)); ++ goto exit; ++ } ++ ++ ASSERT(ip_total_len > ip_hdr_len + tcp_hdr_len); ++ ++ if ((tcp_hdr[TCP_FLAGS_OFFSET] & TCP_FLAG_PSH) == 0) { ++ DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__, __LINE__)); ++ goto exit; ++ } ++ ++ DHD_TRACE(("%s %d: TCP DATA with nonzero DATA length" ++ " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d, flag 0x%x\n", ++ __FUNCTION__, __LINE__, ++ IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), ++ IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), ++ ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), ++ ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), ++ tcp_hdr[TCP_FLAGS_OFFSET])); ++ ++ flags = dhd_os_tcpacklock(dhdp); ++ tcpack_sup_mod = dhdp->tcpack_sup_module; ++ ++ if (!tcpack_sup_mod) { ++ DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); ++ ret = BCME_ERROR; ++ dhd_os_tcpackunlock(dhdp, flags); ++ goto exit; ++ } ++ ++ /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */ ++ i = 0; ++ while (i < tcpack_sup_mod->tcpdata_info_cnt) { ++ tcpdata_info_t *tdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; ++ uint32 now_in_ms = OSL_SYSUPTIME(); ++ DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR ++ " TCP port %d %d\n", __FUNCTION__, __LINE__, i, ++ IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->ip_addr.src)), ++ IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->ip_addr.dst)), ++ ntoh16_ua(tdata_info_tmp->tcp_port.src), ++ ntoh16_ua(tdata_info_tmp->tcp_port.dst))); ++ ++ /* If both IP address and TCP port number match, we found it so break. ++ * Note that src/dst addr fields in ip header are contiguous being 8 bytes in total. ++ * Also, src/dst port fields in TCP header are contiguous being 4 bytes in total. ++ */ ++ if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], ++ (void *)&tdata_info_tmp->ip_addr, IPV4_ADDR_LEN * 2) == 0 && ++ memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], ++ (void *)&tdata_info_tmp->tcp_port, TCP_PORT_LEN * 2) == 0) { ++ tcpdata_info = tdata_info_tmp; ++ tcpdata_info->last_used_time = now_in_ms; ++ break; ++ } ++ ++ if (now_in_ms - tdata_info_tmp->last_used_time > TCPDATA_INFO_TIMEOUT) { ++ tdata_psh_info_t *tdata_psh_info_tmp; ++ tcpdata_info_t *last_tdata_info; ++ ++ while ((tdata_psh_info_tmp = tdata_info_tmp->tdata_psh_info_head)) { ++ tdata_info_tmp->tdata_psh_info_head = tdata_psh_info_tmp->next; ++ tdata_psh_info_tmp->next = NULL; ++ DHD_TRACE(("%s %d: Clean tdata_psh_info(end_seq %u)!\n", ++ __FUNCTION__, __LINE__, tdata_psh_info_tmp->end_seq)); ++ _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info_tmp); ++ } ++#ifdef DHDTCPACK_SUP_DBG ++ DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", ++ __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); ++#endif /* DHDTCPACK_SUP_DBG */ ++ tcpack_sup_mod->tcpdata_info_cnt--; ++ ASSERT(tcpack_sup_mod->tcpdata_info_cnt >= 0); ++ ++ last_tdata_info = ++ &tcpack_sup_mod->tcpdata_info_tbl[tcpack_sup_mod->tcpdata_info_cnt]; ++ if (i < tcpack_sup_mod->tcpdata_info_cnt) { ++ ASSERT(last_tdata_info != tdata_info_tmp); ++ bcopy(last_tdata_info, tdata_info_tmp, sizeof(tcpdata_info_t)); ++ } ++ bzero(last_tdata_info, sizeof(tcpdata_info_t)); ++ DHD_INFO(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n", ++ __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt)); ++ /* Don't increase "i" here, so that the prev last tcpdata_info is checked */ ++ } else ++ i++; ++ } ++ ++ tcp_seq_num = ntoh32_ua(&tcp_hdr[TCP_SEQ_NUM_OFFSET]); ++ tcp_data_len = ip_total_len - ip_hdr_len - tcp_hdr_len; ++ end_tcp_seq_num = tcp_seq_num + tcp_data_len; ++ ++ if (tcpdata_info == NULL) { ++ ASSERT(i == tcpack_sup_mod->tcpdata_info_cnt); ++ if (i >= TCPDATA_INFO_MAXNUM) { ++ DHD_TRACE(("%s %d: tcp_data_info_tbl FULL! %d %d" ++ " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", ++ __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt, ++ IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), ++ IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), ++ ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), ++ ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); ++ dhd_os_tcpackunlock(dhdp, flags); ++ goto exit; ++ } ++ tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; ++ ++ /* No TCP flow with the same IP addr and TCP port is found ++ * in tcp_data_info_tbl. So add this flow to the table. ++ */ ++ DHD_INFO(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR ++ " TCP port %d %d\n", ++ __FUNCTION__, __LINE__, tcpack_sup_mod->tcpdata_info_cnt, ++ IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), ++ IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), ++ ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), ++ ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); ++ /* Note that src/dst addr fields in ip header are contiguous being 8 bytes in total. ++ * Also, src/dst port fields in TCP header are contiguous being 4 bytes in total. ++ */ ++ bcopy(&ip_hdr[IPV4_SRC_IP_OFFSET], (void *)&tcpdata_info->ip_addr, ++ IPV4_ADDR_LEN * 2); ++ bcopy(&tcp_hdr[TCP_SRC_PORT_OFFSET], (void *)&tcpdata_info->tcp_port, ++ TCP_PORT_LEN * 2); ++ ++ tcpdata_info->last_used_time = OSL_SYSUPTIME(); ++ tcpack_sup_mod->tcpdata_info_cnt++; ++ } ++ ++ ASSERT(tcpdata_info != NULL); ++ ++ tdata_psh_info = _tdata_psh_info_pool_deq(tcpack_sup_mod); ++#ifdef DHDTCPACK_SUP_DBG ++ DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", ++ __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); ++#endif /* DHDTCPACK_SUP_DBG */ ++ ++ if (tdata_psh_info == NULL) { ++ DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__, __LINE__)); ++ ret = BCME_ERROR; ++ dhd_os_tcpackunlock(dhdp, flags); ++ goto exit; ++ } ++ tdata_psh_info->end_seq = end_tcp_seq_num; ++ ++#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) ++ tack_tbl.cnt[4]++; ++#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ ++ ++ DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n", ++ __FUNCTION__, __LINE__, tdata_psh_info->end_seq)); ++ ++ ASSERT(tdata_psh_info->next == NULL); ++ ++ if (tcpdata_info->tdata_psh_info_head == NULL) ++ tcpdata_info->tdata_psh_info_head = tdata_psh_info; ++ else { ++ ASSERT(tcpdata_info->tdata_psh_info_tail); ++ tcpdata_info->tdata_psh_info_tail->next = tdata_psh_info; ++ } ++ tcpdata_info->tdata_psh_info_tail = tdata_psh_info; ++ ++ dhd_os_tcpackunlock(dhdp, flags); ++ ++exit: ++ return ret; ++} ++ ++bool ++dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx) ++{ ++ uint8 *new_ether_hdr; /* Ethernet header of the new packet */ ++ uint16 new_ether_type; /* Ethernet type of the new packet */ ++ uint8 *new_ip_hdr; /* IP header of the new packet */ ++ uint8 *new_tcp_hdr; /* TCP header of the new packet */ ++ uint32 new_ip_hdr_len; /* IP header length of the new packet */ ++ uint32 cur_framelen; ++ uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ ++ uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ ++ uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ ++ tcpack_sup_module_t *tcpack_sup_mod; ++ tcpack_info_t *tcpack_info_tbl; ++ int i, free_slot = TCPACK_INFO_MAXNUM; ++ bool hold = FALSE; ++ unsigned long flags; ++ ++ if (dhdp->tcpack_sup_mode != TCPACK_SUP_HOLD) { ++ goto exit; ++ } ++ ++ if (dhdp->tcpack_sup_ratio == 1) { ++ goto exit; ++ } ++ ++ new_ether_hdr = PKTDATA(dhdp->osh, pkt); ++ cur_framelen = PKTLEN(dhdp->osh, pkt); ++ ++ if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { ++ DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", ++ __FUNCTION__, __LINE__, cur_framelen)); ++ goto exit; ++ } ++ ++ new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; ++ ++ if (new_ether_type != ETHER_TYPE_IP) { ++ DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", ++ __FUNCTION__, __LINE__, new_ether_type)); ++ goto exit; ++ } ++ ++ DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); ++ ++ new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; ++ cur_framelen -= ETHER_HDR_LEN; ++ ++ ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); ++ ++ new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); ++ if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { ++ DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", ++ __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); ++ goto exit; ++ } ++ ++ new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; ++ cur_framelen -= new_ip_hdr_len; ++ ++ ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); ++ ++ DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); ++ ++ /* is it an ack ? Allow only ACK flag, not to suppress others. */ ++ if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { ++ DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", ++ __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); ++ goto exit; ++ } ++ ++ new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); ++ new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); ++ ++ /* This packet has TCP data, so just send */ ++ if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { ++ DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); ++ goto exit; ++ } ++ ++ ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); ++ ++ new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); ++ ++ DHD_TRACE(("%s %d: TCP ACK with zero DATA length" ++ " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", ++ __FUNCTION__, __LINE__, ++ IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), ++ IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), ++ ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), ++ ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); ++ ++ /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ ++ flags = dhd_os_tcpacklock(dhdp); ++ ++ tcpack_sup_mod = dhdp->tcpack_sup_module; ++ tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; ++ ++ if (!tcpack_sup_mod) { ++ DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); ++ dhd_os_tcpackunlock(dhdp, flags); ++ goto exit; ++ } ++ ++ hold = TRUE; ++ ++ for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { ++ void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ ++ uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; ++ uint32 old_ip_hdr_len; ++ uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ ++ ++ if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { ++ if (free_slot == TCPACK_INFO_MAXNUM) { ++ free_slot = i; ++ } ++ continue; ++ } ++ ++ if (PKTDATA(dhdp->osh, oldpkt) == NULL) { ++ DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d\n", ++ __FUNCTION__, __LINE__, i)); ++ hold = FALSE; ++ dhd_os_tcpackunlock(dhdp, flags); ++ goto exit; ++ } ++ ++ old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; ++ old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; ++ old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); ++ old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; ++ ++ DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR ++ " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, ++ IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), ++ IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), ++ ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), ++ ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); ++ ++ /* If either of IP address or TCP port number does not match, skip. */ ++ if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], ++ &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || ++ memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], ++ &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) { ++ continue; ++ } ++ ++ old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); ++ ++ if (IS_TCPSEQ_GE(new_tcp_ack_num, old_tcpack_num)) { ++ tcpack_info_tbl[i].supp_cnt++; ++ if (tcpack_info_tbl[i].supp_cnt >= dhdp->tcpack_sup_ratio) { ++ tcpack_info_tbl[i].pkt_in_q = NULL; ++ tcpack_info_tbl[i].pkt_ether_hdr = NULL; ++ tcpack_info_tbl[i].ifidx = 0; ++ tcpack_info_tbl[i].supp_cnt = 0; ++ hold = FALSE; ++ } else { ++ tcpack_info_tbl[i].pkt_in_q = pkt; ++ tcpack_info_tbl[i].pkt_ether_hdr = new_ether_hdr; ++ tcpack_info_tbl[i].ifidx = ifidx; ++ } ++ PKTFREE(dhdp->osh, oldpkt, TRUE); ++ } else { ++ PKTFREE(dhdp->osh, pkt, TRUE); ++ } ++ dhd_os_tcpackunlock(dhdp, flags); ++ ++ if (!hold) { ++ _del_timer_sync(&tcpack_info_tbl[i].timer); ++ } ++ goto exit; ++ } ++ ++ if (free_slot < TCPACK_INFO_MAXNUM) { ++ /* No TCPACK packet with the same IP addr and TCP port is found ++ * in tcp_ack_info_tbl. So add this packet to the table. ++ */ ++ DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", ++ __FUNCTION__, __LINE__, pkt, new_ether_hdr, ++ free_slot)); ++ ++ tcpack_info_tbl[free_slot].pkt_in_q = pkt; ++ tcpack_info_tbl[free_slot].pkt_ether_hdr = new_ether_hdr; ++ tcpack_info_tbl[free_slot].ifidx = ifidx; ++ tcpack_info_tbl[free_slot].supp_cnt = 1; ++ mod_timer(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer, ++ jiffies + msecs_to_jiffies(dhdp->tcpack_sup_delay)); ++ tcpack_sup_mod->tcpack_info_cnt++; ++ } else { ++ DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", ++ __FUNCTION__, __LINE__)); ++ } ++ dhd_os_tcpackunlock(dhdp, flags); ++ ++exit: ++ return hold; ++} ++#endif /* DHDTCPACK_SUPPRESS */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_ip.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_ip.h +new file mode 100644 +index 000000000..240d85215 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_ip.h +@@ -0,0 +1,85 @@ ++/* ++ * Header file describing the common ip parser function. ++ * ++ * Provides type definitions and function prototypes used to parse ip packet. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_ip.h 536854 2015-02-24 13:17:29Z $ ++ */ ++ ++#ifndef _dhd_ip_h_ ++#define _dhd_ip_h_ ++ ++#ifdef DHDTCPACK_SUPPRESS ++#include ++#include ++#include ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++typedef enum pkt_frag ++{ ++ DHD_PKT_FRAG_NONE = 0, ++ DHD_PKT_FRAG_FIRST, ++ DHD_PKT_FRAG_CONT, ++ DHD_PKT_FRAG_LAST ++} pkt_frag_t; ++ ++extern pkt_frag_t pkt_frag_info(osl_t *osh, void *p); ++ ++#ifdef DHDTCPACK_SUPPRESS ++#define TCPACKSZMIN (ETHER_HDR_LEN + IPV4_MIN_HEADER_LEN + TCP_MIN_HEADER_LEN) ++/* Size of MAX possible TCP ACK packet. Extra bytes for IP/TCP option fields */ ++#define TCPACKSZMAX (TCPACKSZMIN + 100) ++ ++/* Max number of TCP streams that have own src/dst IP addrs and TCP ports */ ++#define TCPACK_INFO_MAXNUM 4 ++#define TCPDATA_INFO_MAXNUM 4 ++#define TCPDATA_PSH_INFO_MAXNUM (8 * TCPDATA_INFO_MAXNUM) ++ ++#define TCPDATA_INFO_TIMEOUT 5000 /* Remove tcpdata_info if inactive for this time (in ms) */ ++ ++#define DEFAULT_TCPACK_SUPP_RATIO 3 ++#ifndef CUSTOM_TCPACK_SUPP_RATIO ++#define CUSTOM_TCPACK_SUPP_RATIO DEFAULT_TCPACK_SUPP_RATIO ++#endif /* CUSTOM_TCPACK_SUPP_RATIO */ ++ ++#define DEFAULT_TCPACK_DELAY_TIME 10 /* ms */ ++#ifndef CUSTOM_TCPACK_DELAY_TIME ++#define CUSTOM_TCPACK_DELAY_TIME DEFAULT_TCPACK_DELAY_TIME ++#endif /* CUSTOM_TCPACK_DELAY_TIME */ ++ ++extern int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 on); ++extern void dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp); ++extern int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt); ++extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt); ++extern bool dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt); ++extern bool dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx); ++/* #define DHDTCPACK_SUP_DBG */ ++#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) ++extern counter_tbl_t tack_tbl; ++#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++#endif /* _dhd_ip_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux.c +new file mode 100644 +index 000000000..c5a5aa87a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux.c +@@ -0,0 +1,19882 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface ++ * Basically selected code segments from usb-cdc.c and usb-rndis.c ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_linux.c 710862 2017-07-14 07:43:59Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#ifdef SHOW_LOGTRACE ++#include ++#include ++#endif /* SHOW_LOGTRACE */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef ENABLE_ADAPTIVE_SCHED ++#include ++#endif /* ENABLE_ADAPTIVE_SCHED */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++#include <802.3.h> ++ ++#include ++#include ++#include ++#include ++#ifdef DHD_WET ++#include ++#endif /* DHD_WET */ ++#ifdef PCIE_FULL_DONGLE ++#include ++#endif ++#include ++#include ++#include ++#ifdef WL_ESCAN ++#include ++#endif ++#include ++#include ++#ifdef CONFIG_HAS_WAKELOCK ++#include ++#endif ++#ifdef WL_CFG80211 ++#include ++#endif ++#ifdef PNO_SUPPORT ++#include ++#endif ++#ifdef RTT_SUPPORT ++#include ++#endif ++#ifdef DHD_TIMESYNC ++#include ++#endif /* DHD_TIMESYNC */ ++ ++#ifdef CONFIG_COMPAT ++#include ++#endif ++ ++#if defined(CONFIG_SOC_EXYNOS8895) ++#include ++#endif /* CONFIG_SOC_EXYNOS8895 */ ++ ++#ifdef DHD_WMF ++#include ++#endif /* DHD_WMF */ ++ ++#ifdef DHD_L2_FILTER ++#include ++#include ++#include ++#endif /* DHD_L2_FILTER */ ++ ++#ifdef DHD_PSTA ++#include ++#endif /* DHD_PSTA */ ++ ++ ++#ifdef DHDTCPACK_SUPPRESS ++#include ++#endif /* DHDTCPACK_SUPPRESS */ ++#include ++#ifdef DHD_PKT_LOGGING ++#include ++#endif /* DHD_PKT_LOGGING */ ++#if defined(STAT_REPORT) ++#include ++#endif /* STAT_REPORT */ ++#ifdef DHD_DEBUG_PAGEALLOC ++typedef void (*page_corrupt_cb_t)(void *handle, void *addr_corrupt, size_t len); ++void dhd_page_corrupt_cb(void *handle, void *addr_corrupt, size_t len); ++extern void register_page_corrupt_cb(page_corrupt_cb_t cb, void* handle); ++#endif /* DHD_DEBUG_PAGEALLOC */ ++ ++ ++#if defined(DHD_LB) ++#if !defined(PCIE_FULL_DONGLE) ++#error "DHD Loadbalancing only supported on PCIE_FULL_DONGLE" ++#endif /* !PCIE_FULL_DONGLE */ ++#endif /* DHD_LB */ ++ ++#if defined(DHD_LB_RXP) || defined(DHD_LB_RXC) || defined(DHD_LB_TXC) || \ ++ defined(DHD_LB_STATS) ++#if !defined(DHD_LB) ++#error "DHD loadbalance derivatives are supported only if DHD_LB is defined" ++#endif /* !DHD_LB */ ++#endif /* DHD_LB_RXP || DHD_LB_RXC || DHD_LB_TXC || DHD_LB_STATS */ ++ ++#if defined(DHD_LB) ++/* Dynamic CPU selection for load balancing */ ++#include ++#include ++#include ++#include ++#include ++ ++#if !defined(DHD_LB_PRIMARY_CPUS) ++#define DHD_LB_PRIMARY_CPUS 0x0 /* Big CPU coreids mask */ ++#endif ++#if !defined(DHD_LB_SECONDARY_CPUS) ++#define DHD_LB_SECONDARY_CPUS 0xFE /* Little CPU coreids mask */ ++#endif ++ ++#define HIST_BIN_SIZE 9 ++ ++static void dhd_rx_napi_dispatcher_fn(struct work_struct * work); ++ ++#if defined(DHD_LB_TXP) ++static void dhd_lb_tx_handler(unsigned long data); ++static void dhd_tx_dispatcher_work(struct work_struct * work); ++static void dhd_tx_dispatcher_fn(dhd_pub_t *dhdp); ++static void dhd_lb_tx_dispatch(dhd_pub_t *dhdp); ++ ++/* Pkttag not compatible with PROP_TXSTATUS or WLFC */ ++typedef struct dhd_tx_lb_pkttag_fr { ++ struct net_device *net; ++ int ifidx; ++} dhd_tx_lb_pkttag_fr_t; ++ ++#define DHD_LB_TX_PKTTAG_SET_NETDEV(tag, netdevp) ((tag)->net = netdevp) ++#define DHD_LB_TX_PKTTAG_NETDEV(tag) ((tag)->net) ++ ++#define DHD_LB_TX_PKTTAG_SET_IFIDX(tag, ifidx) ((tag)->ifidx = ifidx) ++#define DHD_LB_TX_PKTTAG_IFIDX(tag) ((tag)->ifidx) ++#endif /* DHD_LB_TXP */ ++#endif /* DHD_LB */ ++ ++#ifdef HOFFLOAD_MODULES ++#include ++#endif ++ ++#ifdef WLMEDIA_HTSF ++#include ++#include ++ ++#define HTSF_MINLEN 200 /* min. packet length to timestamp */ ++#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ ++#define TSMAX 1000 /* max no. of timing record kept */ ++#define NUMBIN 34 ++ ++static uint32 tsidx = 0; ++static uint32 htsf_seqnum = 0; ++uint32 tsfsync; ++struct timeval tsync; ++static uint32 tsport = 5010; ++ ++typedef struct histo_ { ++ uint32 bin[NUMBIN]; ++} histo_t; ++ ++#if !ISPOWEROF2(DHD_SDALIGN) ++#error DHD_SDALIGN is not a power of 2! ++#endif ++ ++static histo_t vi_d1, vi_d2, vi_d3, vi_d4; ++#endif /* WLMEDIA_HTSF */ ++ ++#ifdef WL_MONITOR ++#include ++#include ++#endif ++ ++#define htod32(i) (i) ++#define htod16(i) (i) ++#define dtoh32(i) (i) ++#define dtoh16(i) (i) ++#define htodchanspec(i) (i) ++#define dtohchanspec(i) (i) ++ ++#ifdef STBLINUX ++#ifdef quote_str ++#undef quote_str ++#endif /* quote_str */ ++#ifdef to_str ++#undef to_str ++#endif /* quote_str */ ++#define to_str(s) #s ++#define quote_str(s) to_str(s) ++ ++static char *driver_target = "driver_target: "quote_str(BRCM_DRIVER_TARGET); ++#endif /* STBLINUX */ ++ ++ ++ ++#if defined(SOFTAP) ++extern bool ap_cfg_running; ++extern bool ap_fw_loaded; ++#endif ++ ++extern void dhd_dump_eapol_4way_message(dhd_pub_t *dhd, char *ifname, ++ char *dump_data, bool direction); ++ ++#ifdef FIX_CPU_MIN_CLOCK ++#include ++#endif /* FIX_CPU_MIN_CLOCK */ ++ ++#ifdef SET_RANDOM_MAC_SOFTAP ++#ifndef CONFIG_DHD_SET_RANDOM_MAC_VAL ++#define CONFIG_DHD_SET_RANDOM_MAC_VAL 0x001A11 ++#endif ++static u32 vendor_oui = CONFIG_DHD_SET_RANDOM_MAC_VAL; ++#endif /* SET_RANDOM_MAC_SOFTAP */ ++ ++#ifdef ENABLE_ADAPTIVE_SCHED ++#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */ ++#ifndef CUSTOM_CPUFREQ_THRESH ++#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH ++#endif /* CUSTOM_CPUFREQ_THRESH */ ++#endif /* ENABLE_ADAPTIVE_SCHED */ ++ ++/* enable HOSTIP cache update from the host side when an eth0:N is up */ ++#define AOE_IP_ALIAS_SUPPORT 1 ++ ++#ifdef BCM_FD_AGGR ++#include ++#include ++#endif ++#ifdef PROP_TXSTATUS ++#include ++#include ++#endif ++ ++#include ++ ++/* Maximum STA per radio */ ++#define DHD_MAX_STA 32 ++ ++ ++ ++const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; ++const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; ++#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); ++static int dhd_inetaddr_notifier_call(struct notifier_block *this, ++ unsigned long event, void *ptr); ++static struct notifier_block dhd_inetaddr_notifier = { ++ .notifier_call = dhd_inetaddr_notifier_call ++}; ++/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be ++ * created in kernel notifier link list (with 'next' pointing to itself) ++ */ ++static bool dhd_inetaddr_notifier_registered = FALSE; ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) ++int dhd_inet6addr_notifier_call(struct notifier_block *this, ++ unsigned long event, void *ptr); ++static struct notifier_block dhd_inet6addr_notifier = { ++ .notifier_call = dhd_inet6addr_notifier_call ++}; ++/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be ++ * created in kernel notifier link list (with 'next' pointing to itself) ++ */ ++static bool dhd_inet6addr_notifier_registered = FALSE; ++#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) ++#include ++volatile bool dhd_mmc_suspend = FALSE; ++DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ ++ ++#if defined(OOB_INTR_ONLY) || defined(FORCE_WOWLAN) ++extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++static void dhd_hang_process(void *dhd_info, void *event_data, u8 event); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++MODULE_LICENSE("GPL and additional rights"); ++#endif /* LinuxVer */ ++ ++#if defined(MULTIPLE_SUPPLICANT) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++DEFINE_MUTEX(_dhd_mutex_lock_); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ ++#endif ++static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force); ++ ++#ifdef CONFIG_BCM_DETECT_CONSECUTIVE_HANG ++#define MAX_CONSECUTIVE_HANG_COUNTS 5 ++#endif /* CONFIG_BCM_DETECT_CONSECUTIVE_HANG */ ++ ++#include ++ ++#ifdef DHD_ULP ++#include ++#endif /* DHD_ULP */ ++ ++#ifdef BCM_FD_AGGR ++#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE) ++#else ++#ifndef PROP_TXSTATUS ++#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) ++#else ++#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128) ++#endif ++#endif /* BCM_FD_AGGR */ ++ ++#ifdef PROP_TXSTATUS ++extern bool dhd_wlfc_skip_fc(void * dhdp, uint8 idx); ++extern void dhd_wlfc_plat_init(void *dhd); ++extern void dhd_wlfc_plat_deinit(void *dhd); ++#endif /* PROP_TXSTATUS */ ++#ifdef USE_DYNAMIC_F2_BLKSIZE ++extern uint sd_f2_blocksize; ++extern int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size); ++#endif /* USE_DYNAMIC_F2_BLKSIZE */ ++ ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) ++const char * ++print_tainted() ++{ ++ return ""; ++} ++#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ ++ ++/* Linux wireless extension support */ ++#if defined(WL_WIRELESS_EXT) ++#include ++extern wl_iw_extra_params_t g_wl_iw_params; ++#endif /* defined(WL_WIRELESS_EXT) */ ++ ++#ifdef CONFIG_PARTIALSUSPEND_SLP ++#include ++#define CONFIG_HAS_EARLYSUSPEND ++#define DHD_USE_EARLYSUSPEND ++#define register_early_suspend register_pre_suspend ++#define unregister_early_suspend unregister_pre_suspend ++#define early_suspend pre_suspend ++#define EARLY_SUSPEND_LEVEL_BLANK_SCREEN 50 ++#else ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++#include ++#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ ++#endif /* CONFIG_PARTIALSUSPEND_SLP */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) ++#include ++#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */ ++ ++#if defined(BCMPCIE) ++extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bcn_interval); ++#else ++extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); ++#endif /* OEM_ANDROID && BCMPCIE */ ++ ++#ifdef PKT_FILTER_SUPPORT ++extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); ++extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); ++extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id); ++#endif ++ ++#if defined(PKT_FILTER_SUPPORT) && defined(APF) ++static int __dhd_apf_add_filter(struct net_device *ndev, uint32 filter_id, ++ u8* program, uint32 program_len); ++static int __dhd_apf_config_filter(struct net_device *ndev, uint32 filter_id, ++ uint32 mode, uint32 enable); ++static int __dhd_apf_delete_filter(struct net_device *ndev, uint32 filter_id); ++#endif /* PKT_FILTER_SUPPORT && APF */ ++ ++ ++ ++static INLINE int argos_register_notifier_init(struct net_device *net) { return 0;} ++static INLINE int argos_register_notifier_deinit(void) { return 0;} ++ ++#if defined(BT_OVER_SDIO) ++extern void wl_android_set_wifi_on_flag(bool enable); ++#endif /* BT_OVER_SDIO */ ++ ++ ++#if defined(TRAFFIC_MGMT_DWM) ++void traffic_mgmt_pkt_set_prio(dhd_pub_t *dhdp, void * pktbuf); ++#endif ++ ++#ifdef DHD_FW_COREDUMP ++static void dhd_mem_dump(void *dhd_info, void *event_info, u8 event); ++#endif /* DHD_FW_COREDUMP */ ++#ifdef DHD_LOG_DUMP ++#define DLD_BUFFER_NUM 2 ++/* [0]: General, [1]: Special */ ++struct dhd_log_dump_buf g_dld_buf[DLD_BUFFER_NUM]; ++static const int dld_buf_size[] = { ++ (1024 * 1024), /* DHD_LOG_DUMP_BUFFER_SIZE */ ++ (8 * 1024) /* DHD_LOG_DUMP_BUFFER_EX_SIZE */ ++}; ++static void dhd_log_dump_init(dhd_pub_t *dhd); ++static void dhd_log_dump_deinit(dhd_pub_t *dhd); ++static void dhd_log_dump(void *handle, void *event_info, u8 event); ++void dhd_schedule_log_dump(dhd_pub_t *dhdp); ++static int do_dhd_log_dump(dhd_pub_t *dhdp); ++#endif /* DHD_LOG_DUMP */ ++ ++#ifdef DHD_DEBUG_UART ++#include ++#define DHD_DEBUG_UART_EXEC_PATH "/system/bin/wldu" ++static void dhd_debug_uart_exec_rd(void *handle, void *event_info, u8 event); ++static void dhd_debug_uart_exec(dhd_pub_t *dhdp, char *cmd); ++#endif /* DHD_DEBUG_UART */ ++ ++static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused); ++static struct notifier_block dhd_reboot_notifier = { ++ .notifier_call = dhd_reboot_callback, ++ .priority = 1, ++}; ++ ++#ifdef BCMPCIE ++static int is_reboot = 0; ++#endif /* BCMPCIE */ ++ ++#if defined(BT_OVER_SDIO) ++#include "dhd_bt_interface.h" ++dhd_pub_t *g_dhd_pub = NULL; ++#endif /* defined (BT_OVER_SDIO) */ ++ ++atomic_t exit_in_progress = ATOMIC_INIT(0); ++ ++typedef struct dhd_if_event { ++ struct list_head list; ++ wl_event_data_if_t event; ++ char name[IFNAMSIZ+1]; ++ uint8 mac[ETHER_ADDR_LEN]; ++} dhd_if_event_t; ++ ++/* Interface control information */ ++typedef struct dhd_if { ++ struct dhd_info *info; /* back pointer to dhd_info */ ++ /* OS/stack specifics */ ++ struct net_device *net; ++ int idx; /* iface idx in dongle */ ++ uint subunit; /* subunit */ ++ uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ ++ bool set_macaddress; ++ bool set_multicast; ++ uint8 bssidx; /* bsscfg index for the interface */ ++ bool attached; /* Delayed attachment when unset */ ++ bool txflowcontrol; /* Per interface flow control indicator */ ++ char name[IFNAMSIZ+1]; /* linux interface name */ ++ char dngl_name[IFNAMSIZ+1]; /* corresponding dongle interface name */ ++ struct net_device_stats stats; ++#ifdef DHD_WMF ++ dhd_wmf_t wmf; /* per bsscfg wmf setting */ ++ bool wmf_psta_disable; /* enable/disable MC pkt to each mac ++ * of MC group behind PSTA ++ */ ++#endif /* DHD_WMF */ ++#ifdef PCIE_FULL_DONGLE ++ struct list_head sta_list; /* sll of associated stations */ ++#if !defined(BCM_GMAC3) ++ spinlock_t sta_list_lock; /* lock for manipulating sll */ ++#endif /* ! BCM_GMAC3 */ ++#endif /* PCIE_FULL_DONGLE */ ++ uint32 ap_isolate; /* ap-isolation settings */ ++#ifdef DHD_L2_FILTER ++ bool parp_enable; ++ bool parp_discard; ++ bool parp_allnode; ++ arp_table_t *phnd_arp_table; ++ /* for Per BSS modification */ ++ bool dhcp_unicast; ++ bool block_ping; ++ bool grat_arp; ++#endif /* DHD_L2_FILTER */ ++#ifdef DHD_MCAST_REGEN ++ bool mcast_regen_bss_enable; ++#endif ++ bool rx_pkt_chainable; /* set all rx packet to chainable config by default */ ++ cumm_ctr_t cumm_ctr; /* cummulative queue length of child flowrings */ ++} dhd_if_t; ++ ++#ifdef WLMEDIA_HTSF ++typedef struct { ++ uint32 low; ++ uint32 high; ++} tsf_t; ++ ++typedef struct { ++ uint32 last_cycle; ++ uint32 last_sec; ++ uint32 last_tsf; ++ uint32 coef; /* scaling factor */ ++ uint32 coefdec1; /* first decimal */ ++ uint32 coefdec2; /* second decimal */ ++} htsf_t; ++ ++typedef struct { ++ uint32 t1; ++ uint32 t2; ++ uint32 t3; ++ uint32 t4; ++} tstamp_t; ++ ++static tstamp_t ts[TSMAX]; ++static tstamp_t maxdelayts; ++static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; ++ ++#endif /* WLMEDIA_HTSF */ ++ ++struct ipv6_work_info_t { ++ uint8 if_idx; ++ char ipv6_addr[IPV6_ADDR_LEN]; ++ unsigned long event; ++}; ++static void dhd_process_daemon_msg(struct sk_buff *skb); ++static void dhd_destroy_to_notifier_skt(void); ++static int dhd_create_to_notifier_skt(void); ++static struct sock *nl_to_event_sk = NULL; ++int sender_pid = 0; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ++struct netlink_kernel_cfg g_cfg = { ++ .groups = 1, ++ .input = dhd_process_daemon_msg, ++}; ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) */ ++ ++typedef struct dhd_dump { ++ uint8 *buf; ++ int bufsize; ++} dhd_dump_t; ++ ++ ++/* When Perimeter locks are deployed, any blocking calls must be preceeded ++ * with a PERIM UNLOCK and followed by a PERIM LOCK. ++ * Examples of blocking calls are: schedule_timeout(), down_interruptible(), ++ * wait_event_timeout(). ++ */ ++ ++/* Local private structure (extension of pub) */ ++typedef struct dhd_info { ++#if defined(WL_WIRELESS_EXT) ++ wl_iw_t iw; /* wireless extensions state (must be first) */ ++#endif /* defined(WL_WIRELESS_EXT) */ ++ dhd_pub_t pub; ++ dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */ ++ ++ wifi_adapter_info_t *adapter; /* adapter information, interrupt, fw path etc. */ ++ char fw_path[PATH_MAX]; /* path to firmware image */ ++ char nv_path[PATH_MAX]; /* path to nvram vars file */ ++ char clm_path[PATH_MAX]; /* path to clm vars file */ ++ char conf_path[PATH_MAX]; /* path to config vars file */ ++#ifdef DHD_UCODE_DOWNLOAD ++ char uc_path[PATH_MAX]; /* path to ucode image */ ++#endif /* DHD_UCODE_DOWNLOAD */ ++ ++ /* serialize dhd iovars */ ++ struct mutex dhd_iovar_mutex; ++ ++ struct semaphore proto_sem; ++#ifdef PROP_TXSTATUS ++ spinlock_t wlfc_spinlock; ++ ++#ifdef BCMDBUS ++ ulong wlfc_lock_flags; ++ ulong wlfc_pub_lock_flags; ++#endif /* BCMDBUS */ ++#endif /* PROP_TXSTATUS */ ++#ifdef WLMEDIA_HTSF ++ htsf_t htsf; ++#endif ++ wait_queue_head_t ioctl_resp_wait; ++ wait_queue_head_t d3ack_wait; ++ wait_queue_head_t dhd_bus_busy_state_wait; ++ uint32 default_wd_interval; ++ ++ timer_list_compat_t timer; ++ bool wd_timer_valid; ++#ifdef DHD_PCIE_RUNTIMEPM ++ timer_list_compat_t rpm_timer; ++ bool rpm_timer_valid; ++ tsk_ctl_t thr_rpm_ctl; ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ struct tasklet_struct tasklet; ++ spinlock_t sdlock; ++ spinlock_t txqlock; ++ spinlock_t rxqlock; ++ spinlock_t dhd_lock; ++#ifdef BCMDBUS ++ ulong txqlock_flags; ++#else ++ ++ struct semaphore sdsem; ++ tsk_ctl_t thr_dpc_ctl; ++ tsk_ctl_t thr_wdt_ctl; ++#endif /* BCMDBUS */ ++ ++ tsk_ctl_t thr_rxf_ctl; ++ spinlock_t rxf_lock; ++ bool rxthread_enabled; ++ ++ /* Wakelocks */ ++#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ struct wake_lock wl_wifi; /* Wifi wakelock */ ++ struct wake_lock wl_rxwake; /* Wifi rx wakelock */ ++ struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */ ++ struct wake_lock wl_wdwake; /* Wifi wd wakelock */ ++ struct wake_lock wl_evtwake; /* Wifi event wakelock */ ++ struct wake_lock wl_pmwake; /* Wifi pm handler wakelock */ ++ struct wake_lock wl_txflwake; /* Wifi tx flow wakelock */ ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ struct wake_lock wl_intrwake; /* Host wakeup wakelock */ ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++#ifdef DHD_USE_SCAN_WAKELOCK ++ struct wake_lock wl_scanwake; /* Wifi scan wakelock */ ++#endif /* DHD_USE_SCAN_WAKELOCK */ ++#endif /* CONFIG_HAS_WAKELOCK && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ /* net_device interface lock, prevent race conditions among net_dev interface ++ * calls and wifi_on or wifi_off ++ */ ++ struct mutex dhd_net_if_mutex; ++ struct mutex dhd_suspend_mutex; ++#if defined(PKT_FILTER_SUPPORT) && defined(APF) ++ struct mutex dhd_apf_mutex; ++#endif /* PKT_FILTER_SUPPORT && APF */ ++#endif ++ spinlock_t wakelock_spinlock; ++ spinlock_t wakelock_evt_spinlock; ++ uint32 wakelock_counter; ++ int wakelock_wd_counter; ++ int wakelock_rx_timeout_enable; ++ int wakelock_ctrl_timeout_enable; ++ bool waive_wakelock; ++ uint32 wakelock_before_waive; ++ ++ /* Thread to issue ioctl for multicast */ ++ wait_queue_head_t ctrl_wait; ++ atomic_t pend_8021x_cnt; ++ dhd_attach_states_t dhd_state; ++#ifdef SHOW_LOGTRACE ++ dhd_event_log_t event_data; ++#endif /* SHOW_LOGTRACE */ ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ struct early_suspend early_suspend; ++#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ u32 pend_ipaddr; ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#ifdef BCM_FD_AGGR ++ void *rpc_th; ++ void *rpc_osh; ++ timer_list_compat_t rpcth_timer; ++ bool rpcth_timer_active; ++ uint8 fdaggr; ++#endif ++#ifdef DHDTCPACK_SUPPRESS ++ spinlock_t tcpack_lock; ++#endif /* DHDTCPACK_SUPPRESS */ ++#ifdef FIX_CPU_MIN_CLOCK ++ bool cpufreq_fix_status; ++ struct mutex cpufreq_fix; ++ struct pm_qos_request dhd_cpu_qos; ++#ifdef FIX_BUS_MIN_CLOCK ++ struct pm_qos_request dhd_bus_qos; ++#endif /* FIX_BUS_MIN_CLOCK */ ++#endif /* FIX_CPU_MIN_CLOCK */ ++ void *dhd_deferred_wq; ++#ifdef DEBUG_CPU_FREQ ++ struct notifier_block freq_trans; ++ int __percpu *new_freq; ++#endif ++ unsigned int unit; ++ struct notifier_block pm_notifier; ++#ifdef DHD_PSTA ++ uint32 psta_mode; /* PSTA or PSR */ ++#endif /* DHD_PSTA */ ++#ifdef DHD_WET ++ uint32 wet_mode; ++#endif /* DHD_WET */ ++#ifdef DHD_DEBUG ++ dhd_dump_t *dump; ++ timer_list_compat_t join_timer; ++ u32 join_timeout_val; ++ bool join_timer_active; ++ uint scan_time_count; ++ timer_list_compat_t scan_timer; ++ bool scan_timer_active; ++#endif ++#if defined(DHD_LB) ++ /* CPU Load Balance dynamic CPU selection */ ++ ++ /* Variable that tracks the currect CPUs available for candidacy */ ++ cpumask_var_t cpumask_curr_avail; ++ ++ /* Primary and secondary CPU mask */ ++ cpumask_var_t cpumask_primary, cpumask_secondary; /* configuration */ ++ cpumask_var_t cpumask_primary_new, cpumask_secondary_new; /* temp */ ++ ++ struct notifier_block cpu_notifier; ++ ++ /* Tasklet to handle Tx Completion packet freeing */ ++ struct tasklet_struct tx_compl_tasklet; ++ atomic_t tx_compl_cpu; ++ ++ /* Tasklet to handle RxBuf Post during Rx completion */ ++ struct tasklet_struct rx_compl_tasklet; ++ atomic_t rx_compl_cpu; ++ ++ /* Napi struct for handling rx packet sendup. Packets are removed from ++ * H2D RxCompl ring and placed into rx_pend_queue. rx_pend_queue is then ++ * appended to rx_napi_queue (w/ lock) and the rx_napi_struct is scheduled ++ * to run to rx_napi_cpu. ++ */ ++ struct sk_buff_head rx_pend_queue ____cacheline_aligned; ++ struct sk_buff_head rx_napi_queue ____cacheline_aligned; ++ struct napi_struct rx_napi_struct ____cacheline_aligned; ++ atomic_t rx_napi_cpu; /* cpu on which the napi is dispatched */ ++ struct net_device *rx_napi_netdev; /* netdev of primary interface */ ++ ++ struct work_struct rx_napi_dispatcher_work; ++ struct work_struct tx_compl_dispatcher_work; ++ struct work_struct tx_dispatcher_work; ++ ++ /* Number of times DPC Tasklet ran */ ++ uint32 dhd_dpc_cnt; ++ /* Number of times NAPI processing got scheduled */ ++ uint32 napi_sched_cnt; ++ /* Number of times NAPI processing ran on each available core */ ++ uint32 *napi_percpu_run_cnt; ++ /* Number of times RX Completions got scheduled */ ++ uint32 rxc_sched_cnt; ++ /* Number of times RX Completion ran on each available core */ ++ uint32 *rxc_percpu_run_cnt; ++ /* Number of times TX Completions got scheduled */ ++ uint32 txc_sched_cnt; ++ /* Number of times TX Completions ran on each available core */ ++ uint32 *txc_percpu_run_cnt; ++ /* CPU status */ ++ /* Number of times each CPU came online */ ++ uint32 *cpu_online_cnt; ++ /* Number of times each CPU went offline */ ++ uint32 *cpu_offline_cnt; ++ ++ /* Number of times TX processing run on each core */ ++ uint32 *txp_percpu_run_cnt; ++ /* Number of times TX start run on each core */ ++ uint32 *tx_start_percpu_run_cnt; ++ ++ /* Tx load balancing */ ++ ++ /* TODO: Need to see if batch processing is really required in case of TX ++ * processing. In case of RX the Dongle can send a bunch of rx completions, ++ * hence we took a 3 queue approach ++ * enque - adds the skbs to rx_pend_queue ++ * dispatch - uses a lock and adds the list of skbs from pend queue to ++ * napi queue ++ * napi processing - copies the pend_queue into a local queue and works ++ * on it. ++ * But for TX its going to be 1 skb at a time, so we are just thinking ++ * of using only one queue and use the lock supported skb queue functions ++ * to add and process it. If its in-efficient we'll re-visit the queue ++ * design. ++ */ ++ ++ /* When the NET_TX tries to send a TX packet put it into tx_pend_queue */ ++ /* struct sk_buff_head tx_pend_queue ____cacheline_aligned; */ ++ /* ++ * From the Tasklet that actually sends out data ++ * copy the list tx_pend_queue into tx_active_queue. There by we need ++ * to spinlock to only perform the copy the rest of the code ie to ++ * construct the tx_pend_queue and the code to process tx_active_queue ++ * can be lockless. The concept is borrowed as is from RX processing ++ */ ++ /* struct sk_buff_head tx_active_queue ____cacheline_aligned; */ ++ ++ /* Control TXP in runtime, enable by default */ ++ atomic_t lb_txp_active; ++ ++ /* ++ * When the NET_TX tries to send a TX packet put it into tx_pend_queue ++ * For now, the processing tasklet will also direcly operate on this ++ * queue ++ */ ++ struct sk_buff_head tx_pend_queue ____cacheline_aligned; ++ ++ /* cpu on which the DHD Tx is happenning */ ++ atomic_t tx_cpu; ++ ++ /* CPU on which the Network stack is calling the DHD's xmit function */ ++ atomic_t net_tx_cpu; ++ ++ /* Tasklet context from which the DHD's TX processing happens */ ++ struct tasklet_struct tx_tasklet; ++ ++ /* ++ * Consumer Histogram - NAPI RX Packet processing ++ * ----------------------------------------------- ++ * On Each CPU, when the NAPI RX Packet processing call back was invoked ++ * how many packets were processed is captured in this data structure. ++ * Now its difficult to capture the "exact" number of packets processed. ++ * So considering the packet counter to be a 32 bit one, we have a ++ * bucket with 8 bins (2^1, 2^2 ... 2^8). The "number" of packets ++ * processed is rounded off to the next power of 2 and put in the ++ * approriate "bin" the value in the bin gets incremented. ++ * For example, assume that in CPU 1 if NAPI Rx runs 3 times ++ * and the packet count processed is as follows (assume the bin counters are 0) ++ * iteration 1 - 10 (the bin counter 2^4 increments to 1) ++ * iteration 2 - 30 (the bin counter 2^5 increments to 1) ++ * iteration 3 - 15 (the bin counter 2^4 increments by 1 to become 2) ++ */ ++ uint32 *napi_rx_hist[HIST_BIN_SIZE]; ++ uint32 *txc_hist[HIST_BIN_SIZE]; ++ uint32 *rxc_hist[HIST_BIN_SIZE]; ++#endif /* DHD_LB */ ++ ++#ifdef SHOW_LOGTRACE ++ struct work_struct event_log_dispatcher_work; ++#endif /* SHOW_LOGTRACE */ ++ ++#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) ++#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ ++ struct kobject dhd_kobj; ++#ifdef SHOW_LOGTRACE ++ struct sk_buff_head evt_trace_queue ____cacheline_aligned; ++#endif ++ timer_list_compat_t timesync_timer; ++#if defined(BT_OVER_SDIO) ++ char btfw_path[PATH_MAX]; ++#endif /* defined (BT_OVER_SDIO) */ ++ ++#ifdef WL_MONITOR ++ struct net_device *monitor_dev; /* monitor pseudo device */ ++ struct sk_buff *monitor_skb; ++ uint monitor_len; ++ uint monitor_type; /* monitor pseudo device */ ++ monitor_info_t *monitor_info; ++#endif /* WL_MONITOR */ ++ uint32 shub_enable; ++#if defined(BT_OVER_SDIO) ++ struct mutex bus_user_lock; /* lock for sdio bus apis shared between WLAN & BT */ ++ int bus_user_count; /* User counts of sdio bus shared between WLAN & BT */ ++#endif /* BT_OVER_SDIO */ ++#ifdef DHD_DEBUG_UART ++ bool duart_execute; ++#endif ++#ifdef PCIE_INB_DW ++ wait_queue_head_t ds_exit_wait; ++#endif /* PCIE_INB_DW */ ++} dhd_info_t; ++ ++#ifdef WL_MONITOR ++#define MONPKT_EXTRA_LEN 48 ++#endif ++ ++#define DHDIF_FWDER(dhdif) FALSE ++ ++#if defined(BT_OVER_SDIO) ++/* Flag to indicate if driver is initialized */ ++uint dhd_driver_init_done = TRUE; ++#else ++/* Flag to indicate if driver is initialized */ ++uint dhd_driver_init_done = FALSE; ++#endif ++/* Flag to indicate if we should download firmware on driver load */ ++uint dhd_download_fw_on_driverload = TRUE; ++ ++/* Definitions to provide path to the firmware and nvram ++ * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" ++ */ ++char firmware_path[MOD_PARAM_PATHLEN]; ++char nvram_path[MOD_PARAM_PATHLEN]; ++char clm_path[MOD_PARAM_PATHLEN]; ++char config_path[MOD_PARAM_PATHLEN]; ++#ifdef DHD_UCODE_DOWNLOAD ++char ucode_path[MOD_PARAM_PATHLEN]; ++#endif /* DHD_UCODE_DOWNLOAD */ ++ ++module_param_string(clm_path, clm_path, MOD_PARAM_PATHLEN, 0660); ++ ++ ++/* backup buffer for firmware and nvram path */ ++char fw_bak_path[MOD_PARAM_PATHLEN]; ++char nv_bak_path[MOD_PARAM_PATHLEN]; ++ ++/* information string to keep firmware, chio, cheip version info visiable from log */ ++char info_string[MOD_PARAM_INFOLEN]; ++module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); ++int op_mode = 0; ++int disable_proptx = 0; ++module_param(op_mode, int, 0644); ++extern int wl_control_wl_start(struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (defined(BCMLXSDMMC) || defined(BCMDBUS)) ++struct semaphore dhd_registration_sem; ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++/* deferred handlers */ ++static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event); ++static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event); ++static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event); ++static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event); ++ ++#ifdef DHD_UPDATE_INTF_MAC ++static void dhd_ifupdate_event_handler(void *handle, void *event_info, u8 event); ++#endif /* DHD_UPDATE_INTF_MAC */ ++#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) ++static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event); ++#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ ++#ifdef WL_CFG80211 ++extern void dhd_netdev_free(struct net_device *ndev); ++#endif /* WL_CFG80211 */ ++ ++#if (defined(DHD_WET) || defined(DHD_MCAST_REGEN) || defined(DHD_L2_FILTER)) ++/* update rx_pkt_chainable state of dhd interface */ ++static void dhd_update_rx_pkt_chainable_state(dhd_pub_t* dhdp, uint32 idx); ++#endif /* DHD_WET || DHD_MCAST_REGEN || DHD_L2_FILTER */ ++ ++#ifdef HOFFLOAD_MODULES ++char dhd_hmem_module_string[MOD_PARAM_SRLEN]; ++module_param_string(dhd_hmem_module_string, dhd_hmem_module_string, MOD_PARAM_SRLEN, 0660); ++#endif ++/* Error bits */ ++module_param(dhd_msg_level, int, 0); ++#if defined(WL_WIRELESS_EXT) ++module_param(iw_msg_level, int, 0); ++#endif ++#ifdef WL_CFG80211 ++module_param(wl_dbg_level, int, 0); ++#endif ++module_param(android_msg_level, int, 0); ++module_param(config_msg_level, int, 0); ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++/* ARP offload enable */ ++uint dhd_arp_enable = TRUE; ++module_param(dhd_arp_enable, uint, 0); ++ ++/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ ++ ++#ifdef ENABLE_ARP_SNOOP_MODE ++uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY | ARP_OL_SNOOP | ARP_OL_HOST_AUTO_REPLY; ++#else ++uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; ++#endif /* ENABLE_ARP_SNOOP_MODE */ ++ ++module_param(dhd_arp_mode, uint, 0); ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++/* Disable Prop tx */ ++module_param(disable_proptx, int, 0644); ++/* load firmware and/or nvram values from the filesystem */ ++module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); ++module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660); ++module_param_string(config_path, config_path, MOD_PARAM_PATHLEN, 0); ++#ifdef DHD_UCODE_DOWNLOAD ++module_param_string(ucode_path, ucode_path, MOD_PARAM_PATHLEN, 0660); ++#endif /* DHD_UCODE_DOWNLOAD */ ++ ++/* Watchdog interval */ ++ ++/* extend watchdog expiration to 2 seconds when DPC is running */ ++#define WATCHDOG_EXTEND_INTERVAL (2000) ++ ++uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS; ++module_param(dhd_watchdog_ms, uint, 0); ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++uint dhd_runtimepm_ms = CUSTOM_DHD_RUNTIME_MS; ++#endif /* DHD_PCIE_RUNTIMEPMT */ ++#if defined(DHD_DEBUG) ++/* Console poll interval */ ++uint dhd_console_ms = 0; ++module_param(dhd_console_ms, uint, 0644); ++#else ++uint dhd_console_ms = 0; ++#endif /* DHD_DEBUG */ ++ ++uint dhd_slpauto = TRUE; ++module_param(dhd_slpauto, uint, 0); ++ ++#ifdef PKT_FILTER_SUPPORT ++/* Global Pkt filter enable control */ ++uint dhd_pkt_filter_enable = TRUE; ++module_param(dhd_pkt_filter_enable, uint, 0); ++#endif ++ ++/* Pkt filter init setup */ ++uint dhd_pkt_filter_init = 0; ++module_param(dhd_pkt_filter_init, uint, 0); ++ ++/* Pkt filter mode control */ ++#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER ++uint dhd_master_mode = FALSE; ++#else ++uint dhd_master_mode = FALSE; ++#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ ++module_param(dhd_master_mode, uint, 0); ++ ++int dhd_watchdog_prio = 0; ++module_param(dhd_watchdog_prio, int, 0); ++ ++/* DPC thread priority */ ++int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; ++module_param(dhd_dpc_prio, int, 0); ++ ++/* RX frame thread priority */ ++int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; ++module_param(dhd_rxf_prio, int, 0); ++ ++#if !defined(BCMDBUS) ++extern int dhd_dongle_ramsize; ++module_param(dhd_dongle_ramsize, int, 0); ++#endif /* !BCMDBUS */ ++ ++#ifdef WL_CFG80211 ++int passive_channel_skip = 0; ++module_param(passive_channel_skip, int, (S_IRUSR|S_IWUSR)); ++#endif /* WL_CFG80211 */ ++ ++/* Keep track of number of instances */ ++static int dhd_found = 0; ++static int instance_base = 0; /* Starting instance number */ ++module_param(instance_base, int, 0644); ++ ++#if defined(DHD_LB_RXP) && defined(PCIE_FULL_DONGLE) ++static int dhd_napi_weight = 32; ++module_param(dhd_napi_weight, int, 0644); ++#endif /* DHD_LB_RXP && PCIE_FULL_DONGLE */ ++ ++#ifdef PCIE_FULL_DONGLE ++extern int h2d_max_txpost; ++module_param(h2d_max_txpost, int, 0644); ++#endif /* PCIE_FULL_DONGLE */ ++ ++#ifdef DHD_ARP_DUMP ++#include ++static const char arp_types[][10] = { ++ "NA", "REQUEST", "RESPONSE" ++}; ++static void dhd_arp_dump(char *ifname, uint8 *pktdata, bool tx); ++#endif /* DHD_ARP_DUMP */ ++ ++#ifdef DHD_DHCP_DUMP ++struct bootp_fmt { ++ struct iphdr ip_header; ++ struct udphdr udp_header; ++ uint8 op; ++ uint8 htype; ++ uint8 hlen; ++ uint8 hops; ++ uint32 transaction_id; ++ uint16 secs; ++ uint16 flags; ++ uint32 client_ip; ++ uint32 assigned_ip; ++ uint32 server_ip; ++ uint32 relay_ip; ++ uint8 hw_address[16]; ++ uint8 server_name[64]; ++ uint8 file_name[128]; ++ uint8 options[312]; ++}; ++ ++static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 }; ++static const char dhcp_ops[][10] = { ++ "NA", "REQUEST", "REPLY" ++}; ++static const char dhcp_types[][10] = { ++ "NA", "DISCOVER", "OFFER", "REQUEST", "DECLINE", "ACK", "NAK", "RELEASE", "INFORM" ++}; ++static void dhd_dhcp_dump(char *ifname, uint8 *pktdata, bool tx); ++#endif /* DHD_DHCP_DUMP */ ++ ++#ifdef DHD_ICMP_DUMP ++#include ++static void dhd_icmp_dump(char *ifname, uint8 *pktdata, bool tx); ++#endif /* DHD_ICMP_DUMP */ ++ ++/* Functions to manage sysfs interface for dhd */ ++static int dhd_sysfs_init(dhd_info_t *dhd); ++static void dhd_sysfs_exit(dhd_info_t *dhd); ++ ++#ifdef SHOW_LOGTRACE ++#if defined(CUSTOMER_HW4_DEBUG) ++static char *logstrs_path = PLATFORM_PATH"logstrs.bin"; ++static char *st_str_file_path = PLATFORM_PATH"rtecdc.bin"; ++static char *map_file_path = PLATFORM_PATH"rtecdc.map"; ++static char *rom_st_str_file_path = PLATFORM_PATH"roml.bin"; ++static char *rom_map_file_path = PLATFORM_PATH"roml.map"; ++#elif defined(CUSTOMER_HW2) ++static char *logstrs_path = "/data/misc/wifi/logstrs.bin"; ++static char *st_str_file_path = "/data/misc/wifi/rtecdc.bin"; ++static char *map_file_path = "/data/misc/wifi/rtecdc.map"; ++static char *rom_st_str_file_path = "/data/misc/wifi/roml.bin"; ++static char *rom_map_file_path = "/data/misc/wifi/roml.map"; ++#else ++static char *logstrs_path = "/installmedia/logstrs.bin"; ++static char *st_str_file_path = "/installmedia/rtecdc.bin"; ++static char *map_file_path = "/installmedia/rtecdc.map"; ++static char *rom_st_str_file_path = "/installmedia/roml.bin"; ++static char *rom_map_file_path = "/installmedia/roml.map"; ++#endif /* CUSTOMER_HW4_DEBUG || CUSTOMER_HW2 */ ++static char *ram_file_str = "rtecdc"; ++static char *rom_file_str = "roml"; ++ ++module_param(logstrs_path, charp, S_IRUGO); ++module_param(st_str_file_path, charp, S_IRUGO); ++module_param(map_file_path, charp, S_IRUGO); ++module_param(rom_st_str_file_path, charp, S_IRUGO); ++module_param(rom_map_file_path, charp, S_IRUGO); ++ ++static int dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp); ++static int dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, ++ uint32 *rodata_end); ++static int dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, ++ char *map_file); ++#endif /* SHOW_LOGTRACE */ ++ ++#if defined(DHD_LB) ++ ++static void ++dhd_lb_set_default_cpus(dhd_info_t *dhd) ++{ ++ /* Default CPU allocation for the jobs */ ++ atomic_set(&dhd->rx_napi_cpu, 1); ++ atomic_set(&dhd->rx_compl_cpu, 2); ++ atomic_set(&dhd->tx_compl_cpu, 2); ++ atomic_set(&dhd->tx_cpu, 2); ++ atomic_set(&dhd->net_tx_cpu, 0); ++} ++ ++static void ++dhd_cpumasks_deinit(dhd_info_t *dhd) ++{ ++ free_cpumask_var(dhd->cpumask_curr_avail); ++ free_cpumask_var(dhd->cpumask_primary); ++ free_cpumask_var(dhd->cpumask_primary_new); ++ free_cpumask_var(dhd->cpumask_secondary); ++ free_cpumask_var(dhd->cpumask_secondary_new); ++} ++ ++static int ++dhd_cpumasks_init(dhd_info_t *dhd) ++{ ++ int id; ++ uint32 cpus, num_cpus = num_possible_cpus(); ++ int ret = 0; ++ ++ DHD_ERROR(("%s CPU masks primary(big)=0x%x secondary(little)=0x%x\n", __FUNCTION__, ++ DHD_LB_PRIMARY_CPUS, DHD_LB_SECONDARY_CPUS)); ++ ++ if (!alloc_cpumask_var(&dhd->cpumask_curr_avail, GFP_KERNEL) || ++ !alloc_cpumask_var(&dhd->cpumask_primary, GFP_KERNEL) || ++ !alloc_cpumask_var(&dhd->cpumask_primary_new, GFP_KERNEL) || ++ !alloc_cpumask_var(&dhd->cpumask_secondary, GFP_KERNEL) || ++ !alloc_cpumask_var(&dhd->cpumask_secondary_new, GFP_KERNEL)) { ++ DHD_ERROR(("%s Failed to init cpumasks\n", __FUNCTION__)); ++ ret = -ENOMEM; ++ goto fail; ++ } ++ ++ cpumask_copy(dhd->cpumask_curr_avail, cpu_online_mask); ++ cpumask_clear(dhd->cpumask_primary); ++ cpumask_clear(dhd->cpumask_secondary); ++ ++ if (num_cpus > 32) { ++ DHD_ERROR(("%s max cpus must be 32, %d too big\n", __FUNCTION__, num_cpus)); ++ ASSERT(0); ++ } ++ ++ cpus = DHD_LB_PRIMARY_CPUS; ++ for (id = 0; id < num_cpus; id++) { ++ if (isset(&cpus, id)) ++ cpumask_set_cpu(id, dhd->cpumask_primary); ++ } ++ ++ cpus = DHD_LB_SECONDARY_CPUS; ++ for (id = 0; id < num_cpus; id++) { ++ if (isset(&cpus, id)) ++ cpumask_set_cpu(id, dhd->cpumask_secondary); ++ } ++ ++ return ret; ++fail: ++ dhd_cpumasks_deinit(dhd); ++ return ret; ++} ++ ++/* ++ * The CPU Candidacy Algorithm ++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++ * The available CPUs for selection are divided into two groups ++ * Primary Set - A CPU mask that carries the First Choice CPUs ++ * Secondary Set - A CPU mask that carries the Second Choice CPUs. ++ * ++ * There are two types of Job, that needs to be assigned to ++ * the CPUs, from one of the above mentioned CPU group. The Jobs are ++ * 1) Rx Packet Processing - napi_cpu ++ * 2) Completion Processiong (Tx, RX) - compl_cpu ++ * ++ * To begin with both napi_cpu and compl_cpu are on CPU0. Whenever a CPU goes ++ * on-line/off-line the CPU candidacy algorithm is triggerd. The candidacy ++ * algo tries to pickup the first available non boot CPU (CPU0) for napi_cpu. ++ * If there are more processors free, it assigns one to compl_cpu. ++ * It also tries to ensure that both napi_cpu and compl_cpu are not on the same ++ * CPU, as much as possible. ++ * ++ * By design, both Tx and Rx completion jobs are run on the same CPU core, as it ++ * would allow Tx completion skb's to be released into a local free pool from ++ * which the rx buffer posts could have been serviced. it is important to note ++ * that a Tx packet may not have a large enough buffer for rx posting. ++ */ ++void dhd_select_cpu_candidacy(dhd_info_t *dhd) ++{ ++ uint32 primary_available_cpus; /* count of primary available cpus */ ++ uint32 secondary_available_cpus; /* count of secondary available cpus */ ++ uint32 napi_cpu = 0; /* cpu selected for napi rx processing */ ++ uint32 compl_cpu = 0; /* cpu selected for completion jobs */ ++ uint32 tx_cpu = 0; /* cpu selected for tx processing job */ ++ ++ cpumask_clear(dhd->cpumask_primary_new); ++ cpumask_clear(dhd->cpumask_secondary_new); ++ ++ /* ++ * Now select from the primary mask. Even if a Job is ++ * already running on a CPU in secondary group, we still move ++ * to primary CPU. So no conditional checks. ++ */ ++ cpumask_and(dhd->cpumask_primary_new, dhd->cpumask_primary, ++ dhd->cpumask_curr_avail); ++ ++ cpumask_and(dhd->cpumask_secondary_new, dhd->cpumask_secondary, ++ dhd->cpumask_curr_avail); ++ ++ primary_available_cpus = cpumask_weight(dhd->cpumask_primary_new); ++ ++ if (primary_available_cpus > 0) { ++ napi_cpu = cpumask_first(dhd->cpumask_primary_new); ++ ++ /* If no further CPU is available, ++ * cpumask_next returns >= nr_cpu_ids ++ */ ++ tx_cpu = cpumask_next(napi_cpu, dhd->cpumask_primary_new); ++ if (tx_cpu >= nr_cpu_ids) ++ tx_cpu = 0; ++ ++ /* In case there are no more CPUs, do completions & Tx in same CPU */ ++ compl_cpu = cpumask_next(tx_cpu, dhd->cpumask_primary_new); ++ if (compl_cpu >= nr_cpu_ids) ++ compl_cpu = tx_cpu; ++ } ++ ++ DHD_INFO(("%s After primary CPU check napi_cpu %d compl_cpu %d tx_cpu %d\n", ++ __FUNCTION__, napi_cpu, compl_cpu, tx_cpu)); ++ ++ /* -- Now check for the CPUs from the secondary mask -- */ ++ secondary_available_cpus = cpumask_weight(dhd->cpumask_secondary_new); ++ ++ DHD_INFO(("%s Available secondary cpus %d nr_cpu_ids %d\n", ++ __FUNCTION__, secondary_available_cpus, nr_cpu_ids)); ++ ++ if (secondary_available_cpus > 0) { ++ /* At this point if napi_cpu is unassigned it means no CPU ++ * is online from Primary Group ++ */ ++ if (napi_cpu == 0) { ++ napi_cpu = cpumask_first(dhd->cpumask_secondary_new); ++ tx_cpu = cpumask_next(napi_cpu, dhd->cpumask_secondary_new); ++ compl_cpu = cpumask_next(tx_cpu, dhd->cpumask_secondary_new); ++ } else if (tx_cpu == 0) { ++ tx_cpu = cpumask_first(dhd->cpumask_secondary_new); ++ compl_cpu = cpumask_next(tx_cpu, dhd->cpumask_secondary_new); ++ } else if (compl_cpu == 0) { ++ compl_cpu = cpumask_first(dhd->cpumask_secondary_new); ++ } ++ ++ /* If no CPU was available for tx processing, choose CPU 0 */ ++ if (tx_cpu >= nr_cpu_ids) ++ tx_cpu = 0; ++ ++ /* If no CPU was available for completion, choose CPU 0 */ ++ if (compl_cpu >= nr_cpu_ids) ++ compl_cpu = 0; ++ } ++ if ((primary_available_cpus == 0) && ++ (secondary_available_cpus == 0)) { ++ /* No CPUs available from primary or secondary mask */ ++ napi_cpu = 1; ++ compl_cpu = 0; ++ tx_cpu = 2; ++ } ++ ++ DHD_INFO(("%s After secondary CPU check napi_cpu %d compl_cpu %d tx_cpu %d\n", ++ __FUNCTION__, napi_cpu, compl_cpu, tx_cpu)); ++ ++ ASSERT(napi_cpu < nr_cpu_ids); ++ ASSERT(compl_cpu < nr_cpu_ids); ++ ASSERT(tx_cpu < nr_cpu_ids); ++ ++ atomic_set(&dhd->rx_napi_cpu, napi_cpu); ++ atomic_set(&dhd->tx_compl_cpu, compl_cpu); ++ atomic_set(&dhd->rx_compl_cpu, compl_cpu); ++ atomic_set(&dhd->tx_cpu, tx_cpu); ++ ++ return; ++} ++ ++/* ++ * Function to handle CPU Hotplug notifications. ++ * One of the task it does is to trigger the CPU Candidacy algorithm ++ * for load balancing. ++ */ ++int ++dhd_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) ++{ ++ unsigned long int cpu = (unsigned long int)hcpu; ++ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ dhd_info_t *dhd = container_of(nfb, dhd_info_t, cpu_notifier); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ ++ if (!dhd || !(dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE)) { ++ DHD_INFO(("%s(): LB data is not initialized yet.\n", ++ __FUNCTION__)); ++ return NOTIFY_BAD; ++ } ++ ++ switch (action) ++ { ++ case CPU_ONLINE: ++ case CPU_ONLINE_FROZEN: ++ DHD_LB_STATS_INCR(dhd->cpu_online_cnt[cpu]); ++ cpumask_set_cpu(cpu, dhd->cpumask_curr_avail); ++ dhd_select_cpu_candidacy(dhd); ++ break; ++ ++ case CPU_DOWN_PREPARE: ++ case CPU_DOWN_PREPARE_FROZEN: ++ DHD_LB_STATS_INCR(dhd->cpu_offline_cnt[cpu]); ++ cpumask_clear_cpu(cpu, dhd->cpumask_curr_avail); ++ dhd_select_cpu_candidacy(dhd); ++ break; ++ default: ++ break; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++#if defined(DHD_LB_STATS) ++void dhd_lb_stats_init(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ int i, j, num_cpus = num_possible_cpus(); ++ int alloc_size = sizeof(uint32) * num_cpus; ++ ++ if (dhdp == NULL) { ++ DHD_ERROR(("%s(): Invalid argument dhd pubb pointer is NULL \n", ++ __FUNCTION__)); ++ return; ++ } ++ ++ dhd = dhdp->info; ++ if (dhd == NULL) { ++ DHD_ERROR(("%s(): DHD pointer is NULL \n", __FUNCTION__)); ++ return; ++ } ++ ++ DHD_LB_STATS_CLR(dhd->dhd_dpc_cnt); ++ DHD_LB_STATS_CLR(dhd->napi_sched_cnt); ++ ++ dhd->napi_percpu_run_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); ++ if (!dhd->napi_percpu_run_cnt) { ++ DHD_ERROR(("%s(): napi_percpu_run_cnt malloc failed \n", ++ __FUNCTION__)); ++ return; ++ } ++ for (i = 0; i < num_cpus; i++) ++ DHD_LB_STATS_CLR(dhd->napi_percpu_run_cnt[i]); ++ ++ DHD_LB_STATS_CLR(dhd->rxc_sched_cnt); ++ ++ dhd->rxc_percpu_run_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); ++ if (!dhd->rxc_percpu_run_cnt) { ++ DHD_ERROR(("%s(): rxc_percpu_run_cnt malloc failed \n", ++ __FUNCTION__)); ++ return; ++ } ++ for (i = 0; i < num_cpus; i++) ++ DHD_LB_STATS_CLR(dhd->rxc_percpu_run_cnt[i]); ++ ++ DHD_LB_STATS_CLR(dhd->txc_sched_cnt); ++ ++ dhd->txc_percpu_run_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); ++ if (!dhd->txc_percpu_run_cnt) { ++ DHD_ERROR(("%s(): txc_percpu_run_cnt malloc failed \n", ++ __FUNCTION__)); ++ return; ++ } ++ for (i = 0; i < num_cpus; i++) ++ DHD_LB_STATS_CLR(dhd->txc_percpu_run_cnt[i]); ++ ++ dhd->cpu_online_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); ++ if (!dhd->cpu_online_cnt) { ++ DHD_ERROR(("%s(): cpu_online_cnt malloc failed \n", ++ __FUNCTION__)); ++ return; ++ } ++ for (i = 0; i < num_cpus; i++) ++ DHD_LB_STATS_CLR(dhd->cpu_online_cnt[i]); ++ ++ dhd->cpu_offline_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); ++ if (!dhd->cpu_offline_cnt) { ++ DHD_ERROR(("%s(): cpu_offline_cnt malloc failed \n", ++ __FUNCTION__)); ++ return; ++ } ++ for (i = 0; i < num_cpus; i++) ++ DHD_LB_STATS_CLR(dhd->cpu_offline_cnt[i]); ++ ++ dhd->txp_percpu_run_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); ++ if (!dhd->txp_percpu_run_cnt) { ++ DHD_ERROR(("%s(): txp_percpu_run_cnt malloc failed \n", ++ __FUNCTION__)); ++ return; ++ } ++ for (i = 0; i < num_cpus; i++) ++ DHD_LB_STATS_CLR(dhd->txp_percpu_run_cnt[i]); ++ ++ dhd->tx_start_percpu_run_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); ++ if (!dhd->tx_start_percpu_run_cnt) { ++ DHD_ERROR(("%s(): tx_start_percpu_run_cnt malloc failed \n", ++ __FUNCTION__)); ++ return; ++ } ++ for (i = 0; i < num_cpus; i++) ++ DHD_LB_STATS_CLR(dhd->tx_start_percpu_run_cnt[i]); ++ ++ for (j = 0; j < HIST_BIN_SIZE; j++) { ++ dhd->napi_rx_hist[j] = (uint32 *)MALLOC(dhdp->osh, alloc_size); ++ if (!dhd->napi_rx_hist[j]) { ++ DHD_ERROR(("%s(): dhd->napi_rx_hist[%d] malloc failed \n", ++ __FUNCTION__, j)); ++ return; ++ } ++ for (i = 0; i < num_cpus; i++) { ++ DHD_LB_STATS_CLR(dhd->napi_rx_hist[j][i]); ++ } ++ } ++#ifdef DHD_LB_TXC ++ for (j = 0; j < HIST_BIN_SIZE; j++) { ++ dhd->txc_hist[j] = (uint32 *)MALLOC(dhdp->osh, alloc_size); ++ if (!dhd->txc_hist[j]) { ++ DHD_ERROR(("%s(): dhd->txc_hist[%d] malloc failed \n", ++ __FUNCTION__, j)); ++ return; ++ } ++ for (i = 0; i < num_cpus; i++) { ++ DHD_LB_STATS_CLR(dhd->txc_hist[j][i]); ++ } ++ } ++#endif /* DHD_LB_TXC */ ++#ifdef DHD_LB_RXC ++ for (j = 0; j < HIST_BIN_SIZE; j++) { ++ dhd->rxc_hist[j] = (uint32 *)MALLOC(dhdp->osh, alloc_size); ++ if (!dhd->rxc_hist[j]) { ++ DHD_ERROR(("%s(): dhd->rxc_hist[%d] malloc failed \n", ++ __FUNCTION__, j)); ++ return; ++ } ++ for (i = 0; i < num_cpus; i++) { ++ DHD_LB_STATS_CLR(dhd->rxc_hist[j][i]); ++ } ++ } ++#endif /* DHD_LB_RXC */ ++ return; ++} ++ ++void dhd_lb_stats_deinit(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ int j, num_cpus = num_possible_cpus(); ++ int alloc_size = sizeof(uint32) * num_cpus; ++ ++ if (dhdp == NULL) { ++ DHD_ERROR(("%s(): Invalid argument dhd pubb pointer is NULL \n", ++ __FUNCTION__)); ++ return; ++ } ++ ++ dhd = dhdp->info; ++ if (dhd == NULL) { ++ DHD_ERROR(("%s(): DHD pointer is NULL \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (dhd->napi_percpu_run_cnt) { ++ MFREE(dhdp->osh, dhd->napi_percpu_run_cnt, alloc_size); ++ dhd->napi_percpu_run_cnt = NULL; ++ } ++ if (dhd->rxc_percpu_run_cnt) { ++ MFREE(dhdp->osh, dhd->rxc_percpu_run_cnt, alloc_size); ++ dhd->rxc_percpu_run_cnt = NULL; ++ } ++ if (dhd->txc_percpu_run_cnt) { ++ MFREE(dhdp->osh, dhd->txc_percpu_run_cnt, alloc_size); ++ dhd->txc_percpu_run_cnt = NULL; ++ } ++ if (dhd->cpu_online_cnt) { ++ MFREE(dhdp->osh, dhd->cpu_online_cnt, alloc_size); ++ dhd->cpu_online_cnt = NULL; ++ } ++ if (dhd->cpu_offline_cnt) { ++ MFREE(dhdp->osh, dhd->cpu_offline_cnt, alloc_size); ++ dhd->cpu_offline_cnt = NULL; ++ } ++ ++ if (dhd->txp_percpu_run_cnt) { ++ MFREE(dhdp->osh, dhd->txp_percpu_run_cnt, alloc_size); ++ dhd->txp_percpu_run_cnt = NULL; ++ } ++ if (dhd->tx_start_percpu_run_cnt) { ++ MFREE(dhdp->osh, dhd->tx_start_percpu_run_cnt, alloc_size); ++ dhd->tx_start_percpu_run_cnt = NULL; ++ } ++ ++ for (j = 0; j < HIST_BIN_SIZE; j++) { ++ if (dhd->napi_rx_hist[j]) { ++ MFREE(dhdp->osh, dhd->napi_rx_hist[j], alloc_size); ++ dhd->napi_rx_hist[j] = NULL; ++ } ++#ifdef DHD_LB_TXC ++ if (dhd->txc_hist[j]) { ++ MFREE(dhdp->osh, dhd->txc_hist[j], alloc_size); ++ dhd->txc_hist[j] = NULL; ++ } ++#endif /* DHD_LB_TXC */ ++#ifdef DHD_LB_RXC ++ if (dhd->rxc_hist[j]) { ++ MFREE(dhdp->osh, dhd->rxc_hist[j], alloc_size); ++ dhd->rxc_hist[j] = NULL; ++ } ++#endif /* DHD_LB_RXC */ ++ } ++ ++ return; ++} ++ ++static void dhd_lb_stats_dump_histo( ++ struct bcmstrbuf *strbuf, uint32 **hist) ++{ ++ int i, j; ++ uint32 *per_cpu_total; ++ uint32 total = 0; ++ uint32 num_cpus = num_possible_cpus(); ++ ++ per_cpu_total = (uint32 *)kmalloc(sizeof(uint32) * num_cpus, GFP_ATOMIC); ++ if (!per_cpu_total) { ++ DHD_ERROR(("%s(): dhd->per_cpu_total malloc failed \n", __FUNCTION__)); ++ return; ++ } ++ bzero(per_cpu_total, sizeof(uint32) * num_cpus); ++ ++ bcm_bprintf(strbuf, "CPU: \t\t"); ++ for (i = 0; i < num_cpus; i++) ++ bcm_bprintf(strbuf, "%d\t", i); ++ bcm_bprintf(strbuf, "\nBin\n"); ++ ++ for (i = 0; i < HIST_BIN_SIZE; i++) { ++ bcm_bprintf(strbuf, "%d:\t\t", 1<info; ++ if (dhd == NULL) { ++ DHD_ERROR(("%s(): DHD pointer is NULL \n", __FUNCTION__)); ++ return; ++ } ++ ++ bcm_bprintf(strbuf, "\ncpu_online_cnt:\n"); ++ dhd_lb_stats_dump_cpu_array(strbuf, dhd->cpu_online_cnt); ++ ++ bcm_bprintf(strbuf, "\ncpu_offline_cnt:\n"); ++ dhd_lb_stats_dump_cpu_array(strbuf, dhd->cpu_offline_cnt); ++ ++ bcm_bprintf(strbuf, "\nsched_cnt: dhd_dpc %u napi %u rxc %u txc %u\n", ++ dhd->dhd_dpc_cnt, dhd->napi_sched_cnt, dhd->rxc_sched_cnt, ++ dhd->txc_sched_cnt); ++ ++#ifdef DHD_LB_RXP ++ bcm_bprintf(strbuf, "\nnapi_percpu_run_cnt:\n"); ++ dhd_lb_stats_dump_cpu_array(strbuf, dhd->napi_percpu_run_cnt); ++ bcm_bprintf(strbuf, "\nNAPI Packets Received Histogram:\n"); ++ dhd_lb_stats_dump_histo(strbuf, dhd->napi_rx_hist); ++#endif /* DHD_LB_RXP */ ++ ++#ifdef DHD_LB_RXC ++ bcm_bprintf(strbuf, "\nrxc_percpu_run_cnt:\n"); ++ dhd_lb_stats_dump_cpu_array(strbuf, dhd->rxc_percpu_run_cnt); ++ bcm_bprintf(strbuf, "\nRX Completions (Buffer Post) Histogram:\n"); ++ dhd_lb_stats_dump_histo(strbuf, dhd->rxc_hist); ++#endif /* DHD_LB_RXC */ ++ ++#ifdef DHD_LB_TXC ++ bcm_bprintf(strbuf, "\ntxc_percpu_run_cnt:\n"); ++ dhd_lb_stats_dump_cpu_array(strbuf, dhd->txc_percpu_run_cnt); ++ bcm_bprintf(strbuf, "\nTX Completions (Buffer Free) Histogram:\n"); ++ dhd_lb_stats_dump_histo(strbuf, dhd->txc_hist); ++#endif /* DHD_LB_TXC */ ++ ++#ifdef DHD_LB_TXP ++ bcm_bprintf(strbuf, "\ntxp_percpu_run_cnt:\n"); ++ dhd_lb_stats_dump_cpu_array(strbuf, dhd->txp_percpu_run_cnt); ++ ++ bcm_bprintf(strbuf, "\ntx_start_percpu_run_cnt:\n"); ++ dhd_lb_stats_dump_cpu_array(strbuf, dhd->tx_start_percpu_run_cnt); ++#endif /* DHD_LB_TXP */ ++ ++ bcm_bprintf(strbuf, "\nCPU masks primary(big)=0x%x secondary(little)=0x%x\n", ++ DHD_LB_PRIMARY_CPUS, DHD_LB_SECONDARY_CPUS); ++ ++ bcm_bprintf(strbuf, "napi_cpu %x tx_cpu %x\n", ++ atomic_read(&dhd->rx_napi_cpu), atomic_read(&dhd->tx_cpu)); ++ ++} ++ ++/* Given a number 'n' returns 'm' that is next larger power of 2 after n */ ++static inline uint32 next_larger_power2(uint32 num) ++{ ++ num--; ++ num |= (num >> 1); ++ num |= (num >> 2); ++ num |= (num >> 4); ++ num |= (num >> 8); ++ num |= (num >> 16); ++ ++ return (num + 1); ++} ++ ++static void dhd_lb_stats_update_histo(uint32 **bin, uint32 count, uint32 cpu) ++{ ++ uint32 bin_power; ++ uint32 *p; ++ bin_power = next_larger_power2(count); ++ ++ switch (bin_power) { ++ case 1: p = bin[0] + cpu; break; ++ case 2: p = bin[1] + cpu; break; ++ case 4: p = bin[2] + cpu; break; ++ case 8: p = bin[3] + cpu; break; ++ case 16: p = bin[4] + cpu; break; ++ case 32: p = bin[5] + cpu; break; ++ case 64: p = bin[6] + cpu; break; ++ case 128: p = bin[7] + cpu; break; ++ default : p = bin[8] + cpu; break; ++ } ++ ++ *p = *p + 1; ++ return; ++} ++ ++extern void dhd_lb_stats_update_napi_histo(dhd_pub_t *dhdp, uint32 count) ++{ ++ int cpu; ++ dhd_info_t *dhd = dhdp->info; ++ ++ cpu = get_cpu(); ++ put_cpu(); ++ dhd_lb_stats_update_histo(dhd->napi_rx_hist, count, cpu); ++ ++ return; ++} ++ ++extern void dhd_lb_stats_update_txc_histo(dhd_pub_t *dhdp, uint32 count) ++{ ++ int cpu; ++ dhd_info_t *dhd = dhdp->info; ++ ++ cpu = get_cpu(); ++ put_cpu(); ++ dhd_lb_stats_update_histo(dhd->txc_hist, count, cpu); ++ ++ return; ++} ++ ++extern void dhd_lb_stats_update_rxc_histo(dhd_pub_t *dhdp, uint32 count) ++{ ++ int cpu; ++ dhd_info_t *dhd = dhdp->info; ++ ++ cpu = get_cpu(); ++ put_cpu(); ++ dhd_lb_stats_update_histo(dhd->rxc_hist, count, cpu); ++ ++ return; ++} ++ ++extern void dhd_lb_stats_txc_percpu_cnt_incr(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ DHD_LB_STATS_PERCPU_ARR_INCR(dhd->txc_percpu_run_cnt); ++} ++ ++extern void dhd_lb_stats_rxc_percpu_cnt_incr(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ DHD_LB_STATS_PERCPU_ARR_INCR(dhd->rxc_percpu_run_cnt); ++} ++#endif /* DHD_LB_STATS */ ++ ++#endif /* DHD_LB */ ++ ++#if defined(DISABLE_FRAMEBURST_VSDB) && defined(USE_WFA_CERT_CONF) ++int g_frameburst = 1; ++#endif /* DISABLE_FRAMEBURST_VSDB && USE_WFA_CERT_CONF */ ++ ++static int dhd_get_pend_8021x_cnt(dhd_info_t *dhd); ++ ++/* DHD Perimiter lock only used in router with bypass forwarding. */ ++#define DHD_PERIM_RADIO_INIT() do { /* noop */ } while (0) ++#define DHD_PERIM_LOCK_TRY(unit, flag) do { /* noop */ } while (0) ++#define DHD_PERIM_UNLOCK_TRY(unit, flag) do { /* noop */ } while (0) ++ ++#ifdef PCIE_FULL_DONGLE ++#if defined(BCM_GMAC3) ++#define DHD_IF_STA_LIST_LOCK_INIT(ifp) do { /* noop */ } while (0) ++#define DHD_IF_STA_LIST_LOCK(ifp, flags) ({ BCM_REFERENCE(flags); }) ++#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) ({ BCM_REFERENCE(flags); }) ++ ++#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) ++#define DHD_IF_WMF_UCFORWARD_LOCK(dhd, ifp, slist) ({ BCM_REFERENCE(slist); &(ifp)->sta_list; }) ++#define DHD_IF_WMF_UCFORWARD_UNLOCK(dhd, slist) ({ BCM_REFERENCE(slist); }) ++#endif /* DHD_IGMP_UCQUERY || DHD_UCAST_UPNP */ ++ ++#else /* ! BCM_GMAC3 */ ++#define DHD_IF_STA_LIST_LOCK_INIT(ifp) spin_lock_init(&(ifp)->sta_list_lock) ++#define DHD_IF_STA_LIST_LOCK(ifp, flags) \ ++ spin_lock_irqsave(&(ifp)->sta_list_lock, (flags)) ++#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) \ ++ spin_unlock_irqrestore(&(ifp)->sta_list_lock, (flags)) ++ ++#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) ++static struct list_head * dhd_sta_list_snapshot(dhd_info_t *dhd, dhd_if_t *ifp, ++ struct list_head *snapshot_list); ++static void dhd_sta_list_snapshot_free(dhd_info_t *dhd, struct list_head *snapshot_list); ++#define DHD_IF_WMF_UCFORWARD_LOCK(dhd, ifp, slist) ({ dhd_sta_list_snapshot(dhd, ifp, slist); }) ++#define DHD_IF_WMF_UCFORWARD_UNLOCK(dhd, slist) ({ dhd_sta_list_snapshot_free(dhd, slist); }) ++#endif /* DHD_IGMP_UCQUERY || DHD_UCAST_UPNP */ ++ ++#endif /* ! BCM_GMAC3 */ ++#endif /* PCIE_FULL_DONGLE */ ++ ++/* Control fw roaming */ ++uint dhd_roam_disable = 0; ++ ++#ifdef BCMDBGFS ++extern void dhd_dbgfs_init(dhd_pub_t *dhdp); ++extern void dhd_dbgfs_remove(void); ++#endif ++ ++ ++/* Control radio state */ ++uint dhd_radio_up = 1; ++ ++/* Network inteface name */ ++char iface_name[IFNAMSIZ] = {'\0'}; ++module_param_string(iface_name, iface_name, IFNAMSIZ, 0); ++ ++/* The following are specific to the SDIO dongle */ ++ ++/* IOCTL response timeout */ ++int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; ++ ++/* DS Exit response timeout */ ++int ds_exit_timeout_msec = DS_EXIT_TIMEOUT; ++ ++/* Idle timeout for backplane clock */ ++int dhd_idletime = DHD_IDLETIME_TICKS; ++module_param(dhd_idletime, int, 0); ++ ++/* Use polling */ ++uint dhd_poll = FALSE; ++module_param(dhd_poll, uint, 0); ++ ++/* Use interrupts */ ++uint dhd_intr = TRUE; ++module_param(dhd_intr, uint, 0); ++ ++/* SDIO Drive Strength (in milliamps) */ ++uint dhd_sdiod_drive_strength = 6; ++module_param(dhd_sdiod_drive_strength, uint, 0); ++ ++#ifdef BCMSDIO ++/* Tx/Rx bounds */ ++extern uint dhd_txbound; ++extern uint dhd_rxbound; ++module_param(dhd_txbound, uint, 0); ++module_param(dhd_rxbound, uint, 0); ++ ++/* Deferred transmits */ ++extern uint dhd_deferred_tx; ++module_param(dhd_deferred_tx, uint, 0); ++ ++#endif /* BCMSDIO */ ++ ++ ++#ifdef SDTEST ++/* Echo packet generator (pkts/s) */ ++uint dhd_pktgen = 0; ++module_param(dhd_pktgen, uint, 0); ++ ++/* Echo packet len (0 => sawtooth, max 2040) */ ++uint dhd_pktgen_len = 0; ++module_param(dhd_pktgen_len, uint, 0); ++#endif /* SDTEST */ ++ ++ ++ ++#ifndef BCMDBUS ++/* Allow delayed firmware download for debug purpose */ ++int allow_delay_fwdl = FALSE; ++module_param(allow_delay_fwdl, int, 0); ++#endif /* !BCMDBUS */ ++ ++extern char dhd_version[]; ++extern char fw_version[]; ++extern char clm_version[]; ++ ++int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); ++static void dhd_net_if_lock_local(dhd_info_t *dhd); ++static void dhd_net_if_unlock_local(dhd_info_t *dhd); ++static void dhd_suspend_lock(dhd_pub_t *dhdp); ++static void dhd_suspend_unlock(dhd_pub_t *dhdp); ++ ++#ifdef WLMEDIA_HTSF ++void htsf_update(dhd_info_t *dhd, void *data); ++tsf_t prev_tsf, cur_tsf; ++ ++uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); ++static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); ++static void dhd_dump_latency(void); ++static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); ++static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); ++static void dhd_dump_htsfhisto(histo_t *his, char *s); ++#endif /* WLMEDIA_HTSF */ ++ ++/* Monitor interface */ ++int dhd_monitor_init(void *dhd_pub); ++int dhd_monitor_uninit(void); ++ ++ ++#if defined(WL_WIRELESS_EXT) ++struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); ++#endif /* defined(WL_WIRELESS_EXT) */ ++ ++#ifndef BCMDBUS ++static void dhd_dpc(ulong data); ++#endif /* !BCMDBUS */ ++/* forward decl */ ++extern int dhd_wait_pend8021x(struct net_device *dev); ++void dhd_os_wd_timer_extend(void *bus, bool extend); ++ ++#ifdef TOE ++#ifndef BDC ++#error TOE requires BDC ++#endif /* !BDC */ ++static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); ++static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); ++#endif /* TOE */ ++ ++static int dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen, ++ wl_event_msg_t *event_ptr, void **data_ptr); ++ ++#if defined(CONFIG_PM_SLEEP) ++static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) ++{ ++ int ret = NOTIFY_DONE; ++ bool suspend = FALSE; ++ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ ++ BCM_REFERENCE(dhdinfo); ++ BCM_REFERENCE(suspend); ++ ++ switch (action) { ++ case PM_HIBERNATION_PREPARE: ++ case PM_SUSPEND_PREPARE: ++ suspend = TRUE; ++ break; ++ ++ case PM_POST_HIBERNATION: ++ case PM_POST_SUSPEND: ++ suspend = FALSE; ++ break; ++ } ++ ++ printf("%s: action=%ld, suspend=%d, suspend_mode=%d\n", ++ __FUNCTION__, action, suspend, dhdinfo->pub.conf->suspend_mode); ++ if (suspend) { ++ DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub); ++ if (dhdinfo->pub.conf->suspend_mode == PM_NOTIFIER) ++ dhd_suspend_resume_helper(dhdinfo, suspend, 0); ++#if defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) ++ dhd_wlfc_suspend(&dhdinfo->pub); ++#endif /* defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) */ ++ if (dhdinfo->pub.conf->suspend_mode == PM_NOTIFIER) ++ dhd_conf_set_suspend_resume(&dhdinfo->pub, suspend); ++ DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub); ++ } else { ++ if (dhdinfo->pub.conf->suspend_mode == PM_NOTIFIER) ++ dhd_conf_set_suspend_resume(&dhdinfo->pub, suspend); ++#if defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) ++ dhd_wlfc_resume(&dhdinfo->pub); ++#endif /* defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) */ ++ if (dhdinfo->pub.conf->suspend_mode == PM_NOTIFIER) ++ dhd_suspend_resume_helper(dhdinfo, suspend, 0); ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ ++ KERNEL_VERSION(2, 6, 39)) ++ dhd_mmc_suspend = suspend; ++ smp_mb(); ++#endif ++ ++ return ret; ++} ++ ++/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be ++ * created in kernel notifier link list (with 'next' pointing to itself) ++ */ ++static bool dhd_pm_notifier_registered = FALSE; ++ ++extern int register_pm_notifier(struct notifier_block *nb); ++extern int unregister_pm_notifier(struct notifier_block *nb); ++#endif /* CONFIG_PM_SLEEP */ ++ ++/* Request scheduling of the bus rx frame */ ++static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb); ++static void dhd_os_rxflock(dhd_pub_t *pub); ++static void dhd_os_rxfunlock(dhd_pub_t *pub); ++ ++/** priv_link is the link between netdev and the dhdif and dhd_info structs. */ ++typedef struct dhd_dev_priv { ++ dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */ ++ dhd_if_t * ifp; /* cached pointer to dhd_if in netdevice priv */ ++ int ifidx; /* interface index */ ++ void * lkup; ++} dhd_dev_priv_t; ++ ++#define DHD_DEV_PRIV_SIZE (sizeof(dhd_dev_priv_t)) ++#define DHD_DEV_PRIV(dev) ((dhd_dev_priv_t *)DEV_PRIV(dev)) ++#define DHD_DEV_INFO(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd) ++#define DHD_DEV_IFP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp) ++#define DHD_DEV_IFIDX(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx) ++#define DHD_DEV_LKUP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->lkup) ++ ++#if defined(DHD_OF_SUPPORT) ++extern int dhd_wlan_init(void); ++#endif /* defined(DHD_OF_SUPPORT) */ ++/** Clear the dhd net_device's private structure. */ ++static inline void ++dhd_dev_priv_clear(struct net_device * dev) ++{ ++ dhd_dev_priv_t * dev_priv; ++ ASSERT(dev != (struct net_device *)NULL); ++ dev_priv = DHD_DEV_PRIV(dev); ++ dev_priv->dhd = (dhd_info_t *)NULL; ++ dev_priv->ifp = (dhd_if_t *)NULL; ++ dev_priv->ifidx = DHD_BAD_IF; ++ dev_priv->lkup = (void *)NULL; ++} ++ ++/** Setup the dhd net_device's private structure. */ ++static inline void ++dhd_dev_priv_save(struct net_device * dev, dhd_info_t * dhd, dhd_if_t * ifp, ++ int ifidx) ++{ ++ dhd_dev_priv_t * dev_priv; ++ ASSERT(dev != (struct net_device *)NULL); ++ dev_priv = DHD_DEV_PRIV(dev); ++ dev_priv->dhd = dhd; ++ dev_priv->ifp = ifp; ++ dev_priv->ifidx = ifidx; ++} ++ ++#ifdef PCIE_FULL_DONGLE ++ ++/** Dummy objects are defined with state representing bad|down. ++ * Performance gains from reducing branch conditionals, instruction parallelism, ++ * dual issue, reducing load shadows, avail of larger pipelines. ++ * Use DHD_XXX_NULL instead of (dhd_xxx_t *)NULL, whenever an object pointer ++ * is accessed via the dhd_sta_t. ++ */ ++ ++/* Dummy dhd_info object */ ++dhd_info_t dhd_info_null = { ++#if defined(BCM_GMAC3) ++ .fwdh = FWDER_NULL, ++#endif ++ .pub = { ++ .info = &dhd_info_null, ++#ifdef DHDTCPACK_SUPPRESS ++ .tcpack_sup_mode = TCPACK_SUP_REPLACE, ++#endif /* DHDTCPACK_SUPPRESS */ ++#if defined(TRAFFIC_MGMT_DWM) ++ .dhd_tm_dwm_tbl = { .dhd_dwm_enabled = TRUE }, ++#endif ++ .up = FALSE, ++ .busstate = DHD_BUS_DOWN ++ } ++}; ++#define DHD_INFO_NULL (&dhd_info_null) ++#define DHD_PUB_NULL (&dhd_info_null.pub) ++ ++/* Dummy netdevice object */ ++struct net_device dhd_net_dev_null = { ++ .reg_state = NETREG_UNREGISTERED ++}; ++#define DHD_NET_DEV_NULL (&dhd_net_dev_null) ++ ++/* Dummy dhd_if object */ ++dhd_if_t dhd_if_null = { ++#if defined(BCM_GMAC3) ++ .fwdh = FWDER_NULL, ++#endif ++#ifdef WMF ++ .wmf = { .wmf_enable = TRUE }, ++#endif ++ .info = DHD_INFO_NULL, ++ .net = DHD_NET_DEV_NULL, ++ .idx = DHD_BAD_IF ++}; ++#define DHD_IF_NULL (&dhd_if_null) ++ ++#define DHD_STA_NULL ((dhd_sta_t *)NULL) ++ ++/** Interface STA list management. */ ++ ++/** Fetch the dhd_if object, given the interface index in the dhd. */ ++static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx); ++ ++/** Alloc/Free a dhd_sta object from the dhd instances' sta_pool. */ ++static void dhd_sta_free(dhd_pub_t *pub, dhd_sta_t *sta); ++static dhd_sta_t * dhd_sta_alloc(dhd_pub_t * dhdp); ++ ++/* Delete a dhd_sta or flush all dhd_sta in an interface's sta_list. */ ++static void dhd_if_del_sta_list(dhd_if_t * ifp); ++static void dhd_if_flush_sta(dhd_if_t * ifp); ++ ++/* Construct/Destruct a sta pool. */ ++static int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta); ++static void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta); ++/* Clear the pool of dhd_sta_t objects for built-in type driver */ ++static void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta); ++ ++ ++/* Return interface pointer */ ++static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx) ++{ ++ ASSERT(ifidx < DHD_MAX_IFS); ++ ++ if (ifidx >= DHD_MAX_IFS) ++ return NULL; ++ ++ return dhdp->info->iflist[ifidx]; ++} ++ ++/** Reset a dhd_sta object and free into the dhd pool. */ ++static void ++dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta) ++{ ++ int prio; ++ ++ ASSERT((sta != DHD_STA_NULL) && (sta->idx != ID16_INVALID)); ++ ++ ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL)); ++ ++ /* ++ * Flush and free all packets in all flowring's queues belonging to sta. ++ * Packets in flow ring will be flushed later. ++ */ ++ for (prio = 0; prio < (int)NUMPRIO; prio++) { ++ uint16 flowid = sta->flowid[prio]; ++ ++ if (flowid != FLOWID_INVALID) { ++ unsigned long flags; ++ flow_queue_t * queue = dhd_flow_queue(dhdp, flowid); ++ flow_ring_node_t * flow_ring_node; ++ ++#ifdef DHDTCPACK_SUPPRESS ++ /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, ++ * when there is a newly coming packet from network stack. ++ */ ++ dhd_tcpack_info_tbl_clean(dhdp); ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++ flow_ring_node = dhd_flow_ring_node(dhdp, flowid); ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); ++ flow_ring_node->status = FLOW_RING_STATUS_STA_FREEING; ++ ++ if (!DHD_FLOW_QUEUE_EMPTY(queue)) { ++ void * pkt; ++ while ((pkt = dhd_flow_queue_dequeue(dhdp, queue)) != NULL) { ++ PKTFREE(dhdp->osh, pkt, TRUE); ++ } ++ } ++ ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ ASSERT(DHD_FLOW_QUEUE_EMPTY(queue)); ++ } ++ ++ sta->flowid[prio] = FLOWID_INVALID; ++ } ++ ++ id16_map_free(dhdp->staid_allocator, sta->idx); ++ DHD_CUMM_CTR_INIT(&sta->cumm_ctr); ++ sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */ ++ sta->ifidx = DHD_BAD_IF; ++ bzero(sta->ea.octet, ETHER_ADDR_LEN); ++ INIT_LIST_HEAD(&sta->list); ++ sta->idx = ID16_INVALID; /* implying free */ ++} ++ ++/** Allocate a dhd_sta object from the dhd pool. */ ++static dhd_sta_t * ++dhd_sta_alloc(dhd_pub_t * dhdp) ++{ ++ uint16 idx; ++ dhd_sta_t * sta; ++ dhd_sta_pool_t * sta_pool; ++ ++ ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL)); ++ ++ idx = id16_map_alloc(dhdp->staid_allocator); ++ if (idx == ID16_INVALID) { ++ DHD_ERROR(("%s: cannot get free staid\n", __FUNCTION__)); ++ return DHD_STA_NULL; ++ } ++ ++ sta_pool = (dhd_sta_pool_t *)(dhdp->sta_pool); ++ sta = &sta_pool[idx]; ++ ++ ASSERT((sta->idx == ID16_INVALID) && ++ (sta->ifp == DHD_IF_NULL) && (sta->ifidx == DHD_BAD_IF)); ++ ++ DHD_CUMM_CTR_INIT(&sta->cumm_ctr); ++ ++ sta->idx = idx; /* implying allocated */ ++ ++ return sta; ++} ++ ++/** Delete all STAs in an interface's STA list. */ ++static void ++dhd_if_del_sta_list(dhd_if_t *ifp) ++{ ++ dhd_sta_t *sta, *next; ++ unsigned long flags; ++ ++ DHD_IF_STA_LIST_LOCK(ifp, flags); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { ++#if defined(BCM_GMAC3) ++ if (ifp->fwdh) { ++ /* Remove sta from WOFA forwarder. */ ++ fwder_deassoc(ifp->fwdh, (uint16 *)(sta->ea.octet), (uintptr_t)sta); ++ } ++#endif /* BCM_GMAC3 */ ++ list_del(&sta->list); ++ dhd_sta_free(&ifp->info->pub, sta); ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ DHD_IF_STA_LIST_UNLOCK(ifp, flags); ++ ++ return; ++} ++ ++/** Router/GMAC3: Flush all station entries in the forwarder's WOFA database. */ ++static void ++dhd_if_flush_sta(dhd_if_t * ifp) ++{ ++#if defined(BCM_GMAC3) ++ ++ if (ifp && (ifp->fwdh != FWDER_NULL)) { ++ dhd_sta_t *sta, *next; ++ unsigned long flags; ++ ++ DHD_IF_STA_LIST_LOCK(ifp, flags); ++ ++ list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { ++ /* Remove any sta entry from WOFA forwarder. */ ++ fwder_flush(ifp->fwdh, (uintptr_t)sta); ++ } ++ ++ DHD_IF_STA_LIST_UNLOCK(ifp, flags); ++ } ++#endif /* BCM_GMAC3 */ ++} ++ ++/** Construct a pool of dhd_sta_t objects to be used by interfaces. */ ++static int ++dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) ++{ ++ int idx, prio, sta_pool_memsz; ++ dhd_sta_t * sta; ++ dhd_sta_pool_t * sta_pool; ++ void * staid_allocator; ++ ++ ASSERT(dhdp != (dhd_pub_t *)NULL); ++ ASSERT((dhdp->staid_allocator == NULL) && (dhdp->sta_pool == NULL)); ++ ++ /* dhd_sta objects per radio are managed in a table. id#0 reserved. */ ++ staid_allocator = id16_map_init(dhdp->osh, max_sta, 1); ++ if (staid_allocator == NULL) { ++ DHD_ERROR(("%s: sta id allocator init failure\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ /* Pre allocate a pool of dhd_sta objects (one extra). */ ++ sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); /* skip idx 0 */ ++ sta_pool = (dhd_sta_pool_t *)MALLOC(dhdp->osh, sta_pool_memsz); ++ if (sta_pool == NULL) { ++ DHD_ERROR(("%s: sta table alloc failure\n", __FUNCTION__)); ++ id16_map_fini(dhdp->osh, staid_allocator); ++ return BCME_ERROR; ++ } ++ ++ dhdp->sta_pool = sta_pool; ++ dhdp->staid_allocator = staid_allocator; ++ ++ /* Initialize all sta(s) for the pre-allocated free pool. */ ++ bzero((uchar *)sta_pool, sta_pool_memsz); ++ for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */ ++ sta = &sta_pool[idx]; ++ sta->idx = id16_map_alloc(staid_allocator); ++ ASSERT(sta->idx <= max_sta); ++ } ++ /* Now place them into the pre-allocated free pool. */ ++ for (idx = 1; idx <= max_sta; idx++) { ++ sta = &sta_pool[idx]; ++ for (prio = 0; prio < (int)NUMPRIO; prio++) { ++ sta->flowid[prio] = FLOWID_INVALID; /* Flow rings do not exist */ ++ } ++ dhd_sta_free(dhdp, sta); ++ } ++ ++ return BCME_OK; ++} ++ ++/** Destruct the pool of dhd_sta_t objects. ++ * Caller must ensure that no STA objects are currently associated with an if. ++ */ ++static void ++dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) ++{ ++ dhd_sta_pool_t * sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool; ++ ++ if (sta_pool) { ++ int idx; ++ int sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); ++ for (idx = 1; idx <= max_sta; idx++) { ++ ASSERT(sta_pool[idx].ifp == DHD_IF_NULL); ++ ASSERT(sta_pool[idx].idx == ID16_INVALID); ++ } ++ MFREE(dhdp->osh, dhdp->sta_pool, sta_pool_memsz); ++ dhdp->sta_pool = NULL; ++ } ++ ++ id16_map_fini(dhdp->osh, dhdp->staid_allocator); ++ dhdp->staid_allocator = NULL; ++} ++ ++/* Clear the pool of dhd_sta_t objects for built-in type driver */ ++static void ++dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) ++{ ++ int idx, prio, sta_pool_memsz; ++ dhd_sta_t * sta; ++ dhd_sta_pool_t * sta_pool; ++ void *staid_allocator; ++ ++ if (!dhdp) { ++ DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool; ++ staid_allocator = dhdp->staid_allocator; ++ ++ if (!sta_pool) { ++ DHD_ERROR(("%s: sta_pool is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!staid_allocator) { ++ DHD_ERROR(("%s: staid_allocator is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ /* clear free pool */ ++ sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); ++ bzero((uchar *)sta_pool, sta_pool_memsz); ++ ++ /* dhd_sta objects per radio are managed in a table. id#0 reserved. */ ++ id16_map_clear(staid_allocator, max_sta, 1); ++ ++ /* Initialize all sta(s) for the pre-allocated free pool. */ ++ for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */ ++ sta = &sta_pool[idx]; ++ sta->idx = id16_map_alloc(staid_allocator); ++ ASSERT(sta->idx <= max_sta); ++ } ++ /* Now place them into the pre-allocated free pool. */ ++ for (idx = 1; idx <= max_sta; idx++) { ++ sta = &sta_pool[idx]; ++ for (prio = 0; prio < (int)NUMPRIO; prio++) { ++ sta->flowid[prio] = FLOWID_INVALID; /* Flow rings do not exist */ ++ } ++ dhd_sta_free(dhdp, sta); ++ } ++} ++ ++/** Find STA with MAC address ea in an interface's STA list. */ ++dhd_sta_t * ++dhd_find_sta(void *pub, int ifidx, void *ea) ++{ ++ dhd_sta_t *sta; ++ dhd_if_t *ifp; ++ unsigned long flags; ++ ++ ASSERT(ea != NULL); ++ ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); ++ if (ifp == NULL) ++ return DHD_STA_NULL; ++ ++ DHD_IF_STA_LIST_LOCK(ifp, flags); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry(sta, &ifp->sta_list, list) { ++ if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) { ++ DHD_INFO(("%s: found STA " MACDBG "\n", ++ __FUNCTION__, MAC2STRDBG((char *)ea))); ++ DHD_IF_STA_LIST_UNLOCK(ifp, flags); ++ return sta; ++ } ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ DHD_IF_STA_LIST_UNLOCK(ifp, flags); ++ ++ return DHD_STA_NULL; ++} ++ ++/** Add STA into the interface's STA list. */ ++dhd_sta_t * ++dhd_add_sta(void *pub, int ifidx, void *ea) ++{ ++ dhd_sta_t *sta; ++ dhd_if_t *ifp; ++ unsigned long flags; ++ ++ ASSERT(ea != NULL); ++ ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); ++ if (ifp == NULL) ++ return DHD_STA_NULL; ++ ++ sta = dhd_sta_alloc((dhd_pub_t *)pub); ++ if (sta == DHD_STA_NULL) { ++ DHD_ERROR(("%s: Alloc failed\n", __FUNCTION__)); ++ return DHD_STA_NULL; ++ } ++ ++ memcpy(sta->ea.octet, ea, ETHER_ADDR_LEN); ++ ++ /* link the sta and the dhd interface */ ++ sta->ifp = ifp; ++ sta->ifidx = ifidx; ++#ifdef DHD_WMF ++ sta->psta_prim = NULL; ++#endif ++ INIT_LIST_HEAD(&sta->list); ++ ++ DHD_IF_STA_LIST_LOCK(ifp, flags); ++ ++ list_add_tail(&sta->list, &ifp->sta_list); ++ ++#if defined(BCM_GMAC3) ++ if (ifp->fwdh) { ++ ASSERT(ISALIGNED(ea, 2)); ++ /* Add sta to WOFA forwarder. */ ++ fwder_reassoc(ifp->fwdh, (uint16 *)ea, (uintptr_t)sta); ++ } ++#endif /* BCM_GMAC3 */ ++ ++ DHD_IF_STA_LIST_UNLOCK(ifp, flags); ++ ++ return sta; ++} ++ ++/** Delete all STAs from the interface's STA list. */ ++void ++dhd_del_all_sta(void *pub, int ifidx) ++{ ++ dhd_sta_t *sta, *next; ++ dhd_if_t *ifp; ++ unsigned long flags; ++ ++ ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); ++ if (ifp == NULL) ++ return; ++ ++ DHD_IF_STA_LIST_LOCK(ifp, flags); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { ++#if defined(BCM_GMAC3) ++ if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */ ++ ASSERT(ISALIGNED(sta->ea.octet, 2)); ++ fwder_deassoc(ifp->fwdh, (uint16 *)sta->ea.octet, (uintptr_t)sta); ++ } ++#endif /* BCM_GMAC3 */ ++ ++ list_del(&sta->list); ++ dhd_sta_free(&ifp->info->pub, sta); ++#ifdef DHD_L2_FILTER ++ if (ifp->parp_enable) { ++ /* clear Proxy ARP cache of specific Ethernet Address */ ++ bcm_l2_filter_arp_table_update(((dhd_pub_t*)pub)->osh, ++ ifp->phnd_arp_table, FALSE, ++ sta->ea.octet, FALSE, ((dhd_pub_t*)pub)->tickcnt); ++ } ++#endif /* DHD_L2_FILTER */ ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ DHD_IF_STA_LIST_UNLOCK(ifp, flags); ++ ++ return; ++} ++ ++/** Delete STA from the interface's STA list. */ ++void ++dhd_del_sta(void *pub, int ifidx, void *ea) ++{ ++ dhd_sta_t *sta, *next; ++ dhd_if_t *ifp; ++ unsigned long flags; ++ char macstr[ETHER_ADDR_STR_LEN]; ++ ++ ASSERT(ea != NULL); ++ ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); ++ if (ifp == NULL) ++ return; ++ ++ DHD_IF_STA_LIST_LOCK(ifp, flags); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { ++ if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) { ++#if defined(BCM_GMAC3) ++ if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */ ++ ASSERT(ISALIGNED(ea, 2)); ++ fwder_deassoc(ifp->fwdh, (uint16 *)ea, (uintptr_t)sta); ++ } ++#endif /* BCM_GMAC3 */ ++ DHD_MAC_TO_STR(((char *)ea), macstr); ++ DHD_ERROR(("%s: Deleting STA %s\n", __FUNCTION__, macstr)); ++ list_del(&sta->list); ++ dhd_sta_free(&ifp->info->pub, sta); ++ } ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ DHD_IF_STA_LIST_UNLOCK(ifp, flags); ++#ifdef DHD_L2_FILTER ++ if (ifp->parp_enable) { ++ /* clear Proxy ARP cache of specific Ethernet Address */ ++ bcm_l2_filter_arp_table_update(((dhd_pub_t*)pub)->osh, ifp->phnd_arp_table, FALSE, ++ ea, FALSE, ((dhd_pub_t*)pub)->tickcnt); ++ } ++#endif /* DHD_L2_FILTER */ ++ return; ++} ++ ++/** Add STA if it doesn't exist. Not reentrant. */ ++dhd_sta_t* ++dhd_findadd_sta(void *pub, int ifidx, void *ea) ++{ ++ dhd_sta_t *sta; ++ ++ sta = dhd_find_sta(pub, ifidx, ea); ++ ++ if (!sta) { ++ /* Add entry */ ++ sta = dhd_add_sta(pub, ifidx, ea); ++ } ++ ++ return sta; ++} ++ ++#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) ++#if !defined(BCM_GMAC3) ++static struct list_head * ++dhd_sta_list_snapshot(dhd_info_t *dhd, dhd_if_t *ifp, struct list_head *snapshot_list) ++{ ++ unsigned long flags; ++ dhd_sta_t *sta, *snapshot; ++ ++ INIT_LIST_HEAD(snapshot_list); ++ ++ DHD_IF_STA_LIST_LOCK(ifp, flags); ++ ++ list_for_each_entry(sta, &ifp->sta_list, list) { ++ /* allocate one and add to snapshot */ ++ snapshot = (dhd_sta_t *)MALLOC(dhd->pub.osh, sizeof(dhd_sta_t)); ++ if (snapshot == NULL) { ++ DHD_ERROR(("%s: Cannot allocate memory\n", __FUNCTION__)); ++ continue; ++ } ++ ++ memcpy(snapshot->ea.octet, sta->ea.octet, ETHER_ADDR_LEN); ++ ++ INIT_LIST_HEAD(&snapshot->list); ++ list_add_tail(&snapshot->list, snapshot_list); ++ } ++ ++ DHD_IF_STA_LIST_UNLOCK(ifp, flags); ++ ++ return snapshot_list; ++} ++ ++static void ++dhd_sta_list_snapshot_free(dhd_info_t *dhd, struct list_head *snapshot_list) ++{ ++ dhd_sta_t *sta, *next; ++ ++ list_for_each_entry_safe(sta, next, snapshot_list, list) { ++ list_del(&sta->list); ++ MFREE(dhd->pub.osh, sta, sizeof(dhd_sta_t)); ++ } ++} ++#endif /* !BCM_GMAC3 */ ++#endif /* DHD_IGMP_UCQUERY || DHD_UCAST_UPNP */ ++ ++#else ++static inline void dhd_if_flush_sta(dhd_if_t * ifp) { } ++static inline void dhd_if_del_sta_list(dhd_if_t *ifp) {} ++static inline int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) { return BCME_OK; } ++static inline void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) {} ++static inline void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) {} ++dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; } ++dhd_sta_t *dhd_find_sta(void *pub, int ifidx, void *ea) { return NULL; } ++void dhd_del_sta(void *pub, int ifidx, void *ea) {} ++#endif /* PCIE_FULL_DONGLE */ ++ ++ ++ ++#if defined(DHD_LB) ++ ++#if defined(DHD_LB_TXC) || defined(DHD_LB_RXC) || defined(DHD_LB_TXP) ++/** ++ * dhd_tasklet_schedule - Function that runs in IPI context of the destination ++ * CPU and schedules a tasklet. ++ * @tasklet: opaque pointer to the tasklet ++ */ ++INLINE void ++dhd_tasklet_schedule(void *tasklet) ++{ ++ tasklet_schedule((struct tasklet_struct *)tasklet); ++} ++/** ++ * dhd_tasklet_schedule_on - Executes the passed takslet in a given CPU ++ * @tasklet: tasklet to be scheduled ++ * @on_cpu: cpu core id ++ * ++ * If the requested cpu is online, then an IPI is sent to this cpu via the ++ * smp_call_function_single with no wait and the tasklet_schedule function ++ * will be invoked to schedule the specified tasklet on the requested CPU. ++ */ ++INLINE void ++dhd_tasklet_schedule_on(struct tasklet_struct *tasklet, int on_cpu) ++{ ++ const int wait = 0; ++ smp_call_function_single(on_cpu, ++ dhd_tasklet_schedule, (void *)tasklet, wait); ++} ++ ++/** ++ * dhd_work_schedule_on - Executes the passed work in a given CPU ++ * @work: work to be scheduled ++ * @on_cpu: cpu core id ++ * ++ * If the requested cpu is online, then an IPI is sent to this cpu via the ++ * schedule_work_on and the work function ++ * will be invoked to schedule the specified work on the requested CPU. ++ */ ++ ++INLINE void ++dhd_work_schedule_on(struct work_struct *work, int on_cpu) ++{ ++ schedule_work_on(on_cpu, work); ++} ++#endif /* DHD_LB_TXC || DHD_LB_RXC || DHD_LB_TXP */ ++ ++#if defined(DHD_LB_TXC) ++/** ++ * dhd_lb_tx_compl_dispatch - load balance by dispatching the tx_compl_tasklet ++ * on another cpu. The tx_compl_tasklet will take care of DMA unmapping and ++ * freeing the packets placed in the tx_compl workq ++ */ ++void ++dhd_lb_tx_compl_dispatch(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ int curr_cpu, on_cpu; ++ ++ if (dhd->rx_napi_netdev == NULL) { ++ DHD_ERROR(("%s: dhd->rx_napi_netdev is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ DHD_LB_STATS_INCR(dhd->txc_sched_cnt); ++ /* ++ * If the destination CPU is NOT online or is same as current CPU ++ * no need to schedule the work ++ */ ++ curr_cpu = get_cpu(); ++ put_cpu(); ++ ++ on_cpu = atomic_read(&dhd->tx_compl_cpu); ++ ++ if ((on_cpu == curr_cpu) || (!cpu_online(on_cpu))) { ++ dhd_tasklet_schedule(&dhd->tx_compl_tasklet); ++ } else { ++ schedule_work(&dhd->tx_compl_dispatcher_work); ++ } ++} ++ ++static void dhd_tx_compl_dispatcher_fn(struct work_struct * work) ++{ ++ struct dhd_info *dhd = ++ container_of(work, struct dhd_info, tx_compl_dispatcher_work); ++ int cpu; ++ ++ get_online_cpus(); ++ cpu = atomic_read(&dhd->tx_compl_cpu); ++ if (!cpu_online(cpu)) ++ dhd_tasklet_schedule(&dhd->tx_compl_tasklet); ++ else ++ dhd_tasklet_schedule_on(&dhd->tx_compl_tasklet, cpu); ++ put_online_cpus(); ++} ++#endif /* DHD_LB_TXC */ ++ ++#if defined(DHD_LB_RXC) ++/** ++ * dhd_lb_rx_compl_dispatch - load balance by dispatching the rx_compl_tasklet ++ * on another cpu. The rx_compl_tasklet will take care of reposting rx buffers ++ * in the H2D RxBuffer Post common ring, by using the recycled pktids that were ++ * placed in the rx_compl workq. ++ * ++ * @dhdp: pointer to dhd_pub object ++ */ ++void ++dhd_lb_rx_compl_dispatch(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ int curr_cpu, on_cpu; ++ ++ if (dhd->rx_napi_netdev == NULL) { ++ DHD_ERROR(("%s: dhd->rx_napi_netdev is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ DHD_LB_STATS_INCR(dhd->rxc_sched_cnt); ++ /* ++ * If the destination CPU is NOT online or is same as current CPU ++ * no need to schedule the work ++ */ ++ curr_cpu = get_cpu(); ++ put_cpu(); ++ on_cpu = atomic_read(&dhd->rx_compl_cpu); ++ ++ if ((on_cpu == curr_cpu) || (!cpu_online(on_cpu))) { ++ dhd_tasklet_schedule(&dhd->rx_compl_tasklet); ++ } else { ++ dhd_rx_compl_dispatcher_fn(dhdp); ++ } ++} ++ ++static void dhd_rx_compl_dispatcher_fn(dhd_pub_t *dhdp) ++{ ++ struct dhd_info *dhd = dhdp->info; ++ int cpu; ++ ++ preempt_disable(); ++ cpu = atomic_read(&dhd->rx_compl_cpu); ++ if (!cpu_online(cpu)) ++ dhd_tasklet_schedule(&dhd->rx_compl_tasklet); ++ else { ++ dhd_tasklet_schedule_on(&dhd->rx_compl_tasklet, cpu); ++ } ++ preempt_enable(); ++} ++#endif /* DHD_LB_RXC */ ++ ++#if defined(DHD_LB_TXP) ++static void dhd_tx_dispatcher_work(struct work_struct * work) ++{ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ struct dhd_info *dhd = ++ container_of(work, struct dhd_info, tx_dispatcher_work); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ dhd_tasklet_schedule(&dhd->tx_tasklet); ++} ++ ++static void dhd_tx_dispatcher_fn(dhd_pub_t *dhdp) ++{ ++ int cpu; ++ int net_tx_cpu; ++ dhd_info_t *dhd = dhdp->info; ++ ++ preempt_disable(); ++ cpu = atomic_read(&dhd->tx_cpu); ++ net_tx_cpu = atomic_read(&dhd->net_tx_cpu); ++ ++ /* ++ * Now if the NET_TX has pushed the packet in the same ++ * CPU that is chosen for Tx processing, seperate it out ++ * i.e run the TX processing tasklet in compl_cpu ++ */ ++ if (net_tx_cpu == cpu) ++ cpu = atomic_read(&dhd->tx_compl_cpu); ++ ++ if (!cpu_online(cpu)) { ++ /* ++ * Ooohh... but the Chosen CPU is not online, ++ * Do the job in the current CPU itself. ++ */ ++ dhd_tasklet_schedule(&dhd->tx_tasklet); ++ } else { ++ /* ++ * Schedule tx_dispatcher_work to on the cpu which ++ * in turn will schedule tx_tasklet. ++ */ ++ dhd_work_schedule_on(&dhd->tx_dispatcher_work, cpu); ++ } ++ preempt_enable(); ++} ++ ++/** ++ * dhd_lb_tx_dispatch - load balance by dispatching the tx_tasklet ++ * on another cpu. The tx_tasklet will take care of actually putting ++ * the skbs into appropriate flow ring and ringing H2D interrupt ++ * ++ * @dhdp: pointer to dhd_pub object ++ */ ++static void ++dhd_lb_tx_dispatch(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ int curr_cpu; ++ ++ curr_cpu = get_cpu(); ++ put_cpu(); ++ ++ /* Record the CPU in which the TX request from Network stack came */ ++ atomic_set(&dhd->net_tx_cpu, curr_cpu); ++ ++ /* Schedule the work to dispatch ... */ ++ dhd_tx_dispatcher_fn(dhdp); ++ ++} ++#endif /* DHD_LB_TXP */ ++ ++#if defined(DHD_LB_RXP) ++/** ++ * dhd_napi_poll - Load balance napi poll function to process received ++ * packets and send up the network stack using netif_receive_skb() ++ * ++ * @napi: napi object in which context this poll function is invoked ++ * @budget: number of packets to be processed. ++ * ++ * Fetch the dhd_info given the rx_napi_struct. Move all packets from the ++ * rx_napi_queue into a local rx_process_queue (lock and queue move and unlock). ++ * Dequeue each packet from head of rx_process_queue, fetch the ifid from the ++ * packet tag and sendup. ++ */ ++static int ++dhd_napi_poll(struct napi_struct *napi, int budget) ++{ ++ int ifid; ++ const int pkt_count = 1; ++ const int chan = 0; ++ struct sk_buff * skb; ++ unsigned long flags; ++ struct dhd_info *dhd; ++ int processed = 0; ++ struct sk_buff_head rx_process_queue; ++ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ dhd = container_of(napi, struct dhd_info, rx_napi_struct); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ ++ DHD_INFO(("%s napi_queue<%d> budget<%d>\n", ++ __FUNCTION__, skb_queue_len(&dhd->rx_napi_queue), budget)); ++ __skb_queue_head_init(&rx_process_queue); ++ ++ /* extract the entire rx_napi_queue into local rx_process_queue */ ++ spin_lock_irqsave(&dhd->rx_napi_queue.lock, flags); ++ skb_queue_splice_tail_init(&dhd->rx_napi_queue, &rx_process_queue); ++ spin_unlock_irqrestore(&dhd->rx_napi_queue.lock, flags); ++ ++ while ((skb = __skb_dequeue(&rx_process_queue)) != NULL) { ++ OSL_PREFETCH(skb->data); ++ ++ ifid = DHD_PKTTAG_IFID((dhd_pkttag_fr_t *)PKTTAG(skb)); ++ ++ DHD_INFO(("%s dhd_rx_frame pkt<%p> ifid<%d>\n", ++ __FUNCTION__, skb, ifid)); ++ ++ dhd_rx_frame(&dhd->pub, ifid, skb, pkt_count, chan); ++ processed++; ++ } ++ ++ DHD_LB_STATS_UPDATE_NAPI_HISTO(&dhd->pub, processed); ++ ++ DHD_INFO(("%s processed %d\n", __FUNCTION__, processed)); ++ napi_complete(napi); ++ ++ return budget - 1; ++} ++ ++/** ++ * dhd_napi_schedule - Place the napi struct into the current cpus softnet napi ++ * poll list. This function may be invoked via the smp_call_function_single ++ * from a remote CPU. ++ * ++ * This function will essentially invoke __raise_softirq_irqoff(NET_RX_SOFTIRQ) ++ * after the napi_struct is added to the softnet data's poll_list ++ * ++ * @info: pointer to a dhd_info struct ++ */ ++static void ++dhd_napi_schedule(void *info) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)info; ++ ++ DHD_INFO(("%s rx_napi_struct<%p> on cpu<%d>\n", ++ __FUNCTION__, &dhd->rx_napi_struct, atomic_read(&dhd->rx_napi_cpu))); ++ ++ /* add napi_struct to softnet data poll list and raise NET_RX_SOFTIRQ */ ++ if (napi_schedule_prep(&dhd->rx_napi_struct)) { ++ __napi_schedule(&dhd->rx_napi_struct); ++ DHD_LB_STATS_PERCPU_ARR_INCR(dhd->napi_percpu_run_cnt); ++ } ++ ++ /* ++ * If the rx_napi_struct was already running, then we let it complete ++ * processing all its packets. The rx_napi_struct may only run on one ++ * core at a time, to avoid out-of-order handling. ++ */ ++} ++ ++/** ++ * dhd_napi_schedule_on - API to schedule on a desired CPU core a NET_RX_SOFTIRQ ++ * action after placing the dhd's rx_process napi object in the the remote CPU's ++ * softnet data's poll_list. ++ * ++ * @dhd: dhd_info which has the rx_process napi object ++ * @on_cpu: desired remote CPU id ++ */ ++static INLINE int ++dhd_napi_schedule_on(dhd_info_t *dhd, int on_cpu) ++{ ++ int wait = 0; /* asynchronous IPI */ ++ DHD_INFO(("%s dhd<%p> napi<%p> on_cpu<%d>\n", ++ __FUNCTION__, dhd, &dhd->rx_napi_struct, on_cpu)); ++ ++ if (smp_call_function_single(on_cpu, dhd_napi_schedule, dhd, wait)) { ++ DHD_ERROR(("%s smp_call_function_single on_cpu<%d> failed\n", ++ __FUNCTION__, on_cpu)); ++ } ++ ++ DHD_LB_STATS_INCR(dhd->napi_sched_cnt); ++ ++ return 0; ++} ++ ++/* ++ * Call get_online_cpus/put_online_cpus around dhd_napi_schedule_on ++ * Why should we do this? ++ * The candidacy algorithm is run from the call back function ++ * registered to CPU hotplug notifier. This call back happens from Worker ++ * context. The dhd_napi_schedule_on is also from worker context. ++ * Note that both of this can run on two different CPUs at the same time. ++ * So we can possibly have a window where a given CPUn is being brought ++ * down from CPUm while we try to run a function on CPUn. ++ * To prevent this its better have the whole code to execute an SMP ++ * function under get_online_cpus. ++ * This function call ensures that hotplug mechanism does not kick-in ++ * until we are done dealing with online CPUs ++ * If the hotplug worker is already running, no worries because the ++ * candidacy algo would then reflect the same in dhd->rx_napi_cpu. ++ * ++ * The below mentioned code structure is proposed in ++ * https://www.kernel.org/doc/Documentation/cpu-hotplug.txt ++ * for the question ++ * Q: I need to ensure that a particular cpu is not removed when there is some ++ * work specific to this cpu is in progress ++ * ++ * According to the documentation calling get_online_cpus is NOT required, if ++ * we are running from tasklet context. Since dhd_rx_napi_dispatcher_fn can ++ * run from Work Queue context we have to call these functions ++ */ ++static void dhd_rx_napi_dispatcher_fn(struct work_struct * work) ++{ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ struct dhd_info *dhd = ++ container_of(work, struct dhd_info, rx_napi_dispatcher_work); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ int cpu; ++ ++ get_online_cpus(); ++ cpu = atomic_read(&dhd->rx_napi_cpu); ++ ++ if (!cpu_online(cpu)) ++ dhd_napi_schedule(dhd); ++ else ++ dhd_napi_schedule_on(dhd, cpu); ++ ++ put_online_cpus(); ++} ++ ++/** ++ * dhd_lb_rx_napi_dispatch - load balance by dispatching the rx_napi_struct ++ * to run on another CPU. The rx_napi_struct's poll function will retrieve all ++ * the packets enqueued into the rx_napi_queue and sendup. ++ * The producer's rx packet queue is appended to the rx_napi_queue before ++ * dispatching the rx_napi_struct. ++ */ ++void ++dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp) ++{ ++ unsigned long flags; ++ dhd_info_t *dhd = dhdp->info; ++ int curr_cpu; ++ int on_cpu; ++ ++ if (dhd->rx_napi_netdev == NULL) { ++ DHD_ERROR(("%s: dhd->rx_napi_netdev is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ DHD_INFO(("%s append napi_queue<%d> pend_queue<%d>\n", __FUNCTION__, ++ skb_queue_len(&dhd->rx_napi_queue), skb_queue_len(&dhd->rx_pend_queue))); ++ ++ /* append the producer's queue of packets to the napi's rx process queue */ ++ spin_lock_irqsave(&dhd->rx_napi_queue.lock, flags); ++ skb_queue_splice_tail_init(&dhd->rx_pend_queue, &dhd->rx_napi_queue); ++ spin_unlock_irqrestore(&dhd->rx_napi_queue.lock, flags); ++ ++ /* ++ * If the destination CPU is NOT online or is same as current CPU ++ * no need to schedule the work ++ */ ++ curr_cpu = get_cpu(); ++ put_cpu(); ++ ++ on_cpu = atomic_read(&dhd->rx_napi_cpu); ++ if ((on_cpu == curr_cpu) || (!cpu_online(on_cpu))) { ++ dhd_napi_schedule(dhd); ++ } else { ++ schedule_work(&dhd->rx_napi_dispatcher_work); ++ } ++} ++ ++/** ++ * dhd_lb_rx_pkt_enqueue - Enqueue the packet into the producer's queue ++ */ ++void ++dhd_lb_rx_pkt_enqueue(dhd_pub_t *dhdp, void *pkt, int ifidx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ ++ DHD_INFO(("%s enqueue pkt<%p> ifidx<%d> pend_queue<%d>\n", __FUNCTION__, ++ pkt, ifidx, skb_queue_len(&dhd->rx_pend_queue))); ++ DHD_PKTTAG_SET_IFID((dhd_pkttag_fr_t *)PKTTAG(pkt), ifidx); ++ __skb_queue_tail(&dhd->rx_pend_queue, pkt); ++} ++#endif /* DHD_LB_RXP */ ++ ++#endif /* DHD_LB */ ++ ++ ++/** Returns dhd iflist index corresponding the the bssidx provided by apps */ ++int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx) ++{ ++ dhd_if_t *ifp; ++ dhd_info_t *dhd = dhdp->info; ++ int i; ++ ++ ASSERT(bssidx < DHD_MAX_IFS); ++ ASSERT(dhdp); ++ ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ ifp = dhd->iflist[i]; ++ if (ifp && (ifp->bssidx == bssidx)) { ++ DHD_TRACE(("Index manipulated for %s from %d to %d\n", ++ ifp->name, bssidx, i)); ++ break; ++ } ++ } ++ return i; ++} ++ ++static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb) ++{ ++ uint32 store_idx; ++ uint32 sent_idx; ++ ++ if (!skb) { ++ DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n")); ++ return BCME_ERROR; ++ } ++ ++ dhd_os_rxflock(dhdp); ++ store_idx = dhdp->store_idx; ++ sent_idx = dhdp->sent_idx; ++ if (dhdp->skbbuf[store_idx] != NULL) { ++ /* Make sure the previous packets are processed */ ++ dhd_os_rxfunlock(dhdp); ++#ifdef RXF_DEQUEUE_ON_BUSY ++ DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", ++ skb, store_idx, sent_idx)); ++ return BCME_BUSY; ++#else /* RXF_DEQUEUE_ON_BUSY */ ++ DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", ++ skb, store_idx, sent_idx)); ++ /* removed msleep here, should use wait_event_timeout if we ++ * want to give rx frame thread a chance to run ++ */ ++#if defined(WAIT_DEQUEUE) ++ OSL_SLEEP(1); ++#endif ++ return BCME_ERROR; ++#endif /* RXF_DEQUEUE_ON_BUSY */ ++ } ++ DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n", ++ skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1))); ++ dhdp->skbbuf[store_idx] = skb; ++ dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1); ++ dhd_os_rxfunlock(dhdp); ++ ++ return BCME_OK; ++} ++ ++static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp) ++{ ++ uint32 store_idx; ++ uint32 sent_idx; ++ void *skb; ++ ++ dhd_os_rxflock(dhdp); ++ ++ store_idx = dhdp->store_idx; ++ sent_idx = dhdp->sent_idx; ++ skb = dhdp->skbbuf[sent_idx]; ++ ++ if (skb == NULL) { ++ dhd_os_rxfunlock(dhdp); ++ DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n", ++ store_idx, sent_idx)); ++ return NULL; ++ } ++ ++ dhdp->skbbuf[sent_idx] = NULL; ++ dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1); ++ ++ DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n", ++ skb, sent_idx)); ++ ++ dhd_os_rxfunlock(dhdp); ++ ++ return skb; ++} ++ ++int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) ++{ ++ if (prepost) { /* pre process */ ++ dhd_read_cis(dhdp); ++ dhd_check_module_cid(dhdp); ++ dhd_check_module_mac(dhdp); ++ dhd_set_macaddr_from_file(dhdp); ++ } else { /* post process */ ++ dhd_write_macaddr(&dhdp->mac); ++ dhd_clear_cis(dhdp); ++ } ++ ++ return 0; ++} ++ ++// terence 20160615: fix building error if ARP_OFFLOAD_SUPPORT removed ++#if defined(PKT_FILTER_SUPPORT) ++#if defined(ARP_OFFLOAD_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER) ++static bool ++_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode_param) ++{ ++ bool _apply = FALSE; ++ /* In case of IBSS mode, apply arp pkt filter */ ++ if (op_mode_param & DHD_FLAG_IBSS_MODE) { ++ _apply = TRUE; ++ goto exit; ++ } ++ /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */ ++ if (op_mode_param & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE)) { ++ _apply = TRUE; ++ goto exit; ++ } ++ ++exit: ++ return _apply; ++} ++#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ ++ ++void ++dhd_set_packet_filter(dhd_pub_t *dhd) ++{ ++ int i; ++ ++ DHD_TRACE(("%s: enter\n", __FUNCTION__)); ++ if (dhd_pkt_filter_enable) { ++ for (i = 0; i < dhd->pktfilter_count; i++) { ++ dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); ++ } ++ } ++} ++ ++void ++dhd_enable_packet_filter(int value, dhd_pub_t *dhd) ++{ ++ int i; ++ ++ DHD_ERROR(("%s: enter, value = %d\n", __FUNCTION__, value)); ++ if ((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) && value && ++ !dhd_conf_get_insuspend(dhd, AP_FILTER_IN_SUSPEND)) { ++ DHD_ERROR(("%s: DHD_FLAG_HOSTAP_MODE\n", __FUNCTION__)); ++ return; ++ } ++ /* 1 - Enable packet filter, only allow unicast packet to send up */ ++ /* 0 - Disable packet filter */ ++ if (dhd_pkt_filter_enable && (!value || ++ (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress) || ++ dhd_conf_get_insuspend(dhd, AP_FILTER_IN_SUSPEND))) ++ { ++ for (i = 0; i < dhd->pktfilter_count; i++) { ++// terence 20160615: fix building error if ARP_OFFLOAD_SUPPORT removed ++#if defined(ARP_OFFLOAD_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER) ++ if (value && (i == DHD_ARP_FILTER_NUM) && ++ !_turn_on_arp_filter(dhd, dhd->op_mode)) { ++ DHD_TRACE(("Do not turn on ARP white list pkt filter:" ++ "val %d, cnt %d, op_mode 0x%x\n", ++ value, i, dhd->op_mode)); ++ continue; ++ } ++#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ ++ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], ++ value, dhd_master_mode); ++ } ++ } ++} ++ ++int ++dhd_packet_filter_add_remove(dhd_pub_t *dhdp, int add_remove, int num) ++{ ++ char *filterp = NULL; ++ int filter_id = 0; ++ ++ switch (num) { ++ case DHD_BROADCAST_FILTER_NUM: ++ filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; ++ filter_id = 101; ++ break; ++ case DHD_MULTICAST4_FILTER_NUM: ++ filter_id = 102; ++ if (FW_SUPPORTED((dhdp), pf6)) { ++ if (dhdp->pktfilter[num] != NULL) { ++ dhd_pktfilter_offload_delete(dhdp, filter_id); ++ dhdp->pktfilter[num] = NULL; ++ } ++ if (!add_remove) { ++ filterp = DISCARD_IPV4_MCAST; ++ add_remove = 1; ++ break; ++ } ++ } ++ filterp = "102 0 0 0 0xFFFFFF 0x01005E"; ++ break; ++ case DHD_MULTICAST6_FILTER_NUM: ++ filter_id = 103; ++ if (FW_SUPPORTED((dhdp), pf6)) { ++ if (dhdp->pktfilter[num] != NULL) { ++ dhd_pktfilter_offload_delete(dhdp, filter_id); ++ dhdp->pktfilter[num] = NULL; ++ } ++ if (!add_remove) { ++ filterp = DISCARD_IPV6_MCAST; ++ add_remove = 1; ++ break; ++ } ++ } ++ filterp = "103 0 0 0 0xFFFF 0x3333"; ++ break; ++ case DHD_MDNS_FILTER_NUM: ++ filterp = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; ++ filter_id = 104; ++ break; ++ case DHD_ARP_FILTER_NUM: ++ filterp = "105 0 0 12 0xFFFF 0x0806"; ++ filter_id = 105; ++ break; ++ case DHD_BROADCAST_ARP_FILTER_NUM: ++ filterp = "106 0 0 0 0xFFFFFFFFFFFF0000000000000806" ++ " 0xFFFFFFFFFFFF0000000000000806"; ++ filter_id = 106; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* Add filter */ ++ if (add_remove) { ++ dhdp->pktfilter[num] = filterp; ++ dhd_pktfilter_offload_set(dhdp, dhdp->pktfilter[num]); ++ } else { /* Delete filter */ ++ if (dhdp->pktfilter[num]) { ++ dhd_pktfilter_offload_delete(dhdp, filter_id); ++ dhdp->pktfilter[num] = NULL; ++ } ++ } ++ ++ return 0; ++} ++#endif /* PKT_FILTER_SUPPORT */ ++ ++static int dhd_set_suspend(int value, dhd_pub_t *dhd) ++{ ++#ifndef SUPPORT_PM2_ONLY ++ int power_mode = PM_MAX; ++#endif /* SUPPORT_PM2_ONLY */ ++#ifdef SUPPORT_SENSORHUB ++ shub_control_t shub_ctl; ++#endif /* SUPPORT_SENSORHUB */ ++ /* wl_pkt_filter_enable_t enable_parm; */ ++ int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ ++ int ret = 0; ++#ifdef DHD_USE_EARLYSUSPEND ++#ifdef CUSTOM_BCN_TIMEOUT_IN_SUSPEND ++ int bcn_timeout = 0; ++#endif /* CUSTOM_BCN_TIMEOUT_IN_SUSPEND */ ++#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND ++ int roam_time_thresh = 0; /* (ms) */ ++#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ ++#ifndef ENABLE_FW_ROAM_SUSPEND ++ uint roamvar = 1; ++#endif /* ENABLE_FW_ROAM_SUSPEND */ ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ int bcn_li_bcn; ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ uint nd_ra_filter = 0; ++#endif /* DHD_USE_EARLYSUSPEND */ ++#ifdef PASS_ALL_MCAST_PKTS ++ struct dhd_info *dhdinfo; ++ uint32 allmulti; ++ uint i; ++#endif /* PASS_ALL_MCAST_PKTS */ ++#ifdef ENABLE_IPMCAST_FILTER ++ int ipmcast_l2filter; ++#endif /* ENABLE_IPMCAST_FILTER */ ++#ifdef DYNAMIC_SWOOB_DURATION ++#ifndef CUSTOM_INTR_WIDTH ++#define CUSTOM_INTR_WIDTH 100 ++ int intr_width = 0; ++#endif /* CUSTOM_INTR_WIDTH */ ++#endif /* DYNAMIC_SWOOB_DURATION */ ++ ++#if defined(BCMPCIE) ++ int lpas = 0; ++ int dtim_period = 0; ++ int bcn_interval = 0; ++ int bcn_to_dly = 0; ++#ifndef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND ++ int bcn_timeout = CUSTOM_BCN_TIMEOUT_SETTING; ++#else ++ bcn_timeout = CUSTOM_BCN_TIMEOUT_SETTING; ++#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ ++#endif /* OEM_ANDROID && BCMPCIE */ ++ ++ if (!dhd) ++ return -ENODEV; ++ ++#ifdef PASS_ALL_MCAST_PKTS ++ dhdinfo = dhd->info; ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", ++ __FUNCTION__, value, dhd->in_suspend)); ++ ++ dhd_suspend_lock(dhd); ++ ++#ifdef CUSTOM_SET_CPUCORE ++ DHD_TRACE(("%s set cpucore(suspend%d)\n", __FUNCTION__, value)); ++ /* set specific cpucore */ ++ dhd_set_cpucore(dhd, TRUE); ++#endif /* CUSTOM_SET_CPUCORE */ ++ if (dhd->up) { ++ if (value && dhd->in_suspend) { ++#ifdef PKT_FILTER_SUPPORT ++ dhd->early_suspended = 1; ++#endif ++ /* Kernel suspended */ ++ DHD_ERROR(("%s: force extra suspend setting\n", __FUNCTION__)); ++ ++#ifndef SUPPORT_PM2_ONLY ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, ++ sizeof(power_mode), TRUE, 0); ++#endif /* SUPPORT_PM2_ONLY */ ++ ++#ifdef PKT_FILTER_SUPPORT ++ /* Enable packet filter, ++ * only allow unicast packet to send up ++ */ ++ dhd_enable_packet_filter(1, dhd); ++#ifdef APF ++ dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd)); ++#endif /* APF */ ++#endif /* PKT_FILTER_SUPPORT */ ++ ++#ifdef SUPPORT_SENSORHUB ++ shub_ctl.enable = 1; ++ shub_ctl.cmd = 0x000; ++ shub_ctl.op_mode = 1; ++ shub_ctl.interval = 0; ++ if (dhd->info->shub_enable == 1) { ++ ret = dhd_iovar(dhd, 0, "shub_msreq", ++ (char *)&shub_ctl, sizeof(shub_ctl), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s SensorHub MS start: failed %d\n", ++ __FUNCTION__, ret)); ++ } ++ } ++#endif /* SUPPORT_SENSORHUB */ ++ ++ ++#ifdef PASS_ALL_MCAST_PKTS ++ allmulti = 0; ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) ++ dhd_iovar(dhd, i, "allmulti", (char *)&allmulti, ++ sizeof(allmulti), NULL, 0, TRUE); ++ ++ } ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ /* If DTIM skip is set up as default, force it to wake ++ * each third DTIM for better power savings. Note that ++ * one side effect is a chance to miss BC/MC packet. ++ */ ++#ifdef WLTDLS ++ /* Do not set bcn_li_ditm on WFD mode */ ++ if (dhd->tdls_mode) { ++ bcn_li_dtim = 0; ++ } else ++#endif /* WLTDLS */ ++#if defined(BCMPCIE) ++ bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd, &dtim_period, ++ &bcn_interval); ++ dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, ++ sizeof(bcn_li_dtim), NULL, 0, TRUE); ++ ++ if ((bcn_li_dtim * dtim_period * bcn_interval) >= ++ MIN_DTIM_FOR_ROAM_THRES_EXTEND) { ++ /* ++ * Increase max roaming threshold from 2 secs to 8 secs ++ * the real roam threshold is MIN(max_roam_threshold, ++ * bcn_timeout/2) ++ */ ++ lpas = 1; ++ dhd_iovar(dhd, 0, "lpas", (char *)&lpas, sizeof(lpas), NULL, ++ 0, TRUE); ++ ++ bcn_to_dly = 1; ++ /* ++ * if bcn_to_dly is 1, the real roam threshold is ++ * MIN(max_roam_threshold, bcn_timeout -1); ++ * notify link down event after roaming procedure complete ++ * if we hit bcn_timeout while we are in roaming progress. ++ */ ++ dhd_iovar(dhd, 0, "bcn_to_dly", (char *)&bcn_to_dly, ++ sizeof(bcn_to_dly), NULL, 0, TRUE); ++ /* Increase beacon timeout to 6 secs or use bigger one */ ++ bcn_timeout = max(bcn_timeout, BCN_TIMEOUT_IN_SUSPEND); ++ dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, ++ sizeof(bcn_timeout), NULL, 0, TRUE); ++ } ++#else ++ bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); ++ if (dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, ++ sizeof(bcn_li_dtim), NULL, 0, TRUE) < 0) ++ DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__)); ++#endif /* OEM_ANDROID && BCMPCIE */ ++ ++#ifdef DHD_USE_EARLYSUSPEND ++#ifdef CUSTOM_BCN_TIMEOUT_IN_SUSPEND ++ bcn_timeout = CUSTOM_BCN_TIMEOUT_IN_SUSPEND; ++ dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, ++ sizeof(bcn_timeout), NULL, 0, TRUE); ++#endif /* CUSTOM_BCN_TIMEOUT_IN_SUSPEND */ ++#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND ++ roam_time_thresh = CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND; ++ dhd_iovar(dhd, 0, "roam_time_thresh", (char *)&roam_time_thresh, ++ sizeof(roam_time_thresh), NULL, 0, TRUE); ++#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ ++#ifndef ENABLE_FW_ROAM_SUSPEND ++ /* Disable firmware roaming during suspend */ ++ dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), ++ NULL, 0, TRUE); ++#endif /* ENABLE_FW_ROAM_SUSPEND */ ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ bcn_li_bcn = 0; ++ dhd_iovar(dhd, 0, "bcn_li_bcn", (char *)&bcn_li_bcn, ++ sizeof(bcn_li_bcn), NULL, 0, TRUE); ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++#ifdef NDO_CONFIG_SUPPORT ++ if (dhd->ndo_enable) { ++ if (!dhd->ndo_host_ip_overflow) { ++ /* enable ND offload on suspend */ ++ ret = dhd_ndo_enable(dhd, 1); ++ if (ret < 0) { ++ DHD_ERROR(("%s: failed to enable NDO\n", ++ __FUNCTION__)); ++ } ++ } else { ++ DHD_INFO(("%s: NDO disabled on suspend due to" ++ "HW capacity\n", __FUNCTION__)); ++ } ++ } ++#endif /* NDO_CONFIG_SUPPORT */ ++#ifndef APF ++ if (FW_SUPPORTED(dhd, ndoe)) ++#else ++ if (FW_SUPPORTED(dhd, ndoe) && !FW_SUPPORTED(dhd, apf)) ++#endif /* APF */ ++ { ++ /* enable IPv6 RA filter in firmware during suspend */ ++ nd_ra_filter = 1; ++ ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", ++ (char *)&nd_ra_filter, sizeof(nd_ra_filter), ++ NULL, 0, TRUE); ++ if (ret < 0) ++ DHD_ERROR(("failed to set nd_ra_filter (%d)\n", ++ ret)); ++ } ++ dhd_os_suppress_logging(dhd, TRUE); ++#ifdef ENABLE_IPMCAST_FILTER ++ ipmcast_l2filter = 1; ++ ret = dhd_iovar(dhd, 0, "ipmcast_l2filter", ++ (char *)&ipmcast_l2filter, sizeof(ipmcast_l2filter), ++ NULL, 0, TRUE); ++#endif /* ENABLE_IPMCAST_FILTER */ ++#ifdef DYNAMIC_SWOOB_DURATION ++ intr_width = CUSTOM_INTR_WIDTH; ++ ret = dhd_iovar(dhd, 0, "bus:intr_width", (char *)&intr_width, ++ sizeof(intr_width), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("failed to set intr_width (%d)\n", ret)); ++ } ++#endif /* DYNAMIC_SWOOB_DURATION */ ++#endif /* DHD_USE_EARLYSUSPEND */ ++ } else { ++#ifdef PKT_FILTER_SUPPORT ++ dhd->early_suspended = 0; ++#endif ++ /* Kernel resumed */ ++ DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__)); ++ ++#ifdef SUPPORT_SENSORHUB ++ shub_ctl.enable = 1; ++ shub_ctl.cmd = 0x000; ++ shub_ctl.op_mode = 0; ++ shub_ctl.interval = 0; ++ if (dhd->info->shub_enable == 1) { ++ ret = dhd_iovar(dhd, 0, "shub_msreq", ++ (char *)&shub_ctl, sizeof(shub_ctl), ++ NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s SensorHub MS stop: failed %d\n", ++ __FUNCTION__, ret)); ++ } ++ } ++#endif /* SUPPORT_SENSORHUB */ ++ ++#ifdef DYNAMIC_SWOOB_DURATION ++ intr_width = 0; ++ ret = dhd_iovar(dhd, 0, "bus:intr_width", (char *)&intr_width, ++ sizeof(intr_width), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("failed to set intr_width (%d)\n", ret)); ++ } ++#endif /* DYNAMIC_SWOOB_DURATION */ ++#ifndef SUPPORT_PM2_ONLY ++ power_mode = PM_FAST; ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, ++ sizeof(power_mode), TRUE, 0); ++#endif /* SUPPORT_PM2_ONLY */ ++#ifdef PKT_FILTER_SUPPORT ++ /* disable pkt filter */ ++ dhd_enable_packet_filter(0, dhd); ++#ifdef APF ++ dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd)); ++#endif /* APF */ ++#endif /* PKT_FILTER_SUPPORT */ ++#ifdef PASS_ALL_MCAST_PKTS ++ allmulti = 1; ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) ++ dhd_iovar(dhd, i, "allmulti", (char *)&allmulti, ++ sizeof(allmulti), NULL, 0, TRUE); ++ } ++#endif /* PASS_ALL_MCAST_PKTS */ ++#if defined(BCMPCIE) ++ /* restore pre-suspend setting */ ++ ret = dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, ++ sizeof(bcn_li_dtim), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s:bcn_li_ditm fail:%d\n", __FUNCTION__, ret)); ++ } ++ ++ dhd_iovar(dhd, 0, "lpas", (char *)&lpas, sizeof(lpas), NULL, 0, ++ TRUE); ++ ++ dhd_iovar(dhd, 0, "bcn_to_dly", (char *)&bcn_to_dly, ++ sizeof(bcn_to_dly), NULL, 0, TRUE); ++ ++ dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, ++ sizeof(bcn_timeout), NULL, 0, TRUE); ++#else ++ /* restore pre-suspend setting for dtim_skip */ ++ ret = dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, ++ sizeof(bcn_li_dtim), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s:bcn_li_ditm fail:%d\n", __FUNCTION__, ret)); ++ } ++#endif /* OEM_ANDROID && BCMPCIE */ ++#ifdef DHD_USE_EARLYSUSPEND ++#ifdef CUSTOM_BCN_TIMEOUT_IN_SUSPEND ++ bcn_timeout = CUSTOM_BCN_TIMEOUT; ++ dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, ++ sizeof(bcn_timeout), NULL, 0, TRUE); ++#endif /* CUSTOM_BCN_TIMEOUT_IN_SUSPEND */ ++#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND ++ roam_time_thresh = 2000; ++ dhd_iovar(dhd, 0, "roam_time_thresh", (char *)&roam_time_thresh, ++ sizeof(roam_time_thresh), NULL, 0, TRUE); ++ ++#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ ++#ifndef ENABLE_FW_ROAM_SUSPEND ++ roamvar = dhd_roam_disable; ++ dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), ++ NULL, 0, TRUE); ++#endif /* ENABLE_FW_ROAM_SUSPEND */ ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ bcn_li_bcn = 1; ++ dhd_iovar(dhd, 0, "bcn_li_bcn", (char *)&bcn_li_bcn, ++ sizeof(bcn_li_bcn), NULL, 0, TRUE); ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++#ifdef NDO_CONFIG_SUPPORT ++ if (dhd->ndo_enable) { ++ /* Disable ND offload on resume */ ++ ret = dhd_ndo_enable(dhd, 0); ++ if (ret < 0) { ++ DHD_ERROR(("%s: failed to disable NDO\n", ++ __FUNCTION__)); ++ } ++ } ++#endif /* NDO_CONFIG_SUPPORT */ ++#ifndef APF ++ if (FW_SUPPORTED(dhd, ndoe)) ++#else ++ if (FW_SUPPORTED(dhd, ndoe) && !FW_SUPPORTED(dhd, apf)) ++#endif /* APF */ ++ { ++ /* disable IPv6 RA filter in firmware during suspend */ ++ nd_ra_filter = 0; ++ ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", ++ (char *)&nd_ra_filter, sizeof(nd_ra_filter), ++ NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("failed to set nd_ra_filter (%d)\n", ++ ret)); ++ } ++ } ++ dhd_os_suppress_logging(dhd, FALSE); ++#ifdef ENABLE_IPMCAST_FILTER ++ ipmcast_l2filter = 0; ++ ret = dhd_iovar(dhd, 0, "ipmcast_l2filter", ++ (char *)&ipmcast_l2filter, sizeof(ipmcast_l2filter), ++ NULL, 0, TRUE); ++#endif /* ENABLE_IPMCAST_FILTER */ ++#endif /* DHD_USE_EARLYSUSPEND */ ++ } ++ } ++ dhd_suspend_unlock(dhd); ++ ++ return 0; ++} ++ ++static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) ++{ ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ret = 0; ++ ++ DHD_OS_WAKE_LOCK(dhdp); ++ DHD_PERIM_LOCK(dhdp); ++ ++ /* Set flag when early suspend was called */ ++ dhdp->in_suspend = val; ++ if ((force || !dhdp->suspend_disable_flag) && ++ (dhd_support_sta_mode(dhdp) || dhd_conf_get_insuspend(dhdp, ALL_IN_SUSPEND))) ++ { ++ ret = dhd_set_suspend(val, dhdp); ++ } ++ ++ DHD_PERIM_UNLOCK(dhdp); ++ DHD_OS_WAKE_UNLOCK(dhdp); ++ return ret; ++} ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++static void dhd_early_suspend(struct early_suspend *h) ++{ ++ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); ++ DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); ++ ++ if (dhd && dhd->pub.conf->suspend_mode == EARLY_SUSPEND) { ++ dhd_suspend_resume_helper(dhd, 1, 0); ++ dhd_conf_set_suspend_resume(&dhd->pub, 1); ++ } ++} ++ ++static void dhd_late_resume(struct early_suspend *h) ++{ ++ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); ++ DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); ++ ++ if (dhd && dhd->pub.conf->suspend_mode == EARLY_SUSPEND) { ++ dhd_conf_set_suspend_resume(&dhd->pub, 0); ++ dhd_suspend_resume_helper(dhd, 0, 0); ++ } ++} ++#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ ++ ++/* ++ * Generalized timeout mechanism. Uses spin sleep with exponential back-off until ++ * the sleep time reaches one jiffy, then switches over to task delay. Usage: ++ * ++ * dhd_timeout_start(&tmo, usec); ++ * while (!dhd_timeout_expired(&tmo)) ++ * if (poll_something()) ++ * break; ++ * if (dhd_timeout_expired(&tmo)) ++ * fatal(); ++ */ ++ ++void ++dhd_timeout_start(dhd_timeout_t *tmo, uint usec) ++{ ++ tmo->limit = usec; ++ tmo->increment = 0; ++ tmo->elapsed = 0; ++ tmo->tick = jiffies_to_usecs(1); ++} ++ ++int ++dhd_timeout_expired(dhd_timeout_t *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 ((!CAN_SLEEP()) || tmo->increment < tmo->tick) { ++ OSL_DELAY(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); ++ init_waitqueue_head(&delay_wait); ++ add_wait_queue(&delay_wait, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ (void)schedule_timeout(1); ++ remove_wait_queue(&delay_wait, &wait); ++ set_current_state(TASK_RUNNING); ++ } ++ ++ return 0; ++} ++ ++int ++dhd_net2idx(dhd_info_t *dhd, struct net_device *net) ++{ ++ int i = 0; ++ ++ if (!dhd) { ++ DHD_ERROR(("%s : DHD_BAD_IF return\n", __FUNCTION__)); ++ return DHD_BAD_IF; ++ } ++ ++ while (i < DHD_MAX_IFS) { ++ if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net)) ++ return i; ++ i++; ++ } ++ ++ return DHD_BAD_IF; ++} ++ ++struct net_device * dhd_idx2net(void *pub, int ifidx) ++{ ++ struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; ++ struct dhd_info *dhd_info; ++ ++ if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) ++ return NULL; ++ dhd_info = dhd_pub->info; ++ if (dhd_info && dhd_info->iflist[ifidx]) ++ return dhd_info->iflist[ifidx]->net; ++ return NULL; ++} ++ ++int ++dhd_ifname2idx(dhd_info_t *dhd, char *name) ++{ ++ int i = DHD_MAX_IFS; ++ ++ ASSERT(dhd); ++ ++ if (name == NULL || *name == '\0') ++ return 0; ++ ++ while (--i > 0) ++ if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->dngl_name, name, IFNAMSIZ)) ++ break; ++ ++ DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name)); ++ ++ return i; /* default - the primary interface */ ++} ++ ++char * ++dhd_ifname(dhd_pub_t *dhdp, int ifidx) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ ++ ASSERT(dhd); ++ ++ if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { ++ DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx)); ++ return ""; ++ } ++ ++ if (dhd->iflist[ifidx] == NULL) { ++ DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx)); ++ return ""; ++ } ++ ++ if (dhd->iflist[ifidx]->net) ++ return dhd->iflist[ifidx]->net->name; ++ ++ return ""; ++} ++ ++uint8 * ++dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) ++{ ++ int i; ++ dhd_info_t *dhd = (dhd_info_t *)dhdp; ++ ++ ASSERT(dhd); ++ for (i = 0; i < DHD_MAX_IFS; i++) ++ if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) ++ return dhd->iflist[i]->mac_addr; ++ ++ return NULL; ++} ++ ++ ++static void ++_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) ++{ ++ struct net_device *dev; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ++ struct netdev_hw_addr *ha; ++#else ++ struct dev_mc_list *mclist; ++#endif ++ uint32 allmulti, cnt; ++ ++ wl_ioctl_t ioc; ++ char *buf, *bufp; ++ uint buflen; ++ int ret; ++ ++ if (!dhd->iflist[ifidx]) { ++ DHD_ERROR(("%s : dhd->iflist[%d] was NULL\n", __FUNCTION__, ifidx)); ++ return; ++ } ++ dev = dhd->iflist[ifidx]->net; ++ if (!dev) ++ return; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_lock_bh(dev); ++#endif /* LINUX >= 2.6.27 */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ++ cnt = netdev_mc_count(dev); ++#else ++ cnt = dev->mc_count; ++#endif /* LINUX >= 2.6.35 */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_unlock_bh(dev); ++#endif /* LINUX >= 2.6.27 */ ++ ++ /* Determine initial value of allmulti flag */ ++ allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; ++ ++#ifdef PASS_ALL_MCAST_PKTS ++#ifdef PKT_FILTER_SUPPORT ++ if (!dhd->pub.early_suspended) ++#endif /* PKT_FILTER_SUPPORT */ ++ allmulti = TRUE; ++#endif /* PASS_ALL_MCAST_PKTS */ ++ ++ /* Send down the multicast list first. */ ++ ++ ++ buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); ++ if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { ++ DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", ++ dhd_ifname(&dhd->pub, ifidx), cnt)); ++ return; ++ } ++ ++ strncpy(bufp, "mcast_list", buflen - 1); ++ bufp[buflen - 1] = '\0'; ++ bufp += strlen("mcast_list") + 1; ++ ++ cnt = htol32(cnt); ++ memcpy(bufp, &cnt, sizeof(cnt)); ++ bufp += sizeof(cnt); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_lock_bh(dev); ++#endif /* LINUX >= 2.6.27 */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ netdev_for_each_mc_addr(ha, dev) { ++ if (!cnt) ++ break; ++ memcpy(bufp, ha->addr, ETHER_ADDR_LEN); ++ bufp += ETHER_ADDR_LEN; ++ cnt--; ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++#else /* LINUX < 2.6.35 */ ++ for (mclist = dev->mc_list; (mclist && (cnt > 0)); ++ cnt--, mclist = mclist->next) { ++ memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); ++ bufp += ETHER_ADDR_LEN; ++ } ++#endif /* LINUX >= 2.6.35 */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ netif_addr_unlock_bh(dev); ++#endif /* LINUX >= 2.6.27 */ ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = buflen; ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (ret < 0) { ++ DHD_ERROR(("%s: set mcast_list failed, cnt %d\n", ++ dhd_ifname(&dhd->pub, ifidx), cnt)); ++ allmulti = cnt ? TRUE : allmulti; ++ } ++ ++ MFREE(dhd->pub.osh, buf, buflen); ++ ++ /* Now send the allmulti setting. This is based on the setting in the ++ * net_device flags, but might be modified above to be turned on if we ++ * were trying to set some addresses and dongle rejected it... ++ */ ++ ++ allmulti = htol32(allmulti); ++ ret = dhd_iovar(&dhd->pub, ifidx, "allmulti", (char *)&allmulti, ++ sizeof(allmulti), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: set allmulti %d failed\n", ++ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); ++ } ++ ++ /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ ++ ++ allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; ++ ++ allmulti = htol32(allmulti); ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ioc.cmd = WLC_SET_PROMISC; ++ ioc.buf = &allmulti; ++ ioc.len = sizeof(allmulti); ++ ioc.set = TRUE; ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); ++ if (ret < 0) { ++ DHD_ERROR(("%s: set promisc %d failed\n", ++ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); ++ } ++} ++ ++int ++_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr) ++{ ++ int ret; ++ ++ ret = dhd_iovar(&dhd->pub, ifidx, "cur_etheraddr", (char *)addr, ++ ETHER_ADDR_LEN, NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); ++ } else { ++ memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); ++ if (ifidx == 0) ++ memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); ++ } ++ ++ return ret; ++} ++ ++#ifdef DHD_WMF ++void dhd_update_psta_interface_for_sta(dhd_pub_t* dhdp, char* ifname, void* ea, ++ void* event_data) ++{ ++ struct wl_psta_primary_intf_event *psta_prim_event = ++ (struct wl_psta_primary_intf_event*)event_data; ++ dhd_sta_t *psta_interface = NULL; ++ dhd_sta_t *sta = NULL; ++ uint8 ifindex; ++ ASSERT(ifname); ++ ASSERT(psta_prim_event); ++ ASSERT(ea); ++ ++ ifindex = (uint8)dhd_ifname2idx(dhdp->info, ifname); ++ sta = dhd_find_sta(dhdp, ifindex, ea); ++ if (sta != NULL) { ++ psta_interface = dhd_find_sta(dhdp, ifindex, ++ (void *)(psta_prim_event->prim_ea.octet)); ++ if (psta_interface != NULL) { ++ sta->psta_prim = psta_interface; ++ } ++ } ++} ++ ++/* Get wmf_psta_disable configuration configuration */ ++int dhd_get_wmf_psta_disable(dhd_pub_t *dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ASSERT(idx < DHD_MAX_IFS); ++ ifp = dhd->iflist[idx]; ++ return ifp->wmf_psta_disable; ++} ++ ++/* Set wmf_psta_disable configuration configuration */ ++int dhd_set_wmf_psta_disable(dhd_pub_t *dhdp, uint32 idx, int val) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ASSERT(idx < DHD_MAX_IFS); ++ ifp = dhd->iflist[idx]; ++ ifp->wmf_psta_disable = val; ++ return 0; ++} ++#endif /* DHD_WMF */ ++ ++#ifdef DHD_PSTA ++/* Get psta/psr configuration configuration */ ++int dhd_get_psta_mode(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ return (int)dhd->psta_mode; ++} ++/* Set psta/psr configuration configuration */ ++int dhd_set_psta_mode(dhd_pub_t *dhdp, uint32 val) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd->psta_mode = val; ++ return 0; ++} ++#endif /* DHD_PSTA */ ++ ++#if (defined(DHD_WET) || defined(DHD_MCAST_REGEN) || defined(DHD_L2_FILTER)) ++static void ++dhd_update_rx_pkt_chainable_state(dhd_pub_t* dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ if ( ++#ifdef DHD_L2_FILTER ++ (ifp->block_ping) || ++#endif ++#ifdef DHD_WET ++ (dhd->wet_mode) || ++#endif ++#ifdef DHD_MCAST_REGEN ++ (ifp->mcast_regen_bss_enable) || ++#endif ++ FALSE) { ++ ifp->rx_pkt_chainable = FALSE; ++ } ++} ++#endif /* DHD_WET || DHD_MCAST_REGEN || DHD_L2_FILTER */ ++ ++#ifdef DHD_WET ++/* Get wet configuration configuration */ ++int dhd_get_wet_mode(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ return (int)dhd->wet_mode; ++} ++ ++/* Set wet configuration configuration */ ++int dhd_set_wet_mode(dhd_pub_t *dhdp, uint32 val) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd->wet_mode = val; ++ dhd_update_rx_pkt_chainable_state(dhdp, 0); ++ return 0; ++} ++#endif /* DHD_WET */ ++ ++#if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++int32 dhd_role_to_nl80211_iftype(int32 role) ++{ ++ switch (role) { ++ case WLC_E_IF_ROLE_STA: ++ return NL80211_IFTYPE_STATION; ++ case WLC_E_IF_ROLE_AP: ++ return NL80211_IFTYPE_AP; ++ case WLC_E_IF_ROLE_WDS: ++ return NL80211_IFTYPE_WDS; ++ case WLC_E_IF_ROLE_P2P_GO: ++ return NL80211_IFTYPE_P2P_GO; ++ case WLC_E_IF_ROLE_P2P_CLIENT: ++ return NL80211_IFTYPE_P2P_CLIENT; ++ case WLC_E_IF_ROLE_IBSS: ++ case WLC_E_IF_ROLE_NAN: ++ return NL80211_IFTYPE_ADHOC; ++ default: ++ return NL80211_IFTYPE_UNSPECIFIED; ++ } ++} ++#endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ ++static void ++dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ dhd_if_event_t *if_event = event_info; ++ struct net_device *ndev; ++ int ifidx, bssidx; ++ int ret; ++#if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ struct wl_if_event_info info; ++#endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ ++ if (event != DHD_WQ_WORK_IF_ADD) { ++ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!if_event) { ++ DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); ++ return; ++ } ++ ++ dhd_net_if_lock_local(dhd); ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ DHD_PERIM_LOCK(&dhd->pub); ++ ++ ifidx = if_event->event.ifidx; ++ bssidx = if_event->event.bssidx; ++ DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx)); ++ ++ ++#if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ if (if_event->event.ifidx > 0) { ++ bzero(&info, sizeof(info)); ++ info.ifidx = if_event->event.ifidx; ++ info.bssidx = if_event->event.bssidx; ++ info.role = if_event->event.role; ++ strncpy(info.name, if_event->name, IFNAMSIZ); ++ if (wl_cfg80211_post_ifcreate(dhd->pub.info->iflist[0]->net, ++ &info, if_event->mac, NULL, true) != NULL) { ++ /* Do the post interface create ops */ ++ DHD_ERROR(("Post ifcreate ops done. Returning \n")); ++ goto done; ++ } ++ } ++#endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ ++ /* This path is for non-android case */ ++ /* The interface name in host and in event msg are same */ ++ /* if name in event msg is used to create dongle if list on host */ ++ ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name, ++ if_event->mac, bssidx, TRUE, if_event->name); ++ if (!ndev) { ++ DHD_ERROR(("%s: net device alloc failed \n", __FUNCTION__)); ++ goto done; ++ } ++ ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ ret = dhd_register_if(&dhd->pub, ifidx, TRUE); ++ DHD_PERIM_LOCK(&dhd->pub); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__)); ++ dhd_remove_if(&dhd->pub, ifidx, TRUE); ++ goto done; ++ } ++#ifndef PCIE_FULL_DONGLE ++ /* Turn on AP isolation in the firmware for interfaces operating in AP mode */ ++ if (FW_SUPPORTED((&dhd->pub), ap) && (if_event->event.role != WLC_E_IF_ROLE_STA)) { ++ uint32 var_int = 1; ++ ret = dhd_iovar(&dhd->pub, ifidx, "ap_isolate", (char *)&var_int, sizeof(var_int), ++ NULL, 0, TRUE); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s: Failed to set ap_isolate to dongle\n", __FUNCTION__)); ++ dhd_remove_if(&dhd->pub, ifidx, TRUE); ++ } ++ } ++#endif /* PCIE_FULL_DONGLE */ ++ ++done: ++ MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); ++ ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ dhd_net_if_unlock_local(dhd); ++} ++ ++static void ++dhd_ifdel_event_handler(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ int ifidx; ++ dhd_if_event_t *if_event = event_info; ++ ++ ++ if (event != DHD_WQ_WORK_IF_DEL) { ++ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!if_event) { ++ DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); ++ return; ++ } ++ ++ dhd_net_if_lock_local(dhd); ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ DHD_PERIM_LOCK(&dhd->pub); ++ ++ ifidx = if_event->event.ifidx; ++ DHD_TRACE(("Removing interface with idx %d\n", ifidx)); ++ ++ DHD_PERIM_UNLOCK(&dhd->pub); ++#if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ if (if_event->event.ifidx > 0) { ++ /* Do the post interface del ops */ ++ if (wl_cfg80211_post_ifdel(dhd->pub.info->iflist[ifidx]->net, true) == 0) { ++ DHD_TRACE(("Post ifdel ops done. Returning \n")); ++ DHD_PERIM_LOCK(&dhd->pub); ++ goto done; ++ } ++ } ++#endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ ++ dhd_remove_if(&dhd->pub, ifidx, TRUE); ++ DHD_PERIM_LOCK(&dhd->pub); ++ ++#if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++done: ++#endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); ++ ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ dhd_net_if_unlock_local(dhd); ++} ++ ++#ifdef DHD_UPDATE_INTF_MAC ++static void ++dhd_ifupdate_event_handler(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ int ifidx; ++ dhd_if_event_t *if_event = event_info; ++ ++ if (event != DHD_WQ_WORK_IF_UPDATE) { ++ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!if_event) { ++ DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); ++ return; ++ } ++ ++ dhd_net_if_lock_local(dhd); ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ ++ ifidx = if_event->event.ifidx; ++ DHD_TRACE(("%s: Update interface with idx %d\n", __FUNCTION__, ifidx)); ++ ++ dhd_op_if_update(&dhd->pub, ifidx); ++ ++ MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); ++ ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ dhd_net_if_unlock_local(dhd); ++} ++ ++int dhd_op_if_update(dhd_pub_t *dhdpub, int ifidx) ++{ ++ dhd_info_t * dhdinfo = NULL; ++ dhd_if_t * ifp = NULL; ++ int ret = 0; ++ char buf[128]; ++ ++ if ((NULL==dhdpub)||(NULL==dhdpub->info)) { ++ DHD_ERROR(("%s: *** DHD handler is NULL!\n", __FUNCTION__)); ++ return -1; ++ } else { ++ dhdinfo = (dhd_info_t *)dhdpub->info; ++ ifp = dhdinfo->iflist[ifidx]; ++ if (NULL==ifp) { ++ DHD_ERROR(("%s: *** ifp handler is NULL!\n", __FUNCTION__)); ++ return -2; ++ } ++ } ++ ++ DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx)); ++ // Get MAC address ++ strcpy(buf, "cur_etheraddr"); ++ ret = dhd_wl_ioctl_cmd(&dhdinfo->pub, WLC_GET_VAR, buf, sizeof(buf), FALSE, ifp->idx); ++ if (0>ret) { ++ DHD_ERROR(("Failed to upudate the MAC address for itf=%s, ret=%d\n", ifp->name, ret)); ++ // avoid collision ++ dhdinfo->iflist[ifp->idx]->mac_addr[5] += 1; ++ // force locally administrate address ++ ETHER_SET_LOCALADDR(&dhdinfo->iflist[ifp->idx]->mac_addr); ++ } else { ++ DHD_EVENT(("Got mac for itf %s, idx %d, MAC=%02X:%02X:%02X:%02X:%02X:%02X\n", ++ ifp->name, ifp->idx, ++ (unsigned char)buf[0], (unsigned char)buf[1], (unsigned char)buf[2], ++ (unsigned char)buf[3], (unsigned char)buf[4], (unsigned char)buf[5])); ++ memcpy(dhdinfo->iflist[ifp->idx]->mac_addr, buf, ETHER_ADDR_LEN); ++ if (dhdinfo->iflist[ifp->idx]->net) { ++ memcpy(dhdinfo->iflist[ifp->idx]->net->dev_addr, buf, ETHER_ADDR_LEN); ++ } ++ } ++ ++ return ret; ++} ++#endif /* DHD_UPDATE_INTF_MAC */ ++ ++static void ++dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ dhd_if_t *ifp = event_info; ++ ++ if (event != DHD_WQ_WORK_SET_MAC) { ++ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); ++ } ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); ++ return; ++ } ++ ++ dhd_net_if_lock_local(dhd); ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ DHD_PERIM_LOCK(&dhd->pub); ++ ++ // terence 20160907: fix for not able to set mac when wlan0 is down ++ if (ifp == NULL || !ifp->set_macaddress) { ++ goto done; ++ } ++ if (ifp == NULL || !dhd->pub.up) { ++ DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); ++ goto done; ++ } ++ ++ DHD_ERROR(("%s: MACID is overwritten\n", __FUNCTION__)); ++ ifp->set_macaddress = FALSE; ++ if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0) ++ DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); ++ else ++ DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); ++ ++done: ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ dhd_net_if_unlock_local(dhd); ++} ++ ++static void ++dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ int ifidx = (int)((long int)event_info); ++ dhd_if_t *ifp = NULL; ++ ++ if (event != DHD_WQ_WORK_SET_MCAST_LIST) { ++ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); ++ return; ++ } ++ ++ dhd_net_if_lock_local(dhd); ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ DHD_PERIM_LOCK(&dhd->pub); ++ ++ ifp = dhd->iflist[ifidx]; ++ ++ if (ifp == NULL || !dhd->pub.up) { ++ DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); ++ goto done; ++ } ++ ++ if (ifp == NULL || !dhd->pub.up) { ++ DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); ++ goto done; ++ } ++ ++ ifidx = ifp->idx; ++ ++ ++ _dhd_set_multicast_list(dhd, ifidx); ++ DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx)); ++ ++done: ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ dhd_net_if_unlock_local(dhd); ++} ++ ++static int ++dhd_set_mac_address(struct net_device *dev, void *addr) ++{ ++ int ret = 0; ++ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ struct sockaddr *sa = (struct sockaddr *)addr; ++ int ifidx; ++ dhd_if_t *dhdif; ++ ++ ifidx = dhd_net2idx(dhd, dev); ++ if (ifidx == DHD_BAD_IF) ++ return -1; ++ ++ dhdif = dhd->iflist[ifidx]; ++ ++ dhd_net_if_lock_local(dhd); ++ memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN); ++ dhdif->set_macaddress = TRUE; ++ dhd_net_if_unlock_local(dhd); ++ dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC, ++ dhd_set_mac_addr_handler, DHD_WQ_WORK_PRIORITY_LOW); ++ return ret; ++} ++ ++static void ++dhd_set_multicast_list(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int ifidx; ++ ++ ifidx = dhd_net2idx(dhd, dev); ++ if (ifidx == DHD_BAD_IF) ++ return; ++ ++ dhd->iflist[ifidx]->set_multicast = TRUE; ++ dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)((long int)ifidx), ++ DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WQ_WORK_PRIORITY_LOW); ++ ++ // terence 20160907: fix for not able to set mac when wlan0 is down ++ dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx], ++ DHD_WQ_WORK_SET_MAC, dhd_set_mac_addr_handler, DHD_WQ_WORK_PRIORITY_LOW); ++} ++ ++#ifdef DHD_UCODE_DOWNLOAD ++/* Get ucode path */ ++char * ++dhd_get_ucode_path(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ return dhd->uc_path; ++} ++#endif /* DHD_UCODE_DOWNLOAD */ ++ ++#ifdef PROP_TXSTATUS ++int ++dhd_os_wlfc_block(dhd_pub_t *pub) ++{ ++ dhd_info_t *di = (dhd_info_t *)(pub->info); ++ ASSERT(di != NULL); ++ /* terence 20161229: don't do spin lock if proptx not enabled */ ++ if (disable_proptx) ++ return 1; ++#ifdef BCMDBUS ++ spin_lock_irqsave(&di->wlfc_spinlock, di->wlfc_lock_flags); ++#else ++ spin_lock_bh(&di->wlfc_spinlock); ++#endif /* BCMDBUS */ ++ return 1; ++} ++ ++int ++dhd_os_wlfc_unblock(dhd_pub_t *pub) ++{ ++ dhd_info_t *di = (dhd_info_t *)(pub->info); ++ ++ ASSERT(di != NULL); ++ /* terence 20161229: don't do spin lock if proptx not enabled */ ++ if (disable_proptx) ++ return 1; ++#ifdef BCMDBUS ++ spin_unlock_irqrestore(&di->wlfc_spinlock, di->wlfc_lock_flags); ++#else ++ spin_unlock_bh(&di->wlfc_spinlock); ++#endif /* BCMDBUS */ ++ return 1; ++} ++ ++#endif /* PROP_TXSTATUS */ ++ ++#if defined(DHD_RX_DUMP) || defined(DHD_TX_DUMP) ++typedef struct { ++ uint16 type; ++ const char *str; ++} PKTTYPE_INFO; ++ ++static const PKTTYPE_INFO packet_type_info[] = ++{ ++ { ETHER_TYPE_IP, "IP" }, ++ { ETHER_TYPE_ARP, "ARP" }, ++ { ETHER_TYPE_BRCM, "BRCM" }, ++ { ETHER_TYPE_802_1X, "802.1X" }, ++ { ETHER_TYPE_WAI, "WAPI" }, ++ { 0, ""} ++}; ++ ++static const char *_get_packet_type_str(uint16 type) ++{ ++ int i; ++ int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; ++ ++ for (i = 0; i < n; i++) { ++ if (packet_type_info[i].type == type) ++ return packet_type_info[i].str; ++ } ++ ++ return packet_type_info[n].str; ++} ++ ++void ++dhd_trx_dump(struct net_device *ndev, uint8 *dump_data, uint datalen, bool tx) ++{ ++ uint16 protocol; ++ char *ifname; ++ ++ protocol = (dump_data[12] << 8) | dump_data[13]; ++ ifname = ndev ? ndev->name : "N/A"; ++ ++ if (protocol != ETHER_TYPE_BRCM) { ++ printk("[dhd-%s] %s DUMP - %s\n", ifname, tx?"Tx":"Rx", ++ _get_packet_type_str(protocol)); ++#if defined(DHD_TX_FULL_DUMP) || defined(DHD_RX_FULL_DUMP) ++ prhex("Data", dump_data, datalen); ++#endif /* DHD_TX_FULL_DUMP || DHD_RX_FULL_DUMP */ ++ } ++} ++#endif /* DHD_TX_DUMP || DHD_RX_DUMP */ ++ ++/* This routine do not support Packet chain feature, Currently tested for ++ * proxy arp feature ++ */ ++int dhd_sendup(dhd_pub_t *dhdp, int ifidx, void *p) ++{ ++ struct sk_buff *skb; ++ void *skbhead = NULL; ++ void *skbprev = NULL; ++ dhd_if_t *ifp; ++ ASSERT(!PKTISCHAINED(p)); ++ skb = PKTTONATIVE(dhdp->osh, p); ++ ++ ifp = dhdp->info->iflist[ifidx]; ++ skb->dev = ifp->net; ++#if defined(BCM_GMAC3) ++ /* Forwarder capable interfaces use WOFA based forwarding */ ++ if (ifp->fwdh) { ++ struct ether_header *eh = (struct ether_header *)PKTDATA(dhdp->osh, p); ++ uint16 * da = (uint16 *)(eh->ether_dhost); ++ uintptr_t wofa_data; ++ ASSERT(ISALIGNED(da, 2)); ++ ++ wofa_data = fwder_lookup(ifp->fwdh->mate, da, ifp->idx); ++ if (wofa_data == WOFA_DATA_INVALID) { /* Unknown MAC address */ ++ if (fwder_transmit(ifp->fwdh, skb, 1, skb->dev) == FWDER_SUCCESS) { ++ return BCME_OK; ++ } ++ } ++ PKTFRMNATIVE(dhdp->osh, p); ++ PKTFREE(dhdp->osh, p, FALSE); ++ return BCME_OK; ++ } ++#endif /* BCM_GMAC3 */ ++ ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ if (in_interrupt()) { ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, ++ __FUNCTION__, __LINE__); ++ netif_rx(skb); ++ } else { ++ if (dhdp->info->rxthread_enabled) { ++ if (!skbhead) { ++ skbhead = skb; ++ } else { ++ PKTSETNEXT(dhdp->osh, skbprev, skb); ++ } ++ skbprev = skb; ++ } 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 ++ * by netif_rx_ni(), but in earlier kernels, we need ++ * to do it manually. ++ */ ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, ++ __FUNCTION__, __LINE__); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ netif_rx_ni(skb); ++#else ++ ulong flags; ++ netif_rx(skb); ++ local_irq_save(flags); ++ RAISE_RX_SOFTIRQ(); ++ local_irq_restore(flags); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ ++ } ++ } ++ ++ if (dhdp->info->rxthread_enabled && skbhead) ++ dhd_sched_rxf(dhdp, skbhead); ++ ++ return BCME_OK; ++} ++ ++int BCMFASTPATH ++__dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) ++{ ++ int ret = BCME_OK; ++ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); ++ struct ether_header *eh = NULL; ++#if defined(DHD_L2_FILTER) ++ dhd_if_t *ifp = dhd_get_ifp(dhdp, ifidx); ++#endif ++ ++ /* Reject if down */ ++ if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { ++ /* free the packet here since the caller won't */ ++ PKTCFREE(dhdp->osh, pktbuf, TRUE); ++ return -ENODEV; ++ } ++ ++#ifdef PCIE_FULL_DONGLE ++ if (dhdp->busstate == DHD_BUS_SUSPEND) { ++ DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); ++ PKTCFREE(dhdp->osh, pktbuf, TRUE); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return -ENODEV; ++#else ++ return NETDEV_TX_BUSY; ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) */ ++ } ++#endif /* PCIE_FULL_DONGLE */ ++ ++#ifdef DHD_L2_FILTER ++ /* if dhcp_unicast is enabled, we need to convert the */ ++ /* broadcast DHCP ACK/REPLY packets to Unicast. */ ++ if (ifp->dhcp_unicast) { ++ uint8* mac_addr; ++ uint8* ehptr = NULL; ++ int ret; ++ ret = bcm_l2_filter_get_mac_addr_dhcp_pkt(dhdp->osh, pktbuf, ifidx, &mac_addr); ++ if (ret == BCME_OK) { ++ /* if given mac address having valid entry in sta list ++ * copy the given mac address, and return with BCME_OK ++ */ ++ if (dhd_find_sta(dhdp, ifidx, mac_addr)) { ++ ehptr = PKTDATA(dhdp->osh, pktbuf); ++ bcopy(mac_addr, ehptr + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); ++ } ++ } ++ } ++ ++ if (ifp->grat_arp && DHD_IF_ROLE_AP(dhdp, ifidx)) { ++ if (bcm_l2_filter_gratuitous_arp(dhdp->osh, pktbuf) == BCME_OK) { ++ PKTCFREE(dhdp->osh, pktbuf, TRUE); ++ return BCME_ERROR; ++ } ++ } ++ ++ if (ifp->parp_enable && DHD_IF_ROLE_AP(dhdp, ifidx)) { ++ ret = dhd_l2_filter_pkt_handle(dhdp, ifidx, pktbuf, TRUE); ++ ++ /* Drop the packets if l2 filter has processed it already ++ * otherwise continue with the normal path ++ */ ++ if (ret == BCME_OK) { ++ PKTCFREE(dhdp->osh, pktbuf, TRUE); ++ return BCME_ERROR; ++ } ++ } ++#endif /* DHD_L2_FILTER */ ++ /* Update multicast statistic */ ++ if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { ++ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); ++ eh = (struct ether_header *)pktdata; ++ ++ if (ETHER_ISMULTI(eh->ether_dhost)) ++ dhdp->tx_multicast++; ++ if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) { ++#ifdef DHD_LOSSLESS_ROAMING ++ uint8 prio = (uint8)PKTPRIO(pktbuf); ++ ++ /* back up 802.1x's priority */ ++ dhdp->prio_8021x = prio; ++#endif /* DHD_LOSSLESS_ROAMING */ ++ DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED); ++ atomic_inc(&dhd->pend_8021x_cnt); ++ dhd_dump_eapol_4way_message(dhdp, dhd_ifname(dhdp, ifidx), pktdata, TRUE); ++ } ++ ++ if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { ++#ifdef DHD_DHCP_DUMP ++ dhd_dhcp_dump(dhd_ifname(dhdp, ifidx), pktdata, TRUE); ++#endif /* DHD_DHCP_DUMP */ ++#ifdef DHD_ICMP_DUMP ++ dhd_icmp_dump(dhd_ifname(dhdp, ifidx), pktdata, TRUE); ++#endif /* DHD_ICMP_DUMP */ ++ } ++#ifdef DHD_ARP_DUMP ++ if (ntoh16(eh->ether_type) == ETHER_TYPE_ARP) { ++ dhd_arp_dump(dhd_ifname(dhdp, ifidx), pktdata, TRUE); ++ } ++#endif /* DHD_ARP_DUMP */ ++ } else { ++ PKTCFREE(dhdp->osh, pktbuf, TRUE); ++ return BCME_ERROR; ++ } ++ ++ { ++ /* Look into the packet and update the packet priority */ ++#ifndef PKTPRIO_OVERRIDE ++ if (PKTPRIO(pktbuf) == 0) ++#endif /* !PKTPRIO_OVERRIDE */ ++ { ++#if defined(QOS_MAP_SET) ++ pktsetprio_qms(pktbuf, wl_get_up_table(dhdp, ifidx), FALSE); ++#else ++ pktsetprio(pktbuf, FALSE); ++#endif /* QOS_MAP_SET */ ++ } ++ } ++ ++ ++#if defined(TRAFFIC_MGMT_DWM) ++ traffic_mgmt_pkt_set_prio(dhdp, pktbuf); ++ ++#ifdef BCM_GMAC3 ++ DHD_PKT_SET_DATAOFF(pktbuf, 0); ++#endif /* BCM_GMAC3 */ ++#endif ++ ++#ifdef PCIE_FULL_DONGLE ++ /* ++ * Lkup the per interface hash table, for a matching flowring. If one is not ++ * available, allocate a unique flowid and add a flowring entry. ++ * The found or newly created flowid is placed into the pktbuf's tag. ++ */ ++ ret = dhd_flowid_update(dhdp, ifidx, dhdp->flow_prio_map[(PKTPRIO(pktbuf))], pktbuf); ++ if (ret != BCME_OK) { ++ PKTCFREE(dhd->pub.osh, pktbuf, TRUE); ++ return ret; ++ } ++#endif ++ ++#if defined(DHD_TX_DUMP) ++ dhd_trx_dump(dhd_idx2net(dhdp, ifidx), PKTDATA(dhdp->osh, pktbuf), ++ PKTLEN(dhdp->osh, pktbuf), TRUE); ++#endif ++ /* terence 20150901: Micky add to ajust the 802.1X priority */ ++ /* Set the 802.1X packet with the highest priority 7 */ ++ if (dhdp->conf->pktprio8021x >= 0) ++ pktset8021xprio(pktbuf, dhdp->conf->pktprio8021x); ++ ++#ifdef PROP_TXSTATUS ++ if (dhd_wlfc_is_supported(dhdp)) { ++ /* store the interface ID */ ++ DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); ++ ++ /* store destination MAC in the tag as well */ ++ DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); ++ ++ /* decide which FIFO this packet belongs to */ ++ if (ETHER_ISMULTI(eh->ether_dhost)) ++ /* one additional queue index (highest AC + 1) is used for bc/mc queue */ ++ DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); ++ else ++ DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); ++ } else ++#endif /* PROP_TXSTATUS */ ++ { ++ /* If the protocol uses a data header, apply it */ ++ dhd_prot_hdrpush(dhdp, ifidx, pktbuf); ++ } ++ ++ /* Use bus module to send data frame */ ++#ifdef WLMEDIA_HTSF ++ dhd_htsf_addtxts(dhdp, pktbuf); ++#endif ++#ifdef PROP_TXSTATUS ++ { ++ if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata, ++ dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) { ++ /* non-proptxstatus way */ ++#ifdef BCMPCIE ++ ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); ++#else ++ ret = dhd_bus_txdata(dhdp->bus, pktbuf); ++#endif /* BCMPCIE */ ++ } ++ } ++#else ++#ifdef BCMPCIE ++ ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); ++#else ++ ret = dhd_bus_txdata(dhdp->bus, pktbuf); ++#endif /* BCMPCIE */ ++#endif /* PROP_TXSTATUS */ ++#ifdef BCMDBUS ++ if (ret) ++ PKTCFREE(dhdp->osh, pktbuf, TRUE); ++#endif /* BCMDBUS */ ++ ++ return ret; ++} ++ ++int BCMFASTPATH ++dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) ++{ ++ int ret = 0; ++ unsigned long flags; ++ ++ DHD_GENERAL_LOCK(dhdp, flags); ++ if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) { ++ DHD_ERROR(("%s: returning as busstate=%d\n", ++ __FUNCTION__, dhdp->busstate)); ++ DHD_GENERAL_UNLOCK(dhdp, flags); ++ PKTCFREE(dhdp->osh, pktbuf, TRUE); ++ return -ENODEV; ++ } ++ DHD_BUS_BUSY_SET_IN_SEND_PKT(dhdp); ++ DHD_GENERAL_UNLOCK(dhdp, flags); ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++ if (dhdpcie_runtime_bus_wake(dhdp, FALSE, __builtin_return_address(0))) { ++ DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); ++ PKTCFREE(dhdp->osh, pktbuf, TRUE); ++ ret = -EBUSY; ++ goto exit; ++ } ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ DHD_GENERAL_LOCK(dhdp, flags); ++ if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) { ++ DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", ++ __FUNCTION__, dhdp->busstate, dhdp->dhd_bus_busy_state)); ++ DHD_BUS_BUSY_CLEAR_IN_SEND_PKT(dhdp); ++ dhd_os_busbusy_wake(dhdp); ++ DHD_GENERAL_UNLOCK(dhdp, flags); ++ PKTCFREE(dhdp->osh, pktbuf, TRUE); ++ return -ENODEV; ++ } ++ DHD_GENERAL_UNLOCK(dhdp, flags); ++ ++ ret = __dhd_sendpkt(dhdp, ifidx, pktbuf); ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++exit: ++#endif ++ DHD_GENERAL_LOCK(dhdp, flags); ++ DHD_BUS_BUSY_CLEAR_IN_SEND_PKT(dhdp); ++ dhd_os_busbusy_wake(dhdp); ++ DHD_GENERAL_UNLOCK(dhdp, flags); ++ return ret; ++} ++ ++#if defined(DHD_LB_TXP) ++ ++int BCMFASTPATH ++dhd_lb_sendpkt(dhd_info_t *dhd, struct net_device *net, ++ int ifidx, void *skb) ++{ ++ DHD_LB_STATS_PERCPU_ARR_INCR(dhd->tx_start_percpu_run_cnt); ++ ++ /* If the feature is disabled run-time do TX from here */ ++ if (atomic_read(&dhd->lb_txp_active) == 0) { ++ DHD_LB_STATS_PERCPU_ARR_INCR(dhd->txp_percpu_run_cnt); ++ return __dhd_sendpkt(&dhd->pub, ifidx, skb); ++ } ++ ++ /* Store the address of net device and interface index in the Packet tag */ ++ DHD_LB_TX_PKTTAG_SET_NETDEV((dhd_tx_lb_pkttag_fr_t *)PKTTAG(skb), net); ++ DHD_LB_TX_PKTTAG_SET_IFIDX((dhd_tx_lb_pkttag_fr_t *)PKTTAG(skb), ifidx); ++ ++ /* Enqueue the skb into tx_pend_queue */ ++ skb_queue_tail(&dhd->tx_pend_queue, skb); ++ ++ DHD_TRACE(("%s(): Added skb %p for netdev %p \r\n", __FUNCTION__, skb, net)); ++ ++ /* Dispatch the Tx job to be processed by the tx_tasklet */ ++ dhd_lb_tx_dispatch(&dhd->pub); ++ ++ return NETDEV_TX_OK; ++} ++#endif /* DHD_LB_TXP */ ++ ++int BCMFASTPATH ++dhd_start_xmit(struct sk_buff *skb, struct net_device *net) ++{ ++ int ret; ++ uint datalen; ++ void *pktbuf; ++ dhd_info_t *dhd = DHD_DEV_INFO(net); ++ dhd_if_t *ifp = NULL; ++ int ifidx; ++ unsigned long flags; ++#ifdef WLMEDIA_HTSF ++ uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; ++#else ++ uint8 htsfdlystat_sz = 0; ++#endif ++#ifdef DHD_WMF ++ struct ether_header *eh; ++ uint8 *iph; ++#endif /* DHD_WMF */ ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (dhd_query_bus_erros(&dhd->pub)) { ++ return -ENODEV; ++ } ++ ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ DHD_BUS_BUSY_SET_IN_TX(&dhd->pub); ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++ if (dhdpcie_runtime_bus_wake(&dhd->pub, FALSE, dhd_start_xmit)) { ++ /* In order to avoid pkt loss. Return NETDEV_TX_BUSY until run-time resumed. */ ++ /* stop the network queue temporarily until resume done */ ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ if (!dhdpcie_is_resume_done(&dhd->pub)) { ++ dhd_bus_stop_queue(dhd->pub.bus); ++ } ++ DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); ++ dhd_os_busbusy_wake(&dhd->pub); ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return -ENODEV; ++#else ++ return NETDEV_TX_BUSY; ++#endif ++ } ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++#ifdef BCMPCIE ++ if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(&dhd->pub)) { ++ DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", ++ __FUNCTION__, dhd->pub.busstate, dhd->pub.dhd_bus_busy_state)); ++ DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); ++#ifdef PCIE_FULL_DONGLE ++ /* Stop tx queues if suspend is in progress */ ++ if (DHD_BUS_CHECK_ANY_SUSPEND_IN_PROGRESS(&dhd->pub)) { ++ dhd_bus_stop_queue(dhd->pub.bus); ++ } ++#endif /* PCIE_FULL_DONGLE */ ++ dhd_os_busbusy_wake(&dhd->pub); ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return -ENODEV; ++#else ++ return NETDEV_TX_BUSY; ++#endif ++ } ++#else ++ if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(&dhd->pub)) { ++ DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", ++ __FUNCTION__, dhd->pub.busstate, dhd->pub.dhd_bus_busy_state)); ++ } ++#endif ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); ++ ++ ++#if defined(DHD_HANG_SEND_UP_TEST) ++ if (dhd->pub.req_hang_type == HANG_REASON_BUS_DOWN) { ++ dhd->pub.busstate = DHD_BUS_DOWN; ++ } ++#endif /* DHD_HANG_SEND_UP_TEST */ ++ ++ /* Reject if down */ ++ if (dhd->pub.hang_was_sent || DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(&dhd->pub)) { ++ DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", ++ __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); ++ netif_stop_queue(net); ++ /* Send Event when bus down detected during data session */ ++ if (dhd->pub.up && !dhd->pub.hang_was_sent && !DHD_BUS_CHECK_REMOVE(&dhd->pub)) { ++ DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); ++ dhd->pub.hang_reason = HANG_REASON_BUS_DOWN; ++ net_os_send_hang_message(net); ++ } ++ DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); ++ dhd_os_busbusy_wake(&dhd->pub); ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return -ENODEV; ++#else ++ return NETDEV_TX_BUSY; ++#endif ++ } ++ ++ ifp = DHD_DEV_IFP(net); ++ ifidx = DHD_DEV_IFIDX(net); ++ if (ifidx == DHD_BAD_IF) { ++ DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); ++ netif_stop_queue(net); ++ DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); ++ dhd_os_busbusy_wake(&dhd->pub); ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return -ENODEV; ++#else ++ return NETDEV_TX_BUSY; ++#endif ++ } ++ ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ ++ ASSERT(ifidx == dhd_net2idx(dhd, net)); ++ ASSERT((ifp != NULL) && ((ifidx < DHD_MAX_IFS) && (ifp == dhd->iflist[ifidx]))); ++ ++ bcm_object_trace_opr(skb, BCM_OBJDBG_ADD_PKT, __FUNCTION__, __LINE__); ++ ++ /* re-align socket buffer if "skb->data" is odd address */ ++ if (((unsigned long)(skb->data)) & 0x1) { ++ unsigned char *data = skb->data; ++ uint32 length = skb->len; ++ PKTPUSH(dhd->pub.osh, skb, 1); ++ memmove(skb->data, data, length); ++ PKTSETLEN(dhd->pub.osh, skb, length); ++ } ++ ++ datalen = PKTLEN(dhd->pub.osh, skb); ++ ++ /* Make sure there's enough room for any header */ ++ if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { ++ struct sk_buff *skb2; ++ ++ DHD_INFO(("%s: insufficient headroom\n", ++ dhd_ifname(&dhd->pub, ifidx))); ++ dhd->pub.tx_realloc++; ++ ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, __FUNCTION__, __LINE__); ++ skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); ++ ++ dev_kfree_skb(skb); ++ if ((skb = skb2) == NULL) { ++ DHD_ERROR(("%s: skb_realloc_headroom failed\n", ++ dhd_ifname(&dhd->pub, ifidx))); ++ ret = -ENOMEM; ++ goto done; ++ } ++ bcm_object_trace_opr(skb, BCM_OBJDBG_ADD_PKT, __FUNCTION__, __LINE__); ++ } ++ ++ /* move from dhdsdio_sendfromq(), try to orphan skb early */ ++ if (dhd->pub.conf->orphan_move == 2) ++ PKTORPHAN(skb, dhd->pub.conf->tsq); ++ else if (dhd->pub.conf->orphan_move == 3) ++ skb_orphan(skb); ++ ++ /* Convert to packet */ ++ if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { ++ DHD_ERROR(("%s: PKTFRMNATIVE failed\n", ++ dhd_ifname(&dhd->pub, ifidx))); ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, __FUNCTION__, __LINE__); ++ dev_kfree_skb_any(skb); ++ ret = -ENOMEM; ++ goto done; ++ } ++ ++#if defined(WLMEDIA_HTSF) ++ if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { ++ uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); ++ struct ether_header *eh = (struct ether_header *)pktdata; ++ ++ if (!ETHER_ISMULTI(eh->ether_dhost) && ++ (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { ++ eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); ++ } ++ } ++#endif ++#ifdef DHD_WET ++ /* wet related packet proto manipulation should be done in DHD ++ since dongle doesn't have complete payload ++ */ ++ if (WET_ENABLED(&dhd->pub) && ++ (dhd_wet_send_proc(dhd->pub.wet_info, pktbuf, &pktbuf) < 0)) { ++ DHD_INFO(("%s:%s: wet send proc failed\n", ++ __FUNCTION__, dhd_ifname(&dhd->pub, ifidx))); ++ PKTFREE(dhd->pub.osh, pktbuf, FALSE); ++ ret = -EFAULT; ++ goto done; ++ } ++#endif /* DHD_WET */ ++ ++#ifdef DHD_WMF ++ eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf); ++ iph = (uint8 *)eh + ETHER_HDR_LEN; ++ ++ /* WMF processing for multicast packets ++ * Only IPv4 packets are handled ++ */ ++ if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) && ++ (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) || ++ ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) { ++#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) ++ void *sdu_clone; ++ bool ucast_convert = FALSE; ++#ifdef DHD_UCAST_UPNP ++ uint32 dest_ip; ++ ++ dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET))); ++ ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip); ++#endif /* DHD_UCAST_UPNP */ ++#ifdef DHD_IGMP_UCQUERY ++ ucast_convert |= dhd->pub.wmf_ucast_igmp_query && ++ (IPV4_PROT(iph) == IP_PROT_IGMP) && ++ (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY); ++#endif /* DHD_IGMP_UCQUERY */ ++ if (ucast_convert) { ++ dhd_sta_t *sta; ++ unsigned long flags; ++ struct list_head snapshot_list; ++ struct list_head *wmf_ucforward_list; ++ ++ ret = NETDEV_TX_OK; ++ ++ /* For non BCM_GMAC3 platform we need a snapshot sta_list to ++ * resolve double DHD_IF_STA_LIST_LOCK call deadlock issue. ++ */ ++ wmf_ucforward_list = DHD_IF_WMF_UCFORWARD_LOCK(dhd, ifp, &snapshot_list); ++ ++ /* Convert upnp/igmp query to unicast for each assoc STA */ ++ list_for_each_entry(sta, wmf_ucforward_list, list) { ++ /* Skip sending to proxy interfaces of proxySTA */ ++ if (sta->psta_prim != NULL && !ifp->wmf_psta_disable) { ++ continue; ++ } ++ if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) { ++ ret = WMF_NOP; ++ break; ++ } ++ dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1); ++ } ++ DHD_IF_WMF_UCFORWARD_UNLOCK(dhd, wmf_ucforward_list); ++ ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); ++ dhd_os_busbusy_wake(&dhd->pub); ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++ if (ret == NETDEV_TX_OK) ++ PKTFREE(dhd->pub.osh, pktbuf, TRUE); ++ ++ return ret; ++ } else ++#endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */ ++ { ++ /* There will be no STA info if the packet is coming from LAN host ++ * Pass as NULL ++ */ ++ ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0); ++ switch (ret) { ++ case WMF_TAKEN: ++ case WMF_DROP: ++ /* Either taken by WMF or we should drop it. ++ * Exiting send path ++ */ ++ ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); ++ dhd_os_busbusy_wake(&dhd->pub); ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return NETDEV_TX_OK; ++ default: ++ /* Continue the transmit path */ ++ break; ++ } ++ } ++ } ++#endif /* DHD_WMF */ ++#ifdef DHD_PSTA ++ /* PSR related packet proto manipulation should be done in DHD ++ * since dongle doesn't have complete payload ++ */ ++ if (PSR_ENABLED(&dhd->pub) && (dhd_psta_proc(&dhd->pub, ++ ifidx, &pktbuf, TRUE) < 0)) { ++ DHD_ERROR(("%s:%s: psta send proc failed\n", __FUNCTION__, ++ dhd_ifname(&dhd->pub, ifidx))); ++ } ++#endif /* DHD_PSTA */ ++ ++#ifdef DHDTCPACK_SUPPRESS ++ if (dhd->pub.tcpack_sup_mode == TCPACK_SUP_HOLD) { ++ /* If this packet has been hold or got freed, just return */ ++ if (dhd_tcpack_hold(&dhd->pub, pktbuf, ifidx)) { ++ ret = 0; ++ goto done; ++ } ++ } else { ++ /* If this packet has replaced another packet and got freed, just return */ ++ if (dhd_tcpack_suppress(&dhd->pub, pktbuf)) { ++ ret = 0; ++ goto done; ++ } ++ } ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++ /* ++ * If Load Balance is enabled queue the packet ++ * else send directly from here. ++ */ ++#if defined(DHD_LB_TXP) ++ ret = dhd_lb_sendpkt(dhd, net, ifidx, pktbuf); ++#else ++ ret = __dhd_sendpkt(&dhd->pub, ifidx, pktbuf); ++#endif ++ ++done: ++ if (ret) { ++ ifp->stats.tx_dropped++; ++ dhd->pub.tx_dropped++; ++ } else { ++#ifdef PROP_TXSTATUS ++ /* tx_packets counter can counted only when wlfc is disabled */ ++ if (!dhd_wlfc_is_supported(&dhd->pub)) ++#endif ++ { ++ dhd->pub.tx_packets++; ++ ifp->stats.tx_packets++; ++ ifp->stats.tx_bytes += datalen; ++ } ++ } ++ ++ ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); ++ dhd_os_busbusy_wake(&dhd->pub); ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ /* Return ok: we always eat the packet */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ return 0; ++#else ++ return NETDEV_TX_OK; ++#endif ++} ++ ++ ++void ++dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) ++{ ++ struct net_device *net; ++ dhd_info_t *dhd = dhdp->info; ++ int i; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ ASSERT(dhd); ++ ++#ifdef DHD_LOSSLESS_ROAMING ++ /* block flowcontrol during roaming */ ++ if ((dhdp->dequeue_prec_map == 1 << PRIO_8021D_NC) && state == ON) { ++ return; ++ } ++#endif ++ ++ if (ifidx == ALL_INTERFACES) { ++ /* Flow control on all active interfaces */ ++ dhdp->txoff = state; ++ for (i = 0; i < DHD_MAX_IFS; i++) { ++ if (dhd->iflist[i]) { ++ net = dhd->iflist[i]->net; ++ if (state == ON) ++ netif_stop_queue(net); ++ else ++ netif_wake_queue(net); ++ } ++ } ++ } else { ++ if (dhd->iflist[ifidx]) { ++ net = dhd->iflist[ifidx]->net; ++ if (state == ON) ++ netif_stop_queue(net); ++ else ++ netif_wake_queue(net); ++ } ++ } ++} ++ ++ ++#ifdef DHD_WMF ++bool ++dhd_is_rxthread_enabled(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ ++ return dhd->rxthread_enabled; ++} ++#endif /* DHD_WMF */ ++ ++#ifdef DHD_MCAST_REGEN ++/* ++ * Description: This function is called to do the reverse translation ++ * ++ * Input eh - pointer to the ethernet header ++ */ ++int32 ++dhd_mcast_reverse_translation(struct ether_header *eh) ++{ ++ uint8 *iph; ++ uint32 dest_ip; ++ ++ iph = (uint8 *)eh + ETHER_HDR_LEN; ++ dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET))); ++ ++ /* Only IP packets are handled */ ++ if (eh->ether_type != hton16(ETHER_TYPE_IP)) ++ return BCME_ERROR; ++ ++ /* Non-IPv4 multicast packets are not handled */ ++ if (IP_VER(iph) != IP_VER_4) ++ return BCME_ERROR; ++ ++ /* ++ * The packet has a multicast IP and unicast MAC. That means ++ * we have to do the reverse translation ++ */ ++ if (IPV4_ISMULTI(dest_ip) && !ETHER_ISMULTI(&eh->ether_dhost)) { ++ ETHER_FILL_MCAST_ADDR_FROM_IP(eh->ether_dhost, dest_ip); ++ return BCME_OK; ++ } ++ ++ return BCME_ERROR; ++} ++#endif /* MCAST_REGEN */ ++ ++#ifdef SHOW_LOGTRACE ++static int ++dhd_event_logtrace_pkt_process(dhd_pub_t *dhdp, struct sk_buff * skb) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ int ret = BCME_OK; ++ uint datalen; ++ bcm_event_msg_u_t evu; ++ void *data = NULL; ++ void *pktdata = NULL; ++ bcm_event_t *pvt_data; ++ uint pktlen; ++ ++ DHD_TRACE(("%s:Enter\n", __FUNCTION__)); ++ ++ /* In dhd_rx_frame, header is stripped using skb_pull ++ * of size ETH_HLEN, so adjust pktlen accordingly ++ */ ++ pktlen = skb->len + ETH_HLEN; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++ pktdata = (void *)skb_mac_header(skb); ++#else ++ pktdata = (void *)skb->mac.raw; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ ++ ++ ret = wl_host_event_get_data(pktdata, pktlen, &evu); ++ ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s: wl_host_event_get_data err = %d\n", ++ __FUNCTION__, ret)); ++ goto exit; ++ } ++ ++ datalen = ntoh32(evu.event.datalen); ++ ++ pvt_data = (bcm_event_t *)pktdata; ++ data = &pvt_data[1]; ++ ++ dhd_dbg_trace_evnt_handler(dhdp, data, &dhd->event_data, datalen); ++ ++exit: ++ return ret; ++} ++ ++static void ++dhd_event_logtrace_process(struct work_struct * work) ++{ ++/* Ignore compiler warnings due to -Werror=cast-qual */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ struct dhd_info *dhd = ++ container_of(work, struct dhd_info, event_log_dispatcher_work); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ ++ dhd_pub_t *dhdp; ++ struct sk_buff *skb; ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); ++ return; ++ } ++ ++ dhdp = &dhd->pub; ++ ++ if (!dhdp) { ++ DHD_ERROR(("%s: dhd pub is null \n", __FUNCTION__)); ++ return; ++ } ++ ++ DHD_TRACE(("%s:Enter\n", __FUNCTION__)); ++ ++ /* Run while(1) loop till all skbs are dequeued */ ++ while ((skb = skb_dequeue(&dhd->evt_trace_queue)) != NULL) { ++#ifdef PCIE_FULL_DONGLE ++ int ifid; ++ ifid = DHD_PKTTAG_IFID((dhd_pkttag_fr_t *)PKTTAG(skb)); ++ if (ifid == DHD_EVENT_IF) { ++ dhd_event_logtrace_infobuf_pkt_process(dhdp, skb, &dhd->event_data); ++ /* For sending skb to network layer, convert it to Native PKT ++ * after that assign skb->dev with Primary interface n/w device ++ * as for infobuf events, we are sending special DHD_EVENT_IF ++ */ ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhdp->osh, skb, FALSE); ++#else ++ PKTFREE(dhdp->osh, skb, FALSE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ continue; ++ } ++ else { ++ dhd_event_logtrace_pkt_process(dhdp, skb); ++ } ++#else ++ dhd_event_logtrace_pkt_process(dhdp, skb); ++#endif /* PCIE_FULL_DONGLE */ ++ ++ /* Free skb buffer here if DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT ++ * macro is defined the Info Ring event and WLC_E_TRACE event is freed in DHD ++ * else it is always sent up to network layers. ++ */ ++#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhdp->osh, skb, FALSE); ++#else ++ PKTFREE(dhdp->osh, skb, FALSE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++#else /* !DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ ++ /* Do not call netif_recieve_skb as this workqueue scheduler is not from NAPI ++ * Also as we are not in INTR context, do not call netif_rx, instead call ++ * netif_rx_ni (for kerenl >= 2.6) which does netif_rx, disables irq, raise ++ * NET_IF_RX softirq and enables interrupts back ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ netif_rx_ni(skb); ++#else ++ { ++ ulong flags; ++ netif_rx(skb); ++ local_irq_save(flags); ++ RAISE_RX_SOFTIRQ(); ++ local_irq_restore(flags); ++ } ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ ++#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ ++ } ++} ++ ++void ++dhd_event_logtrace_enqueue(dhd_pub_t *dhdp, int ifidx, void *pktbuf) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ ++#ifdef PCIE_FULL_DONGLE ++ /* Add ifidx in the PKTTAG */ ++ DHD_PKTTAG_SET_IFID((dhd_pkttag_fr_t *)PKTTAG(pktbuf), ifidx); ++#endif /* PCIE_FULL_DONGLE */ ++ skb_queue_tail(&dhd->evt_trace_queue, pktbuf); ++ ++ schedule_work(&dhd->event_log_dispatcher_work); ++} ++ ++void ++dhd_event_logtrace_flush_queue(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ struct sk_buff *skb; ++ ++ while ((skb = skb_dequeue(&dhd->evt_trace_queue)) != NULL) { ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhdp->osh, skb, FALSE); ++#else ++ PKTFREE(dhdp->osh, skb, FALSE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ } ++} ++#endif /* SHOW_LOGTRACE */ ++ ++/** Called when a frame is received by the dongle on interface 'ifidx' */ ++void ++dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ struct sk_buff *skb; ++ uchar *eth; ++ uint len; ++ void *data, *pnext = NULL; ++ int i; ++ dhd_if_t *ifp; ++ wl_event_msg_t event; ++ int tout_rx = 0; ++ int tout_ctrl = 0; ++ void *skbhead = NULL; ++ void *skbprev = NULL; ++ uint16 protocol; ++ unsigned char *dump_data; ++#ifdef DHD_MCAST_REGEN ++ uint8 interface_role; ++ if_flow_lkup_t *if_flow_lkup; ++ unsigned long flags; ++#endif ++#ifdef DHD_WAKE_STATUS ++ int pkt_wake = 0; ++ wake_counts_t *wcp = NULL; ++#endif /* DHD_WAKE_STATUS */ ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { ++ struct ether_header *eh; ++ ++ pnext = PKTNEXT(dhdp->osh, pktbuf); ++ PKTSETNEXT(dhdp->osh, pktbuf, NULL); ++ ++ /* info ring "debug" data, which is not a 802.3 frame, is sent/hacked with a ++ * special ifidx of DHD_EVENT_IF. This is just internal to dhd to get the data from ++ * dhd_msgbuf.c:dhd_prot_infobuf_cmplt_process() to here (dhd_rx_frame). ++ */ ++ if (ifidx == DHD_EVENT_IF) { ++ /* Event msg printing is called from dhd_rx_frame which is in Tasklet ++ * context in case of PCIe FD, in case of other bus this will be from ++ * DPC context. If we get bunch of events from Dongle then printing all ++ * of them from Tasklet/DPC context that too in data path is costly. ++ * Also in the new Dongle SW(4359, 4355 onwards) console prints too come as ++ * events with type WLC_E_TRACE. ++ * We'll print this console logs from the WorkQueue context by enqueing SKB ++ * here and Dequeuing will be done in WorkQueue and will be freed only if ++ * DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT is defined ++ */ ++#ifdef SHOW_LOGTRACE ++ dhd_event_logtrace_enqueue(dhdp, ifidx, pktbuf); ++#else /* !SHOW_LOGTRACE */ ++ /* If SHOW_LOGTRACE not defined and ifidx is DHD_EVENT_IF, ++ * free the PKT here itself ++ */ ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); ++#else ++ PKTFREE(dhdp->osh, pktbuf, FALSE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++#endif /* SHOW_LOGTRACE */ ++ continue; ++ } ++#ifdef DHD_WAKE_STATUS ++#ifdef BCMDBUS ++ wcp = NULL; ++#else ++ pkt_wake = dhd_bus_get_bus_wake(dhdp); ++ wcp = dhd_bus_get_wakecount(dhdp); ++#endif /* BCMDBUS */ ++ if (wcp == NULL) { ++ /* If wakeinfo count buffer is null do not update wake count values */ ++ pkt_wake = 0; ++ } ++#endif /* DHD_WAKE_STATUS */ ++ ++ ifp = dhd->iflist[ifidx]; ++ if (ifp == NULL) { ++ DHD_ERROR(("%s: ifp is NULL. drop packet\n", ++ __FUNCTION__)); ++ PKTCFREE(dhdp->osh, pktbuf, FALSE); ++ continue; ++ } ++ ++ eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); ++ ++ /* Dropping only data packets before registering net device to avoid kernel panic */ ++#ifndef PROP_TXSTATUS_VSDB ++ if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) && ++ (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) ++#else ++ if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) && ++ (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) ++#endif /* PROP_TXSTATUS_VSDB */ ++ { ++ DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", ++ __FUNCTION__)); ++ PKTCFREE(dhdp->osh, pktbuf, FALSE); ++ continue; ++ } ++ ++#ifdef PROP_TXSTATUS ++ if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) { ++ /* WLFC may send header only packet when ++ there is an urgent message but no packet to ++ piggy-back on ++ */ ++ PKTCFREE(dhdp->osh, pktbuf, FALSE); ++ continue; ++ } ++#endif ++#ifdef DHD_L2_FILTER ++ /* If block_ping is enabled drop the ping packet */ ++ if (ifp->block_ping) { ++ if (bcm_l2_filter_block_ping(dhdp->osh, pktbuf) == BCME_OK) { ++ PKTCFREE(dhdp->osh, pktbuf, FALSE); ++ continue; ++ } ++ } ++ if (ifp->grat_arp && DHD_IF_ROLE_STA(dhdp, ifidx)) { ++ if (bcm_l2_filter_gratuitous_arp(dhdp->osh, pktbuf) == BCME_OK) { ++ PKTCFREE(dhdp->osh, pktbuf, FALSE); ++ continue; ++ } ++ } ++ if (ifp->parp_enable && DHD_IF_ROLE_AP(dhdp, ifidx)) { ++ int ret = dhd_l2_filter_pkt_handle(dhdp, ifidx, pktbuf, FALSE); ++ ++ /* Drop the packets if l2 filter has processed it already ++ * otherwise continue with the normal path ++ */ ++ if (ret == BCME_OK) { ++ PKTCFREE(dhdp->osh, pktbuf, TRUE); ++ continue; ++ } ++ } ++#endif /* DHD_L2_FILTER */ ++ ++#ifdef DHD_MCAST_REGEN ++ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); ++ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; ++ ASSERT(if_flow_lkup); ++ ++ interface_role = if_flow_lkup[ifidx].role; ++ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); ++ ++ if (ifp->mcast_regen_bss_enable && (interface_role != WLC_E_IF_ROLE_WDS) && ++ !DHD_IF_ROLE_AP(dhdp, ifidx) && ++ ETHER_ISUCAST(eh->ether_dhost)) { ++ if (dhd_mcast_reverse_translation(eh) == BCME_OK) { ++#ifdef DHD_PSTA ++ /* Change bsscfg to primary bsscfg for unicast-multicast packets */ ++ if ((dhd_get_psta_mode(dhdp) == DHD_MODE_PSTA) || ++ (dhd_get_psta_mode(dhdp) == DHD_MODE_PSR)) { ++ if (ifidx != 0) { ++ /* Let the primary in PSTA interface handle this ++ * frame after unicast to Multicast conversion ++ */ ++ ifp = dhd_get_ifp(dhdp, 0); ++ ASSERT(ifp); ++ } ++ } ++ } ++#endif /* PSTA */ ++ } ++#endif /* MCAST_REGEN */ ++ ++#ifdef DHD_WMF ++ /* WMF processing for multicast packets */ ++ if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) { ++ dhd_sta_t *sta; ++ int ret; ++ ++ sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost); ++ ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1); ++ switch (ret) { ++ case WMF_TAKEN: ++ /* The packet is taken by WMF. Continue to next iteration */ ++ continue; ++ case WMF_DROP: ++ /* Packet DROP decision by WMF. Toss it */ ++ DHD_ERROR(("%s: WMF decides to drop packet\n", ++ __FUNCTION__)); ++ PKTCFREE(dhdp->osh, pktbuf, FALSE); ++ continue; ++ default: ++ /* Continue the transmit path */ ++ break; ++ } ++ } ++#endif /* DHD_WMF */ ++ ++#ifdef DHDTCPACK_SUPPRESS ++ dhd_tcpdata_info_get(dhdp, pktbuf); ++#endif ++ skb = PKTTONATIVE(dhdp->osh, pktbuf); ++ ++ ASSERT(ifp); ++ skb->dev = ifp->net; ++#ifdef DHD_WET ++ /* wet related packet proto manipulation should be done in DHD ++ * since dongle doesn't have complete payload ++ */ ++ if (WET_ENABLED(&dhd->pub) && (dhd_wet_recv_proc(dhd->pub.wet_info, ++ pktbuf) < 0)) { ++ DHD_INFO(("%s:%s: wet recv proc failed\n", ++ __FUNCTION__, dhd_ifname(dhdp, ifidx))); ++ } ++#endif /* DHD_WET */ ++ ++#ifdef DHD_PSTA ++ if (PSR_ENABLED(dhdp) && (dhd_psta_proc(dhdp, ifidx, &pktbuf, FALSE) < 0)) { ++ DHD_ERROR(("%s:%s: psta recv proc failed\n", __FUNCTION__, ++ dhd_ifname(dhdp, ifidx))); ++ } ++#endif /* DHD_PSTA */ ++ ++#ifdef PCIE_FULL_DONGLE ++ if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) && ++ (!ifp->ap_isolate)) { ++ eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); ++ if (ETHER_ISUCAST(eh->ether_dhost)) { ++ if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) { ++ dhd_sendpkt(dhdp, ifidx, pktbuf); ++ continue; ++ } ++ } else { ++ void *npktbuf = PKTDUP(dhdp->osh, pktbuf); ++ if (npktbuf) ++ dhd_sendpkt(dhdp, ifidx, npktbuf); ++ } ++ } ++#endif /* PCIE_FULL_DONGLE */ ++ ++ /* Get the protocol, maintain skb around eth_type_trans() ++ * The main reason for this hack is for the limitation of ++ * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len' ++ * to perform skb_pull inside vs ETH_HLEN. Since to avoid ++ * coping of the packet coming from the network stack to add ++ * BDC, Hardware header etc, during network interface registration ++ * we set the 'net->hard_header_len' to ETH_HLEN + extra space required ++ * for BDC, Hardware header etc. and not just the ETH_HLEN ++ */ ++ eth = skb->data; ++ len = skb->len; ++ ++ dump_data = skb->data; ++ ++ protocol = (skb->data[12] << 8) | skb->data[13]; ++ if (protocol == ETHER_TYPE_802_1X) { ++ DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED); ++ dhd_dump_eapol_4way_message(dhdp, dhd_ifname(dhdp, ifidx), dump_data, FALSE); ++ } ++ ++ if (protocol != ETHER_TYPE_BRCM && protocol == ETHER_TYPE_IP) { ++#ifdef DHD_DHCP_DUMP ++ dhd_dhcp_dump(dhd_ifname(dhdp, ifidx), dump_data, FALSE); ++#endif /* DHD_DHCP_DUMP */ ++#ifdef DHD_ICMP_DUMP ++ dhd_icmp_dump(dhd_ifname(dhdp, ifidx), dump_data, FALSE); ++#endif /* DHD_ICMP_DUMP */ ++ } ++#ifdef DHD_ARP_DUMP ++ if (ntoh16(eh->ether_type) == ETHER_TYPE_ARP) { ++ dhd_arp_dump(dhd_ifname(dhdp, ifidx), dump_data, FALSE); ++ } ++#endif /* DHD_ARP_DUMP */ ++#ifdef DHD_RX_DUMP ++ dhd_trx_dump(dhd_idx2net(dhdp, ifidx), dump_data, skb->len, FALSE); ++#endif /* DHD_RX_DUMP */ ++#if defined(DHD_WAKE_STATUS) && defined(DHD_WAKEPKT_DUMP) ++ if (pkt_wake) { ++ prhex("[wakepkt_dump]", (char*)dump_data, MIN(len, 32)); ++ } ++#endif /* DHD_WAKE_STATUS && DHD_WAKEPKT_DUMP */ ++ ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ if (skb->pkt_type == PACKET_MULTICAST) { ++ dhd->pub.rx_multicast++; ++ ifp->stats.multicast++; ++ } ++ ++ skb->data = eth; ++ skb->len = len; ++ ++#ifdef WLMEDIA_HTSF ++ dhd_htsf_addrxts(dhdp, pktbuf); ++#endif ++#ifdef DBG_PKT_MON ++ DHD_DBG_PKT_MON_RX(dhdp, skb); ++#endif /* DBG_PKT_MON */ ++#ifdef DHD_PKT_LOGGING ++ DHD_PKTLOG_RX(dhdp, skb); ++#endif /* DHD_PKT_LOGGING */ ++ /* Strip header, count, deliver upward */ ++ skb_pull(skb, ETH_HLEN); ++ ++ /* Process special event packets and then discard them */ ++ memset(&event, 0, sizeof(event)); ++ ++ if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { ++ bcm_event_msg_u_t evu; ++ int ret_event; ++ int event_type; ++ ++ ret_event = wl_host_event_get_data( ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++ skb_mac_header(skb), ++#else ++ skb->mac.raw, ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ ++ len, &evu); ++ ++ if (ret_event != BCME_OK) { ++ DHD_ERROR(("%s: wl_host_event_get_data err = %d\n", ++ __FUNCTION__, ret_event)); ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); ++#else ++ PKTFREE(dhdp->osh, pktbuf, FALSE); ++#endif ++ continue; ++ } ++ ++ memcpy(&event, &evu.event, sizeof(wl_event_msg_t)); ++ event_type = ntoh32_ua((void *)&event.event_type); ++#ifdef SHOW_LOGTRACE ++ /* Event msg printing is called from dhd_rx_frame which is in Tasklet ++ * context in case of PCIe FD, in case of other bus this will be from ++ * DPC context. If we get bunch of events from Dongle then printing all ++ * of them from Tasklet/DPC context that too in data path is costly. ++ * Also in the new Dongle SW(4359, 4355 onwards) console prints too come as ++ * events with type WLC_E_TRACE. ++ * We'll print this console logs from the WorkQueue context by enqueing SKB ++ * here and Dequeuing will be done in WorkQueue and will be freed only if ++ * DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT is defined ++ */ ++ if (event_type == WLC_E_TRACE) { ++ DHD_TRACE(("%s: WLC_E_TRACE\n", __FUNCTION__)); ++ dhd_event_logtrace_enqueue(dhdp, ifidx, pktbuf); ++ continue; ++ } ++#endif /* SHOW_LOGTRACE */ ++ ++ ret_event = dhd_wl_host_event(dhd, ifidx, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++ skb_mac_header(skb), ++#else ++ skb->mac.raw, ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ ++ len, &event, &data); ++ ++ wl_event_to_host_order(&event); ++ if (!tout_ctrl) ++ tout_ctrl = DHD_PACKET_TIMEOUT_MS; ++ ++#if defined(PNO_SUPPORT) ++ if (event_type == WLC_E_PFN_NET_FOUND) { ++ /* enforce custom wake lock to garantee that Kernel not suspended */ ++ tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; ++ } ++#endif /* PNO_SUPPORT */ ++ if (numpkt != 1) { ++ DHD_TRACE(("%s: Got BRCM event packet in a chained packet.\n", ++ __FUNCTION__)); ++ } ++ ++#ifdef DHD_WAKE_STATUS ++ if (unlikely(pkt_wake)) { ++#ifdef DHD_WAKE_EVENT_STATUS ++ if (event.event_type < WLC_E_LAST) { ++ wcp->rc_event[event.event_type]++; ++ wcp->rcwake++; ++ pkt_wake = 0; ++ } ++#endif /* DHD_WAKE_EVENT_STATUS */ ++ } ++#endif /* DHD_WAKE_STATUS */ ++ ++ /* For delete virtual interface event, wl_host_event returns positive ++ * i/f index, do not proceed. just free the pkt. ++ */ ++ if ((event_type == WLC_E_IF) && (ret_event > 0)) { ++ DHD_ERROR(("%s: interface is deleted. Free event packet\n", ++ __FUNCTION__)); ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); ++#else ++ PKTFREE(dhdp->osh, pktbuf, FALSE); ++#endif ++ continue; ++ } ++ ++#if defined(DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT) && !defined(SENDPROB) ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); ++#else ++ PKTFREE(dhdp->osh, pktbuf, FALSE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ continue; ++#else ++#ifdef SENDPROB ++ if (!dhdp->recv_probereq || (event.event_type != WLC_E_PROBREQ_MSG)) { ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); ++#else ++ PKTFREE(dhdp->osh, pktbuf, FALSE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ continue; ++ } ++#endif ++ /* ++ * For the event packets, there is a possibility ++ * of ifidx getting modifed.Thus update the ifp ++ * once again. ++ */ ++ ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); ++ ifp = dhd->iflist[ifidx]; ++#ifndef PROP_TXSTATUS_VSDB ++ if (!(ifp && ifp->net && (ifp->net->reg_state == NETREG_REGISTERED))) ++#else ++ if (!(ifp && ifp->net && (ifp->net->reg_state == NETREG_REGISTERED) && ++ dhd->pub.up)) ++#endif /* PROP_TXSTATUS_VSDB */ ++ { ++ DHD_ERROR(("%s: net device is NOT registered. drop event packet\n", ++ __FUNCTION__)); ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); ++#else ++ PKTFREE(dhdp->osh, pktbuf, FALSE); ++#endif ++ continue; ++ } ++#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ ++ } else { ++ tout_rx = DHD_PACKET_TIMEOUT_MS; ++ ++#ifdef PROP_TXSTATUS ++ dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb)); ++#endif /* PROP_TXSTATUS */ ++ ++#ifdef DHD_WAKE_STATUS ++ if (unlikely(pkt_wake)) { ++ wcp->rxwake++; ++#ifdef DHD_WAKE_RX_STATUS ++#define ETHER_ICMP6_HEADER 20 ++#define ETHER_IPV6_SADDR (ETHER_ICMP6_HEADER + 2) ++#define ETHER_IPV6_DAADR (ETHER_IPV6_SADDR + IPV6_ADDR_LEN) ++#define ETHER_ICMPV6_TYPE (ETHER_IPV6_DAADR + IPV6_ADDR_LEN) ++ ++ if (ntoh16(skb->protocol) == ETHER_TYPE_ARP) /* ARP */ ++ wcp->rx_arp++; ++ if (dump_data[0] == 0xFF) { /* Broadcast */ ++ wcp->rx_bcast++; ++ } else if (dump_data[0] & 0x01) { /* Multicast */ ++ wcp->rx_mcast++; ++ if (ntoh16(skb->protocol) == ETHER_TYPE_IPV6) { ++ wcp->rx_multi_ipv6++; ++ if ((skb->len > ETHER_ICMP6_HEADER) && ++ (dump_data[ETHER_ICMP6_HEADER] == IPPROTO_ICMPV6)) { ++ wcp->rx_icmpv6++; ++ if (skb->len > ETHER_ICMPV6_TYPE) { ++ switch (dump_data[ETHER_ICMPV6_TYPE]) { ++ case NDISC_ROUTER_ADVERTISEMENT: ++ wcp->rx_icmpv6_ra++; ++ break; ++ case NDISC_NEIGHBOUR_ADVERTISEMENT: ++ wcp->rx_icmpv6_na++; ++ break; ++ case NDISC_NEIGHBOUR_SOLICITATION: ++ wcp->rx_icmpv6_ns++; ++ break; ++ } ++ } ++ } ++ } else if (dump_data[2] == 0x5E) { ++ wcp->rx_multi_ipv4++; ++ } else { ++ wcp->rx_multi_other++; ++ } ++ } else { /* Unicast */ ++ wcp->rx_ucast++; ++ } ++#undef ETHER_ICMP6_HEADER ++#undef ETHER_IPV6_SADDR ++#undef ETHER_IPV6_DAADR ++#undef ETHER_ICMPV6_TYPE ++#endif /* DHD_WAKE_RX_STATUS */ ++ pkt_wake = 0; ++ } ++#endif /* DHD_WAKE_STATUS */ ++ } ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) ++ if (ifp->net) ++ ifp->net->last_rx = jiffies; ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) */ ++ ++ if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { ++ dhdp->dstats.rx_bytes += skb->len; ++ dhdp->rx_packets++; /* Local count */ ++ ifp->stats.rx_bytes += skb->len; ++ ifp->stats.rx_packets++; ++ } ++ ++ if (in_interrupt()) { ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, ++ __FUNCTION__, __LINE__); ++ DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++#if defined(DHD_LB_RXP) ++ netif_receive_skb(skb); ++#else /* !defined(DHD_LB_RXP) */ ++ netif_rx(skb); ++#endif /* !defined(DHD_LB_RXP) */ ++ DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++ } else { ++ if (dhd->rxthread_enabled) { ++ if (!skbhead) ++ skbhead = skb; ++ else ++ PKTSETNEXT(dhdp->osh, skbprev, skb); ++ skbprev = skb; ++ } 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 ++ * by netif_rx_ni(), but in earlier kernels, we need ++ * to do it manually. ++ */ ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, ++ __FUNCTION__, __LINE__); ++ ++#if defined(DHD_LB_RXP) ++ DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++ netif_receive_skb(skb); ++ DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++#else /* !defined(DHD_LB_RXP) */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++ netif_rx_ni(skb); ++ DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++#else ++ ulong flags; ++ DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++ netif_rx(skb); ++ DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++ local_irq_save(flags); ++ RAISE_RX_SOFTIRQ(); ++ local_irq_restore(flags); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ ++#endif /* !defined(DHD_LB_RXP) */ ++ } ++ } ++ } ++ ++ if (dhd->rxthread_enabled && skbhead) ++ dhd_sched_rxf(dhdp, skbhead); ++ ++ DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); ++ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); ++} ++ ++void ++dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) ++{ ++ /* Linux version has nothing to do */ ++ return; ++} ++ ++void ++dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); ++ struct ether_header *eh; ++ uint16 type; ++ ++ dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); ++ ++ ++ eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); ++ type = ntoh16(eh->ether_type); ++ ++ if ((type == ETHER_TYPE_802_1X) && (dhd_get_pend_8021x_cnt(dhd) > 0)) { ++ atomic_dec(&dhd->pend_8021x_cnt); ++ } ++ ++#ifdef PROP_TXSTATUS ++ if (dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) { ++ dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))]; ++ uint datalen = PKTLEN(dhd->pub.osh, txp); ++ if (ifp != NULL) { ++ if (success) { ++ dhd->pub.tx_packets++; ++ ifp->stats.tx_packets++; ++ ifp->stats.tx_bytes += datalen; ++ } else { ++ ifp->stats.tx_dropped++; ++ } ++ } ++ } ++#endif ++} ++ ++static struct net_device_stats * ++dhd_get_stats(struct net_device *net) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(net); ++ dhd_if_t *ifp; ++ int ifidx; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (!dhd) { ++ DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); ++ goto error; ++ } ++ ++ ifidx = dhd_net2idx(dhd, net); ++ if (ifidx == DHD_BAD_IF) { ++ DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__)); ++ goto error; ++ } ++ ++ ifp = dhd->iflist[ifidx]; ++ ++ if (!ifp) { ++ ASSERT(ifp); ++ DHD_ERROR(("%s: ifp is NULL\n", __FUNCTION__)); ++ goto error; ++ } ++ ++ if (dhd->pub.up) { ++ /* Use the protocol to get dongle stats */ ++ dhd_prot_dstats(&dhd->pub); ++ } ++ return &ifp->stats; ++ ++error: ++ memset(&net->stats, 0, sizeof(net->stats)); ++ return &net->stats; ++} ++ ++#ifndef BCMDBUS ++static int ++dhd_watchdog_thread(void *data) ++{ ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; ++ /* This thread doesn't need any user-level access, ++ * so get rid of all our resources ++ */ ++ if (dhd_watchdog_prio > 0) { ++ struct sched_param param; ++ param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? ++ dhd_watchdog_prio:(MAX_RT_PRIO-1); ++ setScheduler(current, SCHED_FIFO, ¶m); ++ } ++ ++ while (1) { ++ if (down_interruptible (&tsk->sema) == 0) { ++ unsigned long flags; ++ unsigned long jiffies_at_start = jiffies; ++ unsigned long time_lapse; ++ DHD_OS_WD_WAKE_LOCK(&dhd->pub); ++ ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) { ++ break; ++ } ++ ++ if (dhd->pub.dongle_reset == FALSE) { ++ DHD_TIMER(("%s:\n", __FUNCTION__)); ++ dhd_bus_watchdog(&dhd->pub); ++ ++#ifdef DHD_TIMESYNC ++ /* Call the timesync module watchdog */ ++ dhd_timesync_watchdog(&dhd->pub); ++#endif /* DHD_TIMESYNC */ ++ ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ /* Count the tick for reference */ ++ dhd->pub.tickcnt++; ++#ifdef DHD_L2_FILTER ++ dhd_l2_filter_watchdog(&dhd->pub); ++#endif /* DHD_L2_FILTER */ ++ time_lapse = jiffies - jiffies_at_start; ++ ++ /* Reschedule the watchdog */ ++ if (dhd->wd_timer_valid) { ++ mod_timer(&dhd->timer, ++ jiffies + ++ msecs_to_jiffies(dhd_watchdog_ms) - ++ min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse)); ++ } ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ } ++ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); ++ } else { ++ break; ++ } ++ } ++ ++ complete_and_exit(&tsk->completed, 0); ++} ++ ++static void dhd_watchdog(ulong data) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)data; ++ unsigned long flags; ++ ++ if (dhd->pub.dongle_reset) { ++ return; ++ } ++ ++ if (dhd->thr_wdt_ctl.thr_pid >= 0) { ++ up(&dhd->thr_wdt_ctl.sema); ++ return; ++ } ++ ++ DHD_OS_WD_WAKE_LOCK(&dhd->pub); ++ /* Call the bus module watchdog */ ++ dhd_bus_watchdog(&dhd->pub); ++ ++#ifdef DHD_TIMESYNC ++ /* Call the timesync module watchdog */ ++ dhd_timesync_watchdog(&dhd->pub); ++#endif /* DHD_TIMESYNC */ ++ ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ /* Count the tick for reference */ ++ dhd->pub.tickcnt++; ++ ++#ifdef DHD_L2_FILTER ++ dhd_l2_filter_watchdog(&dhd->pub); ++#endif /* DHD_L2_FILTER */ ++ /* Reschedule the watchdog */ ++ if (dhd->wd_timer_valid) ++ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); ++} ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++static int ++dhd_rpm_state_thread(void *data) ++{ ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; ++ ++ while (1) { ++ if (down_interruptible (&tsk->sema) == 0) { ++ unsigned long flags; ++ unsigned long jiffies_at_start = jiffies; ++ unsigned long time_lapse; ++ ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) { ++ break; ++ } ++ ++ if (dhd->pub.dongle_reset == FALSE) { ++ DHD_TIMER(("%s:\n", __FUNCTION__)); ++ if (dhd->pub.up) { ++ dhd_runtimepm_state(&dhd->pub); ++ } ++ ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ time_lapse = jiffies - jiffies_at_start; ++ ++ /* Reschedule the watchdog */ ++ if (dhd->rpm_timer_valid) { ++ mod_timer(&dhd->rpm_timer, ++ jiffies + ++ msecs_to_jiffies(dhd_runtimepm_ms) - ++ min(msecs_to_jiffies(dhd_runtimepm_ms), ++ time_lapse)); ++ } ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ } ++ } else { ++ break; ++ } ++ } ++ ++ complete_and_exit(&tsk->completed, 0); ++} ++ ++static void dhd_runtimepm(ulong data) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)data; ++ ++ if (dhd->pub.dongle_reset) { ++ return; ++ } ++ ++ if (dhd->thr_rpm_ctl.thr_pid >= 0) { ++ up(&dhd->thr_rpm_ctl.sema); ++ return; ++ } ++} ++ ++void dhd_runtime_pm_disable(dhd_pub_t *dhdp) ++{ ++ dhd_os_runtimepm_timer(dhdp, 0); ++ dhdpcie_runtime_bus_wake(dhdp, TRUE, __builtin_return_address(0)); ++ DHD_ERROR(("DHD Runtime PM Disabled \n")); ++} ++ ++void dhd_runtime_pm_enable(dhd_pub_t *dhdp) ++{ ++ if (dhd_get_idletime(dhdp)) { ++ dhd_os_runtimepm_timer(dhdp, dhd_runtimepm_ms); ++ DHD_ERROR(("DHD Runtime PM Enabled \n")); ++ } ++} ++ ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ ++#ifdef ENABLE_ADAPTIVE_SCHED ++static void ++dhd_sched_policy(int prio) ++{ ++ struct sched_param param; ++ if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) { ++ param.sched_priority = 0; ++ setScheduler(current, SCHED_NORMAL, ¶m); ++ } else { ++ if (get_scheduler_policy(current) != SCHED_FIFO) { ++ param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1); ++ setScheduler(current, SCHED_FIFO, ¶m); ++ } ++ } ++} ++#endif /* ENABLE_ADAPTIVE_SCHED */ ++#ifdef DEBUG_CPU_FREQ ++static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) ++{ ++ dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans); ++ struct cpufreq_freqs *freq = data; ++ if (dhd) { ++ if (!dhd->new_freq) ++ goto exit; ++ if (val == CPUFREQ_POSTCHANGE) { ++ DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n", ++ freq->new, freq->cpu)); ++ *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new; ++ } ++ } ++exit: ++ return 0; ++} ++#endif /* DEBUG_CPU_FREQ */ ++ ++static int ++dhd_dpc_thread(void *data) ++{ ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; ++ ++ /* This thread doesn't need any user-level access, ++ * so get rid of all our resources ++ */ ++ if (dhd_dpc_prio > 0) ++ { ++ struct sched_param param; ++ param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); ++ setScheduler(current, SCHED_FIFO, ¶m); ++ } ++ ++#ifdef CUSTOM_DPC_CPUCORE ++ set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE)); ++#endif ++#ifdef CUSTOM_SET_CPUCORE ++ dhd->pub.current_dpc = current; ++#endif /* CUSTOM_SET_CPUCORE */ ++ /* Run until signal received */ ++ while (1) { ++ if (dhd->pub.conf->dpc_cpucore >= 0) { ++ printf("%s: set dpc_cpucore %d\n", __FUNCTION__, dhd->pub.conf->dpc_cpucore); ++ set_cpus_allowed_ptr(current, cpumask_of(dhd->pub.conf->dpc_cpucore)); ++ dhd->pub.conf->dpc_cpucore = -1; ++ } ++ if (!binary_sema_down(tsk)) { ++#ifdef ENABLE_ADAPTIVE_SCHED ++ dhd_sched_policy(dhd_dpc_prio); ++#endif /* ENABLE_ADAPTIVE_SCHED */ ++ SMP_RD_BARRIER_DEPENDS(); ++ if (tsk->terminated) { ++ break; ++ } ++ ++ /* Call bus dpc unless it indicated down (then clean stop) */ ++ if (dhd->pub.busstate != DHD_BUS_DOWN) { ++#ifdef DEBUG_DPC_THREAD_WATCHDOG ++ int resched_cnt = 0; ++#endif /* DEBUG_DPC_THREAD_WATCHDOG */ ++ dhd_os_wd_timer_extend(&dhd->pub, TRUE); ++ while (dhd_bus_dpc(dhd->pub.bus)) { ++ /* process all data */ ++#ifdef DEBUG_DPC_THREAD_WATCHDOG ++ resched_cnt++; ++ if (resched_cnt > MAX_RESCHED_CNT) { ++ DHD_INFO(("%s Calling msleep to" ++ "let other processes run. \n", ++ __FUNCTION__)); ++ dhd->pub.dhd_bug_on = true; ++ resched_cnt = 0; ++ OSL_SLEEP(1); ++ } ++#endif /* DEBUG_DPC_THREAD_WATCHDOG */ ++ } ++ dhd_os_wd_timer_extend(&dhd->pub, FALSE); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ } else { ++ if (dhd->pub.up) ++ dhd_bus_stop(dhd->pub.bus, TRUE); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ } ++ } else { ++ break; ++ } ++ } ++ complete_and_exit(&tsk->completed, 0); ++} ++ ++static int ++dhd_rxf_thread(void *data) ++{ ++ tsk_ctl_t *tsk = (tsk_ctl_t *)data; ++ dhd_info_t *dhd = (dhd_info_t *)tsk->parent; ++#if defined(WAIT_DEQUEUE) ++#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */ ++ ulong watchdogTime = OSL_SYSUPTIME(); /* msec */ ++#endif ++ dhd_pub_t *pub = &dhd->pub; ++ ++ /* This thread doesn't need any user-level access, ++ * so get rid of all our resources ++ */ ++ if (dhd_rxf_prio > 0) ++ { ++ struct sched_param param; ++ param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1); ++ setScheduler(current, SCHED_FIFO, ¶m); ++ } ++ ++#ifdef CUSTOM_SET_CPUCORE ++ dhd->pub.current_rxf = current; ++#endif /* CUSTOM_SET_CPUCORE */ ++ /* Run until signal received */ ++ while (1) { ++ if (dhd->pub.conf->rxf_cpucore >= 0) { ++ printf("%s: set rxf_cpucore %d\n", __FUNCTION__, dhd->pub.conf->rxf_cpucore); ++ set_cpus_allowed_ptr(current, cpumask_of(dhd->pub.conf->rxf_cpucore)); ++ dhd->pub.conf->rxf_cpucore = -1; ++ } ++ if (down_interruptible(&tsk->sema) == 0) { ++ void *skb; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) ++ ulong flags; ++#endif ++#ifdef ENABLE_ADAPTIVE_SCHED ++ dhd_sched_policy(dhd_rxf_prio); ++#endif /* ENABLE_ADAPTIVE_SCHED */ ++ ++ SMP_RD_BARRIER_DEPENDS(); ++ ++ if (tsk->terminated) { ++ break; ++ } ++ skb = dhd_rxf_dequeue(pub); ++ ++ if (skb == NULL) { ++ continue; ++ } ++ while (skb) { ++ void *skbnext = PKTNEXT(pub->osh, skb); ++ PKTSETNEXT(pub->osh, skb, NULL); ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, ++ __FUNCTION__, __LINE__); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ netif_rx_ni(skb); ++#else ++ netif_rx(skb); ++ local_irq_save(flags); ++ RAISE_RX_SOFTIRQ(); ++ local_irq_restore(flags); ++ ++#endif ++ skb = skbnext; ++ } ++#if defined(WAIT_DEQUEUE) ++ if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) { ++ OSL_SLEEP(1); ++ watchdogTime = OSL_SYSUPTIME(); ++ } ++#endif ++ ++ DHD_OS_WAKE_UNLOCK(pub); ++ } else { ++ break; ++ } ++ } ++ complete_and_exit(&tsk->completed, 0); ++} ++ ++#ifdef BCMPCIE ++void dhd_dpc_enable(dhd_pub_t *dhdp) ++{ ++#if defined(DHD_LB_RXP) || defined(DHD_LB_TXP) ++ dhd_info_t *dhd; ++ ++ if (!dhdp || !dhdp->info) ++ return; ++ dhd = dhdp->info; ++#endif /* DHD_LB_RXP || DHD_LB_TXP */ ++ ++#ifdef DHD_LB_RXP ++ __skb_queue_head_init(&dhd->rx_pend_queue); ++#endif /* DHD_LB_RXP */ ++ ++#ifdef DHD_LB_TXP ++ skb_queue_head_init(&dhd->tx_pend_queue); ++#endif /* DHD_LB_TXP */ ++} ++#endif /* BCMPCIE */ ++ ++#ifdef BCMPCIE ++void ++dhd_dpc_kill(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ ++ if (!dhdp) { ++ return; ++ } ++ ++ dhd = dhdp->info; ++ ++ if (!dhd) { ++ return; ++ } ++ ++ if (dhd->thr_dpc_ctl.thr_pid < 0) { ++ tasklet_kill(&dhd->tasklet); ++ DHD_ERROR(("%s: tasklet disabled\n", __FUNCTION__)); ++ } ++ ++#ifdef DHD_LB ++#ifdef DHD_LB_RXP ++ cancel_work_sync(&dhd->rx_napi_dispatcher_work); ++ __skb_queue_purge(&dhd->rx_pend_queue); ++#endif /* DHD_LB_RXP */ ++#ifdef DHD_LB_TXP ++ cancel_work_sync(&dhd->tx_dispatcher_work); ++ skb_queue_purge(&dhd->tx_pend_queue); ++#endif /* DHD_LB_TXP */ ++ ++ /* Kill the Load Balancing Tasklets */ ++#if defined(DHD_LB_TXC) ++ tasklet_kill(&dhd->tx_compl_tasklet); ++#endif /* DHD_LB_TXC */ ++#if defined(DHD_LB_RXC) ++ tasklet_kill(&dhd->rx_compl_tasklet); ++#endif /* DHD_LB_RXC */ ++#if defined(DHD_LB_TXP) ++ tasklet_kill(&dhd->tx_tasklet); ++#endif /* DHD_LB_TXP */ ++#endif /* DHD_LB */ ++} ++ ++void ++dhd_dpc_tasklet_kill(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ ++ if (!dhdp) { ++ return; ++ } ++ ++ dhd = dhdp->info; ++ ++ if (!dhd) { ++ return; ++ } ++ ++ if (dhd->thr_dpc_ctl.thr_pid < 0) { ++ tasklet_kill(&dhd->tasklet); ++ } ++} ++#endif /* BCMPCIE */ ++ ++static void ++dhd_dpc(ulong data) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)data; ++ ++ /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] ++ * down below , wake lock is set, ++ * the tasklet is initialized in dhd_attach() ++ */ ++ /* Call bus dpc unless it indicated down (then clean stop) */ ++ if (dhd->pub.busstate != DHD_BUS_DOWN) { ++#if defined(DHD_LB_STATS) && defined(PCIE_FULL_DONGLE) ++ DHD_LB_STATS_INCR(dhd->dhd_dpc_cnt); ++#endif /* DHD_LB_STATS && PCIE_FULL_DONGLE */ ++ if (dhd_bus_dpc(dhd->pub.bus)) { ++ tasklet_schedule(&dhd->tasklet); ++ } ++ } else { ++ dhd_bus_stop(dhd->pub.bus, TRUE); ++ } ++} ++ ++void ++dhd_sched_dpc(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ ++ if (dhd->thr_dpc_ctl.thr_pid >= 0) { ++ DHD_OS_WAKE_LOCK(dhdp); ++ /* If the semaphore does not get up, ++ * wake unlock should be done here ++ */ ++ if (!binary_sema_up(&dhd->thr_dpc_ctl)) { ++ DHD_OS_WAKE_UNLOCK(dhdp); ++ } ++ return; ++ } else { ++ tasklet_schedule(&dhd->tasklet); ++ } ++} ++#endif /* BCMDBUS */ ++ ++static void ++dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++#ifdef RXF_DEQUEUE_ON_BUSY ++ int ret = BCME_OK; ++ int retry = 2; ++#endif /* RXF_DEQUEUE_ON_BUSY */ ++ ++ DHD_OS_WAKE_LOCK(dhdp); ++ ++ DHD_TRACE(("dhd_sched_rxf: Enter\n")); ++#ifdef RXF_DEQUEUE_ON_BUSY ++ do { ++ ret = dhd_rxf_enqueue(dhdp, skb); ++ if (ret == BCME_OK || ret == BCME_ERROR) ++ break; ++ else ++ OSL_SLEEP(50); /* waiting for dequeueing */ ++ } while (retry-- > 0); ++ ++ if (retry <= 0 && ret == BCME_BUSY) { ++ void *skbp = skb; ++ ++ while (skbp) { ++ void *skbnext = PKTNEXT(dhdp->osh, skbp); ++ PKTSETNEXT(dhdp->osh, skbp, NULL); ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, ++ __FUNCTION__, __LINE__); ++ netif_rx_ni(skbp); ++ skbp = skbnext; ++ } ++ DHD_ERROR(("send skb to kernel backlog without rxf_thread\n")); ++ } else { ++ if (dhd->thr_rxf_ctl.thr_pid >= 0) { ++ up(&dhd->thr_rxf_ctl.sema); ++ } ++ } ++#else /* RXF_DEQUEUE_ON_BUSY */ ++ do { ++ if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK) ++ break; ++ } while (1); ++ if (dhd->thr_rxf_ctl.thr_pid >= 0) { ++ up(&dhd->thr_rxf_ctl.sema); ++ } ++ return; ++#endif /* RXF_DEQUEUE_ON_BUSY */ ++} ++ ++#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) ++#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ ++ ++#ifdef TOE ++/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ ++static int ++dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) ++{ ++ char buf[32]; ++ int ret; ++ ++ ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", NULL, 0, (char *)&buf, sizeof(buf), FALSE); ++ ++ if (ret < 0) { ++ if (ret == -EIO) { ++ DHD_ERROR(("%s: toe not supported by device\n", dhd_ifname(&dhd->pub, ++ ifidx))); ++ return -EOPNOTSUPP; ++ } ++ ++ DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); ++ return ret; ++ } ++ ++ memcpy(toe_ol, buf, sizeof(uint32)); ++ return 0; ++} ++ ++/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ ++static int ++dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) ++{ ++ int toe, ret; ++ ++ /* Set toe_ol as requested */ ++ ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", (char *)&toe_ol, sizeof(toe_ol), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", ++ dhd_ifname(&dhd->pub, ifidx), ret)); ++ return ret; ++ } ++ ++ /* Enable toe globally only if any components are enabled. */ ++ toe = (toe_ol != 0); ++ ret = dhd_iovar(&dhd->pub, ifidx, "toe", (char *)&toe, sizeof(toe), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif /* TOE */ ++ ++#if defined(WL_CFG80211) && defined(NUM_SCB_MAX_PROBE) ++void dhd_set_scb_probe(dhd_pub_t *dhd) ++{ ++ wl_scb_probe_t scb_probe; ++ int ret; ++ ++ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { ++ return; ++ } ++ ++ ret = dhd_iovar(dhd, 0, "scb_probe", NULL, 0, ++ (char *)&scb_probe, sizeof(scb_probe), FALSE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__)); ++ } ++ ++ scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE; ++ ++ ret = dhd_iovar(dhd, 0, "scb_probe", (char *)&scb_probe, sizeof(scb_probe), ++ NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: max_scb_probe setting failed\n", __FUNCTION__)); ++ return; ++ } ++} ++#endif /* WL_CFG80211 && NUM_SCB_MAX_PROBE */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ++static void ++dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(net); ++ ++ snprintf(info->driver, sizeof(info->driver), "wl"); ++ snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version); ++} ++ ++struct ethtool_ops dhd_ethtool_ops = { ++ .get_drvinfo = dhd_ethtool_get_drvinfo ++}; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ ++ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) ++static int ++dhd_ethtool(dhd_info_t *dhd, void *uaddr) ++{ ++ struct ethtool_drvinfo info; ++ char drvname[sizeof(info.driver)]; ++ uint32 cmd; ++#ifdef TOE ++ struct ethtool_value edata; ++ uint32 toe_cmpnt, csum_dir; ++ int ret; ++#endif ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ /* all ethtool calls start with a cmd word */ ++ if (copy_from_user(&cmd, uaddr, sizeof (uint32))) ++ return -EFAULT; ++ ++ switch (cmd) { ++ case ETHTOOL_GDRVINFO: ++ /* Copy out any request driver name */ ++ if (copy_from_user(&info, uaddr, sizeof(info))) ++ return -EFAULT; ++ strncpy(drvname, info.driver, sizeof(info.driver)); ++ drvname[sizeof(info.driver)-1] = '\0'; ++ ++ /* clear struct for return */ ++ memset(&info, 0, sizeof(info)); ++ info.cmd = cmd; ++ ++ /* if dhd requested, identify ourselves */ ++ if (strcmp(drvname, "?dhd") == 0) { ++ snprintf(info.driver, sizeof(info.driver), "dhd"); ++ strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1); ++ info.version[sizeof(info.version) - 1] = '\0'; ++ } ++ ++ /* otherwise, require dongle to be up */ ++ else if (!dhd->pub.up) { ++ DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++ /* finally, report dongle driver type */ ++ else if (dhd->pub.iswl) ++ snprintf(info.driver, sizeof(info.driver), "wl"); ++ else ++ snprintf(info.driver, sizeof(info.driver), "xx"); ++ ++ snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version); ++ if (copy_to_user(uaddr, &info, sizeof(info))) ++ return -EFAULT; ++ DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__, ++ (int)sizeof(drvname), drvname, info.driver)); ++ break; ++ ++#ifdef TOE ++ /* Get toe offload components from dongle */ ++ case ETHTOOL_GRXCSUM: ++ case ETHTOOL_GTXCSUM: ++ if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) ++ return ret; ++ ++ csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; ++ ++ edata.cmd = cmd; ++ edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; ++ ++ if (copy_to_user(uaddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ break; ++ ++ /* Set toe offload components in dongle */ ++ case ETHTOOL_SRXCSUM: ++ case ETHTOOL_STXCSUM: ++ if (copy_from_user(&edata, uaddr, sizeof(edata))) ++ return -EFAULT; ++ ++ /* Read the current settings, update and write back */ ++ if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) ++ return ret; ++ ++ csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; ++ ++ if (edata.data != 0) ++ toe_cmpnt |= csum_dir; ++ else ++ toe_cmpnt &= ~csum_dir; ++ ++ if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) ++ return ret; ++ ++ /* If setting TX checksum mode, tell Linux the new mode */ ++ if (cmd == ETHTOOL_STXCSUM) { ++ if (edata.data) ++ dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; ++ else ++ dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; ++ } ++ ++ break; ++#endif /* TOE */ ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ ++ ++static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) ++{ ++ if (!dhdp) { ++ DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); ++ return FALSE; ++ } ++ ++ if (!dhdp->up) ++ return FALSE; ++ ++#if !defined(BCMPCIE) && !defined(BCMDBUS) ++ if (dhdp->info->thr_dpc_ctl.thr_pid < 0) { ++ DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); ++ return FALSE; ++ } ++#endif /* !BCMPCIE && !BCMDBUS */ ++ ++ if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || ++ ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { ++#ifdef BCMPCIE ++ DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d d3acke=%d e=%d s=%d\n", ++ __FUNCTION__, dhdp->rxcnt_timeout, dhdp->txcnt_timeout, ++ dhdp->d3ackcnt_timeout, error, dhdp->busstate)); ++#else ++ DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, ++ dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate)); ++#endif /* BCMPCIE */ ++ if (dhdp->hang_reason == 0) { ++ if (dhdp->dongle_trap_occured) { ++ dhdp->hang_reason = HANG_REASON_DONGLE_TRAP; ++#ifdef BCMPCIE ++ } else if (dhdp->d3ackcnt_timeout) { ++ dhdp->hang_reason = HANG_REASON_D3_ACK_TIMEOUT; ++#endif /* BCMPCIE */ ++ } else { ++ dhdp->hang_reason = HANG_REASON_IOCTL_RESP_TIMEOUT; ++ } ++ } ++ printf("%s\n", info_string); ++ net_os_send_hang_message(net); ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++#ifdef WL_MONITOR ++bool ++dhd_monitor_enabled(dhd_pub_t *dhd, int ifidx) ++{ ++ return (dhd->info->monitor_type != 0); ++} ++ ++void ++dhd_rx_mon_pkt(dhd_pub_t *dhdp, host_rxbuf_cmpl_t* msg, void *pkt, int ifidx) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++#ifdef HOST_RADIOTAP_CONV ++ uint16 len = 0, offset = 0; ++ monitor_pkt_info_t pkt_info; ++ memcpy(&pkt_info.marker, &msg->marker, sizeof(msg->marker)); ++ memcpy(&pkt_info.ts, &msg->ts, sizeof(monitor_pkt_ts_t)); ++ ++ if (!dhd->monitor_skb) { ++ if ((dhd->monitor_skb = dev_alloc_skb(MAX_MON_PKT_SIZE)) == NULL) ++ return; ++ } ++ ++ len = bcmwifi_monitor(dhd->monitor_info, &pkt_info, PKTDATA(dhdp->osh, pkt), ++ PKTLEN(dhdp->osh, pkt), PKTDATA(dhdp->osh, dhd->monitor_skb), &offset); ++ ++ if (dhd->monitor_type && dhd->monitor_dev) ++ dhd->monitor_skb->dev = dhd->monitor_dev; ++ else { ++ PKTFREE(dhdp->osh, pkt, FALSE); ++ dev_kfree_skb(dhd->monitor_skb); ++ return; ++ } ++ ++ PKTFREE(dhdp->osh, pkt, FALSE); ++ ++ if (!len) { ++ return; ++ } ++ ++ skb_put(dhd->monitor_skb, len); ++ skb_pull(dhd->monitor_skb, offset); ++ ++ dhd->monitor_skb->protocol = eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); ++#else ++ uint8 amsdu_flag = (msg->flags & BCMPCIE_PKT_FLAGS_MONITOR_MASK) >> ++ BCMPCIE_PKT_FLAGS_MONITOR_SHIFT; ++ switch (amsdu_flag) { ++ case BCMPCIE_PKT_FLAGS_MONITOR_NO_AMSDU: ++ default: ++ if (!dhd->monitor_skb) { ++ if ((dhd->monitor_skb = PKTTONATIVE(dhdp->osh, pkt)) == NULL) ++ return; ++ } ++ ++ if (dhd->monitor_type && dhd->monitor_dev) ++ dhd->monitor_skb->dev = dhd->monitor_dev; ++ else { ++ PKTFREE(dhdp->osh, pkt, FALSE); ++ dhd->monitor_skb = NULL; ++ return; ++ } ++ ++ dhd->monitor_skb->protocol = ++ eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); ++ dhd->monitor_len = 0; ++ break; ++ case BCMPCIE_PKT_FLAGS_MONITOR_FIRST_PKT: ++ if (!dhd->monitor_skb) { ++ if ((dhd->monitor_skb = dev_alloc_skb(MAX_MON_PKT_SIZE)) == NULL) ++ return; ++ dhd->monitor_len = 0; ++ } ++ if (dhd->monitor_type && dhd->monitor_dev) ++ dhd->monitor_skb->dev = dhd->monitor_dev; ++ else { ++ PKTFREE(dhdp->osh, pkt, FALSE); ++ dev_kfree_skb(dhd->monitor_skb); ++ return; ++ } ++ memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb), ++ PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); ++ ++ dhd->monitor_len = PKTLEN(dhdp->osh, pkt); ++ PKTFREE(dhdp->osh, pkt, FALSE); ++ return; ++ case BCMPCIE_PKT_FLAGS_MONITOR_INTER_PKT: ++ memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb) + dhd->monitor_len, ++ PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); ++ dhd->monitor_len += PKTLEN(dhdp->osh, pkt); ++ ++ PKTFREE(dhdp->osh, pkt, FALSE); ++ return; ++ case BCMPCIE_PKT_FLAGS_MONITOR_LAST_PKT: ++ memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb) + dhd->monitor_len, ++ PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); ++ dhd->monitor_len += PKTLEN(dhdp->osh, pkt); ++ ++ PKTFREE(dhdp->osh, pkt, FALSE); ++ skb_put(dhd->monitor_skb, dhd->monitor_len); ++ dhd->monitor_skb->protocol = ++ eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); ++ dhd->monitor_len = 0; ++ break; ++ } ++ ++#endif /* HOST_RADIOTAP_CONV */ ++ if (in_interrupt()) { ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, ++ __FUNCTION__, __LINE__); ++ DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++ netif_rx(dhd->monitor_skb); ++ DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++ } 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 ++ * by netif_rx_ni(), but in earlier kernels, we need ++ * to do it manually. ++ */ ++ bcm_object_trace_opr(dhd->monitor_skb, BCM_OBJDBG_REMOVE, ++ __FUNCTION__, __LINE__); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++ netif_rx_ni(dhd->monitor_skb); ++ DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++#else ++ ulong flags; ++ DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++ netif_rx(dhd->monitor_skb); ++ DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); ++ local_irq_save(flags); ++ RAISE_RX_SOFTIRQ(); ++ local_irq_restore(flags); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ ++ } ++ ++ dhd->monitor_skb = NULL; ++} ++ ++typedef struct dhd_mon_dev_priv { ++ struct net_device_stats stats; ++} dhd_mon_dev_priv_t; ++ ++#define DHD_MON_DEV_PRIV_SIZE (sizeof(dhd_mon_dev_priv_t)) ++#define DHD_MON_DEV_PRIV(dev) ((dhd_mon_dev_priv_t *)DEV_PRIV(dev)) ++#define DHD_MON_DEV_STATS(dev) (((dhd_mon_dev_priv_t *)DEV_PRIV(dev))->stats) ++ ++static int ++dhd_monitor_start(struct sk_buff *skb, struct net_device *dev) ++{ ++ PKTFREE(NULL, skb, FALSE); ++ return 0; ++} ++ ++static int ++dhd_monitor_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++ return 0; ++} ++ ++static struct net_device_stats* ++dhd_monitor_get_stats(struct net_device *dev) ++{ ++ return &DHD_MON_DEV_STATS(dev); ++} ++ ++static const struct net_device_ops netdev_monitor_ops = ++{ ++ .ndo_start_xmit = dhd_monitor_start, ++ .ndo_get_stats = dhd_monitor_get_stats, ++ .ndo_do_ioctl = dhd_monitor_ioctl ++}; ++ ++static void ++dhd_add_monitor_if(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ struct net_device *dev; ++ char *devname; ++ ++ if (event != DHD_WQ_WORK_IF_ADD) { ++ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); ++ return; ++ } ++ ++ dev = alloc_etherdev(DHD_MON_DEV_PRIV_SIZE); ++ if (!dev) { ++ DHD_ERROR(("%s: alloc wlif failed\n", __FUNCTION__)); ++ return; ++ } ++ ++ devname = "radiotap"; ++ ++ snprintf(dev->name, sizeof(dev->name), "%s%u", devname, dhd->unit); ++ ++#ifndef ARPHRD_IEEE80211_PRISM /* From Linux 2.4.18 */ ++#define ARPHRD_IEEE80211_PRISM 802 ++#endif ++ ++#ifndef ARPHRD_IEEE80211_RADIOTAP ++#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ ++#endif /* ARPHRD_IEEE80211_RADIOTAP */ ++ ++ dev->type = ARPHRD_IEEE80211_RADIOTAP; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ dev->hard_start_xmit = dhd_monitor_start; ++ dev->do_ioctl = dhd_monitor_ioctl; ++ dev->get_stats = dhd_monitor_get_stats; ++#else ++ dev->netdev_ops = &netdev_monitor_ops; ++#endif ++ ++ if (register_netdev(dev)) { ++ DHD_ERROR(("%s, register_netdev failed for %s\n", ++ __FUNCTION__, dev->name)); ++ free_netdev(dev); ++ } ++ ++ bcmwifi_monitor_create(&dhd->monitor_info); ++ dhd->monitor_dev = dev; ++} ++ ++static void ++dhd_del_monitor_if(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ ++ if (event != DHD_WQ_WORK_IF_DEL) { ++ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); ++ return; ++ } ++ ++ if (dhd->monitor_dev) { ++ unregister_netdev(dhd->monitor_dev); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++ MFREE(dhd->osh, dhd->monitor_dev->priv, DHD_MON_DEV_PRIV_SIZE); ++ MFREE(dhd->osh, dhd->monitor_dev, sizeof(struct net_device)); ++#else ++ free_netdev(dhd->monitor_dev); ++#endif /* 2.6.24 */ ++ ++ dhd->monitor_dev = NULL; ++ } ++ ++ if (dhd->monitor_info) { ++ bcmwifi_monitor_delete(dhd->monitor_info); ++ dhd->monitor_info = NULL; ++ } ++} ++ ++static void ++dhd_set_monitor(dhd_pub_t *dhd, int ifidx, int val) ++{ ++ dhd_info_t *info = dhd->info; ++ ++ DHD_TRACE(("%s: val %d\n", __FUNCTION__, val)); ++ if ((val && info->monitor_dev) || (!val && !info->monitor_dev)) { ++ DHD_ERROR(("%s: Mismatched params, return\n", __FUNCTION__)); ++ return; ++ } ++ ++ /* Delete monitor */ ++ if (!val) { ++ info->monitor_type = val; ++ dhd_deferred_schedule_work(info->dhd_deferred_wq, NULL, DHD_WQ_WORK_IF_DEL, ++ dhd_del_monitor_if, DHD_WQ_WORK_PRIORITY_LOW); ++ return; ++ } ++ ++ /* Add monitor */ ++ info->monitor_type = val; ++ dhd_deferred_schedule_work(info->dhd_deferred_wq, NULL, DHD_WQ_WORK_IF_ADD, ++ dhd_add_monitor_if, DHD_WQ_WORK_PRIORITY_LOW); ++} ++#endif /* WL_MONITOR */ ++ ++int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf) ++{ ++ int bcmerror = BCME_OK; ++ int buflen = 0; ++ struct net_device *net; ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++ if (ioc->cmd == WLC_SET_WPA_AUTH) { ++ int wpa_auth; ++ ++ wpa_auth = *((int *)ioc->buf); ++ DHD_INFO(("wpa_auth:%d\n", wpa_auth)); ++ if (wpa_auth != WPA_AUTH_DISABLED) { ++ /* If AP is with security then enable WLC_E_PSK_SUP event checking */ ++ dhd_set_join_error(pub, WLC_WPA_MASK); ++ } else { ++ /* If AP is with open then disable WLC_E_PSK_SUP event checking */ ++ dhd_clear_join_error(pub, WLC_WPA_MASK); ++ } ++ } ++ ++ if (ioc->cmd == WLC_SET_AUTH) { ++ int auth; ++ auth = *((int *)ioc->buf); ++ DHD_INFO(("Auth:%d\n", auth)); ++ ++ if (auth != WL_AUTH_OPEN_SYSTEM) { ++ /* If AP is with security then enable WLC_E_PSK_SUP event checking */ ++ dhd_set_join_error(pub, WLC_WPA_MASK); ++ } else { ++ /* If AP is with open then disable WLC_E_PSK_SUP event checking */ ++ dhd_clear_join_error(pub, WLC_WPA_MASK); ++ } ++ } ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ net = dhd_idx2net(pub, ifidx); ++ if (!net) { ++ bcmerror = BCME_BADARG; ++ goto done; ++ } ++ ++ /* check for local dhd ioctl and handle it */ ++ if (ioc->driver == DHD_IOCTL_MAGIC) { ++ /* This is a DHD IOVAR, truncate buflen to DHD_IOCTL_MAXLEN */ ++ if (data_buf) ++ buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN); ++ bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen); ++ if (bcmerror) ++ pub->bcmerror = bcmerror; ++ goto done; ++ } ++ ++ /* This is a WL IOVAR, truncate buflen to WLC_IOCTL_MAXLEN */ ++ if (data_buf) ++ buflen = MIN(ioc->len, WLC_IOCTL_MAXLEN); ++ ++#ifndef BCMDBUS ++ /* send to dongle (must be up, and wl). */ ++ if (pub->busstate == DHD_BUS_DOWN || pub->busstate == DHD_BUS_LOAD) { ++ if ((!pub->dongle_trap_occured) && allow_delay_fwdl) { ++ int ret; ++ if (atomic_read(&exit_in_progress)) { ++ DHD_ERROR(("%s module exit in progress\n", __func__)); ++ bcmerror = BCME_DONGLE_DOWN; ++ goto done; ++ } ++ ret = dhd_bus_start(pub); ++ if (ret != 0) { ++ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); ++ bcmerror = BCME_DONGLE_DOWN; ++ goto done; ++ } ++ } else { ++ bcmerror = BCME_DONGLE_DOWN; ++ goto done; ++ } ++ } ++ ++ if (!pub->iswl) { ++ bcmerror = BCME_DONGLE_DOWN; ++ goto done; ++ } ++#endif /* !BCMDBUS */ ++ ++ /* ++ * Flush the TX queue if required for proper message serialization: ++ * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to ++ * prevent M4 encryption and ++ * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to ++ * prevent disassoc frame being sent before WPS-DONE frame. ++ */ ++ if (ioc->cmd == WLC_SET_KEY || ++ (ioc->cmd == WLC_SET_VAR && data_buf != NULL && ++ strncmp("wsec_key", data_buf, 9) == 0) || ++ (ioc->cmd == WLC_SET_VAR && data_buf != NULL && ++ strncmp("bsscfg:wsec_key", data_buf, 15) == 0) || ++ ioc->cmd == WLC_DISASSOC) ++ dhd_wait_pend8021x(net); ++ ++#ifdef WLMEDIA_HTSF ++ if (data_buf) { ++ /* short cut wl ioctl calls here */ ++ if (strcmp("htsf", data_buf) == 0) { ++ dhd_ioctl_htsf_get(dhd, 0); ++ return BCME_OK; ++ } ++ ++ if (strcmp("htsflate", data_buf) == 0) { ++ if (ioc->set) { ++ memset(ts, 0, sizeof(tstamp_t)*TSMAX); ++ memset(&maxdelayts, 0, sizeof(tstamp_t)); ++ maxdelay = 0; ++ tspktcnt = 0; ++ maxdelaypktno = 0; ++ memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); ++ } else { ++ dhd_dump_latency(); ++ } ++ return BCME_OK; ++ } ++ if (strcmp("htsfclear", data_buf) == 0) { ++ memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); ++ memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); ++ htsf_seqnum = 0; ++ return BCME_OK; ++ } ++ if (strcmp("htsfhis", data_buf) == 0) { ++ dhd_dump_htsfhisto(&vi_d1, "H to D"); ++ dhd_dump_htsfhisto(&vi_d2, "D to D"); ++ dhd_dump_htsfhisto(&vi_d3, "D to H"); ++ dhd_dump_htsfhisto(&vi_d4, "H to H"); ++ return BCME_OK; ++ } ++ if (strcmp("tsport", data_buf) == 0) { ++ if (ioc->set) { ++ memcpy(&tsport, data_buf + 7, 4); ++ } else { ++ DHD_ERROR(("current timestamp port: %d \n", tsport)); ++ } ++ return BCME_OK; ++ } ++ } ++#endif /* WLMEDIA_HTSF */ ++ ++ if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) && ++ data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) { ++#ifdef BCM_FD_AGGR ++ bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); ++#else ++ bcmerror = BCME_UNSUPPORTED; ++#endif ++ goto done; ++ } ++ bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); ++ ++#ifdef WL_MONITOR ++ /* Intercept monitor ioctl here, add/del monitor if */ ++ if (bcmerror == BCME_OK && ioc->cmd == WLC_SET_MONITOR) { ++ dhd_set_monitor(pub, ifidx, *(int32*)data_buf); ++ } ++#endif ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++ if (ioc->cmd == WLC_SCAN && bcmerror == 0) { ++ dhd_start_scan_timer(pub); ++ } ++ if (ioc->cmd == WLC_SET_SSID && bcmerror == 0) { ++ dhd_start_join_timer(pub); ++ } ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++done: ++ dhd_check_hang(net, pub, bcmerror); ++ ++ return bcmerror; ++} ++ ++static int ++dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(net); ++ dhd_ioctl_t ioc; ++ int bcmerror = 0; ++ int ifidx; ++ int ret; ++ void *local_buf = NULL; ++ void __user *ioc_buf_user = NULL; ++ u16 buflen = 0; ++ ++ if (atomic_read(&exit_in_progress)) { ++ DHD_ERROR(("%s module exit in progress\n", __func__)); ++ bcmerror = BCME_DONGLE_DOWN; ++ return OSL_ERROR(bcmerror); ++ } ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ DHD_PERIM_LOCK(&dhd->pub); ++ ++ /* Interface up check for built-in type */ ++ if (!dhd_download_fw_on_driverload && dhd->pub.up == FALSE) { ++ DHD_ERROR(("%s: Interface is down \n", __FUNCTION__)); ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return OSL_ERROR(BCME_NOTUP); ++ } ++ ++ ifidx = dhd_net2idx(dhd, net); ++ DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); ++ ++ if (ifidx == DHD_BAD_IF) { ++ DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return -1; ++ } ++ ++#if defined(WL_WIRELESS_EXT) ++ /* linux wireless extensions */ ++ if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { ++ /* may recurse, do NOT lock */ ++ ret = wl_iw_ioctl(net, ifr, cmd); ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return ret; ++ } ++#endif /* defined(WL_WIRELESS_EXT) */ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) ++ if (cmd == SIOCETHTOOL) { ++ ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return ret; ++ } ++#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ ++ ++ if (cmd == SIOCDEVPRIVATE+1) { ++ ret = wl_android_priv_cmd(net, ifr, cmd); ++ dhd_check_hang(net, &dhd->pub, ret); ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return ret; ++ } ++ ++ if (cmd != SIOCDEVPRIVATE) { ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ return -EOPNOTSUPP; ++ } ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++#ifdef CONFIG_COMPAT ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) ++ if (in_compat_syscall()) ++#else ++ if (is_compat_task()) ++#endif ++ { ++ compat_wl_ioctl_t compat_ioc; ++ if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ ioc.cmd = compat_ioc.cmd; ++ if (ioc.cmd & WLC_SPEC_FLAG) { ++ memset(&ioc, 0, sizeof(ioc)); ++ /* Copy the ioc control structure part of ioctl request */ ++ if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ ioc.cmd &= ~WLC_SPEC_FLAG; /* Clear the FLAG */ ++ ++ /* To differentiate between wl and dhd read 4 more byes */ ++ if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), ++ sizeof(uint)) != 0)) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ ++ } else { /* ioc.cmd & WLC_SPEC_FLAG */ ++ ioc.buf = compat_ptr(compat_ioc.buf); ++ ioc.len = compat_ioc.len; ++ ioc.set = compat_ioc.set; ++ ioc.used = compat_ioc.used; ++ ioc.needed = compat_ioc.needed; ++ /* To differentiate between wl and dhd read 4 more byes */ ++ if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t), ++ sizeof(uint)) != 0)) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ } /* ioc.cmd & WLC_SPEC_FLAG */ ++ } else ++#endif /* CONFIG_COMPAT */ ++ { ++ /* Copy the ioc control structure part of ioctl request */ ++ if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++#ifdef CONFIG_COMPAT ++ ioc.cmd &= ~WLC_SPEC_FLAG; /* make sure it was clear when it isn't a compat task*/ ++#endif ++ ++ /* To differentiate between wl and dhd read 4 more byes */ ++ if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), ++ sizeof(uint)) != 0)) { ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ } ++ ++#ifndef CONFIG_VTS_SUPPORT ++ if (!capable(CAP_NET_ADMIN)) { ++ bcmerror = BCME_EPERM; ++ goto done; ++ } ++#endif ++ ++ /* Take backup of ioc.buf and restore later */ ++ ioc_buf_user = ioc.buf; ++ ++ if (ioc.len > 0) { ++ buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); ++ if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) { ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ if (copy_from_user(local_buf, ioc.buf, buflen)) { ++ DHD_PERIM_LOCK(&dhd->pub); ++ bcmerror = BCME_BADADDR; ++ goto done; ++ } ++ DHD_PERIM_LOCK(&dhd->pub); ++ ++ *((char *)local_buf + buflen) = '\0'; ++ ++ /* For some platforms accessing userspace memory ++ * of ioc.buf is causing kernel panic, so to avoid that ++ * make ioc.buf pointing to kernel space memory local_buf ++ */ ++ ioc.buf = local_buf; ++ } ++ ++ /* Skip all the non DHD iovars (wl iovars) after f/w hang */ ++ if (ioc.driver != DHD_IOCTL_MAGIC && dhd->pub.hang_was_sent) { ++ DHD_TRACE(("%s: HANG was sent up earlier\n", __FUNCTION__)); ++ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); ++ bcmerror = BCME_DONGLE_DOWN; ++ goto done; ++ } ++ ++ bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf); ++ ++ /* Restore back userspace pointer to ioc.buf */ ++ ioc.buf = ioc_buf_user; ++ ++ if (!bcmerror && buflen && local_buf && ioc.buf) { ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ if (copy_to_user(ioc.buf, local_buf, buflen)) ++ bcmerror = -EFAULT; ++ DHD_PERIM_LOCK(&dhd->pub); ++ } ++ ++done: ++ if (local_buf) ++ MFREE(dhd->pub.osh, local_buf, buflen+1); ++ ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++ return OSL_ERROR(bcmerror); ++} ++ ++ ++#ifdef FIX_CPU_MIN_CLOCK ++static int dhd_init_cpufreq_fix(dhd_info_t *dhd) ++{ ++ if (dhd) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_init(&dhd->cpufreq_fix); ++#endif ++ dhd->cpufreq_fix_status = FALSE; ++ } ++ return 0; ++} ++ ++static void dhd_fix_cpu_freq(dhd_info_t *dhd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_lock(&dhd->cpufreq_fix); ++#endif ++ if (dhd && !dhd->cpufreq_fix_status) { ++ pm_qos_add_request(&dhd->dhd_cpu_qos, PM_QOS_CPU_FREQ_MIN, 300000); ++#ifdef FIX_BUS_MIN_CLOCK ++ pm_qos_add_request(&dhd->dhd_bus_qos, PM_QOS_BUS_THROUGHPUT, 400000); ++#endif /* FIX_BUS_MIN_CLOCK */ ++ DHD_ERROR(("pm_qos_add_requests called\n")); ++ ++ dhd->cpufreq_fix_status = TRUE; ++ } ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_unlock(&dhd->cpufreq_fix); ++#endif ++} ++ ++static void dhd_rollback_cpu_freq(dhd_info_t *dhd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_lock(&dhd ->cpufreq_fix); ++#endif ++ if (dhd && dhd->cpufreq_fix_status != TRUE) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_unlock(&dhd->cpufreq_fix); ++#endif ++ return; ++ } ++ ++ pm_qos_remove_request(&dhd->dhd_cpu_qos); ++#ifdef FIX_BUS_MIN_CLOCK ++ pm_qos_remove_request(&dhd->dhd_bus_qos); ++#endif /* FIX_BUS_MIN_CLOCK */ ++ DHD_ERROR(("pm_qos_add_requests called\n")); ++ ++ dhd->cpufreq_fix_status = FALSE; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_unlock(&dhd->cpufreq_fix); ++#endif ++} ++#endif /* FIX_CPU_MIN_CLOCK */ ++ ++#if defined(BT_OVER_SDIO) ++ ++void ++dhdsdio_bus_usr_cnt_inc(dhd_pub_t *dhdp) ++{ ++ dhdp->info->bus_user_count++; ++} ++ ++void ++dhdsdio_bus_usr_cnt_dec(dhd_pub_t *dhdp) ++{ ++ dhdp->info->bus_user_count--; ++} ++ ++/* Return values: ++ * Success: Returns 0 ++ * Failure: Returns -1 or errono code ++ */ ++int ++dhd_bus_get(wlan_bt_handle_t handle, bus_owner_t owner) ++{ ++ dhd_pub_t *dhdp = (dhd_pub_t *)handle; ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ int ret = 0; ++ ++ mutex_lock(&dhd->bus_user_lock); ++ ++dhd->bus_user_count; ++ if (dhd->bus_user_count < 0) { ++ DHD_ERROR(("%s(): bus_user_count is negative, which is invalid\n", __FUNCTION__)); ++ ret = -1; ++ goto exit; ++ } ++ ++ if (dhd->bus_user_count == 1) { ++ ++ dhd->pub.hang_was_sent = 0; ++ ++ /* First user, turn on WL_REG, start the bus */ ++ DHD_ERROR(("%s(): First user Turn On WL_REG & start the bus", __FUNCTION__)); ++ ++ if (!wifi_platform_set_power(dhd->adapter, TRUE, WIFI_TURNON_DELAY)) { ++ /* Enable F1 */ ++ ret = dhd_bus_resume(dhdp, 0); ++ if (ret) { ++ DHD_ERROR(("%s(): Failed to enable F1, err=%d\n", ++ __FUNCTION__, ret)); ++ goto exit; ++ } ++ } ++ ++ dhd_update_fw_nv_path(dhd); ++ /* update firmware and nvram path to sdio bus */ ++ dhd_bus_update_fw_nv_path(dhd->pub.bus, ++ dhd->fw_path, dhd->nv_path); ++ /* download the firmware, Enable F2 */ ++ /* TODO: Should be done only in case of FW switch */ ++ ret = dhd_bus_devreset(dhdp, FALSE); ++ dhd_bus_resume(dhdp, 1); ++ if (!ret) { ++ if (dhd_sync_with_dongle(&dhd->pub) < 0) { ++ DHD_ERROR(("%s(): Sync with dongle failed!!\n", __FUNCTION__)); ++ ret = -EFAULT; ++ } ++ } else { ++ DHD_ERROR(("%s(): Failed to download, err=%d\n", __FUNCTION__, ret)); ++ } ++ } else { ++ DHD_ERROR(("%s(): BUS is already acquired, just increase the count %d \r\n", ++ __FUNCTION__, dhd->bus_user_count)); ++ } ++exit: ++ mutex_unlock(&dhd->bus_user_lock); ++ return ret; ++} ++EXPORT_SYMBOL(dhd_bus_get); ++ ++/* Return values: ++ * Success: Returns 0 ++ * Failure: Returns -1 or errono code ++ */ ++int ++dhd_bus_put(wlan_bt_handle_t handle, bus_owner_t owner) ++{ ++ dhd_pub_t *dhdp = (dhd_pub_t *)handle; ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ int ret = 0; ++ BCM_REFERENCE(owner); ++ ++ mutex_lock(&dhd->bus_user_lock); ++ --dhd->bus_user_count; ++ if (dhd->bus_user_count < 0) { ++ DHD_ERROR(("%s(): bus_user_count is negative, which is invalid\n", __FUNCTION__)); ++ dhd->bus_user_count = 0; ++ ret = -1; ++ goto exit; ++ } ++ ++ if (dhd->bus_user_count == 0) { ++ /* Last user, stop the bus and turn Off WL_REG */ ++ DHD_ERROR(("%s(): There are no owners left Trunf Off WL_REG & stop the bus \r\n", ++ __FUNCTION__)); ++#ifdef PROP_TXSTATUS ++ if (dhd->pub.wlfc_enabled) { ++ dhd_wlfc_deinit(&dhd->pub); ++ } ++#endif /* PROP_TXSTATUS */ ++#ifdef PNO_SUPPORT ++ if (dhd->pub.pno_state) { ++ dhd_pno_deinit(&dhd->pub); ++ } ++#endif /* PNO_SUPPORT */ ++#ifdef RTT_SUPPORT ++ if (dhd->pub.rtt_state) { ++ dhd_rtt_deinit(&dhd->pub); ++ } ++#endif /* RTT_SUPPORT */ ++ ret = dhd_bus_devreset(dhdp, TRUE); ++ if (!ret) { ++ dhd_bus_suspend(dhdp); ++ wifi_platform_set_power(dhd->adapter, FALSE, WIFI_TURNOFF_DELAY); ++ } ++ } else { ++ DHD_ERROR(("%s(): Other owners using bus, decrease the count %d \r\n", ++ __FUNCTION__, dhd->bus_user_count)); ++ } ++exit: ++ mutex_unlock(&dhd->bus_user_lock); ++ return ret; ++} ++EXPORT_SYMBOL(dhd_bus_put); ++ ++int ++dhd_net_bus_get(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ return dhd_bus_get(&dhd->pub, WLAN_MODULE); ++} ++ ++int ++dhd_net_bus_put(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ return dhd_bus_put(&dhd->pub, WLAN_MODULE); ++} ++ ++/* ++ * Function to enable the Bus Clock ++ * Returns BCME_OK on success and BCME_xxx on failure ++ * ++ * This function is not callable from non-sleepable context ++ */ ++int dhd_bus_clk_enable(wlan_bt_handle_t handle, bus_owner_t owner) ++{ ++ dhd_pub_t *dhdp = (dhd_pub_t *)handle; ++ ++ int ret; ++ ++ dhd_os_sdlock(dhdp); ++ /* ++ * The second argument is TRUE, that means, we expect ++ * the function to "wait" until the clocks are really ++ * available ++ */ ++ ret = __dhdsdio_clk_enable(dhdp->bus, owner, TRUE); ++ dhd_os_sdunlock(dhdp); ++ ++ return ret; ++} ++EXPORT_SYMBOL(dhd_bus_clk_enable); ++ ++/* ++ * Function to disable the Bus Clock ++ * Returns BCME_OK on success and BCME_xxx on failure ++ * ++ * This function is not callable from non-sleepable context ++ */ ++int dhd_bus_clk_disable(wlan_bt_handle_t handle, bus_owner_t owner) ++{ ++ dhd_pub_t *dhdp = (dhd_pub_t *)handle; ++ ++ int ret; ++ ++ dhd_os_sdlock(dhdp); ++ /* ++ * The second argument is TRUE, that means, we expect ++ * the function to "wait" until the clocks are really ++ * disabled ++ */ ++ ret = __dhdsdio_clk_disable(dhdp->bus, owner, TRUE); ++ dhd_os_sdunlock(dhdp); ++ ++ return ret; ++} ++EXPORT_SYMBOL(dhd_bus_clk_disable); ++ ++/* ++ * Function to reset bt_use_count counter to zero. ++ * ++ * This function is not callable from non-sleepable context ++ */ ++void dhd_bus_reset_bt_use_count(wlan_bt_handle_t handle) ++{ ++ dhd_pub_t *dhdp = (dhd_pub_t *)handle; ++ ++ /* take the lock and reset bt use count */ ++ dhd_os_sdlock(dhdp); ++ dhdsdio_reset_bt_use_count(dhdp->bus); ++ dhd_os_sdunlock(dhdp); ++} ++EXPORT_SYMBOL(dhd_bus_reset_bt_use_count); ++ ++#endif /* BT_OVER_SDIO */ ++ ++#define MAX_TRY_CNT 5 /* Number of tries to disable deepsleep */ ++int dhd_deepsleep(dhd_info_t *dhd, int flag) ++{ ++ char iovbuf[20]; ++ uint powervar = 0; ++ dhd_pub_t *dhdp; ++ int cnt = 0; ++ int ret = 0; ++ ++ dhdp = &dhd->pub; ++ ++ switch (flag) { ++ case 1 : /* Deepsleep on */ ++ DHD_ERROR(("dhd_deepsleep: ON\n")); ++ /* give some time to sysioc_work before deepsleep */ ++ OSL_SLEEP(200); ++#ifdef PKT_FILTER_SUPPORT ++ /* disable pkt filter */ ++ dhd_enable_packet_filter(0, dhdp); ++#endif /* PKT_FILTER_SUPPORT */ ++ /* Disable MPC */ ++ powervar = 0; ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ ++ /* Enable Deepsleep */ ++ powervar = 1; ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ break; ++ ++ case 0: /* Deepsleep Off */ ++ DHD_ERROR(("dhd_deepsleep: OFF\n")); ++ ++ /* Disable Deepsleep */ ++ for (cnt = 0; cnt < MAX_TRY_CNT; cnt++) { ++ powervar = 0; ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ bcm_mkiovar("deepsleep", (char *)&powervar, 4, ++ iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, ++ sizeof(iovbuf), TRUE, 0); ++ ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ bcm_mkiovar("deepsleep", (char *)&powervar, 4, ++ iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, ++ sizeof(iovbuf), FALSE, 0)) < 0) { ++ DHD_ERROR(("the error of dhd deepsleep status" ++ " ret value :%d\n", ret)); ++ } else { ++ if (!(*(int *)iovbuf)) { ++ DHD_ERROR(("deepsleep mode is 0," ++ " count: %d\n", cnt)); ++ break; ++ } ++ } ++ } ++ ++ /* Enable MPC */ ++ powervar = 1; ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int ++dhd_stop(struct net_device *net) ++{ ++ int ifidx = 0; ++#ifdef WL_CFG80211 ++ unsigned long flags = 0; ++#endif /* WL_CFG80211 */ ++ dhd_info_t *dhd = DHD_DEV_INFO(net); ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ DHD_PERIM_LOCK(&dhd->pub); ++ printf("%s: Enter %p\n", __FUNCTION__, net); ++ dhd->pub.rxcnt_timeout = 0; ++ dhd->pub.txcnt_timeout = 0; ++ ++#ifdef BCMPCIE ++ dhd->pub.d3ackcnt_timeout = 0; ++#endif /* BCMPCIE */ ++ ++ if (dhd->pub.up == 0) { ++ goto exit; ++ } ++#if defined(DHD_HANG_SEND_UP_TEST) ++ if (dhd->pub.req_hang_type) { ++ DHD_ERROR(("%s, Clear HANG test request 0x%x\n", ++ __FUNCTION__, dhd->pub.req_hang_type)); ++ dhd->pub.req_hang_type = 0; ++ } ++#endif /* DHD_HANG_SEND_UP_TEST */ ++ ++ dhd_if_flush_sta(DHD_DEV_IFP(net)); ++ ++ /* Disable Runtime PM before interface down */ ++ DHD_DISABLE_RUNTIME_PM(&dhd->pub); ++ ++#ifdef FIX_CPU_MIN_CLOCK ++ if (dhd_get_fw_mode(dhd) == DHD_FLAG_HOSTAP_MODE) ++ dhd_rollback_cpu_freq(dhd); ++#endif /* FIX_CPU_MIN_CLOCK */ ++ ++ ifidx = dhd_net2idx(dhd, net); ++ BCM_REFERENCE(ifidx); ++ ++ /* Set state and stop OS transmissions */ ++ netif_stop_queue(net); ++#ifdef WL_CFG80211 ++ spin_lock_irqsave(&dhd->pub.up_lock, flags); ++ dhd->pub.up = 0; ++ spin_unlock_irqrestore(&dhd->pub.up_lock, flags); ++#else ++ dhd->pub.up = 0; ++#endif /* WL_CFG80211 */ ++ ++#ifdef WL_CFG80211 ++ if (ifidx == 0) { ++ dhd_if_t *ifp; ++ wl_cfg80211_down(net); ++ ++ ifp = dhd->iflist[0]; ++ ASSERT(ifp && ifp->net); ++ /* ++ * For CFG80211: Clean up all the left over virtual interfaces ++ * when the primary Interface is brought down. [ifconfig wlan0 down] ++ */ ++ if (!dhd_download_fw_on_driverload) { ++ if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && ++ (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { ++ int i; ++#ifdef WL_CFG80211_P2P_DEV_IF ++ wl_cfg80211_del_p2p_wdev(net); ++#endif /* WL_CFG80211_P2P_DEV_IF */ ++ ++ dhd_net_if_lock_local(dhd); ++ for (i = 1; i < DHD_MAX_IFS; i++) ++ dhd_remove_if(&dhd->pub, i, FALSE); ++ ++ if (ifp && ifp->net) { ++ dhd_if_del_sta_list(ifp); ++ } ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd_inetaddr_notifier_registered) { ++ dhd_inetaddr_notifier_registered = FALSE; ++ unregister_inetaddr_notifier(&dhd_inetaddr_notifier); ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) ++ if (dhd_inet6addr_notifier_registered) { ++ dhd_inet6addr_notifier_registered = FALSE; ++ unregister_inet6addr_notifier(&dhd_inet6addr_notifier); ++ } ++#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ ++ dhd_net_if_unlock_local(dhd); ++ } ++#if 0 ++ // terence 20161024: remove this to prevent dev_close() get stuck in dhd_hang_process ++ cancel_work_sync(dhd->dhd_deferred_wq); ++#endif ++ ++#ifdef SHOW_LOGTRACE ++ /* Wait till event_log_dispatcher_work finishes */ ++ cancel_work_sync(&dhd->event_log_dispatcher_work); ++#endif /* SHOW_LOGTRACE */ ++ ++#if defined(DHD_LB_RXP) ++ __skb_queue_purge(&dhd->rx_pend_queue); ++#endif /* DHD_LB_RXP */ ++ ++#if defined(DHD_LB_TXP) ++ skb_queue_purge(&dhd->tx_pend_queue); ++#endif /* DHD_LB_TXP */ ++ } ++ ++ argos_register_notifier_deinit(); ++#ifdef DHDTCPACK_SUPPRESS ++ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); ++#endif /* DHDTCPACK_SUPPRESS */ ++#if defined(DHD_LB_RXP) ++ if (ifp->net == dhd->rx_napi_netdev) { ++ DHD_INFO(("%s napi<%p> disabled ifp->net<%p,%s>\n", ++ __FUNCTION__, &dhd->rx_napi_struct, net, net->name)); ++ skb_queue_purge(&dhd->rx_napi_queue); ++ napi_disable(&dhd->rx_napi_struct); ++ netif_napi_del(&dhd->rx_napi_struct); ++ dhd->rx_napi_netdev = NULL; ++ } ++#endif /* DHD_LB_RXP */ ++ } ++#endif /* WL_CFG80211 */ ++ ++ DHD_SSSR_DUMP_DEINIT(&dhd->pub); ++ ++#ifdef PROP_TXSTATUS ++ dhd_wlfc_cleanup(&dhd->pub, NULL, 0); ++#endif ++#ifdef SHOW_LOGTRACE ++ if (!dhd_download_fw_on_driverload) { ++ /* Release the skbs from queue for WLC_E_TRACE event */ ++ dhd_event_logtrace_flush_queue(&dhd->pub); ++ if (dhd->dhd_state & DHD_ATTACH_LOGTRACE_INIT) { ++ if (dhd->event_data.fmts) { ++ MFREE(dhd->pub.osh, dhd->event_data.fmts, ++ dhd->event_data.fmts_size); ++ dhd->event_data.fmts = NULL; ++ } ++ if (dhd->event_data.raw_fmts) { ++ MFREE(dhd->pub.osh, dhd->event_data.raw_fmts, ++ dhd->event_data.raw_fmts_size); ++ dhd->event_data.raw_fmts = NULL; ++ } ++ if (dhd->event_data.raw_sstr) { ++ MFREE(dhd->pub.osh, dhd->event_data.raw_sstr, ++ dhd->event_data.raw_sstr_size); ++ dhd->event_data.raw_sstr = NULL; ++ } ++ if (dhd->event_data.rom_raw_sstr) { ++ MFREE(dhd->pub.osh, dhd->event_data.rom_raw_sstr, ++ dhd->event_data.rom_raw_sstr_size); ++ dhd->event_data.rom_raw_sstr = NULL; ++ } ++ dhd->dhd_state &= ~DHD_ATTACH_LOGTRACE_INIT; ++ } ++ } ++#endif /* SHOW_LOGTRACE */ ++#ifdef APF ++ dhd_dev_apf_delete_filter(net); ++#endif /* APF */ ++ ++ /* Stop the protocol module */ ++ dhd_prot_stop(&dhd->pub); ++ ++ OLD_MOD_DEC_USE_COUNT; ++exit: ++#if defined(WL_WIRELESS_EXT) ++ if (ifidx == 0) { ++ wl_iw_down(net, &dhd->pub); ++ } ++#endif /* defined(WL_WIRELESS_EXT) */ ++#ifdef WL_ESCAN ++ if (ifidx == 0) { ++ wl_escan_down(net, &dhd->pub); ++ } ++#endif /* WL_ESCAN */ ++ if (ifidx == 0 && !dhd_download_fw_on_driverload) { ++#if defined(BT_OVER_SDIO) ++ dhd_bus_put(&dhd->pub, WLAN_MODULE); ++ wl_android_set_wifi_on_flag(FALSE); ++#else ++ wl_android_wifi_off(net, TRUE); ++#if defined(WL_EXT_IAPSTA) || defined(USE_IW) || defined(WL_ESCAN) ++#ifdef WL_EXT_IAPSTA ++ wl_ext_iapsta_dettach_netdev(net, ifidx); ++#endif /* WL_EXT_IAPSTA */ ++#ifdef WL_ESCAN ++ wl_escan_event_dettach(net, &dhd->pub); ++#endif /* WL_ESCAN */ ++ wl_ext_event_dettach_netdev(net, ifidx); ++#endif /* WL_EXT_IAPSTA || USE_IW || WL_ESCAN */ ++ } else { ++ if (dhd->pub.conf->deepsleep) ++ dhd_deepsleep(dhd, 1); ++#endif /* BT_OVER_SDIO */ ++ } ++ dhd->pub.hang_was_sent = 0; ++ ++ /* Clear country spec for for built-in type driver */ ++ if (!dhd_download_fw_on_driverload) { ++ dhd->pub.dhd_cspec.country_abbrev[0] = 0x00; ++ dhd->pub.dhd_cspec.rev = 0; ++ dhd->pub.dhd_cspec.ccode[0] = 0x00; ++ } ++ ++#ifdef BCMDBGFS ++ dhd_dbgfs_remove(); ++#endif ++ ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++ /* Destroy wakelock */ ++ if (!dhd_download_fw_on_driverload && ++ (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { ++ DHD_OS_WAKE_LOCK_DESTROY(dhd); ++ dhd->dhd_state &= ~DHD_ATTACH_STATE_WAKELOCKS_INIT; ++ } ++ printf("%s: Exit\n", __FUNCTION__); ++ ++ return 0; ++} ++ ++#if defined(WL_CFG80211) && defined(USE_INITIAL_SHORT_DWELL_TIME) ++extern bool g_first_broadcast_scan; ++#endif ++ ++#ifdef WL11U ++static int dhd_interworking_enable(dhd_pub_t *dhd) ++{ ++ uint32 enable = true; ++ int ret = BCME_OK; ++ ++ ret = dhd_iovar(dhd, 0, "interworking", (char *)&enable, sizeof(enable), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret)); ++ } ++ ++ return ret; ++} ++#endif /* WL11u */ ++ ++static int ++dhd_open(struct net_device *net) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(net); ++#ifdef TOE ++ uint32 toe_ol; ++#endif ++#ifdef BCM_FD_AGGR ++ char iovbuf[WLC_IOCTL_SMLEN]; ++ dbus_config_t config; ++ uint32 agglimit = 0; ++ uint32 rpc_agg = BCM_RPC_TP_DNGL_AGG_DPC; /* host aggr not enabled yet */ ++#endif /* BCM_FD_AGGR */ ++ int ifidx; ++ int32 ret = 0; ++#if defined(OOB_INTR_ONLY) ++ uint32 bus_type = -1; ++ uint32 bus_num = -1; ++ uint32 slot_num = -1; ++ wifi_adapter_info_t *adapter = NULL; ++#endif ++#if defined(WL_EXT_IAPSTA) && defined(ISAM_PREINIT) ++ int bytes_written = 0; ++#endif ++ ++ if (!dhd_download_fw_on_driverload) { ++ if (!dhd_driver_init_done) { ++ DHD_ERROR(("%s: WLAN driver is not initialized\n", __FUNCTION__)); ++ return -1; ++ } ++ } ++ ++ printf("%s: Enter %p\n", __FUNCTION__, net); ++ DHD_MUTEX_LOCK(); ++ /* Init wakelock */ ++ if (!dhd_download_fw_on_driverload) { ++ if (!(dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { ++ DHD_OS_WAKE_LOCK_INIT(dhd); ++ dhd->dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; ++ } ++#ifdef SHOW_LOGTRACE ++ skb_queue_head_init(&dhd->evt_trace_queue); ++ ++ if (!(dhd->dhd_state & DHD_ATTACH_LOGTRACE_INIT)) { ++ ret = dhd_init_logstrs_array(dhd->pub.osh, &dhd->event_data); ++ if (ret == BCME_OK) { ++ dhd_init_static_strs_array(dhd->pub.osh, &dhd->event_data, ++ st_str_file_path, map_file_path); ++ dhd_init_static_strs_array(dhd->pub.osh, &dhd->event_data, ++ rom_st_str_file_path, rom_map_file_path); ++ dhd->dhd_state |= DHD_ATTACH_LOGTRACE_INIT; ++ } ++ } ++#endif /* SHOW_LOGTRACE */ ++ } ++ ++#if defined(PREVENT_REOPEN_DURING_HANG) ++ /* WAR : to prevent calling dhd_open abnormally in quick succession after hang event */ ++ if (dhd->pub.hang_was_sent == 1) { ++ DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); ++ /* Force to bring down WLAN interface in case dhd_stop() is not called ++ * from the upper layer when HANG event is triggered. ++ */ ++ if (!dhd_download_fw_on_driverload && dhd->pub.up == 1) { ++ DHD_ERROR(("%s: WLAN interface is not brought down\n", __FUNCTION__)); ++ dhd_stop(net); ++ } else { ++ DHD_MUTEX_UNLOCK(); ++ return -1; ++ } ++ } ++#endif /* PREVENT_REOPEN_DURING_HANG */ ++ ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ DHD_PERIM_LOCK(&dhd->pub); ++ dhd->pub.dongle_trap_occured = 0; ++ dhd->pub.hang_was_sent = 0; ++ dhd->pub.hang_reason = 0; ++ dhd->pub.iovar_timeout_occured = 0; ++#ifdef PCIE_FULL_DONGLE ++ dhd->pub.d3ack_timeout_occured = 0; ++#endif /* PCIE_FULL_DONGLE */ ++ ++#ifdef DHD_LOSSLESS_ROAMING ++ dhd->pub.dequeue_prec_map = ALLPRIO; ++#endif ++#if 0 ++ /* ++ * Force start if ifconfig_up gets called before START command ++ * We keep WEXT's wl_control_wl_start to provide backward compatibility ++ * This should be removed in the future ++ */ ++ ret = wl_control_wl_start(net); ++ if (ret != 0) { ++ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); ++ ret = -1; ++ goto exit; ++ } ++#endif ++ ++ ifidx = dhd_net2idx(dhd, net); ++ DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); ++ ++ if (ifidx < 0) { ++ DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__)); ++ ret = -1; ++ goto exit; ++ } ++ ++ if (!dhd->iflist[ifidx]) { ++ DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); ++ ret = -1; ++ goto exit; ++ } ++ ++ if (ifidx == 0) { ++ atomic_set(&dhd->pend_8021x_cnt, 0); ++ if (!dhd_download_fw_on_driverload) { ++ DHD_ERROR(("\n%s\n", dhd_version)); ++#if defined(WL_EXT_IAPSTA) || defined(USE_IW) || defined(WL_ESCAN) ++ wl_ext_event_attach_netdev(net, ifidx, dhd->iflist[ifidx]->bssidx); ++#ifdef WL_ESCAN ++ wl_escan_event_attach(net, &dhd->pub); ++#endif /* WL_ESCAN */ ++#ifdef WL_EXT_IAPSTA ++ wl_ext_iapsta_attach_netdev(net, ifidx, dhd->iflist[ifidx]->bssidx); ++#endif /* WL_EXT_IAPSTA */ ++#endif /* WL_EXT_IAPSTA || USE_IW || WL_ESCAN */ ++#if defined(USE_INITIAL_SHORT_DWELL_TIME) ++ g_first_broadcast_scan = TRUE; ++#endif ++#if defined(BT_OVER_SDIO) ++ ret = dhd_bus_get(&dhd->pub, WLAN_MODULE); ++ wl_android_set_wifi_on_flag(TRUE); ++#else ++ ret = wl_android_wifi_on(net); ++#endif /* BT_OVER_SDIO */ ++ if (ret != 0) { ++ DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n", ++ __FUNCTION__, ret)); ++ ret = -1; ++ goto exit; ++ } ++ } ++#ifdef FIX_CPU_MIN_CLOCK ++ if (dhd_get_fw_mode(dhd) == DHD_FLAG_HOSTAP_MODE) { ++ dhd_init_cpufreq_fix(dhd); ++ dhd_fix_cpu_freq(dhd); ++ } ++#endif /* FIX_CPU_MIN_CLOCK */ ++#if defined(OOB_INTR_ONLY) ++ if (dhd->pub.conf->dpc_cpucore >= 0) { ++ dhd_bus_get_ids(dhd->pub.bus, &bus_type, &bus_num, &slot_num); ++ adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); ++ if (adapter) { ++ printf("%s: set irq affinity hit %d\n", __FUNCTION__, dhd->pub.conf->dpc_cpucore); ++ irq_set_affinity_hint(adapter->irq_num, cpumask_of(dhd->pub.conf->dpc_cpucore)); ++ } ++ } ++#endif ++ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++#ifdef BCMDBUS ++ dhd_set_path(&dhd->pub); ++ DHD_MUTEX_UNLOCK(); ++ wait_event_interruptible_timeout(dhd->adapter->status_event, ++ wifi_get_adapter_status(dhd->adapter, WIFI_STATUS_FW_READY), ++ msecs_to_jiffies(DHD_FW_READY_TIMEOUT)); ++ DHD_MUTEX_LOCK(); ++ if ((ret = dbus_up(dhd->pub.bus)) != 0) { ++ DHD_ERROR(("%s: failed to dbus_up with code %d\n", __FUNCTION__, ret)); ++ goto exit; ++ } else { ++ dhd->pub.busstate = DHD_BUS_DATA; ++ } ++ if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) { ++ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); ++ goto exit; ++ } ++#else ++ /* try to bring up bus */ ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ ret = dhd_bus_start(&dhd->pub); ++ DHD_PERIM_LOCK(&dhd->pub); ++ if (ret) { ++ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); ++ ret = -1; ++ goto exit; ++ } ++#endif /* !BCMDBUS */ ++ ++ } ++#ifdef WL_EXT_IAPSTA ++ wl_ext_iapsta_attach_name(net, ifidx); ++#endif ++ if (dhd_download_fw_on_driverload) { ++ if (dhd->pub.conf->deepsleep) ++ dhd_deepsleep(dhd, 0); ++ } ++ ++#ifdef BCM_FD_AGGR ++ config.config_id = DBUS_CONFIG_ID_AGGR_LIMIT; ++ ++ ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ bcm_mkiovar("rpc_dngl_agglimit", (char *)&agglimit, 4, ++ iovbuf, sizeof(iovbuf)); ++ ++ if (!dhd_wl_ioctl_cmd(&dhd->pub, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) { ++ agglimit = *(uint32 *)iovbuf; ++ config.aggr_param.maxrxsf = agglimit >> BCM_RPC_TP_AGG_SF_SHIFT; ++ config.aggr_param.maxrxsize = agglimit & BCM_RPC_TP_AGG_BYTES_MASK; ++ DHD_ERROR(("rpc_dngl_agglimit %x : sf_limit %d bytes_limit %d\n", ++ agglimit, config.aggr_param.maxrxsf, config.aggr_param.maxrxsize)); ++ if (bcm_rpc_tp_set_config(dhd->pub.info->rpc_th, &config)) { ++ DHD_ERROR(("set tx/rx queue size and buffersize failed\n")); ++ } ++ } else { ++ DHD_ERROR(("get rpc_dngl_agglimit failed\n")); ++ rpc_agg &= ~BCM_RPC_TP_DNGL_AGG_DPC; ++ } ++ ++ /* Set aggregation for TX */ ++ bcm_rpc_tp_agg_set(dhd->pub.info->rpc_th, BCM_RPC_TP_HOST_AGG_MASK, ++ rpc_agg & BCM_RPC_TP_HOST_AGG_MASK); ++ ++ /* Set aggregation for RX */ ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ bcm_mkiovar("rpc_agg", (char *)&rpc_agg, sizeof(rpc_agg), iovbuf, sizeof(iovbuf)); ++ if (!dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) { ++ dhd->pub.info->fdaggr = 0; ++ if (rpc_agg & BCM_RPC_TP_HOST_AGG_MASK) ++ dhd->pub.info->fdaggr |= BCM_FDAGGR_H2D_ENABLED; ++ if (rpc_agg & BCM_RPC_TP_DNGL_AGG_MASK) ++ dhd->pub.info->fdaggr |= BCM_FDAGGR_D2H_ENABLED; ++ } else { ++ DHD_ERROR(("%s(): Setting RX aggregation failed %d\n", __FUNCTION__, ret)); ++ } ++#endif /* BCM_FD_AGGR */ ++ ++#ifdef BT_OVER_SDIO ++ if (dhd->pub.is_bt_recovery_required) { ++ DHD_ERROR(("%s: Send Hang Notification 2 to BT\n", __FUNCTION__)); ++ bcmsdh_btsdio_process_dhd_hang_notification(TRUE); ++ } ++ dhd->pub.is_bt_recovery_required = FALSE; ++#endif ++ ++ /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */ ++ memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); ++ ++#ifdef TOE ++ /* Get current TOE mode from dongle */ ++ if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) { ++ dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; ++ } else { ++ dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; ++ } ++#endif /* TOE */ ++ ++#if defined(DHD_LB_RXP) ++ __skb_queue_head_init(&dhd->rx_pend_queue); ++ if (dhd->rx_napi_netdev == NULL) { ++ dhd->rx_napi_netdev = dhd->iflist[ifidx]->net; ++ memset(&dhd->rx_napi_struct, 0, sizeof(struct napi_struct)); ++ netif_napi_add(dhd->rx_napi_netdev, &dhd->rx_napi_struct, ++ dhd_napi_poll, dhd_napi_weight); ++ DHD_INFO(("%s napi<%p> enabled ifp->net<%p,%s>\n", ++ __FUNCTION__, &dhd->rx_napi_struct, net, net->name)); ++ napi_enable(&dhd->rx_napi_struct); ++ DHD_INFO(("%s load balance init rx_napi_struct\n", __FUNCTION__)); ++ skb_queue_head_init(&dhd->rx_napi_queue); ++ } /* rx_napi_netdev == NULL */ ++#endif /* DHD_LB_RXP */ ++ ++#if defined(DHD_LB_TXP) ++ /* Use the variant that uses locks */ ++ skb_queue_head_init(&dhd->tx_pend_queue); ++#endif /* DHD_LB_TXP */ ++ ++#if defined(WL_CFG80211) ++ if (unlikely(wl_cfg80211_up(net))) { ++ DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); ++ ret = -1; ++ goto exit; ++ } ++ if (!dhd_download_fw_on_driverload) { ++#ifdef ARP_OFFLOAD_SUPPORT ++ dhd->pend_ipaddr = 0; ++ if (!dhd_inetaddr_notifier_registered) { ++ dhd_inetaddr_notifier_registered = TRUE; ++ register_inetaddr_notifier(&dhd_inetaddr_notifier); ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) ++ if (!dhd_inet6addr_notifier_registered) { ++ dhd_inet6addr_notifier_registered = TRUE; ++ register_inet6addr_notifier(&dhd_inet6addr_notifier); ++ } ++#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ ++ } ++ ++ argos_register_notifier_init(net); ++#if defined(NUM_SCB_MAX_PROBE) ++ dhd_set_scb_probe(&dhd->pub); ++#endif /* NUM_SCB_MAX_PROBE */ ++#endif /* WL_CFG80211 */ ++#if defined(WL_WIRELESS_EXT) ++ if (unlikely(wl_iw_up(net, &dhd->pub))) { ++ DHD_ERROR(("%s: failed to bring up wext\n", __FUNCTION__)); ++ ret = -1; ++ goto exit; ++ } ++#endif ++#ifdef WL_ESCAN ++ if (unlikely(wl_escan_up(net, &dhd->pub))) { ++ DHD_ERROR(("%s: failed to bring up escan\n", __FUNCTION__)); ++ ret = -1; ++ goto exit; ++ } ++#endif /* WL_ESCAN */ ++#if defined(ISAM_PREINIT) ++ if (!dhd_download_fw_on_driverload) { ++ if (dhd->pub.conf) { ++ wl_android_ext_priv_cmd(net, dhd->pub.conf->isam_init, 0, &bytes_written); ++ wl_android_ext_priv_cmd(net, dhd->pub.conf->isam_config, 0, &bytes_written); ++ wl_android_ext_priv_cmd(net, dhd->pub.conf->isam_enable, 0, &bytes_written); ++ } ++ } ++#endif ++ } ++ ++ /* Allow transmit calls */ ++ netif_start_queue(net); ++ dhd->pub.up = 1; ++ ++ OLD_MOD_INC_USE_COUNT; ++ ++#ifdef BCMDBGFS ++ dhd_dbgfs_init(&dhd->pub); ++#endif ++ ++exit: ++ if (ret) { ++ dhd_stop(net); ++ } ++ ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ DHD_MUTEX_UNLOCK(); ++ ++ printf("%s: Exit ret=%d\n", __FUNCTION__, ret); ++ return ret; ++} ++ ++int dhd_do_driver_init(struct net_device *net) ++{ ++ dhd_info_t *dhd = NULL; ++ ++ if (!net) { ++ DHD_ERROR(("Primary Interface not initialized \n")); ++ return -EINVAL; ++ } ++ ++ DHD_MUTEX_IS_LOCK_RETURN(); ++ ++ /* && defined(OEM_ANDROID) && defined(BCMSDIO) */ ++ dhd = DHD_DEV_INFO(net); ++ ++ /* If driver is already initialized, do nothing ++ */ ++ if (dhd->pub.busstate == DHD_BUS_DATA) { ++ DHD_TRACE(("Driver already Inititalized. Nothing to do")); ++ return 0; ++ } ++ ++ if (dhd_open(net) < 0) { ++ DHD_ERROR(("Driver Init Failed \n")); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int ++dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) ++{ ++ ++#ifdef WL_CFG80211 ++ if (wl_cfg80211_notify_ifadd(dhd_linux_get_primary_netdev(&dhdinfo->pub), ++ ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) ++ return BCME_OK; ++#endif ++ ++ /* handle IF event caused by wl commands, SoftAP, WEXT and ++ * anything else. This has to be done asynchronously otherwise ++ * DPC will be blocked (and iovars will timeout as DPC has no chance ++ * to read the response back) ++ */ ++ if (ifevent->ifidx > 0) { ++ dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); ++ if (if_event == NULL) { ++ DHD_ERROR(("dhd_event_ifadd: Failed MALLOC, malloced %d bytes", ++ MALLOCED(dhdinfo->pub.osh))); ++ return BCME_NOMEM; ++ } ++ ++ memcpy(&if_event->event, ifevent, sizeof(if_event->event)); ++ memcpy(if_event->mac, mac, ETHER_ADDR_LEN); ++ strncpy(if_event->name, name, IFNAMSIZ); ++ if_event->name[IFNAMSIZ - 1] = '\0'; ++ dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, ++ DHD_WQ_WORK_IF_ADD, dhd_ifadd_event_handler, DHD_WQ_WORK_PRIORITY_LOW); ++ } ++ ++ return BCME_OK; ++} ++ ++int ++dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) ++{ ++ dhd_if_event_t *if_event; ++ ++#ifdef WL_CFG80211 ++ if (wl_cfg80211_notify_ifdel(dhd_linux_get_primary_netdev(&dhdinfo->pub), ++ ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) ++ return BCME_OK; ++#endif /* WL_CFG80211 */ ++ ++ /* handle IF event caused by wl commands, SoftAP, WEXT and ++ * anything else ++ */ ++ if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); ++ if (if_event == NULL) { ++ DHD_ERROR(("dhd_event_ifdel: malloc failed for if_event, malloced %d bytes", ++ MALLOCED(dhdinfo->pub.osh))); ++ return BCME_NOMEM; ++ } ++ memcpy(&if_event->event, ifevent, sizeof(if_event->event)); ++ memcpy(if_event->mac, mac, ETHER_ADDR_LEN); ++ strncpy(if_event->name, name, IFNAMSIZ); ++ if_event->name[IFNAMSIZ - 1] = '\0'; ++ dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_DEL, ++ dhd_ifdel_event_handler, DHD_WQ_WORK_PRIORITY_LOW); ++ ++ return BCME_OK; ++} ++ ++int ++dhd_event_ifchange(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) ++{ ++#ifdef DHD_UPDATE_INTF_MAC ++ dhd_if_event_t *if_event; ++#endif /* DHD_UPDATE_INTF_MAC */ ++ ++#ifdef WL_CFG80211 ++ wl_cfg80211_notify_ifchange(dhd_linux_get_primary_netdev(&dhdinfo->pub), ++ ifevent->ifidx, name, mac, ifevent->bssidx); ++#endif /* WL_CFG80211 */ ++ ++#ifdef DHD_UPDATE_INTF_MAC ++ /* handle IF event caused by wl commands, SoftAP, WEXT, MBSS and ++ * anything else ++ */ ++ if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); ++ if (if_event == NULL) { ++ DHD_ERROR(("dhd_event_ifdel: malloc failed for if_event, malloced %d bytes", ++ MALLOCED(dhdinfo->pub.osh))); ++ return BCME_NOMEM; ++ } ++ memcpy(&if_event->event, ifevent, sizeof(if_event->event)); ++ // construct a change event ++ if_event->event.ifidx = dhd_ifname2idx(dhdinfo, name); ++ if_event->event.opcode = WLC_E_IF_CHANGE; ++ memcpy(if_event->mac, mac, ETHER_ADDR_LEN); ++ strncpy(if_event->name, name, IFNAMSIZ); ++ if_event->name[IFNAMSIZ - 1] = '\0'; ++ dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_UPDATE, ++ dhd_ifupdate_event_handler, DHD_WQ_WORK_PRIORITY_LOW); ++#endif /* DHD_UPDATE_INTF_MAC */ ++ ++ return BCME_OK; ++} ++ ++/* unregister and free the existing net_device interface (if any) in iflist and ++ * allocate a new one. the slot is reused. this function does NOT register the ++ * new interface to linux kernel. dhd_register_if does the job ++ */ ++struct net_device* ++dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, const char *name, ++ uint8 *mac, uint8 bssidx, bool need_rtnl_lock, const char *dngl_name) ++{ ++ dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS)); ++ ifp = dhdinfo->iflist[ifidx]; ++ ++ if (ifp != NULL) { ++ if (ifp->net != NULL) { ++ DHD_ERROR(("%s: free existing IF %s ifidx:%d \n", ++ __FUNCTION__, ifp->net->name, ifidx)); ++ ++ if (ifidx == 0) { ++ /* For primary ifidx (0), there shouldn't be ++ * any netdev present already. ++ */ ++ DHD_ERROR(("Primary ifidx populated already\n")); ++ ASSERT(0); ++ return NULL; ++ } ++ ++ dhd_dev_priv_clear(ifp->net); /* clear net_device private */ ++ ++ /* in unregister_netdev case, the interface gets freed by net->destructor ++ * (which is set to free_netdev) ++ */ ++ if (ifp->net->reg_state == NETREG_UNINITIALIZED) { ++ free_netdev(ifp->net); ++ } else { ++ netif_stop_queue(ifp->net); ++ if (need_rtnl_lock) ++ unregister_netdev(ifp->net); ++ else ++ unregister_netdevice(ifp->net); ++ } ++ ifp->net = NULL; ++ } ++ } else { ++ ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t)); ++ if (ifp == NULL) { ++ DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t))); ++ return NULL; ++ } ++ } ++ ++ memset(ifp, 0, sizeof(dhd_if_t)); ++ ifp->info = dhdinfo; ++ ifp->idx = ifidx; ++ ifp->bssidx = bssidx; ++#ifdef DHD_MCAST_REGEN ++ ifp->mcast_regen_bss_enable = FALSE; ++#endif ++ /* set to TRUE rx_pkt_chainable at alloc time */ ++ ifp->rx_pkt_chainable = TRUE; ++ ++ if (mac != NULL) ++ memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN); ++ ++ /* Allocate etherdev, including space for private structure */ ++ ifp->net = alloc_etherdev(DHD_DEV_PRIV_SIZE); ++ if (ifp->net == NULL) { ++ DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo))); ++ goto fail; ++ } ++ ++ /* Setup the dhd interface's netdevice private structure. */ ++ dhd_dev_priv_save(ifp->net, dhdinfo, ifp, ifidx); ++ ++ if (name && name[0]) { ++ strncpy(ifp->net->name, name, IFNAMSIZ); ++ ifp->net->name[IFNAMSIZ - 1] = '\0'; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 9)) ++#define IFP_NET_DESTRUCTOR ifp->net->priv_destructor ++#else ++#define IFP_NET_DESTRUCTOR ifp->net->destructor ++#endif // endif ++ ++#ifdef WL_CFG80211 ++ if (ifidx == 0) { ++ IFP_NET_DESTRUCTOR = free_netdev; ++ } else { ++ IFP_NET_DESTRUCTOR = dhd_netdev_free; ++ } ++#else ++ IFP_NET_DESTRUCTOR = free_netdev; ++#endif /* WL_CFG80211 */ ++ strncpy(ifp->name, ifp->net->name, IFNAMSIZ); ++ ifp->name[IFNAMSIZ - 1] = '\0'; ++ dhdinfo->iflist[ifidx] = ifp; ++ ++/* initialize the dongle provided if name */ ++ if (dngl_name) ++ strncpy(ifp->dngl_name, dngl_name, IFNAMSIZ); ++ else if (name) ++ strncpy(ifp->dngl_name, name, IFNAMSIZ); ++ ++#ifdef PCIE_FULL_DONGLE ++ /* Initialize STA info list */ ++ INIT_LIST_HEAD(&ifp->sta_list); ++ DHD_IF_STA_LIST_LOCK_INIT(ifp); ++#endif /* PCIE_FULL_DONGLE */ ++ ++#ifdef DHD_L2_FILTER ++ ifp->phnd_arp_table = init_l2_filter_arp_table(dhdpub->osh); ++ ifp->parp_allnode = TRUE; ++#endif /* DHD_L2_FILTER */ ++ ++ ++ DHD_CUMM_CTR_INIT(&ifp->cumm_ctr); ++ ++ return ifp->net; ++ ++fail: ++ if (ifp != NULL) { ++ if (ifp->net != NULL) { ++#if defined(DHD_LB_RXP) && defined(PCIE_FULL_DONGLE) ++ if (ifp->net == dhdinfo->rx_napi_netdev) { ++ napi_disable(&dhdinfo->rx_napi_struct); ++ netif_napi_del(&dhdinfo->rx_napi_struct); ++ skb_queue_purge(&dhdinfo->rx_napi_queue); ++ dhdinfo->rx_napi_netdev = NULL; ++ } ++#endif /* DHD_LB_RXP && PCIE_FULL_DONGLE */ ++ dhd_dev_priv_clear(ifp->net); ++ free_netdev(ifp->net); ++ ifp->net = NULL; ++ } ++ MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); ++ ifp = NULL; ++ } ++ dhdinfo->iflist[ifidx] = NULL; ++ return NULL; ++} ++ ++/* unregister and free the the net_device interface associated with the indexed ++ * slot, also free the slot memory and set the slot pointer to NULL ++ */ ++int ++dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock) ++{ ++ dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; ++ dhd_if_t *ifp; ++#ifdef PCIE_FULL_DONGLE ++ if_flow_lkup_t *if_flow_lkup = (if_flow_lkup_t *)dhdpub->if_flow_lkup; ++#endif /* PCIE_FULL_DONGLE */ ++ ++ ifp = dhdinfo->iflist[ifidx]; ++ ++ if (ifp != NULL) { ++ if (ifp->net != NULL) { ++ DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx)); ++ ++ dhdinfo->iflist[ifidx] = NULL; ++ /* in unregister_netdev case, the interface gets freed by net->destructor ++ * (which is set to free_netdev) ++ */ ++ if (ifp->net->reg_state == NETREG_UNINITIALIZED) { ++ free_netdev(ifp->net); ++ } else { ++ netif_tx_disable(ifp->net); ++ ++ ++ ++#if defined(SET_RPS_CPUS) ++ custom_rps_map_clear(ifp->net->_rx); ++#endif /* SET_RPS_CPUS */ ++ if (need_rtnl_lock) ++ unregister_netdev(ifp->net); ++ else ++ unregister_netdevice(ifp->net); ++#if defined(WL_EXT_IAPSTA) || defined(USE_IW) || defined(WL_ESCAN) ++#ifdef WL_EXT_IAPSTA ++ wl_ext_iapsta_dettach_netdev(ifp->net, ifidx); ++#endif /* WL_EXT_IAPSTA */ ++#ifdef WL_ESCAN ++ wl_escan_event_dettach(ifp->net, dhdpub); ++#endif /* WL_ESCAN */ ++ wl_ext_event_dettach_netdev(ifp->net, ifidx); ++#endif /* WL_EXT_IAPSTA || USE_IW || WL_ESCAN */ ++ } ++ ifp->net = NULL; ++ } ++#ifdef DHD_WMF ++ dhd_wmf_cleanup(dhdpub, ifidx); ++#endif /* DHD_WMF */ ++#ifdef DHD_L2_FILTER ++ bcm_l2_filter_arp_table_update(dhdpub->osh, ifp->phnd_arp_table, TRUE, ++ NULL, FALSE, dhdpub->tickcnt); ++ deinit_l2_filter_arp_table(dhdpub->osh, ifp->phnd_arp_table); ++ ifp->phnd_arp_table = NULL; ++#endif /* DHD_L2_FILTER */ ++ ++ ++ dhd_if_del_sta_list(ifp); ++#ifdef PCIE_FULL_DONGLE ++ /* Delete flowrings of WDS interface */ ++ if (if_flow_lkup[ifidx].role == WLC_E_IF_ROLE_WDS) { ++ dhd_flow_rings_delete(dhdpub, ifidx); ++ } ++#endif /* PCIE_FULL_DONGLE */ ++ DHD_CUMM_CTR_INIT(&ifp->cumm_ctr); ++ ++ MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); ++ ifp = NULL; ++ } ++ ++ return BCME_OK; ++} ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++static struct net_device_ops dhd_ops_pri = { ++ .ndo_open = dhd_open, ++ .ndo_stop = dhd_stop, ++ .ndo_get_stats = dhd_get_stats, ++ .ndo_do_ioctl = dhd_ioctl_entry, ++ .ndo_start_xmit = dhd_start_xmit, ++ .ndo_set_mac_address = dhd_set_mac_address, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ .ndo_set_rx_mode = dhd_set_multicast_list, ++#else ++ .ndo_set_multicast_list = dhd_set_multicast_list, ++#endif ++}; ++ ++static struct net_device_ops dhd_ops_virt = { ++ .ndo_get_stats = dhd_get_stats, ++ .ndo_do_ioctl = dhd_ioctl_entry, ++ .ndo_start_xmit = dhd_start_xmit, ++ .ndo_set_mac_address = dhd_set_mac_address, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ .ndo_set_rx_mode = dhd_set_multicast_list, ++#else ++ .ndo_set_multicast_list = dhd_set_multicast_list, ++#endif ++}; ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ ++ ++#ifdef DEBUGGER ++extern void debugger_init(void *bus_handle); ++#endif ++ ++ ++#ifdef SHOW_LOGTRACE ++int ++dhd_os_read_file(void *file, char *buf, uint32 size) ++{ ++ struct file *filep = (struct file *)file; ++ ++ if (!file || !buf) ++ return -1; ++ ++ return vfs_read(filep, buf, size, &filep->f_pos); ++} ++ ++int ++dhd_os_seek_file(void *file, int64 offset) ++{ ++ struct file *filep = (struct file *)file; ++ if (!file) ++ return -1; ++ ++ /* offset can be -ve */ ++ filep->f_pos = filep->f_pos + offset; ++ ++ return 0; ++} ++ ++static int ++dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) ++{ ++ struct file *filep = NULL; ++ struct kstat stat; ++ mm_segment_t fs; ++ char *raw_fmts = NULL; ++ int logstrs_size = 0; ++ int error = 0; ++ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ filep = filp_open(logstrs_path, O_RDONLY, 0); ++ ++ if (IS_ERR(filep)) { ++ DHD_ERROR(("%s: Failed to open the file %s \n", __FUNCTION__, logstrs_path)); ++ goto fail; ++ } ++ error = vfs_stat(logstrs_path, &stat); ++ if (error) { ++ DHD_ERROR(("%s: Failed to stat file %s \n", __FUNCTION__, logstrs_path)); ++ goto fail; ++ } ++ logstrs_size = (int) stat.size; ++ ++ if (logstrs_size == 0) { ++ DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__)); ++ goto fail1; ++ } ++ ++ raw_fmts = MALLOC(osh, logstrs_size); ++ if (raw_fmts == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory \n", __FUNCTION__)); ++ goto fail; ++ } ++ if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) != logstrs_size) { ++ DHD_ERROR(("%s: Failed to read file %s\n", __FUNCTION__, logstrs_path)); ++ goto fail; ++ } ++ ++ if (dhd_parse_logstrs_file(osh, raw_fmts, logstrs_size, temp) ++ == BCME_OK) { ++ filp_close(filep, NULL); ++ set_fs(fs); ++ return BCME_OK; ++ } ++ ++fail: ++ if (raw_fmts) { ++ MFREE(osh, raw_fmts, logstrs_size); ++ raw_fmts = NULL; ++ } ++ ++fail1: ++ if (!IS_ERR(filep)) ++ filp_close(filep, NULL); ++ ++ set_fs(fs); ++ temp->fmts = NULL; ++ return BCME_ERROR; ++} ++ ++static int ++dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, ++ uint32 *rodata_end) ++{ ++ struct file *filep = NULL; ++ mm_segment_t fs; ++ int err = BCME_ERROR; ++ ++ if (fname == NULL) { ++ DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ filep = filp_open(fname, O_RDONLY, 0); ++ if (IS_ERR(filep)) { ++ DHD_ERROR(("%s: Failed to open %s \n", __FUNCTION__, fname)); ++ goto fail; ++ } ++ ++ if ((err = dhd_parse_map_file(osh, filep, ramstart, ++ rodata_start, rodata_end)) < 0) ++ goto fail; ++ ++fail: ++ if (!IS_ERR(filep)) ++ filp_close(filep, NULL); ++ ++ set_fs(fs); ++ ++ return err; ++} ++ ++static int ++dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, char *map_file) ++{ ++ struct file *filep = NULL; ++ mm_segment_t fs; ++ char *raw_fmts = NULL; ++ uint32 logstrs_size = 0; ++ ++ int error = 0; ++ uint32 ramstart = 0; ++ uint32 rodata_start = 0; ++ uint32 rodata_end = 0; ++ uint32 logfilebase = 0; ++ ++ error = dhd_read_map(osh, map_file, &ramstart, &rodata_start, &rodata_end); ++ if (error != BCME_OK) { ++ DHD_ERROR(("readmap Error!! \n")); ++ /* don't do event log parsing in actual case */ ++ if (strstr(str_file, ram_file_str) != NULL) { ++ temp->raw_sstr = NULL; ++ } else if (strstr(str_file, rom_file_str) != NULL) { ++ temp->rom_raw_sstr = NULL; ++ } ++ return error; ++ } ++ DHD_ERROR(("ramstart: 0x%x, rodata_start: 0x%x, rodata_end:0x%x\n", ++ ramstart, rodata_start, rodata_end)); ++ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ filep = filp_open(str_file, O_RDONLY, 0); ++ if (IS_ERR(filep)) { ++ DHD_ERROR(("%s: Failed to open the file %s \n", __FUNCTION__, str_file)); ++ goto fail; ++ } ++ ++ /* Full file size is huge. Just read required part */ ++ logstrs_size = rodata_end - rodata_start; ++ ++ if (logstrs_size == 0) { ++ DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__)); ++ goto fail1; ++ } ++ ++ raw_fmts = MALLOC(osh, logstrs_size); ++ if (raw_fmts == NULL) { ++ DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ logfilebase = rodata_start - ramstart; ++ ++ error = generic_file_llseek(filep, logfilebase, SEEK_SET); ++ if (error < 0) { ++ DHD_ERROR(("%s: %s llseek failed %d \n", __FUNCTION__, str_file, error)); ++ goto fail; ++ } ++ ++ error = vfs_read(filep, raw_fmts, logstrs_size, (&filep->f_pos)); ++ if (error != logstrs_size) { ++ DHD_ERROR(("%s: %s read failed %d \n", __FUNCTION__, str_file, error)); ++ goto fail; ++ } ++ ++ if (strstr(str_file, ram_file_str) != NULL) { ++ temp->raw_sstr = raw_fmts; ++ temp->raw_sstr_size = logstrs_size; ++ temp->ramstart = ramstart; ++ temp->rodata_start = rodata_start; ++ temp->rodata_end = rodata_end; ++ } else if (strstr(str_file, rom_file_str) != NULL) { ++ temp->rom_raw_sstr = raw_fmts; ++ temp->rom_raw_sstr_size = logstrs_size; ++ temp->rom_ramstart = ramstart; ++ temp->rom_rodata_start = rodata_start; ++ temp->rom_rodata_end = rodata_end; ++ } ++ ++ filp_close(filep, NULL); ++ set_fs(fs); ++ ++ return BCME_OK; ++ ++fail: ++ if (raw_fmts) { ++ MFREE(osh, raw_fmts, logstrs_size); ++ raw_fmts = NULL; ++ } ++ ++fail1: ++ if (!IS_ERR(filep)) ++ filp_close(filep, NULL); ++ ++ set_fs(fs); ++ ++ if (strstr(str_file, ram_file_str) != NULL) { ++ temp->raw_sstr = NULL; ++ } else if (strstr(str_file, rom_file_str) != NULL) { ++ temp->rom_raw_sstr = NULL; ++ } ++ ++ return error; ++} ++ ++#endif /* SHOW_LOGTRACE */ ++ ++#ifdef BCMDBUS ++uint ++dhd_get_rxsz(dhd_pub_t *pub) ++{ ++ struct net_device *net = NULL; ++ dhd_info_t *dhd = NULL; ++ uint rxsz; ++ ++ /* Assign rxsz for dbus_attach */ ++ dhd = pub->info; ++ net = dhd->iflist[0]->net; ++ net->hard_header_len = ETH_HLEN + pub->hdrlen; ++ rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); ++ ++ return rxsz; ++} ++ ++void ++dhd_set_path(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = NULL; ++ ++ dhd = pub->info; ++ ++ /* try to download image and nvram to the dongle */ ++ if (dhd_update_fw_nv_path(dhd) && dhd->pub.bus) { ++ DHD_INFO(("%s: fw %s, nv %s, conf %s\n", ++ __FUNCTION__, dhd->fw_path, dhd->nv_path, dhd->conf_path)); ++ dhd_bus_update_fw_nv_path(dhd->pub.bus, ++ dhd->fw_path, dhd->nv_path, dhd->clm_path, dhd->conf_path); ++ } ++} ++#endif ++ ++dhd_pub_t * ++dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen ++#ifdef BCMDBUS ++ , void *data ++#endif ++) ++{ ++ dhd_info_t *dhd = NULL; ++ struct net_device *net = NULL; ++ char if_name[IFNAMSIZ] = {'\0'}; ++#ifdef SHOW_LOGTRACE ++ int ret; ++#endif /* SHOW_LOGTRACE */ ++#if defined(BCMSDIO) || defined(BCMPCIE) ++ uint32 bus_type = -1; ++ uint32 bus_num = -1; ++ uint32 slot_num = -1; ++ wifi_adapter_info_t *adapter = NULL; ++#elif defined(BCMDBUS) ++ wifi_adapter_info_t *adapter = data; ++#endif ++#ifdef GET_CUSTOM_MAC_ENABLE ++ char hw_ether[62]; ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++ dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++#ifdef STBLINUX ++ DHD_ERROR(("%s\n", driver_target)); ++#endif /* STBLINUX */ ++ /* will implement get_ids for DBUS later */ ++#if defined(BCMSDIO) ++ dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num); ++#endif ++#if defined(BCMSDIO) || defined(BCMPCIE) ++ adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); ++#endif ++ ++ /* Allocate primary dhd_info */ ++ dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t)); ++ if (dhd == NULL) { ++ dhd = MALLOC(osh, sizeof(dhd_info_t)); ++ if (dhd == NULL) { ++ DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); ++ goto dhd_null_flag; ++ } ++ } ++ memset(dhd, 0, sizeof(dhd_info_t)); ++ dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; ++ ++ dhd->unit = dhd_found + instance_base; /* do not increment dhd_found, yet */ ++ ++ dhd->pub.osh = osh; ++#ifdef DUMP_IOCTL_IOV_LIST ++ dll_init(&(dhd->pub.dump_iovlist_head)); ++#endif /* DUMP_IOCTL_IOV_LIST */ ++ dhd->adapter = adapter; ++ dhd->pub.adapter = (void *)adapter; ++#ifdef DHD_DEBUG ++ dll_init(&(dhd->pub.mw_list_head)); ++#endif /* DHD_DEBUG */ ++#ifdef BT_OVER_SDIO ++ dhd->pub.is_bt_recovery_required = FALSE; ++ mutex_init(&dhd->bus_user_lock); ++#endif /* BT_OVER_SDIO */ ++ ++#ifdef GET_CUSTOM_MAC_ENABLE ++ wifi_platform_get_mac_addr(dhd->adapter, hw_ether); ++ bcopy(hw_ether, dhd->pub.mac.octet, sizeof(struct ether_addr)); ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++#ifdef CUSTOM_FORCE_NODFS_FLAG ++ dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; ++ dhd->pub.force_country_change = TRUE; ++#endif /* CUSTOM_FORCE_NODFS_FLAG */ ++#ifdef CUSTOM_COUNTRY_CODE ++ get_customized_country_code(dhd->adapter, ++ dhd->pub.dhd_cspec.country_abbrev, &dhd->pub.dhd_cspec, ++ dhd->pub.dhd_cflags); ++#endif /* CUSTOM_COUNTRY_CODE */ ++#ifndef BCMDBUS ++ dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; ++ dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; ++#ifdef DHD_WET ++ dhd->pub.wet_info = dhd_get_wet_info(&dhd->pub); ++#endif /* DHD_WET */ ++ /* Initialize thread based operation and lock */ ++ sema_init(&dhd->sdsem, 1); ++#endif /* !BCMDBUS */ ++ ++ /* Link to info module */ ++ dhd->pub.info = dhd; ++ ++ ++ /* Link to bus module */ ++ dhd->pub.bus = bus; ++ dhd->pub.hdrlen = bus_hdrlen; ++ ++ /* dhd_conf must be attached after linking dhd to dhd->pub.info, ++ * because dhd_detech will check .info is NULL or not. ++ */ ++ if (dhd_conf_attach(&dhd->pub) != 0) { ++ DHD_ERROR(("dhd_conf_attach failed\n")); ++ goto fail; ++ } ++#ifndef BCMDBUS ++ dhd_conf_reset(&dhd->pub); ++ dhd_conf_set_chiprev(&dhd->pub, dhd_bus_chip(bus), dhd_bus_chiprev(bus)); ++ dhd_conf_preinit(&dhd->pub); ++#endif /* !BCMDBUS */ ++ ++ /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name. ++ * This is indeed a hack but we have to make it work properly before we have a better ++ * solution ++ */ ++ dhd_update_fw_nv_path(dhd); ++ ++ /* Set network interface name if it was provided as module parameter */ ++ if (iface_name[0]) { ++ int len; ++ char ch; ++ strncpy(if_name, iface_name, IFNAMSIZ); ++ if_name[IFNAMSIZ - 1] = 0; ++ len = strlen(if_name); ++ ch = if_name[len - 1]; ++ if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) ++ strncat(if_name, "%d", 2); ++ } ++ ++ /* Passing NULL to dngl_name to ensure host gets if_name in dngl_name member */ ++ net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE, NULL); ++ if (net == NULL) { ++ goto fail; ++ } ++ ++ ++ dhd_state |= DHD_ATTACH_STATE_ADD_IF; ++#ifdef DHD_L2_FILTER ++ /* initialize the l2_filter_cnt */ ++ dhd->pub.l2_filter_cnt = 0; ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ net->open = NULL; ++#else ++ net->netdev_ops = NULL; ++#endif ++ ++ mutex_init(&dhd->dhd_iovar_mutex); ++ sema_init(&dhd->proto_sem, 1); ++#ifdef DHD_ULP ++ if (!(dhd_ulp_init(osh, &dhd->pub))) ++ goto fail; ++#endif /* DHD_ULP */ ++ ++#if defined(DHD_HANG_SEND_UP_TEST) ++ dhd->pub.req_hang_type = 0; ++#endif /* DHD_HANG_SEND_UP_TEST */ ++ ++#ifdef PROP_TXSTATUS ++ spin_lock_init(&dhd->wlfc_spinlock); ++ ++ dhd->pub.skip_fc = dhd_wlfc_skip_fc; ++ dhd->pub.plat_init = dhd_wlfc_plat_init; ++ dhd->pub.plat_deinit = dhd_wlfc_plat_deinit; ++ ++#ifdef DHD_WLFC_THREAD ++ init_waitqueue_head(&dhd->pub.wlfc_wqhead); ++ dhd->pub.wlfc_thread = kthread_create(dhd_wlfc_transfer_packets, &dhd->pub, "wlfc-thread"); ++ if (IS_ERR(dhd->pub.wlfc_thread)) { ++ DHD_ERROR(("create wlfc thread failed\n")); ++ goto fail; ++ } else { ++ wake_up_process(dhd->pub.wlfc_thread); ++ } ++#endif /* DHD_WLFC_THREAD */ ++#endif /* PROP_TXSTATUS */ ++ ++ /* Initialize other structure content */ ++ init_waitqueue_head(&dhd->ioctl_resp_wait); ++ init_waitqueue_head(&dhd->d3ack_wait); ++#ifdef PCIE_INB_DW ++ init_waitqueue_head(&dhd->ds_exit_wait); ++#endif /* PCIE_INB_DW */ ++ init_waitqueue_head(&dhd->ctrl_wait); ++ init_waitqueue_head(&dhd->dhd_bus_busy_state_wait); ++ dhd->pub.dhd_bus_busy_state = 0; ++ ++ /* Initialize the spinlocks */ ++ spin_lock_init(&dhd->sdlock); ++ spin_lock_init(&dhd->txqlock); ++ spin_lock_init(&dhd->rxqlock); ++ spin_lock_init(&dhd->dhd_lock); ++ spin_lock_init(&dhd->rxf_lock); ++#ifdef WLTDLS ++ spin_lock_init(&dhd->pub.tdls_lock); ++#endif /* WLTDLS */ ++#if defined(RXFRAME_THREAD) ++ dhd->rxthread_enabled = TRUE; ++#endif /* defined(RXFRAME_THREAD) */ ++ ++#ifdef DHDTCPACK_SUPPRESS ++ spin_lock_init(&dhd->tcpack_lock); ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++ /* Initialize Wakelock stuff */ ++ spin_lock_init(&dhd->wakelock_spinlock); ++ spin_lock_init(&dhd->wakelock_evt_spinlock); ++ DHD_OS_WAKE_LOCK_INIT(dhd); ++ dhd->wakelock_counter = 0; ++#ifdef CONFIG_HAS_WAKELOCK ++ // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry ++ wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); ++ wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake"); ++#endif /* CONFIG_HAS_WAKELOCK */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ mutex_init(&dhd->dhd_net_if_mutex); ++ mutex_init(&dhd->dhd_suspend_mutex); ++#if defined(PKT_FILTER_SUPPORT) && defined(APF) ++ mutex_init(&dhd->dhd_apf_mutex); ++#endif /* PKT_FILTER_SUPPORT && APF */ ++#endif ++ dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; ++ ++ /* Attach and link in the protocol */ ++ if (dhd_prot_attach(&dhd->pub) != 0) { ++ DHD_ERROR(("dhd_prot_attach failed\n")); ++ goto fail; ++ } ++ dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; ++ ++#ifdef DHD_TIMESYNC ++ /* attach the timesync module */ ++ if (dhd_timesync_attach(&dhd->pub) != 0) { ++ DHD_ERROR(("dhd_timesync_attach failed\n")); ++ goto fail; ++ } ++ dhd_state |= DHD_ATTACH_TIMESYNC_ATTACH_DONE; ++#endif /* DHD_TIMESYNC */ ++ ++#ifdef WL_CFG80211 ++ spin_lock_init(&dhd->pub.up_lock); ++ /* Attach and link in the cfg80211 */ ++ if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { ++ DHD_ERROR(("wl_cfg80211_attach failed\n")); ++ goto fail; ++ } ++ ++ dhd_monitor_init(&dhd->pub); ++ dhd_state |= DHD_ATTACH_STATE_CFG80211; ++#endif ++#ifdef DHD_LOG_DUMP ++ dhd_log_dump_init(&dhd->pub); ++#endif /* DHD_LOG_DUMP */ ++#if defined(WL_EXT_IAPSTA) || defined(USE_IW) || defined(WL_ESCAN) ++ if (wl_ext_event_attach(net, &dhd->pub) != 0) { ++ DHD_ERROR(("wl_ext_event_attach failed\n")); ++ goto fail; ++ } ++#ifdef WL_ESCAN ++ /* Attach and link in the escan */ ++ if (wl_escan_attach(net, &dhd->pub) != 0) { ++ DHD_ERROR(("wl_escan_attach failed\n")); ++ goto fail; ++ } ++#endif /* WL_ESCAN */ ++#ifdef WL_EXT_IAPSTA ++ if (wl_ext_iapsta_attach(&dhd->pub) != 0) { ++ DHD_ERROR(("wl_ext_iapsta_attach failed\n")); ++ goto fail; ++ } ++#endif /* WL_EXT_IAPSTA */ ++#endif /* WL_EXT_IAPSTA || USE_IW || WL_ESCAN */ ++#if defined(WL_WIRELESS_EXT) ++ /* Attach and link in the iw */ ++ if (wl_iw_attach(net, &dhd->pub) != 0) { ++ DHD_ERROR(("wl_iw_attach failed\n")); ++ goto fail; ++ } ++ dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; ++#endif /* defined(WL_WIRELESS_EXT) */ ++ ++#ifdef SHOW_LOGTRACE ++ ret = dhd_init_logstrs_array(osh, &dhd->event_data); ++ if (ret == BCME_OK) { ++ dhd_init_static_strs_array(osh, &dhd->event_data, st_str_file_path, map_file_path); ++ dhd_init_static_strs_array(osh, &dhd->event_data, rom_st_str_file_path, ++ rom_map_file_path); ++ dhd_state |= DHD_ATTACH_LOGTRACE_INIT; ++ } ++#endif /* SHOW_LOGTRACE */ ++ ++#ifdef DEBUGABILITY ++ /* attach debug if support */ ++ if (dhd_os_dbg_attach(&dhd->pub)) { ++ DHD_ERROR(("%s debug module attach failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++#ifdef DBG_PKT_MON ++ dhd->pub.dbg->pkt_mon_lock = dhd_os_spin_lock_init(dhd->pub.osh); ++#ifdef DBG_PKT_MON_INIT_DEFAULT ++ dhd_os_dbg_attach_pkt_monitor(&dhd->pub); ++#endif /* DBG_PKT_MON_INIT_DEFAULT */ ++#endif /* DBG_PKT_MON */ ++#endif /* DEBUGABILITY */ ++#ifdef DHD_PKT_LOGGING ++ dhd_os_attach_pktlog(&dhd->pub); ++#endif /* DHD_PKT_LOGGING */ ++ ++ if (dhd_sta_pool_init(&dhd->pub, DHD_MAX_STA) != BCME_OK) { ++ DHD_ERROR(("%s: Initializing %u sta\n", __FUNCTION__, DHD_MAX_STA)); ++ goto fail; ++ } ++ ++ ++ ++#ifndef BCMDBUS ++ /* Set up the watchdog timer */ ++ init_timer_compat(&dhd->timer, dhd_watchdog, dhd); ++ dhd->default_wd_interval = dhd_watchdog_ms; ++ ++ if (dhd_watchdog_prio >= 0) { ++ /* Initialize watchdog thread */ ++ PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); ++ if (dhd->thr_wdt_ctl.thr_pid < 0) { ++ goto fail; ++ } ++ ++ } else { ++ dhd->thr_wdt_ctl.thr_pid = -1; ++ } ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++ /* Setup up the runtime PM Idlecount timer */ ++ init_timer_compat(&dhd->rpm_timer, dhd_runtimepm, dhd); ++ dhd->rpm_timer_valid = FALSE; ++ ++ dhd->thr_rpm_ctl.thr_pid = DHD_PID_KT_INVALID; ++ PROC_START(dhd_rpm_state_thread, dhd, &dhd->thr_rpm_ctl, 0, "dhd_rpm_state_thread"); ++ if (dhd->thr_rpm_ctl.thr_pid < 0) { ++ goto fail; ++ } ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++#ifdef DEBUGGER ++ debugger_init((void *) bus); ++#endif ++ ++ /* Set up the bottom half handler */ ++ if (dhd_dpc_prio >= 0) { ++ /* Initialize DPC thread */ ++ PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); ++ if (dhd->thr_dpc_ctl.thr_pid < 0) { ++ goto fail; ++ } ++ } else { ++ /* use tasklet for dpc */ ++ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); ++ dhd->thr_dpc_ctl.thr_pid = -1; ++ } ++ ++ if (dhd->rxthread_enabled) { ++ bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND); ++ /* Initialize RXF thread */ ++ PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf"); ++ if (dhd->thr_rxf_ctl.thr_pid < 0) { ++ goto fail; ++ } ++ } ++#endif /* !BCMDBUS */ ++#ifdef SHOW_LOGTRACE ++ skb_queue_head_init(&dhd->evt_trace_queue); ++#endif /* SHOW_LOGTRACE */ ++ ++ dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; ++ ++#if defined(CONFIG_PM_SLEEP) ++ if (!dhd_pm_notifier_registered) { ++ dhd_pm_notifier_registered = TRUE; ++ dhd->pm_notifier.notifier_call = dhd_pm_callback; ++ dhd->pm_notifier.priority = 10; ++ register_pm_notifier(&dhd->pm_notifier); ++ } ++ ++#endif /* CONFIG_PM_SLEEP */ ++ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; ++ dhd->early_suspend.suspend = dhd_early_suspend; ++ dhd->early_suspend.resume = dhd_late_resume; ++ register_early_suspend(&dhd->early_suspend); ++ dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; ++#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ dhd->pend_ipaddr = 0; ++ if (!dhd_inetaddr_notifier_registered) { ++ dhd_inetaddr_notifier_registered = TRUE; ++ register_inetaddr_notifier(&dhd_inetaddr_notifier); ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) ++ if (!dhd_inet6addr_notifier_registered) { ++ dhd_inet6addr_notifier_registered = TRUE; ++ register_inet6addr_notifier(&dhd_inet6addr_notifier); ++ } ++#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ ++ dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd); ++#ifdef DEBUG_CPU_FREQ ++ dhd->new_freq = alloc_percpu(int); ++ dhd->freq_trans.notifier_call = dhd_cpufreq_notifier; ++ cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); ++#endif ++#ifdef DHDTCPACK_SUPPRESS ++ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DEFAULT); ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) ++#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ ++ ++ ++#ifdef DHD_DEBUG_PAGEALLOC ++ register_page_corrupt_cb(dhd_page_corrupt_cb, &dhd->pub); ++#endif /* DHD_DEBUG_PAGEALLOC */ ++ ++#if defined(DHD_LB) ++ ++ dhd_lb_set_default_cpus(dhd); ++ ++ /* Initialize the CPU Masks */ ++ if (dhd_cpumasks_init(dhd) == 0) { ++ /* Now we have the current CPU maps, run through candidacy */ ++ dhd_select_cpu_candidacy(dhd); ++ /* ++ * If we are able to initialize CPU masks, lets register to the ++ * CPU Hotplug framework to change the CPU for each job dynamically ++ * using candidacy algorithm. ++ */ ++ dhd->cpu_notifier.notifier_call = dhd_cpu_callback; ++ register_hotcpu_notifier(&dhd->cpu_notifier); /* Register a callback */ ++ } else { ++ /* ++ * We are unable to initialize CPU masks, so candidacy algorithm ++ * won't run, but still Load Balancing will be honoured based ++ * on the CPUs allocated for a given job statically during init ++ */ ++ dhd->cpu_notifier.notifier_call = NULL; ++ DHD_ERROR(("%s():dhd_cpumasks_init failed CPUs for JOB would be static\n", ++ __FUNCTION__)); ++ } ++ ++#ifdef DHD_LB_TXP ++#ifdef DHD_LB_TXP_DEFAULT_ENAB ++ /* Trun ON the feature by default */ ++ atomic_set(&dhd->lb_txp_active, 1); ++#else ++ /* Trun OFF the feature by default */ ++ atomic_set(&dhd->lb_txp_active, 0); ++#endif /* DHD_LB_TXP_DEFAULT_ENAB */ ++#endif /* DHD_LB_TXP */ ++ ++ DHD_LB_STATS_INIT(&dhd->pub); ++ ++ /* Initialize the Load Balancing Tasklets and Napi object */ ++#if defined(DHD_LB_TXC) ++ tasklet_init(&dhd->tx_compl_tasklet, ++ dhd_lb_tx_compl_handler, (ulong)(&dhd->pub)); ++ INIT_WORK(&dhd->tx_compl_dispatcher_work, dhd_tx_compl_dispatcher_fn); ++ DHD_INFO(("%s load balance init tx_compl_tasklet\n", __FUNCTION__)); ++#endif /* DHD_LB_TXC */ ++ ++#if defined(DHD_LB_RXC) ++ tasklet_init(&dhd->rx_compl_tasklet, ++ dhd_lb_rx_compl_handler, (ulong)(&dhd->pub)); ++ DHD_INFO(("%s load balance init rx_compl_tasklet\n", __FUNCTION__)); ++#endif /* DHD_LB_RXC */ ++ ++#if defined(DHD_LB_RXP) ++ __skb_queue_head_init(&dhd->rx_pend_queue); ++ skb_queue_head_init(&dhd->rx_napi_queue); ++ /* Initialize the work that dispatches NAPI job to a given core */ ++ INIT_WORK(&dhd->rx_napi_dispatcher_work, dhd_rx_napi_dispatcher_fn); ++ DHD_INFO(("%s load balance init rx_napi_queue\n", __FUNCTION__)); ++#endif /* DHD_LB_RXP */ ++ ++#if defined(DHD_LB_TXP) ++ INIT_WORK(&dhd->tx_dispatcher_work, dhd_tx_dispatcher_work); ++ skb_queue_head_init(&dhd->tx_pend_queue); ++ /* Initialize the work that dispatches TX job to a given core */ ++ tasklet_init(&dhd->tx_tasklet, ++ dhd_lb_tx_handler, (ulong)(dhd)); ++ DHD_INFO(("%s load balance init tx_pend_queue\n", __FUNCTION__)); ++#endif /* DHD_LB_TXP */ ++ ++ dhd_state |= DHD_ATTACH_STATE_LB_ATTACH_DONE; ++#endif /* DHD_LB */ ++ ++#ifdef SHOW_LOGTRACE ++ INIT_WORK(&dhd->event_log_dispatcher_work, dhd_event_logtrace_process); ++#endif /* SHOW_LOGTRACE */ ++ ++ DHD_SSSR_MEMPOOL_INIT(&dhd->pub); ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++ init_dhd_timeouts(&dhd->pub); ++#endif /* REPORT_FATAL_TIMEOUTS */ ++#ifdef BCMPCIE ++ dhd->pub.extended_trap_data = MALLOCZ(osh, BCMPCIE_EXT_TRAP_DATA_MAXLEN); ++ if (dhd->pub.extended_trap_data == NULL) { ++ DHD_ERROR(("%s: Failed to alloc extended_trap_data\n", __FUNCTION__)); ++ } ++#endif /* BCMPCIE */ ++ ++ (void)dhd_sysfs_init(dhd); ++ ++ dhd_state |= DHD_ATTACH_STATE_DONE; ++ dhd->dhd_state = dhd_state; ++ ++ dhd_found++; ++ ++ return &dhd->pub; ++ ++fail: ++ if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) { ++ DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", ++ __FUNCTION__, dhd_state, &dhd->pub)); ++ dhd->dhd_state = dhd_state; ++ dhd_detach(&dhd->pub); ++ dhd_free(&dhd->pub); ++ } ++dhd_null_flag: ++ return NULL; ++} ++ ++int dhd_get_fw_mode(dhd_info_t *dhdinfo) ++{ ++ if (strstr(dhdinfo->fw_path, "_apsta") != NULL) ++ return DHD_FLAG_HOSTAP_MODE; ++ if (strstr(dhdinfo->fw_path, "_p2p") != NULL) ++ return DHD_FLAG_P2P_MODE; ++ if (strstr(dhdinfo->fw_path, "_ibss") != NULL) ++ return DHD_FLAG_IBSS_MODE; ++ if (strstr(dhdinfo->fw_path, "_mfg") != NULL) ++ return DHD_FLAG_MFG_MODE; ++ ++ return DHD_FLAG_STA_MODE; ++} ++ ++int dhd_bus_get_fw_mode(dhd_pub_t *dhdp) ++{ ++ return dhd_get_fw_mode(dhdp->info); ++} ++ ++bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) ++{ ++ int fw_len; ++ int nv_len; ++ int clm_len; ++ int conf_len; ++ const char *fw = NULL; ++ const char *nv = NULL; ++ const char *clm = NULL; ++ const char *conf = NULL; ++#ifdef DHD_UCODE_DOWNLOAD ++ int uc_len; ++ const char *uc = NULL; ++#endif /* DHD_UCODE_DOWNLOAD */ ++ wifi_adapter_info_t *adapter = dhdinfo->adapter; ++ int fw_path_len = sizeof(dhdinfo->fw_path); ++ int nv_path_len = sizeof(dhdinfo->nv_path); ++ ++ ++ /* Update firmware and nvram path. The path may be from adapter info or module parameter ++ * The path from adapter info is used for initialization only (as it won't change). ++ * ++ * The firmware_path/nvram_path module parameter may be changed by the system at run ++ * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private ++ * command may change dhdinfo->fw_path. As such we need to clear the path info in ++ * module parameter after it is copied. We won't update the path until the module parameter ++ * is changed again (first character is not '\0') ++ */ ++ ++ /* set default firmware and nvram path for built-in type driver */ ++// if (!dhd_download_fw_on_driverload) { ++#ifdef CONFIG_BCMDHD_FW_PATH ++ fw = CONFIG_BCMDHD_FW_PATH; ++#endif /* CONFIG_BCMDHD_FW_PATH */ ++#ifdef CONFIG_BCMDHD_NVRAM_PATH ++ nv = CONFIG_BCMDHD_NVRAM_PATH; ++#endif /* CONFIG_BCMDHD_NVRAM_PATH */ ++// } ++ ++ /* check if we need to initialize the path */ ++ if (dhdinfo->fw_path[0] == '\0') { ++ if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0') ++ fw = adapter->fw_path; ++ ++ } ++ if (dhdinfo->nv_path[0] == '\0') { ++ if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0') ++ nv = adapter->nv_path; ++ } ++ if (dhdinfo->clm_path[0] == '\0') { ++ if (adapter && adapter->clm_path && adapter->clm_path[0] != '\0') ++ clm = adapter->clm_path; ++ } ++ if (dhdinfo->conf_path[0] == '\0') { ++ if (adapter && adapter->conf_path && adapter->conf_path[0] != '\0') ++ conf = adapter->conf_path; ++ } ++ ++ /* Use module parameter if it is valid, EVEN IF the path has not been initialized ++ * ++ * TODO: need a solution for multi-chip, can't use the same firmware for all chips ++ */ ++ if (firmware_path[0] != '\0') ++ fw = firmware_path; ++ if (nvram_path[0] != '\0') ++ nv = nvram_path; ++ if (clm_path[0] != '\0') ++ clm = clm_path; ++ if (config_path[0] != '\0') ++ conf = config_path; ++#ifdef DHD_UCODE_DOWNLOAD ++ if (ucode_path[0] != '\0') ++ uc = ucode_path; ++#endif /* DHD_UCODE_DOWNLOAD */ ++ ++ if (fw && fw[0] != '\0') { ++ fw_len = strlen(fw); ++ if (fw_len >= fw_path_len) { ++ DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n")); ++ return FALSE; ++ } ++ strncpy(dhdinfo->fw_path, fw, fw_path_len); ++ if (dhdinfo->fw_path[fw_len-1] == '\n') ++ dhdinfo->fw_path[fw_len-1] = '\0'; ++ } ++ if (nv && nv[0] != '\0') { ++ nv_len = strlen(nv); ++ if (nv_len >= nv_path_len) { ++ DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n")); ++ return FALSE; ++ } ++ memset(dhdinfo->nv_path, 0, nv_path_len); ++ strncpy(dhdinfo->nv_path, nv, nv_path_len); ++#ifdef DHD_USE_SINGLE_NVRAM_FILE ++ /* Remove "_net" or "_mfg" tag from current nvram path */ ++ { ++ char *nvram_tag = "nvram_"; ++ char *ext_tag = ".txt"; ++ char *sp_nvram = strnstr(dhdinfo->nv_path, nvram_tag, nv_path_len); ++ bool valid_buf = sp_nvram && ((uint32)(sp_nvram + strlen(nvram_tag) + ++ strlen(ext_tag) - dhdinfo->nv_path) <= nv_path_len); ++ if (valid_buf) { ++ char *sp = sp_nvram + strlen(nvram_tag) - 1; ++ uint32 padding_size = (uint32)(dhdinfo->nv_path + ++ nv_path_len - sp); ++ memset(sp, 0, padding_size); ++ strncat(dhdinfo->nv_path, ext_tag, strlen(ext_tag)); ++ nv_len = strlen(dhdinfo->nv_path); ++ DHD_INFO(("%s: new nvram path = %s\n", ++ __FUNCTION__, dhdinfo->nv_path)); ++ } else if (sp_nvram) { ++ DHD_ERROR(("%s: buffer space for nvram path is not enough\n", ++ __FUNCTION__)); ++ return FALSE; ++ } else { ++ DHD_ERROR(("%s: Couldn't find the nvram tag. current" ++ " nvram path = %s\n", __FUNCTION__, dhdinfo->nv_path)); ++ } ++ } ++#endif /* DHD_USE_SINGLE_NVRAM_FILE */ ++ if (dhdinfo->nv_path[nv_len-1] == '\n') ++ dhdinfo->nv_path[nv_len-1] = '\0'; ++ } ++ if (clm && clm[0] != '\0') { ++ clm_len = strlen(clm); ++ if (clm_len >= sizeof(dhdinfo->clm_path)) { ++ DHD_ERROR(("clm path len exceeds max len of dhdinfo->clm_path\n")); ++ return FALSE; ++ } ++ strncpy(dhdinfo->clm_path, clm, sizeof(dhdinfo->clm_path)); ++ if (dhdinfo->clm_path[clm_len-1] == '\n') ++ dhdinfo->clm_path[clm_len-1] = '\0'; ++ } ++ if (conf && conf[0] != '\0') { ++ conf_len = strlen(conf); ++ if (conf_len >= sizeof(dhdinfo->conf_path)) { ++ DHD_ERROR(("config path len exceeds max len of dhdinfo->conf_path\n")); ++ return FALSE; ++ } ++ strncpy(dhdinfo->conf_path, conf, sizeof(dhdinfo->conf_path)); ++ if (dhdinfo->conf_path[conf_len-1] == '\n') ++ dhdinfo->conf_path[conf_len-1] = '\0'; ++ } ++#ifdef DHD_UCODE_DOWNLOAD ++ if (uc && uc[0] != '\0') { ++ uc_len = strlen(uc); ++ if (uc_len >= sizeof(dhdinfo->uc_path)) { ++ DHD_ERROR(("uc path len exceeds max len of dhdinfo->uc_path\n")); ++ return FALSE; ++ } ++ strncpy(dhdinfo->uc_path, uc, sizeof(dhdinfo->uc_path)); ++ if (dhdinfo->uc_path[uc_len-1] == '\n') ++ dhdinfo->uc_path[uc_len-1] = '\0'; ++ } ++#endif /* DHD_UCODE_DOWNLOAD */ ++ ++#if 0 ++ /* clear the path in module parameter */ ++ if (dhd_download_fw_on_driverload) { ++ firmware_path[0] = '\0'; ++ nvram_path[0] = '\0'; ++ clm_path[0] = '\0'; ++ config_path[0] = '\0'; ++ } ++#endif ++#ifdef DHD_UCODE_DOWNLOAD ++ ucode_path[0] = '\0'; ++ DHD_ERROR(("ucode path: %s\n", dhdinfo->uc_path)); ++#endif /* DHD_UCODE_DOWNLOAD */ ++ ++#ifndef BCMEMBEDIMAGE ++ /* fw_path and nv_path are not mandatory for BCMEMBEDIMAGE */ ++ if (dhdinfo->fw_path[0] == '\0') { ++ DHD_ERROR(("firmware path not found\n")); ++ return FALSE; ++ } ++ if (dhdinfo->nv_path[0] == '\0') { ++ DHD_ERROR(("nvram path not found\n")); ++ return FALSE; ++ } ++#endif /* BCMEMBEDIMAGE */ ++ ++ return TRUE; ++} ++ ++#if defined(BT_OVER_SDIO) ++extern bool dhd_update_btfw_path(dhd_info_t *dhdinfo, char* btfw_path) ++{ ++ int fw_len; ++ const char *fw = NULL; ++ wifi_adapter_info_t *adapter = dhdinfo->adapter; ++ ++ ++ /* Update bt firmware path. The path may be from adapter info or module parameter ++ * The path from adapter info is used for initialization only (as it won't change). ++ * ++ * The btfw_path module parameter may be changed by the system at run ++ * time. When it changes we need to copy it to dhdinfo->btfw_path. Also Android private ++ * command may change dhdinfo->btfw_path. As such we need to clear the path info in ++ * module parameter after it is copied. We won't update the path until the module parameter ++ * is changed again (first character is not '\0') ++ */ ++ ++ /* set default firmware and nvram path for built-in type driver */ ++ if (!dhd_download_fw_on_driverload) { ++#ifdef CONFIG_BCMDHD_BTFW_PATH ++ fw = CONFIG_BCMDHD_BTFW_PATH; ++#endif /* CONFIG_BCMDHD_FW_PATH */ ++ } ++ ++ /* check if we need to initialize the path */ ++ if (dhdinfo->btfw_path[0] == '\0') { ++ if (adapter && adapter->btfw_path && adapter->btfw_path[0] != '\0') ++ fw = adapter->btfw_path; ++ } ++ ++ /* Use module parameter if it is valid, EVEN IF the path has not been initialized ++ */ ++ if (btfw_path[0] != '\0') ++ fw = btfw_path; ++ ++ if (fw && fw[0] != '\0') { ++ fw_len = strlen(fw); ++ if (fw_len >= sizeof(dhdinfo->btfw_path)) { ++ DHD_ERROR(("fw path len exceeds max len of dhdinfo->btfw_path\n")); ++ return FALSE; ++ } ++ strncpy(dhdinfo->btfw_path, fw, sizeof(dhdinfo->btfw_path)); ++ if (dhdinfo->btfw_path[fw_len-1] == '\n') ++ dhdinfo->btfw_path[fw_len-1] = '\0'; ++ } ++ ++ /* clear the path in module parameter */ ++ btfw_path[0] = '\0'; ++ ++ if (dhdinfo->btfw_path[0] == '\0') { ++ DHD_ERROR(("bt firmware path not found\n")); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++#endif /* defined (BT_OVER_SDIO) */ ++ ++ ++#ifdef CUSTOMER_HW4_DEBUG ++bool dhd_validate_chipid(dhd_pub_t *dhdp) ++{ ++ uint chipid = dhd_bus_chip_id(dhdp); ++ uint config_chipid; ++ ++#ifdef BCM4361_CHIP ++ config_chipid = BCM4361_CHIP_ID; ++#elif defined(BCM4359_CHIP) ++ config_chipid = BCM4359_CHIP_ID; ++#elif defined(BCM4358_CHIP) ++ config_chipid = BCM4358_CHIP_ID; ++#elif defined(BCM4354_CHIP) ++ config_chipid = BCM4354_CHIP_ID; ++#elif defined(BCM4339_CHIP) ++ config_chipid = BCM4339_CHIP_ID; ++#elif defined(BCM43349_CHIP) ++ config_chipid = BCM43349_CHIP_ID; ++#elif defined(BCM4335_CHIP) ++ config_chipid = BCM4335_CHIP_ID; ++#elif defined(BCM43241_CHIP) ++ config_chipid = BCM4324_CHIP_ID; ++#elif defined(BCM4330_CHIP) ++ config_chipid = BCM4330_CHIP_ID; ++#elif defined(BCM43430_CHIP) ++ config_chipid = BCM43430_CHIP_ID; ++#elif defined(BCM43018_CHIP) ++ config_chipid = BCM43018_CHIP_ID; ++#elif defined(BCM43455_CHIP) ++ config_chipid = BCM4345_CHIP_ID; ++#elif defined(BCM4334W_CHIP) ++ config_chipid = BCM43342_CHIP_ID; ++#elif defined(BCM43454_CHIP) ++ config_chipid = BCM43454_CHIP_ID; ++#elif defined(BCM43012_CHIP_) ++ config_chipid = BCM43012_CHIP_ID; ++#else ++ DHD_ERROR(("%s: Unknown chip id, if you use new chipset," ++ " please add CONFIG_BCMXXXX into the Kernel and" ++ " BCMXXXX_CHIP definition into the DHD driver\n", ++ __FUNCTION__)); ++ config_chipid = 0; ++ ++ return FALSE; ++#endif /* BCM4354_CHIP */ ++ ++#ifdef SUPPORT_MULTIPLE_CHIP_4345X ++ if (config_chipid == BCM43454_CHIP_ID || config_chipid == BCM4345_CHIP_ID) { ++ return TRUE; ++ } ++#endif /* SUPPORT_MULTIPLE_CHIP_4345X */ ++#if defined(BCM4359_CHIP) ++ if (chipid == BCM4355_CHIP_ID && config_chipid == BCM4359_CHIP_ID) { ++ return TRUE; ++ } ++#endif /* BCM4359_CHIP */ ++#if defined(BCM4361_CHIP) ++ if (chipid == BCM4347_CHIP_ID && config_chipid == BCM4361_CHIP_ID) { ++ return TRUE; ++ } ++#endif /* BCM4361_CHIP */ ++ ++ return config_chipid == chipid; ++} ++#endif /* CUSTOMER_HW4_DEBUG */ ++ ++#if defined(BT_OVER_SDIO) ++wlan_bt_handle_t dhd_bt_get_pub_hndl(void) ++{ ++ DHD_ERROR(("%s: g_dhd_pub %p\n", __FUNCTION__, g_dhd_pub)); ++ /* assuming that dhd_pub_t type pointer is available from a global variable */ ++ return (wlan_bt_handle_t) g_dhd_pub; ++} EXPORT_SYMBOL(dhd_bt_get_pub_hndl); ++ ++int dhd_download_btfw(wlan_bt_handle_t handle, char* btfw_path) ++{ ++ int ret = -1; ++ dhd_pub_t *dhdp = (dhd_pub_t *)handle; ++ dhd_info_t *dhd = (dhd_info_t*)dhdp->info; ++ ++ ++ /* Download BT firmware image to the dongle */ ++ if (dhd->pub.busstate == DHD_BUS_DATA && dhd_update_btfw_path(dhd, btfw_path)) { ++ DHD_INFO(("%s: download btfw from: %s\n", __FUNCTION__, dhd->btfw_path)); ++ ret = dhd_bus_download_btfw(dhd->pub.bus, dhd->pub.osh, dhd->btfw_path); ++ if (ret < 0) { ++ DHD_ERROR(("%s: failed to download btfw from: %s\n", ++ __FUNCTION__, dhd->btfw_path)); ++ return ret; ++ } ++ } ++ return ret; ++} EXPORT_SYMBOL(dhd_download_btfw); ++#endif /* defined (BT_OVER_SDIO) */ ++ ++#ifndef BCMDBUS ++int ++dhd_bus_start(dhd_pub_t *dhdp) ++{ ++ int ret = -1; ++ dhd_info_t *dhd = (dhd_info_t*)dhdp->info; ++ unsigned long flags; ++ ++#if defined(DHD_DEBUG) && defined(BCMSDIO) ++ int fw_download_start = 0, fw_download_end = 0, f2_sync_start = 0, f2_sync_end = 0; ++#endif /* DHD_DEBUG && BCMSDIO */ ++ ASSERT(dhd); ++ ++ DHD_TRACE(("Enter %s:\n", __FUNCTION__)); ++ ++ DHD_PERIM_LOCK(dhdp); ++#ifdef HOFFLOAD_MODULES ++ dhd_linux_get_modfw_address(dhdp); ++#endif ++ /* try to download image and nvram to the dongle */ ++ if (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) { ++ /* Indicate FW Download has not yet done */ ++ dhd->pub.fw_download_done = FALSE; ++ DHD_INFO(("%s download fw %s, nv %s, conf %s\n", ++ __FUNCTION__, dhd->fw_path, dhd->nv_path, dhd->conf_path)); ++#if defined(DHD_DEBUG) && defined(BCMSDIO) ++ fw_download_start = OSL_SYSUPTIME(); ++#endif /* DHD_DEBUG && BCMSDIO */ ++ ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, ++ dhd->fw_path, dhd->nv_path, dhd->clm_path, dhd->conf_path); ++#if defined(DHD_DEBUG) && defined(BCMSDIO) ++ fw_download_end = OSL_SYSUPTIME(); ++#endif /* DHD_DEBUG && BCMSDIO */ ++ if (ret < 0) { ++ DHD_ERROR(("%s: failed to download firmware %s\n", ++ __FUNCTION__, dhd->fw_path)); ++ DHD_PERIM_UNLOCK(dhdp); ++ return ret; ++ } ++ /* Indicate FW Download has succeeded */ ++ dhd->pub.fw_download_done = TRUE; ++ } ++ if (dhd->pub.busstate != DHD_BUS_LOAD) { ++ DHD_PERIM_UNLOCK(dhdp); ++ return -ENETDOWN; ++ } ++ ++#ifdef BCMSDIO ++ dhd_os_sdlock(dhdp); ++#endif /* BCMSDIO */ ++ ++ /* Start the watchdog timer */ ++ dhd->pub.tickcnt = 0; ++ dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); ++ ++ /* Bring up the bus */ ++ if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { ++ ++ DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); ++#ifdef BCMSDIO ++ dhd_os_sdunlock(dhdp); ++#endif /* BCMSDIO */ ++ DHD_PERIM_UNLOCK(dhdp); ++ return ret; ++ } ++ ++ DHD_ENABLE_RUNTIME_PM(&dhd->pub); ++ ++#ifdef DHD_ULP ++ dhd_ulp_set_ulp_state(dhdp, DHD_ULP_DISABLED); ++#endif /* DHD_ULP */ ++#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE) ++ /* Host registration for OOB interrupt */ ++ if (dhd_bus_oob_intr_register(dhdp)) { ++ /* deactivate timer and wait for the handler to finish */ ++#if !defined(BCMPCIE_OOB_HOST_WAKE) ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ dhd->wd_timer_valid = FALSE; ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ _del_timer_sync(&dhd->timer); ++ ++#endif /* !BCMPCIE_OOB_HOST_WAKE */ ++ DHD_DISABLE_RUNTIME_PM(&dhd->pub); ++ DHD_PERIM_UNLOCK(dhdp); ++ DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++#if defined(BCMPCIE_OOB_HOST_WAKE) ++ dhd_bus_oob_intr_set(dhdp, TRUE); ++#else ++ /* Enable oob at firmware */ ++ dhd_enable_oob_intr(dhd->pub.bus, TRUE); ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++#elif defined(FORCE_WOWLAN) ++ /* Enable oob at firmware */ ++ dhd_enable_oob_intr(dhd->pub.bus, TRUE); ++#endif ++#ifdef PCIE_FULL_DONGLE ++ { ++ /* max_h2d_rings includes H2D common rings */ ++ uint32 max_h2d_rings = dhd_bus_max_h2d_queues(dhd->pub.bus); ++ ++ DHD_ERROR(("%s: Initializing %u h2drings\n", __FUNCTION__, ++ max_h2d_rings)); ++ if ((ret = dhd_flow_rings_init(&dhd->pub, max_h2d_rings)) != BCME_OK) { ++#ifdef BCMSDIO ++ dhd_os_sdunlock(dhdp); ++#endif /* BCMSDIO */ ++ DHD_PERIM_UNLOCK(dhdp); ++ return ret; ++ } ++ } ++#endif /* PCIE_FULL_DONGLE */ ++ ++ /* Do protocol initialization necessary for IOCTL/IOVAR */ ++ ret = dhd_prot_init(&dhd->pub); ++ if (unlikely(ret) != BCME_OK) { ++ DHD_PERIM_UNLOCK(dhdp); ++ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); ++ return ret; ++ } ++ ++ /* If bus is not ready, can't come up */ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ dhd->wd_timer_valid = FALSE; ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ _del_timer_sync(&dhd->timer); ++ DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); ++ DHD_DISABLE_RUNTIME_PM(&dhd->pub); ++#ifdef BCMSDIO ++ dhd_os_sdunlock(dhdp); ++#endif /* BCMSDIO */ ++ DHD_PERIM_UNLOCK(dhdp); ++ return -ENODEV; ++ } ++ ++#ifdef BCMSDIO ++ dhd_os_sdunlock(dhdp); ++#endif /* BCMSDIO */ ++ ++ /* Bus is ready, query any dongle information */ ++#if defined(DHD_DEBUG) && defined(BCMSDIO) ++ f2_sync_start = OSL_SYSUPTIME(); ++#endif /* DHD_DEBUG && BCMSDIO */ ++ if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) { ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ dhd->wd_timer_valid = FALSE; ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ _del_timer_sync(&dhd->timer); ++ DHD_ERROR(("%s failed to sync with dongle\n", __FUNCTION__)); ++ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); ++ DHD_PERIM_UNLOCK(dhdp); ++ return ret; ++ } ++#if defined(CONFIG_SOC_EXYNOS8895) ++ DHD_ERROR(("%s: Enable L1ss EP side\n", __FUNCTION__)); ++ exynos_pcie_l1ss_ctrl(1, PCIE_L1SS_CTRL_WIFI); ++#endif /* CONFIG_SOC_EXYNOS8895 */ ++ ++#if defined(DHD_DEBUG) && defined(BCMSDIO) ++ f2_sync_end = OSL_SYSUPTIME(); ++ DHD_ERROR(("Time taken for FW download and F2 ready is: %d msec\n", ++ (fw_download_end - fw_download_start) + (f2_sync_end - f2_sync_start))); ++#endif /* DHD_DEBUG && BCMSDIO */ ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd->pend_ipaddr) { ++#ifdef AOE_IP_ALIAS_SUPPORT ++ aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0); ++#endif /* AOE_IP_ALIAS_SUPPORT */ ++ dhd->pend_ipaddr = 0; ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#if defined(TRAFFIC_MGMT_DWM) ++ bzero(&dhd->pub.dhd_tm_dwm_tbl, sizeof(dhd_trf_mgmt_dwm_tbl_t)); ++#endif ++ DHD_PERIM_UNLOCK(dhdp); ++ return 0; ++} ++#endif /* !BCMDBUS */ ++ ++#ifdef WLTDLS ++int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac) ++{ ++ uint32 tdls = tdls_on; ++ int ret = 0; ++ uint32 tdls_auto_op = 0; ++ uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING; ++ int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH; ++ int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW; ++ BCM_REFERENCE(mac); ++ if (!FW_SUPPORTED(dhd, tdls)) ++ return BCME_ERROR; ++ ++ if (dhd->tdls_enable == tdls_on) ++ goto auto_mode; ++ ret = dhd_iovar(dhd, 0, "tdls_enable", (char *)&tdls, sizeof(tdls), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret)); ++ goto exit; ++ } ++ dhd->tdls_enable = tdls_on; ++auto_mode: ++ ++ tdls_auto_op = auto_on; ++ ret = dhd_iovar(dhd, 0, "tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), NULL, ++ 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret)); ++ goto exit; ++ } ++ ++ if (tdls_auto_op) { ++ ret = dhd_iovar(dhd, 0, "tdls_idle_time", (char *)&tdls_idle_time, ++ sizeof(tdls_idle_time), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret)); ++ goto exit; ++ } ++ ret = dhd_iovar(dhd, 0, "tdls_rssi_high", (char *)&tdls_rssi_high, ++ sizeof(tdls_rssi_high), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret)); ++ goto exit; ++ } ++ ret = dhd_iovar(dhd, 0, "tdls_rssi_low", (char *)&tdls_rssi_low, ++ sizeof(tdls_rssi_low), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret)); ++ goto exit; ++ } ++ } ++ ++exit: ++ return ret; ++} ++ ++int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int ret = 0; ++ if (dhd) ++ ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac); ++ else ++ ret = BCME_ERROR; ++ return ret; ++} ++ ++int ++dhd_tdls_set_mode(dhd_pub_t *dhd, bool wfd_mode) ++{ ++ int ret = 0; ++ bool auto_on = false; ++ uint32 mode = wfd_mode; ++ ++#ifdef ENABLE_TDLS_AUTO_MODE ++ if (wfd_mode) { ++ auto_on = false; ++ } else { ++ auto_on = true; ++ } ++#else ++ auto_on = false; ++#endif /* ENABLE_TDLS_AUTO_MODE */ ++ ret = _dhd_tdls_enable(dhd, false, auto_on, NULL); ++ if (ret < 0) { ++ DHD_ERROR(("Disable tdls_auto_op failed. %d\n", ret)); ++ return ret; ++ } ++ ++ ret = dhd_iovar(dhd, 0, "tdls_wfd_mode", (char *)&mode, sizeof(mode), NULL, 0, TRUE); ++ if ((ret < 0) && (ret != BCME_UNSUPPORTED)) { ++ DHD_ERROR(("%s: tdls_wfd_mode faile_wfd_mode %d\n", __FUNCTION__, ret)); ++ return ret; ++ } ++ ++ ret = _dhd_tdls_enable(dhd, true, auto_on, NULL); ++ if (ret < 0) { ++ DHD_ERROR(("enable tdls_auto_op failed. %d\n", ret)); ++ return ret; ++ } ++ ++ dhd->tdls_mode = mode; ++ return ret; ++} ++#ifdef PCIE_FULL_DONGLE ++int dhd_tdls_update_peer_info(dhd_pub_t *dhdp, wl_event_msg_t *event) ++{ ++ dhd_pub_t *dhd_pub = dhdp; ++ tdls_peer_node_t *cur = dhd_pub->peer_tbl.node; ++ tdls_peer_node_t *new = NULL, *prev = NULL; ++ int ifindex = dhd_ifname2idx(dhd_pub->info, event->ifname); ++ uint8 *da = (uint8 *)&event->addr.octet[0]; ++ bool connect = FALSE; ++ uint32 reason = ntoh32(event->reason); ++ unsigned long flags; ++ ++ if (reason == WLC_E_TDLS_PEER_CONNECTED) ++ connect = TRUE; ++ else if (reason == WLC_E_TDLS_PEER_DISCONNECTED) ++ connect = FALSE; ++ else ++ { ++ DHD_ERROR(("%s: TDLS Event reason is unknown\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ if (ifindex == DHD_BAD_IF) ++ return BCME_ERROR; ++ ++ if (connect) { ++ while (cur != NULL) { ++ if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { ++ DHD_ERROR(("%s: TDLS Peer exist already %d\n", ++ __FUNCTION__, __LINE__)); ++ return BCME_ERROR; ++ } ++ cur = cur->next; ++ } ++ ++ new = MALLOC(dhd_pub->osh, sizeof(tdls_peer_node_t)); ++ if (new == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ memcpy(new->addr, da, ETHER_ADDR_LEN); ++ DHD_TDLS_LOCK(&dhdp->tdls_lock, flags); ++ new->next = dhd_pub->peer_tbl.node; ++ dhd_pub->peer_tbl.node = new; ++ dhd_pub->peer_tbl.tdls_peer_count++; ++ DHD_TDLS_UNLOCK(&dhdp->tdls_lock, flags); ++ ++ } else { ++ while (cur != NULL) { ++ if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { ++ dhd_flow_rings_delete_for_peer(dhd_pub, (uint8)ifindex, da); ++ DHD_TDLS_LOCK(&dhdp->tdls_lock, flags); ++ if (prev) ++ prev->next = cur->next; ++ else ++ dhd_pub->peer_tbl.node = cur->next; ++ MFREE(dhd_pub->osh, cur, sizeof(tdls_peer_node_t)); ++ dhd_pub->peer_tbl.tdls_peer_count--; ++ DHD_TDLS_UNLOCK(&dhdp->tdls_lock, flags); ++ return BCME_OK; ++ } ++ prev = cur; ++ cur = cur->next; ++ } ++ DHD_ERROR(("%s: TDLS Peer Entry Not found\n", __FUNCTION__)); ++ } ++ return BCME_OK; ++} ++#endif /* PCIE_FULL_DONGLE */ ++#endif ++ ++bool dhd_is_concurrent_mode(dhd_pub_t *dhd) ++{ ++ if (!dhd) ++ return FALSE; ++ ++ if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE) ++ return TRUE; ++ else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) == ++ DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) ++ return TRUE; ++ else ++ return FALSE; ++} ++#if !defined(AP) && defined(WLP2P) ++/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware ++ * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA ++ * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware ++ * would still be named as fw_bcmdhd_apsta. ++ */ ++uint32 ++dhd_get_concurrent_capabilites(dhd_pub_t *dhd) ++{ ++ int32 ret = 0; ++ char buf[WLC_IOCTL_SMLEN]; ++ bool mchan_supported = FALSE; ++ /* if dhd->op_mode is already set for HOSTAP and Manufacturing ++ * test mode, that means we only will use the mode as it is ++ */ ++ if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE)) ++ return 0; ++ if (FW_SUPPORTED(dhd, vsdb)) { ++ mchan_supported = TRUE; ++ } ++ if (!FW_SUPPORTED(dhd, p2p)) { ++ DHD_TRACE(("Chip does not support p2p\n")); ++ return 0; ++ } else { ++ /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ ++ memset(buf, 0, sizeof(buf)); ++ ret = dhd_iovar(dhd, 0, "p2p", NULL, 0, (char *)&buf, ++ sizeof(buf), FALSE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); ++ return 0; ++ } else { ++ if (buf[0] == 1) { ++ /* By default, chip supports single chan concurrency, ++ * now lets check for mchan ++ */ ++ ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; ++ if (mchan_supported) ++ ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; ++ if (FW_SUPPORTED(dhd, rsdb)) { ++ ret |= DHD_FLAG_RSDB_MODE; ++ } ++#ifdef WL_SUPPORT_MULTIP2P ++ if (FW_SUPPORTED(dhd, mp2p)) { ++ ret |= DHD_FLAG_MP2P_MODE; ++ } ++#endif /* WL_SUPPORT_MULTIP2P */ ++#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) ++ return ret; ++#else ++ return 0; ++#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */ ++ } ++ } ++ } ++ return 0; ++} ++#endif ++ ++#ifdef SUPPORT_AP_POWERSAVE ++#define RXCHAIN_PWRSAVE_PPS 10 ++#define RXCHAIN_PWRSAVE_QUIET_TIME 10 ++#define RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK 0 ++int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable) ++{ ++ int32 pps = RXCHAIN_PWRSAVE_PPS; ++ int32 quiet_time = RXCHAIN_PWRSAVE_QUIET_TIME; ++ int32 stas_assoc_check = RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK; ++ int ret; ++ ++ if (enable) { ++ ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_enable", (char *)&enable, sizeof(enable), ++ NULL, 0, TRUE); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("Failed to enable AP power save\n")); ++ } ++ ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_pps", (char *)&pps, sizeof(pps), NULL, 0, ++ TRUE); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("Failed to set pps\n")); ++ } ++ ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_quiet_time", (char *)&quiet_time, ++ sizeof(quiet_time), NULL, 0, TRUE); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("Failed to set quiet time\n")); ++ } ++ ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_stas_assoc_check", ++ (char *)&stas_assoc_check, sizeof(stas_assoc_check), NULL, 0, TRUE); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("Failed to set stas assoc check\n")); ++ } ++ } else { ++ ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_enable", (char *)&enable, sizeof(enable), ++ NULL, 0, TRUE); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("Failed to disable AP power save\n")); ++ } ++ } ++ ++ return 0; ++} ++#endif /* SUPPORT_AP_POWERSAVE */ ++ ++ ++ ++ ++#if defined(WLADPS) || defined(WLADPS_PRIVATE_CMD) ++int ++dhd_enable_adps(dhd_pub_t *dhd, uint8 on) ++{ ++ int i; ++ int len; ++ int ret = BCME_OK; ++ ++ bcm_iov_buf_t *iov_buf = NULL; ++ wl_adps_params_v1_t *data = NULL; ++ char buf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ ++ ++ len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(*data); ++ iov_buf = kmalloc(len, GFP_KERNEL); ++ if (iov_buf == NULL) { ++ DHD_ERROR(("%s - failed to allocate %d bytes for iov_buf\n", __FUNCTION__, len)); ++ ret = BCME_NOMEM; ++ goto exit; ++ } ++ ++ iov_buf->version = WL_ADPS_IOV_VER; ++ iov_buf->len = sizeof(*data); ++ iov_buf->id = WL_ADPS_IOV_MODE; ++ ++ data = (wl_adps_params_v1_t *)iov_buf->data; ++ data->version = ADPS_SUB_IOV_VERSION_1; ++ data->length = sizeof(*data); ++ data->mode = on; ++ ++ for (i = 1; i <= MAX_BANDS; i++) { ++ data->band = i; ++ bcm_mkiovar("adps", (char *)iov_buf, len, buf, sizeof(buf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0)) < 0) { ++ if (ret == BCME_UNSUPPORTED) { ++ DHD_ERROR(("%s adps is not supported\n", __FUNCTION__)); ++ ret = BCME_OK; ++ goto exit; ++ } ++ else { ++ DHD_ERROR(("%s fail to set adps %s for band %d (%d)\n", ++ __FUNCTION__, on ? "On" : "Off", i, ret)); ++ goto exit; ++ } ++ } ++ } ++ ++exit: ++ if (iov_buf) { ++ kfree(iov_buf); ++ } ++ return ret; ++} ++#endif /* WLADPS || WLADPS_PRIVATE_CMD */ ++ ++int ++dhd_preinit_ioctls(dhd_pub_t *dhd) ++{ ++ int ret = 0; ++ char eventmask[WL_EVENTING_MASK_LEN]; ++ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ ++ uint32 buf_key_b4_m4 = 1; ++ uint8 msglen; ++ eventmsgs_ext_t *eventmask_msg = NULL; ++ char* iov_buf = NULL; ++ int ret2 = 0; ++ uint32 wnm_cap = 0; ++#if defined(CUSTOM_AMPDU_BA_WSIZE) ++ uint32 ampdu_ba_wsize = 0; ++#endif ++#if defined(CUSTOM_AMPDU_MPDU) ++ int32 ampdu_mpdu = 0; ++#endif ++#if defined(CUSTOM_AMPDU_RELEASE) ++ int32 ampdu_release = 0; ++#endif ++#if defined(CUSTOM_AMSDU_AGGSF) ++ int32 amsdu_aggsf = 0; ++#endif ++ shub_control_t shub_ctl; ++ ++#if defined(BCMSDIO) || defined(BCMDBUS) ++#ifdef PROP_TXSTATUS ++ int wlfc_enable = TRUE; ++#ifndef DISABLE_11N ++ uint32 hostreorder = 1; ++ uint wl_down = 1; ++#endif /* DISABLE_11N */ ++#endif /* PROP_TXSTATUS */ ++#endif /* BCMSDIO || BCMDBUS */ ++#ifndef PCIE_FULL_DONGLE ++ uint32 wl_ap_isolate; ++#endif /* PCIE_FULL_DONGLE */ ++ uint32 frameburst = CUSTOM_FRAMEBURST_SET; ++ uint wnm_bsstrans_resp = 0; ++#ifdef SUPPORT_SET_CAC ++ uint32 cac = 1; ++#endif /* SUPPORT_SET_CAC */ ++#ifdef DHD_ENABLE_LPC ++ uint32 lpc = 1; ++#endif /* DHD_ENABLE_LPC */ ++ uint power_mode = PM_FAST; ++#if defined(BCMSDIO) ++ uint32 dongle_align = DHD_SDALIGN; ++ uint32 glom = CUSTOM_GLOM_SETTING; ++#endif /* defined(BCMSDIO) */ ++#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) ++ uint32 credall = 1; ++#endif ++ uint bcn_timeout = CUSTOM_BCN_TIMEOUT; ++ uint scancache_enab = TRUE; ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ uint32 bcn_li_bcn = 1; ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ uint retry_max = CUSTOM_ASSOC_RETRY_MAX; ++#if defined(ARP_OFFLOAD_SUPPORT) ++ int arpoe = 1; ++#endif ++ int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; ++ int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; ++ int scan_passive_time = DHD_SCAN_PASSIVE_TIME; ++ char buf[WLC_IOCTL_SMLEN]; ++ char *ptr; ++ uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ ++#if defined(DHD_8021X_DUMP) && defined(SHOW_LOGTRACE) ++ wl_el_tag_params_t *el_tag = NULL; ++#endif /* DHD_8021X_DUMP */ ++#ifdef ROAM_ENABLE ++ uint roamvar = 0; ++ int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; ++ int roam_scan_period[2] = {10, WLC_BAND_ALL}; ++ int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; ++#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC ++ int roam_fullscan_period = 60; ++#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ ++ int roam_fullscan_period = 120; ++#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ ++#ifdef DISABLE_BCNLOSS_ROAM ++ uint roam_bcnloss_off = 1; ++#endif /* DISABLE_BCNLOSS_ROAM */ ++#else ++#ifdef DISABLE_BUILTIN_ROAM ++ uint roamvar = 1; ++#endif /* DISABLE_BUILTIN_ROAM */ ++#endif /* ROAM_ENABLE */ ++ ++#if defined(SOFTAP) ++ uint dtim = 1; ++#endif ++#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) ++ struct ether_addr p2p_ea; ++#endif ++#ifdef SOFTAP_UAPSD_OFF ++ uint32 wme_apsd = 0; ++#endif /* SOFTAP_UAPSD_OFF */ ++#if (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) ++ uint32 apsta = 1; /* Enable APSTA mode */ ++#elif defined(SOFTAP_AND_GC) ++ uint32 apsta = 0; ++ int ap_mode = 1; ++#endif /* (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) */ ++#ifdef GET_CUSTOM_MAC_ENABLE ++ struct ether_addr ea_addr; ++ char hw_ether[62]; ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++#ifdef DISABLE_11N ++ uint32 nmode = 0; ++#endif /* DISABLE_11N */ ++ ++#ifdef USE_WL_TXBF ++ uint32 txbf = 1; ++#endif /* USE_WL_TXBF */ ++#ifdef DISABLE_TXBFR ++ uint32 txbf_bfr_cap = 0; ++#endif /* DISABLE_TXBFR */ ++#if defined(PROP_TXSTATUS) ++#ifdef USE_WFA_CERT_CONF ++ uint32 proptx = 0; ++#endif /* USE_WFA_CERT_CONF */ ++#endif /* PROP_TXSTATUS */ ++#if defined(SUPPORT_5G_1024QAM_VHT) ++ uint32 vht_features = 0; /* init to 0, will be set based on each support */ ++#endif ++#ifdef DISABLE_11N_PROPRIETARY_RATES ++ uint32 ht_features = 0; ++#endif /* DISABLE_11N_PROPRIETARY_RATES */ ++#ifdef CUSTOM_PSPRETEND_THR ++ uint32 pspretend_thr = CUSTOM_PSPRETEND_THR; ++#endif ++#ifdef CUSTOM_EVENT_PM_WAKE ++ uint32 pm_awake_thresh = CUSTOM_EVENT_PM_WAKE; ++#endif /* CUSTOM_EVENT_PM_WAKE */ ++ uint32 rsdb_mode = 0; ++#ifdef ENABLE_TEMP_THROTTLING ++ wl_temp_control_t temp_control; ++#endif /* ENABLE_TEMP_THROTTLING */ ++#ifdef DISABLE_PRUNED_SCAN ++ uint32 scan_features = 0; ++#endif /* DISABLE_PRUNED_SCAN */ ++#ifdef PKT_FILTER_SUPPORT ++ dhd_pkt_filter_enable = TRUE; ++#ifdef APF ++ dhd->apf_set = FALSE; ++#endif /* APF */ ++#endif /* PKT_FILTER_SUPPORT */ ++#ifdef WLTDLS ++ dhd->tdls_enable = FALSE; ++ dhd_tdls_set_mode(dhd, false); ++#endif /* WLTDLS */ ++ dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; ++#ifdef ENABLE_MAX_DTIM_IN_SUSPEND ++ dhd->max_dtim_enable = TRUE; ++#else ++ dhd->max_dtim_enable = FALSE; ++#endif /* ENABLE_MAX_DTIM_IN_SUSPEND */ ++#ifdef CUSTOM_SET_OCLOFF ++ dhd->ocl_off = FALSE; ++#endif /* CUSTOM_SET_OCLOFF */ ++ DHD_TRACE(("Enter %s\n", __FUNCTION__)); ++ ++#ifdef DHDTCPACK_SUPPRESS ++ dhd_tcpack_suppress_set(dhd, dhd->conf->tcpack_sup_mode); ++#endif ++ dhd->op_mode = 0; ++ ++#if defined(CUSTOM_COUNTRY_CODE) && defined(CUSTOMER_HW2) ++ /* clear AP flags */ ++ dhd->dhd_cflags &= ~WLAN_PLAT_AP_FLAG; ++#endif /* CUSTOM_COUNTRY_CODE && CUSTOMER_HW2 */ ++ ++#ifdef CUSTOMER_HW4_DEBUG ++ if (!dhd_validate_chipid(dhd)) { ++ DHD_ERROR(("%s: CONFIG_BCMXXX and CHIP ID(%x) is mismatched\n", ++ __FUNCTION__, dhd_bus_chip_id(dhd))); ++#ifndef SUPPORT_MULTIPLE_CHIPS ++ ret = BCME_BADARG; ++ goto done; ++#endif /* !SUPPORT_MULTIPLE_CHIPS */ ++ } ++#endif /* CUSTOMER_HW4_DEBUG */ ++ if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || ++ (op_mode == DHD_FLAG_MFG_MODE)) { ++ dhd->op_mode = DHD_FLAG_MFG_MODE; ++#ifdef DHD_PCIE_RUNTIMEPM ++ /* Disable RuntimePM in mfg mode */ ++ DHD_DISABLE_RUNTIME_PM(dhd); ++ DHD_ERROR(("%s : Disable RuntimePM in Manufactring Firmware\n", __FUNCTION__)); ++#endif /* DHD_PCIE_RUNTIME_PM */ ++ /* Check and adjust IOCTL response timeout for Manufactring firmware */ ++ dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT); ++ DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n", ++ __FUNCTION__)); ++ } else { ++ dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); ++ DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__)); ++ } ++#ifdef GET_CUSTOM_MAC_ENABLE ++ memset(hw_ether, 0, sizeof(hw_ether)); ++ ret = wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether); ++#ifdef GET_CUSTOM_MAC_FROM_CONFIG ++ if (!memcmp(ðer_null, &dhd->conf->hw_ether, ETHER_ADDR_LEN)) { ++ ret = 0; ++ } else ++#endif ++ if (!ret) { ++ memset(buf, 0, sizeof(buf)); ++#ifdef GET_CUSTOM_MAC_FROM_CONFIG ++ memcpy(hw_ether, &dhd->conf->hw_ether, sizeof(dhd->conf->hw_ether)); ++#endif ++ bcopy(hw_ether, ea_addr.octet, sizeof(struct ether_addr)); ++ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++ if (ret < 0) { ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("hw_ether", hw_ether, sizeof(hw_ether), buf, sizeof(buf)); ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++ if (ret) { ++ DHD_ERROR(("%s: can't set MAC address MAC="MACDBG", error=%d\n", ++ __FUNCTION__, MAC2STRDBG(hw_ether), ret)); ++ prhex("MACPAD", &hw_ether[ETHER_ADDR_LEN], sizeof(hw_ether)-ETHER_ADDR_LEN); ++ ret = BCME_NOTUP; ++ goto done; ++ } ++ } ++ } else { ++ DHD_ERROR(("%s: can't get custom MAC address, ret=%d\n", __FUNCTION__, ret)); ++ ret = BCME_NOTUP; ++ goto done; ++ } ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ /* Get the default device MAC address directly from firmware */ ++ memset(buf, 0, sizeof(buf)); ++ bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), ++ FALSE, 0)) < 0) { ++ DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); ++ ret = BCME_NOTUP; ++ goto done; ++ } ++ /* Update public MAC address after reading from Firmware */ ++ memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); ++ ++ if ((ret = dhd_apply_default_clm(dhd, dhd->clm_path)) < 0) { ++ DHD_ERROR(("%s: CLM set failed. Abort initialization.\n", __FUNCTION__)); ++ goto done; ++ } ++ ++ /* get a capabilities from firmware */ ++ { ++ uint32 cap_buf_size = sizeof(dhd->fw_capabilities); ++ memset(dhd->fw_capabilities, 0, cap_buf_size); ++ ret = dhd_iovar(dhd, 0, "cap", NULL, 0, dhd->fw_capabilities, (cap_buf_size - 1), ++ FALSE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: Get Capability failed (error=%d)\n", ++ __FUNCTION__, ret)); ++ return 0; ++ } ++ ++ memmove(&dhd->fw_capabilities[1], dhd->fw_capabilities, (cap_buf_size - 1)); ++ dhd->fw_capabilities[0] = ' '; ++ dhd->fw_capabilities[cap_buf_size - 2] = ' '; ++ dhd->fw_capabilities[cap_buf_size - 1] = '\0'; ++ } ++ ++ if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) || ++ (op_mode == DHD_FLAG_HOSTAP_MODE)) { ++#ifdef SET_RANDOM_MAC_SOFTAP ++ uint rand_mac; ++#endif /* SET_RANDOM_MAC_SOFTAP */ ++ dhd->op_mode = DHD_FLAG_HOSTAP_MODE; ++#if defined(ARP_OFFLOAD_SUPPORT) ++ arpoe = 0; ++#endif ++#ifdef PKT_FILTER_SUPPORT ++ if (dhd_conf_get_insuspend(dhd, AP_FILTER_IN_SUSPEND)) ++ dhd_pkt_filter_enable = TRUE; ++ else ++ dhd_pkt_filter_enable = FALSE; ++#endif ++#ifdef SET_RANDOM_MAC_SOFTAP ++ SRANDOM32((uint)jiffies); ++ rand_mac = RANDOM32(); ++ iovbuf[0] = (unsigned char)(vendor_oui >> 16) | 0x02; /* local admin bit */ ++ iovbuf[1] = (unsigned char)(vendor_oui >> 8); ++ iovbuf[2] = (unsigned char)vendor_oui; ++ iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; ++ iovbuf[4] = (unsigned char)(rand_mac >> 8); ++ iovbuf[5] = (unsigned char)(rand_mac >> 16); ++ ++ ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char *)&iovbuf, ETHER_ADDR_LEN, NULL, 0, ++ TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); ++ } else ++ memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); ++#endif /* SET_RANDOM_MAC_SOFTAP */ ++#ifdef USE_DYNAMIC_F2_BLKSIZE ++ dhdsdio_func_blocksize(dhd, 2, DYNAMIC_F2_BLKSIZE_FOR_NONLEGACY); ++#endif /* USE_DYNAMIC_F2_BLKSIZE */ ++#ifdef SUPPORT_AP_POWERSAVE ++ dhd_set_ap_powersave(dhd, 0, TRUE); ++#endif /* SUPPORT_AP_POWERSAVE */ ++#ifdef SOFTAP_UAPSD_OFF ++ ret = dhd_iovar(dhd, 0, "wme_apsd", (char *)&wme_apsd, sizeof(wme_apsd), NULL, 0, ++ TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: set wme_apsd 0 fail (error=%d)\n", ++ __FUNCTION__, ret)); ++ } ++#endif /* SOFTAP_UAPSD_OFF */ ++#if defined(CUSTOM_COUNTRY_CODE) && defined(CUSTOMER_HW2) ++ /* set AP flag for specific country code of SOFTAP */ ++ dhd->dhd_cflags |= WLAN_PLAT_AP_FLAG | WLAN_PLAT_NODFS_FLAG; ++#endif /* CUSTOM_COUNTRY_CODE && CUSTOMER_HW2 */ ++ } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || ++ (op_mode == DHD_FLAG_MFG_MODE)) { ++#if defined(ARP_OFFLOAD_SUPPORT) ++ arpoe = 0; ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#ifdef PKT_FILTER_SUPPORT ++ dhd_pkt_filter_enable = FALSE; ++#endif /* PKT_FILTER_SUPPORT */ ++ dhd->op_mode = DHD_FLAG_MFG_MODE; ++#ifdef USE_DYNAMIC_F2_BLKSIZE ++ dhdsdio_func_blocksize(dhd, 2, DYNAMIC_F2_BLKSIZE_FOR_NONLEGACY); ++#endif /* USE_DYNAMIC_F2_BLKSIZE */ ++ if (FW_SUPPORTED(dhd, rsdb)) { ++ rsdb_mode = 0; ++ ret = dhd_iovar(dhd, 0, "rsdb_mode", (char *)&rsdb_mode, sizeof(rsdb_mode), ++ NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s Disable rsdb_mode is failed ret= %d\n", ++ __FUNCTION__, ret)); ++ } ++ } ++ } else { ++ uint32 concurrent_mode = 0; ++ if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) || ++ (op_mode == DHD_FLAG_P2P_MODE)) { ++#if defined(ARP_OFFLOAD_SUPPORT) ++ arpoe = 0; ++#endif ++#ifdef PKT_FILTER_SUPPORT ++ dhd_pkt_filter_enable = FALSE; ++#endif ++ dhd->op_mode = DHD_FLAG_P2P_MODE; ++ } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) || ++ (op_mode == DHD_FLAG_IBSS_MODE)) { ++ dhd->op_mode = DHD_FLAG_IBSS_MODE; ++ } else ++ dhd->op_mode = DHD_FLAG_STA_MODE; ++#if !defined(AP) && defined(WLP2P) ++ if (dhd->op_mode != DHD_FLAG_IBSS_MODE && ++ (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { ++#if defined(ARP_OFFLOAD_SUPPORT) ++ arpoe = 1; ++#endif ++ dhd->op_mode |= concurrent_mode; ++ } ++ ++ /* Check if we are enabling p2p */ ++ if (dhd->op_mode & DHD_FLAG_P2P_MODE) { ++ ret = dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, ++ TRUE); ++ if (ret < 0) ++ DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret)); ++ ++#if defined(SOFTAP_AND_GC) ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_AP, ++ (char *)&ap_mode, sizeof(ap_mode), TRUE, 0)) < 0) { ++ DHD_ERROR(("%s WLC_SET_AP failed %d\n", __FUNCTION__, ret)); ++ } ++#endif ++ memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); ++ ETHER_SET_LOCALADDR(&p2p_ea); ++ ret = dhd_iovar(dhd, 0, "p2p_da_override", (char *)&p2p_ea, sizeof(p2p_ea), ++ NULL, 0, TRUE); ++ if (ret < 0) ++ DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret)); ++ else ++ DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n")); ++ } ++#else ++ (void)concurrent_mode; ++#endif ++ } ++ ++#if defined(RSDB_MODE_FROM_FILE) ++ (void)dhd_rsdb_mode_from_file(dhd); ++#endif ++ ++#ifdef DISABLE_PRUNED_SCAN ++ if (FW_SUPPORTED(dhd, rsdb)) { ++ ret = dhd_iovar(dhd, 0, "scan_features", (char *)&scan_features, ++ sizeof(scan_features), iovbuf, sizeof(iovbuf), FALSE); ++ if (ret < 0) { ++ DHD_ERROR(("%s get scan_features is failed ret=%d\n", ++ __FUNCTION__, ret)); ++ } else { ++ memcpy(&scan_features, iovbuf, 4); ++ scan_features &= ~RSDB_SCAN_DOWNGRADED_CH_PRUNE_ROAM; ++ ret = dhd_iovar(dhd, 0, "scan_features", (char *)&scan_features, ++ sizeof(scan_features), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s set scan_features is failed ret=%d\n", ++ __FUNCTION__, ret)); ++ } ++ } ++ } ++#endif /* DISABLE_PRUNED_SCAN */ ++ ++ DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n", ++ dhd->op_mode, MAC2STRDBG(dhd->mac.octet))); ++#ifdef CUSTOMER_HW2 ++#if defined(DHD_BLOB_EXISTENCE_CHECK) ++ if (!dhd->pub.is_blob) ++#endif /* DHD_BLOB_EXISTENCE_CHECK */ ++ { ++ /* get a ccode and revision for the country code */ ++#if defined(CUSTOM_COUNTRY_CODE) ++ get_customized_country_code(dhd->info->adapter, dhd->dhd_cspec.country_abbrev, ++ &dhd->dhd_cspec, dhd->dhd_cflags); ++#else ++ get_customized_country_code(dhd->info->adapter, dhd->dhd_cspec.country_abbrev, ++ &dhd->dhd_cspec); ++#endif /* CUSTOM_COUNTRY_CODE */ ++ } ++#endif /* CUSTOMER_HW2 */ ++ ++#if defined(RXFRAME_THREAD) && defined(RXTHREAD_ONLYSTA) ++ if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) ++ dhd->info->rxthread_enabled = FALSE; ++ else ++ dhd->info->rxthread_enabled = TRUE; ++#endif ++ /* Set Country code */ ++ if (dhd->dhd_cspec.ccode[0] != 0) { ++ ret = dhd_iovar(dhd, 0, "country", (char *)&dhd->dhd_cspec, sizeof(wl_country_t), ++ NULL, 0, TRUE); ++ if (ret < 0) ++ DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); ++ } ++ ++ ++ /* Set Listen Interval */ ++ ret = dhd_iovar(dhd, 0, "assoc_listen", (char *)&listen_interval, sizeof(listen_interval), ++ NULL, 0, TRUE); ++ if (ret < 0) ++ DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); ++ ++#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) ++#ifdef USE_WFA_CERT_CONF ++ if (sec_get_param_wfa_cert(dhd, SET_PARAM_ROAMOFF, &roamvar) == BCME_OK) { ++ DHD_ERROR(("%s: read roam_off param =%d\n", __FUNCTION__, roamvar)); ++ } ++#endif /* USE_WFA_CERT_CONF */ ++ /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ ++ dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), NULL, 0, TRUE); ++#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ ++#if defined(ROAM_ENABLE) ++#ifdef DISABLE_BCNLOSS_ROAM ++ dhd_iovar(dhd, 0, "roam_bcnloss_off", (char *)&roam_bcnloss_off, sizeof(roam_bcnloss_off), ++ NULL, 0, TRUE); ++#endif /* DISABLE_BCNLOSS_ROAM */ ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, ++ sizeof(roam_trigger), TRUE, 0)) < 0) ++ DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, ++ sizeof(roam_scan_period), TRUE, 0)) < 0) ++ DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret)); ++ if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, ++ sizeof(roam_delta), TRUE, 0)) < 0) ++ DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret)); ++ ret = dhd_iovar(dhd, 0, "fullroamperiod", (char *)&roam_fullscan_period, ++ sizeof(roam_fullscan_period), NULL, 0, TRUE); ++ if (ret < 0) ++ DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); ++#endif /* ROAM_ENABLE */ ++ ++#ifdef CUSTOM_EVENT_PM_WAKE ++ ret = dhd_iovar(dhd, 0, "const_awake_thresh", (char *)&pm_awake_thresh, ++ sizeof(pm_awake_thresh), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s set const_awake_thresh failed %d\n", __FUNCTION__, ret)); ++ } ++#endif /* CUSTOM_EVENT_PM_WAKE */ ++#ifdef WLTDLS ++#ifdef ENABLE_TDLS_AUTO_MODE ++ /* by default TDLS on and auto mode on */ ++ _dhd_tdls_enable(dhd, true, true, NULL); ++#else ++ /* by default TDLS on and auto mode off */ ++ _dhd_tdls_enable(dhd, true, false, NULL); ++#endif /* ENABLE_TDLS_AUTO_MODE */ ++#endif /* WLTDLS */ ++ ++#ifdef DHD_ENABLE_LPC ++ /* Set lpc 1 */ ++ ret = dhd_iovar(dhd, 0, "lpc", (char *)&lpc, sizeof(lpc), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret)); ++ ++ if (ret == BCME_NOTDOWN) { ++ uint wl_down = 1; ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, ++ (char *)&wl_down, sizeof(wl_down), TRUE, 0); ++ DHD_ERROR(("%s lpc fail WL_DOWN : %d, lpc = %d\n", __FUNCTION__, ret, lpc)); ++ ++ ret = dhd_iovar(dhd, 0, "lpc", (char *)&lpc, sizeof(lpc), NULL, 0, TRUE); ++ DHD_ERROR(("%s Set lpc ret --> %d\n", __FUNCTION__, ret)); ++ } ++ } ++#endif /* DHD_ENABLE_LPC */ ++ ++#ifdef WLADPS ++#ifdef WLADPS_SEAK_AP_WAR ++ dhd->disabled_adps = FALSE; ++#endif /* WLADPS_SEAK_AP_WAR */ ++ if (dhd->op_mode & DHD_FLAG_STA_MODE) { ++#ifdef ADPS_MODE_FROM_FILE ++ dhd_adps_mode_from_file(dhd); ++#else ++ if ((ret = dhd_enable_adps(dhd, ADPS_ENABLE)) != BCME_OK) { ++ DHD_ERROR(("%s dhd_enable_adps failed %d\n", ++ __FUNCTION__, ret)); ++ } ++#endif /* ADPS_MODE_FROM_FILE */ ++ } ++#endif /* WLADPS */ ++ ++ /* Set PowerSave mode */ ++ (void) dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); ++ ++#if defined(BCMSDIO) ++ /* Match Host and Dongle rx alignment */ ++ dhd_iovar(dhd, 0, "bus:txglomalign", (char *)&dongle_align, sizeof(dongle_align), ++ NULL, 0, TRUE); ++ ++#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) ++ /* enable credall to reduce the chance of no bus credit happened. */ ++ dhd_iovar(dhd, 0, "bus:credall", (char *)&credall, sizeof(credall), NULL, 0, TRUE); ++#endif ++ ++#ifdef USE_WFA_CERT_CONF ++ if (sec_get_param_wfa_cert(dhd, SET_PARAM_BUS_TXGLOM_MODE, &glom) == BCME_OK) { ++ DHD_ERROR(("%s, read txglom param =%d\n", __FUNCTION__, glom)); ++ } ++#endif /* USE_WFA_CERT_CONF */ ++ if (glom != DEFAULT_GLOM_VALUE) { ++ DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom)); ++ dhd_iovar(dhd, 0, "bus:txglom", (char *)&glom, sizeof(glom), NULL, 0, TRUE); ++ } ++#endif /* defined(BCMSDIO) */ ++ ++ /* Setup timeout if Beacons are lost and roam is off to report link down */ ++ dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, sizeof(bcn_timeout), NULL, 0, TRUE); ++ ++ /* Setup assoc_retry_max count to reconnect target AP in dongle */ ++ dhd_iovar(dhd, 0, "assoc_retry_max", (char *)&retry_max, sizeof(retry_max), NULL, 0, TRUE); ++ ++#if defined(AP) && !defined(WLP2P) ++ dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, TRUE); ++ ++#endif /* defined(AP) && !defined(WLP2P) */ ++ ++#ifdef MIMO_ANT_SETTING ++ dhd_sel_ant_from_file(dhd); ++#endif /* MIMO_ANT_SETTING */ ++ ++#if defined(SOFTAP) ++ if (ap_fw_loaded == TRUE) { ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); ++ } ++#endif ++ ++#if defined(KEEP_ALIVE) ++ { ++ /* Set Keep Alive : be sure to use FW with -keepalive */ ++ int res; ++ ++#if defined(SOFTAP) ++ if (ap_fw_loaded == FALSE) ++#endif ++ if (!(dhd->op_mode & ++ (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) { ++ if ((res = dhd_keep_alive_onoff(dhd)) < 0) ++ DHD_ERROR(("%s set keeplive failed %d\n", ++ __FUNCTION__, res)); ++ } ++ } ++#endif /* defined(KEEP_ALIVE) */ ++ ++#ifdef USE_WL_TXBF ++ ret = dhd_iovar(dhd, 0, "txbf", (char *)&txbf, sizeof(txbf), NULL, 0, TRUE); ++ if (ret < 0) ++ DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret)); ++ ++#endif /* USE_WL_TXBF */ ++ ++ ret = dhd_iovar(dhd, 0, "scancache", (char *)&scancache_enab, sizeof(scancache_enab), NULL, ++ 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s Set scancache failed %d\n", __FUNCTION__, ret)); ++ } ++ ++#ifdef DISABLE_TXBFR ++ ret = dhd_iovar(dhd, 0, "txbf_bfr_cap", (char *)&txbf_bfr_cap, sizeof(txbf_bfr_cap), NULL, ++ 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s Clear txbf_bfr_cap failed %d\n", __FUNCTION__, ret)); ++ } ++#endif /* DISABLE_TXBFR */ ++ ++#ifdef USE_WFA_CERT_CONF ++#ifdef USE_WL_FRAMEBURST ++ if (sec_get_param_wfa_cert(dhd, SET_PARAM_FRAMEBURST, &frameburst) == BCME_OK) { ++ DHD_ERROR(("%s, read frameburst param=%d\n", __FUNCTION__, frameburst)); ++ } ++#endif /* USE_WL_FRAMEBURST */ ++#ifdef DISABLE_FRAMEBURST_VSDB ++ g_frameburst = frameburst; ++#endif /* DISABLE_FRAMEBURST_VSDB */ ++#endif /* USE_WFA_CERT_CONF */ ++#ifdef DISABLE_WL_FRAMEBURST_SOFTAP ++ /* Disable Framebursting for SofAP */ ++ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { ++ frameburst = 0; ++ } ++#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */ ++ /* Set frameburst to value */ ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst, ++ sizeof(frameburst), TRUE, 0)) < 0) { ++ DHD_INFO(("%s frameburst not supported %d\n", __FUNCTION__, ret)); ++ } ++ ++ iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); ++ if (iov_buf == NULL) { ++ DHD_ERROR(("failed to allocate %d bytes for iov_buf\n", WLC_IOCTL_SMLEN)); ++ ret = BCME_NOMEM; ++ goto done; ++ } ++ ++ ++#if defined(CUSTOM_AMPDU_BA_WSIZE) ++ /* Set ampdu ba wsize to 64 or 16 */ ++#ifdef CUSTOM_AMPDU_BA_WSIZE ++ ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE; ++#endif ++ if (ampdu_ba_wsize != 0) { ++ ret = dhd_iovar(dhd, 0, "ampdu_ba_wsize", (char *)&du_ba_wsize, ++ sizeof(ampdu_ba_wsize), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n", ++ __FUNCTION__, ampdu_ba_wsize, ret)); ++ } ++ } ++#endif ++ ++#ifdef ENABLE_TEMP_THROTTLING ++ if (dhd->op_mode & DHD_FLAG_STA_MODE) { ++ memset(&temp_control, 0, sizeof(temp_control)); ++ temp_control.enable = 1; ++ temp_control.control_bit = TEMP_THROTTLE_CONTROL_BIT; ++ ret = dhd_iovar(dhd, 0, "temp_throttle_control", (char *)&temp_control, ++ sizeof(temp_control), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s Set temp_throttle_control to %d failed \n", ++ __FUNCTION__, ret)); ++ } ++ } ++#endif /* ENABLE_TEMP_THROTTLING */ ++ ++#if defined(CUSTOM_AMPDU_MPDU) ++ ampdu_mpdu = CUSTOM_AMPDU_MPDU; ++ if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) { ++ ret = dhd_iovar(dhd, 0, "ampdu_mpdu", (char *)&du_mpdu, sizeof(ampdu_mpdu), ++ NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s Set ampdu_mpdu to %d failed %d\n", ++ __FUNCTION__, CUSTOM_AMPDU_MPDU, ret)); ++ } ++ } ++#endif /* CUSTOM_AMPDU_MPDU */ ++ ++#if defined(CUSTOM_AMPDU_RELEASE) ++ ampdu_release = CUSTOM_AMPDU_RELEASE; ++ if (ampdu_release != 0 && (ampdu_release <= ampdu_ba_wsize)) { ++ ret = dhd_iovar(dhd, 0, "ampdu_release", (char *)&du_release, ++ sizeof(ampdu_release), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s Set ampdu_release to %d failed %d\n", ++ __FUNCTION__, CUSTOM_AMPDU_RELEASE, ret)); ++ } ++ } ++#endif /* CUSTOM_AMPDU_RELEASE */ ++ ++#if defined(CUSTOM_AMSDU_AGGSF) ++ amsdu_aggsf = CUSTOM_AMSDU_AGGSF; ++ if (amsdu_aggsf != 0) { ++ ret = dhd_iovar(dhd, 0, "amsdu_aggsf", (char *)&amsdu_aggsf, sizeof(amsdu_aggsf), ++ NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s Set amsdu_aggsf to %d failed %d\n", ++ __FUNCTION__, CUSTOM_AMSDU_AGGSF, ret)); ++ } ++ } ++#endif /* CUSTOM_AMSDU_AGGSF */ ++ ++#if defined(SUPPORT_5G_1024QAM_VHT) ++#ifdef SUPPORT_5G_1024QAM_VHT ++ if (dhd_get_chipid(dhd) == BCM4361_CHIP_ID) { ++ vht_features |= 0x6; /* 5G 1024 QAM support */ ++ } ++#endif /* SUPPORT_5G_1024QAM_VHT */ ++ if (vht_features) { ++ ret = dhd_iovar(dhd, 0, "vht_features", (char *)&vht_features, sizeof(vht_features), ++ NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret)); ++ ++ if (ret == BCME_NOTDOWN) { ++ uint wl_down = 1; ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, ++ (char *)&wl_down, sizeof(wl_down), TRUE, 0); ++ DHD_ERROR(("%s vht_features fail WL_DOWN : %d," ++ " vht_features = 0x%x\n", ++ __FUNCTION__, ret, vht_features)); ++ ++ ret = dhd_iovar(dhd, 0, "vht_features", (char *)&vht_features, ++ sizeof(vht_features), NULL, 0, TRUE); ++ DHD_ERROR(("%s vht_features set. ret --> %d\n", __FUNCTION__, ret)); ++ } ++ } ++ } ++#endif ++#ifdef DISABLE_11N_PROPRIETARY_RATES ++ ret = dhd_iovar(dhd, 0, "ht_features", (char *)&ht_features, sizeof(ht_features), NULL, 0, ++ TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s ht_features set failed %d\n", __FUNCTION__, ret)); ++ } ++#endif /* DISABLE_11N_PROPRIETARY_RATES */ ++#ifdef CUSTOM_PSPRETEND_THR ++ /* Turn off MPC in AP mode */ ++ ret = dhd_iovar(dhd, 0, "pspretend_threshold", (char *)&pspretend_thr, ++ sizeof(pspretend_thr), NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n", ++ __FUNCTION__, ret)); ++ } ++#endif ++ ++ ret = dhd_iovar(dhd, 0, "buf_key_b4_m4", (char *)&buf_key_b4_m4, sizeof(buf_key_b4_m4), ++ NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret)); ++ } ++#ifdef SUPPORT_SET_CAC ++ bcm_mkiovar("cac", (char *)&cac, sizeof(cac), iovbuf, sizeof(iovbuf)); ++ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { ++ DHD_ERROR(("%s Failed to set cac to %d, %d\n", __FUNCTION__, cac, ret)); ++ } ++#endif /* SUPPORT_SET_CAC */ ++#ifdef DHD_ULP ++ /* Get the required details from dongle during preinit ioctl */ ++ dhd_ulp_preinit(dhd); ++#endif /* DHD_ULP */ ++ ++ /* Read event_msgs mask */ ++ ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, ++ sizeof(iovbuf), FALSE); ++ if (ret < 0) { ++ DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret)); ++ goto done; ++ } ++ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); ++ ++ /* Setup event_msgs */ ++ setbit(eventmask, WLC_E_SET_SSID); ++ setbit(eventmask, WLC_E_PRUNE); ++ setbit(eventmask, WLC_E_AUTH); ++ setbit(eventmask, WLC_E_AUTH_IND); ++ setbit(eventmask, WLC_E_ASSOC); ++ setbit(eventmask, WLC_E_REASSOC); ++ setbit(eventmask, WLC_E_REASSOC_IND); ++ if (!(dhd->op_mode & DHD_FLAG_IBSS_MODE)) ++ setbit(eventmask, WLC_E_DEAUTH); ++ setbit(eventmask, WLC_E_DEAUTH_IND); ++ setbit(eventmask, WLC_E_DISASSOC_IND); ++ setbit(eventmask, WLC_E_DISASSOC); ++ setbit(eventmask, WLC_E_JOIN); ++ setbit(eventmask, WLC_E_BSSID); ++ setbit(eventmask, WLC_E_START); ++ setbit(eventmask, WLC_E_ASSOC_IND); ++ setbit(eventmask, WLC_E_PSK_SUP); ++ setbit(eventmask, WLC_E_LINK); ++ setbit(eventmask, WLC_E_MIC_ERROR); ++ setbit(eventmask, WLC_E_ASSOC_REQ_IE); ++ setbit(eventmask, WLC_E_ASSOC_RESP_IE); ++#ifdef LIMIT_BORROW ++ setbit(eventmask, WLC_E_ALLOW_CREDIT_BORROW); ++#endif ++#ifndef WL_CFG80211 ++ setbit(eventmask, WLC_E_PMKID_CACHE); ++// setbit(eventmask, WLC_E_TXFAIL); // terence 20181106: remove unnecessary event ++#endif ++ setbit(eventmask, WLC_E_JOIN_START); ++// setbit(eventmask, WLC_E_SCAN_COMPLETE); // terence 20150628: remove redundant event ++#ifdef DHD_DEBUG ++ setbit(eventmask, WLC_E_SCAN_CONFIRM_IND); ++#endif ++#ifdef WLMEDIA_HTSF ++ setbit(eventmask, WLC_E_HTSFSYNC); ++#endif /* WLMEDIA_HTSF */ ++#ifdef PNO_SUPPORT ++ setbit(eventmask, WLC_E_PFN_NET_FOUND); ++ setbit(eventmask, WLC_E_PFN_BEST_BATCHING); ++ setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND); ++ setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST); ++#endif /* PNO_SUPPORT */ ++ /* enable dongle roaming event */ ++ setbit(eventmask, WLC_E_ROAM); ++#ifdef WLTDLS ++ setbit(eventmask, WLC_E_TDLS_PEER_EVENT); ++#endif /* WLTDLS */ ++#ifdef WL_ESCAN ++ setbit(eventmask, WLC_E_ESCAN_RESULT); ++#endif /* WL_ESCAN */ ++#ifdef RTT_SUPPORT ++ setbit(eventmask, WLC_E_PROXD); ++#endif /* RTT_SUPPORT */ ++#ifdef WL_CFG80211 ++ setbit(eventmask, WLC_E_ESCAN_RESULT); ++ setbit(eventmask, WLC_E_AP_STARTED); ++ setbit(eventmask, WLC_E_ACTION_FRAME_RX); ++ if (dhd->op_mode & DHD_FLAG_P2P_MODE) { ++ setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); ++ } ++#endif /* WL_CFG80211 */ ++ ++#if defined(SHOW_LOGTRACE) && defined(LOGTRACE_FROM_FILE) ++ if (dhd_logtrace_from_file(dhd)) { ++ setbit(eventmask, WLC_E_TRACE); ++ } else { ++ clrbit(eventmask, WLC_E_TRACE); ++ } ++#elif defined(SHOW_LOGTRACE) ++ setbit(eventmask, WLC_E_TRACE); ++#else ++ clrbit(eventmask, WLC_E_TRACE); ++#endif /* defined(SHOW_LOGTRACE) && defined(LOGTRACE_FROM_FILE) */ ++ ++ setbit(eventmask, WLC_E_CSA_COMPLETE_IND); ++#ifdef DHD_WMF ++ setbit(eventmask, WLC_E_PSTA_PRIMARY_INTF_IND); ++#endif ++#ifdef CUSTOM_EVENT_PM_WAKE ++ setbit(eventmask, WLC_E_EXCESS_PM_WAKE_EVENT); ++#endif /* CUSTOM_EVENT_PM_WAKE */ ++#ifdef DHD_LOSSLESS_ROAMING ++ setbit(eventmask, WLC_E_ROAM_PREP); ++#endif ++#if defined(PCIE_FULL_DONGLE) && defined(DHD_LOSSLESS_ROAMING) ++ dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_LLR_MAP); ++#endif /* defined(PCIE_FULL_DONGLE) && defined(DHD_LOSSLESS_ROAMING) */ ++ ++#if defined(BCMPCIE) && defined(EAPOL_PKT_PRIO) ++ dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_LLR_MAP); ++#endif /* defined(BCMPCIE) && defined(EAPOL_PKT_PRIO) */ ++ ++ /* Write updated Event mask */ ++ ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, NULL, 0, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret)); ++ goto done; ++ } ++ ++ /* make up event mask ext message iovar for event larger than 128 */ ++ msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE; ++ eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL); ++ if (eventmask_msg == NULL) { ++ DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen)); ++ ret = BCME_NOMEM; ++ goto done; ++ } ++ bzero(eventmask_msg, msglen); ++ eventmask_msg->ver = EVENTMSGS_VER; ++ eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; ++ ++ /* Read event_msgs_ext mask */ ++ ret2 = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, ++ WLC_IOCTL_SMLEN, FALSE); ++ ++ if (ret2 == 0) { /* event_msgs_ext must be supported */ ++ bcopy(iov_buf, eventmask_msg, msglen); ++#ifdef RSSI_MONITOR_SUPPORT ++ setbit(eventmask_msg->mask, WLC_E_RSSI_LQM); ++#endif /* RSSI_MONITOR_SUPPORT */ ++#ifdef GSCAN_SUPPORT ++ setbit(eventmask_msg->mask, WLC_E_PFN_GSCAN_FULL_RESULT); ++ setbit(eventmask_msg->mask, WLC_E_PFN_SCAN_COMPLETE); ++ setbit(eventmask_msg->mask, WLC_E_PFN_SSID_EXT); ++ setbit(eventmask_msg->mask, WLC_E_ROAM_EXP_EVENT); ++#endif /* GSCAN_SUPPORT */ ++ setbit(eventmask_msg->mask, WLC_E_RSSI_LQM); ++#ifdef BT_WIFI_HANDOVER ++ setbit(eventmask_msg->mask, WLC_E_BT_WIFI_HANDOVER_REQ); ++#endif /* BT_WIFI_HANDOVER */ ++#ifdef DBG_PKT_MON ++ setbit(eventmask_msg->mask, WLC_E_ROAM_PREP); ++#endif /* DBG_PKT_MON */ ++#ifdef DHD_ULP ++ setbit(eventmask_msg->mask, WLC_E_ULP); ++#endif ++#ifdef ENABLE_TEMP_THROTTLING ++ setbit(eventmask_msg->mask, WLC_E_TEMP_THROTTLE); ++#endif /* ENABLE_TEMP_THROTTLING */ ++ ++ /* Write updated Event mask */ ++ eventmask_msg->ver = EVENTMSGS_VER; ++ eventmask_msg->command = EVENTMSGS_SET_MASK; ++ eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; ++ ret = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, NULL, 0, ++ TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret)); ++ goto done; ++ } ++ } else if (ret2 == BCME_UNSUPPORTED || ret2 == BCME_VERSION) { ++ /* Skip for BCME_UNSUPPORTED or BCME_VERSION */ ++ DHD_ERROR(("%s event_msgs_ext not support or version mismatch %d\n", ++ __FUNCTION__, ret2)); ++ } else { ++ DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2)); ++ ret = ret2; ++ goto done; ++ } ++ ++#if defined(DHD_8021X_DUMP) && defined(SHOW_LOGTRACE) ++ /* Enabling event log trace for EAP events */ ++ el_tag = (wl_el_tag_params_t *)kmalloc(sizeof(wl_el_tag_params_t), GFP_KERNEL); ++ if (el_tag == NULL) { ++ DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", ++ (int)sizeof(wl_el_tag_params_t))); ++ ret = BCME_NOMEM; ++ goto done; ++ } ++ el_tag->tag = EVENT_LOG_TAG_4WAYHANDSHAKE; ++ el_tag->set = 1; ++ el_tag->flags = EVENT_LOG_TAG_FLAG_LOG; ++ bcm_mkiovar("event_log_tag_control", (char *)el_tag, ++ sizeof(*el_tag), iovbuf, sizeof(iovbuf)); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); ++#endif /* DHD_8021X_DUMP */ ++ ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, ++ sizeof(scan_assoc_time), TRUE, 0); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, ++ sizeof(scan_unassoc_time), TRUE, 0); ++ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time, ++ sizeof(scan_passive_time), TRUE, 0); ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ /* Set and enable ARP offload feature for STA only */ ++#if defined(SOFTAP) ++ if (arpoe && !ap_fw_loaded) ++#else ++ if (arpoe) ++#endif ++ { ++ dhd_arp_offload_enable(dhd, TRUE); ++ dhd_arp_offload_set(dhd, dhd_arp_mode); ++ } else { ++ dhd_arp_offload_enable(dhd, FALSE); ++ dhd_arp_offload_set(dhd, 0); ++ } ++ dhd_arp_enable = arpoe; ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#ifdef PKT_FILTER_SUPPORT ++ /* Setup default defintions for pktfilter , enable in suspend */ ++ if (dhd_master_mode) { ++ dhd->pktfilter_count = 6; ++ dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; ++ if (!FW_SUPPORTED(dhd, pf6)) { ++ dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; ++ dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; ++ } else { ++ /* Immediately pkt filter TYPE 6 Discard IPv4/IPv6 Multicast Packet */ ++ dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = DISCARD_IPV4_MCAST; ++ dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = DISCARD_IPV6_MCAST; ++ } ++ /* apply APP pktfilter */ ++ dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; ++ ++ /* Setup filter to allow only unicast */ ++ dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; ++ ++ /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ ++ dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL; ++ ++ dhd->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM] = NULL; ++ if (FW_SUPPORTED(dhd, pf6)) { ++ /* Immediately pkt filter TYPE 6 Dicard Broadcast IP packet */ ++ dhd->pktfilter[DHD_IP4BCAST_DROP_FILTER_NUM] = ++ "107 1 6 IP4_H:16 0xf0 !0xe0 IP4_H:19 0xff 0xff"; ++ dhd->pktfilter_count = 8; ++ } ++ ++#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER ++ dhd->pktfilter_count = 4; ++ /* Setup filter to block broadcast and NAT Keepalive packets */ ++ /* discard all broadcast packets */ ++ dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0xffffff 0xffffff"; ++ /* discard NAT Keepalive packets */ ++ dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "102 0 0 36 0xffffffff 0x11940009"; ++ /* discard NAT Keepalive packets */ ++ dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "104 0 0 38 0xffffffff 0x11940009"; ++ dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; ++#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ ++ } else ++ dhd_conf_discard_pkt_filter(dhd); ++ dhd_conf_add_pkt_filter(dhd); ++ ++#if defined(SOFTAP) ++ if (ap_fw_loaded) { ++ dhd_enable_packet_filter(0, dhd); ++ } ++#endif /* defined(SOFTAP) */ ++ dhd_set_packet_filter(dhd); ++#endif /* PKT_FILTER_SUPPORT */ ++#ifdef DISABLE_11N ++ ret = dhd_iovar(dhd, 0, "nmode", (char *)&nmode, sizeof(nmode), NULL, 0, TRUE); ++ if (ret < 0) ++ DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret)); ++#endif /* DISABLE_11N */ ++ ++#ifdef ENABLE_BCN_LI_BCN_WAKEUP ++ dhd_iovar(dhd, 0, "bcn_li_bcn", (char *)&bcn_li_bcn, sizeof(bcn_li_bcn), NULL, 0, TRUE); ++#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ ++ /* query for 'clmver' to get clm version info from firmware */ ++ memset(buf, 0, sizeof(buf)); ++ ret = dhd_iovar(dhd, 0, "clmver", NULL, 0, buf, sizeof(buf), FALSE); ++ if (ret < 0) ++ DHD_ERROR(("%s clmver failed %d\n", __FUNCTION__, ret)); ++ else { ++ char *ver_temp_buf = NULL, *ver_date_buf = NULL; ++ int len; ++ ++ if ((ver_temp_buf = bcmstrstr(buf, "Data:")) == NULL) { ++ DHD_ERROR(("Couldn't find \"Data:\"\n")); ++ } else { ++ ver_date_buf = bcmstrstr(buf, "Creation:"); ++ ptr = (ver_temp_buf + strlen("Data:")); ++ if ((ver_temp_buf = bcmstrtok(&ptr, "\n", 0)) == NULL) { ++ DHD_ERROR(("Couldn't find New line character\n")); ++ } else { ++ memset(clm_version, 0, CLM_VER_STR_LEN); ++ len = snprintf(clm_version, CLM_VER_STR_LEN - 1, "%s", ver_temp_buf); ++ if (ver_date_buf) { ++ ptr = (ver_date_buf + strlen("Creation:")); ++ ver_date_buf = bcmstrtok(&ptr, "\n", 0); ++ if (ver_date_buf) ++ snprintf(clm_version+len, CLM_VER_STR_LEN-1-len, ++ " (%s)", ver_date_buf); ++ } ++ DHD_INFO(("CLM version = %s\n", clm_version)); ++ } ++ } ++ } ++ ++ /* query for 'ver' to get version info from firmware */ ++ memset(buf, 0, sizeof(buf)); ++ ptr = buf; ++ ret = dhd_iovar(dhd, 0, "ver", NULL, 0, (char *)&buf, sizeof(buf), FALSE); ++ if (ret < 0) ++ DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); ++ else { ++ bcmstrtok(&ptr, "\n", 0); ++ strncpy(fw_version, buf, FW_VER_STR_LEN); ++ fw_version[FW_VER_STR_LEN-1] = '\0'; ++ dhd_set_version_info(dhd, buf); ++#ifdef WRITE_WLANINFO ++ sec_save_wlinfo(buf, EPI_VERSION_STR, dhd->info->nv_path, clm_version); ++#endif /* WRITE_WLANINFO */ ++ } ++#ifdef GEN_SOFTAP_INFO_FILE ++ sec_save_softap_info(); ++#endif /* GEN_SOFTAP_INFO_FILE */ ++ ++#if defined(BCMSDIO) ++ dhd_txglom_enable(dhd, dhd->conf->bus_rxglom); ++#endif /* defined(BCMSDIO) */ ++ ++#if defined(BCMSDIO) || defined(BCMDBUS) ++#ifdef PROP_TXSTATUS ++ if (disable_proptx || ++#ifdef PROP_TXSTATUS_VSDB ++ /* enable WLFC only if the firmware is VSDB when it is in STA mode */ ++ (dhd->op_mode != DHD_FLAG_HOSTAP_MODE && ++ dhd->op_mode != DHD_FLAG_IBSS_MODE) || ++#endif /* PROP_TXSTATUS_VSDB */ ++ FALSE) { ++ wlfc_enable = FALSE; ++ } ++ ret = dhd_conf_get_disable_proptx(dhd); ++ if (ret == 0){ ++ disable_proptx = 0; ++ wlfc_enable = TRUE; ++ } else if (ret >= 1) { ++ disable_proptx = 1; ++ wlfc_enable = FALSE; ++ /* terence 20161229: we should set ampdu_hostreorder=0 when disable_proptx=1 */ ++ hostreorder = 0; ++ } ++ ++#if defined(PROP_TXSTATUS) ++#ifdef USE_WFA_CERT_CONF ++ if (sec_get_param_wfa_cert(dhd, SET_PARAM_PROPTX, &proptx) == BCME_OK) { ++ DHD_ERROR(("%s , read proptx param=%d\n", __FUNCTION__, proptx)); ++ wlfc_enable = proptx; ++ } ++#endif /* USE_WFA_CERT_CONF */ ++#endif /* PROP_TXSTATUS */ ++ ++#ifndef DISABLE_11N ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down, sizeof(wl_down), TRUE, 0); ++ ret2 = dhd_iovar(dhd, 0, "ampdu_hostreorder", (char *)&hostreorder, sizeof(hostreorder), ++ NULL, 0, TRUE); ++ if (ret2 < 0) { ++ DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2)); ++ if (ret2 != BCME_UNSUPPORTED) ++ ret = ret2; ++ ++ if (ret == BCME_NOTDOWN) { ++ uint wl_down = 1; ++ ret2 = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down, ++ sizeof(wl_down), TRUE, 0); ++ DHD_ERROR(("%s ampdu_hostreorder fail WL_DOWN : %d, hostreorder :%d\n", ++ __FUNCTION__, ret2, hostreorder)); ++ ++ ret2 = dhd_iovar(dhd, 0, "ampdu_hostreorder", (char *)&hostreorder, ++ sizeof(hostreorder), NULL, 0, TRUE); ++ DHD_ERROR(("%s wl ampdu_hostreorder. ret --> %d\n", __FUNCTION__, ret2)); ++ if (ret2 != BCME_UNSUPPORTED) ++ ret = ret2; ++ } ++ if (ret2 != BCME_OK) ++ hostreorder = 0; ++ } ++#endif /* DISABLE_11N */ ++ ++ ++ if (wlfc_enable) { ++ dhd_wlfc_init(dhd); ++ /* terence 20161229: enable ampdu_hostreorder if tlv enabled */ ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_hostreorder", 1, 0, TRUE); ++ } ++#ifndef DISABLE_11N ++ else if (hostreorder) ++ dhd_wlfc_hostreorder_init(dhd); ++#endif /* DISABLE_11N */ ++#else ++ /* terence 20161229: disable ampdu_hostreorder if PROP_TXSTATUS not defined */ ++ printf("%s: not define PROP_TXSTATUS\n", __FUNCTION__); ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_hostreorder", 0, 0, TRUE); ++#endif /* PROP_TXSTATUS */ ++#endif /* BCMSDIO || BCMDBUS */ ++#ifndef PCIE_FULL_DONGLE ++ /* For FD we need all the packets at DHD to handle intra-BSS forwarding */ ++ if (FW_SUPPORTED(dhd, ap)) { ++ wl_ap_isolate = AP_ISOLATE_SENDUP_ALL; ++ ret = dhd_iovar(dhd, 0, "ap_isolate", (char *)&wl_ap_isolate, sizeof(wl_ap_isolate), ++ NULL, 0, TRUE); ++ if (ret < 0) ++ DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); ++ } ++#endif /* PCIE_FULL_DONGLE */ ++#ifdef PNO_SUPPORT ++ if (!dhd->pno_state) { ++ dhd_pno_init(dhd); ++ } ++#endif ++#ifdef RTT_SUPPORT ++ if (!dhd->rtt_state) { ++ ret = dhd_rtt_init(dhd); ++ if (ret < 0) { ++ DHD_ERROR(("%s failed to initialize RTT\n", __FUNCTION__)); ++ } ++ } ++#endif ++#ifdef WL11U ++ dhd_interworking_enable(dhd); ++#endif /* WL11U */ ++ ++#ifdef SUPPORT_SENSORHUB ++ DHD_ERROR(("%s: SensorHub enabled %d\n", ++ __FUNCTION__, dhd->info->shub_enable)); ++ ret2 = dhd_iovar(dhd, 0, "shub", NULL, 0, ++ (char *)&shub_ctl, sizeof(shub_ctl), FALSE); ++ if (ret2 < 0) { ++ DHD_ERROR(("%s failed to get shub hub enable information %d\n", ++ __FUNCTION__, ret2)); ++ dhd->info->shub_enable = 0; ++ } else { ++ dhd->info->shub_enable = shub_ctl.enable; ++ DHD_ERROR(("%s: checking sensorhub enable %d\n", ++ __FUNCTION__, dhd->info->shub_enable)); ++ } ++#else ++ DHD_ERROR(("%s: SensorHub diabled %d\n", ++ __FUNCTION__, dhd->info->shub_enable)); ++ dhd->info->shub_enable = FALSE; ++ shub_ctl.enable = FALSE; ++ ret2 = dhd_iovar(dhd, 0, "shub", (char *)&shub_ctl, sizeof(shub_ctl), ++ NULL, 0, TRUE); ++ if (ret2 < 0) { ++ DHD_ERROR(("%s failed to set ShubHub disable\n", ++ __FUNCTION__)); ++ } ++#endif /* SUPPORT_SENSORHUB */ ++ ++ ++#ifdef NDO_CONFIG_SUPPORT ++ dhd->ndo_enable = FALSE; ++ dhd->ndo_host_ip_overflow = FALSE; ++ dhd->ndo_max_host_ip = NDO_MAX_HOST_IP_ENTRIES; ++#endif /* NDO_CONFIG_SUPPORT */ ++ ++ /* ND offload version supported */ ++ dhd->ndo_version = dhd_ndo_get_version(dhd); ++ if (dhd->ndo_version > 0) { ++ DHD_INFO(("%s: ndo version %d\n", __FUNCTION__, dhd->ndo_version)); ++ ++#ifdef NDO_CONFIG_SUPPORT ++ /* enable Unsolicited NA filter */ ++ ret = dhd_ndo_unsolicited_na_filter_enable(dhd, 1); ++ if (ret < 0) { ++ DHD_ERROR(("%s failed to enable Unsolicited NA filter\n", __FUNCTION__)); ++ } ++#endif /* NDO_CONFIG_SUPPORT */ ++ } ++ ++ /* check dongle supports wbtext or not */ ++ dhd->wbtext_support = FALSE; ++ if (dhd_wl_ioctl_get_intiovar(dhd, "wnm_bsstrans_resp", &wnm_bsstrans_resp, ++ WLC_GET_VAR, FALSE, 0) != BCME_OK) { ++ DHD_ERROR(("failed to get wnm_bsstrans_resp\n")); ++ } ++ if (wnm_bsstrans_resp == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) { ++ dhd->wbtext_support = TRUE; ++ } ++#ifndef WBTEXT ++ /* driver can turn off wbtext feature through makefile */ ++ if (dhd->wbtext_support) { ++ if (dhd_wl_ioctl_set_intiovar(dhd, "wnm_bsstrans_resp", ++ WL_BSSTRANS_POLICY_ROAM_ALWAYS, ++ WLC_SET_VAR, FALSE, 0) != BCME_OK) { ++ DHD_ERROR(("failed to disable WBTEXT\n")); ++ } ++ } ++#endif /* !WBTEXT */ ++ ++ /* WNM capabilities */ ++ wnm_cap = 0 ++#ifdef WL11U ++ | WL_WNM_BSSTRANS | WL_WNM_NOTIF ++#endif ++#ifdef WBTEXT ++ | WL_WNM_BSSTRANS | WL_WNM_MAXIDLE ++#endif ++ ; ++ if (dhd_iovar(dhd, 0, "wnm", (char *)&wnm_cap, sizeof(wnm_cap), NULL, 0, TRUE) < 0) { ++ DHD_ERROR(("failed to set WNM capabilities\n")); ++ } ++ ++ dhd_conf_postinit_ioctls(dhd); ++done: ++ ++ if (eventmask_msg) ++ kfree(eventmask_msg); ++ if (iov_buf) ++ kfree(iov_buf); ++#if defined(DHD_8021X_DUMP) && defined(SHOW_LOGTRACE) ++ if (el_tag) ++ kfree(el_tag); ++#endif /* DHD_8021X_DUMP */ ++ return ret; ++} ++ ++ ++int ++dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, char *res_buf, ++ uint res_len, int set) ++{ ++ char *buf = NULL; ++ int input_len; ++ wl_ioctl_t ioc; ++ int ret; ++ ++ if (res_len > WLC_IOCTL_MAXLEN || param_len > WLC_IOCTL_MAXLEN) ++ return BCME_BADARG; ++ ++ input_len = strlen(name) + 1 + param_len; ++ if (input_len > WLC_IOCTL_MAXLEN) ++ return BCME_BADARG; ++ ++ buf = NULL; ++ if (set) { ++ if (res_buf || res_len != 0) { ++ DHD_ERROR(("%s: SET wrong arguemnet\n", __FUNCTION__)); ++ ret = BCME_BADARG; ++ goto exit; ++ } ++ buf = kzalloc(input_len, GFP_KERNEL); ++ if (!buf) { ++ DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); ++ ret = BCME_NOMEM; ++ goto exit; ++ } ++ ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); ++ if (!ret) { ++ ret = BCME_NOMEM; ++ goto exit; ++ } ++ ++ ioc.cmd = WLC_SET_VAR; ++ ioc.buf = buf; ++ ioc.len = input_len; ++ ioc.set = set; ++ ++ ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); ++ } else { ++ if (!res_buf || !res_len) { ++ DHD_ERROR(("%s: GET failed. resp_buf NULL or length 0.\n", __FUNCTION__)); ++ ret = BCME_BADARG; ++ goto exit; ++ } ++ ++ if (res_len < input_len) { ++ DHD_INFO(("%s: res_len(%d) < input_len(%d)\n", __FUNCTION__, ++ res_len, input_len)); ++ buf = kzalloc(input_len, GFP_KERNEL); ++ if (!buf) { ++ DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); ++ ret = BCME_NOMEM; ++ goto exit; ++ } ++ ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); ++ if (!ret) { ++ ret = BCME_NOMEM; ++ goto exit; ++ } ++ ++ ioc.cmd = WLC_GET_VAR; ++ ioc.buf = buf; ++ ioc.len = input_len; ++ ioc.set = set; ++ ++ ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); ++ ++ if (ret == BCME_OK) { ++ memcpy(res_buf, buf, res_len); ++ } ++ } else { ++ memset(res_buf, 0, res_len); ++ ret = bcm_mkiovar(name, param_buf, param_len, res_buf, res_len); ++ if (!ret) { ++ ret = BCME_NOMEM; ++ goto exit; ++ } ++ ++ ioc.cmd = WLC_GET_VAR; ++ ioc.buf = res_buf; ++ ioc.len = res_len; ++ ioc.set = set; ++ ++ ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); ++ } ++ } ++exit: ++ kfree(buf); ++ return ret; ++} ++ ++int ++dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, ++ uint cmd_len, char **resptr, uint resp_len) ++{ ++ int len = resp_len; ++ int ret; ++ char *buf = *resptr; ++ wl_ioctl_t ioc; ++ if (resp_len > WLC_IOCTL_MAXLEN) ++ return BCME_BADARG; ++ ++ memset(buf, 0, resp_len); ++ ++ ret = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); ++ if (ret == 0) { ++ return BCME_BUFTOOSHORT; ++ } ++ ++ memset(&ioc, 0, sizeof(ioc)); ++ ++ ioc.cmd = WLC_GET_VAR; ++ ioc.buf = buf; ++ ioc.len = len; ++ ioc.set = 0; ++ ++ ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); ++ ++ return ret; ++} ++ ++ ++int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) ++{ ++ struct dhd_info *dhd = dhdp->info; ++ struct net_device *dev = NULL; ++ ++ ASSERT(dhd && dhd->iflist[ifidx]); ++ dev = dhd->iflist[ifidx]->net; ++ ASSERT(dev); ++ ++ if (netif_running(dev)) { ++ DHD_ERROR(("%s: Must be down to change its MTU\n", dev->name)); ++ return BCME_NOTDOWN; ++ } ++ ++#define DHD_MIN_MTU 1500 ++#define DHD_MAX_MTU 1752 ++ ++ if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { ++ DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu)); ++ return BCME_BADARG; ++ } ++ ++ dev->mtu = new_mtu; ++ return 0; ++} ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ ++void ++aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx) ++{ ++ u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */ ++ int i; ++ int ret; ++ ++ bzero(ipv4_buf, sizeof(ipv4_buf)); ++ ++ /* display what we've got */ ++ ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); ++ DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__)); ++#ifdef AOE_DBG ++ dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ ++#endif ++ /* now we saved hoste_ip table, clr it in the dongle AOE */ ++ dhd_aoe_hostip_clr(dhd_pub, idx); ++ ++ if (ret) { ++ DHD_ERROR(("%s failed\n", __FUNCTION__)); ++ return; ++ } ++ ++ for (i = 0; i < MAX_IPV4_ENTRIES; i++) { ++ if (add && (ipv4_buf[i] == 0)) { ++ ipv4_buf[i] = ipa; ++ add = FALSE; /* added ipa to local table */ ++ DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n", ++ __FUNCTION__, i)); ++ } else if (ipv4_buf[i] == ipa) { ++ ipv4_buf[i] = 0; ++ DHD_ARPOE(("%s: removed IP:%x from temp table %d\n", ++ __FUNCTION__, ipa, i)); ++ } ++ ++ if (ipv4_buf[i] != 0) { ++ /* add back host_ip entries from our local cache */ ++ dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx); ++ DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n", ++ __FUNCTION__, ipv4_buf[i], i)); ++ } ++ } ++#ifdef AOE_DBG ++ /* see the resulting hostip table */ ++ dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); ++ DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__)); ++ dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ ++#endif ++} ++ ++/* ++ * Notification mechanism from kernel to our driver. This function is called by the Linux kernel ++ * whenever there is an event related to an IP address. ++ * ptr : kernel provided pointer to IP address that has changed ++ */ ++static int dhd_inetaddr_notifier_call(struct notifier_block *this, ++ unsigned long event, ++ void *ptr) ++{ ++ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; ++ ++ dhd_info_t *dhd; ++ dhd_pub_t *dhd_pub; ++ int idx; ++ ++ if (!dhd_arp_enable) ++ return NOTIFY_DONE; ++ if (!ifa || !(ifa->ifa_dev->dev)) ++ return NOTIFY_DONE; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++ /* Filter notifications meant for non Broadcom devices */ ++ if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) && ++ (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) { ++#if defined(WL_ENABLE_P2P_IF) ++ if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) ++#endif /* WL_ENABLE_P2P_IF */ ++ return NOTIFY_DONE; ++ } ++#endif /* LINUX_VERSION_CODE */ ++ ++ dhd = DHD_DEV_INFO(ifa->ifa_dev->dev); ++ if (!dhd) ++ return NOTIFY_DONE; ++ ++ dhd_pub = &dhd->pub; ++ ++ if (dhd_pub->arp_version == 1) { ++ idx = 0; ++ } else { ++ for (idx = 0; idx < DHD_MAX_IFS; idx++) { ++ if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev) ++ break; ++ } ++ if (idx < DHD_MAX_IFS) ++ DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net, ++ dhd->iflist[idx]->name, dhd->iflist[idx]->idx)); ++ else { ++ DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label)); ++ idx = 0; ++ } ++ } ++ ++ switch (event) { ++ case NETDEV_UP: ++ DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n", ++ __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); ++ ++ if (dhd->pub.busstate != DHD_BUS_DATA) { ++ DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__)); ++ if (dhd->pend_ipaddr) { ++ DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n", ++ __FUNCTION__, dhd->pend_ipaddr)); ++ } ++ dhd->pend_ipaddr = ifa->ifa_address; ++ break; ++ } ++ ++#ifdef AOE_IP_ALIAS_SUPPORT ++ DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", ++ __FUNCTION__)); ++ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx); ++#endif /* AOE_IP_ALIAS_SUPPORT */ ++ dhd_conf_set_garp(dhd_pub, idx, ifa->ifa_address, TRUE); ++ break; ++ ++ case NETDEV_DOWN: ++ DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n", ++ __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); ++ dhd->pend_ipaddr = 0; ++#ifdef AOE_IP_ALIAS_SUPPORT ++ DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n", ++ __FUNCTION__)); ++ if ((dhd_pub->op_mode & DHD_FLAG_HOSTAP_MODE) || ++ (ifa->ifa_dev->dev != dhd_linux_get_primary_netdev(dhd_pub))) { ++ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx); ++ } else ++#endif /* AOE_IP_ALIAS_SUPPORT */ ++ { ++ dhd_aoe_hostip_clr(&dhd->pub, idx); ++ dhd_aoe_arp_clr(&dhd->pub, idx); ++ } ++ dhd_conf_set_garp(dhd_pub, idx, ifa->ifa_address, FALSE); ++ break; ++ ++ default: ++ DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n", ++ __func__, ifa->ifa_label, event)); ++ break; ++ } ++ return NOTIFY_DONE; ++} ++#endif /* ARP_OFFLOAD_SUPPORT */ ++ ++#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) ++/* Neighbor Discovery Offload: defered handler */ ++static void ++dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event) ++{ ++ struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data; ++ dhd_info_t *dhd = (dhd_info_t *)dhd_info; ++ dhd_pub_t *dhdp; ++ int ret; ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: invalid dhd_info\n", __FUNCTION__)); ++ goto done; ++ } ++ dhdp = &dhd->pub; ++ ++ if (event != DHD_WQ_WORK_IPV6_NDO) { ++ DHD_ERROR(("%s: unexpected event\n", __FUNCTION__)); ++ goto done; ++ } ++ ++ if (!ndo_work) { ++ DHD_ERROR(("%s: ipv6 work info is not initialized\n", __FUNCTION__)); ++ return; ++ } ++ ++ switch (ndo_work->event) { ++ case NETDEV_UP: ++#ifndef NDO_CONFIG_SUPPORT ++ DHD_TRACE(("%s: Enable NDO \n ", __FUNCTION__)); ++ ret = dhd_ndo_enable(dhdp, TRUE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret)); ++ } ++#endif /* !NDO_CONFIG_SUPPORT */ ++ DHD_TRACE(("%s: Add a host ip for NDO\n", __FUNCTION__)); ++ if (dhdp->ndo_version > 0) { ++ /* inet6 addr notifier called only for unicast address */ ++ ret = dhd_ndo_add_ip_with_type(dhdp, &ndo_work->ipv6_addr[0], ++ WL_ND_IPV6_ADDR_TYPE_UNICAST, ndo_work->if_idx); ++ } else { ++ ret = dhd_ndo_add_ip(dhdp, &ndo_work->ipv6_addr[0], ++ ndo_work->if_idx); ++ } ++ if (ret < 0) { ++ DHD_ERROR(("%s: Adding a host ip for NDO failed %d\n", ++ __FUNCTION__, ret)); ++ } ++ break; ++ case NETDEV_DOWN: ++ if (dhdp->ndo_version > 0) { ++ DHD_TRACE(("%s: Remove a host ip for NDO\n", __FUNCTION__)); ++ ret = dhd_ndo_remove_ip_by_addr(dhdp, ++ &ndo_work->ipv6_addr[0], ndo_work->if_idx); ++ } else { ++ DHD_TRACE(("%s: Clear host ip table for NDO \n", __FUNCTION__)); ++ ret = dhd_ndo_remove_ip(dhdp, ndo_work->if_idx); ++ } ++ if (ret < 0) { ++ DHD_ERROR(("%s: Removing host ip for NDO failed %d\n", ++ __FUNCTION__, ret)); ++ goto done; ++ } ++#ifdef NDO_CONFIG_SUPPORT ++ if (dhdp->ndo_host_ip_overflow) { ++ ret = dhd_dev_ndo_update_inet6addr( ++ dhd_idx2net(dhdp, ndo_work->if_idx)); ++ if ((ret < 0) && (ret != BCME_NORESOURCE)) { ++ DHD_ERROR(("%s: Updating host ip for NDO failed %d\n", ++ __FUNCTION__, ret)); ++ goto done; ++ } ++ } ++#else /* !NDO_CONFIG_SUPPORT */ ++ DHD_TRACE(("%s: Disable NDO\n ", __FUNCTION__)); ++ ret = dhd_ndo_enable(dhdp, FALSE); ++ if (ret < 0) { ++ DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret)); ++ goto done; ++ } ++#endif /* NDO_CONFIG_SUPPORT */ ++ break; ++ ++ default: ++ DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__)); ++ break; ++ } ++done: ++ /* free ndo_work. alloced while scheduling the work */ ++ if (ndo_work) { ++ kfree(ndo_work); ++ } ++ ++ return; ++} ++ ++/* ++ * Neighbor Discovery Offload: Called when an interface ++ * is assigned with ipv6 address. ++ * Handles only primary interface ++ */ ++int dhd_inet6addr_notifier_call(struct notifier_block *this, unsigned long event, void *ptr) ++{ ++ dhd_info_t *dhd; ++ dhd_pub_t *dhdp; ++ struct inet6_ifaddr *inet6_ifa = ptr; ++ struct ipv6_work_info_t *ndo_info; ++ int idx; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++ /* Filter notifications meant for non Broadcom devices */ ++ if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) { ++ return NOTIFY_DONE; ++ } ++#endif /* LINUX_VERSION_CODE */ ++ ++ dhd = DHD_DEV_INFO(inet6_ifa->idev->dev); ++ if (!dhd) { ++ return NOTIFY_DONE; ++ } ++ dhdp = &dhd->pub; ++ ++ /* Supports only primary interface */ ++ idx = dhd_net2idx(dhd, inet6_ifa->idev->dev); ++ if (idx != 0) { ++ return NOTIFY_DONE; ++ } ++ ++ /* FW capability */ ++ if (!FW_SUPPORTED(dhdp, ndoe)) { ++ return NOTIFY_DONE; ++ } ++ ++ ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC); ++ if (!ndo_info) { ++ DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__)); ++ return NOTIFY_DONE; ++ } ++ ++ /* fill up ndo_info */ ++ ndo_info->event = event; ++ ndo_info->if_idx = idx; ++ memcpy(ndo_info->ipv6_addr, &inet6_ifa->addr, IPV6_ADDR_LEN); ++ ++ /* defer the work to thread as it may block kernel */ ++ dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)ndo_info, DHD_WQ_WORK_IPV6_NDO, ++ dhd_inet6_work_handler, DHD_WQ_WORK_PRIORITY_LOW); ++ return NOTIFY_DONE; ++} ++#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ ++ ++int ++dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ dhd_if_t *ifp; ++ struct net_device *net = NULL; ++ int err = 0; ++ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; ++ ++ DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); ++ ++ if (dhd == NULL || dhd->iflist[ifidx] == NULL) { ++ DHD_ERROR(("%s: Invalid Interface\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ ASSERT(dhd && dhd->iflist[ifidx]); ++ ifp = dhd->iflist[ifidx]; ++ net = ifp->net; ++ ASSERT(net && (ifp->idx == ifidx)); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ ASSERT(!net->open); ++ net->get_stats = dhd_get_stats; ++ net->do_ioctl = dhd_ioctl_entry; ++ net->hard_start_xmit = dhd_start_xmit; ++ net->set_mac_address = dhd_set_mac_address; ++ net->set_multicast_list = dhd_set_multicast_list; ++ net->open = net->stop = NULL; ++#else ++ ASSERT(!net->netdev_ops); ++ net->netdev_ops = &dhd_ops_virt; ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ ++ ++ /* Ok, link into the network layer... */ ++ if (ifidx == 0) { ++ /* ++ * device functions for the primary interface only ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) ++ net->open = dhd_open; ++ net->stop = dhd_stop; ++#else ++ net->netdev_ops = &dhd_ops_pri; ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ ++ if (!ETHER_ISNULLADDR(dhd->pub.mac.octet)) ++ memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); ++ } else { ++ /* ++ * We have to use the primary MAC for virtual interfaces ++ */ ++ memcpy(temp_addr, ifp->mac_addr, ETHER_ADDR_LEN); ++ /* ++ * Android sets the locally administered bit to indicate that this is a ++ * portable hotspot. This will not work in simultaneous AP/STA mode, ++ * nor with P2P. Need to set the Donlge's MAC address, and then use that. ++ */ ++ if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, ++ ETHER_ADDR_LEN)) { ++ DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", ++ __func__, net->name)); ++ temp_addr[0] |= 0x02; ++ } ++ } ++ ++ net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) ++ net->ethtool_ops = &dhd_ethtool_ops; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ ++ ++#if defined(WL_WIRELESS_EXT) ++#if WIRELESS_EXT < 19 ++ net->get_wireless_stats = dhd_get_wireless_stats; ++#endif /* WIRELESS_EXT < 19 */ ++#if WIRELESS_EXT > 12 ++ net->wireless_handlers = &wl_iw_handler_def; ++#endif /* WIRELESS_EXT > 12 */ ++#endif /* defined(WL_WIRELESS_EXT) */ ++ ++ dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); ++ ++#ifdef WLMESH ++ if (ifidx >= 2 && dhdp->conf->fw_type == FW_TYPE_MESH) { ++ temp_addr[4] ^= 0x80; ++ temp_addr[4] += ifidx; ++ temp_addr[5] += ifidx; ++ } ++#endif ++ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); ++ ++ if (ifidx == 0) ++ printf("%s\n", dhd_version); ++ else { ++#ifdef WL_EXT_IAPSTA ++ wl_ext_iapsta_update_net_device(net, ifidx); ++#endif /* WL_EXT_IAPSTA */ ++ if (_dhd_set_mac_address(dhd, ifidx, net->dev_addr) == 0) ++ DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); ++ else ++ DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); ++ } ++ ++ if (need_rtnl_lock) ++ err = register_netdev(net); ++ else ++ err = register_netdevice(net); ++ ++ if (err != 0) { ++ DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err)); ++ goto fail; ++ } ++#if defined(WL_EXT_IAPSTA) || defined(USE_IW) || defined(WL_ESCAN) ++ wl_ext_event_attach_netdev(net, ifidx, ifp->bssidx); ++#ifdef WL_ESCAN ++ wl_escan_event_attach(net, dhdp); ++#endif /* WL_ESCAN */ ++#ifdef WL_EXT_IAPSTA ++ wl_ext_iapsta_attach_netdev(net, ifidx, ifp->bssidx); ++ wl_ext_iapsta_attach_name(net, ifidx); ++#endif /* WL_EXT_IAPSTA */ ++#endif /* WL_EXT_IAPSTA || USE_IW || WL_ESCAN */ ++ ++ ++ ++ printf("Register interface [%s] MAC: "MACDBG"\n\n", net->name, ++#if defined(CUSTOMER_HW4_DEBUG) ++ MAC2STRDBG(dhd->pub.mac.octet)); ++#else ++ MAC2STRDBG(net->dev_addr)); ++#endif /* CUSTOMER_HW4_DEBUG */ ++ ++#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211) ++// wl_iw_iscan_set_scan_broadcast_prep(net, 1); ++#endif ++ ++#if (defined(BCMPCIE) || (defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= \ ++ KERNEL_VERSION(2, 6, 27))) || defined(BCMDBUS)) ++ if (ifidx == 0) { ++#if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD) ++ up(&dhd_registration_sem); ++#endif /* BCMLXSDMMC */ ++ if (!dhd_download_fw_on_driverload) { ++#ifdef WL_CFG80211 ++ wl_terminate_event_handler(net); ++#endif /* WL_CFG80211 */ ++#if defined(DHD_LB_RXP) ++ __skb_queue_purge(&dhd->rx_pend_queue); ++#endif /* DHD_LB_RXP */ ++ ++#if defined(DHD_LB_TXP) ++ skb_queue_purge(&dhd->tx_pend_queue); ++#endif /* DHD_LB_TXP */ ++ ++#ifdef SHOW_LOGTRACE ++ /* Release the skbs from queue for WLC_E_TRACE event */ ++ dhd_event_logtrace_flush_queue(dhdp); ++#endif /* SHOW_LOGTRACE */ ++ ++#ifdef DHDTCPACK_SUPPRESS ++ dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); ++#endif /* DHDTCPACK_SUPPRESS */ ++ dhd_net_bus_devreset(net, TRUE); ++#ifdef BCMLXSDMMC ++ dhd_net_bus_suspend(net); ++#endif /* BCMLXSDMMC */ ++ wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY); ++#if defined(BT_OVER_SDIO) ++ dhd->bus_user_count--; ++#endif /* BT_OVER_SDIO */ ++ } ++#if defined(WL_WIRELESS_EXT) ++ wl_iw_down(net, &dhd->pub); ++#endif /* defined(WL_WIRELESS_EXT) */ ++ } ++#endif /* OEM_ANDROID && (BCMPCIE || (BCMLXSDMMC && KERNEL_VERSION >= 2.6.27)) */ ++ return 0; ++ ++fail: ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) ++ net->open = NULL; ++#else ++ net->netdev_ops = NULL; ++#endif ++ return err; ++} ++ ++void ++dhd_bus_detach(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (dhdp) { ++ dhd = (dhd_info_t *)dhdp->info; ++ if (dhd) { ++ ++ /* ++ * In case of Android cfg80211 driver, the bus is down in dhd_stop, ++ * calling stop again will cuase SD read/write errors. ++ */ ++ if (dhd->pub.busstate != DHD_BUS_DOWN && dhd_download_fw_on_driverload) { ++ /* Stop the protocol module */ ++ dhd_prot_stop(&dhd->pub); ++ ++ /* Stop the bus module */ ++#ifdef BCMDBUS ++ /* Force Dongle terminated */ ++ if (dhd_wl_ioctl_cmd(dhdp, WLC_TERMINATED, NULL, 0, TRUE, 0) < 0) ++ DHD_ERROR(("%s Setting WLC_TERMINATED failed\n", ++ __FUNCTION__)); ++ dbus_stop(dhd->pub.bus); ++ dhd->pub.busstate = DHD_BUS_DOWN; ++#else ++ dhd_bus_stop(dhd->pub.bus, TRUE); ++#endif /* BCMDBUS */ ++ } ++ ++#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE) ++ dhd_bus_oob_intr_unregister(dhdp); ++#endif ++ } ++ } ++} ++ ++ ++void dhd_detach(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ unsigned long flags; ++ int timer_valid = FALSE; ++ struct net_device *dev; ++#ifdef WL_CFG80211 ++ struct bcm_cfg80211 *cfg = NULL; ++#endif ++#ifdef HOFFLOAD_MODULES ++ struct module_metadata *hmem = NULL; ++#endif ++ if (!dhdp) ++ return; ++ ++ dhd = (dhd_info_t *)dhdp->info; ++ if (!dhd) ++ return; ++ ++ dev = dhd->iflist[0]->net; ++ ++ if (dev) { ++ rtnl_lock(); ++ if (dev->flags & IFF_UP) { ++ /* If IFF_UP is still up, it indicates that ++ * "ifconfig wlan0 down" hasn't been called. ++ * So invoke dev_close explicitly here to ++ * bring down the interface. ++ */ ++ DHD_TRACE(("IFF_UP flag is up. Enforcing dev_close from detach \n")); ++ dev_close(dev); ++ } ++ rtnl_unlock(); ++ } ++ ++ DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); ++ ++ dhd->pub.up = 0; ++ if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { ++ /* Give sufficient time for threads to start running in case ++ * dhd_attach() has failed ++ */ ++ OSL_SLEEP(100); ++ } ++#ifdef DHD_WET ++ dhd_free_wet_info(&dhd->pub, dhd->pub.wet_info); ++#endif /* DHD_WET */ ++#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) ++#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ ++ ++#ifdef PROP_TXSTATUS ++#ifdef DHD_WLFC_THREAD ++ if (dhd->pub.wlfc_thread) { ++ kthread_stop(dhd->pub.wlfc_thread); ++ dhdp->wlfc_thread_go = TRUE; ++ wake_up_interruptible(&dhdp->wlfc_wqhead); ++ } ++ dhd->pub.wlfc_thread = NULL; ++#endif /* DHD_WLFC_THREAD */ ++#endif /* PROP_TXSTATUS */ ++ ++#ifdef DHD_TIMESYNC ++ if (dhd->dhd_state & DHD_ATTACH_TIMESYNC_ATTACH_DONE) { ++ dhd_timesync_detach(dhdp); ++ } ++#endif /* DHD_TIMESYNC */ ++#ifdef WL_CFG80211 ++ if (dev) { ++ wl_cfg80211_down(dev); ++ } ++#endif /* WL_CFG80211 */ ++ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { ++ dhd_bus_detach(dhdp); ++#ifdef BCMPCIE ++ if (is_reboot == SYS_RESTART) { ++ extern bcmdhd_wifi_platdata_t *dhd_wifi_platdata; ++ if (dhd_wifi_platdata && !dhdp->dongle_reset) { ++ dhdpcie_bus_clock_stop(dhdp->bus); ++ wifi_platform_set_power(dhd_wifi_platdata->adapters, ++ FALSE, WIFI_TURNOFF_DELAY); ++ } ++ } ++#endif /* BCMPCIE */ ++#ifndef PCIE_FULL_DONGLE ++ if (dhdp->prot) ++ dhd_prot_detach(dhdp); ++#endif /* !PCIE_FULL_DONGLE */ ++ } ++ ++#ifdef ARP_OFFLOAD_SUPPORT ++ if (dhd_inetaddr_notifier_registered) { ++ dhd_inetaddr_notifier_registered = FALSE; ++ unregister_inetaddr_notifier(&dhd_inetaddr_notifier); ++ } ++#endif /* ARP_OFFLOAD_SUPPORT */ ++#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) ++ if (dhd_inet6addr_notifier_registered) { ++ dhd_inet6addr_notifier_registered = FALSE; ++ unregister_inet6addr_notifier(&dhd_inet6addr_notifier); ++ } ++#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { ++ if (dhd->early_suspend.suspend) ++ unregister_early_suspend(&dhd->early_suspend); ++ } ++#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ ++ ++#if defined(WL_WIRELESS_EXT) ++ if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { ++ /* Detatch and unlink in the iw */ ++ wl_iw_detach(dev, dhdp); ++ } ++#endif /* defined(WL_WIRELESS_EXT) */ ++#if defined(WL_EXT_IAPSTA) || defined(USE_IW) || defined(WL_ESCAN) ++#ifdef WL_EXT_IAPSTA ++ wl_ext_iapsta_dettach(dhdp); ++#endif /* WL_EXT_IAPSTA */ ++#ifdef WL_ESCAN ++ wl_escan_detach(dev, dhdp); ++#endif /* WL_ESCAN */ ++ wl_ext_event_dettach(dhdp); ++#endif /* WL_EXT_IAPSTA || USE_IW || WL_ESCAN */ ++ ++#ifdef DHD_ULP ++ dhd_ulp_deinit(dhd->pub.osh, dhdp); ++#endif /* DHD_ULP */ ++ ++ /* delete all interfaces, start with virtual */ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { ++ int i = 1; ++ dhd_if_t *ifp; ++ ++ /* Cleanup virtual interfaces */ ++ dhd_net_if_lock_local(dhd); ++ for (i = 1; i < DHD_MAX_IFS; i++) { ++ if (dhd->iflist[i]) { ++ dhd_remove_if(&dhd->pub, i, TRUE); ++ } ++ } ++ dhd_net_if_unlock_local(dhd); ++ ++ /* delete primary interface 0 */ ++ ifp = dhd->iflist[0]; ++ ASSERT(ifp); ++ ASSERT(ifp->net); ++ if (ifp && ifp->net) { ++#ifdef WL_CFG80211 ++ cfg = wl_get_cfg(ifp->net); ++#endif ++ /* in unregister_netdev case, the interface gets freed by net->destructor ++ * (which is set to free_netdev) ++ */ ++ if (ifp->net->reg_state == NETREG_UNINITIALIZED) { ++ free_netdev(ifp->net); ++ } else { ++ argos_register_notifier_deinit(); ++#ifdef SET_RPS_CPUS ++ custom_rps_map_clear(ifp->net->_rx); ++#endif /* SET_RPS_CPUS */ ++ netif_tx_disable(ifp->net); ++ unregister_netdev(ifp->net); ++ } ++#ifdef PCIE_FULL_DONGLE ++ ifp->net = DHD_NET_DEV_NULL; ++#else ++ ifp->net = NULL; ++#endif /* PCIE_FULL_DONGLE */ ++ ++#ifdef DHD_WMF ++ dhd_wmf_cleanup(dhdp, 0); ++#endif /* DHD_WMF */ ++#ifdef DHD_L2_FILTER ++ bcm_l2_filter_arp_table_update(dhdp->osh, ifp->phnd_arp_table, TRUE, ++ NULL, FALSE, dhdp->tickcnt); ++ deinit_l2_filter_arp_table(dhdp->osh, ifp->phnd_arp_table); ++ ifp->phnd_arp_table = NULL; ++#endif /* DHD_L2_FILTER */ ++ ++ ++ dhd_if_del_sta_list(ifp); ++ ++ MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); ++ dhd->iflist[0] = NULL; ++ } ++ } ++ ++ /* Clear the watchdog timer */ ++ DHD_GENERAL_LOCK(&dhd->pub, flags); ++ timer_valid = dhd->wd_timer_valid; ++ dhd->wd_timer_valid = FALSE; ++ DHD_GENERAL_UNLOCK(&dhd->pub, flags); ++ if (timer_valid) ++ _del_timer_sync(&dhd->timer); ++ DHD_DISABLE_RUNTIME_PM(&dhd->pub); ++ ++#ifdef BCMDBUS ++ tasklet_kill(&dhd->tasklet); ++#else ++ if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { ++#ifdef DHD_PCIE_RUNTIMEPM ++ if (dhd->thr_rpm_ctl.thr_pid >= 0) { ++ PROC_STOP(&dhd->thr_rpm_ctl); ++ } ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ if (dhd->thr_wdt_ctl.thr_pid >= 0) { ++ PROC_STOP(&dhd->thr_wdt_ctl); ++ } ++ ++ if (dhd->rxthread_enabled && dhd->thr_rxf_ctl.thr_pid >= 0) { ++ PROC_STOP(&dhd->thr_rxf_ctl); ++ } ++ ++ if (dhd->thr_dpc_ctl.thr_pid >= 0) { ++ PROC_STOP(&dhd->thr_dpc_ctl); ++ } else ++ { ++ tasklet_kill(&dhd->tasklet); ++ } ++ } ++#endif /* BCMDBUS */ ++ ++#ifdef DHD_LB ++ if (dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE) { ++ /* Clear the flag first to avoid calling the cpu notifier */ ++ dhd->dhd_state &= ~DHD_ATTACH_STATE_LB_ATTACH_DONE; ++ ++ /* Kill the Load Balancing Tasklets */ ++#ifdef DHD_LB_RXP ++ cancel_work_sync(&dhd->rx_napi_dispatcher_work); ++ __skb_queue_purge(&dhd->rx_pend_queue); ++#endif /* DHD_LB_RXP */ ++#ifdef DHD_LB_TXP ++ cancel_work_sync(&dhd->tx_dispatcher_work); ++ tasklet_kill(&dhd->tx_tasklet); ++ __skb_queue_purge(&dhd->tx_pend_queue); ++#endif /* DHD_LB_TXP */ ++#ifdef DHD_LB_TXC ++ cancel_work_sync(&dhd->tx_compl_dispatcher_work); ++ tasklet_kill(&dhd->tx_compl_tasklet); ++#endif /* DHD_LB_TXC */ ++#ifdef DHD_LB_RXC ++ tasklet_kill(&dhd->rx_compl_tasklet); ++#endif /* DHD_LB_RXC */ ++ ++ if (dhd->cpu_notifier.notifier_call != NULL) { ++ unregister_cpu_notifier(&dhd->cpu_notifier); ++ } ++ dhd_cpumasks_deinit(dhd); ++ DHD_LB_STATS_DEINIT(&dhd->pub); ++ } ++#endif /* DHD_LB */ ++ ++ DHD_SSSR_MEMPOOL_DEINIT(&dhd->pub); ++ ++#ifdef DHD_LOG_DUMP ++ dhd_log_dump_deinit(&dhd->pub); ++#endif /* DHD_LOG_DUMP */ ++#ifdef WL_CFG80211 ++ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { ++ if (!cfg) { ++ DHD_ERROR(("cfg NULL!\n")); ++ ASSERT(0); ++ } else { ++ wl_cfg80211_detach(cfg); ++ dhd_monitor_uninit(); ++ } ++ } ++#endif ++ ++#ifdef DEBUGABILITY ++ if (dhdp->dbg) { ++#ifdef DBG_PKT_MON ++ dhd_os_dbg_detach_pkt_monitor(dhdp); ++ dhd_os_spin_lock_deinit(dhd->pub.osh, dhd->pub.dbg->pkt_mon_lock); ++#endif /* DBG_PKT_MON */ ++ dhd_os_dbg_detach(dhdp); ++ } ++#endif /* DEBUGABILITY */ ++#ifdef SHOW_LOGTRACE ++#ifdef DHD_PKT_LOGGING ++ dhd_os_detach_pktlog(dhdp); ++#endif /* DHD_PKT_LOGGING */ ++ /* Release the skbs from queue for WLC_E_TRACE event */ ++ dhd_event_logtrace_flush_queue(dhdp); ++ ++ if (dhd->dhd_state & DHD_ATTACH_LOGTRACE_INIT) { ++ if (dhd->event_data.fmts) { ++ MFREE(dhd->pub.osh, dhd->event_data.fmts, ++ dhd->event_data.fmts_size); ++ dhd->event_data.fmts = NULL; ++ } ++ if (dhd->event_data.raw_fmts) { ++ MFREE(dhd->pub.osh, dhd->event_data.raw_fmts, ++ dhd->event_data.raw_fmts_size); ++ dhd->event_data.raw_fmts = NULL; ++ } ++ if (dhd->event_data.raw_sstr) { ++ MFREE(dhd->pub.osh, dhd->event_data.raw_sstr, ++ dhd->event_data.raw_sstr_size); ++ dhd->event_data.raw_sstr = NULL; ++ } ++ if (dhd->event_data.rom_raw_sstr) { ++ MFREE(dhd->pub.osh, dhd->event_data.rom_raw_sstr, ++ dhd->event_data.rom_raw_sstr_size); ++ dhd->event_data.rom_raw_sstr = NULL; ++ } ++ dhd->dhd_state &= ~DHD_ATTACH_LOGTRACE_INIT; ++ } ++#endif /* SHOW_LOGTRACE */ ++#ifdef BCMPCIE ++ if (dhdp->extended_trap_data) ++ { ++ MFREE(dhdp->osh, dhdp->extended_trap_data, BCMPCIE_EXT_TRAP_DATA_MAXLEN); ++ dhdp->extended_trap_data = NULL; ++ } ++#endif /* BCMPCIE */ ++#ifdef PNO_SUPPORT ++ if (dhdp->pno_state) ++ dhd_pno_deinit(dhdp); ++#endif ++#ifdef RTT_SUPPORT ++ if (dhdp->rtt_state) { ++ dhd_rtt_deinit(dhdp); ++ } ++#endif ++#if defined(CONFIG_PM_SLEEP) ++ if (dhd_pm_notifier_registered) { ++ unregister_pm_notifier(&dhd->pm_notifier); ++ dhd_pm_notifier_registered = FALSE; ++ } ++#endif /* CONFIG_PM_SLEEP */ ++ ++#ifdef DEBUG_CPU_FREQ ++ if (dhd->new_freq) ++ free_percpu(dhd->new_freq); ++ dhd->new_freq = NULL; ++ cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); ++#endif ++ DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd->wakelock_wd_counter = 0; ++ wake_lock_destroy(&dhd->wl_wdwake); ++ // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry ++ wake_lock_destroy(&dhd->wl_wifi); ++#endif /* CONFIG_HAS_WAKELOCK */ ++ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { ++ DHD_OS_WAKE_LOCK_DESTROY(dhd); ++ } ++ ++ ++ ++#ifdef DHDTCPACK_SUPPRESS ++ /* This will free all MEM allocated for TCPACK SUPPRESS */ ++ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++#ifdef PCIE_FULL_DONGLE ++ dhd_flow_rings_deinit(dhdp); ++ if (dhdp->prot) ++ dhd_prot_detach(dhdp); ++#endif ++ ++#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) ++ dhd_free_tdls_peer_list(dhdp); ++#endif ++ ++#ifdef HOFFLOAD_MODULES ++ hmem = &dhdp->hmem; ++ dhd_free_module_memory(dhdp->bus, hmem); ++#endif /* HOFFLOAD_MODULES */ ++#if defined(BT_OVER_SDIO) ++ mutex_destroy(&dhd->bus_user_lock); ++#endif /* BT_OVER_SDIO */ ++#ifdef DUMP_IOCTL_IOV_LIST ++ dhd_iov_li_delete(dhdp, &(dhdp->dump_iovlist_head)); ++#endif /* DUMP_IOCTL_IOV_LIST */ ++#ifdef DHD_DEBUG ++ /* memory waste feature list initilization */ ++ dhd_mw_list_delete(dhdp, &(dhdp->mw_list_head)); ++#endif /* DHD_DEBUG */ ++#ifdef WL_MONITOR ++ dhd_del_monitor_if(dhd, NULL, DHD_WQ_WORK_IF_DEL); ++#endif /* WL_MONITOR */ ++ ++ /* Prefer adding de-init code above this comment unless necessary. ++ * The idea is to cancel work queue, sysfs and flags at the end. ++ */ ++ dhd_deferred_work_deinit(dhd->dhd_deferred_wq); ++ dhd->dhd_deferred_wq = NULL; ++ ++#ifdef SHOW_LOGTRACE ++ /* Wait till event_log_dispatcher_work finishes */ ++ cancel_work_sync(&dhd->event_log_dispatcher_work); ++#endif /* SHOW_LOGTRACE */ ++ ++ dhd_sysfs_exit(dhd); ++ dhd->pub.fw_download_done = FALSE; ++ dhd_conf_detach(dhdp); ++} ++ ++ ++void ++dhd_free(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd; ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (dhdp) { ++ int i; ++ for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { ++ if (dhdp->reorder_bufs[i]) { ++ reorder_info_t *ptr; ++ uint32 buf_size = sizeof(struct reorder_info); ++ ++ ptr = dhdp->reorder_bufs[i]; ++ ++ buf_size += ((ptr->max_idx + 1) * sizeof(void*)); ++ DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", ++ i, ptr->max_idx, buf_size)); ++ ++ MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); ++ dhdp->reorder_bufs[i] = NULL; ++ } ++ } ++ ++ dhd_sta_pool_fini(dhdp, DHD_MAX_STA); ++ ++ dhd = (dhd_info_t *)dhdp->info; ++ if (dhdp->soc_ram) { ++#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) ++ DHD_OS_PREFREE(dhdp, dhdp->soc_ram, dhdp->soc_ram_length); ++#else ++ MFREE(dhdp->osh, dhdp->soc_ram, dhdp->soc_ram_length); ++#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ ++ dhdp->soc_ram = NULL; ++ } ++#ifdef CACHE_FW_IMAGES ++ if (dhdp->cached_fw) { ++ MFREE(dhdp->osh, dhdp->cached_fw, dhdp->bus->ramsize); ++ dhdp->cached_fw = NULL; ++ } ++ ++ if (dhdp->cached_nvram) { ++ MFREE(dhdp->osh, dhdp->cached_nvram, MAX_NVRAMBUF_SIZE); ++ dhdp->cached_nvram = NULL; ++ } ++#endif ++ if (dhd) { ++#ifdef REPORT_FATAL_TIMEOUTS ++ deinit_dhd_timeouts(&dhd->pub); ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++ /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */ ++ if (dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, ++ DHD_PREALLOC_DHD_INFO, 0, FALSE)) ++ MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); ++ dhd = NULL; ++ } ++ } ++} ++ ++void ++dhd_clear(dhd_pub_t *dhdp) ++{ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (dhdp) { ++ int i; ++#ifdef DHDTCPACK_SUPPRESS ++ /* Clean up timer/data structure for any remaining/pending packet or timer. */ ++ dhd_tcpack_info_tbl_clean(dhdp); ++#endif /* DHDTCPACK_SUPPRESS */ ++ for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { ++ if (dhdp->reorder_bufs[i]) { ++ reorder_info_t *ptr; ++ uint32 buf_size = sizeof(struct reorder_info); ++ ++ ptr = dhdp->reorder_bufs[i]; ++ ++ buf_size += ((ptr->max_idx + 1) * sizeof(void*)); ++ DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", ++ i, ptr->max_idx, buf_size)); ++ ++ MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); ++ dhdp->reorder_bufs[i] = NULL; ++ } ++ } ++ ++ dhd_sta_pool_clear(dhdp, DHD_MAX_STA); ++ ++ if (dhdp->soc_ram) { ++#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) ++ DHD_OS_PREFREE(dhdp, dhdp->soc_ram, dhdp->soc_ram_length); ++#else ++ MFREE(dhdp->osh, dhdp->soc_ram, dhdp->soc_ram_length); ++#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ ++ dhdp->soc_ram = NULL; ++ } ++ } ++} ++ ++static void ++dhd_module_cleanup(void) ++{ ++ printf("%s: Enter\n", __FUNCTION__); ++ ++ dhd_bus_unregister(); ++ ++ wl_android_exit(); ++ ++ dhd_wifi_platform_unregister_drv(); ++ printf("%s: Exit\n", __FUNCTION__); ++} ++ ++static void __exit ++dhd_module_exit(void) ++{ ++ atomic_set(&exit_in_progress, 1); ++ dhd_module_cleanup(); ++ unregister_reboot_notifier(&dhd_reboot_notifier); ++ dhd_destroy_to_notifier_skt(); ++} ++ ++static int __init ++dhd_module_init(void) ++{ ++ int err; ++ int retry = POWERUP_MAX_RETRY; ++ ++ printf("%s: in %s\n", __FUNCTION__, dhd_version); ++ ++ DHD_PERIM_RADIO_INIT(); ++ ++ ++ if (firmware_path[0] != '\0') { ++ strncpy(fw_bak_path, firmware_path, MOD_PARAM_PATHLEN); ++ fw_bak_path[MOD_PARAM_PATHLEN-1] = '\0'; ++ } ++ ++ if (nvram_path[0] != '\0') { ++ strncpy(nv_bak_path, nvram_path, MOD_PARAM_PATHLEN); ++ nv_bak_path[MOD_PARAM_PATHLEN-1] = '\0'; ++ } ++ ++ do { ++ err = dhd_wifi_platform_register_drv(); ++ if (!err) { ++ register_reboot_notifier(&dhd_reboot_notifier); ++ break; ++ } else { ++ DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n", ++ __FUNCTION__, retry)); ++ strncpy(firmware_path, fw_bak_path, MOD_PARAM_PATHLEN); ++ firmware_path[MOD_PARAM_PATHLEN-1] = '\0'; ++ strncpy(nvram_path, nv_bak_path, MOD_PARAM_PATHLEN); ++ nvram_path[MOD_PARAM_PATHLEN-1] = '\0'; ++ } ++ } while (retry--); ++ ++ dhd_create_to_notifier_skt(); ++ ++ if (err) { ++ DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__)); ++ } else { ++ if (!dhd_download_fw_on_driverload) { ++ dhd_driver_init_done = TRUE; ++ } ++ } ++ ++ printf("%s: Exit err=%d\n", __FUNCTION__, err); ++ return err; ++} ++ ++static int ++dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused) ++{ ++ DHD_TRACE(("%s: code = %ld\n", __FUNCTION__, code)); ++ if (code == SYS_RESTART) { ++#ifdef BCMPCIE ++ is_reboot = code; ++#endif /* BCMPCIE */ ++ } ++ return NOTIFY_DONE; ++} ++ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++#if defined(CONFIG_DEFERRED_INITCALLS) && !defined(EXYNOS_PCIE_MODULE_PATCH) ++#if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS8890) || \ ++ defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_SOC_EXYNOS8895) || \ ++ defined(CONFIG_ARCH_MSM8998) ++deferred_module_init_sync(dhd_module_init); ++#else ++deferred_module_init(dhd_module_init); ++#endif /* CONFIG_MACH_UNIVERSAL7420 || CONFIG_SOC_EXYNOS8890 || ++ * CONFIG_ARCH_MSM8996 || CONFIG_SOC_EXYNOS8895 || CONFIG_ARCH_MSM8998 ++ */ ++#elif defined(USE_LATE_INITCALL_SYNC) ++late_initcall_sync(dhd_module_init); ++#else ++late_initcall(dhd_module_init); ++#endif /* USE_LATE_INITCALL_SYNC */ ++#else ++module_init(dhd_module_init); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ ++ ++module_exit(dhd_module_exit); ++ ++/* ++ * OS specific functions required to implement DHD driver in OS independent way ++ */ ++int ++dhd_os_proto_block(dhd_pub_t *pub) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ DHD_PERIM_UNLOCK(pub); ++ ++ down(&dhd->proto_sem); ++ ++ DHD_PERIM_LOCK(pub); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++int ++dhd_os_proto_unblock(dhd_pub_t *pub) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ up(&dhd->proto_sem); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++void ++dhd_os_dhdiovar_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ mutex_lock(&dhd->dhd_iovar_mutex); ++ } ++} ++ ++void ++dhd_os_dhdiovar_unlock(dhd_pub_t *pub) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ mutex_unlock(&dhd->dhd_iovar_mutex); ++ } ++} ++ ++unsigned int ++dhd_os_get_ioctl_resp_timeout(void) ++{ ++ return ((unsigned int)dhd_ioctl_timeout_msec); ++} ++ ++void ++dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) ++{ ++ dhd_ioctl_timeout_msec = (int)timeout_msec; ++} ++ ++int ++dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ int timeout; ++ ++ /* Convert timeout in millsecond to jiffies */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); ++#else ++ timeout = dhd_ioctl_timeout_msec * HZ / 1000; ++#endif ++ ++ DHD_PERIM_UNLOCK(pub); ++ ++ timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); ++ ++ DHD_PERIM_LOCK(pub); ++ ++ return timeout; ++} ++ ++int ++dhd_os_ioctl_resp_wake(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ wake_up(&dhd->ioctl_resp_wait); ++ return 0; ++} ++ ++int ++dhd_os_d3ack_wait(dhd_pub_t *pub, uint *condition) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ int timeout; ++ ++ /* Convert timeout in millsecond to jiffies */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); ++#else ++ timeout = dhd_ioctl_timeout_msec * HZ / 1000; ++#endif ++ ++ DHD_PERIM_UNLOCK(pub); ++ ++ timeout = wait_event_timeout(dhd->d3ack_wait, (*condition), timeout); ++ ++ DHD_PERIM_LOCK(pub); ++ ++ return timeout; ++} ++ ++#ifdef PCIE_INB_DW ++int ++dhd_os_ds_exit_wait(dhd_pub_t *pub, uint *condition) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ int timeout; ++ ++ /* Convert timeout in millsecond to jiffies */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ timeout = msecs_to_jiffies(ds_exit_timeout_msec); ++#else ++ timeout = ds_exit_timeout_msec * HZ / 1000; ++#endif ++ ++ DHD_PERIM_UNLOCK(pub); ++ ++ timeout = wait_event_timeout(dhd->ds_exit_wait, (*condition), timeout); ++ ++ DHD_PERIM_LOCK(pub); ++ ++ return timeout; ++} ++ ++int ++dhd_os_ds_exit_wake(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ wake_up(&dhd->ds_exit_wait); ++ return 0; ++} ++ ++#endif /* PCIE_INB_DW */ ++ ++int ++dhd_os_d3ack_wake(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ wake_up(&dhd->d3ack_wait); ++ return 0; ++} ++ ++int ++dhd_os_busbusy_wait_negation(dhd_pub_t *pub, uint *condition) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ int timeout; ++ ++ /* Wait for bus usage contexts to gracefully exit within some timeout value ++ * Set time out to little higher than dhd_ioctl_timeout_msec, ++ * so that IOCTL timeout should not get affected. ++ */ ++ /* Convert timeout in millsecond to jiffies */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ timeout = msecs_to_jiffies(DHD_BUS_BUSY_TIMEOUT); ++#else ++ timeout = DHD_BUS_BUSY_TIMEOUT * HZ / 1000; ++#endif ++ ++ timeout = wait_event_timeout(dhd->dhd_bus_busy_state_wait, !(*condition), timeout); ++ ++ return timeout; ++} ++ ++/* ++ * Wait until the condition *var == condition is met. ++ * Returns 0 if the @condition evaluated to false after the timeout elapsed ++ * Returns 1 if the @condition evaluated to true ++ */ ++int ++dhd_os_busbusy_wait_condition(dhd_pub_t *pub, uint *var, uint condition) ++{ ++ dhd_info_t * dhd = (dhd_info_t *)(pub->info); ++ int timeout; ++ ++ /* Convert timeout in millsecond to jiffies */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ timeout = msecs_to_jiffies(DHD_BUS_BUSY_TIMEOUT); ++#else ++ timeout = DHD_BUS_BUSY_TIMEOUT * HZ / 1000; ++#endif ++ ++ timeout = wait_event_timeout(dhd->dhd_bus_busy_state_wait, (*var == condition), timeout); ++ ++ return timeout; ++} ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) ++/* Fix compilation error for FC11 */ ++INLINE ++#endif ++int ++dhd_os_busbusy_wake(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ /* Call wmb() to make sure before waking up the other event value gets updated */ ++ OSL_SMP_WMB(); ++ wake_up(&dhd->dhd_bus_busy_state_wait); ++ return 0; ++} ++ ++void ++dhd_os_wd_timer_extend(void *bus, bool extend) ++{ ++#ifndef BCMDBUS ++ dhd_pub_t *pub = bus; ++ dhd_info_t *dhd = (dhd_info_t *)pub->info; ++ ++ if (extend) ++ dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL); ++ else ++ dhd_os_wd_timer(bus, dhd->default_wd_interval); ++#endif /* !BCMDBUS */ ++} ++ ++ ++void ++dhd_os_wd_timer(void *bus, uint wdtick) ++{ ++#ifndef BCMDBUS ++ dhd_pub_t *pub = bus; ++ dhd_info_t *dhd = (dhd_info_t *)pub->info; ++ unsigned long flags; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ DHD_GENERAL_LOCK(pub, flags); ++ ++ /* don't start the wd until fw is loaded */ ++ if (pub->busstate == DHD_BUS_DOWN) { ++ DHD_GENERAL_UNLOCK(pub, flags); ++ return; ++ } ++ ++ /* Totally stop the timer */ ++ if (!wdtick && dhd->wd_timer_valid == TRUE) { ++ dhd->wd_timer_valid = FALSE; ++ DHD_GENERAL_UNLOCK(pub, flags); ++ _del_timer_sync(&dhd->timer); ++ return; ++ } ++ ++ if (wdtick) { ++ dhd_watchdog_ms = (uint)wdtick; ++ /* Re arm the timer, at last watchdog period */ ++ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); ++ dhd->wd_timer_valid = TRUE; ++ } ++ DHD_GENERAL_UNLOCK(pub, flags); ++#endif /* !BCMDBUS */ ++} ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++void ++dhd_os_runtimepm_timer(void *bus, uint tick) ++{ ++ dhd_pub_t *pub = bus; ++ dhd_info_t *dhd = (dhd_info_t *)pub->info; ++ unsigned long flags; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ DHD_GENERAL_LOCK(pub, flags); ++ ++ /* don't start the RPM until fw is loaded */ ++ if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(pub)) { ++ DHD_GENERAL_UNLOCK(pub, flags); ++ return; ++ } ++ ++ /* If tick is non-zero, the request is to start the timer */ ++ if (tick) { ++ /* Start the timer only if its not already running */ ++ if (dhd->rpm_timer_valid == FALSE) { ++ mod_timer(&dhd->rpm_timer, jiffies + msecs_to_jiffies(dhd_runtimepm_ms)); ++ dhd->rpm_timer_valid = TRUE; ++ } ++ } else { ++ /* tick is zero, we have to stop the timer */ ++ /* Stop the timer only if its running, otherwise we don't have to do anything */ ++ if (dhd->rpm_timer_valid == TRUE) { ++ dhd->rpm_timer_valid = FALSE; ++ DHD_GENERAL_UNLOCK(pub, flags); ++ _del_timer_sync(&dhd->rpm_timer); ++ /* we have already released the lock, so just go to exit */ ++ goto exit; ++ } ++ } ++ ++ DHD_GENERAL_UNLOCK(pub, flags); ++exit: ++ return; ++ ++} ++ ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++void * ++dhd_os_open_image(char *filename) ++{ ++ struct file *fp; ++ int size; ++ ++ fp = filp_open(filename, O_RDONLY, 0); ++ /* ++ * 2.6.11 (FC4) supports filp_open() but later revs don't? ++ * Alternative: ++ * fp = open_namei(AT_FDCWD, filename, O_RD, 0); ++ * ??? ++ */ ++ if (IS_ERR(fp)) { ++ fp = NULL; ++ goto err; ++ } ++ ++ if (!S_ISREG(file_inode(fp)->i_mode)) { ++ DHD_ERROR(("%s: %s is not regular file\n", __FUNCTION__, filename)); ++ fp = NULL; ++ goto err; ++ } ++ ++ size = i_size_read(file_inode(fp)); ++ if (size <= 0) { ++ DHD_ERROR(("%s: %s file size invalid %d\n", __FUNCTION__, filename, size)); ++ fp = NULL; ++ goto err; ++ } ++ ++ DHD_ERROR(("%s: %s (%d bytes) open success\n", __FUNCTION__, filename, size)); ++ ++err: ++ return fp; ++} ++ ++int ++dhd_os_get_image_block(char *buf, int len, void *image) ++{ ++ struct file *fp = (struct file *)image; ++ int rdlen; ++ int size; ++ ++ if (!image) { ++ return 0; ++ } ++ ++ size = i_size_read(file_inode(fp)); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ rdlen = kernel_read(fp, buf, MIN(len, size), &fp->f_pos); ++#else ++ rdlen = kernel_read(fp, fp->f_pos, buf, MIN(len, size)); ++#endif ++ ++ if (len >= size && size != rdlen) { ++ return -EIO; ++ } ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ if (rdlen > 0) { ++ fp->f_pos += rdlen; ++ } ++#endif ++ ++ return rdlen; ++} ++ ++int ++dhd_os_get_image_size(void *image) ++{ ++ struct file *fp = (struct file *)image; ++ int size; ++ if (!image) { ++ return 0; ++ } ++ ++ size = i_size_read(file_inode(fp)); ++ ++ return size; ++} ++ ++#if defined(BT_OVER_SDIO) ++int ++dhd_os_gets_image(dhd_pub_t *pub, char *str, int len, void *image) ++{ ++ struct file *fp = (struct file *)image; ++ int rd_len; ++ uint str_len = 0; ++ char *str_end = NULL; ++ ++ if (!image) ++ return 0; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ rd_len = kernel_read(fp, str, len, &fp->f_pos); ++#else ++ rd_len = kernel_read(fp, fp->f_pos, str, len); ++#endif ++ str_end = strnchr(str, len, '\n'); ++ if (str_end == NULL) { ++ goto err; ++ } ++ str_len = (uint)(str_end - str); ++ ++ /* Advance file pointer past the string length */ ++ fp->f_pos += str_len + 1; ++ bzero(str_end, rd_len - str_len); ++ ++err: ++ return str_len; ++} ++#endif /* defined (BT_OVER_SDIO) */ ++ ++ ++void ++dhd_os_close_image(void *image) ++{ ++ if (image) ++ filp_close((struct file *)image, NULL); ++} ++ ++void ++dhd_os_sdlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ ++#ifdef BCMDBUS ++ spin_lock_bh(&dhd->sdlock); ++#else ++ if (dhd_dpc_prio >= 0) ++ down(&dhd->sdsem); ++ else ++ spin_lock_bh(&dhd->sdlock); ++#endif /* !BCMDBUS */ ++} ++ ++void ++dhd_os_sdunlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ ++#ifdef BCMDBUS ++ spin_unlock_bh(&dhd->sdlock); ++#else ++ if (dhd_dpc_prio >= 0) ++ up(&dhd->sdsem); ++ else ++ spin_unlock_bh(&dhd->sdlock); ++#endif /* !BCMDBUS */ ++} ++ ++void ++dhd_os_sdlock_txq(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++#ifdef BCMDBUS ++ spin_lock_irqsave(&dhd->txqlock, dhd->txqlock_flags); ++#else ++ spin_lock_bh(&dhd->txqlock); ++#endif /* BCMDBUS */ ++} ++ ++void ++dhd_os_sdunlock_txq(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++#ifdef BCMDBUS ++ spin_unlock_irqrestore(&dhd->txqlock, dhd->txqlock_flags); ++#else ++ spin_unlock_bh(&dhd->txqlock); ++#endif /* BCMDBUS */ ++} ++ ++void ++dhd_os_sdlock_rxq(dhd_pub_t *pub) ++{ ++#if 0 ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ spin_lock_bh(&dhd->rxqlock); ++#endif ++} ++ ++void ++dhd_os_sdunlock_rxq(dhd_pub_t *pub) ++{ ++#if 0 ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ spin_unlock_bh(&dhd->rxqlock); ++#endif ++} ++ ++static void ++dhd_os_rxflock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ spin_lock_bh(&dhd->rxf_lock); ++ ++} ++ ++static void ++dhd_os_rxfunlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ spin_unlock_bh(&dhd->rxf_lock); ++} ++ ++#ifdef DHDTCPACK_SUPPRESS ++unsigned long ++dhd_os_tcpacklock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd; ++ unsigned long flags = 0; ++ ++ dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++#ifdef BCMSDIO ++ spin_lock_bh(&dhd->tcpack_lock); ++#else ++ spin_lock_irqsave(&dhd->tcpack_lock, flags); ++#endif /* BCMSDIO */ ++ } ++ ++ return flags; ++} ++ ++void ++dhd_os_tcpackunlock(dhd_pub_t *pub, unsigned long flags) ++{ ++ dhd_info_t *dhd; ++ ++#ifdef BCMSDIO ++ BCM_REFERENCE(flags); ++#endif /* BCMSDIO */ ++ ++ dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++#ifdef BCMSDIO ++ spin_unlock_bh(&dhd->tcpack_lock); ++#else ++ spin_unlock_irqrestore(&dhd->tcpack_lock, flags); ++#endif /* BCMSDIO */ ++ } ++} ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail) ++{ ++ uint8* buf; ++ gfp_t flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; ++ ++ buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size); ++ if (buf == NULL && kmalloc_if_fail) ++ buf = kmalloc(size, flags); ++ ++ return buf; ++} ++ ++void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size) ++{ ++} ++ ++#if defined(WL_WIRELESS_EXT) ++struct iw_statistics * ++dhd_get_wireless_stats(struct net_device *dev) ++{ ++ int res = 0; ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ if (!dhd->pub.up) { ++ return NULL; ++ } ++ ++ res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); ++ ++ if (res == 0) ++ return &dhd->iw.wstats; ++ else ++ return NULL; ++} ++#endif /* defined(WL_WIRELESS_EXT) */ ++ ++static int ++dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen, ++ wl_event_msg_t *event, void **data) ++{ ++ int bcmerror = 0; ++#ifdef WL_CFG80211 ++ unsigned long flags = 0; ++#endif /* WL_CFG80211 */ ++ ASSERT(dhd != NULL); ++ ++#ifdef SHOW_LOGTRACE ++ bcmerror = wl_process_host_event(&dhd->pub, &ifidx, pktdata, pktlen, event, data, ++ &dhd->event_data); ++#else ++ bcmerror = wl_process_host_event(&dhd->pub, &ifidx, pktdata, pktlen, event, data, ++ NULL); ++#endif /* SHOW_LOGTRACE */ ++ ++ if (bcmerror != BCME_OK) ++ return (bcmerror); ++ ++#if defined(WL_EXT_IAPSTA) || defined(USE_IW) ++ wl_ext_event_send(dhd->pub.event_params, event, *data); ++#endif ++ ++#ifdef WL_CFG80211 ++ ASSERT(dhd->iflist[ifidx] != NULL); ++ ASSERT(dhd->iflist[ifidx]->net != NULL); ++ if (dhd->iflist[ifidx]->net) { ++ spin_lock_irqsave(&dhd->pub.up_lock, flags); ++ if (dhd->pub.up) { ++ wl_cfg80211_event(dhd->iflist[ifidx]->net, event, *data); ++ } ++ spin_unlock_irqrestore(&dhd->pub.up_lock, flags); ++ } ++#endif /* defined(WL_CFG80211) */ ++ ++ return (bcmerror); ++} ++ ++/* send up locally generated event */ ++void ++dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) ++{ ++ /* Just return from here */ ++ return; ++} ++ ++#ifdef LOG_INTO_TCPDUMP ++void ++dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len) ++{ ++ struct sk_buff *p, *skb; ++ uint32 pktlen; ++ int len; ++ dhd_if_t *ifp; ++ dhd_info_t *dhd; ++ uchar *skb_data; ++ int ifidx = 0; ++ struct ether_header eth; ++ ++ pktlen = sizeof(eth) + data_len; ++ dhd = dhdp->info; ++ ++ if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { ++ ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); ++ ++ bcopy(&dhdp->mac, ð.ether_dhost, ETHER_ADDR_LEN); ++ bcopy(&dhdp->mac, ð.ether_shost, ETHER_ADDR_LEN); ++ ETHER_TOGGLE_LOCALADDR(ð.ether_shost); ++ eth.ether_type = hton16(ETHER_TYPE_BRCM); ++ ++ bcopy((void *)ð, PKTDATA(dhdp->osh, p), sizeof(eth)); ++ bcopy(data, PKTDATA(dhdp->osh, p) + sizeof(eth), data_len); ++ skb = PKTTONATIVE(dhdp->osh, p); ++ skb_data = skb->data; ++ len = skb->len; ++ ++ ifidx = dhd_ifname2idx(dhd, "wlan0"); ++ ifp = dhd->iflist[ifidx]; ++ if (ifp == NULL) ++ ifp = dhd->iflist[0]; ++ ++ ASSERT(ifp); ++ skb->dev = ifp->net; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ skb->data = skb_data; ++ skb->len = len; ++ ++ /* Strip header, count, deliver upward */ ++ skb_pull(skb, ETH_HLEN); ++ ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, ++ __FUNCTION__, __LINE__); ++ /* Send the packet */ ++ if (in_interrupt()) { ++ netif_rx(skb); ++ } else { ++ netif_rx_ni(skb); ++ } ++ } else { ++ /* Could not allocate a sk_buf */ ++ DHD_ERROR(("%s: unable to alloc sk_buf\n", __FUNCTION__)); ++ } ++} ++#endif /* LOG_INTO_TCPDUMP */ ++ ++void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) ++{ ++#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ struct dhd_info *dhdinfo = dhd->info; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); ++#else ++ int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++ ++ dhd_os_sdunlock(dhd); ++ wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); ++ dhd_os_sdlock(dhd); ++#endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ ++ return; ++} ++ ++void dhd_wait_event_wakeup(dhd_pub_t *dhd) ++{ ++#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ struct dhd_info *dhdinfo = dhd->info; ++ if (waitqueue_active(&dhdinfo->ctrl_wait)) ++ wake_up(&dhdinfo->ctrl_wait); ++#endif ++ return; ++} ++ ++#if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS) ++int ++dhd_net_bus_devreset(struct net_device *dev, uint8 flag) ++{ ++ int ret; ++ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ if (flag == TRUE) { ++ /* Issue wl down command before resetting the chip */ ++ if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { ++ DHD_TRACE(("%s: wl down failed\n", __FUNCTION__)); ++ } ++#ifdef PROP_TXSTATUS ++ if (dhd->pub.wlfc_enabled) { ++ dhd_wlfc_deinit(&dhd->pub); ++ } ++#endif /* PROP_TXSTATUS */ ++#ifdef PNO_SUPPORT ++ if (dhd->pub.pno_state) { ++ dhd_pno_deinit(&dhd->pub); ++ } ++#endif ++#ifdef RTT_SUPPORT ++ if (dhd->pub.rtt_state) { ++ dhd_rtt_deinit(&dhd->pub); ++ } ++#endif /* RTT_SUPPORT */ ++ ++#if defined(DBG_PKT_MON) && !defined(DBG_PKT_MON_INIT_DEFAULT) ++ dhd_os_dbg_detach_pkt_monitor(&dhd->pub); ++#endif /* DBG_PKT_MON */ ++ } ++ ++#ifdef BCMSDIO ++ if (!flag) { ++ dhd_update_fw_nv_path(dhd); ++ /* update firmware and nvram path to sdio bus */ ++ dhd_bus_update_fw_nv_path(dhd->pub.bus, ++ dhd->fw_path, dhd->nv_path, dhd->clm_path, dhd->conf_path); ++ } ++#endif /* BCMSDIO */ ++ ++ ret = dhd_bus_devreset(&dhd->pub, flag); ++ if (ret) { ++ DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++#ifdef BCMSDIO ++int ++dhd_net_bus_suspend(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ return dhd_bus_suspend(&dhd->pub); ++} ++ ++int ++dhd_net_bus_resume(struct net_device *dev, uint8 stage) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ return dhd_bus_resume(&dhd->pub, stage); ++} ++ ++#endif /* BCMSDIO */ ++#endif /* BCMSDIO || BCMPCIE || BCMDBUS */ ++ ++int net_os_set_suspend_disable(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int ret = 0; ++ ++ if (dhd) { ++ ret = dhd->pub.suspend_disable_flag; ++ dhd->pub.suspend_disable_flag = val; ++ } ++ return ret; ++} ++ ++int net_os_set_suspend(struct net_device *dev, int val, int force) ++{ ++ int ret = 0; ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ if (dhd && dhd->pub.conf->suspend_mode == EARLY_SUSPEND) { ++ if (!val) ++ dhd_conf_set_suspend_resume(&dhd->pub, val); ++#ifdef CONFIG_MACH_UNIVERSAL7420 ++#endif /* CONFIG_MACH_UNIVERSAL7420 */ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++ ret = dhd_set_suspend(val, &dhd->pub); ++#else ++ ret = dhd_suspend_resume_helper(dhd, val, force); ++#endif ++#ifdef WL_CFG80211 ++ wl_cfg80211_update_power_mode(dev); ++#endif ++ if (val) ++ dhd_conf_set_suspend_resume(&dhd->pub, val); ++ } ++ return ret; ++} ++ ++int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ if (dhd) ++ dhd->pub.suspend_bcn_li_dtim = val; ++ ++ return 0; ++} ++ ++int net_os_set_max_dtim_enable(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ if (dhd) { ++ DHD_ERROR(("%s: use MAX bcn_li_dtim in suspend %s\n", ++ __FUNCTION__, (val ? "Enable" : "Disable"))); ++ if (val) { ++ dhd->pub.max_dtim_enable = TRUE; ++ } else { ++ dhd->pub.max_dtim_enable = FALSE; ++ } ++ } else { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++#ifdef PKT_FILTER_SUPPORT ++int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) ++{ ++ int ret = 0; ++ ++#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ if (!dhd_master_mode) ++ add_remove = !add_remove; ++ DHD_ERROR(("%s: add_remove = %d, num = %d\n", __FUNCTION__, add_remove, num)); ++ if (!dhd || (num == DHD_UNICAST_FILTER_NUM)) { ++ return 0; ++ } ++ ++ ++ if (num >= dhd->pub.pktfilter_count) { ++ return -EINVAL; ++ } ++ ++ ret = dhd_packet_filter_add_remove(&dhd->pub, add_remove, num); ++#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ ++ ++ return ret; ++} ++ ++int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) ++ ++{ ++ int ret = 0; ++ ++ /* Packet filtering is set only if we still in early-suspend and ++ * we need either to turn it ON or turn it OFF ++ * We can always turn it OFF in case of early-suspend, but we turn it ++ * back ON only if suspend_disable_flag was not set ++ */ ++ if (dhdp && dhdp->up) { ++ if (dhdp->in_suspend) { ++ if (!val || (val && !dhdp->suspend_disable_flag)) ++ dhd_enable_packet_filter(val, dhdp); ++ } ++ } ++ return ret; ++} ++ ++/* function to enable/disable packet for Network device */ ++int net_os_enable_packet_filter(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ DHD_ERROR(("%s: val = %d\n", __FUNCTION__, val)); ++ return dhd_os_enable_packet_filter(&dhd->pub, val); ++} ++#endif /* PKT_FILTER_SUPPORT */ ++ ++int ++dhd_dev_init_ioctl(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int ret; ++ ++ if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) ++ goto done; ++ ++done: ++ return ret; ++} ++ ++int ++dhd_dev_get_feature_set(struct net_device *dev) ++{ ++ dhd_info_t *ptr = *(dhd_info_t **)netdev_priv(dev); ++ dhd_pub_t *dhd = (&ptr->pub); ++ int feature_set = 0; ++ ++ if (FW_SUPPORTED(dhd, sta)) ++ feature_set |= WIFI_FEATURE_INFRA; ++ if (FW_SUPPORTED(dhd, dualband)) ++ feature_set |= WIFI_FEATURE_INFRA_5G; ++ if (FW_SUPPORTED(dhd, p2p)) ++ feature_set |= WIFI_FEATURE_P2P; ++ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) ++ feature_set |= WIFI_FEATURE_SOFT_AP; ++ if (FW_SUPPORTED(dhd, tdls)) ++ feature_set |= WIFI_FEATURE_TDLS; ++ if (FW_SUPPORTED(dhd, vsdb)) ++ feature_set |= WIFI_FEATURE_TDLS_OFFCHANNEL; ++ if (FW_SUPPORTED(dhd, nan)) { ++ feature_set |= WIFI_FEATURE_NAN; ++ /* NAN is essentail for d2d rtt */ ++ if (FW_SUPPORTED(dhd, rttd2d)) ++ feature_set |= WIFI_FEATURE_D2D_RTT; ++ } ++#ifdef RTT_SUPPORT ++ if (dhd->rtt_supported) { ++ feature_set |= WIFI_FEATURE_D2D_RTT; ++ feature_set |= WIFI_FEATURE_D2AP_RTT; ++ } ++#endif /* RTT_SUPPORT */ ++#ifdef LINKSTAT_SUPPORT ++ feature_set |= WIFI_FEATURE_LINKSTAT; ++#endif /* LINKSTAT_SUPPORT */ ++ ++#ifdef PNO_SUPPORT ++ if (dhd_is_pno_supported(dhd)) { ++ feature_set |= WIFI_FEATURE_PNO; ++#ifdef GSCAN_SUPPORT ++ /* terence 20171115: remove to get GTS PASS ++ * com.google.android.gts.wifi.WifiHostTest#testWifiScannerBatchTimestamp ++ */ ++// feature_set |= WIFI_FEATURE_GSCAN; ++// feature_set |= WIFI_FEATURE_HAL_EPNO; ++#endif /* GSCAN_SUPPORT */ ++ } ++#endif /* PNO_SUPPORT */ ++#ifdef RSSI_MONITOR_SUPPORT ++ if (FW_SUPPORTED(dhd, rssi_mon)) { ++ feature_set |= WIFI_FEATURE_RSSI_MONITOR; ++ } ++#endif /* RSSI_MONITOR_SUPPORT */ ++#ifdef WL11U ++ feature_set |= WIFI_FEATURE_HOTSPOT; ++#endif /* WL11U */ ++#ifdef NDO_CONFIG_SUPPORT ++ feature_set |= WIFI_FEATURE_CONFIG_NDO; ++#endif /* NDO_CONFIG_SUPPORT */ ++#ifdef KEEP_ALIVE ++ feature_set |= WIFI_FEATURE_MKEEP_ALIVE; ++#endif /* KEEP_ALIVE */ ++ ++ return feature_set; ++} ++ ++int ++dhd_dev_get_feature_set_matrix(struct net_device *dev, int num) ++{ ++ int feature_set_full; ++ int ret = 0; ++ ++ feature_set_full = dhd_dev_get_feature_set(dev); ++ ++ /* Common feature set for all interface */ ++ ret = (feature_set_full & WIFI_FEATURE_INFRA) | ++ (feature_set_full & WIFI_FEATURE_INFRA_5G) | ++ (feature_set_full & WIFI_FEATURE_D2D_RTT) | ++ (feature_set_full & WIFI_FEATURE_D2AP_RTT) | ++ (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | ++ (feature_set_full & WIFI_FEATURE_EPR); ++ ++ /* Specific feature group for each interface */ ++ switch (num) { ++ case 0: ++ ret |= (feature_set_full & WIFI_FEATURE_P2P) | ++ /* Not supported yet */ ++ /* (feature_set_full & WIFI_FEATURE_NAN) | */ ++ (feature_set_full & WIFI_FEATURE_TDLS) | ++ (feature_set_full & WIFI_FEATURE_PNO) | ++ (feature_set_full & WIFI_FEATURE_HAL_EPNO) | ++ (feature_set_full & WIFI_FEATURE_BATCH_SCAN) | ++ (feature_set_full & WIFI_FEATURE_GSCAN) | ++ (feature_set_full & WIFI_FEATURE_HOTSPOT) | ++ (feature_set_full & WIFI_FEATURE_ADDITIONAL_STA); ++ break; ++ ++ case 1: ++ ret |= (feature_set_full & WIFI_FEATURE_P2P); ++ /* Not yet verified NAN with P2P */ ++ /* (feature_set_full & WIFI_FEATURE_NAN) | */ ++ break; ++ ++ case 2: ++ ret |= (feature_set_full & WIFI_FEATURE_NAN) | ++ (feature_set_full & WIFI_FEATURE_TDLS) | ++ (feature_set_full & WIFI_FEATURE_TDLS_OFFCHANNEL); ++ break; ++ ++ default: ++ ret = WIFI_FEATURE_INVALID; ++ DHD_ERROR(("%s: Out of index(%d) for get feature set\n", __FUNCTION__, num)); ++ break; ++ } ++ ++ return ret; ++} ++ ++#ifdef CUSTOM_FORCE_NODFS_FLAG ++int ++dhd_dev_set_nodfs(struct net_device *dev, u32 nodfs) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ if (nodfs) ++ dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; ++ else ++ dhd->pub.dhd_cflags &= ~WLAN_PLAT_NODFS_FLAG; ++ dhd->pub.force_country_change = TRUE; ++ return 0; ++} ++#endif /* CUSTOM_FORCE_NODFS_FLAG */ ++ ++#ifdef NDO_CONFIG_SUPPORT ++int ++dhd_dev_ndo_cfg(struct net_device *dev, u8 enable) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ret = 0; ++ ++ if (enable) { ++ /* enable ND offload feature (will be enabled in FW on suspend) */ ++ dhdp->ndo_enable = TRUE; ++ ++ /* Update changes of anycast address & DAD failed address */ ++ ret = dhd_dev_ndo_update_inet6addr(dev); ++ if ((ret < 0) && (ret != BCME_NORESOURCE)) { ++ DHD_ERROR(("%s: failed to update host ip addr: %d\n", __FUNCTION__, ret)); ++ return ret; ++ } ++ } else { ++ /* disable ND offload feature */ ++ dhdp->ndo_enable = FALSE; ++ ++ /* disable ND offload in FW */ ++ ret = dhd_ndo_enable(dhdp, 0); ++ if (ret < 0) { ++ DHD_ERROR(("%s: failed to disable NDO: %d\n", __FUNCTION__, ret)); ++ } ++ } ++ return ret; ++} ++ ++/* #pragma used as a WAR to fix build failure, ++* ignore dropping of 'const' qualifier in 'list_entry' macro ++* this pragma disables the warning only for the following function ++*/ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++ ++static int ++dhd_dev_ndo_get_valid_inet6addr_count(struct inet6_dev *inet6) ++{ ++ struct inet6_ifaddr *ifa; ++ struct ifacaddr6 *acaddr = NULL; ++ int addr_count = 0; ++ ++ /* lock */ ++ read_lock_bh(&inet6->lock); ++ ++ /* Count valid unicast address */ ++ list_for_each_entry(ifa, &inet6->addr_list, if_list) { ++ if ((ifa->flags & IFA_F_DADFAILED) == 0) { ++ addr_count++; ++ } ++ } ++ ++ /* Count anycast address */ ++ acaddr = inet6->ac_list; ++ while (acaddr) { ++ addr_count++; ++ acaddr = acaddr->aca_next; ++ } ++ ++ /* unlock */ ++ read_unlock_bh(&inet6->lock); ++ ++ return addr_count; ++} ++ ++int ++dhd_dev_ndo_update_inet6addr(struct net_device *dev) ++{ ++ dhd_info_t *dhd; ++ dhd_pub_t *dhdp; ++ struct inet6_dev *inet6; ++ struct inet6_ifaddr *ifa; ++ struct ifacaddr6 *acaddr = NULL; ++ struct in6_addr *ipv6_addr = NULL; ++ int cnt, i; ++ int ret = BCME_OK; ++ ++ /* ++ * this function evaulates host ip address in struct inet6_dev ++ * unicast addr in inet6_dev->addr_list ++ * anycast addr in inet6_dev->ac_list ++ * while evaluating inet6_dev, read_lock_bh() is required to prevent ++ * access on null(freed) pointer. ++ */ ++ ++ if (dev) { ++ inet6 = dev->ip6_ptr; ++ if (!inet6) { ++ DHD_ERROR(("%s: Invalid inet6_dev\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ dhd = DHD_DEV_INFO(dev); ++ if (!dhd) { ++ DHD_ERROR(("%s: Invalid dhd_info\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ dhdp = &dhd->pub; ++ ++ if (dhd_net2idx(dhd, dev) != 0) { ++ DHD_ERROR(("%s: Not primary interface\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ } else { ++ DHD_ERROR(("%s: Invalid net_device\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ /* Check host IP overflow */ ++ cnt = dhd_dev_ndo_get_valid_inet6addr_count(inet6); ++ if (cnt > dhdp->ndo_max_host_ip) { ++ if (!dhdp->ndo_host_ip_overflow) { ++ dhdp->ndo_host_ip_overflow = TRUE; ++ /* Disable ND offload in FW */ ++ DHD_INFO(("%s: Host IP overflow, disable NDO\n", __FUNCTION__)); ++ ret = dhd_ndo_enable(dhdp, 0); ++ } ++ ++ return ret; ++ } ++ ++ /* ++ * Allocate ipv6 addr buffer to store addresses to be added/removed. ++ * driver need to lock inet6_dev while accessing structure. but, driver ++ * cannot use ioctl while inet6_dev locked since it requires scheduling ++ * hence, copy addresses to the buffer and do ioctl after unlock. ++ */ ++ ipv6_addr = (struct in6_addr *)MALLOC(dhdp->osh, ++ sizeof(struct in6_addr) * dhdp->ndo_max_host_ip); ++ if (!ipv6_addr) { ++ DHD_ERROR(("%s: failed to alloc ipv6 addr buffer\n", __FUNCTION__)); ++ return BCME_NOMEM; ++ } ++ ++ /* Find DAD failed unicast address to be removed */ ++ cnt = 0; ++ read_lock_bh(&inet6->lock); ++ list_for_each_entry(ifa, &inet6->addr_list, if_list) { ++ /* DAD failed unicast address */ ++ if ((ifa->flags & IFA_F_DADFAILED) && ++ (cnt < dhdp->ndo_max_host_ip)) { ++ memcpy(&ipv6_addr[cnt], &ifa->addr, sizeof(struct in6_addr)); ++ cnt++; ++ } ++ } ++ read_unlock_bh(&inet6->lock); ++ ++ /* Remove DAD failed unicast address */ ++ for (i = 0; i < cnt; i++) { ++ DHD_INFO(("%s: Remove DAD failed addr\n", __FUNCTION__)); ++ ret = dhd_ndo_remove_ip_by_addr(dhdp, (char *)&ipv6_addr[i], 0); ++ if (ret < 0) { ++ goto done; ++ } ++ } ++ ++ /* Remove all anycast address */ ++ ret = dhd_ndo_remove_ip_by_type(dhdp, WL_ND_IPV6_ADDR_TYPE_ANYCAST, 0); ++ if (ret < 0) { ++ goto done; ++ } ++ ++ /* ++ * if ND offload was disabled due to host ip overflow, ++ * attempt to add valid unicast address. ++ */ ++ if (dhdp->ndo_host_ip_overflow) { ++ /* Find valid unicast address */ ++ cnt = 0; ++ read_lock_bh(&inet6->lock); ++ list_for_each_entry(ifa, &inet6->addr_list, if_list) { ++ /* valid unicast address */ ++ if (!(ifa->flags & IFA_F_DADFAILED) && ++ (cnt < dhdp->ndo_max_host_ip)) { ++ memcpy(&ipv6_addr[cnt], &ifa->addr, ++ sizeof(struct in6_addr)); ++ cnt++; ++ } ++ } ++ read_unlock_bh(&inet6->lock); ++ ++ /* Add valid unicast address */ ++ for (i = 0; i < cnt; i++) { ++ ret = dhd_ndo_add_ip_with_type(dhdp, ++ (char *)&ipv6_addr[i], WL_ND_IPV6_ADDR_TYPE_UNICAST, 0); ++ if (ret < 0) { ++ goto done; ++ } ++ } ++ } ++ ++ /* Find anycast address */ ++ cnt = 0; ++ read_lock_bh(&inet6->lock); ++ acaddr = inet6->ac_list; ++ while (acaddr) { ++ if (cnt < dhdp->ndo_max_host_ip) { ++ memcpy(&ipv6_addr[cnt], &acaddr->aca_addr, sizeof(struct in6_addr)); ++ cnt++; ++ } ++ acaddr = acaddr->aca_next; ++ } ++ read_unlock_bh(&inet6->lock); ++ ++ /* Add anycast address */ ++ for (i = 0; i < cnt; i++) { ++ ret = dhd_ndo_add_ip_with_type(dhdp, ++ (char *)&ipv6_addr[i], WL_ND_IPV6_ADDR_TYPE_ANYCAST, 0); ++ if (ret < 0) { ++ goto done; ++ } ++ } ++ ++ /* Now All host IP addr were added successfully */ ++ if (dhdp->ndo_host_ip_overflow) { ++ dhdp->ndo_host_ip_overflow = FALSE; ++ if (dhdp->in_suspend) { ++ /* drvier is in (early) suspend state, need to enable ND offload in FW */ ++ DHD_INFO(("%s: enable NDO\n", __FUNCTION__)); ++ ret = dhd_ndo_enable(dhdp, 1); ++ } ++ } ++ ++done: ++ if (ipv6_addr) { ++ MFREE(dhdp->osh, ipv6_addr, sizeof(struct in6_addr) * dhdp->ndo_max_host_ip); ++ } ++ ++ return ret; ++} ++#pragma GCC diagnostic pop ++ ++#endif /* NDO_CONFIG_SUPPORT */ ++ ++#ifdef PNO_SUPPORT ++/* Linux wrapper to call common dhd_pno_stop_for_ssid */ ++int ++dhd_dev_pno_stop_for_ssid(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ return (dhd_pno_stop_for_ssid(&dhd->pub)); ++} ++ ++/* Linux wrapper to call common dhd_pno_set_for_ssid */ ++int ++dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, ++ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr, ++ pno_repeat, pno_freq_expo_max, channel_list, nchan)); ++} ++ ++/* Linux wrapper to call common dhd_pno_enable */ ++int ++dhd_dev_pno_enable(struct net_device *dev, int enable) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ return (dhd_pno_enable(&dhd->pub, enable)); ++} ++ ++/* Linux wrapper to call common dhd_pno_set_for_hotlist */ ++int ++dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, ++ struct dhd_pno_hotlist_params *hotlist_params) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params)); ++} ++/* Linux wrapper to call common dhd_dev_pno_stop_for_batch */ ++int ++dhd_dev_pno_stop_for_batch(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ return (dhd_pno_stop_for_batch(&dhd->pub)); ++} ++ ++/* Linux wrapper to call common dhd_dev_pno_set_for_batch */ ++int ++dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ return (dhd_pno_set_for_batch(&dhd->pub, batch_params)); ++} ++ ++/* Linux wrapper to call common dhd_dev_pno_get_for_batch */ ++int ++dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL)); ++} ++#endif /* PNO_SUPPORT */ ++ ++#if defined(PNO_SUPPORT) ++#ifdef GSCAN_SUPPORT ++bool ++dhd_dev_is_legacy_pno_enabled(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_is_legacy_pno_enabled(&dhd->pub)); ++} ++ ++int ++dhd_dev_set_epno(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ if (!dhd) { ++ return BCME_ERROR; ++ } ++ return dhd_pno_set_epno(&dhd->pub); ++} ++int ++dhd_dev_flush_fw_epno(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ if (!dhd) { ++ return BCME_ERROR; ++ } ++ return dhd_pno_flush_fw_epno(&dhd->pub); ++} ++ ++/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ ++int ++dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, ++ void *buf, bool flush) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_set_cfg_gscan(&dhd->pub, type, buf, flush)); ++} ++ ++/* Linux wrapper to call common dhd_wait_batch_results_complete */ ++int ++dhd_dev_wait_batch_results_complete(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_wait_batch_results_complete(&dhd->pub)); ++} ++ ++/* Linux wrapper to call common dhd_pno_lock_batch_results */ ++int ++dhd_dev_pno_lock_access_batch_results(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_lock_batch_results(&dhd->pub)); ++} ++/* Linux wrapper to call common dhd_pno_unlock_batch_results */ ++void ++dhd_dev_pno_unlock_access_batch_results(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_unlock_batch_results(&dhd->pub)); ++} ++ ++/* Linux wrapper to call common dhd_pno_initiate_gscan_request */ ++int ++dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_initiate_gscan_request(&dhd->pub, run, flush)); ++} ++ ++/* Linux wrapper to call common dhd_pno_enable_full_scan_result */ ++int ++dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time_flag) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_enable_full_scan_result(&dhd->pub, real_time_flag)); ++} ++ ++/* Linux wrapper to call common dhd_handle_hotlist_scan_evt */ ++void * ++dhd_dev_hotlist_scan_event(struct net_device *dev, ++ const void *data, int *send_evt_bytes, hotlist_type_t type) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_handle_hotlist_scan_evt(&dhd->pub, data, send_evt_bytes, type)); ++} ++ ++/* Linux wrapper to call common dhd_process_full_gscan_result */ ++void * ++dhd_dev_process_full_gscan_result(struct net_device *dev, ++const void *data, uint32 len, int *send_evt_bytes) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_process_full_gscan_result(&dhd->pub, data, len, send_evt_bytes)); ++} ++ ++void ++dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ dhd_gscan_hotlist_cache_cleanup(&dhd->pub, type); ++ ++ return; ++} ++ ++int ++dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_gscan_batch_cache_cleanup(&dhd->pub)); ++} ++ ++/* Linux wrapper to call common dhd_retreive_batch_scan_results */ ++int ++dhd_dev_retrieve_batch_scan(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_retreive_batch_scan_results(&dhd->pub)); ++} ++ ++/* Linux wrapper to call common dhd_pno_process_epno_result */ ++void * dhd_dev_process_epno_result(struct net_device *dev, ++ const void *data, uint32 event, int *send_evt_bytes) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_process_epno_result(&dhd->pub, data, event, send_evt_bytes)); ++} ++ ++int ++dhd_dev_set_lazy_roam_cfg(struct net_device *dev, ++ wlc_roam_exp_params_t *roam_param) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ wl_roam_exp_cfg_t roam_exp_cfg; ++ int err; ++ ++ if (!roam_param) { ++ return BCME_BADARG; ++ } ++ ++ DHD_ERROR(("a_band_boost_thr %d a_band_penalty_thr %d\n", ++ roam_param->a_band_boost_threshold, roam_param->a_band_penalty_threshold)); ++ DHD_ERROR(("a_band_boost_factor %d a_band_penalty_factor %d cur_bssid_boost %d\n", ++ roam_param->a_band_boost_factor, roam_param->a_band_penalty_factor, ++ roam_param->cur_bssid_boost)); ++ DHD_ERROR(("alert_roam_trigger_thr %d a_band_max_boost %d\n", ++ roam_param->alert_roam_trigger_threshold, roam_param->a_band_max_boost)); ++ ++ memcpy(&roam_exp_cfg.params, roam_param, sizeof(*roam_param)); ++ roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; ++ roam_exp_cfg.flags = ROAM_EXP_CFG_PRESENT; ++ if (dhd->pub.lazy_roam_enable) { ++ roam_exp_cfg.flags |= ROAM_EXP_ENABLE_FLAG; ++ } ++ err = dhd_iovar(&dhd->pub, 0, "roam_exp_params", ++ (char *)&roam_exp_cfg, sizeof(roam_exp_cfg), NULL, 0, ++ TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); ++ } ++ return err; ++} ++ ++int ++dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable) ++{ ++ int err; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ wl_roam_exp_cfg_t roam_exp_cfg; ++ ++ memset(&roam_exp_cfg, 0, sizeof(roam_exp_cfg)); ++ roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; ++ if (enable) { ++ roam_exp_cfg.flags = ROAM_EXP_ENABLE_FLAG; ++ } ++ ++ err = dhd_iovar(&dhd->pub, 0, "roam_exp_params", ++ (char *)&roam_exp_cfg, sizeof(roam_exp_cfg), NULL, 0, ++ TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); ++ } else { ++ dhd->pub.lazy_roam_enable = (enable != 0); ++ } ++ return err; ++} ++ ++int ++dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, ++ wl_bssid_pref_cfg_t *bssid_pref, uint32 flush) ++{ ++ int err; ++ int len; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ bssid_pref->version = BSSID_PREF_LIST_VERSION; ++ /* By default programming bssid pref flushes out old values */ ++ bssid_pref->flags = (flush && !bssid_pref->count) ? ROAM_EXP_CLEAR_BSSID_PREF: 0; ++ len = sizeof(wl_bssid_pref_cfg_t); ++ len += (bssid_pref->count - 1) * sizeof(wl_bssid_pref_list_t); ++ err = dhd_iovar(&(dhd->pub), 0, "roam_exp_bssid_pref", (char *)bssid_pref, ++ len, NULL, 0, TRUE); ++ if (err != BCME_OK) { ++ DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); ++ } ++ return err; ++} ++ ++int ++dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, ++ uint32 len, uint32 flush) ++{ ++ int err; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ int macmode; ++ ++ if (blacklist) { ++ err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACLIST, (char *)blacklist, ++ len, TRUE, 0); ++ if (err != BCME_OK) { ++ DHD_ERROR(("%s : WLC_SET_MACLIST failed %d\n", __FUNCTION__, err)); ++ return err; ++ } ++ } ++ /* By default programming blacklist flushes out old values */ ++ macmode = (flush && !blacklist) ? WLC_MACMODE_DISABLED : WLC_MACMODE_DENY; ++ err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACMODE, (char *)&macmode, ++ sizeof(macmode), TRUE, 0); ++ if (err != BCME_OK) { ++ DHD_ERROR(("%s : WLC_SET_MACMODE failed %d\n", __FUNCTION__, err)); ++ } ++ return err; ++} ++ ++int ++dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid_whitelist, ++ uint32 len, uint32 flush) ++{ ++ int err; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ wl_ssid_whitelist_t whitelist_ssid_flush; ++ ++ if (!ssid_whitelist) { ++ if (flush) { ++ ssid_whitelist = &whitelist_ssid_flush; ++ ssid_whitelist->ssid_count = 0; ++ } else { ++ DHD_ERROR(("%s : Nothing to do here\n", __FUNCTION__)); ++ return BCME_BADARG; ++ } ++ } ++ ssid_whitelist->version = SSID_WHITELIST_VERSION; ++ ssid_whitelist->flags = flush ? ROAM_EXP_CLEAR_SSID_WHITELIST : 0; ++ err = dhd_iovar(&(dhd->pub), 0, "roam_exp_ssid_whitelist", (char *)ssid_whitelist, ++ len, NULL, 0, TRUE); ++ if (err != BCME_OK) { ++ DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); ++ } ++ return err; ++} ++#endif /* GSCAN_SUPPORT */ ++ ++#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) ++/* Linux wrapper to call common dhd_pno_get_gscan */ ++void * ++dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, ++ void *info, uint32 *len) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_pno_get_gscan(&dhd->pub, type, info, len)); ++} ++#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ ++#endif ++ ++#ifdef RSSI_MONITOR_SUPPORT ++int ++dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, ++ int8 max_rssi, int8 min_rssi) ++{ ++ int err; ++ wl_rssi_monitor_cfg_t rssi_monitor; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ rssi_monitor.version = RSSI_MONITOR_VERSION; ++ rssi_monitor.max_rssi = max_rssi; ++ rssi_monitor.min_rssi = min_rssi; ++ rssi_monitor.flags = start ? 0: RSSI_MONITOR_STOP; ++ err = dhd_iovar(&(dhd->pub), 0, "rssi_monitor", (char *)&rssi_monitor, ++ sizeof(rssi_monitor), NULL, 0, TRUE); ++ if (err < 0 && err != BCME_UNSUPPORTED) { ++ DHD_ERROR(("%s : Failed to execute rssi_monitor %d\n", __FUNCTION__, err)); ++ } ++ return err; ++} ++#endif /* RSSI_MONITOR_SUPPORT */ ++ ++#ifdef DHDTCPACK_SUPPRESS ++int dhd_dev_set_tcpack_sup_mode_cfg(struct net_device *dev, uint8 enable) ++{ ++ int err; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ err = dhd_tcpack_suppress_set(&(dhd->pub), enable); ++ if (err != BCME_OK) { ++ DHD_ERROR(("%s : Failed to execute rssi_monitor %d\n", __FUNCTION__, err)); ++ } ++ return err; ++} ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++int ++dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ ++ if (!dhdp || !oui) { ++ DHD_ERROR(("NULL POINTER : %s\n", ++ __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ if (ETHER_ISMULTI(oui)) { ++ DHD_ERROR(("Expected unicast OUI\n")); ++ return BCME_ERROR; ++ } else { ++ uint8 *rand_mac_oui = dhdp->rand_mac_oui; ++ memcpy(rand_mac_oui, oui, DOT11_OUI_LEN); ++ DHD_ERROR(("Random MAC OUI to be used - %02x:%02x:%02x\n", rand_mac_oui[0], ++ rand_mac_oui[1], rand_mac_oui[2])); ++ } ++ return BCME_OK; ++} ++ ++int ++dhd_set_rand_mac_oui(dhd_pub_t *dhd) ++{ ++ int err; ++ wl_pfn_macaddr_cfg_t wl_cfg; ++ uint8 *rand_mac_oui = dhd->rand_mac_oui; ++ ++ memset(&wl_cfg.macaddr, 0, ETHER_ADDR_LEN); ++ memcpy(&wl_cfg.macaddr, rand_mac_oui, DOT11_OUI_LEN); ++ wl_cfg.version = WL_PFN_MACADDR_CFG_VER; ++ if (ETHER_ISNULLADDR(&wl_cfg.macaddr)) { ++ wl_cfg.flags = 0; ++ } else { ++ wl_cfg.flags = (WL_PFN_MAC_OUI_ONLY_MASK | WL_PFN_SET_MAC_UNASSOC_MASK); ++ } ++ ++ DHD_ERROR(("Setting rand mac oui to FW - %02x:%02x:%02x\n", rand_mac_oui[0], ++ rand_mac_oui[1], rand_mac_oui[2])); ++ ++ err = dhd_iovar(dhd, 0, "pfn_macaddr", (char *)&wl_cfg, sizeof(wl_cfg), NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to execute pfn_macaddr %d\n", __FUNCTION__, err)); ++ } ++ return err; ++} ++ ++#ifdef RTT_SUPPORT ++#ifdef WL_CFG80211 ++/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ ++int ++dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_rtt_set_cfg(&dhd->pub, buf)); ++} ++ ++int ++dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_rtt_stop(&dhd->pub, mac_list, mac_cnt)); ++} ++ ++int ++dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, dhd_rtt_compl_noti_fn noti_fn) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_rtt_register_noti_callback(&dhd->pub, ctx, noti_fn)); ++} ++ ++int ++dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_rtt_unregister_noti_callback(&dhd->pub, noti_fn)); ++} ++ ++int ++dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ ++ return (dhd_rtt_capability(&dhd->pub, capa)); ++} ++ ++int ++dhd_dev_rtt_avail_channel(struct net_device *dev, wifi_channel_info *channel_info) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ return (dhd_rtt_avail_channel(&dhd->pub, channel_info)); ++} ++ ++int ++dhd_dev_rtt_enable_responder(struct net_device *dev, wifi_channel_info *channel_info) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ return (dhd_rtt_enable_responder(&dhd->pub, channel_info)); ++} ++ ++int dhd_dev_rtt_cancel_responder(struct net_device *dev) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ return (dhd_rtt_cancel_responder(&dhd->pub)); ++} ++#endif /* WL_CFG80211 */ ++#endif /* RTT_SUPPORT */ ++ ++#ifdef KEEP_ALIVE ++#define KA_TEMP_BUF_SIZE 512 ++#define KA_FRAME_SIZE 300 ++ ++int ++dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, uint8 mkeep_alive_id, uint8 *ip_pkt, ++ uint16 ip_pkt_len, uint8* src_mac, uint8* dst_mac, uint32 period_msec) ++{ ++ const int ETHERTYPE_LEN = 2; ++ char *pbuf = NULL; ++ const char *str; ++ wl_mkeep_alive_pkt_t mkeep_alive_pkt; ++ wl_mkeep_alive_pkt_t *mkeep_alive_pktp = NULL; ++ int buf_len = 0; ++ int str_len = 0; ++ int res = BCME_ERROR; ++ int len_bytes = 0; ++ int i = 0; ++ ++ /* ether frame to have both max IP pkt (256 bytes) and ether header */ ++ char *pmac_frame = NULL; ++ char *pmac_frame_begin = NULL; ++ ++ /* ++ * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, ++ * dongle shall reject a mkeep_alive request. ++ */ ++ if (!dhd_support_sta_mode(dhd_pub)) ++ return res; ++ ++ DHD_TRACE(("%s execution\n", __FUNCTION__)); ++ ++ if ((pbuf = kzalloc(KA_TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { ++ DHD_ERROR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE)); ++ res = BCME_NOMEM; ++ return res; ++ } ++ ++ if ((pmac_frame = kzalloc(KA_FRAME_SIZE, GFP_KERNEL)) == NULL) { ++ DHD_ERROR(("failed to allocate mac_frame with size %d\n", KA_FRAME_SIZE)); ++ res = BCME_NOMEM; ++ goto exit; ++ } ++ pmac_frame_begin = pmac_frame; ++ ++ /* ++ * Get current mkeep-alive status. ++ */ ++ res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, ++ KA_TEMP_BUF_SIZE, FALSE); ++ if (res < 0) { ++ DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); ++ goto exit; ++ } else { ++ /* Check available ID whether it is occupied */ ++ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; ++ if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { ++ DHD_ERROR(("%s: Get mkeep_alive failed, ID %u is in use.\n", ++ __FUNCTION__, mkeep_alive_id)); ++ ++ /* Current occupied ID info */ ++ DHD_ERROR(("%s: mkeep_alive\n", __FUNCTION__)); ++ DHD_ERROR((" Id : %d\n" ++ " Period: %d msec\n" ++ " Length: %d\n" ++ " Packet: 0x", ++ mkeep_alive_pktp->keep_alive_id, ++ dtoh32(mkeep_alive_pktp->period_msec), ++ dtoh16(mkeep_alive_pktp->len_bytes))); ++ ++ for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { ++ DHD_ERROR(("%02x", mkeep_alive_pktp->data[i])); ++ } ++ DHD_ERROR(("\n")); ++ ++ res = BCME_NOTFOUND; ++ goto exit; ++ } ++ } ++ ++ /* Request the specified ID */ ++ memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); ++ memset(pbuf, 0, KA_TEMP_BUF_SIZE); ++ str = "mkeep_alive"; ++ str_len = strlen(str); ++ strncpy(pbuf, str, str_len); ++ pbuf[str_len] = '\0'; ++ ++ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + str_len + 1); ++ mkeep_alive_pkt.period_msec = htod32(period_msec); ++ buf_len = str_len + 1; ++ mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); ++ mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); ++ ++ /* ID assigned */ ++ mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; ++ ++ buf_len += WL_MKEEP_ALIVE_FIXED_LEN; ++ ++ /* ++ * Build up Ethernet Frame ++ */ ++ ++ /* Mapping dest mac addr */ ++ memcpy(pmac_frame, dst_mac, ETHER_ADDR_LEN); ++ pmac_frame += ETHER_ADDR_LEN; ++ ++ /* Mapping src mac addr */ ++ memcpy(pmac_frame, src_mac, ETHER_ADDR_LEN); ++ pmac_frame += ETHER_ADDR_LEN; ++ ++ /* Mapping Ethernet type (ETHERTYPE_IP: 0x0800) */ ++ *(pmac_frame++) = 0x08; ++ *(pmac_frame++) = 0x00; ++ ++ /* Mapping IP pkt */ ++ memcpy(pmac_frame, ip_pkt, ip_pkt_len); ++ pmac_frame += ip_pkt_len; ++ ++ /* ++ * Length of ether frame (assume to be all hexa bytes) ++ * = src mac + dst mac + ether type + ip pkt len ++ */ ++ len_bytes = ETHER_ADDR_LEN*2 + ETHERTYPE_LEN + ip_pkt_len; ++ memcpy(mkeep_alive_pktp->data, pmac_frame_begin, len_bytes); ++ buf_len += len_bytes; ++ mkeep_alive_pkt.len_bytes = htod16(len_bytes); ++ ++ /* ++ * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and ++ * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no ++ * guarantee that the buffer is properly aligned. ++ */ ++ memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); ++ ++ res = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, pbuf, buf_len, TRUE, 0); ++exit: ++ kfree(pmac_frame_begin); ++ kfree(pbuf); ++ return res; ++} ++ ++int ++dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, uint8 mkeep_alive_id) ++{ ++ char *pbuf; ++ wl_mkeep_alive_pkt_t mkeep_alive_pkt; ++ wl_mkeep_alive_pkt_t *mkeep_alive_pktp; ++ int res = BCME_ERROR; ++ int i; ++ ++ /* ++ * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, ++ * dongle shall reject a mkeep_alive request. ++ */ ++ if (!dhd_support_sta_mode(dhd_pub)) ++ return res; ++ ++ DHD_TRACE(("%s execution\n", __FUNCTION__)); ++ ++ /* ++ * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt. ++ */ ++ if ((pbuf = kmalloc(KA_TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { ++ DHD_ERROR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE)); ++ return res; ++ } ++ ++ res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, ++ sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, FALSE); ++ if (res < 0) { ++ DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); ++ goto exit; ++ } else { ++ /* Check occupied ID */ ++ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; ++ DHD_INFO(("%s: mkeep_alive\n", __FUNCTION__)); ++ DHD_INFO((" Id : %d\n" ++ " Period: %d msec\n" ++ " Length: %d\n" ++ " Packet: 0x", ++ mkeep_alive_pktp->keep_alive_id, ++ dtoh32(mkeep_alive_pktp->period_msec), ++ dtoh16(mkeep_alive_pktp->len_bytes))); ++ ++ for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { ++ DHD_INFO(("%02x", mkeep_alive_pktp->data[i])); ++ } ++ DHD_INFO(("\n")); ++ } ++ ++ /* Make it stop if available */ ++ if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { ++ DHD_INFO(("stop mkeep_alive on ID %d\n", mkeep_alive_id)); ++ memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); ++ ++ mkeep_alive_pkt.period_msec = 0; ++ mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); ++ mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); ++ mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; ++ ++ res = dhd_iovar(dhd_pub, 0, "mkeep_alive", ++ (char *)&mkeep_alive_pkt, ++ WL_MKEEP_ALIVE_FIXED_LEN, NULL, 0, TRUE); ++ } else { ++ DHD_ERROR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id)); ++ res = BCME_NOTFOUND; ++ } ++exit: ++ kfree(pbuf); ++ return res; ++} ++#endif /* KEEP_ALIVE */ ++ ++#if defined(PKT_FILTER_SUPPORT) && defined(APF) ++static void _dhd_apf_lock_local(dhd_info_t *dhd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ if (dhd) { ++ mutex_lock(&dhd->dhd_apf_mutex); ++ } ++#endif ++} ++ ++static void _dhd_apf_unlock_local(dhd_info_t *dhd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ if (dhd) { ++ mutex_unlock(&dhd->dhd_apf_mutex); ++ } ++#endif ++} ++ ++static int ++__dhd_apf_add_filter(struct net_device *ndev, uint32 filter_id, ++ u8* program, uint32 program_len) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(ndev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ wl_pkt_filter_t * pkt_filterp; ++ wl_apf_program_t *apf_program; ++ char *buf; ++ u32 cmd_len, buf_len; ++ int ifidx, ret; ++ gfp_t kflags; ++ char cmd[] = "pkt_filter_add"; ++ ++ ifidx = dhd_net2idx(dhd, ndev); ++ if (ifidx == DHD_BAD_IF) { ++ DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++ cmd_len = sizeof(cmd); ++ ++ /* Check if the program_len is more than the expected len ++ * and if the program is NULL return from here. ++ */ ++ if ((program_len > WL_APF_PROGRAM_MAX_SIZE) || (program == NULL)) { ++ DHD_ERROR(("%s Invalid program_len: %d, program: %pK\n", ++ __FUNCTION__, program_len, program)); ++ return -EINVAL; ++ } ++ buf_len = cmd_len + WL_PKT_FILTER_FIXED_LEN + ++ WL_APF_PROGRAM_FIXED_LEN + program_len; ++ ++ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ buf = kzalloc(buf_len, kflags); ++ if (unlikely(!buf)) { ++ DHD_ERROR(("%s: MALLOC failure, %d bytes\n", __FUNCTION__, buf_len)); ++ return -ENOMEM; ++ } ++ ++ memcpy(buf, cmd, cmd_len); ++ ++ pkt_filterp = (wl_pkt_filter_t *) (buf + cmd_len); ++ pkt_filterp->id = htod32(filter_id); ++ pkt_filterp->negate_match = htod32(FALSE); ++ pkt_filterp->type = htod32(WL_PKT_FILTER_TYPE_APF_MATCH); ++ ++ apf_program = &pkt_filterp->u.apf_program; ++ apf_program->version = htod16(WL_APF_INTERNAL_VERSION); ++ apf_program->instr_len = htod16(program_len); ++ memcpy(apf_program->instrs, program, program_len); ++ ++ ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, buf_len, TRUE, ifidx); ++ if (unlikely(ret)) { ++ DHD_ERROR(("%s: failed to add APF filter, id=%d, ret=%d\n", ++ __FUNCTION__, filter_id, ret)); ++ } ++ ++ if (buf) { ++ kfree(buf); ++ } ++ return ret; ++} ++ ++static int ++__dhd_apf_config_filter(struct net_device *ndev, uint32 filter_id, ++ uint32 mode, uint32 enable) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(ndev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ wl_pkt_filter_enable_t * pkt_filterp; ++ char *buf; ++ u32 cmd_len, buf_len; ++ int ifidx, ret; ++ gfp_t kflags; ++ char cmd[] = "pkt_filter_enable"; ++ ++ ifidx = dhd_net2idx(dhd, ndev); ++ if (ifidx == DHD_BAD_IF) { ++ DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++ cmd_len = sizeof(cmd); ++ buf_len = cmd_len + sizeof(*pkt_filterp); ++ ++ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ buf = kzalloc(buf_len, kflags); ++ if (unlikely(!buf)) { ++ DHD_ERROR(("%s: MALLOC failure, %d bytes\n", __FUNCTION__, buf_len)); ++ return -ENOMEM; ++ } ++ ++ memcpy(buf, cmd, cmd_len); ++ ++ pkt_filterp = (wl_pkt_filter_enable_t *) (buf + cmd_len); ++ pkt_filterp->id = htod32(filter_id); ++ pkt_filterp->enable = htod32(enable); ++ ++ ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, buf_len, TRUE, ifidx); ++ if (unlikely(ret)) { ++ DHD_ERROR(("%s: failed to enable APF filter, id=%d, ret=%d\n", ++ __FUNCTION__, filter_id, ret)); ++ goto exit; ++ } ++ ++ ret = dhd_wl_ioctl_set_intiovar(dhdp, "pkt_filter_mode", dhd_master_mode, ++ WLC_SET_VAR, TRUE, ifidx); ++ if (unlikely(ret)) { ++ DHD_ERROR(("%s: failed to set APF filter mode, id=%d, ret=%d\n", ++ __FUNCTION__, filter_id, ret)); ++ } ++ ++exit: ++ if (buf) { ++ kfree(buf); ++ } ++ return ret; ++} ++ ++static int ++__dhd_apf_delete_filter(struct net_device *ndev, uint32 filter_id) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(ndev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ifidx, ret; ++ ++ ifidx = dhd_net2idx(dhd, ndev); ++ if (ifidx == DHD_BAD_IF) { ++ DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++ ret = dhd_wl_ioctl_set_intiovar(dhdp, "pkt_filter_delete", ++ htod32(filter_id), WLC_SET_VAR, TRUE, ifidx); ++ if (unlikely(ret)) { ++ DHD_ERROR(("%s: failed to delete APF filter, id=%d, ret=%d\n", ++ __FUNCTION__, filter_id, ret)); ++ } ++ ++ return ret; ++} ++ ++void dhd_apf_lock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ _dhd_apf_lock_local(dhd); ++} ++ ++void dhd_apf_unlock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ _dhd_apf_unlock_local(dhd); ++} ++ ++int ++dhd_dev_apf_get_version(struct net_device *ndev, uint32 *version) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(ndev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ifidx, ret; ++ ++ if (!FW_SUPPORTED(dhdp, apf)) { ++ DHD_ERROR(("%s: firmware doesn't support APF\n", __FUNCTION__)); ++ ++ /* ++ * Notify Android framework that APF is not supported by setting ++ * version as zero. ++ */ ++ *version = 0; ++ return BCME_OK; ++ } ++ ++ ifidx = dhd_net2idx(dhd, ndev); ++ if (ifidx == DHD_BAD_IF) { ++ DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++ ret = dhd_wl_ioctl_get_intiovar(dhdp, "apf_ver", version, ++ WLC_GET_VAR, FALSE, ifidx); ++ if (unlikely(ret)) { ++ DHD_ERROR(("%s: failed to get APF version, ret=%d\n", ++ __FUNCTION__, ret)); ++ } ++ ++ return ret; ++} ++ ++int ++dhd_dev_apf_get_max_len(struct net_device *ndev, uint32 *max_len) ++{ ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(ndev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ifidx, ret; ++ ++ if (!FW_SUPPORTED(dhdp, apf)) { ++ DHD_ERROR(("%s: firmware doesn't support APF\n", __FUNCTION__)); ++ *max_len = 0; ++ return BCME_OK; ++ } ++ ++ ifidx = dhd_net2idx(dhd, ndev); ++ if (ifidx == DHD_BAD_IF) { ++ DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++ ret = dhd_wl_ioctl_get_intiovar(dhdp, "apf_size_limit", max_len, ++ WLC_GET_VAR, FALSE, ifidx); ++ if (unlikely(ret)) { ++ DHD_ERROR(("%s: failed to get APF size limit, ret=%d\n", ++ __FUNCTION__, ret)); ++ } ++ ++ return ret; ++} ++ ++int ++dhd_dev_apf_add_filter(struct net_device *ndev, u8* program, ++ uint32 program_len) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(ndev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ret; ++ ++ DHD_APF_LOCK(ndev); ++ ++ /* delete, if filter already exists */ ++ if (dhdp->apf_set) { ++ ret = __dhd_apf_delete_filter(ndev, PKT_FILTER_APF_ID); ++ if (unlikely(ret)) { ++ goto exit; ++ } ++ dhdp->apf_set = FALSE; ++ } ++ ++ ret = __dhd_apf_add_filter(ndev, PKT_FILTER_APF_ID, program, program_len); ++ if (ret) { ++ goto exit; ++ } ++ dhdp->apf_set = TRUE; ++ ++ if (dhdp->in_suspend && dhdp->apf_set && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) { ++ /* Driver is still in (early) suspend state, enable APF filter back */ ++ ret = __dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, ++ PKT_FILTER_MODE_FORWARD_ON_MATCH, TRUE); ++ } ++exit: ++ DHD_APF_UNLOCK(ndev); ++ ++ return ret; ++} ++ ++int ++dhd_dev_apf_enable_filter(struct net_device *ndev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(ndev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ret = 0; ++ ++ DHD_APF_LOCK(ndev); ++ ++ if (dhdp->apf_set && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) { ++ ret = __dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, ++ PKT_FILTER_MODE_FORWARD_ON_MATCH, TRUE); ++ } ++ ++ DHD_APF_UNLOCK(ndev); ++ ++ return ret; ++} ++ ++int ++dhd_dev_apf_disable_filter(struct net_device *ndev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(ndev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ret = 0; ++ ++ DHD_APF_LOCK(ndev); ++ ++ if (dhdp->apf_set) { ++ ret = __dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, ++ PKT_FILTER_MODE_FORWARD_ON_MATCH, FALSE); ++ } ++ ++ DHD_APF_UNLOCK(ndev); ++ ++ return ret; ++} ++ ++int ++dhd_dev_apf_delete_filter(struct net_device *ndev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(ndev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ int ret = 0; ++ ++ DHD_APF_LOCK(ndev); ++ ++ if (dhdp->apf_set) { ++ ret = __dhd_apf_delete_filter(ndev, PKT_FILTER_APF_ID); ++ if (!ret) { ++ dhdp->apf_set = FALSE; ++ } ++ } ++ ++ DHD_APF_UNLOCK(ndev); ++ ++ return ret; ++} ++#endif /* PKT_FILTER_SUPPORT && APF */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++static void dhd_hang_process(void *dhd_info, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd; ++ struct net_device *dev; ++ ++ dhd = (dhd_info_t *)dhd_info; ++ if (!dhd || !dhd->iflist[0]) ++ return; ++ dev = dhd->iflist[0]->net; ++ ++ if (dev) { ++ /* ++ * For HW2, dev_close need to be done to recover ++ * from upper layer after hang. For Interposer skip ++ * dev_close so that dhd iovars can be used to take ++ * socramdump after crash, also skip for HW4 as ++ * handling of hang event is different ++ */ ++#if !defined(CUSTOMER_HW2_INTERPOSER) ++ rtnl_lock(); ++ dev_close(dev); ++ rtnl_unlock(); ++#endif ++#if defined(WL_WIRELESS_EXT) ++ wl_iw_send_priv_event(dev, "HANG"); ++#endif ++#if defined(WL_CFG80211) ++ wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); ++#endif ++ } ++} ++ ++#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY ++extern dhd_pub_t *link_recovery; ++void dhd_host_recover_link(void) ++{ ++ DHD_ERROR(("****** %s ******\n", __FUNCTION__)); ++ link_recovery->hang_reason = HANG_REASON_PCIE_LINK_DOWN; ++ dhd_bus_set_linkdown(link_recovery, TRUE); ++ dhd_os_send_hang_message(link_recovery); ++} ++EXPORT_SYMBOL(dhd_host_recover_link); ++#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */ ++ ++int dhd_os_send_hang_message(dhd_pub_t *dhdp) ++{ ++ int ret = 0; ++ if (dhdp) { ++#if defined(DHD_HANG_SEND_UP_TEST) ++ if (dhdp->req_hang_type) { ++ DHD_ERROR(("%s, Clear HANG test request 0x%x\n", ++ __FUNCTION__, dhdp->req_hang_type)); ++ dhdp->req_hang_type = 0; ++ } ++#endif /* DHD_HANG_SEND_UP_TEST */ ++ ++ if (!dhdp->hang_was_sent) { ++#if defined(CONFIG_BCM_DETECT_CONSECUTIVE_HANG) ++ dhdp->hang_counts++; ++ if (dhdp->hang_counts >= MAX_CONSECUTIVE_HANG_COUNTS) { ++ DHD_ERROR(("%s, Consecutive hang from Dongle :%u\n", ++ __func__, dhdp->hang_counts)); ++ BUG_ON(1); ++ } ++#endif /* CONFIG_BCM_DETECT_CONSECUTIVE_HANG */ ++#ifdef DHD_DEBUG_UART ++ /* If PCIe lane has broken, execute the debug uart application ++ * to gether a ramdump data from dongle via uart ++ */ ++ if (!dhdp->info->duart_execute) { ++ dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, ++ (void *)dhdp, DHD_WQ_WORK_DEBUG_UART_DUMP, ++ dhd_debug_uart_exec_rd, DHD_WQ_WORK_PRIORITY_HIGH); ++ } ++#endif /* DHD_DEBUG_UART */ ++ dhdp->hang_was_sent = 1; ++#ifdef BT_OVER_SDIO ++ dhdp->is_bt_recovery_required = TRUE; ++#endif ++ dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dhdp, ++ DHD_WQ_WORK_HANG_MSG, dhd_hang_process, DHD_WQ_WORK_PRIORITY_HIGH); ++ DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d s=%d\n", __FUNCTION__, ++ dhdp->rxcnt_timeout, dhdp->txcnt_timeout, dhdp->busstate)); ++ } ++ } ++ return ret; ++} ++ ++int net_os_send_hang_message(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int ret = 0; ++ ++ if (dhd) { ++ /* Report FW problem when enabled */ ++ if (dhd->pub.hang_report) { ++#ifdef BT_OVER_SDIO ++ if (netif_running(dev)) { ++#endif /* BT_OVER_SDIO */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ ret = dhd_os_send_hang_message(&dhd->pub); ++#else ++ ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); ++#endif ++#ifdef BT_OVER_SDIO ++ } ++ DHD_ERROR(("%s: HANG -> Reset BT\n", __FUNCTION__)); ++ bcmsdh_btsdio_process_dhd_hang_notification(!netif_running(dev)); ++#endif /* BT_OVER_SDIO */ ++ } else { ++ DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n", ++ __FUNCTION__)); ++ } ++ } ++ return ret; ++} ++ ++int net_os_send_hang_message_reason(struct net_device *dev, const char *string_num) ++{ ++ dhd_info_t *dhd = NULL; ++ dhd_pub_t *dhdp = NULL; ++ int reason; ++ ++ dhd = DHD_DEV_INFO(dev); ++ if (dhd) { ++ dhdp = &dhd->pub; ++ } ++ ++ if (!dhd || !dhdp) { ++ return 0; ++ } ++ ++ reason = bcm_strtoul(string_num, NULL, 0); ++ DHD_INFO(("%s: Enter, reason=0x%x\n", __FUNCTION__, reason)); ++ ++ if ((reason <= HANG_REASON_MASK) || (reason >= HANG_REASON_MAX)) { ++ reason = 0; ++ } ++ ++ dhdp->hang_reason = reason; ++ ++ return net_os_send_hang_message(dev); ++} ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ ++ ++ ++int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, unsigned long delay_msec) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ return wifi_platform_set_power(dhd->adapter, on, delay_msec); ++} ++ ++bool dhd_force_country_change(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ if (dhd && dhd->pub.up) ++ return dhd->pub.force_country_change; ++ return FALSE; ++} ++ ++void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code, ++ wl_country_t *cspec) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++#if defined(DHD_BLOB_EXISTENCE_CHECK) ++ if (!dhd->pub.is_blob) ++#endif /* DHD_BLOB_EXISTENCE_CHECK */ ++ { ++#if defined(CUSTOM_COUNTRY_CODE) ++ get_customized_country_code(dhd->adapter, country_iso_code, cspec, ++ dhd->pub.dhd_cflags); ++#else ++ get_customized_country_code(dhd->adapter, country_iso_code, cspec); ++#endif /* CUSTOM_COUNTRY_CODE */ ++ } ++ ++ BCM_REFERENCE(dhd); ++} ++ ++void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++#ifdef WL_CFG80211 ++ struct bcm_cfg80211 *cfg = wl_get_cfg(dev); ++#endif ++ ++ if (dhd && dhd->pub.up) { ++ memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); ++#ifdef WL_CFG80211 ++ wl_update_wiphybands(cfg, notify); ++#endif ++ } ++} ++ ++void dhd_bus_band_set(struct net_device *dev, uint band) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++#ifdef WL_CFG80211 ++ struct bcm_cfg80211 *cfg = wl_get_cfg(dev); ++#endif ++ if (dhd && dhd->pub.up) { ++#ifdef WL_CFG80211 ++ wl_update_wiphybands(cfg, true); ++#endif ++ } ++} ++ ++int dhd_net_set_fw_path(struct net_device *dev, char *fw) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ if (!fw || fw[0] == '\0') ++ return -EINVAL; ++ ++ strncpy(dhd->fw_path, fw, sizeof(dhd->fw_path) - 1); ++ dhd->fw_path[sizeof(dhd->fw_path)-1] = '\0'; ++ ++#if defined(SOFTAP) ++ if (strstr(fw, "apsta") != NULL) { ++ DHD_INFO(("GOT APSTA FIRMWARE\n")); ++ ap_fw_loaded = TRUE; ++ } else { ++ DHD_INFO(("GOT STA FIRMWARE\n")); ++ ap_fw_loaded = FALSE; ++ } ++#endif ++ return 0; ++} ++ ++void dhd_net_if_lock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ dhd_net_if_lock_local(dhd); ++} ++ ++void dhd_net_if_unlock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ dhd_net_if_unlock_local(dhd); ++} ++ ++static void dhd_net_if_lock_local(dhd_info_t *dhd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ if (dhd) ++ mutex_lock(&dhd->dhd_net_if_mutex); ++#endif ++} ++ ++static void dhd_net_if_unlock_local(dhd_info_t *dhd) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ if (dhd) ++ mutex_unlock(&dhd->dhd_net_if_mutex); ++#endif ++} ++ ++static void dhd_suspend_lock(dhd_pub_t *pub) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ if (dhd) ++ mutex_lock(&dhd->dhd_suspend_mutex); ++#endif ++} ++ ++static void dhd_suspend_unlock(dhd_pub_t *pub) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ if (dhd) ++ mutex_unlock(&dhd->dhd_suspend_mutex); ++#endif ++} ++ ++unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags = 0; ++ ++ if (dhd) ++ spin_lock_irqsave(&dhd->dhd_lock, flags); ++ ++ return flags; ++} ++ ++void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) ++ spin_unlock_irqrestore(&dhd->dhd_lock, flags); ++} ++ ++/* Linux specific multipurpose spinlock API */ ++void * ++dhd_os_spin_lock_init(osl_t *osh) ++{ ++ /* Adding 4 bytes since the sizeof(spinlock_t) could be 0 */ ++ /* if CONFIG_SMP and CONFIG_DEBUG_SPINLOCK are not defined */ ++ /* and this results in kernel asserts in internal builds */ ++ spinlock_t * lock = MALLOC(osh, sizeof(spinlock_t) + 4); ++ if (lock) ++ spin_lock_init(lock); ++ return ((void *)lock); ++} ++void ++dhd_os_spin_lock_deinit(osl_t *osh, void *lock) ++{ ++ if (lock) ++ MFREE(osh, lock, sizeof(spinlock_t) + 4); ++} ++unsigned long ++dhd_os_spin_lock(void *lock) ++{ ++ unsigned long flags = 0; ++ ++ if (lock) ++ spin_lock_irqsave((spinlock_t *)lock, flags); ++ ++ return flags; ++} ++void ++dhd_os_spin_unlock(void *lock, unsigned long flags) ++{ ++ if (lock) ++ spin_unlock_irqrestore((spinlock_t *)lock, flags); ++} ++ ++static int ++dhd_get_pend_8021x_cnt(dhd_info_t *dhd) ++{ ++ return (atomic_read(&dhd->pend_8021x_cnt)); ++} ++ ++#define MAX_WAIT_FOR_8021X_TX 100 ++ ++int ++dhd_wait_pend8021x(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int timeout = msecs_to_jiffies(10); ++ int ntimes = MAX_WAIT_FOR_8021X_TX; ++ int pend = dhd_get_pend_8021x_cnt(dhd); ++ ++ while (ntimes && pend) { ++ if (pend) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ schedule_timeout(timeout); ++ DHD_PERIM_LOCK(&dhd->pub); ++ set_current_state(TASK_RUNNING); ++ ntimes--; ++ } ++ pend = dhd_get_pend_8021x_cnt(dhd); ++ } ++ if (ntimes == 0) ++ { ++ atomic_set(&dhd->pend_8021x_cnt, 0); ++ DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__)); ++ } ++ return pend; ++} ++ ++#if defined(DHD_DEBUG) ++int write_file(const char * file_name, uint32 flags, uint8 *buf, int size) ++{ ++ int ret = 0; ++ struct file *fp = NULL; ++ mm_segment_t old_fs; ++ loff_t pos = 0; ++ /* change to KERNEL_DS address limit */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ /* open file to write */ ++ fp = filp_open(file_name, flags, 0664); ++ if (IS_ERR(fp)) { ++ DHD_ERROR(("open file error, err = %ld\n", PTR_ERR(fp))); ++ ret = -1; ++ goto exit; ++ } ++ ++ /* Write buf to file */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ ret = kernel_write(fp, buf, size, &pos); ++#else ++ ret = vfs_write(fp, buf, size, &pos); ++#endif ++ if (ret < 0) { ++ DHD_ERROR(("write file error, err = %d\n", ret)); ++ goto exit; ++ } ++ ++ /* Sync file from filesystem to physical media */ ++ ret = vfs_fsync(fp, 0); ++ if (ret < 0) { ++ DHD_ERROR(("sync file error, error = %d\n", ret)); ++ goto exit; ++ } ++ ret = BCME_OK; ++ ++exit: ++ /* close file before return */ ++ if (!IS_ERR(fp)) ++ filp_close(fp, current->files); ++ ++ /* restore previous address limit */ ++ set_fs(old_fs); ++ ++ return ret; ++} ++#endif ++ ++#ifdef DHD_DEBUG ++static void ++dhd_convert_memdump_type_to_str(uint32 type, char *buf) ++{ ++ char *type_str = NULL; ++ ++ switch (type) { ++ case DUMP_TYPE_RESUMED_ON_TIMEOUT: ++ type_str = "resumed_on_timeout"; ++ break; ++ case DUMP_TYPE_D3_ACK_TIMEOUT: ++ type_str = "D3_ACK_timeout"; ++ break; ++ case DUMP_TYPE_DONGLE_TRAP: ++ type_str = "Dongle_Trap"; ++ break; ++ case DUMP_TYPE_MEMORY_CORRUPTION: ++ type_str = "Memory_Corruption"; ++ break; ++ case DUMP_TYPE_PKTID_AUDIT_FAILURE: ++ type_str = "PKTID_AUDIT_Fail"; ++ break; ++ case DUMP_TYPE_PKTID_INVALID: ++ type_str = "PKTID_INVALID"; ++ break; ++ case DUMP_TYPE_SCAN_TIMEOUT: ++ type_str = "SCAN_timeout"; ++ break; ++ case DUMP_TYPE_JOIN_TIMEOUT: ++ type_str = "JOIN_timeout"; ++ break; ++ case DUMP_TYPE_SCAN_BUSY: ++ type_str = "SCAN_Busy"; ++ break; ++ case DUMP_TYPE_BY_SYSDUMP: ++ type_str = "BY_SYSDUMP"; ++ break; ++ case DUMP_TYPE_BY_LIVELOCK: ++ type_str = "BY_LIVELOCK"; ++ break; ++ case DUMP_TYPE_AP_LINKUP_FAILURE: ++ type_str = "BY_AP_LINK_FAILURE"; ++ break; ++ case DUMP_TYPE_AP_ABNORMAL_ACCESS: ++ type_str = "INVALID_ACCESS"; ++ break; ++ case DUMP_TYPE_CFG_VENDOR_TRIGGERED: ++ type_str = "CFG_VENDOR_TRIGGERED"; ++ break; ++ case DUMP_TYPE_RESUMED_ON_TIMEOUT_RX: ++ type_str = "ERROR_RX_TIMED_OUT"; ++ break; ++ case DUMP_TYPE_RESUMED_ON_TIMEOUT_TX: ++ type_str = "ERROR_TX_TIMED_OUT"; ++ break; ++ case DUMP_TYPE_RESUMED_ON_INVALID_RING_RDWR: ++ type_str = "BY_INVALID_RING_RDWR"; ++ break; ++ case DUMP_TYPE_DONGLE_HOST_EVENT: ++ type_str = "BY_DONGLE_HOST_EVENT"; ++ break; ++ case DUMP_TYPE_TRANS_ID_MISMATCH: ++ type_str = "BY_TRANS_ID_MISMATCH"; ++ break; ++ case DUMP_TYPE_HANG_ON_IFACE_OP_FAIL: ++ type_str = "HANG_IFACE_OP_FAIL"; ++ break; ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ case DUMP_TYPE_READ_SHM_FAIL: ++ type_str = "READ_SHM_FAIL"; ++ break; ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ default: ++ type_str = "Unknown_type"; ++ break; ++ } ++ ++ strncpy(buf, type_str, strlen(type_str)); ++ buf[strlen(type_str)] = 0; ++} ++ ++int ++write_dump_to_file(dhd_pub_t *dhd, uint8 *buf, int size, char *fname) ++{ ++ int ret = 0; ++ char memdump_path[128]; ++ char memdump_type[32]; ++ struct osl_timespec curtime; ++ uint32 file_mode; ++ ++ /* Init file name */ ++ memset(memdump_path, 0, sizeof(memdump_path)); ++ memset(memdump_type, 0, sizeof(memdump_type)); ++ osl_do_gettimeofday(&curtime); ++ dhd_convert_memdump_type_to_str(dhd->memdump_type, memdump_type); ++#ifdef CUSTOMER_HW4_DEBUG ++ snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_%ld.%ld", ++ DHD_COMMON_DUMP_PATH, fname, memdump_type, ++ (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); ++ file_mode = O_CREAT | O_WRONLY | O_SYNC; ++#elif defined(CUSTOMER_HW2) ++ snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_%ld.%ld", ++ "/data/misc/wifi/", fname, memdump_type, ++ (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); ++ file_mode = O_CREAT | O_WRONLY | O_SYNC; ++#elif (defined(BOARD_PANDA) || defined(__ARM_ARCH_7A__)) ++ snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_%ld.%ld", ++ "/data/misc/wifi/", fname, memdump_type, ++ (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); ++ file_mode = O_CREAT | O_WRONLY; ++#else ++ snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_%ld.%ld", ++ "/installmedia/", fname, memdump_type, ++ (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); ++ /* Extra flags O_DIRECT and O_SYNC are required for Brix Android, as we are ++ * calling BUG_ON immediately after collecting the socram dump. ++ * So the file write operation should directly write the contents into the ++ * file instead of caching it. O_TRUNC flag ensures that file will be re-written ++ * instead of appending. ++ */ ++ file_mode = O_CREAT | O_WRONLY | O_SYNC; ++ { ++ struct file *fp = filp_open(memdump_path, file_mode, 0664); ++ /* Check if it is live Brix image having /installmedia, else use /data */ ++ if (IS_ERR(fp)) { ++ DHD_ERROR(("open file %s, try /data/\n", memdump_path)); ++ snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_%ld.%ld", ++ "/data/", fname, memdump_type, ++ (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); ++ } else { ++ filp_close(fp, NULL); ++ } ++ } ++#endif /* CUSTOMER_HW4_DEBUG */ ++ ++ /* print SOCRAM dump file path */ ++ DHD_ERROR(("%s: file_path = %s\n", __FUNCTION__, memdump_path)); ++ ++ /* Write file */ ++ ret = write_file(memdump_path, file_mode, buf, size); ++ ++ return ret; ++} ++#endif /* DHD_DEBUG */ ++ ++int dhd_os_wake_lock_timeout(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? ++ dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; ++#ifdef CONFIG_HAS_WAKELOCK ++ if (dhd->wakelock_rx_timeout_enable) ++ wake_lock_timeout(&dhd->wl_rxwake, ++ msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); ++ if (dhd->wakelock_ctrl_timeout_enable) ++ wake_lock_timeout(&dhd->wl_ctrlwake, ++ msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); ++#endif ++ dhd->wakelock_rx_timeout_enable = 0; ++ dhd->wakelock_ctrl_timeout_enable = 0; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int net_os_wake_lock_timeout(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock_timeout(&dhd->pub); ++ return ret; ++} ++ ++int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ ++ if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (val > dhd->wakelock_rx_timeout_enable) ++ dhd->wakelock_rx_timeout_enable = val; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return 0; ++} ++ ++int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ ++ if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (val > dhd->wakelock_ctrl_timeout_enable) ++ dhd->wakelock_ctrl_timeout_enable = val; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return 0; ++} ++ ++int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ ++ if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ dhd->wakelock_ctrl_timeout_enable = 0; ++#ifdef CONFIG_HAS_WAKELOCK ++ if (wake_lock_active(&dhd->wl_ctrlwake)) ++ wake_unlock(&dhd->wl_ctrlwake); ++#endif ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return 0; ++} ++ ++int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); ++ return ret; ++} ++ ++int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); ++ return ret; ++} ++ ++ ++#if defined(DHD_TRACE_WAKE_LOCK) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) ++#include ++#else ++#include ++#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) ++/* Define 2^5 = 32 bucket size hash table */ ++DEFINE_HASHTABLE(wklock_history, 5); ++#else ++/* Define 2^5 = 32 bucket size hash table */ ++struct hlist_head wklock_history[32] = { [0 ... 31] = HLIST_HEAD_INIT }; ++#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ ++ ++int trace_wklock_onoff = 1; ++typedef enum dhd_wklock_type { ++ DHD_WAKE_LOCK, ++ DHD_WAKE_UNLOCK, ++ DHD_WAIVE_LOCK, ++ DHD_RESTORE_LOCK ++} dhd_wklock_t; ++ ++struct wk_trace_record { ++ unsigned long addr; /* Address of the instruction */ ++ dhd_wklock_t lock_type; /* lock_type */ ++ unsigned long long counter; /* counter information */ ++ struct hlist_node wklock_node; /* hash node */ ++}; ++ ++static struct wk_trace_record *find_wklock_entry(unsigned long addr) ++{ ++ struct wk_trace_record *wklock_info; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) ++ hash_for_each_possible(wklock_history, wklock_info, wklock_node, addr) ++#else ++ struct hlist_node *entry; ++ int index = hash_long(addr, ilog2(ARRAY_SIZE(wklock_history))); ++ hlist_for_each_entry(wklock_info, entry, &wklock_history[index], wklock_node) ++#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ ++ { ++ if (wklock_info->addr == addr) { ++ return wklock_info; ++ } ++ } ++ return NULL; ++} ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) ++#define HASH_ADD(hashtable, node, key) \ ++ do { \ ++ hash_add(hashtable, node, key); \ ++ } while (0); ++#else ++#define HASH_ADD(hashtable, node, key) \ ++ do { \ ++ int index = hash_long(key, ilog2(ARRAY_SIZE(hashtable))); \ ++ hlist_add_head(node, &hashtable[index]); \ ++ } while (0); ++#endif /* KERNEL_VER < KERNEL_VERSION(3, 7, 0) */ ++ ++#define STORE_WKLOCK_RECORD(wklock_type) \ ++ do { \ ++ struct wk_trace_record *wklock_info = NULL; \ ++ unsigned long func_addr = (unsigned long)__builtin_return_address(0); \ ++ wklock_info = find_wklock_entry(func_addr); \ ++ if (wklock_info) { \ ++ if (wklock_type == DHD_WAIVE_LOCK || wklock_type == DHD_RESTORE_LOCK) { \ ++ wklock_info->counter = dhd->wakelock_counter; \ ++ } else { \ ++ wklock_info->counter++; \ ++ } \ ++ } else { \ ++ wklock_info = kzalloc(sizeof(*wklock_info), GFP_ATOMIC); \ ++ if (!wklock_info) {\ ++ printk("Can't allocate wk_trace_record \n"); \ ++ } else { \ ++ wklock_info->addr = func_addr; \ ++ wklock_info->lock_type = wklock_type; \ ++ if (wklock_type == DHD_WAIVE_LOCK || \ ++ wklock_type == DHD_RESTORE_LOCK) { \ ++ wklock_info->counter = dhd->wakelock_counter; \ ++ } else { \ ++ wklock_info->counter++; \ ++ } \ ++ HASH_ADD(wklock_history, &wklock_info->wklock_node, func_addr); \ ++ } \ ++ } \ ++ } while (0); ++ ++static inline void dhd_wk_lock_rec_dump(void) ++{ ++ int bkt; ++ struct wk_trace_record *wklock_info; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) ++ hash_for_each(wklock_history, bkt, wklock_info, wklock_node) ++#else ++ struct hlist_node *entry = NULL; ++ int max_index = ARRAY_SIZE(wklock_history); ++ for (bkt = 0; bkt < max_index; bkt++) ++ hlist_for_each_entry(wklock_info, entry, &wklock_history[bkt], wklock_node) ++#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ ++ { ++ switch (wklock_info->lock_type) { ++ case DHD_WAKE_LOCK: ++ printk("wakelock lock : %pS lock_counter : %llu \n", ++ (void *)wklock_info->addr, wklock_info->counter); ++ break; ++ case DHD_WAKE_UNLOCK: ++ printk("wakelock unlock : %pS, unlock_counter : %llu \n", ++ (void *)wklock_info->addr, wklock_info->counter); ++ break; ++ case DHD_WAIVE_LOCK: ++ printk("wakelock waive : %pS before_waive : %llu \n", ++ (void *)wklock_info->addr, wklock_info->counter); ++ break; ++ case DHD_RESTORE_LOCK: ++ printk("wakelock restore : %pS, after_waive : %llu \n", ++ (void *)wklock_info->addr, wklock_info->counter); ++ break; ++ } ++ } ++} ++ ++static void dhd_wk_lock_trace_init(struct dhd_info *dhd) ++{ ++ unsigned long flags; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) ++ int i; ++#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ ++ ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) ++ hash_init(wklock_history); ++#else ++ for (i = 0; i < ARRAY_SIZE(wklock_history); i++) ++ INIT_HLIST_HEAD(&wklock_history[i]); ++#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++} ++ ++static void dhd_wk_lock_trace_deinit(struct dhd_info *dhd) ++{ ++ int bkt; ++ struct wk_trace_record *wklock_info; ++ struct hlist_node *tmp; ++ unsigned long flags; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) ++ struct hlist_node *entry = NULL; ++ int max_index = ARRAY_SIZE(wklock_history); ++#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ ++ ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) ++ hash_for_each_safe(wklock_history, bkt, tmp, wklock_info, wklock_node) ++#else ++ for (bkt = 0; bkt < max_index; bkt++) ++ hlist_for_each_entry_safe(wklock_info, entry, tmp, ++ &wklock_history[bkt], wklock_node) ++#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0)) */ ++ { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) ++ hash_del(&wklock_info->wklock_node); ++#else ++ hlist_del_init(&wklock_info->wklock_node); ++#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0)) */ ++ kfree(wklock_info); ++ } ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++} ++ ++void dhd_wk_lock_stats_dump(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); ++ unsigned long flags; ++ ++ printk(KERN_ERR"DHD Printing wl_wake Lock/Unlock Record \r\n"); ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ dhd_wk_lock_rec_dump(); ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ ++} ++#else ++#define STORE_WKLOCK_RECORD(wklock_type) ++#endif /* ! DHD_TRACE_WAKE_LOCK */ ++ ++int dhd_os_wake_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { ++#ifdef CONFIG_HAS_WAKELOCK ++ wake_lock(&dhd->wl_wifi); ++#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ dhd_bus_dev_pm_stay_awake(pub); ++#endif ++ } ++#ifdef DHD_TRACE_WAKE_LOCK ++ if (trace_wklock_onoff) { ++ STORE_WKLOCK_RECORD(DHD_WAKE_LOCK); ++ } ++#endif /* DHD_TRACE_WAKE_LOCK */ ++ dhd->wakelock_counter++; ++ ret = dhd->wakelock_counter; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ ++ return ret; ++} ++ ++void dhd_event_wake_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++#ifdef CONFIG_HAS_WAKELOCK ++ wake_lock(&dhd->wl_evtwake); ++#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ dhd_bus_dev_pm_stay_awake(pub); ++#endif ++ } ++} ++ ++void ++dhd_pm_wake_lock_timeout(dhd_pub_t *pub, int val) ++{ ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ wake_lock_timeout(&dhd->wl_pmwake, msecs_to_jiffies(val)); ++ } ++#endif /* CONFIG_HAS_WAKE_LOCK */ ++} ++ ++void ++dhd_txfl_wake_lock_timeout(dhd_pub_t *pub, int val) ++{ ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ wake_lock_timeout(&dhd->wl_txflwake, msecs_to_jiffies(val)); ++ } ++#endif /* CONFIG_HAS_WAKE_LOCK */ ++} ++ ++int net_os_wake_lock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_lock(&dhd->pub); ++ return ret; ++} ++ ++int dhd_os_wake_unlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ dhd_os_wake_lock_timeout(pub); ++ if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ ++ if (dhd->wakelock_counter > 0) { ++ dhd->wakelock_counter--; ++#ifdef DHD_TRACE_WAKE_LOCK ++ if (trace_wklock_onoff) { ++ STORE_WKLOCK_RECORD(DHD_WAKE_UNLOCK); ++ } ++#endif /* DHD_TRACE_WAKE_LOCK */ ++ if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { ++#ifdef CONFIG_HAS_WAKELOCK ++ wake_unlock(&dhd->wl_wifi); ++#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ dhd_bus_dev_pm_relax(pub); ++#endif ++ } ++ ret = dhd->wakelock_counter; ++ } ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++void dhd_event_wake_unlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++#ifdef CONFIG_HAS_WAKELOCK ++ wake_unlock(&dhd->wl_evtwake); ++#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ dhd_bus_dev_pm_relax(pub); ++#endif ++ } ++} ++ ++void dhd_pm_wake_unlock(dhd_pub_t *pub) ++{ ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ /* if wl_pmwake is active, unlock it */ ++ if (wake_lock_active(&dhd->wl_pmwake)) { ++ wake_unlock(&dhd->wl_pmwake); ++ } ++ } ++#endif /* CONFIG_HAS_WAKELOCK */ ++} ++ ++void dhd_txfl_wake_unlock(dhd_pub_t *pub) ++{ ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ /* if wl_txflwake is active, unlock it */ ++ if (wake_lock_active(&dhd->wl_txflwake)) { ++ wake_unlock(&dhd->wl_txflwake); ++ } ++ } ++#endif /* CONFIG_HAS_WAKELOCK */ ++} ++ ++int dhd_os_check_wakelock(dhd_pub_t *pub) ++{ ++#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \ ++ KERNEL_VERSION(2, 6, 36))) ++ dhd_info_t *dhd; ++ ++ if (!pub) ++ return 0; ++ dhd = (dhd_info_t *)(pub->info); ++#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ ++ ++#ifdef CONFIG_HAS_WAKELOCK ++ /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ ++ if (dhd && (wake_lock_active(&dhd->wl_wifi) || ++ (wake_lock_active(&dhd->wl_wdwake)))) ++ return 1; ++#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) ++ return 1; ++#endif ++ return 0; ++} ++ ++int ++dhd_os_check_wakelock_all(dhd_pub_t *pub) ++{ ++#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \ ++ KERNEL_VERSION(2, 6, 36))) ++#if defined(CONFIG_HAS_WAKELOCK) ++ int l1, l2, l3, l4, l7, l8, l9; ++ int l5 = 0, l6 = 0; ++ int c, lock_active; ++#endif /* CONFIG_HAS_WAKELOCK */ ++ dhd_info_t *dhd; ++ ++ if (!pub) { ++ return 0; ++ } ++ dhd = (dhd_info_t *)(pub->info); ++ if (!dhd) { ++ return 0; ++ } ++#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ ++ ++#ifdef CONFIG_HAS_WAKELOCK ++ c = dhd->wakelock_counter; ++ l1 = wake_lock_active(&dhd->wl_wifi); ++ l2 = wake_lock_active(&dhd->wl_wdwake); ++ l3 = wake_lock_active(&dhd->wl_rxwake); ++ l4 = wake_lock_active(&dhd->wl_ctrlwake); ++ l7 = wake_lock_active(&dhd->wl_evtwake); ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ l5 = wake_lock_active(&dhd->wl_intrwake); ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++#ifdef DHD_USE_SCAN_WAKELOCK ++ l6 = wake_lock_active(&dhd->wl_scanwake); ++#endif /* DHD_USE_SCAN_WAKELOCK */ ++ l8 = wake_lock_active(&dhd->wl_pmwake); ++ l9 = wake_lock_active(&dhd->wl_txflwake); ++ lock_active = (l1 || l2 || l3 || l4 || l5 || l6 || l7 || l8 || l9); ++ ++ /* Indicate to the Host to avoid going to suspend if internal locks are up */ ++ if (lock_active) { ++ DHD_ERROR(("%s wakelock c-%d wl-%d wd-%d rx-%d " ++ "ctl-%d intr-%d scan-%d evt-%d, pm-%d, txfl-%d\n", ++ __FUNCTION__, c, l1, l2, l3, l4, l5, l6, l7, l8, l9)); ++ return 1; ++ } ++#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) { ++ return 1; ++ } ++#endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ ++ return 0; ++} ++ ++int net_os_wake_unlock(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ int ret = 0; ++ ++ if (dhd) ++ ret = dhd_os_wake_unlock(&dhd->pub); ++ return ret; ++} ++ ++int dhd_os_wd_wake_lock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++#ifdef CONFIG_HAS_WAKELOCK ++ /* if wakelock_wd_counter was never used : lock it at once */ ++ if (!dhd->wakelock_wd_counter) ++ wake_lock(&dhd->wl_wdwake); ++#endif ++ dhd->wakelock_wd_counter++; ++ ret = dhd->wakelock_wd_counter; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int dhd_os_wd_wake_unlock(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ if (dhd->wakelock_wd_counter) { ++ dhd->wakelock_wd_counter = 0; ++#ifdef CONFIG_HAS_WAKELOCK ++ wake_unlock(&dhd->wl_wdwake); ++#endif ++ } ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++#ifdef BCMPCIE_OOB_HOST_WAKE ++void ++dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val) ++{ ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ wake_lock_timeout(&dhd->wl_intrwake, msecs_to_jiffies(val)); ++ } ++#endif /* CONFIG_HAS_WAKELOCK */ ++} ++ ++void ++dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub) ++{ ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ /* if wl_intrwake is active, unlock it */ ++ if (wake_lock_active(&dhd->wl_intrwake)) { ++ wake_unlock(&dhd->wl_intrwake); ++ } ++ } ++#endif /* CONFIG_HAS_WAKELOCK */ ++} ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ ++#ifdef DHD_USE_SCAN_WAKELOCK ++void ++dhd_os_scan_wake_lock_timeout(dhd_pub_t *pub, int val) ++{ ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ wake_lock_timeout(&dhd->wl_scanwake, msecs_to_jiffies(val)); ++ } ++#endif /* CONFIG_HAS_WAKELOCK */ ++} ++ ++void ++dhd_os_scan_wake_unlock(dhd_pub_t *pub) ++{ ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ ++ if (dhd) { ++ /* if wl_scanwake is active, unlock it */ ++ if (wake_lock_active(&dhd->wl_scanwake)) { ++ wake_unlock(&dhd->wl_scanwake); ++ } ++ } ++#endif /* CONFIG_HAS_WAKELOCK */ ++} ++#endif /* DHD_USE_SCAN_WAKELOCK */ ++ ++/* waive wakelocks for operations such as IOVARs in suspend function, must be closed ++ * by a paired function call to dhd_wakelock_restore. returns current wakelock counter ++ */ ++int dhd_os_wake_lock_waive(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ ++ /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ ++ if (dhd->waive_wakelock == FALSE) { ++#ifdef DHD_TRACE_WAKE_LOCK ++ if (trace_wklock_onoff) { ++ STORE_WKLOCK_RECORD(DHD_WAIVE_LOCK); ++ } ++#endif /* DHD_TRACE_WAKE_LOCK */ ++ /* record current lock status */ ++ dhd->wakelock_before_waive = dhd->wakelock_counter; ++ dhd->waive_wakelock = TRUE; ++ } ++ ret = dhd->wakelock_wd_counter; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ } ++ return ret; ++} ++ ++int dhd_os_wake_lock_restore(dhd_pub_t *pub) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(pub->info); ++ unsigned long flags; ++ int ret = 0; ++ ++ if (!dhd) ++ return 0; ++ if ((dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) == 0) ++ return 0; ++ ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ ++ /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ ++ if (!dhd->waive_wakelock) ++ goto exit; ++ ++ dhd->waive_wakelock = FALSE; ++ /* if somebody else acquires wakelock between dhd_wakelock_waive/dhd_wakelock_restore, ++ * we need to make it up by calling wake_lock or pm_stay_awake. or if somebody releases ++ * the lock in between, do the same by calling wake_unlock or pm_relax ++ */ ++#ifdef DHD_TRACE_WAKE_LOCK ++ if (trace_wklock_onoff) { ++ STORE_WKLOCK_RECORD(DHD_RESTORE_LOCK); ++ } ++#endif /* DHD_TRACE_WAKE_LOCK */ ++ ++ if (dhd->wakelock_before_waive == 0 && dhd->wakelock_counter > 0) { ++#ifdef CONFIG_HAS_WAKELOCK ++ wake_lock(&dhd->wl_wifi); ++#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ dhd_bus_dev_pm_stay_awake(&dhd->pub); ++#endif ++ } else if (dhd->wakelock_before_waive > 0 && dhd->wakelock_counter == 0) { ++#ifdef CONFIG_HAS_WAKELOCK ++ wake_unlock(&dhd->wl_wifi); ++#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) ++ dhd_bus_dev_pm_relax(&dhd->pub); ++#endif ++ } ++ dhd->wakelock_before_waive = 0; ++exit: ++ ret = dhd->wakelock_wd_counter; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ return ret; ++} ++ ++void dhd_os_wake_lock_init(struct dhd_info *dhd) ++{ ++ DHD_TRACE(("%s: initialize wake_lock_counters\n", __FUNCTION__)); ++ dhd->wakelock_counter = 0; ++ dhd->wakelock_rx_timeout_enable = 0; ++ dhd->wakelock_ctrl_timeout_enable = 0; ++#ifdef CONFIG_HAS_WAKELOCK ++ // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry ++ wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); ++ wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); ++ wake_lock_init(&dhd->wl_evtwake, WAKE_LOCK_SUSPEND, "wlan_evt_wake"); ++ wake_lock_init(&dhd->wl_pmwake, WAKE_LOCK_SUSPEND, "wlan_pm_wake"); ++ wake_lock_init(&dhd->wl_txflwake, WAKE_LOCK_SUSPEND, "wlan_txfl_wake"); ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ wake_lock_init(&dhd->wl_intrwake, WAKE_LOCK_SUSPEND, "wlan_oob_irq_wake"); ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++#ifdef DHD_USE_SCAN_WAKELOCK ++ wake_lock_init(&dhd->wl_scanwake, WAKE_LOCK_SUSPEND, "wlan_scan_wake"); ++#endif /* DHD_USE_SCAN_WAKELOCK */ ++#endif /* CONFIG_HAS_WAKELOCK */ ++#ifdef DHD_TRACE_WAKE_LOCK ++ dhd_wk_lock_trace_init(dhd); ++#endif /* DHD_TRACE_WAKE_LOCK */ ++} ++ ++void dhd_os_wake_lock_destroy(struct dhd_info *dhd) ++{ ++ DHD_TRACE(("%s: deinit wake_lock_counters\n", __FUNCTION__)); ++#ifdef CONFIG_HAS_WAKELOCK ++ dhd->wakelock_counter = 0; ++ dhd->wakelock_rx_timeout_enable = 0; ++ dhd->wakelock_ctrl_timeout_enable = 0; ++ // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry ++ wake_lock_destroy(&dhd->wl_rxwake); ++ wake_lock_destroy(&dhd->wl_ctrlwake); ++ wake_lock_destroy(&dhd->wl_evtwake); ++ wake_lock_destroy(&dhd->wl_pmwake); ++ wake_lock_destroy(&dhd->wl_txflwake); ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ wake_lock_destroy(&dhd->wl_intrwake); ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++#ifdef DHD_USE_SCAN_WAKELOCK ++ wake_lock_destroy(&dhd->wl_scanwake); ++#endif /* DHD_USE_SCAN_WAKELOCK */ ++#ifdef DHD_TRACE_WAKE_LOCK ++ dhd_wk_lock_trace_deinit(dhd); ++#endif /* DHD_TRACE_WAKE_LOCK */ ++#endif /* CONFIG_HAS_WAKELOCK */ ++} ++ ++bool dhd_os_check_if_up(dhd_pub_t *pub) ++{ ++ if (!pub) ++ return FALSE; ++ return pub->up; ++} ++ ++/* function to collect firmware, chip id and chip version info */ ++void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) ++{ ++ int i; ++ ++ i = snprintf(info_string, sizeof(info_string), ++ " Driver: %s\n Firmware: %s\n CLM: %s ", EPI_VERSION_STR, fw, clm_version); ++ printf("%s\n", info_string); ++ ++ if (!dhdp) ++ return; ++ ++ i = snprintf(&info_string[i], sizeof(info_string) - i, ++ "\n Chip: %x Rev %x", dhd_conf_get_chip(dhdp), ++ dhd_conf_get_chiprev(dhdp)); ++} ++ ++int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) ++{ ++ int ifidx; ++ int ret = 0; ++ dhd_info_t *dhd = NULL; ++ ++ if (!net || !DEV_PRIV(net)) { ++ DHD_ERROR(("%s invalid parameter\n", __FUNCTION__)); ++ return -EINVAL; ++ } ++ ++ dhd = DHD_DEV_INFO(net); ++ if (!dhd) ++ return -EINVAL; ++ ++ ifidx = dhd_net2idx(dhd, net); ++ if (ifidx == DHD_BAD_IF) { ++ DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++ DHD_OS_WAKE_LOCK(&dhd->pub); ++ DHD_PERIM_LOCK(&dhd->pub); ++ ++ ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); ++ dhd_check_hang(net, &dhd->pub, ret); ++ ++ DHD_PERIM_UNLOCK(&dhd->pub); ++ DHD_OS_WAKE_UNLOCK(&dhd->pub); ++ ++ return ret; ++} ++ ++bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) ++{ ++ struct net_device *net; ++ ++ net = dhd_idx2net(dhdp, ifidx); ++ if (!net) { ++ DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx)); ++ return -EINVAL; ++ } ++ ++ return dhd_check_hang(net, dhdp, ret); ++} ++ ++/* Return instance */ ++int dhd_get_instance(dhd_pub_t *dhdp) ++{ ++ return dhdp->info->unit; ++} ++ ++ ++#ifdef PROP_TXSTATUS ++ ++void dhd_wlfc_plat_init(void *dhd) ++{ ++#ifdef USE_DYNAMIC_F2_BLKSIZE ++ dhdsdio_func_blocksize((dhd_pub_t *)dhd, 2, DYNAMIC_F2_BLKSIZE_FOR_NONLEGACY); ++#endif /* USE_DYNAMIC_F2_BLKSIZE */ ++ return; ++} ++ ++void dhd_wlfc_plat_deinit(void *dhd) ++{ ++#ifdef USE_DYNAMIC_F2_BLKSIZE ++ dhdsdio_func_blocksize((dhd_pub_t *)dhd, 2, sd_f2_blocksize); ++#endif /* USE_DYNAMIC_F2_BLKSIZE */ ++ return; ++} ++ ++bool dhd_wlfc_skip_fc(void * dhdp, uint8 idx) ++{ ++#ifdef SKIP_WLFC_ON_CONCURRENT ++ ++#ifdef WL_CFG80211 ++ struct net_device * net = dhd_idx2net((dhd_pub_t *)dhdp, idx); ++ if (net) ++ /* enable flow control in vsdb mode */ ++ return !(wl_cfg80211_is_concurrent_mode(net)); ++#else ++ return TRUE; /* skip flow control */ ++#endif /* WL_CFG80211 */ ++ ++#else ++ return FALSE; ++#endif /* SKIP_WLFC_ON_CONCURRENT */ ++ return FALSE; ++} ++#endif /* PROP_TXSTATUS */ ++ ++#ifdef BCMDBGFS ++#include ++ ++typedef struct dhd_dbgfs { ++ struct dentry *debugfs_dir; ++ struct dentry *debugfs_mem; ++ dhd_pub_t *dhdp; ++ uint32 size; ++} dhd_dbgfs_t; ++ ++dhd_dbgfs_t g_dbgfs; ++ ++extern uint32 dhd_readregl(void *bp, uint32 addr); ++extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); ++ ++static int ++dhd_dbg_state_open(struct inode *inode, struct file *file) ++{ ++ file->private_data = inode->i_private; ++ return 0; ++} ++ ++static ssize_t ++dhd_dbg_state_read(struct file *file, char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t rval; ++ uint32 tmp; ++ loff_t pos = *ppos; ++ size_t ret; ++ ++ if (pos < 0) ++ return -EINVAL; ++ if (pos >= g_dbgfs.size || !count) ++ return 0; ++ if (count > g_dbgfs.size - pos) ++ count = g_dbgfs.size - pos; ++ ++ /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ ++ tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); ++ ++ ret = copy_to_user(ubuf, &tmp, 4); ++ if (ret == count) ++ return -EFAULT; ++ ++ count -= ret; ++ *ppos = pos + count; ++ rval = count; ++ ++ return rval; ++} ++ ++ ++static ssize_t ++dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) ++{ ++ loff_t pos = *ppos; ++ size_t ret; ++ uint32 buf; ++ ++ if (pos < 0) ++ return -EINVAL; ++ if (pos >= g_dbgfs.size || !count) ++ return 0; ++ if (count > g_dbgfs.size - pos) ++ count = g_dbgfs.size - pos; ++ ++ ret = copy_from_user(&buf, ubuf, sizeof(uint32)); ++ if (ret == count) ++ return -EFAULT; ++ ++ /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ ++ dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); ++ ++ return count; ++} ++ ++ ++loff_t ++dhd_debugfs_lseek(struct file *file, loff_t off, int whence) ++{ ++ loff_t pos = -1; ++ ++ switch (whence) { ++ case 0: ++ pos = off; ++ break; ++ case 1: ++ pos = file->f_pos + off; ++ break; ++ case 2: ++ pos = g_dbgfs.size - off; ++ } ++ return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); ++} ++ ++static const struct file_operations dhd_dbg_state_ops = { ++ .read = dhd_dbg_state_read, ++ .write = dhd_debugfs_write, ++ .open = dhd_dbg_state_open, ++ .llseek = dhd_debugfs_lseek ++}; ++ ++static void dhd_dbgfs_create(void) ++{ ++ if (g_dbgfs.debugfs_dir) { ++ g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, ++ NULL, &dhd_dbg_state_ops); ++ } ++} ++ ++void dhd_dbgfs_init(dhd_pub_t *dhdp) ++{ ++ g_dbgfs.dhdp = dhdp; ++ g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ ++ ++ g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); ++ if (IS_ERR(g_dbgfs.debugfs_dir)) { ++ g_dbgfs.debugfs_dir = NULL; ++ return; ++ } ++ ++ dhd_dbgfs_create(); ++ ++ return; ++} ++ ++void dhd_dbgfs_remove(void) ++{ ++ debugfs_remove(g_dbgfs.debugfs_mem); ++ debugfs_remove(g_dbgfs.debugfs_dir); ++ ++ bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); ++} ++#endif /* BCMDBGFS */ ++ ++#ifdef WLMEDIA_HTSF ++ ++static ++void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); ++ struct sk_buff *skb; ++ uint32 htsf = 0; ++ uint16 dport = 0, oldmagic = 0xACAC; ++ char *p1; ++ htsfts_t ts; ++ ++ /* timestamp packet */ ++ ++ p1 = (char*) PKTDATA(dhdp->osh, pktbuf); ++ ++ if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { ++/* memcpy(&proto, p1+26, 4); */ ++ memcpy(&dport, p1+40, 2); ++/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ ++ dport = ntoh16(dport); ++ } ++ ++ /* timestamp only if icmp or udb iperf with port 5555 */ ++/* if (proto == 17 && dport == tsport) { */ ++ if (dport >= tsport && dport <= tsport + 20) { ++ ++ skb = (struct sk_buff *) pktbuf; ++ ++ htsf = dhd_get_htsf(dhd, 0); ++ memset(skb->data + 44, 0, 2); /* clear checksum */ ++ memcpy(skb->data+82, &oldmagic, 2); ++ memcpy(skb->data+84, &htsf, 4); ++ ++ memset(&ts, 0, sizeof(htsfts_t)); ++ ts.magic = HTSFMAGIC; ++ ts.prio = PKTPRIO(pktbuf); ++ ts.seqnum = htsf_seqnum++; ++ ts.c10 = get_cycles(); ++ ts.t10 = htsf; ++ ts.endmagic = HTSFENDMAGIC; ++ ++ memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); ++ } ++} ++ ++static void dhd_dump_htsfhisto(histo_t *his, char *s) ++{ ++ int pktcnt = 0, curval = 0, i; ++ for (i = 0; i < (NUMBIN-2); i++) { ++ curval += 500; ++ printf("%d ", his->bin[i]); ++ pktcnt += his->bin[i]; ++ } ++ printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, ++ his->bin[NUMBIN-1], s); ++} ++ ++static ++void sorttobin(int value, histo_t *histo) ++{ ++ int i, binval = 0; ++ ++ if (value < 0) { ++ histo->bin[NUMBIN-1]++; ++ return; ++ } ++ if (value > histo->bin[NUMBIN-2]) /* store the max value */ ++ histo->bin[NUMBIN-2] = value; ++ ++ for (i = 0; i < (NUMBIN-2); i++) { ++ binval += 500; /* 500m s bins */ ++ if (value <= binval) { ++ histo->bin[i]++; ++ return; ++ } ++ } ++ histo->bin[NUMBIN-3]++; ++} ++ ++static ++void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)dhdp->info; ++ struct sk_buff *skb; ++ char *p1; ++ uint16 old_magic; ++ int d1, d2, d3, end2end; ++ htsfts_t *htsf_ts; ++ uint32 htsf; ++ ++ skb = PKTTONATIVE(dhdp->osh, pktbuf); ++ p1 = (char*)PKTDATA(dhdp->osh, pktbuf); ++ ++ if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { ++ memcpy(&old_magic, p1+78, 2); ++ htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); ++ } else { ++ return; ++ } ++ ++ if (htsf_ts->magic == HTSFMAGIC) { ++ htsf_ts->tE0 = dhd_get_htsf(dhd, 0); ++ htsf_ts->cE0 = get_cycles(); ++ } ++ ++ if (old_magic == 0xACAC) { ++ ++ tspktcnt++; ++ htsf = dhd_get_htsf(dhd, 0); ++ memcpy(skb->data+92, &htsf, sizeof(uint32)); ++ ++ memcpy(&ts[tsidx].t1, skb->data+80, 16); ++ ++ d1 = ts[tsidx].t2 - ts[tsidx].t1; ++ d2 = ts[tsidx].t3 - ts[tsidx].t2; ++ d3 = ts[tsidx].t4 - ts[tsidx].t3; ++ end2end = ts[tsidx].t4 - ts[tsidx].t1; ++ ++ sorttobin(d1, &vi_d1); ++ sorttobin(d2, &vi_d2); ++ sorttobin(d3, &vi_d3); ++ sorttobin(end2end, &vi_d4); ++ ++ if (end2end > 0 && end2end > maxdelay) { ++ maxdelay = end2end; ++ maxdelaypktno = tspktcnt; ++ memcpy(&maxdelayts, &ts[tsidx], 16); ++ } ++ if (++tsidx >= TSMAX) ++ tsidx = 0; ++ } ++} ++ ++uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) ++{ ++ uint32 htsf = 0, cur_cycle, delta, delta_us; ++ uint32 factor, baseval, baseval2; ++ cycles_t t; ++ ++ t = get_cycles(); ++ cur_cycle = t; ++ ++ if (cur_cycle > dhd->htsf.last_cycle) ++ delta = cur_cycle - dhd->htsf.last_cycle; ++ else { ++ delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); ++ } ++ ++ delta = delta >> 4; ++ ++ if (dhd->htsf.coef) { ++ /* times ten to get the first digit */ ++ factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); ++ baseval = (delta*10)/factor; ++ baseval2 = (delta*10)/(factor+1); ++ delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); ++ htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; ++ } else { ++ DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n")); ++ } ++ ++ return htsf; ++} ++ ++static void dhd_dump_latency(void) ++{ ++ int i, max = 0; ++ int d1, d2, d3, d4, d5; ++ ++ printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n"); ++ for (i = 0; i < TSMAX; i++) { ++ d1 = ts[i].t2 - ts[i].t1; ++ d2 = ts[i].t3 - ts[i].t2; ++ d3 = ts[i].t4 - ts[i].t3; ++ d4 = ts[i].t4 - ts[i].t1; ++ d5 = ts[max].t4-ts[max].t1; ++ if (d4 > d5 && d4 > 0) { ++ max = i; ++ } ++ printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", ++ ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, ++ d1, d2, d3, d4, i); ++ } ++ ++ printf("current idx = %d \n", tsidx); ++ ++ printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt); ++ printf("%08X %08X %08X %08X \t%d %d %d %d\n", ++ maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, ++ maxdelayts.t2 - maxdelayts.t1, ++ maxdelayts.t3 - maxdelayts.t2, ++ maxdelayts.t4 - maxdelayts.t3, ++ maxdelayts.t4 - maxdelayts.t1); ++} ++ ++ ++static int ++dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) ++{ ++ char buf[32]; ++ int ret; ++ uint32 s1, s2; ++ ++ struct tsf { ++ uint32 low; ++ uint32 high; ++ } tsf_buf; ++ ++ memset(&tsf_buf, 0, sizeof(tsf_buf)); ++ ++ s1 = dhd_get_htsf(dhd, 0); ++ ret = dhd_iovar(&dhd->pub, ifidx, "tsf", NULL, 0, buf, sizeof(buf), FALSE); ++ if (ret < 0) { ++ if (ret == -EIO) { ++ DHD_ERROR(("%s: tsf is not supported by device\n", ++ dhd_ifname(&dhd->pub, ifidx))); ++ return -EOPNOTSUPP; ++ } ++ return ret; ++ } ++ s2 = dhd_get_htsf(dhd, 0); ++ ++ memcpy(&tsf_buf, buf, sizeof(tsf_buf)); ++ printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", ++ tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, ++ dhd->htsf.coefdec2, s2-tsf_buf.low); ++ printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle); ++ return 0; ++} ++ ++void htsf_update(dhd_info_t *dhd, void *data) ++{ ++ static ulong cur_cycle = 0, prev_cycle = 0; ++ uint32 htsf, tsf_delta = 0; ++ uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; ++ ulong b, a; ++ cycles_t t; ++ ++ /* cycles_t in inlcude/mips/timex.h */ ++ ++ t = get_cycles(); ++ ++ prev_cycle = cur_cycle; ++ cur_cycle = t; ++ ++ if (cur_cycle > prev_cycle) ++ cyc_delta = cur_cycle - prev_cycle; ++ else { ++ b = cur_cycle; ++ a = prev_cycle; ++ cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); ++ } ++ ++ if (data == NULL) ++ printf(" tsf update ata point er is null \n"); ++ ++ memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); ++ memcpy(&cur_tsf, data, sizeof(tsf_t)); ++ ++ if (cur_tsf.low == 0) { ++ DHD_INFO((" ---- 0 TSF, do not update, return\n")); ++ return; ++ } ++ ++ if (cur_tsf.low > prev_tsf.low) ++ tsf_delta = (cur_tsf.low - prev_tsf.low); ++ else { ++ DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", ++ cur_tsf.low, prev_tsf.low)); ++ if (cur_tsf.high > prev_tsf.high) { ++ tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); ++ DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta)); ++ } else { ++ return; /* do not update */ ++ } ++ } ++ ++ if (tsf_delta) { ++ hfactor = cyc_delta / tsf_delta; ++ tmp = (cyc_delta - (hfactor * tsf_delta))*10; ++ dec1 = tmp/tsf_delta; ++ dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; ++ tmp = (tmp - (dec1*tsf_delta))*10; ++ dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; ++ ++ if (dec3 > 4) { ++ if (dec2 == 9) { ++ dec2 = 0; ++ if (dec1 == 9) { ++ dec1 = 0; ++ hfactor++; ++ } else { ++ dec1++; ++ } ++ } else { ++ dec2++; ++ } ++ } ++ } ++ ++ if (hfactor) { ++ htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; ++ dhd->htsf.coef = hfactor; ++ dhd->htsf.last_cycle = cur_cycle; ++ dhd->htsf.last_tsf = cur_tsf.low; ++ dhd->htsf.coefdec1 = dec1; ++ dhd->htsf.coefdec2 = dec2; ++ } else { ++ htsf = prev_tsf.low; ++ } ++} ++ ++#endif /* WLMEDIA_HTSF */ ++ ++#ifdef CUSTOM_SET_CPUCORE ++void dhd_set_cpucore(dhd_pub_t *dhd, int set) ++{ ++ int e_dpc = 0, e_rxf = 0, retry_set = 0; ++ ++ if (!(dhd->chan_isvht80)) { ++ DHD_ERROR(("%s: chan_status(%d) cpucore!!!\n", __FUNCTION__, dhd->chan_isvht80)); ++ return; ++ } ++ ++ if (DPC_CPUCORE) { ++ do { ++ if (set == TRUE) { ++ e_dpc = set_cpus_allowed_ptr(dhd->current_dpc, ++ cpumask_of(DPC_CPUCORE)); ++ } else { ++ e_dpc = set_cpus_allowed_ptr(dhd->current_dpc, ++ cpumask_of(PRIMARY_CPUCORE)); ++ } ++ if (retry_set++ > MAX_RETRY_SET_CPUCORE) { ++ DHD_ERROR(("%s: dpc(%d) invalid cpu!\n", __FUNCTION__, e_dpc)); ++ return; ++ } ++ if (e_dpc < 0) ++ OSL_SLEEP(1); ++ } while (e_dpc < 0); ++ } ++ if (RXF_CPUCORE) { ++ do { ++ if (set == TRUE) { ++ e_rxf = set_cpus_allowed_ptr(dhd->current_rxf, ++ cpumask_of(RXF_CPUCORE)); ++ } else { ++ e_rxf = set_cpus_allowed_ptr(dhd->current_rxf, ++ cpumask_of(PRIMARY_CPUCORE)); ++ } ++ if (retry_set++ > MAX_RETRY_SET_CPUCORE) { ++ DHD_ERROR(("%s: rxf(%d) invalid cpu!\n", __FUNCTION__, e_rxf)); ++ return; ++ } ++ if (e_rxf < 0) ++ OSL_SLEEP(1); ++ } while (e_rxf < 0); ++ } ++#ifdef DHD_OF_SUPPORT ++ interrupt_set_cpucore(set, DPC_CPUCORE, PRIMARY_CPUCORE); ++#endif /* DHD_OF_SUPPORT */ ++ DHD_TRACE(("%s: set(%d) cpucore success!\n", __FUNCTION__, set)); ++ ++ return; ++} ++#endif /* CUSTOM_SET_CPUCORE */ ++ ++#ifdef DHD_MCAST_REGEN ++/* Get interface specific ap_isolate configuration */ ++int dhd_get_mcast_regen_bss_enable(dhd_pub_t *dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ return ifp->mcast_regen_bss_enable; ++} ++ ++/* Set interface specific mcast_regen configuration */ ++int dhd_set_mcast_regen_bss_enable(dhd_pub_t *dhdp, uint32 idx, int val) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ ifp->mcast_regen_bss_enable = val; ++ ++ /* Disable rx_pkt_chain feature for interface, if mcast_regen feature ++ * is enabled ++ */ ++ dhd_update_rx_pkt_chainable_state(dhdp, idx); ++ return BCME_OK; ++} ++#endif /* DHD_MCAST_REGEN */ ++ ++/* Get interface specific ap_isolate configuration */ ++int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ return ifp->ap_isolate; ++} ++ ++/* Set interface specific ap_isolate configuration */ ++int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ if (ifp) ++ ifp->ap_isolate = val; ++ ++ return 0; ++} ++ ++#ifdef DHD_FW_COREDUMP ++#if defined(CONFIG_X86) ++#define MEMDUMPINFO_LIVE "/installmedia/.memdump.info" ++#define MEMDUMPINFO_INST "/data/.memdump.info" ++#endif /* CONFIG_X86 && OEM_ANDROID */ ++ ++#ifdef CUSTOMER_HW4_DEBUG ++#define MEMDUMPINFO PLATFORM_PATH".memdump.info" ++#elif defined(CUSTOMER_HW2) ++#define MEMDUMPINFO "/data/misc/wifi/.memdump.info" ++#elif (defined(BOARD_PANDA) || defined(__ARM_ARCH_7A__)) ++#define MEMDUMPINFO "/data/misc/wifi/.memdump.info" ++#else ++#define MEMDUMPINFO "/data/misc/wifi/.memdump.info" ++#endif /* CUSTOMER_HW4_DEBUG */ ++ ++void dhd_get_memdump_info(dhd_pub_t *dhd) ++{ ++ struct file *fp = NULL; ++ uint32 mem_val = DUMP_MEMFILE_MAX; ++ int ret = 0; ++ char *filepath = MEMDUMPINFO; ++ ++ /* Read memdump info from the file */ ++ fp = filp_open(filepath, O_RDONLY, 0); ++ if (IS_ERR(fp)) { ++ DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); ++#if defined(CONFIG_X86) ++ /* Check if it is Live Brix Image */ ++ if (strcmp(filepath, MEMDUMPINFO_LIVE) != 0) { ++ goto done; ++ } ++ /* Try if it is Installed Brix Image */ ++ filepath = MEMDUMPINFO_INST; ++ DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath)); ++ fp = filp_open(filepath, O_RDONLY, 0); ++ if (IS_ERR(fp)) { ++ DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); ++ goto done; ++ } ++#else /* Non Brix Android platform */ ++ goto done; ++#endif /* CONFIG_X86 && OEM_ANDROID */ ++ } ++ ++ /* Handle success case */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ ret = kernel_read(fp, (char *)&mem_val, 4, NULL); ++#else ++ ret = kernel_read(fp, 0, (char *)&mem_val, 4); ++#endif ++ if (ret < 0) { ++ DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret)); ++ filp_close(fp, NULL); ++ goto done; ++ } ++ ++ mem_val = bcm_atoi((char *)&mem_val); ++ ++ filp_close(fp, NULL); ++ ++#ifdef DHD_INIT_DEFAULT_MEMDUMP ++ if (mem_val == 0 || mem_val == DUMP_MEMFILE_MAX) ++ mem_val = DUMP_MEMFILE_BUGON; ++#endif /* DHD_INIT_DEFAULT_MEMDUMP */ ++ ++done: ++#ifdef CUSTOMER_HW4_DEBUG ++ dhd->memdump_enabled = (mem_val < DUMP_MEMFILE_MAX) ? mem_val : DUMP_DISABLED; ++#else ++ dhd->memdump_enabled = (mem_val < DUMP_MEMFILE_MAX) ? mem_val : DUMP_MEMFILE; ++#endif /* CUSTOMER_HW4_DEBUG */ ++ ++ DHD_ERROR(("%s: MEMDUMP ENABLED = %d\n", __FUNCTION__, dhd->memdump_enabled)); ++} ++ ++void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size) ++{ ++ dhd_dump_t *dump = NULL; ++ dump = (dhd_dump_t *)MALLOC(dhdp->osh, sizeof(dhd_dump_t)); ++ if (dump == NULL) { ++ DHD_ERROR(("%s: dhd dump memory allocation failed\n", __FUNCTION__)); ++ return; ++ } ++ dump->buf = buf; ++ dump->bufsize = size; ++ ++#if defined(CONFIG_ARM64) ++ DHD_ERROR(("%s: buf(va)=%llx, buf(pa)=%llx, bufsize=%d\n", __FUNCTION__, ++ (uint64)buf, (uint64)__virt_to_phys((ulong)buf), size)); ++#elif defined(__ARM_ARCH_7A__) ++ DHD_ERROR(("%s: buf(va)=%x, buf(pa)=%x, bufsize=%d\n", __FUNCTION__, ++ (uint32)buf, (uint32)__virt_to_phys((ulong)buf), size)); ++#endif /* __ARM_ARCH_7A__ */ ++ if (dhdp->memdump_enabled == DUMP_MEMONLY) { ++ BUG_ON(1); ++ } ++ ++#ifdef DHD_LOG_DUMP ++ if (dhdp->memdump_type != DUMP_TYPE_BY_SYSDUMP) { ++ dhd_schedule_log_dump(dhdp); ++ } ++#endif /* DHD_LOG_DUMP */ ++ dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dump, ++ DHD_WQ_WORK_SOC_RAM_DUMP, dhd_mem_dump, DHD_WQ_WORK_PRIORITY_HIGH); ++} ++ ++static void ++dhd_mem_dump(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ dhd_dump_t *dump = event_info; ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!dump) { ++ DHD_ERROR(("%s: dump is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (write_dump_to_file(&dhd->pub, dump->buf, dump->bufsize, "mem_dump")) { ++ DHD_ERROR(("%s: writing SoC_RAM dump to the file failed\n", __FUNCTION__)); ++ dhd->pub.memdump_success = FALSE; ++ } ++ ++ if (dhd->pub.memdump_enabled == DUMP_MEMFILE_BUGON && ++#ifdef DHD_LOG_DUMP ++ dhd->pub.memdump_type != DUMP_TYPE_BY_SYSDUMP && ++#endif /* DHD_LOG_DUMP */ ++#ifdef DHD_DEBUG_UART ++ dhd->pub.memdump_success == TRUE && ++#endif /* DHD_DEBUG_UART */ ++ dhd->pub.memdump_type != DUMP_TYPE_CFG_VENDOR_TRIGGERED) { ++ ++#ifdef SHOW_LOGTRACE ++ /* Wait till event_log_dispatcher_work finishes */ ++ cancel_work_sync(&dhd->event_log_dispatcher_work); ++#endif /* SHOW_LOGTRACE */ ++ ++ BUG_ON(1); ++ } ++ MFREE(dhd->pub.osh, dump, sizeof(dhd_dump_t)); ++} ++#endif /* DHD_FW_COREDUMP */ ++ ++#ifdef DHD_SSSR_DUMP ++ ++static void ++dhd_sssr_dump(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ dhd_pub_t *dhdp; ++ int i; ++ char before_sr_dump[128]; ++ char after_sr_dump[128]; ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ dhdp = &dhd->pub; ++ ++ for (i = 0; i < MAX_NUM_D11CORES; i++) { ++ /* Init file name */ ++ memset(before_sr_dump, 0, sizeof(before_sr_dump)); ++ memset(after_sr_dump, 0, sizeof(after_sr_dump)); ++ ++ snprintf(before_sr_dump, sizeof(before_sr_dump), "%s_%d_%s", ++ "sssr_core", i, "before_SR"); ++ snprintf(after_sr_dump, sizeof(after_sr_dump), "%s_%d_%s", ++ "sssr_core", i, "after_SR"); ++ ++ if (dhdp->sssr_d11_before[i] && dhdp->sssr_d11_outofreset[i]) { ++ if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_d11_before[i], ++ dhdp->sssr_reg_info.mac_regs[i].sr_size, before_sr_dump)) { ++ DHD_ERROR(("%s: writing SSSR MAIN dump before to the file failed\n", ++ __FUNCTION__)); ++ } ++ } ++ if (dhdp->sssr_d11_after[i] && dhdp->sssr_d11_outofreset[i]) { ++ if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_d11_after[i], ++ dhdp->sssr_reg_info.mac_regs[i].sr_size, after_sr_dump)) { ++ DHD_ERROR(("%s: writing SSSR AUX dump after to the file failed\n", ++ __FUNCTION__)); ++ } ++ } ++ } ++ ++ if (dhdp->sssr_vasip_buf_before) { ++ if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_vasip_buf_before, ++ dhdp->sssr_reg_info.vasip_regs.vasip_sr_size, "sssr_vasip_before_SR")) { ++ DHD_ERROR(("%s: writing SSSR VASIP dump before to the file failed\n", ++ __FUNCTION__)); ++ } ++ } ++ ++ if (dhdp->sssr_vasip_buf_after) { ++ if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_vasip_buf_after, ++ dhdp->sssr_reg_info.vasip_regs.vasip_sr_size, "sssr_vasip_after_SR")) { ++ DHD_ERROR(("%s: writing SSSR VASIP dump after to the file failed\n", ++ __FUNCTION__)); ++ } ++ } ++ ++} ++ ++void ++dhd_schedule_sssr_dump(dhd_pub_t *dhdp) ++{ ++ dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, NULL, ++ DHD_WQ_WORK_SSSR_DUMP, dhd_sssr_dump, DHD_WQ_WORK_PRIORITY_HIGH); ++} ++#endif /* DHD_SSSR_DUMP */ ++ ++#ifdef DHD_LOG_DUMP ++static void ++dhd_log_dump(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (do_dhd_log_dump(&dhd->pub)) { ++ DHD_ERROR(("%s: writing debug dump to the file failed\n", __FUNCTION__)); ++ return; ++ } ++} ++ ++void dhd_schedule_log_dump(dhd_pub_t *dhdp) ++{ ++ dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, ++ (void*)NULL, DHD_WQ_WORK_DHD_LOG_DUMP, ++ dhd_log_dump, DHD_WQ_WORK_PRIORITY_HIGH); ++} ++ ++static int ++do_dhd_log_dump(dhd_pub_t *dhdp) ++{ ++ int ret = 0, i = 0; ++ struct file *fp = NULL; ++ mm_segment_t old_fs; ++ loff_t pos = 0; ++ unsigned int wr_size = 0; ++ char dump_path[128]; ++ struct osl_timespec curtime; ++ uint32 file_mode; ++ unsigned long flags = 0; ++ struct dhd_log_dump_buf *dld_buf = &g_dld_buf[0]; ++ ++ const char *pre_strs = ++ "-------------------- General log ---------------------------\n"; ++ ++ const char *post_strs = ++ "-------------------- Specific log --------------------------\n"; ++ ++ if (!dhdp) { ++ return -1; ++ } ++ ++ DHD_ERROR(("DHD version: %s\n", dhd_version)); ++ DHD_ERROR(("F/W version: %s\n", fw_version)); ++ ++ /* change to KERNEL_DS address limit */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ /* Init file name */ ++ memset(dump_path, 0, sizeof(dump_path)); ++ osl_do_gettimeofday(&curtime); ++ snprintf(dump_path, sizeof(dump_path), "%s_%ld.%ld", ++ DHD_COMMON_DUMP_PATH "debug_dump", ++ (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); ++ file_mode = O_CREAT | O_WRONLY | O_SYNC; ++ ++ DHD_ERROR(("debug_dump_path = %s\n", dump_path)); ++ fp = filp_open(dump_path, file_mode, 0664); ++ if (IS_ERR(fp)) { ++ ret = PTR_ERR(fp); ++ DHD_ERROR(("open file error, err = %d\n", ret)); ++ goto exit; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ ret = kernel_write(fp, pre_strs, strlen(pre_strs), &pos); ++#else ++ ret = vfs_write(fp, pre_strs, strlen(pre_strs), &pos); ++#endif ++ if (ret < 0) { ++ DHD_ERROR(("write file error, err = %d\n", ret)); ++ goto exit; ++ } ++ ++ do { ++ unsigned int buf_size = (unsigned int)(dld_buf->max - ++ (unsigned long)dld_buf->buffer); ++ if (dld_buf->wraparound) { ++ wr_size = buf_size; ++ } else { ++ if (!dld_buf->buffer[0]) { /* print log if buf is empty. */ ++ DHD_ERROR_EX(("Buffer is empty. No event/log.\n")); ++ } ++ wr_size = (unsigned int)(dld_buf->present - dld_buf->front); ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ ret = kernel_write(fp, dld_buf->buffer, wr_size, &pos); ++#else ++ ret = vfs_write(fp, dld_buf->buffer, wr_size, &pos); ++#endif ++ if (ret < 0) { ++ DHD_ERROR(("write file error, err = %d\n", ret)); ++ goto exit; ++ } ++ ++ /* re-init dhd_log_dump_buf structure */ ++ spin_lock_irqsave(&dld_buf->lock, flags); ++ dld_buf->wraparound = 0; ++ dld_buf->present = dld_buf->front; ++ dld_buf->remain = buf_size; ++ bzero(dld_buf->buffer, buf_size); ++ spin_unlock_irqrestore(&dld_buf->lock, flags); ++ ret = BCME_OK; ++ ++ if (++i < DLD_BUFFER_NUM) { ++ dld_buf = &g_dld_buf[i]; ++ } else { ++ break; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ ret = kernel_write(fp, post_strs, strlen(post_strs), &pos); ++#else ++ ret = vfs_write(fp, post_strs, strlen(post_strs), &pos); ++#endif ++ if (ret < 0) { ++ DHD_ERROR(("write file error, err = %d\n", ret)); ++ goto exit; ++ } ++ } while (1); ++ ++exit: ++#if defined(STAT_REPORT) ++ if (!IS_ERR(fp) && ret >= 0) { ++ wl_stat_report_file_save(dhdp, fp); ++ } ++#endif /* STAT_REPORT */ ++ ++ if (!IS_ERR(fp)) { ++ filp_close(fp, NULL); ++ } ++ set_fs(old_fs); ++ ++ return ret; ++} ++#endif /* DHD_LOG_DUMP */ ++ ++ ++#ifdef BCMASSERT_LOG ++#ifdef CUSTOMER_HW4_DEBUG ++#define ASSERTINFO PLATFORM_PATH".assert.info" ++#elif defined(CUSTOMER_HW2) ++#define ASSERTINFO "/data/misc/wifi/.assert.info" ++#else ++#define ASSERTINFO "/installmedia/.assert.info" ++#endif /* CUSTOMER_HW4_DEBUG */ ++void dhd_get_assert_info(dhd_pub_t *dhd) ++{ ++ struct file *fp = NULL; ++ char *filepath = ASSERTINFO; ++ int mem_val = -1; ++ ++ /* ++ * Read assert info from the file ++ * 0: Trigger Kernel crash by panic() ++ * 1: Print out the logs and don't trigger Kernel panic. (default) ++ * 2: Trigger Kernel crash by BUG() ++ * File doesn't exist: Keep default value (1). ++ */ ++ fp = filp_open(filepath, O_RDONLY, 0); ++ if (IS_ERR(fp)) { ++ DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); ++ } else { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ ssize_t ret = kernel_read(fp, (char *)&mem_val, 4, NULL); ++#else ++ int ret = kernel_read(fp, 0, (char *)&mem_val, 4); ++#endif ++ if (ret < 0) { ++ DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret)); ++ } else { ++ mem_val = bcm_atoi((char *)&mem_val); ++ DHD_ERROR(("%s: ASSERT ENABLED = %d\n", __FUNCTION__, mem_val)); ++ } ++ filp_close(fp, NULL); ++ } ++#ifdef CUSTOMER_HW4_DEBUG ++ /* By default. set to 1, No Kernel Panic */ ++ g_assert_type = (mem_val >= 0) ? mem_val : 1; ++#else ++ /* By default. set to 0, Kernel Panic */ ++ g_assert_type = (mem_val >= 0) ? mem_val : 0; ++#endif ++} ++#endif /* BCMASSERT_LOG */ ++ ++/* ++ * This call is to get the memdump size so that, ++ * halutil can alloc that much buffer in user space. ++ */ ++int ++dhd_os_socram_dump(struct net_device *dev, uint32 *dump_size) ++{ ++ int ret = BCME_OK; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ ++ if (dhdp->busstate == DHD_BUS_DOWN) { ++ DHD_ERROR(("%s: bus is down\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) { ++ DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state, so skip\n", ++ __FUNCTION__, dhdp->busstate, dhdp->dhd_bus_busy_state)); ++ return BCME_ERROR; ++ } ++ ++ ret = dhd_common_socram_dump(dhdp); ++ if (ret == BCME_OK) { ++ *dump_size = dhdp->soc_ram_length; ++ } ++ return ret; ++} ++ ++/* ++ * This is to get the actual memdup after getting the memdump size ++ */ ++int ++dhd_os_get_socram_dump(struct net_device *dev, char **buf, uint32 *size) ++{ ++ int ret = BCME_OK; ++ int orig_len = 0; ++ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); ++ dhd_pub_t *dhdp = &dhd->pub; ++ if (buf == NULL) ++ return BCME_ERROR; ++ orig_len = *size; ++ if (dhdp->soc_ram) { ++ if (orig_len >= dhdp->soc_ram_length) { ++ memcpy(*buf, dhdp->soc_ram, dhdp->soc_ram_length); ++ /* reset the storage of dump */ ++ memset(dhdp->soc_ram, 0, dhdp->soc_ram_length); ++ *size = dhdp->soc_ram_length; ++ } else { ++ ret = BCME_BUFTOOSHORT; ++ DHD_ERROR(("The length of the buffer is too short" ++ " to save the memory dump with %d\n", dhdp->soc_ram_length)); ++ } ++ } else { ++ DHD_ERROR(("socram_dump is not ready to get\n")); ++ ret = BCME_NOTREADY; ++ } ++ return ret; ++} ++ ++int ++dhd_os_get_version(struct net_device *dev, bool dhd_ver, char **buf, uint32 size) ++{ ++ char *fw_str; ++ ++ if (size == 0) ++ return BCME_BADARG; ++ ++ fw_str = strstr(info_string, "Firmware: "); ++ if (fw_str == NULL) { ++ return BCME_ERROR; ++ } ++ ++ memset(*buf, 0, size); ++ if (dhd_ver) { ++ strncpy(*buf, dhd_version, size - 1); ++ } else { ++ strncpy(*buf, fw_str, size - 1); ++ } ++ return BCME_OK; ++} ++ ++#ifdef DHD_WMF ++/* Returns interface specific WMF configuration */ ++dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ return &ifp->wmf; ++} ++#endif /* DHD_WMF */ ++ ++#if defined(TRAFFIC_MGMT_DWM) ++void traffic_mgmt_pkt_set_prio(dhd_pub_t *dhdp, void * pktbuf) ++{ ++ struct ether_header *eh; ++ struct ethervlan_header *evh; ++ uint8 *pktdata, *ip_body; ++ uint8 dwm_filter; ++ uint8 tos_tc = 0; ++ uint8 dscp = 0; ++ pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); ++ eh = (struct ether_header *) pktdata; ++ ip_body = NULL; ++ ++ if (dhdp->dhd_tm_dwm_tbl.dhd_dwm_enabled) { ++ if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { ++ evh = (struct ethervlan_header *)eh; ++ if ((evh->ether_type == hton16(ETHER_TYPE_IP)) || ++ (evh->ether_type == hton16(ETHER_TYPE_IPV6))) { ++ ip_body = pktdata + sizeof(struct ethervlan_header); ++ } ++ } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) || ++ (eh->ether_type == hton16(ETHER_TYPE_IPV6))) { ++ ip_body = pktdata + sizeof(struct ether_header); ++ } ++ if (ip_body) { ++ tos_tc = IP_TOS46(ip_body); ++ dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; ++ } ++ ++ if (dscp < DHD_DWM_TBL_SIZE) { ++ dwm_filter = dhdp->dhd_tm_dwm_tbl.dhd_dwm_tbl[dscp]; ++ if (DHD_TRF_MGMT_DWM_IS_FILTER_SET(dwm_filter)) { ++ PKTSETPRIO(pktbuf, DHD_TRF_MGMT_DWM_PRIO(dwm_filter)); ++ } ++ } ++ } ++} ++#endif ++ ++bool dhd_sta_associated(dhd_pub_t *dhdp, uint32 bssidx, uint8 *mac) ++{ ++ return dhd_find_sta(dhdp, bssidx, mac) ? TRUE : FALSE; ++} ++ ++#ifdef DHD_L2_FILTER ++arp_table_t* ++dhd_get_ifp_arp_table_handle(dhd_pub_t *dhdp, uint32 bssidx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(bssidx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[bssidx]; ++ return ifp->phnd_arp_table; ++} ++ ++int dhd_get_parp_status(dhd_pub_t *dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ if (ifp) ++ return ifp->parp_enable; ++ else ++ return FALSE; ++} ++ ++/* Set interface specific proxy arp configuration */ ++int dhd_set_parp_status(dhd_pub_t *dhdp, uint32 idx, int val) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ASSERT(idx < DHD_MAX_IFS); ++ ifp = dhd->iflist[idx]; ++ ++ if (!ifp) ++ return BCME_ERROR; ++ ++ /* At present all 3 variables are being ++ * handled at once ++ */ ++ ifp->parp_enable = val; ++ ifp->parp_discard = val; ++ ifp->parp_allnode = val; ++ ++ /* Flush ARP entries when disabled */ ++ if (val == FALSE) { ++ bcm_l2_filter_arp_table_update(dhdp->osh, ifp->phnd_arp_table, TRUE, NULL, ++ FALSE, dhdp->tickcnt); ++ } ++ return BCME_OK; ++} ++ ++bool dhd_parp_discard_is_enabled(dhd_pub_t *dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ ASSERT(ifp); ++ return ifp->parp_discard; ++} ++ ++bool ++dhd_parp_allnode_is_enabled(dhd_pub_t *dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ ASSERT(ifp); ++ ++ return ifp->parp_allnode; ++} ++ ++int dhd_get_dhcp_unicast_status(dhd_pub_t *dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ ASSERT(ifp); ++ ++ return ifp->dhcp_unicast; ++} ++ ++int dhd_set_dhcp_unicast_status(dhd_pub_t *dhdp, uint32 idx, int val) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ASSERT(idx < DHD_MAX_IFS); ++ ifp = dhd->iflist[idx]; ++ ++ ASSERT(ifp); ++ ++ ifp->dhcp_unicast = val; ++ return BCME_OK; ++} ++ ++int dhd_get_block_ping_status(dhd_pub_t *dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ ASSERT(ifp); ++ ++ return ifp->block_ping; ++} ++ ++int dhd_set_block_ping_status(dhd_pub_t *dhdp, uint32 idx, int val) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ASSERT(idx < DHD_MAX_IFS); ++ ifp = dhd->iflist[idx]; ++ ++ ASSERT(ifp); ++ ++ ifp->block_ping = val; ++ /* Disable rx_pkt_chain feature for interface if block_ping option is ++ * enabled ++ */ ++ dhd_update_rx_pkt_chainable_state(dhdp, idx); ++ return BCME_OK; ++} ++ ++int dhd_get_grat_arp_status(dhd_pub_t *dhdp, uint32 idx) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ++ ASSERT(idx < DHD_MAX_IFS); ++ ++ ifp = dhd->iflist[idx]; ++ ++ ASSERT(ifp); ++ ++ return ifp->grat_arp; ++} ++ ++int dhd_set_grat_arp_status(dhd_pub_t *dhdp, uint32 idx, int val) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ dhd_if_t *ifp; ++ ASSERT(idx < DHD_MAX_IFS); ++ ifp = dhd->iflist[idx]; ++ ++ ASSERT(ifp); ++ ++ ifp->grat_arp = val; ++ ++ return BCME_OK; ++} ++#endif /* DHD_L2_FILTER */ ++ ++ ++#if defined(SET_RPS_CPUS) ++int dhd_rps_cpus_enable(struct net_device *net, int enable) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(net); ++ dhd_if_t *ifp; ++ int ifidx; ++ char * RPS_CPU_SETBUF; ++ ++ ifidx = dhd_net2idx(dhd, net); ++ if (ifidx == DHD_BAD_IF) { ++ DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++ if (ifidx == PRIMARY_INF) { ++ if (dhd->pub.op_mode == DHD_FLAG_IBSS_MODE) { ++ DHD_INFO(("%s : set for IBSS.\n", __FUNCTION__)); ++ RPS_CPU_SETBUF = RPS_CPUS_MASK_IBSS; ++ } else { ++ DHD_INFO(("%s : set for BSS.\n", __FUNCTION__)); ++ RPS_CPU_SETBUF = RPS_CPUS_MASK; ++ } ++ } else if (ifidx == VIRTUAL_INF) { ++ DHD_INFO(("%s : set for P2P.\n", __FUNCTION__)); ++ RPS_CPU_SETBUF = RPS_CPUS_MASK_P2P; ++ } else { ++ DHD_ERROR(("%s : Invalid index : %d.\n", __FUNCTION__, ifidx)); ++ return -EINVAL; ++ } ++ ++ ifp = dhd->iflist[ifidx]; ++ if (ifp) { ++ if (enable) { ++ DHD_INFO(("%s : set rps_cpus as [%s]\n", __FUNCTION__, RPS_CPU_SETBUF)); ++ custom_rps_map_set(ifp->net->_rx, RPS_CPU_SETBUF, strlen(RPS_CPU_SETBUF)); ++ } else { ++ custom_rps_map_clear(ifp->net->_rx); ++ } ++ } else { ++ DHD_ERROR(("%s : ifp is NULL!!\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ return BCME_OK; ++} ++ ++int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len) ++{ ++ struct rps_map *old_map, *map; ++ cpumask_var_t mask; ++ int err, cpu, i; ++ static DEFINE_SPINLOCK(rps_map_lock); ++ ++ DHD_INFO(("%s : Entered.\n", __FUNCTION__)); ++ ++ if (!alloc_cpumask_var(&mask, GFP_KERNEL)) { ++ DHD_ERROR(("%s : alloc_cpumask_var fail.\n", __FUNCTION__)); ++ return -ENOMEM; ++ } ++ ++ err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); ++ if (err) { ++ free_cpumask_var(mask); ++ DHD_ERROR(("%s : bitmap_parse fail.\n", __FUNCTION__)); ++ return err; ++ } ++ ++ map = kzalloc(max_t(unsigned int, ++ RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), ++ GFP_KERNEL); ++ if (!map) { ++ free_cpumask_var(mask); ++ DHD_ERROR(("%s : map malloc fail.\n", __FUNCTION__)); ++ return -ENOMEM; ++ } ++ ++ i = 0; ++ for_each_cpu(cpu, mask) { ++ map->cpus[i++] = cpu; ++ } ++ ++ if (i) { ++ map->len = i; ++ } else { ++ kfree(map); ++ map = NULL; ++ free_cpumask_var(mask); ++ DHD_ERROR(("%s : mapping cpu fail.\n", __FUNCTION__)); ++ return -1; ++ } ++ ++ spin_lock(&rps_map_lock); ++ old_map = rcu_dereference_protected(queue->rps_map, ++ lockdep_is_held(&rps_map_lock)); ++ rcu_assign_pointer(queue->rps_map, map); ++ spin_unlock(&rps_map_lock); ++ ++ if (map) { ++ static_key_slow_inc(&rps_needed); ++ } ++ if (old_map) { ++ kfree_rcu(old_map, rcu); ++ static_key_slow_dec(&rps_needed); ++ } ++ free_cpumask_var(mask); ++ ++ DHD_INFO(("%s : Done. mapping cpu nummber : %d\n", __FUNCTION__, map->len)); ++ return map->len; ++} ++ ++void custom_rps_map_clear(struct netdev_rx_queue *queue) ++{ ++ struct rps_map *map; ++ ++ DHD_INFO(("%s : Entered.\n", __FUNCTION__)); ++ ++ map = rcu_dereference_protected(queue->rps_map, 1); ++ if (map) { ++ RCU_INIT_POINTER(queue->rps_map, NULL); ++ kfree_rcu(map, rcu); ++ DHD_INFO(("%s : rps_cpus map clear.\n", __FUNCTION__)); ++ } ++} ++#endif ++ ++ ++ ++#ifdef DHD_DEBUG_PAGEALLOC ++ ++void ++dhd_page_corrupt_cb(void *handle, void *addr_corrupt, size_t len) ++{ ++ dhd_pub_t *dhdp = (dhd_pub_t *)handle; ++ ++ DHD_ERROR(("%s: Got dhd_page_corrupt_cb 0x%p %d\n", ++ __FUNCTION__, addr_corrupt, (uint32)len)); ++ ++ DHD_OS_WAKE_LOCK(dhdp); ++ prhex("Page Corruption:", addr_corrupt, len); ++ dhd_dump_to_kernelog(dhdp); ++#if defined(BCMPCIE) && defined(DHD_FW_COREDUMP) ++ /* Load the dongle side dump to host memory and then BUG_ON() */ ++ dhdp->memdump_enabled = DUMP_MEMONLY; ++ dhdp->memdump_type = DUMP_TYPE_MEMORY_CORRUPTION; ++ dhd_bus_mem_dump(dhdp); ++#endif /* BCMPCIE && DHD_FW_COREDUMP */ ++ DHD_OS_WAKE_UNLOCK(dhdp); ++} ++EXPORT_SYMBOL(dhd_page_corrupt_cb); ++#endif /* DHD_DEBUG_PAGEALLOC */ ++ ++#if defined(BCMPCIE) && defined(DHD_PKTID_AUDIT_ENABLED) ++void ++dhd_pktid_error_handler(dhd_pub_t *dhdp) ++{ ++ DHD_ERROR(("%s: Got Pkt Id Audit failure \n", __FUNCTION__)); ++ DHD_OS_WAKE_LOCK(dhdp); ++ dhd_dump_to_kernelog(dhdp); ++#ifdef DHD_FW_COREDUMP ++ /* Load the dongle side dump to host memory */ ++ if (dhdp->memdump_enabled == DUMP_DISABLED) { ++ dhdp->memdump_enabled = DUMP_MEMFILE; ++ } ++ dhdp->memdump_type = DUMP_TYPE_PKTID_AUDIT_FAILURE; ++ dhd_bus_mem_dump(dhdp); ++#endif /* DHD_FW_COREDUMP */ ++ dhdp->hang_reason = HANG_REASON_PCIE_PKTID_ERROR; ++ dhd_os_check_hang(dhdp, 0, -EREMOTEIO); ++ DHD_OS_WAKE_UNLOCK(dhdp); ++} ++#endif /* BCMPCIE && DHD_PKTID_AUDIT_ENABLED */ ++ ++struct net_device * ++dhd_linux_get_primary_netdev(dhd_pub_t *dhdp) ++{ ++ dhd_info_t *dhd = dhdp->info; ++ ++ if (dhd->iflist[0] && dhd->iflist[0]->net) ++ return dhd->iflist[0]->net; ++ else ++ return NULL; ++} ++ ++#ifdef DHD_ARP_DUMP ++#define ARP_PRINT(str) \ ++ do { \ ++ printk("[dhd-%s] " str " [%s] : %s(%s) %s %s(%s)\n", \ ++ ifname, tx?"TX":"RX", \ ++ tx?sabuf:dabuf, tx?seabuf:deabuf, \ ++ tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf); \ ++ } while (0) ++ ++#define ARP_PRINT_OTHER(str) \ ++ do { \ ++ printk("[dhd-%s] " str " [%s] : %s(%s) %s %s(%s) op_code=%d\n", \ ++ ifname, tx?"TX":"RX", \ ++ tx?sabuf:dabuf, tx?seabuf:deabuf, \ ++ tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, opcode); \ ++ } while (0) ++ ++static void ++dhd_arp_dump(char *ifname, uint8 *pktdata, bool tx) ++{ ++ uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN]; ++ struct bcmarp *arph = (struct bcmarp *)pkt; ++ uint16 opcode; ++ char sabuf[20]="", dabuf[20]=""; ++ char seabuf[ETHER_ADDR_STR_LEN]=""; ++ char deabuf[ETHER_ADDR_STR_LEN]=""; ++ ++ if (!(dump_msg_level & DUMP_ARP_VAL)) ++ return; ++ ++ /* validation check */ ++ if (arph->htype != hton16(HTYPE_ETHERNET) || ++ arph->hlen != ETHER_ADDR_LEN || ++ arph->plen != 4) { ++ return; ++ } ++ ++ opcode = ntoh16(arph->oper); ++ bcm_ip_ntoa((struct ipv4_addr *)arph->src_ip, sabuf); ++ bcm_ip_ntoa((struct ipv4_addr *)arph->dst_ip, dabuf); ++ bcm_ether_ntoa((struct ether_addr *)arph->dst_eth, deabuf); ++ bcm_ether_ntoa((struct ether_addr *)arph->src_eth, seabuf); ++ if (opcode == ARP_OPC_REQUEST) { ++ ARP_PRINT("ARP REQUEST "); ++ } else if (opcode == ARP_OPC_REPLY) { ++ ARP_PRINT("ARP RESPONSE"); ++ } else { ++ ARP_PRINT_OTHER("ARP OTHER"); ++ } ++} ++#endif /* DHD_ARP_DUMP */ ++ ++#ifdef DHD_DHCP_DUMP ++#define DHCP_PRINT(str) \ ++ do { \ ++ printk("[dhd-%s] " str " %8s, %8s [%s] : %s(%s) %s %s(%s)\n", \ ++ ifname, dhcp_types[dhcp_type], dhcp_ops[b->op], \ ++ tx?"TX":"RX", \ ++ tx?sabuf:dabuf, tx?seabuf:deabuf, \ ++ tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf); \ ++ } while (0) ++static void ++dhd_dhcp_dump(char *ifname, uint8 *pktdata, bool tx) ++{ ++ struct bootp_fmt *b = (struct bootp_fmt *) &pktdata[ETHER_HDR_LEN]; ++ struct iphdr *h = &b->ip_header; ++ uint8 *ptr, *opt, *end = (uint8 *) b + ntohs(b->ip_header.tot_len); ++ int dhcp_type = 0, len, opt_len; ++ uint32 ip_saddr, ip_daddr; ++ char sabuf[20]="", dabuf[20]=""; ++ char seabuf[ETHER_ADDR_STR_LEN]=""; ++ char deabuf[ETHER_ADDR_STR_LEN]=""; ++ ++ if (!(dump_msg_level & DUMP_DHCP_VAL)) ++ return; ++ ++ /* check IP header */ ++ if (h->ihl != 5 || h->version != 4 || h->protocol != IPPROTO_UDP) { ++ return; ++ } ++ ++ /* check UDP port for bootp (67, 68) */ ++ if (b->udp_header.source != htons(67) && b->udp_header.source != htons(68) && ++ b->udp_header.dest != htons(67) && b->udp_header.dest != htons(68)) { ++ return; ++ } ++ ++ /* check header length */ ++ if (ntohs(h->tot_len) < ntohs(b->udp_header.len) + sizeof(struct iphdr)) { ++ return; ++ } ++ ip_saddr = h->saddr; ++ ip_daddr = h->daddr; ++ bcm_ip_ntoa((struct ipv4_addr *)&ip_saddr, sabuf); ++ bcm_ip_ntoa((struct ipv4_addr *)&ip_daddr, dabuf); ++ bcm_ether_ntoa((struct ether_addr *)pktdata, deabuf); ++ bcm_ether_ntoa((struct ether_addr *)(pktdata+6), seabuf); ++ ++ len = ntohs(b->udp_header.len) - sizeof(struct udphdr); ++ opt_len = len ++ - (sizeof(*b) - sizeof(struct iphdr) - sizeof(struct udphdr) - sizeof(b->options)); ++ ++ /* parse bootp options */ ++ if (opt_len >= 4 && !memcmp(b->options, bootp_magic_cookie, 4)) { ++ ptr = &b->options[4]; ++ while (ptr < end && *ptr != 0xff) { ++ opt = ptr++; ++ if (*opt == 0) { ++ continue; ++ } ++ ptr += *ptr + 1; ++ if (ptr >= end) { ++ break; ++ } ++ /* 53 is dhcp type */ ++ if (*opt == 53) { ++ if (opt[1]) { ++ dhcp_type = opt[2]; ++ DHCP_PRINT("DHCP"); ++ break; ++ } ++ } ++ } ++ } ++} ++#endif /* DHD_DHCP_DUMP */ ++ ++#ifdef DHD_ICMP_DUMP ++#define ICMP_TYPE_ECHO_REQUEST 8 /* ICMP type echo request */ ++#define ICMP_TYPE_ECHO_REPLY 0 /* ICMP type echo reply */ ++#define ICMP_TYPE_DEST_UNREACH 3 ++#define ICMP_ECHO_SEQ_OFFSET 6 ++#define ICMP_ECHO_SEQ(h) (*(uint16 *)((uint8 *)(h) + (ICMP_ECHO_SEQ_OFFSET))) ++#define ICMP_PING_PRINT(str) \ ++ do { \ ++ printk("[dhd-%s] " str " [%2s] : %s(%s) %s %s(%s) SEQNUM=%d\n", \ ++ ifname, tx?"TX":"RX", tx?sabuf:dabuf, tx?seabuf:deabuf, \ ++ tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, seqnum); \ ++ } while (0) ++#define ICMP_PRINT(str) \ ++ do { \ ++ printk("[dhd-%s] " str " [%2s] : %s(%s) %s %s(%s)\n", \ ++ ifname, tx?"TX":"RX", tx?sabuf:dabuf, tx?seabuf:deabuf, \ ++ tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf); \ ++ } while (0) ++static void ++dhd_icmp_dump(char *ifname, uint8 *pktdata, bool tx) ++{ ++ uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN]; ++ struct iphdr *iph = (struct iphdr *)pkt; ++ struct icmphdr *icmph; ++ uint32 ip_saddr, ip_daddr; ++ char sabuf[20]="", dabuf[20]=""; ++ char seabuf[ETHER_ADDR_STR_LEN]=""; ++ char deabuf[ETHER_ADDR_STR_LEN]=""; ++ uint16 seqnum, type, code; ++ ++ if (!(dump_msg_level & DUMP_ICMP_VAL)) ++ return; ++ ++ /* check IP header */ ++ if (iph->ihl != 5 || iph->version != 4 || iph->protocol != IP_PROT_ICMP) { ++ return; ++ } ++ ++ icmph = (struct icmphdr *)((uint8 *)pkt + sizeof(struct iphdr)); ++ seqnum = 0; ++ type = icmph->type; ++ code = icmph->code; ++ ip_saddr = iph->saddr; ++ ip_daddr = iph->daddr; ++ bcm_ip_ntoa((struct ipv4_addr *)&ip_saddr, sabuf); ++ bcm_ip_ntoa((struct ipv4_addr *)&ip_daddr, dabuf); ++ bcm_ether_ntoa((struct ether_addr *)pktdata, deabuf); ++ bcm_ether_ntoa((struct ether_addr *)(pktdata+6), seabuf); ++ if (type == ICMP_TYPE_ECHO_REQUEST) { ++ seqnum = ntoh16(ICMP_ECHO_SEQ(icmph)); ++ ICMP_PING_PRINT("PING REQUEST"); ++ } else if (type == ICMP_TYPE_ECHO_REPLY) { ++ seqnum = ntoh16(ICMP_ECHO_SEQ(icmph)); ++ ICMP_PING_PRINT("PING REPLY "); ++ } else if (type == ICMP_TYPE_DEST_UNREACH) { ++ ICMP_PRINT("ICMP DEST UNREACH"); ++ } else { ++ ICMP_PRINT("ICMP OTHER"); ++ } ++} ++#endif /* DHD_ICMP_DUMP */ ++ ++#ifdef SHOW_LOGTRACE ++void ++dhd_get_read_buf_ptr(dhd_pub_t *dhd_pub, trace_buf_info_t *trace_buf_info) ++{ ++ dhd_dbg_ring_status_t ring_status; ++ uint32 rlen; ++ ++ rlen = dhd_dbg_ring_pull_single(dhd_pub, FW_VERBOSE_RING_ID, trace_buf_info->buf, ++ TRACE_LOG_BUF_MAX_SIZE, TRUE); ++ trace_buf_info->size = rlen; ++ trace_buf_info->availability = NEXT_BUF_NOT_AVAIL; ++ if (rlen == 0) { ++ trace_buf_info->availability = BUF_NOT_AVAILABLE; ++ return; ++ } ++ dhd_dbg_get_ring_status(dhd_pub, FW_VERBOSE_RING_ID, &ring_status); ++ if (ring_status.written_bytes != ring_status.read_bytes) { ++ trace_buf_info->availability = NEXT_BUF_AVAIL; ++ } ++} ++#endif /* SHOW_LOGTRACE */ ++ ++bool ++dhd_fw_download_status(dhd_pub_t * dhd_pub) ++{ ++ return dhd_pub->fw_download_done; ++} ++ ++int ++dhd_create_to_notifier_skt(void) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) ++ /* Kernel 3.7 onwards this API accepts only 3 arguments. */ ++ /* Kernel version 3.6 is a special case which accepts 4 arguments */ ++ nl_to_event_sk = netlink_kernel_create(&init_net, BCM_NL_USER, &g_cfg); ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) ++ /* Kernel version 3.5 and below use this old API format */ ++ nl_to_event_sk = netlink_kernel_create(&init_net, BCM_NL_USER, 0, ++ dhd_process_daemon_msg, NULL, THIS_MODULE); ++#else ++ nl_to_event_sk = netlink_kernel_create(&init_net, BCM_NL_USER, THIS_MODULE, &g_cfg); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) */ ++ if (!nl_to_event_sk) ++ { ++ printf("Error creating socket.\n"); ++ return -1; ++ } ++ DHD_INFO(("nl_to socket created successfully...\n")); ++ return 0; ++} ++ ++void ++dhd_destroy_to_notifier_skt(void) ++{ ++ DHD_INFO(("Destroying nl_to socket\n")); ++ if (nl_to_event_sk) { ++ netlink_kernel_release(nl_to_event_sk); ++ } ++} ++ ++static void ++dhd_recv_msg_from_daemon(struct sk_buff *skb) ++{ ++ struct nlmsghdr *nlh; ++ bcm_to_info_t *cmd; ++ ++ nlh = (struct nlmsghdr *)skb->data; ++ cmd = (bcm_to_info_t *)nlmsg_data(nlh); ++ if ((cmd->magic == BCM_TO_MAGIC) && (cmd->reason == REASON_DAEMON_STARTED)) { ++ sender_pid = ((struct nlmsghdr *)(skb->data))->nlmsg_pid; ++ DHD_INFO(("DHD Daemon Started\n")); ++ } ++} ++ ++int ++dhd_send_msg_to_daemon(struct sk_buff *skb, void *data, int size) ++{ ++ struct nlmsghdr *nlh; ++ struct sk_buff *skb_out; ++ ++ if (!nl_to_event_sk) { ++ DHD_INFO(("No socket available\n")); ++ return -1; ++ } ++ ++ BCM_REFERENCE(skb); ++ if (sender_pid == 0) { ++ DHD_INFO(("Invalid PID 0\n")); ++ return -1; ++ } ++ ++ if ((skb_out = nlmsg_new(size, 0)) == NULL) { ++ DHD_ERROR(("%s: skb alloc failed\n", __FUNCTION__)); ++ return -1; ++ } ++ nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, size, 0); ++ NETLINK_CB(skb_out).dst_group = 0; /* Unicast */ ++ memcpy(nlmsg_data(nlh), (char *)data, size); ++ ++ if ((nlmsg_unicast(nl_to_event_sk, skb_out, sender_pid)) < 0) { ++ DHD_INFO(("Error sending message\n")); ++ } ++ return 0; ++} ++ ++ ++static void ++dhd_process_daemon_msg(struct sk_buff *skb) ++{ ++ bcm_to_info_t to_info; ++ ++ to_info.magic = BCM_TO_MAGIC; ++ to_info.reason = REASON_DAEMON_STARTED; ++ to_info.trap = NO_TRAP; ++ ++ dhd_recv_msg_from_daemon(skb); ++ dhd_send_msg_to_daemon(skb, &to_info, sizeof(to_info)); ++} ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++static void ++dhd_send_trap_to_fw(dhd_pub_t * pub, int reason, int trap) ++{ ++ bcm_to_info_t to_info; ++ ++ to_info.magic = BCM_TO_MAGIC; ++ to_info.reason = reason; ++ to_info.trap = trap; ++ ++ DHD_ERROR(("Sending Event reason:%d trap:%d\n", reason, trap)); ++ dhd_send_msg_to_daemon(NULL, (void *)&to_info, sizeof(bcm_to_info_t)); ++} ++ ++void ++dhd_send_trap_to_fw_for_timeout(dhd_pub_t * pub, timeout_reasons_t reason) ++{ ++ int to_reason; ++ int trap = NO_TRAP; ++ switch (reason) { ++ case DHD_REASON_COMMAND_TO: ++ to_reason = REASON_COMMAND_TO; ++ trap = DO_TRAP; ++ break; ++ case DHD_REASON_JOIN_TO: ++ to_reason = REASON_JOIN_TO; ++ break; ++ case DHD_REASON_SCAN_TO: ++ to_reason = REASON_SCAN_TO; ++ break; ++ case DHD_REASON_OQS_TO: ++ to_reason = REASON_OQS_TO; ++ trap = DO_TRAP; ++ break; ++ default: ++ to_reason = REASON_UNKOWN; ++ } ++ dhd_send_trap_to_fw(pub, to_reason, trap); ++} ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++#ifdef DHD_LOG_DUMP ++void ++dhd_log_dump_init(dhd_pub_t *dhd) ++{ ++ struct dhd_log_dump_buf *dld_buf; ++ int i = 0; ++#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) ++ int prealloc_idx = DHD_PREALLOC_DHD_LOG_DUMP_BUF; ++#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ ++ ++ for (i = 0; i < DLD_BUFFER_NUM; i++) { ++ dld_buf = &g_dld_buf[i]; ++ spin_lock_init(&dld_buf->lock); ++#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) ++ dld_buf->buffer = DHD_OS_PREALLOC(dhd, prealloc_idx++, dld_buf_size[i]); ++#else ++ dld_buf->buffer = kmalloc(dld_buf_size[i], GFP_KERNEL); ++#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ ++ ++ if (!dld_buf->buffer) { ++ dld_buf->buffer = kmalloc(dld_buf_size[i], GFP_KERNEL); ++ DHD_ERROR(("Try to allocate memory using kmalloc().\n")); ++ ++ if (!dld_buf->buffer) { ++ DHD_ERROR(("Failed to allocate memory for dld_buf[%d].\n", i)); ++ goto fail; ++ } ++ } ++ ++ dld_buf->wraparound = 0; ++ dld_buf->max = (unsigned long)dld_buf->buffer + dld_buf_size[i]; ++ dld_buf->present = dld_buf->front = dld_buf->buffer; ++ dld_buf->remain = dld_buf_size[i]; ++ dld_buf->enable = 1; ++ } ++ return; ++ ++fail: ++ for (i = 0; i < DLD_BUFFER_NUM; i++) { ++ if (dld_buf[i].buffer) { ++ kfree(dld_buf[i].buffer); ++ } ++ } ++} ++ ++void ++dhd_log_dump_deinit(dhd_pub_t *dhd) ++{ ++ struct dhd_log_dump_buf *dld_buf; ++ int i = 0; ++ ++ for (i = 0; i < DLD_BUFFER_NUM; i++) { ++ dld_buf = &g_dld_buf[i]; ++ dld_buf->enable = 0; ++#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) ++ DHD_OS_PREFREE(dhd, dld_buf->buffer, dld_buf_size[i]); ++#else ++ kfree(dld_buf->buffer); ++#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ ++ } ++} ++ ++void ++dhd_log_dump_write(int type, const char *fmt, ...) ++{ ++ int len = 0; ++ char tmp_buf[DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE] = {0, }; ++ va_list args; ++ unsigned long flags = 0; ++ struct dhd_log_dump_buf *dld_buf = NULL; ++ ++ switch (type) ++ { ++ case DLD_BUF_TYPE_GENERAL: ++ dld_buf = &g_dld_buf[type]; ++ break; ++ case DLD_BUF_TYPE_SPECIAL: ++ dld_buf = &g_dld_buf[type]; ++ break; ++ default: ++ DHD_ERROR(("%s: Unknown DHD_LOG_DUMP_BUF_TYPE(%d).\n", ++ __FUNCTION__, type)); ++ return; ++ } ++ ++ if (dld_buf->enable != 1) { ++ return; ++ } ++ ++ va_start(args, fmt); ++ ++ len = vsnprintf(tmp_buf, DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE, fmt, args); ++ /* Non ANSI C99 compliant returns -1, ++ * ANSI compliant return len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE ++ */ ++ if (len < 0) { ++ return; ++ } ++ ++ if (len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE) { ++ len = DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE - 1; ++ tmp_buf[len] = '\0'; ++ } ++ ++ /* make a critical section to eliminate race conditions */ ++ spin_lock_irqsave(&dld_buf->lock, flags); ++ if (dld_buf->remain < len) { ++ dld_buf->wraparound = 1; ++ dld_buf->present = dld_buf->front; ++ dld_buf->remain = dld_buf_size[type]; ++ } ++ ++ strncpy(dld_buf->present, tmp_buf, len); ++ dld_buf->remain -= len; ++ dld_buf->present += len; ++ spin_unlock_irqrestore(&dld_buf->lock, flags); ++ ++ /* double check invalid memory operation */ ++ ASSERT((unsigned long)dld_buf->present <= dld_buf->max); ++ va_end(args); ++} ++ ++char* ++dhd_log_dump_get_timestamp(void) ++{ ++ static char buf[16]; ++ u64 ts_nsec; ++ unsigned long rem_nsec; ++ ++ ts_nsec = local_clock(); ++ rem_nsec = do_div(ts_nsec, 1000000000); ++ snprintf(buf, sizeof(buf), "%5lu.%06lu", ++ (unsigned long)ts_nsec, rem_nsec / 1000); ++ ++ return buf; ++} ++#endif /* DHD_LOG_DUMP */ ++ ++int ++dhd_write_file(const char *filepath, char *buf, int buf_len) ++{ ++ struct file *fp = NULL; ++ mm_segment_t old_fs; ++ int ret = 0; ++ ++ /* change to KERNEL_DS address limit */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ /* File is always created. */ ++ fp = filp_open(filepath, O_RDWR | O_CREAT, 0664); ++ if (IS_ERR(fp)) { ++ DHD_ERROR(("%s: Couldn't open file '%s' err %ld\n", ++ __FUNCTION__, filepath, PTR_ERR(fp))); ++ ret = BCME_ERROR; ++ } else { ++ if (fp->f_mode & FMODE_WRITE) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ ret = kernel_write(fp, buf, buf_len, &fp->f_pos); ++#else ++ ret = vfs_write(fp, buf, buf_len, &fp->f_pos); ++#endif ++ if (ret < 0) { ++ DHD_ERROR(("%s: Couldn't write file '%s'\n", ++ __FUNCTION__, filepath)); ++ ret = BCME_ERROR; ++ } else { ++ ret = BCME_OK; ++ } ++ } ++ filp_close(fp, NULL); ++ } ++ ++ /* restore previous address limit */ ++ set_fs(old_fs); ++ ++ return ret; ++} ++ ++int ++dhd_read_file(const char *filepath, char *buf, int buf_len) ++{ ++ struct file *fp = NULL; ++ mm_segment_t old_fs; ++ int ret; ++ ++ /* change to KERNEL_DS address limit */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ fp = filp_open(filepath, O_RDONLY, 0); ++ if (IS_ERR(fp)) { ++ set_fs(old_fs); ++ DHD_ERROR(("%s: File %s doesn't exist\n", __FUNCTION__, filepath)); ++ return BCME_ERROR; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ ret = kernel_read(fp, buf, buf_len, NULL); ++#else ++ ret = kernel_read(fp, 0, buf, buf_len); ++#endif ++ filp_close(fp, NULL); ++ ++ /* restore previous address limit */ ++ set_fs(old_fs); ++ ++ /* Return the number of bytes read */ ++ if (ret > 0) { ++ /* Success to read */ ++ ret = 0; ++ } else { ++ DHD_ERROR(("%s: Couldn't read the file %s, ret=%d\n", ++ __FUNCTION__, filepath, ret)); ++ ret = BCME_ERROR; ++ } ++ ++ return ret; ++} ++ ++int ++dhd_write_file_and_check(const char *filepath, char *buf, int buf_len) ++{ ++ int ret; ++ ++ ret = dhd_write_file(filepath, buf, buf_len); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ /* Read the file again and check if the file size is not zero */ ++ memset(buf, 0, buf_len); ++ ret = dhd_read_file(filepath, buf, buf_len); ++ ++ return ret; ++} ++ ++#ifdef DHD_LB_TXP ++#define DHD_LB_TXBOUND 64 ++/* ++ * Function that performs the TX processing on a given CPU ++ */ ++bool ++dhd_lb_tx_process(dhd_info_t *dhd) ++{ ++ struct sk_buff *skb; ++ int cnt = 0; ++ struct net_device *net; ++ int ifidx; ++ bool resched = FALSE; ++ ++ DHD_TRACE(("%s(): TX Processing \r\n", __FUNCTION__)); ++ if (dhd == NULL) { ++ DHD_ERROR((" Null pointer DHD \r\n")); ++ return resched; ++ } ++ ++ DHD_LB_STATS_PERCPU_ARR_INCR(dhd->txp_percpu_run_cnt); ++ ++ /* Base Loop to perform the actual Tx */ ++ do { ++ skb = skb_dequeue(&dhd->tx_pend_queue); ++ if (skb == NULL) { ++ DHD_TRACE(("Dequeued a Null Packet \r\n")); ++ break; ++ } ++ cnt++; ++ ++ net = DHD_LB_TX_PKTTAG_NETDEV((dhd_tx_lb_pkttag_fr_t *)PKTTAG(skb)); ++ ifidx = DHD_LB_TX_PKTTAG_IFIDX((dhd_tx_lb_pkttag_fr_t *)PKTTAG(skb)); ++ ++ BCM_REFERENCE(net); ++ DHD_TRACE(("Processing skb %p for net %p index %d \r\n", skb, ++ net, ifidx)); ++ ++ __dhd_sendpkt(&dhd->pub, ifidx, skb); ++ ++ if (cnt >= DHD_LB_TXBOUND) { ++ resched = TRUE; ++ break; ++ } ++ ++ } while (1); ++ ++ DHD_INFO(("%s(): Processed %d packets \r\n", __FUNCTION__, cnt)); ++ ++ return resched; ++} ++ ++void ++dhd_lb_tx_handler(unsigned long data) ++{ ++ dhd_info_t *dhd = (dhd_info_t *)data; ++ ++ if (dhd_lb_tx_process(dhd)) { ++ dhd_tasklet_schedule(&dhd->tx_tasklet); ++ } ++} ++ ++#endif /* DHD_LB_TXP */ ++ ++/* ---------------------------------------------------------------------------- ++ * Infrastructure code for sysfs interface support for DHD ++ * ++ * What is sysfs interface? ++ * https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt ++ * ++ * Why sysfs interface? ++ * This is the Linux standard way of changing/configuring Run Time parameters ++ * for a driver. We can use this interface to control "linux" specific driver ++ * parameters. ++ * ++ * ----------------------------------------------------------------------------- ++ */ ++ ++#include ++#include ++ ++#if defined(DHD_TRACE_WAKE_LOCK) ++ ++/* Function to show the history buffer */ ++static ssize_t ++show_wklock_trace(struct dhd_info *dev, char *buf) ++{ ++ ssize_t ret = 0; ++ dhd_info_t *dhd = (dhd_info_t *)dev; ++ ++ buf[ret] = '\n'; ++ buf[ret+1] = 0; ++ ++ dhd_wk_lock_stats_dump(&dhd->pub); ++ return ret+1; ++} ++ ++/* Function to enable/disable wakelock trace */ ++static ssize_t ++wklock_trace_onoff(struct dhd_info *dev, const char *buf, size_t count) ++{ ++ unsigned long onoff; ++ unsigned long flags; ++ dhd_info_t *dhd = (dhd_info_t *)dev; ++ ++ onoff = bcm_strtoul(buf, NULL, 10); ++ if (onoff != 0 && onoff != 1) { ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&dhd->wakelock_spinlock, flags); ++ trace_wklock_onoff = onoff; ++ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); ++ if (trace_wklock_onoff) { ++ printk("ENABLE WAKLOCK TRACE\n"); ++ } else { ++ printk("DISABLE WAKELOCK TRACE\n"); ++ } ++ ++ return (ssize_t)(onoff+1); ++} ++#endif /* DHD_TRACE_WAKE_LOCK */ ++ ++#if defined(DHD_LB_TXP) ++static ssize_t ++show_lbtxp(struct dhd_info *dev, char *buf) ++{ ++ ssize_t ret = 0; ++ unsigned long onoff; ++ dhd_info_t *dhd = (dhd_info_t *)dev; ++ ++ onoff = atomic_read(&dhd->lb_txp_active); ++ ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", ++ onoff); ++ return ret; ++} ++ ++static ssize_t ++lbtxp_onoff(struct dhd_info *dev, const char *buf, size_t count) ++{ ++ unsigned long onoff; ++ dhd_info_t *dhd = (dhd_info_t *)dev; ++ int i; ++ ++ onoff = bcm_strtoul(buf, NULL, 10); ++ ++ sscanf(buf, "%lu", &onoff); ++ if (onoff != 0 && onoff != 1) { ++ return -EINVAL; ++ } ++ atomic_set(&dhd->lb_txp_active, onoff); ++ ++ /* Since the scheme is changed clear the counters */ ++ for (i = 0; i < NR_CPUS; i++) { ++ DHD_LB_STATS_CLR(dhd->txp_percpu_run_cnt[i]); ++ DHD_LB_STATS_CLR(dhd->tx_start_percpu_run_cnt[i]); ++ } ++ ++ return count; ++} ++ ++#endif /* DHD_LB_TXP */ ++/* ++ * Generic Attribute Structure for DHD. ++ * If we have to add a new sysfs entry under /sys/bcm-dhd/, we have ++ * to instantiate an object of type dhd_attr, populate it with ++ * the required show/store functions (ex:- dhd_attr_cpumask_primary) ++ * and add the object to default_attrs[] array, that gets registered ++ * to the kobject of dhd (named bcm-dhd). ++ */ ++ ++struct dhd_attr { ++ struct attribute attr; ++ ssize_t(*show)(struct dhd_info *, char *); ++ ssize_t(*store)(struct dhd_info *, const char *, size_t count); ++}; ++ ++#if defined(DHD_TRACE_WAKE_LOCK) ++static struct dhd_attr dhd_attr_wklock = ++ __ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff); ++#endif /* defined(DHD_TRACE_WAKE_LOCK */ ++ ++#if defined(DHD_LB_TXP) ++static struct dhd_attr dhd_attr_lbtxp = ++ __ATTR(lbtxp, 0660, show_lbtxp, lbtxp_onoff); ++#endif /* DHD_LB_TXP */ ++ ++/* Attribute object that gets registered with "bcm-dhd" kobject tree */ ++static struct attribute *default_attrs[] = { ++#if defined(DHD_TRACE_WAKE_LOCK) ++ &dhd_attr_wklock.attr, ++#endif /* DHD_TRACE_WAKE_LOCK */ ++#if defined(DHD_LB_TXP) ++ &dhd_attr_lbtxp.attr, ++#endif /* DHD_LB_TXP */ ++ NULL ++}; ++ ++#define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj) ++#define to_attr(a) container_of(a, struct dhd_attr, attr) ++ ++/* ++ * bcm-dhd kobject show function, the "attr" attribute specifices to which ++ * node under "bcm-dhd" the show function is called. ++ */ ++static ssize_t dhd_show(struct kobject *kobj, struct attribute *attr, char *buf) ++{ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ dhd_info_t *dhd = to_dhd(kobj); ++ struct dhd_attr *d_attr = to_attr(attr); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ int ret; ++ ++ if (d_attr->show) ++ ret = d_attr->show(dhd, buf); ++ else ++ ret = -EIO; ++ ++ return ret; ++} ++ ++/* ++ * bcm-dhd kobject show function, the "attr" attribute specifices to which ++ * node under "bcm-dhd" the store function is called. ++ */ ++static ssize_t dhd_store(struct kobject *kobj, struct attribute *attr, ++ const char *buf, size_t count) ++{ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ dhd_info_t *dhd = to_dhd(kobj); ++ struct dhd_attr *d_attr = to_attr(attr); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ int ret; ++ ++ if (d_attr->store) ++ ret = d_attr->store(dhd, buf, count); ++ else ++ ret = -EIO; ++ ++ return ret; ++ ++} ++ ++static struct sysfs_ops dhd_sysfs_ops = { ++ .show = dhd_show, ++ .store = dhd_store, ++}; ++ ++static struct kobj_type dhd_ktype = { ++ .sysfs_ops = &dhd_sysfs_ops, ++ .default_attrs = default_attrs, ++}; ++ ++/* Create a kobject and attach to sysfs interface */ ++static int dhd_sysfs_init(dhd_info_t *dhd) ++{ ++ int ret = -1; ++ ++ if (dhd == NULL) { ++ DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__)); ++ return ret; ++ } ++ ++ /* Initialize the kobject */ ++ ret = kobject_init_and_add(&dhd->dhd_kobj, &dhd_ktype, NULL, "bcm-dhd"); ++ if (ret) { ++ kobject_put(&dhd->dhd_kobj); ++ DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__)); ++ return ret; ++ } ++ ++ /* ++ * We are always responsible for sending the uevent that the kobject ++ * was added to the system. ++ */ ++ kobject_uevent(&dhd->dhd_kobj, KOBJ_ADD); ++ ++ return ret; ++} ++ ++/* Done with the kobject and detach the sysfs interface */ ++static void dhd_sysfs_exit(dhd_info_t *dhd) ++{ ++ if (dhd == NULL) { ++ DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__)); ++ return; ++ } ++ ++ /* Releae the kobject */ ++ if (dhd->dhd_kobj.state_initialized) ++ kobject_put(&dhd->dhd_kobj); ++} ++ ++#ifdef DHD_DEBUG_UART ++bool ++dhd_debug_uart_is_running(struct net_device *dev) ++{ ++ dhd_info_t *dhd = DHD_DEV_INFO(dev); ++ ++ if (dhd->duart_execute) { ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static void ++dhd_debug_uart_exec_rd(void *handle, void *event_info, u8 event) ++{ ++ dhd_pub_t *dhdp = handle; ++ dhd_debug_uart_exec(dhdp, "rd"); ++} ++ ++static void ++dhd_debug_uart_exec(dhd_pub_t *dhdp, char *cmd) ++{ ++ int ret; ++ ++ char *argv[] = {DHD_DEBUG_UART_EXEC_PATH, cmd, NULL}; ++ char *envp[] = {"HOME=/", "TERM=linux", "PATH=/sbin:/system/bin", NULL}; ++ ++#ifdef DHD_FW_COREDUMP ++ if (dhdp->memdump_enabled == DUMP_MEMFILE_BUGON) ++#endif ++ { ++ if (dhdp->hang_reason == HANG_REASON_PCIE_LINK_DOWN || ++#ifdef DHD_FW_COREDUMP ++ dhdp->memdump_success == FALSE || ++#endif ++ FALSE) { ++ dhdp->info->duart_execute = TRUE; ++ DHD_ERROR(("DHD: %s - execute %s %s\n", ++ __FUNCTION__, DHD_DEBUG_UART_EXEC_PATH, cmd)); ++ ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); ++ DHD_ERROR(("DHD: %s - %s %s ret = %d\n", ++ __FUNCTION__, DHD_DEBUG_UART_EXEC_PATH, cmd, ret)); ++ dhdp->info->duart_execute = FALSE; ++ ++#ifdef DHD_LOG_DUMP ++ if (dhdp->memdump_type != DUMP_TYPE_BY_SYSDUMP) ++#endif ++ { ++ BUG_ON(1); ++ } ++ } ++ } ++} ++#endif /* DHD_DEBUG_UART */ ++ ++#if defined(DHD_BLOB_EXISTENCE_CHECK) ++void ++dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path) ++{ ++ struct file *fp; ++ char *filepath = CONFIG_BCMDHD_CLM_PATH; ++ ++ fp = filp_open(filepath, O_RDONLY, 0); ++ if (IS_ERR(fp)) { ++ DHD_ERROR(("%s: ----- blob file dosen't exist -----\n", __FUNCTION__)); ++ dhdp->is_blob = FALSE; ++ } else { ++ DHD_ERROR(("%s: ----- blob file exist -----\n", __FUNCTION__)); ++ dhdp->is_blob = TRUE; ++#if defined(CONCATE_BLOB) ++ strncat(fw_path, "_blob", strlen("_blob")); ++#else ++ BCM_REFERENCE(fw_path); ++#endif /* SKIP_CONCATE_BLOB */ ++ filp_close(fp, NULL); ++ } ++} ++#endif /* DHD_BLOB_EXISTENCE_CHECK */ ++ ++#if defined(PCIE_FULL_DONGLE) ++/** test / loopback */ ++void ++dmaxfer_free_dmaaddr_handler(void *handle, void *event_info, u8 event) ++{ ++ dmaxref_mem_map_t *dmmap = (dmaxref_mem_map_t *)event_info; ++ dhd_info_t *dhd_info = (dhd_info_t *)handle; ++ dhd_pub_t *dhdp = &dhd_info->pub; ++ ++ if (event != DHD_WQ_WORK_DMA_LB_MEM_REL) { ++ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); ++ return; ++ } ++ ++ if ((dhd_info == NULL) || (dhdp == NULL)) { ++ DHD_ERROR(("%s: invalid dhd_info\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (dmmap == NULL) { ++ DHD_ERROR(("%s: dmmap is null\n", __FUNCTION__)); ++ return; ++ } ++ dmaxfer_free_prev_dmaaddr(dhdp, dmmap); ++} ++ ++ ++void ++dhd_schedule_dmaxfer_free(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap) ++{ ++ dhd_info_t *dhd_info = dhdp->info; ++ ++ dhd_deferred_schedule_work(dhd_info->dhd_deferred_wq, (void *)dmmap, ++ DHD_WQ_WORK_DMA_LB_MEM_REL, dmaxfer_free_dmaaddr_handler, DHD_WQ_WORK_PRIORITY_LOW); ++} ++#endif /* PCIE_FULL_DONGLE */ ++/* ---------------------------- End of sysfs implementation ------------------------------------- */ ++#ifdef HOFFLOAD_MODULES ++void ++dhd_linux_get_modfw_address(dhd_pub_t *dhd) ++{ ++ const char* module_name = NULL; ++ const struct firmware *module_fw; ++ struct module_metadata *hmem = &dhd->hmem; ++ ++ if (dhd_hmem_module_string[0] != '\0') { ++ module_name = dhd_hmem_module_string; ++ } else { ++ DHD_ERROR(("%s No module image name specified\n", __FUNCTION__)); ++ return; ++ } ++ if (request_firmware(&module_fw, module_name, dhd_bus_to_dev(dhd->bus))) { ++ DHD_ERROR(("modules.img not available\n")); ++ return; ++ } ++ if (!dhd_alloc_module_memory(dhd->bus, module_fw->size, hmem)) { ++ release_firmware(module_fw); ++ return; ++ } ++ memcpy(hmem->data, module_fw->data, module_fw->size); ++ release_firmware(module_fw); ++} ++#endif /* HOFFLOAD_MODULES */ ++ ++#ifdef SET_PCIE_IRQ_CPU_CORE ++void ++dhd_set_irq_cpucore(dhd_pub_t *dhdp, int set) ++{ ++ unsigned int irq; ++ if (!dhdp) { ++ DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (!dhdp->bus) { ++ DHD_ERROR(("%s : dhd->bus is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (dhdpcie_get_pcieirq(dhdp->bus, &irq)) { ++ return; ++ } ++ ++ set_irq_cpucore(irq, set); ++} ++#endif /* SET_PCIE_IRQ_CPU_CORE */ ++ ++#if defined(DHD_HANG_SEND_UP_TEST) ++void ++dhd_make_hang_with_reason(struct net_device *dev, const char *string_num) ++{ ++ dhd_info_t *dhd = NULL; ++ dhd_pub_t *dhdp = NULL; ++ uint reason = HANG_REASON_MAX; ++ char buf[WLC_IOCTL_SMLEN] = {0, }; ++ uint32 fw_test_code = 0; ++ dhd = DHD_DEV_INFO(dev); ++ ++ if (dhd) { ++ dhdp = &dhd->pub; ++ } ++ ++ if (!dhd || !dhdp) { ++ return; ++ } ++ ++ reason = (uint) bcm_strtoul(string_num, NULL, 0); ++ DHD_ERROR(("Enter %s, reason=0x%x\n", __FUNCTION__, reason)); ++ ++ if (reason == 0) { ++ if (dhdp->req_hang_type) { ++ DHD_ERROR(("%s, Clear HANG test request 0x%x\n", ++ __FUNCTION__, dhdp->req_hang_type)); ++ dhdp->req_hang_type = 0; ++ return; ++ } else { ++ DHD_ERROR(("%s, No requested HANG test\n", __FUNCTION__)); ++ return; ++ } ++ } else if ((reason <= HANG_REASON_MASK) || (reason >= HANG_REASON_MAX)) { ++ DHD_ERROR(("Invalid HANG request, reason 0x%x\n", reason)); ++ return; ++ } ++ ++ if (dhdp->req_hang_type != 0) { ++ DHD_ERROR(("Already HANG requested for test\n")); ++ return; ++ } ++ ++ switch (reason) { ++ case HANG_REASON_IOCTL_RESP_TIMEOUT: ++ DHD_ERROR(("Make HANG!!!: IOCTL response timeout(0x%x)\n", reason)); ++ dhdp->req_hang_type = reason; ++ fw_test_code = 102; /* resumed on timeour */ ++ bcm_mkiovar("bus:disconnect", (void *)&fw_test_code, 4, buf, sizeof(buf)); ++ dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++ break; ++ case HANG_REASON_DONGLE_TRAP: ++ DHD_ERROR(("Make HANG!!!: Dongle trap (0x%x)\n", reason)); ++ dhdp->req_hang_type = reason; ++ fw_test_code = 99; /* dongle trap */ ++ bcm_mkiovar("bus:disconnect", (void *)&fw_test_code, 4, buf, sizeof(buf)); ++ dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); ++ break; ++ case HANG_REASON_D3_ACK_TIMEOUT: ++ DHD_ERROR(("Make HANG!!!: D3 ACK timeout (0x%x)\n", reason)); ++ dhdp->req_hang_type = reason; ++ break; ++ case HANG_REASON_BUS_DOWN: ++ DHD_ERROR(("Make HANG!!!: BUS down(0x%x)\n", reason)); ++ dhdp->req_hang_type = reason; ++ break; ++ case HANG_REASON_PCIE_LINK_DOWN: ++ case HANG_REASON_MSGBUF_LIVELOCK: ++ dhdp->req_hang_type = 0; ++ DHD_ERROR(("Does not support requested HANG(0x%x)\n", reason)); ++ break; ++ case HANG_REASON_IFACE_OP_FAILURE: ++ DHD_ERROR(("Make HANG!!!: P2P inrerface delete failure(0x%x)\n", reason)); ++ dhdp->req_hang_type = reason; ++ break; ++ case HANG_REASON_HT_AVAIL_ERROR: ++ dhdp->req_hang_type = 0; ++ DHD_ERROR(("PCIe does not support requested HANG(0x%x)\n", reason)); ++ break; ++ case HANG_REASON_PCIE_RC_LINK_UP_FAIL: ++ DHD_ERROR(("Make HANG!!!:Link Up(0x%x)\n", reason)); ++ dhdp->req_hang_type = reason; ++ break; ++ default: ++ dhdp->req_hang_type = 0; ++ DHD_ERROR(("Unknown HANG request (0x%x)\n", reason)); ++ break; ++ } ++} ++#endif /* DHD_HANG_SEND_UP_TEST */ ++#ifdef DHD_WAKE_STATUS ++wake_counts_t* ++dhd_get_wakecount(dhd_pub_t *dhdp) ++{ ++#ifdef BCMDBUS ++ return NULL; ++#else ++ return dhd_bus_get_wakecount(dhdp); ++#endif /* BCMDBUS */ ++} ++#endif /* DHD_WAKE_STATUS */ ++ ++#ifdef BCM_ASLR_HEAP ++uint32 ++dhd_get_random_number(void) ++{ ++ uint32 rand = 0; ++ get_random_bytes_arch(&rand, sizeof(rand)); ++ return rand; ++} ++#endif /* BCM_ASLR_HEAP */ ++ ++#ifdef DHD_PKT_LOGGING ++void ++dhd_pktlog_dump(void *handle, void *event_info, u8 event) ++{ ++ dhd_info_t *dhd = handle; ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (dhd_pktlog_write_file(&dhd->pub)) { ++ DHD_ERROR(("%s: writing pktlog dump to the file failed\n", __FUNCTION__)); ++ return; ++ } ++} ++ ++void ++dhd_schedule_pktlog_dump(dhd_pub_t *dhdp) ++{ ++ dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, ++ (void*)NULL, DHD_WQ_WORK_PKTLOG_DUMP, ++ dhd_pktlog_dump, DHD_WQ_WORK_PRIORITY_HIGH); ++} ++#endif /* DHD_PKT_LOGGING */ ++ ++void *dhd_get_pub(struct net_device *dev) ++{ ++ dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev); ++ if (dhdinfo) ++ return (void *)&dhdinfo->pub; ++ else { ++ printf("%s: null dhdinfo\n", __FUNCTION__); ++ return NULL; ++ } ++} ++ ++bool dhd_os_wd_timer_enabled(void *bus) ++{ ++ dhd_pub_t *pub = bus; ++ dhd_info_t *dhd = (dhd_info_t *)pub->info; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__)); ++ return FALSE; ++ } ++ return dhd->wd_timer_valid; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux.h +new file mode 100644 +index 000000000..f19170628 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux.h +@@ -0,0 +1,189 @@ ++/* ++ * DHD Linux header file (dhd_linux exports for cfg80211 and other components) ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_linux.h 699532 2017-05-15 11:00:39Z $ ++ */ ++ ++/* wifi platform functions for power, interrupt and pre-alloc, either ++ * from Android-like platform device data, or Broadcom wifi platform ++ * device data. ++ * ++ */ ++#ifndef __DHD_LINUX_H__ ++#define __DHD_LINUX_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#ifdef DHD_WMF ++#include ++#endif ++/* Linux wireless extension support */ ++#if defined(WL_WIRELESS_EXT) ++#include ++#endif /* defined(WL_WIRELESS_EXT) */ ++#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ++#include ++#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ ++ ++/* dongle status */ ++enum wifi_adapter_status { ++ WIFI_STATUS_POWER_ON = 0, ++ WIFI_STATUS_ATTACH, ++ WIFI_STATUS_FW_READY, ++ WIFI_STATUS_DETTACH ++}; ++#define wifi_chk_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status)) ++#define wifi_get_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status)) ++#define wifi_set_adapter_status(adapter, stat) (set_bit(stat, &(adapter)->status)) ++#define wifi_clr_adapter_status(adapter, stat) (clear_bit(stat, &(adapter)->status)) ++#define wifi_chg_adapter_status(adapter, stat) (change_bit(stat, &(adapter)->status)) ++ ++#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ ++#define DHD_FW_READY_TIMEOUT 5000 /* msec : allowed time to finished fw download */ ++ ++typedef struct wifi_adapter_info { ++ const char *name; ++ uint irq_num; ++ uint intr_flags; ++ const char *fw_path; ++ const char *nv_path; ++ const char *clm_path; ++ const char *conf_path; ++ void *wifi_plat_data; /* wifi ctrl func, for backward compatibility */ ++ uint bus_type; ++ uint bus_num; ++ uint slot_num; ++ wait_queue_head_t status_event; ++ unsigned long status; ++#if defined(BT_OVER_SDIO) ++ const char *btfw_path; ++#endif /* defined (BT_OVER_SDIO) */ ++#ifdef BUS_POWER_RESTORE ++#if defined(BCMSDIO) ++ struct sdio_func *sdio_func; ++#endif /* BCMSDIO */ ++#if defined(BCMPCIE) ++ struct pci_dev *pci_dev; ++ struct pci_saved_state *pci_saved_state; ++#endif /* BCMPCIE */ ++#endif ++} wifi_adapter_info_t; ++ ++#define WLAN_PLAT_NODFS_FLAG 0x01 ++#define WLAN_PLAT_AP_FLAG 0x02 ++#if !defined(CONFIG_WIFI_CONTROL_FUNC) ++struct wifi_platform_data { ++#ifdef BUS_POWER_RESTORE ++ int (*set_power)(int val, wifi_adapter_info_t *adapter); ++#else ++ int (*set_power)(int val); ++#endif ++ int (*set_reset)(int val); ++ int (*set_carddetect)(int val); ++ void *(*mem_prealloc)(int section, unsigned long size); ++ int (*get_mac_addr)(unsigned char *buf); ++#ifdef CUSTOM_FORCE_NODFS_FLAG ++ void *(*get_country_code)(char *ccode, u32 flags); ++#else /* defined (CUSTOM_FORCE_NODFS_FLAG) */ ++ void *(*get_country_code)(char *ccode); ++#endif ++}; ++#endif ++ ++typedef struct bcmdhd_wifi_platdata { ++ uint num_adapters; ++ wifi_adapter_info_t *adapters; ++} bcmdhd_wifi_platdata_t; ++ ++/** Per STA params. A list of dhd_sta objects are managed in dhd_if */ ++typedef struct dhd_sta { ++ cumm_ctr_t cumm_ctr; /* cummulative queue length of child flowrings */ ++ uint16 flowid[NUMPRIO]; /* allocated flow ring ids (by priority) */ ++ void * ifp; /* associated dhd_if */ ++ struct ether_addr ea; /* stations ethernet mac address */ ++ struct list_head list; /* link into dhd_if::sta_list */ ++ int idx; /* index of self in dhd_pub::sta_pool[] */ ++ int ifidx; /* index of interface in dhd */ ++#ifdef DHD_WMF ++ struct dhd_sta *psta_prim; /* primary index of psta interface */ ++#endif /* DHD_WMF */ ++} dhd_sta_t; ++typedef dhd_sta_t dhd_sta_pool_t; ++ ++int dhd_wifi_platform_register_drv(void); ++void dhd_wifi_platform_unregister_drv(void); ++wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type, ++ uint32 bus_num, uint32 slot_num, unsigned long status); ++wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, ++ uint32 slot_num); ++int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec); ++int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present); ++int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr); ++int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf); ++#ifdef CUSTOM_COUNTRY_CODE ++void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, ++ u32 flags); ++#else ++void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode); ++#endif /* CUSTOM_COUNTRY_CODE */ ++void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size); ++void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter); ++ ++int dhd_get_fw_mode(struct dhd_info *dhdinfo); ++bool dhd_update_fw_nv_path(struct dhd_info *dhdinfo); ++ ++#ifdef DHD_WMF ++dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx); ++int dhd_get_wmf_psta_disable(dhd_pub_t *dhdp, uint32 idx); ++int dhd_set_wmf_psta_disable(dhd_pub_t *dhdp, uint32 idx, int val); ++void dhd_update_psta_interface_for_sta(dhd_pub_t *dhdp, char* ifname, ++ void* mac_addr, void* event_data); ++#endif /* DHD_WMF */ ++#if defined(BT_OVER_SDIO) ++int dhd_net_bus_get(struct net_device *dev); ++int dhd_net_bus_put(struct net_device *dev); ++#endif /* BT_OVER_SDIO */ ++#ifdef HOFFLOAD_MODULES ++extern void dhd_free_module_memory(struct dhd_bus *bus, struct module_metadata *hmem); ++extern void* dhd_alloc_module_memory(struct dhd_bus *bus, uint32_t size, ++ struct module_metadata *hmem); ++#endif /* HOFFLOAD_MODULES */ ++#if defined(WLADPS) || defined(WLADPS_PRIVATE_CMD) ++#define ADPS_ENABLE 1 ++#define ADPS_DISABLE 0 ++typedef struct bcm_iov_buf { ++ uint16 version; ++ uint16 len; ++ uint16 id; ++ uint16 data[1]; ++} bcm_iov_buf_t; ++ ++int dhd_enable_adps(dhd_pub_t *dhd, uint8 on); ++#endif /* WLADPS || WLADPS_PRIVATE_CMD */ ++#endif /* __DHD_LINUX_H__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c +new file mode 100644 +index 000000000..3848bc552 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c +@@ -0,0 +1,1013 @@ ++/* ++ * Linux platform device for DHD WLAN adapter ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_linux_platdev.c 662397 2016-09-29 10:15:08Z $ ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++#include ++#endif ++#ifdef CONFIG_DTS ++#include ++#include ++#endif /* CONFIG_DTS */ ++ ++#if defined(CUSTOMER_HW) ++extern int dhd_wlan_init_plat_data(void); ++extern void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter); ++#endif /* CUSTOMER_HW */ ++ ++#define WIFI_PLAT_NAME "bcmdhd_wlan" ++#define WIFI_PLAT_NAME2 "bcm4329_wlan" ++#define WIFI_PLAT_EXT "bcmdhd_wifi_platform" ++ ++#ifdef CONFIG_DTS ++struct regulator *wifi_regulator = NULL; ++extern struct wifi_platform_data dhd_wlan_control; ++#endif /* CONFIG_DTS */ ++ ++bool cfg_multichip = FALSE; ++bcmdhd_wifi_platdata_t *dhd_wifi_platdata = NULL; ++static int wifi_plat_dev_probe_ret = 0; ++static bool is_power_on = FALSE; ++#if !defined(CONFIG_DTS) ++#if defined(DHD_OF_SUPPORT) ++static bool dts_enabled = TRUE; ++extern struct resource dhd_wlan_resources; ++extern struct wifi_platform_data dhd_wlan_control; ++#else ++static bool dts_enabled = FALSE; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wmissing-field-initializers" ++#endif ++struct resource dhd_wlan_resources = {0}; ++struct wifi_platform_data dhd_wlan_control = {0}; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++#endif /* CONFIG_OF && !defined(CONFIG_ARCH_MSM) */ ++#endif /* !defind(CONFIG_DTS) */ ++ ++static int dhd_wifi_platform_load(void); ++ ++extern void* wl_cfg80211_get_dhdp(struct net_device *dev); ++ ++#ifdef ENABLE_4335BT_WAR ++extern int bcm_bt_lock(int cookie); ++extern void bcm_bt_unlock(int cookie); ++static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ ++#endif /* ENABLE_4335BT_WAR */ ++ ++wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type, ++ uint32 bus_num, uint32 slot_num, unsigned long status) ++{ ++ int i; ++ ++ if (dhd_wifi_platdata == NULL) ++ return NULL; ++ ++ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { ++ wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i]; ++ if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && ++ (adapter->bus_num == -1 || adapter->bus_num == bus_num) && ++ (adapter->slot_num == -1 || adapter->slot_num == slot_num) ++#if defined(ENABLE_INSMOD_NO_FW_LOAD) ++ && (wifi_chk_adapter_status(adapter, status)) ++#endif ++ ) { ++ DHD_ERROR(("attach adapter info '%s'\n", adapter->name)); ++ return adapter; ++ } ++ } ++ return NULL; ++} ++ ++wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num) ++{ ++ int i; ++ ++ if (dhd_wifi_platdata == NULL) ++ return NULL; ++ ++ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { ++ wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i]; ++ if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && ++ (adapter->bus_num == -1 || adapter->bus_num == bus_num) && ++ (adapter->slot_num == -1 || adapter->slot_num == slot_num)) { ++ DHD_TRACE(("found adapter info '%s'\n", adapter->name)); ++ return adapter; ++ } ++ } ++ return NULL; ++} ++ ++void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size) ++{ ++ void *alloc_ptr = NULL; ++ struct wifi_platform_data *plat_data; ++ ++ if (!adapter || !adapter->wifi_plat_data) ++ return NULL; ++ plat_data = adapter->wifi_plat_data; ++ if (plat_data->mem_prealloc) { ++ alloc_ptr = plat_data->mem_prealloc(section, size); ++ if (alloc_ptr) { ++ DHD_INFO(("success alloc section %d\n", section)); ++ if (size != 0L) ++ bzero(alloc_ptr, size); ++ return alloc_ptr; ++ } ++ } else ++ return NULL; ++ ++ DHD_ERROR(("%s: failed to alloc static mem section %d\n", __FUNCTION__, section)); ++ return NULL; ++} ++ ++void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter) ++{ ++ struct wifi_platform_data *plat_data; ++ ++ if (!adapter || !adapter->wifi_plat_data) ++ return NULL; ++ plat_data = adapter->wifi_plat_data; ++ return plat_data->mem_prealloc; ++} ++ ++int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr) ++{ ++ if (adapter == NULL) ++ return -1; ++ if (irq_flags_ptr) ++ *irq_flags_ptr = adapter->intr_flags; ++ return adapter->irq_num; ++} ++ ++int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec) ++{ ++ int err = 0; ++#ifndef CONFIG_DTS ++ struct wifi_platform_data *plat_data; ++#endif ++#ifdef BT_OVER_SDIO ++ if (is_power_on == on) { ++ return -EINVAL; ++ } ++#endif /* BT_OVER_SDIO */ ++ if (on) { ++ wifi_set_adapter_status(adapter, WIFI_STATUS_POWER_ON); ++ } else { ++ wifi_clr_adapter_status(adapter, WIFI_STATUS_POWER_ON); ++ } ++#ifdef CONFIG_DTS ++ if (on) { ++ printf("======== PULL WL_REG_ON HIGH! ========\n"); ++ err = regulator_enable(wifi_regulator); ++ is_power_on = TRUE; ++ } ++ else { ++ printf("======== PULL WL_REG_ON LOW! ========\n"); ++ err = regulator_disable(wifi_regulator); ++ is_power_on = FALSE; ++ } ++ if (err < 0) { ++ DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__)); ++ goto fail; ++ } ++#else ++ if (!adapter || !adapter->wifi_plat_data) { ++ err = -EINVAL; ++ goto fail; ++ } ++ plat_data = adapter->wifi_plat_data; ++ ++ DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); ++ if (plat_data->set_power) { ++#ifdef ENABLE_4335BT_WAR ++ if (on) { ++ printk("WiFi: trying to acquire BT lock\n"); ++ if (bcm_bt_lock(lock_cookie_wifi) != 0) ++ printk("** WiFi: timeout in acquiring bt lock**\n"); ++ printk("%s: btlock acquired\n", __FUNCTION__); ++ } ++ else { ++ /* For a exceptional case, release btlock */ ++ bcm_bt_unlock(lock_cookie_wifi); ++ } ++#endif /* ENABLE_4335BT_WAR */ ++ ++#ifdef BUS_POWER_RESTORE ++ err = plat_data->set_power(on, adapter); ++#else ++ err = plat_data->set_power(on); ++#endif ++ } ++ ++ if (msec && !err) ++ OSL_SLEEP(msec); ++ ++ if (on && !err) ++ is_power_on = TRUE; ++ else ++ is_power_on = FALSE; ++ ++#endif /* CONFIG_DTS */ ++ ++ return err; ++fail: ++ if (on) { ++ wifi_clr_adapter_status(adapter, WIFI_STATUS_POWER_ON); ++ } else { ++ wifi_set_adapter_status(adapter, WIFI_STATUS_POWER_ON); ++ } ++ return err; ++} ++ ++int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present) ++{ ++ int err = 0; ++ struct wifi_platform_data *plat_data; ++ ++ if (!adapter || !adapter->wifi_plat_data) ++ return -EINVAL; ++ plat_data = adapter->wifi_plat_data; ++ ++ DHD_ERROR(("%s device present %d\n", __FUNCTION__, device_present)); ++ if (plat_data->set_carddetect) { ++ err = plat_data->set_carddetect(device_present); ++ } ++ return err; ++ ++} ++ ++int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf) ++{ ++ struct wifi_platform_data *plat_data; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ if (!buf || !adapter || !adapter->wifi_plat_data) ++ return -EINVAL; ++ plat_data = adapter->wifi_plat_data; ++ if (plat_data->get_mac_addr) { ++ return plat_data->get_mac_addr(buf); ++ } ++ return -EOPNOTSUPP; ++} ++ ++void * ++#ifdef CUSTOM_COUNTRY_CODE ++wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags) ++#else ++wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) ++#endif /* CUSTOM_COUNTRY_CODE */ ++{ ++ /* get_country_code was added after 2.6.39 */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ struct wifi_platform_data *plat_data; ++ ++ if (!ccode || !adapter || !adapter->wifi_plat_data) ++ return NULL; ++ plat_data = adapter->wifi_plat_data; ++ ++ DHD_TRACE(("%s\n", __FUNCTION__)); ++ if (plat_data->get_country_code) { ++#ifdef CUSTOM_FORCE_NODFS_FLAG ++ return plat_data->get_country_code(ccode, flags); ++#else ++ return plat_data->get_country_code(ccode); ++#endif /* CUSTOM_COUNTRY_CODE */ ++ } ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ ++ ++ return NULL; ++} ++ ++#ifndef CUSTOMER_HW ++static int wifi_plat_dev_drv_probe(struct platform_device *pdev) ++{ ++ struct resource *resource; ++ wifi_adapter_info_t *adapter; ++#if defined(CONFIG_DTS) && defined(CUSTOMER_OOB) ++ int irq, gpio; ++#endif /* CONFIG_DTS */ ++ ++ /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") ++ * is kept for backward compatibility and supports only 1 adapter ++ */ ++ ASSERT(dhd_wifi_platdata != NULL); ++ ASSERT(dhd_wifi_platdata->num_adapters == 1); ++ adapter = &dhd_wifi_platdata->adapters[0]; ++#if defined(CONFIG_WIFI_CONTROL_FUNC) ++ adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data); ++#else ++ adapter->wifi_plat_data = (void *)&dhd_wlan_control; ++#endif ++ ++ resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); ++ if (resource == NULL) ++ resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); ++ if (resource) { ++ adapter->irq_num = resource->start; ++ adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK; ++#ifdef DHD_ISR_NO_SUSPEND ++ adapter->intr_flags |= IRQF_NO_SUSPEND; ++#endif ++ } ++ ++#ifdef CONFIG_DTS ++ wifi_regulator = regulator_get(&pdev->dev, "wlreg_on"); ++ if (wifi_regulator == NULL) { ++ DHD_ERROR(("%s regulator is null\n", __FUNCTION__)); ++ return -1; ++ } ++ ++#if defined(CUSTOMER_OOB) ++ /* This is to get the irq for the OOB */ ++ gpio = of_get_gpio(pdev->dev.of_node, 0); ++ ++ if (gpio < 0) { ++ DHD_ERROR(("%s gpio information is incorrect\n", __FUNCTION__)); ++ return -1; ++ } ++ irq = gpio_to_irq(gpio); ++ if (irq < 0) { ++ DHD_ERROR(("%s irq information is incorrect\n", __FUNCTION__)); ++ return -1; ++ } ++ adapter->irq_num = irq; ++ ++ /* need to change the flags according to our requirement */ ++ adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | ++ IORESOURCE_IRQ_SHAREABLE; ++#endif ++#endif /* CONFIG_DTS */ ++ ++ wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); ++ return wifi_plat_dev_probe_ret; ++} ++ ++static int wifi_plat_dev_drv_remove(struct platform_device *pdev) ++{ ++ wifi_adapter_info_t *adapter; ++ ++ /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") ++ * is kept for backward compatibility and supports only 1 adapter ++ */ ++ ASSERT(dhd_wifi_platdata != NULL); ++ ASSERT(dhd_wifi_platdata->num_adapters == 1); ++ adapter = &dhd_wifi_platdata->adapters[0]; ++ if (is_power_on) { ++#ifdef BCMPCIE ++ wifi_platform_bus_enumerate(adapter, FALSE); ++ wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); ++#else ++ wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); ++ wifi_platform_bus_enumerate(adapter, FALSE); ++#endif /* BCMPCIE */ ++ } ++ ++#ifdef CONFIG_DTS ++ regulator_put(wifi_regulator); ++#endif /* CONFIG_DTS */ ++ return 0; ++} ++ ++static int wifi_plat_dev_drv_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ DHD_TRACE(("##> %s\n", __FUNCTION__)); ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \ ++ defined(BCMSDIO) ++ bcmsdh_oob_intr_set(0); ++#endif /* (OOB_INTR_ONLY) */ ++ return 0; ++} ++ ++static int wifi_plat_dev_drv_resume(struct platform_device *pdev) ++{ ++ DHD_TRACE(("##> %s\n", __FUNCTION__)); ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \ ++ defined(BCMSDIO) ++ if (dhd_os_check_if_up(wl_cfg80211_get_dhdp())) ++ bcmsdh_oob_intr_set(1); ++#endif /* (OOB_INTR_ONLY) */ ++ return 0; ++} ++ ++#ifdef CONFIG_DTS ++static const struct of_device_id wifi_device_dt_match[] = { ++ { .compatible = "android,bcmdhd_wlan", }, ++ {}, ++}; ++#endif /* CONFIG_DTS */ ++ ++static struct platform_driver wifi_platform_dev_driver = { ++ .probe = wifi_plat_dev_drv_probe, ++ .remove = wifi_plat_dev_drv_remove, ++ .suspend = wifi_plat_dev_drv_suspend, ++ .resume = wifi_plat_dev_drv_resume, ++ .driver = { ++ .name = WIFI_PLAT_NAME, ++#ifdef CONFIG_DTS ++ .of_match_table = wifi_device_dt_match, ++#endif /* CONFIG_DTS */ ++ } ++}; ++ ++static struct platform_driver wifi_platform_dev_driver_legacy = { ++ .probe = wifi_plat_dev_drv_probe, ++ .remove = wifi_plat_dev_drv_remove, ++ .suspend = wifi_plat_dev_drv_suspend, ++ .resume = wifi_plat_dev_drv_resume, ++ .driver = { ++ .name = WIFI_PLAT_NAME2, ++ } ++}; ++ ++static int wifi_platdev_match(struct device *dev, void *data) ++{ ++ char *name = (char*)data; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ const struct platform_device *pdev = to_platform_device(dev); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ ++ if (strcmp(pdev->name, name) == 0) { ++ DHD_ERROR(("found wifi platform device %s\n", name)); ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++#endif ++ ++static int wifi_ctrlfunc_register_drv(void) ++{ ++ wifi_adapter_info_t *adapter; ++ ++#ifndef CUSTOMER_HW ++ int err = 0; ++ struct device *dev1, *dev2; ++ dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); ++ dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); ++#endif ++ ++#if !defined(CONFIG_DTS) && !defined(CUSTOMER_HW) ++ if (!dts_enabled) { ++ if (dev1 == NULL && dev2 == NULL) { ++ DHD_ERROR(("no wifi platform data, skip\n")); ++ return -ENXIO; ++ } ++ } ++#endif /* !defined(CONFIG_DTS) */ ++ ++ /* multi-chip support not enabled, build one adapter information for ++ * DHD (either SDIO, USB or PCIe) ++ */ ++ adapter = kzalloc(sizeof(wifi_adapter_info_t), GFP_KERNEL); ++ if (adapter == NULL) { ++ DHD_ERROR(("%s:adapter alloc failed", __FUNCTION__)); ++ return -ENOMEM; ++ } ++ adapter->name = "DHD generic adapter"; ++ adapter->bus_type = -1; ++ adapter->bus_num = -1; ++ adapter->slot_num = -1; ++ adapter->irq_num = -1; ++ is_power_on = FALSE; ++ wifi_plat_dev_probe_ret = 0; ++ dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL); ++ dhd_wifi_platdata->num_adapters = 1; ++ dhd_wifi_platdata->adapters = adapter; ++ init_waitqueue_head(&adapter->status_event); ++ ++#ifndef CUSTOMER_HW ++ if (dev1) { ++ err = platform_driver_register(&wifi_platform_dev_driver); ++ if (err) { ++ DHD_ERROR(("%s: failed to register wifi ctrl func driver\n", ++ __FUNCTION__)); ++ return err; ++ } ++ } ++ if (dev2) { ++ err = platform_driver_register(&wifi_platform_dev_driver_legacy); ++ if (err) { ++ DHD_ERROR(("%s: failed to register wifi ctrl func legacy driver\n", ++ __FUNCTION__)); ++ return err; ++ } ++ } ++#endif ++ ++#if !defined(CONFIG_DTS) ++ if (dts_enabled) { ++ struct resource *resource; ++ adapter->wifi_plat_data = (void *)&dhd_wlan_control; ++ resource = &dhd_wlan_resources; ++#ifdef CUSTOMER_HW ++ wifi_plat_dev_probe_ret = dhd_wlan_init_plat_data(); ++ if (wifi_plat_dev_probe_ret) ++ return wifi_plat_dev_probe_ret; ++#endif ++ adapter->irq_num = resource->start; ++ adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK; ++#ifdef DHD_ISR_NO_SUSPEND ++ adapter->intr_flags |= IRQF_NO_SUSPEND; ++#endif ++ wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); ++ } ++#endif /* !defined(CONFIG_DTS) */ ++ ++ ++#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW) ++ wifi_plat_dev_probe_ret = platform_driver_register(&wifi_platform_dev_driver); ++#endif /* CONFIG_DTS */ ++ ++ /* return probe function's return value if registeration succeeded */ ++ return wifi_plat_dev_probe_ret; ++} ++ ++void wifi_ctrlfunc_unregister_drv(void) ++{ ++#ifndef CONFIG_DTS ++ wifi_adapter_info_t *adapter; ++#endif ++ ++#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW) ++ DHD_ERROR(("unregister wifi platform drivers\n")); ++ platform_driver_unregister(&wifi_platform_dev_driver); ++#else ++#ifndef CUSTOMER_HW ++ struct device *dev1, *dev2; ++ dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); ++ dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); ++ if (!dts_enabled) ++ if (dev1 == NULL && dev2 == NULL) ++ return; ++#endif ++ DHD_ERROR(("unregister wifi platform drivers\n")); ++#ifndef CUSTOMER_HW ++ if (dev1) ++ platform_driver_unregister(&wifi_platform_dev_driver); ++ if (dev2) ++ platform_driver_unregister(&wifi_platform_dev_driver_legacy); ++#endif ++ if (dts_enabled) { ++ adapter = &dhd_wifi_platdata->adapters[0]; ++ if (is_power_on) { ++ wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); ++ } ++ wifi_platform_bus_enumerate(adapter, FALSE); ++ } ++#endif /* !defined(CONFIG_DTS) */ ++ ++#if defined(CUSTOMER_HW) ++ dhd_wlan_deinit_plat_data(adapter); ++#endif ++ ++ kfree(dhd_wifi_platdata->adapters); ++ dhd_wifi_platdata->adapters = NULL; ++ dhd_wifi_platdata->num_adapters = 0; ++ kfree(dhd_wifi_platdata); ++ dhd_wifi_platdata = NULL; ++} ++ ++#ifndef CUSTOMER_HW ++static int bcmdhd_wifi_plat_dev_drv_probe(struct platform_device *pdev) ++{ ++ dhd_wifi_platdata = (bcmdhd_wifi_platdata_t *)(pdev->dev.platform_data); ++ ++ return dhd_wifi_platform_load(); ++} ++ ++static int bcmdhd_wifi_plat_dev_drv_remove(struct platform_device *pdev) ++{ ++ int i; ++ wifi_adapter_info_t *adapter; ++ ASSERT(dhd_wifi_platdata != NULL); ++ ++ /* power down all adapters */ ++ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { ++ adapter = &dhd_wifi_platdata->adapters[i]; ++ wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); ++ wifi_platform_bus_enumerate(adapter, FALSE); ++ } ++ return 0; ++} ++ ++static struct platform_driver dhd_wifi_platform_dev_driver = { ++ .probe = bcmdhd_wifi_plat_dev_drv_probe, ++ .remove = bcmdhd_wifi_plat_dev_drv_remove, ++ .driver = { ++ .name = WIFI_PLAT_EXT, ++ } ++}; ++#endif ++ ++int dhd_wifi_platform_register_drv(void) ++{ ++ int err = 0; ++#ifndef CUSTOMER_HW ++ struct device *dev; ++ ++ /* register Broadcom wifi platform data driver if multi-chip is enabled, ++ * otherwise use Android style wifi platform data (aka wifi control function) ++ * if it exists ++ * ++ * to support multi-chip DHD, Broadcom wifi platform data device must ++ * be added in kernel early boot (e.g. board config file). ++ */ ++ if (cfg_multichip) { ++ dev = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_EXT, wifi_platdev_match); ++ if (dev == NULL) { ++ DHD_ERROR(("bcmdhd wifi platform data device not found!!\n")); ++ return -ENXIO; ++ } ++ err = platform_driver_register(&dhd_wifi_platform_dev_driver); ++ } else ++#endif ++ { ++ err = wifi_ctrlfunc_register_drv(); ++ ++ /* no wifi ctrl func either, load bus directly and ignore this error */ ++ if (err) { ++ if (err == -ENXIO) { ++ /* wifi ctrl function does not exist */ ++ err = dhd_wifi_platform_load(); ++ } else { ++ /* unregister driver due to initialization failure */ ++ wifi_ctrlfunc_unregister_drv(); ++ } ++ } ++ } ++ ++ return err; ++} ++ ++#ifdef BCMPCIE ++static int dhd_wifi_platform_load_pcie(void) ++{ ++ int err = 0; ++ int i; ++ wifi_adapter_info_t *adapter; ++ ++ BCM_REFERENCE(i); ++ BCM_REFERENCE(adapter); ++ ++ if (dhd_wifi_platdata == NULL) { ++ err = dhd_bus_register(); ++ } else { ++ if (dhd_download_fw_on_driverload) { ++ /* power up all adapters */ ++ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { ++ int retry = POWERUP_MAX_RETRY; ++ adapter = &dhd_wifi_platdata->adapters[i]; ++ ++ DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); ++ DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", ++ adapter->irq_num, adapter->intr_flags, adapter->fw_path, ++ adapter->nv_path)); ++ DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", ++ adapter->bus_type, adapter->bus_num, adapter->slot_num)); ++ ++ do { ++ err = wifi_platform_set_power(adapter, ++ TRUE, WIFI_TURNON_DELAY); ++ if (err) { ++ DHD_ERROR(("failed to power up %s," ++ " %d retry left\n", ++ adapter->name, retry)); ++ /* WL_REG_ON state unknown, Power off forcely */ ++ wifi_platform_set_power(adapter, ++ FALSE, WIFI_TURNOFF_DELAY); ++ continue; ++ } else { ++ err = wifi_platform_bus_enumerate(adapter, TRUE); ++ if (err) { ++ DHD_ERROR(("failed to enumerate bus %s, " ++ "%d retry left\n", ++ adapter->name, retry)); ++ wifi_platform_set_power(adapter, FALSE, ++ WIFI_TURNOFF_DELAY); ++ } else { ++ break; ++ } ++ } ++ } while (retry--); ++ ++ if (retry < 0) { ++ DHD_ERROR(("failed to power up %s, max retry reached**\n", ++ adapter->name)); ++ return -ENODEV; ++ } ++ } ++ } ++ ++ err = dhd_bus_register(); ++ ++ if (err) { ++ DHD_ERROR(("%s: pcie_register_driver failed\n", __FUNCTION__)); ++ if (dhd_download_fw_on_driverload) { ++ /* power down all adapters */ ++ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { ++ adapter = &dhd_wifi_platdata->adapters[i]; ++ wifi_platform_bus_enumerate(adapter, FALSE); ++ wifi_platform_set_power(adapter, ++ FALSE, WIFI_TURNOFF_DELAY); ++ } ++ } ++ } ++ } ++ ++ return err; ++} ++#else ++static int dhd_wifi_platform_load_pcie(void) ++{ ++ return 0; ++} ++#endif /* BCMPCIE */ ++ ++ ++void dhd_wifi_platform_unregister_drv(void) ++{ ++#ifndef CUSTOMER_HW ++ if (cfg_multichip) ++ platform_driver_unregister(&dhd_wifi_platform_dev_driver); ++ else ++#endif ++ wifi_ctrlfunc_unregister_drv(); ++} ++ ++extern int dhd_watchdog_prio; ++extern int dhd_dpc_prio; ++extern uint dhd_deferred_tx; ++#if defined(BCMLXSDMMC) || defined(BCMDBUS) ++extern struct semaphore dhd_registration_sem; ++#endif ++ ++#ifdef BCMSDIO ++static int dhd_wifi_platform_load_sdio(void) ++{ ++ int i; ++ int err = 0; ++ wifi_adapter_info_t *adapter; ++ ++ BCM_REFERENCE(i); ++ BCM_REFERENCE(adapter); ++ /* Sanity check on the module parameters ++ * - Both watchdog and DPC as tasklets are ok ++ * - If both watchdog and DPC are threads, TX must be deferred ++ */ ++ if (!(dhd_watchdog_prio < 0 && dhd_dpc_prio < 0) && ++ !(dhd_watchdog_prio >= 0 && dhd_dpc_prio >= 0 && dhd_deferred_tx)) ++ return -EINVAL; ++ ++#if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD) ++ sema_init(&dhd_registration_sem, 0); ++#endif ++ ++ if (dhd_wifi_platdata == NULL) { ++ DHD_ERROR(("DHD wifi platform data is required for Android build\n")); ++ DHD_ERROR(("DHD registeing bus directly\n")); ++ /* x86 bring-up PC needs no power-up operations */ ++ err = dhd_bus_register(); ++ return err; ++ } ++ ++#if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD) ++ /* power up all adapters */ ++ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { ++ bool chip_up = FALSE; ++ int retry = POWERUP_MAX_RETRY; ++ struct semaphore dhd_chipup_sem; ++ ++ adapter = &dhd_wifi_platdata->adapters[i]; ++ ++ DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); ++ DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", ++ adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path)); ++ DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", ++ adapter->bus_type, adapter->bus_num, adapter->slot_num)); ++ ++ do { ++ sema_init(&dhd_chipup_sem, 0); ++ err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem); ++ if (err) { ++ DHD_ERROR(("%s dhd_bus_reg_sdio_notify fail(%d)\n\n", ++ __FUNCTION__, err)); ++ return err; ++ } ++ ++#ifdef CUSTOMER_HW_INGENIC ++ /*case: sdio device probed earlier than wifi driver.*/ ++ if(down_trylock(&dhd_chipup_sem) == 0) { ++ dhd_bus_unreg_sdio_notify(); ++ chip_up = TRUE; ++ break; ++ } ++#endif ++ ++ err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); ++ if (err) { ++ dhd_bus_unreg_sdio_notify(); ++ /* WL_REG_ON state unknown, Power off forcely */ ++ wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); ++ continue; ++ } else { ++ wifi_platform_bus_enumerate(adapter, TRUE); ++ } ++ ++ if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { ++ dhd_bus_unreg_sdio_notify(); ++ chip_up = TRUE; ++ break; ++ } ++ ++ DHD_ERROR(("failed to power up %s, %d retry left\n", adapter->name, retry)); ++ dhd_bus_unreg_sdio_notify(); ++ wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); ++ wifi_platform_bus_enumerate(adapter, FALSE); ++ } while (retry--); ++ ++ if (!chip_up) { ++ DHD_ERROR(("failed to power up %s, max retry reached**\n", adapter->name)); ++ return -ENODEV; ++ } ++ ++ } ++ ++ err = dhd_bus_register(); ++ ++ if (err) { ++ DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* ++ * Wait till MMC sdio_register_driver callback called and made driver attach. ++ * It's needed to make sync up exit from dhd insmod and ++ * Kernel MMC sdio device callback registration ++ */ ++ err = down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); ++ if (err) { ++ DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__)); ++ dhd_bus_unregister(); ++ goto fail; ++ } ++ ++ return err; ++ ++fail: ++ /* power down all adapters */ ++ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { ++ adapter = &dhd_wifi_platdata->adapters[i]; ++ wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); ++ wifi_platform_bus_enumerate(adapter, FALSE); ++ } ++#else ++ /* x86 bring-up PC needs no power-up operations */ ++ err = dhd_bus_register(); ++#endif ++ ++ return err; ++} ++#else /* BCMSDIO */ ++static int dhd_wifi_platform_load_sdio(void) ++{ ++ return 0; ++} ++#endif /* BCMSDIO */ ++ ++#ifdef BCMDBUS ++static int dhd_wifi_platform_load_usb(void) ++{ ++ int err = 0; ++#if !defined(DHD_PRELOAD) ++ wifi_adapter_info_t *adapter; ++ s32 timeout = -1; ++ int i; ++ enum wifi_adapter_status wait_status; ++#endif ++ ++ err = dhd_bus_register(); ++ if (err) { ++ DHD_ERROR(("%s: usb_register failed\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++#if !defined(DHD_PRELOAD) ++ /* power up all adapters */ ++ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { ++ adapter = &dhd_wifi_platdata->adapters[i]; ++ DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); ++ DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", ++ adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path)); ++ DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", ++ adapter->bus_type, adapter->bus_num, adapter->slot_num)); ++ err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); ++ if (err) { ++ DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name)); ++ goto fail; ++ } ++ if (dhd_download_fw_on_driverload) ++ wait_status = WIFI_STATUS_ATTACH; ++ else ++ wait_status = WIFI_STATUS_DETTACH; ++ timeout = wait_event_interruptible_timeout(adapter->status_event, ++ wifi_get_adapter_status(adapter, wait_status), ++ msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); ++ if (timeout <= 0) { ++ err = -1; ++ DHD_ERROR(("%s: usb_register_driver timeout\n", __FUNCTION__)); ++ goto fail; ++ } ++ } ++#endif ++ ++exit: ++ return err; ++ ++#if !defined(DHD_PRELOAD) ++fail: ++ dhd_bus_unregister(); ++ /* power down all adapters */ ++ for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { ++ adapter = &dhd_wifi_platdata->adapters[i]; ++ wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); ++ } ++ ++ return err; ++#endif ++} ++#else /* BCMDBUS */ ++static int dhd_wifi_platform_load_usb(void) ++{ ++ return 0; ++} ++#endif /* BCMDBUS */ ++ ++static int dhd_wifi_platform_load() ++{ ++ int err = 0; ++ printf("%s: Enter\n", __FUNCTION__); ++ ++ wl_android_init(); ++ ++ if ((err = dhd_wifi_platform_load_usb())) ++ goto end; ++ else if ((err = dhd_wifi_platform_load_sdio())) ++ goto end; ++ else ++ err = dhd_wifi_platform_load_pcie(); ++ ++end: ++ if (err) ++ wl_android_exit(); ++#if !defined(MULTIPLE_SUPPLICANT) ++ else ++ wl_android_post_init(); ++#endif ++ ++ return err; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_sched.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_sched.c +new file mode 100644 +index 000000000..88c0cce63 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_sched.c +@@ -0,0 +1,51 @@ ++/* ++ * Expose some of the kernel scheduler routines ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_linux_sched.c 514727 2014-11-12 03:02:48Z $ ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++int setScheduler(struct task_struct *p, int policy, struct sched_param *param) ++{ ++ int rc = 0; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ rc = sched_setscheduler(p, policy, param); ++#endif /* LinuxVer */ ++ return rc; ++} ++ ++int get_scheduler_policy(struct task_struct *p) ++{ ++ int rc = SCHED_NORMAL; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ rc = p->policy; ++#endif /* LinuxVer */ ++ return rc; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_wq.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_wq.c +new file mode 100644 +index 000000000..1cba8d140 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_wq.c +@@ -0,0 +1,379 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), Generic work queue framework ++ * Generic interface to handle dhd deferred work events ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_linux_wq.c 641330 2016-06-02 06:55:00Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++typedef struct dhd_deferred_event { ++ u8 event; /* holds the event */ ++ void *event_data; /* holds event specific data */ ++ event_handler_t event_handler; ++ unsigned long pad; /* for memory alignment to power of 2 */ ++} dhd_deferred_event_t; ++ ++#define DEFRD_EVT_SIZE (sizeof(dhd_deferred_event_t)) ++ ++/* ++ * work events may occur simultaneously. ++ * can hold upto 64 low priority events and 16 high priority events ++ */ ++#define DHD_PRIO_WORK_FIFO_SIZE (16 * DEFRD_EVT_SIZE) ++#define DHD_WORK_FIFO_SIZE (64 * DEFRD_EVT_SIZE) ++ ++#define DHD_FIFO_HAS_FREE_SPACE(fifo) \ ++ ((fifo) && (kfifo_avail(fifo) >= DEFRD_EVT_SIZE)) ++#define DHD_FIFO_HAS_ENOUGH_DATA(fifo) \ ++ ((fifo) && (kfifo_len(fifo) >= DEFRD_EVT_SIZE)) ++ ++struct dhd_deferred_wq { ++ struct work_struct deferred_work; /* should be the first member */ ++ ++ struct kfifo *prio_fifo; ++ struct kfifo *work_fifo; ++ u8 *prio_fifo_buf; ++ u8 *work_fifo_buf; ++ spinlock_t work_lock; ++ void *dhd_info; /* review: does it require */ ++}; ++ ++static inline struct kfifo* ++dhd_kfifo_init(u8 *buf, int size, spinlock_t *lock) ++{ ++ struct kfifo *fifo; ++ gfp_t flags = CAN_SLEEP() ? GFP_KERNEL : GFP_ATOMIC; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) ++ fifo = kfifo_init(buf, size, flags, lock); ++#else ++ fifo = (struct kfifo *)kzalloc(sizeof(struct kfifo), flags); ++ if (!fifo) { ++ return NULL; ++ } ++ kfifo_init(fifo, buf, size); ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ ++ return fifo; ++} ++ ++static inline void ++dhd_kfifo_free(struct kfifo *fifo) ++{ ++ kfifo_free(fifo); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) ++ /* FC11 releases the fifo memory */ ++ kfree(fifo); ++#endif ++} ++ ++/* deferred work functions */ ++static void dhd_deferred_work_handler(struct work_struct *data); ++ ++void* ++dhd_deferred_work_init(void *dhd_info) ++{ ++ struct dhd_deferred_wq *work = NULL; ++ u8* buf; ++ unsigned long fifo_size = 0; ++ gfp_t flags = CAN_SLEEP() ? GFP_KERNEL : GFP_ATOMIC; ++ ++ if (!dhd_info) { ++ DHD_ERROR(("%s: dhd info not initialized\n", __FUNCTION__)); ++ goto return_null; ++ } ++ ++ work = (struct dhd_deferred_wq *)kzalloc(sizeof(struct dhd_deferred_wq), ++ flags); ++ if (!work) { ++ DHD_ERROR(("%s: work queue creation failed\n", __FUNCTION__)); ++ goto return_null; ++ } ++ ++ INIT_WORK((struct work_struct *)work, dhd_deferred_work_handler); ++ ++ /* initialize event fifo */ ++ spin_lock_init(&work->work_lock); ++ ++ /* allocate buffer to hold prio events */ ++ fifo_size = DHD_PRIO_WORK_FIFO_SIZE; ++ fifo_size = is_power_of_2(fifo_size) ? fifo_size : ++ roundup_pow_of_two(fifo_size); ++ buf = (u8*)kzalloc(fifo_size, flags); ++ if (!buf) { ++ DHD_ERROR(("%s: prio work fifo allocation failed\n", ++ __FUNCTION__)); ++ goto return_null; ++ } ++ ++ /* Initialize prio event fifo */ ++ work->prio_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock); ++ if (!work->prio_fifo) { ++ kfree(buf); ++ goto return_null; ++ } ++ ++ /* allocate buffer to hold work events */ ++ fifo_size = DHD_WORK_FIFO_SIZE; ++ fifo_size = is_power_of_2(fifo_size) ? fifo_size : ++ roundup_pow_of_two(fifo_size); ++ buf = (u8*)kzalloc(fifo_size, flags); ++ if (!buf) { ++ DHD_ERROR(("%s: work fifo allocation failed\n", __FUNCTION__)); ++ goto return_null; ++ } ++ ++ /* Initialize event fifo */ ++ work->work_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock); ++ if (!work->work_fifo) { ++ kfree(buf); ++ goto return_null; ++ } ++ ++ work->dhd_info = dhd_info; ++ DHD_ERROR(("%s: work queue initialized\n", __FUNCTION__)); ++ return work; ++ ++return_null: ++ if (work) { ++ dhd_deferred_work_deinit(work); ++ } ++ ++ return NULL; ++} ++ ++void ++dhd_deferred_work_deinit(void *work) ++{ ++ struct dhd_deferred_wq *deferred_work = work; ++ ++ ++ if (!deferred_work) { ++ DHD_ERROR(("%s: deferred work has been freed already\n", ++ __FUNCTION__)); ++ return; ++ } ++ ++ /* cancel the deferred work handling */ ++ cancel_work_sync((struct work_struct *)deferred_work); ++ ++ /* ++ * free work event fifo. ++ * kfifo_free frees locally allocated fifo buffer ++ */ ++ if (deferred_work->prio_fifo) { ++ dhd_kfifo_free(deferred_work->prio_fifo); ++ } ++ ++ if (deferred_work->work_fifo) { ++ dhd_kfifo_free(deferred_work->work_fifo); ++ } ++ ++ kfree(deferred_work); ++} ++ ++/* select kfifo according to priority */ ++static inline struct kfifo * ++dhd_deferred_work_select_kfifo(struct dhd_deferred_wq *deferred_wq, ++ u8 priority) ++{ ++ if (priority == DHD_WQ_WORK_PRIORITY_HIGH) { ++ return deferred_wq->prio_fifo; ++ } else if (priority == DHD_WQ_WORK_PRIORITY_LOW) { ++ return deferred_wq->work_fifo; ++ } else { ++ return NULL; ++ } ++} ++ ++/* ++ * Prepares event to be queued ++ * Schedules the event ++ */ ++int ++dhd_deferred_schedule_work(void *workq, void *event_data, u8 event, ++ event_handler_t event_handler, u8 priority) ++{ ++ struct dhd_deferred_wq *deferred_wq = (struct dhd_deferred_wq *)workq; ++ struct kfifo *fifo; ++ dhd_deferred_event_t deferred_event; ++ int bytes_copied = 0; ++ ++ if (!deferred_wq) { ++ DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__)); ++ ASSERT(0); ++ return DHD_WQ_STS_UNINITIALIZED; ++ } ++ ++ if (!event || (event >= DHD_MAX_WQ_EVENTS)) { ++ DHD_ERROR(("%s: unknown event, event=%d\n", __FUNCTION__, ++ event)); ++ return DHD_WQ_STS_UNKNOWN_EVENT; ++ } ++ ++ if (!priority || (priority >= DHD_WQ_MAX_PRIORITY)) { ++ DHD_ERROR(("%s: unknown priority, priority=%d\n", ++ __FUNCTION__, priority)); ++ return DHD_WQ_STS_UNKNOWN_PRIORITY; ++ } ++ ++ /* ++ * default element size is 1, which can be changed ++ * using kfifo_esize(). Older kernel(FC11) doesn't support ++ * changing element size. For compatibility changing ++ * element size is not prefered ++ */ ++ ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); ++ ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); ++ ++ deferred_event.event = event; ++ deferred_event.event_data = event_data; ++ deferred_event.event_handler = event_handler; ++ ++ fifo = dhd_deferred_work_select_kfifo(deferred_wq, priority); ++ if (DHD_FIFO_HAS_FREE_SPACE(fifo)) { ++ bytes_copied = kfifo_in_spinlocked(fifo, &deferred_event, ++ DEFRD_EVT_SIZE, &deferred_wq->work_lock); ++ } ++ if (bytes_copied != DEFRD_EVT_SIZE) { ++ DHD_ERROR(("%s: failed to schedule deferred work, " ++ "priority=%d, bytes_copied=%d\n", __FUNCTION__, ++ priority, bytes_copied)); ++ return DHD_WQ_STS_SCHED_FAILED; ++ } ++ schedule_work((struct work_struct *)deferred_wq); ++ return DHD_WQ_STS_OK; ++} ++ ++static bool ++dhd_get_scheduled_work(struct dhd_deferred_wq *deferred_wq, ++ dhd_deferred_event_t *event) ++{ ++ int bytes_copied = 0; ++ ++ if (!deferred_wq) { ++ DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__)); ++ return DHD_WQ_STS_UNINITIALIZED; ++ } ++ ++ /* ++ * default element size is 1 byte, which can be changed ++ * using kfifo_esize(). Older kernel(FC11) doesn't support ++ * changing element size. For compatibility changing ++ * element size is not prefered ++ */ ++ ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); ++ ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); ++ ++ /* handle priority work */ ++ if (DHD_FIFO_HAS_ENOUGH_DATA(deferred_wq->prio_fifo)) { ++ bytes_copied = kfifo_out_spinlocked(deferred_wq->prio_fifo, ++ event, DEFRD_EVT_SIZE, &deferred_wq->work_lock); ++ } ++ ++ /* handle normal work if priority work doesn't have enough data */ ++ if ((bytes_copied != DEFRD_EVT_SIZE) && ++ DHD_FIFO_HAS_ENOUGH_DATA(deferred_wq->work_fifo)) { ++ bytes_copied = kfifo_out_spinlocked(deferred_wq->work_fifo, ++ event, DEFRD_EVT_SIZE, &deferred_wq->work_lock); ++ } ++ ++ return (bytes_copied == DEFRD_EVT_SIZE); ++} ++ ++static inline void ++dhd_deferred_dump_work_event(dhd_deferred_event_t *work_event) ++{ ++ if (!work_event) { ++ DHD_ERROR(("%s: work_event is null\n", __FUNCTION__)); ++ return; ++ } ++ ++ DHD_ERROR(("%s: work_event->event = %d\n", __FUNCTION__, ++ work_event->event)); ++ DHD_ERROR(("%s: work_event->event_data = %p\n", __FUNCTION__, ++ work_event->event_data)); ++ DHD_ERROR(("%s: work_event->event_handler = %p\n", __FUNCTION__, ++ work_event->event_handler)); ++} ++ ++/* ++ * Called when work is scheduled ++ */ ++static void ++dhd_deferred_work_handler(struct work_struct *work) ++{ ++ struct dhd_deferred_wq *deferred_work = (struct dhd_deferred_wq *)work; ++ dhd_deferred_event_t work_event; ++ ++ if (!deferred_work) { ++ DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__)); ++ return; ++ } ++ ++ do { ++ if (!dhd_get_scheduled_work(deferred_work, &work_event)) { ++ DHD_TRACE(("%s: no event to handle\n", __FUNCTION__)); ++ break; ++ } ++ ++ if (work_event.event >= DHD_MAX_WQ_EVENTS) { ++ DHD_ERROR(("%s: unknown event\n", __FUNCTION__)); ++ dhd_deferred_dump_work_event(&work_event); ++ ASSERT(work_event.event < DHD_MAX_WQ_EVENTS); ++ continue; ++ } ++ ++ ++ if (work_event.event_handler) { ++ work_event.event_handler(deferred_work->dhd_info, ++ work_event.event_data, work_event.event); ++ } else { ++ DHD_ERROR(("%s: event handler is null\n", ++ __FUNCTION__)); ++ dhd_deferred_dump_work_event(&work_event); ++ ASSERT(work_event.event_handler != NULL); ++ } ++ } while (1); ++ ++ return; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_wq.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_wq.h +new file mode 100644 +index 000000000..9c51d0665 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_linux_wq.h +@@ -0,0 +1,81 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), Generic work queue framework ++ * Generic interface to handle dhd deferred work events ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_linux_wq.h 704361 2017-06-13 08:50:38Z $ ++ */ ++#ifndef _dhd_linux_wq_h_ ++#define _dhd_linux_wq_h_ ++/* ++ * Work event definitions ++ */ ++enum _wq_event { ++ DHD_WQ_WORK_IF_ADD = 1, ++ DHD_WQ_WORK_IF_DEL, ++ DHD_WQ_WORK_SET_MAC, ++ DHD_WQ_WORK_SET_MCAST_LIST, ++ DHD_WQ_WORK_IPV6_NDO, ++ DHD_WQ_WORK_HANG_MSG, ++ DHD_WQ_WORK_SOC_RAM_DUMP, ++ DHD_WQ_WORK_DHD_LOG_DUMP, ++ DHD_WQ_WORK_INFORM_DHD_MON, ++ DHD_WQ_WORK_EVENT_LOGTRACE, ++ DHD_WQ_WORK_DMA_LB_MEM_REL, ++ DHD_WQ_WORK_DEBUG_UART_DUMP, ++ DHD_WQ_WORK_SSSR_DUMP, ++ DHD_WQ_WORK_PKTLOG_DUMP, ++#ifdef DHD_UPDATE_INTF_MAC ++ DHD_WQ_WORK_IF_UPDATE, ++#endif /* DHD_UPDATE_INTF_MAC */ ++ DHD_MAX_WQ_EVENTS ++}; ++ ++/* ++ * Work event priority ++ */ ++enum wq_priority { ++ DHD_WQ_WORK_PRIORITY_LOW = 1, ++ DHD_WQ_WORK_PRIORITY_HIGH, ++ DHD_WQ_MAX_PRIORITY ++}; ++ ++/* ++ * Error definitions ++ */ ++#define DHD_WQ_STS_OK 0 ++#define DHD_WQ_STS_FAILED -1 /* General failure */ ++#define DHD_WQ_STS_UNINITIALIZED -2 ++#define DHD_WQ_STS_SCHED_FAILED -3 ++#define DHD_WQ_STS_UNKNOWN_EVENT -4 ++#define DHD_WQ_STS_UNKNOWN_PRIORITY -5 ++ ++typedef void (*event_handler_t)(void *handle, void *event_data, u8 event); ++ ++void *dhd_deferred_work_init(void *dhd); ++void dhd_deferred_work_deinit(void *workq); ++int dhd_deferred_schedule_work(void *workq, void *event_data, u8 event, ++ event_handler_t evt_handler, u8 priority); ++#endif /* _dhd_linux_wq_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_mschdbg.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_mschdbg.c +new file mode 100644 +index 000000000..c1032f203 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_mschdbg.c +@@ -0,0 +1,747 @@ ++/* ++ * DHD debugability support ++ * ++ * <> ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_mschdbg.c 639872 2016-05-25 05:39:30Z $ ++ */ ++#ifdef SHOW_LOGTRACE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++static const char *head_log = ""; ++#define MSCH_EVENT_HEAD(space) \ ++ do { \ ++ MSCH_EVENT(("%s_E: ", head_log)); \ ++ if (space > 0) { \ ++ int ii; \ ++ for (ii = 0; ii < space; ii += 4) MSCH_EVENT((" ")); \ ++ } \ ++ } while (0) ++#define MSCH_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) ++ ++static uint64 solt_start_time[4], req_start_time[4], profiler_start_time[4]; ++static uint32 solt_chanspec[4] = {0, }, req_start[4] = {0, }; ++static bool lastMessages = FALSE; ++ ++#define US_PRE_SEC 1000000 ++ ++static void dhd_mschdbg_us_to_sec(uint32 time_h, uint32 time_l, uint32 *sec, uint32 *remain) ++{ ++ uint64 cur_time = ((uint64)(ntoh32(time_h)) << 32) | ntoh32(time_l); ++ uint64 r, u = 0; ++ ++ r = cur_time; ++ while (time_h != 0) { ++ u += (uint64)((0xffffffff / US_PRE_SEC)) * time_h; ++ r = cur_time - u * US_PRE_SEC; ++ time_h = (uint32)(r >> 32); ++ } ++ ++ *sec = (uint32)(u + ((uint32)(r) / US_PRE_SEC)); ++ *remain = (uint32)(r) % US_PRE_SEC; ++} ++ ++static char *dhd_mschdbg_display_time(uint32 time_h, uint32 time_l) ++{ ++ static char display_time[32]; ++ uint32 s, ss; ++ ++ if (time_h == 0xffffffff && time_l == 0xffffffff) { ++ snprintf(display_time, 31, "-1"); ++ } else { ++ dhd_mschdbg_us_to_sec(time_h, time_l, &s, &ss); ++ snprintf(display_time, 31, "%d.%06d", s, ss); ++ } ++ return display_time; ++} ++ ++static void ++dhd_mschdbg_chanspec_list(int sp, char *data, uint16 ptr, uint16 chanspec_cnt) ++{ ++ int i, cnt = (int)ntoh16(chanspec_cnt); ++ uint16 *chanspec_list = (uint16 *)(data + ntoh16(ptr)); ++ char buf[CHANSPEC_STR_LEN]; ++ chanspec_t c; ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT((":")); ++ for (i = 0; i < cnt; i++) { ++ c = (chanspec_t)ntoh16(chanspec_list[i]); ++ MSCH_EVENT((" %s", wf_chspec_ntoa(c, buf))); ++ } ++ MSCH_EVENT(("\n")); ++} ++ ++static void ++dhd_mschdbg_elem_list(int sp, char *title, char *data, uint16 ptr, uint16 list_cnt) ++{ ++ int i, cnt = (int)ntoh16(list_cnt); ++ uint32 *list = (uint32 *)(data + ntoh16(ptr)); ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT(("%s_list: ", title)); ++ for (i = 0; i < cnt; i++) { ++ MSCH_EVENT(("0x%08x->", ntoh32(list[i]))); ++ } ++ MSCH_EVENT(("null\n")); ++} ++ ++static void ++dhd_mschdbg_req_param_profiler_event_data(int sp, int ver, char *data, uint16 ptr) ++{ ++ int sn = sp + 4; ++ msch_req_param_profiler_event_data_t *p = ++ (msch_req_param_profiler_event_data_t *)(data + ntoh16(ptr)); ++ uint32 type, flags; ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT(("\n")); ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("req_type: ")); ++ ++ type = p->req_type; ++ if (type < 4) { ++ char *req_type[] = {"fixed", "start-flexible", "duration-flexible", ++ "both-flexible"}; ++ MSCH_EVENT(("%s", req_type[type])); ++ } ++ else ++ MSCH_EVENT(("unknown(%d)", type)); ++ ++ flags = ntoh16(p->flags); ++ if (flags & WL_MSCH_REQ_FLAGS_CHAN_CONTIGUOUS) ++ MSCH_EVENT((", CHAN_CONTIGUOUS")); ++ if (flags & WL_MSCH_REQ_FLAGS_MERGE_CONT_SLOTS) ++ MSCH_EVENT((", MERGE_CONT_SLOTS")); ++ if (flags & WL_MSCH_REQ_FLAGS_PREMTABLE) ++ MSCH_EVENT((", PREMTABLE")); ++ if (flags & WL_MSCH_REQ_FLAGS_PREMT_CURTS) ++ MSCH_EVENT((", PREMT_CURTS")); ++ if (flags & WL_MSCH_REQ_FLAGS_PREMT_IMMEDIATE) ++ MSCH_EVENT((", PREMT_IMMEDIATE")); ++ MSCH_EVENT((", priority: %d\n", p->priority)); ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("start-time: %s, duration: %d(us), interval: %d(us)\n", ++ dhd_mschdbg_display_time(p->start_time_h, p->start_time_l), ++ ntoh32(p->duration), ntoh32(p->interval))); ++ ++ if (type == WL_MSCH_RT_DUR_FLEX) { ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("dur_flex: %d(us)\n", ntoh32(p->flex.dur_flex))); ++ } else if (type == WL_MSCH_RT_BOTH_FLEX) { ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("min_dur: %d(us), max_away_dur: %d(us)\n", ++ ntoh32(p->flex.bf.min_dur), ntoh32(p->flex.bf.max_away_dur))); ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("hi_prio_time: %s, hi_prio_interval: %d(us)\n", ++ dhd_mschdbg_display_time(p->flex.bf.hi_prio_time_h, ++ p->flex.bf.hi_prio_time_l), ++ ntoh32(p->flex.bf.hi_prio_interval))); ++ } ++} ++ ++static void ++dhd_mschdbg_timeslot_profiler_event_data(int sp, int ver, char *title, char *data, ++ uint16 ptr, bool empty) ++{ ++ int s, sn = sp + 4; ++ msch_timeslot_profiler_event_data_t *p = ++ (msch_timeslot_profiler_event_data_t *)(data + ntoh16(ptr)); ++ char *state[] = {"NONE", "CHN_SW", "ONCHAN_FIRE", "OFF_CHN_PREP", ++ "OFF_CHN_DONE", "TS_COMPLETE"}; ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT(("<%s timeslot>: ", title)); ++ if (empty) { ++ MSCH_EVENT((" null\n")); ++ return; ++ } ++ else ++ MSCH_EVENT(("0x%08x\n", ntoh32(p->p_timeslot))); ++ ++ s = (int)(ntoh32(p->state)); ++ if (s > 5) s = 0; ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("id: %d, state[%d]: %s, chan_ctxt: [0x%08x]\n", ++ ntoh32(p->timeslot_id), ntoh32(p->state), state[s], ntoh32(p->p_chan_ctxt))); ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("fire_time: %s", ++ dhd_mschdbg_display_time(p->fire_time_h, p->fire_time_l))); ++ ++ MSCH_EVENT((", pre_start_time: %s", ++ dhd_mschdbg_display_time(p->pre_start_time_h, p->pre_start_time_l))); ++ ++ MSCH_EVENT((", end_time: %s", ++ dhd_mschdbg_display_time(p->end_time_h, p->end_time_l))); ++ ++ MSCH_EVENT((", sch_dur: %s\n", ++ dhd_mschdbg_display_time(p->sch_dur_h, p->sch_dur_l))); ++} ++ ++static void ++dhd_mschdbg_req_timing_profiler_event_data(int sp, int ver, char *title, char *data, ++ uint16 ptr, bool empty) ++{ ++ int sn = sp + 4; ++ msch_req_timing_profiler_event_data_t *p = ++ (msch_req_timing_profiler_event_data_t *)(data + ntoh16(ptr)); ++ uint32 type; ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT(("<%s req_timing>: ", title)); ++ if (empty) { ++ MSCH_EVENT((" null\n")); ++ return; ++ } ++ else ++ MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n", ++ ntoh32(p->p_req_timing), ntoh32(p->p_prev), ntoh32(p->p_next))); ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("flags:")); ++ type = ntoh16(p->flags); ++ if ((type & 0x7f) == 0) ++ MSCH_EVENT((" NONE")); ++ else { ++ if (type & WL_MSCH_RC_FLAGS_ONCHAN_FIRE) ++ MSCH_EVENT((" ONCHAN_FIRE")); ++ if (type & WL_MSCH_RC_FLAGS_START_FIRE_DONE) ++ MSCH_EVENT((" START_FIRE")); ++ if (type & WL_MSCH_RC_FLAGS_END_FIRE_DONE) ++ MSCH_EVENT((" END_FIRE")); ++ if (type & WL_MSCH_RC_FLAGS_ONFIRE_DONE) ++ MSCH_EVENT((" ONFIRE_DONE")); ++ if (type & WL_MSCH_RC_FLAGS_SPLIT_SLOT_START) ++ MSCH_EVENT((" SPLIT_SLOT_START")); ++ if (type & WL_MSCH_RC_FLAGS_SPLIT_SLOT_END) ++ MSCH_EVENT((" SPLIT_SLOT_END")); ++ if (type & WL_MSCH_RC_FLAGS_PRE_ONFIRE_DONE) ++ MSCH_EVENT((" PRE_ONFIRE_DONE")); ++ } ++ MSCH_EVENT(("\n")); ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("pre_start_time: %s", ++ dhd_mschdbg_display_time(p->pre_start_time_h, p->pre_start_time_l))); ++ ++ MSCH_EVENT((", start_time: %s", ++ dhd_mschdbg_display_time(p->start_time_h, p->start_time_l))); ++ ++ MSCH_EVENT((", end_time: %s\n", ++ dhd_mschdbg_display_time(p->end_time_h, p->end_time_l))); ++ ++ if (p->p_timeslot && (p->timeslot_ptr == 0)) { ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("<%s timeslot>: 0x%08x\n", title, ntoh32(p->p_timeslot))); ++ } else ++ dhd_mschdbg_timeslot_profiler_event_data(sn, ver, title, data, p->timeslot_ptr, ++ (p->timeslot_ptr == 0)); ++} ++ ++static void ++dhd_mschdbg_chan_ctxt_profiler_event_data(int sp, int ver, char *data, uint16 ptr, bool empty) ++{ ++ int sn = sp + 4; ++ msch_chan_ctxt_profiler_event_data_t *p = ++ (msch_chan_ctxt_profiler_event_data_t *)(data + ntoh16(ptr)); ++ chanspec_t c; ++ char buf[CHANSPEC_STR_LEN]; ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT((": ")); ++ if (empty) { ++ MSCH_EVENT((" null\n")); ++ return; ++ } ++ else ++ MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n", ++ ntoh32(p->p_chan_ctxt), ntoh32(p->p_prev), ntoh32(p->p_next))); ++ ++ c = (chanspec_t)ntoh16(p->chanspec); ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("channel: %s, bf_sch_pending: %s, bf_skipped: %d\n", ++ wf_chspec_ntoa(c, buf), p->bf_sch_pending? "TRUE" : "FALSE", ++ ntoh32(p->bf_skipped_count))); ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("bf_link: prev 0x%08x, next 0x%08x\n", ++ ntoh32(p->bf_link_prev), ntoh32(p->bf_link_next))); ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("onchan_time: %s", ++ dhd_mschdbg_display_time(p->onchan_time_h, p->onchan_time_l))); ++ MSCH_EVENT((", actual_onchan_dur: %s", ++ dhd_mschdbg_display_time(p->actual_onchan_dur_h, p->actual_onchan_dur_l))); ++ MSCH_EVENT((", pend_onchan_dur: %s\n", ++ dhd_mschdbg_display_time(p->pend_onchan_dur_h, p->pend_onchan_dur_l))); ++ ++ dhd_mschdbg_elem_list(sn, "req_entity", data, p->req_entity_list_ptr, ++ p->req_entity_list_cnt); ++ dhd_mschdbg_elem_list(sn, "bf_entity", data, p->bf_entity_list_ptr, ++ p->bf_entity_list_cnt); ++} ++ ++static void ++dhd_mschdbg_req_entity_profiler_event_data(int sp, int ver, char *data, uint16 ptr, bool empty) ++{ ++ int sn = sp + 4; ++ msch_req_entity_profiler_event_data_t *p = ++ (msch_req_entity_profiler_event_data_t *)(data + ntoh16(ptr)); ++ char buf[CHANSPEC_STR_LEN]; ++ chanspec_t c; ++ uint32 flags; ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT((": ")); ++ if (empty) { ++ MSCH_EVENT((" null\n")); ++ return; ++ } ++ else ++ MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n", ++ ntoh32(p->p_req_entity), ntoh32(p->req_hdl_link_prev), ++ ntoh32(p->req_hdl_link_next))); ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("req_hdl: [0x%08x]\n", ntoh32(p->p_req_hdl))); ++ ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("chan_ctxt_link: prev 0x%08x, next 0x%08x\n", ++ ntoh32(p->chan_ctxt_link_prev), ntoh32(p->chan_ctxt_link_next))); ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("rt_specific_link: prev 0x%08x, next 0x%08x\n", ++ ntoh32(p->rt_specific_link_prev), ntoh32(p->rt_specific_link_next))); ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("start_fixed_link: prev 0x%08x, next 0x%08x\n", ++ ntoh32(p->start_fixed_link_prev), ntoh32(p->start_fixed_link_next))); ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("both_flex_list: prev 0x%08x, next 0x%08x\n", ++ ntoh32(p->both_flex_list_prev), ntoh32(p->both_flex_list_next))); ++ ++ c = (chanspec_t)ntoh16(p->chanspec); ++ MSCH_EVENT_HEAD(sn); ++ if (ver >= 2) { ++ MSCH_EVENT(("channel: %s, onchan Id %d, current chan Id %d, priority %d", ++ wf_chspec_ntoa(c, buf), ntoh16(p->onchan_chn_idx), ntoh16(p->cur_chn_idx), ++ ntoh16(p->priority))); ++ flags = ntoh32(p->flags); ++ if (flags & WL_MSCH_ENTITY_FLAG_MULTI_INSTANCE) ++ MSCH_EVENT((" : MULTI_INSTANCE\n")); ++ else ++ MSCH_EVENT(("\n")); ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("actual_start_time: %s, ", ++ dhd_mschdbg_display_time(p->actual_start_time_h, p->actual_start_time_l))); ++ MSCH_EVENT(("curts_fire_time: %s, ", ++ dhd_mschdbg_display_time(p->curts_fire_time_h, p->curts_fire_time_l))); ++ } else { ++ MSCH_EVENT(("channel: %s, priority %d, ", wf_chspec_ntoa(c, buf), ++ ntoh16(p->priority))); ++ } ++ MSCH_EVENT(("bf_last_serv_time: %s\n", ++ dhd_mschdbg_display_time(p->bf_last_serv_time_h, p->bf_last_serv_time_l))); ++ ++ dhd_mschdbg_req_timing_profiler_event_data(sn, ver, "current", data, p->cur_slot_ptr, ++ (p->cur_slot_ptr == 0)); ++ dhd_mschdbg_req_timing_profiler_event_data(sn, ver, "pending", data, p->pend_slot_ptr, ++ (p->pend_slot_ptr == 0)); ++ ++ if (p->p_chan_ctxt && (p->chan_ctxt_ptr == 0)) { ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT((": 0x%08x\n", ntoh32(p->p_chan_ctxt))); ++ } ++ else ++ dhd_mschdbg_chan_ctxt_profiler_event_data(sn, ver, data, p->chan_ctxt_ptr, ++ (p->chan_ctxt_ptr == 0)); ++} ++ ++static void ++dhd_mschdbg_req_handle_profiler_event_data(int sp, int ver, char *data, uint16 ptr, bool empty) ++{ ++ int sn = sp + 4; ++ msch_req_handle_profiler_event_data_t *p = ++ (msch_req_handle_profiler_event_data_t *)(data + ntoh16(ptr)); ++ uint32 flags; ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT((": ")); ++ if (empty) { ++ MSCH_EVENT((" null\n")); ++ return; ++ } ++ else ++ MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n", ++ ntoh32(p->p_req_handle), ntoh32(p->p_prev), ntoh32(p->p_next))); ++ ++ dhd_mschdbg_elem_list(sn, "req_entity", data, p->req_entity_list_ptr, ++ p->req_entity_list_cnt); ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("cb_func: [0x%08x], cb_func: [0x%08x]", ++ ntoh32(p->cb_func), ntoh32(p->cb_ctxt))); ++ if (ver < 2) { ++ MSCH_EVENT((", chan_cnt: %d", ntoh16(p->chan_cnt))); ++ } ++ flags = ntoh32(p->flags); ++ if (flags & WL_MSCH_REQ_HDL_FLAGS_NEW_REQ) ++ MSCH_EVENT((", NEW_REQ")); ++ MSCH_EVENT(("\n")); ++ ++ dhd_mschdbg_req_param_profiler_event_data(sn, ver, data, p->req_param_ptr); ++ ++ if (ver >= 2) { ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("req_time: %s\n", ++ dhd_mschdbg_display_time(p->req_time_h, p->req_time_l))); ++ MSCH_EVENT_HEAD(sn); ++ MSCH_EVENT(("chan_cnt: %d, chan idx %d, last chan idx %d\n", ++ ntoh16(p->chan_cnt), ntoh16(p->chan_idx), ntoh16(p->last_chan_idx))); ++ if (p->chanspec_list && p->chanspec_cnt) { ++ dhd_mschdbg_chanspec_list(sn, data, p->chanspec_list, p->chanspec_cnt); ++ } ++ } ++} ++ ++static void ++dhd_mschdbg_profiler_profiler_event_data(int sp, int ver, char *data, uint16 ptr) ++{ ++ msch_profiler_profiler_event_data_t *p = ++ (msch_profiler_profiler_event_data_t *)(data + ntoh16(ptr)); ++ uint32 flags; ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT(("free list: req_hdl 0x%08x, req_entity 0x%08x," ++ " chan_ctxt 0x%08x, chanspec 0x%08x\n", ++ ntoh32(p->free_req_hdl_list), ntoh32(p->free_req_entity_list), ++ ntoh32(p->free_chan_ctxt_list), ntoh32(p->free_chanspec_list))); ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT(("alloc count: chanspec %d, req_entity %d, req_hdl %d, " ++ "chan_ctxt %d, timeslot %d\n", ++ ntoh16(p->msch_chanspec_alloc_cnt), ntoh16(p->msch_req_entity_alloc_cnt), ++ ntoh16(p->msch_req_hdl_alloc_cnt), ntoh16(p->msch_chan_ctxt_alloc_cnt), ++ ntoh16(p->msch_timeslot_alloc_cnt))); ++ ++ dhd_mschdbg_elem_list(sp, "req_hdl", data, p->msch_req_hdl_list_ptr, ++ p->msch_req_hdl_list_cnt); ++ dhd_mschdbg_elem_list(sp, "chan_ctxt", data, p->msch_chan_ctxt_list_ptr, ++ p->msch_chan_ctxt_list_cnt); ++ dhd_mschdbg_elem_list(sp, "req_timing", data, p->msch_req_timing_list_ptr, ++ p->msch_req_timing_list_cnt); ++ dhd_mschdbg_elem_list(sp, "start_fixed", data, p->msch_start_fixed_list_ptr, ++ p->msch_start_fixed_list_cnt); ++ dhd_mschdbg_elem_list(sp, "both_flex_req_entity", data, ++ p->msch_both_flex_req_entity_list_ptr, ++ p->msch_both_flex_req_entity_list_cnt); ++ dhd_mschdbg_elem_list(sp, "start_flex", data, p->msch_start_flex_list_ptr, ++ p->msch_start_flex_list_cnt); ++ dhd_mschdbg_elem_list(sp, "both_flex", data, p->msch_both_flex_list_ptr, ++ p->msch_both_flex_list_cnt); ++ ++ if (p->p_cur_msch_timeslot && (p->cur_msch_timeslot_ptr == 0)) { ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT((": 0x%08x\n", ++ ntoh32(p->p_cur_msch_timeslot))); ++ } else ++ dhd_mschdbg_timeslot_profiler_event_data(sp, ver, "cur_msch", data, ++ p->cur_msch_timeslot_ptr, (p->cur_msch_timeslot_ptr == 0)); ++ ++ if (p->p_next_timeslot && (p->next_timeslot_ptr == 0)) { ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT((": 0x%08x\n", ++ ntoh32(p->p_next_timeslot))); ++ } else ++ dhd_mschdbg_timeslot_profiler_event_data(sp, ver, "next", data, ++ p->next_timeslot_ptr, (p->next_timeslot_ptr == 0)); ++ ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT(("ts_id: %d, ", ntoh32(p->ts_id))); ++ flags = ntoh32(p->flags); ++ if (flags & WL_MSCH_STATE_IN_TIEMR_CTXT) ++ MSCH_EVENT(("IN_TIEMR_CTXT, ")); ++ if (flags & WL_MSCH_STATE_SCHD_PENDING) ++ MSCH_EVENT(("SCHD_PENDING, ")); ++ MSCH_EVENT(("slotskip_flags: %d, cur_armed_timeslot: 0x%08x\n", ++ (ver >= 2)? ntoh32(p->slotskip_flag) : 0, ntoh32(p->cur_armed_timeslot))); ++ MSCH_EVENT_HEAD(sp); ++ MSCH_EVENT(("flex_list_cnt: %d, service_interval: %d, " ++ "max_lo_prio_interval: %d\n", ++ ntoh16(p->flex_list_cnt), ntoh32(p->service_interval), ++ ntoh32(p->max_lo_prio_interval))); ++} ++ ++static void dhd_mschdbg_dump_data(dhd_pub_t *dhdp, void *raw_event_ptr, int type, ++ char *data, int len) ++{ ++ uint64 t = 0, tt = 0; ++ uint32 s = 0, ss = 0; ++ int wlc_index, ver; ++ ++ ver = (type & WL_MSCH_PROFILER_VER_MASK) >> WL_MSCH_PROFILER_VER_SHIFT; ++ wlc_index = (type & WL_MSCH_PROFILER_WLINDEX_MASK) >> WL_MSCH_PROFILER_WLINDEX_SHIFT; ++ if (wlc_index >= 4) ++ return; ++ ++ type &= WL_MSCH_PROFILER_TYPE_MASK; ++ if (type <= WL_MSCH_PROFILER_PROFILE_END) { ++ msch_profiler_event_data_t *pevent = (msch_profiler_event_data_t *)data; ++ tt = ((uint64)(ntoh32(pevent->time_hi)) << 32) | ntoh32(pevent->time_lo); ++ dhd_mschdbg_us_to_sec(pevent->time_hi, pevent->time_lo, &s, &ss); ++ } ++ ++ if (lastMessages && (type != WL_MSCH_PROFILER_MESSAGE) && ++ (type != WL_MSCH_PROFILER_EVENT_LOG)) { ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("\n")); ++ lastMessages = FALSE; ++ } ++ ++ switch (type) { ++ case WL_MSCH_PROFILER_START: ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("%06d.%06d START\n", s, ss)); ++ break; ++ ++ case WL_MSCH_PROFILER_EXIT: ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("%06d.%06d EXIT\n", s, ss)); ++ break; ++ ++ case WL_MSCH_PROFILER_REQ: ++ { ++ msch_req_profiler_event_data_t *p = (msch_req_profiler_event_data_t *)data; ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("\n")); ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("===============================\n")); ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("%06d.%06d [wl%d] REGISTER:\n", s, ss, wlc_index)); ++ dhd_mschdbg_req_param_profiler_event_data(4, ver, data, p->req_param_ptr); ++ dhd_mschdbg_chanspec_list(4, data, p->chanspec_ptr, p->chanspec_cnt); ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("===============================\n")); ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("\n")); ++ } ++ break; ++ ++ case WL_MSCH_PROFILER_CALLBACK: ++ { ++ msch_callback_profiler_event_data_t *p = ++ (msch_callback_profiler_event_data_t *)data; ++ char buf[CHANSPEC_STR_LEN]; ++ chanspec_t chanspec; ++ uint16 cbtype; ++ ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("%06d.%06d [wl%d] CALLBACK: ", s, ss, wlc_index)); ++ chanspec = (chanspec_t)ntoh16(p->chanspec); ++ MSCH_EVENT(("req_hdl[0x%08x], channel %s --", ++ ntoh32(p->p_req_hdl), wf_chspec_ntoa(chanspec, buf))); ++ ++ cbtype = ntoh16(p->type); ++ if (cbtype & WL_MSCH_CT_ON_CHAN) ++ MSCH_EVENT((" ON_CHAN")); ++ if (cbtype & WL_MSCH_CT_OFF_CHAN) ++ MSCH_EVENT((" OFF_CHAN")); ++ if (cbtype & WL_MSCH_CT_REQ_START) ++ MSCH_EVENT((" REQ_START")); ++ if (cbtype & WL_MSCH_CT_REQ_END) ++ MSCH_EVENT((" REQ_END")); ++ if (cbtype & WL_MSCH_CT_SLOT_START) ++ MSCH_EVENT((" SLOT_START")); ++ if (cbtype & WL_MSCH_CT_SLOT_SKIP) ++ MSCH_EVENT((" SLOT_SKIP")); ++ if (cbtype & WL_MSCH_CT_SLOT_END) ++ MSCH_EVENT((" SLOT_END")); ++ if (cbtype & WL_MSCH_CT_OFF_CHAN_DONE) ++ MSCH_EVENT((" OFF_CHAN_DONE")); ++ if (cbtype & WL_MSCH_CT_PARTIAL) ++ MSCH_EVENT((" PARTIAL")); ++ if (cbtype & WL_MSCH_CT_PRE_ONCHAN) ++ MSCH_EVENT((" PRE_ONCHAN")); ++ if (cbtype & WL_MSCH_CT_PRE_REQ_START) ++ MSCH_EVENT((" PRE_REQ_START")); ++ ++ if (cbtype & WL_MSCH_CT_REQ_START) { ++ req_start[wlc_index] = 1; ++ req_start_time[wlc_index] = tt; ++ } else if (cbtype & WL_MSCH_CT_REQ_END) { ++ if (req_start[wlc_index]) { ++ MSCH_EVENT((" : REQ duration %d", ++ (uint32)(tt - req_start_time[wlc_index]))); ++ req_start[wlc_index] = 0; ++ } ++ } ++ ++ if (cbtype & WL_MSCH_CT_SLOT_START) { ++ solt_chanspec[wlc_index] = p->chanspec; ++ solt_start_time[wlc_index] = tt; ++ } else if (cbtype & WL_MSCH_CT_SLOT_END) { ++ if (p->chanspec == solt_chanspec[wlc_index]) { ++ MSCH_EVENT((" : SLOT duration %d", ++ (uint32)(tt - solt_start_time[wlc_index]))); ++ solt_chanspec[wlc_index] = 0; ++ } ++ } ++ MSCH_EVENT(("\n")); ++ ++ if (cbtype & (WL_MSCH_CT_ON_CHAN | WL_MSCH_CT_SLOT_SKIP)) { ++ MSCH_EVENT_HEAD(4); ++ if (cbtype & WL_MSCH_CT_ON_CHAN) { ++ MSCH_EVENT(("ID %d onchan idx %d cur_chan_seq_start %s ", ++ ntoh32(p->timeslot_id), ntoh32(p->onchan_idx), ++ dhd_mschdbg_display_time(p->cur_chan_seq_start_time_h, ++ p->cur_chan_seq_start_time_l))); ++ } ++ t = ((uint64)(ntoh32(p->start_time_h)) << 32) | ++ ntoh32(p->start_time_l); ++ MSCH_EVENT(("start %s ", ++ dhd_mschdbg_display_time(p->start_time_h, ++ p->start_time_l))); ++ tt = ((uint64)(ntoh32(p->end_time_h)) << 32) | ntoh32(p->end_time_l); ++ MSCH_EVENT(("end %s duration %d\n", ++ dhd_mschdbg_display_time(p->end_time_h, p->end_time_l), ++ (p->end_time_h == 0xffffffff && p->end_time_l == 0xffffffff)? ++ -1 : (int)(tt - t))); ++ } ++ ++ } ++ break; ++ ++ case WL_MSCH_PROFILER_EVENT_LOG: ++ { ++ while (len > 0) { ++ msch_event_log_profiler_event_data_t *p = ++ (msch_event_log_profiler_event_data_t *)data; ++ int size = WL_MSCH_EVENT_LOG_HEAD_SIZE + p->hdr.count * sizeof(uint32); ++ data += size; ++ len -= size; ++ dhd_mschdbg_us_to_sec(p->time_hi, p->time_lo, &s, &ss); ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("%06d.%06d [wl%d]: ", s, ss, p->hdr.tag)); ++ p->hdr.tag = EVENT_LOG_TAG_MSCHPROFILE; ++ p->hdr.fmt_num = ntoh16(p->hdr.fmt_num); ++ dhd_dbg_verboselog_printf(dhdp, &p->hdr, raw_event_ptr, p->data); ++ } ++ lastMessages = TRUE; ++ break; ++ } ++ ++ case WL_MSCH_PROFILER_MESSAGE: ++ { ++ msch_message_profiler_event_data_t *p = (msch_message_profiler_event_data_t *)data; ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("%06d.%06d [wl%d]: %s", s, ss, wlc_index, p->message)); ++ lastMessages = TRUE; ++ break; ++ } ++ ++ case WL_MSCH_PROFILER_PROFILE_START: ++ profiler_start_time[wlc_index] = tt; ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("-------------------------------\n")); ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("%06d.%06d [wl%d] PROFILE DATA:\n", s, ss, wlc_index)); ++ dhd_mschdbg_profiler_profiler_event_data(4, ver, data, 0); ++ break; ++ ++ case WL_MSCH_PROFILER_PROFILE_END: ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("%06d.%06d [wl%d] PROFILE END: take time %d\n", s, ss, ++ wlc_index, (uint32)(tt - profiler_start_time[wlc_index]))); ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("-------------------------------\n")); ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("\n")); ++ break; ++ ++ case WL_MSCH_PROFILER_REQ_HANDLE: ++ dhd_mschdbg_req_handle_profiler_event_data(4, ver, data, 0, FALSE); ++ break; ++ ++ case WL_MSCH_PROFILER_REQ_ENTITY: ++ dhd_mschdbg_req_entity_profiler_event_data(4, ver, data, 0, FALSE); ++ break; ++ ++ case WL_MSCH_PROFILER_CHAN_CTXT: ++ dhd_mschdbg_chan_ctxt_profiler_event_data(4, ver, data, 0, FALSE); ++ break; ++ ++ case WL_MSCH_PROFILER_REQ_TIMING: ++ dhd_mschdbg_req_timing_profiler_event_data(4, ver, "msch", data, 0, FALSE); ++ break; ++ ++ default: ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("[wl%d] ERROR: unsupported EVENT reason code:%d; ", ++ wlc_index, type)); ++ break; ++ } ++} ++ ++void ++wl_mschdbg_event_handler(dhd_pub_t *dhdp, void *raw_event_ptr, int type, void *data, int len) ++{ ++ head_log = "MSCH"; ++ dhd_mschdbg_dump_data(dhdp, raw_event_ptr, type, (char *)data, len); ++} ++ ++void ++wl_mschdbg_verboselog_handler(dhd_pub_t *dhdp, void *raw_event_ptr, int tag, uint32 *log_ptr) ++{ ++ head_log = "CONSOLE"; ++ if (tag == EVENT_LOG_TAG_MSCHPROFILE) { ++ msch_event_log_profiler_event_data_t *p = ++ (msch_event_log_profiler_event_data_t *)log_ptr; ++ uint32 s, ss; ++ dhd_mschdbg_us_to_sec(p->time_hi, p->time_lo, &s, &ss); ++ MSCH_EVENT_HEAD(0); ++ MSCH_EVENT(("%06d.%06d [wl%d]: ", s, ss, p->hdr.tag)); ++ p->hdr.tag = EVENT_LOG_TAG_MSCHPROFILE; ++ p->hdr.fmt_num = ntoh16(p->hdr.fmt_num); ++ dhd_dbg_verboselog_printf(dhdp, &p->hdr, raw_event_ptr, p->data); ++ } else { ++ msch_collect_tlv_t *p = (msch_collect_tlv_t *)log_ptr; ++ int type = ntoh16(p->type); ++ int len = ntoh16(p->size); ++ dhd_mschdbg_dump_data(dhdp, raw_event_ptr, type, p->value, len); ++ } ++} ++#endif /* SHOW_LOGTRACE */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_mschdbg.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_mschdbg.h +new file mode 100644 +index 000000000..749e1119f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_mschdbg.h +@@ -0,0 +1,39 @@ ++/* ++ * DHD debugability header file ++ * ++ * <> ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: dhd_mschdbg.h 571265 2015-07-14 20:50:18Z $ ++ */ ++ ++#ifndef _dhd_mschdbg_h_ ++#define _dhd_mschdbg_h_ ++ ++#ifdef SHOW_LOGTRACE ++extern void wl_mschdbg_event_handler(dhd_pub_t *dhdp, void *raw_event_ptr, int type, ++ void *data, int len); ++extern void wl_mschdbg_verboselog_handler(dhd_pub_t *dhdp, void *raw_event_ptr, int tag, ++ uint32 *log_ptr); ++#endif /* SHOW_LOGTRACE */ ++ ++#endif /* _dhd_mschdbg_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_msgbuf.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_msgbuf.c +new file mode 100644 +index 000000000..bb56c1aa0 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_msgbuf.c +@@ -0,0 +1,8951 @@ ++/** ++ * @file definition of host message ring functionality ++ * Provides type definitions and function prototypes used to link the ++ * DHD OS, bus, and protocol modules. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_msgbuf.c 704361 2017-06-13 08:50:38Z $ ++ */ ++ ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++#ifdef DHD_TIMESYNC ++#include ++#endif /* DHD_TIMESYNC */ ++ ++#if defined(DHD_LB) ++#include ++#include ++#define DHD_LB_WORKQ_SZ (8192) ++#define DHD_LB_WORKQ_SYNC (16) ++#define DHD_LB_WORK_SCHED (DHD_LB_WORKQ_SYNC * 2) ++#endif /* DHD_LB */ ++ ++#include ++#include ++ ++#ifdef DHD_PKT_LOGGING ++#include ++#endif /* DHD_PKT_LOGGING */ ++ ++extern char dhd_version[]; ++extern char fw_version[]; ++ ++/** ++ * Host configures a soft doorbell for d2h rings, by specifying a 32bit host ++ * address where a value must be written. Host may also interrupt coalescing ++ * on this soft doorbell. ++ * Use Case: Hosts with network processors, may register with the dongle the ++ * network processor's thread wakeup register and a value corresponding to the ++ * core/thread context. Dongle will issue a write transaction ++ * to the PCIE RC which will need to be routed to the mapped register space, by ++ * the host. ++ */ ++/* #define DHD_D2H_SOFT_DOORBELL_SUPPORT */ ++ ++/* Dependency Check */ ++#if defined(IOCTLRESP_USE_CONSTMEM) && defined(DHD_USE_STATIC_CTRLBUF) ++#error "DHD_USE_STATIC_CTRLBUF is NOT working with DHD_USE_OSLPKT_FOR_RESPBUF" ++#endif /* IOCTLRESP_USE_CONSTMEM && DHD_USE_STATIC_CTRLBUF */ ++ ++#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ ++ ++#define DEFAULT_RX_BUFFERS_TO_POST 256 ++#define RXBUFPOST_THRESHOLD 32 ++#define RX_BUF_BURST 32 /* Rx buffers for MSDU Data */ ++ ++#define DHD_STOP_QUEUE_THRESHOLD 200 ++#define DHD_START_QUEUE_THRESHOLD 100 ++ ++#define RX_DMA_OFFSET 8 /* Mem2mem DMA inserts an extra 8 */ ++#define IOCT_RETBUF_SIZE (RX_DMA_OFFSET + WLC_IOCTL_MAXLEN) ++ ++/* flags for ioctl pending status */ ++#define MSGBUF_IOCTL_ACK_PENDING (1<<0) ++#define MSGBUF_IOCTL_RESP_PENDING (1<<1) ++ ++#define DMA_ALIGN_LEN 4 ++ ++#define DMA_D2H_SCRATCH_BUF_LEN 8 ++#define DMA_XFER_LEN_LIMIT 0x400000 ++ ++#ifdef BCM_HOST_BUF ++#ifndef DMA_HOST_BUFFER_LEN ++#define DMA_HOST_BUFFER_LEN 0x200000 ++#endif ++#endif /* BCM_HOST_BUF */ ++ ++#define DHD_FLOWRING_IOCTL_BUFPOST_PKTSZ 8192 ++ ++#define DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D 1 ++#define DHD_FLOWRING_MAX_EVENTBUF_POST 32 ++#define DHD_FLOWRING_MAX_IOCTLRESPBUF_POST 8 ++#define DHD_H2D_INFORING_MAX_BUF_POST 32 ++#define DHD_MAX_TSBUF_POST 8 ++ ++#define DHD_PROT_FUNCS 41 ++ ++/* Length of buffer in host for bus throughput measurement */ ++#define DHD_BUS_TPUT_BUF_LEN 2048 ++ ++#define TXP_FLUSH_NITEMS ++ ++/* optimization to write "n" tx items at a time to ring */ ++#define TXP_FLUSH_MAX_ITEMS_FLUSH_CNT 48 ++ ++#define RING_NAME_MAX_LENGTH 24 ++#define CTRLSUB_HOSTTS_MEESAGE_SIZE 1024 ++/* Giving room before ioctl_trans_id rollsover. */ ++#define BUFFER_BEFORE_ROLLOVER 300 ++ ++struct msgbuf_ring; /* ring context for common and flow rings */ ++ ++/** ++ * PCIE D2H DMA Complete Sync Modes ++ * ++ * Firmware may interrupt the host, prior to the D2H Mem2Mem DMA completes into ++ * Host system memory. A WAR using one of 3 approaches is needed: ++ * 1. Dongle places a modulo-253 seqnum in last word of each D2H message ++ * 2. XOR Checksum, with epoch# in each work item. Dongle builds an XOR checksum ++ * writes in the last word of each work item. Each work item has a seqnum ++ * number = sequence num % 253. ++ * ++ * 3. Read Barrier: Dongle does a host memory read access prior to posting an ++ * interrupt, ensuring that D2H data transfer indeed completed. ++ * 4. Dongle DMA's all indices after producing items in the D2H ring, flushing ++ * ring contents before the indices. ++ * ++ * Host does not sync for DMA to complete with option #3 or #4, and a noop sync ++ * callback (see dhd_prot_d2h_sync_none) may be bound. ++ * ++ * Dongle advertizes host side sync mechanism requirements. ++ */ ++ ++#define PCIE_D2H_SYNC_WAIT_TRIES (512UL) ++#define PCIE_D2H_SYNC_NUM_OF_STEPS (5UL) ++#define PCIE_D2H_SYNC_DELAY (100UL) /* in terms of usecs */ ++ ++/** ++ * Custom callback attached based upon D2H DMA Sync mode advertized by dongle. ++ * ++ * On success: return cmn_msg_hdr_t::msg_type ++ * On failure: return 0 (invalid msg_type) ++ */ ++typedef uint8 (* d2h_sync_cb_t)(dhd_pub_t *dhd, struct msgbuf_ring *ring, ++ volatile cmn_msg_hdr_t *msg, int msglen); ++ ++/* ++ * +---------------------------------------------------------------------------- ++ * ++ * RingIds and FlowId are not equivalent as ringids include D2H rings whereas ++ * flowids do not. ++ * ++ * Dongle advertizes the max H2D rings, as max_sub_queues = 'N' which includes ++ * the H2D common rings as well as the (N-BCMPCIE_H2D_COMMON_MSGRINGS) flowrings ++ * ++ * Here is a sample mapping for (based on PCIE Full Dongle Rev5) where, ++ * BCMPCIE_H2D_COMMON_MSGRINGS = 2, i.e. 2 H2D common rings, ++ * BCMPCIE_COMMON_MSGRINGS = 5, i.e. include 3 D2H common rings. ++ * ++ * H2D Control Submit RingId = 0 FlowId = 0 reserved never allocated ++ * H2D RxPost Submit RingId = 1 FlowId = 1 reserved never allocated ++ * ++ * D2H Control Complete RingId = 2 ++ * D2H Transmit Complete RingId = 3 ++ * D2H Receive Complete RingId = 4 ++ * ++ * H2D TxPost FLOWRING RingId = 5 FlowId = 2 (1st flowring) ++ * H2D TxPost FLOWRING RingId = 6 FlowId = 3 (2nd flowring) ++ * H2D TxPost FLOWRING RingId = 5 + (N-1) FlowId = (N-1) (Nth flowring) ++ * ++ * When TxPost FlowId(s) are allocated, the FlowIds [0..FLOWID_RESERVED) are ++ * unused, where FLOWID_RESERVED is BCMPCIE_H2D_COMMON_MSGRINGS. ++ * ++ * Example: when a system supports 4 bc/mc and 128 uc flowrings, with ++ * BCMPCIE_H2D_COMMON_MSGRINGS = 2, and BCMPCIE_H2D_COMMON_MSGRINGS = 5, and the ++ * FlowId values would be in the range [2..133] and the corresponding ++ * RingId values would be in the range [5..136]. ++ * ++ * The flowId allocator, may chose to, allocate Flowids: ++ * bc/mc (per virtual interface) in one consecutive range [2..(2+VIFS)) ++ * X# of uc flowids in consecutive ranges (per station Id), where X is the ++ * packet's access category (e.g. 4 uc flowids per station). ++ * ++ * CAUTION: ++ * When DMA indices array feature is used, RingId=5, corresponding to the 0th ++ * FLOWRING, will actually use the FlowId as index into the H2D DMA index, ++ * since the FlowId truly represents the index in the H2D DMA indices array. ++ * ++ * Likewise, in the D2H direction, the RingId - BCMPCIE_H2D_COMMON_MSGRINGS, ++ * will represent the index in the D2H DMA indices array. ++ * ++ * +---------------------------------------------------------------------------- ++ */ ++ ++/* First TxPost Flowring Id */ ++#define DHD_FLOWRING_START_FLOWID BCMPCIE_H2D_COMMON_MSGRINGS ++ ++/* Determine whether a ringid belongs to a TxPost flowring */ ++#define DHD_IS_FLOWRING(ringid, max_flow_rings) \ ++ ((ringid) >= BCMPCIE_COMMON_MSGRINGS && \ ++ (ringid) < ((max_flow_rings) + BCMPCIE_COMMON_MSGRINGS)) ++ ++/* Convert a H2D TxPost FlowId to a MsgBuf RingId */ ++#define DHD_FLOWID_TO_RINGID(flowid) \ ++ (BCMPCIE_COMMON_MSGRINGS + ((flowid) - BCMPCIE_H2D_COMMON_MSGRINGS)) ++ ++/* Convert a MsgBuf RingId to a H2D TxPost FlowId */ ++#define DHD_RINGID_TO_FLOWID(ringid) \ ++ (BCMPCIE_H2D_COMMON_MSGRINGS + ((ringid) - BCMPCIE_COMMON_MSGRINGS)) ++ ++/* Convert a H2D MsgBuf RingId to an offset index into the H2D DMA indices array ++ * This may be used for the H2D DMA WR index array or H2D DMA RD index array or ++ * any array of H2D rings. ++ */ ++#define DHD_H2D_RING_OFFSET(ringid) \ ++ (((ringid) >= BCMPCIE_COMMON_MSGRINGS) ? DHD_RINGID_TO_FLOWID(ringid) : (ringid)) ++ ++/* Convert a H2D MsgBuf Flowring Id to an offset index into the H2D DMA indices array ++ * This may be used for IFRM. ++ */ ++#define DHD_H2D_FRM_FLOW_RING_OFFSET(ringid) \ ++ ((ringid) - BCMPCIE_COMMON_MSGRINGS) ++ ++/* Convert a D2H MsgBuf RingId to an offset index into the D2H DMA indices array ++ * This may be used for the D2H DMA WR index array or D2H DMA RD index array or ++ * any array of D2H rings. ++ * d2h debug ring is located at the end, i.e. after all the tx flow rings and h2d debug ring ++ * max_h2d_rings: total number of h2d rings ++ */ ++#define DHD_D2H_RING_OFFSET(ringid, max_h2d_rings) \ ++ ((ringid) > (max_h2d_rings) ? \ ++ ((ringid) - max_h2d_rings) : \ ++ ((ringid) - BCMPCIE_H2D_COMMON_MSGRINGS)) ++ ++/* Convert a D2H DMA Indices Offset to a RingId */ ++#define DHD_D2H_RINGID(offset) \ ++ ((offset) + BCMPCIE_H2D_COMMON_MSGRINGS) ++ ++ ++#define DHD_DMAH_NULL ((void*)NULL) ++ ++/* ++ * Pad a DMA-able buffer by an additional cachline. If the end of the DMA-able ++ * buffer does not occupy the entire cacheline, and another object is placed ++ * following the DMA-able buffer, data corruption may occur if the DMA-able ++ * buffer is used to DMAing into (e.g. D2H direction), when HW cache coherency ++ * is not available. ++ */ ++#if defined(L1_CACHE_BYTES) ++#define DHD_DMA_PAD (L1_CACHE_BYTES) ++#else ++#define DHD_DMA_PAD (128) ++#endif ++ ++/* Used in loopback tests */ ++typedef struct dhd_dmaxfer { ++ dhd_dma_buf_t srcmem; ++ dhd_dma_buf_t dstmem; ++ uint32 srcdelay; ++ uint32 destdelay; ++ uint32 len; ++ bool in_progress; ++ uint64 start_usec; ++ uint32 d11_lpbk; ++} dhd_dmaxfer_t; ++ ++/** ++ * msgbuf_ring : This object manages the host side ring that includes a DMA-able ++ * buffer, the WR and RD indices, ring parameters such as max number of items ++ * an length of each items, and other miscellaneous runtime state. ++ * A msgbuf_ring may be used to represent a H2D or D2H common ring or a ++ * H2D TxPost ring as specified in the PCIE FullDongle Spec. ++ * Ring parameters are conveyed to the dongle, which maintains its own peer end ++ * ring state. Depending on whether the DMA Indices feature is supported, the ++ * host will update the WR/RD index in the DMA indices array in host memory or ++ * directly in dongle memory. ++ */ ++typedef struct msgbuf_ring { ++ bool inited; ++ uint16 idx; /* ring id */ ++ uint16 rd; /* read index */ ++ uint16 curr_rd; /* read index for debug */ ++ uint16 wr; /* write index */ ++ uint16 max_items; /* maximum number of items in ring */ ++ uint16 item_len; /* length of each item in the ring */ ++ sh_addr_t base_addr; /* LITTLE ENDIAN formatted: base address */ ++ dhd_dma_buf_t dma_buf; /* DMA-able buffer: pa, va, len, dmah, secdma */ ++ uint32 seqnum; /* next expected item's sequence number */ ++#ifdef TXP_FLUSH_NITEMS ++ void *start_addr; ++ /* # of messages on ring not yet announced to dongle */ ++ uint16 pend_items_count; ++#endif /* TXP_FLUSH_NITEMS */ ++ ++ uint8 ring_type; ++ uint8 n_completion_ids; ++ bool create_pending; ++ uint16 create_req_id; ++ uint8 current_phase; ++ uint16 compeltion_ring_ids[MAX_COMPLETION_RING_IDS_ASSOCIATED]; ++ uchar name[RING_NAME_MAX_LENGTH]; ++ uint32 ring_mem_allocated; ++} msgbuf_ring_t; ++ ++#define DHD_RING_BGN_VA(ring) ((ring)->dma_buf.va) ++#define DHD_RING_END_VA(ring) \ ++ ((uint8 *)(DHD_RING_BGN_VA((ring))) + \ ++ (((ring)->max_items - 1) * (ring)->item_len)) ++ ++ ++ ++/* This can be overwritten by module parameter defined in dhd_linux.c ++ * or by dhd iovar h2d_max_txpost. ++ */ ++int h2d_max_txpost = H2DRING_TXPOST_MAX_ITEM; ++ ++/** DHD protocol handle. Is an opaque type to other DHD software layers. */ ++typedef struct dhd_prot { ++ osl_t *osh; /* OSL handle */ ++ uint16 rxbufpost; ++ uint16 max_rxbufpost; ++ uint16 max_eventbufpost; ++ uint16 max_ioctlrespbufpost; ++ uint16 max_tsbufpost; ++ uint16 max_infobufpost; ++ uint16 infobufpost; ++ uint16 cur_event_bufs_posted; ++ uint16 cur_ioctlresp_bufs_posted; ++ uint16 cur_ts_bufs_posted; ++ ++ /* Flow control mechanism based on active transmits pending */ ++ uint16 active_tx_count; /* increments on every packet tx, and decrements on tx_status */ ++ uint16 h2d_max_txpost; ++ uint16 txp_threshold; /* optimization to write "n" tx items at a time to ring */ ++ ++ /* MsgBuf Ring info: has a dhd_dma_buf that is dynamically allocated */ ++ msgbuf_ring_t h2dring_ctrl_subn; /* H2D ctrl message submission ring */ ++ msgbuf_ring_t h2dring_rxp_subn; /* H2D RxBuf post ring */ ++ msgbuf_ring_t d2hring_ctrl_cpln; /* D2H ctrl completion ring */ ++ msgbuf_ring_t d2hring_tx_cpln; /* D2H Tx complete message ring */ ++ msgbuf_ring_t d2hring_rx_cpln; /* D2H Rx complete message ring */ ++ msgbuf_ring_t *h2dring_info_subn; /* H2D info submission ring */ ++ msgbuf_ring_t *d2hring_info_cpln; /* D2H info completion ring */ ++ ++ msgbuf_ring_t *h2d_flowrings_pool; /* Pool of preallocated flowings */ ++ dhd_dma_buf_t flowrings_dma_buf; /* Contiguous DMA buffer for flowrings */ ++ uint16 h2d_rings_total; /* total H2D (common rings + flowrings) */ ++ ++ uint32 rx_dataoffset; ++ ++ dhd_mb_ring_t mb_ring_fn; /* called when dongle needs to be notified of new msg */ ++ dhd_mb_ring_2_t mb_2_ring_fn; /* called when dongle needs to be notified of new msg */ ++ ++ /* ioctl related resources */ ++ uint8 ioctl_state; ++ int16 ioctl_status; /* status returned from dongle */ ++ uint16 ioctl_resplen; ++ dhd_ioctl_recieved_status_t ioctl_received; ++ uint curr_ioctl_cmd; ++ dhd_dma_buf_t retbuf; /* For holding ioctl response */ ++ dhd_dma_buf_t ioctbuf; /* For holding ioctl request */ ++ ++ dhd_dma_buf_t d2h_dma_scratch_buf; /* For holding d2h scratch */ ++ ++ /* DMA-able arrays for holding WR and RD indices */ ++ uint32 rw_index_sz; /* Size of a RD or WR index in dongle */ ++ dhd_dma_buf_t h2d_dma_indx_wr_buf; /* Array of H2D WR indices */ ++ dhd_dma_buf_t h2d_dma_indx_rd_buf; /* Array of H2D RD indices */ ++ dhd_dma_buf_t d2h_dma_indx_wr_buf; /* Array of D2H WR indices */ ++ dhd_dma_buf_t d2h_dma_indx_rd_buf; /* Array of D2H RD indices */ ++ dhd_dma_buf_t h2d_ifrm_indx_wr_buf; /* Array of H2D WR indices for ifrm */ ++ ++ dhd_dma_buf_t host_bus_throughput_buf; /* bus throughput measure buffer */ ++ ++ dhd_dma_buf_t *flowring_buf; /* pool of flow ring buf */ ++ uint32 flowring_num; ++ ++ d2h_sync_cb_t d2h_sync_cb; /* Sync on D2H DMA done: SEQNUM or XORCSUM */ ++ ulong d2h_sync_wait_max; /* max number of wait loops to receive one msg */ ++ ulong d2h_sync_wait_tot; /* total wait loops */ ++ ++ dhd_dmaxfer_t dmaxfer; /* for test/DMA loopback */ ++ ++ uint16 ioctl_seq_no; ++ uint16 data_seq_no; ++ uint16 ioctl_trans_id; ++ void *pktid_ctrl_map; /* a pktid maps to a packet and its metadata */ ++ void *pktid_rx_map; /* pktid map for rx path */ ++ void *pktid_tx_map; /* pktid map for tx path */ ++ void *rx_lock; /* rx pktid map and rings access protection */ ++ bool metadata_dbg; ++ void *pktid_map_handle_ioctl; ++ ++ /* Applications/utilities can read tx and rx metadata using IOVARs */ ++ uint16 rx_metadata_offset; ++ uint16 tx_metadata_offset; ++ ++ ++#if defined(DHD_D2H_SOFT_DOORBELL_SUPPORT) ++ /* Host's soft doorbell configuration */ ++ bcmpcie_soft_doorbell_t soft_doorbell[BCMPCIE_D2H_COMMON_MSGRINGS]; ++#endif /* DHD_D2H_SOFT_DOORBELL_SUPPORT */ ++ ++ /* Work Queues to be used by the producer and the consumer, and threshold ++ * when the WRITE index must be synced to consumer's workq ++ */ ++#if defined(DHD_LB_TXC) ++ uint32 tx_compl_prod_sync ____cacheline_aligned; ++ bcm_workq_t tx_compl_prod, tx_compl_cons; ++#endif /* DHD_LB_TXC */ ++#if defined(DHD_LB_RXC) ++ uint32 rx_compl_prod_sync ____cacheline_aligned; ++ bcm_workq_t rx_compl_prod, rx_compl_cons; ++#endif /* DHD_LB_RXC */ ++ ++ dhd_dma_buf_t fw_trap_buf; /* firmware trap buffer */ ++ ++ uint32 host_ipc_version; /* Host sypported IPC rev */ ++ uint32 device_ipc_version; /* FW supported IPC rev */ ++ uint32 active_ipc_version; /* Host advertised IPC rev */ ++ dhd_dma_buf_t hostts_req_buf; /* For holding host timestamp request buf */ ++ bool hostts_req_buf_inuse; ++ bool rx_ts_log_enabled; ++ bool tx_ts_log_enabled; ++} dhd_prot_t; ++ ++extern void dhd_schedule_dmaxfer_free(dhd_pub_t* dhdp, dmaxref_mem_map_t *dmmap); ++ ++static atomic_t dhd_msgbuf_rxbuf_post_event_bufs_running = ATOMIC_INIT(0); ++ ++/* Convert a dmaaddr_t to a base_addr with htol operations */ ++static INLINE void dhd_base_addr_htolpa(sh_addr_t *base_addr, dmaaddr_t pa); ++ ++/* APIs for managing a DMA-able buffer */ ++static int dhd_dma_buf_audit(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf); ++static int dhd_dma_buf_alloc(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf, uint32 buf_len); ++static void dhd_dma_buf_reset(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf); ++static void dhd_dma_buf_free(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf); ++ ++/* msgbuf ring management */ ++static int dhd_prot_ring_attach(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ const char *name, uint16 max_items, uint16 len_item, uint16 ringid); ++static void dhd_prot_ring_init(dhd_pub_t *dhd, msgbuf_ring_t *ring); ++static void dhd_prot_ring_reset(dhd_pub_t *dhd, msgbuf_ring_t *ring); ++static void dhd_prot_ring_detach(dhd_pub_t *dhd, msgbuf_ring_t *ring); ++static void dhd_prot_process_fw_timestamp(dhd_pub_t *dhd, void* buf); ++ ++/* Pool of pre-allocated msgbuf_ring_t with DMA-able buffers for Flowrings */ ++static int dhd_prot_flowrings_pool_attach(dhd_pub_t *dhd); ++static void dhd_prot_flowrings_pool_reset(dhd_pub_t *dhd); ++static void dhd_prot_flowrings_pool_detach(dhd_pub_t *dhd); ++ ++/* Fetch and Release a flowring msgbuf_ring from flowring pool */ ++static msgbuf_ring_t *dhd_prot_flowrings_pool_fetch(dhd_pub_t *dhd, ++ uint16 flowid); ++/* see also dhd_prot_flowrings_pool_release() in dhd_prot.h */ ++ ++/* Producer: Allocate space in a msgbuf ring */ ++static void* dhd_prot_alloc_ring_space(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ uint16 nitems, uint16 *alloced, bool exactly_nitems); ++static void* dhd_prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, ++ uint16 *alloced, bool exactly_nitems); ++ ++/* Consumer: Determine the location where the next message may be consumed */ ++static uint8* dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ uint32 *available_len); ++ ++/* Producer (WR index update) or Consumer (RD index update) indication */ ++static void dhd_prot_ring_write_complete(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ void *p, uint16 len); ++static void dhd_prot_upd_read_idx(dhd_pub_t *dhd, msgbuf_ring_t *ring); ++ ++static INLINE int dhd_prot_dma_indx_alloc(dhd_pub_t *dhd, uint8 type, ++ dhd_dma_buf_t *dma_buf, uint32 bufsz); ++ ++/* Set/Get a RD or WR index in the array of indices */ ++/* See also: dhd_prot_dma_indx_init() */ ++void dhd_prot_dma_indx_set(dhd_pub_t *dhd, uint16 new_index, uint8 type, ++ uint16 ringid); ++static uint16 dhd_prot_dma_indx_get(dhd_pub_t *dhd, uint8 type, uint16 ringid); ++ ++/* Locate a packet given a pktid */ ++static INLINE void *dhd_prot_packet_get(dhd_pub_t *dhd, uint32 pktid, uint8 pkttype, ++ bool free_pktid); ++/* Locate a packet given a PktId and free it. */ ++static INLINE void dhd_prot_packet_free(dhd_pub_t *dhd, void *pkt, uint8 pkttype, bool send); ++ ++static int dhd_msgbuf_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, ++ void *buf, uint len, uint8 action); ++static int dhd_msgbuf_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, ++ void *buf, uint len, uint8 action); ++static int dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf); ++static int dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, ++ void *buf, int ifidx); ++ ++/* Post buffers for Rx, control ioctl response and events */ ++static uint16 dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, uint8 msgid, uint32 max_to_post); ++static void dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd_pub_t *pub); ++static void dhd_msgbuf_rxbuf_post_event_bufs(dhd_pub_t *pub); ++static void dhd_msgbuf_rxbuf_post(dhd_pub_t *dhd, bool use_rsv_pktid); ++static int dhd_prot_rxbuf_post(dhd_pub_t *dhd, uint16 count, bool use_rsv_pktid); ++static int dhd_msgbuf_rxbuf_post_ts_bufs(dhd_pub_t *pub); ++ ++static void dhd_prot_return_rxbuf(dhd_pub_t *dhd, uint32 pktid, uint32 rxcnt); ++ ++ ++/* D2H Message handling */ ++static int dhd_prot_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8 *buf, uint32 len); ++ ++/* D2H Message handlers */ ++static void dhd_prot_noop(dhd_pub_t *dhd, void *msg); ++static void dhd_prot_txstatus_process(dhd_pub_t *dhd, void *msg); ++static void dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void *msg); ++static void dhd_prot_ioctack_process(dhd_pub_t *dhd, void *msg); ++static void dhd_prot_ringstatus_process(dhd_pub_t *dhd, void *msg); ++static void dhd_prot_genstatus_process(dhd_pub_t *dhd, void *msg); ++static void dhd_prot_event_process(dhd_pub_t *dhd, void *msg); ++ ++/* Loopback test with dongle */ ++static void dmaxfer_free_dmaaddr(dhd_pub_t *dhd, dhd_dmaxfer_t *dma); ++static int dmaxfer_prepare_dmaaddr(dhd_pub_t *dhd, uint len, uint srcdelay, ++ uint destdelay, dhd_dmaxfer_t *dma); ++static void dhd_msgbuf_dmaxfer_process(dhd_pub_t *dhd, void *msg); ++ ++/* Flowring management communication with dongle */ ++static void dhd_prot_flow_ring_create_response_process(dhd_pub_t *dhd, void *msg); ++static void dhd_prot_flow_ring_delete_response_process(dhd_pub_t *dhd, void *msg); ++static void dhd_prot_flow_ring_flush_response_process(dhd_pub_t *dhd, void *msg); ++static void dhd_prot_process_flow_ring_resume_response(dhd_pub_t *dhd, void* msg); ++static void dhd_prot_process_flow_ring_suspend_response(dhd_pub_t *dhd, void* msg); ++ ++/* Monitor Mode */ ++#ifdef WL_MONITOR ++extern bool dhd_monitor_enabled(dhd_pub_t *dhd, int ifidx); ++extern void dhd_rx_mon_pkt(dhd_pub_t *dhdp, host_rxbuf_cmpl_t* msg, void *pkt, int ifidx); ++#endif /* WL_MONITOR */ ++ ++/* Configure a soft doorbell per D2H ring */ ++static void dhd_msgbuf_ring_config_d2h_soft_doorbell(dhd_pub_t *dhd); ++static void dhd_prot_process_d2h_ring_config_complete(dhd_pub_t *dhd, void *msg); ++static void dhd_prot_process_d2h_ring_create_complete(dhd_pub_t *dhd, void *buf); ++static void dhd_prot_process_h2d_ring_create_complete(dhd_pub_t *dhd, void *buf); ++static void dhd_prot_process_d2h_mb_data(dhd_pub_t *dhd, void* buf); ++static void dhd_prot_process_infobuf_complete(dhd_pub_t *dhd, void* buf); ++static void dhd_prot_detach_info_rings(dhd_pub_t *dhd); ++static void dhd_prot_process_d2h_host_ts_complete(dhd_pub_t *dhd, void* buf); ++ ++typedef void (*dhd_msgbuf_func_t)(dhd_pub_t *dhd, void *msg); ++ ++/** callback functions for messages generated by the dongle */ ++#define MSG_TYPE_INVALID 0 ++ ++static dhd_msgbuf_func_t table_lookup[DHD_PROT_FUNCS] = { ++ dhd_prot_noop, /* 0 is MSG_TYPE_INVALID */ ++ dhd_prot_genstatus_process, /* MSG_TYPE_GEN_STATUS */ ++ dhd_prot_ringstatus_process, /* MSG_TYPE_RING_STATUS */ ++ NULL, ++ dhd_prot_flow_ring_create_response_process, /* MSG_TYPE_FLOW_RING_CREATE_CMPLT */ ++ NULL, ++ dhd_prot_flow_ring_delete_response_process, /* MSG_TYPE_FLOW_RING_DELETE_CMPLT */ ++ NULL, ++ dhd_prot_flow_ring_flush_response_process, /* MSG_TYPE_FLOW_RING_FLUSH_CMPLT */ ++ NULL, ++ dhd_prot_ioctack_process, /* MSG_TYPE_IOCTLPTR_REQ_ACK */ ++ NULL, ++ dhd_prot_ioctcmplt_process, /* MSG_TYPE_IOCTL_CMPLT */ ++ NULL, ++ dhd_prot_event_process, /* MSG_TYPE_WL_EVENT */ ++ NULL, ++ dhd_prot_txstatus_process, /* MSG_TYPE_TX_STATUS */ ++ NULL, ++ NULL, /* MSG_TYPE_RX_CMPLT use dedicated handler */ ++ NULL, ++ dhd_msgbuf_dmaxfer_process, /* MSG_TYPE_LPBK_DMAXFER_CMPLT */ ++ NULL, /* MSG_TYPE_FLOW_RING_RESUME */ ++ dhd_prot_process_flow_ring_resume_response, /* MSG_TYPE_FLOW_RING_RESUME_CMPLT */ ++ NULL, /* MSG_TYPE_FLOW_RING_SUSPEND */ ++ dhd_prot_process_flow_ring_suspend_response, /* MSG_TYPE_FLOW_RING_SUSPEND_CMPLT */ ++ NULL, /* MSG_TYPE_INFO_BUF_POST */ ++ dhd_prot_process_infobuf_complete, /* MSG_TYPE_INFO_BUF_CMPLT */ ++ NULL, /* MSG_TYPE_H2D_RING_CREATE */ ++ NULL, /* MSG_TYPE_D2H_RING_CREATE */ ++ dhd_prot_process_h2d_ring_create_complete, /* MSG_TYPE_H2D_RING_CREATE_CMPLT */ ++ dhd_prot_process_d2h_ring_create_complete, /* MSG_TYPE_D2H_RING_CREATE_CMPLT */ ++ NULL, /* MSG_TYPE_H2D_RING_CONFIG */ ++ NULL, /* MSG_TYPE_D2H_RING_CONFIG */ ++ NULL, /* MSG_TYPE_H2D_RING_CONFIG_CMPLT */ ++ dhd_prot_process_d2h_ring_config_complete, /* MSG_TYPE_D2H_RING_CONFIG_CMPLT */ ++ NULL, /* MSG_TYPE_H2D_MAILBOX_DATA */ ++ dhd_prot_process_d2h_mb_data, /* MSG_TYPE_D2H_MAILBOX_DATA */ ++ NULL, /* MSG_TYPE_TIMSTAMP_BUFPOST */ ++ NULL, /* MSG_TYPE_HOSTTIMSTAMP */ ++ dhd_prot_process_d2h_host_ts_complete, /* MSG_TYPE_HOSTTIMSTAMP_CMPLT */ ++ dhd_prot_process_fw_timestamp, /* MSG_TYPE_FIRMWARE_TIMESTAMP */ ++}; ++ ++ ++#ifdef DHD_RX_CHAINING ++ ++#define PKT_CTF_CHAINABLE(dhd, ifidx, evh, prio, h_sa, h_da, h_prio) \ ++ (dhd_wet_chainable(dhd) && \ ++ dhd_rx_pkt_chainable((dhd), (ifidx)) && \ ++ !ETHER_ISNULLDEST(((struct ether_header *)(evh))->ether_dhost) && \ ++ !ETHER_ISMULTI(((struct ether_header *)(evh))->ether_dhost) && \ ++ !eacmp((h_da), ((struct ether_header *)(evh))->ether_dhost) && \ ++ !eacmp((h_sa), ((struct ether_header *)(evh))->ether_shost) && \ ++ ((h_prio) == (prio)) && (dhd_ctf_hotbrc_check((dhd), (evh), (ifidx))) && \ ++ ((((struct ether_header *)(evh))->ether_type == HTON16(ETHER_TYPE_IP)) || \ ++ (((struct ether_header *)(evh))->ether_type == HTON16(ETHER_TYPE_IPV6)))) ++ ++static INLINE void BCMFASTPATH dhd_rxchain_reset(rxchain_info_t *rxchain); ++static void BCMFASTPATH dhd_rxchain_frame(dhd_pub_t *dhd, void *pkt, uint ifidx); ++static void BCMFASTPATH dhd_rxchain_commit(dhd_pub_t *dhd); ++ ++#define DHD_PKT_CTF_MAX_CHAIN_LEN 64 ++ ++#endif /* DHD_RX_CHAINING */ ++ ++static void dhd_prot_h2d_sync_init(dhd_pub_t *dhd); ++ ++/** ++ * D2H DMA to completion callback handlers. Based on the mode advertised by the ++ * dongle through the PCIE shared region, the appropriate callback will be ++ * registered in the proto layer to be invoked prior to precessing any message ++ * from a D2H DMA ring. If the dongle uses a read barrier or another mode that ++ * does not require host participation, then a noop callback handler will be ++ * bound that simply returns the msg_type. ++ */ ++static void dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, uint32 msg_seqnum, msgbuf_ring_t *ring, ++ uint32 tries, volatile uchar *msg, int msglen); ++static uint8 dhd_prot_d2h_sync_seqnum(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ volatile cmn_msg_hdr_t *msg, int msglen); ++static uint8 dhd_prot_d2h_sync_xorcsum(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ volatile cmn_msg_hdr_t *msg, int msglen); ++static uint8 dhd_prot_d2h_sync_none(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ volatile cmn_msg_hdr_t *msg, int msglen); ++static void dhd_prot_d2h_sync_init(dhd_pub_t *dhd); ++static int dhd_send_d2h_ringcreate(dhd_pub_t *dhd, msgbuf_ring_t *ring_to_create); ++static int dhd_send_h2d_ringcreate(dhd_pub_t *dhd, msgbuf_ring_t *ring_to_create); ++static uint16 dhd_get_max_flow_rings(dhd_pub_t *dhd); ++ ++bool ++dhd_prot_is_cmpl_ring_empty(dhd_pub_t *dhd, void *prot_info) ++{ ++ msgbuf_ring_t *flow_ring = (msgbuf_ring_t *)prot_info; ++ uint16 rd, wr; ++ bool ret; ++ ++ if (dhd->dma_d2h_ring_upd_support) { ++ wr = flow_ring->wr; ++ } else { ++ dhd_bus_cmn_readshared(dhd->bus, &wr, RING_WR_UPD, flow_ring->idx); ++ } ++ if (dhd->dma_h2d_ring_upd_support) { ++ rd = flow_ring->rd; ++ } else { ++ dhd_bus_cmn_readshared(dhd->bus, &rd, RING_RD_UPD, flow_ring->idx); ++ } ++ ret = (wr == rd) ? TRUE : FALSE; ++ return ret; ++} ++uint16 ++dhd_prot_get_h2d_max_txpost(dhd_pub_t *dhd) ++{ ++ return (uint16)h2d_max_txpost; ++} ++void ++dhd_prot_set_h2d_max_txpost(dhd_pub_t *dhd, uint16 max_txpost) ++{ ++ h2d_max_txpost = max_txpost; ++} ++/** ++ * dhd_prot_d2h_sync_livelock - when the host determines that a DMA transfer has ++ * not completed, a livelock condition occurs. Host will avert this livelock by ++ * dropping this message and moving to the next. This dropped message can lead ++ * to a packet leak, or even something disastrous in the case the dropped ++ * message happens to be a control response. ++ * Here we will log this condition. One may choose to reboot the dongle. ++ * ++ */ ++static void ++dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, uint32 msg_seqnum, msgbuf_ring_t *ring, uint32 tries, ++ volatile uchar *msg, int msglen) ++{ ++ uint32 ring_seqnum = ring->seqnum; ++ DHD_ERROR(( ++ "LIVELOCK DHD<%p> ring<%s> msg_seqnum<%u> ring_seqnum<%u:%u> tries<%u> max<%lu>" ++ " tot<%lu> dma_buf va<%p> msg<%p> curr_rd<%d>\n", ++ dhd, ring->name, msg_seqnum, ring_seqnum, ring_seqnum% D2H_EPOCH_MODULO, tries, ++ dhd->prot->d2h_sync_wait_max, dhd->prot->d2h_sync_wait_tot, ++ ring->dma_buf.va, msg, ring->curr_rd)); ++ prhex("D2H MsgBuf Failure", (volatile uchar *)msg, msglen); ++ ++ dhd_bus_dump_console_buffer(dhd->bus); ++ dhd_prot_debug_info_print(dhd); ++ ++#ifdef DHD_FW_COREDUMP ++ if (dhd->memdump_enabled) { ++ /* collect core dump */ ++ dhd->memdump_type = DUMP_TYPE_BY_LIVELOCK; ++ dhd_bus_mem_dump(dhd); ++ } ++#endif /* DHD_FW_COREDUMP */ ++ ++ dhd_schedule_reset(dhd); ++ ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++#ifdef CONFIG_ARCH_MSM ++ dhd->bus->no_cfg_restore = 1; ++#endif /* CONFIG_ARCH_MSM */ ++ dhd->hang_reason = HANG_REASON_MSGBUF_LIVELOCK; ++ dhd_os_send_hang_message(dhd); ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++} ++ ++/** ++ * dhd_prot_d2h_sync_seqnum - Sync on a D2H DMA completion using the SEQNUM ++ * mode. Sequence number is always in the last word of a message. ++ */ ++static uint8 BCMFASTPATH ++dhd_prot_d2h_sync_seqnum(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ volatile cmn_msg_hdr_t *msg, int msglen) ++{ ++ uint32 tries; ++ uint32 ring_seqnum = ring->seqnum % D2H_EPOCH_MODULO; ++ int num_words = msglen / sizeof(uint32); /* num of 32bit words */ ++ volatile uint32 *marker = (volatile uint32 *)msg + (num_words - 1); /* last word */ ++ dhd_prot_t *prot = dhd->prot; ++ uint32 msg_seqnum; ++ uint32 step = 0; ++ uint32 delay = PCIE_D2H_SYNC_DELAY; ++ uint32 total_tries = 0; ++ ++ ASSERT(msglen == ring->item_len); ++ ++ BCM_REFERENCE(delay); ++ /* ++ * For retries we have to make some sort of stepper algorithm. ++ * We see that every time when the Dongle comes out of the D3 ++ * Cold state, the first D2H mem2mem DMA takes more time to ++ * complete, leading to livelock issues. ++ * ++ * Case 1 - Apart from Host CPU some other bus master is ++ * accessing the DDR port, probably page close to the ring ++ * so, PCIE does not get a change to update the memory. ++ * Solution - Increase the number of tries. ++ * ++ * Case 2 - The 50usec delay given by the Host CPU is not ++ * sufficient for the PCIe RC to start its work. ++ * In this case the breathing time of 50usec given by ++ * the Host CPU is not sufficient. ++ * Solution: Increase the delay in a stepper fashion. ++ * This is done to ensure that there are no ++ * unwanted extra delay introdcued in normal conditions. ++ */ ++ for (step = 1; step <= PCIE_D2H_SYNC_NUM_OF_STEPS; step++) { ++ for (tries = 0; tries < PCIE_D2H_SYNC_WAIT_TRIES; tries++) { ++ msg_seqnum = *marker; ++ if (ltoh32(msg_seqnum) == ring_seqnum) { /* dma upto last word done */ ++ ring->seqnum++; /* next expected sequence number */ ++ goto dma_completed; ++ } ++ ++ total_tries = ((step-1) * PCIE_D2H_SYNC_WAIT_TRIES) + tries; ++ ++ if (total_tries > prot->d2h_sync_wait_max) ++ prot->d2h_sync_wait_max = total_tries; ++ ++ OSL_CACHE_INV(msg, msglen); /* invalidate and try again */ ++ OSL_CPU_RELAX(); /* CPU relax for msg_seqnum value to update */ ++ OSL_DELAY(delay * step); /* Add stepper delay */ ++ ++ } /* for PCIE_D2H_SYNC_WAIT_TRIES */ ++ } /* for PCIE_D2H_SYNC_NUM_OF_STEPS */ ++ ++ dhd_prot_d2h_sync_livelock(dhd, msg_seqnum, ring, total_tries, ++ (volatile uchar *) msg, msglen); ++ ++ ring->seqnum++; /* skip this message ... leak of a pktid */ ++ return MSG_TYPE_INVALID; /* invalid msg_type 0 -> noop callback */ ++ ++dma_completed: ++ ++ prot->d2h_sync_wait_tot += tries; ++ return msg->msg_type; ++} ++ ++/** ++ * dhd_prot_d2h_sync_xorcsum - Sync on a D2H DMA completion using the XORCSUM ++ * mode. The xorcsum is placed in the last word of a message. Dongle will also ++ * place a seqnum in the epoch field of the cmn_msg_hdr. ++ */ ++static uint8 BCMFASTPATH ++dhd_prot_d2h_sync_xorcsum(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ volatile cmn_msg_hdr_t *msg, int msglen) ++{ ++ uint32 tries; ++ uint32 prot_checksum = 0; /* computed checksum */ ++ int num_words = msglen / sizeof(uint32); /* num of 32bit words */ ++ uint8 ring_seqnum = ring->seqnum % D2H_EPOCH_MODULO; ++ dhd_prot_t *prot = dhd->prot; ++ uint32 step = 0; ++ uint32 delay = PCIE_D2H_SYNC_DELAY; ++ uint32 total_tries = 0; ++ ++ ASSERT(msglen == ring->item_len); ++ ++ BCM_REFERENCE(delay); ++ /* ++ * For retries we have to make some sort of stepper algorithm. ++ * We see that every time when the Dongle comes out of the D3 ++ * Cold state, the first D2H mem2mem DMA takes more time to ++ * complete, leading to livelock issues. ++ * ++ * Case 1 - Apart from Host CPU some other bus master is ++ * accessing the DDR port, probably page close to the ring ++ * so, PCIE does not get a change to update the memory. ++ * Solution - Increase the number of tries. ++ * ++ * Case 2 - The 50usec delay given by the Host CPU is not ++ * sufficient for the PCIe RC to start its work. ++ * In this case the breathing time of 50usec given by ++ * the Host CPU is not sufficient. ++ * Solution: Increase the delay in a stepper fashion. ++ * This is done to ensure that there are no ++ * unwanted extra delay introdcued in normal conditions. ++ */ ++ for (step = 1; step <= PCIE_D2H_SYNC_NUM_OF_STEPS; step++) { ++ for (tries = 0; tries < PCIE_D2H_SYNC_WAIT_TRIES; tries++) { ++ prot_checksum = bcm_compute_xor32((volatile uint32 *)msg, num_words); ++ if (prot_checksum == 0U) { /* checksum is OK */ ++ if (msg->epoch == ring_seqnum) { ++ ring->seqnum++; /* next expected sequence number */ ++ goto dma_completed; ++ } ++ } ++ ++ total_tries = ((step-1) * PCIE_D2H_SYNC_WAIT_TRIES) + tries; ++ ++ if (total_tries > prot->d2h_sync_wait_max) ++ prot->d2h_sync_wait_max = total_tries; ++ ++ OSL_CACHE_INV(msg, msglen); /* invalidate and try again */ ++ OSL_CPU_RELAX(); /* CPU relax for msg_seqnum value to update */ ++ OSL_DELAY(delay * step); /* Add stepper delay */ ++ ++ } /* for PCIE_D2H_SYNC_WAIT_TRIES */ ++ } /* for PCIE_D2H_SYNC_NUM_OF_STEPS */ ++ ++ DHD_ERROR(("%s: prot_checksum = 0x%x\n", __FUNCTION__, prot_checksum)); ++ dhd_prot_d2h_sync_livelock(dhd, msg->epoch, ring, total_tries, ++ (volatile uchar *) msg, msglen); ++ ++ ring->seqnum++; /* skip this message ... leak of a pktid */ ++ return MSG_TYPE_INVALID; /* invalid msg_type 0 -> noop callback */ ++ ++dma_completed: ++ ++ prot->d2h_sync_wait_tot += tries; ++ return msg->msg_type; ++} ++ ++/** ++ * dhd_prot_d2h_sync_none - Dongle ensure that the DMA will complete and host ++ * need to try to sync. This noop sync handler will be bound when the dongle ++ * advertises that neither the SEQNUM nor XORCSUM mode of DMA sync is required. ++ */ ++static uint8 BCMFASTPATH ++dhd_prot_d2h_sync_none(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ volatile cmn_msg_hdr_t *msg, int msglen) ++{ ++ return msg->msg_type; ++} ++ ++INLINE void ++dhd_wakeup_ioctl_event(dhd_pub_t *dhd, dhd_ioctl_recieved_status_t reason) ++{ ++ /* To synchronize with the previous memory operations call wmb() */ ++ OSL_SMP_WMB(); ++ dhd->prot->ioctl_received = reason; ++ /* Call another wmb() to make sure before waking up the other event value gets updated */ ++ OSL_SMP_WMB(); ++ dhd_os_ioctl_resp_wake(dhd); ++} ++ ++/** ++ * dhd_prot_d2h_sync_init - Setup the host side DMA sync mode based on what ++ * dongle advertizes. ++ */ ++static void ++dhd_prot_d2h_sync_init(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ prot->d2h_sync_wait_max = 0UL; ++ prot->d2h_sync_wait_tot = 0UL; ++ ++ prot->d2hring_ctrl_cpln.seqnum = D2H_EPOCH_INIT_VAL; ++ prot->d2hring_ctrl_cpln.current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; ++ ++ prot->d2hring_tx_cpln.seqnum = D2H_EPOCH_INIT_VAL; ++ prot->d2hring_tx_cpln.current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; ++ ++ prot->d2hring_rx_cpln.seqnum = D2H_EPOCH_INIT_VAL; ++ prot->d2hring_rx_cpln.current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; ++ ++ if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM) { ++ prot->d2h_sync_cb = dhd_prot_d2h_sync_seqnum; ++ DHD_ERROR(("%s(): D2H sync mechanism is SEQNUM \r\n", __FUNCTION__)); ++ } else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM) { ++ prot->d2h_sync_cb = dhd_prot_d2h_sync_xorcsum; ++ DHD_ERROR(("%s(): D2H sync mechanism is XORCSUM \r\n", __FUNCTION__)); ++ } else { ++ prot->d2h_sync_cb = dhd_prot_d2h_sync_none; ++ DHD_ERROR(("%s(): D2H sync mechanism is NONE \r\n", __FUNCTION__)); ++ } ++} ++ ++/** ++ * dhd_prot_h2d_sync_init - Per H2D common ring, setup the msgbuf ring seqnum ++ */ ++static void ++dhd_prot_h2d_sync_init(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ prot->h2dring_rxp_subn.seqnum = H2D_EPOCH_INIT_VAL; ++ prot->h2dring_rxp_subn.current_phase = 0; ++ ++ prot->h2dring_ctrl_subn.seqnum = H2D_EPOCH_INIT_VAL; ++ prot->h2dring_ctrl_subn.current_phase = 0; ++} ++ ++/* +----------------- End of PCIE DHD H2D DMA SYNC ------------------------+ */ ++ ++ ++/* ++ * +---------------------------------------------------------------------------+ ++ * PCIE DMA-able buffer. Sets up a dhd_dma_buf_t object, which includes the ++ * virtual and physical address, the buffer lenght and the DMA handler. ++ * A secdma handler is also included in the dhd_dma_buf object. ++ * +---------------------------------------------------------------------------+ ++ */ ++ ++static INLINE void ++dhd_base_addr_htolpa(sh_addr_t *base_addr, dmaaddr_t pa) ++{ ++ base_addr->low_addr = htol32(PHYSADDRLO(pa)); ++ base_addr->high_addr = htol32(PHYSADDRHI(pa)); ++} ++ ++ ++/** ++ * dhd_dma_buf_audit - Any audits on a DHD DMA Buffer. ++ */ ++static int ++dhd_dma_buf_audit(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf) ++{ ++ uint32 pa_lowaddr, end; /* dongle uses 32bit ptr arithmetic */ ++ ASSERT(dma_buf); ++ pa_lowaddr = PHYSADDRLO(dma_buf->pa); ++ ASSERT(PHYSADDRLO(dma_buf->pa) || PHYSADDRHI(dma_buf->pa)); ++ ASSERT(ISALIGNED(pa_lowaddr, DMA_ALIGN_LEN)); ++ ASSERT(dma_buf->len != 0); ++ ++ /* test 32bit offset arithmetic over dma buffer for loss of carry-over */ ++ end = (pa_lowaddr + dma_buf->len); /* end address */ ++ ++ if ((end & 0xFFFFFFFF) < (pa_lowaddr & 0xFFFFFFFF)) { /* exclude carryover */ ++ DHD_ERROR(("%s: dma_buf %x len %d spans dongle 32bit ptr arithmetic\n", ++ __FUNCTION__, pa_lowaddr, dma_buf->len)); ++ return BCME_ERROR; ++ } ++ ++ return BCME_OK; ++} ++ ++/** ++ * dhd_dma_buf_alloc - Allocate a cache coherent DMA-able buffer. ++ * returns BCME_OK=0 on success ++ * returns non-zero negative error value on failure. ++ */ ++static int ++dhd_dma_buf_alloc(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf, uint32 buf_len) ++{ ++ uint32 dma_pad = 0; ++ osl_t *osh = dhd->osh; ++ uint16 dma_align = DMA_ALIGN_LEN; ++ ++ ++ ASSERT(dma_buf != NULL); ++ ASSERT(dma_buf->va == NULL); ++ ASSERT(dma_buf->len == 0); ++ ++ /* Pad the buffer length by one extra cacheline size. ++ * Required for D2H direction. ++ */ ++ dma_pad = (buf_len % DHD_DMA_PAD) ? DHD_DMA_PAD : 0; ++ dma_buf->va = DMA_ALLOC_CONSISTENT(osh, buf_len + dma_pad, ++ dma_align, &dma_buf->_alloced, &dma_buf->pa, &dma_buf->dmah); ++ ++ if (dma_buf->va == NULL) { ++ DHD_ERROR(("%s: buf_len %d, no memory available\n", ++ __FUNCTION__, buf_len)); ++ return BCME_NOMEM; ++ } ++ ++ dma_buf->len = buf_len; /* not including padded len */ ++ ++ if (dhd_dma_buf_audit(dhd, dma_buf) != BCME_OK) { /* audit dma buf */ ++ dhd_dma_buf_free(dhd, dma_buf); ++ return BCME_ERROR; ++ } ++ ++ dhd_dma_buf_reset(dhd, dma_buf); /* zero out and cache flush */ ++ ++ return BCME_OK; ++} ++ ++/** ++ * dhd_dma_buf_reset - Reset a cache coherent DMA-able buffer. ++ */ ++static void ++dhd_dma_buf_reset(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf) ++{ ++ if ((dma_buf == NULL) || (dma_buf->va == NULL)) ++ return; ++ ++ (void)dhd_dma_buf_audit(dhd, dma_buf); ++ ++ /* Zero out the entire buffer and cache flush */ ++ memset((void*)dma_buf->va, 0, dma_buf->len); ++ OSL_CACHE_FLUSH((void *)dma_buf->va, dma_buf->len); ++} ++ ++/** ++ * dhd_dma_buf_free - Free a DMA-able buffer that was previously allocated using ++ * dhd_dma_buf_alloc(). ++ */ ++static void ++dhd_dma_buf_free(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf) ++{ ++ osl_t *osh = dhd->osh; ++ ++ ASSERT(dma_buf); ++ ++ if (dma_buf->va == NULL) ++ return; /* Allow for free invocation, when alloc failed */ ++ ++ /* DEBUG: dhd_dma_buf_reset(dhd, dma_buf) */ ++ (void)dhd_dma_buf_audit(dhd, dma_buf); ++ ++ /* dma buffer may have been padded at allocation */ ++ DMA_FREE_CONSISTENT(osh, dma_buf->va, dma_buf->_alloced, ++ dma_buf->pa, dma_buf->dmah); ++ ++ memset(dma_buf, 0, sizeof(dhd_dma_buf_t)); ++} ++ ++/** ++ * dhd_dma_buf_init - Initialize a dhd_dma_buf with speicifed values. ++ * Do not use dhd_dma_buf_init to zero out a dhd_dma_buf_t object. Use memset 0. ++ */ ++void ++dhd_dma_buf_init(dhd_pub_t *dhd, void *dhd_dma_buf, ++ void *va, uint32 len, dmaaddr_t pa, void *dmah, void *secdma) ++{ ++ dhd_dma_buf_t *dma_buf; ++ ASSERT(dhd_dma_buf); ++ dma_buf = (dhd_dma_buf_t *)dhd_dma_buf; ++ dma_buf->va = va; ++ dma_buf->len = len; ++ dma_buf->pa = pa; ++ dma_buf->dmah = dmah; ++ dma_buf->secdma = secdma; ++ ++ /* Audit user defined configuration */ ++ (void)dhd_dma_buf_audit(dhd, dma_buf); ++} ++ ++/* +------------------ End of PCIE DHD DMA BUF ADT ------------------------+ */ ++ ++/* ++ * +---------------------------------------------------------------------------+ ++ * PktId Map: Provides a native packet pointer to unique 32bit PktId mapping. ++ * Main purpose is to save memory on the dongle, has other purposes as well. ++ * The packet id map, also includes storage for some packet parameters that ++ * may be saved. A native packet pointer along with the parameters may be saved ++ * and a unique 32bit pkt id will be returned. Later, the saved packet pointer ++ * and the metadata may be retrieved using the previously allocated packet id. ++ * +---------------------------------------------------------------------------+ ++ */ ++#define DHD_PCIE_PKTID ++#define MAX_CTRL_PKTID (1024) /* Maximum number of pktids supported */ ++#define MAX_RX_PKTID (1024) ++#define MAX_TX_PKTID (3072 * 2) ++ ++/* On Router, the pktptr serves as a pktid. */ ++ ++ ++#if defined(PROP_TXSTATUS) && !defined(DHD_PCIE_PKTID) ++#error "PKTIDMAP must be supported with PROP_TXSTATUS/WLFC" ++#endif ++ ++/* Enum for marking the buffer color based on usage */ ++typedef enum dhd_pkttype { ++ PKTTYPE_DATA_TX = 0, ++ PKTTYPE_DATA_RX, ++ PKTTYPE_IOCTL_RX, ++ PKTTYPE_EVENT_RX, ++ PKTTYPE_INFO_RX, ++ /* dhd_prot_pkt_free no check, if pktid reserved and no space avail case */ ++ PKTTYPE_NO_CHECK, ++ PKTTYPE_TSBUF_RX ++} dhd_pkttype_t; ++ ++#define DHD_PKTID_INVALID (0U) ++#define DHD_IOCTL_REQ_PKTID (0xFFFE) ++#define DHD_FAKE_PKTID (0xFACE) ++#define DHD_H2D_DBGRING_REQ_PKTID 0xFFFD ++#define DHD_D2H_DBGRING_REQ_PKTID 0xFFFC ++#define DHD_H2D_HOSTTS_REQ_PKTID 0xFFFB ++ ++#define IS_FLOWRING(ring) \ ++ ((strncmp(ring->name, "h2dflr", sizeof("h2dflr"))) == (0)) ++ ++typedef void * dhd_pktid_map_handle_t; /* opaque handle to a pktid map */ ++ ++/* Construct a packet id mapping table, returning an opaque map handle */ ++static dhd_pktid_map_handle_t *dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items); ++ ++/* Destroy a packet id mapping table, freeing all packets active in the table */ ++static void dhd_pktid_map_fini(dhd_pub_t *dhd, dhd_pktid_map_handle_t *map); ++ ++#define DHD_NATIVE_TO_PKTID_INIT(dhd, items) dhd_pktid_map_init((dhd), (items)) ++#define DHD_NATIVE_TO_PKTID_RESET(dhd, map) dhd_pktid_map_reset((dhd), (map)) ++#define DHD_NATIVE_TO_PKTID_FINI(dhd, map) dhd_pktid_map_fini((dhd), (map)) ++#define DHD_NATIVE_TO_PKTID_FINI_IOCTL(osh, map) dhd_pktid_map_fini_ioctl((osh), (map)) ++ ++#ifdef MACOSX_DHD ++#undef DHD_PCIE_PKTID ++#define DHD_PCIE_PKTID 1 ++#endif /* MACOSX_DHD */ ++ ++#if defined(DHD_PCIE_PKTID) ++#if defined(MACOSX_DHD) || defined(DHD_EFI) ++#define IOCTLRESP_USE_CONSTMEM ++static void free_ioctl_return_buffer(dhd_pub_t *dhd, dhd_dma_buf_t *retbuf); ++static int alloc_ioctl_return_buffer(dhd_pub_t *dhd, dhd_dma_buf_t *retbuf); ++#endif ++ ++/* Determine number of pktids that are available */ ++static INLINE uint32 dhd_pktid_map_avail_cnt(dhd_pktid_map_handle_t *handle); ++ ++/* Allocate a unique pktid against which a pkt and some metadata is saved */ ++static INLINE uint32 dhd_pktid_map_reserve(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, ++ void *pkt, dhd_pkttype_t pkttype); ++static INLINE void dhd_pktid_map_save(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, ++ void *pkt, uint32 nkey, dmaaddr_t pa, uint32 len, uint8 dma, ++ void *dmah, void *secdma, dhd_pkttype_t pkttype); ++static uint32 dhd_pktid_map_alloc(dhd_pub_t *dhd, dhd_pktid_map_handle_t *map, ++ void *pkt, dmaaddr_t pa, uint32 len, uint8 dma, ++ void *dmah, void *secdma, dhd_pkttype_t pkttype); ++ ++/* Return an allocated pktid, retrieving previously saved pkt and metadata */ ++static void *dhd_pktid_map_free(dhd_pub_t *dhd, dhd_pktid_map_handle_t *map, ++ uint32 id, dmaaddr_t *pa, uint32 *len, void **dmah, ++ void **secdma, dhd_pkttype_t pkttype, bool rsv_locker); ++ ++/* ++ * DHD_PKTID_AUDIT_ENABLED: Audit of PktIds in DHD for duplicate alloc and frees ++ * ++ * DHD_PKTID_AUDIT_MAP: Audit the LIFO or FIFO PktIdMap allocator ++ * DHD_PKTID_AUDIT_RING: Audit the pktid during producer/consumer ring operation ++ * ++ * CAUTION: When DHD_PKTID_AUDIT_ENABLED is defined, ++ * either DHD_PKTID_AUDIT_MAP or DHD_PKTID_AUDIT_RING may be selected. ++ */ ++#if defined(DHD_PKTID_AUDIT_ENABLED) ++#define USE_DHD_PKTID_AUDIT_LOCK 1 ++/* Audit the pktidmap allocator */ ++/* #define DHD_PKTID_AUDIT_MAP */ ++ ++/* Audit the pktid during production/consumption of workitems */ ++#define DHD_PKTID_AUDIT_RING ++ ++#if defined(DHD_PKTID_AUDIT_MAP) && defined(DHD_PKTID_AUDIT_RING) ++#error "May only enabled audit of MAP or RING, at a time." ++#endif /* DHD_PKTID_AUDIT_MAP && DHD_PKTID_AUDIT_RING */ ++ ++#define DHD_DUPLICATE_ALLOC 1 ++#define DHD_DUPLICATE_FREE 2 ++#define DHD_TEST_IS_ALLOC 3 ++#define DHD_TEST_IS_FREE 4 ++ ++#ifdef USE_DHD_PKTID_AUDIT_LOCK ++#define DHD_PKTID_AUDIT_LOCK_INIT(osh) dhd_os_spin_lock_init(osh) ++#define DHD_PKTID_AUDIT_LOCK_DEINIT(osh, lock) dhd_os_spin_lock_deinit(osh, lock) ++#define DHD_PKTID_AUDIT_LOCK(lock) dhd_os_spin_lock(lock) ++#define DHD_PKTID_AUDIT_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, flags) ++#else ++#define DHD_PKTID_AUDIT_LOCK_INIT(osh) (void *)(1) ++#define DHD_PKTID_AUDIT_LOCK_DEINIT(osh, lock) do { /* noop */ } while (0) ++#define DHD_PKTID_AUDIT_LOCK(lock) 0 ++#define DHD_PKTID_AUDIT_UNLOCK(lock, flags) do { /* noop */ } while (0) ++#endif /* !USE_DHD_PKTID_AUDIT_LOCK */ ++ ++#endif /* DHD_PKTID_AUDIT_ENABLED */ ++ ++/* #define USE_DHD_PKTID_LOCK 1 */ ++ ++#ifdef USE_DHD_PKTID_LOCK ++#define DHD_PKTID_LOCK_INIT(osh) dhd_os_spin_lock_init(osh) ++#define DHD_PKTID_LOCK_DEINIT(osh, lock) dhd_os_spin_lock_deinit(osh, lock) ++#define DHD_PKTID_LOCK(lock) dhd_os_spin_lock(lock) ++#define DHD_PKTID_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, flags) ++#else ++#define DHD_PKTID_LOCK_INIT(osh) (void *)(1) ++#define DHD_PKTID_LOCK_DEINIT(osh, lock) \ ++ do { \ ++ BCM_REFERENCE(osh); \ ++ BCM_REFERENCE(lock); \ ++ } while (0) ++#define DHD_PKTID_LOCK(lock) 0 ++#define DHD_PKTID_UNLOCK(lock, flags) \ ++ do { \ ++ BCM_REFERENCE(lock); \ ++ BCM_REFERENCE(flags); \ ++ } while (0) ++#endif /* !USE_DHD_PKTID_LOCK */ ++ ++typedef enum dhd_locker_state { ++ LOCKER_IS_FREE, ++ LOCKER_IS_BUSY, ++ LOCKER_IS_RSVD ++} dhd_locker_state_t; ++ ++/* Packet metadata saved in packet id mapper */ ++ ++typedef struct dhd_pktid_item { ++ dhd_locker_state_t state; /* tag a locker to be free, busy or reserved */ ++ uint8 dir; /* dma map direction (Tx=flush or Rx=invalidate) */ ++ dhd_pkttype_t pkttype; /* pktlists are maintained based on pkttype */ ++ uint16 len; /* length of mapped packet's buffer */ ++ void *pkt; /* opaque native pointer to a packet */ ++ dmaaddr_t pa; /* physical address of mapped packet's buffer */ ++ void *dmah; /* handle to OS specific DMA map */ ++ void *secdma; ++} dhd_pktid_item_t; ++ ++typedef uint32 dhd_pktid_key_t; ++ ++typedef struct dhd_pktid_map { ++ uint32 items; /* total items in map */ ++ uint32 avail; /* total available items */ ++ int failures; /* lockers unavailable count */ ++#if defined(DHD_PKTID_AUDIT_ENABLED) ++ void *pktid_audit_lock; ++ struct bcm_mwbmap *pktid_audit; /* multi word bitmap based audit */ ++#endif /* DHD_PKTID_AUDIT_ENABLED */ ++ dhd_pktid_key_t *keys; /* map_items +1 unique pkt ids */ ++ dhd_pktid_item_t lockers[0]; /* metadata storage */ ++} dhd_pktid_map_t; ++ ++/* ++ * PktId (Locker) #0 is never allocated and is considered invalid. ++ * ++ * On request for a pktid, a value DHD_PKTID_INVALID must be treated as a ++ * depleted pktid pool and must not be used by the caller. ++ * ++ * Likewise, a caller must never free a pktid of value DHD_PKTID_INVALID. ++ */ ++ ++#define DHD_PKTID_FREE_LOCKER (FALSE) ++#define DHD_PKTID_RSV_LOCKER (TRUE) ++ ++#define DHD_PKTID_ITEM_SZ (sizeof(dhd_pktid_item_t)) ++#define DHD_PKIDMAP_ITEMS(items) (items) ++#define DHD_PKTID_MAP_SZ(items) (sizeof(dhd_pktid_map_t) + \ ++ (DHD_PKTID_ITEM_SZ * ((items) + 1))) ++#define DHD_PKTIDMAP_KEYS_SZ(items) (sizeof(dhd_pktid_key_t) * ((items) + 1)) ++ ++#define DHD_NATIVE_TO_PKTID_RESET_IOCTL(dhd, map) dhd_pktid_map_reset_ioctl((dhd), (map)) ++ ++/* Convert a packet to a pktid, and save pkt pointer in busy locker */ ++#define DHD_NATIVE_TO_PKTID_RSV(dhd, map, pkt, pkttype) \ ++ dhd_pktid_map_reserve((dhd), (map), (pkt), (pkttype)) ++/* Reuse a previously reserved locker to save packet params */ ++#define DHD_NATIVE_TO_PKTID_SAVE(dhd, map, pkt, nkey, pa, len, dir, dmah, secdma, pkttype) \ ++ dhd_pktid_map_save((dhd), (map), (void *)(pkt), (nkey), (pa), (uint32)(len), \ ++ (uint8)(dir), (void *)(dmah), (void *)(secdma), \ ++ (dhd_pkttype_t)(pkttype)) ++/* Convert a packet to a pktid, and save packet params in locker */ ++#define DHD_NATIVE_TO_PKTID(dhd, map, pkt, pa, len, dir, dmah, secdma, pkttype) \ ++ dhd_pktid_map_alloc((dhd), (map), (void *)(pkt), (pa), (uint32)(len), \ ++ (uint8)(dir), (void *)(dmah), (void *)(secdma), \ ++ (dhd_pkttype_t)(pkttype)) ++ ++/* Convert pktid to a packet, and free the locker */ ++#define DHD_PKTID_TO_NATIVE(dhd, map, pktid, pa, len, dmah, secdma, pkttype) \ ++ dhd_pktid_map_free((dhd), (map), (uint32)(pktid), \ ++ (dmaaddr_t *)&(pa), (uint32 *)&(len), (void **)&(dmah), \ ++ (void **)&(secdma), (dhd_pkttype_t)(pkttype), DHD_PKTID_FREE_LOCKER) ++ ++/* Convert the pktid to a packet, empty locker, but keep it reserved */ ++#define DHD_PKTID_TO_NATIVE_RSV(dhd, map, pktid, pa, len, dmah, secdma, pkttype) \ ++ dhd_pktid_map_free((dhd), (map), (uint32)(pktid), \ ++ (dmaaddr_t *)&(pa), (uint32 *)&(len), (void **)&(dmah), \ ++ (void **)&(secdma), (dhd_pkttype_t)(pkttype), DHD_PKTID_RSV_LOCKER) ++ ++#define DHD_PKTID_AVAIL(map) dhd_pktid_map_avail_cnt(map) ++ ++#if defined(DHD_PKTID_AUDIT_ENABLED) ++/** ++* dhd_pktid_audit - Use the mwbmap to audit validity of a pktid. ++*/ ++static int ++dhd_pktid_audit(dhd_pub_t *dhd, dhd_pktid_map_t *pktid_map, uint32 pktid, ++ const int test_for, const char *errmsg) ++{ ++#define DHD_PKT_AUDIT_STR "ERROR: %16s Host PktId Audit: " ++ struct bcm_mwbmap *handle; ++ uint32 flags; ++ bool ignore_audit; ++ ++ if (pktid_map == (dhd_pktid_map_t *)NULL) { ++ DHD_ERROR((DHD_PKT_AUDIT_STR "Pkt id map NULL\n", errmsg)); ++ return BCME_OK; ++ } ++ ++ flags = DHD_PKTID_AUDIT_LOCK(pktid_map->pktid_audit_lock); ++ ++ handle = pktid_map->pktid_audit; ++ if (handle == (struct bcm_mwbmap *)NULL) { ++ DHD_ERROR((DHD_PKT_AUDIT_STR "Handle NULL\n", errmsg)); ++ DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); ++ return BCME_OK; ++ } ++ ++ /* Exclude special pktids from audit */ ++ ignore_audit = (pktid == DHD_IOCTL_REQ_PKTID) | (pktid == DHD_FAKE_PKTID); ++ if (ignore_audit) { ++ DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); ++ return BCME_OK; ++ } ++ ++ if ((pktid == DHD_PKTID_INVALID) || (pktid > pktid_map->items)) { ++ DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> invalid\n", errmsg, pktid)); ++ /* lock is released in "error" */ ++ goto error; ++ } ++ ++ /* Perform audit */ ++ switch (test_for) { ++ case DHD_DUPLICATE_ALLOC: ++ if (!bcm_mwbmap_isfree(handle, pktid)) { ++ DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> alloc duplicate\n", ++ errmsg, pktid)); ++ goto error; ++ } ++ bcm_mwbmap_force(handle, pktid); ++ break; ++ ++ case DHD_DUPLICATE_FREE: ++ if (bcm_mwbmap_isfree(handle, pktid)) { ++ DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> free duplicate\n", ++ errmsg, pktid)); ++ goto error; ++ } ++ bcm_mwbmap_free(handle, pktid); ++ break; ++ ++ case DHD_TEST_IS_ALLOC: ++ if (bcm_mwbmap_isfree(handle, pktid)) { ++ DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> is not allocated\n", ++ errmsg, pktid)); ++ goto error; ++ } ++ break; ++ ++ case DHD_TEST_IS_FREE: ++ if (!bcm_mwbmap_isfree(handle, pktid)) { ++ DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> is not free", ++ errmsg, pktid)); ++ goto error; ++ } ++ break; ++ ++ default: ++ goto error; ++ } ++ ++ DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); ++ return BCME_OK; ++ ++error: ++ ++ DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); ++ /* May insert any trap mechanism here ! */ ++ dhd_pktid_error_handler(dhd); ++ ++ return BCME_ERROR; ++} ++ ++#define DHD_PKTID_AUDIT(dhdp, map, pktid, test_for) \ ++ dhd_pktid_audit((dhdp), (dhd_pktid_map_t *)(map), (pktid), (test_for), __FUNCTION__) ++ ++static int ++dhd_pktid_audit_ring_debug(dhd_pub_t *dhdp, dhd_pktid_map_t *map, uint32 pktid, ++ const int test_for, void *msg, uint32 msg_len, const char * func) ++{ ++ int ret = 0; ++ ret = DHD_PKTID_AUDIT(dhdp, map, pktid, test_for); ++ if (ret == BCME_ERROR) { ++ prhex(func, (uchar *)msg, msg_len); ++ } ++ return ret; ++} ++#define DHD_PKTID_AUDIT_RING_DEBUG(dhdp, map, pktid, test_for, msg, msg_len) \ ++ dhd_pktid_audit_ring_debug((dhdp), (dhd_pktid_map_t *)(map), \ ++ (pktid), (test_for), msg, msg_len, __FUNCTION__) ++ ++#endif /* DHD_PKTID_AUDIT_ENABLED */ ++ ++ ++/** ++ * +---------------------------------------------------------------------------+ ++ * Packet to Packet Id mapper using a paradigm. ++ * ++ * dhd_pktid_map manages a set of unique Packet Ids range[1..MAX_xxx_PKTID]. ++ * ++ * dhd_pktid_map_alloc() may be used to save some packet metadata, and a unique ++ * packet id is returned. This unique packet id may be used to retrieve the ++ * previously saved packet metadata, using dhd_pktid_map_free(). On invocation ++ * of dhd_pktid_map_free(), the unique packet id is essentially freed. A ++ * subsequent call to dhd_pktid_map_alloc() may reuse this packet id. ++ * ++ * Implementation Note: ++ * Convert this into a abstraction and place into bcmutils ! ++ * Locker abstraction should treat contents as opaque storage, and a ++ * callback should be registered to handle busy lockers on destructor. ++ * ++ * +---------------------------------------------------------------------------+ ++ */ ++ ++/** Allocate and initialize a mapper of num_items */ ++ ++static dhd_pktid_map_handle_t * ++dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items) ++{ ++ void* osh; ++ uint32 nkey; ++ dhd_pktid_map_t *map; ++ uint32 dhd_pktid_map_sz; ++ uint32 map_items; ++ uint32 map_keys_sz; ++ osh = dhd->osh; ++ ++ dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(num_items); ++ ++ map = (dhd_pktid_map_t *)VMALLOC(osh, dhd_pktid_map_sz); ++ if (map == NULL) { ++ DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", ++ __FUNCTION__, __LINE__, dhd_pktid_map_sz)); ++ return (dhd_pktid_map_handle_t *)NULL; ++ } ++ ++ /* Initialize the lock that protects this structure */ ++ map->items = num_items; ++ map->avail = num_items; ++ ++ map_items = DHD_PKIDMAP_ITEMS(map->items); ++ ++ map_keys_sz = DHD_PKTIDMAP_KEYS_SZ(map->items); ++ map->keys = (dhd_pktid_key_t *)MALLOC(osh, map_keys_sz); ++ if (map->keys == NULL) { ++ DHD_ERROR(("%s:%d: MALLOC failed for map->keys size %d\n", ++ __FUNCTION__, __LINE__, map_keys_sz)); ++ goto error; ++ } ++ ++#if defined(DHD_PKTID_AUDIT_ENABLED) ++ /* Incarnate a hierarchical multiword bitmap for auditing pktid allocator */ ++ map->pktid_audit = bcm_mwbmap_init(osh, map_items + 1); ++ if (map->pktid_audit == (struct bcm_mwbmap *)NULL) { ++ DHD_ERROR(("%s:%d: pktid_audit init failed\r\n", __FUNCTION__, __LINE__)); ++ goto error; ++ } else { ++ DHD_ERROR(("%s:%d: pktid_audit init succeeded %d\n", ++ __FUNCTION__, __LINE__, map_items + 1)); ++ } ++ map->pktid_audit_lock = DHD_PKTID_AUDIT_LOCK_INIT(osh); ++#endif /* DHD_PKTID_AUDIT_ENABLED */ ++ ++ for (nkey = 1; nkey <= map_items; nkey++) { /* locker #0 is reserved */ ++ map->keys[nkey] = nkey; /* populate with unique keys */ ++ map->lockers[nkey].state = LOCKER_IS_FREE; ++ map->lockers[nkey].pkt = NULL; /* bzero: redundant */ ++ map->lockers[nkey].len = 0; ++ } ++ ++ /* Reserve pktid #0, i.e. DHD_PKTID_INVALID to be inuse */ ++ map->lockers[DHD_PKTID_INVALID].state = LOCKER_IS_BUSY; /* tag locker #0 as inuse */ ++ map->lockers[DHD_PKTID_INVALID].pkt = NULL; /* bzero: redundant */ ++ map->lockers[DHD_PKTID_INVALID].len = 0; ++ ++#if defined(DHD_PKTID_AUDIT_ENABLED) ++ /* do not use dhd_pktid_audit() here, use bcm_mwbmap_force directly */ ++ bcm_mwbmap_force(map->pktid_audit, DHD_PKTID_INVALID); ++#endif /* DHD_PKTID_AUDIT_ENABLED */ ++ ++ return (dhd_pktid_map_handle_t *)map; /* opaque handle */ ++ ++error: ++ if (map) { ++#if defined(DHD_PKTID_AUDIT_ENABLED) ++ if (map->pktid_audit != (struct bcm_mwbmap *)NULL) { ++ bcm_mwbmap_fini(osh, map->pktid_audit); /* Destruct pktid_audit */ ++ map->pktid_audit = (struct bcm_mwbmap *)NULL; ++ if (map->pktid_audit_lock) ++ DHD_PKTID_AUDIT_LOCK_DEINIT(osh, map->pktid_audit_lock); ++ } ++#endif /* DHD_PKTID_AUDIT_ENABLED */ ++ if (map->keys) { ++ MFREE(osh, map->keys, map_keys_sz); ++ } ++ VMFREE(osh, map, dhd_pktid_map_sz); ++ } ++ return (dhd_pktid_map_handle_t *)NULL; ++} ++ ++/** ++ * Retrieve all allocated keys and free all . ++ * Freeing implies: unmapping the buffers and freeing the native packet ++ * This could have been a callback registered with the pktid mapper. ++ */ ++static void ++dhd_pktid_map_reset(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) ++{ ++ void *osh; ++ uint32 nkey; ++ dhd_pktid_map_t *map; ++ dhd_pktid_item_t *locker; ++ uint32 map_items; ++ uint32 flags; ++ bool data_tx = FALSE; ++ ++ map = (dhd_pktid_map_t *)handle; ++ DHD_GENERAL_LOCK(dhd, flags); ++ osh = dhd->osh; ++ ++ map_items = DHD_PKIDMAP_ITEMS(map->items); ++ /* skip reserved KEY #0, and start from 1 */ ++ ++ for (nkey = 1; nkey <= map_items; nkey++) { ++ if (map->lockers[nkey].state == LOCKER_IS_BUSY) { ++ locker = &map->lockers[nkey]; ++ locker->state = LOCKER_IS_FREE; ++ data_tx = (locker->pkttype == PKTTYPE_DATA_TX); ++ if (data_tx) { ++ dhd->prot->active_tx_count--; ++ } ++ ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_DUPLICATE_FREE); /* duplicate frees */ ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ { ++ if (SECURE_DMA_ENAB(dhd->osh)) ++ SECURE_DMA_UNMAP(osh, locker->pa, ++ locker->len, locker->dir, 0, ++ locker->dmah, locker->secdma, 0); ++ else ++ DMA_UNMAP(osh, locker->pa, locker->len, ++ locker->dir, 0, locker->dmah); ++ } ++ dhd_prot_packet_free(dhd, (ulong*)locker->pkt, ++ locker->pkttype, data_tx); ++ } ++ else { ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_TEST_IS_FREE); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ } ++ map->keys[nkey] = nkey; /* populate with unique keys */ ++ } ++ ++ map->avail = map_items; ++ memset(&map->lockers[1], 0, sizeof(dhd_pktid_item_t) * map_items); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++} ++ ++#ifdef IOCTLRESP_USE_CONSTMEM ++/** Called in detach scenario. Releasing IOCTL buffers. */ ++static void ++dhd_pktid_map_reset_ioctl(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) ++{ ++ uint32 nkey; ++ dhd_pktid_map_t *map; ++ dhd_pktid_item_t *locker; ++ uint32 map_items; ++ uint32 flags; ++ ++ map = (dhd_pktid_map_t *)handle; ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ map_items = DHD_PKIDMAP_ITEMS(map->items); ++ /* skip reserved KEY #0, and start from 1 */ ++ for (nkey = 1; nkey <= map_items; nkey++) { ++ if (map->lockers[nkey].state == LOCKER_IS_BUSY) { ++ dhd_dma_buf_t retbuf; ++ ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_DUPLICATE_FREE); /* duplicate frees */ ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ locker = &map->lockers[nkey]; ++ retbuf.va = locker->pkt; ++ retbuf.len = locker->len; ++ retbuf.pa = locker->pa; ++ retbuf.dmah = locker->dmah; ++ retbuf.secdma = locker->secdma; ++ ++ /* This could be a callback registered with dhd_pktid_map */ ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ free_ioctl_return_buffer(dhd, &retbuf); ++ DHD_GENERAL_LOCK(dhd, flags); ++ } ++ else { ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_TEST_IS_FREE); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ } ++ map->keys[nkey] = nkey; /* populate with unique keys */ ++ } ++ ++ map->avail = map_items; ++ memset(&map->lockers[1], 0, sizeof(dhd_pktid_item_t) * map_items); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++} ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ ++ ++/** ++ * Free the pktid map. ++ */ ++static void ++dhd_pktid_map_fini(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) ++{ ++ dhd_pktid_map_t *map; ++ uint32 dhd_pktid_map_sz; ++ uint32 map_keys_sz; ++ ++ /* Free any pending packets */ ++ dhd_pktid_map_reset(dhd, handle); ++ ++ map = (dhd_pktid_map_t *)handle; ++ dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(map->items); ++ map_keys_sz = DHD_PKTIDMAP_KEYS_SZ(map->items); ++ ++#if defined(DHD_PKTID_AUDIT_ENABLED) ++ if (map->pktid_audit != (struct bcm_mwbmap *)NULL) { ++ bcm_mwbmap_fini(dhd->osh, map->pktid_audit); /* Destruct pktid_audit */ ++ map->pktid_audit = (struct bcm_mwbmap *)NULL; ++ if (map->pktid_audit_lock) { ++ DHD_PKTID_AUDIT_LOCK_DEINIT(dhd->osh, map->pktid_audit_lock); ++ } ++ } ++#endif /* DHD_PKTID_AUDIT_ENABLED */ ++ MFREE(dhd->osh, map->keys, map_keys_sz); ++ VMFREE(dhd->osh, handle, dhd_pktid_map_sz); ++} ++#ifdef IOCTLRESP_USE_CONSTMEM ++static void ++dhd_pktid_map_fini_ioctl(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) ++{ ++ dhd_pktid_map_t *map; ++ uint32 dhd_pktid_map_sz; ++ uint32 map_keys_sz; ++ ++ /* Free any pending packets */ ++ dhd_pktid_map_reset_ioctl(dhd, handle); ++ ++ map = (dhd_pktid_map_t *)handle; ++ dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(map->items); ++ map_keys_sz = DHD_PKTIDMAP_KEYS_SZ(map->items); ++ ++#if defined(DHD_PKTID_AUDIT_ENABLED) ++ if (map->pktid_audit != (struct bcm_mwbmap *)NULL) { ++ bcm_mwbmap_fini(dhd->osh, map->pktid_audit); /* Destruct pktid_audit */ ++ map->pktid_audit = (struct bcm_mwbmap *)NULL; ++ if (map->pktid_audit_lock) { ++ DHD_PKTID_AUDIT_LOCK_DEINIT(dhd->osh, map->pktid_audit_lock); ++ } ++ } ++#endif /* DHD_PKTID_AUDIT_ENABLED */ ++ ++ MFREE(dhd->osh, map->keys, map_keys_sz); ++ VMFREE(dhd->osh, handle, dhd_pktid_map_sz); ++} ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ ++/** Get the pktid free count */ ++static INLINE uint32 BCMFASTPATH ++dhd_pktid_map_avail_cnt(dhd_pktid_map_handle_t *handle) ++{ ++ dhd_pktid_map_t *map; ++ uint32 avail; ++ ++ ASSERT(handle != NULL); ++ map = (dhd_pktid_map_t *)handle; ++ ++ avail = map->avail; ++ ++ return avail; ++} ++ ++/** ++ * dhd_pktid_map_reserve - reserve a unique numbered key. Reserved locker is not ++ * yet populated. Invoke the pktid save api to populate the packet parameters ++ * into the locker. This function is not reentrant, and is the caller's ++ * responsibility. Caller must treat a returned value DHD_PKTID_INVALID as ++ * a failure case, implying a depleted pool of pktids. ++ */ ++static INLINE uint32 ++dhd_pktid_map_reserve(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, ++ void *pkt, dhd_pkttype_t pkttype) ++{ ++ uint32 nkey; ++ dhd_pktid_map_t *map; ++ dhd_pktid_item_t *locker; ++ ++ ASSERT(handle != NULL); ++ map = (dhd_pktid_map_t *)handle; ++ ++ if ((int)(map->avail) <= 0) { /* no more pktids to allocate */ ++ map->failures++; ++ DHD_INFO(("%s:%d: failed, no free keys\n", __FUNCTION__, __LINE__)); ++ return DHD_PKTID_INVALID; /* failed alloc request */ ++ } ++ ++ ASSERT(map->avail <= map->items); ++ nkey = map->keys[map->avail]; /* fetch a free locker, pop stack */ ++ ++ if ((map->avail > map->items) || (nkey > map->items)) { ++ map->failures++; ++ DHD_ERROR(("%s:%d: failed to allocate a new pktid," ++ " map->avail<%u>, nkey<%u>, pkttype<%u>\n", ++ __FUNCTION__, __LINE__, map->avail, nkey, ++ pkttype)); ++ return DHD_PKTID_INVALID; /* failed alloc request */ ++ } ++ ++ locker = &map->lockers[nkey]; /* save packet metadata in locker */ ++ map->avail--; ++ locker->pkt = pkt; /* pkt is saved, other params not yet saved. */ ++ locker->len = 0; ++ locker->state = LOCKER_IS_BUSY; /* reserve this locker */ ++ ++ ASSERT(nkey != DHD_PKTID_INVALID); ++ return nkey; /* return locker's numbered key */ ++} ++ ++/* ++ * dhd_pktid_map_save - Save a packet's parameters into a locker ++ * corresponding to a previously reserved unique numbered key. ++ */ ++static INLINE void ++dhd_pktid_map_save(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, void *pkt, ++ uint32 nkey, dmaaddr_t pa, uint32 len, uint8 dir, void *dmah, void *secdma, ++ dhd_pkttype_t pkttype) ++{ ++ dhd_pktid_map_t *map; ++ dhd_pktid_item_t *locker; ++ ++ ASSERT(handle != NULL); ++ map = (dhd_pktid_map_t *)handle; ++ ++ if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items))) { ++ DHD_ERROR(("%s:%d: Error! saving invalid pktid<%u> pkttype<%u>\n", ++ __FUNCTION__, __LINE__, nkey, pkttype)); ++#ifdef DHD_FW_COREDUMP ++ if (dhd->memdump_enabled) { ++ /* collect core dump */ ++ dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; ++ dhd_bus_mem_dump(dhd); ++ } ++#else ++ ASSERT(0); ++#endif /* DHD_FW_COREDUMP */ ++ return; ++ } ++ ++ locker = &map->lockers[nkey]; ++ ++ ASSERT(((locker->state == LOCKER_IS_BUSY) && (locker->pkt == pkt)) || ++ ((locker->state == LOCKER_IS_RSVD) && (locker->pkt == NULL))); ++ ++ /* store contents in locker */ ++ locker->dir = dir; ++ locker->pa = pa; ++ locker->len = (uint16)len; /* 16bit len */ ++ locker->dmah = dmah; /* 16bit len */ ++ locker->secdma = secdma; ++ locker->pkttype = pkttype; ++ locker->pkt = pkt; ++ locker->state = LOCKER_IS_BUSY; /* make this locker busy */ ++} ++ ++/** ++ * dhd_pktid_map_alloc - Allocate a unique numbered key and save the packet ++ * contents into the corresponding locker. Return the numbered key. ++ */ ++static uint32 BCMFASTPATH ++dhd_pktid_map_alloc(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, void *pkt, ++ dmaaddr_t pa, uint32 len, uint8 dir, void *dmah, void *secdma, ++ dhd_pkttype_t pkttype) ++{ ++ uint32 nkey; ++ ++ nkey = dhd_pktid_map_reserve(dhd, handle, pkt, pkttype); ++ if (nkey != DHD_PKTID_INVALID) { ++ dhd_pktid_map_save(dhd, handle, pkt, nkey, pa, ++ len, dir, dmah, secdma, pkttype); ++ } ++ ++ return nkey; ++} ++ ++/** ++ * dhd_pktid_map_free - Given a numbered key, return the locker contents. ++ * dhd_pktid_map_free() is not reentrant, and is the caller's responsibility. ++ * Caller may not free a pktid value DHD_PKTID_INVALID or an arbitrary pktid ++ * value. Only a previously allocated pktid may be freed. ++ */ ++static void * BCMFASTPATH ++dhd_pktid_map_free(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, uint32 nkey, ++ dmaaddr_t *pa, uint32 *len, void **dmah, void **secdma, dhd_pkttype_t pkttype, ++ bool rsv_locker) ++{ ++ dhd_pktid_map_t *map; ++ dhd_pktid_item_t *locker; ++ void * pkt; ++ unsigned long long locker_addr; ++ ++ ASSERT(handle != NULL); ++ ++ map = (dhd_pktid_map_t *)handle; ++ ++ if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items))) { ++ DHD_ERROR(("%s:%d: Error! Try to free invalid pktid<%u>, pkttype<%d>\n", ++ __FUNCTION__, __LINE__, nkey, pkttype)); ++#ifdef DHD_FW_COREDUMP ++ if (dhd->memdump_enabled) { ++ /* collect core dump */ ++ dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; ++ dhd_bus_mem_dump(dhd); ++ } ++#else ++ ASSERT(0); ++#endif /* DHD_FW_COREDUMP */ ++ return NULL; ++ } ++ ++ locker = &map->lockers[nkey]; ++ ++#if defined(DHD_PKTID_AUDIT_MAP) ++ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_DUPLICATE_FREE); /* Audit duplicate FREE */ ++#endif /* DHD_PKTID_AUDIT_MAP */ ++ ++ /* Debug check for cloned numbered key */ ++ if (locker->state == LOCKER_IS_FREE) { ++ DHD_ERROR(("%s:%d: Error! freeing already freed invalid pktid<%u>\n", ++ __FUNCTION__, __LINE__, nkey)); ++#ifdef DHD_FW_COREDUMP ++ if (dhd->memdump_enabled) { ++ /* collect core dump */ ++ dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; ++ dhd_bus_mem_dump(dhd); ++ } ++#else ++ ASSERT(0); ++#endif /* DHD_FW_COREDUMP */ ++ return NULL; ++ } ++ ++ /* Check for the colour of the buffer i.e The buffer posted for TX, ++ * should be freed for TX completion. Similarly the buffer posted for ++ * IOCTL should be freed for IOCT completion etc. ++ */ ++ if ((pkttype != PKTTYPE_NO_CHECK) && (locker->pkttype != pkttype)) { ++ ++ DHD_ERROR(("%s:%d: Error! Invalid Buffer Free for pktid<%u> \n", ++ __FUNCTION__, __LINE__, nkey)); ++#ifdef BCMDMA64OSL ++ PHYSADDRTOULONG(locker->pa, locker_addr); ++#else ++ locker_addr = PHYSADDRLO(locker->pa); ++#endif /* BCMDMA64OSL */ ++ DHD_ERROR(("%s:%d: locker->state <%d>, locker->pkttype <%d>," ++ "pkttype <%d> locker->pa <0x%llx> \n", ++ __FUNCTION__, __LINE__, locker->state, locker->pkttype, ++ pkttype, locker_addr)); ++#ifdef DHD_FW_COREDUMP ++ if (dhd->memdump_enabled) { ++ /* collect core dump */ ++ dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; ++ dhd_bus_mem_dump(dhd); ++ } ++#else ++ ASSERT(0); ++#endif /* DHD_FW_COREDUMP */ ++ return NULL; ++ } ++ ++ if (rsv_locker == DHD_PKTID_FREE_LOCKER) { ++ map->avail++; ++ map->keys[map->avail] = nkey; /* make this numbered key available */ ++ locker->state = LOCKER_IS_FREE; /* open and free Locker */ ++ } else { ++ /* pktid will be reused, but the locker does not have a valid pkt */ ++ locker->state = LOCKER_IS_RSVD; ++ } ++ ++#if defined(DHD_PKTID_AUDIT_MAP) ++ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_TEST_IS_FREE); ++#endif /* DHD_PKTID_AUDIT_MAP */ ++ ++ *pa = locker->pa; /* return contents of locker */ ++ *len = (uint32)locker->len; ++ *dmah = locker->dmah; ++ *secdma = locker->secdma; ++ ++ pkt = locker->pkt; ++ locker->pkt = NULL; /* Clear pkt */ ++ locker->len = 0; ++ ++ return pkt; ++} ++ ++#else /* ! DHD_PCIE_PKTID */ ++ ++ ++typedef struct pktlist { ++ PKT_LIST *tx_pkt_list; /* list for tx packets */ ++ PKT_LIST *rx_pkt_list; /* list for rx packets */ ++ PKT_LIST *ctrl_pkt_list; /* list for ioctl/event buf post */ ++} pktlists_t; ++ ++/* ++ * Given that each workitem only uses a 32bit pktid, only 32bit hosts may avail ++ * of a one to one mapping 32bit pktptr and a 32bit pktid. ++ * ++ * - When PKTIDMAP is not used, DHD_NATIVE_TO_PKTID variants will never fail. ++ * - Neither DHD_NATIVE_TO_PKTID nor DHD_PKTID_TO_NATIVE need to be protected by ++ * a lock. ++ * - Hence DHD_PKTID_INVALID is not defined when DHD_PCIE_PKTID is undefined. ++ */ ++#define DHD_PKTID32(pktptr32) ((uint32)(pktptr32)) ++#define DHD_PKTPTR32(pktid32) ((void *)(pktid32)) ++ ++ ++static INLINE uint32 dhd_native_to_pktid(dhd_pktid_map_handle_t *map, void *pktptr32, ++ dmaaddr_t pa, uint32 dma_len, void *dmah, void *secdma, ++ dhd_pkttype_t pkttype); ++static INLINE void * dhd_pktid_to_native(dhd_pktid_map_handle_t *map, uint32 pktid32, ++ dmaaddr_t *pa, uint32 *dma_len, void **dmah, void **secdma, ++ dhd_pkttype_t pkttype); ++ ++static dhd_pktid_map_handle_t * ++dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items) ++{ ++ osl_t *osh = dhd->osh; ++ pktlists_t *handle = NULL; ++ ++ if ((handle = (pktlists_t *) MALLOCZ(osh, sizeof(pktlists_t))) == NULL) { ++ DHD_ERROR(("%s:%d: MALLOC failed for lists allocation, size=%d\n", ++ __FUNCTION__, __LINE__, sizeof(pktlists_t))); ++ goto error_done; ++ } ++ ++ if ((handle->tx_pkt_list = (PKT_LIST *) MALLOC(osh, sizeof(PKT_LIST))) == NULL) { ++ DHD_ERROR(("%s:%d: MALLOC failed for list allocation, size=%d\n", ++ __FUNCTION__, __LINE__, sizeof(PKT_LIST))); ++ goto error; ++ } ++ ++ if ((handle->rx_pkt_list = (PKT_LIST *) MALLOC(osh, sizeof(PKT_LIST))) == NULL) { ++ DHD_ERROR(("%s:%d: MALLOC failed for list allocation, size=%d\n", ++ __FUNCTION__, __LINE__, sizeof(PKT_LIST))); ++ goto error; ++ } ++ ++ if ((handle->ctrl_pkt_list = (PKT_LIST *) MALLOC(osh, sizeof(PKT_LIST))) == NULL) { ++ DHD_ERROR(("%s:%d: MALLOC failed for list allocation, size=%d\n", ++ __FUNCTION__, __LINE__, sizeof(PKT_LIST))); ++ goto error; ++ } ++ ++ PKTLIST_INIT(handle->tx_pkt_list); ++ PKTLIST_INIT(handle->rx_pkt_list); ++ PKTLIST_INIT(handle->ctrl_pkt_list); ++ ++ return (dhd_pktid_map_handle_t *) handle; ++ ++error: ++ if (handle->ctrl_pkt_list) { ++ MFREE(osh, handle->ctrl_pkt_list, sizeof(PKT_LIST)); ++ } ++ ++ if (handle->rx_pkt_list) { ++ MFREE(osh, handle->rx_pkt_list, sizeof(PKT_LIST)); ++ } ++ ++ if (handle->tx_pkt_list) { ++ MFREE(osh, handle->tx_pkt_list, sizeof(PKT_LIST)); ++ } ++ ++ if (handle) { ++ MFREE(osh, handle, sizeof(pktlists_t)); ++ } ++ ++error_done: ++ return (dhd_pktid_map_handle_t *)NULL; ++} ++ ++static void ++dhd_pktid_map_fini(dhd_pub_t *dhd, dhd_pktid_map_handle_t *map) ++{ ++ osl_t *osh = dhd->osh; ++ pktlists_t *handle = (pktlists_t *) map; ++ ++ ASSERT(handle != NULL); ++ if (handle == (pktlists_t *)NULL) ++ return; ++ ++ if (handle->ctrl_pkt_list) { ++ PKTLIST_FINI(handle->ctrl_pkt_list); ++ MFREE(osh, handle->ctrl_pkt_list, sizeof(PKT_LIST)); ++ } ++ ++ if (handle->rx_pkt_list) { ++ PKTLIST_FINI(handle->rx_pkt_list); ++ MFREE(osh, handle->rx_pkt_list, sizeof(PKT_LIST)); ++ } ++ ++ if (handle->tx_pkt_list) { ++ PKTLIST_FINI(handle->tx_pkt_list); ++ MFREE(osh, handle->tx_pkt_list, sizeof(PKT_LIST)); ++ } ++ ++ if (handle) { ++ MFREE(osh, handle, sizeof(pktlists_t)); ++ } ++} ++ ++/** Save dma parameters into the packet's pkttag and convert a pktptr to pktid */ ++static INLINE uint32 ++dhd_native_to_pktid(dhd_pktid_map_handle_t *map, void *pktptr32, ++ dmaaddr_t pa, uint32 dma_len, void *dmah, void *secdma, ++ dhd_pkttype_t pkttype) ++{ ++ pktlists_t *handle = (pktlists_t *) map; ++ ASSERT(pktptr32 != NULL); ++ DHD_PKT_SET_DMA_LEN(pktptr32, dma_len); ++ DHD_PKT_SET_DMAH(pktptr32, dmah); ++ DHD_PKT_SET_PA(pktptr32, pa); ++ DHD_PKT_SET_SECDMA(pktptr32, secdma); ++ ++ if (pkttype == PKTTYPE_DATA_TX) { ++ PKTLIST_ENQ(handle->tx_pkt_list, pktptr32); ++ } else if (pkttype == PKTTYPE_DATA_RX) { ++ PKTLIST_ENQ(handle->rx_pkt_list, pktptr32); ++ } else { ++ PKTLIST_ENQ(handle->ctrl_pkt_list, pktptr32); ++ } ++ ++ return DHD_PKTID32(pktptr32); ++} ++ ++/** Convert a pktid to pktptr and retrieve saved dma parameters from packet */ ++static INLINE void * ++dhd_pktid_to_native(dhd_pktid_map_handle_t *map, uint32 pktid32, ++ dmaaddr_t *pa, uint32 *dma_len, void **dmah, void **secdma, ++ dhd_pkttype_t pkttype) ++{ ++ pktlists_t *handle = (pktlists_t *) map; ++ void *pktptr32; ++ ++ ASSERT(pktid32 != 0U); ++ pktptr32 = DHD_PKTPTR32(pktid32); ++ *dma_len = DHD_PKT_GET_DMA_LEN(pktptr32); ++ *dmah = DHD_PKT_GET_DMAH(pktptr32); ++ *pa = DHD_PKT_GET_PA(pktptr32); ++ *secdma = DHD_PKT_GET_SECDMA(pktptr32); ++ ++ if (pkttype == PKTTYPE_DATA_TX) { ++ PKTLIST_UNLINK(handle->tx_pkt_list, pktptr32); ++ } else if (pkttype == PKTTYPE_DATA_RX) { ++ PKTLIST_UNLINK(handle->rx_pkt_list, pktptr32); ++ } else { ++ PKTLIST_UNLINK(handle->ctrl_pkt_list, pktptr32); ++ } ++ ++ return pktptr32; ++} ++ ++#define DHD_NATIVE_TO_PKTID_RSV(dhd, map, pkt, pkttype) DHD_PKTID32(pkt) ++ ++#define DHD_NATIVE_TO_PKTID_SAVE(dhd, map, pkt, nkey, pa, len, dma_dir, dmah, secdma, pkttype) \ ++ ({ BCM_REFERENCE(dhd); BCM_REFERENCE(nkey); BCM_REFERENCE(dma_dir); \ ++ dhd_native_to_pktid((dhd_pktid_map_handle_t *) map, (pkt), (pa), (len), \ ++ (dmah), (secdma), (dhd_pkttype_t)(pkttype)); \ ++ }) ++ ++#define DHD_NATIVE_TO_PKTID(dhd, map, pkt, pa, len, dma_dir, dmah, secdma, pkttype) \ ++ ({ BCM_REFERENCE(dhd); BCM_REFERENCE(dma_dir); \ ++ dhd_native_to_pktid((dhd_pktid_map_handle_t *) map, (pkt), (pa), (len), \ ++ (dmah), (secdma), (dhd_pkttype_t)(pkttype)); \ ++ }) ++ ++#define DHD_PKTID_TO_NATIVE(dhd, map, pktid, pa, len, dmah, secdma, pkttype) \ ++ ({ BCM_REFERENCE(dhd); BCM_REFERENCE(pkttype); \ ++ dhd_pktid_to_native((dhd_pktid_map_handle_t *) map, (uint32)(pktid), \ ++ (dmaaddr_t *)&(pa), (uint32 *)&(len), (void **)&(dmah), \ ++ (void **)&secdma, (dhd_pkttype_t)(pkttype)); \ ++ }) ++ ++#define DHD_PKTID_AVAIL(map) (~0) ++ ++#endif /* ! DHD_PCIE_PKTID */ ++ ++/* +------------------ End of PCIE DHD PKTID MAPPER -----------------------+ */ ++ ++ ++/** ++ * The PCIE FD protocol layer is constructed in two phases: ++ * Phase 1. dhd_prot_attach() ++ * Phase 2. dhd_prot_init() ++ * ++ * dhd_prot_attach() - Allocates a dhd_prot_t object and resets all its fields. ++ * All Common rings are allose attached (msgbuf_ring_t objects are allocated ++ * with DMA-able buffers). ++ * All dhd_dma_buf_t objects are also allocated here. ++ * ++ * As dhd_prot_attach is invoked prior to the pcie_shared object is read, any ++ * initialization of objects that requires information advertized by the dongle ++ * may not be performed here. ++ * E.g. the number of TxPost flowrings is not know at this point, neither do ++ * we know shich form of D2H DMA sync mechanism is advertized by the dongle, or ++ * whether the dongle supports DMA-ing of WR/RD indices for the H2D and/or D2H ++ * rings (common + flow). ++ * ++ * dhd_prot_init() is invoked after the bus layer has fetched the information ++ * advertized by the dongle in the pcie_shared_t. ++ */ ++int ++dhd_prot_attach(dhd_pub_t *dhd) ++{ ++ osl_t *osh = dhd->osh; ++ dhd_prot_t *prot; ++ ++ /* Allocate prot structure */ ++ if (!(prot = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, ++ sizeof(dhd_prot_t)))) { ++ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ memset(prot, 0, sizeof(*prot)); ++ ++ prot->osh = osh; ++ dhd->prot = prot; ++ ++ /* DMAing ring completes supported? FALSE by default */ ++ dhd->dma_d2h_ring_upd_support = FALSE; ++ dhd->dma_h2d_ring_upd_support = FALSE; ++ dhd->dma_ring_upd_overwrite = FALSE; ++ ++ dhd->idma_inited = 0; ++ dhd->ifrm_inited = 0; ++ ++ /* Common Ring Allocations */ ++ ++ /* Ring 0: H2D Control Submission */ ++ if (dhd_prot_ring_attach(dhd, &prot->h2dring_ctrl_subn, "h2dctrl", ++ H2DRING_CTRL_SUB_MAX_ITEM, H2DRING_CTRL_SUB_ITEMSIZE, ++ BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT) != BCME_OK) { ++ DHD_ERROR(("%s: dhd_prot_ring_attach H2D Ctrl Submission failed\n", ++ __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* Ring 1: H2D Receive Buffer Post */ ++ if (dhd_prot_ring_attach(dhd, &prot->h2dring_rxp_subn, "h2drxp", ++ H2DRING_RXPOST_MAX_ITEM, H2DRING_RXPOST_ITEMSIZE, ++ BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT) != BCME_OK) { ++ DHD_ERROR(("%s: dhd_prot_ring_attach H2D RxPost failed\n", ++ __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* Ring 2: D2H Control Completion */ ++ if (dhd_prot_ring_attach(dhd, &prot->d2hring_ctrl_cpln, "d2hctrl", ++ D2HRING_CTRL_CMPLT_MAX_ITEM, D2HRING_CTRL_CMPLT_ITEMSIZE, ++ BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE) != BCME_OK) { ++ DHD_ERROR(("%s: dhd_prot_ring_attach D2H Ctrl Completion failed\n", ++ __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* Ring 3: D2H Transmit Complete */ ++ if (dhd_prot_ring_attach(dhd, &prot->d2hring_tx_cpln, "d2htxcpl", ++ D2HRING_TXCMPLT_MAX_ITEM, D2HRING_TXCMPLT_ITEMSIZE, ++ BCMPCIE_D2H_MSGRING_TX_COMPLETE) != BCME_OK) { ++ DHD_ERROR(("%s: dhd_prot_ring_attach D2H Tx Completion failed\n", ++ __FUNCTION__)); ++ goto fail; ++ ++ } ++ ++ /* Ring 4: D2H Receive Complete */ ++ if (dhd_prot_ring_attach(dhd, &prot->d2hring_rx_cpln, "d2hrxcpl", ++ D2HRING_RXCMPLT_MAX_ITEM, D2HRING_RXCMPLT_ITEMSIZE, ++ BCMPCIE_D2H_MSGRING_RX_COMPLETE) != BCME_OK) { ++ DHD_ERROR(("%s: dhd_prot_ring_attach D2H Rx Completion failed\n", ++ __FUNCTION__)); ++ goto fail; ++ ++ } ++ ++ /* ++ * Max number of flowrings is not yet known. msgbuf_ring_t with DMA-able ++ * buffers for flowrings will be instantiated, in dhd_prot_init() . ++ * See dhd_prot_flowrings_pool_attach() ++ */ ++ /* ioctl response buffer */ ++ if (dhd_dma_buf_alloc(dhd, &prot->retbuf, IOCT_RETBUF_SIZE)) { ++ goto fail; ++ } ++ ++ /* IOCTL request buffer */ ++ if (dhd_dma_buf_alloc(dhd, &prot->ioctbuf, IOCT_RETBUF_SIZE)) { ++ goto fail; ++ } ++ ++ /* Host TS request buffer one buffer for now */ ++ if (dhd_dma_buf_alloc(dhd, &prot->hostts_req_buf, CTRLSUB_HOSTTS_MEESAGE_SIZE)) { ++ goto fail; ++ } ++ prot->hostts_req_buf_inuse = FALSE; ++ ++ /* Scratch buffer for dma rx offset */ ++#ifdef BCM_HOST_BUF ++ if (dhd_dma_buf_alloc(dhd, &prot->d2h_dma_scratch_buf, ++ ROUNDUP(DMA_D2H_SCRATCH_BUF_LEN, 16) + DMA_HOST_BUFFER_LEN)) ++#else ++ if (dhd_dma_buf_alloc(dhd, &prot->d2h_dma_scratch_buf, DMA_D2H_SCRATCH_BUF_LEN)) ++#endif /* BCM_HOST_BUF */ ++ { ++ goto fail; ++ } ++ ++ /* scratch buffer bus throughput measurement */ ++ if (dhd_dma_buf_alloc(dhd, &prot->host_bus_throughput_buf, DHD_BUS_TPUT_BUF_LEN)) { ++ goto fail; ++ } ++ ++#ifdef DHD_RX_CHAINING ++ dhd_rxchain_reset(&prot->rxchain); ++#endif ++ ++ prot->rx_lock = dhd_os_spin_lock_init(dhd->osh); ++ ++ prot->pktid_ctrl_map = DHD_NATIVE_TO_PKTID_INIT(dhd, MAX_CTRL_PKTID); ++ if (prot->pktid_ctrl_map == NULL) { ++ goto fail; ++ } ++ ++ prot->pktid_rx_map = DHD_NATIVE_TO_PKTID_INIT(dhd, MAX_RX_PKTID); ++ if (prot->pktid_rx_map == NULL) ++ goto fail; ++ ++ prot->pktid_tx_map = DHD_NATIVE_TO_PKTID_INIT(dhd, MAX_TX_PKTID); ++ if (prot->pktid_rx_map == NULL) ++ goto fail; ++ ++#ifdef IOCTLRESP_USE_CONSTMEM ++ prot->pktid_map_handle_ioctl = DHD_NATIVE_TO_PKTID_INIT(dhd, ++ DHD_FLOWRING_MAX_IOCTLRESPBUF_POST); ++ if (prot->pktid_map_handle_ioctl == NULL) { ++ goto fail; ++ } ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ ++ /* Initialize the work queues to be used by the Load Balancing logic */ ++#if defined(DHD_LB_TXC) ++ { ++ void *buffer; ++ buffer = MALLOC(dhd->osh, sizeof(void*) * DHD_LB_WORKQ_SZ); ++ bcm_workq_init(&prot->tx_compl_prod, &prot->tx_compl_cons, ++ buffer, DHD_LB_WORKQ_SZ); ++ prot->tx_compl_prod_sync = 0; ++ DHD_INFO(("%s: created tx_compl_workq <%p,%d>\n", ++ __FUNCTION__, buffer, DHD_LB_WORKQ_SZ)); ++ } ++#endif /* DHD_LB_TXC */ ++ ++#if defined(DHD_LB_RXC) ++ { ++ void *buffer; ++ buffer = MALLOC(dhd->osh, sizeof(void*) * DHD_LB_WORKQ_SZ); ++ bcm_workq_init(&prot->rx_compl_prod, &prot->rx_compl_cons, ++ buffer, DHD_LB_WORKQ_SZ); ++ prot->rx_compl_prod_sync = 0; ++ DHD_INFO(("%s: created rx_compl_workq <%p,%d>\n", ++ __FUNCTION__, buffer, DHD_LB_WORKQ_SZ)); ++ } ++#endif /* DHD_LB_RXC */ ++ /* Initialize trap buffer */ ++ if (dhd_dma_buf_alloc(dhd, &dhd->prot->fw_trap_buf, BCMPCIE_EXT_TRAP_DATA_MAXLEN)) { ++ DHD_ERROR(("%s: dhd_init_trap_buffer falied\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ return BCME_OK; ++ ++fail: ++ ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ if (prot != NULL) { ++ dhd_prot_detach(dhd); ++ } ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++ return BCME_NOMEM; ++} /* dhd_prot_attach */ ++ ++void ++dhd_set_host_cap(dhd_pub_t *dhd) ++{ ++ uint32 data = 0; ++ dhd_prot_t *prot = dhd->prot; ++ ++ if (dhd->bus->api.fw_rev >= PCIE_SHARED_VERSION_6) { ++ if (dhd->h2d_phase_supported) { ++ ++ data |= HOSTCAP_H2D_VALID_PHASE; ++ ++ if (dhd->force_dongletrap_on_bad_h2d_phase) { ++ data |= HOSTCAP_H2D_ENABLE_TRAP_ON_BADPHASE; ++ } ++ } ++ if (prot->host_ipc_version > prot->device_ipc_version) { ++ prot->active_ipc_version = prot->device_ipc_version; ++ } else { ++ prot->active_ipc_version = prot->host_ipc_version; ++ } ++ ++ data |= prot->active_ipc_version; ++ ++ if (dhdpcie_bus_get_pcie_hostready_supported(dhd->bus)) { ++ ++ DHD_INFO(("Advertise Hostready Capability\n")); ++ ++ data |= HOSTCAP_H2D_ENABLE_HOSTRDY; ++ } ++#ifdef PCIE_INB_DW ++ if (dhdpcie_bus_get_pcie_inband_dw_supported(dhd->bus)) { ++ DHD_INFO(("Advertise Inband-DW Capability\n")); ++ data |= HOSTCAP_DS_INBAND_DW; ++ data |= HOSTCAP_DS_NO_OOB_DW; ++ dhdpcie_bus_enab_pcie_dw(dhd->bus, DEVICE_WAKE_INB); ++ } else ++#endif /* PCIE_INB_DW */ ++#ifdef PCIE_OOB ++ if (dhdpcie_bus_get_pcie_oob_dw_supported(dhd->bus)) { ++ dhdpcie_bus_enab_pcie_dw(dhd->bus, DEVICE_WAKE_OOB); ++ } else ++#endif /* PCIE_OOB */ ++ { ++ /* Disable DS altogether */ ++ data |= HOSTCAP_DS_NO_OOB_DW; ++ dhdpcie_bus_enab_pcie_dw(dhd->bus, DEVICE_WAKE_NONE); ++ } ++ ++ if (dhdpcie_bus_get_pcie_idma_supported(dhd->bus)) { ++ ++ DHD_ERROR(("IDMA inited\n")); ++ data |= HOSTCAP_H2D_IDMA; ++ dhd->idma_inited = TRUE; ++ } ++ ++ if (dhdpcie_bus_get_pcie_ifrm_supported(dhd->bus)) { ++ DHD_ERROR(("IFRM Inited\n")); ++ data |= HOSTCAP_H2D_IFRM; ++ dhd->ifrm_inited = TRUE; ++ dhd->dma_h2d_ring_upd_support = FALSE; ++ dhd_prot_dma_indx_free(dhd); ++ } ++ ++ /* Indicate support for TX status metadata */ ++ data |= HOSTCAP_TXSTATUS_METADATA; ++ ++ /* Indicate support for extended trap data */ ++ data |= HOSTCAP_EXTENDED_TRAP_DATA; ++ ++ DHD_INFO(("%s:Active Ver:%d, Host Ver:%d, FW Ver:%d\n", ++ __FUNCTION__, ++ prot->active_ipc_version, prot->host_ipc_version, ++ prot->device_ipc_version)); ++ ++ dhd_bus_cmn_writeshared(dhd->bus, &data, sizeof(uint32), HOST_API_VERSION, 0); ++ dhd_bus_cmn_writeshared(dhd->bus, &prot->fw_trap_buf.pa, ++ sizeof(prot->fw_trap_buf.pa), DNGL_TO_HOST_TRAP_ADDR, 0); ++ } ++#ifdef HOFFLOAD_MODULES ++ dhd_bus_cmn_writeshared(dhd->bus, &dhd->hmem.data_addr, ++ sizeof(dhd->hmem.data_addr), WRT_HOST_MODULE_ADDR, 0); ++#endif ++ ++#ifdef DHD_TIMESYNC ++ dhd_timesync_notify_ipc_rev(dhd->ts, prot->active_ipc_version); ++#endif /* DHD_TIMESYNC */ ++} ++ ++/** ++ * dhd_prot_init - second stage of dhd_prot_attach. Now that the dongle has ++ * completed it's initialization of the pcie_shared structure, we may now fetch ++ * the dongle advertized features and adjust the protocol layer accordingly. ++ * ++ * dhd_prot_init() may be invoked again after a dhd_prot_reset(). ++ */ ++int ++dhd_prot_init(dhd_pub_t *dhd) ++{ ++ sh_addr_t base_addr; ++ dhd_prot_t *prot = dhd->prot; ++ int ret = 0; ++ ++ /** ++ * A user defined value can be assigned to global variable h2d_max_txpost via ++ * 1. DHD IOVAR h2d_max_txpost, before firmware download ++ * 2. module parameter h2d_max_txpost ++ * prot->h2d_max_txpost is assigned with H2DRING_TXPOST_MAX_ITEM, ++ * if user has not defined any buffers by one of the above methods. ++ */ ++ prot->h2d_max_txpost = (uint16)h2d_max_txpost; ++ ++ DHD_ERROR(("%s:%d: h2d_max_txpost = %d\n", __FUNCTION__, __LINE__, prot->h2d_max_txpost)); ++ ++ /* Read max rx packets supported by dongle */ ++ dhd_bus_cmn_readshared(dhd->bus, &prot->max_rxbufpost, MAX_HOST_RXBUFS, 0); ++ if (prot->max_rxbufpost == 0) { ++ /* This would happen if the dongle firmware is not */ ++ /* using the latest shared structure template */ ++ prot->max_rxbufpost = DEFAULT_RX_BUFFERS_TO_POST; ++ } ++ DHD_INFO(("%s:%d: MAX_RXBUFPOST = %d\n", __FUNCTION__, __LINE__, prot->max_rxbufpost)); ++ ++ /* Initialize. bzero() would blow away the dma pointers. */ ++ prot->max_eventbufpost = DHD_FLOWRING_MAX_EVENTBUF_POST; ++ prot->max_ioctlrespbufpost = DHD_FLOWRING_MAX_IOCTLRESPBUF_POST; ++ prot->max_infobufpost = DHD_H2D_INFORING_MAX_BUF_POST; ++ prot->max_tsbufpost = DHD_MAX_TSBUF_POST; ++ ++ prot->cur_ioctlresp_bufs_posted = 0; ++ prot->active_tx_count = 0; ++ prot->data_seq_no = 0; ++ prot->ioctl_seq_no = 0; ++ prot->rxbufpost = 0; ++ prot->cur_event_bufs_posted = 0; ++ prot->ioctl_state = 0; ++ prot->curr_ioctl_cmd = 0; ++ prot->cur_ts_bufs_posted = 0; ++ prot->infobufpost = 0; ++ ++ prot->dmaxfer.srcmem.va = NULL; ++ prot->dmaxfer.dstmem.va = NULL; ++ prot->dmaxfer.in_progress = FALSE; ++ ++ prot->metadata_dbg = FALSE; ++ prot->rx_metadata_offset = 0; ++ prot->tx_metadata_offset = 0; ++ prot->txp_threshold = TXP_FLUSH_MAX_ITEMS_FLUSH_CNT; ++ ++ /* To catch any rollover issues fast, starting with higher ioctl_trans_id */ ++ prot->ioctl_trans_id = MAXBITVAL(NBITS(prot->ioctl_trans_id)) - BUFFER_BEFORE_ROLLOVER; ++ prot->ioctl_state = 0; ++ prot->ioctl_status = 0; ++ prot->ioctl_resplen = 0; ++ prot->ioctl_received = IOCTL_WAIT; ++ ++ /* Register the interrupt function upfront */ ++ /* remove corerev checks in data path */ ++ prot->mb_ring_fn = dhd_bus_get_mbintr_fn(dhd->bus); ++ ++ prot->mb_2_ring_fn = dhd_bus_get_mbintr_2_fn(dhd->bus); ++ ++ /* Initialize Common MsgBuf Rings */ ++ ++ prot->device_ipc_version = dhd->bus->api.fw_rev; ++ prot->host_ipc_version = PCIE_SHARED_VERSION; ++ ++ /* Init the host API version */ ++ dhd_set_host_cap(dhd); ++ ++ dhd_prot_ring_init(dhd, &prot->h2dring_ctrl_subn); ++ dhd_prot_ring_init(dhd, &prot->h2dring_rxp_subn); ++ dhd_prot_ring_init(dhd, &prot->d2hring_ctrl_cpln); ++ ++ /* Make it compatibile with pre-rev7 Firmware */ ++ if (prot->active_ipc_version < PCIE_SHARED_VERSION_7) { ++ prot->d2hring_tx_cpln.item_len = ++ D2HRING_TXCMPLT_ITEMSIZE_PREREV7; ++ prot->d2hring_rx_cpln.item_len = ++ D2HRING_RXCMPLT_ITEMSIZE_PREREV7; ++ } ++ dhd_prot_ring_init(dhd, &prot->d2hring_tx_cpln); ++ dhd_prot_ring_init(dhd, &prot->d2hring_rx_cpln); ++ ++ dhd_prot_d2h_sync_init(dhd); ++ ++ dhd_prot_h2d_sync_init(dhd); ++ ++#ifdef PCIE_INB_DW ++ /* Set the initial DS state */ ++ if (INBAND_DW_ENAB(dhd->bus)) { ++ dhdpcie_bus_set_pcie_inband_dw_state(dhd->bus, ++ DW_DEVICE_DS_ACTIVE); ++ } ++#endif /* PCIE_INB_DW */ ++ ++ /* init the scratch buffer */ ++ dhd_base_addr_htolpa(&base_addr, prot->d2h_dma_scratch_buf.pa); ++ dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), ++ D2H_DMA_SCRATCH_BUF, 0); ++ dhd_bus_cmn_writeshared(dhd->bus, &prot->d2h_dma_scratch_buf.len, ++ sizeof(prot->d2h_dma_scratch_buf.len), D2H_DMA_SCRATCH_BUF_LEN, 0); ++ ++ /* If supported by the host, indicate the memory block ++ * for completion writes / submission reads to shared space ++ */ ++ if (dhd->dma_d2h_ring_upd_support) { ++ dhd_base_addr_htolpa(&base_addr, prot->d2h_dma_indx_wr_buf.pa); ++ dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), ++ D2H_DMA_INDX_WR_BUF, 0); ++ dhd_base_addr_htolpa(&base_addr, prot->h2d_dma_indx_rd_buf.pa); ++ dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), ++ H2D_DMA_INDX_RD_BUF, 0); ++ } ++ ++ if (dhd->dma_h2d_ring_upd_support || IDMA_ENAB(dhd)) { ++ dhd_base_addr_htolpa(&base_addr, prot->h2d_dma_indx_wr_buf.pa); ++ dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), ++ H2D_DMA_INDX_WR_BUF, 0); ++ dhd_base_addr_htolpa(&base_addr, prot->d2h_dma_indx_rd_buf.pa); ++ dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), ++ D2H_DMA_INDX_RD_BUF, 0); ++ ++ } ++ ++ /* Signal to the dongle that common ring init is complete */ ++ dhd_bus_hostready(dhd->bus); ++ ++ /* ++ * If the DMA-able buffers for flowring needs to come from a specific ++ * contiguous memory region, then setup prot->flowrings_dma_buf here. ++ * dhd_prot_flowrings_pool_attach() will carve out DMA-able buffers from ++ * this contiguous memory region, for each of the flowrings. ++ */ ++ ++ /* Pre-allocate pool of msgbuf_ring for flowrings */ ++ if (dhd_prot_flowrings_pool_attach(dhd) != BCME_OK) { ++ return BCME_ERROR; ++ } ++ ++ /* If IFRM is enabled, wait for FW to setup the DMA channel */ ++ if (IFRM_ENAB(dhd)) { ++ dhd_base_addr_htolpa(&base_addr, prot->h2d_ifrm_indx_wr_buf.pa); ++ dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), ++ H2D_IFRM_INDX_WR_BUF, 0); ++ } ++ ++ /* See if info rings could be created */ ++ if (dhd->bus->api.fw_rev >= PCIE_SHARED_VERSION_6) { ++ if ((ret = dhd_prot_init_info_rings(dhd)) != BCME_OK) { ++ /* For now log and proceed, further clean up action maybe necessary ++ * when we have more clarity. ++ */ ++ DHD_ERROR(("%s Info rings couldn't be created: Err Code%d", ++ __FUNCTION__, ret)); ++ } ++ } ++ ++ /* Host should configure soft doorbells if needed ... here */ ++ ++ /* Post to dongle host configured soft doorbells */ ++ dhd_msgbuf_ring_config_d2h_soft_doorbell(dhd); ++ ++ /* Post buffers for packet reception and ioctl/event responses */ ++ dhd_msgbuf_rxbuf_post(dhd, FALSE); /* alloc pkt ids */ ++ dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd); ++ /* Fix re-entry problem without general lock */ ++ atomic_set(&dhd_msgbuf_rxbuf_post_event_bufs_running, 0); ++ dhd_msgbuf_rxbuf_post_event_bufs(dhd); ++ ++ return BCME_OK; ++} /* dhd_prot_init */ ++ ++ ++/** ++ * dhd_prot_detach - PCIE FD protocol layer destructor. ++ * Unlink, frees allocated protocol memory (including dhd_prot) ++ */ ++void dhd_prot_detach(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ ++ /* Stop the protocol module */ ++ if (prot) { ++ ++ /* free up all DMA-able buffers allocated during prot attach/init */ ++ ++ dhd_dma_buf_free(dhd, &prot->d2h_dma_scratch_buf); ++ dhd_dma_buf_free(dhd, &prot->retbuf); ++ dhd_dma_buf_free(dhd, &prot->ioctbuf); ++ dhd_dma_buf_free(dhd, &prot->host_bus_throughput_buf); ++ dhd_dma_buf_free(dhd, &prot->hostts_req_buf); ++ dhd_dma_buf_free(dhd, &prot->fw_trap_buf); ++ ++ /* DMA-able buffers for DMAing H2D/D2H WR/RD indices */ ++ dhd_dma_buf_free(dhd, &prot->h2d_dma_indx_wr_buf); ++ dhd_dma_buf_free(dhd, &prot->h2d_dma_indx_rd_buf); ++ dhd_dma_buf_free(dhd, &prot->d2h_dma_indx_wr_buf); ++ dhd_dma_buf_free(dhd, &prot->d2h_dma_indx_rd_buf); ++ ++ dhd_dma_buf_free(dhd, &prot->h2d_ifrm_indx_wr_buf); ++ ++ /* Common MsgBuf Rings */ ++ dhd_prot_ring_detach(dhd, &prot->h2dring_ctrl_subn); ++ dhd_prot_ring_detach(dhd, &prot->h2dring_rxp_subn); ++ dhd_prot_ring_detach(dhd, &prot->d2hring_ctrl_cpln); ++ dhd_prot_ring_detach(dhd, &prot->d2hring_tx_cpln); ++ dhd_prot_ring_detach(dhd, &prot->d2hring_rx_cpln); ++ ++ /* Detach each DMA-able buffer and free the pool of msgbuf_ring_t */ ++ dhd_prot_flowrings_pool_detach(dhd); ++ ++ /* detach info rings */ ++ dhd_prot_detach_info_rings(dhd); ++ ++ /* if IOCTLRESP_USE_CONSTMEM is defined IOCTL PKTs use pktid_map_handle_ioctl ++ * handler and PKT memory is allocated using alloc_ioctl_return_buffer(), Otherwise ++ * they will be part of pktid_ctrl_map handler and PKT memory is allocated using ++ * PKTGET_STATIC (if DHD_USE_STATIC_CTRLBUF is defined) OR PKGET. ++ * Similarly for freeing PKT buffers DHD_NATIVE_TO_PKTID_FINI will be used ++ * which calls PKTFREE_STATIC (if DHD_USE_STATIC_CTRLBUF is defined) OR PKFREE. ++ * Else if IOCTLRESP_USE_CONSTMEM is defined IOCTL PKTs will be freed using ++ * DHD_NATIVE_TO_PKTID_FINI_IOCTL which calls free_ioctl_return_buffer. ++ */ ++ DHD_NATIVE_TO_PKTID_FINI(dhd, prot->pktid_ctrl_map); ++ DHD_NATIVE_TO_PKTID_FINI(dhd, prot->pktid_rx_map); ++ DHD_NATIVE_TO_PKTID_FINI(dhd, prot->pktid_tx_map); ++#ifdef IOCTLRESP_USE_CONSTMEM ++ DHD_NATIVE_TO_PKTID_FINI_IOCTL(dhd, prot->pktid_map_handle_ioctl); ++#endif ++ ++ dhd_os_spin_lock_deinit(dhd->osh, prot->rx_lock); ++ ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++#if defined(DHD_LB_TXC) ++ if (prot->tx_compl_prod.buffer) ++ MFREE(dhd->osh, prot->tx_compl_prod.buffer, ++ sizeof(void*) * DHD_LB_WORKQ_SZ); ++#endif /* DHD_LB_TXC */ ++#if defined(DHD_LB_RXC) ++ if (prot->rx_compl_prod.buffer) ++ MFREE(dhd->osh, prot->rx_compl_prod.buffer, ++ sizeof(void*) * DHD_LB_WORKQ_SZ); ++#endif /* DHD_LB_RXC */ ++ ++ dhd->prot = NULL; ++ } ++} /* dhd_prot_detach */ ++ ++ ++/** ++ * dhd_prot_reset - Reset the protocol layer without freeing any objects. ++ * This may be invoked to soft reboot the dongle, without having to ++ * detach and attach the entire protocol layer. ++ * ++ * After dhd_prot_reset(), dhd_prot_init() may be invoked ++ * without going througha dhd_prot_attach() phase. ++ */ ++void ++dhd_prot_reset(dhd_pub_t *dhd) ++{ ++ struct dhd_prot *prot = dhd->prot; ++ ++ DHD_TRACE(("%s\n", __FUNCTION__)); ++ ++ if (prot == NULL) { ++ return; ++ } ++ ++ dhd_prot_flowrings_pool_reset(dhd); ++ ++ /* Reset Common MsgBuf Rings */ ++ dhd_prot_ring_reset(dhd, &prot->h2dring_ctrl_subn); ++ dhd_prot_ring_reset(dhd, &prot->h2dring_rxp_subn); ++ dhd_prot_ring_reset(dhd, &prot->d2hring_ctrl_cpln); ++ dhd_prot_ring_reset(dhd, &prot->d2hring_tx_cpln); ++ dhd_prot_ring_reset(dhd, &prot->d2hring_rx_cpln); ++ ++ /* Reset info rings */ ++ if (prot->h2dring_info_subn) { ++ dhd_prot_ring_reset(dhd, prot->h2dring_info_subn); ++ } ++ ++ if (prot->d2hring_info_cpln) { ++ dhd_prot_ring_reset(dhd, prot->d2hring_info_cpln); ++ } ++ ++ /* Reset all DMA-able buffers allocated during prot attach */ ++ dhd_dma_buf_reset(dhd, &prot->d2h_dma_scratch_buf); ++ dhd_dma_buf_reset(dhd, &prot->retbuf); ++ dhd_dma_buf_reset(dhd, &prot->ioctbuf); ++ dhd_dma_buf_reset(dhd, &prot->host_bus_throughput_buf); ++ dhd_dma_buf_reset(dhd, &prot->hostts_req_buf); ++ dhd_dma_buf_reset(dhd, &prot->fw_trap_buf); ++ ++ dhd_dma_buf_reset(dhd, &prot->h2d_ifrm_indx_wr_buf); ++ ++ /* Reset all DMA-able buffers for DMAing H2D/D2H WR/RD indices */ ++ dhd_dma_buf_reset(dhd, &prot->h2d_dma_indx_rd_buf); ++ dhd_dma_buf_reset(dhd, &prot->h2d_dma_indx_wr_buf); ++ dhd_dma_buf_reset(dhd, &prot->d2h_dma_indx_rd_buf); ++ dhd_dma_buf_reset(dhd, &prot->d2h_dma_indx_wr_buf); ++ ++ ++ prot->rx_metadata_offset = 0; ++ prot->tx_metadata_offset = 0; ++ ++ prot->rxbufpost = 0; ++ prot->cur_event_bufs_posted = 0; ++ prot->cur_ioctlresp_bufs_posted = 0; ++ ++ prot->active_tx_count = 0; ++ prot->data_seq_no = 0; ++ prot->ioctl_seq_no = 0; ++ prot->ioctl_state = 0; ++ prot->curr_ioctl_cmd = 0; ++ prot->ioctl_received = IOCTL_WAIT; ++ /* To catch any rollover issues fast, starting with higher ioctl_trans_id */ ++ prot->ioctl_trans_id = MAXBITVAL(NBITS(prot->ioctl_trans_id)) - BUFFER_BEFORE_ROLLOVER; ++ ++ /* dhd_flow_rings_init is located at dhd_bus_start, ++ * so when stopping bus, flowrings shall be deleted ++ */ ++ if (dhd->flow_rings_inited) { ++ dhd_flow_rings_deinit(dhd); ++ } ++ ++ /* Reset PKTID map */ ++ DHD_NATIVE_TO_PKTID_RESET(dhd, prot->pktid_ctrl_map); ++ DHD_NATIVE_TO_PKTID_RESET(dhd, prot->pktid_rx_map); ++ DHD_NATIVE_TO_PKTID_RESET(dhd, prot->pktid_tx_map); ++#ifdef IOCTLRESP_USE_CONSTMEM ++ DHD_NATIVE_TO_PKTID_RESET_IOCTL(dhd, prot->pktid_map_handle_ioctl); ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++#ifdef DMAMAP_STATS ++ dhd->dma_stats.txdata = dhd->dma_stats.txdata_sz = 0; ++ dhd->dma_stats.rxdata = dhd->dma_stats.rxdata_sz = 0; ++#ifndef IOCTLRESP_USE_CONSTMEM ++ dhd->dma_stats.ioctl_rx = dhd->dma_stats.ioctl_rx_sz = 0; ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ dhd->dma_stats.event_rx = dhd->dma_stats.event_rx_sz = 0; ++ dhd->dma_stats.info_rx = dhd->dma_stats.info_rx_sz = 0; ++ dhd->dma_stats.tsbuf_rx = dhd->dma_stats.tsbuf_rx_sz = 0; ++#endif /* DMAMAP_STATS */ ++} /* dhd_prot_reset */ ++ ++#if defined(DHD_LB_RXP) ++#define DHD_LB_DISPATCH_RX_PROCESS(dhdp) dhd_lb_dispatch_rx_process(dhdp) ++#else /* !DHD_LB_RXP */ ++#define DHD_LB_DISPATCH_RX_PROCESS(dhdp) do { /* noop */ } while (0) ++#endif /* !DHD_LB_RXP */ ++ ++#if defined(DHD_LB_RXC) ++#define DHD_LB_DISPATCH_RX_COMPL(dhdp) dhd_lb_dispatch_rx_compl(dhdp) ++#else /* !DHD_LB_RXC */ ++#define DHD_LB_DISPATCH_RX_COMPL(dhdp) do { /* noop */ } while (0) ++#endif /* !DHD_LB_RXC */ ++ ++#if defined(DHD_LB_TXC) ++#define DHD_LB_DISPATCH_TX_COMPL(dhdp) dhd_lb_dispatch_tx_compl(dhdp) ++#else /* !DHD_LB_TXC */ ++#define DHD_LB_DISPATCH_TX_COMPL(dhdp) do { /* noop */ } while (0) ++#endif /* !DHD_LB_TXC */ ++ ++ ++#if defined(DHD_LB) ++/* DHD load balancing: deferral of work to another online CPU */ ++/* DHD_LB_TXC DHD_LB_RXC DHD_LB_RXP dispatchers, in dhd_linux.c */ ++extern void dhd_lb_tx_compl_dispatch(dhd_pub_t *dhdp); ++extern void dhd_lb_rx_compl_dispatch(dhd_pub_t *dhdp); ++extern void dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp); ++extern void dhd_lb_rx_pkt_enqueue(dhd_pub_t *dhdp, void *pkt, int ifidx); ++ ++#if defined(DHD_LB_RXP) ++/** ++ * dhd_lb_dispatch_rx_process - load balance by dispatch Rx processing work ++ * to other CPU cores ++ */ ++static INLINE void ++dhd_lb_dispatch_rx_process(dhd_pub_t *dhdp) ++{ ++ dhd_lb_rx_napi_dispatch(dhdp); /* dispatch rx_process_napi */ ++} ++#endif /* DHD_LB_RXP */ ++ ++#if defined(DHD_LB_TXC) ++/** ++ * dhd_lb_dispatch_tx_compl - load balance by dispatch Tx complition work ++ * to other CPU cores ++ */ ++static INLINE void ++dhd_lb_dispatch_tx_compl(dhd_pub_t *dhdp, uint16 ring_idx) ++{ ++ bcm_workq_prod_sync(&dhdp->prot->tx_compl_prod); /* flush WR index */ ++ dhd_lb_tx_compl_dispatch(dhdp); /* dispatch tx_compl_tasklet */ ++} ++ ++/** ++ * DHD load balanced tx completion tasklet handler, that will perform the ++ * freeing of packets on the selected CPU. Packet pointers are delivered to ++ * this tasklet via the tx complete workq. ++ */ ++void ++dhd_lb_tx_compl_handler(unsigned long data) ++{ ++ int elem_ix; ++ void *pkt, **elem; ++ dmaaddr_t pa; ++ uint32 pa_len; ++ dhd_pub_t *dhd = (dhd_pub_t *)data; ++ dhd_prot_t *prot = dhd->prot; ++ bcm_workq_t *workq = &prot->tx_compl_cons; ++ uint32 count = 0; ++ ++ int curr_cpu; ++ curr_cpu = get_cpu(); ++ put_cpu(); ++ ++ DHD_LB_STATS_TXC_PERCPU_CNT_INCR(dhd); ++ ++ while (1) { ++ elem_ix = bcm_ring_cons(WORKQ_RING(workq), DHD_LB_WORKQ_SZ); ++ ++ if (elem_ix == BCM_RING_EMPTY) { ++ break; ++ } ++ ++ elem = WORKQ_ELEMENT(void *, workq, elem_ix); ++ pkt = *elem; ++ ++ DHD_INFO(("%s: tx_compl_cons pkt<%p>\n", __FUNCTION__, pkt)); ++ ++ OSL_PREFETCH(PKTTAG(pkt)); ++ OSL_PREFETCH(pkt); ++ ++ pa = DHD_PKTTAG_PA((dhd_pkttag_fr_t *)PKTTAG(pkt)); ++ pa_len = DHD_PKTTAG_PA_LEN((dhd_pkttag_fr_t *)PKTTAG(pkt)); ++ ++ DMA_UNMAP(dhd->osh, pa, pa_len, DMA_RX, 0, 0); ++#if defined(BCMPCIE) ++ dhd_txcomplete(dhd, pkt, true); ++#endif ++ ++ PKTFREE(dhd->osh, pkt, TRUE); ++ count++; ++ } ++ ++ /* smp_wmb(); */ ++ bcm_workq_cons_sync(workq); ++ DHD_LB_STATS_UPDATE_TXC_HISTO(dhd, count); ++} ++#endif /* DHD_LB_TXC */ ++ ++#if defined(DHD_LB_RXC) ++ ++/** ++ * dhd_lb_dispatch_rx_compl - load balance by dispatch rx complition work ++ * to other CPU cores ++ */ ++static INLINE void ++dhd_lb_dispatch_rx_compl(dhd_pub_t *dhdp) ++{ ++ dhd_prot_t *prot = dhdp->prot; ++ /* Schedule the takslet only if we have to */ ++ if (prot->rxbufpost <= (prot->max_rxbufpost - RXBUFPOST_THRESHOLD)) { ++ /* flush WR index */ ++ bcm_workq_prod_sync(&dhdp->prot->rx_compl_prod); ++ dhd_lb_rx_compl_dispatch(dhdp); /* dispatch rx_compl_tasklet */ ++ } ++} ++ ++void ++dhd_lb_rx_compl_handler(unsigned long data) ++{ ++ dhd_pub_t *dhd = (dhd_pub_t *)data; ++ bcm_workq_t *workq = &dhd->prot->rx_compl_cons; ++ ++ DHD_LB_STATS_RXC_PERCPU_CNT_INCR(dhd); ++ ++ dhd_msgbuf_rxbuf_post(dhd, TRUE); /* re-use pktids */ ++ bcm_workq_cons_sync(workq); ++} ++#endif /* DHD_LB_RXC */ ++#endif /* DHD_LB */ ++ ++void ++dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 rx_offset) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ prot->rx_dataoffset = rx_offset; ++} ++ ++static int ++dhd_check_create_info_rings(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ int ret = BCME_ERROR; ++ uint16 ringid = dhd->bus->max_tx_flowrings + BCMPCIE_COMMON_MSGRINGS; ++ ++ if (prot->h2dring_info_subn && prot->d2hring_info_cpln) { ++ return BCME_OK; /* dhd_prot_init rentry after a dhd_prot_reset */ ++ } ++ ++ if (prot->h2dring_info_subn == NULL) { ++ prot->h2dring_info_subn = MALLOCZ(prot->osh, sizeof(msgbuf_ring_t)); ++ ++ if (prot->h2dring_info_subn == NULL) { ++ DHD_ERROR(("%s: couldn't alloc memory for h2dring_info_subn\n", ++ __FUNCTION__)); ++ return BCME_NOMEM; ++ } ++ ++ DHD_INFO(("%s: about to create debug submit ring\n", __FUNCTION__)); ++ ret = dhd_prot_ring_attach(dhd, prot->h2dring_info_subn, "h2dinfo", ++ H2DRING_DYNAMIC_INFO_MAX_ITEM, H2DRING_INFO_BUFPOST_ITEMSIZE, ++ ringid); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s: couldn't alloc resources for dbg submit ring\n", ++ __FUNCTION__)); ++ goto err; ++ } ++ } ++ ++ if (prot->d2hring_info_cpln == NULL) { ++ prot->d2hring_info_cpln = MALLOCZ(prot->osh, sizeof(msgbuf_ring_t)); ++ ++ if (prot->d2hring_info_cpln == NULL) { ++ DHD_ERROR(("%s: couldn't alloc memory for h2dring_info_subn\n", ++ __FUNCTION__)); ++ return BCME_NOMEM; ++ } ++ ++ /* create the debug info completion ring next to debug info submit ring ++ * ringid = id next to debug info submit ring ++ */ ++ ringid = ringid + 1; ++ ++ DHD_INFO(("%s: about to create debug cpl ring\n", __FUNCTION__)); ++ ret = dhd_prot_ring_attach(dhd, prot->d2hring_info_cpln, "d2hinfo", ++ D2HRING_DYNAMIC_INFO_MAX_ITEM, D2HRING_INFO_BUFCMPLT_ITEMSIZE, ++ ringid); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s: couldn't alloc resources for dbg cpl ring\n", ++ __FUNCTION__)); ++ dhd_prot_ring_detach(dhd, prot->h2dring_info_subn); ++ goto err; ++ } ++ } ++ ++ return ret; ++err: ++ MFREE(prot->osh, prot->h2dring_info_subn, sizeof(msgbuf_ring_t)); ++ prot->h2dring_info_subn = NULL; ++ ++ if (prot->d2hring_info_cpln) { ++ MFREE(prot->osh, prot->d2hring_info_cpln, sizeof(msgbuf_ring_t)); ++ prot->d2hring_info_cpln = NULL; ++ } ++ return ret; ++} /* dhd_check_create_info_rings */ ++ ++int ++dhd_prot_init_info_rings(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ int ret = BCME_OK; ++ ++ if ((ret = dhd_check_create_info_rings(dhd)) != BCME_OK) { ++ DHD_ERROR(("%s: info rings aren't created! \n", ++ __FUNCTION__)); ++ return ret; ++ } ++ ++ if ((prot->d2hring_info_cpln->inited) || (prot->d2hring_info_cpln->create_pending)) { ++ DHD_INFO(("Info completion ring was created!\n")); ++ return ret; ++ } ++ ++ DHD_TRACE(("trying to send create d2h info ring: id %d\n", prot->d2hring_info_cpln->idx)); ++ ret = dhd_send_d2h_ringcreate(dhd, prot->d2hring_info_cpln); ++ if (ret != BCME_OK) ++ return ret; ++ ++ prot->d2hring_info_cpln->seqnum = D2H_EPOCH_INIT_VAL; ++ ++ DHD_TRACE(("trying to send create h2d info ring id %d\n", prot->h2dring_info_subn->idx)); ++ prot->h2dring_info_subn->n_completion_ids = 1; ++ prot->h2dring_info_subn->compeltion_ring_ids[0] = prot->d2hring_info_cpln->idx; ++ ++ ret = dhd_send_h2d_ringcreate(dhd, prot->h2dring_info_subn); ++ ++ /* Note that there is no way to delete d2h or h2d ring deletion incase either fails, ++ * so can not cleanup if one ring was created while the other failed ++ */ ++ return ret; ++} /* dhd_prot_init_info_rings */ ++ ++static void ++dhd_prot_detach_info_rings(dhd_pub_t *dhd) ++{ ++ if (dhd->prot->h2dring_info_subn) { ++ dhd_prot_ring_detach(dhd, dhd->prot->h2dring_info_subn); ++ MFREE(dhd->prot->osh, dhd->prot->h2dring_info_subn, sizeof(msgbuf_ring_t)); ++ dhd->prot->h2dring_info_subn = NULL; ++ } ++ if (dhd->prot->d2hring_info_cpln) { ++ dhd_prot_ring_detach(dhd, dhd->prot->d2hring_info_cpln); ++ MFREE(dhd->prot->osh, dhd->prot->d2hring_info_cpln, sizeof(msgbuf_ring_t)); ++ dhd->prot->d2hring_info_cpln = NULL; ++ } ++} ++ ++/** ++ * Initialize protocol: sync w/dongle state. ++ * Sets dongle media info (iswl, drv_version, mac address). ++ */ ++int dhd_sync_with_dongle(dhd_pub_t *dhd) ++{ ++ int ret = 0; ++ wlc_rev_info_t revinfo; ++ ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); ++ ++ /* Post ts buffer after shim layer is attached */ ++ ret = dhd_msgbuf_rxbuf_post_ts_bufs(dhd); ++ ++ ++#ifdef DHD_FW_COREDUMP ++ /* Check the memdump capability */ ++ dhd_get_memdump_info(dhd); ++#endif /* DHD_FW_COREDUMP */ ++#ifdef BCMASSERT_LOG ++ dhd_get_assert_info(dhd); ++#endif /* BCMASSERT_LOG */ ++ ++ /* Get the device rev info */ ++ memset(&revinfo, 0, sizeof(revinfo)); ++ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); ++ if (ret < 0) { ++ DHD_ERROR(("%s: GET revinfo FAILED\n", __FUNCTION__)); ++ goto done; ++ } ++ DHD_ERROR(("%s: GET_REVINFO device 0x%x, vendor 0x%x, chipnum 0x%x\n", __FUNCTION__, ++ revinfo.deviceid, revinfo.vendorid, revinfo.chipnum)); ++ ++ DHD_SSSR_DUMP_INIT(dhd); ++ ++ dhd_process_cid_mac(dhd, TRUE); ++ ret = dhd_preinit_ioctls(dhd); ++ dhd_process_cid_mac(dhd, FALSE); ++ ++ /* Always assumes wl for now */ ++ dhd->iswl = TRUE; ++done: ++ return ret; ++} /* dhd_sync_with_dongle */ ++ ++ ++#define DHD_DBG_SHOW_METADATA 0 ++ ++#if DHD_DBG_SHOW_METADATA ++static void BCMFASTPATH ++dhd_prot_print_metadata(dhd_pub_t *dhd, void *ptr, int len) ++{ ++ uint8 tlv_t; ++ uint8 tlv_l; ++ uint8 *tlv_v = (uint8 *)ptr; ++ ++ if (len <= BCMPCIE_D2H_METADATA_HDRLEN) ++ return; ++ ++ len -= BCMPCIE_D2H_METADATA_HDRLEN; ++ tlv_v += BCMPCIE_D2H_METADATA_HDRLEN; ++ ++ while (len > TLV_HDR_LEN) { ++ tlv_t = tlv_v[TLV_TAG_OFF]; ++ tlv_l = tlv_v[TLV_LEN_OFF]; ++ ++ len -= TLV_HDR_LEN; ++ tlv_v += TLV_HDR_LEN; ++ if (len < tlv_l) ++ break; ++ if ((tlv_t == 0) || (tlv_t == WLFC_CTL_TYPE_FILLER)) ++ break; ++ ++ switch (tlv_t) { ++ case WLFC_CTL_TYPE_TXSTATUS: { ++ uint32 txs; ++ memcpy(&txs, tlv_v, sizeof(uint32)); ++ if (tlv_l < (sizeof(wl_txstatus_additional_info_t) + sizeof(uint32))) { ++ printf("METADATA TX_STATUS: %08x\n", txs); ++ } else { ++ wl_txstatus_additional_info_t tx_add_info; ++ memcpy(&tx_add_info, tlv_v + sizeof(uint32), ++ sizeof(wl_txstatus_additional_info_t)); ++ printf("METADATA TX_STATUS: %08x WLFCTS[%04x | %08x - %08x - %08x]" ++ " rate = %08x tries = %d - %d\n", txs, ++ tx_add_info.seq, tx_add_info.entry_ts, ++ tx_add_info.enq_ts, tx_add_info.last_ts, ++ tx_add_info.rspec, tx_add_info.rts_cnt, ++ tx_add_info.tx_cnt); ++ } ++ } break; ++ ++ case WLFC_CTL_TYPE_RSSI: { ++ if (tlv_l == 1) ++ printf("METADATA RX_RSSI: rssi = %d\n", *tlv_v); ++ else ++ printf("METADATA RX_RSSI[%04x]: rssi = %d snr = %d\n", ++ (*(tlv_v + 3) << 8) | *(tlv_v + 2), ++ (int8)(*tlv_v), *(tlv_v + 1)); ++ } break; ++ ++ case WLFC_CTL_TYPE_FIFO_CREDITBACK: ++ bcm_print_bytes("METADATA FIFO_CREDITBACK", tlv_v, tlv_l); ++ break; ++ ++ case WLFC_CTL_TYPE_TX_ENTRY_STAMP: ++ bcm_print_bytes("METADATA TX_ENTRY", tlv_v, tlv_l); ++ break; ++ ++ case WLFC_CTL_TYPE_RX_STAMP: { ++ struct { ++ uint32 rspec; ++ uint32 bus_time; ++ uint32 wlan_time; ++ } rx_tmstamp; ++ memcpy(&rx_tmstamp, tlv_v, sizeof(rx_tmstamp)); ++ printf("METADATA RX TIMESTMAP: WLFCTS[%08x - %08x] rate = %08x\n", ++ rx_tmstamp.wlan_time, rx_tmstamp.bus_time, rx_tmstamp.rspec); ++ } break; ++ ++ case WLFC_CTL_TYPE_TRANS_ID: ++ bcm_print_bytes("METADATA TRANS_ID", tlv_v, tlv_l); ++ break; ++ ++ case WLFC_CTL_TYPE_COMP_TXSTATUS: ++ bcm_print_bytes("METADATA COMP_TXSTATUS", tlv_v, tlv_l); ++ break; ++ ++ default: ++ bcm_print_bytes("METADATA UNKNOWN", tlv_v, tlv_l); ++ break; ++ } ++ ++ len -= tlv_l; ++ tlv_v += tlv_l; ++ } ++} ++#endif /* DHD_DBG_SHOW_METADATA */ ++ ++static INLINE void BCMFASTPATH ++dhd_prot_packet_free(dhd_pub_t *dhd, void *pkt, uint8 pkttype, bool send) ++{ ++ if (pkt) { ++ if (pkttype == PKTTYPE_IOCTL_RX || ++ pkttype == PKTTYPE_EVENT_RX || ++ pkttype == PKTTYPE_INFO_RX || ++ pkttype == PKTTYPE_TSBUF_RX) { ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhd->osh, pkt, send); ++#else ++ PKTFREE(dhd->osh, pkt, send); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ } else { ++ PKTFREE(dhd->osh, pkt, send); ++ } ++ } ++} ++ ++/* dhd_prot_packet_get should be called only for items having pktid_ctrl_map handle */ ++static INLINE void * BCMFASTPATH ++dhd_prot_packet_get(dhd_pub_t *dhd, uint32 pktid, uint8 pkttype, bool free_pktid) ++{ ++ void *PKTBUF; ++ dmaaddr_t pa; ++ uint32 len; ++ void *dmah; ++ void *secdma; ++ ++#ifdef DHD_PCIE_PKTID ++ if (free_pktid) { ++ PKTBUF = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_ctrl_map, ++ pktid, pa, len, dmah, secdma, pkttype); ++ } else { ++ PKTBUF = DHD_PKTID_TO_NATIVE_RSV(dhd, dhd->prot->pktid_ctrl_map, ++ pktid, pa, len, dmah, secdma, pkttype); ++ } ++#else ++ PKTBUF = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_ctrl_map, pktid, pa, ++ len, dmah, secdma, pkttype); ++#endif /* DHD_PCIE_PKTID */ ++ if (PKTBUF) { ++ { ++ if (SECURE_DMA_ENAB(dhd->osh)) ++ SECURE_DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, dmah, ++ secdma, 0); ++ else ++ DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, dmah); ++#ifdef DMAMAP_STATS ++ switch (pkttype) { ++#ifndef IOCTLRESP_USE_CONSTMEM ++ case PKTTYPE_IOCTL_RX: ++ dhd->dma_stats.ioctl_rx--; ++ dhd->dma_stats.ioctl_rx_sz -= len; ++ break; ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ case PKTTYPE_EVENT_RX: ++ dhd->dma_stats.event_rx--; ++ dhd->dma_stats.event_rx_sz -= len; ++ break; ++ case PKTTYPE_INFO_RX: ++ dhd->dma_stats.info_rx--; ++ dhd->dma_stats.info_rx_sz -= len; ++ break; ++ case PKTTYPE_TSBUF_RX: ++ dhd->dma_stats.tsbuf_rx--; ++ dhd->dma_stats.tsbuf_rx_sz -= len; ++ break; ++ } ++#endif /* DMAMAP_STATS */ ++ } ++ } ++ ++ return PKTBUF; ++} ++ ++#ifdef IOCTLRESP_USE_CONSTMEM ++static INLINE void BCMFASTPATH ++dhd_prot_ioctl_ret_buffer_get(dhd_pub_t *dhd, uint32 pktid, dhd_dma_buf_t *retbuf) ++{ ++ memset(retbuf, 0, sizeof(dhd_dma_buf_t)); ++ retbuf->va = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_map_handle_ioctl, pktid, ++ retbuf->pa, retbuf->len, retbuf->dmah, retbuf->secdma, PKTTYPE_IOCTL_RX); ++ ++ return; ++} ++#endif ++ ++#ifdef PCIE_INB_DW ++static int ++dhd_prot_inc_hostactive_devwake_assert(dhd_bus_t *bus) ++{ ++ unsigned long flags = 0; ++ ++ if (INBAND_DW_ENAB(bus)) { ++ DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); ++ bus->host_active_cnt++; ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ if (dhd_bus_set_device_wake(bus, TRUE) != BCME_OK) { ++ DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); ++ bus->host_active_cnt--; ++ dhd_bus_inb_ack_pending_ds_req(bus); ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ return BCME_ERROR; ++ } ++ } ++ ++ return BCME_OK; ++} ++ ++static void ++dhd_prot_dec_hostactive_ack_pending_dsreq(dhd_bus_t *bus) ++{ ++ unsigned long flags = 0; ++ if (INBAND_DW_ENAB(bus)) { ++ DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); ++ bus->host_active_cnt--; ++ dhd_bus_inb_ack_pending_ds_req(bus); ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ } ++} ++#endif /* PCIE_INB_DW */ ++ ++static void BCMFASTPATH ++dhd_msgbuf_rxbuf_post(dhd_pub_t *dhd, bool use_rsv_pktid) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ int16 fillbufs; ++ uint16 cnt = 256; ++ int retcount = 0; ++ ++ fillbufs = prot->max_rxbufpost - prot->rxbufpost; ++ while (fillbufs >= RX_BUF_BURST) { ++ cnt--; ++ if (cnt == 0) { ++ /* find a better way to reschedule rx buf post if space not available */ ++ DHD_ERROR(("h2d rx post ring not available to post host buffers \n")); ++ DHD_ERROR(("Current posted host buf count %d \n", prot->rxbufpost)); ++ break; ++ } ++ ++ /* Post in a burst of 32 buffers at a time */ ++ fillbufs = MIN(fillbufs, RX_BUF_BURST); ++ ++ /* Post buffers */ ++ retcount = dhd_prot_rxbuf_post(dhd, fillbufs, use_rsv_pktid); ++ ++ if (retcount >= 0) { ++ prot->rxbufpost += (uint16)retcount; ++#ifdef DHD_LB_RXC ++ /* dhd_prot_rxbuf_post returns the number of buffers posted */ ++ DHD_LB_STATS_UPDATE_RXC_HISTO(dhd, retcount); ++#endif /* DHD_LB_RXC */ ++ /* how many more to post */ ++ fillbufs = prot->max_rxbufpost - prot->rxbufpost; ++ } else { ++ /* Make sure we don't run loop any further */ ++ fillbufs = 0; ++ } ++ } ++} ++ ++/** Post 'count' no of rx buffers to dongle */ ++static int BCMFASTPATH ++dhd_prot_rxbuf_post(dhd_pub_t *dhd, uint16 count, bool use_rsv_pktid) ++{ ++ void *p, **pktbuf; ++ uint16 pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; ++ uint8 *rxbuf_post_tmp; ++ host_rxbuf_post_t *rxbuf_post; ++ void *msg_start; ++ dmaaddr_t pa, *pktbuf_pa; ++ uint32 *pktlen; ++ uint16 i = 0, alloced = 0; ++ unsigned long flags; ++ uint32 pktid; ++ dhd_prot_t *prot = dhd->prot; ++ msgbuf_ring_t *ring = &prot->h2dring_rxp_subn; ++ void *lcl_buf; ++ uint16 lcl_buf_size; ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ /* allocate a local buffer to store pkt buffer va, pa and length */ ++ lcl_buf_size = (sizeof(void *) + sizeof(dmaaddr_t) + sizeof(uint32)) * ++ RX_BUF_BURST; ++ lcl_buf = MALLOC(dhd->osh, lcl_buf_size); ++ if (!lcl_buf) { ++ DHD_ERROR(("%s: local scratch buffer allocation failed\n", __FUNCTION__)); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return 0; ++ } ++ pktbuf = lcl_buf; ++ pktbuf_pa = (dmaaddr_t *)((uint8 *)pktbuf + sizeof(void *) * RX_BUF_BURST); ++ pktlen = (uint32 *)((uint8 *)pktbuf_pa + sizeof(dmaaddr_t) * RX_BUF_BURST); ++ ++ for (i = 0; i < count; i++) { ++ if ((p = PKTGET(dhd->osh, pktsz, FALSE)) == NULL) { ++ DHD_ERROR(("%s:%d: PKTGET for rxbuf failed\n", __FUNCTION__, __LINE__)); ++ dhd->rx_pktgetfail++; ++ break; ++ } ++ ++ pktlen[i] = PKTLEN(dhd->osh, p); ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ pa = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen[i], ++ DMA_RX, p, 0, ring->dma_buf.secdma, 0); ++ } ++#ifndef BCM_SECURE_DMA ++ else ++ pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen[i], DMA_RX, p, 0); ++#endif /* #ifndef BCM_SECURE_DMA */ ++ ++ if (PHYSADDRISZERO(pa)) { ++ PKTFREE(dhd->osh, p, FALSE); ++ DHD_ERROR(("Invalid phyaddr 0\n")); ++ ASSERT(0); ++ break; ++ } ++#ifdef DMAMAP_STATS ++ dhd->dma_stats.rxdata++; ++ dhd->dma_stats.rxdata_sz += pktlen[i]; ++#endif /* DMAMAP_STATS */ ++ ++ PKTPULL(dhd->osh, p, prot->rx_metadata_offset); ++ pktlen[i] = PKTLEN(dhd->osh, p); ++ pktbuf[i] = p; ++ pktbuf_pa[i] = pa; ++ } ++ ++ /* only post what we have */ ++ count = i; ++ ++ /* grab the rx lock to allocate pktid and post on ring */ ++ DHD_SPIN_LOCK(prot->rx_lock, flags); ++ ++ /* Claim space for exactly 'count' no of messages, for mitigation purpose */ ++ msg_start = (void *) ++ dhd_prot_alloc_ring_space(dhd, ring, count, &alloced, TRUE); ++ if (msg_start == NULL) { ++ DHD_INFO(("%s:%d: Rxbufpost Msgbuf Not available\n", __FUNCTION__, __LINE__)); ++ goto cleanup; ++ } ++ /* if msg_start != NULL, we should have alloced space for atleast 1 item */ ++ ASSERT(alloced > 0); ++ ++ rxbuf_post_tmp = (uint8*)msg_start; ++ ++ for (i = 0; i < alloced; i++) { ++ rxbuf_post = (host_rxbuf_post_t *)rxbuf_post_tmp; ++ p = pktbuf[i]; ++ pa = pktbuf_pa[i]; ++ ++#if defined(DHD_LB_RXC) ++ if (use_rsv_pktid == TRUE) { ++ bcm_workq_t *workq = &prot->rx_compl_cons; ++ int elem_ix = bcm_ring_cons(WORKQ_RING(workq), DHD_LB_WORKQ_SZ); ++ ++ if (elem_ix == BCM_RING_EMPTY) { ++ DHD_INFO(("%s rx_compl_cons ring is empty\n", __FUNCTION__)); ++ pktid = DHD_PKTID_INVALID; ++ goto alloc_pkt_id; ++ } else { ++ uint32 *elem = WORKQ_ELEMENT(uint32, workq, elem_ix); ++ pktid = *elem; ++ } ++ ++ rxbuf_post->cmn_hdr.request_id = htol32(pktid); ++ ++ /* Now populate the previous locker with valid information */ ++ if (pktid != DHD_PKTID_INVALID) { ++ DHD_NATIVE_TO_PKTID_SAVE(dhd, dhd->prot->pktid_rx_map, ++ p, pktid, pa, pktlen[i], DMA_RX, NULL, NULL, ++ PKTTYPE_DATA_RX); ++ } ++ } else ++#endif /* ! DHD_LB_RXC */ ++ { ++#if defined(DHD_LB_RXC) ++alloc_pkt_id: ++#endif /* DHD_LB_RXC */ ++ pktid = DHD_NATIVE_TO_PKTID(dhd, dhd->prot->pktid_rx_map, p, pa, ++ pktlen[i], DMA_RX, NULL, ring->dma_buf.secdma, PKTTYPE_DATA_RX); ++#if defined(DHD_PCIE_PKTID) ++ if (pktid == DHD_PKTID_INVALID) { ++ break; ++ } ++#endif /* DHD_PCIE_PKTID */ ++ } ++ ++ /* Common msg header */ ++ rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_RXBUF_POST; ++ rxbuf_post->cmn_hdr.if_id = 0; ++ rxbuf_post->cmn_hdr.epoch = ring->seqnum % H2D_EPOCH_MODULO; ++ rxbuf_post->cmn_hdr.flags = ring->current_phase; ++ ring->seqnum++; ++ rxbuf_post->data_buf_len = htol16((uint16)pktlen[i]); ++ rxbuf_post->data_buf_addr.high_addr = htol32(PHYSADDRHI(pa)); ++ rxbuf_post->data_buf_addr.low_addr = ++ htol32(PHYSADDRLO(pa) + prot->rx_metadata_offset); ++ ++ if (prot->rx_metadata_offset) { ++ rxbuf_post->metadata_buf_len = prot->rx_metadata_offset; ++ rxbuf_post->metadata_buf_addr.high_addr = htol32(PHYSADDRHI(pa)); ++ rxbuf_post->metadata_buf_addr.low_addr = htol32(PHYSADDRLO(pa)); ++ } else { ++ rxbuf_post->metadata_buf_len = 0; ++ rxbuf_post->metadata_buf_addr.high_addr = 0; ++ rxbuf_post->metadata_buf_addr.low_addr = 0; ++ } ++ ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT(dhd, prot->pktid_rx_map, pktid, DHD_DUPLICATE_ALLOC); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ rxbuf_post->cmn_hdr.request_id = htol32(pktid); ++ ++ /* Move rxbuf_post_tmp to next item */ ++ rxbuf_post_tmp = rxbuf_post_tmp + ring->item_len; ++ } ++ ++ if (i < alloced) { ++ if (ring->wr < (alloced - i)) ++ ring->wr = ring->max_items - (alloced - i); ++ else ++ ring->wr -= (alloced - i); ++ ++ if (ring->wr == 0) { ++ DHD_INFO(("%s: flipping the phase now\n", ring->name)); ++ ring->current_phase = ring->current_phase ? ++ 0 : BCMPCIE_CMNHDR_PHASE_BIT_INIT; ++ } ++ ++ alloced = i; ++ } ++ ++ /* update ring's WR index and ring doorbell to dongle */ ++ if (alloced > 0) { ++ unsigned long flags1; ++ DHD_GENERAL_LOCK(dhd, flags1); ++ dhd_prot_ring_write_complete(dhd, ring, msg_start, alloced); ++ DHD_GENERAL_UNLOCK(dhd, flags1); ++ } ++ ++ DHD_SPIN_UNLOCK(prot->rx_lock, flags); ++ ++cleanup: ++ for (i = alloced; i < count; i++) { ++ p = pktbuf[i]; ++ pa = pktbuf_pa[i]; ++ ++ if (SECURE_DMA_ENAB(dhd->osh)) ++ SECURE_DMA_UNMAP(dhd->osh, pa, pktlen[i], DMA_RX, 0, ++ DHD_DMAH_NULL, ring->dma_buf.secdma, 0); ++ else ++ DMA_UNMAP(dhd->osh, pa, pktlen[i], DMA_RX, 0, DHD_DMAH_NULL); ++ PKTFREE(dhd->osh, p, FALSE); ++ } ++ ++ MFREE(dhd->osh, lcl_buf, lcl_buf_size); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return alloced; ++} /* dhd_prot_rxbufpost */ ++ ++static int ++dhd_prot_infobufpost(dhd_pub_t *dhd) ++{ ++ unsigned long flags; ++ uint32 pktid; ++ dhd_prot_t *prot = dhd->prot; ++ msgbuf_ring_t *ring = prot->h2dring_info_subn; ++ uint16 alloced = 0; ++ uint16 pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; ++ uint32 pktlen; ++ info_buf_post_msg_t *infobuf_post; ++ uint8 *infobuf_post_tmp; ++ void *p; ++ void* msg_start; ++ uint8 i = 0; ++ dmaaddr_t pa; ++ int16 count; ++ ++ if (ring == NULL) ++ return 0; ++ ++ if (ring->inited != TRUE) ++ return 0; ++ if (prot->max_infobufpost == 0) ++ return 0; ++ ++ count = prot->max_infobufpost - prot->infobufpost; ++ ++ if (count <= 0) { ++ DHD_INFO(("%s: Cannot post more than max info resp buffers\n", ++ __FUNCTION__)); ++ return 0; ++ } ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ /* Claim space for exactly 'count' no of messages, for mitigation purpose */ ++ msg_start = (void *) dhd_prot_alloc_ring_space(dhd, ring, count, &alloced, FALSE); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ if (msg_start == NULL) { ++ DHD_INFO(("%s:%d: infobufpost Msgbuf Not available\n", __FUNCTION__, __LINE__)); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return -1; ++ } ++ ++ /* if msg_start != NULL, we should have alloced space for atleast 1 item */ ++ ASSERT(alloced > 0); ++ ++ infobuf_post_tmp = (uint8*) msg_start; ++ ++ /* loop through each allocated message in the host ring */ ++ for (i = 0; i < alloced; i++) { ++ infobuf_post = (info_buf_post_msg_t *) infobuf_post_tmp; ++ /* Create a rx buffer */ ++#ifdef DHD_USE_STATIC_CTRLBUF ++ p = PKTGET_STATIC(dhd->osh, pktsz, FALSE); ++#else ++ p = PKTGET(dhd->osh, pktsz, FALSE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ if (p == NULL) { ++ DHD_ERROR(("%s:%d: PKTGET for infobuf failed\n", __FUNCTION__, __LINE__)); ++ dhd->rx_pktgetfail++; ++ break; ++ } ++ pktlen = PKTLEN(dhd->osh, p); ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ pa = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, ++ DMA_RX, p, 0, ring->dma_buf.secdma, 0); ++ } ++#ifndef BCM_SECURE_DMA ++ else ++ pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0); ++#endif /* #ifndef BCM_SECURE_DMA */ ++ if (PHYSADDRISZERO(pa)) { ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ SECURE_DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL, ++ ring->dma_buf.secdma, 0); ++ } ++ else ++ DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL); ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhd->osh, p, FALSE); ++#else ++ PKTFREE(dhd->osh, p, FALSE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ DHD_ERROR(("Invalid phyaddr 0\n")); ++ ASSERT(0); ++ break; ++ } ++#ifdef DMAMAP_STATS ++ dhd->dma_stats.info_rx++; ++ dhd->dma_stats.info_rx_sz += pktlen; ++#endif /* DMAMAP_STATS */ ++ pktlen = PKTLEN(dhd->osh, p); ++ ++ /* Common msg header */ ++ infobuf_post->cmn_hdr.msg_type = MSG_TYPE_INFO_BUF_POST; ++ infobuf_post->cmn_hdr.if_id = 0; ++ infobuf_post->cmn_hdr.epoch = ring->seqnum % H2D_EPOCH_MODULO; ++ infobuf_post->cmn_hdr.flags = ring->current_phase; ++ ring->seqnum++; ++ ++#if defined(DHD_PCIE_PKTID) ++ /* get the lock before calling DHD_NATIVE_TO_PKTID */ ++ DHD_GENERAL_LOCK(dhd, flags); ++#endif /* DHD_PCIE_PKTID */ ++ ++ pktid = DHD_NATIVE_TO_PKTID(dhd, dhd->prot->pktid_ctrl_map, p, pa, ++ pktlen, DMA_RX, NULL, ring->dma_buf.secdma, PKTTYPE_INFO_RX); ++ ++ ++#if defined(DHD_PCIE_PKTID) ++ /* free lock */ ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ if (pktid == DHD_PKTID_INVALID) { ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ DHD_GENERAL_LOCK(dhd, flags); ++ SECURE_DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, 0, ++ ring->dma_buf.secdma, 0); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ } else ++ DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, 0); ++ ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhd->osh, p, FALSE); ++#else ++ PKTFREE(dhd->osh, p, FALSE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ DHD_ERROR(("%s: Pktid pool depleted.\n", __FUNCTION__)); ++ break; ++ } ++#endif /* DHD_PCIE_PKTID */ ++ ++ infobuf_post->host_buf_len = htol16((uint16)pktlen); ++ infobuf_post->host_buf_addr.high_addr = htol32(PHYSADDRHI(pa)); ++ infobuf_post->host_buf_addr.low_addr = htol32(PHYSADDRLO(pa)); ++ ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT(dhd, prot->pktid_ctrl_map, pktid, DHD_DUPLICATE_ALLOC); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ DHD_INFO(("ID %d, low_addr 0x%08x, high_addr 0x%08x\n", ++ infobuf_post->cmn_hdr.request_id, infobuf_post->host_buf_addr.low_addr, ++ infobuf_post->host_buf_addr.high_addr)); ++ ++ infobuf_post->cmn_hdr.request_id = htol32(pktid); ++ /* Move rxbuf_post_tmp to next item */ ++ infobuf_post_tmp = infobuf_post_tmp + ring->item_len; ++ } ++ ++ if (i < alloced) { ++ if (ring->wr < (alloced - i)) ++ ring->wr = ring->max_items - (alloced - i); ++ else ++ ring->wr -= (alloced - i); ++ ++ alloced = i; ++ if (alloced && ring->wr == 0) { ++ DHD_INFO(("%s: flipping the phase now\n", ring->name)); ++ ring->current_phase = ring->current_phase ? ++ 0 : BCMPCIE_CMNHDR_PHASE_BIT_INIT; ++ } ++ } ++ ++ /* Update the write pointer in TCM & ring bell */ ++ if (alloced > 0) { ++ prot->infobufpost += alloced; ++ DHD_INFO(("allocated %d buffers for info ring\n", alloced)); ++ DHD_GENERAL_LOCK(dhd, flags); ++ dhd_prot_ring_write_complete(dhd, ring, msg_start, alloced); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ } ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return alloced; ++} /* dhd_prot_infobufpost */ ++ ++#ifdef IOCTLRESP_USE_CONSTMEM ++static int ++alloc_ioctl_return_buffer(dhd_pub_t *dhd, dhd_dma_buf_t *retbuf) ++{ ++ int err; ++ memset(retbuf, 0, sizeof(dhd_dma_buf_t)); ++ ++ if ((err = dhd_dma_buf_alloc(dhd, retbuf, IOCT_RETBUF_SIZE)) != BCME_OK) { ++ DHD_ERROR(("%s: dhd_dma_buf_alloc err %d\n", __FUNCTION__, err)); ++ ASSERT(0); ++ return BCME_NOMEM; ++ } ++ ++ return BCME_OK; ++} ++ ++static void ++free_ioctl_return_buffer(dhd_pub_t *dhd, dhd_dma_buf_t *retbuf) ++{ ++ /* retbuf (declared on stack) not fully populated ... */ ++ if (retbuf->va) { ++ uint32 dma_pad; ++ dma_pad = (IOCT_RETBUF_SIZE % DHD_DMA_PAD) ? DHD_DMA_PAD : 0; ++ retbuf->len = IOCT_RETBUF_SIZE; ++ retbuf->_alloced = retbuf->len + dma_pad; ++ } ++ ++ dhd_dma_buf_free(dhd, retbuf); ++ return; ++} ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ ++static int ++dhd_prot_rxbufpost_ctrl(dhd_pub_t *dhd, uint8 msg_type) ++{ ++ void *p; ++ uint16 pktsz; ++ ioctl_resp_evt_buf_post_msg_t *rxbuf_post; ++ dmaaddr_t pa; ++ uint32 pktlen; ++ dhd_prot_t *prot = dhd->prot; ++ uint16 alloced = 0; ++ unsigned long flags; ++ dhd_dma_buf_t retbuf; ++ void *dmah = NULL; ++ uint32 pktid; ++ void *map_handle; ++ msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; ++ bool non_ioctl_resp_buf = 0; ++ dhd_pkttype_t buf_type; ++ ++ if (dhd->busstate == DHD_BUS_DOWN) { ++ DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); ++ return -1; ++ } ++ memset(&retbuf, 0, sizeof(dhd_dma_buf_t)); ++ ++ if (msg_type == MSG_TYPE_IOCTLRESP_BUF_POST) ++ buf_type = PKTTYPE_IOCTL_RX; ++ else if (msg_type == MSG_TYPE_EVENT_BUF_POST) ++ buf_type = PKTTYPE_EVENT_RX; ++ else if (msg_type == MSG_TYPE_TIMSTAMP_BUFPOST) ++ buf_type = PKTTYPE_TSBUF_RX; ++ else { ++ DHD_ERROR(("invalid message type to be posted to Ctrl ring %d\n", msg_type)); ++ return -1; ++ } ++ ++ ++ if ((msg_type == MSG_TYPE_EVENT_BUF_POST) || (msg_type == MSG_TYPE_TIMSTAMP_BUFPOST)) ++ non_ioctl_resp_buf = TRUE; ++ else ++ non_ioctl_resp_buf = FALSE; ++ ++ if (non_ioctl_resp_buf) { ++ /* Allocate packet for not ioctl resp buffer post */ ++ pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; ++ } else { ++ /* Allocate packet for ctrl/ioctl buffer post */ ++ pktsz = DHD_FLOWRING_IOCTL_BUFPOST_PKTSZ; ++ } ++ ++#ifdef IOCTLRESP_USE_CONSTMEM ++ if (!non_ioctl_resp_buf) { ++ if (alloc_ioctl_return_buffer(dhd, &retbuf) != BCME_OK) { ++ DHD_ERROR(("Could not allocate IOCTL response buffer\n")); ++ return -1; ++ } ++ ASSERT(retbuf.len == IOCT_RETBUF_SIZE); ++ p = retbuf.va; ++ pktlen = retbuf.len; ++ pa = retbuf.pa; ++ dmah = retbuf.dmah; ++ } else ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ { ++#ifdef DHD_USE_STATIC_CTRLBUF ++ p = PKTGET_STATIC(dhd->osh, pktsz, FALSE); ++#else ++ p = PKTGET(dhd->osh, pktsz, FALSE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ if (p == NULL) { ++ DHD_ERROR(("%s:%d: PKTGET for %s buf failed\n", ++ __FUNCTION__, __LINE__, non_ioctl_resp_buf ? ++ "EVENT" : "IOCTL RESP")); ++ dhd->rx_pktgetfail++; ++ return -1; ++ } ++ ++ pktlen = PKTLEN(dhd->osh, p); ++ ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ DHD_GENERAL_LOCK(dhd, flags); ++ pa = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, ++ DMA_RX, p, 0, ring->dma_buf.secdma, 0); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ } ++#ifndef BCM_SECURE_DMA ++ else ++ pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0); ++#endif /* #ifndef BCM_SECURE_DMA */ ++ ++ if (PHYSADDRISZERO(pa)) { ++ DHD_ERROR(("Invalid physaddr 0\n")); ++ ASSERT(0); ++ goto free_pkt_return; ++ } ++ ++#ifdef DMAMAP_STATS ++ switch (buf_type) { ++#ifndef IOCTLRESP_USE_CONSTMEM ++ case PKTTYPE_IOCTL_RX: ++ dhd->dma_stats.ioctl_rx++; ++ dhd->dma_stats.ioctl_rx_sz += pktlen; ++ break; ++#endif /* !IOCTLRESP_USE_CONSTMEM */ ++ case PKTTYPE_EVENT_RX: ++ dhd->dma_stats.event_rx++; ++ dhd->dma_stats.event_rx_sz += pktlen; ++ break; ++ case PKTTYPE_TSBUF_RX: ++ dhd->dma_stats.tsbuf_rx++; ++ dhd->dma_stats.tsbuf_rx_sz += pktlen; ++ break; ++ default: ++ break; ++ } ++#endif /* DMAMAP_STATS */ ++ ++ } ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ rxbuf_post = (ioctl_resp_evt_buf_post_msg_t *) ++ dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); ++ ++ if (rxbuf_post == NULL) { ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ DHD_ERROR(("%s:%d: Ctrl submit Msgbuf Not available to post buffer \n", ++ __FUNCTION__, __LINE__)); ++ ++#ifdef IOCTLRESP_USE_CONSTMEM ++ if (non_ioctl_resp_buf) ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ { ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ DHD_GENERAL_LOCK(dhd, flags); ++ SECURE_DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL, ++ ring->dma_buf.secdma, 0); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ } else { ++ DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL); ++ } ++ } ++ goto free_pkt_return; ++ } ++ ++ /* CMN msg header */ ++ rxbuf_post->cmn_hdr.msg_type = msg_type; ++ ++#ifdef IOCTLRESP_USE_CONSTMEM ++ if (!non_ioctl_resp_buf) { ++ map_handle = dhd->prot->pktid_map_handle_ioctl; ++ pktid = DHD_NATIVE_TO_PKTID(dhd, map_handle, p, pa, pktlen, DMA_RX, dmah, ++ ring->dma_buf.secdma, buf_type); ++ } else ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ { ++ map_handle = dhd->prot->pktid_ctrl_map; ++ pktid = DHD_NATIVE_TO_PKTID(dhd, map_handle, ++ p, pa, pktlen, DMA_RX, dmah, ring->dma_buf.secdma, ++ buf_type); ++ } ++ ++ if (pktid == DHD_PKTID_INVALID) { ++ if (ring->wr == 0) { ++ ring->wr = ring->max_items - 1; ++ } else { ++ ring->wr--; ++ if (ring->wr == 0) { ++ ring->current_phase = ring->current_phase ? 0 : ++ BCMPCIE_CMNHDR_PHASE_BIT_INIT; ++ } ++ } ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL); ++ DHD_ERROR(("%s: Pktid pool depleted.\n", __FUNCTION__)); ++ goto free_pkt_return; ++ } ++ ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT(dhd, map_handle, pktid, DHD_DUPLICATE_ALLOC); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ rxbuf_post->cmn_hdr.request_id = htol32(pktid); ++ rxbuf_post->cmn_hdr.if_id = 0; ++ rxbuf_post->cmn_hdr.epoch = ring->seqnum % H2D_EPOCH_MODULO; ++ ring->seqnum++; ++ rxbuf_post->cmn_hdr.flags = ring->current_phase; ++ ++#if defined(DHD_PCIE_PKTID) ++ if (rxbuf_post->cmn_hdr.request_id == DHD_PKTID_INVALID) { ++ if (ring->wr == 0) { ++ ring->wr = ring->max_items - 1; ++ } else { ++ if (ring->wr == 0) { ++ ring->current_phase = ring->current_phase ? 0 : ++ BCMPCIE_CMNHDR_PHASE_BIT_INIT; ++ } ++ } ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef IOCTLRESP_USE_CONSTMEM ++ if (non_ioctl_resp_buf) ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ { ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ DHD_GENERAL_LOCK(dhd, flags); ++ SECURE_DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL, ++ ring->dma_buf.secdma, 0); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ } else ++ DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL); ++ } ++ goto free_pkt_return; ++ } ++#endif /* DHD_PCIE_PKTID */ ++ ++#ifndef IOCTLRESP_USE_CONSTMEM ++ rxbuf_post->host_buf_len = htol16((uint16)PKTLEN(dhd->osh, p)); ++#else ++ rxbuf_post->host_buf_len = htol16((uint16)pktlen); ++#endif /* IOCTLRESP_USE_CONSTMEM */ ++ rxbuf_post->host_buf_addr.high_addr = htol32(PHYSADDRHI(pa)); ++ rxbuf_post->host_buf_addr.low_addr = htol32(PHYSADDRLO(pa)); ++ ++ /* update ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ring, rxbuf_post, 1); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return 1; ++ ++free_pkt_return: ++#ifdef IOCTLRESP_USE_CONSTMEM ++ if (!non_ioctl_resp_buf) { ++ free_ioctl_return_buffer(dhd, &retbuf); ++ } else ++#endif ++ { ++ dhd_prot_packet_free(dhd, p, buf_type, FALSE); ++ } ++ ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return -1; ++} /* dhd_prot_rxbufpost_ctrl */ ++ ++static uint16 ++dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, uint8 msg_type, uint32 max_to_post) ++{ ++ uint32 i = 0; ++ int32 ret_val; ++ ++ DHD_INFO(("max to post %d, event %d \n", max_to_post, msg_type)); ++ ++ if (dhd->busstate == DHD_BUS_DOWN) { ++ DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); ++ return 0; ++ } ++ ++ while (i < max_to_post) { ++ ret_val = dhd_prot_rxbufpost_ctrl(dhd, msg_type); ++ if (ret_val < 0) ++ break; ++ i++; ++ } ++ DHD_INFO(("posted %d buffers of type %d\n", i, msg_type)); ++ return (uint16)i; ++} ++ ++static void ++dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ int max_to_post; ++ ++ DHD_INFO(("ioctl resp buf post\n")); ++ max_to_post = prot->max_ioctlrespbufpost - prot->cur_ioctlresp_bufs_posted; ++ if (max_to_post <= 0) { ++ DHD_INFO(("%s: Cannot post more than max IOCTL resp buffers\n", ++ __FUNCTION__)); ++ return; ++ } ++ prot->cur_ioctlresp_bufs_posted += dhd_msgbuf_rxbuf_post_ctrlpath(dhd, ++ MSG_TYPE_IOCTLRESP_BUF_POST, max_to_post); ++} ++ ++static void ++dhd_msgbuf_rxbuf_post_event_bufs(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ int max_to_post; ++ ++ /* Use atomic variable to avoid re-entry */ ++ if (atomic_read(&dhd_msgbuf_rxbuf_post_event_bufs_running) > 0) { ++ return; ++ } ++ atomic_inc(&dhd_msgbuf_rxbuf_post_event_bufs_running); ++ ++ max_to_post = prot->max_eventbufpost - prot->cur_event_bufs_posted; ++ if (max_to_post <= 0) { ++ DHD_ERROR(("%s: Cannot post more than max event buffers\n", ++ __FUNCTION__)); ++ return; ++ } ++ prot->cur_event_bufs_posted += dhd_msgbuf_rxbuf_post_ctrlpath(dhd, ++ MSG_TYPE_EVENT_BUF_POST, max_to_post); ++ ++ atomic_dec(&dhd_msgbuf_rxbuf_post_event_bufs_running); ++} ++ ++static int ++dhd_msgbuf_rxbuf_post_ts_bufs(dhd_pub_t *dhd) ++{ ++#ifdef DHD_TIMESYNC ++ dhd_prot_t *prot = dhd->prot; ++ int max_to_post; ++ ++ if (prot->active_ipc_version < 7) { ++ DHD_ERROR(("no ts buffers to device ipc rev is %d, needs to be atleast 7\n", ++ prot->active_ipc_version)); ++ return 0; ++ } ++ ++ max_to_post = prot->max_tsbufpost - prot->cur_ts_bufs_posted; ++ if (max_to_post <= 0) { ++ DHD_INFO(("%s: Cannot post more than max ts buffers\n", ++ __FUNCTION__)); ++ return 0; ++ } ++ ++ prot->cur_ts_bufs_posted += dhd_msgbuf_rxbuf_post_ctrlpath(dhd, ++ MSG_TYPE_TIMSTAMP_BUFPOST, max_to_post); ++#endif /* DHD_TIMESYNC */ ++ return 0; ++} ++ ++bool BCMFASTPATH ++dhd_prot_process_msgbuf_infocpl(dhd_pub_t *dhd, uint bound) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ bool more = TRUE; ++ uint n = 0; ++ msgbuf_ring_t *ring = prot->d2hring_info_cpln; ++ ++ if (ring == NULL) ++ return FALSE; ++ if (ring->inited != TRUE) ++ return FALSE; ++ ++ /* Process all the messages - DTOH direction */ ++ while (!dhd_is_device_removed(dhd)) { ++ uint8 *msg_addr; ++ uint32 msg_len; ++ ++ if (dhd->hang_was_sent) { ++ more = FALSE; ++ break; ++ } ++ ++ /* Get the message from ring */ ++ msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); ++ if (msg_addr == NULL) { ++ more = FALSE; ++ break; ++ } ++ ++ /* Prefetch data to populate the cache */ ++ OSL_PREFETCH(msg_addr); ++ ++ if (dhd_prot_process_msgtype(dhd, ring, msg_addr, msg_len) != BCME_OK) { ++ DHD_ERROR(("%s: Error at process rxpl msgbuf of len %d\n", ++ __FUNCTION__, msg_len)); ++ } ++ ++ /* Update read pointer */ ++ dhd_prot_upd_read_idx(dhd, ring); ++ ++ /* After batch processing, check RX bound */ ++ n += msg_len / ring->item_len; ++ if (n >= bound) { ++ break; ++ } ++ } ++ ++ return more; ++} ++ ++/** called when DHD needs to check for 'receive complete' messages from the dongle */ ++bool BCMFASTPATH ++dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound) ++{ ++ bool more = FALSE; ++ uint n = 0; ++ dhd_prot_t *prot = dhd->prot; ++ msgbuf_ring_t *ring = &prot->d2hring_rx_cpln; ++ uint16 item_len = ring->item_len; ++ host_rxbuf_cmpl_t *msg = NULL; ++ uint8 *msg_addr; ++ uint32 msg_len; ++ uint16 pkt_cnt, pkt_cnt_newidx; ++ unsigned long flags; ++ dmaaddr_t pa; ++ uint32 len; ++ void *dmah; ++ void *secdma; ++ int ifidx = 0, if_newidx = 0; ++ void *pkt, *pktqhead = NULL, *prevpkt = NULL, *pkt_newidx, *nextpkt; ++ uint32 pktid; ++ int i; ++ uint8 sync; ++ ++ while (1) { ++ if (dhd_is_device_removed(dhd)) ++ break; ++ ++ if (dhd->hang_was_sent) ++ break; ++ ++ pkt_cnt = 0; ++ pktqhead = pkt_newidx = NULL; ++ pkt_cnt_newidx = 0; ++ ++ DHD_SPIN_LOCK(prot->rx_lock, flags); ++ ++ /* Get the address of the next message to be read from ring */ ++ msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); ++ if (msg_addr == NULL) { ++ DHD_SPIN_UNLOCK(prot->rx_lock, flags); ++ break; ++ } ++ ++ while (msg_len > 0) { ++ msg = (host_rxbuf_cmpl_t *)msg_addr; ++ ++ /* Wait until DMA completes, then fetch msg_type */ ++ sync = prot->d2h_sync_cb(dhd, ring, &msg->cmn_hdr, item_len); ++ /* ++ * Update the curr_rd to the current index in the ring, from where ++ * the work item is fetched. This way if the fetched work item ++ * fails in LIVELOCK, we can print the exact read index in the ring ++ * that shows up the corrupted work item. ++ */ ++ if ((ring->curr_rd + 1) >= ring->max_items) { ++ ring->curr_rd = 0; ++ } else { ++ ring->curr_rd += 1; ++ } ++ ++ if (!sync) { ++ msg_len -= item_len; ++ msg_addr += item_len; ++ continue; ++ } ++ ++ pktid = ltoh32(msg->cmn_hdr.request_id); ++ ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_rx_map, pktid, ++ DHD_DUPLICATE_FREE, msg, D2HRING_RXCMPLT_ITEMSIZE); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ pkt = DHD_PKTID_TO_NATIVE(dhd, prot->pktid_rx_map, pktid, pa, ++ len, dmah, secdma, PKTTYPE_DATA_RX); ++ if (!pkt) { ++ msg_len -= item_len; ++ msg_addr += item_len; ++ continue; ++ } ++ ++ if (SECURE_DMA_ENAB(dhd->osh)) ++ SECURE_DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, ++ dmah, secdma, 0); ++ else ++ DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, dmah); ++ ++#ifdef DMAMAP_STATS ++ dhd->dma_stats.rxdata--; ++ dhd->dma_stats.rxdata_sz -= len; ++#endif /* DMAMAP_STATS */ ++ DHD_INFO(("id 0x%04x, offset %d, len %d, idx %d, phase 0x%02x, " ++ "pktdata %p, metalen %d\n", ++ ltoh32(msg->cmn_hdr.request_id), ++ ltoh16(msg->data_offset), ++ ltoh16(msg->data_len), msg->cmn_hdr.if_id, ++ msg->cmn_hdr.flags, PKTDATA(dhd->osh, pkt), ++ ltoh16(msg->metadata_len))); ++ ++ pkt_cnt++; ++ msg_len -= item_len; ++ msg_addr += item_len; ++ ++#if DHD_DBG_SHOW_METADATA ++ if (prot->metadata_dbg && prot->rx_metadata_offset && ++ msg->metadata_len) { ++ uchar *ptr; ++ ptr = PKTDATA(dhd->osh, pkt) - (prot->rx_metadata_offset); ++ /* header followed by data */ ++ bcm_print_bytes("rxmetadata", ptr, msg->metadata_len); ++ dhd_prot_print_metadata(dhd, ptr, msg->metadata_len); ++ } ++#endif /* DHD_DBG_SHOW_METADATA */ ++ ++ /* data_offset from buf start */ ++ if (ltoh16(msg->data_offset)) { ++ /* data offset given from dongle after split rx */ ++ PKTPULL(dhd->osh, pkt, ltoh16(msg->data_offset)); ++ } ++ else if (prot->rx_dataoffset) { ++ /* DMA RX offset updated through shared area */ ++ PKTPULL(dhd->osh, pkt, prot->rx_dataoffset); ++ } ++ /* Actual length of the packet */ ++ PKTSETLEN(dhd->osh, pkt, ltoh16(msg->data_len)); ++#if defined(WL_MONITOR) ++ if (dhd_monitor_enabled(dhd, ifidx) && ++ (msg->flags & BCMPCIE_PKT_FLAGS_FRAME_802_11)) { ++ dhd_rx_mon_pkt(dhd, msg, pkt, ifidx); ++ continue; ++ } ++#endif ++ ++ if (!pktqhead) { ++ pktqhead = prevpkt = pkt; ++ ifidx = msg->cmn_hdr.if_id; ++ } else { ++ if (ifidx != msg->cmn_hdr.if_id) { ++ pkt_newidx = pkt; ++ if_newidx = msg->cmn_hdr.if_id; ++ pkt_cnt--; ++ pkt_cnt_newidx = 1; ++ break; ++ } else { ++ PKTSETNEXT(dhd->osh, prevpkt, pkt); ++ prevpkt = pkt; ++ } ++ } ++ ++#ifdef DHD_TIMESYNC ++ if (dhd->prot->rx_ts_log_enabled) { ++ ts_timestamp_t *ts = (ts_timestamp_t *)&msg->ts; ++ dhd_timesync_log_rx_timestamp(dhd->ts, ifidx, ts->low, ts->high); ++ } ++#endif /* DHD_TIMESYNC */ ++ } ++ ++ /* roll back read pointer for unprocessed message */ ++ if (msg_len > 0) { ++ if (ring->rd < msg_len / item_len) ++ ring->rd = ring->max_items - msg_len / item_len; ++ else ++ ring->rd -= msg_len / item_len; ++ } ++ ++ /* Update read pointer */ ++ dhd_prot_upd_read_idx(dhd, ring); ++ ++ DHD_SPIN_UNLOCK(prot->rx_lock, flags); ++ ++ pkt = pktqhead; ++ for (i = 0; pkt && i < pkt_cnt; i++, pkt = nextpkt) { ++ nextpkt = PKTNEXT(dhd->osh, pkt); ++ PKTSETNEXT(dhd->osh, pkt, NULL); ++#ifdef DHD_LB_RXP ++ dhd_lb_rx_pkt_enqueue(dhd, pkt, ifidx); ++#elif defined(DHD_RX_CHAINING) ++ dhd_rxchain_frame(dhd, pkt, ifidx); ++#else ++ dhd_bus_rx_frame(dhd->bus, pkt, ifidx, 1); ++#endif /* DHD_LB_RXP */ ++ } ++ ++ if (pkt_newidx) { ++#ifdef DHD_LB_RXP ++ dhd_lb_rx_pkt_enqueue(dhd, pkt_newidx, if_newidx); ++#elif defined(DHD_RX_CHAINING) ++ dhd_rxchain_frame(dhd, pkt_newidx, if_newidx); ++#else ++ dhd_bus_rx_frame(dhd->bus, pkt_newidx, if_newidx, 1); ++#endif /* DHD_LB_RXP */ ++ } ++ ++ pkt_cnt += pkt_cnt_newidx; ++ ++ /* Post another set of rxbufs to the device */ ++ dhd_prot_return_rxbuf(dhd, 0, pkt_cnt); ++ ++ /* After batch processing, check RX bound */ ++ n += pkt_cnt; ++ if (n >= bound) { ++ more = TRUE; ++ break; ++ } ++ } ++ ++ /* Call lb_dispatch only if packets are queued */ ++ if (n) { ++ DHD_LB_DISPATCH_RX_COMPL(dhd); ++ DHD_LB_DISPATCH_RX_PROCESS(dhd); ++ } ++ ++ return more; ++} ++ ++/** ++ * Hands transmit packets (with a caller provided flow_id) over to dongle territory (the flow ring) ++ */ ++void ++dhd_prot_update_txflowring(dhd_pub_t *dhd, uint16 flowid, void *msgring) ++{ ++ msgbuf_ring_t *ring = (msgbuf_ring_t *)msgring; ++ ++ if (ring == NULL) { ++ DHD_ERROR(("%s: NULL txflowring. exiting...\n", __FUNCTION__)); ++ return; ++ } ++ /* Update read pointer */ ++ if (dhd->dma_d2h_ring_upd_support) { ++ ring->rd = dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, ring->idx); ++ } ++ ++ DHD_TRACE(("ringid %d flowid %d write %d read %d \n\n", ++ ring->idx, flowid, ring->wr, ring->rd)); ++ ++ /* Need more logic here, but for now use it directly */ ++ dhd_bus_schedule_queue(dhd->bus, flowid, TRUE); /* from queue to flowring */ ++} ++ ++/** called when DHD needs to check for 'transmit complete' messages from the dongle */ ++bool BCMFASTPATH ++dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound) ++{ ++ bool more = TRUE; ++ uint n = 0; ++ msgbuf_ring_t *ring = &dhd->prot->d2hring_tx_cpln; ++ ++ /* Process all the messages - DTOH direction */ ++ while (!dhd_is_device_removed(dhd)) { ++ uint8 *msg_addr; ++ uint32 msg_len; ++ ++ if (dhd->hang_was_sent) { ++ more = FALSE; ++ break; ++ } ++ ++ /* Get the address of the next message to be read from ring */ ++ msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); ++ if (msg_addr == NULL) { ++ more = FALSE; ++ break; ++ } ++ ++ /* Prefetch data to populate the cache */ ++ OSL_PREFETCH(msg_addr); ++ ++ if (dhd_prot_process_msgtype(dhd, ring, msg_addr, msg_len) != BCME_OK) { ++ DHD_ERROR(("%s: process %s msg addr %p len %d\n", ++ __FUNCTION__, ring->name, msg_addr, msg_len)); ++ } ++ ++ /* Write to dngl rd ptr */ ++ dhd_prot_upd_read_idx(dhd, ring); ++ ++ /* After batch processing, check bound */ ++ n += msg_len / ring->item_len; ++ if (n >= bound) { ++ break; ++ } ++ } ++ ++ DHD_LB_DISPATCH_TX_COMPL(dhd); ++ ++ return more; ++} ++ ++int BCMFASTPATH ++dhd_prot_process_trapbuf(dhd_pub_t *dhd) ++{ ++ uint32 data; ++ dhd_dma_buf_t *trap_addr = &dhd->prot->fw_trap_buf; ++ ++ /* Interrupts can come in before this struct ++ * has been initialized. ++ */ ++ if (trap_addr->va == NULL) { ++ DHD_ERROR(("%s: trap_addr->va is NULL\n", __FUNCTION__)); ++ return 0; ++ } ++ ++ OSL_CACHE_INV((void *)trap_addr->va, sizeof(uint32)); ++ data = *(uint32 *)(trap_addr->va); ++ ++ if (data & D2H_DEV_FWHALT) { ++ DHD_ERROR(("Firmware trapped and trap_data is 0x%04x\n", data)); ++ if (data & D2H_DEV_EXT_TRAP_DATA) ++ { ++ if (dhd->extended_trap_data) { ++ OSL_CACHE_INV((void *)trap_addr->va, ++ BCMPCIE_EXT_TRAP_DATA_MAXLEN); ++ memcpy(dhd->extended_trap_data, (uint32 *)trap_addr->va, ++ BCMPCIE_EXT_TRAP_DATA_MAXLEN); ++ } ++ DHD_ERROR(("Extended trap data available\n")); ++ } ++ return data; ++ } ++ return 0; ++} ++ ++/** called when DHD needs to check for 'ioctl complete' messages from the dongle */ ++int BCMFASTPATH ++dhd_prot_process_ctrlbuf(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ msgbuf_ring_t *ring = &prot->d2hring_ctrl_cpln; ++ ++ /* Process all the messages - DTOH direction */ ++ while (!dhd_is_device_removed(dhd)) { ++ uint8 *msg_addr; ++ uint32 msg_len; ++ ++ if (dhd->hang_was_sent) { ++ break; ++ } ++ ++ /* Get the address of the next message to be read from ring */ ++ msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); ++ if (msg_addr == NULL) { ++ break; ++ } ++ ++ /* Prefetch data to populate the cache */ ++ OSL_PREFETCH(msg_addr); ++ if (dhd_prot_process_msgtype(dhd, ring, msg_addr, msg_len) != BCME_OK) { ++ DHD_ERROR(("%s: process %s msg addr %p len %d\n", ++ __FUNCTION__, ring->name, msg_addr, msg_len)); ++ } ++ ++ /* Write to dngl rd ptr */ ++ dhd_prot_upd_read_idx(dhd, ring); ++ } ++ ++ return 0; ++} ++ ++/** ++ * Consume messages out of the D2H ring. Ensure that the message's DMA to host ++ * memory has completed, before invoking the message handler via a table lookup ++ * of the cmn_msg_hdr::msg_type. ++ */ ++static int BCMFASTPATH ++dhd_prot_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8 *buf, uint32 len) ++{ ++ uint32 buf_len = len; ++ uint16 item_len; ++ uint8 msg_type; ++ cmn_msg_hdr_t *msg = NULL; ++ int ret = BCME_OK; ++ ++ ASSERT(ring); ++ item_len = ring->item_len; ++ if (item_len == 0) { ++ DHD_ERROR(("%s: ringidx %d, item_len %d buf_len %d \n", ++ __FUNCTION__, ring->idx, item_len, buf_len)); ++ return BCME_ERROR; ++ } ++ ++ while (buf_len > 0) { ++ if (dhd->hang_was_sent) { ++ ret = BCME_ERROR; ++ goto done; ++ } ++ ++ msg = (cmn_msg_hdr_t *)buf; ++ ++ /* Wait until DMA completes, then fetch msg_type */ ++ msg_type = dhd->prot->d2h_sync_cb(dhd, ring, msg, item_len); ++ ++ /* ++ * Update the curr_rd to the current index in the ring, from where ++ * the work item is fetched. This way if the fetched work item ++ * fails in LIVELOCK, we can print the exact read index in the ring ++ * that shows up the corrupted work item. ++ */ ++ if ((ring->curr_rd + 1) >= ring->max_items) { ++ ring->curr_rd = 0; ++ } else { ++ ring->curr_rd += 1; ++ } ++ ++ /* Prefetch data to populate the cache */ ++ OSL_PREFETCH(buf + item_len); ++ ++ DHD_INFO(("msg_type %d item_len %d buf_len %d\n", ++ msg_type, item_len, buf_len)); ++ ++ if (msg_type == MSG_TYPE_LOOPBACK) { ++ bcm_print_bytes("LPBK RESP: ", (uint8 *)msg, item_len); ++ DHD_ERROR((" MSG_TYPE_LOOPBACK, len %d\n", item_len)); ++ } ++ ++ ASSERT(msg_type < DHD_PROT_FUNCS); ++ if (msg_type >= DHD_PROT_FUNCS) { ++ DHD_ERROR(("%s: msg_type %d, item_len %d buf_len %d\n", ++ __FUNCTION__, msg_type, item_len, buf_len)); ++ ret = BCME_ERROR; ++ goto done; ++ } ++ ++ if (table_lookup[msg_type]) { ++ table_lookup[msg_type](dhd, buf); ++ } ++ ++ if (buf_len < item_len) { ++ ret = BCME_ERROR; ++ goto done; ++ } ++ buf_len = buf_len - item_len; ++ buf = buf + item_len; ++ } ++ ++done: ++ ++#ifdef DHD_RX_CHAINING ++ dhd_rxchain_commit(dhd); ++#endif ++ ++ return ret; ++} /* dhd_prot_process_msgtype */ ++ ++static void ++dhd_prot_noop(dhd_pub_t *dhd, void *msg) ++{ ++ return; ++} ++ ++/** called on MSG_TYPE_RING_STATUS message received from dongle */ ++static void ++dhd_prot_ringstatus_process(dhd_pub_t *dhd, void *msg) ++{ ++ pcie_ring_status_t *ring_status = (pcie_ring_status_t *) msg; ++ uint32 request_id = ltoh32(ring_status->cmn_hdr.request_id); ++ uint16 status = ltoh16(ring_status->compl_hdr.status); ++ uint16 ring_id = ltoh16(ring_status->compl_hdr.flow_ring_id); ++ ++ DHD_ERROR(("ring status: request_id %d, status 0x%04x, flow ring %d, write_idx %d \n", ++ request_id, status, ring_id, ltoh16(ring_status->write_idx))); ++ ++ if (ltoh16(ring_status->compl_hdr.ring_id) != BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT) ++ return; ++ if (status == BCMPCIE_BAD_PHASE) { ++ /* bad phase report from */ ++ DHD_ERROR(("Bad phase\n")); ++ } ++ if (status != BCMPCIE_BADOPTION) ++ return; ++ ++ if (request_id == DHD_H2D_DBGRING_REQ_PKTID) { ++ if (dhd->prot->h2dring_info_subn != NULL) { ++ if (dhd->prot->h2dring_info_subn->create_pending == TRUE) { ++ DHD_ERROR(("H2D ring create failed for info ring\n")); ++ dhd->prot->h2dring_info_subn->create_pending = FALSE; ++ } ++ else ++ DHD_ERROR(("ring create ID for a ring, create not pending\n")); ++ } else { ++ DHD_ERROR(("%s info submit ring doesn't exist\n", __FUNCTION__)); ++ } ++ } ++ else if (request_id == DHD_D2H_DBGRING_REQ_PKTID) { ++ if (dhd->prot->d2hring_info_cpln != NULL) { ++ if (dhd->prot->d2hring_info_cpln->create_pending == TRUE) { ++ DHD_ERROR(("D2H ring create failed for info ring\n")); ++ dhd->prot->d2hring_info_cpln->create_pending = FALSE; ++ } ++ else ++ DHD_ERROR(("ring create ID for info ring, create not pending\n")); ++ } else { ++ DHD_ERROR(("%s info cpl ring doesn't exist\n", __FUNCTION__)); ++ } ++ } ++ else { ++ DHD_ERROR(("don;t know how to pair with original request\n")); ++ } ++ /* How do we track this to pair it with ??? */ ++ return; ++} ++ ++/** called on MSG_TYPE_GEN_STATUS ('general status') message received from dongle */ ++static void ++dhd_prot_genstatus_process(dhd_pub_t *dhd, void *msg) ++{ ++ pcie_gen_status_t *gen_status = (pcie_gen_status_t *)msg; ++ DHD_ERROR(("ERROR: gen status: request_id %d, STATUS 0x%04x, flow ring %d \n", ++ gen_status->cmn_hdr.request_id, gen_status->compl_hdr.status, ++ gen_status->compl_hdr.flow_ring_id)); ++ ++ /* How do we track this to pair it with ??? */ ++ return; ++} ++ ++/** ++ * Called on MSG_TYPE_IOCTLPTR_REQ_ACK ('ioctl ack') message received from dongle, meaning that the ++ * dongle received the ioctl message in dongle memory. ++ */ ++static void ++dhd_prot_ioctack_process(dhd_pub_t *dhd, void *msg) ++{ ++ ioctl_req_ack_msg_t *ioct_ack = (ioctl_req_ack_msg_t *)msg; ++ unsigned long flags; ++#ifdef DHD_PKTID_AUDIT_RING ++ uint32 pktid = ltoh32(ioct_ack->cmn_hdr.request_id); ++ ++ /* Skip audit for ADHD_IOCTL_REQ_PKTID = 0xFFFE */ ++ if (pktid != DHD_IOCTL_REQ_PKTID) { ++#ifndef IOCTLRESP_USE_CONSTMEM ++ DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, pktid, ++ DHD_TEST_IS_ALLOC, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); ++#else ++ DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_map_handle_ioctl, pktid, ++ DHD_TEST_IS_ALLOC, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); ++#endif /* !IOCTLRESP_USE_CONSTMEM */ ++ } ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ if ((dhd->prot->ioctl_state & MSGBUF_IOCTL_ACK_PENDING) && ++ (dhd->prot->ioctl_state & MSGBUF_IOCTL_RESP_PENDING)) { ++ dhd->prot->ioctl_state &= ~MSGBUF_IOCTL_ACK_PENDING; ++ } else { ++ DHD_ERROR(("%s: received ioctl ACK with state %02x trans_id = %d\n", ++ __FUNCTION__, dhd->prot->ioctl_state, dhd->prot->ioctl_trans_id)); ++ prhex("dhd_prot_ioctack_process:", ++ (uchar *)msg, D2HRING_CTRL_CMPLT_ITEMSIZE); ++ } ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ DHD_CTL(("ioctl req ack: request_id %d, status 0x%04x, flow ring %d \n", ++ ioct_ack->cmn_hdr.request_id, ioct_ack->compl_hdr.status, ++ ioct_ack->compl_hdr.flow_ring_id)); ++ if (ioct_ack->compl_hdr.status != 0) { ++ DHD_ERROR(("got an error status for the ioctl request...need to handle that\n")); ++ } ++#ifdef REPORT_FATAL_TIMEOUTS ++ else { ++ dhd_stop_bus_timer(dhd); ++ } ++#endif /* REPORT_FATAL_TIMEOUTS */ ++} ++ ++/** called on MSG_TYPE_IOCTL_CMPLT message received from dongle */ ++static void ++dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void *msg) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ uint32 pkt_id, xt_id; ++ ioctl_comp_resp_msg_t *ioct_resp = (ioctl_comp_resp_msg_t *)msg; ++ void *pkt; ++ unsigned long flags; ++ dhd_dma_buf_t retbuf; ++#ifdef REPORT_FATAL_TIMEOUTS ++ uint16 dhd_xt_id; ++#endif ++ ++ memset(&retbuf, 0, sizeof(dhd_dma_buf_t)); ++ ++ pkt_id = ltoh32(ioct_resp->cmn_hdr.request_id); ++ ++#ifdef DHD_PKTID_AUDIT_RING ++#ifndef IOCTLRESP_USE_CONSTMEM ++ DHD_PKTID_AUDIT_RING_DEBUG(dhd, prot->pktid_ctrl_map, pkt_id, ++ DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); ++#else ++ DHD_PKTID_AUDIT_RING_DEBUG(dhd, prot->pktid_map_handle_ioctl, pkt_id, ++ DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); ++#endif /* !IOCTLRESP_USE_CONSTMEM */ ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ if ((prot->ioctl_state & MSGBUF_IOCTL_ACK_PENDING) || ++ !(prot->ioctl_state & MSGBUF_IOCTL_RESP_PENDING)) { ++ DHD_ERROR(("%s: received ioctl response with state %02x trans_id = %d\n", ++ __FUNCTION__, dhd->prot->ioctl_state, dhd->prot->ioctl_trans_id)); ++ prhex("dhd_prot_ioctcmplt_process:", ++ (uchar *)msg, D2HRING_CTRL_CMPLT_ITEMSIZE); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ return; ++ } ++ ++ /* Clear Response pending bit */ ++ prot->ioctl_state &= ~MSGBUF_IOCTL_RESP_PENDING; ++ ++#ifndef IOCTLRESP_USE_CONSTMEM ++ pkt = dhd_prot_packet_get(dhd, pkt_id, PKTTYPE_IOCTL_RX, TRUE); ++#else ++ dhd_prot_ioctl_ret_buffer_get(dhd, pkt_id, &retbuf); ++ pkt = retbuf.va; ++#endif /* !IOCTLRESP_USE_CONSTMEM */ ++ if (!pkt) { ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ DHD_ERROR(("%s: received ioctl response with NULL pkt\n", __FUNCTION__)); ++ prhex("dhd_prot_ioctcmplt_process:", ++ (uchar *)msg, D2HRING_CTRL_CMPLT_ITEMSIZE); ++ return; ++ } ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ prot->ioctl_resplen = ltoh16(ioct_resp->resp_len); ++ prot->ioctl_status = ltoh16(ioct_resp->compl_hdr.status); ++ xt_id = ltoh16(ioct_resp->trans_id); ++ ++ if (xt_id != prot->ioctl_trans_id || prot->curr_ioctl_cmd != ioct_resp->cmd) { ++ DHD_ERROR(("%s: transaction id(%d %d) or cmd(%d %d) mismatch\n", ++ __FUNCTION__, xt_id, prot->ioctl_trans_id, ++ prot->curr_ioctl_cmd, ioct_resp->cmd)); ++#ifdef REPORT_FATAL_TIMEOUTS ++ dhd_stop_cmd_timer(dhd); ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ dhd_wakeup_ioctl_event(dhd, IOCTL_RETURN_ON_ERROR); ++ dhd_prot_debug_info_print(dhd); ++#ifdef DHD_FW_COREDUMP ++ if (dhd->memdump_enabled) { ++ /* collect core dump */ ++ dhd->memdump_type = DUMP_TYPE_TRANS_ID_MISMATCH; ++ dhd_bus_mem_dump(dhd); ++ } ++#else ++ ASSERT(0); ++#endif /* DHD_FW_COREDUMP */ ++ dhd_schedule_reset(dhd); ++ goto exit; ++ } ++#ifdef REPORT_FATAL_TIMEOUTS ++ dhd_xt_id = dhd_get_request_id(dhd); ++ if (xt_id == dhd_xt_id) { ++ dhd_stop_cmd_timer(dhd); ++ } else { ++ DHD_ERROR(("%s: Cmd timer not stopped received xt_id %d stored xt_id %d", ++ __FUNCTION__, xt_id, dhd_xt_id)); ++ } ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ DHD_CTL(("IOCTL_COMPLETE: req_id %x transid %d status %x resplen %d\n", ++ pkt_id, xt_id, prot->ioctl_status, prot->ioctl_resplen)); ++ ++ if (prot->ioctl_resplen > 0) { ++#ifndef IOCTLRESP_USE_CONSTMEM ++ bcopy(PKTDATA(dhd->osh, pkt), prot->retbuf.va, prot->ioctl_resplen); ++#else ++ bcopy(pkt, prot->retbuf.va, prot->ioctl_resplen); ++#endif /* !IOCTLRESP_USE_CONSTMEM */ ++ } ++ ++ /* wake up any dhd_os_ioctl_resp_wait() */ ++ dhd_wakeup_ioctl_event(dhd, IOCTL_RETURN_ON_SUCCESS); ++ ++exit: ++#ifndef IOCTLRESP_USE_CONSTMEM ++ dhd_prot_packet_free(dhd, pkt, ++ PKTTYPE_IOCTL_RX, FALSE); ++#else ++ free_ioctl_return_buffer(dhd, &retbuf); ++#endif /* !IOCTLRESP_USE_CONSTMEM */ ++ ++ /* Post another ioctl buf to the device */ ++ if (prot->cur_ioctlresp_bufs_posted > 0) { ++ prot->cur_ioctlresp_bufs_posted--; ++ } ++ ++ dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd); ++} ++ ++/** called on MSG_TYPE_TX_STATUS message received from dongle */ ++static void BCMFASTPATH ++dhd_prot_txstatus_process(dhd_pub_t *dhd, void *msg) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ host_txbuf_cmpl_t * txstatus; ++ unsigned long flags; ++ uint32 pktid; ++ void *pkt; ++ dmaaddr_t pa; ++ uint32 len; ++ void *dmah; ++ void *secdma; ++ bool pkt_fate; ++#ifdef DEVICE_TX_STUCK_DETECT ++ flow_ring_node_t *flow_ring_node; ++ uint16 flowid; ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ ++ ++ txstatus = (host_txbuf_cmpl_t *)msg; ++#ifdef DEVICE_TX_STUCK_DETECT ++ flowid = txstatus->compl_hdr.flow_ring_id; ++ flow_ring_node = DHD_FLOW_RING(dhd, flowid); ++ /** ++ * Since we got a completion message on this flowid, ++ * update tx_cmpl time stamp ++ */ ++ flow_ring_node->tx_cmpl = OSL_SYSUPTIME(); ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ ++ /* locks required to protect circular buffer accesses */ ++ DHD_GENERAL_LOCK(dhd, flags); ++ pktid = ltoh32(txstatus->cmn_hdr.request_id); ++ pkt_fate = TRUE; ++ ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_tx_map, pktid, ++ DHD_DUPLICATE_FREE, msg, D2HRING_TXCMPLT_ITEMSIZE); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ DHD_INFO(("txstatus for pktid 0x%04x\n", pktid)); ++ if (prot->active_tx_count) { ++ prot->active_tx_count--; ++ ++ /* Release the Lock when no more tx packets are pending */ ++ if (prot->active_tx_count == 0) ++ DHD_TXFL_WAKE_UNLOCK(dhd); ++ } else { ++ DHD_ERROR(("Extra packets are freed\n")); ++ } ++ ++ ASSERT(pktid != 0); ++#if defined(DHD_LB_TXC) && !defined(BCM_SECURE_DMA) ++ { ++ int elem_ix; ++ void **elem; ++ bcm_workq_t *workq; ++ dmaaddr_t pa; ++ uint32 pa_len; ++ ++ pkt = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_tx_map, ++ pktid, pa, pa_len, dmah, secdma, PKTTYPE_DATA_TX); ++ ++ workq = &prot->tx_compl_prod; ++ /* ++ * Produce the packet into the tx_compl workq for the tx compl tasklet ++ * to consume. ++ */ ++ OSL_PREFETCH(PKTTAG(pkt)); ++ ++ /* fetch next available slot in workq */ ++ elem_ix = bcm_ring_prod(WORKQ_RING(workq), DHD_LB_WORKQ_SZ); ++ ++ DHD_PKTTAG_SET_PA((dhd_pkttag_fr_t *)PKTTAG(pkt), pa); ++ DHD_PKTTAG_SET_PA_LEN((dhd_pkttag_fr_t *)PKTTAG(pkt), pa_len); ++ ++ if (elem_ix == BCM_RING_FULL) { ++ DHD_ERROR(("tx_compl_prod BCM_RING_FULL\n")); ++ goto workq_ring_full; ++ } ++ ++ elem = WORKQ_ELEMENT(void *, &prot->tx_compl_prod, elem_ix); ++ *elem = pkt; ++ ++ smp_wmb(); ++ ++ /* Sync WR index to consumer if the SYNC threshold has been reached */ ++ if (++prot->tx_compl_prod_sync >= DHD_LB_WORKQ_SYNC) { ++ bcm_workq_prod_sync(workq); ++ prot->tx_compl_prod_sync = 0; ++ } ++ ++ DHD_INFO(("%s: tx_compl_prod pkt<%p> sync<%d>\n", ++ __FUNCTION__, pkt, prot->tx_compl_prod_sync)); ++ ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ return; ++ } ++ ++workq_ring_full: ++ ++#endif /* !DHD_LB_TXC */ ++ ++ pkt = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_tx_map, pktid, ++ pa, len, dmah, secdma, PKTTYPE_DATA_TX); ++ ++ if (pkt) { ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ int offset = 0; ++ BCM_REFERENCE(offset); ++ ++ if (dhd->prot->tx_metadata_offset) ++ offset = dhd->prot->tx_metadata_offset + ETHER_HDR_LEN; ++ SECURE_DMA_UNMAP(dhd->osh, (uint) pa, ++ (uint) dhd->prot->tx_metadata_offset, DMA_RX, 0, dmah, ++ secdma, offset); ++ } else ++ DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, dmah); ++#ifdef DMAMAP_STATS ++ dhd->dma_stats.txdata--; ++ dhd->dma_stats.txdata_sz -= len; ++#endif /* DMAMAP_STATS */ ++#if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING) ++ if (dhd->d11_tx_status) { ++ uint16 tx_status; ++ ++ tx_status = ltoh16(txstatus->compl_hdr.status) & ++ WLFC_CTL_PKTFLAG_MASK; ++ pkt_fate = (tx_status == WLFC_CTL_PKTFLAG_DISCARD) ? TRUE : FALSE; ++ ++ DHD_DBG_PKT_MON_TX_STATUS(dhd, pkt, pktid, tx_status); ++#ifdef DHD_PKT_LOGGING ++ DHD_PKTLOG_TXS(dhd, pkt, pktid, tx_status); ++#endif /* DHD_PKT_LOGGING */ ++ } ++#endif /* DBG_PKT_MON || DHD_PKT_LOGGING */ ++#if defined(BCMPCIE) ++ dhd_txcomplete(dhd, pkt, pkt_fate); ++#endif ++ ++#if DHD_DBG_SHOW_METADATA ++ if (dhd->prot->metadata_dbg && ++ dhd->prot->tx_metadata_offset && txstatus->metadata_len) { ++ uchar *ptr; ++ /* The Ethernet header of TX frame was copied and removed. ++ * Here, move the data pointer forward by Ethernet header size. ++ */ ++ PKTPULL(dhd->osh, pkt, ETHER_HDR_LEN); ++ ptr = PKTDATA(dhd->osh, pkt) - (dhd->prot->tx_metadata_offset); ++ bcm_print_bytes("txmetadata", ptr, txstatus->metadata_len); ++ dhd_prot_print_metadata(dhd, ptr, txstatus->metadata_len); ++ } ++#endif /* DHD_DBG_SHOW_METADATA */ ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ PKTFREE(dhd->osh, pkt, TRUE); ++ DHD_GENERAL_LOCK(dhd, flags); ++ DHD_FLOWRING_TXSTATUS_CNT_UPDATE(dhd->bus, txstatus->compl_hdr.flow_ring_id, ++ txstatus->tx_status); ++ ++#ifdef DHD_TIMESYNC ++ if (dhd->prot->tx_ts_log_enabled) { ++ ts_timestamp_t *ts = (ts_timestamp_t *)&(txstatus->ts); ++ dhd_timesync_log_tx_timestamp(dhd->ts, ++ txstatus->compl_hdr.flow_ring_id, ++ txstatus->cmn_hdr.if_id, ++ ts->low, ts->high); ++ } ++#endif /* DHD_TIMESYNC */ ++ } ++ ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ return; ++} /* dhd_prot_txstatus_process */ ++ ++/** called on MSG_TYPE_WL_EVENT message received from dongle */ ++static void ++dhd_prot_event_process(dhd_pub_t *dhd, void *msg) ++{ ++ wlevent_req_msg_t *evnt; ++ uint32 bufid; ++ uint16 buflen; ++ int ifidx = 0; ++ void* pkt; ++ unsigned long flags; ++ dhd_prot_t *prot = dhd->prot; ++ ++ /* Event complete header */ ++ evnt = (wlevent_req_msg_t *)msg; ++ bufid = ltoh32(evnt->cmn_hdr.request_id); ++ ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, bufid, ++ DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ buflen = ltoh16(evnt->event_data_len); ++ ++ ifidx = BCMMSGBUF_API_IFIDX(&evnt->cmn_hdr); ++ ++ /* Post another rxbuf to the device */ ++ if (prot->cur_event_bufs_posted) ++ prot->cur_event_bufs_posted--; ++ dhd_msgbuf_rxbuf_post_event_bufs(dhd); ++ ++ /* locks required to protect pktid_map */ ++ DHD_GENERAL_LOCK(dhd, flags); ++ pkt = dhd_prot_packet_get(dhd, bufid, PKTTYPE_EVENT_RX, TRUE); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ if (!pkt) { ++ DHD_ERROR(("%s: pkt is NULL for pktid %d\n", __FUNCTION__, bufid)); ++ return; ++ } ++ ++ /* DMA RX offset updated through shared area */ ++ if (dhd->prot->rx_dataoffset) ++ PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset); ++ ++ PKTSETLEN(dhd->osh, pkt, buflen); ++ ++ dhd_bus_rx_frame(dhd->bus, pkt, ifidx, 1); ++} ++ ++/** called on MSG_TYPE_INFO_BUF_CMPLT message received from dongle */ ++static void BCMFASTPATH ++dhd_prot_process_infobuf_complete(dhd_pub_t *dhd, void* buf) ++{ ++ info_buf_resp_t *resp; ++ uint32 pktid; ++ uint16 buflen; ++ void * pkt; ++ unsigned long flags; ++ ++ resp = (info_buf_resp_t *)buf; ++ pktid = ltoh32(resp->cmn_hdr.request_id); ++ buflen = ltoh16(resp->info_data_len); ++ ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, pktid, ++ DHD_DUPLICATE_FREE, buf, D2HRING_INFO_BUFCMPLT_ITEMSIZE); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ DHD_INFO(("id 0x%04x, len %d, phase 0x%02x, seqnum %d, rx_dataoffset %d\n", ++ pktid, buflen, resp->cmn_hdr.flags, ltoh16(resp->seqnum), ++ dhd->prot->rx_dataoffset)); ++ ++ if (!dhd->prot->infobufpost) { ++ DHD_ERROR(("infobuf posted are zero, but there is a completion\n")); ++ return; ++ } ++ ++ dhd->prot->infobufpost--; ++ dhd_prot_infobufpost(dhd); ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ pkt = dhd_prot_packet_get(dhd, pktid, PKTTYPE_INFO_RX, TRUE); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ if (!pkt) ++ return; ++ ++ /* DMA RX offset updated through shared area */ ++ if (dhd->prot->rx_dataoffset) ++ PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset); ++ ++ PKTSETLEN(dhd->osh, pkt, buflen); ++ ++ /* info ring "debug" data, which is not a 802.3 frame, is sent/hacked with a ++ * special ifidx of -1. This is just internal to dhd to get the data to ++ * dhd_linux.c:dhd_rx_frame() from here (dhd_prot_infobuf_cmplt_process). ++ */ ++ dhd_bus_rx_frame(dhd->bus, pkt, DHD_EVENT_IF /* ifidx HACK */, 1); ++} ++ ++/** Stop protocol: sync w/dongle state. */ ++void dhd_prot_stop(dhd_pub_t *dhd) ++{ ++ ASSERT(dhd); ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++} ++ ++/* Add any protocol-specific data header. ++ * Caller must reserve prot_hdrlen prepend space. ++ */ ++void BCMFASTPATH ++dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) ++{ ++ return; ++} ++ ++uint ++dhd_prot_hdrlen(dhd_pub_t *dhd, void *PKTBUF) ++{ ++ return 0; ++} ++ ++ ++#define PKTBUF pktbuf ++ ++/** ++ * Called when a tx ethernet packet has been dequeued from a flow queue, and has to be inserted in ++ * the corresponding flow ring. ++ */ ++int BCMFASTPATH ++dhd_prot_txdata(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) ++{ ++ unsigned long flags; ++ dhd_prot_t *prot = dhd->prot; ++ host_txbuf_post_t *txdesc = NULL; ++ dmaaddr_t pa, meta_pa; ++ uint8 *pktdata; ++ uint32 pktlen; ++ uint32 pktid; ++ uint8 prio; ++ uint16 flowid = 0; ++ uint16 alloced = 0; ++ uint16 headroom; ++ msgbuf_ring_t *ring; ++ flow_ring_table_t *flow_ring_table; ++ flow_ring_node_t *flow_ring_node; ++ ++ if (dhd->flow_ring_table == NULL) { ++ return BCME_NORESOURCE; ++ } ++ ++ flowid = DHD_PKT_GET_FLOWID(PKTBUF); ++ flow_ring_table = (flow_ring_table_t *)dhd->flow_ring_table; ++ flow_ring_node = (flow_ring_node_t *)&flow_ring_table[flowid]; ++ ++ ring = (msgbuf_ring_t *)flow_ring_node->prot_info; ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ /* Create a unique 32-bit packet id */ ++ pktid = DHD_NATIVE_TO_PKTID_RSV(dhd, dhd->prot->pktid_tx_map, ++ PKTBUF, PKTTYPE_DATA_TX); ++#if defined(DHD_PCIE_PKTID) ++ if (pktid == DHD_PKTID_INVALID) { ++ DHD_ERROR(("%s: Pktid pool depleted.\n", __FUNCTION__)); ++ /* ++ * If we return error here, the caller would queue the packet ++ * again. So we'll just free the skb allocated in DMA Zone. ++ * Since we have not freed the original SKB yet the caller would ++ * requeue the same. ++ */ ++ goto err_no_res_pktfree; ++ } ++#endif /* DHD_PCIE_PKTID */ ++ ++ /* Reserve space in the circular buffer */ ++ txdesc = (host_txbuf_post_t *) ++ dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); ++ if (txdesc == NULL) { ++ DHD_INFO(("%s:%d: HTOD Msgbuf Not available TxCount = %d\n", ++ __FUNCTION__, __LINE__, prot->active_tx_count)); ++ goto err_free_pktid; ++ } ++ ++#ifdef DBG_PKT_MON ++ DHD_DBG_PKT_MON_TX(dhd, PKTBUF, pktid); ++#endif /* DBG_PKT_MON */ ++#ifdef DHD_PKT_LOGGING ++ DHD_PKTLOG_TX(dhd, PKTBUF, pktid); ++#endif /* DHD_PKT_LOGGING */ ++ ++ ++ /* Extract the data pointer and length information */ ++ pktdata = PKTDATA(dhd->osh, PKTBUF); ++ pktlen = PKTLEN(dhd->osh, PKTBUF); ++ ++ /* Ethernet header: Copy before we cache flush packet using DMA_MAP */ ++ bcopy(pktdata, txdesc->txhdr, ETHER_HDR_LEN); ++ ++ /* Extract the ethernet header and adjust the data pointer and length */ ++ pktdata = PKTPULL(dhd->osh, PKTBUF, ETHER_HDR_LEN); ++ pktlen -= ETHER_HDR_LEN; ++ ++ /* Map the data pointer to a DMA-able address */ ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ int offset = 0; ++ BCM_REFERENCE(offset); ++ ++ if (prot->tx_metadata_offset) ++ offset = prot->tx_metadata_offset + ETHER_HDR_LEN; ++ ++ pa = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), pktlen, ++ DMA_TX, PKTBUF, 0, ring->dma_buf.secdma, offset); ++ } ++#ifndef BCM_SECURE_DMA ++ else ++ pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), pktlen, DMA_TX, PKTBUF, 0); ++#endif /* #ifndef BCM_SECURE_DMA */ ++ ++ if (PHYSADDRISZERO(pa)) { ++ DHD_ERROR(("%s: Something really bad, unless 0 is " ++ "a valid phyaddr for pa\n", __FUNCTION__)); ++ ASSERT(0); ++ goto err_rollback_idx; ++ } ++ ++#ifdef DMAMAP_STATS ++ dhd->dma_stats.txdata++; ++ dhd->dma_stats.txdata_sz += pktlen; ++#endif /* DMAMAP_STATS */ ++ /* No need to lock. Save the rest of the packet's metadata */ ++ DHD_NATIVE_TO_PKTID_SAVE(dhd, dhd->prot->pktid_tx_map, PKTBUF, pktid, ++ pa, pktlen, DMA_TX, NULL, ring->dma_buf.secdma, PKTTYPE_DATA_TX); ++ ++#ifdef TXP_FLUSH_NITEMS ++ if (ring->pend_items_count == 0) ++ ring->start_addr = (void *)txdesc; ++ ring->pend_items_count++; ++#endif ++ ++ /* Form the Tx descriptor message buffer */ ++ ++ /* Common message hdr */ ++ txdesc->cmn_hdr.msg_type = MSG_TYPE_TX_POST; ++ txdesc->cmn_hdr.if_id = ifidx; ++ txdesc->cmn_hdr.flags = ring->current_phase; ++ ++ txdesc->flags = BCMPCIE_PKT_FLAGS_FRAME_802_3; ++ prio = (uint8)PKTPRIO(PKTBUF); ++ ++ ++ txdesc->flags |= (prio & 0x7) << BCMPCIE_PKT_FLAGS_PRIO_SHIFT; ++ txdesc->seg_cnt = 1; ++ ++ txdesc->data_len = htol16((uint16) pktlen); ++ txdesc->data_buf_addr.high_addr = htol32(PHYSADDRHI(pa)); ++ txdesc->data_buf_addr.low_addr = htol32(PHYSADDRLO(pa)); ++ ++ /* Move data pointer to keep ether header in local PKTBUF for later reference */ ++ PKTPUSH(dhd->osh, PKTBUF, ETHER_HDR_LEN); ++ ++ /* Handle Tx metadata */ ++ headroom = (uint16)PKTHEADROOM(dhd->osh, PKTBUF); ++ if (prot->tx_metadata_offset && (headroom < prot->tx_metadata_offset)) ++ DHD_ERROR(("No headroom for Metadata tx %d %d\n", ++ prot->tx_metadata_offset, headroom)); ++ ++ if (prot->tx_metadata_offset && (headroom >= prot->tx_metadata_offset)) { ++ DHD_TRACE(("Metadata in tx %d\n", prot->tx_metadata_offset)); ++ ++ /* Adjust the data pointer to account for meta data in DMA_MAP */ ++ PKTPUSH(dhd->osh, PKTBUF, prot->tx_metadata_offset); ++ ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ meta_pa = SECURE_DMA_MAP_TXMETA(dhd->osh, PKTDATA(dhd->osh, PKTBUF), ++ prot->tx_metadata_offset + ETHER_HDR_LEN, DMA_RX, PKTBUF, ++ 0, ring->dma_buf.secdma); ++ } ++#ifndef BCM_SECURE_DMA ++ else ++ meta_pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), ++ prot->tx_metadata_offset, DMA_RX, PKTBUF, 0); ++#endif /* #ifndef BCM_SECURE_DMA */ ++ ++ if (PHYSADDRISZERO(meta_pa)) { ++ /* Unmap the data pointer to a DMA-able address */ ++ if (SECURE_DMA_ENAB(dhd->osh)) { ++ ++ int offset = 0; ++ BCM_REFERENCE(offset); ++ ++ if (prot->tx_metadata_offset) { ++ offset = prot->tx_metadata_offset + ETHER_HDR_LEN; ++ } ++ ++ SECURE_DMA_UNMAP(dhd->osh, pa, pktlen, ++ DMA_TX, 0, DHD_DMAH_NULL, ring->dma_buf.secdma, offset); ++ } ++#ifndef BCM_SECURE_DMA ++ else { ++ DMA_UNMAP(dhd->osh, pa, pktlen, DMA_TX, 0, DHD_DMAH_NULL); ++ } ++#endif /* #ifndef BCM_SECURE_DMA */ ++#ifdef TXP_FLUSH_NITEMS ++ /* update pend_items_count */ ++ ring->pend_items_count--; ++#endif /* TXP_FLUSH_NITEMS */ ++ ++ DHD_ERROR(("%s: Something really bad, unless 0 is " ++ "a valid phyaddr for meta_pa\n", __FUNCTION__)); ++ ASSERT(0); ++ goto err_rollback_idx; ++ } ++ ++ /* Adjust the data pointer back to original value */ ++ PKTPULL(dhd->osh, PKTBUF, prot->tx_metadata_offset); ++ ++ txdesc->metadata_buf_len = prot->tx_metadata_offset; ++ txdesc->metadata_buf_addr.high_addr = htol32(PHYSADDRHI(meta_pa)); ++ txdesc->metadata_buf_addr.low_addr = htol32(PHYSADDRLO(meta_pa)); ++ } else { ++ txdesc->metadata_buf_len = htol16(0); ++ txdesc->metadata_buf_addr.high_addr = 0; ++ txdesc->metadata_buf_addr.low_addr = 0; ++ } ++ ++#ifdef DHD_PKTID_AUDIT_RING ++ DHD_PKTID_AUDIT(dhd, prot->pktid_tx_map, pktid, DHD_DUPLICATE_ALLOC); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ txdesc->cmn_hdr.request_id = htol32(pktid); ++ ++ DHD_TRACE(("txpost: data_len %d, pktid 0x%04x\n", txdesc->data_len, ++ txdesc->cmn_hdr.request_id)); ++ ++ /* Update the write pointer in TCM & ring bell */ ++#ifdef TXP_FLUSH_NITEMS ++ /* Flush if we have either hit the txp_threshold or if this msg is */ ++ /* occupying the last slot in the flow_ring - before wrap around. */ ++ if ((ring->pend_items_count == prot->txp_threshold) || ++ ((uint8 *) txdesc == (uint8 *) DHD_RING_END_VA(ring))) { ++ dhd_prot_txdata_write_flush(dhd, flowid, TRUE); ++ } ++#else ++ /* update ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ring, txdesc, 1); ++#endif ++ ++ prot->active_tx_count++; ++ ++ /* ++ * Take a wake lock, do not sleep if we have atleast one packet ++ * to finish. ++ */ ++ if (prot->active_tx_count >= 1) ++ DHD_TXFL_WAKE_LOCK_TIMEOUT(dhd, MAX_TX_TIMEOUT); ++ ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return BCME_OK; ++ ++err_rollback_idx: ++ /* roll back write pointer for unprocessed message */ ++ if (ring->wr == 0) { ++ ring->wr = ring->max_items - 1; ++ } else { ++ ring->wr--; ++ if (ring->wr == 0) { ++ DHD_INFO(("%s: flipping the phase now\n", ring->name)); ++ ring->current_phase = ring->current_phase ? ++ 0 : BCMPCIE_CMNHDR_PHASE_BIT_INIT; ++ } ++ } ++ ++err_free_pktid: ++#if defined(DHD_PCIE_PKTID) ++ { ++ void *dmah; ++ void *secdma; ++ /* Free up the PKTID. physaddr and pktlen will be garbage. */ ++ DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_tx_map, pktid, ++ pa, pktlen, dmah, secdma, PKTTYPE_NO_CHECK); ++ } ++ ++err_no_res_pktfree: ++#endif /* DHD_PCIE_PKTID */ ++ ++ ++ ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return BCME_NORESOURCE; ++} /* dhd_prot_txdata */ ++ ++/* called with a lock */ ++/** optimization to write "n" tx items at a time to ring */ ++void BCMFASTPATH ++dhd_prot_txdata_write_flush(dhd_pub_t *dhd, uint16 flowid, bool in_lock) ++{ ++#ifdef TXP_FLUSH_NITEMS ++ unsigned long flags = 0; ++ flow_ring_table_t *flow_ring_table; ++ flow_ring_node_t *flow_ring_node; ++ msgbuf_ring_t *ring; ++ ++ if (dhd->flow_ring_table == NULL) { ++ return; ++ } ++ ++ if (!in_lock) { ++ DHD_GENERAL_LOCK(dhd, flags); ++ } ++ ++ flow_ring_table = (flow_ring_table_t *)dhd->flow_ring_table; ++ flow_ring_node = (flow_ring_node_t *)&flow_ring_table[flowid]; ++ ring = (msgbuf_ring_t *)flow_ring_node->prot_info; ++ ++ if (ring->pend_items_count) { ++ /* update ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ring, ring->start_addr, ++ ring->pend_items_count); ++ ring->pend_items_count = 0; ++ ring->start_addr = NULL; ++ } ++ ++ if (!in_lock) { ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ } ++#endif /* TXP_FLUSH_NITEMS */ ++} ++ ++#undef PKTBUF /* Only defined in the above routine */ ++ ++int BCMFASTPATH ++dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pkt, uchar *buf, uint *len) ++{ ++ return 0; ++} ++ ++/** post a set of receive buffers to the dongle */ ++static void BCMFASTPATH ++dhd_prot_return_rxbuf(dhd_pub_t *dhd, uint32 pktid, uint32 rxcnt) ++{ ++ dhd_prot_t *prot = dhd->prot; ++#if defined(DHD_LB_RXC) ++ int elem_ix; ++ uint32 *elem; ++ bcm_workq_t *workq; ++ ++ workq = &prot->rx_compl_prod; ++ ++ /* Produce the work item */ ++ elem_ix = bcm_ring_prod(WORKQ_RING(workq), DHD_LB_WORKQ_SZ); ++ if (elem_ix == BCM_RING_FULL) { ++ DHD_ERROR(("%s LB RxCompl workQ is full\n", __FUNCTION__)); ++ ASSERT(0); ++ return; ++ } ++ ++ elem = WORKQ_ELEMENT(uint32, workq, elem_ix); ++ *elem = pktid; ++ ++ smp_wmb(); ++ ++ /* Sync WR index to consumer if the SYNC threshold has been reached */ ++ if (++prot->rx_compl_prod_sync >= DHD_LB_WORKQ_SYNC) { ++ bcm_workq_prod_sync(workq); ++ prot->rx_compl_prod_sync = 0; ++ } ++ ++ DHD_INFO(("%s: rx_compl_prod pktid<%u> sync<%d>\n", ++ __FUNCTION__, pktid, prot->rx_compl_prod_sync)); ++ ++#endif /* DHD_LB_RXC */ ++ ++ if (prot->rxbufpost >= rxcnt) { ++ prot->rxbufpost -= (uint16)rxcnt; ++ } else { ++ /* ASSERT(0); */ ++ prot->rxbufpost = 0; ++ } ++ ++#if !defined(DHD_LB_RXC) ++ if (prot->rxbufpost <= (prot->max_rxbufpost - RXBUFPOST_THRESHOLD)) ++ dhd_msgbuf_rxbuf_post(dhd, FALSE); /* alloc pkt ids */ ++#endif /* !DHD_LB_RXC */ ++ return; ++} ++ ++/* called before an ioctl is sent to the dongle */ ++static void ++dhd_prot_wlioctl_intercept(dhd_pub_t *dhd, wl_ioctl_t * ioc, void * buf) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ ++ if (ioc->cmd == WLC_SET_VAR && buf != NULL && !strcmp(buf, "pcie_bus_tput")) { ++ int slen = 0; ++ pcie_bus_tput_params_t *tput_params; ++ ++ slen = strlen("pcie_bus_tput") + 1; ++ tput_params = (pcie_bus_tput_params_t*)((char *)buf + slen); ++ bcopy(&prot->host_bus_throughput_buf.pa, &tput_params->host_buf_addr, ++ sizeof(tput_params->host_buf_addr)); ++ tput_params->host_buf_len = DHD_BUS_TPUT_BUF_LEN; ++ } ++} ++ ++ ++/** Use protocol to issue ioctl to dongle. Only one ioctl may be in transit. */ ++int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) ++{ ++ int ret = -1; ++ uint8 action; ++ ++ if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { ++ DHD_ERROR(("%s : bus is down. we have nothing to do - bs: %d, has: %d\n", ++ __FUNCTION__, dhd->busstate, dhd->hang_was_sent)); ++ goto done; ++ } ++ ++ if (dhd->busstate == DHD_BUS_SUSPEND) { ++ DHD_ERROR(("%s : bus is suspended\n", __FUNCTION__)); ++ goto done; ++ } ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (ioc->cmd == WLC_SET_PM) { ++ DHD_TRACE_HW4(("%s: SET PM to %d\n", __FUNCTION__, buf ? *(char *)buf : 0)); ++ } ++ ++ ASSERT(len <= WLC_IOCTL_MAXLEN); ++ ++ if (len > WLC_IOCTL_MAXLEN) ++ goto done; ++ ++ action = ioc->set; ++ ++ dhd_prot_wlioctl_intercept(dhd, ioc, buf); ++ ++ if (action & WL_IOCTL_ACTION_SET) { ++ ret = dhd_msgbuf_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); ++ } else { ++ ret = dhd_msgbuf_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); ++ if (ret > 0) ++ ioc->used = ret; ++ } ++ ++ /* Too many programs assume ioctl() returns 0 on success */ ++ if (ret >= 0) { ++ ret = 0; ++ } else { ++ DHD_INFO(("%s: status ret value is %d \n", __FUNCTION__, ret)); ++ dhd->dongle_error = ret; ++ } ++ ++ if (!ret && ioc->cmd == WLC_SET_VAR && buf != NULL) { ++ /* Intercept the wme_dp ioctl here */ ++ if (!strcmp(buf, "wme_dp")) { ++ int slen, val = 0; ++ ++ slen = strlen("wme_dp") + 1; ++ if (len >= (int)(slen + sizeof(int))) ++ bcopy(((char *)buf + slen), &val, sizeof(int)); ++ dhd->wme_dp = (uint8) ltoh32(val); ++ } ++ ++ } ++ ++done: ++ return ret; ++ ++} /* dhd_prot_ioctl */ ++ ++/** test / loopback */ ++ ++int ++dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len) ++{ ++ unsigned long flags; ++ dhd_prot_t *prot = dhd->prot; ++ uint16 alloced = 0; ++ ++ ioct_reqst_hdr_t *ioct_rqst; ++ ++ uint16 hdrlen = sizeof(ioct_reqst_hdr_t); ++ uint16 msglen = len + hdrlen; ++ msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; ++ ++ msglen = ALIGN_SIZE(msglen, DMA_ALIGN_LEN); ++ msglen = LIMIT_TO_MAX(msglen, MSGBUF_MAX_MSG_SIZE); ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ ioct_rqst = (ioct_reqst_hdr_t *) ++ dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); ++ ++ if (ioct_rqst == NULL) { ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return 0; ++ } ++ ++ { ++ uint8 *ptr; ++ uint16 i; ++ ++ ptr = (uint8 *)ioct_rqst; ++ for (i = 0; i < msglen; i++) { ++ ptr[i] = i % 256; ++ } ++ } ++ ++ /* Common msg buf hdr */ ++ ioct_rqst->msg.epoch = ring->seqnum % H2D_EPOCH_MODULO; ++ ring->seqnum++; ++ ++ ioct_rqst->msg.msg_type = MSG_TYPE_LOOPBACK; ++ ioct_rqst->msg.if_id = 0; ++ ioct_rqst->msg.flags = ring->current_phase; ++ ++ bcm_print_bytes("LPBK REQ: ", (uint8 *)ioct_rqst, msglen); ++ ++ /* update ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ring, ioct_rqst, 1); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return 0; ++} ++ ++/** test / loopback */ ++void dmaxfer_free_dmaaddr(dhd_pub_t *dhd, dhd_dmaxfer_t *dmaxfer) ++{ ++ if (dmaxfer == NULL) ++ return; ++ ++ dhd_dma_buf_free(dhd, &dmaxfer->srcmem); ++ dhd_dma_buf_free(dhd, &dmaxfer->dstmem); ++} ++ ++/** test / loopback */ ++int ++dhd_prepare_schedule_dmaxfer_free(dhd_pub_t *dhdp) ++{ ++ dhd_prot_t *prot = dhdp->prot; ++ dhd_dmaxfer_t *dmaxfer = &prot->dmaxfer; ++ dmaxref_mem_map_t *dmap = NULL; ++ ++ dmap = MALLOCZ(dhdp->osh, sizeof(dmaxref_mem_map_t)); ++ if (!dmap) { ++ DHD_ERROR(("%s: dmap alloc failed\n", __FUNCTION__)); ++ goto mem_alloc_fail; ++ } ++ dmap->srcmem = &(dmaxfer->srcmem); ++ dmap->dstmem = &(dmaxfer->dstmem); ++ ++ DMAXFER_FREE(dhdp, dmap); ++ return BCME_OK; ++ ++mem_alloc_fail: ++ if (dmap) { ++ MFREE(dhdp->osh, dmap, sizeof(dmaxref_mem_map_t)); ++ dmap = NULL; ++ } ++ return BCME_NOMEM; ++} /* dhd_prepare_schedule_dmaxfer_free */ ++ ++ ++/** test / loopback */ ++void ++dmaxfer_free_prev_dmaaddr(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap) ++{ ++ ++ dhd_dma_buf_free(dhdp, dmmap->srcmem); ++ dhd_dma_buf_free(dhdp, dmmap->dstmem); ++ ++ MFREE(dhdp->osh, dmmap, sizeof(dmaxref_mem_map_t)); ++ dmmap = NULL; ++ ++} /* dmaxfer_free_prev_dmaaddr */ ++ ++ ++/** test / loopback */ ++int dmaxfer_prepare_dmaaddr(dhd_pub_t *dhd, uint len, ++ uint srcdelay, uint destdelay, dhd_dmaxfer_t *dmaxfer) ++{ ++ uint i; ++ if (!dmaxfer) ++ return BCME_ERROR; ++ ++ /* First free up existing buffers */ ++ dmaxfer_free_dmaaddr(dhd, dmaxfer); ++ ++ if (dhd_dma_buf_alloc(dhd, &dmaxfer->srcmem, len)) { ++ return BCME_NOMEM; ++ } ++ ++ if (dhd_dma_buf_alloc(dhd, &dmaxfer->dstmem, len + 8)) { ++ dhd_dma_buf_free(dhd, &dmaxfer->srcmem); ++ return BCME_NOMEM; ++ } ++ ++ dmaxfer->len = len; ++ ++ /* Populate source with a pattern */ ++ for (i = 0; i < dmaxfer->len; i++) { ++ ((uint8*)dmaxfer->srcmem.va)[i] = i % 256; ++ } ++ OSL_CACHE_FLUSH(dmaxfer->srcmem.va, dmaxfer->len); ++ ++ dmaxfer->srcdelay = srcdelay; ++ dmaxfer->destdelay = destdelay; ++ ++ return BCME_OK; ++} /* dmaxfer_prepare_dmaaddr */ ++ ++static void ++dhd_msgbuf_dmaxfer_process(dhd_pub_t *dhd, void *msg) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ uint64 end_usec; ++ pcie_dmaxfer_cmplt_t *cmplt = (pcie_dmaxfer_cmplt_t *)msg; ++ ++ BCM_REFERENCE(cmplt); ++ DHD_INFO(("DMA status: %d\n", cmplt->compl_hdr.status)); ++ OSL_CACHE_INV(prot->dmaxfer.dstmem.va, prot->dmaxfer.len); ++ if (prot->dmaxfer.srcmem.va && prot->dmaxfer.dstmem.va) { ++ if (memcmp(prot->dmaxfer.srcmem.va, ++ prot->dmaxfer.dstmem.va, prot->dmaxfer.len)) { ++ prhex("XFER SRC: ", ++ prot->dmaxfer.srcmem.va, prot->dmaxfer.len); ++ prhex("XFER DST: ", ++ prot->dmaxfer.dstmem.va, prot->dmaxfer.len); ++ DHD_ERROR(("DMA failed\n")); ++ } ++ else { ++ if (prot->dmaxfer.d11_lpbk) { ++ DHD_ERROR(("DMA successful with d11 loopback\n")); ++ } else { ++ DHD_ERROR(("DMA successful without d11 loopback\n")); ++ } ++ } ++ } ++ end_usec = OSL_SYSUPTIME_US(); ++ dhd_prepare_schedule_dmaxfer_free(dhd); ++ end_usec -= prot->dmaxfer.start_usec; ++ DHD_ERROR(("DMA loopback %d bytes in %llu usec, %u kBps\n", ++ prot->dmaxfer.len, end_usec, ++ (prot->dmaxfer.len * (1000 * 1000 / 1024) / (uint32)(end_usec + 1)))); ++ dhd->prot->dmaxfer.in_progress = FALSE; ++} ++ ++/** Test functionality. ++ * Transfers bytes from host to dongle and to host again using DMA ++ * This function is not reentrant, as prot->dmaxfer.in_progress is not protected ++ * by a spinlock. ++ */ ++int ++dhdmsgbuf_dmaxfer_req(dhd_pub_t *dhd, uint len, uint srcdelay, uint destdelay, uint d11_lpbk) ++{ ++ unsigned long flags; ++ int ret = BCME_OK; ++ dhd_prot_t *prot = dhd->prot; ++ pcie_dma_xfer_params_t *dmap; ++ uint32 xferlen = LIMIT_TO_MAX(len, DMA_XFER_LEN_LIMIT); ++ uint16 alloced = 0; ++ msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; ++ ++ if (prot->dmaxfer.in_progress) { ++ DHD_ERROR(("DMA is in progress...\n")); ++ return ret; ++ } ++ ++ prot->dmaxfer.in_progress = TRUE; ++ if ((ret = dmaxfer_prepare_dmaaddr(dhd, xferlen, srcdelay, destdelay, ++ &prot->dmaxfer)) != BCME_OK) { ++ prot->dmaxfer.in_progress = FALSE; ++ return ret; ++ } ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ dmap = (pcie_dma_xfer_params_t *) ++ dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); ++ ++ if (dmap == NULL) { ++ dmaxfer_free_dmaaddr(dhd, &prot->dmaxfer); ++ prot->dmaxfer.in_progress = FALSE; ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return BCME_NOMEM; ++ } ++ ++ /* Common msg buf hdr */ ++ dmap->cmn_hdr.msg_type = MSG_TYPE_LPBK_DMAXFER; ++ dmap->cmn_hdr.request_id = htol32(DHD_FAKE_PKTID); ++ dmap->cmn_hdr.epoch = ring->seqnum % H2D_EPOCH_MODULO; ++ dmap->cmn_hdr.flags = ring->current_phase; ++ ring->seqnum++; ++ ++ dmap->host_input_buf_addr.high = htol32(PHYSADDRHI(prot->dmaxfer.srcmem.pa)); ++ dmap->host_input_buf_addr.low = htol32(PHYSADDRLO(prot->dmaxfer.srcmem.pa)); ++ dmap->host_ouput_buf_addr.high = htol32(PHYSADDRHI(prot->dmaxfer.dstmem.pa)); ++ dmap->host_ouput_buf_addr.low = htol32(PHYSADDRLO(prot->dmaxfer.dstmem.pa)); ++ dmap->xfer_len = htol32(prot->dmaxfer.len); ++ dmap->srcdelay = htol32(prot->dmaxfer.srcdelay); ++ dmap->destdelay = htol32(prot->dmaxfer.destdelay); ++ prot->dmaxfer.d11_lpbk = d11_lpbk ? 1 : 0; ++ dmap->flags = (prot->dmaxfer.d11_lpbk << PCIE_DMA_XFER_FLG_D11_LPBK_SHIFT) ++ & PCIE_DMA_XFER_FLG_D11_LPBK_MASK; ++ ++ /* update ring's WR index and ring doorbell to dongle */ ++ prot->dmaxfer.start_usec = OSL_SYSUPTIME_US(); ++ dhd_prot_ring_write_complete(dhd, ring, dmap, 1); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ DHD_INFO(("DMA Started...\n")); ++ ++ return BCME_OK; ++} /* dhdmsgbuf_dmaxfer_req */ ++ ++/** Called in the process of submitting an ioctl to the dongle */ ++static int ++dhd_msgbuf_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) ++{ ++ int ret = 0; ++ uint copylen = 0; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (cmd == WLC_GET_VAR && buf) ++ { ++ if (!len || !*(uint8 *)buf) { ++ DHD_ERROR(("%s(): Zero length bailing\n", __FUNCTION__)); ++ ret = BCME_BADARG; ++ goto done; ++ } ++ ++ /* Respond "bcmerror" and "bcmerrorstr" with local cache */ ++ copylen = MIN(len, BCME_STRLEN); ++ ++ if ((len >= strlen("bcmerrorstr")) && ++ (!strcmp((char *)buf, "bcmerrorstr"))) { ++ ++ strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), copylen); ++ *(uint8 *)((uint8 *)buf + (copylen - 1)) = '\0'; ++ ++ goto done; ++ } else if ((len >= strlen("bcmerror")) && ++ !strcmp((char *)buf, "bcmerror")) { ++ ++ *(uint32 *)(uint32 *)buf = dhd->dongle_error; ++ ++ goto done; ++ } ++ } ++ ++ ++ DHD_CTL(("query_ioctl: ACTION %d ifdix %d cmd %d len %d \n", ++ action, ifidx, cmd, len)); ++#ifdef REPORT_FATAL_TIMEOUTS ++ /* ++ * These timers "should" be started before sending H2D interrupt. ++ * Think of the scenario where H2D interrupt is fired and the Dongle ++ * responds back immediately. From the DPC we would stop the cmd, bus ++ * timers. But the process context could have switched out leading to ++ * a situation where the timers are Not started yet, but are actually stopped. ++ * ++ * Disable preemption from the time we start the timer until we are done ++ * with seding H2D interrupts. ++ */ ++ OSL_DISABLE_PREEMPTION(dhd->osh); ++ dhd_set_request_id(dhd, dhd->prot->ioctl_trans_id+1, cmd); ++ dhd_start_cmd_timer(dhd); ++ dhd_start_bus_timer(dhd); ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++ ret = dhd_fillup_ioct_reqst(dhd, (uint16)len, cmd, buf, ifidx); ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++ /* For some reason if we fail to ring door bell, stop the timers */ ++ if (ret < 0) { ++ DHD_ERROR(("%s(): dhd_fillup_ioct_reqst failed \r\n", __FUNCTION__)); ++ dhd_stop_cmd_timer(dhd); ++ dhd_stop_bus_timer(dhd); ++ OSL_ENABLE_PREEMPTION(dhd->osh); ++ goto done; ++ } ++ OSL_ENABLE_PREEMPTION(dhd->osh); ++#else ++ if (ret < 0) { ++ DHD_ERROR(("%s(): dhd_fillup_ioct_reqst failed \r\n", __FUNCTION__)); ++ goto done; ++ } ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++ /* wait for IOCTL completion message from dongle and get first fragment */ ++ ret = dhd_msgbuf_wait_ioctl_cmplt(dhd, len, buf); ++ ++done: ++ return ret; ++} ++ ++/** ++ * Waits for IOCTL completion message from the dongle, copies this into caller ++ * provided parameter 'buf'. ++ */ ++static int ++dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ int timeleft; ++ unsigned long flags; ++ int ret = 0; ++ static uint cnt = 0; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (dhd_query_bus_erros(dhd)) { ++ ret = -EIO; ++ goto out; ++ } ++ ++ timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received); ++ ++#ifdef DHD_RECOVER_TIMEOUT ++ if (prot->ioctl_received == 0) { ++ uint32 intstatus = 0; ++ uint32 intmask = 0; ++ intstatus = si_corereg(dhd->bus->sih, ++ dhd->bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); ++ intmask = si_corereg(dhd->bus->sih, ++ dhd->bus->sih->buscoreidx, PCIMailBoxMask, 0, 0); ++ if ((intstatus) && (!intmask) && (timeleft == 0) && (!dhd_query_bus_erros(dhd))) ++ { ++ DHD_ERROR(("%s: iovar timeout trying again intstatus=%x intmask=%x\n", ++ __FUNCTION__, intstatus, intmask)); ++ DHD_ERROR(("\n ------- DUMPING INTR enable/disable counters\r\n")); ++ DHD_ERROR(("resume_intr_enable_count=%lu dpc_intr_enable_count=%lu\n" ++ "isr_intr_disable_count=%lu suspend_intr_disable_count=%lu\n" ++ "dpc_return_busdown_count=%lu\n", ++ dhd->bus->resume_intr_enable_count, dhd->bus->dpc_intr_enable_count, ++ dhd->bus->isr_intr_disable_count, ++ dhd->bus->suspend_intr_disable_count, ++ dhd->bus->dpc_return_busdown_count)); ++ ++ dhd_prot_process_ctrlbuf(dhd); ++ ++ timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received); ++ /* Enable Back Interrupts using IntMask */ ++ dhdpcie_bus_intr_enable(dhd->bus); ++ } ++ } ++#endif /* DHD_RECOVER_TIMEOUT */ ++ ++ if (dhd->conf->ctrl_resched > 0 && timeleft == 0 && (!dhd_query_bus_erros(dhd))) { ++ cnt++; ++ if (cnt <= dhd->conf->ctrl_resched) { ++ uint32 intstatus = 0, intmask = 0; ++ intstatus = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); ++ intmask = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCIMailBoxMask, 0, 0); ++ if (intstatus) { ++ DHD_ERROR(("%s: reschedule dhd_dpc, cnt=%d, intstatus=0x%x, intmask=0x%x\n", ++ __FUNCTION__, cnt, intstatus, intmask)); ++ dhd->bus->intstatus = intstatus; ++ dhd->bus->ipend = TRUE; ++ dhd->bus->dpc_sched = TRUE; ++ dhd_sched_dpc(dhd); ++ timeleft = dhd_os_ioctl_resp_wait(dhd, &prot->ioctl_received); ++ } ++ } ++ } else { ++ cnt = 0; ++ } ++ ++ if (timeleft == 0 && (!dhd_query_bus_erros(dhd))) { ++ uint32 intstatus; ++ ++ dhd->rxcnt_timeout++; ++ dhd->rx_ctlerrs++; ++ dhd->iovar_timeout_occured = TRUE; ++ DHD_ERROR(("%s: resumed on timeout rxcnt_timeout %d ioctl_cmd %d " ++ "trans_id %d state %d busstate=%d ioctl_received=%d\n", ++ __FUNCTION__, dhd->rxcnt_timeout, prot->curr_ioctl_cmd, ++ prot->ioctl_trans_id, prot->ioctl_state, ++ dhd->busstate, prot->ioctl_received)); ++ if (prot->curr_ioctl_cmd == WLC_SET_VAR || ++ prot->curr_ioctl_cmd == WLC_GET_VAR) { ++ char iovbuf[32]; ++ int i; ++ int dump_size = 128; ++ uint8 *ioctl_buf = (uint8 *)prot->ioctbuf.va; ++ memset(iovbuf, 0, sizeof(iovbuf)); ++ strncpy(iovbuf, ioctl_buf, sizeof(iovbuf) - 1); ++ iovbuf[sizeof(iovbuf) - 1] = '\0'; ++ DHD_ERROR(("Current IOVAR (%s): %s\n", ++ prot->curr_ioctl_cmd == WLC_SET_VAR ? ++ "WLC_SET_VAR" : "WLC_GET_VAR", iovbuf)); ++ DHD_ERROR(("========== START IOCTL REQBUF DUMP ==========\n")); ++ for (i = 0; i < dump_size; i++) { ++ DHD_ERROR(("%02X ", ioctl_buf[i])); ++ if ((i % 32) == 31) { ++ DHD_ERROR(("\n")); ++ } ++ } ++ DHD_ERROR(("\n========== END IOCTL REQBUF DUMP ==========\n")); ++ } ++ ++ /* Check the PCIe link status by reading intstatus register */ ++ intstatus = si_corereg(dhd->bus->sih, ++ dhd->bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); ++ if (intstatus == (uint32)-1) { ++ DHD_ERROR(("%s : PCIe link might be down\n", __FUNCTION__)); ++ dhd->bus->is_linkdown = TRUE; ++ } ++ ++ dhd_bus_dump_console_buffer(dhd->bus); ++ dhd_prot_debug_info_print(dhd); ++ ++#ifdef DHD_FW_COREDUMP ++ /* Collect socram dump */ ++ if (dhd->memdump_enabled) { ++ /* collect core dump */ ++ dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT; ++ dhd_bus_mem_dump(dhd); ++ } ++#endif /* DHD_FW_COREDUMP */ ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++#ifdef CONFIG_ARCH_MSM ++ dhd->bus->no_cfg_restore = 1; ++#endif /* CONFIG_ARCH_MSM */ ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ ret = -ETIMEDOUT; ++ goto out; ++ } else { ++ if (prot->ioctl_received != IOCTL_RETURN_ON_SUCCESS) { ++ DHD_ERROR(("%s: IOCTL failure due to ioctl_received = %d\n", ++ __FUNCTION__, prot->ioctl_received)); ++ ret = -EINVAL; ++ goto out; ++ } ++ dhd->rxcnt_timeout = 0; ++ dhd->rx_ctlpkts++; ++ DHD_CTL(("%s: ioctl resp resumed, got %d\n", ++ __FUNCTION__, prot->ioctl_resplen)); ++ } ++ ++ if (dhd->prot->ioctl_resplen > len) ++ dhd->prot->ioctl_resplen = (uint16)len; ++ if (buf) ++ bcopy(dhd->prot->retbuf.va, buf, dhd->prot->ioctl_resplen); ++ ++ ret = (int)(dhd->prot->ioctl_status); ++ ++out: ++ DHD_GENERAL_LOCK(dhd, flags); ++ dhd->prot->ioctl_state = 0; ++ dhd->prot->ioctl_resplen = 0; ++ dhd->prot->ioctl_received = IOCTL_WAIT; ++ dhd->prot->curr_ioctl_cmd = 0; ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ return ret; ++} /* dhd_msgbuf_wait_ioctl_cmplt */ ++ ++static int ++dhd_msgbuf_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) ++{ ++ int ret = 0; ++ ++ DHD_TRACE(("%s: Enter \n", __FUNCTION__)); ++ ++ if (dhd->busstate == DHD_BUS_DOWN) { ++ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); ++ return -EIO; ++ } ++ ++ /* don't talk to the dongle if fw is about to be reloaded */ ++ if (dhd->hang_was_sent) { ++ DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n", ++ __FUNCTION__)); ++ return -EIO; ++ } ++ ++ DHD_CTL(("ACTION %d ifdix %d cmd %d len %d \n", ++ action, ifidx, cmd, len)); ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++ /* ++ * These timers "should" be started before sending H2D interrupt. ++ * Think of the scenario where H2D interrupt is fired and the Dongle ++ * responds back immediately. From the DPC we would stop the cmd, bus ++ * timers. But the process context could have switched out leading to ++ * a situation where the timers are Not started yet, but are actually stopped. ++ * ++ * Disable preemption from the time we start the timer until we are done ++ * with seding H2D interrupts. ++ */ ++ OSL_DISABLE_PREEMPTION(dhd->osh); ++ dhd_set_request_id(dhd, dhd->prot->ioctl_trans_id+1, cmd); ++ dhd_start_cmd_timer(dhd); ++ dhd_start_bus_timer(dhd); ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++ /* Fill up msgbuf for ioctl req */ ++ ret = dhd_fillup_ioct_reqst(dhd, (uint16)len, cmd, buf, ifidx); ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++ /* For some reason if we fail to ring door bell, stop the timers */ ++ if (ret < 0) { ++ DHD_ERROR(("%s(): dhd_fillup_ioct_reqst failed \r\n", __FUNCTION__)); ++ dhd_stop_cmd_timer(dhd); ++ dhd_stop_bus_timer(dhd); ++ OSL_ENABLE_PREEMPTION(dhd->osh); ++ goto done; ++ } ++ ++ OSL_ENABLE_PREEMPTION(dhd->osh); ++#else ++ if (ret < 0) { ++ DHD_ERROR(("%s(): dhd_fillup_ioct_reqst failed \r\n", __FUNCTION__)); ++ goto done; ++ } ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++ ret = dhd_msgbuf_wait_ioctl_cmplt(dhd, len, buf); ++ ++done: ++ return ret; ++} ++ ++/** Called by upper DHD layer. Handles a protocol control response asynchronously. */ ++int dhd_prot_ctl_complete(dhd_pub_t *dhd) ++{ ++ return 0; ++} ++ ++/** Called by upper DHD layer. Check for and handle local prot-specific iovar commands */ ++int dhd_prot_iovar_op(dhd_pub_t *dhd, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ return BCME_UNSUPPORTED; ++} ++ ++/** Add prot dump output to a buffer */ ++void dhd_prot_dump(dhd_pub_t *dhd, struct bcmstrbuf *b) ++{ ++ ++ if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM) ++ bcm_bprintf(b, "\nd2h_sync: SEQNUM:"); ++ else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM) ++ bcm_bprintf(b, "\nd2h_sync: XORCSUM:"); ++ else ++ bcm_bprintf(b, "\nd2h_sync: NONE:"); ++ bcm_bprintf(b, " d2h_sync_wait max<%lu> tot<%lu>\n", ++ dhd->prot->d2h_sync_wait_max, dhd->prot->d2h_sync_wait_tot); ++ ++ bcm_bprintf(b, "\nDongle DMA Indices: h2d %d d2h %d index size %d bytes\n", ++ dhd->dma_h2d_ring_upd_support, ++ dhd->dma_d2h_ring_upd_support, ++ dhd->prot->rw_index_sz); ++ bcm_bprintf(b, "h2d_max_txpost: %d, prot->h2d_max_txpost: %d\n", ++ h2d_max_txpost, dhd->prot->h2d_max_txpost); ++} ++ ++/* Update local copy of dongle statistics */ ++void dhd_prot_dstats(dhd_pub_t *dhd) ++{ ++ return; ++} ++ ++/** Called by upper DHD layer */ ++int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, ++ uint reorder_info_len, void **pkt, uint32 *free_buf_count) ++{ ++ return 0; ++} ++ ++/** Debug related, post a dummy message to interrupt dongle. Used to process cons commands. */ ++int ++dhd_post_dummy_msg(dhd_pub_t *dhd) ++{ ++ unsigned long flags; ++ hostevent_hdr_t *hevent = NULL; ++ uint16 alloced = 0; ++ ++ dhd_prot_t *prot = dhd->prot; ++ msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ hevent = (hostevent_hdr_t *) ++ dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); ++ ++ if (hevent == NULL) { ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return -1; ++ } ++ ++ /* CMN msg header */ ++ hevent->msg.epoch = ring->seqnum % H2D_EPOCH_MODULO; ++ ring->seqnum++; ++ hevent->msg.msg_type = MSG_TYPE_HOST_EVNT; ++ hevent->msg.if_id = 0; ++ hevent->msg.flags = ring->current_phase; ++ ++ /* Event payload */ ++ hevent->evnt_pyld = htol32(HOST_EVENT_CONS_CMD); ++ ++ /* Since, we are filling the data directly into the bufptr obtained ++ * from the msgbuf, we can directly call the write_complete ++ */ ++ dhd_prot_ring_write_complete(dhd, ring, hevent, 1); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return 0; ++} ++ ++/** ++ * If exactly_nitems is true, this function will allocate space for nitems or fail ++ * If exactly_nitems is false, this function will allocate space for nitems or less ++ */ ++static void * BCMFASTPATH ++dhd_prot_alloc_ring_space(dhd_pub_t *dhd, msgbuf_ring_t *ring, ++ uint16 nitems, uint16 * alloced, bool exactly_nitems) ++{ ++ void * ret_buf; ++ ++ /* Alloc space for nitems in the ring */ ++ ret_buf = dhd_prot_get_ring_space(ring, nitems, alloced, exactly_nitems); ++ ++ if (ret_buf == NULL) { ++ /* if alloc failed , invalidate cached read ptr */ ++ if (dhd->dma_d2h_ring_upd_support) { ++ ring->rd = dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, ring->idx); ++ } else { ++ dhd_bus_cmn_readshared(dhd->bus, &(ring->rd), RING_RD_UPD, ring->idx); ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ /* Check if ring->rd is valid */ ++ if (ring->rd >= ring->max_items) { ++ dhd->bus->read_shm_fail = TRUE; ++ DHD_ERROR(("%s: Invalid rd idx=%d\n", ring->name, ring->rd)); ++ return NULL; ++ } ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ } ++ ++ /* Try allocating once more */ ++ ret_buf = dhd_prot_get_ring_space(ring, nitems, alloced, exactly_nitems); ++ ++ if (ret_buf == NULL) { ++ DHD_INFO(("%s: Ring space not available \n", ring->name)); ++ return NULL; ++ } ++ } ++ ++ if (ret_buf == HOST_RING_BASE(ring)) { ++ DHD_INFO(("%s: setting the phase now\n", ring->name)); ++ ring->current_phase = ring->current_phase ? 0 : BCMPCIE_CMNHDR_PHASE_BIT_INIT; ++ } ++ ++ /* Return alloced space */ ++ return ret_buf; ++} ++ ++/** ++ * Non inline ioct request. ++ * Form a ioctl request first as per ioctptr_reqst_hdr_t header in the circular buffer ++ * Form a separate request buffer where a 4 byte cmn header is added in the front ++ * buf contents from parent function is copied to remaining section of this buffer ++ */ ++static int ++dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ ioctl_req_msg_t *ioct_rqst; ++ void * ioct_buf; /* For ioctl payload */ ++ uint16 rqstlen, resplen; ++ unsigned long flags; ++ uint16 alloced = 0; ++ msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; ++ ++ if (dhd_query_bus_erros(dhd)) { ++ return -EIO; ++ } ++ ++ rqstlen = len; ++ resplen = len; ++ ++ /* Limit ioct request to MSGBUF_MAX_MSG_SIZE bytes including hdrs */ ++ /* 8K allocation of dongle buffer fails */ ++ /* dhd doesnt give separate input & output buf lens */ ++ /* so making the assumption that input length can never be more than 1.5k */ ++ rqstlen = MIN(rqstlen, MSGBUF_MAX_MSG_SIZE); ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ if (prot->ioctl_state) { ++ DHD_ERROR(("%s: pending ioctl %02x\n", __FUNCTION__, prot->ioctl_state)); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return BCME_BUSY; ++ } else { ++ prot->ioctl_state = MSGBUF_IOCTL_ACK_PENDING | MSGBUF_IOCTL_RESP_PENDING; ++ } ++ ++ /* Request for cbuf space */ ++ ioct_rqst = (ioctl_req_msg_t*) ++ dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); ++ if (ioct_rqst == NULL) { ++ DHD_ERROR(("couldn't allocate space on msgring to send ioctl request\n")); ++ prot->ioctl_state = 0; ++ prot->curr_ioctl_cmd = 0; ++ prot->ioctl_received = IOCTL_WAIT; ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return -1; ++ } ++ ++ /* Common msg buf hdr */ ++ ioct_rqst->cmn_hdr.msg_type = MSG_TYPE_IOCTLPTR_REQ; ++ ioct_rqst->cmn_hdr.if_id = (uint8)ifidx; ++ ioct_rqst->cmn_hdr.flags = ring->current_phase; ++ ioct_rqst->cmn_hdr.request_id = htol32(DHD_IOCTL_REQ_PKTID); ++ ioct_rqst->cmn_hdr.epoch = ring->seqnum % H2D_EPOCH_MODULO; ++ ring->seqnum++; ++ ++ ioct_rqst->cmd = htol32(cmd); ++ prot->curr_ioctl_cmd = cmd; ++ ioct_rqst->output_buf_len = htol16(resplen); ++ prot->ioctl_trans_id++; ++ ioct_rqst->trans_id = prot->ioctl_trans_id; ++ ++ /* populate ioctl buffer info */ ++ ioct_rqst->input_buf_len = htol16(rqstlen); ++ ioct_rqst->host_input_buf_addr.high = htol32(PHYSADDRHI(prot->ioctbuf.pa)); ++ ioct_rqst->host_input_buf_addr.low = htol32(PHYSADDRLO(prot->ioctbuf.pa)); ++ /* copy ioct payload */ ++ ioct_buf = (void *) prot->ioctbuf.va; ++ ++ if (buf) ++ memcpy(ioct_buf, buf, len); ++ ++ OSL_CACHE_FLUSH((void *) prot->ioctbuf.va, len); ++ ++ if (!ISALIGNED(ioct_buf, DMA_ALIGN_LEN)) ++ DHD_ERROR(("host ioct address unaligned !!!!! \n")); ++ ++ DHD_CTL(("submitted IOCTL request request_id %d, cmd %d, output_buf_len %d, tx_id %d\n", ++ ioct_rqst->cmn_hdr.request_id, cmd, ioct_rqst->output_buf_len, ++ ioct_rqst->trans_id)); ++ ++ /* update ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ring, ioct_rqst, 1); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return 0; ++} /* dhd_fillup_ioct_reqst */ ++ ++ ++/** ++ * dhd_prot_ring_attach - Initialize the msgbuf_ring object and attach a ++ * DMA-able buffer to it. The ring is NOT tagged as inited until all the ring ++ * information is posted to the dongle. ++ * ++ * Invoked in dhd_prot_attach for the common rings, and in dhd_prot_init for ++ * each flowring in pool of flowrings. ++ * ++ * returns BCME_OK=0 on success ++ * returns non-zero negative error value on failure. ++ */ ++static int ++dhd_prot_ring_attach(dhd_pub_t *dhd, msgbuf_ring_t *ring, const char *name, ++ uint16 max_items, uint16 item_len, uint16 ringid) ++{ ++ int dma_buf_alloced = BCME_NOMEM; ++ uint32 dma_buf_len = max_items * item_len; ++ dhd_prot_t *prot = dhd->prot; ++ uint16 max_flowrings = dhd->bus->max_tx_flowrings; ++ ++ ASSERT(ring); ++ ASSERT(name); ++ ASSERT((max_items < 0xFFFF) && (item_len < 0xFFFF) && (ringid < 0xFFFF)); ++ ++ /* Init name */ ++ strncpy(ring->name, name, RING_NAME_MAX_LENGTH); ++ ring->name[RING_NAME_MAX_LENGTH - 1] = '\0'; ++ ++ ring->idx = ringid; ++ ++ ring->max_items = max_items; ++ ring->item_len = item_len; ++ ++ /* A contiguous space may be reserved for all flowrings */ ++ if (DHD_IS_FLOWRING(ringid, max_flowrings) && (prot->flowrings_dma_buf.va)) { ++ /* Carve out from the contiguous DMA-able flowring buffer */ ++ uint16 flowid; ++ uint32 base_offset; ++ ++ dhd_dma_buf_t *dma_buf = &ring->dma_buf; ++ dhd_dma_buf_t *rsv_buf = &prot->flowrings_dma_buf; ++ ++ flowid = DHD_RINGID_TO_FLOWID(ringid); ++ base_offset = (flowid - BCMPCIE_H2D_COMMON_MSGRINGS) * dma_buf_len; ++ ++ ASSERT(base_offset + dma_buf_len <= rsv_buf->len); ++ ++ dma_buf->len = dma_buf_len; ++ dma_buf->va = (void *)((uintptr)rsv_buf->va + base_offset); ++ PHYSADDRHISET(dma_buf->pa, PHYSADDRHI(rsv_buf->pa)); ++ PHYSADDRLOSET(dma_buf->pa, PHYSADDRLO(rsv_buf->pa) + base_offset); ++ ++ /* On 64bit, contiguous space may not span across 0x00000000FFFFFFFF */ ++ ASSERT(PHYSADDRLO(dma_buf->pa) >= PHYSADDRLO(rsv_buf->pa)); ++ ++ dma_buf->dmah = rsv_buf->dmah; ++ dma_buf->secdma = rsv_buf->secdma; ++ ++ (void)dhd_dma_buf_audit(dhd, &ring->dma_buf); ++ } else { ++ /* Allocate a dhd_dma_buf */ ++ dma_buf_alloced = dhd_dma_buf_alloc(dhd, &ring->dma_buf, dma_buf_len); ++ if (dma_buf_alloced != BCME_OK) { ++ return BCME_NOMEM; ++ } ++ } ++ ++ /* CAUTION: Save ring::base_addr in little endian format! */ ++ dhd_base_addr_htolpa(&ring->base_addr, ring->dma_buf.pa); ++ ++#ifdef BCM_SECURE_DMA ++ if (SECURE_DMA_ENAB(prot->osh)) { ++ ring->dma_buf.secdma = MALLOCZ(prot->osh, sizeof(sec_cma_info_t)); ++ if (ring->dma_buf.secdma == NULL) { ++ goto free_dma_buf; ++ } ++ } ++#endif /* BCM_SECURE_DMA */ ++ ++ DHD_INFO(("RING_ATTACH : %s Max item %d len item %d total size %d " ++ "ring start %p buf phys addr %x:%x \n", ++ ring->name, ring->max_items, ring->item_len, ++ dma_buf_len, ring->dma_buf.va, ltoh32(ring->base_addr.high_addr), ++ ltoh32(ring->base_addr.low_addr))); ++ ++ return BCME_OK; ++ ++#ifdef BCM_SECURE_DMA ++free_dma_buf: ++ if (dma_buf_alloced == BCME_OK) { ++ dhd_dma_buf_free(dhd, &ring->dma_buf); ++ } ++#endif /* BCM_SECURE_DMA */ ++ ++ return BCME_NOMEM; ++ ++} /* dhd_prot_ring_attach */ ++ ++ ++/** ++ * dhd_prot_ring_init - Post the common ring information to dongle. ++ * ++ * Used only for common rings. ++ * ++ * The flowrings information is passed via the create flowring control message ++ * (tx_flowring_create_request_t) sent over the H2D control submission common ++ * ring. ++ */ ++static void ++dhd_prot_ring_init(dhd_pub_t *dhd, msgbuf_ring_t *ring) ++{ ++ ring->wr = 0; ++ ring->rd = 0; ++ ring->curr_rd = 0; ++ ++ /* CAUTION: ring::base_addr already in Little Endian */ ++ dhd_bus_cmn_writeshared(dhd->bus, &ring->base_addr, ++ sizeof(sh_addr_t), RING_BUF_ADDR, ring->idx); ++ dhd_bus_cmn_writeshared(dhd->bus, &ring->max_items, ++ sizeof(uint16), RING_MAX_ITEMS, ring->idx); ++ dhd_bus_cmn_writeshared(dhd->bus, &ring->item_len, ++ sizeof(uint16), RING_ITEM_LEN, ring->idx); ++ ++ dhd_bus_cmn_writeshared(dhd->bus, &(ring->wr), ++ sizeof(uint16), RING_WR_UPD, ring->idx); ++ dhd_bus_cmn_writeshared(dhd->bus, &(ring->rd), ++ sizeof(uint16), RING_RD_UPD, ring->idx); ++ ++ /* ring inited */ ++ ring->inited = TRUE; ++ ++} /* dhd_prot_ring_init */ ++ ++ ++/** ++ * dhd_prot_ring_reset - bzero a ring's DMA-ble buffer and cache flush ++ * Reset WR and RD indices to 0. ++ */ ++static void ++dhd_prot_ring_reset(dhd_pub_t *dhd, msgbuf_ring_t *ring) ++{ ++ DHD_TRACE(("%s\n", __FUNCTION__)); ++ ++ dhd_dma_buf_reset(dhd, &ring->dma_buf); ++ ++ ring->rd = ring->wr = 0; ++ ring->curr_rd = 0; ++ ring->inited = FALSE; ++ ring->create_pending = FALSE; ++} ++ ++ ++/** ++ * dhd_prot_ring_detach - Detach the DMA-able buffer and any other objects ++ * hanging off the msgbuf_ring. ++ */ ++static void ++dhd_prot_ring_detach(dhd_pub_t *dhd, msgbuf_ring_t *ring) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ uint16 max_flowrings = dhd->bus->max_tx_flowrings; ++ ASSERT(ring); ++ ++ ring->inited = FALSE; ++ /* rd = ~0, wr = ring->rd - 1, max_items = 0, len_item = ~0 */ ++ ++#ifdef BCM_SECURE_DMA ++ if (SECURE_DMA_ENAB(prot->osh)) { ++ if (ring->dma_buf.secdma) { ++ SECURE_DMA_UNMAP_ALL(prot->osh, ring->dma_buf.secdma); ++ MFREE(prot->osh, ring->dma_buf.secdma, sizeof(sec_cma_info_t)); ++ ring->dma_buf.secdma = NULL; ++ } ++ } ++#endif /* BCM_SECURE_DMA */ ++ ++ /* If the DMA-able buffer was carved out of a pre-reserved contiguous ++ * memory, then simply stop using it. ++ */ ++ if (DHD_IS_FLOWRING(ring->idx, max_flowrings) && (prot->flowrings_dma_buf.va)) { ++ (void)dhd_dma_buf_audit(dhd, &ring->dma_buf); ++ memset(&ring->dma_buf, 0, sizeof(dhd_dma_buf_t)); ++ } else { ++ dhd_dma_buf_free(dhd, &ring->dma_buf); ++ } ++ ++} /* dhd_prot_ring_detach */ ++ ++ ++/* ++ * +---------------------------------------------------------------------------- ++ * Flowring Pool ++ * ++ * Unlike common rings, which are attached very early on (dhd_prot_attach), ++ * flowrings are dynamically instantiated. Moreover, flowrings may require a ++ * larger DMA-able buffer. To avoid issues with fragmented cache coherent ++ * DMA-able memory, a pre-allocated pool of msgbuf_ring_t is allocated once. ++ * The DMA-able buffers are attached to these pre-allocated msgbuf_ring. ++ * ++ * Each DMA-able buffer may be allocated independently, or may be carved out ++ * of a single large contiguous region that is registered with the protocol ++ * layer into flowrings_dma_buf. On a 64bit platform, this contiguous region ++ * may not span 0x00000000FFFFFFFF (avoid dongle side 64bit ptr arithmetic). ++ * ++ * No flowring pool action is performed in dhd_prot_attach(), as the number ++ * of h2d rings is not yet known. ++ * ++ * In dhd_prot_init(), the dongle advertized number of h2d rings is used to ++ * determine the number of flowrings required, and a pool of msgbuf_rings are ++ * allocated and a DMA-able buffer (carved or allocated) is attached. ++ * See: dhd_prot_flowrings_pool_attach() ++ * ++ * A flowring msgbuf_ring object may be fetched from this pool during flowring ++ * creation, using the flowid. Likewise, flowrings may be freed back into the ++ * pool on flowring deletion. ++ * See: dhd_prot_flowrings_pool_fetch(), dhd_prot_flowrings_pool_release() ++ * ++ * In dhd_prot_detach(), the flowring pool is detached. The DMA-able buffers ++ * are detached (returned back to the carved region or freed), and the pool of ++ * msgbuf_ring and any objects allocated against it are freed. ++ * See: dhd_prot_flowrings_pool_detach() ++ * ++ * In dhd_prot_reset(), the flowring pool is simply reset by returning it to a ++ * state as-if upon an attach. All DMA-able buffers are retained. ++ * Following a dhd_prot_reset(), in a subsequent dhd_prot_init(), the flowring ++ * pool attach will notice that the pool persists and continue to use it. This ++ * will avoid the case of a fragmented DMA-able region. ++ * ++ * +---------------------------------------------------------------------------- ++ */ ++ ++/* Conversion of a flowid to a flowring pool index */ ++#define DHD_FLOWRINGS_POOL_OFFSET(flowid) \ ++ ((flowid) - BCMPCIE_H2D_COMMON_MSGRINGS) ++ ++/* Fetch the msgbuf_ring_t from the flowring pool given a flowid */ ++#define DHD_RING_IN_FLOWRINGS_POOL(prot, flowid) \ ++ (msgbuf_ring_t*)((prot)->h2d_flowrings_pool) + \ ++ DHD_FLOWRINGS_POOL_OFFSET(flowid) ++ ++/* Traverse each flowring in the flowring pool, assigning ring and flowid */ ++#define FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid, total_flowrings) \ ++ for ((flowid) = DHD_FLOWRING_START_FLOWID, \ ++ (ring) = DHD_RING_IN_FLOWRINGS_POOL(prot, flowid); \ ++ (flowid) < ((total_flowrings) + DHD_FLOWRING_START_FLOWID); \ ++ (ring)++, (flowid)++) ++ ++/* Fetch number of H2D flowrings given the total number of h2d rings */ ++static uint16 ++dhd_get_max_flow_rings(dhd_pub_t *dhd) ++{ ++ if (dhd->bus->api.fw_rev >= PCIE_SHARED_VERSION_6) ++ return dhd->bus->max_tx_flowrings; ++ else ++ return (dhd->bus->max_tx_flowrings - BCMPCIE_H2D_COMMON_MSGRINGS); ++} ++ ++/** ++ * dhd_prot_flowrings_pool_attach - Initialize a pool of flowring msgbuf_ring_t. ++ * ++ * Allocate a pool of msgbuf_ring along with DMA-able buffers for flowrings. ++ * Dongle includes common rings when it advertizes the number of H2D rings. ++ * Allocates a pool of msgbuf_ring_t and invokes dhd_prot_ring_attach to ++ * allocate the DMA-able buffer and initialize each msgbuf_ring_t object. ++ * ++ * dhd_prot_ring_attach is invoked to perform the actual initialization and ++ * attaching the DMA-able buffer. ++ * ++ * Later dhd_prot_flowrings_pool_fetch() may be used to fetch a preallocated and ++ * initialized msgbuf_ring_t object. ++ * ++ * returns BCME_OK=0 on success ++ * returns non-zero negative error value on failure. ++ */ ++static int ++dhd_prot_flowrings_pool_attach(dhd_pub_t *dhd) ++{ ++ uint16 flowid; ++ msgbuf_ring_t *ring; ++ uint16 h2d_flowrings_total; /* exclude H2D common rings */ ++ dhd_prot_t *prot = dhd->prot; ++ char ring_name[RING_NAME_MAX_LENGTH]; ++ ++ if (prot->h2d_flowrings_pool != NULL) ++ return BCME_OK; /* dhd_prot_init rentry after a dhd_prot_reset */ ++ ++ ASSERT(prot->h2d_rings_total == 0); ++ ++ /* h2d_rings_total includes H2D common rings: ctrl and rxbuf subn */ ++ prot->h2d_rings_total = (uint16)dhd_bus_max_h2d_queues(dhd->bus); ++ ++ if (prot->h2d_rings_total < BCMPCIE_H2D_COMMON_MSGRINGS) { ++ DHD_ERROR(("%s: h2d_rings_total advertized as %u\n", ++ __FUNCTION__, prot->h2d_rings_total)); ++ return BCME_ERROR; ++ } ++ ++ /* Subtract number of H2D common rings, to determine number of flowrings */ ++ h2d_flowrings_total = dhd_get_max_flow_rings(dhd); ++ ++ DHD_ERROR(("Attach flowrings pool for %d rings\n", h2d_flowrings_total)); ++ ++ /* Allocate pool of msgbuf_ring_t objects for all flowrings */ ++ prot->h2d_flowrings_pool = (msgbuf_ring_t *)MALLOCZ(prot->osh, ++ (h2d_flowrings_total * sizeof(msgbuf_ring_t))); ++ ++ if (prot->h2d_flowrings_pool == NULL) { ++ DHD_ERROR(("%s: flowrings pool for %d flowrings, alloc failure\n", ++ __FUNCTION__, h2d_flowrings_total)); ++ goto fail; ++ } ++ ++ /* Setup & Attach a DMA-able buffer to each flowring in the flowring pool */ ++ FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid, h2d_flowrings_total) { ++ snprintf(ring_name, sizeof(ring_name), "h2dflr_%03u", flowid); ++ if (dhd_prot_ring_attach(dhd, ring, ring_name, ++ prot->h2d_max_txpost, H2DRING_TXPOST_ITEMSIZE, ++ DHD_FLOWID_TO_RINGID(flowid)) != BCME_OK) { ++ goto attach_fail; ++ } ++ } ++ ++ return BCME_OK; ++ ++attach_fail: ++ dhd_prot_flowrings_pool_detach(dhd); /* Free entire pool of flowrings */ ++ ++fail: ++ prot->h2d_rings_total = 0; ++ return BCME_NOMEM; ++ ++} /* dhd_prot_flowrings_pool_attach */ ++ ++ ++/** ++ * dhd_prot_flowrings_pool_reset - Reset all msgbuf_ring_t objects in the pool. ++ * Invokes dhd_prot_ring_reset to perform the actual reset. ++ * ++ * The DMA-able buffer is not freed during reset and neither is the flowring ++ * pool freed. ++ * ++ * dhd_prot_flowrings_pool_reset will be invoked in dhd_prot_reset. Following ++ * the dhd_prot_reset, dhd_prot_init will be re-invoked, and the flowring pool ++ * from a previous flowring pool instantiation will be reused. ++ * ++ * This will avoid a fragmented DMA-able memory condition, if multiple ++ * dhd_prot_reset were invoked to reboot the dongle without a full detach/attach ++ * cycle. ++ */ ++static void ++dhd_prot_flowrings_pool_reset(dhd_pub_t *dhd) ++{ ++ uint16 flowid, h2d_flowrings_total; ++ msgbuf_ring_t *ring; ++ dhd_prot_t *prot = dhd->prot; ++ ++ if (prot->h2d_flowrings_pool == NULL) { ++ ASSERT(prot->h2d_rings_total == 0); ++ return; ++ } ++ h2d_flowrings_total = dhd_get_max_flow_rings(dhd); ++ /* Reset each flowring in the flowring pool */ ++ FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid, h2d_flowrings_total) { ++ dhd_prot_ring_reset(dhd, ring); ++ ring->inited = FALSE; ++ } ++ ++ /* Flowring pool state must be as-if dhd_prot_flowrings_pool_attach */ ++} ++ ++ ++/** ++ * dhd_prot_flowrings_pool_detach - Free pool of msgbuf_ring along with ++ * DMA-able buffers for flowrings. ++ * dhd_prot_ring_detach is invoked to free the DMA-able buffer and perform any ++ * de-initialization of each msgbuf_ring_t. ++ */ ++static void ++dhd_prot_flowrings_pool_detach(dhd_pub_t *dhd) ++{ ++ int flowid; ++ msgbuf_ring_t *ring; ++ uint16 h2d_flowrings_total; /* exclude H2D common rings */ ++ dhd_prot_t *prot = dhd->prot; ++ ++ if (prot->h2d_flowrings_pool == NULL) { ++ ASSERT(prot->h2d_rings_total == 0); ++ return; ++ } ++ ++ h2d_flowrings_total = dhd_get_max_flow_rings(dhd); ++ /* Detach the DMA-able buffer for each flowring in the flowring pool */ ++ FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid, h2d_flowrings_total) { ++ dhd_prot_ring_detach(dhd, ring); ++ } ++ ++ ++ MFREE(prot->osh, prot->h2d_flowrings_pool, ++ (h2d_flowrings_total * sizeof(msgbuf_ring_t))); ++ ++ prot->h2d_flowrings_pool = (msgbuf_ring_t*)NULL; ++ prot->h2d_rings_total = 0; ++ ++} /* dhd_prot_flowrings_pool_detach */ ++ ++ ++/** ++ * dhd_prot_flowrings_pool_fetch - Fetch a preallocated and initialized ++ * msgbuf_ring from the flowring pool, and assign it. ++ * ++ * Unlike common rings, which uses a dhd_prot_ring_init() to pass the common ++ * ring information to the dongle, a flowring's information is passed via a ++ * flowring create control message. ++ * ++ * Only the ring state (WR, RD) index are initialized. ++ */ ++static msgbuf_ring_t * ++dhd_prot_flowrings_pool_fetch(dhd_pub_t *dhd, uint16 flowid) ++{ ++ msgbuf_ring_t *ring; ++ dhd_prot_t *prot = dhd->prot; ++ ++ ASSERT(flowid >= DHD_FLOWRING_START_FLOWID); ++ ASSERT(flowid < prot->h2d_rings_total); ++ ASSERT(prot->h2d_flowrings_pool != NULL); ++ ++ ring = DHD_RING_IN_FLOWRINGS_POOL(prot, flowid); ++ ++ /* ASSERT flow_ring->inited == FALSE */ ++ ++ ring->wr = 0; ++ ring->rd = 0; ++ ring->curr_rd = 0; ++ ring->inited = TRUE; ++ /** ++ * Every time a flowring starts dynamically, initialize current_phase with 0 ++ * then flip to BCMPCIE_CMNHDR_PHASE_BIT_INIT ++ */ ++ ring->current_phase = 0; ++ return ring; ++} ++ ++ ++/** ++ * dhd_prot_flowrings_pool_release - release a previously fetched flowring's ++ * msgbuf_ring back to the flow_ring pool. ++ */ ++void ++dhd_prot_flowrings_pool_release(dhd_pub_t *dhd, uint16 flowid, void *flow_ring) ++{ ++ msgbuf_ring_t *ring; ++ dhd_prot_t *prot = dhd->prot; ++ ++ ASSERT(flowid >= DHD_FLOWRING_START_FLOWID); ++ ASSERT(flowid < prot->h2d_rings_total); ++ ASSERT(prot->h2d_flowrings_pool != NULL); ++ ++ ring = DHD_RING_IN_FLOWRINGS_POOL(prot, flowid); ++ ++ ASSERT(ring == (msgbuf_ring_t*)flow_ring); ++ /* ASSERT flow_ring->inited == TRUE */ ++ ++ (void)dhd_dma_buf_audit(dhd, &ring->dma_buf); ++ ++ ring->wr = 0; ++ ring->rd = 0; ++ ring->inited = FALSE; ++ ++ ring->curr_rd = 0; ++} ++ ++ ++/* Assumes only one index is updated at a time */ ++/* If exactly_nitems is true, this function will allocate space for nitems or fail */ ++/* Exception: when wrap around is encountered, to prevent hangup (last nitems of ring buffer) */ ++/* If exactly_nitems is false, this function will allocate space for nitems or less */ ++static void *BCMFASTPATH ++dhd_prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced, ++ bool exactly_nitems) ++{ ++ void *ret_ptr = NULL; ++ uint16 ring_avail_cnt; ++ ++ ASSERT(nitems <= ring->max_items); ++ ++ ring_avail_cnt = CHECK_WRITE_SPACE(ring->rd, ring->wr, ring->max_items); ++ ++ if ((ring_avail_cnt == 0) || ++ (exactly_nitems && (ring_avail_cnt < nitems) && ++ ((ring->max_items - ring->wr) >= nitems))) { ++ DHD_INFO(("Space not available: ring %s items %d write %d read %d\n", ++ ring->name, nitems, ring->wr, ring->rd)); ++ return NULL; ++ } ++ *alloced = MIN(nitems, ring_avail_cnt); ++ ++ /* Return next available space */ ++ ret_ptr = (char *)DHD_RING_BGN_VA(ring) + (ring->wr * ring->item_len); ++ ++ /* Update write index */ ++ if ((ring->wr + *alloced) == ring->max_items) ++ ring->wr = 0; ++ else if ((ring->wr + *alloced) < ring->max_items) ++ ring->wr += *alloced; ++ else { ++ /* Should never hit this */ ++ ASSERT(0); ++ return NULL; ++ } ++ ++ return ret_ptr; ++} /* dhd_prot_get_ring_space */ ++ ++ ++/** ++ * dhd_prot_ring_write_complete - Host updates the new WR index on producing ++ * new messages in a H2D ring. The messages are flushed from cache prior to ++ * posting the new WR index. The new WR index will be updated in the DMA index ++ * array or directly in the dongle's ring state memory. ++ * A PCIE doorbell will be generated to wake up the dongle. ++ * This is a non-atomic function, make sure the callers ++ * always hold appropriate locks. ++ */ ++static void BCMFASTPATH ++dhd_prot_ring_write_complete(dhd_pub_t *dhd, msgbuf_ring_t * ring, void* p, ++ uint16 nitems) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ uint8 db_index; ++ uint16 max_flowrings = dhd->bus->max_tx_flowrings; ++ ++ /* cache flush */ ++ OSL_CACHE_FLUSH(p, ring->item_len * nitems); ++ ++ if (IDMA_DS_ACTIVE(dhd) && IDMA_ACTIVE(dhd)) { ++ dhd_bus_cmn_writeshared(dhd->bus, &(ring->wr), ++ sizeof(uint16), RING_WR_UPD, ring->idx); ++ } else if (IDMA_ACTIVE(dhd) || dhd->dma_h2d_ring_upd_support) { ++ dhd_prot_dma_indx_set(dhd, ring->wr, ++ H2D_DMA_INDX_WR_UPD, ring->idx); ++ } else if (IFRM_ACTIVE(dhd) && DHD_IS_FLOWRING(ring->idx, max_flowrings)) { ++ dhd_prot_dma_indx_set(dhd, ring->wr, ++ H2D_IFRM_INDX_WR_UPD, ring->idx); ++ } else { ++ dhd_bus_cmn_writeshared(dhd->bus, &(ring->wr), ++ sizeof(uint16), RING_WR_UPD, ring->idx); ++ } ++ ++ /* raise h2d interrupt */ ++ if (IDMA_ACTIVE(dhd) || ++ (IFRM_ACTIVE(dhd) && DHD_IS_FLOWRING(ring->idx, max_flowrings))) { ++ if (IDMA_DS_ACTIVE(dhd)) { ++ prot->mb_ring_fn(dhd->bus, ring->wr); ++ } else { ++ db_index = IDMA_IDX0; ++ prot->mb_2_ring_fn(dhd->bus, db_index, TRUE); ++ } ++ } else { ++ prot->mb_ring_fn(dhd->bus, ring->wr); ++ } ++} ++ ++/** ++ * dhd_prot_upd_read_idx - Host updates the new RD index on consuming messages ++ * from a D2H ring. The new RD index will be updated in the DMA Index array or ++ * directly in dongle's ring state memory. ++ */ ++static void ++dhd_prot_upd_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ uint8 db_index; ++ ++ /* update read index */ ++ /* If dma'ing h2d indices supported ++ * update the r -indices in the ++ * host memory o/w in TCM ++ */ ++ if (IDMA_ACTIVE(dhd)) { ++ dhd_prot_dma_indx_set(dhd, ring->rd, ++ D2H_DMA_INDX_RD_UPD, ring->idx); ++ if (IDMA_DS_ACTIVE(dhd)) { ++ dhd_bus_cmn_writeshared(dhd->bus, &(ring->rd), ++ sizeof(uint16), RING_RD_UPD, ring->idx); ++ } else { ++ db_index = IDMA_IDX1; ++ prot->mb_2_ring_fn(dhd->bus, db_index, FALSE); ++ } ++ } else if (dhd->dma_h2d_ring_upd_support) { ++ dhd_prot_dma_indx_set(dhd, ring->rd, ++ D2H_DMA_INDX_RD_UPD, ring->idx); ++ } else { ++ dhd_bus_cmn_writeshared(dhd->bus, &(ring->rd), ++ sizeof(uint16), RING_RD_UPD, ring->idx); ++ } ++} ++ ++static int ++dhd_send_d2h_ringcreate(dhd_pub_t *dhd, msgbuf_ring_t *ring_to_create) ++{ ++ unsigned long flags; ++ d2h_ring_create_req_t *d2h_ring; ++ uint16 alloced = 0; ++ int ret = BCME_OK; ++ uint16 max_h2d_rings = dhd->bus->max_submission_rings; ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ DHD_TRACE(("%s trying to send D2H ring create Req\n", __FUNCTION__)); ++ ++ if (ring_to_create == NULL) { ++ DHD_ERROR(("%s: FATAL: ring_to_create is NULL\n", __FUNCTION__)); ++ ret = BCME_ERROR; ++ goto err; ++ } ++ ++ /* Request for ring buffer space */ ++ d2h_ring = (d2h_ring_create_req_t *) dhd_prot_alloc_ring_space(dhd, ++ &dhd->prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, ++ &alloced, FALSE); ++ ++ if (d2h_ring == NULL) { ++ DHD_ERROR(("%s: FATAL: No space in control ring to send D2H ring create\n", ++ __FUNCTION__)); ++ ret = BCME_NOMEM; ++ goto err; ++ } ++ ring_to_create->create_req_id = DHD_D2H_DBGRING_REQ_PKTID; ++ ring_to_create->create_pending = TRUE; ++ ++ /* Common msg buf hdr */ ++ d2h_ring->msg.msg_type = MSG_TYPE_D2H_RING_CREATE; ++ d2h_ring->msg.if_id = 0; ++ d2h_ring->msg.flags = dhd->prot->h2dring_ctrl_subn.current_phase; ++ d2h_ring->msg.request_id = htol32(ring_to_create->create_req_id); ++ d2h_ring->ring_id = htol16(DHD_D2H_RING_OFFSET(ring_to_create->idx, max_h2d_rings)); ++ d2h_ring->ring_type = BCMPCIE_D2H_RING_TYPE_DBGBUF_CPL; ++ d2h_ring->max_items = htol16(D2HRING_DYNAMIC_INFO_MAX_ITEM); ++ d2h_ring->len_item = htol16(D2HRING_INFO_BUFCMPLT_ITEMSIZE); ++ d2h_ring->ring_ptr.low_addr = ring_to_create->base_addr.low_addr; ++ d2h_ring->ring_ptr.high_addr = ring_to_create->base_addr.high_addr; ++ ++ d2h_ring->flags = 0; ++ d2h_ring->msg.epoch = ++ dhd->prot->h2dring_ctrl_subn.seqnum % H2D_EPOCH_MODULO; ++ dhd->prot->h2dring_ctrl_subn.seqnum++; ++ ++ /* Update the flow_ring's WRITE index */ ++ dhd_prot_ring_write_complete(dhd, &dhd->prot->h2dring_ctrl_subn, d2h_ring, ++ DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); ++ ++err: ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return ret; ++} ++ ++static int ++dhd_send_h2d_ringcreate(dhd_pub_t *dhd, msgbuf_ring_t *ring_to_create) ++{ ++ unsigned long flags; ++ h2d_ring_create_req_t *h2d_ring; ++ uint16 alloced = 0; ++ uint8 i = 0; ++ int ret = BCME_OK; ++ ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ DHD_TRACE(("%s trying to send H2D ring create Req\n", __FUNCTION__)); ++ ++ if (ring_to_create == NULL) { ++ DHD_ERROR(("%s: FATAL: ring_to_create is NULL\n", __FUNCTION__)); ++ ret = BCME_ERROR; ++ goto err; ++ } ++ ++ /* Request for ring buffer space */ ++ h2d_ring = (h2d_ring_create_req_t *)dhd_prot_alloc_ring_space(dhd, ++ &dhd->prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, ++ &alloced, FALSE); ++ ++ if (h2d_ring == NULL) { ++ DHD_ERROR(("%s: FATAL: No space in control ring to send H2D ring create\n", ++ __FUNCTION__)); ++ ret = BCME_NOMEM; ++ goto err; ++ } ++ ring_to_create->create_req_id = DHD_H2D_DBGRING_REQ_PKTID; ++ ring_to_create->create_pending = TRUE; ++ ++ /* Common msg buf hdr */ ++ h2d_ring->msg.msg_type = MSG_TYPE_H2D_RING_CREATE; ++ h2d_ring->msg.if_id = 0; ++ h2d_ring->msg.request_id = htol32(ring_to_create->create_req_id); ++ h2d_ring->msg.flags = dhd->prot->h2dring_ctrl_subn.current_phase; ++ h2d_ring->ring_id = htol16(DHD_H2D_RING_OFFSET(ring_to_create->idx)); ++ h2d_ring->ring_type = BCMPCIE_H2D_RING_TYPE_DBGBUF_SUBMIT; ++ h2d_ring->max_items = htol16(H2DRING_DYNAMIC_INFO_MAX_ITEM); ++ h2d_ring->n_completion_ids = ring_to_create->n_completion_ids; ++ h2d_ring->len_item = htol16(H2DRING_INFO_BUFPOST_ITEMSIZE); ++ h2d_ring->ring_ptr.low_addr = ring_to_create->base_addr.low_addr; ++ h2d_ring->ring_ptr.high_addr = ring_to_create->base_addr.high_addr; ++ ++ for (i = 0; i < ring_to_create->n_completion_ids; i++) { ++ h2d_ring->completion_ring_ids[i] = htol16(ring_to_create->compeltion_ring_ids[i]); ++ } ++ ++ h2d_ring->flags = 0; ++ h2d_ring->msg.epoch = ++ dhd->prot->h2dring_ctrl_subn.seqnum % H2D_EPOCH_MODULO; ++ dhd->prot->h2dring_ctrl_subn.seqnum++; ++ ++ /* Update the flow_ring's WRITE index */ ++ dhd_prot_ring_write_complete(dhd, &dhd->prot->h2dring_ctrl_subn, h2d_ring, ++ DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); ++ ++err: ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return ret; ++} ++ ++/** ++ * dhd_prot_dma_indx_set - set a new WR or RD index in the DMA index array. ++ * Dongle will DMA the entire array (if DMA_INDX feature is enabled). ++ * See dhd_prot_dma_indx_init() ++ */ ++void ++dhd_prot_dma_indx_set(dhd_pub_t *dhd, uint16 new_index, uint8 type, uint16 ringid) ++{ ++ uint8 *ptr; ++ uint16 offset; ++ dhd_prot_t *prot = dhd->prot; ++ uint16 max_h2d_rings = dhd->bus->max_submission_rings; ++ ++ switch (type) { ++ case H2D_DMA_INDX_WR_UPD: ++ ptr = (uint8 *)(prot->h2d_dma_indx_wr_buf.va); ++ offset = DHD_H2D_RING_OFFSET(ringid); ++ break; ++ ++ case D2H_DMA_INDX_RD_UPD: ++ ptr = (uint8 *)(prot->d2h_dma_indx_rd_buf.va); ++ offset = DHD_D2H_RING_OFFSET(ringid, max_h2d_rings); ++ break; ++ ++ case H2D_IFRM_INDX_WR_UPD: ++ ptr = (uint8 *)(prot->h2d_ifrm_indx_wr_buf.va); ++ offset = DHD_H2D_FRM_FLOW_RING_OFFSET(ringid); ++ break; ++ ++ default: ++ DHD_ERROR(("%s: Invalid option for DMAing read/write index\n", ++ __FUNCTION__)); ++ return; ++ } ++ ++ ASSERT(prot->rw_index_sz != 0); ++ ptr += offset * prot->rw_index_sz; ++ ++ *(uint16*)ptr = htol16(new_index); ++ ++ OSL_CACHE_FLUSH((void *)ptr, prot->rw_index_sz); ++ ++ DHD_TRACE(("%s: data %d type %d ringid %d ptr 0x%p offset %d\n", ++ __FUNCTION__, new_index, type, ringid, ptr, offset)); ++ ++} /* dhd_prot_dma_indx_set */ ++ ++ ++/** ++ * dhd_prot_dma_indx_get - Fetch a WR or RD index from the dongle DMA-ed index ++ * array. ++ * Dongle DMAes an entire array to host memory (if the feature is enabled). ++ * See dhd_prot_dma_indx_init() ++ */ ++static uint16 ++dhd_prot_dma_indx_get(dhd_pub_t *dhd, uint8 type, uint16 ringid) ++{ ++ uint8 *ptr; ++ uint16 data; ++ uint16 offset; ++ dhd_prot_t *prot = dhd->prot; ++ uint16 max_h2d_rings = dhd->bus->max_submission_rings; ++ ++ switch (type) { ++ case H2D_DMA_INDX_WR_UPD: ++ ptr = (uint8 *)(prot->h2d_dma_indx_wr_buf.va); ++ offset = DHD_H2D_RING_OFFSET(ringid); ++ break; ++ ++ case H2D_DMA_INDX_RD_UPD: ++ ptr = (uint8 *)(prot->h2d_dma_indx_rd_buf.va); ++ offset = DHD_H2D_RING_OFFSET(ringid); ++ break; ++ ++ case D2H_DMA_INDX_WR_UPD: ++ ptr = (uint8 *)(prot->d2h_dma_indx_wr_buf.va); ++ offset = DHD_D2H_RING_OFFSET(ringid, max_h2d_rings); ++ break; ++ ++ case D2H_DMA_INDX_RD_UPD: ++ ptr = (uint8 *)(prot->d2h_dma_indx_rd_buf.va); ++ offset = DHD_D2H_RING_OFFSET(ringid, max_h2d_rings); ++ break; ++ ++ default: ++ DHD_ERROR(("%s: Invalid option for DMAing read/write index\n", ++ __FUNCTION__)); ++ return 0; ++ } ++ ++ ASSERT(prot->rw_index_sz != 0); ++ ptr += offset * prot->rw_index_sz; ++ ++ OSL_CACHE_INV((void *)ptr, prot->rw_index_sz); ++ ++ data = LTOH16(*((uint16*)ptr)); ++ ++ DHD_TRACE(("%s: data %d type %d ringid %d ptr 0x%p offset %d\n", ++ __FUNCTION__, data, type, ringid, ptr, offset)); ++ ++ return (data); ++ ++} /* dhd_prot_dma_indx_get */ ++ ++/** ++ * An array of DMA read/write indices, containing information about host rings, can be maintained ++ * either in host memory or in device memory, dependent on preprocessor options. This function is, ++ * dependent on these options, called during driver initialization. It reserves and initializes ++ * blocks of DMA'able host memory containing an array of DMA read or DMA write indices. The physical ++ * address of these host memory blocks are communicated to the dongle later on. By reading this host ++ * memory, the dongle learns about the state of the host rings. ++ */ ++ ++static INLINE int ++dhd_prot_dma_indx_alloc(dhd_pub_t *dhd, uint8 type, ++ dhd_dma_buf_t *dma_buf, uint32 bufsz) ++{ ++ int rc; ++ ++ if ((dma_buf->len == bufsz) || (dma_buf->va != NULL)) ++ return BCME_OK; ++ ++ rc = dhd_dma_buf_alloc(dhd, dma_buf, bufsz); ++ ++ return rc; ++} ++ ++int ++dhd_prot_dma_indx_init(dhd_pub_t *dhd, uint32 rw_index_sz, uint8 type, uint32 length) ++{ ++ uint32 bufsz; ++ dhd_prot_t *prot = dhd->prot; ++ dhd_dma_buf_t *dma_buf; ++ ++ if (prot == NULL) { ++ DHD_ERROR(("prot is not inited\n")); ++ return BCME_ERROR; ++ } ++ ++ /* Dongle advertizes 2B or 4B RW index size */ ++ ASSERT(rw_index_sz != 0); ++ prot->rw_index_sz = rw_index_sz; ++ ++ bufsz = rw_index_sz * length; ++ ++ switch (type) { ++ case H2D_DMA_INDX_WR_BUF: ++ dma_buf = &prot->h2d_dma_indx_wr_buf; ++ if (dhd_prot_dma_indx_alloc(dhd, type, dma_buf, bufsz)) ++ goto ret_no_mem; ++ DHD_ERROR(("H2D DMA WR INDX : array size %d = %d * %d\n", ++ dma_buf->len, rw_index_sz, length)); ++ break; ++ ++ case H2D_DMA_INDX_RD_BUF: ++ dma_buf = &prot->h2d_dma_indx_rd_buf; ++ if (dhd_prot_dma_indx_alloc(dhd, type, dma_buf, bufsz)) ++ goto ret_no_mem; ++ DHD_ERROR(("H2D DMA RD INDX : array size %d = %d * %d\n", ++ dma_buf->len, rw_index_sz, length)); ++ break; ++ ++ case D2H_DMA_INDX_WR_BUF: ++ dma_buf = &prot->d2h_dma_indx_wr_buf; ++ if (dhd_prot_dma_indx_alloc(dhd, type, dma_buf, bufsz)) ++ goto ret_no_mem; ++ DHD_ERROR(("D2H DMA WR INDX : array size %d = %d * %d\n", ++ dma_buf->len, rw_index_sz, length)); ++ break; ++ ++ case D2H_DMA_INDX_RD_BUF: ++ dma_buf = &prot->d2h_dma_indx_rd_buf; ++ if (dhd_prot_dma_indx_alloc(dhd, type, dma_buf, bufsz)) ++ goto ret_no_mem; ++ DHD_ERROR(("D2H DMA RD INDX : array size %d = %d * %d\n", ++ dma_buf->len, rw_index_sz, length)); ++ break; ++ ++ case H2D_IFRM_INDX_WR_BUF: ++ dma_buf = &prot->h2d_ifrm_indx_wr_buf; ++ if (dhd_prot_dma_indx_alloc(dhd, type, dma_buf, bufsz)) ++ goto ret_no_mem; ++ DHD_ERROR(("H2D IFRM WR INDX : array size %d = %d * %d\n", ++ dma_buf->len, rw_index_sz, length)); ++ break; ++ ++ default: ++ DHD_ERROR(("%s: Unexpected option\n", __FUNCTION__)); ++ return BCME_BADOPTION; ++ } ++ ++ return BCME_OK; ++ ++ret_no_mem: ++ DHD_ERROR(("%s: dhd_prot_dma_indx_alloc type %d buf_sz %d failure\n", ++ __FUNCTION__, type, bufsz)); ++ return BCME_NOMEM; ++ ++} /* dhd_prot_dma_indx_init */ ++ ++ ++/** ++ * Called on checking for 'completion' messages from the dongle. Returns next host buffer to read ++ * from, or NULL if there are no more messages to read. ++ */ ++static uint8* ++dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 *available_len) ++{ ++ uint16 wr; ++ uint16 rd; ++ uint16 depth; ++ uint16 items; ++ void *read_addr = NULL; /* address of next msg to be read in ring */ ++ uint16 d2h_wr = 0; ++ ++ DHD_TRACE(("%s: d2h_dma_indx_rd_buf %p, d2h_dma_indx_wr_buf %p\n", ++ __FUNCTION__, (uint32 *)(dhd->prot->d2h_dma_indx_rd_buf.va), ++ (uint32 *)(dhd->prot->d2h_dma_indx_wr_buf.va))); ++ ++ /* Remember the read index in a variable. ++ * This is becuase ring->rd gets updated in the end of this function ++ * So if we have to print the exact read index from which the ++ * message is read its not possible. ++ */ ++ ring->curr_rd = ring->rd; ++ ++ /* update write pointer */ ++ if (dhd->dma_d2h_ring_upd_support) { ++ /* DMAing write/read indices supported */ ++ d2h_wr = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); ++ ring->wr = d2h_wr; ++ } else { ++ dhd_bus_cmn_readshared(dhd->bus, &(ring->wr), RING_WR_UPD, ring->idx); ++ } ++ ++ wr = ring->wr; ++ rd = ring->rd; ++ depth = ring->max_items; ++ ++ /* check for avail space, in number of ring items */ ++ items = READ_AVAIL_SPACE(wr, rd, depth); ++ if (items == 0) ++ return NULL; ++ ++ /* ++ * Note that there are builds where Assert translates to just printk ++ * so, even if we had hit this condition we would never halt. Now ++ * dhd_prot_process_msgtype can get into an big loop if this ++ * happens. ++ */ ++ if (items > ring->max_items) { ++ DHD_ERROR(("\r\n======================= \r\n")); ++ DHD_ERROR(("%s(): ring %p, ring->name %s, ring->max_items %d, items %d \r\n", ++ __FUNCTION__, ring, ring->name, ring->max_items, items)); ++ DHD_ERROR(("wr: %d, rd: %d, depth: %d \r\n", wr, rd, depth)); ++ DHD_ERROR(("dhd->busstate %d bus->wait_for_d3_ack %d \r\n", ++ dhd->busstate, dhd->bus->wait_for_d3_ack)); ++ DHD_ERROR(("\r\n======================= \r\n")); ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ if (wr >= ring->max_items) { ++ dhd->bus->read_shm_fail = TRUE; ++ } ++#else ++#ifdef DHD_FW_COREDUMP ++ if (dhd->memdump_enabled) { ++ /* collect core dump */ ++ dhd->memdump_type = DUMP_TYPE_RESUMED_ON_INVALID_RING_RDWR; ++ dhd_bus_mem_dump(dhd); ++ ++ } ++#endif /* DHD_FW_COREDUMP */ ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ ++ *available_len = 0; ++ dhd_schedule_reset(dhd); ++ ++ return NULL; ++ } ++ ++ /* if space is available, calculate address to be read */ ++ read_addr = (char*)ring->dma_buf.va + (rd * ring->item_len); ++ ++ /* update read pointer */ ++ if ((ring->rd + items) >= ring->max_items) ++ ring->rd = 0; ++ else ++ ring->rd += items; ++ ++ ASSERT(ring->rd < ring->max_items); ++ ++ /* convert items to bytes : available_len must be 32bits */ ++ *available_len = (uint32)(items * ring->item_len); ++ ++ OSL_CACHE_INV(read_addr, *available_len); ++ ++ /* return read address */ ++ return read_addr; ++ ++} /* dhd_prot_get_read_addr */ ++ ++/** ++ * dhd_prot_h2d_mbdata_send_ctrlmsg is a non-atomic function, ++ * make sure the callers always hold appropriate locks. ++ */ ++int dhd_prot_h2d_mbdata_send_ctrlmsg(dhd_pub_t *dhd, uint32 mb_data) ++{ ++ h2d_mailbox_data_t *h2d_mb_data; ++ uint16 alloced = 0; ++ int num_post = 1; ++ int i; ++ ++ DHD_INFO(("%s Sending H2D MB data Req data 0x%04x\n", ++ __FUNCTION__, mb_data)); ++ if (!dhd->prot->h2dring_ctrl_subn.inited) { ++ DHD_ERROR(("%s: Ctrl Submit Ring: not inited\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++#ifdef PCIE_INB_DW ++ if ((INBAND_DW_ENAB(dhd->bus)) && ++ (dhdpcie_bus_get_pcie_inband_dw_state(dhd->bus) == ++ DW_DEVICE_DS_DEV_SLEEP)) { ++ if (mb_data == H2D_HOST_CONS_INT) { ++ /* One additional device_wake post needed */ ++ num_post = 2; ++ } ++ } ++#endif /* PCIE_INB_DW */ ++ ++ for (i = 0; i < num_post; i ++) { ++ /* Request for ring buffer space */ ++ h2d_mb_data = (h2d_mailbox_data_t *)dhd_prot_alloc_ring_space(dhd, ++ &dhd->prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, ++ &alloced, FALSE); ++ ++ if (h2d_mb_data == NULL) { ++ DHD_ERROR(("%s: FATAL: No space in control ring to send H2D Mb data\n", ++ __FUNCTION__)); ++ return BCME_NOMEM; ++ } ++ ++ memset(h2d_mb_data, 0, sizeof(h2d_mailbox_data_t)); ++ /* Common msg buf hdr */ ++ h2d_mb_data->msg.msg_type = MSG_TYPE_H2D_MAILBOX_DATA; ++ h2d_mb_data->msg.flags = dhd->prot->h2dring_ctrl_subn.current_phase; ++ ++ h2d_mb_data->msg.epoch = ++ dhd->prot->h2dring_ctrl_subn.seqnum % H2D_EPOCH_MODULO; ++ dhd->prot->h2dring_ctrl_subn.seqnum++; ++ ++#ifdef PCIE_INB_DW ++ /* post device_wake first */ ++ if ((num_post == 2) && (i == 0)) { ++ h2d_mb_data->mail_box_data = htol32(H2DMB_DS_DEVICE_WAKE); ++ } else ++#endif /* PCIE_INB_DW */ ++ { ++ h2d_mb_data->mail_box_data = htol32(mb_data); ++ } ++ ++ DHD_INFO(("%s Send H2D MB data Req data 0x%04x\n", __FUNCTION__, mb_data)); ++ ++ /* upd wrt ptr and raise interrupt */ ++ /* caller of dhd_prot_h2d_mbdata_send_ctrlmsg already holding general lock */ ++ dhd_prot_ring_write_complete(dhd, &dhd->prot->h2dring_ctrl_subn, h2d_mb_data, ++ DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); ++#ifdef PCIE_INB_DW ++ /* Add a delay if device_wake is posted */ ++ if ((num_post == 2) && (i == 0)) { ++ OSL_DELAY(1000); ++ } ++#endif /* PCIE_INB_DW */ ++ } ++ ++ return 0; ++} ++ ++/** Creates a flow ring and informs dongle of this event */ ++int ++dhd_prot_flow_ring_create(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) ++{ ++ tx_flowring_create_request_t *flow_create_rqst; ++ msgbuf_ring_t *flow_ring; ++ dhd_prot_t *prot = dhd->prot; ++ unsigned long flags; ++ uint16 alloced = 0; ++ msgbuf_ring_t *ctrl_ring = &prot->h2dring_ctrl_subn; ++ uint16 max_flowrings = dhd->bus->max_tx_flowrings; ++ ++ /* Fetch a pre-initialized msgbuf_ring from the flowring pool */ ++ flow_ring = dhd_prot_flowrings_pool_fetch(dhd, flow_ring_node->flowid); ++ if (flow_ring == NULL) { ++ DHD_ERROR(("%s: dhd_prot_flowrings_pool_fetch TX Flowid %d failed\n", ++ __FUNCTION__, flow_ring_node->flowid)); ++ return BCME_NOMEM; ++ } ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ /* Request for ctrl_ring buffer space */ ++ flow_create_rqst = (tx_flowring_create_request_t *) ++ dhd_prot_alloc_ring_space(dhd, ctrl_ring, 1, &alloced, FALSE); ++ ++ if (flow_create_rqst == NULL) { ++ dhd_prot_flowrings_pool_release(dhd, flow_ring_node->flowid, flow_ring); ++ DHD_ERROR(("%s: Flow Create Req flowid %d - failure ring space\n", ++ __FUNCTION__, flow_ring_node->flowid)); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return BCME_NOMEM; ++ } ++ ++ flow_ring_node->prot_info = (void *)flow_ring; ++ ++ /* Common msg buf hdr */ ++ flow_create_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_CREATE; ++ flow_create_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; ++ flow_create_rqst->msg.request_id = htol32(0); /* TBD */ ++ flow_create_rqst->msg.flags = ctrl_ring->current_phase; ++ ++ flow_create_rqst->msg.epoch = ctrl_ring->seqnum % H2D_EPOCH_MODULO; ++ ctrl_ring->seqnum++; ++ ++ /* Update flow create message */ ++ flow_create_rqst->tid = flow_ring_node->flow_info.tid; ++ flow_create_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); ++ memcpy(flow_create_rqst->sa, flow_ring_node->flow_info.sa, sizeof(flow_create_rqst->sa)); ++ memcpy(flow_create_rqst->da, flow_ring_node->flow_info.da, sizeof(flow_create_rqst->da)); ++ /* CAUTION: ring::base_addr already in Little Endian */ ++ flow_create_rqst->flow_ring_ptr.low_addr = flow_ring->base_addr.low_addr; ++ flow_create_rqst->flow_ring_ptr.high_addr = flow_ring->base_addr.high_addr; ++ flow_create_rqst->max_items = htol16(prot->h2d_max_txpost); ++ flow_create_rqst->len_item = htol16(H2DRING_TXPOST_ITEMSIZE); ++ ++ /* definition for ifrm mask : bit0:d11ac core, bit1:d11ad core ++ * currently it is not used for priority. so uses solely for ifrm mask ++ */ ++ if (IFRM_ACTIVE(dhd)) ++ flow_create_rqst->priority_ifrmmask = (1 << IFRM_DEV_0); ++ ++ DHD_ERROR(("%s: Send Flow Create Req flow ID %d for peer " MACDBG ++ " prio %d ifindex %d\n", __FUNCTION__, flow_ring_node->flowid, ++ MAC2STRDBG(flow_ring_node->flow_info.da), flow_ring_node->flow_info.tid, ++ flow_ring_node->flow_info.ifindex)); ++ ++ /* Update the flow_ring's WRITE index */ ++ if (IDMA_ACTIVE(dhd) || dhd->dma_h2d_ring_upd_support) { ++ dhd_prot_dma_indx_set(dhd, flow_ring->wr, ++ H2D_DMA_INDX_WR_UPD, flow_ring->idx); ++ } else if (IFRM_ACTIVE(dhd) && DHD_IS_FLOWRING(flow_ring->idx, max_flowrings)) { ++ dhd_prot_dma_indx_set(dhd, flow_ring->wr, ++ H2D_IFRM_INDX_WR_UPD, flow_ring->idx); ++ } else { ++ dhd_bus_cmn_writeshared(dhd->bus, &(flow_ring->wr), ++ sizeof(uint16), RING_WR_UPD, flow_ring->idx); ++ } ++ ++ /* update control subn ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ctrl_ring, flow_create_rqst, 1); ++ ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return BCME_OK; ++} /* dhd_prot_flow_ring_create */ ++ ++/** called on receiving MSG_TYPE_FLOW_RING_CREATE_CMPLT message from dongle */ ++static void ++dhd_prot_flow_ring_create_response_process(dhd_pub_t *dhd, void *msg) ++{ ++ tx_flowring_create_response_t *flow_create_resp = (tx_flowring_create_response_t *)msg; ++ ++ DHD_ERROR(("%s: Flow Create Response status = %d Flow %d\n", __FUNCTION__, ++ ltoh16(flow_create_resp->cmplt.status), ++ ltoh16(flow_create_resp->cmplt.flow_ring_id))); ++ ++ dhd_bus_flow_ring_create_response(dhd->bus, ++ ltoh16(flow_create_resp->cmplt.flow_ring_id), ++ ltoh16(flow_create_resp->cmplt.status)); ++} ++ ++static void ++dhd_prot_process_h2d_ring_create_complete(dhd_pub_t *dhd, void *buf) ++{ ++ h2d_ring_create_response_t *resp = (h2d_ring_create_response_t *)buf; ++ DHD_INFO(("%s ring create Response status = %d ring %d, id 0x%04x\n", __FUNCTION__, ++ ltoh16(resp->cmplt.status), ++ ltoh16(resp->cmplt.ring_id), ++ ltoh32(resp->cmn_hdr.request_id))); ++ if (ltoh32(resp->cmn_hdr.request_id) != DHD_H2D_DBGRING_REQ_PKTID) { ++ DHD_ERROR(("invalid request ID with h2d ring create complete\n")); ++ return; ++ } ++ if (!dhd->prot->h2dring_info_subn->create_pending) { ++ DHD_ERROR(("info ring create status for not pending submit ring\n")); ++ } ++ ++ if (ltoh16(resp->cmplt.status) != BCMPCIE_SUCCESS) { ++ DHD_ERROR(("info ring create failed with status %d\n", ++ ltoh16(resp->cmplt.status))); ++ return; ++ } ++ dhd->prot->h2dring_info_subn->create_pending = FALSE; ++ dhd->prot->h2dring_info_subn->inited = TRUE; ++ dhd_prot_infobufpost(dhd); ++} ++ ++static void ++dhd_prot_process_d2h_ring_create_complete(dhd_pub_t *dhd, void *buf) ++{ ++ d2h_ring_create_response_t *resp = (d2h_ring_create_response_t *)buf; ++ DHD_INFO(("%s ring create Response status = %d ring %d, id 0x%04x\n", __FUNCTION__, ++ ltoh16(resp->cmplt.status), ++ ltoh16(resp->cmplt.ring_id), ++ ltoh32(resp->cmn_hdr.request_id))); ++ if (ltoh32(resp->cmn_hdr.request_id) != DHD_D2H_DBGRING_REQ_PKTID) { ++ DHD_ERROR(("invalid request ID with d2h ring create complete\n")); ++ return; ++ } ++ if (!dhd->prot->d2hring_info_cpln->create_pending) { ++ DHD_ERROR(("info ring create status for not pending cpl ring\n")); ++ return; ++ } ++ ++ if (ltoh16(resp->cmplt.status) != BCMPCIE_SUCCESS) { ++ DHD_ERROR(("info cpl ring create failed with status %d\n", ++ ltoh16(resp->cmplt.status))); ++ return; ++ } ++ dhd->prot->d2hring_info_cpln->create_pending = FALSE; ++ dhd->prot->d2hring_info_cpln->inited = TRUE; ++} ++ ++static void ++dhd_prot_process_d2h_mb_data(dhd_pub_t *dhd, void* buf) ++{ ++ d2h_mailbox_data_t *d2h_data; ++ ++ d2h_data = (d2h_mailbox_data_t *)buf; ++ DHD_INFO(("%s dhd_prot_process_d2h_mb_data, 0x%04x\n", __FUNCTION__, ++ d2h_data->d2h_mailbox_data)); ++ dhd_bus_handle_mb_data(dhd->bus, d2h_data->d2h_mailbox_data); ++} ++ ++static void ++dhd_prot_process_d2h_host_ts_complete(dhd_pub_t *dhd, void* buf) ++{ ++#ifdef DHD_TIMESYNC ++ host_timestamp_msg_cpl_t *host_ts_cpl; ++ uint32 pktid; ++ dhd_prot_t *prot = dhd->prot; ++ ++ host_ts_cpl = (host_timestamp_msg_cpl_t *)buf; ++ DHD_INFO(("%s host TS cpl: status %d, req_ID: 0x%04x, xt_id %d \n", __FUNCTION__, ++ host_ts_cpl->cmplt.status, host_ts_cpl->msg.request_id, host_ts_cpl->xt_id)); ++ ++ pktid = ltoh32(host_ts_cpl->msg.request_id); ++ if (prot->hostts_req_buf_inuse == FALSE) { ++ DHD_ERROR(("No Pending Host TS req, but completion\n")); ++ return; ++ } ++ prot->hostts_req_buf_inuse = FALSE; ++ if (pktid != DHD_H2D_HOSTTS_REQ_PKTID) { ++ DHD_ERROR(("Host TS req CPL, but req ID different 0x%04x, exp 0x%04x\n", ++ pktid, DHD_H2D_HOSTTS_REQ_PKTID)); ++ return; ++ } ++ dhd_timesync_handle_host_ts_complete(dhd->ts, host_ts_cpl->xt_id, ++ host_ts_cpl->cmplt.status); ++#else /* DHD_TIMESYNC */ ++ DHD_ERROR(("Timesunc feature not compiled in but GOT HOST_TS_COMPLETE\n")); ++#endif /* DHD_TIMESYNC */ ++ ++} ++ ++/** called on e.g. flow ring delete */ ++void dhd_prot_clean_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info) ++{ ++ msgbuf_ring_t *flow_ring = (msgbuf_ring_t *)msgbuf_flow_info; ++ dhd_prot_ring_detach(dhd, flow_ring); ++ DHD_INFO(("%s Cleaning up Flow \n", __FUNCTION__)); ++} ++ ++void dhd_prot_print_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info, ++ struct bcmstrbuf *strbuf, const char * fmt) ++{ ++ const char *default_fmt = "RD %d WR %d BASE(VA) %p BASE(PA) %x:%x" ++ " WORK ITEM SIZE %d MAX WORK ITEMS %d SIZE %d\n"; ++ msgbuf_ring_t *flow_ring = (msgbuf_ring_t *)msgbuf_flow_info; ++ uint16 rd, wr; ++ uint32 dma_buf_len = flow_ring->max_items * flow_ring->item_len; ++ ++ if (fmt == NULL) { ++ fmt = default_fmt; ++ } ++ dhd_bus_cmn_readshared(dhd->bus, &rd, RING_RD_UPD, flow_ring->idx); ++ dhd_bus_cmn_readshared(dhd->bus, &wr, RING_WR_UPD, flow_ring->idx); ++ bcm_bprintf(strbuf, fmt, rd, wr, flow_ring->dma_buf.va, ++ ltoh32(flow_ring->base_addr.high_addr), ++ ltoh32(flow_ring->base_addr.low_addr), ++ flow_ring->item_len, flow_ring->max_items, dma_buf_len); ++} ++ ++void dhd_prot_print_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ bcm_bprintf(strbuf, "IPCrevs: Dev %d, \t Host %d, \tactive %d\n", ++ dhd->prot->device_ipc_version, ++ dhd->prot->host_ipc_version, ++ dhd->prot->active_ipc_version); ++ ++ bcm_bprintf(strbuf, "max Host TS bufs to post: %d, \t posted %d \n", ++ dhd->prot->max_tsbufpost, dhd->prot->cur_ts_bufs_posted); ++ bcm_bprintf(strbuf, "max INFO bufs to post: %d, \t posted %d \n", ++ dhd->prot->max_infobufpost, dhd->prot->infobufpost); ++ bcm_bprintf(strbuf, "max event bufs to post: %d, \t posted %d \n", ++ dhd->prot->max_eventbufpost, dhd->prot->cur_event_bufs_posted); ++ bcm_bprintf(strbuf, "max ioctlresp bufs to post: %d, \t posted %d \n", ++ dhd->prot->max_ioctlrespbufpost, dhd->prot->cur_ioctlresp_bufs_posted); ++ bcm_bprintf(strbuf, "max RX bufs to post: %d, \t posted %d \n", ++ dhd->prot->max_rxbufpost, dhd->prot->rxbufpost); ++ ++ bcm_bprintf(strbuf, ++ "%14s %5s %5s %17s %17s %14s %14s %10s\n", ++ "Type", "RD", "WR", "BASE(VA)", "BASE(PA)", ++ "WORK_ITEM_SIZE", "MAX_WORK_ITEMS", "TOTAL_SIZE"); ++ bcm_bprintf(strbuf, "%14s", "H2DCtrlPost"); ++ dhd_prot_print_flow_ring(dhd, &prot->h2dring_ctrl_subn, strbuf, ++ " %5d %5d %17p %8x:%8x %14d %14d %10d\n"); ++ bcm_bprintf(strbuf, "%14s", "D2HCtrlCpl"); ++ dhd_prot_print_flow_ring(dhd, &prot->d2hring_ctrl_cpln, strbuf, ++ " %5d %5d %17p %8x:%8x %14d %14d %10d\n"); ++ bcm_bprintf(strbuf, "%14s", "H2DRxPost", prot->rxbufpost); ++ dhd_prot_print_flow_ring(dhd, &prot->h2dring_rxp_subn, strbuf, ++ " %5d %5d %17p %8x:%8x %14d %14d %10d\n"); ++ bcm_bprintf(strbuf, "%14s", "D2HRxCpl"); ++ dhd_prot_print_flow_ring(dhd, &prot->d2hring_rx_cpln, strbuf, ++ " %5d %5d %17p %8x:%8x %14d %14d %10d\n"); ++ bcm_bprintf(strbuf, "%14s", "D2HTxCpl"); ++ dhd_prot_print_flow_ring(dhd, &prot->d2hring_tx_cpln, strbuf, ++ " %5d %5d %17p %8x:%8x %14d %14d %10d\n"); ++ if (dhd->prot->h2dring_info_subn != NULL && dhd->prot->d2hring_info_cpln != NULL) { ++ bcm_bprintf(strbuf, "%14s", "H2DRingInfoSub"); ++ dhd_prot_print_flow_ring(dhd, prot->h2dring_info_subn, strbuf, ++ " %5d %5d %17p %8x:%8x %14d %14d %10d\n"); ++ bcm_bprintf(strbuf, "%14s", "D2HRingInfoCpl"); ++ dhd_prot_print_flow_ring(dhd, prot->d2hring_info_cpln, strbuf, ++ " %5d %5d %17p %8x:%8x %14d %14d %10d\n"); ++ } ++ ++ bcm_bprintf(strbuf, "active_tx_count %d pktidmap_avail(ctrl/rx/tx) %d %d %d\n", ++ dhd->prot->active_tx_count, ++ DHD_PKTID_AVAIL(dhd->prot->pktid_ctrl_map), ++ DHD_PKTID_AVAIL(dhd->prot->pktid_rx_map), ++ DHD_PKTID_AVAIL(dhd->prot->pktid_tx_map)); ++ ++} ++ ++int ++dhd_prot_flow_ring_delete(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) ++{ ++ tx_flowring_delete_request_t *flow_delete_rqst; ++ dhd_prot_t *prot = dhd->prot; ++ unsigned long flags; ++ uint16 alloced = 0; ++ msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ /* Request for ring buffer space */ ++ flow_delete_rqst = (tx_flowring_delete_request_t *) ++ dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); ++ ++ if (flow_delete_rqst == NULL) { ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ DHD_ERROR(("%s: Flow Delete Req - failure ring space\n", __FUNCTION__)); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return BCME_NOMEM; ++ } ++ ++ /* Common msg buf hdr */ ++ flow_delete_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_DELETE; ++ flow_delete_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; ++ flow_delete_rqst->msg.request_id = htol32(0); /* TBD */ ++ flow_delete_rqst->msg.flags = ring->current_phase; ++ ++ flow_delete_rqst->msg.epoch = ring->seqnum % H2D_EPOCH_MODULO; ++ ring->seqnum++; ++ ++ /* Update Delete info */ ++ flow_delete_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); ++ flow_delete_rqst->reason = htol16(BCME_OK); ++ ++ DHD_ERROR(("%s: Send Flow Delete Req RING ID %d for peer " MACDBG ++ " prio %d ifindex %d\n", __FUNCTION__, flow_ring_node->flowid, ++ MAC2STRDBG(flow_ring_node->flow_info.da), flow_ring_node->flow_info.tid, ++ flow_ring_node->flow_info.ifindex)); ++ ++ /* update ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ring, flow_delete_rqst, 1); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return BCME_OK; ++} ++ ++static void ++dhd_prot_flow_ring_delete_response_process(dhd_pub_t *dhd, void *msg) ++{ ++ tx_flowring_delete_response_t *flow_delete_resp = (tx_flowring_delete_response_t *)msg; ++ ++ DHD_ERROR(("%s: Flow Delete Response status = %d Flow %d\n", __FUNCTION__, ++ flow_delete_resp->cmplt.status, flow_delete_resp->cmplt.flow_ring_id)); ++ ++ dhd_bus_flow_ring_delete_response(dhd->bus, flow_delete_resp->cmplt.flow_ring_id, ++ flow_delete_resp->cmplt.status); ++} ++ ++static void ++dhd_prot_process_flow_ring_resume_response(dhd_pub_t *dhd, void* msg) ++{ ++#ifdef IDLE_TX_FLOW_MGMT ++ tx_idle_flowring_resume_response_t *flow_resume_resp = ++ (tx_idle_flowring_resume_response_t *)msg; ++ ++ DHD_ERROR(("%s Flow resume Response status = %d Flow %d\n", __FUNCTION__, ++ flow_resume_resp->cmplt.status, flow_resume_resp->cmplt.flow_ring_id)); ++ ++ dhd_bus_flow_ring_resume_response(dhd->bus, flow_resume_resp->cmplt.flow_ring_id, ++ flow_resume_resp->cmplt.status); ++#endif /* IDLE_TX_FLOW_MGMT */ ++} ++ ++static void ++dhd_prot_process_flow_ring_suspend_response(dhd_pub_t *dhd, void* msg) ++{ ++#ifdef IDLE_TX_FLOW_MGMT ++ int16 status; ++ tx_idle_flowring_suspend_response_t *flow_suspend_resp = ++ (tx_idle_flowring_suspend_response_t *)msg; ++ status = flow_suspend_resp->cmplt.status; ++ ++ DHD_ERROR(("%s Flow id %d suspend Response status = %d\n", ++ __FUNCTION__, flow_suspend_resp->cmplt.flow_ring_id, ++ status)); ++ ++ if (status != BCME_OK) { ++ ++ DHD_ERROR(("%s Error in Suspending Flow rings!!" ++ "Dongle will still be polling idle rings!!Status = %d \n", ++ __FUNCTION__, status)); ++ } ++#endif /* IDLE_TX_FLOW_MGMT */ ++} ++ ++int ++dhd_prot_flow_ring_flush(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) ++{ ++ tx_flowring_flush_request_t *flow_flush_rqst; ++ dhd_prot_t *prot = dhd->prot; ++ unsigned long flags; ++ uint16 alloced = 0; ++ msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ /* Request for ring buffer space */ ++ flow_flush_rqst = (tx_flowring_flush_request_t *) ++ dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); ++ if (flow_flush_rqst == NULL) { ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ DHD_ERROR(("%s: Flow Flush Req - failure ring space\n", __FUNCTION__)); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return BCME_NOMEM; ++ } ++ ++ /* Common msg buf hdr */ ++ flow_flush_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_FLUSH; ++ flow_flush_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; ++ flow_flush_rqst->msg.request_id = htol32(0); /* TBD */ ++ flow_flush_rqst->msg.flags = ring->current_phase; ++ flow_flush_rqst->msg.epoch = ring->seqnum % H2D_EPOCH_MODULO; ++ ring->seqnum++; ++ ++ flow_flush_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); ++ flow_flush_rqst->reason = htol16(BCME_OK); ++ ++ DHD_INFO(("%s: Send Flow Flush Req\n", __FUNCTION__)); ++ ++ /* update ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ring, flow_flush_rqst, 1); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return BCME_OK; ++} /* dhd_prot_flow_ring_flush */ ++ ++static void ++dhd_prot_flow_ring_flush_response_process(dhd_pub_t *dhd, void *msg) ++{ ++ tx_flowring_flush_response_t *flow_flush_resp = (tx_flowring_flush_response_t *)msg; ++ ++ DHD_INFO(("%s: Flow Flush Response status = %d\n", __FUNCTION__, ++ flow_flush_resp->cmplt.status)); ++ ++ dhd_bus_flow_ring_flush_response(dhd->bus, flow_flush_resp->cmplt.flow_ring_id, ++ flow_flush_resp->cmplt.status); ++} ++ ++/** ++ * Request dongle to configure soft doorbells for D2H rings. Host populated soft ++ * doorbell information is transferred to dongle via the d2h ring config control ++ * message. ++ */ ++void ++dhd_msgbuf_ring_config_d2h_soft_doorbell(dhd_pub_t *dhd) ++{ ++#if defined(DHD_D2H_SOFT_DOORBELL_SUPPORT) ++ uint16 ring_idx; ++ uint8 *msg_next; ++ void *msg_start; ++ uint16 alloced = 0; ++ unsigned long flags; ++ dhd_prot_t *prot = dhd->prot; ++ ring_config_req_t *ring_config_req; ++ bcmpcie_soft_doorbell_t *soft_doorbell; ++ msgbuf_ring_t *ctrl_ring = &prot->h2dring_ctrl_subn; ++ const uint16 d2h_rings = BCMPCIE_D2H_COMMON_MSGRINGS; ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ /* Claim space for d2h_ring number of d2h_ring_config_req_t messages */ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ msg_start = dhd_prot_alloc_ring_space(dhd, ctrl_ring, d2h_rings, &alloced, TRUE); ++ ++ if (msg_start == NULL) { ++ DHD_ERROR(("%s Msgbuf no space for %d D2H ring config soft doorbells\n", ++ __FUNCTION__, d2h_rings)); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return; ++ } ++ ++ msg_next = (uint8*)msg_start; ++ ++ for (ring_idx = 0; ring_idx < d2h_rings; ring_idx++) { ++ ++ /* position the ring_config_req into the ctrl subm ring */ ++ ring_config_req = (ring_config_req_t *)msg_next; ++ ++ /* Common msg header */ ++ ring_config_req->msg.msg_type = MSG_TYPE_D2H_RING_CONFIG; ++ ring_config_req->msg.if_id = 0; ++ ring_config_req->msg.flags = 0; ++ ++ ring_config_req->msg.epoch = ctrl_ring->seqnum % H2D_EPOCH_MODULO; ++ ctrl_ring->seqnum++; ++ ++ ring_config_req->msg.request_id = htol32(DHD_FAKE_PKTID); /* unused */ ++ ++ /* Ring Config subtype and d2h ring_id */ ++ ring_config_req->subtype = htol16(D2H_RING_CONFIG_SUBTYPE_SOFT_DOORBELL); ++ ring_config_req->ring_id = htol16(DHD_D2H_RINGID(ring_idx)); ++ ++ /* Host soft doorbell configuration */ ++ soft_doorbell = &prot->soft_doorbell[ring_idx]; ++ ++ ring_config_req->soft_doorbell.value = htol32(soft_doorbell->value); ++ ring_config_req->soft_doorbell.haddr.high = ++ htol32(soft_doorbell->haddr.high); ++ ring_config_req->soft_doorbell.haddr.low = ++ htol32(soft_doorbell->haddr.low); ++ ring_config_req->soft_doorbell.items = htol16(soft_doorbell->items); ++ ring_config_req->soft_doorbell.msecs = htol16(soft_doorbell->msecs); ++ ++ DHD_INFO(("%s: Soft doorbell haddr 0x%08x 0x%08x value 0x%08x\n", ++ __FUNCTION__, ring_config_req->soft_doorbell.haddr.high, ++ ring_config_req->soft_doorbell.haddr.low, ++ ring_config_req->soft_doorbell.value)); ++ ++ msg_next = msg_next + ctrl_ring->item_len; ++ } ++ ++ /* update control subn ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ctrl_ring, msg_start, d2h_rings); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++#endif /* DHD_D2H_SOFT_DOORBELL_SUPPORT */ ++} ++ ++static void ++dhd_prot_process_d2h_ring_config_complete(dhd_pub_t *dhd, void *msg) ++{ ++ DHD_INFO(("%s: Ring Config Response - status %d ringid %d\n", ++ __FUNCTION__, ltoh16(((ring_config_resp_t *)msg)->compl_hdr.status), ++ ltoh16(((ring_config_resp_t *)msg)->compl_hdr.flow_ring_id))); ++} ++ ++int ++dhd_prot_debug_dma_info_print(dhd_pub_t *dhd) ++{ ++ if (dhd->bus->is_linkdown) { ++ DHD_ERROR(("\n ------- SKIP DUMPING DMA Registers " ++ "due to PCIe link down ------- \r\n")); ++ return 0; ++ } ++ ++ DHD_ERROR(("\n ------- DUMPING DMA Registers ------- \r\n")); ++ ++ //HostToDev ++ DHD_ERROR(("HostToDev TX: XmtCtrl=0x%08x XmtPtr=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x200, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x204, 0, 0))); ++ DHD_ERROR((" : XmtAddrLow=0x%08x XmtAddrHigh=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x208, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x20C, 0, 0))); ++ DHD_ERROR((" : XmtStatus0=0x%08x XmtStatus1=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x210, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x214, 0, 0))); ++ ++ DHD_ERROR(("HostToDev RX: RcvCtrl=0x%08x RcvPtr=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x220, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x224, 0, 0))); ++ DHD_ERROR((" : RcvAddrLow=0x%08x RcvAddrHigh=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x228, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x22C, 0, 0))); ++ DHD_ERROR((" : RcvStatus0=0x%08x RcvStatus1=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x230, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x234, 0, 0))); ++ ++ //DevToHost ++ DHD_ERROR(("DevToHost TX: XmtCtrl=0x%08x XmtPtr=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x240, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x244, 0, 0))); ++ DHD_ERROR((" : XmtAddrLow=0x%08x XmtAddrHigh=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x248, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x24C, 0, 0))); ++ DHD_ERROR((" : XmtStatus0=0x%08x XmtStatus1=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x250, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x254, 0, 0))); ++ ++ DHD_ERROR(("DevToHost RX: RcvCtrl=0x%08x RcvPtr=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x260, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x264, 0, 0))); ++ DHD_ERROR((" : RcvAddrLow=0x%08x RcvAddrHigh=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x268, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x26C, 0, 0))); ++ DHD_ERROR((" : RcvStatus0=0x%08x RcvStatus1=0x%08x\n", ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x270, 0, 0), ++ si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, 0x274, 0, 0))); ++ ++ return 0; ++} ++ ++int ++dhd_prot_debug_info_print(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ msgbuf_ring_t *ring; ++ uint16 rd, wr; ++ uint32 intstatus = 0; ++ uint32 intmask = 0; ++ uint32 mbintstatus = 0; ++ uint32 d2h_mb_data = 0; ++ uint32 dma_buf_len; ++ ++ DHD_ERROR(("\n ------- DUMPING VERSION INFORMATION ------- \r\n")); ++ DHD_ERROR(("DHD: %s\n", dhd_version)); ++ DHD_ERROR(("Firmware: %s\n", fw_version)); ++ ++ DHD_ERROR(("\n ------- DUMPING PROTOCOL INFORMATION ------- \r\n")); ++ DHD_ERROR(("ICPrevs: Dev %d, Host %d, active %d\n", ++ prot->device_ipc_version, ++ prot->host_ipc_version, ++ prot->active_ipc_version)); ++ DHD_ERROR(("max Host TS bufs to post: %d, posted %d\n", ++ prot->max_tsbufpost, prot->cur_ts_bufs_posted)); ++ DHD_ERROR(("max INFO bufs to post: %d, posted %d\n", ++ prot->max_infobufpost, prot->infobufpost)); ++ DHD_ERROR(("max event bufs to post: %d, posted %d\n", ++ prot->max_eventbufpost, prot->cur_event_bufs_posted)); ++ DHD_ERROR(("max ioctlresp bufs to post: %d, posted %d\n", ++ prot->max_ioctlrespbufpost, prot->cur_ioctlresp_bufs_posted)); ++ DHD_ERROR(("max RX bufs to post: %d, posted %d\n", ++ prot->max_rxbufpost, prot->rxbufpost)); ++ DHD_ERROR(("h2d_max_txpost: %d, prot->h2d_max_txpost: %d\n", ++ h2d_max_txpost, prot->h2d_max_txpost)); ++ ++ DHD_ERROR(("\n ------- DUMPING IOCTL RING RD WR Pointers ------- \r\n")); ++ ++ ring = &prot->h2dring_ctrl_subn; ++ dma_buf_len = ring->max_items * ring->item_len; ++ DHD_ERROR(("CtrlPost: Mem Info: BASE(VA) %p BASE(PA) %x:%x SIZE %d \r\n", ++ ring->dma_buf.va, ltoh32(ring->base_addr.high_addr), ++ ltoh32(ring->base_addr.low_addr), dma_buf_len)); ++ DHD_ERROR(("CtrlPost: From Host mem: RD: %d WR %d \r\n", ring->rd, ring->wr)); ++ dhd_bus_cmn_readshared(dhd->bus, &rd, RING_RD_UPD, ring->idx); ++ dhd_bus_cmn_readshared(dhd->bus, &wr, RING_WR_UPD, ring->idx); ++ DHD_ERROR(("CtrlPost: From Shared Mem: RD: %d WR %d \r\n", rd, wr)); ++ DHD_ERROR(("CtrlPost: seq num: %d \r\n", ring->seqnum % H2D_EPOCH_MODULO)); ++ ++ ring = &prot->d2hring_ctrl_cpln; ++ dma_buf_len = ring->max_items * ring->item_len; ++ DHD_ERROR(("CtrlCpl: Mem Info: BASE(VA) %p BASE(PA) %x:%x SIZE %d \r\n", ++ ring->dma_buf.va, ltoh32(ring->base_addr.high_addr), ++ ltoh32(ring->base_addr.low_addr), dma_buf_len)); ++ DHD_ERROR(("CtrlCpl: From Host mem: RD: %d WR %d \r\n", ring->rd, ring->wr)); ++ dhd_bus_cmn_readshared(dhd->bus, &rd, RING_RD_UPD, ring->idx); ++ dhd_bus_cmn_readshared(dhd->bus, &wr, RING_WR_UPD, ring->idx); ++ DHD_ERROR(("CtrlCpl: From Shared Mem: RD: %d WR %d \r\n", rd, wr)); ++ DHD_ERROR(("CtrlCpl: Expected seq num: %d \r\n", ring->seqnum % H2D_EPOCH_MODULO)); ++ ++ ring = prot->h2dring_info_subn; ++ if (ring) { ++ dma_buf_len = ring->max_items * ring->item_len; ++ DHD_ERROR(("InfoSub: Mem Info: BASE(VA) %p BASE(PA) %x:%x SIZE %d \r\n", ++ ring->dma_buf.va, ltoh32(ring->base_addr.high_addr), ++ ltoh32(ring->base_addr.low_addr), dma_buf_len)); ++ DHD_ERROR(("InfoSub: From Host mem: RD: %d WR %d \r\n", ring->rd, ring->wr)); ++ dhd_bus_cmn_readshared(dhd->bus, &rd, RING_RD_UPD, ring->idx); ++ dhd_bus_cmn_readshared(dhd->bus, &wr, RING_WR_UPD, ring->idx); ++ DHD_ERROR(("InfoSub: From Shared Mem: RD: %d WR %d \r\n", rd, wr)); ++ DHD_ERROR(("InfoSub: seq num: %d \r\n", ring->seqnum % H2D_EPOCH_MODULO)); ++ } ++ ring = prot->d2hring_info_cpln; ++ if (ring) { ++ dma_buf_len = ring->max_items * ring->item_len; ++ DHD_ERROR(("InfoCpl: Mem Info: BASE(VA) %p BASE(PA) %x:%x SIZE %d \r\n", ++ ring->dma_buf.va, ltoh32(ring->base_addr.high_addr), ++ ltoh32(ring->base_addr.low_addr), dma_buf_len)); ++ DHD_ERROR(("InfoCpl: From Host mem: RD: %d WR %d \r\n", ring->rd, ring->wr)); ++ dhd_bus_cmn_readshared(dhd->bus, &rd, RING_RD_UPD, ring->idx); ++ dhd_bus_cmn_readshared(dhd->bus, &wr, RING_WR_UPD, ring->idx); ++ DHD_ERROR(("InfoCpl: From Shared Mem: RD: %d WR %d \r\n", rd, wr)); ++ DHD_ERROR(("InfoCpl: Expected seq num: %d \r\n", ring->seqnum % H2D_EPOCH_MODULO)); ++ } ++ ++ DHD_ERROR(("%s: cur_ioctlresp_bufs_posted %d cur_event_bufs_posted %d\n", ++ __FUNCTION__, prot->cur_ioctlresp_bufs_posted, prot->cur_event_bufs_posted)); ++ ++ if (!dhd->bus->is_linkdown && dhd->bus->intstatus != (uint32)-1) { ++ DHD_ERROR(("\n ------- DUMPING INTR Status and Masks ------- \r\n")); ++ intstatus = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, ++ PCIMailBoxInt, 0, 0); ++ intmask = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, ++ PCIMailBoxMask, 0, 0); ++ mbintstatus = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, ++ PCID2H_MailBox, 0, 0); ++ dhd_bus_cmn_readshared(dhd->bus, &d2h_mb_data, D2H_MB_DATA, 0); ++ ++ DHD_ERROR(("intstatus=0x%x intmask=0x%x mbintstatus=0x%x\n", ++ intstatus, intmask, mbintstatus)); ++ DHD_ERROR(("d2h_mb_data=0x%x def_intmask=0x%x \r\n", d2h_mb_data, ++ dhd->bus->def_intmask)); ++ ++ DHD_ERROR(("host pcie_irq enabled = %d\n", dhdpcie_irq_enabled(dhd->bus))); ++ ++ DHD_ERROR(("\n ------- DUMPING PCIE Registers ------- \r\n")); ++ /* hwnbu-twiki.sj.broadcom.com/bin/view/Mwgroup/CurrentPcieGen2ProgramGuide */ ++ DHD_ERROR(("Status Command(0x%x)=0x%x, BaseAddress0(0x%x)=0x%x\n", ++ PCIECFGREG_STATUS_CMD, ++ dhd_pcie_config_read(dhd->bus->osh, PCIECFGREG_STATUS_CMD, sizeof(uint32)), ++ PCIECFGREG_BASEADDR0, ++ dhd_pcie_config_read(dhd->bus->osh, PCIECFGREG_BASEADDR0, sizeof(uint32)))); ++ DHD_ERROR(("LinkCtl(0x%x)=0x%x DeviceStatusControl2(0x%x)=0x%x " ++ "L1SSControl(0x%x)=0x%x\n", PCIECFGREG_LINK_STATUS_CTRL, ++ dhd_pcie_config_read(dhd->bus->osh, PCIECFGREG_LINK_STATUS_CTRL, ++ sizeof(uint32)), PCIECFGGEN_DEV_STATUS_CTRL2, ++ dhd_pcie_config_read(dhd->bus->osh, PCIECFGGEN_DEV_STATUS_CTRL2, ++ sizeof(uint32)), PCIECFGREG_PML1_SUB_CTRL1, ++ dhd_pcie_config_read(dhd->bus->osh, PCIECFGREG_PML1_SUB_CTRL1, ++ sizeof(uint32)))); ++ ++ /* hwnbu-twiki.sj.broadcom.com/twiki/pub/Mwgroup/ ++ * CurrentPcieGen2ProgramGuide/pcie_ep.htm ++ */ ++ DHD_ERROR(("ClkReq0(0x%x)=0x%x ClkReq1(0x%x)=0x%x ClkReq2(0x%x)=0x%x " ++ "ClkReq3(0x%x)=0x%x\n", PCIECFGREG_PHY_DBG_CLKREQ0, ++ dhd_pcie_corereg_read(dhd->bus->sih, PCIECFGREG_PHY_DBG_CLKREQ0), ++ PCIECFGREG_PHY_DBG_CLKREQ1, ++ dhd_pcie_corereg_read(dhd->bus->sih, PCIECFGREG_PHY_DBG_CLKREQ1), ++ PCIECFGREG_PHY_DBG_CLKREQ2, ++ dhd_pcie_corereg_read(dhd->bus->sih, PCIECFGREG_PHY_DBG_CLKREQ2), ++ PCIECFGREG_PHY_DBG_CLKREQ3, ++ dhd_pcie_corereg_read(dhd->bus->sih, PCIECFGREG_PHY_DBG_CLKREQ3))); ++ ++#if defined(PCIE_RC_VENDOR_ID) && defined(PCIE_RC_DEVICE_ID) ++ DHD_ERROR(("Pcie RC Error Status Val=0x%x\n", ++ dhdpcie_rc_access_cap(dhd->bus, PCIE_EXTCAP_ID_ERR, ++ PCIE_EXTCAP_AER_UCERR_OFFSET, TRUE, FALSE, 0))); ++ ++ DHD_ERROR(("RootPort PCIe linkcap=0x%08x\n", ++ dhd_debug_get_rc_linkcap(dhd->bus))); ++#endif ++ ++ DHD_ERROR(("\n ------- DUMPING INTR enable/disable counters ------- \r\n")); ++ DHD_ERROR(("resume_intr_enable_count=%lu dpc_intr_enable_count=%lu\n" ++ "isr_intr_disable_count=%lu suspend_intr_disable_count=%lu\n" ++ "dpc_return_busdown_count=%lu\n", ++ dhd->bus->resume_intr_enable_count, dhd->bus->dpc_intr_enable_count, ++ dhd->bus->isr_intr_disable_count, dhd->bus->suspend_intr_disable_count, ++ dhd->bus->dpc_return_busdown_count)); ++ ++ } ++ dhd_prot_debug_dma_info_print(dhd); ++#ifdef DHD_FW_COREDUMP ++ if (dhd->memdump_enabled) { ++#ifdef DHD_SSSR_DUMP ++ if (dhd->sssr_inited) { ++ dhdpcie_sssr_dump(dhd); ++ } ++#endif /* DHD_SSSR_DUMP */ ++ } ++#endif /* DHD_FW_COREDUMP */ ++ return 0; ++} ++ ++int ++dhd_prot_ringupd_dump(dhd_pub_t *dhd, struct bcmstrbuf *b) ++{ ++ uint32 *ptr; ++ uint32 value; ++ uint32 i; ++ uint32 max_h2d_queues = dhd_bus_max_h2d_queues(dhd->bus); ++ ++ OSL_CACHE_INV((void *)dhd->prot->d2h_dma_indx_wr_buf.va, ++ dhd->prot->d2h_dma_indx_wr_buf.len); ++ ++ ptr = (uint32 *)(dhd->prot->d2h_dma_indx_wr_buf.va); ++ ++ bcm_bprintf(b, "\n max_tx_queues %d\n", max_h2d_queues); ++ ++ bcm_bprintf(b, "\nRPTR block H2D common rings, 0x%04x\n", ptr); ++ value = ltoh32(*ptr); ++ bcm_bprintf(b, "\tH2D CTRL: value 0x%04x\n", value); ++ ptr++; ++ value = ltoh32(*ptr); ++ bcm_bprintf(b, "\tH2D RXPOST: value 0x%04x\n", value); ++ ++ ptr++; ++ bcm_bprintf(b, "RPTR block Flow rings , 0x%04x\n", ptr); ++ for (i = BCMPCIE_H2D_COMMON_MSGRINGS; i < max_h2d_queues; i++) { ++ value = ltoh32(*ptr); ++ bcm_bprintf(b, "\tflowring ID %d: value 0x%04x\n", i, value); ++ ptr++; ++ } ++ ++ OSL_CACHE_INV((void *)dhd->prot->h2d_dma_indx_rd_buf.va, ++ dhd->prot->h2d_dma_indx_rd_buf.len); ++ ++ ptr = (uint32 *)(dhd->prot->h2d_dma_indx_rd_buf.va); ++ ++ bcm_bprintf(b, "\nWPTR block D2H common rings, 0x%04x\n", ptr); ++ value = ltoh32(*ptr); ++ bcm_bprintf(b, "\tD2H CTRLCPLT: value 0x%04x\n", value); ++ ptr++; ++ value = ltoh32(*ptr); ++ bcm_bprintf(b, "\tD2H TXCPLT: value 0x%04x\n", value); ++ ptr++; ++ value = ltoh32(*ptr); ++ bcm_bprintf(b, "\tD2H RXCPLT: value 0x%04x\n", value); ++ ++ return 0; ++} ++ ++uint32 ++dhd_prot_metadata_dbg_set(dhd_pub_t *dhd, bool val) ++{ ++ dhd_prot_t *prot = dhd->prot; ++#if DHD_DBG_SHOW_METADATA ++ prot->metadata_dbg = val; ++#endif ++ return (uint32)prot->metadata_dbg; ++} ++ ++uint32 ++dhd_prot_metadata_dbg_get(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ return (uint32)prot->metadata_dbg; ++} ++ ++uint32 ++dhd_prot_metadatalen_set(dhd_pub_t *dhd, uint32 val, bool rx) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ if (rx) ++ prot->rx_metadata_offset = (uint16)val; ++ else ++ prot->tx_metadata_offset = (uint16)val; ++ return dhd_prot_metadatalen_get(dhd, rx); ++} ++ ++uint32 ++dhd_prot_metadatalen_get(dhd_pub_t *dhd, bool rx) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ if (rx) ++ return prot->rx_metadata_offset; ++ else ++ return prot->tx_metadata_offset; ++} ++ ++/** optimization to write "n" tx items at a time to ring */ ++uint32 ++dhd_prot_txp_threshold(dhd_pub_t *dhd, bool set, uint32 val) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ if (set) ++ prot->txp_threshold = (uint16)val; ++ val = prot->txp_threshold; ++ return val; ++} ++ ++#ifdef DHD_RX_CHAINING ++ ++static INLINE void BCMFASTPATH ++dhd_rxchain_reset(rxchain_info_t *rxchain) ++{ ++ rxchain->pkt_count = 0; ++} ++ ++static void BCMFASTPATH ++dhd_rxchain_frame(dhd_pub_t *dhd, void *pkt, uint ifidx) ++{ ++ uint8 *eh; ++ uint8 prio; ++ dhd_prot_t *prot = dhd->prot; ++ rxchain_info_t *rxchain = &prot->rxchain; ++ ++ ASSERT(!PKTISCHAINED(pkt)); ++ ASSERT(PKTCLINK(pkt) == NULL); ++ ASSERT(PKTCGETATTR(pkt) == 0); ++ ++ eh = PKTDATA(dhd->osh, pkt); ++ prio = IP_TOS46(eh + ETHER_HDR_LEN) >> IPV4_TOS_PREC_SHIFT; ++ ++ if (rxchain->pkt_count && !(PKT_CTF_CHAINABLE(dhd, ifidx, eh, prio, rxchain->h_sa, ++ rxchain->h_da, rxchain->h_prio))) { ++ /* Different flow - First release the existing chain */ ++ dhd_rxchain_commit(dhd); ++ } ++ ++ /* For routers, with HNDCTF, link the packets using PKTSETCLINK, */ ++ /* so that the chain can be handed off to CTF bridge as is. */ ++ if (rxchain->pkt_count == 0) { ++ /* First packet in chain */ ++ rxchain->pkthead = rxchain->pkttail = pkt; ++ ++ /* Keep a copy of ptr to ether_da, ether_sa and prio */ ++ rxchain->h_da = ((struct ether_header *)eh)->ether_dhost; ++ rxchain->h_sa = ((struct ether_header *)eh)->ether_shost; ++ rxchain->h_prio = prio; ++ rxchain->ifidx = ifidx; ++ rxchain->pkt_count++; ++ } else { ++ /* Same flow - keep chaining */ ++ PKTSETCLINK(rxchain->pkttail, pkt); ++ rxchain->pkttail = pkt; ++ rxchain->pkt_count++; ++ } ++ ++ if ((dhd_rx_pkt_chainable(dhd, ifidx)) && (!ETHER_ISMULTI(rxchain->h_da)) && ++ ((((struct ether_header *)eh)->ether_type == HTON16(ETHER_TYPE_IP)) || ++ (((struct ether_header *)eh)->ether_type == HTON16(ETHER_TYPE_IPV6)))) { ++ PKTSETCHAINED(dhd->osh, pkt); ++ PKTCINCRCNT(rxchain->pkthead); ++ PKTCADDLEN(rxchain->pkthead, PKTLEN(dhd->osh, pkt)); ++ } else { ++ dhd_rxchain_commit(dhd); ++ return; ++ } ++ ++ /* If we have hit the max chain length, dispatch the chain and reset */ ++ if (rxchain->pkt_count >= DHD_PKT_CTF_MAX_CHAIN_LEN) { ++ dhd_rxchain_commit(dhd); ++ } ++} ++ ++static void BCMFASTPATH ++dhd_rxchain_commit(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ rxchain_info_t *rxchain = &prot->rxchain; ++ ++ if (rxchain->pkt_count == 0) ++ return; ++ ++ /* Release the packets to dhd_linux */ ++ dhd_bus_rx_frame(dhd->bus, rxchain->pkthead, rxchain->ifidx, rxchain->pkt_count); ++ ++ /* Reset the chain */ ++ dhd_rxchain_reset(rxchain); ++} ++ ++#endif /* DHD_RX_CHAINING */ ++ ++ ++#ifdef IDLE_TX_FLOW_MGMT ++int ++dhd_prot_flow_ring_resume(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node) ++{ ++ tx_idle_flowring_resume_request_t *flow_resume_rqst; ++ msgbuf_ring_t *flow_ring; ++ dhd_prot_t *prot = dhd->prot; ++ unsigned long flags; ++ uint16 alloced = 0; ++ msgbuf_ring_t *ctrl_ring = &prot->h2dring_ctrl_subn; ++ ++ /* Fetch a pre-initialized msgbuf_ring from the flowring pool */ ++ flow_ring = dhd_prot_flowrings_pool_fetch(dhd, flow_ring_node->flowid); ++ if (flow_ring == NULL) { ++ DHD_ERROR(("%s: dhd_prot_flowrings_pool_fetch TX Flowid %d failed\n", ++ __FUNCTION__, flow_ring_node->flowid)); ++ return BCME_NOMEM; ++ } ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ /* Request for ctrl_ring buffer space */ ++ flow_resume_rqst = (tx_idle_flowring_resume_request_t *) ++ dhd_prot_alloc_ring_space(dhd, ctrl_ring, 1, &alloced, FALSE); ++ ++ if (flow_resume_rqst == NULL) { ++ dhd_prot_flowrings_pool_release(dhd, flow_ring_node->flowid, flow_ring); ++ DHD_ERROR(("%s: Flow resume Req flowid %d - failure ring space\n", ++ __FUNCTION__, flow_ring_node->flowid)); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return BCME_NOMEM; ++ } ++ ++ flow_ring_node->prot_info = (void *)flow_ring; ++ ++ /* Common msg buf hdr */ ++ flow_resume_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_RESUME; ++ flow_resume_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; ++ flow_resume_rqst->msg.request_id = htol32(0); /* TBD */ ++ ++ flow_resume_rqst->msg.epoch = ctrl_ring->seqnum % H2D_EPOCH_MODULO; ++ ctrl_ring->seqnum++; ++ ++ flow_resume_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid); ++ DHD_ERROR(("%s Send Flow resume Req flow ID %d\n", ++ __FUNCTION__, flow_ring_node->flowid)); ++ ++ /* Update the flow_ring's WRITE index */ ++ if (IDMA_ACTIVE(dhd) || dhd->dma_h2d_ring_upd_support) { ++ dhd_prot_dma_indx_set(dhd, flow_ring->wr, ++ H2D_DMA_INDX_WR_UPD, flow_ring->idx); ++ } else if (IFRM_ACTIVE(dhd) && (flow_ring->idx >= BCMPCIE_H2D_MSGRING_TXFLOW_IDX_START)) { ++ dhd_prot_dma_indx_set(dhd, flow_ring->wr, ++ H2D_IFRM_INDX_WR_UPD, ++ (flow_ring->idx - BCMPCIE_H2D_MSGRING_TXFLOW_IDX_START)); ++ } else { ++ dhd_bus_cmn_writeshared(dhd->bus, &(flow_ring->wr), ++ sizeof(uint16), RING_WR_UPD, flow_ring->idx); ++ } ++ ++ /* update control subn ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ctrl_ring, flow_resume_rqst, 1); ++ ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return BCME_OK; ++} /* dhd_prot_flow_ring_create */ ++ ++int ++dhd_prot_flow_ring_batch_suspend_request(dhd_pub_t *dhd, uint16 *ringid, uint16 count) ++{ ++ tx_idle_flowring_suspend_request_t *flow_suspend_rqst; ++ dhd_prot_t *prot = dhd->prot; ++ unsigned long flags; ++ uint16 index; ++ uint16 alloced = 0; ++ msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; ++ ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ /* Request for ring buffer space */ ++ flow_suspend_rqst = (tx_idle_flowring_suspend_request_t *) ++ dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); ++ ++ if (flow_suspend_rqst == NULL) { ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ DHD_ERROR(("%s: Flow suspend Req - failure ring space\n", __FUNCTION__)); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ return BCME_NOMEM; ++ } ++ ++ /* Common msg buf hdr */ ++ flow_suspend_rqst->msg.msg_type = MSG_TYPE_FLOW_RING_SUSPEND; ++ /* flow_suspend_rqst->msg.if_id = (uint8)flow_ring_node->flow_info.ifindex; */ ++ flow_suspend_rqst->msg.request_id = htol32(0); /* TBD */ ++ ++ flow_suspend_rqst->msg.epoch = ring->seqnum % H2D_EPOCH_MODULO; ++ ring->seqnum++; ++ ++ /* Update flow id info */ ++ for (index = 0; index < count; index++) ++ { ++ flow_suspend_rqst->ring_id[index] = ringid[index]; ++ } ++ flow_suspend_rqst->num = count; ++ ++ DHD_ERROR(("%s sending batch suspend!! count is %d\n", __FUNCTION__, count)); ++ ++ /* update ring's WR index and ring doorbell to dongle */ ++ dhd_prot_ring_write_complete(dhd, ring, flow_suspend_rqst, 1); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); ++#endif ++ ++ return BCME_OK; ++} ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++ ++int dhd_prot_dump_extended_trap(dhd_pub_t *dhdp, struct bcmstrbuf *b, bool raw) ++{ ++ uint32 i; ++ uint32 *ext_data; ++ hnd_ext_trap_hdr_t *hdr; ++ bcm_tlv_t *tlv; ++ trap_t *tr; ++ uint32 *stack; ++ hnd_ext_trap_bp_err_t *bpe; ++ uint32 raw_len; ++ ++ ext_data = dhdp->extended_trap_data; ++ ++ /* return if there is no extended trap data */ ++ if (!ext_data || !(dhdp->dongle_trap_data & D2H_DEV_EXT_TRAP_DATA)) ++ { ++ bcm_bprintf(b, "%d (0x%x)", dhdp->dongle_trap_data, dhdp->dongle_trap_data); ++ return BCME_OK; ++ } ++ ++ bcm_bprintf(b, "Extended trap data\n"); ++ ++ /* First word is original trap_data */ ++ bcm_bprintf(b, "trap_data = 0x%08x\n", *ext_data); ++ ext_data++; ++ ++ /* Followed by the extended trap data header */ ++ hdr = (hnd_ext_trap_hdr_t *)ext_data; ++ bcm_bprintf(b, "version: %d, len: %d\n", hdr->version, hdr->len); ++ ++ if (raw) ++ { ++ raw_len = sizeof(hnd_ext_trap_hdr_t) + (hdr->len / 4) + (hdr->len % 4 ? 1 : 0); ++ for (i = 0; i < raw_len; i++) ++ { ++ bcm_bprintf(b, "0x%08x ", ext_data[i]); ++ if (i % 4 == 3) ++ bcm_bprintf(b, "\n"); ++ } ++ return BCME_OK; ++ } ++ ++ /* Extract the various supported TLVs from the extended trap data */ ++ tlv = bcm_parse_tlvs(hdr->data, hdr->len, TAG_TRAP_SIGNATURE); ++ if (tlv) ++ { ++ bcm_bprintf(b, "\nTAG_TRAP_SIGNATURE len: %d\n", tlv->len); ++ tr = (trap_t *)tlv->data; ++ ++ bcm_bprintf(b, "TRAP %x: pc %x, lr %x, sp %x, cpsr %x, spsr %x\n", ++ tr->type, tr->pc, tr->r14, tr->r13, tr->cpsr, tr->spsr); ++ bcm_bprintf(b, " r0 %x, r1 %x, r2 %x, r3 %x, r4 %x, r5 %x, r6 %x\n", ++ tr->r0, tr->r1, tr->r2, tr->r3, tr->r4, tr->r5, tr->r6); ++ bcm_bprintf(b, " r7 %x, r8 %x, r9 %x, r10 %x, r11 %x, r12 %x\n", ++ tr->r7, tr->r8, tr->r9, tr->r10, tr->r11, tr->r12); ++ } ++ ++ tlv = bcm_parse_tlvs(hdr->data, hdr->len, TAG_TRAP_STACK); ++ if (tlv) ++ { ++ bcm_bprintf(b, "\nTAG_TRAP_STACK len: %d\n", tlv->len); ++ stack = (uint32 *)tlv->data; ++ for (i = 0; i < (uint32)(tlv->len / 4); i++) ++ { ++ bcm_bprintf(b, " 0x%08x\n", *stack); ++ stack++; ++ } ++ } ++ ++ tlv = bcm_parse_tlvs(hdr->data, hdr->len, TAG_TRAP_BACKPLANE); ++ if (tlv) ++ { ++ bcm_bprintf(b, "\nTAG_TRAP_BACKPLANE len: %d\n", tlv->len); ++ bpe = (hnd_ext_trap_bp_err_t *)tlv->data; ++ bcm_bprintf(b, " error: %x\n", bpe->error); ++ bcm_bprintf(b, " coreid: %x\n", bpe->coreid); ++ bcm_bprintf(b, " baseaddr: %x\n", bpe->baseaddr); ++ bcm_bprintf(b, " ioctrl: %x\n", bpe->ioctrl); ++ bcm_bprintf(b, " iostatus: %x\n", bpe->iostatus); ++ bcm_bprintf(b, " resetctrl: %x\n", bpe->resetctrl); ++ bcm_bprintf(b, " resetstatus: %x\n", bpe->resetstatus); ++ bcm_bprintf(b, " errlogctrl: %x\n", bpe->errlogctrl); ++ bcm_bprintf(b, " errlogdone: %x\n", bpe->errlogdone); ++ bcm_bprintf(b, " errlogstatus: %x\n", bpe->errlogstatus); ++ bcm_bprintf(b, " errlogaddrlo: %x\n", bpe->errlogaddrlo); ++ bcm_bprintf(b, " errlogaddrhi: %x\n", bpe->errlogaddrhi); ++ bcm_bprintf(b, " errlogid: %x\n", bpe->errlogid); ++ bcm_bprintf(b, " errloguser: %x\n", bpe->errloguser); ++ bcm_bprintf(b, " errlogflags: %x\n", bpe->errlogflags); ++ } ++ ++ return BCME_OK; ++} ++ ++ ++#ifdef BCMPCIE ++int ++dhd_prot_send_host_timestamp(dhd_pub_t *dhdp, uchar *tlvs, uint16 tlv_len, ++ uint16 seqnum, uint16 xt_id) ++{ ++ dhd_prot_t *prot = dhdp->prot; ++ host_timestamp_msg_t *ts_req; ++ unsigned long flags; ++ uint16 alloced = 0; ++ uchar *ts_tlv_buf; ++ ++ if ((tlvs == NULL) || (tlv_len == 0)) { ++ DHD_ERROR(("%s: argument error tlv: %p, tlv_len %d\n", ++ __FUNCTION__, tlvs, tlv_len)); ++ return -1; ++ } ++#ifdef PCIE_INB_DW ++ if (dhd_prot_inc_hostactive_devwake_assert(dhdp->bus) != BCME_OK) ++ return BCME_ERROR; ++#endif /* PCIE_INB_DW */ ++ ++ DHD_GENERAL_LOCK(dhdp, flags); ++ ++ /* if Host TS req already pending go away */ ++ if (prot->hostts_req_buf_inuse == TRUE) { ++ DHD_ERROR(("one host TS request already pending at device\n")); ++ DHD_GENERAL_UNLOCK(dhdp, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhdp->bus); ++#endif ++ return -1; ++ } ++ ++ /* Request for cbuf space */ ++ ts_req = (host_timestamp_msg_t*)dhd_prot_alloc_ring_space(dhdp, &prot->h2dring_ctrl_subn, ++ DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced, FALSE); ++ if (ts_req == NULL) { ++ DHD_ERROR(("couldn't allocate space on msgring to send host TS request\n")); ++ DHD_GENERAL_UNLOCK(dhdp, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhdp->bus); ++#endif ++ return -1; ++ } ++ ++ /* Common msg buf hdr */ ++ ts_req->msg.msg_type = MSG_TYPE_HOSTTIMSTAMP; ++ ts_req->msg.if_id = 0; ++ ts_req->msg.flags = prot->h2dring_ctrl_subn.current_phase; ++ ts_req->msg.request_id = DHD_H2D_HOSTTS_REQ_PKTID; ++ ++ ts_req->msg.epoch = prot->h2dring_ctrl_subn.seqnum % H2D_EPOCH_MODULO; ++ prot->h2dring_ctrl_subn.seqnum++; ++ ++ ts_req->xt_id = xt_id; ++ ts_req->seqnum = seqnum; ++ /* populate TS req buffer info */ ++ ts_req->input_data_len = htol16(tlv_len); ++ ts_req->host_buf_addr.high = htol32(PHYSADDRHI(prot->hostts_req_buf.pa)); ++ ts_req->host_buf_addr.low = htol32(PHYSADDRLO(prot->hostts_req_buf.pa)); ++ /* copy ioct payload */ ++ ts_tlv_buf = (void *) prot->hostts_req_buf.va; ++ prot->hostts_req_buf_inuse = TRUE; ++ memcpy(ts_tlv_buf, tlvs, tlv_len); ++ ++ OSL_CACHE_FLUSH((void *) prot->hostts_req_buf.va, tlv_len); ++ ++ if (ISALIGNED(ts_tlv_buf, DMA_ALIGN_LEN) == FALSE) { ++ DHD_ERROR(("host TS req buffer address unaligned !!!!! \n")); ++ } ++ ++ DHD_CTL(("submitted Host TS request request_id %d, data_len %d, tx_id %d, seq %d\n", ++ ts_req->msg.request_id, ts_req->input_data_len, ++ ts_req->xt_id, ts_req->seqnum)); ++ ++ ++ /* upd wrt ptr and raise interrupt */ ++ dhd_prot_ring_write_complete(dhdp, &prot->h2dring_ctrl_subn, ts_req, ++ DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); ++ DHD_GENERAL_UNLOCK(dhdp, flags); ++#ifdef PCIE_INB_DW ++ dhd_prot_dec_hostactive_ack_pending_dsreq(dhdp->bus); ++#endif ++ ++ return 0; ++} /* dhd_prot_send_host_timestamp */ ++ ++ ++bool ++dhd_prot_data_path_tx_timestamp_logging(dhd_pub_t *dhd, bool enable, bool set) ++{ ++ if (set) ++ dhd->prot->tx_ts_log_enabled = enable; ++ ++ return dhd->prot->tx_ts_log_enabled; ++} ++ ++bool ++dhd_prot_data_path_rx_timestamp_logging(dhd_pub_t *dhd, bool enable, bool set) ++{ ++ if (set) ++ dhd->prot->rx_ts_log_enabled = enable; ++ ++ return dhd->prot->rx_ts_log_enabled; ++} ++#endif /* BCMPCIE */ ++ ++void ++dhd_prot_dma_indx_free(dhd_pub_t *dhd) ++{ ++ dhd_prot_t *prot = dhd->prot; ++ ++ dhd_dma_buf_free(dhd, &prot->h2d_dma_indx_wr_buf); ++ dhd_dma_buf_free(dhd, &prot->d2h_dma_indx_rd_buf); ++} ++ ++static void BCMFASTPATH ++dhd_prot_process_fw_timestamp(dhd_pub_t *dhd, void* buf) ++{ ++#ifdef DHD_TIMESYNC ++ fw_timestamp_event_msg_t *resp; ++ uint32 pktid; ++ uint16 buflen, seqnum; ++ void * pkt; ++ unsigned long flags; ++ ++ resp = (fw_timestamp_event_msg_t *)buf; ++ pktid = ltoh32(resp->msg.request_id); ++ buflen = ltoh16(resp->buf_len); ++ seqnum = ltoh16(resp->seqnum); ++ ++#if defined(DHD_PKTID_AUDIT_RING) ++ DHD_PKTID_AUDIT(dhd, dhd->prot->pktid_ctrl_map, pktid, ++ DHD_DUPLICATE_FREE); ++#endif /* DHD_PKTID_AUDIT_RING */ ++ ++ DHD_INFO(("id 0x%04x, len %d, phase 0x%02x, seqnum %d\n", ++ pktid, buflen, resp->msg.flags, ltoh16(resp->seqnum))); ++ ++ if (!dhd->prot->cur_ts_bufs_posted) { ++ DHD_ERROR(("tsbuf posted are zero, but there is a completion\n")); ++ return; ++ } ++ ++ dhd->prot->cur_ts_bufs_posted--; ++ if (dhd->prot->max_tsbufpost > 0) ++ dhd_msgbuf_rxbuf_post_ts_bufs(dhd); ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ pkt = dhd_prot_packet_get(dhd, pktid, PKTTYPE_TSBUF_RX, TRUE); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ if (!pkt) { ++ DHD_ERROR(("no ts buffer associated with pktid 0x%04x\n", pktid)); ++ return; ++ } ++ ++ PKTSETLEN(dhd->osh, pkt, buflen); ++ dhd_timesync_handle_fw_timestamp(dhd->ts, PKTDATA(dhd->osh, pkt), buflen, seqnum); ++#ifdef DHD_USE_STATIC_CTRLBUF ++ PKTFREE_STATIC(dhd->osh, pkt, TRUE); ++#else ++ PKTFREE(dhd->osh, pkt, TRUE); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++#else /* DHD_TIMESYNC */ ++ DHD_ERROR(("Timesunc feature not compiled in but GOT FW TS message\n")); ++#endif /* DHD_TIMESYNC */ ++ ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie.c +new file mode 100644 +index 000000000..3d302287f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie.c +@@ -0,0 +1,8489 @@ ++/* ++ * DHD Bus Module for PCIE ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_pcie.c 710862 2017-07-14 07:43:59Z $ ++ */ ++ ++ ++/* include files */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(DHD_DEBUG) ++#include ++#endif /* defined(DHD_DEBUG) */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef DHDTCPACK_SUPPRESS ++#include ++#endif /* DHDTCPACK_SUPPRESS */ ++#include ++#include ++ ++#ifdef DHD_TIMESYNC ++#include ++#endif /* DHD_TIMESYNC */ ++ ++#if defined(BCMEMBEDIMAGE) ++#ifndef DHD_EFI ++#include BCMEMBEDIMAGE ++#else ++#include ++#endif /* !DHD_EFI */ ++#endif /* BCMEMBEDIMAGE */ ++ ++#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ ++#define MAX_WKLK_IDLE_CHECK 3 /* times wake_lock checked before deciding not to suspend */ ++ ++#define ARMCR4REG_BANKIDX (0x40/sizeof(uint32)) ++#define ARMCR4REG_BANKPDA (0x4C/sizeof(uint32)) ++/* Temporary war to fix precommit till sync issue between trunk & precommit branch is resolved */ ++ ++/* CTO Prevention Recovery */ ++#define CTO_TO_CLEAR_WAIT_MS 1000 ++#define CTO_TO_CLEAR_WAIT_MAX_CNT 10 ++ ++#if defined(SUPPORT_MULTIPLE_BOARD_REV) ++ extern unsigned int system_rev; ++#endif /* SUPPORT_MULTIPLE_BOARD_REV */ ++ ++int dhd_dongle_memsize; ++int dhd_dongle_ramsize; ++static int dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size); ++static int dhdpcie_bus_readconsole(dhd_bus_t *bus); ++#if defined(DHD_FW_COREDUMP) ++struct dhd_bus *g_dhd_bus = NULL; ++static int dhdpcie_mem_dump(dhd_bus_t *bus); ++#endif /* DHD_FW_COREDUMP */ ++ ++static int dhdpcie_bus_membytes(dhd_bus_t *bus, bool write, ulong address, uint8 *data, uint size); ++static int dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, ++ const char *name, void *params, ++ int plen, void *arg, int len, int val_size); ++static int dhdpcie_bus_lpback_req(struct dhd_bus *bus, uint32 intval); ++static int dhdpcie_bus_dmaxfer_req(struct dhd_bus *bus, ++ uint32 len, uint32 srcdelay, uint32 destdelay, uint32 d11_lpbk); ++static int dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter); ++static int _dhdpcie_download_firmware(struct dhd_bus *bus); ++static int dhdpcie_download_firmware(dhd_bus_t *bus, osl_t *osh); ++static int dhdpcie_bus_write_vars(dhd_bus_t *bus); ++static bool dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus); ++static bool dhdpci_bus_read_frames(dhd_bus_t *bus); ++static int dhdpcie_readshared(dhd_bus_t *bus); ++static void dhdpcie_init_shared_addr(dhd_bus_t *bus); ++static bool dhdpcie_dongle_attach(dhd_bus_t *bus); ++static void dhdpcie_bus_dongle_setmemsize(dhd_bus_t *bus, int mem_size); ++static void dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, ++ bool dongle_isolation, bool reset_flag); ++static void dhdpcie_bus_release_malloc(dhd_bus_t *bus, osl_t *osh); ++static int dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len); ++static uint8 dhdpcie_bus_rtcm8(dhd_bus_t *bus, ulong offset); ++static void dhdpcie_bus_wtcm8(dhd_bus_t *bus, ulong offset, uint8 data); ++static void dhdpcie_bus_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data); ++static uint16 dhdpcie_bus_rtcm16(dhd_bus_t *bus, ulong offset); ++static void dhdpcie_bus_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data); ++static uint32 dhdpcie_bus_rtcm32(dhd_bus_t *bus, ulong offset); ++#ifdef DHD_SUPPORT_64BIT ++static void dhdpcie_bus_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data); ++static uint64 dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset); ++#endif /* DHD_SUPPORT_64BIT */ ++static void dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data); ++static void dhdpcie_bus_reg_unmap(osl_t *osh, volatile char *addr, int size); ++static int dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b); ++static void dhdpcie_fw_trap(dhd_bus_t *bus); ++static void dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info); ++extern void dhd_dpc_enable(dhd_pub_t *dhdp); ++extern void dhd_dpc_kill(dhd_pub_t *dhdp); ++ ++#ifdef IDLE_TX_FLOW_MGMT ++static void dhd_bus_check_idle_scan(dhd_bus_t *bus); ++static void dhd_bus_idle_scan(dhd_bus_t *bus); ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++#ifdef BCMEMBEDIMAGE ++static int dhdpcie_download_code_array(dhd_bus_t *bus); ++#endif /* BCMEMBEDIMAGE */ ++ ++ ++#ifdef EXYNOS_PCIE_DEBUG ++extern void exynos_pcie_register_dump(int ch_num); ++#endif /* EXYNOS_PCIE_DEBUG */ ++ ++#define PCI_VENDOR_ID_BROADCOM 0x14e4 ++ ++#define DHD_DEFAULT_DOORBELL_TIMEOUT 200 /* ms */ ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++static uint dhd_doorbell_timeout = DHD_DEFAULT_DOORBELL_TIMEOUT; ++#endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ ++static bool dhdpcie_check_firmware_compatible(uint32 f_api_version, uint32 h_api_version); ++static void dhdpcie_cto_error_recovery(struct dhd_bus *bus); ++ ++#ifdef BCM_ASLR_HEAP ++static void dhdpcie_wrt_rnd(struct dhd_bus *bus); ++#endif /* BCM_ASLR_HEAP */ ++ ++extern uint16 dhd_prot_get_h2d_max_txpost(dhd_pub_t *dhd); ++extern void dhd_prot_set_h2d_max_txpost(dhd_pub_t *dhd, uint16 max_txpost); ++ ++/* IOVar table */ ++enum { ++ IOV_INTR = 1, ++ IOV_MEMSIZE, ++ IOV_SET_DOWNLOAD_STATE, ++ IOV_DEVRESET, ++ IOV_VARS, ++ IOV_MSI_SIM, ++ IOV_PCIE_LPBK, ++ IOV_CC_NVMSHADOW, ++ IOV_RAMSIZE, ++ IOV_RAMSTART, ++ IOV_SLEEP_ALLOWED, ++ IOV_PCIE_DMAXFER, ++ IOV_PCIE_SUSPEND, ++ IOV_DONGLEISOLATION, ++ IOV_LTRSLEEPON_UNLOOAD, ++ IOV_METADATA_DBG, ++ IOV_RX_METADATALEN, ++ IOV_TX_METADATALEN, ++ IOV_TXP_THRESHOLD, ++ IOV_BUZZZ_DUMP, ++ IOV_DUMP_RINGUPD_BLOCK, ++ IOV_DMA_RINGINDICES, ++ IOV_FORCE_FW_TRAP, ++ IOV_DB1_FOR_MB, ++ IOV_FLOW_PRIO_MAP, ++#ifdef DHD_PCIE_RUNTIMEPM ++ IOV_IDLETIME, ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ IOV_RXBOUND, ++ IOV_TXBOUND, ++ IOV_HANGREPORT, ++ IOV_H2D_MAILBOXDATA, ++ IOV_INFORINGS, ++ IOV_H2D_PHASE, ++ IOV_H2D_ENABLE_TRAP_BADPHASE, ++ IOV_H2D_TXPOST_MAX_ITEM, ++ IOV_TRAPDATA, ++ IOV_TRAPDATA_RAW, ++ IOV_CTO_PREVENTION, ++#ifdef PCIE_OOB ++ IOV_OOB_BT_REG_ON, ++ IOV_OOB_ENABLE, ++#endif /* PCIE_OOB */ ++ IOV_PCIE_WD_RESET, ++ IOV_CTO_THRESHOLD, ++#ifdef DHD_EFI ++ IOV_CONTROL_SIGNAL, ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++ IOV_DEEP_SLEEP, ++#endif /* PCIE_OOB || PCIE_INB_DW */ ++#endif /* DHD_EFI */ ++#ifdef DEVICE_TX_STUCK_DETECT ++ IOV_DEVICE_TX_STUCK_DETECT, ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ IOV_INB_DW_ENABLE, ++ IOV_IDMA_ENABLE, ++ IOV_IFRM_ENABLE, ++ IOV_CLEAR_RING, ++#ifdef DHD_EFI ++ IOV_WIFI_PROPERTIES, ++ IOV_OTP_DUMP ++#endif ++}; ++ ++ ++const bcm_iovar_t dhdpcie_iovars[] = { ++ {"intr", IOV_INTR, 0, 0, IOVT_BOOL, 0 }, ++ {"memsize", IOV_MEMSIZE, 0, 0, IOVT_UINT32, 0 }, ++ {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, 0, IOVT_BOOL, 0 }, ++ {"vars", IOV_VARS, 0, 0, IOVT_BUFFER, 0 }, ++ {"devreset", IOV_DEVRESET, 0, 0, IOVT_BOOL, 0 }, ++ {"pcie_device_trap", IOV_FORCE_FW_TRAP, 0, 0, 0, 0 }, ++ {"pcie_lpbk", IOV_PCIE_LPBK, 0, 0, IOVT_UINT32, 0 }, ++ {"cc_nvmshadow", IOV_CC_NVMSHADOW, 0, 0, IOVT_BUFFER, 0 }, ++ {"ramsize", IOV_RAMSIZE, 0, 0, IOVT_UINT32, 0 }, ++ {"ramstart", IOV_RAMSTART, 0, 0, IOVT_UINT32, 0 }, ++ {"pcie_dmaxfer", IOV_PCIE_DMAXFER, 0, 0, IOVT_BUFFER, 3 * sizeof(int32) }, ++ {"pcie_suspend", IOV_PCIE_SUSPEND, 0, 0, IOVT_UINT32, 0 }, ++#ifdef PCIE_OOB ++ {"oob_bt_reg_on", IOV_OOB_BT_REG_ON, 0, 0, IOVT_UINT32, 0 }, ++ {"oob_enable", IOV_OOB_ENABLE, 0, 0, IOVT_UINT32, 0 }, ++#endif /* PCIE_OOB */ ++ {"sleep_allowed", IOV_SLEEP_ALLOWED, 0, 0, IOVT_BOOL, 0 }, ++ {"dngl_isolation", IOV_DONGLEISOLATION, 0, 0, IOVT_UINT32, 0 }, ++ {"ltrsleep_on_unload", IOV_LTRSLEEPON_UNLOOAD, 0, 0, IOVT_UINT32, 0 }, ++ {"dump_ringupdblk", IOV_DUMP_RINGUPD_BLOCK, 0, 0, IOVT_BUFFER, 0 }, ++ {"dma_ring_indices", IOV_DMA_RINGINDICES, 0, 0, IOVT_UINT32, 0}, ++ {"metadata_dbg", IOV_METADATA_DBG, 0, 0, IOVT_BOOL, 0 }, ++ {"rx_metadata_len", IOV_RX_METADATALEN, 0, 0, IOVT_UINT32, 0 }, ++ {"tx_metadata_len", IOV_TX_METADATALEN, 0, 0, IOVT_UINT32, 0 }, ++ {"db1_for_mb", IOV_DB1_FOR_MB, 0, 0, IOVT_UINT32, 0 }, ++ {"txp_thresh", IOV_TXP_THRESHOLD, 0, 0, IOVT_UINT32, 0 }, ++ {"buzzz_dump", IOV_BUZZZ_DUMP, 0, 0, IOVT_UINT32, 0 }, ++ {"flow_prio_map", IOV_FLOW_PRIO_MAP, 0, 0, IOVT_UINT32, 0 }, ++#ifdef DHD_PCIE_RUNTIMEPM ++ {"idletime", IOV_IDLETIME, 0, 0, IOVT_INT32, 0 }, ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ {"rxbound", IOV_RXBOUND, 0, 0, IOVT_UINT32, 0 }, ++ {"txbound", IOV_TXBOUND, 0, 0, IOVT_UINT32, 0 }, ++ {"fw_hang_report", IOV_HANGREPORT, 0, 0, IOVT_BOOL, 0 }, ++ {"h2d_mb_data", IOV_H2D_MAILBOXDATA, 0, 0, IOVT_UINT32, 0 }, ++ {"inforings", IOV_INFORINGS, 0, 0, IOVT_UINT32, 0 }, ++ {"h2d_phase", IOV_H2D_PHASE, 0, 0, IOVT_UINT32, 0 }, ++ {"force_trap_bad_h2d_phase", IOV_H2D_ENABLE_TRAP_BADPHASE, 0, 0, ++ IOVT_UINT32, 0 }, ++ {"h2d_max_txpost", IOV_H2D_TXPOST_MAX_ITEM, 0, 0, IOVT_UINT32, 0 }, ++ {"trap_data", IOV_TRAPDATA, 0, 0, IOVT_BUFFER, 0 }, ++ {"trap_data_raw", IOV_TRAPDATA_RAW, 0, 0, IOVT_BUFFER, 0 }, ++ {"cto_prevention", IOV_CTO_PREVENTION, 0, 0, IOVT_UINT32, 0 }, ++ {"pcie_wd_reset", IOV_PCIE_WD_RESET, 0, 0, IOVT_BOOL, 0 }, ++ {"cto_threshold", IOV_CTO_THRESHOLD, 0, 0, IOVT_UINT32, 0 }, ++#ifdef DHD_EFI ++ {"control_signal", IOV_CONTROL_SIGNAL, 0, 0, IOVT_UINT32, 0}, ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++ {"deep_sleep", IOV_DEEP_SLEEP, 0, 0, IOVT_UINT32, 0}, ++#endif /* PCIE_OOB || PCIE_INB_DW */ ++#endif /* DHD_EFI */ ++ {"inb_dw_enable", IOV_INB_DW_ENABLE, 0, 0, IOVT_UINT32, 0 }, ++#ifdef DEVICE_TX_STUCK_DETECT ++ {"dev_tx_stuck_monitor", IOV_DEVICE_TX_STUCK_DETECT, 0, 0, IOVT_UINT32, 0 }, ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ {"idma_enable", IOV_IDMA_ENABLE, 0, 0, IOVT_UINT32, 0 }, ++ {"ifrm_enable", IOV_IFRM_ENABLE, 0, 0, IOVT_UINT32, 0 }, ++ {"clear_ring", IOV_CLEAR_RING, 0, 0, IOVT_UINT32, 0 }, ++#ifdef DHD_EFI ++ {"properties", IOV_WIFI_PROPERTIES, 0, 0, IOVT_BUFFER, 0}, ++ {"otp_dump", IOV_OTP_DUMP, 0, 0, IOVT_BUFFER, 0}, ++#endif ++ {NULL, 0, 0, 0, 0, 0 } ++}; ++ ++ ++#define MAX_READ_TIMEOUT 5 * 1000 * 1000 ++ ++#ifndef DHD_RXBOUND ++#define DHD_RXBOUND 64 ++#endif ++#ifndef DHD_TXBOUND ++#define DHD_TXBOUND 64 ++#endif ++ ++#define DHD_INFORING_BOUND 32 ++ ++uint dhd_rxbound = DHD_RXBOUND; ++uint dhd_txbound = DHD_TXBOUND; ++ ++/** ++ * Register/Unregister functions are called by the main DHD entry point (eg module insertion) to ++ * link with the bus driver, in order to look for or await the device. ++ */ ++int ++dhd_bus_register(void) ++{ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ return dhdpcie_bus_register(); ++} ++ ++void ++dhd_bus_unregister(void) ++{ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ dhdpcie_bus_unregister(); ++ return; ++} ++ ++ ++/** returns a host virtual address */ ++uint32 * ++dhdpcie_bus_reg_map(osl_t *osh, ulong addr, int size) ++{ ++ return (uint32 *)REG_MAP(addr, size); ++} ++ ++void ++dhdpcie_bus_reg_unmap(osl_t *osh, volatile char *addr, int size) ++{ ++ REG_UNMAP(addr); ++ return; ++} ++ ++/** ++ * 'regs' is the host virtual address that maps to the start of the PCIe BAR0 window. The first 4096 ++ * bytes in this window are mapped to the backplane address in the PCIEBAR0Window register. The ++ * precondition is that the PCIEBAR0Window register 'points' at the PCIe core. ++ * ++ * 'tcm' is the *host* virtual address at which tcm is mapped. ++ */ ++dhd_bus_t* dhdpcie_bus_attach(osl_t *osh, ++ volatile char *regs, volatile char *tcm, void *pci_dev) ++{ ++ dhd_bus_t *bus; ++ ++ DHD_TRACE(("%s: ENTER\n", __FUNCTION__)); ++ ++ do { ++ if (!(bus = MALLOCZ(osh, sizeof(dhd_bus_t)))) { ++ DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); ++ break; ++ } ++ ++ bus->regs = regs; ++ bus->tcm = tcm; ++ bus->osh = osh; ++ /* Save pci_dev into dhd_bus, as it may be needed in dhd_attach */ ++ bus->dev = (struct pci_dev *)pci_dev; ++ ++ ++ dll_init(&bus->flowring_active_list); ++#ifdef IDLE_TX_FLOW_MGMT ++ bus->active_list_last_process_ts = OSL_SYSUPTIME(); ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++#ifdef DEVICE_TX_STUCK_DETECT ++ /* Enable the Device stuck detection feature by default */ ++ bus->dev_tx_stuck_monitor = TRUE; ++ bus->device_tx_stuck_check = OSL_SYSUPTIME(); ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ ++ /* Attach pcie shared structure */ ++ if (!(bus->pcie_sh = MALLOCZ(osh, sizeof(pciedev_shared_t)))) { ++ DHD_ERROR(("%s: MALLOC of bus->pcie_sh failed\n", __FUNCTION__)); ++ break; ++ } ++ ++ /* dhd_common_init(osh); */ ++ ++ if (dhdpcie_dongle_attach(bus)) { ++ DHD_ERROR(("%s: dhdpcie_probe_attach failed\n", __FUNCTION__)); ++ break; ++ } ++ ++ /* software resources */ ++ if (!(bus->dhd = dhd_attach(osh, bus, PCMSGBUF_HDRLEN))) { ++ DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__)); ++ ++ break; ++ } ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ bus->db1_for_mb = TRUE; ++ bus->dhd->hang_report = TRUE; ++ bus->use_mailbox = FALSE; ++ bus->use_d0_inform = FALSE; ++#ifdef IDLE_TX_FLOW_MGMT ++ bus->enable_idle_flowring_mgmt = FALSE; ++#endif /* IDLE_TX_FLOW_MGMT */ ++ bus->irq_registered = FALSE; ++ ++ DHD_TRACE(("%s: EXIT SUCCESS\n", ++ __FUNCTION__)); ++#ifdef DHD_FW_COREDUMP ++ g_dhd_bus = bus; ++#endif ++ return bus; ++ } while (0); ++ ++ DHD_TRACE(("%s: EXIT FAILURE\n", __FUNCTION__)); ++ ++ if (bus && bus->pcie_sh) { ++ MFREE(osh, bus->pcie_sh, sizeof(pciedev_shared_t)); ++ } ++ ++ if (bus) { ++ MFREE(osh, bus, sizeof(dhd_bus_t)); ++ } ++ return NULL; ++} ++ ++uint ++dhd_bus_chip(struct dhd_bus *bus) ++{ ++ ASSERT(bus->sih != NULL); ++ return bus->sih->chip; ++} ++ ++uint ++dhd_bus_chiprev(struct dhd_bus *bus) ++{ ++ ASSERT(bus); ++ ASSERT(bus->sih != NULL); ++ return bus->sih->chiprev; ++} ++ ++void * ++dhd_bus_pub(struct dhd_bus *bus) ++{ ++ return bus->dhd; ++} ++ ++const void * ++dhd_bus_sih(struct dhd_bus *bus) ++{ ++ return (const void *)bus->sih; ++} ++ ++void * ++dhd_bus_txq(struct dhd_bus *bus) ++{ ++ return &bus->txq; ++} ++ ++/** Get Chip ID version */ ++uint dhd_bus_chip_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ return bus->sih->chip; ++} ++ ++/** Get Chip Rev ID version */ ++uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ return bus->sih->chiprev; ++} ++ ++/** Get Chip Pkg ID version */ ++uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ return bus->sih->chippkg; ++} ++ ++/** Read and clear intstatus. This should be called with interrupts disabled or inside isr */ ++uint32 ++dhdpcie_bus_intstatus(dhd_bus_t *bus) ++{ ++ uint32 intstatus = 0; ++#ifndef DHD_READ_INTSTATUS_IN_DPC ++ uint32 intmask = 0; ++#endif /* DHD_READ_INTSTATUS_IN_DPC */ ++ ++ if ((bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) && ++ bus->wait_for_d3_ack) { ++#ifdef DHD_EFI ++ DHD_INFO(("%s: trying to clear intstatus during suspend (%d)" ++ " or suspend in progress %d\n", ++ __FUNCTION__, bus->dhd->busstate, bus->d3_suspend_pending)); ++#else ++ DHD_ERROR(("%s: trying to clear intstatus during suspend (%d)" ++ " or suspend in progress %d\n", ++ __FUNCTION__, bus->dhd->busstate, bus->d3_suspend_pending)); ++#endif /* !DHD_EFI */ ++ return intstatus; ++ } ++ if ((bus->sih->buscorerev == 6) || (bus->sih->buscorerev == 4) || ++ (bus->sih->buscorerev == 2)) { ++ intstatus = dhdpcie_bus_cfg_read_dword(bus, PCIIntstatus, 4); ++ dhdpcie_bus_cfg_write_dword(bus, PCIIntstatus, 4, intstatus); ++ intstatus &= I_MB; ++ } else { ++ /* this is a PCIE core register..not a config register... */ ++ intstatus = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); ++ ++#ifndef DHD_READ_INTSTATUS_IN_DPC ++ /* this is a PCIE core register..not a config register... */ ++ intmask = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, 0, 0); ++ ++ intstatus &= intmask; ++#endif /* DHD_READ_INTSTATUS_IN_DPC */ ++ /* Is device removed. intstatus & intmask read 0xffffffff */ ++ if (intstatus == (uint32)-1) { ++ DHD_ERROR(("%s: Device is removed or Link is down.\n", __FUNCTION__)); ++#ifdef CUSTOMER_HW4_DEBUG ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ bus->dhd->hang_reason = HANG_REASON_PCIE_LINK_DOWN; ++ dhd_os_send_hang_message(bus->dhd); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ ++#endif /* CUSTOMER_HW4_DEBUG */ ++ return intstatus; ++ } ++ ++ ++ /* ++ * The fourth argument to si_corereg is the "mask" fields of the register to update ++ * and the fifth field is the "value" to update. Now if we are interested in only ++ * few fields of the "mask" bit map, we should not be writing back what we read ++ * By doing so, we might clear/ack interrupts that are not handled yet. ++ */ ++ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, bus->def_intmask, ++ intstatus); ++ ++ intstatus &= bus->def_intmask; ++ } ++ ++ return intstatus; ++} ++ ++/** ++ * Name: dhdpcie_bus_isr ++ * Parameters: ++ * 1: IN int irq -- interrupt vector ++ * 2: IN void *arg -- handle to private data structure ++ * Return value: ++ * Status (TRUE or FALSE) ++ * ++ * Description: ++ * Interrupt Service routine checks for the status register, ++ * disable interrupt and queue DPC if mail box interrupts are raised. ++ */ ++int32 ++dhdpcie_bus_isr(dhd_bus_t *bus) ++{ ++ uint32 intstatus = 0; ++ ++ do { ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ /* verify argument */ ++ if (!bus) { ++ DHD_ERROR(("%s : bus is null pointer, exit \n", __FUNCTION__)); ++ break; ++ } ++ ++ if (bus->dhd->dongle_reset) { ++ break; ++ } ++ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ break; ++ } ++ ++ ++ if (PCIECTO_ENAB(bus->dhd)) { ++ /* read pci_intstatus */ ++ intstatus = dhdpcie_bus_cfg_read_dword(bus, PCI_INT_STATUS, 4); ++ ++ if (intstatus & PCI_CTO_INT_MASK) { ++ /* reset backplane and cto, ++ * then access through pcie is recovered. ++ */ ++ dhdpcie_cto_error_recovery(bus); ++ return TRUE; ++ } ++ } ++ ++#ifndef DHD_READ_INTSTATUS_IN_DPC ++ intstatus = dhdpcie_bus_intstatus(bus); ++ ++ /* Check if the interrupt is ours or not */ ++ if (intstatus == 0) { ++ break; ++ } ++ ++ /* save the intstatus */ ++ /* read interrupt status register!! Status bits will be cleared in DPC !! */ ++ bus->intstatus = intstatus; ++ ++ /* return error for 0xFFFFFFFF */ ++ if (intstatus == (uint32)-1) { ++ dhdpcie_disable_irq_nosync(bus); ++ bus->is_linkdown = TRUE; ++ return BCME_ERROR; ++ } ++ ++ /* Overall operation: ++ * - Mask further interrupts ++ * - Read/ack intstatus ++ * - Take action based on bits and state ++ * - Reenable interrupts (as per state) ++ */ ++ ++ /* Count the interrupt call */ ++ bus->intrcount++; ++#endif /* DHD_READ_INTSTATUS_IN_DPC */ ++ ++ bus->ipend = TRUE; ++ ++ bus->isr_intr_disable_count++; ++ dhdpcie_bus_intr_disable(bus); /* Disable interrupt using IntMask!! */ ++ ++ bus->intdis = TRUE; ++ ++#if defined(PCIE_ISR_THREAD) ++ ++ DHD_TRACE(("Calling dhd_bus_dpc() from %s\n", __FUNCTION__)); ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ while (dhd_bus_dpc(bus)); ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++#else ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); /* queue DPC now!! */ ++#endif /* defined(SDIO_ISR_THREAD) */ ++ ++ DHD_TRACE(("%s: Exit Success DPC Queued\n", __FUNCTION__)); ++ return TRUE; ++ ++ } while (0); ++ ++ DHD_TRACE(("%s: Exit Failure\n", __FUNCTION__)); ++ return FALSE; ++} ++ ++int ++dhdpcie_set_pwr_state(dhd_bus_t *bus, uint state) ++{ ++ uint32 cur_state = 0; ++ uint32 pm_csr = 0; ++ osl_t *osh = bus->osh; ++ ++ pm_csr = OSL_PCI_READ_CONFIG(osh, PCIECFGREG_PM_CSR, sizeof(uint32)); ++ cur_state = pm_csr & PCIECFGREG_PM_CSR_STATE_MASK; ++ ++ if (cur_state == state) { ++ DHD_ERROR(("%s: Already in state %u \n", __FUNCTION__, cur_state)); ++ return BCME_OK; ++ } ++ ++ if (state > PCIECFGREG_PM_CSR_STATE_D3_HOT) ++ return BCME_ERROR; ++ ++ /* Validate the state transition ++ * if already in a lower power state, return error ++ */ ++ if (state != PCIECFGREG_PM_CSR_STATE_D0 && ++ cur_state <= PCIECFGREG_PM_CSR_STATE_D3_COLD && ++ cur_state > state) { ++ DHD_ERROR(("%s: Invalid power state transition !\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ pm_csr &= ~PCIECFGREG_PM_CSR_STATE_MASK; ++ pm_csr |= state; ++ ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_PM_CSR, sizeof(uint32), pm_csr); ++ ++ /* need to wait for the specified mandatory pcie power transition delay time */ ++ if (state == PCIECFGREG_PM_CSR_STATE_D3_HOT || ++ cur_state == PCIECFGREG_PM_CSR_STATE_D3_HOT) ++ OSL_DELAY(DHDPCIE_PM_D3_DELAY); ++ else if (state == PCIECFGREG_PM_CSR_STATE_D2 || ++ cur_state == PCIECFGREG_PM_CSR_STATE_D2) ++ OSL_DELAY(DHDPCIE_PM_D2_DELAY); ++ ++ /* read back the power state and verify */ ++ pm_csr = OSL_PCI_READ_CONFIG(osh, PCIECFGREG_PM_CSR, sizeof(uint32)); ++ cur_state = pm_csr & PCIECFGREG_PM_CSR_STATE_MASK; ++ if (cur_state != state) { ++ DHD_ERROR(("%s: power transition failed ! Current state is %u \n", ++ __FUNCTION__, cur_state)); ++ return BCME_ERROR; ++ } else { ++ DHD_ERROR(("%s: power transition to %u success \n", ++ __FUNCTION__, cur_state)); ++ } ++ ++ return BCME_OK; ++ ++} ++ ++int ++dhdpcie_config_check(dhd_bus_t *bus) ++{ ++ uint32 i, val; ++ int ret = BCME_ERROR; ++ ++ for (i = 0; i < DHDPCIE_CONFIG_CHECK_RETRY_COUNT; i++) { ++ val = OSL_PCI_READ_CONFIG(bus->osh, PCI_CFG_VID, sizeof(uint32)); ++ if ((val & 0xFFFF) == VENDOR_BROADCOM) { ++ ret = BCME_OK; ++ break; ++ } ++ OSL_DELAY(DHDPCIE_CONFIG_CHECK_DELAY_MS * 1000); ++ } ++ ++ return ret; ++} ++ ++int ++dhdpcie_config_restore(dhd_bus_t *bus, bool restore_pmcsr) ++{ ++ uint32 i; ++ osl_t *osh = bus->osh; ++ ++ if (BCME_OK != dhdpcie_config_check(bus)) { ++ return BCME_ERROR; ++ } ++ ++ for (i = PCI_CFG_REV >> 2; i < DHDPCIE_CONFIG_HDR_SIZE; i++) { ++ OSL_PCI_WRITE_CONFIG(osh, i << 2, sizeof(uint32), bus->saved_config.header[i]); ++ } ++ OSL_PCI_WRITE_CONFIG(osh, PCI_CFG_CMD, sizeof(uint32), bus->saved_config.header[1]); ++ ++ if (restore_pmcsr) ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_PM_CSR, ++ sizeof(uint32), bus->saved_config.pmcsr); ++ ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_MSI_CAP, sizeof(uint32), bus->saved_config.msi_cap); ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_MSI_ADDR_L, sizeof(uint32), ++ bus->saved_config.msi_addr0); ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_MSI_ADDR_H, ++ sizeof(uint32), bus->saved_config.msi_addr1); ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_MSI_DATA, ++ sizeof(uint32), bus->saved_config.msi_data); ++ ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_DEV_STATUS_CTRL, ++ sizeof(uint32), bus->saved_config.exp_dev_ctrl_stat); ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGGEN_DEV_STATUS_CTRL2, ++ sizeof(uint32), bus->saved_config.exp_dev_ctrl_stat2); ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_LINK_STATUS_CTRL, ++ sizeof(uint32), bus->saved_config.exp_link_ctrl_stat); ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_LINK_STATUS_CTRL2, ++ sizeof(uint32), bus->saved_config.exp_link_ctrl_stat2); ++ ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_PML1_SUB_CTRL1, ++ sizeof(uint32), bus->saved_config.l1pm0); ++ OSL_PCI_WRITE_CONFIG(osh, PCIECFGREG_PML1_SUB_CTRL2, ++ sizeof(uint32), bus->saved_config.l1pm1); ++ ++ OSL_PCI_WRITE_CONFIG(bus->osh, PCI_BAR0_WIN, ++ sizeof(uint32), bus->saved_config.bar0_win); ++ OSL_PCI_WRITE_CONFIG(bus->osh, PCI_BAR1_WIN, ++ sizeof(uint32), bus->saved_config.bar1_win); ++ ++ return BCME_OK; ++} ++ ++int ++dhdpcie_config_save(dhd_bus_t *bus) ++{ ++ uint32 i; ++ osl_t *osh = bus->osh; ++ ++ if (BCME_OK != dhdpcie_config_check(bus)) { ++ return BCME_ERROR; ++ } ++ ++ for (i = 0; i < DHDPCIE_CONFIG_HDR_SIZE; i++) { ++ bus->saved_config.header[i] = OSL_PCI_READ_CONFIG(osh, i << 2, sizeof(uint32)); ++ } ++ ++ bus->saved_config.pmcsr = OSL_PCI_READ_CONFIG(osh, PCIECFGREG_PM_CSR, sizeof(uint32)); ++ ++ bus->saved_config.msi_cap = OSL_PCI_READ_CONFIG(osh, PCIECFGREG_MSI_CAP, ++ sizeof(uint32)); ++ bus->saved_config.msi_addr0 = OSL_PCI_READ_CONFIG(osh, PCIECFGREG_MSI_ADDR_L, ++ sizeof(uint32)); ++ bus->saved_config.msi_addr1 = OSL_PCI_READ_CONFIG(osh, PCIECFGREG_MSI_ADDR_H, ++ sizeof(uint32)); ++ bus->saved_config.msi_data = OSL_PCI_READ_CONFIG(osh, PCIECFGREG_MSI_DATA, ++ sizeof(uint32)); ++ ++ bus->saved_config.exp_dev_ctrl_stat = OSL_PCI_READ_CONFIG(osh, ++ PCIECFGREG_DEV_STATUS_CTRL, sizeof(uint32)); ++ bus->saved_config.exp_dev_ctrl_stat2 = OSL_PCI_READ_CONFIG(osh, ++ PCIECFGGEN_DEV_STATUS_CTRL2, sizeof(uint32)); ++ bus->saved_config.exp_link_ctrl_stat = OSL_PCI_READ_CONFIG(osh, ++ PCIECFGREG_LINK_STATUS_CTRL, sizeof(uint32)); ++ bus->saved_config.exp_link_ctrl_stat2 = OSL_PCI_READ_CONFIG(osh, ++ PCIECFGREG_LINK_STATUS_CTRL2, sizeof(uint32)); ++ ++ bus->saved_config.l1pm0 = OSL_PCI_READ_CONFIG(osh, PCIECFGREG_PML1_SUB_CTRL1, ++ sizeof(uint32)); ++ bus->saved_config.l1pm1 = OSL_PCI_READ_CONFIG(osh, PCIECFGREG_PML1_SUB_CTRL2, ++ sizeof(uint32)); ++ ++ bus->saved_config.bar0_win = OSL_PCI_READ_CONFIG(osh, PCI_BAR0_WIN, ++ sizeof(uint32)); ++ bus->saved_config.bar1_win = OSL_PCI_READ_CONFIG(osh, PCI_BAR1_WIN, ++ sizeof(uint32)); ++ return BCME_OK; ++} ++ ++#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY ++dhd_pub_t *link_recovery = NULL; ++#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */ ++static bool ++dhdpcie_dongle_attach(dhd_bus_t *bus) ++{ ++ ++ osl_t *osh = bus->osh; ++ volatile void *regsva = (volatile void*)bus->regs; ++ uint16 devid = bus->cl_devid; ++ uint32 val; ++ sbpcieregs_t *sbpcieregs; ++ ++ DHD_TRACE(("%s: ENTER\n", __FUNCTION__)); ++ ++#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY ++ link_recovery = bus->dhd; ++#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */ ++ ++ bus->alp_only = TRUE; ++ bus->sih = NULL; ++ ++ /* Set bar0 window to si_enum_base */ ++ dhdpcie_bus_cfg_set_bar0_win(bus, SI_ENUM_BASE); ++ ++ /* Checking PCIe bus status with reading configuration space */ ++ val = OSL_PCI_READ_CONFIG(osh, PCI_CFG_VID, sizeof(uint32)); ++ if ((val & 0xFFFF) != VENDOR_BROADCOM) { ++ DHD_ERROR(("%s : failed to read PCI configuration space!\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* ++ * Checking PCI_SPROM_CONTROL register for preventing invalid address access ++ * due to switch address space from PCI_BUS to SI_BUS. ++ */ ++ val = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); ++ if (val == 0xffffffff) { ++ DHD_ERROR(("%s : failed to read SPROM control register\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++#ifdef DHD_EFI ++ /* Save good copy of PCIe config space */ ++ if (BCME_OK != dhdpcie_config_save(bus)) { ++ DHD_ERROR(("%s : failed to save PCI configuration space!\n", __FUNCTION__)); ++ goto fail; ++ } ++#endif /* DHD_EFI */ ++ ++ /* si_attach() will provide an SI handle and scan the backplane */ ++ if (!(bus->sih = si_attach((uint)devid, osh, regsva, PCI_BUS, bus, ++ &bus->vars, &bus->varsz))) { ++ DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* Olympic EFI requirement - stop driver load if FW is already running ++ * need to do this here before pcie_watchdog_reset, because ++ * pcie_watchdog_reset will put the ARM back into halt state ++ */ ++ if (!dhdpcie_is_arm_halted(bus)) { ++ DHD_ERROR(("%s: ARM is not halted,FW is already running! Abort.\n", ++ __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* Enable CLKREQ# */ ++ dhdpcie_clkreq(bus->osh, 1, 1); ++ ++#ifndef DONGLE_ENABLE_ISOLATION ++ /* ++ * Issue CC watchdog to reset all the cores on the chip - similar to rmmod dhd ++ * This is required to avoid spurious interrupts to the Host and bring back ++ * dongle to a sane state (on host soft-reboot / watchdog-reboot). ++ */ ++ pcie_watchdog_reset(bus->osh, bus->sih, (sbpcieregs_t *) bus->regs); ++#endif /* !DONGLE_ENABLE_ISOLATION */ ++ ++#ifdef DHD_EFI ++ dhdpcie_dongle_pwr_toggle(bus); ++#endif ++ ++ si_setcore(bus->sih, PCIE2_CORE_ID, 0); ++ sbpcieregs = (sbpcieregs_t*)(bus->regs); ++ ++ /* WAR where the BAR1 window may not be sized properly */ ++ W_REG(osh, &sbpcieregs->configaddr, 0x4e0); ++ val = R_REG(osh, &sbpcieregs->configdata); ++ W_REG(osh, &sbpcieregs->configdata, val); ++ ++ /* Get info on the ARM and SOCRAM cores... */ ++ /* Should really be qualified by device id */ ++ if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || ++ (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || ++ (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) || ++ (si_setcore(bus->sih, ARMCA7_CORE_ID, 0))) { ++ bus->armrev = si_corerev(bus->sih); ++ } else { ++ DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ if (si_setcore(bus->sih, SYSMEM_CORE_ID, 0)) { ++ /* Only set dongle RAMSIZE to default value when ramsize is not adjusted */ ++ if (!bus->ramsize_adjusted) { ++ if (!(bus->orig_ramsize = si_sysmem_size(bus->sih))) { ++ DHD_ERROR(("%s: failed to find SYSMEM memory!\n", __FUNCTION__)); ++ goto fail; ++ } ++ /* also populate base address */ ++ bus->dongle_ram_base = CA7_4365_RAM_BASE; ++ /* Default reserve 1.75MB for CA7 */ ++ bus->orig_ramsize = 0x1c0000; ++ } ++ } else if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { ++ DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); ++ goto fail; ++ } ++ } else { ++ /* cr4 has a different way to find the RAM size from TCM's */ ++ if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { ++ DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__)); ++ goto fail; ++ } ++ /* also populate base address */ ++ switch ((uint16)bus->sih->chip) { ++ case BCM4339_CHIP_ID: ++ case BCM4335_CHIP_ID: ++ bus->dongle_ram_base = CR4_4335_RAM_BASE; ++ break; ++ case BCM4358_CHIP_ID: ++ case BCM4354_CHIP_ID: ++ case BCM43567_CHIP_ID: ++ case BCM43569_CHIP_ID: ++ case BCM4350_CHIP_ID: ++ case BCM43570_CHIP_ID: ++ bus->dongle_ram_base = CR4_4350_RAM_BASE; ++ break; ++ case BCM4360_CHIP_ID: ++ bus->dongle_ram_base = CR4_4360_RAM_BASE; ++ break; ++ ++ case BCM4364_CHIP_ID: ++ bus->dongle_ram_base = CR4_4364_RAM_BASE; ++ break; ++ ++ CASE_BCM4345_CHIP: ++ bus->dongle_ram_base = (bus->sih->chiprev < 6) /* changed at 4345C0 */ ++ ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE; ++ break; ++ CASE_BCM43602_CHIP: ++ bus->dongle_ram_base = CR4_43602_RAM_BASE; ++ break; ++ case BCM4349_CHIP_GRPID: ++ /* RAM based changed from 4349c0(revid=9) onwards */ ++ bus->dongle_ram_base = ((bus->sih->chiprev < 9) ? ++ CR4_4349_RAM_BASE : CR4_4349_RAM_BASE_FROM_REV_9); ++ break; ++ case BCM4347_CHIP_GRPID: ++ bus->dongle_ram_base = CR4_4347_RAM_BASE; ++ break; ++ case BCM4362_CHIP_ID: ++ bus->dongle_ram_base = CR4_4362_RAM_BASE; ++ break; ++ default: ++ bus->dongle_ram_base = 0; ++ DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", ++ __FUNCTION__, bus->dongle_ram_base)); ++ } ++ } ++ bus->ramsize = bus->orig_ramsize; ++ if (dhd_dongle_memsize) ++ dhdpcie_bus_dongle_setmemsize(bus, dhd_dongle_memsize); ++ ++ DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n", ++ bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base)); ++ ++ bus->srmemsize = si_socram_srmem_size(bus->sih); ++ ++ ++ bus->def_intmask = PCIE_MB_D2H_MB_MASK | PCIE_MB_TOPCIE_FN0_0 | PCIE_MB_TOPCIE_FN0_1; ++ ++ /* Set the poll and/or interrupt flags */ ++ bus->intr = (bool)dhd_intr; ++ if ((bus->poll = (bool)dhd_poll)) ++ bus->pollrate = 1; ++ ++ bus->wait_for_d3_ack = 1; ++#ifdef PCIE_OOB ++ dhdpcie_oob_init(bus); ++#endif /* PCIE_OOB */ ++#ifdef PCIE_INB_DW ++ bus->inb_enabled = TRUE; ++#endif /* PCIE_INB_DW */ ++ bus->dongle_in_ds = FALSE; ++ bus->idma_enabled = TRUE; ++ bus->ifrm_enabled = TRUE; ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++ bus->ds_enabled = TRUE; ++#endif ++ DHD_TRACE(("%s: EXIT: SUCCESS\n", __FUNCTION__)); ++ return 0; ++ ++fail: ++ if (bus->sih != NULL) { ++ si_detach(bus->sih); ++ bus->sih = NULL; ++ } ++ DHD_TRACE(("%s: EXIT: FAILURE\n", __FUNCTION__)); ++ return -1; ++} ++ ++int ++dhpcie_bus_unmask_interrupt(dhd_bus_t *bus) ++{ ++ dhdpcie_bus_cfg_write_dword(bus, PCIIntmask, 4, I_MB); ++ return 0; ++} ++int ++dhpcie_bus_mask_interrupt(dhd_bus_t *bus) ++{ ++ dhdpcie_bus_cfg_write_dword(bus, PCIIntmask, 4, 0x0); ++ return 0; ++} ++ ++void ++dhdpcie_bus_intr_enable(dhd_bus_t *bus) ++{ ++ DHD_TRACE(("%s Enter\n", __FUNCTION__)); ++ if (bus && bus->sih && !bus->is_linkdown) { ++ if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || ++ (bus->sih->buscorerev == 4)) { ++ dhpcie_bus_unmask_interrupt(bus); ++ } else { ++ /* Skip after recieving D3 ACK */ ++ if ((bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) && ++ bus->wait_for_d3_ack) { ++ return; ++ } ++ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, ++ bus->def_intmask, bus->def_intmask); ++ } ++ } ++ DHD_TRACE(("%s Exit\n", __FUNCTION__)); ++} ++ ++void ++dhdpcie_bus_intr_disable(dhd_bus_t *bus) ++{ ++ DHD_TRACE(("%s Enter\n", __FUNCTION__)); ++ if (bus && bus->sih && !bus->is_linkdown) { ++ if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || ++ (bus->sih->buscorerev == 4)) { ++ dhpcie_bus_mask_interrupt(bus); ++ } else { ++ /* Skip after recieving D3 ACK */ ++ if ((bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) && ++ bus->wait_for_d3_ack) { ++ return; ++ } ++ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, ++ bus->def_intmask, 0); ++ } ++ } ++ DHD_TRACE(("%s Exit\n", __FUNCTION__)); ++} ++ ++/* ++ * dhdpcie_advertise_bus_cleanup advertises that clean up is under progress ++ * to other bus user contexts like Tx, Rx, IOVAR, WD etc and it waits for other contexts ++ * to gracefully exit. All the bus usage contexts before marking busstate as busy, will check for ++ * whether the busstate is DHD_BUS_DOWN or DHD_BUS_DOWN_IN_PROGRESS, if so ++ * they will exit from there itself without marking dhd_bus_busy_state as BUSY. ++ */ ++static void ++dhdpcie_advertise_bus_cleanup(dhd_pub_t *dhdp) ++{ ++ unsigned long flags; ++ int timeleft; ++ ++ DHD_GENERAL_LOCK(dhdp, flags); ++ dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS; ++ DHD_GENERAL_UNLOCK(dhdp, flags); ++ ++ timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); ++ if ((timeleft == 0) || (timeleft == 1)) { ++ DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", ++ __FUNCTION__, dhdp->dhd_bus_busy_state)); ++ ASSERT(0); ++ } ++ ++ return; ++} ++ ++static void ++dhdpcie_advertise_bus_remove(dhd_pub_t *dhdp) ++{ ++ unsigned long flags; ++ int timeleft; ++ ++ DHD_GENERAL_LOCK(dhdp, flags); ++ dhdp->busstate = DHD_BUS_REMOVE; ++ DHD_GENERAL_UNLOCK(dhdp, flags); ++ ++ timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); ++ if ((timeleft == 0) || (timeleft == 1)) { ++ DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", ++ __FUNCTION__, dhdp->dhd_bus_busy_state)); ++ ASSERT(0); ++ } ++ ++ return; ++} ++ ++ ++static void ++dhdpcie_bus_remove_prep(dhd_bus_t *bus) ++{ ++ unsigned long flags; ++ DHD_TRACE(("%s Enter\n", __FUNCTION__)); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++#ifdef PCIE_INB_DW ++ /* De-Initialize the lock to serialize Device Wake Inband activities */ ++ if (bus->inb_lock) { ++ dhd_os_spin_lock_deinit(bus->dhd->osh, bus->inb_lock); ++ bus->inb_lock = NULL; ++ } ++#endif ++ ++ ++ dhd_os_sdlock(bus->dhd); ++ ++ if (bus->sih && !bus->dhd->dongle_isolation) { ++ /* Has insmod fails after rmmod issue in Brix Android */ ++ /* if the pcie link is down, watchdog reset should not be done, as it may hang */ ++ if (!bus->is_linkdown) ++ pcie_watchdog_reset(bus->osh, bus->sih, (sbpcieregs_t *) bus->regs); ++ else ++ DHD_ERROR(("%s: skipping watchdog reset, due to pcie link down ! \n", ++ __FUNCTION__)); ++ ++ bus->dhd->is_pcie_watchdog_reset = TRUE; ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ DHD_TRACE(("%s Exit\n", __FUNCTION__)); ++} ++ ++/** Detach and free everything */ ++void ++dhdpcie_bus_release(dhd_bus_t *bus) ++{ ++ bool dongle_isolation = FALSE; ++ osl_t *osh = NULL; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (bus) { ++ ++ osh = bus->osh; ++ ASSERT(osh); ++ ++ if (bus->dhd) { ++ dhdpcie_advertise_bus_remove(bus->dhd); ++ dongle_isolation = bus->dhd->dongle_isolation; ++ bus->dhd->is_pcie_watchdog_reset = FALSE; ++ dhdpcie_bus_remove_prep(bus); ++ ++ if (bus->intr) { ++ dhdpcie_bus_intr_disable(bus); ++ dhdpcie_free_irq(bus); ++ } ++ dhdpcie_bus_release_dongle(bus, osh, dongle_isolation, TRUE); ++ dhd_detach(bus->dhd); ++ dhd_free(bus->dhd); ++ bus->dhd = NULL; ++ } ++ ++ /* unmap the regs and tcm here!! */ ++ if (bus->regs) { ++ dhdpcie_bus_reg_unmap(osh, bus->regs, DONGLE_REG_MAP_SIZE); ++ bus->regs = NULL; ++ } ++ if (bus->tcm) { ++ dhdpcie_bus_reg_unmap(osh, bus->tcm, DONGLE_TCM_MAP_SIZE); ++ bus->tcm = NULL; ++ } ++ ++ dhdpcie_bus_release_malloc(bus, osh); ++ /* Detach pcie shared structure */ ++ if (bus->pcie_sh) { ++ MFREE(osh, bus->pcie_sh, sizeof(pciedev_shared_t)); ++ bus->pcie_sh = NULL; ++ } ++ ++ if (bus->console.buf != NULL) { ++ MFREE(osh, bus->console.buf, bus->console.bufsize); ++ } ++ ++ ++ /* Finally free bus info */ ++ MFREE(osh, bus, sizeof(dhd_bus_t)); ++ ++ } ++ ++ DHD_TRACE(("%s: Exit\n", __FUNCTION__)); ++} /* dhdpcie_bus_release */ ++ ++ ++void ++dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) ++{ ++ DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, ++ bus->dhd, bus->dhd->dongle_reset)); ++ ++ if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) { ++ DHD_TRACE(("%s Exit\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (bus->sih) { ++ ++ if (!dongle_isolation && ++ (bus->dhd && !bus->dhd->is_pcie_watchdog_reset)) ++ pcie_watchdog_reset(bus->osh, bus->sih, ++ (sbpcieregs_t *) bus->regs); ++#ifdef DHD_EFI ++ dhdpcie_dongle_pwr_toggle(bus); ++#endif ++ if (bus->ltrsleep_on_unload) { ++ si_corereg(bus->sih, bus->sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, u.pcie2.ltr_state), ~0, 0); ++ } ++ ++ if (bus->sih->buscorerev == 13) ++ pcie_serdes_iddqdisable(bus->osh, bus->sih, ++ (sbpcieregs_t *) bus->regs); ++ ++ /* Disable CLKREQ# */ ++ dhdpcie_clkreq(bus->osh, 1, 0); ++ ++ if (bus->sih != NULL) { ++ si_detach(bus->sih); ++ bus->sih = NULL; ++ } ++ if (bus->vars && bus->varsz) ++ MFREE(osh, bus->vars, bus->varsz); ++ bus->vars = NULL; ++ } ++ ++ DHD_TRACE(("%s Exit\n", __FUNCTION__)); ++} ++ ++uint32 ++dhdpcie_bus_cfg_read_dword(dhd_bus_t *bus, uint32 addr, uint32 size) ++{ ++ uint32 data = OSL_PCI_READ_CONFIG(bus->osh, addr, size); ++ return data; ++} ++ ++/** 32 bit config write */ ++void ++dhdpcie_bus_cfg_write_dword(dhd_bus_t *bus, uint32 addr, uint32 size, uint32 data) ++{ ++ OSL_PCI_WRITE_CONFIG(bus->osh, addr, size, data); ++} ++ ++void ++dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data) ++{ ++ OSL_PCI_WRITE_CONFIG(bus->osh, PCI_BAR0_WIN, 4, data); ++} ++ ++void ++dhdpcie_bus_dongle_setmemsize(struct dhd_bus *bus, int mem_size) ++{ ++ int32 min_size = DONGLE_MIN_MEMSIZE; ++ /* Restrict the memsize to user specified limit */ ++ DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", ++ dhd_dongle_memsize, min_size)); ++ if ((dhd_dongle_memsize > min_size) && ++ (dhd_dongle_memsize < (int32)bus->orig_ramsize)) ++ bus->ramsize = dhd_dongle_memsize; ++} ++ ++void ++dhdpcie_bus_release_malloc(dhd_bus_t *bus, osl_t *osh) ++{ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (bus->dhd && bus->dhd->dongle_reset) ++ return; ++ ++ if (bus->vars && bus->varsz) { ++ MFREE(osh, bus->vars, bus->varsz); ++ bus->vars = NULL; ++ } ++ ++ DHD_TRACE(("%s: Exit\n", __FUNCTION__)); ++ return; ++ ++} ++ ++/** Stop bus module: clear pending frames, disable data flow */ ++void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) ++{ ++ uint32 status; ++ unsigned long flags; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (!bus->dhd) ++ return; ++ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ DHD_ERROR(("%s: already down by net_dev_reset\n", __FUNCTION__)); ++ goto done; ++ } ++ ++ DHD_DISABLE_RUNTIME_PM(bus->dhd); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ dhdpcie_bus_intr_disable(bus); ++ status = dhdpcie_bus_cfg_read_dword(bus, PCIIntstatus, 4); ++ dhdpcie_bus_cfg_write_dword(bus, PCIIntstatus, 4, status); ++ ++ if (!dhd_download_fw_on_driverload) { ++ dhd_dpc_kill(bus->dhd); ++ } ++ ++ /* Clear rx control and wake any waiters */ ++ dhd_os_set_ioctl_resp_timeout(IOCTL_DISABLE_TIMEOUT); ++ dhd_wakeup_ioctl_event(bus->dhd, IOCTL_RETURN_ON_BUS_STOP); ++ ++done: ++ return; ++} ++ ++#ifdef DEVICE_TX_STUCK_DETECT ++void ++dhd_bus_send_msg_to_daemon(int reason) ++{ ++ bcm_to_info_t to_info; ++ ++ to_info.magic = BCM_TO_MAGIC; ++ to_info.reason = reason; ++ ++ dhd_send_msg_to_daemon(NULL, (void *)&to_info, sizeof(bcm_to_info_t)); ++ return; ++} ++ ++/** ++ * scan the flow rings in active list to check if stuck and notify application ++ * The conditions for warn/stuck detection are ++ * 1. Flow ring is active ++ * 2. There are packets to be consumed by the consumer (wr != rd) ++ * If 1 and 2 are true, then ++ * 3. Warn, if Tx completion is not received for a duration of DEVICE_TX_STUCK_WARN_DURATION ++ * 4. Trap FW, if Tx completion is not received for a duration of DEVICE_TX_STUCK_DURATION ++ */ ++static void ++dhd_bus_device_tx_stuck_scan(dhd_bus_t *bus) ++{ ++ uint32 tx_cmpl; ++ unsigned long list_lock_flags; ++ unsigned long ring_lock_flags; ++ dll_t *item, *prev; ++ flow_ring_node_t *flow_ring_node; ++ bool ring_empty; ++ bool active; ++ ++ DHD_FLOWRING_LIST_LOCK(bus->dhd->flowring_list_lock, list_lock_flags); ++ ++ for (item = dll_tail_p(&bus->flowring_active_list); ++ !dll_end(&bus->flowring_active_list, item); item = prev) { ++ ++ prev = dll_prev_p(item); ++ ++ flow_ring_node = dhd_constlist_to_flowring(item); ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, ring_lock_flags); ++ tx_cmpl = flow_ring_node->tx_cmpl; ++ active = flow_ring_node->active; ++ ring_empty = dhd_prot_is_cmpl_ring_empty(bus->dhd, flow_ring_node->prot_info); ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, ring_lock_flags); ++ ++ if (ring_empty) { ++ /* reset conters... etc */ ++ flow_ring_node->stuck_count = 0; ++ flow_ring_node->tx_cmpl_prev = tx_cmpl; ++ continue; ++ } ++ /** ++ * DEVICE_TX_STUCK_WARN_DURATION, DEVICE_TX_STUCK_DURATION are integer ++ * representation of time, to decide if a flow is in warn state or stuck. ++ * ++ * flow_ring_node->stuck_count is an integer counter representing how long ++ * tx_cmpl is not received though there are pending packets in the ring ++ * to be consumed by the dongle for that particular flow. ++ * ++ * This method of determining time elapsed is helpful in sleep/wake scenarios. ++ * If host sleeps and wakes up, that sleep time is not considered into ++ * stuck duration. ++ */ ++ if ((tx_cmpl == flow_ring_node->tx_cmpl_prev) && active) { ++ ++ flow_ring_node->stuck_count++; ++ ++ DHD_ERROR(("%s: flowid: %d tx_cmpl: %u tx_cmpl_prev: %u stuck_count: %d\n", ++ __func__, flow_ring_node->flowid, tx_cmpl, ++ flow_ring_node->tx_cmpl_prev, flow_ring_node->stuck_count)); ++ ++ switch (flow_ring_node->stuck_count) { ++ case DEVICE_TX_STUCK_WARN_DURATION: ++ /** ++ * Notify Device Tx Stuck Notification App about the ++ * device Tx stuck warning for this flowid. ++ * App will collect the logs required. ++ */ ++ DHD_ERROR(("stuck warning for flowid: %d sent to app\n", ++ flow_ring_node->flowid)); ++ dhd_bus_send_msg_to_daemon(REASON_DEVICE_TX_STUCK_WARNING); ++ break; ++ case DEVICE_TX_STUCK_DURATION: ++ /** ++ * Notify Device Tx Stuck Notification App about the ++ * device Tx stuck info for this flowid. ++ * App will collect the logs required. ++ */ ++ DHD_ERROR(("stuck information for flowid: %d sent to app\n", ++ flow_ring_node->flowid)); ++ dhd_bus_send_msg_to_daemon(REASON_DEVICE_TX_STUCK); ++ break; ++ default: ++ break; ++ } ++ } else { ++ flow_ring_node->tx_cmpl_prev = tx_cmpl; ++ flow_ring_node->stuck_count = 0; ++ } ++ } ++ DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, list_lock_flags); ++} ++/** ++ * schedules dhd_bus_device_tx_stuck_scan after DEVICE_TX_STUCK_CKECK_TIMEOUT, ++ * to determine if any flowid is stuck. ++ */ ++static void ++dhd_bus_device_stuck_scan(dhd_bus_t *bus) ++{ ++ uint32 time_stamp; /* in millisec */ ++ uint32 diff; ++ ++ /* Need not run the algorith if Dongle has trapped */ ++ if (bus->dhd->dongle_trap_occured) { ++ return; ++ } ++ time_stamp = OSL_SYSUPTIME(); ++ diff = time_stamp - bus->device_tx_stuck_check; ++ if (diff > DEVICE_TX_STUCK_CKECK_TIMEOUT) { ++ dhd_bus_device_tx_stuck_scan(bus); ++ bus->device_tx_stuck_check = OSL_SYSUPTIME(); ++ } ++ return; ++} ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ ++/** Watchdog timer function */ ++bool dhd_bus_watchdog(dhd_pub_t *dhd) ++{ ++ unsigned long flags; ++ dhd_bus_t *bus; ++ bus = dhd->bus; ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd) || ++ DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhd)) { ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ return FALSE; ++ } ++ DHD_BUS_BUSY_SET_IN_WD(dhd); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++ dhdpcie_runtime_bus_wake(dhd, TRUE, __builtin_return_address(0)); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ ++ ++ /* Poll for console output periodically */ ++ if (dhd->busstate == DHD_BUS_DATA && ++ dhd_console_ms != 0 && !bus->d3_suspend_pending) { ++ bus->console.count += dhd_watchdog_ms; ++ if (bus->console.count >= dhd_console_ms) { ++ bus->console.count -= dhd_console_ms; ++ /* Make sure backplane clock is on */ ++ if (dhdpcie_bus_readconsole(bus) < 0) ++ dhd_console_ms = 0; /* On error, stop trying */ ++ } ++ } ++ ++#ifdef DHD_READ_INTSTATUS_IN_DPC ++ if (bus->poll) { ++ bus->ipend = TRUE; ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); /* queue DPC now!! */ ++ } ++#endif /* DHD_READ_INTSTATUS_IN_DPC */ ++ ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++ /* If haven't communicated with device for a while, deassert the Device_Wake GPIO */ ++ if (dhd_doorbell_timeout != 0 && dhd->busstate == DHD_BUS_DATA && ++ dhd->up && dhd_timeout_expired(&bus->doorbell_timer)) { ++ dhd_bus_set_device_wake(bus, FALSE); ++ } ++#endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ ++#ifdef PCIE_INB_DW ++ if (INBAND_DW_ENAB(bus)) { ++ if (bus->ds_exit_timeout) { ++ bus->ds_exit_timeout --; ++ if (bus->ds_exit_timeout == 1) { ++ DHD_ERROR(("DS-EXIT TIMEOUT\n")); ++ bus->ds_exit_timeout = 0; ++ bus->inband_ds_exit_to_cnt++; ++ } ++ } ++ if (bus->host_sleep_exit_timeout) { ++ bus->host_sleep_exit_timeout --; ++ if (bus->host_sleep_exit_timeout == 1) { ++ DHD_ERROR(("HOST_SLEEP-EXIT TIMEOUT\n")); ++ bus->host_sleep_exit_timeout = 0; ++ bus->inband_host_sleep_exit_to_cnt++; ++ } ++ } ++ } ++#endif /* PCIE_INB_DW */ ++ ++#ifdef DEVICE_TX_STUCK_DETECT ++ if (dhd->bus->dev_tx_stuck_monitor == TRUE) { ++ dhd_bus_device_stuck_scan(dhd->bus); ++ } ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ DHD_BUS_BUSY_CLEAR_IN_WD(dhd); ++ dhd_os_busbusy_wake(dhd); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ return TRUE; ++} /* dhd_bus_watchdog */ ++ ++ ++uint16 ++dhd_get_chipid(dhd_pub_t *dhd) ++{ ++ dhd_bus_t *bus = dhd->bus; ++ ++ if (bus && bus->sih) ++ return (uint16)si_chipid(bus->sih); ++ else ++ return 0; ++} ++ ++/* Download firmware image and nvram image */ ++int ++dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ++ char *pfw_path, char *pnv_path, ++ char *pclm_path, char *pconf_path) ++{ ++ int ret; ++ ++ bus->fw_path = pfw_path; ++ bus->nv_path = pnv_path; ++ bus->dhd->clm_path = pclm_path; ++ bus->dhd->conf_path = pconf_path; ++ ++ ++#if defined(DHD_BLOB_EXISTENCE_CHECK) ++ dhd_set_blob_support(bus->dhd, bus->fw_path); ++#endif /* DHD_BLOB_EXISTENCE_CHECK */ ++ ++ DHD_ERROR(("%s: firmware path=%s, nvram path=%s\n", ++ __FUNCTION__, bus->fw_path, bus->nv_path)); ++ ++ ret = dhdpcie_download_firmware(bus, osh); ++ ++ return ret; ++} ++ ++void ++dhd_set_bus_params(struct dhd_bus *bus) ++{ ++ if (bus->dhd->conf->dhd_poll >= 0) { ++ bus->poll = bus->dhd->conf->dhd_poll; ++ if (!bus->pollrate) ++ bus->pollrate = 1; ++ printf("%s: set polling mode %d\n", __FUNCTION__, bus->dhd->conf->dhd_poll); ++ } ++} ++ ++static int ++dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh) ++{ ++ int ret = 0; ++#if defined(BCM_REQUEST_FW) ++ uint chipid = bus->sih->chip; ++ uint revid = bus->sih->chiprev; ++ char fw_path[64] = "/lib/firmware/brcm/bcm"; /* path to firmware image */ ++ char nv_path[64]; /* path to nvram vars file */ ++ bus->fw_path = fw_path; ++ bus->nv_path = nv_path; ++ switch (chipid) { ++ case BCM43570_CHIP_ID: ++ bcmstrncat(fw_path, "43570", 5); ++ switch (revid) { ++ case 0: ++ bcmstrncat(fw_path, "a0", 2); ++ break; ++ case 2: ++ bcmstrncat(fw_path, "a2", 2); ++ break; ++ default: ++ DHD_ERROR(("%s: revid is not found %x\n", __FUNCTION__, ++ revid)); ++ break; ++ } ++ break; ++ default: ++ DHD_ERROR(("%s: unsupported device %x\n", __FUNCTION__, ++ chipid)); ++ return 0; ++ } ++ /* load board specific nvram file */ ++ snprintf(bus->nv_path, sizeof(nv_path), "%s.nvm", fw_path); ++ /* load firmware */ ++ snprintf(bus->fw_path, sizeof(fw_path), "%s-firmware.bin", fw_path); ++#endif /* BCM_REQUEST_FW */ ++ ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ ++ dhd_conf_set_path_params(bus->dhd, NULL, bus->fw_path, bus->nv_path); ++ dhd_set_bus_params(bus); ++ ++ ret = _dhdpcie_download_firmware(bus); ++ ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++ return ret; ++} ++ ++static int ++dhdpcie_download_code_file(struct dhd_bus *bus, char *pfw_path) ++{ ++ int bcmerror = BCME_ERROR; ++ int offset = 0; ++ int len = 0; ++ bool store_reset; ++ char *imgbuf = NULL; ++ uint8 *memblock = NULL, *memptr; ++ uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct ++ ++ int offset_end = bus->ramsize; ++ ++#ifndef DHD_EFI ++ DHD_ERROR(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); ++#endif /* DHD_EFI */ ++ ++ /* Should succeed in opening image if it is actually given through registry ++ * entry or in module param. ++ */ ++ imgbuf = dhd_os_open_image(pfw_path); ++ if (imgbuf == NULL) { ++ printf("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path); ++ goto err; ++ } ++ ++ memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); ++ if (memblock == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); ++ goto err; ++ } ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); ++ if (memptr_tmp == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); ++ goto err; ++ } ++ } ++ if ((uint32)(uintptr)memblock % DHD_SDALIGN) { ++ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); ++ } ++ ++ ++ /* check if CR4/CA7 */ ++ store_reset = (si_setcore(bus->sih, ARMCR4_CORE_ID, 0) || ++ si_setcore(bus->sih, ARMCA7_CORE_ID, 0)); ++ ++ /* Download image with MEMBLOCK size */ ++ while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, imgbuf))) { ++ if (len < 0) { ++ DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); ++ bcmerror = BCME_ERROR; ++ goto err; ++ } ++ /* if address is 0, store the reset instruction to be written in 0 */ ++ if (store_reset) { ++ ASSERT(offset == 0); ++ bus->resetinstr = *(((uint32*)memptr)); ++ /* Add start of RAM address to the address given by user */ ++ offset += bus->dongle_ram_base; ++ offset_end += offset; ++ store_reset = FALSE; ++ } ++ ++ bcmerror = dhdpcie_bus_membytes(bus, TRUE, offset, (uint8 *)memptr, len); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset)); ++ goto err; ++ } ++ ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ bcmerror = dhdpcie_bus_membytes(bus, FALSE, offset, memptr_tmp, len); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset)); ++ goto err; ++ } ++ if (memcmp(memptr_tmp, memptr, len)) { ++ DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__)); ++ goto err; ++ } else ++ DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__)); ++ } ++ offset += MEMBLOCK; ++ ++ if (offset >= offset_end) { ++ DHD_ERROR(("%s: invalid address access to %x (offset end: %x)\n", ++ __FUNCTION__, offset, offset_end)); ++ bcmerror = BCME_ERROR; ++ goto err; ++ } ++ } ++ ++err: ++ if (memblock) { ++ MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ if (memptr_tmp) ++ MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN); ++ } ++ } ++ ++ if (imgbuf) { ++ dhd_os_close_image(imgbuf); ++ } ++ ++ return bcmerror; ++} /* dhdpcie_download_code_file */ ++ ++#ifdef CUSTOMER_HW4_DEBUG ++#define MIN_NVRAMVARS_SIZE 128 ++#endif /* CUSTOMER_HW4_DEBUG */ ++ ++static int ++dhdpcie_download_nvram(struct dhd_bus *bus) ++{ ++ int bcmerror = BCME_ERROR; ++ uint len; ++ char * memblock = NULL; ++ char *bufp; ++ char *pnv_path; ++ bool nvram_file_exists; ++ bool nvram_uefi_exists = FALSE; ++ bool local_alloc = FALSE; ++ pnv_path = bus->nv_path; ++ ++#ifdef BCMEMBEDIMAGE ++ nvram_file_exists = TRUE; ++#else ++ nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); ++#endif ++ ++ /* First try UEFI */ ++ len = MAX_NVRAMBUF_SIZE; ++ dhd_get_download_buffer(bus->dhd, NULL, NVRAM, &memblock, (int *)&len); ++ ++ /* If UEFI empty, then read from file system */ ++ if ((len <= 0) || (memblock == NULL)) { ++ ++ if (nvram_file_exists) { ++ len = MAX_NVRAMBUF_SIZE; ++ dhd_get_download_buffer(bus->dhd, pnv_path, NVRAM, &memblock, (int *)&len); ++ if ((len <= 0 || len > MAX_NVRAMBUF_SIZE)) { ++ goto err; ++ } ++ } ++ else { ++ /* For SROM OTP no external file or UEFI required */ ++ bcmerror = BCME_OK; ++ } ++ } else { ++ nvram_uefi_exists = TRUE; ++ } ++ ++ DHD_ERROR(("%s: dhd_get_download_buffer len %d\n", __FUNCTION__, len)); ++ ++ if (len > 0 && len <= MAX_NVRAMBUF_SIZE && memblock != NULL) { ++ bufp = (char *) memblock; ++ ++#ifdef CACHE_FW_IMAGES ++ if (bus->processed_nvram_params_len) { ++ len = bus->processed_nvram_params_len; ++ } ++ ++ if (!bus->processed_nvram_params_len) { ++ bufp[len] = 0; ++ if (nvram_uefi_exists || nvram_file_exists) { ++ len = process_nvram_vars(bufp, len); ++ bus->processed_nvram_params_len = len; ++ } ++ } else ++#else ++ { ++ bufp[len] = 0; ++ if (nvram_uefi_exists || nvram_file_exists) { ++ len = process_nvram_vars(bufp, len); ++ } ++ } ++#endif /* CACHE_FW_IMAGES */ ++ ++ DHD_ERROR(("%s: process_nvram_vars len %d\n", __FUNCTION__, len)); ++#ifdef CUSTOMER_HW4_DEBUG ++ if (len < MIN_NVRAMVARS_SIZE) { ++ DHD_ERROR(("%s: invalid nvram size in process_nvram_vars \n", ++ __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto err; ++ } ++#endif /* CUSTOMER_HW4_DEBUG */ ++ ++ if (len % 4) { ++ len += 4 - (len % 4); ++ } ++ bufp += len; ++ *bufp++ = 0; ++ if (len) ++ bcmerror = dhdpcie_downloadvars(bus, memblock, len + 1); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error downloading vars: %d\n", ++ __FUNCTION__, bcmerror)); ++ } ++ } ++ ++ ++err: ++ if (memblock) { ++ if (local_alloc) { ++ MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); ++ } else { ++ dhd_free_download_buffer(bus->dhd, memblock, MAX_NVRAMBUF_SIZE); ++ } ++ } ++ ++ return bcmerror; ++} ++ ++ ++#ifdef BCMEMBEDIMAGE ++int ++dhdpcie_download_code_array(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ int offset = 0; ++ unsigned char *p_dlarray = NULL; ++ unsigned int dlarray_size = 0; ++ unsigned int downloded_len, remaining_len, len; ++ char *p_dlimagename, *p_dlimagever, *p_dlimagedate; ++ uint8 *memblock = NULL, *memptr; ++ ++ downloded_len = 0; ++ remaining_len = 0; ++ len = 0; ++ ++#ifdef DHD_EFI ++ p_dlarray = rtecdc_fw_arr; ++ dlarray_size = sizeof(rtecdc_fw_arr); ++#else ++ p_dlarray = dlarray; ++ dlarray_size = sizeof(dlarray); ++ p_dlimagename = dlimagename; ++ p_dlimagever = dlimagever; ++ p_dlimagedate = dlimagedate; ++#endif /* DHD_EFI */ ++ ++#ifndef DHD_EFI ++ if ((p_dlarray == 0) || (dlarray_size == 0) ||(dlarray_size > bus->ramsize) || ++ (p_dlimagename == 0) || (p_dlimagever == 0) || (p_dlimagedate == 0)) ++ goto err; ++#endif /* DHD_EFI */ ++ ++ memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); ++ if (memblock == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); ++ goto err; ++ } ++ if ((uint32)(uintptr)memblock % DHD_SDALIGN) ++ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); ++ ++ while (downloded_len < dlarray_size) { ++ remaining_len = dlarray_size - downloded_len; ++ if (remaining_len >= MEMBLOCK) ++ len = MEMBLOCK; ++ else ++ len = remaining_len; ++ ++ memcpy(memptr, (p_dlarray + downloded_len), len); ++ /* check if CR4/CA7 */ ++ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0) || ++ si_setcore(bus->sih, SYSMEM_CORE_ID, 0)) { ++ /* if address is 0, store the reset instruction to be written in 0 */ ++ if (offset == 0) { ++ bus->resetinstr = *(((uint32*)memptr)); ++ /* Add start of RAM address to the address given by user */ ++ offset += bus->dongle_ram_base; ++ } ++ } ++ bcmerror = dhdpcie_bus_membytes(bus, TRUE, offset, (uint8 *)memptr, len); ++ downloded_len += len; ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset)); ++ goto err; ++ } ++ offset += MEMBLOCK; ++ } ++ ++#ifdef DHD_DEBUG ++ /* Upload and compare the downloaded code */ ++ { ++ unsigned char *ularray = NULL; ++ unsigned int uploded_len; ++ uploded_len = 0; ++ bcmerror = -1; ++ ularray = MALLOC(bus->dhd->osh, dlarray_size); ++ if (ularray == NULL) ++ goto upload_err; ++ /* Upload image to verify downloaded contents. */ ++ offset = bus->dongle_ram_base; ++ memset(ularray, 0xaa, dlarray_size); ++ while (uploded_len < dlarray_size) { ++ remaining_len = dlarray_size - uploded_len; ++ if (remaining_len >= MEMBLOCK) ++ len = MEMBLOCK; ++ else ++ len = remaining_len; ++ bcmerror = dhdpcie_bus_membytes(bus, FALSE, offset, ++ (uint8 *)(ularray + uploded_len), len); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset)); ++ goto upload_err; ++ } ++ ++ uploded_len += len; ++ offset += MEMBLOCK; ++ } ++#ifdef DHD_EFI ++ if (memcmp(p_dlarray, ularray, dlarray_size)) { ++ DHD_ERROR(("%s: Downloaded image is corrupted ! \n", __FUNCTION__)); ++ goto upload_err; ++ } else ++ DHD_ERROR(("%s: Download, Upload and compare succeeded .\n", __FUNCTION__)); ++#else ++ if (memcmp(p_dlarray, ularray, dlarray_size)) { ++ DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", ++ __FUNCTION__, p_dlimagename, p_dlimagever, p_dlimagedate)); ++ goto upload_err; ++ ++ } else ++ DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", ++ __FUNCTION__, p_dlimagename, p_dlimagever, p_dlimagedate)); ++#endif /* DHD_EFI */ ++ ++upload_err: ++ if (ularray) ++ MFREE(bus->dhd->osh, ularray, dlarray_size); ++ } ++#endif /* DHD_DEBUG */ ++err: ++ ++ if (memblock) ++ MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); ++ ++ return bcmerror; ++} /* dhdpcie_download_code_array */ ++#endif /* BCMEMBEDIMAGE */ ++ ++ ++static int ++dhdpcie_ramsize_read_image(struct dhd_bus *bus, char *buf, int len) ++{ ++ int bcmerror = BCME_ERROR; ++ char *imgbuf = NULL; ++ ++ if (buf == NULL || len == 0) ++ goto err; ++ ++ /* External image takes precedence if specified */ ++ if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { ++ imgbuf = dhd_os_open_image(bus->fw_path); ++ if (imgbuf == NULL) { ++ DHD_ERROR(("%s: Failed to open firmware file\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ /* Read it */ ++ if (len != dhd_os_get_image_block(buf, len, imgbuf)) { ++ DHD_ERROR(("%s: Failed to read %d bytes data\n", __FUNCTION__, len)); ++ goto err; ++ } ++ ++ bcmerror = BCME_OK; ++ } ++ ++err: ++ if (imgbuf) ++ dhd_os_close_image(imgbuf); ++ ++ return bcmerror; ++} ++ ++ ++/* The ramsize can be changed in the dongle image, for example 4365 chip share the sysmem ++ * with BMC and we can adjust how many sysmem belong to CA7 during dongle compilation. ++ * So in DHD we need to detect this case and update the correct dongle RAMSIZE as well. ++ */ ++static void ++dhdpcie_ramsize_adj(struct dhd_bus *bus) ++{ ++ int i, search_len = 0; ++ uint8 *memptr = NULL; ++ uint8 *ramsizeptr = NULL; ++ uint ramsizelen; ++ uint32 ramsize_ptr_ptr[] = {RAMSIZE_PTR_PTR_LIST}; ++ hnd_ramsize_ptr_t ramsize_info; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ /* Adjust dongle RAMSIZE already called. */ ++ if (bus->ramsize_adjusted) { ++ return; ++ } ++ ++ /* success or failure, we don't want to be here ++ * more than once. ++ */ ++ bus->ramsize_adjusted = TRUE; ++ ++ /* Not handle if user restrict dongle ram size enabled */ ++ if (dhd_dongle_memsize) { ++ DHD_ERROR(("%s: user restrict dongle ram size to %d.\n", __FUNCTION__, ++ dhd_dongle_memsize)); ++ return; ++ } ++ ++#ifndef BCMEMBEDIMAGE ++ /* Out immediately if no image to download */ ++ if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { ++ DHD_ERROR(("%s: no fimrware file\n", __FUNCTION__)); ++ return; ++ } ++#endif /* !BCMEMBEDIMAGE */ ++ ++ /* Get maximum RAMSIZE info search length */ ++ for (i = 0; ; i++) { ++ if (ramsize_ptr_ptr[i] == RAMSIZE_PTR_PTR_END) ++ break; ++ ++ if (search_len < (int)ramsize_ptr_ptr[i]) ++ search_len = (int)ramsize_ptr_ptr[i]; ++ } ++ ++ if (!search_len) ++ return; ++ ++ search_len += sizeof(hnd_ramsize_ptr_t); ++ ++ memptr = MALLOC(bus->dhd->osh, search_len); ++ if (memptr == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, search_len)); ++ return; ++ } ++ ++ /* External image takes precedence if specified */ ++ if (dhdpcie_ramsize_read_image(bus, (char *)memptr, search_len) != BCME_OK) { ++#if defined(BCMEMBEDIMAGE) && !defined(DHD_EFI) ++ unsigned char *p_dlarray = NULL; ++ unsigned int dlarray_size = 0; ++ char *p_dlimagename, *p_dlimagever, *p_dlimagedate; ++ ++ p_dlarray = dlarray; ++ dlarray_size = sizeof(dlarray); ++ p_dlimagename = dlimagename; ++ p_dlimagever = dlimagever; ++ p_dlimagedate = dlimagedate; ++ ++ if ((p_dlarray == 0) || (dlarray_size == 0) || (p_dlimagename == 0) || ++ (p_dlimagever == 0) || (p_dlimagedate == 0)) ++ goto err; ++ ++ ramsizeptr = p_dlarray; ++ ramsizelen = dlarray_size; ++#else ++ goto err; ++#endif /* BCMEMBEDIMAGE && !DHD_EFI */ ++ } ++ else { ++ ramsizeptr = memptr; ++ ramsizelen = search_len; ++ } ++ ++ if (ramsizeptr) { ++ /* Check Magic */ ++ for (i = 0; ; i++) { ++ if (ramsize_ptr_ptr[i] == RAMSIZE_PTR_PTR_END) ++ break; ++ ++ if (ramsize_ptr_ptr[i] + sizeof(hnd_ramsize_ptr_t) > ramsizelen) ++ continue; ++ ++ memcpy((char *)&ramsize_info, ramsizeptr + ramsize_ptr_ptr[i], ++ sizeof(hnd_ramsize_ptr_t)); ++ ++ if (ramsize_info.magic == HTOL32(HND_RAMSIZE_PTR_MAGIC)) { ++ bus->orig_ramsize = LTOH32(ramsize_info.ram_size); ++ bus->ramsize = LTOH32(ramsize_info.ram_size); ++ DHD_ERROR(("%s: Adjust dongle RAMSIZE to 0x%x\n", __FUNCTION__, ++ bus->ramsize)); ++ break; ++ } ++ } ++ } ++ ++err: ++ if (memptr) ++ MFREE(bus->dhd->osh, memptr, search_len); ++ ++ return; ++} /* _dhdpcie_download_firmware */ ++ ++static int ++_dhdpcie_download_firmware(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ ++ bool embed = FALSE; /* download embedded firmware */ ++ bool dlok = FALSE; /* download firmware succeeded */ ++ ++ /* Out immediately if no image to download */ ++ if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { ++#ifdef BCMEMBEDIMAGE ++ embed = TRUE; ++#else ++ DHD_ERROR(("%s: no fimrware file\n", __FUNCTION__)); ++ return 0; ++#endif ++ } ++ /* Adjust ram size */ ++ dhdpcie_ramsize_adj(bus); ++ ++ /* Keep arm in reset */ ++ if (dhdpcie_bus_download_state(bus, TRUE)) { ++ DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ /* External image takes precedence if specified */ ++ if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { ++ if (dhdpcie_download_code_file(bus, bus->fw_path)) { ++ DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); ++#ifdef BCMEMBEDIMAGE ++ embed = TRUE; ++#else ++ goto err; ++#endif ++ } else { ++ embed = FALSE; ++ dlok = TRUE; ++ } ++ } ++ ++#ifdef BCMEMBEDIMAGE ++ if (embed) { ++ if (dhdpcie_download_code_array(bus)) { ++ DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__)); ++ goto err; ++ } else { ++ dlok = TRUE; ++ } ++ } ++#else ++ BCM_REFERENCE(embed); ++#endif ++ if (!dlok) { ++ DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ /* EXAMPLE: nvram_array */ ++ /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ ++ /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ ++ ++ ++ /* External nvram takes precedence if specified */ ++ if (dhdpcie_download_nvram(bus)) { ++ DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ /* Take arm out of reset */ ++ if (dhdpcie_bus_download_state(bus, FALSE)) { ++ DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ bcmerror = 0; ++ ++err: ++ return bcmerror; ++} /* _dhdpcie_download_firmware */ ++ ++#define CONSOLE_LINE_MAX 192 ++ ++static int ++dhdpcie_bus_readconsole(dhd_bus_t *bus) ++{ ++ dhd_console_t *c = &bus->console; ++ uint8 line[CONSOLE_LINE_MAX], ch; ++ uint32 n, idx, addr; ++ int rv; ++ ++ /* Don't do anything until FWREADY updates console address */ ++ if (bus->console_addr == 0) ++ return -1; ++ ++ /* Read console log struct */ ++ addr = bus->console_addr + OFFSETOF(hnd_cons_t, log); ++ ++ if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) ++ return rv; ++ ++ /* Allocate console buffer (one time only) */ ++ if (c->buf == NULL) { ++ c->bufsize = ltoh32(c->log.buf_size); ++ if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) ++ return BCME_NOMEM; ++ } ++ idx = ltoh32(c->log.idx); ++ ++ /* Protect against corrupt value */ ++ if (idx > c->bufsize) ++ return BCME_ERROR; ++ ++ /* Skip reading the console buffer if the index pointer has not moved */ ++ if (idx == c->last) ++ return BCME_OK; ++ ++ /* Read the console buffer */ ++ addr = ltoh32(c->log.buf); ++ if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 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; ++ DHD_FWLOG(("CONSOLE: %s\n", line)); ++ } ++ } ++break2: ++ ++ return BCME_OK; ++} /* dhdpcie_bus_readconsole */ ++ ++void ++dhd_bus_dump_console_buffer(dhd_bus_t *bus) ++{ ++ uint32 n, i; ++ uint32 addr; ++ char *console_buffer = NULL; ++ uint32 console_ptr, console_size, console_index; ++ uint8 line[CONSOLE_LINE_MAX], ch; ++ int rv; ++ ++ DHD_ERROR(("%s: Dump Complete Console Buffer\n", __FUNCTION__)); ++ ++ if (bus->is_linkdown) { ++ DHD_ERROR(("%s: Skip dump Console Buffer due to PCIe link down\n", __FUNCTION__)); ++ return; ++ } ++ ++ addr = bus->pcie_sh->console_addr + OFFSETOF(hnd_cons_t, log); ++ if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, ++ (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) { ++ goto exit; ++ } ++ ++ addr = bus->pcie_sh->console_addr + OFFSETOF(hnd_cons_t, log.buf_size); ++ if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, ++ (uint8 *)&console_size, sizeof(console_size))) < 0) { ++ goto exit; ++ } ++ ++ addr = bus->pcie_sh->console_addr + OFFSETOF(hnd_cons_t, log.idx); ++ if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, ++ (uint8 *)&console_index, sizeof(console_index))) < 0) { ++ goto exit; ++ } ++ ++ console_ptr = ltoh32(console_ptr); ++ console_size = ltoh32(console_size); ++ console_index = ltoh32(console_index); ++ ++ if (console_size > CONSOLE_BUFFER_MAX || ++ !(console_buffer = MALLOC(bus->dhd->osh, console_size))) { ++ goto exit; ++ } ++ ++ if ((rv = dhdpcie_bus_membytes(bus, FALSE, console_ptr, ++ (uint8 *)console_buffer, console_size)) < 0) { ++ goto exit; ++ } ++ ++ for (i = 0, n = 0; i < console_size; i += n + 1) { ++ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { ++ ch = console_buffer[(console_index + i + n) % console_size]; ++ if (ch == '\n') ++ break; ++ line[n] = ch; ++ } ++ ++ ++ if (n > 0) { ++ if (line[n - 1] == '\r') ++ n--; ++ line[n] = 0; ++ /* Don't use DHD_ERROR macro since we print ++ * a lot of information quickly. The macro ++ * will truncate a lot of the printfs ++ */ ++ ++ DHD_FWLOG(("CONSOLE: %s\n", line)); ++ } ++ } ++ ++exit: ++ if (console_buffer) ++ MFREE(bus->dhd->osh, console_buffer, console_size); ++ return; ++} ++ ++static int ++dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size) ++{ ++ int bcmerror = 0; ++ uint msize = 512; ++ char *mbuffer = NULL; ++ uint maxstrlen = 256; ++ char *str = NULL; ++ pciedev_shared_t *local_pciedev_shared = bus->pcie_sh; ++ struct bcmstrbuf strbuf; ++ unsigned long flags; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (DHD_NOCHECKDIED_ON()) { ++ return 0; ++ } ++ ++ if (data == NULL) { ++ /* ++ * Called after a rx ctrl timeout. "data" is NULL. ++ * allocate memory to trace the trap or assert. ++ */ ++ size = msize; ++ mbuffer = data = MALLOC(bus->dhd->osh, msize); ++ ++ if (mbuffer == NULL) { ++ DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ } ++ ++ if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { ++ DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_SET_IN_CHECKDIED(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ if ((bcmerror = dhdpcie_readshared(bus)) < 0) { ++ goto done; ++ } ++ ++ bcm_binit(&strbuf, data, size); ++ ++ bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", ++ local_pciedev_shared->msgtrace_addr, local_pciedev_shared->console_addr); ++ ++ if ((local_pciedev_shared->flags & PCIE_SHARED_ASSERT_BUILT) == 0) { ++ /* NOTE: Misspelled assert is intentional - DO NOT FIX. ++ * (Avoids conflict with real asserts for programmatic parsing of output.) ++ */ ++ bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); ++ } ++ ++ if ((bus->pcie_sh->flags & (PCIE_SHARED_ASSERT|PCIE_SHARED_TRAP)) == 0) { ++ /* NOTE: Misspelled assert is intentional - DO NOT FIX. ++ * (Avoids conflict with real asserts for programmatic parsing of output.) ++ */ ++ bcm_bprintf(&strbuf, "No trap%s in dongle", ++ (bus->pcie_sh->flags & PCIE_SHARED_ASSERT_BUILT) ++ ?"/assrt" :""); ++ } else { ++ if (bus->pcie_sh->flags & PCIE_SHARED_ASSERT) { ++ /* Download assert */ ++ bcm_bprintf(&strbuf, "Dongle assert"); ++ if (bus->pcie_sh->assert_exp_addr != 0) { ++ str[0] = '\0'; ++ if ((bcmerror = dhdpcie_bus_membytes(bus, FALSE, ++ bus->pcie_sh->assert_exp_addr, ++ (uint8 *)str, maxstrlen)) < 0) { ++ goto done; ++ } ++ ++ str[maxstrlen - 1] = '\0'; ++ bcm_bprintf(&strbuf, " expr \"%s\"", str); ++ } ++ ++ if (bus->pcie_sh->assert_file_addr != 0) { ++ str[0] = '\0'; ++ if ((bcmerror = dhdpcie_bus_membytes(bus, FALSE, ++ bus->pcie_sh->assert_file_addr, ++ (uint8 *)str, maxstrlen)) < 0) { ++ goto done; ++ } ++ ++ str[maxstrlen - 1] = '\0'; ++ bcm_bprintf(&strbuf, " file \"%s\"", str); ++ } ++ ++ bcm_bprintf(&strbuf, " line %d ", bus->pcie_sh->assert_line); ++ } ++ ++ if (bus->pcie_sh->flags & PCIE_SHARED_TRAP) { ++ trap_t *tr = &bus->dhd->last_trap_info; ++ bus->dhd->dongle_trap_occured = TRUE; ++ if ((bcmerror = dhdpcie_bus_membytes(bus, FALSE, ++ bus->pcie_sh->trap_addr, (uint8*)tr, sizeof(trap_t))) < 0) { ++ goto done; ++ } ++ dhd_bus_dump_trap_info(bus, &strbuf); ++ ++ dhd_bus_dump_console_buffer(bus); ++ } ++ } ++ ++ if (bus->pcie_sh->flags & (PCIE_SHARED_ASSERT | PCIE_SHARED_TRAP)) { ++ printf("%s: %s\n", __FUNCTION__, strbuf.origbuf); ++#ifdef REPORT_FATAL_TIMEOUTS ++ /** ++ * stop the timers as FW trapped ++ */ ++ if (dhd_stop_scan_timer(bus->dhd)) { ++ DHD_ERROR(("dhd_stop_scan_timer failed\n")); ++ ASSERT(0); ++ } ++ if (dhd_stop_bus_timer(bus->dhd)) { ++ DHD_ERROR(("dhd_stop_bus_timer failed\n")); ++ ASSERT(0); ++ } ++ if (dhd_stop_cmd_timer(bus->dhd)) { ++ DHD_ERROR(("dhd_stop_cmd_timer failed\n")); ++ ASSERT(0); ++ } ++ if (dhd_stop_join_timer(bus->dhd)) { ++ DHD_ERROR(("dhd_stop_join_timer failed\n")); ++ ASSERT(0); ++ } ++#endif /* REPORT_FATAL_TIMEOUTS */ ++ ++ dhd_prot_debug_info_print(bus->dhd); ++ ++#if defined(DHD_FW_COREDUMP) ++ /* save core dump or write to a file */ ++ if (bus->dhd->memdump_enabled) { ++ bus->dhd->memdump_type = DUMP_TYPE_DONGLE_TRAP; ++ dhdpcie_mem_dump(bus); ++ } ++#endif /* DHD_FW_COREDUMP */ ++ ++ /* wake up IOCTL wait event */ ++ dhd_wakeup_ioctl_event(bus->dhd, IOCTL_RETURN_ON_TRAP); ++ ++ dhd_schedule_reset(bus->dhd); ++ ++ ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_CLEAR_IN_CHECKDIED(bus->dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++done: ++ if (mbuffer) ++ MFREE(bus->dhd->osh, mbuffer, msize); ++ if (str) ++ MFREE(bus->dhd->osh, str, maxstrlen); ++ ++ return bcmerror; ++} /* dhdpcie_checkdied */ ++ ++ ++/* Custom copy of dhdpcie_mem_dump() that can be called at interrupt level */ ++void dhdpcie_mem_dump_bugcheck(dhd_bus_t *bus, uint8 *buf) ++{ ++ int ret = 0; ++ int size; /* Full mem size */ ++ int start; /* Start address */ ++ int read_size = 0; /* Read size of each iteration */ ++ uint8 *databuf = buf; ++ ++ if (bus == NULL) { ++ return; ++ } ++ ++ start = bus->dongle_ram_base; ++ read_size = 4; ++ /* check for dead bus */ ++ { ++ uint test_word = 0; ++ ret = dhdpcie_bus_membytes(bus, FALSE, start, (uint8*)&test_word, read_size); ++ /* if read error or bus timeout */ ++ if (ret || (test_word == 0xFFFFFFFF)) { ++ return; ++ } ++ } ++ ++ /* Get full mem size */ ++ size = bus->ramsize; ++ /* Read mem content */ ++ while (size) ++ { ++ read_size = MIN(MEMBLOCK, size); ++ if ((ret = dhdpcie_bus_membytes(bus, FALSE, start, databuf, read_size))) { ++ return; ++ } ++ ++ /* Decrement size and increment start address */ ++ size -= read_size; ++ start += read_size; ++ databuf += read_size; ++ } ++ bus->dhd->soc_ram = buf; ++ bus->dhd->soc_ram_length = bus->ramsize; ++ return; ++} ++ ++ ++#if defined(DHD_FW_COREDUMP) ++static int ++dhdpcie_mem_dump(dhd_bus_t *bus) ++{ ++ int ret = 0; ++ int size; /* Full mem size */ ++ int start = bus->dongle_ram_base; /* Start address */ ++ int read_size = 0; /* Read size of each iteration */ ++ uint8 *buf = NULL, *databuf = NULL; ++ ++#ifdef EXYNOS_PCIE_DEBUG ++ exynos_pcie_register_dump(1); ++#endif /* EXYNOS_PCIE_DEBUG */ ++ ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ if (bus->is_linkdown) { ++ DHD_ERROR(("%s: PCIe link is down so skip\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ ++ /* Get full mem size */ ++ size = bus->ramsize; ++ buf = dhd_get_fwdump_buf(bus->dhd, size); ++ if (!buf) { ++ DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__, size)); ++ return BCME_ERROR; ++ } ++ ++ /* Read mem content */ ++ DHD_TRACE_HW4(("Dump dongle memory\n")); ++ databuf = buf; ++ while (size) ++ { ++ read_size = MIN(MEMBLOCK, size); ++ if ((ret = dhdpcie_bus_membytes(bus, FALSE, start, databuf, read_size))) ++ { ++ DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret)); ++ bus->dhd->memdump_success = FALSE; ++ return BCME_ERROR; ++ } ++ DHD_TRACE((".")); ++ ++ /* Decrement size and increment start address */ ++ size -= read_size; ++ start += read_size; ++ databuf += read_size; ++ } ++ bus->dhd->memdump_success = TRUE; ++ ++ dhd_schedule_memdump(bus->dhd, buf, bus->ramsize); ++ /* buf, actually soc_ram free handled in dhd_{free,clear} */ ++ ++ return ret; ++} ++ ++int ++dhd_bus_mem_dump(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ if (dhdp->busstate == DHD_BUS_DOWN) { ++ DHD_ERROR(("%s bus is down\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++#ifdef DHD_PCIE_RUNTIMEPM ++ if (dhdp->memdump_type == DUMP_TYPE_BY_SYSDUMP) { ++ DHD_ERROR(("%s : bus wakeup by SYSDUMP\n", __FUNCTION__)); ++ dhdpcie_runtime_bus_wake(dhdp, TRUE, __builtin_return_address(0)); ++ } ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) { ++ DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state, so skip\n", ++ __FUNCTION__, dhdp->busstate, dhdp->dhd_bus_busy_state)); ++ return BCME_ERROR; ++ } ++ ++ return dhdpcie_mem_dump(bus); ++} ++ ++int ++dhd_dongle_mem_dump(void) ++{ ++ if (!g_dhd_bus) { ++ DHD_ERROR(("%s: Bus is NULL\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++ dhd_bus_dump_console_buffer(g_dhd_bus); ++ dhd_prot_debug_info_print(g_dhd_bus->dhd); ++ ++ g_dhd_bus->dhd->memdump_enabled = DUMP_MEMFILE_BUGON; ++ g_dhd_bus->dhd->memdump_type = DUMP_TYPE_AP_ABNORMAL_ACCESS; ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++ dhdpcie_runtime_bus_wake(g_dhd_bus->dhd, TRUE, __builtin_return_address(0)); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ DHD_OS_WAKE_LOCK(g_dhd_bus->dhd); ++ dhd_bus_mem_dump(g_dhd_bus->dhd); ++ DHD_OS_WAKE_UNLOCK(g_dhd_bus->dhd); ++ return 0; ++} ++EXPORT_SYMBOL(dhd_dongle_mem_dump); ++#endif /* DHD_FW_COREDUMP */ ++ ++int ++dhd_socram_dump(dhd_bus_t *bus) ++{ ++#ifdef DHD_PCIE_RUNTIMEPM ++ dhdpcie_runtime_bus_wake(bus->dhd, TRUE, __builtin_return_address(0)); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++#if defined(DHD_FW_COREDUMP) ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ dhd_bus_mem_dump(bus->dhd); ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++ return 0; ++#else ++ return -1; ++#endif ++} ++ ++/** ++ * Transfers bytes from host to dongle using pio mode. ++ * Parameter 'address' is a backplane address. ++ */ ++static int ++dhdpcie_bus_membytes(dhd_bus_t *bus, bool write, ulong address, uint8 *data, uint size) ++{ ++ uint dsize; ++ int detect_endian_flag = 0x01; ++ bool little_endian; ++ ++ if (write && bus->is_linkdown) { ++ DHD_ERROR(("%s: PCIe link was down\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ ++ /* Detect endianness. */ ++ little_endian = *(char *)&detect_endian_flag; ++ ++ /* In remap mode, adjust address beyond socram and redirect ++ * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize ++ * is not backplane accessible ++ */ ++ ++ /* Determine initial transfer parameters */ ++#ifdef DHD_SUPPORT_64BIT ++ dsize = sizeof(uint64); ++#else /* !DHD_SUPPORT_64BIT */ ++ dsize = sizeof(uint32); ++#endif /* DHD_SUPPORT_64BIT */ ++ ++ /* Do the transfer(s) */ ++ DHD_INFO(("%s: %s %d bytes in window 0x%08lx\n", ++ __FUNCTION__, (write ? "write" : "read"), size, address)); ++ if (write) { ++ while (size) { ++#ifdef DHD_SUPPORT_64BIT ++ if (size >= sizeof(uint64) && little_endian && !(address % 8)) { ++ dhdpcie_bus_wtcm64(bus, address, *((uint64 *)data)); ++ } ++#else /* !DHD_SUPPORT_64BIT */ ++ if (size >= sizeof(uint32) && little_endian && !(address % 4)) { ++ dhdpcie_bus_wtcm32(bus, address, *((uint32*)data)); ++ } ++#endif /* DHD_SUPPORT_64BIT */ ++ else { ++ dsize = sizeof(uint8); ++ dhdpcie_bus_wtcm8(bus, address, *data); ++ } ++ ++ /* Adjust for next transfer (if any) */ ++ if ((size -= dsize)) { ++ data += dsize; ++ address += dsize; ++ } ++ } ++ } else { ++ while (size) { ++#ifdef DHD_SUPPORT_64BIT ++ if (size >= sizeof(uint64) && little_endian && !(address % 8)) ++ { ++ *(uint64 *)data = dhdpcie_bus_rtcm64(bus, address); ++ } ++#else /* !DHD_SUPPORT_64BIT */ ++ if (size >= sizeof(uint32) && little_endian && !(address % 4)) ++ { ++ *(uint32 *)data = dhdpcie_bus_rtcm32(bus, address); ++ } ++#endif /* DHD_SUPPORT_64BIT */ ++ else { ++ dsize = sizeof(uint8); ++ *data = dhdpcie_bus_rtcm8(bus, address); ++ } ++ ++ /* Adjust for next transfer (if any) */ ++ if ((size -= dsize) > 0) { ++ data += dsize; ++ address += dsize; ++ } ++ } ++ } ++ return BCME_OK; ++} /* dhdpcie_bus_membytes */ ++ ++/** ++ * Transfers one transmit (ethernet) packet that was queued in the (flow controlled) flow ring queue ++ * to the (non flow controlled) flow ring. ++ */ ++int BCMFASTPATH ++dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs) ++{ ++ flow_ring_node_t *flow_ring_node; ++ int ret = BCME_OK; ++#ifdef DHD_LOSSLESS_ROAMING ++ dhd_pub_t *dhdp = bus->dhd; ++#endif ++ DHD_INFO(("%s: flow_id is %d\n", __FUNCTION__, flow_id)); ++ ++ /* ASSERT on flow_id */ ++ if (flow_id >= bus->max_submission_rings) { ++ DHD_ERROR(("%s: flow_id is invalid %d, max %d\n", __FUNCTION__, ++ flow_id, bus->max_submission_rings)); ++ return 0; ++ } ++ ++ flow_ring_node = DHD_FLOW_RING(bus->dhd, flow_id); ++ ++#ifdef DHD_LOSSLESS_ROAMING ++ if ((dhdp->dequeue_prec_map & (1 << flow_ring_node->flow_info.tid)) == 0) { ++ DHD_INFO(("%s: tid %d is not in precedence map. block scheduling\n", ++ __FUNCTION__, flow_ring_node->flow_info.tid)); ++ return BCME_OK; ++ } ++#endif /* DHD_LOSSLESS_ROAMING */ ++ ++ { ++ unsigned long flags; ++ void *txp = NULL; ++ flow_queue_t *queue; ++#ifdef DHD_LOSSLESS_ROAMING ++ struct ether_header *eh; ++ uint8 *pktdata; ++#endif /* DHD_LOSSLESS_ROAMING */ ++ ++ queue = &flow_ring_node->queue; /* queue associated with flow ring */ ++ ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); ++ ++ if (flow_ring_node->status != FLOW_RING_STATUS_OPEN) { ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ return BCME_NOTREADY; ++ } ++ ++ while ((txp = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { ++ if (bus->dhd->conf->orphan_move <= 1) ++ PKTORPHAN(txp, bus->dhd->conf->tsq); ++ ++ /* ++ * Modifying the packet length caused P2P cert failures. ++ * Specifically on test cases where a packet of size 52 bytes ++ * was injected, the sniffer capture showed 62 bytes because of ++ * which the cert tests failed. So making the below change ++ * only Router specific. ++ */ ++ ++#ifdef DHDTCPACK_SUPPRESS ++ if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_HOLD) { ++ ret = dhd_tcpack_check_xmit(bus->dhd, txp); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s: dhd_tcpack_check_xmit() error.\n", ++ __FUNCTION__)); ++ } ++ } ++#endif /* DHDTCPACK_SUPPRESS */ ++#ifdef DHD_LOSSLESS_ROAMING ++ pktdata = (uint8 *)PKTDATA(OSH_NULL, txp); ++ eh = (struct ether_header *) pktdata; ++ if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { ++ uint8 prio = (uint8)PKTPRIO(txp); ++ ++ /* Restore to original priority for 802.1X packet */ ++ if (prio == PRIO_8021D_NC) { ++ PKTSETPRIO(txp, dhdp->prio_8021x); ++ } ++ } ++#endif /* DHD_LOSSLESS_ROAMING */ ++ ++ /* Attempt to transfer packet over flow ring */ ++ ret = dhd_prot_txdata(bus->dhd, txp, flow_ring_node->flow_info.ifindex); ++ if (ret != BCME_OK) { /* may not have resources in flow ring */ ++ DHD_INFO(("%s: Reinserrt %d\n", __FUNCTION__, ret)); ++ dhd_prot_txdata_write_flush(bus->dhd, flow_id, FALSE); ++ /* reinsert at head */ ++ dhd_flow_queue_reinsert(bus->dhd, queue, txp); ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ ++ /* If we are able to requeue back, return success */ ++ return BCME_OK; ++ } ++ } ++ ++ dhd_prot_txdata_write_flush(bus->dhd, flow_id, FALSE); ++ ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ } ++ ++ return ret; ++} /* dhd_bus_schedule_queue */ ++ ++/** Sends an (ethernet) data frame (in 'txp') to the dongle. Callee disposes of txp. */ ++int BCMFASTPATH ++dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx) ++{ ++ uint16 flowid; ++#ifdef IDLE_TX_FLOW_MGMT ++ uint8 node_status; ++#endif /* IDLE_TX_FLOW_MGMT */ ++ flow_queue_t *queue; ++ flow_ring_node_t *flow_ring_node; ++ unsigned long flags; ++ int ret = BCME_OK; ++ void *txp_pend = NULL; ++ ++ if (!bus->dhd->flowid_allocator) { ++ DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); ++ goto toss; ++ } ++ ++ flowid = DHD_PKT_GET_FLOWID(txp); ++ ++ flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); ++ ++ DHD_TRACE(("%s: pkt flowid %d, status %d active %d\n", ++ __FUNCTION__, flowid, flow_ring_node->status, flow_ring_node->active)); ++ ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); ++ if ((flowid >= bus->dhd->num_flow_rings) || ++#ifdef IDLE_TX_FLOW_MGMT ++ (!flow_ring_node->active)) ++#else ++ (!flow_ring_node->active) || ++ (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING) || ++ (flow_ring_node->status == FLOW_RING_STATUS_STA_FREEING)) ++#endif /* IDLE_TX_FLOW_MGMT */ ++ { ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ DHD_INFO(("%s: Dropping pkt flowid %d, status %d active %d\n", ++ __FUNCTION__, flowid, flow_ring_node->status, ++ flow_ring_node->active)); ++ ret = BCME_ERROR; ++ goto toss; ++ } ++ ++#ifdef IDLE_TX_FLOW_MGMT ++ node_status = flow_ring_node->status; ++ ++ /* handle diffrent status states here!! */ ++ switch (node_status) ++ { ++ case FLOW_RING_STATUS_OPEN: ++ ++ if (bus->enable_idle_flowring_mgmt) { ++ /* Move the node to the head of active list */ ++ dhd_flow_ring_move_to_active_list_head(bus, flow_ring_node); ++ } ++ break; ++ ++ case FLOW_RING_STATUS_SUSPENDED: ++ DHD_INFO(("Need to Initiate TX Flow resume\n")); ++ /* Issue resume_ring request */ ++ dhd_bus_flow_ring_resume_request(bus, ++ flow_ring_node); ++ break; ++ ++ case FLOW_RING_STATUS_CREATE_PENDING: ++ case FLOW_RING_STATUS_RESUME_PENDING: ++ /* Dont do anything here!! */ ++ DHD_INFO(("Waiting for Flow create/resume! status is %u\n", ++ node_status)); ++ break; ++ ++ case FLOW_RING_STATUS_DELETE_PENDING: ++ default: ++ DHD_ERROR(("Dropping packet!! flowid %u status is %u\n", ++ flowid, node_status)); ++ /* error here!! */ ++ ret = BCME_ERROR; ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ goto toss; ++ } ++ /* Now queue the packet */ ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++ queue = &flow_ring_node->queue; /* queue associated with flow ring */ ++ ++ if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp)) != BCME_OK) ++ txp_pend = txp; ++ ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ ++ if (flow_ring_node->status) { ++ DHD_INFO(("%s: Enq pkt flowid %d, status %d active %d\n", ++ __FUNCTION__, flowid, flow_ring_node->status, ++ flow_ring_node->active)); ++ if (txp_pend) { ++ txp = txp_pend; ++ goto toss; ++ } ++ return BCME_OK; ++ } ++ ret = dhd_bus_schedule_queue(bus, flowid, FALSE); /* from queue to flowring */ ++ ++ /* If we have anything pending, try to push into q */ ++ if (txp_pend) { ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); ++ ++ if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp_pend)) != BCME_OK) { ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ txp = txp_pend; ++ goto toss; ++ } ++ ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ } ++ ++ return ret; ++ ++toss: ++ DHD_INFO(("%s: Toss %d\n", __FUNCTION__, ret)); ++/* for EFI, pass the 'send' flag as false, to avoid enqueuing the failed tx pkt ++* into the Tx done queue ++*/ ++#ifdef DHD_EFI ++ PKTCFREE(bus->dhd->osh, txp, FALSE); ++#else ++ PKTCFREE(bus->dhd->osh, txp, TRUE); ++#endif ++ return ret; ++} /* dhd_bus_txdata */ ++ ++ ++void ++dhd_bus_stop_queue(struct dhd_bus *bus) ++{ ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); ++ bus->bus_flowctrl = TRUE; ++} ++ ++void ++dhd_bus_start_queue(struct dhd_bus *bus) ++{ ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); ++ bus->bus_flowctrl = TRUE; ++} ++ ++/* Device console input function */ ++int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen) ++{ ++ dhd_bus_t *bus = dhd->bus; ++ uint32 addr, val; ++ int rv; ++ /* Address could be zero if CONSOLE := 0 in dongle Makefile */ ++ if (bus->console_addr == 0) ++ return BCME_UNSUPPORTED; ++ ++ /* Don't allow input if dongle is in reset */ ++ if (bus->dhd->dongle_reset) { ++ return BCME_NOTREADY; ++ } ++ ++ /* Zero cbuf_index */ ++ addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx); ++ val = htol32(0); ++ if ((rv = dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) ++ goto done; ++ ++ /* Write message into cbuf */ ++ addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf); ++ if ((rv = dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) ++ goto done; ++ ++ /* Write length into vcons_in */ ++ addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in); ++ val = htol32(msglen); ++ if ((rv = dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) ++ goto done; ++ ++ /* generate an interrupt to dongle to indicate that it needs to process cons command */ ++ dhdpcie_send_mb_data(bus, H2D_HOST_CONS_INT); ++done: ++ return rv; ++} /* dhd_bus_console_in */ ++ ++/** ++ * Called on frame reception, the frame was received from the dongle on interface 'ifidx' and is ++ * contained in 'pkt'. Processes rx frame, forwards up the layer to netif. ++ */ ++void BCMFASTPATH ++dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count) ++{ ++ dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, 0); ++} ++ ++/** 'offset' is a backplane address */ ++void ++dhdpcie_bus_wtcm8(dhd_bus_t *bus, ulong offset, uint8 data) ++{ ++ W_REG(bus->dhd->osh, (volatile uint8 *)(bus->tcm + offset), data); ++} ++ ++uint8 ++dhdpcie_bus_rtcm8(dhd_bus_t *bus, ulong offset) ++{ ++ volatile uint8 data; ++ data = R_REG(bus->dhd->osh, (volatile uint8 *)(bus->tcm + offset)); ++ return data; ++} ++ ++void ++dhdpcie_bus_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data) ++{ ++ W_REG(bus->dhd->osh, (volatile uint32 *)(bus->tcm + offset), data); ++} ++void ++dhdpcie_bus_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data) ++{ ++ W_REG(bus->dhd->osh, (volatile uint16 *)(bus->tcm + offset), data); ++} ++#ifdef DHD_SUPPORT_64BIT ++void ++dhdpcie_bus_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data) ++{ ++ W_REG(bus->dhd->osh, (volatile uint64 *)(bus->tcm + offset), data); ++} ++#endif /* DHD_SUPPORT_64BIT */ ++ ++uint16 ++dhdpcie_bus_rtcm16(dhd_bus_t *bus, ulong offset) ++{ ++ volatile uint16 data; ++ data = R_REG(bus->dhd->osh, (volatile uint16 *)(bus->tcm + offset)); ++ return data; ++} ++ ++uint32 ++dhdpcie_bus_rtcm32(dhd_bus_t *bus, ulong offset) ++{ ++ volatile uint32 data; ++ data = R_REG(bus->dhd->osh, (volatile uint32 *)(bus->tcm + offset)); ++ return data; ++} ++ ++#ifdef DHD_SUPPORT_64BIT ++uint64 ++dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset) ++{ ++ volatile uint64 data; ++ data = R_REG(bus->dhd->osh, (volatile uint64 *)(bus->tcm + offset)); ++ return data; ++} ++#endif /* DHD_SUPPORT_64BIT */ ++ ++/** A snippet of dongle memory is shared between host and dongle */ ++void ++dhd_bus_cmn_writeshared(dhd_bus_t *bus, void *data, uint32 len, uint8 type, uint16 ringid) ++{ ++ uint64 long_data; ++ uintptr tcm_offset; ++ ++ DHD_INFO(("%s: writing to dongle type %d len %d\n", __FUNCTION__, type, len)); ++ ++ if (bus->is_linkdown) { ++ DHD_ERROR(("%s: PCIe link was down\n", __FUNCTION__)); ++ return; ++ } ++ ++ switch (type) { ++ case D2H_DMA_SCRATCH_BUF: ++ { ++ pciedev_shared_t *sh = (pciedev_shared_t*)bus->shared_addr; ++ long_data = HTOL64(*(uint64 *)data); ++ tcm_offset = (uintptr)&(sh->host_dma_scratch_buffer); ++ dhdpcie_bus_membytes(bus, TRUE, ++ (ulong)tcm_offset, (uint8*) &long_data, len); ++ if (dhd_msg_level & DHD_INFO_VAL) { ++ prhex(__FUNCTION__, data, len); ++ } ++ break; ++ } ++ ++ case D2H_DMA_SCRATCH_BUF_LEN : ++ { ++ pciedev_shared_t *sh = (pciedev_shared_t*)bus->shared_addr; ++ tcm_offset = (uintptr)&(sh->host_dma_scratch_buffer_len); ++ dhdpcie_bus_wtcm32(bus, ++ (ulong)tcm_offset, (uint32) HTOL32(*(uint32 *)data)); ++ if (dhd_msg_level & DHD_INFO_VAL) { ++ prhex(__FUNCTION__, data, len); ++ } ++ break; ++ } ++ ++ case H2D_DMA_INDX_WR_BUF: ++ { ++ pciedev_shared_t *shmem = (pciedev_shared_t *)bus->pcie_sh; ++ ++ long_data = HTOL64(*(uint64 *)data); ++ tcm_offset = (uintptr)shmem->rings_info_ptr; ++ tcm_offset += OFFSETOF(ring_info_t, h2d_w_idx_hostaddr); ++ dhdpcie_bus_membytes(bus, TRUE, ++ (ulong)tcm_offset, (uint8*) &long_data, len); ++ if (dhd_msg_level & DHD_INFO_VAL) { ++ prhex(__FUNCTION__, data, len); ++ } ++ break; ++ } ++ ++ case H2D_DMA_INDX_RD_BUF: ++ { ++ pciedev_shared_t *shmem = (pciedev_shared_t *)bus->pcie_sh; ++ long_data = HTOL64(*(uint64 *)data); ++ tcm_offset = (uintptr)shmem->rings_info_ptr; ++ tcm_offset += OFFSETOF(ring_info_t, h2d_r_idx_hostaddr); ++ dhdpcie_bus_membytes(bus, TRUE, ++ (ulong)tcm_offset, (uint8*) &long_data, len); ++ if (dhd_msg_level & DHD_INFO_VAL) { ++ prhex(__FUNCTION__, data, len); ++ } ++ break; ++ } ++ ++ case D2H_DMA_INDX_WR_BUF: ++ { ++ pciedev_shared_t *shmem = (pciedev_shared_t *)bus->pcie_sh; ++ long_data = HTOL64(*(uint64 *)data); ++ tcm_offset = (uintptr)shmem->rings_info_ptr; ++ tcm_offset += OFFSETOF(ring_info_t, d2h_w_idx_hostaddr); ++ dhdpcie_bus_membytes(bus, TRUE, ++ (ulong)tcm_offset, (uint8*) &long_data, len); ++ if (dhd_msg_level & DHD_INFO_VAL) { ++ prhex(__FUNCTION__, data, len); ++ } ++ break; ++ } ++ ++ case D2H_DMA_INDX_RD_BUF: ++ { ++ pciedev_shared_t *shmem = (pciedev_shared_t *)bus->pcie_sh; ++ long_data = HTOL64(*(uint64 *)data); ++ tcm_offset = (uintptr)shmem->rings_info_ptr; ++ tcm_offset += OFFSETOF(ring_info_t, d2h_r_idx_hostaddr); ++ dhdpcie_bus_membytes(bus, TRUE, ++ (ulong)tcm_offset, (uint8*) &long_data, len); ++ if (dhd_msg_level & DHD_INFO_VAL) { ++ prhex(__FUNCTION__, data, len); ++ } ++ break; ++ } ++ ++ case H2D_IFRM_INDX_WR_BUF: ++ { ++ pciedev_shared_t *shmem = (pciedev_shared_t *)bus->pcie_sh; ++ ++ long_data = HTOL64(*(uint64 *)data); ++ tcm_offset = (uintptr)shmem->rings_info_ptr; ++ tcm_offset += OFFSETOF(ring_info_t, ifrm_w_idx_hostaddr); ++ dhdpcie_bus_membytes(bus, TRUE, ++ (ulong)tcm_offset, (uint8*) &long_data, len); ++ if (dhd_msg_level & DHD_INFO_VAL) { ++ prhex(__FUNCTION__, data, len); ++ } ++ break; ++ } ++ ++ case RING_ITEM_LEN : ++ tcm_offset = bus->ring_sh[ringid].ring_mem_addr; ++ tcm_offset += OFFSETOF(ring_mem_t, len_items); ++ dhdpcie_bus_wtcm16(bus, ++ (ulong)tcm_offset, (uint16) HTOL16(*(uint16 *)data)); ++ break; ++ ++ case RING_MAX_ITEMS : ++ tcm_offset = bus->ring_sh[ringid].ring_mem_addr; ++ tcm_offset += OFFSETOF(ring_mem_t, max_item); ++ dhdpcie_bus_wtcm16(bus, ++ (ulong)tcm_offset, (uint16) HTOL16(*(uint16 *)data)); ++ break; ++ ++ case RING_BUF_ADDR : ++ long_data = HTOL64(*(uint64 *)data); ++ tcm_offset = bus->ring_sh[ringid].ring_mem_addr; ++ tcm_offset += OFFSETOF(ring_mem_t, base_addr); ++ dhdpcie_bus_membytes(bus, TRUE, ++ (ulong)tcm_offset, (uint8 *) &long_data, len); ++ if (dhd_msg_level & DHD_INFO_VAL) { ++ prhex(__FUNCTION__, data, len); ++ } ++ break; ++ ++ case RING_WR_UPD : ++ tcm_offset = bus->ring_sh[ringid].ring_state_w; ++ dhdpcie_bus_wtcm16(bus, ++ (ulong)tcm_offset, (uint16) HTOL16(*(uint16 *)data)); ++ break; ++ ++ case RING_RD_UPD : ++ tcm_offset = bus->ring_sh[ringid].ring_state_r; ++ dhdpcie_bus_wtcm16(bus, ++ (ulong)tcm_offset, (uint16) HTOL16(*(uint16 *)data)); ++ break; ++ ++ case D2H_MB_DATA: ++ dhdpcie_bus_wtcm32(bus, bus->d2h_mb_data_ptr_addr, ++ (uint32) HTOL32(*(uint32 *)data)); ++ break; ++ ++ case H2D_MB_DATA: ++ dhdpcie_bus_wtcm32(bus, bus->h2d_mb_data_ptr_addr, ++ (uint32) HTOL32(*(uint32 *)data)); ++ break; ++ ++ case HOST_API_VERSION: ++ { ++ pciedev_shared_t *sh = (pciedev_shared_t*) bus->shared_addr; ++ tcm_offset = (uintptr)sh + OFFSETOF(pciedev_shared_t, host_cap); ++ dhdpcie_bus_wtcm32(bus, ++ (ulong)tcm_offset, (uint32) HTOL32(*(uint32 *)data)); ++ break; ++ } ++ ++ case DNGL_TO_HOST_TRAP_ADDR: ++ { ++ pciedev_shared_t *sh = (pciedev_shared_t*) bus->shared_addr; ++ long_data = HTOL64(*(uint64 *)data); ++ tcm_offset = (uintptr)&(sh->host_trap_addr); ++ dhdpcie_bus_membytes(bus, TRUE, ++ (ulong)tcm_offset, (uint8*) &long_data, len); ++ break; ++ } ++ ++#ifdef HOFFLOAD_MODULES ++ case WRT_HOST_MODULE_ADDR: ++ { ++ pciedev_shared_t *sh = (pciedev_shared_t*) bus->shared_addr; ++ long_data = HTOL64(*(uint64 *)data); ++ tcm_offset = (uintptr)&(sh->hoffload_addr); ++ dhdpcie_bus_membytes(bus, TRUE, ++ (ulong)tcm_offset, (uint8*) &long_data, len); ++ break; ++ } ++#endif ++ default: ++ break; ++ } ++} /* dhd_bus_cmn_writeshared */ ++ ++/** A snippet of dongle memory is shared between host and dongle */ ++void ++dhd_bus_cmn_readshared(dhd_bus_t *bus, void* data, uint8 type, uint16 ringid) ++{ ++ ulong tcm_offset; ++ ++ switch (type) { ++ case RING_WR_UPD : ++ tcm_offset = bus->ring_sh[ringid].ring_state_w; ++ *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, tcm_offset)); ++ break; ++ case RING_RD_UPD : ++ tcm_offset = bus->ring_sh[ringid].ring_state_r; ++ *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, tcm_offset)); ++ break; ++ case TOTAL_LFRAG_PACKET_CNT : ++ { ++ pciedev_shared_t *sh = (pciedev_shared_t*)bus->shared_addr; ++ *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, ++ (ulong)(uintptr) &sh->total_lfrag_pkt_cnt)); ++ break; ++ } ++ case H2D_MB_DATA: ++ *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, bus->h2d_mb_data_ptr_addr)); ++ break; ++ case D2H_MB_DATA: ++ *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, bus->d2h_mb_data_ptr_addr)); ++ break; ++ case MAX_HOST_RXBUFS : ++ { ++ pciedev_shared_t *sh = (pciedev_shared_t*)bus->shared_addr; ++ *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, ++ (ulong)(uintptr) &sh->max_host_rxbufs)); ++ break; ++ } ++ default : ++ break; ++ } ++} ++ ++uint32 dhd_bus_get_sharedflags(dhd_bus_t *bus) ++{ ++ return ((pciedev_shared_t*)bus->pcie_sh)->flags; ++} ++ ++void ++dhd_bus_clearcounts(dhd_pub_t *dhdp) ++{ ++} ++ ++int ++dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ const bcm_iovar_t *vi = NULL; ++ int bcmerror = BCME_UNSUPPORTED; ++ int val_size; ++ uint32 actionid; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get MUST have return space */ ++ ASSERT(set || (arg && len)); ++ ++ /* Set does NOT take qualifiers */ ++ ASSERT(!set || (!params && !plen)); ++ ++ DHD_INFO(("%s: %s %s, len %d plen %d\n", __FUNCTION__, ++ name, (set ? "set" : "get"), len, plen)); ++ ++ /* Look up var locally; if not found pass to host driver */ ++ if ((vi = bcm_iovar_lookup(dhdpcie_iovars, name)) == NULL) { ++ goto exit; ++ } ++ ++ ++ /* 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 = dhdpcie_bus_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); ++ ++exit: ++ return bcmerror; ++} /* dhd_bus_iovar_op */ ++ ++#ifdef BCM_BUZZZ ++#include ++ ++int ++dhd_buzzz_dump_cntrs(char *p, uint32 *core, uint32 *log, ++ const int num_counters) ++{ ++ int bytes = 0; ++ uint32 ctr; ++ uint32 curr[BCM_BUZZZ_COUNTERS_MAX], prev[BCM_BUZZZ_COUNTERS_MAX]; ++ uint32 delta[BCM_BUZZZ_COUNTERS_MAX]; ++ ++ /* Compute elapsed counter values per counter event type */ ++ for (ctr = 0U; ctr < num_counters; ctr++) { ++ prev[ctr] = core[ctr]; ++ curr[ctr] = *log++; ++ core[ctr] = curr[ctr]; /* saved for next log */ ++ ++ if (curr[ctr] < prev[ctr]) ++ delta[ctr] = curr[ctr] + (~0U - prev[ctr]); ++ else ++ delta[ctr] = (curr[ctr] - prev[ctr]); ++ ++ bytes += sprintf(p + bytes, "%12u ", delta[ctr]); ++ } ++ ++ return bytes; ++} ++ ++typedef union cm3_cnts { /* export this in bcm_buzzz.h */ ++ uint32 u32; ++ uint8 u8[4]; ++ struct { ++ uint8 cpicnt; ++ uint8 exccnt; ++ uint8 sleepcnt; ++ uint8 lsucnt; ++ }; ++} cm3_cnts_t; ++ ++int ++dhd_bcm_buzzz_dump_cntrs6(char *p, uint32 *core, uint32 *log) ++{ ++ int bytes = 0; ++ ++ uint32 cyccnt, instrcnt; ++ cm3_cnts_t cm3_cnts; ++ uint8 foldcnt; ++ ++ { /* 32bit cyccnt */ ++ uint32 curr, prev, delta; ++ prev = core[0]; curr = *log++; core[0] = curr; ++ if (curr < prev) ++ delta = curr + (~0U - prev); ++ else ++ delta = (curr - prev); ++ ++ bytes += sprintf(p + bytes, "%12u ", delta); ++ cyccnt = delta; ++ } ++ ++ { /* Extract the 4 cnts: cpi, exc, sleep and lsu */ ++ int i; ++ uint8 max8 = ~0; ++ cm3_cnts_t curr, prev, delta; ++ prev.u32 = core[1]; curr.u32 = * log++; core[1] = curr.u32; ++ for (i = 0; i < 4; i++) { ++ if (curr.u8[i] < prev.u8[i]) ++ delta.u8[i] = curr.u8[i] + (max8 - prev.u8[i]); ++ else ++ delta.u8[i] = (curr.u8[i] - prev.u8[i]); ++ bytes += sprintf(p + bytes, "%4u ", delta.u8[i]); ++ } ++ cm3_cnts.u32 = delta.u32; ++ } ++ ++ { /* Extract the foldcnt from arg0 */ ++ uint8 curr, prev, delta, max8 = ~0; ++ bcm_buzzz_arg0_t arg0; arg0.u32 = *log; ++ prev = core[2]; curr = arg0.klog.cnt; core[2] = curr; ++ if (curr < prev) ++ delta = curr + (max8 - prev); ++ else ++ delta = (curr - prev); ++ bytes += sprintf(p + bytes, "%4u ", delta); ++ foldcnt = delta; ++ } ++ ++ instrcnt = cyccnt - (cm3_cnts.u8[0] + cm3_cnts.u8[1] + cm3_cnts.u8[2] ++ + cm3_cnts.u8[3]) + foldcnt; ++ if (instrcnt > 0xFFFFFF00) ++ bytes += sprintf(p + bytes, "[%10s] ", "~"); ++ else ++ bytes += sprintf(p + bytes, "[%10u] ", instrcnt); ++ return bytes; ++} ++ ++int ++dhd_buzzz_dump_log(char *p, uint32 *core, uint32 *log, bcm_buzzz_t *buzzz) ++{ ++ int bytes = 0; ++ bcm_buzzz_arg0_t arg0; ++ static uint8 * fmt[] = BCM_BUZZZ_FMT_STRINGS; ++ ++ if (buzzz->counters == 6) { ++ bytes += dhd_bcm_buzzz_dump_cntrs6(p, core, log); ++ log += 2; /* 32bit cyccnt + (4 x 8bit) CM3 */ ++ } else { ++ bytes += dhd_buzzz_dump_cntrs(p, core, log, buzzz->counters); ++ log += buzzz->counters; /* (N x 32bit) CR4=3, CA7=4 */ ++ } ++ ++ /* Dump the logged arguments using the registered formats */ ++ arg0.u32 = *log++; ++ ++ switch (arg0.klog.args) { ++ case 0: ++ bytes += sprintf(p + bytes, fmt[arg0.klog.id]); ++ break; ++ case 1: ++ { ++ uint32 arg1 = *log++; ++ bytes += sprintf(p + bytes, fmt[arg0.klog.id], arg1); ++ break; ++ } ++ case 2: ++ { ++ uint32 arg1, arg2; ++ arg1 = *log++; arg2 = *log++; ++ bytes += sprintf(p + bytes, fmt[arg0.klog.id], arg1, arg2); ++ break; ++ } ++ case 3: ++ { ++ uint32 arg1, arg2, arg3; ++ arg1 = *log++; arg2 = *log++; arg3 = *log++; ++ bytes += sprintf(p + bytes, fmt[arg0.klog.id], arg1, arg2, arg3); ++ break; ++ } ++ case 4: ++ { ++ uint32 arg1, arg2, arg3, arg4; ++ arg1 = *log++; arg2 = *log++; ++ arg3 = *log++; arg4 = *log++; ++ bytes += sprintf(p + bytes, fmt[arg0.klog.id], arg1, arg2, arg3, arg4); ++ break; ++ } ++ default: ++ printf("%s: Maximum one argument supported\n", __FUNCTION__); ++ break; ++ } ++ ++ bytes += sprintf(p + bytes, "\n"); ++ ++ return bytes; ++} ++ ++void dhd_buzzz_dump(bcm_buzzz_t *buzzz_p, void *buffer_p, char *p) ++{ ++ int i; ++ uint32 total, part1, part2, log_sz, core[BCM_BUZZZ_COUNTERS_MAX]; ++ void * log; ++ ++ for (i = 0; i < BCM_BUZZZ_COUNTERS_MAX; i++) { ++ core[i] = 0; ++ } ++ ++ log_sz = buzzz_p->log_sz; ++ ++ part1 = ((uint32)buzzz_p->cur - (uint32)buzzz_p->log) / log_sz; ++ ++ if (buzzz_p->wrap == TRUE) { ++ part2 = ((uint32)buzzz_p->end - (uint32)buzzz_p->cur) / log_sz; ++ total = (buzzz_p->buffer_sz - BCM_BUZZZ_LOGENTRY_MAXSZ) / log_sz; ++ } else { ++ part2 = 0U; ++ total = buzzz_p->count; ++ } ++ ++ if (total == 0U) { ++ printf("%s: bcm_buzzz_dump total<%u> done\n", __FUNCTION__, total); ++ return; ++ } else { ++ printf("%s: bcm_buzzz_dump total<%u> : part2<%u> + part1<%u>\n", __FUNCTION__, ++ total, part2, part1); ++ } ++ ++ if (part2) { /* with wrap */ ++ log = (void*)((size_t)buffer_p + (buzzz_p->cur - buzzz_p->log)); ++ while (part2--) { /* from cur to end : part2 */ ++ p[0] = '\0'; ++ dhd_buzzz_dump_log(p, core, (uint32 *)log, buzzz_p); ++ printf("%s", p); ++ log = (void*)((size_t)log + buzzz_p->log_sz); ++ } ++ } ++ ++ log = (void*)buffer_p; ++ while (part1--) { ++ p[0] = '\0'; ++ dhd_buzzz_dump_log(p, core, (uint32 *)log, buzzz_p); ++ printf("%s", p); ++ log = (void*)((size_t)log + buzzz_p->log_sz); ++ } ++ ++ printf("%s: bcm_buzzz_dump done.\n", __FUNCTION__); ++} ++ ++int dhd_buzzz_dump_dngl(dhd_bus_t *bus) ++{ ++ bcm_buzzz_t * buzzz_p = NULL; ++ void * buffer_p = NULL; ++ char * page_p = NULL; ++ pciedev_shared_t *sh; ++ int ret = 0; ++ ++ if (bus->dhd->busstate != DHD_BUS_DATA) { ++ return BCME_UNSUPPORTED; ++ } ++ if ((page_p = (char *)MALLOC(bus->dhd->osh, 4096)) == NULL) { ++ printf("%s: Page memory allocation failure\n", __FUNCTION__); ++ goto done; ++ } ++ if ((buzzz_p = MALLOC(bus->dhd->osh, sizeof(bcm_buzzz_t))) == NULL) { ++ printf("%s: BCM BUZZZ memory allocation failure\n", __FUNCTION__); ++ goto done; ++ } ++ ++ ret = dhdpcie_readshared(bus); ++ if (ret < 0) { ++ DHD_ERROR(("%s :Shared area read failed \n", __FUNCTION__)); ++ goto done; ++ } ++ ++ sh = bus->pcie_sh; ++ ++ DHD_INFO(("%s buzzz:%08x\n", __FUNCTION__, sh->buzz_dbg_ptr)); ++ ++ if (sh->buzz_dbg_ptr != 0U) { /* Fetch and display dongle BUZZZ Trace */ ++ ++ dhdpcie_bus_membytes(bus, FALSE, (ulong)sh->buzz_dbg_ptr, ++ (uint8 *)buzzz_p, sizeof(bcm_buzzz_t)); ++ ++ printf("BUZZZ[0x%08x]: log<0x%08x> cur<0x%08x> end<0x%08x> " ++ "count<%u> status<%u> wrap<%u>\n" ++ "cpu<0x%02X> counters<%u> group<%u> buffer_sz<%u> log_sz<%u>\n", ++ (int)sh->buzz_dbg_ptr, ++ (int)buzzz_p->log, (int)buzzz_p->cur, (int)buzzz_p->end, ++ buzzz_p->count, buzzz_p->status, buzzz_p->wrap, ++ buzzz_p->cpu_idcode, buzzz_p->counters, buzzz_p->group, ++ buzzz_p->buffer_sz, buzzz_p->log_sz); ++ ++ if (buzzz_p->count == 0) { ++ printf("%s: Empty dongle BUZZZ trace\n\n", __FUNCTION__); ++ goto done; ++ } ++ ++ /* Allocate memory for trace buffer and format strings */ ++ buffer_p = MALLOC(bus->dhd->osh, buzzz_p->buffer_sz); ++ if (buffer_p == NULL) { ++ printf("%s: Buffer memory allocation failure\n", __FUNCTION__); ++ goto done; ++ } ++ ++ /* Fetch the trace. format strings are exported via bcm_buzzz.h */ ++ dhdpcie_bus_membytes(bus, FALSE, (uint32)buzzz_p->log, /* Trace */ ++ (uint8 *)buffer_p, buzzz_p->buffer_sz); ++ ++ /* Process and display the trace using formatted output */ ++ ++ { ++ int ctr; ++ for (ctr = 0; ctr < buzzz_p->counters; ctr++) { ++ printf(" ", buzzz_p->eventid[ctr]); ++ } ++ printf("\n"); ++ } ++ ++ dhd_buzzz_dump(buzzz_p, buffer_p, page_p); ++ ++ printf("%s: ----- End of dongle BCM BUZZZ Trace -----\n\n", __FUNCTION__); ++ ++ MFREE(bus->dhd->osh, buffer_p, buzzz_p->buffer_sz); buffer_p = NULL; ++ } ++ ++done: ++ ++ if (page_p) MFREE(bus->dhd->osh, page_p, 4096); ++ if (buzzz_p) MFREE(bus->dhd->osh, buzzz_p, sizeof(bcm_buzzz_t)); ++ if (buffer_p) MFREE(bus->dhd->osh, buffer_p, buzzz_p->buffer_sz); ++ ++ return BCME_OK; ++} ++#endif /* BCM_BUZZZ */ ++ ++#define PCIE_GEN2(sih) ((BUSTYPE((sih)->bustype) == PCI_BUS) && \ ++ ((sih)->buscoretype == PCIE2_CORE_ID)) ++ ++int ++dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ int bcmerror = 0; ++ unsigned long flags; ++#ifdef CONFIG_ARCH_MSM ++ int retry = POWERUP_MAX_RETRY; ++#endif /* CONFIG_ARCH_MSM */ ++ ++ if (dhd_download_fw_on_driverload) { ++ bcmerror = dhd_bus_start(dhdp); ++ } else { ++ if (flag == TRUE) { /* Turn off WLAN */ ++ /* Removing Power */ ++ DHD_ERROR(("%s: == Power OFF ==\n", __FUNCTION__)); ++ ++ bus->dhd->up = FALSE; ++ ++ if (bus->dhd->busstate != DHD_BUS_DOWN) { ++ dhdpcie_advertise_bus_cleanup(bus->dhd); ++ if (bus->intr) { ++ dhdpcie_bus_intr_disable(bus); ++ dhdpcie_free_irq(bus); ++ } ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ /* Clean up any pending host wake IRQ */ ++ dhd_bus_oob_intr_set(bus->dhd, FALSE); ++ dhd_bus_oob_intr_unregister(bus->dhd); ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ dhd_os_wd_timer(dhdp, 0); ++ dhd_bus_stop(bus, TRUE); ++ dhd_prot_reset(dhdp); ++ dhd_clear(dhdp); ++ dhd_bus_release_dongle(bus); ++ dhdpcie_bus_free_resource(bus); ++ bcmerror = dhdpcie_bus_disable_device(bus); ++ if (bcmerror) { ++ DHD_ERROR(("%s: dhdpcie_bus_disable_device: %d\n", ++ __FUNCTION__, bcmerror)); ++ goto done; ++ } ++#ifdef CONFIG_ARCH_MSM ++ bcmerror = dhdpcie_bus_clock_stop(bus); ++ if (bcmerror) { ++ DHD_ERROR(("%s: host clock stop failed: %d\n", ++ __FUNCTION__, bcmerror)); ++ goto done; ++ } ++#endif /* CONFIG_ARCH_MSM */ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ } else { ++ if (bus->intr) { ++ dhdpcie_free_irq(bus); ++ } ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ /* Clean up any pending host wake IRQ */ ++ dhd_bus_oob_intr_set(bus->dhd, FALSE); ++ dhd_bus_oob_intr_unregister(bus->dhd); ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ dhd_dpc_kill(bus->dhd); ++ dhd_prot_reset(dhdp); ++ dhd_clear(dhdp); ++ dhd_bus_release_dongle(bus); ++ dhdpcie_bus_free_resource(bus); ++ bcmerror = dhdpcie_bus_disable_device(bus); ++ if (bcmerror) { ++ DHD_ERROR(("%s: dhdpcie_bus_disable_device: %d\n", ++ __FUNCTION__, bcmerror)); ++ goto done; ++ } ++ ++#ifdef CONFIG_ARCH_MSM ++ bcmerror = dhdpcie_bus_clock_stop(bus); ++ if (bcmerror) { ++ DHD_ERROR(("%s: host clock stop failed: %d\n", ++ __FUNCTION__, bcmerror)); ++ goto done; ++ } ++#endif /* CONFIG_ARCH_MSM */ ++ } ++ ++ bus->dhd->dongle_reset = TRUE; ++ DHD_ERROR(("%s: WLAN OFF Done\n", __FUNCTION__)); ++ ++ } else { /* Turn on WLAN */ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ /* Powering On */ ++ DHD_ERROR(("%s: == Power ON ==\n", __FUNCTION__)); ++#ifdef CONFIG_ARCH_MSM ++ while (--retry) { ++ bcmerror = dhdpcie_bus_clock_start(bus); ++ if (!bcmerror) { ++ DHD_ERROR(("%s: dhdpcie_bus_clock_start OK\n", ++ __FUNCTION__)); ++ break; ++ } else { ++ OSL_SLEEP(10); ++ } ++ } ++ ++ if (bcmerror && !retry) { ++ DHD_ERROR(("%s: host pcie clock enable failed: %d\n", ++ __FUNCTION__, bcmerror)); ++ goto done; ++ } ++#endif /* CONFIG_ARCH_MSM */ ++ bus->is_linkdown = 0; ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ bus->read_shm_fail = FALSE; ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ bcmerror = dhdpcie_bus_enable_device(bus); ++ if (bcmerror) { ++ DHD_ERROR(("%s: host configuration restore failed: %d\n", ++ __FUNCTION__, bcmerror)); ++ goto done; ++ } ++ ++ bcmerror = dhdpcie_bus_alloc_resource(bus); ++ if (bcmerror) { ++ DHD_ERROR(("%s: dhdpcie_bus_resource_alloc failed: %d\n", ++ __FUNCTION__, bcmerror)); ++ goto done; ++ } ++ ++ bcmerror = dhdpcie_bus_dongle_attach(bus); ++ if (bcmerror) { ++ DHD_ERROR(("%s: dhdpcie_bus_dongle_attach failed: %d\n", ++ __FUNCTION__, bcmerror)); ++ goto done; ++ } ++ ++ bcmerror = dhd_bus_request_irq(bus); ++ if (bcmerror) { ++ DHD_ERROR(("%s: dhd_bus_request_irq failed: %d\n", ++ __FUNCTION__, bcmerror)); ++ goto done; ++ } ++ ++ bus->dhd->dongle_reset = FALSE; ++ ++ bcmerror = dhd_bus_start(dhdp); ++ if (bcmerror) { ++ DHD_ERROR(("%s: dhd_bus_start: %d\n", ++ __FUNCTION__, bcmerror)); ++ goto done; ++ } ++ ++ bus->dhd->up = TRUE; ++ DHD_ERROR(("%s: WLAN Power On Done\n", __FUNCTION__)); ++ } else { ++ DHD_ERROR(("%s: what should we do here\n", __FUNCTION__)); ++ goto done; ++ } ++ } ++ } ++ ++done: ++ if (bcmerror) { ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ } ++ ++ return bcmerror; ++} ++ ++static int ++dhdpcie_bus_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, ++ void *params, int plen, void *arg, int len, int val_size) ++{ ++ int bcmerror = 0; ++ int32 int_val = 0; ++ int32 int_val2 = 0; ++ int32 int_val3 = 0; ++ bool bool_val = 0; ++ ++ DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", ++ __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) ++ goto exit; ++ ++ if (plen >= (int)sizeof(int_val)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ if (plen >= (int)sizeof(int_val) * 2) ++ bcopy((void*)((uintptr)params + sizeof(int_val)), &int_val2, sizeof(int_val2)); ++ ++ if (plen >= (int)sizeof(int_val) * 3) ++ bcopy((void*)((uintptr)params + 2 * sizeof(int_val)), &int_val3, sizeof(int_val3)); ++ ++ bool_val = (int_val != 0) ? TRUE : FALSE; ++ ++ /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ ++ if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || ++ actionid == IOV_GVAL(IOV_DEVRESET))) { ++ bcmerror = BCME_NOTREADY; ++ goto exit; ++ } ++ ++ switch (actionid) { ++ ++ ++ case IOV_SVAL(IOV_VARS): ++ bcmerror = dhdpcie_downloadvars(bus, arg, len); ++ break; ++ case IOV_SVAL(IOV_PCIE_LPBK): ++ bcmerror = dhdpcie_bus_lpback_req(bus, int_val); ++ break; ++ ++ case IOV_SVAL(IOV_PCIE_DMAXFER): { ++ int int_val4 = 0; ++ if (plen >= (int)sizeof(int_val) * 4) { ++ bcopy((void*)((uintptr)params + 3 * sizeof(int_val)), ++ &int_val4, sizeof(int_val4)); ++ } ++ bcmerror = dhdpcie_bus_dmaxfer_req(bus, int_val, int_val2, int_val3, int_val4); ++ break; ++ } ++ ++#ifdef DEVICE_TX_STUCK_DETECT ++ case IOV_GVAL(IOV_DEVICE_TX_STUCK_DETECT): ++ int_val = bus->dev_tx_stuck_monitor; ++ bcopy(&int_val, arg, val_size); ++ break; ++ case IOV_SVAL(IOV_DEVICE_TX_STUCK_DETECT): ++ bus->dev_tx_stuck_monitor = (bool)int_val; ++ break; ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ case IOV_GVAL(IOV_PCIE_SUSPEND): ++ int_val = (bus->dhd->busstate == DHD_BUS_SUSPEND) ? 1 : 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_PCIE_SUSPEND): ++ if (bool_val) { /* Suspend */ ++ int ret; ++ unsigned long flags; ++ ++ /* ++ * If some other context is busy, wait until they are done, ++ * before starting suspend ++ */ ++ ret = dhd_os_busbusy_wait_condition(bus->dhd, ++ &bus->dhd->dhd_bus_busy_state, DHD_BUS_BUSY_IN_DHD_IOVAR); ++ if (ret == 0) { ++ DHD_ERROR(("%s:Wait Timedout, dhd_bus_busy_state = 0x%x\n", ++ __FUNCTION__, bus->dhd->dhd_bus_busy_state)); ++ return BCME_BUSY; ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ dhdpcie_bus_suspend(bus, TRUE); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ } else { /* Resume */ ++ unsigned long flags; ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ dhdpcie_bus_suspend(bus, FALSE); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ } ++ break; ++ ++ case IOV_GVAL(IOV_MEMSIZE): ++ int_val = (int32)bus->ramsize; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++#ifdef BCM_BUZZZ ++ /* Dump dongle side buzzz trace to console */ ++ case IOV_GVAL(IOV_BUZZZ_DUMP): ++ bcmerror = dhd_buzzz_dump_dngl(bus); ++ break; ++#endif /* BCM_BUZZZ */ ++ ++ case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): ++ bcmerror = dhdpcie_bus_download_state(bus, bool_val); ++ break; ++ ++ case IOV_GVAL(IOV_RAMSIZE): ++ int_val = (int32)bus->ramsize; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_RAMSIZE): ++ bus->ramsize = int_val; ++ bus->orig_ramsize = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_RAMSTART): ++ int_val = (int32)bus->dongle_ram_base; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_CC_NVMSHADOW): ++ { ++ struct bcmstrbuf dump_b; ++ ++ bcm_binit(&dump_b, arg, len); ++ bcmerror = dhdpcie_cc_nvmshadow(bus, &dump_b); ++ break; ++ } ++ ++ case IOV_GVAL(IOV_SLEEP_ALLOWED): ++ bool_val = bus->sleep_allowed; ++ bcopy(&bool_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SLEEP_ALLOWED): ++ bus->sleep_allowed = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_DONGLEISOLATION): ++ int_val = bus->dhd->dongle_isolation; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DONGLEISOLATION): ++ bus->dhd->dongle_isolation = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_LTRSLEEPON_UNLOOAD): ++ int_val = bus->ltrsleep_on_unload; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_LTRSLEEPON_UNLOOAD): ++ bus->ltrsleep_on_unload = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_DUMP_RINGUPD_BLOCK): ++ { ++ struct bcmstrbuf dump_b; ++ bcm_binit(&dump_b, arg, len); ++ bcmerror = dhd_prot_ringupd_dump(bus->dhd, &dump_b); ++ break; ++ } ++ case IOV_GVAL(IOV_DMA_RINGINDICES): ++ { int h2d_support, d2h_support; ++ ++ d2h_support = bus->dhd->dma_d2h_ring_upd_support ? 1 : 0; ++ h2d_support = bus->dhd->dma_h2d_ring_upd_support ? 1 : 0; ++ int_val = d2h_support | (h2d_support << 1); ++ bcopy(&int_val, arg, sizeof(int_val)); ++ break; ++ } ++ case IOV_SVAL(IOV_DMA_RINGINDICES): ++ /* Can change it only during initialization/FW download */ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ if ((int_val > 3) || (int_val < 0)) { ++ DHD_ERROR(("%s: Bad argument. Possible values: 0, 1, 2 & 3\n", __FUNCTION__)); ++ bcmerror = BCME_BADARG; ++ } else { ++ bus->dhd->dma_d2h_ring_upd_support = (int_val & 1) ? TRUE : FALSE; ++ bus->dhd->dma_h2d_ring_upd_support = (int_val & 2) ? TRUE : FALSE; ++ bus->dhd->dma_ring_upd_overwrite = TRUE; ++ } ++ } else { ++ DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", ++ __FUNCTION__)); ++ bcmerror = BCME_NOTDOWN; ++ } ++ break; ++ ++ case IOV_GVAL(IOV_METADATA_DBG): ++ int_val = dhd_prot_metadata_dbg_get(bus->dhd); ++ bcopy(&int_val, arg, val_size); ++ break; ++ case IOV_SVAL(IOV_METADATA_DBG): ++ dhd_prot_metadata_dbg_set(bus->dhd, (int_val != 0)); ++ break; ++ ++ case IOV_GVAL(IOV_RX_METADATALEN): ++ int_val = dhd_prot_metadatalen_get(bus->dhd, TRUE); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_RX_METADATALEN): ++ if (int_val > 64) { ++ bcmerror = BCME_BUFTOOLONG; ++ break; ++ } ++ dhd_prot_metadatalen_set(bus->dhd, int_val, TRUE); ++ break; ++ ++ case IOV_SVAL(IOV_TXP_THRESHOLD): ++ dhd_prot_txp_threshold(bus->dhd, TRUE, int_val); ++ break; ++ ++ case IOV_GVAL(IOV_TXP_THRESHOLD): ++ int_val = dhd_prot_txp_threshold(bus->dhd, FALSE, int_val); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DB1_FOR_MB): ++ if (int_val) ++ bus->db1_for_mb = TRUE; ++ else ++ bus->db1_for_mb = FALSE; ++ break; ++ ++ case IOV_GVAL(IOV_DB1_FOR_MB): ++ if (bus->db1_for_mb) ++ int_val = 1; ++ else ++ int_val = 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_TX_METADATALEN): ++ int_val = dhd_prot_metadatalen_get(bus->dhd, FALSE); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TX_METADATALEN): ++ if (int_val > 64) { ++ bcmerror = BCME_BUFTOOLONG; ++ break; ++ } ++ dhd_prot_metadatalen_set(bus->dhd, int_val, FALSE); ++ break; ++ ++ case IOV_SVAL(IOV_DEVRESET): ++ dhd_bus_devreset(bus->dhd, (uint8)bool_val); ++ break; ++ case IOV_SVAL(IOV_FORCE_FW_TRAP): ++ if (bus->dhd->busstate == DHD_BUS_DATA) ++ dhdpcie_fw_trap(bus); ++ else { ++ DHD_ERROR(("%s: Bus is NOT up\n", __FUNCTION__)); ++ bcmerror = BCME_NOTUP; ++ } ++ break; ++ case IOV_GVAL(IOV_FLOW_PRIO_MAP): ++ int_val = bus->dhd->flow_prio_map_type; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_FLOW_PRIO_MAP): ++ int_val = (int32)dhd_update_flow_prio_map(bus->dhd, (uint8)int_val); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++ case IOV_GVAL(IOV_IDLETIME): ++ int_val = bus->idletime; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_IDLETIME): ++ if (int_val < 0) { ++ bcmerror = BCME_BADARG; ++ } else { ++ bus->idletime = int_val; ++ if (bus->idletime) { ++ DHD_ENABLE_RUNTIME_PM(bus->dhd); ++ } else { ++ DHD_DISABLE_RUNTIME_PM(bus->dhd); ++ } ++ } ++ break; ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ case IOV_GVAL(IOV_TXBOUND): ++ int_val = (int32)dhd_txbound; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXBOUND): ++ dhd_txbound = (uint)int_val; ++ break; ++ ++ case IOV_SVAL(IOV_H2D_MAILBOXDATA): ++ dhdpcie_send_mb_data(bus, (uint)int_val); ++ break; ++ ++ case IOV_SVAL(IOV_INFORINGS): ++ dhd_prot_init_info_rings(bus->dhd); ++ break; ++ ++ case IOV_SVAL(IOV_H2D_PHASE): ++ if (bus->dhd->busstate != DHD_BUS_DOWN) { ++ DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", ++ __FUNCTION__)); ++ bcmerror = BCME_NOTDOWN; ++ break; ++ } ++ if (int_val) ++ bus->dhd->h2d_phase_supported = TRUE; ++ else ++ bus->dhd->h2d_phase_supported = FALSE; ++ break; ++ ++ case IOV_GVAL(IOV_H2D_PHASE): ++ int_val = (int32) bus->dhd->h2d_phase_supported; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_H2D_ENABLE_TRAP_BADPHASE): ++ if (bus->dhd->busstate != DHD_BUS_DOWN) { ++ DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", ++ __FUNCTION__)); ++ bcmerror = BCME_NOTDOWN; ++ break; ++ } ++ if (int_val) ++ bus->dhd->force_dongletrap_on_bad_h2d_phase = TRUE; ++ else ++ bus->dhd->force_dongletrap_on_bad_h2d_phase = FALSE; ++ break; ++ ++ case IOV_GVAL(IOV_H2D_ENABLE_TRAP_BADPHASE): ++ int_val = (int32) bus->dhd->force_dongletrap_on_bad_h2d_phase; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_H2D_TXPOST_MAX_ITEM): ++ if (bus->dhd->busstate != DHD_BUS_DOWN) { ++ DHD_ERROR(("%s: Can change only when bus down (before FW download)\n", ++ __FUNCTION__)); ++ bcmerror = BCME_NOTDOWN; ++ break; ++ } ++ dhd_prot_set_h2d_max_txpost(bus->dhd, (uint16)int_val); ++ break; ++ ++ case IOV_GVAL(IOV_H2D_TXPOST_MAX_ITEM): ++ int_val = dhd_prot_get_h2d_max_txpost(bus->dhd); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_RXBOUND): ++ int_val = (int32)dhd_rxbound; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_RXBOUND): ++ dhd_rxbound = (uint)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_TRAPDATA): ++ { ++ struct bcmstrbuf dump_b; ++ bcm_binit(&dump_b, arg, len); ++ bcmerror = dhd_prot_dump_extended_trap(bus->dhd, &dump_b, FALSE); ++ break; ++ } ++ ++ case IOV_GVAL(IOV_TRAPDATA_RAW): ++ { ++ struct bcmstrbuf dump_b; ++ bcm_binit(&dump_b, arg, len); ++ bcmerror = dhd_prot_dump_extended_trap(bus->dhd, &dump_b, TRUE); ++ break; ++ } ++ case IOV_SVAL(IOV_HANGREPORT): ++ bus->dhd->hang_report = bool_val; ++ DHD_ERROR(("%s: Set hang_report as %d\n", ++ __FUNCTION__, bus->dhd->hang_report)); ++ break; ++ ++ case IOV_GVAL(IOV_HANGREPORT): ++ int_val = (int32)bus->dhd->hang_report; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_CTO_PREVENTION): ++ { ++ uint32 pcie_lnkst; ++ ++ if (bus->sih->buscorerev < 19) { ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ si_corereg(bus->sih, bus->sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, configaddr), ~0, PCI_LINK_STATUS); ++ ++ pcie_lnkst = si_corereg(bus->sih, bus->sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, configdata), 0, 0); ++ ++ /* 4347A0 in PCIEGEN1 doesn't support CTO prevention due to ++ * 4347A0 DAR Issue : JIRA:CRWLPCIEGEN2-443: Issue in DAR write ++ */ ++ if ((bus->sih->buscorerev == 19) && ++ (((pcie_lnkst >> PCI_LINK_SPEED_SHIFT) & ++ PCI_LINK_SPEED_MASK) == PCIE_LNK_SPEED_GEN1)) { ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ bus->dhd->cto_enable = bool_val; ++ dhdpcie_cto_init(bus, bus->dhd->cto_enable); ++ DHD_ERROR(("%s: set CTO prevention and recovery enable/disable %d\n", ++ __FUNCTION__, bus->dhd->cto_enable)); ++ } ++ break; ++ ++ case IOV_GVAL(IOV_CTO_PREVENTION): ++ if (bus->sih->buscorerev < 19) { ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ int_val = (int32)bus->dhd->cto_enable; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_CTO_THRESHOLD): ++ { ++ if (bus->sih->buscorerev < 19) { ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ bus->dhd->cto_threshold = (uint32)int_val; ++ } ++ break; ++ ++ case IOV_GVAL(IOV_CTO_THRESHOLD): ++ if (bus->sih->buscorerev < 19) { ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ if (bus->dhd->cto_threshold) ++ int_val = (int32)bus->dhd->cto_threshold; ++ else ++ int_val = (int32)PCIE_CTO_TO_THRESH_DEFAULT; ++ ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_PCIE_WD_RESET): ++ if (bool_val) { ++ pcie_watchdog_reset(bus->osh, bus->sih, (sbpcieregs_t *) bus->regs); ++ } ++ break; ++#ifdef DHD_EFI ++ case IOV_SVAL(IOV_CONTROL_SIGNAL): ++ { ++ bcmerror = dhd_control_signal(bus, arg, TRUE); ++ break; ++ } ++ ++ case IOV_GVAL(IOV_CONTROL_SIGNAL): ++ { ++ bcmerror = dhd_control_signal(bus, params, FALSE); ++ break; ++ } ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++ case IOV_GVAL(IOV_DEEP_SLEEP): ++ int_val = bus->ds_enabled; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DEEP_SLEEP): ++ if (int_val == 1) { ++ bus->ds_enabled = TRUE; ++ /* Deassert */ ++ if (dhd_bus_set_device_wake(bus, FALSE) == BCME_OK) { ++#ifdef PCIE_INB_DW ++ int timeleft; ++ timeleft = dhd_os_ds_enter_wait(bus->dhd, NULL); ++ if (timeleft == 0) { ++ DHD_ERROR(("DS-ENTER timeout\n")); ++ bus->ds_enabled = FALSE; ++ break; ++ } ++#endif /* PCIE_INB_DW */ ++ } ++ else { ++ DHD_ERROR(("%s: Enable Deep Sleep failed !\n", __FUNCTION__)); ++ bus->ds_enabled = FALSE; ++ } ++ } ++ else if (int_val == 0) { ++ /* Assert */ ++ if (dhd_bus_set_device_wake(bus, TRUE) == BCME_OK) ++ bus->ds_enabled = FALSE; ++ else ++ DHD_ERROR(("%s: Disable Deep Sleep failed !\n", __FUNCTION__)); ++ } ++ else ++ DHD_ERROR(("%s: Invalid number, allowed only 0|1\n", __FUNCTION__)); ++ ++ break; ++#endif /* PCIE_OOB || PCIE_INB_DW */ ++ ++ case IOV_GVAL(IOV_WIFI_PROPERTIES): ++ bcmerror = dhd_wifi_properties(bus, params); ++ break; ++ ++ case IOV_GVAL(IOV_OTP_DUMP): ++ bcmerror = dhd_otp_dump(bus, params); ++ break; ++#endif /* DHD_EFI */ ++ ++ case IOV_GVAL(IOV_IDMA_ENABLE): ++ int_val = bus->idma_enabled; ++ bcopy(&int_val, arg, val_size); ++ break; ++ case IOV_SVAL(IOV_IDMA_ENABLE): ++ bus->idma_enabled = (bool)int_val; ++ break; ++ case IOV_GVAL(IOV_IFRM_ENABLE): ++ int_val = bus->ifrm_enabled; ++ bcopy(&int_val, arg, val_size); ++ break; ++ case IOV_SVAL(IOV_IFRM_ENABLE): ++ bus->ifrm_enabled = (bool)int_val; ++ break; ++ case IOV_GVAL(IOV_CLEAR_RING): ++ bcopy(&int_val, arg, val_size); ++ dhd_flow_rings_flush(bus->dhd, 0); ++ break; ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ ++exit: ++ return bcmerror; ++} /* dhdpcie_bus_doiovar */ ++ ++/** Transfers bytes from host to dongle using pio mode */ ++static int ++dhdpcie_bus_lpback_req(struct dhd_bus *bus, uint32 len) ++{ ++ if (bus->dhd == NULL) { ++ DHD_ERROR(("%s: bus not inited\n", __FUNCTION__)); ++ return 0; ++ } ++ if (bus->dhd->prot == NULL) { ++ DHD_ERROR(("%s: prot is not inited\n", __FUNCTION__)); ++ return 0; ++ } ++ if (bus->dhd->busstate != DHD_BUS_DATA) { ++ DHD_ERROR(("%s: not in a readystate to LPBK is not inited\n", __FUNCTION__)); ++ return 0; ++ } ++ dhdmsgbuf_lpbk_req(bus->dhd, len); ++ return 0; ++} ++ ++/* Ring DoorBell1 to indicate Hostready i.e. D3 Exit */ ++void ++dhd_bus_hostready(struct dhd_bus *bus) ++{ ++ if (!bus->dhd->d2h_hostrdy_supported) { ++ return; ++ } ++ ++ if (bus->is_linkdown) { ++ DHD_ERROR(("%s: PCIe link was down\n", __FUNCTION__)); ++ return; ++ } ++ ++ DHD_INFO_HW4(("%s : Read PCICMD Reg: 0x%08X\n", __FUNCTION__, ++ dhd_pcie_config_read(bus->osh, PCI_CFG_CMD, sizeof(uint32)))); ++ si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_DB1, ~0, 0x12345678); ++ bus->hostready_count ++; ++ DHD_INFO_HW4(("%s: Ring Hostready:%d\n", __FUNCTION__, bus->hostready_count)); ++} ++ ++/* Clear INTSTATUS */ ++void ++dhdpcie_bus_clear_intstatus(struct dhd_bus *bus) ++{ ++ uint32 intstatus = 0; ++ if ((bus->sih->buscorerev == 6) || (bus->sih->buscorerev == 4) || ++ (bus->sih->buscorerev == 2)) { ++ intstatus = dhdpcie_bus_cfg_read_dword(bus, PCIIntstatus, 4); ++ dhdpcie_bus_cfg_write_dword(bus, PCIIntstatus, 4, intstatus); ++ } else { ++ /* this is a PCIE core register..not a config register... */ ++ intstatus = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); ++ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, bus->def_intmask, ++ intstatus); ++ } ++} ++ ++int ++dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) ++{ ++ int timeleft; ++ int rc = 0; ++ unsigned long flags; ++ ++ printf("%s: state=%d\n", __FUNCTION__, state); ++ if (bus->dhd == NULL) { ++ DHD_ERROR(("%s: bus not inited\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ if (bus->dhd->prot == NULL) { ++ DHD_ERROR(("%s: prot is not inited\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ if (dhd_query_bus_erros(bus->dhd)) { ++ return BCME_ERROR; ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ if (!(bus->dhd->busstate == DHD_BUS_DATA || bus->dhd->busstate == DHD_BUS_SUSPEND)) { ++ DHD_ERROR(("%s: not in a readystate\n", __FUNCTION__)); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ return BCME_ERROR; ++ } ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ if (bus->dhd->dongle_reset) { ++ DHD_ERROR(("Dongle is in reset state.\n")); ++ return -EIO; ++ } ++ ++ /* Check whether we are already in the requested state. ++ * state=TRUE means Suspend ++ * state=FALSE meanse Resume ++ */ ++ if (state == TRUE && bus->dhd->busstate == DHD_BUS_SUSPEND) { ++ DHD_ERROR(("Bus is already in SUSPEND state.\n")); ++ return BCME_OK; ++ } else if (state == FALSE && bus->dhd->busstate == DHD_BUS_DATA) { ++ DHD_ERROR(("Bus is already in RESUME state.\n")); ++ return BCME_OK; ++ } ++ ++ if (bus->d3_suspend_pending) { ++ DHD_ERROR(("Suspend pending ...\n")); ++ return BCME_ERROR; ++ } ++ ++ ++ if (state) { ++ int idle_retry = 0; ++ int active; ++ ++ if (bus->is_linkdown) { ++ DHD_ERROR(("%s: PCIe link was down, state=%d\n", ++ __FUNCTION__, state)); ++ return BCME_ERROR; ++ } ++ ++ /* Suspend */ ++ DHD_ERROR(("%s: Entering suspend state\n", __FUNCTION__)); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ if (DHD_BUS_BUSY_CHECK_IN_TX(bus->dhd)) { ++ DHD_ERROR(("Tx Request is not ended\n")); ++ bus->dhd->busstate = DHD_BUS_DATA; ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++#ifndef DHD_EFI ++ return -EBUSY; ++#else ++ return BCME_ERROR; ++#endif ++ } ++ ++ /* stop all interface network queue. */ ++ dhd_bus_stop_queue(bus); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); ++#ifdef DHD_TIMESYNC ++ /* disable time sync mechanism, if configed */ ++ dhd_timesync_control(bus->dhd, TRUE); ++#endif /* DHD_TIMESYNC */ ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++ dhd_bus_set_device_wake(bus, TRUE); ++#endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ ++#ifdef PCIE_OOB ++ bus->oob_presuspend = TRUE; ++#endif ++#ifdef PCIE_INB_DW ++ /* De-assert at this point for In-band device_wake */ ++ if (INBAND_DW_ENAB(bus)) { ++ dhd_bus_set_device_wake(bus, FALSE); ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, DW_DEVICE_HOST_SLEEP_WAIT); ++ } ++#endif /* PCIE_INB_DW */ ++ ++ /* Clear wait_for_d3_ack */ ++ bus->wait_for_d3_ack = 0; ++ /* ++ * Send H2D_HOST_D3_INFORM to dongle and mark ++ * bus->d3_suspend_pending to TRUE in dhdpcie_send_mb_data ++ * inside atomic context, so that no more DBs will be ++ * rung after sending D3_INFORM ++ */ ++ dhdpcie_send_mb_data(bus, H2D_HOST_D3_INFORM); ++ ++ /* Wait for D3 ACK for D3_ACK_RESP_TIMEOUT seconds */ ++ dhd_os_set_ioctl_resp_timeout(D3_ACK_RESP_TIMEOUT); ++ timeleft = dhd_os_d3ack_wait(bus->dhd, &bus->wait_for_d3_ack); ++ ++#ifdef DHD_RECOVER_TIMEOUT ++ if (bus->wait_for_d3_ack == 0) { ++ /* If wait_for_d3_ack was not updated because D2H MB was not received */ ++ uint32 intstatus = 0; ++ uint32 intmask = 0; ++ intstatus = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); ++ intmask = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, 0, 0); ++ if ((intstatus) && (!intmask) && (timeleft == 0) && ++ (!dhd_query_bus_erros(bus->dhd))) { ++ ++ DHD_ERROR(("%s: D3 ACK trying again intstatus=%x intmask=%x\n", ++ __FUNCTION__, intstatus, intmask)); ++ DHD_ERROR(("\n ------- DUMPING INTR enable/disable counters\r\n")); ++ DHD_ERROR(("resume_intr_enable_count=%lu dpc_intr_en_count=%lu\n" ++ "isr_intr_disable_count=%lu suspend_intr_dis_count=%lu\n" ++ "dpc_return_busdown_count=%lu\n", ++ bus->resume_intr_enable_count, bus->dpc_intr_enable_count, ++ bus->isr_intr_disable_count, ++ bus->suspend_intr_disable_count, ++ bus->dpc_return_busdown_count)); ++ ++ dhd_prot_process_ctrlbuf(bus->dhd); ++ ++ timeleft = dhd_os_d3ack_wait(bus->dhd, &bus->wait_for_d3_ack); ++ ++ /* Enable Back Interrupts using IntMask */ ++ dhdpcie_bus_intr_enable(bus); ++ } ++ ++ ++ } /* bus->wait_for_d3_ack was 0 */ ++#endif /* DHD_RECOVER_TIMEOUT */ ++ ++ DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); ++ ++ /* To allow threads that got pre-empted to complete. ++ */ ++ while ((active = dhd_os_check_wakelock_all(bus->dhd)) && ++ (idle_retry < MAX_WKLK_IDLE_CHECK)) { ++ OSL_SLEEP(1); ++ idle_retry++; ++ } ++ ++ if (bus->wait_for_d3_ack) { ++ DHD_ERROR(("%s: Got D3 Ack \n", __FUNCTION__)); ++ ++ /* Got D3 Ack. Suspend the bus */ ++ if (active) { ++ DHD_ERROR(("%s():Suspend failed because of wakelock" ++ "restoring Dongle to D0\n", __FUNCTION__)); ++ ++ /* ++ * Dongle still thinks that it has to be in D3 state until ++ * it gets a D0 Inform, but we are backing off from suspend. ++ * Ensure that Dongle is brought back to D0. ++ * ++ * Bringing back Dongle from D3 Ack state to D0 state is a ++ * 2 step process. Dongle would want to know that D0 Inform ++ * would be sent as a MB interrupt to bring it out of D3 Ack ++ * state to D0 state. So we have to send both this message. ++ */ ++ ++ /* Clear wait_for_d3_ack to send D0_INFORM or host_ready */ ++ bus->wait_for_d3_ack = 0; ++ ++ /* Enable back the intmask which was cleared in DPC ++ * after getting D3_ACK. ++ */ ++ bus->resume_intr_enable_count++; ++ dhdpcie_bus_intr_enable(bus); ++ ++ if (bus->use_d0_inform) { ++ DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); ++ dhdpcie_send_mb_data(bus, ++ (H2D_HOST_D0_INFORM_IN_USE | H2D_HOST_D0_INFORM)); ++ DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); ++ } ++ /* ring doorbell 1 (hostready) */ ++ dhd_bus_hostready(bus); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ bus->d3_suspend_pending = FALSE; ++ bus->dhd->busstate = DHD_BUS_DATA; ++ /* resume all interface network queue. */ ++ dhd_bus_start_queue(bus); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ rc = BCME_ERROR; ++ } else { ++#ifdef PCIE_OOB ++ bus->oob_presuspend = FALSE; ++ if (OOB_DW_ENAB(bus)) { ++ dhd_bus_set_device_wake(bus, FALSE); ++ } ++#endif /* PCIE_OOB */ ++#if defined(PCIE_OOB) || defined(BCMPCIE_OOB_HOST_WAKE) ++ bus->oob_presuspend = TRUE; ++#endif /* PCIE_OOB || BCMPCIE_OOB_HOST_WAKE */ ++#ifdef PCIE_INB_DW ++ if (INBAND_DW_ENAB(bus)) { ++ if (dhdpcie_bus_get_pcie_inband_dw_state(bus) == ++ DW_DEVICE_HOST_SLEEP_WAIT) { ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, ++ DW_DEVICE_HOST_SLEEP); ++ } ++ } ++#endif /* PCIE_INB_DW */ ++ if (bus->use_d0_inform && ++ (bus->api.fw_rev < PCIE_SHARED_VERSION_6)) { ++ DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); ++ dhdpcie_send_mb_data(bus, (H2D_HOST_D0_INFORM_IN_USE)); ++ DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); ++ } ++#if defined(BCMPCIE_OOB_HOST_WAKE) ++ dhdpcie_oob_intr_set(bus, TRUE); ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ /* The Host cannot process interrupts now so disable the same. ++ * No need to disable the dongle INTR using intmask, as we are ++ * already calling dhdpcie_bus_intr_disable from DPC context after ++ * getting D3_ACK. Code may not look symmetric between Suspend and ++ * Resume paths but this is done to close down the timing window ++ * between DPC and suspend context. ++ */ ++ /* Disable interrupt from host side!! */ ++ dhdpcie_disable_irq_nosync(bus); ++ ++ bus->dhd->d3ackcnt_timeout = 0; ++ bus->d3_suspend_pending = FALSE; ++ bus->dhd->busstate = DHD_BUS_SUSPEND; ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ /* Handle Host Suspend */ ++ rc = dhdpcie_pci_suspend_resume(bus, state); ++ } ++ } else if (timeleft == 0) { ++ bus->dhd->d3ack_timeout_occured = TRUE; ++ /* If the D3 Ack has timeout */ ++ bus->dhd->d3ackcnt_timeout++; ++ DHD_ERROR(("%s: resumed on timeout for D3 ACK d3_inform_cnt %d \n", ++ __FUNCTION__, bus->dhd->d3ackcnt_timeout)); ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ bus->d3_suspend_pending = FALSE; ++ bus->dhd->busstate = DHD_BUS_DATA; ++ /* resume all interface network queue. */ ++ dhd_bus_start_queue(bus); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ if (!bus->dhd->dongle_trap_occured) { ++ uint32 intstatus = 0; ++ ++ /* Check if PCIe bus status is valid */ ++ intstatus = si_corereg(bus->sih, ++ bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); ++ if (intstatus == (uint32)-1) { ++ /* Invalidate PCIe bus status */ ++ bus->is_linkdown = 1; ++ } ++ ++ dhd_bus_dump_console_buffer(bus); ++ dhd_prot_debug_info_print(bus->dhd); ++#ifdef DHD_FW_COREDUMP ++ if (bus->dhd->memdump_enabled) { ++ /* write core dump to file */ ++ bus->dhd->memdump_type = DUMP_TYPE_D3_ACK_TIMEOUT; ++ dhdpcie_mem_dump(bus); ++ } ++#endif /* DHD_FW_COREDUMP */ ++ DHD_ERROR(("%s: Event HANG send up due to D3_ACK timeout\n", ++ __FUNCTION__)); ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++#ifdef CONFIG_ARCH_MSM ++ bus->no_cfg_restore = 1; ++#endif /* CONFIG_ARCH_MSM */ ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ dhd_os_check_hang(bus->dhd, 0, -ETIMEDOUT); ++ } ++ rc = -ETIMEDOUT; ++ } ++ bus->wait_for_d3_ack = 1; ++ ++#ifdef PCIE_OOB ++ bus->oob_presuspend = FALSE; ++#endif /* PCIE_OOB */ ++ } else { ++ /* Resume */ ++ /** ++ * PCIE2_BAR0_CORE2_WIN gets reset after D3 cold. ++ * si_backplane_access(function to read/write backplane) ++ * updates the window(PCIE2_BAR0_CORE2_WIN) only if ++ * window being accessed is different form the window ++ * being pointed by second_bar0win. ++ * Since PCIE2_BAR0_CORE2_WIN is already reset because of D3 cold, ++ * invalidating second_bar0win after resume updates ++ * PCIE2_BAR0_CORE2_WIN with right window. ++ */ ++ si_invalidate_second_bar0win(bus->sih); ++#if defined(BCMPCIE_OOB_HOST_WAKE) ++ DHD_OS_OOB_IRQ_WAKE_UNLOCK(bus->dhd); ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++#ifdef PCIE_INB_DW ++ if (INBAND_DW_ENAB(bus)) { ++ if (dhdpcie_bus_get_pcie_inband_dw_state(bus) == DW_DEVICE_HOST_SLEEP) { ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, DW_DEVICE_HOST_WAKE_WAIT); ++ } ++ } ++#endif /* PCIE_INB_DW */ ++ rc = dhdpcie_pci_suspend_resume(bus, state); ++ ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ bus->oob_presuspend = FALSE; ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ ++ if (bus->dhd->busstate == DHD_BUS_SUSPEND) { ++ if (bus->use_d0_inform) { ++ DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); ++ dhdpcie_send_mb_data(bus, (H2D_HOST_D0_INFORM)); ++ DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); ++ } ++ /* ring doorbell 1 (hostready) */ ++ dhd_bus_hostready(bus); ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ bus->dhd->busstate = DHD_BUS_DATA; ++#ifdef DHD_PCIE_RUNTIMEPM ++ if (DHD_BUS_BUSY_CHECK_RPM_SUSPEND_DONE(bus->dhd)) { ++ bus->bus_wake = 1; ++ OSL_SMP_WMB(); ++ wake_up_interruptible(&bus->rpm_queue); ++ } ++#endif /* DHD_PCIE_RUNTIMEPM */ ++#ifdef PCIE_OOB ++ /* ++ * Assert & Deassert the Device Wake. The following is the explanation for doing so. ++ * 0) At this point, ++ * Host is in suspend state, Link is in L2/L3, Dongle is in D3 Cold ++ * Device Wake is enabled. ++ * 1) When the Host comes out of Suspend, it first sends PERST# in the Link. ++ * Looking at this the Dongle moves from D3 Cold to NO DS State ++ * 2) Now The Host OS calls the "resume" function of DHD. From here the DHD first ++ * Asserts the Device Wake. ++ * From the defn, when the Device Wake is asserted, The dongle FW will ensure ++ * that the Dongle is out of deep sleep IF the device is already in deep sleep. ++ * But note that now the Dongle is NOT in Deep sleep and is actually in ++ * NO DS state. So just driving the Device Wake high does not trigger any state ++ * transitions. The Host should actually "Toggle" the Device Wake to ensure ++ * that Dongle synchronizes with the Host and starts the State Transition to D0. ++ * 4) Note that the above explanation is applicable Only when the Host comes out of ++ * suspend and the Dongle comes out of D3 Cold ++ */ ++ /* This logic is not required when hostready is enabled */ ++ ++ if (!bus->dhd->d2h_hostrdy_supported) { ++ if (OOB_DW_ENAB(bus)) { ++ dhd_bus_set_device_wake(bus, TRUE); ++ OSL_DELAY(1000); ++ dhd_bus_set_device_wake(bus, FALSE); ++ } ++ } ++#endif /* PCIE_OOB */ ++ /* resume all interface network queue. */ ++ dhd_bus_start_queue(bus); ++ /* The Host is ready to process interrupts now so enable the same. */ ++ ++ /* TODO: for NDIS also we need to use enable_irq in future */ ++ bus->resume_intr_enable_count++; ++ dhdpcie_bus_intr_enable(bus); /* Enable back interrupt using Intmask!! */ ++ dhdpcie_enable_irq(bus); /* Enable back interrupt from Host side!! */ ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++#ifdef DHD_TIMESYNC ++ DHD_OS_WAKE_LOCK_WAIVE(bus->dhd); ++ /* enable time sync mechanism, if configed */ ++ dhd_timesync_control(bus->dhd, FALSE); ++ DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); ++#endif /* DHD_TIMESYNC */ ++ } ++ return rc; ++} ++ ++uint32 ++dhdpcie_force_alp(struct dhd_bus *bus, bool enable) ++{ ++ ASSERT(bus && bus->sih); ++ if (enable) { ++ si_corereg(bus->sih, bus->sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, u.pcie2.clk_ctl_st), CCS_FORCEALP, CCS_FORCEALP); ++ } else { ++ si_corereg(bus->sih, bus->sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, u.pcie2.clk_ctl_st), CCS_FORCEALP, 0); ++ } ++ return 0; ++} ++ ++/* set pcie l1 entry time: dhd pciereg 0x1004[22:16] */ ++uint32 ++dhdpcie_set_l1_entry_time(struct dhd_bus *bus, int l1_entry_time) ++{ ++ uint reg_val; ++ ++ ASSERT(bus && bus->sih); ++ ++ si_corereg(bus->sih, bus->sih->buscoreidx, OFFSETOF(sbpcieregs_t, configaddr), ~0, ++ 0x1004); ++ reg_val = si_corereg(bus->sih, bus->sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, configdata), 0, 0); ++ reg_val = (reg_val & ~(0x7f << 16)) | ((l1_entry_time & 0x7f) << 16); ++ si_corereg(bus->sih, bus->sih->buscoreidx, OFFSETOF(sbpcieregs_t, configdata), ~0, ++ reg_val); ++ ++ return 0; ++} ++ ++/** Transfers bytes from host to dongle and to host again using DMA */ ++static int ++dhdpcie_bus_dmaxfer_req( ++ struct dhd_bus *bus, uint32 len, uint32 srcdelay, uint32 destdelay, uint32 d11_lpbk) ++{ ++ if (bus->dhd == NULL) { ++ DHD_ERROR(("%s: bus not inited\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ if (bus->dhd->prot == NULL) { ++ DHD_ERROR(("%s: prot is not inited\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ if (bus->dhd->busstate != DHD_BUS_DATA) { ++ DHD_ERROR(("%s: not in a readystate to LPBK is not inited\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ if (len < 5 || len > 4194296) { ++ DHD_ERROR(("%s: len is too small or too large\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ return dhdmsgbuf_dmaxfer_req(bus->dhd, len, srcdelay, destdelay, d11_lpbk); ++} ++ ++ ++ ++static int ++dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter) ++{ ++ int bcmerror = 0; ++ volatile uint32 *cr4_regs; ++ ++ if (!bus->sih) { ++ DHD_ERROR(("%s: NULL sih!!\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ /* To enter download state, disable ARM and reset SOCRAM. ++ * To exit download state, simply reset ARM (default is RAM boot). ++ */ ++ if (enter) { ++ /* Make sure BAR1 maps to backplane address 0 */ ++ dhdpcie_bus_cfg_write_dword(bus, PCI_BAR1_WIN, 4, 0x00000000); ++ bus->alp_only = TRUE; ++ ++ /* some chips (e.g. 43602) have two ARM cores, the CR4 is receives the firmware. */ ++ cr4_regs = si_setcore(bus->sih, ARMCR4_CORE_ID, 0); ++ ++ if (cr4_regs == NULL && !(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && ++ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) && ++ !(si_setcore(bus->sih, ARMCA7_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ if (si_setcore(bus->sih, ARMCA7_CORE_ID, 0)) { ++ /* Halt ARM & remove reset */ ++ si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); ++ if (!(si_setcore(bus->sih, SYSMEM_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find SYSMEM core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ si_core_reset(bus->sih, 0, 0); ++ /* reset last 4 bytes of RAM address. to be used for shared area */ ++ dhdpcie_init_shared_addr(bus); ++ } else if (cr4_regs == NULL) { /* no CR4 present on chip */ ++ si_core_disable(bus->sih, 0); ++ ++ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ si_core_reset(bus->sih, 0, 0); ++ ++ /* Clear the top bit of memory */ ++ if (bus->ramsize) { ++ uint32 zeros = 0; ++ if (dhdpcie_bus_membytes(bus, TRUE, bus->ramsize - 4, ++ (uint8*)&zeros, 4) < 0) { ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ } ++ } else { ++ /* For CR4, ++ * Halt ARM ++ * Remove ARM reset ++ * Read RAM base address [0x18_0000] ++ * [next] Download firmware ++ * [done at else] Populate the reset vector ++ * [done at else] Remove ARM halt ++ */ ++ /* Halt ARM & remove reset */ ++ si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); ++ if (BCM43602_CHIP(bus->sih->chip)) { ++ W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKIDX, 5); ++ W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKPDA, 0); ++ W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKIDX, 7); ++ W_REG(bus->pcie_mb_intr_osh, cr4_regs + ARMCR4REG_BANKPDA, 0); ++ } ++ /* reset last 4 bytes of RAM address. to be used for shared area */ ++ dhdpcie_init_shared_addr(bus); ++ } ++ } else { ++ if (si_setcore(bus->sih, ARMCA7_CORE_ID, 0)) { ++ /* write vars */ ++ if ((bcmerror = dhdpcie_bus_write_vars(bus))) { ++ DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); ++ goto fail; ++ } ++ /* switch back to arm core again */ ++ if (!(si_setcore(bus->sih, ARMCA7_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find ARM CA7 core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ /* write address 0 with reset instruction */ ++ bcmerror = dhdpcie_bus_membytes(bus, TRUE, 0, ++ (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); ++ /* now remove reset and halt and continue to run CA7 */ ++ } else if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ if (!si_iscoreup(bus->sih)) { ++ DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ /* Enable remap before ARM reset but after vars. ++ * No backplane access in remap mode ++ */ ++ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && ++ !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { ++ DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ ++ if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && ++ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ } else { ++ if (BCM43602_CHIP(bus->sih->chip)) { ++ /* Firmware crashes on SOCSRAM access when core is in reset */ ++ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find SOCRAM core!\n", ++ __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ si_core_reset(bus->sih, 0, 0); ++ si_setcore(bus->sih, ARMCR4_CORE_ID, 0); ++ } ++ ++ /* write vars */ ++ if ((bcmerror = dhdpcie_bus_write_vars(bus))) { ++ DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++#ifdef BCM_ASLR_HEAP ++ /* write a random number to TCM for the purpose of ++ * randomizing heap address space. ++ */ ++ dhdpcie_wrt_rnd(bus); ++#endif /* BCM_ASLR_HEAP */ ++ ++ /* switch back to arm core again */ ++ if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ /* write address 0 with reset instruction */ ++ bcmerror = dhdpcie_bus_membytes(bus, TRUE, 0, ++ (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); ++ ++ if (bcmerror == BCME_OK) { ++ uint32 tmp; ++ ++ bcmerror = dhdpcie_bus_membytes(bus, FALSE, 0, ++ (uint8 *)&tmp, sizeof(tmp)); ++ ++ if (bcmerror == BCME_OK && tmp != bus->resetinstr) { ++ DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n", ++ __FUNCTION__, bus->resetinstr)); ++ DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n", ++ __FUNCTION__, tmp)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ } ++ ++ /* now remove reset and halt and continue to run CR4 */ ++ } ++ ++ si_core_reset(bus->sih, 0, 0); ++ ++ /* Allow HT Clock now that the ARM is running. */ ++ bus->alp_only = FALSE; ++ ++ bus->dhd->busstate = DHD_BUS_LOAD; ++ } ++ ++fail: ++ /* Always return to PCIE core */ ++ si_setcore(bus->sih, PCIE2_CORE_ID, 0); ++ ++ return bcmerror; ++} /* dhdpcie_bus_download_state */ ++ ++static int ++dhdpcie_bus_write_vars(dhd_bus_t *bus) ++{ ++ int bcmerror = 0; ++ uint32 varsize, phys_size; ++ uint32 varaddr; ++ uint8 *vbuffer; ++ uint32 varsizew; ++#ifdef DHD_DEBUG ++ uint8 *nvram_ularray; ++#endif /* DHD_DEBUG */ ++ ++ /* 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; ++ ++ varaddr += bus->dongle_ram_base; ++ ++ if (bus->vars) { ++ ++ vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); ++ if (!vbuffer) ++ return BCME_NOMEM; ++ ++ bzero(vbuffer, varsize); ++ bcopy(bus->vars, vbuffer, bus->varsz); ++ /* Write the vars list */ ++ bcmerror = dhdpcie_bus_membytes(bus, TRUE, varaddr, vbuffer, varsize); ++ ++ /* Implement read back and verify later */ ++#ifdef DHD_DEBUG ++ /* Verify NVRAM bytes */ ++ DHD_INFO(("%s: Compare NVRAM dl & ul; varsize=%d\n", __FUNCTION__, varsize)); ++ nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); ++ if (!nvram_ularray) ++ return BCME_NOMEM; ++ ++ /* Upload image to verify downloaded contents. */ ++ memset(nvram_ularray, 0xaa, varsize); ++ ++ /* Read the vars list to temp buffer for comparison */ ++ bcmerror = dhdpcie_bus_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, varsize, varaddr)); ++ } ++ ++ /* Compare the org NVRAM with the one read from RAM */ ++ if (memcmp(vbuffer, nvram_ularray, varsize)) { ++ DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); ++ } else ++ DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", ++ __FUNCTION__)); ++ ++ MFREE(bus->dhd->osh, nvram_ularray, varsize); ++#endif /* DHD_DEBUG */ ++ ++ MFREE(bus->dhd->osh, vbuffer, varsize); ++ } ++ ++ phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; ++ ++ phys_size += bus->dongle_ram_base; ++ ++ /* adjust to the user specified RAM */ ++ DHD_INFO(("%s: Physical memory size: %d, usable memory size: %d\n", __FUNCTION__, ++ phys_size, bus->ramsize)); ++ DHD_INFO(("%s: Vars are at %d, orig varsize is %d\n", __FUNCTION__, ++ varaddr, varsize)); ++ varsize = ((phys_size - 4) - varaddr); ++ ++ /* ++ * Determine the length token: ++ * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. ++ */ ++ if (bcmerror) { ++ varsizew = 0; ++ bus->nvram_csm = varsizew; ++ } else { ++ varsizew = varsize / 4; ++ varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); ++ bus->nvram_csm = varsizew; ++ varsizew = htol32(varsizew); ++ } ++ ++ DHD_INFO(("%s: New varsize is %d, length token=0x%08x\n", __FUNCTION__, varsize, varsizew)); ++ ++ /* Write the length token to the last word */ ++ bcmerror = dhdpcie_bus_membytes(bus, TRUE, (phys_size - 4), ++ (uint8*)&varsizew, 4); ++ ++ return bcmerror; ++} /* dhdpcie_bus_write_vars */ ++ ++int ++dhdpcie_downloadvars(dhd_bus_t *bus, void *arg, int len) ++{ ++ int bcmerror = BCME_OK; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ /* Basic sanity checks */ ++ if (bus->dhd->up) { ++ bcmerror = BCME_NOTDOWN; ++ goto err; ++ } ++ if (!len) { ++ bcmerror = BCME_BUFTOOSHORT; ++ goto err; ++ } ++ ++ /* Free the old ones and replace with passed variables */ ++ if (bus->vars) ++ MFREE(bus->dhd->osh, bus->vars, bus->varsz); ++ ++ bus->vars = MALLOC(bus->dhd->osh, len); ++ bus->varsz = bus->vars ? len : 0; ++ if (bus->vars == NULL) { ++ bcmerror = BCME_NOMEM; ++ goto err; ++ } ++ ++ /* Copy the passed variables, which should include the terminating double-null */ ++ bcopy(arg, bus->vars, bus->varsz); ++ ++#ifdef DHD_USE_SINGLE_NVRAM_FILE ++ if (dhd_bus_get_fw_mode(bus->dhd) == DHD_FLAG_MFG_MODE) { ++ char *sp = NULL; ++ char *ep = NULL; ++ int i; ++ char tag[2][8] = {"ccode=", "regrev="}; ++ ++ /* Find ccode and regrev info */ ++ for (i = 0; i < 2; i++) { ++ sp = strnstr(bus->vars, tag[i], bus->varsz); ++ if (!sp) { ++ DHD_ERROR(("%s: Could not find ccode info from the nvram %s\n", ++ __FUNCTION__, bus->nv_path)); ++ bcmerror = BCME_ERROR; ++ goto err; ++ } ++ sp = strchr(sp, '='); ++ ep = strchr(sp, '\0'); ++ /* We assumed that string length of both ccode and ++ * regrev values should not exceed WLC_CNTRY_BUF_SZ ++ */ ++ if (sp && ep && ((ep - sp) <= WLC_CNTRY_BUF_SZ)) { ++ sp++; ++ while (*sp != '\0') { ++ DHD_INFO(("%s: parse '%s', current sp = '%c'\n", ++ __FUNCTION__, tag[i], *sp)); ++ *sp++ = '0'; ++ } ++ } else { ++ DHD_ERROR(("%s: Invalid parameter format when parsing for %s\n", ++ __FUNCTION__, tag[i])); ++ bcmerror = BCME_ERROR; ++ goto err; ++ } ++ } ++ } ++#endif /* DHD_USE_SINGLE_NVRAM_FILE */ ++ ++ ++err: ++ return bcmerror; ++} ++ ++/* loop through the capability list and see if the pcie capabilty exists */ ++uint8 ++dhdpcie_find_pci_capability(osl_t *osh, uint8 req_cap_id) ++{ ++ uint8 cap_id; ++ uint8 cap_ptr = 0; ++ uint8 byte_val; ++ ++ /* check for Header type 0 */ ++ byte_val = read_pci_cfg_byte(PCI_CFG_HDR); ++ if ((byte_val & 0x7f) != PCI_HEADER_NORMAL) { ++ DHD_ERROR(("%s : PCI config header not normal.\n", __FUNCTION__)); ++ goto end; ++ } ++ ++ /* check if the capability pointer field exists */ ++ byte_val = read_pci_cfg_byte(PCI_CFG_STAT); ++ if (!(byte_val & PCI_CAPPTR_PRESENT)) { ++ DHD_ERROR(("%s : PCI CAP pointer not present.\n", __FUNCTION__)); ++ goto end; ++ } ++ ++ cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR); ++ /* check if the capability pointer is 0x00 */ ++ if (cap_ptr == 0x00) { ++ DHD_ERROR(("%s : PCI CAP pointer is 0x00.\n", __FUNCTION__)); ++ goto end; ++ } ++ ++ /* loop thr'u the capability list and see if the pcie capabilty exists */ ++ ++ cap_id = read_pci_cfg_byte(cap_ptr); ++ ++ while (cap_id != req_cap_id) { ++ cap_ptr = read_pci_cfg_byte((cap_ptr + 1)); ++ if (cap_ptr == 0x00) break; ++ cap_id = read_pci_cfg_byte(cap_ptr); ++ } ++ ++end: ++ return cap_ptr; ++} ++ ++void ++dhdpcie_pme_active(osl_t *osh, bool enable) ++{ ++ uint8 cap_ptr; ++ uint32 pme_csr; ++ ++ cap_ptr = dhdpcie_find_pci_capability(osh, PCI_CAP_POWERMGMTCAP_ID); ++ ++ if (!cap_ptr) { ++ DHD_ERROR(("%s : Power Management Capability not present\n", __FUNCTION__)); ++ return; ++ } ++ ++ pme_csr = OSL_PCI_READ_CONFIG(osh, cap_ptr + PME_CSR_OFFSET, sizeof(uint32)); ++ DHD_ERROR(("%s : pme_sts_ctrl 0x%x\n", __FUNCTION__, pme_csr)); ++ ++ pme_csr |= PME_CSR_PME_STAT; ++ if (enable) { ++ pme_csr |= PME_CSR_PME_EN; ++ } else { ++ pme_csr &= ~PME_CSR_PME_EN; ++ } ++ ++ OSL_PCI_WRITE_CONFIG(osh, cap_ptr + PME_CSR_OFFSET, sizeof(uint32), pme_csr); ++} ++ ++bool ++dhdpcie_pme_cap(osl_t *osh) ++{ ++ uint8 cap_ptr; ++ uint32 pme_cap; ++ ++ cap_ptr = dhdpcie_find_pci_capability(osh, PCI_CAP_POWERMGMTCAP_ID); ++ ++ if (!cap_ptr) { ++ DHD_ERROR(("%s : Power Management Capability not present\n", __FUNCTION__)); ++ return FALSE; ++ } ++ ++ pme_cap = OSL_PCI_READ_CONFIG(osh, cap_ptr, sizeof(uint32)); ++ ++ DHD_ERROR(("%s : pme_cap 0x%x\n", __FUNCTION__, pme_cap)); ++ ++ return ((pme_cap & PME_CAP_PM_STATES) != 0); ++} ++ ++uint32 ++dhdpcie_lcreg(osl_t *osh, uint32 mask, uint32 val) ++{ ++ ++ uint8 pcie_cap; ++ uint8 lcreg_offset; /* PCIE capability LCreg offset in the config space */ ++ uint32 reg_val; ++ ++ ++ pcie_cap = dhdpcie_find_pci_capability(osh, PCI_CAP_PCIECAP_ID); ++ ++ if (!pcie_cap) { ++ DHD_ERROR(("%s : PCIe Capability not present\n", __FUNCTION__)); ++ return 0; ++ } ++ ++ lcreg_offset = pcie_cap + PCIE_CAP_LINKCTRL_OFFSET; ++ ++ /* set operation */ ++ if (mask) { ++ /* read */ ++ reg_val = OSL_PCI_READ_CONFIG(osh, lcreg_offset, sizeof(uint32)); ++ ++ /* modify */ ++ reg_val &= ~mask; ++ reg_val |= (mask & val); ++ ++ /* write */ ++ OSL_PCI_WRITE_CONFIG(osh, lcreg_offset, sizeof(uint32), reg_val); ++ } ++ return OSL_PCI_READ_CONFIG(osh, lcreg_offset, sizeof(uint32)); ++} ++ ++ ++ ++uint8 ++dhdpcie_clkreq(osl_t *osh, uint32 mask, uint32 val) ++{ ++ uint8 pcie_cap; ++ uint32 reg_val; ++ uint8 lcreg_offset; /* PCIE capability LCreg offset in the config space */ ++ ++ pcie_cap = dhdpcie_find_pci_capability(osh, PCI_CAP_PCIECAP_ID); ++ ++ if (!pcie_cap) { ++ DHD_ERROR(("%s : PCIe Capability not present\n", __FUNCTION__)); ++ return 0; ++ } ++ ++ lcreg_offset = pcie_cap + PCIE_CAP_LINKCTRL_OFFSET; ++ ++ reg_val = OSL_PCI_READ_CONFIG(osh, lcreg_offset, sizeof(uint32)); ++ /* set operation */ ++ if (mask) { ++ if (val) ++ reg_val |= PCIE_CLKREQ_ENAB; ++ else ++ reg_val &= ~PCIE_CLKREQ_ENAB; ++ OSL_PCI_WRITE_CONFIG(osh, lcreg_offset, sizeof(uint32), reg_val); ++ reg_val = OSL_PCI_READ_CONFIG(osh, lcreg_offset, sizeof(uint32)); ++ } ++ if (reg_val & PCIE_CLKREQ_ENAB) ++ return 1; ++ else ++ return 0; ++} ++ ++void dhd_dump_intr_registers(dhd_pub_t *dhd, struct bcmstrbuf *strbuf) ++{ ++ uint32 intstatus = 0; ++ uint32 intmask = 0; ++ uint32 mbintstatus = 0; ++ uint32 d2h_mb_data = 0; ++ ++ intstatus = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); ++ intmask = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCIMailBoxMask, 0, 0); ++ mbintstatus = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCID2H_MailBox, 0, 0); ++ dhd_bus_cmn_readshared(dhd->bus, &d2h_mb_data, D2H_MB_DATA, 0); ++ ++ bcm_bprintf(strbuf, "intstatus=0x%x intmask=0x%x mbintstatus=0x%x\n", ++ intstatus, intmask, mbintstatus); ++ bcm_bprintf(strbuf, "d2h_mb_data=0x%x def_intmask=0x%x\n", ++ d2h_mb_data, dhd->bus->def_intmask); ++ bcm_bprintf(strbuf, "\n ------- DUMPING INTR enable/disable counters-------\n"); ++ bcm_bprintf(strbuf, "resume_intr_enable_count=%lu dpc_intr_enable_count=%lu\n" ++ "isr_intr_disable_count=%lu suspend_intr_disable_count=%lu\n" ++ "dpc_return_busdown_count=%lu\n", ++ dhd->bus->resume_intr_enable_count, dhd->bus->dpc_intr_enable_count, ++ dhd->bus->isr_intr_disable_count, dhd->bus->suspend_intr_disable_count, ++ dhd->bus->dpc_return_busdown_count); ++} ++ ++/** Add bus dump output to a buffer */ ++void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ uint16 flowid; ++ int ix = 0; ++ flow_ring_node_t *flow_ring_node; ++ flow_info_t *flow_info; ++ char eabuf[ETHER_ADDR_STR_LEN]; ++ ++ if (dhdp->busstate != DHD_BUS_DATA) ++ return; ++ ++#ifdef DHD_WAKE_STATUS ++ bcm_bprintf(strbuf, "wake %u rxwake %u readctrlwake %u\n", ++ bcmpcie_get_total_wake(dhdp->bus), dhdp->bus->wake_counts.rxwake, ++ dhdp->bus->wake_counts.rcwake); ++#ifdef DHD_WAKE_RX_STATUS ++ bcm_bprintf(strbuf, " unicast %u muticast %u broadcast %u arp %u\n", ++ dhdp->bus->wake_counts.rx_ucast, dhdp->bus->wake_counts.rx_mcast, ++ dhdp->bus->wake_counts.rx_bcast, dhdp->bus->wake_counts.rx_arp); ++ bcm_bprintf(strbuf, " multi4 %u multi6 %u icmp6 %u multiother %u\n", ++ dhdp->bus->wake_counts.rx_multi_ipv4, dhdp->bus->wake_counts.rx_multi_ipv6, ++ dhdp->bus->wake_counts.rx_icmpv6, dhdp->bus->wake_counts.rx_multi_other); ++ bcm_bprintf(strbuf, " icmp6_ra %u, icmp6_na %u, icmp6_ns %u\n", ++ dhdp->bus->wake_counts.rx_icmpv6_ra, dhdp->bus->wake_counts.rx_icmpv6_na, ++ dhdp->bus->wake_counts.rx_icmpv6_ns); ++#endif /* DHD_WAKE_RX_STATUS */ ++#ifdef DHD_WAKE_EVENT_STATUS ++ for (flowid = 0; flowid < WLC_E_LAST; flowid++) ++ if (dhdp->bus->wake_counts.rc_event[flowid] != 0) ++ bcm_bprintf(strbuf, " %s = %u\n", bcmevent_get_name(flowid), ++ dhdp->bus->wake_counts.rc_event[flowid]); ++ bcm_bprintf(strbuf, "\n"); ++#endif /* DHD_WAKE_EVENT_STATUS */ ++#endif /* DHD_WAKE_STATUS */ ++ ++ dhd_prot_print_info(dhdp, strbuf); ++ dhd_dump_intr_registers(dhdp, strbuf); ++ bcm_bprintf(strbuf, "h2d_mb_data_ptr_addr 0x%x, d2h_mb_data_ptr_addr 0x%x\n", ++ dhdp->bus->h2d_mb_data_ptr_addr, dhdp->bus->d2h_mb_data_ptr_addr); ++ bcm_bprintf(strbuf, "dhd cumm_ctr %d\n", DHD_CUMM_CTR_READ(&dhdp->cumm_ctr)); ++ bcm_bprintf(strbuf, ++ "%s %4s %2s %4s %17s %4s %4s %6s %10s %4s %4s ", ++ "Num:", "Flow", "If", "Prio", ":Dest_MacAddress:", "Qlen", "CLen", "L2CLen", ++ "Overflows", "RD", "WR"); ++ bcm_bprintf(strbuf, "%5s %6s %5s \n", "Acked", "tossed", "noack"); ++ ++ for (flowid = 0; flowid < dhdp->num_flow_rings; flowid++) { ++ flow_ring_node = DHD_FLOW_RING(dhdp, flowid); ++ if (!flow_ring_node->active) ++ continue; ++ ++ flow_info = &flow_ring_node->flow_info; ++ bcm_bprintf(strbuf, ++ "%3d. %4d %2d %4d %17s %4d %4d %6d %10u ", ix++, ++ flow_ring_node->flowid, flow_info->ifindex, flow_info->tid, ++ bcm_ether_ntoa((struct ether_addr *)&flow_info->da, eabuf), ++ DHD_FLOW_QUEUE_LEN(&flow_ring_node->queue), ++ DHD_CUMM_CTR_READ(DHD_FLOW_QUEUE_CLEN_PTR(&flow_ring_node->queue)), ++ DHD_CUMM_CTR_READ(DHD_FLOW_QUEUE_L2CLEN_PTR(&flow_ring_node->queue)), ++ DHD_FLOW_QUEUE_FAILURES(&flow_ring_node->queue)); ++ dhd_prot_print_flow_ring(dhdp, flow_ring_node->prot_info, strbuf, ++ "%4d %4d "); ++ bcm_bprintf(strbuf, ++ "%5s %6s %5s\n", "NA", "NA", "NA"); ++ } ++ bcm_bprintf(strbuf, "D3 inform cnt %d\n", dhdp->bus->d3_inform_cnt); ++ bcm_bprintf(strbuf, "D0 inform cnt %d\n", dhdp->bus->d0_inform_cnt); ++ bcm_bprintf(strbuf, "D0 inform in use cnt %d\n", dhdp->bus->d0_inform_in_use_cnt); ++ if (dhdp->d2h_hostrdy_supported) { ++ bcm_bprintf(strbuf, "hostready count:%d\n", dhdp->bus->hostready_count); ++ } ++#ifdef PCIE_INB_DW ++ /* Inband device wake counters */ ++ if (INBAND_DW_ENAB(dhdp->bus)) { ++ bcm_bprintf(strbuf, "Inband device_wake assert count: %d\n", ++ dhdp->bus->inband_dw_assert_cnt); ++ bcm_bprintf(strbuf, "Inband device_wake deassert count: %d\n", ++ dhdp->bus->inband_dw_deassert_cnt); ++ bcm_bprintf(strbuf, "Inband DS-EXIT count: %d\n", ++ dhdp->bus->inband_ds_exit_host_cnt); ++ bcm_bprintf(strbuf, "Inband DS-EXIT count: %d\n", ++ dhdp->bus->inband_ds_exit_device_cnt); ++ bcm_bprintf(strbuf, "Inband DS-EXIT Timeout count: %d\n", ++ dhdp->bus->inband_ds_exit_to_cnt); ++ bcm_bprintf(strbuf, "Inband HOST_SLEEP-EXIT Timeout count: %d\n", ++ dhdp->bus->inband_host_sleep_exit_to_cnt); ++ } ++#endif /* PCIE_INB_DW */ ++} ++ ++/** ++ * Brings transmit packets on all flow rings closer to the dongle, by moving (a subset) from their ++ * flow queue to their flow ring. ++ */ ++static void ++dhd_update_txflowrings(dhd_pub_t *dhd) ++{ ++ unsigned long flags; ++ dll_t *item, *next; ++ flow_ring_node_t *flow_ring_node; ++ struct dhd_bus *bus = dhd->bus; ++ ++ /* Hold flowring_list_lock to ensure no race condition while accessing the List */ ++ DHD_FLOWRING_LIST_LOCK(bus->dhd->flowring_list_lock, flags); ++ for (item = dll_head_p(&bus->flowring_active_list); ++ (!dhd_is_device_removed(dhd) && !dll_end(&bus->flowring_active_list, item)); ++ item = next) { ++ if (dhd->hang_was_sent) { ++ break; ++ } ++ ++ next = dll_next_p(item); ++ flow_ring_node = dhd_constlist_to_flowring(item); ++ ++ /* Ensure that flow_ring_node in the list is Not Null */ ++ ASSERT(flow_ring_node != NULL); ++ ++ /* Ensure that the flowring node has valid contents */ ++ ASSERT(flow_ring_node->prot_info != NULL); ++ ++ dhd_prot_update_txflowring(dhd, flow_ring_node->flowid, flow_ring_node->prot_info); ++ } ++ DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, flags); ++} ++ ++/** Mailbox ringbell Function */ ++static void ++dhd_bus_gen_devmb_intr(struct dhd_bus *bus) ++{ ++ if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || ++ (bus->sih->buscorerev == 4)) { ++ DHD_ERROR(("%s: mailbox communication not supported\n", __FUNCTION__)); ++ return; ++ } ++ if (bus->db1_for_mb) { ++ /* this is a pcie core register, not the config register */ ++ DHD_INFO(("%s: writing a mail box interrupt to the device, through doorbell 1\n", __FUNCTION__)); ++ si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_DB1, ~0, 0x12345678); ++ } else { ++ DHD_INFO(("%s: writing a mail box interrupt to the device, through config space\n", __FUNCTION__)); ++ dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0)); ++ dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0)); ++ } ++} ++ ++/* Upon receiving a mailbox interrupt, ++ * if H2D_FW_TRAP bit is set in mailbox location ++ * device traps ++ */ ++static void ++dhdpcie_fw_trap(dhd_bus_t *bus) ++{ ++ /* Send the mailbox data and generate mailbox intr. */ ++ dhdpcie_send_mb_data(bus, H2D_FW_TRAP); ++} ++ ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++void ++dhd_bus_doorbell_timeout_reset(struct dhd_bus *bus) ++{ ++ if (dhd_doorbell_timeout) ++ dhd_timeout_start(&bus->doorbell_timer, ++ (dhd_doorbell_timeout * 1000) / dhd_watchdog_ms); ++ else if (!(bus->dhd->busstate == DHD_BUS_SUSPEND)) { ++ dhd_bus_set_device_wake(bus, FALSE); ++ } ++} ++#endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ ++ ++#ifdef PCIE_INB_DW ++ ++void ++dhd_bus_inb_ack_pending_ds_req(dhd_bus_t *bus) ++{ ++ /* The DHD_BUS_INB_DW_LOCK must be held before ++ * calling this function !! ++ */ ++ if ((dhdpcie_bus_get_pcie_inband_dw_state(bus) == ++ DW_DEVICE_DS_DEV_SLEEP_PEND) && ++ (bus->host_active_cnt == 0)) { ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, DW_DEVICE_DS_DEV_SLEEP); ++ dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); ++ } ++} ++ ++int ++dhd_bus_inb_set_device_wake(struct dhd_bus *bus, bool val) ++{ ++ int timeleft; ++ unsigned long flags; ++ int ret; ++ ++ if (!INBAND_DW_ENAB(bus)) { ++ return BCME_ERROR; ++ } ++ ++ if (val) { ++ DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); ++ ++ /* ++ * Reset the Door Bell Timeout value. So that the Watchdog ++ * doesn't try to Deassert Device Wake, while we are in ++ * the process of still Asserting the same. ++ */ ++ if (dhd_doorbell_timeout) { ++ dhd_timeout_start(&bus->doorbell_timer, ++ (dhd_doorbell_timeout * 1000) / dhd_watchdog_ms); ++ } ++ ++ if (dhdpcie_bus_get_pcie_inband_dw_state(bus) == ++ DW_DEVICE_DS_DEV_SLEEP) { ++ /* Clear wait_for_ds_exit */ ++ bus->wait_for_ds_exit = 0; ++ ret = dhdpcie_send_mb_data(bus, H2DMB_DS_DEVICE_WAKE_ASSERT); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("Failed: assert Inband device_wake\n")); ++ bus->wait_for_ds_exit = 1; ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ ret = BCME_ERROR; ++ goto exit; ++ } ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, ++ DW_DEVICE_DS_DISABLED_WAIT); ++ bus->inband_dw_assert_cnt++; ++ } else { ++ DHD_INFO(("Not in DS SLEEP state \n")); ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ ret = BCME_OK; ++ goto exit; ++ } ++ ++ /* ++ * Since we are going to wait/sleep .. release the lock. ++ * The Device Wake sanity is still valid, because ++ * a) If there is another context that comes in and tries ++ * to assert DS again and if it gets the lock, since ++ * ds_state would be now != DW_DEVICE_DS_DEV_SLEEP the ++ * context would return saying Not in DS Sleep. ++ * b) If ther is another context that comes in and tries ++ * to de-assert DS and gets the lock, ++ * since the ds_state is != DW_DEVICE_DS_DEV_WAKE ++ * that context would return too. This can not happen ++ * since the watchdog is the only context that can ++ * De-Assert Device Wake and as the first step of ++ * Asserting the Device Wake, we have pushed out the ++ * Door Bell Timeout. ++ * ++ */ ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ ++ if (!CAN_SLEEP()) { ++ /* Called from context that cannot sleep */ ++ OSL_DELAY(1000); ++ bus->wait_for_ds_exit = 1; ++ } else { ++ /* Wait for DS EXIT for DS_EXIT_TIMEOUT seconds */ ++ timeleft = dhd_os_ds_exit_wait(bus->dhd, &bus->wait_for_ds_exit); ++ if (!bus->wait_for_ds_exit && timeleft == 0) { ++ DHD_ERROR(("DS-EXIT timeout\n")); ++ bus->inband_ds_exit_to_cnt++; ++ bus->ds_exit_timeout = 0; ++ ret = BCME_ERROR; ++ goto exit; ++ } ++ } ++ ++ DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, ++ DW_DEVICE_DS_DEV_WAKE); ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ ++ ret = BCME_OK; ++ } else { ++ DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); ++ if ((dhdpcie_bus_get_pcie_inband_dw_state(bus) == ++ DW_DEVICE_DS_DEV_WAKE)) { ++ ret = dhdpcie_send_mb_data(bus, H2DMB_DS_DEVICE_WAKE_DEASSERT); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("Failed: deassert Inband device_wake\n")); ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ goto exit; ++ } ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, ++ DW_DEVICE_DS_ACTIVE); ++ bus->inband_dw_deassert_cnt++; ++ } else if ((dhdpcie_bus_get_pcie_inband_dw_state(bus) == ++ DW_DEVICE_DS_DEV_SLEEP_PEND) && ++ (bus->host_active_cnt == 0)) { ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, DW_DEVICE_DS_DEV_SLEEP); ++ dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); ++ } ++ ++ ret = BCME_OK; ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ } ++ ++exit: ++ return ret; ++} ++#endif /* PCIE_INB_DW */ ++ ++ ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++int ++dhd_bus_set_device_wake(struct dhd_bus *bus, bool val) ++{ ++ if (bus->ds_enabled) { ++#ifdef PCIE_INB_DW ++ if (INBAND_DW_ENAB(bus)) { ++ return dhd_bus_inb_set_device_wake(bus, val); ++ } ++#endif /* PCIE_INB_DW */ ++#ifdef PCIE_OOB ++ if (OOB_DW_ENAB(bus)) { ++ return dhd_os_oob_set_device_wake(bus, val); ++ } ++#endif /* PCIE_OOB */ ++ } ++ return BCME_OK; ++} ++#endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ ++ ++/** mailbox doorbell ring function */ ++void ++dhd_bus_ringbell(struct dhd_bus *bus, uint32 value) ++{ ++ /* Skip after sending D3_INFORM */ ++ if (bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) { ++ DHD_ERROR(("%s: trying to ring the doorbell when in suspend state :" ++ "busstate=%d, d3_suspend_pending=%d\n", ++ __FUNCTION__, bus->dhd->busstate, bus->d3_suspend_pending)); ++ return; ++ } ++ if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || ++ (bus->sih->buscorerev == 4)) { ++ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, PCIE_INTB, PCIE_INTB); ++ } else { ++ /* this is a pcie core register, not the config regsiter */ ++ DHD_INFO(("%s: writing a door bell to the device\n", __FUNCTION__)); ++ if (IDMA_ACTIVE(bus->dhd)) { ++ si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_MailBox_2, ++ ~0, value); ++ } else { ++ si_corereg(bus->sih, bus->sih->buscoreidx, ++ PCIH2D_MailBox, ~0, 0x12345678); ++ } ++ } ++} ++ ++/** mailbox doorbell ring function for IDMA/IFRM using dma channel2 */ ++void ++dhd_bus_ringbell_2(struct dhd_bus *bus, uint32 value, bool devwake) ++{ ++ /* this is a pcie core register, not the config regsiter */ ++ /* Skip after sending D3_INFORM */ ++ if (bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) { ++ DHD_ERROR(("%s: trying to ring the doorbell when in suspend state :" ++ "busstate=%d, d3_suspend_pending=%d\n", ++ __FUNCTION__, bus->dhd->busstate, bus->d3_suspend_pending)); ++ return; ++ } ++ DHD_INFO(("writing a door bell 2 to the device\n")); ++ si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_MailBox_2, ++ ~0, value); ++} ++ ++void ++dhdpcie_bus_ringbell_fast(struct dhd_bus *bus, uint32 value) ++{ ++ /* Skip after sending D3_INFORM */ ++ if (bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) { ++ DHD_ERROR(("%s: trying to ring the doorbell when in suspend state :" ++ "busstate=%d, d3_suspend_pending=%d\n", ++ __FUNCTION__, bus->dhd->busstate, bus->d3_suspend_pending)); ++ return; ++ } ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++ if (OOB_DW_ENAB(bus)) { ++ dhd_bus_set_device_wake(bus, TRUE); ++ } ++ dhd_bus_doorbell_timeout_reset(bus); ++#endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ ++ W_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr, value); ++} ++ ++void ++dhdpcie_bus_ringbell_2_fast(struct dhd_bus *bus, uint32 value, bool devwake) ++{ ++ /* Skip after sending D3_INFORM */ ++ if (bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) { ++ DHD_ERROR(("%s: trying to ring the doorbell when in suspend state :" ++ "busstate=%d, d3_suspend_pending=%d\n", ++ __FUNCTION__, bus->dhd->busstate, bus->d3_suspend_pending)); ++ return; ++ } ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++ if (devwake) { ++ if (OOB_DW_ENAB(bus)) { ++ dhd_bus_set_device_wake(bus, TRUE); ++ } ++ } ++ dhd_bus_doorbell_timeout_reset(bus); ++#endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ ++ ++ W_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_2_addr, value); ++} ++ ++static void ++dhd_bus_ringbell_oldpcie(struct dhd_bus *bus, uint32 value) ++{ ++ uint32 w; ++ /* Skip after sending D3_INFORM */ ++ if (bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) { ++ DHD_ERROR(("%s: trying to ring the doorbell when in suspend state :" ++ "busstate=%d, d3_suspend_pending=%d\n", ++ __FUNCTION__, bus->dhd->busstate, bus->d3_suspend_pending)); ++ return; ++ } ++ w = (R_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr) & ~PCIE_INTB) | PCIE_INTB; ++ W_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr, w); ++} ++ ++dhd_mb_ring_t ++dhd_bus_get_mbintr_fn(struct dhd_bus *bus) ++{ ++ if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || ++ (bus->sih->buscorerev == 4)) { ++ bus->pcie_mb_intr_addr = si_corereg_addr(bus->sih, bus->sih->buscoreidx, ++ PCIMailBoxInt); ++ if (bus->pcie_mb_intr_addr) { ++ bus->pcie_mb_intr_osh = si_osh(bus->sih); ++ return dhd_bus_ringbell_oldpcie; ++ } ++ } else { ++ bus->pcie_mb_intr_addr = si_corereg_addr(bus->sih, bus->sih->buscoreidx, ++ PCIH2D_MailBox); ++ if (bus->pcie_mb_intr_addr) { ++ bus->pcie_mb_intr_osh = si_osh(bus->sih); ++ return dhdpcie_bus_ringbell_fast; ++ } ++ } ++ return dhd_bus_ringbell; ++} ++ ++dhd_mb_ring_2_t ++dhd_bus_get_mbintr_2_fn(struct dhd_bus *bus) ++{ ++ bus->pcie_mb_intr_2_addr = si_corereg_addr(bus->sih, bus->sih->buscoreidx, ++ PCIH2D_MailBox_2); ++ if (bus->pcie_mb_intr_2_addr) { ++ bus->pcie_mb_intr_osh = si_osh(bus->sih); ++ return dhdpcie_bus_ringbell_2_fast; ++ } ++ return dhd_bus_ringbell_2; ++} ++ ++bool BCMFASTPATH ++dhd_bus_dpc(struct dhd_bus *bus) ++{ ++ bool resched = FALSE; /* Flag indicating resched wanted */ ++ unsigned long flags; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ /* Check for only DHD_BUS_DOWN and not for DHD_BUS_DOWN_IN_PROGRESS ++ * to avoid IOCTL Resumed On timeout when ioctl is waiting for response ++ * and rmmod is fired in parallel, which will make DHD_BUS_DOWN_IN_PROGRESS ++ * and if we return from here, then IOCTL response will never be handled ++ */ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); ++ bus->intstatus = 0; ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ bus->dpc_return_busdown_count++; ++ return 0; ++ } ++#ifdef DHD_PCIE_RUNTIMEPM ++ bus->idlecount = 0; ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ DHD_BUS_BUSY_SET_IN_DPC(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++#ifdef DHD_READ_INTSTATUS_IN_DPC ++ if (bus->ipend) { ++ bus->ipend = FALSE; ++ bus->intstatus = dhdpcie_bus_intstatus(bus); ++ /* Check if the interrupt is ours or not */ ++ if (bus->intstatus == 0) { ++ goto INTR_ON; ++ } ++ bus->intrcount++; ++ } ++#endif /* DHD_READ_INTSTATUS_IN_DPC */ ++ ++ resched = dhdpcie_bus_process_mailbox_intr(bus, bus->intstatus); ++ if (!resched) { ++ bus->intstatus = 0; ++#ifdef DHD_READ_INTSTATUS_IN_DPC ++INTR_ON: ++#endif /* DHD_READ_INTSTATUS_IN_DPC */ ++ bus->dpc_intr_enable_count++; ++ dhdpcie_bus_intr_enable(bus); /* Enable back interrupt using Intmask!! */ ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_CLEAR_IN_DPC(bus->dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ return resched; ++ ++} ++ ++ ++int ++dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data) ++{ ++ uint32 cur_h2d_mb_data = 0; ++ unsigned long flags; ++ ++ DHD_INFO_HW4(("%s: H2D_MB_DATA: 0x%08X\n", __FUNCTION__, h2d_mb_data)); ++ ++ if (bus->is_linkdown) { ++ DHD_ERROR(("%s: PCIe link was down\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ ++ if (bus->api.fw_rev >= PCIE_SHARED_VERSION_6 && !bus->use_mailbox) { ++ DHD_INFO(("API rev is 6, sending mb data as H2D Ctrl message to dongle, 0x%04x\n", ++ h2d_mb_data)); ++ /* Prevent asserting device_wake during doorbell ring for mb data to avoid loop. */ ++#ifdef PCIE_OOB ++ bus->oob_enabled = FALSE; ++#endif /* PCIE_OOB */ ++ if (dhd_prot_h2d_mbdata_send_ctrlmsg(bus->dhd, h2d_mb_data)) { ++ DHD_ERROR(("failure sending the H2D Mailbox message to firmware\n")); ++ goto fail; ++ } ++#ifdef PCIE_OOB ++ bus->oob_enabled = TRUE; ++#endif /* PCIE_OOB */ ++ goto done; ++ } ++ ++ dhd_bus_cmn_readshared(bus, &cur_h2d_mb_data, H2D_MB_DATA, 0); ++ ++ if (cur_h2d_mb_data != 0) { ++ uint32 i = 0; ++ DHD_INFO(("%s: GRRRRRRR: MB transaction is already pending 0x%04x\n", __FUNCTION__, cur_h2d_mb_data)); ++ while ((i++ < 100) && cur_h2d_mb_data) { ++ OSL_DELAY(10); ++ dhd_bus_cmn_readshared(bus, &cur_h2d_mb_data, H2D_MB_DATA, 0); ++ } ++ if (i >= 100) { ++ DHD_ERROR(("%s : waited 1ms for the dngl " ++ "to ack the previous mb transaction\n", __FUNCTION__)); ++ DHD_ERROR(("%s : MB transaction is still pending 0x%04x\n", ++ __FUNCTION__, cur_h2d_mb_data)); ++ } ++ } ++ ++ dhd_bus_cmn_writeshared(bus, &h2d_mb_data, sizeof(uint32), H2D_MB_DATA, 0); ++ dhd_bus_gen_devmb_intr(bus); ++ ++done: ++ if (h2d_mb_data == H2D_HOST_D3_INFORM) { ++ DHD_INFO_HW4(("%s: send H2D_HOST_D3_INFORM to dongle\n", __FUNCTION__)); ++ /* Mark D3_INFORM in the atomic context to ++ * skip ringing H2D DB after D3_INFORM ++ */ ++ bus->d3_suspend_pending = TRUE; ++ bus->d3_inform_cnt++; ++ } ++ if (h2d_mb_data == H2D_HOST_D0_INFORM_IN_USE) { ++ DHD_INFO_HW4(("%s: send H2D_HOST_D0_INFORM_IN_USE to dongle\n", __FUNCTION__)); ++ bus->d0_inform_in_use_cnt++; ++ } ++ if (h2d_mb_data == H2D_HOST_D0_INFORM) { ++ DHD_INFO_HW4(("%s: send H2D_HOST_D0_INFORM to dongle\n", __FUNCTION__)); ++ bus->d0_inform_cnt++; ++ } ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ return BCME_OK; ++ ++fail: ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ return BCME_ERROR; ++} ++ ++void ++dhd_bus_handle_mb_data(dhd_bus_t *bus, uint32 d2h_mb_data) ++{ ++#ifdef PCIE_INB_DW ++ unsigned long flags = 0; ++#endif ++ DHD_INFO(("D2H_MB_DATA: 0x%04x\n", d2h_mb_data)); ++ ++ if (d2h_mb_data & D2H_DEV_FWHALT) { ++ DHD_ERROR(("FW trap has happened\n")); ++ dhdpcie_checkdied(bus, NULL, 0); ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++#ifdef CONFIG_ARCH_MSM ++ bus->no_cfg_restore = 1; ++#endif /* CONFIG_ARCH_MSM */ ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ dhd_os_check_hang(bus->dhd, 0, -EREMOTEIO); ++ return; ++ } ++ if (d2h_mb_data & D2H_DEV_DS_ENTER_REQ) { ++ if ((bus->dhd->busstate == DHD_BUS_SUSPEND || bus->d3_suspend_pending) && ++ bus->wait_for_d3_ack) { ++ DHD_ERROR(("DS-ENTRY AFTER D3-ACK!!!!! QUITING\n")); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ return; ++ } ++ /* what should we do */ ++ DHD_INFO(("D2H_MB_DATA: DEEP SLEEP REQ\n")); ++#ifdef PCIE_INB_DW ++ if (INBAND_DW_ENAB(bus)) { ++ DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); ++ if (dhdpcie_bus_get_pcie_inband_dw_state(bus) == DW_DEVICE_DS_ACTIVE) { ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, ++ DW_DEVICE_DS_DEV_SLEEP_PEND); ++ if (bus->host_active_cnt == 0) { ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, ++ DW_DEVICE_DS_DEV_SLEEP); ++ dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); ++ } ++ } ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ dhd_os_ds_enter_wake(bus->dhd); ++ } else ++#endif /* PCIE_INB_DW */ ++ { ++ dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); ++ } ++ if (IDMA_DS_ENAB(bus->dhd)) { ++ bus->dongle_in_ds = TRUE; ++ } ++ DHD_INFO(("D2H_MB_DATA: sent DEEP SLEEP ACK\n")); ++ } ++ if (d2h_mb_data & D2H_DEV_DS_EXIT_NOTE) { ++ /* what should we do */ ++ bus->dongle_in_ds = FALSE; ++ DHD_INFO(("D2H_MB_DATA: DEEP SLEEP EXIT\n")); ++#ifdef PCIE_INB_DW ++ if (INBAND_DW_ENAB(bus)) { ++ bus->inband_ds_exit_device_cnt++; ++ DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); ++ if (dhdpcie_bus_get_pcie_inband_dw_state(bus) == ++ DW_DEVICE_DS_DISABLED_WAIT) { ++ /* wake up only if some one is waiting in ++ * DW_DEVICE_DS_DISABLED_WAIT state ++ * in this case the waiter will change the state ++ * to DW_DEVICE_DS_DEV_WAKE ++ */ ++ bus->wait_for_ds_exit = 1; ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ dhd_os_ds_exit_wake(bus->dhd); ++ } else { ++ DHD_INFO(("D2H_MB_DATA: not in DW_DEVICE_DS_DISABLED_WAIT!\n")); ++ /* ++ * If there is no one waiting, then update the state from here ++ */ ++ bus->wait_for_ds_exit = 1; ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, ++ DW_DEVICE_DS_DEV_WAKE); ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ } ++ } ++#endif /* PCIE_INB_DW */ ++ } ++ if (d2h_mb_data & D2HMB_DS_HOST_SLEEP_EXIT_ACK) { ++ /* what should we do */ ++ DHD_INFO(("D2H_MB_DATA: D0 ACK\n")); ++#ifdef PCIE_INB_DW ++ if (INBAND_DW_ENAB(bus)) { ++ DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); ++ if (dhdpcie_bus_get_pcie_inband_dw_state(bus) == ++ DW_DEVICE_HOST_WAKE_WAIT) { ++ dhdpcie_bus_set_pcie_inband_dw_state(bus, DW_DEVICE_DS_ACTIVE); ++ } ++ DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); ++ } ++#endif /* PCIE_INB_DW */ ++ } ++ if (d2h_mb_data & D2H_DEV_D3_ACK) { ++ /* what should we do */ ++ DHD_INFO_HW4(("D2H_MB_DATA: D3 ACK\n")); ++ if (!bus->wait_for_d3_ack) { ++ /* Disable dongle Interrupts Immediately after D3 */ ++ bus->suspend_intr_disable_count++; ++ dhdpcie_bus_intr_disable(bus); ++#if defined(DHD_HANG_SEND_UP_TEST) ++ if (bus->dhd->req_hang_type == HANG_REASON_D3_ACK_TIMEOUT) { ++ DHD_ERROR(("TEST HANG: Skip to process D3 ACK\n")); ++ } else { ++ bus->wait_for_d3_ack = 1; ++ dhd_os_d3ack_wake(bus->dhd); ++ } ++#else /* DHD_HANG_SEND_UP_TEST */ ++ bus->wait_for_d3_ack = 1; ++ dhd_os_d3ack_wake(bus->dhd); ++#endif /* DHD_HANG_SEND_UP_TEST */ ++ } ++ } ++} ++ ++static void ++dhdpcie_handle_mb_data(dhd_bus_t *bus) ++{ ++ uint32 d2h_mb_data = 0; ++ uint32 zero = 0; ++ dhd_bus_cmn_readshared(bus, &d2h_mb_data, D2H_MB_DATA, 0); ++ if (D2H_DEV_MB_INVALIDATED(d2h_mb_data)) { ++ DHD_ERROR(("%s: Invalid D2H_MB_DATA: 0x%08x\n", ++ __FUNCTION__, d2h_mb_data)); ++ return; ++ } ++ ++ dhd_bus_cmn_writeshared(bus, &zero, sizeof(uint32), D2H_MB_DATA, 0); ++ ++ DHD_INFO_HW4(("%s: D2H_MB_DATA: 0x%04x\n", __FUNCTION__, d2h_mb_data)); ++ if (d2h_mb_data & D2H_DEV_FWHALT) { ++ DHD_ERROR(("FW trap has happened\n")); ++ dhdpcie_checkdied(bus, NULL, 0); ++ /* not ready yet dhd_os_ind_firmware_stall(bus->dhd); */ ++ return; ++ } ++ if (d2h_mb_data & D2H_DEV_DS_ENTER_REQ) { ++ /* what should we do */ ++ DHD_INFO(("%s: D2H_MB_DATA: DEEP SLEEP REQ\n", __FUNCTION__)); ++ dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK); ++ if (IDMA_DS_ENAB(bus->dhd)) { ++ bus->dongle_in_ds = TRUE; ++ } ++ DHD_INFO(("%s: D2H_MB_DATA: sent DEEP SLEEP ACK\n", __FUNCTION__)); ++ } ++ if (d2h_mb_data & D2H_DEV_DS_EXIT_NOTE) { ++ /* what should we do */ ++ DHD_INFO(("%s: D2H_MB_DATA: DEEP SLEEP EXIT\n", __FUNCTION__)); ++ bus->dongle_in_ds = FALSE; ++ } ++ if (d2h_mb_data & D2H_DEV_D3_ACK) { ++ /* what should we do */ ++ DHD_INFO_HW4(("%s: D2H_MB_DATA: D3 ACK\n", __FUNCTION__)); ++ if (!bus->wait_for_d3_ack) { ++#if defined(DHD_HANG_SEND_UP_TEST) ++ if (bus->dhd->req_hang_type == HANG_REASON_D3_ACK_TIMEOUT) { ++ DHD_ERROR(("TEST HANG: Skip to process D3 ACK\n")); ++ } else { ++ bus->wait_for_d3_ack = 1; ++ dhd_os_d3ack_wake(bus->dhd); ++ } ++#else /* DHD_HANG_SEND_UP_TEST */ ++ bus->wait_for_d3_ack = 1; ++ dhd_os_d3ack_wake(bus->dhd); ++#endif /* DHD_HANG_SEND_UP_TEST */ ++ } ++ } ++} ++ ++static void ++dhdpcie_read_handle_mb_data(dhd_bus_t *bus) ++{ ++ uint32 d2h_mb_data = 0; ++ uint32 zero = 0; ++ ++ dhd_bus_cmn_readshared(bus, &d2h_mb_data, D2H_MB_DATA, 0); ++ if (!d2h_mb_data) ++ return; ++ ++ dhd_bus_cmn_writeshared(bus, &zero, sizeof(uint32), D2H_MB_DATA, 0); ++ ++ dhd_bus_handle_mb_data(bus, d2h_mb_data); ++} ++ ++static bool ++dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus) ++{ ++ bool resched = FALSE; ++ ++ if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) || ++ (bus->sih->buscorerev == 4)) { ++ /* Msg stream interrupt */ ++ if (intstatus & I_BIT1) { ++ resched = dhdpci_bus_read_frames(bus); ++ } else if (intstatus & I_BIT0) { ++ /* do nothing for Now */ ++ } ++ } else { ++ if (intstatus & (PCIE_MB_TOPCIE_FN0_0 | PCIE_MB_TOPCIE_FN0_1)) ++ bus->api.handle_mb_data(bus); ++ ++ if (bus->dhd->busstate == DHD_BUS_SUSPEND) { ++ goto exit; ++ } ++ ++ if (intstatus & PCIE_MB_D2H_MB_MASK) { ++ resched = dhdpci_bus_read_frames(bus); ++ } ++ } ++ ++exit: ++ return resched; ++} ++ ++static bool ++dhdpci_bus_read_frames(dhd_bus_t *bus) ++{ ++ bool more = FALSE; ++ ++ /* First check if there a FW trap */ ++ if ((bus->api.fw_rev >= PCIE_SHARED_VERSION_6) && ++ (bus->dhd->dongle_trap_data = dhd_prot_process_trapbuf(bus->dhd))) { ++ dhd_bus_handle_mb_data(bus, D2H_DEV_FWHALT); ++ return FALSE; ++ } ++ ++ /* There may be frames in both ctrl buf and data buf; check ctrl buf first */ ++ DHD_PERIM_LOCK_ALL((bus->dhd->fwder_unit % FWDER_MAX_UNIT)); ++ ++ dhd_prot_process_ctrlbuf(bus->dhd); ++ /* Unlock to give chance for resp to be handled */ ++ DHD_PERIM_UNLOCK_ALL((bus->dhd->fwder_unit % FWDER_MAX_UNIT)); ++ ++ DHD_PERIM_LOCK_ALL((bus->dhd->fwder_unit % FWDER_MAX_UNIT)); ++ /* update the flow ring cpls */ ++ dhd_update_txflowrings(bus->dhd); ++ ++ /* With heavy TX traffic, we could get a lot of TxStatus ++ * so add bound ++ */ ++ more |= dhd_prot_process_msgbuf_txcpl(bus->dhd, dhd_txbound); ++ ++ /* With heavy RX traffic, this routine potentially could spend some time ++ * processing RX frames without RX bound ++ */ ++ more |= dhd_prot_process_msgbuf_rxcpl(bus->dhd, dhd_rxbound); ++ ++ /* Process info ring completion messages */ ++ more |= dhd_prot_process_msgbuf_infocpl(bus->dhd, DHD_INFORING_BOUND); ++ ++#ifdef IDLE_TX_FLOW_MGMT ++ if (bus->enable_idle_flowring_mgmt) { ++ /* Look for idle flow rings */ ++ dhd_bus_check_idle_scan(bus); ++ } ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++ /* don't talk to the dongle if fw is about to be reloaded */ ++ if (bus->dhd->hang_was_sent) { ++ more = FALSE; ++ } ++ DHD_PERIM_UNLOCK_ALL((bus->dhd->fwder_unit % FWDER_MAX_UNIT)); ++ ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ if (bus->read_shm_fail) { ++ /* Read interrupt state once again to confirm linkdown */ ++ int intstatus = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); ++ if (intstatus != (uint32)-1) { ++ DHD_ERROR(("%s: read SHM failed but intstatus is valid\n", __FUNCTION__)); ++#ifdef DHD_FW_COREDUMP ++ if (bus->dhd->memdump_enabled) { ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ bus->dhd->memdump_type = DUMP_TYPE_READ_SHM_FAIL; ++ dhd_bus_mem_dump(bus->dhd); ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++ } ++#endif /* DHD_FW_COREDUMP */ ++ bus->dhd->hang_reason = HANG_REASON_PCIE_LINK_DOWN; ++ dhd_os_send_hang_message(bus->dhd); ++ } else { ++ DHD_ERROR(("%s: Link is Down.\n", __FUNCTION__)); ++#ifdef CONFIG_ARCH_MSM ++ bus->no_cfg_restore = 1; ++#endif /* CONFIG_ARCH_MSM */ ++ bus->is_linkdown = 1; ++ bus->dhd->hang_reason = HANG_REASON_PCIE_LINK_DOWN; ++ dhd_os_send_hang_message(bus->dhd); ++ } ++ } ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ return more; ++} ++ ++bool ++dhdpcie_tcm_valid(dhd_bus_t *bus) ++{ ++ uint32 addr = 0; ++ int rv; ++ uint32 shaddr = 0; ++ pciedev_shared_t sh; ++ ++ shaddr = bus->dongle_ram_base + bus->ramsize - 4; ++ ++ /* Read last word in memory to determine address of pciedev_shared structure */ ++ addr = LTOH32(dhdpcie_bus_rtcm32(bus, shaddr)); ++ ++ if ((addr == 0) || (addr == bus->nvram_csm) || (addr < bus->dongle_ram_base) || ++ (addr > shaddr)) { ++ DHD_ERROR(("%s: address (0x%08x) of pciedev_shared invalid addr\n", ++ __FUNCTION__, addr)); ++ return FALSE; ++ } ++ ++ /* Read hndrte_shared structure */ ++ if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, (uint8 *)&sh, ++ sizeof(pciedev_shared_t))) < 0) { ++ DHD_ERROR(("Failed to read PCIe shared struct with %d\n", rv)); ++ return FALSE; ++ } ++ ++ /* Compare any field in pciedev_shared_t */ ++ if (sh.console_addr != bus->pcie_sh->console_addr) { ++ DHD_ERROR(("Contents of pciedev_shared_t structure are not matching.\n")); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static void ++dhdpcie_update_bus_api_revisions(uint32 firmware_api_version, uint32 host_api_version) ++{ ++ snprintf(bus_api_revision, BUS_API_REV_STR_LEN, "\nBus API revisions:(FW rev%d)(DHD rev%d)", ++ firmware_api_version, host_api_version); ++ return; ++} ++ ++static bool ++dhdpcie_check_firmware_compatible(uint32 firmware_api_version, uint32 host_api_version) ++{ ++ bool retcode = FALSE; ++ ++ DHD_INFO(("firmware api revision %d, host api revision %d\n", ++ firmware_api_version, host_api_version)); ++ ++ switch (firmware_api_version) { ++ case PCIE_SHARED_VERSION_7: ++ case PCIE_SHARED_VERSION_6: ++ case PCIE_SHARED_VERSION_5: ++ retcode = TRUE; ++ break; ++ default: ++ if (firmware_api_version <= host_api_version) ++ retcode = TRUE; ++ } ++ return retcode; ++} ++ ++static int ++dhdpcie_readshared(dhd_bus_t *bus) ++{ ++ uint32 addr = 0; ++ int rv, dma_indx_wr_buf, dma_indx_rd_buf; ++ uint32 shaddr = 0; ++ pciedev_shared_t *sh = bus->pcie_sh; ++ dhd_timeout_t tmo; ++ ++ shaddr = bus->dongle_ram_base + bus->ramsize - 4; ++ /* start a timer for 5 seconds */ ++ dhd_timeout_start(&tmo, MAX_READ_TIMEOUT); ++ ++ while (((addr == 0) || (addr == bus->nvram_csm)) && !dhd_timeout_expired(&tmo)) { ++ /* Read last word in memory to determine address of pciedev_shared structure */ ++ addr = LTOH32(dhdpcie_bus_rtcm32(bus, shaddr)); ++ } ++ ++ if ((addr == 0) || (addr == bus->nvram_csm) || (addr < bus->dongle_ram_base) || ++ (addr > shaddr)) { ++ DHD_ERROR(("%s: address (0x%08x) of pciedev_shared invalid\n", ++ __FUNCTION__, addr)); ++ DHD_ERROR(("%s: Waited %u usec, dongle is not ready\n", __FUNCTION__, tmo.elapsed)); ++ return BCME_ERROR; ++ } else { ++ bus->shared_addr = (ulong)addr; ++ DHD_ERROR(("%s: PCIe shared addr (0x%08x) read took %u usec " ++ "before dongle is ready\n", __FUNCTION__, addr, tmo.elapsed)); ++ } ++ ++ /* Read hndrte_shared structure */ ++ if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, (uint8 *)sh, ++ sizeof(pciedev_shared_t))) < 0) { ++ DHD_ERROR(("%s: Failed to read PCIe shared struct with %d\n", __FUNCTION__, rv)); ++ return rv; ++ } ++ ++ /* Endianness */ ++ sh->flags = ltoh32(sh->flags); ++ sh->trap_addr = ltoh32(sh->trap_addr); ++ sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); ++ sh->assert_file_addr = ltoh32(sh->assert_file_addr); ++ sh->assert_line = ltoh32(sh->assert_line); ++ sh->console_addr = ltoh32(sh->console_addr); ++ sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); ++ sh->dma_rxoffset = ltoh32(sh->dma_rxoffset); ++ sh->rings_info_ptr = ltoh32(sh->rings_info_ptr); ++ sh->flags2 = ltoh32(sh->flags2); ++ ++ /* load bus console address */ ++ bus->console_addr = sh->console_addr; ++ ++ /* Read the dma rx offset */ ++ bus->dma_rxoffset = bus->pcie_sh->dma_rxoffset; ++ dhd_prot_rx_dataoffset(bus->dhd, bus->dma_rxoffset); ++ ++ DHD_INFO(("%s: DMA RX offset from shared Area %d\n", __FUNCTION__, bus->dma_rxoffset)); ++ ++ bus->api.fw_rev = sh->flags & PCIE_SHARED_VERSION_MASK; ++ if (!(dhdpcie_check_firmware_compatible(bus->api.fw_rev, PCIE_SHARED_VERSION))) ++ { ++ DHD_ERROR(("%s: pcie_shared version %d in dhd " ++ "is older than pciedev_shared version %d in dongle\n", ++ __FUNCTION__, PCIE_SHARED_VERSION, ++ bus->api.fw_rev)); ++ return BCME_ERROR; ++ } ++ dhdpcie_update_bus_api_revisions(bus->api.fw_rev, PCIE_SHARED_VERSION); ++ ++ bus->rw_index_sz = (sh->flags & PCIE_SHARED_2BYTE_INDICES) ? ++ sizeof(uint16) : sizeof(uint32); ++ DHD_INFO(("%s: Dongle advertizes %d size indices\n", ++ __FUNCTION__, bus->rw_index_sz)); ++ ++#ifdef IDLE_TX_FLOW_MGMT ++ if (sh->flags & PCIE_SHARED_IDLE_FLOW_RING) { ++ DHD_ERROR(("%s: FW Supports IdleFlow ring managment!\n", ++ __FUNCTION__)); ++ bus->enable_idle_flowring_mgmt = TRUE; ++ } ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++ bus->dhd->idma_enable = (sh->flags & PCIE_SHARED_IDMA) ? TRUE : FALSE; ++ bus->dhd->ifrm_enable = (sh->flags & PCIE_SHARED_IFRM) ? TRUE : FALSE; ++ ++ bus->dhd->idma_retention_ds = (sh->flags & PCIE_SHARED_IDMA_RETENTION_DS) ? TRUE : FALSE; ++ ++ bus->dhd->d2h_sync_mode = sh->flags & PCIE_SHARED_D2H_SYNC_MODE_MASK; ++ ++ /* Does the FW support DMA'ing r/w indices */ ++ if (sh->flags & PCIE_SHARED_DMA_INDEX) { ++ if (!bus->dhd->dma_ring_upd_overwrite) { ++ { ++ if (!IFRM_ENAB(bus->dhd)) { ++ bus->dhd->dma_h2d_ring_upd_support = TRUE; ++ } ++ bus->dhd->dma_d2h_ring_upd_support = TRUE; ++ } ++ } ++ ++ if (bus->dhd->dma_d2h_ring_upd_support) ++ bus->dhd->d2h_sync_mode = 0; ++ ++ DHD_INFO(("%s: Host support DMAing indices: H2D:%d - D2H:%d. FW supports it\n", ++ __FUNCTION__, ++ (bus->dhd->dma_h2d_ring_upd_support ? 1 : 0), ++ (bus->dhd->dma_d2h_ring_upd_support ? 1 : 0))); ++ } else if (!(sh->flags & PCIE_SHARED_D2H_SYNC_MODE_MASK)) { ++ DHD_ERROR(("%s FW has to support either dma indices or d2h sync\n", ++ __FUNCTION__)); ++ return BCME_UNSUPPORTED; ++ } else { ++ bus->dhd->dma_h2d_ring_upd_support = FALSE; ++ bus->dhd->dma_d2h_ring_upd_support = FALSE; ++ } ++ ++ /* get ring_info, ring_state and mb data ptrs and store the addresses in bus structure */ ++ { ++ ring_info_t ring_info; ++ ++ if ((rv = dhdpcie_bus_membytes(bus, FALSE, sh->rings_info_ptr, ++ (uint8 *)&ring_info, sizeof(ring_info_t))) < 0) ++ return rv; ++ ++ bus->h2d_mb_data_ptr_addr = ltoh32(sh->h2d_mb_data_ptr); ++ bus->d2h_mb_data_ptr_addr = ltoh32(sh->d2h_mb_data_ptr); ++ ++ ++ if (bus->api.fw_rev >= PCIE_SHARED_VERSION_6) { ++ bus->max_tx_flowrings = ltoh16(ring_info.max_tx_flowrings); ++ bus->max_submission_rings = ltoh16(ring_info.max_submission_queues); ++ bus->max_completion_rings = ltoh16(ring_info.max_completion_rings); ++ bus->max_cmn_rings = bus->max_submission_rings - bus->max_tx_flowrings; ++ bus->api.handle_mb_data = dhdpcie_read_handle_mb_data; ++ bus->use_mailbox = sh->flags & PCIE_SHARED_USE_MAILBOX; ++ } ++ else { ++ bus->max_tx_flowrings = ltoh16(ring_info.max_tx_flowrings); ++ bus->max_submission_rings = bus->max_tx_flowrings; ++ bus->max_completion_rings = BCMPCIE_D2H_COMMON_MSGRINGS; ++ bus->max_cmn_rings = BCMPCIE_H2D_COMMON_MSGRINGS; ++ bus->api.handle_mb_data = dhdpcie_handle_mb_data; ++ } ++ if (bus->max_completion_rings == 0) { ++ DHD_ERROR(("dongle completion rings are invalid %d\n", ++ bus->max_completion_rings)); ++ return BCME_ERROR; ++ } ++ if (bus->max_submission_rings == 0) { ++ DHD_ERROR(("dongle submission rings are invalid %d\n", ++ bus->max_submission_rings)); ++ return BCME_ERROR; ++ } ++ if (bus->max_tx_flowrings == 0) { ++ DHD_ERROR(("dongle txflow rings are invalid %d\n", bus->max_tx_flowrings)); ++ return BCME_ERROR; ++ } ++ ++ /* If both FW and Host support DMA'ing indices, allocate memory and notify FW ++ * The max_sub_queues is read from FW initialized ring_info ++ */ ++ if (bus->dhd->dma_h2d_ring_upd_support || IDMA_ENAB(bus->dhd)) { ++ dma_indx_wr_buf = dhd_prot_dma_indx_init(bus->dhd, bus->rw_index_sz, ++ H2D_DMA_INDX_WR_BUF, bus->max_submission_rings); ++ dma_indx_rd_buf = dhd_prot_dma_indx_init(bus->dhd, bus->rw_index_sz, ++ D2H_DMA_INDX_RD_BUF, bus->max_completion_rings); ++ ++ if ((dma_indx_wr_buf != BCME_OK) || (dma_indx_rd_buf != BCME_OK)) { ++ DHD_ERROR(("%s: Failed to allocate memory for dma'ing h2d indices" ++ "Host will use w/r indices in TCM\n", ++ __FUNCTION__)); ++ bus->dhd->dma_h2d_ring_upd_support = FALSE; ++ bus->dhd->idma_enable = FALSE; ++ } ++ } ++ ++ if (bus->dhd->dma_d2h_ring_upd_support) { ++ dma_indx_wr_buf = dhd_prot_dma_indx_init(bus->dhd, bus->rw_index_sz, ++ D2H_DMA_INDX_WR_BUF, bus->max_completion_rings); ++ dma_indx_rd_buf = dhd_prot_dma_indx_init(bus->dhd, bus->rw_index_sz, ++ H2D_DMA_INDX_RD_BUF, bus->max_submission_rings); ++ ++ if ((dma_indx_wr_buf != BCME_OK) || (dma_indx_rd_buf != BCME_OK)) { ++ DHD_ERROR(("%s: Failed to allocate memory for dma'ing d2h indices" ++ "Host will use w/r indices in TCM\n", ++ __FUNCTION__)); ++ bus->dhd->dma_d2h_ring_upd_support = FALSE; ++ } ++ } ++ ++ if (IFRM_ENAB(bus->dhd)) { ++ dma_indx_wr_buf = dhd_prot_dma_indx_init(bus->dhd, bus->rw_index_sz, ++ H2D_IFRM_INDX_WR_BUF, bus->max_tx_flowrings); ++ ++ if (dma_indx_wr_buf != BCME_OK) { ++ DHD_ERROR(("%s: Failed to alloc memory for Implicit DMA\n", ++ __FUNCTION__)); ++ bus->dhd->ifrm_enable = FALSE; ++ } ++ } ++ ++ /* read ringmem and ringstate ptrs from shared area and store in host variables */ ++ dhd_fillup_ring_sharedptr_info(bus, &ring_info); ++ if (dhd_msg_level & DHD_INFO_VAL) { ++ bcm_print_bytes("ring_info_raw", (uchar *)&ring_info, sizeof(ring_info_t)); ++ } ++ DHD_INFO(("%s: ring_info\n", __FUNCTION__)); ++ ++ DHD_ERROR(("%s: max H2D queues %d\n", ++ __FUNCTION__, ltoh16(ring_info.max_tx_flowrings))); ++ ++ DHD_INFO(("mail box address\n")); ++ DHD_INFO(("%s: h2d_mb_data_ptr_addr 0x%04x\n", ++ __FUNCTION__, bus->h2d_mb_data_ptr_addr)); ++ DHD_INFO(("%s: d2h_mb_data_ptr_addr 0x%04x\n", ++ __FUNCTION__, bus->d2h_mb_data_ptr_addr)); ++ } ++ ++ DHD_INFO(("%s: d2h_sync_mode 0x%08x\n", ++ __FUNCTION__, bus->dhd->d2h_sync_mode)); ++ ++ bus->dhd->d2h_hostrdy_supported = ++ ((sh->flags & PCIE_SHARED_HOSTRDY_SUPPORT) == PCIE_SHARED_HOSTRDY_SUPPORT); ++ ++#ifdef PCIE_OOB ++ bus->dhd->d2h_no_oob_dw = (sh->flags & PCIE_SHARED_NO_OOB_DW) ? TRUE : FALSE; ++#endif /* PCIE_OOB */ ++ ++#ifdef PCIE_INB_DW ++ bus->dhd->d2h_inband_dw = (sh->flags & PCIE_SHARED_INBAND_DS) ? TRUE : FALSE; ++#endif /* PCIE_INB_DW */ ++ ++#if defined(PCIE_OOB) && defined(PCIE_INB_DW) ++ DHD_ERROR(("FW supports Inband dw ? %s oob dw ? %s\n", ++ bus->dhd->d2h_inband_dw ? "Y":"N", ++ bus->dhd->d2h_no_oob_dw ? "N":"Y")); ++#endif /* defined(PCIE_OOB) && defined(PCIE_INB_DW) */ ++ ++ bus->dhd->ext_trap_data_supported = ++ ((sh->flags2 & PCIE_SHARED2_EXTENDED_TRAP_DATA) == PCIE_SHARED2_EXTENDED_TRAP_DATA); ++ ++ return BCME_OK; ++} /* dhdpcie_readshared */ ++ ++/** Read ring mem and ring state ptr info from shared memory area in device memory */ ++static void ++dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info) ++{ ++ uint16 i = 0; ++ uint16 j = 0; ++ uint32 tcm_memloc; ++ uint32 d2h_w_idx_ptr, d2h_r_idx_ptr, h2d_w_idx_ptr, h2d_r_idx_ptr; ++ uint16 max_tx_flowrings = bus->max_tx_flowrings; ++ ++ /* Ring mem ptr info */ ++ /* Alloated in the order ++ H2D_MSGRING_CONTROL_SUBMIT 0 ++ H2D_MSGRING_RXPOST_SUBMIT 1 ++ D2H_MSGRING_CONTROL_COMPLETE 2 ++ D2H_MSGRING_TX_COMPLETE 3 ++ D2H_MSGRING_RX_COMPLETE 4 ++ */ ++ ++ { ++ /* ringmemptr holds start of the mem block address space */ ++ tcm_memloc = ltoh32(ring_info->ringmem_ptr); ++ ++ /* Find out ringmem ptr for each ring common ring */ ++ for (i = 0; i <= BCMPCIE_COMMON_MSGRING_MAX_ID; i++) { ++ bus->ring_sh[i].ring_mem_addr = tcm_memloc; ++ /* Update mem block */ ++ tcm_memloc = tcm_memloc + sizeof(ring_mem_t); ++ DHD_INFO(("%s: ring id %d ring mem addr 0x%04x \n", __FUNCTION__, ++ i, bus->ring_sh[i].ring_mem_addr)); ++ } ++ } ++ ++ /* Ring state mem ptr info */ ++ { ++ d2h_w_idx_ptr = ltoh32(ring_info->d2h_w_idx_ptr); ++ d2h_r_idx_ptr = ltoh32(ring_info->d2h_r_idx_ptr); ++ h2d_w_idx_ptr = ltoh32(ring_info->h2d_w_idx_ptr); ++ h2d_r_idx_ptr = ltoh32(ring_info->h2d_r_idx_ptr); ++ ++ /* Store h2d common ring write/read pointers */ ++ for (i = 0; i < BCMPCIE_H2D_COMMON_MSGRINGS; i++) { ++ bus->ring_sh[i].ring_state_w = h2d_w_idx_ptr; ++ bus->ring_sh[i].ring_state_r = h2d_r_idx_ptr; ++ ++ /* update mem block */ ++ h2d_w_idx_ptr = h2d_w_idx_ptr + bus->rw_index_sz; ++ h2d_r_idx_ptr = h2d_r_idx_ptr + bus->rw_index_sz; ++ ++ DHD_INFO(("%s: h2d w/r : idx %d write %x read %x \n", __FUNCTION__, i, ++ bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); ++ } ++ ++ /* Store d2h common ring write/read pointers */ ++ for (j = 0; j < BCMPCIE_D2H_COMMON_MSGRINGS; j++, i++) { ++ bus->ring_sh[i].ring_state_w = d2h_w_idx_ptr; ++ bus->ring_sh[i].ring_state_r = d2h_r_idx_ptr; ++ ++ /* update mem block */ ++ d2h_w_idx_ptr = d2h_w_idx_ptr + bus->rw_index_sz; ++ d2h_r_idx_ptr = d2h_r_idx_ptr + bus->rw_index_sz; ++ ++ DHD_INFO(("%s: d2h w/r : idx %d write %x read %x \n", __FUNCTION__, i, ++ bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); ++ } ++ ++ /* Store txflow ring write/read pointers */ ++ if (bus->api.fw_rev < PCIE_SHARED_VERSION_6) { ++ max_tx_flowrings -= BCMPCIE_H2D_COMMON_MSGRINGS; ++ } else { ++ /* Account for Debug info h2d ring located after the last tx flow ring */ ++ max_tx_flowrings = max_tx_flowrings + 1; ++ } ++ for (j = 0; j < max_tx_flowrings; i++, j++) ++ { ++ bus->ring_sh[i].ring_state_w = h2d_w_idx_ptr; ++ bus->ring_sh[i].ring_state_r = h2d_r_idx_ptr; ++ ++ /* update mem block */ ++ h2d_w_idx_ptr = h2d_w_idx_ptr + bus->rw_index_sz; ++ h2d_r_idx_ptr = h2d_r_idx_ptr + bus->rw_index_sz; ++ ++ DHD_INFO(("%s: FLOW Rings h2d w/r : idx %d write %x read %x \n", ++ __FUNCTION__, i, ++ bus->ring_sh[i].ring_state_w, ++ bus->ring_sh[i].ring_state_r)); ++ } ++ /* store wr/rd pointers for debug info completion ring */ ++ bus->ring_sh[i].ring_state_w = d2h_w_idx_ptr; ++ bus->ring_sh[i].ring_state_r = d2h_r_idx_ptr; ++ d2h_w_idx_ptr = d2h_w_idx_ptr + bus->rw_index_sz; ++ d2h_r_idx_ptr = d2h_r_idx_ptr + bus->rw_index_sz; ++ DHD_INFO(("d2h w/r : idx %d write %x read %x \n", i, ++ bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r)); ++ } ++} /* dhd_fillup_ring_sharedptr_info */ ++ ++/** ++ * Initialize bus module: prepare for communication with the dongle. Called after downloading ++ * firmware into the dongle. ++ */ ++int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ int ret = 0; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ ASSERT(bus->dhd); ++ if (!bus->dhd) ++ return 0; ++ ++ /* Make sure we're talking to the core. */ ++ bus->reg = si_setcore(bus->sih, PCIE2_CORE_ID, 0); ++ ASSERT(bus->reg != NULL); ++ ++ /* before opening up bus for data transfer, check if shared are is intact */ ++ ret = dhdpcie_readshared(bus); ++ if (ret < 0) { ++ DHD_ERROR(("%s :Shared area read failed \n", __FUNCTION__)); ++ return ret; ++ } ++ ++ /* Make sure we're talking to the core. */ ++ bus->reg = si_setcore(bus->sih, PCIE2_CORE_ID, 0); ++ ASSERT(bus->reg != NULL); ++ ++ /* Set bus state according to enable result */ ++ dhdp->busstate = DHD_BUS_DATA; ++ bus->d3_suspend_pending = FALSE; ++ ++#if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING) ++ if (bus->pcie_sh->flags2 & PCIE_SHARED_D2H_D11_TX_STATUS) { ++ uint32 flags2 = bus->pcie_sh->flags2; ++ uint32 addr; ++ ++ addr = bus->shared_addr + OFFSETOF(pciedev_shared_t, flags2); ++ flags2 |= PCIE_SHARED_H2D_D11_TX_STATUS; ++ ret = dhdpcie_bus_membytes(bus, TRUE, addr, ++ (uint8 *)&flags2, sizeof(flags2)); ++ if (ret < 0) { ++ DHD_ERROR(("%s: update flag bit (H2D_D11_TX_STATUS) failed\n", ++ __FUNCTION__)); ++ return ret; ++ } ++ bus->pcie_sh->flags2 = flags2; ++ bus->dhd->d11_tx_status = TRUE; ++ } ++#endif /* DBG_PKT_MON || DHD_PKT_LOGGING */ ++ ++ if (!dhd_download_fw_on_driverload) ++ dhd_dpc_enable(bus->dhd); ++ /* Enable the interrupt after device is up */ ++ dhdpcie_bus_intr_enable(bus); ++ ++ /* bcmsdh_intr_unmask(bus->sdh); */ ++#ifdef DHD_PCIE_RUNTIMEPM ++ bus->idlecount = 0; ++ bus->idletime = (int32)MAX_IDLE_COUNT; ++ init_waitqueue_head(&bus->rpm_queue); ++ mutex_init(&bus->pm_lock); ++#else ++ bus->idletime = 0; ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++#ifdef PCIE_INB_DW ++ /* Initialize the lock to serialize Device Wake Inband activities */ ++ if (!bus->inb_lock) { ++ bus->inb_lock = dhd_os_spin_lock_init(bus->dhd->osh); ++ } ++#endif ++ ++ ++ /* Make use_d0_inform TRUE for Rev 5 for backward compatibility */ ++ if (bus->api.fw_rev < PCIE_SHARED_VERSION_6) { ++ bus->use_d0_inform = TRUE; ++ } else { ++ bus->use_d0_inform = FALSE; ++ } ++ ++ return ret; ++} ++ ++static void ++dhdpcie_init_shared_addr(dhd_bus_t *bus) ++{ ++ uint32 addr = 0; ++ uint32 val = 0; ++ addr = bus->dongle_ram_base + bus->ramsize - 4; ++#ifdef DHD_PCIE_RUNTIMEPM ++ dhdpcie_runtime_bus_wake(bus->dhd, TRUE, __builtin_return_address(0)); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val)); ++} ++ ++ ++bool ++dhdpcie_chipmatch(uint16 vendor, uint16 device) ++{ ++ if (vendor != PCI_VENDOR_ID_BROADCOM) { ++#ifndef DHD_EFI ++ DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__, ++ vendor, device)); ++#endif /* DHD_EFI */ ++ return (-ENODEV); ++ } ++ ++ if ((device == BCM4350_D11AC_ID) || (device == BCM4350_D11AC2G_ID) || ++ (device == BCM4350_D11AC5G_ID) || (device == BCM4350_CHIP_ID) || ++ (device == BCM43569_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4354_D11AC_ID) || (device == BCM4354_D11AC2G_ID) || ++ (device == BCM4354_D11AC5G_ID) || (device == BCM4354_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4356_D11AC_ID) || (device == BCM4356_D11AC2G_ID) || ++ (device == BCM4356_D11AC5G_ID) || (device == BCM4356_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4371_D11AC_ID) || (device == BCM4371_D11AC2G_ID) || ++ (device == BCM4371_D11AC5G_ID) || (device == BCM4371_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4345_D11AC_ID) || (device == BCM4345_D11AC2G_ID) || ++ (device == BCM4345_D11AC5G_ID) || BCM4345_CHIP(device)) ++ return 0; ++ ++ if ((device == BCM43452_D11AC_ID) || (device == BCM43452_D11AC2G_ID) || ++ (device == BCM43452_D11AC5G_ID)) ++ return 0; ++ ++ if ((device == BCM4335_D11AC_ID) || (device == BCM4335_D11AC2G_ID) || ++ (device == BCM4335_D11AC5G_ID) || (device == BCM4335_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM43602_D11AC_ID) || (device == BCM43602_D11AC2G_ID) || ++ (device == BCM43602_D11AC5G_ID) || (device == BCM43602_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM43569_D11AC_ID) || (device == BCM43569_D11AC2G_ID) || ++ (device == BCM43569_D11AC5G_ID) || (device == BCM43569_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4358_D11AC_ID) || (device == BCM4358_D11AC2G_ID) || ++ (device == BCM4358_D11AC5G_ID)) ++ return 0; ++ ++ if ((device == BCM4349_D11AC_ID) || (device == BCM4349_D11AC2G_ID) || ++ (device == BCM4349_D11AC5G_ID) || (device == BCM4349_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4355_D11AC_ID) || (device == BCM4355_D11AC2G_ID) || ++ (device == BCM4355_D11AC5G_ID) || (device == BCM4355_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4359_D11AC_ID) || (device == BCM4359_D11AC2G_ID) || ++ (device == BCM4359_D11AC5G_ID)) ++ return 0; ++ ++ if ((device == BCM43596_D11AC_ID) || (device == BCM43596_D11AC2G_ID) || ++ (device == BCM43596_D11AC5G_ID)) ++ return 0; ++ ++ if ((device == BCM43597_D11AC_ID) || (device == BCM43597_D11AC2G_ID) || ++ (device == BCM43597_D11AC5G_ID)) ++ return 0; ++ ++ if ((device == BCM4364_D11AC_ID) || (device == BCM4364_D11AC2G_ID) || ++ (device == BCM4364_D11AC5G_ID) || (device == BCM4364_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4347_D11AC_ID) || (device == BCM4347_D11AC2G_ID) || ++ (device == BCM4347_D11AC5G_ID) || (device == BCM4347_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4361_D11AC_ID) || (device == BCM4361_D11AC2G_ID) || ++ (device == BCM4361_D11AC5G_ID) || (device == BCM4361_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4362_D11AX_ID) || (device == BCM4362_D11AX2G_ID) || ++ (device == BCM4362_D11AX5G_ID) || (device == BCM4362_CHIP_ID)) { ++ return 0; ++ } ++ ++ if ((device == BCM4365_D11AC_ID) || (device == BCM4365_D11AC2G_ID) || ++ (device == BCM4365_D11AC5G_ID) || (device == BCM4365_CHIP_ID)) ++ return 0; ++ ++ if ((device == BCM4366_D11AC_ID) || (device == BCM4366_D11AC2G_ID) || ++ (device == BCM4366_D11AC5G_ID) || (device == BCM4366_CHIP_ID)) ++ return 0; ++#ifndef DHD_EFI ++ DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__, vendor, device)); ++#endif ++ return (-ENODEV); ++} /* dhdpcie_chipmatch */ ++ ++/** ++ * Name: dhdpcie_cc_nvmshadow ++ * ++ * Description: ++ * A shadow of OTP/SPROM exists in ChipCommon Region ++ * betw. 0x800 and 0xBFF (Backplane Addr. 0x1800_0800 and 0x1800_0BFF). ++ * Strapping option (SPROM vs. OTP), presence of OTP/SPROM and its size ++ * can also be read from ChipCommon Registers. ++ */ ++static int ++dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b) ++{ ++ uint16 dump_offset = 0; ++ uint32 dump_size = 0, otp_size = 0, sprom_size = 0; ++ ++ /* Table for 65nm OTP Size (in bits) */ ++ int otp_size_65nm[8] = {0, 2048, 4096, 8192, 4096, 6144, 512, 1024}; ++ ++ volatile uint16 *nvm_shadow; ++ ++ uint cur_coreid; ++ uint chipc_corerev; ++ chipcregs_t *chipcregs; ++ ++ /* Save the current core */ ++ cur_coreid = si_coreid(bus->sih); ++ /* Switch to ChipC */ ++ chipcregs = (chipcregs_t *)si_setcore(bus->sih, CC_CORE_ID, 0); ++ ASSERT(chipcregs != NULL); ++ ++ chipc_corerev = si_corerev(bus->sih); ++ ++ /* Check ChipcommonCore Rev */ ++ if (chipc_corerev < 44) { ++ DHD_ERROR(("%s: ChipcommonCore Rev %d < 44\n", __FUNCTION__, chipc_corerev)); ++ return BCME_UNSUPPORTED; ++ } ++ ++ /* Check ChipID */ ++ if (((uint16)bus->sih->chip != BCM4350_CHIP_ID) && !BCM4345_CHIP((uint16)bus->sih->chip) && ++ ((uint16)bus->sih->chip != BCM4355_CHIP_ID) && ++ ((uint16)bus->sih->chip != BCM4364_CHIP_ID)) { ++ DHD_ERROR(("%s: cc_nvmdump cmd. supported for Olympic chips" ++ "4350/4345/4355/4364 only\n", __FUNCTION__)); ++ return BCME_UNSUPPORTED; ++ } ++ ++ /* Check if SRC_PRESENT in SpromCtrl(0x190 in ChipCommon Regs) is set */ ++ if (chipcregs->sromcontrol & SRC_PRESENT) { ++ /* SPROM Size: 1Kbits (0x0), 4Kbits (0x1), 16Kbits(0x2) */ ++ sprom_size = (1 << (2 * ((chipcregs->sromcontrol & SRC_SIZE_MASK) ++ >> SRC_SIZE_SHIFT))) * 1024; ++ bcm_bprintf(b, "\nSPROM Present (Size %d bits)\n", sprom_size); ++ } ++ ++ if (chipcregs->sromcontrol & SRC_OTPPRESENT) { ++ bcm_bprintf(b, "\nOTP Present"); ++ ++ if (((chipcregs->otplayout & OTPL_WRAP_TYPE_MASK) >> OTPL_WRAP_TYPE_SHIFT) ++ == OTPL_WRAP_TYPE_40NM) { ++ /* 40nm OTP: Size = (OtpSize + 1) * 1024 bits */ ++ /* Chipcommon rev51 is a variation on rev45 and does not support ++ * the latest OTP configuration. ++ */ ++ if (chipc_corerev != 51 && chipc_corerev >= 49) { ++ otp_size = (((chipcregs->otplayout & OTPL_ROW_SIZE_MASK) ++ >> OTPL_ROW_SIZE_SHIFT) + 1) * 1024; ++ bcm_bprintf(b, "(Size %d bits)\n", otp_size); ++ } else { ++ otp_size = (((chipcregs->capabilities & CC_CAP_OTPSIZE) ++ >> CC_CAP_OTPSIZE_SHIFT) + 1) * 1024; ++ bcm_bprintf(b, "(Size %d bits)\n", otp_size); ++ } ++ } else { ++ /* This part is untested since newer chips have 40nm OTP */ ++ /* Chipcommon rev51 is a variation on rev45 and does not support ++ * the latest OTP configuration. ++ */ ++ if (chipc_corerev != 51 && chipc_corerev >= 49) { ++ otp_size = otp_size_65nm[(chipcregs->otplayout & OTPL_ROW_SIZE_MASK) ++ >> OTPL_ROW_SIZE_SHIFT]; ++ bcm_bprintf(b, "(Size %d bits)\n", otp_size); ++ } else { ++ otp_size = otp_size_65nm[(chipcregs->capabilities & CC_CAP_OTPSIZE) ++ >> CC_CAP_OTPSIZE_SHIFT]; ++ bcm_bprintf(b, "(Size %d bits)\n", otp_size); ++ DHD_INFO(("%s: 65nm/130nm OTP Size not tested. \n", ++ __FUNCTION__)); ++ } ++ } ++ } ++ ++ /* Chipcommon rev51 is a variation on rev45 and does not support ++ * the latest OTP configuration. ++ */ ++ if (chipc_corerev != 51 && chipc_corerev >= 49) { ++ if (((chipcregs->sromcontrol & SRC_PRESENT) == 0) && ++ ((chipcregs->otplayout & OTPL_ROW_SIZE_MASK) == 0)) { ++ DHD_ERROR(("%s: SPROM and OTP could not be found " ++ "sromcontrol = %x, otplayout = %x \n", ++ __FUNCTION__, chipcregs->sromcontrol, chipcregs->otplayout)); ++ return BCME_NOTFOUND; ++ } ++ } else { ++ if (((chipcregs->sromcontrol & SRC_PRESENT) == 0) && ++ ((chipcregs->capabilities & CC_CAP_OTPSIZE) == 0)) { ++ DHD_ERROR(("%s: SPROM and OTP could not be found " ++ "sromcontrol = %x, capablities = %x \n", ++ __FUNCTION__, chipcregs->sromcontrol, chipcregs->capabilities)); ++ return BCME_NOTFOUND; ++ } ++ } ++ ++ /* Check the strapping option in SpromCtrl: Set = OTP otherwise SPROM */ ++ if ((!(chipcregs->sromcontrol & SRC_PRESENT) || (chipcregs->sromcontrol & SRC_OTPSEL)) && ++ (chipcregs->sromcontrol & SRC_OTPPRESENT)) { ++ ++ bcm_bprintf(b, "OTP Strap selected.\n" ++ "\nOTP Shadow in ChipCommon:\n"); ++ ++ dump_size = otp_size / 16 ; /* 16bit words */ ++ ++ } else if (((chipcregs->sromcontrol & SRC_OTPSEL) == 0) && ++ (chipcregs->sromcontrol & SRC_PRESENT)) { ++ ++ bcm_bprintf(b, "SPROM Strap selected\n" ++ "\nSPROM Shadow in ChipCommon:\n"); ++ ++ /* If SPROM > 8K only 8Kbits is mapped to ChipCommon (0x800 - 0xBFF) */ ++ /* dump_size in 16bit words */ ++ dump_size = sprom_size > 8 ? (8 * 1024) / 16 : sprom_size / 16; ++ } else { ++ DHD_ERROR(("%s: NVM Shadow does not exist in ChipCommon\n", ++ __FUNCTION__)); ++ return BCME_NOTFOUND; ++ } ++ ++ if (bus->regs == NULL) { ++ DHD_ERROR(("ChipCommon Regs. not initialized\n")); ++ return BCME_NOTREADY; ++ } else { ++ bcm_bprintf(b, "\n OffSet:"); ++ ++ /* Chipcommon rev51 is a variation on rev45 and does not support ++ * the latest OTP configuration. ++ */ ++ if (chipc_corerev != 51 && chipc_corerev >= 49) { ++ /* Chip common can read only 8kbits, ++ * for ccrev >= 49 otp size is around 12 kbits so use GCI core ++ */ ++ nvm_shadow = (volatile uint16 *)si_setcore(bus->sih, GCI_CORE_ID, 0); ++ } else { ++ /* Point to the SPROM/OTP shadow in ChipCommon */ ++ nvm_shadow = chipcregs->sromotp; ++ } ++ ++ if (nvm_shadow == NULL) { ++ DHD_ERROR(("%s: NVM Shadow is not intialized\n", __FUNCTION__)); ++ return BCME_NOTFOUND; ++ } ++ ++ /* ++ * Read 16 bits / iteration. ++ * dump_size & dump_offset in 16-bit words ++ */ ++ while (dump_offset < dump_size) { ++ if (dump_offset % 2 == 0) ++ /* Print the offset in the shadow space in Bytes */ ++ bcm_bprintf(b, "\n 0x%04x", dump_offset * 2); ++ ++ bcm_bprintf(b, "\t0x%04x", *(nvm_shadow + dump_offset)); ++ dump_offset += 0x1; ++ } ++ } ++ ++ /* Switch back to the original core */ ++ si_setcore(bus->sih, cur_coreid, 0); ++ ++ return BCME_OK; ++} /* dhdpcie_cc_nvmshadow */ ++ ++/** Flow rings are dynamically created and destroyed */ ++void dhd_bus_clean_flow_ring(dhd_bus_t *bus, void *node) ++{ ++ void *pkt; ++ flow_queue_t *queue; ++ flow_ring_node_t *flow_ring_node = (flow_ring_node_t *)node; ++ unsigned long flags; ++ ++ queue = &flow_ring_node->queue; ++ ++#ifdef DHDTCPACK_SUPPRESS ++ /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, ++ * when there is a newly coming packet from network stack. ++ */ ++ dhd_tcpack_info_tbl_clean(bus->dhd); ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++ /* clean up BUS level info */ ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); ++ ++ /* Flush all pending packets in the queue, if any */ ++ while ((pkt = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { ++ PKTFREE(bus->dhd->osh, pkt, TRUE); ++ } ++ ASSERT(DHD_FLOW_QUEUE_EMPTY(queue)); ++ ++ /* Reinitialise flowring's queue */ ++ dhd_flow_queue_reinit(bus->dhd, queue, FLOW_RING_QUEUE_THRESHOLD); ++ flow_ring_node->status = FLOW_RING_STATUS_CLOSED; ++ flow_ring_node->active = FALSE; ++ ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ ++ /* Hold flowring_list_lock to ensure no race condition while accessing the List */ ++ DHD_FLOWRING_LIST_LOCK(bus->dhd->flowring_list_lock, flags); ++ dll_delete(&flow_ring_node->list); ++ DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, flags); ++ ++ /* Release the flowring object back into the pool */ ++ dhd_prot_flowrings_pool_release(bus->dhd, ++ flow_ring_node->flowid, flow_ring_node->prot_info); ++ ++ /* Free the flowid back to the flowid allocator */ ++ dhd_flowid_free(bus->dhd, flow_ring_node->flow_info.ifindex, ++ flow_ring_node->flowid); ++} ++ ++/** ++ * Allocate a Flow ring buffer, ++ * Init Ring buffer, send Msg to device about flow ring creation ++*/ ++int ++dhd_bus_flow_ring_create_request(dhd_bus_t *bus, void *arg) ++{ ++ flow_ring_node_t *flow_ring_node = (flow_ring_node_t *)arg; ++ ++ DHD_INFO(("%s :Flow create\n", __FUNCTION__)); ++ ++ /* Send Msg to device about flow ring creation */ ++ if (dhd_prot_flow_ring_create(bus->dhd, flow_ring_node) != BCME_OK) ++ return BCME_NOMEM; ++ ++ return BCME_OK; ++} ++ ++/** Handle response from dongle on a 'flow ring create' request */ ++void ++dhd_bus_flow_ring_create_response(dhd_bus_t *bus, uint16 flowid, int32 status) ++{ ++ flow_ring_node_t *flow_ring_node; ++ unsigned long flags; ++ ++ DHD_INFO(("%s :Flow Response %d \n", __FUNCTION__, flowid)); ++ ++ flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); ++ ASSERT(flow_ring_node->flowid == flowid); ++ ++ if (status != BCME_OK) { ++ DHD_ERROR(("%s Flow create Response failure error status = %d \n", ++ __FUNCTION__, status)); ++ /* Call Flow clean up */ ++ dhd_bus_clean_flow_ring(bus, flow_ring_node); ++ return; ++ } ++ ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); ++ flow_ring_node->status = FLOW_RING_STATUS_OPEN; ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ ++ /* Now add the Flow ring node into the active list ++ * Note that this code to add the newly created node to the active ++ * list was living in dhd_flowid_lookup. But note that after ++ * adding the node to the active list the contents of node is being ++ * filled in dhd_prot_flow_ring_create. ++ * If there is a D2H interrupt after the node gets added to the ++ * active list and before the node gets populated with values ++ * from the Bottom half dhd_update_txflowrings would be called. ++ * which will then try to walk through the active flow ring list, ++ * pickup the nodes and operate on them. Now note that since ++ * the function dhd_prot_flow_ring_create is not finished yet ++ * the contents of flow_ring_node can still be NULL leading to ++ * crashes. Hence the flow_ring_node should be added to the ++ * active list only after its truely created, which is after ++ * receiving the create response message from the Host. ++ */ ++ DHD_FLOWRING_LIST_LOCK(bus->dhd->flowring_list_lock, flags); ++ dll_prepend(&bus->flowring_active_list, &flow_ring_node->list); ++ DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, flags); ++ ++ dhd_bus_schedule_queue(bus, flowid, FALSE); /* from queue to flowring */ ++ ++ return; ++} ++ ++int ++dhd_bus_flow_ring_delete_request(dhd_bus_t *bus, void *arg) ++{ ++ void * pkt; ++ flow_queue_t *queue; ++ flow_ring_node_t *flow_ring_node; ++ unsigned long flags; ++ ++ DHD_INFO(("%s :Flow Delete\n", __FUNCTION__)); ++ ++ flow_ring_node = (flow_ring_node_t *)arg; ++ ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); ++ if (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING) { ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ DHD_ERROR(("%s :Delete Pending flowid %u\n", __FUNCTION__, flow_ring_node->flowid)); ++ return BCME_ERROR; ++ } ++ flow_ring_node->status = FLOW_RING_STATUS_DELETE_PENDING; ++ ++ queue = &flow_ring_node->queue; /* queue associated with flow ring */ ++ ++#ifdef DHDTCPACK_SUPPRESS ++ /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, ++ * when there is a newly coming packet from network stack. ++ */ ++ dhd_tcpack_info_tbl_clean(bus->dhd); ++#endif /* DHDTCPACK_SUPPRESS */ ++ /* Flush all pending packets in the queue, if any */ ++ while ((pkt = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { ++ PKTFREE(bus->dhd->osh, pkt, TRUE); ++ } ++ ASSERT(DHD_FLOW_QUEUE_EMPTY(queue)); ++ ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ ++ /* Send Msg to device about flow ring deletion */ ++ dhd_prot_flow_ring_delete(bus->dhd, flow_ring_node); ++ ++ return BCME_OK; ++} ++ ++void ++dhd_bus_flow_ring_delete_response(dhd_bus_t *bus, uint16 flowid, uint32 status) ++{ ++ flow_ring_node_t *flow_ring_node; ++ ++ DHD_INFO(("%s :Flow Delete Response %d \n", __FUNCTION__, flowid)); ++ ++ flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); ++ ASSERT(flow_ring_node->flowid == flowid); ++ ++ if (status != BCME_OK) { ++ DHD_ERROR(("%s Flow Delete Response failure error status = %d \n", ++ __FUNCTION__, status)); ++ return; ++ } ++ /* Call Flow clean up */ ++ dhd_bus_clean_flow_ring(bus, flow_ring_node); ++ ++ return; ++ ++} ++ ++int dhd_bus_flow_ring_flush_request(dhd_bus_t *bus, void *arg) ++{ ++ void *pkt; ++ flow_queue_t *queue; ++ flow_ring_node_t *flow_ring_node; ++ unsigned long flags; ++ ++ DHD_INFO(("%s :Flow Flush\n", __FUNCTION__)); ++ ++ flow_ring_node = (flow_ring_node_t *)arg; ++ ++ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); ++ queue = &flow_ring_node->queue; /* queue associated with flow ring */ ++ /* Flow ring status will be set back to FLOW_RING_STATUS_OPEN ++ * once flow ring flush response is received for this flowring node. ++ */ ++ flow_ring_node->status = FLOW_RING_STATUS_FLUSH_PENDING; ++ ++#ifdef DHDTCPACK_SUPPRESS ++ /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, ++ * when there is a newly coming packet from network stack. ++ */ ++ dhd_tcpack_info_tbl_clean(bus->dhd); ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++ /* Flush all pending packets in the queue, if any */ ++ while ((pkt = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) { ++ PKTFREE(bus->dhd->osh, pkt, TRUE); ++ } ++ ASSERT(DHD_FLOW_QUEUE_EMPTY(queue)); ++ ++ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); ++ ++ /* Send Msg to device about flow ring flush */ ++ dhd_prot_flow_ring_flush(bus->dhd, flow_ring_node); ++ ++ return BCME_OK; ++} ++ ++void ++dhd_bus_flow_ring_flush_response(dhd_bus_t *bus, uint16 flowid, uint32 status) ++{ ++ flow_ring_node_t *flow_ring_node; ++ ++ if (status != BCME_OK) { ++ DHD_ERROR(("%s Flow flush Response failure error status = %d \n", ++ __FUNCTION__, status)); ++ return; ++ } ++ ++ flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); ++ ASSERT(flow_ring_node->flowid == flowid); ++ ++ flow_ring_node->status = FLOW_RING_STATUS_OPEN; ++ return; ++} ++ ++uint32 ++dhd_bus_max_h2d_queues(struct dhd_bus *bus) ++{ ++ return bus->max_submission_rings; ++} ++ ++/* To be symmetric with SDIO */ ++void ++dhd_bus_pktq_flush(dhd_pub_t *dhdp) ++{ ++ return; ++} ++ ++void ++dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val) ++{ ++ dhdp->bus->is_linkdown = val; ++} ++ ++#ifdef IDLE_TX_FLOW_MGMT ++/* resume request */ ++int ++dhd_bus_flow_ring_resume_request(dhd_bus_t *bus, void *arg) ++{ ++ flow_ring_node_t *flow_ring_node = (flow_ring_node_t *)arg; ++ ++ DHD_ERROR(("%s :Flow Resume Request flow id %u\n", __FUNCTION__, flow_ring_node->flowid)); ++ ++ flow_ring_node->status = FLOW_RING_STATUS_RESUME_PENDING; ++ ++ /* Send Msg to device about flow ring resume */ ++ dhd_prot_flow_ring_resume(bus->dhd, flow_ring_node); ++ ++ return BCME_OK; ++} ++ ++/* add the node back to active flowring */ ++void ++dhd_bus_flow_ring_resume_response(dhd_bus_t *bus, uint16 flowid, int32 status) ++{ ++ ++ flow_ring_node_t *flow_ring_node; ++ ++ DHD_TRACE(("%s :flowid %d \n", __FUNCTION__, flowid)); ++ ++ flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid); ++ ASSERT(flow_ring_node->flowid == flowid); ++ ++ if (status != BCME_OK) { ++ DHD_ERROR(("%s Error Status = %d \n", ++ __FUNCTION__, status)); ++ return; ++ } ++ ++ DHD_TRACE(("%s :Number of pkts queued in FlowId:%d is -> %u!!\n", ++ __FUNCTION__, flow_ring_node->flowid, flow_ring_node->queue.len)); ++ ++ flow_ring_node->status = FLOW_RING_STATUS_OPEN; ++ ++ dhd_bus_schedule_queue(bus, flowid, FALSE); ++ return; ++} ++ ++/* scan the flow rings in active list for idle time out */ ++void ++dhd_bus_check_idle_scan(dhd_bus_t *bus) ++{ ++ uint64 time_stamp; /* in millisec */ ++ uint64 diff; ++ ++ time_stamp = OSL_SYSUPTIME(); ++ diff = time_stamp - bus->active_list_last_process_ts; ++ ++ if (diff > IDLE_FLOW_LIST_TIMEOUT) { ++ dhd_bus_idle_scan(bus); ++ bus->active_list_last_process_ts = OSL_SYSUPTIME(); ++ } ++ ++ return; ++} ++ ++ ++/* scan the nodes in active list till it finds a non idle node */ ++void ++dhd_bus_idle_scan(dhd_bus_t *bus) ++{ ++ dll_t *item, *prev; ++ flow_ring_node_t *flow_ring_node; ++ uint64 time_stamp, diff; ++ unsigned long flags; ++ uint16 ringid[MAX_SUSPEND_REQ]; ++ uint16 count = 0; ++ ++ time_stamp = OSL_SYSUPTIME(); ++ DHD_FLOWRING_LIST_LOCK(bus->dhd->flowring_list_lock, flags); ++ ++ for (item = dll_tail_p(&bus->flowring_active_list); ++ !dll_end(&bus->flowring_active_list, item); item = prev) { ++ prev = dll_prev_p(item); ++ ++ flow_ring_node = dhd_constlist_to_flowring(item); ++ ++ if (flow_ring_node->flowid == (bus->max_submission_rings - 1)) ++ continue; ++ ++ if (flow_ring_node->status != FLOW_RING_STATUS_OPEN) { ++ /* Takes care of deleting zombie rings */ ++ /* delete from the active list */ ++ DHD_INFO(("deleting flow id %u from active list\n", ++ flow_ring_node->flowid)); ++ __dhd_flow_ring_delete_from_active_list(bus, flow_ring_node); ++ continue; ++ } ++ ++ diff = time_stamp - flow_ring_node->last_active_ts; ++ ++ if ((diff > IDLE_FLOW_RING_TIMEOUT) && !(flow_ring_node->queue.len)) { ++ DHD_ERROR(("\nSuspending flowid %d\n", flow_ring_node->flowid)); ++ /* delete from the active list */ ++ __dhd_flow_ring_delete_from_active_list(bus, flow_ring_node); ++ flow_ring_node->status = FLOW_RING_STATUS_SUSPENDED; ++ ringid[count] = flow_ring_node->flowid; ++ count++; ++ if (count == MAX_SUSPEND_REQ) { ++ /* create a batch message now!! */ ++ dhd_prot_flow_ring_batch_suspend_request(bus->dhd, ringid, count); ++ count = 0; ++ } ++ ++ } else { ++ ++ /* No more scanning, break from here! */ ++ break; ++ } ++ } ++ ++ if (count) { ++ dhd_prot_flow_ring_batch_suspend_request(bus->dhd, ringid, count); ++ } ++ ++ DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, flags); ++ ++ return; ++} ++ ++void dhd_flow_ring_move_to_active_list_head(struct dhd_bus *bus, flow_ring_node_t *flow_ring_node) ++{ ++ unsigned long flags; ++ dll_t* list; ++ ++ DHD_FLOWRING_LIST_LOCK(bus->dhd->flowring_list_lock, flags); ++ /* check if the node is already at head, otherwise delete it and prepend */ ++ list = dll_head_p(&bus->flowring_active_list); ++ if (&flow_ring_node->list != list) { ++ dll_delete(&flow_ring_node->list); ++ dll_prepend(&bus->flowring_active_list, &flow_ring_node->list); ++ } ++ ++ /* update flow ring timestamp */ ++ flow_ring_node->last_active_ts = OSL_SYSUPTIME(); ++ ++ DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, flags); ++ ++ return; ++} ++ ++void dhd_flow_ring_add_to_active_list(struct dhd_bus *bus, flow_ring_node_t *flow_ring_node) ++{ ++ unsigned long flags; ++ ++ DHD_FLOWRING_LIST_LOCK(bus->dhd->flowring_list_lock, flags); ++ ++ dll_prepend(&bus->flowring_active_list, &flow_ring_node->list); ++ /* update flow ring timestamp */ ++ flow_ring_node->last_active_ts = OSL_SYSUPTIME(); ++ ++ DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, flags); ++ ++ return; ++} ++void __dhd_flow_ring_delete_from_active_list(struct dhd_bus *bus, flow_ring_node_t *flow_ring_node) ++{ ++ dll_delete(&flow_ring_node->list); ++} ++ ++void dhd_flow_ring_delete_from_active_list(struct dhd_bus *bus, flow_ring_node_t *flow_ring_node) ++{ ++ unsigned long flags; ++ ++ DHD_FLOWRING_LIST_LOCK(bus->dhd->flowring_list_lock, flags); ++ ++ __dhd_flow_ring_delete_from_active_list(bus, flow_ring_node); ++ ++ DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, flags); ++ ++ return; ++} ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++int ++dhdpcie_bus_clock_start(struct dhd_bus *bus) ++{ ++ return dhdpcie_start_host_pcieclock(bus); ++} ++ ++int ++dhdpcie_bus_clock_stop(struct dhd_bus *bus) ++{ ++ return dhdpcie_stop_host_pcieclock(bus); ++} ++ ++int ++dhdpcie_bus_disable_device(struct dhd_bus *bus) ++{ ++ return dhdpcie_disable_device(bus); ++} ++ ++int ++dhdpcie_bus_enable_device(struct dhd_bus *bus) ++{ ++ return dhdpcie_enable_device(bus); ++} ++ ++int ++dhdpcie_bus_alloc_resource(struct dhd_bus *bus) ++{ ++ return dhdpcie_alloc_resource(bus); ++} ++ ++void ++dhdpcie_bus_free_resource(struct dhd_bus *bus) ++{ ++ dhdpcie_free_resource(bus); ++} ++ ++int ++dhd_bus_request_irq(struct dhd_bus *bus) ++{ ++ return dhdpcie_bus_request_irq(bus); ++} ++ ++bool ++dhdpcie_bus_dongle_attach(struct dhd_bus *bus) ++{ ++ return dhdpcie_dongle_attach(bus); ++} ++ ++int ++dhd_bus_release_dongle(struct dhd_bus *bus) ++{ ++ bool dongle_isolation; ++ osl_t *osh; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (bus) { ++ osh = bus->osh; ++ ASSERT(osh); ++ ++ if (bus->dhd) { ++ dongle_isolation = bus->dhd->dongle_isolation; ++ dhdpcie_bus_release_dongle(bus, osh, dongle_isolation, TRUE); ++ } ++ } ++ ++ return 0; ++} ++ ++void ++dhdpcie_cto_init(struct dhd_bus *bus, bool enable) ++{ ++ if (enable) { ++ dhdpcie_bus_cfg_write_dword(bus, PCI_INT_MASK, 4, ++ PCI_CTO_INT_MASK | PCI_SBIM_MASK_SERR); ++ dhdpcie_bus_cfg_write_dword(bus, PCI_SPROM_CONTROL, 4, SPROM_BACKPLANE_EN); ++ ++ if (bus->dhd->cto_threshold == 0) { ++ bus->dhd->cto_threshold = PCIE_CTO_TO_THRESH_DEFAULT; ++ } ++ ++ si_corereg(bus->sih, bus->sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, ctoctrl), ~0, ++ ((bus->dhd->cto_threshold << PCIE_CTO_TO_THRESHOLD_SHIFT) & ++ PCIE_CTO_TO_THRESHHOLD_MASK) | ++ ((PCIE_CTO_CLKCHKCNT_VAL << PCIE_CTO_CLKCHKCNT_SHIFT) & ++ PCIE_CTO_CLKCHKCNT_MASK) | ++ PCIE_CTO_ENAB_MASK); ++ } else { ++ dhdpcie_bus_cfg_write_dword(bus, PCI_INT_MASK, 4, 0); ++ dhdpcie_bus_cfg_write_dword(bus, PCI_SPROM_CONTROL, 4, 0); ++ ++ si_corereg(bus->sih, bus->sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, ctoctrl), ~0, 0); ++ } ++} ++ ++static void ++dhdpcie_cto_error_recovery(struct dhd_bus *bus) ++{ ++ uint32 pci_intmask, err_status; ++ uint8 i = 0; ++ ++ pci_intmask = dhdpcie_bus_cfg_read_dword(bus, PCI_INT_MASK, 4); ++ dhdpcie_bus_cfg_write_dword(bus, PCI_INT_MASK, 4, pci_intmask & ~PCI_CTO_INT_MASK); ++ ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ ++ /* reset backplane */ ++ dhdpcie_bus_cfg_write_dword(bus, PCI_SPROM_CONTROL, 4, SPROM_CFG_TO_SB_RST); ++ ++ /* clear timeout error */ ++ while (1) { ++ err_status = si_corereg(bus->sih, bus->sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, dm_errlog), ++ 0, 0); ++ if (err_status & PCIE_CTO_ERR_MASK) { ++ si_corereg(bus->sih, bus->sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, dm_errlog), ++ ~0, PCIE_CTO_ERR_MASK); ++ } else { ++ break; ++ } ++ OSL_DELAY(CTO_TO_CLEAR_WAIT_MS * 1000); ++ i++; ++ if (i > CTO_TO_CLEAR_WAIT_MAX_CNT) { ++ DHD_ERROR(("cto recovery fail\n")); ++ ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++ return; ++ } ++ } ++ ++ /* clear interrupt status */ ++ dhdpcie_bus_cfg_write_dword(bus, PCI_INT_STATUS, 4, PCI_CTO_INT_MASK); ++ ++ /* Halt ARM & remove reset */ ++ /* TBD : we can add ARM Halt here in case */ ++ ++ DHD_ERROR(("cto recovery success\n")); ++ ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++} ++ ++#ifdef BCMPCIE_OOB_HOST_WAKE ++int ++dhd_bus_oob_intr_register(dhd_pub_t *dhdp) ++{ ++ return dhdpcie_oob_intr_register(dhdp->bus); ++} ++ ++void ++dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp) ++{ ++ dhdpcie_oob_intr_unregister(dhdp->bus); ++} ++ ++void ++dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable) ++{ ++ dhdpcie_oob_intr_set(dhdp->bus, enable); ++} ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ ++ ++ ++bool ++dhdpcie_bus_get_pcie_hostready_supported(dhd_bus_t *bus) ++{ ++ return bus->dhd->d2h_hostrdy_supported; ++} ++ ++void ++dhd_pcie_dump_core_regs(dhd_pub_t * pub, uint32 index, uint32 first_addr, uint32 last_addr) ++{ ++ dhd_bus_t *bus = pub->bus; ++ uint32 coreoffset = index << 12; ++ uint32 core_addr = SI_ENUM_BASE + coreoffset; ++ uint32 value; ++ ++ ++ while (first_addr <= last_addr) { ++ core_addr = SI_ENUM_BASE + coreoffset + first_addr; ++ if (si_backplane_access(bus->sih, core_addr, 4, &value, TRUE) != BCME_OK) { ++ DHD_ERROR(("Invalid size/addr combination \n")); ++ } ++ DHD_ERROR(("[0x%08x]: 0x%08x\n", core_addr, value)); ++ first_addr = first_addr + 4; ++ } ++} ++ ++#ifdef PCIE_OOB ++bool ++dhdpcie_bus_get_pcie_oob_dw_supported(dhd_bus_t *bus) ++{ ++ if (!bus->dhd) ++ return FALSE; ++ if (bus->oob_enabled) { ++ return !bus->dhd->d2h_no_oob_dw; ++ } else { ++ return FALSE; ++ } ++} ++#endif /* PCIE_OOB */ ++ ++void ++dhdpcie_bus_enab_pcie_dw(dhd_bus_t *bus, uint8 dw_option) ++{ ++ DHD_ERROR(("ENABLING DW:%d\n", dw_option)); ++ bus->dw_option = dw_option; ++} ++ ++#ifdef PCIE_INB_DW ++bool ++dhdpcie_bus_get_pcie_inband_dw_supported(dhd_bus_t *bus) ++{ ++ if (!bus->dhd) ++ return FALSE; ++ if (bus->inb_enabled) { ++ return bus->dhd->d2h_inband_dw; ++ } else { ++ return FALSE; ++ } ++} ++ ++void ++dhdpcie_bus_set_pcie_inband_dw_state(dhd_bus_t *bus, enum dhd_bus_ds_state state) ++{ ++ if (!INBAND_DW_ENAB(bus)) ++ return; ++ ++ DHD_INFO(("%s:%d\n", __FUNCTION__, state)); ++ bus->dhd->ds_state = state; ++ if (state == DW_DEVICE_DS_DISABLED_WAIT || state == DW_DEVICE_DS_D3_INFORM_WAIT) { ++ bus->ds_exit_timeout = 100; ++ } ++ if (state == DW_DEVICE_HOST_WAKE_WAIT) { ++ bus->host_sleep_exit_timeout = 100; ++ } ++ if (state == DW_DEVICE_DS_DEV_WAKE) { ++ bus->ds_exit_timeout = 0; ++ } ++ if (state == DW_DEVICE_DS_ACTIVE) { ++ bus->host_sleep_exit_timeout = 0; ++ } ++} ++ ++enum dhd_bus_ds_state ++dhdpcie_bus_get_pcie_inband_dw_state(dhd_bus_t *bus) ++{ ++ if (!INBAND_DW_ENAB(bus)) ++ return DW_DEVICE_DS_INVALID; ++ return bus->dhd->ds_state; ++} ++#endif /* PCIE_INB_DW */ ++ ++bool ++dhdpcie_bus_get_pcie_idma_supported(dhd_bus_t *bus) ++{ ++ if (!bus->dhd) ++ return FALSE; ++ else if (bus->idma_enabled) { ++ return bus->dhd->idma_enable; ++ } else { ++ return FALSE; ++ } ++} ++ ++bool ++dhdpcie_bus_get_pcie_ifrm_supported(dhd_bus_t *bus) ++{ ++ if (!bus->dhd) ++ return FALSE; ++ else if (bus->ifrm_enabled) { ++ return bus->dhd->ifrm_enable; ++ } else { ++ return FALSE; ++ } ++} ++ ++ ++void ++dhd_bus_dump_trap_info(dhd_bus_t *bus, struct bcmstrbuf *strbuf) ++{ ++ trap_t *tr = &bus->dhd->last_trap_info; ++ bcm_bprintf(strbuf, ++ "\nTRAP type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," ++ " lp 0x%x, rpc 0x%x" ++ "\nTrap 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\n", ++ ltoh32(tr->type), ltoh32(tr->epc), ltoh32(tr->cpsr), ltoh32(tr->spsr), ++ ltoh32(tr->r13), ltoh32(tr->r14), ltoh32(tr->pc), ++ ltoh32(bus->pcie_sh->trap_addr), ++ ltoh32(tr->r0), ltoh32(tr->r1), ltoh32(tr->r2), ltoh32(tr->r3), ++ ltoh32(tr->r4), ltoh32(tr->r5), ltoh32(tr->r6), ltoh32(tr->r7)); ++} ++ ++int ++dhd_bus_readwrite_bp_addr(dhd_pub_t *dhdp, uint addr, uint size, uint* data, bool read) ++{ ++ int bcmerror = 0; ++ struct dhd_bus *bus = dhdp->bus; ++ ++ if (si_backplane_access(bus->sih, addr, size, data, read) != BCME_OK) { ++ DHD_ERROR(("Invalid size/addr combination \n")); ++ bcmerror = BCME_ERROR; ++ } ++ ++ return bcmerror; ++} ++ ++int ++dhd_get_idletime(dhd_pub_t *dhd) ++{ ++ return dhd->bus->idletime; ++} ++ ++#ifdef DHD_SSSR_DUMP ++ ++static INLINE void ++dhd_sbreg_op(dhd_pub_t *dhd, uint addr, uint *val, bool read) ++{ ++ OSL_DELAY(1); ++ si_backplane_access(dhd->bus->sih, addr, sizeof(uint), val, read); ++ DHD_ERROR(("%s: addr:0x%x val:0x%x read:%d\n", __FUNCTION__, addr, *val, read)); ++ return; ++} ++ ++static int ++dhdpcie_get_sssr_fifo_dump(dhd_pub_t *dhd, uint *buf, uint fifo_size, ++ uint addr_reg, uint data_reg) ++{ ++ uint addr; ++ uint val = 0; ++ int i; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ if (!buf) { ++ DHD_ERROR(("%s: buf is NULL\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ if (!fifo_size) { ++ DHD_ERROR(("%s: fifo_size is 0\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ /* Set the base address offset to 0 */ ++ addr = addr_reg; ++ val = 0; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ addr = data_reg; ++ /* Read 4 bytes at once and loop for fifo_size / 4 */ ++ for (i = 0; i < fifo_size / 4; i++) { ++ si_backplane_access(dhd->bus->sih, addr, sizeof(uint), &val, TRUE); ++ buf[i] = val; ++ OSL_DELAY(1); ++ } ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_get_sssr_vasip_dump(dhd_pub_t *dhd, uint *buf, uint fifo_size, ++ uint addr_reg) ++{ ++ uint addr; ++ uint val = 0; ++ int i; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ if (!buf) { ++ DHD_ERROR(("%s: buf is NULL\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ if (!fifo_size) { ++ DHD_ERROR(("%s: fifo_size is 0\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ /* Check if vasip clk is disabled, if yes enable it */ ++ addr = dhd->sssr_reg_info.vasip_regs.wrapper_regs.ioctrl; ++ dhd_sbreg_op(dhd, addr, &val, TRUE); ++ if (!val) { ++ val = 1; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ } ++ ++ addr = addr_reg; ++ /* Read 4 bytes at once and loop for fifo_size / 4 */ ++ for (i = 0; i < fifo_size / 4; i++, addr += 4) { ++ si_backplane_access(dhd->bus->sih, addr, sizeof(uint), &val, TRUE); ++ buf[i] = val; ++ OSL_DELAY(1); ++ } ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_resume_chipcommon_powerctrl(dhd_pub_t *dhd) ++{ ++ uint addr; ++ uint val; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ /* conditionally clear bits [11:8] of PowerCtrl */ ++ addr = dhd->sssr_reg_info.chipcommon_regs.base_regs.powerctrl; ++ dhd_sbreg_op(dhd, addr, &val, TRUE); ++ if (!(val & dhd->sssr_reg_info.chipcommon_regs.base_regs.powerctrl_mask)) { ++ addr = dhd->sssr_reg_info.chipcommon_regs.base_regs.powerctrl; ++ val = dhd->sssr_reg_info.chipcommon_regs.base_regs.powerctrl_mask; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ } ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_suspend_chipcommon_powerctrl(dhd_pub_t *dhd) ++{ ++ uint addr; ++ uint val; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ /* conditionally clear bits [11:8] of PowerCtrl */ ++ addr = dhd->sssr_reg_info.chipcommon_regs.base_regs.powerctrl; ++ dhd_sbreg_op(dhd, addr, &val, TRUE); ++ if (val & dhd->sssr_reg_info.chipcommon_regs.base_regs.powerctrl_mask) { ++ addr = dhd->sssr_reg_info.chipcommon_regs.base_regs.powerctrl; ++ val = 0; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ } ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_clear_intmask_and_timer(dhd_pub_t *dhd) ++{ ++ uint addr; ++ uint val; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ /* clear chipcommon intmask */ ++ addr = dhd->sssr_reg_info.chipcommon_regs.base_regs.intmask; ++ val = 0x0; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ /* clear PMUIntMask0 */ ++ addr = dhd->sssr_reg_info.pmu_regs.base_regs.pmuintmask0; ++ val = 0x0; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ /* clear PMUIntMask1 */ ++ addr = dhd->sssr_reg_info.pmu_regs.base_regs.pmuintmask1; ++ val = 0x0; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ /* clear res_req_timer */ ++ addr = dhd->sssr_reg_info.pmu_regs.base_regs.resreqtimer; ++ val = 0x0; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ /* clear macresreqtimer */ ++ addr = dhd->sssr_reg_info.pmu_regs.base_regs.macresreqtimer; ++ val = 0x0; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ /* clear macresreqtimer1 */ ++ addr = dhd->sssr_reg_info.pmu_regs.base_regs.macresreqtimer1; ++ val = 0x0; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ /* clear VasipClkEn */ ++ if (dhd->sssr_reg_info.vasip_regs.vasip_sr_size) { ++ addr = dhd->sssr_reg_info.vasip_regs.wrapper_regs.ioctrl; ++ val = 0x0; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ } ++ ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_d11_check_outofreset(dhd_pub_t *dhd) ++{ ++ int i; ++ uint addr; ++ uint val = 0; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ for (i = 0; i < MAX_NUM_D11CORES; i++) { ++ /* Check if bit 0 of resetctrl is cleared */ ++ addr = dhd->sssr_reg_info.mac_regs[i].wrapper_regs.resetctrl; ++ dhd_sbreg_op(dhd, addr, &val, TRUE); ++ if (!(val & 1)) { ++ dhd->sssr_d11_outofreset[i] = TRUE; ++ } else { ++ dhd->sssr_d11_outofreset[i] = FALSE; ++ } ++ DHD_ERROR(("%s: sssr_d11_outofreset[%d] : %d\n", ++ __FUNCTION__, i, dhd->sssr_d11_outofreset[i])); ++ } ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_d11_clear_clk_req(dhd_pub_t *dhd) ++{ ++ int i; ++ uint addr; ++ uint val = 0; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ for (i = 0; i < MAX_NUM_D11CORES; i++) { ++ if (dhd->sssr_d11_outofreset[i]) { ++ /* clear request clk only if itopoobb is non zero */ ++ addr = dhd->sssr_reg_info.mac_regs[i].wrapper_regs.itopoobb; ++ dhd_sbreg_op(dhd, addr, &val, TRUE); ++ if (val != 0) { ++ /* clear clockcontrolstatus */ ++ addr = dhd->sssr_reg_info.mac_regs[i].base_regs.clockcontrolstatus; ++ val = ++ dhd->sssr_reg_info.mac_regs[i].base_regs.clockcontrolstatus_val; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ } ++ } ++ } ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_arm_clear_clk_req(dhd_pub_t *dhd) ++{ ++ uint addr; ++ uint val = 0; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ /* Check if bit 0 of resetctrl is cleared */ ++ addr = dhd->sssr_reg_info.arm_regs.wrapper_regs.resetctrl; ++ dhd_sbreg_op(dhd, addr, &val, TRUE); ++ if (!(val & 1)) { ++ /* clear request clk only if itopoobb is non zero */ ++ addr = dhd->sssr_reg_info.arm_regs.wrapper_regs.itopoobb; ++ dhd_sbreg_op(dhd, addr, &val, TRUE); ++ if (val != 0) { ++ /* clear clockcontrolstatus */ ++ addr = dhd->sssr_reg_info.arm_regs.base_regs.clockcontrolstatus; ++ val = dhd->sssr_reg_info.arm_regs.base_regs.clockcontrolstatus_val; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ } ++ } ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_pcie_clear_clk_req(dhd_pub_t *dhd) ++{ ++ uint addr; ++ uint val = 0; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ /* clear request clk only if itopoobb is non zero */ ++ addr = dhd->sssr_reg_info.pcie_regs.wrapper_regs.itopoobb; ++ dhd_sbreg_op(dhd, addr, &val, TRUE); ++ if (val) { ++ /* clear clockcontrolstatus */ ++ addr = dhd->sssr_reg_info.pcie_regs.base_regs.clockcontrolstatus; ++ val = dhd->sssr_reg_info.pcie_regs.base_regs.clockcontrolstatus_val; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ } ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_pcie_send_ltrsleep(dhd_pub_t *dhd) ++{ ++ uint addr; ++ uint val = 0; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ addr = dhd->sssr_reg_info.pcie_regs.base_regs.ltrstate; ++ val = LTR_ACTIVE; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ val = LTR_SLEEP; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_clear_clk_req(dhd_pub_t *dhd) ++{ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ dhdpcie_arm_clear_clk_req(dhd); ++ ++ dhdpcie_d11_clear_clk_req(dhd); ++ ++ dhdpcie_pcie_clear_clk_req(dhd); ++ ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_bring_d11_outofreset(dhd_pub_t *dhd) ++{ ++ int i; ++ uint addr; ++ uint val = 0; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ for (i = 0; i < MAX_NUM_D11CORES; i++) { ++ if (dhd->sssr_d11_outofreset[i]) { ++ /* disable core by setting bit 0 */ ++ addr = dhd->sssr_reg_info.mac_regs[i].wrapper_regs.resetctrl; ++ val = 1; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ OSL_DELAY(6000); ++ ++ addr = dhd->sssr_reg_info.mac_regs[i].wrapper_regs.ioctrl; ++ val = dhd->sssr_reg_info.mac_regs[0].wrapper_regs.ioctrl_resetseq_val[0]; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ val = dhd->sssr_reg_info.mac_regs[0].wrapper_regs.ioctrl_resetseq_val[1]; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ /* enable core by clearing bit 0 */ ++ addr = dhd->sssr_reg_info.mac_regs[i].wrapper_regs.resetctrl; ++ val = 0; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ addr = dhd->sssr_reg_info.mac_regs[i].wrapper_regs.ioctrl; ++ val = dhd->sssr_reg_info.mac_regs[0].wrapper_regs.ioctrl_resetseq_val[2]; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ val = dhd->sssr_reg_info.mac_regs[0].wrapper_regs.ioctrl_resetseq_val[3]; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ ++ val = dhd->sssr_reg_info.mac_regs[0].wrapper_regs.ioctrl_resetseq_val[4]; ++ dhd_sbreg_op(dhd, addr, &val, FALSE); ++ } ++ } ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_sssr_dump_get_before_sr(dhd_pub_t *dhd) ++{ ++ int i; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ for (i = 0; i < MAX_NUM_D11CORES; i++) { ++ if (dhd->sssr_d11_outofreset[i]) { ++ dhdpcie_get_sssr_fifo_dump(dhd, dhd->sssr_d11_before[i], ++ dhd->sssr_reg_info.mac_regs[i].sr_size, ++ dhd->sssr_reg_info.mac_regs[i].base_regs.xmtaddress, ++ dhd->sssr_reg_info.mac_regs[i].base_regs.xmtdata); ++ } ++ } ++ ++ if (dhd->sssr_reg_info.vasip_regs.vasip_sr_size) { ++ dhdpcie_get_sssr_vasip_dump(dhd, dhd->sssr_vasip_buf_before, ++ dhd->sssr_reg_info.vasip_regs.vasip_sr_size, ++ dhd->sssr_reg_info.vasip_regs.vasip_sr_addr); ++ } ++ ++ return BCME_OK; ++} ++ ++static int ++dhdpcie_sssr_dump_get_after_sr(dhd_pub_t *dhd) ++{ ++ int i; ++ ++ DHD_ERROR(("%s\n", __FUNCTION__)); ++ ++ for (i = 0; i < MAX_NUM_D11CORES; i++) { ++ if (dhd->sssr_d11_outofreset[i]) { ++ dhdpcie_get_sssr_fifo_dump(dhd, dhd->sssr_d11_after[i], ++ dhd->sssr_reg_info.mac_regs[i].sr_size, ++ dhd->sssr_reg_info.mac_regs[i].base_regs.xmtaddress, ++ dhd->sssr_reg_info.mac_regs[i].base_regs.xmtdata); ++ } ++ } ++ ++ if (dhd->sssr_reg_info.vasip_regs.vasip_sr_size) { ++ dhdpcie_get_sssr_vasip_dump(dhd, dhd->sssr_vasip_buf_after, ++ dhd->sssr_reg_info.vasip_regs.vasip_sr_size, ++ dhd->sssr_reg_info.vasip_regs.vasip_sr_addr); ++ } ++ ++ return BCME_OK; ++} ++ ++int ++dhdpcie_sssr_dump(dhd_pub_t *dhd) ++{ ++ if (!dhd->sssr_inited) { ++ DHD_ERROR(("%s: SSSR not inited\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ if (dhd->bus->is_linkdown) { ++ DHD_ERROR(("%s: PCIe link is down\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ dhdpcie_d11_check_outofreset(dhd); ++ ++ DHD_ERROR(("%s: Collecting Dump before SR\n", __FUNCTION__)); ++ if (dhdpcie_sssr_dump_get_before_sr(dhd) != BCME_OK) { ++ DHD_ERROR(("%s: dhdpcie_sssr_dump_get_before_sr failed\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ dhdpcie_clear_intmask_and_timer(dhd); ++ dhdpcie_suspend_chipcommon_powerctrl(dhd); ++ dhdpcie_clear_clk_req(dhd); ++ dhdpcie_pcie_send_ltrsleep(dhd); ++ ++ /* Wait for some time before Restore */ ++ OSL_DELAY(6000); ++ ++ dhdpcie_resume_chipcommon_powerctrl(dhd); ++ dhdpcie_bring_d11_outofreset(dhd); ++ ++ DHD_ERROR(("%s: Collecting Dump after SR\n", __FUNCTION__)); ++ if (dhdpcie_sssr_dump_get_after_sr(dhd) != BCME_OK) { ++ DHD_ERROR(("%s: dhdpcie_sssr_dump_get_after_sr failed\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ dhd_schedule_sssr_dump(dhd); ++ ++ return BCME_OK; ++} ++#endif /* DHD_SSSR_DUMP */ ++ ++#ifdef DHD_WAKE_STATUS ++wake_counts_t* ++dhd_bus_get_wakecount(dhd_pub_t *dhd) ++{ ++ if (!dhd->bus) { ++ return NULL; ++ } ++ return &dhd->bus->wake_counts; ++} ++int ++dhd_bus_get_bus_wake(dhd_pub_t *dhd) ++{ ++ return bcmpcie_set_get_wake(dhd->bus, 0); ++} ++#endif /* DHD_WAKE_STATUS */ ++ ++#ifdef BCM_ASLR_HEAP ++/* Writes random number(s) to the TCM. FW upon initialization reads the metadata ++ * of the random number and then based on metadata, reads the random number from the TCM. ++ */ ++static void ++dhdpcie_wrt_rnd(struct dhd_bus *bus) ++{ ++ bcm_rand_metadata_t rnd_data; ++ uint32 rand_no; ++ uint32 count = 1; /* start with 1 random number */ ++ ++ uint32 addr = bus->dongle_ram_base + (bus->ramsize - BCM_NVRAM_OFFSET_TCM) - ++ ((bus->nvram_csm & 0xffff)* BCM_NVRAM_IMG_COMPRS_FACTOR + sizeof(rnd_data)); ++ rnd_data.signature = htol32(BCM_RNG_SIGNATURE); ++ rnd_data.count = htol32(count); ++ /* write the metadata about random number */ ++ dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&rnd_data, sizeof(rnd_data)); ++ /* scale back by number of random number counts */ ++ addr -= sizeof(count) * count; ++ /* Now write the random number(s) */ ++ rand_no = htol32(dhd_get_random_number()); ++ dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&rand_no, sizeof(rand_no)); ++} ++#endif /* BCM_ASLR_HEAP */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie.h +new file mode 100644 +index 000000000..92b07c6e4 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie.h +@@ -0,0 +1,607 @@ ++/* ++ * Linux DHD Bus Module for PCIE ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_pcie.h 707536 2017-06-28 04:23:48Z $ ++ */ ++ ++ ++#ifndef dhd_pcie_h ++#define dhd_pcie_h ++ ++#include ++#include ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++#ifdef CONFIG_ARCH_MSM ++#ifdef CONFIG_PCI_MSM ++#include ++#else ++#include ++#endif /* CONFIG_PCI_MSM */ ++#endif /* CONFIG_ARCH_MSM */ ++#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY ++#if defined(CONFIG_SOC_EXYNOS8890) || defined(CONFIG_SOC_EXYNOS8895) ++#include ++extern int exynos_pcie_register_event(struct exynos_pcie_register_event *reg); ++extern int exynos_pcie_deregister_event(struct exynos_pcie_register_event *reg); ++#endif /* CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895 */ ++#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */ ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++#include ++#include ++ ++#define DEFAULT_DHD_RUNTIME_MS 100 ++#ifndef CUSTOM_DHD_RUNTIME_MS ++#define CUSTOM_DHD_RUNTIME_MS DEFAULT_DHD_RUNTIME_MS ++#endif /* CUSTOM_DHD_RUNTIME_MS */ ++ ++ ++#ifndef MAX_IDLE_COUNT ++#define MAX_IDLE_COUNT 16 ++#endif /* MAX_IDLE_COUNT */ ++ ++#ifndef MAX_RESUME_WAIT ++#define MAX_RESUME_WAIT 100 ++#endif /* MAX_RESUME_WAIT */ ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++/* defines */ ++ ++#define PCMSGBUF_HDRLEN 0 ++#define DONGLE_REG_MAP_SIZE (32 * 1024) ++#define DONGLE_TCM_MAP_SIZE (4096 * 1024) ++#define DONGLE_MIN_MEMSIZE (128 *1024) ++#ifdef DHD_DEBUG ++#define DHD_PCIE_SUCCESS 0 ++#define DHD_PCIE_FAILURE 1 ++#endif /* DHD_DEBUG */ ++#define REMAP_ENAB(bus) ((bus)->remap) ++#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) ++ ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++#ifdef CONFIG_ARCH_MSM ++#define struct_pcie_notify struct msm_pcie_notify ++#define struct_pcie_register_event struct msm_pcie_register_event ++#endif /* CONFIG_ARCH_MSM */ ++#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY ++#if defined(CONFIG_SOC_EXYNOS8890) || defined(CONFIG_SOC_EXYNOS8895) ++#define struct_pcie_notify struct exynos_pcie_notify ++#define struct_pcie_register_event struct exynos_pcie_register_event ++#endif /* CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895 */ ++#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */ ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ ++#define MAX_DHD_TX_FLOWS 320 ++ ++/* user defined data structures */ ++/* Device console log buffer state */ ++#define CONSOLE_LINE_MAX 192 ++#define CONSOLE_BUFFER_MAX (8 * 1024) ++ ++#ifdef IDLE_TX_FLOW_MGMT ++#define IDLE_FLOW_LIST_TIMEOUT 5000 ++#define IDLE_FLOW_RING_TIMEOUT 5000 ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++#ifdef DEVICE_TX_STUCK_DETECT ++#define DEVICE_TX_STUCK_CKECK_TIMEOUT 1000 /* 1 sec */ ++#define DEVICE_TX_STUCK_TIMEOUT 10000 /* 10 secs */ ++#define DEVICE_TX_STUCK_WARN_DURATION (DEVICE_TX_STUCK_TIMEOUT / DEVICE_TX_STUCK_CKECK_TIMEOUT) ++#define DEVICE_TX_STUCK_DURATION (DEVICE_TX_STUCK_WARN_DURATION * 2) ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ ++/* implicit DMA for h2d wr and d2h rd indice from Host memory to TCM */ ++#define IDMA_ENAB(dhd) ((dhd)->idma_enable) ++#define IDMA_ACTIVE(dhd) (((dhd)->idma_enable) && ((dhd)->idma_inited)) ++ ++#define IDMA_DS_ENAB(dhd) ((dhd)->idma_retention_ds) ++#define IDMA_DS_ACTIVE(dhd) ((dhd)->bus->dongle_in_ds) ++ ++/* IFRM (Implicit Flow Ring Manager enable and inited */ ++#define IFRM_ENAB(dhd) ((dhd)->ifrm_enable) ++#define IFRM_ACTIVE(dhd) (((dhd)->ifrm_enable) && ((dhd)->ifrm_inited)) ++ ++/* PCIE CTO Prevention and Recovery */ ++#define PCIECTO_ENAB(dhd) ((dhd)->cto_enable) ++ ++/* Implicit DMA index usage : ++ * Index 0 for h2d write index transfer ++ * Index 1 for d2h read index transfer ++ */ ++#define IDMA_IDX0 0 ++#define IDMA_IDX1 1 ++#define IDMA_IDX2 2 ++#define IDMA_IDX3 3 ++ ++#define DHDPCIE_CONFIG_HDR_SIZE 16 ++#define DHDPCIE_CONFIG_CHECK_DELAY_MS 10 /* 10ms */ ++#define DHDPCIE_CONFIG_CHECK_RETRY_COUNT 20 ++#define DHDPCIE_DONGLE_PWR_TOGGLE_DELAY 1000 /* 1ms in units of us */ ++#define DHDPCIE_PM_D3_DELAY 200000 /* 200ms in units of us */ ++#define DHDPCIE_PM_D2_DELAY 200 /* 200us */ ++ ++typedef struct dhd_console { ++ uint count; /* Poll interval msec counter */ ++ uint log_addr; /* Log struct address (fixed) */ ++ hnd_log_t log; /* Log struct (host copy) */ ++ uint bufsize; /* Size of log buffer */ ++ uint8 *buf; /* Log buffer (host copy) */ ++ uint last; /* Last buffer read index */ ++} dhd_console_t; ++ ++typedef struct ring_sh_info { ++ uint32 ring_mem_addr; ++ uint32 ring_state_w; ++ uint32 ring_state_r; ++} ring_sh_info_t; ++ ++ ++#define DEVICE_WAKE_NONE 0 ++#define DEVICE_WAKE_OOB 1 ++#define DEVICE_WAKE_INB 2 ++ ++#define INBAND_DW_ENAB(bus) ((bus)->dw_option == DEVICE_WAKE_INB) ++#define OOB_DW_ENAB(bus) ((bus)->dw_option == DEVICE_WAKE_OOB) ++#define NO_DW_ENAB(bus) ((bus)->dw_option == DEVICE_WAKE_NONE) ++ ++struct dhd_bus; ++ ++struct dhd_pcie_rev { ++ uint8 fw_rev; ++ void (*handle_mb_data)(struct dhd_bus *); ++}; ++ ++typedef struct dhdpcie_config_save ++{ ++ uint32 header[DHDPCIE_CONFIG_HDR_SIZE]; ++ /* pmcsr save */ ++ uint32 pmcsr; ++ /* express save */ ++ uint32 exp_dev_ctrl_stat; ++ uint32 exp_link_ctrl_stat; ++ uint32 exp_dev_ctrl_stat2; ++ uint32 exp_link_ctrl_stat2; ++ /* msi save */ ++ uint32 msi_cap; ++ uint32 msi_addr0; ++ uint32 msi_addr1; ++ uint32 msi_data; ++ /* l1pm save */ ++ uint32 l1pm0; ++ uint32 l1pm1; ++ /* ltr save */ ++ uint32 ltr; ++ /* aer save */ ++ uint32 aer_caps_ctrl; /* 0x18 */ ++ uint32 aer_severity; /* 0x0C */ ++ uint32 aer_umask; /* 0x08 */ ++ uint32 aer_cmask; /* 0x14 */ ++ uint32 aer_root_cmd; /* 0x2c */ ++ /* BAR0 and BAR1 windows */ ++ uint32 bar0_win; ++ uint32 bar1_win; ++} dhdpcie_config_save_t; ++ ++typedef struct dhd_bus { ++ dhd_pub_t *dhd; ++ struct pci_dev *rc_dev; /* pci RC device handle */ ++ struct pci_dev *dev; /* pci device handle */ ++#ifdef DHD_EFI ++ void *pcie_dev; ++#endif ++ ++ dll_t flowring_active_list; /* constructed list of tx flowring queues */ ++#ifdef IDLE_TX_FLOW_MGMT ++ uint64 active_list_last_process_ts; ++ /* stores the timestamp of active list processing */ ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++#ifdef DEVICE_TX_STUCK_DETECT ++ /* Flag to enable/disable device tx stuck monitor by DHD IOVAR dev_tx_stuck_monitor */ ++ uint32 dev_tx_stuck_monitor; ++ /* Stores the timestamp (msec) of the last device Tx stuck check */ ++ uint32 device_tx_stuck_check; ++#endif /* DEVICE_TX_STUCK_DETECT */ ++ ++ si_t *sih; /* Handle for SI calls */ ++ char *vars; /* Variables (from CIS and/or other) */ ++ uint varsz; /* Size of variables buffer */ ++ uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ ++ sbpcieregs_t *reg; /* Registers for PCIE core */ ++ ++ uint armrev; /* CPU core revision */ ++ uint ramrev; /* SOCRAM core revision */ ++ uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ ++ uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ ++ bool ramsize_adjusted; /* flag to note adjustment, so that ++ * adjustment routine and file io ++ * are avoided on D3 cold -> D0 ++ */ ++ uint32 srmemsize; /* Size of SRMEM */ ++ ++ uint32 bus; /* gSPI or SDIO bus */ ++ uint32 intstatus; /* Intstatus bits (events) pending */ ++ bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ ++ bool fcstate; /* State of dongle flow-control */ ++ ++ uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ ++ char *fw_path; /* module_param: path to firmware image */ ++ char *nv_path; /* module_param: path to nvram vars file */ ++#ifdef CACHE_FW_IMAGES ++ int processed_nvram_params_len; /* Modified len of NVRAM info */ ++#endif ++ ++ ++ struct pktq txq; /* Queue length used for flow-control */ ++ ++ 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 */ ++ ++ dhd_console_t console; /* Console output polling support */ ++ uint console_addr; /* Console address from shared struct */ ++ ++ bool alp_only; /* Don't use HT clock (ALP only) */ ++ ++ bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram ++ * Available with socram rev 16 ++ * Remap region not DMA-able ++ */ ++ uint32 resetinstr; ++ uint32 dongle_ram_base; ++ ++ ulong shared_addr; ++ pciedev_shared_t *pcie_sh; ++ bool bus_flowctrl; ++ uint32 dma_rxoffset; ++ volatile char *regs; /* pci device memory va */ ++ volatile char *tcm; /* pci device memory va */ ++ osl_t *osh; ++ uint32 nvram_csm; /* Nvram checksum */ ++ uint16 pollrate; ++ uint16 polltick; ++ ++ volatile uint32 *pcie_mb_intr_addr; ++ volatile uint32 *pcie_mb_intr_2_addr; ++ void *pcie_mb_intr_osh; ++ bool sleep_allowed; ++ ++ wake_counts_t wake_counts; ++ ++ /* version 3 shared struct related info start */ ++ ring_sh_info_t ring_sh[BCMPCIE_COMMON_MSGRINGS + MAX_DHD_TX_FLOWS]; ++ ++ uint8 h2d_ring_count; ++ uint8 d2h_ring_count; ++ uint32 ringmem_ptr; ++ uint32 ring_state_ptr; ++ ++ uint32 d2h_dma_scratch_buffer_mem_addr; ++ ++ uint32 h2d_mb_data_ptr_addr; ++ uint32 d2h_mb_data_ptr_addr; ++ /* version 3 shared struct related info end */ ++ ++ uint32 def_intmask; ++ bool ltrsleep_on_unload; ++ uint wait_for_d3_ack; ++ uint16 max_tx_flowrings; ++ uint16 max_submission_rings; ++ uint16 max_completion_rings; ++ uint16 max_cmn_rings; ++ uint32 rw_index_sz; ++ bool db1_for_mb; ++ ++ dhd_timeout_t doorbell_timer; ++ bool device_wake_state; ++#ifdef PCIE_OOB ++ bool oob_enabled; ++#endif /* PCIE_OOB */ ++ bool irq_registered; ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++#if defined(CONFIG_ARCH_MSM) || (defined(EXYNOS_PCIE_LINKDOWN_RECOVERY) && \ ++ defined(CONFIG_SOC_EXYNOS8890) || defined(CONFIG_SOC_EXYNOS8895)) ++#ifdef CONFIG_ARCH_MSM ++ uint8 no_cfg_restore; ++#endif /* CONFIG_ARCH_MSM */ ++ struct_pcie_register_event pcie_event; ++#endif /* CONFIG_ARCH_MSM || (EXYNOS_PCIE_LINKDOWN_RECOVERY && ++ * (CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895)) ++ */ ++ bool read_shm_fail; ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ int32 idletime; /* Control for activity timeout */ ++#ifdef DHD_PCIE_RUNTIMEPM ++ int32 idlecount; /* Activity timeout counter */ ++ int32 bus_wake; /* For wake up the bus */ ++ bool runtime_resume_done; /* For check runtime suspend end */ ++ struct mutex pm_lock; /* Synchronize for system PM & runtime PM */ ++ wait_queue_head_t rpm_queue; /* wait-queue for bus wake up */ ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ uint32 d3_inform_cnt; ++ uint32 d0_inform_cnt; ++ uint32 d0_inform_in_use_cnt; ++ uint8 force_suspend; ++ uint8 is_linkdown; ++#ifdef IDLE_TX_FLOW_MGMT ++ bool enable_idle_flowring_mgmt; ++#endif /* IDLE_TX_FLOW_MGMT */ ++ struct dhd_pcie_rev api; ++ bool use_mailbox; ++ bool d3_suspend_pending; ++ bool use_d0_inform; ++ uint32 hostready_count; /* Number of hostready issued */ ++#if defined(PCIE_OOB) || defined(BCMPCIE_OOB_HOST_WAKE) ++ bool oob_presuspend; ++#endif /* PCIE_OOB || BCMPCIE_OOB_HOST_WAKE */ ++ bool dongle_in_ds; ++ uint8 dw_option; ++#ifdef PCIE_INB_DW ++ bool inb_enabled; ++ uint32 ds_exit_timeout; ++ uint32 host_sleep_exit_timeout; ++ uint wait_for_ds_exit; ++ uint32 inband_dw_assert_cnt; /* # of inband device_wake assert */ ++ uint32 inband_dw_deassert_cnt; /* # of inband device_wake deassert */ ++ uint32 inband_ds_exit_host_cnt; /* # of DS-EXIT , host initiated */ ++ uint32 inband_ds_exit_device_cnt; /* # of DS-EXIT , device initiated */ ++ uint32 inband_ds_exit_to_cnt; /* # of DS-EXIT timeout */ ++ uint32 inband_host_sleep_exit_to_cnt; /* # of Host_Sleep exit timeout */ ++ void *inb_lock; /* Lock to serialize in band device wake activity */ ++ /* # of contexts in the host which currently want a FW transaction */ ++ uint32 host_active_cnt; ++#endif /* PCIE_INB_DW */ ++ dhdpcie_config_save_t saved_config; ++ ulong resume_intr_enable_count; ++ ulong dpc_intr_enable_count; ++ ulong isr_intr_disable_count; ++ ulong suspend_intr_disable_count; ++ ulong dpc_return_busdown_count; ++ bool idma_enabled; ++ bool ifrm_enabled; ++#if defined(PCIE_OOB) || defined(PCIE_INB_DW) ++ bool ds_enabled; ++#endif ++#ifdef DHD_PCIE_RUNTIMEPM ++ bool chk_pm; /* To avoid counting of wake up from Runtime PM */ ++#endif /* DHD_PCIE_RUNTIMEPM */ ++} dhd_bus_t; ++ ++/* function declarations */ ++ ++extern uint32* dhdpcie_bus_reg_map(osl_t *osh, ulong addr, int size); ++extern int dhdpcie_bus_register(void); ++extern void dhdpcie_bus_unregister(void); ++extern bool dhdpcie_chipmatch(uint16 vendor, uint16 device); ++ ++extern struct dhd_bus* dhdpcie_bus_attach(osl_t *osh, ++ volatile char *regs, volatile char *tcm, void *pci_dev); ++extern uint32 dhdpcie_bus_cfg_read_dword(struct dhd_bus *bus, uint32 addr, uint32 size); ++extern void dhdpcie_bus_cfg_write_dword(struct dhd_bus *bus, uint32 addr, uint32 size, uint32 data); ++extern void dhdpcie_bus_intr_enable(struct dhd_bus *bus); ++extern void dhdpcie_bus_intr_disable(struct dhd_bus *bus); ++extern int dhpcie_bus_mask_interrupt(dhd_bus_t *bus); ++extern void dhdpcie_bus_release(struct dhd_bus *bus); ++extern int32 dhdpcie_bus_isr(struct dhd_bus *bus); ++extern void dhdpcie_free_irq(dhd_bus_t *bus); ++extern void dhdpcie_bus_ringbell_fast(struct dhd_bus *bus, uint32 value); ++extern void dhdpcie_bus_ringbell_2_fast(struct dhd_bus *bus, uint32 value, bool devwake); ++extern int dhdpcie_bus_suspend(struct dhd_bus *bus, bool state); ++extern int dhdpcie_pci_suspend_resume(struct dhd_bus *bus, bool state); ++extern uint32 dhdpcie_force_alp(struct dhd_bus *bus, bool enable); ++extern uint32 dhdpcie_set_l1_entry_time(struct dhd_bus *bus, int force_l1_entry_time); ++extern bool dhdpcie_tcm_valid(dhd_bus_t *bus); ++extern void dhdpcie_pme_active(osl_t *osh, bool enable); ++extern bool dhdpcie_pme_cap(osl_t *osh); ++extern uint32 dhdpcie_lcreg(osl_t *osh, uint32 mask, uint32 val); ++extern void dhdpcie_set_pmu_min_res_mask(struct dhd_bus *bus, uint min_res_mask); ++extern uint8 dhdpcie_clkreq(osl_t *osh, uint32 mask, uint32 val); ++extern int dhdpcie_disable_irq(dhd_bus_t *bus); ++extern int dhdpcie_disable_irq_nosync(dhd_bus_t *bus); ++extern int dhdpcie_enable_irq(dhd_bus_t *bus); ++extern uint32 dhdpcie_rc_config_read(dhd_bus_t *bus, uint offset); ++extern uint32 dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext, ++ bool is_write, uint32 writeval); ++extern uint32 dhd_debug_get_rc_linkcap(dhd_bus_t *bus); ++extern int dhdpcie_start_host_pcieclock(dhd_bus_t *bus); ++extern int dhdpcie_stop_host_pcieclock(dhd_bus_t *bus); ++extern int dhdpcie_disable_device(dhd_bus_t *bus); ++extern int dhdpcie_alloc_resource(dhd_bus_t *bus); ++extern void dhdpcie_free_resource(dhd_bus_t *bus); ++extern int dhdpcie_bus_request_irq(struct dhd_bus *bus); ++extern int dhdpcie_enable_device(dhd_bus_t *bus); ++#ifdef BCMPCIE_OOB_HOST_WAKE ++extern int dhdpcie_oob_intr_register(dhd_bus_t *bus); ++extern void dhdpcie_oob_intr_unregister(dhd_bus_t *bus); ++extern void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable); ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++#ifdef PCIE_OOB ++extern void dhd_oob_set_bt_reg_on(struct dhd_bus *bus, bool val); ++extern int dhd_oob_get_bt_reg_on(struct dhd_bus *bus); ++extern void dhdpcie_oob_init(dhd_bus_t *bus); ++extern void dhd_bus_doorbell_timeout_reset(struct dhd_bus *bus); ++extern int dhd_os_oob_set_device_wake(struct dhd_bus *bus, bool val); ++extern void dhd_os_ib_set_device_wake(struct dhd_bus *bus, bool val); ++#endif /* PCIE_OOB */ ++ ++#if defined(CONFIG_ARCH_EXYNOS) ++#define SAMSUNG_PCIE_VENDOR_ID 0x144d ++#if defined(CONFIG_MACH_UNIVERSAL5433) ++#define SAMSUNG_PCIE_DEVICE_ID 0xa5e3 ++#define SAMSUNG_PCIE_CH_NUM ++#elif defined(CONFIG_MACH_UNIVERSAL7420) ++#define SAMSUNG_PCIE_DEVICE_ID 0xa575 ++#define SAMSUNG_PCIE_CH_NUM 1 ++#elif defined(CONFIG_SOC_EXYNOS8890) ++#define SAMSUNG_PCIE_DEVICE_ID 0xa544 ++#define SAMSUNG_PCIE_CH_NUM 0 ++#elif defined(CONFIG_SOC_EXYNOS7420) ++#define SAMSUNG_PCIE_DEVICE_ID 0xa575 ++#define SAMSUNG_PCIE_CH_NUM 1 ++#elif defined(CONFIG_SOC_EXYNOS8895) ++#define SAMSUNG_PCIE_DEVICE_ID 0xecec ++#define SAMSUNG_PCIE_CH_NUM 0 ++#else ++#error "Not supported platform" ++#endif /* CONFIG_SOC_EXYNOSXXXX & CONFIG_MACH_UNIVERSALXXXX */ ++#endif /* CONFIG_ARCH_EXYNOS */ ++ ++#if defined(CONFIG_ARCH_MSM) ++#define MSM_PCIE_VENDOR_ID 0x17cb ++#if defined(CONFIG_ARCH_APQ8084) ++#define MSM_PCIE_DEVICE_ID 0x0101 ++#elif defined(CONFIG_ARCH_MSM8994) ++#define MSM_PCIE_DEVICE_ID 0x0300 ++#elif defined(CONFIG_ARCH_MSM8996) ++#define MSM_PCIE_DEVICE_ID 0x0104 ++#elif defined(CONFIG_ARCH_MSM8998) ++#define MSM_PCIE_DEVICE_ID 0x0105 ++#else ++#error "Not supported platform" ++#endif ++#endif /* CONFIG_ARCH_MSM */ ++ ++#if defined(CONFIG_X86) ++#define X86_PCIE_VENDOR_ID 0x8086 ++#define X86_PCIE_DEVICE_ID 0x9c1a ++#endif /* CONFIG_X86 */ ++ ++#if defined(CONFIG_ARCH_TEGRA) ++#define TEGRA_PCIE_VENDOR_ID 0x14e4 ++#define TEGRA_PCIE_DEVICE_ID 0x4347 ++#endif /* CONFIG_ARCH_TEGRA */ ++ ++#if defined(CONFIG_ARCH_EXYNOS) ++#define PCIE_RC_VENDOR_ID SAMSUNG_PCIE_VENDOR_ID ++#define PCIE_RC_DEVICE_ID SAMSUNG_PCIE_DEVICE_ID ++#elif defined(CONFIG_ARCH_MSM) ++#define PCIE_RC_VENDOR_ID MSM_PCIE_VENDOR_ID ++#define PCIE_RC_DEVICE_ID MSM_PCIE_DEVICE_ID ++#elif defined(CONFIG_X86) ++#define PCIE_RC_VENDOR_ID X86_PCIE_VENDOR_ID ++#define PCIE_RC_DEVICE_ID X86_PCIE_DEVICE_ID ++#elif defined(CONFIG_ARCH_TEGRA) ++#define PCIE_RC_VENDOR_ID TEGRA_PCIE_VENDOR_ID ++#define PCIE_RC_DEVICE_ID TEGRA_PCIE_DEVICE_ID ++#endif /* CONFIG_ARCH_EXYNOS */ ++ ++#ifdef USE_EXYNOS_PCIE_RC_PMPATCH ++#ifdef CONFIG_MACH_UNIVERSAL5433 ++extern int exynos_pcie_pm_suspend(void); ++extern int exynos_pcie_pm_resume(void); ++#else ++extern int exynos_pcie_pm_suspend(int ch_num); ++extern int exynos_pcie_pm_resume(int ch_num); ++#endif /* CONFIG_MACH_UNIVERSAL5433 */ ++#endif /* USE_EXYNOS_PCIE_RC_PMPATCH */ ++ ++#ifdef CONFIG_ARCH_TEGRA ++extern int tegra_pcie_pm_suspend(void); ++extern int tegra_pcie_pm_resume(void); ++#endif /* CONFIG_ARCH_TEGRA */ ++ ++extern int dhd_buzzz_dump_dngl(dhd_bus_t *bus); ++#ifdef IDLE_TX_FLOW_MGMT ++extern int dhd_bus_flow_ring_resume_request(struct dhd_bus *bus, void *arg); ++extern void dhd_bus_flow_ring_resume_response(struct dhd_bus *bus, uint16 flowid, int32 status); ++extern int dhd_bus_flow_ring_suspend_request(struct dhd_bus *bus, void *arg); ++extern void dhd_bus_flow_ring_suspend_response(struct dhd_bus *bus, uint16 flowid, uint32 status); ++extern void dhd_flow_ring_move_to_active_list_head(struct dhd_bus *bus, ++ flow_ring_node_t *flow_ring_node); ++extern void dhd_flow_ring_add_to_active_list(struct dhd_bus *bus, ++ flow_ring_node_t *flow_ring_node); ++extern void dhd_flow_ring_delete_from_active_list(struct dhd_bus *bus, ++ flow_ring_node_t *flow_ring_node); ++extern void __dhd_flow_ring_delete_from_active_list(struct dhd_bus *bus, ++ flow_ring_node_t *flow_ring_node); ++#endif /* IDLE_TX_FLOW_MGMT */ ++ ++extern int dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data); ++ ++#ifdef DHD_WAKE_STATUS ++int bcmpcie_get_total_wake(struct dhd_bus *bus); ++int bcmpcie_set_get_wake(struct dhd_bus *bus, int flag); ++#endif /* DHD_WAKE_STATUS */ ++extern bool dhdpcie_bus_get_pcie_hostready_supported(dhd_bus_t *bus); ++extern void dhd_bus_hostready(struct dhd_bus *bus); ++#ifdef PCIE_OOB ++extern bool dhdpcie_bus_get_pcie_oob_dw_supported(dhd_bus_t *bus); ++#endif /* PCIE_OOB */ ++#ifdef PCIE_INB_DW ++extern bool dhdpcie_bus_get_pcie_inband_dw_supported(dhd_bus_t *bus); ++extern void dhdpcie_bus_set_pcie_inband_dw_state(dhd_bus_t *bus, ++ enum dhd_bus_ds_state state); ++extern enum dhd_bus_ds_state dhdpcie_bus_get_pcie_inband_dw_state(dhd_bus_t *bus); ++extern const char * dhd_convert_inb_state_names(enum dhd_bus_ds_state inbstate); ++extern const char * dhd_convert_dsval(uint32 val, bool d2h); ++extern int dhd_bus_inb_set_device_wake(struct dhd_bus *bus, bool val); ++extern void dhd_bus_inb_ack_pending_ds_req(dhd_bus_t *bus); ++#endif /* PCIE_INB_DW */ ++extern void dhdpcie_bus_enab_pcie_dw(dhd_bus_t *bus, uint8 dw_option); ++extern bool dhdpcie_irq_enabled(struct dhd_bus *bus); ++extern bool dhdpcie_bus_get_pcie_idma_supported(dhd_bus_t *bus); ++extern bool dhdpcie_bus_get_pcie_ifrm_supported(dhd_bus_t *bus); ++ ++static INLINE uint32 ++dhd_pcie_config_read(osl_t *osh, uint offset, uint size) ++{ ++ OSL_DELAY(100); ++ return OSL_PCI_READ_CONFIG(osh, offset, size); ++} ++ ++static INLINE uint32 ++dhd_pcie_corereg_read(si_t *sih, uint val) ++{ ++ OSL_DELAY(100); ++ si_corereg(sih, sih->buscoreidx, OFFSETOF(sbpcieregs_t, configaddr), ~0, val); ++ return si_corereg(sih, sih->buscoreidx, OFFSETOF(sbpcieregs_t, configdata), 0, 0); ++} ++ ++#ifdef DHD_SSSR_DUMP ++extern int dhdpcie_sssr_dump(dhd_pub_t *dhd); ++#endif /* DHD_SSSR_DUMP */ ++ ++#ifdef DHD_EFI ++extern int dhd_os_wifi_platform_set_power(uint32 value); ++int dhd_control_signal(dhd_bus_t *bus, char *arg, int set); ++extern int dhd_wifi_properties(struct dhd_bus *bus, char *arg); ++extern bool dhdpcie_is_arm_halted(struct dhd_bus *bus); ++extern void dhdpcie_dongle_pwr_toggle(dhd_bus_t *bus); ++extern int dhd_otp_dump(dhd_bus_t *bus, char *arg); ++#else ++static INLINE int dhd_os_wifi_platform_set_power(uint32 value) {return BCME_OK; } ++static INLINE bool dhdpcie_is_arm_halted(struct dhd_bus *bus) {return TRUE;} ++#endif /* DHD_EFI */ ++int dhdpcie_config_check(dhd_bus_t *bus); ++int dhdpcie_config_restore(dhd_bus_t *bus, bool restore_pmcsr); ++int dhdpcie_config_save(dhd_bus_t *bus); ++int dhdpcie_set_pwr_state(dhd_bus_t *bus, uint state); ++ ++#endif /* dhd_pcie_h */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c +new file mode 100644 +index 000000000..928c72ba1 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c +@@ -0,0 +1,2316 @@ ++/* ++ * Linux DHD Bus Module for PCIE ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_pcie_linux.c 707536 2017-06-28 04:23:48Z $ ++ */ ++ ++ ++/* include files */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(DHD_DEBUG) ++#include ++#include ++#endif /* defined(DHD_DEBUG) */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_ARCH_MSM ++#if defined(CONFIG_PCI_MSM) || defined(CONFIG_ARCH_MSM8996) ++#include ++#else ++#include ++#endif /* CONFIG_PCI_MSM */ ++#endif /* CONFIG_ARCH_MSM */ ++#ifdef PCIE_OOB ++#include "ftdi_sio_external.h" ++#endif /* PCIE_OOB */ ++#include ++#ifdef USE_SMMU_ARCH_MSM ++#include ++#include ++#include ++#include ++#endif /* USE_SMMU_ARCH_MSM */ ++ ++#define PCI_CFG_RETRY 10 ++#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ ++#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ ++ ++#define OSL_PKTTAG_CLEAR(p) \ ++do { \ ++ struct sk_buff *s = (struct sk_buff *)(p); \ ++ ASSERT(OSL_PKTTAG_SZ == 32); \ ++ *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \ ++ *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ ++ *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ ++ *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ ++} while (0) ++ ++#ifdef PCIE_OOB ++#define HOST_WAKE 4 /* GPIO_0 (HOST_WAKE) - Output from WLAN */ ++#define DEVICE_WAKE 5 /* GPIO_1 (DEVICE_WAKE) - Input to WLAN */ ++#define BIT_WL_REG_ON 6 ++#define BIT_BT_REG_ON 7 ++ ++int gpio_handle_val = 0; ++unsigned char gpio_port = 0; ++unsigned char gpio_direction = 0; ++#define OOB_PORT "ttyUSB0" ++#endif /* PCIE_OOB */ ++ ++/* user defined data structures */ ++ ++typedef struct dhd_pc_res { ++ uint32 bar0_size; ++ void* bar0_addr; ++ uint32 bar1_size; ++ void* bar1_addr; ++} pci_config_res, *pPci_config_res; ++ ++typedef bool (*dhdpcie_cb_fn_t)(void *); ++ ++typedef struct dhdpcie_info ++{ ++ dhd_bus_t *bus; ++ osl_t *osh; ++ struct pci_dev *dev; /* pci device handle */ ++ volatile char *regs; /* pci device memory va */ ++ volatile char *tcm; /* pci device memory va */ ++ uint32 tcm_size; /* pci device memory size */ ++ struct pcos_info *pcos_info; ++ uint16 last_intrstatus; /* to cache intrstatus */ ++ int irq; ++ char pciname[32]; ++ struct pci_saved_state* default_state; ++ struct pci_saved_state* state; ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ void *os_cxt; /* Pointer to per-OS private data */ ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++#ifdef DHD_WAKE_STATUS ++ spinlock_t pcie_lock; ++ unsigned int total_wake_count; ++ int pkt_wake; ++ int wake_irq; ++#endif /* DHD_WAKE_STATUS */ ++#ifdef USE_SMMU_ARCH_MSM ++ void *smmu_cxt; ++#endif /* USE_SMMU_ARCH_MSM */ ++} dhdpcie_info_t; ++ ++ ++struct pcos_info { ++ dhdpcie_info_t *pc; ++ spinlock_t lock; ++ wait_queue_head_t intr_wait_queue; ++ timer_list_compat_t tuning_timer; ++ int tuning_timer_exp; ++ atomic_t timer_enab; ++ struct tasklet_struct tuning_tasklet; ++}; ++ ++#ifdef BCMPCIE_OOB_HOST_WAKE ++typedef struct dhdpcie_os_info { ++ int oob_irq_num; /* valid when hardware or software oob in use */ ++ unsigned long oob_irq_flags; /* valid when hardware or software oob in use */ ++ bool oob_irq_registered; ++ bool oob_irq_enabled; ++ bool oob_irq_wake_enabled; ++ spinlock_t oob_irq_spinlock; ++ void *dev; /* handle to the underlying device */ ++} dhdpcie_os_info_t; ++static irqreturn_t wlan_oob_irq(int irq, void *data); ++#if defined(CUSTOMER_HW2) && defined(CONFIG_ARCH_APQ8084) ++extern struct brcm_pcie_wake brcm_pcie_wake; ++#endif /* CUSTOMER_HW2 && CONFIG_ARCH_APQ8084 */ ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ ++#ifdef USE_SMMU_ARCH_MSM ++typedef struct dhdpcie_smmu_info { ++ struct dma_iommu_mapping *smmu_mapping; ++ dma_addr_t smmu_iova_start; ++ size_t smmu_iova_len; ++} dhdpcie_smmu_info_t; ++#endif /* USE_SMMU_ARCH_MSM */ ++ ++/* function declarations */ ++static int __devinit ++dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); ++static void __devexit ++dhdpcie_pci_remove(struct pci_dev *pdev); ++static int dhdpcie_init(struct pci_dev *pdev); ++static irqreturn_t dhdpcie_isr(int irq, void *arg); ++/* OS Routine functions for PCI suspend/resume */ ++ ++static int dhdpcie_set_suspend_resume(dhd_bus_t *bus, bool state); ++static int dhdpcie_resume_host_dev(dhd_bus_t *bus); ++static int dhdpcie_suspend_host_dev(dhd_bus_t *bus); ++static int dhdpcie_resume_dev(struct pci_dev *dev); ++static int dhdpcie_suspend_dev(struct pci_dev *dev); ++#ifdef DHD_PCIE_RUNTIMEPM ++static int dhdpcie_pm_suspend(struct device *dev); ++static int dhdpcie_pm_prepare(struct device *dev); ++static int dhdpcie_pm_resume(struct device *dev); ++static void dhdpcie_pm_complete(struct device *dev); ++#else ++static int dhdpcie_pci_suspend(struct pci_dev *dev, pm_message_t state); ++static int dhdpcie_pci_resume(struct pci_dev *dev); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++static struct pci_device_id dhdpcie_pci_devid[] __devinitdata = { ++ { vendor: 0x14e4, ++ device: PCI_ANY_ID, ++ subvendor: PCI_ANY_ID, ++ subdevice: PCI_ANY_ID, ++ class: PCI_CLASS_NETWORK_OTHER << 8, ++ class_mask: 0xffff00, ++ driver_data: 0, ++ }, ++ { 0, 0, 0, 0, 0, 0, 0} ++}; ++MODULE_DEVICE_TABLE(pci, dhdpcie_pci_devid); ++ ++/* Power Management Hooks */ ++#ifdef DHD_PCIE_RUNTIMEPM ++static const struct dev_pm_ops dhd_pcie_pm_ops = { ++ .prepare = dhdpcie_pm_prepare, ++ .suspend = dhdpcie_pm_suspend, ++ .resume = dhdpcie_pm_resume, ++ .complete = dhdpcie_pm_complete, ++}; ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++static struct pci_driver dhdpcie_driver = { ++ node: {&dhdpcie_driver.node, &dhdpcie_driver.node}, ++ name: "pcieh", ++ id_table: dhdpcie_pci_devid, ++ probe: dhdpcie_pci_probe, ++ remove: dhdpcie_pci_remove, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++ save_state: NULL, ++#endif ++#ifdef DHD_PCIE_RUNTIMEPM ++ .driver.pm = &dhd_pcie_pm_ops, ++#else ++ suspend: dhdpcie_pci_suspend, ++ resume: dhdpcie_pci_resume, ++#endif /* DHD_PCIE_RUNTIMEPM */ ++}; ++ ++int dhdpcie_init_succeeded = FALSE; ++ ++#ifdef USE_SMMU_ARCH_MSM ++static int dhdpcie_smmu_init(struct pci_dev *pdev, void *smmu_cxt) ++{ ++ struct dma_iommu_mapping *mapping; ++ struct device_node *root_node = NULL; ++ dhdpcie_smmu_info_t *smmu_info = (dhdpcie_smmu_info_t *)smmu_cxt; ++ int smmu_iova_address[2]; ++ char *wlan_node = "android,bcmdhd_wlan"; ++ char *wlan_smmu_node = "wlan-smmu-iova-address"; ++ int atomic_ctx = 1; ++ int s1_bypass = 1; ++ int ret = 0; ++ ++ DHD_ERROR(("%s: SMMU initialize\n", __FUNCTION__)); ++ ++ root_node = of_find_compatible_node(NULL, NULL, wlan_node); ++ if (!root_node) { ++ WARN(1, "failed to get device node of BRCM WLAN\n"); ++ return -ENODEV; ++ } ++ ++ if (of_property_read_u32_array(root_node, wlan_smmu_node, ++ smmu_iova_address, 2) == 0) { ++ DHD_ERROR(("%s : get SMMU start address 0x%x, size 0x%x\n", ++ __FUNCTION__, smmu_iova_address[0], smmu_iova_address[1])); ++ smmu_info->smmu_iova_start = smmu_iova_address[0]; ++ smmu_info->smmu_iova_len = smmu_iova_address[1]; ++ } else { ++ printf("%s : can't get smmu iova address property\n", ++ __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ if (smmu_info->smmu_iova_len <= 0) { ++ DHD_ERROR(("%s: Invalid smmu iova len %d\n", ++ __FUNCTION__, (int)smmu_info->smmu_iova_len)); ++ return -EINVAL; ++ } ++ ++ DHD_ERROR(("%s : SMMU init start\n", __FUNCTION__)); ++ mapping = arm_iommu_create_mapping(&platform_bus_type, ++ smmu_info->smmu_iova_start, smmu_info->smmu_iova_len); ++ if (IS_ERR(mapping)) { ++ DHD_ERROR(("%s: create mapping failed, err = %d\n", ++ __FUNCTION__, ret)); ++ ret = PTR_ERR(mapping); ++ goto map_fail; ++ } ++ ++ ret = iommu_domain_set_attr(mapping->domain, ++ DOMAIN_ATTR_ATOMIC, &atomic_ctx); ++ if (ret) { ++ DHD_ERROR(("%s: set atomic_ctx attribute failed, err = %d\n", ++ __FUNCTION__, ret)); ++ goto set_attr_fail; ++ } ++ ++ ret = iommu_domain_set_attr(mapping->domain, ++ DOMAIN_ATTR_S1_BYPASS, &s1_bypass); ++ if (ret < 0) { ++ DHD_ERROR(("%s: set s1_bypass attribute failed, err = %d\n", ++ __FUNCTION__, ret)); ++ goto set_attr_fail; ++ } ++ ++ ret = arm_iommu_attach_device(&pdev->dev, mapping); ++ if (ret) { ++ DHD_ERROR(("%s: attach device failed, err = %d\n", ++ __FUNCTION__, ret)); ++ goto attach_fail; ++ } ++ ++ smmu_info->smmu_mapping = mapping; ++ ++ return ret; ++ ++attach_fail: ++set_attr_fail: ++ arm_iommu_release_mapping(mapping); ++map_fail: ++ return ret; ++} ++ ++static void dhdpcie_smmu_remove(struct pci_dev *pdev, void *smmu_cxt) ++{ ++ dhdpcie_smmu_info_t *smmu_info; ++ ++ if (!smmu_cxt) { ++ return; ++ } ++ ++ smmu_info = (dhdpcie_smmu_info_t *)smmu_cxt; ++ if (smmu_info->smmu_mapping) { ++ arm_iommu_detach_device(&pdev->dev); ++ arm_iommu_release_mapping(smmu_info->smmu_mapping); ++ smmu_info->smmu_mapping = NULL; ++ } ++} ++#endif /* USE_SMMU_ARCH_MSM */ ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++static int dhdpcie_pm_suspend(struct device *dev) ++{ ++ int ret = 0; ++ struct pci_dev *pdev = to_pci_dev(dev); ++ dhdpcie_info_t *pch = pci_get_drvdata(pdev); ++ dhd_bus_t *bus = NULL; ++ unsigned long flags; ++ ++ if (pch) { ++ bus = pch->bus; ++ } ++ if (!bus) { ++ return ret; ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ if (!DHD_BUS_BUSY_CHECK_IDLE(bus->dhd)) { ++ DHD_ERROR(("%s: Bus not IDLE!! dhd_bus_busy_state = 0x%x\n", ++ __FUNCTION__, bus->dhd->dhd_bus_busy_state)); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ return -EBUSY; ++ } ++ DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ if (!bus->dhd->dongle_reset) ++ ret = dhdpcie_set_suspend_resume(bus, TRUE); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ return ret; ++ ++} ++ ++static int dhdpcie_pm_prepare(struct device *dev) ++{ ++ struct pci_dev *pdev = to_pci_dev(dev); ++ dhdpcie_info_t *pch = pci_get_drvdata(pdev); ++ dhd_bus_t *bus = NULL; ++ ++ if (pch) { ++ bus = pch->bus; ++ DHD_DISABLE_RUNTIME_PM(bus->dhd); ++ } ++ ++ bus->chk_pm = TRUE; ++ return 0; ++} ++ ++static int dhdpcie_pm_resume(struct device *dev) ++{ ++ int ret = 0; ++ struct pci_dev *pdev = to_pci_dev(dev); ++ dhdpcie_info_t *pch = pci_get_drvdata(pdev); ++ dhd_bus_t *bus = NULL; ++ unsigned long flags; ++ ++ if (pch) { ++ bus = pch->bus; ++ } ++ if (!bus) { ++ return ret; ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ if (!bus->dhd->dongle_reset) { ++ ret = dhdpcie_set_suspend_resume(bus, FALSE); ++ bus->chk_pm = FALSE; ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ return ret; ++} ++ ++static void dhdpcie_pm_complete(struct device *dev) ++{ ++ struct pci_dev *pdev = to_pci_dev(dev); ++ dhdpcie_info_t *pch = pci_get_drvdata(pdev); ++ dhd_bus_t *bus = NULL; ++ ++ if (pch) { ++ bus = pch->bus; ++ DHD_ENABLE_RUNTIME_PM(bus->dhd); ++ } ++ ++ return; ++} ++#else ++static int dhdpcie_pci_suspend(struct pci_dev * pdev, pm_message_t state) ++{ ++ int ret = 0; ++ dhdpcie_info_t *pch = pci_get_drvdata(pdev); ++ dhd_bus_t *bus = NULL; ++ unsigned long flags; ++ ++ if (pch) { ++ bus = pch->bus; ++ } ++ if (!bus) { ++ return ret; ++ } ++ ++ BCM_REFERENCE(state); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ if (!DHD_BUS_BUSY_CHECK_IDLE(bus->dhd)) { ++ DHD_ERROR(("%s: Bus not IDLE!! dhd_bus_busy_state = 0x%x\n", ++ __FUNCTION__, bus->dhd->dhd_bus_busy_state)); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ return -EBUSY; ++ } ++ DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ if (!bus->dhd->dongle_reset) ++ ret = dhdpcie_set_suspend_resume(bus, TRUE); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ return ret; ++} ++ ++static int dhdpcie_pci_resume(struct pci_dev *pdev) ++{ ++ int ret = 0; ++ dhdpcie_info_t *pch = pci_get_drvdata(pdev); ++ dhd_bus_t *bus = NULL; ++ unsigned long flags; ++ ++ if (pch) { ++ bus = pch->bus; ++ } ++ if (!bus) { ++ return ret; ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ if (!bus->dhd->dongle_reset) ++ ret = dhdpcie_set_suspend_resume(bus, FALSE); ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ return ret; ++} ++ ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++static int dhdpcie_set_suspend_resume(dhd_bus_t *bus, bool state) ++{ ++ int ret = 0; ++ ++ ASSERT(bus && !bus->dhd->dongle_reset); ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++ /* if wakelock is held during suspend, return failed */ ++ if (state == TRUE && dhd_os_check_wakelock_all(bus->dhd)) { ++ return -EBUSY; ++ } ++ mutex_lock(&bus->pm_lock); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ /* When firmware is not loaded do the PCI bus */ ++ /* suspend/resume only */ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ ret = dhdpcie_pci_suspend_resume(bus, state); ++#ifdef DHD_PCIE_RUNTIMEPM ++ mutex_unlock(&bus->pm_lock); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ return ret; ++ } ++ ++ ret = dhdpcie_bus_suspend(bus, state); ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++ mutex_unlock(&bus->pm_lock); ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++ return ret; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++extern void dhd_dpc_tasklet_kill(dhd_pub_t *dhdp); ++#endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ ++static int dhdpcie_suspend_dev(struct pci_dev *dev) ++{ ++ int ret; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ dhdpcie_info_t *pch = pci_get_drvdata(dev); ++ dhd_bus_t *bus = pch->bus; ++ ++ if (bus->is_linkdown) { ++ DHD_ERROR(("%s: PCIe link is down\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++#endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ DHD_TRACE_HW4(("%s: Enter\n", __FUNCTION__)); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ dhd_dpc_tasklet_kill(bus->dhd); ++#endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ pci_save_state(dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ pch->state = pci_store_saved_state(dev); ++#endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ pci_enable_wake(dev, PCI_D0, TRUE); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++ if (pci_is_enabled(dev)) ++#endif ++ pci_disable_device(dev); ++ ++ ret = pci_set_power_state(dev, PCI_D3hot); ++ if (ret) { ++ DHD_ERROR(("%s: pci_set_power_state error %d\n", ++ __FUNCTION__, ret)); ++ } ++// dev->state_saved = FALSE; ++ return ret; ++} ++ ++#ifdef DHD_WAKE_STATUS ++int bcmpcie_get_total_wake(struct dhd_bus *bus) ++{ ++ dhdpcie_info_t *pch = pci_get_drvdata(bus->dev); ++ ++ return pch->total_wake_count; ++} ++ ++int bcmpcie_set_get_wake(struct dhd_bus *bus, int flag) ++{ ++ dhdpcie_info_t *pch = pci_get_drvdata(bus->dev); ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&pch->pcie_lock, flags); ++ ++ ret = pch->pkt_wake; ++ pch->total_wake_count += flag; ++ pch->pkt_wake = flag; ++ ++ spin_unlock_irqrestore(&pch->pcie_lock, flags); ++ return ret; ++} ++#endif /* DHD_WAKE_STATUS */ ++ ++static int dhdpcie_resume_dev(struct pci_dev *dev) ++{ ++ int err = 0; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ dhdpcie_info_t *pch = pci_get_drvdata(dev); ++ pci_load_and_free_saved_state(dev, &pch->state); ++#endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ DHD_TRACE_HW4(("%s: Enter\n", __FUNCTION__)); ++// dev->state_saved = TRUE; ++ pci_restore_state(dev); ++ err = pci_enable_device(dev); ++ if (err) { ++ printf("%s:pci_enable_device error %d \n", __FUNCTION__, err); ++ goto out; ++ } ++ pci_set_master(dev); ++ err = pci_set_power_state(dev, PCI_D0); ++ if (err) { ++ printf("%s:pci_set_power_state error %d \n", __FUNCTION__, err); ++ goto out; ++ } ++ ++out: ++ return err; ++} ++ ++static int dhdpcie_resume_host_dev(dhd_bus_t *bus) ++{ ++ int bcmerror = 0; ++#ifdef USE_EXYNOS_PCIE_RC_PMPATCH ++ bcmerror = exynos_pcie_pm_resume(SAMSUNG_PCIE_CH_NUM); ++#endif /* USE_EXYNOS_PCIE_RC_PMPATCH */ ++#ifdef CONFIG_ARCH_MSM ++ bcmerror = dhdpcie_start_host_pcieclock(bus); ++#endif /* CONFIG_ARCH_MSM */ ++#ifdef CONFIG_ARCH_TEGRA ++ bcmerror = tegra_pcie_pm_resume(); ++#endif /* CONFIG_ARCH_TEGRA */ ++ if (bcmerror < 0) { ++ DHD_ERROR(("%s: PCIe RC resume failed!!! (%d)\n", ++ __FUNCTION__, bcmerror)); ++ bus->is_linkdown = 1; ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++#ifdef CONFIG_ARCH_MSM ++ bus->no_cfg_restore = 1; ++#endif /* CONFIG_ARCH_MSM */ ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ } ++ ++ return bcmerror; ++} ++ ++static int dhdpcie_suspend_host_dev(dhd_bus_t *bus) ++{ ++ int bcmerror = 0; ++#ifdef USE_EXYNOS_PCIE_RC_PMPATCH ++ if (bus->rc_dev) { ++ pci_save_state(bus->rc_dev); ++ } else { ++ DHD_ERROR(("%s: RC %x:%x handle is NULL\n", ++ __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID)); ++ } ++ exynos_pcie_pm_suspend(SAMSUNG_PCIE_CH_NUM); ++#endif /* USE_EXYNOS_PCIE_RC_PMPATCH */ ++#ifdef CONFIG_ARCH_MSM ++ bcmerror = dhdpcie_stop_host_pcieclock(bus); ++#endif /* CONFIG_ARCH_MSM */ ++#ifdef CONFIG_ARCH_TEGRA ++ bcmerror = tegra_pcie_pm_suspend(); ++#endif /* CONFIG_ARCH_TEGRA */ ++ return bcmerror; ++} ++ ++#if defined(PCIE_RC_VENDOR_ID) && defined(PCIE_RC_DEVICE_ID) ++uint32 ++dhdpcie_rc_config_read(dhd_bus_t *bus, uint offset) ++{ ++ uint val = -1; /* Initialise to 0xfffffff */ ++ if (bus->rc_dev) { ++ pci_read_config_dword(bus->rc_dev, offset, &val); ++ OSL_DELAY(100); ++ } else { ++ DHD_ERROR(("%s: RC %x:%x handle is NULL\n", ++ __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID)); ++ } ++ DHD_ERROR(("%s: RC %x:%x offset 0x%x val 0x%x\n", ++ __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID, offset, val)); ++ return (val); ++} ++ ++/* ++ * Reads/ Writes the value of capability register ++ * from the given CAP_ID section of PCI Root Port ++ * ++ * Arguements ++ * @bus current dhd_bus_t pointer ++ * @cap Capability or Extended Capability ID to get ++ * @offset offset of Register to Read ++ * @is_ext TRUE if @cap is given for Extended Capability ++ * @is_write is set to TRUE to indicate write ++ * @val value to write ++ * ++ * Return Value ++ * Returns 0xffffffff on error ++ * on write success returns BCME_OK (0) ++ * on Read Success returns the value of register requested ++ * Note: caller shoud ensure valid capability ID and Ext. Capability ID. ++ */ ++ ++uint32 ++dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext, bool is_write, ++ uint32 writeval) ++{ ++ int cap_ptr = 0; ++ uint32 ret = -1; ++ uint32 readval; ++ ++ if (!(bus->rc_dev)) { ++ DHD_ERROR(("%s: RC %x:%x handle is NULL\n", ++ __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID)); ++ return ret; ++ } ++ ++ /* Find Capability offset */ ++ if (is_ext) { ++ /* removing max EXT_CAP_ID check as ++ * linux kernel definition's max value is not upadted yet as per spec ++ */ ++ cap_ptr = pci_find_ext_capability(bus->rc_dev, cap); ++ ++ } else { ++ /* removing max PCI_CAP_ID_MAX check as ++ * pervious kernel versions dont have this definition ++ */ ++ cap_ptr = pci_find_capability(bus->rc_dev, cap); ++ } ++ ++ /* Return if capability with given ID not found */ ++ if (cap_ptr == 0) { ++ DHD_ERROR(("%s: RC %x:%x PCI Cap(0x%02x) not supported.\n", ++ __FUNCTION__, PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID, cap)); ++ return BCME_ERROR; ++ } ++ ++ if (is_write) { ++ ret = pci_write_config_dword(bus->rc_dev, (cap_ptr + offset), writeval); ++ if (ret) { ++ DHD_ERROR(("%s: pci_write_config_dword failed. cap=%d offset=%d\n", ++ __FUNCTION__, cap, offset)); ++ return BCME_ERROR; ++ } ++ ret = BCME_OK; ++ ++ } else { ++ ++ ret = pci_read_config_dword(bus->rc_dev, (cap_ptr + offset), &readval); ++ ++ if (ret) { ++ DHD_ERROR(("%s: pci_read_config_dword failed. cap=%d offset=%d\n", ++ __FUNCTION__, cap, offset)); ++ return BCME_ERROR; ++ } ++ ret = readval; ++ } ++ ++ return ret; ++} ++ ++/* API wrapper to read Root Port link capability ++ * Returns 2 = GEN2 1 = GEN1 BCME_ERR on linkcap not found ++ */ ++ ++uint32 dhd_debug_get_rc_linkcap(dhd_bus_t *bus) ++{ ++ uint32 linkcap = -1; ++ linkcap = dhdpcie_rc_access_cap(bus, PCIE_CAP_ID_EXP, ++ PCIE_CAP_LINKCAP_OFFSET, FALSE, FALSE, 0); ++ linkcap &= PCIE_CAP_LINKCAP_LNKSPEED_MASK; ++ return linkcap; ++} ++#endif ++ ++int dhdpcie_pci_suspend_resume(dhd_bus_t *bus, bool state) ++{ ++ int rc; ++ ++ struct pci_dev *dev = bus->dev; ++ ++ if (state) { ++#ifndef BCMPCIE_OOB_HOST_WAKE ++ dhdpcie_pme_active(bus->osh, state); ++#endif /* !BCMPCIE_OOB_HOST_WAKE */ ++ rc = dhdpcie_suspend_dev(dev); ++ if (!rc) { ++ dhdpcie_suspend_host_dev(bus); ++ } ++ } else { ++ dhdpcie_resume_host_dev(bus); ++ rc = dhdpcie_resume_dev(dev); ++#ifndef BCMPCIE_OOB_HOST_WAKE ++ dhdpcie_pme_active(bus->osh, state); ++#endif /* !BCMPCIE_OOB_HOST_WAKE */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++#if defined(DHD_HANG_SEND_UP_TEST) ++ if (bus->is_linkdown || ++ bus->dhd->req_hang_type == HANG_REASON_PCIE_RC_LINK_UP_FAIL) ++#else /* DHD_HANG_SEND_UP_TEST */ ++ if (bus->is_linkdown) ++#endif /* DHD_HANG_SEND_UP_TEST */ ++ { ++ bus->dhd->hang_reason = HANG_REASON_PCIE_RC_LINK_UP_FAIL; ++ dhd_os_send_hang_message(bus->dhd); ++ } ++#endif ++ } ++ return rc; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++static int dhdpcie_device_scan(struct device *dev, void *data) ++{ ++ struct pci_dev *pcidev; ++ int *cnt = data; ++ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ pcidev = container_of(dev, struct pci_dev, dev); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ if (pcidev->vendor != 0x14e4) ++ return 0; ++ ++ DHD_INFO(("Found Broadcom PCI device 0x%04x\n", pcidev->device)); ++ *cnt += 1; ++ if (pcidev->driver && strcmp(pcidev->driver->name, dhdpcie_driver.name)) ++ DHD_ERROR(("Broadcom PCI Device 0x%04x has allocated with driver %s\n", ++ pcidev->device, pcidev->driver->name)); ++ ++ return 0; ++} ++#endif /* LINUX_VERSION >= 2.6.0 */ ++ ++int ++dhdpcie_bus_register(void) ++{ ++ int error = 0; ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++ if (!(error = pci_module_init(&dhdpcie_driver))) ++ return 0; ++ ++ DHD_ERROR(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error)); ++#else ++ if (!(error = pci_register_driver(&dhdpcie_driver))) { ++ bus_for_each_dev(dhdpcie_driver.driver.bus, NULL, &error, dhdpcie_device_scan); ++ if (!error) { ++ DHD_ERROR(("No Broadcom PCI device enumerated!\n")); ++ } else if (!dhdpcie_init_succeeded) { ++ DHD_ERROR(("%s: dhdpcie initialize failed.\n", __FUNCTION__)); ++ } else { ++ return 0; ++ } ++ ++ pci_unregister_driver(&dhdpcie_driver); ++ error = BCME_ERROR; ++ } ++#endif /* LINUX_VERSION < 2.6.0 */ ++ ++ return error; ++} ++ ++ ++void ++dhdpcie_bus_unregister(void) ++{ ++ pci_unregister_driver(&dhdpcie_driver); ++} ++ ++int __devinit ++dhdpcie_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ++{ ++ int err = 0; ++ DHD_MUTEX_LOCK(); ++ ++ if (dhdpcie_chipmatch (pdev->vendor, pdev->device)) { ++ DHD_ERROR(("%s: chipmatch failed!!\n", __FUNCTION__)); ++ err = -ENODEV; ++ goto exit; ++ } ++ printf("PCI_PROBE: bus %X, slot %X,vendor %X, device %X" ++ "(good PCI location)\n", pdev->bus->number, ++ PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device); ++ ++ if (dhdpcie_init (pdev)) { ++ DHD_ERROR(("%s: PCIe Enumeration failed\n", __FUNCTION__)); ++ err = -ENODEV; ++ goto exit; ++ } ++ ++#ifdef BCMPCIE_DISABLE_ASYNC_SUSPEND ++ /* disable async suspend */ ++ device_disable_async_suspend(&pdev->dev); ++#endif /* BCMPCIE_DISABLE_ASYNC_SUSPEND */ ++ ++ DHD_TRACE(("%s: PCIe Enumeration done!!\n", __FUNCTION__)); ++ ++exit: ++ DHD_MUTEX_UNLOCK(); ++ return err; ++} ++ ++int ++dhdpcie_detach(dhdpcie_info_t *pch) ++{ ++ if (pch) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ if (!dhd_download_fw_on_driverload) { ++ pci_load_and_free_saved_state(pch->dev, &pch->default_state); ++ } ++#endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ MFREE(pch->osh, pch, sizeof(dhdpcie_info_t)); ++ } ++ return 0; ++} ++ ++ ++void __devexit ++dhdpcie_pci_remove(struct pci_dev *pdev) ++{ ++ osl_t *osh = NULL; ++ dhdpcie_info_t *pch = NULL; ++ dhd_bus_t *bus = NULL; ++ ++ DHD_TRACE(("%s Enter\n", __FUNCTION__)); ++ ++ DHD_MUTEX_LOCK(); ++ ++ pch = pci_get_drvdata(pdev); ++ bus = pch->bus; ++ osh = pch->osh; ++ ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ if (bus) { ++#ifdef CONFIG_ARCH_MSM ++ msm_pcie_deregister_event(&bus->pcie_event); ++#endif /* CONFIG_ARCH_MSM */ ++#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY ++#ifdef CONFIG_SOC_EXYNOS8890 ++ exynos_pcie_deregister_event(&bus->pcie_event); ++#endif /* CONFIG_SOC_EXYNOS8890 */ ++#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */ ++ } ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ ++ bus->rc_dev = NULL; ++ ++ dhdpcie_bus_release(bus); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++ if (pci_is_enabled(pdev)) ++#endif ++ pci_disable_device(pdev); ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ /* pcie os info detach */ ++ MFREE(osh, pch->os_cxt, sizeof(dhdpcie_os_info_t)); ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++#ifdef USE_SMMU_ARCH_MSM ++ /* smmu info detach */ ++ dhdpcie_smmu_remove(pdev, pch->smmu_cxt); ++ MFREE(osh, pch->smmu_cxt, sizeof(dhdpcie_smmu_info_t)); ++#endif /* USE_SMMU_ARCH_MSM */ ++ /* pcie info detach */ ++ dhdpcie_detach(pch); ++ /* osl detach */ ++ osl_detach(osh); ++ ++#if defined(BCMPCIE_OOB_HOST_WAKE) && defined(CUSTOMER_HW2) && \ ++ defined(CONFIG_ARCH_APQ8084) ++ brcm_pcie_wake.wake_irq = NULL; ++ brcm_pcie_wake.data = NULL; ++#endif /* BCMPCIE_OOB_HOST_WAKE && CUSTOMR_HW2 && CONFIG_ARCH_APQ8084 */ ++ ++ dhdpcie_init_succeeded = FALSE; ++ ++ DHD_MUTEX_UNLOCK(); ++ ++ DHD_TRACE(("%s Exit\n", __FUNCTION__)); ++ ++ return; ++} ++ ++/* Free Linux irq */ ++int ++dhdpcie_request_irq(dhdpcie_info_t *dhdpcie_info) ++{ ++ dhd_bus_t *bus = dhdpcie_info->bus; ++ struct pci_dev *pdev = dhdpcie_info->bus->dev; ++ int err = 0; ++ ++ if (!bus->irq_registered) { ++ snprintf(dhdpcie_info->pciname, sizeof(dhdpcie_info->pciname), ++ "dhdpcie:%s", pci_name(pdev)); ++#ifdef DHD_USE_MSI ++ printf("%s: MSI enabled\n", __FUNCTION__); ++ err = pci_enable_msi(pdev); ++ if (err < 0) { ++ DHD_ERROR(("%s: pci_enable_msi() failed, %d, fall back to INTx\n", __FUNCTION__, err)); ++ } ++#else ++ printf("%s: MSI not enabled\n", __FUNCTION__); ++#endif /* DHD_USE_MSI */ ++ err = request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED, ++ dhdpcie_info->pciname, bus); ++ if (err) { ++ DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__)); ++#ifdef DHD_USE_MSI ++ pci_disable_msi(pdev); ++#endif /* DHD_USE_MSI */ ++ return -1; ++ } else { ++ bus->irq_registered = TRUE; ++ } ++ } else { ++ DHD_ERROR(("%s: PCI IRQ is already registered\n", __FUNCTION__)); ++ } ++ ++ if (!dhdpcie_irq_enabled(bus)) { ++ DHD_ERROR(("%s: PCIe IRQ was disabled, so, enabled it again\n", __FUNCTION__)); ++ dhdpcie_enable_irq(bus); ++ } ++ ++ DHD_TRACE(("%s %s\n", __FUNCTION__, dhdpcie_info->pciname)); ++ ++ ++ return 0; /* SUCCESS */ ++} ++ ++/** ++ * dhdpcie_get_pcieirq - return pcie irq number to linux-dhd ++ */ ++int ++dhdpcie_get_pcieirq(struct dhd_bus *bus, unsigned int *irq) ++{ ++ struct pci_dev *pdev = bus->dev; ++ ++ if (!pdev) { ++ DHD_ERROR(("%s : bus->dev is NULL\n", __FUNCTION__)); ++ return -ENODEV; ++ } ++ ++ *irq = pdev->irq; ++ ++ return 0; /* SUCCESS */ ++} ++ ++#ifdef CONFIG_PHYS_ADDR_T_64BIT ++#define PRINTF_RESOURCE "0x%016llx" ++#else ++#define PRINTF_RESOURCE "0x%08x" ++#endif ++ ++/* ++ ++Name: osl_pci_get_resource ++ ++Parametrs: ++ ++1: struct pci_dev *pdev -- pci device structure ++2: pci_res -- structure containing pci configuration space values ++ ++ ++Return value: ++ ++int - Status (TRUE or FALSE) ++ ++Description: ++Access PCI configuration space, retrieve PCI allocated resources , updates in resource structure. ++ ++ */ ++int dhdpcie_get_resource(dhdpcie_info_t *dhdpcie_info) ++{ ++ phys_addr_t bar0_addr, bar1_addr; ++ ulong bar1_size; ++ struct pci_dev *pdev = NULL; ++ pdev = dhdpcie_info->dev; ++#ifdef EXYNOS_PCIE_MODULE_PATCH ++ pci_restore_state(pdev); ++#endif /* EXYNOS_MODULE_PATCH */ ++ do { ++ if (pci_enable_device(pdev)) { ++ printf("%s: Cannot enable PCI device\n", __FUNCTION__); ++ break; ++ } ++ pci_set_master(pdev); ++ bar0_addr = pci_resource_start(pdev, 0); /* Bar-0 mapped address */ ++ bar1_addr = pci_resource_start(pdev, 2); /* Bar-1 mapped address */ ++ ++ /* read Bar-1 mapped memory range */ ++ bar1_size = pci_resource_len(pdev, 2); ++ ++ if ((bar1_size == 0) || (bar1_addr == 0)) { ++ printf("%s: BAR1 Not enabled for this device size(%ld)," ++ " addr(0x"PRINTF_RESOURCE")\n", ++ __FUNCTION__, bar1_size, bar1_addr); ++ goto err; ++ } ++ ++ dhdpcie_info->regs = (volatile char *) REG_MAP(bar0_addr, DONGLE_REG_MAP_SIZE); ++ dhdpcie_info->tcm_size = ++ (bar1_size > DONGLE_TCM_MAP_SIZE) ? bar1_size : DONGLE_TCM_MAP_SIZE; ++ dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, dhdpcie_info->tcm_size); ++ ++ if (!dhdpcie_info->regs || !dhdpcie_info->tcm) { ++ DHD_ERROR(("%s:ioremap() failed\n", __FUNCTION__)); ++ break; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ if (!dhd_download_fw_on_driverload) { ++ /* Backup PCIe configuration so as to use Wi-Fi on/off process ++ * in case of built in driver ++ */ ++ pci_save_state(pdev); ++ dhdpcie_info->default_state = pci_store_saved_state(pdev); ++ ++ if (dhdpcie_info->default_state == NULL) { ++ DHD_ERROR(("%s pci_store_saved_state returns NULL\n", ++ __FUNCTION__)); ++ REG_UNMAP(dhdpcie_info->regs); ++ REG_UNMAP(dhdpcie_info->tcm); ++ pci_disable_device(pdev); ++ break; ++ } ++ } ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ ++#ifdef EXYNOS_PCIE_MODULE_PATCH ++ pci_save_state(pdev); ++#endif /* EXYNOS_MODULE_PATCH */ ++ ++ DHD_TRACE(("%s:Phys addr : reg space = %p base addr 0x"PRINTF_RESOURCE" \n", ++ __FUNCTION__, dhdpcie_info->regs, bar0_addr)); ++ DHD_TRACE(("%s:Phys addr : tcm_space = %p base addr 0x"PRINTF_RESOURCE" \n", ++ __FUNCTION__, dhdpcie_info->tcm, bar1_addr)); ++ ++ return 0; /* SUCCESS */ ++ } while (0); ++err: ++ return -1; /* FAILURE */ ++} ++ ++int dhdpcie_scan_resource(dhdpcie_info_t *dhdpcie_info) ++{ ++ ++ DHD_TRACE(("%s: ENTER\n", __FUNCTION__)); ++ ++ do { ++ /* define it here only!! */ ++ if (dhdpcie_get_resource (dhdpcie_info)) { ++ DHD_ERROR(("%s: Failed to get PCI resources\n", __FUNCTION__)); ++ break; ++ } ++ DHD_TRACE(("%s:Exit - SUCCESS \n", ++ __FUNCTION__)); ++ ++ return 0; /* SUCCESS */ ++ ++ } while (0); ++ ++ DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__)); ++ ++ return -1; /* FAILURE */ ++ ++} ++ ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++#if defined(CONFIG_ARCH_MSM) || (defined(EXYNOS_PCIE_LINKDOWN_RECOVERY) && \ ++ (defined(CONFIG_SOC_EXYNOS8890) || defined(CONFIG_SOC_EXYNOS8895))) ++void dhdpcie_linkdown_cb(struct_pcie_notify *noti) ++{ ++ struct pci_dev *pdev = (struct pci_dev *)noti->user; ++ dhdpcie_info_t *pch = NULL; ++ ++ if (pdev) { ++ pch = pci_get_drvdata(pdev); ++ if (pch) { ++ dhd_bus_t *bus = pch->bus; ++ if (bus) { ++ dhd_pub_t *dhd = bus->dhd; ++ if (dhd) { ++ DHD_ERROR(("%s: Event HANG send up " ++ "due to PCIe linkdown\n", ++ __FUNCTION__)); ++#ifdef CONFIG_ARCH_MSM ++ bus->no_cfg_restore = 1; ++#endif /* CONFIG_ARCH_MSM */ ++ bus->is_linkdown = 1; ++ DHD_OS_WAKE_LOCK(dhd); ++ dhd->hang_reason = HANG_REASON_PCIE_LINK_DOWN; ++ dhd_os_send_hang_message(dhd); ++ } ++ } ++ } ++ } ++ ++} ++#endif ++/* CONFIG_ARCH_MSM || (EXYNOS_PCIE_LINKDOWN_RECOVERY && ++ * (CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895)) ++ */ ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ ++int dhdpcie_init(struct pci_dev *pdev) ++{ ++ ++ osl_t *osh = NULL; ++ dhd_bus_t *bus = NULL; ++ dhdpcie_info_t *dhdpcie_info = NULL; ++ wifi_adapter_info_t *adapter = NULL; ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ dhdpcie_os_info_t *dhdpcie_osinfo = NULL; ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++#ifdef USE_SMMU_ARCH_MSM ++ dhdpcie_smmu_info_t *dhdpcie_smmu_info = NULL; ++#endif /* USE_SMMU_ARCH_MSM */ ++ ++ do { ++ /* osl attach */ ++ if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) { ++ DHD_ERROR(("%s: osl_attach failed\n", __FUNCTION__)); ++ break; ++ } ++ ++ /* initialize static buffer */ ++ adapter = dhd_wifi_platform_get_adapter(PCI_BUS, pdev->bus->number, ++ PCI_SLOT(pdev->devfn)); ++ if (adapter != NULL) { ++ DHD_ERROR(("%s: found adapter info '%s'\n", __FUNCTION__, adapter->name)); ++#ifdef BUS_POWER_RESTORE ++ adapter->pci_dev = pdev; ++#endif ++ } else ++ DHD_ERROR(("%s: can't find adapter info for this chip\n", __FUNCTION__)); ++ osl_static_mem_init(osh, adapter); ++ ++ /* Set ACP coherence flag */ ++ if (OSL_ACP_WAR_ENAB() || OSL_ARCH_IS_COHERENT()) ++ osl_flag_set(osh, OSL_ACP_COHERENCE); ++ ++ /* allocate linux spcific pcie structure here */ ++ if (!(dhdpcie_info = MALLOC(osh, sizeof(dhdpcie_info_t)))) { ++ DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); ++ break; ++ } ++ bzero(dhdpcie_info, sizeof(dhdpcie_info_t)); ++ dhdpcie_info->osh = osh; ++ dhdpcie_info->dev = pdev; ++ ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ /* allocate OS speicific structure */ ++ dhdpcie_osinfo = MALLOC(osh, sizeof(dhdpcie_os_info_t)); ++ if (dhdpcie_osinfo == NULL) { ++ DHD_ERROR(("%s: MALLOC of dhdpcie_os_info_t failed\n", ++ __FUNCTION__)); ++ break; ++ } ++ bzero(dhdpcie_osinfo, sizeof(dhdpcie_os_info_t)); ++ dhdpcie_info->os_cxt = (void *)dhdpcie_osinfo; ++ ++ /* Initialize host wake IRQ */ ++ spin_lock_init(&dhdpcie_osinfo->oob_irq_spinlock); ++ /* Get customer specific host wake IRQ parametres: IRQ number as IRQ type */ ++ dhdpcie_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter, ++ &dhdpcie_osinfo->oob_irq_flags); ++ if (dhdpcie_osinfo->oob_irq_num < 0) { ++ DHD_ERROR(("%s: Host OOB irq is not defined\n", __FUNCTION__)); ++ } ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ ++#ifdef USE_SMMU_ARCH_MSM ++ /* allocate private structure for using SMMU */ ++ dhdpcie_smmu_info = MALLOC(osh, sizeof(dhdpcie_smmu_info_t)); ++ if (dhdpcie_smmu_info == NULL) { ++ DHD_ERROR(("%s: MALLOC of dhdpcie_smmu_info_t failed\n", ++ __FUNCTION__)); ++ break; ++ } ++ bzero(dhdpcie_smmu_info, sizeof(dhdpcie_smmu_info_t)); ++ dhdpcie_info->smmu_cxt = (void *)dhdpcie_smmu_info; ++ ++ /* Initialize smmu structure */ ++ if (dhdpcie_smmu_init(pdev, dhdpcie_info->smmu_cxt) < 0) { ++ DHD_ERROR(("%s: Failed to initialize SMMU\n", ++ __FUNCTION__)); ++ break; ++ } ++#endif /* USE_SMMU_ARCH_MSM */ ++ ++#ifdef DHD_WAKE_STATUS ++ /* Initialize pcie_lock */ ++ spin_lock_init(&dhdpcie_info->pcie_lock); ++#endif /* DHD_WAKE_STATUS */ ++ ++ /* Find the PCI resources, verify the */ ++ /* vendor and device ID, map BAR regions and irq, update in structures */ ++ if (dhdpcie_scan_resource(dhdpcie_info)) { ++ DHD_ERROR(("%s: dhd_Scan_PCI_Res failed\n", __FUNCTION__)); ++ ++ break; ++ } ++ ++ /* Bus initialization */ ++ bus = dhdpcie_bus_attach(osh, dhdpcie_info->regs, dhdpcie_info->tcm, pdev); ++ if (!bus) { ++ DHD_ERROR(("%s:dhdpcie_bus_attach() failed\n", __FUNCTION__)); ++ break; ++ } ++ ++ dhdpcie_info->bus = bus; ++ bus->is_linkdown = 0; ++ ++ /* Get RC Device Handle */ ++#if defined(PCIE_RC_VENDOR_ID) && defined(PCIE_RC_DEVICE_ID) ++ bus->rc_dev = pci_get_device(PCIE_RC_VENDOR_ID, PCIE_RC_DEVICE_ID, NULL); ++#else ++ bus->rc_dev = NULL; ++#endif ++ ++#if defined(BCMPCIE_OOB_HOST_WAKE) && defined(CUSTOMER_HW2) && \ ++ defined(CONFIG_ARCH_APQ8084) ++ brcm_pcie_wake.wake_irq = wlan_oob_irq; ++ brcm_pcie_wake.data = bus; ++#endif /* BCMPCIE_OOB_HOST_WAKE && CUSTOMR_HW2 && CONFIG_ARCH_APQ8084 */ ++ ++#ifdef DONGLE_ENABLE_ISOLATION ++ bus->dhd->dongle_isolation = TRUE; ++#endif /* DONGLE_ENABLE_ISOLATION */ ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++#ifdef CONFIG_ARCH_MSM ++ bus->pcie_event.events = MSM_PCIE_EVENT_LINKDOWN; ++ bus->pcie_event.user = pdev; ++ bus->pcie_event.mode = MSM_PCIE_TRIGGER_CALLBACK; ++ bus->pcie_event.callback = dhdpcie_linkdown_cb; ++ bus->pcie_event.options = MSM_PCIE_CONFIG_NO_RECOVERY; ++ msm_pcie_register_event(&bus->pcie_event); ++ bus->no_cfg_restore = 0; ++#endif /* CONFIG_ARCH_MSM */ ++#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY ++#if defined(CONFIG_SOC_EXYNOS8890) || defined(CONFIG_SOC_EXYNOS8895) ++ bus->pcie_event.events = EXYNOS_PCIE_EVENT_LINKDOWN; ++ bus->pcie_event.user = pdev; ++ bus->pcie_event.mode = EXYNOS_PCIE_TRIGGER_CALLBACK; ++ bus->pcie_event.callback = dhdpcie_linkdown_cb; ++ exynos_pcie_register_event(&bus->pcie_event); ++#endif /* CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895 */ ++#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */ ++ bus->read_shm_fail = FALSE; ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ ++ if (bus->intr) { ++ /* Register interrupt callback, but mask it (not operational yet). */ ++ DHD_INTR(("%s: Registering and masking interrupts\n", __FUNCTION__)); ++ dhdpcie_bus_intr_disable(bus); ++ ++ if (dhdpcie_request_irq(dhdpcie_info)) { ++ DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__)); ++ break; ++ } ++ } else { ++ bus->pollrate = 1; ++ DHD_INFO(("%s: PCIe interrupt function is NOT registered " ++ "due to polling mode\n", __FUNCTION__)); ++ } ++ ++#if defined(BCM_REQUEST_FW) ++ if (dhd_bus_download_firmware(bus, osh, NULL, NULL) < 0) { ++ DHD_ERROR(("%s: failed to download firmware\n", __FUNCTION__)); ++ } ++ bus->nv_path = NULL; ++ bus->fw_path = NULL; ++#endif /* BCM_REQUEST_FW */ ++ ++ /* set private data for pci_dev */ ++ pci_set_drvdata(pdev, dhdpcie_info); ++ ++ if (dhd_download_fw_on_driverload) { ++ if (dhd_bus_start(bus->dhd)) { ++ DHD_ERROR(("%s: dhd_bud_start() failed\n", __FUNCTION__)); ++ if (!allow_delay_fwdl) ++ break; ++ } ++ } else { ++ /* Set ramdom MAC address during boot time */ ++ get_random_bytes(&bus->dhd->mac.octet[3], 3); ++ /* Adding BRCM OUI */ ++ bus->dhd->mac.octet[0] = 0; ++ bus->dhd->mac.octet[1] = 0x90; ++ bus->dhd->mac.octet[2] = 0x4C; ++ } ++ ++ /* Attach to the OS network interface */ ++ DHD_TRACE(("%s(): Calling dhd_register_if() \n", __FUNCTION__)); ++ if (dhd_register_if(bus->dhd, 0, TRUE)) { ++ DHD_ERROR(("%s(): ERROR.. dhd_register_if() failed\n", __FUNCTION__)); ++ break; ++ } ++ ++ dhdpcie_init_succeeded = TRUE; ++ ++#if defined(MULTIPLE_SUPPLICANT) ++ wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe ++#endif /* MULTIPLE_SUPPLICANT */ ++ ++ DHD_TRACE(("%s:Exit - SUCCESS \n", __FUNCTION__)); ++ return 0; /* return SUCCESS */ ++ ++ } while (0); ++ /* reverse the initialization in order in case of error */ ++ ++ if (bus) ++ dhdpcie_bus_release(bus); ++ ++#ifdef BCMPCIE_OOB_HOST_WAKE ++ if (dhdpcie_osinfo) { ++ MFREE(osh, dhdpcie_osinfo, sizeof(dhdpcie_os_info_t)); ++ } ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ ++#ifdef USE_SMMU_ARCH_MSM ++ if (dhdpcie_smmu_info) { ++ MFREE(osh, dhdpcie_smmu_info, sizeof(dhdpcie_smmu_info_t)); ++ dhdpcie_info->smmu_cxt = NULL; ++ } ++#endif /* USE_SMMU_ARCH_MSM */ ++ ++ if (dhdpcie_info) ++ dhdpcie_detach(dhdpcie_info); ++ pci_disable_device(pdev); ++ if (osh) ++ osl_detach(osh); ++ ++ dhdpcie_init_succeeded = FALSE; ++ ++ DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__)); ++ ++ return -1; /* return FAILURE */ ++} ++ ++/* Free Linux irq */ ++void ++dhdpcie_free_irq(dhd_bus_t *bus) ++{ ++ struct pci_dev *pdev = NULL; ++ ++ DHD_TRACE(("%s: freeing up the IRQ\n", __FUNCTION__)); ++ if (bus) { ++ pdev = bus->dev; ++ if (bus->irq_registered) { ++ free_irq(pdev->irq, bus); ++ bus->irq_registered = FALSE; ++#ifdef DHD_USE_MSI ++ pci_disable_msi(pdev); ++#endif /* DHD_USE_MSI */ ++ } else { ++ DHD_ERROR(("%s: PCIe IRQ is not registered\n", __FUNCTION__)); ++ } ++ } ++ DHD_TRACE(("%s: Exit\n", __FUNCTION__)); ++ return; ++} ++ ++/* ++ ++Name: dhdpcie_isr ++ ++Parametrs: ++ ++1: IN int irq -- interrupt vector ++2: IN void *arg -- handle to private data structure ++ ++Return value: ++ ++Status (TRUE or FALSE) ++ ++Description: ++Interrupt Service routine checks for the status register, ++disable interrupt and queue DPC if mail box interrupts are raised. ++*/ ++ ++ ++irqreturn_t ++dhdpcie_isr(int irq, void *arg) ++{ ++ dhd_bus_t *bus = (dhd_bus_t*)arg; ++ if (dhdpcie_bus_isr(bus)) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++int ++dhdpcie_disable_irq_nosync(dhd_bus_t *bus) ++{ ++ struct pci_dev *dev; ++ if ((bus == NULL) || (bus->dev == NULL)) { ++ DHD_ERROR(("%s: bus or bus->dev is NULL\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ dev = bus->dev; ++ disable_irq_nosync(dev->irq); ++ return BCME_OK; ++} ++ ++int ++dhdpcie_disable_irq(dhd_bus_t *bus) ++{ ++ struct pci_dev *dev; ++ if ((bus == NULL) || (bus->dev == NULL)) { ++ DHD_ERROR(("%s: bus or bus->dev is NULL\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ dev = bus->dev; ++ disable_irq(dev->irq); ++ return BCME_OK; ++} ++ ++int ++dhdpcie_enable_irq(dhd_bus_t *bus) ++{ ++ struct pci_dev *dev; ++ if ((bus == NULL) || (bus->dev == NULL)) { ++ DHD_ERROR(("%s: bus or bus->dev is NULL\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ dev = bus->dev; ++ enable_irq(dev->irq); ++ return BCME_OK; ++} ++ ++bool ++dhdpcie_irq_enabled(dhd_bus_t *bus) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) ++ struct irq_desc *desc = irq_to_desc(bus->dev->irq); ++ /* depth will be zero, if enabled */ ++ if (!desc->depth) { ++ DHD_ERROR(("%s: depth:%d\n", __FUNCTION__, desc->depth)); ++ } ++ return desc->depth ? FALSE : TRUE; ++#else ++ /* return TRUE by default as there is no support for lower versions */ ++ return TRUE; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++} ++ ++int ++dhdpcie_start_host_pcieclock(dhd_bus_t *bus) ++{ ++ int ret = 0; ++#ifdef CONFIG_ARCH_MSM ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ int options = 0; ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++#endif /* CONFIG_ARCH_MSM */ ++ DHD_TRACE(("%s Enter:\n", __FUNCTION__)); ++ ++ if (bus == NULL) { ++ return BCME_ERROR; ++ } ++ ++ if (bus->dev == NULL) { ++ return BCME_ERROR; ++ } ++ ++#ifdef CONFIG_ARCH_MSM ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ if (bus->no_cfg_restore) { ++ options = MSM_PCIE_CONFIG_NO_CFG_RESTORE; ++ } ++ ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number, ++ bus->dev, NULL, options); ++ if (bus->no_cfg_restore && !ret) { ++ msm_pcie_recover_config(bus->dev); ++ bus->no_cfg_restore = 0; ++ } ++#else ++ ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number, ++ bus->dev, NULL, 0); ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ if (ret) { ++ DHD_ERROR(("%s Failed to bring up PCIe link\n", __FUNCTION__)); ++ goto done; ++ } ++ ++done: ++#endif /* CONFIG_ARCH_MSM */ ++ DHD_TRACE(("%s Exit:\n", __FUNCTION__)); ++ return ret; ++} ++ ++int ++dhdpcie_stop_host_pcieclock(dhd_bus_t *bus) ++{ ++ int ret = 0; ++#ifdef CONFIG_ARCH_MSM ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ int options = 0; ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++#endif /* CONFIG_ARCH_MSM */ ++ ++ DHD_TRACE(("%s Enter:\n", __FUNCTION__)); ++ ++ if (bus == NULL) { ++ return BCME_ERROR; ++ } ++ ++ if (bus->dev == NULL) { ++ return BCME_ERROR; ++ } ++ ++#ifdef CONFIG_ARCH_MSM ++#ifdef SUPPORT_LINKDOWN_RECOVERY ++ /* Always reset the PCIe host when wifi off */ ++ bus->no_cfg_restore = 1; ++ ++ if (bus->no_cfg_restore) { ++ options = MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN; ++ } ++ ++ ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number, ++ bus->dev, NULL, options); ++#else ++ ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number, ++ bus->dev, NULL, 0); ++#endif /* SUPPORT_LINKDOWN_RECOVERY */ ++ if (ret) { ++ DHD_ERROR(("Failed to stop PCIe link\n")); ++ goto done; ++ } ++done: ++#endif /* CONFIG_ARCH_MSM */ ++ DHD_TRACE(("%s Exit:\n", __FUNCTION__)); ++ return ret; ++} ++ ++int ++dhdpcie_disable_device(dhd_bus_t *bus) ++{ ++ DHD_TRACE(("%s Enter:\n", __FUNCTION__)); ++ ++ if (bus == NULL) { ++ return BCME_ERROR; ++ } ++ ++ if (bus->dev == NULL) { ++ return BCME_ERROR; ++ } ++ ++ pci_disable_device(bus->dev); ++ ++ return 0; ++} ++ ++int ++dhdpcie_enable_device(dhd_bus_t *bus) ++{ ++ int ret = BCME_ERROR; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ dhdpcie_info_t *pch; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ ++ ++ DHD_TRACE(("%s Enter:\n", __FUNCTION__)); ++ ++ if (bus == NULL) { ++ return BCME_ERROR; ++ } ++ ++ if (bus->dev == NULL) { ++ return BCME_ERROR; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) ++ pch = pci_get_drvdata(bus->dev); ++ if (pch == NULL) { ++ return BCME_ERROR; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) && (LINUX_VERSION_CODE < \ ++ KERNEL_VERSION(3, 19, 0)) && !defined(CONFIG_SOC_EXYNOS8890) ++ /* Updated with pci_load_and_free_saved_state to compatible ++ * with Kernel version 3.14.0 to 3.18.41. ++ */ ++ pci_load_and_free_saved_state(bus->dev, &pch->default_state); ++ pch->default_state = pci_store_saved_state(bus->dev); ++#else ++ pci_load_saved_state(bus->dev, pch->default_state); ++#endif /* LINUX_VERSION >= 3.14.0 && LINUX_VERSION < 3.19.0 && !CONFIG_SOC_EXYNOS8890 */ ++ ++ pci_restore_state(bus->dev); ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) */ ++ ++ ret = pci_enable_device(bus->dev); ++ if (ret) { ++ pci_disable_device(bus->dev); ++ } else { ++ pci_set_master(bus->dev); ++ } ++ ++ return ret; ++} ++ ++int ++dhdpcie_alloc_resource(dhd_bus_t *bus) ++{ ++ dhdpcie_info_t *dhdpcie_info; ++ phys_addr_t bar0_addr, bar1_addr; ++ ulong bar1_size; ++ ++ do { ++ if (bus == NULL) { ++ DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); ++ break; ++ } ++ ++ if (bus->dev == NULL) { ++ DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); ++ break; ++ } ++ ++ dhdpcie_info = pci_get_drvdata(bus->dev); ++ if (dhdpcie_info == NULL) { ++ DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__)); ++ break; ++ } ++ ++ bar0_addr = pci_resource_start(bus->dev, 0); /* Bar-0 mapped address */ ++ bar1_addr = pci_resource_start(bus->dev, 2); /* Bar-1 mapped address */ ++ ++ /* read Bar-1 mapped memory range */ ++ bar1_size = pci_resource_len(bus->dev, 2); ++ ++ if ((bar1_size == 0) || (bar1_addr == 0)) { ++ printf("%s: BAR1 Not enabled for this device size(%ld)," ++ " addr(0x"PRINTF_RESOURCE")\n", ++ __FUNCTION__, bar1_size, bar1_addr); ++ break; ++ } ++ ++ dhdpcie_info->regs = (volatile char *) REG_MAP(bar0_addr, DONGLE_REG_MAP_SIZE); ++ if (!dhdpcie_info->regs) { ++ DHD_ERROR(("%s: ioremap() for regs is failed\n", __FUNCTION__)); ++ break; ++ } ++ ++ bus->regs = dhdpcie_info->regs; ++ dhdpcie_info->tcm_size = ++ (bar1_size > DONGLE_TCM_MAP_SIZE) ? bar1_size : DONGLE_TCM_MAP_SIZE; ++ dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, dhdpcie_info->tcm_size); ++ if (!dhdpcie_info->tcm) { ++ DHD_ERROR(("%s: ioremap() for regs is failed\n", __FUNCTION__)); ++ REG_UNMAP(dhdpcie_info->regs); ++ bus->regs = NULL; ++ break; ++ } ++ ++ bus->tcm = dhdpcie_info->tcm; ++ ++ DHD_TRACE(("%s:Phys addr : reg space = %p base addr 0x"PRINTF_RESOURCE" \n", ++ __FUNCTION__, dhdpcie_info->regs, bar0_addr)); ++ DHD_TRACE(("%s:Phys addr : tcm_space = %p base addr 0x"PRINTF_RESOURCE" \n", ++ __FUNCTION__, dhdpcie_info->tcm, bar1_addr)); ++ ++ return 0; ++ } while (0); ++ ++ return BCME_ERROR; ++} ++ ++void ++dhdpcie_free_resource(dhd_bus_t *bus) ++{ ++ dhdpcie_info_t *dhdpcie_info; ++ ++ if (bus == NULL) { ++ DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (bus->dev == NULL) { ++ DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ dhdpcie_info = pci_get_drvdata(bus->dev); ++ if (dhdpcie_info == NULL) { ++ DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (bus->regs) { ++ REG_UNMAP(dhdpcie_info->regs); ++ bus->regs = NULL; ++ } ++ ++ if (bus->tcm) { ++ REG_UNMAP(dhdpcie_info->tcm); ++ bus->tcm = NULL; ++ } ++} ++ ++int ++dhdpcie_bus_request_irq(struct dhd_bus *bus) ++{ ++ dhdpcie_info_t *dhdpcie_info; ++ int ret = 0; ++ ++ if (bus == NULL) { ++ DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ if (bus->dev == NULL) { ++ DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ dhdpcie_info = pci_get_drvdata(bus->dev); ++ if (dhdpcie_info == NULL) { ++ DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ if (bus->intr) { ++ /* Register interrupt callback, but mask it (not operational yet). */ ++ DHD_INTR(("%s: Registering and masking interrupts\n", __FUNCTION__)); ++ dhdpcie_bus_intr_disable(bus); ++ ret = dhdpcie_request_irq(dhdpcie_info); ++ if (ret) { ++ DHD_ERROR(("%s: request_irq() failed, ret=%d\n", ++ __FUNCTION__, ret)); ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++ ++#ifdef BCMPCIE_OOB_HOST_WAKE ++void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable) ++{ ++ unsigned long flags; ++ dhdpcie_info_t *pch; ++ dhdpcie_os_info_t *dhdpcie_osinfo; ++ ++ if (bus == NULL) { ++ DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (bus->dev == NULL) { ++ DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ pch = pci_get_drvdata(bus->dev); ++ if (pch == NULL) { ++ DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt; ++ spin_lock_irqsave(&dhdpcie_osinfo->oob_irq_spinlock, flags); ++ if ((dhdpcie_osinfo->oob_irq_enabled != enable) && ++ (dhdpcie_osinfo->oob_irq_num > 0)) { ++ if (enable) { ++ enable_irq(dhdpcie_osinfo->oob_irq_num); ++ } else { ++ disable_irq_nosync(dhdpcie_osinfo->oob_irq_num); ++ } ++ dhdpcie_osinfo->oob_irq_enabled = enable; ++ } ++ spin_unlock_irqrestore(&dhdpcie_osinfo->oob_irq_spinlock, flags); ++} ++ ++static irqreturn_t wlan_oob_irq(int irq, void *data) ++{ ++ dhd_bus_t *bus; ++ DHD_TRACE(("%s: IRQ Triggered\n", __FUNCTION__)); ++ bus = (dhd_bus_t *)data; ++ dhdpcie_oob_intr_set(bus, FALSE); ++#ifdef DHD_WAKE_STATUS ++#ifdef DHD_PCIE_RUNTIMEPM ++ /* This condition is for avoiding counting of wake up from Runtime PM */ ++ if (bus->chk_pm) ++#endif /* DHD_PCIE_RUNTIMPM */ ++ { ++ bcmpcie_set_get_wake(bus, 1); ++ } ++#endif /* DHD_WAKE_STATUS */ ++#ifdef DHD_PCIE_RUNTIMEPM ++ dhdpcie_runtime_bus_wake(bus->dhd, FALSE, wlan_oob_irq); ++#endif /* DHD_PCIE_RUNTIMPM */ ++ if (bus->dhd->up && bus->oob_presuspend) { ++ DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(bus->dhd, OOB_WAKE_LOCK_TIMEOUT); ++ } ++ return IRQ_HANDLED; ++} ++ ++int dhdpcie_oob_intr_register(dhd_bus_t *bus) ++{ ++ int err = 0; ++ dhdpcie_info_t *pch; ++ dhdpcie_os_info_t *dhdpcie_osinfo; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ if (bus == NULL) { ++ DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); ++ return -EINVAL; ++ } ++ ++ if (bus->dev == NULL) { ++ DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); ++ return -EINVAL; ++ } ++ ++ pch = pci_get_drvdata(bus->dev); ++ if (pch == NULL) { ++ DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__)); ++ return -EINVAL; ++ } ++ ++ dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt; ++ if (dhdpcie_osinfo->oob_irq_registered) { ++ DHD_ERROR(("%s: irq is already registered\n", __FUNCTION__)); ++ return -EBUSY; ++ } ++ ++ if (dhdpcie_osinfo->oob_irq_num > 0) { ++ printf("%s OOB irq=%d flags=0x%X\n", __FUNCTION__, ++ (int)dhdpcie_osinfo->oob_irq_num, ++ (int)dhdpcie_osinfo->oob_irq_flags); ++ err = request_irq(dhdpcie_osinfo->oob_irq_num, wlan_oob_irq, ++ dhdpcie_osinfo->oob_irq_flags, "dhdpcie_host_wake", ++ bus); ++ if (err) { ++ DHD_ERROR(("%s: request_irq failed with %d\n", ++ __FUNCTION__, err)); ++ return err; ++ } ++#if defined(DISABLE_WOWLAN) ++ printf("%s: disable_irq_wake\n", __FUNCTION__); ++ dhdpcie_osinfo->oob_irq_wake_enabled = FALSE; ++#else ++ printf("%s: enable_irq_wake\n", __FUNCTION__); ++ err = enable_irq_wake(dhdpcie_osinfo->oob_irq_num); ++ if (!err) { ++ dhdpcie_osinfo->oob_irq_wake_enabled = TRUE; ++ } else ++ printf("%s: enable_irq_wake failed with %d\n", __FUNCTION__, err); ++#endif ++ dhdpcie_osinfo->oob_irq_enabled = TRUE; ++ } ++ ++ dhdpcie_osinfo->oob_irq_registered = TRUE; ++ ++ return err; ++} ++ ++void dhdpcie_oob_intr_unregister(dhd_bus_t *bus) ++{ ++ int err = 0; ++ dhdpcie_info_t *pch; ++ dhdpcie_os_info_t *dhdpcie_osinfo; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ if (bus == NULL) { ++ DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (bus->dev == NULL) { ++ DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ pch = pci_get_drvdata(bus->dev); ++ if (pch == NULL) { ++ DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++ dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt; ++ if (!dhdpcie_osinfo->oob_irq_registered) { ++ DHD_ERROR(("%s: irq is not registered\n", __FUNCTION__)); ++ return; ++ } ++ if (dhdpcie_osinfo->oob_irq_num > 0) { ++ if (dhdpcie_osinfo->oob_irq_wake_enabled) { ++ err = disable_irq_wake(dhdpcie_osinfo->oob_irq_num); ++ if (!err) { ++ dhdpcie_osinfo->oob_irq_wake_enabled = FALSE; ++ } ++ } ++ if (dhdpcie_osinfo->oob_irq_enabled) { ++ disable_irq(dhdpcie_osinfo->oob_irq_num); ++ dhdpcie_osinfo->oob_irq_enabled = FALSE; ++ } ++ free_irq(dhdpcie_osinfo->oob_irq_num, bus); ++ } ++ dhdpcie_osinfo->oob_irq_registered = FALSE; ++} ++#endif /* BCMPCIE_OOB_HOST_WAKE */ ++ ++#ifdef PCIE_OOB ++void dhdpcie_oob_init(dhd_bus_t *bus) ++{ ++ gpio_handle_val = get_handle(OOB_PORT); ++ if (gpio_handle_val < 0) ++ { ++ DHD_ERROR(("%s: Could not get GPIO handle.\n", __FUNCTION__)); ++ ASSERT(FALSE); ++ } ++ ++ gpio_direction = 0; ++ ftdi_set_bitmode(gpio_handle_val, 0, BITMODE_BITBANG); ++ ++ /* Note BT core is also enabled here */ ++ gpio_port = 1 << BIT_WL_REG_ON | 1 << BIT_BT_REG_ON | 1 << DEVICE_WAKE; ++ gpio_write_port(gpio_handle_val, gpio_port); ++ ++ gpio_direction = 1 << BIT_WL_REG_ON | 1 << BIT_BT_REG_ON | 1 << DEVICE_WAKE; ++ ftdi_set_bitmode(gpio_handle_val, gpio_direction, BITMODE_BITBANG); ++ ++ bus->oob_enabled = TRUE; ++ bus->oob_presuspend = FALSE; ++ ++ /* drive the Device_Wake GPIO low on startup */ ++ bus->device_wake_state = TRUE; ++ dhd_bus_set_device_wake(bus, FALSE); ++ dhd_bus_doorbell_timeout_reset(bus); ++ ++} ++ ++void ++dhd_oob_set_bt_reg_on(struct dhd_bus *bus, bool val) ++{ ++ DHD_INFO(("Set Device_Wake to %d\n", val)); ++ if (val) ++ { ++ gpio_port = gpio_port | (1 << BIT_BT_REG_ON); ++ gpio_write_port(gpio_handle_val, gpio_port); ++ } else { ++ gpio_port = gpio_port & (0xff ^ (1 << BIT_BT_REG_ON)); ++ gpio_write_port(gpio_handle_val, gpio_port); ++ } ++} ++ ++int ++dhd_oob_get_bt_reg_on(struct dhd_bus *bus) ++{ ++ int ret; ++ uint8 val; ++ ret = gpio_read_port(gpio_handle_val, &val); ++ ++ if (ret < 0) { ++ DHD_ERROR(("gpio_read_port returns %d\n", ret)); ++ return ret; ++ } ++ ++ if (val & (1 << BIT_BT_REG_ON)) ++ { ++ ret = 1; ++ } else { ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++int ++dhd_os_oob_set_device_wake(struct dhd_bus *bus, bool val) ++{ ++ if (bus->device_wake_state != val) ++ { ++ DHD_INFO(("Set Device_Wake to %d\n", val)); ++ ++ if (bus->oob_enabled && !bus->oob_presuspend) ++ { ++ if (val) ++ { ++ gpio_port = gpio_port | (1 << DEVICE_WAKE); ++ gpio_write_port_non_block(gpio_handle_val, gpio_port); ++ } else { ++ gpio_port = gpio_port & (0xff ^ (1 << DEVICE_WAKE)); ++ gpio_write_port_non_block(gpio_handle_val, gpio_port); ++ } ++ } ++ ++ bus->device_wake_state = val; ++ } ++ return BCME_OK; ++} ++ ++INLINE void ++dhd_os_ib_set_device_wake(struct dhd_bus *bus, bool val) ++{ ++ /* TODO: Currently Inband implementation of Device_Wake is not supported, ++ * so this function is left empty later this can be used to support the same. ++ */ ++} ++#endif /* PCIE_OOB */ ++ ++#ifdef DHD_PCIE_RUNTIMEPM ++bool dhd_runtimepm_state(dhd_pub_t *dhd) ++{ ++ dhd_bus_t *bus; ++ unsigned long flags; ++ bus = dhd->bus; ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ ++ bus->idlecount++; ++ ++ DHD_TRACE(("%s : Enter \n", __FUNCTION__)); ++ if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) { ++ bus->idlecount = 0; ++ if (DHD_BUS_BUSY_CHECK_IDLE(dhd) && !DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd)) { ++ bus->bus_wake = 0; ++ DHD_BUS_BUSY_SET_RPM_SUSPEND_IN_PROGRESS(dhd); ++ bus->runtime_resume_done = FALSE; ++ /* stop all interface network queue. */ ++ dhd_bus_stop_queue(bus); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ DHD_ERROR(("%s: DHD Idle state!! - idletime :%d, wdtick :%d \n", ++ __FUNCTION__, bus->idletime, dhd_runtimepm_ms)); ++ /* RPM suspend is failed, return FALSE then re-trying */ ++ if (dhdpcie_set_suspend_resume(bus, TRUE)) { ++ DHD_ERROR(("%s: exit with wakelock \n", __FUNCTION__)); ++ DHD_GENERAL_LOCK(dhd, flags); ++ DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_IN_PROGRESS(dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ bus->runtime_resume_done = TRUE; ++ /* It can make stuck NET TX Queue without below */ ++ dhd_bus_start_queue(bus); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ smp_wmb(); ++ wake_up_interruptible(&bus->rpm_queue); ++ return FALSE; ++ } ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_IN_PROGRESS(dhd); ++ DHD_BUS_BUSY_SET_RPM_SUSPEND_DONE(dhd); ++ /* For making sure NET TX Queue active */ ++ dhd_bus_start_queue(bus); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ wait_event_interruptible(bus->rpm_queue, bus->bus_wake); ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_DONE(dhd); ++ DHD_BUS_BUSY_SET_RPM_RESUME_IN_PROGRESS(dhd); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ dhdpcie_set_suspend_resume(bus, FALSE); ++ ++ DHD_GENERAL_LOCK(dhd, flags); ++ DHD_BUS_BUSY_CLEAR_RPM_RESUME_IN_PROGRESS(dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ /* Inform the wake up context that Resume is over */ ++ bus->runtime_resume_done = TRUE; ++ /* For making sure NET TX Queue active */ ++ dhd_bus_start_queue(bus); ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ ++ smp_wmb(); ++ wake_up_interruptible(&bus->rpm_queue); ++ DHD_ERROR(("%s : runtime resume ended \n", __FUNCTION__)); ++ return TRUE; ++ } else { ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ /* Since one of the contexts are busy (TX, IOVAR or RX) ++ * we should not suspend ++ */ ++ DHD_ERROR(("%s : bus is active with dhd_bus_busy_state = 0x%x\n", ++ __FUNCTION__, dhd->dhd_bus_busy_state)); ++ return FALSE; ++ } ++ } ++ ++ DHD_GENERAL_UNLOCK(dhd, flags); ++ return FALSE; ++} /* dhd_runtimepm_state */ ++ ++/* ++ * dhd_runtime_bus_wake ++ * TRUE - related with runtime pm context ++ * FALSE - It isn't invloved in runtime pm context ++ */ ++bool dhd_runtime_bus_wake(dhd_bus_t *bus, bool wait, void *func_addr) ++{ ++ unsigned long flags; ++ bus->idlecount = 0; ++ DHD_TRACE(("%s : enter\n", __FUNCTION__)); ++ if (bus->dhd->up == FALSE) { ++ DHD_INFO(("%s : dhd is not up\n", __FUNCTION__)); ++ return FALSE; ++ } ++ ++ DHD_GENERAL_LOCK(bus->dhd, flags); ++ if (DHD_BUS_BUSY_CHECK_RPM_ALL(bus->dhd)) { ++ /* Wake up RPM state thread if it is suspend in progress or suspended */ ++ if (DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(bus->dhd) || ++ DHD_BUS_BUSY_CHECK_RPM_SUSPEND_DONE(bus->dhd)) { ++ bus->bus_wake = 1; ++ ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ DHD_ERROR(("Runtime Resume is called in %pf\n", func_addr)); ++ smp_wmb(); ++ wake_up_interruptible(&bus->rpm_queue); ++ /* No need to wake up the RPM state thread */ ++ } else if (DHD_BUS_BUSY_CHECK_RPM_RESUME_IN_PROGRESS(bus->dhd)) { ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ } ++ ++ /* If wait is TRUE, function with wait = TRUE will be wait in here */ ++ if (wait) { ++ wait_event_interruptible(bus->rpm_queue, bus->runtime_resume_done); ++ } else { ++ DHD_INFO(("%s: bus wakeup but no wait until resume done\n", __FUNCTION__)); ++ } ++ /* If it is called from RPM context, it returns TRUE */ ++ return TRUE; ++ } ++ ++ DHD_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ return FALSE; ++} ++ ++bool dhdpcie_runtime_bus_wake(dhd_pub_t *dhdp, bool wait, void* func_addr) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ return dhd_runtime_bus_wake(bus, wait, func_addr); ++} ++ ++void dhdpcie_block_runtime_pm(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ bus->idletime = 0; ++} ++ ++bool dhdpcie_is_resume_done(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ return bus->runtime_resume_done; ++} ++#endif /* DHD_PCIE_RUNTIMEPM */ ++ ++struct device * dhd_bus_to_dev(dhd_bus_t *bus) ++{ ++ struct pci_dev *pdev; ++ pdev = bus->dev; ++ ++ if (pdev) ++ return &pdev->dev; ++ else ++ return NULL; ++} ++ ++#ifdef HOFFLOAD_MODULES ++void ++dhd_free_module_memory(struct dhd_bus *bus, struct module_metadata *hmem) ++{ ++ struct device *dev = &bus->dev->dev; ++ if (hmem) { ++ dma_unmap_single(dev, (dma_addr_t) hmem->data_addr, hmem->size, DMA_TO_DEVICE); ++ kfree(hmem->data); ++ hmem->data = NULL; ++ hmem->size = 0; ++ } else { ++ DHD_ERROR(("dev:%p pci unmapping error\n", dev)); ++ } ++} ++ ++void * ++dhd_alloc_module_memory(struct dhd_bus *bus, uint32_t size, struct module_metadata *hmem) ++{ ++ struct device *dev = &bus->dev->dev; ++ if (!hmem->data) { ++ hmem->data = kzalloc(size, GFP_KERNEL); ++ if (!hmem->data) { ++ DHD_ERROR(("dev:%p mem alloc failure\n", dev)); ++ return NULL; ++ } ++ } ++ hmem->size = size; ++ DHD_INFO(("module size: 0x%x \n", hmem->size)); ++ hmem->data_addr = (u64) dma_map_single(dev, hmem->data, hmem->size, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, hmem->data_addr)) { ++ DHD_ERROR(("dev:%p dma mapping error\n", dev)); ++ kfree(hmem->data); ++ hmem->data = NULL; ++ return hmem->data; ++ } ++ return hmem->data; ++} ++#endif /* HOFFLOAD_MODULES */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_pno.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_pno.c +new file mode 100644 +index 000000000..af8f35cd0 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_pno.c +@@ -0,0 +1,4050 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD) ++ * Prefered Network Offload and Wi-Fi Location Service(WLS) code. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_pno.c 707287 2017-06-27 06:44:29Z $ ++ */ ++ ++#if defined(GSCAN_SUPPORT) && !defined(PNO_SUPPORT) ++#error "GSCAN needs PNO to be enabled!" ++#endif ++ ++#ifdef PNO_SUPPORT ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#ifdef GSCAN_SUPPORT ++#include ++#endif /* GSCAN_SUPPORT */ ++#ifdef WL_CFG80211 ++#include ++#endif /* WL_CFG80211 */ ++ ++#ifdef __BIG_ENDIAN ++#include ++#define htod32(i) (bcmswap32(i)) ++#define htod16(i) (bcmswap16(i)) ++#define dtoh32(i) (bcmswap32(i)) ++#define dtoh16(i) (bcmswap16(i)) ++#define htodchanspec(i) htod16(i) ++#define dtohchanspec(i) dtoh16(i) ++#else ++#define htod32(i) (i) ++#define htod16(i) (i) ++#define dtoh32(i) (i) ++#define dtoh16(i) (i) ++#define htodchanspec(i) (i) ++#define dtohchanspec(i) (i) ++#endif /* IL_BIGENDINA */ ++ ++#define NULL_CHECK(p, s, err) \ ++ do { \ ++ if (!(p)) { \ ++ printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ ++ err = BCME_ERROR; \ ++ return err; \ ++ } \ ++ } while (0) ++#define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state) ++#define PNO_BESTNET_LEN 1024 ++#define PNO_ON 1 ++#define PNO_OFF 0 ++#define CHANNEL_2G_MAX 14 ++#define CHANNEL_5G_MAX 165 ++#define MAX_NODE_CNT 5 ++#define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE) ++#define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000) \ ++ - (uint32)(timestamp2/1000))) ++#define TIME_DIFF_MS(timestamp1, timestamp2) (abs((uint32)(timestamp1) \ ++ - (uint32)(timestamp2))) ++#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ ++ (ts).tv_nsec / NSEC_PER_USEC) ++ ++#define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") ++#define TIME_MIN_DIFF 5 ++ ++#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) ++#define EVENT_MAX_NETCNT_V1 \ ++ ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_v1_t)) \ ++ / sizeof(wl_pfn_net_info_v1_t) + 1) ++#define EVENT_MAX_NETCNT_V2 \ ++ ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_v2_t)) \ ++ / sizeof(wl_pfn_net_info_v2_t) + 1) ++ ++#ifdef GSCAN_SUPPORT ++static int _dhd_pno_flush_ssid(dhd_pub_t *dhd); ++static wl_pfn_gscan_ch_bucket_cfg_t * ++dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state, ++ uint16 *chan_list, uint32 *num_buckets, uint32 *num_buckets_to_fw); ++#endif /* GSCAN_SUPPORT */ ++static int dhd_pno_set_legacy_pno(dhd_pub_t *dhd, uint16 scan_fr, int pno_repeat, ++ int pno_freq_expo_max, uint16 *channel_list, int nchan); ++ ++static inline bool ++is_dfs(uint16 channel) ++{ ++ if (channel >= 52 && channel <= 64) /* class 2 */ ++ return TRUE; ++ else if (channel >= 100 && channel <= 140) /* class 4 */ ++ return TRUE; ++ else ++ return FALSE; ++} ++int ++dhd_pno_clean(dhd_pub_t *dhd) ++{ ++ int pfn = 0; ++ int err; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ /* Disable PNO */ ++ err = dhd_iovar(dhd, 0, "pfn", (char *)&pfn, sizeof(pfn), NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to execute pfn(error : %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ _pno_state->pno_status = DHD_PNO_DISABLED; ++ err = dhd_iovar(dhd, 0, "pfnclear", NULL, 0, NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to execute pfnclear(error : %d)\n", ++ __FUNCTION__, err)); ++ } ++exit: ++ return err; ++} ++ ++bool ++dhd_is_pno_supported(dhd_pub_t *dhd) ++{ ++ dhd_pno_status_info_t *_pno_state; ++ ++ if (!dhd || !dhd->pno_state) { ++ DHD_ERROR(("NULL POINTER : %s\n", ++ __FUNCTION__)); ++ return FALSE; ++ } ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ return WLS_SUPPORTED(_pno_state); ++} ++ ++bool ++dhd_is_legacy_pno_enabled(dhd_pub_t *dhd) ++{ ++ dhd_pno_status_info_t *_pno_state; ++ ++ if (!dhd || !dhd->pno_state) { ++ DHD_ERROR(("NULL POINTER : %s\n", ++ __FUNCTION__)); ++ return FALSE; ++ } ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ return ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) != 0); ++} ++ ++#ifdef GSCAN_SUPPORT ++static uint64 ++convert_fw_rel_time_to_systime(struct osl_timespec *ts, uint32 fw_ts_ms) ++{ ++ return ((uint64)(TIMESPEC_TO_US(*ts)) - (uint64)(fw_ts_ms * 1000)); ++} ++ ++static void ++dhd_pno_idx_to_ssid(struct dhd_pno_gscan_params *gscan_params, ++ dhd_epno_results_t *res, uint32 idx) ++{ ++ dhd_pno_ssid_t *iter, *next; ++ int i; ++ ++ /* If idx doesn't make sense */ ++ if (idx >= gscan_params->epno_cfg.num_epno_ssid) { ++ DHD_ERROR(("No match, idx %d num_ssid %d\n", idx, ++ gscan_params->epno_cfg.num_epno_ssid)); ++ goto exit; ++ } ++ ++ if (gscan_params->epno_cfg.num_epno_ssid > 0) { ++ i = 0; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(iter, next, ++ &gscan_params->epno_cfg.epno_ssid_list, list) { ++ if (i++ == idx) { ++ memcpy(res->ssid, iter->SSID, iter->SSID_len); ++ res->ssid_len = iter->SSID_len; ++ return; ++ } ++ } ++ } ++exit: ++ /* If we are here then there was no match */ ++ res->ssid[0] = '\0'; ++ res->ssid_len = 0; ++ return; ++} ++ ++/* Translate HAL flag bitmask to BRCM FW flag bitmask */ ++void dhd_pno_translate_epno_fw_flags(uint32 *flags) ++{ ++ uint32 in_flags, fw_flags = 0; ++ in_flags = *flags; ++ ++ if (in_flags & DHD_EPNO_A_BAND_TRIG) { ++ fw_flags |= WL_PFN_SSID_A_BAND_TRIG; ++ } ++ ++ if (in_flags & DHD_EPNO_BG_BAND_TRIG) { ++ fw_flags |= WL_PFN_SSID_BG_BAND_TRIG; ++ } ++ ++ if (!(in_flags & DHD_EPNO_STRICT_MATCH) && ++ !(in_flags & DHD_EPNO_HIDDEN_SSID)) { ++ fw_flags |= WL_PFN_SSID_IMPRECISE_MATCH; ++ } ++ ++ if (in_flags & DHD_EPNO_SAME_NETWORK) { ++ fw_flags |= WL_PFN_SSID_SAME_NETWORK; ++ } ++ ++ /* Add any hard coded flags needed */ ++ fw_flags |= WL_PFN_SUPPRESS_AGING_MASK; ++ *flags = fw_flags; ++ ++ return; ++} ++ ++/* Translate HAL auth bitmask to BRCM FW bitmask */ ++void dhd_pno_set_epno_auth_flag(uint32 *wpa_auth) ++{ ++ switch (*wpa_auth) { ++ case DHD_PNO_AUTH_CODE_OPEN: ++ *wpa_auth = WPA_AUTH_DISABLED; ++ break; ++ case DHD_PNO_AUTH_CODE_PSK: ++ *wpa_auth = (WPA_AUTH_PSK | WPA2_AUTH_PSK); ++ break; ++ case DHD_PNO_AUTH_CODE_EAPOL: ++ *wpa_auth = ~WPA_AUTH_NONE; ++ break; ++ default: ++ DHD_ERROR(("%s: Unknown auth %d", __FUNCTION__, *wpa_auth)); ++ *wpa_auth = WPA_AUTH_PFN_ANY; ++ break; ++ } ++ return; ++} ++ ++/* Cleanup all results */ ++static void ++dhd_gscan_clear_all_batch_results(dhd_pub_t *dhd) ++{ ++ struct dhd_pno_gscan_params *gscan_params; ++ dhd_pno_status_info_t *_pno_state; ++ gscan_results_cache_t *iter; ++ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; ++ iter = gscan_params->gscan_batch_cache; ++ /* Mark everything as consumed */ ++ while (iter) { ++ iter->tot_consumed = iter->tot_count; ++ iter = iter->next; ++ } ++ dhd_gscan_batch_cache_cleanup(dhd); ++ return; ++} ++ ++static int ++_dhd_pno_gscan_cfg(dhd_pub_t *dhd, wl_pfn_gscan_cfg_t *pfncfg_gscan_param, int size) ++{ ++ int err = BCME_OK; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ ++ err = dhd_iovar(dhd, 0, "pfn_gscan_cfg", (char *)pfncfg_gscan_param, size, NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to execute pfncfg_gscan_param\n", __FUNCTION__)); ++ goto exit; ++ } ++exit: ++ return err; ++} ++ ++#ifdef GSCAN_SUPPORT ++static int ++_dhd_pno_flush_ssid(dhd_pub_t *dhd) ++{ ++ int err; ++ wl_pfn_t pfn_elem; ++ memset(&pfn_elem, 0, sizeof(wl_pfn_t)); ++ pfn_elem.flags = htod32(WL_PFN_FLUSH_ALL_SSIDS); ++ err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_elem, sizeof(wl_pfn_t), NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); ++ } ++ return err; ++} ++#endif /* GSCAN_SUPPORT */ ++ ++static bool ++is_batch_retrieval_complete(struct dhd_pno_gscan_params *gscan_params) ++{ ++ smp_rmb(); ++ return (gscan_params->get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE); ++} ++#endif /* GSCAN_SUPPORT */ ++ ++static int ++_dhd_pno_suspend(dhd_pub_t *dhd) ++{ ++ int err; ++ int suspend = 1; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err)); ++ goto exit; ++ ++ } ++ _pno_state->pno_status = DHD_PNO_SUSPEND; ++exit: ++ return err; ++} ++static int ++_dhd_pno_enable(dhd_pub_t *dhd, int enable) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ ++ if (enable & 0xfffe) { ++ DHD_ERROR(("%s invalid value\n", __FUNCTION__)); ++ err = BCME_BADARG; ++ goto exit; ++ } ++ if (!dhd_support_sta_mode(dhd)) { ++ DHD_ERROR(("PNO is not allowed for non-STA mode")); ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (enable) { ++ if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && ++ dhd_is_associated(dhd, 0, NULL)) { ++ DHD_ERROR(("%s Legacy PNO mode cannot be enabled " ++ "in assoc mode , ignore it\n", __FUNCTION__)); ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ } ++ /* Enable/Disable PNO */ ++ err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to execute pfn_set - %d\n", __FUNCTION__, err)); ++ goto exit; ++ } ++ _pno_state->pno_status = (enable)? ++ DHD_PNO_ENABLED : DHD_PNO_DISABLED; ++ if (!enable) ++ _pno_state->pno_mode = DHD_PNO_NONE_MODE; ++ ++ DHD_PNO(("%s set pno as %s\n", ++ __FUNCTION__, enable ? "Enable" : "Disable")); ++exit: ++ return err; ++} ++ ++static int ++_dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode) ++{ ++ int err = BCME_OK; ++ wl_pfn_param_t pfn_param; ++ dhd_pno_params_t *_params; ++ dhd_pno_status_info_t *_pno_state; ++ bool combined_scan = FALSE; ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ memset(&pfn_param, 0, sizeof(pfn_param)); ++ ++ /* set pfn parameters */ ++ pfn_param.version = htod32(PFN_VERSION); ++ pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) | ++ (ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT)); ++ if (mode == DHD_PNO_LEGACY_MODE) { ++ /* check and set extra pno params */ ++ if ((pno_params->params_legacy.pno_repeat != 0) || ++ (pno_params->params_legacy.pno_freq_expo_max != 0)) { ++ pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); ++ pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat); ++ pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max); ++ } ++ /* set up pno scan fr */ ++ if (pno_params->params_legacy.scan_fr != 0) ++ pfn_param.scan_freq = htod32(pno_params->params_legacy.scan_fr); ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ DHD_PNO(("will enable combined scan with BATCHIG SCAN MODE\n")); ++ mode |= DHD_PNO_BATCH_MODE; ++ combined_scan = TRUE; ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ DHD_PNO(("will enable combined scan with HOTLIST SCAN MODE\n")); ++ mode |= DHD_PNO_HOTLIST_MODE; ++ combined_scan = TRUE; ++ } ++#ifdef GSCAN_SUPPORT ++ else if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { ++ DHD_PNO(("will enable combined scan with GSCAN SCAN MODE\n")); ++ mode |= DHD_PNO_GSCAN_MODE; ++ } ++#endif /* GSCAN_SUPPORT */ ++ } ++ if (mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { ++ /* Scan frequency of 30 sec */ ++ pfn_param.scan_freq = htod32(30); ++ /* slow adapt scan is off by default */ ++ pfn_param.slow_freq = htod32(0); ++ /* RSSI margin of 30 dBm */ ++ pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM); ++ /* Network timeout 60 sec */ ++ pfn_param.lost_network_timeout = htod32(60); ++ /* best n = 2 by default */ ++ pfn_param.bestn = DEFAULT_BESTN; ++ /* mscan m=0 by default, so not record best networks by default */ ++ pfn_param.mscan = DEFAULT_MSCAN; ++ /* default repeat = 10 */ ++ pfn_param.repeat = DEFAULT_REPEAT; ++ /* by default, maximum scan interval = 2^2 ++ * scan_freq when adaptive scan is turned on ++ */ ++ pfn_param.exp = DEFAULT_EXP; ++ if (mode == DHD_PNO_BATCH_MODE) { ++ /* In case of BATCH SCAN */ ++ if (pno_params->params_batch.bestn) ++ pfn_param.bestn = pno_params->params_batch.bestn; ++ if (pno_params->params_batch.scan_fr) ++ pfn_param.scan_freq = htod32(pno_params->params_batch.scan_fr); ++ if (pno_params->params_batch.mscan) ++ pfn_param.mscan = pno_params->params_batch.mscan; ++ /* enable broadcast scan */ ++ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); ++ } else if (mode == DHD_PNO_HOTLIST_MODE) { ++ /* In case of HOTLIST SCAN */ ++ if (pno_params->params_hotlist.scan_fr) ++ pfn_param.scan_freq = htod32(pno_params->params_hotlist.scan_fr); ++ pfn_param.bestn = 0; ++ pfn_param.repeat = 0; ++ /* enable broadcast scan */ ++ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); ++ } ++ if (combined_scan) { ++ /* Disable Adaptive Scan */ ++ pfn_param.flags &= ~(htod16(ENABLE << ENABLE_ADAPTSCAN_BIT)); ++ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); ++ pfn_param.repeat = 0; ++ pfn_param.exp = 0; ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ /* In case of Legacy PNO + BATCH SCAN */ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ if (_params->params_batch.bestn) ++ pfn_param.bestn = _params->params_batch.bestn; ++ if (_params->params_batch.scan_fr) ++ pfn_param.scan_freq = htod32(_params->params_batch.scan_fr); ++ if (_params->params_batch.mscan) ++ pfn_param.mscan = _params->params_batch.mscan; ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ /* In case of Legacy PNO + HOTLIST SCAN */ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ if (_params->params_hotlist.scan_fr) ++ pfn_param.scan_freq = htod32(_params->params_hotlist.scan_fr); ++ pfn_param.bestn = 0; ++ pfn_param.repeat = 0; ++ } ++ } ++ } ++#ifdef GSCAN_SUPPORT ++ if (mode & DHD_PNO_GSCAN_MODE) { ++ uint32 lost_network_timeout; ++ ++ pfn_param.scan_freq = htod32(pno_params->params_gscan.scan_fr); ++ if (pno_params->params_gscan.mscan) { ++ pfn_param.bestn = pno_params->params_gscan.bestn; ++ pfn_param.mscan = pno_params->params_gscan.mscan; ++ pfn_param.flags |= (ENABLE << ENABLE_BD_SCAN_BIT); ++ } ++ /* RSSI margin of 30 dBm */ ++ pfn_param.rssi_margin = htod16(PNO_RSSI_MARGIN_DBM); ++ pfn_param.repeat = 0; ++ pfn_param.exp = 0; ++ pfn_param.slow_freq = 0; ++ pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); ++ ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ dhd_pno_params_t *params; ++ ++ params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ ++ pfn_param.scan_freq = gcd(pno_params->params_gscan.scan_fr, ++ params->params_legacy.scan_fr); ++ ++ if ((params->params_legacy.pno_repeat != 0) || ++ (params->params_legacy.pno_freq_expo_max != 0)) { ++ pfn_param.repeat = (uchar) (params->params_legacy.pno_repeat); ++ pfn_param.exp = (uchar) (params->params_legacy.pno_freq_expo_max); ++ } ++ } ++ ++ lost_network_timeout = (pno_params->params_gscan.max_ch_bucket_freq * ++ pfn_param.scan_freq * ++ pno_params->params_gscan.lost_ap_window); ++ if (lost_network_timeout) { ++ pfn_param.lost_network_timeout = htod32(MIN(lost_network_timeout, ++ GSCAN_MIN_BSSID_TIMEOUT)); ++ } else { ++ pfn_param.lost_network_timeout = htod32(GSCAN_MIN_BSSID_TIMEOUT); ++ } ++ } else ++#endif /* GSCAN_SUPPORT */ ++ { ++ if (pfn_param.scan_freq < htod32(PNO_SCAN_MIN_FW_SEC) || ++ pfn_param.scan_freq > htod32(PNO_SCAN_MAX_FW_SEC)) { ++ DHD_ERROR(("%s pno freq(%d sec) is not valid \n", ++ __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); ++ err = BCME_BADARG; ++ goto exit; ++ } ++ } ++ ++ err = dhd_set_rand_mac_oui(dhd); ++ /* Ignore if chip doesnt support the feature */ ++ if (err < 0 && err != BCME_UNSUPPORTED) { ++ DHD_ERROR(("%s : failed to set random mac for PNO scan, %d\n", __FUNCTION__, err)); ++ goto exit; ++ } ++ ++#ifdef GSCAN_SUPPORT ++ if (mode == DHD_PNO_BATCH_MODE || ++ ((mode & DHD_PNO_GSCAN_MODE) && pno_params->params_gscan.mscan)) ++#else ++ if (mode == DHD_PNO_BATCH_MODE) ++#endif /* GSCAN_SUPPORT */ ++ { ++ int _tmp = pfn_param.bestn; ++ /* set bestn to calculate the max mscan which firmware supports */ ++ err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to set pfnmem\n", __FUNCTION__)); ++ goto exit; ++ } ++ /* get max mscan which the firmware supports */ ++ err = dhd_iovar(dhd, 0, "pfnmem", NULL, 0, (char *)&_tmp, sizeof(_tmp), FALSE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to get pfnmem\n", __FUNCTION__)); ++ goto exit; ++ } ++ pfn_param.mscan = MIN(pfn_param.mscan, _tmp); ++ DHD_PNO((" returned mscan : %d, set bestn : %d mscan %d\n", _tmp, pfn_param.bestn, ++ pfn_param.mscan)); ++ } ++ err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to execute pfn_set %d\n", __FUNCTION__, err)); ++ goto exit; ++ } ++ /* need to return mscan if this is for batch scan instead of err */ ++ err = (mode == DHD_PNO_BATCH_MODE)? pfn_param.mscan : err; ++exit: ++ return err; ++} ++ ++static int ++_dhd_pno_add_ssid(dhd_pub_t *dhd, struct list_head *ssid_list, int nssid) ++{ ++ int err = BCME_OK; ++ int i = 0, mem_needed; ++ wl_pfn_t *pfn_elem_buf; ++ struct dhd_pno_ssid *iter, *next; ++ ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (!nssid) { ++ NULL_CHECK(ssid_list, "ssid list is NULL", err); ++ return BCME_ERROR; ++ } ++ mem_needed = (sizeof(wl_pfn_t) * nssid); ++ pfn_elem_buf = (wl_pfn_t *) kzalloc(mem_needed, GFP_KERNEL); ++ if (!pfn_elem_buf) { ++ DHD_ERROR(("%s: Can't malloc %d bytes!\n", __FUNCTION__, mem_needed)); ++ return BCME_NOMEM; ++ } ++ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(iter, next, ssid_list, list) { ++ pfn_elem_buf[i].infra = htod32(1); ++ pfn_elem_buf[i].auth = htod32(DOT11_OPEN_SYSTEM); ++ pfn_elem_buf[i].wpa_auth = htod32(iter->wpa_auth); ++ pfn_elem_buf[i].flags = htod32(iter->flags); ++ if (iter->hidden) ++ pfn_elem_buf[i].flags |= htod32(ENABLE << WL_PFN_HIDDEN_BIT); ++ /* If a single RSSI threshold is defined, use that */ ++#ifdef PNO_MIN_RSSI_TRIGGER ++ pfn_elem_buf[i].flags |= ((PNO_MIN_RSSI_TRIGGER & 0xFF) << WL_PFN_RSSI_SHIFT); ++#else ++ pfn_elem_buf[i].flags |= ((iter->rssi_thresh & 0xFF) << WL_PFN_RSSI_SHIFT); ++#endif /* PNO_MIN_RSSI_TRIGGER */ ++ memcpy((char *)pfn_elem_buf[i].ssid.SSID, iter->SSID, ++ iter->SSID_len); ++ pfn_elem_buf[i].ssid.SSID_len = iter->SSID_len; ++ DHD_PNO(("%s size = %d hidden = %d flags = %x rssi_thresh %d\n", ++ iter->SSID, iter->SSID_len, iter->hidden, ++ iter->flags, iter->rssi_thresh)); ++ if (++i >= nssid) { ++ /* shouldn't happen */ ++ break; ++ } ++ } ++ err = dhd_iovar(dhd, 0, "pfn_add", (char *)pfn_elem_buf, mem_needed, NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); ++ } ++ kfree(pfn_elem_buf); ++ return err; ++} ++ ++/* qsort compare function */ ++static int ++_dhd_pno_cmpfunc(const void *a, const void *b) ++{ ++ return (*(const uint16*)a - *(const uint16*)b); ++} ++ ++static int ++_dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan, ++ uint16 *chan_list1, int nchan1, uint16 *chan_list2, int nchan2) ++{ ++ int err = BCME_OK; ++ int i = 0, j = 0, k = 0; ++ uint16 tmp; ++ NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); ++ NULL_CHECK(nchan, "nchan is NULL", err); ++ NULL_CHECK(chan_list1, "chan_list1 is NULL", err); ++ NULL_CHECK(chan_list2, "chan_list2 is NULL", err); ++ /* chan_list1 and chan_list2 should be sorted at first */ ++ while (i < nchan1 && j < nchan2) { ++ tmp = chan_list1[i] < chan_list2[j]? ++ chan_list1[i++] : chan_list2[j++]; ++ for (; i < nchan1 && chan_list1[i] == tmp; i++); ++ for (; j < nchan2 && chan_list2[j] == tmp; j++); ++ d_chan_list[k++] = tmp; ++ } ++ ++ while (i < nchan1) { ++ tmp = chan_list1[i++]; ++ for (; i < nchan1 && chan_list1[i] == tmp; i++); ++ d_chan_list[k++] = tmp; ++ } ++ ++ while (j < nchan2) { ++ tmp = chan_list2[j++]; ++ for (; j < nchan2 && chan_list2[j] == tmp; j++); ++ d_chan_list[k++] = tmp; ++ ++ } ++ *nchan = k; ++ return err; ++} ++ ++static int ++_dhd_pno_get_channels(dhd_pub_t *dhd, uint16 *d_chan_list, ++ int *nchan, uint8 band, bool skip_dfs) ++{ ++ int err = BCME_OK; ++ int i, j; ++ uint32 chan_buf[WL_NUMCHANNELS + 1]; ++ wl_uint32_list_t *list; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (*nchan) { ++ NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); ++ } ++ memset(&chan_buf, 0, sizeof(chan_buf)); ++ list = (wl_uint32_list_t *) (void *)chan_buf; ++ list->count = htod32(WL_NUMCHANNELS); ++ err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0); ++ if (err < 0) { ++ DHD_ERROR(("failed to get channel list (err: %d)\n", err)); ++ goto exit; ++ } ++ for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) { ++ if (band == WLC_BAND_2G) { ++ if (dtoh32(list->element[i]) > CHANNEL_2G_MAX) ++ continue; ++ } else if (band == WLC_BAND_5G) { ++ if (dtoh32(list->element[i]) <= CHANNEL_2G_MAX) ++ continue; ++ if (skip_dfs && is_dfs(dtoh32(list->element[i]))) ++ continue; ++ ++ } else if (band == WLC_BAND_AUTO) { ++ if (skip_dfs || !is_dfs(dtoh32(list->element[i]))) ++ continue; ++ ++ } else { /* All channels */ ++ if (skip_dfs && is_dfs(dtoh32(list->element[i]))) ++ continue; ++ } ++ if (dtoh32(list->element[i]) <= CHANNEL_5G_MAX) { ++ d_chan_list[j++] = (uint16) dtoh32(list->element[i]); ++ } else { ++ err = BCME_BADCHAN; ++ goto exit; ++ } ++ } ++ *nchan = j; ++exit: ++ return err; ++} ++ ++static int ++_dhd_pno_convert_format(dhd_pub_t *dhd, struct dhd_pno_batch_params *params_batch, ++ char *buf, int nbufsize) ++{ ++ int err = BCME_OK; ++ int bytes_written = 0, nreadsize = 0; ++ int t_delta = 0; ++ int nleftsize = nbufsize; ++ uint8 cnt = 0; ++ char *bp = buf; ++ char eabuf[ETHER_ADDR_STR_LEN]; ++#ifdef PNO_DEBUG ++ char *_base_bp; ++ char msg[150]; ++#endif ++ dhd_pno_bestnet_entry_t *iter, *next; ++ dhd_pno_scan_results_t *siter, *snext; ++ dhd_pno_best_header_t *phead, *pprev; ++ NULL_CHECK(params_batch, "params_batch is NULL", err); ++ if (nbufsize > 0) ++ NULL_CHECK(buf, "buf is NULL", err); ++ /* initialize the buffer */ ++ memset(buf, 0, nbufsize); ++ DHD_PNO(("%s enter \n", __FUNCTION__)); ++ /* # of scans */ ++ if (!params_batch->get_batch.batch_started) { ++ bp += nreadsize = snprintf(bp, nleftsize, "scancount=%d\n", ++ params_batch->get_batch.expired_tot_scan_cnt); ++ nleftsize -= nreadsize; ++ params_batch->get_batch.batch_started = TRUE; ++ } ++ DHD_PNO(("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt)); ++ /* preestimate scan count until which scan result this report is going to end */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(siter, snext, ++ ¶ms_batch->get_batch.expired_scan_results_list, list) { ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ phead = siter->bestnetheader; ++ while (phead != NULL) { ++ /* if left_size is less than bestheader total size , stop this */ ++ if (nleftsize <= ++ (phead->tot_size + phead->tot_cnt * ENTRY_OVERHEAD)) ++ goto exit; ++ /* increase scan count */ ++ cnt++; ++ /* # best of each scan */ ++ DHD_PNO(("\n\n", cnt - 1, phead->tot_cnt)); ++ /* attribute of the scan */ ++ if (phead->reason & PNO_STATUS_ABORT_MASK) { ++ bp += nreadsize = snprintf(bp, nleftsize, "trunc\n"); ++ nleftsize -= nreadsize; ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(iter, next, ++ &phead->entry_list, list) { ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ t_delta = jiffies_to_msecs(jiffies - iter->recorded_time); ++#ifdef PNO_DEBUG ++ _base_bp = bp; ++ memset(msg, 0, sizeof(msg)); ++#endif ++ /* BSSID info */ ++ bp += nreadsize = snprintf(bp, nleftsize, "bssid=%s\n", ++ bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf)); ++ nleftsize -= nreadsize; ++ /* SSID */ ++ bp += nreadsize = snprintf(bp, nleftsize, "ssid=%s\n", iter->SSID); ++ nleftsize -= nreadsize; ++ /* channel */ ++ bp += nreadsize = snprintf(bp, nleftsize, "freq=%d\n", ++ wf_channel2mhz(iter->channel, ++ iter->channel <= CH_MAX_2G_CHANNEL? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); ++ nleftsize -= nreadsize; ++ /* RSSI */ ++ bp += nreadsize = snprintf(bp, nleftsize, "level=%d\n", iter->RSSI); ++ nleftsize -= nreadsize; ++ /* add the time consumed in Driver to the timestamp of firmware */ ++ iter->timestamp += t_delta; ++ bp += nreadsize = snprintf(bp, nleftsize, ++ "age=%d\n", iter->timestamp); ++ nleftsize -= nreadsize; ++ /* RTT0 */ ++ bp += nreadsize = snprintf(bp, nleftsize, "dist=%d\n", ++ (iter->rtt0 == 0)? -1 : iter->rtt0); ++ nleftsize -= nreadsize; ++ /* RTT1 */ ++ bp += nreadsize = snprintf(bp, nleftsize, "distSd=%d\n", ++ (iter->rtt0 == 0)? -1 : iter->rtt1); ++ nleftsize -= nreadsize; ++ bp += nreadsize = snprintf(bp, nleftsize, "%s", AP_END_MARKER); ++ nleftsize -= nreadsize; ++ list_del(&iter->list); ++ MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); ++#ifdef PNO_DEBUG ++ memcpy(msg, _base_bp, bp - _base_bp); ++ DHD_PNO(("Entry : \n%s", msg)); ++#endif ++ } ++ bp += nreadsize = snprintf(bp, nleftsize, "%s", SCAN_END_MARKER); ++ DHD_PNO(("%s", SCAN_END_MARKER)); ++ nleftsize -= nreadsize; ++ pprev = phead; ++ /* reset the header */ ++ siter->bestnetheader = phead = phead->next; ++ MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); ++ ++ siter->cnt_header--; ++ } ++ if (phead == NULL) { ++ /* we store all entry in this scan , so it is ok to delete */ ++ list_del(&siter->list); ++ MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); ++ } ++ } ++exit: ++ if (cnt < params_batch->get_batch.expired_tot_scan_cnt) { ++ DHD_ERROR(("Buffer size is small to save all batch entry," ++ " cnt : %d (remained_scan_cnt): %d\n", ++ cnt, params_batch->get_batch.expired_tot_scan_cnt - cnt)); ++ } ++ params_batch->get_batch.expired_tot_scan_cnt -= cnt; ++ /* set FALSE only if the link list is empty after returning the data */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ if (list_empty(¶ms_batch->get_batch.expired_scan_results_list)) { ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ params_batch->get_batch.batch_started = FALSE; ++ bp += snprintf(bp, nleftsize, "%s", RESULTS_END_MARKER); ++ DHD_PNO(("%s", RESULTS_END_MARKER)); ++ DHD_PNO(("%s : Getting the batching data is complete\n", __FUNCTION__)); ++ } ++ /* return used memory in buffer */ ++ bytes_written = (int32)(bp - buf); ++ return bytes_written; ++} ++ ++static int ++_dhd_pno_clear_all_batch_results(dhd_pub_t *dhd, struct list_head *head, bool only_last) ++{ ++ int err = BCME_OK; ++ int removed_scan_cnt = 0; ++ dhd_pno_scan_results_t *siter, *snext; ++ dhd_pno_best_header_t *phead, *pprev; ++ dhd_pno_bestnet_entry_t *iter, *next; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(head, "head is NULL", err); ++ NULL_CHECK(head->next, "head->next is NULL", err); ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(siter, snext, ++ head, list) { ++ if (only_last) { ++ /* in case that we need to delete only last one */ ++ if (!list_is_last(&siter->list, head)) { ++ /* skip if the one is not last */ ++ continue; ++ } ++ } ++ /* delete all data belong if the one is last */ ++ phead = siter->bestnetheader; ++ while (phead != NULL) { ++ removed_scan_cnt++; ++ list_for_each_entry_safe(iter, next, ++ &phead->entry_list, list) { ++ list_del(&iter->list); ++ MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); ++ } ++ pprev = phead; ++ phead = phead->next; ++ MFREE(dhd->osh, pprev, BEST_HEADER_SIZE); ++ } ++ if (phead == NULL) { ++ /* it is ok to delete top node */ ++ list_del(&siter->list); ++ MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); ++ } ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ return removed_scan_cnt; ++} ++ ++static int ++_dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan) ++{ ++ int err = BCME_OK; ++ int i = 0; ++ wl_pfn_cfg_t pfncfg_param; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (nchan) { ++ NULL_CHECK(channel_list, "nchan is NULL", err); ++ } ++ if (nchan > WL_NUMCHANNELS) { ++ return BCME_RANGE; ++ } ++ DHD_PNO(("%s enter : nchan : %d\n", __FUNCTION__, nchan)); ++ memset(&pfncfg_param, 0, sizeof(wl_pfn_cfg_t)); ++ /* Setup default values */ ++ pfncfg_param.reporttype = htod32(WL_PFN_REPORT_ALLNET); ++ pfncfg_param.channel_num = htod32(0); ++ ++ for (i = 0; i < nchan; i++) ++ pfncfg_param.channel_list[i] = channel_list[i]; ++ ++ pfncfg_param.channel_num = htod32(nchan); ++ err = dhd_iovar(dhd, 0, "pfn_cfg", (char *)&pfncfg_param, sizeof(pfncfg_param), NULL, 0, ++ TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); ++ goto exit; ++ } ++exit: ++ return err; ++} ++ ++static int ++_dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mode_t mode) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL\n", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL\n", err); ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ mutex_lock(&_pno_state->pno_mutex); ++ switch (mode) { ++ case DHD_PNO_LEGACY_MODE: { ++ struct dhd_pno_ssid *iter, *next; ++ if (params->params_legacy.nssid > 0) { ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(iter, next, ++ ¶ms->params_legacy.ssid_list, list) { ++ list_del(&iter->list); ++ kfree(iter); ++ } ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ params->params_legacy.nssid = 0; ++ params->params_legacy.scan_fr = 0; ++ params->params_legacy.pno_freq_expo_max = 0; ++ params->params_legacy.pno_repeat = 0; ++ params->params_legacy.nchan = 0; ++ memset(params->params_legacy.chan_list, 0, ++ sizeof(params->params_legacy.chan_list)); ++ break; ++ } ++ case DHD_PNO_BATCH_MODE: { ++ params->params_batch.scan_fr = 0; ++ params->params_batch.mscan = 0; ++ params->params_batch.nchan = 0; ++ params->params_batch.rtt = 0; ++ params->params_batch.bestn = 0; ++ params->params_batch.nchan = 0; ++ params->params_batch.band = WLC_BAND_AUTO; ++ memset(params->params_batch.chan_list, 0, ++ sizeof(params->params_batch.chan_list)); ++ params->params_batch.get_batch.batch_started = FALSE; ++ params->params_batch.get_batch.buf = NULL; ++ params->params_batch.get_batch.bufsize = 0; ++ params->params_batch.get_batch.reason = 0; ++ _dhd_pno_clear_all_batch_results(dhd, ++ ¶ms->params_batch.get_batch.scan_results_list, FALSE); ++ _dhd_pno_clear_all_batch_results(dhd, ++ ¶ms->params_batch.get_batch.expired_scan_results_list, FALSE); ++ params->params_batch.get_batch.tot_scan_cnt = 0; ++ params->params_batch.get_batch.expired_tot_scan_cnt = 0; ++ params->params_batch.get_batch.top_node_cnt = 0; ++ INIT_LIST_HEAD(¶ms->params_batch.get_batch.scan_results_list); ++ INIT_LIST_HEAD(¶ms->params_batch.get_batch.expired_scan_results_list); ++ break; ++ } ++ case DHD_PNO_HOTLIST_MODE: { ++ struct dhd_pno_bssid *iter, *next; ++ if (params->params_hotlist.nbssid > 0) { ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(iter, next, ++ ¶ms->params_hotlist.bssid_list, list) { ++ list_del(&iter->list); ++ kfree(iter); ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ } ++ params->params_hotlist.scan_fr = 0; ++ params->params_hotlist.nbssid = 0; ++ params->params_hotlist.nchan = 0; ++ params->params_batch.band = WLC_BAND_AUTO; ++ memset(params->params_hotlist.chan_list, 0, ++ sizeof(params->params_hotlist.chan_list)); ++ break; ++ } ++ default: ++ DHD_ERROR(("%s : unknown mode : %d\n", __FUNCTION__, mode)); ++ break; ++ } ++ mutex_unlock(&_pno_state->pno_mutex); ++ return err; ++} ++ ++static int ++_dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) ++{ ++ int err = BCME_OK; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ if (nbssid) { ++ NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err); ++ } ++ err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)p_pfn_bssid, ++ sizeof(wl_pfn_bssid_t) * nbssid, NULL, 0, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); ++ goto exit; ++ } ++exit: ++ return err; ++} ++ ++int ++dhd_pno_stop_for_ssid(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ uint32 mode = 0; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ wl_pfn_bssid_t *p_pfn_bssid = NULL; ++ NULL_CHECK(dhd, "dev is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { ++ DHD_ERROR(("%s : LEGACY PNO MODE is not enabled\n", __FUNCTION__)); ++ goto exit; ++ } ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++#ifdef GSCAN_SUPPORT ++ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { ++ struct dhd_pno_gscan_params *gscan_params; ++ ++ _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ gscan_params = &_params->params_gscan; ++ if (gscan_params->mscan) { ++ /* retrieve the batching data from firmware into host */ ++ err = dhd_wait_batch_results_complete(dhd); ++ if (err != BCME_OK) ++ goto exit; ++ } ++ /* save current pno_mode before calling dhd_pno_clean */ ++ mutex_lock(&_pno_state->pno_mutex); ++ mode = _pno_state->pno_mode; ++ err = dhd_pno_clean(dhd); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err)); ++ mutex_unlock(&_pno_state->pno_mutex); ++ goto exit; ++ } ++ /* restore previous pno_mode */ ++ _pno_state->pno_mode = mode; ++ mutex_unlock(&_pno_state->pno_mutex); ++ /* Restart gscan */ ++ err = dhd_pno_initiate_gscan_request(dhd, 1, 0); ++ goto exit; ++ } ++#endif /* GSCAN_SUPPORT */ ++ /* restart Batch mode if the batch mode is on */ ++ if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { ++ /* retrieve the batching data from firmware into host */ ++ dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); ++ /* save current pno_mode before calling dhd_pno_clean */ ++ mode = _pno_state->pno_mode; ++ err = dhd_pno_clean(dhd); ++ if (err < 0) { ++ err = BCME_ERROR; ++ DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ ++ /* restore previous pno_mode */ ++ _pno_state->pno_mode = mode; ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ /* restart BATCH SCAN */ ++ err = dhd_pno_set_for_batch(dhd, &_params->params_batch); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ /* restart HOTLIST SCAN */ ++ struct dhd_pno_bssid *iter, *next; ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * ++ _params->params_hotlist.nbssid, GFP_KERNEL); ++ if (p_pfn_bssid == NULL) { ++ DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" ++ " (count: %d)", ++ __FUNCTION__, _params->params_hotlist.nbssid)); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ goto exit; ++ } ++ /* convert dhd_pno_bssid to wl_pfn_bssid */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(iter, next, ++ &_params->params_hotlist.bssid_list, list) { ++ memcpy(&p_pfn_bssid->macaddr, ++ &iter->macaddr, ETHER_ADDR_LEN); ++ p_pfn_bssid->flags = iter->flags; ++ p_pfn_bssid++; ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++ } else { ++ err = dhd_pno_clean(dhd); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++exit: ++ kfree(p_pfn_bssid); ++ return err; ++} ++ ++int ++dhd_pno_enable(dhd_pub_t *dhd, int enable) ++{ ++ int err = BCME_OK; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ return (_dhd_pno_enable(dhd, enable)); ++} ++ ++static int ++dhd_pno_add_to_ssid_list(struct list_head *ptr, wlc_ssid_ext_t *ssid_list, ++ int nssid, int *num_ssid_added) ++{ ++ int ret = BCME_OK; ++ int i; ++ struct dhd_pno_ssid *_pno_ssid; ++ ++ for (i = 0; i < nssid; i++) { ++ if (ssid_list[i].SSID_len > DOT11_MAX_SSID_LEN) { ++ DHD_ERROR(("%s : Invalid SSID length %d\n", ++ __FUNCTION__, ssid_list[i].SSID_len)); ++ ret = BCME_ERROR; ++ goto exit; ++ } ++ /* Check for broadcast ssid */ ++ if (!ssid_list[i].SSID_len) { ++ DHD_ERROR(("%d: Broadcast SSID is illegal for PNO setting\n", i)); ++ ret = BCME_ERROR; ++ goto exit; ++ } ++ ++ _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); ++ if (_pno_ssid == NULL) { ++ DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n", ++ __FUNCTION__)); ++ ret = BCME_ERROR; ++ goto exit; ++ } ++ _pno_ssid->SSID_len = ssid_list[i].SSID_len; ++ _pno_ssid->hidden = ssid_list[i].hidden; ++ _pno_ssid->rssi_thresh = ssid_list[i].rssi_thresh; ++ _pno_ssid->flags = ssid_list[i].flags; ++ _pno_ssid->wpa_auth = WPA_AUTH_PFN_ANY; ++ ++ memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); ++ list_add_tail(&_pno_ssid->list, ptr); ++ } ++ ++exit: ++ *num_ssid_added = i; ++ return ret; ++} ++ ++int ++dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, ++ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) ++{ ++ ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ struct dhd_pno_legacy_params *params_legacy; ++ int err = BCME_OK; ++ ++ if (!dhd || !dhd->pno_state) { ++ DHD_ERROR(("%s: PNO Not enabled/Not ready\n", __FUNCTION__)); ++ return BCME_NOTREADY; ++ } ++ ++ if (!dhd_support_sta_mode(dhd)) { ++ return BCME_BADOPTION; ++ } ++ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ params_legacy = &(_params->params_legacy); ++ err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); ++ ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n", ++ __FUNCTION__, err)); ++ return err; ++ } ++ ++ INIT_LIST_HEAD(¶ms_legacy->ssid_list); ++ ++ if (dhd_pno_add_to_ssid_list(¶ms_legacy->ssid_list, ssid_list, ++ nssid, ¶ms_legacy->nssid) < 0) { ++ _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); ++ return BCME_ERROR; ++ } ++ ++ DHD_PNO(("%s enter : nssid %d, scan_fr :%d, pno_repeat :%d," ++ "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, ++ params_legacy->nssid, scan_fr, pno_repeat, pno_freq_expo_max, nchan)); ++ ++ return dhd_pno_set_legacy_pno(dhd, scan_fr, pno_repeat, ++ pno_freq_expo_max, channel_list, nchan); ++ ++} ++ ++static int ++dhd_pno_set_legacy_pno(dhd_pub_t *dhd, uint16 scan_fr, int pno_repeat, ++ int pno_freq_expo_max, uint16 *channel_list, int nchan) ++{ ++ dhd_pno_params_t *_params; ++ dhd_pno_params_t *_params2; ++ dhd_pno_status_info_t *_pno_state; ++ uint16 _chan_list[WL_NUMCHANNELS]; ++ int32 tot_nchan = 0; ++ int err = BCME_OK; ++ int i, nssid; ++ int mode = 0; ++ struct list_head *ssid_list; ++ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ /* If GSCAN is also ON will handle this down below */ ++#ifdef GSCAN_SUPPORT ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE && ++ !(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) ++#else ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) ++#endif /* GSCAN_SUPPORT */ ++ { ++ DHD_ERROR(("%s : Legacy PNO mode was already started, " ++ "will disable previous one to start new one\n", __FUNCTION__)); ++ err = dhd_pno_stop_for_ssid(dhd); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to stop legacy PNO (err %d)\n", ++ __FUNCTION__, err)); ++ return err; ++ } ++ } ++ _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; ++ memset(_chan_list, 0, sizeof(_chan_list)); ++ tot_nchan = MIN(nchan, WL_NUMCHANNELS); ++ if (tot_nchan > 0 && channel_list) { ++ for (i = 0; i < tot_nchan; i++) ++ _params->params_legacy.chan_list[i] = _chan_list[i] = channel_list[i]; ++ } ++#ifdef GSCAN_SUPPORT ++ else { ++ tot_nchan = WL_NUMCHANNELS; ++ err = _dhd_pno_get_channels(dhd, _chan_list, &tot_nchan, ++ (WLC_BAND_2G | WLC_BAND_5G), FALSE); ++ if (err < 0) { ++ tot_nchan = 0; ++ DHD_PNO(("Could not get channel list for PNO SSID\n")); ++ } else { ++ for (i = 0; i < tot_nchan; i++) ++ _params->params_legacy.chan_list[i] = _chan_list[i]; ++ } ++ } ++#endif /* GSCAN_SUPPORT */ ++ ++ if (_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_HOTLIST_MODE)) { ++ DHD_PNO(("BATCH SCAN is on progress in firmware\n")); ++ /* retrieve the batching data from firmware into host */ ++ dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); ++ /* store current pno_mode before disabling pno */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_enable(dhd, PNO_OFF); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); ++ goto exit; ++ } ++ /* restore the previous mode */ ++ _pno_state->pno_mode = mode; ++ /* use superset of channel list between two mode */ ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ if (_params2->params_batch.nchan > 0 && tot_nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_batch.chan_list[0], ++ _params2->params_batch.nchan, ++ &channel_list[0], tot_nchan); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to merge channel list" ++ " between legacy and batch\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ } else { ++ DHD_PNO(("superset channel will use" ++ " all channels in firmware\n")); ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ if (_params2->params_hotlist.nchan > 0 && tot_nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_hotlist.chan_list[0], ++ _params2->params_hotlist.nchan, ++ &channel_list[0], tot_nchan); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to merge channel list" ++ " between legacy and hotlist\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ } ++ } ++ } ++ _params->params_legacy.scan_fr = scan_fr; ++ _params->params_legacy.pno_repeat = pno_repeat; ++ _params->params_legacy.pno_freq_expo_max = pno_freq_expo_max; ++ _params->params_legacy.nchan = tot_nchan; ++ ssid_list = &_params->params_legacy.ssid_list; ++ nssid = _params->params_legacy.nssid; ++ ++#ifdef GSCAN_SUPPORT ++ /* dhd_pno_initiate_gscan_request will handle simultaneous Legacy PNO and GSCAN */ ++ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { ++ struct dhd_pno_gscan_params *gscan_params; ++ gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; ++ /* ePNO and Legacy PNO do not co-exist */ ++ if (gscan_params->epno_cfg.num_epno_ssid) { ++ DHD_PNO(("ePNO and Legacy PNO do not co-exist\n")); ++ err = BCME_EPERM; ++ goto exit; ++ } ++ DHD_PNO(("GSCAN mode is ON! Will restart GSCAN+Legacy PNO\n")); ++ err = dhd_pno_initiate_gscan_request(dhd, 1, 0); ++ goto exit; ++ } ++#endif /* GSCAN_SUPPORT */ ++ if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_LEGACY_MODE)) < 0) { ++ DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); ++ goto exit; ++ } ++ if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) { ++ DHD_ERROR(("failed to add ssid list(err %d), %d in firmware\n", err, nssid)); ++ goto exit; ++ } ++ if (tot_nchan > 0) { ++ if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { ++ DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++ if (_pno_state->pno_status == DHD_PNO_DISABLED) { ++ if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) ++ DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); ++ } ++exit: ++ if (err < 0) { ++ _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); ++ } ++ /* clear mode in case of error */ ++ if (err < 0) { ++ int ret = dhd_pno_clean(dhd); ++ ++ if (ret < 0) { ++ DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, ret)); ++ } else { ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ } ++ } ++ return err; ++} ++ ++int ++dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) ++{ ++ int err = BCME_OK; ++ uint16 _chan_list[WL_NUMCHANNELS]; ++ int rem_nchan = 0, tot_nchan = 0; ++ int mode = 0, mscan = 0; ++ dhd_pno_params_t *_params; ++ dhd_pno_params_t *_params2; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ NULL_CHECK(batch_params, "batch_params is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ _pno_state->pno_mode |= DHD_PNO_BATCH_MODE; ++ err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ } else { ++ /* batch mode is already started */ ++ return -EBUSY; ++ } ++ _params->params_batch.scan_fr = batch_params->scan_fr; ++ _params->params_batch.bestn = batch_params->bestn; ++ _params->params_batch.mscan = (batch_params->mscan)? ++ batch_params->mscan : DEFAULT_BATCH_MSCAN; ++ _params->params_batch.nchan = batch_params->nchan; ++ memcpy(_params->params_batch.chan_list, batch_params->chan_list, ++ sizeof(_params->params_batch.chan_list)); ++ ++ memset(_chan_list, 0, sizeof(_chan_list)); ++ ++ rem_nchan = ARRAYSIZE(batch_params->chan_list) - batch_params->nchan; ++ if (batch_params->band == WLC_BAND_2G || batch_params->band == WLC_BAND_5G) { ++ /* get a valid channel list based on band B or A */ ++ err = _dhd_pno_get_channels(dhd, ++ &_params->params_batch.chan_list[batch_params->nchan], ++ &rem_nchan, batch_params->band, FALSE); ++ if (err < 0) { ++ DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", ++ __FUNCTION__, batch_params->band)); ++ goto exit; ++ } ++ /* now we need to update nchan because rem_chan has valid channel count */ ++ _params->params_batch.nchan += rem_nchan; ++ /* need to sort channel list */ ++ sort(_params->params_batch.chan_list, _params->params_batch.nchan, ++ sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL); ++ } ++#ifdef PNO_DEBUG ++{ ++ DHD_PNO(("Channel list : ")); ++ for (i = 0; i < _params->params_batch.nchan; i++) { ++ DHD_PNO(("%d ", _params->params_batch.chan_list[i])); ++ } ++ DHD_PNO(("\n")); ++} ++#endif ++ if (_params->params_batch.nchan) { ++ /* copy the channel list into local array */ ++ memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list)); ++ tot_nchan = _params->params_batch.nchan; ++ } ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ DHD_PNO(("PNO SSID is on progress in firmware\n")); ++ /* store current pno_mode before disabling pno */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_enable(dhd, PNO_OFF); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); ++ goto exit; ++ } ++ /* restore the previous mode */ ++ _pno_state->pno_mode = mode; ++ /* Use the superset for channelist between two mode */ ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ if (_params2->params_legacy.nchan > 0 && _params->params_batch.nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_legacy.chan_list[0], ++ _params2->params_legacy.nchan, ++ &_params->params_batch.chan_list[0], _params->params_batch.nchan); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to merge channel list" ++ " between legacy and batch\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ } else { ++ DHD_PNO(("superset channel will use all channels in firmware\n")); ++ } ++ if ((err = _dhd_pno_add_ssid(dhd, &_params2->params_legacy.ssid_list, ++ _params2->params_legacy.nssid)) < 0) { ++ DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); ++ goto exit; ++ } ++ } ++ if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_BATCH_MODE)) < 0) { ++ DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } else { ++ /* we need to return mscan */ ++ mscan = err; ++ } ++ if (tot_nchan > 0) { ++ if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { ++ DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++ if (_pno_state->pno_status == DHD_PNO_DISABLED) { ++ if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) ++ DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); ++ } ++exit: ++ /* clear mode in case of error */ ++ if (err < 0) ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ else { ++ /* return #max scan firmware can do */ ++ err = mscan; ++ } ++ return err; ++} ++ ++ ++#ifdef GSCAN_SUPPORT ++ ++static int ++dhd_set_epno_params(dhd_pub_t *dhd, wl_pfn_ssid_params_t *params, bool set) ++{ ++ wl_pfn_ssid_cfg_t cfg; ++ int err; ++ NULL_CHECK(dhd, "dhd is NULL\n", err); ++ memset(&cfg, 0, sizeof(wl_pfn_ssid_cfg_t)); ++ cfg.version = WL_PFN_SSID_CFG_VERSION; ++ ++ /* If asked to clear params (set == FALSE) just set the CLEAR bit */ ++ if (!set) ++ cfg.flags |= WL_PFN_SSID_CFG_CLEAR; ++ else if (params) ++ memcpy(&cfg.params, params, sizeof(wl_pfn_ssid_params_t)); ++ err = dhd_iovar(dhd, 0, "pfn_ssid_cfg", (char *)&cfg, ++ sizeof(wl_pfn_ssid_cfg_t), NULL, 0, TRUE); ++ if (err != BCME_OK) { ++ DHD_ERROR(("%s : Failed to execute pfn_ssid_cfg %d\n", __FUNCTION__, err)); ++ } ++ return err; ++} ++ ++int ++dhd_pno_flush_fw_epno(dhd_pub_t *dhd) ++{ ++ int err; ++ ++ NULL_CHECK(dhd, "dhd is NULL\n", err); ++ ++ err = dhd_set_epno_params(dhd, NULL, FALSE); ++ if (err < 0) { ++ DHD_ERROR(("failed to set ePNO params %d\n", err)); ++ return err; ++ } ++ err = _dhd_pno_flush_ssid(dhd); ++ return err; ++} ++ ++int ++dhd_pno_set_epno(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ dhd_pno_params_t *params; ++ dhd_pno_status_info_t *_pno_state; ++ ++ struct dhd_pno_gscan_params *gscan_params; ++ ++ NULL_CHECK(dhd, "dhd is NULL\n", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ gscan_params = ¶ms->params_gscan; ++ ++ if (gscan_params->epno_cfg.num_epno_ssid) { ++ DHD_PNO(("num_epno_ssid %d\n", gscan_params->epno_cfg.num_epno_ssid)); ++ if ((err = _dhd_pno_add_ssid(dhd, &gscan_params->epno_cfg.epno_ssid_list, ++ gscan_params->epno_cfg.num_epno_ssid)) < 0) { ++ DHD_ERROR(("failed to add ssid list (err %d) to firmware\n", err)); ++ return err; ++ } ++ err = dhd_set_epno_params(dhd, &gscan_params->epno_cfg.params, TRUE); ++ if (err < 0) { ++ DHD_ERROR(("failed to set ePNO params %d\n", err)); ++ } ++ } ++ return err; ++} ++ ++ ++static void ++dhd_pno_reset_cfg_gscan(dhd_pno_params_t *_params, ++ dhd_pno_status_info_t *_pno_state, uint8 flags) ++{ ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ ++ if (flags & GSCAN_FLUSH_SCAN_CFG) { ++ _params->params_gscan.bestn = 0; ++ _params->params_gscan.mscan = 0; ++ _params->params_gscan.buffer_threshold = GSCAN_BATCH_NO_THR_SET; ++ _params->params_gscan.scan_fr = 0; ++ _params->params_gscan.send_all_results_flag = 0; ++ memset(_params->params_gscan.channel_bucket, 0, ++ _params->params_gscan.nchannel_buckets * ++ sizeof(struct dhd_pno_gscan_channel_bucket)); ++ _params->params_gscan.nchannel_buckets = 0; ++ DHD_PNO(("Flush Scan config\n")); ++ } ++ if (flags & GSCAN_FLUSH_HOTLIST_CFG) { ++ struct dhd_pno_bssid *iter, *next; ++ if (_params->params_gscan.nbssid_hotlist > 0) { ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(iter, next, ++ &_params->params_gscan.hotlist_bssid_list, list) { ++ list_del(&iter->list); ++ kfree(iter); ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ } ++ _params->params_gscan.nbssid_hotlist = 0; ++ DHD_PNO(("Flush Hotlist Config\n")); ++ } ++ if (flags & GSCAN_FLUSH_EPNO_CFG) { ++ dhd_pno_ssid_t *iter, *next; ++ dhd_epno_ssid_cfg_t *epno_cfg = &_params->params_gscan.epno_cfg; ++ ++ if (epno_cfg->num_epno_ssid > 0) { ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(iter, next, ++ &epno_cfg->epno_ssid_list, list) { ++ list_del(&iter->list); ++ kfree(iter); ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ epno_cfg->num_epno_ssid = 0; ++ } ++ memset(&epno_cfg->params, 0, sizeof(wl_pfn_ssid_params_t)); ++ DHD_PNO(("Flushed ePNO Config\n")); ++ } ++ ++ return; ++} ++ ++int ++dhd_pno_lock_batch_results(dhd_pub_t *dhd) ++{ ++ dhd_pno_status_info_t *_pno_state; ++ int err = BCME_OK; ++ ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ mutex_lock(&_pno_state->pno_mutex); ++ return err; ++} ++ ++void ++dhd_pno_unlock_batch_results(dhd_pub_t *dhd) ++{ ++ dhd_pno_status_info_t *_pno_state; ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ mutex_unlock(&_pno_state->pno_mutex); ++ return; ++} ++ ++int dhd_wait_batch_results_complete(dhd_pub_t *dhd) ++{ ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ int err = BCME_OK; ++ ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ ++ /* Has the workqueue finished its job already?? */ ++ if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_IN_PROGRESS) { ++ DHD_PNO(("%s: Waiting to complete retrieval..\n", __FUNCTION__)); ++ wait_event_interruptible_timeout(_pno_state->batch_get_wait, ++ is_batch_retrieval_complete(&_params->params_gscan), ++ msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); ++ } else { /* GSCAN_BATCH_RETRIEVAL_COMPLETE */ ++ gscan_results_cache_t *iter; ++ uint16 num_results = 0; ++ ++ mutex_lock(&_pno_state->pno_mutex); ++ iter = _params->params_gscan.gscan_batch_cache; ++ while (iter) { ++ num_results += iter->tot_count - iter->tot_consumed; ++ iter = iter->next; ++ } ++ mutex_unlock(&_pno_state->pno_mutex); ++ ++ /* All results consumed/No results cached?? ++ * Get fresh results from FW ++ */ ++ if ((_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) && !num_results) { ++ DHD_PNO(("%s: No results cached, getting from FW..\n", __FUNCTION__)); ++ err = dhd_retreive_batch_scan_results(dhd); ++ if (err == BCME_OK) { ++ wait_event_interruptible_timeout(_pno_state->batch_get_wait, ++ is_batch_retrieval_complete(&_params->params_gscan), ++ msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); ++ } ++ } ++ } ++ DHD_PNO(("%s: Wait complete\n", __FUNCTION__)); ++ return err; ++} ++ ++static void * ++dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len) ++{ ++ gscan_results_cache_t *iter, *results; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ uint16 num_scan_ids = 0, num_results = 0; ++ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ ++ iter = results = _params->params_gscan.gscan_batch_cache; ++ while (iter) { ++ num_results += iter->tot_count - iter->tot_consumed; ++ num_scan_ids++; ++ iter = iter->next; ++ } ++ ++ *len = ((num_results << 16) | (num_scan_ids)); ++ return results; ++} ++ ++int ++dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, ++ void *buf, bool flush) ++{ ++ int err = BCME_OK; ++ dhd_pno_params_t *_params; ++ int i; ++ dhd_pno_status_info_t *_pno_state; ++ ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ mutex_lock(&_pno_state->pno_mutex); ++ ++ switch (type) { ++ case DHD_PNO_BATCH_SCAN_CFG_ID: ++ { ++ gscan_batch_params_t *ptr = (gscan_batch_params_t *)buf; ++ _params->params_gscan.bestn = ptr->bestn; ++ _params->params_gscan.mscan = ptr->mscan; ++ _params->params_gscan.buffer_threshold = ptr->buffer_threshold; ++ } ++ break; ++ case DHD_PNO_GEOFENCE_SCAN_CFG_ID: ++ { ++ gscan_hotlist_scan_params_t *ptr = (gscan_hotlist_scan_params_t *)buf; ++ struct dhd_pno_bssid *_pno_bssid; ++ struct bssid_t *bssid_ptr; ++ int8 flags; ++ ++ if (flush) { ++ dhd_pno_reset_cfg_gscan(_params, _pno_state, ++ GSCAN_FLUSH_HOTLIST_CFG); ++ } ++ ++ if (!ptr->nbssid) { ++ break; ++ } ++ if (!_params->params_gscan.nbssid_hotlist) { ++ INIT_LIST_HEAD(&_params->params_gscan.hotlist_bssid_list); ++ } ++ ++ for (i = 0, bssid_ptr = ptr->bssid; i < ptr->nbssid; i++, bssid_ptr++) { ++ _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); ++ ++ if (!_pno_bssid) { ++ DHD_ERROR(("_pno_bssid is NULL, cannot kalloc %zd bytes", ++ sizeof(struct dhd_pno_bssid))); ++ err = BCME_NOMEM; ++ goto exit; ++ } ++ memcpy(&_pno_bssid->macaddr, &bssid_ptr->macaddr, ETHER_ADDR_LEN); ++ ++ flags = (int8) bssid_ptr->rssi_reporting_threshold; ++ _pno_bssid->flags = flags << WL_PFN_RSSI_SHIFT; ++ list_add_tail(&_pno_bssid->list, ++ &_params->params_gscan.hotlist_bssid_list); ++ } ++ ++ _params->params_gscan.nbssid_hotlist += ptr->nbssid; ++ _params->params_gscan.lost_ap_window = ptr->lost_ap_window; ++ } ++ break; ++ case DHD_PNO_SCAN_CFG_ID: ++ { ++ int k; ++ uint16 band; ++ gscan_scan_params_t *ptr = (gscan_scan_params_t *)buf; ++ struct dhd_pno_gscan_channel_bucket *ch_bucket; ++ ++ if (ptr->nchannel_buckets <= GSCAN_MAX_CH_BUCKETS) { ++ _params->params_gscan.nchannel_buckets = ptr->nchannel_buckets; ++ ++ memcpy(_params->params_gscan.channel_bucket, ptr->channel_bucket, ++ _params->params_gscan.nchannel_buckets * ++ sizeof(struct dhd_pno_gscan_channel_bucket)); ++ ch_bucket = _params->params_gscan.channel_bucket; ++ ++ for (i = 0; i < ptr->nchannel_buckets; i++) { ++ band = ch_bucket[i].band; ++ for (k = 0; k < ptr->channel_bucket[i].num_channels; k++) { ++ ch_bucket[i].chan_list[k] = ++ wf_mhz2channel(ptr->channel_bucket[i].chan_list[k], ++ 0); ++ } ++ ch_bucket[i].band = 0; ++ /* HAL and DHD use different bits for 2.4G and ++ * 5G in bitmap. Hence translating it here... ++ */ ++ if (band & GSCAN_BG_BAND_MASK) { ++ ch_bucket[i].band |= WLC_BAND_2G; ++ } ++ if (band & GSCAN_A_BAND_MASK) { ++ ch_bucket[i].band |= WLC_BAND_5G; ++ } ++ if (band & GSCAN_DFS_MASK) { ++ ch_bucket[i].band |= GSCAN_DFS_MASK; ++ } ++ DHD_PNO(("band %d report_flag %d\n", ch_bucket[i].band, ++ ch_bucket[i].report_flag)); ++ } ++ ++ for (i = 0; i < ptr->nchannel_buckets; i++) { ++ ch_bucket[i].bucket_freq_multiple = ++ ch_bucket[i].bucket_freq_multiple/ptr->scan_fr; ++ ch_bucket[i].bucket_max_multiple = ++ ch_bucket[i].bucket_max_multiple/ptr->scan_fr; ++ DHD_PNO(("mult %d max_mult %d\n", ++ ch_bucket[i].bucket_freq_multiple, ++ ch_bucket[i].bucket_max_multiple)); ++ } ++ _params->params_gscan.scan_fr = ptr->scan_fr; ++ ++ DHD_PNO(("num_buckets %d scan_fr %d\n", ptr->nchannel_buckets, ++ _params->params_gscan.scan_fr)); ++ } else { ++ err = BCME_BADARG; ++ } ++ } ++ break; ++ case DHD_PNO_EPNO_CFG_ID: ++ if (flush) { ++ dhd_pno_reset_cfg_gscan(_params, _pno_state, ++ GSCAN_FLUSH_EPNO_CFG); ++ } ++ break; ++ case DHD_PNO_EPNO_PARAMS_ID: ++ if (flush) { ++ memset(&_params->params_gscan.epno_cfg.params, 0, ++ sizeof(wl_pfn_ssid_params_t)); ++ } ++ if (buf) { ++ memcpy(&_params->params_gscan.epno_cfg.params, buf, ++ sizeof(wl_pfn_ssid_params_t)); ++ } ++ break; ++ default: ++ err = BCME_BADARG; ++ DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); ++ break; ++ } ++exit: ++ mutex_unlock(&_pno_state->pno_mutex); ++ return err; ++ ++} ++ ++ ++static bool ++validate_gscan_params(struct dhd_pno_gscan_params *gscan_params) ++{ ++ unsigned int i, k; ++ ++ if (!gscan_params->scan_fr || !gscan_params->nchannel_buckets) { ++ DHD_ERROR(("%s : Scan freq - %d or number of channel buckets - %d is empty\n", ++ __FUNCTION__, gscan_params->scan_fr, gscan_params->nchannel_buckets)); ++ return false; ++ } ++ ++ for (i = 0; i < gscan_params->nchannel_buckets; i++) { ++ if (!gscan_params->channel_bucket[i].band) { ++ for (k = 0; k < gscan_params->channel_bucket[i].num_channels; k++) { ++ if (gscan_params->channel_bucket[i].chan_list[k] > CHANNEL_5G_MAX) { ++ DHD_ERROR(("%s : Unknown channel %d\n", __FUNCTION__, ++ gscan_params->channel_bucket[i].chan_list[k])); ++ return false; ++ } ++ } ++ } ++ } ++ ++ return true; ++} ++ ++static int ++dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) ++{ ++ int err = BCME_OK; ++ int mode, i = 0; ++ uint16 _chan_list[WL_NUMCHANNELS]; ++ int tot_nchan = 0; ++ int num_buckets_to_fw, tot_num_buckets, gscan_param_size; ++ dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); ++ wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL; ++ wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL; ++ wl_pfn_significant_bssid_t *p_pfn_significant_bssid = NULL; ++ wl_pfn_bssid_t *p_pfn_bssid = NULL; ++ dhd_pno_params_t *_params; ++ bool fw_flushed = FALSE; ++ ++ _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ NULL_CHECK(gscan_params, "gscan_params is NULL", err); ++ ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ if (!validate_gscan_params(gscan_params)) { ++ DHD_ERROR(("%s : Cannot start gscan - bad params\n", __FUNCTION__)); ++ err = BCME_BADARG; ++ goto exit; ++ } ++ ++ if (!(ch_bucket = dhd_pno_gscan_create_channel_list(dhd, _pno_state, ++ _chan_list, &tot_num_buckets, &num_buckets_to_fw))) { ++ goto exit; ++ } ++ ++ mutex_lock(&_pno_state->pno_mutex); ++ /* Clear any pre-existing results in our cache ++ * not consumed by framework ++ */ ++ dhd_gscan_clear_all_batch_results(dhd); ++ if (_pno_state->pno_mode & (DHD_PNO_GSCAN_MODE | DHD_PNO_LEGACY_MODE)) { ++ /* store current pno_mode before disabling pno */ ++ mode = _pno_state->pno_mode; ++ err = dhd_pno_clean(dhd); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); ++ mutex_unlock(&_pno_state->pno_mutex); ++ goto exit; ++ } ++ fw_flushed = TRUE; ++ /* restore the previous mode */ ++ _pno_state->pno_mode = mode; ++ } ++ _pno_state->pno_mode |= DHD_PNO_GSCAN_MODE; ++ mutex_unlock(&_pno_state->pno_mutex); ++ ++ if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && ++ !gscan_params->epno_cfg.num_epno_ssid) { ++ struct dhd_pno_legacy_params *params_legacy; ++ params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); ++ ++ if ((err = _dhd_pno_add_ssid(dhd, ¶ms_legacy->ssid_list, ++ params_legacy->nssid)) < 0) { ++ DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); ++ goto exit; ++ } ++ } ++ ++ if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_GSCAN_MODE)) < 0) { ++ DHD_ERROR(("failed to set call pno_set (err %d) in firmware\n", err)); ++ goto exit; ++ } ++ ++ gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + ++ (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); ++ pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOCZ(dhd->osh, gscan_param_size); ++ ++ if (!pfn_gscan_cfg_t) { ++ DHD_ERROR(("%s: failed to malloc memory of size %d\n", ++ __FUNCTION__, gscan_param_size)); ++ err = BCME_NOMEM; ++ goto exit; ++ } ++ ++ pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION; ++ if (gscan_params->mscan) ++ pfn_gscan_cfg_t->buffer_threshold = gscan_params->buffer_threshold; ++ else ++ pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET; ++ ++ pfn_gscan_cfg_t->flags = ++ (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); ++ pfn_gscan_cfg_t->flags |= GSCAN_ALL_BUCKETS_IN_FIRST_SCAN_MASK; ++ pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw; ++ pfn_gscan_cfg_t->retry_threshold = GSCAN_RETRY_THRESHOLD; ++ ++ for (i = 0; i < num_buckets_to_fw; i++) { ++ pfn_gscan_cfg_t->channel_bucket[i].bucket_end_index = ++ ch_bucket[i].bucket_end_index; ++ pfn_gscan_cfg_t->channel_bucket[i].bucket_freq_multiple = ++ ch_bucket[i].bucket_freq_multiple; ++ pfn_gscan_cfg_t->channel_bucket[i].max_freq_multiple = ++ ch_bucket[i].max_freq_multiple; ++ pfn_gscan_cfg_t->channel_bucket[i].repeat = ++ ch_bucket[i].repeat; ++ pfn_gscan_cfg_t->channel_bucket[i].flag = ++ ch_bucket[i].flag; ++ } ++ ++ tot_nchan = pfn_gscan_cfg_t->channel_bucket[num_buckets_to_fw - 1].bucket_end_index + 1; ++ DHD_PNO(("Total channel num %d total ch_buckets %d ch_buckets_to_fw %d \n", tot_nchan, ++ tot_num_buckets, num_buckets_to_fw)); ++ ++ if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { ++ DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ ++ if ((err = _dhd_pno_gscan_cfg(dhd, pfn_gscan_cfg_t, gscan_param_size)) < 0) { ++ DHD_ERROR(("%s : failed to set call pno_gscan_cfg (err %d) in firmware\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ /* Reprogram ePNO cfg from dhd cache if FW has been flushed */ ++ if (fw_flushed) { ++ dhd_pno_set_epno(dhd); ++ } ++ ++ if (gscan_params->nbssid_hotlist) { ++ struct dhd_pno_bssid *iter, *next; ++ wl_pfn_bssid_t *ptr; ++ p_pfn_bssid = (wl_pfn_bssid_t *)kzalloc(sizeof(wl_pfn_bssid_t) * ++ gscan_params->nbssid_hotlist, GFP_KERNEL); ++ if (p_pfn_bssid == NULL) { ++ DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" ++ " (count: %d)", ++ __FUNCTION__, _params->params_hotlist.nbssid)); ++ err = BCME_NOMEM; ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ goto exit; ++ } ++ ptr = p_pfn_bssid; ++ /* convert dhd_pno_bssid to wl_pfn_bssid */ ++ DHD_PNO(("nhotlist %d\n", gscan_params->nbssid_hotlist)); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(iter, next, ++ &gscan_params->hotlist_bssid_list, list) { ++ char buffer_hotlist[64]; ++ memcpy(&ptr->macaddr, ++ &iter->macaddr, ETHER_ADDR_LEN); ++ DHD_PNO(("%s\n", bcm_ether_ntoa(&ptr->macaddr, buffer_hotlist))); ++ BCM_REFERENCE(buffer_hotlist); ++ ptr->flags = iter->flags; ++ ptr++; ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ ++ err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, gscan_params->nbssid_hotlist); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++ if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) { ++ DHD_ERROR(("%s : failed to enable PNO err %d\n", __FUNCTION__, err)); ++ } ++ ++exit: ++ /* clear mode in case of error */ ++ if (err < 0) { ++ int ret = dhd_pno_clean(dhd); ++ ++ if (ret < 0) { ++ DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, ret)); ++ } else { ++ _pno_state->pno_mode &= ~DHD_PNO_GSCAN_MODE; ++ } ++ } ++ kfree(p_pfn_significant_bssid); ++ kfree(p_pfn_bssid); ++ if (pfn_gscan_cfg_t) { ++ MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size); ++ } ++ if (ch_bucket) { ++ MFREE(dhd->osh, ch_bucket, ++ (tot_num_buckets * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); ++ } ++ return err; ++ ++} ++ ++static wl_pfn_gscan_ch_bucket_cfg_t * ++dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, ++ dhd_pno_status_info_t *_pno_state, ++ uint16 *chan_list, ++ uint32 *num_buckets, ++ uint32 *num_buckets_to_fw) ++{ ++ int i, num_channels, err, nchan = WL_NUMCHANNELS, ch_cnt; ++ uint16 *ptr = chan_list, max; ++ wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket; ++ dhd_pno_params_t *_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ bool is_pno_legacy_running; ++ dhd_pno_gscan_channel_bucket_t *gscan_buckets = _params->params_gscan.channel_bucket; ++ ++ /* ePNO and Legacy PNO do not co-exist */ ++ is_pno_legacy_running = ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && ++ !_params->params_gscan.epno_cfg.num_epno_ssid); ++ ++ if (is_pno_legacy_running) ++ *num_buckets = _params->params_gscan.nchannel_buckets + 1; ++ else ++ *num_buckets = _params->params_gscan.nchannel_buckets; ++ ++ *num_buckets_to_fw = 0; ++ ++ ch_bucket = (wl_pfn_gscan_ch_bucket_cfg_t *) MALLOC(dhd->osh, ++ ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); ++ ++ if (!ch_bucket) { ++ DHD_ERROR(("%s: failed to malloc memory of size %zd\n", ++ __FUNCTION__, (*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); ++ *num_buckets_to_fw = *num_buckets = 0; ++ return NULL; ++ } ++ ++ max = gscan_buckets[0].bucket_freq_multiple; ++ num_channels = 0; ++ /* nchan is the remaining space left in chan_list buffer ++ * So any overflow list of channels is ignored ++ */ ++ for (i = 0; i < _params->params_gscan.nchannel_buckets && nchan; i++) { ++ if (!gscan_buckets[i].band) { ++ ch_cnt = MIN(gscan_buckets[i].num_channels, (uint8)nchan); ++ num_channels += ch_cnt; ++ memcpy(ptr, gscan_buckets[i].chan_list, ++ ch_cnt * sizeof(uint16)); ++ ptr = ptr + ch_cnt; ++ } else { ++ /* get a valid channel list based on band B or A */ ++ err = _dhd_pno_get_channels(dhd, ptr, ++ &nchan, (gscan_buckets[i].band & GSCAN_ABG_BAND_MASK), ++ !(gscan_buckets[i].band & GSCAN_DFS_MASK)); ++ ++ if (err < 0) { ++ DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", ++ __FUNCTION__, gscan_buckets[i].band)); ++ MFREE(dhd->osh, ch_bucket, ++ ((*num_buckets) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t))); ++ *num_buckets_to_fw = *num_buckets = 0; ++ return NULL; ++ } ++ ++ num_channels += nchan; ++ ptr = ptr + nchan; ++ } ++ ++ ch_bucket[i].bucket_end_index = num_channels - 1; ++ ch_bucket[i].bucket_freq_multiple = gscan_buckets[i].bucket_freq_multiple; ++ ch_bucket[i].repeat = gscan_buckets[i].repeat; ++ ch_bucket[i].max_freq_multiple = gscan_buckets[i].bucket_max_multiple; ++ ch_bucket[i].flag = gscan_buckets[i].report_flag; ++ /* HAL and FW interpretations are opposite for this bit */ ++ ch_bucket[i].flag ^= DHD_PNO_REPORT_NO_BATCH; ++ if (max < gscan_buckets[i].bucket_freq_multiple) ++ max = gscan_buckets[i].bucket_freq_multiple; ++ nchan = WL_NUMCHANNELS - num_channels; ++ *num_buckets_to_fw = *num_buckets_to_fw + 1; ++ DHD_PNO(("end_idx %d freq_mult - %d\n", ++ ch_bucket[i].bucket_end_index, ch_bucket[i].bucket_freq_multiple)); ++ } ++ ++ _params->params_gscan.max_ch_bucket_freq = max; ++ /* Legacy PNO maybe running, which means we need to create a legacy PNO bucket ++ * Get GCF of Legacy PNO and Gscan scanfreq ++ */ ++ if (is_pno_legacy_running) { ++ dhd_pno_params_t *_params1 = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; ++ uint16 *legacy_chan_list = _params1->params_legacy.chan_list; ++ uint16 common_freq; ++ uint32 legacy_bucket_idx = _params->params_gscan.nchannel_buckets; ++ /* If no space is left then only gscan buckets will be sent to FW */ ++ if (nchan) { ++ common_freq = gcd(_params->params_gscan.scan_fr, ++ _params1->params_legacy.scan_fr); ++ max = gscan_buckets[0].bucket_freq_multiple; ++ /* GSCAN buckets */ ++ for (i = 0; i < _params->params_gscan.nchannel_buckets; i++) { ++ ch_bucket[i].bucket_freq_multiple *= _params->params_gscan.scan_fr; ++ ch_bucket[i].bucket_freq_multiple /= common_freq; ++ if (max < gscan_buckets[i].bucket_freq_multiple) ++ max = gscan_buckets[i].bucket_freq_multiple; ++ } ++ /* Legacy PNO bucket */ ++ ch_bucket[legacy_bucket_idx].bucket_freq_multiple = ++ _params1->params_legacy.scan_fr; ++ ch_bucket[legacy_bucket_idx].bucket_freq_multiple /= ++ common_freq; ++ _params->params_gscan.max_ch_bucket_freq = MAX(max, ++ ch_bucket[legacy_bucket_idx].bucket_freq_multiple); ++ ch_bucket[legacy_bucket_idx].flag = CH_BUCKET_REPORT_REGULAR; ++ /* Now add channels to the legacy scan bucket */ ++ for (i = 0; i < _params1->params_legacy.nchan && nchan; i++, nchan--) { ++ ptr[i] = legacy_chan_list[i]; ++ num_channels++; ++ } ++ ch_bucket[legacy_bucket_idx].bucket_end_index = num_channels - 1; ++ *num_buckets_to_fw = *num_buckets_to_fw + 1; ++ DHD_PNO(("end_idx %d freq_mult - %d\n", ++ ch_bucket[legacy_bucket_idx].bucket_end_index, ++ ch_bucket[legacy_bucket_idx].bucket_freq_multiple)); ++ } ++ } ++ return ch_bucket; ++} ++ ++static int ++dhd_pno_stop_for_gscan(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ int mode; ++ dhd_pno_status_info_t *_pno_state; ++ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", ++ __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { ++ DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__)); ++ goto exit; ++ } ++ if (_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.mscan) { ++ /* retrieve the batching data from firmware into host */ ++ err = dhd_wait_batch_results_complete(dhd); ++ if (err != BCME_OK) ++ goto exit; ++ } ++ mutex_lock(&_pno_state->pno_mutex); ++ mode = _pno_state->pno_mode & ~DHD_PNO_GSCAN_MODE; ++ err = dhd_pno_clean(dhd); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err)); ++ mutex_unlock(&_pno_state->pno_mutex); ++ return err; ++ } ++ _pno_state->pno_mode = mode; ++ mutex_unlock(&_pno_state->pno_mutex); ++ ++ /* Reprogram Legacy PNO if it was running */ ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ struct dhd_pno_legacy_params *params_legacy; ++ uint16 chan_list[WL_NUMCHANNELS]; ++ ++ params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); ++ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; ++ DHD_PNO(("Restarting Legacy PNO SSID scan...\n")); ++ memcpy(chan_list, params_legacy->chan_list, ++ (params_legacy->nchan * sizeof(uint16))); ++ err = dhd_pno_set_legacy_pno(dhd, params_legacy->scan_fr, ++ params_legacy->pno_repeat, params_legacy->pno_freq_expo_max, ++ chan_list, params_legacy->nchan); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ ++ } ++ ++exit: ++ return err; ++} ++ ++int ++dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush) ++{ ++ int err = BCME_OK; ++ dhd_pno_params_t *params; ++ dhd_pno_status_info_t *_pno_state; ++ struct dhd_pno_gscan_params *gscan_params; ++ ++ NULL_CHECK(dhd, "dhd is NULL\n", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ DHD_PNO(("%s enter - run %d flush %d\n", __FUNCTION__, run, flush)); ++ ++ params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ gscan_params = ¶ms->params_gscan; ++ ++ if (run) { ++ err = dhd_pno_set_for_gscan(dhd, gscan_params); ++ } else { ++ if (flush) { ++ mutex_lock(&_pno_state->pno_mutex); ++ dhd_pno_reset_cfg_gscan(params, _pno_state, GSCAN_FLUSH_ALL_CFG); ++ mutex_unlock(&_pno_state->pno_mutex); ++ } ++ /* Need to stop all gscan */ ++ err = dhd_pno_stop_for_gscan(dhd); ++ } ++ ++ return err; ++} ++ ++int ++dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag) ++{ ++ int err = BCME_OK; ++ dhd_pno_params_t *params; ++ dhd_pno_status_info_t *_pno_state; ++ struct dhd_pno_gscan_params *gscan_params; ++ uint8 old_flag; ++ ++ NULL_CHECK(dhd, "dhd is NULL\n", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ gscan_params = ¶ms->params_gscan; ++ ++ mutex_lock(&_pno_state->pno_mutex); ++ ++ old_flag = gscan_params->send_all_results_flag; ++ gscan_params->send_all_results_flag = (uint8) real_time_flag; ++ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { ++ if (old_flag != gscan_params->send_all_results_flag) { ++ wl_pfn_gscan_cfg_t gscan_cfg; ++ ++ gscan_cfg.version = WL_GSCAN_CFG_VERSION; ++ gscan_cfg.flags = (gscan_params->send_all_results_flag & ++ GSCAN_SEND_ALL_RESULTS_MASK); ++ gscan_cfg.flags |= GSCAN_CFG_FLAGS_ONLY_MASK; ++ ++ if ((err = _dhd_pno_gscan_cfg(dhd, &gscan_cfg, ++ sizeof(wl_pfn_gscan_cfg_t))) < 0) { ++ DHD_ERROR(("%s : pno_gscan_cfg failed (err %d) in firmware\n", ++ __FUNCTION__, err)); ++ goto exit_mutex_unlock; ++ } ++ } else { ++ DHD_PNO(("No change in flag - %d\n", old_flag)); ++ } ++ } else { ++ DHD_PNO(("Gscan not started\n")); ++ } ++exit_mutex_unlock: ++ mutex_unlock(&_pno_state->pno_mutex); ++exit: ++ return err; ++} ++ ++/* Cleanup any consumed results ++ * Return TRUE if all results consumed, else FALSE ++ */ ++int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd) ++{ ++ int ret = 0; ++ dhd_pno_params_t *params; ++ struct dhd_pno_gscan_params *gscan_params; ++ dhd_pno_status_info_t *_pno_state; ++ gscan_results_cache_t *iter, *tmp; ++ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ gscan_params = ¶ms->params_gscan; ++ iter = gscan_params->gscan_batch_cache; ++ ++ while (iter) { ++ if (iter->tot_consumed == iter->tot_count) { ++ tmp = iter->next; ++ kfree(iter); ++ iter = tmp; ++ } else ++ break; ++ } ++ gscan_params->gscan_batch_cache = iter; ++ ret = (iter == NULL); ++ return ret; ++} ++ ++static int ++_dhd_pno_get_gscan_batch_from_fw(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ uint32 timestamp = 0, ts = 0, i, j, timediff; ++ dhd_pno_params_t *params; ++ dhd_pno_status_info_t *_pno_state; ++ wl_pfn_lnet_info_v2_t *plnetinfo; ++ struct dhd_pno_gscan_params *gscan_params; ++ wl_pfn_lscanresults_v2_t *plbestnet = NULL; ++ gscan_results_cache_t *iter, *tail; ++ wifi_gscan_result_t *result; ++ uint8 *nAPs_per_scan = NULL; ++ uint8 num_scans_in_cur_iter; ++ uint16 count; ++ struct osl_timespec tm_spec; ++ ++ NULL_CHECK(dhd, "dhd is NULL\n", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { ++ DHD_ERROR(("%s: GSCAN is not enabled\n", __FUNCTION__)); ++ goto exit; ++ } ++ gscan_params = ¶ms->params_gscan; ++ nAPs_per_scan = (uint8 *) MALLOC(dhd->osh, gscan_params->mscan); ++ ++ if (!nAPs_per_scan) { ++ DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, ++ gscan_params->mscan)); ++ err = BCME_NOMEM; ++ goto exit; ++ } ++ ++ plbestnet = (wl_pfn_lscanresults_v2_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); ++ if (!plbestnet) { ++ DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, ++ PNO_BESTNET_LEN)); ++ err = BCME_NOMEM; ++ goto exit; ++ } ++ ++ mutex_lock(&_pno_state->pno_mutex); ++ ++ dhd_gscan_clear_all_batch_results(dhd); ++ ++ if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { ++ DHD_ERROR(("%s : GSCAN is not enabled\n", __FUNCTION__)); ++ goto exit_mutex_unlock; ++ } ++ ++ timediff = gscan_params->scan_fr * 1000; ++ timediff = timediff >> 1; ++ ++ /* Ok, now lets start getting results from the FW */ ++ plbestnet->status = PFN_INCOMPLETE; ++ tail = gscan_params->gscan_batch_cache; ++ while (plbestnet->status != PFN_COMPLETE) { ++ memset(plbestnet, 0, PNO_BESTNET_LEN); ++ err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet, PNO_BESTNET_LEN, ++ FALSE); ++ if (err < 0) { ++ DHD_ERROR(("%s : Cannot get all the batch results, err :%d\n", ++ __FUNCTION__, err)); ++ goto exit_mutex_unlock; ++ } ++ osl_get_monotonic_boottime(&tm_spec); ++ DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, ++ plbestnet->status, plbestnet->count)); ++ if (plbestnet->version != PFN_SCANRESULT_VERSION) { ++ err = BCME_VERSION; ++ DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", ++ plbestnet->version, PFN_SCANRESULT_VERSION)); ++ goto exit_mutex_unlock; ++ } ++ if (plbestnet->count == 0) { ++ DHD_PNO(("No more batch results\n")); ++ goto exit_mutex_unlock; ++ } ++ num_scans_in_cur_iter = 0; ++ timestamp = plbestnet->netinfo[0].timestamp; ++ /* find out how many scans' results did we get in this batch of FW results */ ++ for (i = 0, count = 0; i < plbestnet->count; i++, count++) { ++ plnetinfo = &plbestnet->netinfo[i]; ++ /* Unlikely to happen, but just in case the results from ++ * FW doesnt make sense..... Assume its part of one single scan ++ */ ++ if (num_scans_in_cur_iter >= gscan_params->mscan) { ++ num_scans_in_cur_iter = 0; ++ count = plbestnet->count; ++ break; ++ } ++ if (TIME_DIFF_MS(timestamp, plnetinfo->timestamp) > timediff) { ++ nAPs_per_scan[num_scans_in_cur_iter] = count; ++ count = 0; ++ num_scans_in_cur_iter++; ++ } ++ timestamp = plnetinfo->timestamp; ++ } ++ if (num_scans_in_cur_iter < gscan_params->mscan) { ++ nAPs_per_scan[num_scans_in_cur_iter] = count; ++ num_scans_in_cur_iter++; ++ } ++ ++ DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter)); ++ plnetinfo = &plbestnet->netinfo[0]; ++ ++ for (i = 0; i < num_scans_in_cur_iter; i++) { ++ iter = (gscan_results_cache_t *) ++ kmalloc(((nAPs_per_scan[i] - 1) * sizeof(wifi_gscan_result_t)) + ++ sizeof(gscan_results_cache_t), GFP_KERNEL); ++ if (!iter) { ++ DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", ++ __FUNCTION__, gscan_params->mscan)); ++ err = BCME_NOMEM; ++ goto exit_mutex_unlock; ++ } ++ /* Need this check because the new set of results from FW ++ * maybe a continuation of previous sets' scan results ++ */ ++ if (TIME_DIFF_MS(ts, plnetinfo->timestamp) > timediff) { ++ iter->scan_id = ++gscan_params->scan_id; ++ } else { ++ iter->scan_id = gscan_params->scan_id; ++ } ++ DHD_PNO(("scan_id %d tot_count %d ch_bucket %x\n", ++ gscan_params->scan_id, nAPs_per_scan[i], ++ plbestnet->scan_ch_buckets[i])); ++ iter->tot_count = nAPs_per_scan[i]; ++ iter->scan_ch_bucket = plbestnet->scan_ch_buckets[i]; ++ iter->tot_consumed = 0; ++ iter->flag = 0; ++ if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { ++ DHD_PNO(("This scan is aborted\n")); ++ iter->flag = (ENABLE << PNO_STATUS_ABORT); ++ } else if (gscan_params->reason) { ++ iter->flag = (ENABLE << gscan_params->reason); ++ } ++ ++ if (!tail) { ++ gscan_params->gscan_batch_cache = iter; ++ } else { ++ tail->next = iter; ++ } ++ tail = iter; ++ iter->next = NULL; ++ for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo++) { ++ result = &iter->results[j]; ++ ++ result->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, ++ (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); ++ result->rssi = (int32) plnetinfo->RSSI; ++ /* Info not available & not expected */ ++ result->beacon_period = 0; ++ result->capability = 0; ++ result->rtt = (uint64) plnetinfo->rtt0; ++ result->rtt_sd = (uint64) plnetinfo->rtt1; ++ result->ts = convert_fw_rel_time_to_systime(&tm_spec, ++ plnetinfo->timestamp); ++ ts = plnetinfo->timestamp; ++ if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { ++ DHD_ERROR(("%s: Invalid SSID length %d\n", ++ __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); ++ plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; ++ } ++ memcpy(result->ssid, plnetinfo->pfnsubnet.u.SSID, ++ plnetinfo->pfnsubnet.SSID_len); ++ result->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; ++ memcpy(&result->macaddr, &plnetinfo->pfnsubnet.BSSID, ++ ETHER_ADDR_LEN); ++ ++ DHD_PNO(("\tSSID : ")); ++ DHD_PNO(("\n")); ++ DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ result->macaddr.octet[0], ++ result->macaddr.octet[1], ++ result->macaddr.octet[2], ++ result->macaddr.octet[3], ++ result->macaddr.octet[4], ++ result->macaddr.octet[5])); ++ DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", ++ plnetinfo->pfnsubnet.channel, ++ plnetinfo->RSSI, plnetinfo->timestamp)); ++ DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", ++ plnetinfo->rtt0, plnetinfo->rtt1)); ++ ++ } ++ } ++ } ++exit_mutex_unlock: ++ mutex_unlock(&_pno_state->pno_mutex); ++exit: ++ params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_COMPLETE; ++ smp_wmb(); ++ wake_up_interruptible(&_pno_state->batch_get_wait); ++ if (nAPs_per_scan) { ++ MFREE(dhd->osh, nAPs_per_scan, gscan_params->mscan * sizeof(uint8)); ++ } ++ if (plbestnet) { ++ MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); ++ } ++ DHD_PNO(("Batch retrieval done!\n")); ++ return err; ++} ++#endif /* GSCAN_SUPPORT */ ++ ++#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) ++void * ++dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, ++ void *info, uint32 *len) ++{ ++ void *ret = NULL; ++ dhd_pno_gscan_capabilities_t *ptr; ++ dhd_pno_ssid_t *ssid_elem; ++ dhd_pno_params_t *_params; ++ dhd_epno_ssid_cfg_t *epno_cfg; ++ dhd_pno_status_info_t *_pno_state; ++ ++ ++ if (!dhd || !dhd->pno_state) { ++ DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__)); ++ return NULL; ++ } ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ if (!len) { ++ DHD_ERROR(("%s: len is NULL\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ switch (type) { ++ case DHD_PNO_GET_CAPABILITIES: ++ ptr = (dhd_pno_gscan_capabilities_t *) ++ kmalloc(sizeof(dhd_pno_gscan_capabilities_t), GFP_KERNEL); ++ if (!ptr) ++ break; ++ /* Hardcoding these values for now, need to get ++ * these values from FW, will change in a later check-in ++ */ ++ ptr->max_scan_cache_size = GSCAN_MAX_AP_CACHE; ++ ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS; ++ ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN; ++ ptr->max_scan_reporting_threshold = 100; ++ ptr->max_hotlist_aps = PFN_HOTLIST_MAX_NUM_APS; ++ ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM; ++ ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID; ++ ptr->max_white_list_ssid = MAX_WHITELIST_SSID; ++ ret = (void *)ptr; ++ *len = sizeof(dhd_pno_gscan_capabilities_t); ++ break; ++#ifdef GSCAN_SUPPORT ++ case DHD_PNO_GET_BATCH_RESULTS: ++ ret = dhd_get_gscan_batch_results(dhd, len); ++ break; ++#endif /* GSCAN_SUPPORT */ ++ case DHD_PNO_GET_CHANNEL_LIST: ++ if (info) { ++ uint16 ch_list[WL_NUMCHANNELS]; ++ uint32 *p, mem_needed, i; ++ int32 err, nchan = WL_NUMCHANNELS; ++ uint32 *gscan_band = (uint32 *) info; ++ uint8 band = 0; ++ ++ /* No band specified?, nothing to do */ ++ if ((*gscan_band & GSCAN_BAND_MASK) == 0) { ++ DHD_PNO(("No band specified\n")); ++ *len = 0; ++ break; ++ } ++ ++ /* HAL and DHD use different bits for 2.4G and ++ * 5G in bitmap. Hence translating it here... ++ */ ++ if (*gscan_band & GSCAN_BG_BAND_MASK) { ++ band |= WLC_BAND_2G; ++ } ++ if (*gscan_band & GSCAN_A_BAND_MASK) { ++ band |= WLC_BAND_5G; ++ } ++ ++ err = _dhd_pno_get_channels(dhd, ch_list, &nchan, ++ (band & GSCAN_ABG_BAND_MASK), ++ !(*gscan_band & GSCAN_DFS_MASK)); ++ ++ if (err < 0) { ++ DHD_ERROR(("%s: failed to get valid channel list\n", ++ __FUNCTION__)); ++ *len = 0; ++ } else { ++ mem_needed = sizeof(uint32) * nchan; ++ p = (uint32 *) kmalloc(mem_needed, GFP_KERNEL); ++ if (!p) { ++ DHD_ERROR(("%s: Unable to malloc %d bytes\n", ++ __FUNCTION__, mem_needed)); ++ break; ++ } ++ for (i = 0; i < nchan; i++) { ++ p[i] = wf_channel2mhz(ch_list[i], ++ (ch_list[i] <= CH_MAX_2G_CHANNEL? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); ++ } ++ ret = p; ++ *len = mem_needed; ++ } ++ } else { ++ *len = 0; ++ DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__)); ++ } ++ break; ++ case DHD_PNO_GET_NEW_EPNO_SSID_ELEM: ++ epno_cfg = &_params->params_gscan.epno_cfg; ++ if (epno_cfg->num_epno_ssid >= ++ MAX_EPNO_SSID_NUM) { ++ DHD_ERROR(("Excessive number of ePNO SSIDs programmed %d\n", ++ epno_cfg->num_epno_ssid)); ++ return NULL; ++ } ++ if (!epno_cfg->num_epno_ssid) { ++ INIT_LIST_HEAD(&epno_cfg->epno_ssid_list); ++ } ++ ssid_elem = kzalloc(sizeof(dhd_pno_ssid_t), GFP_KERNEL); ++ if (!ssid_elem) { ++ DHD_ERROR(("EPNO ssid: cannot alloc %zd bytes", ++ sizeof(dhd_pno_ssid_t))); ++ return NULL; ++ } ++ epno_cfg->num_epno_ssid++; ++ list_add_tail(&ssid_elem->list, &epno_cfg->epno_ssid_list); ++ ret = ssid_elem; ++ break; ++ ++ default: ++ DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); ++ break; ++ } ++ ++ return ret; ++ ++} ++#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ ++ ++static int ++_dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) ++{ ++ int err = BCME_OK; ++ int i, j; ++ uint32 timestamp = 0; ++ dhd_pno_params_t *_params = NULL; ++ dhd_pno_status_info_t *_pno_state = NULL; ++ wl_pfn_lscanresults_v2_t *plbestnet = NULL; ++ wl_pfn_lnet_info_v2_t *plnetinfo; ++ dhd_pno_bestnet_entry_t *pbestnet_entry; ++ dhd_pno_best_header_t *pbestnetheader = NULL; ++ dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext; ++ bool allocate_header = FALSE; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit_no_unlock; ++ } ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit_no_unlock; ++ } ++ ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); ++ goto exit_no_unlock; ++ } ++ mutex_lock(&_pno_state->pno_mutex); ++ _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; ++ if (buf && bufsize) { ++ if (!list_empty(&_params->params_batch.get_batch.expired_scan_results_list)) { ++ /* need to check whether we have cashed data or not */ ++ DHD_PNO(("%s: have cashed batching data in Driver\n", ++ __FUNCTION__)); ++ /* convert to results format */ ++ goto convert_format; ++ } else { ++ /* this is a first try to get batching results */ ++ if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { ++ /* move the scan_results_list to expired_scan_results_lists */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(siter, snext, ++ &_params->params_batch.get_batch.scan_results_list, list) { ++ list_move_tail(&siter->list, ++ &_params->params_batch.get_batch.expired_scan_results_list); ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ _params->params_batch.get_batch.top_node_cnt = 0; ++ _params->params_batch.get_batch.expired_tot_scan_cnt = ++ _params->params_batch.get_batch.tot_scan_cnt; ++ _params->params_batch.get_batch.tot_scan_cnt = 0; ++ goto convert_format; ++ } ++ } ++ } ++ /* create dhd_pno_scan_results_t whenever we got event WLC_E_PFN_BEST_BATCHING */ ++ pscan_results = (dhd_pno_scan_results_t *)MALLOC(dhd->osh, SCAN_RESULTS_SIZE); ++ if (pscan_results == NULL) { ++ err = BCME_NOMEM; ++ DHD_ERROR(("failed to allocate dhd_pno_scan_results_t\n")); ++ goto exit; ++ } ++ pscan_results->bestnetheader = NULL; ++ pscan_results->cnt_header = 0; ++ /* add the element into list unless total node cnt is less than MAX_NODE_ CNT */ ++ if (_params->params_batch.get_batch.top_node_cnt < MAX_NODE_CNT) { ++ list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); ++ _params->params_batch.get_batch.top_node_cnt++; ++ } else { ++ int _removed_scan_cnt; ++ /* remove oldest one and add new one */ ++ DHD_PNO(("%s : Remove oldest node and add new one\n", __FUNCTION__)); ++ _removed_scan_cnt = _dhd_pno_clear_all_batch_results(dhd, ++ &_params->params_batch.get_batch.scan_results_list, TRUE); ++ _params->params_batch.get_batch.tot_scan_cnt -= _removed_scan_cnt; ++ list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); ++ ++ } ++ plbestnet = (wl_pfn_lscanresults_v2_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); ++ if (!(plbestnet)) ++ { ++ DHD_ERROR(("(%s) : plbestnet (%p) is NULL\n", __FUNCTION__, (plbestnet))); ++ goto exit; ++ } ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ memset(plbestnet, 0, PNO_BESTNET_LEN); ++ while (plbestnet->status != PFN_COMPLETE) { ++ memset(plbestnet, 0, PNO_BESTNET_LEN); ++ err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet, PNO_BESTNET_LEN, 0); ++ if (err < 0) { ++ if (err == BCME_EPERM) { ++ DHD_ERROR(("we cannot get the batching data " ++ "during scanning in firmware, try again\n,")); ++ msleep(500); ++ continue; ++ } else { ++ DHD_ERROR(("%s : failed to execute pfnlbest (err :%d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++ DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, ++ plbestnet->status, plbestnet->count)); ++ if (plbestnet->version != PFN_SCANRESULT_VERSION) { ++ err = BCME_VERSION; ++ DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", ++ plbestnet->version, PFN_SCANRESULT_VERSION)); ++ goto exit; ++ } ++ plnetinfo = plbestnet->netinfo; ++ for (i = 0; i < plbestnet->count; i++) { ++ pbestnet_entry = (dhd_pno_bestnet_entry_t *) ++ MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); ++ if (pbestnet_entry == NULL) { ++ err = BCME_NOMEM; ++ DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); ++ goto exit; ++ } ++ memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE); ++ pbestnet_entry->recorded_time = jiffies; /* record the current time */ ++ /* create header for the first entry */ ++ allocate_header = (i == 0)? TRUE : FALSE; ++ /* check whether the new generation is started or not */ ++ if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp) ++ > TIME_MIN_DIFF)) ++ allocate_header = TRUE; ++ timestamp = plnetinfo->timestamp; ++ if (allocate_header) { ++ pbestnetheader = (dhd_pno_best_header_t *) ++ MALLOC(dhd->osh, BEST_HEADER_SIZE); ++ if (pbestnetheader == NULL) { ++ err = BCME_NOMEM; ++ if (pbestnet_entry) ++ MFREE(dhd->osh, pbestnet_entry, ++ BESTNET_ENTRY_SIZE); ++ DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); ++ goto exit; ++ } ++ /* increase total cnt of bestnet header */ ++ pscan_results->cnt_header++; ++ /* need to record the reason to call dhd_pno_get_for_bach */ ++ if (reason) ++ pbestnetheader->reason = (ENABLE << reason); ++ memset(pbestnetheader, 0, BEST_HEADER_SIZE); ++ /* initialize the head of linked list */ ++ INIT_LIST_HEAD(&(pbestnetheader->entry_list)); ++ /* link the pbestnet heaer into existed list */ ++ if (pscan_results->bestnetheader == NULL) ++ /* In case of header */ ++ pscan_results->bestnetheader = pbestnetheader; ++ else { ++ dhd_pno_best_header_t *head = pscan_results->bestnetheader; ++ pscan_results->bestnetheader = pbestnetheader; ++ pbestnetheader->next = head; ++ } ++ } ++ /* fills the best network info */ ++ pbestnet_entry->channel = plnetinfo->pfnsubnet.channel; ++ pbestnet_entry->RSSI = plnetinfo->RSSI; ++ if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { ++ /* if RSSI is positive value, we assume that ++ * this scan is aborted by other scan ++ */ ++ DHD_PNO(("This scan is aborted\n")); ++ pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); ++ } ++ pbestnet_entry->rtt0 = plnetinfo->rtt0; ++ pbestnet_entry->rtt1 = plnetinfo->rtt1; ++ pbestnet_entry->timestamp = plnetinfo->timestamp; ++ if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { ++ DHD_ERROR(("%s: Invalid SSID length %d: trimming it to max\n", ++ __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); ++ plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; ++ } ++ pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; ++ memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.u.SSID, ++ pbestnet_entry->SSID_len); ++ memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); ++ /* add the element into list */ ++ list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); ++ /* increase best entry count */ ++ pbestnetheader->tot_cnt++; ++ pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; ++ DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1)); ++ DHD_PNO(("\tSSID : ")); ++ for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++) ++ DHD_PNO(("%c", plnetinfo->pfnsubnet.u.SSID[j])); ++ DHD_PNO(("\n")); ++ DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ plnetinfo->pfnsubnet.BSSID.octet[0], ++ plnetinfo->pfnsubnet.BSSID.octet[1], ++ plnetinfo->pfnsubnet.BSSID.octet[2], ++ plnetinfo->pfnsubnet.BSSID.octet[3], ++ plnetinfo->pfnsubnet.BSSID.octet[4], ++ plnetinfo->pfnsubnet.BSSID.octet[5])); ++ DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", ++ plnetinfo->pfnsubnet.channel, ++ plnetinfo->RSSI, plnetinfo->timestamp)); ++ DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, plnetinfo->rtt1)); ++ plnetinfo++; ++ } ++ } ++ if (pscan_results->cnt_header == 0) { ++ /* In case that we didn't get any data from the firmware ++ * Remove the current scan_result list from get_bach.scan_results_list. ++ */ ++ DHD_PNO(("NO BATCH DATA from Firmware, Delete current SCAN RESULT LIST\n")); ++ list_del(&pscan_results->list); ++ MFREE(dhd->osh, pscan_results, SCAN_RESULTS_SIZE); ++ _params->params_batch.get_batch.top_node_cnt--; ++ } else { ++ /* increase total scan count using current scan count */ ++ _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; ++ } ++ ++ if (buf && bufsize) { ++ /* This is a first try to get batching results */ ++ if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { ++ /* move the scan_results_list to expired_scan_results_lists */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(siter, snext, ++ &_params->params_batch.get_batch.scan_results_list, list) { ++ list_move_tail(&siter->list, ++ &_params->params_batch.get_batch.expired_scan_results_list); ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ /* reset gloval values after moving to expired list */ ++ _params->params_batch.get_batch.top_node_cnt = 0; ++ _params->params_batch.get_batch.expired_tot_scan_cnt = ++ _params->params_batch.get_batch.tot_scan_cnt; ++ _params->params_batch.get_batch.tot_scan_cnt = 0; ++ } ++convert_format: ++ err = _dhd_pno_convert_format(dhd, &_params->params_batch, buf, bufsize); ++ if (err < 0) { ++ DHD_ERROR(("failed to convert the data into upper layer format\n")); ++ goto exit; ++ } ++ } ++exit: ++ if (plbestnet) ++ MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); ++ if (_params) { ++ _params->params_batch.get_batch.buf = NULL; ++ _params->params_batch.get_batch.bufsize = 0; ++ _params->params_batch.get_batch.bytes_written = err; ++ } ++ mutex_unlock(&_pno_state->pno_mutex); ++exit_no_unlock: ++ if (waitqueue_active((struct wait_queue_head *)&_pno_state->get_batch_done.wait)) ++ complete(&_pno_state->get_batch_done); ++ return err; ++} ++ ++static void ++_dhd_pno_get_batch_handler(struct work_struct *work) ++{ ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pub_t *dhd; ++ struct dhd_pno_batch_params *params_batch; ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ _pno_state = container_of(work, struct dhd_pno_status_info, work); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ dhd = _pno_state->dhd; ++ if (dhd == NULL) { ++ DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ ++#ifdef GSCAN_SUPPORT ++ _dhd_pno_get_gscan_batch_from_fw(dhd); ++#endif /* GSCAN_SUPPORT */ ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; ++ ++ _dhd_pno_get_for_batch(dhd, params_batch->get_batch.buf, ++ params_batch->get_batch.bufsize, params_batch->get_batch.reason); ++ } ++} ++ ++int ++dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) ++{ ++ int err = BCME_OK; ++ char *pbuf = buf; ++ dhd_pno_status_info_t *_pno_state; ++ struct dhd_pno_batch_params *params_batch; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; ++#ifdef GSCAN_SUPPORT ++ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { ++ struct dhd_pno_gscan_params *gscan_params; ++ gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; ++ gscan_params->reason = reason; ++ err = dhd_retreive_batch_scan_results(dhd); ++ if (err == BCME_OK) { ++ wait_event_interruptible_timeout(_pno_state->batch_get_wait, ++ is_batch_retrieval_complete(gscan_params), ++ msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); ++ } ++ } else ++#endif ++ { ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); ++ memset(pbuf, 0, bufsize); ++ pbuf += snprintf(pbuf, bufsize, "scancount=%d\n", 0); ++ snprintf(pbuf, bufsize, "%s", RESULTS_END_MARKER); ++ err = strlen(buf); ++ goto exit; ++ } ++ params_batch->get_batch.buf = buf; ++ params_batch->get_batch.bufsize = bufsize; ++ params_batch->get_batch.reason = reason; ++ params_batch->get_batch.bytes_written = 0; ++ schedule_work(&_pno_state->work); ++ wait_for_completion(&_pno_state->get_batch_done); ++ } ++ ++#ifdef GSCAN_SUPPORT ++ if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) ++#endif ++ err = params_batch->get_batch.bytes_written; ++exit: ++ return err; ++} ++ ++int ++dhd_pno_stop_for_batch(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ int mode = 0; ++ int i = 0; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ wl_pfn_bssid_t *p_pfn_bssid = NULL; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", ++ __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++#ifdef GSCAN_SUPPORT ++ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { ++ DHD_PNO(("Gscan is ongoing, nothing to stop here\n")); ++ return err; ++ } ++#endif ++ ++ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { ++ DHD_ERROR(("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__)); ++ goto exit; ++ } ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) { ++ mode = _pno_state->pno_mode; ++ err = dhd_pno_clean(dhd); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ ++ _pno_state->pno_mode = mode; ++ /* restart Legacy PNO if the Legacy PNO is on */ ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ struct dhd_pno_legacy_params *_params_legacy; ++ _params_legacy = ++ &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); ++ err = dhd_pno_set_legacy_pno(dhd, _params_legacy->scan_fr, ++ _params_legacy->pno_repeat, ++ _params_legacy->pno_freq_expo_max, ++ _params_legacy->chan_list, _params_legacy->nchan); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { ++ struct dhd_pno_bssid *iter, *next; ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); ++ p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * ++ _params->params_hotlist.nbssid, GFP_KERNEL); ++ if (p_pfn_bssid == NULL) { ++ DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" ++ " (count: %d)", ++ __FUNCTION__, _params->params_hotlist.nbssid)); ++ err = BCME_ERROR; ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ goto exit; ++ } ++ i = 0; ++ /* convert dhd_pno_bssid to wl_pfn_bssid */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(iter, next, ++ &_params->params_hotlist.bssid_list, list) { ++ memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN); ++ p_pfn_bssid[i].flags = iter->flags; ++ i++; ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ DHD_ERROR(("%s : failed to restart hotlist scan(err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++ } else { ++ err = dhd_pno_clean(dhd); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++exit: ++ _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; ++ _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); ++ kfree(p_pfn_bssid); ++ return err; ++} ++ ++int ++dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, ++ struct dhd_pno_hotlist_params *hotlist_params) ++{ ++ int err = BCME_OK; ++ int i; ++ uint16 _chan_list[WL_NUMCHANNELS]; ++ int rem_nchan = 0; ++ int tot_nchan = 0; ++ int mode = 0; ++ dhd_pno_params_t *_params; ++ dhd_pno_params_t *_params2; ++ struct dhd_pno_bssid *_pno_bssid; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ NULL_CHECK(hotlist_params, "hotlist_params is NULL", err); ++ NULL_CHECK(p_pfn_bssid, "p_pfn_bssid is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ ++ if (!dhd_support_sta_mode(dhd)) { ++ err = BCME_BADOPTION; ++ goto exit; ++ } ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ _params = &_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]; ++ if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { ++ _pno_state->pno_mode |= DHD_PNO_HOTLIST_MODE; ++ err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_HOTLIST_MODE); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call _dhd_pno_reinitialize_prof\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ } ++ _params->params_batch.nchan = hotlist_params->nchan; ++ _params->params_batch.scan_fr = hotlist_params->scan_fr; ++ if (hotlist_params->nchan) ++ memcpy(_params->params_hotlist.chan_list, hotlist_params->chan_list, ++ sizeof(_params->params_hotlist.chan_list)); ++ memset(_chan_list, 0, sizeof(_chan_list)); ++ ++ rem_nchan = ARRAYSIZE(hotlist_params->chan_list) - hotlist_params->nchan; ++ if (hotlist_params->band == WLC_BAND_2G || hotlist_params->band == WLC_BAND_5G) { ++ /* get a valid channel list based on band B or A */ ++ err = _dhd_pno_get_channels(dhd, ++ &_params->params_hotlist.chan_list[hotlist_params->nchan], ++ &rem_nchan, hotlist_params->band, FALSE); ++ if (err < 0) { ++ DHD_ERROR(("%s: failed to get valid channel list(band : %d)\n", ++ __FUNCTION__, hotlist_params->band)); ++ goto exit; ++ } ++ /* now we need to update nchan because rem_chan has valid channel count */ ++ _params->params_hotlist.nchan += rem_nchan; ++ /* need to sort channel list */ ++ sort(_params->params_hotlist.chan_list, _params->params_hotlist.nchan, ++ sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL); ++ } ++#ifdef PNO_DEBUG ++{ ++ int i; ++ DHD_PNO(("Channel list : ")); ++ for (i = 0; i < _params->params_batch.nchan; i++) { ++ DHD_PNO(("%d ", _params->params_batch.chan_list[i])); ++ } ++ DHD_PNO(("\n")); ++} ++#endif ++ if (_params->params_hotlist.nchan) { ++ /* copy the channel list into local array */ ++ memcpy(_chan_list, _params->params_hotlist.chan_list, ++ sizeof(_chan_list)); ++ tot_nchan = _params->params_hotlist.nchan; ++ } ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ DHD_PNO(("PNO SSID is on progress in firmware\n")); ++ /* store current pno_mode before disabling pno */ ++ mode = _pno_state->pno_mode; ++ err = _dhd_pno_enable(dhd, PNO_OFF); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); ++ goto exit; ++ } ++ /* restore the previous mode */ ++ _pno_state->pno_mode = mode; ++ /* Use the superset for channelist between two mode */ ++ _params2 = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); ++ if (_params2->params_legacy.nchan > 0 && ++ _params->params_hotlist.nchan > 0) { ++ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan, ++ &_params2->params_legacy.chan_list[0], ++ _params2->params_legacy.nchan, ++ &_params->params_hotlist.chan_list[0], ++ _params->params_hotlist.nchan); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to merge channel list" ++ "between legacy and hotlist\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ } ++ ++ } ++ ++ INIT_LIST_HEAD(&(_params->params_hotlist.bssid_list)); ++ ++ err = _dhd_pno_add_bssid(dhd, p_pfn_bssid, hotlist_params->nbssid); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ if ((err = _dhd_pno_set(dhd, _params, DHD_PNO_HOTLIST_MODE)) < 0) { ++ DHD_ERROR(("%s : failed to set call pno_set (err %d) in firmware\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ if (tot_nchan > 0) { ++ if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { ++ DHD_ERROR(("%s : failed to set call pno_cfg (err %d) in firmware\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++ for (i = 0; i < hotlist_params->nbssid; i++) { ++ _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); ++ NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err); ++ memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN); ++ _pno_bssid->flags = p_pfn_bssid[i].flags; ++ list_add_tail(&_pno_bssid->list, &_params->params_hotlist.bssid_list); ++ } ++ _params->params_hotlist.nbssid = hotlist_params->nbssid; ++ if (_pno_state->pno_status == DHD_PNO_DISABLED) { ++ if ((err = _dhd_pno_enable(dhd, PNO_ON)) < 0) ++ DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); ++ } ++exit: ++ /* clear mode in case of error */ ++ if (err < 0) ++ _pno_state->pno_mode &= ~DHD_PNO_HOTLIST_MODE; ++ return err; ++} ++ ++int ++dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ uint32 mode = 0; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", ++ __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ if (!(_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE)) { ++ DHD_ERROR(("%s : Hotlist MODE is not enabled\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ ++ if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_BATCH_MODE)) { ++ /* retrieve the batching data from firmware into host */ ++ dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); ++ /* save current pno_mode before calling dhd_pno_clean */ ++ mode = _pno_state->pno_mode; ++ err = dhd_pno_clean(dhd); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ /* restore previos pno mode */ ++ _pno_state->pno_mode = mode; ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ /* restart Legacy PNO Scan */ ++ struct dhd_pno_legacy_params *_params_legacy; ++ _params_legacy = ++ &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); ++ ++ err = dhd_pno_set_legacy_pno(dhd, _params_legacy->scan_fr, ++ _params_legacy->pno_repeat, _params_legacy->pno_freq_expo_max, ++ _params_legacy->chan_list, _params_legacy->nchan); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } else if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ /* restart Batching Scan */ ++ _params = &(_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]); ++ /* restart BATCH SCAN */ ++ err = dhd_pno_set_for_batch(dhd, &_params->params_batch); ++ if (err < 0) { ++ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; ++ DHD_ERROR(("%s : failed to restart batch scan(err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++ } else { ++ err = dhd_pno_clean(dhd); ++ if (err < 0) { ++ DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", ++ __FUNCTION__, err)); ++ goto exit; ++ } ++ } ++exit: ++ return err; ++} ++ ++#ifdef GSCAN_SUPPORT ++int ++dhd_retreive_batch_scan_results(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ struct dhd_pno_batch_params *params_batch; ++ ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ ++ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; ++ if (_params->params_gscan.get_batch_flag == GSCAN_BATCH_RETRIEVAL_COMPLETE) { ++ DHD_PNO(("Retreive batch results\n")); ++ params_batch->get_batch.buf = NULL; ++ params_batch->get_batch.bufsize = 0; ++ params_batch->get_batch.reason = PNO_STATUS_EVENT; ++ _params->params_gscan.get_batch_flag = GSCAN_BATCH_RETRIEVAL_IN_PROGRESS; ++ smp_wmb(); ++ schedule_work(&_pno_state->work); ++ } else { ++ DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING retrieval" ++ "already in progress, will skip\n", __FUNCTION__)); ++ err = BCME_ERROR; ++ } ++ ++ return err; ++} ++ ++void ++dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) ++{ ++ dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); ++ struct dhd_pno_gscan_params *gscan_params; ++ gscan_results_cache_t *iter, *tmp; ++ ++ if (!_pno_state) { ++ return; ++ } ++ gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); ++ ++ if (type == HOTLIST_FOUND) { ++ iter = gscan_params->gscan_hotlist_found; ++ gscan_params->gscan_hotlist_found = NULL; ++ } else { ++ iter = gscan_params->gscan_hotlist_lost; ++ gscan_params->gscan_hotlist_lost = NULL; ++ } ++ ++ while (iter) { ++ tmp = iter->next; ++ kfree(iter); ++ iter = tmp; ++ } ++ ++ return; ++} ++ ++void * ++dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size) ++{ ++ wl_bss_info_t *bi = NULL; ++ wl_gscan_result_t *gscan_result; ++ wifi_gscan_full_result_t *result = NULL; ++ u32 bi_length = 0; ++ uint8 channel; ++ uint32 mem_needed; ++ struct osl_timespec ts; ++ u32 bi_ie_length = 0; ++ u32 bi_ie_offset = 0; ++ ++ *size = 0; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ gscan_result = (wl_gscan_result_t *)data; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ if (!gscan_result) { ++ DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); ++ goto exit; ++ } ++ ++ if ((len < sizeof(*gscan_result)) || ++ (len < dtoh32(gscan_result->buflen)) || ++ (dtoh32(gscan_result->buflen) > ++ (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { ++ DHD_ERROR(("%s: invalid gscan buflen:%u\n", __FUNCTION__, ++ dtoh32(gscan_result->buflen))); ++ goto exit; ++ } ++ ++ bi = &gscan_result->bss_info[0].info; ++ bi_length = dtoh32(bi->length); ++ if (bi_length != (dtoh32(gscan_result->buflen) - ++ WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) { ++ DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); ++ goto exit; ++ } ++ bi_ie_offset = dtoh32(bi->ie_offset); ++ bi_ie_length = dtoh32(bi->ie_length); ++ if ((bi_ie_offset + bi_ie_length) > bi_length) { ++ DHD_ERROR(("%s: Invalid ie_length:%u or ie_offset:%u\n", ++ __FUNCTION__, bi_ie_length, bi_ie_offset)); ++ goto exit; ++ } ++ if (bi->SSID_len > DOT11_MAX_SSID_LEN) { ++ DHD_ERROR(("%s: Invalid SSID length:%u\n", __FUNCTION__, bi->SSID_len)); ++ goto exit; ++ } ++ mem_needed = OFFSETOF(wifi_gscan_full_result_t, ie_data) + bi_ie_length; ++ result = (wifi_gscan_full_result_t *) kmalloc(mem_needed, GFP_KERNEL); ++ if (!result) { ++ DHD_ERROR(("%s Cannot malloc scan result buffer %d bytes\n", ++ __FUNCTION__, mem_needed)); ++ goto exit; ++ } ++ result->scan_ch_bucket = gscan_result->scan_ch_bucket; ++ memcpy(result->fixed.ssid, bi->SSID, bi->SSID_len); ++ result->fixed.ssid[bi->SSID_len] = '\0'; ++ channel = wf_chspec_ctlchan(bi->chanspec); ++ result->fixed.channel = wf_channel2mhz(channel, ++ (channel <= CH_MAX_2G_CHANNEL? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); ++ result->fixed.rssi = (int32) bi->RSSI; ++ result->fixed.rtt = 0; ++ result->fixed.rtt_sd = 0; ++ osl_get_monotonic_boottime(&ts); ++ result->fixed.ts = (uint64) TIMESPEC_TO_US(ts); ++ result->fixed.beacon_period = dtoh16(bi->beacon_period); ++ result->fixed.capability = dtoh16(bi->capability); ++ result->ie_length = bi_ie_length; ++ memcpy(&result->fixed.macaddr, &bi->BSSID, ETHER_ADDR_LEN); ++ memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi_ie_length); ++ *size = mem_needed; ++exit: ++ return result; ++} ++ ++void * ++dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size) ++{ ++ dhd_epno_results_t *results = NULL; ++ dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); ++ struct dhd_pno_gscan_params *gscan_params; ++ uint32 count, mem_needed = 0, i; ++ uint8 ssid[DOT11_MAX_SSID_LEN + 1]; ++ struct ether_addr *bssid; ++ ++ *size = 0; ++ if (!_pno_state) ++ return NULL; ++ gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); ++ ++ if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) { ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ wl_pfn_scanresults_v2_t *pfn_result = (wl_pfn_scanresults_v2_t *)data; ++ wl_pfn_net_info_v2_t *net; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ if (pfn_result->version != PFN_SCANRESULT_VERSION) { ++ DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, ++ pfn_result->version, PFN_SCANRESULT_VERSION)); ++ return NULL; ++ } ++ /* Check if count of pfn results is corrupted */ ++ if (pfn_result->count > EVENT_MAX_NETCNT_V2) { ++ DHD_ERROR(("%s event %d: pfn results count %d" ++ "exceeds the max limit\n", __FUNCTION__, event, ++ pfn_result->count)); ++ return NULL; ++ } ++ ++ count = pfn_result->count; ++ mem_needed = sizeof(dhd_epno_results_t) * count; ++ results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); ++ if (!results) { ++ DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, ++ mem_needed)); ++ return NULL; ++ } ++ for (i = 0; i < count; i++) { ++ net = &pfn_result->netinfo[i]; ++ results[i].rssi = net->RSSI; ++ results[i].channel = wf_channel2mhz(net->pfnsubnet.channel, ++ (net->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); ++ results[i].flags = (event == WLC_E_PFN_NET_FOUND) ? ++ WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST; ++ results[i].ssid_len = min(net->pfnsubnet.SSID_len, ++ (uint8)DOT11_MAX_SSID_LEN); ++ bssid = &results[i].bssid; ++ memcpy(bssid, &net->pfnsubnet.BSSID, ETHER_ADDR_LEN); ++ if (!net->pfnsubnet.SSID_len) { ++ dhd_pno_idx_to_ssid(gscan_params, &results[i], ++ net->pfnsubnet.u.index); ++ } else { ++ memcpy(results[i].ssid, net->pfnsubnet.u.SSID, results[i].ssid_len); ++ } ++ memcpy(ssid, results[i].ssid, results[i].ssid_len); ++ ssid[results[i].ssid_len] = '\0'; ++ DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " ++ "ch %d rssi %d flags %d\n", ssid, ++ bssid->octet[0], bssid->octet[1], ++ bssid->octet[2], bssid->octet[3], ++ bssid->octet[4], bssid->octet[5], ++ results[i].channel, results[i].rssi, results[i].flags)); ++ } ++ } ++ *size = mem_needed; ++ return results; ++} ++ ++void * ++dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, ++ int *send_evt_bytes, hotlist_type_t type) ++{ ++ void *ptr = NULL; ++ dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); ++ struct dhd_pno_gscan_params *gscan_params; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ wl_pfn_scanresults_v2_t *results = (wl_pfn_scanresults_v2_t *)event_data; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ wifi_gscan_result_t *hotlist_found_array; ++ wl_pfn_net_info_v2_t *plnetinfo; ++ gscan_results_cache_t *gscan_hotlist_cache; ++ int malloc_size = 0, i, total = 0; ++ struct osl_timespec tm_spec; ++ ++ gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); ++ ++ if ((results->count == 0) || (results->count > EVENT_MAX_NETCNT_V2)) { ++ DHD_ERROR(("%s: wrong result count:%d\n", __FUNCTION__, results->count)); ++ *send_evt_bytes = 0; ++ return ptr; ++ } ++ ++ osl_get_monotonic_boottime(&tm_spec); ++ malloc_size = sizeof(gscan_results_cache_t) + ++ ((results->count - 1) * sizeof(wifi_gscan_result_t)); ++ gscan_hotlist_cache = (gscan_results_cache_t *) kmalloc(malloc_size, GFP_KERNEL); ++ ++ if (!gscan_hotlist_cache) { ++ DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size)); ++ *send_evt_bytes = 0; ++ return ptr; ++ } ++ ++ if (type == HOTLIST_FOUND) { ++ gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found; ++ gscan_params->gscan_hotlist_found = gscan_hotlist_cache; ++ DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, results->count)); ++ } else { ++ gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost; ++ gscan_params->gscan_hotlist_lost = gscan_hotlist_cache; ++ DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, results->count)); ++ } ++ ++ gscan_hotlist_cache->tot_count = results->count; ++ gscan_hotlist_cache->tot_consumed = 0; ++ gscan_hotlist_cache->scan_ch_bucket = results->scan_ch_bucket; ++ plnetinfo = results->netinfo; ++ ++ for (i = 0; i < results->count; i++, plnetinfo++) { ++ hotlist_found_array = &gscan_hotlist_cache->results[i]; ++ memset(hotlist_found_array, 0, sizeof(wifi_gscan_result_t)); ++ hotlist_found_array->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, ++ (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? ++ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); ++ hotlist_found_array->rssi = (int32) plnetinfo->RSSI; ++ ++ hotlist_found_array->ts = ++ convert_fw_rel_time_to_systime(&tm_spec, (plnetinfo->timestamp * 1000)); ++ if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { ++ DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", ++ plnetinfo->pfnsubnet.SSID_len)); ++ plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; ++ } ++ memcpy(hotlist_found_array->ssid, plnetinfo->pfnsubnet.u.SSID, ++ plnetinfo->pfnsubnet.SSID_len); ++ hotlist_found_array->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; ++ ++ memcpy(&hotlist_found_array->macaddr, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); ++ DHD_PNO(("\t%s %02x:%02x:%02x:%02x:%02x:%02x rssi %d\n", hotlist_found_array->ssid, ++ hotlist_found_array->macaddr.octet[0], ++ hotlist_found_array->macaddr.octet[1], ++ hotlist_found_array->macaddr.octet[2], ++ hotlist_found_array->macaddr.octet[3], ++ hotlist_found_array->macaddr.octet[4], ++ hotlist_found_array->macaddr.octet[5], ++ hotlist_found_array->rssi)); ++ } ++ ++ ++ if (results->status == PFN_COMPLETE) { ++ ptr = (void *) gscan_hotlist_cache; ++ while (gscan_hotlist_cache) { ++ total += gscan_hotlist_cache->tot_count; ++ gscan_hotlist_cache = gscan_hotlist_cache->next; ++ } ++ *send_evt_bytes = total * sizeof(wifi_gscan_result_t); ++ } ++ ++ return ptr; ++} ++#endif /* GSCAN_SUPPORT */ ++int ++dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) ++{ ++ int err = BCME_OK; ++ uint event_type; ++ dhd_pno_status_info_t *_pno_state; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ if (!WLS_SUPPORTED(_pno_state)) { ++ DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); ++ err = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ event_type = ntoh32(event->event_type); ++ DHD_PNO(("%s enter : event_type :%d\n", __FUNCTION__, event_type)); ++ switch (event_type) { ++ case WLC_E_PFN_BSSID_NET_FOUND: ++ case WLC_E_PFN_BSSID_NET_LOST: ++ /* TODO : need to implement event logic using generic netlink */ ++ break; ++ case WLC_E_PFN_BEST_BATCHING: ++#ifndef GSCAN_SUPPORT ++ { ++ struct dhd_pno_batch_params *params_batch; ++ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; ++ if (!waitqueue_active((struct wait_queue_head *)&_pno_state->get_batch_done.wait)) { ++ DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__)); ++ params_batch->get_batch.buf = NULL; ++ params_batch->get_batch.bufsize = 0; ++ params_batch->get_batch.reason = PNO_STATUS_EVENT; ++ schedule_work(&_pno_state->work); ++ } else ++ DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING" ++ "will skip this event\n", __FUNCTION__)); ++ break; ++ } ++#else ++ break; ++#endif /* !GSCAN_SUPPORT */ ++ default: ++ DHD_ERROR(("unknown event : %d\n", event_type)); ++ } ++exit: ++ return err; ++} ++ ++int dhd_pno_init(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ char *buf = NULL; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ UNUSED_PARAMETER(_dhd_pno_suspend); ++ if (dhd->pno_state) ++ goto exit; ++ dhd->pno_state = MALLOC(dhd->osh, sizeof(dhd_pno_status_info_t)); ++ NULL_CHECK(dhd->pno_state, "failed to create dhd_pno_state", err); ++ memset(dhd->pno_state, 0, sizeof(dhd_pno_status_info_t)); ++ /* need to check whether current firmware support batching and hotlist scan */ ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ _pno_state->wls_supported = TRUE; ++ _pno_state->dhd = dhd; ++ mutex_init(&_pno_state->pno_mutex); ++ INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler); ++ init_completion(&_pno_state->get_batch_done); ++#ifdef GSCAN_SUPPORT ++ init_waitqueue_head(&_pno_state->batch_get_wait); ++#endif /* GSCAN_SUPPORT */ ++ buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); ++ if (!buf) { ++ DHD_ERROR((":%s buf alloc err.\n", __FUNCTION__)); ++ return BCME_NOMEM; ++ } ++ err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, buf, WLC_IOCTL_SMLEN, ++ FALSE); ++ if (err == BCME_UNSUPPORTED) { ++ _pno_state->wls_supported = FALSE; ++ DHD_INFO(("Current firmware doesn't support" ++ " Android Location Service\n")); ++ } else { ++ DHD_ERROR(("%s: Support Android Location Service\n", ++ __FUNCTION__)); ++ } ++exit: ++ kfree(buf); ++ return err; ++} ++ ++int dhd_pno_deinit(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ dhd_pno_status_info_t *_pno_state; ++ dhd_pno_params_t *_params; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ ++ DHD_PNO(("%s enter\n", __FUNCTION__)); ++ _pno_state = PNO_GET_PNOSTATE(dhd); ++ NULL_CHECK(_pno_state, "pno_state is NULL", err); ++ /* may need to free legacy ssid_list */ ++ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { ++ _params = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; ++ _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); ++ } ++ ++#ifdef GSCAN_SUPPORT ++ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { ++ _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; ++ mutex_lock(&_pno_state->pno_mutex); ++ dhd_pno_reset_cfg_gscan(_params, _pno_state, GSCAN_FLUSH_ALL_CFG); ++ mutex_unlock(&_pno_state->pno_mutex); ++ } ++#endif /* GSCAN_SUPPORT */ ++ ++ if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { ++ _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; ++ /* clear resource if the BATCH MODE is on */ ++ _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); ++ } ++ cancel_work_sync(&_pno_state->work); ++ MFREE(dhd->osh, _pno_state, sizeof(dhd_pno_status_info_t)); ++ dhd->pno_state = NULL; ++ return err; ++} ++#endif /* PNO_SUPPORT */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_pno.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_pno.h +new file mode 100644 +index 000000000..7b56c5512 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_pno.h +@@ -0,0 +1,572 @@ ++/* ++ * Header file of Broadcom Dongle Host Driver (DHD) ++ * Prefered Network Offload code and Wi-Fi Location Service(WLS) code. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_pno.h 707287 2017-06-27 06:44:29Z $ ++ */ ++ ++#ifndef __DHD_PNO_H__ ++#define __DHD_PNO_H__ ++ ++#if defined(PNO_SUPPORT) ++#define PNO_TLV_PREFIX 'S' ++#define PNO_TLV_VERSION '1' ++#define PNO_TLV_SUBTYPE_LEGACY_PNO '2' ++#define PNO_TLV_RESERVED '0' ++ ++#define PNO_BATCHING_SET "SET" ++#define PNO_BATCHING_GET "GET" ++#define PNO_BATCHING_STOP "STOP" ++ ++#define PNO_PARAMS_DELIMETER " " ++#define PNO_PARAM_CHANNEL_DELIMETER "," ++#define PNO_PARAM_VALUE_DELLIMETER '=' ++#define PNO_PARAM_SCANFREQ "SCANFREQ" ++#define PNO_PARAM_BESTN "BESTN" ++#define PNO_PARAM_MSCAN "MSCAN" ++#define PNO_PARAM_CHANNEL "CHANNEL" ++#define PNO_PARAM_RTT "RTT" ++ ++#define PNO_TLV_TYPE_SSID_IE 'S' ++#define PNO_TLV_TYPE_TIME 'T' ++#define PNO_TLV_FREQ_REPEAT 'R' ++#define PNO_TLV_FREQ_EXPO_MAX 'M' ++ ++#define MAXNUM_SSID_PER_ADD 16 ++#define MAXNUM_PNO_PARAMS 2 ++#define PNO_TLV_COMMON_LENGTH 1 ++#define DEFAULT_BATCH_MSCAN 16 ++ ++#define RESULTS_END_MARKER "----\n" ++#define SCAN_END_MARKER "####\n" ++#define AP_END_MARKER "====\n" ++#define PNO_RSSI_MARGIN_DBM 30 ++ ++#define CSCAN_COMMAND "CSCAN " ++#define CSCAN_TLV_PREFIX 'S' ++#define CSCAN_TLV_VERSION 1 ++#define CSCAN_TLV_SUBVERSION 0 ++#define CSCAN_TLV_TYPE_SSID_IE 'S' ++#define CSCAN_TLV_TYPE_CHANNEL_IE 'C' ++#define CSCAN_TLV_TYPE_NPROBE_IE 'N' ++#define CSCAN_TLV_TYPE_ACTIVE_IE 'A' ++#define CSCAN_TLV_TYPE_PASSIVE_IE 'P' ++#define CSCAN_TLV_TYPE_HOME_IE 'H' ++#define CSCAN_TLV_TYPE_STYPE_IE 'T' ++ ++#define WL_SCAN_PARAMS_SSID_MAX 10 ++#define GET_SSID "SSID=" ++#define GET_CHANNEL "CH=" ++#define GET_NPROBE "NPROBE=" ++#define GET_ACTIVE_ASSOC_DWELL "ACTIVE=" ++#define GET_PASSIVE_ASSOC_DWELL "PASSIVE=" ++#define GET_HOME_DWELL "HOME=" ++#define GET_SCAN_TYPE "TYPE=" ++ ++#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) ++#define GSCAN_MAX_CH_BUCKETS 8 ++#define GSCAN_MAX_CHANNELS_IN_BUCKET 32 ++#define GSCAN_MAX_AP_CACHE_PER_SCAN 32 ++#define GSCAN_MAX_AP_CACHE 320 ++#define GSCAN_BG_BAND_MASK (1 << 0) ++#define GSCAN_A_BAND_MASK (1 << 1) ++#define GSCAN_DFS_MASK (1 << 2) ++#define GSCAN_ABG_BAND_MASK (GSCAN_A_BAND_MASK | GSCAN_BG_BAND_MASK) ++#define GSCAN_BAND_MASK (GSCAN_ABG_BAND_MASK | GSCAN_DFS_MASK) ++ ++#define GSCAN_FLUSH_HOTLIST_CFG (1 << 0) ++#define GSCAN_FLUSH_SIGNIFICANT_CFG (1 << 1) ++#define GSCAN_FLUSH_SCAN_CFG (1 << 2) ++#define GSCAN_FLUSH_EPNO_CFG (1 << 3) ++#define GSCAN_FLUSH_ALL_CFG (GSCAN_FLUSH_SCAN_CFG | \ ++ GSCAN_FLUSH_SIGNIFICANT_CFG | \ ++ GSCAN_FLUSH_HOTLIST_CFG | \ ++ GSCAN_FLUSH_EPNO_CFG) ++#define DHD_EPNO_HIDDEN_SSID (1 << 0) ++#define DHD_EPNO_A_BAND_TRIG (1 << 1) ++#define DHD_EPNO_BG_BAND_TRIG (1 << 2) ++#define DHD_EPNO_STRICT_MATCH (1 << 3) ++#define DHD_EPNO_SAME_NETWORK (1 << 4) ++#define DHD_PNO_USE_SSID (DHD_EPNO_HIDDEN_SSID | DHD_EPNO_STRICT_MATCH) ++ ++/* Do not change GSCAN_BATCH_RETRIEVAL_COMPLETE */ ++#define GSCAN_BATCH_RETRIEVAL_COMPLETE 0 ++#define GSCAN_BATCH_RETRIEVAL_IN_PROGRESS 1 ++#define GSCAN_BATCH_NO_THR_SET 101 ++#define GSCAN_LOST_AP_WINDOW_DEFAULT 4 ++#define GSCAN_MIN_BSSID_TIMEOUT 90 ++#define GSCAN_BATCH_GET_MAX_WAIT 500 ++#define CHANNEL_BUCKET_EMPTY_INDEX 0xFFFF ++#define GSCAN_RETRY_THRESHOLD 3 ++ ++#define MAX_EPNO_SSID_NUM 64 ++#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ ++ ++enum scan_status { ++ /* SCAN ABORT by other scan */ ++ PNO_STATUS_ABORT, ++ /* RTT is presence or not */ ++ PNO_STATUS_RTT_PRESENCE, ++ /* Disable PNO by Driver */ ++ PNO_STATUS_DISABLE, ++ /* NORMAL BATCHING GET */ ++ PNO_STATUS_NORMAL, ++ /* WLC_E_PFN_BEST_BATCHING */ ++ PNO_STATUS_EVENT, ++ PNO_STATUS_MAX ++}; ++#define PNO_STATUS_ABORT_MASK 0x0001 ++#define PNO_STATUS_RTT_MASK 0x0002 ++#define PNO_STATUS_DISABLE_MASK 0x0004 ++#define PNO_STATUS_OOM_MASK 0x0010 ++ ++enum index_mode { ++ INDEX_OF_LEGACY_PARAMS, ++ INDEX_OF_BATCH_PARAMS, ++ INDEX_OF_HOTLIST_PARAMS, ++ /* GSCAN includes hotlist scan and they do not run ++ * independent of each other ++ */ ++ INDEX_OF_GSCAN_PARAMS = INDEX_OF_HOTLIST_PARAMS, ++ INDEX_MODE_MAX ++}; ++enum dhd_pno_status { ++ DHD_PNO_DISABLED, ++ DHD_PNO_ENABLED, ++ DHD_PNO_SUSPEND ++}; ++typedef struct cmd_tlv { ++ char prefix; ++ char version; ++ char subtype; ++ char reserved; ++} cmd_tlv_t; ++#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) ++typedef enum { ++ WIFI_BAND_UNSPECIFIED, ++ WIFI_BAND_BG = 1, /* 2.4 GHz */ ++ WIFI_BAND_A = 2, /* 5 GHz without DFS */ ++ WIFI_BAND_A_DFS = 4, /* 5 GHz DFS only */ ++ WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ ++ WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ ++ WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ ++} gscan_wifi_band_t; ++ ++typedef enum { ++ HOTLIST_LOST, ++ HOTLIST_FOUND ++} hotlist_type_t; ++ ++typedef enum dhd_pno_gscan_cmd_cfg { ++ DHD_PNO_BATCH_SCAN_CFG_ID = 0, ++ DHD_PNO_GEOFENCE_SCAN_CFG_ID, ++ DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, ++ DHD_PNO_SCAN_CFG_ID, ++ DHD_PNO_GET_CAPABILITIES, ++ DHD_PNO_GET_BATCH_RESULTS, ++ DHD_PNO_GET_CHANNEL_LIST, ++ DHD_PNO_GET_NEW_EPNO_SSID_ELEM, ++ DHD_PNO_EPNO_CFG_ID, ++ DHD_PNO_GET_AUTOJOIN_CAPABILITIES, ++ DHD_PNO_EPNO_PARAMS_ID ++} dhd_pno_gscan_cmd_cfg_t; ++ ++typedef enum dhd_pno_mode { ++ /* Wi-Fi Legacy PNO Mode */ ++ DHD_PNO_NONE_MODE = 0, ++ DHD_PNO_LEGACY_MODE = (1 << (0)), ++ /* Wi-Fi Android BATCH SCAN Mode */ ++ DHD_PNO_BATCH_MODE = (1 << (1)), ++ /* Wi-Fi Android Hotlist SCAN Mode */ ++ DHD_PNO_HOTLIST_MODE = (1 << (2)), ++ /* Wi-Fi Google Android SCAN Mode */ ++ DHD_PNO_GSCAN_MODE = (1 << (3)) ++} dhd_pno_mode_t; ++#else ++typedef enum dhd_pno_mode { ++ /* Wi-Fi Legacy PNO Mode */ ++ DHD_PNO_NONE_MODE = 0, ++ DHD_PNO_LEGACY_MODE = (1 << (0)), ++ /* Wi-Fi Android BATCH SCAN Mode */ ++ DHD_PNO_BATCH_MODE = (1 << (1)), ++ /* Wi-Fi Android Hotlist SCAN Mode */ ++ DHD_PNO_HOTLIST_MODE = (1 << (2)) ++} dhd_pno_mode_t; ++#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ ++ ++typedef struct dhd_pno_ssid { ++ bool hidden; ++ int8 rssi_thresh; ++ uint8 dummy; ++ uint16 SSID_len; ++ uint32 flags; ++ int32 wpa_auth; ++ uchar SSID[DOT11_MAX_SSID_LEN]; ++ struct list_head list; ++} dhd_pno_ssid_t; ++ ++struct dhd_pno_bssid { ++ struct ether_addr macaddr; ++ /* Bit4: suppress_lost, Bit3: suppress_found */ ++ uint16 flags; ++ struct list_head list; ++}; ++ ++typedef struct dhd_pno_bestnet_entry { ++ struct ether_addr BSSID; ++ uint8 SSID_len; ++ uint8 SSID[DOT11_MAX_SSID_LEN]; ++ int8 RSSI; ++ uint8 channel; ++ uint32 timestamp; ++ uint16 rtt0; /* distance_cm based on RTT */ ++ uint16 rtt1; /* distance_cm based on sample standard deviation */ ++ unsigned long recorded_time; ++ struct list_head list; ++} dhd_pno_bestnet_entry_t; ++#define BESTNET_ENTRY_SIZE (sizeof(dhd_pno_bestnet_entry_t)) ++ ++typedef struct dhd_pno_bestnet_header { ++ struct dhd_pno_bestnet_header *next; ++ uint8 reason; ++ uint32 tot_cnt; ++ uint32 tot_size; ++ struct list_head entry_list; ++} dhd_pno_best_header_t; ++#define BEST_HEADER_SIZE (sizeof(dhd_pno_best_header_t)) ++ ++typedef struct dhd_pno_scan_results { ++ dhd_pno_best_header_t *bestnetheader; ++ uint8 cnt_header; ++ struct list_head list; ++} dhd_pno_scan_results_t; ++#define SCAN_RESULTS_SIZE (sizeof(dhd_pno_scan_results_t)) ++ ++struct dhd_pno_get_batch_info { ++ /* info related to get batch */ ++ char *buf; ++ bool batch_started; ++ uint32 tot_scan_cnt; ++ uint32 expired_tot_scan_cnt; ++ uint32 top_node_cnt; ++ uint32 bufsize; ++ uint32 bytes_written; ++ int reason; ++ struct list_head scan_results_list; ++ struct list_head expired_scan_results_list; ++}; ++struct dhd_pno_legacy_params { ++ uint16 scan_fr; ++ uint16 chan_list[WL_NUMCHANNELS]; ++ uint16 nchan; ++ int pno_repeat; ++ int pno_freq_expo_max; ++ int nssid; ++ struct list_head ssid_list; ++}; ++struct dhd_pno_batch_params { ++ int32 scan_fr; ++ uint8 bestn; ++ uint8 mscan; ++ uint8 band; ++ uint16 chan_list[WL_NUMCHANNELS]; ++ uint16 nchan; ++ uint16 rtt; ++ struct dhd_pno_get_batch_info get_batch; ++}; ++struct dhd_pno_hotlist_params { ++ uint8 band; ++ int32 scan_fr; ++ uint16 chan_list[WL_NUMCHANNELS]; ++ uint16 nchan; ++ uint16 nbssid; ++ struct list_head bssid_list; ++}; ++#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) ++#define DHD_PNO_REPORT_NO_BATCH (1 << 2) ++ ++typedef struct dhd_pno_gscan_channel_bucket { ++ uint16 bucket_freq_multiple; ++ /* band = 1 All bg band channels, ++ * band = 2 All a band channels, ++ * band = 0 chan_list channels ++ */ ++ uint16 band; ++ uint8 report_flag; ++ uint8 num_channels; ++ uint16 repeat; ++ uint16 bucket_max_multiple; ++ uint16 chan_list[GSCAN_MAX_CHANNELS_IN_BUCKET]; ++} dhd_pno_gscan_channel_bucket_t; ++ ++ ++#define DHD_PNO_AUTH_CODE_OPEN 1 /* Open */ ++#define DHD_PNO_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */ ++#define DHD_PNO_AUTH_CODE_EAPOL 4 /* any EAPOL */ ++ ++#define DHD_EPNO_DEFAULT_INDEX 0xFFFFFFFF ++ ++typedef struct dhd_epno_params { ++ uint8 ssid[DOT11_MAX_SSID_LEN]; ++ uint8 ssid_len; ++ int8 rssi_thresh; ++ uint8 flags; ++ uint8 auth; ++ /* index required only for visble ssid */ ++ uint32 index; ++ struct list_head list; ++} dhd_epno_params_t; ++ ++typedef struct dhd_epno_results { ++ uint8 ssid[DOT11_MAX_SSID_LEN]; ++ uint8 ssid_len; ++ int8 rssi; ++ uint16 channel; ++ uint16 flags; ++ struct ether_addr bssid; ++} dhd_epno_results_t; ++ ++typedef struct wifi_gscan_result { ++ uint64 ts; /* Time of discovery */ ++ char ssid[DOT11_MAX_SSID_LEN+1]; /* null terminated */ ++ struct ether_addr macaddr; /* BSSID */ ++ uint32 channel; /* channel frequency in MHz */ ++ int32 rssi; /* in db */ ++ uint64 rtt; /* in nanoseconds */ ++ uint64 rtt_sd; /* standard deviation in rtt */ ++ uint16 beacon_period; /* units are Kusec */ ++ uint16 capability; /* Capability information */ ++ uint32 pad; ++} wifi_gscan_result_t; ++ ++typedef struct wifi_gscan_full_result { ++ wifi_gscan_result_t fixed; ++ uint32 scan_ch_bucket; ++ uint32 ie_length; /* byte length of Information Elements */ ++ char ie_data[1]; /* IE data to follow */ ++} wifi_gscan_full_result_t; ++ ++typedef struct gscan_results_cache { ++ struct gscan_results_cache *next; ++ uint8 scan_id; ++ uint8 flag; ++ uint8 tot_count; ++ uint8 tot_consumed; ++ uint32 scan_ch_bucket; ++ wifi_gscan_result_t results[1]; ++} gscan_results_cache_t; ++ ++typedef struct dhd_pno_gscan_capabilities { ++ int max_scan_cache_size; ++ int max_scan_buckets; ++ int max_ap_cache_per_scan; ++ int max_rssi_sample_size; ++ int max_scan_reporting_threshold; ++ int max_hotlist_aps; ++ int max_significant_wifi_change_aps; ++ int max_epno_ssid_crc32; ++ int max_epno_hidden_ssid; ++ int max_white_list_ssid; ++} dhd_pno_gscan_capabilities_t; ++ ++typedef struct dhd_epno_ssid_cfg { ++ wl_pfn_ssid_params_t params; ++ uint32 num_epno_ssid; ++ struct list_head epno_ssid_list; ++} dhd_epno_ssid_cfg_t; ++ ++struct dhd_pno_gscan_params { ++ int32 scan_fr; ++ uint8 bestn; ++ uint8 mscan; ++ uint8 buffer_threshold; ++ uint8 lost_ap_window; ++ uint8 nchannel_buckets; ++ uint8 reason; ++ uint8 get_batch_flag; ++ uint8 send_all_results_flag; ++ uint16 max_ch_bucket_freq; ++ gscan_results_cache_t *gscan_batch_cache; ++ gscan_results_cache_t *gscan_hotlist_found; ++ gscan_results_cache_t *gscan_hotlist_lost; ++ uint16 nbssid_hotlist; ++ struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS]; ++ struct list_head hotlist_bssid_list; ++ dhd_epno_ssid_cfg_t epno_cfg; ++ uint32 scan_id; ++}; ++ ++typedef struct gscan_scan_params { ++ int32 scan_fr; ++ uint16 nchannel_buckets; ++ struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS]; ++} gscan_scan_params_t; ++ ++typedef struct gscan_batch_params { ++ uint8 bestn; ++ uint8 mscan; ++ uint8 buffer_threshold; ++} gscan_batch_params_t; ++ ++struct bssid_t { ++ struct ether_addr macaddr; ++ int16 rssi_reporting_threshold; /* 0 -> no reporting threshold */ ++}; ++ ++typedef struct gscan_hotlist_scan_params { ++ uint16 lost_ap_window; /* number of scans to declare LOST */ ++ uint16 nbssid; /* number of bssids */ ++ struct bssid_t bssid[1]; /* n bssids to follow */ ++} gscan_hotlist_scan_params_t; ++ ++#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ ++typedef union dhd_pno_params { ++ struct dhd_pno_legacy_params params_legacy; ++ struct dhd_pno_batch_params params_batch; ++ struct dhd_pno_hotlist_params params_hotlist; ++#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) ++ struct dhd_pno_gscan_params params_gscan; ++#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ ++} dhd_pno_params_t; ++typedef struct dhd_pno_status_info { ++ dhd_pub_t *dhd; ++ struct work_struct work; ++ struct mutex pno_mutex; ++#ifdef GSCAN_SUPPORT ++ wait_queue_head_t batch_get_wait; ++#endif /* GSCAN_SUPPORT */ ++ struct completion get_batch_done; ++ bool wls_supported; /* wifi location service supported or not */ ++ enum dhd_pno_status pno_status; ++ enum dhd_pno_mode pno_mode; ++ dhd_pno_params_t pno_params_arr[INDEX_MODE_MAX]; ++ struct list_head head_list; ++} dhd_pno_status_info_t; ++ ++/* wrapper functions */ ++extern int ++dhd_dev_pno_enable(struct net_device *dev, int enable); ++ ++extern int ++dhd_dev_pno_stop_for_ssid(struct net_device *dev); ++ ++extern int ++dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, ++ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); ++ ++extern int ++dhd_dev_pno_set_for_batch(struct net_device *dev, ++ struct dhd_pno_batch_params *batch_params); ++ ++extern int ++dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize); ++ ++extern int ++dhd_dev_pno_stop_for_batch(struct net_device *dev); ++ ++extern int ++dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, ++ struct dhd_pno_hotlist_params *hotlist_params); ++extern bool dhd_dev_is_legacy_pno_enabled(struct net_device *dev); ++#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) ++extern void * ++dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, void *info, ++ uint32 *len); ++#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ ++#ifdef GSCAN_SUPPORT ++extern int ++dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, ++ void *buf, bool flush); ++int dhd_dev_pno_lock_access_batch_results(struct net_device *dev); ++void dhd_dev_pno_unlock_access_batch_results(struct net_device *dev); ++extern int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush); ++extern int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time); ++int dhd_retreive_batch_scan_results(dhd_pub_t *dhd); ++extern void * dhd_dev_hotlist_scan_event(struct net_device *dev, ++ const void *data, int *send_evt_bytes, hotlist_type_t type); ++void * dhd_dev_process_full_gscan_result(struct net_device *dev, ++ const void *data, uint32 len, int *send_evt_bytes); ++extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev); ++extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type); ++extern int dhd_dev_wait_batch_results_complete(struct net_device *dev); ++extern void * dhd_dev_process_epno_result(struct net_device *dev, ++ const void *data, uint32 event, int *send_evt_bytes); ++extern int dhd_dev_set_epno(struct net_device *dev); ++extern int dhd_dev_flush_fw_epno(struct net_device *dev); ++#endif /* GSCAN_SUPPORT */ ++/* dhd pno fuctions */ ++extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd); ++extern int dhd_pno_enable(dhd_pub_t *dhd, int enable); ++extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, ++ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); ++ ++extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params); ++ ++extern int dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason); ++ ++ ++extern int dhd_pno_stop_for_batch(dhd_pub_t *dhd); ++ ++extern int dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, ++ struct dhd_pno_hotlist_params *hotlist_params); ++ ++extern int dhd_pno_stop_for_hotlist(dhd_pub_t *dhd); ++ ++extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); ++extern int dhd_pno_init(dhd_pub_t *dhd); ++extern int dhd_pno_deinit(dhd_pub_t *dhd); ++extern bool dhd_is_pno_supported(dhd_pub_t *dhd); ++extern bool dhd_is_legacy_pno_enabled(dhd_pub_t *dhd); ++#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) ++extern void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *info, ++ uint32 *len); ++#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ ++#ifdef GSCAN_SUPPORT ++extern int dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, ++ void *buf, bool flush); ++extern int dhd_pno_lock_batch_results(dhd_pub_t *dhd); ++extern void dhd_pno_unlock_batch_results(dhd_pub_t *dhd); ++extern int dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush); ++extern int dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag); ++extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *buf); ++extern int dhd_dev_retrieve_batch_scan(struct net_device *dev); ++extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, ++ int *send_evt_bytes, hotlist_type_t type); ++extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data, ++ uint32 len, int *send_evt_bytes); ++extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd); ++extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type); ++extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd); ++extern void * dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, ++ uint32 event, int *size); ++extern void dhd_pno_translate_epno_fw_flags(uint32 *flags); ++extern int dhd_pno_set_epno(dhd_pub_t *dhd); ++extern int dhd_pno_flush_fw_epno(dhd_pub_t *dhd); ++extern void dhd_pno_set_epno_auth_flag(uint32 *wpa_auth); ++#endif /* GSCAN_SUPPORT */ ++#endif ++ ++#endif /* __DHD_PNO_H__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_proto.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_proto.h +new file mode 100644 +index 000000000..820e3449f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_proto.h +@@ -0,0 +1,201 @@ ++/* ++ * Header file describing the internal (inter-module) DHD interfaces. ++ * ++ * Provides type definitions and function prototypes used to link the ++ * DHD OS, bus, and protocol modules. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_proto.h 678890 2017-01-11 11:48:36Z $ ++ */ ++ ++#ifndef _dhd_proto_h_ ++#define _dhd_proto_h_ ++ ++#include ++#include ++#ifdef BCMPCIE ++#include ++#endif ++ ++#define DEFAULT_IOCTL_RESP_TIMEOUT 4000 ++#ifndef IOCTL_RESP_TIMEOUT ++/* In milli second default value for Production FW */ ++#define IOCTL_RESP_TIMEOUT DEFAULT_IOCTL_RESP_TIMEOUT ++#endif /* IOCTL_RESP_TIMEOUT */ ++ ++#ifndef MFG_IOCTL_RESP_TIMEOUT ++#define MFG_IOCTL_RESP_TIMEOUT 20000 /* In milli second default value for MFG FW */ ++#endif /* MFG_IOCTL_RESP_TIMEOUT */ ++ ++#define DEFAULT_D3_ACK_RESP_TIMEOUT 1000 ++#ifndef D3_ACK_RESP_TIMEOUT ++#define D3_ACK_RESP_TIMEOUT DEFAULT_D3_ACK_RESP_TIMEOUT ++#endif /* D3_ACK_RESP_TIMEOUT */ ++ ++#define DEFAULT_DHD_BUS_BUSY_TIMEOUT (IOCTL_RESP_TIMEOUT + 1000) ++#ifndef DHD_BUS_BUSY_TIMEOUT ++#define DHD_BUS_BUSY_TIMEOUT DEFAULT_DHD_BUS_BUSY_TIMEOUT ++#endif /* DEFAULT_DHD_BUS_BUSY_TIMEOUT */ ++ ++#define DS_EXIT_TIMEOUT 1000 /* In ms */ ++#define DS_ENTER_TIMEOUT 1000 /* In ms */ ++ ++#define IOCTL_DISABLE_TIMEOUT 0 ++ ++/* ++ * Exported from the dhd protocol module (dhd_cdc, dhd_rndis) ++ */ ++ ++/* Linkage, sets prot link and updates hdrlen in pub */ ++extern int dhd_prot_attach(dhd_pub_t *dhdp); ++ ++/* Initilizes the index block for dma'ing indices */ ++extern int dhd_prot_dma_indx_init(dhd_pub_t *dhdp, uint32 rw_index_sz, ++ uint8 type, uint32 length); ++ ++/* Unlink, frees allocated protocol memory (including dhd_prot) */ ++extern void dhd_prot_detach(dhd_pub_t *dhdp); ++ ++/* Initialize protocol: sync w/dongle state. ++ * Sets dongle media info (iswl, drv_version, mac address). ++ */ ++extern int dhd_sync_with_dongle(dhd_pub_t *dhdp); ++ ++/* Protocol initialization needed for IOCTL/IOVAR path */ ++extern int dhd_prot_init(dhd_pub_t *dhd); ++ ++/* Stop protocol: sync w/dongle state. */ ++extern void dhd_prot_stop(dhd_pub_t *dhdp); ++ ++/* Add any protocol-specific data header. ++ * Caller must reserve prot_hdrlen prepend space. ++ */ ++extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); ++extern uint dhd_prot_hdrlen(dhd_pub_t *, void *txp); ++ ++/* Remove any protocol-specific data header. */ ++extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); ++ ++/* Use protocol to issue ioctl to dongle */ ++extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); ++ ++/* Handles a protocol control response asynchronously */ ++extern int dhd_prot_ctl_complete(dhd_pub_t *dhd); ++ ++/* Check for and handle local prot-specific iovar commands */ ++extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Add prot dump output to a buffer */ ++extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); ++ ++/* Dump extended trap data */ ++extern int dhd_prot_dump_extended_trap(dhd_pub_t *dhdp, struct bcmstrbuf *b, bool raw); ++ ++/* Update local copy of dongle statistics */ ++extern void dhd_prot_dstats(dhd_pub_t *dhdp); ++ ++extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen); ++ ++extern int dhd_preinit_ioctls(dhd_pub_t *dhd); ++ ++extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, ++ uint reorder_info_len, void **pkt, uint32 *free_buf_count); ++ ++#ifdef BCMPCIE ++extern bool dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound); ++extern bool dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound); ++extern bool dhd_prot_process_msgbuf_infocpl(dhd_pub_t *dhd, uint bound); ++extern int dhd_prot_process_ctrlbuf(dhd_pub_t * dhd); ++extern int dhd_prot_process_trapbuf(dhd_pub_t * dhd); ++extern bool dhd_prot_dtohsplit(dhd_pub_t * dhd); ++extern int dhd_post_dummy_msg(dhd_pub_t *dhd); ++extern int dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len); ++extern void dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 offset); ++extern int dhd_prot_txdata(dhd_pub_t *dhd, void *p, uint8 ifidx); ++extern int dhdmsgbuf_dmaxfer_req(dhd_pub_t *dhd, ++ uint len, uint srcdelay, uint destdelay, uint d11_lpbk); ++ ++extern void dhd_dma_buf_init(dhd_pub_t *dhd, void *dma_buf, ++ void *va, uint32 len, dmaaddr_t pa, void *dmah, void *secdma); ++extern void dhd_prot_flowrings_pool_release(dhd_pub_t *dhd, ++ uint16 flowid, void *msgbuf_ring); ++extern int dhd_prot_flow_ring_create(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); ++extern int dhd_post_tx_ring_item(dhd_pub_t *dhd, void *PKTBUF, uint8 ifindex); ++extern int dhd_prot_flow_ring_delete(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); ++extern int dhd_prot_flow_ring_flush(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); ++extern int dhd_prot_ringupd_dump(dhd_pub_t *dhd, struct bcmstrbuf *b); ++extern uint32 dhd_prot_metadata_dbg_set(dhd_pub_t *dhd, bool val); ++extern uint32 dhd_prot_metadata_dbg_get(dhd_pub_t *dhd); ++extern uint32 dhd_prot_metadatalen_set(dhd_pub_t *dhd, uint32 val, bool rx); ++extern uint32 dhd_prot_metadatalen_get(dhd_pub_t *dhd, bool rx); ++extern void dhd_prot_print_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info, ++ struct bcmstrbuf *strbuf, const char * fmt); ++extern void dhd_prot_print_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf); ++extern void dhd_prot_update_txflowring(dhd_pub_t *dhdp, uint16 flow_id, void *msgring_info); ++extern void dhd_prot_txdata_write_flush(dhd_pub_t *dhd, uint16 flow_id, bool in_lock); ++extern uint32 dhd_prot_txp_threshold(dhd_pub_t *dhd, bool set, uint32 val); ++extern void dhd_prot_reset(dhd_pub_t *dhd); ++ ++#ifdef IDLE_TX_FLOW_MGMT ++extern int dhd_prot_flow_ring_batch_suspend_request(dhd_pub_t *dhd, uint16 *ringid, uint16 count); ++extern int dhd_prot_flow_ring_resume(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node); ++#endif /* IDLE_TX_FLOW_MGMT */ ++extern int dhd_prot_init_info_rings(dhd_pub_t *dhd); ++ ++#endif /* BCMPCIE */ ++ ++#ifdef DHD_LB ++extern void dhd_lb_tx_compl_handler(unsigned long data); ++extern void dhd_lb_rx_compl_handler(unsigned long data); ++extern void dhd_lb_rx_process_handler(unsigned long data); ++#endif /* DHD_LB */ ++extern int dhd_prot_h2d_mbdata_send_ctrlmsg(dhd_pub_t *dhd, uint32 mb_data); ++ ++#ifdef BCMPCIE ++extern int dhd_prot_send_host_timestamp(dhd_pub_t *dhdp, uchar *tlv, uint16 tlv_len, ++ uint16 seq, uint16 xt_id); ++extern bool dhd_prot_data_path_tx_timestamp_logging(dhd_pub_t *dhd, bool enable, bool set); ++extern bool dhd_prot_data_path_rx_timestamp_logging(dhd_pub_t *dhd, bool enable, bool set); ++#else /* BCMPCIE */ ++#define dhd_prot_send_host_timestamp(a, b, c, d, e) 0 ++#define dhd_prot_data_path_tx_timestamp_logging(a, b, c) 0 ++#define dhd_prot_data_path_rx_timestamp_logging(a, b, c) 0 ++#endif /* BCMPCIE */ ++ ++extern void dhd_prot_dma_indx_free(dhd_pub_t *dhd); ++ ++/******************************** ++ * For version-string expansion * ++ */ ++#if defined(BDC) ++#define DHD_PROTOCOL "bdc" ++#elif defined(CDC) ++#define DHD_PROTOCOL "cdc" ++#else ++#define DHD_PROTOCOL "unknown" ++#endif /* proto */ ++ ++#endif /* _dhd_proto_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_rtt.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_rtt.c +new file mode 100644 +index 000000000..a13f7ae14 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_rtt.c +@@ -0,0 +1,2421 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), RTT ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id$ ++ */ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#ifdef WL_CFG80211 ++#include ++#endif /* WL_CFG80211 */ ++static DEFINE_SPINLOCK(noti_list_lock); ++#define NULL_CHECK(p, s, err) \ ++ do { \ ++ if (!(p)) { \ ++ printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ ++ err = BCME_ERROR; \ ++ return err; \ ++ } \ ++ } while (0) ++ ++#define RTT_IS_ENABLED(rtt_status) (rtt_status->status == RTT_ENABLED) ++#define RTT_IS_STOPPED(rtt_status) (rtt_status->status == RTT_STOPPED) ++#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \ ++ (ts).tv_nsec / NSEC_PER_USEC) ++ ++#define FTM_IOC_BUFSZ 2048 /* ioc buffsize for our module (> BCM_XTLV_HDR_SIZE) */ ++#define FTM_AVAIL_MAX_SLOTS 32 ++#define FTM_MAX_CONFIGS 10 ++#define FTM_MAX_PARAMS 10 ++#define FTM_DEFAULT_SESSION 1 ++#define FTM_BURST_TIMEOUT_UNIT 250 /* 250 ns */ ++#define FTM_INVALID -1 ++#define FTM_DEFAULT_CNT_20M 12 ++#define FTM_DEFAULT_CNT_40M 10 ++#define FTM_DEFAULT_CNT_80M 5 ++ ++/* convenience macros */ ++#define FTM_TU2MICRO(_tu) ((uint64)(_tu) << 10) ++#define FTM_MICRO2TU(_tu) ((uint64)(_tu) >> 10) ++#define FTM_TU2MILLI(_tu) ((uint32)FTM_TU2MICRO(_tu) / 1000) ++#define FTM_MICRO2MILLI(_x) ((uint32)(_x) / 1000) ++#define FTM_MICRO2SEC(_x) ((uint32)(_x) / 1000000) ++#define FTM_INTVL2NSEC(_intvl) ((uint32)ftm_intvl2nsec(_intvl)) ++#define FTM_INTVL2USEC(_intvl) ((uint32)ftm_intvl2usec(_intvl)) ++#define FTM_INTVL2MSEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000) ++#define FTM_INTVL2SEC(_intvl) (FTM_INTVL2USEC(_intvl) / 1000000) ++#define FTM_USECIN100MILLI(_usec) ((_usec) / 100000) ++ ++/* broadcom specific set to have more accurate data */ ++#define ENABLE_VHT_ACK ++#define CH_MIN_5G_CHANNEL 34 ++#define CH_MIN_2G_CHANNEL 1 ++ ++struct rtt_noti_callback { ++ struct list_head list; ++ void *ctx; ++ dhd_rtt_compl_noti_fn noti_fn; ++}; ++ ++ ++/* bitmask indicating which command groups; */ ++typedef enum { ++ FTM_SUBCMD_FLAG_METHOD = 0x01, /* FTM method command */ ++ FTM_SUBCMD_FLAG_SESSION = 0x02, /* FTM session command */ ++ FTM_SUBCMD_FLAG_ALL = FTM_SUBCMD_FLAG_METHOD | FTM_SUBCMD_FLAG_SESSION ++} ftm_subcmd_flag_t; ++ ++/* proxd ftm config-category definition */ ++typedef enum { ++ FTM_CONFIG_CAT_GENERAL = 1, /* generial configuration */ ++ FTM_CONFIG_CAT_OPTIONS = 2, /* 'config options' */ ++ FTM_CONFIG_CAT_AVAIL = 3, /* 'config avail' */ ++} ftm_config_category_t; ++ ++ ++typedef struct ftm_subcmd_info { ++ int16 version; /* FTM version (optional) */ ++ char *name; /* cmd-name string as cmdline input */ ++ wl_proxd_cmd_t cmdid; /* cmd-id */ ++ bcm_xtlv_unpack_cbfn_t *handler; /* cmd response handler (optional) */ ++ ftm_subcmd_flag_t cmdflag; /* CMD flag (optional) */ ++} ftm_subcmd_info_t; ++ ++ ++typedef struct ftm_config_options_info { ++ uint32 flags; /* wl_proxd_flags_t/wl_proxd_session_flags_t */ ++ bool enable; ++} ftm_config_options_info_t; ++ ++typedef struct ftm_config_param_info { ++ uint16 tlvid; /* mapping TLV id for the item */ ++ union { ++ uint32 chanspec; ++ struct ether_addr mac_addr; ++ wl_proxd_intvl_t data_intvl; ++ uint32 data32; ++ uint16 data16; ++ uint8 data8; ++ }; ++} ftm_config_param_info_t; ++ ++/* ++* definition for id-string mapping. ++* This is used to map an id (can be cmd-id, tlv-id, ....) to a text-string ++* for debug-display or cmd-log-display ++*/ ++typedef struct ftm_strmap_entry { ++ int32 id; ++ char *text; ++} ftm_strmap_entry_t; ++ ++ ++typedef struct ftm_status_map_host_entry { ++ wl_proxd_status_t proxd_status; ++ rtt_reason_t rtt_reason; ++} ftm_status_map_host_entry_t; ++ ++static int ++dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len); ++ ++static wifi_rate_t ++dhd_rtt_convert_rate_to_host(uint32 ratespec); ++ ++#ifdef WL_CFG80211 ++static int ++dhd_rtt_start(dhd_pub_t *dhd); ++#endif /* WL_CFG80211 */ ++static const int burst_duration_idx[] = {0, 0, 1, 2, 4, 8, 16, 32, 64, 128, 0, 0}; ++ ++/* ftm status mapping to host status */ ++static const ftm_status_map_host_entry_t ftm_status_map_info[] = { ++ {WL_PROXD_E_INCOMPLETE, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_OVERRIDDEN, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_ASAP_FAILED, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_NOTSTARTED, RTT_REASON_FAIL_NOT_SCHEDULED_YET}, ++ {WL_PROXD_E_INVALIDMEAS, RTT_REASON_FAIL_INVALID_TS}, ++ {WL_PROXD_E_INCAPABLE, RTT_REASON_FAIL_NO_CAPABILITY}, ++ {WL_PROXD_E_MISMATCH, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_DUP_SESSION, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_REMOTE_FAIL, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_REMOTE_INCAPABLE, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_SCHED_FAIL, RTT_REASON_FAIL_SCHEDULE}, ++ {WL_PROXD_E_PROTO, RTT_REASON_FAIL_PROTOCOL}, ++ {WL_PROXD_E_EXPIRED, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_TIMEOUT, RTT_REASON_FAIL_TM_TIMEOUT}, ++ {WL_PROXD_E_NOACK, RTT_REASON_FAIL_NO_RSP}, ++ {WL_PROXD_E_DEFERRED, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_INVALID_SID, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_REMOTE_CANCEL, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_CANCELED, RTT_REASON_ABORTED}, ++ {WL_PROXD_E_INVALID_SESSION, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_BAD_STATE, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_ERROR, RTT_REASON_FAILURE}, ++ {WL_PROXD_E_OK, RTT_REASON_SUCCESS} ++}; ++ ++/* ftm tlv-id mapping */ ++static const ftm_strmap_entry_t ftm_tlvid_loginfo[] = { ++ /* { WL_PROXD_TLV_ID_xxx, "text for WL_PROXD_TLV_ID_xxx" }, */ ++ { WL_PROXD_TLV_ID_NONE, "none" }, ++ { WL_PROXD_TLV_ID_METHOD, "method" }, ++ { WL_PROXD_TLV_ID_FLAGS, "flags" }, ++ { WL_PROXD_TLV_ID_CHANSPEC, "chanspec" }, ++ { WL_PROXD_TLV_ID_TX_POWER, "tx power" }, ++ { WL_PROXD_TLV_ID_RATESPEC, "ratespec" }, ++ { WL_PROXD_TLV_ID_BURST_DURATION, "burst duration" }, ++ { WL_PROXD_TLV_ID_BURST_PERIOD, "burst period" }, ++ { WL_PROXD_TLV_ID_BURST_FTM_SEP, "burst ftm sep" }, ++ { WL_PROXD_TLV_ID_BURST_NUM_FTM, "burst num ftm" }, ++ { WL_PROXD_TLV_ID_NUM_BURST, "num burst" }, ++ { WL_PROXD_TLV_ID_FTM_RETRIES, "ftm retries" }, ++ { WL_PROXD_TLV_ID_BSS_INDEX, "BSS index" }, ++ { WL_PROXD_TLV_ID_BSSID, "bssid" }, ++ { WL_PROXD_TLV_ID_INIT_DELAY, "burst init delay" }, ++ { WL_PROXD_TLV_ID_BURST_TIMEOUT, "burst timeout" }, ++ { WL_PROXD_TLV_ID_EVENT_MASK, "event mask" }, ++ { WL_PROXD_TLV_ID_FLAGS_MASK, "flags mask" }, ++ { WL_PROXD_TLV_ID_PEER_MAC, "peer addr" }, ++ { WL_PROXD_TLV_ID_FTM_REQ, "ftm req" }, ++ { WL_PROXD_TLV_ID_LCI_REQ, "lci req" }, ++ { WL_PROXD_TLV_ID_LCI, "lci" }, ++ { WL_PROXD_TLV_ID_CIVIC_REQ, "civic req" }, ++ { WL_PROXD_TLV_ID_CIVIC, "civic" }, ++ { WL_PROXD_TLV_ID_AVAIL, "availability" }, ++ { WL_PROXD_TLV_ID_SESSION_FLAGS, "session flags" }, ++ { WL_PROXD_TLV_ID_SESSION_FLAGS_MASK, "session flags mask" }, ++ { WL_PROXD_TLV_ID_RX_MAX_BURST, "rx max bursts" }, ++ { WL_PROXD_TLV_ID_RANGING_INFO, "ranging info" }, ++ { WL_PROXD_TLV_ID_RANGING_FLAGS, "ranging flags" }, ++ { WL_PROXD_TLV_ID_RANGING_FLAGS_MASK, "ranging flags mask" }, ++ /* output - 512 + x */ ++ { WL_PROXD_TLV_ID_STATUS, "status" }, ++ { WL_PROXD_TLV_ID_COUNTERS, "counters" }, ++ { WL_PROXD_TLV_ID_INFO, "info" }, ++ { WL_PROXD_TLV_ID_RTT_RESULT, "rtt result" }, ++ { WL_PROXD_TLV_ID_AOA_RESULT, "aoa result" }, ++ { WL_PROXD_TLV_ID_SESSION_INFO, "session info" }, ++ { WL_PROXD_TLV_ID_SESSION_STATUS, "session status" }, ++ { WL_PROXD_TLV_ID_SESSION_ID_LIST, "session ids" }, ++ /* debug tlvs can be added starting 1024 */ ++ { WL_PROXD_TLV_ID_DEBUG_MASK, "debug mask" }, ++ { WL_PROXD_TLV_ID_COLLECT, "collect" }, ++ { WL_PROXD_TLV_ID_STRBUF, "result" }, ++ { WL_PROXD_TLV_ID_COLLECT_DATA, "collect-data" }, ++ { WL_PROXD_TLV_ID_RI_RR, "ri_rr" }, ++ { WL_PROXD_TLV_ID_COLLECT_CHAN_DATA, "chan est"} ++}; ++ ++static const ftm_strmap_entry_t ftm_event_type_loginfo[] = { ++ /* wl_proxd_event_type_t, text-string */ ++ { WL_PROXD_EVENT_NONE, "none" }, ++ { WL_PROXD_EVENT_SESSION_CREATE, "session create" }, ++ { WL_PROXD_EVENT_SESSION_START, "session start" }, ++ { WL_PROXD_EVENT_FTM_REQ, "FTM req" }, ++ { WL_PROXD_EVENT_BURST_START, "burst start" }, ++ { WL_PROXD_EVENT_BURST_END, "burst end" }, ++ { WL_PROXD_EVENT_SESSION_END, "session end" }, ++ { WL_PROXD_EVENT_SESSION_RESTART, "session restart" }, ++ { WL_PROXD_EVENT_BURST_RESCHED, "burst rescheduled" }, ++ { WL_PROXD_EVENT_SESSION_DESTROY, "session destroy" }, ++ { WL_PROXD_EVENT_RANGE_REQ, "range request" }, ++ { WL_PROXD_EVENT_FTM_FRAME, "FTM frame" }, ++ { WL_PROXD_EVENT_DELAY, "delay" }, ++ { WL_PROXD_EVENT_VS_INITIATOR_RPT, "initiator-report " }, /* rx */ ++ { WL_PROXD_EVENT_RANGING, "ranging " }, ++ { WL_PROXD_EVENT_COLLECT, "collect" }, ++}; ++ ++/* ++* session-state --> text string mapping ++*/ ++static const ftm_strmap_entry_t ftm_session_state_value_loginfo[] = { ++ /* wl_proxd_session_state_t, text string */ ++ { WL_PROXD_SESSION_STATE_CREATED, "created" }, ++ { WL_PROXD_SESSION_STATE_CONFIGURED, "configured" }, ++ { WL_PROXD_SESSION_STATE_STARTED, "started" }, ++ { WL_PROXD_SESSION_STATE_DELAY, "delay" }, ++ { WL_PROXD_SESSION_STATE_USER_WAIT, "user-wait" }, ++ { WL_PROXD_SESSION_STATE_SCHED_WAIT, "sched-wait" }, ++ { WL_PROXD_SESSION_STATE_BURST, "burst" }, ++ { WL_PROXD_SESSION_STATE_STOPPING, "stopping" }, ++ { WL_PROXD_SESSION_STATE_ENDED, "ended" }, ++ { WL_PROXD_SESSION_STATE_DESTROYING, "destroying" }, ++ { WL_PROXD_SESSION_STATE_NONE, "none" } ++}; ++ ++/* ++* ranging-state --> text string mapping ++*/ ++static const ftm_strmap_entry_t ftm_ranging_state_value_loginfo [] = { ++ /* wl_proxd_ranging_state_t, text string */ ++ { WL_PROXD_RANGING_STATE_NONE, "none" }, ++ { WL_PROXD_RANGING_STATE_NOTSTARTED, "nonstarted" }, ++ { WL_PROXD_RANGING_STATE_INPROGRESS, "inprogress" }, ++ { WL_PROXD_RANGING_STATE_DONE, "done" }, ++}; ++ ++/* ++* status --> text string mapping ++*/ ++static const ftm_strmap_entry_t ftm_status_value_loginfo[] = { ++ /* wl_proxd_status_t, text-string */ ++ { WL_PROXD_E_OVERRIDDEN, "overridden" }, ++ { WL_PROXD_E_ASAP_FAILED, "ASAP failed" }, ++ { WL_PROXD_E_NOTSTARTED, "not started" }, ++ { WL_PROXD_E_INVALIDMEAS, "invalid measurement" }, ++ { WL_PROXD_E_INCAPABLE, "incapable" }, ++ { WL_PROXD_E_MISMATCH, "mismatch"}, ++ { WL_PROXD_E_DUP_SESSION, "dup session" }, ++ { WL_PROXD_E_REMOTE_FAIL, "remote fail" }, ++ { WL_PROXD_E_REMOTE_INCAPABLE, "remote incapable" }, ++ { WL_PROXD_E_SCHED_FAIL, "sched failure" }, ++ { WL_PROXD_E_PROTO, "protocol error" }, ++ { WL_PROXD_E_EXPIRED, "expired" }, ++ { WL_PROXD_E_TIMEOUT, "timeout" }, ++ { WL_PROXD_E_NOACK, "no ack" }, ++ { WL_PROXD_E_DEFERRED, "deferred" }, ++ { WL_PROXD_E_INVALID_SID, "invalid session id" }, ++ { WL_PROXD_E_REMOTE_CANCEL, "remote cancel" }, ++ { WL_PROXD_E_CANCELED, "canceled" }, ++ { WL_PROXD_E_INVALID_SESSION, "invalid session" }, ++ { WL_PROXD_E_BAD_STATE, "bad state" }, ++ { WL_PROXD_E_ERROR, "error" }, ++ { WL_PROXD_E_OK, "OK" } ++}; ++ ++/* ++* time interval unit --> text string mapping ++*/ ++static const ftm_strmap_entry_t ftm_tmu_value_loginfo[] = { ++ /* wl_proxd_tmu_t, text-string */ ++ { WL_PROXD_TMU_TU, "TU" }, ++ { WL_PROXD_TMU_SEC, "sec" }, ++ { WL_PROXD_TMU_MILLI_SEC, "ms" }, ++ { WL_PROXD_TMU_MICRO_SEC, "us" }, ++ { WL_PROXD_TMU_NANO_SEC, "ns" }, ++ { WL_PROXD_TMU_PICO_SEC, "ps" } ++}; ++ ++#define RSPEC_BW(rspec) ((rspec) & WL_RSPEC_BW_MASK) ++#define RSPEC_IS20MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_20MHZ) ++#define RSPEC_IS40MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_40MHZ) ++#define RSPEC_IS80MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_80MHZ) ++#define RSPEC_IS160MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_160MHZ) ++ ++#define IS_MCS(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) != WL_RSPEC_ENCODE_RATE) ++#define IS_STBC(rspec) (((((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) || \ ++ (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)) && \ ++ (((rspec) & WL_RSPEC_STBC) == WL_RSPEC_STBC)) ++#define RSPEC_ISSGI(rspec) (((rspec) & WL_RSPEC_SGI) != 0) ++#define RSPEC_ISLDPC(rspec) (((rspec) & WL_RSPEC_LDPC) != 0) ++#define RSPEC_ISSTBC(rspec) (((rspec) & WL_RSPEC_STBC) != 0) ++#define RSPEC_ISTXBF(rspec) (((rspec) & WL_RSPEC_TXBF) != 0) ++#define RSPEC_ISVHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) ++#define RSPEC_ISHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) ++#define RSPEC_ISLEGACY(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) ++#define RSPEC2RATE(rspec) (RSPEC_ISLEGACY(rspec) ? \ ++ ((rspec) & RSPEC_RATE_MASK) : rate_rspec2rate(rspec)) ++/* return rate in unit of 500Kbps -- for internal use in wlc_rate_sel.c */ ++#define RSPEC2KBPS(rspec) rate_rspec2rate(rspec) ++ ++struct ieee_80211_mcs_rate_info { ++ uint8 constellation_bits; ++ uint8 coding_q; ++ uint8 coding_d; ++}; ++ ++static const struct ieee_80211_mcs_rate_info wl_mcs_info[] = { ++ { 1, 1, 2 }, /* MCS 0: MOD: BPSK, CR 1/2 */ ++ { 2, 1, 2 }, /* MCS 1: MOD: QPSK, CR 1/2 */ ++ { 2, 3, 4 }, /* MCS 2: MOD: QPSK, CR 3/4 */ ++ { 4, 1, 2 }, /* MCS 3: MOD: 16QAM, CR 1/2 */ ++ { 4, 3, 4 }, /* MCS 4: MOD: 16QAM, CR 3/4 */ ++ { 6, 2, 3 }, /* MCS 5: MOD: 64QAM, CR 2/3 */ ++ { 6, 3, 4 }, /* MCS 6: MOD: 64QAM, CR 3/4 */ ++ { 6, 5, 6 }, /* MCS 7: MOD: 64QAM, CR 5/6 */ ++ { 8, 3, 4 }, /* MCS 8: MOD: 256QAM, CR 3/4 */ ++ { 8, 5, 6 } /* MCS 9: MOD: 256QAM, CR 5/6 */ ++}; ++ ++/** ++ * Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination. ++ * 'mcs' : a *single* spatial stream MCS (11n or 11ac) ++ */ ++uint ++rate_mcs2rate(uint mcs, uint nss, uint bw, int sgi) ++{ ++ const int ksps = 250; /* kilo symbols per sec, 4 us sym */ ++ const int Nsd_20MHz = 52; ++ const int Nsd_40MHz = 108; ++ const int Nsd_80MHz = 234; ++ const int Nsd_160MHz = 468; ++ uint rate; ++ ++ if (mcs == 32) { ++ /* just return fixed values for mcs32 instead of trying to parametrize */ ++ rate = (sgi == 0) ? 6000 : 6778; ++ } else if (mcs <= 9) { ++ /* This calculation works for 11n HT and 11ac VHT if the HT mcs values ++ * are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8. ++ * That is, HT MCS 23 is a base MCS = 7, Nss = 3 ++ */ ++ ++ /* find the number of complex numbers per symbol */ ++ if (RSPEC_IS20MHZ(bw)) { ++ rate = Nsd_20MHz; ++ } else if (RSPEC_IS40MHZ(bw)) { ++ rate = Nsd_40MHz; ++ } else if (bw == WL_RSPEC_BW_80MHZ) { ++ rate = Nsd_80MHz; ++ } else if (bw == WL_RSPEC_BW_160MHZ) { ++ rate = Nsd_160MHz; ++ } else { ++ rate = 0; ++ } ++ ++ /* multiply by bits per number from the constellation in use */ ++ rate = rate * wl_mcs_info[mcs].constellation_bits; ++ ++ /* adjust for the number of spatial streams */ ++ rate = rate * nss; ++ ++ /* adjust for the coding rate given as a quotient and divisor */ ++ rate = (rate * wl_mcs_info[mcs].coding_q) / wl_mcs_info[mcs].coding_d; ++ ++ /* multiply by Kilo symbols per sec to get Kbps */ ++ rate = rate * ksps; ++ ++ /* adjust the symbols per sec for SGI ++ * symbol duration is 4 us without SGI, and 3.6 us with SGI, ++ * so ratio is 10 / 9 ++ */ ++ if (sgi) { ++ /* add 4 for rounding of division by 9 */ ++ rate = ((rate * 10) + 4) / 9; ++ } ++ } else { ++ rate = 0; ++ } ++ ++ return rate; ++} /* wlc_rate_mcs2rate */ ++ ++/** take a well formed ratespec_t arg and return phy rate in [Kbps] units */ ++int ++rate_rspec2rate(uint32 rspec) ++{ ++ int rate = -1; ++ ++ if (RSPEC_ISLEGACY(rspec)) { ++ rate = 500 * (rspec & WL_RSPEC_RATE_MASK); ++ } else if (RSPEC_ISHT(rspec)) { ++ uint mcs = (rspec & WL_RSPEC_RATE_MASK); ++ ++ if (mcs == 32) { ++ rate = rate_mcs2rate(mcs, 1, WL_RSPEC_BW_40MHZ, RSPEC_ISSGI(rspec)); ++ } else { ++ uint nss = 1 + (mcs / 8); ++ mcs = mcs % 8; ++ rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); ++ } ++ } else if (RSPEC_ISVHT(rspec)) { ++ uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK); ++ uint nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; ++ ++ ASSERT(mcs <= 9); ++ ASSERT(nss <= 8); ++ ++ rate = rate_mcs2rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec)); ++ } else { ++ ASSERT(0); ++ } ++ ++ return (rate == 0) ? -1 : rate; ++} ++ ++char resp_buf[WLC_IOCTL_SMLEN]; ++ ++static uint64 ++ftm_intvl2nsec(const wl_proxd_intvl_t *intvl) ++{ ++ uint64 ret; ++ ret = intvl->intvl; ++ switch (intvl->tmu) { ++ case WL_PROXD_TMU_TU: ret = FTM_TU2MICRO(ret) * 1000; break; ++ case WL_PROXD_TMU_SEC: ret *= 1000000000; break; ++ case WL_PROXD_TMU_MILLI_SEC: ret *= 1000000; break; ++ case WL_PROXD_TMU_MICRO_SEC: ret *= 1000; break; ++ case WL_PROXD_TMU_PICO_SEC: ret = intvl->intvl / 1000; break; ++ case WL_PROXD_TMU_NANO_SEC: /* fall through */ ++ default: break; ++ } ++ return ret; ++} ++uint64 ++ftm_intvl2usec(const wl_proxd_intvl_t *intvl) ++{ ++ uint64 ret; ++ ret = intvl->intvl; ++ switch (intvl->tmu) { ++ case WL_PROXD_TMU_TU: ret = FTM_TU2MICRO(ret); break; ++ case WL_PROXD_TMU_SEC: ret *= 1000000; break; ++ case WL_PROXD_TMU_NANO_SEC: ret = intvl->intvl / 1000; break; ++ case WL_PROXD_TMU_PICO_SEC: ret = intvl->intvl / 1000000; break; ++ case WL_PROXD_TMU_MILLI_SEC: ret *= 1000; break; ++ case WL_PROXD_TMU_MICRO_SEC: /* fall through */ ++ default: break; ++ } ++ return ret; ++} ++ ++/* ++* lookup 'id' (as a key) from a fw status to host map table ++* if found, return the corresponding reason code ++*/ ++ ++static rtt_reason_t ++ftm_get_statusmap_info(wl_proxd_status_t id, const ftm_status_map_host_entry_t *p_table, ++ uint32 num_entries) ++{ ++ int i; ++ const ftm_status_map_host_entry_t *p_entry; ++ /* scan thru the table till end */ ++ p_entry = p_table; ++ for (i = 0; i < (int) num_entries; i++) ++ { ++ if (p_entry->proxd_status == id) { ++ return p_entry->rtt_reason; ++ } ++ p_entry++; /* next entry */ ++ } ++ return RTT_REASON_FAILURE; /* not found */ ++} ++/* ++* lookup 'id' (as a key) from a table ++* if found, return the entry pointer, otherwise return NULL ++*/ ++static const ftm_strmap_entry_t* ++ftm_get_strmap_info(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries) ++{ ++ int i; ++ const ftm_strmap_entry_t *p_entry; ++ ++ /* scan thru the table till end */ ++ p_entry = p_table; ++ for (i = 0; i < (int) num_entries; i++) ++ { ++ if (p_entry->id == id) ++ return p_entry; ++ p_entry++; /* next entry */ ++ } ++ return NULL; /* not found */ ++} ++ ++/* ++* map enum to a text-string for display, this function is called by the following: ++* For debug/trace: ++* ftm_[cmdid|tlvid]_to_str() ++* For TLV-output log for 'get' commands ++* ftm_[method|tmu|caps|status|state]_value_to_logstr() ++* Input: ++* pTable -- point to a 'enum to string' table. ++*/ ++static const char * ++ftm_map_id_to_str(int32 id, const ftm_strmap_entry_t *p_table, uint32 num_entries) ++{ ++ const ftm_strmap_entry_t*p_entry = ftm_get_strmap_info(id, p_table, num_entries); ++ if (p_entry) ++ return (p_entry->text); ++ ++ return "invalid"; ++} ++ ++ ++#ifdef RTT_DEBUG ++ ++/* define entry, e.g. { WL_PROXD_CMD_xxx, "WL_PROXD_CMD_xxx" } */ ++#define DEF_STRMAP_ENTRY(id) { (id), #id } ++ ++/* ftm cmd-id mapping */ ++static const ftm_strmap_entry_t ftm_cmdid_map[] = { ++ /* {wl_proxd_cmd_t(WL_PROXD_CMD_xxx), "WL_PROXD_CMD_xxx" }, */ ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_NONE), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_VERSION), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_ENABLE), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_DISABLE), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_CONFIG), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_SESSION), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_BURST_REQUEST), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_SESSION), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_DELETE_SESSION), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RESULT), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_INFO), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_STATUS), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_SESSIONS), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_COUNTERS), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_CLEAR_COUNTERS), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_COLLECT), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_TUNE), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_DUMP), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_START_RANGING), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_STOP_RANGING), ++ DEF_STRMAP_ENTRY(WL_PROXD_CMD_GET_RANGING_INFO), ++}; ++ ++/* ++* map a ftm cmd-id to a text-string for display ++*/ ++static const char * ++ftm_cmdid_to_str(uint16 cmdid) ++{ ++ return ftm_map_id_to_str((int32) cmdid, &ftm_cmdid_map[0], ARRAYSIZE(ftm_cmdid_map)); ++} ++#endif /* RTT_DEBUG */ ++ ++ ++/* ++* convert BCME_xxx error codes into related error strings ++* note, bcmerrorstr() defined in bcmutils is for BCMDRIVER only, ++* this duplicate copy is for WL access and may need to clean up later ++*/ ++static const char *ftm_bcmerrorstrtable[] = BCMERRSTRINGTABLE; ++static const char * ++ftm_status_value_to_logstr(wl_proxd_status_t status) ++{ ++ static char ftm_msgbuf_status_undef[32]; ++ const ftm_strmap_entry_t *p_loginfo; ++ int bcmerror; ++ ++ /* check if within BCME_xxx error range */ ++ bcmerror = (int) status; ++ if (VALID_BCMERROR(bcmerror)) ++ return ftm_bcmerrorstrtable[-bcmerror]; ++ ++ /* otherwise, look for 'proxd ftm status' range */ ++ p_loginfo = ftm_get_strmap_info((int32) status, ++ &ftm_status_value_loginfo[0], ARRAYSIZE(ftm_status_value_loginfo)); ++ if (p_loginfo) ++ return p_loginfo->text; ++ ++ /* report for 'out of range' FTM-status error code */ ++ memset(ftm_msgbuf_status_undef, 0, sizeof(ftm_msgbuf_status_undef)); ++ snprintf(ftm_msgbuf_status_undef, sizeof(ftm_msgbuf_status_undef), ++ "Undefined status %d", status); ++ return &ftm_msgbuf_status_undef[0]; ++} ++ ++static const char * ++ftm_tmu_value_to_logstr(wl_proxd_tmu_t tmu) ++{ ++ return ftm_map_id_to_str((int32)tmu, ++ &ftm_tmu_value_loginfo[0], ARRAYSIZE(ftm_tmu_value_loginfo)); ++} ++ ++static const ftm_strmap_entry_t* ++ftm_get_event_type_loginfo(wl_proxd_event_type_t event_type) ++{ ++ /* look up 'event-type' from a predefined table */ ++ return ftm_get_strmap_info((int32) event_type, ++ ftm_event_type_loginfo, ARRAYSIZE(ftm_event_type_loginfo)); ++} ++ ++static const char * ++ftm_session_state_value_to_logstr(wl_proxd_session_state_t state) ++{ ++ return ftm_map_id_to_str((int32)state, &ftm_session_state_value_loginfo[0], ++ ARRAYSIZE(ftm_session_state_value_loginfo)); ++} ++ ++ ++#ifdef WL_CFG80211 ++/* ++* send 'proxd' iovar for all ftm get-related commands ++*/ ++static int ++rtt_do_get_ioctl(dhd_pub_t *dhd, wl_proxd_iov_t *p_proxd_iov, uint16 proxd_iovsize, ++ ftm_subcmd_info_t *p_subcmd_info) ++{ ++ ++ wl_proxd_iov_t *p_iovresp = (wl_proxd_iov_t *)resp_buf; ++ int status; ++ int tlvs_len; ++ /* send getbuf proxd iovar */ ++ status = dhd_getiovar(dhd, 0, "proxd", (char *)p_proxd_iov, ++ proxd_iovsize, (char **)&p_iovresp, WLC_IOCTL_SMLEN); ++ if (status != BCME_OK) { ++ DHD_ERROR(("%s: failed to send getbuf proxd iovar (CMD ID : %d), status=%d\n", ++ __FUNCTION__, p_subcmd_info->cmdid, status)); ++ return status; ++ } ++ if (p_subcmd_info->cmdid == WL_PROXD_CMD_GET_VERSION) { ++ p_subcmd_info->version = ltoh16(p_iovresp->version); ++ DHD_RTT(("ftm version: 0x%x\n", ltoh16(p_iovresp->version))); ++ goto exit; ++ } ++ ++ tlvs_len = ltoh16(p_iovresp->len) - WL_PROXD_IOV_HDR_SIZE; ++ if (tlvs_len < 0) { ++ DHD_ERROR(("%s: alert, p_iovresp->len(%d) should not be smaller than %d\n", ++ __FUNCTION__, ltoh16(p_iovresp->len), (int) WL_PROXD_IOV_HDR_SIZE)); ++ tlvs_len = 0; ++ } ++ ++ if (tlvs_len > 0 && p_subcmd_info->handler) { ++ /* unpack TLVs and invokes the cbfn for processing */ ++ status = bcm_unpack_xtlv_buf(p_proxd_iov, (uint8 *)p_iovresp->tlvs, ++ tlvs_len, BCM_XTLV_OPTION_ALIGN32, p_subcmd_info->handler); ++ } ++exit: ++ return status; ++} ++ ++ ++static wl_proxd_iov_t * ++rtt_alloc_getset_buf(wl_proxd_method_t method, wl_proxd_session_id_t session_id, ++ wl_proxd_cmd_t cmdid, uint16 tlvs_bufsize, uint16 *p_out_bufsize) ++{ ++ uint16 proxd_iovsize; ++ uint16 kflags; ++ wl_proxd_tlv_t *p_tlv; ++ wl_proxd_iov_t *p_proxd_iov = (wl_proxd_iov_t *) NULL; ++ ++ *p_out_bufsize = 0; /* init */ ++ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ /* calculate the whole buffer size, including one reserve-tlv entry in the header */ ++ proxd_iovsize = sizeof(wl_proxd_iov_t) + tlvs_bufsize; ++ ++ p_proxd_iov = kzalloc(proxd_iovsize, kflags); ++ if (p_proxd_iov == NULL) { ++ DHD_ERROR(("error: failed to allocate %d bytes of memory\n", proxd_iovsize)); ++ return NULL; ++ } ++ ++ /* setup proxd-FTM-method iovar header */ ++ p_proxd_iov->version = htol16(WL_PROXD_API_VERSION); ++ p_proxd_iov->len = htol16(proxd_iovsize); /* caller may adjust it based on #of TLVs */ ++ p_proxd_iov->cmd = htol16(cmdid); ++ p_proxd_iov->method = htol16(method); ++ p_proxd_iov->sid = htol16(session_id); ++ ++ /* initialize the reserved/dummy-TLV in iovar header */ ++ p_tlv = p_proxd_iov->tlvs; ++ p_tlv->id = htol16(WL_PROXD_TLV_ID_NONE); ++ p_tlv->len = htol16(0); ++ ++ *p_out_bufsize = proxd_iovsize; /* for caller's reference */ ++ ++ return p_proxd_iov; ++} ++ ++ ++static int ++dhd_rtt_common_get_handler(dhd_pub_t *dhd, ftm_subcmd_info_t *p_subcmd_info, ++ wl_proxd_method_t method, ++ wl_proxd_session_id_t session_id) ++{ ++ int status = BCME_OK; ++ uint16 proxd_iovsize = 0; ++ wl_proxd_iov_t *p_proxd_iov; ++#ifdef RTT_DEBUG ++ DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n", ++ __FUNCTION__, method, session_id, p_subcmd_info->cmdid, ++ ftm_cmdid_to_str(p_subcmd_info->cmdid))); ++#endif ++ /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */ ++ p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid, ++ 0, &proxd_iovsize); ++ ++ if (p_proxd_iov == NULL) ++ return BCME_NOMEM; ++ ++ status = rtt_do_get_ioctl(dhd, p_proxd_iov, proxd_iovsize, p_subcmd_info); ++ ++ if (status != BCME_OK) { ++ DHD_RTT(("%s failed: status=%d\n", __FUNCTION__, status)); ++ } ++ kfree(p_proxd_iov); ++ return status; ++} ++ ++/* ++* common handler for set-related proxd method commands which require no TLV as input ++* wl proxd ftm [session-id] ++* e.g. ++* wl proxd ftm enable -- to enable ftm ++* wl proxd ftm disable -- to disable ftm ++* wl proxd ftm start -- to start a specified session ++* wl proxd ftm stop -- to cancel a specified session; ++* state is maintained till session is delete. ++* wl proxd ftm delete -- to delete a specified session ++* wl proxd ftm [] clear-counters -- to clear counters ++* wl proxd ftm burst-request -- on initiator: to send burst request; ++* on target: send FTM frame ++* wl proxd ftm collect ++* wl proxd ftm tune (TBD) ++*/ ++static int ++dhd_rtt_common_set_handler(dhd_pub_t *dhd, const ftm_subcmd_info_t *p_subcmd_info, ++ wl_proxd_method_t method, wl_proxd_session_id_t session_id) ++{ ++ uint16 proxd_iovsize; ++ wl_proxd_iov_t *p_proxd_iov; ++ int ret; ++ ++#ifdef RTT_DEBUG ++ DHD_RTT(("enter %s: method=%d, session_id=%d, cmdid=%d(%s)\n", ++ __FUNCTION__, method, session_id, p_subcmd_info->cmdid, ++ ftm_cmdid_to_str(p_subcmd_info->cmdid))); ++#endif ++ ++ /* allocate and initialize a temp buffer for 'set proxd' iovar */ ++ proxd_iovsize = 0; ++ p_proxd_iov = rtt_alloc_getset_buf(method, session_id, p_subcmd_info->cmdid, ++ 0, &proxd_iovsize); /* no TLV */ ++ if (p_proxd_iov == NULL) ++ return BCME_NOMEM; ++ ++ /* no TLV to pack, simply issue a set-proxd iovar */ ++ ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, proxd_iovsize, NULL, 0, TRUE); ++#ifdef RTT_DEBUG ++ if (ret != BCME_OK) { ++ DHD_RTT(("error: IOVAR failed, status=%d\n", ret)); ++ } ++#endif ++ /* clean up */ ++ kfree(p_proxd_iov); ++ ++ return ret; ++} ++#endif /* WL_CFG80211 */ ++ ++static int ++rtt_unpack_xtlv_cbfn(void *ctx, uint8 *p_data, uint16 tlvid, uint16 len) ++{ ++ int ret = BCME_OK; ++ int i; ++ wl_proxd_ftm_session_status_t *p_data_info = NULL; ++ wl_proxd_collect_event_data_t *p_collect_data = NULL; ++ uint32 chan_data_entry = 0; ++ ++ switch (tlvid) { ++ case WL_PROXD_TLV_ID_RTT_RESULT: ++ ret = dhd_rtt_convert_results_to_host((rtt_report_t *)ctx, ++ p_data, tlvid, len); ++ break; ++ case WL_PROXD_TLV_ID_SESSION_STATUS: ++ DHD_RTT(("WL_PROXD_TLV_ID_SESSION_STATUS\n")); ++ memcpy(ctx, p_data, sizeof(wl_proxd_ftm_session_status_t)); ++ p_data_info = (wl_proxd_ftm_session_status_t *)ctx; ++ p_data_info->sid = ltoh16_ua(&p_data_info->sid); ++ p_data_info->state = ltoh16_ua(&p_data_info->state); ++ p_data_info->status = ltoh32_ua(&p_data_info->status); ++ p_data_info->burst_num = ltoh16_ua(&p_data_info->burst_num); ++ DHD_RTT(("\tsid=%u, state=%d, status=%d, burst_num=%u\n", ++ p_data_info->sid, p_data_info->state, ++ p_data_info->status, p_data_info->burst_num)); ++ ++ break; ++ case WL_PROXD_TLV_ID_COLLECT_DATA: ++ DHD_RTT(("WL_PROXD_TLV_ID_COLLECT_DATA\n")); ++ memcpy(ctx, p_data, sizeof(wl_proxd_collect_event_data_t)); ++ p_collect_data = (wl_proxd_collect_event_data_t *)ctx; ++ DHD_RTT(("\tH_RX\n")); ++ for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) { ++ p_collect_data->H_RX[i] = ltoh32_ua(&p_collect_data->H_RX[i]); ++ DHD_RTT(("\t%u\n", p_collect_data->H_RX[i])); ++ } ++ DHD_RTT(("\n")); ++ DHD_RTT(("\tH_LB\n")); ++ for (i = 0; i < K_TOF_COLLECT_H_SIZE_20MHZ; i++) { ++ p_collect_data->H_LB[i] = ltoh32_ua(&p_collect_data->H_LB[i]); ++ DHD_RTT(("\t%u\n", p_collect_data->H_LB[i])); ++ } ++ DHD_RTT(("\n")); ++ DHD_RTT(("\tri_rr\n")); ++ for (i = 0; i < FTM_TPK_RI_RR_LEN; i++) { ++ DHD_RTT(("\t%u\n", p_collect_data->ri_rr[i])); ++ } ++ p_collect_data->phy_err_mask = ltoh32_ua(&p_collect_data->phy_err_mask); ++ DHD_RTT(("\tphy_err_mask=0x%x\n", p_collect_data->phy_err_mask)); ++ break; ++ case WL_PROXD_TLV_ID_COLLECT_CHAN_DATA: ++ DHD_RTT(("WL_PROXD_TLV_ID_COLLECT_CHAN_DATA\n")); ++ DHD_RTT(("\tchan est %u\n", (uint32) (len / sizeof(uint32)))); ++ for (i = 0; i < (len/sizeof(chan_data_entry)); i++) { ++ uint32 *p = (uint32*)p_data; ++ chan_data_entry = ltoh32_ua(p + i); ++ DHD_RTT(("\t%u\n", chan_data_entry)); ++ } ++ break; ++ default: ++ DHD_ERROR(("> Unsupported TLV ID %d\n", tlvid)); ++ ret = BCME_ERROR; ++ break; ++ } ++ ++ return ret; ++} ++ ++#ifdef WL_CFG80211 ++static int ++rtt_handle_config_options(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv, ++ uint16 *p_buf_space_left, ftm_config_options_info_t *ftm_configs, int ftm_cfg_cnt) ++{ ++ int ret = BCME_OK; ++ int cfg_idx = 0; ++ uint32 flags = WL_PROXD_FLAG_NONE; ++ uint32 flags_mask = WL_PROXD_FLAG_NONE; ++ uint32 new_mask; /* cmdline input */ ++ ftm_config_options_info_t *p_option_info; ++ uint16 type = (session_id == WL_PROXD_SESSION_ID_GLOBAL) ? ++ WL_PROXD_TLV_ID_FLAGS_MASK : WL_PROXD_TLV_ID_SESSION_FLAGS_MASK; ++ for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) { ++ p_option_info = (ftm_configs + cfg_idx); ++ if (p_option_info != NULL) { ++ new_mask = p_option_info->flags; ++ /* update flags mask */ ++ flags_mask |= new_mask; ++ if (p_option_info->enable) { ++ flags |= new_mask; /* set the bit on */ ++ } else { ++ flags &= ~new_mask; /* set the bit off */ ++ } ++ } ++ } ++ flags = htol32(flags); ++ flags_mask = htol32(flags_mask); ++ /* setup flags_mask TLV */ ++ ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left, ++ type, sizeof(uint32), &flags_mask, BCM_XTLV_OPTION_ALIGN32); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s : bcm_pack_xltv_entry() for mask flags failed, status=%d\n", ++ __FUNCTION__, ret)); ++ goto exit; ++ } ++ ++ type = (session_id == WL_PROXD_SESSION_ID_GLOBAL)? ++ WL_PROXD_TLV_ID_FLAGS : WL_PROXD_TLV_ID_SESSION_FLAGS; ++ /* setup flags TLV */ ++ ret = bcm_pack_xtlv_entry((uint8 **)p_tlv, p_buf_space_left, ++ type, sizeof(uint32), &flags, BCM_XTLV_OPTION_ALIGN32); ++ if (ret != BCME_OK) { ++#ifdef RTT_DEBUG ++ DHD_RTT(("%s: bcm_pack_xltv_entry() for flags failed, status=%d\n", ++ __FUNCTION__, ret)); ++#endif ++ } ++exit: ++ return ret; ++} ++ ++static int ++rtt_handle_config_general(wl_proxd_session_id_t session_id, wl_proxd_tlv_t **p_tlv, ++ uint16 *p_buf_space_left, ftm_config_param_info_t *ftm_configs, int ftm_cfg_cnt) ++{ ++ int ret = BCME_OK; ++ int cfg_idx = 0; ++ uint32 chanspec; ++ ftm_config_param_info_t *p_config_param_info; ++ void *p_src_data; ++ uint16 src_data_size; /* size of data pointed by p_src_data as 'source' */ ++ for (cfg_idx = 0; cfg_idx < ftm_cfg_cnt; cfg_idx++) { ++ p_config_param_info = (ftm_configs + cfg_idx); ++ if (p_config_param_info != NULL) { ++ switch (p_config_param_info->tlvid) { ++ case WL_PROXD_TLV_ID_BSS_INDEX: ++ case WL_PROXD_TLV_ID_FTM_RETRIES: ++ case WL_PROXD_TLV_ID_FTM_REQ_RETRIES: ++ p_src_data = &p_config_param_info->data8; ++ src_data_size = sizeof(uint8); ++ break; ++ case WL_PROXD_TLV_ID_BURST_NUM_FTM: /* uint16 */ ++ case WL_PROXD_TLV_ID_NUM_BURST: ++ case WL_PROXD_TLV_ID_RX_MAX_BURST: ++ p_src_data = &p_config_param_info->data16; ++ src_data_size = sizeof(uint16); ++ break; ++ case WL_PROXD_TLV_ID_TX_POWER: /* uint32 */ ++ case WL_PROXD_TLV_ID_RATESPEC: ++ case WL_PROXD_TLV_ID_EVENT_MASK: /* wl_proxd_event_mask_t/uint32 */ ++ case WL_PROXD_TLV_ID_DEBUG_MASK: ++ p_src_data = &p_config_param_info->data32; ++ src_data_size = sizeof(uint32); ++ break; ++ case WL_PROXD_TLV_ID_CHANSPEC: /* chanspec_t --> 32bit */ ++ chanspec = p_config_param_info->chanspec; ++ p_src_data = (void *) &chanspec; ++ src_data_size = sizeof(uint32); ++ break; ++ case WL_PROXD_TLV_ID_BSSID: /* mac address */ ++ case WL_PROXD_TLV_ID_PEER_MAC: ++ p_src_data = &p_config_param_info->mac_addr; ++ src_data_size = sizeof(struct ether_addr); ++ break; ++ case WL_PROXD_TLV_ID_BURST_DURATION: /* wl_proxd_intvl_t */ ++ case WL_PROXD_TLV_ID_BURST_PERIOD: ++ case WL_PROXD_TLV_ID_BURST_FTM_SEP: ++ case WL_PROXD_TLV_ID_BURST_TIMEOUT: ++ case WL_PROXD_TLV_ID_INIT_DELAY: ++ p_src_data = &p_config_param_info->data_intvl; ++ src_data_size = sizeof(wl_proxd_intvl_t); ++ break; ++ default: ++ ret = BCME_BADARG; ++ break; ++ } ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s bad TLV ID : %d\n", ++ __FUNCTION__, p_config_param_info->tlvid)); ++ break; ++ } ++ ++ ret = bcm_pack_xtlv_entry((uint8 **) p_tlv, p_buf_space_left, ++ p_config_param_info->tlvid, src_data_size, p_src_data, ++ BCM_XTLV_OPTION_ALIGN32); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s: bcm_pack_xltv_entry() failed," ++ " status=%d\n", __FUNCTION__, ret)); ++ break; ++ } ++ ++ } ++ } ++ return ret; ++} ++ ++static int ++dhd_rtt_ftm_enable(dhd_pub_t *dhd, bool enable) ++{ ++ ftm_subcmd_info_t subcmd_info; ++ subcmd_info.name = (enable)? "enable" : "disable"; ++ subcmd_info.cmdid = (enable)? WL_PROXD_CMD_ENABLE: WL_PROXD_CMD_DISABLE; ++ subcmd_info.handler = NULL; ++ return dhd_rtt_common_set_handler(dhd, &subcmd_info, ++ WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); ++} ++ ++static int ++dhd_rtt_start_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, bool start) ++{ ++ ftm_subcmd_info_t subcmd_info; ++ subcmd_info.name = (start)? "start session" : "stop session"; ++ subcmd_info.cmdid = (start)? WL_PROXD_CMD_START_SESSION: WL_PROXD_CMD_STOP_SESSION; ++ subcmd_info.handler = NULL; ++ return dhd_rtt_common_set_handler(dhd, &subcmd_info, ++ WL_PROXD_METHOD_FTM, session_id); ++} ++ ++static int ++dhd_rtt_delete_session(dhd_pub_t *dhd, wl_proxd_session_id_t session_id) ++{ ++ ftm_subcmd_info_t subcmd_info; ++ subcmd_info.name = "delete session"; ++ subcmd_info.cmdid = WL_PROXD_CMD_DELETE_SESSION; ++ subcmd_info.handler = NULL; ++ return dhd_rtt_common_set_handler(dhd, &subcmd_info, ++ WL_PROXD_METHOD_FTM, session_id); ++} ++ ++static int ++dhd_rtt_ftm_config(dhd_pub_t *dhd, wl_proxd_session_id_t session_id, ++ ftm_config_category_t catagory, void *ftm_configs, int ftm_cfg_cnt) ++{ ++ ftm_subcmd_info_t subcmd_info; ++ wl_proxd_tlv_t *p_tlv; ++ /* alloc mem for ioctl headr + reserved 0 bufsize for tlvs (initialize to zero) */ ++ wl_proxd_iov_t *p_proxd_iov; ++ uint16 proxd_iovsize = 0; ++ uint16 bufsize; ++ uint16 buf_space_left; ++ uint16 all_tlvsize; ++ int ret = BCME_OK; ++ ++ subcmd_info.name = "config"; ++ subcmd_info.cmdid = WL_PROXD_CMD_CONFIG; ++ ++ p_proxd_iov = rtt_alloc_getset_buf(WL_PROXD_METHOD_FTM, session_id, subcmd_info.cmdid, ++ FTM_IOC_BUFSZ, &proxd_iovsize); ++ ++ if (p_proxd_iov == NULL) { ++ DHD_ERROR(("%s : failed to allocate the iovar (size :%d)\n", ++ __FUNCTION__, FTM_IOC_BUFSZ)); ++ return BCME_NOMEM; ++ } ++ /* setup TLVs */ ++ bufsize = proxd_iovsize - WL_PROXD_IOV_HDR_SIZE; /* adjust available size for TLVs */ ++ p_tlv = &p_proxd_iov->tlvs[0]; ++ /* TLV buffer starts with a full size, will decrement for each packed TLV */ ++ buf_space_left = bufsize; ++ if (catagory == FTM_CONFIG_CAT_OPTIONS) { ++ ret = rtt_handle_config_options(session_id, &p_tlv, &buf_space_left, ++ (ftm_config_options_info_t *)ftm_configs, ftm_cfg_cnt); ++ } else if (catagory == FTM_CONFIG_CAT_GENERAL) { ++ ret = rtt_handle_config_general(session_id, &p_tlv, &buf_space_left, ++ (ftm_config_param_info_t *)ftm_configs, ftm_cfg_cnt); ++ } ++ if (ret == BCME_OK) { ++ /* update the iov header, set len to include all TLVs + header */ ++ all_tlvsize = (bufsize - buf_space_left); ++ p_proxd_iov->len = htol16(all_tlvsize + WL_PROXD_IOV_HDR_SIZE); ++ ret = dhd_iovar(dhd, 0, "proxd", (char *)p_proxd_iov, ++ all_tlvsize + WL_PROXD_IOV_HDR_SIZE, NULL, 0, TRUE); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s : failed to set config\n", __FUNCTION__)); ++ } ++ } ++ /* clean up */ ++ kfree(p_proxd_iov); ++ return ret; ++} ++ ++static int ++dhd_rtt_get_version(dhd_pub_t *dhd, int *out_version) ++{ ++ int ret; ++ ftm_subcmd_info_t subcmd_info; ++ subcmd_info.name = "ver"; ++ subcmd_info.cmdid = WL_PROXD_CMD_GET_VERSION; ++ subcmd_info.handler = NULL; ++ ret = dhd_rtt_common_get_handler(dhd, &subcmd_info, ++ WL_PROXD_METHOD_FTM, WL_PROXD_SESSION_ID_GLOBAL); ++ *out_version = (ret == BCME_OK) ? subcmd_info.version : 0; ++ return ret; ++} ++#endif /* WL_CFG80211 */ ++ ++chanspec_t ++dhd_rtt_convert_to_chspec(wifi_channel_info_t channel) ++{ ++ int bw; ++ chanspec_t chanspec = 0; ++ uint8 center_chan; ++ uint8 primary_chan; ++ /* set witdh to 20MHZ for 2.4G HZ */ ++ if (channel.center_freq >= 2400 && channel.center_freq <= 2500) { ++ channel.width = WIFI_CHAN_WIDTH_20; ++ } ++ switch (channel.width) { ++ case WIFI_CHAN_WIDTH_20: ++ bw = WL_CHANSPEC_BW_20; ++ primary_chan = wf_mhz2channel(channel.center_freq, 0); ++ chanspec = wf_channel2chspec(primary_chan, bw); ++ break; ++ case WIFI_CHAN_WIDTH_40: ++ bw = WL_CHANSPEC_BW_40; ++ primary_chan = wf_mhz2channel(channel.center_freq, 0); ++ chanspec = wf_channel2chspec(primary_chan, bw); ++ break; ++ case WIFI_CHAN_WIDTH_80: ++ bw = WL_CHANSPEC_BW_80; ++ primary_chan = wf_mhz2channel(channel.center_freq, 0); ++ center_chan = wf_mhz2channel(channel.center_freq0, 0); ++ chanspec = wf_chspec_80(center_chan, primary_chan); ++ break; ++ default: ++ DHD_ERROR(("doesn't support this bandwith : %d", channel.width)); ++ bw = -1; ++ break; ++ } ++ return chanspec; ++} ++ ++int ++dhd_rtt_idx_to_burst_duration(uint idx) ++{ ++ if (idx >= ARRAY_SIZE(burst_duration_idx)) { ++ return -1; ++ } ++ return burst_duration_idx[idx]; ++} ++ ++int ++dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params) ++{ ++ int err = BCME_OK; ++ int idx; ++ rtt_status_info_t *rtt_status; ++ NULL_CHECK(params, "params is NULL", err); ++ ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ rtt_status = GET_RTTSTATE(dhd); ++ NULL_CHECK(rtt_status, "rtt_status is NULL", err); ++ if (!HAS_11MC_CAP(rtt_status->rtt_capa.proto)) { ++ DHD_ERROR(("doesn't support RTT \n")); ++ return BCME_ERROR; ++ } ++ if (rtt_status->status != RTT_STOPPED) { ++ DHD_ERROR(("rtt is already started\n")); ++ return BCME_BUSY; ++ } ++ DHD_RTT(("%s enter\n", __FUNCTION__)); ++ ++ memset(rtt_status->rtt_config.target_info, 0, TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); ++ rtt_status->rtt_config.rtt_target_cnt = params->rtt_target_cnt; ++ memcpy(rtt_status->rtt_config.target_info, ++ params->target_info, TARGET_INFO_SIZE(params->rtt_target_cnt)); ++ rtt_status->status = RTT_STARTED; ++ /* start to measure RTT from first device */ ++ /* find next target to trigger RTT */ ++ for (idx = rtt_status->cur_idx; idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { ++ /* skip the disabled device */ ++ if (rtt_status->rtt_config.target_info[idx].disable) { ++ continue; ++ } else { ++ /* set the idx to cur_idx */ ++ rtt_status->cur_idx = idx; ++ break; ++ } ++ } ++ if (idx < rtt_status->rtt_config.rtt_target_cnt) { ++ DHD_RTT(("rtt_status->cur_idx : %d\n", rtt_status->cur_idx)); ++ schedule_work(&rtt_status->work); ++ } ++ return err; ++} ++ ++int ++dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt) ++{ ++ int err = BCME_OK; ++#ifdef WL_CFG8011 ++ int i = 0, j = 0; ++ rtt_status_info_t *rtt_status; ++ rtt_results_header_t *entry, *next; ++ rtt_result_t *rtt_result, *next2; ++ struct rtt_noti_callback *iter; ++ ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ rtt_status = GET_RTTSTATE(dhd); ++ NULL_CHECK(rtt_status, "rtt_status is NULL", err); ++ if (rtt_status->status == RTT_STOPPED) { ++ DHD_ERROR(("rtt is not started\n")); ++ return BCME_OK; ++ } ++ DHD_RTT(("%s enter\n", __FUNCTION__)); ++ mutex_lock(&rtt_status->rtt_mutex); ++ for (i = 0; i < mac_cnt; i++) { ++ for (j = 0; j < rtt_status->rtt_config.rtt_target_cnt; j++) { ++ if (!bcmp(&mac_list[i], &rtt_status->rtt_config.target_info[j].addr, ++ ETHER_ADDR_LEN)) { ++ rtt_status->rtt_config.target_info[j].disable = TRUE; ++ } ++ } ++ } ++ if (rtt_status->all_cancel) { ++ /* cancel all of request */ ++ rtt_status->status = RTT_STOPPED; ++ DHD_RTT(("current RTT process is cancelled\n")); ++ /* remove the rtt results in cache */ ++ if (!list_empty(&rtt_status->rtt_results_cache)) { ++ /* Iterate rtt_results_header list */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry_safe(entry, next, ++ &rtt_status->rtt_results_cache, list) { ++ list_del(&entry->list); ++ /* Iterate rtt_result list */ ++ list_for_each_entry_safe(rtt_result, next2, ++ &entry->result_list, list) { ++ list_del(&rtt_result->list); ++ kfree(rtt_result); ++ } ++ kfree(entry); ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ } ++ /* send the rtt complete event to wake up the user process */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { ++ iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache); ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ /* reinitialize the HEAD */ ++ INIT_LIST_HEAD(&rtt_status->rtt_results_cache); ++ /* clear information for rtt_config */ ++ rtt_status->rtt_config.rtt_target_cnt = 0; ++ memset(rtt_status->rtt_config.target_info, 0, ++ TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); ++ rtt_status->cur_idx = 0; ++ dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION); ++ dhd_rtt_ftm_enable(dhd, FALSE); ++ } ++ mutex_unlock(&rtt_status->rtt_mutex); ++#endif /* WL_CFG80211 */ ++ return err; ++} ++ ++ ++#ifdef WL_CFG80211 ++static int ++dhd_rtt_start(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ char eabuf[ETHER_ADDR_STR_LEN]; ++ char chanbuf[CHANSPEC_STR_LEN]; ++ int ftm_cfg_cnt = 0; ++ int ftm_param_cnt = 0; ++ uint32 rspec = 0; ++ ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS]; ++ ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS]; ++ rtt_target_info_t *rtt_target; ++ rtt_status_info_t *rtt_status; ++ int pm = PM_OFF; ++ struct net_device *dev = dhd_linux_get_primary_netdev(dhd); ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ ++ rtt_status = GET_RTTSTATE(dhd); ++ NULL_CHECK(rtt_status, "rtt_status is NULL", err); ++ ++ DHD_RTT(("Enter %s\n", __FUNCTION__)); ++ if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) { ++ err = BCME_RANGE; ++ DHD_RTT(("%s : idx %d is out of range\n", __FUNCTION__, rtt_status->cur_idx)); ++ if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) { ++ DHD_ERROR(("STA is set as Target/Responder \n")); ++ return BCME_ERROR; ++ } ++ goto exit; ++ } ++ if (RTT_IS_STOPPED(rtt_status)) { ++ DHD_RTT(("RTT is stopped\n")); ++ goto exit; ++ } ++ err = wldev_ioctl_get(dev, WLC_GET_PM, &rtt_status->pm, sizeof(rtt_status->pm)); ++ if (err) { ++ DHD_ERROR(("Failed to get the PM value\n")); ++ } else { ++ err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm)); ++ if (err) { ++ DHD_ERROR(("Failed to set the PM\n")); ++ rtt_status->pm_restore = FALSE; ++ } else { ++ rtt_status->pm_restore = TRUE; ++ } ++ } ++ ++ mutex_lock(&rtt_status->rtt_mutex); ++ /* Get a target information */ ++ rtt_target = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; ++ mutex_unlock(&rtt_status->rtt_mutex); ++ DHD_RTT(("%s enter\n", __FUNCTION__)); ++ if (!RTT_IS_ENABLED(rtt_status)) { ++ /* enable ftm */ ++ err = dhd_rtt_ftm_enable(dhd, TRUE); ++ if (err) { ++ DHD_ERROR(("failed to enable FTM (%d)\n", err)); ++ goto exit; ++ } ++ } ++ ++ /* delete session of index default sesession */ ++ err = dhd_rtt_delete_session(dhd, FTM_DEFAULT_SESSION); ++ if (err < 0 && err != BCME_NOTFOUND) { ++ DHD_ERROR(("failed to delete session of FTM (%d)\n", err)); ++ goto exit; ++ } ++ rtt_status->status = RTT_ENABLED; ++ memset(ftm_configs, 0, sizeof(ftm_configs)); ++ memset(ftm_params, 0, sizeof(ftm_params)); ++ ++ /* configure the session 1 as initiator */ ++ ftm_configs[ftm_cfg_cnt].enable = TRUE; ++ ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_INITIATOR; ++ dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS, ++ ftm_configs, ftm_cfg_cnt); ++ /* target's mac address */ ++ if (!ETHER_ISNULLADDR(rtt_target->addr.octet)) { ++ ftm_params[ftm_param_cnt].mac_addr = rtt_target->addr; ++ ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_PEER_MAC; ++ bcm_ether_ntoa(&rtt_target->addr, eabuf); ++ DHD_RTT((">\t target %s\n", eabuf)); ++ } ++ /* target's chanspec */ ++ if (rtt_target->chanspec) { ++ ftm_params[ftm_param_cnt].chanspec = htol32((uint32)rtt_target->chanspec); ++ ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_CHANSPEC; ++ wf_chspec_ntoa(rtt_target->chanspec, chanbuf); ++ DHD_RTT((">\t chanspec : %s\n", chanbuf)); ++ } ++ /* num-burst */ ++ if (rtt_target->num_burst) { ++ ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_burst); ++ ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_NUM_BURST; ++ DHD_RTT((">\t num of burst : %d\n", rtt_target->num_burst)); ++ } ++ /* number of frame per burst */ ++ if (rtt_target->num_frames_per_burst == 0) { ++ rtt_target->num_frames_per_burst = ++ CHSPEC_IS20(rtt_target->chanspec) ? FTM_DEFAULT_CNT_20M : ++ CHSPEC_IS40(rtt_target->chanspec) ? FTM_DEFAULT_CNT_40M : ++ FTM_DEFAULT_CNT_80M; ++ } ++ ftm_params[ftm_param_cnt].data16 = htol16(rtt_target->num_frames_per_burst); ++ ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_NUM_FTM; ++ DHD_RTT((">\t number of frame per burst : %d\n", rtt_target->num_frames_per_burst)); ++ /* FTM retry count */ ++ if (rtt_target->num_retries_per_ftm) { ++ ftm_params[ftm_param_cnt].data8 = rtt_target->num_retries_per_ftm; ++ ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_RETRIES; ++ DHD_RTT((">\t retry count of FTM : %d\n", rtt_target->num_retries_per_ftm)); ++ } ++ /* FTM Request retry count */ ++ if (rtt_target->num_retries_per_ftmr) { ++ ftm_params[ftm_param_cnt].data8 = rtt_target->num_retries_per_ftmr; ++ ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_FTM_REQ_RETRIES; ++ DHD_RTT((">\t retry count of FTM Req : %d\n", rtt_target->num_retries_per_ftmr)); ++ } ++ /* burst-period */ ++ if (rtt_target->burst_period) { ++ ftm_params[ftm_param_cnt].data_intvl.intvl = ++ htol32(rtt_target->burst_period); /* ms */ ++ ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC; ++ ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_PERIOD; ++ DHD_RTT((">\t burst period : %d ms\n", rtt_target->burst_period)); ++ } ++ /* burst-duration */ ++ if (rtt_target->burst_duration) { ++ ftm_params[ftm_param_cnt].data_intvl.intvl = ++ htol32(rtt_target->burst_duration); /* ms */ ++ ftm_params[ftm_param_cnt].data_intvl.tmu = WL_PROXD_TMU_MILLI_SEC; ++ ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_BURST_DURATION; ++ DHD_RTT((">\t burst duration : %d ms\n", ++ rtt_target->burst_duration)); ++ } ++ if (rtt_target->bw && rtt_target->preamble) { ++ bool use_default = FALSE; ++ int nss; ++ int mcs; ++ switch (rtt_target->preamble) { ++ case RTT_PREAMBLE_LEGACY: ++ rspec |= WL_RSPEC_ENCODE_RATE; /* 11abg */ ++ rspec |= WL_RATE_6M; ++ break; ++ case RTT_PREAMBLE_HT: ++ rspec |= WL_RSPEC_ENCODE_HT; /* 11n HT */ ++ mcs = 0; /* default MCS 0 */ ++ rspec |= mcs; ++ break; ++ case RTT_PREAMBLE_VHT: ++ rspec |= WL_RSPEC_ENCODE_VHT; /* 11ac VHT */ ++ mcs = 0; /* default MCS 0 */ ++ nss = 1; /* default Nss = 1 */ ++ rspec |= (nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs; ++ break; ++ default: ++ DHD_RTT(("doesn't support this preamble : %d\n", rtt_target->preamble)); ++ use_default = TRUE; ++ break; ++ } ++ switch (rtt_target->bw) { ++ case RTT_BW_20: ++ rspec |= WL_RSPEC_BW_20MHZ; ++ break; ++ case RTT_BW_40: ++ rspec |= WL_RSPEC_BW_40MHZ; ++ break; ++ case RTT_BW_80: ++ rspec |= WL_RSPEC_BW_80MHZ; ++ break; ++ default: ++ DHD_RTT(("doesn't support this BW : %d\n", rtt_target->bw)); ++ use_default = TRUE; ++ break; ++ } ++ if (!use_default) { ++ ftm_params[ftm_param_cnt].data32 = htol32(rspec); ++ ftm_params[ftm_param_cnt++].tlvid = WL_PROXD_TLV_ID_RATESPEC; ++ DHD_RTT((">\t ratespec : %d\n", rspec)); ++ } ++ ++ } ++ dhd_set_rand_mac_oui(dhd); ++ dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_GENERAL, ++ ftm_params, ftm_param_cnt); ++ ++ err = dhd_rtt_start_session(dhd, FTM_DEFAULT_SESSION, TRUE); ++ if (err) { ++ DHD_ERROR(("failed to start session of FTM : error %d\n", err)); ++ } ++exit: ++ if (err) { ++ DHD_ERROR(("rtt is stopped %s \n", __FUNCTION__)); ++ rtt_status->status = RTT_STOPPED; ++ /* disable FTM */ ++ dhd_rtt_ftm_enable(dhd, FALSE); ++ if (rtt_status->pm_restore) { ++ DHD_ERROR(("pm_restore =%d func =%s \n", ++ rtt_status->pm_restore, __FUNCTION__)); ++ pm = PM_FAST; ++ err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm)); ++ if (err) { ++ DHD_ERROR(("Failed to set PM \n")); ++ } else { ++ rtt_status->pm_restore = FALSE; ++ } ++ } ++ } ++ return err; ++} ++#endif /* WL_CFG80211 */ ++ ++int ++dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn) ++{ ++ int err = BCME_OK; ++ struct rtt_noti_callback *cb = NULL, *iter; ++ rtt_status_info_t *rtt_status; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(noti_fn, "noti_fn is NULL", err); ++ ++ rtt_status = GET_RTTSTATE(dhd); ++ NULL_CHECK(rtt_status, "rtt_status is NULL", err); ++ spin_lock_bh(¬i_list_lock); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { ++ if (iter->noti_fn == noti_fn) { ++ goto exit; ++ } ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ cb = kmalloc(sizeof(struct rtt_noti_callback), GFP_ATOMIC); ++ if (!cb) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ cb->noti_fn = noti_fn; ++ cb->ctx = ctx; ++ list_add(&cb->list, &rtt_status->noti_fn_list); ++exit: ++ spin_unlock_bh(¬i_list_lock); ++ return err; ++} ++ ++int ++dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn) ++{ ++ int err = BCME_OK; ++ struct rtt_noti_callback *cb = NULL, *iter; ++ rtt_status_info_t *rtt_status; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ NULL_CHECK(noti_fn, "noti_fn is NULL", err); ++ rtt_status = GET_RTTSTATE(dhd); ++ NULL_CHECK(rtt_status, "rtt_status is NULL", err); ++ spin_lock_bh(¬i_list_lock); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { ++ if (iter->noti_fn == noti_fn) { ++ cb = iter; ++ list_del(&cb->list); ++ break; ++ } ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ ++ spin_unlock_bh(¬i_list_lock); ++ if (cb) { ++ kfree(cb); ++ } ++ return err; ++} ++ ++static wifi_rate_t ++dhd_rtt_convert_rate_to_host(uint32 rspec) ++{ ++ wifi_rate_t host_rate; ++ memset(&host_rate, 0, sizeof(wifi_rate_t)); ++ if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE) { ++ host_rate.preamble = 0; ++ } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT) { ++ host_rate.preamble = 2; ++ host_rate.rateMcsIdx = rspec & WL_RSPEC_RATE_MASK; ++ } else if ((rspec & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT) { ++ host_rate.preamble = 3; ++ host_rate.rateMcsIdx = rspec & WL_RSPEC_VHT_MCS_MASK; ++ host_rate.nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT; ++ } ++ host_rate.bw = (rspec & WL_RSPEC_BW_MASK) - 1; ++ host_rate.bitrate = rate_rspec2rate(rspec) / 100; /* 100kbps */ ++ DHD_RTT(("bit rate : %d\n", host_rate.bitrate)); ++ return host_rate; ++} ++ ++ ++static int ++dhd_rtt_convert_results_to_host(rtt_report_t *rtt_report, uint8 *p_data, uint16 tlvid, uint16 len) ++{ ++ int err = BCME_OK; ++ char eabuf[ETHER_ADDR_STR_LEN]; ++ wl_proxd_rtt_result_t *p_data_info; ++ wl_proxd_result_flags_t flags; ++ wl_proxd_session_state_t session_state; ++ wl_proxd_status_t proxd_status; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ struct osl_timespec ts; ++#endif /* LINUX_VER >= 2.6.39 */ ++ uint32 ratespec; ++ uint32 avg_dist; ++ wl_proxd_rtt_sample_t *p_sample; ++ wl_proxd_intvl_t rtt; ++ wl_proxd_intvl_t p_time; ++ ++ NULL_CHECK(rtt_report, "rtt_report is NULL", err); ++ NULL_CHECK(p_data, "p_data is NULL", err); ++ DHD_RTT(("%s enter\n", __FUNCTION__)); ++ p_data_info = (wl_proxd_rtt_result_t *) p_data; ++ /* unpack and format 'flags' for display */ ++ flags = ltoh16_ua(&p_data_info->flags); ++ ++ /* session state and status */ ++ session_state = ltoh16_ua(&p_data_info->state); ++ proxd_status = ltoh32_ua(&p_data_info->status); ++ bcm_ether_ntoa((&(p_data_info->peer)), eabuf); ++ ftm_session_state_value_to_logstr(session_state); ++ ftm_status_value_to_logstr(proxd_status); ++ DHD_RTT((">\tTarget(%s) session state=%d(%s), status=%d(%s)\n", ++ eabuf, ++ session_state, ++ ftm_session_state_value_to_logstr(session_state), ++ proxd_status, ++ ftm_status_value_to_logstr(proxd_status))); ++ ++ /* show avg_dist (1/256m units), burst_num */ ++ avg_dist = ltoh32_ua(&p_data_info->avg_dist); ++ if (avg_dist == 0xffffffff) { /* report 'failure' case */ ++ DHD_RTT((">\tavg_dist=-1m, burst_num=%d, valid_measure_cnt=%d\n", ++ ltoh16_ua(&p_data_info->burst_num), ++ p_data_info->num_valid_rtt)); /* in a session */ ++ avg_dist = FTM_INVALID; ++ } ++ else { ++ DHD_RTT((">\tavg_dist=%d.%04dm, burst_num=%d, valid_measure_cnt=%d num_ftm=%d\n", ++ avg_dist >> 8, /* 1/256m units */ ++ ((avg_dist & 0xff) * 625) >> 4, ++ ltoh16_ua(&p_data_info->burst_num), ++ p_data_info->num_valid_rtt, ++ p_data_info->num_ftm)); /* in a session */ ++ } ++ /* show 'avg_rtt' sample */ ++ p_sample = &p_data_info->avg_rtt; ++ ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)); ++ DHD_RTT((">\tavg_rtt sample: rssi=%d rtt=%d%s std_deviation =%d.%d ratespec=0x%08x\n", ++ (int16) ltoh16_ua(&p_sample->rssi), ++ ltoh32_ua(&p_sample->rtt.intvl), ++ ftm_tmu_value_to_logstr(ltoh16_ua(&p_sample->rtt.tmu)), ++ ltoh16_ua(&p_data_info->sd_rtt)/10, ltoh16_ua(&p_data_info->sd_rtt)%10, ++ ltoh32_ua(&p_sample->ratespec))); ++ ++ /* set peer address */ ++ rtt_report->addr = p_data_info->peer; ++ /* burst num */ ++ rtt_report->burst_num = ltoh16_ua(&p_data_info->burst_num); ++ /* success num */ ++ rtt_report->success_num = p_data_info->num_valid_rtt; ++ /* actual number of FTM supported by peer */ ++ rtt_report->num_per_burst_peer = p_data_info->num_ftm; ++ rtt_report->negotiated_burst_num = p_data_info->num_ftm; ++ /* status */ ++ rtt_report->status = ftm_get_statusmap_info(proxd_status, ++ &ftm_status_map_info[0], ARRAYSIZE(ftm_status_map_info)); ++ ++ /* rssi (0.5db) */ ++ rtt_report->rssi = ABS((wl_proxd_rssi_t)ltoh16_ua(&p_data_info->avg_rtt.rssi)) * 2; ++ ++ /* rx rate */ ++ ratespec = ltoh32_ua(&p_data_info->avg_rtt.ratespec); ++ rtt_report->rx_rate = dhd_rtt_convert_rate_to_host(ratespec); ++ /* tx rate */ ++ if (flags & WL_PROXD_RESULT_FLAG_VHTACK) { ++ rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0x2010010); ++ } else { ++ rtt_report->tx_rate = dhd_rtt_convert_rate_to_host(0xc); ++ } ++ /* rtt_sd */ ++ rtt.tmu = ltoh16_ua(&p_data_info->avg_rtt.rtt.tmu); ++ rtt.intvl = ltoh32_ua(&p_data_info->avg_rtt.rtt.intvl); ++ rtt_report->rtt = (wifi_timespan)FTM_INTVL2NSEC(&rtt) * 1000; /* nano -> pico seconds */ ++ rtt_report->rtt_sd = ltoh16_ua(&p_data_info->sd_rtt); /* nano -> 0.1 nano */ ++ DHD_RTT(("rtt_report->rtt : %llu\n", rtt_report->rtt)); ++ DHD_RTT(("rtt_report->rssi : %d (0.5db)\n", rtt_report->rssi)); ++ ++ /* average distance */ ++ if (avg_dist != FTM_INVALID) { ++ rtt_report->distance = (avg_dist >> 8) * 1000; /* meter -> mm */ ++ rtt_report->distance += (avg_dist & 0xff) * 1000 / 256; ++ } else { ++ rtt_report->distance = FTM_INVALID; ++ } ++ /* time stamp */ ++ /* get the time elapsed from boot time */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ osl_get_monotonic_boottime(&ts); ++ rtt_report->ts = (uint64)TIMESPEC_TO_US(ts); ++#endif /* LINUX_VER >= 2.6.39 */ ++ ++ if (proxd_status == WL_PROXD_E_REMOTE_FAIL) { ++ /* retry time after failure */ ++ p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); ++ p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); ++ rtt_report->retry_after_duration = FTM_INTVL2SEC(&p_time); /* s -> s */ ++ DHD_RTT((">\tretry_after: %d%s\n", ++ ltoh32_ua(&p_data_info->u.retry_after.intvl), ++ ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.retry_after.tmu)))); ++ } else { ++ /* burst duration */ ++ p_time.intvl = ltoh32_ua(&p_data_info->u.retry_after.intvl); ++ p_time.tmu = ltoh16_ua(&p_data_info->u.retry_after.tmu); ++ rtt_report->burst_duration = FTM_INTVL2MSEC(&p_time); /* s -> ms */ ++ DHD_RTT((">\tburst_duration: %d%s\n", ++ ltoh32_ua(&p_data_info->u.burst_duration.intvl), ++ ftm_tmu_value_to_logstr(ltoh16_ua(&p_data_info->u.burst_duration.tmu)))); ++ DHD_RTT(("rtt_report->burst_duration : %d\n", rtt_report->burst_duration)); ++ } ++ return err; ++} ++ ++int ++dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) ++{ ++ int ret = BCME_OK; ++ int tlvs_len; ++ uint16 version; ++ wl_proxd_event_t *p_event; ++ wl_proxd_event_type_t event_type; ++ wl_proxd_ftm_session_status_t session_status; ++ wl_proxd_collect_event_data_t *collect_event_data; ++ const ftm_strmap_entry_t *p_loginfo; ++ rtt_result_t *rtt_result; ++ gfp_t kflags; ++#ifdef WL_CFG80211 ++ int idx; ++ struct rtt_noti_callback *iter; ++ bool is_new = TRUE; ++ rtt_status_info_t *rtt_status; ++ rtt_result_t *next2; ++ rtt_results_header_t *next = NULL; ++ rtt_target_info_t *rtt_target_info; ++ rtt_results_header_t *entry, *rtt_results_header = NULL; ++#endif /* WL_CFG80211 */ ++ ++ DHD_RTT(("Enter %s \n", __FUNCTION__)); ++ NULL_CHECK(dhd, "dhd is NULL", ret); ++ ++#ifdef WL_CFG80211 ++ rtt_status = GET_RTTSTATE(dhd); ++ NULL_CHECK(rtt_status, "rtt_status is NULL", ret); ++ ++ if (RTT_IS_STOPPED(rtt_status)) { ++ /* Ignore the Proxd event */ ++ DHD_RTT((" event handler rtt is stopped \n")); ++ if (rtt_status->flags == WL_PROXD_SESSION_FLAG_TARGET) { ++ DHD_RTT(("Device is target/Responder. Recv the event. \n")); ++ } else { ++ return ret; ++ } ++ } ++#endif /* WL_CFG80211 */ ++ if (ntoh32_ua((void *)&event->datalen) < OFFSETOF(wl_proxd_event_t, tlvs)) { ++ DHD_RTT(("%s: wrong datalen:%d\n", __FUNCTION__, ++ ntoh32_ua((void *)&event->datalen))); ++ return -EINVAL; ++ } ++ event_type = ntoh32_ua((void *)&event->event_type); ++ if (event_type != WLC_E_PROXD) { ++ DHD_ERROR((" failed event \n")); ++ return -EINVAL; ++ } ++ ++ if (!event_data) { ++ DHD_ERROR(("%s: event_data:NULL\n", __FUNCTION__)); ++ return -EINVAL; ++ } ++ p_event = (wl_proxd_event_t *) event_data; ++ version = ltoh16(p_event->version); ++ if (version < WL_PROXD_API_VERSION) { ++ DHD_ERROR(("ignore non-ftm event version = 0x%0x < WL_PROXD_API_VERSION (0x%x)\n", ++ version, WL_PROXD_API_VERSION)); ++ return ret; ++ } ++#ifdef WL_CFG80211 ++ if (!in_atomic()) { ++ mutex_lock(&rtt_status->rtt_mutex); ++ } ++#endif /* WL_CFG80211 */ ++ event_type = (wl_proxd_event_type_t) ltoh16(p_event->type); ++ ++ kflags = in_softirq()? GFP_ATOMIC : GFP_KERNEL; ++ ++ DHD_RTT(("event_type=0x%x, ntoh16()=0x%x, ltoh16()=0x%x\n", ++ p_event->type, ntoh16(p_event->type), ltoh16(p_event->type))); ++ p_loginfo = ftm_get_event_type_loginfo(event_type); ++ if (p_loginfo == NULL) { ++ DHD_ERROR(("receive an invalid FTM event %d\n", event_type)); ++ ret = -EINVAL; ++ goto exit; /* ignore this event */ ++ } ++ /* get TLVs len, skip over event header */ ++ if (ltoh16(p_event->len) < OFFSETOF(wl_proxd_event_t, tlvs)) { ++ DHD_ERROR(("invalid FTM event length:%d\n", ltoh16(p_event->len))); ++ ret = -EINVAL; ++ goto exit; ++ } ++ tlvs_len = ltoh16(p_event->len) - OFFSETOF(wl_proxd_event_t, tlvs); ++ DHD_RTT(("receive '%s' event: version=0x%x len=%d method=%d sid=%d tlvs_len=%d\n", ++ p_loginfo->text, ++ version, ++ ltoh16(p_event->len), ++ ltoh16(p_event->method), ++ ltoh16(p_event->sid), ++ tlvs_len)); ++#ifdef WL_CFG80211 ++ rtt_target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx]; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ /* find a rtt_report_header for this mac address */ ++ list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) { ++ if (!memcmp(&entry->peer_mac, &event->addr, ETHER_ADDR_LEN)) { ++ /* found a rtt_report_header for peer_mac in the list */ ++ is_new = FALSE; ++ rtt_results_header = entry; ++ break; ++ } ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++#endif /* WL_CFG80211 */ ++ switch (event_type) { ++ case WL_PROXD_EVENT_SESSION_CREATE: ++ DHD_RTT(("WL_PROXD_EVENT_SESSION_CREATE\n")); ++ break; ++ case WL_PROXD_EVENT_SESSION_START: ++ DHD_RTT(("WL_PROXD_EVENT_SESSION_START\n")); ++ break; ++ case WL_PROXD_EVENT_BURST_START: ++ DHD_RTT(("WL_PROXD_EVENT_BURST_START\n")); ++ break; ++ case WL_PROXD_EVENT_BURST_END: ++ DHD_RTT(("WL_PROXD_EVENT_BURST_END\n")); ++#ifdef WL_CFG80211 ++ if (is_new) { ++ /* allocate new header for rtt_results */ ++ rtt_results_header = kzalloc(sizeof(rtt_results_header_t), kflags); ++ if (!rtt_results_header) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ /* Initialize the head of list for rtt result */ ++ INIT_LIST_HEAD(&rtt_results_header->result_list); ++ rtt_results_header->peer_mac = event->addr; ++ list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache); ++ } ++#endif /* WL_CFG80211 */ ++ if (tlvs_len > 0) { ++ /* allocate rtt_results for new results */ ++ rtt_result = kzalloc(sizeof(rtt_result_t), kflags); ++ if (!rtt_result) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ /* unpack TLVs and invokes the cbfn to print the event content TLVs */ ++ ret = bcm_unpack_xtlv_buf((void *) &(rtt_result->report), ++ (uint8 *)&p_event->tlvs[0], tlvs_len, ++ BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++#ifdef WL_CFG80211 ++ /* fill out the results from the configuration param */ ++ rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst; ++ rtt_result->report.type = RTT_TWO_WAY; ++ DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num)); ++ rtt_result->report_len = RTT_REPORT_SIZE; ++ ++ list_add_tail(&rtt_result->list, &rtt_results_header->result_list); ++ rtt_results_header->result_cnt++; ++ rtt_results_header->result_tot_len += rtt_result->report_len; ++#endif /* WL_CFG80211 */ ++ } ++ break; ++ case WL_PROXD_EVENT_SESSION_END: ++ DHD_RTT(("WL_PROXD_EVENT_SESSION_END\n")); ++#ifdef WL_CFG80211 ++ if (!RTT_IS_ENABLED(rtt_status)) { ++ DHD_RTT(("Ignore the session end evt\n")); ++ goto exit; ++ } ++#endif /* WL_CFG80211 */ ++ if (tlvs_len > 0) { ++ /* unpack TLVs and invokes the cbfn to print the event content TLVs */ ++ ret = bcm_unpack_xtlv_buf((void *) &session_status, ++ (uint8 *)&p_event->tlvs[0], tlvs_len, ++ BCM_XTLV_OPTION_ALIGN32, rtt_unpack_xtlv_cbfn); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ } ++#ifdef WL_CFG80211 ++ /* In case of no result for the peer device, make fake result for error case */ ++ if (is_new) { ++ /* allocate new header for rtt_results */ ++ rtt_results_header = kzalloc(sizeof(rtt_results_header_t), GFP_KERNEL); ++ if (!rtt_results_header) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ /* Initialize the head of list for rtt result */ ++ INIT_LIST_HEAD(&rtt_results_header->result_list); ++ rtt_results_header->peer_mac = event->addr; ++ list_add_tail(&rtt_results_header->list, &rtt_status->rtt_results_cache); ++ ++ /* allocate rtt_results for new results */ ++ rtt_result = kzalloc(sizeof(rtt_result_t), kflags); ++ if (!rtt_result) { ++ ret = -ENOMEM; ++ kfree(rtt_results_header); ++ goto exit; ++ } ++ /* fill out the results from the configuration param */ ++ rtt_result->report.ftm_num = rtt_target_info->num_frames_per_burst; ++ rtt_result->report.type = RTT_TWO_WAY; ++ DHD_RTT(("report->ftm_num : %d\n", rtt_result->report.ftm_num)); ++ rtt_result->report_len = RTT_REPORT_SIZE; ++ rtt_result->report.status = RTT_REASON_FAIL_NO_RSP; ++ rtt_result->report.addr = rtt_target_info->addr; ++ rtt_result->report.distance = FTM_INVALID; ++ list_add_tail(&rtt_result->list, &rtt_results_header->result_list); ++ rtt_results_header->result_cnt++; ++ rtt_results_header->result_tot_len += rtt_result->report_len; ++ } ++ /* find next target to trigger RTT */ ++ for (idx = (rtt_status->cur_idx + 1); ++ idx < rtt_status->rtt_config.rtt_target_cnt; idx++) { ++ /* skip the disabled device */ ++ if (rtt_status->rtt_config.target_info[idx].disable) { ++ continue; ++ } else { ++ /* set the idx to cur_idx */ ++ rtt_status->cur_idx = idx; ++ break; ++ } ++ } ++ if (idx < rtt_status->rtt_config.rtt_target_cnt) { ++ /* restart to measure RTT from next device */ ++ DHD_ERROR(("restart to measure rtt\n")); ++ schedule_work(&rtt_status->work); ++ } else { ++ DHD_RTT(("RTT_STOPPED\n")); ++ rtt_status->status = RTT_STOPPED; ++ /* to turn on mpc mode */ ++ schedule_work(&rtt_status->work); ++ /* notify the completed information to others */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_entry(iter, &rtt_status->noti_fn_list, list) { ++ iter->noti_fn(iter->ctx, &rtt_status->rtt_results_cache); ++ } ++ /* remove the rtt results in cache */ ++ if (!list_empty(&rtt_status->rtt_results_cache)) { ++ /* Iterate rtt_results_header list */ ++ list_for_each_entry_safe(entry, next, ++ &rtt_status->rtt_results_cache, list) { ++ list_del(&entry->list); ++ /* Iterate rtt_result list */ ++ list_for_each_entry_safe(rtt_result, next2, ++ &entry->result_list, list) { ++ list_del(&rtt_result->list); ++ kfree(rtt_result); ++ } ++ kfree(entry); ++ } ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ /* reinitialize the HEAD */ ++ INIT_LIST_HEAD(&rtt_status->rtt_results_cache); ++ /* clear information for rtt_config */ ++ rtt_status->rtt_config.rtt_target_cnt = 0; ++ memset(rtt_status->rtt_config.target_info, 0, ++ TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT)); ++ rtt_status->cur_idx = 0; ++ } ++#endif /* WL_CFG80211 */ ++ break; ++ case WL_PROXD_EVENT_SESSION_RESTART: ++ DHD_RTT(("WL_PROXD_EVENT_SESSION_RESTART\n")); ++ break; ++ case WL_PROXD_EVENT_BURST_RESCHED: ++ DHD_RTT(("WL_PROXD_EVENT_BURST_RESCHED\n")); ++ break; ++ case WL_PROXD_EVENT_SESSION_DESTROY: ++ DHD_RTT(("WL_PROXD_EVENT_SESSION_DESTROY\n")); ++ break; ++ case WL_PROXD_EVENT_FTM_FRAME: ++ DHD_RTT(("WL_PROXD_EVENT_FTM_FRAME\n")); ++ break; ++ case WL_PROXD_EVENT_DELAY: ++ DHD_RTT(("WL_PROXD_EVENT_DELAY\n")); ++ break; ++ case WL_PROXD_EVENT_VS_INITIATOR_RPT: ++ DHD_RTT(("WL_PROXD_EVENT_VS_INITIATOR_RPT\n ")); ++ break; ++ case WL_PROXD_EVENT_RANGING: ++ DHD_RTT(("WL_PROXD_EVENT_RANGING\n")); ++ break; ++ case WL_PROXD_EVENT_COLLECT: ++ DHD_RTT(("WL_PROXD_EVENT_COLLECT\n")); ++ if (tlvs_len > 0) { ++ collect_event_data = kzalloc(sizeof(wl_proxd_collect_event_data_t), kflags); ++ if (!collect_event_data) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ /* unpack TLVs and invokes the cbfn to print the event content TLVs */ ++ ret = bcm_unpack_xtlv_buf((void *) collect_event_data, ++ (uint8 *)&p_event->tlvs[0], tlvs_len, ++ BCM_XTLV_OPTION_NONE, rtt_unpack_xtlv_cbfn); ++ kfree(collect_event_data); ++ if (ret != BCME_OK) { ++ DHD_ERROR(("%s : Failed to unpack xtlv for an event\n", ++ __FUNCTION__)); ++ goto exit; ++ } ++ } ++ break; ++ ++ ++ default: ++ DHD_ERROR(("WLC_E_PROXD: not supported EVENT Type:%d\n", event_type)); ++ break; ++ } ++exit: ++#ifdef WL_CFG80211 ++ if (!in_atomic()) { ++ mutex_unlock(&rtt_status->rtt_mutex); ++ } ++#endif /* WL_CFG80211 */ ++ ++ return ret; ++} ++ ++#ifdef WL_CFG80211 ++static void ++dhd_rtt_work(struct work_struct *work) ++{ ++ rtt_status_info_t *rtt_status; ++ dhd_pub_t *dhd; ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ rtt_status = container_of(work, rtt_status_info_t, work); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ if (rtt_status == NULL) { ++ DHD_ERROR(("%s : rtt_status is NULL\n", __FUNCTION__)); ++ return; ++ } ++ dhd = rtt_status->dhd; ++ if (dhd == NULL) { ++ DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); ++ return; ++ } ++ (void) dhd_rtt_start(dhd); ++} ++#endif /* WL_CFG80211 */ ++ ++int ++dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa) ++{ ++ rtt_status_info_t *rtt_status; ++ int err = BCME_OK; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ rtt_status = GET_RTTSTATE(dhd); ++ NULL_CHECK(rtt_status, "rtt_status is NULL", err); ++ NULL_CHECK(capa, "capa is NULL", err); ++ bzero(capa, sizeof(rtt_capabilities_t)); ++ ++ /* set rtt capabilities */ ++ if (rtt_status->rtt_capa.proto & RTT_CAP_ONE_WAY) ++ capa->rtt_one_sided_supported = 1; ++ if (rtt_status->rtt_capa.proto & RTT_CAP_FTM_WAY) ++ capa->rtt_ftm_supported = 1; ++ ++ if (rtt_status->rtt_capa.feature & RTT_FEATURE_LCI) ++ capa->lci_support = 1; ++ if (rtt_status->rtt_capa.feature & RTT_FEATURE_LCR) ++ capa->lcr_support = 1; ++ if (rtt_status->rtt_capa.feature & RTT_FEATURE_PREAMBLE) ++ capa->preamble_support = 1; ++ if (rtt_status->rtt_capa.feature & RTT_FEATURE_BW) ++ capa->bw_support = 1; ++ ++ /* bit mask */ ++ capa->preamble_support = rtt_status->rtt_capa.preamble; ++ capa->bw_support = rtt_status->rtt_capa.bw; ++ ++ return err; ++} ++ ++#ifdef WL_CFG80211 ++int ++dhd_rtt_avail_channel(dhd_pub_t *dhd, wifi_channel_info *channel_info) ++{ ++ u32 chanspec = 0; ++ int err = BCME_OK; ++ chanspec_t c = 0; ++ u32 channel; ++ struct net_device *dev = dhd_linux_get_primary_netdev(dhd); ++ ++ if ((err = wldev_iovar_getint(dev, "chanspec", ++ (s32 *)&chanspec)) == BCME_OK) { ++ c = (chanspec_t)dtoh32(chanspec); ++ c = wl_chspec_driver_to_host(c); ++ channel = wf_chspec_ctlchan(c); ++ DHD_RTT((" control channel is %d \n", channel)); ++ if (CHSPEC_IS20(c)) { ++ channel_info->width = WIFI_CHAN_WIDTH_20; ++ DHD_RTT((" band is 20 \n")); ++ } else if (CHSPEC_IS40(c)) { ++ channel_info->width = WIFI_CHAN_WIDTH_40; ++ DHD_RTT(("band is 40 \n")); ++ } else { ++ channel_info->width = WIFI_CHAN_WIDTH_80; ++ DHD_RTT(("band is 80 \n")); ++ } ++ if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) && ++ (channel <= CH_MAX_2G_CHANNEL)) { ++ channel_info->center_freq = ++ ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ); ++ } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) { ++ channel_info->center_freq = ++ ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ++ } ++ if ((channel_info->width == WIFI_CHAN_WIDTH_80) || ++ (channel_info->width == WIFI_CHAN_WIDTH_40)) { ++ channel = CHSPEC_CHANNEL(c); ++ channel_info->center_freq0 = ++ ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ); ++ } ++ } else { ++ DHD_ERROR(("Failed to get the chanspec \n")); ++ } ++ return err; ++} ++ ++int ++dhd_rtt_enable_responder(dhd_pub_t *dhd, wifi_channel_info *channel_info) ++{ ++ int err = BCME_OK; ++ char chanbuf[CHANSPEC_STR_LEN]; ++ int pm = PM_OFF; ++ int ftm_cfg_cnt = 0; ++ chanspec_t chanspec; ++ wifi_channel_info_t channel; ++ struct net_device *dev = dhd_linux_get_primary_netdev(dhd); ++ ftm_config_options_info_t ftm_configs[FTM_MAX_CONFIGS]; ++ ftm_config_param_info_t ftm_params[FTM_MAX_PARAMS]; ++ rtt_status_info_t *rtt_status; ++ ++ memset(&channel, 0, sizeof(channel)); ++ BCM_REFERENCE(chanbuf); ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ rtt_status = GET_RTTSTATE(dhd); ++ NULL_CHECK(rtt_status, "rtt_status is NULL", err); ++ if (RTT_IS_STOPPED(rtt_status)) { ++ DHD_RTT(("STA responder/Target. \n")); ++ } ++ DHD_RTT(("Enter %s \n", __FUNCTION__)); ++ if (!dhd_is_associated(dhd, 0, NULL)) { ++ if (channel_info) { ++ channel.width = channel_info->width; ++ channel.center_freq = channel_info->center_freq; ++ channel.center_freq0 = channel_info->center_freq; ++ } ++ else { ++ channel.width = WIFI_CHAN_WIDTH_80; ++ channel.center_freq = DEFAULT_FTM_FREQ; ++ channel.center_freq0 = DEFAULT_FTM_CNTR_FREQ0; ++ } ++ chanspec = dhd_rtt_convert_to_chspec(channel); ++ DHD_RTT(("chanspec/channel set as %s for rtt.\n", ++ wf_chspec_ntoa(chanspec, chanbuf))); ++ err = wldev_iovar_setint(dev, "chanspec", chanspec); ++ if (err) { ++ DHD_ERROR(("Failed to set the chanspec \n")); ++ } ++ } ++ err = wldev_ioctl_get(dev, WLC_GET_PM, &rtt_status->pm, sizeof(rtt_status->pm)); ++ DHD_RTT(("Current PM value read %d\n", rtt_status->pm)); ++ if (err) { ++ DHD_ERROR(("Failed to get the PM value \n")); ++ } else { ++ err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm)); ++ if (err) { ++ DHD_ERROR(("Failed to set the PM \n")); ++ rtt_status->pm_restore = FALSE; ++ } else { ++ rtt_status->pm_restore = TRUE; ++ } ++ } ++ if (!RTT_IS_ENABLED(rtt_status)) { ++ err = dhd_rtt_ftm_enable(dhd, TRUE); ++ if (err) { ++ DHD_ERROR(("Failed to enable FTM (%d)\n", err)); ++ goto exit; ++ } ++ DHD_RTT(("FTM enabled \n")); ++ } ++ rtt_status->status = RTT_ENABLED; ++ DHD_RTT(("Responder enabled \n")); ++ memset(ftm_configs, 0, sizeof(ftm_configs)); ++ memset(ftm_params, 0, sizeof(ftm_params)); ++ ftm_configs[ftm_cfg_cnt].enable = TRUE; ++ ftm_configs[ftm_cfg_cnt++].flags = WL_PROXD_SESSION_FLAG_TARGET; ++ rtt_status->flags = WL_PROXD_SESSION_FLAG_TARGET; ++ DHD_RTT(("Set the device as responder \n")); ++ err = dhd_rtt_ftm_config(dhd, FTM_DEFAULT_SESSION, FTM_CONFIG_CAT_OPTIONS, ++ ftm_configs, ftm_cfg_cnt); ++exit: ++ if (err) { ++ rtt_status->status = RTT_STOPPED; ++ DHD_ERROR(("rtt is stopped %s \n", __FUNCTION__)); ++ dhd_rtt_ftm_enable(dhd, FALSE); ++ DHD_RTT(("restoring the PM value \n")); ++ if (rtt_status->pm_restore) { ++ pm = PM_FAST; ++ err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm)); ++ if (err) { ++ DHD_ERROR(("Failed to restore PM \n")); ++ } else { ++ rtt_status->pm_restore = FALSE; ++ } ++ } ++ } ++ return err; ++} ++ ++int ++dhd_rtt_cancel_responder(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++ rtt_status_info_t *rtt_status; ++ int pm = 0; ++ struct net_device *dev = dhd_linux_get_primary_netdev(dhd); ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ rtt_status = GET_RTTSTATE(dhd); ++ NULL_CHECK(rtt_status, "rtt_status is NULL", err); ++ DHD_RTT(("Enter %s \n", __FUNCTION__)); ++ err = dhd_rtt_ftm_enable(dhd, FALSE); ++ if (err) { ++ DHD_ERROR(("failed to disable FTM (%d)\n", err)); ++ } ++ rtt_status->status = RTT_STOPPED; ++ if (rtt_status->pm_restore) { ++ pm = PM_FAST; ++ DHD_RTT(("pm_restore =%d \n", rtt_status->pm_restore)); ++ err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm)); ++ if (err) { ++ DHD_ERROR(("Failed to restore PM \n")); ++ } else { ++ rtt_status->pm_restore = FALSE; ++ } ++ } ++ return err; ++} ++#endif /* WL_CFG80211 */ ++ ++int ++dhd_rtt_init(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++#ifdef WL_CFG80211 ++ int ret; ++ int32 drv_up = 1; ++ int32 version; ++ rtt_status_info_t *rtt_status; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ dhd->rtt_supported = FALSE; ++ if (dhd->rtt_state) { ++ return err; ++ } ++ dhd->rtt_state = kzalloc(sizeof(rtt_status_info_t), GFP_KERNEL); ++ if (dhd->rtt_state == NULL) { ++ err = BCME_NOMEM; ++ DHD_ERROR(("%s : failed to create rtt_state\n", __FUNCTION__)); ++ return err; ++ } ++ bzero(dhd->rtt_state, sizeof(rtt_status_info_t)); ++ rtt_status = GET_RTTSTATE(dhd); ++ rtt_status->rtt_config.target_info = ++ kzalloc(TARGET_INFO_SIZE(RTT_MAX_TARGET_CNT), GFP_KERNEL); ++ if (rtt_status->rtt_config.target_info == NULL) { ++ DHD_ERROR(("%s failed to allocate the target info for %d\n", ++ __FUNCTION__, RTT_MAX_TARGET_CNT)); ++ err = BCME_NOMEM; ++ goto exit; ++ } ++ rtt_status->dhd = dhd; ++ /* need to do WLC_UP */ ++ dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&drv_up, sizeof(int32), TRUE, 0); ++ ++ ret = dhd_rtt_get_version(dhd, &version); ++ if (ret == BCME_OK && (version == WL_PROXD_API_VERSION)) { ++ DHD_ERROR(("%s : FTM is supported\n", __FUNCTION__)); ++ dhd->rtt_supported = TRUE; ++ /* rtt_status->rtt_capa.proto |= RTT_CAP_ONE_WAY; */ ++ rtt_status->rtt_capa.proto |= RTT_CAP_FTM_WAY; ++ ++ /* indicate to set tx rate */ ++ rtt_status->rtt_capa.feature |= RTT_FEATURE_LCI; ++ rtt_status->rtt_capa.feature |= RTT_FEATURE_LCR; ++ rtt_status->rtt_capa.feature |= RTT_FEATURE_PREAMBLE; ++ rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_VHT; ++ rtt_status->rtt_capa.preamble |= RTT_PREAMBLE_HT; ++ ++ /* indicate to set bandwith */ ++ rtt_status->rtt_capa.feature |= RTT_FEATURE_BW; ++ rtt_status->rtt_capa.bw |= RTT_BW_20; ++ rtt_status->rtt_capa.bw |= RTT_BW_40; ++ rtt_status->rtt_capa.bw |= RTT_BW_80; ++ } else { ++ if ((ret != BCME_OK) || (version == 0)) { ++ DHD_ERROR(("%s : FTM is not supported\n", __FUNCTION__)); ++ } else { ++ DHD_ERROR(("%s : FTM version mismatch between HOST (%d) and FW (%d)\n", ++ __FUNCTION__, WL_PROXD_API_VERSION, version)); ++ } ++ } ++ /* cancel all of RTT request once we got the cancel request */ ++ rtt_status->all_cancel = TRUE; ++ mutex_init(&rtt_status->rtt_mutex); ++ INIT_LIST_HEAD(&rtt_status->noti_fn_list); ++ INIT_LIST_HEAD(&rtt_status->rtt_results_cache); ++ INIT_WORK(&rtt_status->work, dhd_rtt_work); ++exit: ++ if (err < 0) { ++ kfree(rtt_status->rtt_config.target_info); ++ kfree(dhd->rtt_state); ++ } ++#endif /* WL_CFG80211 */ ++ return err; ++ ++} ++ ++int ++dhd_rtt_deinit(dhd_pub_t *dhd) ++{ ++ int err = BCME_OK; ++#ifdef WL_CFG80211 ++ rtt_status_info_t *rtt_status; ++ rtt_results_header_t *rtt_header, *next; ++ rtt_result_t *rtt_result, *next2; ++ struct rtt_noti_callback *iter, *iter2; ++ NULL_CHECK(dhd, "dhd is NULL", err); ++ rtt_status = GET_RTTSTATE(dhd); ++ NULL_CHECK(rtt_status, "rtt_status is NULL", err); ++ rtt_status->status = RTT_STOPPED; ++ DHD_RTT(("rtt is stopped %s \n", __FUNCTION__)); ++ /* clear evt callback list */ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ ++ if (!list_empty(&rtt_status->noti_fn_list)) { ++ list_for_each_entry_safe(iter, iter2, &rtt_status->noti_fn_list, list) { ++ list_del(&iter->list); ++ kfree(iter); ++ } ++ } ++ /* remove the rtt results */ ++ if (!list_empty(&rtt_status->rtt_results_cache)) { ++ list_for_each_entry_safe(rtt_header, next, &rtt_status->rtt_results_cache, list) { ++ list_del(&rtt_header->list); ++ list_for_each_entry_safe(rtt_result, next2, ++ &rtt_header->result_list, list) { ++ list_del(&rtt_result->list); ++ kfree(rtt_result); ++ } ++ kfree(rtt_header); ++ } ++ } ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ kfree(rtt_status->rtt_config.target_info); ++ kfree(dhd->rtt_state); ++ dhd->rtt_state = NULL; ++#endif /* WL_CFG80211 */ ++ return err; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_rtt.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_rtt.h +new file mode 100644 +index 000000000..b3ca820b7 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_rtt.h +@@ -0,0 +1,387 @@ ++/* ++ * Broadcom Dongle Host Driver (DHD), RTT ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id$ ++ */ ++#ifndef __DHD_RTT_H__ ++#define __DHD_RTT_H__ ++ ++#include "dngl_stats.h" ++ ++#define RTT_MAX_TARGET_CNT 50 ++#define RTT_MAX_FRAME_CNT 25 ++#define RTT_MAX_RETRY_CNT 10 ++#define DEFAULT_FTM_CNT 6 ++#define DEFAULT_RETRY_CNT 6 ++#define DEFAULT_FTM_FREQ 5180 ++#define DEFAULT_FTM_CNTR_FREQ0 5210 ++ ++#define TARGET_INFO_SIZE(count) (sizeof(rtt_target_info_t) * count) ++ ++#define TARGET_TYPE(target) (target->type) ++ ++#ifndef BIT ++#define BIT(x) (1 << (x)) ++#endif ++ ++/* DSSS, CCK and 802.11n rates in [500kbps] units */ ++#define WL_MAXRATE 108 /* in 500kbps units */ ++#define WL_RATE_1M 2 /* in 500kbps units */ ++#define WL_RATE_2M 4 /* in 500kbps units */ ++#define WL_RATE_5M5 11 /* in 500kbps units */ ++#define WL_RATE_11M 22 /* in 500kbps units */ ++#define WL_RATE_6M 12 /* in 500kbps units */ ++#define WL_RATE_9M 18 /* in 500kbps units */ ++#define WL_RATE_12M 24 /* in 500kbps units */ ++#define WL_RATE_18M 36 /* in 500kbps units */ ++#define WL_RATE_24M 48 /* in 500kbps units */ ++#define WL_RATE_36M 72 /* in 500kbps units */ ++#define WL_RATE_48M 96 /* in 500kbps units */ ++#define WL_RATE_54M 108 /* in 500kbps units */ ++#define GET_RTTSTATE(dhd) ((rtt_status_info_t *)dhd->rtt_state) ++ ++enum rtt_role { ++ RTT_INITIATOR = 0, ++ RTT_TARGET = 1 ++}; ++enum rtt_status { ++ RTT_STOPPED = 0, ++ RTT_STARTED = 1, ++ RTT_ENABLED = 2 ++}; ++typedef int64_t wifi_timestamp; /* In microseconds (us) */ ++typedef int64_t wifi_timespan; ++typedef int32 wifi_rssi_rtt; ++ ++typedef enum { ++ RTT_INVALID, ++ RTT_ONE_WAY, ++ RTT_TWO_WAY, ++ RTT_AUTO ++} rtt_type_t; ++ ++typedef enum { ++ RTT_PEER_STA, ++ RTT_PEER_AP, ++ RTT_PEER_P2P, ++ RTT_PEER_NAN, ++ RTT_PEER_INVALID ++} rtt_peer_type_t; ++ ++typedef enum rtt_reason { ++ RTT_REASON_SUCCESS, ++ RTT_REASON_FAILURE, ++ RTT_REASON_FAIL_NO_RSP, ++ RTT_REASON_FAIL_INVALID_TS, /* Invalid timestamp */ ++ RTT_REASON_FAIL_PROTOCOL, /* 11mc protocol failed */ ++ RTT_REASON_FAIL_REJECTED, ++ RTT_REASON_FAIL_NOT_SCHEDULED_YET, ++ RTT_REASON_FAIL_SCHEDULE, /* schedule failed */ ++ RTT_REASON_FAIL_TM_TIMEOUT, ++ RTT_REASON_FAIL_AP_ON_DIFF_CHANNEL, ++ RTT_REASON_FAIL_NO_CAPABILITY, ++ RTT_REASON_FAIL_BUSY_TRY_LATER, ++ RTT_REASON_ABORTED ++} rtt_reason_t; ++ ++enum { ++ RTT_CAP_ONE_WAY = BIT(0), ++ /* IEEE802.11mc */ ++ RTT_CAP_FTM_WAY = BIT(1) ++}; ++ ++enum { ++ RTT_FEATURE_LCI = BIT(0), ++ RTT_FEATURE_LCR = BIT(1), ++ RTT_FEATURE_PREAMBLE = BIT(2), ++ RTT_FEATURE_BW = BIT(3) ++}; ++ ++enum { ++ RTT_PREAMBLE_LEGACY = BIT(0), ++ RTT_PREAMBLE_HT = BIT(1), ++ RTT_PREAMBLE_VHT = BIT(2) ++}; ++ ++ ++enum { ++ RTT_BW_5 = BIT(0), ++ RTT_BW_10 = BIT(1), ++ RTT_BW_20 = BIT(2), ++ RTT_BW_40 = BIT(3), ++ RTT_BW_80 = BIT(4), ++ RTT_BW_160 = BIT(5) ++}; ++#define FTM_MAX_NUM_BURST_EXP 14 ++#define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY) ++#define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY) ++#define HAS_RTT_CAP(cap) (HAS_ONEWAY_CAP(cap) || HAS_11MC_CAP(cap)) ++ ++typedef struct wifi_channel_info { ++ wifi_channel_width_t width; ++ wifi_channel center_freq; /* primary 20 MHz channel */ ++ wifi_channel center_freq0; /* center freq (MHz) first segment */ ++ wifi_channel center_freq1; /* center freq (MHz) second segment valid for 80 + 80 */ ++} wifi_channel_info_t; ++ ++typedef struct wifi_rate { ++ uint32 preamble :3; /* 0: OFDM, 1: CCK, 2 : HT, 3: VHT, 4..7 reserved */ ++ uint32 nss :2; /* 1 : 1x1, 2: 2x2, 3: 3x3, 4: 4x4 */ ++ uint32 bw :3; /* 0: 20Mhz, 1: 40Mhz, 2: 80Mhz, 3: 160Mhz */ ++ /* OFDM/CCK rate code would be as per IEEE std in the unit of 0.5 mb ++ * HT/VHT it would be mcs index ++ */ ++ uint32 rateMcsIdx :8; ++ uint32 reserved :16; /* reserved */ ++ uint32 bitrate; /* unit of 100 Kbps */ ++} wifi_rate_t; ++ ++typedef struct rtt_target_info { ++ struct ether_addr addr; ++ rtt_type_t type; /* rtt_type */ ++ rtt_peer_type_t peer; /* peer type */ ++ wifi_channel_info_t channel; /* channel information */ ++ chanspec_t chanspec; /* chanspec for channel */ ++ bool disable; /* disable for RTT measurement */ ++ /* ++ * Time interval between bursts (units: 100 ms). ++ * Applies to 1-sided and 2-sided RTT multi-burst requests. ++ * Range: 0-31, 0: no preference by initiator (2-sided RTT) ++ */ ++ uint32 burst_period; ++ /* ++ * Total number of RTT bursts to be executed. It will be ++ * specified in the same way as the parameter "Number of ++ * Burst Exponent" found in the FTM frame format. It ++ * applies to both: 1-sided RTT and 2-sided RTT. Valid ++ * values are 0 to 15 as defined in 802.11mc std. ++ * 0 means single shot ++ * The implication of this parameter on the maximum ++ * number of RTT results is the following: ++ * for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst) ++ * for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1) ++ */ ++ uint16 num_burst; ++ /* ++ * num of frames per burst. ++ * Minimum value = 1, Maximum value = 31 ++ * For 2-sided this equals the number of FTM frames ++ * to be attempted in a single burst. This also ++ * equals the number of FTM frames that the ++ * initiator will request that the responder send ++ * in a single frame ++ */ ++ uint32 num_frames_per_burst; ++ /* num of frames in each RTT burst ++ * for single side, measurement result num = frame number ++ * for 2 side RTT, measurement result num = frame number - 1 ++ */ ++ uint32 num_retries_per_ftm; /* retry time for RTT measurment frame */ ++ /* following fields are only valid for 2 side RTT */ ++ uint32 num_retries_per_ftmr; ++ uint8 LCI_request; ++ uint8 LCR_request; ++ /* ++ * Applies to 1-sided and 2-sided RTT. Valid values will ++ * be 2-11 and 15 as specified by the 802.11mc std for ++ * the FTM parameter burst duration. In a multi-burst ++ * request, if responder overrides with larger value, ++ * the initiator will return failure. In a single-burst ++ * request if responder overrides with larger value, ++ * the initiator will sent TMR_STOP to terminate RTT ++ * at the end of the burst_duration it requested. ++ */ ++ uint32 burst_duration; ++ uint8 preamble; /* 1 - Legacy, 2 - HT, 4 - VHT */ ++ uint8 bw; /* 5, 10, 20, 40, 80, 160 */ ++} rtt_target_info_t; ++ ++typedef struct rtt_config_params { ++ int8 rtt_target_cnt; ++ rtt_target_info_t *target_info; ++} rtt_config_params_t; ++ ++typedef struct rtt_status_info { ++ dhd_pub_t *dhd; ++ int8 status; /* current status for the current entry */ ++ int8 txchain; /* current device tx chain */ ++ int8 mpc; /* indicate we change mpc mode */ ++ int pm; /* to save current value of pm */ ++ int8 pm_restore; /* flag to reset the old value of pm */ ++ int8 cur_idx; /* current entry to do RTT */ ++ bool all_cancel; /* cancel all request once we got the cancel requet */ ++ uint32 flags; /* indicate whether device is configured as initiator or target */ ++ struct capability { ++ int32 proto :8; ++ int32 feature :8; ++ int32 preamble :8; ++ int32 bw :8; ++ } rtt_capa; /* rtt capability */ ++ struct mutex rtt_mutex; ++ rtt_config_params_t rtt_config; ++ struct work_struct work; ++ struct list_head noti_fn_list; ++ struct list_head rtt_results_cache; /* store results for RTT */ ++} rtt_status_info_t; ++ ++typedef struct rtt_report { ++ struct ether_addr addr; ++ unsigned int burst_num; /* # of burst inside a multi-burst request */ ++ unsigned int ftm_num; /* total RTT measurement frames attempted */ ++ unsigned int success_num; /* total successful RTT measurement frames */ ++ uint8 num_per_burst_peer; /* max number of FTM number per burst the peer support */ ++ rtt_reason_t status; /* raging status */ ++ /* in s, 11mc only, only for RTT_REASON_FAIL_BUSY_TRY_LATER, 1- 31s */ ++ uint8 retry_after_duration; ++ rtt_type_t type; /* rtt type */ ++ wifi_rssi_rtt rssi; /* average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB */ ++ wifi_rssi_rtt rssi_spread; /* rssi spread in 0.5 db steps e.g. 5 implies 2.5 spread */ ++ /* ++ * 1-sided RTT: TX rate of RTT frame. ++ * 2-sided RTT: TX rate of initiator's Ack in response to FTM frame. ++ */ ++ wifi_rate_t tx_rate; ++ /* ++ * 1-sided RTT: TX rate of Ack from other side. ++ * 2-sided RTT: TX rate of FTM frame coming from responder. ++ */ ++ wifi_rate_t rx_rate; ++ wifi_timespan rtt; /* round trip time in 0.1 nanoseconds */ ++ wifi_timespan rtt_sd; /* rtt standard deviation in 0.1 nanoseconds */ ++ wifi_timespan rtt_spread; /* difference between max and min rtt times recorded */ ++ int distance; /* distance in cm (optional) */ ++ int distance_sd; /* standard deviation in cm (optional) */ ++ int distance_spread; /* difference between max and min distance recorded (optional) */ ++ wifi_timestamp ts; /* time of the measurement (in microseconds since boot) */ ++ int burst_duration; /* in ms, how long the FW time is to fininish one burst measurement */ ++ int negotiated_burst_num; /* Number of bursts allowed by the responder */ ++ bcm_tlv_t *LCI; /* LCI Report */ ++ bcm_tlv_t *LCR; /* Location Civic Report */ ++} rtt_report_t; ++#define RTT_REPORT_SIZE (sizeof(rtt_report_t)) ++ ++/* rtt_results_header to maintain rtt result list per mac address */ ++typedef struct rtt_results_header { ++ struct ether_addr peer_mac; ++ uint32 result_cnt; ++ uint32 result_tot_len; /* sum of report_len of rtt_result */ ++ struct list_head list; ++ struct list_head result_list; ++} rtt_results_header_t; ++ ++/* rtt_result to link all of rtt_report */ ++typedef struct rtt_result { ++ struct list_head list; ++ struct rtt_report report; ++ int32 report_len; /* total length of rtt_report */ ++} rtt_result_t; ++ ++/* RTT Capabilities */ ++typedef struct rtt_capabilities { ++ uint8 rtt_one_sided_supported; /* if 1-sided rtt data collection is supported */ ++ uint8 rtt_ftm_supported; /* if ftm rtt data collection is supported */ ++ uint8 lci_support; /* location configuration information */ ++ uint8 lcr_support; /* Civic Location */ ++ uint8 preamble_support; /* bit mask indicate what preamble is supported */ ++ uint8 bw_support; /* bit mask indicate what BW is supported */ ++} rtt_capabilities_t; ++ ++ ++/* RTT responder information */ ++typedef struct wifi_rtt_responder { ++ wifi_channel_info channel; /* channel of responder */ ++ uint8 preamble; /* preamble supported by responder */ ++} wifi_rtt_responder_t; ++ ++typedef void (*dhd_rtt_compl_noti_fn)(void *ctx, void *rtt_data); ++/* Linux wrapper to call common dhd_rtt_set_cfg */ ++int ++dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf); ++ ++int ++dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt); ++ ++int ++dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, ++ dhd_rtt_compl_noti_fn noti_fn); ++ ++int ++dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn); ++ ++int ++dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa); ++ ++#ifdef WL_CFG80211 ++int ++dhd_dev_rtt_avail_channel(struct net_device *dev, wifi_channel_info *channel_info); ++#endif /* WL_CFG80211 */ ++ ++int ++dhd_dev_rtt_enable_responder(struct net_device *dev, wifi_channel_info *channel_info); ++ ++int ++dhd_dev_rtt_cancel_responder(struct net_device *dev); ++/* export to upper layer */ ++chanspec_t ++dhd_rtt_convert_to_chspec(wifi_channel_info_t channel); ++ ++int ++dhd_rtt_idx_to_burst_duration(uint idx); ++ ++int ++dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params); ++ ++int ++dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt); ++ ++ ++int ++dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn); ++ ++int ++dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn); ++ ++int ++dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data); ++ ++int ++dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa); ++ ++int ++dhd_rtt_avail_channel(dhd_pub_t *dhd, wifi_channel_info *channel_info); ++ ++int ++dhd_rtt_enable_responder(dhd_pub_t *dhd, wifi_channel_info *channel_info); ++ ++int ++dhd_rtt_cancel_responder(dhd_pub_t *dhd); ++ ++int ++dhd_rtt_init(dhd_pub_t *dhd); ++ ++int ++dhd_rtt_deinit(dhd_pub_t *dhd); ++#endif /* __DHD_RTT_H__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_sdio.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_sdio.c +new file mode 100644 +index 000000000..50637fead +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_sdio.c +@@ -0,0 +1,10180 @@ ++/* ++ * DHD Bus Module for SDIO ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_sdio.c 705650 2017-06-19 03:00:50Z $ ++ */ ++ ++#include ++#include ++#include ++ ++#ifdef BCMEMBEDIMAGE ++#include BCMEMBEDIMAGE ++#endif /* BCMEMBEDIMAGE */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include <802.1d.h> ++#include <802.11.h> ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef PROP_TXSTATUS ++#include ++#endif ++#ifdef DHDTCPACK_SUPPRESS ++#include ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++#ifdef BT_OVER_SDIO ++#include ++#endif /* BT_OVER_SDIO */ ++ ++bool dhd_mp_halting(dhd_pub_t *dhdp); ++extern void bcmsdh_waitfor_iodrain(void *sdh); ++extern void bcmsdh_reject_ioreqs(void *sdh, bool reject); ++extern bool bcmsdh_fatal_error(void *sdh); ++static int dhdsdio_suspend(void *context); ++static int dhdsdio_resume(void *context); ++ ++ ++#ifndef DHDSDIO_MEM_DUMP_FNAME ++#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" ++#endif ++ ++#define QLEN (1024) /* bulk rx and tx queue lengths */ ++#define FCHI (QLEN - 10) ++#define FCLOW (FCHI / 2) ++#define PRIOMASK 7 ++ ++#define F0_BLOCK_SIZE 32 ++#define TXRETRIES 2 /* # of retries for tx frames */ ++#define READ_FRM_CNT_RETRIES 3 ++#ifndef DHD_RXBOUND ++#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ ++#endif ++ ++#ifndef DHD_TXBOUND ++#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ ++#endif ++ ++#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ ++ ++#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ ++#define MAX_MEMBLOCK (32 * 1024) /* Block size used for downloading of dongle image */ ++ ++#define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */ ++#define MAX_MEM_BUF 4096 ++ ++#ifndef DHD_FIRSTREAD ++#define DHD_FIRSTREAD 32 ++#endif ++#if !ISPOWEROF2(DHD_FIRSTREAD) ++#error DHD_FIRSTREAD is not a power of 2! ++#endif ++ ++/* Total length of frame header for dongle protocol */ ++#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) ++#define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN) ++#define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE ++ ++#ifdef SDTEST ++#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) ++#else ++#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN) ++#endif ++ ++/* 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_RX_DATASZ 2048 ++ ++/* Maximum milliseconds to wait for F2 to come up */ ++#define DHD_WAIT_F2RDY 3000 ++ ++/* Maximum usec to wait for HTAVAIL to come up */ ++#define DHD_WAIT_HTAVAIL 10000 ++ ++/* Bump up limit on waiting for HT to account for first startup; ++ * if the image is doing a CRC calculation before programming the PMU ++ * 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 ++ ++/* hooks for limiting threshold custom tx num in rx processing */ ++#define DEFAULT_TXINRX_THRES 0 ++#ifndef CUSTOM_TXINRX_THRES ++#define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES ++#endif ++ ++/* Value for ChipClockCSR during initial setup */ ++#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ) ++#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP) ++ ++/* Flags for SDH calls */ ++#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) ++ ++/* Packet free applicable unconditionally for sdio and sdspi. Conditional if ++ * bufpool was present for gspi bus. ++ */ ++#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); ++ ++#ifdef PKT_STATICS ++pkt_statics_t tx_statics = {0}; ++#endif ++ ++#ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW ++extern unsigned int system_hw_rev; ++#endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */ ++ ++/* Device console log buffer state */ ++#define CONSOLE_LINE_MAX 192 ++#define CONSOLE_BUFFER_MAX 8192 ++typedef struct dhd_console { ++ uint count; /* Poll interval msec counter */ ++ uint log_addr; /* Log struct address (fixed) */ ++ hnd_log_t log; /* Log struct (host copy) */ ++ uint bufsize; /* Size of log buffer */ ++ uint8 *buf; /* Log buffer (host copy) */ ++ uint last; /* Last buffer read index */ ++} dhd_console_t; ++ ++#define REMAP_ENAB(bus) ((bus)->remap) ++#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) ++#define KSO_ENAB(bus) ((bus)->kso) ++#define SR_ENAB(bus) ((bus)->_srenab) ++#define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto)) ++ ++#define MIN_RSRC_SR 0x3 ++#define CORE_CAPEXT_ADDR_OFFSET (0x64c) ++#define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) ++#define RCTL_MACPHY_DISABLE_MASK (1 << 26) ++#define RCTL_LOGIC_DISABLE_MASK (1 << 27) ++ ++#define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) ++#define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ ++#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ ++#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ ++#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) ++#define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2) ++#define OVERFLOW_BLKSZ512_WM 96 ++#define OVERFLOW_BLKSZ512_MES 80 ++ ++#define CC_PMUCC3 (0x3) ++ ++#ifdef DHD_UCODE_DOWNLOAD ++/* Ucode host download related macros */ ++#define UCODE_DOWNLOAD_REQUEST 0xCAFECAFE ++#define UCODE_DOWNLOAD_COMPLETE 0xABCDABCD ++#endif /* DHD_UCODE_DOWNLOAD */ ++ ++#if defined(BT_OVER_SDIO) ++#define BTMEM_OFFSET 0x19000000 ++/* BIT0 => WLAN Power UP and BIT1=> WLAN Wake */ ++#define BT2WLAN_PWRUP_WAKE 0x03 ++#define BT2WLAN_PWRUP_ADDR 0x640894 /* This address is specific to 43012B0 */ ++ ++#define BTFW_MAX_STR_LEN 600 ++#define BTFW_DOWNLOAD_BLK_SIZE (BTFW_MAX_STR_LEN/2 + 8) ++ ++#define BTFW_ADDR_MODE_UNKNOWN 0 ++#define BTFW_ADDR_MODE_EXTENDED 1 ++#define BTFW_ADDR_MODE_SEGMENT 2 ++#define BTFW_ADDR_MODE_LINEAR32 3 ++ ++#define BTFW_HEX_LINE_TYPE_DATA 0 ++#define BTFW_HEX_LINE_TYPE_END_OF_DATA 1 ++#define BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS 2 ++#define BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS 4 ++#define BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS 5 ++ ++#endif /* defined (BT_OVER_SDIO) */ ++ ++/* Private data for SDIO bus interaction */ ++typedef struct dhd_bus { ++ dhd_pub_t *dhd; ++ ++ bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ ++ si_t *sih; /* Handle for SI calls */ ++ char *vars; /* Variables (from CIS and/or other) */ ++ uint varsz; /* Size of variables buffer */ ++ uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ ++ ++ sdpcmd_regs_t *regs; /* Registers for SDIO core */ ++ uint sdpcmrev; /* SDIO core revision */ ++ uint armrev; /* CPU core revision */ ++ uint ramrev; /* SOCRAM core revision */ ++ uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ ++ uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ ++ uint32 srmemsize; /* Size of SRMEM */ ++ ++ uint32 bus; /* gSPI or SDIO bus */ ++ uint32 bus_num; /* bus number */ ++ uint32 slot_num; /* slot ID */ ++ uint32 hostintmask; /* Copy of Host Interrupt Mask */ ++ uint32 intstatus; /* Intstatus bits (events) pending */ ++ bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ ++ bool fcstate; /* State of dongle flow-control */ ++ ++ uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ ++ char *fw_path; /* module_param: path to firmware image */ ++ char *nv_path; /* module_param: path to nvram vars file */ ++ ++ uint blocksize; /* Block size of SDIO transfers */ ++ uint roundup; /* Max roundup limit */ ++ ++ struct pktq txq; /* Queue length used for flow-control */ ++ uint8 flowcontrol; /* per prio flow control bitmask */ ++ uint8 tx_seq; /* Transmit sequence number (next) */ ++ uint8 tx_max; /* Maximum transmit sequence allowed */ ++ ++ uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; ++ uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ ++ uint16 nextlen; /* Next Read Len from last header */ ++ uint8 rx_seq; /* Receive sequence number (expected) */ ++ bool rxskip; /* Skip receive (awaiting NAK ACK) */ ++ ++ void *glomd; /* Packet containing glomming descriptor */ ++ void *glom; /* Packet chain for glommed superframe */ ++ uint glomerr; /* Glom packet read errors */ ++ ++ uint8 *rxbuf; /* Buffer for receiving control packets */ ++ uint rxblen; /* Allocated length of rxbuf */ ++ uint8 *rxctl; /* Aligned pointer into rxbuf */ ++ uint8 *databuf; /* Buffer for receiving big glom packet */ ++ uint8 *dataptr; /* Aligned pointer into databuf */ ++ uint rxlen; /* Length of valid data in buffer */ ++ ++ uint8 sdpcm_ver; /* Bus protocol reported by dongle */ ++ ++ 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 */ ++ uint pollrate; /* Ticks between device polls */ ++ uint polltick; /* Tick counter */ ++ uint pollcnt; /* Count of active polls */ ++ ++ dhd_console_t console; /* Console output polling support */ ++ uint console_addr; /* Console address from shared struct */ ++ ++ uint regfails; /* Count of R_REG/W_REG failures */ ++ ++ uint clkstate; /* State of sd and backplane clock(s) */ ++ bool activity; /* Activity flag for clock down */ ++ int32 idletime; /* Control for activity timeout */ ++ int32 idlecount; /* Activity timeout counter */ ++ int32 idleclock; /* How to set bus driver when idle */ ++ int32 sd_divisor; /* Speed control to bus driver */ ++ int32 sd_mode; /* Mode control to bus driver */ ++ int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ ++ bool use_rxchain; /* If dhd should use PKT chains */ ++ bool sleeping; /* Is SDIO bus sleeping? */ ++#if defined(SUPPORT_P2P_GO_PS) ++ wait_queue_head_t bus_sleep; ++#endif /* LINUX && SUPPORT_P2P_GO_PS */ ++ bool ctrl_wait; ++ wait_queue_head_t ctrl_tx_wait; ++ uint rxflow_mode; /* Rx flow control mode */ ++ bool rxflow; /* Is rx flow control on */ ++ uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ ++ bool alp_only; /* Don't use HT clock (ALP only) */ ++ /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ ++ bool usebufpool; ++ int32 txinrx_thres; /* num of in-queued pkts */ ++ int32 dotxinrx; /* tx first in dhdsdio_readframes */ ++#ifdef BCMSDIO_RXLIM_POST ++ bool rxlim_en; ++ uint32 rxlim_addr; ++#endif /* BCMSDIO_RXLIM_POST */ ++#ifdef SDTEST ++ /* external loopback */ ++ bool ext_loop; ++ uint8 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_prev_time; /* Time at which previous stats where printed */ ++ uint pktgen_prev_sent; /* Number of test packets generated when ++ * previous stats were printed ++ */ ++ uint pktgen_prev_rcvd; /* Number of test packets received when ++ * previous stats were printed ++ */ ++ uint pktgen_fail; /* Number of failed send attempts */ ++ uint16 pktgen_len; /* Length of next packet to send */ ++#define PKTGEN_RCV_IDLE (0) ++#define PKTGEN_RCV_ONGOING (1) ++ uint16 pktgen_rcv_state; /* receive state */ ++ uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ ++#endif /* SDTEST */ ++ ++ /* Some additional counters */ ++ uint tx_sderrs; /* Count of tx attempts with sd errors */ ++ uint fcqueued; /* Tx packets that got queued */ ++ uint rxrtx; /* Count of rtx requests (NAK to dongle) */ ++ uint rx_toolong; /* Receive frames too long to receive */ ++ uint rxc_errors; /* SDIO errors when reading control frames */ ++ uint rx_hdrfail; /* SDIO errors on header reads */ ++ uint rx_badhdr; /* Bad received headers (roosync?) */ ++ uint rx_badseq; /* Mismatched rx sequence number */ ++ uint fc_rcvd; /* Number of flow-control events received */ ++ uint fc_xoff; /* Number which turned on flow-control */ ++ uint fc_xon; /* Number which turned off flow-control */ ++ uint rxglomfail; /* Failed deglom attempts */ ++ uint rxglomframes; /* Number of glom frames (superframes) */ ++ uint rxglompkts; /* Number of packets from glom frames */ ++ uint f2rxhdrs; /* Number of header reads */ ++ uint f2rxdata; /* Number of frame data reads */ ++ uint f2txdata; /* Number of f2 frame writes */ ++ uint f1regdata; /* Number of f1 register accesses */ ++ wake_counts_t wake_counts; /* Wake up counter */ ++#ifdef DHDENABLE_TAILPAD ++ uint tx_tailpad_chain; /* Number of tail padding by chaining pad_pkt */ ++ uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */ ++#endif /* DHDENABLE_TAILPAD */ ++ uint8 *ctrl_frame_buf; ++ uint32 ctrl_frame_len; ++ bool ctrl_frame_stat; ++ uint32 rxint_mode; /* rx interrupt mode */ ++ bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram ++ * Available with socram rev 16 ++ * Remap region not DMA-able ++ */ ++ bool kso; ++ bool _slpauto; ++ bool _oobwakeup; ++ bool _srenab; ++ bool readframes; ++ bool reqbussleep; ++ uint32 resetinstr; ++ uint32 dongle_ram_base; ++ ++ void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */ ++ uint32 txglom_cnt; /* Number of pkts in the glom array */ ++ uint32 txglom_total_len; /* Total length of pkts in glom array */ ++ bool txglom_enable; /* Flag to indicate whether tx glom is enabled/disabled */ ++ uint32 txglomsize; /* Glom size limitation */ ++#ifdef DHDENABLE_TAILPAD ++ void *pad_pkt; ++#endif /* DHDENABLE_TAILPAD */ ++ uint32 dongle_trap_addr; /* device trap addr location in device memory */ ++#if defined(BT_OVER_SDIO) ++ char *btfw_path; /* module_param: path to BT firmware image */ ++ uint32 bt_use_count; /* Counter that tracks whether BT is using the bus */ ++#endif /* defined (BT_OVER_SDIO) */ ++ uint txglomframes; /* Number of tx glom frames (superframes) */ ++ uint txglompkts; /* Number of packets from tx glom frames */ ++ uint8 *membuf; /* Buffer for dhdsdio_membytes */ ++#ifdef CONSOLE_DPC ++ char cons_cmd[16]; ++#endif ++} dhd_bus_t; ++ ++ ++/* ++ * Whenever DHD_IDLE_IMMEDIATE condition is handled, we have to now check if ++ * BT is active too. Instead of adding #ifdef code in all the places, we thought ++ * of adding one macro check as part of the if condition that checks for DHD_IDLE_IMMEDIATE ++ * In case of non BT over SDIO builds, this macro will always return TRUE. In case ++ * of the builds where BT_OVER_SDIO is enabled, it will expand to a condition check ++ * that checks if bt_use_count is zero. So this macro will return equate to 1 if ++ * bt_use_count is 0, indicating that there are no active users and if bt_use_count ++ * is non zero it would return 0 there by preventing the caller from executing the ++ * sleep calls. ++ */ ++#ifdef BT_OVER_SDIO ++#define NO_OTHER_ACTIVE_BUS_USER(bus) (bus->bt_use_count == 0) ++#else ++#define NO_OTHER_ACTIVE_BUS_USER(bus) (1) ++#endif /* BT_OVER_SDIO */ ++ ++/* clkstate */ ++#define CLK_NONE 0 ++#define CLK_SDONLY 1 ++#define CLK_PENDING 2 /* Not used yet */ ++#define CLK_AVAIL 3 ++ ++#define DHD_NOPMU(dhd) (FALSE) ++ ++#if defined(BCMSDIOH_STD) ++#define BLK_64_MAXTXGLOM 20 ++#endif /* BCMSDIOH_STD */ ++ ++#ifdef DHD_DEBUG ++static int qcount[NUMPRIO]; ++static int tx_packets[NUMPRIO]; ++#endif /* DHD_DEBUG */ ++ ++/* Deferred transmit */ ++const uint dhd_deferred_tx = 1; ++ ++extern uint dhd_watchdog_ms; ++extern uint sd_f1_blocksize; ++ ++ ++#if defined(BT_OVER_SDIO) ++extern dhd_pub_t *g_dhd_pub; ++#endif /* (BT_OVER_SDIO) */ ++extern void dhd_os_wd_timer(void *bus, uint wdtick); ++int dhd_enableOOB(dhd_pub_t *dhd, bool sleep); ++ ++ ++/* Tx/Rx bounds */ ++uint dhd_txbound; ++uint dhd_rxbound; ++uint dhd_txminmax = DHD_TXMINMAX; ++ ++/* override the RAM size if possible */ ++#define DONGLE_MIN_RAMSIZE (128 *1024) ++int dhd_dongle_ramsize; ++ ++uint dhd_doflow = TRUE; ++uint dhd_dpcpoll = FALSE; ++ ++module_param(dhd_doflow, uint, 0644); ++module_param(dhd_dpcpoll, uint, 0644); ++ ++static bool dhd_alignctl; ++ ++static bool sd1idle; ++ ++static bool retrydata; ++#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) ++ ++static uint watermark = 8; ++static uint mesbusyctrl = 0; ++static const uint firstread = DHD_FIRSTREAD; ++ ++/* 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 ++ ++#if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN) ++extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); ++#endif ++ ++#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) ++#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD ++#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ ++#define PKTALIGN(osh, p, len, align) \ ++ do { \ ++ uintptr datalign; \ ++ datalign = (uintptr)PKTDATA((osh), (p)); \ ++ datalign = ROUNDUP(datalign, (align)) - datalign; \ ++ ASSERT(datalign < (align)); \ ++ ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ ++ if (datalign) \ ++ PKTPULL((osh), (p), (uint)datalign); \ ++ PKTSETLEN((osh), (p), (len)); \ ++ } while (0) ++ ++/* Limit on rounding up frames */ ++static const uint max_roundup = 512; ++ ++/* Try doing readahead */ ++static bool dhd_readahead; ++ ++#if defined(BCMSDIOH_TXGLOM_EXT) ++bool ++dhdsdio_is_dataok(dhd_bus_t *bus) { ++ return (((uint8)(bus->tx_max - bus->tx_seq) - bus->dhd->conf->tx_max_offset > 1) && \ ++ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)); ++} ++ ++uint8 ++dhdsdio_get_databufcnt(dhd_bus_t *bus) { ++ return ((uint8)(bus->tx_max - bus->tx_seq) - 1 - bus->dhd->conf->tx_max_offset); ++} ++#endif ++ ++/* To check if there's window offered */ ++#if defined(BCMSDIOH_TXGLOM_EXT) ++#define DATAOK(bus) dhdsdio_is_dataok(bus) ++#else ++#define DATAOK(bus) \ ++ (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ ++ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) ++#endif ++ ++/* To check if there's window offered for ctrl frame */ ++#define TXCTLOK(bus) \ ++ (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ ++ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) ++ ++/* Number of pkts available in dongle for data RX */ ++#if defined(BCMSDIOH_TXGLOM_EXT) ++#define DATABUFCNT(bus) dhdsdio_get_databufcnt(bus) ++#else ++#define DATABUFCNT(bus) \ ++ ((uint8)(bus->tx_max - bus->tx_seq) - 1) ++#endif ++ ++/* Macros to get register read/write status */ ++/* NOTE: these assume a local dhdsdio_bus_t *bus! */ ++#define R_SDREG(regvar, regaddr, retryvar) \ ++do { \ ++ retryvar = 0; \ ++ do { \ ++ regvar = R_REG(bus->dhd->osh, regaddr); \ ++ } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ ++ if (retryvar) { \ ++ bus->regfails += (retryvar-1); \ ++ if (retryvar > retry_limit) { \ ++ DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \ ++ __FUNCTION__, __LINE__)); \ ++ regvar = 0; \ ++ } \ ++ } \ ++} while (0) ++ ++#define W_SDREG(regval, regaddr, retryvar) \ ++do { \ ++ retryvar = 0; \ ++ do { \ ++ W_REG(bus->dhd->osh, regaddr, regval); \ ++ } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ ++ if (retryvar) { \ ++ bus->regfails += (retryvar-1); \ ++ if (retryvar > retry_limit) \ ++ DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \ ++ __FUNCTION__, __LINE__)); \ ++ } \ ++} while (0) ++ ++#define BUS_WAKE(bus) \ ++ do { \ ++ bus->idlecount = 0; \ ++ if ((bus)->sleeping) \ ++ dhdsdio_bussleep((bus), FALSE); \ ++ } while (0); ++ ++/* ++ * pktavail interrupts from dongle to host can be managed in 3 different ways ++ * whenever there is a packet available in dongle to transmit to host. ++ * ++ * Mode 0: Dongle writes the software host mailbox and host is interrupted. ++ * Mode 1: (sdiod core rev >= 4) ++ * Device sets a new bit in the intstatus whenever there is a packet ++ * available in fifo. Host can't clear this specific status bit until all the ++ * packets are read from the FIFO. No need to ack dongle intstatus. ++ * Mode 2: (sdiod core rev >= 4) ++ * Device sets a bit in the intstatus, and host acks this by writing ++ * one to this bit. Dongle won't generate anymore packet interrupts ++ * until host reads all the packets from the dongle and reads a zero to ++ * figure that there are no more packets. No need to disable host ints. ++ * Need to ack the intstatus. ++ */ ++ ++#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ ++#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ ++#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ ++ ++ ++#define FRAME_AVAIL_MASK(bus) \ ++ ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) ++ ++#define DHD_BUS SDIO_BUS ++ ++#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) ++ ++#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) ++ ++#define GSPI_PR55150_BAILOUT ++ ++#ifdef SDTEST ++static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); ++static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count); ++#endif ++ ++static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size); ++#ifdef DHD_DEBUG ++static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); ++#endif /* DHD_DEBUG */ ++ ++#if defined(DHD_FW_COREDUMP) ++static int dhdsdio_mem_dump(dhd_bus_t *bus); ++#endif /* DHD_FW_COREDUMP */ ++static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap); ++static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); ++ ++static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); ++static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); ++static void dhdsdio_disconnect(void *ptr); ++static bool dhdsdio_chipmatch(uint16 chipid); ++static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, ++ void * regsva, uint16 devid); ++static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); ++static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); ++static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, ++ bool reset_flag); ++ ++static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size); ++static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); ++static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry); ++static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt); ++static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq, ++ int prev_chain_total_len, bool last_chained_pkt, ++ int *pad_pkt_len, void **new_pkt ++#if defined(BCMSDIOH_TXGLOM_EXT) ++ , int first_frame ++#endif ++); ++static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt); ++ ++static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); ++static int _dhdsdio_download_firmware(dhd_bus_t *bus); ++ ++#ifdef DHD_UCODE_DOWNLOAD ++static int dhdsdio_download_ucode_file(struct dhd_bus *bus, char *ucode_path); ++#endif /* DHD_UCODE_DOWNLOAD */ ++static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); ++static int dhdsdio_download_nvram(dhd_bus_t *bus); ++#ifdef BCMEMBEDIMAGE ++static int dhdsdio_download_code_array(dhd_bus_t *bus); ++#endif ++static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep); ++static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok); ++static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus); ++static bool dhdsdio_dpc(dhd_bus_t *bus); ++static int dhd_bcmsdh_send_buffer(void *bus, uint8 *frame, uint16 len); ++static int dhdsdio_set_sdmode(dhd_bus_t *bus, int32 sd_mode); ++static int dhdsdio_sdclk(dhd_bus_t *bus, bool on); ++static void dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp); ++static void dhdsdio_advertise_bus_remove(dhd_pub_t *dhdp); ++#ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT ++int dhd_get_system_rev(void); ++#endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */ ++ ++#ifdef WLMEDIA_HTSF ++#include ++extern uint32 dhd_get_htsf(void *dhd, int ifidx); ++#endif /* WLMEDIA_HTSF */ ++ ++#if defined(BT_OVER_SDIO) ++static int extract_hex_field(char * line, uint16 start_pos, uint16 num_chars, uint16 * value); ++static int read_more_btbytes(struct dhd_bus *bus, void * file, char *line, int * addr_mode, ++ uint16 * hi_addr, uint32 * dest_addr, uint8 *data_bytes, uint32 * num_bytes); ++static int dhdsdio_download_btfw(struct dhd_bus *bus, osl_t *osh, void *sdh); ++static int _dhdsdio_download_btfw(struct dhd_bus *bus); ++#endif /* defined (BT_OVER_SDIO) */ ++ ++#ifdef DHD_ULP ++#include ++static int dhd_bus_ulp_reinit_fw(dhd_bus_t *bus); ++#endif /* DHD_ULP */ ++ ++#ifdef DHD_WAKE_STATUS ++int bcmsdh_get_total_wake(bcmsdh_info_t *bcmsdh); ++int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag); ++#endif /* DHD_WAKE_STATUS */ ++ ++static void ++dhdsdio_tune_fifoparam(struct dhd_bus *bus) ++{ ++ int err; ++ uint8 devctl, wm, mes; ++ ++ if (bus->sih->buscorerev >= 15) { ++ /* See .ppt in PR for these recommended values */ ++ if (bus->blocksize == 512) { ++ wm = OVERFLOW_BLKSZ512_WM; ++ mes = OVERFLOW_BLKSZ512_MES; ++ } else { ++ mes = bus->blocksize/4; ++ wm = bus->blocksize/4; ++ } ++ ++ watermark = wm; ++ mesbusyctrl = mes; ++ } else { ++ DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n", ++ bus->sih->buscorerev)); ++ return; ++ } ++ ++ /* Update watermark */ ++ if (wm > 0) { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err); ++ ++ devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ devctl |= SBSDIO_DEVCTL_F2WM_ENAB; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ } ++ ++ /* Update MES */ ++ if (mes > 0) { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, ++ (mes | SBSDIO_MESBUSYCTRL_ENAB), &err); ++ } ++ ++ DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n", ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err), ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err), ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err))); ++} ++ ++static void ++dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size) ++{ ++ int32 min_size = DONGLE_MIN_RAMSIZE; ++ /* Restrict the ramsize to user specified limit */ ++ DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", ++ dhd_dongle_ramsize, min_size)); ++ if ((dhd_dongle_ramsize > min_size) && ++ (dhd_dongle_ramsize < (int32)bus->orig_ramsize)) ++ bus->ramsize = dhd_dongle_ramsize; ++} ++ ++static int ++dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) ++{ ++ int err = 0; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, ++ (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, ++ (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); ++ if (!err) ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, ++ (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); ++ return err; ++} ++ ++ ++#ifdef USE_OOB_GPIO1 ++static int ++dhdsdio_oobwakeup_init(dhd_bus_t *bus) ++{ ++ uint32 val, addr, data; ++ ++ bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP); ++ ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ ++ /* Set device for gpio1 wakeup */ ++ bcmsdh_reg_write(bus->sdh, addr, 4, 2); ++ val = bcmsdh_reg_read(bus->sdh, data, 4); ++ val |= CC_CHIPCTRL2_GPIO1_WAKEUP; ++ bcmsdh_reg_write(bus->sdh, data, 4, val); ++ ++ bus->_oobwakeup = TRUE; ++ ++ return 0; ++} ++#endif /* USE_OOB_GPIO1 */ ++ ++/* ++ * Query if FW is in SR mode ++ */ ++static bool ++dhdsdio_sr_cap(dhd_bus_t *bus) ++{ ++ bool cap = FALSE; ++ uint32 core_capext, addr, data; ++ ++ if (bus->sih->chip == BCM43430_CHIP_ID || ++ bus->sih->chip == BCM43018_CHIP_ID) { ++ /* check if fw initialized sr engine */ ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, sr_control1); ++ if (bcmsdh_reg_read(bus->sdh, addr, 4) != 0) ++ cap = TRUE; ++ ++ return cap; ++ } ++ if (bus->sih->chip == BCM4324_CHIP_ID) { ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ bcmsdh_reg_write(bus->sdh, addr, 4, 3); ++ core_capext = bcmsdh_reg_read(bus->sdh, data, 4); ++ } else if ((bus->sih->chip == BCM4330_CHIP_ID) || ++ (bus->sih->chip == BCM43362_CHIP_ID) || ++ (BCM4347_CHIP(bus->sih->chip))) { ++ core_capext = FALSE; ++ } else if ((bus->sih->chip == BCM4335_CHIP_ID) || ++ (bus->sih->chip == BCM4339_CHIP_ID) || ++ (bus->sih->chip == BCM43349_CHIP_ID) || ++ BCM4345_CHIP(bus->sih->chip) || ++ (bus->sih->chip == BCM4354_CHIP_ID) || ++ (bus->sih->chip == BCM4358_CHIP_ID) || ++ (bus->sih->chip == BCM43569_CHIP_ID) || ++ (bus->sih->chip == BCM4371_CHIP_ID) || ++ (BCM4349_CHIP(bus->sih->chip)) || ++ (bus->sih->chip == BCM4350_CHIP_ID) || ++ (bus->sih->chip == BCM43012_CHIP_ID) || ++ (bus->sih->chip == BCM4362_CHIP_ID)) { ++ core_capext = TRUE; ++ } else { ++ core_capext = bcmsdh_reg_read(bus->sdh, ++ si_get_pmu_reg_addr(bus->sih, OFFSETOF(chipcregs_t, core_cap_ext)), ++ 4); ++ core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK); ++ } ++ if (!(core_capext)) ++ return FALSE; ++ ++ if (bus->sih->chip == BCM4324_CHIP_ID) { ++ /* FIX: Should change to query SR control register instead */ ++ cap = TRUE; ++ } else if ((bus->sih->chip == BCM4335_CHIP_ID) || ++ (bus->sih->chip == BCM4339_CHIP_ID) || ++ (bus->sih->chip == BCM43349_CHIP_ID) || ++ BCM4345_CHIP(bus->sih->chip) || ++ (bus->sih->chip == BCM4354_CHIP_ID) || ++ (bus->sih->chip == BCM4358_CHIP_ID) || ++ (bus->sih->chip == BCM43569_CHIP_ID) || ++ (bus->sih->chip == BCM4371_CHIP_ID) || ++ (bus->sih->chip == BCM4350_CHIP_ID)) { ++ uint32 enabval = 0; ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3); ++ enabval = bcmsdh_reg_read(bus->sdh, data, 4); ++ ++ if ((bus->sih->chip == BCM4350_CHIP_ID) || ++ BCM4345_CHIP(bus->sih->chip) || ++ (bus->sih->chip == BCM4354_CHIP_ID) || ++ (bus->sih->chip == BCM4358_CHIP_ID) || ++ (bus->sih->chip == BCM43569_CHIP_ID) || ++ (bus->sih->chip == BCM4371_CHIP_ID)) ++ enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE; ++ ++ if (enabval) ++ cap = TRUE; ++ } else { ++ data = bcmsdh_reg_read(bus->sdh, ++ si_get_pmu_reg_addr(bus->sih, OFFSETOF(chipcregs_t, retention_ctl)), ++ 4); ++ if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0) ++ cap = TRUE; ++ } ++ ++ return cap; ++} ++ ++static int ++dhdsdio_srwar_init(dhd_bus_t *bus) ++{ ++ bcmsdh_gpio_init(bus->sdh); ++ ++#ifdef USE_OOB_GPIO1 ++ dhdsdio_oobwakeup_init(bus); ++#endif ++ ++ ++ return 0; ++} ++ ++static int ++dhdsdio_sr_init(dhd_bus_t *bus) ++{ ++ uint8 val; ++ int err = 0; ++ ++ if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) ++ dhdsdio_srwar_init(bus); ++ ++ ++ if (bus->sih->chip == BCM43012_CHIP_ID) { ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); ++ val |= 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, ++ 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT, &err); ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); ++ } else { ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); ++ val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, ++ 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); ++ } ++ ++#ifdef USE_CMD14 ++ /* Add CMD14 Support */ ++ dhdsdio_devcap_set(bus, ++ (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT)); ++#endif /* USE_CMD14 */ ++ ++ if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID || ++ CHIPID(bus->sih->chip) == BCM43018_CHIP_ID || ++ CHIPID(bus->sih->chip) == BCM4339_CHIP_ID || ++ CHIPID(bus->sih->chip) == BCM43012_CHIP_ID || ++ CHIPID(bus->sih->chip) == BCM4362_CHIP_ID) ++ dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC); ++ ++ if (bus->sih->chip == BCM43012_CHIP_ID) { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_HT_AVAIL_REQ, &err); ++ } else { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err); ++ } ++ bus->_slpauto = dhd_slpauto ? TRUE : FALSE; ++ ++ bus->_srenab = TRUE; ++ ++ return 0; ++} ++ ++/* ++ * FIX: Be sure KSO bit is enabled ++ * Currently, it's defaulting to 0 which should be 1. ++ */ ++static int ++dhdsdio_clk_kso_init(dhd_bus_t *bus) ++{ ++ uint8 val; ++ int err = 0; ++ ++ /* set flag */ ++ bus->kso = TRUE; ++ ++ /* ++ * Enable KeepSdioOn (KSO) bit for normal operation ++ * Default is 0 (4334A0) so set it. Fixed in B0. ++ */ ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL); ++ if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { ++ val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); ++ if (err) ++ DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err)); ++ } ++ ++ return 0; ++} ++ ++#define KSO_DBG(x) ++#define KSO_WAIT_US 50 ++#define KSO_WAIT_MS 1 ++#define KSO_SLEEP_RETRY_COUNT 20 ++#define KSO_WAKE_RETRY_COUNT 100 ++#define ERROR_BCME_NODEVICE_MAX 1 ++ ++#define DEFAULT_MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) ++#ifndef CUSTOM_MAX_KSO_ATTEMPTS ++#define CUSTOM_MAX_KSO_ATTEMPTS DEFAULT_MAX_KSO_ATTEMPTS ++#endif ++ ++static int ++dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) ++{ ++ uint8 wr_val = 0, rd_val, cmp_val, bmask; ++ int err = 0; ++ int try_cnt = 0; ++ ++ KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"))); ++ ++ wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); ++ ++ ++ /* In case of 43012 chip, the chip could go down immediately after KSO bit is cleared. ++ * So the further reads of KSO register could fail. Thereby just bailing out immediately ++ * after clearing KSO bit, to avoid polling of KSO bit. ++ */ ++ if ((!on) && (bus->sih->chip == BCM43012_CHIP_ID)) { ++ return err; ++ } ++ ++ if (on) { ++ cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK; ++ bmask = cmp_val; ++ ++ OSL_SLEEP(3); ++ ++ } else { ++ /* Put device to sleep, turn off KSO */ ++ cmp_val = 0; ++ bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK; ++ } ++ ++ do { ++ rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); ++ if (((rd_val & bmask) == cmp_val) && !err) ++ break; ++ ++ KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err)); ++ ++ if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) { ++ OSL_SLEEP(KSO_WAIT_MS); ++ } else ++ OSL_DELAY(KSO_WAIT_US); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err); ++ } while (try_cnt++ < CUSTOM_MAX_KSO_ATTEMPTS); ++ ++ ++ if (try_cnt > 2) ++ KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n", ++ __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); ++ ++ if (try_cnt > CUSTOM_MAX_KSO_ATTEMPTS) { ++ DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n", ++ __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err)); ++ } ++ ++ return err; ++} ++ ++static int ++dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on) ++{ ++ int err = 0; ++ ++ if (on == FALSE) { ++ ++ BUS_WAKE(bus); ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__, ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err))); ++ dhdsdio_clk_kso_enab(bus, FALSE); ++ } else { ++ DHD_ERROR(("%s: KSO enable\n", __FUNCTION__)); ++ ++ /* Make sure we have SD bus access */ ++ if (bus->clkstate == CLK_NONE) { ++ DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__)); ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ } ++ ++ dhdsdio_clk_kso_enab(bus, TRUE); ++ ++ DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__, ++ dhdsdio_sleepcsr_get(bus))); ++ } ++ ++ bus->kso = on; ++ BCM_REFERENCE(err); ++ ++ return 0; ++} ++ ++static uint8 ++dhdsdio_sleepcsr_get(dhd_bus_t *bus) ++{ ++ int err = 0; ++ uint8 val = 0; ++ ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); ++ if (err) ++ DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err)); ++ ++ return val; ++} ++ ++uint8 ++dhdsdio_devcap_get(dhd_bus_t *bus) ++{ ++ return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL); ++} ++ ++static int ++dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap) ++{ ++ int err = 0; ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err); ++ if (err) ++ DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err)); ++ ++ return 0; ++} ++ ++static int ++dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) ++{ ++ int err = 0, retry; ++ uint8 val; ++ ++ retry = 0; ++ if (on == TRUE) { ++ /* Enter Sleep */ ++ ++ /* Be sure we request clk before going to sleep ++ * so we can wake-up with clk request already set ++ * else device can go back to sleep immediately ++ */ ++ if (!SLPAUTO_ENAB(bus)) ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ else { ++ val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if ((val & SBSDIO_CSR_MASK) == 0) { ++ DHD_ERROR(("%s: No clock before enter sleep:0x%x\n", ++ __FUNCTION__, val)); ++ ++ /* Reset clock request */ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ SBSDIO_ALP_AVAIL_REQ, &err); ++ DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__, ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err))); ++ } ++ } ++ ++ DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__, ++ bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err))); ++#ifdef USE_CMD14 ++ err = bcmsdh_sleep(bus->sdh, TRUE); ++#else ++ if ((SLPAUTO_ENAB(bus)) && (bus->idleclock == DHD_IDLE_STOP)) { ++ if (sd1idle) { ++ /* Change to SD1 mode */ ++ dhdsdio_set_sdmode(bus, 1); ++ } ++ } ++ ++ err = dhdsdio_clk_kso_enab(bus, FALSE); ++ if (OOB_WAKEUP_ENAB(bus)) ++ { ++ err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */ ++ } ++#endif /* USE_CMD14 */ ++ ++ if ((SLPAUTO_ENAB(bus)) && (bus->idleclock != DHD_IDLE_ACTIVE)) { ++ DHD_TRACE(("%s: Turnoff SD clk\n", __FUNCTION__)); ++ /* Now remove the SD clock */ ++ err = dhdsdio_sdclk(bus, FALSE); ++ } ++ } else { ++ /* Exit Sleep */ ++ /* Make sure we have SD bus access */ ++ if (bus->clkstate == CLK_NONE) { ++ DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__)); ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ } ++ ++ if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) { ++ SPINWAIT_SLEEP(sdioh_spinwait_sleep, ++ (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), ++ GPIO_DEV_SRSTATE_TIMEOUT); ++ ++ if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) { ++ DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n")); ++ } ++ } ++#ifdef USE_CMD14 ++ err = bcmsdh_sleep(bus->sdh, FALSE); ++ if (SLPAUTO_ENAB(bus) && (err != 0)) { ++ OSL_DELAY(10000); ++ DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__)); ++ ++ /* Toggle sleep to resync with host and device */ ++ err = bcmsdh_sleep(bus->sdh, TRUE); ++ OSL_DELAY(10000); ++ err = bcmsdh_sleep(bus->sdh, FALSE); ++ ++ if (err) { ++ OSL_DELAY(10000); ++ DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__)); ++ ++ /* Toggle sleep to resync with host and device */ ++ err = bcmsdh_sleep(bus->sdh, TRUE); ++ OSL_DELAY(10000); ++ err = bcmsdh_sleep(bus->sdh, FALSE); ++ if (err) { ++ DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__)); ++ DHD_ERROR(("%s: FATAL: Device non-response!\n", ++ __FUNCTION__)); ++ err = 0; ++ } ++ } ++ } ++#else ++ if (OOB_WAKEUP_ENAB(bus)) ++ { ++ err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */ ++ } ++ do { ++ err = dhdsdio_clk_kso_enab(bus, TRUE); ++ if (err) ++ OSL_SLEEP(10); ++ } while ((err != 0) && (++retry < 3)); ++ ++ if (err != 0) { ++ DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry)); ++#ifndef BT_OVER_SDIO ++ err = 0; /* continue anyway */ ++#endif /* BT_OVER_SDIO */ ++ } ++ ++ if ((SLPAUTO_ENAB(bus)) && (bus->idleclock == DHD_IDLE_STOP)) { ++ dhdsdio_set_sdmode(bus, bus->sd_mode); ++ } ++#endif /* !USE_CMD14 */ ++ ++ if (err == 0) { ++ uint8 csr; ++ ++ /* Wait for device ready during transition to wake-up */ ++ SPINWAIT_SLEEP(sdioh_spinwait_sleep, ++ (((csr = dhdsdio_sleepcsr_get(bus)) & ++ SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != ++ (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000)); ++ ++ DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr)); ++ ++ if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) { ++ DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n", ++ __FUNCTION__, csr)); ++ err = BCME_NODEVICE; ++ } ++ ++ SPINWAIT_SLEEP(sdioh_spinwait_sleep, ++ (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) != ++ (SBSDIO_HT_AVAIL)), (DHD_WAIT_HTAVAIL)); ++ ++ DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr)); ++ if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) { ++ DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n", ++ __FUNCTION__, csr)); ++ err = BCME_NODEVICE; ++ } ++ } ++ } ++ ++ /* Update if successful */ ++ if (err == 0) ++ bus->kso = on ? FALSE : TRUE; ++ else { ++ DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n", ++ __FUNCTION__, bus->kso, on, err)); ++ if (!on && retry > 2) ++ bus->kso = FALSE; ++ } ++ ++ return err; ++} ++ ++/* Turn backplane clock on or off */ ++static int ++dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) ++{ ++#define HT_AVAIL_ERROR_MAX 10 ++ static int ht_avail_error = 0; ++ int err; ++ uint8 clkctl, clkreq, devctl; ++ bcmsdh_info_t *sdh; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ clkctl = 0; ++ sdh = bus->sdh; ++ ++ ++ if (!KSO_ENAB(bus)) ++ return BCME_OK; ++ ++ if (SLPAUTO_ENAB(bus)) { ++ bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); ++ return BCME_OK; ++ } ++ ++ if (on) { ++ /* Request HT Avail */ ++ clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; ++ ++ ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); ++ if (err) { ++ ht_avail_error++; ++ if (ht_avail_error < HT_AVAIL_ERROR_MAX) { ++ DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++ else if (ht_avail_error == HT_AVAIL_ERROR_MAX) { ++ bus->dhd->hang_reason = HANG_REASON_HT_AVAIL_ERROR; ++ dhd_os_send_hang_message(bus->dhd); ++ } ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ ++ return BCME_ERROR; ++ } else { ++ ht_avail_error = 0; ++ } ++ ++ ++ /* Check current status */ ++ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (err) { ++ DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err)); ++ return BCME_ERROR; ++ } ++ ++#if !defined(OOB_INTR_ONLY) ++ /* Go to pending and await interrupt if appropriate */ ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { ++ /* Allow only clock-available interrupt */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ DHD_ERROR(("%s: Devctl access error setting CA: %d\n", ++ __FUNCTION__, err)); ++ return BCME_ERROR; ++ } ++ ++ devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ DHD_INFO(("CLKCTL: set PENDING\n")); ++ bus->clkstate = CLK_PENDING; ++ return BCME_OK; ++ } else ++#endif /* !defined (OOB_INTR_ONLY) */ ++ { ++ if (bus->clkstate == CLK_PENDING) { ++ /* Cancel CA-only interrupt filter */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ } ++ } ++ ++ /* Otherwise, wait here (polling) for HT Avail */ ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { ++ SPINWAIT_SLEEP(sdioh_spinwait_sleep, ++ ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, &err)), ++ !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); ++ } ++ if (err) { ++ DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); ++ return BCME_ERROR; ++ } ++ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { ++ DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n", ++ __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl)); ++ return BCME_ERROR; ++ } ++ ++ /* Mark clock available */ ++ bus->clkstate = CLK_AVAIL; ++ DHD_INFO(("CLKCTL: turned ON\n")); ++ ++#if defined(DHD_DEBUG) ++ if (bus->alp_only == TRUE) { ++#if !defined(BCMLXSDMMC) ++ if (!SBSDIO_ALPONLY(clkctl)) { ++ DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__)); ++ } ++#endif /* !defined(BCMLXSDMMC) */ ++ } else { ++ if (SBSDIO_ALPONLY(clkctl)) { ++ DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__)); ++ } ++ } ++#endif /* defined (DHD_DEBUG) */ ++ ++ bus->activity = TRUE; ++#ifdef DHD_USE_IDLECOUNT ++ bus->idlecount = 0; ++#endif /* DHD_USE_IDLECOUNT */ ++ } else { ++ clkreq = 0; ++ ++ if (bus->clkstate == CLK_PENDING) { ++ /* Cancel CA-only interrupt filter */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ } ++ ++ bus->clkstate = CLK_SDONLY; ++ if (!SR_ENAB(bus)) { ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); ++ DHD_INFO(("CLKCTL: turned OFF\n")); ++ if (err) { ++ DHD_ERROR(("%s: Failed access turning clock off: %d\n", ++ __FUNCTION__, err)); ++ return BCME_ERROR; ++ } ++ } ++ } ++ return BCME_OK; ++} ++ ++/* Change SD1/SD4 bus mode */ ++static int ++dhdsdio_set_sdmode(dhd_bus_t *bus, int32 sd_mode) ++{ ++ int err; ++ ++ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, ++ &sd_mode, sizeof(sd_mode), TRUE); ++ if (err) { ++ DHD_ERROR(("%s: error changing sd_mode: %d\n", ++ __FUNCTION__, err)); ++ return BCME_ERROR; ++ } ++ return BCME_OK; ++} ++ ++/* Change idle/active SD state */ ++static int ++dhdsdio_sdclk(dhd_bus_t *bus, bool on) ++{ ++ int err; ++ int32 iovalue; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (on) { ++ if (bus->idleclock == DHD_IDLE_STOP) { ++ /* Turn on clock and restore mode */ ++ iovalue = 1; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ DHD_ERROR(("%s: error enabling sd_clock: %d\n", ++ __FUNCTION__, err)); ++ return BCME_ERROR; ++ } ++ ++ } else if (bus->idleclock != DHD_IDLE_ACTIVE) { ++ /* Restore clock speed */ ++ iovalue = bus->sd_divisor; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ DHD_ERROR(("%s: error restoring sd_divisor: %d\n", ++ __FUNCTION__, err)); ++ return BCME_ERROR; ++ } ++ } ++ bus->clkstate = CLK_SDONLY; ++ } else { ++ /* Stop or slow the SD clock itself */ ++ if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) { ++ DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n", ++ __FUNCTION__, bus->sd_divisor, bus->sd_mode)); ++ return BCME_ERROR; ++ } ++ if (bus->idleclock == DHD_IDLE_STOP) { ++ iovalue = 0; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ DHD_ERROR(("%s: error disabling sd_clock: %d\n", ++ __FUNCTION__, err)); ++ return BCME_ERROR; ++ } ++ } else if (bus->idleclock != DHD_IDLE_ACTIVE) { ++ /* Set divisor to idle value */ ++ iovalue = bus->idleclock; ++ err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, ++ &iovalue, sizeof(iovalue), TRUE); ++ if (err) { ++ DHD_ERROR(("%s: error changing sd_divisor: %d\n", ++ __FUNCTION__, err)); ++ return BCME_ERROR; ++ } ++ } ++ bus->clkstate = CLK_NONE; ++ } ++ ++ return BCME_OK; ++} ++ ++/* Transition SD and backplane clock readiness */ ++static int ++dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) ++{ ++ int ret = BCME_OK; ++#ifdef DHD_DEBUG ++ uint oldstate = bus->clkstate; ++#endif /* DHD_DEBUG */ ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ /* Early exit if we're already there */ ++ if (bus->clkstate == target) { ++ if (target == CLK_AVAIL) { ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ bus->activity = TRUE; ++#ifdef DHD_USE_IDLECOUNT ++ bus->idlecount = 0; ++#endif /* DHD_USE_IDLECOUNT */ ++ } ++ return ret; ++ } ++ ++ switch (target) { ++ case CLK_AVAIL: ++ /* Make sure SD clock is available */ ++ if (bus->clkstate == CLK_NONE) ++ dhdsdio_sdclk(bus, TRUE); ++ /* Now request HT Avail on the backplane */ ++ ret = dhdsdio_htclk(bus, TRUE, pendok); ++ if (ret == BCME_OK) { ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ bus->activity = TRUE; ++#ifdef DHD_USE_IDLECOUNT ++ bus->idlecount = 0; ++#endif /* DHD_USE_IDLECOUNT */ ++ } ++ break; ++ ++ case CLK_SDONLY: ++ ++#ifdef BT_OVER_SDIO ++ /* ++ * If the request is to switch off Back plane clock, ++ * confirm that BT is inactive before doing so. ++ * If this call had come from Non Watchdog context any way ++ * the Watchdog would switch off the clock again when ++ * nothing is to be done & Bt has finished using the bus. ++ */ ++ if (bus->bt_use_count != 0) { ++ DHD_INFO(("%s(): Req CLK_SDONLY, BT is active %d not switching off \r\n", ++ __FUNCTION__, bus->bt_use_count)); ++ ret = BCME_OK; ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ break; ++ } ++ ++ DHD_INFO(("%s(): Request CLK_NONE BT is NOT active switching off \r\n", ++ __FUNCTION__)); ++#endif /* BT_OVER_SDIO */ ++ ++ /* Remove HT request, or bring up SD clock */ ++ if (bus->clkstate == CLK_NONE) ++ ret = dhdsdio_sdclk(bus, TRUE); ++ else if (bus->clkstate == CLK_AVAIL) ++ ret = dhdsdio_htclk(bus, FALSE, FALSE); ++ else ++ DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", ++ bus->clkstate, target)); ++ if (ret == BCME_OK) { ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ } ++ break; ++ ++ case CLK_NONE: ++ ++#ifdef BT_OVER_SDIO ++ /* ++ * If the request is to switch off Back plane clock, ++ * confirm that BT is inactive before doing so. ++ * If this call had come from Non Watchdog context any way ++ * the Watchdog would switch off the clock again when ++ * nothing is to be done & Bt has finished using the bus. ++ */ ++ if (bus->bt_use_count != 0) { ++ DHD_INFO(("%s(): Request CLK_NONE BT is active %d not switching off \r\n", ++ __FUNCTION__, bus->bt_use_count)); ++ ret = BCME_OK; ++ break; ++ } ++ ++ DHD_INFO(("%s(): Request CLK_NONE BT is NOT active switching off \r\n", ++ __FUNCTION__)); ++#endif /* BT_OVER_SDIO */ ++ ++ /* Make sure to remove HT request */ ++ if (bus->clkstate == CLK_AVAIL) ++ ret = dhdsdio_htclk(bus, FALSE, FALSE); ++ /* Now remove the SD clock */ ++ ret = dhdsdio_sdclk(bus, FALSE); ++#ifdef DHD_DEBUG ++ if (dhd_console_ms == 0) ++#endif /* DHD_DEBUG */ ++ if (bus->poll == 0) ++ dhd_os_wd_timer(bus->dhd, 0); ++ break; ++ } ++#ifdef DHD_DEBUG ++ DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); ++#endif /* DHD_DEBUG */ ++ ++ return ret; ++} ++ ++static int ++dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) ++{ ++ int err = 0; ++ bcmsdh_info_t *sdh = bus->sdh; ++ sdpcmd_regs_t *regs = bus->regs; ++ uint retries = 0; ++ ++ DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n", ++ (sleep ? "SLEEP" : "WAKE"), ++ (bus->sleeping ? "SLEEP" : "WAKE"))); ++ ++ if (bus->dhd->hang_was_sent) ++ return BCME_ERROR; ++ ++ /* Done if we're already in the requested state */ ++ if (sleep == bus->sleeping) ++ return BCME_OK; ++ ++ /* Going to sleep: set the alarm and turn off the lights... */ ++ if (sleep) { ++ /* Don't sleep if something is pending */ ++#ifdef DHD_USE_IDLECOUNT ++ if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq) || bus->readframes || ++ bus->ctrl_frame_stat) ++#else ++ if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) ++#endif /* DHD_USE_IDLECOUNT */ ++ return BCME_BUSY; ++ ++#ifdef BT_OVER_SDIO ++ /* ++ * The following is the assumption based on which the hook is placed. ++ * From WLAN driver, either from the active contexts OR from the Watchdog contexts ++ * we will be attempting to Go to Sleep. AT that moment if we see that BT is still ++ * actively using the bus, we will return BCME_BUSY from here, but the bus->sleeping ++ * state would not have changed. So the caller can then schedule the Watchdog again ++ * which will come and attempt to sleep at a later point. ++ * ++ * In case if BT is the only one and is the last user, we don't switch off the clock ++ * immediately, we allow the WLAN to decide when to sleep i.e from the watchdog. ++ * Now if the watchdog becomes active and attempts to switch off the clock and if ++ * another WLAN context is active they are any way serialized with sdlock. ++ */ ++ if (bus->bt_use_count != 0) { ++ DHD_INFO(("%s(): Cannot sleep BT is active \r\n", __FUNCTION__)); ++ return BCME_BUSY; ++ } ++#endif /* !BT_OVER_SDIO */ ++ ++ ++ if (!SLPAUTO_ENAB(bus)) { ++ /* Disable SDIO interrupts (no longer interested) */ ++ bcmsdh_intr_disable(bus->sdh); ++ ++ /* Make sure the controller has the bus up */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Tell device to start using OOB wakeup */ ++ W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); ++ if (retries > retry_limit) ++ DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); ++ ++ /* Turn off our contribution to the HT clock request */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); ++ ++ /* Isolate the bus */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, ++ SBSDIO_DEVCTL_PADS_ISO, NULL); ++ } else { ++ /* Leave interrupts enabled since device can exit sleep and ++ * interrupt host ++ */ ++ err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */); ++ } ++ ++ /* Change state */ ++ bus->sleeping = TRUE; ++#if defined(SUPPORT_P2P_GO_PS) ++ wake_up(&bus->bus_sleep); ++#endif /* LINUX && SUPPORT_P2P_GO_PS */ ++ } else { ++ /* Waking up: bus power up is ok, set local state */ ++ ++ if (!SLPAUTO_ENAB(bus)) { ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err); ++ ++ /* Force pad isolation off if possible (in case power never toggled) */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); ++ ++ ++ /* Make sure the controller has the bus up */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Send misc interrupt to indicate OOB not needed */ ++ W_SDREG(0, ®s->tosbmailboxdata, retries); ++ if (retries <= retry_limit) ++ W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); ++ ++ if (retries > retry_limit) ++ DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); ++ ++ /* Make sure we have SD bus access */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ ++ /* Enable interrupts again */ ++ if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) { ++ bus->intdis = FALSE; ++ bcmsdh_intr_enable(bus->sdh); ++ } ++ } else { ++ err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */); ++#ifdef BT_OVER_SDIO ++ if (err < 0) { ++ struct net_device *net = NULL; ++ dhd_pub_t *dhd = bus->dhd; ++ net = dhd_idx2net(dhd, 0); ++ if (net != NULL) { ++ DHD_ERROR(("<<<<<< WIFI HANG by KSO Enabled failure\n")); ++ dhd_os_sdunlock(dhd); ++ net_os_send_hang_message(net); ++ dhd_os_sdlock(dhd); ++ } else { ++ DHD_ERROR(("<<<<< WIFI HANG Fail because net is NULL\n")); ++ } ++ } ++#endif /* BT_OVER_SDIO */ ++ } ++ ++ if (err == 0) { ++ /* Change state */ ++ bus->sleeping = FALSE; ++ } ++ } ++ ++ return err; ++} ++ ++#ifdef BT_OVER_SDIO ++/* ++ * Call this function to Get the Clock running. ++ * Assumes that the caller holds the sdlock. ++ * bus - Pointer to the dhd_bus handle ++ * can_wait - TRUE if the caller can wait until the clock becomes ready ++ * FALSE if the caller cannot wait ++ */ ++int __dhdsdio_clk_enable(struct dhd_bus *bus, bus_owner_t owner, int can_wait) ++{ ++ int ret = BCME_ERROR; ++ ++ BCM_REFERENCE(owner); ++ ++ bus->bt_use_count++; ++ ++ /* ++ * We can call BUS_WAKE, clkctl multiple times, both of the items ++ * have states and if its already ON, no new configuration is done ++ */ ++ ++ /* Wake up the Dongle FW from SR */ ++ BUS_WAKE(bus); ++ ++ /* ++ * Make sure back plane ht clk is on ++ * CLK_AVAIL - Turn On both SD & HT clock ++ */ ++ ret = dhdsdio_clkctl(bus, CLK_AVAIL, can_wait); ++ ++ DHD_INFO(("%s():bt_use_count %d \r\n", __FUNCTION__, ++ bus->bt_use_count)); ++ return ret; ++} ++ ++/* ++ * Call this function to relinquish the Clock. ++ * Assumes that the caller holds the sdlock. ++ * bus - Pointer to the dhd_bus handle ++ * can_wait - TRUE if the caller can wait until the clock becomes ready ++ * FALSE if the caller cannot wait ++ */ ++int __dhdsdio_clk_disable(struct dhd_bus *bus, bus_owner_t owner, int can_wait) ++{ ++ int ret = BCME_ERROR; ++ ++ BCM_REFERENCE(owner); ++ BCM_REFERENCE(can_wait); ++ ++ if (bus->bt_use_count == 0) { ++ DHD_ERROR(("%s(): Clocks are already turned off \r\n", ++ __FUNCTION__)); ++ return ret; ++ } ++ ++ bus->bt_use_count--; ++ ++ /* ++ * When the SDIO Bus is shared between BT & WLAN, we turn Off the clock ++ * once the last user has relinqushed the same. But there are two schemes ++ * in that too. We consider WLAN as the bus master (even if its not ++ * active). Even when the WLAN is OFF the DHD Watchdog is active. ++ * So this Bus Watchdog is the context whill put the Bus to sleep. ++ * Refer dhd_bus_watchdog function ++ */ ++ ++ ret = BCME_OK; ++ DHD_INFO(("%s():bt_use_count %d \r\n", __FUNCTION__, ++ bus->bt_use_count)); ++ return ret; ++} ++ ++void dhdsdio_reset_bt_use_count(struct dhd_bus *bus) ++{ ++ /* reset bt use count */ ++ bus->bt_use_count = 0; ++} ++#endif /* BT_OVER_SDIO */ ++ ++#ifdef USE_DYNAMIC_F2_BLKSIZE ++int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size) ++{ ++ int func_blk_size = function_num; ++ int bcmerr = 0; ++ int result; ++ ++ bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size, ++ sizeof(int), &result, sizeof(int), IOV_GET); ++ ++ if (bcmerr != BCME_OK) { ++ DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__, function_num)); ++ return BCME_ERROR; ++ } ++ ++ if (result != block_size) { ++ DHD_TRACE_HW4(("%s: F%d Block size set from %d to %d\n", ++ __FUNCTION__, function_num, result, block_size)); ++ func_blk_size = function_num << 16 | block_size; ++ bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", NULL, ++ 0, &func_blk_size, sizeof(int32), IOV_SET); ++ if (bcmerr != BCME_OK) { ++ DHD_ERROR(("%s: Set F2 Block size error\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ } ++ ++ return BCME_OK; ++} ++#endif /* USE_DYNAMIC_F2_BLKSIZE */ ++ ++#if defined(OOB_INTR_ONLY) || defined(FORCE_WOWLAN) ++void ++dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) ++{ ++#if defined(HW_OOB) || defined(FORCE_WOWLAN) ++ bcmsdh_enable_hw_oob_intr(bus->sdh, enable); ++#else ++ sdpcmd_regs_t *regs = bus->regs; ++ uint retries = 0; ++ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ if (enable == TRUE) { ++ ++ /* Tell device to start using OOB wakeup */ ++ W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); ++ if (retries > retry_limit) ++ DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); ++ ++ } else { ++ /* Send misc interrupt to indicate OOB not needed */ ++ W_SDREG(0, ®s->tosbmailboxdata, retries); ++ if (retries <= retry_limit) ++ W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); ++ } ++ ++ /* Turn off our contribution to the HT clock request */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++#endif /* !defined(HW_OOB) */ ++} ++#endif ++ ++int ++dhd_bus_txdata(struct dhd_bus *bus, void *pkt) ++{ ++ int ret = BCME_ERROR; ++ osl_t *osh; ++ uint datalen, prec; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ osh = bus->dhd->osh; ++ datalen = PKTLEN(osh, pkt); ++ ++#ifdef SDTEST ++ /* Push the test header if doing loopback */ ++ if (bus->ext_loop) { ++ uint8* data; ++ PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN); ++ data = PKTDATA(osh, pkt); ++ *data++ = SDPCM_TEST_ECHOREQ; ++ *data++ = (uint8)bus->loopid++; ++ *data++ = (datalen >> 0); ++ *data++ = (datalen >> 8); ++ datalen += SDPCM_TEST_HDRLEN; ++ } ++#else /* SDTEST */ ++ BCM_REFERENCE(datalen); ++#endif /* SDTEST */ ++ ++ prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); ++ ++ /* move from dhdsdio_sendfromq(), try to orphan skb early */ ++ if (bus->dhd->conf->orphan_move == 1) ++ PKTORPHAN(pkt, bus->dhd->conf->tsq); ++ ++ /* Check for existing queue, current flow-control, pending event, or pending clock */ ++ if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || ++ (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || ++ (bus->clkstate != CLK_AVAIL)) { ++ bool deq_ret; ++ int pkq_len = 0; ++ ++ DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq))); ++ bus->fcqueued++; ++ ++ /* Priority based enq */ ++ dhd_os_sdlock_txq(bus->dhd); ++ deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec); ++ dhd_os_sdunlock_txq(bus->dhd); ++ ++ if (!deq_ret) { ++#ifdef PROP_TXSTATUS ++ if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0) ++#endif /* PROP_TXSTATUS */ ++ { ++#ifdef DHDTCPACK_SUPPRESS ++ if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) { ++ DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n", ++ __FUNCTION__, __LINE__)); ++ dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); ++ } ++#endif /* DHDTCPACK_SUPPRESS */ ++ dhd_txcomplete(bus->dhd, pkt, FALSE); ++ PKTFREE(osh, pkt, TRUE); ++ } ++ ret = BCME_NORESOURCE; ++ } else ++ ret = BCME_OK; ++ ++ if (dhd_doflow) { ++ dhd_os_sdlock_txq(bus->dhd); ++ pkq_len = pktq_len(&bus->txq); ++ dhd_os_sdunlock_txq(bus->dhd); ++ } ++ if (dhd_doflow && pkq_len >= FCHI) { ++ bool wlfc_enabled = FALSE; ++#ifdef PROP_TXSTATUS ++ wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) != ++ WLFC_UNSUPPORTED); ++#endif ++ if (!wlfc_enabled && dhd_doflow) { ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); ++ } ++ } ++ ++#ifdef DHD_DEBUG ++ dhd_os_sdlock_txq(bus->dhd); ++ if (pktq_plen(&bus->txq, prec) > qcount[prec]) ++ qcount[prec] = pktq_plen(&bus->txq, prec); ++ dhd_os_sdunlock_txq(bus->dhd); ++#endif ++ ++ /* Schedule DPC if needed to send queued packet(s) */ ++ if (dhd_deferred_tx && !bus->dpc_sched) { ++ if (bus->dhd->conf->deferred_tx_len) { ++ if(dhd_os_wd_timer_enabled(bus->dhd) == FALSE) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ if(pktq_len(&bus->txq) >= bus->dhd->conf->deferred_tx_len && ++ dhd_os_wd_timer_enabled(bus->dhd) == FALSE) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ } else { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ } ++ } else { ++ int chan = SDPCM_DATA_CHANNEL; ++ ++#ifdef SDTEST ++ chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL); ++#endif ++ /* Lock: we're about to use shared data/code (and SDIO) */ ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Otherwise, send it now */ ++ BUS_WAKE(bus); ++ /* Make sure back plane ht clk is on, no pending allowed */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); ++ ++ ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE); ++ ++ if (ret != BCME_OK) ++ bus->dhd->tx_errors++; ++ else ++ bus->dhd->dstats.tx_bytes += datalen; ++ ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched && ++ NO_OTHER_ACTIVE_BUS_USER(bus)) { ++ bus->activity = FALSE; ++ dhdsdio_bussleep(bus, TRUE); ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ } ++ ++ return ret; ++} ++ ++/* align packet data pointer and packet length to n-byte boundary, process packet headers, ++ * a new packet may be allocated if there is not enough head and/or tail from for padding. ++ * the caller is responsible for updating the glom size in the head packet (when glom is ++ * used) ++ * ++ * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter ++ * is taken in tx glom mode only ++ * ++ * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment ++ * padding, NULL if not needed, the caller is responsible for freeing the new packet ++ * ++ * return: positive value - length of the packet, including head and tail padding ++ * negative value - errors ++ */ ++static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq, ++ int prev_chain_total_len, bool last_chained_pkt, ++ int *pad_pkt_len, void **new_pkt ++#if defined(BCMSDIOH_TXGLOM_EXT) ++ , int first_frame ++#endif ++) ++{ ++ osl_t *osh; ++ uint8 *frame; ++ int pkt_len; ++ int modulo; ++ int head_padding; ++ int tail_padding = 0; ++ uint32 swheader; ++ uint32 swhdr_offset; ++ bool alloc_new_pkt = FALSE; ++ uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; ++#ifdef PKT_STATICS ++ uint16 len; ++#endif ++ ++ *new_pkt = NULL; ++ osh = bus->dhd->osh; ++ ++#ifdef DHDTCPACK_SUPPRESS ++ if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) { ++ DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", ++ __FUNCTION__, __LINE__)); ++ dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF); ++ } ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++ /* Add space for the SDPCM hardware/software headers */ ++ PKTPUSH(osh, pkt, sdpcm_hdrlen); ++ ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); ++ ++ frame = (uint8*)PKTDATA(osh, pkt); ++ pkt_len = (uint16)PKTLEN(osh, pkt); ++ ++#ifdef WLMEDIA_HTSF ++ frame = (uint8*)PKTDATA(osh, pkt); ++ if (PKTLEN(osh, pkt) >= 100) { ++ htsf_ts = (htsfts_t*) (frame + HTSF_HOSTOFFSET + 12); ++ if (htsf_ts->magic == HTSFMAGIC) { ++ htsf_ts->c20 = get_cycles(); ++ htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); ++ } ++ } ++#endif /* WLMEDIA_HTSF */ ++#ifdef PKT_STATICS ++ len = (uint16)PKTLEN(osh, pkt); ++ switch(chan) { ++ case SDPCM_CONTROL_CHANNEL: ++ tx_statics.ctrl_count++; ++ tx_statics.ctrl_size += len; ++ break; ++ case SDPCM_DATA_CHANNEL: ++ tx_statics.data_count++; ++ tx_statics.data_size += len; ++ break; ++ case SDPCM_GLOM_CHANNEL: ++ tx_statics.glom_count++; ++ tx_statics.glom_size += len; ++ break; ++ case SDPCM_EVENT_CHANNEL: ++ tx_statics.event_count++; ++ tx_statics.event_size += len; ++ break; ++ case SDPCM_TEST_CHANNEL: ++ tx_statics.test_count++; ++ tx_statics.test_size += len; ++ break; ++ ++ default: ++ break; ++ } ++#endif /* PKT_STATICS */ ++#ifdef DHD_DEBUG ++ if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) ++ tx_packets[PKTPRIO(pkt)]++; ++#endif /* DHD_DEBUG */ ++ ++ /* align the data pointer, allocate a new packet if there is not enough space (new ++ * packet data pointer will be aligned thus no padding will be needed) ++ */ ++ head_padding = (uintptr)frame % DHD_SDALIGN; ++ if (PKTHEADROOM(osh, pkt) < head_padding) { ++ head_padding = 0; ++ alloc_new_pkt = TRUE; ++ } else { ++ uint cur_chain_total_len; ++ int chain_tail_padding = 0; ++ ++ /* All packets need to be aligned by DHD_SDALIGN */ ++ modulo = (pkt_len + head_padding) % DHD_SDALIGN; ++ tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0; ++ ++ /* Total pkt chain length needs to be aligned by block size, ++ * unless it is a single pkt chain with total length less than one block size, ++ * which we prefer sending by byte mode. ++ * ++ * Do the chain alignment here if ++ * 1. This is the last pkt of the chain of multiple pkts or a single pkt. ++ * 2-1. This chain is of multiple pkts, or ++ * 2-2. This is a single pkt whose size is longer than one block size. ++ */ ++ cur_chain_total_len = prev_chain_total_len + ++ (head_padding + pkt_len + tail_padding); ++ if (last_chained_pkt && bus->blocksize != 0 && ++ (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) { ++ modulo = cur_chain_total_len % bus->blocksize; ++ chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0; ++ } ++ ++#ifdef DHDENABLE_TAILPAD ++ if (PKTTAILROOM(osh, pkt) < tail_padding) { ++ /* We don't have tail room to align by DHD_SDALIGN */ ++ alloc_new_pkt = TRUE; ++ bus->tx_tailpad_pktget++; ++ } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) { ++ /* We have tail room for tail_padding of this pkt itself, but not for ++ * total pkt chain alignment by block size. ++ * Use the padding packet to avoid memory copy if applicable, ++ * otherwise, just allocate a new pkt. ++ */ ++ if (bus->pad_pkt) { ++ *pad_pkt_len = chain_tail_padding; ++ bus->tx_tailpad_chain++; ++ } else { ++ alloc_new_pkt = TRUE; ++ bus->tx_tailpad_pktget++; ++ } ++ } else ++ /* This last pkt's tailroom is sufficient to hold both tail_padding ++ * of the pkt itself and chain_tail_padding of total pkt chain ++ */ ++#endif /* DHDENABLE_TAILPAD */ ++ tail_padding += chain_tail_padding; ++ } ++ ++ DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n", ++ __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len)); ++ ++ if (alloc_new_pkt) { ++ void *tmp_pkt; ++ int newpkt_size; ++ int cur_total_len; ++ ++ ASSERT(*pad_pkt_len == 0); ++ ++ DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__)); ++ ++ /* head pointer is aligned now, no padding needed */ ++ head_padding = 0; ++ ++ /* update the tail padding as it depends on the head padding, since a new packet is ++ * allocated, the head padding is non longer needed and packet length is chagned ++ */ ++ ++ cur_total_len = prev_chain_total_len + pkt_len; ++ if (last_chained_pkt && bus->blocksize != 0 && ++ (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) { ++ modulo = cur_total_len % bus->blocksize; ++ tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0; ++ } else { ++ modulo = pkt_len % DHD_SDALIGN; ++ tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0; ++ } ++ ++ newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN; ++ bus->dhd->tx_realloc++; ++ tmp_pkt = PKTGET(osh, newpkt_size, TRUE); ++ if (tmp_pkt == NULL) { ++ DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size)); ++ return BCME_NOMEM; ++ } ++ PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN); ++ bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt)); ++ *new_pkt = tmp_pkt; ++ pkt = tmp_pkt; ++ } ++ ++ if (head_padding) ++ PKTPUSH(osh, pkt, head_padding); ++ ++ frame = (uint8*)PKTDATA(osh, pkt); ++ bzero(frame, head_padding + sdpcm_hdrlen); ++ pkt_len = (uint16)PKTLEN(osh, pkt); ++ ++ /* the header has the followming format ++ * 4-byte HW frame tag: length, ~length (for glom this is the total length) ++ * ++ * 8-byte HW extesion flags (glom mode only) as the following: ++ * 2-byte packet length, excluding HW tag and padding ++ * 2-byte frame channel and frame flags (e.g. next frame following) ++ * 2-byte header length ++ * 2-byte tail padding size ++ * ++ * 8-byte SW frame tags as the following ++ * 4-byte flags: host tx seq, channel, data offset ++ * 4-byte flags: TBD ++ */ ++ ++ swhdr_offset = SDPCM_FRAMETAG_LEN; ++ ++ /* hardware frame tag: ++ * ++ * in tx-glom mode, dongle only checks the hardware frame tag in the first ++ * packet and sees it as the total lenght of the glom (including tail padding), ++ * for each packet in the glom, the packet length needs to be updated, (see ++ * below PKTSETLEN) ++ * ++ * in non tx-glom mode, PKTLEN still need to include tail padding as to be ++ * referred to in sdioh_request_buffer(). The tail length will be excluded in ++ * dhdsdio_txpkt_postprocess(). ++ */ ++#if defined(BCMSDIOH_TXGLOM_EXT) ++ if (bus->dhd->conf->txglom_bucket_size) ++ tail_padding = 0; ++#endif ++ *(uint16*)frame = (uint16)htol16(pkt_len); ++ *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len); ++ pkt_len += tail_padding; ++ ++ /* hardware extesion flags */ ++ if (bus->txglom_enable) { ++ uint32 hwheader1; ++ uint32 hwheader2; ++#ifdef BCMSDIOH_TXGLOM_EXT ++ uint32 act_len = pkt_len - tail_padding; ++ uint32 real_pad = 0; ++ if(bus->dhd->conf->txglom_ext && !last_chained_pkt) { ++ tail_padding = 0; ++ if(first_frame == 0) { ++ // first pkt, add pad to bucket size - recv offset ++ pkt_len = bus->dhd->conf->txglom_bucket_size - TXGLOM_RECV_OFFSET; ++ } else { ++ // add pad to bucket size ++ pkt_len = bus->dhd->conf->txglom_bucket_size; ++ } ++ swhdr_offset += SDPCM_HWEXT_LEN; ++ hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (last_chained_pkt << 24); ++ hwheader2 = (pkt_len - act_len) << 16; ++ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); ++ real_pad = pkt_len - act_len; ++ ++ if (PKTTAILROOM(osh, pkt) < real_pad) { ++ DHD_INFO(("%s : insufficient tailroom %d for %d real_pad\n", ++ __func__, (int)PKTTAILROOM(osh, pkt), real_pad)); ++ if (PKTPADTAILROOM(osh, pkt, real_pad)) { ++ DHD_ERROR(("CHK1: padding error size %d\n", real_pad)); ++ } else ++ frame = (uint8 *)PKTDATA(osh, pkt); ++ } ++ } else ++#endif ++ { ++ swhdr_offset += SDPCM_HWEXT_LEN; ++ hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) | ++ (last_chained_pkt << 24); ++ hwheader2 = (tail_padding) << 16; ++ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); ++ } ++ } ++ PKTSETLEN((osh), (pkt), (pkt_len)); ++ ++ /* software frame tags */ ++ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) ++ | (txseq % SDPCM_SEQUENCE_WRAP) | ++ (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); ++ htol32_ua_store(swheader, frame + swhdr_offset); ++ htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader)); ++ ++ return pkt_len; ++} ++ ++static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt) ++{ ++ osl_t *osh; ++ uint8 *frame; ++ int data_offset; ++ int tail_padding; ++ int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0); ++ ++ (void)osh; ++ osh = bus->dhd->osh; ++ ++ /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */ ++ frame = (uint8*)PKTDATA(osh, pkt); ++ ++ DHD_INFO(("%s PKTLEN before postprocess %d", ++ __FUNCTION__, PKTLEN(osh, pkt))); ++ ++ /* PKTLEN still includes tail_padding, so exclude it. ++ * We shall have head_padding + original pkt_len for PKTLEN afterwards. ++ */ ++ if (bus->txglom_enable) { ++ /* txglom pkts have tail_padding length in HW ext header */ ++ tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16; ++ PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding); ++ DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n", ++ tail_padding, PKTLEN(osh, pkt))); ++ } else { ++ /* non-txglom pkts have head_padding + original pkt length in HW frame tag. ++ * We cannot refer to this field for txglom pkts as the first pkt of the chain will ++ * have the field for the total length of the chain. ++ */ ++ PKTSETLEN(osh, pkt, *(uint16*)frame); ++ DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n", ++ *(uint16*)frame, PKTLEN(osh, pkt))); ++ } ++ ++ data_offset = ltoh32_ua(frame + swhdr_offset); ++ data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT; ++ /* Get rid of sdpcm header + head_padding */ ++ PKTPULL(osh, pkt, data_offset); ++ ++ DHD_INFO(("%s data_offset %d, PKTLEN %d\n", ++ __FUNCTION__, data_offset, PKTLEN(osh, pkt))); ++ ++ return BCME_OK; ++} ++ ++static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt) ++{ ++ int i; ++ int ret = 0; ++ osl_t *osh; ++ bcmsdh_info_t *sdh; ++ void *pkt = NULL; ++ void *pkt_chain; ++ int total_len = 0; ++ void *head_pkt = NULL; ++ void *prev_pkt = NULL; ++ int pad_pkt_len = 0; ++ int new_pkt_num = 0; ++ void *new_pkts[MAX_TX_PKTCHAIN_CNT]; ++ bool wlfc_enabled = FALSE; ++ ++ if (bus->dhd->dongle_reset) ++ return BCME_NOTREADY; ++ ++ if (num_pkt <= 0) ++ return BCME_BADARG; ++ ++ sdh = bus->sdh; ++ osh = bus->dhd->osh; ++ /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */ ++ new_pkts[0] = NULL; ++ ++ for (i = 0; i < num_pkt; i++) { ++ int pkt_len; ++ bool last_pkt; ++ void *new_pkt = NULL; ++ ++ pkt = pkts[i]; ++ ASSERT(pkt); ++ last_pkt = (i == num_pkt - 1); ++ pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i, ++ total_len, last_pkt, &pad_pkt_len, &new_pkt ++#if defined(BCMSDIOH_TXGLOM_EXT) ++ , i ++#endif ++ ); ++ if (pkt_len <= 0) ++ goto done; ++ if (new_pkt) { ++ pkt = new_pkt; ++ new_pkts[new_pkt_num++] = new_pkt; ++ } ++ total_len += pkt_len; ++ ++ PKTSETNEXT(osh, pkt, NULL); ++ /* insert the packet into the list */ ++ head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt); ++ prev_pkt = pkt; ++ ++ } ++ ++ /* Update the HW frame tag (total length) in the first pkt of the glom */ ++ if (bus->txglom_enable) { ++ uint8 *frame; ++ ++ total_len += pad_pkt_len; ++ frame = (uint8*)PKTDATA(osh, head_pkt); ++ *(uint16*)frame = (uint16)htol16(total_len); ++ *(((uint16*)frame) + 1) = (uint16)htol16(~total_len); ++ ++ } ++ ++#ifdef DHDENABLE_TAILPAD ++ /* if a padding packet if needed, insert it to the end of the link list */ ++ if (pad_pkt_len) { ++ PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len); ++ PKTSETNEXT(osh, pkt, bus->pad_pkt); ++ } ++#endif /* DHDENABLE_TAILPAD */ ++ ++ /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet ++ * parameter is not NULL, for non packet chian we pass NULL pkt pointer ++ * so it will take the aligned length and buffer pointer. ++ */ ++ pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL; ++ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES); ++ if (ret == BCME_OK) ++ bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP; ++ ++ /* if a padding packet was needed, remove it from the link list as it not a data pkt */ ++ if (pad_pkt_len && pkt) ++ PKTSETNEXT(osh, pkt, NULL); ++ ++done: ++ pkt = head_pkt; ++ while (pkt) { ++ void *pkt_next = PKTNEXT(osh, pkt); ++ PKTSETNEXT(osh, pkt, NULL); ++ dhdsdio_txpkt_postprocess(bus, pkt); ++ pkt = pkt_next; ++ } ++ ++ /* new packets might be allocated due to insufficient room for padding, but we ++ * still have to indicate the original packets to upper layer ++ */ ++ for (i = 0; i < num_pkt; i++) { ++ pkt = pkts[i]; ++ wlfc_enabled = FALSE; ++#ifdef PROP_TXSTATUS ++ if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) { ++ wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) != ++ WLFC_UNSUPPORTED); ++ } ++#endif /* PROP_TXSTATUS */ ++ if (!wlfc_enabled) { ++ PKTSETNEXT(osh, pkt, NULL); ++ dhd_txcomplete(bus->dhd, pkt, ret != 0); ++ if (free_pkt) ++ PKTFREE(osh, pkt, TRUE); ++ } ++ } ++ ++ for (i = 0; i < new_pkt_num; i++) ++ PKTFREE(osh, new_pkts[i], TRUE); ++ ++ return ret; ++} ++ ++static uint ++dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) ++{ ++ uint cnt = 0; ++ uint8 tx_prec_map; ++ uint16 txpktqlen = 0; ++ uint32 intstatus = 0; ++ uint retries = 0; ++ osl_t *osh; ++ uint datalen = 0; ++ dhd_pub_t *dhd = bus->dhd; ++ sdpcmd_regs_t *regs = bus->regs; ++#ifdef DHD_LOSSLESS_ROAMING ++ uint8 *pktdata; ++ struct ether_header *eh; ++#endif /* DHD_LOSSLESS_ROAMING */ ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (!KSO_ENAB(bus)) { ++ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); ++ return BCME_NODEVICE; ++ } ++ ++ osh = dhd->osh; ++ tx_prec_map = ~bus->flowcontrol; ++#ifdef DHD_LOSSLESS_ROAMING ++ tx_prec_map &= dhd->dequeue_prec_map; ++#endif /* DHD_LOSSLESS_ROAMING */ ++ for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) { ++ int i; ++ int num_pkt = 1; ++ void *pkts[MAX_TX_PKTCHAIN_CNT]; ++ int prec_out; ++ ++ dhd_os_sdlock_txq(bus->dhd); ++ if (bus->txglom_enable) { ++ uint32 glomlimit = (uint32)bus->txglomsize; ++#if defined(BCMSDIOH_STD) ++ if (bus->blocksize == 64) { ++ glomlimit = MIN((uint32)bus->txglomsize, BLK_64_MAXTXGLOM); ++ } ++#endif /* BCMSDIOH_STD */ ++ num_pkt = MIN((uint32)DATABUFCNT(bus), glomlimit); ++ num_pkt = MIN(num_pkt, ARRAYSIZE(pkts)); ++ } ++ num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map)); ++ for (i = 0; i < num_pkt; i++) { ++ pkts[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); ++ if (!pkts[i]) { ++ DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n", ++ __FUNCTION__)); ++ ASSERT(0); ++ break; ++ } ++#ifdef DHD_LOSSLESS_ROAMING ++ pktdata = (uint8 *)PKTDATA(osh, pkts[i]); ++#ifdef BDC ++ /* Skip BDC header */ ++ pktdata += BDC_HEADER_LEN + ((struct bdc_header *)pktdata)->dataOffset; ++#endif ++ eh = (struct ether_header *)pktdata; ++ if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { ++ uint8 prio = (uint8)PKTPRIO(pkts[i]); ++ ++ /* Restore to original priority for 802.1X packet */ ++ if (prio == PRIO_8021D_NC) { ++ PKTSETPRIO(pkts[i], dhd->prio_8021x); ++ } ++ } ++#endif /* DHD_LOSSLESS_ROAMING */ ++ if (!bus->dhd->conf->orphan_move) ++ PKTORPHAN(pkts[i], bus->dhd->conf->tsq); ++ datalen += PKTLEN(osh, pkts[i]); ++ } ++ dhd_os_sdunlock_txq(bus->dhd); ++ ++ if (i == 0) ++ break; ++ if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK) ++ dhd->tx_errors++; ++ else { ++ dhd->dstats.tx_bytes += datalen; ++ bus->txglomframes++; ++ bus->txglompkts += num_pkt; ++ } ++ cnt += i; ++#ifdef PKT_STATICS ++ if (num_pkt) { ++ tx_statics.glom_cnt[num_pkt-1]++; ++ if (num_pkt > tx_statics.glom_max) ++ tx_statics.glom_max = num_pkt; ++ } ++#endif ++ ++ /* In poll mode, need to check for other events */ ++ if (!bus->intr && cnt) ++ { ++ /* Check device status, signal pending interrupt */ ++ R_SDREG(intstatus, ®s->intstatus, retries); ++ bus->f2txdata++; ++ if (bcmsdh_regfail(bus->sdh)) ++ break; ++ if (intstatus & bus->hostintmask) ++ bus->ipend = TRUE; ++ } ++ ++ } ++ ++ if (dhd_doflow) { ++ dhd_os_sdlock_txq(bus->dhd); ++ txpktqlen = pktq_len(&bus->txq); ++ dhd_os_sdunlock_txq(bus->dhd); ++ } ++ ++ /* Do flow-control if needed */ ++ if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) { ++ bool wlfc_enabled = FALSE; ++#ifdef PROP_TXSTATUS ++ wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED); ++#endif ++ if (!wlfc_enabled && dhd_doflow && dhd->txoff) { ++ dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); ++ } ++ } ++ ++ return cnt; ++} ++ ++static void ++dhdsdio_sendpendctl(dhd_bus_t *bus) ++{ ++ bcmsdh_info_t *sdh = bus->sdh; ++ int ret; ++ uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; ++ ++ if (bus->txglom_enable) ++ frame_seq += SDPCM_HWEXT_LEN; ++ ++ if (*frame_seq != bus->tx_seq) { ++ DHD_INFO(("%s IOCTL frame seq lag detected!" ++ " frm_seq:%d != bus->tx_seq:%d, corrected\n", ++ __FUNCTION__, *frame_seq, bus->tx_seq)); ++ *frame_seq = bus->tx_seq; ++ } ++ ++ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, ++ NULL, NULL, NULL, 1); ++ if (ret == BCME_OK) ++ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ ++ bus->ctrl_frame_stat = FALSE; ++ dhd_wait_event_wakeup(bus->dhd); ++} ++ ++int ++dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) ++{ ++ static int err_nodevice = 0; ++ uint8 *frame; ++ uint16 len; ++ uint32 swheader; ++ uint8 doff = 0; ++ int ret = -1; ++ uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (bus->dhd->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 (dhd_alignctl) { ++ if ((doff = ((uintptr)frame % DHD_SDALIGN))) { ++ frame -= doff; ++ len += doff; ++ msglen += doff; ++ bzero(frame, doff + sdpcm_hdrlen); ++ } ++ ASSERT(doff < DHD_SDALIGN); ++ } ++ doff += sdpcm_hdrlen; ++ ++ /* Round send length to next SDIO block */ ++ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { ++ uint16 pad = bus->blocksize - (len % bus->blocksize); ++ if ((pad <= bus->roundup) && (pad < bus->blocksize)) ++ len += pad; ++ } else if (len % DHD_SDALIGN) { ++ len += DHD_SDALIGN - (len % DHD_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (forcealign && (len & (ALIGNMENT - 1))) ++ len = ROUNDUP(len, ALIGNMENT); ++ ++ ASSERT(ISALIGNED((uintptr)frame, 2)); ++ ++ ++ /* Need to lock here to protect txseq and SDIO tx calls */ ++ dhd_os_sdlock(bus->dhd); ++ if (bus->dhd->conf->txctl_tmo_fix > 0 && !TXCTLOK(bus)) { ++ bus->ctrl_wait = TRUE; ++ dhd_os_sdunlock(bus->dhd); ++ wait_event_interruptible_timeout(bus->ctrl_tx_wait, TXCTLOK(bus), ++ msecs_to_jiffies(bus->dhd->conf->txctl_tmo_fix)); ++ dhd_os_sdlock(bus->dhd); ++ bus->ctrl_wait = FALSE; ++ } ++ ++ BUS_WAKE(bus); ++ ++ /* Make sure backplane clock is on */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ ++ *(uint16*)frame = htol16((uint16)msglen); ++ *(((uint16*)frame) + 1) = htol16(~msglen); ++ ++ if (bus->txglom_enable) { ++ uint32 hwheader1, hwheader2; ++ /* 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); ++ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN); ++ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN ++ + SDPCM_HWEXT_LEN + sizeof(swheader)); ++ ++ hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24); ++ hwheader2 = (len - (msglen)) << 16; ++ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4); ++ ++ *(uint16*)frame = htol16(len); ++ *(((uint16*)frame) + 1) = htol16(~(len)); ++ } else { ++ /* 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); ++ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); ++ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); ++ } ++ ++#ifdef DHD_ULP ++ dhd_ulp_set_path(bus->dhd, DHD_ULP_TX_CTRL); ++ ++ if (!TXCTLOK(bus) || !dhd_ulp_f2_ready(bus->dhd, bus->sdh)) ++#else ++ if (!TXCTLOK(bus)) ++#endif ++ { ++ DHD_CTL(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", ++ __FUNCTION__, bus->tx_max, bus->tx_seq)); ++ bus->ctrl_frame_stat = TRUE; ++ /* Send from dpc */ ++ bus->ctrl_frame_buf = frame; ++ bus->ctrl_frame_len = len; ++ ++ if (!bus->dpc_sched) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ if (bus->ctrl_frame_stat) { ++ dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); ++ } ++ ++ if (bus->ctrl_frame_stat == FALSE) { ++ DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); ++ ret = 0; ++ } else { ++ bus->dhd->txcnt_timeout++; ++ if (!bus->dhd->hang_was_sent) { ++#ifdef CUSTOMER_HW4_DEBUG ++ uint32 status, retry = 0; ++ R_SDREG(status, &bus->regs->intstatus, retry); ++ DHD_TRACE_HW4(("%s: txcnt_timeout, INT status=0x%08X\n", ++ __FUNCTION__, status)); ++ DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n", ++ __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate)); ++#endif /* CUSTOMER_HW4_DEBUG */ ++ DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", ++ __FUNCTION__, bus->dhd->txcnt_timeout)); ++#ifdef BCMSDIO_RXLIM_POST ++ DHD_ERROR(("%s: rxlim_en=%d, rxlim enable=%d, rxlim_addr=%d\n", ++ __FUNCTION__, ++ bus->dhd->conf->rxlim_en, bus->rxlim_en, bus->rxlim_addr)); ++#endif /* BCMSDIO_RXLIM_POST */ ++ } ++#ifdef DHD_FW_COREDUMP ++ /* Collect socram dump */ ++ if (bus->dhd->memdump_enabled) { ++ /* collect core dump */ ++ bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT_TX; ++ dhd_os_sdunlock(bus->dhd); ++ dhd_bus_mem_dump(bus->dhd); ++ dhd_os_sdlock(bus->dhd); ++ } ++#endif /* DHD_FW_COREDUMP */ ++ ret = -1; ++ bus->ctrl_frame_stat = FALSE; ++ goto done; ++ } ++ } ++ ++ bus->dhd->txcnt_timeout = 0; ++ bus->ctrl_frame_stat = TRUE; ++ ++ if (ret == -1) { ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_CTL_ON()) { ++ prhex("Tx Frame", frame, len); ++ } else if (DHD_HDRS_ON()) { ++ prhex("TxHdr", frame, MIN(len, 16)); ++ } ++#endif ++#ifdef PKT_STATICS ++ tx_statics.ctrl_count++; ++ tx_statics.ctrl_size += len; ++#endif ++ ret = dhd_bcmsdh_send_buffer(bus, frame, len); ++ } ++ bus->ctrl_frame_stat = FALSE; ++#ifdef DHD_ULP ++ dhd_ulp_enable_cached_sbwad(bus->dhd, bus->sdh); ++#endif /* DHD_ULP */ ++ ++done: ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched && ++ NO_OTHER_ACTIVE_BUS_USER(bus)) { ++ bus->activity = FALSE; ++ dhdsdio_bussleep(bus, TRUE); ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ if (ret) ++ bus->dhd->tx_ctlerrs++; ++ else ++ bus->dhd->tx_ctlpkts++; ++ ++ if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT) { ++ return -ETIMEDOUT; ++ } ++ ++ if (ret == BCME_NODEVICE) ++ err_nodevice++; ++ else ++ err_nodevice = 0; ++ ++ return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0; ++} ++ ++int ++dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) ++{ ++ int timeleft; ++ uint rxlen = 0; ++ static uint cnt = 0; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (bus->dhd->dongle_reset) ++ return -EIO; ++ ++ /* Wait until control frame is available */ ++ timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen); ++ ++ dhd_os_sdlock(bus->dhd); ++ rxlen = bus->rxlen; ++ bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); ++ bus->rxlen = 0; ++ dhd_os_sdunlock(bus->dhd); ++ ++ if (bus->dhd->conf->ctrl_resched > 0 && !rxlen && timeleft == 0) { ++ cnt++; ++ if (cnt <= bus->dhd->conf->ctrl_resched) { ++ uint32 status, retry = 0; ++ R_SDREG(status, &bus->regs->intstatus, retry); ++ if ((status & I_HMB_HOST_INT) || PKT_AVAILABLE(bus, status)) { ++ DHD_ERROR(("%s: reschedule dhd_dpc, cnt=%d, status=0x%x\n", ++ __FUNCTION__, cnt, status)); ++ bus->ipend = TRUE; ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ ++ /* Wait until control frame is available */ ++ timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen); ++ ++ dhd_os_sdlock(bus->dhd); ++ rxlen = bus->rxlen; ++ bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); ++ bus->rxlen = 0; ++ dhd_os_sdunlock(bus->dhd); ++ } ++ } ++ } else { ++ cnt = 0; ++ } ++ ++ if (rxlen) { ++ DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", ++ __FUNCTION__, rxlen, msglen)); ++ } else { ++ if (timeleft == 0) { ++#ifdef DHD_DEBUG ++ uint32 status, retry = 0; ++ R_SDREG(status, &bus->regs->intstatus, retry); ++ DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n", ++ __FUNCTION__, status)); ++#else ++ DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__)); ++#endif /* DHD_DEBUG */ ++ if (!bus->dhd->dongle_trap_occured) { ++#ifdef DHD_FW_COREDUMP ++ bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT; ++#endif /* DHD_FW_COREDUMP */ ++ dhd_os_sdlock(bus->dhd); ++ dhdsdio_checkdied(bus, NULL, 0); ++ dhd_os_sdunlock(bus->dhd); ++ } ++ } else { ++ DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__)); ++ if (!bus->dhd->dongle_trap_occured) { ++#ifdef DHD_FW_COREDUMP ++ bus->dhd->memdump_type = DUMP_TYPE_RESUMED_UNKNOWN; ++#endif /* DHD_FW_COREDUMP */ ++ dhd_os_sdlock(bus->dhd); ++ dhdsdio_checkdied(bus, NULL, 0); ++ dhd_os_sdunlock(bus->dhd); ++ } ++ } ++#ifdef DHD_FW_COREDUMP ++ /* Dump the ram image */ ++ if (bus->dhd->memdump_enabled && !bus->dhd->dongle_trap_occured) ++ dhdsdio_mem_dump(bus); ++#endif /* DHD_FW_COREDUMP */ ++ } ++ if (timeleft == 0) { ++ if (rxlen == 0) ++ bus->dhd->rxcnt_timeout++; ++ DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__, ++ bus->dhd->rxcnt_timeout, rxlen)); ++#ifdef DHD_FW_COREDUMP ++ /* collect socram dump */ ++ if (bus->dhd->memdump_enabled) { ++ bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT_RX; ++ dhd_bus_mem_dump(bus->dhd); ++ } ++#endif /* DHD_FW_COREDUMP */ ++ } else { ++ bus->dhd->rxcnt_timeout = 0; ++ } ++ ++ if (rxlen) ++ bus->dhd->rx_ctlpkts++; ++ else ++ bus->dhd->rx_ctlerrs++; ++ ++ if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) { ++ return -ETIMEDOUT; ++ } ++ ++ ++ if (bus->dhd->dongle_trap_occured) ++ return -EREMOTEIO; ++ ++ return rxlen ? (int)rxlen : -EIO; ++} ++ ++/* IOVar table */ ++enum { ++ IOV_INTR = 1, ++ IOV_POLLRATE, ++ IOV_SDREG, ++ IOV_SBREG, ++ IOV_SDCIS, ++ IOV_RAMSIZE, ++ IOV_RAMSTART, ++#ifdef DHD_DEBUG ++ IOV_CHECKDIED, ++ IOV_SERIALCONS, ++#endif /* DHD_DEBUG */ ++ IOV_SET_DOWNLOAD_STATE, ++ IOV_SOCRAM_STATE, ++ IOV_FORCEEVEN, ++ IOV_SDIOD_DRIVE, ++ IOV_READAHEAD, ++ IOV_SDRXCHAIN, ++ IOV_ALIGNCTL, ++ IOV_SDALIGN, ++ IOV_DEVRESET, ++ IOV_CPU, ++#if defined(USE_SDIOFIFO_IOVAR) ++ IOV_WATERMARK, ++ IOV_MESBUSYCTRL, ++#endif /* USE_SDIOFIFO_IOVAR */ ++#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_DONGLEISOLATION, ++ IOV_KSO, ++ IOV_DEVSLEEP, ++ IOV_DEVCAP, ++ IOV_VARS, ++#ifdef SOFTAP ++ IOV_FWPATH, ++#endif ++ IOV_TXGLOMSIZE, ++ IOV_TXGLOMMODE, ++ IOV_HANGREPORT, ++ IOV_TXINRX_THRES, ++ IOV_SDIO_SUSPEND ++}; ++ ++const bcm_iovar_t dhdsdio_iovars[] = { ++ {"intr", IOV_INTR, 0, 0, IOVT_BOOL, 0 }, ++ {"sleep", IOV_SLEEP, 0, 0, IOVT_BOOL, 0 }, ++ {"pollrate", IOV_POLLRATE, 0, 0, IOVT_UINT32, 0 }, ++ {"idletime", IOV_IDLETIME, 0, 0, IOVT_INT32, 0 }, ++ {"idleclock", IOV_IDLECLOCK, 0, 0, IOVT_INT32, 0 }, ++ {"sd1idle", IOV_SD1IDLE, 0, 0, IOVT_BOOL, 0 }, ++ {"ramsize", IOV_RAMSIZE, 0, 0, IOVT_UINT32, 0 }, ++ {"ramstart", IOV_RAMSTART, 0, 0, IOVT_UINT32, 0 }, ++ {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, 0, IOVT_BOOL, 0 }, ++ {"socram_state", IOV_SOCRAM_STATE, 0, 0, IOVT_BOOL, 0 }, ++ {"vars", IOV_VARS, 0, 0, IOVT_BUFFER, 0 }, ++ {"sdiod_drive", IOV_SDIOD_DRIVE, 0, 0, IOVT_UINT32, 0 }, ++ {"readahead", IOV_READAHEAD, 0, 0, IOVT_BOOL, 0 }, ++ {"sdrxchain", IOV_SDRXCHAIN, 0, 0, IOVT_BOOL, 0 }, ++ {"alignctl", IOV_ALIGNCTL, 0, 0, IOVT_BOOL, 0 }, ++ {"sdalign", IOV_SDALIGN, 0, 0, IOVT_BOOL, 0 }, ++ {"devreset", IOV_DEVRESET, 0, 0, IOVT_BOOL, 0 }, ++#ifdef DHD_DEBUG ++ {"sdreg", IOV_SDREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sbreg", IOV_SBREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) }, ++ {"sd_cis", IOV_SDCIS, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, ++ {"forcealign", IOV_FORCEEVEN, 0, 0, IOVT_BOOL, 0 }, ++ {"txbound", IOV_TXBOUND, 0, 0, IOVT_UINT32, 0 }, ++ {"rxbound", IOV_RXBOUND, 0, 0, IOVT_UINT32, 0 }, ++ {"txminmax", IOV_TXMINMAX, 0, 0, IOVT_UINT32, 0 }, ++ {"cpu", IOV_CPU, 0, 0, IOVT_BOOL, 0 }, ++#ifdef DHD_DEBUG ++ {"checkdied", IOV_CHECKDIED, 0, 0, IOVT_BUFFER, 0 }, ++ {"serial", IOV_SERIALCONS, 0, 0, IOVT_UINT32, 0 }, ++#endif /* DHD_DEBUG */ ++#endif /* DHD_DEBUG */ ++#ifdef SDTEST ++ {"extloop", IOV_EXTLOOP, 0, 0, IOVT_BOOL, 0 }, ++ {"pktgen", IOV_PKTGEN, 0, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, ++#endif /* SDTEST */ ++#if defined(USE_SDIOFIFO_IOVAR) ++ {"watermark", IOV_WATERMARK, 0, 0, IOVT_UINT32, 0 }, ++ {"mesbusyctrl", IOV_MESBUSYCTRL, 0, 0, IOVT_UINT32, 0 }, ++#endif /* USE_SDIOFIFO_IOVAR */ ++ {"devcap", IOV_DEVCAP, 0, 0, IOVT_UINT32, 0 }, ++ {"dngl_isolation", IOV_DONGLEISOLATION, 0, 0, IOVT_UINT32, 0 }, ++ {"kso", IOV_KSO, 0, 0, IOVT_UINT32, 0 }, ++ {"devsleep", IOV_DEVSLEEP, 0, 0, IOVT_UINT32, 0 }, ++#ifdef SOFTAP ++ {"fwpath", IOV_FWPATH, 0, 0, IOVT_BUFFER, 0 }, ++#endif ++ {"txglomsize", IOV_TXGLOMSIZE, 0, 0, IOVT_UINT32, 0 }, ++ {"fw_hang_report", IOV_HANGREPORT, 0, 0, IOVT_BOOL, 0 }, ++ {"txinrx_thres", IOV_TXINRX_THRES, 0, 0, IOVT_INT32, 0 }, ++ {"sdio_suspend", IOV_SDIO_SUSPEND, 0, 0, IOVT_UINT32, 0 }, ++ {NULL, 0, 0, 0, 0, 0 } ++}; ++ ++static void ++dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div) ++{ ++ uint q1, q2; ++ ++ if (!div) { ++ bcm_bprintf(strbuf, "%s N/A", desc); ++ } else { ++ q1 = num / div; ++ q2 = (100 * (num - (q1 * div))) / div; ++ bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); ++ } ++} ++ ++void ++dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++#if defined(DHD_WAKE_STATUS) && defined(DHD_WAKE_EVENT_STATUS) ++ int i; ++#endif ++ ++ bcm_bprintf(strbuf, "Bus SDIO structure:\n"); ++ bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", ++ bus->hostintmask, bus->intstatus, bus->sdpcm_ver); ++ bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n", ++ bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, ++ bus->rxlen, bus->rx_seq); ++ bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n", ++ bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); ++ ++#ifdef DHD_WAKE_STATUS ++ bcm_bprintf(strbuf, "wake %u rxwake %u readctrlwake %u\n", ++ bcmsdh_get_total_wake(bus->sdh), bus->wake_counts.rxwake, ++ bus->wake_counts.rcwake); ++#ifdef DHD_WAKE_RX_STATUS ++ bcm_bprintf(strbuf, " unicast %u multicast %u broadcast %u arp %u\n", ++ bus->wake_counts.rx_ucast, bus->wake_counts.rx_mcast, ++ bus->wake_counts.rx_bcast, bus->wake_counts.rx_arp); ++ bcm_bprintf(strbuf, " multi4 %u multi6 %u icmp6 %u multiother %u\n", ++ bus->wake_counts.rx_multi_ipv4, bus->wake_counts.rx_multi_ipv6, ++ bus->wake_counts.rx_icmpv6, bus->wake_counts.rx_multi_other); ++ bcm_bprintf(strbuf, " icmp6_ra %u, icmp6_na %u, icmp6_ns %u\n", ++ bus->wake_counts.rx_icmpv6_ra, bus->wake_counts.rx_icmpv6_na, ++ bus->wake_counts.rx_icmpv6_ns); ++#endif /* DHD_WAKE_RX_STATUS */ ++#ifdef DHD_WAKE_EVENT_STATUS ++ for (i = 0; i < WLC_E_LAST; i++) ++ if (bus->wake_counts.rc_event[i] != 0) ++ bcm_bprintf(strbuf, " %s = %u\n", bcmevent_get_name(i), ++ bus->wake_counts.rc_event[i]); ++ bcm_bprintf(strbuf, "\n"); ++#endif /* DHD_WAKE_EVENT_STATUS */ ++#endif /* DHD_WAKE_STATUS */ ++ ++ bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n", ++ bus->pollrate, bus->pollcnt, bus->regfails); ++ ++ bcm_bprintf(strbuf, "\nAdditional counters:\n"); ++#ifdef DHDENABLE_TAILPAD ++ bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n", ++ bus->tx_tailpad_chain, bus->tx_tailpad_pktget); ++#endif /* DHDENABLE_TAILPAD */ ++ bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n", ++ bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, ++ bus->rxc_errors); ++ bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n", ++ bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); ++ bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n", ++ bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); ++ bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n", ++ bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); ++ bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n", ++ (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, ++ bus->f2txdata, bus->f1regdata); ++ { ++ dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets, ++ (bus->f2rxhdrs + bus->f2rxdata)); ++ dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata); ++ dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets, ++ (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); ++ dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount); ++ bcm_bprintf(strbuf, "\n"); ++ ++ dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts), ++ bus->dhd->rx_packets); ++ dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes); ++ bcm_bprintf(strbuf, "\n"); ++ ++ dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata); ++ dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata); ++ dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets, ++ (bus->f2txdata + bus->f1regdata)); ++ dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount); ++ bcm_bprintf(strbuf, "\n"); ++ ++ dhd_dump_pct(strbuf, "Total: pkts/f2rw", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), ++ (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata)); ++ dhd_dump_pct(strbuf, ", pkts/f1sd", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata); ++ dhd_dump_pct(strbuf, ", pkts/sd", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), ++ (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); ++ dhd_dump_pct(strbuf, ", pkts/int", ++ (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount); ++ bcm_bprintf(strbuf, "\n\n"); ++ } ++ ++#ifdef SDTEST ++ if (bus->pktgen_count) { ++ bcm_bprintf(strbuf, "pktgen config and count:\n"); ++ bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n", ++ bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print, ++ bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen); ++ bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n", ++ bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); ++ } ++#endif /* SDTEST */ ++#ifdef DHD_DEBUG ++ bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", ++ bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not ")); ++ bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup); ++#endif /* DHD_DEBUG */ ++ bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", ++ bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); ++ dhd_dump_pct(strbuf, "Tx: glom pct", (100 * bus->txglompkts), bus->dhd->tx_packets); ++ dhd_dump_pct(strbuf, ", pkts/glom", bus->txglompkts, bus->txglomframes); ++ bcm_bprintf(strbuf, "\n"); ++ bcm_bprintf(strbuf, "txglomframes %u, txglompkts %u\n", bus->txglomframes, bus->txglompkts); ++ bcm_bprintf(strbuf, "\n"); ++} ++ ++void ++dhd_bus_clearcounts(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = (dhd_bus_t *)dhdp->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; ++#ifdef DHDENABLE_TAILPAD ++ bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0; ++#endif /* DHDENABLE_TAILPAD */ ++ 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; ++ bus->txglomframes = bus->txglompkts = 0; ++} ++ ++#ifdef SDTEST ++static int ++dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg) ++{ ++ dhd_pktgen_t pktgen; ++ ++ pktgen.version = DHD_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; ++ ++ bcopy(&pktgen, arg, sizeof(pktgen)); ++ ++ return 0; ++} ++ ++static int ++dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg) ++{ ++ dhd_pktgen_t pktgen; ++ uint oldcnt, oldmode; ++ ++ bcopy(arg, &pktgen, sizeof(pktgen)); ++ if (pktgen.version != DHD_PKTGEN_VERSION) ++ return BCME_BADARG; ++ ++ 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_prev_time = jiffies; ++ 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_prev_sent = bus->pktgen_rcvd = 0; ++ bus->pktgen_prev_rcvd = bus->pktgen_fail = 0; ++ } ++ ++ return 0; ++} ++#endif /* SDTEST */ ++ ++static void ++dhdsdio_devram_remap(dhd_bus_t *bus, bool val) ++{ ++ uint8 enable, protect, remap; ++ ++ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); ++ remap = val ? TRUE : FALSE; ++ si_socdevram(bus->sih, TRUE, &enable, &protect, &remap); ++} ++ ++static int ++dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size) ++{ ++ int bcmerror = 0; ++ uint32 sdaddr; ++ uint dsize; ++ uint8 *pdata; ++ ++ /* In remap mode, adjust address beyond socram and redirect ++ * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize ++ * is not backplane accessible ++ */ ++ if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) { ++ address -= bus->orig_ramsize; ++ address += SOCDEVRAM_BP_ADDR; ++ } ++ ++ /* 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 */ ++ if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { ++ DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); ++ goto xfer_done; ++ } ++ ++ /* Do the transfer(s) */ ++ while (size) { ++ DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n", ++ __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr, ++ (address & SBSDIO_SBWINDOW_MASK))); ++ if (dsize <= MAX_MEM_BUF) { ++ pdata = bus->membuf; ++ if (write) ++ memcpy(bus->membuf, data, dsize); ++ } else { ++ pdata = data; ++ } ++ if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, pdata, dsize))) { ++ DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__)); ++ break; ++ } ++ if (dsize <= MAX_MEM_BUF && !write) ++ memcpy(data, bus->membuf, dsize); ++ ++ /* Adjust for next transfer (if any) */ ++ if ((size -= dsize)) { ++ data += dsize; ++ address += dsize; ++ if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { ++ DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); ++ break; ++ } ++ sdaddr = 0; ++ dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size); ++ } ++ ++ } ++ ++xfer_done: ++ /* Return the window to backplane enumeration space for core access */ ++ if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) { ++ DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__, ++ bcmsdh_cur_sbwad(bus->sdh))); ++ } ++ ++ return bcmerror; ++} ++ ++static int ++dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) ++{ ++ uint32 addr; ++ int rv, i; ++ uint32 shaddr = 0; ++ ++ if (bus->sih == NULL) { ++ if (bus->dhd && bus->dhd->dongle_reset) { ++ DHD_ERROR(("%s: Dongle is in reset state\n", __FUNCTION__)); ++ return BCME_NOTREADY; ++ } else { ++ ASSERT(bus->dhd); ++ ASSERT(bus->sih); ++ DHD_ERROR(("%s: The address of sih is invalid\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ } ++ if ((CHIPID(bus->sih->chip) == BCM43430_CHIP_ID || ++ CHIPID(bus->sih->chip) == BCM43018_CHIP_ID) && !dhdsdio_sr_cap(bus)) ++ bus->srmemsize = 0; ++ ++ shaddr = bus->dongle_ram_base + bus->ramsize - 4; ++ i = 0; ++ do { ++ /* Read last word in memory to determine address of sdpcm_shared structure */ ++ if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) ++ return rv; ++ ++ addr = ltoh32(addr); ++ ++ DHD_INFO(("sdpcm_shared address 0x%08X\n", addr)); ++ ++ /* ++ * Check if addr is valid. ++ * NVRAM length at the end of memory should have been overwritten. ++ */ ++ if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { ++ if ((bus->srmemsize > 0) && (i++ == 0)) { ++ shaddr -= bus->srmemsize; ++ } else { ++ DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", ++ __FUNCTION__, addr)); ++ return BCME_ERROR; ++ } ++ } else ++ break; ++ } while (i < 2); ++ ++ /* Read hndrte_shared structure */ ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) ++ return rv; ++ ++ /* Endianness */ ++ sh->flags = ltoh32(sh->flags); ++ sh->trap_addr = ltoh32(sh->trap_addr); ++ sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); ++ sh->assert_file_addr = ltoh32(sh->assert_file_addr); ++ sh->assert_line = ltoh32(sh->assert_line); ++ sh->console_addr = ltoh32(sh->console_addr); ++ sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); ++ ++#ifdef BCMSDIO_RXLIM_POST ++ if (sh->flags & SDPCM_SHARED_RXLIM_POST) { ++ if (bus->dhd->conf->rxlim_en) ++ bus->rxlim_en = !!sh->msgtrace_addr; ++ bus->rxlim_addr = sh->msgtrace_addr; ++ DHD_INFO(("%s: rxlim_en=%d, rxlim enable=%d, rxlim_addr=%d\n", ++ __FUNCTION__, ++ bus->dhd->conf->rxlim_en, bus->rxlim_en, bus->rxlim_addr)); ++ sh->flags &= ~SDPCM_SHARED_RXLIM_POST; ++ } else { ++ bus->rxlim_en = 0; ++ DHD_INFO(("%s: FW has no rx limit post support\n", __FUNCTION__)); ++ } ++#endif /* BCMSDIO_RXLIM_POST */ ++ ++ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1) ++ return BCME_OK; ++ ++ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { ++ DHD_ERROR(("%s: sdpcm_shared version %d in dhd " ++ "is different than sdpcm_shared version %d in dongle\n", ++ __FUNCTION__, SDPCM_SHARED_VERSION, ++ sh->flags & SDPCM_SHARED_VERSION_MASK)); ++ return BCME_ERROR; ++ } ++ ++ return BCME_OK; ++} ++ ++#define CONSOLE_LINE_MAX 192 ++ ++#ifdef DHD_DEBUG ++static int ++dhdsdio_readconsole(dhd_bus_t *bus) ++{ ++ dhd_console_t *c = &bus->console; ++ uint8 line[CONSOLE_LINE_MAX], ch; ++ uint32 n, idx, addr; ++ int rv; ++ ++ /* Don't do anything until FWREADY updates console address */ ++ if (bus->console_addr == 0) ++ return 0; ++ ++ if (!KSO_ENAB(bus)) ++ return 0; ++ ++ /* Read console log struct */ ++ addr = bus->console_addr + OFFSETOF(hnd_cons_t, log); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) ++ return rv; ++ ++ /* Allocate console buffer (one time only) */ ++ if (c->buf == NULL) { ++ c->bufsize = ltoh32(c->log.buf_size); ++ if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) ++ return BCME_NOMEM; ++ } ++ ++ idx = ltoh32(c->log.idx); ++ ++ /* Protect against corrupt value */ ++ if (idx > c->bufsize) ++ return BCME_ERROR; ++ ++ /* Skip reading the console buffer if the index pointer has not moved */ ++ if (idx == c->last) ++ return BCME_OK; ++ ++ /* Read the console buffer */ ++ addr = ltoh32(c->log.buf); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 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; ++ printf("CONSOLE: %s\n", line); ++#ifdef LOG_INTO_TCPDUMP ++ dhd_sendup_log(bus->dhd, line, n); ++#endif /* LOG_INTO_TCPDUMP */ ++ } ++ } ++break2: ++ ++ return BCME_OK; ++} ++#endif /* DHD_DEBUG */ ++ ++static int ++dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) ++{ ++ int bcmerror = 0; ++ uint msize = 512; ++ char *mbuffer = NULL; ++ char *console_buffer = NULL; ++ uint maxstrlen = 256; ++ char *str = NULL; ++ sdpcm_shared_t l_sdpcm_shared; ++ struct bcmstrbuf strbuf; ++ uint32 console_ptr, console_size, console_index; ++ uint8 line[CONSOLE_LINE_MAX], ch; ++ uint32 n, i, addr; ++ int rv; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (DHD_NOCHECKDIED_ON()) ++ return 0; ++ ++ if (data == NULL) { ++ /* ++ * Called after a rx ctrl timeout. "data" is NULL. ++ * allocate memory to trace the trap or assert. ++ */ ++ size = msize; ++ mbuffer = data = MALLOC(bus->dhd->osh, msize); ++ if (mbuffer == NULL) { ++ DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ } ++ ++ if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { ++ DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); ++ bcmerror = BCME_NOMEM; ++ goto done; ++ } ++ ++ if ((bcmerror = dhdsdio_readshared(bus, &l_sdpcm_shared)) < 0) ++ goto done; ++ ++ bcm_binit(&strbuf, data, size); ++ ++ bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", ++ l_sdpcm_shared.msgtrace_addr, l_sdpcm_shared.console_addr); ++ ++ if ((l_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.) ++ */ ++ bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); ++ } ++ ++ if ((l_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.) ++ */ ++ bcm_bprintf(&strbuf, "No trap%s in dongle", ++ (l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) ++ ?"/assrt" :""); ++ } else { ++ if (l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { ++ /* Download assert */ ++ bcm_bprintf(&strbuf, "Dongle assert"); ++ if (l_sdpcm_shared.assert_exp_addr != 0) { ++ str[0] = '\0'; ++ if ((bcmerror = dhdsdio_membytes(bus, FALSE, ++ l_sdpcm_shared.assert_exp_addr, ++ (uint8 *)str, maxstrlen)) < 0) ++ goto done; ++ ++ str[maxstrlen - 1] = '\0'; ++ bcm_bprintf(&strbuf, " expr \"%s\"", str); ++ } ++ ++ if (l_sdpcm_shared.assert_file_addr != 0) { ++ str[0] = '\0'; ++ if ((bcmerror = dhdsdio_membytes(bus, FALSE, ++ l_sdpcm_shared.assert_file_addr, ++ (uint8 *)str, maxstrlen)) < 0) ++ goto done; ++ ++ str[maxstrlen - 1] = '\0'; ++ bcm_bprintf(&strbuf, " file \"%s\"", str); ++ } ++ ++ bcm_bprintf(&strbuf, " line %d ", l_sdpcm_shared.assert_line); ++ } ++ ++ if (l_sdpcm_shared.flags & SDPCM_SHARED_TRAP) { ++ trap_t *tr = &bus->dhd->last_trap_info; ++ bus->dhd->dongle_trap_occured = TRUE; ++ if ((bcmerror = dhdsdio_membytes(bus, FALSE, ++ l_sdpcm_shared.trap_addr, ++ (uint8*)tr, sizeof(trap_t))) < 0) ++ goto done; ++ ++ bus->dongle_trap_addr = ltoh32(l_sdpcm_shared.trap_addr); ++ ++ dhd_bus_dump_trap_info(bus, &strbuf); ++ ++ addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, ++ (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) ++ goto printbuf; ++ ++ addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.buf_size); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, ++ (uint8 *)&console_size, sizeof(console_size))) < 0) ++ goto printbuf; ++ ++ addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.idx); ++ if ((rv = dhdsdio_membytes(bus, FALSE, addr, ++ (uint8 *)&console_index, sizeof(console_index))) < 0) ++ goto printbuf; ++ ++ console_ptr = ltoh32(console_ptr); ++ console_size = ltoh32(console_size); ++ console_index = ltoh32(console_index); ++ ++ if (console_size > CONSOLE_BUFFER_MAX || ++ !(console_buffer = MALLOC(bus->dhd->osh, console_size))) ++ goto printbuf; ++ ++ if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, ++ (uint8 *)console_buffer, console_size)) < 0) ++ goto printbuf; ++ ++ for (i = 0, n = 0; i < console_size; i += n + 1) { ++ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { ++ ch = console_buffer[(console_index + i + n) % console_size]; ++ if (ch == '\n') ++ break; ++ line[n] = ch; ++ } ++ ++ ++ if (n > 0) { ++ if (line[n - 1] == '\r') ++ n--; ++ line[n] = 0; ++ /* Don't use DHD_ERROR macro since we print ++ * a lot of information quickly. The macro ++ * will truncate a lot of the printfs ++ */ ++ ++ if (dhd_msg_level & DHD_ERROR_VAL) ++ printf("CONSOLE: %s\n", line); ++ } ++ } ++ } ++ } ++ ++printbuf: ++ if (l_sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) { ++ DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); ++ } ++ ++#if defined(DHD_FW_COREDUMP) ++ if (bus->dhd->memdump_enabled && (l_sdpcm_shared.flags & SDPCM_SHARED_TRAP)) { ++ /* Mem dump to a file on device */ ++ bus->dhd->memdump_type = DUMP_TYPE_DONGLE_TRAP; ++ dhd_os_sdunlock(bus->dhd); ++ dhdsdio_mem_dump(bus); ++ dhd_os_sdlock(bus->dhd); ++ } ++#endif /* #if defined(DHD_FW_COREDUMP) */ ++ ++done: ++ if (mbuffer) ++ MFREE(bus->dhd->osh, mbuffer, msize); ++ if (str) ++ MFREE(bus->dhd->osh, str, maxstrlen); ++ if (console_buffer) ++ MFREE(bus->dhd->osh, console_buffer, console_size); ++ ++ return bcmerror; ++} ++ ++#if defined(DHD_FW_COREDUMP) ++int ++dhd_bus_mem_dump(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ if (dhdp->busstate == DHD_BUS_SUSPEND) { ++ DHD_ERROR(("%s: Bus is suspend so skip\n", __FUNCTION__)); ++ return 0; ++ } ++ return dhdsdio_mem_dump(bus); ++} ++ ++static int ++dhdsdio_mem_dump(dhd_bus_t *bus) ++{ ++ int ret = 0; ++ int size; /* Full mem size */ ++ uint32 start = bus->dongle_ram_base; /* Start address */ ++ uint read_size = 0; /* Read size of each iteration */ ++ uint8 *buf = NULL, *databuf = NULL; ++ ++ /* Get full mem size */ ++ size = bus->ramsize; ++ buf = dhd_get_fwdump_buf(bus->dhd, size); ++ if (!buf) { ++ DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__, size)); ++ return -1; ++ } ++ ++ dhd_os_sdlock(bus->dhd); ++ BUS_WAKE(bus); ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Read mem content */ ++ DHD_ERROR(("Dump dongle memory\n")); ++ databuf = buf; ++ while (size) ++ { ++ read_size = MIN(MEMBLOCK, size); ++ if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size))) ++ { ++ DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret)); ++ ret = BCME_ERROR; ++ break; ++ } ++ /* Decrement size and increment start address */ ++ size -= read_size; ++ start += read_size; ++ databuf += read_size; ++ } ++ ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched && ++ NO_OTHER_ACTIVE_BUS_USER(bus)) { ++ bus->activity = FALSE; ++ dhdsdio_clkctl(bus, CLK_NONE, TRUE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ /* schedule a work queue to perform actual memdump. dhd_mem_dump() performs the job */ ++ if (!ret) { ++ /* buf, actually soc_ram free handled in dhd_{free,clear} */ ++ dhd_schedule_memdump(bus->dhd, buf, bus->ramsize); ++ } ++ ++ return ret; ++} ++#endif /* DHD_FW_COREDUMP */ ++ ++int ++dhd_socram_dump(dhd_bus_t * bus) ++{ ++#if defined(DHD_FW_COREDUMP) ++ return (dhdsdio_mem_dump(bus)); ++#else ++ return -1; ++#endif ++} ++ ++int ++dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len) ++{ ++ int bcmerror = BCME_OK; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (bus->dhd->up && ++#ifdef DHD_ULP ++ (DHD_ULP_DISABLED == dhd_ulp_get_ulp_state(bus->dhd)) && ++#endif /* DHD_ULP */ ++ 1) { ++ bcmerror = BCME_NOTDOWN; ++ goto err; ++ } ++ if (!len) { ++ bcmerror = BCME_BUFTOOSHORT; ++ goto err; ++ } ++ ++ /* Free the old ones and replace with passed variables */ ++ if (bus->vars) ++ MFREE(bus->dhd->osh, bus->vars, bus->varsz); ++ ++ bus->vars = MALLOC(bus->dhd->osh, len); ++ bus->varsz = bus->vars ? len : 0; ++ if (bus->vars == NULL) { ++ bcmerror = BCME_NOMEM; ++ goto err; ++ } ++ ++ /* Copy the passed variables, which should include the terminating double-null */ ++ bcopy(arg, bus->vars, bus->varsz); ++err: ++ return bcmerror; ++} ++ ++#ifdef DHD_DEBUG ++ ++#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24) ++#define CC_CHIPCTRL_JTAG_SEL (1 << 3) ++#define CC_CHIPCTRL_GPIO_SEL (0x3) ++#define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28) ++ ++static int ++dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) ++{ ++ int int_val; ++ uint32 addr, data, uart_enab = 0; ++ uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL; ++ uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL; ++ ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); ++ data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); ++ *bcmerror = 0; ++ ++ bcmsdh_reg_write(bus->sdh, addr, 4, 1); ++ if (bcmsdh_regfail(bus->sdh)) { ++ *bcmerror = BCME_SDIO_ERROR; ++ return -1; ++ } ++ int_val = bcmsdh_reg_read(bus->sdh, data, 4); ++ if (bcmsdh_regfail(bus->sdh)) { ++ *bcmerror = BCME_SDIO_ERROR; ++ return -1; ++ } ++ ++ if (bus->sih->chip == BCM4330_CHIP_ID) { ++ uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; ++ } else if (bus->sih->chip == BCM4334_CHIP_ID || ++ bus->sih->chip == BCM43340_CHIP_ID || ++ bus->sih->chip == BCM43341_CHIP_ID || ++ bus->sih->chip == BCM43342_CHIP_ID || ++ 0) { ++ if (enable) { ++ /* Moved to PMU chipcontrol 1 from 4330 */ ++ int_val &= ~gpio_sel; ++ int_val |= jtag_sel; ++ } else { ++ int_val |= gpio_sel; ++ int_val &= ~jtag_sel; ++ } ++ uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334; ++ } ++ ++ if (!set) ++ return (int_val & uart_enab); ++ if (enable) ++ int_val |= uart_enab; ++ else ++ int_val &= ~uart_enab; ++ bcmsdh_reg_write(bus->sdh, data, 4, int_val); ++ if (bcmsdh_regfail(bus->sdh)) { ++ *bcmerror = BCME_SDIO_ERROR; ++ return -1; ++ } ++ if (bus->sih->chip == BCM4330_CHIP_ID) { ++ uint32 chipcontrol; ++ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol); ++ chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4); ++ chipcontrol &= ~jtag_sel; ++ if (enable) { ++ chipcontrol |= jtag_sel; ++ chipcontrol &= ~gpio_sel; ++ } ++ bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol); ++ } ++ ++ return (int_val & uart_enab); ++} ++#endif ++ ++static int ++dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, ++ void *params, int plen, void *arg, int len, int val_size) ++{ ++ int bcmerror = 0; ++ int32 int_val = 0; ++ bool bool_val = 0; ++ ++ DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", ++ __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); ++ ++ if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) ++ goto exit; ++ ++ if (plen >= (int)sizeof(int_val)) ++ bcopy(params, &int_val, sizeof(int_val)); ++ ++ bool_val = (int_val != 0) ? TRUE : FALSE; ++ ++ ++ /* Some ioctls use the bus */ ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ ++ if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || ++ actionid == IOV_GVAL(IOV_DEVRESET))) { ++ bcmerror = BCME_NOTREADY; ++ goto exit; ++ } ++ ++ /* ++ * Special handling for keepSdioOn: New SDIO Wake-up Mechanism ++ */ ++ if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) { ++ dhdsdio_clk_kso_iovar(bus, bool_val); ++ goto exit; ++ } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) { ++ { ++ dhdsdio_clk_devsleep_iovar(bus, bool_val); ++ if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) { ++ DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n", ++ bus->dpc_sched)); ++ if (!bus->dpc_sched) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ } ++ } ++ goto exit; ++ } ++ ++ /* Handle sleep stuff before any clock mucking */ ++ if (vi->varid == IOV_SLEEP) { ++ if (IOV_ISSET(actionid)) { ++ bcmerror = dhdsdio_bussleep(bus, bool_val); ++ } else { ++ int_val = (int32)bus->sleeping; ++ bcopy(&int_val, arg, val_size); ++ } ++ goto exit; ++ } ++ ++ /* Request clock to allow SDIO accesses */ ++ if (!bus->dhd->dongle_reset) { ++ BUS_WAKE(bus); ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ } ++ ++ switch (actionid) { ++ case IOV_GVAL(IOV_INTR): ++ int_val = (int32)bus->intr; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_INTR): ++ bus->intr = bool_val; ++ bus->intdis = FALSE; ++ if (bus->dhd->up) { ++ if (bus->intr) { ++ DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); ++ // terence 20141207: enbale intdis ++ bus->intdis = TRUE; ++ bcmsdh_intr_enable(bus->sdh); ++ } else { ++ DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); ++ bcmsdh_intr_disable(bus->sdh); ++ } ++ } ++ break; ++ ++ case IOV_GVAL(IOV_POLLRATE): ++ int_val = (int32)bus->pollrate; ++ bcopy(&int_val, arg, 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; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_IDLETIME): ++ if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) { ++ bcmerror = BCME_BADARG; ++ } else { ++ bus->idletime = int_val; ++ } ++ break; ++ ++ case IOV_GVAL(IOV_IDLECLOCK): ++ int_val = (int32)bus->idleclock; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_IDLECLOCK): ++ bus->idleclock = int_val; ++ break; ++ ++ case IOV_GVAL(IOV_SD1IDLE): ++ int_val = (int32)sd1idle; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SD1IDLE): ++ sd1idle = bool_val; ++ break; ++ ++ ++ ++ case IOV_GVAL(IOV_RAMSIZE): ++ int_val = (int32)bus->ramsize; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_RAMSTART): ++ int_val = (int32)bus->dongle_ram_base; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_SDIOD_DRIVE): ++ int_val = (int32)dhd_sdiod_drive_strength; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDIOD_DRIVE): ++ dhd_sdiod_drive_strength = int_val; ++ si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength); ++ break; ++ ++ case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): ++ bcmerror = dhdsdio_download_state(bus, bool_val); ++ break; ++ ++ case IOV_SVAL(IOV_SOCRAM_STATE): ++ bcmerror = dhdsdio_download_state(bus, bool_val); ++ break; ++ ++ case IOV_SVAL(IOV_VARS): ++ bcmerror = dhdsdio_downloadvars(bus, arg, len); ++ break; ++ ++ case IOV_GVAL(IOV_READAHEAD): ++ int_val = (int32)dhd_readahead; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_READAHEAD): ++ if (bool_val && !dhd_readahead) ++ bus->nextlen = 0; ++ dhd_readahead = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_SDRXCHAIN): ++ int_val = (int32)bus->use_rxchain; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDRXCHAIN): ++ if (bool_val && !bus->sd_rxchain) ++ bcmerror = BCME_UNSUPPORTED; ++ else ++ bus->use_rxchain = bool_val; ++ break; ++ case IOV_GVAL(IOV_ALIGNCTL): ++ int_val = (int32)dhd_alignctl; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_ALIGNCTL): ++ dhd_alignctl = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_SDALIGN): ++ int_val = DHD_SDALIGN; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++#ifdef DHD_DEBUG ++ case IOV_GVAL(IOV_VARS): ++ if (bus->varsz < (uint)len) ++ bcopy(bus->vars, arg, bus->varsz); ++ else ++ bcmerror = BCME_BUFTOOSHORT; ++ break; ++#endif /* DHD_DEBUG */ ++ ++#ifdef DHD_DEBUG ++ case IOV_GVAL(IOV_SDREG): ++ { ++ sdreg_t *sd_ptr; ++ uintptr addr; ++ uint size; ++ ++ sd_ptr = (sdreg_t *)params; ++ ++ addr = ((uintptr)bus->regs + sd_ptr->offset); ++ size = sd_ptr->func; ++ int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ bcopy(&int_val, arg, sizeof(int32)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_SDREG): ++ { ++ sdreg_t *sd_ptr; ++ uintptr addr; ++ uint size; ++ ++ sd_ptr = (sdreg_t *)params; ++ ++ addr = ((uintptr)bus->regs + sd_ptr->offset); ++ size = sd_ptr->func; ++ bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ ++ /* Same as above, but offset is not backplane (not SDIO core) */ ++ case IOV_GVAL(IOV_SBREG): ++ { ++ sdreg_t sdreg; ++ uint32 addr, size; ++ ++ bcopy(params, &sdreg, sizeof(sdreg)); ++ ++ addr = SI_ENUM_BASE + sdreg.offset; ++ size = sdreg.func; ++ int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ bcopy(&int_val, arg, sizeof(int32)); ++ break; ++ } ++ ++ case IOV_SVAL(IOV_SBREG): ++ { ++ sdreg_t sdreg; ++ uint32 addr, size; ++ ++ bcopy(params, &sdreg, sizeof(sdreg)); ++ ++ addr = SI_ENUM_BASE + sdreg.offset; ++ size = sdreg.func; ++ bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value); ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ break; ++ } ++ ++ case IOV_GVAL(IOV_SDCIS): ++ { ++ *(char *)arg = 0; ++ ++ bcmstrcat(arg, "\nFunc 0\n"); ++ bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); ++ bcmstrcat(arg, "\nFunc 1\n"); ++ bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); ++ bcmstrcat(arg, "\nFunc 2\n"); ++ bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); ++ break; ++ } ++ ++ case IOV_GVAL(IOV_FORCEEVEN): ++ int_val = (int32)forcealign; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_FORCEEVEN): ++ forcealign = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_TXBOUND): ++ int_val = (int32)dhd_txbound; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXBOUND): ++ dhd_txbound = (uint)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_RXBOUND): ++ int_val = (int32)dhd_rxbound; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_RXBOUND): ++ dhd_rxbound = (uint)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_TXMINMAX): ++ int_val = (int32)dhd_txminmax; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXMINMAX): ++ dhd_txminmax = (uint)int_val; ++ break; ++ ++ case IOV_GVAL(IOV_SERIALCONS): ++ int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror); ++ if (bcmerror != 0) ++ break; ++ ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SERIALCONS): ++ dhd_serialconsole(bus, TRUE, bool_val, &bcmerror); ++ break; ++ ++ ++#endif /* DHD_DEBUG */ ++ ++ ++#ifdef SDTEST ++ case IOV_GVAL(IOV_EXTLOOP): ++ int_val = (int32)bus->ext_loop; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_EXTLOOP): ++ bus->ext_loop = bool_val; ++ break; ++ ++ case IOV_GVAL(IOV_PKTGEN): ++ bcmerror = dhdsdio_pktgen_get(bus, arg); ++ break; ++ ++ case IOV_SVAL(IOV_PKTGEN): ++ bcmerror = dhdsdio_pktgen_set(bus, arg); ++ break; ++#endif /* SDTEST */ ++ ++#if defined(USE_SDIOFIFO_IOVAR) ++ case IOV_GVAL(IOV_WATERMARK): ++ int_val = (int32)watermark; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_WATERMARK): ++ watermark = (uint)int_val; ++ watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark; ++ DHD_ERROR(("Setting watermark as 0x%x.\n", watermark)); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL); ++ break; ++ ++ case IOV_GVAL(IOV_MESBUSYCTRL): ++ int_val = (int32)mesbusyctrl; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_MESBUSYCTRL): ++ mesbusyctrl = (uint)int_val; ++ mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK) ++ ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl; ++ DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl)); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, ++ ((uint8)mesbusyctrl | 0x80), NULL); ++ break; ++#endif ++ ++ ++ case IOV_GVAL(IOV_DONGLEISOLATION): ++ int_val = bus->dhd->dongle_isolation; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DONGLEISOLATION): ++ bus->dhd->dongle_isolation = bool_val; ++ break; ++ ++ case IOV_SVAL(IOV_DEVRESET): ++ DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n", ++ __FUNCTION__, bool_val, bus->dhd->dongle_reset, ++ bus->dhd->busstate)); ++ ++ ASSERT(bus->dhd->osh); ++ /* ASSERT(bus->cl_devid); */ ++ ++ dhd_bus_devreset(bus->dhd, (uint8)bool_val); ++ ++ break; ++ /* ++ * softap firmware is updated through module parameter or android private command ++ */ ++ ++ case IOV_GVAL(IOV_DEVRESET): ++ DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__)); ++ ++ /* Get its status */ ++ int_val = (bool) bus->dhd->dongle_reset; ++ bcopy(&int_val, arg, val_size); ++ ++ break; ++ ++ case IOV_GVAL(IOV_KSO): ++ int_val = dhdsdio_sleepcsr_get(bus); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_DEVCAP): ++ int_val = dhdsdio_devcap_get(bus); ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_DEVCAP): ++ dhdsdio_devcap_set(bus, (uint8) int_val); ++ break; ++ case IOV_GVAL(IOV_TXGLOMSIZE): ++ int_val = (int32)bus->txglomsize; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_TXGLOMSIZE): ++ if (int_val > SDPCM_MAXGLOM_SIZE) { ++ bcmerror = BCME_ERROR; ++ } else { ++ bus->txglomsize = (uint)int_val; ++ } ++ break; ++ case IOV_SVAL(IOV_HANGREPORT): ++ bus->dhd->hang_report = bool_val; ++ DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report)); ++ break; ++ ++ case IOV_GVAL(IOV_HANGREPORT): ++ int_val = (int32)bus->dhd->hang_report; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_GVAL(IOV_TXINRX_THRES): ++ int_val = bus->txinrx_thres; ++ bcopy(&int_val, arg, val_size); ++ break; ++ case IOV_SVAL(IOV_TXINRX_THRES): ++ if (int_val < 0) { ++ bcmerror = BCME_BADARG; ++ } else { ++ bus->txinrx_thres = int_val; ++ } ++ break; ++ ++ case IOV_GVAL(IOV_SDIO_SUSPEND): ++ int_val = (bus->dhd->busstate == DHD_BUS_SUSPEND) ? 1 : 0; ++ bcopy(&int_val, arg, val_size); ++ break; ++ ++ case IOV_SVAL(IOV_SDIO_SUSPEND): ++ if (bool_val) { /* Suspend */ ++ dhdsdio_suspend(bus); ++ } ++ else { /* Resume */ ++ dhdsdio_resume(bus); ++ } ++ break; ++ ++ default: ++ bcmerror = BCME_UNSUPPORTED; ++ break; ++ } ++ ++exit: ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched && ++ NO_OTHER_ACTIVE_BUS_USER(bus)) { ++ bus->activity = FALSE; ++ dhdsdio_bussleep(bus, TRUE); ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ return bcmerror; ++} ++ ++static int ++dhdsdio_write_vars(dhd_bus_t *bus) ++{ ++ int bcmerror = 0; ++ uint32 varsize, phys_size; ++ uint32 varaddr; ++ uint8 *vbuffer; ++ uint32 varsizew; ++#ifdef DHD_DEBUG ++ uint8 *nvram_ularray; ++#endif /* DHD_DEBUG */ ++ ++ /* 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; ++ ++ // terence 20150412: fix for nvram failed to download ++ if (bus->dhd->conf->chip == BCM43340_CHIP_ID || ++ bus->dhd->conf->chip == BCM43341_CHIP_ID) { ++ varsize = varsize ? ROUNDUP(varsize, 64) : 0; ++ varaddr = (bus->ramsize - 64) - varsize; ++ } ++ ++ varaddr += bus->dongle_ram_base; ++ ++ if (bus->vars) { ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { ++ if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { ++ DHD_ERROR(("PR85623WAR in place\n")); ++ varsize += 4; ++ varaddr -= 4; ++ } ++ } ++ ++ vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); ++ if (!vbuffer) ++ return BCME_NOMEM; ++ ++ bzero(vbuffer, varsize); ++ bcopy(bus->vars, vbuffer, bus->varsz); ++ ++ /* Write the vars list */ ++ bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, varsize, varaddr)); ++ return bcmerror; ++ } ++ ++#ifdef DHD_DEBUG ++ /* Verify NVRAM bytes */ ++ DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); ++ nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); ++ if (!nvram_ularray) { ++ MFREE(bus->dhd->osh, vbuffer, varsize); ++ return BCME_NOMEM; ++ } ++ ++ /* Upload image to verify downloaded contents. */ ++ memset(nvram_ularray, 0xaa, varsize); ++ ++ /* Read the vars list to temp buffer for comparison */ ++ bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, varsize, varaddr)); ++ } ++ /* Compare the org NVRAM with the one read from RAM */ ++ if (memcmp(vbuffer, nvram_ularray, varsize)) { ++ DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); ++ } else ++ DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", ++ __FUNCTION__)); ++ ++ MFREE(bus->dhd->osh, nvram_ularray, varsize); ++#endif /* DHD_DEBUG */ ++ ++ MFREE(bus->dhd->osh, vbuffer, varsize); ++ } ++ ++ phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; ++ ++ phys_size += bus->dongle_ram_base; ++ ++ /* adjust to the user specified RAM */ ++ DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", ++ phys_size, bus->ramsize)); ++ DHD_INFO(("Vars are at %d, orig varsize is %d\n", ++ varaddr, varsize)); ++ varsize = ((phys_size - 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 = htol32(varsizew); ++ } ++ ++ DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); ++ ++ /* Write the length token to the last word */ ++ bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4), ++ (uint8*)&varsizew, 4); ++ ++ return bcmerror; ++} ++ ++static int ++dhdsdio_download_state(dhd_bus_t *bus, bool enter) ++{ ++ uint retries; ++ int bcmerror = 0; ++ int foundcr4 = 0; ++ ++ if (!bus->sih) ++ return BCME_ERROR; ++ /* To enter download state, disable ARM and reset SOCRAM. ++ * To exit download state, simply reset ARM (default is RAM boot). ++ */ ++ if (enter) { ++ bus->alp_only = TRUE; ++ ++ if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && ++ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { ++ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ foundcr4 = 1; ++ } else { ++ DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ } ++ ++ if (!foundcr4) { ++ si_core_disable(bus->sih, 0); ++ if (bcmsdh_regfail(bus->sdh)) { ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ ++ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ si_core_reset(bus->sih, 0, 0); ++ if (bcmsdh_regfail(bus->sdh)) { ++ DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", ++ __FUNCTION__)); ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ ++ /* Disable remap for download */ ++ if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) ++ dhdsdio_devram_remap(bus, FALSE); ++ ++ if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID || ++ CHIPID(bus->sih->chip) == BCM43018_CHIP_ID) { ++ /* Disabling Remap for SRAM_3 */ ++ si_socram_set_bankpda(bus->sih, 0x3, 0x0); ++ } ++ ++ /* Clear the top bit of memory */ ++ if (bus->ramsize) { ++ uint32 zeros = 0; ++ if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, ++ (uint8*)&zeros, 4) < 0) { ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ } ++ } else { ++ /* For CR4, ++ * Halt ARM ++ * Remove ARM reset ++ * Read RAM base address [0x18_0000] ++ * [next] Download firmware ++ * [done at else] Populate the reset vector ++ * [done at else] Remove ARM halt ++ */ ++ /* Halt ARM & remove reset */ ++ si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT); ++ } ++ } else { ++ if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ if (!si_iscoreup(bus->sih)) { ++ DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ ++ if ((bcmerror = dhdsdio_write_vars(bus))) { ++ DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* Enable remap before ARM reset but after vars. ++ * No backplane access in remap mode ++ */ ++ if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) ++ dhdsdio_devram_remap(bus, TRUE); ++ ++ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && ++ !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { ++ DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); ++ ++ ++ if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && ++ !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ } else { ++ /* cr4 has no socram, but tcm's */ ++ /* write vars */ ++ if ((bcmerror = dhdsdio_write_vars(bus))) { ++ DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && ++ !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { ++ DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); ++ ++ /* switch back to arm core again */ ++ if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { ++ DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__)); ++ bcmerror = BCME_ERROR; ++ goto fail; ++ } ++ /* write address 0 with reset instruction */ ++ bcmerror = dhdsdio_membytes(bus, TRUE, 0, ++ (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr)); ++ ++ if (bcmerror == BCME_OK) { ++ uint32 tmp; ++ ++ /* verify write */ ++ bcmerror = dhdsdio_membytes(bus, FALSE, 0, ++ (uint8 *)&tmp, sizeof(tmp)); ++ ++ if (bcmerror == BCME_OK && tmp != bus->resetinstr) { ++ DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n", ++ __FUNCTION__, bus->resetinstr)); ++ DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n", ++ __FUNCTION__, tmp)); ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ } ++ ++ /* now remove reset and halt and continue to run CR4 */ ++ } ++ ++ si_core_reset(bus->sih, 0, 0); ++ if (bcmsdh_regfail(bus->sdh)) { ++ DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__)); ++ bcmerror = BCME_SDIO_ERROR; ++ goto fail; ++ } ++ ++ /* Allow HT Clock now that the ARM is running. */ ++ bus->alp_only = FALSE; ++ ++ bus->dhd->busstate = DHD_BUS_LOAD; ++ } ++ ++fail: ++ /* Always return to SDIOD core */ ++ if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) ++ si_setcore(bus->sih, SDIOD_CORE_ID, 0); ++ ++ return bcmerror; ++} ++ ++int ++dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, ++ void *params, int plen, void *arg, int len, bool set) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ const bcm_iovar_t *vi = NULL; ++ int bcmerror = 0; ++ int val_size; ++ uint32 actionid; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ ASSERT(name); ++ ASSERT(len >= 0); ++ ++ /* Get MUST have return space */ ++ ASSERT(set || (arg && len)); ++ ++ /* Set does NOT take qualifiers */ ++ ASSERT(!set || (!params && !plen)); ++ ++ /* Look up var locally; if not found pass to host driver */ ++ if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) { ++ dhd_os_sdlock(bus->dhd); ++ ++ BUS_WAKE(bus); ++ ++ /* Turn on clock in case SD command needs backplane */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set); ++ ++ /* Check for bus configuration changes of interest */ ++ ++ /* If it was divisor change, read the new one */ ++ if (set && strcmp(name, "sd_divisor") == 0) { ++ if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, ++ &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { ++ bus->sd_divisor = -1; ++ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); ++ } else { ++ DHD_INFO(("%s: noted %s update, value now %d\n", ++ __FUNCTION__, name, bus->sd_divisor)); ++ } ++ } ++ /* If it was a mode change, read the new one */ ++ if (set && strcmp(name, "sd_mode") == 0) { ++ if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, ++ &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { ++ bus->sd_mode = -1; ++ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); ++ } else { ++ DHD_INFO(("%s: noted %s update, value now %d\n", ++ __FUNCTION__, name, bus->sd_mode)); ++ } ++ } ++ /* Similar check for blocksize change */ ++ if (set && strcmp(name, "sd_blocksize") == 0) { ++ int32 fnum = 2; ++ if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32), ++ &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { ++ bus->blocksize = 0; ++ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); ++ } else { ++ DHD_INFO(("%s: noted %s update, value now %d\n", ++ __FUNCTION__, "sd_blocksize", bus->blocksize)); ++ ++ dhdsdio_tune_fifoparam(bus); ++ } ++ } ++ bus->roundup = MIN(max_roundup, bus->blocksize); ++ ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched && ++ NO_OTHER_ACTIVE_BUS_USER(bus)) { ++ bus->activity = FALSE; ++ dhdsdio_bussleep(bus, TRUE); ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ ++ dhd_os_sdunlock(bus->dhd); ++ goto exit; ++ } ++ ++ DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, ++ 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 = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); ++ ++exit: ++ return bcmerror; ++} ++ ++void ++dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) ++{ ++ osl_t *osh; ++ uint32 local_hostintmask; ++ uint8 saveclk; ++ uint retries; ++ int err; ++ bool wlfc_enabled = FALSE; ++ unsigned long flags; ++ ++ if (!bus->dhd) ++ return; ++ ++ osh = bus->dhd->osh; ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ bcmsdh_waitlockfree(bus->sdh); ++ ++ if (enforce_mutex) ++ dhd_os_sdlock(bus->dhd); ++ ++ if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) { ++ /* if Firmware already hangs disbale any interrupt */ ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ bus->hostintmask = 0; ++ bcmsdh_intr_disable(bus->sdh); ++ } else { ++ ++ BUS_WAKE(bus); ++ ++ if (KSO_ENAB(bus)) { ++ ++ /* Enable clock for device interrupts */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Disable and clear interrupts at the chip level also */ ++ W_SDREG(0, &bus->regs->hostintmask, retries); ++ local_hostintmask = bus->hostintmask; ++ bus->hostintmask = 0; ++ ++ /* Force clocks on backplane to be sure F2 interrupt propagates */ ++ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (!err) { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ (saveclk | SBSDIO_FORCE_HT), &err); ++ } ++ if (err) { ++ DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", ++ __FUNCTION__, err)); ++ } ++ ++ /* Turn off the bus (F2), free any pending packets */ ++ DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); ++ bcmsdh_intr_disable(bus->sdh); ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); ++ ++ /* Clear any pending interrupts now that F2 is disabled */ ++ W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); ++ } ++ ++ /* Turn off the backplane clock (only) */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ ++ /* Change our idea of bus state */ ++ DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ } ++ ++#ifdef PROP_TXSTATUS ++ wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED); ++#endif ++ if (!wlfc_enabled) { ++#ifdef DHDTCPACK_SUPPRESS ++ /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, ++ * when there is a newly coming packet from network stack. ++ */ ++ dhd_tcpack_info_tbl_clean(bus->dhd); ++#endif /* DHDTCPACK_SUPPRESS */ ++ dhd_os_sdlock_txq(bus->dhd); ++ /* Clear the data packet queues */ ++ pktq_flush(osh, &bus->txq, TRUE); ++ dhd_os_sdunlock_txq(bus->dhd); ++ } ++ ++ /* Clear any held glomming stuff */ ++ if (bus->glomd) ++ PKTFREE(osh, bus->glomd, FALSE); ++ ++ if (bus->glom) ++ PKTFREE(osh, bus->glom, FALSE); ++ ++ bus->glom = bus->glomd = NULL; ++ ++ /* Clear rx control and wake any waiters */ ++ bus->rxlen = 0; ++ dhd_os_ioctl_resp_wake(bus->dhd); ++ ++ /* Reset some F2 state stuff */ ++ bus->rxskip = FALSE; ++ bus->tx_seq = bus->rx_seq = 0; ++ ++ bus->tx_max = 4; ++ ++ if (enforce_mutex) ++ dhd_os_sdunlock(bus->dhd); ++} ++ ++#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD) ++extern uint sd_txglom; ++#endif ++void ++dhd_txglom_enable(dhd_pub_t *dhdp, bool enable) ++{ ++ /* can't enable host txglom by default, some platforms have no ++ * (or crappy) ADMA support and txglom will cause kernel assertions (e.g. ++ * panda board) ++ */ ++ dhd_bus_t *bus = dhdp->bus; ++#ifdef BCMSDIOH_TXGLOM ++ uint32 rxglom; ++ int32 ret; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++#ifdef BCMSDIOH_STD ++ if (enable) ++ enable = sd_txglom; ++#endif /* BCMSDIOH_STD */ ++ ++ if (enable) { ++ rxglom = 1; ++ ret = dhd_iovar(dhdp, 0, "bus:rxglom", (char *)&rxglom, sizeof(rxglom), NULL, 0, ++ TRUE); ++ if (ret >= 0) ++ bus->txglom_enable = TRUE; ++ else { ++#ifdef BCMSDIOH_STD ++ sd_txglom = 0; ++#endif /* BCMSDIOH_STD */ ++ bus->txglom_enable = FALSE; ++ } ++ } else ++#endif /* BCMSDIOH_TXGLOM */ ++ bus->txglom_enable = FALSE; ++ printf("%s: enable %d\n", __FUNCTION__, bus->txglom_enable); ++ dhd_conf_set_txglom_params(bus->dhd, bus->txglom_enable); ++ bcmsdh_set_mode(bus->sdh, bus->dhd->conf->txglom_mode); ++} ++ ++int ++dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ dhd_timeout_t tmo; ++ uint retries = 0; ++ uint8 ready, enable; ++ int err, ret = 0; ++ uint8 saveclk; ++#if defined(SDIO_ISR_THREAD) ++ int intr_extn; ++#endif ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ ASSERT(bus->dhd); ++ if (!bus->dhd) ++ return 0; ++ ++ if (enforce_mutex) ++ dhd_os_sdlock(bus->dhd); ++ ++ if (bus->sih->chip == BCM43362_CHIP_ID) { ++ printf("%s: delay 100ms for BCM43362\n", __FUNCTION__); ++ OSL_DELAY(100000); // terence 20131209: delay for 43362 ++ } ++ ++ /* Make sure backplane clock is on, needed to generate F2 interrupt */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ if (bus->clkstate != CLK_AVAIL) { ++ DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate)); ++ ret = -1; ++ goto exit; ++ } ++ ++ /* Force clocks on backplane to be sure F2 interrupt propagates */ ++ saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ ++ if (!err) { ++ if (bus->sih->chip == BCM43012_CHIP_ID) { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ (saveclk | SBSDIO_HT_AVAIL_REQ), &err); ++ } else { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ (saveclk | SBSDIO_FORCE_HT), &err); ++ } ++ } ++ ++ if (err) { ++ DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); ++ ret = -1; ++ goto exit; ++ } ++ ++ /* Enable function 2 (frame transfers) */ ++ W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT), ++ &bus->regs->tosbmailboxdata, retries); ++ enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); ++ ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); ++ ++ /* Give the dongle some time to do its thing and set IOR2 */ ++ dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000); ++ ++ ready = 0; ++ while (ready != enable && !dhd_timeout_expired(&tmo)) ++ ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); ++ ++ DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", ++ __FUNCTION__, enable, ready, tmo.elapsed)); ++ ++#if defined(SDIO_ISR_THREAD) ++ if (dhdp->conf->intr_extn) { ++ intr_extn = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTR_EXTN, NULL); ++ if (intr_extn & 0x1) { ++ intr_extn |= 0x2; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTR_EXTN, intr_extn, NULL); ++ } ++ } ++#endif ++ ++ /* If F2 successfully enabled, set core and enable interrupts */ ++ if (ready == enable) { ++ /* Make sure we're talking to the core. */ ++ if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) ++ bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0); ++ ASSERT(bus->regs != NULL); ++ ++ /* Set up the interrupt mask and enable interrupts */ ++ bus->hostintmask = HOSTINTMASK; ++ /* corerev 4 could use the newer interrupt logic to detect the frames */ ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && ++ (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { ++ bus->hostintmask &= ~I_HMB_FRAME_IND; ++ bus->hostintmask |= I_XMTDATA_AVAIL; ++ } ++ W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); ++ ++ if (bus->sih->buscorerev < 15) { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, ++ (uint8)watermark, &err); ++ } ++ ++ /* Set bus state according to enable result */ ++ dhdp->busstate = DHD_BUS_DATA; ++ ++ /* Need to set fn2 block size to match fn1 block size. ++ * Requests to fn2 go thru fn1. * ++ * faltwig has this code contitioned with #if !BCMSPI_ANDROID. ++ * It would be cleaner to use the ->sdh->block_sz[fno] instead of ++ * 64, but this layer has no access to sdh types. ++ */ ++ ++ /* bcmsdh_intr_unmask(bus->sdh); */ ++ ++ bus->intdis = FALSE; ++ if (bus->intr) { ++ DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); ++ bcmsdh_intr_enable(bus->sdh); ++ } else { ++ DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); ++ bcmsdh_intr_disable(bus->sdh); ++ } ++ ++ } ++ ++ ++ else { ++ /* Disable F2 again */ ++ enable = SDIO_FUNC_ENABLE_1; ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); ++ } ++ ++ if (dhdsdio_sr_cap(bus)) { ++ dhdsdio_sr_init(bus); ++ /* Masking the chip active interrupt permanantly */ ++ bus->hostintmask &= ~I_CHIPACTIVE; ++ W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); ++ DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n", ++ __FUNCTION__, bus->hostintmask)); ++ } else { ++ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); ++ } ++ ++ /* If we didn't come up, turn off backplane clock */ ++ if (dhdp->busstate != DHD_BUS_DATA) ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ ++exit: ++ if (enforce_mutex) ++ dhd_os_sdunlock(bus->dhd); ++ ++ return ret; ++} ++ ++static void ++dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) ++{ ++ bcmsdh_info_t *sdh = bus->sdh; ++ sdpcmd_regs_t *regs = bus->regs; ++ uint retries = 0; ++ uint16 lastrbc; ++ uint8 hi, lo; ++ int err; ++ ++ DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__, ++ (abort ? "abort command, " : ""), (rtx ? ", send NAK" : ""))); ++ ++ if (!KSO_ENAB(bus)) { ++ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (abort) { ++ bcmsdh_abort(sdh, SDIO_FUNC_2); ++ } ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); ++ if (err) { ++ DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__)); ++ goto fail; ++ } ++ bus->f1regdata++; ++ ++ /* Wait until the packet has been flushed (device/FIFO stable) */ ++ for (lastrbc = retries = 0xffff; retries > 0; retries--) { ++ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); ++ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err); ++ if (err) { ++ DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ bus->f1regdata += 2; ++ ++ if ((hi == 0) && (lo == 0)) ++ break; ++ ++ if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { ++ DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n", ++ __FUNCTION__, lastrbc, ((hi << 8) + lo))); ++ } ++ lastrbc = (hi << 8) + lo; ++ } ++ ++ if (!retries) { ++ DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc)); ++ } else { ++ DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries))); ++ } ++ ++ if (rtx) { ++ bus->rxrtx++; ++ W_SDREG(SMB_NAK, ®s->tosbmailbox, retries); ++ bus->f1regdata++; ++ if (retries <= retry_limit) { ++ bus->rxskip = TRUE; ++ } ++ } ++ ++ /* Clear partial in any case */ ++ bus->nextlen = 0; ++ ++fail: ++ /* If we can't reach the device, signal failure */ ++ if (err || bcmsdh_regfail(sdh)) ++ bus->dhd->busstate = DHD_BUS_DOWN; ++} ++ ++static void ++dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) ++{ ++ bcmsdh_info_t *sdh = bus->sdh; ++ uint rdlen, pad; ++ ++ int sdret; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ /* Control data already received in aligned rxctl */ ++ if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) ++ goto gotpkt; ++ ++ ASSERT(bus->rxbuf); ++ /* Set rxctl for frame (w/optional alignment) */ ++ bus->rxctl = bus->rxbuf; ++ if (dhd_alignctl) { ++ bus->rxctl += firstread; ++ if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) ++ bus->rxctl += (DHD_SDALIGN - pad); ++ bus->rxctl -= firstread; ++ } ++ ASSERT(bus->rxctl >= bus->rxbuf); ++ ++ /* Copy the already-read portion over */ ++ bcopy(hdr, bus->rxctl, firstread); ++ if (len <= firstread) ++ goto gotpkt; ++ ++ /* Copy the full data pkt in gSPI case and process ioctl. */ ++ if (bus->bus == SPI_BUS) { ++ bcopy(hdr, bus->rxctl, 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->dhd->maxctl)) ++ rdlen += pad; ++ } else if (rdlen % DHD_SDALIGN) { ++ rdlen += DHD_SDALIGN - (rdlen % DHD_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->dhd->maxctl) { ++ DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n", ++ __FUNCTION__, rdlen, bus->dhd->maxctl)); ++ bus->dhd->rx_errors++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ goto done; ++ } ++ ++ if ((len - doff) > bus->dhd->maxctl) { ++ DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", ++ __FUNCTION__, len, (len - doff), bus->dhd->maxctl)); ++ bus->dhd->rx_errors++; bus->rx_toolong++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ goto done; ++ } ++ ++ ++ /* Read remainder of frame body into the rxctl buffer */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ /* Control frame failures need retransmission */ ++ if (sdret < 0) { ++ DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret)); ++ bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */ ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ goto done; ++ } ++ ++gotpkt: ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_CTL_ON()) { ++ prhex("RxCtrl", bus->rxctl, len); ++ } ++#endif ++ ++ /* Point to valid data and indicate its length */ ++ bus->rxctl += doff; ++ bus->rxlen = len - doff; ++ ++done: ++ /* Awake any waiters */ ++ dhd_os_ioctl_resp_wake(bus->dhd); ++} ++int ++dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, ++ void **pkt, uint32 *pkt_count); ++ ++static uint8 ++dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) ++{ ++ uint16 dlen, totlen; ++ uint8 *dptr, num = 0; ++ ++ uint16 sublen, check; ++ void *pfirst, *plast, *pnext; ++ void * list_tail[DHD_MAX_IFS] = { NULL }; ++ void * list_head[DHD_MAX_IFS] = { NULL }; ++ uint8 idx; ++ osl_t *osh = bus->dhd->osh; ++ ++ int errcode; ++ uint8 chan, seq, doff, sfdoff; ++ uint8 txmax; ++ uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; ++ uint reorder_info_len; ++ ++ int ifidx = 0; ++ bool usechain = bus->use_rxchain; ++ ++ /* If packets, issue read(s) and send up packet chain */ ++ /* Return sequence numbers consumed? */ ++ ++ DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom)); ++ ++ /* If there's a descriptor, generate the packet chain */ ++ if (bus->glomd) { ++ dhd_os_sdlock_rxq(bus->dhd); ++ ++ pfirst = plast = pnext = NULL; ++ dlen = (uint16)PKTLEN(osh, bus->glomd); ++ dptr = PKTDATA(osh, bus->glomd); ++ if (!dlen || (dlen & 1)) { ++ DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n", ++ __FUNCTION__, dlen)); ++ dlen = 0; ++ } ++ ++ for (totlen = num = 0; dlen; num++) { ++ /* Get (and move past) next length */ ++ sublen = ltoh16_ua(dptr); ++ dlen -= sizeof(uint16); ++ dptr += sizeof(uint16); ++ if ((sublen < SDPCM_HDRLEN) || ++ ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { ++ DHD_ERROR(("%s: descriptor len %d bad: %d\n", ++ __FUNCTION__, num, sublen)); ++ pnext = NULL; ++ break; ++ } ++ if (sublen % DHD_SDALIGN) { ++ DHD_ERROR(("%s: sublen %d not a multiple of %d\n", ++ __FUNCTION__, sublen, DHD_SDALIGN)); ++ usechain = FALSE; ++ } ++ totlen += sublen; ++ ++ /* For last frame, adjust read len so total is a block multiple */ ++ if (!dlen) { ++ sublen += (ROUNDUP(totlen, bus->blocksize) - totlen); ++ totlen = ROUNDUP(totlen, bus->blocksize); ++ } ++ ++ /* Allocate/chain packet for next subframe */ ++ if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) { ++ DHD_ERROR(("%s: PKTGET failed, num %d len %d\n", ++ __FUNCTION__, num, sublen)); ++ break; ++ } ++ ASSERT(!PKTLINK(pnext)); ++ if (!pfirst) { ++ ASSERT(!plast); ++ pfirst = plast = pnext; ++ } else { ++ ASSERT(plast); ++ PKTSETNEXT(osh, plast, pnext); ++ plast = pnext; ++ } ++ ++ /* Adhere to start alignment requirements */ ++ PKTALIGN(osh, pnext, sublen, DHD_SDALIGN); ++ } ++ ++ /* If all allocations succeeded, save packet chain in bus structure */ ++ if (pnext) { ++ DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n", ++ __FUNCTION__, totlen, num)); ++ if (DHD_GLOM_ON() && bus->nextlen) { ++ if (totlen != bus->nextlen) { ++ DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d " ++ "rxseq %d\n", __FUNCTION__, bus->nextlen, ++ totlen, rxseq)); ++ } ++ } ++ bus->glom = pfirst; ++ pfirst = pnext = NULL; ++ } else { ++ if (pfirst) ++ PKTFREE(osh, pfirst, FALSE); ++ bus->glom = NULL; ++ num = 0; ++ } ++ ++ /* Done with descriptor packet */ ++ PKTFREE(osh, bus->glomd, FALSE); ++ bus->glomd = NULL; ++ bus->nextlen = 0; ++ ++ dhd_os_sdunlock_rxq(bus->dhd); ++ } ++ ++ /* Ok -- either we just generated a packet chain, or had one from before */ ++ if (bus->glom) { ++ if (DHD_GLOM_ON()) { ++ DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__)); ++ for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) { ++ DHD_GLOM((" %p: %p len 0x%04x (%d)\n", ++ pnext, (uint8*)PKTDATA(osh, pnext), ++ PKTLEN(osh, pnext), PKTLEN(osh, pnext))); ++ } ++ } ++ ++ pfirst = bus->glom; ++ dlen = (uint16)pkttotlen(osh, pfirst); ++ ++ /* Do an SDIO read for the superframe. Configurable iovar to ++ * read directly into the chained packet, or allocate a large ++ * packet and and copy into the chain. ++ */ ++ if (usechain) { ++ errcode = dhd_bcmsdh_recv_buf(bus, ++ bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, ++ F2SYNC, (uint8*)PKTDATA(osh, pfirst), ++ dlen, pfirst, NULL, NULL); ++ } else if (bus->dataptr) { ++ errcode = dhd_bcmsdh_recv_buf(bus, ++ bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, ++ F2SYNC, bus->dataptr, ++ dlen, NULL, NULL, NULL); ++ sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr); ++ if (sublen != dlen) { ++ DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n", ++ __FUNCTION__, dlen, sublen)); ++ errcode = -1; ++ } ++ pnext = NULL; ++ BCM_REFERENCE(pnext); ++ } else { ++ DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen)); ++ errcode = -1; ++ } ++ bus->f2rxdata++; ++ ASSERT(errcode != BCME_PENDING); ++ ++ /* On failure, kill the superframe, allow a couple retries */ ++ if (errcode < 0) { ++ DHD_ERROR(("%s: glom read of %d bytes failed: %d\n", ++ __FUNCTION__, dlen, errcode)); ++ bus->dhd->rx_errors++; ++ ++ if (bus->glomerr++ < 3) { ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ } else { ++ bus->glomerr = 0; ++ dhdsdio_rxfail(bus, TRUE, FALSE); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(osh, bus->glom, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->rxglomfail++; ++ bus->glom = NULL; ++ } ++ return 0; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ prhex("SUPERFRAME", PKTDATA(osh, pfirst), ++ MIN(PKTLEN(osh, pfirst), 48)); ++ } ++#endif ++ ++ ++ /* Validate the superframe header */ ++ dptr = (uint8 *)PKTDATA(osh, pfirst); ++ sublen = ltoh16_ua(dptr); ++ check = ltoh16_ua(dptr + sizeof(uint16)); ++ ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); ++ bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n", ++ __FUNCTION__, bus->nextlen, seq)); ++ bus->nextlen = 0; ++ } ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ ++ errcode = 0; ++ if ((uint16)~(sublen^check)) { ++ DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n", ++ __FUNCTION__, sublen, check)); ++ errcode = -1; ++ } else if (ROUNDUP(sublen, bus->blocksize) != dlen) { ++ DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", ++ __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen)); ++ errcode = -1; ++ } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) { ++ DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__, ++ SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]))); ++ errcode = -1; ++ } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { ++ DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__)); ++ errcode = -1; ++ } else if ((doff < SDPCM_HDRLEN) || ++ (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) { ++ DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n", ++ __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), ++ SDPCM_HDRLEN)); ++ errcode = -1; ++ } ++ ++ /* Check sequence number of superframe SW header */ ++ if (rxseq != seq) { ++ DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n", ++ __FUNCTION__, seq, rxseq)); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((uint8)(txmax - bus->tx_seq) > 0x70) { ++ DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n", ++ __FUNCTION__, txmax, bus->tx_seq)); ++ txmax = bus->tx_max; ++ } ++ bus->tx_max = txmax; ++ ++ /* Remove superframe header, remember offset */ ++ PKTPULL(osh, pfirst, doff); ++ sfdoff = doff; ++ ++ /* Validate all the subframe headers */ ++ for (num = 0, pnext = pfirst; pnext && !errcode; ++ num++, pnext = PKTNEXT(osh, pnext)) { ++ dptr = (uint8 *)PKTDATA(osh, pnext); ++ dlen = (uint16)PKTLEN(osh, pnext); ++ sublen = ltoh16_ua(dptr); ++ check = ltoh16_ua(dptr + sizeof(uint16)); ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ prhex("subframe", dptr, 32); ++ } ++#endif ++ ++ if ((uint16)~(sublen^check)) { ++ DHD_ERROR(("%s (subframe %d): HW hdr error: " ++ "len/check 0x%04x/0x%04x\n", ++ __FUNCTION__, num, sublen, check)); ++ errcode = -1; ++ } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { ++ DHD_ERROR(("%s (subframe %d): length mismatch: " ++ "len 0x%04x, expect 0x%04x\n", ++ __FUNCTION__, num, sublen, dlen)); ++ errcode = -1; ++ } else if ((chan != SDPCM_DATA_CHANNEL) && ++ (chan != SDPCM_EVENT_CHANNEL)) { ++ DHD_ERROR(("%s (subframe %d): bad channel %d\n", ++ __FUNCTION__, num, chan)); ++ errcode = -1; ++ } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { ++ DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n", ++ __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN)); ++ errcode = -1; ++ } ++ } ++ ++ if (errcode) { ++ /* Terminate frame on error, request a couple retries */ ++ if (bus->glomerr++ < 3) { ++ /* Restore superframe header space */ ++ PKTPUSH(osh, pfirst, sfdoff); ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ } else { ++ bus->glomerr = 0; ++ dhdsdio_rxfail(bus, TRUE, FALSE); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(osh, bus->glom, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->rxglomfail++; ++ bus->glom = NULL; ++ } ++ bus->nextlen = 0; ++ return 0; ++ } ++ ++ /* Basic SD framing looks ok - process each packet (header) */ ++ bus->glom = NULL; ++ plast = NULL; ++ ++ dhd_os_sdlock_rxq(bus->dhd); ++ for (num = 0; pfirst; rxseq++, pfirst = pnext) { ++ pnext = PKTNEXT(osh, pfirst); ++ PKTSETNEXT(osh, pfirst, NULL); ++ ++ dptr = (uint8 *)PKTDATA(osh, pfirst); ++ sublen = ltoh16_ua(dptr); ++ chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); ++ ++ DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", ++ __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst), ++ PKTLEN(osh, pfirst), sublen, chan, seq)); ++ ++ ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL)); ++ ++ if (rxseq != seq) { ++ DHD_GLOM(("%s: rx_seq %d, expected %d\n", ++ __FUNCTION__, seq, rxseq)); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ prhex("Rx Subframe Data", dptr, dlen); ++ } ++#endif ++ ++ PKTSETLEN(osh, pfirst, sublen); ++ PKTPULL(osh, pfirst, doff); ++ ++ reorder_info_len = sizeof(reorder_info_buf); ++ ++ if (PKTLEN(osh, pfirst) == 0) { ++ PKTFREE(bus->dhd->osh, pfirst, FALSE); ++ continue; ++ } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, ++ &reorder_info_len) != 0) { ++ DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); ++ bus->dhd->rx_errors++; ++ PKTFREE(osh, pfirst, FALSE); ++ continue; ++ } ++ if (reorder_info_len) { ++ uint32 free_buf_count; ++ void *ppfirst; ++ ++ ppfirst = pfirst; ++ /* Reordering info from the firmware */ ++ dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, ++ reorder_info_len, &ppfirst, &free_buf_count); ++ ++ if (free_buf_count == 0) { ++ continue; ++ } else { ++ void *temp; ++ ++ /* go to the end of the chain and attach the pnext there */ ++ temp = ppfirst; ++ while (PKTNEXT(osh, temp) != NULL) { ++ temp = PKTNEXT(osh, temp); ++ } ++ pfirst = temp; ++ if (list_tail[ifidx] == NULL) ++ list_head[ifidx] = ppfirst; ++ else ++ PKTSETNEXT(osh, list_tail[ifidx], ppfirst); ++ list_tail[ifidx] = pfirst; ++ } ++ ++ num += (uint8)free_buf_count; ++ } else { ++ /* this packet will go up, link back into chain and count it */ ++ ++ if (list_tail[ifidx] == NULL) { ++ list_head[ifidx] = list_tail[ifidx] = pfirst; ++ } else { ++ PKTSETNEXT(osh, list_tail[ifidx], pfirst); ++ list_tail[ifidx] = pfirst; ++ } ++ num++; ++ } ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n", ++ __FUNCTION__, num, pfirst, ++ PKTDATA(osh, pfirst), PKTLEN(osh, pfirst), ++ PKTNEXT(osh, pfirst), PKTLINK(pfirst))); ++ prhex("", (uint8 *)PKTDATA(osh, pfirst), ++ MIN(PKTLEN(osh, pfirst), 32)); ++ } ++#endif /* DHD_DEBUG */ ++ } ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ++ for (idx = 0; idx < DHD_MAX_IFS; idx++) { ++ if (list_head[idx]) { ++ void *temp; ++ uint8 cnt = 0; ++ temp = list_head[idx]; ++ do { ++ temp = PKTNEXT(osh, temp); ++ cnt++; ++ } while (temp); ++ if (cnt) { ++ dhd_os_sdunlock(bus->dhd); ++ dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0); ++ dhd_os_sdlock(bus->dhd); ++#if defined(SDIO_ISR_THREAD) ++ /* terence 20150615: fix for below error due to bussleep in watchdog after dhd_os_sdunlock here, ++ * so call BUS_WAKE to wake up bus again ++ * dhd_bcmsdh_recv_buf: Device asleep ++ * dhdsdio_readframes: RXHEADER FAILED: -40 ++ * dhdsdio_rxfail: abort command, terminate frame, send NAK ++ */ ++ BUS_WAKE(bus); ++#endif ++ } ++ } ++ } ++ bus->rxglomframes++; ++ bus->rxglompkts += num; ++ } ++ return num; ++} ++ ++ ++/* Return TRUE if there may be more frames to read */ ++static uint ++dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) ++{ ++ osl_t *osh = bus->dhd->osh; ++ bcmsdh_info_t *sdh = bus->sdh; ++ ++ uint16 len, check; /* Extracted hardware header fields */ ++ uint8 chan, seq, doff; /* Extracted software header fields */ ++ uint8 fcbits; /* Extracted fcbits from software header */ ++ uint8 delta; ++ ++ void *pkt; /* Packet for event or data frames */ ++ uint16 pad; /* Number of pad bytes to read */ ++ uint16 rdlen; /* Total number of bytes to read */ ++ uint8 rxseq; /* Next sequence number to expect */ ++ uint rxleft = 0; /* Remaining number of frames allowed */ ++ int sdret; /* Return code from bcmsdh calls */ ++ uint8 txmax; /* Maximum tx sequence offered */ ++ bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */ ++ uint8 *rxbuf; ++ int ifidx = 0; ++ uint rxcount = 0; /* Total frames read */ ++ uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; ++ uint reorder_info_len; ++ uint pkt_count; ++ ++#if defined(DHD_DEBUG) || defined(SDTEST) ++ bool sdtest = FALSE; /* To limit message spew from test mode */ ++#endif ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ bus->readframes = TRUE; ++ ++ if (!KSO_ENAB(bus)) { ++ DHD_ERROR(("%s: KSO off\n", __FUNCTION__)); ++ bus->readframes = FALSE; ++ return 0; ++ } ++ ++ ASSERT(maxframes); ++ ++#ifdef SDTEST ++ /* Allow pktgen to override maxframes */ ++ if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) { ++ maxframes = bus->pktgen_count; ++ sdtest = TRUE; ++ } ++#endif ++ ++ /* Not finished unless we encounter no more frames indication */ ++ *finished = FALSE; ++ ++ ++ for (rxseq = bus->rx_seq, rxleft = maxframes; ++ !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; ++ rxseq++, rxleft--) { ++#ifdef DHDTCPACK_SUP_DBG ++ if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) { ++ if (bus->dotxinrx == FALSE) ++ DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n", ++ __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode)); ++ } ++#ifdef DEBUG_COUNTER ++ else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) { ++ tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++; ++ } ++#endif /* DEBUG_COUNTER */ ++#endif /* DHDTCPACK_SUP_DBG */ ++ /* tx more to improve rx performance */ ++ if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { ++ dhdsdio_sendpendctl(bus); ++ } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) && ++ !bus->fcstate && DATAOK(bus) && ++ (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) { ++ dhdsdio_sendfromq(bus, dhd_txbound); ++#ifdef DHDTCPACK_SUPPRESS ++ /* In TCPACK_SUP_DELAYTX mode, do txinrx only if ++ * 1. Any DATA packet to TX ++ * 2. TCPACK to TCPDATA PSH packets. ++ * in bus txq. ++ */ ++ bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ? ++ FALSE : TRUE; ++#endif ++ } ++ ++ /* Handle glomming separately */ ++ if (bus->glom || bus->glomd) { ++ uint8 cnt; ++ DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n", ++ __FUNCTION__, bus->glomd, bus->glom)); ++ cnt = dhdsdio_rxglom(bus, rxseq); ++ DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt)); ++ rxseq += cnt - 1; ++ rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; ++ continue; ++ } ++ ++ /* Try doing single read if we can */ ++ if (dhd_readahead && bus->nextlen) { ++ uint16 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 % DHD_SDALIGN) { ++ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); ++ } ++ } ++ ++ /* 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 */ ++ dhd_os_sdlock_rxq(bus->dhd); ++ if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) { ++ if (bus->bus == SPI_BUS) { ++ bus->usebufpool = FALSE; ++ bus->rxctl = bus->rxbuf; ++ if (dhd_alignctl) { ++ bus->rxctl += firstread; ++ if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) ++ bus->rxctl += (DHD_SDALIGN - pad); ++ bus->rxctl -= firstread; ++ } ++ ASSERT(bus->rxctl >= bus->rxbuf); ++ rxbuf = bus->rxctl; ++ /* Read the entire frame */ ++ sdret = dhd_bcmsdh_recv_buf(bus, ++ bcmsdh_cur_sbwad(sdh), ++ SDIO_FUNC_2, ++ F2SYNC, rxbuf, rdlen, ++ NULL, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ ++ /* Control frame failures need retransmission */ ++ if (sdret < 0) { ++ DHD_ERROR(("%s: read %d control bytes failed: %d\n", ++ __FUNCTION__, rdlen, sdret)); ++ /* dhd.rx_ctlerrs is higher level */ ++ bus->rxc_errors++; ++ dhd_os_sdunlock_rxq(bus->dhd); ++ dhdsdio_rxfail(bus, TRUE, ++ (bus->bus == SPI_BUS) ? FALSE : TRUE); ++ continue; ++ } ++ } else { ++ /* Give up on data, request rtx of events */ ++ DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d " ++ "expected rxseq %d\n", ++ __FUNCTION__, len, rdlen, rxseq)); ++ /* Just go try again w/normal header read */ ++ dhd_os_sdunlock_rxq(bus->dhd); ++ continue; ++ } ++ } else { ++ if (bus->bus == SPI_BUS) ++ bus->usebufpool = TRUE; ++ ++ ASSERT(!PKTLINK(pkt)); ++ PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); ++ rxbuf = (uint8 *)PKTDATA(osh, pkt); ++ /* Read the entire frame */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), ++ SDIO_FUNC_2, ++ F2SYNC, rxbuf, rdlen, ++ pkt, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ if (sdret < 0) { ++ DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n", ++ __FUNCTION__, rdlen, sdret)); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ bus->dhd->rx_errors++; ++ dhd_os_sdunlock_rxq(bus->dhd); ++ /* Force retry w/normal header read. Don't attempt NAK for ++ * gSPI ++ */ ++ dhdsdio_rxfail(bus, TRUE, ++ (bus->bus == SPI_BUS) ? FALSE : TRUE); ++ continue; ++ } ++ } ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ++ /* Now check the header */ ++ bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN); ++ ++ /* Extract hardware header fields */ ++ len = ltoh16_ua(bus->rxhdr); ++ check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); ++ ++ /* All zeros means readahead info was bad */ ++ if (!(len|check)) { ++ DHD_INFO(("%s (nextlen): read zeros in HW header???\n", ++ __FUNCTION__)); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ /* Validate check bytes */ ++ if ((uint16)~(len^check)) { ++ DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check" ++ " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen, ++ len, check)); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->rx_badhdr++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ /* Validate frame length */ ++ if (len < SDPCM_HDRLEN) { ++ DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n", ++ __FUNCTION__, len)); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ /* 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) */ ++ DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; " ++ "expected rxseq %d\n", ++ __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq)); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE); ++ GSPI_PR55150_BAILOUT; ++ continue; ++ } ++ ++ ++ /* Extract software header fields */ ++ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ bus->nextlen = ++ bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ DHD_INFO(("%s (nextlen): got frame w/nextlen too large" ++ " (%d), seq %d\n", __FUNCTION__, bus->nextlen, ++ seq)); ++ bus->nextlen = 0; ++ } ++ ++ bus->dhd->rx_readahead_cnt ++; ++ /* Handle Flow Control */ ++ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ delta = 0; ++ if (~bus->flowcontrol & fcbits) { ++ bus->fc_xoff++; ++ delta = 1; ++ } ++ if (bus->flowcontrol & ~fcbits) { ++ bus->fc_xon++; ++ delta = 1; ++ } ++ ++ if (delta) { ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++ /* Check and update sequence number */ ++ if (rxseq != seq) { ++ DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n", ++ __FUNCTION__, seq, rxseq)); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((uint8)(txmax - bus->tx_seq) > 0x70) { ++ DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n", ++ __FUNCTION__, txmax, bus->tx_seq)); ++ txmax = bus->tx_max; ++ } ++ bus->tx_max = txmax; ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ prhex("Rx Data", rxbuf, len); ++ } else if (DHD_HDRS_ON()) { ++ prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); ++ } ++#endif ++ ++ if (chan == SDPCM_CONTROL_CHANNEL) { ++ if (bus->bus == SPI_BUS) { ++ dhdsdio_read_control(bus, rxbuf, len, doff); ++ if (bus->usebufpool) { ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ } ++ continue; ++ } else { ++ DHD_ERROR(("%s (nextlen): readahead on control" ++ " packet %d?\n", __FUNCTION__, seq)); ++ /* Force retry w/normal header read */ ++ bus->nextlen = 0; ++ dhdsdio_rxfail(bus, FALSE, TRUE); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ continue; ++ } ++ } ++ ++ if ((bus->bus == SPI_BUS) && !bus->usebufpool) { ++ DHD_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)) { ++ DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n", ++ __FUNCTION__, doff, len, SDPCM_HDRLEN)); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE2(); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ASSERT(0); ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ /* 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 = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ bus->rxhdr, firstread, NULL, NULL, NULL); ++ bus->f2rxhdrs++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ if (sdret < 0) { ++ DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret)); ++ bus->rx_hdrfail++; ++ dhdsdio_rxfail(bus, TRUE, TRUE); ++ continue; ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() || DHD_HDRS_ON()) { ++ prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); ++ } ++#endif ++ ++ /* Extract hardware header fields */ ++ len = ltoh16_ua(bus->rxhdr); ++ check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); ++ ++ /* All zeros means no more frames */ ++ if (!(len|check)) { ++ *finished = TRUE; ++ break; ++ } ++ ++ /* Validate check bytes */ ++ if ((uint16)~(len^check)) { ++ DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n", ++ __FUNCTION__, len, check)); ++ bus->rx_badhdr++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ /* Validate frame length */ ++ if (len < SDPCM_HDRLEN) { ++ DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len)); ++ continue; ++ } ++ ++ /* Extract software header fields */ ++ chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ /* Validate data offset */ ++ if ((doff < SDPCM_HDRLEN) || (doff > len)) { ++ DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n", ++ __FUNCTION__, doff, len, SDPCM_HDRLEN, seq)); ++ bus->rx_badhdr++; ++ ASSERT(0); ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ /* Save the readahead length if there is one */ ++ bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; ++ if ((bus->nextlen << 4) > MAX_RX_DATASZ) { ++ DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n", ++ __FUNCTION__, bus->nextlen, seq)); ++ bus->nextlen = 0; ++ } ++ ++ /* Handle Flow Control */ ++ fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); ++ ++ delta = 0; ++ if (~bus->flowcontrol & fcbits) { ++ bus->fc_xoff++; ++ delta = 1; ++ } ++ if (bus->flowcontrol & ~fcbits) { ++ bus->fc_xon++; ++ delta = 1; ++ } ++ ++ if (delta) { ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++ /* Check and update sequence number */ ++ if (rxseq != seq) { ++ DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq)); ++ bus->rx_badseq++; ++ rxseq = seq; ++ } ++ ++ /* Check window for sanity */ ++ if ((uint8)(txmax - bus->tx_seq) > 0x70) { ++ DHD_INFO(("%s: got unlikely tx max %d with tx_seq %d\n", ++ __FUNCTION__, txmax, bus->tx_seq)); ++ txmax = bus->tx_max; ++ } ++ bus->tx_max = txmax; ++ ++ /* Call a separate function for control frames */ ++ if (chan == SDPCM_CONTROL_CHANNEL) { ++ dhdsdio_read_control(bus, bus->rxhdr, len, doff); ++ continue; ++ } ++ ++ ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) || ++ (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL)); ++ ++ /* Length to read */ ++ rdlen = (len > firstread) ? (len - 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; ++ } else if (rdlen % DHD_SDALIGN) { ++ rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); ++ } ++ ++ /* Satisfy length-alignment requirements */ ++ if (forcealign && (rdlen & (ALIGNMENT - 1))) ++ rdlen = ROUNDUP(rdlen, ALIGNMENT); ++ ++ if ((rdlen + firstread) > MAX_RX_DATASZ) { ++ /* Too long -- skip this frame */ ++ DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen)); ++ bus->dhd->rx_errors++; bus->rx_toolong++; ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ continue; ++ } ++ ++ dhd_os_sdlock_rxq(bus->dhd); ++ if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) { ++ /* Give up on data, request rtx of events */ ++ DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n", ++ __FUNCTION__, rdlen, chan)); ++ bus->dhd->rx_dropped++; ++ dhd_os_sdunlock_rxq(bus->dhd); ++ dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan)); ++ continue; ++ } ++ dhd_os_sdunlock_rxq(bus->dhd); ++ ++ ASSERT(!PKTLINK(pkt)); ++ ++ /* Leave room for what we already read, and align remainder */ ++ ASSERT(firstread < (PKTLEN(osh, pkt))); ++ PKTPULL(osh, pkt, firstread); ++ PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); ++ ++ /* Read the remaining frame data */ ++ sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, ++ ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); ++ bus->f2rxdata++; ++ ASSERT(sdret != BCME_PENDING); ++ ++ if (sdret < 0) { ++ DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen, ++ ((chan == SDPCM_EVENT_CHANNEL) ? "event" : ++ ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret)); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->dhd->rx_errors++; ++ dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan)); ++ continue; ++ } ++ ++ /* Copy the already-read portion */ ++ PKTPUSH(osh, pkt, firstread); ++ bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread); ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ prhex("Rx Data", PKTDATA(osh, pkt), len); ++ } ++#endif ++ ++deliver: ++ /* Save superframe descriptor and allocate packet frame */ ++ if (chan == SDPCM_GLOM_CHANNEL) { ++ if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { ++ DHD_GLOM(("%s: got glom descriptor, %d bytes:\n", ++ __FUNCTION__, len)); ++#ifdef DHD_DEBUG ++ if (DHD_GLOM_ON()) { ++ prhex("Glom Data", PKTDATA(osh, pkt), len); ++ } ++#endif ++ PKTSETLEN(osh, pkt, len); ++ ASSERT(doff == SDPCM_HDRLEN); ++ PKTPULL(osh, pkt, SDPCM_HDRLEN); ++ bus->glomd = pkt; ++ } else { ++ DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__)); ++ dhdsdio_rxfail(bus, FALSE, FALSE); ++ } ++ continue; ++ } ++ ++ /* Fill in packet len and prio, deliver upward */ ++ PKTSETLEN(osh, pkt, len); ++ PKTPULL(osh, pkt, doff); ++ ++#ifdef SDTEST ++ /* Test channel packets are processed separately */ ++ if (chan == SDPCM_TEST_CHANNEL) { ++ dhdsdio_testrcv(bus, pkt, seq); ++ continue; ++ } ++#endif /* SDTEST */ ++ ++ if (PKTLEN(osh, pkt) == 0) { ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ continue; ++ } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf, ++ &reorder_info_len) != 0) { ++ DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); ++ dhd_os_sdlock_rxq(bus->dhd); ++ PKTFREE(bus->dhd->osh, pkt, FALSE); ++ dhd_os_sdunlock_rxq(bus->dhd); ++ bus->dhd->rx_errors++; ++ continue; ++ } ++ ++ if (reorder_info_len) { ++ /* Reordering info from the firmware */ ++ dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len, ++ &pkt, &pkt_count); ++ if (pkt_count == 0) ++ continue; ++ } else { ++ pkt_count = 1; ++ } ++ ++ /* Unlock during rx call */ ++ dhd_os_sdunlock(bus->dhd); ++ dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); ++ dhd_os_sdlock(bus->dhd); ++#if defined(SDIO_ISR_THREAD) ++ /* terence 20150615: fix for below error due to bussleep in watchdog after dhd_os_sdunlock here, ++ * so call BUS_WAKE to wake up bus again ++ * dhd_bcmsdh_recv_buf: Device asleep ++ * dhdsdio_readframes: RXHEADER FAILED: -40 ++ * dhdsdio_rxfail: abort command, terminate frame, send NAK ++ */ ++ BUS_WAKE(bus); ++#endif ++ } ++ rxcount = maxframes - rxleft; ++#ifdef DHD_DEBUG ++ /* Message if we hit the limit */ ++ if (!rxleft && !sdtest) ++ DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes)); ++ else ++#endif /* DHD_DEBUG */ ++ DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount)); ++ /* Back off rxseq if awaiting rtx, update rx_seq */ ++ if (bus->rxskip) ++ rxseq--; ++ bus->rx_seq = rxseq; ++ ++ if (bus->reqbussleep) ++ { ++ dhdsdio_bussleep(bus, TRUE); ++ bus->reqbussleep = FALSE; ++ } ++ bus->readframes = FALSE; ++ ++ return rxcount; ++} ++ ++static uint32 ++dhdsdio_hostmail(dhd_bus_t *bus, uint32 *hmbd) ++{ ++ sdpcmd_regs_t *regs = bus->regs; ++ uint32 intstatus = 0; ++ uint32 hmb_data; ++ uint8 fcbits; ++ uint retries = 0; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ /* Read mailbox data and ack that we did so */ ++ R_SDREG(hmb_data, ®s->tohostmailboxdata, retries); ++ if (retries <= retry_limit) ++ W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries); ++ bus->f1regdata += 2; ++ ++ /* Dongle recomposed rx frames, accept them again */ ++ if (hmb_data & HMB_DATA_NAKHANDLED) { ++ DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq)); ++ if (!bus->rxskip) { ++ DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__)); ++ } ++ bus->rxskip = FALSE; ++ intstatus |= FRAME_AVAIL_MASK(bus); ++ } ++ ++ /* ++ * 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) ++ DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n", ++ bus->sdpcm_ver, SDPCM_PROT_VERSION)); ++ else ++ DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver)); ++ /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && ++ (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { ++ uint32 val; ++ ++ val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); ++ val &= ~CC_XMTDATAAVAIL_MODE; ++ val |= CC_XMTDATAAVAIL_CTRL; ++ W_REG(bus->dhd->osh, &bus->regs->corecontrol, val); ++ ++ val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); ++ } ++ ++#ifdef DHD_DEBUG ++ /* Retrieve console state address now that firmware should have updated it */ ++ { ++ sdpcm_shared_t shared; ++ if (dhdsdio_readshared(bus, &shared) == 0) ++ bus->console_addr = shared.console_addr; ++ } ++#endif /* DHD_DEBUG */ ++ } ++ ++ /* ++ * Flow Control has been moved into the RX headers and this out of band ++ * method isn't used any more. Leave this here for possibly remaining backward ++ * compatible with older dongles ++ */ ++ if (hmb_data & HMB_DATA_FC) { ++ fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT; ++ ++ if (fcbits & ~bus->flowcontrol) ++ bus->fc_xoff++; ++ if (bus->flowcontrol & ~fcbits) ++ bus->fc_xon++; ++ ++ bus->fc_rcvd++; ++ bus->flowcontrol = fcbits; ++ } ++ ++ /* At least print a message if FW halted */ ++ if (hmb_data & HMB_DATA_FWHALT) { ++ DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n")); ++ dhdsdio_checkdied(bus, NULL, 0); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++ ++ /* Shouldn't be any others */ ++ if (hmb_data & ~(HMB_DATA_DEVREADY | ++ HMB_DATA_FWHALT | ++ HMB_DATA_NAKHANDLED | ++ HMB_DATA_FC | ++ HMB_DATA_FWREADY | ++ HMB_DATA_FCDATA_MASK | ++ HMB_DATA_VERSION_MASK)) { ++ DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data)); ++ } ++ ++ if (hmbd) { ++ *hmbd = hmb_data; ++ } ++ ++ return intstatus; ++} ++ ++static bool ++dhdsdio_dpc(dhd_bus_t *bus) ++{ ++ bcmsdh_info_t *sdh = bus->sdh; ++ sdpcmd_regs_t *regs = bus->regs; ++ uint32 intstatus, newstatus = 0; ++ uint retries = 0; ++ uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */ ++ uint txlimit = dhd_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 */ ++ unsigned long flags; ++#ifdef DEBUG_DPC_THREAD_WATCHDOG ++ bool is_resched_by_readframe = FALSE; ++#endif /* DEBUG_DPC_THREAD_WATCHDOG */ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ dhd_os_sdlock(bus->dhd); ++ DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); ++ bus->intstatus = 0; ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ dhd_os_sdunlock(bus->dhd); ++ return 0; ++ } ++ ++ DHD_BUS_BUSY_SET_IN_DPC(bus->dhd); ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ /* Start with leftover status bits */ ++ intstatus = bus->intstatus; ++ ++ if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) { ++ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); ++ goto exit; ++ } ++ ++ /* If waiting for HTAVAIL, check status */ ++ if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) { ++ int err; ++ uint8 clkctl, devctl = 0; ++ ++#ifdef DHD_DEBUG ++ /* Check for inconsistent device control */ ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err)); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } else { ++ ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); ++ } ++#endif /* DHD_DEBUG */ ++ ++ /* Read CSR, if clock on switch to AVAIL, else ignore */ ++ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ if (err) { ++ DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err)); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++ ++ DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl)); ++ ++ if (SBSDIO_HTAV(clkctl)) { ++ devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); ++ if (err) { ++ DHD_ERROR(("%s: error reading DEVCTL: %d\n", ++ __FUNCTION__, err)); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++ devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); ++ if (err) { ++ DHD_ERROR(("%s: error writing DEVCTL: %d\n", ++ __FUNCTION__, err)); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ } ++ bus->clkstate = CLK_AVAIL; ++ } else { ++ goto clkwait; ++ } ++ } ++ ++ BUS_WAKE(bus); ++ ++ /* Make sure backplane clock is on */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); ++ if (bus->clkstate != CLK_AVAIL) ++ goto clkwait; ++ ++ /* Pending interrupt indicates new device status */ ++ if (bus->ipend) { ++ bus->ipend = FALSE; ++#if defined(BT_OVER_SDIO) ++ bcmsdh_btsdio_process_f3_intr(); ++#endif /* defined (BT_OVER_SDIO) */ ++ ++ R_SDREG(newstatus, ®s->intstatus, retries); ++ bus->f1regdata++; ++ if (bcmsdh_regfail(bus->sdh)) ++ newstatus = 0; ++ newstatus &= bus->hostintmask; ++ bus->fcstate = !!(newstatus & I_HMB_FC_STATE); ++ if (newstatus) { ++ bus->f1regdata++; ++ if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && ++ (newstatus == I_XMTDATA_AVAIL)) { ++ } else ++ W_SDREG(newstatus, ®s->intstatus, retries); ++ } ++ } ++ ++ /* Merge new bits with previous */ ++ intstatus |= newstatus; ++ bus->intstatus = 0; ++ ++ /* Handle flow-control change: read new state in case our ack ++ * crossed another change interrupt. If change still set, assume ++ * FC ON for safety, let next loop through do the debounce. ++ */ ++ if (intstatus & I_HMB_FC_CHANGE) { ++ intstatus &= ~I_HMB_FC_CHANGE; ++ W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries); ++ R_SDREG(newstatus, ®s->intstatus, retries); ++ bus->f1regdata += 2; ++ bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); ++ intstatus |= (newstatus & bus->hostintmask); ++ } ++ ++ /* Handle host mailbox indication */ ++ if (intstatus & I_HMB_HOST_INT) { ++ uint32 hmbdata = 0; ++ ++ intstatus &= ~I_HMB_HOST_INT; ++ intstatus |= dhdsdio_hostmail(bus, &hmbdata); ++ ++#ifdef DHD_ULP ++ /* ULP prototyping. Redowload fw on oob interupt */ ++ ++ /* all the writes after this point CAN use cached sbwad value */ ++ bcmsdh_force_sbwad_calc(bus->sdh, FALSE); ++ ++ if (dhd_ulp_pre_redownload_check(bus->dhd, bus->sdh, hmbdata)) { ++ if (dhd_bus_ulp_reinit_fw(bus) < 0) { ++ DHD_ERROR(("%s:%d FW redownload failed\n", ++ __FUNCTION__, __LINE__)); ++ goto exit; ++ } ++ } ++#endif ++ ++ } ++ ++ /* Just being here means nothing more to do for chipactive */ ++ if (intstatus & I_CHIPACTIVE) { ++ /* ASSERT(bus->clkstate == CLK_AVAIL); */ ++ intstatus &= ~I_CHIPACTIVE; ++ } ++ ++ /* Handle host mailbox indication */ ++ if (intstatus & I_HMB_HOST_INT) { ++ intstatus &= ~I_HMB_HOST_INT; ++ intstatus |= dhdsdio_hostmail(bus, NULL); ++ } ++ ++ /* Generally don't ask for these, can get CRC errors... */ ++ if (intstatus & I_WR_OOSYNC) { ++ DHD_ERROR(("Dongle reports WR_OOSYNC\n")); ++ intstatus &= ~I_WR_OOSYNC; ++ } ++ ++ if (intstatus & I_RD_OOSYNC) { ++ DHD_ERROR(("Dongle reports RD_OOSYNC\n")); ++ intstatus &= ~I_RD_OOSYNC; ++ } ++ ++ if (intstatus & I_SBINT) { ++ DHD_ERROR(("Dongle reports SBINT\n")); ++ intstatus &= ~I_SBINT; ++ } ++ ++ /* Would be active due to wake-wlan in gSPI */ ++ if (intstatus & I_CHIPACTIVE) { ++ DHD_INFO(("Dongle reports CHIPACTIVE\n")); ++ intstatus &= ~I_CHIPACTIVE; ++ } ++ ++ if (intstatus & I_HMB_FC_STATE) { ++ DHD_INFO(("Dongle reports HMB_FC_STATE\n")); ++ intstatus &= ~I_HMB_FC_STATE; ++ } ++ ++ /* Ignore frame indications if rxskip is set */ ++ if (bus->rxskip) { ++ intstatus &= ~FRAME_AVAIL_MASK(bus); ++ } ++ ++ /* On frame indication, read available frames */ ++ if (PKT_AVAILABLE(bus, intstatus)) { ++ ++ framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); ++ if (rxdone || bus->rxskip) ++ intstatus &= ~FRAME_AVAIL_MASK(bus); ++ rxlimit -= MIN(framecnt, rxlimit); ++ } ++ ++ /* Keep still-pending events for next scheduling */ ++ 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 && !bcmsdh_regfail(sdh) && ++ !(bus->dhd->conf->oob_enabled_later && !bus->ctrl_frame_stat)) { ++ DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", ++ __FUNCTION__, rxdone, framecnt)); ++ bus->intdis = FALSE; ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_oob_intr_set(bus->sdh, TRUE); ++#endif /* defined(OOB_INTR_ONLY) */ ++ bcmsdh_intr_enable(sdh); ++ } ++ ++#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) ++ /* In case of SW-OOB(using edge trigger), ++ * Check interrupt status in the dongle again after enable irq on the host. ++ * and rechedule dpc if interrupt is pended in the dongle. ++ * There is a chance to miss OOB interrupt while irq is disabled on the host. ++ * No need to do this with HW-OOB(level trigger) ++ */ ++ R_SDREG(newstatus, ®s->intstatus, retries); ++ if (bcmsdh_regfail(bus->sdh)) ++ newstatus = 0; ++ if (newstatus & bus->hostintmask) { ++ bus->ipend = TRUE; ++ resched = TRUE; ++ } ++#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ ++ ++#ifdef BCMSDIO_RXLIM_POST ++ if (!DATAOK(bus) && bus->rxlim_en) { ++ uint8 rxlim = 0; ++ if (0 == dhdsdio_membytes(bus, FALSE, bus->rxlim_addr, (uint8 *)&rxlim, 1)) { ++ if (bus->tx_max != rxlim) { ++ DHD_INFO(("%s: bus->tx_max/rxlim=%d/%d\n", __FUNCTION__, ++ bus->tx_max, rxlim)); ++ bus->tx_max = rxlim; ++ } ++ } ++ } ++#endif /* BCMSDIO_RXLIM_POST */ ++ ++#ifdef PROP_TXSTATUS ++ dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE); ++#endif ++ ++ if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) ++ dhdsdio_sendpendctl(bus); ++#ifdef CONSOLE_DPC ++ else if (DATAOK(bus) && strlen(bus->cons_cmd) && (bus->clkstate == CLK_AVAIL) && ++ !bus->fcstate) { ++ dhd_bus_console_in(bus->dhd, bus->cons_cmd, strlen(bus->cons_cmd)); ++ } ++#endif ++ ++ /* Send queued frames (limit 1 if rx may still be pending) */ ++ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && ++ pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { ++ ++#ifdef DHD_ULP ++ if (dhd_ulp_f2_ready(bus->dhd, bus->sdh)) { ++#endif /* DHD_ULP */ ++ if (bus->dhd->conf->dhd_txminmax < 0) ++ framecnt = rxdone ? txlimit : MIN(txlimit, DATABUFCNT(bus)); ++ else ++ framecnt = rxdone ? txlimit : MIN(txlimit, bus->dhd->conf->dhd_txminmax); ++ framecnt = dhdsdio_sendfromq(bus, framecnt); ++ txlimit -= framecnt; ++#ifdef DHD_ULP ++ } else { ++ /* In other transient states like DHD_ULP_, after the states are ++ * DHD_ULP_F2ENAB_CLEARING and DHD_ULP_F2ENAB_SETTING, ++ * dpc is scheduled after steady-state and dhdsdio_sendfromq() will ++ * execute again ++ */ ++ } ++#endif /* DHD_ULP */ ++ } ++ /* Resched the DPC if ctrl cmd is pending on bus credit */ ++ if (bus->ctrl_frame_stat) { ++ if (bus->dhd->conf->txctl_tmo_fix) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!kthread_should_stop()) ++ schedule_timeout(1); ++ set_current_state(TASK_RUNNING); ++ } ++ resched = TRUE; ++ } ++ ++ /* Resched if events or tx frames are pending, else await next interrupt */ ++ /* On failed register access, all bets are off: no resched or interrupts */ ++ if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { ++ if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & ++ SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { ++ /* Bus failed because of KSO */ ++ DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__)); ++ bus->kso = FALSE; ++ } else { ++ DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n", ++ __FUNCTION__)); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ bus->intstatus = 0; ++ } ++ } else if (bus->clkstate == CLK_PENDING) { ++ /* Awaiting I_CHIPACTIVE; don't resched */ ++ } else if (bus->intstatus || bus->ipend || ++ (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || ++ PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ ++ resched = TRUE; ++ } ++ ++ bus->dpc_sched = resched; ++ ++ /* If we're done for now, turn off clock request. */ ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING) && ++ NO_OTHER_ACTIVE_BUS_USER(bus)) { ++ bus->activity = FALSE; ++ dhdsdio_bussleep(bus, TRUE); ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ ++exit: ++ ++ if (!resched) { ++ /* 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 && !bcmsdh_regfail(sdh) && ++ (bus->dhd->conf->oob_enabled_later && !bus->ctrl_frame_stat)) { ++ DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", ++ __FUNCTION__, rxdone, framecnt)); ++ bus->intdis = FALSE; ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_oob_intr_set(bus->sdh, TRUE); ++#endif /* defined(OOB_INTR_ONLY) */ ++ bcmsdh_intr_enable(sdh); ++ } ++ if (dhd_dpcpoll) { ++ if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) { ++ resched = TRUE; ++#ifdef DEBUG_DPC_THREAD_WATCHDOG ++ is_resched_by_readframe = TRUE; ++#endif /* DEBUG_DPC_THREAD_WATCHDOG */ ++ } ++ } ++ } ++ ++ if (bus->ctrl_wait && TXCTLOK(bus)) ++ wake_up_interruptible(&bus->ctrl_tx_wait); ++ dhd_os_sdunlock(bus->dhd); ++#ifdef DEBUG_DPC_THREAD_WATCHDOG ++ if (bus->dhd->dhd_bug_on) { ++ DHD_INFO(("%s: resched = %d ctrl_frame_stat = %d intstatus 0x%08x" ++ " ipend = %d pktq_mlen = %d is_resched_by_readframe = %d \n", ++ __FUNCTION__, resched, bus->ctrl_frame_stat, ++ bus->intstatus, bus->ipend, ++ pktq_mlen(&bus->txq, ~bus->flowcontrol), is_resched_by_readframe)); ++ ++ bus->dhd->dhd_bug_on = FALSE; ++ } ++#endif /* DEBUG_DPC_THREAD_WATCHDOG */ ++ ++ DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_CLEAR_IN_DPC(bus->dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ return resched; ++} ++ ++bool ++dhd_bus_dpc(struct dhd_bus *bus) ++{ ++ bool resched; ++ ++ /* Call the DPC directly. */ ++ DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); ++ resched = dhdsdio_dpc(bus); ++ ++ return resched; ++} ++ ++void ++dhdsdio_isr(void *arg) ++{ ++ dhd_bus_t *bus = (dhd_bus_t*)arg; ++ bcmsdh_info_t *sdh; ++ ++ DHD_INTR(("%s: Enter\n", __FUNCTION__)); ++ ++ if (!bus) { ++ DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__)); ++ return; ++ } ++ sdh = bus->sdh; ++ ++ if (bus->dhd->busstate == DHD_BUS_DOWN) { ++ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); ++ return; ++ } ++ ++ /* Count the interrupt call */ ++ bus->intrcount++; ++ bus->ipend = TRUE; ++ ++ /* Shouldn't get this interrupt if we're sleeping? */ ++ if (!SLPAUTO_ENAB(bus)) { ++ if (bus->sleeping) { ++ DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n")); ++ return; ++ } else if (!KSO_ENAB(bus)) { ++ DHD_ERROR(("ISR in devsleep 1\n")); ++ } ++ } ++ ++ /* Disable additional interrupts (is this needed now)? */ ++ if (bus->intr) { ++ DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); ++ } else { ++ DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n")); ++ } ++ ++ bcmsdh_intr_disable(sdh); ++ bus->intdis = TRUE; ++ ++#if defined(SDIO_ISR_THREAD) ++ DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ /* terence 20150209: dpc should be scheded again if dpc_sched is TRUE or dhd_bus_txdata can ++ not schedule anymore because dpc_sched is TRUE now. ++ */ ++ if (dhdsdio_dpc(bus)) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++#else ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++#endif /* defined(SDIO_ISR_THREAD) */ ++ ++} ++ ++#ifdef PKT_STATICS ++void dhdsdio_txpktstatics(void) ++{ ++ uint i, total = 0; ++ ++ printf("%s: TYPE EVENT: %d pkts (size=%d) transfered\n", ++ __FUNCTION__, tx_statics.event_count, tx_statics.event_size); ++ printf("%s: TYPE CTRL: %d pkts (size=%d) transfered\n", ++ __FUNCTION__, tx_statics.ctrl_count, tx_statics.ctrl_size); ++ printf("%s: TYPE DATA: %d pkts (size=%d) transfered\n", ++ __FUNCTION__, tx_statics.data_count, tx_statics.data_size); ++ printf("%s: Glom size distribution:\n", __FUNCTION__); ++ for (i=0;ipktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN); ++ bus->pktgen_minlen = bus->pktgen_maxlen; ++ } else { ++ bus->pktgen_maxlen = MAX_PKTGEN_LEN; ++ bus->pktgen_minlen = 0; ++ } ++ bus->pktgen_len = (uint16)bus->pktgen_minlen; ++ ++ /* Default to per-watchdog burst with 10s print time */ ++ bus->pktgen_freq = 1; ++ bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0; ++ bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; ++ ++ /* Default to echo mode */ ++ bus->pktgen_mode = DHD_PKTGEN_ECHO; ++ bus->pktgen_stop = 1; ++} ++ ++static void ++dhdsdio_pktgen(dhd_bus_t *bus) ++{ ++ void *pkt; ++ uint8 *data; ++ uint pktcount; ++ uint fillbyte; ++ osl_t *osh = bus->dhd->osh; ++ uint16 len; ++ ulong time_lapse; ++ uint sent_pkts; ++ uint rcvd_pkts; ++ ++ /* Display current count if appropriate */ ++ if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { ++ bus->pktgen_ptick = 0; ++ printf("%s: send attempts %d, rcvd %d, errors %d\n", ++ __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); ++ ++ /* Print throughput stats only for constant length packet runs */ ++ if (bus->pktgen_minlen == bus->pktgen_maxlen) { ++ time_lapse = jiffies - bus->pktgen_prev_time; ++ bus->pktgen_prev_time = jiffies; ++ sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent; ++ bus->pktgen_prev_sent = bus->pktgen_sent; ++ rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd; ++ bus->pktgen_prev_rcvd = bus->pktgen_rcvd; ++ ++ printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n", ++ __FUNCTION__, ++ (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8, ++ (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8); ++ } ++ } ++ ++ /* For recv mode, just make sure dongle has started sending */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { ++ if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { ++ bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; ++ dhdsdio_sdtest_set(bus, bus->pktgen_total); ++ } ++ return; ++ } ++ ++ /* 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 */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { ++ len = SDPCM_TEST_PKT_CNT_FLD_LEN; ++ } else { ++ len = bus->pktgen_len; ++ } ++ if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), ++ TRUE))) {; ++ DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); ++ break; ++ } ++ PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); ++ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; ++ ++ /* Write test header cmd and extra based on mode */ ++ switch (bus->pktgen_mode) { ++ case DHD_PKTGEN_ECHO: ++ *data++ = SDPCM_TEST_ECHOREQ; ++ *data++ = (uint8)bus->pktgen_sent; ++ break; ++ ++ case DHD_PKTGEN_SEND: ++ *data++ = SDPCM_TEST_DISCARD; ++ *data++ = (uint8)bus->pktgen_sent; ++ break; ++ ++ case DHD_PKTGEN_RXBURST: ++ *data++ = SDPCM_TEST_BURST; ++ *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */ ++ break; ++ ++ default: ++ DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode)); ++ PKTFREE(osh, pkt, TRUE); ++ bus->pktgen_count = 0; ++ return; ++ } ++ ++ /* Write test header length field */ ++ *data++ = (bus->pktgen_len >> 0); ++ *data++ = (bus->pktgen_len >> 8); ++ ++ /* Write frame count in a 4 byte field adjucent to SDPCM test header for ++ * burst mode ++ */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) { ++ *data++ = (uint8)(bus->pktgen_count >> 0); ++ *data++ = (uint8)(bus->pktgen_count >> 8); ++ *data++ = (uint8)(bus->pktgen_count >> 16); ++ *data++ = (uint8)(bus->pktgen_count >> 24); ++ } else { ++ ++ /* Then fill in the remainder -- N/A for burst */ ++ for (fillbyte = 0; fillbyte < len; fillbyte++) ++ *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); ++ } ++ ++#ifdef DHD_DEBUG ++ if (DHD_BYTES_ON() && DHD_DATA_ON()) { ++ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; ++ prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN); ++ } ++#endif ++ ++ /* Send it */ ++ if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) { ++ 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 = (uint16)bus->pktgen_minlen; ++ ++ /* Special case for burst mode: just send one request! */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) ++ break; ++ } ++} ++ ++static void ++dhdsdio_sdtest_set(dhd_bus_t *bus, uint count) ++{ ++ void *pkt; ++ uint8 *data; ++ osl_t *osh = bus->dhd->osh; ++ ++ /* Allocate the packet */ ++ if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + ++ SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) { ++ DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); ++ return; ++ } ++ PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + ++ SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN); ++ data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; ++ ++ /* Fill in the test header */ ++ *data++ = SDPCM_TEST_SEND; ++ *data++ = (count > 0)?TRUE:FALSE; ++ *data++ = (bus->pktgen_maxlen >> 0); ++ *data++ = (bus->pktgen_maxlen >> 8); ++ *data++ = (uint8)(count >> 0); ++ *data++ = (uint8)(count >> 8); ++ *data++ = (uint8)(count >> 16); ++ *data++ = (uint8)(count >> 24); ++ ++ /* Send it */ ++ if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) ++ bus->pktgen_fail++; ++} ++ ++ ++static void ++dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) ++{ ++ osl_t *osh = bus->dhd->osh; ++ uint8 *data; ++ uint pktlen; ++ ++ uint8 cmd; ++ uint8 extra; ++ uint16 len; ++ uint16 offset; ++ ++ /* Check for min length */ ++ if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) { ++ DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen)); ++ PKTFREE(osh, pkt, FALSE); ++ return; ++ } ++ ++ /* Extract header fields */ ++ data = PKTDATA(osh, pkt); ++ cmd = *data++; ++ extra = *data++; ++ len = *data++; len += *data++ << 8; ++ DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len)); ++ /* Check length for relevant commands */ ++ if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) { ++ if (pktlen != len + SDPCM_TEST_HDRLEN) { ++ DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d" ++ " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); ++ PKTFREE(osh, pkt, FALSE); ++ return; ++ } ++ } ++ ++ /* Process as per command */ ++ switch (cmd) { ++ case SDPCM_TEST_ECHOREQ: ++ /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ ++ *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP; ++ if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) { ++ bus->pktgen_sent++; ++ } else { ++ bus->pktgen_fail++; ++ PKTFREE(osh, pkt, FALSE); ++ } ++ bus->pktgen_rcvd++; ++ break; ++ ++ case SDPCM_TEST_ECHORSP: ++ if (bus->ext_loop) { ++ PKTFREE(osh, pkt, FALSE); ++ bus->pktgen_rcvd++; ++ break; ++ } ++ ++ for (offset = 0; offset < len; offset++, data++) { ++ if (*data != SDPCM_TEST_FILL(offset, extra)) { ++ DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: " ++ "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n", ++ offset, len, SDPCM_TEST_FILL(offset, extra), *data)); ++ break; ++ } ++ } ++ PKTFREE(osh, pkt, FALSE); ++ bus->pktgen_rcvd++; ++ break; ++ ++ case SDPCM_TEST_DISCARD: ++ { ++ int i = 0; ++ uint8 *prn = data; ++ uint8 testval = extra; ++ for (i = 0; i < len; i++) { ++ if (*prn != testval) { ++ DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n", ++ i, bus->pktgen_rcvd_rcvsession, testval, *prn)); ++ prn++; testval++; ++ } ++ } ++ } ++ PKTFREE(osh, pkt, FALSE); ++ bus->pktgen_rcvd++; ++ break; ++ ++ case SDPCM_TEST_BURST: ++ case SDPCM_TEST_SEND: ++ default: ++ DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d" ++ " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); ++ PKTFREE(osh, pkt, FALSE); ++ break; ++ } ++ ++ /* For recv mode, stop at limit (and tell dongle to stop sending) */ ++ if (bus->pktgen_mode == DHD_PKTGEN_RECV) { ++ if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) { ++ bus->pktgen_rcvd_rcvsession++; ++ ++ if (bus->pktgen_total && ++ (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) { ++ bus->pktgen_count = 0; ++ DHD_ERROR(("Pktgen:rcv test complete!\n")); ++ bus->pktgen_rcv_state = PKTGEN_RCV_IDLE; ++ dhdsdio_sdtest_set(bus, FALSE); ++ bus->pktgen_rcvd_rcvsession = 0; ++ } ++ } ++ } ++} ++#endif /* SDTEST */ ++ ++int dhd_bus_oob_intr_register(dhd_pub_t *dhdp) ++{ ++ int err = 0; ++ ++#if defined(OOB_INTR_ONLY) ++ err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus); ++#endif ++ return err; ++} ++ ++void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp) ++{ ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_oob_intr_unregister(dhdp->bus->sdh); ++#endif ++} ++ ++void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable) ++{ ++#if defined(OOB_INTR_ONLY) ++ bcmsdh_oob_intr_set(dhdp->bus->sdh, enable); ++#endif ++} ++ ++void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub) ++{ ++ bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh); ++} ++ ++void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub) ++{ ++ bcmsdh_dev_relax(dhdpub->bus->sdh); ++} ++ ++bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub) ++{ ++ bool enabled = FALSE; ++ ++ enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh); ++ return enabled; ++} ++ ++extern bool ++dhd_bus_watchdog(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus; ++ unsigned long flags; ++ ++ DHD_TIMER(("%s: Enter\n", __FUNCTION__)); ++ ++ bus = dhdp->bus; ++ ++ if (bus->dhd->dongle_reset) ++ return FALSE; ++ ++ if (bus->dhd->hang_was_sent) { ++ dhd_os_wd_timer(bus->dhd, 0); ++ return FALSE; ++ } ++ ++ /* Ignore the timer if simulating bus down */ ++ if (!SLPAUTO_ENAB(bus) && bus->sleeping) ++ return FALSE; ++ ++ DHD_LINUX_GENERAL_LOCK(dhdp, flags); ++ if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp) || ++ DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) { ++ DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); ++ return FALSE; ++ } ++ DHD_BUS_BUSY_SET_IN_WD(dhdp); ++ DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); ++ ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Poll period: check device if appropriate. */ ++ // terence 20160615: remove !SLPAUTO_ENAB(bus) to fix not able to polling if sr supported ++ if (1 && (bus->poll && (++bus->polltick >= bus->pollrate))) { ++ uint32 intstatus = 0; ++ ++ /* Reset poll tick */ ++ bus->polltick = 0; ++ ++ /* Check device if no interrupts */ ++ if (!bus->intr || (bus->intrcount == bus->lastintrs)) { ++ ++ if (!bus->dpc_sched) { ++ uint8 devpend; ++ devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, ++ SDIOD_CCCR_INTPEND, 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) { ++ bcmsdh_intr_disable(bus->sdh); ++ } ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ } ++ ++ /* Update interrupt tracking */ ++ bus->lastintrs = bus->intrcount; ++ } ++ ++ if ((!bus->dpc_sched) && pktq_len(&bus->txq)) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ ++#ifdef DHD_DEBUG ++ /* Poll for console output periodically */ ++ if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { ++ bus->console.count += dhd_watchdog_ms; ++ if (bus->console.count >= dhd_console_ms) { ++ bus->console.count -= dhd_console_ms; ++ /* Make sure backplane clock is on */ ++ if (SLPAUTO_ENAB(bus)) ++ dhdsdio_bussleep(bus, FALSE); ++ else ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ if (dhdsdio_readconsole(bus) < 0) ++ dhd_console_ms = 0; /* On error, stop trying */ ++ } ++ } ++#endif /* DHD_DEBUG */ ++ ++#ifdef SDTEST ++ /* Generate packets if configured */ ++ if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { ++ /* Make sure backplane clock is on */ ++ if (SLPAUTO_ENAB(bus)) ++ dhdsdio_bussleep(bus, FALSE); ++ else ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ bus->pktgen_tick = 0; ++ dhdsdio_pktgen(bus); ++ } ++#endif ++ ++ /* On idle timeout clear activity flag and/or turn off clock */ ++#ifdef DHD_USE_IDLECOUNT ++ if (bus->activity) ++ bus->activity = FALSE; ++ else { ++ bus->idlecount++; ++ ++ /* ++ * If the condition to switch off the clock is reached And if ++ * BT is inactive (in case of BT_OVER_SDIO build) turn off clk. ++ * ++ * Consider the following case, DHD is configured with ++ * 1) idletime == DHD_IDLE_IMMEDIATE ++ * 2) BT is the last user of the clock ++ * We cannot disable the clock from __dhdsdio_clk_disable ++ * since WLAN might be using it. If WLAN is active then ++ * from the respective function/context after doing the job ++ * the clk is turned off. ++ * But if WLAN is actually inactive then the watchdog should ++ * disable the clock. So the condition check below should be ++ * bus->idletime != 0 instead of idletime == 0 ++ */ ++ if ((bus->idletime != 0) && (bus->idlecount >= bus->idletime) && ++ NO_OTHER_ACTIVE_BUS_USER(bus)) { ++ DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); ++ if (!bus->poll && SLPAUTO_ENAB(bus)) { ++ if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) ++ dhd_os_wd_timer(bus->dhd, 0); ++ } else ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ ++ bus->idlecount = 0; ++ } ++ } ++#else ++ if ((bus->idletime != 0) && (bus->clkstate == CLK_AVAIL) && ++ NO_OTHER_ACTIVE_BUS_USER(bus)) { ++ if (++bus->idlecount >= bus->idletime) { ++ bus->idlecount = 0; ++ if (bus->activity) { ++ bus->activity = FALSE; ++ if (!bus->poll && SLPAUTO_ENAB(bus)) { ++ if (!bus->readframes) ++ dhdsdio_bussleep(bus, TRUE); ++ else ++ bus->reqbussleep = TRUE; ++ } else { ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ } ++ } ++ } ++#endif /* DHD_USE_IDLECOUNT */ ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ DHD_LINUX_GENERAL_LOCK(dhdp, flags); ++ DHD_BUS_BUSY_CLEAR_IN_WD(dhdp); ++ dhd_os_busbusy_wake(dhdp); ++ DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); ++ ++ return bus->ipend; ++} ++ ++extern int ++dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ uint32 addr, val; ++ int rv; ++ void *pkt; ++ ++#ifndef CONSOLE_DPC ++ /* Exclusive bus access */ ++ dhd_os_sdlock(bus->dhd); ++#endif ++ ++ /* Address could be zero if CONSOLE := 0 in dongle Makefile */ ++ if (bus->console_addr == 0) { ++ rv = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ /* Don't allow input if dongle is in reset */ ++ if (bus->dhd->dongle_reset) { ++ rv = BCME_NOTREADY; ++ goto exit; ++ } ++ ++#ifndef CONSOLE_DPC ++ if (!DATAOK(bus)) { ++ DHD_CTL(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d, pktq_len %d\n", ++ __FUNCTION__, bus->tx_max, bus->tx_seq, pktq_len(&bus->txq))); ++ rv = BCME_NOTREADY; ++ goto exit; ++ } ++ ++ /* Request clock to allow SDIO accesses */ ++ BUS_WAKE(bus); ++ /* No pend allowed since txpkt is called later, ht clk has to be on */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++#endif ++ ++ /* Zero cbuf_index */ ++ addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx); ++ val = htol32(0); ++ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) ++ goto done; ++ ++ /* Write message into cbuf */ ++ addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf); ++ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) ++ goto done; ++ ++ /* Write length into vcons_in */ ++ addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in); ++ val = htol32(msglen); ++ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) ++ goto done; ++ ++ /* Bump dongle by sending an empty packet on the event channel. ++ * sdpcm_sendup (RX) checks for virtual console input. ++ */ ++ if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) ++ rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE); ++ ++done: ++#ifndef CONSOLE_DPC ++ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched && ++ NO_OTHER_ACTIVE_BUS_USER(bus)) { ++ bus->activity = FALSE; ++ dhdsdio_bussleep(bus, TRUE); ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++#endif ++ ++exit: ++#ifdef CONSOLE_DPC ++ memset(bus->cons_cmd, 0, sizeof(bus->cons_cmd)); ++#else ++ dhd_os_sdunlock(bus->dhd); ++#endif ++ return rv; ++} ++ ++#ifdef CONSOLE_DPC ++extern int ++dhd_bus_txcons(dhd_pub_t *dhdp, uchar *msg, uint msglen) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ int ret = BCME_OK; ++ ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Address could be zero if CONSOLE := 0 in dongle Makefile */ ++ if (bus->console_addr == 0) { ++ ret = BCME_UNSUPPORTED; ++ goto exit; ++ } ++ ++ /* Don't allow input if dongle is in reset */ ++ if (bus->dhd->dongle_reset) { ++ ret = BCME_NOTREADY; ++ goto exit; ++ } ++ ++ if (msglen >= sizeof(bus->cons_cmd)) { ++ DHD_ERROR(("%s: \"%s\"(%d) too long\n", __FUNCTION__, msg, msglen)); ++ ret = BCME_BADARG; ++ goto exit; ++ } ++ ++ if (!strlen(bus->cons_cmd)) { ++ strncpy(bus->cons_cmd, msg, sizeof(bus->cons_cmd)); ++ DHD_CTL(("%s: \"%s\" delay send, tx_max %d, tx_seq %d, pktq_len %d\n", ++ __FUNCTION__, bus->cons_cmd, bus->tx_max, bus->tx_seq, pktq_len(&bus->txq))); ++ if (!bus->dpc_sched) { ++ bus->dpc_sched = TRUE; ++ dhd_sched_dpc(bus->dhd); ++ } ++ } else { ++ DHD_CTL(("%s: \"%s\" is pending, tx_max %d, tx_seq %d, pktq_len %d\n", ++ __FUNCTION__, bus->cons_cmd, bus->tx_max, bus->tx_seq, pktq_len(&bus->txq))); ++ ret = BCME_NOTREADY; ++ } ++ ++exit: ++ dhd_os_sdunlock(bus->dhd); ++ ++ return ret; ++} ++#endif ++ ++#ifdef DHD_DEBUG ++static void ++dhd_dump_cis(uint fn, uint8 *cis) ++{ ++ uint byte, tag, tdata; ++ DHD_INFO(("Function %d CIS:\n", fn)); ++ ++ for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) { ++ if ((byte % 16) == 0) ++ DHD_INFO((" ")); ++ DHD_INFO(("%02x ", cis[byte])); ++ if ((byte % 16) == 15) ++ DHD_INFO(("\n")); ++ if (!tdata--) { ++ tag = cis[byte]; ++ if (tag == 0xff) ++ break; ++ else if (!tag) ++ tdata = 0; ++ else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) ++ tdata = cis[byte + 1] + 1; ++ else ++ DHD_INFO(("]")); ++ } ++ } ++ if ((byte % 16) != 15) ++ DHD_INFO(("\n")); ++} ++#endif /* DHD_DEBUG */ ++ ++static bool ++dhdsdio_chipmatch(uint16 chipid) ++{ ++ if (chipid == BCM4336_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4330_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43237_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43362_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4314_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43242_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43340_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43341_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43143_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43342_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4334_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43239_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4324_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4335_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4339_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43349_CHIP_ID) ++ return TRUE; ++ if (BCM4345_CHIP(chipid)) ++ return TRUE; ++ if (chipid == BCM4350_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4354_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4358_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43569_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4371_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43430_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM43018_CHIP_ID) ++ return TRUE; ++ if (BCM4349_CHIP(chipid)) ++ return TRUE; ++ if (BCM4347_CHIP(chipid)) ++ return TRUE; ++ if (chipid == BCM4364_CHIP_ID) ++ return TRUE; ++ ++ if (chipid == BCM43012_CHIP_ID) ++ return TRUE; ++ if (chipid == BCM4362_CHIP_ID) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static void * ++dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, ++ uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) ++{ ++ int ret; ++ dhd_bus_t *bus; ++ ++ DHD_MUTEX_LOCK(); ++ ++ /* 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. ++ */ ++ dhd_txbound = DHD_TXBOUND; ++ dhd_rxbound = DHD_RXBOUND; ++ dhd_alignctl = TRUE; ++ sd1idle = TRUE; ++ dhd_readahead = TRUE; ++ retrydata = FALSE; ++ ++#ifdef DISABLE_FLOW_CONTROL ++ dhd_doflow = FALSE; ++#endif /* DISABLE_FLOW_CONTROL */ ++ dhd_dongle_ramsize = 0; ++ dhd_txminmax = DHD_TXMINMAX; ++ ++ forcealign = TRUE; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid)); ++ ++ /* We make assumptions about address window mappings */ ++ ASSERT((uintptr)regsva == SI_ENUM_BASE); ++ ++ /* BCMSDH 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 VENDOR_BROADCOM: ++ break; ++ default: ++ DHD_ERROR(("%s: unknown vendor: 0x%04x\n", ++ __FUNCTION__, venid)); ++ goto forcereturn; ++ } ++ ++ /* Check the Device ID and make sure it's one that we support */ ++ switch (devid) { ++ case 0: ++ DHD_INFO(("%s: allow device id 0, will check chip internals\n", ++ __FUNCTION__)); ++ break; ++ ++ default: ++ DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", ++ __FUNCTION__, venid, devid)); ++ goto forcereturn; ++ } ++ ++ if (osh == NULL) { ++ DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__)); ++ goto forcereturn; ++ } ++ ++ /* Allocate private bus interface state */ ++ if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { ++ DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ bzero(bus, sizeof(dhd_bus_t)); ++ bus->sdh = sdh; ++ bus->cl_devid = (uint16)devid; ++ bus->bus = DHD_BUS; ++ bus->bus_num = bus_no; ++ bus->slot_num = slot; ++ bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; ++ bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */ ++#ifdef BT_OVER_SDIO ++ bus->bt_use_count = 0; ++#endif ++ ++#if defined(SUPPORT_P2P_GO_PS) ++ init_waitqueue_head(&bus->bus_sleep); ++#endif /* LINUX && SUPPORT_P2P_GO_PS */ ++ init_waitqueue_head(&bus->ctrl_tx_wait); ++ ++ /* attempt to attach to the dongle */ ++ if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { ++ DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ /* Attach to the dhd/OS/network interface */ ++ if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) { ++ DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__)); ++ goto fail; ++ } ++#if defined(BT_OVER_SDIO) ++ g_dhd_pub = bus->dhd; ++ DHD_ERROR(("%s: g_dhd_pub %p\n", __FUNCTION__, g_dhd_pub)); ++#endif /* defined (BT_OVER_SDIO) */ ++ ++#if defined(GET_OTP_MAC_ENABLE) || defined(GET_OTP_MODULE_NAME) ++ dhd_conf_get_otp(bus->dhd, sdh); ++#endif ++ ++ /* Allocate buffers */ ++ if (!(dhdsdio_probe_malloc(bus, osh, sdh))) { ++ DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ if (!(dhdsdio_probe_init(bus, osh, sdh))) { ++ DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ if (bus->intr) { ++ /* Register interrupt callback, but mask it (not operational yet). */ ++ DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__)); ++ bcmsdh_intr_disable(sdh); ++ if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { ++ DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n", ++ __FUNCTION__, ret)); ++ goto fail; ++ } ++ DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__)); ++ } else { ++ DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n", ++ __FUNCTION__)); ++ } ++ ++ DHD_INFO(("%s: completed!!\n", __FUNCTION__)); ++ ++ /* if firmware path present try to download and bring up bus */ ++ bus->dhd->hang_report = TRUE; ++#if 0 // terence 20150325: fix for WPA/WPA2 4-way handshake fail in hostapd ++ if (dhd_download_fw_on_driverload) { ++ if ((ret = dhd_bus_start(bus->dhd)) != 0) { ++ DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); ++ goto fail; ++ } ++ } ++ else { ++ /* Set random MAC address during boot time */ ++ get_random_bytes(&bus->dhd->mac.octet[3], 3); ++ /* Adding BRCM OUI */ ++ bus->dhd->mac.octet[0] = 0; ++ bus->dhd->mac.octet[1] = 0x90; ++ bus->dhd->mac.octet[2] = 0x4C; ++ } ++#endif ++#if defined(BT_OVER_SDIO) ++ /* At this point Regulators are turned on and iconditionaly sdio bus is started ++ * based upon dhd_download_fw_on_driverload check, so ++ * increase the bus user count, this count will only be disabled inside ++ * dhd_register_if() function if flag dhd_download_fw_on_driverload is set to false, ++ * i.e FW download during insmod is not needed, otherwise it will not be decremented ++ * so that WALN will always hold the bus untill rmmod is done. ++ */ ++ dhdsdio_bus_usr_cnt_inc(bus->dhd); ++#endif /* BT_OVER_SDIO */ ++ ++#ifdef GET_OTP_MAC_ENABLE ++ if (memcmp(ðer_null, &bus->dhd->conf->otp_mac, ETHER_ADDR_LEN)) ++ memcpy(bus->dhd->mac.octet, (void *)&bus->dhd->conf->otp_mac, ETHER_ADDR_LEN); ++#endif /* GET_CUSTOM_MAC_ENABLE */ ++ ++ /* Ok, have the per-port tell the stack we're open for business */ ++ if (dhd_register_if(bus->dhd, 0, TRUE) != 0) { ++ DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++#ifdef BCMHOST_XTAL_PU_TIME_MOD ++ bcmsdh_reg_write(bus->sdh, 0x18000620, 2, 11); ++#ifdef BCM4330_CHIP ++ bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x0000F801); ++#else ++ bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x00F80001); ++#endif /* BCM4330_CHIP */ ++#endif /* BCMHOST_XTAL_PU_TIME_MOD */ ++ ++#if defined(MULTIPLE_SUPPLICANT) ++ wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe ++#endif /* MULTIPLE_SUPPLICANT */ ++ DHD_MUTEX_UNLOCK(); ++ ++ return bus; ++ ++fail: ++ dhdsdio_release(bus, osh); ++ ++forcereturn: ++ DHD_MUTEX_UNLOCK(); ++ ++ return NULL; ++} ++ ++static bool ++dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, ++ uint16 devid) ++{ ++ uint8 clkctl = 0; ++ uint fn, numfn; ++ uint8 *cis[SDIOD_MAX_IOFUNCS]; ++ int err = 0; ++ ++ ++ bus->alp_only = TRUE; ++ bus->sih = NULL; ++ ++ /* Return the window to backplane enumeration space for core access */ ++ if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) { ++ DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__)); ++ } ++ ++#if defined(DHD_DEBUG) && !defined(CUSTOMER_HW4_DEBUG) ++ DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n", ++ bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4))); ++#endif /* DHD_DEBUG && !CUSTOMER_HW4_DEBUG */ ++ ++ ++ /* Force PLL off until si_attach() programs PLL control regs */ ++ ++ ++ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err); ++ if (!err) ++ clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); ++ ++ if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) { ++ DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", ++ err, DHD_INIT_CLKCTL1, clkctl)); ++ goto fail; ++ } ++ numfn = bcmsdh_query_iofnum(sdh); ++ ASSERT(numfn <= SDIOD_MAX_IOFUNCS); ++ ++ /* Make sure ALP is available before trying to read CIS */ ++ SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, NULL)), ++ !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY); ++ ++ /* Now request ALP be put on the bus */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ DHD_INIT_CLKCTL2, &err); ++ OSL_DELAY(200); ++ ++ if (DHD_INFO_ON()) { ++ for (fn = 0; fn <= numfn; fn++) { ++ if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { ++ DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn)); ++ break; ++ } ++ bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); ++ ++ if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], ++ SBSDIO_CIS_SIZE_LIMIT))) { ++ DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err)); ++ MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); ++ break; ++ } ++#if 0 ++ /* Reading the F1, F2 and F3 max blocksize values from CIS ++ * and writing into the F1, F2 and F3 block size registers. ++ * There is no max block size register value available for F0 in CIS register. ++ * So, setting default value for F0 block size as 32 (which was set earlier ++ * in iovar). IOVAR takes only one arguement. ++ * So, we are passing the function number alongwith the value (fn<<16) ++ */ ++ if (!fn) ++ value = F0_BLOCK_SIZE; ++ else ++ value = (cis[fn][25]<<8) | cis[fn][24] | (fn<<16); ++ printf("%s: fn=%d, value=%d\n", __FUNCTION__, fn, value); ++ if (bcmsdh_iovar_op(sdh, "sd_blocksize", NULL, 0, &value, ++ sizeof(value), TRUE) != BCME_OK) { ++ bus->blocksize = 0; ++ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, ++ "sd_blocksize")); ++ } ++#endif ++#ifdef DHD_DEBUG ++ if (DHD_INFO_ON()) { ++ dhd_dump_cis(fn, cis[fn]); ++ } ++#endif /* DHD_DEBUG */ ++ } ++ while (fn-- > 0) { ++ ASSERT(cis[fn]); ++ MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); ++ } ++ } ++#if 0 ++ if (dhd_conf_set_blksize(sdh)) { ++ bus->blocksize = 0; ++ } ++#endif ++ if (err) { ++ DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n")); ++ goto fail; ++ } ++ /* si_attach() will provide an SI handle and scan the backplane */ ++ if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh, ++ &bus->vars, &bus->varsz))) { ++ DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++#ifdef DHD_DEBUG ++ DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n", ++ bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg)); ++#endif /* DHD_DEBUG */ ++ ++ ++ bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); ++ ++ if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { ++ DHD_ERROR(("%s: unsupported chip: 0x%04x\n", ++ __FUNCTION__, bus->sih->chip)); ++ goto fail; ++ } ++ ++ if (bus->sih->buscorerev >= 12) ++ dhdsdio_clk_kso_init(bus); ++ else ++ bus->kso = TRUE; ++ ++ if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) { ++ } ++ ++ si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); ++ ++ ++ /* Get info on the ARM and SOCRAM cores... */ ++ if (!DHD_NOPMU(bus)) { ++ if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || ++ (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) || ++ (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) { ++ bus->armrev = si_corerev(bus->sih); ++ } else { ++ DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); ++ goto fail; ++ } ++ ++ if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { ++ DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); ++ goto fail; ++ } ++ } else { ++ /* cr4 has a different way to find the RAM size from TCM's */ ++ if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) { ++ DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__)); ++ goto fail; ++ } ++ /* also populate base address */ ++ switch ((uint16)bus->sih->chip) { ++ case BCM4335_CHIP_ID: ++ case BCM4339_CHIP_ID: ++ case BCM43349_CHIP_ID: ++ bus->dongle_ram_base = CR4_4335_RAM_BASE; ++ break; ++ case BCM4350_CHIP_ID: ++ case BCM4354_CHIP_ID: ++ case BCM4358_CHIP_ID: ++ case BCM43569_CHIP_ID: ++ case BCM4371_CHIP_ID: ++ bus->dongle_ram_base = CR4_4350_RAM_BASE; ++ break; ++ case BCM4360_CHIP_ID: ++ bus->dongle_ram_base = CR4_4360_RAM_BASE; ++ break; ++ CASE_BCM4345_CHIP: ++ bus->dongle_ram_base = (bus->sih->chiprev < 6) /* from 4345C0 */ ++ ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE; ++ break; ++ case BCM4349_CHIP_GRPID: ++ /* RAM based changed from 4349c0(revid=9) onwards */ ++ bus->dongle_ram_base = ((bus->sih->chiprev < 9) ? ++ CR4_4349_RAM_BASE: CR4_4349_RAM_BASE_FROM_REV_9); ++ break; ++ case BCM4364_CHIP_ID: ++ bus->dongle_ram_base = CR4_4364_RAM_BASE; ++ break; ++ case BCM4347_CHIP_GRPID: ++ bus->dongle_ram_base = CR4_4347_RAM_BASE; ++ break; ++ case BCM4362_CHIP_ID: ++ bus->dongle_ram_base = CR4_4362_RAM_BASE; ++ break; ++ default: ++ bus->dongle_ram_base = 0; ++ DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n", ++ __FUNCTION__, bus->dongle_ram_base)); ++ } ++ } ++ bus->ramsize = bus->orig_ramsize; ++ if (dhd_dongle_ramsize) ++ dhd_dongle_setramsize(bus, dhd_dongle_ramsize); ++ ++ DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n", ++ bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base)); ++ ++ bus->srmemsize = si_socram_srmem_size(bus->sih); ++ } ++ ++ /* ...but normally deal with the SDPCMDEV core */ ++ if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) && ++ !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) { ++ DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__)); ++ goto fail; ++ } ++ bus->sdpcmrev = si_corerev(bus->sih); ++ ++ /* Set core control so an SDIO reset does a backplane reset */ ++ OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); ++ bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; ++ ++ if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && ++ (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) ++ { ++ uint32 val; ++ ++ val = R_REG(osh, &bus->regs->corecontrol); ++ val &= ~CC_XMTDATAAVAIL_MODE; ++ val |= CC_XMTDATAAVAIL_CTRL; ++ W_REG(osh, &bus->regs->corecontrol, val); ++ } ++ ++ ++ pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); ++ ++ /* Locate an appropriately-aligned portion of hdrbuf */ ++ bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); ++ ++ /* Set the poll and/or interrupt flags */ ++ bus->intr = (bool)dhd_intr; ++ if ((bus->poll = (bool)dhd_poll)) ++ bus->pollrate = 1; ++ ++ /* Setting default Glom size */ ++ bus->txglomsize = SDPCM_DEFGLOM_SIZE; ++ ++ return TRUE; ++ ++fail: ++ if (bus->sih != NULL) { ++ si_detach(bus->sih); ++ bus->sih = NULL; ++ } ++ return FALSE; ++} ++ ++static bool ++dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) ++{ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (bus->dhd->maxctl) { ++ bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; ++ if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) { ++ DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", ++ __FUNCTION__, bus->rxblen)); ++ goto fail; ++ } ++ } ++ /* Allocate buffer to receive glomed packet */ ++ if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { ++ DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", ++ __FUNCTION__, MAX_DATA_BUF)); ++ /* release rxbuf which was already located as above */ ++ if (!bus->rxblen) ++ DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen); ++ goto fail; ++ } ++ /* Allocate buffer to membuf */ ++ bus->membuf = MALLOC(osh, MAX_MEM_BUF); ++ if (bus->membuf == NULL) { ++ DHD_ERROR(("%s: MALLOC of %d-byte membuf failed\n", ++ __FUNCTION__, MAX_MEM_BUF)); ++ if (bus->databuf) { ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(osh, bus->databuf, MAX_DATA_BUF); ++#endif ++ bus->databuf = NULL; ++ } ++ /* release rxbuf which was already located as above */ ++ if (!bus->rxblen) ++ DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen); ++ goto fail; ++ } ++ memset(bus->membuf, 0, MAX_MEM_BUF); ++ ++ /* Align the buffer */ ++ if ((uintptr)bus->databuf % DHD_SDALIGN) ++ bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN)); ++ else ++ bus->dataptr = bus->databuf; ++ ++ return TRUE; ++ ++fail: ++ return FALSE; ++} ++ ++static bool ++dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) ++{ ++ int32 fnum; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ bus->_srenab = FALSE; ++ ++#ifdef SDTEST ++ dhdsdio_pktgen_init(bus); ++#endif /* SDTEST */ ++ ++ /* set PMU minimum resource mask to default */ ++ dhd_bus_set_default_min_res_mask(bus); ++ /* Disable F2 to clear any intermediate frame state on the dongle */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); ++ ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ bus->sleeping = FALSE; ++ bus->rxflow = FALSE; ++ bus->prev_rxlim_hit = 0; ++ ++ /* Done with backplane-dependent accesses, can drop clock... */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); ++ ++ /* ...and initialize clock/power states */ ++ bus->clkstate = CLK_SDONLY; ++ bus->idletime = (int32)dhd_idletime; ++ bus->idleclock = DHD_IDLE_ACTIVE; ++ ++ /* Query the SD clock speed */ ++ if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0, ++ &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { ++ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor")); ++ bus->sd_divisor = -1; ++ } else { ++ DHD_INFO(("%s: Initial value for %s is %d\n", ++ __FUNCTION__, "sd_divisor", bus->sd_divisor)); ++ } ++ ++ /* Query the SD bus mode */ ++ if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0, ++ &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { ++ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode")); ++ bus->sd_mode = -1; ++ } else { ++ DHD_INFO(("%s: Initial value for %s is %d\n", ++ __FUNCTION__, "sd_mode", bus->sd_mode)); ++ } ++ ++ /* Query the F2 block size, set roundup accordingly */ ++ fnum = 2; ++ if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32), ++ &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { ++ bus->blocksize = 0; ++ DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); ++ } else { ++ DHD_INFO(("%s: Initial value for %s is %d\n", ++ __FUNCTION__, "sd_blocksize", bus->blocksize)); ++ ++ dhdsdio_tune_fifoparam(bus); ++ } ++ bus->roundup = MIN(max_roundup, bus->blocksize); ++ ++#ifdef DHDENABLE_TAILPAD ++ if (bus->pad_pkt) ++ PKTFREE(osh, bus->pad_pkt, FALSE); ++ bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE); ++ if (bus->pad_pkt == NULL) ++ DHD_ERROR(("failed to allocate padding packet\n")); ++ else { ++ int alignment_offset = 0; ++ uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt); ++ if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN))) ++ PKTPUSH(osh, bus->pad_pkt, alignment_offset); ++ PKTSETNEXT(osh, bus->pad_pkt, NULL); ++ } ++#endif /* DHDENABLE_TAILPAD */ ++ ++ /* Query if bus module supports packet chaining, default to use if supported */ ++ if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0, ++ &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) { ++ bus->sd_rxchain = FALSE; ++ } else { ++ DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n", ++ __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support"))); ++ } ++ bus->use_rxchain = (bool)bus->sd_rxchain; ++ bus->txinrx_thres = CUSTOM_TXINRX_THRES; ++ /* TX first in dhdsdio_readframes() */ ++ bus->dotxinrx = TRUE; ++ ++#ifdef PKT_STATICS ++ memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t)); ++#endif ++ ++ return TRUE; ++} ++ ++int ++dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ++ char *pfw_path, char *pnv_path, ++ char *pclm_path, char *pconf_path) ++{ ++ int ret; ++ ++ bus->fw_path = pfw_path; ++ bus->nv_path = pnv_path; ++ bus->dhd->clm_path = pclm_path; ++ bus->dhd->conf_path = pconf_path; ++ ++ ret = dhdsdio_download_firmware(bus, osh, bus->sdh); ++ ++ return ret; ++} ++ ++void ++dhd_set_bus_params(struct dhd_bus *bus) ++{ ++ if (bus->dhd->conf->dhd_poll >= 0) { ++ bus->poll = bus->dhd->conf->dhd_poll; ++ if (!bus->pollrate) ++ bus->pollrate = 1; ++ printf("%s: set polling mode %d\n", __FUNCTION__, bus->dhd->conf->dhd_poll); ++ } ++ if (bus->dhd->conf->use_rxchain >= 0) { ++ bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain; ++ } ++ if (bus->dhd->conf->txinrx_thres >= 0) { ++ bus->txinrx_thres = bus->dhd->conf->txinrx_thres; ++ } ++ if (bus->dhd->conf->txglomsize >= 0) { ++ bus->txglomsize = bus->dhd->conf->txglomsize; ++ } ++} ++ ++static int ++dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) ++{ ++ int ret; ++ ++ ++#if defined(DHD_BLOB_EXISTENCE_CHECK) ++ dhd_set_blob_support(bus->dhd, bus->fw_path); ++#endif /* DHD_BLOB_EXISTENCE_CHECK */ ++ ++ DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n", ++ __FUNCTION__, bus->fw_path, bus->nv_path)); ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ ++ dhd_conf_set_path_params(bus->dhd, bus->fw_path, bus->nv_path); ++ dhd_set_bus_params(bus); ++ ++ /* Download the firmware */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ ret = _dhdsdio_download_firmware(bus); ++ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++ return ret; ++} ++ ++/* Detach and free everything */ ++static void ++dhdsdio_release(dhd_bus_t *bus, osl_t *osh) ++{ ++ bool dongle_isolation = FALSE; ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (bus) { ++ ASSERT(osh); ++ ++ if (bus->dhd) { ++ dongle_isolation = bus->dhd->dongle_isolation; ++ dhd_detach(bus->dhd); ++ } ++ ++ /* De-register interrupt handler */ ++ bcmsdh_intr_disable(bus->sdh); ++ bcmsdh_intr_dereg(bus->sdh); ++ ++ if (bus->dhd) { ++ dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); ++ dhd_free(bus->dhd); ++ bus->dhd = NULL; ++ } ++ ++ dhdsdio_release_malloc(bus, osh); ++ ++#ifdef DHD_DEBUG ++ if (bus->console.buf != NULL) ++ MFREE(osh, bus->console.buf, bus->console.bufsize); ++#endif ++ ++#ifdef DHDENABLE_TAILPAD ++ if (bus->pad_pkt) ++ PKTFREE(osh, bus->pad_pkt, FALSE); ++#endif /* DHDENABLE_TAILPAD */ ++ ++ MFREE(osh, bus, sizeof(dhd_bus_t)); ++ } ++ ++ DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); ++} ++ ++static void ++dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) ++{ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ if (bus->dhd && bus->dhd->dongle_reset) ++ return; ++ ++ if (bus->rxbuf) { ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(osh, bus->rxbuf, bus->rxblen); ++#endif ++ bus->rxctl = bus->rxbuf = NULL; ++ bus->rxlen = 0; ++ } ++ ++ if (bus->databuf) { ++#ifndef CONFIG_DHD_USE_STATIC_BUF ++ MFREE(osh, bus->databuf, MAX_DATA_BUF); ++#endif ++ bus->databuf = NULL; ++ } ++ ++ if (bus->membuf) { ++ MFREE(osh, bus->membuf, MAX_DATA_BUF); ++ bus->membuf = NULL; ++ } ++ ++ if (bus->vars && bus->varsz) { ++ MFREE(osh, bus->vars, bus->varsz); ++ bus->vars = NULL; ++ } ++ ++} ++ ++ ++static void ++dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) ++{ ++ DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, ++ bus->dhd, bus->dhd->dongle_reset)); ++ ++ if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) ++ return; ++ ++ if (bus->sih) { ++ /* In Win10, system will be BSOD if using "sysprep" to do OS image */ ++ /* Skip this will not cause the BSOD. */ ++#if !defined(BCMLXSDMMC) ++ if (bus->dhd) { ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ } ++ if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) ++ si_watchdog(bus->sih, 4); ++#endif /* !defined(BCMLXSDMMC) */ ++ if (bus->dhd) { ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ si_detach(bus->sih); ++ bus->sih = NULL; ++ if (bus->vars && bus->varsz) ++ MFREE(osh, bus->vars, bus->varsz); ++ bus->vars = NULL; ++ } ++ ++ DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); ++} ++ ++static void ++dhdsdio_disconnect(void *ptr) ++{ ++ dhd_bus_t *bus = (dhd_bus_t *)ptr; ++ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ DHD_MUTEX_LOCK(); ++ if (bus) { ++ ASSERT(bus->dhd); ++ /* Advertise bus remove during rmmod */ ++ dhdsdio_advertise_bus_remove(bus->dhd); ++ dhdsdio_release(bus, bus->dhd->osh); ++ } ++ DHD_MUTEX_UNLOCK(); ++ ++ DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); ++} ++ ++static int ++dhdsdio_suspend(void *context) ++{ ++ int ret = 0; ++#ifdef SUPPORT_P2P_GO_PS ++ int wait_time = 0; ++#endif /* SUPPORT_P2P_GO_PS */ ++ ++ dhd_bus_t *bus = (dhd_bus_t*)context; ++ unsigned long flags; ++ ++ DHD_ERROR(("%s Enter\n", __FUNCTION__)); ++ if (bus->dhd == NULL) { ++ DHD_ERROR(("bus not inited\n")); ++ return BCME_ERROR; ++ } ++ if (bus->dhd->prot == NULL) { ++ DHD_ERROR(("prot is not inited\n")); ++ return BCME_ERROR; ++ } ++ ++ if (bus->dhd->up == FALSE) { ++ return BCME_OK; ++ } ++ ++ DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); ++ if (bus->dhd->busstate != DHD_BUS_DATA && bus->dhd->busstate != DHD_BUS_SUSPEND) { ++ DHD_ERROR(("not in a readystate to LPBK is not inited\n")); ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ return BCME_ERROR; ++ } ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ if (bus->dhd->dongle_reset) { ++ DHD_ERROR(("Dongle is in reset state.\n")); ++ return -EIO; ++ } ++ ++ DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); ++ bus->dhd->busstate = DHD_BUS_SUSPEND; ++ if (DHD_BUS_BUSY_CHECK_IN_TX(bus->dhd)) { ++ DHD_ERROR(("Tx Request is not ended\n")); ++ bus->dhd->busstate = DHD_BUS_DATA; ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ return -EBUSY; ++ } ++ DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd); ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ ++#ifdef SUPPORT_P2P_GO_PS ++ if (bus->idletime > 0) { ++ wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms); ++ } ++#endif /* SUPPORT_P2P_GO_PS */ ++ ret = dhd_os_check_wakelock(bus->dhd); ++#ifdef SUPPORT_P2P_GO_PS ++ // terence 20141124: fix for suspend issue ++ if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up) && (bus->dhd->op_mode != DHD_FLAG_HOSTAP_MODE)) { ++ if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) { ++ if (!bus->sleeping) { ++ ret = 1; ++ } ++ } ++ } ++#endif /* SUPPORT_P2P_GO_PS */ ++ ++ DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); ++ if (ret) { ++ bus->dhd->busstate = DHD_BUS_DATA; ++ } ++ DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd); ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ return ret; ++} ++ ++static int ++dhdsdio_resume(void *context) ++{ ++ dhd_bus_t *bus = (dhd_bus_t*)context; ++ ulong flags; ++ ++ DHD_ERROR(("%s Enter\n", __FUNCTION__)); ++ ++ if (bus->dhd->up == FALSE) { ++ return BCME_OK; ++ } ++ ++ DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd); ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ ++#if defined(OOB_INTR_ONLY) ++ if (dhd_os_check_if_up(bus->dhd)) ++ bcmsdh_oob_intr_set(bus->sdh, TRUE); ++#endif ++ ++ DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); ++ DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd); ++ bus->dhd->busstate = DHD_BUS_DATA; ++ dhd_os_busbusy_wake(bus->dhd); ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ return 0; ++} ++ ++ ++/* 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. ++ */ ++ ++static bcmsdh_driver_t dhd_sdio = { ++ dhdsdio_probe, ++ dhdsdio_disconnect, ++ dhdsdio_suspend, ++ dhdsdio_resume ++}; ++ ++int ++dhd_bus_register(void) ++{ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ return bcmsdh_register(&dhd_sdio); ++} ++ ++void ++dhd_bus_unregister(void) ++{ ++ DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ++ ++ bcmsdh_unregister(); ++} ++ ++#if defined(BCMLXSDMMC) ++/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ ++int dhd_bus_reg_sdio_notify(void* semaphore) ++{ ++ return bcmsdh_reg_sdio_notify(semaphore); ++} ++ ++void dhd_bus_unreg_sdio_notify(void) ++{ ++ bcmsdh_unreg_sdio_notify(); ++} ++#endif /* defined(BCMLXSDMMC) */ ++ ++#ifdef BCMEMBEDIMAGE ++static int ++dhdsdio_download_code_array(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ int offset = 0; ++ unsigned char *ularray = NULL; ++ ++ DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__)); ++ ++ /* Download image */ ++ while ((offset + MEMBLOCK) < sizeof(dlarray)) { ++ /* check if CR4 */ ++ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ /* if address is 0, store the reset instruction to be written in 0 */ ++ ++ if (offset == 0) { ++ bus->resetinstr = *(((uint32*)dlarray)); ++ /* Add start of RAM address to the address given by user */ ++ offset += bus->dongle_ram_base; ++ } ++ } ++ ++ bcmerror = dhdsdio_membytes(bus, TRUE, offset, ++ (uint8 *) (dlarray + offset), MEMBLOCK); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset)); ++ goto err; ++ } ++ ++ offset += MEMBLOCK; ++ } ++ ++ if (offset < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, TRUE, offset, ++ (uint8 *) (dlarray + offset), sizeof(dlarray) - offset); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); ++ goto err; ++ } ++ } ++ ++#ifdef DHD_DEBUG ++ /* Upload and compare the downloaded code */ ++ { ++ ularray = MALLOC(bus->dhd->osh, bus->ramsize); ++ /* Upload image to verify downloaded contents. */ ++ offset = 0; ++ memset(ularray, 0xaa, bus->ramsize); ++ while ((offset + MEMBLOCK) < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset)); ++ goto err; ++ } ++ ++ offset += MEMBLOCK; ++ } ++ ++ if (offset < sizeof(dlarray)) { ++ bcmerror = dhdsdio_membytes(bus, FALSE, offset, ++ ularray + offset, sizeof(dlarray) - offset); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); ++ goto err; ++ } ++ } ++ ++ if (memcmp(dlarray, ularray, sizeof(dlarray))) { ++ DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", ++ __FUNCTION__, dlimagename, dlimagever, dlimagedate)); ++ goto err; ++ } else ++ DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", ++ __FUNCTION__, dlimagename, dlimagever, dlimagedate)); ++ ++ } ++#endif /* DHD_DEBUG */ ++ ++err: ++ if (ularray) ++ MFREE(bus->dhd->osh, ularray, bus->ramsize); ++ return bcmerror; ++} ++#endif /* BCMEMBEDIMAGE */ ++ ++static int ++dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) ++{ ++ int bcmerror = -1; ++ int offset = 0; ++ int len; ++ void *image = NULL; ++ uint8 *memblock = NULL, *memptr; ++ uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct ++ uint memblock_size = MEMBLOCK; ++#ifdef DHD_DEBUG_DOWNLOADTIME ++ unsigned long initial_jiffies = 0; ++ uint firmware_sz = 0; ++#endif ++ ++ DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); ++ ++ image = dhd_os_open_image(pfw_path); ++ if (image == NULL) { ++ printf("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path); ++ goto err; ++ } ++ ++ /* Update the dongle image download block size depending on the F1 block size */ ++ if (sd_f1_blocksize == 512) ++ memblock_size = MAX_MEMBLOCK; ++ ++ memptr = memblock = MALLOC(bus->dhd->osh, memblock_size + DHD_SDALIGN); ++ if (memblock == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, ++ memblock_size)); ++ goto err; ++ } ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); ++ if (memptr_tmp == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); ++ goto err; ++ } ++ } ++ if ((uint32)(uintptr)memblock % DHD_SDALIGN) ++ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); ++ ++#ifdef DHD_DEBUG_DOWNLOADTIME ++ initial_jiffies = jiffies; ++#endif ++ ++ /* Download image */ ++ while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, image))) { ++ // terence 20150412: fix for firmware failed to download ++ if (bus->dhd->conf->chip == BCM43340_CHIP_ID || ++ bus->dhd->conf->chip == BCM43341_CHIP_ID) { ++ if (len % 64 != 0) { ++ memset(memptr+len, 0, len%64); ++ len += (64 - len%64); ++ } ++ } ++ if (len < 0) { ++ DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); ++ bcmerror = BCME_ERROR; ++ goto err; ++ } ++ /* check if CR4 */ ++ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) { ++ /* if address is 0, store the reset instruction to be written in 0 */ ++ ++ if (offset == 0) { ++ bus->resetinstr = *(((uint32*)memptr)); ++ /* Add start of RAM address to the address given by user */ ++ offset += bus->dongle_ram_base; ++ } ++ } ++ ++ bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, memblock_size, offset)); ++ goto err; ++ } ++ ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, MEMBLOCK, offset)); ++ goto err; ++ } ++ if (memcmp(memptr_tmp, memptr, len)) { ++ DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__)); ++ goto err; ++ } else ++ DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__)); ++ } ++ ++ offset += memblock_size; ++#ifdef DHD_DEBUG_DOWNLOADTIME ++ firmware_sz += len; ++#endif ++ } ++ ++#ifdef DHD_DEBUG_DOWNLOADTIME ++ DHD_ERROR(("Firmware download time for %u bytes: %u ms\n", ++ firmware_sz, jiffies_to_msecs(jiffies - initial_jiffies))); ++#endif ++ ++err: ++ if (memblock) ++ MFREE(bus->dhd->osh, memblock, memblock_size + DHD_SDALIGN); ++ if (dhd_msg_level & DHD_TRACE_VAL) { ++ if (memptr_tmp) ++ MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN); ++ } ++ ++ if (image) ++ dhd_os_close_image(image); ++ ++ return bcmerror; ++} ++ ++#ifdef DHD_UCODE_DOWNLOAD ++/* Currently supported only for the chips in which ucode RAM is AXI addressable */ ++static uint32 ++dhdsdio_ucode_base(struct dhd_bus *bus) ++{ ++ uint32 ucode_base = 0; ++ ++ switch ((uint16)bus->sih->chip) { ++ case BCM43012_CHIP_ID: ++ ucode_base = 0xE8020000; ++ break; ++ default: ++ DHD_ERROR(("%s: Unsupported!\n", __func__)); ++ break; ++ } ++ ++ return ucode_base; ++} ++ ++static int ++dhdsdio_download_ucode_file(struct dhd_bus *bus, char *ucode_path) ++{ ++ int bcmerror = -1; ++ int offset = 0; ++ int len; ++ uint32 ucode_base; ++ void *image = NULL; ++ uint8 *memblock = NULL, *memptr; ++ uint memblock_size = MEMBLOCK; ++#ifdef DHD_DEBUG_DOWNLOADTIME ++ unsigned long initial_jiffies = 0; ++ uint firmware_sz = 0; ++#endif ++ ++ DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, ucode_path)); ++ ++ ucode_base = dhdsdio_ucode_base(bus); ++ ++ image = dhd_os_open_image(ucode_path); ++ if (image == NULL) ++ goto err; ++ ++ /* Update the dongle image download block size depending on the F1 block size */ ++ if (sd_f1_blocksize == 512) ++ memblock_size = MAX_MEMBLOCK; ++ ++ memptr = memblock = MALLOC(bus->dhd->osh, memblock_size + DHD_SDALIGN); ++ if (memblock == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, ++ memblock_size)); ++ goto err; ++ } ++ if ((uint32)(uintptr)memblock % DHD_SDALIGN) ++ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); ++ ++#ifdef DHD_DEBUG_DOWNLOADTIME ++ initial_jiffies = jiffies; ++#endif ++ ++ /* Download image */ ++ while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, image))) { ++ if (len < 0) { ++ DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); ++ bcmerror = BCME_ERROR; ++ goto err; ++ } ++ ++ bcmerror = dhdsdio_membytes(bus, TRUE, (ucode_base + offset), memptr, len); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcmerror, memblock_size, offset)); ++ goto err; ++ } ++ ++ offset += memblock_size; ++#ifdef DHD_DEBUG_DOWNLOADTIME ++ firmware_sz += len; ++#endif ++ } ++ ++#ifdef DHD_DEBUG_DOWNLOADTIME ++ DHD_ERROR(("ucode download time for %u bytes: %u ms\n", ++ firmware_sz, jiffies_to_msecs(jiffies - initial_jiffies))); ++#endif ++ ++err: ++ if (memblock) ++ MFREE(bus->dhd->osh, memblock, memblock_size + DHD_SDALIGN); ++ ++ if (image) ++ dhd_os_close_image(image); ++ ++ return bcmerror; ++} ++ ++void ++dhd_bus_ucode_download(struct dhd_bus *bus) ++{ ++ uint32 shaddr = 0, shdata = 0; ++ ++ shaddr = bus->dongle_ram_base + bus->ramsize - 4; ++ dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&shdata, 4); ++ ++ DHD_TRACE(("%s: shdata:[0x%08x :0x%08x]\n", __func__, shaddr, shdata)); ++ ++ if (shdata == UCODE_DOWNLOAD_REQUEST) ++ { ++ DHD_ERROR(("%s: Received ucode download request!\n", __func__)); ++ ++ /* Download the ucode */ ++ if (!dhd_get_ucode_path(bus->dhd)) { ++ DHD_ERROR(("%s: bus->uc_path not set!\n", __func__)); ++ return; ++ } ++ dhdsdio_download_ucode_file(bus, dhd_get_ucode_path(bus->dhd)); ++ ++ DHD_ERROR(("%s: Ucode downloaded successfully!\n", __func__)); ++ ++ shdata = UCODE_DOWNLOAD_COMPLETE; ++ dhdsdio_membytes(bus, TRUE, shaddr, (uint8 *)&shdata, 4); ++ } ++} ++ ++#endif /* DHD_UCODE_DOWNLOAD */ ++ ++static int ++dhdsdio_download_nvram(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ uint len; ++ void * image = NULL; ++ char * memblock = NULL; ++ char *bufp; ++ char *pnv_path; ++ bool nvram_file_exists; ++ ++ pnv_path = bus->nv_path; ++ ++ nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); ++ ++ /* For Get nvram from UEFI */ ++ if (nvram_file_exists) { ++ image = dhd_os_open_image(pnv_path); ++ if (image == NULL) { ++ printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path); ++ goto err; ++ } ++ } ++ ++ memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); ++ if (memblock == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", ++ __FUNCTION__, MAX_NVRAMBUF_SIZE)); ++ goto err; ++ } ++ ++ /* For Get nvram from image or UEFI (when image == NULL ) */ ++ len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); ++ ++ if (len > 0 && len < MAX_NVRAMBUF_SIZE) { ++ bufp = (char *)memblock; ++ bufp[len] = 0; ++ len = process_nvram_vars(bufp, len); ++ if (len % 4) { ++ len += 4 - (len % 4); ++ } ++ bufp += len; ++ *bufp++ = 0; ++ if (len) ++ bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1); ++ if (bcmerror) { ++ DHD_ERROR(("%s: error downloading vars: %d\n", ++ __FUNCTION__, bcmerror)); ++ } ++ } else { ++ DHD_ERROR(("%s: error reading nvram file: %d\n", ++ __FUNCTION__, len)); ++ bcmerror = BCME_SDIO_ERROR; ++ } ++ ++err: ++ if (memblock) ++ MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); ++ ++ if (image) ++ dhd_os_close_image(image); ++ ++ return bcmerror; ++} ++ ++static int ++_dhdsdio_download_firmware(struct dhd_bus *bus) ++{ ++ int bcmerror = -1; ++ ++ bool embed = FALSE; /* download embedded firmware */ ++ bool dlok = FALSE; /* download firmware succeeded */ ++ ++ /* Out immediately if no image to download */ ++ if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { ++#ifdef BCMEMBEDIMAGE ++ embed = TRUE; ++#else ++ return 0; ++#endif ++ } ++ ++ /* Keep arm in reset */ ++ if (dhdsdio_download_state(bus, TRUE)) { ++ DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ /* External image takes precedence if specified */ ++ if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { ++ if (dhdsdio_download_code_file(bus, bus->fw_path)) { ++ DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); ++#ifdef BCMEMBEDIMAGE ++ embed = TRUE; ++#else ++ goto err; ++#endif ++ } else { ++ embed = FALSE; ++ dlok = TRUE; ++ } ++ } ++ ++#ifdef BCMEMBEDIMAGE ++ if (embed) { ++ if (dhdsdio_download_code_array(bus)) { ++ DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__)); ++ goto err; ++ } else { ++ dlok = TRUE; ++ } ++ } ++#else ++ BCM_REFERENCE(embed); ++#endif ++ if (!dlok) { ++ DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ /* External nvram takes precedence if specified */ ++ if (dhdsdio_download_nvram(bus)) { ++ DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ /* Take arm out of reset */ ++ if (dhdsdio_download_state(bus, FALSE)) { ++ DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); ++ goto err; ++ } ++ ++ bcmerror = 0; ++ ++err: ++ return bcmerror; ++} ++ ++static int ++dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete_fn, void *handle) ++{ ++ int status; ++ ++ if (!KSO_ENAB(bus)) { ++ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); ++ return BCME_NODEVICE; ++ } ++ ++ status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete_fn, handle); ++ ++ return status; ++} ++ ++static int ++dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, ++ void *pkt, bcmsdh_cmplt_fn_t complete_fn, void *handle, int max_retry) ++{ ++ int ret; ++ int i = 0; ++ int retries = 0; ++ bcmsdh_info_t *sdh; ++ ++ if (!KSO_ENAB(bus)) { ++ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); ++ return BCME_NODEVICE; ++ } ++ ++ sdh = bus->sdh; ++ do { ++ ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, ++ pkt, complete_fn, handle); ++ ++ bus->f2txdata++; ++ ASSERT(ret != BCME_PENDING); ++ ++ if (ret == BCME_NODEVICE) { ++ DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); ++ } else if (ret < 0) { ++ /* On failure, abort the command and terminate the frame */ ++ DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n", ++ __FUNCTION__, ret)); ++ bus->tx_sderrs++; ++ bus->f1regdata++; ++ bus->dhd->tx_errors++; ++ bcmsdh_abort(sdh, SDIO_FUNC_2); ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, ++ SFC_WF_TERM, NULL); ++ for (i = 0; i < READ_FRM_CNT_RETRIES; i++) { ++ uint8 hi, lo; ++ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI, ++ NULL); ++ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO, ++ NULL); ++ bus->f1regdata += 2; ++ if ((hi == 0) && (lo == 0)) ++ break; ++ } ++ } ++ } while ((ret < 0) && retrydata && ++retries < max_retry); ++ ++ return ret; ++} ++ ++uint8 ++dhd_bus_is_ioready(struct dhd_bus *bus) ++{ ++ uint8 enable; ++ bcmsdh_info_t *sdh; ++ ASSERT(bus); ++ ASSERT(bus->sih != NULL); ++ enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); ++ sdh = bus->sdh; ++ return (enable == bcmsdh_cfg_read(sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL)); ++} ++ ++uint ++dhd_bus_chip(struct dhd_bus *bus) ++{ ++ ASSERT(bus->sih != NULL); ++ return bus->sih->chip; ++} ++ ++uint ++dhd_bus_chiprev(struct dhd_bus *bus) ++{ ++ ASSERT(bus); ++ ASSERT(bus->sih != NULL); ++ return bus->sih->chiprev; ++} ++ ++void * ++dhd_bus_pub(struct dhd_bus *bus) ++{ ++ return bus->dhd; ++} ++ ++const void * ++dhd_bus_sih(struct dhd_bus *bus) ++{ ++ return (const void *)bus->sih; ++} ++ ++void * ++dhd_bus_txq(struct dhd_bus *bus) ++{ ++ return &bus->txq; ++} ++ ++uint ++dhd_bus_hdrlen(struct dhd_bus *bus) ++{ ++ return (bus->txglom_enable) ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN; ++} ++ ++void ++dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val) ++{ ++ bus->dotxinrx = val; ++} ++ ++/* ++ * dhdsdio_advertise_bus_cleanup advertises that clean up is under progress ++ * to other bus user contexts like Tx, Rx, IOVAR, WD etc and it waits for other contexts ++ * to gracefully exit. All the bus usage contexts before marking busstate as busy, will check for ++ * whether the busstate is DHD_BUS_DOWN or DHD_BUS_DOWN_IN_PROGRESS, if so ++ * they will exit from there itself without marking dhd_bus_busy_state as BUSY. ++ */ ++static void ++dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp) ++{ ++ unsigned long flags; ++ int timeleft; ++ ++ DHD_LINUX_GENERAL_LOCK(dhdp, flags); ++ dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS; ++ DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); ++ ++ timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); ++ if ((timeleft == 0) || (timeleft == 1)) { ++ DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", ++ __FUNCTION__, dhdp->dhd_bus_busy_state)); ++ ASSERT(0); ++ } ++ ++ return; ++} ++ ++static void ++dhdsdio_advertise_bus_remove(dhd_pub_t *dhdp) ++{ ++ unsigned long flags; ++ int timeleft; ++ ++ DHD_LINUX_GENERAL_LOCK(dhdp, flags); ++ dhdp->busstate = DHD_BUS_REMOVE; ++ DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); ++ ++ timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); ++ if ((timeleft == 0) || (timeleft == 1)) { ++ DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", ++ __FUNCTION__, dhdp->dhd_bus_busy_state)); ++ ASSERT(0); ++ } ++ ++ return; ++} ++ ++ ++int ++dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) ++{ ++ int bcmerror = 0; ++ dhd_bus_t *bus; ++ unsigned long flags; ++ ++ bus = dhdp->bus; ++ ++ if (flag == TRUE) { ++ if (!bus->dhd->dongle_reset) { ++ DHD_ERROR(("%s: == Power OFF ==\n", __FUNCTION__)); ++ dhdsdio_advertise_bus_cleanup(bus->dhd); ++ dhd_os_sdlock(dhdp); ++ dhd_os_wd_timer(dhdp, 0); ++#if !defined(IGNORE_ETH0_DOWN) ++ /* Force flow control as protection when stop come before ifconfig_down */ ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); ++#endif /* !defined(IGNORE_ETH0_DOWN) */ ++ /* Expect app to have torn down any connection before calling */ ++ /* Stop the bus, disable F2 */ ++ dhd_bus_stop(bus, FALSE); ++ ++#if defined(OOB_INTR_ONLY) ++ /* Clean up any pending IRQ */ ++ dhd_enable_oob_intr(bus, FALSE); ++ bcmsdh_oob_intr_set(bus->sdh, FALSE); ++ bcmsdh_oob_intr_unregister(bus->sdh); ++#endif ++ ++ /* Clean tx/rx buffer pointers, detach from the dongle */ ++ dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); ++ ++ bus->dhd->dongle_reset = TRUE; ++ bus->dhd->up = FALSE; ++ dhd_txglom_enable(dhdp, FALSE); ++ dhd_os_sdunlock(dhdp); ++ ++ DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ ++ printf("%s: WLAN OFF DONE\n", __FUNCTION__); ++ /* App can now remove power from device */ ++ } else ++ bcmerror = BCME_SDIO_ERROR; ++ } else { ++ /* App must have restored power to device before calling */ ++ ++ printf("\n\n%s: == WLAN ON ==\n", __FUNCTION__); ++ ++ if (bus->dhd->dongle_reset) { ++ /* Turn on WLAN */ ++ dhd_os_sdlock(dhdp); ++ /* Reset SD client */ ++ bcmsdh_reset(bus->sdh); ++ ++ /* Attempt to re-attach & download */ ++ if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh, ++ (uint32 *)SI_ENUM_BASE, ++ bus->cl_devid)) { ++ ++ DHD_LINUX_GENERAL_LOCK(bus->dhd, flags); ++ bus->dhd->busstate = DHD_BUS_DOWN; ++ DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags); ++ /* Attempt to download binary to the dongle */ ++ if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) && ++ dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) { ++ ++ /* Re-init bus, enable F2 transfer */ ++ bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); ++ if (bcmerror == BCME_OK) { ++#if defined(OOB_INTR_ONLY) ++ dhd_enable_oob_intr(bus, TRUE); ++ bcmsdh_oob_intr_register(bus->sdh, ++ dhdsdio_isr, bus); ++ bcmsdh_oob_intr_set(bus->sdh, TRUE); ++#elif defined(FORCE_WOWLAN) ++ dhd_enable_oob_intr(bus, TRUE); ++#endif ++ ++ bus->dhd->dongle_reset = FALSE; ++ bus->dhd->up = TRUE; ++ ++#if !defined(IGNORE_ETH0_DOWN) ++ /* Restore flow control */ ++ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); ++#endif ++ dhd_os_wd_timer(dhdp, dhd_watchdog_ms); ++ ++ DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); ++ } else { ++ dhd_bus_stop(bus, FALSE); ++ dhdsdio_release_dongle(bus, bus->dhd->osh, ++ TRUE, FALSE); ++ } ++ } else { ++ DHD_ERROR(("%s Failed to download binary to the dongle\n", ++ __FUNCTION__)); ++ if (bus->sih != NULL) { ++ si_detach(bus->sih); ++ bus->sih = NULL; ++ } ++ bcmerror = BCME_SDIO_ERROR; ++ } ++ } else ++ bcmerror = BCME_SDIO_ERROR; ++ ++ dhd_os_sdunlock(dhdp); ++ } else { ++ printf("%s called when dongle is not in reset\n", ++ __FUNCTION__); ++ printf("Will call dhd_bus_start instead\n"); ++ dhd_bus_resume(dhdp, 1); ++#if defined(HW_OOB) || defined(FORCE_WOWLAN) ++ dhd_conf_set_hw_oob_intr(bus->sdh, bus->sih->chip); // terence 20120615: fix for OOB initial issue ++#endif ++ if ((bcmerror = dhd_bus_start(dhdp)) != 0) ++ DHD_ERROR(("%s: dhd_bus_start fail with %d\n", ++ __FUNCTION__, bcmerror)); ++ } ++ } ++ ++#ifdef PKT_STATICS ++ memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t)); ++#endif ++ return bcmerror; ++} ++ ++int dhd_bus_suspend(dhd_pub_t *dhdpub) ++{ ++ return bcmsdh_stop(dhdpub->bus->sdh); ++} ++ ++int dhd_bus_resume(dhd_pub_t *dhdpub, int stage) ++{ ++ return bcmsdh_start(dhdpub->bus->sdh, stage); ++} ++ ++/* Get Chip ID version */ ++uint dhd_bus_chip_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ if (bus && bus->sih) ++ return bus->sih->chip; ++ else ++ return 0; ++} ++ ++/* Get Chip Rev ID version */ ++uint dhd_bus_chiprev_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ if (bus && bus->sih) ++ return bus->sih->chiprev; ++ else ++ return 0; ++} ++ ++/* Get Chip Pkg ID version */ ++uint dhd_bus_chippkg_id(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ ++ return bus->sih->chippkg; ++} ++ ++int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num) ++{ ++ *bus_type = bus->bus; ++ *bus_num = bus->bus_num; ++ *slot_num = bus->slot_num; ++ return 0; ++} ++ ++int ++dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) ++{ ++ dhd_bus_t *bus; ++ ++ bus = dhdp->bus; ++ return dhdsdio_membytes(bus, set, address, data, size); ++} ++ ++ ++void ++dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path, ++ char *pclm_path, char *pconf_path) ++{ ++ bus->fw_path = pfw_path; ++ bus->nv_path = pnv_path; ++ bus->dhd->clm_path = pclm_path; ++ bus->dhd->conf_path = pconf_path; ++} ++ ++int ++dhd_enableOOB(dhd_pub_t *dhd, bool sleep) ++{ ++ dhd_bus_t *bus = dhd->bus; ++ sdpcmd_regs_t *regs = bus->regs; ++ uint retries = 0; ++ ++ if (sleep) { ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ /* Tell device to start using OOB wakeup */ ++ W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); ++ if (retries > retry_limit) { ++ DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); ++ return BCME_BUSY; ++ } ++ /* Turn off our contribution to the HT clock request */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ } else { ++ /* Make sure the controller has the bus up */ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ /* Send misc interrupt to indicate OOB not needed */ ++ W_SDREG(0, ®s->tosbmailboxdata, retries); ++ if (retries <= retry_limit) ++ W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); ++ ++ if (retries > retry_limit) ++ DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); ++ ++ /* Make sure we have SD bus access */ ++ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); ++ } ++ return BCME_OK; ++} ++ ++void ++dhd_bus_pktq_flush(dhd_pub_t *dhdp) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ bool wlfc_enabled = FALSE; ++ ++#ifdef PROP_TXSTATUS ++ wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED); ++#endif ++ if (!wlfc_enabled) { ++#ifdef DHDTCPACK_SUPPRESS ++ /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, ++ * when there is a newly coming packet from network stack. ++ */ ++ dhd_tcpack_info_tbl_clean(bus->dhd); ++#endif /* DHDTCPACK_SUPPRESS */ ++ /* Clear the data packet queues */ ++ pktq_flush(dhdp->osh, &bus->txq, TRUE); ++ } ++} ++ ++#ifdef BCMSDIO ++int ++dhd_sr_config(dhd_pub_t *dhd, bool on) ++{ ++ dhd_bus_t *bus = dhd->bus; ++ ++ if (!bus->_srenab) ++ return -1; ++ ++ return dhdsdio_clk_devsleep_iovar(bus, on); ++} ++ ++uint16 ++dhd_get_chipid(dhd_pub_t *dhd) ++{ ++ dhd_bus_t *bus = dhd->bus; ++ ++ if (bus && bus->sih) ++ return (uint16)bus->sih->chip; ++ else ++ return 0; ++} ++#endif /* BCMSDIO */ ++ ++#ifdef DEBUGGER ++uint32 dhd_sdio_reg_read(void *h, uint32 addr) ++{ ++ uint32 rval; ++ struct dhd_bus *bus = (struct dhd_bus *) h; ++ ++ dhd_os_sdlock(bus->dhd); ++ ++ BUS_WAKE(bus); ++ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ rval = bcmsdh_reg_read(bus->sdh, addr, 4); ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ return rval; ++} ++ ++void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val) ++{ ++ struct dhd_bus *bus = (struct dhd_bus *) h; ++ ++ dhd_os_sdlock(bus->dhd); ++ ++ BUS_WAKE(bus); ++ ++ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); ++ ++ bcmsdh_reg_write(bus->sdh, addr, 4, val); ++ ++ dhd_os_sdunlock(bus->dhd); ++} ++ ++#endif /* DEBUGGER */ ++ ++ ++#if defined(BT_OVER_SDIO) ++uint8 dhd_bus_cfg_read(void *h, uint fun_num, uint32 addr, int *err) ++{ ++ uint8 intrd; ++ dhd_pub_t *dhdp = (dhd_pub_t *)h; ++ dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; ++ ++ dhd_os_sdlock(bus->dhd); ++ ++ intrd = bcmsdh_cfg_read(bus->sdh, fun_num, addr, err); ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++ return intrd; ++} EXPORT_SYMBOL(dhd_bus_cfg_read); ++ ++void dhd_bus_cfg_write(void *h, uint fun_num, uint32 addr, uint8 val, int *err) ++{ ++ dhd_pub_t *dhdp = (dhd_pub_t *)h; ++ dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; ++ ++ dhd_os_sdlock(bus->dhd); ++ ++ bcmsdh_cfg_write(bus->sdh, fun_num, addr, val, err); ++ ++ dhd_os_sdunlock(bus->dhd); ++ ++} EXPORT_SYMBOL(dhd_bus_cfg_write); ++ ++static int ++extract_hex_field(char * line, uint16 start_pos, uint16 num_chars, uint16 * value) ++{ ++ char field [8]; ++ ++ strncpy(field, line + start_pos, num_chars); ++ field [num_chars] = '\0'; ++ ++ return (sscanf (field, "%hX", value) == 1); ++} ++ ++static int ++read_more_btbytes(struct dhd_bus *bus, void * file, char *line, int * addr_mode, uint16 * hi_addr, ++ uint32 * dest_addr, uint8 *data_bytes, uint32 * num_bytes) ++{ ++ int str_len; ++ uint16 num_data_bytes, addr, data_pos, type, w, i; ++ uint32 abs_base_addr32 = 0; ++ *num_bytes = 0; ++ ++ while (!*num_bytes) ++ { ++ str_len = dhd_os_gets_image(bus->dhd, line, BTFW_MAX_STR_LEN, file); ++ ++ DHD_TRACE(("%s: Len :0x%x %s\n", __FUNCTION__, str_len, line)); ++ ++ if (str_len == 0) { ++ break; ++ } else if (str_len > 9) { ++ extract_hex_field(line, 1, 2, &num_data_bytes); ++ extract_hex_field(line, 3, 4, &addr); ++ extract_hex_field(line, 7, 2, &type); ++ ++ data_pos = 9; ++ for (i = 0; i < num_data_bytes; i++) { ++ extract_hex_field(line, data_pos, 2, &w); ++ data_bytes [i] = (uint8)(w & 0x00FF); ++ data_pos += 2; ++ } ++ ++ if (type == BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS) { ++ *hi_addr = (data_bytes [0] << 8) | data_bytes [1]; ++ *addr_mode = BTFW_ADDR_MODE_EXTENDED; ++ } else if (type == BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS) { ++ *hi_addr = (data_bytes [0] << 8) | data_bytes [1]; ++ *addr_mode = BTFW_ADDR_MODE_SEGMENT; ++ } else if (type == BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS) { ++ abs_base_addr32 = (data_bytes [0] << 24) | (data_bytes [1] << 16) | ++ (data_bytes [2] << 8) | data_bytes [3]; ++ *addr_mode = BTFW_ADDR_MODE_LINEAR32; ++ } else if (type == BTFW_HEX_LINE_TYPE_DATA) { ++ *dest_addr = addr; ++ if (*addr_mode == BTFW_ADDR_MODE_EXTENDED) ++ *dest_addr += (*hi_addr << 16); ++ else if (*addr_mode == BTFW_ADDR_MODE_SEGMENT) ++ *dest_addr += (*hi_addr << 4); ++ else if (*addr_mode == BTFW_ADDR_MODE_LINEAR32) ++ *dest_addr += abs_base_addr32; ++ *num_bytes = num_data_bytes; ++ } ++ } ++ } ++ return (*num_bytes > 0); ++} ++ ++static int ++_dhdsdio_download_btfw(struct dhd_bus *bus) ++{ ++ int bcm_error = -1; ++ void *image = NULL; ++ uint8 *mem_blk = NULL, *mem_ptr = NULL, *data_ptr = NULL; ++ ++ ++ uint32 offset_addr = 0, offset_len = 0, bytes_to_write = 0; ++ ++ char *line = NULL; ++ uint32 dest_addr = 0, num_bytes; ++ uint16 hiAddress = 0; ++ uint32 start_addr, start_data, end_addr, end_data, i, index, pad; ++ uint32 bt2wlan_pwrup_adr; ++ ++ int addr_mode = BTFW_ADDR_MODE_EXTENDED; ++ ++ /* Out immediately if no image to download */ ++ if ((bus->btfw_path == NULL) || (bus->btfw_path[0] == '\0')) { ++ return 0; ++ } ++ ++ image = dhd_os_open_image(bus->btfw_path); ++ if (image == NULL) ++ goto err; ++ ++ mem_ptr = mem_blk = MALLOC(bus->dhd->osh, BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN); ++ if (mem_blk == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, ++ BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN)); ++ goto err; ++ } ++ if ((uint32)(uintptr)mem_blk % DHD_SDALIGN) ++ mem_ptr += (DHD_SDALIGN - ((uint32)(uintptr)mem_blk % DHD_SDALIGN)); ++ ++ data_ptr = MALLOC(bus->dhd->osh, BTFW_DOWNLOAD_BLK_SIZE - 8); ++ if (data_ptr == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, ++ BTFW_DOWNLOAD_BLK_SIZE - 8)); ++ goto err; ++ } ++ /* Write to BT register to hold WLAN wake high during BT FW download */ ++ bt2wlan_pwrup_adr = BTMEM_OFFSET + BT2WLAN_PWRUP_ADDR; ++ bcmsdh_reg_write(bus->sdh, bt2wlan_pwrup_adr, 4, BT2WLAN_PWRUP_WAKE); ++ /* ++ * Wait for at least 2msec for the clock to be ready/Available. ++ */ ++ OSL_DELAY(2000); ++ ++ line = MALLOC(bus->dhd->osh, BTFW_MAX_STR_LEN); ++ if (line == NULL) { ++ DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", ++ __FUNCTION__, BTFW_MAX_STR_LEN)); ++ goto err; ++ } ++ memset(line, 0, BTFW_MAX_STR_LEN); ++ ++ while (read_more_btbytes (bus, image, line, &addr_mode, &hiAddress, &dest_addr, ++ data_ptr, &num_bytes)) { ++ ++ DHD_TRACE(("read %d bytes at address %08X\n", num_bytes, dest_addr)); ++ ++ start_addr = BTMEM_OFFSET + dest_addr; ++ index = 0; ++ ++ /* Make sure the start address is 4 byte aligned to avoid alignment issues ++ * with SD host controllers ++ */ ++ if (!ISALIGNED(start_addr, 4)) { ++ pad = start_addr % 4; ++ start_addr = ROUNDDN(start_addr, 4); ++ start_data = bcmsdh_reg_read(bus->sdh, start_addr, 4); ++ for (i = 0; i < pad; i++, index++) { ++ mem_ptr[index] = (uint8)((uint8 *)&start_data)[i]; ++ } ++ } ++ bcopy(data_ptr, &(mem_ptr[index]), num_bytes); ++ index += num_bytes; ++ ++ /* Make sure the length is multiple of 4bytes to avoid alignment issues ++ * with SD host controllers ++ */ ++ end_addr = start_addr + index; ++ if (!ISALIGNED(end_addr, 4)) { ++ end_addr = ROUNDDN(end_addr, 4); ++ end_data = bcmsdh_reg_read(bus->sdh, end_addr, 4); ++ for (i = (index % 4); i < 4; i++, index++) { ++ mem_ptr[index] = (uint8)((uint8 *)&end_data)[i]; ++ } ++ } ++ ++ offset_addr = start_addr & 0xFFF; ++ offset_len = offset_addr + index; ++ if (offset_len <= 0x1000) { ++ bcm_error = dhdsdio_membytes(bus, TRUE, start_addr, mem_ptr, index); ++ if (bcm_error) { ++ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcm_error, num_bytes, start_addr)); ++ goto err; ++ } ++ } ++ else { ++ bytes_to_write = 0x1000 - offset_addr; ++ bcm_error = dhdsdio_membytes(bus, TRUE, start_addr, mem_ptr, ++ bytes_to_write); ++ if (bcm_error) { ++ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcm_error, num_bytes, start_addr)); ++ goto err; ++ } ++ ++ OSL_DELAY(10000); ++ ++ bcm_error = dhdsdio_membytes(bus, TRUE, (start_addr + bytes_to_write), ++ (mem_ptr + bytes_to_write), (index - bytes_to_write)); ++ if (bcm_error) { ++ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", ++ __FUNCTION__, bcm_error, num_bytes, start_addr)); ++ goto err; ++ } ++ } ++ memset(line, 0, BTFW_MAX_STR_LEN); ++ } ++ ++ bcm_error = 0; ++err: ++ if (mem_blk) ++ MFREE(bus->dhd->osh, mem_blk, BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN); ++ ++ if (data_ptr) ++ MFREE(bus->dhd->osh, data_ptr, BTFW_DOWNLOAD_BLK_SIZE - 8); ++ ++ if (line) ++ MFREE(bus->dhd->osh, line, BTFW_MAX_STR_LEN); ++ ++ if (image) ++ dhd_os_close_image(image); ++ ++ return bcm_error; ++} ++ ++static int ++dhdsdio_download_btfw(struct dhd_bus *bus, osl_t *osh, void *sdh) ++{ ++ int ret; ++ ++ DHD_TRACE(("%s: btfw path=%s\n", ++ __FUNCTION__, bus->btfw_path)); ++ DHD_OS_WAKE_LOCK(bus->dhd); ++ dhd_os_sdlock(bus->dhd); ++ ++ /* Download the firmware */ ++ ret = _dhdsdio_download_btfw(bus); ++ ++ dhd_os_sdunlock(bus->dhd); ++ DHD_OS_WAKE_UNLOCK(bus->dhd); ++ ++ return ret; ++} ++ ++int ++dhd_bus_download_btfw(struct dhd_bus *bus, osl_t *osh, ++ char *pbtfw_path) ++{ ++ int ret; ++ ++ bus->btfw_path = pbtfw_path; ++ ++ ret = dhdsdio_download_btfw(bus, osh, bus->sdh); ++ ++ return ret; ++} ++#endif /* defined (BT_OVER_SDIO) */ ++ ++void ++dhd_bus_dump_trap_info(dhd_bus_t *bus, struct bcmstrbuf *strbuf) ++{ ++ trap_t *tr = &bus->dhd->last_trap_info; ++ ++ bcm_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\n", ++ ltoh32(tr->type), ltoh32(tr->epc), ltoh32(tr->cpsr), ltoh32(tr->spsr), ++ ltoh32(tr->r13), ltoh32(tr->r14), ltoh32(tr->pc), ++ ltoh32(bus->dongle_trap_addr), ++ ltoh32(tr->r0), ltoh32(tr->r1), ltoh32(tr->r2), ltoh32(tr->r3), ++ ltoh32(tr->r4), ltoh32(tr->r5), ltoh32(tr->r6), ltoh32(tr->r7)); ++ ++} ++ ++static int ++dhd_bcmsdh_send_buffer(void *bus, uint8 *frame, uint16 len) ++{ ++ int ret = -1; ++ ++ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(((dhd_bus_t*)bus)->sdh), ++ SDIO_FUNC_2, F2SYNC, frame, len, NULL, NULL, NULL, TXRETRIES); ++ ++ if (ret == BCME_OK) ++ ((dhd_bus_t*)bus)->tx_seq = (((dhd_bus_t*)bus)->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; ++ ++ return ret; ++} ++ ++/* Function to set the min res mask depending on the chip ID used */ ++bool ++dhd_bus_set_default_min_res_mask(struct dhd_bus *bus) ++{ ++ if ((bus == NULL) || (bus->sih == NULL)) { ++ DHD_ERROR(("%s(): Invalid Arguments \r\n", __FUNCTION__)); ++ return FALSE; ++ } ++ ++ switch (bus->sih->chip) { ++ case BCM4339_CHIP_ID: ++ bcmsdh_reg_write(bus->sdh, SI_ENUM_BASE + 0x618, 4, 0x3fcaf377); ++ if (bcmsdh_regfail(bus->sdh)) { ++ DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__, __LINE__)); ++ return FALSE; ++ } ++ break; ++ ++ case BCM43012_CHIP_ID: ++ bcmsdh_reg_write(bus->sdh, ++ si_get_pmu_reg_addr(bus->sih, OFFSETOF(pmuregs_t, min_res_mask)), ++ 4, DEFAULT_43012_MIN_RES_MASK); ++ if (bcmsdh_regfail(bus->sdh)) { ++ DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__, __LINE__)); ++ return FALSE; ++ } ++ break; ++ ++ default: ++ DHD_ERROR(("%s: Unhandled chip id\n", __FUNCTION__)); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/* Function to reset PMU registers */ ++void ++dhd_bus_pmu_reg_reset(dhd_pub_t *dhdp) ++{ ++ struct dhd_bus *bus = dhdp->bus; ++ bcmsdh_reg_write(bus->sdh, si_get_pmu_reg_addr(bus->sih, ++ OFFSETOF(pmuregs_t, swscratch)), 4, 0x0); ++ if (bcmsdh_regfail(bus->sdh)) { ++ DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__, __LINE__)); ++ } ++} ++ ++ ++#ifdef DHD_ULP ++/* Function to disable console messages on entering ULP mode */ ++void ++dhd_bus_ulp_disable_console(dhd_pub_t *dhdp) ++{ ++#ifdef DHD_DEBUG ++ DHD_ERROR(("Flushing and disabling console messages\n")); ++ ++ /* Save the console print interval */ ++ dhd_ulp_save_console_interval(dhdp); ++ ++ /* Flush the console buffer before disabling */ ++ dhdsdio_readconsole(dhdp->bus); ++ dhd_console_ms = 0; ++#endif /* DHD_DEBUG */ ++} ++ ++/* Function for redownloading firmaware */ ++static int ++dhd_bus_ulp_reinit_fw(dhd_bus_t *bus) ++{ ++ int bcmerror = 0; ++ ++ /* After firmware redownload tx/rx seq are reset accordingly these values are ++ reset on DHD side tx_max is initially set to 4, which later is updated by FW ++ */ ++ bus->tx_seq = bus->rx_seq = 0; ++ bus->tx_max = 4; ++ ++ if (dhd_bus_download_firmware(bus, bus->dhd->osh, ++ bus->fw_path, bus->nv_path) >= 0) { ++ ++ /* Re-init bus, enable F2 transfer */ ++ bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); ++ if (bcmerror == BCME_OK) { ++ bus->dhd->up = TRUE; ++ dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); ++ ++ dhd_ulp_set_ulp_state(bus->dhd, DHD_ULP_READY); ++#if defined(OOB_INTR_ONLY) ++ dhd_enable_oob_intr(bus, TRUE); ++ bcmsdh_oob_intr_set(bus->sdh, TRUE); ++#endif ++#ifdef DHD_DEBUG ++ /* Re-enable the console messages on FW redownload to default value */ ++ dhd_ulp_restore_console_interval(bus->dhd); ++#endif /* DHD_DEBUG */ ++ } else { ++ DHD_ERROR(("bus init failed\n")); ++ dhd_bus_stop(bus, FALSE); ++ dhdsdio_release_dongle(bus, bus->dhd->osh, ++ TRUE, FALSE); ++ } ++ } else ++ bcmerror = BCME_SDIO_ERROR; ++ ++ return bcmerror; ++} ++#endif /* DHD_ULP */ ++ ++int ++dhd_bus_readwrite_bp_addr(dhd_pub_t *dhdp, uint addr, uint size, uint* data, bool read) ++{ ++ int bcmerror = 0; ++ struct dhd_bus *bus = dhdp->bus; ++ ++ if (read) { ++ *data = (int32)bcmsdh_reg_read(bus->sdh, addr, size); ++ } else { ++ bcmsdh_reg_write(bus->sdh, addr, size, *data); ++ } ++ ++ if (bcmsdh_regfail(bus->sdh)) ++ bcmerror = BCME_SDIO_ERROR; ++ ++ return bcmerror; ++} ++ ++int dhd_get_idletime(dhd_pub_t *dhd) ++{ ++ return dhd->bus->idletime; ++} ++ ++#ifdef DHD_WAKE_STATUS ++wake_counts_t* ++dhd_bus_get_wakecount(dhd_pub_t *dhd) ++{ ++ if (!dhd->bus) { ++ return NULL; ++ } ++ return &dhd->bus->wake_counts; ++} ++int ++dhd_bus_get_bus_wake(dhd_pub_t *dhd) ++{ ++ return bcmsdh_set_get_wake(dhd->bus->sdh, 0); ++} ++#endif /* DHD_WAKE_STATUS */ ++ ++int ++dhd_bus_sleep(dhd_pub_t *dhdp, bool sleep, uint32 *intstatus) ++{ ++ dhd_bus_t *bus = dhdp->bus; ++ uint32 retry = 0; ++ int ret = 0; ++ ++ if (bus) { ++ dhd_os_sdlock(dhdp); ++ BUS_WAKE(bus); ++ R_SDREG(*intstatus, &bus->regs->intstatus, retry); ++ if (sleep) { ++ if (SLPAUTO_ENAB(bus)) { ++ ret = dhdsdio_bussleep(bus, sleep); ++ if (ret != BCME_BUSY) ++ dhd_os_wd_timer(bus->dhd, 0); ++ } else ++ dhdsdio_clkctl(bus, CLK_NONE, FALSE); ++ } ++ dhd_os_sdunlock(dhdp); ++ } else { ++ DHD_ERROR(("bus is NULL\n")); ++ ret = -1; ++ } ++ ++ return ret; ++} +\ No newline at end of file +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_static_buf.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_static_buf.c +new file mode 100644 +index 000000000..38dd04404 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_static_buf.c +@@ -0,0 +1,535 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DHD_STATIC_VERSION_STR "1.579.77.41.9" ++ ++#define BCMDHD_SDIO ++#define BCMDHD_PCIE ++ ++enum dhd_prealloc_index { ++ DHD_PREALLOC_PROT = 0, ++#if defined(BCMDHD_SDIO) ++ DHD_PREALLOC_RXBUF = 1, ++ DHD_PREALLOC_DATABUF = 2, ++#endif ++ DHD_PREALLOC_OSL_BUF = 3, ++ DHD_PREALLOC_SKB_BUF = 4, ++ DHD_PREALLOC_WIPHY_ESCAN0 = 5, ++ DHD_PREALLOC_WIPHY_ESCAN1 = 6, ++ DHD_PREALLOC_DHD_INFO = 7, ++ DHD_PREALLOC_DHD_WLFC_INFO = 8, ++#ifdef BCMDHD_PCIE ++ DHD_PREALLOC_IF_FLOW_LKUP = 9, ++#endif ++ DHD_PREALLOC_MEMDUMP_BUF = 10, ++ DHD_PREALLOC_MEMDUMP_RAM = 11, ++ DHD_PREALLOC_DHD_WLFC_HANGER = 12, ++ DHD_PREALLOC_PKTID_MAP = 13, ++ DHD_PREALLOC_PKTID_MAP_IOCTL = 14, ++ DHD_PREALLOC_DHD_LOG_DUMP_BUF = 15, ++ DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX = 16, ++ DHD_PREALLOC_DHD_PKTLOG_DUMP_BUF = 17, ++ DHD_PREALLOC_STAT_REPORT_BUF = 18, ++ DHD_PREALLOC_WL_ESCAN = 19, ++ DHD_PREALLOC_FW_VERBOSE_RING = 20, ++ DHD_PREALLOC_FW_EVENT_RING = 21, ++ DHD_PREALLOC_DHD_EVENT_RING = 22, ++ DHD_PREALLOC_NAN_EVENT_RING = 23, ++ DHD_PREALLOC_MAX ++}; ++ ++#define STATIC_BUF_MAX_NUM 20 ++#define STATIC_BUF_SIZE (PAGE_SIZE*2) ++ ++#define DHD_PREALLOC_PROT_SIZE (16 * 1024) ++#define DHD_PREALLOC_RXBUF_SIZE (24 * 1024) ++#define DHD_PREALLOC_DATABUF_SIZE (64 * 1024) ++#define DHD_PREALLOC_OSL_BUF_SIZE (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) ++#define DHD_PREALLOC_WIPHY_ESCAN0_SIZE (64 * 1024) ++#define DHD_PREALLOC_DHD_INFO_SIZE (32 * 1024) ++#define DHD_PREALLOC_MEMDUMP_RAM_SIZE (810 * 1024) ++#define DHD_PREALLOC_DHD_WLFC_HANGER_SIZE (73 * 1024) ++#define DHD_PREALLOC_WL_ESCAN_SIZE (70 * 1024) ++#ifdef CONFIG_64BIT ++#define DHD_PREALLOC_IF_FLOW_LKUP_SIZE (20 * 1024 * 2) ++#else ++#define DHD_PREALLOC_IF_FLOW_LKUP_SIZE (20 * 1024) ++#endif ++#define FW_VERBOSE_RING_SIZE (64 * 1024) ++#define FW_EVENT_RING_SIZE (64 * 1024) ++#define DHD_EVENT_RING_SIZE (64 * 1024) ++#define NAN_EVENT_RING_SIZE (64 * 1024) ++ ++#if defined(CONFIG_64BIT) ++#define WLAN_DHD_INFO_BUF_SIZE (24 * 1024) ++#define WLAN_DHD_WLFC_BUF_SIZE (64 * 1024) ++#define WLAN_DHD_IF_FLOW_LKUP_SIZE (64 * 1024) ++#else ++#define WLAN_DHD_INFO_BUF_SIZE (16 * 1024) ++#define WLAN_DHD_WLFC_BUF_SIZE (24 * 1024) ++#define WLAN_DHD_IF_FLOW_LKUP_SIZE (20 * 1024) ++#endif /* CONFIG_64BIT */ ++#define WLAN_DHD_MEMDUMP_SIZE (800 * 1024) ++ ++#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE*1) ++#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE*2) ++#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE*4) ++ ++#define DHD_SKB_1PAGE_BUF_NUM 8 ++#ifdef BCMDHD_PCIE ++#define DHD_SKB_2PAGE_BUF_NUM 64 ++#elif defined(BCMDHD_SDIO) ++#define DHD_SKB_2PAGE_BUF_NUM 8 ++#endif ++#define DHD_SKB_4PAGE_BUF_NUM 1 ++ ++/* The number is defined in linux_osl.c ++ * WLAN_SKB_1_2PAGE_BUF_NUM => STATIC_PKT_1_2PAGE_NUM ++ * WLAN_SKB_BUF_NUM => STATIC_PKT_MAX_NUM ++ */ ++#define WLAN_SKB_1_2PAGE_BUF_NUM ((DHD_SKB_1PAGE_BUF_NUM) + \ ++ (DHD_SKB_2PAGE_BUF_NUM)) ++#define WLAN_SKB_BUF_NUM ((WLAN_SKB_1_2PAGE_BUF_NUM) + (DHD_SKB_4PAGE_BUF_NUM)) ++ ++void *wlan_static_prot = NULL; ++void *wlan_static_rxbuf = NULL; ++void *wlan_static_databuf = NULL; ++void *wlan_static_osl_buf = NULL; ++void *wlan_static_scan_buf0 = NULL; ++void *wlan_static_scan_buf1 = NULL; ++void *wlan_static_dhd_info_buf = NULL; ++void *wlan_static_dhd_wlfc_info_buf = NULL; ++void *wlan_static_if_flow_lkup = NULL; ++void *wlan_static_dhd_memdump_ram_buf = NULL; ++void *wlan_static_dhd_wlfc_hanger_buf = NULL; ++void *wlan_static_wl_escan_info_buf = NULL; ++void *wlan_static_fw_verbose_ring_buf = NULL; ++void *wlan_static_fw_event_ring_buf = NULL; ++void *wlan_static_dhd_event_ring_buf = NULL; ++void *wlan_static_nan_event_ring_buf = NULL; ++ ++static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM]; ++ ++void *dhd_wlan_mem_prealloc(int section, unsigned long size) ++{ ++ pr_err("%s: sectoin %d, %ld\n", __func__, section, size); ++ if (section == DHD_PREALLOC_PROT) ++ return wlan_static_prot; ++ ++#if defined(BCMDHD_SDIO) ++ if (section == DHD_PREALLOC_RXBUF) ++ return wlan_static_rxbuf; ++ ++ if (section == DHD_PREALLOC_DATABUF) ++ return wlan_static_databuf; ++#endif /* BCMDHD_SDIO */ ++ ++ if (section == DHD_PREALLOC_SKB_BUF) ++ return wlan_static_skb; ++ ++ if (section == DHD_PREALLOC_WIPHY_ESCAN0) ++ return wlan_static_scan_buf0; ++ ++ if (section == DHD_PREALLOC_WIPHY_ESCAN1) ++ return wlan_static_scan_buf1; ++ ++ if (section == DHD_PREALLOC_OSL_BUF) { ++ if (size > DHD_PREALLOC_OSL_BUF_SIZE) { ++ pr_err("request OSL_BUF(%lu) > %ld\n", ++ size, DHD_PREALLOC_OSL_BUF_SIZE); ++ return NULL; ++ } ++ return wlan_static_osl_buf; ++ } ++ ++ if (section == DHD_PREALLOC_DHD_INFO) { ++ if (size > DHD_PREALLOC_DHD_INFO_SIZE) { ++ pr_err("request DHD_INFO size(%lu) > %d\n", ++ size, DHD_PREALLOC_DHD_INFO_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_info_buf; ++ } ++ if (section == DHD_PREALLOC_DHD_WLFC_INFO) { ++ if (size > WLAN_DHD_WLFC_BUF_SIZE) { ++ pr_err("request DHD_WLFC_INFO size(%lu) > %d\n", ++ size, WLAN_DHD_WLFC_BUF_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_wlfc_info_buf; ++ } ++#ifdef BCMDHD_PCIE ++ if (section == DHD_PREALLOC_IF_FLOW_LKUP) { ++ if (size > DHD_PREALLOC_IF_FLOW_LKUP_SIZE) { ++ pr_err("request DHD_IF_FLOW_LKUP size(%lu) > %d\n", ++ size, DHD_PREALLOC_IF_FLOW_LKUP_SIZE); ++ return NULL; ++ } ++ ++ return wlan_static_if_flow_lkup; ++ } ++#endif /* BCMDHD_PCIE */ ++ if (section == DHD_PREALLOC_MEMDUMP_RAM) { ++ if (size > DHD_PREALLOC_MEMDUMP_RAM_SIZE) { ++ pr_err("request DHD_PREALLOC_MEMDUMP_RAM_SIZE(%lu) > %d\n", ++ size, DHD_PREALLOC_MEMDUMP_RAM_SIZE); ++ return NULL; ++ } ++ ++ return wlan_static_dhd_memdump_ram_buf; ++ } ++ if (section == DHD_PREALLOC_DHD_WLFC_HANGER) { ++ if (size > DHD_PREALLOC_DHD_WLFC_HANGER_SIZE) { ++ pr_err("request DHD_WLFC_HANGER size(%lu) > %d\n", ++ size, DHD_PREALLOC_DHD_WLFC_HANGER_SIZE); ++ return NULL; ++ } ++ return wlan_static_dhd_wlfc_hanger_buf; ++ } ++ if (section == DHD_PREALLOC_WL_ESCAN) { ++ if (size > DHD_PREALLOC_WL_ESCAN_SIZE) { ++ pr_err("request DHD_PREALLOC_WL_ESCAN_SIZE(%lu) > %d\n", ++ size, DHD_PREALLOC_WL_ESCAN_SIZE); ++ return NULL; ++ } ++ ++ return wlan_static_wl_escan_info_buf; ++ } ++ if (section == DHD_PREALLOC_FW_VERBOSE_RING) { ++ if (size > FW_VERBOSE_RING_SIZE) { ++ pr_err("request DHD_PREALLOC_FW_VERBOSE_RING(%lu) > %d\n", ++ size, FW_VERBOSE_RING_SIZE); ++ return NULL; ++ } ++ ++ return wlan_static_fw_verbose_ring_buf; ++ } ++ if (section == DHD_PREALLOC_FW_EVENT_RING) { ++ if (size > FW_EVENT_RING_SIZE) { ++ pr_err("request DHD_PREALLOC_FW_EVENT_RING(%lu) > %d\n", ++ size, FW_EVENT_RING_SIZE); ++ return NULL; ++ } ++ ++ return wlan_static_fw_event_ring_buf; ++ } ++ if (section == DHD_PREALLOC_DHD_EVENT_RING) { ++ if (size > DHD_EVENT_RING_SIZE) { ++ pr_err("request DHD_PREALLOC_DHD_EVENT_RING(%lu) > %d\n", ++ size, DHD_EVENT_RING_SIZE); ++ return NULL; ++ } ++ ++ return wlan_static_dhd_event_ring_buf; ++ } ++ if (section == DHD_PREALLOC_NAN_EVENT_RING) { ++ if (size > NAN_EVENT_RING_SIZE) { ++ pr_err("request DHD_PREALLOC_NAN_EVENT_RING(%lu) > %d\n", ++ size, NAN_EVENT_RING_SIZE); ++ return NULL; ++ } ++ ++ return wlan_static_nan_event_ring_buf; ++ } ++ if ((section < 0) || (section > DHD_PREALLOC_MAX)) ++ pr_err("request section id(%d) is out of max index %d\n", ++ section, DHD_PREALLOC_MAX); ++ ++ pr_err("%s: failed to alloc section %d, size=%ld\n", ++ __func__, section, size); ++ ++ return NULL; ++} ++EXPORT_SYMBOL(dhd_wlan_mem_prealloc); ++ ++static int dhd_init_wlan_mem(void) ++{ ++ int i; ++ int j; ++ printk(KERN_ERR "%s(): %s\n", __func__, DHD_STATIC_VERSION_STR); ++ ++ for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) { ++ wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE); ++ if (!wlan_static_skb[i]) { ++ goto err_skb_alloc; ++ } ++ pr_err("%s: sectoin %d skb[%d], size=%ld\n", __func__, ++ DHD_PREALLOC_SKB_BUF, i, DHD_SKB_1PAGE_BUFSIZE); ++ } ++ ++ for (i = DHD_SKB_1PAGE_BUF_NUM; i < WLAN_SKB_1_2PAGE_BUF_NUM; i++) { ++ wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE); ++ if (!wlan_static_skb[i]) { ++ goto err_skb_alloc; ++ } ++ pr_err("%s: sectoin %d skb[%d], size=%ld\n", __func__, ++ DHD_PREALLOC_SKB_BUF, i, DHD_SKB_2PAGE_BUFSIZE); ++ } ++ ++#if defined(BCMDHD_SDIO) ++ wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE); ++ if (!wlan_static_skb[i]) ++ goto err_skb_alloc; ++ pr_err("%s: sectoin %d skb[%d], size=%ld\n", __func__, ++ DHD_PREALLOC_SKB_BUF, i, DHD_SKB_4PAGE_BUFSIZE); ++#endif /* BCMDHD_SDIO */ ++ ++ wlan_static_prot = kmalloc(DHD_PREALLOC_PROT_SIZE, GFP_KERNEL); ++ if (!wlan_static_prot) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_PROT, DHD_PREALLOC_PROT_SIZE); ++ ++#if defined(BCMDHD_SDIO) ++ wlan_static_rxbuf = kmalloc(DHD_PREALLOC_RXBUF_SIZE, GFP_KERNEL); ++ if (!wlan_static_rxbuf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_RXBUF, DHD_PREALLOC_RXBUF_SIZE); ++ ++ wlan_static_databuf = kmalloc(DHD_PREALLOC_DATABUF_SIZE, GFP_KERNEL); ++ if (!wlan_static_databuf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_DATABUF, DHD_PREALLOC_DATABUF_SIZE); ++#endif /* BCMDHD_SDIO */ ++ ++ wlan_static_osl_buf = kmalloc(DHD_PREALLOC_OSL_BUF_SIZE, GFP_KERNEL); ++ if (!wlan_static_osl_buf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%ld\n", __func__, ++ DHD_PREALLOC_OSL_BUF, DHD_PREALLOC_OSL_BUF_SIZE); ++ ++ wlan_static_scan_buf0 = kmalloc(DHD_PREALLOC_WIPHY_ESCAN0_SIZE, GFP_KERNEL); ++ if (!wlan_static_scan_buf0) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_WIPHY_ESCAN0, DHD_PREALLOC_WIPHY_ESCAN0_SIZE); ++ ++ wlan_static_dhd_info_buf = kmalloc(DHD_PREALLOC_DHD_INFO_SIZE, GFP_KERNEL); ++ if (!wlan_static_dhd_info_buf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_DHD_INFO, DHD_PREALLOC_DHD_INFO_SIZE); ++ ++ wlan_static_dhd_wlfc_info_buf = kmalloc(WLAN_DHD_WLFC_BUF_SIZE, GFP_KERNEL); ++ if (!wlan_static_dhd_wlfc_info_buf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_DHD_WLFC_INFO, WLAN_DHD_WLFC_BUF_SIZE); ++ ++#ifdef BCMDHD_PCIE ++ wlan_static_if_flow_lkup = kmalloc(DHD_PREALLOC_IF_FLOW_LKUP_SIZE, GFP_KERNEL); ++ if (!wlan_static_if_flow_lkup) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_IF_FLOW_LKUP, DHD_PREALLOC_IF_FLOW_LKUP_SIZE); ++#endif /* BCMDHD_PCIE */ ++ ++ wlan_static_dhd_memdump_ram_buf = kmalloc(DHD_PREALLOC_MEMDUMP_RAM_SIZE, GFP_KERNEL); ++ if (!wlan_static_dhd_memdump_ram_buf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_MEMDUMP_RAM, DHD_PREALLOC_MEMDUMP_RAM_SIZE); ++ ++ wlan_static_dhd_wlfc_hanger_buf = kmalloc(DHD_PREALLOC_DHD_WLFC_HANGER_SIZE, GFP_KERNEL); ++ if (!wlan_static_dhd_wlfc_hanger_buf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_DHD_WLFC_HANGER, DHD_PREALLOC_DHD_WLFC_HANGER_SIZE); ++ ++ wlan_static_wl_escan_info_buf = kmalloc(DHD_PREALLOC_WL_ESCAN_SIZE, GFP_KERNEL); ++ if (!wlan_static_wl_escan_info_buf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_WL_ESCAN, DHD_PREALLOC_WL_ESCAN_SIZE); ++ ++ wlan_static_fw_verbose_ring_buf = kmalloc(FW_VERBOSE_RING_SIZE, GFP_KERNEL); ++ if (!wlan_static_fw_verbose_ring_buf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_FW_VERBOSE_RING, FW_VERBOSE_RING_SIZE); ++ ++ wlan_static_fw_event_ring_buf = kmalloc(FW_EVENT_RING_SIZE, GFP_KERNEL); ++ if (!wlan_static_fw_event_ring_buf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_FW_EVENT_RING, FW_EVENT_RING_SIZE); ++ ++ wlan_static_dhd_event_ring_buf = kmalloc(DHD_EVENT_RING_SIZE, GFP_KERNEL); ++ if (!wlan_static_dhd_event_ring_buf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_DHD_EVENT_RING, DHD_EVENT_RING_SIZE); ++ ++ wlan_static_nan_event_ring_buf = kmalloc(NAN_EVENT_RING_SIZE, GFP_KERNEL); ++ if (!wlan_static_nan_event_ring_buf) ++ goto err_mem_alloc; ++ pr_err("%s: sectoin %d, size=%d\n", __func__, ++ DHD_PREALLOC_NAN_EVENT_RING, NAN_EVENT_RING_SIZE); ++ ++ return 0; ++ ++err_mem_alloc: ++ ++ if (wlan_static_prot) ++ kfree(wlan_static_prot); ++ ++#if defined(BCMDHD_SDIO) ++ if (wlan_static_rxbuf) ++ kfree(wlan_static_rxbuf); ++ ++ if (wlan_static_databuf) ++ kfree(wlan_static_databuf); ++#endif /* BCMDHD_SDIO */ ++ ++ if (wlan_static_osl_buf) ++ kfree(wlan_static_osl_buf); ++ ++ if (wlan_static_scan_buf0) ++ kfree(wlan_static_scan_buf0); ++ ++ if (wlan_static_scan_buf1) ++ kfree(wlan_static_scan_buf1); ++ ++ if (wlan_static_dhd_info_buf) ++ kfree(wlan_static_dhd_info_buf); ++ ++ if (wlan_static_dhd_wlfc_info_buf) ++ kfree(wlan_static_dhd_wlfc_info_buf); ++ ++#ifdef BCMDHD_PCIE ++ if (wlan_static_if_flow_lkup) ++ kfree(wlan_static_if_flow_lkup); ++#endif /* BCMDHD_PCIE */ ++ ++ if (wlan_static_dhd_memdump_ram_buf) ++ kfree(wlan_static_dhd_memdump_ram_buf); ++ ++ if (wlan_static_dhd_wlfc_hanger_buf) ++ kfree(wlan_static_dhd_wlfc_hanger_buf); ++ ++ if (wlan_static_wl_escan_info_buf) ++ kfree(wlan_static_wl_escan_info_buf); ++ ++#ifdef BCMDHD_PCIE ++ if (wlan_static_fw_verbose_ring_buf) ++ kfree(wlan_static_fw_verbose_ring_buf); ++ ++ if (wlan_static_fw_event_ring_buf) ++ kfree(wlan_static_fw_event_ring_buf); ++ ++ if (wlan_static_dhd_event_ring_buf) ++ kfree(wlan_static_dhd_event_ring_buf); ++ ++ if (wlan_static_nan_event_ring_buf) ++ kfree(wlan_static_nan_event_ring_buf); ++#endif /* BCMDHD_PCIE */ ++ ++ pr_err("%s: Failed to mem_alloc for WLAN\n", __func__); ++ ++ i = WLAN_SKB_BUF_NUM; ++ ++err_skb_alloc: ++ pr_err("%s: Failed to skb_alloc for WLAN\n", __func__); ++ for (j = 0; j < i; j++) ++ dev_kfree_skb(wlan_static_skb[j]); ++ ++ return -ENOMEM; ++} ++ ++static int __init ++dhd_static_buf_init(void) ++{ ++ dhd_init_wlan_mem(); ++ ++ return 0; ++} ++ ++static void __exit ++dhd_static_buf_exit(void) ++{ ++ int i; ++ ++ pr_err("%s()\n", __FUNCTION__); ++ ++ for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) { ++ if (wlan_static_skb[i]) ++ dev_kfree_skb(wlan_static_skb[i]); ++ } ++ ++ for (i = DHD_SKB_1PAGE_BUF_NUM; i < WLAN_SKB_1_2PAGE_BUF_NUM; i++) { ++ if (wlan_static_skb[i]) ++ dev_kfree_skb(wlan_static_skb[i]); ++ } ++ ++#if defined(BCMDHD_SDIO) ++ if (wlan_static_skb[i]) ++ dev_kfree_skb(wlan_static_skb[i]); ++#endif /* BCMDHD_SDIO */ ++ ++ if (wlan_static_prot) ++ kfree(wlan_static_prot); ++ ++#if defined(BCMDHD_SDIO) ++ if (wlan_static_rxbuf) ++ kfree(wlan_static_rxbuf); ++ ++ if (wlan_static_databuf) ++ kfree(wlan_static_databuf); ++#endif /* BCMDHD_SDIO */ ++ ++ if (wlan_static_osl_buf) ++ kfree(wlan_static_osl_buf); ++ ++ if (wlan_static_scan_buf0) ++ kfree(wlan_static_scan_buf0); ++ ++ if (wlan_static_scan_buf1) ++ kfree(wlan_static_scan_buf1); ++ ++ if (wlan_static_dhd_info_buf) ++ kfree(wlan_static_dhd_info_buf); ++ ++ if (wlan_static_dhd_wlfc_info_buf) ++ kfree(wlan_static_dhd_wlfc_info_buf); ++ ++#ifdef BCMDHD_PCIE ++ if (wlan_static_if_flow_lkup) ++ kfree(wlan_static_if_flow_lkup); ++#endif /* BCMDHD_PCIE */ ++ ++ if (wlan_static_dhd_memdump_ram_buf) ++ kfree(wlan_static_dhd_memdump_ram_buf); ++ ++ if (wlan_static_dhd_wlfc_hanger_buf) ++ kfree(wlan_static_dhd_wlfc_hanger_buf); ++ ++ if (wlan_static_wl_escan_info_buf) ++ kfree(wlan_static_wl_escan_info_buf); ++ ++#ifdef BCMDHD_PCIE ++ if (wlan_static_fw_verbose_ring_buf) ++ kfree(wlan_static_fw_verbose_ring_buf); ++ ++ if (wlan_static_fw_event_ring_buf) ++ kfree(wlan_static_fw_event_ring_buf); ++ ++ if (wlan_static_dhd_event_ring_buf) ++ kfree(wlan_static_dhd_event_ring_buf); ++ ++ if (wlan_static_nan_event_ring_buf) ++ kfree(wlan_static_nan_event_ring_buf); ++#endif ++ ++ return; ++} ++ ++module_init(dhd_static_buf_init); ++ ++module_exit(dhd_static_buf_exit); +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_wlfc.c b/module_drivers/drivers/net/wireless/bcmdhd/dhd_wlfc.c +new file mode 100644 +index 000000000..1768c90e0 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_wlfc.c +@@ -0,0 +1,4567 @@ ++/* ++ * DHD PROP_TXSTATUS Module. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_wlfc.c 679733 2017-01-17 06:40:39Z $ ++ * ++ */ ++ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#ifdef PROP_TXSTATUS /* a form of flow control between host and dongle */ ++#include ++#include ++#endif ++ ++#ifdef DHDTCPACK_SUPPRESS ++#include ++#endif /* DHDTCPACK_SUPPRESS */ ++ ++ ++/* ++ * wlfc naming and lock rules: ++ * ++ * 1. Private functions name like _dhd_wlfc_XXX, declared as static and avoid wlfc lock operation. ++ * 2. Public functions name like dhd_wlfc_XXX, use wlfc lock if needed. ++ * 3. Non-Proptxstatus module call public functions only and avoid wlfc lock operation. ++ * ++ */ ++ ++#if defined(DHD_WLFC_THREAD) ++#define WLFC_THREAD_QUICK_RETRY_WAIT_MS 10 /* 10 msec */ ++#define WLFC_THREAD_RETRY_WAIT_MS 10000 /* 10 sec */ ++#endif /* defined (DHD_WLFC_THREAD) */ ++ ++ ++#ifdef PROP_TXSTATUS ++ ++#define DHD_WLFC_QMON_COMPLETE(entry) ++ ++ ++/** reordering related */ ++ ++#if defined(DHD_WLFC_THREAD) ++static void ++_dhd_wlfc_thread_wakeup(dhd_pub_t *dhdp) ++{ ++ dhdp->wlfc_thread_go = TRUE; ++ wake_up_interruptible(&dhdp->wlfc_wqhead); ++} ++#endif /* DHD_WLFC_THREAD */ ++ ++static uint16 ++_dhd_wlfc_adjusted_seq(void* p, uint8 current_seq) ++{ ++ uint16 seq; ++ ++ if (!p) { ++ return 0xffff; ++ } ++ ++ seq = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ if (seq < current_seq) { ++ /* wrap around */ ++ seq += 256; ++ } ++ ++ return seq; ++} ++ ++/** ++ * Enqueue a caller supplied packet on a caller supplied precedence queue, optionally reorder ++ * suppressed packets. ++ * @param[in] pq caller supplied packet queue to enqueue the packet on ++ * @param[in] prec precedence of the to-be-queued packet ++ * @param[in] p transmit packet to enqueue ++ * @param[in] qHead if TRUE, enqueue to head instead of tail. Used to maintain d11 seq order. ++ * @param[in] current_seq ++ * @param[in] reOrder reOrder on odd precedence (=suppress queue) ++ */ ++static void ++_dhd_wlfc_prec_enque(struct pktq *pq, int prec, void* p, bool qHead, ++ uint8 current_seq, bool reOrder) ++{ ++ struct pktq_prec *q; ++ uint16 seq, seq2; ++ void *p2, *p2_prev; ++ ++ if (!p) ++ return; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ ++ ++ ASSERT(!pktq_full(pq)); ++ ASSERT(!pktq_pfull(pq, prec)); ++ ++ q = &pq->q[prec]; ++ ++ PKTSETLINK(p, NULL); ++ if (q->head == NULL) { ++ /* empty queue */ ++ q->head = p; ++ q->tail = p; ++ } else { ++ if (reOrder && (prec & 1)) { ++ seq = _dhd_wlfc_adjusted_seq(p, current_seq); ++ p2 = qHead ? q->head : q->tail; ++ seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); ++ ++ if ((qHead &&((seq+1) > seq2)) || (!qHead && ((seq2+1) > seq))) { ++ /* need reorder */ ++ p2 = q->head; ++ p2_prev = NULL; ++ seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); ++ ++ while (seq > seq2) { ++ p2_prev = p2; ++ p2 = PKTLINK(p2); ++ if (!p2) { ++ break; ++ } ++ seq2 = _dhd_wlfc_adjusted_seq(p2, current_seq); ++ } ++ ++ if (p2_prev == NULL) { ++ /* insert head */ ++ PKTSETLINK(p, q->head); ++ q->head = p; ++ } else if (p2 == NULL) { ++ /* insert tail */ ++ PKTSETLINK(p2_prev, p); ++ q->tail = p; ++ } else { ++ /* insert after p2_prev */ ++ PKTSETLINK(p, PKTLINK(p2_prev)); ++ PKTSETLINK(p2_prev, p); ++ } ++ goto exit; ++ } ++ } ++ ++ if (qHead) { ++ PKTSETLINK(p, q->head); ++ q->head = p; ++ } else { ++ PKTSETLINK(q->tail, p); ++ q->tail = p; ++ } ++ } ++ ++exit: ++ ++ q->len++; ++ pq->len++; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (uint8)prec; ++} /* _dhd_wlfc_prec_enque */ ++ ++/** ++ * Create a place to store all packet pointers submitted to the firmware until a status comes back, ++ * suppress or otherwise. ++ * ++ * hang-er: noun, a contrivance on which things are hung, as a hook. ++ */ ++/** @deprecated soon */ ++static void* ++_dhd_wlfc_hanger_create(dhd_pub_t *dhd, int max_items) ++{ ++ int i; ++ wlfc_hanger_t* hanger; ++ ++ /* allow only up to a specific size for now */ ++ ASSERT(max_items == WLFC_HANGER_MAXITEMS); ++ ++ if ((hanger = (wlfc_hanger_t*)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_DHD_WLFC_HANGER, ++ WLFC_HANGER_SIZE(max_items))) == NULL) { ++ return NULL; ++ } ++ memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); ++ hanger->max_items = max_items; ++ ++ for (i = 0; i < hanger->max_items; i++) { ++ hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++ return hanger; ++} ++ ++/** @deprecated soon */ ++static int ++_dhd_wlfc_hanger_delete(dhd_pub_t *dhd, void* hanger) ++{ ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h) { ++ DHD_OS_PREFREE(dhd, h, WLFC_HANGER_SIZE(h->max_items)); ++ return BCME_OK; ++ } ++ return BCME_BADARG; ++} ++ ++/** @deprecated soon */ ++static uint16 ++_dhd_wlfc_hanger_get_free_slot(void* hanger) ++{ ++ uint32 i; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h) { ++ i = h->slot_pos + 1; ++ if (i == h->max_items) { ++ i = 0; ++ } ++ while (i != h->slot_pos) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) { ++ h->slot_pos = i; ++ return (uint16)i; ++ } ++ i++; ++ if (i == h->max_items) ++ i = 0; ++ } ++ h->failed_slotfind++; ++ } ++ return WLFC_HANGER_MAXITEMS; ++} ++ ++/** @deprecated soon */ ++static int ++_dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ *gen = 0xff; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ ++ if (h) { ++ if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ *gen = h->items[slot_id].gen; ++ } ++ else { ++ DHD_ERROR(("Error: %s():%d item not used\n", ++ __FUNCTION__, __LINE__)); ++ rc = BCME_NOTFOUND; ++ } ++ ++ } else { ++ rc = BCME_BADARG; ++ } ++ ++ return rc; ++} ++ ++/** @deprecated soon */ ++static int ++_dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { ++ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { ++ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; ++ h->items[slot_id].pkt = pkt; ++ h->items[slot_id].pkt_state = 0; ++ h->items[slot_id].pkt_txstatus = 0; ++ h->pushed++; ++ } else { ++ h->failed_to_push++; ++ rc = BCME_NOTFOUND; ++ } ++ } else { ++ rc = BCME_BADARG; ++ } ++ ++ return rc; ++} ++ ++/** @deprecated soon */ ++static int ++_dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, bool remove_from_hanger) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ *pktout = NULL; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ ++ if (h) { ++ if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ *pktout = h->items[slot_id].pkt; ++ if (remove_from_hanger) { ++ h->items[slot_id].state = ++ WLFC_HANGER_ITEM_STATE_FREE; ++ h->items[slot_id].pkt = NULL; ++ h->items[slot_id].gen = 0xff; ++ h->items[slot_id].identifier = 0; ++ h->popped++; ++ } ++ } else { ++ h->failed_to_pop++; ++ rc = BCME_NOTFOUND; ++ } ++ } else { ++ rc = BCME_BADARG; ++ } ++ ++ return rc; ++} ++ ++/** @deprecated soon */ ++static int ++_dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) ++{ ++ int rc = BCME_OK; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; ++ ++ /* this packet was not pushed at the time it went to the firmware */ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return BCME_NOTFOUND; ++ if (h) { ++ h->items[slot_id].gen = gen; ++ if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { ++ h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; ++ } else { ++ rc = BCME_BADARG; ++ } ++ } else { ++ rc = BCME_BADARG; ++ } ++ ++ return rc; ++} ++ ++/** remove reference of specific packet in hanger */ ++/** @deprecated soon */ ++static bool ++_dhd_wlfc_hanger_remove_reference(wlfc_hanger_t* h, void* pkt) ++{ ++ int i; ++ ++ if (!h || !pkt) { ++ return FALSE; ++ } ++ ++ i = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(pkt))); ++ ++ if ((i < h->max_items) && (pkt == h->items[i].pkt)) { ++ if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; ++ h->items[i].pkt = NULL; ++ h->items[i].gen = 0xff; ++ h->items[i].identifier = 0; ++ return TRUE; ++ } else { ++ DHD_ERROR(("Error: %s():%d item not suppressed\n", ++ __FUNCTION__, __LINE__)); ++ } ++ } ++ ++ return FALSE; ++} ++ ++/** afq = At Firmware Queue, queue containing packets pending in the dongle */ ++static int ++_dhd_wlfc_enque_afq(athost_wl_status_info_t* ctx, void *p) ++{ ++ wlfc_mac_descriptor_t* entry; ++ uint16 entry_idx = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ uint8 prec = DHD_PKTTAG_FIFO(PKTTAG(p)); ++ ++ if (entry_idx < WLFC_MAC_DESC_TABLE_SIZE) ++ entry = &ctx->destination_entries.nodes[entry_idx]; ++ else if (entry_idx < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) ++ entry = &ctx->destination_entries.interfaces[entry_idx - WLFC_MAC_DESC_TABLE_SIZE]; ++ else ++ entry = &ctx->destination_entries.other; ++ ++ pktq_penq(&entry->afq, prec, p); ++ ++ return BCME_OK; ++} ++ ++/** afq = At Firmware Queue, queue containing packets pending in the dongle */ ++static int ++_dhd_wlfc_deque_afq(athost_wl_status_info_t* ctx, uint16 hslot, uint8 hcnt, uint8 prec, ++ void **pktout) ++{ ++ wlfc_mac_descriptor_t *entry; ++ struct pktq *pq; ++ struct pktq_prec *q; ++ void *p, *b; ++ ++ if (!ctx) { ++ DHD_ERROR(("%s: ctx(%p), pktout(%p)\n", __FUNCTION__, ctx, pktout)); ++ return BCME_BADARG; ++ } ++ ++ if (pktout) { ++ *pktout = NULL; ++ } ++ ++ ASSERT(hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM + 1)); ++ ++ if (hslot < WLFC_MAC_DESC_TABLE_SIZE) ++ entry = &ctx->destination_entries.nodes[hslot]; ++ else if (hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) ++ entry = &ctx->destination_entries.interfaces[hslot - WLFC_MAC_DESC_TABLE_SIZE]; ++ else ++ entry = &ctx->destination_entries.other; ++ ++ pq = &entry->afq; ++ ++ ASSERT(prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ ++ b = NULL; ++ p = q->head; ++ ++ while (p && (hcnt != WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))))) ++ { ++ b = p; ++ p = PKTLINK(p); ++ } ++ ++ if (p == NULL) { ++ /* none is matched */ ++ if (b) { ++ DHD_ERROR(("%s: can't find matching seq(%d)\n", __FUNCTION__, hcnt)); ++ } else { ++ DHD_ERROR(("%s: queue is empty\n", __FUNCTION__)); ++ } ++ ++ return BCME_ERROR; ++ } ++ ++ bcm_pkt_validate_chk(p); ++ ++ if (!b) { ++ /* head packet is matched */ ++ if ((q->head = PKTLINK(p)) == NULL) { ++ q->tail = NULL; ++ } ++ } else { ++ /* middle packet is matched */ ++ DHD_INFO(("%s: out of order, seq(%d), head_seq(%d)\n", __FUNCTION__, hcnt, ++ WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(q->head))))); ++ ctx->stats.ooo_pkts[prec]++; ++ PKTSETLINK(b, PKTLINK(p)); ++ if (PKTLINK(p) == NULL) { ++ q->tail = b; ++ } ++ } ++ ++ q->len--; ++ pq->len--; ++ ++ PKTSETLINK(p, NULL); ++ ++ if (pktout) { ++ *pktout = p; ++ } ++ ++ return BCME_OK; ++} /* _dhd_wlfc_deque_afq */ ++ ++/** ++ * Flow control information piggy backs on packets, in the form of one or more TLVs. This function ++ * pushes one or more TLVs onto a packet that is going to be sent towards the dongle. ++ * ++ * @param[in] ctx ++ * @param[in/out] packet ++ * @param[in] tim_signal TRUE if parameter 'tim_bmp' is valid ++ * @param[in] tim_bmp ++ * @param[in] mac_handle ++ * @param[in] htodtag ++ * @param[in] htodseq d11 seqno for seqno reuse, only used if 'seq reuse' was agreed upon ++ * earlier between host and firmware. ++ * @param[in] skip_wlfc_hdr ++ */ ++static int ++_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void** packet, bool tim_signal, ++ uint8 tim_bmp, uint8 mac_handle, uint32 htodtag, uint16 htodseq, bool skip_wlfc_hdr) ++{ ++ uint32 wl_pktinfo = 0; ++ uint8* wlh; ++ uint8 dataOffset = 0; ++ uint8 fillers; ++ uint8 tim_signal_len = 0; ++ dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; ++ ++ struct bdc_header *h; ++ void *p = *packet; ++ ++ if (skip_wlfc_hdr) ++ goto push_bdc_hdr; ++ ++ if (tim_signal) { ++ tim_signal_len = TLV_HDR_LEN + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; ++ } ++ ++ /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ ++ dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + TLV_HDR_LEN + tim_signal_len; ++ if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { ++ dataOffset += WLFC_CTL_VALUE_LEN_SEQ; ++ } ++ ++ fillers = ROUNDUP(dataOffset, 4) - dataOffset; ++ dataOffset += fillers; ++ ++ PKTPUSH(ctx->osh, p, dataOffset); ++ wlh = (uint8*) PKTDATA(ctx->osh, p); ++ ++ wl_pktinfo = htol32(htodtag); ++ ++ wlh[TLV_TAG_OFF] = WLFC_CTL_TYPE_PKTTAG; ++ wlh[TLV_LEN_OFF] = WLFC_CTL_VALUE_LEN_PKTTAG; ++ memcpy(&wlh[TLV_HDR_LEN] /* dst */, &wl_pktinfo, sizeof(uint32)); ++ ++ if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { ++ uint16 wl_seqinfo = htol16(htodseq); ++ wlh[TLV_LEN_OFF] += WLFC_CTL_VALUE_LEN_SEQ; ++ memcpy(&wlh[TLV_HDR_LEN + WLFC_CTL_VALUE_LEN_PKTTAG], &wl_seqinfo, ++ WLFC_CTL_VALUE_LEN_SEQ); ++ } ++ ++ if (tim_signal_len) { ++ wlh[dataOffset - fillers - tim_signal_len ] = ++ WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; ++ wlh[dataOffset - fillers - tim_signal_len + 1] = ++ WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; ++ wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; ++ wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; ++ } ++ if (fillers) ++ memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); ++ ++push_bdc_hdr: ++ PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); ++ h = (struct bdc_header *)PKTDATA(ctx->osh, p); ++ h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); ++ if (PKTSUMNEEDED(p)) ++ h->flags |= BDC_FLAG_SUM_NEEDED; ++ ++ ++ h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); ++ h->flags2 = 0; ++ h->dataOffset = dataOffset >> 2; ++ BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); ++ *packet = p; ++ return BCME_OK; ++} /* _dhd_wlfc_pushheader */ ++ ++/** ++ * Removes (PULLs) flow control related headers from the caller supplied packet, is invoked eg ++ * when a packet is about to be freed. ++ */ ++static int ++_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) ++{ ++ struct bdc_header *h; ++ ++ if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { ++ DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN)); ++ return BCME_ERROR; ++ } ++ h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); ++ ++ /* pull BDC header */ ++ PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); ++ ++ if (PKTLEN(ctx->osh, pktbuf) < (uint)(h->dataOffset << 2)) { ++ DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, ++ PKTLEN(ctx->osh, pktbuf), (h->dataOffset << 2))); ++ return BCME_ERROR; ++ } ++ ++ /* pull wl-header */ ++ PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); ++ return BCME_OK; ++} ++ ++/** ++ * @param[in/out] p packet ++ */ ++static wlfc_mac_descriptor_t* ++_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) ++{ ++ int i; ++ wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; ++ uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); ++ uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); ++ wlfc_mac_descriptor_t* entry = DHD_PKTTAG_ENTRY(PKTTAG(p)); ++ int iftype = ctx->destination_entries.interfaces[ifid].iftype; ++ ++ /* saved one exists, return it */ ++ if (entry) ++ return entry; ++ ++ /* Multicast destination, STA and P2P clients get the interface entry. ++ * STA/GC gets the Mac Entry for TDLS destinations, TDLS destinations ++ * have their own entry. ++ */ ++ if ((iftype == WLC_E_IF_ROLE_STA || ETHER_ISMULTI(dstn) || ++ iftype == WLC_E_IF_ROLE_P2P_CLIENT) && ++ (ctx->destination_entries.interfaces[ifid].occupied)) { ++ entry = &ctx->destination_entries.interfaces[ifid]; ++ } ++ ++ if (entry && ETHER_ISMULTI(dstn)) { ++ DHD_PKTTAG_SET_ENTRY(PKTTAG(p), entry); ++ return entry; ++ } ++ ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (table[i].occupied) { ++ if (table[i].interface_id == ifid) { ++ if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) { ++ entry = &table[i]; ++ break; ++ } ++ } ++ } ++ } ++ ++ if (entry == NULL) ++ entry = &ctx->destination_entries.other; ++ ++ DHD_PKTTAG_SET_ENTRY(PKTTAG(p), entry); ++ ++ return entry; ++} /* _dhd_wlfc_find_table_entry */ ++ ++/** ++ * In case a packet must be dropped (because eg the queues are full), various tallies have to be ++ * be updated. Called from several other functions. ++ * @param[in] dhdp pointer to public DHD structure ++ * @param[in] prec precedence of the packet ++ * @param[in] p the packet to be dropped ++ * @param[in] bPktInQ TRUE if packet is part of a queue ++ */ ++static int ++_dhd_wlfc_prec_drop(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ) ++{ ++ athost_wl_status_info_t* ctx; ++ void *pout = NULL; ++ ++ ASSERT(dhdp && p); ++ ASSERT(prec >= 0 && prec <= WLFC_PSQ_PREC_COUNT); ++ ++ ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; ++ ++ if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && (prec & 1)) { ++ /* suppressed queue, need pop from hanger */ ++ _dhd_wlfc_hanger_poppkt(ctx->hanger, WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG ++ (PKTTAG(p))), &pout, TRUE); ++ ASSERT(p == pout); ++ } ++ ++ if (!(prec & 1)) { ++#ifdef DHDTCPACK_SUPPRESS ++ /* pkt in delayed q, so fake push BDC header for ++ * dhd_tcpack_check_xmit() and dhd_txcomplete(). ++ */ ++ _dhd_wlfc_pushheader(ctx, &p, FALSE, 0, 0, 0, 0, TRUE); ++ ++ /* This packet is about to be freed, so remove it from tcp_ack_info_tbl ++ * This must be one of... ++ * 1. A pkt already in delayQ is evicted by another pkt with higher precedence ++ * in _dhd_wlfc_prec_enq_with_drop() ++ * 2. A pkt could not be enqueued to delayQ because it is full, ++ * in _dhd_wlfc_enque_delayq(). ++ * 3. A pkt could not be enqueued to delayQ because it is full, ++ * in _dhd_wlfc_rollback_packet_toq(). ++ */ ++ if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { ++ DHD_ERROR(("%s %d: tcpack_suppress ERROR!!!" ++ " Stop using it\n", ++ __FUNCTION__, __LINE__)); ++ dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); ++ } ++#endif /* DHDTCPACK_SUPPRESS */ ++ } ++ ++ if (bPktInQ) { ++ ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; ++ ctx->pkt_cnt_per_ac[prec>>1]--; ++ ctx->pkt_cnt_in_psq--; ++ } ++ ++ ctx->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(p))][DHD_PKTTAG_FIFO(PKTTAG(p))]--; ++ ctx->stats.pktout++; ++ ctx->stats.drop_pkts[prec]++; ++ ++ dhd_txcomplete(dhdp, p, FALSE); ++ PKTFREE(ctx->osh, p, TRUE); ++ ++ return 0; ++} /* _dhd_wlfc_prec_drop */ ++ ++/** ++ * Called when eg the host handed a new packet over to the driver, or when the dongle reported ++ * that a packet could currently not be transmitted (=suppressed). This function enqueues a transmit ++ * packet in the host driver to be (re)transmitted at a later opportunity. ++ * @param[in] dhdp pointer to public DHD structure ++ * @param[in] qHead When TRUE, queue packet at head instead of tail, to preserve d11 sequence ++ */ ++static bool ++_dhd_wlfc_prec_enq_with_drop(dhd_pub_t *dhdp, struct pktq *pq, void *pkt, int prec, bool qHead, ++ uint8 current_seq) ++{ ++ void *p = NULL; ++ int eprec = -1; /* precedence to evict from */ ++ athost_wl_status_info_t* ctx; ++ ++ ASSERT(dhdp && pq && pkt); ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; ++ ++ /* Fast case, precedence queue is not full and we are also not ++ * exceeding total queue length ++ */ ++ if (!pktq_pfull(pq, prec) && !pktq_full(pq)) { ++ goto exit; ++ } ++ ++ /* Determine precedence from which to evict packet, if any */ ++ if (pktq_pfull(pq, prec)) { ++ eprec = prec; ++ } else if (pktq_full(pq)) { ++ p = pktq_peek_tail(pq, &eprec); ++ if (!p) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return FALSE; ++ } ++ if ((eprec > prec) || (eprec < 0)) { ++ if (!pktq_pempty(pq, prec)) { ++ eprec = prec; ++ } else { ++ return FALSE; ++ } ++ } ++ } ++ ++ /* Evict if needed */ ++ if (eprec >= 0) { ++ /* Detect queueing to unconfigured precedence */ ++ ASSERT(!pktq_pempty(pq, eprec)); ++ /* Evict all fragmented frames */ ++ dhd_prec_drop_pkts(dhdp, pq, eprec, _dhd_wlfc_prec_drop); ++ } ++ ++exit: ++ /* Enqueue */ ++ _dhd_wlfc_prec_enque(pq, prec, pkt, qHead, current_seq, ++ WLFC_GET_REORDERSUPP(dhdp->wlfc_mode)); ++ ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(pkt))][prec>>1]++; ++ ctx->pkt_cnt_per_ac[prec>>1]++; ++ ctx->pkt_cnt_in_psq++; ++ ++ return TRUE; ++} /* _dhd_wlfc_prec_enq_with_drop */ ++ ++/** ++ * Called during eg the 'committing' of a transmit packet from the OS layer to a lower layer, in ++ * the event that this 'commit' failed. ++ */ ++static int ++_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, ++ void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) ++{ ++ /* ++ * put the packet back to the head of queue ++ * - suppressed packet goes back to suppress sub-queue ++ * - pull out the header, if new or delayed packet ++ * ++ * Note: hslot is used only when header removal is done. ++ */ ++ wlfc_mac_descriptor_t* entry; ++ int rc = BCME_OK; ++ int prec, fifo_id; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ prec = DHD_PKTTAG_FIFO(PKTTAG(p)); ++ fifo_id = prec << 1; ++ if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) ++ fifo_id += 1; ++ if (entry != NULL) { ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the firmware (for pspoll etc.) ++ */ ++ if ((prec != AC_COUNT) && !DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) ++ entry->requested_credit++; ++ ++ if (pkt_type == eWLFC_PKTTYPE_DELAYED) { ++ /* decrement sequence count */ ++ WLFC_DECR_SEQCOUNT(entry, prec); ++ /* remove header first */ ++ rc = _dhd_wlfc_pullheader(ctx, p); ++ if (rc != BCME_OK) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ goto exit; ++ } ++ } ++ ++ if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, p, fifo_id, TRUE, ++ WLFC_SEQCOUNT(entry, fifo_id>>1)) ++ == FALSE) { ++ /* enque failed */ ++ DHD_ERROR(("Error: %s():%d, fifo_id(%d)\n", ++ __FUNCTION__, __LINE__, fifo_id)); ++ rc = BCME_ERROR; ++ } ++ } else { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ rc = BCME_ERROR; ++ } ++ ++exit: ++ if (rc != BCME_OK) { ++ ctx->stats.rollback_failed++; ++ _dhd_wlfc_prec_drop(ctx->dhdp, fifo_id, p, FALSE); ++ } else { ++ ctx->stats.rollback++; ++ } ++ ++ return rc; ++} /* _dhd_wlfc_rollback_packet_toq */ ++ ++/** Returns TRUE if host OS -> DHD flow control is allowed on the caller supplied interface */ ++static bool ++_dhd_wlfc_allow_fc(athost_wl_status_info_t* ctx, uint8 ifid) ++{ ++ int prec, ac_traffic = WLFC_NO_TRAFFIC; ++ ++ for (prec = 0; prec < AC_COUNT; prec++) { ++ if (ctx->pkt_cnt_in_drv[ifid][prec] > 0) { ++ if (ac_traffic == WLFC_NO_TRAFFIC) ++ ac_traffic = prec + 1; ++ else if (ac_traffic != (prec + 1)) ++ ac_traffic = WLFC_MULTI_TRAFFIC; ++ } ++ } ++ ++ if (ac_traffic >= 1 && ac_traffic <= AC_COUNT) { ++ /* single AC (BE/BK/VI/VO) in queue */ ++ if (ctx->allow_fc) { ++ return TRUE; ++ } else { ++ uint32 delta; ++ uint32 curr_t = OSL_SYSUPTIME(); ++ ++ if (ctx->fc_defer_timestamp == 0) { ++ /* first single ac scenario */ ++ ctx->fc_defer_timestamp = curr_t; ++ return FALSE; ++ } ++ ++ /* single AC duration, this handles wrap around, e.g. 1 - ~0 = 2. */ ++ delta = curr_t - ctx->fc_defer_timestamp; ++ if (delta >= WLFC_FC_DEFER_PERIOD_MS) { ++ ctx->allow_fc = TRUE; ++ } ++ } ++ } else { ++ /* multiple ACs or BCMC in queue */ ++ ctx->allow_fc = FALSE; ++ ctx->fc_defer_timestamp = 0; ++ } ++ ++ return ctx->allow_fc; ++} /* _dhd_wlfc_allow_fc */ ++ ++/** ++ * Starts or stops the flow of transmit packets from the host OS towards the DHD, depending on ++ * low/high watermarks. ++ */ ++static void ++_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) ++{ ++ dhd_pub_t *dhdp; ++ ++ ASSERT(ctx); ++ ++ dhdp = (dhd_pub_t *)ctx->dhdp; ++ ASSERT(dhdp); ++ ++ if (dhdp->skip_fc && dhdp->skip_fc((void *)dhdp, if_id)) ++ return; ++ ++ if ((ctx->hostif_flow_state[if_id] == OFF) && !_dhd_wlfc_allow_fc(ctx, if_id)) ++ return; ++ ++ if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { ++ /* start traffic */ ++ ctx->hostif_flow_state[if_id] = OFF; ++ /* ++ WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", ++ pq->len, if_id, __FUNCTION__)); ++ */ ++ WLFC_DBGMESG(("F")); ++ ++ dhd_txflowcontrol(dhdp, if_id, OFF); ++ ++ ctx->toggle_host_if = 0; ++ } ++ ++ if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { ++ /* stop traffic */ ++ ctx->hostif_flow_state[if_id] = ON; ++ /* ++ WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", ++ pq->len, if_id, __FUNCTION__)); ++ */ ++ WLFC_DBGMESG(("N")); ++ ++ dhd_txflowcontrol(dhdp, if_id, ON); ++ ++ ctx->host_ifidx = if_id; ++ ctx->toggle_host_if = 1; ++ } ++ ++ return; ++} /* _dhd_wlfc_flow_control_check */ ++ ++static int ++_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ uint8 ta_bmp) ++{ ++ int rc = BCME_OK; ++ void* p = NULL; ++ int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 16; ++ dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; ++ ++ if (dhdp->proptxstatus_txoff) { ++ rc = BCME_NORESOURCE; ++ return rc; ++ } ++ ++ /* allocate a dummy packet */ ++ p = PKTGET(ctx->osh, dummylen, TRUE); ++ if (p) { ++ PKTPULL(ctx->osh, p, dummylen); ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); ++ _dhd_wlfc_pushheader(ctx, &p, TRUE, ta_bmp, entry->mac_handle, 0, 0, FALSE); ++ DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); ++ DHD_PKTTAG_WLFCPKT_SET(PKTTAG(p), 1); ++#ifdef PROP_TXSTATUS_DEBUG ++ ctx->stats.signal_only_pkts_sent++; ++#endif ++ ++#if defined(BCMPCIE) ++ rc = dhd_bus_txdata(dhdp->bus, p, ctx->host_ifidx); ++#else ++ rc = dhd_bus_txdata(dhdp->bus, p); ++#endif ++ if (rc != BCME_OK) { ++ _dhd_wlfc_pullheader(ctx, p); ++ PKTFREE(ctx->osh, p, TRUE); ++ } ++ } else { ++ DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", ++ __FUNCTION__, dummylen)); ++ rc = BCME_NOMEM; ++ dhdp->tx_pktgetfail++; ++ } ++ ++ return rc; ++} /* _dhd_wlfc_send_signalonly_packet */ ++ ++/** ++ * Called on eg receiving 'mac close' indication from dongle. Updates the per-MAC administration ++ * maintained in caller supplied parameter 'entry'. ++ * ++ * @param[in/out] entry administration about a remote MAC entity ++ * @param[in] prec precedence queue for this remote MAC entitity ++ * ++ * Return value: TRUE if traffic availability changed ++ */ ++static bool ++_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ int prec) ++{ ++ bool rc = FALSE; ++ ++ if (entry->state == WLFC_STATE_CLOSE) { ++ if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && ++ (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { ++ /* no packets in both 'normal' and 'suspended' queues */ ++ if (entry->traffic_pending_bmp & NBITVAL(prec)) { ++ rc = TRUE; ++ entry->traffic_pending_bmp = ++ entry->traffic_pending_bmp & ~ NBITVAL(prec); ++ } ++ } else { ++ /* packets are queued in host for transmission to dongle */ ++ if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { ++ rc = TRUE; ++ entry->traffic_pending_bmp = ++ entry->traffic_pending_bmp | NBITVAL(prec); ++ } ++ } ++ } ++ ++ if (rc) { ++ /* request a TIM update to firmware at the next piggyback opportunity */ ++ if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { ++ entry->send_tim_signal = 1; ++ _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); ++ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; ++ entry->send_tim_signal = 0; ++ } else { ++ rc = FALSE; ++ } ++ } ++ ++ return rc; ++} /* _dhd_wlfc_traffic_pending_check */ ++ ++/** ++ * Called on receiving a 'd11 suppressed' or 'wl suppressed' tx status from the firmware. Enqueues ++ * the packet to transmit to firmware again at a later opportunity. ++ */ ++static int ++_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) ++{ ++ wlfc_mac_descriptor_t* entry; ++ ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ if (entry == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_NOTFOUND; ++ } ++ /* ++ - suppressed packets go to sub_queue[2*prec + 1] AND ++ - delayed packets go to sub_queue[2*prec + 0] to ensure ++ order of delivery. ++ */ ++ if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, p, ((prec << 1) + 1), FALSE, ++ WLFC_SEQCOUNT(entry, prec)) ++ == FALSE) { ++ ctx->stats.delayq_full_error++; ++ /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */ ++ WLFC_DBGMESG(("s")); ++ return BCME_ERROR; ++ } ++ ++ /* A packet has been pushed, update traffic availability bitmap, if applicable */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); ++ return BCME_OK; ++} ++ ++/** ++ * Called when a transmit packet is about to be 'committed' from the OS layer to a lower layer ++ * towards the dongle (eg the DBUS layer). Updates wlfc administration. May modify packet. ++ * ++ * @param[in/out] ctx driver specific flow control administration ++ * @param[in/out] entry The remote MAC entity for which the packet is destined. ++ * @param[in/out] packet Packet to send. This function optionally adds TLVs to the packet. ++ * @param[in] header_needed True if packet is 'new' to flow control ++ * @param[out] slot Handle to container in which the packet was 'parked' ++ */ ++static int ++_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, ++ wlfc_mac_descriptor_t* entry, void** packet, int header_needed, uint32* slot) ++{ ++ int rc = BCME_OK; ++ int hslot = WLFC_HANGER_MAXITEMS; ++ bool send_tim_update = FALSE; ++ uint32 htod = 0; ++ uint16 htodseq = 0; ++ uint8 free_ctr; ++ int gen = 0xff; ++ dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; ++ void * p = *packet; ++ ++ *slot = hslot; ++ ++ if (entry == NULL) { ++ entry = _dhd_wlfc_find_table_entry(ctx, p); ++ } ++ ++ if (entry == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_ERROR; ++ } ++ ++ if (entry->send_tim_signal) { ++ /* sends a traffic indication bitmap to the dongle */ ++ send_tim_update = TRUE; ++ entry->send_tim_signal = 0; ++ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; ++ } ++ ++ if (header_needed) { ++ if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { ++ hslot = (uint)(entry - &ctx->destination_entries.nodes[0]); ++ } else { ++ hslot = _dhd_wlfc_hanger_get_free_slot(ctx->hanger); ++ } ++ gen = entry->generation; ++ free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ } else { ++ if (WLFC_GET_REUSESEQ(dhdp->wlfc_mode)) { ++ htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(p)); ++ } ++ ++ hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ ++ if (WLFC_GET_REORDERSUPP(dhdp->wlfc_mode)) { ++ gen = entry->generation; ++ } else if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { ++ gen = WL_TXSTATUS_GET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ } else { ++ _dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); ++ } ++ ++ free_ctr = WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))); ++ /* remove old header */ ++ _dhd_wlfc_pullheader(ctx, p); ++ } ++ ++ if (hslot >= WLFC_HANGER_MAXITEMS) { ++ DHD_ERROR(("Error: %s():no hanger slot available\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ WL_TXSTATUS_SET_FREERUNCTR(htod, free_ctr); ++ WL_TXSTATUS_SET_HSLOT(htod, hslot); ++ WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); ++ WL_TXSTATUS_SET_GENERATION(htod, gen); ++ DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); ++ ++ if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { ++ /* ++ Indicate that this packet is being sent in response to an ++ explicit request from the firmware side. ++ */ ++ WLFC_PKTFLAG_SET_PKTREQUESTED(htod); ++ } else { ++ WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); ++ } ++ ++ rc = _dhd_wlfc_pushheader(ctx, &p, send_tim_update, ++ entry->traffic_lastreported_bmp, entry->mac_handle, htod, htodseq, FALSE); ++ if (rc == BCME_OK) { ++ DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); ++ ++ if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { ++ wlfc_hanger_t *h = (wlfc_hanger_t*)(ctx->hanger); ++ if (header_needed) { ++ /* ++ a new header was created for this packet. ++ push to hanger slot and scrub q. Since bus ++ send succeeded, increment seq number as well. ++ */ ++ rc = _dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); ++ if (rc == BCME_OK) { ++#ifdef PROP_TXSTATUS_DEBUG ++ h->items[hslot].push_time = ++ OSL_SYSUPTIME(); ++#endif ++ } else { ++ DHD_ERROR(("%s() hanger_pushpkt() failed, rc: %d\n", ++ __FUNCTION__, rc)); ++ } ++ } else { ++ /* clear hanger state */ ++ if (((wlfc_hanger_t*)(ctx->hanger))->items[hslot].pkt != p) ++ DHD_ERROR(("%s() pkt not match: cur %p, hanger pkt %p\n", ++ __FUNCTION__, p, h->items[hslot].pkt)); ++ ASSERT(h->items[hslot].pkt == p); ++ bcm_object_feature_set(h->items[hslot].pkt, ++ BCM_OBJECT_FEATURE_PKT_STATE, 0); ++ h->items[hslot].pkt_state = 0; ++ h->items[hslot].pkt_txstatus = 0; ++ h->items[hslot].state = WLFC_HANGER_ITEM_STATE_INUSE; ++ } ++ } ++ ++ if ((rc == BCME_OK) && header_needed) { ++ /* increment free running sequence count */ ++ WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); ++ } ++ } ++ *slot = hslot; ++ *packet = p; ++ return rc; ++} /* _dhd_wlfc_pretx_pktprocess */ ++ ++/** ++ * A remote wireless mac may be temporarily 'closed' due to power management. Returns '1' if remote ++ * mac is in the 'open' state, otherwise '0'. ++ */ ++static int ++_dhd_wlfc_is_destination_open(athost_wl_status_info_t* ctx, ++ wlfc_mac_descriptor_t* entry, int prec) ++{ ++ wlfc_mac_descriptor_t* interfaces = ctx->destination_entries.interfaces; ++ ++ if (entry->interface_id >= WLFC_MAX_IFNUM) { ++ ASSERT(&ctx->destination_entries.other == entry); ++ return 1; ++ } ++ ++ if (interfaces[entry->interface_id].iftype == ++ WLC_E_IF_ROLE_P2P_GO) { ++ /* - destination interface is of type p2p GO. ++ For a p2pGO interface, if the destination is OPEN but the interface is ++ CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is ++ destination-specific-credit left send packets. This is because the ++ firmware storing the destination-specific-requested packet in queue. ++ */ ++ if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && ++ (entry->requested_packet == 0)) { ++ return 0; ++ } ++ } ++ ++ /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ ++ if ((((entry->state == WLFC_STATE_CLOSE) || ++ (interfaces[entry->interface_id].state == WLFC_STATE_CLOSE)) && ++ (entry->requested_credit == 0) && ++ (entry->requested_packet == 0)) || ++ (!(entry->ac_bitmap & (1 << prec)))) { ++ return 0; ++ } ++ ++ return 1; ++} /* _dhd_wlfc_is_destination_open */ ++ ++/** ++ * Dequeues a suppressed or delayed packet from a queue ++ * @param[in/out] ctx Driver specific flow control administration ++ * @param[in] prec Precedence of queue to dequeue from ++ * @param[out] ac_credit_spent Boolean, returns 0 or 1 ++ * @param[out] needs_hdr Boolean, returns 0 or 1 ++ * @param[out] entry_out The remote MAC for which the packet is destined ++ * @param[in] only_no_credit If TRUE, searches all entries instead of just the active ones ++ * ++ * Return value: the dequeued packet ++ */ ++static void* ++_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, int prec, ++ uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out, ++ bool only_no_credit) ++{ ++ wlfc_mac_descriptor_t* entry; ++ int total_entries; ++ void* p = NULL; ++ int i; ++ uint8 credit_spent = ((prec == AC_COUNT) && !ctx->bcmc_credit_supported) ? 0 : 1; ++ ++ *entry_out = NULL; ++ /* most cases a packet will count against FIFO credit */ ++ *ac_credit_spent = credit_spent; ++ ++ /* search all entries, include nodes as well as interfaces */ ++ if (only_no_credit) { ++ total_entries = ctx->requested_entry_count; ++ } else { ++ total_entries = ctx->active_entry_count; ++ } ++ ++ for (i = 0; i < total_entries; i++) { ++ if (only_no_credit) { ++ entry = ctx->requested_entry[i]; ++ } else { ++ entry = ctx->active_entry_head; ++ /* move head to ensure fair round-robin */ ++ ctx->active_entry_head = ctx->active_entry_head->next; ++ } ++ ASSERT(entry); ++ ++ if (entry->occupied && _dhd_wlfc_is_destination_open(ctx, entry, prec) && ++ (entry->transit_count < WL_TXSTATUS_FREERUNCTR_MASK) && ++ (!entry->suppressed)) { ++ *ac_credit_spent = credit_spent; ++ if (entry->state == WLFC_STATE_CLOSE) { ++ *ac_credit_spent = 0; ++ } ++ ++ /* higher precedence will be picked up first, ++ * i.e. suppressed packets before delayed ones ++ */ ++ p = pktq_pdeq(&entry->psq, PSQ_SUP_IDX(prec)); ++ *needs_hdr = 0; ++ if (p == NULL) { ++ /* De-Q from delay Q */ ++ p = pktq_pdeq(&entry->psq, PSQ_DLY_IDX(prec)); ++ *needs_hdr = 1; ++ } ++ ++ if (p != NULL) { ++ bcm_pkt_validate_chk(p); ++ /* did the packet come from suppress sub-queue? */ ++ if (entry->requested_credit > 0) { ++ entry->requested_credit--; ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_sent_packets++; ++#endif ++ } else if (entry->requested_packet > 0) { ++ entry->requested_packet--; ++ DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); ++ } ++ ++ *entry_out = entry; ++ ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec]--; ++ ctx->pkt_cnt_per_ac[prec]--; ++ ctx->pkt_cnt_in_psq--; ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, ++ DHD_PKTTAG_IF(PKTTAG(p))); ++ /* ++ * A packet has been picked up, update traffic availability bitmap, ++ * if applicable. ++ */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ return p; ++ } ++ } ++ } ++ return NULL; ++} /* _dhd_wlfc_deque_delayedq */ ++ ++/** Enqueues caller supplied packet on either a 'suppressed' or 'delayed' queue */ ++static int ++_dhd_wlfc_enque_delayq(athost_wl_status_info_t* ctx, void* pktbuf, int prec) ++{ ++ wlfc_mac_descriptor_t* entry; ++ ++ if (pktbuf != NULL) { ++ entry = _dhd_wlfc_find_table_entry(ctx, pktbuf); ++ if (entry == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_ERROR; ++ } ++ ++ /* ++ - suppressed packets go to sub_queue[2*prec + 1] AND ++ - delayed packets go to sub_queue[2*prec + 0] to ensure ++ order of delivery. ++ */ ++ if (_dhd_wlfc_prec_enq_with_drop(ctx->dhdp, &entry->psq, pktbuf, (prec << 1), ++ FALSE, WLFC_SEQCOUNT(entry, prec)) ++ == FALSE) { ++ WLFC_DBGMESG(("D")); ++ ctx->stats.delayq_full_error++; ++ return BCME_ERROR; ++ } ++ ++ ++ /* A packet has been pushed, update traffic availability bitmap, if applicable */ ++ _dhd_wlfc_traffic_pending_check(ctx, entry, prec); ++ } ++ ++ return BCME_OK; ++} /* _dhd_wlfc_enque_delayq */ ++ ++/** Returns TRUE if caller supplied packet is destined for caller supplied interface */ ++static bool _dhd_wlfc_ifpkt_fn(void* p, void *p_ifid) ++{ ++ if (!p || !p_ifid) ++ return FALSE; ++ ++ return (DHD_PKTTAG_WLFCPKT(PKTTAG(p))&& (*((uint8 *)p_ifid) == DHD_PKTTAG_IF(PKTTAG(p)))); ++} ++ ++/** Returns TRUE if caller supplied packet is destined for caller supplied remote MAC */ ++static bool _dhd_wlfc_entrypkt_fn(void* p, void *entry) ++{ ++ if (!p || !entry) ++ return FALSE; ++ ++ return (DHD_PKTTAG_WLFCPKT(PKTTAG(p))&& (entry == DHD_PKTTAG_ENTRY(PKTTAG(p)))); ++} ++ ++static void ++_dhd_wlfc_return_implied_credit(athost_wl_status_info_t* wlfc, void* pkt) ++{ ++ dhd_pub_t *dhdp; ++ bool credit_return = FALSE; ++ ++ if (!wlfc || !pkt) { ++ return; ++ } ++ ++ dhdp = (dhd_pub_t *)(wlfc->dhdp); ++ if (dhdp && (dhdp->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) && ++ DHD_PKTTAG_CREDITCHECK(PKTTAG(pkt))) { ++ int lender, credit_returned = 0; ++ uint8 fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pkt)); ++ ++ credit_return = TRUE; ++ ++ /* Note that borrower is fifo_id */ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; lender >= 0; lender--) { ++ if (wlfc->credits_borrowed[fifo_id][lender] > 0) { ++ wlfc->FIFO_credit[lender]++; ++ wlfc->credits_borrowed[fifo_id][lender]--; ++ credit_returned = 1; ++ break; ++ } ++ } ++ ++ if (!credit_returned) { ++ wlfc->FIFO_credit[fifo_id]++; ++ } ++ } ++ ++ BCM_REFERENCE(credit_return); ++#if defined(DHD_WLFC_THREAD) ++ if (credit_return) { ++ _dhd_wlfc_thread_wakeup(dhdp); ++ } ++#endif /* defined(DHD_WLFC_THREAD) */ ++} ++ ++/** Removes and frees a packet from the hanger. Called during eg tx complete. */ ++static void ++_dhd_wlfc_hanger_free_pkt(athost_wl_status_info_t* wlfc, uint32 slot_id, uint8 pkt_state, ++ int pkt_txstatus) ++{ ++ wlfc_hanger_t* hanger; ++ wlfc_hanger_item_t* item; ++ ++ if (!wlfc) ++ return; ++ ++ hanger = (wlfc_hanger_t*)wlfc->hanger; ++ if (!hanger) ++ return; ++ ++ if (slot_id == WLFC_HANGER_MAXITEMS) ++ return; ++ ++ item = &hanger->items[slot_id]; ++ ++ if (item->pkt) { ++ item->pkt_state |= pkt_state; ++ if (pkt_txstatus != -1) ++ item->pkt_txstatus = (uint8)pkt_txstatus; ++ bcm_object_feature_set(item->pkt, BCM_OBJECT_FEATURE_PKT_STATE, item->pkt_state); ++ if (item->pkt_state == WLFC_HANGER_PKT_STATE_COMPLETE) { ++ void *p = NULL; ++ void *pkt = item->pkt; ++ uint8 old_state = item->state; ++ int ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, slot_id, &p, TRUE); ++ BCM_REFERENCE(ret); ++ BCM_REFERENCE(pkt); ++ ASSERT((ret == BCME_OK) && p && (pkt == p)); ++ if (old_state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { ++ printf("ERROR: free a suppressed pkt %p state %d pkt_state %d\n", ++ pkt, old_state, item->pkt_state); ++ } ++ ASSERT(old_state != WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED); ++ ++ /* free packet */ ++ wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(p))] ++ [DHD_PKTTAG_FIFO(PKTTAG(p))]--; ++ wlfc->stats.pktout++; ++ dhd_txcomplete((dhd_pub_t *)wlfc->dhdp, p, item->pkt_txstatus); ++ PKTFREE(wlfc->osh, p, TRUE); ++ } ++ } else { ++ /* free slot */ ++ if (item->state == WLFC_HANGER_ITEM_STATE_FREE) ++ DHD_ERROR(("Error: %s():%d Multiple TXSTATUS or BUSRETURNED: %d (%d)\n", ++ __FUNCTION__, __LINE__, item->pkt_state, pkt_state)); ++ item->state = WLFC_HANGER_ITEM_STATE_FREE; ++ } ++} /* _dhd_wlfc_hanger_free_pkt */ ++ ++/** Called during eg detach() */ ++static void ++_dhd_wlfc_pktq_flush(athost_wl_status_info_t* ctx, struct pktq *pq, ++ bool dir, f_processpkt_t fn, void *arg, q_type_t q_type) ++{ ++ int prec; ++ dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp; ++ ++ ASSERT(dhdp); ++ ++ /* Optimize flush, if pktq len = 0, just return. ++ * pktq len of 0 means pktq's prec q's are all empty. ++ */ ++ if (pq->len == 0) { ++ return; ++ } ++ ++ for (prec = 0; prec < pq->num_prec; prec++) { ++ struct pktq_prec *q; ++ void *p, *prev = NULL; ++ ++ q = &pq->q[prec]; ++ p = q->head; ++ while (p) { ++ bcm_pkt_validate_chk(p); ++ if (fn == NULL || (*fn)(p, arg)) { ++ bool head = (p == q->head); ++ if (head) ++ q->head = PKTLINK(p); ++ else ++ PKTSETLINK(prev, PKTLINK(p)); ++ if (q_type == Q_TYPE_PSQ) { ++ if (!WLFC_GET_AFQ(dhdp->wlfc_mode) && (prec & 1)) { ++ _dhd_wlfc_hanger_remove_reference(ctx->hanger, p); ++ } ++ ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; ++ ctx->pkt_cnt_per_ac[prec>>1]--; ++ ctx->pkt_cnt_in_psq--; ++ ctx->stats.cleanup_psq_cnt++; ++ if (!(prec & 1)) { ++ /* pkt in delayed q, so fake push BDC header for ++ * dhd_tcpack_check_xmit() and dhd_txcomplete(). ++ */ ++ _dhd_wlfc_pushheader(ctx, &p, FALSE, 0, 0, ++ 0, 0, TRUE); ++#ifdef DHDTCPACK_SUPPRESS ++ if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { ++ DHD_ERROR(("%s %d: tcpack_suppress ERROR!!!" ++ " Stop using it\n", ++ __FUNCTION__, __LINE__)); ++ dhd_tcpack_suppress_set(dhdp, ++ TCPACK_SUP_OFF); ++ } ++#endif /* DHDTCPACK_SUPPRESS */ ++ } ++ } else if (q_type == Q_TYPE_AFQ) { ++ wlfc_mac_descriptor_t* entry = ++ _dhd_wlfc_find_table_entry(ctx, p); ++ if (entry->transit_count) ++ entry->transit_count--; ++ if (entry->suppr_transit_count) { ++ entry->suppr_transit_count--; ++ if (entry->suppressed && ++ (!entry->onbus_pkts_count) && ++ (!entry->suppr_transit_count)) ++ entry->suppressed = FALSE; ++ } ++ _dhd_wlfc_return_implied_credit(ctx, p); ++ ctx->stats.cleanup_fw_cnt++; ++ } ++ PKTSETLINK(p, NULL); ++ if (dir) { ++ ctx->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(p))][prec>>1]--; ++ ctx->stats.pktout++; ++ dhd_txcomplete(dhdp, p, FALSE); ++ } ++ PKTFREE(ctx->osh, p, dir); ++ ++ q->len--; ++ pq->len--; ++ p = (head ? q->head : PKTLINK(prev)); ++ } else { ++ prev = p; ++ p = PKTLINK(p); ++ } ++ } ++ ++ if (q->head == NULL) { ++ ASSERT(q->len == 0); ++ q->tail = NULL; ++ } ++ ++ } ++ ++ if (fn == NULL) ++ ASSERT(pq->len == 0); ++} /* _dhd_wlfc_pktq_flush */ ++ ++#ifndef BCMDBUS ++/** !BCMDBUS specific function. Dequeues a packet from the caller supplied queue. */ ++static void* ++_dhd_wlfc_pktq_pdeq_with_fn(struct pktq *pq, int prec, f_processpkt_t fn, void *arg) ++{ ++ struct pktq_prec *q; ++ void *p, *prev = NULL; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ p = q->head; ++ ++ while (p) { ++ if (fn == NULL || (*fn)(p, arg)) { ++ break; ++ } else { ++ prev = p; ++ p = PKTLINK(p); ++ } ++ } ++ if (p == NULL) ++ return NULL; ++ ++ bcm_pkt_validate_chk(p); ++ ++ if (prev == NULL) { ++ if ((q->head = PKTLINK(p)) == NULL) { ++ q->tail = NULL; ++ } ++ } else { ++ PKTSETLINK(prev, PKTLINK(p)); ++ if (q->tail == p) { ++ q->tail = prev; ++ } ++ } ++ ++ q->len--; ++ ++ pq->len--; ++ ++ PKTSETLINK(p, NULL); ++ ++ return p; ++} ++ ++/** !BCMDBUS specific function */ ++static void ++_dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) ++{ ++ int prec; ++ void *pkt = NULL, *head = NULL, *tail = NULL; ++ struct pktq *txq = (struct pktq *)dhd_bus_txq(dhd->bus); ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; ++ wlfc_mac_descriptor_t* entry; ++ ++ dhd_os_sdlock_txq(dhd); ++ for (prec = 0; prec < txq->num_prec; prec++) { ++ while ((pkt = _dhd_wlfc_pktq_pdeq_with_fn(txq, prec, fn, arg))) { ++#ifdef DHDTCPACK_SUPPRESS ++ if (dhd_tcpack_check_xmit(dhd, pkt) == BCME_ERROR) { ++ DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", ++ __FUNCTION__, __LINE__)); ++ dhd_tcpack_suppress_set(dhd, TCPACK_SUP_OFF); ++ } ++#endif /* DHDTCPACK_SUPPRESS */ ++ if (!head) { ++ head = pkt; ++ } ++ if (tail) { ++ PKTSETLINK(tail, pkt); ++ } ++ tail = pkt; ++ } ++ } ++ dhd_os_sdunlock_txq(dhd); ++ ++ ++ while ((pkt = head)) { ++ head = PKTLINK(pkt); ++ PKTSETLINK(pkt, NULL); ++ entry = _dhd_wlfc_find_table_entry(wlfc, pkt); ++ ++ if (!WLFC_GET_AFQ(dhd->wlfc_mode) && ++ !_dhd_wlfc_hanger_remove_reference(h, pkt)) { ++ DHD_ERROR(("%s: can't find pkt(%p) in hanger, free it anyway\n", ++ __FUNCTION__, pkt)); ++ } ++ if (entry->transit_count) ++ entry->transit_count--; ++ if (entry->suppr_transit_count) { ++ entry->suppr_transit_count--; ++ if (entry->suppressed && ++ (!entry->onbus_pkts_count) && ++ (!entry->suppr_transit_count)) ++ entry->suppressed = FALSE; ++ } ++ _dhd_wlfc_return_implied_credit(wlfc, pkt); ++ wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(pkt))][DHD_PKTTAG_FIFO(PKTTAG(pkt))]--; ++ wlfc->stats.pktout++; ++ wlfc->stats.cleanup_txq_cnt++; ++ dhd_txcomplete(dhd, pkt, FALSE); ++ PKTFREE(wlfc->osh, pkt, TRUE); ++ } ++} /* _dhd_wlfc_cleanup_txq */ ++#endif /* !BCMDBUS */ ++ ++/** called during eg detach */ ++void ++_dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) ++{ ++ int i; ++ int total_entries; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; ++ ++ wlfc->stats.cleanup_txq_cnt = 0; ++ wlfc->stats.cleanup_psq_cnt = 0; ++ wlfc->stats.cleanup_fw_cnt = 0; ++ ++ /* ++ * flush sequence should be txq -> psq -> hanger/afq, hanger has to be last one ++ */ ++#ifndef BCMDBUS ++ /* flush bus->txq */ ++ _dhd_wlfc_cleanup_txq(dhd, fn, arg); ++#endif /* !BCMDBUS */ ++ ++ /* flush psq, search all entries, include nodes as well as interfaces */ ++ total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); ++ table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; ++ ++ for (i = 0; i < total_entries; i++) { ++ if (table[i].occupied) { ++ /* release packets held in PSQ (both delayed and suppressed) */ ++ if (table[i].psq.len) { ++ WLFC_DBGMESG(("%s(): PSQ[%d].len = %d\n", ++ __FUNCTION__, i, table[i].psq.len)); ++ _dhd_wlfc_pktq_flush(wlfc, &table[i].psq, TRUE, ++ fn, arg, Q_TYPE_PSQ); ++ } ++ ++ /* free packets held in AFQ */ ++ if (WLFC_GET_AFQ(dhd->wlfc_mode) && (table[i].afq.len)) { ++ _dhd_wlfc_pktq_flush(wlfc, &table[i].afq, TRUE, ++ fn, arg, Q_TYPE_AFQ); ++ } ++ ++ if ((fn == NULL) && (&table[i] != &wlfc->destination_entries.other)) { ++ table[i].occupied = 0; ++ if (table[i].transit_count || table[i].suppr_transit_count) { ++ DHD_ERROR(("%s: table[%d] transit(%d), suppr_tansit(%d)\n", ++ __FUNCTION__, i, ++ table[i].transit_count, ++ table[i].suppr_transit_count)); ++ } ++ } ++ } ++ } ++ ++ /* ++ . flush remained pkt in hanger queue, not in bus->txq nor psq. ++ . the remained pkt was successfully downloaded to dongle already. ++ . hanger slot state cannot be set to free until receive txstatus update. ++ */ ++ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ for (i = 0; i < h->max_items; i++) { ++ if ((h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) || ++ (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { ++ if (fn == NULL || (*fn)(h->items[i].pkt, arg)) { ++ h->items[i].state = WLFC_HANGER_ITEM_STATE_FLUSHED; ++ } ++ } ++ } ++ } ++ ++ return; ++} /* _dhd_wlfc_cleanup */ ++ ++/** Called after eg the dongle signalled a new remote MAC that it connected with to the DHD */ ++static int ++_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, ++ uint8 action, uint8 ifid, uint8 iftype, uint8* ea, ++ f_processpkt_t fn, void *arg) ++{ ++ int rc = BCME_OK; ++ ++ ++ if ((action == eWLFC_MAC_ENTRY_ACTION_ADD) || (action == eWLFC_MAC_ENTRY_ACTION_UPDATE)) { ++ entry->occupied = 1; ++ entry->state = WLFC_STATE_OPEN; ++ entry->requested_credit = 0; ++ entry->interface_id = ifid; ++ entry->iftype = iftype; ++ entry->ac_bitmap = 0xff; /* update this when handling APSD */ ++ ++ /* for an interface entry we may not care about the MAC address */ ++ if (ea != NULL) ++ memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); ++ ++ if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { ++ entry->suppressed = FALSE; ++ entry->transit_count = 0; ++ entry->suppr_transit_count = 0; ++ entry->onbus_pkts_count = 0; ++ } ++ ++ if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { ++ dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp); ++ ++ pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, ifid); ++ ++ if (WLFC_GET_AFQ(dhdp->wlfc_mode)) { ++ pktq_init(&entry->afq, WLFC_AFQ_PREC_COUNT, WLFC_PSQ_LEN); ++ } ++ ++ if (entry->next == NULL) { ++ /* not linked to anywhere, add to tail */ ++ if (ctx->active_entry_head) { ++ entry->prev = ctx->active_entry_head->prev; ++ ctx->active_entry_head->prev->next = entry; ++ ctx->active_entry_head->prev = entry; ++ entry->next = ctx->active_entry_head; ++ } else { ++ ASSERT(ctx->active_entry_count == 0); ++ entry->prev = entry->next = entry; ++ ctx->active_entry_head = entry; ++ } ++ ctx->active_entry_count++; ++ } else { ++ DHD_ERROR(("%s():%d, entry(%d)\n", __FUNCTION__, __LINE__, ++ (int)(entry - &ctx->destination_entries.nodes[0]))); ++ } ++ } ++ } else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { ++ /* When the entry is deleted, the packets that are queued in the entry must be ++ cleanup. The cleanup action should be before the occupied is set as 0. ++ */ ++ _dhd_wlfc_cleanup(ctx->dhdp, fn, arg); ++ _dhd_wlfc_flow_control_check(ctx, &entry->psq, ifid); ++ ++ entry->occupied = 0; ++ entry->state = WLFC_STATE_CLOSE; ++ memset(&entry->ea[0], 0, ETHER_ADDR_LEN); ++ ++ if (entry->next) { ++ /* not floating, remove from Q */ ++ if (ctx->active_entry_count <= 1) { ++ /* last item */ ++ ctx->active_entry_head = NULL; ++ ctx->active_entry_count = 0; ++ } else { ++ entry->prev->next = entry->next; ++ entry->next->prev = entry->prev; ++ if (entry == ctx->active_entry_head) { ++ ctx->active_entry_head = entry->next; ++ } ++ ctx->active_entry_count--; ++ } ++ entry->next = entry->prev = NULL; ++ } else { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ } ++ } ++ return rc; ++} /* _dhd_wlfc_mac_entry_update */ ++ ++ ++#ifdef LIMIT_BORROW ++ ++/** LIMIT_BORROW specific function */ ++static int ++_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, int highest_lender_ac, int borrower_ac, ++ bool bBorrowAll) ++{ ++ int lender_ac, borrow_limit = 0; ++ int rc = -1; ++ ++ if (ctx == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return -1; ++ } ++ ++ /* Borrow from lowest priority available AC (including BC/MC credits) */ ++ for (lender_ac = 0; lender_ac <= highest_lender_ac; lender_ac++) { ++ if (!bBorrowAll) { ++ borrow_limit = ctx->Init_FIFO_credit[lender_ac]/WLFC_BORROW_LIMIT_RATIO; ++ } else { ++ borrow_limit = 0; ++ } ++ ++ if (ctx->FIFO_credit[lender_ac] > borrow_limit) { ++ ctx->credits_borrowed[borrower_ac][lender_ac]++; ++ ctx->FIFO_credit[lender_ac]--; ++ rc = lender_ac; ++ break; ++ } ++ } ++ ++ return rc; ++} ++ ++/** LIMIT_BORROW specific function */ ++static int _dhd_wlfc_return_credit(athost_wl_status_info_t* ctx, int lender_ac, int borrower_ac) ++{ ++ if ((ctx == NULL) || (lender_ac < 0) || (lender_ac > AC_COUNT) || ++ (borrower_ac < 0) || (borrower_ac > AC_COUNT)) { ++ DHD_ERROR(("Error: %s():%d, ctx(%p), lender_ac(%d), borrower_ac(%d)\n", ++ __FUNCTION__, __LINE__, ctx, lender_ac, borrower_ac)); ++ ++ return BCME_BADARG; ++ } ++ ++ ctx->credits_borrowed[borrower_ac][lender_ac]--; ++ ctx->FIFO_credit[lender_ac]++; ++ ++ return BCME_OK; ++} ++ ++#endif /* LIMIT_BORROW */ ++ ++/** ++ * Called on an interface event (WLC_E_IF) indicated by firmware. ++ * @param action : eg eWLFC_MAC_ENTRY_ACTION_UPDATE or eWLFC_MAC_ENTRY_ACTION_ADD ++ */ ++static int ++_dhd_wlfc_interface_entry_update(void* state, ++ uint8 action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ wlfc_mac_descriptor_t* entry; ++ ++ if (ifid >= WLFC_MAX_IFNUM) ++ return BCME_BADARG; ++ ++ entry = &ctx->destination_entries.interfaces[ifid]; ++ ++ return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea, ++ _dhd_wlfc_ifpkt_fn, &ifid); ++} ++ ++/** ++ * Called eg on receiving a WLC_E_BCMC_CREDIT_SUPPORT event from the dongle (broadcast/multicast ++ * specific) ++ */ ++static int ++_dhd_wlfc_BCMCCredit_support_update(void* state) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ ++ ctx->bcmc_credit_supported = TRUE; ++ return BCME_OK; ++} ++ ++/** Called eg on receiving a WLC_E_FIFO_CREDIT_MAP event from the dongle */ ++static int ++_dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) ++{ ++ athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; ++ int i; ++ ++ for (i = 0; i <= 4; i++) { ++ if (ctx->Init_FIFO_credit[i] != ctx->FIFO_credit[i]) { ++ DHD_ERROR(("%s: credit[i] is not returned, (%d %d)\n", ++ __FUNCTION__, ctx->Init_FIFO_credit[i], ctx->FIFO_credit[i])); ++ } ++ } ++ ++ /* update the AC FIFO credit map */ ++ ctx->FIFO_credit[0] += (credits[0] - ctx->Init_FIFO_credit[0]); ++ ctx->FIFO_credit[1] += (credits[1] - ctx->Init_FIFO_credit[1]); ++ ctx->FIFO_credit[2] += (credits[2] - ctx->Init_FIFO_credit[2]); ++ ctx->FIFO_credit[3] += (credits[3] - ctx->Init_FIFO_credit[3]); ++ ctx->FIFO_credit[4] += (credits[4] - ctx->Init_FIFO_credit[4]); ++ ++ ctx->Init_FIFO_credit[0] = credits[0]; ++ ctx->Init_FIFO_credit[1] = credits[1]; ++ ctx->Init_FIFO_credit[2] = credits[2]; ++ ctx->Init_FIFO_credit[3] = credits[3]; ++ ctx->Init_FIFO_credit[4] = credits[4]; ++ ++ /* credit for ATIM FIFO is not used yet. */ ++ ctx->Init_FIFO_credit[5] = ctx->FIFO_credit[5] = 0; ++ ++ return BCME_OK; ++} ++ ++/** ++ * Called during committing of a transmit packet from the OS DHD layer to the next layer towards ++ * the dongle (eg the DBUS layer). All transmit packets flow via this function to the next layer. ++ * ++ * @param[in/out] ctx Driver specific flow control administration ++ * @param[in] ac Access Category (QoS) of called supplied packet ++ * @param[in] commit_info Contains eg the packet to send ++ * @param[in] fcommit Function pointer to transmit function of next software layer ++ * @param[in] commit_ctx Opaque context used when calling next layer ++ */ ++static int ++_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, ++ dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) ++{ ++ uint32 hslot; ++ int rc; ++ dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp); ++ ++ /* ++ if ac_fifo_credit_spent = 0 ++ ++ This packet will not count against the FIFO credit. ++ To ensure the txstatus corresponding to this packet ++ does not provide an implied credit (default behavior) ++ mark the packet accordingly. ++ ++ if ac_fifo_credit_spent = 1 ++ ++ This is a normal packet and it counts against the FIFO ++ credit count. ++ */ ++ DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); ++ rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, &commit_info->p, ++ commit_info->needs_hdr, &hslot); ++ ++ if (rc == BCME_OK) { ++ rc = fcommit(commit_ctx, commit_info->p); ++ if (rc == BCME_OK) { ++ uint8 gen = WL_TXSTATUS_GET_GENERATION( ++ DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p))); ++ ctx->stats.pkt2bus++; ++ if (commit_info->ac_fifo_credit_spent || (ac == AC_COUNT)) { ++ ctx->stats.send_pkts[ac]++; ++ WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); ++ } ++ ++ if (gen != commit_info->mac_entry->generation) { ++ /* will be suppressed back by design */ ++ if (!commit_info->mac_entry->suppressed) { ++ commit_info->mac_entry->suppressed = TRUE; ++ } ++ commit_info->mac_entry->suppr_transit_count++; ++ } ++ commit_info->mac_entry->transit_count++; ++ commit_info->mac_entry->onbus_pkts_count++; ++ } else if (commit_info->needs_hdr) { ++ if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { ++ void *pout = NULL; ++ /* pop hanger for delayed packet */ ++ _dhd_wlfc_hanger_poppkt(ctx->hanger, WL_TXSTATUS_GET_HSLOT( ++ DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p))), &pout, TRUE); ++ ASSERT(commit_info->p == pout); ++ } ++ } ++ } else { ++ ctx->stats.generic_error++; ++ } ++ ++ if (rc != BCME_OK) { ++ /* ++ pretx pkt process or bus commit has failed, rollback. ++ - remove wl-header for a delayed packet ++ - save wl-header header for suppressed packets ++ - reset credit check flag ++ */ ++ _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, commit_info->pkt_type, hslot); ++ DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), 0); ++ } ++ ++ return rc; ++} /* _dhd_wlfc_handle_packet_commit */ ++ ++/** Returns remote MAC descriptor for caller supplied MAC address */ ++static uint8 ++_dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8 *ea) ++{ ++ wlfc_mac_descriptor_t* table = ++ ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; ++ uint8 table_index; ++ ++ if (ea != NULL) { ++ for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { ++ if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && ++ table[table_index].occupied) ++ return table_index; ++ } ++ } ++ return WLFC_MAC_DESC_ID_INVALID; ++} ++ ++/** ++ * Called when the host receives a WLFC_CTL_TYPE_TXSTATUS event from the dongle, indicating the ++ * status of a frame that the dongle attempted to transmit over the wireless medium. ++ */ ++static int ++dhd_wlfc_suppressed_acked_update(dhd_pub_t *dhd, uint16 hslot, uint8 prec, uint8 hcnt) ++{ ++ athost_wl_status_info_t* ctx; ++ wlfc_mac_descriptor_t* entry = NULL; ++ struct pktq *pq; ++ struct pktq_prec *q; ++ void *p, *b; ++ ++ if (!dhd) { ++ DHD_ERROR(("%s: dhd(%p)\n", __FUNCTION__, dhd)); ++ return BCME_BADARG; ++ } ++ ctx = (athost_wl_status_info_t*)dhd->wlfc_state; ++ if (!ctx) { ++ DHD_ERROR(("%s: ctx(%p)\n", __FUNCTION__, ctx)); ++ return BCME_ERROR; ++ } ++ ++ ASSERT(hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM + 1)); ++ ++ if (hslot < WLFC_MAC_DESC_TABLE_SIZE) ++ entry = &ctx->destination_entries.nodes[hslot]; ++ else if (hslot < (WLFC_MAC_DESC_TABLE_SIZE + WLFC_MAX_IFNUM)) ++ entry = &ctx->destination_entries.interfaces[hslot - WLFC_MAC_DESC_TABLE_SIZE]; ++ else ++ entry = &ctx->destination_entries.other; ++ ++ pq = &entry->psq; ++ ++ ASSERT(((prec << 1) + 1) < pq->num_prec); ++ ++ q = &pq->q[((prec << 1) + 1)]; ++ ++ b = NULL; ++ p = q->head; ++ ++ while (p && (hcnt != WL_TXSTATUS_GET_FREERUNCTR(DHD_PKTTAG_H2DTAG(PKTTAG(p))))) { ++ b = p; ++ p = PKTLINK(p); ++ } ++ ++ if (p == NULL) { ++ /* none is matched */ ++ if (b) { ++ DHD_ERROR(("%s: can't find matching seq(%d)\n", __FUNCTION__, hcnt)); ++ } else { ++ DHD_ERROR(("%s: queue is empty\n", __FUNCTION__)); ++ } ++ ++ return BCME_ERROR; ++ } ++ ++ if (!b) { ++ /* head packet is matched */ ++ if ((q->head = PKTLINK(p)) == NULL) { ++ q->tail = NULL; ++ } ++ } else { ++ /* middle packet is matched */ ++ PKTSETLINK(b, PKTLINK(p)); ++ if (PKTLINK(p) == NULL) { ++ q->tail = b; ++ } ++ } ++ ++ q->len--; ++ pq->len--; ++ ctx->pkt_cnt_in_q[DHD_PKTTAG_IF(PKTTAG(p))][prec]--; ++ ctx->pkt_cnt_per_ac[prec]--; ++ ++ PKTSETLINK(p, NULL); ++ ++ if (WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ _dhd_wlfc_enque_afq(ctx, p); ++ } else { ++ _dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); ++ } ++ ++ entry->transit_count++; ++ ++ return BCME_OK; ++} ++ ++static int ++_dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len, void** p_mac) ++{ ++ uint8 status_flag_ori, status_flag; ++ uint32 status; ++ int ret = BCME_OK; ++ int remove_from_hanger_ori, remove_from_hanger = 1; ++ void* pktbuf = NULL; ++ uint8 fifo_id = 0, gen = 0, count = 0, hcnt; ++ uint16 hslot; ++ wlfc_mac_descriptor_t* entry = NULL; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ uint16 seq = 0, seq_fromfw = 0, seq_num = 0; ++ ++ memcpy(&status, pkt_info, sizeof(uint32)); ++ status = ltoh32(status); ++ status_flag = WL_TXSTATUS_GET_FLAGS(status); ++ hcnt = WL_TXSTATUS_GET_FREERUNCTR(status); ++ hslot = WL_TXSTATUS_GET_HSLOT(status); ++ fifo_id = WL_TXSTATUS_GET_FIFO(status); ++ gen = WL_TXSTATUS_GET_GENERATION(status); ++ ++ if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { ++ memcpy(&seq, pkt_info + WLFC_CTL_VALUE_LEN_TXSTATUS, WLFC_CTL_VALUE_LEN_SEQ); ++ seq = ltoh16(seq); ++ seq_fromfw = GET_WL_HAS_ASSIGNED_SEQ(seq); ++ seq_num = WL_SEQ_GET_NUM(seq); ++ } ++ ++ wlfc->stats.txstatus_in += len; ++ ++ if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { ++ wlfc->stats.pkt_freed += len; ++ } else if (status_flag == WLFC_CTL_PKTFLAG_DISCARD_NOACK) { ++ wlfc->stats.pkt_freed += len; ++ } else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { ++ wlfc->stats.d11_suppress += len; ++ remove_from_hanger = 0; ++ } else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { ++ wlfc->stats.wl_suppress += len; ++ remove_from_hanger = 0; ++ } else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { ++ wlfc->stats.wlc_tossed_pkts += len; ++ } else if (status_flag == WLFC_CTL_PKTFLAG_SUPPRESS_ACKED) { ++ wlfc->stats.pkt_freed += len; ++ } ++ ++ if (dhd->proptxstatus_txstatus_ignore) { ++ if (!remove_from_hanger) { ++ DHD_ERROR(("suppress txstatus: %d\n", status_flag)); ++ } ++ return BCME_OK; ++ } ++ ++ status_flag_ori = status_flag; ++ remove_from_hanger_ori = remove_from_hanger; ++ ++ while (count < len) { ++ if (status_flag == WLFC_CTL_PKTFLAG_SUPPRESS_ACKED) { ++ dhd_wlfc_suppressed_acked_update(dhd, hslot, fifo_id, hcnt); ++ } ++ if (WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ ret = _dhd_wlfc_deque_afq(wlfc, hslot, hcnt, fifo_id, &pktbuf); ++ } else { ++ status_flag = status_flag_ori; ++ remove_from_hanger = remove_from_hanger_ori; ++ ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, hslot, &pktbuf, FALSE); ++ if (!pktbuf) { ++ _dhd_wlfc_hanger_free_pkt(wlfc, hslot, ++ WLFC_HANGER_PKT_STATE_TXSTATUS, -1); ++ goto cont; ++ } else { ++ wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; ++ if (h->items[hslot].state == WLFC_HANGER_ITEM_STATE_FLUSHED) { ++ status_flag = WLFC_CTL_PKTFLAG_DISCARD; ++ remove_from_hanger = 1; ++ } ++ } ++ } ++ ++ if ((ret != BCME_OK) || !pktbuf) { ++ goto cont; ++ } ++ ++ bcm_pkt_validate_chk(pktbuf); ++ ++ /* set fifo_id to correct value because not all FW does that */ ++ fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); ++ ++ if (!remove_from_hanger) { ++ /* this packet was suppressed */ ++ if (!entry->suppressed || (entry->generation != gen)) { ++ if (!entry->suppressed) { ++ entry->suppr_transit_count = entry->transit_count; ++ if (p_mac) { ++ *p_mac = entry; ++ } ++ } else { ++ DHD_ERROR(("gen(%d), entry->generation(%d)\n", ++ gen, entry->generation)); ++ } ++ entry->suppressed = TRUE; ++ ++ } ++ entry->generation = gen; ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) ++ { ++ uint32 new_t = OSL_SYSUPTIME(); ++ uint32 old_t; ++ uint32 delta; ++ old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[hslot].push_time; ++ ++ ++ wlfc->stats.latency_sample_count++; ++ if (new_t > old_t) ++ delta = new_t - old_t; ++ else ++ delta = 0xffffffff + new_t - old_t; ++ wlfc->stats.total_status_latency += delta; ++ wlfc->stats.latency_most_recent = delta; ++ ++ wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; ++ if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) ++ wlfc->stats.idx_delta = 0; ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ ++ /* pick up the implicit credit from this packet */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { ++ _dhd_wlfc_return_implied_credit(wlfc, pktbuf); ++ } else { ++ /* ++ if this packet did not count against FIFO credit, it must have ++ taken a requested_credit from the destination entry (for pspoll etc.) ++ */ ++ if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) { ++ entry->requested_credit++; ++#if defined(DHD_WLFC_THREAD) ++ _dhd_wlfc_thread_wakeup(dhd); ++#endif /* DHD_WLFC_THREAD */ ++ } ++#ifdef PROP_TXSTATUS_DEBUG ++ entry->dstncredit_acks++; ++#endif ++ } ++ ++ if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || ++ (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { ++ /* save generation bit inside packet */ ++ WL_TXSTATUS_SET_GENERATION(DHD_PKTTAG_H2DTAG(PKTTAG(pktbuf)), gen); ++ ++ if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { ++ WL_SEQ_SET_REUSE(DHD_PKTTAG_H2DSEQ(PKTTAG(pktbuf)), seq_fromfw); ++ WL_SEQ_SET_NUM(DHD_PKTTAG_H2DSEQ(PKTTAG(pktbuf)), seq_num); ++ } ++ ++ ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); ++ if (ret != BCME_OK) { ++ /* delay q is full, drop this packet */ ++ DHD_WLFC_QMON_COMPLETE(entry); ++ _dhd_wlfc_prec_drop(dhd, (fifo_id << 1) + 1, pktbuf, FALSE); ++ } else { ++ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ /* Mark suppressed to avoid a double free ++ during wlfc cleanup ++ */ ++ _dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, hslot, gen); ++ } ++ } ++ } else { ++ ++ DHD_WLFC_QMON_COMPLETE(entry); ++ ++ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ _dhd_wlfc_hanger_free_pkt(wlfc, hslot, ++ WLFC_HANGER_PKT_STATE_TXSTATUS, TRUE); ++ } else { ++ dhd_txcomplete(dhd, pktbuf, TRUE); ++ wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(pktbuf))] ++ [DHD_PKTTAG_FIFO(PKTTAG(pktbuf))]--; ++ wlfc->stats.pktout++; ++ /* free the packet */ ++ PKTFREE(wlfc->osh, pktbuf, TRUE); ++ } ++ } ++ /* pkt back from firmware side */ ++ if (entry->transit_count) ++ entry->transit_count--; ++ if (entry->suppr_transit_count) { ++ entry->suppr_transit_count--; ++ if (entry->suppressed && ++ (!entry->onbus_pkts_count) && ++ (!entry->suppr_transit_count)) ++ entry->suppressed = FALSE; ++ } ++ ++cont: ++ hcnt = (hcnt + 1) & WL_TXSTATUS_FREERUNCTR_MASK; ++ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ hslot = (hslot + 1) & WL_TXSTATUS_HSLOT_MASK; ++ } ++ ++ if (WLFC_GET_REUSESEQ(dhd->wlfc_mode) && seq_fromfw) { ++ seq_num = (seq_num + 1) & WL_SEQ_NUM_MASK; ++ } ++ ++ count++; ++ } ++ ++ return BCME_OK; ++} /* _dhd_wlfc_compressed_txstatus_update */ ++ ++/** ++ * Called when eg host receives a 'WLFC_CTL_TYPE_FIFO_CREDITBACK' event from the dongle. ++ * @param[in] credits caller supplied credit that will be added to the host credit. ++ */ ++static int ++_dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) ++{ ++ int i; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { ++#ifdef PROP_TXSTATUS_DEBUG ++ wlfc->stats.fifo_credits_back[i] += credits[i]; ++#endif ++ ++ /* update FIFO credits */ ++ if (dhd->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) ++ { ++ int lender; /* Note that borrower is i */ ++ ++ /* Return credits to highest priority lender first */ ++ for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { ++ if (wlfc->credits_borrowed[i][lender] > 0) { ++ if (credits[i] >= wlfc->credits_borrowed[i][lender]) { ++ credits[i] -= ++ (uint8)wlfc->credits_borrowed[i][lender]; ++ wlfc->FIFO_credit[lender] += ++ wlfc->credits_borrowed[i][lender]; ++ wlfc->credits_borrowed[i][lender] = 0; ++ } else { ++ wlfc->credits_borrowed[i][lender] -= credits[i]; ++ wlfc->FIFO_credit[lender] += credits[i]; ++ credits[i] = 0; ++ } ++ } ++ } ++ ++ /* If we have more credits left over, these must belong to the AC */ ++ if (credits[i] > 0) { ++ wlfc->FIFO_credit[i] += credits[i]; ++ } ++ ++ if (wlfc->FIFO_credit[i] > wlfc->Init_FIFO_credit[i]) { ++ wlfc->FIFO_credit[i] = wlfc->Init_FIFO_credit[i]; ++ } ++ } ++ } ++ ++#if defined(DHD_WLFC_THREAD) ++ _dhd_wlfc_thread_wakeup(dhd); ++#endif /* defined(DHD_WLFC_THREAD) */ ++ ++ return BCME_OK; ++} /* _dhd_wlfc_fifocreditback_indicate */ ++ ++#ifndef BCMDBUS ++/** !BCMDBUS specific function */ ++static void ++_dhd_wlfc_suppress_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ wlfc_mac_descriptor_t* entry; ++ int prec; ++ void *pkt = NULL, *head = NULL, *tail = NULL; ++ struct pktq *txq = (struct pktq *)dhd_bus_txq(dhd->bus); ++ uint8 results[WLFC_CTL_VALUE_LEN_TXSTATUS+WLFC_CTL_VALUE_LEN_SEQ]; ++ uint8 credits[WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK] = {0}; ++ uint32 htod = 0; ++ uint16 htodseq = 0; ++ bool bCreditUpdate = FALSE; ++ ++ dhd_os_sdlock_txq(dhd); ++ for (prec = 0; prec < txq->num_prec; prec++) { ++ while ((pkt = _dhd_wlfc_pktq_pdeq_with_fn(txq, prec, fn, arg))) { ++ if (!head) { ++ head = pkt; ++ } ++ if (tail) { ++ PKTSETLINK(tail, pkt); ++ } ++ tail = pkt; ++ } ++ } ++ dhd_os_sdunlock_txq(dhd); ++ ++ while ((pkt = head)) { ++ head = PKTLINK(pkt); ++ PKTSETLINK(pkt, NULL); ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, pkt); ++ if (!entry) { ++ PKTFREE(dhd->osh, pkt, TRUE); ++ continue; ++ } ++ if (entry->onbus_pkts_count > 0) { ++ entry->onbus_pkts_count--; ++ } ++ if (entry->suppressed && ++ (!entry->onbus_pkts_count) && ++ (!entry->suppr_transit_count)) { ++ entry->suppressed = FALSE; ++ } ++ /* fake a suppression txstatus */ ++ htod = DHD_PKTTAG_H2DTAG(PKTTAG(pkt)); ++ WL_TXSTATUS_SET_FLAGS(htod, WLFC_CTL_PKTFLAG_WLSUPPRESS); ++ WL_TXSTATUS_SET_GENERATION(htod, entry->generation); ++ htod = htol32(htod); ++ memcpy(results, &htod, WLFC_CTL_VALUE_LEN_TXSTATUS); ++ if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { ++ htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(pkt)); ++ if (IS_WL_TO_REUSE_SEQ(htodseq)) { ++ SET_WL_HAS_ASSIGNED_SEQ(htodseq); ++ RESET_WL_TO_REUSE_SEQ(htodseq); ++ } ++ htodseq = htol16(htodseq); ++ memcpy(results + WLFC_CTL_VALUE_LEN_TXSTATUS, &htodseq, ++ WLFC_CTL_VALUE_LEN_SEQ); ++ } ++ if (WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ _dhd_wlfc_enque_afq(wlfc, pkt); ++ } ++ _dhd_wlfc_compressed_txstatus_update(dhd, results, 1, NULL); ++ ++ /* fake a fifo credit back */ ++ if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pkt))) { ++ credits[DHD_PKTTAG_FIFO(PKTTAG(pkt))]++; ++ bCreditUpdate = TRUE; ++ } ++ } ++ ++ if (bCreditUpdate) { ++ _dhd_wlfc_fifocreditback_indicate(dhd, credits); ++ } ++} /* _dhd_wlfc_suppress_txq */ ++#endif /* !BCMDBUS */ ++ ++static int ++_dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value) ++{ ++ uint32 timestamp; ++ ++ (void)dhd; ++ ++ bcopy(&value[2], ×tamp, sizeof(uint32)); ++ timestamp = ltoh32(timestamp); ++ DHD_INFO(("RXPKT: SEQ: %d, timestamp %d\n", value[1], timestamp)); ++ return BCME_OK; ++} ++ ++static int ++_dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) ++{ ++ (void)dhd; ++ (void)rssi; ++ return BCME_OK; ++} ++ ++static void ++_dhd_wlfc_add_requested_entry(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry) ++{ ++ int i; ++ ++ if (!wlfc || !entry) { ++ return; ++ } ++ ++ for (i = 0; i < wlfc->requested_entry_count; i++) { ++ if (entry == wlfc->requested_entry[i]) { ++ break; ++ } ++ } ++ ++ if (i == wlfc->requested_entry_count) { ++ /* no match entry found */ ++ ASSERT(wlfc->requested_entry_count <= (WLFC_MAC_DESC_TABLE_SIZE-1)); ++ wlfc->requested_entry[wlfc->requested_entry_count++] = entry; ++ } ++} ++ ++/** called on eg receiving 'mac open' event from the dongle. */ ++static void ++_dhd_wlfc_remove_requested_entry(athost_wl_status_info_t* wlfc, wlfc_mac_descriptor_t* entry) ++{ ++ int i; ++ ++ if (!wlfc || !entry) { ++ return; ++ } ++ ++ for (i = 0; i < wlfc->requested_entry_count; i++) { ++ if (entry == wlfc->requested_entry[i]) { ++ break; ++ } ++ } ++ ++ if (i < wlfc->requested_entry_count) { ++ /* found */ ++ ASSERT(wlfc->requested_entry_count > 0); ++ wlfc->requested_entry_count--; ++ if (i != wlfc->requested_entry_count) { ++ wlfc->requested_entry[i] = ++ wlfc->requested_entry[wlfc->requested_entry_count]; ++ } ++ wlfc->requested_entry[wlfc->requested_entry_count] = NULL; ++ } ++} ++ ++/** called on eg receiving a WLFC_CTL_TYPE_MACDESC_ADD TLV from the dongle */ ++static int ++_dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ int rc; ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ uint8 existing_index; ++ uint8 table_index; ++ uint8 ifid; ++ uint8* ea; ++ ++ WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", ++ __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], ++ ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), ++ WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0])); ++ ++ table = wlfc->destination_entries.nodes; ++ table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); ++ ifid = value[1]; ++ ea = &value[2]; ++ ++ _dhd_wlfc_remove_requested_entry(wlfc, &table[table_index]); ++ if (type == WLFC_CTL_TYPE_MACDESC_ADD) { ++ existing_index = _dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); ++ if ((existing_index != WLFC_MAC_DESC_ID_INVALID) && ++ (existing_index != table_index) && table[existing_index].occupied) { ++ /* ++ there is an existing different entry, free the old one ++ and move it to new index if necessary. ++ */ ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[existing_index], ++ eWLFC_MAC_ENTRY_ACTION_DEL, table[existing_index].interface_id, ++ table[existing_index].iftype, NULL, _dhd_wlfc_entrypkt_fn, ++ &table[existing_index]); ++ } ++ ++ if (!table[table_index].occupied) { ++ /* this new MAC entry does not exist, create one */ ++ table[table_index].mac_handle = value[0]; ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], ++ eWLFC_MAC_ENTRY_ACTION_ADD, ifid, ++ wlfc->destination_entries.interfaces[ifid].iftype, ++ ea, NULL, NULL); ++ } else { ++ /* the space should have been empty, but it's not */ ++ wlfc->stats.mac_update_failed++; ++ } ++ } ++ ++ if (type == WLFC_CTL_TYPE_MACDESC_DEL) { ++ if (table[table_index].occupied) { ++ rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], ++ eWLFC_MAC_ENTRY_ACTION_DEL, ifid, ++ wlfc->destination_entries.interfaces[ifid].iftype, ++ ea, _dhd_wlfc_entrypkt_fn, &table[table_index]); ++ } else { ++ /* the space should have been occupied, but it's not */ ++ wlfc->stats.mac_update_failed++; ++ } ++ } ++ BCM_REFERENCE(rc); ++ return BCME_OK; ++} /* _dhd_wlfc_mac_table_update */ ++ ++/** Called on a 'mac open' or 'mac close' event indicated by the dongle */ ++static int ++_dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ /* Handle PS on/off indication */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; /* a table maps from mac handle to mac descriptor */ ++ uint8 mac_handle = value[0]; ++ int i; ++ ++ table = wlfc->destination_entries.nodes; ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ if (type == WLFC_CTL_TYPE_MAC_OPEN) { ++ desc->state = WLFC_STATE_OPEN; ++ desc->ac_bitmap = 0xff; ++ DHD_WLFC_CTRINC_MAC_OPEN(desc); ++ desc->requested_credit = 0; ++ desc->requested_packet = 0; ++ _dhd_wlfc_remove_requested_entry(wlfc, desc); ++ } else { ++ desc->state = WLFC_STATE_CLOSE; ++ DHD_WLFC_CTRINC_MAC_CLOSE(desc); ++ /* Indicate to firmware if there is any traffic pending. */ ++ for (i = 0; i < AC_COUNT; i++) { ++ _dhd_wlfc_traffic_pending_check(wlfc, desc, i); ++ } ++ } ++ } else { ++ wlfc->stats.psmode_update_failed++; ++ } ++ ++ return BCME_OK; ++} /* _dhd_wlfc_psmode_update */ ++ ++/** called upon receiving 'interface open' or 'interface close' event from the dongle */ ++static int ++_dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) ++{ ++ /* Handle PS on/off indication */ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ uint8 if_id = value[0]; ++ ++ if (if_id < WLFC_MAX_IFNUM) { ++ table = wlfc->destination_entries.interfaces; ++ if (table[if_id].occupied) { ++ if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { ++ table[if_id].state = WLFC_STATE_OPEN; ++ /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ ++ } else { ++ table[if_id].state = WLFC_STATE_CLOSE; ++ /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ ++ } ++ return BCME_OK; ++ } ++ } ++ wlfc->stats.interface_update_failed++; ++ ++ return BCME_OK; ++} ++ ++/** Called on receiving a WLFC_CTL_TYPE_MAC_REQUEST_CREDIT TLV from the dongle */ ++static int ++_dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle; ++ uint8 credit; ++ ++ table = wlfc->destination_entries.nodes; ++ mac_handle = value[1]; ++ credit = value[0]; ++ ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ desc->requested_credit = credit; ++ ++ desc->ac_bitmap = value[2] & (~(1<stats.credit_request_failed++; ++ } ++ ++ return BCME_OK; ++} ++ ++/** Called on receiving a WLFC_CTL_TYPE_MAC_REQUEST_PACKET TLV from the dongle */ ++static int ++_dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) ++{ ++ athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ wlfc_mac_descriptor_t* table; ++ wlfc_mac_descriptor_t* desc; ++ uint8 mac_handle; ++ uint8 packet_count; ++ ++ table = wlfc->destination_entries.nodes; ++ mac_handle = value[1]; ++ packet_count = value[0]; ++ ++ desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; ++ if (desc->occupied) { ++ desc->requested_packet = packet_count; ++ ++ desc->ac_bitmap = value[2] & (~(1<stats.packet_request_failed++; ++ } ++ ++ return BCME_OK; ++} ++ ++/** Called when host receives a WLFC_CTL_TYPE_HOST_REORDER_RXPKTS TLV from the dongle */ ++static void ++_dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) ++{ ++ if (info_len) { ++ /* Check copy length to avoid buffer overrun. In case of length exceeding ++ * WLHOST_REORDERDATA_TOTLEN, return failure instead sending incomplete result ++ * of length WLHOST_REORDERDATA_TOTLEN ++ */ ++ if ((info_buf) && (len <= WLHOST_REORDERDATA_TOTLEN)) { ++ bcopy(val, info_buf, len); ++ *info_len = len; ++ } else { ++ *info_len = 0; ++ } ++ } ++} ++ ++/* ++ * public functions ++ */ ++ ++bool dhd_wlfc_is_supported(dhd_pub_t *dhd) ++{ ++ bool rc = TRUE; ++ ++ if (dhd == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return FALSE; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ rc = FALSE; ++ } ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return rc; ++} ++ ++int dhd_wlfc_enable(dhd_pub_t *dhd) ++{ ++ int i, rc = BCME_OK; ++ athost_wl_status_info_t* wlfc; ++ ++ if (dhd == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (!dhd->wlfc_enabled || dhd->wlfc_state) { ++ rc = BCME_OK; ++ goto exit; ++ } ++ ++ /* allocate space to track txstatus propagated from firmware */ ++ dhd->wlfc_state = DHD_OS_PREALLOC(dhd, DHD_PREALLOC_DHD_WLFC_INFO, ++ sizeof(athost_wl_status_info_t)); ++ if (dhd->wlfc_state == NULL) { ++ rc = BCME_NOMEM; ++ goto exit; ++ } ++ ++ /* initialize state space */ ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ memset(wlfc, 0, sizeof(athost_wl_status_info_t)); ++ ++ /* remember osh & dhdp */ ++ wlfc->osh = dhd->osh; ++ wlfc->dhdp = dhd; ++ ++ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ wlfc->hanger = _dhd_wlfc_hanger_create(dhd, WLFC_HANGER_MAXITEMS); ++ if (wlfc->hanger == NULL) { ++ DHD_OS_PREFREE(dhd, dhd->wlfc_state, ++ sizeof(athost_wl_status_info_t)); ++ dhd->wlfc_state = NULL; ++ rc = BCME_NOMEM; ++ goto exit; ++ } ++ } ++ ++ dhd->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; ++ /* default to check rx pkt */ ++ dhd->wlfc_rxpkt_chk = TRUE; ++ if (dhd->op_mode & DHD_FLAG_IBSS_MODE) { ++ dhd->wlfc_rxpkt_chk = FALSE; ++ } ++ ++ /* initialize all interfaces to accept traffic */ ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ wlfc->hostif_flow_state[i] = OFF; ++ } ++ ++ _dhd_wlfc_mac_entry_update(wlfc, &wlfc->destination_entries.other, ++ eWLFC_MAC_ENTRY_ACTION_ADD, 0xff, 0, NULL, NULL, NULL); ++ ++ wlfc->allow_credit_borrow = 0; ++ wlfc->single_ac = 0; ++ wlfc->single_ac_timestamp = 0; ++ ++ ++exit: ++ DHD_ERROR(("%s: ret=%d\n", __FUNCTION__, rc)); ++ dhd_os_wlfc_unblock(dhd); ++ ++ return rc; ++} /* dhd_wlfc_enable */ ++ ++#ifdef SUPPORT_P2P_GO_PS ++ ++/** ++ * Called when the host platform enters a lower power mode, eg right before a system hibernate. ++ * SUPPORT_P2P_GO_PS specific function. ++ */ ++int ++dhd_wlfc_suspend(dhd_pub_t *dhd) ++{ ++ uint32 tlv = 0; ++ ++ DHD_TRACE(("%s: masking wlfc events\n", __FUNCTION__)); ++ if (!dhd->wlfc_enabled) ++ return -1; ++ ++ if (!dhd_wl_ioctl_get_intiovar(dhd, "tlv", &tlv, WLC_GET_VAR, FALSE, 0)) ++ return -1; ++ if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == 0) ++ return 0; ++ tlv &= ~(WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); ++ if (!dhd_wl_ioctl_set_intiovar(dhd, "tlv", tlv, WLC_SET_VAR, TRUE, 0)) ++ return -1; ++ ++ return 0; ++} ++ ++/** ++ * Called when the host platform resumes from a power management operation, eg resume after a ++ * system hibernate. SUPPORT_P2P_GO_PS specific function. ++ */ ++int ++dhd_wlfc_resume(dhd_pub_t *dhd) ++{ ++ uint32 tlv = 0; ++ ++ DHD_TRACE(("%s: unmasking wlfc events\n", __FUNCTION__)); ++ if (!dhd->wlfc_enabled) ++ return -1; ++ ++ if (!dhd_wl_ioctl_get_intiovar(dhd, "tlv", &tlv, WLC_GET_VAR, FALSE, 0)) ++ return -1; ++ if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == ++ (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) ++ return 0; ++ tlv |= (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS); ++ if (!dhd_wl_ioctl_set_intiovar(dhd, "tlv", tlv, WLC_SET_VAR, TRUE, 0)) ++ return -1; ++ ++ return 0; ++} ++ ++#endif /* SUPPORT_P2P_GO_PS */ ++ ++/** A flow control header was received from firmware, containing one or more TLVs */ ++int ++dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, ++ uint *reorder_info_len) ++{ ++ uint8 type, len; ++ uint8* value; ++ uint8* tmpbuf; ++ uint16 remainder = (uint16)tlv_hdr_len; ++ uint16 processed = 0; ++ athost_wl_status_info_t* wlfc = NULL; ++ void* entry; ++ ++ if ((dhd == NULL) || (pktbuf == NULL)) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (dhd->proptxstatus_mode != WLFC_ONLY_AMPDU_HOSTREORDER) { ++ if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhd); ++ return WLFC_UNSUPPORTED; ++ } ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ } ++ ++ tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); ++ ++ if (remainder) { ++ while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { ++ type = tmpbuf[processed]; ++ if (type == WLFC_CTL_TYPE_FILLER) { ++ remainder -= 1; ++ processed += 1; ++ continue; ++ } ++ ++ len = tmpbuf[processed + 1]; ++ value = &tmpbuf[processed + 2]; ++ ++ if (remainder < (2 + len)) ++ break; ++ ++ remainder -= 2 + len; ++ processed += 2 + len; ++ entry = NULL; ++ ++ DHD_INFO(("%s():%d type %d remainder %d processed %d\n", ++ __FUNCTION__, __LINE__, type, remainder, processed)); ++ ++ if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) ++ _dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, ++ reorder_info_len); ++ ++ if (wlfc == NULL) { ++ ASSERT(dhd->proptxstatus_mode == WLFC_ONLY_AMPDU_HOSTREORDER); ++ ++ if (type != WLFC_CTL_TYPE_HOST_REORDER_RXPKTS && ++ type != WLFC_CTL_TYPE_TRANS_ID) ++ DHD_INFO(("%s():%d dhd->wlfc_state is NULL yet!" ++ " type %d remainder %d processed %d\n", ++ __FUNCTION__, __LINE__, type, remainder, processed)); ++ continue; ++ } ++ ++ if (type == WLFC_CTL_TYPE_TXSTATUS) { ++ _dhd_wlfc_compressed_txstatus_update(dhd, value, 1, &entry); ++ } else if (type == WLFC_CTL_TYPE_COMP_TXSTATUS) { ++ uint8 compcnt_offset = WLFC_CTL_VALUE_LEN_TXSTATUS; ++ ++ if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) { ++ compcnt_offset += WLFC_CTL_VALUE_LEN_SEQ; ++ } ++ _dhd_wlfc_compressed_txstatus_update(dhd, value, ++ value[compcnt_offset], &entry); ++ } else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) { ++ _dhd_wlfc_fifocreditback_indicate(dhd, value); ++ } else if (type == WLFC_CTL_TYPE_RSSI) { ++ _dhd_wlfc_rssi_indicate(dhd, value); ++ } else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) { ++ _dhd_wlfc_credit_request(dhd, value); ++ } else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) { ++ _dhd_wlfc_packet_request(dhd, value); ++ } else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || ++ (type == WLFC_CTL_TYPE_MAC_CLOSE)) { ++ _dhd_wlfc_psmode_update(dhd, value, type); ++ } else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || ++ (type == WLFC_CTL_TYPE_MACDESC_DEL)) { ++ _dhd_wlfc_mac_table_update(dhd, value, type); ++ } else if (type == WLFC_CTL_TYPE_TRANS_ID) { ++ _dhd_wlfc_dbg_senum_check(dhd, value); ++ } else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || ++ (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { ++ _dhd_wlfc_interface_update(dhd, value, type); ++ } ++ ++#ifndef BCMDBUS ++ if (entry && WLFC_GET_REORDERSUPP(dhd->wlfc_mode)) { ++ /* suppress all packets for this mac entry from bus->txq */ ++ _dhd_wlfc_suppress_txq(dhd, _dhd_wlfc_entrypkt_fn, entry); ++ } ++#endif /* !BCMDBUS */ ++ } /* while */ ++ ++ if (remainder != 0 && wlfc) { ++ /* trouble..., something is not right */ ++ wlfc->stats.tlv_parse_failed++; ++ } ++ } /* if */ ++ ++ if (wlfc) ++ wlfc->stats.dhd_hdrpulls++; ++ ++ dhd_os_wlfc_unblock(dhd); ++ return BCME_OK; ++} ++ ++KERNEL_THREAD_RETURN_TYPE ++dhd_wlfc_transfer_packets(void *data) ++{ ++ dhd_pub_t *dhdp = (dhd_pub_t *)data; ++ int ac, single_ac = 0, rc = BCME_OK; ++ dhd_wlfc_commit_info_t commit_info; ++ athost_wl_status_info_t* ctx; ++ int bus_retry_count = 0; ++ int pkt_send = 0; ++ int pkt_send_per_ac = 0; ++ ++ uint8 tx_map = 0; /* packets (send + in queue), Bitmask for 4 ACs + BC/MC */ ++ uint8 rx_map = 0; /* received packets, Bitmask for 4 ACs + BC/MC */ ++ uint8 packets_map = 0; /* packets in queue, Bitmask for 4 ACs + BC/MC */ ++ bool no_credit = FALSE; ++ ++ int lender; ++ ++#if defined(DHD_WLFC_THREAD) ++ /* wait till someone wakeup me up, will change it at running time */ ++ int wait_msec = msecs_to_jiffies(0xFFFFFFFF); ++#endif /* defined(DHD_WLFC_THREAD) */ ++ ++#if defined(DHD_WLFC_THREAD) ++ while (1) { ++ bus_retry_count = 0; ++ pkt_send = 0; ++ tx_map = 0; ++ rx_map = 0; ++ packets_map = 0; ++ wait_msec = wait_event_interruptible_timeout(dhdp->wlfc_wqhead, ++ dhdp->wlfc_thread_go, wait_msec); ++ if (kthread_should_stop()) { ++ break; ++ } ++ dhdp->wlfc_thread_go = FALSE; ++ ++ dhd_os_wlfc_block(dhdp); ++#endif /* defined(DHD_WLFC_THREAD) */ ++ ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; ++#if defined(DHD_WLFC_THREAD) ++ if (!ctx) ++ goto exit; ++#endif /* defined(DHD_WLFC_THREAD) */ ++ ++ memset(&commit_info, 0, sizeof(commit_info)); ++ ++ /* ++ Commit packets for regular AC traffic. Higher priority first. ++ First, use up FIFO credits available to each AC. Based on distribution ++ and credits left, borrow from other ACs as applicable ++ ++ -NOTE: ++ If the bus between the host and firmware is overwhelmed by the ++ traffic from host, it is possible that higher priority traffic ++ starves the lower priority queue. If that occurs often, we may ++ have to employ weighted round-robin or ucode scheme to avoid ++ low priority packet starvation. ++ */ ++ ++ for (ac = AC_COUNT; ac >= 0; ac--) { ++ if (dhdp->wlfc_rxpkt_chk) { ++ /* check rx packet */ ++ uint32 curr_t = OSL_SYSUPTIME(), delta; ++ ++ delta = curr_t - ctx->rx_timestamp[ac]; ++ if (delta < WLFC_RX_DETECTION_THRESHOLD_MS) { ++ rx_map |= (1 << ac); ++ } ++ } ++ ++ if (ctx->pkt_cnt_per_ac[ac] == 0) { ++ continue; ++ } ++ ++ tx_map |= (1 << ac); ++ single_ac = ac + 1; ++ pkt_send_per_ac = 0; ++ while ((FALSE == dhdp->proptxstatus_txoff) && ++ (pkt_send_per_ac < WLFC_PACKET_BOUND)) { ++ /* packets from delayQ with less priority are fresh and ++ * they'd need header and have no MAC entry ++ */ ++ no_credit = (ctx->FIFO_credit[ac] < 1); ++ if (dhdp->proptxstatus_credit_ignore || ++ ((ac == AC_COUNT) && !ctx->bcmc_credit_supported)) { ++ no_credit = FALSE; ++ } ++ ++ lender = -1; ++#ifdef LIMIT_BORROW ++ if (no_credit && (ac < AC_COUNT) && (tx_map >= rx_map) && ++ dhdp->wlfc_borrow_allowed) { ++ /* try borrow from lower priority */ ++ lender = _dhd_wlfc_borrow_credit(ctx, ac - 1, ac, FALSE); ++ if (lender != -1) { ++ no_credit = FALSE; ++ } ++ } ++#endif ++ commit_info.needs_hdr = 1; ++ commit_info.mac_entry = NULL; ++ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, ++ &(commit_info.ac_fifo_credit_spent), ++ &(commit_info.needs_hdr), ++ &(commit_info.mac_entry), ++ no_credit); ++ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : ++ eWLFC_PKTTYPE_SUPPRESSED; ++ ++ if (commit_info.p == NULL) { ++#ifdef LIMIT_BORROW ++ if (lender != -1 && dhdp->wlfc_borrow_allowed) { ++ _dhd_wlfc_return_credit(ctx, lender, ac); ++ } ++#endif ++ break; ++ } ++ ++ if (!dhdp->proptxstatus_credit_ignore && (lender == -1)) { ++ ASSERT(ctx->FIFO_credit[ac] >= commit_info.ac_fifo_credit_spent); ++ } ++ /* here we can ensure have credit or no credit needed */ ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ ctx->fcommit, ctx->commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ pkt_send++; ++ pkt_send_per_ac++; ++ if (commit_info.ac_fifo_credit_spent && (lender == -1)) { ++ ctx->FIFO_credit[ac]--; ++ } ++#ifdef LIMIT_BORROW ++ else if (!commit_info.ac_fifo_credit_spent && (lender != -1) && ++ dhdp->wlfc_borrow_allowed) { ++ _dhd_wlfc_return_credit(ctx, lender, ac); ++ } ++#endif ++ } else { ++#ifdef LIMIT_BORROW ++ if (lender != -1 && dhdp->wlfc_borrow_allowed) { ++ _dhd_wlfc_return_credit(ctx, lender, ac); ++ } ++#endif ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); ++ goto exit; ++ } ++ } ++ } ++ ++ if (ctx->pkt_cnt_per_ac[ac]) { ++ packets_map |= (1 << ac); ++ } ++ } ++ ++ if ((tx_map == 0) || dhdp->proptxstatus_credit_ignore) { ++ /* nothing send out or remain in queue */ ++ rc = BCME_OK; ++ goto exit; ++ } ++ ++ if (((tx_map & (tx_map - 1)) == 0) && (tx_map >= rx_map)) { ++ /* only one tx ac exist and no higher rx ac */ ++ if ((single_ac == ctx->single_ac) && ctx->allow_credit_borrow) { ++ ac = single_ac - 1; ++ } else { ++ uint32 delta; ++ uint32 curr_t = OSL_SYSUPTIME(); ++ ++ if (single_ac != ctx->single_ac) { ++ /* new single ac traffic (first single ac or different single ac) */ ++ ctx->allow_credit_borrow = 0; ++ ctx->single_ac_timestamp = curr_t; ++ ctx->single_ac = (uint8)single_ac; ++ rc = BCME_OK; ++ goto exit; ++ } ++ /* same ac traffic, check if it lasts enough time */ ++ delta = curr_t - ctx->single_ac_timestamp; ++ ++ if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { ++ /* wait enough time, can borrow now */ ++ ctx->allow_credit_borrow = 1; ++ ac = single_ac - 1; ++ } else { ++ rc = BCME_OK; ++ goto exit; ++ } ++ } ++ } else { ++ /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ ++ ctx->allow_credit_borrow = 0; ++ ctx->single_ac_timestamp = 0; ++ ctx->single_ac = 0; ++ rc = BCME_OK; ++ goto exit; ++ } ++ ++ if (packets_map == 0) { ++ /* nothing to send, skip borrow */ ++ rc = BCME_OK; ++ goto exit; ++ } ++ ++ /* At this point, borrow all credits only for ac */ ++ while (FALSE == dhdp->proptxstatus_txoff) { ++#ifdef LIMIT_BORROW ++ if (dhdp->wlfc_borrow_allowed) { ++ if ((lender = _dhd_wlfc_borrow_credit(ctx, AC_COUNT, ac, TRUE)) == -1) { ++ break; ++ } ++ } ++ else ++ break; ++#endif ++ commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, ++ &(commit_info.ac_fifo_credit_spent), ++ &(commit_info.needs_hdr), ++ &(commit_info.mac_entry), ++ FALSE); ++ if (commit_info.p == NULL) { ++ /* before borrow only one ac exists and now this only ac is empty */ ++#ifdef LIMIT_BORROW ++ _dhd_wlfc_return_credit(ctx, lender, ac); ++#endif ++ break; ++ } ++ ++ commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : ++ eWLFC_PKTTYPE_SUPPRESSED; ++ ++ rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, ++ ctx->fcommit, ctx->commit_ctx); ++ ++ /* Bus commits may fail (e.g. flow control); abort after retries */ ++ if (rc == BCME_OK) { ++ pkt_send++; ++ if (commit_info.ac_fifo_credit_spent) { ++#ifndef LIMIT_BORROW ++ ctx->FIFO_credit[ac]--; ++#endif ++ } else { ++#ifdef LIMIT_BORROW ++ _dhd_wlfc_return_credit(ctx, lender, ac); ++#endif ++ } ++ } else { ++#ifdef LIMIT_BORROW ++ _dhd_wlfc_return_credit(ctx, lender, ac); ++#endif ++ bus_retry_count++; ++ if (bus_retry_count >= BUS_RETRIES) { ++ DHD_ERROR(("%s: bus error %d\n", __FUNCTION__, rc)); ++ goto exit; ++ } ++ } ++ } ++ ++ BCM_REFERENCE(pkt_send); ++ ++exit: ++#if defined(DHD_WLFC_THREAD) ++ dhd_os_wlfc_unblock(dhdp); ++ if (ctx && ctx->pkt_cnt_in_psq && pkt_send) { ++ wait_msec = msecs_to_jiffies(WLFC_THREAD_QUICK_RETRY_WAIT_MS); ++ } else { ++ wait_msec = msecs_to_jiffies(WLFC_THREAD_RETRY_WAIT_MS); ++ } ++ } ++ return 0; ++#else ++ return rc; ++#endif /* defined(DHD_WLFC_THREAD) */ ++} ++ ++/** ++ * Enqueues a transmit packet in the next layer towards the dongle, eg the DBUS layer. Called by ++ * eg dhd_sendpkt(). ++ * @param[in] dhdp Pointer to public DHD structure ++ * @param[in] fcommit Pointer to transmit function of next layer ++ * @param[in] commit_ctx Opaque context used when calling next layer ++ * @param[in] pktbuf Packet to send ++ * @param[in] need_toggle_host_if If TRUE, resets flag ctx->toggle_host_if ++ */ ++int ++dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf, ++ bool need_toggle_host_if) ++{ ++ int rc = BCME_OK; ++ athost_wl_status_info_t* ctx; ++ ++#if defined(DHD_WLFC_THREAD) ++ if (!pktbuf) ++ return BCME_OK; ++#endif /* defined(DHD_WLFC_THREAD) */ ++ ++ if ((dhdp == NULL) || (fcommit == NULL)) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhdp); ++ ++ if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ if (pktbuf) { ++ DHD_PKTTAG_WLFCPKT_SET(PKTTAG(pktbuf), 0); ++ } ++ rc = WLFC_UNSUPPORTED; ++ goto exit; ++ } ++ ++ ctx = (athost_wl_status_info_t*)dhdp->wlfc_state; ++ ++#ifdef BCMDBUS ++ if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { ++ if (pktbuf) { ++ PKTFREE(ctx->osh, pktbuf, TRUE); ++ rc = BCME_OK; ++ } ++ goto exit; ++ } ++#endif /* BCMDBUS */ ++ ++ if (dhdp->proptxstatus_module_ignore) { ++ if (pktbuf) { ++ uint32 htod = 0; ++ WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); ++ _dhd_wlfc_pushheader(ctx, &pktbuf, FALSE, 0, 0, htod, 0, FALSE); ++ if (fcommit(commit_ctx, pktbuf)) { ++ /* free it if failed, otherwise do it in tx complete cb */ ++ PKTFREE(ctx->osh, pktbuf, TRUE); ++ } ++ rc = BCME_OK; ++ } ++ goto exit; ++ } ++ ++ if (pktbuf) { ++ int ac = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); ++ ASSERT(ac <= AC_COUNT); ++ DHD_PKTTAG_WLFCPKT_SET(PKTTAG(pktbuf), 1); ++ /* en-queue the packets to respective queue. */ ++ rc = _dhd_wlfc_enque_delayq(ctx, pktbuf, ac); ++ if (rc) { ++ _dhd_wlfc_prec_drop(ctx->dhdp, (ac << 1), pktbuf, FALSE); ++ } else { ++ ctx->stats.pktin++; ++ ctx->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(pktbuf))][ac]++; ++ } ++ } ++ ++ if (!ctx->fcommit) { ++ ctx->fcommit = fcommit; ++ } else { ++ ASSERT(ctx->fcommit == fcommit); ++ } ++ if (!ctx->commit_ctx) { ++ ctx->commit_ctx = commit_ctx; ++ } else { ++ ASSERT(ctx->commit_ctx == commit_ctx); ++ } ++ ++#if defined(DHD_WLFC_THREAD) ++ _dhd_wlfc_thread_wakeup(dhdp); ++#else ++ dhd_wlfc_transfer_packets(dhdp); ++#endif /* defined(DHD_WLFC_THREAD) */ ++ ++exit: ++ dhd_os_wlfc_unblock(dhdp); ++ return rc; ++} /* dhd_wlfc_commit_packets */ ++ ++/** ++ * Called when the (lower) DBUS layer indicates completion (succesfull or not) of a transmit packet ++ */ ++int ++dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) ++{ ++ athost_wl_status_info_t* wlfc; ++ wlfc_mac_descriptor_t *entry; ++ void* pout = NULL; ++ int rtn = BCME_OK; ++ if ((dhd == NULL) || (txp == NULL)) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ bcm_pkt_validate_chk(txp); ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ rtn = WLFC_UNSUPPORTED; ++ goto EXIT; ++ } ++ ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { ++#ifdef PROP_TXSTATUS_DEBUG ++ wlfc->stats.signal_only_pkts_freed++; ++#endif ++ /* is this a signal-only packet? */ ++ _dhd_wlfc_pullheader(wlfc, txp); ++ PKTFREE(wlfc->osh, txp, TRUE); ++ goto EXIT; ++ } ++ ++ entry = _dhd_wlfc_find_table_entry(wlfc, txp); ++ ASSERT(entry); ++ ++ if (!success || dhd->proptxstatus_txstatus_ignore) { ++ WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", ++ __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp)))); ++ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ _dhd_wlfc_hanger_poppkt(wlfc->hanger, WL_TXSTATUS_GET_HSLOT( ++ DHD_PKTTAG_H2DTAG(PKTTAG(txp))), &pout, TRUE); ++ ASSERT(txp == pout); ++ } ++ ++ /* indicate failure and free the packet */ ++ dhd_txcomplete(dhd, txp, success); ++ ++ /* return the credit, if necessary */ ++ _dhd_wlfc_return_implied_credit(wlfc, txp); ++ ++ if (entry->transit_count) ++ entry->transit_count--; ++ if (entry->suppr_transit_count) ++ entry->suppr_transit_count--; ++ wlfc->pkt_cnt_in_drv[DHD_PKTTAG_IF(PKTTAG(txp))][DHD_PKTTAG_FIFO(PKTTAG(txp))]--; ++ wlfc->stats.pktout++; ++ PKTFREE(wlfc->osh, txp, TRUE); ++ } else { ++ /* bus confirmed pkt went to firmware side */ ++ if (WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ _dhd_wlfc_enque_afq(wlfc, txp); ++ } else { ++ int hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(txp))); ++ _dhd_wlfc_hanger_free_pkt(wlfc, hslot, ++ WLFC_HANGER_PKT_STATE_BUSRETURNED, -1); ++ } ++ } ++ ++ ASSERT(entry->onbus_pkts_count > 0); ++ if (entry->onbus_pkts_count > 0) ++ entry->onbus_pkts_count--; ++ if (entry->suppressed && ++ (!entry->onbus_pkts_count) && ++ (!entry->suppr_transit_count)) ++ entry->suppressed = FALSE; ++EXIT: ++ dhd_os_wlfc_unblock(dhd); ++ return rtn; ++} /* dhd_wlfc_txcomplete */ ++ ++int ++dhd_wlfc_init(dhd_pub_t *dhd) ++{ ++ /* enable all signals & indicate host proptxstatus logic is active */ ++ uint32 tlv, mode, fw_caps; ++ int ret = 0; ++ ++ if (dhd == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ if (dhd->wlfc_enabled) { ++ DHD_ERROR(("%s():%d, Already enabled!\n", __FUNCTION__, __LINE__)); ++ dhd_os_wlfc_unblock(dhd); ++ return BCME_OK; ++ } ++ dhd->wlfc_enabled = TRUE; ++ dhd_os_wlfc_unblock(dhd); ++ ++ tlv = WLFC_FLAGS_RSSI_SIGNALS | ++ WLFC_FLAGS_XONXOFF_SIGNALS | ++ WLFC_FLAGS_CREDIT_STATUS_SIGNALS | ++ WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | ++ WLFC_FLAGS_HOST_RXRERODER_ACTIVE; ++ ++ ++ /* ++ try to enable/disable signaling by sending "tlv" iovar. if that fails, ++ fallback to no flow control? Print a message for now. ++ */ ++ ++ /* enable proptxtstatus signaling by default */ ++ if (!dhd_wl_ioctl_set_intiovar(dhd, "tlv", tlv, WLC_SET_VAR, TRUE, 0)) { ++ /* ++ Leaving the message for now, it should be removed after a while; once ++ the tlv situation is stable. ++ */ ++ DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", ++ dhd->wlfc_enabled?"enabled":"disabled", tlv)); ++ } ++ ++ mode = 0; ++ ++ /* query caps */ ++ ret = dhd_wl_ioctl_get_intiovar(dhd, "wlfc_mode", &fw_caps, WLC_GET_VAR, FALSE, 0); ++ ++ if (!ret) { ++ DHD_ERROR(("%s: query wlfc_mode succeed, fw_caps=0x%x\n", __FUNCTION__, fw_caps)); ++ ++ if (WLFC_IS_OLD_DEF(fw_caps)) { ++#ifdef BCMDBUS ++ mode = WLFC_MODE_HANGER; ++#else ++ /* enable proptxtstatus v2 by default */ ++ mode = WLFC_MODE_AFQ; ++#endif /* BCMDBUS */ ++ } else { ++ WLFC_SET_AFQ(mode, WLFC_GET_AFQ(fw_caps)); ++#ifdef BCMDBUS ++ WLFC_SET_AFQ(mode, 0); ++#endif /* BCMDBUS */ ++ WLFC_SET_REUSESEQ(mode, WLFC_GET_REUSESEQ(fw_caps)); ++ WLFC_SET_REORDERSUPP(mode, WLFC_GET_REORDERSUPP(fw_caps)); ++ } ++ ret = dhd_wl_ioctl_set_intiovar(dhd, "wlfc_mode", mode, WLC_SET_VAR, TRUE, 0); ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ dhd->wlfc_mode = 0; ++ if (ret >= 0) { ++ if (WLFC_IS_OLD_DEF(mode)) { ++ WLFC_SET_AFQ(dhd->wlfc_mode, (mode == WLFC_MODE_AFQ)); ++ } else { ++ dhd->wlfc_mode = mode; ++ } ++ } ++ ++ DHD_ERROR(("dhd_wlfc_init(): wlfc_mode=0x%x, ret=%d\n", dhd->wlfc_mode, ret)); ++#ifdef LIMIT_BORROW ++ dhd->wlfc_borrow_allowed = TRUE; ++#endif ++ dhd_os_wlfc_unblock(dhd); ++ ++ if (dhd->plat_init) ++ dhd->plat_init((void *)dhd); ++ ++ return BCME_OK; ++} /* dhd_wlfc_init */ ++ ++/** AMPDU host reorder specific function */ ++int ++dhd_wlfc_hostreorder_init(dhd_pub_t *dhd) ++{ ++ /* enable only ampdu hostreorder here */ ++ uint32 tlv; ++ ++ if (dhd == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ DHD_TRACE(("%s():%d Enter\n", __FUNCTION__, __LINE__)); ++ ++ tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; ++ ++ /* enable proptxtstatus signaling by default */ ++ if (dhd_wl_ioctl_set_intiovar(dhd, "tlv", tlv, WLC_SET_VAR, TRUE, 0)) { ++ DHD_ERROR(("%s(): failed to enable/disable bdcv2 tlv signaling\n", ++ __FUNCTION__)); ++ } else { ++ /* ++ Leaving the message for now, it should be removed after a while; once ++ the tlv situation is stable. ++ */ ++ DHD_ERROR(("%s(): successful bdcv2 tlv signaling, %d\n", ++ __FUNCTION__, tlv)); ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ dhd->proptxstatus_mode = WLFC_ONLY_AMPDU_HOSTREORDER; ++ dhd_os_wlfc_unblock(dhd); ++ /* terence 20161229: enable ampdu_hostreorder if tlv enable hostreorder */ ++ dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_hostreorder", 1, 0, TRUE); ++ ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) ++{ ++ if (dhd == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhd); ++ return WLFC_UNSUPPORTED; ++ } ++ ++#ifndef BCMDBUS ++ _dhd_wlfc_cleanup_txq(dhd, fn, arg); ++#endif /* !BCMDBUS */ ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** release all packet resources */ ++int ++dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void *arg) ++{ ++ if (dhd == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhd); ++ return WLFC_UNSUPPORTED; ++ } ++ ++ _dhd_wlfc_cleanup(dhd, fn, arg); ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++int ++dhd_wlfc_deinit(dhd_pub_t *dhd) ++{ ++ /* cleanup all psq related resources */ ++ athost_wl_status_info_t* wlfc; ++ uint32 tlv = 0; ++ uint32 hostreorder = 0; ++ ++ if (dhd == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ if (!dhd->wlfc_enabled) { ++ DHD_ERROR(("%s():%d, Already disabled!\n", __FUNCTION__, __LINE__)); ++ dhd_os_wlfc_unblock(dhd); ++ return BCME_OK; ++ } ++ ++ dhd->wlfc_enabled = FALSE; ++ dhd_os_wlfc_unblock(dhd); ++ ++ /* query ampdu hostreorder */ ++ (void) dhd_wl_ioctl_get_intiovar(dhd, "ampdu_hostreorder", ++ &hostreorder, WLC_GET_VAR, FALSE, 0); ++ ++ if (hostreorder) { ++ tlv = WLFC_FLAGS_HOST_RXRERODER_ACTIVE; ++ DHD_ERROR(("%s():%d, maintain HOST RXRERODER flag in tvl\n", ++ __FUNCTION__, __LINE__)); ++ } ++ ++ /* Disable proptxtstatus signaling for deinit */ ++ (void) dhd_wl_ioctl_set_intiovar(dhd, "tlv", tlv, WLC_SET_VAR, TRUE, 0); ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhd); ++ return WLFC_UNSUPPORTED; ++ } ++ ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ ++ _dhd_wlfc_cleanup(dhd, NULL, NULL); ++ ++ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ int i; ++ wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; ++ for (i = 0; i < h->max_items; i++) { ++ if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { ++ _dhd_wlfc_hanger_free_pkt(wlfc, i, ++ WLFC_HANGER_PKT_STATE_COMPLETE, TRUE); ++ } ++ } ++ ++ /* delete hanger */ ++ _dhd_wlfc_hanger_delete(dhd, h); ++ } ++ ++ ++ /* free top structure */ ++ DHD_OS_PREFREE(dhd, dhd->wlfc_state, ++ sizeof(athost_wl_status_info_t)); ++ dhd->wlfc_state = NULL; ++ dhd->proptxstatus_mode = hostreorder ? ++ WLFC_ONLY_AMPDU_HOSTREORDER : WLFC_FCMODE_NONE; ++ ++ DHD_ERROR(("%s: wlfc_mode=0x%x, tlv=%d\n", __FUNCTION__, dhd->wlfc_mode, tlv)); ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ if (dhd->plat_deinit) ++ dhd->plat_deinit((void *)dhd); ++ return BCME_OK; ++} /* dhd_wlfc_init */ ++ ++/** ++ * Called on an interface event (WLC_E_IF) indicated by firmware ++ * @param[in] dhdp Pointer to public DHD structure ++ * @param[in] action eg eWLFC_MAC_ENTRY_ACTION_UPDATE or eWLFC_MAC_ENTRY_ACTION_ADD ++ */ ++int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea) ++{ ++ int rc; ++ ++ if (dhdp == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhdp); ++ ++ if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhdp); ++ return WLFC_UNSUPPORTED; ++ } ++ ++ rc = _dhd_wlfc_interface_entry_update(dhdp->wlfc_state, action, ifid, iftype, ea); ++ ++ dhd_os_wlfc_unblock(dhdp); ++ return rc; ++} ++ ++/** Called eg on receiving a WLC_E_FIFO_CREDIT_MAP event from the dongle */ ++int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data) ++{ ++ int rc; ++ ++ if (dhdp == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhdp); ++ ++ if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhdp); ++ return WLFC_UNSUPPORTED; ++ } ++ ++ rc = _dhd_wlfc_FIFOcreditmap_update(dhdp->wlfc_state, event_data); ++ ++ dhd_os_wlfc_unblock(dhdp); ++ ++ return rc; ++} ++#ifdef LIMIT_BORROW ++int dhd_wlfc_disable_credit_borrow_event(dhd_pub_t *dhdp, uint8* event_data) ++{ ++ if (dhdp == NULL || event_data == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ dhd_os_wlfc_block(dhdp); ++ dhdp->wlfc_borrow_allowed = (bool)(*(uint32 *)event_data); ++ dhd_os_wlfc_unblock(dhdp); ++ ++ return BCME_OK; ++} ++#endif /* LIMIT_BORROW */ ++ ++/** ++ * Called eg on receiving a WLC_E_BCMC_CREDIT_SUPPORT event from the dongle (broadcast/multicast ++ * specific) ++ */ ++int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp) ++{ ++ int rc; ++ ++ if (dhdp == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhdp); ++ ++ if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhdp); ++ return WLFC_UNSUPPORTED; ++ } ++ ++ rc = _dhd_wlfc_BCMCCredit_support_update(dhdp->wlfc_state); ++ ++ dhd_os_wlfc_unblock(dhdp); ++ return rc; ++} ++ ++/** debug specific function */ ++int ++dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) ++{ ++ int i; ++ uint8* ea; ++ athost_wl_status_info_t* wlfc; ++ wlfc_hanger_t* h; ++ wlfc_mac_descriptor_t* mac_table; ++ wlfc_mac_descriptor_t* interfaces; ++ char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; ++ ++ if (!dhdp || !strbuf) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhdp); ++ ++ if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhdp); ++ return WLFC_UNSUPPORTED; ++ } ++ ++ wlfc = (athost_wl_status_info_t*)dhdp->wlfc_state; ++ ++ h = (wlfc_hanger_t*)wlfc->hanger; ++ if (h == NULL) { ++ bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); ++ } ++ ++ mac_table = wlfc->destination_entries.nodes; ++ interfaces = wlfc->destination_entries.interfaces; ++ bcm_bprintf(strbuf, "---- wlfc stats ----\n"); ++ ++ if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) { ++ h = (wlfc_hanger_t*)wlfc->hanger; ++ if (h == NULL) { ++ bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); ++ } else { ++ bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," ++ "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", ++ h->pushed, ++ h->popped, ++ h->failed_to_push, ++ h->failed_to_pop, ++ h->failed_slotfind, ++ (h->pushed - h->popped)); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " ++ "(dq_full,rollback_fail) = (%d,%d,%d,%d), (%d,%d)\n", ++ wlfc->stats.tlv_parse_failed, ++ wlfc->stats.credit_request_failed, ++ wlfc->stats.mac_update_failed, ++ wlfc->stats.psmode_update_failed, ++ wlfc->stats.delayq_full_error, ++ wlfc->stats.rollback_failed); ++ ++ bcm_bprintf(strbuf, "PKTS (init_credit,credit,sent,drop_d,drop_s,outoforder) " ++ "(AC0[%d,%d,%d,%d,%d,%d],AC1[%d,%d,%d,%d,%d,%d],AC2[%d,%d,%d,%d,%d,%d]," ++ "AC3[%d,%d,%d,%d,%d,%d],BC_MC[%d,%d,%d,%d,%d,%d])\n", ++ wlfc->Init_FIFO_credit[0], wlfc->FIFO_credit[0], wlfc->stats.send_pkts[0], ++ wlfc->stats.drop_pkts[0], wlfc->stats.drop_pkts[1], wlfc->stats.ooo_pkts[0], ++ wlfc->Init_FIFO_credit[1], wlfc->FIFO_credit[1], wlfc->stats.send_pkts[1], ++ wlfc->stats.drop_pkts[2], wlfc->stats.drop_pkts[3], wlfc->stats.ooo_pkts[1], ++ wlfc->Init_FIFO_credit[2], wlfc->FIFO_credit[2], wlfc->stats.send_pkts[2], ++ wlfc->stats.drop_pkts[4], wlfc->stats.drop_pkts[5], wlfc->stats.ooo_pkts[2], ++ wlfc->Init_FIFO_credit[3], wlfc->FIFO_credit[3], wlfc->stats.send_pkts[3], ++ wlfc->stats.drop_pkts[6], wlfc->stats.drop_pkts[7], wlfc->stats.ooo_pkts[3], ++ wlfc->Init_FIFO_credit[4], wlfc->FIFO_credit[4], wlfc->stats.send_pkts[4], ++ wlfc->stats.drop_pkts[8], wlfc->stats.drop_pkts[9], wlfc->stats.ooo_pkts[4]); ++ ++ bcm_bprintf(strbuf, "\n"); ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (interfaces[i].occupied) { ++ char* iftype_desc; ++ ++ if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) ++ iftype_desc = "hostif_flow_state[i] == OFF) ++ ? " OFF":" ON")); ++ ++ bcm_bprintf(strbuf, "INTERFACE[%d].PSQ(len,state,credit)," ++ "(trans,supp_trans,onbus)" ++ "= (%d,%s,%d),(%d,%d,%d)\n", ++ i, ++ interfaces[i].psq.len, ++ ((interfaces[i].state == ++ WLFC_STATE_OPEN) ? "OPEN":"CLOSE"), ++ interfaces[i].requested_credit, ++ interfaces[i].transit_count, ++ interfaces[i].suppr_transit_count, ++ interfaces[i].onbus_pkts_count); ++ ++ bcm_bprintf(strbuf, "INTERFACE[%d].PSQ" ++ "(delay0,sup0,afq0),(delay1,sup1,afq1),(delay2,sup2,afq2)," ++ "(delay3,sup3,afq3),(delay4,sup4,afq4) = (%d,%d,%d)," ++ "(%d,%d,%d),(%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n", ++ i, ++ interfaces[i].psq.q[0].len, ++ interfaces[i].psq.q[1].len, ++ interfaces[i].afq.q[0].len, ++ interfaces[i].psq.q[2].len, ++ interfaces[i].psq.q[3].len, ++ interfaces[i].afq.q[1].len, ++ interfaces[i].psq.q[4].len, ++ interfaces[i].psq.q[5].len, ++ interfaces[i].afq.q[2].len, ++ interfaces[i].psq.q[6].len, ++ interfaces[i].psq.q[7].len, ++ interfaces[i].afq.q[3].len, ++ interfaces[i].psq.q[8].len, ++ interfaces[i].psq.q[9].len, ++ interfaces[i].afq.q[4].len); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "\n"); ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (mac_table[i].occupied) { ++ ea = mac_table[i].ea; ++ bcm_bprintf(strbuf, "MAC_table[%d].ea = " ++ "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d \n", i, ++ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], ++ mac_table[i].interface_id); ++ ++ bcm_bprintf(strbuf, "MAC_table[%d].PSQ(len,state,credit)," ++ "(trans,supp_trans,onbus)" ++ "= (%d,%s,%d),(%d,%d,%d)\n", ++ i, ++ mac_table[i].psq.len, ++ ((mac_table[i].state == ++ WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), ++ mac_table[i].requested_credit, ++ mac_table[i].transit_count, ++ mac_table[i].suppr_transit_count, ++ mac_table[i].onbus_pkts_count); ++#ifdef PROP_TXSTATUS_DEBUG ++ bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", ++ i, mac_table[i].opened_ct, mac_table[i].closed_ct); ++#endif ++ bcm_bprintf(strbuf, "MAC_table[%d].PSQ" ++ "(delay0,sup0,afq0),(delay1,sup1,afq1),(delay2,sup2,afq2)," ++ "(delay3,sup3,afq3),(delay4,sup4,afq4) =(%d,%d,%d)," ++ "(%d,%d,%d),(%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n", ++ i, ++ mac_table[i].psq.q[0].len, ++ mac_table[i].psq.q[1].len, ++ mac_table[i].afq.q[0].len, ++ mac_table[i].psq.q[2].len, ++ mac_table[i].psq.q[3].len, ++ mac_table[i].afq.q[1].len, ++ mac_table[i].psq.q[4].len, ++ mac_table[i].psq.q[5].len, ++ mac_table[i].afq.q[2].len, ++ mac_table[i].psq.q[6].len, ++ mac_table[i].psq.q[7].len, ++ mac_table[i].afq.q[3].len, ++ mac_table[i].psq.q[8].len, ++ mac_table[i].psq.q[9].len, ++ mac_table[i].afq.q[4].len); ++ ++ } ++ } ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ { ++ int avg; ++ int moving_avg = 0; ++ int moving_samples; ++ ++ if (wlfc->stats.latency_sample_count) { ++ moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); ++ ++ for (i = 0; i < moving_samples; i++) ++ moving_avg += wlfc->stats.deltas[i]; ++ moving_avg /= moving_samples; ++ ++ avg = (100 * wlfc->stats.total_status_latency) / ++ wlfc->stats.latency_sample_count; ++ bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " ++ "(%d.%d, %03d, %03d)\n", ++ moving_samples, avg/100, (avg - (avg/100)*100), ++ wlfc->stats.latency_most_recent, ++ moving_avg); ++ } ++ } ++ ++ bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " ++ "back = (%d,%d,%d,%d,%d,%d)\n", ++ wlfc->stats.fifo_credits_sent[0], ++ wlfc->stats.fifo_credits_sent[1], ++ wlfc->stats.fifo_credits_sent[2], ++ wlfc->stats.fifo_credits_sent[3], ++ wlfc->stats.fifo_credits_sent[4], ++ wlfc->stats.fifo_credits_sent[5], ++ ++ wlfc->stats.fifo_credits_back[0], ++ wlfc->stats.fifo_credits_back[1], ++ wlfc->stats.fifo_credits_back[2], ++ wlfc->stats.fifo_credits_back[3], ++ wlfc->stats.fifo_credits_back[4], ++ wlfc->stats.fifo_credits_back[5]); ++ { ++ uint32 fifo_cr_sent = 0; ++ uint32 fifo_cr_acked = 0; ++ uint32 request_cr_sent = 0; ++ uint32 request_cr_ack = 0; ++ uint32 bc_mc_cr_ack = 0; ++ ++ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { ++ fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; ++ } ++ ++ for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { ++ fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; ++ } ++ ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (wlfc->destination_entries.nodes[i].occupied) { ++ request_cr_sent += ++ wlfc->destination_entries.nodes[i].dstncredit_sent_packets; ++ } ++ } ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (wlfc->destination_entries.interfaces[i].occupied) { ++ request_cr_sent += ++ wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; ++ } ++ } ++ for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { ++ if (wlfc->destination_entries.nodes[i].occupied) { ++ request_cr_ack += ++ wlfc->destination_entries.nodes[i].dstncredit_acks; ++ } ++ } ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ if (wlfc->destination_entries.interfaces[i].occupied) { ++ request_cr_ack += ++ wlfc->destination_entries.interfaces[i].dstncredit_acks; ++ } ++ } ++ bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," ++ "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", ++ fifo_cr_sent, fifo_cr_acked, ++ request_cr_sent, request_cr_ack, ++ wlfc->destination_entries.other.dstncredit_acks, ++ bc_mc_cr_ack, ++ wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); ++ } ++#endif /* PROP_TXSTATUS_DEBUG */ ++ bcm_bprintf(strbuf, "\n"); ++ bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull,out),(dropped,hdr_only,wlc_tossed)" ++ "(freed,free_err,rollback)) = " ++ "((%d,%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", ++ wlfc->stats.pktin, ++ wlfc->stats.pkt2bus, ++ wlfc->stats.txstatus_in, ++ wlfc->stats.dhd_hdrpulls, ++ wlfc->stats.pktout, ++ ++ wlfc->stats.pktdropped, ++ wlfc->stats.wlfc_header_only_pkt, ++ wlfc->stats.wlc_tossed_pkts, ++ ++ wlfc->stats.pkt_freed, ++ wlfc->stats.pkt_free_err, wlfc->stats.rollback); ++ ++ bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " ++ "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", ++ wlfc->stats.d11_suppress, ++ wlfc->stats.wl_suppress, ++ wlfc->stats.bad_suppress, ++ ++ wlfc->stats.psq_d11sup_enq, ++ wlfc->stats.psq_wlsup_enq, ++ wlfc->stats.psq_hostq_enq, ++ wlfc->stats.mac_handle_notfound, ++ ++ wlfc->stats.psq_d11sup_retx, ++ wlfc->stats.psq_wlsup_retx, ++ wlfc->stats.psq_hostq_retx); ++ ++ bcm_bprintf(strbuf, "wlfc- cleanup(txq,psq,fw) = (%d,%d,%d)\n", ++ wlfc->stats.cleanup_txq_cnt, ++ wlfc->stats.cleanup_psq_cnt, ++ wlfc->stats.cleanup_fw_cnt); ++ ++ bcm_bprintf(strbuf, "wlfc- generic error: %d\n", wlfc->stats.generic_error); ++ ++ for (i = 0; i < WLFC_MAX_IFNUM; i++) { ++ bcm_bprintf(strbuf, "wlfc- if[%d], pkt_cnt_in_q/AC[0-4] = (%d,%d,%d,%d,%d)\n", i, ++ wlfc->pkt_cnt_in_q[i][0], ++ wlfc->pkt_cnt_in_q[i][1], ++ wlfc->pkt_cnt_in_q[i][2], ++ wlfc->pkt_cnt_in_q[i][3], ++ wlfc->pkt_cnt_in_q[i][4]); ++ } ++ bcm_bprintf(strbuf, "\n"); ++ ++ dhd_os_wlfc_unblock(dhdp); ++ return BCME_OK; ++} /* dhd_wlfc_dump */ ++ ++int dhd_wlfc_clear_counts(dhd_pub_t *dhd) ++{ ++ athost_wl_status_info_t* wlfc; ++ wlfc_hanger_t* hanger; ++ ++ if (dhd == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhd); ++ return WLFC_UNSUPPORTED; ++ } ++ ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ ++ memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); ++ ++ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) { ++ hanger = (wlfc_hanger_t*)wlfc->hanger; ++ ++ hanger->pushed = 0; ++ hanger->popped = 0; ++ hanger->failed_slotfind = 0; ++ hanger->failed_to_pop = 0; ++ hanger->failed_to_push = 0; ++ } ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** returns TRUE if flow control is enabled */ ++int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val) ++{ ++ if (!dhd || !val) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ *val = dhd->wlfc_enabled; ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** Called via an IOVAR */ ++int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val) ++{ ++ if (!dhd || !val) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ *val = dhd->wlfc_state ? dhd->proptxstatus_mode : 0; ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** Called via an IOVAR */ ++int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val) ++{ ++ if (!dhd) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (dhd->wlfc_state) { ++ dhd->proptxstatus_mode = val & 0xff; ++ } ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** Called when rx frame is received from the dongle */ ++bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf) ++{ ++ athost_wl_status_info_t* wlfc; ++ bool rc = FALSE; ++ ++ if (dhd == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return FALSE; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhd); ++ return FALSE; ++ } ++ ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ ++ if (PKTLEN(wlfc->osh, pktbuf) == 0) { ++ wlfc->stats.wlfc_header_only_pkt++; ++ rc = TRUE; ++ } ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return rc; ++} ++ ++int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock) ++{ ++ if (dhdp == NULL) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ if (bAcquireLock) { ++ dhd_os_wlfc_block(dhdp); ++ } ++ ++ if (!dhdp->wlfc_state || (dhdp->proptxstatus_mode == WLFC_FCMODE_NONE) || ++ dhdp->proptxstatus_module_ignore) { ++ if (bAcquireLock) { ++ dhd_os_wlfc_unblock(dhdp); ++ } ++ return WLFC_UNSUPPORTED; ++ } ++ ++ if (state != dhdp->proptxstatus_txoff) { ++ dhdp->proptxstatus_txoff = state; ++ } ++ ++ if (bAcquireLock) { ++ dhd_os_wlfc_unblock(dhdp); ++ } ++ ++ return BCME_OK; ++} ++ ++/** Called when eg an rx frame is received from the dongle */ ++int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio) ++{ ++ athost_wl_status_info_t* wlfc; ++ int rx_path_ac = -1; ++ ++ if ((dhd == NULL) || (prio >= NUMPRIO)) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if (!dhd->wlfc_rxpkt_chk) { ++ dhd_os_wlfc_unblock(dhd); ++ return BCME_OK; ++ } ++ ++ if (!dhd->wlfc_state || (dhd->proptxstatus_mode == WLFC_FCMODE_NONE)) { ++ dhd_os_wlfc_unblock(dhd); ++ return WLFC_UNSUPPORTED; ++ } ++ ++ wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; ++ ++ rx_path_ac = prio2fifo[prio]; ++ wlfc->rx_timestamp[rx_path_ac] = OSL_SYSUPTIME(); ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** called via an IOVAR */ ++int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val) ++{ ++ if (!dhd || !val) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ *val = dhd->proptxstatus_module_ignore; ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** called via an IOVAR */ ++int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val) ++{ ++ uint32 tlv = 0; ++ bool bChanged = FALSE; ++ ++ if (!dhd) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ if ((bool)val != dhd->proptxstatus_module_ignore) { ++ dhd->proptxstatus_module_ignore = (val != 0); ++ /* force txstatus_ignore sync with proptxstatus_module_ignore */ ++ dhd->proptxstatus_txstatus_ignore = dhd->proptxstatus_module_ignore; ++ if (FALSE == dhd->proptxstatus_module_ignore) { ++ tlv = WLFC_FLAGS_RSSI_SIGNALS | ++ WLFC_FLAGS_XONXOFF_SIGNALS | ++ WLFC_FLAGS_CREDIT_STATUS_SIGNALS | ++ WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE; ++ } ++ /* always enable host reorder */ ++ tlv |= WLFC_FLAGS_HOST_RXRERODER_ACTIVE; ++ bChanged = TRUE; ++ } ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ if (bChanged) { ++ /* select enable proptxtstatus signaling */ ++ if (dhd_wl_ioctl_set_intiovar(dhd, "tlv", tlv, WLC_SET_VAR, TRUE, 0)) { ++ DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n", ++ __FUNCTION__, tlv)); ++ } else { ++ DHD_ERROR(("%s: successfully set bdcv2 tlv signaling to 0x%x\n", ++ __FUNCTION__, tlv)); ++ } ++ } ++ ++#if defined(DHD_WLFC_THREAD) ++ _dhd_wlfc_thread_wakeup(dhd); ++#endif /* defined(DHD_WLFC_THREAD) */ ++ ++ return BCME_OK; ++} ++ ++/** called via an IOVAR */ ++int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val) ++{ ++ if (!dhd || !val) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ *val = dhd->proptxstatus_credit_ignore; ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** called via an IOVAR */ ++int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val) ++{ ++ if (!dhd) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ dhd->proptxstatus_credit_ignore = (val != 0); ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** called via an IOVAR */ ++int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val) ++{ ++ if (!dhd || !val) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ *val = dhd->proptxstatus_txstatus_ignore; ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** called via an IOVAR */ ++int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val) ++{ ++ if (!dhd) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ dhd->proptxstatus_txstatus_ignore = (val != 0); ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** called via an IOVAR */ ++int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val) ++{ ++ if (!dhd || !val) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ *val = dhd->wlfc_rxpkt_chk; ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++/** called via an IOVAR */ ++int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val) ++{ ++ if (!dhd) { ++ DHD_ERROR(("Error: %s():%d\n", __FUNCTION__, __LINE__)); ++ return BCME_BADARG; ++ } ++ ++ dhd_os_wlfc_block(dhd); ++ ++ dhd->wlfc_rxpkt_chk = (val != 0); ++ ++ dhd_os_wlfc_unblock(dhd); ++ ++ return BCME_OK; ++} ++ ++#endif /* PROP_TXSTATUS */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/module_drivers/drivers/net/wireless/bcmdhd/dhd_wlfc.h +new file mode 100644 +index 000000000..54c6b3b4b +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dhd_wlfc.h +@@ -0,0 +1,562 @@ ++/* ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_wlfc.h 671530 2016-11-22 08:43:33Z $ ++ * ++ */ ++#ifndef __wlfc_host_driver_definitions_h__ ++#define __wlfc_host_driver_definitions_h__ ++ ++ ++/* #define OOO_DEBUG */ ++ ++#define KERNEL_THREAD_RETURN_TYPE int ++ ++typedef int (*f_commitpkt_t)(void* ctx, void* p); ++typedef bool (*f_processpkt_t)(void* p, void* arg); ++ ++#define WLFC_UNSUPPORTED -9999 ++ ++#define WLFC_NO_TRAFFIC -1 ++#define WLFC_MULTI_TRAFFIC 0 ++ ++#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ ++ ++/** 16 bits will provide an absolute max of 65536 slots */ ++#define WLFC_HANGER_MAXITEMS 3072 ++ ++#define WLFC_HANGER_ITEM_STATE_FREE 1 ++#define WLFC_HANGER_ITEM_STATE_INUSE 2 ++#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 ++#define WLFC_HANGER_ITEM_STATE_FLUSHED 4 ++ ++#define WLFC_HANGER_PKT_STATE_TXSTATUS 1 ++#define WLFC_HANGER_PKT_STATE_BUSRETURNED 2 ++#define WLFC_HANGER_PKT_STATE_COMPLETE \ ++ (WLFC_HANGER_PKT_STATE_TXSTATUS | WLFC_HANGER_PKT_STATE_BUSRETURNED) ++ ++typedef enum { ++ Q_TYPE_PSQ, /**< Power Save Queue, contains both delayed and suppressed packets */ ++ Q_TYPE_AFQ /**< At Firmware Queue */ ++} q_type_t; ++ ++typedef enum ewlfc_packet_state { ++ eWLFC_PKTTYPE_NEW, /**< unused in the code (Jan 2015) */ ++ eWLFC_PKTTYPE_DELAYED, /**< packet did not enter wlfc yet */ ++ eWLFC_PKTTYPE_SUPPRESSED, /**< packet entered wlfc and was suppressed by the dongle */ ++ eWLFC_PKTTYPE_MAX ++} ewlfc_packet_state_t; ++ ++typedef enum ewlfc_mac_entry_action { ++ eWLFC_MAC_ENTRY_ACTION_ADD, ++ eWLFC_MAC_ENTRY_ACTION_DEL, ++ eWLFC_MAC_ENTRY_ACTION_UPDATE, ++ eWLFC_MAC_ENTRY_ACTION_MAX ++} ewlfc_mac_entry_action_t; ++ ++typedef struct wlfc_hanger_item { ++ uint8 state; ++ uint8 gen; ++ uint8 pkt_state; /**< bitmask containing eg WLFC_HANGER_PKT_STATE_TXCOMPLETE */ ++ uint8 pkt_txstatus; ++ uint32 identifier; ++ void* pkt; ++#ifdef PROP_TXSTATUS_DEBUG ++ uint32 push_time; ++#endif ++ struct wlfc_hanger_item *next; ++} wlfc_hanger_item_t; ++ ++/** hanger contains packets that have been posted by the dhd to the dongle and are expected back */ ++typedef struct wlfc_hanger { ++ int max_items; ++ uint32 pushed; ++ uint32 popped; ++ uint32 failed_to_push; ++ uint32 failed_to_pop; ++ uint32 failed_slotfind; ++ uint32 slot_pos; ++ wlfc_hanger_item_t items[1]; ++} wlfc_hanger_t; ++ ++#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ ++ sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t))) ++ ++#define WLFC_STATE_OPEN 1 /**< remote MAC is able to receive packets */ ++#define WLFC_STATE_CLOSE 2 /**< remote MAC is in power save mode */ ++ ++#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /**< 2 for each AC traffic and bc/mc */ ++#define WLFC_AFQ_PREC_COUNT (AC_COUNT + 1) ++ ++#define WLFC_PSQ_LEN (4096 * 8) ++ ++#ifdef BCMDBUS ++#define WLFC_FLOWCONTROL_HIWATER 512 ++#define WLFC_FLOWCONTROL_LOWATER (WLFC_FLOWCONTROL_HIWATER / 4) ++#else ++#define WLFC_FLOWCONTROL_HIWATER ((4096 * 8) - 256) ++#define WLFC_FLOWCONTROL_LOWATER 256 ++#endif ++ ++#if (WLFC_FLOWCONTROL_HIWATER >= (WLFC_PSQ_LEN - 256)) ++#undef WLFC_FLOWCONTROL_HIWATER ++#define WLFC_FLOWCONTROL_HIWATER (WLFC_PSQ_LEN - 256) ++#undef WLFC_FLOWCONTROL_LOWATER ++#define WLFC_FLOWCONTROL_LOWATER (WLFC_FLOWCONTROL_HIWATER / 4) ++#endif ++ ++#define WLFC_LOG_BUF_SIZE (1024*1024) ++ ++/** Properties related to a remote MAC entity */ ++typedef struct wlfc_mac_descriptor { ++ uint8 occupied; /**< if 0, this descriptor is unused and thus can be (re)used */ ++ uint8 interface_id; ++ uint8 iftype; /**< eg WLC_E_IF_ROLE_STA */ ++ uint8 state; /**< eg WLFC_STATE_OPEN */ ++ uint8 ac_bitmap; /**< automatic power save delivery (APSD) */ ++ uint8 requested_credit; ++ uint8 requested_packet; /**< unit: [number of packets] */ ++ uint8 ea[ETHER_ADDR_LEN]; ++ ++ /** maintain (MAC,AC) based seq count for packets going to the device. As well as bc/mc. */ ++ uint8 seq[AC_COUNT + 1]; ++ uint8 generation; /**< toggles between 0 and 1 */ ++ struct pktq psq; /**< contains both 'delayed' and 'suppressed' packets */ ++ /** packets at firmware queue */ ++ struct pktq afq; ++ /** The AC pending bitmap that was reported to the fw at last change */ ++ uint8 traffic_lastreported_bmp; ++ /** The new AC pending bitmap */ ++ uint8 traffic_pending_bmp; ++ /** 1= send on next opportunity */ ++ uint8 send_tim_signal; ++ uint8 mac_handle; /**< mac handles are assigned by the dongle */ ++ /** Number of packets at dongle for this entry. */ ++ int transit_count; ++ /** Number of suppression to wait before evict from delayQ */ ++ int suppr_transit_count; ++ /** pkt sent to bus but no bus TX complete yet */ ++ int onbus_pkts_count; ++ /** flag. TRUE when remote MAC is in suppressed state */ ++ uint8 suppressed; ++ ++ ++#ifdef PROP_TXSTATUS_DEBUG ++ uint32 dstncredit_sent_packets; ++ uint32 dstncredit_acks; ++ uint32 opened_ct; ++ uint32 closed_ct; ++#endif ++ struct wlfc_mac_descriptor* prev; ++ struct wlfc_mac_descriptor* next; ++} wlfc_mac_descriptor_t; ++ ++/** A 'commit' is the hand over of a packet from the host OS layer to the layer below (eg DBUS) */ ++typedef struct dhd_wlfc_commit_info { ++ uint8 needs_hdr; ++ uint8 ac_fifo_credit_spent; ++ ewlfc_packet_state_t pkt_type; ++ wlfc_mac_descriptor_t* mac_entry; ++ void* p; ++} dhd_wlfc_commit_info_t; ++ ++#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\ ++ entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0) ++ ++#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++ ++#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)] ++ ++typedef struct athost_wl_stat_counters { ++ uint32 pktin; ++ uint32 pktout; ++ uint32 pkt2bus; ++ uint32 pktdropped; ++ uint32 tlv_parse_failed; ++ uint32 rollback; ++ uint32 rollback_failed; ++ uint32 delayq_full_error; ++ uint32 credit_request_failed; ++ uint32 packet_request_failed; ++ uint32 mac_update_failed; ++ uint32 psmode_update_failed; ++ uint32 interface_update_failed; ++ uint32 wlfc_header_only_pkt; ++ uint32 txstatus_in; ++ uint32 d11_suppress; ++ uint32 wl_suppress; ++ uint32 bad_suppress; ++ uint32 pkt_freed; ++ uint32 pkt_free_err; ++ uint32 psq_wlsup_retx; ++ uint32 psq_wlsup_enq; ++ uint32 psq_d11sup_retx; ++ uint32 psq_d11sup_enq; ++ uint32 psq_hostq_retx; ++ uint32 psq_hostq_enq; ++ uint32 mac_handle_notfound; ++ uint32 wlc_tossed_pkts; ++ uint32 dhd_hdrpulls; ++ uint32 generic_error; ++ /* an extra one for bc/mc traffic */ ++ uint32 send_pkts[AC_COUNT + 1]; ++ uint32 drop_pkts[WLFC_PSQ_PREC_COUNT]; ++ uint32 ooo_pkts[AC_COUNT + 1]; ++#ifdef PROP_TXSTATUS_DEBUG ++ /** all pkt2bus -> txstatus latency accumulated */ ++ uint32 latency_sample_count; ++ uint32 total_status_latency; ++ uint32 latency_most_recent; ++ int idx_delta; ++ uint32 deltas[10]; ++ uint32 fifo_credits_sent[6]; ++ uint32 fifo_credits_back[6]; ++ uint32 dropped_qfull[6]; ++ uint32 signal_only_pkts_sent; ++ uint32 signal_only_pkts_freed; ++#endif ++ uint32 cleanup_txq_cnt; ++ uint32 cleanup_psq_cnt; ++ uint32 cleanup_fw_cnt; ++} athost_wl_stat_counters_t; ++ ++#ifdef PROP_TXSTATUS_DEBUG ++#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \ ++ (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0) ++#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \ ++ (ctx)->stats.fifo_credits_back[(ac)]++;} while (0) ++#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \ ++ (ctx)->stats.dropped_qfull[(ac)]++;} while (0) ++#else ++#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0) ++#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0) ++#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0) ++#endif ++#define WLFC_PACKET_BOUND 10 ++#define WLFC_FCMODE_NONE 0 ++#define WLFC_FCMODE_IMPLIED_CREDIT 1 ++#define WLFC_FCMODE_EXPLICIT_CREDIT 2 ++#define WLFC_ONLY_AMPDU_HOSTREORDER 3 ++ ++/** Reserved credits ratio when borrowed by hihger priority */ ++#define WLFC_BORROW_LIMIT_RATIO 4 ++ ++/** How long to defer borrowing in milliseconds */ ++#define WLFC_BORROW_DEFER_PERIOD_MS 100 ++ ++/** How long to defer flow control in milliseconds */ ++#define WLFC_FC_DEFER_PERIOD_MS 200 ++ ++/** How long to detect occurance per AC in miliseconds */ ++#define WLFC_RX_DETECTION_THRESHOLD_MS 100 ++ ++/** Mask to represent available ACs (note: BC/MC is ignored) */ ++#define WLFC_AC_MASK 0xF ++ ++/** flow control specific information, only 1 instance during driver lifetime */ ++typedef struct athost_wl_status_info { ++ uint8 last_seqid_to_wlc; ++ ++ /** OSL handle */ ++ osl_t *osh; ++ /** dhd public struct pointer */ ++ void *dhdp; ++ ++ f_commitpkt_t fcommit; ++ void* commit_ctx; ++ ++ /** statistics */ ++ athost_wl_stat_counters_t stats; ++ ++ /** incremented on eg receiving a credit map event from the dongle */ ++ int Init_FIFO_credit[AC_COUNT + 2]; ++ /** the additional ones are for bc/mc and ATIM FIFO */ ++ int FIFO_credit[AC_COUNT + 2]; ++ /** Credit borrow counts for each FIFO from each of the other FIFOs */ ++ int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2]; ++ ++ /** packet hanger and MAC->handle lookup table */ ++ void *hanger; ++ ++ struct { ++ /** table for individual nodes */ ++ wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE]; ++ /** table for interfaces */ ++ wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM]; ++ /* OS may send packets to unknown (unassociated) destinations */ ++ /** A place holder for bc/mc and packets to unknown destinations */ ++ wlfc_mac_descriptor_t other; ++ } destination_entries; ++ ++ wlfc_mac_descriptor_t *active_entry_head; /**< a chain of MAC descriptors */ ++ int active_entry_count; ++ ++ wlfc_mac_descriptor_t *requested_entry[WLFC_MAC_DESC_TABLE_SIZE]; ++ int requested_entry_count; ++ ++ /* pkt counts for each interface and ac */ ++ int pkt_cnt_in_q[WLFC_MAX_IFNUM][AC_COUNT+1]; ++ int pkt_cnt_per_ac[AC_COUNT+1]; ++ int pkt_cnt_in_drv[WLFC_MAX_IFNUM][AC_COUNT+1]; ++ int pkt_cnt_in_psq; ++ uint8 allow_fc; /**< Boolean */ ++ uint32 fc_defer_timestamp; ++ uint32 rx_timestamp[AC_COUNT+1]; ++ ++ /** ON/OFF state for flow control to the host network interface */ ++ uint8 hostif_flow_state[WLFC_MAX_IFNUM]; ++ uint8 host_ifidx; ++ ++ /** to flow control an OS interface */ ++ uint8 toggle_host_if; ++ ++ /** To borrow credits */ ++ uint8 allow_credit_borrow; ++ ++ /** ac number for the first single ac traffic */ ++ uint8 single_ac; ++ ++ /** Timestamp for the first single ac traffic */ ++ uint32 single_ac_timestamp; ++ ++ bool bcmc_credit_supported; ++ ++} athost_wl_status_info_t; ++ ++/** Please be mindful that total pkttag space is 32 octets only */ ++typedef struct dhd_pkttag { ++ ++#ifdef BCM_OBJECT_TRACE ++ /* if use this field, keep it at the first 4 bytes */ ++ uint32 sn; ++#endif /* BCM_OBJECT_TRACE */ ++ ++ /** ++ b[15] - 1 = wlfc packet ++ b[14:13] - encryption exemption ++ b[12 ] - 1 = event channel ++ b[11 ] - 1 = this packet was sent in response to one time packet request, ++ do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. ++ b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] ++ b[9 ] - 1 = packet is host->firmware (transmit direction) ++ - 0 = packet received from firmware (firmware->host) ++ b[8 ] - 1 = packet was sent due to credit_request (pspoll), ++ packet does not count against FIFO credit. ++ - 0 = normal transaction, packet counts against FIFO credit ++ b[7 ] - 1 = AP, 0 = STA ++ b[6:4] - AC FIFO number ++ b[3:0] - interface index ++ */ ++ uint16 if_flags; ++ ++ /** ++ * destination MAC address for this packet so that not every module needs to open the packet ++ * to find this ++ */ ++ uint8 dstn_ether[ETHER_ADDR_LEN]; ++ ++ /** This 32-bit goes from host to device for every packet. */ ++ uint32 htod_tag; ++ ++ /** This 16-bit is original d11seq number for every suppressed packet. */ ++ uint16 htod_seq; ++ ++ /** This address is mac entry for every packet. */ ++ void *entry; ++ ++ /** bus specific stuff */ ++ union { ++ struct { ++ void *stuff; ++ uint32 thing1; ++ uint32 thing2; ++ } sd; ++ ++ struct { ++ void *bus; ++ void *urb; ++ } usb; ++ } bus_specific; ++} dhd_pkttag_t; ++ ++#define DHD_PKTTAG_WLFCPKT_MASK 0x1 ++#define DHD_PKTTAG_WLFCPKT_SHIFT 15 ++#define DHD_PKTTAG_WLFCPKT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_WLFCPKT_MASK << DHD_PKTTAG_WLFCPKT_SHIFT)) | \ ++ (((value) & DHD_PKTTAG_WLFCPKT_MASK) << DHD_PKTTAG_WLFCPKT_SHIFT) ++#define DHD_PKTTAG_WLFCPKT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_WLFCPKT_SHIFT) & DHD_PKTTAG_WLFCPKT_MASK) ++ ++#define DHD_PKTTAG_EXEMPT_MASK 0x3 ++#define DHD_PKTTAG_EXEMPT_SHIFT 13 ++#define DHD_PKTTAG_EXEMPT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_EXEMPT_MASK << DHD_PKTTAG_EXEMPT_SHIFT)) | \ ++ (((value) & DHD_PKTTAG_EXEMPT_MASK) << DHD_PKTTAG_EXEMPT_SHIFT) ++#define DHD_PKTTAG_EXEMPT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_EXEMPT_SHIFT) & DHD_PKTTAG_EXEMPT_MASK) ++ ++#define DHD_PKTTAG_EVENT_MASK 0x1 ++#define DHD_PKTTAG_EVENT_SHIFT 12 ++#define DHD_PKTTAG_SETEVENT(tag, event) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_EVENT_MASK << DHD_PKTTAG_EVENT_SHIFT)) | \ ++ (((event) & DHD_PKTTAG_EVENT_MASK) << DHD_PKTTAG_EVENT_SHIFT) ++#define DHD_PKTTAG_EVENT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_EVENT_SHIFT) & DHD_PKTTAG_EVENT_MASK) ++ ++#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 ++#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 ++#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \ ++ (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) ++#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) ++ ++#define DHD_PKTTAG_SIGNALONLY_MASK 0x1 ++#define DHD_PKTTAG_SIGNALONLY_SHIFT 10 ++#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \ ++ (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT) ++#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK) ++ ++#define DHD_PKTTAG_PKTDIR_MASK 0x1 ++#define DHD_PKTTAG_PKTDIR_SHIFT 9 ++#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \ ++ (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT) ++#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK) ++ ++#define DHD_PKTTAG_CREDITCHECK_MASK 0x1 ++#define DHD_PKTTAG_CREDITCHECK_SHIFT 8 ++#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \ ++ (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT) ++#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK) ++ ++#define DHD_PKTTAG_IFTYPE_MASK 0x1 ++#define DHD_PKTTAG_IFTYPE_SHIFT 7 ++#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & \ ++ ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \ ++ (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT) ++#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK) ++ ++#define DHD_PKTTAG_FIFO_MASK 0x7 ++#define DHD_PKTTAG_FIFO_SHIFT 4 ++#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \ ++ (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT) ++#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK) ++ ++#define DHD_PKTTAG_IF_MASK 0xf ++#define DHD_PKTTAG_IF_SHIFT 0 ++#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \ ++ (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_IF_MASK << DHD_PKTTAG_IF_SHIFT)) | \ ++ (((if) & DHD_PKTTAG_IF_MASK) << DHD_PKTTAG_IF_SHIFT) ++#define DHD_PKTTAG_IF(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ ++ DHD_PKTTAG_IF_SHIFT) & DHD_PKTTAG_IF_MASK) ++ ++#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ ++ (dstn_MAC_ea), ETHER_ADDR_LEN) ++#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether ++ ++#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue) ++#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag) ++ ++#define DHD_PKTTAG_SET_H2DSEQ(tag, seq) ((dhd_pkttag_t*)(tag))->htod_seq = (seq) ++#define DHD_PKTTAG_H2DSEQ(tag) (((dhd_pkttag_t*)(tag))->htod_seq) ++ ++#define DHD_PKTTAG_SET_ENTRY(tag, entry) ((dhd_pkttag_t*)(tag))->entry = (entry) ++#define DHD_PKTTAG_ENTRY(tag) (((dhd_pkttag_t*)(tag))->entry) ++ ++#define PSQ_SUP_IDX(x) (x * 2 + 1) ++#define PSQ_DLY_IDX(x) (x * 2) ++ ++#ifdef PROP_TXSTATUS_DEBUG ++#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) ++#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0) ++#else ++#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0) ++#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) ++#endif ++ ++#ifdef BCM_OBJECT_TRACE ++#define DHD_PKTTAG_SET_SN(tag, val) ((dhd_pkttag_t*)(tag))->sn = (val) ++#define DHD_PKTTAG_SN(tag) (((dhd_pkttag_t*)(tag))->sn) ++#endif /* BCM_OBJECT_TRACE */ ++ ++/* public functions */ ++int dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, ++ uchar *reorder_info_buf, uint *reorder_info_len); ++KERNEL_THREAD_RETURN_TYPE dhd_wlfc_transfer_packets(void *data); ++int dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, ++ void* commit_ctx, void *pktbuf, bool need_toggle_host_if); ++int dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); ++int dhd_wlfc_init(dhd_pub_t *dhd); ++#ifdef SUPPORT_P2P_GO_PS ++int dhd_wlfc_suspend(dhd_pub_t *dhd); ++int dhd_wlfc_resume(dhd_pub_t *dhd); ++#endif /* SUPPORT_P2P_GO_PS */ ++int dhd_wlfc_hostreorder_init(dhd_pub_t *dhd); ++int dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg); ++int dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void* arg); ++int dhd_wlfc_deinit(dhd_pub_t *dhd); ++int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea); ++int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data); ++#ifdef LIMIT_BORROW ++int dhd_wlfc_disable_credit_borrow_event(dhd_pub_t *dhdp, uint8* event_data); ++#endif /* LIMIT_BORROW */ ++int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp); ++int dhd_wlfc_enable(dhd_pub_t *dhdp); ++int dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); ++int dhd_wlfc_clear_counts(dhd_pub_t *dhd); ++int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val); ++int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val); ++int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val); ++bool dhd_wlfc_is_supported(dhd_pub_t *dhd); ++bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf); ++int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock); ++int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio); ++ ++int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val); ++int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val); ++int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val); ++int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val); ++int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val); ++int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val); ++ ++int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val); ++int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val); ++ ++#endif /* __wlfc_host_driver_definitions_h__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dngl_stats.h b/module_drivers/drivers/net/wireless/bcmdhd/dngl_stats.h +new file mode 100644 +index 000000000..b995ec5b0 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dngl_stats.h +@@ -0,0 +1,383 @@ ++/* ++ * Common stats definitions for clients of dongle ++ * ports ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dngl_stats.h 681171 2017-01-25 05:27:08Z $ ++ */ ++ ++#ifndef _dngl_stats_h_ ++#define _dngl_stats_h_ ++ ++#include ++#include <802.11.h> ++ ++typedef struct { ++ unsigned long rx_packets; /* total packets received */ ++ unsigned long tx_packets; /* total packets transmitted */ ++ unsigned long rx_bytes; /* total bytes received */ ++ unsigned long tx_bytes; /* total bytes transmitted */ ++ unsigned long rx_errors; /* bad packets received */ ++ unsigned long tx_errors; /* packet transmit problems */ ++ unsigned long rx_dropped; /* packets dropped by dongle */ ++ unsigned long tx_dropped; /* packets dropped by dongle */ ++ unsigned long multicast; /* multicast packets received */ ++} dngl_stats_t; ++ ++typedef int32 wifi_radio; ++typedef int32 wifi_channel; ++typedef int32 wifi_rssi; ++typedef struct { uint16 version; uint16 length; } ver_len; ++ ++typedef enum wifi_channel_width { ++ WIFI_CHAN_WIDTH_20 = 0, ++ WIFI_CHAN_WIDTH_40 = 1, ++ WIFI_CHAN_WIDTH_80 = 2, ++ WIFI_CHAN_WIDTH_160 = 3, ++ WIFI_CHAN_WIDTH_80P80 = 4, ++ WIFI_CHAN_WIDTH_5 = 5, ++ WIFI_CHAN_WIDTH_10 = 6, ++ WIFI_CHAN_WIDTH_INVALID = -1 ++} wifi_channel_width_t; ++ ++typedef enum { ++ WIFI_DISCONNECTED = 0, ++ WIFI_AUTHENTICATING = 1, ++ WIFI_ASSOCIATING = 2, ++ WIFI_ASSOCIATED = 3, ++ WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ ++ WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ ++} wifi_connection_state; ++ ++typedef enum { ++ WIFI_ROAMING_IDLE = 0, ++ WIFI_ROAMING_ACTIVE = 1 ++} wifi_roam_state; ++ ++typedef enum { ++ WIFI_INTERFACE_STA = 0, ++ WIFI_INTERFACE_SOFTAP = 1, ++ WIFI_INTERFACE_IBSS = 2, ++ WIFI_INTERFACE_P2P_CLIENT = 3, ++ WIFI_INTERFACE_P2P_GO = 4, ++ WIFI_INTERFACE_NAN = 5, ++ WIFI_INTERFACE_MESH = 6 ++} wifi_interface_mode; ++ ++#define WIFI_CAPABILITY_QOS 0x00000001 /* set for QOS association */ ++#define WIFI_CAPABILITY_PROTECTED 0x00000002 /* set for protected association (802.11 ++ * beacon frame control protected bit set) ++ */ ++#define WIFI_CAPABILITY_INTERWORKING 0x00000004 /* set if 802.11 Extended Capabilities ++ * element interworking bit is set ++ */ ++#define WIFI_CAPABILITY_HS20 0x00000008 /* set for HS20 association */ ++#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 /* set is 802.11 Extended Capabilities ++ * element UTF-8 SSID bit is set ++ */ ++#define WIFI_CAPABILITY_COUNTRY 0x00000020 /* set is 802.11 Country Element is present */ ++#define PACK_ATTRIBUTE __attribute__ ((packed)) ++typedef struct { ++ wifi_interface_mode mode; /* interface mode */ ++ uint8 mac_addr[6]; /* interface mac address (self) */ ++ wifi_connection_state state; /* connection state (valid for STA, CLI only) */ ++ wifi_roam_state roaming; /* roaming state */ ++ uint32 capabilities; /* WIFI_CAPABILITY_XXX (self) */ ++ uint8 ssid[DOT11_MAX_SSID_LEN+1]; /* null terminated SSID */ ++ uint8 bssid[ETHER_ADDR_LEN]; /* bssid */ ++ uint8 ap_country_str[3]; /* country string advertised by AP */ ++ uint8 country_str[3]; /* country string for this association */ ++} wifi_interface_info; ++ ++typedef wifi_interface_info *wifi_interface_handle; ++ ++/* channel information */ ++typedef struct { ++ wifi_channel_width_t width; /* channel width (20, 40, 80, 80+80, 160) */ ++ wifi_channel center_freq; /* primary 20 MHz channel */ ++ wifi_channel center_freq0; /* center frequency (MHz) first segment */ ++ wifi_channel center_freq1; /* center frequency (MHz) second segment */ ++} wifi_channel_info; ++ ++/* wifi rate */ ++typedef struct { ++ uint32 preamble; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ ++ uint32 nss; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ ++ uint32 bw; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ ++ uint32 rateMcsIdx; /* OFDM/CCK rate code would be as per ieee std ++ * in the units of 0.5mbps ++ */ ++ /* HT/VHT it would be mcs index */ ++ uint32 reserved; /* reserved */ ++ uint32 bitrate; /* units of 100 Kbps */ ++} wifi_rate; ++ ++typedef struct { ++ uint32 preamble :3; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ ++ uint32 nss :2; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ ++ uint32 bw :3; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ ++ uint32 rateMcsIdx :8; /* OFDM/CCK rate code would be as per ieee std ++ * in the units of 0.5mbps HT/VHT it would be ++ * mcs index ++ */ ++ uint32 reserved :16; /* reserved */ ++ uint32 bitrate; /* units of 100 Kbps */ ++} wifi_rate_v1; ++ ++/* channel statistics */ ++typedef struct { ++ wifi_channel_info channel; /* channel */ ++ uint32 on_time; /* msecs the radio is awake (32 bits number ++ * accruing over time) ++ */ ++ uint32 cca_busy_time; /* msecs the CCA register is busy (32 bits number ++ * accruing over time) ++ */ ++} wifi_channel_stat; ++ ++/* radio statistics */ ++typedef struct { ++ struct { ++ uint16 version; ++ uint16 length; ++ }; ++ wifi_radio radio; /* wifi radio (if multiple radio supported) */ ++ uint32 on_time; /* msecs the radio is awake (32 bits number ++ * accruing over time) ++ */ ++ uint32 tx_time; /* msecs the radio is transmitting (32 bits ++ * number accruing over time) ++ */ ++ uint32 rx_time; /* msecs the radio is in active receive (32 bits ++ * number accruing over time) ++ */ ++ uint32 on_time_scan; /* msecs the radio is awake due to all scan (32 bits ++ * number accruing over time) ++ */ ++ uint32 on_time_nbd; /* msecs the radio is awake due to NAN (32 bits ++ * number accruing over time) ++ */ ++ uint32 on_time_gscan; /* msecs the radio is awake due to G?scan (32 bits ++ * number accruing over time) ++ */ ++ uint32 on_time_roam_scan; /* msecs the radio is awake due to roam?scan (32 bits ++ * number accruing over time) ++ */ ++ uint32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan (32 bits ++ * number accruing over time) ++ */ ++ uint32 on_time_hs20; /* msecs the radio is awake due to HS2.0 scans and ++ * GAS exchange (32 bits number accruing over time) ++ */ ++ uint32 num_channels; /* number of channels */ ++ wifi_channel_stat channels[1]; /* channel statistics */ ++} wifi_radio_stat; ++ ++typedef struct { ++ wifi_radio radio; ++ uint32 on_time; ++ uint32 tx_time; ++ uint32 rx_time; ++ uint32 on_time_scan; ++ uint32 on_time_nbd; ++ uint32 on_time_gscan; ++ uint32 on_time_roam_scan; ++ uint32 on_time_pno_scan; ++ uint32 on_time_hs20; ++ uint32 num_channels; ++} wifi_radio_stat_h; ++ ++/* per rate statistics */ ++typedef struct { ++ wifi_rate_v1 rate; /* rate information */ ++ uint32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ ++ uint32 rx_mpdu; /* number of received data pkts */ ++ uint32 mpdu_lost; /* number of data packet losses (no ACK) */ ++ uint32 retries; /* total number of data pkt retries */ ++ uint32 retries_short; /* number of short data pkt retries */ ++ uint32 retries_long; /* number of long data pkt retries */ ++} wifi_rate_stat_v1; ++ ++typedef struct { ++ uint16 version; ++ uint16 length; ++ uint32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */ ++ uint32 rx_mpdu; /* number of received data pkts */ ++ uint32 mpdu_lost; /* number of data packet losses (no ACK) */ ++ uint32 retries; /* total number of data pkt retries */ ++ uint32 retries_short; /* number of short data pkt retries */ ++ uint32 retries_long; /* number of long data pkt retries */ ++ wifi_rate rate; ++} wifi_rate_stat; ++ ++/* access categories */ ++typedef enum { ++ WIFI_AC_VO = 0, ++ WIFI_AC_VI = 1, ++ WIFI_AC_BE = 2, ++ WIFI_AC_BK = 3, ++ WIFI_AC_MAX = 4 ++} wifi_traffic_ac; ++ ++/* wifi peer type */ ++typedef enum ++{ ++ WIFI_PEER_STA, ++ WIFI_PEER_AP, ++ WIFI_PEER_P2P_GO, ++ WIFI_PEER_P2P_CLIENT, ++ WIFI_PEER_NAN, ++ WIFI_PEER_TDLS, ++ WIFI_PEER_INVALID ++} wifi_peer_type; ++ ++/* per peer statistics */ ++typedef struct { ++ wifi_peer_type type; /* peer type (AP, TDLS, GO etc.) */ ++ uint8 peer_mac_address[6]; /* mac address */ ++ uint32 capabilities; /* peer WIFI_CAPABILITY_XXX */ ++ uint32 num_rate; /* number of rates */ ++ wifi_rate_stat rate_stats[1]; /* per rate statistics, number of entries = num_rate */ ++} wifi_peer_info; ++ ++/* per access category statistics */ ++typedef struct { ++ wifi_traffic_ac ac; /* access category (VI, VO, BE, BK) */ ++ uint32 tx_mpdu; /* number of successfully transmitted unicast data pkts ++ * (ACK rcvd) ++ */ ++ uint32 rx_mpdu; /* number of received unicast mpdus */ ++ uint32 tx_mcast; /* number of succesfully transmitted multicast ++ * data packets ++ */ ++ /* STA case: implies ACK received from AP for the ++ * unicast packet in which mcast pkt was sent ++ */ ++ uint32 rx_mcast; /* number of received multicast data packets */ ++ uint32 rx_ampdu; /* number of received unicast a-mpdus */ ++ uint32 tx_ampdu; /* number of transmitted unicast a-mpdus */ ++ uint32 mpdu_lost; /* number of data pkt losses (no ACK) */ ++ uint32 retries; /* total number of data pkt retries */ ++ uint32 retries_short; /* number of short data pkt retries */ ++ uint32 retries_long; /* number of long data pkt retries */ ++ uint32 contention_time_min; /* data pkt min contention time (usecs) */ ++ uint32 contention_time_max; /* data pkt max contention time (usecs) */ ++ uint32 contention_time_avg; /* data pkt avg contention time (usecs) */ ++ uint32 contention_num_samples; /* num of data pkts used for contention statistics */ ++} wifi_wmm_ac_stat; ++ ++/* interface statistics */ ++typedef struct { ++ wifi_interface_handle iface; /* wifi interface */ ++ wifi_interface_info info; /* current state of the interface */ ++ uint32 beacon_rx; /* access point beacon received count from ++ * connected AP ++ */ ++ uint64 average_tsf_offset; /* average beacon offset encountered (beacon_TSF - TBTT) ++ * The average_tsf_offset field is used so as to calculate ++ * the typical beacon contention time on the channel as well ++ * may be used to debug beacon synchronization and related ++ * power consumption issue ++ */ ++ uint32 leaky_ap_detected; /* indicate that this AP ++ * typically leaks packets beyond ++ * the driver guard time. ++ */ ++ uint32 leaky_ap_avg_num_frames_leaked; /* average number of frame leaked by AP after ++ * frame with PM bit set was ACK'ed by AP ++ */ ++ uint32 leaky_ap_guard_time; /* guard time currently in force ++ * (when implementing IEEE power management ++ * based on frame control PM bit), How long ++ * driver waits before shutting down the radio and after ++ * receiving an ACK for a data frame with PM bit set) ++ */ ++ uint32 mgmt_rx; /* access point mgmt frames received count from ++ * connected AP (including Beacon) ++ */ ++ uint32 mgmt_action_rx; /* action frames received count */ ++ uint32 mgmt_action_tx; /* action frames transmit count */ ++ wifi_rssi rssi_mgmt; /* access Point Beacon and Management frames RSSI ++ * (averaged) ++ */ ++ wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) from ++ * connected AP ++ */ ++ wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) from ++ * connected AP ++ */ ++ wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */ ++ uint32 num_peers; /* number of peers */ ++ wifi_peer_info peer_info[1]; /* per peer statistics */ ++} wifi_iface_stat; ++ ++#ifdef CONFIG_COMPAT ++/* interface statistics */ ++typedef struct { ++ compat_uptr_t iface; /* wifi interface */ ++ wifi_interface_info info; /* current state of the interface */ ++ uint32 beacon_rx; /* access point beacon received count from ++ * connected AP ++ */ ++ uint64 average_tsf_offset; /* average beacon offset encountered (beacon_TSF - TBTT) ++ * The average_tsf_offset field is used so as to calculate ++ * the typical beacon contention time on the channel as well ++ * may be used to debug beacon synchronization and related ++ * power consumption issue ++ */ ++ uint32 leaky_ap_detected; /* indicate that this AP ++ * typically leaks packets beyond ++ * the driver guard time. ++ */ ++ uint32 leaky_ap_avg_num_frames_leaked; /* average number of frame leaked by AP after ++ * frame with PM bit set was ACK'ed by AP ++ */ ++ uint32 leaky_ap_guard_time; /* guard time currently in force ++ * (when implementing IEEE power management ++ * based on frame control PM bit), How long ++ * driver waits before shutting down the radio and after ++ * receiving an ACK for a data frame with PM bit set) ++ */ ++ uint32 mgmt_rx; /* access point mgmt frames received count from ++ * connected AP (including Beacon) ++ */ ++ uint32 mgmt_action_rx; /* action frames received count */ ++ uint32 mgmt_action_tx; /* action frames transmit count */ ++ wifi_rssi rssi_mgmt; /* access Point Beacon and Management frames RSSI ++ * (averaged) ++ */ ++ wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) from ++ * connected AP ++ */ ++ wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) from ++ * connected AP ++ */ ++ wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */ ++ uint32 num_peers; /* number of peers */ ++ wifi_peer_info peer_info[1]; /* per peer statistics */ ++} compat_wifi_iface_stat; ++#endif /* CONFIG_COMPAT */ ++ ++#endif /* _dngl_stats_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/dngl_wlhdr.h b/module_drivers/drivers/net/wireless/bcmdhd/dngl_wlhdr.h +new file mode 100644 +index 000000000..96da42e5f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/dngl_wlhdr.h +@@ -0,0 +1,43 @@ ++/* ++ * Dongle WL Header definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dngl_wlhdr.h 514727 2014-11-12 03:02:48Z $ ++ */ ++ ++#ifndef _dngl_wlhdr_h_ ++#define _dngl_wlhdr_h_ ++ ++typedef struct wl_header { ++ uint8 type; /* Header type */ ++ uint8 version; /* Header version */ ++ int8 rssi; /* RSSI */ ++ uint8 pad; /* Unused */ ++} wl_header_t; ++ ++#define WL_HEADER_LEN sizeof(wl_header_t) ++#define WL_HEADER_TYPE 0 ++#define WL_HEADER_VER 1 ++#endif /* _dngl_wlhdr_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/hnd_pktpool.c b/module_drivers/drivers/net/wireless/bcmdhd/hnd_pktpool.c +new file mode 100644 +index 000000000..0c5c3a8a3 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/hnd_pktpool.c +@@ -0,0 +1,1180 @@ ++/* ++ * HND generic packet pool operation primitives ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: hnd_pktpool.c 613891 2016-01-20 10:05:44Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* mutex macros for thread safe */ ++#ifdef HND_PKTPOOL_THREAD_SAFE ++#define HND_PKTPOOL_MUTEX_CREATE(name, mutex) osl_ext_mutex_create(name, mutex) ++#define HND_PKTPOOL_MUTEX_DELETE(mutex) osl_ext_mutex_delete(mutex) ++#define HND_PKTPOOL_MUTEX_ACQUIRE(mutex, msec) osl_ext_mutex_acquire(mutex, msec) ++#define HND_PKTPOOL_MUTEX_RELEASE(mutex) osl_ext_mutex_release(mutex) ++#else ++#define HND_PKTPOOL_MUTEX_CREATE(name, mutex) OSL_EXT_SUCCESS ++#define HND_PKTPOOL_MUTEX_DELETE(mutex) OSL_EXT_SUCCESS ++#define HND_PKTPOOL_MUTEX_ACQUIRE(mutex, msec) OSL_EXT_SUCCESS ++#define HND_PKTPOOL_MUTEX_RELEASE(mutex) OSL_EXT_SUCCESS ++#endif ++ ++/* Registry size is one larger than max pools, as slot #0 is reserved */ ++#define PKTPOOLREG_RSVD_ID (0U) ++#define PKTPOOLREG_RSVD_PTR (POOLPTR(0xdeaddead)) ++#define PKTPOOLREG_FREE_PTR (POOLPTR(NULL)) ++ ++#define PKTPOOL_REGISTRY_SET(id, pp) (pktpool_registry_set((id), (pp))) ++#define PKTPOOL_REGISTRY_CMP(id, pp) (pktpool_registry_cmp((id), (pp))) ++ ++/* Tag a registry entry as free for use */ ++#define PKTPOOL_REGISTRY_CLR(id) \ ++ PKTPOOL_REGISTRY_SET((id), PKTPOOLREG_FREE_PTR) ++#define PKTPOOL_REGISTRY_ISCLR(id) \ ++ (PKTPOOL_REGISTRY_CMP((id), PKTPOOLREG_FREE_PTR)) ++ ++/* Tag registry entry 0 as reserved */ ++#define PKTPOOL_REGISTRY_RSV() \ ++ PKTPOOL_REGISTRY_SET(PKTPOOLREG_RSVD_ID, PKTPOOLREG_RSVD_PTR) ++#define PKTPOOL_REGISTRY_ISRSVD() \ ++ (PKTPOOL_REGISTRY_CMP(PKTPOOLREG_RSVD_ID, PKTPOOLREG_RSVD_PTR)) ++ ++/* Walk all un-reserved entries in registry */ ++#define PKTPOOL_REGISTRY_FOREACH(id) \ ++ for ((id) = 1U; (id) <= pktpools_max; (id)++) ++ ++enum pktpool_empty_cb_state { ++ EMPTYCB_ENABLED = 0, /* Enable callback when new packets are added to pool */ ++ EMPTYCB_DISABLED, /* Disable callback when new packets are added to pool */ ++ EMPTYCB_SKIPPED /* Packet was added to pool when callback was disabled */ ++}; ++ ++uint32 pktpools_max = 0U; /* maximum number of pools that may be initialized */ ++pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; /* Pktpool registry */ ++ ++/* Register/Deregister a pktpool with registry during pktpool_init/deinit */ ++static int pktpool_register(pktpool_t * poolptr); ++static int pktpool_deregister(pktpool_t * poolptr); ++ ++/** add declaration */ ++static void pktpool_avail_notify(pktpool_t *pktp); ++ ++/** accessor functions required when ROMming this file, forced into RAM */ ++ ++ ++pktpool_t * ++BCMRAMFN(get_pktpools_registry)(int id) ++{ ++ return pktpools_registry[id]; ++} ++ ++static void ++BCMRAMFN(pktpool_registry_set)(int id, pktpool_t *pp) ++{ ++ pktpools_registry[id] = pp; ++} ++ ++static bool ++BCMRAMFN(pktpool_registry_cmp)(int id, pktpool_t *pp) ++{ ++ return pktpools_registry[id] == pp; ++} ++ ++/** Constructs a pool registry to serve a maximum of total_pools */ ++int ++pktpool_attach(osl_t *osh, uint32 total_pools) ++{ ++ uint32 poolid; ++ BCM_REFERENCE(osh); ++ ++ if (pktpools_max != 0U) { ++ return BCME_ERROR; ++ } ++ ++ ASSERT(total_pools <= PKTPOOL_MAXIMUM_ID); ++ ++ /* Initialize registry: reserve slot#0 and tag others as free */ ++ PKTPOOL_REGISTRY_RSV(); /* reserve slot#0 */ ++ ++ PKTPOOL_REGISTRY_FOREACH(poolid) { /* tag all unreserved entries as free */ ++ PKTPOOL_REGISTRY_CLR(poolid); ++ } ++ ++ pktpools_max = total_pools; ++ ++ return (int)pktpools_max; ++} ++ ++/** Destructs the pool registry. Ascertain all pools were first de-inited */ ++int ++pktpool_dettach(osl_t *osh) ++{ ++ uint32 poolid; ++ BCM_REFERENCE(osh); ++ ++ if (pktpools_max == 0U) { ++ return BCME_OK; ++ } ++ ++ /* Ascertain that no pools are still registered */ ++ ASSERT(PKTPOOL_REGISTRY_ISRSVD()); /* assert reserved slot */ ++ ++ PKTPOOL_REGISTRY_FOREACH(poolid) { /* ascertain all others are free */ ++ ASSERT(PKTPOOL_REGISTRY_ISCLR(poolid)); ++ } ++ ++ pktpools_max = 0U; /* restore boot state */ ++ ++ return BCME_OK; ++} ++ ++/** Registers a pool in a free slot; returns the registry slot index */ ++static int ++pktpool_register(pktpool_t * poolptr) ++{ ++ uint32 poolid; ++ ++ if (pktpools_max == 0U) { ++ return PKTPOOL_INVALID_ID; /* registry has not yet been constructed */ ++ } ++ ++ ASSERT(pktpools_max != 0U); ++ ++ /* find an empty slot in pktpools_registry */ ++ PKTPOOL_REGISTRY_FOREACH(poolid) { ++ if (PKTPOOL_REGISTRY_ISCLR(poolid)) { ++ PKTPOOL_REGISTRY_SET(poolid, POOLPTR(poolptr)); /* register pool */ ++ return (int)poolid; /* return pool ID */ ++ } ++ } /* FOREACH */ ++ ++ return PKTPOOL_INVALID_ID; /* error: registry is full */ ++} ++ ++/** Deregisters a pktpool, given the pool pointer; tag slot as free */ ++static int ++pktpool_deregister(pktpool_t * poolptr) ++{ ++ uint32 poolid; ++ ++ ASSERT(POOLPTR(poolptr) != POOLPTR(NULL)); ++ ++ poolid = POOLID(poolptr); ++ ASSERT(poolid <= pktpools_max); ++ ++ /* Asertain that a previously registered poolptr is being de-registered */ ++ if (PKTPOOL_REGISTRY_CMP(poolid, POOLPTR(poolptr))) { ++ PKTPOOL_REGISTRY_CLR(poolid); /* mark as free */ ++ } else { ++ ASSERT(0); ++ return BCME_ERROR; /* mismatch in registry */ ++ } ++ ++ return BCME_OK; ++} ++ ++/** ++ * pktpool_init: ++ * User provides a pktpool_t structure and specifies the number of packets to ++ * be pre-filled into the pool (pplen). ++ * pktpool_init first attempts to register the pool and fetch a unique poolid. ++ * If registration fails, it is considered an BCME_ERR, caused by either the ++ * registry was not pre-created (pktpool_attach) or the registry is full. ++ * If registration succeeds, then the requested number of packets will be filled ++ * into the pool as part of initialization. In the event that there is no ++ * available memory to service the request, then BCME_NOMEM will be returned ++ * along with the count of how many packets were successfully allocated. ++ * In dongle builds, prior to memory reclaimation, one should limit the number ++ * of packets to be allocated during pktpool_init and fill the pool up after ++ * reclaim stage. ++ * ++ * @param pplen Number of packets to be pre-filled into the pool ++ * @param plen The size of all packets in a pool must be the same, [bytes] units. E.g. PKTBUFSZ. ++ * @param type e.g. 'lbuf_frag' ++ */ ++int ++pktpool_init(osl_t *osh, pktpool_t *pktp, int *pplen, int plen, bool istx, uint8 type) ++{ ++ int i, err = BCME_OK; ++ int pktplen; ++ uint8 pktp_id; ++ ++ ASSERT(pktp != NULL); ++ ASSERT(osh != NULL); ++ ASSERT(pplen != NULL); ++ ++ pktplen = *pplen; ++ ++ bzero(pktp, sizeof(pktpool_t)); ++ ++ /* assign a unique pktpool id */ ++ if ((pktp_id = (uint8) pktpool_register(pktp)) == PKTPOOL_INVALID_ID) { ++ return BCME_ERROR; ++ } ++ POOLSETID(pktp, pktp_id); ++ ++ pktp->inited = TRUE; ++ pktp->istx = istx ? TRUE : FALSE; ++ pktp->plen = (uint16)plen; ++ pktp->type = type; ++ ++ if (HND_PKTPOOL_MUTEX_CREATE("pktpool", &pktp->mutex) != OSL_EXT_SUCCESS) { ++ return BCME_ERROR; ++ } ++ ++ pktp->maxlen = PKTPOOL_LEN_MAX; ++ pktplen = LIMIT_TO_MAX(pktplen, pktp->maxlen); ++ ++ for (i = 0; i < pktplen; i++) { ++ void *p; ++ p = PKTGET(osh, plen, TRUE); ++ ++ if (p == NULL) { ++ /* Not able to allocate all requested pkts ++ * so just return what was actually allocated ++ * We can add to the pool later ++ */ ++ if (pktp->freelist == NULL) /* pktpool free list is empty */ ++ err = BCME_NOMEM; ++ ++ goto exit; ++ } ++ ++ PKTSETPOOL(osh, p, TRUE, pktp); /* Tag packet with pool ID */ ++ ++ PKTSETFREELIST(p, pktp->freelist); /* insert p at head of free list */ ++ pktp->freelist = p; ++ ++ pktp->avail++; ++ ++#ifdef BCMDBG_POOL ++ pktp->dbg_q[pktp->dbg_qlen++].p = p; ++#endif ++ } ++ ++exit: ++ pktp->len = pktp->avail; ++ ++ *pplen = pktp->len; /* number of packets managed by pool */ ++ return err; ++} /* pktpool_init */ ++ ++/** ++ * pktpool_deinit: ++ * Prior to freeing a pktpool, all packets must be first freed into the pktpool. ++ * Upon pktpool_deinit, all packets in the free pool will be freed to the heap. ++ * An assert is in place to ensure that there are no packets still lingering ++ * around. Packets freed to a pool after the deinit will cause a memory ++ * corruption as the pktpool_t structure no longer exists. ++ */ ++int ++pktpool_deinit(osl_t *osh, pktpool_t *pktp) ++{ ++ uint16 freed = 0; ++ ++ ASSERT(osh != NULL); ++ ASSERT(pktp != NULL); ++ ++#ifdef BCMDBG_POOL ++ { ++ int i; ++ for (i = 0; i <= pktp->len; i++) { ++ pktp->dbg_q[i].p = NULL; ++ } ++ } ++#endif ++ ++ while (pktp->freelist != NULL) { ++ void * p = pktp->freelist; ++ ++ pktp->freelist = PKTFREELIST(p); /* unlink head packet from free list */ ++ PKTSETFREELIST(p, NULL); ++ ++ PKTSETPOOL(osh, p, FALSE, NULL); /* clear pool ID tag in pkt */ ++ ++ PKTFREE(osh, p, pktp->istx); /* free the packet */ ++ ++ freed++; ++ ASSERT(freed <= pktp->len); ++ } ++ ++ pktp->avail -= freed; ++ ASSERT(pktp->avail == 0); ++ ++ pktp->len -= freed; ++ ++ pktpool_deregister(pktp); /* release previously acquired unique pool id */ ++ POOLSETID(pktp, PKTPOOL_INVALID_ID); ++ ++ if (HND_PKTPOOL_MUTEX_DELETE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ pktp->inited = FALSE; ++ ++ /* Are there still pending pkts? */ ++ ASSERT(pktp->len == 0); ++ ++ return 0; ++} ++ ++int ++pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal) ++{ ++ void *p; ++ int err = 0; ++ int len, psize, maxlen; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ ASSERT(pktp->plen != 0); ++ ++ maxlen = pktp->maxlen; ++ psize = minimal ? (maxlen >> 2) : maxlen; ++ for (len = (int)pktp->len; len < psize; len++) { ++ ++ p = PKTGET(osh, pktp->len, TRUE); ++ ++ if (p == NULL) { ++ err = BCME_NOMEM; ++ break; ++ } ++ ++ if (pktpool_add(pktp, p) != BCME_OK) { ++ PKTFREE(osh, p, FALSE); ++ err = BCME_ERROR; ++ break; ++ } ++ } ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ if (pktp->cbcnt) { ++ if (pktp->empty == FALSE) ++ pktpool_avail_notify(pktp); ++ } ++ ++ return err; ++} ++ ++static void * ++pktpool_deq(pktpool_t *pktp) ++{ ++ void *p = NULL; ++ ++ if (pktp->avail == 0) ++ return NULL; ++ ++ ASSERT(pktp->freelist != NULL); ++ ++ p = pktp->freelist; /* dequeue packet from head of pktpool free list */ ++ pktp->freelist = PKTFREELIST(p); /* free list points to next packet */ ++ ++ ++ PKTSETFREELIST(p, NULL); ++ ++ pktp->avail--; ++ ++ return p; ++} ++ ++static void ++pktpool_enq(pktpool_t *pktp, void *p) ++{ ++ ASSERT(p != NULL); ++ ++ PKTSETFREELIST(p, pktp->freelist); /* insert at head of pktpool free list */ ++ pktp->freelist = p; /* free list points to newly inserted packet */ ++ ++ ++ pktp->avail++; ++ ASSERT(pktp->avail <= pktp->len); ++} ++ ++/** utility for registering host addr fill function called from pciedev */ ++int ++/* BCMATTACHFN */ ++(pktpool_hostaddr_fill_register)(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) ++{ ++ ++ ASSERT(cb != NULL); ++ ++ ASSERT(pktp->cbext.cb == NULL); ++ pktp->cbext.cb = cb; ++ pktp->cbext.arg = arg; ++ return 0; ++} ++ ++int ++pktpool_rxcplid_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg) ++{ ++ ++ ASSERT(cb != NULL); ++ ++ if (pktp == NULL) ++ return BCME_ERROR; ++ ASSERT(pktp->rxcplidfn.cb == NULL); ++ pktp->rxcplidfn.cb = cb; ++ pktp->rxcplidfn.arg = arg; ++ return 0; ++} ++ ++/** whenever host posts rxbuffer, invoke dma_rxfill from pciedev layer */ ++void ++pktpool_invoke_dmarxfill(pktpool_t *pktp) ++{ ++ ASSERT(pktp->dmarxfill.cb); ++ ASSERT(pktp->dmarxfill.arg); ++ ++ if (pktp->dmarxfill.cb) ++ pktp->dmarxfill.cb(pktp, pktp->dmarxfill.arg); ++} ++ ++/** Registers callback functions for split rx mode */ ++int ++pkpool_haddr_avail_register_cb(pktpool_t *pktp, pktpool_cb_t cb, void *arg) ++{ ++ ++ ASSERT(cb != NULL); ++ ++ pktp->dmarxfill.cb = cb; ++ pktp->dmarxfill.arg = arg; ++ ++ return 0; ++} ++ ++/** ++ * Registers callback functions. ++ * No BCMATTACHFN as it is used in xdc_enable_ep which is not an attach function ++ */ ++int ++pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) ++{ ++ int err = 0; ++ int i; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ ASSERT(cb != NULL); ++ ++ i = pktp->cbcnt; ++ if (i == PKTPOOL_CB_MAX_AVL) { ++ err = BCME_ERROR; ++ goto done; ++ } ++ ++ ASSERT(pktp->cbs[i].cb == NULL); ++ pktp->cbs[i].cb = cb; ++ pktp->cbs[i].arg = arg; ++ pktp->cbcnt++; ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return err; ++} ++ ++/** Registers callback functions */ ++int ++pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) ++{ ++ int err = 0; ++ int i; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ ASSERT(cb != NULL); ++ ++ i = pktp->ecbcnt; ++ if (i == PKTPOOL_CB_MAX) { ++ err = BCME_ERROR; ++ goto done; ++ } ++ ++ ASSERT(pktp->ecbs[i].cb == NULL); ++ pktp->ecbs[i].cb = cb; ++ pktp->ecbs[i].arg = arg; ++ pktp->ecbcnt++; ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return err; ++} ++ ++/** Calls registered callback functions */ ++static int ++pktpool_empty_notify(pktpool_t *pktp) ++{ ++ int i; ++ ++ pktp->empty = TRUE; ++ for (i = 0; i < pktp->ecbcnt; i++) { ++ ASSERT(pktp->ecbs[i].cb != NULL); ++ pktp->ecbs[i].cb(pktp, pktp->ecbs[i].arg); ++ } ++ pktp->empty = FALSE; ++ ++ return 0; ++} ++ ++#ifdef BCMDBG_POOL ++int ++pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg) ++{ ++ int err = 0; ++ int i; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ ASSERT(cb); ++ ++ i = pktp->dbg_cbcnt; ++ if (i == PKTPOOL_CB_MAX) { ++ err = BCME_ERROR; ++ goto done; ++ } ++ ++ ASSERT(pktp->dbg_cbs[i].cb == NULL); ++ pktp->dbg_cbs[i].cb = cb; ++ pktp->dbg_cbs[i].arg = arg; ++ pktp->dbg_cbcnt++; ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return err; ++} ++ ++int pktpool_dbg_notify(pktpool_t *pktp); ++ ++int ++pktpool_dbg_notify(pktpool_t *pktp) ++{ ++ int i; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ for (i = 0; i < pktp->dbg_cbcnt; i++) { ++ ASSERT(pktp->dbg_cbs[i].cb); ++ pktp->dbg_cbs[i].cb(pktp, pktp->dbg_cbs[i].arg); ++ } ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return 0; ++} ++ ++int ++pktpool_dbg_dump(pktpool_t *pktp) ++{ ++ int i; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ printf("pool len=%d maxlen=%d\n", pktp->dbg_qlen, pktp->maxlen); ++ for (i = 0; i < pktp->dbg_qlen; i++) { ++ ASSERT(pktp->dbg_q[i].p); ++ printf("%d, p: 0x%x dur:%lu us state:%d\n", i, ++ pktp->dbg_q[i].p, pktp->dbg_q[i].dur/100, PKTPOOLSTATE(pktp->dbg_q[i].p)); ++ } ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return 0; ++} ++ ++int ++pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats) ++{ ++ int i; ++ int state; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ bzero(stats, sizeof(pktpool_stats_t)); ++ for (i = 0; i < pktp->dbg_qlen; i++) { ++ ASSERT(pktp->dbg_q[i].p != NULL); ++ ++ state = PKTPOOLSTATE(pktp->dbg_q[i].p); ++ switch (state) { ++ case POOL_TXENQ: ++ stats->enq++; break; ++ case POOL_TXDH: ++ stats->txdh++; break; ++ case POOL_TXD11: ++ stats->txd11++; break; ++ case POOL_RXDH: ++ stats->rxdh++; break; ++ case POOL_RXD11: ++ stats->rxd11++; break; ++ case POOL_RXFILL: ++ stats->rxfill++; break; ++ case POOL_IDLE: ++ stats->idle++; break; ++ } ++ } ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return 0; ++} ++ ++int ++pktpool_start_trigger(pktpool_t *pktp, void *p) ++{ ++ uint32 cycles, i; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ if (!PKTPOOL(OSH_NULL, p)) ++ goto done; ++ ++ OSL_GETCYCLES(cycles); ++ ++ for (i = 0; i < pktp->dbg_qlen; i++) { ++ ASSERT(pktp->dbg_q[i].p != NULL); ++ ++ if (pktp->dbg_q[i].p == p) { ++ pktp->dbg_q[i].cycles = cycles; ++ break; ++ } ++ } ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return 0; ++} ++ ++int pktpool_stop_trigger(pktpool_t *pktp, void *p); ++ ++int ++pktpool_stop_trigger(pktpool_t *pktp, void *p) ++{ ++ uint32 cycles, i; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ if (!PKTPOOL(OSH_NULL, p)) ++ goto done; ++ ++ OSL_GETCYCLES(cycles); ++ ++ for (i = 0; i < pktp->dbg_qlen; i++) { ++ ASSERT(pktp->dbg_q[i].p != NULL); ++ ++ if (pktp->dbg_q[i].p == p) { ++ if (pktp->dbg_q[i].cycles == 0) ++ break; ++ ++ if (cycles >= pktp->dbg_q[i].cycles) ++ pktp->dbg_q[i].dur = cycles - pktp->dbg_q[i].cycles; ++ else ++ pktp->dbg_q[i].dur = ++ (((uint32)-1) - pktp->dbg_q[i].cycles) + cycles + 1; ++ ++ pktp->dbg_q[i].cycles = 0; ++ break; ++ } ++ } ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return 0; ++} ++#endif /* BCMDBG_POOL */ ++ ++int ++pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp) ++{ ++ BCM_REFERENCE(osh); ++ ASSERT(pktp); ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ pktp->availcb_excl = NULL; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return 0; ++} ++ ++int ++pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb) ++{ ++ int i; ++ int err; ++ BCM_REFERENCE(osh); ++ ++ ASSERT(pktp); ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ ASSERT(pktp->availcb_excl == NULL); ++ for (i = 0; i < pktp->cbcnt; i++) { ++ if (cb == pktp->cbs[i].cb) { ++ pktp->availcb_excl = &pktp->cbs[i]; ++ break; ++ } ++ } ++ ++ if (pktp->availcb_excl == NULL) ++ err = BCME_ERROR; ++ else ++ err = 0; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return err; ++} ++ ++static void ++pktpool_avail_notify(pktpool_t *pktp) ++{ ++ int i, k, idx; ++ int avail; ++ ++ ASSERT(pktp); ++ if (pktp->availcb_excl != NULL) { ++ pktp->availcb_excl->cb(pktp, pktp->availcb_excl->arg); ++ return; ++ } ++ ++ k = pktp->cbcnt - 1; ++ for (i = 0; i < pktp->cbcnt; i++) { ++ avail = pktp->avail; ++ ++ if (avail) { ++ if (pktp->cbtoggle) ++ idx = i; ++ else ++ idx = k--; ++ ++ ASSERT(pktp->cbs[idx].cb != NULL); ++ pktp->cbs[idx].cb(pktp, pktp->cbs[idx].arg); ++ } ++ } ++ ++ /* Alternate between filling from head or tail ++ */ ++ pktp->cbtoggle ^= 1; ++ ++ return; ++} ++ ++/** Gets an empty packet from the caller provided pool */ ++void * ++pktpool_get(pktpool_t *pktp) ++{ ++ void *p; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ ++ p = pktpool_deq(pktp); ++ ++ if (p == NULL) { ++ /* Notify and try to reclaim tx pkts */ ++ if (pktp->ecbcnt) ++ pktpool_empty_notify(pktp); ++ ++ p = pktpool_deq(pktp); ++ if (p == NULL) ++ goto done; ++ } ++ ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++void ++pktpool_free(pktpool_t *pktp, void *p) ++{ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return; ++ ++ ASSERT(p != NULL); ++#ifdef BCMDBG_POOL ++ /* pktpool_stop_trigger(pktp, p); */ ++#endif ++ ++ pktpool_enq(pktp, p); ++ ++ /** ++ * Feed critical DMA with freshly freed packets, to avoid DMA starvation. ++ * If any avail callback functions are registered, send a notification ++ * that a new packet is available in the pool. ++ */ ++ if (pktp->cbcnt) { ++ /* To more efficiently use the cpu cycles, callbacks can be temporarily disabled. ++ * This allows to feed on burst basis as opposed to inefficient per-packet basis. ++ */ ++ if (pktp->emptycb_disable == EMPTYCB_ENABLED) { ++ /** ++ * If the call originated from pktpool_empty_notify, the just freed packet ++ * is needed in pktpool_get. ++ * Therefore don't call pktpool_avail_notify. ++ */ ++ if (pktp->empty == FALSE) ++ pktpool_avail_notify(pktp); ++ } else { ++ /** ++ * The callback is temporarily disabled, log that a packet has been freed. ++ */ ++ pktp->emptycb_disable = EMPTYCB_SKIPPED; ++ } ++ } ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return; ++} ++ ++/** Adds a caller provided (empty) packet to the caller provided pool */ ++int ++pktpool_add(pktpool_t *pktp, void *p) ++{ ++ int err = 0; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ ASSERT(p != NULL); ++ ++ if (pktp->len == pktp->maxlen) { ++ err = BCME_RANGE; ++ goto done; ++ } ++ ++ /* pkts in pool have same length */ ++ ASSERT(pktp->plen == PKTLEN(OSH_NULL, p)); ++ PKTSETPOOL(OSH_NULL, p, TRUE, pktp); ++ ++ pktp->len++; ++ pktpool_enq(pktp, p); ++ ++#ifdef BCMDBG_POOL ++ pktp->dbg_q[pktp->dbg_qlen++].p = p; ++#endif ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return err; ++} ++ ++/** ++ * Force pktpool_setmaxlen () into RAM as it uses a constant ++ * (PKTPOOL_LEN_MAX) that may be changed post tapeout for ROM-based chips. ++ */ ++int ++BCMRAMFN(pktpool_setmaxlen)(pktpool_t *pktp, uint16 maxlen) ++{ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ if (maxlen > PKTPOOL_LEN_MAX) ++ maxlen = PKTPOOL_LEN_MAX; ++ ++ /* if pool is already beyond maxlen, then just cap it ++ * since we currently do not reduce the pool len ++ * already allocated ++ */ ++ pktp->maxlen = (pktp->len > maxlen) ? pktp->len : maxlen; ++ ++ /* protect shared resource */ ++ if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS) ++ return BCME_ERROR; ++ ++ return pktp->maxlen; ++} ++ ++void ++pktpool_emptycb_disable(pktpool_t *pktp, bool disable) ++{ ++ ASSERT(pktp); ++ ++ /** ++ * To more efficiently use the cpu cycles, callbacks can be temporarily disabled. ++ * If callback is going to be re-enabled, check if any packet got ++ * freed and added back to the pool while callback was disabled. ++ * When this is the case do the callback now, provided that callback functions ++ * are registered and this call did not originate from pktpool_empty_notify. ++ */ ++ if ((!disable) && (pktp->cbcnt) && (pktp->empty == FALSE) && ++ (pktp->emptycb_disable == EMPTYCB_SKIPPED)) { ++ pktpool_avail_notify(pktp); ++ } ++ ++ /* Enable or temporarily disable callback when packet becomes available. */ ++ pktp->emptycb_disable = disable ? EMPTYCB_DISABLED : EMPTYCB_ENABLED; ++} ++ ++bool ++pktpool_emptycb_disabled(pktpool_t *pktp) ++{ ++ ASSERT(pktp); ++ return pktp->emptycb_disable != EMPTYCB_ENABLED; ++} ++ ++#ifdef BCMPKTPOOL ++#include ++ ++pktpool_t *pktpool_shared = NULL; ++ ++#ifdef BCMFRAGPOOL ++pktpool_t *pktpool_shared_lfrag = NULL; ++#endif /* BCMFRAGPOOL */ ++ ++pktpool_t *pktpool_shared_rxlfrag = NULL; ++ ++static osl_t *pktpool_osh = NULL; ++ ++/** ++ * Initializes several packet pools and allocates packets within those pools. ++ */ ++int ++hnd_pktpool_init(osl_t *osh) ++{ ++ int err; ++ int n; ++ ++ /* Construct a packet pool registry before initializing packet pools */ ++ n = pktpool_attach(osh, PKTPOOL_MAXIMUM_ID); ++ if (n != PKTPOOL_MAXIMUM_ID) { ++ ASSERT(0); ++ err = BCME_ERROR; ++ goto error0; ++ } ++ ++ pktpool_shared = MALLOCZ(osh, sizeof(pktpool_t)); ++ if (pktpool_shared == NULL) { ++ ASSERT(0); ++ err = BCME_NOMEM; ++ goto error1; ++ } ++ ++#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED) ++ pktpool_shared_lfrag = MALLOCZ(osh, sizeof(pktpool_t)); ++ if (pktpool_shared_lfrag == NULL) { ++ ASSERT(0); ++ err = BCME_NOMEM; ++ goto error2; ++ } ++#endif ++ ++#if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED) ++ pktpool_shared_rxlfrag = MALLOCZ(osh, sizeof(pktpool_t)); ++ if (pktpool_shared_rxlfrag == NULL) { ++ ASSERT(0); ++ err = BCME_NOMEM; ++ goto error3; ++ } ++#endif ++ ++ ++ /* ++ * At this early stage, there's not enough memory to allocate all ++ * requested pkts in the shared pool. Need to add to the pool ++ * after reclaim ++ * ++ * n = NRXBUFPOST + SDPCMD_RXBUFS; ++ * ++ * Initialization of packet pools may fail (BCME_ERROR), if the packet pool ++ * registry is not initialized or the registry is depleted. ++ * ++ * A BCME_NOMEM error only indicates that the requested number of packets ++ * were not filled into the pool. ++ */ ++ n = 1; ++ if ((err = pktpool_init(osh, pktpool_shared, ++ &n, PKTBUFSZ, FALSE, lbuf_basic)) != BCME_OK) { ++ ASSERT(0); ++ goto error4; ++ } ++ pktpool_setmaxlen(pktpool_shared, SHARED_POOL_LEN); ++ ++#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED) ++ n = 1; ++ if ((err = pktpool_init(osh, pktpool_shared_lfrag, ++ &n, PKTFRAGSZ, TRUE, lbuf_frag)) != BCME_OK) { ++ ASSERT(0); ++ goto error5; ++ } ++ pktpool_setmaxlen(pktpool_shared_lfrag, SHARED_FRAG_POOL_LEN); ++#endif ++#if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED) ++ n = 1; ++ if ((err = pktpool_init(osh, pktpool_shared_rxlfrag, ++ &n, PKTRXFRAGSZ, TRUE, lbuf_rxfrag)) != BCME_OK) { ++ ASSERT(0); ++ goto error6; ++ } ++ pktpool_setmaxlen(pktpool_shared_rxlfrag, SHARED_RXFRAG_POOL_LEN); ++#endif ++ ++ pktpool_osh = osh; ++ ++ return BCME_OK; ++ ++#if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED) ++error6: ++#endif ++ ++#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED) ++ pktpool_deinit(osh, pktpool_shared_lfrag); ++error5: ++#endif ++ ++#if (defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED)) || \ ++ (defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED)) ++ pktpool_deinit(osh, pktpool_shared); ++#endif ++ ++error4: ++#if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED) ++ hnd_free(pktpool_shared_rxlfrag); ++ pktpool_shared_rxlfrag = (pktpool_t *)NULL; ++error3: ++#endif /* BCMRXFRAGPOOL */ ++ ++#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED) ++ hnd_free(pktpool_shared_lfrag); ++ pktpool_shared_lfrag = (pktpool_t *)NULL; ++error2: ++#endif /* BCMFRAGPOOL */ ++ ++ hnd_free(pktpool_shared); ++ pktpool_shared = (pktpool_t *)NULL; ++ ++error1: ++ pktpool_dettach(osh); ++error0: ++ return err; ++} /* hnd_pktpool_init */ ++ ++int ++hnd_pktpool_fill(pktpool_t *pktpool, bool minimal) ++{ ++ return (pktpool_fill(pktpool_osh, pktpool, minimal)); ++} ++ ++/** refills pktpools after reclaim */ ++void ++hnd_pktpool_refill(bool minimal) ++{ ++ if (POOL_ENAB(pktpool_shared)) { ++ pktpool_fill(pktpool_osh, pktpool_shared, minimal); ++ } ++/* fragpool reclaim */ ++#ifdef BCMFRAGPOOL ++ if (POOL_ENAB(pktpool_shared_lfrag)) { ++#if defined(SRMEM) ++ if (SRMEM_ENAB()) { ++ int maxlen = pktpool_maxlen(pktpool_shared); ++ int len = pktpool_len(pktpool_shared); ++ ++ for (; len < maxlen; len++) { ++ void *p; ++ if ((p = PKTSRGET(pktpool_plen(pktpool_shared))) == NULL) ++ break; ++ pktpool_add(pktpool_shared, p); ++ } ++ } ++#endif /* SRMEM */ ++ pktpool_fill(pktpool_osh, pktpool_shared_lfrag, minimal); ++ } ++#endif /* BCMFRAGPOOL */ ++/* rx fragpool reclaim */ ++#ifdef BCMRXFRAGPOOL ++ if (POOL_ENAB(pktpool_shared_rxlfrag)) { ++ pktpool_fill(pktpool_osh, pktpool_shared_rxlfrag, minimal); ++ } ++#endif ++} ++#endif /* BCMPKTPOOL */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/hnd_pktq.c b/module_drivers/drivers/net/wireless/bcmdhd/hnd_pktq.c +new file mode 100644 +index 000000000..132b32135 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/hnd_pktq.c +@@ -0,0 +1,973 @@ ++/* ++ * HND generic pktq operation primitives ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: hnd_pktq.c 644628 2016-06-21 06:25:58Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* mutex macros for thread safe */ ++#ifdef HND_PKTQ_THREAD_SAFE ++#define HND_PKTQ_MUTEX_CREATE(name, mutex) osl_ext_mutex_create(name, mutex) ++#define HND_PKTQ_MUTEX_DELETE(mutex) osl_ext_mutex_delete(mutex) ++#define HND_PKTQ_MUTEX_ACQUIRE(mutex, msec) osl_ext_mutex_acquire(mutex, msec) ++#define HND_PKTQ_MUTEX_RELEASE(mutex) osl_ext_mutex_release(mutex) ++#else ++#define HND_PKTQ_MUTEX_CREATE(name, mutex) OSL_EXT_SUCCESS ++#define HND_PKTQ_MUTEX_DELETE(mutex) OSL_EXT_SUCCESS ++#define HND_PKTQ_MUTEX_ACQUIRE(mutex, msec) OSL_EXT_SUCCESS ++#define HND_PKTQ_MUTEX_RELEASE(mutex) OSL_EXT_SUCCESS ++#endif /* */ ++ ++/* ++ * osl multiple-precedence packet queue ++ * hi_prec is always >= the number of the highest non-empty precedence ++ */ ++void * BCMFASTPATH ++pktq_penq(struct pktq *pq, int prec, void *p) ++{ ++ struct pktq_prec *q; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ ++ ++ ASSERT(!pktq_full(pq)); ++ ASSERT(!pktq_pfull(pq, prec)); ++ ++ q = &pq->q[prec]; ++ ++ if (q->head) ++ PKTSETLINK(q->tail, p); ++ else ++ q->head = p; ++ ++ q->tail = p; ++ q->len++; ++ ++ pq->len++; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (uint8)prec; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_penq_head(struct pktq *pq, int prec, void *p) ++{ ++ struct pktq_prec *q; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */ ++ ++ ASSERT(!pktq_full(pq)); ++ ASSERT(!pktq_pfull(pq, prec)); ++ ++ q = &pq->q[prec]; ++ ++ if (q->head == NULL) ++ q->tail = p; ++ ++ PKTSETLINK(p, q->head); ++ q->head = p; ++ q->len++; ++ ++ pq->len++; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (uint8)prec; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++/* ++ * Append spktq 'list' to the tail of pktq 'pq' ++ */ ++void BCMFASTPATH ++pktq_append(struct pktq *pq, int prec, struct spktq *list) ++{ ++ struct pktq_prec *q; ++ struct pktq_prec *list_q; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return; ++ ++ list_q = &list->q[0]; ++ ++ /* empty list check */ ++ if (list_q->head == NULL) ++ goto done; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ASSERT(PKTLINK(list_q->tail) == NULL); /* terminated list */ ++ ++ ASSERT(!pktq_full(pq)); ++ ASSERT(!pktq_pfull(pq, prec)); ++ ++ q = &pq->q[prec]; ++ ++ if (q->head) ++ PKTSETLINK(q->tail, list_q->head); ++ else ++ q->head = list_q->head; ++ ++ q->tail = list_q->tail; ++ q->len += list_q->len; ++ pq->len += list_q->len; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (uint8)prec; ++ ++ list_q->head = NULL; ++ list_q->tail = NULL; ++ list_q->len = 0; ++ list->len = 0; ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return; ++} ++ ++/* ++ * Prepend spktq 'list' to the head of pktq 'pq' ++ */ ++void BCMFASTPATH ++pktq_prepend(struct pktq *pq, int prec, struct spktq *list) ++{ ++ struct pktq_prec *q; ++ struct pktq_prec *list_q; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return; ++ ++ list_q = &list->q[0]; ++ ++ /* empty list check */ ++ if (list_q->head == NULL) ++ goto done; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ASSERT(PKTLINK(list_q->tail) == NULL); /* terminated list */ ++ ++ ASSERT(!pktq_full(pq)); ++ ASSERT(!pktq_pfull(pq, prec)); ++ ++ q = &pq->q[prec]; ++ ++ /* set the tail packet of list to point at the former pq head */ ++ PKTSETLINK(list_q->tail, q->head); ++ /* the new q head is the head of list */ ++ q->head = list_q->head; ++ ++ /* If the q tail was non-null, then it stays as is. ++ * If the q tail was null, it is now the tail of list ++ */ ++ if (q->tail == NULL) { ++ q->tail = list_q->tail; ++ } ++ ++ q->len += list_q->len; ++ pq->len += list_q->len; ++ ++ if (pq->hi_prec < prec) ++ pq->hi_prec = (uint8)prec; ++ ++ list_q->head = NULL; ++ list_q->tail = NULL; ++ list_q->len = 0; ++ list->len = 0; ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return; ++} ++ ++void * BCMFASTPATH ++pktq_pdeq(struct pktq *pq, int prec) ++{ ++ struct pktq_prec *q; ++ void *p; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ goto done; ++ ++ if ((q->head = PKTLINK(p)) == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ pq->len--; ++ ++ PKTSETLINK(p, NULL); ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p) ++{ ++ struct pktq_prec *q; ++ void *p = NULL; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ ++ if (prev_p == NULL) ++ goto done; ++ ++ if ((p = PKTLINK(prev_p)) == NULL) ++ goto done; ++ ++ q->len--; ++ ++ pq->len--; ++ ++ PKTSETLINK(prev_p, PKTLINK(p)); ++ PKTSETLINK(p, NULL); ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg) ++{ ++ struct pktq_prec *q; ++ void *p, *prev = NULL; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ p = q->head; ++ ++ while (p) { ++ if (fn == NULL || (*fn)(p, arg)) { ++ break; ++ } else { ++ prev = p; ++ p = PKTLINK(p); ++ } ++ } ++ if (p == NULL) ++ goto done; ++ ++ if (prev == NULL) { ++ if ((q->head = PKTLINK(p)) == NULL) { ++ q->tail = NULL; ++ } ++ } else { ++ PKTSETLINK(prev, PKTLINK(p)); ++ if (q->tail == p) { ++ q->tail = prev; ++ } ++ } ++ ++ q->len--; ++ ++ pq->len--; ++ ++ PKTSETLINK(p, NULL); ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_pdeq_tail(struct pktq *pq, int prec) ++{ ++ struct pktq_prec *q; ++ void *p, *prev; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ goto done; ++ ++ for (prev = NULL; p != q->tail; p = PKTLINK(p)) ++ prev = p; ++ ++ if (prev) ++ PKTSETLINK(prev, NULL); ++ else ++ q->head = NULL; ++ ++ q->tail = prev; ++ q->len--; ++ ++ pq->len--; ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++bool BCMFASTPATH ++pktq_pdel(struct pktq *pq, void *pktbuf, int prec) ++{ ++ bool ret = FALSE; ++ struct pktq_prec *q; ++ void *p = NULL; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return FALSE; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ /* Should this just assert pktbuf? */ ++ if (!pktbuf) ++ goto done; ++ ++ q = &pq->q[prec]; ++ ++ if (q->head == pktbuf) { ++ if ((q->head = PKTLINK(pktbuf)) == NULL) ++ q->tail = NULL; ++ } else { ++ for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p)) ++ ; ++ if (p == NULL) ++ goto done; ++ ++ PKTSETLINK(p, PKTLINK(pktbuf)); ++ if (q->tail == pktbuf) ++ q->tail = p; ++ } ++ ++ q->len--; ++ pq->len--; ++ PKTSETLINK(pktbuf, NULL); ++ ret = TRUE; ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return FALSE; ++ ++ return ret; ++} ++ ++static void ++_pktq_pfilter(struct pktq *pq, int prec, pktq_filter_t fltr, void* fltr_ctx, ++ defer_free_pkt_fn_t defer, void *defer_ctx) ++{ ++ struct pktq_prec wq; ++ struct pktq_prec *q; ++ void *p; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return; ++ ++ /* move the prec queue aside to a work queue */ ++ q = &pq->q[prec]; ++ ++ wq = *q; ++ ++ q->head = NULL; ++ q->tail = NULL; ++ q->len = 0; ++ ++ pq->len -= wq.len; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return; ++ ++ /* start with the head of the work queue */ ++ while ((p = wq.head) != NULL) { ++ /* unlink the current packet from the list */ ++ wq.head = PKTLINK(p); ++ PKTSETLINK(p, NULL); ++ wq.len--; ++ ++ /* call the filter function on current packet */ ++ ASSERT(fltr != NULL); ++ switch ((*fltr)(fltr_ctx, p)) { ++ case PKT_FILTER_NOACTION: ++ /* put this packet back */ ++ pktq_penq(pq, prec, p); ++ break; ++ ++ case PKT_FILTER_DELETE: ++ /* delete this packet */ ++ ASSERT(defer != NULL); ++ (*defer)(defer_ctx, p); ++ break; ++ ++ case PKT_FILTER_REMOVE: ++ /* pkt already removed from list */ ++ break; ++ ++ default: ++ ASSERT(0); ++ break; ++ } ++ } ++ ++ ASSERT(wq.len == 0); ++} ++ ++void ++pktq_pfilter(struct pktq *pq, int prec, pktq_filter_t fltr, void* fltr_ctx, ++ defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx) ++{ ++ _pktq_pfilter(pq, prec, fltr, fltr_ctx, defer, defer_ctx); ++ ++ ASSERT(flush != NULL); ++ (*flush)(flush_ctx); ++} ++ ++void ++pktq_filter(struct pktq *pq, pktq_filter_t fltr, void* fltr_ctx, ++ defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx) ++{ ++ bool filter = FALSE; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return; ++ ++ /* Optimize if pktq len = 0, just return. ++ * pktq len of 0 means pktq's prec q's are all empty. ++ */ ++ if (pq->len > 0) { ++ filter = TRUE; ++ } ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return; ++ ++ if (filter) { ++ int prec; ++ ++ PKTQ_PREC_ITER(pq, prec) { ++ _pktq_pfilter(pq, prec, fltr, fltr_ctx, defer, defer_ctx); ++ } ++ ++ ASSERT(flush != NULL); ++ (*flush)(flush_ctx); ++ } ++} ++ ++bool ++pktq_init(struct pktq *pq, int num_prec, int max_len) ++{ ++ int prec; ++ ++ if (HND_PKTQ_MUTEX_CREATE("pktq", &pq->mutex) != OSL_EXT_SUCCESS) ++ return FALSE; ++ ++ ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC); ++ ++ /* pq is variable size; only zero out what's requested */ ++ bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); ++ ++ pq->num_prec = (uint16)num_prec; ++ ++ pq->max = (uint16)max_len; ++ ++ for (prec = 0; prec < num_prec; prec++) ++ pq->q[prec].max = pq->max; ++ ++ return TRUE; ++} ++ ++bool ++pktq_deinit(struct pktq *pq) ++{ ++ BCM_REFERENCE(pq); ++ if (HND_PKTQ_MUTEX_DELETE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++void ++pktq_set_max_plen(struct pktq *pq, int prec, int max_len) ++{ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return; ++ ++ if (prec < pq->num_prec) ++ pq->q[prec].max = (uint16)max_len; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return; ++} ++ ++void * BCMFASTPATH ++pktq_deq(struct pktq *pq, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p = NULL; ++ int prec; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ if (pq->len == 0) ++ goto done; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ goto done; ++ ++ if ((q->head = PKTLINK(p)) == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ pq->len--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ PKTSETLINK(p, NULL); ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++void * BCMFASTPATH ++pktq_deq_tail(struct pktq *pq, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p = NULL, *prev; ++ int prec; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ if (pq->len == 0) ++ goto done; ++ ++ for (prec = 0; prec < pq->hi_prec; prec++) ++ if (pq->q[prec].head) ++ break; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ goto done; ++ ++ for (prev = NULL; p != q->tail; p = PKTLINK(p)) ++ prev = p; ++ ++ if (prev) ++ PKTSETLINK(prev, NULL); ++ else ++ q->head = NULL; ++ ++ q->tail = prev; ++ q->len--; ++ ++ pq->len--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ PKTSETLINK(p, NULL); ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++void * ++pktq_peek(struct pktq *pq, int *prec_out) ++{ ++ int prec; ++ void *p = NULL; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ if (pq->len == 0) ++ goto done; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ p = pq->q[prec].head; ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++void * ++pktq_peek_tail(struct pktq *pq, int *prec_out) ++{ ++ int prec; ++ void *p = NULL; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ if (pq->len == 0) ++ goto done; ++ ++ for (prec = 0; prec < pq->hi_prec; prec++) ++ if (pq->q[prec].head) ++ break; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ p = pq->q[prec].tail; ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++void ++pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir) ++{ ++ void *p; ++ ++ /* no need for a mutex protection! */ ++ ++ /* start with the head of the list */ ++ while ((p = pktq_pdeq(pq, prec)) != NULL) { ++ ++ /* delete this packet */ ++ PKTFREE(osh, p, dir); ++ } ++} ++ ++void ++pktq_flush(osl_t *osh, struct pktq *pq, bool dir) ++{ ++ bool flush = FALSE; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return; ++ ++ /* Optimize flush, if pktq len = 0, just return. ++ * pktq len of 0 means pktq's prec q's are all empty. ++ */ ++ if (pq->len > 0) { ++ flush = TRUE; ++ } ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return; ++ ++ if (flush) { ++ int prec; ++ ++ PKTQ_PREC_ITER(pq, prec) { ++ pktq_pflush(osh, pq, prec, dir); ++ } ++ } ++} ++ ++/* Return sum of lengths of a specific set of precedences */ ++int ++pktq_mlen(struct pktq *pq, uint prec_bmp) ++{ ++ int prec, len; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return 0; ++ ++ len = 0; ++ ++ for (prec = 0; prec <= pq->hi_prec; prec++) ++ if (prec_bmp & (1 << prec)) ++ len += pq->q[prec].len; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return 0; ++ ++ return len; ++} ++ ++/* Priority peek from a specific set of precedences */ ++void * BCMFASTPATH ++pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p = NULL; ++ int prec; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ if (pq->len == 0) ++ goto done; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) ++ if (prec-- == 0) ++ goto done; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ goto done; ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++/* Priority dequeue from a specific set of precedences */ ++void * BCMFASTPATH ++pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out) ++{ ++ struct pktq_prec *q; ++ void *p = NULL; ++ int prec; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ if (pq->len == 0) ++ goto done; ++ ++ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) ++ pq->hi_prec--; ++ ++ while ((pq->q[prec].head == NULL) || ((prec_bmp & (1 << prec)) == 0)) ++ if (prec-- == 0) ++ goto done; ++ ++ q = &pq->q[prec]; ++ ++ if ((p = q->head) == NULL) ++ goto done; ++ ++ if ((q->head = PKTLINK(p)) == NULL) ++ q->tail = NULL; ++ ++ q->len--; ++ ++ // terence 20150308: fix for non-null pointer of skb->prev sent from ndo_start_xmit ++ if (q->len == 0) { ++ q->head = NULL; ++ q->tail = NULL; ++ } ++ ++ if (prec_out) ++ *prec_out = prec; ++ ++ pq->len--; ++ ++ PKTSETLINK(p, NULL); ++ ++done: ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return NULL; ++ ++ return p; ++} ++ ++#ifdef HND_PKTQ_THREAD_SAFE ++int ++pktq_pavail(struct pktq *pq, int prec) ++{ ++ int ret; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return 0; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ ret = pq->q[prec].max - pq->q[prec].len; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return 0; ++ ++ return ret; ++} ++ ++bool ++pktq_pfull(struct pktq *pq, int prec) ++{ ++ bool ret; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return FALSE; ++ ++ ASSERT(prec >= 0 && prec < pq->num_prec); ++ ++ ret = pq->q[prec].len >= pq->q[prec].max; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return FALSE; ++ ++ return ret; ++} ++ ++int ++pktq_avail(struct pktq *pq) ++{ ++ int ret; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return 0; ++ ++ ret = pq->max - pq->len; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return 0; ++ ++ return ret; ++} ++ ++bool ++pktq_full(struct pktq *pq) ++{ ++ bool ret; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) ++ return FALSE; ++ ++ ret = pq->len >= pq->max; ++ ++ /* protect shared resource */ ++ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS) ++ return FALSE; ++ ++ return ret; ++} ++#endif /* HND_PKTQ_THREAD_SAFE */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/hndpmu.c b/module_drivers/drivers/net/wireless/bcmdhd/hndpmu.c +new file mode 100644 +index 000000000..c76a943da +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/hndpmu.c +@@ -0,0 +1,382 @@ ++/* ++ * Misc utility routines for accessing PMU corerev specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: hndpmu.c 657872 2016-09-02 22:17:34Z $ ++ */ ++ ++ ++/* ++ * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs. ++ * However, in the context of this file the baseband ('BB') PLL/FLL is referred to. ++ * ++ * Throughout this code, the prefixes 'pmu0_', 'pmu1_' and 'pmu2_' are used. ++ * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012) ++ * pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports ++ * fractional frequency generation. pmu2_ does not support fractional frequency generation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(BCMULP) ++#include ++#endif /* defined(BCMULP) */ ++#include ++#ifdef EVENT_LOG_COMPILE ++#include ++#endif ++#include ++ ++#define PMU_ERROR(args) ++ ++#define PMU_MSG(args) ++ ++/* To check in verbose debugging messages not intended ++ * to be on except on private builds. ++ */ ++#define PMU_NONE(args) ++ ++/** contains resource bit positions for a specific chip */ ++struct rsc_per_chip_s { ++ uint8 ht_avail; ++ uint8 macphy_clkavail; ++ uint8 ht_start; ++ uint8 otp_pu; ++}; ++ ++typedef struct rsc_per_chip_s rsc_per_chip_t; ++ ++ ++/* SDIO Pad drive strength to select value mappings. ++ * The last strength value in each table must be 0 (the tri-state value). ++ */ ++typedef struct { ++ uint8 strength; /* Pad Drive Strength in mA */ ++ uint8 sel; /* Chip-specific select value */ ++} sdiod_drive_str_t; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 1 */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = { ++ {4, 0x2}, ++ {2, 0x3}, ++ {1, 0x0}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = { ++ {12, 0x7}, ++ {10, 0x6}, ++ {8, 0x5}, ++ {6, 0x4}, ++ {4, 0x2}, ++ {2, 0x1}, ++ {0, 0x0} }; ++ ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = { ++ {32, 0x7}, ++ {26, 0x6}, ++ {22, 0x5}, ++ {16, 0x4}, ++ {12, 0x3}, ++ {8, 0x2}, ++ {4, 0x1}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { ++ {32, 0x6}, ++ {26, 0x7}, ++ {22, 0x4}, ++ {16, 0x5}, ++ {12, 0x2}, ++ {8, 0x3}, ++ {4, 0x0}, ++ {0, 0x1} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { ++ {6, 0x7}, ++ {5, 0x6}, ++ {4, 0x5}, ++ {3, 0x4}, ++ {2, 0x2}, ++ {1, 0x1}, ++ {0, 0x0} }; ++ ++/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ ++ ++/** SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ ++static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { ++ {3, 0x3}, ++ {2, 0x2}, ++ {1, 0x1}, ++ {0, 0x0} }; ++ ++ ++/** ++ * SDIO Drive Strength to sel value table for 43143 PMU Rev 17, see Confluence 43143 Toplevel ++ * architecture page, section 'PMU Chip Control 1 Register definition', click link to picture ++ * BCM43143_sel_sdio_signals.jpg. Valid after PMU Chip Control 0 Register, bit31 (override) has ++ * been written '1'. ++ */ ++#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 ++ ++static const sdiod_drive_str_t sdiod_drive_strength_tab7_3v3[] = { ++ /* note: for 14, 10, 6 and 2mA hw timing is not met according to rtl team */ ++ {16, 0x7}, ++ {12, 0x5}, ++ {8, 0x3}, ++ {4, 0x1} }; /* note: 43143 does not support tristate */ ++ ++#else ++ ++static const sdiod_drive_str_t sdiod_drive_strength_tab7_1v8[] = { ++ /* note: for 7, 5, 3 and 1mA hw timing is not met according to rtl team */ ++ {8, 0x7}, ++ {6, 0x5}, ++ {4, 0x3}, ++ {2, 0x1} }; /* note: 43143 does not support tristate */ ++ ++#endif /* BCM_SDIO_VDDIO */ ++ ++#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) ++ ++/** ++ * Balance between stable SDIO operation and power consumption is achieved using this function. ++ * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this ++ * function should read the VDDIO itself to select the correct table. For now it has been solved ++ * with the 'BCM_SDIO_VDDIO' preprocessor constant. ++ * ++ * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if ++ * hardware supports this), if no hw support drive strength is not programmed. ++ */ ++void ++si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) ++{ ++ sdiod_drive_str_t *str_tab = NULL; ++ uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */ ++ uint32 str_shift = 0; ++ uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */ ++ uint32 str_ovr_pmuval = 0; /* position of bit within this register */ ++ pmuregs_t *pmu; ++ uint origidx; ++ ++ if (!(sih->cccaps & CC_CAP_PMU)) { ++ return; ++ } ++ BCM_REFERENCE(sdiod_drive_strength_tab1); ++ BCM_REFERENCE(sdiod_drive_strength_tab2); ++ /* Remember original core before switch to chipc/pmu */ ++ origidx = si_coreidx(sih); ++ if (AOB_ENAB(sih)) { ++ pmu = si_setcore(sih, PMU_CORE_ID, 0); ++ } else { ++ pmu = si_setcoreidx(sih, SI_CC_IDX); ++ } ++ ASSERT(pmu != NULL); ++ ++ switch (SDIOD_DRVSTR_KEY(CHIPID(sih->chip), PMUREV(sih->pmurev))) { ++ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): ++ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): ++ if (PMUREV(sih->pmurev) == 8) { ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; ++ } else if (PMUREV(sih->pmurev) == 11) { ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; ++ } ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; ++ str_mask = 0x00003800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; ++ str_mask = 0x00001800; ++ str_shift = 11; ++ break; ++ case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): ++#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 ++ if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) { ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3; ++ } ++#else ++ if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) { ++ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8; ++ } ++#endif /* BCM_SDIO_VDDIO */ ++ str_mask = 0x00000007; ++ str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR; ++ break; ++ default: ++ PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", ++ bcm_chipname( ++ CHIPID(sih->chip), chn, 8), CHIPREV(sih->chiprev), PMUREV(sih->pmurev))); ++ break; ++ } ++ ++ if (str_tab != NULL) { ++ uint32 cc_data_temp; ++ int i; ++ ++ /* Pick the lowest available drive strength equal or greater than the ++ * requested strength. Drive strength of 0 requests tri-state. ++ */ ++ for (i = 0; drivestrength < str_tab[i].strength; i++) ++ ; ++ ++ if (i > 0 && drivestrength > str_tab[i].strength) ++ i--; ++ ++ W_REG(osh, &pmu->chipcontrol_addr, PMU_CHIPCTL1); ++ cc_data_temp = R_REG(osh, &pmu->chipcontrol_data); ++ cc_data_temp &= ~str_mask; ++ cc_data_temp |= str_tab[i].sel << str_shift; ++ W_REG(osh, &pmu->chipcontrol_data, cc_data_temp); ++ if (str_ovr_pmuval) { /* enables the selected drive strength */ ++ W_REG(osh, &pmu->chipcontrol_addr, str_ovr_pmuctl); ++ OR_REG(osh, &pmu->chipcontrol_data, str_ovr_pmuval); ++ } ++ PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", ++ drivestrength, str_tab[i].strength)); ++ } ++ ++ /* Return to original core */ ++ si_setcoreidx(sih, origidx); ++} /* si_sdiod_drive_strength_init */ ++ ++ ++#if defined(BCMULP) ++int ++si_pmu_ulp_register(si_t *sih) ++{ ++ return ulp_p1_module_register(ULP_MODULE_ID_PMU, &ulp_pmu_ctx, (void *)sih); ++} ++ ++static uint ++si_pmu_ulp_get_retention_size_cb(void *handle, ulp_ext_info_t *einfo) ++{ ++ ULP_DBG(("%s: sz: %d\n", __FUNCTION__, sizeof(si_pmu_ulp_cr_dat_t))); ++ return sizeof(si_pmu_ulp_cr_dat_t); ++} ++ ++static int ++si_pmu_ulp_enter_cb(void *handle, ulp_ext_info_t *einfo, uint8 *cache_data) ++{ ++ si_pmu_ulp_cr_dat_t crinfo = {0}; ++ crinfo.ilpcycles_per_sec = ilpcycles_per_sec; ++ ULP_DBG(("%s: ilpcycles_per_sec: %x\n", __FUNCTION__, ilpcycles_per_sec)); ++ memcpy(cache_data, (void*)&crinfo, sizeof(crinfo)); ++ return BCME_OK; ++} ++ ++static int ++si_pmu_ulp_exit_cb(void *handle, uint8 *cache_data, ++ uint8 *p2_cache_data) ++{ ++ si_pmu_ulp_cr_dat_t *crinfo = (si_pmu_ulp_cr_dat_t *)cache_data; ++ ++ ilpcycles_per_sec = crinfo->ilpcycles_per_sec; ++ ULP_DBG(("%s: ilpcycles_per_sec: %x, cache_data: %p\n", __FUNCTION__, ++ ilpcycles_per_sec, cache_data)); ++ return BCME_OK; ++} ++ ++void ++si_pmu_ulp_ilp_config(si_t *sih, osl_t *osh, uint32 ilp_period) ++{ ++ pmuregs_t *pmu; ++ pmu = si_setcoreidx(sih, si_findcoreidx(sih, PMU_CORE_ID, 0)); ++ W_REG(osh, &pmu->ILPPeriod, ilp_period); ++} ++#endif /* defined(BCMULP) */ ++ ++ ++ ++void si_pmu_set_min_res_mask(si_t *sih, osl_t *osh, uint min_res_mask) ++{ ++ pmuregs_t *pmu; ++ uint origidx; ++ ++ /* Remember original core before switch to chipc/pmu */ ++ origidx = si_coreidx(sih); ++ if (AOB_ENAB(sih)) { ++ pmu = si_setcore(sih, PMU_CORE_ID, 0); ++ } ++ else { ++ pmu = si_setcoreidx(sih, SI_CC_IDX); ++ } ++ ASSERT(pmu != NULL); ++ ++ W_REG(osh, &pmu->min_res_mask, min_res_mask); ++ OSL_DELAY(100); ++ ++ /* Return to original core */ ++ si_setcoreidx(sih, origidx); ++} ++ ++bool ++si_pmu_cap_fast_lpo(si_t *sih) ++{ ++ return (PMU_REG(sih, core_cap_ext, 0, 0) & PCAP_EXT_USE_MUXED_ILP_CLK_MASK) ? TRUE : FALSE; ++} ++ ++int ++si_pmu_fast_lpo_disable(si_t *sih) ++{ ++ if (!si_pmu_cap_fast_lpo(sih)) { ++ PMU_ERROR(("%s: No Fast LPO capability\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ PMU_REG(sih, pmucontrol_ext, ++ PCTL_EXT_FASTLPO_ENAB | ++ PCTL_EXT_FASTLPO_SWENAB | ++ PCTL_EXT_FASTLPO_PCIE_SWENAB, ++ 0); ++ OSL_DELAY(1000); ++ return BCME_OK; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/802.11.h b/module_drivers/drivers/net/wireless/bcmdhd/include/802.11.h +new file mode 100644 +index 000000000..f2847ecbe +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/802.11.h +@@ -0,0 +1,5128 @@ ++/* ++ * Fundamental types and constants relating to 802.11 ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: 802.11.h 700693 2017-05-20 20:29:07Z $ ++ */ ++ ++#ifndef _802_11_H_ ++#define _802_11_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++#ifndef _NET_ETHERNET_H_ ++#include ++#endif ++ ++#include ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++#define DOT11_TU_TO_US 1024 /* 802.11 Time Unit is 1024 microseconds */ ++ ++/* Generic 802.11 frame constants */ ++#define DOT11_A3_HDR_LEN 24 /* d11 header length with A3 */ ++#define DOT11_A4_HDR_LEN 30 /* d11 header length with A4 */ ++#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN /* MAC header length */ ++#define DOT11_FCS_LEN 4 /* d11 FCS length */ ++#define DOT11_ICV_LEN 4 /* d11 ICV length */ ++#define DOT11_ICV_AES_LEN 8 /* d11 ICV/AES length */ ++#define DOT11_QOS_LEN 2 /* d11 QoS length */ ++#define DOT11_HTC_LEN 4 /* d11 HT Control field length */ ++ ++#define DOT11_KEY_INDEX_SHIFT 6 /* d11 key index shift */ ++#define DOT11_IV_LEN 4 /* d11 IV length */ ++#define DOT11_IV_TKIP_LEN 8 /* d11 IV TKIP length */ ++#define DOT11_IV_AES_OCB_LEN 4 /* d11 IV/AES/OCB length */ ++#define DOT11_IV_AES_CCM_LEN 8 /* d11 IV/AES/CCM length */ ++#define DOT11_IV_MAX_LEN 8 /* maximum iv len for any encryption */ ++ ++/* Includes MIC */ ++#define DOT11_MAX_MPDU_BODY_LEN 2304 /* max MPDU body length */ ++/* A4 header + QoS + CCMP + PDU + ICV + FCS = 2352 */ ++#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ ++ DOT11_QOS_LEN + \ ++ DOT11_IV_AES_CCM_LEN + \ ++ DOT11_MAX_MPDU_BODY_LEN + \ ++ DOT11_ICV_LEN + \ ++ DOT11_FCS_LEN) /* d11 max MPDU length */ ++ ++#define DOT11_MAX_SSID_LEN 32 /* d11 max ssid length */ ++ ++/* dot11RTSThreshold */ ++#define DOT11_DEFAULT_RTS_LEN 2347 /* d11 default RTS length */ ++#define DOT11_MAX_RTS_LEN 2347 /* d11 max RTS length */ ++ ++/* dot11FragmentationThreshold */ ++#define DOT11_MIN_FRAG_LEN 256 /* d11 min fragmentation length */ ++#define DOT11_MAX_FRAG_LEN 2346 /* Max frag is also limited by aMPDUMaxLength ++ * of the attached PHY ++ */ ++#define DOT11_DEFAULT_FRAG_LEN 2346 /* d11 default fragmentation length */ ++ ++/* dot11BeaconPeriod */ ++#define DOT11_MIN_BEACON_PERIOD 1 /* d11 min beacon period */ ++#define DOT11_MAX_BEACON_PERIOD 0xFFFF /* d11 max beacon period */ ++ ++/* dot11DTIMPeriod */ ++#define DOT11_MIN_DTIM_PERIOD 1 /* d11 min DTIM period */ ++#define DOT11_MAX_DTIM_PERIOD 0xFF /* d11 max DTIM period */ ++ ++/** 802.2 LLC/SNAP header used by 802.11 per 802.1H */ ++#define DOT11_LLC_SNAP_HDR_LEN 8 /* d11 LLC/SNAP header length */ ++/* minimum LLC header length; DSAP, SSAP, 8 bit Control (unnumbered) */ ++#define DOT11_LLC_HDR_LEN_MIN 3 ++#define DOT11_OUI_LEN 3 /* d11 OUI length */ ++BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header { ++ uint8 dsap; /* always 0xAA */ ++ uint8 ssap; /* always 0xAA */ ++ uint8 ctl; /* always 0x03 */ ++ uint8 oui[DOT11_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 ++ * Bridge-Tunnel: 0x00 0x00 0xF8 ++ */ ++ uint16 type; /* ethertype */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* RFC1042 header used by 802.11 per 802.1H */ ++#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) /* RCF1042 header length */ ++ ++/* Generic 802.11 MAC header */ ++/** ++ * N.B.: This struct reflects the full 4 address 802.11 MAC header. ++ * The fields are defined such that the shorter 1, 2, and 3 ++ * address headers just use the first k fields. ++ */ ++BWL_PRE_PACKED_STRUCT struct dot11_header { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr a1; /* address 1 */ ++ struct ether_addr a2; /* address 2 */ ++ struct ether_addr a3; /* address 3 */ ++ uint16 seq; /* sequence control */ ++ struct ether_addr a4; /* address 4 */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* Control frames */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rts_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++ struct ether_addr ta; /* transmitter address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_RTS_LEN 16 /* d11 RTS frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_cts_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_CTS_LEN 10 /* d11 CTS frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ack_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ACK_LEN 10 /* d11 ACK frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* AID */ ++ struct ether_addr bssid; /* receiver address, STA in AP */ ++ struct ether_addr ta; /* transmitter address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_PS_POLL_LEN 16 /* d11 PS poll frame length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++ struct ether_addr bssid; /* transmitter address, STA in AP */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_CS_END_LEN 16 /* d11 CF-END frame length */ ++ ++/** ++ * RWL wifi protocol: The Vendor Specific Action frame is defined for vendor-specific signaling ++ * category+OUI+vendor specific content ( this can be variable) ++ */ ++BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific { ++ uint8 category; ++ uint8 OUI[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 data[1040]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t; ++ ++/** generic vendor specific action frame with variable length */ ++BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr { ++ uint8 category; ++ uint8 OUI[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t; ++ ++#define DOT11_ACTION_VS_HDR_LEN 6 ++ ++#define BCM_ACTION_OUI_BYTE0 0x00 ++#define BCM_ACTION_OUI_BYTE1 0x90 ++#define BCM_ACTION_OUI_BYTE2 0x4c ++ ++/* BA/BAR Control parameters */ ++#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 /* normal ack */ ++#define DOT11_BA_CTL_POLICY_NOACK 0x0001 /* no ack */ ++#define DOT11_BA_CTL_POLICY_MASK 0x0001 /* ack policy mask */ ++ ++#define DOT11_BA_CTL_MTID 0x0002 /* multi tid BA */ ++#define DOT11_BA_CTL_COMPRESSED 0x0004 /* compressed bitmap */ ++ ++#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 /* num msdu in bitmap mask */ ++#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 /* num msdu in bitmap shift */ ++ ++#define DOT11_BA_CTL_TID_MASK 0xF000 /* tid mask */ ++#define DOT11_BA_CTL_TID_SHIFT 12 /* tid shift */ ++ ++/** control frame header (BA/BAR) */ ++BWL_PRE_PACKED_STRUCT struct dot11_ctl_header { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr ra; /* receiver address */ ++ struct ether_addr ta; /* transmitter address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_CTL_HDR_LEN 16 /* control frame hdr len */ ++ ++/** BAR frame payload */ ++BWL_PRE_PACKED_STRUCT struct dot11_bar { ++ uint16 bar_control; /* BAR Control */ ++ uint16 seqnum; /* Starting Sequence control */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_BAR_LEN 4 /* BAR frame payload length */ ++ ++#define DOT11_BA_BITMAP_LEN 128 /* bitmap length */ ++#define DOT11_BA_CMP_BITMAP_LEN 8 /* compressed bitmap length */ ++/** BA frame payload */ ++BWL_PRE_PACKED_STRUCT struct dot11_ba { ++ uint16 ba_control; /* BA Control */ ++ uint16 seqnum; /* Starting Sequence control */ ++ uint8 bitmap[DOT11_BA_BITMAP_LEN]; /* Block Ack Bitmap */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_BA_LEN 4 /* BA frame payload len (wo bitmap) */ ++ ++/** Management frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_management_header { ++ uint16 fc; /* frame control */ ++ uint16 durid; /* duration/ID */ ++ struct ether_addr da; /* receiver address */ ++ struct ether_addr sa; /* transmitter address */ ++ struct ether_addr bssid; /* BSS ID */ ++ uint16 seq; /* sequence control */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_management_header dot11_management_header_t; ++#define DOT11_MGMT_HDR_LEN 24 /* d11 management header length */ ++ ++/* Management frame payloads */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb { ++ uint32 timestamp[2]; ++ uint16 beacon_interval; ++ uint16 capability; ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_BCN_PRB_LEN 12 /* 802.11 beacon/probe frame fixed length */ ++#define DOT11_BCN_PRB_FIXED_LEN 12 /* 802.11 beacon/probe frame fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_auth { ++ uint16 alg; /* algorithm */ ++ uint16 seq; /* sequence control */ ++ uint16 status; /* status code */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_AUTH_FIXED_LEN 6 /* length of auth frame without challenge IE */ ++#define DOT11_AUTH_SEQ_STATUS_LEN 4 /* length of auth frame without challenge IE and ++ * without algorithm ++ */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_assoc_req { ++ uint16 capability; /* capability information */ ++ uint16 listen; /* listen interval */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ASSOC_REQ_FIXED_LEN 4 /* length of assoc frame without info elts */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req { ++ uint16 capability; /* capability information */ ++ uint16 listen; /* listen interval */ ++ struct ether_addr ap; /* Current AP address */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_REASSOC_REQ_FIXED_LEN 10 /* length of assoc frame without info elts */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp { ++ uint16 capability; /* capability information */ ++ uint16 status; /* status code */ ++ uint16 aid; /* association ID */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ASSOC_RESP_FIXED_LEN 6 /* length of assoc resp frame without info elts */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_measure { ++ uint8 category; ++ uint8 action; ++ uint8 token; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_ACTION_MEASURE_LEN 3 /* d11 action measurement header length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width { ++ uint8 category; ++ uint8 action; ++ uint8 ch_width; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops { ++ uint8 category; ++ uint8 action; ++ uint8 control; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_sa_query { ++ uint8 category; ++ uint8 action; ++ uint16 id; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_vht_oper_mode { ++ uint8 category; ++ uint8 action; ++ uint8 mode; ++} BWL_POST_PACKED_STRUCT; ++ ++/* These lengths assume 64 MU groups, as specified in 802.11ac-2013 */ ++#define DOT11_ACTION_GID_MEMBERSHIP_LEN 8 /* bytes */ ++#define DOT11_ACTION_GID_USER_POS_LEN 16 /* bytes */ ++BWL_PRE_PACKED_STRUCT struct dot11_action_group_id { ++ uint8 category; ++ uint8 action; ++ uint8 membership_status[DOT11_ACTION_GID_MEMBERSHIP_LEN]; ++ uint8 user_position[DOT11_ACTION_GID_USER_POS_LEN]; ++} BWL_POST_PACKED_STRUCT; ++ ++#define SM_PWRSAVE_ENABLE 1 ++#define SM_PWRSAVE_MODE 2 ++ ++/* ************* 802.11h related definitions. ************* */ ++BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { ++ uint8 id; ++ uint8 len; ++ uint8 power; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_power_cnst dot11_power_cnst_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_power_cap { ++ int8 min; ++ int8 max; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_power_cap dot11_power_cap_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep { ++ uint8 id; ++ uint8 len; ++ uint8 tx_pwr; ++ uint8 margin; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tpc_rep dot11_tpc_rep_t; ++#define DOT11_MNG_IE_TPC_REPORT_LEN 2 /* length of IE data, not including 2 byte header */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_supp_channels { ++ uint8 id; ++ uint8 len; ++ uint8 first_channel; ++ uint8 num_channels; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_supp_channels dot11_supp_channels_t; ++ ++/** ++ * Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband ++ * offset for 40MHz operation. The possible 3 values are: ++ * 1 = above control channel ++ * 3 = below control channel ++ * 0 = no extension channel ++ */ ++BWL_PRE_PACKED_STRUCT struct dot11_extch { ++ uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */ ++ uint8 len; /* IE length */ ++ uint8 extch; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_extch dot11_extch_ie_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; ++ uint8 type; /* type indicates what follows */ ++ uint8 extch; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; ++ ++#define BRCM_EXTCH_IE_LEN 5 ++#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */ ++#define DOT11_EXTCH_IE_LEN 1 ++#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */ ++#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */ ++#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */ ++#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr { ++ uint8 category; ++ uint8 action; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_action_frmhdr dot11_action_frmhdr_t; ++ ++/* Action Field length */ ++#define DOT11_ACTION_CATEGORY_LEN 1 ++#define DOT11_ACTION_ACTION_LEN 1 ++#define DOT11_ACTION_DIALOG_TOKEN_LEN 1 ++#define DOT11_ACTION_CAPABILITY_LEN 2 ++#define DOT11_ACTION_STATUS_CODE_LEN 2 ++#define DOT11_ACTION_REASON_CODE_LEN 2 ++#define DOT11_ACTION_TARGET_CH_LEN 1 ++#define DOT11_ACTION_OPER_CLASS_LEN 1 ++ ++#define DOT11_ACTION_FRMHDR_LEN 2 ++ ++/** CSA IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_channel_switch { ++ uint8 id; /* id DOT11_MNG_CHANNEL_SWITCH_ID */ ++ uint8 len; /* length of IE */ ++ uint8 mode; /* mode 0 or 1 */ ++ uint8 channel; /* channel switch to */ ++ uint8 count; /* number of beacons before switching */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_channel_switch dot11_chan_switch_ie_t; ++ ++#define DOT11_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ ++/* CSA mode - 802.11h-2003 $7.3.2.20 */ ++#define DOT11_CSA_MODE_ADVISORY 0 /* no DOT11_CSA_MODE_NO_TX restriction imposed */ ++#define DOT11_CSA_MODE_NO_TX 1 /* no transmission upon receiving CSA frame. */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel { ++ uint8 category; ++ uint8 action; ++ dot11_chan_switch_ie_t chan_switch_ie; /* for switch IE */ ++ dot11_brcm_extch_ie_t extch_ie; /* extension channel offset */ ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_csa_body { ++ uint8 mode; /* mode 0 or 1 */ ++ uint8 reg; /* regulatory class */ ++ uint8 channel; /* channel switch to */ ++ uint8 count; /* number of beacons before switching */ ++} BWL_POST_PACKED_STRUCT; ++ ++/** 11n Extended Channel Switch IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_ext_csa { ++ uint8 id; /* id DOT11_MNG_EXT_CSA_ID */ ++ uint8 len; /* length of IE */ ++ struct dot11_csa_body b; /* body of the ie */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ext_csa dot11_ext_csa_ie_t; ++#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa { ++ uint8 category; ++ uint8 action; ++ dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */ ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa { ++ uint8 category; ++ uint8 action; ++ struct dot11_csa_body b; /* body of the ie */ ++} BWL_POST_PACKED_STRUCT; ++ ++/** Wide Bandwidth Channel Switch IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel_switch { ++ uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ ++ uint8 len; /* length of IE */ ++ uint8 channel_width; /* new channel width */ ++ uint8 center_frequency_segment_0; /* center frequency segment 0 */ ++ uint8 center_frequency_segment_1; /* center frequency segment 1 */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_wide_bw_channel_switch dot11_wide_bw_chan_switch_ie_t; ++ ++#define DOT11_WIDE_BW_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ ++ ++/** Channel Switch Wrapper IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_channel_switch_wrapper { ++ uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ ++ uint8 len; /* length of IE */ ++ dot11_wide_bw_chan_switch_ie_t wb_chan_switch_ie; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_channel_switch_wrapper dot11_chan_switch_wrapper_ie_t; ++ ++typedef enum wide_bw_chan_width { ++ WIDE_BW_CHAN_WIDTH_20 = 0, ++ WIDE_BW_CHAN_WIDTH_40 = 1, ++ WIDE_BW_CHAN_WIDTH_80 = 2, ++ WIDE_BW_CHAN_WIDTH_160 = 3, ++ WIDE_BW_CHAN_WIDTH_80_80 = 4 ++} wide_bw_chan_width_t; ++ ++/** Wide Bandwidth Channel IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_wide_bw_channel { ++ uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_ID */ ++ uint8 len; /* length of IE */ ++ uint8 channel_width; /* channel width */ ++ uint8 center_frequency_segment_0; /* center frequency segment 0 */ ++ uint8 center_frequency_segment_1; /* center frequency segment 1 */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_wide_bw_channel dot11_wide_bw_chan_ie_t; ++ ++#define DOT11_WIDE_BW_IE_LEN 3 /* length of IE data, not including 2 byte header */ ++/** VHT Transmit Power Envelope IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_vht_transmit_power_envelope { ++ uint8 id; /* id DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID */ ++ uint8 len; /* length of IE */ ++ uint8 transmit_power_info; ++ uint8 local_max_transmit_power_20; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_vht_transmit_power_envelope dot11_vht_transmit_power_envelope_ie_t; ++ ++/* vht transmit power envelope IE length depends on channel width */ ++#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_40MHZ 1 ++#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_80MHZ 2 ++#define DOT11_VHT_TRANSMIT_PWR_ENVELOPE_IE_LEN_160MHZ 3 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { ++ uint8 id; ++ uint8 len; ++ uint8 info; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_obss_coex dot11_obss_coex_t; ++#define DOT11_OBSS_COEXINFO_LEN 1 /* length of OBSS Coexistence INFO IE */ ++ ++#define DOT11_OBSS_COEX_INFO_REQ 0x01 ++#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02 ++#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist { ++ uint8 id; ++ uint8 len; ++ uint8 regclass; ++ uint8 chanlist[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; ++#define DOT11_OBSS_CHANLIST_FIXED_LEN 1 /* fixed length of regclass */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { ++ uint8 id; ++ uint8 len; ++ uint8 cap[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_extcap_ie dot11_extcap_ie_t; ++ ++#define DOT11_EXTCAP_LEN_COEX 1 ++#define DOT11_EXTCAP_LEN_BT 3 ++#define DOT11_EXTCAP_LEN_IW 4 ++#define DOT11_EXTCAP_LEN_SI 6 ++ ++#define DOT11_EXTCAP_LEN_TDLS 5 ++#define DOT11_11AC_EXTCAP_LEN_TDLS 8 ++ ++#define DOT11_EXTCAP_LEN_FMS 2 ++#define DOT11_EXTCAP_LEN_PROXY_ARP 2 ++#define DOT11_EXTCAP_LEN_TFS 3 ++#define DOT11_EXTCAP_LEN_WNM_SLEEP 3 ++#define DOT11_EXTCAP_LEN_TIMBC 3 ++#define DOT11_EXTCAP_LEN_BSSTRANS 3 ++#define DOT11_EXTCAP_LEN_DMS 4 ++#define DOT11_EXTCAP_LEN_WNM_NOTIFICATION 6 ++#define DOT11_EXTCAP_LEN_TDLS_WBW 8 ++#define DOT11_EXTCAP_LEN_OPMODE_NOTIFICATION 8 ++ ++/* TDLS Capabilities */ ++#define DOT11_TDLS_CAP_TDLS 37 /* TDLS support */ ++#define DOT11_TDLS_CAP_PU_BUFFER_STA 28 /* TDLS Peer U-APSD buffer STA support */ ++#define DOT11_TDLS_CAP_PEER_PSM 20 /* TDLS Peer PSM support */ ++#define DOT11_TDLS_CAP_CH_SW 30 /* TDLS Channel switch */ ++#define DOT11_TDLS_CAP_PROH 38 /* TDLS prohibited */ ++#define DOT11_TDLS_CAP_CH_SW_PROH 39 /* TDLS Channel switch prohibited */ ++#define DOT11_TDLS_CAP_TDLS_WIDER_BW 61 /* TDLS Wider Band-Width */ ++ ++#define TDLS_CAP_MAX_BIT 39 /* TDLS max bit defined in ext cap */ ++ ++/* 802.11h/802.11k Measurement Request/Report IEs */ ++/* Measurement Type field */ ++#define DOT11_MEASURE_TYPE_BASIC 0 /* d11 measurement basic type */ ++#define DOT11_MEASURE_TYPE_CCA 1 /* d11 measurement CCA type */ ++#define DOT11_MEASURE_TYPE_RPI 2 /* d11 measurement RPI type */ ++#define DOT11_MEASURE_TYPE_CHLOAD 3 /* d11 measurement Channel Load type */ ++#define DOT11_MEASURE_TYPE_NOISE 4 /* d11 measurement Noise Histogram type */ ++#define DOT11_MEASURE_TYPE_BEACON 5 /* d11 measurement Beacon type */ ++#define DOT11_MEASURE_TYPE_FRAME 6 /* d11 measurement Frame type */ ++#define DOT11_MEASURE_TYPE_STAT 7 /* d11 measurement STA Statistics type */ ++#define DOT11_MEASURE_TYPE_LCI 8 /* d11 measurement LCI type */ ++#define DOT11_MEASURE_TYPE_TXSTREAM 9 /* d11 measurement TX Stream type */ ++#define DOT11_MEASURE_TYPE_MCDIAGS 10 /* d11 measurement multicast diagnostics */ ++#define DOT11_MEASURE_TYPE_CIVICLOC 11 /* d11 measurement location civic */ ++#define DOT11_MEASURE_TYPE_LOC_ID 12 /* d11 measurement location identifier */ ++#define DOT11_MEASURE_TYPE_DIRCHANQ 13 /* d11 measurement dir channel quality */ ++#define DOT11_MEASURE_TYPE_DIRMEAS 14 /* d11 measurement directional */ ++#define DOT11_MEASURE_TYPE_DIRSTATS 15 /* d11 measurement directional stats */ ++#define DOT11_MEASURE_TYPE_FTMRANGE 16 /* d11 measurement Fine Timing */ ++#define DOT11_MEASURE_TYPE_PAUSE 255 /* d11 measurement pause type */ ++ ++/* Measurement Request Modes */ ++#define DOT11_MEASURE_MODE_PARALLEL (1<<0) /* d11 measurement parallel */ ++#define DOT11_MEASURE_MODE_ENABLE (1<<1) /* d11 measurement enable */ ++#define DOT11_MEASURE_MODE_REQUEST (1<<2) /* d11 measurement request */ ++#define DOT11_MEASURE_MODE_REPORT (1<<3) /* d11 measurement report */ ++#define DOT11_MEASURE_MODE_DUR (1<<4) /* d11 measurement dur mandatory */ ++/* Measurement Report Modes */ ++#define DOT11_MEASURE_MODE_LATE (1<<0) /* d11 measurement late */ ++#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) /* d11 measurement incapable */ ++#define DOT11_MEASURE_MODE_REFUSED (1<<2) /* d11 measurement refuse */ ++/* Basic Measurement Map bits */ ++#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) /* d11 measurement basic map BSS */ ++#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) /* d11 measurement map OFDM */ ++#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) /* d11 measurement map unknown */ ++#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) /* d11 measurement map radar */ ++#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) /* d11 measurement map unmeasuremnt */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meas_req { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 channel; ++ uint8 start_time[8]; ++ uint16 duration; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_meas_req dot11_meas_req_t; ++#define DOT11_MNG_IE_MREQ_LEN 14 /* d11 measurement request IE length */ ++/* length of Measure Request IE data not including variable len */ ++#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 /* d11 measurement request IE fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meas_req_loc { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ BWL_PRE_PACKED_STRUCT union ++ { ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 subject; ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT lci; ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 subject; ++ uint8 type; /* type of civic location */ ++ uint8 siu; /* service interval units */ ++ uint16 si; /* service interval */ ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT civic; ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 subject; ++ uint8 siu; /* service interval units */ ++ uint16 si; /* service interval */ ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT locid; ++ BWL_PRE_PACKED_STRUCT struct { ++ uint16 max_init_delay; /* maximum random initial delay */ ++ uint8 min_ap_count; ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT ftm_range; ++ } BWL_POST_PACKED_STRUCT req; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_meas_req_loc dot11_meas_req_loc_t; ++#define DOT11_MNG_IE_MREQ_MIN_LEN 4 /* d11 measurement report IE length */ ++#define DOT11_MNG_IE_MREQ_LCI_FIXED_LEN 4 /* d11 measurement report IE length */ ++#define DOT11_MNG_IE_MREQ_CIVIC_FIXED_LEN 8 /* d11 measurement report IE length */ ++#define DOT11_MNG_IE_MREQ_FRNG_FIXED_LEN 6 /* d11 measurement report IE length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_lci_subelement { ++ uint8 subelement; ++ uint8 length; ++ uint8 lci_data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_lci_subelement dot11_lci_subelement_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_colocated_bssid_list_se { ++ uint8 sub_id; ++ uint8 length; ++ uint8 max_bssid_ind; /* MaxBSSID Indicator */ ++ struct ether_addr bssid[1]; /* variable */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_colocated_bssid_list_se dot11_colocated_bssid_list_se_t; ++#define DOT11_LCI_COLOCATED_BSSID_LIST_FIXED_LEN 3 ++#define DOT11_LCI_COLOCATED_BSSID_SUBELEM_ID 7 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_civic_subelement { ++ uint8 type; /* type of civic location */ ++ uint8 subelement; ++ uint8 length; ++ uint8 civic_data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_civic_subelement dot11_civic_subelement_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meas_rep { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ BWL_PRE_PACKED_STRUCT union ++ { ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 channel; ++ uint8 start_time[8]; ++ uint16 duration; ++ uint8 map; ++ } BWL_POST_PACKED_STRUCT basic; ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 subelement; ++ uint8 length; ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT lci; ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 type; /* type of civic location */ ++ uint8 subelement; ++ uint8 length; ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT civic; ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 exp_tsf[8]; ++ uint8 subelement; ++ uint8 length; ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT locid; ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 entry_count; ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT ftm_range; ++ uint8 data[1]; ++ } BWL_POST_PACKED_STRUCT rep; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_meas_rep dot11_meas_rep_t; ++#define DOT11_MNG_IE_MREP_MIN_LEN 5 /* d11 measurement report IE length */ ++#define DOT11_MNG_IE_MREP_LCI_FIXED_LEN 5 /* d11 measurement report IE length */ ++#define DOT11_MNG_IE_MREP_CIVIC_FIXED_LEN 6 /* d11 measurement report IE length */ ++#define DOT11_MNG_IE_MREP_LOCID_FIXED_LEN 13 /* d11 measurement report IE length */ ++#define DOT11_MNG_IE_MREP_BASIC_FIXED_LEN 15 /* d11 measurement report IE length */ ++#define DOT11_MNG_IE_MREP_FRNG_FIXED_LEN 4 ++ ++/* length of Measure Report IE data not including variable len */ ++#define DOT11_MNG_IE_MREP_FIXED_LEN 3 /* d11 measurement response IE fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic { ++ uint8 channel; ++ uint8 start_time[8]; ++ uint16 duration; ++ uint8 map; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; ++#define DOT11_MEASURE_BASIC_REP_LEN 12 /* d11 measurement basic report length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_quiet { ++ uint8 id; ++ uint8 len; ++ uint8 count; /* TBTTs until beacon interval in quiet starts */ ++ uint8 period; /* Beacon intervals between periodic quiet periods ? */ ++ uint16 duration; /* Length of quiet period, in TU's */ ++ uint16 offset; /* TU's offset from TBTT in Count field */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_quiet dot11_quiet_t; ++ ++BWL_PRE_PACKED_STRUCT struct chan_map_tuple { ++ uint8 channel; ++ uint8 map; ++} BWL_POST_PACKED_STRUCT; ++typedef struct chan_map_tuple chan_map_tuple_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs { ++ uint8 id; ++ uint8 len; ++ uint8 eaddr[ETHER_ADDR_LEN]; ++ uint8 interval; ++ chan_map_tuple_t map[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; ++ ++/* WME Elements */ ++#define WME_OUI "\x00\x50\xf2" /* WME OUI */ ++#define WME_OUI_LEN 3 ++#define WME_OUI_TYPE 2 /* WME type */ ++#define WME_TYPE 2 /* WME type, deprecated */ ++#define WME_SUBTYPE_IE 0 /* Information Element */ ++#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */ ++#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */ ++#define WME_VER 1 /* WME version */ ++ ++/* WME Access Category Indices (ACIs) */ ++#define AC_BE 0 /* Best Effort */ ++#define AC_BK 1 /* Background */ ++#define AC_VI 2 /* Video */ ++#define AC_VO 3 /* Voice */ ++#define AC_COUNT 4 /* number of ACs */ ++ ++typedef uint8 ac_bitmap_t; /* AC bitmap of (1 << AC_xx) */ ++ ++#define AC_BITMAP_NONE 0x0 /* No ACs */ ++#define AC_BITMAP_ALL 0xf /* All ACs */ ++#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) ++#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac)))) ++#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac)))) ++ ++/* Management PKT Lifetime indices */ ++/* Removing flag checks 'BCMINTERNAL || WLTEST' ++ * while merging MERGE BIS120RC4 to DINGO2 ++ */ ++#define MGMT_ALL 0xffff ++#define MGMT_AUTH_LT FC_SUBTYPE_AUTH ++#define MGMT_ASSOC_LT FC_SUBTYPE_ASSOC_REQ ++ ++/** WME Information Element (IE) */ ++BWL_PRE_PACKED_STRUCT struct wme_ie { ++ uint8 oui[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 version; ++ uint8 qosinfo; ++} BWL_POST_PACKED_STRUCT; ++typedef struct wme_ie wme_ie_t; ++#define WME_IE_LEN 7 /* WME IE length */ ++ ++BWL_PRE_PACKED_STRUCT struct edcf_acparam { ++ uint8 ACI; ++ uint8 ECW; ++ uint16 TXOP; /* stored in network order (ls octet first) */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct edcf_acparam edcf_acparam_t; ++ ++/** WME Parameter Element (PE) */ ++BWL_PRE_PACKED_STRUCT struct wme_param_ie { ++ uint8 oui[3]; ++ uint8 type; ++ uint8 subtype; ++ uint8 version; ++ uint8 qosinfo; ++ uint8 rsvd; ++ edcf_acparam_t acparam[AC_COUNT]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct wme_param_ie wme_param_ie_t; ++#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */ ++ ++/* QoS Info field for IE as sent from AP */ ++#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */ ++#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */ ++#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */ ++#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */ ++ ++/* QoS Info field for IE as sent from STA */ ++#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */ ++#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */ ++#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */ ++#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */ ++#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */ ++#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */ ++#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */ ++#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */ ++#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */ ++#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */ ++#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */ ++#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */ ++ ++/* ACI */ ++#define EDCF_AIFSN_MIN 1 /* AIFSN minimum value */ ++#define EDCF_AIFSN_MAX 15 /* AIFSN maximum value */ ++#define EDCF_AIFSN_MASK 0x0f /* AIFSN mask */ ++#define EDCF_ACM_MASK 0x10 /* ACM mask */ ++#define EDCF_ACI_MASK 0x60 /* ACI mask */ ++#define EDCF_ACI_SHIFT 5 /* ACI shift */ ++#define EDCF_AIFSN_SHIFT 12 /* 4 MSB(0xFFF) in ifs_ctl for AC idx */ ++ ++/* ECW */ ++#define EDCF_ECW_MIN 0 /* cwmin/cwmax exponent minimum value */ ++#define EDCF_ECW_MAX 15 /* cwmin/cwmax exponent maximum value */ ++#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) ++#define EDCF_ECWMIN_MASK 0x0f /* cwmin exponent form mask */ ++#define EDCF_ECWMAX_MASK 0xf0 /* cwmax exponent form mask */ ++#define EDCF_ECWMAX_SHIFT 4 /* cwmax exponent form shift */ ++ ++/* TXOP */ ++#define EDCF_TXOP_MIN 0 /* TXOP minimum value */ ++#define EDCF_TXOP_MAX 65535 /* TXOP maximum value */ ++#define EDCF_TXOP2USEC(txop) ((txop) << 5) ++ ++/* Default BE ACI value for non-WME connection STA */ ++#define NON_EDCF_AC_BE_ACI_STA 0x02 ++ ++/* Default EDCF parameters that AP advertises for STA to use; WMM draft Table 12 */ ++#define EDCF_AC_BE_ACI_STA 0x03 /* STA ACI value for best effort AC */ ++#define EDCF_AC_BE_ECW_STA 0xA4 /* STA ECW value for best effort AC */ ++#define EDCF_AC_BE_TXOP_STA 0x0000 /* STA TXOP value for best effort AC */ ++#define EDCF_AC_BK_ACI_STA 0x27 /* STA ACI value for background AC */ ++#define EDCF_AC_BK_ECW_STA 0xA4 /* STA ECW value for background AC */ ++#define EDCF_AC_BK_TXOP_STA 0x0000 /* STA TXOP value for background AC */ ++#define EDCF_AC_VI_ACI_STA 0x42 /* STA ACI value for video AC */ ++#define EDCF_AC_VI_ECW_STA 0x43 /* STA ECW value for video AC */ ++#define EDCF_AC_VI_TXOP_STA 0x005e /* STA TXOP value for video AC */ ++#define EDCF_AC_VO_ACI_STA 0x62 /* STA ACI value for audio AC */ ++#define EDCF_AC_VO_ECW_STA 0x32 /* STA ECW value for audio AC */ ++#define EDCF_AC_VO_TXOP_STA 0x002f /* STA TXOP value for audio AC */ ++ ++/* Default EDCF parameters that AP uses; WMM draft Table 14 */ ++#define EDCF_AC_BE_ACI_AP 0x03 /* AP ACI value for best effort AC */ ++#define EDCF_AC_BE_ECW_AP 0x64 /* AP ECW value for best effort AC */ ++#define EDCF_AC_BE_TXOP_AP 0x0000 /* AP TXOP value for best effort AC */ ++#define EDCF_AC_BK_ACI_AP 0x27 /* AP ACI value for background AC */ ++#define EDCF_AC_BK_ECW_AP 0xA4 /* AP ECW value for background AC */ ++#define EDCF_AC_BK_TXOP_AP 0x0000 /* AP TXOP value for background AC */ ++#define EDCF_AC_VI_ACI_AP 0x41 /* AP ACI value for video AC */ ++#define EDCF_AC_VI_ECW_AP 0x43 /* AP ECW value for video AC */ ++#define EDCF_AC_VI_TXOP_AP 0x005e /* AP TXOP value for video AC */ ++#define EDCF_AC_VO_ACI_AP 0x61 /* AP ACI value for audio AC */ ++#define EDCF_AC_VO_ECW_AP 0x32 /* AP ECW value for audio AC */ ++#define EDCF_AC_VO_TXOP_AP 0x002f /* AP TXOP value for audio AC */ ++ ++/** EDCA Parameter IE */ ++BWL_PRE_PACKED_STRUCT struct edca_param_ie { ++ uint8 qosinfo; ++ uint8 rsvd; ++ edcf_acparam_t acparam[AC_COUNT]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct edca_param_ie edca_param_ie_t; ++#define EDCA_PARAM_IE_LEN 18 /* EDCA Parameter IE length */ ++ ++/** QoS Capability IE */ ++BWL_PRE_PACKED_STRUCT struct qos_cap_ie { ++ uint8 qosinfo; ++} BWL_POST_PACKED_STRUCT; ++typedef struct qos_cap_ie qos_cap_ie_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie { ++ uint8 id; /* 11, DOT11_MNG_QBSS_LOAD_ID */ ++ uint8 length; ++ uint16 station_count; /* total number of STAs associated */ ++ uint8 channel_utilization; /* % of time, normalized to 255, QAP sensed medium busy */ ++ uint16 aac; /* available admission capacity */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; ++#define BSS_LOAD_IE_SIZE 7 /* BSS load IE size */ ++ ++#define WLC_QBSS_LOAD_CHAN_FREE_MAX 0xff /* max for channel free score */ ++ ++/* nom_msdu_size */ ++#define FIXED_MSDU_SIZE 0x8000 /* MSDU size is fixed */ ++#define MSDU_SIZE_MASK 0x7fff /* (Nominal or fixed) MSDU size */ ++ ++/* surplus_bandwidth */ ++/* Represented as 3 bits of integer, binary point, 13 bits fraction */ ++#define INTEGER_SHIFT 13 /* integer shift */ ++#define FRACTION_MASK 0x1FFF /* fraction mask */ ++ ++/** Management Notification Frame */ ++BWL_PRE_PACKED_STRUCT struct dot11_management_notification { ++ uint8 category; /* DOT11_ACTION_NOTIFICATION */ ++ uint8 action; ++ uint8 token; ++ uint8 status; ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++#define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */ ++ ++/** Timeout Interval IE */ ++BWL_PRE_PACKED_STRUCT struct ti_ie { ++ uint8 ti_type; ++ uint32 ti_val; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ti_ie ti_ie_t; ++#define TI_TYPE_REASSOC_DEADLINE 1 ++#define TI_TYPE_KEY_LIFETIME 2 ++ ++#ifndef CISCO_AIRONET_OUI ++#define CISCO_AIRONET_OUI "\x00\x40\x96" /* Cisco AIRONET OUI */ ++#endif ++/* QoS FastLane IE. */ ++BWL_PRE_PACKED_STRUCT struct ccx_qfl_ie { ++ uint8 id; /* 221, DOT11_MNG_VS_ID */ ++ uint8 length; /* 5 */ ++ uint8 oui[3]; /* 00:40:96 */ ++ uint8 type; /* 11 */ ++ uint8 data; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ccx_qfl_ie ccx_qfl_ie_t; ++#define CCX_QFL_IE_TYPE 11 ++#define CCX_QFL_ENABLE_SHIFT 5 ++#define CCX_QFL_ENALBE (1 << CCX_QFL_ENABLE_SHIFT) ++ ++/* WME Action Codes */ ++#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */ ++#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */ ++#define WME_DELTS_REQUEST 2 /* WME DELTS request */ ++ ++/* WME Setup Response Status Codes */ ++#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */ ++#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */ ++#define WME_ADMISSION_REFUSED 3 /* WME admission refused */ ++ ++/* Macro to take a pointer to a beacon or probe response ++ * body and return the char* pointer to the SSID info element ++ */ ++#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) ++ ++/* Authentication frame payload constants */ ++#define DOT11_OPEN_SYSTEM 0 /* d11 open authentication */ ++#define DOT11_SHARED_KEY 1 /* d11 shared authentication */ ++#define DOT11_FAST_BSS 2 /* d11 fast bss authentication */ ++#define DOT11_SAE 3 /* d11 simultaneous authentication of equals */ ++#define DOT11_FILS_SKEY_PFS 4 /* d11 fils shared key authentication w/o pfs */ ++#define DOT11_FILS_SKEY 5 /* d11 fils shared key authentication w/ pfs */ ++#define DOT11_FILS_PKEY 6 /* d11 fils public key authentication */ ++#define DOT11_CHALLENGE_LEN 128 /* d11 challenge text length */ ++ ++/* Frame control macros */ ++#define FC_PVER_MASK 0x3 /* PVER mask */ ++#define FC_PVER_SHIFT 0 /* PVER shift */ ++#define FC_TYPE_MASK 0xC /* type mask */ ++#define FC_TYPE_SHIFT 2 /* type shift */ ++#define FC_SUBTYPE_MASK 0xF0 /* subtype mask */ ++#define FC_SUBTYPE_SHIFT 4 /* subtype shift */ ++#define FC_TODS 0x100 /* to DS */ ++#define FC_TODS_SHIFT 8 /* to DS shift */ ++#define FC_FROMDS 0x200 /* from DS */ ++#define FC_FROMDS_SHIFT 9 /* from DS shift */ ++#define FC_MOREFRAG 0x400 /* more frag. */ ++#define FC_MOREFRAG_SHIFT 10 /* more frag. shift */ ++#define FC_RETRY 0x800 /* retry */ ++#define FC_RETRY_SHIFT 11 /* retry shift */ ++#define FC_PM 0x1000 /* PM */ ++#define FC_PM_SHIFT 12 /* PM shift */ ++#define FC_MOREDATA 0x2000 /* more data */ ++#define FC_MOREDATA_SHIFT 13 /* more data shift */ ++#define FC_WEP 0x4000 /* WEP */ ++#define FC_WEP_SHIFT 14 /* WEP shift */ ++#define FC_ORDER 0x8000 /* order */ ++#define FC_ORDER_SHIFT 15 /* order shift */ ++ ++/* sequence control macros */ ++#define SEQNUM_SHIFT 4 /* seq. number shift */ ++#define SEQNUM_MAX 0x1000 /* max seqnum + 1 */ ++#define FRAGNUM_MASK 0xF /* frag. number mask */ ++ ++/* Frame Control type/subtype defs */ ++ ++/* FC Types */ ++#define FC_TYPE_MNG 0 /* management type */ ++#define FC_TYPE_CTL 1 /* control type */ ++#define FC_TYPE_DATA 2 /* data type */ ++ ++/* Management Subtypes */ ++#define FC_SUBTYPE_ASSOC_REQ 0 /* assoc. request */ ++#define FC_SUBTYPE_ASSOC_RESP 1 /* assoc. response */ ++#define FC_SUBTYPE_REASSOC_REQ 2 /* reassoc. request */ ++#define FC_SUBTYPE_REASSOC_RESP 3 /* reassoc. response */ ++#define FC_SUBTYPE_PROBE_REQ 4 /* probe request */ ++#define FC_SUBTYPE_PROBE_RESP 5 /* probe response */ ++#define FC_SUBTYPE_BEACON 8 /* beacon */ ++#define FC_SUBTYPE_ATIM 9 /* ATIM */ ++#define FC_SUBTYPE_DISASSOC 10 /* disassoc. */ ++#define FC_SUBTYPE_AUTH 11 /* authentication */ ++#define FC_SUBTYPE_DEAUTH 12 /* de-authentication */ ++#define FC_SUBTYPE_ACTION 13 /* action */ ++#define FC_SUBTYPE_ACTION_NOACK 14 /* action no-ack */ ++ ++/* Control Subtypes */ ++#define FC_SUBTYPE_CTL_WRAPPER 7 /* Control Wrapper */ ++#define FC_SUBTYPE_BLOCKACK_REQ 8 /* Block Ack Req */ ++#define FC_SUBTYPE_BLOCKACK 9 /* Block Ack */ ++#define FC_SUBTYPE_PS_POLL 10 /* PS poll */ ++#define FC_SUBTYPE_RTS 11 /* RTS */ ++#define FC_SUBTYPE_CTS 12 /* CTS */ ++#define FC_SUBTYPE_ACK 13 /* ACK */ ++#define FC_SUBTYPE_CF_END 14 /* CF-END */ ++#define FC_SUBTYPE_CF_END_ACK 15 /* CF-END ACK */ ++ ++/* Data Subtypes */ ++#define FC_SUBTYPE_DATA 0 /* Data */ ++#define FC_SUBTYPE_DATA_CF_ACK 1 /* Data + CF-ACK */ ++#define FC_SUBTYPE_DATA_CF_POLL 2 /* Data + CF-Poll */ ++#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 /* Data + CF-Ack + CF-Poll */ ++#define FC_SUBTYPE_NULL 4 /* Null */ ++#define FC_SUBTYPE_CF_ACK 5 /* CF-Ack */ ++#define FC_SUBTYPE_CF_POLL 6 /* CF-Poll */ ++#define FC_SUBTYPE_CF_ACK_POLL 7 /* CF-Ack + CF-Poll */ ++#define FC_SUBTYPE_QOS_DATA 8 /* QoS Data */ ++#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 /* QoS Data + CF-Ack */ ++#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 /* QoS Data + CF-Poll */ ++#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 /* QoS Data + CF-Ack + CF-Poll */ ++#define FC_SUBTYPE_QOS_NULL 12 /* QoS Null */ ++#define FC_SUBTYPE_QOS_CF_POLL 14 /* QoS CF-Poll */ ++#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 /* QoS CF-Ack + CF-Poll */ ++ ++/* Data Subtype Groups */ ++#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) ++#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) ++#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) ++#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) ++#define FC_SUBTYPE_ANY_PSPOLL(s) (((s) & 10) != 0) ++ ++/* Type/Subtype Combos */ ++#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) /* FC kind mask */ ++ ++#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) /* FC kind */ ++ ++#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) /* Subtype from FC */ ++#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) /* Type from FC */ ++ ++#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) /* assoc. request */ ++#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) /* assoc. response */ ++#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) /* reassoc. request */ ++#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) /* reassoc. response */ ++#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) /* probe request */ ++#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) /* probe response */ ++#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) /* beacon */ ++#define FC_ATIM FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ATIM) /* ATIM */ ++#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) /* disassoc */ ++#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) /* authentication */ ++#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) /* deauthentication */ ++#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) /* action */ ++#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) /* action no-ack */ ++ ++#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) /* Control Wrapper */ ++#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) /* Block Ack Req */ ++#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) /* Block Ack */ ++#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) /* PS poll */ ++#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) /* RTS */ ++#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) /* CTS */ ++#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) /* ACK */ ++#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) /* CF-END */ ++#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) /* CF-END ACK */ ++ ++#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) /* data */ ++#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) /* null data */ ++#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) /* data CF ACK */ ++#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) /* QoS data */ ++#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) /* QoS null */ ++ ++/* QoS Control Field */ ++ ++/* 802.1D Priority */ ++#define QOS_PRIO_SHIFT 0 /* QoS priority shift */ ++#define QOS_PRIO_MASK 0x0007 /* QoS priority mask */ ++#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) /* QoS priority */ ++ ++/* Traffic Identifier */ ++#define QOS_TID_SHIFT 0 /* QoS TID shift */ ++#define QOS_TID_MASK 0x000f /* QoS TID mask */ ++#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) /* QoS TID */ ++ ++/* End of Service Period (U-APSD) */ ++#define QOS_EOSP_SHIFT 4 /* QoS End of Service Period shift */ ++#define QOS_EOSP_MASK 0x0010 /* QoS End of Service Period mask */ ++#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) /* Qos EOSP */ ++ ++/* Ack Policy */ ++#define QOS_ACK_NORMAL_ACK 0 /* Normal Ack */ ++#define QOS_ACK_NO_ACK 1 /* No Ack (eg mcast) */ ++#define QOS_ACK_NO_EXP_ACK 2 /* No Explicit Ack */ ++#define QOS_ACK_BLOCK_ACK 3 /* Block Ack */ ++#define QOS_ACK_SHIFT 5 /* QoS ACK shift */ ++#define QOS_ACK_MASK 0x0060 /* QoS ACK mask */ ++#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) /* QoS ACK */ ++ ++/* A-MSDU flag */ ++#define QOS_AMSDU_SHIFT 7 /* AMSDU shift */ ++#define QOS_AMSDU_MASK 0x0080 /* AMSDU mask */ ++ ++/* Management Frames */ ++ ++/* Management Frame Constants */ ++ ++/* Fixed fields */ ++#define DOT11_MNG_AUTH_ALGO_LEN 2 /* d11 management auth. algo. length */ ++#define DOT11_MNG_AUTH_SEQ_LEN 2 /* d11 management auth. seq. length */ ++#define DOT11_MNG_BEACON_INT_LEN 2 /* d11 management beacon interval length */ ++#define DOT11_MNG_CAP_LEN 2 /* d11 management cap. length */ ++#define DOT11_MNG_AP_ADDR_LEN 6 /* d11 management AP address length */ ++#define DOT11_MNG_LISTEN_INT_LEN 2 /* d11 management listen interval length */ ++#define DOT11_MNG_REASON_LEN 2 /* d11 management reason length */ ++#define DOT11_MNG_AID_LEN 2 /* d11 management AID length */ ++#define DOT11_MNG_STATUS_LEN 2 /* d11 management status length */ ++#define DOT11_MNG_TIMESTAMP_LEN 8 /* d11 management timestamp length */ ++ ++/* DUR/ID field in assoc resp is 0xc000 | AID */ ++#define DOT11_AID_MASK 0x3fff /* d11 AID mask */ ++ ++/* Reason Codes */ ++#define DOT11_RC_RESERVED 0 /* d11 RC reserved */ ++#define DOT11_RC_UNSPECIFIED 1 /* Unspecified reason */ ++#define DOT11_RC_AUTH_INVAL 2 /* Previous authentication no longer valid */ ++#define DOT11_RC_DEAUTH_LEAVING 3 /* Deauthenticated because sending station ++ * is leaving (or has left) IBSS or ESS ++ */ ++#define DOT11_RC_INACTIVITY 4 /* Disassociated due to inactivity */ ++#define DOT11_RC_BUSY 5 /* Disassociated because AP is unable to handle ++ * all currently associated stations ++ */ ++#define DOT11_RC_INVAL_CLASS_2 6 /* Class 2 frame received from ++ * nonauthenticated station ++ */ ++#define DOT11_RC_INVAL_CLASS_3 7 /* Class 3 frame received from ++ * nonassociated station ++ */ ++#define DOT11_RC_DISASSOC_LEAVING 8 /* Disassociated because sending station is ++ * leaving (or has left) BSS ++ */ ++#define DOT11_RC_NOT_AUTH 9 /* Station requesting (re)association is not ++ * authenticated with responding station ++ */ ++#define DOT11_RC_BAD_PC 10 /* Unacceptable power capability element */ ++#define DOT11_RC_BAD_CHANNELS 11 /* Unacceptable supported channels element */ ++ ++/* 12 is unused by STA but could be used by AP/GO */ ++#define DOT11_RC_DISASSOC_BTM 12 /* Disassociated due to BSS Transition Magmt */ ++ ++ ++/* 32-39 are QSTA specific reasons added in 11e */ ++#define DOT11_RC_UNSPECIFIED_QOS 32 /* unspecified QoS-related reason */ ++#define DOT11_RC_INSUFFCIENT_BW 33 /* QAP lacks sufficient bandwidth */ ++#define DOT11_RC_EXCESSIVE_FRAMES 34 /* excessive number of frames need ack */ ++#define DOT11_RC_TX_OUTSIDE_TXOP 35 /* transmitting outside the limits of txop */ ++#define DOT11_RC_LEAVING_QBSS 36 /* QSTA is leaving the QBSS (or restting) */ ++#define DOT11_RC_BAD_MECHANISM 37 /* does not want to use the mechanism */ ++#define DOT11_RC_SETUP_NEEDED 38 /* mechanism needs a setup */ ++#define DOT11_RC_TIMEOUT 39 /* timeout */ ++ ++#define DOT11_RC_MESH_PEERING_CANCELLED 52 ++#define DOT11_RC_MESH_MAX_PEERS 53 ++#define DOT11_RC_MESH_CONFIG_POLICY_VIOLN 54 ++#define DOT11_RC_MESH_CLOSE_RECVD 55 ++#define DOT11_RC_MESH_MAX_RETRIES 56 ++#define DOT11_RC_MESH_CONFIRM_TIMEOUT 57 ++#define DOT11_RC_MESH_INVALID_GTK 58 ++#define DOT11_RC_MESH_INCONSISTENT_PARAMS 59 ++ ++#define DOT11_RC_MESH_INVALID_SEC_CAP 60 ++#define DOT11_RC_MESH_PATHERR_NOPROXYINFO 61 ++#define DOT11_RC_MESH_PATHERR_NOFWINFO 62 ++#define DOT11_RC_MESH_PATHERR_DSTUNREACH 63 ++#define DOT11_RC_MESH_MBSSMAC_EXISTS 64 ++#define DOT11_RC_MESH_CHANSWITCH_REGREQ 65 ++#define DOT11_RC_MESH_CHANSWITCH_UNSPEC 66 ++ ++#define DOT11_RC_MAX 66 /* Reason codes > 66 are reserved */ ++ ++#define DOT11_RC_TDLS_PEER_UNREACH 25 ++#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 ++ ++/* Status Codes */ ++#define DOT11_SC_SUCCESS 0 /* Successful */ ++#define DOT11_SC_FAILURE 1 /* Unspecified failure */ ++#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 /* TDLS wakeup schedule rejected but alternative */ ++ /* schedule provided */ ++#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 /* TDLS wakeup schedule rejected */ ++#define DOT11_SC_TDLS_SEC_DISABLED 5 /* TDLS Security disabled */ ++#define DOT11_SC_LIFETIME_REJ 6 /* Unacceptable lifetime */ ++#define DOT11_SC_NOT_SAME_BSS 7 /* Not in same BSS */ ++#define DOT11_SC_CAP_MISMATCH 10 /* Cannot support all requested ++ * capabilities in the Capability ++ * Information field ++ */ ++#define DOT11_SC_REASSOC_FAIL 11 /* Reassociation denied due to inability ++ * to confirm that association exists ++ */ ++#define DOT11_SC_ASSOC_FAIL 12 /* Association denied due to reason ++ * outside the scope of this standard ++ */ ++#define DOT11_SC_AUTH_MISMATCH 13 /* Responding station does not support ++ * the specified authentication ++ * algorithm ++ */ ++#define DOT11_SC_AUTH_SEQ 14 /* Received an Authentication frame ++ * with authentication transaction ++ * sequence number out of expected ++ * sequence ++ */ ++#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 /* Authentication rejected because of ++ * challenge failure ++ */ ++#define DOT11_SC_AUTH_TIMEOUT 16 /* Authentication rejected due to timeout ++ * waiting for next frame in sequence ++ */ ++#define DOT11_SC_ASSOC_BUSY_FAIL 17 /* Association denied because AP is ++ * unable to handle additional ++ * associated stations ++ */ ++#define DOT11_SC_ASSOC_RATE_MISMATCH 18 /* Association denied due to requesting ++ * station not supporting all of the ++ * data rates in the BSSBasicRateSet ++ * parameter ++ */ ++#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 /* Association denied due to requesting ++ * station not supporting the Short ++ * Preamble option ++ */ ++#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 /* Association denied due to requesting ++ * station not supporting the PBCC ++ * Modulation option ++ */ ++#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 /* Association denied due to requesting ++ * station not supporting the Channel ++ * Agility option ++ */ ++#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum ++ * Management capability is required. ++ */ ++#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info ++ * in the Power Cap element is ++ * unacceptable. ++ */ ++#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 /* Association denied because the info ++ * in the Supported Channel element is ++ * unacceptable ++ */ ++#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting ++ * station not supporting the Short Slot ++ * Time option ++ */ ++#define DOT11_SC_ASSOC_DSSSOFDM_REQUIRED 26 /* Association denied because requesting station ++ * does not support the DSSS-OFDM option ++ */ ++#define DOT11_SC_ASSOC_HT_REQUIRED 27 /* Association denied because the requesting ++ * station does not support HT features ++ */ ++#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 /* Association denied due to AP ++ * being unable to reach the R0 Key Holder ++ */ ++#define DOT11_SC_ASSOC_TRY_LATER 30 /* Association denied temporarily, try again later ++ */ ++#define DOT11_SC_ASSOC_MFP_VIOLATION 31 /* Association denied due to Robust Management ++ * frame policy violation ++ */ ++ ++#define DOT11_SC_DECLINED 37 /* request declined */ ++#define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */ ++#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 /* invalid pairwise cipher */ ++#define DOT11_SC_INVALID_AKMP 43 /* Association denied due to invalid AKMP */ ++#define DOT11_SC_INVALID_RSNIE_CAP 45 /* invalid RSN IE capabilities */ ++#define DOT11_SC_DLS_NOT_ALLOWED 48 /* DLS is not allowed in the BSS by policy */ ++#define DOT11_SC_INVALID_PMKID 53 /* Association denied due to invalid PMKID */ ++#define DOT11_SC_INVALID_MDID 54 /* Association denied due to invalid MDID */ ++#define DOT11_SC_INVALID_FTIE 55 /* Association denied due to invalid FTIE */ ++ ++#define DOT11_SC_ADV_PROTO_NOT_SUPPORTED 59 /* ad proto not supported */ ++#define DOT11_SC_NO_OUTSTAND_REQ 60 /* no outstanding req */ ++#define DOT11_SC_RSP_NOT_RX_FROM_SERVER 61 /* no response from server */ ++#define DOT11_SC_TIMEOUT 62 /* timeout */ ++#define DOT11_SC_QUERY_RSP_TOO_LARGE 63 /* query rsp too large */ ++#define DOT11_SC_SERVER_UNREACHABLE 65 /* server unreachable */ ++ ++#define DOT11_SC_UNEXP_MSG 70 /* Unexpected message */ ++#define DOT11_SC_INVALID_SNONCE 71 /* Invalid SNonce */ ++#define DOT11_SC_INVALID_RSNIE 72 /* Invalid contents of RSNIE */ ++ ++#define DOT11_SC_ANTICLOG_TOCKEN_REQUIRED 76 /* Anti-clogging tocken required */ ++#define DOT11_SC_INVALID_FINITE_CYCLIC_GRP 77 /* Invalid contents of RSNIE */ ++ ++#define DOT11_SC_ASSOC_VHT_REQUIRED 104 /* Association denied because the requesting ++ * station does not support VHT features. ++ */ ++ ++#define DOT11_SC_TRANSMIT_FAILURE 79 /* transmission failure */ ++ ++/* Info Elts, length of INFORMATION portion of Info Elts */ ++#define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */ ++#define DOT11_MNG_IBSS_PARAM_LEN 2 /* d11 management IBSS parameter length */ ++ ++/* TIM Info element has 3 bytes fixed info in INFORMATION field, ++ * followed by 1 to 251 bytes of Partial Virtual Bitmap ++ */ ++#define DOT11_MNG_TIM_FIXED_LEN 3 /* d11 management TIM fixed length */ ++#define DOT11_MNG_TIM_DTIM_COUNT 0 /* d11 management DTIM count */ ++#define DOT11_MNG_TIM_DTIM_PERIOD 1 /* d11 management DTIM period */ ++#define DOT11_MNG_TIM_BITMAP_CTL 2 /* d11 management TIM BITMAP control */ ++#define DOT11_MNG_TIM_PVB 3 /* d11 management TIM PVB */ ++ ++/* TLV defines */ ++#define TLV_TAG_OFF 0 /* tag offset */ ++#define TLV_LEN_OFF 1 /* length offset */ ++#define TLV_HDR_LEN 2 /* header length */ ++#define TLV_BODY_OFF 2 /* body offset */ ++#define TLV_BODY_LEN_MAX 255 /* max body length */ ++ ++/* Management Frame Information Element IDs */ ++#define DOT11_MNG_SSID_ID 0 /* d11 management SSID id */ ++#define DOT11_MNG_RATES_ID 1 /* d11 management rates id */ ++#define DOT11_MNG_FH_PARMS_ID 2 /* d11 management FH parameter id */ ++#define DOT11_MNG_DS_PARMS_ID 3 /* d11 management DS parameter id */ ++#define DOT11_MNG_CF_PARMS_ID 4 /* d11 management CF parameter id */ ++#define DOT11_MNG_TIM_ID 5 /* d11 management TIM id */ ++#define DOT11_MNG_IBSS_PARMS_ID 6 /* d11 management IBSS parameter id */ ++#define DOT11_MNG_COUNTRY_ID 7 /* d11 management country id */ ++#define DOT11_MNG_HOPPING_PARMS_ID 8 /* d11 management hopping parameter id */ ++#define DOT11_MNG_HOPPING_TABLE_ID 9 /* d11 management hopping table id */ ++#define DOT11_MNG_FTM_SYNC_INFO_ID 9 /* 11mc D4.3 */ ++#define DOT11_MNG_REQUEST_ID 10 /* d11 management request id */ ++#define DOT11_MNG_QBSS_LOAD_ID 11 /* d11 management QBSS Load id */ ++#define DOT11_MNG_EDCA_PARAM_ID 12 /* 11E EDCA Parameter id */ ++#define DOT11_MNG_TSPEC_ID 13 /* d11 management TSPEC id */ ++#define DOT11_MNG_TCLAS_ID 14 /* d11 management TCLAS id */ ++#define DOT11_MNG_CHALLENGE_ID 16 /* d11 management chanllenge id */ ++#define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */ ++#define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */ ++#define DOT11_MNG_TPC_REQUEST_ID 34 /* 11H TPC Request */ ++#define DOT11_MNG_TPC_REPORT_ID 35 /* 11H TPC Report */ ++#define DOT11_MNG_SUPP_CHANNELS_ID 36 /* 11H Supported Channels */ ++#define DOT11_MNG_CHANNEL_SWITCH_ID 37 /* 11H ChannelSwitch Announcement */ ++#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */ ++#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementReport */ ++#define DOT11_MNG_QUIET_ID 40 /* 11H Quiet */ ++#define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */ ++#define DOT11_MNG_ERP_ID 42 /* d11 management ERP id */ ++#define DOT11_MNG_TS_DELAY_ID 43 /* d11 management TS Delay id */ ++#define DOT11_MNG_TCLAS_PROC_ID 44 /* d11 management TCLAS processing id */ ++#define DOT11_MNG_HT_CAP 45 /* d11 mgmt HT cap id */ ++#define DOT11_MNG_QOS_CAP_ID 46 /* 11E QoS Capability id */ ++#define DOT11_MNG_NONERP_ID 47 /* d11 management NON-ERP id */ ++#define DOT11_MNG_RSN_ID 48 /* d11 management RSN id */ ++#define DOT11_MNG_EXT_RATES_ID 50 /* d11 management ext. rates id */ ++#define DOT11_MNG_AP_CHREP_ID 51 /* 11k AP Channel report id */ ++#define DOT11_MNG_NEIGHBOR_REP_ID 52 /* 11k & 11v Neighbor report id */ ++#define DOT11_MNG_RCPI_ID 53 /* 11k RCPI */ ++#define DOT11_MNG_MDIE_ID 54 /* 11r Mobility domain id */ ++#define DOT11_MNG_FTIE_ID 55 /* 11r Fast Bss Transition id */ ++#define DOT11_MNG_FT_TI_ID 56 /* 11r Timeout Interval id */ ++#define DOT11_MNG_RDE_ID 57 /* 11r RIC Data Element id */ ++#define DOT11_MNG_REGCLASS_ID 59 /* d11 management regulatory class id */ ++#define DOT11_MNG_EXT_CSA_ID 60 /* d11 Extended CSA */ ++#define DOT11_MNG_HT_ADD 61 /* d11 mgmt additional HT info */ ++#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 /* d11 mgmt ext channel offset */ ++#define DOT11_MNG_BSS_AVR_ACCESS_DELAY_ID 63 /* 11k bss average access delay */ ++#define DOT11_MNG_ANTENNA_ID 64 /* 11k antenna id */ ++#define DOT11_MNG_RSNI_ID 65 /* 11k RSNI id */ ++#define DOT11_MNG_MEASUREMENT_PILOT_TX_ID 66 /* 11k measurement pilot tx info id */ ++#define DOT11_MNG_BSS_AVAL_ADMISSION_CAP_ID 67 /* 11k bss aval admission cap id */ ++#define DOT11_MNG_BSS_AC_ACCESS_DELAY_ID 68 /* 11k bss AC access delay id */ ++#define DOT11_MNG_WAPI_ID 68 /* d11 management WAPI id */ ++#define DOT11_MNG_TIME_ADVERTISE_ID 69 /* 11p time advertisement */ ++#define DOT11_MNG_RRM_CAP_ID 70 /* 11k radio measurement capability */ ++#define DOT11_MNG_MULTIPLE_BSSID_ID 71 /* 11k multiple BSSID id */ ++#define DOT11_MNG_HT_BSS_COEXINFO_ID 72 /* d11 mgmt OBSS Coexistence INFO */ ++#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 /* d11 mgmt OBSS Intolerant Channel list */ ++#define DOT11_MNG_HT_OBSS_ID 74 /* d11 mgmt OBSS HT info */ ++#define DOT11_MNG_MMIE_ID 76 /* d11 mgmt MIC IE */ ++#define DOT11_MNG_FMS_DESCR_ID 86 /* 11v FMS descriptor */ ++#define DOT11_MNG_FMS_REQ_ID 87 /* 11v FMS request id */ ++#define DOT11_MNG_FMS_RESP_ID 88 /* 11v FMS response id */ ++#define DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID 90 /* 11v bss max idle id */ ++#define DOT11_MNG_TFS_REQUEST_ID 91 /* 11v tfs request id */ ++#define DOT11_MNG_TFS_RESPONSE_ID 92 /* 11v tfs response id */ ++#define DOT11_MNG_WNM_SLEEP_MODE_ID 93 /* 11v wnm-sleep mode id */ ++#define DOT11_MNG_TIMBC_REQ_ID 94 /* 11v TIM broadcast request id */ ++#define DOT11_MNG_TIMBC_RESP_ID 95 /* 11v TIM broadcast response id */ ++#define DOT11_MNG_CHANNEL_USAGE 97 /* 11v channel usage */ ++#define DOT11_MNG_TIME_ZONE_ID 98 /* 11v time zone */ ++#define DOT11_MNG_DMS_REQUEST_ID 99 /* 11v dms request id */ ++#define DOT11_MNG_DMS_RESPONSE_ID 100 /* 11v dms response id */ ++#define DOT11_MNG_LINK_IDENTIFIER_ID 101 /* 11z TDLS Link Identifier IE */ ++#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 /* 11z TDLS Wakeup Schedule IE */ ++#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 /* 11z TDLS Channel Switch Timing IE */ ++#define DOT11_MNG_PTI_CONTROL_ID 105 /* 11z TDLS PTI Control IE */ ++#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 /* 11z TDLS PU Buffer Status IE */ ++#define DOT11_MNG_INTERWORKING_ID 107 /* 11u interworking */ ++#define DOT11_MNG_ADVERTISEMENT_ID 108 /* 11u advertisement protocol */ ++#define DOT11_MNG_EXP_BW_REQ_ID 109 /* 11u expedited bandwith request */ ++#define DOT11_MNG_QOS_MAP_ID 110 /* 11u QoS map set */ ++#define DOT11_MNG_ROAM_CONSORT_ID 111 /* 11u roaming consortium */ ++#define DOT11_MNG_EMERGCY_ALERT_ID 112 /* 11u emergency alert identifier */ ++#define DOT11_MNG_MESH_CONFIG 113 /* Mesh Configuration */ ++#define DOT11_MNG_MESH_ID 114 /* Mesh ID */ ++#define DOT11_MNG_MESH_PEER_MGMT_ID 117 /* Mesh PEER MGMT IE */ ++#define DOT11_MNG_EXT_CAP_ID 127 /* d11 mgmt ext capability */ ++#define DOT11_MNG_EXT_PREQ_ID 130 /* Mesh PREQ IE */ ++#define DOT11_MNG_EXT_PREP_ID 131 /* Mesh PREP IE */ ++#define DOT11_MNG_EXT_PERR_ID 132 /* Mesh PERR IE */ ++#define DOT11_MNG_VHT_CAP_ID 191 /* d11 mgmt VHT cap id */ ++#define DOT11_MNG_VHT_OPERATION_ID 192 /* d11 mgmt VHT op id */ ++#define DOT11_MNG_EXT_BSSLOAD_ID 193 /* d11 mgmt VHT extended bss load id */ ++#define DOT11_MNG_WIDE_BW_CHANNEL_SWITCH_ID 194 /* Wide BW Channel Switch IE */ ++#define DOT11_MNG_VHT_TRANSMIT_POWER_ENVELOPE_ID 195 /* VHT transmit Power Envelope IE */ ++#define DOT11_MNG_CHANNEL_SWITCH_WRAPPER_ID 196 /* Channel Switch Wrapper IE */ ++#define DOT11_MNG_AID_ID 197 /* Association ID IE */ ++#define DOT11_MNG_OPER_MODE_NOTIF_ID 199 /* d11 mgmt VHT oper mode notif */ ++#define DOT11_MNG_RNR_ID 201 ++#define DOT11_MNG_HE_CAP_ID 202 ++#define DOT11_MNG_HE_OP_ID 203 ++#define DOT11_MNG_FTM_PARAMS_ID 206 ++#define DOT11_MNG_TWT_ID 216 /* 11ah D5.0 */ ++#define DOT11_MNG_WPA_ID 221 /* d11 management WPA id */ ++#define DOT11_MNG_PROPR_ID 221 ++/* should start using this one instead of above two */ ++#define DOT11_MNG_VS_ID 221 /* d11 management Vendor Specific IE */ ++#define DOT11_MNG_MESH_CSP_ID 222 /* d11 Mesh Channel Switch Parameter */ ++#define DOT11_MNG_FILS_IND_ID 240 /* 11ai FILS Indication element */ ++ ++/* The follwing ID extensions should be defined >= 255 ++ * i.e. the values should include 255 (DOT11_MNG_ID_EXT_ID + ID Extension). ++ */ ++#define DOT11_MNG_ID_EXT_ID 255 /* Element ID Extension 11mc D4.3 */ ++#define DOT11_MNG_RAPS_ID (DOT11_MNG_ID_EXT_ID+11) /* OFDMA Random Access Parameter Set */ ++ ++/* FILS ext ids */ ++#define FILS_REQ_PARAMS_EXT_ID 2 ++#define DOT11_MNG_FILS_REQ_PARAMS (DOT11_MNG_ID_EXT_ID + FILS_REQ_PARAMS_EXT_ID) ++#define FILS_SESSION_EXT_ID 4 ++#define DOT11_MNG_FILS_SESSION (DOT11_MNG_ID_EXT_ID + FILS_SESSION_EXT_ID) ++#define FILS_HLP_CONTAINER_EXT_ID 5 ++#define DOT11_MNG_FILS_HLP_CONTAINER (DOT11_MNG_ID_EXT_ID + FILS_HLP_CONTAINER_EXT_ID) ++#define FILS_WRAPPED_DATA_EXT_ID 8 ++#define DOT11_MNG_FILS_WRAPPED_DATA (DOT11_MNG_ID_EXT_ID + FILS_WRAPPED_DATA_EXT_ID) ++#define FILS_NONCE_EXT_ID 13 ++#define DOT11_MNG_FILS_NONCE (DOT11_MNG_ID_EXT_ID + FILS_NONCE_EXT_ID) ++ ++#define DOT11_MNG_IE_ID_EXT_MATCH(_ie, _id) (\ ++ ((_ie)->id == DOT11_MNG_ID_EXT_ID) && \ ++ ((_ie)->len > 0) && \ ++ ((_id) == ((uint8 *)(_ie) + TLV_HDR_LEN)[0])) ++ ++#define DOT11_MNG_IE_ID_EXT_INIT(_ie, _id, _len) do {\ ++ (_ie)->id = DOT11_MNG_ID_EXT_ID; \ ++ (_ie)->len = _len; \ ++ (_ie)->id_ext = _id; \ ++ } while (0) ++ ++/* Rate Defines */ ++ ++/* Valid rates for the Supported Rates and Extended Supported Rates IEs. ++ * Encoding is the rate in 500kbps units, rouding up for fractional values. ++ * 802.11-2012, section 6.5.5.2, DATA_RATE parameter enumerates all the values. ++ * The rate values cover DSSS, HR/DSSS, ERP, and OFDM phy rates. ++ * The defines below do not cover the rates specific to 10MHz, {3, 4.5, 27}, ++ * and 5MHz, {1.5, 2.25, 3, 4.5, 13.5}, which are not supported by Broadcom devices. ++ */ ++ ++#define DOT11_RATE_1M 2 /* 1 Mbps in 500kbps units */ ++#define DOT11_RATE_2M 4 /* 2 Mbps in 500kbps units */ ++#define DOT11_RATE_5M5 11 /* 5.5 Mbps in 500kbps units */ ++#define DOT11_RATE_11M 22 /* 11 Mbps in 500kbps units */ ++#define DOT11_RATE_6M 12 /* 6 Mbps in 500kbps units */ ++#define DOT11_RATE_9M 18 /* 9 Mbps in 500kbps units */ ++#define DOT11_RATE_12M 24 /* 12 Mbps in 500kbps units */ ++#define DOT11_RATE_18M 36 /* 18 Mbps in 500kbps units */ ++#define DOT11_RATE_24M 48 /* 24 Mbps in 500kbps units */ ++#define DOT11_RATE_36M 72 /* 36 Mbps in 500kbps units */ ++#define DOT11_RATE_48M 96 /* 48 Mbps in 500kbps units */ ++#define DOT11_RATE_54M 108 /* 54 Mbps in 500kbps units */ ++#define DOT11_RATE_MAX 108 /* highest rate (54 Mbps) in 500kbps units */ ++ ++/* Supported Rates and Extended Supported Rates IEs ++ * The supported rates octets are defined a the MSB indicatin a Basic Rate ++ * and bits 0-6 as the rate value ++ */ ++#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */ ++#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ ++ ++/* BSS Membership Selector parameters ++ * 802.11-2016 (and 802.11ax-D1.1), Sec 9.4.2.3 ++ * These selector values are advertised in Supported Rates and Extended Supported Rates IEs ++ * in the supported rates list with the Basic rate bit set. ++ * Constants below include the basic bit. ++ */ ++#define DOT11_BSS_MEMBERSHIP_HT 0xFF /* Basic 0x80 + 127, HT Required to join */ ++#define DOT11_BSS_MEMBERSHIP_VHT 0xFE /* Basic 0x80 + 126, VHT Required to join */ ++#define DOT11_BSS_MEMBERSHIP_HE 0xFD /* Basic 0x80 + 125, HE Required to join */ ++ ++/* ERP info element bit values */ ++#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ ++#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present ++ *in the BSS ++ */ ++#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for ++ *ERP-OFDM frames ++ */ ++#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, ++ * 1 == not allowed ++ */ ++/* TS Delay element offset & size */ ++#define DOT11_MGN_TS_DELAY_LEN 4 /* length of TS DELAY IE */ ++#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */ ++ ++/* Capability Information Field */ ++#define DOT11_CAP_ESS 0x0001 /* d11 cap. ESS */ ++#define DOT11_CAP_IBSS 0x0002 /* d11 cap. IBSS */ ++#define DOT11_CAP_POLLABLE 0x0004 /* d11 cap. pollable */ ++#define DOT11_CAP_POLL_RQ 0x0008 /* d11 cap. poll request */ ++#define DOT11_CAP_PRIVACY 0x0010 /* d11 cap. privacy */ ++#define DOT11_CAP_SHORT 0x0020 /* d11 cap. short */ ++#define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */ ++#define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */ ++#define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */ ++#define DOT11_CAP_QOS 0x0200 /* d11 cap. qos */ ++#define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */ ++#define DOT11_CAP_APSD 0x0800 /* d11 cap. apsd */ ++#define DOT11_CAP_RRM 0x1000 /* d11 cap. 11k radio measurement */ ++#define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */ ++#define DOT11_CAP_DELAY_BA 0x4000 /* d11 cap. delayed block ack */ ++#define DOT11_CAP_IMMEDIATE_BA 0x8000 /* d11 cap. immediate block ack */ ++ ++/* Extended capabilities IE bitfields */ ++/* 20/40 BSS Coexistence Management support bit position */ ++#define DOT11_EXT_CAP_OBSS_COEX_MGMT 0 ++/* Extended Channel Switching support bit position */ ++#define DOT11_EXT_CAP_EXT_CHAN_SWITCHING 2 ++/* scheduled PSMP support bit position */ ++#define DOT11_EXT_CAP_SPSMP 6 ++/* Flexible Multicast Service */ ++#define DOT11_EXT_CAP_FMS 11 ++/* proxy ARP service support bit position */ ++#define DOT11_EXT_CAP_PROXY_ARP 12 ++/* Civic Location */ ++#define DOT11_EXT_CAP_CIVIC_LOC 14 ++/* Geospatial Location */ ++#define DOT11_EXT_CAP_LCI 15 ++/* Traffic Filter Service */ ++#define DOT11_EXT_CAP_TFS 16 ++/* WNM-Sleep Mode */ ++#define DOT11_EXT_CAP_WNM_SLEEP 17 ++/* TIM Broadcast service */ ++#define DOT11_EXT_CAP_TIMBC 18 ++/* BSS Transition Management support bit position */ ++#define DOT11_EXT_CAP_BSSTRANS_MGMT 19 ++/* Direct Multicast Service */ ++#define DOT11_EXT_CAP_DMS 26 ++/* Interworking support bit position */ ++#define DOT11_EXT_CAP_IW 31 ++/* QoS map support bit position */ ++#define DOT11_EXT_CAP_QOS_MAP 32 ++/* service Interval granularity bit position and mask */ ++#define DOT11_EXT_CAP_SI 41 ++#define DOT11_EXT_CAP_SI_MASK 0x0E ++/* Location Identifier service */ ++#define DOT11_EXT_CAP_IDENT_LOC 44 ++/* WNM notification */ ++#define DOT11_EXT_CAP_WNM_NOTIF 46 ++/* Operating mode notification - VHT (11ac D3.0 - 8.4.2.29) */ ++#define DOT11_EXT_CAP_OPER_MODE_NOTIF 62 ++/* Fine timing measurement - D3.0 */ ++#define DOT11_EXT_CAP_FTM_RESPONDER 70 ++#define DOT11_EXT_CAP_FTM_INITIATOR 71 /* tentative 11mcd3.0 */ ++/* TWT support */ ++#define DOT11_EXT_CAP_TWT_REQUESTER 75 ++#define DOT11_EXT_CAP_TWT_RESPONDER 76 ++/* TODO: Update DOT11_EXT_CAP_MAX_IDX to reflect the highest offset. ++ * Note: DOT11_EXT_CAP_MAX_IDX must only be used in attach path. ++ * It will cause ROM invalidation otherwise. ++ */ ++#define DOT11_EXT_CAP_MAX_IDX 76 ++ ++#ifdef WL_FTM ++#define DOT11_EXT_CAP_MAX_BIT_IDX 95 /* !!!update this please!!! */ ++#else ++#define DOT11_EXT_CAP_MAX_BIT_IDX 62 /* !!!update this please!!! */ ++#endif ++/* extended capability */ ++#ifndef DOT11_EXTCAP_LEN_MAX ++#define DOT11_EXTCAP_LEN_MAX ((DOT11_EXT_CAP_MAX_BIT_IDX + 8) >> 3) ++#endif ++BWL_PRE_PACKED_STRUCT struct dot11_extcap { ++ uint8 extcap[DOT11_EXTCAP_LEN_MAX]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_extcap dot11_extcap_t; ++ ++/* VHT Operating mode bit fields - (11ac D8.0/802.11-2016 - 9.4.1.53) */ ++#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0 ++#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3 ++#define DOT11_OPER_MODE_160_8080_BW_SHIFT 2 ++#define DOT11_OPER_MODE_160_8080_BW_MASK 0x04 ++#define DOT11_OPER_MODE_NOLDPC_SHIFT 3 ++#define DOT11_OPER_MODE_NOLDPC_MASK 0x08 ++#define DOT11_OPER_MODE_RXNSS_SHIFT 4 ++#define DOT11_OPER_MODE_RXNSS_MASK 0x70 ++#define DOT11_OPER_MODE_RXNSS_TYPE_SHIFT 7 ++#define DOT11_OPER_MODE_RXNSS_TYPE_MASK 0x80 ++ ++#define DOT11_OPER_MODE(type, nss, chanw) (\ ++ ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ ++ DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ ++ (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ ++ ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ ++ DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) ++ ++#define DOT11_D8_OPER_MODE(type, nss, ldpc, bw160_8080, chanw) (\ ++ ((type) << DOT11_OPER_MODE_RXNSS_TYPE_SHIFT &\ ++ DOT11_OPER_MODE_RXNSS_TYPE_MASK) |\ ++ (((nss) - 1) << DOT11_OPER_MODE_RXNSS_SHIFT & DOT11_OPER_MODE_RXNSS_MASK) |\ ++ ((ldpc) << DOT11_OPER_MODE_NOLDPC_SHIFT & DOT11_OPER_MODE_NOLDPC_MASK) |\ ++ ((bw160_8080) << DOT11_OPER_MODE_160_8080_BW_SHIFT &\ ++ DOT11_OPER_MODE_160_8080_BW_MASK) |\ ++ ((chanw) << DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT &\ ++ DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)) ++ ++#define DOT11_OPER_MODE_CHANNEL_WIDTH(mode) \ ++ (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\ ++ >> DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT) ++#define DOT11_OPER_MODE_160_8080(mode) \ ++ (((mode) & DOT11_OPER_MODE_160_8080_BW_MASK)\ ++ >> DOT11_OPER_MODE_160_8080_BW_SHIFT) ++#define DOT11_OPER_MODE_RXNSS(mode) \ ++ ((((mode) & DOT11_OPER_MODE_RXNSS_MASK) \ ++ >> DOT11_OPER_MODE_RXNSS_SHIFT) + 1) ++#define DOT11_OPER_MODE_RXNSS_TYPE(mode) \ ++ (((mode) & DOT11_OPER_MODE_RXNSS_TYPE_MASK)\ ++ >> DOT11_OPER_MODE_RXNSS_TYPE_SHIFT) ++ ++#define DOT11_OPER_MODE_20MHZ 0 ++#define DOT11_OPER_MODE_40MHZ 1 ++#define DOT11_OPER_MODE_80MHZ 2 ++#define DOT11_OPER_MODE_160MHZ 3 ++#define DOT11_OPER_MODE_8080MHZ 3 ++#define DOT11_OPER_MODE_1608080MHZ 1 ++ ++#define DOT11_OPER_MODE_CHANNEL_WIDTH_20MHZ(mode) (\ ++ ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_20MHZ) ++#define DOT11_OPER_MODE_CHANNEL_WIDTH_40MHZ(mode) (\ ++ ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_40MHZ) ++#define DOT11_OPER_MODE_CHANNEL_WIDTH_80MHZ(mode) (\ ++ ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_80MHZ) ++#define DOT11_OPER_MODE_CHANNEL_WIDTH_160MHZ(mode) (\ ++ ((mode) & DOT11_OPER_MODE_160_8080_BW_MASK)) ++#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\ ++ ((mode) & DOT11_OPER_MODE_160_8080_BW_MASK)) ++ ++/* Operating mode information element 802.11ac D3.0 - 8.4.2.168 */ ++BWL_PRE_PACKED_STRUCT struct dot11_oper_mode_notif_ie { ++ uint8 mode; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_oper_mode_notif_ie dot11_oper_mode_notif_ie_t; ++ ++#define DOT11_OPER_MODE_NOTIF_IE_LEN 1 ++ ++/* Extended Capability Information Field */ ++#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01 /* 20/40 BSS Coexistence Management support */ ++ ++/* ++ * Action Frame Constants ++ */ ++#define DOT11_ACTION_HDR_LEN 2 /* action frame category + action field */ ++#define DOT11_ACTION_CAT_OFF 0 /* category offset */ ++#define DOT11_ACTION_ACT_OFF 1 /* action offset */ ++ ++/* Action Category field (sec 8.4.1.11) */ ++#define DOT11_ACTION_CAT_ERR_MASK 0x80 /* category error mask */ ++#define DOT11_ACTION_CAT_MASK 0x7F /* category mask */ ++#define DOT11_ACTION_CAT_SPECT_MNG 0 /* category spectrum management */ ++#define DOT11_ACTION_CAT_QOS 1 /* category QoS */ ++#define DOT11_ACTION_CAT_DLS 2 /* category DLS */ ++#define DOT11_ACTION_CAT_BLOCKACK 3 /* category block ack */ ++#define DOT11_ACTION_CAT_PUBLIC 4 /* category public */ ++#define DOT11_ACTION_CAT_RRM 5 /* category radio measurements */ ++#define DOT11_ACTION_CAT_FBT 6 /* category fast bss transition */ ++#define DOT11_ACTION_CAT_HT 7 /* category for HT */ ++#define DOT11_ACTION_CAT_SA_QUERY 8 /* security association query */ ++#define DOT11_ACTION_CAT_PDPA 9 /* protected dual of public action */ ++#define DOT11_ACTION_CAT_WNM 10 /* category for WNM */ ++#define DOT11_ACTION_CAT_UWNM 11 /* category for Unprotected WNM */ ++#define DOT11_ACTION_CAT_MESH 13 /* category for Mesh */ ++#define DOT11_ACTION_CAT_SELFPROT 15 /* category for Mesh, self protected */ ++#define DOT11_ACTION_NOTIFICATION 17 ++#define DOT11_ACTION_CAT_VHT 21 /* VHT action */ ++#define DOT11_ACTION_CAT_S1G 22 /* S1G action */ ++#define DOT11_ACTION_CAT_HE 27 /* HE action frame */ ++#define DOT11_ACTION_CAT_FILS 26 /* FILS action frame */ ++#define DOT11_ACTION_CAT_VSP 126 /* protected vendor specific */ ++#define DOT11_ACTION_CAT_VS 127 /* category Vendor Specific */ ++ ++/* Spectrum Management Action IDs (sec 7.4.1) */ ++#define DOT11_SM_ACTION_M_REQ 0 /* d11 action measurement request */ ++#define DOT11_SM_ACTION_M_REP 1 /* d11 action measurement response */ ++#define DOT11_SM_ACTION_TPC_REQ 2 /* d11 action TPC request */ ++#define DOT11_SM_ACTION_TPC_REP 3 /* d11 action TPC response */ ++#define DOT11_SM_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ ++#define DOT11_SM_ACTION_EXT_CSA 5 /* d11 extened CSA for 11n */ ++ ++/* QoS action ids */ ++#define DOT11_QOS_ACTION_ADDTS_REQ 0 /* d11 action ADDTS request */ ++#define DOT11_QOS_ACTION_ADDTS_RESP 1 /* d11 action ADDTS response */ ++#define DOT11_QOS_ACTION_DELTS 2 /* d11 action DELTS */ ++#define DOT11_QOS_ACTION_SCHEDULE 3 /* d11 action schedule */ ++#define DOT11_QOS_ACTION_QOS_MAP 4 /* d11 action QOS map */ ++ ++/* HT action ids */ ++#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */ ++#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */ ++ ++/* Public action ids */ ++#define DOT11_PUB_ACTION_BSS_COEX_MNG 0 /* 20/40 Coexistence Management action id */ ++#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4 /* d11 action channel switch */ ++#define DOT11_PUB_ACTION_VENDOR_SPEC 9 /* Vendor specific */ ++#define DOT11_PUB_ACTION_GAS_CB_REQ 12 /* GAS Comeback Request */ ++#define DOT11_PUB_ACTION_FTM_REQ 32 /* FTM request */ ++#define DOT11_PUB_ACTION_FTM 33 /* FTM measurement */ ++ ++/* Block Ack action types */ ++#define DOT11_BA_ACTION_ADDBA_REQ 0 /* ADDBA Req action frame type */ ++#define DOT11_BA_ACTION_ADDBA_RESP 1 /* ADDBA Resp action frame type */ ++#define DOT11_BA_ACTION_DELBA 2 /* DELBA action frame type */ ++ ++/* ADDBA action parameters */ ++#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 /* AMSDU supported under BA */ ++#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 /* policy mask(ack vs delayed) */ ++#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 /* policy shift */ ++#define DOT11_ADDBA_PARAM_TID_MASK 0x003c /* tid mask */ ++#define DOT11_ADDBA_PARAM_TID_SHIFT 2 /* tid shift */ ++#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 /* buffer size mask */ ++#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 /* buffer size shift */ ++ ++#define DOT11_ADDBA_POLICY_DELAYED 0 /* delayed BA policy */ ++#define DOT11_ADDBA_POLICY_IMMEDIATE 1 /* immediate BA policy */ ++ ++/* Fast Transition action types */ ++#define DOT11_FT_ACTION_FT_RESERVED 0 ++#define DOT11_FT_ACTION_FT_REQ 1 /* FBT request - for over-the-DS FBT */ ++#define DOT11_FT_ACTION_FT_RES 2 /* FBT response - for over-the-DS FBT */ ++#define DOT11_FT_ACTION_FT_CON 3 /* FBT confirm - for OTDS with RRP */ ++#define DOT11_FT_ACTION_FT_ACK 4 /* FBT ack */ ++ ++/* DLS action types */ ++#define DOT11_DLS_ACTION_REQ 0 /* DLS Request */ ++#define DOT11_DLS_ACTION_RESP 1 /* DLS Response */ ++#define DOT11_DLS_ACTION_TD 2 /* DLS Teardown */ ++ ++/* Wireless Network Management (WNM) action types */ ++#define DOT11_WNM_ACTION_EVENT_REQ 0 ++#define DOT11_WNM_ACTION_EVENT_REP 1 ++#define DOT11_WNM_ACTION_DIAG_REQ 2 ++#define DOT11_WNM_ACTION_DIAG_REP 3 ++#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 ++#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 ++#define DOT11_WNM_ACTION_BSSTRANS_QUERY 6 ++#define DOT11_WNM_ACTION_BSSTRANS_REQ 7 ++#define DOT11_WNM_ACTION_BSSTRANS_RESP 8 ++#define DOT11_WNM_ACTION_FMS_REQ 9 ++#define DOT11_WNM_ACTION_FMS_RESP 10 ++#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 ++#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 ++#define DOT11_WNM_ACTION_TFS_REQ 13 ++#define DOT11_WNM_ACTION_TFS_RESP 14 ++#define DOT11_WNM_ACTION_TFS_NOTIFY_REQ 15 ++#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 ++#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 ++#define DOT11_WNM_ACTION_TIMBC_REQ 18 ++#define DOT11_WNM_ACTION_TIMBC_RESP 19 ++#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 ++#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 ++#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 ++#define DOT11_WNM_ACTION_DMS_REQ 23 ++#define DOT11_WNM_ACTION_DMS_RESP 24 ++#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 ++#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 ++#define DOT11_WNM_ACTION_NOTFCTN_RESP 27 ++#define DOT11_WNM_ACTION_TFS_NOTIFY_RESP 28 ++ ++/* Unprotected Wireless Network Management (WNM) action types */ ++#define DOT11_UWNM_ACTION_TIM 0 ++#define DOT11_UWNM_ACTION_TIMING_MEASUREMENT 1 ++ ++#define DOT11_MNG_COUNTRY_ID_LEN 3 ++ ++/* VHT category action types - 802.11ac D3.0 - 8.5.23.1 */ ++#define DOT11_VHT_ACTION_CBF 0 /* Compressed Beamforming */ ++#define DOT11_VHT_ACTION_GID_MGMT 1 /* Group ID Management */ ++#define DOT11_VHT_ACTION_OPER_MODE_NOTIF 2 /* Operating mode notif'n */ ++ ++/* FILS category action types - 802.11ai D11.0 - 9.6.8.1 */ ++#define DOT11_FILS_ACTION_DISCOVERY 34 /* FILS Discovery */ ++ ++/** DLS Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_dls_req { ++ uint8 category; /* category of action frame (2) */ ++ uint8 action; /* DLS action: req (0) */ ++ struct ether_addr da; /* destination address */ ++ struct ether_addr sa; /* source address */ ++ uint16 cap; /* capability */ ++ uint16 timeout; /* timeout value */ ++ uint8 data[1]; /* IE:support rate, extend support rate, HT cap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dls_req dot11_dls_req_t; ++#define DOT11_DLS_REQ_LEN 18 /* Fixed length */ ++ ++/** DLS response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_dls_resp { ++ uint8 category; /* category of action frame (2) */ ++ uint8 action; /* DLS action: req (0) */ ++ uint16 status; /* status code field */ ++ struct ether_addr da; /* destination address */ ++ struct ether_addr sa; /* source address */ ++ uint8 data[1]; /* optional: capability, rate ... */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dls_resp dot11_dls_resp_t; ++#define DOT11_DLS_RESP_LEN 16 /* Fixed length */ ++ ++ ++/* ************* 802.11v related definitions. ************* */ ++ ++/** BSS Management Transition Query frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_query { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: trans_query (6) */ ++ uint8 token; /* dialog token */ ++ uint8 reason; /* transition query reason */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_bsstrans_query dot11_bsstrans_query_t; ++#define DOT11_BSSTRANS_QUERY_LEN 4 /* Fixed length */ ++ ++/* BTM transition reason */ ++#define DOT11_BSSTRANS_REASON_UNSPECIFIED 0 ++#define DOT11_BSSTRANS_REASON_EXC_FRAME_LOSS 1 ++#define DOT11_BSSTRANS_REASON_EXC_TRAFFIC_DELAY 2 ++#define DOT11_BSSTRANS_REASON_INSUFF_QOS_CAPACITY 3 ++#define DOT11_BSSTRANS_REASON_FIRST_ASSOC 4 ++#define DOT11_BSSTRANS_REASON_LOAD_BALANCING 5 ++#define DOT11_BSSTRANS_REASON_BETTER_AP_FOUND 6 ++#define DOT11_BSSTRANS_REASON_DEAUTH_RX 7 ++#define DOT11_BSSTRANS_REASON_8021X_EAP_AUTH_FAIL 8 ++#define DOT11_BSSTRANS_REASON_4WAY_HANDSHK_FAIL 9 ++#define DOT11_BSSTRANS_REASON_MANY_REPLAYCNT_FAIL 10 ++#define DOT11_BSSTRANS_REASON_MANY_DATAMIC_FAIL 11 ++#define DOT11_BSSTRANS_REASON_EXCEED_MAX_RETRANS 12 ++#define DOT11_BSSTRANS_REASON_MANY_BCAST_DISASSOC_RX 13 ++#define DOT11_BSSTRANS_REASON_MANY_BCAST_DEAUTH_RX 14 ++#define DOT11_BSSTRANS_REASON_PREV_TRANSITION_FAIL 15 ++#define DOT11_BSSTRANS_REASON_LOW_RSSI 16 ++#define DOT11_BSSTRANS_REASON_ROAM_FROM_NON_80211 17 ++#define DOT11_BSSTRANS_REASON_RX_BTM_REQ 18 ++#define DOT11_BSSTRANS_REASON_PREF_LIST_INCLUDED 19 ++#define DOT11_BSSTRANS_REASON_LEAVING_ESS 20 ++ ++/** BSS Management Transition Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_req { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: trans_req (7) */ ++ uint8 token; /* dialog token */ ++ uint8 reqmode; /* transition request mode */ ++ uint16 disassoc_tmr; /* disassociation timer */ ++ uint8 validity_intrvl; /* validity interval */ ++ uint8 data[1]; /* optional: BSS term duration, ... */ ++ /* ...session info URL, candidate list */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_bsstrans_req dot11_bsstrans_req_t; ++#define DOT11_BSSTRANS_REQ_LEN 7 /* Fixed length */ ++ ++/* BSS Mgmt Transition Request Mode Field - 802.11v */ ++#define DOT11_BSSTRANS_REQMODE_PREF_LIST_INCL 0x01 ++#define DOT11_BSSTRANS_REQMODE_ABRIDGED 0x02 ++#define DOT11_BSSTRANS_REQMODE_DISASSOC_IMMINENT 0x04 ++#define DOT11_BSSTRANS_REQMODE_BSS_TERM_INCL 0x08 ++#define DOT11_BSSTRANS_REQMODE_ESS_DISASSOC_IMNT 0x10 ++ ++/** BSS Management transition response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_bsstrans_resp { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: trans_resp (8) */ ++ uint8 token; /* dialog token */ ++ uint8 status; /* transition status */ ++ uint8 term_delay; /* validity interval */ ++ uint8 data[1]; /* optional: BSSID target, candidate list */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_bsstrans_resp dot11_bsstrans_resp_t; ++#define DOT11_BSSTRANS_RESP_LEN 5 /* Fixed length */ ++ ++/* BSS Mgmt Transition Response Status Field */ ++#define DOT11_BSSTRANS_RESP_STATUS_ACCEPT 0 ++#define DOT11_BSSTRANS_RESP_STATUS_REJECT 1 ++#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_BCN 2 ++#define DOT11_BSSTRANS_RESP_STATUS_REJ_INSUFF_CAP 3 ++#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_UNDESIRED 4 ++#define DOT11_BSSTRANS_RESP_STATUS_REJ_TERM_DELAY_REQ 5 ++#define DOT11_BSSTRANS_RESP_STATUS_REJ_BSS_LIST_PROVIDED 6 ++#define DOT11_BSSTRANS_RESP_STATUS_REJ_NO_SUITABLE_BSS 7 ++#define DOT11_BSSTRANS_RESP_STATUS_REJ_LEAVING_ESS 8 ++ ++ ++/** BSS Max Idle Period element */ ++BWL_PRE_PACKED_STRUCT struct dot11_bss_max_idle_period_ie { ++ uint8 id; /* 90, DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID */ ++ uint8 len; ++ uint16 max_idle_period; /* in unit of 1000 TUs */ ++ uint8 idle_opt; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_bss_max_idle_period_ie dot11_bss_max_idle_period_ie_t; ++#define DOT11_BSS_MAX_IDLE_PERIOD_IE_LEN 3 /* bss max idle period IE size */ ++#define DOT11_BSS_MAX_IDLE_PERIOD_OPT_PROTECTED 1 /* BSS max idle option */ ++ ++/** TIM Broadcast request element */ ++BWL_PRE_PACKED_STRUCT struct dot11_timbc_req_ie { ++ uint8 id; /* 94, DOT11_MNG_TIMBC_REQ_ID */ ++ uint8 len; ++ uint8 interval; /* in unit of beacon interval */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_timbc_req_ie dot11_timbc_req_ie_t; ++#define DOT11_TIMBC_REQ_IE_LEN 1 /* Fixed length */ ++ ++/** TIM Broadcast request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_timbc_req { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: DOT11_WNM_ACTION_TIMBC_REQ(18) */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; /* TIM broadcast request element */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_timbc_req dot11_timbc_req_t; ++#define DOT11_TIMBC_REQ_LEN 3 /* Fixed length */ ++ ++/** TIM Broadcast response element */ ++BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp_ie { ++ uint8 id; /* 95, DOT11_MNG_TIM_BROADCAST_RESP_ID */ ++ uint8 len; ++ uint8 status; /* status of add request */ ++ uint8 interval; /* in unit of beacon interval */ ++ int32 offset; /* in unit of ms */ ++ uint16 high_rate; /* in unit of 0.5 Mb/s */ ++ uint16 low_rate; /* in unit of 0.5 Mb/s */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_timbc_resp_ie dot11_timbc_resp_ie_t; ++#define DOT11_TIMBC_DENY_RESP_IE_LEN 1 /* Deny. Fixed length */ ++#define DOT11_TIMBC_ACCEPT_RESP_IE_LEN 10 /* Accept. Fixed length */ ++ ++#define DOT11_TIMBC_STATUS_ACCEPT 0 ++#define DOT11_TIMBC_STATUS_ACCEPT_TSTAMP 1 ++#define DOT11_TIMBC_STATUS_DENY 2 ++#define DOT11_TIMBC_STATUS_OVERRIDDEN 3 ++#define DOT11_TIMBC_STATUS_RESERVED 4 ++ ++/** TIM Broadcast request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_timbc_resp { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* action: DOT11_WNM_ACTION_TIMBC_RESP(19) */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; /* TIM broadcast response element */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_timbc_resp dot11_timbc_resp_t; ++#define DOT11_TIMBC_RESP_LEN 3 /* Fixed length */ ++ ++/** TIM element */ ++BWL_PRE_PACKED_STRUCT struct dot11_tim_ie { ++ uint8 id; /* 5, DOT11_MNG_TIM_ID */ ++ uint8 len; /* 4 - 255 */ ++ uint8 dtim_count; /* DTIM decrementing counter */ ++ uint8 dtim_period; /* DTIM period */ ++ uint8 bitmap_control; /* AID 0 + bitmap offset */ ++ uint8 pvb[1]; /* Partial Virtual Bitmap, variable length */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tim_ie dot11_tim_ie_t; ++#define DOT11_TIM_IE_FIXED_LEN 3 /* Fixed length, without id and len */ ++#define DOT11_TIM_IE_FIXED_TOTAL_LEN 5 /* Fixed length, with id and len */ ++ ++/** TIM Broadcast frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_timbc { ++ uint8 category; /* category of action frame (11) */ ++ uint8 action; /* action: TIM (0) */ ++ uint8 check_beacon; /* need to check-beacon */ ++ uint8 tsf[8]; /* Time Synchronization Function */ ++ dot11_tim_ie_t tim_ie; /* TIM element */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_timbc dot11_timbc_t; ++#define DOT11_TIMBC_HDR_LEN (sizeof(dot11_timbc_t) - sizeof(dot11_tim_ie_t)) ++#define DOT11_TIMBC_FIXED_LEN (sizeof(dot11_timbc_t) - 1) /* Fixed length */ ++#define DOT11_TIMBC_LEN 11 /* Fixed length */ ++ ++/** TCLAS frame classifier type */ ++BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_hdr { ++ uint8 type; ++ uint8 mask; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tclas_fc_hdr dot11_tclas_fc_hdr_t; ++#define DOT11_TCLAS_FC_HDR_LEN 2 /* Fixed length */ ++ ++#define DOT11_TCLAS_MASK_0 0x1 ++#define DOT11_TCLAS_MASK_1 0x2 ++#define DOT11_TCLAS_MASK_2 0x4 ++#define DOT11_TCLAS_MASK_3 0x8 ++#define DOT11_TCLAS_MASK_4 0x10 ++#define DOT11_TCLAS_MASK_5 0x20 ++#define DOT11_TCLAS_MASK_6 0x40 ++#define DOT11_TCLAS_MASK_7 0x80 ++ ++#define DOT11_TCLAS_FC_0_ETH 0 ++#define DOT11_TCLAS_FC_1_IP 1 ++#define DOT11_TCLAS_FC_2_8021Q 2 ++#define DOT11_TCLAS_FC_3_OFFSET 3 ++#define DOT11_TCLAS_FC_4_IP_HIGHER 4 ++#define DOT11_TCLAS_FC_5_8021D 5 ++ ++/** TCLAS frame classifier type 0 parameters for Ethernet */ ++BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_0_eth { ++ uint8 type; ++ uint8 mask; ++ uint8 sa[ETHER_ADDR_LEN]; ++ uint8 da[ETHER_ADDR_LEN]; ++ uint16 eth_type; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tclas_fc_0_eth dot11_tclas_fc_0_eth_t; ++#define DOT11_TCLAS_FC_0_ETH_LEN 16 ++ ++/** TCLAS frame classifier type 1 parameters for IPV4 */ ++BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_1_ipv4 { ++ uint8 type; ++ uint8 mask; ++ uint8 version; ++ uint32 src_ip; ++ uint32 dst_ip; ++ uint16 src_port; ++ uint16 dst_port; ++ uint8 dscp; ++ uint8 protocol; ++ uint8 reserved; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_1_ipv4_t; ++#define DOT11_TCLAS_FC_1_IPV4_LEN 18 ++ ++/** TCLAS frame classifier type 2 parameters for 802.1Q */ ++BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_2_8021q { ++ uint8 type; ++ uint8 mask; ++ uint16 tci; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tclas_fc_2_8021q dot11_tclas_fc_2_8021q_t; ++#define DOT11_TCLAS_FC_2_8021Q_LEN 4 ++ ++/** TCLAS frame classifier type 3 parameters for filter offset */ ++BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_3_filter { ++ uint8 type; ++ uint8 mask; ++ uint16 offset; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tclas_fc_3_filter dot11_tclas_fc_3_filter_t; ++#define DOT11_TCLAS_FC_3_FILTER_LEN 4 ++ ++/** TCLAS frame classifier type 4 parameters for IPV4 is the same as TCLAS type 1 */ ++typedef struct dot11_tclas_fc_1_ipv4 dot11_tclas_fc_4_ipv4_t; ++#define DOT11_TCLAS_FC_4_IPV4_LEN DOT11_TCLAS_FC_1_IPV4_LEN ++ ++/** TCLAS frame classifier type 4 parameters for IPV6 */ ++BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_4_ipv6 { ++ uint8 type; ++ uint8 mask; ++ uint8 version; ++ uint8 saddr[16]; ++ uint8 daddr[16]; ++ uint16 src_port; ++ uint16 dst_port; ++ uint8 dscp; ++ uint8 nexthdr; ++ uint8 flow_lbl[3]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tclas_fc_4_ipv6 dot11_tclas_fc_4_ipv6_t; ++#define DOT11_TCLAS_FC_4_IPV6_LEN 44 ++ ++/** TCLAS frame classifier type 5 parameters for 802.1D */ ++BWL_PRE_PACKED_STRUCT struct dot11_tclas_fc_5_8021d { ++ uint8 type; ++ uint8 mask; ++ uint8 pcp; ++ uint8 cfi; ++ uint16 vid; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tclas_fc_5_8021d dot11_tclas_fc_5_8021d_t; ++#define DOT11_TCLAS_FC_5_8021D_LEN 6 ++ ++/** TCLAS frame classifier type parameters */ ++BWL_PRE_PACKED_STRUCT union dot11_tclas_fc { ++ uint8 data[1]; ++ dot11_tclas_fc_hdr_t hdr; ++ dot11_tclas_fc_0_eth_t t0_eth; ++ dot11_tclas_fc_1_ipv4_t t1_ipv4; ++ dot11_tclas_fc_2_8021q_t t2_8021q; ++ dot11_tclas_fc_3_filter_t t3_filter; ++ dot11_tclas_fc_4_ipv4_t t4_ipv4; ++ dot11_tclas_fc_4_ipv6_t t4_ipv6; ++ dot11_tclas_fc_5_8021d_t t5_8021d; ++} BWL_POST_PACKED_STRUCT; ++typedef union dot11_tclas_fc dot11_tclas_fc_t; ++ ++#define DOT11_TCLAS_FC_MIN_LEN 4 /* Classifier Type 2 has the min size */ ++#define DOT11_TCLAS_FC_MAX_LEN 254 ++ ++/** TCLAS element */ ++BWL_PRE_PACKED_STRUCT struct dot11_tclas_ie { ++ uint8 id; /* 14, DOT11_MNG_TCLAS_ID */ ++ uint8 len; ++ uint8 user_priority; ++ dot11_tclas_fc_t fc; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tclas_ie dot11_tclas_ie_t; ++#define DOT11_TCLAS_IE_LEN 3 /* Fixed length, include id and len */ ++ ++/** TCLAS processing element */ ++BWL_PRE_PACKED_STRUCT struct dot11_tclas_proc_ie { ++ uint8 id; /* 44, DOT11_MNG_TCLAS_PROC_ID */ ++ uint8 len; ++ uint8 process; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tclas_proc_ie dot11_tclas_proc_ie_t; ++#define DOT11_TCLAS_PROC_IE_LEN 3 /* Fixed length, include id and len */ ++ ++#define DOT11_TCLAS_PROC_MATCHALL 0 /* All high level element need to match */ ++#define DOT11_TCLAS_PROC_MATCHONE 1 /* One high level element need to match */ ++#define DOT11_TCLAS_PROC_NONMATCH 2 /* Non match to any high level element */ ++ ++ ++/* TSPEC element defined in 802.11 std section 8.4.2.32 - Not supported */ ++#define DOT11_TSPEC_IE_LEN 57 /* Fixed length */ ++ ++/** TFS request element */ ++BWL_PRE_PACKED_STRUCT struct dot11_tfs_req_ie { ++ uint8 id; /* 91, DOT11_MNG_TFS_REQUEST_ID */ ++ uint8 len; ++ uint8 tfs_id; ++ uint8 actcode; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tfs_req_ie dot11_tfs_req_ie_t; ++#define DOT11_TFS_REQ_IE_LEN 2 /* Fixed length, without id and len */ ++ ++/** TFS request action codes (bitfield) */ ++#define DOT11_TFS_ACTCODE_DELETE 1 ++#define DOT11_TFS_ACTCODE_NOTIFY 2 ++ ++/** TFS request subelement IDs */ ++#define DOT11_TFS_REQ_TFS_SE_ID 1 ++#define DOT11_TFS_REQ_VENDOR_SE_ID 221 ++ ++/** TFS subelement */ ++BWL_PRE_PACKED_STRUCT struct dot11_tfs_se { ++ uint8 sub_id; ++ uint8 len; ++ uint8 data[1]; /* TCLAS element(s) + optional TCLAS proc */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tfs_se dot11_tfs_se_t; ++ ++ ++/** TFS response element */ ++BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp_ie { ++ uint8 id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ ++ uint8 len; ++ uint8 tfs_id; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tfs_resp_ie dot11_tfs_resp_ie_t; ++#define DOT11_TFS_RESP_IE_LEN 1 /* Fixed length, without id and len */ ++ ++/** TFS response subelement IDs (same subelments, but different IDs than in TFS request */ ++#define DOT11_TFS_RESP_TFS_STATUS_SE_ID 1 ++#define DOT11_TFS_RESP_TFS_SE_ID 2 ++#define DOT11_TFS_RESP_VENDOR_SE_ID 221 ++ ++/** TFS status subelement */ ++BWL_PRE_PACKED_STRUCT struct dot11_tfs_status_se { ++ uint8 sub_id; /* 92, DOT11_MNG_TFS_RESPONSE_ID */ ++ uint8 len; ++ uint8 resp_st; ++ uint8 data[1]; /* Potential dot11_tfs_se_t included */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tfs_status_se dot11_tfs_status_se_t; ++#define DOT11_TFS_STATUS_SE_LEN 1 /* Fixed length, without id and len */ ++ ++/* Following Definition should be merged to FMS_TFS macro below */ ++/* TFS Response status code. Identical to FMS Element status, without N/A */ ++#define DOT11_TFS_STATUS_ACCEPT 0 ++#define DOT11_TFS_STATUS_DENY_FORMAT 1 ++#define DOT11_TFS_STATUS_DENY_RESOURCE 2 ++#define DOT11_TFS_STATUS_DENY_POLICY 4 ++#define DOT11_TFS_STATUS_DENY_UNSPECIFIED 5 ++#define DOT11_TFS_STATUS_ALTPREF_POLICY 7 ++#define DOT11_TFS_STATUS_ALTPREF_TCLAS_UNSUPP 14 ++ ++/* FMS Element Status and TFS Response Status Definition */ ++#define DOT11_FMS_TFS_STATUS_ACCEPT 0 ++#define DOT11_FMS_TFS_STATUS_DENY_FORMAT 1 ++#define DOT11_FMS_TFS_STATUS_DENY_RESOURCE 2 ++#define DOT11_FMS_TFS_STATUS_DENY_MULTIPLE_DI 3 ++#define DOT11_FMS_TFS_STATUS_DENY_POLICY 4 ++#define DOT11_FMS_TFS_STATUS_DENY_UNSPECIFIED 5 ++#define DOT11_FMS_TFS_STATUS_ALT_DIFF_DI 6 ++#define DOT11_FMS_TFS_STATUS_ALT_POLICY 7 ++#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_DI 8 ++#define DOT11_FMS_TFS_STATUS_ALT_MCRATE 9 ++#define DOT11_FMS_TFS_STATUS_TERM_POLICY 10 ++#define DOT11_FMS_TFS_STATUS_TERM_RESOURCE 11 ++#define DOT11_FMS_TFS_STATUS_TERM_HIGHER_PRIO 12 ++#define DOT11_FMS_TFS_STATUS_ALT_CHANGE_MDI 13 ++#define DOT11_FMS_TFS_STATUS_ALT_TCLAS_UNSUPP 14 ++ ++/** TFS Management Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_tfs_req { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: TFS request (13) */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tfs_req dot11_tfs_req_t; ++#define DOT11_TFS_REQ_LEN 3 /* Fixed length */ ++ ++/** TFS Management Response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_tfs_resp { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: TFS request (14) */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tfs_resp dot11_tfs_resp_t; ++#define DOT11_TFS_RESP_LEN 3 /* Fixed length */ ++ ++/** TFS Management Notify frame request header */ ++BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_req { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: TFS notify request (15) */ ++ uint8 tfs_id_cnt; /* TFS IDs count */ ++ uint8 tfs_id[1]; /* Array of TFS IDs */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tfs_notify_req dot11_tfs_notify_req_t; ++#define DOT11_TFS_NOTIFY_REQ_LEN 3 /* Fixed length */ ++ ++/** TFS Management Notify frame response header */ ++BWL_PRE_PACKED_STRUCT struct dot11_tfs_notify_resp { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: TFS notify response (28) */ ++ uint8 tfs_id_cnt; /* TFS IDs count */ ++ uint8 tfs_id[1]; /* Array of TFS IDs */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tfs_notify_resp dot11_tfs_notify_resp_t; ++#define DOT11_TFS_NOTIFY_RESP_LEN 3 /* Fixed length */ ++ ++ ++/** WNM-Sleep Management Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_req { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: wnm-sleep request (16) */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_wnm_sleep_req dot11_wnm_sleep_req_t; ++#define DOT11_WNM_SLEEP_REQ_LEN 3 /* Fixed length */ ++ ++/** WNM-Sleep Management Response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_resp { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: wnm-sleep request (17) */ ++ uint8 token; /* dialog token */ ++ uint16 key_len; /* key data length */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_wnm_sleep_resp dot11_wnm_sleep_resp_t; ++#define DOT11_WNM_SLEEP_RESP_LEN 5 /* Fixed length */ ++ ++#define DOT11_WNM_SLEEP_SUBELEM_ID_GTK 0 ++#define DOT11_WNM_SLEEP_SUBELEM_ID_IGTK 1 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_gtk { ++ uint8 sub_id; ++ uint8 len; ++ uint16 key_info; ++ uint8 key_length; ++ uint8 rsc[8]; ++ uint8 key[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_wnm_sleep_subelem_gtk dot11_wnm_sleep_subelem_gtk_t; ++#define DOT11_WNM_SLEEP_SUBELEM_GTK_FIXED_LEN 11 /* without sub_id, len, and key */ ++#define DOT11_WNM_SLEEP_SUBELEM_GTK_MAX_LEN 43 /* without sub_id and len */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_subelem_igtk { ++ uint8 sub_id; ++ uint8 len; ++ uint16 key_id; ++ uint8 pn[6]; ++ uint8 key[16]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_wnm_sleep_subelem_igtk dot11_wnm_sleep_subelem_igtk_t; ++#define DOT11_WNM_SLEEP_SUBELEM_IGTK_LEN 24 /* Fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_wnm_sleep_ie { ++ uint8 id; /* 93, DOT11_MNG_WNM_SLEEP_MODE_ID */ ++ uint8 len; ++ uint8 act_type; ++ uint8 resp_status; ++ uint16 interval; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_wnm_sleep_ie dot11_wnm_sleep_ie_t; ++#define DOT11_WNM_SLEEP_IE_LEN 4 /* Fixed length */ ++ ++#define DOT11_WNM_SLEEP_ACT_TYPE_ENTER 0 ++#define DOT11_WNM_SLEEP_ACT_TYPE_EXIT 1 ++ ++#define DOT11_WNM_SLEEP_RESP_ACCEPT 0 ++#define DOT11_WNM_SLEEP_RESP_UPDATE 1 ++#define DOT11_WNM_SLEEP_RESP_DENY 2 ++#define DOT11_WNM_SLEEP_RESP_DENY_TEMP 3 ++#define DOT11_WNM_SLEEP_RESP_DENY_KEY 4 ++#define DOT11_WNM_SLEEP_RESP_DENY_INUSE 5 ++#define DOT11_WNM_SLEEP_RESP_LAST 6 ++ ++/** DMS Management Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_dms_req { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: dms request (23) */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dms_req dot11_dms_req_t; ++#define DOT11_DMS_REQ_LEN 3 /* Fixed length */ ++ ++/** DMS Management Response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_dms_resp { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: dms request (24) */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dms_resp dot11_dms_resp_t; ++#define DOT11_DMS_RESP_LEN 3 /* Fixed length */ ++ ++/** DMS request element */ ++BWL_PRE_PACKED_STRUCT struct dot11_dms_req_ie { ++ uint8 id; /* 99, DOT11_MNG_DMS_REQUEST_ID */ ++ uint8 len; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dms_req_ie dot11_dms_req_ie_t; ++#define DOT11_DMS_REQ_IE_LEN 2 /* Fixed length */ ++ ++/** DMS response element */ ++BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_ie { ++ uint8 id; /* 100, DOT11_MNG_DMS_RESPONSE_ID */ ++ uint8 len; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dms_resp_ie dot11_dms_resp_ie_t; ++#define DOT11_DMS_RESP_IE_LEN 2 /* Fixed length */ ++ ++/** DMS request descriptor */ ++BWL_PRE_PACKED_STRUCT struct dot11_dms_req_desc { ++ uint8 dms_id; ++ uint8 len; ++ uint8 type; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dms_req_desc dot11_dms_req_desc_t; ++#define DOT11_DMS_REQ_DESC_LEN 3 /* Fixed length */ ++ ++#define DOT11_DMS_REQ_TYPE_ADD 0 ++#define DOT11_DMS_REQ_TYPE_REMOVE 1 ++#define DOT11_DMS_REQ_TYPE_CHANGE 2 ++ ++/** DMS response status */ ++BWL_PRE_PACKED_STRUCT struct dot11_dms_resp_st { ++ uint8 dms_id; ++ uint8 len; ++ uint8 type; ++ uint16 lsc; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_dms_resp_st dot11_dms_resp_st_t; ++#define DOT11_DMS_RESP_STATUS_LEN 5 /* Fixed length */ ++ ++#define DOT11_DMS_RESP_TYPE_ACCEPT 0 ++#define DOT11_DMS_RESP_TYPE_DENY 1 ++#define DOT11_DMS_RESP_TYPE_TERM 2 ++ ++#define DOT11_DMS_RESP_LSC_UNSUPPORTED 0xFFFF ++ ++/** WNM-Notification Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_wnm_notif_req { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: Notification request (26) */ ++ uint8 token; /* dialog token */ ++ uint8 type; /* type */ ++ uint8 data[1]; /* Sub-elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_wnm_notif_req dot11_wnm_notif_req_t; ++#define DOT11_WNM_NOTIF_REQ_LEN 4 /* Fixed length */ ++ ++/** FMS Management Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_fms_req { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: fms request (9) */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_fms_req dot11_fms_req_t; ++#define DOT11_FMS_REQ_LEN 3 /* Fixed length */ ++ ++/** FMS Management Response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_fms_resp { ++ uint8 category; /* category of action frame (10) */ ++ uint8 action; /* WNM action: fms request (10) */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_fms_resp dot11_fms_resp_t; ++#define DOT11_FMS_RESP_LEN 3 /* Fixed length */ ++ ++/** FMS Descriptor element */ ++BWL_PRE_PACKED_STRUCT struct dot11_fms_desc { ++ uint8 id; ++ uint8 len; ++ uint8 num_fms_cnt; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_fms_desc dot11_fms_desc_t; ++#define DOT11_FMS_DESC_LEN 1 /* Fixed length */ ++ ++#define DOT11_FMS_CNTR_MAX 0x8 ++#define DOT11_FMS_CNTR_ID_MASK 0x7 ++#define DOT11_FMS_CNTR_ID_SHIFT 0x0 ++#define DOT11_FMS_CNTR_COUNT_MASK 0xf1 ++#define DOT11_FMS_CNTR_SHIFT 0x3 ++ ++/** FMS request element */ ++BWL_PRE_PACKED_STRUCT struct dot11_fms_req_ie { ++ uint8 id; ++ uint8 len; ++ uint8 fms_token; /* token used to identify fms stream set */ ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_fms_req_ie dot11_fms_req_ie_t; ++#define DOT11_FMS_REQ_IE_FIX_LEN 1 /* Fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rate_id_field { ++ uint8 mask; ++ uint8 mcs_idx; ++ uint16 rate; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rate_id_field dot11_rate_id_field_t; ++#define DOT11_RATE_ID_FIELD_MCS_SEL_MASK 0x7 ++#define DOT11_RATE_ID_FIELD_MCS_SEL_OFFSET 0 ++#define DOT11_RATE_ID_FIELD_RATETYPE_MASK 0x18 ++#define DOT11_RATE_ID_FIELD_RATETYPE_OFFSET 3 ++#define DOT11_RATE_ID_FIELD_LEN sizeof(dot11_rate_id_field_t) ++ ++/** FMS request subelements */ ++BWL_PRE_PACKED_STRUCT struct dot11_fms_se { ++ uint8 sub_id; ++ uint8 len; ++ uint8 interval; ++ uint8 max_interval; ++ dot11_rate_id_field_t rate; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_fms_se dot11_fms_se_t; ++#define DOT11_FMS_REQ_SE_LEN 6 /* Fixed length */ ++ ++#define DOT11_FMS_REQ_SE_ID_FMS 1 /* FMS subelement */ ++#define DOT11_FMS_REQ_SE_ID_VS 221 /* Vendor Specific subelement */ ++ ++/** FMS response element */ ++BWL_PRE_PACKED_STRUCT struct dot11_fms_resp_ie { ++ uint8 id; ++ uint8 len; ++ uint8 fms_token; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_fms_resp_ie dot11_fms_resp_ie_t; ++#define DOT11_FMS_RESP_IE_FIX_LEN 1 /* Fixed length */ ++ ++/* FMS status subelements */ ++#define DOT11_FMS_STATUS_SE_ID_FMS 1 /* FMS Status */ ++#define DOT11_FMS_STATUS_SE_ID_TCLAS 2 /* TCLAS Status */ ++#define DOT11_FMS_STATUS_SE_ID_VS 221 /* Vendor Specific subelement */ ++ ++/** FMS status subelement */ ++BWL_PRE_PACKED_STRUCT struct dot11_fms_status_se { ++ uint8 sub_id; ++ uint8 len; ++ uint8 status; ++ uint8 interval; ++ uint8 max_interval; ++ uint8 fmsid; ++ uint8 counter; ++ dot11_rate_id_field_t rate; ++ uint8 mcast_addr[ETHER_ADDR_LEN]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_fms_status_se dot11_fms_status_se_t; ++#define DOT11_FMS_STATUS_SE_LEN 15 /* Fixed length */ ++ ++/** TCLAS status subelement */ ++BWL_PRE_PACKED_STRUCT struct dot11_tclas_status_se { ++ uint8 sub_id; ++ uint8 len; ++ uint8 fmsid; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_tclas_status_se dot11_tclas_status_se_t; ++#define DOT11_TCLAS_STATUS_SE_LEN 1 /* Fixed length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_addba_req { ++ uint8 category; /* category of action frame (3) */ ++ uint8 action; /* action: addba req */ ++ uint8 token; /* identifier */ ++ uint16 addba_param_set; /* parameter set */ ++ uint16 timeout; /* timeout in seconds */ ++ uint16 start_seqnum; /* starting sequence number */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_addba_req dot11_addba_req_t; ++#define DOT11_ADDBA_REQ_LEN 9 /* length of addba req frame */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_addba_resp { ++ uint8 category; /* category of action frame (3) */ ++ uint8 action; /* action: addba resp */ ++ uint8 token; /* identifier */ ++ uint16 status; /* status of add request */ ++ uint16 addba_param_set; /* negotiated parameter set */ ++ uint16 timeout; /* negotiated timeout in seconds */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_addba_resp dot11_addba_resp_t; ++#define DOT11_ADDBA_RESP_LEN 9 /* length of addba resp frame */ ++ ++/* DELBA action parameters */ ++#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 /* initiator mask */ ++#define DOT11_DELBA_PARAM_INIT_SHIFT 11 /* initiator shift */ ++#define DOT11_DELBA_PARAM_TID_MASK 0xf000 /* tid mask */ ++#define DOT11_DELBA_PARAM_TID_SHIFT 12 /* tid shift */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_delba { ++ uint8 category; /* category of action frame (3) */ ++ uint8 action; /* action: addba req */ ++ uint16 delba_param_set; /* paarmeter set */ ++ uint16 reason; /* reason for dellba */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_delba dot11_delba_t; ++#define DOT11_DELBA_LEN 6 /* length of delba frame */ ++ ++/* SA Query action field value */ ++#define SA_QUERY_REQUEST 0 ++#define SA_QUERY_RESPONSE 1 ++ ++/* ************* 802.11r related definitions. ************* */ ++ ++/** Over-the-DS Fast Transition Request frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_ft_req { ++ uint8 category; /* category of action frame (6) */ ++ uint8 action; /* action: ft req */ ++ uint8 sta_addr[ETHER_ADDR_LEN]; ++ uint8 tgt_ap_addr[ETHER_ADDR_LEN]; ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ft_req dot11_ft_req_t; ++#define DOT11_FT_REQ_FIXED_LEN 14 ++ ++/** Over-the-DS Fast Transition Response frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_ft_res { ++ uint8 category; /* category of action frame (6) */ ++ uint8 action; /* action: ft resp */ ++ uint8 sta_addr[ETHER_ADDR_LEN]; ++ uint8 tgt_ap_addr[ETHER_ADDR_LEN]; ++ uint16 status; /* status code */ ++ uint8 data[1]; /* Elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ft_res dot11_ft_res_t; ++#define DOT11_FT_RES_FIXED_LEN 16 ++ ++/** RDE RIC Data Element. */ ++BWL_PRE_PACKED_STRUCT struct dot11_rde_ie { ++ uint8 id; /* 11r, DOT11_MNG_RDE_ID */ ++ uint8 length; ++ uint8 rde_id; /* RDE identifier. */ ++ uint8 rd_count; /* Resource Descriptor Count. */ ++ uint16 status; /* Status Code. */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rde_ie dot11_rde_ie_t; ++ ++/* 11r - Size of the RDE (RIC Data Element) IE, including TLV header. */ ++#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t) ++ ++ ++/* ************* 802.11k related definitions. ************* */ ++ ++/* Radio measurements enabled capability ie */ ++#define DOT11_RRM_CAP_LEN 5 /* length of rrm cap bitmap */ ++#define RCPI_IE_LEN 1 ++#define RSNI_IE_LEN 1 ++BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie { ++ uint8 cap[DOT11_RRM_CAP_LEN]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; ++ ++/* Bitmap definitions for cap ie */ ++#define DOT11_RRM_CAP_LINK 0 ++#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1 ++#define DOT11_RRM_CAP_PARALLEL 2 ++#define DOT11_RRM_CAP_REPEATED 3 ++#define DOT11_RRM_CAP_BCN_PASSIVE 4 ++#define DOT11_RRM_CAP_BCN_ACTIVE 5 ++#define DOT11_RRM_CAP_BCN_TABLE 6 ++#define DOT11_RRM_CAP_BCN_REP_COND 7 ++#define DOT11_RRM_CAP_FM 8 ++#define DOT11_RRM_CAP_CLM 9 ++#define DOT11_RRM_CAP_NHM 10 ++#define DOT11_RRM_CAP_SM 11 ++#define DOT11_RRM_CAP_LCIM 12 ++#define DOT11_RRM_CAP_LCIA 13 ++#define DOT11_RRM_CAP_TSCM 14 ++#define DOT11_RRM_CAP_TTSCM 15 ++#define DOT11_RRM_CAP_AP_CHANREP 16 ++#define DOT11_RRM_CAP_RMMIB 17 ++/* bit18-bit23, not used for RRM_IOVAR */ ++#define DOT11_RRM_CAP_MPC0 24 ++#define DOT11_RRM_CAP_MPC1 25 ++#define DOT11_RRM_CAP_MPC2 26 ++#define DOT11_RRM_CAP_MPTI 27 ++#define DOT11_RRM_CAP_NBRTSFO 28 ++#define DOT11_RRM_CAP_RCPI 29 ++#define DOT11_RRM_CAP_RSNI 30 ++#define DOT11_RRM_CAP_BSSAAD 31 ++#define DOT11_RRM_CAP_BSSAAC 32 ++#define DOT11_RRM_CAP_AI 33 ++#define DOT11_RRM_CAP_FTM_RANGE 34 ++#define DOT11_RRM_CAP_CIVIC_LOC 35 ++#define DOT11_RRM_CAP_IDENT_LOC 36 ++#define DOT11_RRM_CAP_LAST 36 ++ ++#ifdef WL11K_ALL_MEAS ++#define DOT11_RRM_CAP_LINK_ENAB (1 << DOT11_RRM_CAP_LINK) ++#define DOT11_RRM_CAP_FM_ENAB (1 << (DOT11_RRM_CAP_FM - 8)) ++#define DOT11_RRM_CAP_CLM_ENAB (1 << (DOT11_RRM_CAP_CLM - 8)) ++#define DOT11_RRM_CAP_NHM_ENAB (1 << (DOT11_RRM_CAP_NHM - 8)) ++#define DOT11_RRM_CAP_SM_ENAB (1 << (DOT11_RRM_CAP_SM - 8)) ++#define DOT11_RRM_CAP_LCIM_ENAB (1 << (DOT11_RRM_CAP_LCIM - 8)) ++#define DOT11_RRM_CAP_TSCM_ENAB (1 << (DOT11_RRM_CAP_TSCM - 8)) ++#ifdef WL11K_AP ++#define DOT11_RRM_CAP_MPC0_ENAB (1 << (DOT11_RRM_CAP_MPC0 - 24)) ++#define DOT11_RRM_CAP_MPC1_ENAB (1 << (DOT11_RRM_CAP_MPC1 - 24)) ++#define DOT11_RRM_CAP_MPC2_ENAB (1 << (DOT11_RRM_CAP_MPC2 - 24)) ++#define DOT11_RRM_CAP_MPTI_ENAB (1 << (DOT11_RRM_CAP_MPTI - 24)) ++#else ++#define DOT11_RRM_CAP_MPC0_ENAB 0 ++#define DOT11_RRM_CAP_MPC1_ENAB 0 ++#define DOT11_RRM_CAP_MPC2_ENAB 0 ++#define DOT11_RRM_CAP_MPTI_ENAB 0 ++#endif /* WL11K_AP */ ++#define DOT11_RRM_CAP_CIVIC_LOC_ENAB (1 << (DOT11_RRM_CAP_CIVIC_LOC - 32)) ++#define DOT11_RRM_CAP_IDENT_LOC_ENAB (1 << (DOT11_RRM_CAP_IDENT_LOC - 32)) ++#else ++#define DOT11_RRM_CAP_LINK_ENAB 0 ++#define DOT11_RRM_CAP_FM_ENAB 0 ++#define DOT11_RRM_CAP_CLM_ENAB 0 ++#define DOT11_RRM_CAP_NHM_ENAB 0 ++#define DOT11_RRM_CAP_SM_ENAB 0 ++#define DOT11_RRM_CAP_LCIM_ENAB 0 ++#define DOT11_RRM_CAP_TSCM_ENAB 0 ++#define DOT11_RRM_CAP_MPC0_ENAB 0 ++#define DOT11_RRM_CAP_MPC1_ENAB 0 ++#define DOT11_RRM_CAP_MPC2_ENAB 0 ++#define DOT11_RRM_CAP_MPTI_ENAB 0 ++#define DOT11_RRM_CAP_CIVIC_LOC_ENAB 0 ++#define DOT11_RRM_CAP_IDENT_LOC_ENAB 0 ++#endif /* WL11K_ALL_MEAS */ ++#ifdef WL11K_NBR_MEAS ++#define DOT11_RRM_CAP_NEIGHBOR_REPORT_ENAB (1 << DOT11_RRM_CAP_NEIGHBOR_REPORT) ++#else ++#define DOT11_RRM_CAP_NEIGHBOR_REPORT_ENAB 0 ++#endif /* WL11K_NBR_MEAS */ ++#ifdef WL11K_BCN_MEAS ++#define DOT11_RRM_CAP_BCN_PASSIVE_ENAB (1 << DOT11_RRM_CAP_BCN_PASSIVE) ++#define DOT11_RRM_CAP_BCN_ACTIVE_ENAB (1 << DOT11_RRM_CAP_BCN_ACTIVE) ++#else ++#define DOT11_RRM_CAP_BCN_PASSIVE_ENAB 0 ++#define DOT11_RRM_CAP_BCN_ACTIVE_ENAB 0 ++#endif /* WL11K_BCN_MEAS */ ++#define DOT11_RRM_CAP_MPA_MASK 0x7 ++/* Operating Class (formerly "Regulatory Class") definitions */ ++#define DOT11_OP_CLASS_NONE 255 ++ ++BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { ++ uint8 id; ++ uint8 len; ++ uint8 reg; ++ uint8 chanlist[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct do11_ap_chrep dot11_ap_chrep_t; ++ ++/* Radio Measurements action ids */ ++#define DOT11_RM_ACTION_RM_REQ 0 /* Radio measurement request */ ++#define DOT11_RM_ACTION_RM_REP 1 /* Radio measurement report */ ++#define DOT11_RM_ACTION_LM_REQ 2 /* Link measurement request */ ++#define DOT11_RM_ACTION_LM_REP 3 /* Link measurement report */ ++#define DOT11_RM_ACTION_NR_REQ 4 /* Neighbor report request */ ++#define DOT11_RM_ACTION_NR_REP 5 /* Neighbor report response */ ++#define DOT11_PUB_ACTION_MP 7 /* Measurement Pilot public action id */ ++ ++/** Generic radio measurement action frame header */ ++BWL_PRE_PACKED_STRUCT struct dot11_rm_action { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rm_action dot11_rm_action_t; ++#define DOT11_RM_ACTION_LEN 3 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ uint16 reps; /* no. of repetitions */ ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq dot11_rmreq_t; ++#define DOT11_RMREQ_LEN 5 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rm_ie { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rm_ie dot11_rm_ie_t; ++#define DOT11_RM_IE_LEN 5 ++ ++/* Definitions for "mode" bits in rm req */ ++#define DOT11_RMREQ_MODE_PARALLEL 1 ++#define DOT11_RMREQ_MODE_ENABLE 2 ++#define DOT11_RMREQ_MODE_REQUEST 4 ++#define DOT11_RMREQ_MODE_REPORT 8 ++#define DOT11_RMREQ_MODE_DURMAND 0x10 /* Duration Mandatory */ ++ ++/* Definitions for "mode" bits in rm rep */ ++#define DOT11_RMREP_MODE_LATE 1 ++#define DOT11_RMREP_MODE_INCAPABLE 2 ++#define DOT11_RMREP_MODE_REFUSED 4 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 reg; ++ uint8 channel; ++ uint16 interval; ++ uint16 duration; ++ uint8 bcn_mode; ++ struct ether_addr bssid; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t; ++#define DOT11_RMREQ_BCN_LEN 18 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn { ++ uint8 reg; ++ uint8 channel; ++ uint32 starttime[2]; ++ uint16 duration; ++ uint8 frame_info; ++ uint8 rcpi; ++ uint8 rsni; ++ struct ether_addr bssid; ++ uint8 antenna_id; ++ uint32 parent_tsf; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; ++#define DOT11_RMREP_BCN_LEN 26 ++ ++/* Beacon request measurement mode */ ++#define DOT11_RMREQ_BCN_PASSIVE 0 ++#define DOT11_RMREQ_BCN_ACTIVE 1 ++#define DOT11_RMREQ_BCN_TABLE 2 ++ ++/* Sub-element IDs for Beacon Request */ ++#define DOT11_RMREQ_BCN_SSID_ID 0 ++#define DOT11_RMREQ_BCN_REPINFO_ID 1 ++#define DOT11_RMREQ_BCN_REPDET_ID 2 ++#define DOT11_RMREQ_BCN_REQUEST_ID 10 ++#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID ++ ++/* Reporting Detail element definition */ ++#define DOT11_RMREQ_BCN_REPDET_FIXED 0 /* Fixed length fields only */ ++#define DOT11_RMREQ_BCN_REPDET_REQUEST 1 /* + requested information elems */ ++#define DOT11_RMREQ_BCN_REPDET_ALL 2 /* All fields */ ++ ++/* Reporting Information (reporting condition) element definition */ ++#define DOT11_RMREQ_BCN_REPINFO_LEN 2 /* Beacon Reporting Information length */ ++#define DOT11_RMREQ_BCN_REPCOND_DEFAULT 0 /* Report to be issued after each measurement */ ++ ++/* Sub-element IDs for Beacon Report */ ++#define DOT11_RMREP_BCN_FRM_BODY 1 ++#define DOT11_RMREP_BCN_FRM_BODY_LEN_MAX 224 /* 802.11k-2008 7.3.2.22.6 */ ++ ++/* Sub-element IDs for Frame Report */ ++#define DOT11_RMREP_FRAME_COUNT_REPORT 1 ++ ++/* Channel load request */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_chanload { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 reg; ++ uint8 channel; ++ uint16 interval; ++ uint16 duration; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_chanload dot11_rmreq_chanload_t; ++#define DOT11_RMREQ_CHANLOAD_LEN 11 ++ ++/** Channel load report */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_chanload { ++ uint8 reg; ++ uint8 channel; ++ uint32 starttime[2]; ++ uint16 duration; ++ uint8 channel_load; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_chanload dot11_rmrep_chanload_t; ++#define DOT11_RMREP_CHANLOAD_LEN 13 ++ ++/** Noise histogram request */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_noise { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 reg; ++ uint8 channel; ++ uint16 interval; ++ uint16 duration; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_noise dot11_rmreq_noise_t; ++#define DOT11_RMREQ_NOISE_LEN 11 ++ ++/** Noise histogram report */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_noise { ++ uint8 reg; ++ uint8 channel; ++ uint32 starttime[2]; ++ uint16 duration; ++ uint8 antid; ++ uint8 anpi; ++ uint8 ipi0_dens; ++ uint8 ipi1_dens; ++ uint8 ipi2_dens; ++ uint8 ipi3_dens; ++ uint8 ipi4_dens; ++ uint8 ipi5_dens; ++ uint8 ipi6_dens; ++ uint8 ipi7_dens; ++ uint8 ipi8_dens; ++ uint8 ipi9_dens; ++ uint8 ipi10_dens; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_noise dot11_rmrep_noise_t; ++#define DOT11_RMREP_NOISE_LEN 25 ++ ++/** Frame request */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_frame { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 reg; ++ uint8 channel; ++ uint16 interval; ++ uint16 duration; ++ uint8 req_type; ++ struct ether_addr ta; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_frame dot11_rmreq_frame_t; ++#define DOT11_RMREQ_FRAME_LEN 18 ++ ++/** Frame report */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frame { ++ uint8 reg; ++ uint8 channel; ++ uint32 starttime[2]; ++ uint16 duration; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_frame dot11_rmrep_frame_t; ++#define DOT11_RMREP_FRAME_LEN 12 ++ ++/** Frame report entry */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_frmentry { ++ struct ether_addr ta; ++ struct ether_addr bssid; ++ uint8 phy_type; ++ uint8 avg_rcpi; ++ uint8 last_rsni; ++ uint8 last_rcpi; ++ uint8 ant_id; ++ uint16 frame_cnt; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_frmentry dot11_rmrep_frmentry_t; ++#define DOT11_RMREP_FRMENTRY_LEN 19 ++ ++/** STA statistics request */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_stat { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ struct ether_addr peer; ++ uint16 interval; ++ uint16 duration; ++ uint8 group_id; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_stat dot11_rmreq_stat_t; ++#define DOT11_RMREQ_STAT_LEN 16 ++ ++/** STA statistics report */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_stat { ++ uint16 duration; ++ uint8 group_id; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_stat dot11_rmrep_stat_t; ++ ++/* Statistics Group Report: Group IDs */ ++enum { ++ DOT11_RRM_STATS_GRP_ID_0 = 0, ++ DOT11_RRM_STATS_GRP_ID_1, ++ DOT11_RRM_STATS_GRP_ID_2, ++ DOT11_RRM_STATS_GRP_ID_3, ++ DOT11_RRM_STATS_GRP_ID_4, ++ DOT11_RRM_STATS_GRP_ID_5, ++ DOT11_RRM_STATS_GRP_ID_6, ++ DOT11_RRM_STATS_GRP_ID_7, ++ DOT11_RRM_STATS_GRP_ID_8, ++ DOT11_RRM_STATS_GRP_ID_9, ++ DOT11_RRM_STATS_GRP_ID_10, ++ DOT11_RRM_STATS_GRP_ID_11, ++ DOT11_RRM_STATS_GRP_ID_12, ++ DOT11_RRM_STATS_GRP_ID_13, ++ DOT11_RRM_STATS_GRP_ID_14, ++ DOT11_RRM_STATS_GRP_ID_15, ++ DOT11_RRM_STATS_GRP_ID_16 ++}; ++ ++/* Statistics Group Report: Group Data length */ ++#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_0 28 ++typedef struct rrm_stat_group_0 { ++ uint32 txfrag; ++ uint32 txmulti; ++ uint32 txfail; ++ uint32 rxframe; ++ uint32 rxmulti; ++ uint32 rxbadfcs; ++ uint32 txframe; ++} rrm_stat_group_0_t; ++ ++#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_1 24 ++typedef struct rrm_stat_group_1 { ++ uint32 txretry; ++ uint32 txretries; ++ uint32 rxdup; ++ uint32 txrts; ++ uint32 rtsfail; ++ uint32 ackfail; ++} rrm_stat_group_1_t; ++ ++/* group 2-9 use same qos data structure (tid 0-7), total 52 bytes */ ++#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_2_9 52 ++typedef struct rrm_stat_group_qos { ++ uint32 txfrag; ++ uint32 txfail; ++ uint32 txretry; ++ uint32 txretries; ++ uint32 rxdup; ++ uint32 txrts; ++ uint32 rtsfail; ++ uint32 ackfail; ++ uint32 rxfrag; ++ uint32 txframe; ++ uint32 txdrop; ++ uint32 rxmpdu; ++ uint32 rxretries; ++} rrm_stat_group_qos_t; ++ ++/* dot11BSSAverageAccessDelay Group (only available at an AP): 8 byte */ ++#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_10 8 ++typedef BWL_PRE_PACKED_STRUCT struct rrm_stat_group_10 { ++ uint8 apavgdelay; ++ uint8 avgdelaybe; ++ uint8 avgdelaybg; ++ uint8 avgdelayvi; ++ uint8 avgdelayvo; ++ uint16 stacount; ++ uint8 chanutil; ++} BWL_POST_PACKED_STRUCT rrm_stat_group_10_t; ++ ++/* AMSDU, 40 bytes */ ++#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_11 40 ++typedef struct rrm_stat_group_11 { ++ uint32 txamsdu; ++ uint32 amsdufail; ++ uint32 amsduretry; ++ uint32 amsduretries; ++ uint32 txamsdubyte_h; ++ uint32 txamsdubyte_l; ++ uint32 amsduackfail; ++ uint32 rxamsdu; ++ uint32 rxamsdubyte_h; ++ uint32 rxamsdubyte_l; ++} rrm_stat_group_11_t; ++ ++/* AMPDU, 36 bytes */ ++#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_12 36 ++typedef struct rrm_stat_group_12 { ++ uint32 txampdu; ++ uint32 txmpdu; ++ uint32 txampdubyte_h; ++ uint32 txampdubyte_l; ++ uint32 rxampdu; ++ uint32 rxmpdu; ++ uint32 rxampdubyte_h; ++ uint32 rxampdubyte_l; ++ uint32 ampducrcfail; ++} rrm_stat_group_12_t; ++ ++/* BACK etc, 36 bytes */ ++#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_13 36 ++typedef struct rrm_stat_group_13 { ++ uint32 rximpbarfail; ++ uint32 rxexpbarfail; ++ uint32 chanwidthsw; ++ uint32 txframe20mhz; ++ uint32 txframe40mhz; ++ uint32 rxframe20mhz; ++ uint32 rxframe40mhz; ++ uint32 psmpgrantdur; ++ uint32 psmpuseddur; ++} rrm_stat_group_13_t; ++ ++/* RD Dual CTS etc, 36 bytes */ ++#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_14 36 ++typedef struct rrm_stat_group_14 { ++ uint32 grantrdgused; ++ uint32 grantrdgunused; ++ uint32 txframeingrantrdg; ++ uint32 txbyteingrantrdg_h; ++ uint32 txbyteingrantrdg_l; ++ uint32 dualcts; ++ uint32 dualctsfail; ++ uint32 rtslsi; ++ uint32 rtslsifail; ++} rrm_stat_group_14_t; ++ ++/* bf and STBC etc, 20 bytes */ ++#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_15 20 ++typedef struct rrm_stat_group_15 { ++ uint32 bfframe; ++ uint32 stbccts; ++ uint32 stbcctsfail; ++ uint32 nonstbccts; ++ uint32 nonstbcctsfail; ++} rrm_stat_group_15_t; ++ ++/* RSNA, 28 bytes */ ++#define DOT11_RRM_STATS_RPT_LEN_GRP_ID_16 28 ++typedef struct rrm_stat_group_16 { ++ uint32 rsnacmacicverr; ++ uint32 rsnacmacreplay; ++ uint32 rsnarobustmgmtccmpreplay; ++ uint32 rsnatkipicverr; ++ uint32 rsnatkipicvreplay; ++ uint32 rsnaccmpdecrypterr; ++ uint32 rsnaccmpreplay; ++} rrm_stat_group_16_t; ++ ++/* Transmit stream/category measurement request */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_tx_stream { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint16 interval; ++ uint16 duration; ++ struct ether_addr peer; ++ uint8 traffic_id; ++ uint8 bin0_range; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_tx_stream dot11_rmreq_tx_stream_t; ++#define DOT11_RMREQ_TXSTREAM_LEN 17 ++ ++/** Transmit stream/category measurement report */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_tx_stream { ++ uint32 starttime[2]; ++ uint16 duration; ++ struct ether_addr peer; ++ uint8 traffic_id; ++ uint8 reason; ++ uint32 txmsdu_cnt; ++ uint32 msdu_discarded_cnt; ++ uint32 msdufailed_cnt; ++ uint32 msduretry_cnt; ++ uint32 cfpolls_lost_cnt; ++ uint32 avrqueue_delay; ++ uint32 avrtx_delay; ++ uint8 bin0_range; ++ uint32 bin0; ++ uint32 bin1; ++ uint32 bin2; ++ uint32 bin3; ++ uint32 bin4; ++ uint32 bin5; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_tx_stream dot11_rmrep_tx_stream_t; ++#define DOT11_RMREP_TXSTREAM_LEN 71 ++ ++typedef struct rrm_tscm { ++ uint32 msdu_tx; ++ uint32 msdu_exp; ++ uint32 msdu_fail; ++ uint32 msdu_retries; ++ uint32 cfpolls_lost; ++ uint32 queue_delay; ++ uint32 tx_delay_sum; ++ uint32 tx_delay_cnt; ++ uint32 bin0_range_us; ++ uint32 bin0; ++ uint32 bin1; ++ uint32 bin2; ++ uint32 bin3; ++ uint32 bin4; ++ uint32 bin5; ++} rrm_tscm_t; ++enum { ++ DOT11_FTM_LOCATION_SUBJ_LOCAL = 0, /* Where am I? */ ++ DOT11_FTM_LOCATION_SUBJ_REMOTE = 1, /* Where are you? */ ++ DOT11_FTM_LOCATION_SUBJ_THIRDPARTY = 2 /* Where is he/she? */ ++}; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_lci { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 subj; ++ ++ /* Following 3 fields are unused. Keep for ROM compatibility. */ ++ uint8 lat_res; ++ uint8 lon_res; ++ uint8 alt_res; ++ ++ /* optional sub-elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_ftm_lci dot11_rmreq_ftm_lci_t; ++#define DOT11_RMREQ_LCI_LEN 9 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_lci { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 lci_sub_id; ++ uint8 lci_sub_len; ++ /* optional LCI field */ ++ /* optional sub-elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_ftm_lci dot11_rmrep_ftm_lci_t; ++ ++#define DOT11_FTM_LCI_SUBELEM_ID 0 ++#define DOT11_FTM_LCI_SUBELEM_LEN 2 ++#define DOT11_FTM_LCI_FIELD_LEN 16 ++#define DOT11_FTM_LCI_UNKNOWN_LEN 2 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_civic { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 subj; ++ uint8 civloc_type; ++ uint8 siu; /* service interval units */ ++ uint16 si; /* service interval */ ++ /* optional sub-elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_ftm_civic dot11_rmreq_ftm_civic_t; ++#define DOT11_RMREQ_CIVIC_LEN 10 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_civic { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 civloc_type; ++ uint8 civloc_sub_id; ++ uint8 civloc_sub_len; ++ /* optional location civic field */ ++ /* optional sub-elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_ftm_civic dot11_rmrep_ftm_civic_t; ++ ++#define DOT11_FTM_CIVIC_LOC_TYPE_RFC4776 0 ++#define DOT11_FTM_CIVIC_SUBELEM_ID 0 ++#define DOT11_FTM_CIVIC_SUBELEM_LEN 2 ++#define DOT11_FTM_CIVIC_LOC_SI_NONE 0 ++#define DOT11_FTM_CIVIC_TYPE_LEN 1 ++#define DOT11_FTM_CIVIC_UNKNOWN_LEN 3 ++ ++/* Location Identifier measurement request */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_locid { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 subj; ++ uint8 siu; ++ uint16 si; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_locid dot11_rmreq_locid_t; ++#define DOT11_RMREQ_LOCID_LEN 9 ++ ++/* Location Identifier measurement report */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_locid { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 exp_tsf[8]; ++ uint8 locid_sub_id; ++ uint8 locid_sub_len; ++ /* optional location identifier field */ ++ /* optional sub-elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_locid dot11_rmrep_locid_t; ++#define DOT11_LOCID_UNKNOWN_LEN 10 ++#define DOT11_LOCID_SUBELEM_ID 0 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_subel { ++ uint8 id; ++ uint8 len; ++ uint16 max_age; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ftm_range_subel dot11_ftm_range_subel_t; ++#define DOT11_FTM_RANGE_SUBELEM_ID 4 ++#define DOT11_FTM_RANGE_SUBELEM_LEN 2 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_ftm_range { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint16 max_init_delay; /* maximum random initial delay */ ++ uint8 min_ap_count; ++ uint8 data[1]; ++ /* neighbor report sub-elements */ ++ /* optional sub-elements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_ftm_range dot11_rmreq_ftm_range_t; ++#define DOT11_RMREQ_FTM_RANGE_LEN 8 ++ ++#define DOT11_FTM_RANGE_LEN 3 ++BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_entry { ++ uint32 start_tsf; /* 4 lsb of tsf */ ++ struct ether_addr bssid; ++ uint8 range[DOT11_FTM_RANGE_LEN]; ++ uint8 max_err[DOT11_FTM_RANGE_LEN]; ++ uint8 rsvd; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ftm_range_entry dot11_ftm_range_entry_t; ++#define DOT11_FTM_RANGE_ENTRY_MAX_COUNT 15 ++ ++enum { ++ DOT11_FTM_RANGE_ERROR_AP_INCAPABLE = 2, ++ DOT11_FTM_RANGE_ERROR_AP_FAILED = 3, ++ DOT11_FTM_RANGE_ERROR_TX_FAILED = 8, ++ DOT11_FTM_RANGE_ERROR_MAX ++}; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ftm_range_error_entry { ++ uint32 start_tsf; /* 4 lsb of tsf */ ++ struct ether_addr bssid; ++ uint8 code; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ftm_range_error_entry dot11_ftm_range_error_entry_t; ++#define DOT11_FTM_RANGE_ERROR_ENTRY_MAX_COUNT 11 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_rmrep_ftm_range { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint8 entry_count; ++ uint8 data[2]; /* includes pad */ ++ /* ++ dot11_ftm_range_entry_t entries[entry_count]; ++ uint8 error_count; ++ dot11_ftm_error_entry_t errors[error_count]; ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmrep_ftm_range dot11_rmrep_ftm_range_t; ++ ++#define DOT11_FTM_RANGE_REP_MIN_LEN 6 /* No extra byte for error_count */ ++#define DOT11_FTM_RANGE_ENTRY_CNT_MAX 15 ++#define DOT11_FTM_RANGE_ERROR_CNT_MAX 11 ++#define DOT11_FTM_RANGE_REP_FIXED_LEN 1 /* No extra byte for error_count */ ++/** Measurement pause request */ ++BWL_PRE_PACKED_STRUCT struct dot11_rmreq_pause_time { ++ uint8 id; ++ uint8 len; ++ uint8 token; ++ uint8 mode; ++ uint8 type; ++ uint16 pause_time; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_rmreq_pause_time dot11_rmreq_pause_time_t; ++#define DOT11_RMREQ_PAUSE_LEN 7 ++ ++ ++/* Neighbor Report subelements ID (11k & 11v) */ ++#define DOT11_NGBR_TSF_INFO_SE_ID 1 ++#define DOT11_NGBR_CCS_SE_ID 2 ++#define DOT11_NGBR_BSSTRANS_PREF_SE_ID 3 ++#define DOT11_NGBR_BSS_TERM_DUR_SE_ID 4 ++#define DOT11_NGBR_BEARING_SE_ID 5 ++#define DOT11_NGBR_WIDE_BW_CHAN_SE_ID 6 ++ ++/** Neighbor Report, BSS Transition Candidate Preference subelement */ ++BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bsstrans_pref_se { ++ uint8 sub_id; ++ uint8 len; ++ uint8 preference; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ngbr_bsstrans_pref_se dot11_ngbr_bsstrans_pref_se_t; ++#define DOT11_NGBR_BSSTRANS_PREF_SE_LEN 1 ++#define DOT11_NGBR_BSSTRANS_PREF_SE_IE_LEN 3 ++#define DOT11_NGBR_BSSTRANS_PREF_SE_HIGHEST 0xff ++ ++/** Neighbor Report, BSS Termination Duration subelement */ ++BWL_PRE_PACKED_STRUCT struct dot11_ngbr_bss_term_dur_se { ++ uint8 sub_id; ++ uint8 len; ++ uint8 tsf[8]; ++ uint16 duration; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ngbr_bss_term_dur_se dot11_ngbr_bss_term_dur_se_t; ++#define DOT11_NGBR_BSS_TERM_DUR_SE_LEN 10 ++ ++/* Neighbor Report BSSID Information Field */ ++#define DOT11_NGBR_BI_REACHABILTY_UNKN 0x0002 ++#define DOT11_NGBR_BI_REACHABILTY 0x0003 ++#define DOT11_NGBR_BI_SEC 0x0004 ++#define DOT11_NGBR_BI_KEY_SCOPE 0x0008 ++#define DOT11_NGBR_BI_CAP 0x03f0 ++#define DOT11_NGBR_BI_CAP_SPEC_MGMT 0x0010 ++#define DOT11_NGBR_BI_CAP_QOS 0x0020 ++#define DOT11_NGBR_BI_CAP_APSD 0x0040 ++#define DOT11_NGBR_BI_CAP_RDIO_MSMT 0x0080 ++#define DOT11_NGBR_BI_CAP_DEL_BA 0x0100 ++#define DOT11_NGBR_BI_CAP_IMM_BA 0x0200 ++#define DOT11_NGBR_BI_MOBILITY 0x0400 ++#define DOT11_NGBR_BI_HT 0x0800 ++#define DOT11_NGBR_BI_VHT 0x1000 ++#define DOT11_NGBR_BI_FTM 0x2000 ++ ++/** Neighbor Report element (11k & 11v) */ ++BWL_PRE_PACKED_STRUCT struct dot11_neighbor_rep_ie { ++ uint8 id; ++ uint8 len; ++ struct ether_addr bssid; ++ uint32 bssid_info; ++ uint8 reg; /* Operating class */ ++ uint8 channel; ++ uint8 phytype; ++ uint8 data[1]; /* Variable size subelements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_neighbor_rep_ie dot11_neighbor_rep_ie_t; ++#define DOT11_NEIGHBOR_REP_IE_FIXED_LEN 13 ++ ++ ++/* MLME Enumerations */ ++#define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */ ++#define DOT11_BSSTYPE_INDEPENDENT 1 /* d11 independent */ ++#define DOT11_BSSTYPE_ANY 2 /* d11 any BSS type */ ++#define DOT11_BSSTYPE_MESH 3 /* d11 Mesh */ ++#define DOT11_SCANTYPE_ACTIVE 0 /* d11 scan active */ ++#define DOT11_SCANTYPE_PASSIVE 1 /* d11 scan passive */ ++ ++/** Link Measurement */ ++BWL_PRE_PACKED_STRUCT struct dot11_lmreq { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ uint8 txpwr; /* Transmit Power Used */ ++ uint8 maxtxpwr; /* Max Transmit Power */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_lmreq dot11_lmreq_t; ++#define DOT11_LMREQ_LEN 5 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_lmrep { ++ uint8 category; /* category of action frame (5) */ ++ uint8 action; /* radio measurement action */ ++ uint8 token; /* dialog token */ ++ dot11_tpc_rep_t tpc; /* TPC element */ ++ uint8 rxant; /* Receive Antenna ID */ ++ uint8 txant; /* Transmit Antenna ID */ ++ uint8 rcpi; /* RCPI */ ++ uint8 rsni; /* RSNI */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_lmrep dot11_lmrep_t; ++#define DOT11_LMREP_LEN 11 ++ ++#define DOT11_MP_CAP_SPECTRUM 0x01 /* d11 cap. spectrum */ ++#define DOT11_MP_CAP_SHORTSLOT 0x02 /* d11 cap. shortslot */ ++/* Measurement Pilot */ ++BWL_PRE_PACKED_STRUCT struct dot11_mprep { ++ uint8 cap_info; /* Condensed capability Info. */ ++ uint8 country[2]; /* Condensed country string */ ++ uint8 opclass; /* Op. Class */ ++ uint8 channel; /* Channel */ ++ uint8 mp_interval; /* Measurement Pilot Interval */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_mprep dot11_mprep_t; ++#define DOT11_MPREP_LEN 6 ++ ++/* 802.11 BRCM "Compromise" Pre N constants */ ++#define PREN_PREAMBLE 24 /* green field preamble time */ ++#define PREN_MM_EXT 12 /* extra mixed mode preamble time */ ++#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */ ++ ++/* 802.11N PHY constants */ ++#define RIFS_11N_TIME 2 /* NPHY RIFS time */ ++ ++/* 802.11 HT PLCP format 802.11n-2009, sec 20.3.9.4.3 ++ * HT-SIG is composed of two 24 bit parts, HT-SIG1 and HT-SIG2 ++ */ ++/* HT-SIG1 */ ++#define HT_SIG1_MCS_MASK 0x00007F ++#define HT_SIG1_CBW 0x000080 ++#define HT_SIG1_HT_LENGTH 0xFFFF00 ++ ++/* HT-SIG2 */ ++#define HT_SIG2_SMOOTHING 0x000001 ++#define HT_SIG2_NOT_SOUNDING 0x000002 ++#define HT_SIG2_RESERVED 0x000004 ++#define HT_SIG2_AGGREGATION 0x000008 ++#define HT_SIG2_STBC_MASK 0x000030 ++#define HT_SIG2_STBC_SHIFT 4 ++#define HT_SIG2_FEC_CODING 0x000040 ++#define HT_SIG2_SHORT_GI 0x000080 ++#define HT_SIG2_ESS_MASK 0x000300 ++#define HT_SIG2_ESS_SHIFT 8 ++#define HT_SIG2_CRC 0x03FC00 ++#define HT_SIG2_TAIL 0x1C0000 ++ ++/* HT Timing-related parameters (802.11-2012, sec 20.3.6) */ ++#define HT_T_LEG_PREAMBLE 16 ++#define HT_T_L_SIG 4 ++#define HT_T_SIG 8 ++#define HT_T_LTF1 4 ++#define HT_T_GF_LTF1 8 ++#define HT_T_LTFs 4 ++#define HT_T_STF 4 ++#define HT_T_GF_STF 8 ++#define HT_T_SYML 4 ++ ++#define HT_N_SERVICE 16 /* bits in SERVICE field */ ++#define HT_N_TAIL 6 /* tail bits per BCC encoder */ ++ ++/* 802.11 A PHY constants */ ++#define APHY_SLOT_TIME 9 /* APHY slot time */ ++#define APHY_SIFS_TIME 16 /* APHY SIFS time */ ++#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */ ++#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */ ++#define APHY_SIGNAL_TIME 4 /* APHY signal time */ ++#define APHY_SYMBOL_TIME 4 /* APHY symbol time */ ++#define APHY_SERVICE_NBITS 16 /* APHY service nbits */ ++#define APHY_TAIL_NBITS 6 /* APHY tail nbits */ ++#define APHY_CWMIN 15 /* APHY cwmin */ ++#define APHY_PHYHDR_DUR 20 /* APHY PHY Header Duration */ ++ ++/* 802.11 B PHY constants */ ++#define BPHY_SLOT_TIME 20 /* BPHY slot time */ ++#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */ ++#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */ ++#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */ ++#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */ ++#define BPHY_CWMIN 31 /* BPHY cwmin */ ++#define BPHY_SHORT_PHYHDR_DUR 96 /* BPHY Short PHY Header Duration */ ++#define BPHY_LONG_PHYHDR_DUR 192 /* BPHY Long PHY Header Duration */ ++ ++/* 802.11 G constants */ ++#define DOT11_OFDM_SIGNAL_EXTENSION 6 /* d11 OFDM signal extension */ ++ ++#define PHY_CWMAX 1023 /* PHY cwmax */ ++ ++#define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */ ++ ++/* 802.11 VHT constants */ ++ ++typedef int vht_group_id_t; ++ ++/* for VHT-A1 */ ++/* SIG-A1 reserved bits */ ++#define VHT_SIGA1_CONST_MASK 0x800004 ++ ++#define VHT_SIGA1_BW_MASK 0x000003 ++#define VHT_SIGA1_20MHZ_VAL 0x000000 ++#define VHT_SIGA1_40MHZ_VAL 0x000001 ++#define VHT_SIGA1_80MHZ_VAL 0x000002 ++#define VHT_SIGA1_160MHZ_VAL 0x000003 ++ ++#define VHT_SIGA1_STBC 0x000008 ++ ++#define VHT_SIGA1_GID_MASK 0x0003f0 ++#define VHT_SIGA1_GID_SHIFT 4 ++#define VHT_SIGA1_GID_TO_AP 0x00 ++#define VHT_SIGA1_GID_NOT_TO_AP 0x3f ++#define VHT_SIGA1_GID_MAX_GID 0x3f ++ ++#define VHT_SIGA1_NSTS_SHIFT_MASK_USER0 0x001C00 ++#define VHT_SIGA1_NSTS_SHIFT 10 ++#define VHT_SIGA1_MAX_USERPOS 3 ++ ++#define VHT_SIGA1_PARTIAL_AID_MASK 0x3fe000 ++#define VHT_SIGA1_PARTIAL_AID_SHIFT 13 ++ ++#define VHT_SIGA1_TXOP_PS_NOT_ALLOWED 0x400000 ++ ++/* for VHT-A2 */ ++#define VHT_SIGA2_GI_NONE 0x000000 ++#define VHT_SIGA2_GI_SHORT 0x000001 ++#define VHT_SIGA2_GI_W_MOD10 0x000002 ++#define VHT_SIGA2_CODING_LDPC 0x000004 ++#define VHT_SIGA2_LDPC_EXTRA_OFDM_SYM 0x000008 ++#define VHT_SIGA2_BEAMFORM_ENABLE 0x000100 ++#define VHT_SIGA2_MCS_SHIFT 4 ++ ++#define VHT_SIGA2_B9_RESERVED 0x000200 ++#define VHT_SIGA2_TAIL_MASK 0xfc0000 ++#define VHT_SIGA2_TAIL_VALUE 0x000000 ++ ++/* VHT Timing-related parameters (802.11ac D4.0, sec 22.3.6) */ ++#define VHT_T_LEG_PREAMBLE 16 ++#define VHT_T_L_SIG 4 ++#define VHT_T_SIG_A 8 ++#define VHT_T_LTF 4 ++#define VHT_T_STF 4 ++#define VHT_T_SIG_B 4 ++#define VHT_T_SYML 4 ++ ++#define VHT_N_SERVICE 16 /* bits in SERVICE field */ ++#define VHT_N_TAIL 6 /* tail bits per BCC encoder */ ++ ++/** dot11Counters Table - 802.11 spec., Annex D */ ++typedef struct d11cnt { ++ uint32 txfrag; /* dot11TransmittedFragmentCount */ ++ uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ ++ uint32 txfail; /* dot11FailedCount */ ++ uint32 txretry; /* dot11RetryCount */ ++ uint32 txretrie; /* dot11MultipleRetryCount */ ++ uint32 rxdup; /* dot11FrameduplicateCount */ ++ uint32 txrts; /* dot11RTSSuccessCount */ ++ uint32 txnocts; /* dot11RTSFailureCount */ ++ uint32 txnoack; /* dot11ACKFailureCount */ ++ uint32 rxfrag; /* dot11ReceivedFragmentCount */ ++ uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ ++ uint32 rxcrc; /* dot11FCSErrorCount */ ++ uint32 txfrmsnt; /* dot11TransmittedFrameCount */ ++ uint32 rxundec; /* dot11WEPUndecryptableCount */ ++} d11cnt_t; ++ ++#define BRCM_PROP_OUI "\x00\x90\x4C" ++ ++ ++#define BRCM_FTM_IE_TYPE 14 ++ ++/* #define HT_CAP_IE_TYPE 51 ++ * #define HT_ADD_IE_TYPE 52 ++ * #define BRCM_EXTCH_IE_TYPE 53 ++ * #define MEMBER_OF_BRCM_PROP_IE_TYPE 54 ++ * #define BRCM_RELMACST_IE_TYPE 55 ++ * #define BRCM_EVT_WL_BSS_INFO 64 ++ * #define RWL_ACTION_WIFI_FRAG_TYPE 85 ++ * #define BTC_INFO_BRCM_PROP_IE_TYPE 90 ++ * #define ULB_BRCM_PROP_IE_TYPE 91 ++ * #define SDB_BRCM_PROP_IE_TYPE 92 ++ */ ++ ++/* Action frame type for RWL */ ++#define RWL_WIFI_DEFAULT 0 ++#define RWL_WIFI_FIND_MY_PEER 9 /* Used while finding server */ ++#define RWL_WIFI_FOUND_PEER 10 /* Server response to the client */ ++#define RWL_ACTION_WIFI_FRAG_TYPE 85 /* Fragment indicator for receiver */ ++ ++#define PROXD_AF_TYPE 11 /* Wifi proximity action frame type */ ++#define BRCM_RELMACST_AF_TYPE 12 /* RMC action frame type */ ++ ++/* Action frame type for FTM Initiator Report */ ++#define BRCM_FTM_VS_AF_TYPE 14 ++enum { ++ BRCM_FTM_VS_INITIATOR_RPT_SUBTYPE = 1, /* FTM Initiator Report */ ++ BRCM_FTM_VS_COLLECT_SUBTYPE = 2, /* FTM Collect debug protocol */ ++}; ++ ++ ++ ++ ++/* brcm syscap_ie cap */ ++#define BRCM_SYSCAP_WET_TUNNEL 0x0100 /* Device with WET_TUNNEL support */ ++ ++#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ ++ ++/** BRCM info element */ ++BWL_PRE_PACKED_STRUCT struct brcm_ie { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; ++ uint8 ver; /* type/ver of this IE */ ++ uint8 assoc; /* # of assoc STAs */ ++ uint8 flags; /* misc flags */ ++ uint8 flags1; /* misc flags */ ++ uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct brcm_ie brcm_ie_t; ++#define BRCM_IE_LEN 11 /* BRCM IE length */ ++#define BRCM_IE_VER 2 /* BRCM IE version */ ++#define BRCM_IE_LEGACY_AES_VER 1 /* BRCM IE legacy AES version */ ++ ++/* brcm_ie flags */ ++#define BRF_ABCAP 0x1 /* afterburner is obsolete, defined for backward compat */ ++#define BRF_ABRQRD 0x2 /* afterburner is obsolete, defined for backward compat */ ++#define BRF_LZWDS 0x4 /* lazy wds enabled */ ++#define BRF_BLOCKACK 0x8 /* BlockACK capable */ ++#define BRF_ABCOUNTER_MASK 0xf0 /* afterburner is obsolete, defined for backward compat */ ++#define BRF_PROP_11N_MCS 0x10 /* re-use afterburner bit */ ++#define BRF_MEDIA_CLIENT 0x20 /* re-use afterburner bit to indicate media client device */ ++ ++#define GET_BRF_PROP_11N_MCS(brcm_ie) \ ++ (!((brcm_ie)->flags & BRF_ABCAP) && ((brcm_ie)->flags & BRF_PROP_11N_MCS)) ++ ++/* brcm_ie flags1 */ ++#define BRF1_AMSDU 0x1 /* A-MSDU capable */ ++#define BRF1_WNM 0x2 /* WNM capable */ ++#define BRF1_WMEPS 0x4 /* AP is capable of handling WME + PS w/o APSD */ ++#define BRF1_PSOFIX 0x8 /* AP has fixed PS mode out-of-order packets */ ++#define BRF1_RX_LARGE_AGG 0x10 /* device can rx large aggregates */ ++#define BRF1_RFAWARE_DCS 0x20 /* RFAWARE dynamic channel selection (DCS) */ ++#define BRF1_SOFTAP 0x40 /* Configure as Broadcom SOFTAP */ ++#define BRF1_DWDS 0x80 /* DWDS capable */ ++ ++/** Vendor IE structure */ ++BWL_PRE_PACKED_STRUCT struct vndr_ie { ++ uchar id; ++ uchar len; ++ uchar oui [3]; ++ uchar data [1]; /* Variable size data */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct vndr_ie vndr_ie_t; ++ ++#define VNDR_IE_HDR_LEN 2 /* id + len field */ ++#define VNDR_IE_MIN_LEN 3 /* size of the oui field */ ++#define VNDR_IE_FIXED_LEN (VNDR_IE_HDR_LEN + VNDR_IE_MIN_LEN) ++ ++#define VNDR_IE_MAX_LEN 255 /* vendor IE max length, without ID and len */ ++ ++/** BRCM PROP DEVICE PRIMARY MAC ADDRESS IE */ ++BWL_PRE_PACKED_STRUCT struct member_of_brcm_prop_ie { ++ uchar id; ++ uchar len; ++ uchar oui[3]; ++ uint8 type; /* type indicates what follows */ ++ struct ether_addr ea; /* Device Primary MAC Adrress */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct member_of_brcm_prop_ie member_of_brcm_prop_ie_t; ++ ++#define MEMBER_OF_BRCM_PROP_IE_LEN 10 /* IE max length */ ++#define MEMBER_OF_BRCM_PROP_IE_HDRLEN (sizeof(member_of_brcm_prop_ie_t)) ++#define MEMBER_OF_BRCM_PROP_IE_TYPE 54 ++ ++/** BRCM Reliable Multicast IE */ ++BWL_PRE_PACKED_STRUCT struct relmcast_brcm_prop_ie { ++ uint8 id; ++ uint8 len; ++ uint8 oui[3]; ++ uint8 type; /* type indicates what follows */ ++ struct ether_addr ea; /* The ack sender's MAC Adrress */ ++ struct ether_addr mcast_ea; /* The multicast MAC address */ ++ uint8 updtmo; /* time interval(second) for client to send null packet to report its rssi */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct relmcast_brcm_prop_ie relmcast_brcm_prop_ie_t; ++ ++/* IE length */ ++/* BRCM_PROP_IE_LEN = sizeof(relmcast_brcm_prop_ie_t)-((sizeof (id) + sizeof (len)))? */ ++#define RELMCAST_BRCM_PROP_IE_LEN (sizeof(relmcast_brcm_prop_ie_t)-(2*sizeof(uint8))) ++ ++#define RELMCAST_BRCM_PROP_IE_TYPE 55 ++ ++/* BRCM BTC IE */ ++BWL_PRE_PACKED_STRUCT struct btc_brcm_prop_ie { ++ uint8 id; ++ uint8 len; ++ uint8 oui[3]; ++ uint8 type; /* type inidicates what follows */ ++ uint32 info; ++} BWL_POST_PACKED_STRUCT; ++typedef struct btc_brcm_prop_ie btc_brcm_prop_ie_t; ++ ++#define BTC_INFO_BRCM_PROP_IE_TYPE 90 ++#define BRCM_BTC_INFO_TYPE_LEN (sizeof(btc_brcm_prop_ie_t) - (2 * sizeof(uint8))) ++ ++/* ************* HT definitions. ************* */ ++#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ ++#define MAX_MCS_NUM (128) /* max mcs number = 128 */ ++ ++BWL_PRE_PACKED_STRUCT struct ht_cap_ie { ++ uint16 cap; ++ uint8 params; ++ uint8 supp_mcs[MCSSET_LEN]; ++ uint16 ext_htcap; ++ uint32 txbf_cap; ++ uint8 as_cap; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_cap_ie ht_cap_ie_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ht_cap_ie { ++ uint8 id; ++ uint8 len; ++ ht_cap_ie_t ht_cap; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ht_cap_ie dot11_ht_cap_ie_t; ++ ++/* CAP IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ ++/* the capability IE is primarily used to convey this nodes abilities */ ++BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; ++ uint8 type; /* type indicates what follows */ ++ ht_cap_ie_t cap_ie; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_prop_cap_ie ht_prop_cap_ie_t; ++ ++#define HT_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */ ++#define HT_CAP_IE_LEN 26 /* HT capability len (based on .11n d2.0) */ ++#define HT_CAP_IE_TYPE 51 ++ ++#define HT_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ ++#define HT_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ ++#define HT_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ ++#define HT_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ ++#define HT_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ ++#define HT_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ ++#define HT_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ ++#define HT_CAP_GF 0x0010 /* Greenfield preamble support */ ++#define HT_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ ++#define HT_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ ++#define HT_CAP_TX_STBC 0x0080 /* Tx STBC support */ ++#define HT_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ ++#define HT_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ ++#define HT_CAP_DELAYED_BA 0x0400 /* delayed BA support */ ++#define HT_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ ++ ++#define HT_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ ++#define HT_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ ++#define HT_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ ++#define HT_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ ++ ++#define HT_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ ++#define HT_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ ++#define HT_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ ++#define HT_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ ++ ++ ++#define HT_CAP_TXBF_CAP_IMPLICIT_TXBF_RX 0x1 ++#define HT_CAP_TXBF_CAP_NDP_RX 0x8 ++#define HT_CAP_TXBF_CAP_NDP_TX 0x10 ++#define HT_CAP_TXBF_CAP_EXPLICIT_CSI 0x100 ++#define HT_CAP_TXBF_CAP_EXPLICIT_NC_STEERING 0x200 ++#define HT_CAP_TXBF_CAP_EXPLICIT_C_STEERING 0x400 ++#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_MASK 0x1800 ++#define HT_CAP_TXBF_CAP_EXPLICIT_CSI_FB_SHIFT 11 ++#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_MASK 0x6000 ++#define HT_CAP_TXBF_CAP_EXPLICIT_NC_FB_SHIFT 13 ++#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_MASK 0x18000 ++#define HT_CAP_TXBF_CAP_EXPLICIT_C_FB_SHIFT 15 ++#define HT_CAP_TXBF_CAP_CSI_BFR_ANT_SHIFT 19 ++#define HT_CAP_TXBF_CAP_NC_BFR_ANT_SHIFT 21 ++#define HT_CAP_TXBF_CAP_C_BFR_ANT_SHIFT 23 ++#define HT_CAP_TXBF_CAP_C_BFR_ANT_MASK 0x1800000 ++ ++#define HT_CAP_TXBF_CAP_CHAN_ESTIM_SHIFT 27 ++#define HT_CAP_TXBF_CAP_CHAN_ESTIM_MASK 0x18000000 ++ ++#define HT_CAP_TXBF_FB_TYPE_NONE 0 ++#define HT_CAP_TXBF_FB_TYPE_DELAYED 1 ++#define HT_CAP_TXBF_FB_TYPE_IMMEDIATE 2 ++#define HT_CAP_TXBF_FB_TYPE_BOTH 3 ++ ++#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_MASK 0x400 ++#define HT_CAP_TX_BF_CAP_EXPLICIT_CSI_FB_SHIFT 10 ++#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_MASK 0x18000 ++#define HT_CAP_TX_BF_CAP_EXPLICIT_COMPRESSED_FB_SHIFT 15 ++ ++#define HT_CAP_MCS_FLAGS_SUPP_BYTE 12 /* byte offset in HT Cap Supported MCS for various flags */ ++#define HT_CAP_MCS_RX_8TO15_BYTE_OFFSET 1 ++#define HT_CAP_MCS_FLAGS_TX_RX_UNEQUAL 0x02 ++#define HT_CAP_MCS_FLAGS_MAX_SPATIAL_STREAM_MASK 0x0C ++ ++#define VHT_MAX_MPDU 11454 /* max mpdu size for now (bytes) */ ++#define VHT_MPDU_MSDU_DELTA 56 /* Difference in spec - vht mpdu, amsdu len */ ++/* Max AMSDU len - per spec */ ++#define VHT_MAX_AMSDU (VHT_MAX_MPDU - VHT_MPDU_MSDU_DELTA) ++ ++#define HT_MAX_AMSDU 7935 /* max amsdu size (bytes) per the HT spec */ ++#define HT_MIN_AMSDU 3835 /* min amsdu size (bytes) per the HT spec */ ++ ++#define HT_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */ ++#define HT_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */ ++#define HT_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */ ++ ++/* HT/AMPDU specific define */ ++#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/4 usec units */ ++#define AMPDU_DENSITY_NONE 0 /* No density requirement */ ++#define AMPDU_DENSITY_1over4_US 1 /* 1/4 us density */ ++#define AMPDU_DENSITY_1over2_US 2 /* 1/2 us density */ ++#define AMPDU_DENSITY_1_US 3 /* 1 us density */ ++#define AMPDU_DENSITY_2_US 4 /* 2 us density */ ++#define AMPDU_DENSITY_4_US 5 /* 4 us density */ ++#define AMPDU_DENSITY_8_US 6 /* 8 us density */ ++#define AMPDU_DENSITY_16_US 7 /* 16 us density */ ++#define AMPDU_RX_FACTOR_8K 0 /* max rcv ampdu len (8kb) */ ++#define AMPDU_RX_FACTOR_16K 1 /* max rcv ampdu len (16kb) */ ++#define AMPDU_RX_FACTOR_32K 2 /* max rcv ampdu len (32kb) */ ++#define AMPDU_RX_FACTOR_64K 3 /* max rcv ampdu len (64kb) */ ++ ++/* AMPDU RX factors for VHT rates */ ++#define AMPDU_RX_FACTOR_128K 4 /* max rcv ampdu len (128kb) */ ++#define AMPDU_RX_FACTOR_256K 5 /* max rcv ampdu len (256kb) */ ++#define AMPDU_RX_FACTOR_512K 6 /* max rcv ampdu len (512kb) */ ++#define AMPDU_RX_FACTOR_1024K 7 /* max rcv ampdu len (1024kb) */ ++ ++#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */ ++#define AMPDU_RX_FACTOR_BASE_PWR 13 /* ampdu factor base for rx len in power of 2 */ ++ ++#define AMPDU_DELIMITER_LEN 4 /* length of ampdu delimiter */ ++#define AMPDU_DELIMITER_LEN_MAX 63 /* max length of ampdu delimiter(enforced in HW) */ ++ ++#define HT_CAP_EXT_PCO 0x0001 ++#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006 ++#define HT_CAP_EXT_PCO_TTIME_SHIFT 1 ++#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300 ++#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8 ++#define HT_CAP_EXT_HTC 0x0400 ++#define HT_CAP_EXT_RD_RESP 0x0800 ++ ++/** 'ht_add' is called 'HT Operation' information element in the 802.11 standard */ ++BWL_PRE_PACKED_STRUCT struct ht_add_ie { ++ uint8 ctl_ch; /* control channel number */ ++ uint8 byte1; /* ext ch,rec. ch. width, RIFS support */ ++ uint16 opmode; /* operation mode */ ++ uint16 misc_bits; /* misc bits */ ++ uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_add_ie ht_add_ie_t; ++ ++/* ADD IE: HT 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ ++/* the additional IE is primarily used to convey the current BSS configuration */ ++BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie { ++ uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ ++ uint8 len; /* IE length */ ++ uint8 oui[3]; ++ uint8 type; /* indicates what follows */ ++ ht_add_ie_t add_ie; ++} BWL_POST_PACKED_STRUCT; ++typedef struct ht_prop_add_ie ht_prop_add_ie_t; ++ ++#define HT_ADD_IE_LEN 22 ++#define HT_ADD_IE_TYPE 52 ++ ++/* byte1 defn's */ ++#define HT_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */ ++#define HT_RIFS_PERMITTED 0x08 /* RIFS allowed */ ++ ++/* opmode defn's */ ++#define HT_OPMODE_MASK 0x0003 /* protection mode mask */ ++#define HT_OPMODE_SHIFT 0 /* protection mode shift */ ++#define HT_OPMODE_PURE 0x0000 /* protection mode PURE */ ++#define HT_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ ++#define HT_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ ++#define HT_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ ++#define HT_OPMODE_NONGF 0x0004 /* protection mode non-GF */ ++#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ ++#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ ++#define HT_OPMODE_CCFS2_MASK 0x1fe0 /* Channel Center Frequency Segment 2 mask */ ++#define HT_OPMODE_CCFS2_SHIFT 5 /* Channel Center Frequency Segment 2 shift */ ++ ++/* misc_bites defn's */ ++#define HT_BASIC_STBC_MCS 0x007f /* basic STBC MCS */ ++#define HT_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */ ++#define HT_SECOND_BCN 0x0100 /* Secondary beacon support */ ++#define HT_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */ ++#define HT_PCO_ACTIVE 0x0400 /* PCO active */ ++#define HT_PCO_PHASE 0x0800 /* PCO phase */ ++#define HT_DUALCTS_PROTECTION 0x0080 /* DUAL CTS protection needed */ ++ ++/* Tx Burst Limits */ ++#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */ ++#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */ ++ ++/* Macros for opmode */ ++#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ >> HT_OPMODE_SHIFT) ++#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ == HT_OPMODE_MIXED) /* mixed mode present */ ++#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ == HT_OPMODE_HT20IN40) /* 20MHz HT present */ ++#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \ ++ == HT_OPMODE_OPTIONAL) /* Optional protection present */ ++#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \ ++ HT_MIXEDMODE_PRESENT((add_ie))) /* use protection */ ++#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \ ++ == HT_OPMODE_NONGF) /* non-GF present */ ++#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ ++ == DOT11N_TXBURST) /* Tx Burst present */ ++#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ ++ == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */ ++#define HT_OPMODE_CCFS2_GET(add_ie) ((ltoh16_ua(&(add_ie)->opmode) & HT_OPMODE_CCFS2_MASK) \ ++ >> HT_OPMODE_CCFS2_SHIFT) /* get CCFS2 */ ++#define HT_OPMODE_CCFS2_SET(add_ie, ccfs2) do { /* set CCFS2 */ \ ++ (add_ie)->opmode &= htol16(~HT_OPMODE_CCFS2_MASK); \ ++ (add_ie)->opmode |= htol16(((ccfs2) << HT_OPMODE_CCFS2_SHIFT) & HT_OPMODE_CCFS2_MASK); \ ++} while (0) ++ ++/* Macros for HT MCS field access */ ++#define HT_CAP_MCS_BITMASK(supp_mcs) \ ++ ((supp_mcs)[HT_CAP_MCS_RX_8TO15_BYTE_OFFSET]) ++#define HT_CAP_MCS_TX_RX_UNEQUAL(supp_mcs) \ ++ ((supp_mcs)[HT_CAP_MCS_FLAGS_SUPP_BYTE] & HT_CAP_MCS_FLAGS_TX_RX_UNEQUAL) ++#define HT_CAP_MCS_TX_STREAM_SUPPORT(supp_mcs) \ ++ ((supp_mcs)[HT_CAP_MCS_FLAGS_SUPP_BYTE] & HT_CAP_MCS_FLAGS_MAX_SPATIAL_STREAM_MASK) ++ ++BWL_PRE_PACKED_STRUCT struct obss_params { ++ uint16 passive_dwell; ++ uint16 active_dwell; ++ uint16 bss_widthscan_interval; ++ uint16 passive_total; ++ uint16 active_total; ++ uint16 chanwidth_transition_dly; ++ uint16 activity_threshold; ++} BWL_POST_PACKED_STRUCT; ++typedef struct obss_params obss_params_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { ++ uint8 id; ++ uint8 len; ++ obss_params_t obss_params; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_obss_ie dot11_obss_ie_t; ++#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) /* HT OBSS len (based on 802.11n d3.0) */ ++ ++/* HT control field */ ++#define HT_CTRL_LA_TRQ 0x00000002 /* sounding request */ ++#define HT_CTRL_LA_MAI 0x0000003C /* MCS request or antenna selection indication */ ++#define HT_CTRL_LA_MAI_SHIFT 2 ++#define HT_CTRL_LA_MAI_MRQ 0x00000004 /* MCS request */ ++#define HT_CTRL_LA_MAI_MSI 0x00000038 /* MCS request sequence identifier */ ++#define HT_CTRL_LA_MFSI 0x000001C0 /* MFB sequence identifier */ ++#define HT_CTRL_LA_MFSI_SHIFT 6 ++#define HT_CTRL_LA_MFB_ASELC 0x0000FE00 /* MCS feedback, antenna selection command/data */ ++#define HT_CTRL_LA_MFB_ASELC_SH 9 ++#define HT_CTRL_LA_ASELC_CMD 0x00000C00 /* ASEL command */ ++#define HT_CTRL_LA_ASELC_DATA 0x0000F000 /* ASEL data */ ++#define HT_CTRL_CAL_POS 0x00030000 /* Calibration position */ ++#define HT_CTRL_CAL_SEQ 0x000C0000 /* Calibration sequence */ ++#define HT_CTRL_CSI_STEERING 0x00C00000 /* CSI/Steering */ ++#define HT_CTRL_CSI_STEER_SHIFT 22 ++#define HT_CTRL_CSI_STEER_NFB 0 /* no fedback required */ ++#define HT_CTRL_CSI_STEER_CSI 1 /* CSI, H matrix */ ++#define HT_CTRL_CSI_STEER_NCOM 2 /* non-compressed beamforming */ ++#define HT_CTRL_CSI_STEER_COM 3 /* compressed beamforming */ ++#define HT_CTRL_NDP_ANNOUNCE 0x01000000 /* NDP announcement */ ++#define HT_CTRL_AC_CONSTRAINT 0x40000000 /* AC Constraint */ ++#define HT_CTRL_RDG_MOREPPDU 0x80000000 /* RDG/More PPDU */ ++ ++/* ************* VHT definitions. ************* */ ++ ++/** ++ * VHT Capabilites IE (sec 8.4.2.160) ++ */ ++ ++BWL_PRE_PACKED_STRUCT struct vht_cap_ie { ++ uint32 vht_cap_info; ++ /* supported MCS set - 64 bit field */ ++ uint16 rx_mcs_map; ++ uint16 rx_max_rate; ++ uint16 tx_mcs_map; ++ uint16 tx_max_rate; ++} BWL_POST_PACKED_STRUCT; ++typedef struct vht_cap_ie vht_cap_ie_t; ++ ++/* 4B cap_info + 8B supp_mcs */ ++#define VHT_CAP_IE_LEN 12 ++ ++/* VHT Capabilities Info field - 32bit - in VHT Cap IE */ ++#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK 0x00000003 ++#define VHT_CAP_INFO_SUPP_CHAN_WIDTH_MASK 0x0000000c ++#define VHT_CAP_INFO_LDPC 0x00000010 ++#define VHT_CAP_INFO_SGI_80MHZ 0x00000020 ++#define VHT_CAP_INFO_SGI_160MHZ 0x00000040 ++#define VHT_CAP_INFO_TX_STBC 0x00000080 ++#define VHT_CAP_INFO_RX_STBC_MASK 0x00000700 ++#define VHT_CAP_INFO_RX_STBC_SHIFT 8 ++#define VHT_CAP_INFO_SU_BEAMFMR 0x00000800 ++#define VHT_CAP_INFO_SU_BEAMFMEE 0x00001000 ++#define VHT_CAP_INFO_NUM_BMFMR_ANT_MASK 0x0000e000 ++#define VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT 13 ++#define VHT_CAP_INFO_NUM_SOUNDING_DIM_MASK 0x00070000 ++#define VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT 16 ++#define VHT_CAP_INFO_MU_BEAMFMR 0x00080000 ++#define VHT_CAP_INFO_MU_BEAMFMEE 0x00100000 ++#define VHT_CAP_INFO_TXOPPS 0x00200000 ++#define VHT_CAP_INFO_HTCVHT 0x00400000 ++#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_MASK 0x03800000 ++#define VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT 23 ++#define VHT_CAP_INFO_LINK_ADAPT_CAP_MASK 0x0c000000 ++#define VHT_CAP_INFO_LINK_ADAPT_CAP_SHIFT 26 ++#define VHT_CAP_INFO_EXT_NSS_BW_SUP_MASK 0xc0000000 ++#define VHT_CAP_INFO_EXT_NSS_BW_SUP_SHIFT 30 ++ ++/* get Extended NSS BW Support passing vht cap info */ ++#define VHT_CAP_EXT_NSS_BW_SUP(cap_info) \ ++ (((cap_info) & VHT_CAP_INFO_EXT_NSS_BW_SUP_MASK) >> VHT_CAP_INFO_EXT_NSS_BW_SUP_SHIFT) ++ ++/* VHT CAP INFO extended NSS BW support - refer to IEEE 802.11 REVmc D8.0 Figure 9-559 */ ++#define VHT_CAP_INFO_EXT_NSS_BW_HALF_160 1 /* 160MHz at half NSS CAP */ ++#define VHT_CAP_INFO_EXT_NSS_BW_HALF_160_80P80 2 /* 160 & 80p80 MHz at half NSS CAP */ ++ ++/* VHT Supported MCS Set - 64-bit - in VHT Cap IE */ ++#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_MASK 0x1fff ++#define VHT_CAP_SUPP_MCS_RX_HIGHEST_RATE_SHIFT 0 ++#define VHT_CAP_SUPP_CHAN_WIDTH_SHIFT 5 ++ ++#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_MASK 0x1fff ++#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0 ++ ++/* defines for field(s) in vht_cap_ie->rx_max_rate */ ++#define VHT_CAP_MAX_NSTS_MASK 0xe000 ++#define VHT_CAP_MAX_NSTS_SHIFT 13 ++ ++/* defines for field(s) in vht_cap_ie->tx_max_rate */ ++#define VHT_CAP_EXT_NSS_BW_CAP 0x2000 ++ ++#define VHT_CAP_MCS_MAP_0_7 0 ++#define VHT_CAP_MCS_MAP_0_8 1 ++#define VHT_CAP_MCS_MAP_0_9 2 ++#define VHT_CAP_MCS_MAP_NONE 3 ++#define VHT_CAP_MCS_MAP_S 2 /* num bits for 1-stream */ ++#define VHT_CAP_MCS_MAP_M 0x3 /* mask for 1-stream */ ++/* assumes VHT_CAP_MCS_MAP_NONE is 3 and 2 bits are used for encoding */ ++#define VHT_CAP_MCS_MAP_NONE_ALL 0xffff ++ ++/* VHT rates bitmap */ ++#define VHT_CAP_MCS_0_7_RATEMAP 0x00ff ++#define VHT_CAP_MCS_0_8_RATEMAP 0x01ff ++#define VHT_CAP_MCS_0_9_RATEMAP 0x03ff ++#define VHT_CAP_MCS_FULL_RATEMAP VHT_CAP_MCS_0_9_RATEMAP ++ ++#define VHT_PROP_MCS_MAP_10_11 0 ++#define VHT_PROP_MCS_MAP_UNUSED1 1 ++#define VHT_PROP_MCS_MAP_UNUSED2 2 ++#define VHT_PROP_MCS_MAP_NONE 3 ++#define VHT_PROP_MCS_MAP_NONE_ALL 0xffff ++ ++/* VHT prop rates bitmap */ ++#define VHT_PROP_MCS_10_11_RATEMAP 0x0c00 ++#define VHT_PROP_MCS_FULL_RATEMAP VHT_PROP_MCS_10_11_RATEMAP ++ ++#if !defined(VHT_CAP_MCS_MAP_0_9_NSS3) ++/* mcsmap with MCS0-9 for Nss = 3 */ ++#define VHT_CAP_MCS_MAP_0_9_NSS3 \ ++ ((VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(1)) | \ ++ (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(2)) | \ ++ (VHT_CAP_MCS_MAP_0_9 << VHT_MCS_MAP_GET_SS_IDX(3))) ++#endif /* !VHT_CAP_MCS_MAP_0_9_NSS3 */ ++ ++#define VHT_CAP_MCS_MAP_NSS_MAX 8 ++ ++/* get mcsmap with given mcs for given nss streams */ ++#define VHT_CAP_MCS_MAP_CREATE(mcsmap, nss, mcs) \ ++ do { \ ++ int i; \ ++ for (i = 1; i <= nss; i++) { \ ++ VHT_MCS_MAP_SET_MCS_PER_SS(i, mcs, mcsmap); \ ++ } \ ++ } while (0) ++ ++/* Map the mcs code to mcs bit map */ ++#define VHT_MCS_CODE_TO_MCS_MAP(mcs_code) \ ++ ((mcs_code == VHT_CAP_MCS_MAP_0_7) ? VHT_CAP_MCS_0_7_RATEMAP : \ ++ (mcs_code == VHT_CAP_MCS_MAP_0_8) ? VHT_CAP_MCS_0_8_RATEMAP : \ ++ (mcs_code == VHT_CAP_MCS_MAP_0_9) ? VHT_CAP_MCS_0_9_RATEMAP : 0) ++ ++#define VHT_PROP_MCS_CODE_TO_PROP_MCS_MAP(mcs_code) \ ++ ((mcs_code == VHT_PROP_MCS_MAP_10_11) ? VHT_PROP_MCS_10_11_RATEMAP : 0) ++ ++/* Map the mcs bit map to mcs code */ ++#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \ ++ ((mcs_map == VHT_CAP_MCS_0_7_RATEMAP) ? VHT_CAP_MCS_MAP_0_7 : \ ++ (mcs_map == VHT_CAP_MCS_0_8_RATEMAP) ? VHT_CAP_MCS_MAP_0_8 : \ ++ (mcs_map == VHT_CAP_MCS_0_9_RATEMAP) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_MCS_MAP_NONE) ++ ++#define VHT_PROP_MCS_MAP_TO_PROP_MCS_CODE(mcs_map) \ ++ (((mcs_map & 0xc00) == 0xc00) ? VHT_PROP_MCS_MAP_10_11 : VHT_PROP_MCS_MAP_NONE) ++ ++/** VHT Capabilities Supported Channel Width */ ++typedef enum vht_cap_chan_width { ++ VHT_CAP_CHAN_WIDTH_SUPPORT_MANDATORY = 0x00, ++ VHT_CAP_CHAN_WIDTH_SUPPORT_160 = 0x04, ++ VHT_CAP_CHAN_WIDTH_SUPPORT_160_8080 = 0x08 ++} vht_cap_chan_width_t; ++ ++/** VHT Capabilities Supported max MPDU LEN (sec 8.4.2.160.2) */ ++typedef enum vht_cap_max_mpdu_len { ++ VHT_CAP_MPDU_MAX_4K = 0x00, ++ VHT_CAP_MPDU_MAX_8K = 0x01, ++ VHT_CAP_MPDU_MAX_11K = 0x02 ++} vht_cap_max_mpdu_len_t; ++ ++/* Maximum MPDU Length byte counts for the VHT Capabilities advertised limits */ ++#define VHT_MPDU_LIMIT_4K 3895 ++#define VHT_MPDU_LIMIT_8K 7991 ++#define VHT_MPDU_LIMIT_11K 11454 ++ ++ ++/** ++ * VHT Operation IE (sec 8.4.2.161) ++ */ ++ ++BWL_PRE_PACKED_STRUCT struct vht_op_ie { ++ uint8 chan_width; ++ uint8 chan1; ++ uint8 chan2; ++ uint16 supp_mcs; /* same def as above in vht cap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct vht_op_ie vht_op_ie_t; ++ ++/* 3B VHT Op info + 2B Basic MCS */ ++#define VHT_OP_IE_LEN 5 ++ ++typedef enum vht_op_chan_width { ++ VHT_OP_CHAN_WIDTH_20_40 = 0, ++ VHT_OP_CHAN_WIDTH_80 = 1, ++ VHT_OP_CHAN_WIDTH_160 = 2, /* deprecated - IEEE 802.11 REVmc D8.0 Table 11-25 */ ++ VHT_OP_CHAN_WIDTH_80_80 = 3 /* deprecated - IEEE 802.11 REVmc D8.0 Table 11-25 */ ++} vht_op_chan_width_t; ++ ++/* AID length */ ++#define AID_IE_LEN 2 ++/** ++ * BRCM vht features IE header ++ * The header if the fixed part of the IE ++ * On the 5GHz band this is the entire IE, ++ * on 2.4GHz the VHT IEs as defined in the 802.11ac ++ * specification follows ++ * ++ * ++ * VHT features rates bitmap. ++ * Bit0: 5G MCS 0-9 BW 160MHz ++ * Bit1: 5G MCS 0-9 support BW 80MHz ++ * Bit2: 5G MCS 0-9 support BW 20MHz ++ * Bit3: 2.4G MCS 0-9 support BW 20MHz ++ * Bits:4-7 Reserved for future use ++ * ++ */ ++#define VHT_FEATURES_IE_TYPE 0x4 ++BWL_PRE_PACKED_STRUCT struct vht_features_ie_hdr { ++ uint8 oui[3]; ++ uint8 type; /* type of this IE = 4 */ ++ uint8 rate_mask; /* VHT rate mask */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct vht_features_ie_hdr vht_features_ie_hdr_t; ++ ++/* Def for rx & tx basic mcs maps - ea ss num has 2 bits of info */ ++#define VHT_MCS_MAP_GET_SS_IDX(nss) (((nss)-1) * VHT_CAP_MCS_MAP_S) ++#define VHT_MCS_MAP_GET_MCS_PER_SS(nss, mcsMap) \ ++ (((mcsMap) >> VHT_MCS_MAP_GET_SS_IDX(nss)) & VHT_CAP_MCS_MAP_M) ++#define VHT_MCS_MAP_SET_MCS_PER_SS(nss, numMcs, mcsMap) \ ++ do { \ ++ (mcsMap) &= (~(VHT_CAP_MCS_MAP_M << VHT_MCS_MAP_GET_SS_IDX(nss))); \ ++ (mcsMap) |= (((numMcs) & VHT_CAP_MCS_MAP_M) << VHT_MCS_MAP_GET_SS_IDX(nss)); \ ++ } while (0) ++#define VHT_MCS_SS_SUPPORTED(nss, mcsMap) \ ++ (VHT_MCS_MAP_GET_MCS_PER_SS((nss), (mcsMap)) != VHT_CAP_MCS_MAP_NONE) ++ ++/* Get the max ss supported from the mcs map */ ++#define VHT_MAX_SS_SUPPORTED(mcsMap) \ ++ VHT_MCS_SS_SUPPORTED(8, mcsMap) ? 8 : \ ++ VHT_MCS_SS_SUPPORTED(7, mcsMap) ? 7 : \ ++ VHT_MCS_SS_SUPPORTED(6, mcsMap) ? 6 : \ ++ VHT_MCS_SS_SUPPORTED(5, mcsMap) ? 5 : \ ++ VHT_MCS_SS_SUPPORTED(4, mcsMap) ? 4 : \ ++ VHT_MCS_SS_SUPPORTED(3, mcsMap) ? 3 : \ ++ VHT_MCS_SS_SUPPORTED(2, mcsMap) ? 2 : \ ++ VHT_MCS_SS_SUPPORTED(1, mcsMap) ? 1 : 0 ++ ++/* ************* WPA definitions. ************* */ ++#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ ++#define WPA_OUI_LEN 3 /* WPA OUI length */ ++#define WPA_OUI_TYPE 1 ++#define WPA_VERSION 1 /* WPA version */ ++#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */ ++#define WPA2_OUI_LEN 3 /* WPA2 OUI length */ ++#define WPA2_VERSION 1 /* WPA2 version */ ++#define WPA2_VERSION_LEN 2 /* WAP2 version length */ ++ ++/* ************* WPS definitions. ************* */ ++#define WPS_OUI "\x00\x50\xF2" /* WPS OUI */ ++#define WPS_OUI_LEN 3 /* WPS OUI length */ ++#define WPS_OUI_TYPE 4 ++ ++/* ************* WFA definitions. ************* */ ++#if defined(WL_LEGACY_P2P) ++#define MAC_OUI "\x00\x17\xF2" /* MACOSX OUI */ ++#define MAC_OUI_TYPE_P2P 5 ++#endif ++ ++#ifdef P2P_IE_OVRD ++#define WFA_OUI MAC_OUI ++#else ++#define WFA_OUI "\x50\x6F\x9A" /* WFA OUI */ ++#endif /* P2P_IE_OVRD */ ++#define WFA_OUI_LEN 3 /* WFA OUI length */ ++#ifdef P2P_IE_OVRD ++#define WFA_OUI_TYPE_P2P MAC_OUI_TYPE_P2P ++#else ++#define WFA_OUI_TYPE_TPC 8 ++#define WFA_OUI_TYPE_P2P 9 ++#endif ++ ++#define WFA_OUI_TYPE_TPC 8 ++#ifdef WLTDLS ++#define WFA_OUI_TYPE_TPQ 4 /* WFD Tunneled Probe ReQuest */ ++#define WFA_OUI_TYPE_TPS 5 /* WFD Tunneled Probe ReSponse */ ++#define WFA_OUI_TYPE_WFD 10 ++#endif /* WTDLS */ ++#define WFA_OUI_TYPE_HS20 0x10 ++#define WFA_OUI_TYPE_OSEN 0x12 ++#define WFA_OUI_TYPE_NAN 0x13 ++#define WFA_OUI_TYPE_MBO 0x16 ++#define WFA_OUI_TYPE_MBO_OCE 0x16 ++ ++/* RSN authenticated key managment suite */ ++#define RSN_AKM_NONE 0 /* None (IBSS) */ ++#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ ++#define RSN_AKM_PSK 2 /* Pre-shared Key */ ++#define RSN_AKM_FBT_1X 3 /* Fast Bss transition using 802.1X */ ++#define RSN_AKM_FBT_PSK 4 /* Fast Bss transition using Pre-shared Key */ ++/* RSN_AKM_MFP_1X and RSN_AKM_MFP_PSK are not used any more ++ * Just kept here to avoid build issue in BISON/CARIBOU branch ++ */ ++#define RSN_AKM_MFP_1X 5 /* SHA256 key derivation, using 802.1X */ ++#define RSN_AKM_MFP_PSK 6 /* SHA256 key derivation, using Pre-shared Key */ ++#define RSN_AKM_SHA256_1X 5 /* SHA256 key derivation, using 802.1X */ ++#define RSN_AKM_SHA256_PSK 6 /* SHA256 key derivation, using Pre-shared Key */ ++#define RSN_AKM_TPK 7 /* TPK(TDLS Peer Key) handshake */ ++#define RSN_AKM_SAE_PSK 8 /* AKM for SAE with 4-way handshake */ ++#define RSN_AKM_SAE_FBT 9 /* AKM for SAE with FBT */ ++#define RSN_AKM_FILS_SHA256 14 /* SHA256 key derivation, using FILS */ ++#define RSN_AKM_FILS_SHA384 15 /* SHA384 key derivation, using FILS */ ++ ++/* OSEN authenticated key managment suite */ ++#define OSEN_AKM_UNSPECIFIED RSN_AKM_UNSPECIFIED /* Over 802.1x */ ++ ++/* Key related defines */ ++#define DOT11_MAX_DEFAULT_KEYS 4 /* number of default keys */ ++#define DOT11_MAX_IGTK_KEYS 2 ++#define DOT11_MAX_KEY_SIZE 32 /* max size of any key */ ++#define DOT11_MAX_IV_SIZE 16 /* max size of any IV */ ++#define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */ ++#define DOT11_WPA_KEY_RSC_LEN 8 /* WPA RSC key len */ ++ ++#define WEP1_KEY_SIZE 5 /* max size of any WEP key */ ++#define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */ ++#define WEP128_KEY_SIZE 13 /* max size of any WEP key */ ++#define WEP128_KEY_HEX_SIZE 26 /* size of WEP key in hex. */ ++#define TKIP_MIC_SIZE 8 /* size of TKIP MIC */ ++#define TKIP_EOM_SIZE 7 /* max size of TKIP EOM */ ++#define TKIP_EOM_FLAG 0x5a /* TKIP EOM flag byte */ ++#define TKIP_KEY_SIZE 32 /* size of any TKIP key, includs MIC keys */ ++#define TKIP_TK_SIZE 16 ++#define TKIP_MIC_KEY_SIZE 8 ++#define TKIP_MIC_AUTH_TX 16 /* offset to Authenticator MIC TX key */ ++#define TKIP_MIC_AUTH_RX 24 /* offset to Authenticator MIC RX key */ ++#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX /* offset to Supplicant MIC RX key */ ++#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX /* offset to Supplicant MIC TX key */ ++#define AES_KEY_SIZE 16 /* size of AES key */ ++#define AES_MIC_SIZE 8 /* size of AES MIC */ ++#define BIP_KEY_SIZE 16 /* size of BIP key */ ++#define BIP_MIC_SIZE 8 /* sizeof BIP MIC */ ++ ++#define AES_GCM_MIC_SIZE 16 /* size of MIC for 128-bit GCM - .11adD9 */ ++ ++#define AES256_KEY_SIZE 32 /* size of AES 256 key - .11acD5 */ ++#define AES256_MIC_SIZE 16 /* size of MIC for 256 bit keys, incl BIP */ ++ ++/* WCN */ ++#define WCN_OUI "\x00\x50\xf2" /* WCN OUI */ ++#define WCN_TYPE 4 /* WCN type */ ++ ++#ifdef BCMWAPI_WPI ++#define SMS4_KEY_LEN 16 ++#define SMS4_WPI_CBC_MAC_LEN 16 ++#endif ++ ++/* 802.11r protocol definitions */ ++ ++/** Mobility Domain IE */ ++BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie { ++ uint8 id; ++ uint8 len; ++ uint16 mdid; /* Mobility Domain Id */ ++ uint8 cap; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_mdid_ie dot11_mdid_ie_t; ++ ++#define FBT_MDID_CAP_OVERDS 0x01 /* Fast Bss transition over the DS support */ ++#define FBT_MDID_CAP_RRP 0x02 /* Resource request protocol support */ ++ ++/** Fast Bss Transition IE */ ++BWL_PRE_PACKED_STRUCT struct dot11_ft_ie { ++ uint8 id; ++ uint8 len; ++ uint16 mic_control; /* Mic Control */ ++ uint8 mic[16]; ++ uint8 anonce[32]; ++ uint8 snonce[32]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ft_ie dot11_ft_ie_t; ++ ++#define TIE_TYPE_RESERVED 0 ++#define TIE_TYPE_REASSOC_DEADLINE 1 ++#define TIE_TYPE_KEY_LIEFTIME 2 ++#define TIE_TYPE_ASSOC_COMEBACK 3 ++BWL_PRE_PACKED_STRUCT struct dot11_timeout_ie { ++ uint8 id; ++ uint8 len; ++ uint8 type; /* timeout interval type */ ++ uint32 value; /* timeout interval value */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_timeout_ie dot11_timeout_ie_t; ++ ++/** GTK ie */ ++BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { ++ uint8 id; ++ uint8 len; ++ uint16 key_info; ++ uint8 key_len; ++ uint8 rsc[8]; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_gtk_ie dot11_gtk_ie_t; ++ ++/** Management MIC ie */ ++BWL_PRE_PACKED_STRUCT struct mmic_ie { ++ uint8 id; /* IE ID: DOT11_MNG_MMIE_ID */ ++ uint8 len; /* IE length */ ++ uint16 key_id; /* key id */ ++ uint8 ipn[6]; /* ipn */ ++ uint8 mic[16]; /* mic */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct mmic_ie mmic_ie_t; ++ ++/* 802.11r-2008, 11A.10.3 - RRB frame format */ ++BWL_PRE_PACKED_STRUCT struct dot11_ft_rrb_frame { ++ uint8 frame_type; /* 1 for RRB */ ++ uint8 packet_type; /* 0 for Request 1 for Response */ ++ uint16 len; ++ uint8 cur_ap_addr[ETHER_ADDR_LEN]; ++ uint8 data[1]; /* IEs Received/Sent in FT Action Req/Resp Frame */ ++} BWL_POST_PACKED_STRUCT; ++ ++typedef struct dot11_ft_rrb_frame dot11_ft_rrb_frame_t; ++ ++#define DOT11_FT_RRB_FIXED_LEN 10 ++#define DOT11_FT_REMOTE_FRAME_TYPE 1 ++#define DOT11_FT_PACKET_REQ 0 ++#define DOT11_FT_PACKET_RESP 1 ++ ++#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" ++#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" ++ ++#ifdef BCMWAPI_WAI ++#define WAPI_IE_MIN_LEN 20 /* WAPI IE min length */ ++#define WAPI_VERSION 1 /* WAPI version */ ++#define WAPI_VERSION_LEN 2 /* WAPI version length */ ++#define WAPI_OUI "\x00\x14\x72" /* WAPI OUI */ ++#define WAPI_OUI_LEN DOT11_OUI_LEN /* WAPI OUI length */ ++#endif /* BCMWAPI_WAI */ ++ ++/* ************* WMM Parameter definitions. ************* */ ++#define WMM_OUI "\x00\x50\xF2" /* WNN OUI */ ++#define WMM_OUI_LEN 3 /* WMM OUI length */ ++#define WMM_OUI_TYPE 2 /* WMM OUT type */ ++#define WMM_VERSION 1 ++#define WMM_VERSION_LEN 1 ++ ++/* WMM OUI subtype */ ++#define WMM_OUI_SUBTYPE_PARAMETER 1 ++#define WMM_PARAMETER_IE_LEN 24 ++ ++/** Link Identifier Element */ ++BWL_PRE_PACKED_STRUCT struct link_id_ie { ++ uint8 id; ++ uint8 len; ++ struct ether_addr bssid; ++ struct ether_addr tdls_init_mac; ++ struct ether_addr tdls_resp_mac; ++} BWL_POST_PACKED_STRUCT; ++typedef struct link_id_ie link_id_ie_t; ++#define TDLS_LINK_ID_IE_LEN 18 ++ ++/** Link Wakeup Schedule Element */ ++BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { ++ uint8 id; ++ uint8 len; ++ uint32 offset; /* in ms between TSF0 and start of 1st Awake Window */ ++ uint32 interval; /* in ms bwtween the start of 2 Awake Windows */ ++ uint32 awake_win_slots; /* in backof slots, duration of Awake Window */ ++ uint32 max_wake_win; /* in ms, max duration of Awake Window */ ++ uint16 idle_cnt; /* number of consecutive Awake Windows */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wakeup_sch_ie wakeup_sch_ie_t; ++#define TDLS_WAKEUP_SCH_IE_LEN 18 ++ ++/** Channel Switch Timing Element */ ++BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { ++ uint8 id; ++ uint8 len; ++ uint16 switch_time; /* in ms, time to switch channels */ ++ uint16 switch_timeout; /* in ms */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; ++#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 ++ ++/** PTI Control Element */ ++BWL_PRE_PACKED_STRUCT struct pti_control_ie { ++ uint8 id; ++ uint8 len; ++ uint8 tid; ++ uint16 seq_control; ++} BWL_POST_PACKED_STRUCT; ++typedef struct pti_control_ie pti_control_ie_t; ++#define TDLS_PTI_CONTROL_IE_LEN 3 ++ ++/** PU Buffer Status Element */ ++BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { ++ uint8 id; ++ uint8 len; ++ uint8 status; ++} BWL_POST_PACKED_STRUCT; ++typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; ++#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 ++#define TDLS_PU_BUFFER_STATUS_AC_BK 1 ++#define TDLS_PU_BUFFER_STATUS_AC_BE 2 ++#define TDLS_PU_BUFFER_STATUS_AC_VI 4 ++#define TDLS_PU_BUFFER_STATUS_AC_VO 8 ++ ++/* TDLS Action Field Values */ ++#define TDLS_SETUP_REQ 0 ++#define TDLS_SETUP_RESP 1 ++#define TDLS_SETUP_CONFIRM 2 ++#define TDLS_TEARDOWN 3 ++#define TDLS_PEER_TRAFFIC_IND 4 ++#define TDLS_CHANNEL_SWITCH_REQ 5 ++#define TDLS_CHANNEL_SWITCH_RESP 6 ++#define TDLS_PEER_PSM_REQ 7 ++#define TDLS_PEER_PSM_RESP 8 ++#define TDLS_PEER_TRAFFIC_RESP 9 ++#define TDLS_DISCOVERY_REQ 10 ++ ++/* 802.11z TDLS Public Action Frame action field */ ++#define TDLS_DISCOVERY_RESP 14 ++ ++/* 802.11u GAS action frames */ ++#define GAS_REQUEST_ACTION_FRAME 10 ++#define GAS_RESPONSE_ACTION_FRAME 11 ++#define GAS_COMEBACK_REQUEST_ACTION_FRAME 12 ++#define GAS_COMEBACK_RESPONSE_ACTION_FRAME 13 ++ ++/* FTM - fine timing measurement public action frames */ ++BWL_PRE_PACKED_STRUCT struct dot11_ftm_req { ++ uint8 category; /* category of action frame (4) */ ++ uint8 action; /* public action (32) */ ++ uint8 trigger; /* trigger/continue? */ ++ /* optional lci, civic loc, ftm params */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ftm_req dot11_ftm_req_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ftm { ++ uint8 category; /* category of action frame (4) */ ++ uint8 action; /* public action (33) */ ++ uint8 dialog; /* dialog token */ ++ uint8 follow_up; /* follow up dialog token */ ++ uint8 tod[6]; /* t1 - last depart timestamp */ ++ uint8 toa[6]; /* t4 - last ack arrival timestamp */ ++ uint8 tod_err[2]; /* t1 error */ ++ uint8 toa_err[2]; /* t4 error */ ++ /* optional lci report, civic loc report, ftm params */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ftm dot11_ftm_t; ++ ++ ++#define DOT11_FTM_ERR_NOT_CONT_OFFSET 1 ++#define DOT11_FTM_ERR_NOT_CONT_MASK 0x80 ++#define DOT11_FTM_ERR_NOT_CONT_SHIFT 7 ++#define DOT11_FTM_ERR_NOT_CONT(_err) (((_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] & \ ++ DOT11_FTM_ERR_NOT_CONT_MASK) >> DOT11_FTM_ERR_NOT_CONT_SHIFT) ++#define DOT11_FTM_ERR_SET_NOT_CONT(_err, _val) do {\ ++ uint8 _err2 = (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET]; \ ++ _err2 &= ~DOT11_FTM_ERR_NOT_CONT_MASK; \ ++ _err2 |= ((_val) << DOT11_FTM_ERR_NOT_CONT_SHIFT) & DOT11_FTM_ERR_NOT_CONT_MASK; \ ++ (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] = _err2; \ ++} while (0) ++ ++#define DOT11_FTM_ERR_MAX_ERR_OFFSET 0 ++#define DOT11_FTM_ERR_MAX_ERR_MASK 0x7fff ++#define DOT11_FTM_ERR_MAX_ERR_SHIFT 0 ++#define DOT11_FTM_ERR_MAX_ERR(_err) (((((_err)[1] & 0x7f) << 8) | (_err)[0])) ++#define DOT11_FTM_ERR_SET_MAX_ERR(_err, _val) do {\ ++ uint16 _val2; \ ++ uint16 _not_cont; \ ++ _val2 = (((_val) & DOT11_FTM_ERR_MAX_ERR_MASK) << DOT11_FTM_ERR_MAX_ERR_SHIFT); \ ++ _val2 = (_val2 > 0x3fff) ? 0 : _val2; /* not expecting > 16ns error */ \ ++ _not_cont = DOT11_FTM_ERR_NOT_CONT(_err); \ ++ (_err)[0] = _val2 & 0xff; \ ++ (_err)[1] = (_val2 >> 8) & 0xff; \ ++ DOT11_FTM_ERR_SET_NOT_CONT(_err, _not_cont); \ ++} while (0) ++ ++#if defined(DOT11_FTM_ERR_ROM_COMPAT) ++/* incorrect defs - here for ROM compatibiity */ ++#undef DOT11_FTM_ERR_NOT_CONT_OFFSET ++#undef DOT11_FTM_ERR_NOT_CONT_MASK ++#undef DOT11_FTM_ERR_NOT_CONT_SHIFT ++#undef DOT11_FTM_ERR_NOT_CONT ++#undef DOT11_FTM_ERR_SET_NOT_CONT ++ ++#define DOT11_FTM_ERR_NOT_CONT_OFFSET 0 ++#define DOT11_FTM_ERR_NOT_CONT_MASK 0x0001 ++#define DOT11_FTM_ERR_NOT_CONT_SHIFT 0 ++#define DOT11_FTM_ERR_NOT_CONT(_err) (((_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] & \ ++ DOT11_FTM_ERR_NOT_CONT_MASK) >> DOT11_FTM_ERR_NOT_CONT_SHIFT) ++#define DOT11_FTM_ERR_SET_NOT_CONT(_err, _val) do {\ ++ uint8 _err2 = (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET]; \ ++ _err2 &= ~DOT11_FTM_ERR_NOT_CONT_MASK; \ ++ _err2 |= ((_val) << DOT11_FTM_ERR_NOT_CONT_SHIFT) & DOT11_FTM_ERR_NOT_CONT_MASK; \ ++ (_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] = _err2; \ ++} while (0) ++ ++#undef DOT11_FTM_ERR_MAX_ERR_OFFSET ++#undef DOT11_FTM_ERR_MAX_ERR_MASK ++#undef DOT11_FTM_ERR_MAX_ERR_SHIFT ++#undef DOT11_FTM_ERR_MAX_ERR ++#undef DOT11_FTM_ERR_SET_MAX_ERR ++ ++#define DOT11_FTM_ERR_MAX_ERR_OFFSET 0 ++#define DOT11_FTM_ERR_MAX_ERR_MASK 0xfff7 ++#define DOT11_FTM_ERR_MAX_ERR_SHIFT 1 ++#define DOT11_FTM_ERR_MAX_ERR(_err) ((((_err)[1] << 7) | (_err)[0]) >> 1) ++#define DOT11_FTM_ERR_SET_MAX_ERR(_err, _val) do {\ ++ uint16 _val2; \ ++ _val2 = (((_val) << DOT11_FTM_ERR_MAX_ERR_SHIFT) |\ ++ ((_err)[DOT11_FTM_ERR_NOT_CONT_OFFSET] & DOT11_FTM_ERR_NOT_CONT_MASK)); \ ++ (_err)[0] = _val2 & 0xff; \ ++ (_err)[1] = _val2 >> 8 & 0xff; \ ++} while (0) ++#endif /* DOT11_FTM_ERR_ROM_COMPAT */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ftm_params { ++ uint8 id; /* DOT11_MNG_FTM_PARAM_ID 8.4.2.166 11mcd2.6/2014 - revisit */ ++ uint8 len; ++ uint8 info[9]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ftm_params dot11_ftm_params_t; ++#define DOT11_FTM_PARAMS_IE_LEN (sizeof(dot11_ftm_params_t) - 2) ++ ++#define FTM_PARAMS_FIELD(_p, _off, _mask, _shift) (((_p)->info[(_off)] & (_mask)) >> (_shift)) ++#define FTM_PARAMS_SET_FIELD(_p, _off, _mask, _shift, _val) do {\ ++ uint8 _ptmp = (_p)->info[_off] & ~(_mask); \ ++ (_p)->info[(_off)] = _ptmp | (((_val) << (_shift)) & (_mask)); \ ++} while (0) ++ ++#define FTM_PARAMS_STATUS_OFFSET 0 ++#define FTM_PARAMS_STATUS_MASK 0x03 ++#define FTM_PARAMS_STATUS_SHIFT 0 ++#define FTM_PARAMS_STATUS(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_STATUS_OFFSET, \ ++ FTM_PARAMS_STATUS_MASK, FTM_PARAMS_STATUS_SHIFT) ++#define FTM_PARAMS_SET_STATUS(_p, _status) FTM_PARAMS_SET_FIELD(_p, \ ++ FTM_PARAMS_STATUS_OFFSET, FTM_PARAMS_STATUS_MASK, FTM_PARAMS_STATUS_SHIFT, _status) ++ ++#define FTM_PARAMS_VALUE_OFFSET 0 ++#define FTM_PARAMS_VALUE_MASK 0x7c ++#define FTM_PARAMS_VALUE_SHIFT 2 ++#define FTM_PARAMS_VALUE(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_VALUE_OFFSET, \ ++ FTM_PARAMS_VALUE_MASK, FTM_PARAMS_VALUE_SHIFT) ++#define FTM_PARAMS_SET_VALUE(_p, _value) FTM_PARAMS_SET_FIELD(_p, \ ++ FTM_PARAMS_VALUE_OFFSET, FTM_PARAMS_VALUE_MASK, FTM_PARAMS_VALUE_SHIFT, _value) ++#define FTM_PARAMS_MAX_VALUE 32 ++ ++#define FTM_PARAMS_NBURSTEXP_OFFSET 1 ++#define FTM_PARAMS_NBURSTEXP_MASK 0x0f ++#define FTM_PARAMS_NBURSTEXP_SHIFT 0 ++#define FTM_PARAMS_NBURSTEXP(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_NBURSTEXP_OFFSET, \ ++ FTM_PARAMS_NBURSTEXP_MASK, FTM_PARAMS_NBURSTEXP_SHIFT) ++#define FTM_PARAMS_SET_NBURSTEXP(_p, _bexp) FTM_PARAMS_SET_FIELD(_p, \ ++ FTM_PARAMS_NBURSTEXP_OFFSET, FTM_PARAMS_NBURSTEXP_MASK, FTM_PARAMS_NBURSTEXP_SHIFT, \ ++ _bexp) ++ ++#define FTM_PARAMS_NBURST(_p) (1 << FTM_PARAMS_NBURSTEXP(_p)) ++ ++enum { ++ FTM_PARAMS_NBURSTEXP_NOPREF = 15 ++}; ++ ++enum { ++ FTM_PARAMS_BURSTTMO_NOPREF = 15 ++}; ++ ++#define FTM_PARAMS_BURSTTMO_OFFSET 1 ++#define FTM_PARAMS_BURSTTMO_MASK 0xf0 ++#define FTM_PARAMS_BURSTTMO_SHIFT 4 ++#define FTM_PARAMS_BURSTTMO(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_BURSTTMO_OFFSET, \ ++ FTM_PARAMS_BURSTTMO_MASK, FTM_PARAMS_BURSTTMO_SHIFT) ++/* set timeout in params using _tmo where timeout = 2^(_tmo) * 250us */ ++#define FTM_PARAMS_SET_BURSTTMO(_p, _tmo) FTM_PARAMS_SET_FIELD(_p, \ ++ FTM_PARAMS_BURSTTMO_OFFSET, FTM_PARAMS_BURSTTMO_MASK, FTM_PARAMS_BURSTTMO_SHIFT, (_tmo)+2) ++ ++#define FTM_PARAMS_BURSTTMO_USEC(_val) ((1 << ((_val)-2)) * 250) ++#define FTM_PARAMS_BURSTTMO_VALID(_val) ((((_val) < 12 && (_val) > 1)) || \ ++ (_val) == FTM_PARAMS_BURSTTMO_NOPREF) ++#define FTM_PARAMS_BURSTTMO_MAX_MSEC 128 /* 2^9 * 250us */ ++#define FTM_PARAMS_BURSTTMO_MAX_USEC 128000 /* 2^9 * 250us */ ++ ++#define FTM_PARAMS_MINDELTA_OFFSET 2 ++#define FTM_PARAMS_MINDELTA_USEC(_p) ((_p)->info[FTM_PARAMS_MINDELTA_OFFSET] * 100) ++#define FTM_PARAMS_SET_MINDELTA_USEC(_p, _delta) do { \ ++ (_p)->info[FTM_PARAMS_MINDELTA_OFFSET] = (_delta) / 100; \ ++} while (0) ++ ++enum { ++ FTM_PARAMS_MINDELTA_NOPREF = 0 ++}; ++ ++#define FTM_PARAMS_PARTIAL_TSF(_p) ((_p)->info[4] << 8 | (_p)->info[3]) ++#define FTM_PARAMS_SET_PARTIAL_TSF(_p, _partial_tsf) do { \ ++ (_p)->info[3] = (_partial_tsf) & 0xff; \ ++ (_p)->info[4] = ((_partial_tsf) >> 8) & 0xff; \ ++} while (0) ++ ++#define FTM_PARAMS_PARTIAL_TSF_MASK 0x0000000003fffc00ULL ++#define FTM_PARAMS_PARTIAL_TSF_SHIFT 10 ++#define FTM_PARAMS_PARTIAL_TSF_BIT_LEN 16 ++#define FTM_PARAMS_PARTIAL_TSF_MAX 0xffff ++ ++/* FTM can indicate upto 62k TUs forward and 1k TU backward */ ++#define FTM_PARAMS_TSF_FW_HI (63487 << 10) /* in micro sec */ ++#define FTM_PARAMS_TSF_BW_LOW (64512 << 10) /* in micro sec */ ++#define FTM_PARAMS_TSF_BW_HI (65535 << 10) /* in micro sec */ ++#define FTM_PARAMS_TSF_FW_MAX FTM_PARAMS_TSF_FW_HI ++#define FTM_PARAMS_TSF_BW_MAX (FTM_PARAMS_TSF_BW_HI - FTM_PARAMS_TSF_BW_LOW) ++ ++#define FTM_PARAMS_PTSFNOPREF_OFFSET 5 ++#define FTM_PARAMS_PTSFNOPREF_MASK 0x1 ++#define FTM_PARAMS_PTSFNOPREF_SHIFT 0 ++#define FTM_PARAMS_PTSFNOPREF(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_PTSFNOPREF_OFFSET, \ ++ FTM_PARAMS_PTSFNOPREF_MASK, FTM_PARAMS_PTSFNOPREF_SHIFT) ++#define FTM_PARAMS_SET_PTSFNOPREF(_p, _nopref) FTM_PARAMS_SET_FIELD(_p, \ ++ FTM_PARAMS_PTSFNOPREF_OFFSET, FTM_PARAMS_PTSFNOPREF_MASK, \ ++ FTM_PARAMS_PTSFNOPREF_SHIFT, _nopref) ++ ++#define FTM_PARAMS_ASAP_OFFSET 5 ++#define FTM_PARAMS_ASAP_MASK 0x4 ++#define FTM_PARAMS_ASAP_SHIFT 2 ++#define FTM_PARAMS_ASAP(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_ASAP_OFFSET, \ ++ FTM_PARAMS_ASAP_MASK, FTM_PARAMS_ASAP_SHIFT) ++#define FTM_PARAMS_SET_ASAP(_p, _asap) FTM_PARAMS_SET_FIELD(_p, \ ++ FTM_PARAMS_ASAP_OFFSET, FTM_PARAMS_ASAP_MASK, FTM_PARAMS_ASAP_SHIFT, _asap) ++ ++/* FTM1 - AKA ASAP Capable */ ++#define FTM_PARAMS_FTM1_OFFSET 5 ++#define FTM_PARAMS_FTM1_MASK 0x02 ++#define FTM_PARAMS_FTM1_SHIFT 1 ++#define FTM_PARAMS_FTM1(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_FTM1_OFFSET, \ ++ FTM_PARAMS_FTM1_MASK, FTM_PARAMS_FTM1_SHIFT) ++#define FTM_PARAMS_SET_FTM1(_p, _ftm1) FTM_PARAMS_SET_FIELD(_p, \ ++ FTM_PARAMS_FTM1_OFFSET, FTM_PARAMS_FTM1_MASK, FTM_PARAMS_FTM1_SHIFT, _ftm1) ++ ++#define FTM_PARAMS_FTMS_PER_BURST_OFFSET 5 ++#define FTM_PARAMS_FTMS_PER_BURST_MASK 0xf8 ++#define FTM_PARAMS_FTMS_PER_BURST_SHIFT 3 ++#define FTM_PARAMS_FTMS_PER_BURST(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_FTMS_PER_BURST_OFFSET, \ ++ FTM_PARAMS_FTMS_PER_BURST_MASK, FTM_PARAMS_FTMS_PER_BURST_SHIFT) ++#define FTM_PARAMS_SET_FTMS_PER_BURST(_p, _nftms) FTM_PARAMS_SET_FIELD(_p, \ ++ FTM_PARAMS_FTMS_PER_BURST_OFFSET, FTM_PARAMS_FTMS_PER_BURST_MASK, \ ++ FTM_PARAMS_FTMS_PER_BURST_SHIFT, _nftms) ++ ++enum { ++ FTM_PARAMS_FTMS_PER_BURST_NOPREF = 0 ++}; ++ ++#define FTM_PARAMS_CHAN_INFO_OFFSET 6 ++#define FTM_PARAMS_CHAN_INFO_MASK 0xfc ++#define FTM_PARAMS_CHAN_INFO_SHIFT 2 ++#define FTM_PARAMS_CHAN_INFO(_p) FTM_PARAMS_FIELD(_p, FTM_PARAMS_CHAN_INFO_OFFSET, \ ++ FTM_PARAMS_CHAN_INFO_MASK, FTM_PARAMS_CHAN_INFO_SHIFT) ++#define FTM_PARAMS_SET_CHAN_INFO(_p, _ci) FTM_PARAMS_SET_FIELD(_p, \ ++ FTM_PARAMS_CHAN_INFO_OFFSET, FTM_PARAMS_CHAN_INFO_MASK, FTM_PARAMS_CHAN_INFO_SHIFT, _ci) ++ ++/* burst period - units of 100ms */ ++#define FTM_PARAMS_BURST_PERIOD(_p) (((_p)->info[8] << 8) | (_p)->info[7]) ++#define FTM_PARAMS_SET_BURST_PERIOD(_p, _bp) do {\ ++ (_p)->info[7] = (_bp) & 0xff; \ ++ (_p)->info[8] = ((_bp) >> 8) & 0xff; \ ++} while (0) ++ ++#define FTM_PARAMS_BURST_PERIOD_MS(_p) (FTM_PARAMS_BURST_PERIOD(_p) * 100) ++ ++enum { ++ FTM_PARAMS_BURST_PERIOD_NOPREF = 0 ++}; ++ ++/* FTM status values - last updated from 11mcD4.0 */ ++enum { ++ FTM_PARAMS_STATUS_RESERVED = 0, ++ FTM_PARAMS_STATUS_SUCCESSFUL = 1, ++ FTM_PARAMS_STATUS_INCAPABLE = 2, ++ FTM_PARAMS_STATUS_FAILED = 3, ++ /* Below are obsolte */ ++ FTM_PARAMS_STATUS_OVERRIDDEN = 4, ++ FTM_PARAMS_STATUS_ASAP_INCAPABLE = 5, ++ FTM_PARAMS_STATUS_ASAP_FAILED = 6, ++ /* rest are reserved */ ++}; ++ ++enum { ++ FTM_PARAMS_CHAN_INFO_NO_PREF = 0, ++ FTM_PARAMS_CHAN_INFO_RESERVE1 = 1, ++ FTM_PARAMS_CHAN_INFO_RESERVE2 = 2, ++ FTM_PARAMS_CHAN_INFO_RESERVE3 = 3, ++ FTM_PARAMS_CHAN_INFO_NON_HT_5 = 4, ++ FTM_PARAMS_CHAN_INFO_RESERVE5 = 5, ++ FTM_PARAMS_CHAN_INFO_NON_HT_10 = 6, ++ FTM_PARAMS_CHAN_INFO_RESERVE7 = 7, ++ FTM_PARAMS_CHAN_INFO_NON_HT_20 = 8, /* excludes 2.4G, and High rate DSSS */ ++ FTM_PARAMS_CHAN_INFO_HT_MF_20 = 9, ++ FTM_PARAMS_CHAN_INFO_VHT_20 = 10, ++ FTM_PARAMS_CHAN_INFO_HT_MF_40 = 11, ++ FTM_PARAMS_CHAN_INFO_VHT_40 = 12, ++ FTM_PARAMS_CHAN_INFO_VHT_80 = 13, ++ FTM_PARAMS_CHAN_INFO_VHT_80_80 = 14, ++ FTM_PARAMS_CHAN_INFO_VHT_160_2_RFLOS = 15, ++ FTM_PARAMS_CHAN_INFO_VHT_160 = 16, ++ /* Reserved from 17 - 30 */ ++ FTM_PARAMS_CHAN_INFO_DMG_2160 = 31, ++ /* Reserved from 32 - 63 */ ++ FTM_PARAMS_CHAN_INFO_MAX = 63 ++}; ++ ++/* tag_ID/length/value_buffer tuple */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 id; ++ uint8 len; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT ftm_vs_tlv_t; ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ftm_vs_ie { ++ uint8 id; /* DOT11_MNG_VS_ID */ ++ uint8 len; /* length following */ ++ uint8 oui[3]; /* BRCM_PROP_OUI (or Customer) */ ++ uint8 sub_type; /* BRCM_FTM_IE_TYPE (or Customer) */ ++ uint8 version; ++ ftm_vs_tlv_t tlvs[1]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ftm_vs_ie dot11_ftm_vs_ie_t; ++ ++/* ftm vs api version */ ++#define BCM_FTM_VS_PARAMS_VERSION 0x01 ++ ++/* ftm vendor specific information tlv types */ ++enum { ++ FTM_VS_TLV_NONE = 0, ++ FTM_VS_TLV_REQ_PARAMS = 1, /* additional request params (in FTM_REQ) */ ++ FTM_VS_TLV_MEAS_INFO = 2, /* measurement information (in FTM_MEAS) */ ++ FTM_VS_TLV_SEC_PARAMS = 3, /* security parameters (in either) */ ++ FTM_VS_TLV_SEQ_PARAMS = 4, /* toast parameters (FTM_REQ, BRCM proprietary) */ ++ FTM_VS_TLV_MF_BUF = 5, /* multi frame buffer - may span ftm vs ie's */ ++ FTM_VS_TLV_TIMING_PARAMS = 6 /* timing adjustments */ ++ /* add additional types above */ ++}; ++ ++/* the following definitions are *DEPRECATED* and moved to implemenetion files. They ++ * are retained here because previous (May 2016) some branches use them ++ */ ++#define FTM_TPK_LEN 16 ++#define FTM_RI_RR_BUF_LEN 32 ++#define FTM_TPK_RI_RR_LEN 13 ++#define FTM_TPK_RI_RR_LEN_SECURE_2_0 28 ++#define FTM_TPK_DIGEST_LEN 32 ++#define FTM_TPK_BUFFER_LEN 128 ++#define FTM_TPK_RI_PHY_LEN 7 ++#define FTM_TPK_RR_PHY_LEN 7 ++#define FTM_TPK_DATA_BUFFER_LEN 88 ++#define FTM_TPK_LEN_SECURE_2_0 32 ++#define FTM_TPK_RI_PHY_LEN_SECURE_2_0 14 ++#define FTM_TPK_RR_PHY_LEN_SECURE_2_0 14 ++ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ftm_vs_params { ++ uint8 id; /* DOT11_MNG_VS_ID */ ++ uint8 len; ++ uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ ++ uint8 bcm_vs_id; ++ ftm_vs_tlv_t ftm_tpk_ri_rr[1]; /* ftm_TPK_ri_rr place holder */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ftm_vs_params dot11_ftm_vs_tpk_ri_rr_params_t; ++#define DOT11_FTM_VS_LEN (sizeof(dot11_ftm_vs_tpk_ri_rr_params_t) - TLV_HDR_LEN) ++/* end *DEPRECATED* ftm definitions */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_ftm_sync_info { ++ uint8 id; /* Extended - 255 11mc D4.3 */ ++ uint8 len; ++ uint8 id_ext; ++ uint8 tsf_sync_info[4]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_ftm_sync_info dot11_ftm_sync_info_t; ++ ++/* ftm tsf sync info ie len - includes id ext */ ++#define DOT11_FTM_SYNC_INFO_IE_LEN (sizeof(dot11_ftm_sync_info_t) - TLV_HDR_LEN) ++ ++#define DOT11_FTM_IS_SYNC_INFO_IE(_ie) (\ ++ DOT11_MNG_IE_ID_EXT_MATCH(_ie, DOT11_MNG_FTM_SYNC_INFO) && \ ++ (_ie)->len == DOT11_FTM_SYNC_INFO_IE_LEN) ++ ++/* 802.11u interworking access network options */ ++#define IW_ANT_MASK 0x0f ++#define IW_INTERNET_MASK 0x10 ++#define IW_ASRA_MASK 0x20 ++#define IW_ESR_MASK 0x40 ++#define IW_UESA_MASK 0x80 ++ ++/* 802.11u interworking access network type */ ++#define IW_ANT_PRIVATE_NETWORK 0 ++#define IW_ANT_PRIVATE_NETWORK_WITH_GUEST 1 ++#define IW_ANT_CHARGEABLE_PUBLIC_NETWORK 2 ++#define IW_ANT_FREE_PUBLIC_NETWORK 3 ++#define IW_ANT_PERSONAL_DEVICE_NETWORK 4 ++#define IW_ANT_EMERGENCY_SERVICES_NETWORK 5 ++#define IW_ANT_TEST_NETWORK 14 ++#define IW_ANT_WILDCARD_NETWORK 15 ++ ++#define IW_ANT_LEN 1 ++#define IW_VENUE_LEN 2 ++#define IW_HESSID_LEN 6 ++#define IW_HESSID_OFF (IW_ANT_LEN + IW_VENUE_LEN) ++#define IW_MAX_LEN (IW_ANT_LEN + IW_VENUE_LEN + IW_HESSID_LEN) ++ ++/* 802.11u advertisement protocol */ ++#define ADVP_ANQP_PROTOCOL_ID 0 ++#define ADVP_MIH_PROTOCOL_ID 1 ++ ++/* 802.11u advertisement protocol masks */ ++#define ADVP_QRL_MASK 0x7f ++#define ADVP_PAME_BI_MASK 0x80 ++ ++/* 802.11u advertisement protocol values */ ++#define ADVP_QRL_REQUEST 0x00 ++#define ADVP_QRL_RESPONSE 0x7f ++#define ADVP_PAME_BI_DEPENDENT 0x00 ++#define ADVP_PAME_BI_INDEPENDENT ADVP_PAME_BI_MASK ++ ++/* 802.11u ANQP information ID */ ++#define ANQP_ID_QUERY_LIST 256 ++#define ANQP_ID_CAPABILITY_LIST 257 ++#define ANQP_ID_VENUE_NAME_INFO 258 ++#define ANQP_ID_EMERGENCY_CALL_NUMBER_INFO 259 ++#define ANQP_ID_NETWORK_AUTHENTICATION_TYPE_INFO 260 ++#define ANQP_ID_ROAMING_CONSORTIUM_LIST 261 ++#define ANQP_ID_IP_ADDRESS_TYPE_AVAILABILITY_INFO 262 ++#define ANQP_ID_NAI_REALM_LIST 263 ++#define ANQP_ID_G3PP_CELLULAR_NETWORK_INFO 264 ++#define ANQP_ID_AP_GEOSPATIAL_LOCATION 265 ++#define ANQP_ID_AP_CIVIC_LOCATION 266 ++#define ANQP_ID_AP_LOCATION_PUBLIC_ID_URI 267 ++#define ANQP_ID_DOMAIN_NAME_LIST 268 ++#define ANQP_ID_EMERGENCY_ALERT_ID_URI 269 ++#define ANQP_ID_EMERGENCY_NAI 271 ++#define ANQP_ID_VENDOR_SPECIFIC_LIST 56797 ++ ++/* 802.11u ANQP OUI */ ++#define ANQP_OUI_SUBTYPE 9 ++ ++/* 802.11u venue name */ ++#define VENUE_LANGUAGE_CODE_SIZE 3 ++#define VENUE_NAME_SIZE 255 ++ ++/* 802.11u venue groups */ ++#define VENUE_UNSPECIFIED 0 ++#define VENUE_ASSEMBLY 1 ++#define VENUE_BUSINESS 2 ++#define VENUE_EDUCATIONAL 3 ++#define VENUE_FACTORY 4 ++#define VENUE_INSTITUTIONAL 5 ++#define VENUE_MERCANTILE 6 ++#define VENUE_RESIDENTIAL 7 ++#define VENUE_STORAGE 8 ++#define VENUE_UTILITY 9 ++#define VENUE_VEHICULAR 10 ++#define VENUE_OUTDOOR 11 ++ ++/* 802.11u network authentication type indicator */ ++#define NATI_UNSPECIFIED -1 ++#define NATI_ACCEPTANCE_OF_TERMS_CONDITIONS 0 ++#define NATI_ONLINE_ENROLLMENT_SUPPORTED 1 ++#define NATI_HTTP_HTTPS_REDIRECTION 2 ++#define NATI_DNS_REDIRECTION 3 ++ ++/* 802.11u IP address type availability - IPv6 */ ++#define IPA_IPV6_SHIFT 0 ++#define IPA_IPV6_MASK (0x03 << IPA_IPV6_SHIFT) ++#define IPA_IPV6_NOT_AVAILABLE 0x00 ++#define IPA_IPV6_AVAILABLE 0x01 ++#define IPA_IPV6_UNKNOWN_AVAILABILITY 0x02 ++ ++/* 802.11u IP address type availability - IPv4 */ ++#define IPA_IPV4_SHIFT 2 ++#define IPA_IPV4_MASK (0x3f << IPA_IPV4_SHIFT) ++#define IPA_IPV4_NOT_AVAILABLE 0x00 ++#define IPA_IPV4_PUBLIC 0x01 ++#define IPA_IPV4_PORT_RESTRICT 0x02 ++#define IPA_IPV4_SINGLE_NAT 0x03 ++#define IPA_IPV4_DOUBLE_NAT 0x04 ++#define IPA_IPV4_PORT_RESTRICT_SINGLE_NAT 0x05 ++#define IPA_IPV4_PORT_RESTRICT_DOUBLE_NAT 0x06 ++#define IPA_IPV4_UNKNOWN_AVAILABILITY 0x07 ++ ++/* 802.11u NAI realm encoding */ ++#define REALM_ENCODING_RFC4282 0 ++#define REALM_ENCODING_UTF8 1 ++ ++/* 802.11u IANA EAP method type numbers */ ++#define REALM_EAP_TLS 13 ++#define REALM_EAP_LEAP 17 ++#define REALM_EAP_SIM 18 ++#define REALM_EAP_TTLS 21 ++#define REALM_EAP_AKA 23 ++#define REALM_EAP_PEAP 25 ++#define REALM_EAP_FAST 43 ++#define REALM_EAP_PSK 47 ++#define REALM_EAP_AKAP 50 ++#define REALM_EAP_EXPANDED 254 ++ ++/* 802.11u authentication ID */ ++#define REALM_EXPANDED_EAP 1 ++#define REALM_NON_EAP_INNER_AUTHENTICATION 2 ++#define REALM_INNER_AUTHENTICATION_EAP 3 ++#define REALM_EXPANDED_INNER_EAP 4 ++#define REALM_CREDENTIAL 5 ++#define REALM_TUNNELED_EAP_CREDENTIAL 6 ++#define REALM_VENDOR_SPECIFIC_EAP 221 ++ ++/* 802.11u non-EAP inner authentication type */ ++#define REALM_RESERVED_AUTH 0 ++#define REALM_PAP 1 ++#define REALM_CHAP 2 ++#define REALM_MSCHAP 3 ++#define REALM_MSCHAPV2 4 ++ ++/* 802.11u credential type */ ++#define REALM_SIM 1 ++#define REALM_USIM 2 ++#define REALM_NFC 3 ++#define REALM_HARDWARE_TOKEN 4 ++#define REALM_SOFTOKEN 5 ++#define REALM_CERTIFICATE 6 ++#define REALM_USERNAME_PASSWORD 7 ++#define REALM_SERVER_SIDE 8 ++#define REALM_RESERVED_CRED 9 ++#define REALM_VENDOR_SPECIFIC_CRED 10 ++ ++/* 802.11u 3GPP PLMN */ ++#define G3PP_GUD_VERSION 0 ++#define G3PP_PLMN_LIST_IE 0 ++ ++/* AP Location Public ID Info encoding */ ++#define PUBLIC_ID_URI_FQDN_SE_ID 0 ++/* URI/FQDN Descriptor field values */ ++#define LOCATION_ENCODING_HELD 1 ++#define LOCATION_ENCODING_SUPL 2 ++#define URI_FQDN_SIZE 255 ++ ++/** hotspot2.0 indication element (vendor specific) */ ++BWL_PRE_PACKED_STRUCT struct hs20_ie { ++ uint8 oui[3]; ++ uint8 type; ++ uint8 config; ++} BWL_POST_PACKED_STRUCT; ++typedef struct hs20_ie hs20_ie_t; ++#define HS20_IE_LEN 5 /* HS20 IE length */ ++ ++/** IEEE 802.11 Annex E */ ++typedef enum { ++ DOT11_2GHZ_20MHZ_CLASS_12 = 81, /* Ch 1-11 */ ++ DOT11_5GHZ_20MHZ_CLASS_1 = 115, /* Ch 36-48 */ ++ DOT11_5GHZ_20MHZ_CLASS_2_DFS = 118, /* Ch 52-64 */ ++ DOT11_5GHZ_20MHZ_CLASS_3 = 124, /* Ch 149-161 */ ++ DOT11_5GHZ_20MHZ_CLASS_4_DFS = 121, /* Ch 100-140 */ ++ DOT11_5GHZ_20MHZ_CLASS_5 = 125, /* Ch 149-165 */ ++ DOT11_5GHZ_40MHZ_CLASS_22 = 116, /* Ch 36-44, lower */ ++ DOT11_5GHZ_40MHZ_CLASS_23_DFS = 119, /* Ch 52-60, lower */ ++ DOT11_5GHZ_40MHZ_CLASS_24_DFS = 122, /* Ch 100-132, lower */ ++ DOT11_5GHZ_40MHZ_CLASS_25 = 126, /* Ch 149-157, lower */ ++ DOT11_5GHZ_40MHZ_CLASS_27 = 117, /* Ch 40-48, upper */ ++ DOT11_5GHZ_40MHZ_CLASS_28_DFS = 120, /* Ch 56-64, upper */ ++ DOT11_5GHZ_40MHZ_CLASS_29_DFS = 123, /* Ch 104-136, upper */ ++ DOT11_5GHZ_40MHZ_CLASS_30 = 127, /* Ch 153-161, upper */ ++ DOT11_2GHZ_40MHZ_CLASS_32 = 83, /* Ch 1-7, lower */ ++ DOT11_2GHZ_40MHZ_CLASS_33 = 84, /* Ch 5-11, upper */ ++} dot11_op_class_t; ++ ++/* QoS map */ ++#define QOS_MAP_FIXED_LENGTH (8 * 2) /* DSCP ranges fixed with 8 entries */ ++ ++#define BCM_AIBSS_IE_TYPE 56 ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _802_11_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/802.11e.h b/module_drivers/drivers/net/wireless/bcmdhd/include/802.11e.h +new file mode 100644 +index 000000000..f2021e5d4 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/802.11e.h +@@ -0,0 +1,134 @@ ++/* ++ * 802.11e protocol header file ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: 802.11e.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _802_11e_H_ ++#define _802_11e_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++/* WME Traffic Specification (TSPEC) element */ ++#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ ++#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ ++ ++#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ ++#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ ++#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ ++#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ ++ ++BWL_PRE_PACKED_STRUCT struct tsinfo { ++ uint8 octets[3]; ++} BWL_POST_PACKED_STRUCT; ++ ++typedef struct tsinfo tsinfo_t; ++ ++/* 802.11e TSPEC IE */ ++typedef BWL_PRE_PACKED_STRUCT struct tspec { ++ uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ ++ uint8 type; /* WME_TYPE */ ++ uint8 subtype; /* WME_SUBTYPE_TSPEC */ ++ uint8 version; /* WME_VERSION */ ++ tsinfo_t tsinfo; /* TS Info bit field */ ++ uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ ++ uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ ++ uint32 min_srv_interval; /* Minimum Service Interval (us) */ ++ uint32 max_srv_interval; /* Maximum Service Interval (us) */ ++ uint32 inactivity_interval; /* Inactivity Interval (us) */ ++ uint32 suspension_interval; /* Suspension Interval (us) */ ++ uint32 srv_start_time; /* Service Start Time (us) */ ++ uint32 min_data_rate; /* Minimum Data Rate (bps) */ ++ uint32 mean_data_rate; /* Mean Data Rate (bps) */ ++ uint32 peak_data_rate; /* Peak Data Rate (bps) */ ++ uint32 max_burst_size; /* Maximum Burst Size (bytes) */ ++ uint32 delay_bound; /* Delay Bound (us) */ ++ uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ ++ uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */ ++ uint16 medium_time; /* Medium Time (32 us/s periods) */ ++} BWL_POST_PACKED_STRUCT tspec_t; ++ ++#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ ++ ++/* ts_info */ ++/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ ++#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ ++#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ ++#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ ++#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ ++#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ ++#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ ++#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ ++#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ ++#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ ++#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ ++#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ ++#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ ++/* TS info. user priority mask */ ++#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) ++ ++/* Macro to get/set bit(s) field in TSINFO */ ++#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) ++#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ ++ TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) ++#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT) ++#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ ++ TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) ++ ++#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ ++ ((id) << TS_INFO_TID_SHIFT)) ++#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ ++ ((prio) << TS_INFO_USER_PRIO_SHIFT)) ++ ++/* 802.11e QBSS Load IE */ ++#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ ++#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ ++ ++#define CAC_ADDTS_RESP_TIMEOUT 1000 /* default ADDTS response timeout in ms */ ++ /* DEFVAL dot11ADDTSResponseTimeout = 1s */ ++ ++/* 802.11e ADDTS status code */ ++#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ ++#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ ++#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ ++#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */ ++ ++/* 802.11e DELTS status code */ ++#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ ++#define DOT11E_STATUS_END_TS 37 /* END TS */ ++#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ ++#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _802_11e_CAC_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/802.11s.h b/module_drivers/drivers/net/wireless/bcmdhd/include/802.11s.h +new file mode 100644 +index 000000000..8ad1693a9 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/802.11s.h +@@ -0,0 +1,336 @@ ++/* ++ * Fundamental types and constants relating to 802.11s Mesh ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: 802.11s.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _802_11s_h_ ++#define _802_11s_h_ ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#define DOT11_MESH_FLAGS_AE_MASK 0x3 ++#define DOT11_MESH_FLAGS_AE_SHIFT 0 ++ ++#define DOT11_MESH_CONNECTED_AS_SET 7 ++#define DOT11_MESH_NUMBER_PEERING_SET 1 ++#define DOT11_MESH_MESH_GWSET 0 ++ ++#define DOT11_MESH_ACTION_LINK_MET_REP 0 ++#define DOT11_MESH_ACTION_PATH_SEL 1 ++#define DOT11_MESH_ACTION_GATE_ANN 2 ++#define DOT11_MESH_ACTION_CONG_CONT_NOTIF 3 ++#define DOT11_MESH_ACTION_MCCA_SETUP_REQ 4 ++#define DOT11_MESH_ACTION_MCCA_SETUP_REP 5 ++#define DOT11_MESH_ACTION_MCCA_ADVT_REQ 6 ++#define DOT11_MESH_ACTION_MCCA_ADVT 7 ++#define DOT11_MESH_ACTION_MCCA_TEARDOWN 8 ++#define DOT11_MESH_ACTION_TBTT_ADJ_REQ 9 ++#define DOT11_MESH_ACTION_TBTT_ADJ_RESP 10 ++ ++/* self-protected action field values: 7-57v24 */ ++#define DOT11_SELFPROT_ACTION_MESH_PEER_OPEN 1 ++#define DOT11_SELFPROT_ACTION_MESH_PEER_CONFM 2 ++#define DOT11_SELFPROT_ACTION_MESH_PEER_CLOSE 3 ++#define DOT11_SELFPROT_ACTION_MESH_PEER_GK_INF 4 ++#define DOT11_SELFPROT_ACTION_MESH_PEER_GK_ACK 5 ++ ++#define DOT11_MESH_AUTH_PROTO_NONE 0 ++#define DOT11_MESH_AUTH_PROTO_SAE 1 ++#define DOT11_MESH_AUTH_PROTO_8021X 2 ++#define DOT11_MESH_AUTH_PROTO_VS 255 ++ ++#define DOT11_MESH_PATHSEL_LEN 2 ++#define DOT11_MESH_PERR_LEN1 2 /* Least PERR length fixed */ ++#define DOT11_MESH_PERR_LEN2 13 /* Least PERR length variable */ ++#define DOT11_MESH_PREP_LEN 31 /* Least PREP length */ ++#define DOT11_MESH_PREQ_LEN 37 /* Least PREQ length */ ++ ++#define DOT11_MESH_PATHSEL_PROTID_HWMP 1 ++#define DOT11_MESH_PATHSEL_METRICID_ALM 1 /* Air link metric */ ++#define DOT11_MESH_CONGESTCTRL_NONE 0 ++#define DOT11_MESH_CONGESTCTRL_SP 1 ++#define DOT11_MESH_SYNCMETHOD_NOFFSET 1 ++ ++BWL_PRE_PACKED_STRUCT struct dot11_meshctrl_hdr { ++ uint8 flags; /* flag bits such as ae etc */ ++ uint8 ttl; /* time to live */ ++ uint32 seq; /* sequence control */ ++ struct ether_addr a5; /* optional address 5 */ ++ struct ether_addr a6; /* optional address 6 */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* Mesh Path Selection Action Frame */ ++BWL_PRE_PACKED_STRUCT struct dot11_mesh_pathsel { ++ uint8 category; ++ uint8 meshaction; ++ uint8 data[]; ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_mesh_pathsel dot11_mesh_pathsel_t; ++ ++/* Mesh PREQ IE */ ++BWL_PRE_PACKED_STRUCT struct mesh_preq_ie { ++ uint8 id; ++ uint8 len; ++ uint8 flags; ++ uint8 hop_count; ++ uint8 ttl; ++ uint32 pathdis_id; ++ struct ether_addr originator_addr; ++ uint32 originator_seq; ++ union { ++ BWL_PRE_PACKED_STRUCT struct { ++ struct ether_addr target_ext_add; ++ uint32 lifetime; ++ uint32 metric; ++ uint8 target_count; ++ uint8 data[]; ++ } BWL_POST_PACKED_STRUCT oea; ++ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint32 lifetime; ++ uint32 metric; ++ uint8 target_count; ++ uint8 data[]; ++ } BWL_POST_PACKED_STRUCT noea; ++ } u; ++} BWL_POST_PACKED_STRUCT; ++typedef struct mesh_preq_ie mesh_preq_ie_t; ++ ++/* Target info (part of Mesh PREQ IE) */ ++BWL_PRE_PACKED_STRUCT struct mesh_targetinfo { ++ uint8 target_flag; ++ struct ether_addr target_addr; ++ uint32 target_seq; ++} BWL_POST_PACKED_STRUCT; ++typedef struct mesh_targetinfo mesh_targetinfo_t; ++ ++ ++/* Mesh PREP IE */ ++BWL_PRE_PACKED_STRUCT struct mesh_prep_ie { ++ uint8 id; ++ uint8 len; ++ uint8 flags; ++ uint8 hop_count; ++ uint8 ttl; ++ struct ether_addr target_addr; ++ uint32 target_seq; ++ union { ++ BWL_PRE_PACKED_STRUCT struct { ++ struct ether_addr target_ext_add; ++ uint32 lifetime; ++ uint32 metric; ++ uint8 target_count; ++ struct ether_addr originator_addr; ++ uint32 originator_seq; ++ } BWL_POST_PACKED_STRUCT oea; ++ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint32 lifetime; ++ uint32 metric; ++ uint8 target_count; ++ struct ether_addr originator_addr; ++ uint32 originator_seq; ++ } BWL_POST_PACKED_STRUCT noea; ++ } u; ++} BWL_POST_PACKED_STRUCT; ++typedef struct mesh_prep_ie mesh_prep_ie_t; ++ ++ ++/* Mesh PERR IE */ ++struct mesh_perr_ie { ++ uint8 id; ++ uint8 len; ++ uint8 ttl; ++ uint8 num_dest; ++ uint8 data[]; ++}; ++typedef struct mesh_perr_ie mesh_perr_ie_t; ++ ++/* Destination info is part of PERR IE */ ++BWL_PRE_PACKED_STRUCT struct mesh_perr_destinfo { ++ uint8 flags; ++ struct ether_addr destination_addr; ++ uint32 dest_seq; ++ union { ++ BWL_PRE_PACKED_STRUCT struct { ++ struct ether_addr dest_ext_addr; ++ } BWL_POST_PACKED_STRUCT dea; ++ ++ BWL_PRE_PACKED_STRUCT struct { ++ /* 1 byte reason code to be populated manually in software */ ++ uint16 reason_code; ++ } BWL_POST_PACKED_STRUCT nodea; ++ } u; ++} BWL_POST_PACKED_STRUCT; ++typedef struct mesh_perr_destinfo mesh_perr_destinfo_t; ++ ++/* Mesh peering action frame hdr */ ++BWL_PRE_PACKED_STRUCT struct mesh_peering_frmhdr { ++ uint8 category; ++ uint8 action; ++ union { ++ struct { ++ uint16 capability; ++ } open; ++ struct { ++ uint16 capability; ++ uint16 AID; ++ } confirm; ++ uint8 data[1]; ++ } u; ++} BWL_POST_PACKED_STRUCT; ++typedef struct mesh_peering_frmhdr mesh_peering_frmhdr_t; ++ ++/* Mesh peering mgmt IE */ ++BWL_PRE_PACKED_STRUCT struct mesh_peer_mgmt_ie_common { ++ uint16 mesh_peer_prot_id; ++ uint16 local_link_id; ++} BWL_POST_PACKED_STRUCT; ++typedef struct mesh_peer_mgmt_ie_common mesh_peer_mgmt_ie_common_t; ++#define MESH_PEER_MGMT_IE_OPEN_LEN (4) ++ ++BWL_PRE_PACKED_STRUCT struct mesh_peer_mgmt_ie_cfm { ++ mesh_peer_mgmt_ie_common_t common; ++ uint16 peer_link_id; ++} BWL_POST_PACKED_STRUCT; ++typedef struct mesh_peer_mgmt_ie_cfm mesh_peer_mgmt_ie_cfm_t; ++#define MESH_PEER_MGMT_IE_CONF_LEN (6) ++ ++BWL_PRE_PACKED_STRUCT struct mesh_peer_mgmt_ie_close { ++ mesh_peer_mgmt_ie_common_t common; ++ /* uint16 peer_link_id; ++ * simplicity: not supported, TODO for future ++ */ ++ uint16 reason_code; ++} BWL_POST_PACKED_STRUCT; ++typedef struct mesh_peer_mgmt_ie_close mesh_peer_mgmt_ie_close_t; ++#define MESH_PEER_MGMT_IE_CLOSE_LEN (6) ++ ++struct mesh_config_ie { ++ uint8 activ_path_sel_prot_id; ++ uint8 activ_path_sel_metric_id; ++ uint8 cong_ctl_mode_id; ++ uint8 sync_method_id; ++ uint8 auth_prot_id; ++ uint8 mesh_formation_info; ++ uint8 mesh_cap; ++}; ++typedef struct mesh_config_ie mesh_config_ie_t; ++#define MESH_CONFIG_IE_LEN (7) ++ ++/* Mesh peering states */ ++#define MESH_PEERING_IDLE 0 ++#define MESH_PEERING_OPEN_SNT 1 ++#define MESH_PEERING_CNF_RCVD 2 ++#define MESH_PEERING_OPEN_RCVD 3 ++#define MESH_PEERING_ESTAB 4 ++#define MESH_PEERING_HOLDING 5 ++#define MESH_PEERING_LAST_STATE 6 ++/* for debugging: mapping strings */ ++#define MESH_PEERING_STATE_STRINGS \ ++ {"IDLE ", "OPNSNT", "CNFRCV", "OPNRCV", "ESTAB ", "HOLDNG"} ++ ++#ifdef WLMESH ++typedef BWL_PRE_PACKED_STRUCT struct mesh_peer_info { ++ /* mesh_peer_instance as given in the spec. Note that, peer address ++ * is stored in scb ++ */ ++ uint16 mesh_peer_prot_id; ++ uint16 local_link_id; ++ uint16 peer_link_id; ++ /* AID generated by *peer* to self & received in peer_confirm */ ++ uint16 peer_aid; ++ ++ /* TODO: no mention in spec? possibly used in PS case. Note that aid generated ++ * from self to peer is stored in scb. ++ */ ++ uint8 state; ++ /* TODO: struct mesh_peer_info *next; this field is required ++ * if multiple peerings per same src is allowed, which is ++ * true as per spec. ++ */ ++} BWL_POST_PACKED_STRUCT mesh_peer_info_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct mesh_peer_info_ext { ++ mesh_peer_info_t peer_info; ++ uint16 local_aid; /* AID generated by *local* to peer */ ++ struct ether_addr ea; /* peer ea */ ++ uint32 entry_state; /* see MESH_PEER_ENTRY_STATE_ACTIVE etc; valid ++ * ONLY for internal peering requests ++ */ ++ int rssi; ++} BWL_POST_PACKED_STRUCT mesh_peer_info_ext_t; ++ ++/* #ifdef WLMESH */ ++typedef BWL_PRE_PACKED_STRUCT struct mesh_peer_info_dump { ++ uint32 buflen; ++ uint32 version; ++ uint32 count; /* number of results */ ++ mesh_peer_info_ext_t mpi_ext[1]; ++} BWL_POST_PACKED_STRUCT mesh_peer_info_dump_t; ++#define WL_MESH_PEER_RES_FIXED_SIZE (sizeof(mesh_peer_info_dump_t) - sizeof(mesh_peer_info_ext_t)) ++ ++#endif /* WLMESH */ ++ ++/* once an entry is added into mesh_peer_list, if peering is lost, it will ++* get retried for peering, MAX_MESH_PEER_ENTRY_RETRIES times. after wards, it ++* wont get retried and will be moved to MESH_PEER_ENTRY_STATE_TIMEDOUT state, ++* until user adds it again explicitely, when its entry_state is changed ++* to MESH_PEER_ENTRY_STATE_ACTIVE and tried again. ++*/ ++#define MAX_MESH_SELF_PEER_ENTRY_RETRIES 3 ++#define MESH_SELF_PEER_ENTRY_STATE_ACTIVE 1 ++#define MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT 2 ++ ++/** Mesh Channel Switch Parameter IE data structure */ ++BWL_PRE_PACKED_STRUCT struct dot11_mcsp_body { ++ uint8 ttl; /* remaining number of hops allowed for this element. */ ++ uint8 flags; /* attributes of this channel switch attempt */ ++ uint8 reason; /* reason for the mesh channel switch */ ++ uint16 precedence; /* random value in the range 0 to 65535 */ ++} BWL_POST_PACKED_STRUCT; ++ ++#define DOT11_MCSP_TTL_DEFAULT 1 ++#define DOT11_MCSP_FLAG_TRANS_RESTRICT 0x1 /* no transmit except frames with mcsp */ ++#define DOT11_MCSP_FLAG_INIT 0x2 /* initiates the channel switch attempt */ ++#define DOT11_MCSP_FLAG_REASON 0x4 /* validity of reason code field */ ++#define DOT11_MCSP_REASON_REGULATORY 0 /* meet regulatory requirements */ ++#define DOT11_MCSP_REASON_UNSPECIFIED 1 /* unspecified reason */ ++ ++BWL_PRE_PACKED_STRUCT struct dot11_mesh_csp { ++ uint8 id; /* id DOT11_MNG_MESH_CSP_ID */ ++ uint8 len; /* length of IE */ ++ struct dot11_mcsp_body body; /* body of the ie */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct dot11_mesh_csp dot11_mesh_csp_ie_t; ++#define DOT11_MESH_CSP_IE_LEN 5 /* length of mesh channel switch parameter IE body */ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* #ifndef _802_11s_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/802.1d.h b/module_drivers/drivers/net/wireless/bcmdhd/include/802.1d.h +new file mode 100644 +index 000000000..1b8dea5b1 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/802.1d.h +@@ -0,0 +1,53 @@ ++/* ++ * Fundamental types and constants relating to 802.1D ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: 802.1d.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _802_1_D_ ++#define _802_1_D_ ++ ++/* 802.1D priority defines */ ++#define PRIO_8021D_NONE 2 /* None = - */ ++#define PRIO_8021D_BK 1 /* BK - Background */ ++#define PRIO_8021D_BE 0 /* BE - Best-effort */ ++#define PRIO_8021D_EE 3 /* EE - Excellent-effort */ ++#define PRIO_8021D_CL 4 /* CL - Controlled Load */ ++#define PRIO_8021D_VI 5 /* Vi - Video */ ++#define PRIO_8021D_VO 6 /* Vo - Voice */ ++#define PRIO_8021D_NC 7 /* NC - Network Control */ ++#define MAXPRIO 7 /* 0-7 */ ++#define NUMPRIO (MAXPRIO + 1) ++ ++#define ALLPRIO -1 /* All prioirty */ ++ ++/* Converts prio to precedence since the numerical value of ++ * PRIO_8021D_BE and PRIO_8021D_NONE are swapped. ++ */ ++#define PRIO2PREC(prio) \ ++ (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) ++ ++#endif /* _802_1_D__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/802.3.h b/module_drivers/drivers/net/wireless/bcmdhd/include/802.3.h +new file mode 100644 +index 000000000..6758ac048 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/802.3.h +@@ -0,0 +1,55 @@ ++/* ++ * Fundamental constants relating to 802.3 ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: 802.3.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _802_3_h_ ++#define _802_3_h_ ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#define SNAP_HDR_LEN 6 /* 802.3 SNAP header length */ ++#define DOT3_OUI_LEN 3 /* 802.3 oui length */ ++ ++BWL_PRE_PACKED_STRUCT struct dot3_mac_llc_snap_header { ++ uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ ++ uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ ++ uint16 length; /* frame length incl header */ ++ uint8 dsap; /* always 0xAA */ ++ uint8 ssap; /* always 0xAA */ ++ uint8 ctl; /* always 0x03 */ ++ uint8 oui[DOT3_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 ++ * Bridge-Tunnel: 0x00 0x00 0xF8 ++ */ ++ uint16 type; /* ethertype */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* #ifndef _802_3_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/aidmp.h b/module_drivers/drivers/net/wireless/bcmdhd/include/aidmp.h +new file mode 100644 +index 000000000..10992e763 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/aidmp.h +@@ -0,0 +1,424 @@ ++/* ++ * Broadcom AMBA Interconnect definitions. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: aidmp.h 614820 2016-01-23 17:16:17Z $ ++ */ ++ ++#ifndef _AIDMP_H ++#define _AIDMP_H ++ ++/* Manufacturer Ids */ ++#define MFGID_ARM 0x43b ++#define MFGID_BRCM 0x4bf ++#define MFGID_MIPS 0x4a7 ++ ++/* Component Classes */ ++#define CC_SIM 0 ++#define CC_EROM 1 ++#define CC_CORESIGHT 9 ++#define CC_VERIF 0xb ++#define CC_OPTIMO 0xd ++#define CC_GEN 0xe ++#define CC_PRIMECELL 0xf ++ ++/* Enumeration ROM registers */ ++#define ER_EROMENTRY 0x000 ++#define ER_REMAPCONTROL 0xe00 ++#define ER_REMAPSELECT 0xe04 ++#define ER_MASTERSELECT 0xe10 ++#define ER_ITCR 0xf00 ++#define ER_ITIP 0xf04 ++ ++/* Erom entries */ ++#define ER_TAG 0xe ++#define ER_TAG1 0x6 ++#define ER_VALID 1 ++#define ER_CI 0 ++#define ER_MP 2 ++#define ER_ADD 4 ++#define ER_END 0xe ++#define ER_BAD 0xffffffff ++#define ER_SZ_MAX 4096 /* 4KB */ ++ ++/* EROM CompIdentA */ ++#define CIA_MFG_MASK 0xfff00000 ++#define CIA_MFG_SHIFT 20 ++#define CIA_CID_MASK 0x000fff00 ++#define CIA_CID_SHIFT 8 ++#define CIA_CCL_MASK 0x000000f0 ++#define CIA_CCL_SHIFT 4 ++ ++/* EROM CompIdentB */ ++#define CIB_REV_MASK 0xff000000 ++#define CIB_REV_SHIFT 24 ++#define CIB_NSW_MASK 0x00f80000 ++#define CIB_NSW_SHIFT 19 ++#define CIB_NMW_MASK 0x0007c000 ++#define CIB_NMW_SHIFT 14 ++#define CIB_NSP_MASK 0x00003e00 ++#define CIB_NSP_SHIFT 9 ++#define CIB_NMP_MASK 0x000001f0 ++#define CIB_NMP_SHIFT 4 ++ ++/* EROM MasterPortDesc */ ++#define MPD_MUI_MASK 0x0000ff00 ++#define MPD_MUI_SHIFT 8 ++#define MPD_MP_MASK 0x000000f0 ++#define MPD_MP_SHIFT 4 ++ ++/* EROM AddrDesc */ ++#define AD_ADDR_MASK 0xfffff000 ++#define AD_SP_MASK 0x00000f00 ++#define AD_SP_SHIFT 8 ++#define AD_ST_MASK 0x000000c0 ++#define AD_ST_SHIFT 6 ++#define AD_ST_SLAVE 0x00000000 ++#define AD_ST_BRIDGE 0x00000040 ++#define AD_ST_SWRAP 0x00000080 ++#define AD_ST_MWRAP 0x000000c0 ++#define AD_SZ_MASK 0x00000030 ++#define AD_SZ_SHIFT 4 ++#define AD_SZ_4K 0x00000000 ++#define AD_SZ_8K 0x00000010 ++#define AD_SZ_16K 0x00000020 ++#define AD_SZ_SZD 0x00000030 ++#define AD_AG32 0x00000008 ++#define AD_ADDR_ALIGN 0x00000fff ++#define AD_SZ_BASE 0x00001000 /* 4KB */ ++ ++/* EROM SizeDesc */ ++#define SD_SZ_MASK 0xfffff000 ++#define SD_SG32 0x00000008 ++#define SD_SZ_ALIGN 0x00000fff ++ ++ ++#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) ++ ++typedef volatile struct _aidmp { ++ uint32 oobselina30; /* 0x000 */ ++ uint32 oobselina74; /* 0x004 */ ++ uint32 PAD[6]; ++ uint32 oobselinb30; /* 0x020 */ ++ uint32 oobselinb74; /* 0x024 */ ++ uint32 PAD[6]; ++ uint32 oobselinc30; /* 0x040 */ ++ uint32 oobselinc74; /* 0x044 */ ++ uint32 PAD[6]; ++ uint32 oobselind30; /* 0x060 */ ++ uint32 oobselind74; /* 0x064 */ ++ uint32 PAD[38]; ++ uint32 oobselouta30; /* 0x100 */ ++ uint32 oobselouta74; /* 0x104 */ ++ uint32 PAD[6]; ++ uint32 oobseloutb30; /* 0x120 */ ++ uint32 oobseloutb74; /* 0x124 */ ++ uint32 PAD[6]; ++ uint32 oobseloutc30; /* 0x140 */ ++ uint32 oobseloutc74; /* 0x144 */ ++ uint32 PAD[6]; ++ uint32 oobseloutd30; /* 0x160 */ ++ uint32 oobseloutd74; /* 0x164 */ ++ uint32 PAD[38]; ++ uint32 oobsynca; /* 0x200 */ ++ uint32 oobseloutaen; /* 0x204 */ ++ uint32 PAD[6]; ++ uint32 oobsyncb; /* 0x220 */ ++ uint32 oobseloutben; /* 0x224 */ ++ uint32 PAD[6]; ++ uint32 oobsyncc; /* 0x240 */ ++ uint32 oobseloutcen; /* 0x244 */ ++ uint32 PAD[6]; ++ uint32 oobsyncd; /* 0x260 */ ++ uint32 oobseloutden; /* 0x264 */ ++ uint32 PAD[38]; ++ uint32 oobaextwidth; /* 0x300 */ ++ uint32 oobainwidth; /* 0x304 */ ++ uint32 oobaoutwidth; /* 0x308 */ ++ uint32 PAD[5]; ++ uint32 oobbextwidth; /* 0x320 */ ++ uint32 oobbinwidth; /* 0x324 */ ++ uint32 oobboutwidth; /* 0x328 */ ++ uint32 PAD[5]; ++ uint32 oobcextwidth; /* 0x340 */ ++ uint32 oobcinwidth; /* 0x344 */ ++ uint32 oobcoutwidth; /* 0x348 */ ++ uint32 PAD[5]; ++ uint32 oobdextwidth; /* 0x360 */ ++ uint32 oobdinwidth; /* 0x364 */ ++ uint32 oobdoutwidth; /* 0x368 */ ++ uint32 PAD[37]; ++ uint32 ioctrlset; /* 0x400 */ ++ uint32 ioctrlclear; /* 0x404 */ ++ uint32 ioctrl; /* 0x408 */ ++ uint32 PAD[61]; ++ uint32 iostatus; /* 0x500 */ ++ uint32 PAD[127]; ++ uint32 ioctrlwidth; /* 0x700 */ ++ uint32 iostatuswidth; /* 0x704 */ ++ uint32 PAD[62]; ++ uint32 resetctrl; /* 0x800 */ ++ uint32 resetstatus; /* 0x804 */ ++ uint32 resetreadid; /* 0x808 */ ++ uint32 resetwriteid; /* 0x80c */ ++ uint32 PAD[60]; ++ uint32 errlogctrl; /* 0x900 */ ++ uint32 errlogdone; /* 0x904 */ ++ uint32 errlogstatus; /* 0x908 */ ++ uint32 errlogaddrlo; /* 0x90c */ ++ uint32 errlogaddrhi; /* 0x910 */ ++ uint32 errlogid; /* 0x914 */ ++ uint32 errloguser; /* 0x918 */ ++ uint32 errlogflags; /* 0x91c */ ++ uint32 PAD[56]; ++ uint32 intstatus; /* 0xa00 */ ++ uint32 PAD[255]; ++ uint32 config; /* 0xe00 */ ++ uint32 PAD[63]; ++ uint32 itcr; /* 0xf00 */ ++ uint32 PAD[3]; ++ uint32 itipooba; /* 0xf10 */ ++ uint32 itipoobb; /* 0xf14 */ ++ uint32 itipoobc; /* 0xf18 */ ++ uint32 itipoobd; /* 0xf1c */ ++ uint32 PAD[4]; ++ uint32 itipoobaout; /* 0xf30 */ ++ uint32 itipoobbout; /* 0xf34 */ ++ uint32 itipoobcout; /* 0xf38 */ ++ uint32 itipoobdout; /* 0xf3c */ ++ uint32 PAD[4]; ++ uint32 itopooba; /* 0xf50 */ ++ uint32 itopoobb; /* 0xf54 */ ++ uint32 itopoobc; /* 0xf58 */ ++ uint32 itopoobd; /* 0xf5c */ ++ uint32 PAD[4]; ++ uint32 itopoobain; /* 0xf70 */ ++ uint32 itopoobbin; /* 0xf74 */ ++ uint32 itopoobcin; /* 0xf78 */ ++ uint32 itopoobdin; /* 0xf7c */ ++ uint32 PAD[4]; ++ uint32 itopreset; /* 0xf90 */ ++ uint32 PAD[15]; ++ uint32 peripherialid4; /* 0xfd0 */ ++ uint32 peripherialid5; /* 0xfd4 */ ++ uint32 peripherialid6; /* 0xfd8 */ ++ uint32 peripherialid7; /* 0xfdc */ ++ uint32 peripherialid0; /* 0xfe0 */ ++ uint32 peripherialid1; /* 0xfe4 */ ++ uint32 peripherialid2; /* 0xfe8 */ ++ uint32 peripherialid3; /* 0xfec */ ++ uint32 componentid0; /* 0xff0 */ ++ uint32 componentid1; /* 0xff4 */ ++ uint32 componentid2; /* 0xff8 */ ++ uint32 componentid3; /* 0xffc */ ++} aidmp_t; ++ ++#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */ ++ ++/* Out-of-band Router registers */ ++#define OOB_BUSCONFIG 0x020 ++#define OOB_STATUSA 0x100 ++#define OOB_STATUSB 0x104 ++#define OOB_STATUSC 0x108 ++#define OOB_STATUSD 0x10c ++#define OOB_ENABLEA0 0x200 ++#define OOB_ENABLEA1 0x204 ++#define OOB_ENABLEA2 0x208 ++#define OOB_ENABLEA3 0x20c ++#define OOB_ENABLEB0 0x280 ++#define OOB_ENABLEB1 0x284 ++#define OOB_ENABLEB2 0x288 ++#define OOB_ENABLEB3 0x28c ++#define OOB_ENABLEC0 0x300 ++#define OOB_ENABLEC1 0x304 ++#define OOB_ENABLEC2 0x308 ++#define OOB_ENABLEC3 0x30c ++#define OOB_ENABLED0 0x380 ++#define OOB_ENABLED1 0x384 ++#define OOB_ENABLED2 0x388 ++#define OOB_ENABLED3 0x38c ++#define OOB_ITCR 0xf00 ++#define OOB_ITIPOOBA 0xf10 ++#define OOB_ITIPOOBB 0xf14 ++#define OOB_ITIPOOBC 0xf18 ++#define OOB_ITIPOOBD 0xf1c ++#define OOB_ITOPOOBA 0xf30 ++#define OOB_ITOPOOBB 0xf34 ++#define OOB_ITOPOOBC 0xf38 ++#define OOB_ITOPOOBD 0xf3c ++ ++/* DMP wrapper registers */ ++#define AI_OOBSELINA30 0x000 ++#define AI_OOBSELINA74 0x004 ++#define AI_OOBSELINB30 0x020 ++#define AI_OOBSELINB74 0x024 ++#define AI_OOBSELINC30 0x040 ++#define AI_OOBSELINC74 0x044 ++#define AI_OOBSELIND30 0x060 ++#define AI_OOBSELIND74 0x064 ++#define AI_OOBSELOUTA30 0x100 ++#define AI_OOBSELOUTA74 0x104 ++#define AI_OOBSELOUTB30 0x120 ++#define AI_OOBSELOUTB74 0x124 ++#define AI_OOBSELOUTC30 0x140 ++#define AI_OOBSELOUTC74 0x144 ++#define AI_OOBSELOUTD30 0x160 ++#define AI_OOBSELOUTD74 0x164 ++#define AI_OOBSYNCA 0x200 ++#define AI_OOBSELOUTAEN 0x204 ++#define AI_OOBSYNCB 0x220 ++#define AI_OOBSELOUTBEN 0x224 ++#define AI_OOBSYNCC 0x240 ++#define AI_OOBSELOUTCEN 0x244 ++#define AI_OOBSYNCD 0x260 ++#define AI_OOBSELOUTDEN 0x264 ++#define AI_OOBAEXTWIDTH 0x300 ++#define AI_OOBAINWIDTH 0x304 ++#define AI_OOBAOUTWIDTH 0x308 ++#define AI_OOBBEXTWIDTH 0x320 ++#define AI_OOBBINWIDTH 0x324 ++#define AI_OOBBOUTWIDTH 0x328 ++#define AI_OOBCEXTWIDTH 0x340 ++#define AI_OOBCINWIDTH 0x344 ++#define AI_OOBCOUTWIDTH 0x348 ++#define AI_OOBDEXTWIDTH 0x360 ++#define AI_OOBDINWIDTH 0x364 ++#define AI_OOBDOUTWIDTH 0x368 ++ ++ ++#define AI_IOCTRLSET 0x400 ++#define AI_IOCTRLCLEAR 0x404 ++#define AI_IOCTRL 0x408 ++#define AI_IOSTATUS 0x500 ++#define AI_RESETCTRL 0x800 ++#define AI_RESETSTATUS 0x804 ++ ++#define AI_IOCTRLWIDTH 0x700 ++#define AI_IOSTATUSWIDTH 0x704 ++ ++#define AI_RESETREADID 0x808 ++#define AI_RESETWRITEID 0x80c ++#define AI_ERRLOGCTRL 0x900 ++#define AI_ERRLOGDONE 0x904 ++#define AI_ERRLOGSTATUS 0x908 ++#define AI_ERRLOGADDRLO 0x90c ++#define AI_ERRLOGADDRHI 0x910 ++#define AI_ERRLOGID 0x914 ++#define AI_ERRLOGUSER 0x918 ++#define AI_ERRLOGFLAGS 0x91c ++#define AI_INTSTATUS 0xa00 ++#define AI_CONFIG 0xe00 ++#define AI_ITCR 0xf00 ++#define AI_ITIPOOBA 0xf10 ++#define AI_ITIPOOBB 0xf14 ++#define AI_ITIPOOBC 0xf18 ++#define AI_ITIPOOBD 0xf1c ++#define AI_ITIPOOBAOUT 0xf30 ++#define AI_ITIPOOBBOUT 0xf34 ++#define AI_ITIPOOBCOUT 0xf38 ++#define AI_ITIPOOBDOUT 0xf3c ++#define AI_ITOPOOBA 0xf50 ++#define AI_ITOPOOBB 0xf54 ++#define AI_ITOPOOBC 0xf58 ++#define AI_ITOPOOBD 0xf5c ++#define AI_ITOPOOBAIN 0xf70 ++#define AI_ITOPOOBBIN 0xf74 ++#define AI_ITOPOOBCIN 0xf78 ++#define AI_ITOPOOBDIN 0xf7c ++#define AI_ITOPRESET 0xf90 ++#define AI_PERIPHERIALID4 0xfd0 ++#define AI_PERIPHERIALID5 0xfd4 ++#define AI_PERIPHERIALID6 0xfd8 ++#define AI_PERIPHERIALID7 0xfdc ++#define AI_PERIPHERIALID0 0xfe0 ++#define AI_PERIPHERIALID1 0xfe4 ++#define AI_PERIPHERIALID2 0xfe8 ++#define AI_PERIPHERIALID3 0xfec ++#define AI_COMPONENTID0 0xff0 ++#define AI_COMPONENTID1 0xff4 ++#define AI_COMPONENTID2 0xff8 ++#define AI_COMPONENTID3 0xffc ++ ++/* resetctrl */ ++#define AIRC_RESET 1 ++ ++/* errlogctrl */ ++#define AIELC_TO_EXP_MASK 0x0000001f0 /* backplane timeout exponent */ ++#define AIELC_TO_EXP_SHIFT 4 ++#define AIELC_TO_ENAB_SHIFT 9 /* backplane timeout enable */ ++ ++/* errlogdone */ ++#define AIELD_ERRDONE_MASK 0x3 ++ ++/* errlogstatus */ ++#define AIELS_SLAVE_ERR 0x1 ++#define AIELS_TIMEOUT 0x2 ++#define AIELS_DECODE 0x3 ++#define AIELS_TIMEOUT_MASK 0x3 ++ ++/* errorlog status bit map, for SW use */ ++#define AXI_WRAP_STS_NONE (0) ++#define AXI_WRAP_STS_TIMEOUT (1<<0) ++#define AXI_WRAP_STS_SLAVE_ERR (1<<1) ++#define AXI_WRAP_STS_DECODE_ERR (1<<2) ++#define AXI_WRAP_STS_PCI_RD_ERR (1<<3) ++#define AXI_WRAP_STS_WRAP_RD_ERR (1<<4) ++#define AXI_WRAP_STS_SET_CORE_FAIL (1<<5) ++ ++/* errlogFrags */ ++#define AXI_ERRLOG_FLAGS_WRITE_REQ (1<<24) ++ ++/* config */ ++#define AICFG_OOB 0x00000020 ++#define AICFG_IOS 0x00000010 ++#define AICFG_IOC 0x00000008 ++#define AICFG_TO 0x00000004 ++#define AICFG_ERRL 0x00000002 ++#define AICFG_RST 0x00000001 ++ ++/* bit defines for AI_OOBSELOUTB74 reg */ ++#define OOB_SEL_OUTEN_B_5 15 ++#define OOB_SEL_OUTEN_B_6 23 ++ ++/* AI_OOBSEL for A/B/C/D, 0-7 */ ++#define AI_OOBSEL_MASK 0x1F ++#define AI_OOBSEL_0_SHIFT 0 ++#define AI_OOBSEL_1_SHIFT 8 ++#define AI_OOBSEL_2_SHIFT 16 ++#define AI_OOBSEL_3_SHIFT 24 ++#define AI_OOBSEL_4_SHIFT 0 ++#define AI_OOBSEL_5_SHIFT 8 ++#define AI_OOBSEL_6_SHIFT 16 ++#define AI_OOBSEL_7_SHIFT 24 ++#define AI_IOCTRL_ENABLE_D11_PME (1 << 14) ++ ++/* mask for interrupts from each core to wrapper */ ++#define AI_OOBSELINA74_CORE_MASK 0x80808080 ++#define AI_OOBSELINA30_CORE_MASK 0x80808080 ++ ++/* axi id mask in the error log id */ ++#define AI_ERRLOGID_AXI_ID_MASK 0x07 ++ ++#endif /* _AIDMP_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcm_cfg.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcm_cfg.h +new file mode 100644 +index 000000000..12e3cb2ca +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcm_cfg.h +@@ -0,0 +1,32 @@ ++/* ++ * BCM common config options ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcm_cfg.h 514727 2014-11-12 03:02:48Z $ ++ */ ++ ++#ifndef _bcm_cfg_h_ ++#define _bcm_cfg_h_ ++#endif /* _bcm_cfg_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h +new file mode 100644 +index 000000000..f8ce7a78e +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h +@@ -0,0 +1,364 @@ ++/* ++ * Memory pools library, Public interface ++ * ++ * API Overview ++ * ++ * This package provides a memory allocation subsystem based on pools of ++ * homogenous objects. ++ * ++ * Instrumentation is available for reporting memory utilization both ++ * on a per-data-structure basis and system wide. ++ * ++ * There are two main types defined in this API. ++ * ++ * pool manager: A singleton object that acts as a factory for ++ * pool allocators. It also is used for global ++ * instrumentation, such as reporting all blocks ++ * in use across all data structures. The pool manager ++ * creates and provides individual memory pools ++ * upon request to application code. ++ * ++ * memory pool: An object for allocating homogenous memory blocks. ++ * ++ * Global identifiers in this module use the following prefixes: ++ * bcm_mpm_* Memory pool manager ++ * bcm_mp_* Memory pool ++ * ++ * There are two main types of memory pools: ++ * ++ * prealloc: The contiguous memory block of objects can either be supplied ++ * by the client or malloc'ed by the memory manager. The objects are ++ * allocated out of a block of memory and freed back to the block. ++ * ++ * heap: The memory pool allocator uses the heap (malloc/free) for memory. ++ * In this case, the pool allocator is just providing statistics ++ * and instrumentation on top of the heap, without modifying the heap ++ * allocation implementation. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcm_mpool_pub.h 535090 2015-02-17 04:49:01Z $ ++ */ ++ ++#ifndef _BCM_MPOOL_PUB_H ++#define _BCM_MPOOL_PUB_H 1 ++ ++#include /* needed for uint16 */ ++ ++ ++/* ++************************************************************************** ++* ++* Type definitions, handles ++* ++************************************************************************** ++*/ ++ ++/* Forward declaration of OSL handle. */ ++struct osl_info; ++ ++/* Forward declaration of string buffer. */ ++struct bcmstrbuf; ++ ++/* ++ * Opaque type definition for the pool manager handle. This object is used for global ++ * memory pool operations such as obtaining a new pool, deleting a pool, iterating and ++ * instrumentation/debugging. ++ */ ++struct bcm_mpm_mgr; ++typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h; ++ ++/* ++ * Opaque type definition for an instance of a pool. This handle is used for allocating ++ * and freeing memory through the pool, as well as management/instrumentation on this ++ * specific pool. ++ */ ++struct bcm_mp_pool; ++typedef struct bcm_mp_pool *bcm_mp_pool_h; ++ ++ ++/* ++ * To make instrumentation more readable, every memory ++ * pool must have a readable name. Pool names are up to ++ * 8 bytes including '\0' termination. (7 printable characters.) ++ */ ++#define BCM_MP_NAMELEN 8 ++ ++ ++/* ++ * Type definition for pool statistics. ++ */ ++typedef struct bcm_mp_stats { ++ char name[BCM_MP_NAMELEN]; /* Name of this pool. */ ++ unsigned int objsz; /* Object size allocated in this pool */ ++ uint16 nobj; /* Total number of objects in this pool */ ++ uint16 num_alloc; /* Number of objects currently allocated */ ++ uint16 high_water; /* Max number of allocated objects. */ ++ uint16 failed_alloc; /* Failed allocations. */ ++} bcm_mp_stats_t; ++ ++ ++/* ++************************************************************************** ++* ++* API Routines on the pool manager. ++* ++************************************************************************** ++*/ ++ ++/* ++ * bcm_mpm_init() - initialize the whole memory pool system. ++ * ++ * Parameters: ++ * osh: INPUT Operating system handle. Needed for heap memory allocation. ++ * max_pools: INPUT Maximum number of mempools supported. ++ * mgr: OUTPUT The handle is written with the new pools manager object/handle. ++ * ++ * Returns: ++ * BCME_OK Object initialized successfully. May be used. ++ * BCME_NOMEM Initialization failed due to no memory. Object must not be used. ++ */ ++int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp); ++ ++ ++/* ++ * bcm_mpm_deinit() - de-initialize the whole memory pool system. ++ * ++ * Parameters: ++ * mgr: INPUT Pointer to pool manager handle. ++ * ++ * Returns: ++ * BCME_OK Memory pool manager successfully de-initialized. ++ * other Indicated error occured during de-initialization. ++ */ ++int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp); ++ ++/* ++ * bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The ++ * pool uses a contiguous block of pre-alloced ++ * memory. The memory block may either be provided ++ * by the client or dynamically allocated by the ++ * pool manager. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pool manager ++ * obj_sz: INPUT Size of objects that will be allocated by the new pool ++ * Must be >= sizeof(void *). ++ * nobj: INPUT Maximum number of concurrently existing objects to support ++ * memstart INPUT Pointer to the memory to use, or NULL to malloc() ++ * memsize INPUT Number of bytes referenced from memstart (for error checking). ++ * Must be 0 if 'memstart' is NULL. ++ * poolname INPUT For instrumentation, the name of the pool ++ * newp: OUTPUT The handle for the new pool, if creation is successful ++ * ++ * Returns: ++ * BCME_OK Pool created ok. ++ * other Pool not created due to indicated error. newpoolp set to NULL. ++ * ++ * ++ */ ++int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr, ++ unsigned int obj_sz, ++ int nobj, ++ void *memstart, ++ unsigned int memsize, ++ const char poolname[BCM_MP_NAMELEN], ++ bcm_mp_pool_h *newp); ++ ++ ++/* ++ * bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after ++ * all memory objects have been freed back to the pool. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * pool: INPUT The handle of the pool to delete ++ * ++ * Returns: ++ * BCME_OK Pool deleted ok. ++ * other Pool not deleted due to indicated error. ++ * ++ */ ++int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); ++ ++/* ++ * bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory ++ * pool allocator uses the heap (malloc/free) for memory. ++ * In this case, the pool allocator is just providing ++ * statistics and instrumentation on top of the heap, ++ * without modifying the heap allocation implementation. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pool manager ++ * obj_sz: INPUT Size of objects that will be allocated by the new pool ++ * poolname INPUT For instrumentation, the name of the pool ++ * newp: OUTPUT The handle for the new pool, if creation is successful ++ * ++ * Returns: ++ * BCME_OK Pool created ok. ++ * other Pool not created due to indicated error. newpoolp set to NULL. ++ * ++ * ++ */ ++int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz, ++ const char poolname[BCM_MP_NAMELEN], ++ bcm_mp_pool_h *newp); ++ ++ ++/* ++ * bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after ++ * all memory objects have been freed back to the pool. ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * pool: INPUT The handle of the pool to delete ++ * ++ * Returns: ++ * BCME_OK Pool deleted ok. ++ * other Pool not deleted due to indicated error. ++ * ++ */ ++int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp); ++ ++ ++/* ++ * bcm_mpm_stats() - Return stats for all pools ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * stats: OUTPUT Array of pool statistics. ++ * nentries: MOD Max elements in 'stats' array on INPUT. Actual number ++ * of array elements copied to 'stats' on OUTPUT. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error getting stats. ++ * ++ */ ++int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries); ++ ++ ++/* ++ * bcm_mpm_dump() - Display statistics on all pools ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager ++ * b: OUTPUT Output buffer. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error during dump. ++ * ++ */ ++int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b); ++ ++ ++/* ++ * bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to ++ * compensate for alignment requirements of the objects. ++ * This function provides the padded object size. If clients ++ * pre-allocate a memory slab for a memory pool, the ++ * padded object size should be used by the client to allocate ++ * the memory slab (in order to provide sufficent space for ++ * the maximum number of objects). ++ * ++ * Parameters: ++ * mgr: INPUT The handle to the pools manager. ++ * obj_sz: INPUT Input object size. ++ * padded_obj_sz: OUTPUT Padded object size. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * BCME_BADARG Bad arguments. ++ * ++ */ ++int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz); ++ ++ ++/* ++*************************************************************************** ++* ++* API Routines on a specific pool. ++* ++*************************************************************************** ++*/ ++ ++ ++/* ++ * bcm_mp_alloc() - Allocate a memory pool object. ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool. ++ * ++ * Returns: ++ * A pointer to the new object. NULL on error. ++ * ++ */ ++void* bcm_mp_alloc(bcm_mp_pool_h pool); ++ ++/* ++ * bcm_mp_free() - Free a memory pool object. ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool. ++ * objp: INPUT A pointer to the object to free. ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error during free. ++ * ++ */ ++int bcm_mp_free(bcm_mp_pool_h pool, void *objp); ++ ++/* ++ * bcm_mp_stats() - Return stats for this pool ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool ++ * stats: OUTPUT Pool statistics ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error getting statistics. ++ * ++ */ ++void bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats); ++ ++ ++/* ++ * bcm_mp_dump() - Dump a pool ++ * ++ * Parameters: ++ * pool: INPUT The handle to the pool ++ * b OUTPUT Output buffer ++ * ++ * Returns: ++ * BCME_OK Ok ++ * other Error during dump. ++ * ++ */ ++int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b); ++ ++ ++#endif /* _BCM_MPOOL_PUB_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcm_ring.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcm_ring.h +new file mode 100644 +index 000000000..721d7eab6 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcm_ring.h +@@ -0,0 +1,634 @@ ++/* ++ * bcm_ring.h : Ring context abstraction ++ * The ring context tracks the WRITE and READ indices where elements may be ++ * produced and consumed respectively. All elements in the ring need to be ++ * fixed size. ++ * ++ * NOTE: A ring of size N, may only hold N-1 elements. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcm_ring.h 596126 2015-10-29 19:53:48Z $ ++ */ ++#ifndef __bcm_ring_included__ ++#define __bcm_ring_included__ ++/* ++ * API Notes: ++ * ++ * Ring manipulation API allows for: ++ * Pending operations: Often before some work can be completed, it may be ++ * desired that several resources are available, e.g. space for production in ++ * a ring. Approaches such as, #1) reserve resources one by one and return them ++ * if another required resource is not available, or #2) employ a two pass ++ * algorithm of first testing whether all resources are available, have a ++ * an impact on performance critical code. The approach taken here is more akin ++ * to approach #2, where a test for resource availability essentially also ++ * provides the index for production in an un-committed state. ++ * The same approach is taken for the consumer side. ++ * ++ * - Pending production: Fetch the next index where a ring element may be ++ * produced. The caller may not commit the WRITE of the element. ++ * - Pending consumption: Fetch the next index where a ring element may be ++ * consumed. The caller may not commut the READ of the element. ++ * ++ * Producer side API: ++ * - bcm_ring_is_full : Test whether ring is full ++ * - bcm_ring_prod : Fetch index where an element may be produced (commit) ++ * - bcm_ring_prod_pend: Fetch index where an element may be produced (pending) ++ * - bcm_ring_prod_done: Commit a previous pending produce fetch ++ * - bcm_ring_prod_avail: Fetch total number free slots eligible for production ++ * ++ * Consumer side API: ++ * - bcm_ring_is_empty : Test whether ring is empty ++ * - bcm_ring_cons : Fetch index where an element may be consumed (commit) ++ * - bcm_ring_cons_pend: Fetch index where an element may be consumed (pending) ++ * - bcm_ring_cons_done: Commit a previous pending consume fetch ++ * - bcm_ring_cons_avail: Fetch total number elements eligible for consumption ++ * ++ * - bcm_ring_sync_read: Sync read offset in peer ring, from local ring ++ * - bcm_ring_sync_write: Sync write offset in peer ring, from local ring ++ * ++ * +---------------------------------------------------------------------------- ++ * ++ * Design Notes: ++ * Following items are not tracked in a ring context (design decision) ++ * - width of a ring element. ++ * - depth of the ring. ++ * - base of the buffer, where the elements are stored. ++ * - count of number of free slots in the ring ++ * ++ * Implementation Notes: ++ * - When BCM_RING_DEBUG is enabled, need explicit bcm_ring_init(). ++ * - BCM_RING_EMPTY and BCM_RING_FULL are (-1) ++ * ++ * +---------------------------------------------------------------------------- ++ * ++ * Usage Notes: ++ * An application may incarnate a ring of some fixed sized elements, by defining ++ * - a ring data buffer to store the ring elements. ++ * - depth of the ring (max number of elements managed by ring context). ++ * Preferrably, depth may be represented as a constant. ++ * - width of a ring element: to be used in pointer arithmetic with the ring's ++ * data buffer base and an index to fetch the ring element. ++ * ++ * Use bcm_workq_t to instantiate a pair of workq constructs, one for the ++ * producer and the other for the consumer, both pointing to the same circular ++ * buffer. The producer may operate on it's own local workq and flush the write ++ * index to the consumer. Likewise the consumer may use its local workq and ++ * flush the read index to the producer. This way we do not repeatedly access ++ * the peer's context. The two peers may reside on different CPU cores with a ++ * private L1 data cache. ++ * +---------------------------------------------------------------------------- ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * $Id: bcm_ring.h 596126 2015-10-29 19:53:48Z $ ++ * ++ * -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- ++ * vim: set ts=4 noet sw=4 tw=80: ++ * ++ * +---------------------------------------------------------------------------- ++ */ ++ ++#ifdef ____cacheline_aligned ++#define __ring_aligned ____cacheline_aligned ++#else ++#define __ring_aligned ++#endif ++ ++/* Conditional compile for debug */ ++/* #define BCM_RING_DEBUG */ ++ ++#define BCM_RING_EMPTY (-1) ++#define BCM_RING_FULL (-1) ++#define BCM_RING_NULL ((bcm_ring_t *)NULL) ++ ++#if defined(BCM_RING_DEBUG) ++#define RING_ASSERT(exp) ASSERT(exp) ++#define BCM_RING_IS_VALID(ring) (((ring) != BCM_RING_NULL) && \ ++ ((ring)->self == (ring))) ++#else /* ! BCM_RING_DEBUG */ ++#define RING_ASSERT(exp) do {} while (0) ++#define BCM_RING_IS_VALID(ring) ((ring) != BCM_RING_NULL) ++#endif /* ! BCM_RING_DEBUG */ ++ ++#define BCM_RING_SIZE_IS_VALID(ring_size) ((ring_size) > 0) ++ ++/* ++ * +---------------------------------------------------------------------------- ++ * Ring Context ++ * +---------------------------------------------------------------------------- ++ */ ++typedef struct bcm_ring { /* Ring context */ ++#if defined(BCM_RING_DEBUG) ++ struct bcm_ring *self; /* ptr to self for IS VALID test */ ++#endif /* BCM_RING_DEBUG */ ++ int write __ring_aligned; /* WRITE index in a circular ring */ ++ int read __ring_aligned; /* READ index in a circular ring */ ++} bcm_ring_t; ++ ++ ++static INLINE void bcm_ring_init(bcm_ring_t *ring); ++static INLINE void bcm_ring_copy(bcm_ring_t *to, bcm_ring_t *from); ++static INLINE bool bcm_ring_is_empty(bcm_ring_t *ring); ++ ++static INLINE int __bcm_ring_next_write(bcm_ring_t *ring, const int ring_size); ++ ++static INLINE bool __bcm_ring_full(bcm_ring_t *ring, int next_write); ++static INLINE bool bcm_ring_is_full(bcm_ring_t *ring, const int ring_size); ++ ++static INLINE void bcm_ring_prod_done(bcm_ring_t *ring, int write); ++static INLINE int bcm_ring_prod_pend(bcm_ring_t *ring, int *pend_write, ++ const int ring_size); ++static INLINE int bcm_ring_prod(bcm_ring_t *ring, const int ring_size); ++ ++static INLINE void bcm_ring_cons_done(bcm_ring_t *ring, int read); ++static INLINE int bcm_ring_cons_pend(bcm_ring_t *ring, int *pend_read, ++ const int ring_size); ++static INLINE int bcm_ring_cons(bcm_ring_t *ring, const int ring_size); ++ ++static INLINE void bcm_ring_sync_read(bcm_ring_t *peer, const bcm_ring_t *self); ++static INLINE void bcm_ring_sync_write(bcm_ring_t *peer, const bcm_ring_t *self); ++ ++static INLINE int bcm_ring_prod_avail(const bcm_ring_t *ring, ++ const int ring_size); ++static INLINE int bcm_ring_cons_avail(const bcm_ring_t *ring, ++ const int ring_size); ++static INLINE void bcm_ring_cons_all(bcm_ring_t *ring); ++ ++ ++/** ++ * bcm_ring_init - initialize a ring context. ++ * @ring: pointer to a ring context ++ */ ++static INLINE void ++bcm_ring_init(bcm_ring_t *ring) ++{ ++ ASSERT(ring != (bcm_ring_t *)NULL); ++#if defined(BCM_RING_DEBUG) ++ ring->self = ring; ++#endif /* BCM_RING_DEBUG */ ++ ring->write = 0; ++ ring->read = 0; ++} ++ ++/** ++ * bcm_ring_copy - copy construct a ring ++ * @to: pointer to the new ring context ++ * @from: pointer to orig ring context ++ */ ++static INLINE void ++bcm_ring_copy(bcm_ring_t *to, bcm_ring_t *from) ++{ ++ bcm_ring_init(to); ++ ++ to->write = from->write; ++ to->read = from->read; ++} ++ ++/** ++ * bcm_ring_is_empty - "Boolean" test whether ring is empty. ++ * @ring: pointer to a ring context ++ * ++ * PS. does not return BCM_RING_EMPTY value. ++ */ ++static INLINE bool ++bcm_ring_is_empty(bcm_ring_t *ring) ++{ ++ RING_ASSERT(BCM_RING_IS_VALID(ring)); ++ return (ring->read == ring->write); ++} ++ ++ ++/** ++ * __bcm_ring_next_write - determine the index where the next write may occur ++ * (with wrap-around). ++ * @ring: pointer to a ring context ++ * @ring_size: size of the ring ++ * ++ * PRIVATE INTERNAL USE ONLY. ++ */ ++static INLINE int ++__bcm_ring_next_write(bcm_ring_t *ring, const int ring_size) ++{ ++ RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size)); ++ return ((ring->write + 1) % ring_size); ++} ++ ++ ++/** ++ * __bcm_ring_full - support function for ring full test. ++ * @ring: pointer to a ring context ++ * @next_write: next location in ring where an element is to be produced ++ * ++ * PRIVATE INTERNAL USE ONLY. ++ */ ++static INLINE bool ++__bcm_ring_full(bcm_ring_t *ring, int next_write) ++{ ++ return (next_write == ring->read); ++} ++ ++ ++/** ++ * bcm_ring_is_full - "Boolean" test whether a ring is full. ++ * @ring: pointer to a ring context ++ * @ring_size: size of the ring ++ * ++ * PS. does not return BCM_RING_FULL value. ++ */ ++static INLINE bool ++bcm_ring_is_full(bcm_ring_t *ring, const int ring_size) ++{ ++ int next_write; ++ RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size)); ++ next_write = __bcm_ring_next_write(ring, ring_size); ++ return __bcm_ring_full(ring, next_write); ++} ++ ++ ++/** ++ * bcm_ring_prod_done - commit a previously pending index where production ++ * was requested. ++ * @ring: pointer to a ring context ++ * @write: index into ring upto where production was done. ++ * +---------------------------------------------------------------------------- ++ */ ++static INLINE void ++bcm_ring_prod_done(bcm_ring_t *ring, int write) ++{ ++ RING_ASSERT(BCM_RING_IS_VALID(ring)); ++ ring->write = write; ++} ++ ++ ++/** ++ * bcm_ring_prod_pend - Fetch in "pend" mode, the index where an element may be ++ * produced. ++ * @ring: pointer to a ring context ++ * @pend_write: next index, after the returned index ++ * @ring_size: size of the ring ++ */ ++static INLINE int ++bcm_ring_prod_pend(bcm_ring_t *ring, int *pend_write, const int ring_size) ++{ ++ int rtn; ++ RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size)); ++ *pend_write = __bcm_ring_next_write(ring, ring_size); ++ if (__bcm_ring_full(ring, *pend_write)) { ++ *pend_write = BCM_RING_FULL; ++ rtn = BCM_RING_FULL; ++ } else { ++ /* production is not committed, caller needs to explicitly commit */ ++ rtn = ring->write; ++ } ++ return rtn; ++} ++ ++ ++/** ++ * bcm_ring_prod - Fetch and "commit" the next index where a ring element may ++ * be produced. ++ * @ring: pointer to a ring context ++ * @ring_size: size of the ring ++ */ ++static INLINE int ++bcm_ring_prod(bcm_ring_t *ring, const int ring_size) ++{ ++ int next_write, prod_write; ++ RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size)); ++ ++ next_write = __bcm_ring_next_write(ring, ring_size); ++ if (__bcm_ring_full(ring, next_write)) { ++ prod_write = BCM_RING_FULL; ++ } else { ++ prod_write = ring->write; ++ bcm_ring_prod_done(ring, next_write); /* "commit" production */ ++ } ++ return prod_write; ++} ++ ++ ++/** ++ * bcm_ring_cons_done - commit a previously pending read ++ * @ring: pointer to a ring context ++ * @read: index upto which elements have been consumed. ++ */ ++static INLINE void ++bcm_ring_cons_done(bcm_ring_t *ring, int read) ++{ ++ RING_ASSERT(BCM_RING_IS_VALID(ring)); ++ ring->read = read; ++} ++ ++ ++/** ++ * bcm_ring_cons_pend - fetch in "pend" mode, the next index where a ring ++ * element may be consumed. ++ * @ring: pointer to a ring context ++ * @pend_read: index into ring upto which elements may be consumed. ++ * @ring_size: size of the ring ++ */ ++static INLINE int ++bcm_ring_cons_pend(bcm_ring_t *ring, int *pend_read, const int ring_size) ++{ ++ int rtn; ++ RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size)); ++ if (bcm_ring_is_empty(ring)) { ++ *pend_read = BCM_RING_EMPTY; ++ rtn = BCM_RING_EMPTY; ++ } else { ++ *pend_read = (ring->read + 1) % ring_size; ++ /* production is not committed, caller needs to explicitly commit */ ++ rtn = ring->read; ++ } ++ return rtn; ++} ++ ++ ++/** ++ * bcm_ring_cons - fetch and "commit" the next index where a ring element may ++ * be consumed. ++ * @ring: pointer to a ring context ++ * @ring_size: size of the ring ++ */ ++static INLINE int ++bcm_ring_cons(bcm_ring_t *ring, const int ring_size) ++{ ++ int cons_read; ++ RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size)); ++ if (bcm_ring_is_empty(ring)) { ++ cons_read = BCM_RING_EMPTY; ++ } else { ++ cons_read = ring->read; ++ ring->read = (ring->read + 1) % ring_size; /* read is committed */ ++ } ++ return cons_read; ++} ++ ++ ++/** ++ * bcm_ring_sync_read - on consumption, update peer's read index. ++ * @peer: pointer to peer's producer ring context ++ * @self: pointer to consumer's ring context ++ */ ++static INLINE void ++bcm_ring_sync_read(bcm_ring_t *peer, const bcm_ring_t *self) ++{ ++ RING_ASSERT(BCM_RING_IS_VALID(peer)); ++ RING_ASSERT(BCM_RING_IS_VALID(self)); ++ peer->read = self->read; /* flush read update to peer producer */ ++} ++ ++ ++/** ++ * bcm_ring_sync_write - on consumption, update peer's write index. ++ * @peer: pointer to peer's consumer ring context ++ * @self: pointer to producer's ring context ++ */ ++static INLINE void ++bcm_ring_sync_write(bcm_ring_t *peer, const bcm_ring_t *self) ++{ ++ RING_ASSERT(BCM_RING_IS_VALID(peer)); ++ RING_ASSERT(BCM_RING_IS_VALID(self)); ++ peer->write = self->write; /* flush write update to peer consumer */ ++} ++ ++ ++/** ++ * bcm_ring_prod_avail - fetch total number of available empty slots in the ++ * ring for production. ++ * @ring: pointer to a ring context ++ * @ring_size: size of the ring ++ */ ++static INLINE int ++bcm_ring_prod_avail(const bcm_ring_t *ring, const int ring_size) ++{ ++ int prod_avail; ++ RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size)); ++ if (ring->write >= ring->read) { ++ prod_avail = (ring_size - (ring->write - ring->read) - 1); ++ } else { ++ prod_avail = (ring->read - (ring->write + 1)); ++ } ++ ASSERT(prod_avail < ring_size); ++ return prod_avail; ++} ++ ++ ++/** ++ * bcm_ring_cons_avail - fetch total number of available elements for consumption. ++ * @ring: pointer to a ring context ++ * @ring_size: size of the ring ++ */ ++static INLINE int ++bcm_ring_cons_avail(const bcm_ring_t *ring, const int ring_size) ++{ ++ int cons_avail; ++ RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size)); ++ if (ring->read == ring->write) { ++ cons_avail = 0; ++ } else if (ring->read > ring->write) { ++ cons_avail = ((ring_size - ring->read) + ring->write); ++ } else { ++ cons_avail = ring->write - ring->read; ++ } ++ ASSERT(cons_avail < ring_size); ++ return cons_avail; ++} ++ ++ ++/** ++ * bcm_ring_cons_all - set ring in state where all elements are consumed. ++ * @ring: pointer to a ring context ++ */ ++static INLINE void ++bcm_ring_cons_all(bcm_ring_t *ring) ++{ ++ ring->read = ring->write; ++} ++ ++ ++/** ++ * Work Queue ++ * A work Queue is composed of a ring of work items, of a specified depth. ++ * It HAS-A bcm_ring object, comprising of a RD and WR offset, to implement a ++ * producer/consumer circular ring. ++ */ ++ ++struct bcm_workq { ++ bcm_ring_t ring; /* Ring context abstraction */ ++ struct bcm_workq *peer; /* Peer workq context */ ++ void *buffer; /* Buffer storage for work items in workQ */ ++ int ring_size; /* Depth of workQ */ ++} __ring_aligned; ++ ++typedef struct bcm_workq bcm_workq_t; ++ ++ ++/* #define BCM_WORKQ_DEBUG */ ++#if defined(BCM_WORKQ_DEBUG) ++#define WORKQ_ASSERT(exp) ASSERT(exp) ++#else /* ! BCM_WORKQ_DEBUG */ ++#define WORKQ_ASSERT(exp) do {} while (0) ++#endif /* ! BCM_WORKQ_DEBUG */ ++ ++#define WORKQ_AUDIT(workq) \ ++ WORKQ_ASSERT((workq) != BCM_WORKQ_NULL); \ ++ WORKQ_ASSERT(WORKQ_PEER(workq) != BCM_WORKQ_NULL); \ ++ WORKQ_ASSERT((workq)->buffer == WORKQ_PEER(workq)->buffer); \ ++ WORKQ_ASSERT((workq)->ring_size == WORKQ_PEER(workq)->ring_size); ++ ++#define BCM_WORKQ_NULL ((bcm_workq_t *)NULL) ++ ++#define WORKQ_PEER(workq) ((workq)->peer) ++#define WORKQ_RING(workq) (&((workq)->ring)) ++#define WORKQ_PEER_RING(workq) (&((workq)->peer->ring)) ++ ++#define WORKQ_ELEMENT(__elem_type, __workq, __index) ({ \ ++ WORKQ_ASSERT((__workq) != BCM_WORKQ_NULL); \ ++ WORKQ_ASSERT((__index) < ((__workq)->ring_size)); \ ++ ((__elem_type *)((__workq)->buffer)) + (__index); \ ++}) ++ ++ ++static INLINE void bcm_workq_init(bcm_workq_t *workq, bcm_workq_t *workq_peer, ++ void *buffer, int ring_size); ++ ++static INLINE bool bcm_workq_is_empty(bcm_workq_t *workq_prod); ++ ++static INLINE void bcm_workq_prod_sync(bcm_workq_t *workq_prod); ++static INLINE void bcm_workq_cons_sync(bcm_workq_t *workq_cons); ++ ++static INLINE void bcm_workq_prod_refresh(bcm_workq_t *workq_prod); ++static INLINE void bcm_workq_cons_refresh(bcm_workq_t *workq_cons); ++ ++/** ++ * bcm_workq_init - initialize a workq ++ * @workq: pointer to a workq context ++ * @buffer: pointer to a pre-allocated circular buffer to serve as a ring ++ * @ring_size: size of the ring in terms of max number of elements. ++ */ ++static INLINE void ++bcm_workq_init(bcm_workq_t *workq, bcm_workq_t *workq_peer, ++ void *buffer, int ring_size) ++{ ++ ASSERT(workq != BCM_WORKQ_NULL); ++ ASSERT(workq_peer != BCM_WORKQ_NULL); ++ ASSERT(buffer != NULL); ++ ASSERT(ring_size > 0); ++ ++ WORKQ_PEER(workq) = workq_peer; ++ WORKQ_PEER(workq_peer) = workq; ++ ++ bcm_ring_init(WORKQ_RING(workq)); ++ bcm_ring_init(WORKQ_RING(workq_peer)); ++ ++ workq->buffer = workq_peer->buffer = buffer; ++ workq->ring_size = workq_peer->ring_size = ring_size; ++} ++ ++/** ++ * bcm_workq_empty - test whether there is work ++ * @workq_prod: producer's workq ++ */ ++static INLINE bool ++bcm_workq_is_empty(bcm_workq_t *workq_prod) ++{ ++ return bcm_ring_is_empty(WORKQ_RING(workq_prod)); ++} ++ ++/** ++ * bcm_workq_prod_sync - Commit the producer write index to peer workq's ring ++ * @workq_prod: producer's workq whose write index must be synced to peer ++ */ ++static INLINE void ++bcm_workq_prod_sync(bcm_workq_t *workq_prod) ++{ ++ WORKQ_AUDIT(workq_prod); ++ ++ /* cons::write <--- prod::write */ ++ bcm_ring_sync_write(WORKQ_PEER_RING(workq_prod), WORKQ_RING(workq_prod)); ++} ++ ++/** ++ * bcm_workq_cons_sync - Commit the consumer read index to the peer workq's ring ++ * @workq_cons: consumer's workq whose read index must be synced to peer ++ */ ++static INLINE void ++bcm_workq_cons_sync(bcm_workq_t *workq_cons) ++{ ++ WORKQ_AUDIT(workq_cons); ++ ++ /* prod::read <--- cons::read */ ++ bcm_ring_sync_read(WORKQ_PEER_RING(workq_cons), WORKQ_RING(workq_cons)); ++} ++ ++ ++/** ++ * bcm_workq_prod_refresh - Fetch the updated consumer's read index ++ * @workq_prod: producer's workq whose read index must be refreshed from peer ++ */ ++static INLINE void ++bcm_workq_prod_refresh(bcm_workq_t *workq_prod) ++{ ++ WORKQ_AUDIT(workq_prod); ++ ++ /* prod::read <--- cons::read */ ++ bcm_ring_sync_read(WORKQ_RING(workq_prod), WORKQ_PEER_RING(workq_prod)); ++} ++ ++/** ++ * bcm_workq_cons_refresh - Fetch the updated producer's write index ++ * @workq_cons: consumer's workq whose write index must be refreshed from peer ++ */ ++static INLINE void ++bcm_workq_cons_refresh(bcm_workq_t *workq_cons) ++{ ++ WORKQ_AUDIT(workq_cons); ++ ++ /* cons::write <--- prod::write */ ++ bcm_ring_sync_write(WORKQ_RING(workq_cons), WORKQ_PEER_RING(workq_cons)); ++} ++ ++ ++#endif /* ! __bcm_ring_h_included__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmcdc.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmcdc.h +new file mode 100644 +index 000000000..22fd8a093 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmcdc.h +@@ -0,0 +1,135 @@ ++/* ++ * CDC network driver ioctl/indication encoding ++ * Broadcom 802.11abg Networking Device Driver ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmcdc.h 676811 2016-12-24 20:48:46Z $ ++ */ ++#ifndef _bcmcdc_h_ ++#define _bcmcdc_h_ ++#include ++ ++typedef struct cdc_ioctl { ++ uint32 cmd; /* ioctl command value */ ++ uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */ ++ uint32 flags; /* flag defns given below */ ++ uint32 status; /* status code returned from the device */ ++} cdc_ioctl_t; ++ ++/* Max valid buffer size that can be sent to the dongle */ ++#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN ++ ++/* len field is divided into input and output buffer lengths */ ++#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */ ++ /* excluding IOCTL header */ ++#define CDCL_IOC_OUTLEN_SHIFT 0 ++#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */ ++#define CDCL_IOC_INLEN_SHIFT 16 ++ ++/* CDC flag definitions */ ++#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */ ++#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */ ++#define CDCF_IOC_OVL_IDX_MASK 0x3c /* overlay region index mask */ ++#define CDCF_IOC_OVL_RSV 0x40 /* 1=reserve this overlay region */ ++#define CDCF_IOC_OVL 0x80 /* 1=this ioctl corresponds to an overlay */ ++#define CDCF_IOC_ACTION_MASK 0xfe /* SET/GET, OVL_IDX, OVL_RSV, OVL mask */ ++#define CDCF_IOC_ACTION_SHIFT 1 /* SET/GET, OVL_IDX, OVL_RSV, OVL shift */ ++#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */ ++#define CDCF_IOC_IF_SHIFT 12 ++#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */ ++#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */ ++ ++#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT) ++#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT) ++ ++#define CDC_GET_IF_IDX(hdr) \ ++ ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)) ++#define CDC_SET_IF_IDX(hdr, idx) \ ++ ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT))) ++ ++/* ++ * BDC header ++ * ++ * The BDC header is used on data packets to convey priority across USB. ++ */ ++ ++struct bdc_header { ++ uint8 flags; /* Flags */ ++ uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 USB flow control info */ ++ uint8 flags2; ++ uint8 dataOffset; /* Offset from end of BDC header to packet data, in ++ * 4-byte words. Leaves room for optional headers. ++ */ ++}; ++ ++#define BDC_HEADER_LEN 4 ++ ++/* flags field bitmap */ ++#define BDC_FLAG_80211_PKT 0x01 /* Packet is in 802.11 format (dongle -> host) */ ++#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */ ++#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums: host->device */ ++#define BDC_FLAG_EVENT_MSG 0x08 /* Payload contains an event msg: device->host */ ++#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ ++#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ ++ ++/* priority field bitmap */ ++#define BDC_PRIORITY_MASK 0x07 ++#define BDC_PRIORITY_FC_MASK 0xf0 /* flow control info mask */ ++#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */ ++ ++/* flags2 field bitmap */ ++#define BDC_FLAG2_IF_MASK 0x0f /* interface index (host <-> dongle) */ ++#define BDC_FLAG2_IF_SHIFT 0 ++#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */ ++ /* FLOW CONTROL info only */ ++ ++/* version numbers */ ++#define BDC_PROTO_VER_1 1 /* Old Protocol version */ ++#define BDC_PROTO_VER 2 /* Protocol version */ ++ ++/* flags2.if field access macros */ ++#define BDC_GET_IF_IDX(hdr) \ ++ ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) ++#define BDC_SET_IF_IDX(hdr, idx) \ ++ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | ((idx) << BDC_FLAG2_IF_SHIFT))) ++ ++#define BDC_FLAG2_PAD_MASK 0xf0 ++#define BDC_FLAG_PAD_MASK 0x03 ++#define BDC_FLAG2_PAD_SHIFT 2 ++#define BDC_FLAG_PAD_SHIFT 0 ++#define BDC_FLAG2_PAD_IDX 0x3c ++#define BDC_FLAG_PAD_IDX 0x03 ++#define BDC_GET_PAD_LEN(hdr) \ ++ ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \ ++ ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT))) ++#define BDC_SET_PAD_LEN(hdr, idx) \ ++ ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \ ++ (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \ ++ ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \ ++ (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT))) ++ ++#endif /* _bcmcdc_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmdefs.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmdefs.h +new file mode 100644 +index 000000000..58cbe5e7a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmdefs.h +@@ -0,0 +1,462 @@ ++/* ++ * Misc system wide definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmdefs.h 657791 2016-09-02 15:14:42Z $ ++ */ ++ ++#ifndef _bcmdefs_h_ ++#define _bcmdefs_h_ ++ ++/* ++ * One doesn't need to include this file explicitly, gets included automatically if ++ * typedefs.h is included. ++ */ ++ ++/* Use BCM_REFERENCE to suppress warnings about intentionally-unused function ++ * arguments or local variables. ++ */ ++#define BCM_REFERENCE(data) ((void)(data)) ++ ++/* Allow for suppressing unused variable warnings. */ ++#ifdef __GNUC__ ++#define UNUSED_VAR __attribute__ ((unused)) ++#else ++#define UNUSED_VAR ++#endif ++ ++/* Compile-time assert can be used in place of ASSERT if the expression evaluates ++ * to a constant at compile time. ++ */ ++#define STATIC_ASSERT(expr) { \ ++ /* Make sure the expression is constant. */ \ ++ typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e UNUSED_VAR; \ ++ /* Make sure the expression is true. */ \ ++ typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] UNUSED_VAR; \ ++} ++ ++/* Reclaiming text and data : ++ * The following macros specify special linker sections that can be reclaimed ++ * after a system is considered 'up'. ++ * BCMATTACHFN is also used for detach functions (it's not worth having a BCMDETACHFN, ++ * as in most cases, the attach function calls the detach function to clean up on error). ++ */ ++#if defined(BCM_RECLAIM) ++ ++extern bool bcm_reclaimed; ++extern bool bcm_attach_part_reclaimed; ++extern bool bcm_preattach_part_reclaimed; ++ ++#if defined(BCM_RECLAIM_ATTACH_FN_DATA) ++#define _data __attribute__ ((__section__ (".dataini2." #_data))) _data ++#define _fn __attribute__ ((__section__ (".textini2." #_fn), noinline)) _fn ++ ++/* Relocate attach symbols to save-restore region to increase pre-reclaim heap size. */ ++#define BCM_SRM_ATTACH_DATA(_data) __attribute__ ((__section__ (".datasrm." #_data))) _data ++#define BCM_SRM_ATTACH_FN(_fn) __attribute__ ((__section__ (".textsrm." #_fn), noinline)) _fn ++ ++#ifndef PREATTACH_NORECLAIM ++#define BCMPREATTACHDATA(_data) __attribute__ ((__section__ (".dataini3." #_data))) _data ++#define BCMPREATTACHFN(_fn) __attribute__ ((__section__ (".textini3." #_fn), noinline)) _fn ++#else ++#define BCMPREATTACHDATA(_data) __attribute__ ((__section__ (".dataini2." #_data))) _data ++#define BCMPREATTACHFN(_fn) __attribute__ ((__section__ (".textini2." #_fn), noinline)) _fn ++#endif /* PREATTACH_NORECLAIM */ ++#else /* BCM_RECLAIM_ATTACH_FN_DATA */ ++#define _data _data ++#define _fn _fn ++#define BCMPREATTACHDATA(_data) _data ++#define BCMPREATTACHFN(_fn) _fn ++#endif /* BCM_RECLAIM_ATTACH_FN_DATA */ ++ ++#if defined(BCM_RECLAIM_INIT_FN_DATA) ++#define _data __attribute__ ((__section__ (".dataini1." #_data))) _data ++#define _fn __attribute__ ((__section__ (".textini1." #_fn), noinline)) _fn ++#define CONST ++#else /* BCM_RECLAIM_INIT_FN_DATA */ ++#define _data _data ++#define _fn _fn ++#ifndef CONST ++#define CONST const ++#endif ++#endif /* BCM_RECLAIM_INIT_FN_DATA */ ++ ++/* Non-manufacture or internal attach function/dat */ ++#define BCMNMIATTACHFN(_fn) _fn ++#define BCMNMIATTACHDATA(_data) _data ++ ++#ifdef BCMNODOWN ++#define _fn _fn ++#else ++#define _fn _fn ++#endif ++ ++#else /* BCM_RECLAIM */ ++ ++#define bcm_reclaimed 0 ++#define _data _data ++#define _fn _fn ++#define BCM_SRM_ATTACH_DATA(_data) _data ++#define BCM_SRM_ATTACH_FN(_fn) _fn ++#define BCMPREATTACHDATA(_data) _data ++#define BCMPREATTACHFN(_fn) _fn ++#define _data _data ++#define _fn _fn ++#define _fn _fn ++#define BCMNMIATTACHFN(_fn) _fn ++#define BCMNMIATTACHDATA(_data) _data ++#define CONST const ++ ++#endif /* BCM_RECLAIM */ ++ ++#if !defined STB ++#undef BCM47XX_CA9 ++#endif /* STB */ ++ ++/* BCMFASTPATH Related Macro defines ++*/ ++#ifndef BCMFASTPATH ++#if defined(STB) ++#define BCMFASTPATH __attribute__ ((__section__ (".text.fastpath"))) ++#define BCMFASTPATH_HOST __attribute__ ((__section__ (".text.fastpath_host"))) ++#else ++#define BCMFASTPATH ++#define BCMFASTPATH_HOST ++#endif ++#endif /* BCMFASTPATH */ ++ ++ ++/* Use the BCMRAMFN() macro to tag functions in source that must be included in RAM (excluded from ++ * ROM). This should eliminate the need to manually specify these functions in the ROM config file. ++ * It should only be used in special cases where the function must be in RAM for *all* ROM-based ++ * chips. ++ */ ++ #define BCMRAMFN(_fn) _fn ++ ++#define STATIC static ++ ++/* Bus types */ ++#define SI_BUS 0 /* SOC Interconnect */ ++#define PCI_BUS 1 /* PCI target */ ++#define PCMCIA_BUS 2 /* PCMCIA 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 */ ++ ++/* Allows size optimization for single-bus image */ ++#ifdef BCMBUSTYPE ++#define BUSTYPE(bus) (BCMBUSTYPE) ++#else ++#define BUSTYPE(bus) (bus) ++#endif ++ ++#ifdef BCMBUSCORETYPE ++#define BUSCORETYPE(ct) (BCMBUSCORETYPE) ++#else ++#define BUSCORETYPE(ct) (ct) ++#endif ++ ++/* Allows size optimization for single-backplane image */ ++#ifdef BCMCHIPTYPE ++#define CHIPTYPE(bus) (BCMCHIPTYPE) ++#else ++#define CHIPTYPE(bus) (bus) ++#endif ++ ++ ++/* Allows size optimization for SPROM support */ ++#if defined(BCMSPROMBUS) ++#define SPROMBUS (BCMSPROMBUS) ++#elif defined(SI_PCMCIA_SROM) ++#define SPROMBUS (PCMCIA_BUS) ++#else ++#define SPROMBUS (PCI_BUS) ++#endif ++ ++/* Allows size optimization for single-chip image */ ++#ifdef BCMCHIPID ++#define CHIPID(chip) (BCMCHIPID) ++#else ++#define CHIPID(chip) (chip) ++#endif ++ ++#ifdef BCMCHIPREV ++#define CHIPREV(rev) (BCMCHIPREV) ++#else ++#define CHIPREV(rev) (rev) ++#endif ++ ++#ifdef BCMPCIEREV ++#define PCIECOREREV(rev) (BCMPCIEREV) ++#else ++#define PCIECOREREV(rev) (rev) ++#endif ++ ++#ifdef BCMPMUREV ++#define PMUREV(rev) (BCMPMUREV) ++#else ++#define PMUREV(rev) (rev) ++#endif ++ ++#ifdef BCMCCREV ++#define CCREV(rev) (BCMCCREV) ++#else ++#define CCREV(rev) (rev) ++#endif ++ ++#ifdef BCMGCIREV ++#define GCIREV(rev) (BCMGCIREV) ++#else ++#define GCIREV(rev) (rev) ++#endif ++ ++/* Defines for DMA Address Width - Shared between OSL and HNDDMA */ ++#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */ ++#define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */ ++#define DMADDR_MASK_26 0xFC000000 /* Address maks for 26-bits */ ++#define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */ ++ ++#define DMADDRWIDTH_26 26 /* 26-bit addressing capability */ ++#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 */ ++ ++typedef struct { ++ uint32 loaddr; ++ uint32 hiaddr; ++} dma64addr_t; ++ ++#define PHYSADDR64HI(_pa) ((_pa).hiaddr) ++#define PHYSADDR64HISET(_pa, _val) \ ++ do { \ ++ (_pa).hiaddr = (_val); \ ++ } while (0) ++#define PHYSADDR64LO(_pa) ((_pa).loaddr) ++#define PHYSADDR64LOSET(_pa, _val) \ ++ do { \ ++ (_pa).loaddr = (_val); \ ++ } while (0) ++ ++#ifdef BCMDMA64OSL ++typedef dma64addr_t dmaaddr_t; ++#define PHYSADDRHI(_pa) PHYSADDR64HI(_pa) ++#define PHYSADDRHISET(_pa, _val) PHYSADDR64HISET(_pa, _val) ++#define PHYSADDRLO(_pa) PHYSADDR64LO(_pa) ++#define PHYSADDRLOSET(_pa, _val) PHYSADDR64LOSET(_pa, _val) ++#define PHYSADDRTOULONG(_pa, _ulong) \ ++ do { \ ++ _ulong = ((unsigned long long)(_pa).hiaddr << 32) | ((_pa).loaddr); \ ++ } while (0) ++ ++#else ++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) ++#endif /* BCMDMA64OSL */ ++#define PHYSADDRISZERO(_pa) (PHYSADDRLO(_pa) == 0 && PHYSADDRHI(_pa) == 0) ++ ++/* One physical DMA segment */ ++typedef struct { ++ dmaaddr_t addr; ++ uint32 length; ++} hnddma_seg_t; ++ ++#define MAX_DMA_SEGS 8 ++ ++ ++typedef struct { ++ void *oshdmah; /* Opaque handle for OSL to store its information */ ++ uint origsize; /* Size of the virtual packet */ ++ uint nsegs; ++ hnddma_seg_t segs[MAX_DMA_SEGS]; ++} hnddma_seg_map_t; ++ ++ ++/* 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 (hnddma.c). ++ */ ++ ++#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) ++/* add 40 bytes to allow for extra RPC header and info */ ++#define BCMEXTRAHDROOM 260 ++#else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ ++#if defined(STB) ++#if defined(BCM_GMAC3) ++#define BCMEXTRAHDROOM 32 /* For FullDongle, no D11 headroom space required. */ ++#else ++#define BCMEXTRAHDROOM 224 ++#endif /* ! BCM_GMAC3 */ ++#else ++#define BCMEXTRAHDROOM 204 ++#endif ++#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ ++ ++/* Packet alignment for most efficient SDIO (can change based on platform) */ ++#ifndef SDALIGN ++#define SDALIGN 32 ++#endif ++ ++/* Headroom required for dongle-to-host communication. Packets allocated ++ * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should ++ * leave this much room in front for low-level message headers which may ++ * be needed to get across the dongle bus to the host. (These messages ++ * don't go over the network, so room for the full WL header above would ++ * be a waste.). ++*/ ++#define BCMDONGLEHDRSZ 12 ++#define BCMDONGLEPADSZ 16 ++ ++#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) ++ ++ ++#if defined(NO_BCMDBG_ASSERT) ++# undef BCMDBG_ASSERT ++# undef BCMASSERT_LOG ++#endif ++ ++#if defined(BCMASSERT_LOG) ++#define BCMASSERT_SUPPORT ++#endif ++ ++/* Macros for doing definition and get/set of bitfields ++ * Usage example, e.g. a three-bit field (bits 4-6): ++ * #define _M BITFIELD_MASK(3) ++ * #define _S 4 ++ * ... ++ * regval = R_REG(osh, ®s->regfoo); ++ * field = GFIELD(regval, ); ++ * regval = SFIELD(regval, , 1); ++ * W_REG(osh, ®s->regfoo, regval); ++ */ ++#define BITFIELD_MASK(width) \ ++ (((unsigned)1 << (width)) - 1) ++#define GFIELD(val, field) \ ++ (((val) >> field ## _S) & field ## _M) ++#define SFIELD(val, field, bits) \ ++ (((val) & (~(field ## _M << field ## _S))) | \ ++ ((unsigned)(bits) << field ## _S)) ++ ++/* define BCMSMALL to remove misc features for memory-constrained environments */ ++#ifdef BCMSMALL ++#undef BCMSPACE ++#define bcmspace FALSE /* if (bcmspace) code is discarded */ ++#else ++#define BCMSPACE ++#define bcmspace TRUE /* if (bcmspace) code is retained */ ++#endif ++ ++/* Max. nvram variable table size */ ++#ifndef MAXSZ_NVRAM_VARS ++#ifdef LARGE_NVRAM_MAXSZ ++#define MAXSZ_NVRAM_VARS LARGE_NVRAM_MAXSZ ++#else ++/* SROM12 changes */ ++#define MAXSZ_NVRAM_VARS 6144 ++#endif /* LARGE_NVRAM_MAXSZ */ ++#endif /* !MAXSZ_NVRAM_VARS */ ++ ++ ++ ++/* WL_ENAB_RUNTIME_CHECK may be set based upon the #define below (for ROM builds). It may also ++ * be defined via makefiles (e.g. ROM auto abandon unoptimized compiles). ++ */ ++ ++ ++#ifdef BCMLFRAG /* BCMLFRAG support enab macros */ ++ extern bool _bcmlfrag; ++ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) ++ #define BCMLFRAG_ENAB() (_bcmlfrag) ++ #elif defined(BCMLFRAG_DISABLED) ++ #define BCMLFRAG_ENAB() (0) ++ #else ++ #define BCMLFRAG_ENAB() (1) ++ #endif ++#else ++ #define BCMLFRAG_ENAB() (0) ++#endif /* BCMLFRAG_ENAB */ ++ ++#ifdef BCMPCIEDEV /* BCMPCIEDEV support enab macros */ ++extern bool _pciedevenab; ++ #if defined(WL_ENAB_RUNTIME_CHECK) ++ #define BCMPCIEDEV_ENAB() (_pciedevenab) ++ #elif defined(BCMPCIEDEV_ENABLED) ++ #define BCMPCIEDEV_ENAB() 1 ++ #else ++ #define BCMPCIEDEV_ENAB() 0 ++ #endif ++#else ++ #define BCMPCIEDEV_ENAB() 0 ++#endif /* BCMPCIEDEV */ ++ ++ #define BCMSDIODEV_ENAB() 0 ++ ++/* Max size for reclaimable NVRAM array */ ++#ifdef DL_NVRAM ++#define NVRAM_ARRAY_MAXSIZE DL_NVRAM ++#else ++#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS ++#endif /* DL_NVRAM */ ++ ++extern uint32 gFWID; ++ ++/* Chip related low power flags (lpflags) */ ++#define LPFLAGS_SI_GLOBAL_DISABLE (1 << 0) ++#define LPFLAGS_SI_MEM_STDBY_DISABLE (1 << 1) ++#define LPFLAGS_SI_SFLASH_DISABLE (1 << 2) ++#define LPFLAGS_SI_BTLDO3P3_DISABLE (1 << 3) ++#define LPFLAGS_SI_GCI_FORCE_REGCLK_DISABLE (1 << 4) ++#define LPFLAGS_SI_FORCE_PWM_WHEN_RADIO_ON (1 << 5) ++#define LPFLAGS_PHY_GLOBAL_DISABLE (1 << 16) ++#define LPFLAGS_PHY_LP_DISABLE (1 << 17) ++#define LPFLAGS_PSM_PHY_CTL (1 << 18) ++ ++/* Chip related Cbuck modes */ ++#define PMU_43012_VREG8_DYNAMIC_CBUCK_MODE0 0x00001c03 ++#define PMU_43012_VREG9_DYNAMIC_CBUCK_MODE0 0x00492490 ++#define PMU_43012_VREG8_DYNAMIC_CBUCK_MODE1 0x00001c03 ++#define PMU_43012_VREG9_DYNAMIC_CBUCK_MODE1 0x00490410 ++ ++/* Chip related dynamic cbuck mode mask */ ++ ++#define PMU_43012_VREG8_DYNAMIC_CBUCK_MODE_MASK 0xFFFFFC00 ++#define PMU_43012_VREG9_DYNAMIC_CBUCK_MODE_MASK 0xFFFFFFFF ++ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif ++ ++#endif /* _bcmdefs_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmdevs.h +new file mode 100644 +index 000000000..5437c8f2a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmdevs.h +@@ -0,0 +1,933 @@ ++/* ++ * Broadcom device-specific manifest constants. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmdevs.h 625027 2016-03-15 08:20:18Z $ ++ */ ++ ++#ifndef _BCMDEVS_H ++#define _BCMDEVS_H ++ ++/* PCI vendor IDs */ ++#define VENDOR_EPIGRAM 0xfeda ++#define VENDOR_BROADCOM 0x14e4 ++#define VENDOR_3COM 0x10b7 ++#define VENDOR_NETGEAR 0x1385 ++#define VENDOR_DIAMOND 0x1092 ++#define VENDOR_INTEL 0x8086 ++#define VENDOR_DELL 0x1028 ++#define VENDOR_HP 0x103c ++#define VENDOR_HP_COMPAQ 0x0e11 ++#define VENDOR_APPLE 0x106b ++#define VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */ ++#define VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */ ++#define VENDOR_TI 0x104c /* Texas Instruments */ ++#define VENDOR_RICOH 0x1180 /* Ricoh */ ++#define VENDOR_JMICRON 0x197b ++ ++ ++/* PCMCIA vendor IDs */ ++#define VENDOR_BROADCOM_PCMCIA 0x02d0 ++ ++/* SDIO vendor IDs */ ++#define VENDOR_BROADCOM_SDIO 0x00BF ++ ++/* DONGLE VID/PIDs */ ++#define BCM_DNGL_VID 0x0a5c ++#define BCM_DNGL_BL_PID_4328 0xbd12 ++#define BCM_DNGL_BL_PID_4322 0xbd13 ++#define BCM_DNGL_BL_PID_4319 0xbd16 ++#define BCM_DNGL_BL_PID_43236 0xbd17 ++#define BCM_DNGL_BL_PID_4332 0xbd18 ++#define BCM_DNGL_BL_PID_4330 0xbd19 ++#define BCM_DNGL_BL_PID_4334 0xbd1a ++#define BCM_DNGL_BL_PID_43239 0xbd1b ++#define BCM_DNGL_BL_PID_4324 0xbd1c ++#define BCM_DNGL_BL_PID_4360 0xbd1d ++#define BCM_DNGL_BL_PID_43143 0xbd1e ++#define BCM_DNGL_BL_PID_43242 0xbd1f ++#define BCM_DNGL_BL_PID_43342 0xbd21 ++#define BCM_DNGL_BL_PID_4335 0xbd20 ++#define BCM_DNGL_BL_PID_43341 0xbd22 ++#define BCM_DNGL_BL_PID_4350 0xbd23 ++#define BCM_DNGL_BL_PID_4345 0xbd24 ++#define BCM_DNGL_BL_PID_4349 0xbd25 ++#define BCM_DNGL_BL_PID_4354 0xbd26 ++#define BCM_DNGL_BL_PID_43569 0xbd27 ++#define BCM_DNGL_BL_PID_43909 0xbd28 ++#define BCM_DNGL_BL_PID_4373 0xbd29 ++ ++#define BCM_DNGL_BDC_PID 0x0bdc ++#define BCM_DNGL_JTAG_PID 0x4a44 ++ ++/* HW USB BLOCK [CPULESS USB] PIDs */ ++#define BCM_HWUSB_PID_43239 43239 ++ ++/* PCI Device IDs */ ++#ifdef DEPRECATED /* These products have been deprecated */ ++#define BCM4210_DEVICE_ID 0x1072 /* never used */ ++#define BCM4230_DEVICE_ID 0x1086 /* never used */ ++#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */ ++#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */ ++#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */ ++#define BCM4211_DEVICE_ID 0x4211 ++#define BCM4231_DEVICE_ID 0x4231 ++#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */ ++#define BCM4311_D11G_ID 0x4311 /* 4311 802.11b/g id */ ++#define BCM4311_D11DUAL_ID 0x4312 /* 4311 802.11a/b/g id */ ++#define BCM4311_D11A_ID 0x4313 /* 4311 802.11a id */ ++#define BCM4328_D11DUAL_ID 0x4314 /* 4328/4312 802.11a/g id */ ++#define BCM4328_D11G_ID 0x4315 /* 4328/4312 802.11g id */ ++#define BCM4328_D11A_ID 0x4316 /* 4328/4312 802.11a id */ ++#define BCM4318_D11A_ID 0x431a /* 4318 802.11a id */ ++#define BCM4325_D11DUAL_ID 0x431b /* 4325 802.11a/g id */ ++#define BCM4325_D11G_ID 0x431c /* 4325 802.11g id */ ++#define BCM4325_D11A_ID 0x431d /* 4325 802.11a id */ ++#define BCM4306_UART_ID 0x4322 /* 4306 uart */ ++#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */ ++#define BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G_ID; INF w/loose binding war */ ++#define BCM4321_D11N_ID 0x4328 /* 4321 802.11n dualband id */ ++#define BCM4321_D11N2G_ID 0x4329 /* 4321 802.11n 2.4Ghz band id */ ++#define BCM4321_D11N5G_ID 0x432a /* 4321 802.11n 5Ghz band id */ ++#define BCM4322_D11N_ID 0x432b /* 4322 802.11n dualband device */ ++#define BCM4322_D11N2G_ID 0x432c /* 4322 802.11n 2.4GHz device */ ++#define BCM4322_D11N5G_ID 0x432d /* 4322 802.11n 5GHz device */ ++#define BCM4329_D11N_ID 0x432e /* 4329 802.11n dualband device */ ++#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */ ++#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */ ++#define BCM4315_D11DUAL_ID 0x4334 /* 4315 802.11a/g id */ ++#define BCM4315_D11G_ID 0x4335 /* 4315 802.11g id */ ++#define BCM4315_D11A_ID 0x4336 /* 4315 802.11a id */ ++#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */ ++#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */ ++#define BCM4319_D11N5G_ID 0x4339 /* 4319 802.11n 5G device */ ++#define BCM43231_D11N2G_ID 0x4340 /* 43231 802.11n 2.4GHz device */ ++#define BCM43221_D11N2G_ID 0x4341 /* 43221 802.11n 2.4GHz device */ ++#define BCM43222_D11N_ID 0x4350 /* 43222 802.11n dualband device */ ++#define BCM43222_D11N2G_ID 0x4351 /* 43222 802.11n 2.4GHz device */ ++#define BCM43222_D11N5G_ID 0x4352 /* 43222 802.11n 5GHz device */ ++#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband device */ ++#endif /* DEPRECATED */ ++/* DEPRECATED but used */ ++#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */ ++#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */ ++#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */ ++#define BCM4318_D11G_ID 0x4318 /* 4318 802.11b/g id */ ++#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g id */ ++/* DEPRECATED */ ++ ++#define BCM53572_D11N2G_ID 0x4329 /* 53572 802.11n 2.4Ghz band id (same as BCM4321) */ ++#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ ++#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */ ++#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ ++#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ ++#define BCM43236_D11N5G_ID 0x4348 /* 43236 802.11n 5GHz device */ ++#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */ ++#define BCM43421_D11N_ID 0xA99D /* 43421 802.11n dualband device */ ++#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ ++#define BCM4330_D11N_ID 0x4360 /* 4330 802.11n dualband device */ ++#define BCM4330_D11N2G_ID 0x4361 /* 4330 802.11n 2.4G device */ ++#define BCM4330_D11N5G_ID 0x4362 /* 4330 802.11n 5G device */ ++#define BCM4336_D11N_ID 0x4343 /* 4336 802.11n 2.4GHz device */ ++#define BCM6362_D11N_ID 0x435f /* 6362 802.11n dualband device */ ++#define BCM6362_D11N2G_ID 0x433f /* 6362 802.11n 2.4Ghz band id */ ++#define BCM6362_D11N5G_ID 0x434f /* 6362 802.11n 5Ghz band id */ ++#define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */ ++#define BCM4331_D11N2G_ID 0x4332 /* 4331 802.11n 2.4Ghz band id */ ++#define BCM4331_D11N5G_ID 0x4333 /* 4331 802.11n 5Ghz band id */ ++#define BCM43237_D11N_ID 0x4355 /* 43237 802.11n dualband device */ ++#define BCM43237_D11N5G_ID 0x4356 /* 43237 802.11n 5GHz device */ ++#define BCM43227_D11N2G_ID 0x4358 /* 43228 802.11n 2.4GHz device */ ++#define BCM43228_D11N_ID 0x4359 /* 43228 802.11n DualBand device */ ++#define BCM43228_D11N5G_ID 0x435a /* 43228 802.11n 5GHz device */ ++#define BCM43362_D11N_ID 0x4363 /* 43362 802.11n 2.4GHz device */ ++#define BCM43239_D11N_ID 0x4370 /* 43239 802.11n dualband device */ ++#define BCM4324_D11N_ID 0x4374 /* 4324 802.11n dualband device */ ++#define BCM43217_D11N2G_ID 0x43a9 /* 43217 802.11n 2.4GHz device */ ++#define BCM43131_D11N2G_ID 0x43aa /* 43131 802.11n 2.4GHz device */ ++#define BCM4314_D11N2G_ID 0x4364 /* 4314 802.11n 2.4G device */ ++#define BCM43142_D11N2G_ID 0x4365 /* 43142 802.11n 2.4G device */ ++#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ ++#define BCM4334_D11N_ID 0x4380 /* 4334 802.11n dualband device */ ++#define BCM4334_D11N2G_ID 0x4381 /* 4334 802.11n 2.4G device */ ++#define BCM4334_D11N5G_ID 0x4382 /* 4334 802.11n 5G device */ ++#define BCM43342_D11N_ID 0x4383 /* 43342 802.11n dualband device */ ++#define BCM43342_D11N2G_ID 0x4384 /* 43342 802.11n 2.4G device */ ++#define BCM43342_D11N5G_ID 0x4385 /* 43342 802.11n 5G device */ ++#define BCM43341_D11N_ID 0x4386 /* 43341 802.11n dualband device */ ++#define BCM43341_D11N2G_ID 0x4387 /* 43341 802.11n 2.4G device */ ++#define BCM43341_D11N5G_ID 0x4388 /* 43341 802.11n 5G device */ ++#define BCM4360_D11AC_ID 0x43a0 ++#define BCM4360_D11AC2G_ID 0x43a1 ++#define BCM4360_D11AC5G_ID 0x43a2 ++#define BCM4345_D11AC_ID 0x43ab /* 4345 802.11ac dualband device */ ++#define BCM4345_D11AC2G_ID 0x43ac /* 4345 802.11ac 2.4G device */ ++#define BCM4345_D11AC5G_ID 0x43ad /* 4345 802.11ac 5G device */ ++#define BCM43455_D11AC_ID 0x43e3 /* 43455 802.11ac dualband device */ ++#define BCM43455_D11AC2G_ID 0x43e4 /* 43455 802.11ac 2.4G device */ ++#define BCM43455_D11AC5G_ID 0x43e5 /* 43455 802.11ac 5G device */ ++#define BCM4335_D11AC_ID 0x43ae ++#define BCM4335_D11AC2G_ID 0x43af ++#define BCM4335_D11AC5G_ID 0x43b0 ++#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */ ++#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */ ++#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */ ++#define BCM43602_D11AC_ID 0x43ba /* ac dualband PCI devid SPROM programmed */ ++#define BCM43602_D11AC2G_ID 0x43bb /* 43602 802.11ac 2.4G device */ ++#define BCM43602_D11AC5G_ID 0x43bc /* 43602 802.11ac 5G device */ ++#define BCM4349_D11AC_ID 0x4349 /* 4349 802.11ac dualband device */ ++#define BCM4349_D11AC2G_ID 0x43dd /* 4349 802.11ac 2.4G device */ ++#define BCM4349_D11AC5G_ID 0x43de /* 4349 802.11ac 5G device */ ++#define BCM53573_D11AC_ID 0x43b4 /* 53573 802.11ac dualband device */ ++#define BCM53573_D11AC2G_ID 0x43b5 /* 53573 802.11ac 2.4G device */ ++#define BCM53573_D11AC5G_ID 0x43b6 /* 53573 802.11ac 5G device */ ++#define BCM47189_D11AC_ID 0x43c6 /* 47189 802.11ac dualband device */ ++#define BCM47189_D11AC2G_ID 0x43c7 /* 47189 802.11ac 2.4G device */ ++#define BCM47189_D11AC5G_ID 0x43c8 /* 47189 802.11ac 5G device */ ++#define BCM4355_D11AC_ID 0x43dc /* 4355 802.11ac dualband device */ ++#define BCM4355_D11AC2G_ID 0x43fc /* 4355 802.11ac 2.4G device */ ++#define BCM4355_D11AC5G_ID 0x43fd /* 4355 802.11ac 5G device */ ++#define BCM4359_D11AC_ID 0x43ef /* 4359 802.11ac dualband device */ ++#define BCM4359_D11AC2G_ID 0x43fe /* 4359 802.11ac 2.4G device */ ++#define BCM4359_D11AC5G_ID 0x43ff /* 4359 802.11ac 5G device */ ++#define BCM43596_D11AC_ID 0x4415 /* 43596 802.11ac dualband device */ ++#define BCM43596_D11AC2G_ID 0x4416 /* 43596 802.11ac 2.4G device */ ++#define BCM43596_D11AC5G_ID 0x4417 /* 43596 802.11ac 5G device */ ++#define BCM43597_D11AC_ID 0x441c /* 43597 802.11ac dualband device */ ++#define BCM43597_D11AC2G_ID 0x441d /* 43597 802.11ac 2.4G device */ ++#define BCM43597_D11AC5G_ID 0x441e /* 43597 802.11ac 5G device */ ++#define BCM43909_D11AC_ID 0x43d0 /* 43909 802.11ac dualband device */ ++#define BCM43909_D11AC2G_ID 0x43d1 /* 43909 802.11ac 2.4G device */ ++#define BCM43909_D11AC5G_ID 0x43d2 /* 43909 802.11ac 5G device */ ++#define BCM43012_D11N_ID 0xA804 /* 43012 802.11n dualband device */ ++#define BCM43012_D11N2G_ID 0xA805 /* 43012 802.11n 2.4G device */ ++#define BCM43012_D11N5G_ID 0xA806 /* 43012 802.11n 5G device */ ++ ++/* PCI Subsystem ID */ ++#define BCM943228HMB_SSID_VEN1 0x0607 ++#define BCM94313HMGBL_SSID_VEN1 0x0608 ++#define BCM94313HMG_SSID_VEN1 0x0609 ++#define BCM943142HM_SSID_VEN1 0x0611 ++ ++#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */ ++ ++#define BCM43242_D11N_ID 0x4367 /* 43242 802.11n dualband device */ ++#define BCM43242_D11N2G_ID 0x4368 /* 43242 802.11n 2.4G device */ ++#define BCM43242_D11N5G_ID 0x4369 /* 43242 802.11n 5G device */ ++ ++#define BCM4350_D11AC_ID 0x43a3 ++#define BCM4350_D11AC2G_ID 0x43a4 ++#define BCM4350_D11AC5G_ID 0x43a5 ++ ++#define BCM43556_D11AC_ID 0x43b7 ++#define BCM43556_D11AC2G_ID 0x43b8 ++#define BCM43556_D11AC5G_ID 0x43b9 ++ ++#define BCM43558_D11AC_ID 0x43c0 ++#define BCM43558_D11AC2G_ID 0x43c1 ++#define BCM43558_D11AC5G_ID 0x43c2 ++ ++#define BCM43566_D11AC_ID 0x43d3 ++#define BCM43566_D11AC2G_ID 0x43d4 ++#define BCM43566_D11AC5G_ID 0x43d5 ++ ++#define BCM43568_D11AC_ID 0x43d6 ++#define BCM43568_D11AC2G_ID 0x43d7 ++#define BCM43568_D11AC5G_ID 0x43d8 ++ ++#define BCM43569_D11AC_ID 0x43d9 ++#define BCM43569_D11AC2G_ID 0x43da ++#define BCM43569_D11AC5G_ID 0x43db ++ ++#define BCM43570_D11AC_ID 0x43d9 ++#define BCM43570_D11AC2G_ID 0x43da ++#define BCM43570_D11AC5G_ID 0x43db ++ ++#define BCM4354_D11AC_ID 0x43df /* 4354 802.11ac dualband device */ ++#define BCM4354_D11AC2G_ID 0x43e0 /* 4354 802.11ac 2.4G device */ ++#define BCM4354_D11AC5G_ID 0x43e1 /* 4354 802.11ac 5G device */ ++#define BCM43430_D11N2G_ID 0x43e2 /* 43430 802.11n 2.4G device */ ++#define BCM43018_D11N2G_ID 0x441b /* 43018 802.11n 2.4G device */ ++ ++ ++#define BCM4347_D11AC_ID 0x440a /* 4347 802.11ac dualband device */ ++#define BCM4347_D11AC2G_ID 0x440b /* 4347 802.11ac 2.4G device */ ++#define BCM4347_D11AC5G_ID 0x440c /* 4347 802.11ac 5G device */ ++ ++#define BCM4361_D11AC_ID 0x441f /* 4361 802.11ac dualband device */ ++#define BCM4361_D11AC2G_ID 0x4420 /* 4361 802.11ac 2.4G device */ ++#define BCM4361_D11AC5G_ID 0x4421 /* 4361 802.11ac 5G device */ ++ ++#define BCM4362_D11AX_ID 0x4490 /* 4362 802.11ax dualband device */ ++#define BCM4362_D11AX2G_ID 0x4491 /* 4362 802.11ax 2.4G device */ ++#define BCM4362_D11AX5G_ID 0x4492 /* 4362 802.11ax 5G device */ ++ ++#define BCM4364_D11AC_ID 0x4464 /* 4364 802.11ac dualband device */ ++#define BCM4364_D11AC2G_ID 0x446a /* 4364 802.11ac 2.4G device */ ++#define BCM4364_D11AC5G_ID 0x446b /* 4364 802.11ac 5G device */ ++ ++#define BCM4365_D11AC_ID 0x43ca ++#define BCM4365_D11AC2G_ID 0x43cb ++#define BCM4365_D11AC5G_ID 0x43cc ++ ++#define BCM4366_D11AC_ID 0x43c3 ++#define BCM4366_D11AC2G_ID 0x43c4 ++#define BCM4366_D11AC5G_ID 0x43c5 ++ ++#define BCM43349_D11N_ID 0x43e6 /* 43349 802.11n dualband id */ ++#define BCM43349_D11N2G_ID 0x43e7 /* 43349 802.11n 2.4Ghz band id */ ++#define BCM43349_D11N5G_ID 0x43e8 /* 43349 802.11n 5Ghz band id */ ++ ++#define BCM4358_D11AC_ID 0x43e9 /* 4358 802.11ac dualband device */ ++#define BCM4358_D11AC2G_ID 0x43ea /* 4358 802.11ac 2.4G device */ ++#define BCM4358_D11AC5G_ID 0x43eb /* 4358 802.11ac 5G device */ ++ ++#define BCM4356_D11AC_ID 0x43ec /* 4356 802.11ac dualband device */ ++#define BCM4356_D11AC2G_ID 0x43ed /* 4356 802.11ac 2.4G device */ ++#define BCM4356_D11AC5G_ID 0x43ee /* 4356 802.11ac 5G device */ ++ ++#define BCM4371_D11AC_ID 0x440d /* 4371 802.11ac dualband device */ ++#define BCM4371_D11AC2G_ID 0x440e /* 4371 802.11ac 2.4G device */ ++#define BCM4371_D11AC5G_ID 0x440f /* 4371 802.11ac 5G device */ ++#define BCM7271_D11AC_ID 0x4410 /* 7271 802.11ac dualband device */ ++#define BCM7271_D11AC2G_ID 0x4411 /* 7271 802.11ac 2.4G device */ ++#define BCM7271_D11AC5G_ID 0x4412 /* 7271 802.11ac 5G device */ ++ ++#define BCM4373_D11AC_ID 0x4418 /* 4373 802.11ac dualband device */ ++#define BCM4373_D11AC2G_ID 0x4419 /* 4373 802.11ac 2.4G device */ ++#define BCM4373_D11AC5G_ID 0x441a /* 4373 802.11ac 5G device */ ++ ++#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */ ++#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */ ++#define FPGA_JTAGM_ID 0x43f0 /* FPGA jtagm device id */ ++#define BCM_JTAGM_ID 0x43f1 /* BCM jtagm device id */ ++#define SDIOH_FPGA_ID 0x43f2 /* sdio host fpga */ ++#define BCM_SDIOH_ID 0x43f3 /* BCM sdio host id */ ++#define SDIOD_FPGA_ID 0x43f4 /* sdio device fpga */ ++#define SPIH_FPGA_ID 0x43f5 /* PCI SPI Host Controller FPGA */ ++#define BCM_SPIH_ID 0x43f6 /* Synopsis SPI Host Controller */ ++#define MIMO_FPGA_ID 0x43f8 /* FPGA mimo minimacphy device id */ ++#define BCM_JTAGM2_ID 0x43f9 /* BCM alternate jtagm device id */ ++#define SDHCI_FPGA_ID 0x43fa /* Standard SDIO Host Controller FPGA */ ++#define BCM4402_ENET_ID 0x4402 /* 4402 enet */ ++#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */ ++#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */ ++#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */ ++#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */ ++#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */ ++#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */ ++#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */ ++#define BCM47XX_AUDIO_ID 0x4711 /* 47xx audio codec */ ++#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */ ++#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */ ++#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */ ++#define BCM47XX_GMAC_ID 0x4715 /* 47xx Unimac based GbE */ ++#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */ ++#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */ ++#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */ ++#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */ ++#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */ ++#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */ ++#define BCM47XX_ATA100_ID 0x471d /* 47xx parallel ATA */ ++#define BCM47XX_SATAXOR_ID 0x471e /* 47xx serial ATA & XOR DMA */ ++#define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */ ++#ifdef DEPRECATED /* These products have been deprecated */ ++#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */ ++#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */ ++#endif /* DEPRECATED */ ++#define BCM47XX_USB30H_ID 0x472a /* 47xx usb 3.0 host */ ++#define BCM47XX_USB30D_ID 0x472b /* 47xx usb 3.0 device */ ++#define BCM47XX_USBHUB_ID 0x472c /* 47xx usb hub */ ++#define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */ ++#define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */ ++#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */ ++#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */ ++#define JINVANI_SDIOH_ID 0x4743 /* Jinvani SDIO Gold Host */ ++#define BCM27XX_SDIOH_ID 0x2702 /* BCM27xx Standard SDIO Host */ ++#define PCIXX21_FLASHMEDIA_ID 0x803b /* TI PCI xx21 Standard Host Controller */ ++#define PCIXX21_SDIOH_ID 0x803c /* TI PCI xx21 Standard Host Controller */ ++#define R5C822_SDIOH_ID 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */ ++#define JMICRON_SDIOH_ID 0x2381 /* JMicron Standard SDIO Host Controller */ ++ ++#define BCM43452_D11AC_ID 0x47ab /* 43452 802.11ac dualband device */ ++#define BCM43452_D11AC2G_ID 0x47ac /* 43452 802.11ac 2.4G device */ ++#define BCM43452_D11AC5G_ID 0x47ad /* 43452 802.11ac 5G device */ ++ ++/* Chip IDs */ ++#ifdef DEPRECATED /* These products have been deprecated */ ++#define BCM4306_CHIP_ID 0x4306 /* 4306 chipcommon chipid */ ++#define BCM4311_CHIP_ID 0x4311 /* 4311 PCIe 802.11a/b/g */ ++#define BCM43111_CHIP_ID 43111 /* 43111 chipcommon chipid (OTP chipid) */ ++#define BCM43112_CHIP_ID 43112 /* 43112 chipcommon chipid (OTP chipid) */ ++#define BCM4312_CHIP_ID 0x4312 /* 4312 chipcommon chipid */ ++#define BCM4315_CHIP_ID 0x4315 /* 4315 chip id */ ++#define BCM4318_CHIP_ID 0x4318 /* 4318 chipcommon chipid */ ++#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */ ++#define BCM4320_CHIP_ID 0x4320 /* 4320 chipcommon chipid */ ++#define BCM4321_CHIP_ID 0x4321 /* 4321 chipcommon chipid */ ++#define BCM4322_CHIP_ID 0x4322 /* 4322 chipcommon chipid */ ++#define BCM43221_CHIP_ID 43221 /* 43221 chipcommon chipid (OTP chipid) */ ++#define BCM43222_CHIP_ID 43222 /* 43222 chipcommon chipid */ ++#define BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */ ++#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (OTP chipid) */ ++#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */ ++#define BCM4325_CHIP_ID 0x4325 /* 4325 chip id */ ++#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */ ++#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */ ++#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */ ++#endif /* DEPRECATED */ ++ ++/* DEPRECATED but still referenced in components - start */ ++#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */ ++#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */ ++#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */ ++#define BCM5354_CHIP_ID 0x5354 /* 5354 chipcommon chipid */ ++/* DEPRECATED but still referenced in components - end */ ++ ++#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */ ++#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */ ++#define BCM43227_CHIP_ID 43227 /* 43227 chipcommon chipid */ ++#define BCM43228_CHIP_ID 43228 /* 43228 chipcommon chipid */ ++#define BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP chipid) */ ++#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */ ++#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP chipid) */ ++#define BCM43234_CHIP_ID 43234 /* 43234 chipcommon chipid */ ++#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ ++#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ ++#define BCM43237_CHIP_ID 43237 /* 43237 chipcommon chipid */ ++#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ ++#define BCM43239_CHIP_ID 43239 /* 43239 chipcommon chipid */ ++#define BCM43420_CHIP_ID 43420 /* 43222 chipcommon chipid (OTP, RBBU) */ ++#define BCM43421_CHIP_ID 43421 /* 43224 chipcommon chipid (OTP, RBBU) */ ++#define BCM43428_CHIP_ID 43428 /* 43228 chipcommon chipid (OTP, RBBU) */ ++#define BCM43431_CHIP_ID 43431 /* 4331 chipcommon chipid (OTP, RBBU) */ ++#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */ ++#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */ ++#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */ ++#define BCM43362_CHIP_ID 43362 /* 43362 chipcommon chipid */ ++#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ ++#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ ++#define BCM4314_CHIP_ID 0x4314 /* 4314 chipcommon chipid */ ++#define BCM43142_CHIP_ID 43142 /* 43142 chipcommon chipid */ ++#define BCM43143_CHIP_ID 43143 /* 43143 chipcommon chipid */ ++#define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */ ++#define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */ ++#define BCM43243_CHIP_ID 43243 /* 43243 chipcommon chipid */ ++#define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */ ++#define BCM4335_CHIP_ID 0x4335 /* 4335 chipcommon chipid */ ++#define BCM4339_CHIP_ID 0x4339 /* 4339 chipcommon chipid */ ++#define BCM43349_CHIP_ID 43349 /* 43349(0xA955) chipcommon chipid */ ++#define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */ ++#define BCM4364_CHIP_ID 0x4364 /* 4364 chipcommon chipid */ ++#define BCM4352_CHIP_ID 0x4352 /* 4352 chipcommon chipid */ ++#define BCM43526_CHIP_ID 0xAA06 ++#define BCM43340_CHIP_ID 43340 /* 43340 chipcommon chipid */ ++#define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */ ++#define BCM43342_CHIP_ID 43342 /* 43342 chipcommon chipid */ ++#define BCM4350_CHIP_ID 0x4350 /* 4350 chipcommon chipid */ ++#define BCM4354_CHIP_ID 0x4354 /* 4354 chipcommon chipid */ ++#define BCM4356_CHIP_ID 0x4356 /* 4356 chipcommon chipid */ ++#define BCM4371_CHIP_ID 0x4371 /* 4371 chipcommon chipid */ ++#define BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */ ++#define BCM43558_CHIP_ID 0xAA26 /* 43558 chipcommon chipid */ ++#define BCM43562_CHIP_ID 0xAA2A /* 43562 chipcommon chipid */ ++#define BCM43566_CHIP_ID 0xAA2E /* 43566 chipcommon chipid */ ++#define BCM43567_CHIP_ID 0xAA2F /* 43567 chipcommon chipid */ ++#define BCM43568_CHIP_ID 0xAA30 /* 43568 chipcommon chipid */ ++#define BCM43569_CHIP_ID 0xAA31 /* 43569 chipcommon chipid */ ++#define BCM43570_CHIP_ID 0xAA32 /* 43570 chipcommon chipid */ ++#define BCM4358_CHIP_ID 0x4358 /* 4358 chipcommon chipid */ ++#define BCM4371_CHIP_ID 0x4371 /* 4371 chipcommon chipid */ ++#define BCM43012_CHIP_ID 0xA804 /* 43012 chipcommon chipid */ ++#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM4354_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM43556_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM43558_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM43566_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM43567_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM43568_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM43569_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM43570_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM4358_CHIP_ID)) /* 4350 variations */ ++ ++#define BCM4345_CHIP_ID 0x4345 /* 4345 chipcommon chipid */ ++#define BCM43454_CHIP_ID 43454 /* 43454 chipcommon chipid */ ++#define BCM43455_CHIP_ID 43455 /* 43455 chipcommon chipid */ ++#define BCM43457_CHIP_ID 43457 /* 43457 chipcommon chipid */ ++#define BCM43458_CHIP_ID 43458 /* 43458 chipcommon chipid */ ++ ++#define BCM4345_CHIP(chipid) (CHIPID(chipid) == BCM4345_CHIP_ID || \ ++ CHIPID(chipid) == BCM43454_CHIP_ID || \ ++ CHIPID(chipid) == BCM43455_CHIP_ID || \ ++ CHIPID(chipid) == BCM43457_CHIP_ID || \ ++ CHIPID(chipid) == BCM43458_CHIP_ID) ++ ++#define CASE_BCM4345_CHIP case BCM4345_CHIP_ID: /* fallthrough */ \ ++ case BCM43454_CHIP_ID: /* fallthrough */ \ ++ case BCM43455_CHIP_ID: /* fallthrough */ \ ++ case BCM43457_CHIP_ID: /* fallthrough */ \ ++ case BCM43458_CHIP_ID ++ ++#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */ ++#define BCM43018_CHIP_ID 43018 /* 43018 chipcommon chipid */ ++#define BCM4349_CHIP_ID 0x4349 /* 4349 chipcommon chipid */ ++#define BCM4355_CHIP_ID 0x4355 /* 4355 chipcommon chipid */ ++#define BCM4359_CHIP_ID 0x4359 /* 4359 chipcommon chipid */ ++#define BCM4349_CHIP(chipid) ((CHIPID(chipid) == BCM4349_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM4355_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM4359_CHIP_ID)) ++#define BCM4349_CHIP_GRPID BCM4349_CHIP_ID: \ ++ case BCM4355_CHIP_ID: \ ++ case BCM4359_CHIP_ID ++#define BCM43596_CHIP_ID 43596 /* 43596 chipcommon chipid */ ++#define BCM4347_CHIP_ID 0x4347 /* 4347 chipcommon chipid */ ++#define BCM4357_CHIP_ID 0x4357 /* 4357 chipcommon chipid */ ++#define BCM4361_CHIP_ID 0x4361 /* 4361 chipcommon chipid */ ++#define BCM4362_CHIP_ID 0x4362 /* 4362 chipcommon chipid */ ++#define BCM4347_CHIP(chipid) ((CHIPID(chipid) == BCM4347_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM4357_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM4361_CHIP_ID)) ++#define BCM4347_CHIP_GRPID BCM4347_CHIP_ID: \ ++ case BCM4357_CHIP_ID: \ ++ case BCM4361_CHIP_ID ++ ++#define BCM4365_CHIP_ID 0x4365 /* 4365 chipcommon chipid */ ++#define BCM4366_CHIP_ID 0x4366 /* 4366 chipcommon chipid */ ++#define BCM4365_CHIP(chipid) ((CHIPID(chipid) == BCM4365_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM4366_CHIP_ID)) ++ ++ ++#define BCM43909_CHIP_ID 0xab85 /* 43909 chipcommon chipid */ ++ ++#define BCM43602_CHIP_ID 0xaa52 /* 43602 chipcommon chipid */ ++#define BCM43462_CHIP_ID 0xa9c6 /* 43462 chipcommon chipid */ ++#define BCM43522_CHIP_ID 0xaa02 /* 43522 chipcommon chipid */ ++#define BCM43602_CHIP(chipid) ((CHIPID(chipid) == BCM43602_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM43462_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM43522_CHIP_ID)) /* 43602 variations */ ++#define BCM43012_CHIP(chipid) (CHIPID(chipid) == BCM43012_CHIP_ID) ++#define CASE_BCM43602_CHIP case BCM43602_CHIP_ID: /* fallthrough */ \ ++ case BCM43462_CHIP_ID: /* fallthrough */ \ ++ case BCM43522_CHIP_ID ++ ++#define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */ ++#define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */ ++#define BCM4706_CHIP_ID 0x5300 /* 4706 chipcommon chipid */ ++#define BCM4707_CHIP_ID 53010 /* 4707 chipcommon chipid */ ++#define BCM47094_CHIP_ID 53030 /* 47094 chipcommon chipid */ ++#define BCM53018_CHIP_ID 53018 /* 53018 chipcommon chipid */ ++#define BCM4707_CHIP(chipid) (((chipid) == BCM4707_CHIP_ID) || \ ++ ((chipid) == BCM53018_CHIP_ID) || \ ++ ((chipid) == BCM47094_CHIP_ID)) ++#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */ ++#define BCM4749_CHIP_ID 0x4749 /* 5357 chipcommon chipid (OTP, RBBU) */ ++#define BCM4785_CHIP_ID 0x4785 /* 4785 chipcommon chipid */ ++#define BCM5350_CHIP_ID 0x5350 /* 5350 chipcommon chipid */ ++#define BCM5352_CHIP_ID 0x5352 /* 5352 chipcommon chipid */ ++#define BCM5365_CHIP_ID 0x5365 /* 5365 chipcommon chipid */ ++#define BCM5356_CHIP_ID 0x5356 /* 5356 chipcommon chipid */ ++#define BCM5357_CHIP_ID 0x5357 /* 5357 chipcommon chipid */ ++#define BCM53572_CHIP_ID 53572 /* 53572 chipcommon chipid */ ++#define BCM53573_CHIP_ID 53573 /* 53573 chipcommon chipid */ ++#define BCM53574_CHIP_ID 53574 /* 53574 chipcommon chipid */ ++#define BCM53573_CHIP(chipid) ((CHIPID(chipid) == BCM53573_CHIP_ID) || \ ++ (CHIPID(chipid) == BCM53574_CHIP_ID)) ++#define BCM53573_CHIP_GRPID BCM53573_CHIP_ID : \ ++ case BCM53574_CHIP_ID ++#define BCM53573_DEVICE(devid) (((devid) == BCM53573_D11AC_ID) || \ ++ ((devid) == BCM53573_D11AC2G_ID) || \ ++ ((devid) == BCM53573_D11AC5G_ID) || \ ++ ((devid) == BCM47189_D11AC_ID) || \ ++ ((devid) == BCM47189_D11AC2G_ID) || \ ++ ((devid) == BCM47189_D11AC5G_ID)) ++ ++#define BCM7271_CHIP_ID 0x05c9 /* 7271 chipcommon chipid */ ++#define BCM4373_CHIP_ID 0x4373 /* 4373 chipcommon chipid */ ++ ++/* Package IDs */ ++#ifdef DEPRECATED /* These products have been deprecated */ ++#define BCM4303_PKG_ID 2 /* 4303 package id */ ++#define BCM4309_PKG_ID 1 /* 4309 package id */ ++#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */ ++#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */ ++#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */ ++#define BCM4328USBD11G_PKG_ID 2 /* 4328 802.11g USB package id */ ++#define BCM4328USBDUAL_PKG_ID 3 /* 4328 802.11a/g USB package id */ ++#define BCM4328SDIOD11G_PKG_ID 4 /* 4328 802.11g SDIO package id */ ++#define BCM4328SDIODUAL_PKG_ID 5 /* 4328 802.11a/g SDIO package id */ ++#define BCM4329_289PIN_PKG_ID 0 /* 4329 289-pin package id */ ++#define BCM4329_182PIN_PKG_ID 1 /* 4329N 182-pin package id */ ++#define BCM5354E_PKG_ID 1 /* 5354E package id */ ++#define BCM4716_PKG_ID 8 /* 4716 package id */ ++#define BCM4717_PKG_ID 9 /* 4717 package id */ ++#define BCM4718_PKG_ID 10 /* 4718 package id */ ++#endif /* DEPRECATED */ ++#define BCM5356_PKG_NONMODE 1 /* 5356 package without nmode suppport */ ++#define BCM5358U_PKG_ID 8 /* 5358U package id */ ++#define BCM5358_PKG_ID 9 /* 5358 package id */ ++#define BCM47186_PKG_ID 10 /* 47186 package id */ ++#define BCM5357_PKG_ID 11 /* 5357 package id */ ++#define BCM5356U_PKG_ID 12 /* 5356U package id */ ++#define BCM53572_PKG_ID 8 /* 53572 package id */ ++#define BCM5357C0_PKG_ID 8 /* 5357c0 package id (the same as 53572) */ ++#define BCM47188_PKG_ID 9 /* 47188 package id */ ++#define BCM5358C0_PKG_ID 0xa /* 5358c0 package id */ ++#define BCM5356C0_PKG_ID 0xb /* 5356c0 package id */ ++#define BCM4331TT_PKG_ID 8 /* 4331 12x12 package id */ ++#define BCM4331TN_PKG_ID 9 /* 4331 12x9 package id */ ++#define BCM4331TNA0_PKG_ID 0xb /* 4331 12x9 package id */ ++#define BCM47189_PKG_ID 1 /* 47189 package id */ ++#define BCM53573_PKG_ID 0 /* 53573 package id */ ++#define BCM4706L_PKG_ID 1 /* 4706L package id */ ++ ++#define HDLSIM5350_PKG_ID 1 /* HDL simulator package id for a 5350 */ ++#define HDLSIM_PKG_ID 14 /* HDL simulator package id */ ++#define HWSIM_PKG_ID 15 /* Hardware simulator package id */ ++#define BCM43224_FAB_CSM 0x8 /* the chip is manufactured by CSM */ ++#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ ++#define BCM4336_WLBGA_PKG_ID 0x8 ++#define BCM4330_WLBGA_PKG_ID 0x0 ++#define BCM4314PCIE_ARM_PKG_ID (8 | 0) /* 4314 QFN PCI package id, bit 3 tie high */ ++#define BCM4314SDIO_PKG_ID (8 | 1) /* 4314 QFN SDIO package id */ ++#define BCM4314PCIE_PKG_ID (8 | 2) /* 4314 QFN PCI (ARM-less) package id */ ++#define BCM4314SDIO_ARM_PKG_ID (8 | 3) /* 4314 QFN SDIO (ARM-less) package id */ ++#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) /* 4314 FpBGA SDIO package id */ ++#define BCM4314DEV_PKG_ID (8 | 6) /* 4314 Developement package id */ ++ ++#define BCM4707_PKG_ID 1 /* 4707 package id */ ++#define BCM4708_PKG_ID 2 /* 4708 package id */ ++#define BCM4709_PKG_ID 0 /* 4709 package id */ ++ ++#define PCIXX21_FLASHMEDIA0_ID 0x8033 /* TI PCI xx21 Standard Host Controller */ ++#define PCIXX21_SDIOH0_ID 0x8034 /* TI PCI xx21 Standard Host Controller */ ++ ++#define BCM4335_WLCSP_PKG_ID (0x0) /* WLCSP Module/Mobile SDIO/HSIC. */ ++#define BCM4335_FCBGA_PKG_ID (0x1) /* FCBGA PC/Embeded/Media PCIE/SDIO */ ++#define BCM4335_WLBGA_PKG_ID (0x2) /* WLBGA COB/Mobile SDIO/HSIC. */ ++#define BCM4335_FCBGAD_PKG_ID (0x3) /* FCBGA Debug Debug/Dev All if's. */ ++#define BCM4335_PKG_MASK (0x3) ++#define BCM43602_12x12_PKG_ID (0x1) /* 12x12 pins package, used for e.g. router designs */ ++ ++/* boardflags */ ++#define BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */ ++#define BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */ ++#define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */ ++#define BFL_AIRLINEMODE 0x00000004 /* Board implements gpio radio disable indication */ ++#define BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */ ++#define BFL_DIS_256QAM 0x00000008 ++#define BFL_ENETROBO 0x00000010 /* Board has robo switch or core */ ++#define BFL_TSSIAVG 0x00000010 /* TSSI averaging for ACPHY chips */ ++#define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */ ++#define BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */ ++#define BFL_ENETADM 0x00000080 /* Board has ADMtek switch */ ++#define BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */ ++#define BFL_LTECOEX 0x00000200 /* LTE Coex enabled */ ++#define BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ ++#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_HGPA 0x00002000 /* Board has a high gain PA */ ++#define BFL_BTC2WIRE_ALTGPIO 0x00004000 /* Board's BTC 2wire is in the alternate gpios */ ++#define BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */ ++#define BFL_NOPA 0x00010000 /* Board has no PA */ ++#define BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */ ++#define BFL_PAREF 0x00040000 /* Board uses the PARef LDO */ ++#define BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */ ++#define BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */ ++#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_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */ ++#define BFL_PALDO 0x02000000 /* Power topology uses PALDO */ ++#define BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */ ++#define BFL_FASTPWR 0x08000000 ++#define BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */ ++#define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ ++#define BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */ ++#define BFL_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ ++#define BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */ ++#define BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field ++ * when this flag is set ++ */ ++#define BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */ ++ ++/* 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 */ ++#define BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */ ++#define BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */ ++#define BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace ++ * BFL2_BTC3WIRE ++ */ ++#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_TRISTATE_LED 0x00000800 /* Tri-state the LED */ ++#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_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */ ++#define BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */ ++#define BFL2_DAC_SPUR_IMPROVEMENT 0x00008000 /* Reducing DAC Spurs */ ++#define BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */ ++#define BFL2_REDUCED_PA_TURNONTIME 0x00010000 /* Flag to reduce PA turn on Time */ ++#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. */ ++ ++#define BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */ ++#define BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */ ++#define BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */ ++#define BFL2_BT_SHARE_ANT0 0x00800000 /* share core0 antenna with BT */ ++#define BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value ++ * than programmed. The exact delta is decided by ++ * driver per chip/boardtype. This can be used ++ * when tempsense qualification happens after shipment ++ */ ++#define BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */ ++#define BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */ ++#define BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save */ ++ /* ucode control of eLNA during Tx */ ++#define BFL2_4313_RADIOREG 0x10000000 ++ /* board rework */ ++#define BFL2_DYNAMIC_VMID 0x10000000 /* enable dynamic Vmid in idle TSSI CAL for 4331 */ ++ ++#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */ ++#define BFL2_DYNAMIC_VMID 0x10000000 /* boardflag to enable dynamic Vmid idle TSSI CAL */ ++#define BFL2_LNA1BYPFORTR2G 0x40000000 /* acphy, enable lna1 bypass for clip gain, 2g */ ++#define BFL2_LNA1BYPFORTR5G 0x80000000 /* acphy, enable lna1 bypass for clip gain, 5g */ ++ ++/* SROM 11 - 11ac boardflag definitions */ ++#define BFL_SROM11_BTCOEX 0x00000001 /* Board supports BTCOEX */ ++#define BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 /* bluetooth and wlan share same crystal */ ++#define BFL_SROM11_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ ++#define BFL_SROM11_EPA_TURNON_TIME 0x00018000 /* 2 bits for different PA turn on times */ ++#define BFL_SROM11_EPA_TURNON_TIME_SHIFT 15 ++#define BFL_SROM11_PRECAL_TX_IDX 0x00040000 /* Dedicated TX IQLOCAL IDX values */ ++ /* per subband, as derived from 43602A1 MCH5 */ ++#define BFL_SROM11_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ ++#define BFL_SROM11_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ ++#define BFL2_SROM11_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ ++#define BFL2_SROM11_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are ctrl-ed by analog PA ctrl lines */ ++#define BFL2_SROM11_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are ctrl-ed by analog PA ctrl lines */ ++#define BFL2_SROM11_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ ++#define BFL2_SROM11_EPA_ON_DURING_TXIQLOCAL 0x00020000 /* Keep ext. PA's on in TX IQLO CAL */ ++ ++/* boardflags3 */ ++#define BFL3_FEMCTRL_SUB 0x00000007 /* acphy, subrevs of femctrl on top of srom_femctrl */ ++#define BFL3_RCAL_WAR 0x00000008 /* acphy, rcal war active on this board (4335a0) */ ++#define BFL3_TXGAINTBLID 0x00000070 /* acphy, txgain table id */ ++#define BFL3_TXGAINTBLID_SHIFT 0x4 /* acphy, txgain table id shift bit */ ++#define BFL3_TSSI_DIV_WAR 0x00000080 /* acphy, Seperate paparam for 20/40/80 */ ++#define BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Seperate paparam for 20/40/80 shift bit */ ++#define BFL3_FEMTBL_FROM_NVRAM 0x00000100 /* acphy, femctrl table is read from nvram */ ++#define BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 /* acphy, femctrl table is read from nvram */ ++#define BFL3_AGC_CFG_2G 0x00000200 /* acphy, gain control configuration for 2G */ ++#define BFL3_AGC_CFG_5G 0x00000400 /* acphy, gain control configuration for 5G */ ++#define BFL3_PPR_BIT_EXT 0x00000800 /* acphy, bit position for 1bit extension for ppr */ ++#define BFL3_PPR_BIT_EXT_SHIFT 11 /* acphy, bit shift for 1bit extension for ppr */ ++#define BFL3_BBPLL_SPR_MODE_DIS 0x00001000 /* acphy, disables bbpll spur modes */ ++#define BFL3_RCAL_OTP_VAL_EN 0x00002000 /* acphy, to read rcal_trim value from otp */ ++#define BFL3_2GTXGAINTBL_BLANK 0x00004000 /* acphy, blank the first X ticks of 2g gaintbl */ ++#define BFL3_2GTXGAINTBL_BLANK_SHIFT 14 /* acphy, blank the first X ticks of 2g gaintbl */ ++#define BFL3_5GTXGAINTBL_BLANK 0x00008000 /* acphy, blank the first X ticks of 5g gaintbl */ ++#define BFL3_5GTXGAINTBL_BLANK_SHIFT 15 /* acphy, blank the first X ticks of 5g gaintbl */ ++#define BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 /* acphy, to max out alpha,beta to 511 */ ++#define BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 /* acphy, to max out alpha,beta to 511 */ ++/* acphy, to use backed off gaintbl for lte-coex */ ++#define BFL3_LTECOEX_GAINTBL_EN 0x00060000 ++/* acphy, to use backed off gaintbl for lte-coex */ ++#define BFL3_LTECOEX_GAINTBL_EN_SHIFT 17 ++#define BFL3_5G_SPUR_WAR 0x00080000 /* acphy, enable spur WAR in 5G band */ ++#define BFL3_1X1_RSDB_ANT 0x01000000 /* to find if 2-ant RSDB board or 1-ant RSDB board */ ++#define BFL3_1X1_RSDB_ANT_SHIFT 24 ++ ++/* acphy: lpmode2g and lpmode_5g related boardflags */ ++#define BFL3_ACPHY_LPMODE_2G 0x00300000 /* bits 20:21 for lpmode_2g choice */ ++#define BFL3_ACPHY_LPMODE_2G_SHIFT 20 ++ ++#define BFL3_ACPHY_LPMODE_5G 0x00C00000 /* bits 22:23 for lpmode_5g choice */ ++#define BFL3_ACPHY_LPMODE_5G_SHIFT 22 ++ ++#define BFL3_EXT_LPO_ISCLOCK 0x02000000 /* External LPO is clock, not x-tal */ ++#define BFL3_FORCE_INT_LPO_SEL 0x04000000 /* Force internal lpo */ ++#define BFL3_FORCE_EXT_LPO_SEL 0x08000000 /* Force external lpo */ ++ ++#define BFL3_EN_BRCM_IMPBF 0x10000000 /* acphy, Allow BRCM Implicit TxBF */ ++#define BFL3_AVVMID_FROM_NVRAM 0x40000000 /* Read Av Vmid from NVRAM */ ++#define BFL3_VLIN_EN_FROM_NVRAM 0x80000000 /* Read Vlin En from NVRAM */ ++ ++#define BFL3_AVVMID_FROM_NVRAM_SHIFT 30 /* Read Av Vmid from NVRAM */ ++#define BFL3_VLIN_EN_FROM_NVRAM_SHIFT 31 /* Enable Vlin from NVRAM */ ++ ++/* boardflags4 for SROM12 */ ++#define BFL4_SROM12_4dBPAD (1 << 0) /* To distinguigh between normal and 4dB pad board */ ++#define BFL4_SROM12_2G_DETTYPE (1 << 1) /* Determine power detector type for 2G */ ++#define BFL4_SROM12_5G_DETTYPE (1 << 2) /* Determine power detector type for 5G */ ++#define BFL4_4364_HARPOON 0x0100 /* Harpoon module 4364 */ ++#define BFL4_4364_GODZILLA 0x0200 /* Godzilla module 4364 */ ++ ++ ++/* papd params */ ++#define PAPD_TX_ATTN_2G 0xFF ++#define PAPD_TX_ATTN_5G 0xFF00 ++#define PAPD_TX_ATTN_5G_SHIFT 8 ++#define PAPD_RX_ATTN_2G 0xFF ++#define PAPD_RX_ATTN_5G 0xFF00 ++#define PAPD_RX_ATTN_5G_SHIFT 8 ++#define PAPD_CAL_IDX_2G 0xFF ++#define PAPD_CAL_IDX_5G 0xFF00 ++#define PAPD_CAL_IDX_5G_SHIFT 8 ++#define PAPD_BBMULT_2G 0xFF ++#define PAPD_BBMULT_5G 0xFF00 ++#define PAPD_BBMULT_5G_SHIFT 8 ++#define TIA_GAIN_MODE_2G 0xFF ++#define TIA_GAIN_MODE_5G 0xFF00 ++#define TIA_GAIN_MODE_5G_SHIFT 8 ++#define PAPD_EPS_OFFSET_2G 0xFFFF ++#define PAPD_EPS_OFFSET_5G 0xFFFF0000 ++#define PAPD_EPS_OFFSET_5G_SHIFT 16 ++#define PAPD_CALREF_DB_2G 0xFF ++#define PAPD_CALREF_DB_5G 0xFF00 ++#define PAPD_CALREF_DB_5G_SHIFT 8 ++ ++ ++/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */ ++#define BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */ ++#define BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */ ++#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */ ++#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */ ++#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */ ++#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */ ++#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 */ ++#define BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */ ++#define BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */ ++#define BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */ ++#define BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */ ++#define BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */ ++#define BOARD_GPIO_2_WLAN_PWR 0x04 /* throttle WLAN power on X29C board */ ++#define BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */ ++#define BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */ ++#define BOARD_GPIO_13_WLAN_PWR 0x2000 /* throttle WLAN power on X14 board */ ++ ++#define GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_43224 0x020 /* bit 5 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 /* bit 5 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_43225 0x0e0 /* bit 5 BT_IODISABLE, bit 6 SW_BT, bit 7 SW_WL */ ++#define GPIO_BTC4W_OUT_43421 0x020 /* bit 5 is BT_IODISABLE */ ++#define GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */ ++#define GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */ ++ ++#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ ++#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */ ++#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 */ ++ ++/* power control defines */ ++#define PLL_DELAY 150 /* us pll on delay */ ++#define FREF_DELAY 200 /* us fref change delay */ ++#define MIN_SLOW_CLK 32 /* us Slow clock period */ ++#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */ ++ ++ ++/* 43341 Boards */ ++#define BCM943341WLABGS_SSID 0x062d ++ ++/* 43342 Boards */ ++#define BCM943342FCAGBI_SSID 0x0641 ++ ++/* 43012 wlbga Board */ ++#define BCM943012WLREF_SSID 0x07d7 ++ ++/* 43012 fcbga Board */ ++#define BCM943012FCREF_SSID 0x07d4 ++ ++/* 43602 Boards, unclear yet what boards will be created. */ ++#define BCM943602RSVD1_SSID 0x06a5 ++#define BCM943602RSVD2_SSID 0x06a6 ++#define BCM943602X87 0X0133 ++#define BCM943602X87P2 0X0152 ++#define BCM943602X87P3 0X0153 ++#define BCM943602X238 0X0132 ++#define BCM943602X238D 0X014A ++#define BCM943602X238DP2 0X0155 ++#define BCM943602X238DP3 0X0156 ++#define BCM943602X100 0x0761 ++#define BCM943602X100GS 0x0157 ++#define BCM943602X100P2 0x015A ++ ++/* # of GPIO pins */ ++#define GPIO_NUMPINS 32 ++ ++/* These values are used by dhd host driver. */ ++#define RDL_RAM_BASE_4319 0x60000000 ++#define RDL_RAM_BASE_4329 0x60000000 ++#define RDL_RAM_SIZE_4319 0x48000 ++#define RDL_RAM_SIZE_4329 0x48000 ++#define RDL_RAM_SIZE_43236 0x70000 ++#define RDL_RAM_BASE_43236 0x60000000 ++#define RDL_RAM_SIZE_4328 0x60000 ++#define RDL_RAM_BASE_4328 0x80000000 ++#define RDL_RAM_SIZE_4322 0x60000 ++#define RDL_RAM_BASE_4322 0x60000000 ++#define RDL_RAM_SIZE_4360 0xA0000 ++#define RDL_RAM_BASE_4360 0x60000000 ++#define RDL_RAM_SIZE_43242 0x90000 ++#define RDL_RAM_BASE_43242 0x60000000 ++#define RDL_RAM_SIZE_43143 0x70000 ++#define RDL_RAM_BASE_43143 0x60000000 ++#define RDL_RAM_SIZE_4350 0xC0000 ++#define RDL_RAM_BASE_4350 0x180800 ++ ++/* generic defs for nvram "muxenab" bits ++* Note: these differ for 4335a0. refer bcmchipc.h for specific mux options. ++*/ ++#define MUXENAB_UART 0x00000001 ++#define MUXENAB_GPIO 0x00000002 ++#define MUXENAB_ERCX 0x00000004 /* External Radio BT coex */ ++#define MUXENAB_JTAG 0x00000008 ++#define MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */ ++#define MUXENAB_I2S_EN 0x00000020 ++#define MUXENAB_I2S_MASTER 0x00000040 ++#define MUXENAB_I2S_FULL 0x00000080 ++#define MUXENAB_SFLASH 0x00000100 ++#define MUXENAB_RFSWCTRL0 0x00000200 ++#define MUXENAB_RFSWCTRL1 0x00000400 ++#define MUXENAB_RFSWCTRL2 0x00000800 ++#define MUXENAB_SECI 0x00001000 ++#define MUXENAB_BT_LEGACY 0x00002000 ++#define MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */ ++ ++/* Boot flags */ ++#define FLASH_KERNEL_NFLASH 0x00000001 ++#define FLASH_BOOT_NFLASH 0x00000002 ++ ++#endif /* _BCMDEVS_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmdhcp.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmdhcp.h +new file mode 100644 +index 000000000..f3e1b08ed +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmdhcp.h +@@ -0,0 +1,92 @@ ++/* ++ * Fundamental constants relating to DHCP Protocol ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmdhcp.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _bcmdhcp_h_ ++#define _bcmdhcp_h_ ++ ++/* DHCP params */ ++#define DHCP_TYPE_OFFSET 0 /* DHCP type (request|reply) offset */ ++#define DHCP_TID_OFFSET 4 /* DHCP transition id offset */ ++#define DHCP_FLAGS_OFFSET 10 /* DHCP flags offset */ ++#define DHCP_CIADDR_OFFSET 12 /* DHCP client IP address offset */ ++#define DHCP_YIADDR_OFFSET 16 /* DHCP your IP address offset */ ++#define DHCP_GIADDR_OFFSET 24 /* DHCP relay agent IP address offset */ ++#define DHCP_CHADDR_OFFSET 28 /* DHCP client h/w address offset */ ++#define DHCP_OPT_OFFSET 236 /* DHCP options offset */ ++ ++#define DHCP_OPT_MSGTYPE 53 /* DHCP message type */ ++#define DHCP_OPT_MSGTYPE_REQ 3 ++#define DHCP_OPT_MSGTYPE_ACK 5 /* DHCP message type - ACK */ ++ ++#define DHCP_OPT_CODE_OFFSET 0 /* Option identifier */ ++#define DHCP_OPT_LEN_OFFSET 1 /* Option data length */ ++#define DHCP_OPT_DATA_OFFSET 2 /* Option data */ ++ ++#define DHCP_OPT_CODE_CLIENTID 61 /* Option identifier */ ++ ++#define DHCP_TYPE_REQUEST 1 /* DHCP request (discover|request) */ ++#define DHCP_TYPE_REPLY 2 /* DHCP reply (offset|ack) */ ++ ++#define DHCP_PORT_SERVER 67 /* DHCP server UDP port */ ++#define DHCP_PORT_CLIENT 68 /* DHCP client UDP port */ ++ ++#define DHCP_FLAG_BCAST 0x8000 /* DHCP broadcast flag */ ++ ++#define DHCP_FLAGS_LEN 2 /* DHCP flags field length */ ++ ++#define DHCP6_TYPE_SOLICIT 1 /* DHCP6 solicit */ ++#define DHCP6_TYPE_ADVERTISE 2 /* DHCP6 advertise */ ++#define DHCP6_TYPE_REQUEST 3 /* DHCP6 request */ ++#define DHCP6_TYPE_CONFIRM 4 /* DHCP6 confirm */ ++#define DHCP6_TYPE_RENEW 5 /* DHCP6 renew */ ++#define DHCP6_TYPE_REBIND 6 /* DHCP6 rebind */ ++#define DHCP6_TYPE_REPLY 7 /* DHCP6 reply */ ++#define DHCP6_TYPE_RELEASE 8 /* DHCP6 release */ ++#define DHCP6_TYPE_DECLINE 9 /* DHCP6 decline */ ++#define DHCP6_TYPE_RECONFIGURE 10 /* DHCP6 reconfigure */ ++#define DHCP6_TYPE_INFOREQ 11 /* DHCP6 information request */ ++#define DHCP6_TYPE_RELAYFWD 12 /* DHCP6 relay forward */ ++#define DHCP6_TYPE_RELAYREPLY 13 /* DHCP6 relay reply */ ++ ++#define DHCP6_TYPE_OFFSET 0 /* DHCP6 type offset */ ++ ++#define DHCP6_MSG_OPT_OFFSET 4 /* Offset of options in client server messages */ ++#define DHCP6_RELAY_OPT_OFFSET 34 /* Offset of options in relay messages */ ++ ++#define DHCP6_OPT_CODE_OFFSET 0 /* Option identifier */ ++#define DHCP6_OPT_LEN_OFFSET 2 /* Option data length */ ++#define DHCP6_OPT_DATA_OFFSET 4 /* Option data */ ++ ++#define DHCP6_OPT_CODE_CLIENTID 1 /* DHCP6 CLIENTID option */ ++#define DHCP6_OPT_CODE_SERVERID 2 /* DHCP6 SERVERID option */ ++ ++#define DHCP6_PORT_SERVER 547 /* DHCP6 server UDP port */ ++#define DHCP6_PORT_CLIENT 546 /* DHCP6 client UDP port */ ++ ++#endif /* #ifndef _bcmdhcp_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmendian.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmendian.h +new file mode 100644 +index 000000000..00adedf1c +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmendian.h +@@ -0,0 +1,332 @@ ++/* ++ * Byte order utilities ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmendian.h 514727 2014-11-12 03:02:48Z $ ++ * ++ * This file by default provides proper behavior on little-endian architectures. ++ * On big-endian architectures, IL_BIGENDIAN should be defined. ++ */ ++ ++#ifndef _BCMENDIAN_H_ ++#define _BCMENDIAN_H_ ++ ++#include ++ ++/* Reverse the bytes in a 16-bit value */ ++#define BCMSWAP16(val) \ ++ ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \ ++ (((uint16)(val) & (uint16)0xff00U) >> 8))) ++ ++/* Reverse the bytes in a 32-bit value */ ++#define BCMSWAP32(val) \ ++ ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \ ++ (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \ ++ (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \ ++ (((uint32)(val) & (uint32)0xff000000U) >> 24))) ++ ++/* Reverse the two 16-bit halves of a 32-bit value */ ++#define BCMSWAP32BY16(val) \ ++ ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \ ++ (((uint32)(val) & (uint32)0xffff0000U) >> 16))) ++ ++/* Reverse the bytes in a 64-bit value */ ++#define BCMSWAP64(val) \ ++ ((uint64)((((uint64)(val) & 0x00000000000000ffULL) << 56) | \ ++ (((uint64)(val) & 0x000000000000ff00ULL) << 40) | \ ++ (((uint64)(val) & 0x0000000000ff0000ULL) << 24) | \ ++ (((uint64)(val) & 0x00000000ff000000ULL) << 8) | \ ++ (((uint64)(val) & 0x000000ff00000000ULL) >> 8) | \ ++ (((uint64)(val) & 0x0000ff0000000000ULL) >> 24) | \ ++ (((uint64)(val) & 0x00ff000000000000ULL) >> 40) | \ ++ (((uint64)(val) & 0xff00000000000000ULL) >> 56))) ++ ++/* Reverse the two 32-bit halves of a 64-bit value */ ++#define BCMSWAP64BY32(val) \ ++ ((uint64)((((uint64)(val) & 0x00000000ffffffffULL) << 32) | \ ++ (((uint64)(val) & 0xffffffff00000000ULL) >> 32))) ++ ++ ++/* Byte swapping macros ++ * Host <=> Network (Big Endian) for 16- and 32-bit values ++ * Host <=> Little-Endian for 16- and 32-bit values ++ */ ++#ifndef hton16 ++#define HTON16(i) BCMSWAP16(i) ++#define hton16(i) bcmswap16(i) ++#define HTON32(i) BCMSWAP32(i) ++#define hton32(i) bcmswap32(i) ++#define NTOH16(i) BCMSWAP16(i) ++#define ntoh16(i) bcmswap16(i) ++#define NTOH32(i) BCMSWAP32(i) ++#define ntoh32(i) bcmswap32(i) ++#define LTOH16(i) (i) ++#define ltoh16(i) (i) ++#define LTOH32(i) (i) ++#define ltoh32(i) (i) ++#define HTOL16(i) (i) ++#define htol16(i) (i) ++#define HTOL32(i) (i) ++#define htol32(i) (i) ++#define HTOL64(i) (i) ++#define htol64(i) (i) ++#endif /* hton16 */ ++ ++#define ltoh16_buf(buf, i) ++#define htol16_buf(buf, i) ++ ++/* Unaligned loads and stores in host byte order */ ++#define load32_ua(a) ltoh32_ua(a) ++#define store32_ua(a, v) htol32_ua_store(v, a) ++#define load16_ua(a) ltoh16_ua(a) ++#define store16_ua(a, v) htol16_ua_store(v, a) ++ ++#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8)) ++#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24)) ++#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1]) ++#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3]) ++ ++#define ltoh_ua(ptr) \ ++ (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ ++ sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \ ++ sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \ ++ *(uint8 *)0) ++ ++#define ntoh_ua(ptr) \ ++ (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \ ++ sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \ ++ sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \ ++ *(uint8 *)0) ++ ++#ifdef __GNUC__ ++ ++/* GNU macro versions avoid referencing the argument multiple times, while also ++ * avoiding the -fno-inline used in ROM builds. ++ */ ++ ++#define bcmswap16(val) ({ \ ++ uint16 _val = (val); \ ++ BCMSWAP16(_val); \ ++}) ++ ++#define bcmswap32(val) ({ \ ++ uint32 _val = (val); \ ++ BCMSWAP32(_val); \ ++}) ++ ++#define bcmswap64(val) ({ \ ++ uint64 _val = (val); \ ++ BCMSWAP64(_val); \ ++}) ++ ++#define bcmswap32by16(val) ({ \ ++ uint32 _val = (val); \ ++ BCMSWAP32BY16(_val); \ ++}) ++ ++#define bcmswap16_buf(buf, len) ({ \ ++ uint16 *_buf = (uint16 *)(buf); \ ++ uint _wds = (len) / 2; \ ++ while (_wds--) { \ ++ *_buf = bcmswap16(*_buf); \ ++ _buf++; \ ++ } \ ++}) ++ ++#define htol16_ua_store(val, bytes) ({ \ ++ uint16 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val & 0xff; \ ++ _bytes[1] = _val >> 8; \ ++}) ++ ++#define htol32_ua_store(val, bytes) ({ \ ++ uint32 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val & 0xff; \ ++ _bytes[1] = (_val >> 8) & 0xff; \ ++ _bytes[2] = (_val >> 16) & 0xff; \ ++ _bytes[3] = _val >> 24; \ ++}) ++ ++#define hton16_ua_store(val, bytes) ({ \ ++ uint16 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val >> 8; \ ++ _bytes[1] = _val & 0xff; \ ++}) ++ ++#define hton32_ua_store(val, bytes) ({ \ ++ uint32 _val = (val); \ ++ uint8 *_bytes = (uint8 *)(bytes); \ ++ _bytes[0] = _val >> 24; \ ++ _bytes[1] = (_val >> 16) & 0xff; \ ++ _bytes[2] = (_val >> 8) & 0xff; \ ++ _bytes[3] = _val & 0xff; \ ++}) ++ ++#define ltoh16_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _LTOH16_UA(_bytes); \ ++}) ++ ++#define ltoh32_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _LTOH32_UA(_bytes); \ ++}) ++ ++#define ntoh16_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _NTOH16_UA(_bytes); \ ++}) ++ ++#define ntoh32_ua(bytes) ({ \ ++ const uint8 *_bytes = (const uint8 *)(bytes); \ ++ _NTOH32_UA(_bytes); \ ++}) ++ ++#else /* !__GNUC__ */ ++ ++/* Inline versions avoid referencing the argument multiple times */ ++static INLINE uint16 ++bcmswap16(uint16 val) ++{ ++ return BCMSWAP16(val); ++} ++ ++static INLINE uint32 ++bcmswap32(uint32 val) ++{ ++ return BCMSWAP32(val); ++} ++ ++static INLINE uint64 ++bcmswap64(uint64 val) ++{ ++ return BCMSWAP64(val); ++} ++ ++static INLINE uint32 ++bcmswap32by16(uint32 val) ++{ ++ return BCMSWAP32BY16(val); ++} ++ ++/* Reverse pairs of bytes in a buffer (not for high-performance use) */ ++/* buf - start of buffer of shorts to swap */ ++/* len - byte length of buffer */ ++static INLINE void ++bcmswap16_buf(uint16 *buf, uint len) ++{ ++ len = len / 2; ++ ++ while (len--) { ++ *buf = bcmswap16(*buf); ++ buf++; ++ } ++} ++ ++/* ++ * Store 16-bit value to unaligned little-endian byte array. ++ */ ++static INLINE void ++htol16_ua_store(uint16 val, uint8 *bytes) ++{ ++ bytes[0] = val & 0xff; ++ bytes[1] = val >> 8; ++} ++ ++/* ++ * Store 32-bit value to unaligned little-endian byte array. ++ */ ++static INLINE void ++htol32_ua_store(uint32 val, uint8 *bytes) ++{ ++ bytes[0] = val & 0xff; ++ bytes[1] = (val >> 8) & 0xff; ++ bytes[2] = (val >> 16) & 0xff; ++ bytes[3] = val >> 24; ++} ++ ++/* ++ * Store 16-bit value to unaligned network-(big-)endian byte array. ++ */ ++static INLINE void ++hton16_ua_store(uint16 val, uint8 *bytes) ++{ ++ bytes[0] = val >> 8; ++ bytes[1] = val & 0xff; ++} ++ ++/* ++ * Store 32-bit value to unaligned network-(big-)endian byte array. ++ */ ++static INLINE void ++hton32_ua_store(uint32 val, uint8 *bytes) ++{ ++ bytes[0] = val >> 24; ++ bytes[1] = (val >> 16) & 0xff; ++ bytes[2] = (val >> 8) & 0xff; ++ bytes[3] = val & 0xff; ++} ++ ++/* ++ * Load 16-bit value from unaligned little-endian byte array. ++ */ ++static INLINE uint16 ++ltoh16_ua(const void *bytes) ++{ ++ return _LTOH16_UA((const uint8 *)bytes); ++} ++ ++/* ++ * Load 32-bit value from unaligned little-endian byte array. ++ */ ++static INLINE uint32 ++ltoh32_ua(const void *bytes) ++{ ++ return _LTOH32_UA((const uint8 *)bytes); ++} ++ ++/* ++ * Load 16-bit value from unaligned big-(network-)endian byte array. ++ */ ++static INLINE uint16 ++ntoh16_ua(const void *bytes) ++{ ++ return _NTOH16_UA((const uint8 *)bytes); ++} ++ ++/* ++ * Load 32-bit value from unaligned big-(network-)endian byte array. ++ */ ++static INLINE uint32 ++ntoh32_ua(const void *bytes) ++{ ++ return _NTOH32_UA((const uint8 *)bytes); ++} ++ ++#endif /* !__GNUC__ */ ++#endif /* !_BCMENDIAN_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmeth.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmeth.h +new file mode 100644 +index 000000000..e1d2d6669 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmeth.h +@@ -0,0 +1,117 @@ ++/* ++ * Broadcom Ethernettype protocol definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmeth.h 701825 2017-05-26 16:45:27Z $ ++ */ ++ ++/* ++ * Broadcom Ethernet protocol defines ++ */ ++ ++#ifndef _BCMETH_H_ ++#define _BCMETH_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++/* ETHER_TYPE_BRCM is defined in ethernet.h */ ++ ++/* ++ * Following the 2byte BRCM ether_type is a 16bit BRCM subtype field ++ * in one of two formats: (only subtypes 32768-65535 are in use now) ++ * ++ * subtypes 0-32767: ++ * 8 bit subtype (0-127) ++ * 8 bit length in bytes (0-255) ++ * ++ * subtypes 32768-65535: ++ * 16 bit big-endian subtype ++ * 16 bit big-endian length in bytes (0-65535) ++ * ++ * length is the number of additional bytes beyond the 4 or 6 byte header ++ * ++ * Reserved values: ++ * 0 reserved ++ * 5-15 reserved for iLine protocol assignments ++ * 17-126 reserved, assignable ++ * 127 reserved ++ * 32768 reserved ++ * 32769-65534 reserved, assignable ++ * 65535 reserved ++ */ ++ ++/* ++ * While adding the subtypes and their specific processing code make sure ++ * bcmeth_bcm_hdr_t is the first data structure in the user specific data structure definition ++ */ ++ ++#define BCMILCP_SUBTYPE_RATE 1 ++#define BCMILCP_SUBTYPE_LINK 2 ++#define BCMILCP_SUBTYPE_CSA 3 ++#define BCMILCP_SUBTYPE_LARQ 4 ++#define BCMILCP_SUBTYPE_VENDOR 5 ++#define BCMILCP_SUBTYPE_FLH 17 ++ ++#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 ++#define BCMILCP_SUBTYPE_CERT 32770 ++#define BCMILCP_SUBTYPE_SES 32771 ++ ++ ++#define BCMILCP_BCM_SUBTYPE_RESERVED 0 ++#define BCMILCP_BCM_SUBTYPE_EVENT 1 ++#define BCMILCP_BCM_SUBTYPE_SES 2 ++/* ++ * The EAPOL type is not used anymore. Instead EAPOL messages are now embedded ++ * within BCMILCP_BCM_SUBTYPE_EVENT type messages ++ */ ++/* #define BCMILCP_BCM_SUBTYPE_EAPOL 3 */ ++#define BCMILCP_BCM_SUBTYPE_DPT 4 ++#define BCMILCP_BCM_SUBTYPE_DNGLEVENT 5 ++ ++#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 ++#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 ++#define BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD 2 ++ ++/* These fields are stored in network order */ ++typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr ++{ ++ uint16 subtype; /* Vendor specific..32769 */ ++ uint16 length; ++ uint8 version; /* Version is 0 */ ++ uint8 oui[3]; /* Broadcom OUI */ ++ /* user specific Data */ ++ uint16 usr_subtype; ++} BWL_POST_PACKED_STRUCT bcmeth_hdr_t; ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _BCMETH_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmevent.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmevent.h +new file mode 100644 +index 000000000..27f77a001 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmevent.h +@@ -0,0 +1,948 @@ ++/* ++ * Broadcom Event protocol definitions ++ * ++ * Dependencies: bcmeth.h ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmevent.h 700076 2017-05-17 14:42:22Z $ ++ * ++ */ ++ ++/* ++ * Broadcom Ethernet Events protocol defines ++ * ++ */ ++ ++#ifndef _BCMEVENT_H_ ++#define _BCMEVENT_H_ ++ ++#include ++/* #include -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */ ++#include ++#if defined(DNGL_EVENT_SUPPORT) ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#define BCM_EVENT_MSG_VERSION 2 /* wl_event_msg_t struct version */ ++#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */ ++ ++/* flags */ ++#define WLC_EVENT_MSG_LINK 0x01 /* link is up */ ++#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */ ++#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */ ++#define WLC_EVENT_MSG_UNKBSS 0x08 /* unknown source bsscfg */ ++#define WLC_EVENT_MSG_UNKIF 0x10 /* unknown source OS i/f */ ++ ++/* these fields are stored in network order */ ++ ++/* version 1 */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint16 version; ++ uint16 flags; /* see flags below */ ++ uint32 event_type; /* Message (see below) */ ++ uint32 status; /* Status code (see below) */ ++ uint32 reason; /* Reason code (if applicable) */ ++ uint32 auth_type; /* WLC_E_AUTH */ ++ uint32 datalen; /* data buf */ ++ struct ether_addr addr; /* Station address (if applicable) */ ++ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ ++} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t; ++ ++/* the current version */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint16 version; ++ uint16 flags; /* see flags below */ ++ uint32 event_type; /* Message (see below) */ ++ uint32 status; /* Status code (see below) */ ++ uint32 reason; /* Reason code (if applicable) */ ++ uint32 auth_type; /* WLC_E_AUTH */ ++ uint32 datalen; /* data buf */ ++ struct ether_addr addr; /* Station address (if applicable) */ ++ char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ ++ uint8 ifidx; /* destination OS i/f index */ ++ uint8 bsscfgidx; /* source bsscfg index */ ++} BWL_POST_PACKED_STRUCT wl_event_msg_t; ++ ++/* used by driver msgs */ ++typedef BWL_PRE_PACKED_STRUCT struct bcm_event { ++ struct ether_header eth; ++ bcmeth_hdr_t bcm_hdr; ++ wl_event_msg_t event; ++ /* data portion follows */ ++} BWL_POST_PACKED_STRUCT bcm_event_t; ++ ++/* ++ * used by host event ++ * note: if additional event types are added, it should go with is_wlc_event_frame() as well. ++ */ ++typedef union bcm_event_msg_u { ++ wl_event_msg_t event; ++#if defined(DNGL_EVENT_SUPPORT) ++ bcm_dngl_event_msg_t dngl_event; ++#endif ++ ++ /* add new event here */ ++} bcm_event_msg_u_t; ++ ++#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) ++ ++/* Event messages */ ++#define WLC_E_SET_SSID 0 /* indicates status of set SSID */ ++#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */ ++#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */ ++#define WLC_E_AUTH 3 /* 802.11 AUTH request */ ++#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */ ++#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */ ++#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */ ++#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */ ++#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */ ++#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */ ++#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */ ++#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */ ++#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */ ++#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */ ++#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */ ++#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */ ++#define WLC_E_LINK 16 /* generic link indication */ ++#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */ ++#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */ ++#define WLC_E_ROAM 19 /* roam complete: indicate status & reason */ ++#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */ ++#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */ ++#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */ ++#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */ ++#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */ ++#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */ ++#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */ ++#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */ ++#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */ ++#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */ ++#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */ ++#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */ ++#define WLC_E_ROAM_PREP 32 /* before attempting to roam association */ ++#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */ ++#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */ ++#define WLC_E_RESET_COMPLETE 35 ++#define WLC_E_JOIN_START 36 ++#define WLC_E_ROAM_START 37 /* roam attempt started: indicate reason */ ++#define WLC_E_ASSOC_START 38 ++#define WLC_E_IBSS_ASSOC 39 ++#define WLC_E_RADIO 40 ++#define WLC_E_PSM_WATCHDOG 41 /* PSM microcode watchdog fired */ ++ ++#define WLC_E_PROBREQ_MSG 44 /* probe request received */ ++#define WLC_E_SCAN_CONFIRM_IND 45 ++#define WLC_E_PSK_SUP 46 /* WPA Handshake fail */ ++#define WLC_E_COUNTRY_CODE_CHANGED 47 ++#define WLC_E_EXCEEDED_MEDIUM_TIME 48 /* WMMAC excedded medium time */ ++#define WLC_E_ICV_ERROR 49 /* WEP ICV error occurred */ ++#define WLC_E_UNICAST_DECODE_ERROR 50 /* Unsupported unicast encrypted frame */ ++#define WLC_E_MULTICAST_DECODE_ERROR 51 /* Unsupported multicast encrypted frame */ ++#define WLC_E_TRACE 52 ++#define WLC_E_IF 54 /* I/F change (for dongle host notification) */ ++#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55 /* listen state expires */ ++#define WLC_E_RSSI 56 /* indicate RSSI change based on configured levels */ ++#define WLC_E_PFN_BEST_BATCHING 57 /* PFN best network batching event */ ++#define WLC_E_EXTLOG_MSG 58 ++#define WLC_E_ACTION_FRAME 59 /* Action frame Rx */ ++#define WLC_E_ACTION_FRAME_COMPLETE 60 /* Action frame Tx complete */ ++#define WLC_E_PRE_ASSOC_IND 61 /* assoc request received */ ++#define WLC_E_PRE_REASSOC_IND 62 /* re-assoc request received */ ++#define WLC_E_CHANNEL_ADOPTED 63 ++#define WLC_E_AP_STARTED 64 /* AP started */ ++#define WLC_E_DFS_AP_STOP 65 /* AP stopped due to DFS */ ++#define WLC_E_DFS_AP_RESUME 66 /* AP resumed due to DFS */ ++#define WLC_E_WAI_STA_EVENT 67 /* WAI stations event */ ++#define WLC_E_WAI_MSG 68 /* event encapsulating an WAI message */ ++#define WLC_E_ESCAN_RESULT 69 /* escan result event */ ++#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 /* action frame off channel complete */ ++#define WLC_E_PROBRESP_MSG 71 /* probe response received */ ++#define WLC_E_P2P_PROBREQ_MSG 72 /* P2P Probe request received */ ++#define WLC_E_DCS_REQUEST 73 ++#define WLC_E_FIFO_CREDIT_MAP 74 /* credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] */ ++#define WLC_E_ACTION_FRAME_RX 75 /* Received action frame event WITH ++ * wl_event_rx_frame_data_t header ++ */ ++#define WLC_E_WAKE_EVENT 76 /* Wake Event timer fired, used for wake WLAN test mode */ ++#define WLC_E_RM_COMPLETE 77 /* Radio measurement complete */ ++#define WLC_E_HTSFSYNC 78 /* Synchronize TSF with the host */ ++#define WLC_E_OVERLAY_REQ 79 /* request an overlay IOCTL/iovar from the host */ ++#define WLC_E_CSA_COMPLETE_IND 80 /* 802.11 CHANNEL SWITCH ACTION completed */ ++#define WLC_E_EXCESS_PM_WAKE_EVENT 81 /* excess PM Wake Event to inform host */ ++#define WLC_E_PFN_SCAN_NONE 82 /* no PFN networks around */ ++/* PFN BSSID network found event, conflict/share with WLC_E_PFN_SCAN_NONE */ ++#define WLC_E_PFN_BSSID_NET_FOUND 82 ++#define WLC_E_PFN_SCAN_ALLGONE 83 /* last found PFN network gets lost */ ++/* PFN BSSID network lost event, conflict/share with WLC_E_PFN_SCAN_ALLGONE */ ++#define WLC_E_PFN_BSSID_NET_LOST 83 ++#define WLC_E_GTK_PLUMBED 84 ++#define WLC_E_ASSOC_IND_NDIS 85 /* 802.11 ASSOC indication for NDIS only */ ++#define WLC_E_REASSOC_IND_NDIS 86 /* 802.11 REASSOC indication for NDIS only */ ++#define WLC_E_ASSOC_REQ_IE 87 ++#define WLC_E_ASSOC_RESP_IE 88 ++#define WLC_E_ASSOC_RECREATED 89 /* association recreated on resume */ ++#define WLC_E_ACTION_FRAME_RX_NDIS 90 /* rx action frame event for NDIS only */ ++#define WLC_E_AUTH_REQ 91 /* authentication request received */ ++#define WLC_E_TDLS_PEER_EVENT 92 /* discovered peer, connected/disconnected peer */ ++#define WLC_E_SPEEDY_RECREATE_FAIL 93 /* fast assoc recreation failed */ ++#define WLC_E_NATIVE 94 /* port-specific event and payload (e.g. NDIS) */ ++#define WLC_E_PKTDELAY_IND 95 /* event for tx pkt delay suddently jump */ ++#define WLC_E_PSTA_PRIMARY_INTF_IND 99 /* psta primary interface indication */ ++#define WLC_E_NAN 100 /* NAN event - Reserved for future */ ++#define WLC_E_BEACON_FRAME_RX 101 ++#define WLC_E_SERVICE_FOUND 102 /* desired service found */ ++#define WLC_E_GAS_FRAGMENT_RX 103 /* GAS fragment received */ ++#define WLC_E_GAS_COMPLETE 104 /* GAS sessions all complete */ ++#define WLC_E_P2PO_ADD_DEVICE 105 /* New device found by p2p offload */ ++#define WLC_E_P2PO_DEL_DEVICE 106 /* device has been removed by p2p offload */ ++#define WLC_E_WNM_STA_SLEEP 107 /* WNM event to notify STA enter sleep mode */ ++#define WLC_E_TXFAIL_THRESH 108 /* Indication of MAC tx failures (exhaustion of ++ * 802.11 retries) exceeding threshold(s) ++ */ ++#define WLC_E_PROXD 109 /* Proximity Detection event */ ++#define WLC_E_IBSS_COALESCE 110 /* IBSS Coalescing */ ++#define WLC_E_AIBSS_TXFAIL 110 /* TXFAIL event for AIBSS, re using event 110 */ ++#define WLC_E_BSS_LOAD 114 /* Inform host of beacon bss load */ ++#define WLC_E_MIMO_PWR_SAVE 115 /* Inform host MIMO PWR SAVE learning events */ ++#define WLC_E_LEAKY_AP_STATS 116 /* Inform host leaky Ap stats events */ ++#define WLC_E_ALLOW_CREDIT_BORROW 117 /* Allow or disallow wlfc credit borrowing in DHD */ ++#define WLC_E_MSCH 120 /* Multiple channel scheduler event */ ++#define WLC_E_CSA_START_IND 121 ++#define WLC_E_CSA_DONE_IND 122 ++#define WLC_E_CSA_FAILURE_IND 123 ++#define WLC_E_CCA_CHAN_QUAL 124 /* CCA based channel quality report */ ++#define WLC_E_BSSID 125 /* to report change in BSSID while roaming */ ++#define WLC_E_TX_STAT_ERROR 126 /* tx error indication */ ++#define WLC_E_BCMC_CREDIT_SUPPORT 127 /* credit check for BCMC supported */ ++#define WLC_E_PEER_TIMEOUT 128 /* silently drop a STA because of inactivity */ ++#define WLC_E_BT_WIFI_HANDOVER_REQ 130 /* Handover Request Initiated */ ++#define WLC_E_SPW_TXINHIBIT 131 /* Southpaw TxInhibit notification */ ++#define WLC_E_FBT_AUTH_REQ_IND 132 /* FBT Authentication Request Indication */ ++#define WLC_E_RSSI_LQM 133 /* Enhancement addition for WLC_E_RSSI */ ++#define WLC_E_PFN_GSCAN_FULL_RESULT 134 /* Full probe/beacon (IEs etc) results */ ++#define WLC_E_PFN_SWC 135 /* Significant change in rssi of bssids being tracked */ ++#define WLC_E_AUTHORIZED 136 /* a STA been authroized for traffic */ ++#define WLC_E_PROBREQ_MSG_RX 137 /* probe req with wl_event_rx_frame_data_t header */ ++#define WLC_E_PFN_SCAN_COMPLETE 138 /* PFN completed scan of network list */ ++#define WLC_E_RMC_EVENT 139 /* RMC Event */ ++#define WLC_E_DPSTA_INTF_IND 140 /* DPSTA interface indication */ ++#define WLC_E_RRM 141 /* RRM Event */ ++#define WLC_E_PFN_SSID_EXT 142 /* SSID EXT event */ ++#define WLC_E_ROAM_EXP_EVENT 143 /* Expanded roam event */ ++#define WLC_E_ULP 146 /* ULP entered indication */ ++#define WLC_E_MACDBG 147 /* Ucode debugging event */ ++#define WLC_E_RESERVED 148 /* reserved */ ++#define WLC_E_PRE_ASSOC_RSEP_IND 149 /* assoc resp received */ ++#define WLC_E_PSK_AUTH 150 /* PSK AUTH WPA2-PSK 4 WAY Handshake failure */ ++#define WLC_E_TKO 151 /* TCP keepalive offload */ ++#define WLC_E_SDB_TRANSITION 152 /* SDB mode-switch event */ ++#define WLC_E_NATOE_NFCT 153 /* natoe event */ ++#define WLC_E_TEMP_THROTTLE 154 /* Temperature throttling control event */ ++#define WLC_E_LINK_QUALITY 155 /* Link quality measurement complete */ ++#define WLC_E_BSSTRANS_RESP 156 /* BSS Transition Response received */ ++#define WLC_E_TWT_SETUP 157 /* TWT Setup Complete event */ ++#define WLC_E_HE_TWT_SETUP 157 /* TODO:Remove after merging TWT changes to trunk */ ++#define WLC_E_NAN_CRITICAL 158 /* NAN Critical Event */ ++#define WLC_E_NAN_NON_CRITICAL 159 /* NAN Non-Critical Event */ ++#define WLC_E_RADAR_DETECTED 160 /* Radar Detected event */ ++#define WLC_E_RANGING_EVENT 161 /* Ranging event */ ++#define WLC_E_INVALID_IE 162 /* Received invalid IE */ ++#define WLC_E_MODE_SWITCH 163 /* Mode switch event */ ++#define WLC_E_PKT_FILTER 164 /* Packet filter event */ ++#define WLC_E_DMA_TXFLUSH_COMPLETE 165 /* TxFlush done before changing ++ * tx/rxchain ++ */ ++#define WLC_E_FBT 166 /* FBT event */ ++#define WLC_E_PFN_SCAN_BACKOFF 167 /* PFN SCAN Backoff event */ ++#define WLC_E_PFN_BSSID_SCAN_BACKOFF 168 /* PFN BSSID SCAN BAckoff event */ ++#define WLC_E_AGGR_EVENT 169 /* Aggregated event */ ++#define WLC_E_TVPM_MITIGATION 171 /* Change in mitigation applied by TVPM */ ++#define WLC_E_LAST 172 /* highest val + 1 for range checking */ ++#if (WLC_E_LAST > 172) ++#error "WLC_E_LAST: Invalid value for last event; must be <= 172." ++#endif /* WLC_E_LAST */ ++ ++/* define an API for getting the string name of an event */ ++extern const char *bcmevent_get_name(uint event_type); ++extern void wl_event_to_host_order(wl_event_msg_t * evt); ++extern void wl_event_to_network_order(wl_event_msg_t * evt); ++ ++/* validate if the event is proper and if valid copy event header to event */ ++extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, ++ bcm_event_msg_u_t *out_event); ++ ++/* conversion between host and network order for events */ ++void wl_event_to_host_order(wl_event_msg_t * evt); ++void wl_event_to_network_order(wl_event_msg_t * evt); ++ ++ ++/* Event status codes */ ++#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */ ++#define WLC_E_STATUS_FAIL 1 /* operation failed */ ++#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */ ++#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */ ++#define WLC_E_STATUS_ABORT 4 /* operation was aborted */ ++#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */ ++#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */ ++#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */ ++#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */ ++#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */ ++#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */ ++#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */ ++#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */ ++#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */ ++#define WLC_E_STATUS_CS_ABORT 15 /* abort channel select */ ++#define WLC_E_STATUS_ERROR 16 /* request failed due to error */ ++#define WLC_E_STATUS_INVALID 0xff /* Invalid status code to init variables. */ ++ ++/* 4-way handshake event type */ ++#define WLC_E_PSK_AUTH_SUB_EAPOL_START 1 /* EAPOL start */ ++#define WLC_E_PSK_AUTH_SUB_EAPOL_DONE 2 /* EAPOL end */ ++/* GTK event type */ ++#define WLC_E_PSK_AUTH_SUB_GTK_DONE 3 /* GTK end */ ++ ++/* 4-way handshake event status code */ ++#define WLC_E_STATUS_PSK_AUTH_WPA_TIMOUT 1 /* operation timed out */ ++#define WLC_E_STATUS_PSK_AUTH_MIC_WPA_ERR 2 /* MIC error */ ++#define WLC_E_STATUS_PSK_AUTH_IE_MISMATCH_ERR 3 /* IE Missmatch error */ ++#define WLC_E_STATUS_PSK_AUTH_REPLAY_COUNT_ERR 4 ++#define WLC_E_STATUS_PSK_AUTH_PEER_BLACKISTED 5 /* Blaclisted peer */ ++#define WLC_E_STATUS_PSK_AUTH_GTK_REKEY_FAIL 6 /* GTK event status code */ ++ ++/* SDB transition status code */ ++#define WLC_E_STATUS_SDB_START 1 ++#define WLC_E_STATUS_SDB_COMPLETE 2 ++/* Slice-swap status code */ ++#define WLC_E_STATUS_SLICE_SWAP_START 3 ++#define WLC_E_STATUS_SLICE_SWAP_COMPLETE 4 ++ ++ ++/* SDB transition reason code */ ++#define WLC_E_REASON_HOST_DIRECT 0 ++#define WLC_E_REASON_INFRA_ASSOC 1 ++#define WLC_E_REASON_INFRA_ROAM 2 ++#define WLC_E_REASON_INFRA_DISASSOC 3 ++#define WLC_E_REASON_NO_MODE_CHANGE_NEEDED 4 ++#define WLC_E_REASON_AWDL_ENABLE 5 ++#define WLC_E_REASON_AWDL_DISABLE 6 ++ ++/* WLC_E_SDB_TRANSITION event data */ ++#define WL_MAX_BSSCFG 4 ++#define WL_EVENT_SDB_TRANSITION_VER 1 ++typedef struct wl_event_sdb_data { ++ uint8 wlunit; /* Core index */ ++ uint8 is_iftype; /* Interface Type(Station, SoftAP, P2P_GO, P2P_GC */ ++ uint16 chanspec; /* Interface Channel/Chanspec */ ++ char ssidbuf[(4 * 32) + 1]; /* SSID_FMT_BUF_LEN: ((4 * DOT11_MAX_SSID_LEN) + 1) */ ++} wl_event_sdb_data_t; ++ ++typedef struct wl_event_sdb_trans { ++ uint8 version; /* Event Data Version */ ++ uint8 rsdb_mode; ++ uint8 enable_bsscfg; ++ uint8 reserved; ++ struct wl_event_sdb_data values[WL_MAX_BSSCFG]; ++} wl_event_sdb_trans_t; ++ ++/* roam reason codes */ ++#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */ ++#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */ ++#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */ ++#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */ ++#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */ ++ ++#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */ ++#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */ ++#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */ ++#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */ ++#define WLC_E_REASON_MINTXRATE 9 /* roamed because at mintxrate for too long */ ++#define WLC_E_REASON_TXFAIL 10 /* We can hear AP, but AP can't hear us */ ++/* retained for precommit auto-merging errors; remove once all branches are synced */ ++#define WLC_E_REASON_REQUESTED_ROAM 11 ++#define WLC_E_REASON_BSSTRANS_REQ 11 /* roamed due to BSS Transition request by AP */ ++#define WLC_E_REASON_LOW_RSSI_CU 12 /* roamed due to low RSSI and Channel Usage */ ++#define WLC_E_REASON_RADAR_DETECTED 13 /* roamed due to radar detection by STA */ ++ ++/* prune reason codes */ ++#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ ++#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ ++#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */ ++#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */ ++#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */ ++#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */ ++#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */ ++#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */ ++#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */ ++#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */ ++#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */ ++#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */ ++#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */ ++#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */ ++#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */ ++#define WLC_E_PRUNE_AUTH_RESP_MAC 20 /* suppress auth resp by MAC filter */ ++ ++/* WPA failure reason codes carried in the WLC_E_PSK_SUP event */ ++#define WLC_E_SUP_OTHER 0 /* Other reason */ ++#define WLC_E_SUP_DECRYPT_KEY_DATA 1 /* Decryption of key data failed */ ++#define WLC_E_SUP_BAD_UCAST_WEP128 2 /* Illegal use of ucast WEP128 */ ++#define WLC_E_SUP_BAD_UCAST_WEP40 3 /* Illegal use of ucast WEP40 */ ++#define WLC_E_SUP_UNSUP_KEY_LEN 4 /* Unsupported key length */ ++#define WLC_E_SUP_PW_KEY_CIPHER 5 /* Unicast cipher mismatch in pairwise key */ ++#define WLC_E_SUP_MSG3_TOO_MANY_IE 6 /* WPA IE contains > 1 RSN IE in key msg 3 */ ++#define WLC_E_SUP_MSG3_IE_MISMATCH 7 /* WPA IE mismatch in key message 3 */ ++#define WLC_E_SUP_NO_INSTALL_FLAG 8 /* INSTALL flag unset in 4-way msg */ ++#define WLC_E_SUP_MSG3_NO_GTK 9 /* encapsulated GTK missing from msg 3 */ ++#define WLC_E_SUP_GRP_KEY_CIPHER 10 /* Multicast cipher mismatch in group key */ ++#define WLC_E_SUP_GRP_MSG1_NO_GTK 11 /* encapsulated GTK missing from group msg 1 */ ++#define WLC_E_SUP_GTK_DECRYPT_FAIL 12 /* GTK decrypt failure */ ++#define WLC_E_SUP_SEND_FAIL 13 /* message send failure */ ++#define WLC_E_SUP_DEAUTH 14 /* received FC_DEAUTH */ ++#define WLC_E_SUP_WPA_PSK_TMO 15 /* WPA PSK 4-way handshake timeout */ ++#define WLC_E_SUP_WPA_PSK_M1_TMO 16 /* WPA PSK 4-way handshake M1 timeout */ ++#define WLC_E_SUP_WPA_PSK_M3_TMO 17 /* WPA PSK 4-way handshake M3 timeout */ ++ ++ ++/* Ucode reason codes carried in the WLC_E_MACDBG event */ ++#define WLC_E_MACDBG_LIST_PSM 0 /* Dump list update for PSM registers */ ++#define WLC_E_MACDBG_LIST_PSMX 1 /* Dump list update for PSMx registers */ ++#define WLC_E_MACDBG_REGALL 2 /* Dump all registers */ ++ ++/* Event data for events that include frames received over the air */ ++/* WLC_E_PROBRESP_MSG ++ * WLC_E_P2P_PROBREQ_MSG ++ * WLC_E_ACTION_FRAME_RX ++ */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data { ++ uint16 version; ++ uint16 channel; /* Matches chanspec_t format from bcmwifi_channels.h */ ++ int32 rssi; ++ uint32 mactime; ++ uint32 rate; ++} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t; ++ ++#define BCM_RX_FRAME_DATA_VERSION 1 ++ ++/* WLC_E_IF event data */ ++typedef struct wl_event_data_if { ++ uint8 ifidx; /* RTE virtual device index (for dongle) */ ++ uint8 opcode; /* see I/F opcode */ ++ uint8 reserved; /* bit mask (WLC_E_IF_FLAGS_XXX ) */ ++ uint8 bssidx; /* bsscfg index */ ++ uint8 role; /* see I/F role */ ++} wl_event_data_if_t; ++ ++/* WLC_E_NATOE event data */ ++typedef struct wl_event_data_natoe { ++ uint32 natoe_active; ++ uint32 sta_ip; ++ uint16 start_port; ++ uint16 end_port; ++} wl_event_data_natoe_t; ++ ++/* opcode in WLC_E_IF event */ ++#define WLC_E_IF_ADD 1 /* bsscfg add */ ++#define WLC_E_IF_DEL 2 /* bsscfg delete */ ++#define WLC_E_IF_CHANGE 3 /* bsscfg role change */ ++ ++/* I/F role code in WLC_E_IF event */ ++#define WLC_E_IF_ROLE_STA 0 /* Infra STA */ ++#define WLC_E_IF_ROLE_AP 1 /* Access Point */ ++#define WLC_E_IF_ROLE_WDS 2 /* WDS link */ ++#define WLC_E_IF_ROLE_P2P_GO 3 /* P2P Group Owner */ ++#define WLC_E_IF_ROLE_P2P_CLIENT 4 /* P2P Client */ ++#define WLC_E_IF_ROLE_IBSS 8 /* IBSS */ ++#define WLC_E_IF_ROLE_NAN 9 /* NAN */ ++ ++/* WLC_E_RSSI event data */ ++typedef struct wl_event_data_rssi { ++ int32 rssi; ++ int32 snr; ++ int32 noise; ++} wl_event_data_rssi_t; ++ ++/* WLC_E_IF flag */ ++#define WLC_E_IF_FLAGS_BSSCFG_NOIF 0x1 /* no host I/F creation needed */ ++ ++/* Reason codes for LINK */ ++#define WLC_E_LINK_BCN_LOSS 1 /* Link down because of beacon loss */ ++#define WLC_E_LINK_DISASSOC 2 /* Link down because of disassoc */ ++#define WLC_E_LINK_ASSOC_REC 3 /* Link down because assoc recreate failed */ ++#define WLC_E_LINK_BSSCFG_DIS 4 /* Link down due to bsscfg down */ ++ ++ ++/* WLC_E_NDIS_LINK event data */ ++typedef BWL_PRE_PACKED_STRUCT struct ndis_link_parms { ++ struct ether_addr peer_mac; /* 6 bytes */ ++ uint16 chanspec; /* 2 bytes */ ++ uint32 link_speed; /* current datarate in units of 500 Kbit/s */ ++ uint32 max_link_speed; /* max possible datarate for link in units of 500 Kbit/s */ ++ int32 rssi; /* average rssi */ ++} BWL_POST_PACKED_STRUCT ndis_link_parms_t; ++ ++/* reason codes for WLC_E_OVERLAY_REQ event */ ++#define WLC_E_OVL_DOWNLOAD 0 /* overlay download request */ ++#define WLC_E_OVL_UPDATE_IND 1 /* device indication of host overlay update */ ++ ++/* reason codes for WLC_E_TDLS_PEER_EVENT event */ ++#define WLC_E_TDLS_PEER_DISCOVERED 0 /* peer is ready to establish TDLS */ ++#define WLC_E_TDLS_PEER_CONNECTED 1 ++#define WLC_E_TDLS_PEER_DISCONNECTED 2 ++ ++/* reason codes for WLC_E_RMC_EVENT event */ ++#define WLC_E_REASON_RMC_NONE 0 ++#define WLC_E_REASON_RMC_AR_LOST 1 ++#define WLC_E_REASON_RMC_AR_NO_ACK 2 ++ ++#ifdef WLTDLS ++/* TDLS Action Category code */ ++#define TDLS_AF_CATEGORY 12 ++/* Wi-Fi Display (WFD) Vendor Specific Category */ ++/* used for WFD Tunneled Probe Request and Response */ ++#define TDLS_VENDOR_SPECIFIC 127 ++/* TDLS Action Field Values */ ++#define TDLS_ACTION_SETUP_REQ 0 ++#define TDLS_ACTION_SETUP_RESP 1 ++#define TDLS_ACTION_SETUP_CONFIRM 2 ++#define TDLS_ACTION_TEARDOWN 3 ++#define WLAN_TDLS_SET_PROBE_WFD_IE 11 ++#define WLAN_TDLS_SET_SETUP_WFD_IE 12 ++#define WLAN_TDLS_SET_WFD_ENABLED 13 ++#define WLAN_TDLS_SET_WFD_DISABLED 14 ++#endif ++ ++/* WLC_E_RANGING_EVENT subtypes */ ++#define WLC_E_RANGING_RESULTS 0 ++ ++ ++/* GAS event data */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas { ++ uint16 channel; /* channel of GAS protocol */ ++ uint8 dialog_token; /* GAS dialog token */ ++ uint8 fragment_id; /* fragment id */ ++ uint16 status_code; /* status code on GAS completion */ ++ uint16 data_len; /* length of data to follow */ ++ uint8 data[1]; /* variable length specified by data_len */ ++} BWL_POST_PACKED_STRUCT wl_event_gas_t; ++ ++/* service discovery TLV */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_sd_tlv { ++ uint16 length; /* length of response_data */ ++ uint8 protocol; /* service protocol type */ ++ uint8 transaction_id; /* service transaction id */ ++ uint8 status_code; /* status code */ ++ uint8 data[1]; /* response data */ ++} BWL_POST_PACKED_STRUCT wl_sd_tlv_t; ++ ++/* service discovery event data */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_event_sd { ++ uint16 channel; /* channel */ ++ uint8 count; /* number of tlvs */ ++ wl_sd_tlv_t tlv[1]; /* service discovery TLV */ ++} BWL_POST_PACKED_STRUCT wl_event_sd_t; ++ ++/* WLC_E_PKT_FILTER event sub-classification codes */ ++#define WLC_E_PKT_FILTER_TIMEOUT 1 /* Matching packet not received in last timeout seconds */ ++ ++/* Note: proxd has a new API (ver 3.0) deprecates the following */ ++ ++/* Reason codes for WLC_E_PROXD */ ++#define WLC_E_PROXD_FOUND 1 /* Found a proximity device */ ++#define WLC_E_PROXD_GONE 2 /* Lost a proximity device */ ++#define WLC_E_PROXD_START 3 /* used by: target */ ++#define WLC_E_PROXD_STOP 4 /* used by: target */ ++#define WLC_E_PROXD_COMPLETED 5 /* used by: initiator completed */ ++#define WLC_E_PROXD_ERROR 6 /* used by both initiator and target */ ++#define WLC_E_PROXD_COLLECT_START 7 /* used by: target & initiator */ ++#define WLC_E_PROXD_COLLECT_STOP 8 /* used by: target */ ++#define WLC_E_PROXD_COLLECT_COMPLETED 9 /* used by: initiator completed */ ++#define WLC_E_PROXD_COLLECT_ERROR 10 /* used by both initiator and target */ ++#define WLC_E_PROXD_NAN_EVENT 11 /* used by both initiator and target */ ++#define WLC_E_PROXD_TS_RESULTS 12 /* used by: initiator completed */ ++ ++/* proxd_event data */ ++typedef struct ftm_sample { ++ uint32 value; /* RTT in ns */ ++ int8 rssi; /* RSSI */ ++} ftm_sample_t; ++ ++typedef struct ts_sample { ++ uint32 t1; ++ uint32 t2; ++ uint32 t3; ++ uint32 t4; ++} ts_sample_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct proxd_event_data { ++ uint16 ver; /* version */ ++ uint16 mode; /* mode: target/initiator */ ++ uint16 method; /* method: rssi/TOF/AOA */ ++ uint8 err_code; /* error classification */ ++ uint8 TOF_type; /* one way or two way TOF */ ++ uint8 OFDM_frame_type; /* legacy or VHT */ ++ uint8 bandwidth; /* Bandwidth is 20, 40,80, MHZ */ ++ struct ether_addr peer_mac; /* (e.g for tgt:initiator's */ ++ uint32 distance; /* dst to tgt, units meter */ ++ uint32 meanrtt; /* mean delta */ ++ uint32 modertt; /* Mode delta */ ++ uint32 medianrtt; /* median RTT */ ++ uint32 sdrtt; /* Standard deviation of RTT */ ++ int32 gdcalcresult; /* Software or Hardware Kind of redundant, but if */ ++ /* frame type is VHT, then we should do it by hardware */ ++ int16 avg_rssi; /* avg rssi accroos the ftm frames */ ++ int16 validfrmcnt; /* Firmware's valid frame counts */ ++ int32 peer_router_info; /* Peer router information if available in TLV, */ ++ /* We will add this field later */ ++ int32 var1; /* average of group delay */ ++ int32 var2; /* average of threshold crossing */ ++ int32 var3; /* difference between group delay and threshold crossing */ ++ /* raw Fine Time Measurements (ftm) data */ ++ uint16 ftm_unit; /* ftm cnt resolution in picoseconds , 6250ps - default */ ++ uint16 ftm_cnt; /* num of rtd measurments/length in the ftm buffer */ ++ ftm_sample_t ftm_buff[1]; /* 1 ... ftm_cnt */ ++} BWL_POST_PACKED_STRUCT wl_proxd_event_data_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct proxd_event_ts_results { ++ uint16 ver; /* version */ ++ uint16 mode; /* mode: target/initiator */ ++ uint16 method; /* method: rssi/TOF/AOA */ ++ uint8 err_code; /* error classification */ ++ uint8 TOF_type; /* one way or two way TOF */ ++ uint16 ts_cnt; /* number of timestamp measurements */ ++ ts_sample_t ts_buff[1]; /* Timestamps */ ++} BWL_POST_PACKED_STRUCT wl_proxd_event_ts_results_t; ++ ++ ++/* Video Traffic Interference Monitor Event */ ++#define INTFER_EVENT_VERSION 1 ++#define INTFER_STREAM_TYPE_NONTCP 1 ++#define INTFER_STREAM_TYPE_TCP 2 ++#define WLINTFER_STATS_NSMPLS 4 ++typedef struct wl_intfer_event { ++ uint16 version; /* version */ ++ uint16 status; /* status */ ++ uint8 txfail_histo[WLINTFER_STATS_NSMPLS]; /* txfail histo */ ++} wl_intfer_event_t; ++ ++#define RRM_EVENT_VERSION 0 ++typedef struct wl_rrm_event { ++ int16 version; ++ int16 len; ++ int16 cat; /* Category */ ++ int16 subevent; ++ char payload[1]; /* Measurement payload */ ++} wl_rrm_event_t; ++ ++ ++/* WLC_E_PSTA_PRIMARY_INTF_IND event data */ ++typedef struct wl_psta_primary_intf_event { ++ struct ether_addr prim_ea; /* primary intf ether addr */ ++} wl_psta_primary_intf_event_t; ++ ++/* WLC_E_DPSTA_INTF_IND event data */ ++typedef enum { ++ WL_INTF_PSTA = 1, ++ WL_INTF_DWDS = 2 ++} wl_dpsta_intf_type; ++ ++typedef struct wl_dpsta_intf_event { ++ wl_dpsta_intf_type intf_type; /* dwds/psta intf register */ ++} wl_dpsta_intf_event_t; ++ ++/* ********** NAN protocol events/subevents ********** */ ++#define NAN_EVENT_BUFFER_SIZE 512 /* max size */ ++/* NAN Events sent by firmware */ ++ ++/* ++ * If you make changes to this enum, dont forget to update the mask (if need be). ++ */ ++typedef enum wl_nan_events { ++ WL_NAN_EVENT_START = 1, /* NAN cluster started */ ++ WL_NAN_EVENT_JOIN = 2, /* To be deprecated */ ++ WL_NAN_EVENT_ROLE = 3, /* Role changed */ ++ WL_NAN_EVENT_SCAN_COMPLETE = 4, /* To be deprecated */ ++ WL_NAN_EVENT_DISCOVERY_RESULT = 5, /* Subscribe Received */ ++ WL_NAN_EVENT_REPLIED = 6, /* Publish Sent */ ++ WL_NAN_EVENT_TERMINATED = 7, /* sub / pub is terminated */ ++ WL_NAN_EVENT_RECEIVE = 8, /* Follow up Received */ ++ WL_NAN_EVENT_STATUS_CHG = 9, /* change in nan_mac status */ ++ WL_NAN_EVENT_MERGE = 10, /* Merged to a NAN cluster */ ++ WL_NAN_EVENT_STOP = 11, /* To be deprecated */ ++ WL_NAN_EVENT_P2P = 12, /* Unused */ ++ WL_NAN_EVENT_WINDOW_BEGIN_P2P = 13, /* Unused */ ++ WL_NAN_EVENT_WINDOW_BEGIN_MESH = 14, /* Unused */ ++ WL_NAN_EVENT_WINDOW_BEGIN_IBSS = 15, /* Unused */ ++ WL_NAN_EVENT_WINDOW_BEGIN_RANGING = 16, /* Unused */ ++ WL_NAN_EVENT_POST_DISC = 17, /* Event for post discovery data */ ++ WL_NAN_EVENT_DATA_IF_ADD = 18, /* Unused */ ++ WL_NAN_EVENT_DATA_PEER_ADD = 19, /* Event for peer add */ ++ /* nan 2.0 */ ++ /* Will be removed after source code is committed. */ ++ WL_NAN_EVENT_DATA_IND = 20, ++ WL_NAN_EVENT_PEER_DATAPATH_IND = 20, /* Incoming DP req */ ++ /* Will be removed after source code is committed. */ ++ WL_NAN_EVENT_DATA_CONF = 21, ++ WL_NAN_EVENT_DATAPATH_ESTB = 21, /* DP Established */ ++ WL_NAN_EVENT_SDF_RX = 22, /* SDF payload */ ++ WL_NAN_EVENT_DATAPATH_END = 23, /* DP Terminate recvd */ ++ /* Below event needs to be removed after source code is committed. */ ++ WL_NAN_EVENT_DATA_END = 23, ++ WL_NAN_EVENT_BCN_RX = 24, /* received beacon payload */ ++ WL_NAN_EVENT_PEER_DATAPATH_RESP = 25, /* Peer's DP response */ ++ WL_NAN_EVENT_PEER_DATAPATH_CONF = 26, /* Peer's DP confirm */ ++ WL_NAN_EVENT_RNG_REQ_IND = 27, /* Range Request */ ++ WL_NAN_EVENT_RNG_RPT_IND = 28, /* Range Report */ ++ WL_NAN_EVENT_RNG_TERM_IND = 29, /* Range Termination */ ++ WL_NAN_EVENT_PEER_DATAPATH_SEC_INST = 30, /* Peer's DP sec install */ ++ WL_NAN_EVENT_TXS = 31, /* for tx status of follow-up and SDFs */ ++ WL_NAN_EVENT_INVALID /* delimiter for max value */ ++} nan_app_events_e; ++ ++#define NAN_EV_MASK(ev) \ ++ (1 << (ev - 1)) ++#define IS_NAN_EVT_ON(var, evt) ((var & (1 << (evt-1))) != 0) ++/* ******************* end of NAN section *************** */ ++ ++/* WLC_E_ULP event data */ ++#define WL_ULP_EVENT_VERSION 1 ++#define WL_ULP_DISABLE_CONSOLE 1 /* Disable console message on ULP entry */ ++#define WL_ULP_UCODE_DOWNLOAD 2 /* Download ULP ucode file */ ++ ++typedef struct wl_ulp_event { ++ uint16 version; ++ uint16 ulp_dongle_action; ++} wl_ulp_event_t; ++ ++/* TCP keepalive event data */ ++typedef BWL_PRE_PACKED_STRUCT struct wl_event_tko { ++ uint8 index; /* TCP connection index, 0 to max-1 */ ++ uint8 pad[3]; /* 4-byte struct alignment */ ++} BWL_POST_PACKED_STRUCT wl_event_tko_t; ++ ++typedef struct { ++ uint8 radar_type; /* one of RADAR_TYPE_XXX */ ++ uint16 min_pw; /* minimum pulse-width (usec * 20) */ ++ uint16 max_pw; /* maximum pulse-width (usec * 20) */ ++ uint16 min_pri; /* minimum pulse repetition interval (usec) */ ++ uint16 max_pri; /* maximum pulse repetition interval (usec) */ ++ uint16 subband; /* subband/frequency */ ++} radar_detected_event_info_t; ++typedef struct wl_event_radar_detect_data { ++ ++ uint32 version; ++ uint16 current_chanspec; /* chanspec on which the radar is recieved */ ++ uint16 target_chanspec; /* Target chanspec after detection of radar on current_chanspec */ ++ radar_detected_event_info_t radar_info[2]; ++} wl_event_radar_detect_data_t; ++ ++ ++#define WL_EVENT_MODESW_VER_1 1 ++#define WL_EVENT_MODESW_VER_CURRENT WL_EVENT_MODESW_VER_1 ++ ++#define WL_E_MODESW_FLAG_MASK_DEVICE 0x01u /* mask of device: belongs to local or peer */ ++#define WL_E_MODESW_FLAG_MASK_FROM 0x02u /* mask of origin: firmware or user */ ++#define WL_E_MODESW_FLAG_MASK_STATE 0x0Cu /* mask of state: modesw progress state */ ++ ++#define WL_E_MODESW_FLAG_DEVICE_LOCAL 0x00u /* flag - device: info is about self/local */ ++#define WL_E_MODESW_FLAG_DEVICE_PEER 0x01u /* flag - device: info is about peer */ ++ ++#define WL_E_MODESW_FLAG_FROM_FIRMWARE 0x00u /* flag - from: request is from firmware */ ++#define WL_E_MODESW_FLAG_FROM_USER 0x02u /* flag - from: request is from user/iov */ ++ ++#define WL_E_MODESW_FLAG_STATE_REQUESTED 0x00u /* flag - state: mode switch request */ ++#define WL_E_MODESW_FLAG_STATE_INITIATED 0x04u /* flag - state: switch initiated */ ++#define WL_E_MODESW_FLAG_STATE_COMPLETE 0x08u /* flag - state: switch completed/success */ ++#define WL_E_MODESW_FLAG_STATE_FAILURE 0x0Cu /* flag - state: failed to switch */ ++ ++/* Get sizeof *X including variable data's length where X is pointer to wl_event_mode_switch_t */ ++#define WL_E_MODESW_SIZE(X) (sizeof(*(X)) + (X)->length) ++ ++/* Get variable data's length where X is pointer to wl_event_mode_switch_t */ ++#define WL_E_MODESW_DATA_SIZE(X) (((X)->length > sizeof(*(X))) ? ((X)->length - sizeof(*(X))) : 0) ++ ++#define WL_E_MODESW_REASON_UNKNOWN 0u /* reason: UNKNOWN */ ++#define WL_E_MODESW_REASON_ACSD 1u /* reason: ACSD (based on events from FW */ ++#define WL_E_MODESW_REASON_OBSS_DBS 2u /* reason: OBSS DBS (eg. on interference) */ ++#define WL_E_MODESW_REASON_DFS 3u /* reason: DFS (eg. on subband radar) */ ++#define WL_E_MODESW_REASON_DYN160 4u /* reason: DYN160 (160/2x2 - 80/4x4) */ ++ ++/* event structure for WLC_E_MODE_SWITCH */ ++typedef struct { ++ uint16 version; ++ uint16 length; /* size including 'data' field */ ++ uint16 opmode_from; ++ uint16 opmode_to; ++ uint32 flags; /* bit 0: peer(/local==0); ++ * bit 1: user(/firmware==0); ++ * bits 3,2: 00==requested, 01==initiated, ++ * 10==complete, 11==failure; ++ * rest: reserved ++ */ ++ uint16 reason; /* value 0: unknown, 1: ACSD, 2: OBSS_DBS, ++ * 3: DFS, 4: DYN160, rest: reserved ++ */ ++ uint16 data_offset; /* offset to 'data' from beginning of this struct. ++ * fields may be added between data_offset and data ++ */ ++ /* ADD NEW FIELDS HERE */ ++ uint8 data[]; /* reason specific data; could be empty */ ++} wl_event_mode_switch_t; ++ ++/* when reason in WLC_E_MODE_SWITCH is DYN160, data will carry the following structure */ ++typedef struct { ++ uint16 trigger; /* value 0: MU to SU, 1: SU to MU, 2: metric_dyn160, 3:re-/assoc, ++ * 4: disassoc, 5: rssi, 6: traffic, 7: interference, ++ * 8: chanim_stats ++ */ ++ struct ether_addr sta_addr; /* causal STA's MAC address when known */ ++ uint16 metric_160_80; /* latest dyn160 metric */ ++ uint8 nss; /* NSS of the STA */ ++ uint8 bw; /* BW of the STA */ ++ int8 rssi; /* RSSI of the STA */ ++ uint8 traffic; /* internal metric of traffic */ ++} wl_event_mode_switch_dyn160; ++ ++#define WL_EVENT_FBT_VER_1 1 ++ ++#define WL_E_FBT_TYPE_FBT_OTD_AUTH 1 ++#define WL_E_FBT_TYPE_FBT_OTA_AUTH 2 ++ ++/* event structure for WLC_E_FBT */ ++typedef struct { ++ uint16 version; ++ uint16 length; /* size including 'data' field */ ++ uint16 type; /* value 0: unknown, 1: FBT OTD Auth Req */ ++ uint16 data_offset; /* offset to 'data' from beginning of this struct. ++ * fields may be added between data_offset and data ++ */ ++ /* ADD NEW FIELDS HERE */ ++ uint8 data[]; /* type specific data; could be empty */ ++} wl_event_fbt_t; ++ ++/* TWT Setup Completion is designed to notify the user of TWT Setup process ++ * status. When 'status' field is value of BCME_OK, the user must check the ++ * 'setup_cmd' field value in 'wl_twt_sdesc_t' structure that at the end of ++ * the event data to see the response from the TWT Responding STA; when ++ * 'status' field is value of BCME_ERROR or non BCME_OK, user must not use ++ * anything from 'wl_twt_sdesc_t' structure as it is the TWT Requesting STA's ++ * own TWT parameter. ++ */ ++ ++#define WL_TWT_SETUP_CPLT_VER 0 ++ ++/* TWT Setup Completion event data */ ++typedef struct wl_twt_setup_cplt { ++ uint16 version; ++ uint16 length; /* the byte count of fields from 'dialog' onwards */ ++ uint8 dialog; /* the dialog token user supplied to the TWT setup API */ ++ uint8 pad[3]; ++ int32 status; ++ /* wl_twt_sdesc_t desc; - defined in wlioctl.h */ ++} wl_twt_setup_cplt_t; ++ ++#define WL_INVALID_IE_EVENT_VERSION 0 ++ ++/* Invalid IE Event data */ ++typedef struct wl_invalid_ie_event { ++ uint16 version; ++ uint16 len; /* Length of the invalid IE copy */ ++ uint16 type; /* Type/subtype of the frame which contains the invalid IE */ ++ uint16 error; /* error code of the wrong IE, defined in ie_error_code_t */ ++ uint8 ie[]; /* Variable length buffer for the invalid IE copy */ ++} wl_invalid_ie_event_t; ++ ++/* Fixed header portion of Invalid IE Event */ ++typedef struct wl_invalid_ie_event_hdr { ++ uint16 version; ++ uint16 len; /* Length of the invalid IE copy */ ++ uint16 type; /* Type/subtype of the frame which contains the invalid IE */ ++ uint16 error; /* error code of the wrong IE, defined in ie_error_code_t */ ++ /* var length IE data follows */ ++} wl_invalid_ie_event_hdr_t; ++ ++typedef enum ie_error_code { ++ IE_ERROR_OUT_OF_RANGE = 0x01 ++} ie_error_code_t; ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++/* reason of channel switch */ ++typedef enum { ++ CHANSW_DFS = 10, /* channel switch due to DFS module */ ++ CHANSW_HOMECH_REQ = 14, /* channel switch due to HOME Channel Request */ ++ CHANSW_STA = 15, /* channel switch due to STA */ ++ CHANSW_SOFTAP = 16, /* channel switch due to SodtAP */ ++ CHANSW_AIBSS = 17, /* channel switch due to AIBSS */ ++ CHANSW_NAN = 18, /* channel switch due to NAN */ ++ CHANSW_NAN_DISC = 19, /* channel switch due to NAN Disc */ ++ CHANSW_NAN_SCHED = 20, /* channel switch due to NAN Sched */ ++ CHANSW_AWDL_AW = 21, /* channel switch due to AWDL aw */ ++ CHANSW_AWDL_SYNC = 22, /* channel switch due to AWDL sync */ ++ CHANSW_AWDL_CAL = 23, /* channel switch due to AWDL Cal */ ++ CHANSW_AWDL_PSF = 24, /* channel switch due to AWDL PSF */ ++ CHANSW_AWDL_OOB_AF = 25, /* channel switch due to AWDL OOB action frame */ ++ CHANSW_TDLS = 26, /* channel switch due to TDLS */ ++ CHANSW_PROXD = 27, /* channel switch due to PROXD */ ++ CHANSW_MAX_NUMBER = 28 /* max channel switch reason */ ++} wl_chansw_reason_t; ++ ++#define CHANSW_REASON(reason) (1 << reason) ++ ++#define EVENT_AGGR_DATA_HDR_LEN 8 ++ ++typedef struct event_aggr_data { ++ uint16 num_events; /* No of events aggregated */ ++ uint16 len; /* length of the aggregated events, excludes padding */ ++ uint8 pad[4]; /* Padding to make aggr event packet header aligned ++ * on 64-bit boundary, for a 64-bit host system. ++ */ ++ uint8 data[]; /* Aggregate buffer containing Events */ ++} event_aggr_data_t; ++ ++ ++/* WLC_E_TVPM_MITIGATION event structure version */ ++#define WL_TVPM_MITIGATION_VERSION 1 ++ ++/* TVPM mitigation on/off status bits */ ++#define WL_TVPM_MITIGATION_TXDC 0x1 ++#define WL_TVPM_MITIGATION_TXPOWER 0x2 ++#define WL_TVPM_MITIGATION_TXCHAINS 0x4 ++ ++/* Event structure for WLC_E_TVPM_MITIGATION */ ++typedef struct wl_event_tvpm_mitigation { ++ uint16 version; /* structure version */ ++ uint16 length; /* length of this structure */ ++ uint32 timestamp_ms; /* millisecond timestamp */ ++ uint8 slice; /* slice number */ ++ uint8 pad; ++ uint16 on_off; /* mitigation status bits */ ++} wl_event_tvpm_mitigation_t; ++ ++#endif /* _BCMEVENT_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmip.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmip.h +new file mode 100644 +index 000000000..47781a25a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmip.h +@@ -0,0 +1,264 @@ ++/* ++ * Fundamental constants relating to IP Protocol ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmip.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _bcmip_h_ ++#define _bcmip_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* IPV4 and IPV6 common */ ++#define IP_VER_OFFSET 0x0 /* offset to version field */ ++#define IP_VER_MASK 0xf0 /* version mask */ ++#define IP_VER_SHIFT 4 /* version shift */ ++#define IP_VER_4 4 /* version number for IPV4 */ ++#define IP_VER_6 6 /* version number for IPV6 */ ++ ++#define IP_VER(ip_body) \ ++ ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) ++ ++#define IP_PROT_ICMP 0x1 /* ICMP protocol */ ++#define IP_PROT_IGMP 0x2 /* IGMP protocol */ ++#define IP_PROT_TCP 0x6 /* TCP protocol */ ++#define IP_PROT_UDP 0x11 /* UDP protocol type */ ++#define IP_PROT_GRE 0x2f /* GRE protocol type */ ++#define IP_PROT_ICMP6 0x3a /* ICMPv6 protocol type */ ++ ++/* IPV4 field offsets */ ++#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ ++#define IPV4_TOS_OFFSET 1 /* type of service offset */ ++#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */ ++#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */ ++#define IPV4_PROT_OFFSET 9 /* protocol type offset */ ++#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ ++#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ ++#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ ++#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */ ++#define IPV4_MIN_HEADER_LEN 20 /* Minimum size for an IP header (no options) */ ++ ++/* IPV4 field decodes */ ++#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ ++#define IPV4_VER_SHIFT 4 /* IPV4 version shift */ ++ ++#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */ ++#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) ++ ++#define IPV4_ADDR_LEN 4 /* IPV4 address length */ ++ ++#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ ++ ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) ++ ++#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ ++ ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) ++ ++#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */ ++#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */ ++ ++#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) ++ ++#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */ ++#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */ ++ ++#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */ ++#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */ ++#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */ ++ ++#define IPV4_TOS_ROUTINE 0 ++#define IPV4_TOS_PRIORITY 1 ++#define IPV4_TOS_IMMEDIATE 2 ++#define IPV4_TOS_FLASH 3 ++#define IPV4_TOS_FLASHOVERRIDE 4 ++#define IPV4_TOS_CRITICAL 5 ++#define IPV4_TOS_INETWORK_CTRL 6 ++#define IPV4_TOS_NETWORK_CTRL 7 ++ ++#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) ++ ++#define IPV4_FRAG_RESV 0x8000 /* Reserved */ ++#define IPV4_FRAG_DONT 0x4000 /* Don't fragment */ ++#define IPV4_FRAG_MORE 0x2000 /* More fragments */ ++#define IPV4_FRAG_OFFSET_MASK 0x1fff /* Fragment offset */ ++ ++#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */ ++ ++/* IPV4 packet formats */ ++BWL_PRE_PACKED_STRUCT struct ipv4_addr { ++ uint8 addr[IPV4_ADDR_LEN]; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct ipv4_hdr { ++ uint8 version_ihl; /* Version and Internet Header Length */ ++ uint8 tos; /* Type Of Service */ ++ uint16 tot_len; /* Number of bytes in packet (max 65535) */ ++ uint16 id; ++ uint16 frag; /* 3 flag bits and fragment offset */ ++ uint8 ttl; /* Time To Live */ ++ uint8 prot; /* Protocol */ ++ uint16 hdr_chksum; /* IP header checksum */ ++ uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ ++ uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ ++} BWL_POST_PACKED_STRUCT; ++ ++#define HTYPE_ETHERNET 1 /* htype for ethernet */ ++#define ARP_OPC_REQUEST 1 /* ARP request */ ++#define ARP_OPC_REPLY 2 /* ARP reply */ ++BWL_PRE_PACKED_STRUCT struct bcmarp { ++ uint16 htype; /* Header type (1 = ethernet) */ ++ uint16 ptype; /* Protocol type (0x800 = IP) */ ++ uint8 hlen; /* Hardware address length (Eth = 6) */ ++ uint8 plen; /* Protocol address length (IP = 4) */ ++ uint16 oper; /* ARP_OPC_... */ ++ uint8 src_eth[ETHER_ADDR_LEN]; /* Source hardware address */ ++ uint8 src_ip[IPV4_ADDR_LEN]; /* Source protocol address (not aligned) */ ++ uint8 dst_eth[ETHER_ADDR_LEN]; /* Destination hardware address */ ++ uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination protocol address */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* IPV6 field offsets */ ++#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ ++#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ ++#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */ ++#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */ ++#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */ ++ ++/* IPV6 field decodes */ ++#define IPV6_TRAFFIC_CLASS(ipv6_body) \ ++ (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ ++ ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) ++ ++#define IPV6_FLOW_LABEL(ipv6_body) \ ++ (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ ++ (((uint8 *)(ipv6_body))[2] << 8) | \ ++ (((uint8 *)(ipv6_body))[3])) ++ ++#define IPV6_PAYLOAD_LEN(ipv6_body) \ ++ ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ ++ ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) ++ ++#define IPV6_NEXT_HDR(ipv6_body) \ ++ (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) ++ ++#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) ++ ++#define IPV6_ADDR_LEN 16 /* IPV6 address length */ ++ ++/* IPV4 TOS or IPV6 Traffic Classifier or 0 */ ++#define IP_TOS46(ip_body) \ ++ (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ ++ IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) ++ ++#define IP_DSCP46(ip_body) (IP_TOS46(ip_body) >> IPV4_TOS_DSCP_SHIFT); ++ ++/* IPV4 or IPV6 Protocol Classifier or 0 */ ++#define IP_PROT46(ip_body) \ ++ (IP_VER(ip_body) == IP_VER_4 ? IPV4_PROT(ip_body) : \ ++ IP_VER(ip_body) == IP_VER_6 ? IPV6_PROT(ip_body) : 0) ++ ++/* IPV6 extension headers (options) */ ++#define IPV6_EXTHDR_HOP 0 ++#define IPV6_EXTHDR_ROUTING 43 ++#define IPV6_EXTHDR_FRAGMENT 44 ++#define IPV6_EXTHDR_AUTH 51 ++#define IPV6_EXTHDR_NONE 59 ++#define IPV6_EXTHDR_DEST 60 ++ ++#define IPV6_EXTHDR(prot) (((prot) == IPV6_EXTHDR_HOP) || \ ++ ((prot) == IPV6_EXTHDR_ROUTING) || \ ++ ((prot) == IPV6_EXTHDR_FRAGMENT) || \ ++ ((prot) == IPV6_EXTHDR_AUTH) || \ ++ ((prot) == IPV6_EXTHDR_NONE) || \ ++ ((prot) == IPV6_EXTHDR_DEST)) ++ ++#define IPV6_MIN_HLEN 40 ++ ++#define IPV6_EXTHDR_LEN(eh) ((((struct ipv6_exthdr *)(eh))->hdrlen + 1) << 3) ++ ++BWL_PRE_PACKED_STRUCT struct ipv6_exthdr { ++ uint8 nexthdr; ++ uint8 hdrlen; ++} BWL_POST_PACKED_STRUCT; ++ ++BWL_PRE_PACKED_STRUCT struct ipv6_exthdr_frag { ++ uint8 nexthdr; ++ uint8 rsvd; ++ uint16 frag_off; ++ uint32 ident; ++} BWL_POST_PACKED_STRUCT; ++ ++static INLINE int32 ++ipv6_exthdr_len(uint8 *h, uint8 *proto) ++{ ++ uint16 len = 0, hlen; ++ struct ipv6_exthdr *eh = (struct ipv6_exthdr *)h; ++ ++ while (IPV6_EXTHDR(eh->nexthdr)) { ++ if (eh->nexthdr == IPV6_EXTHDR_NONE) ++ return -1; ++ else if (eh->nexthdr == IPV6_EXTHDR_FRAGMENT) ++ hlen = 8; ++ else if (eh->nexthdr == IPV6_EXTHDR_AUTH) ++ hlen = (eh->hdrlen + 2) << 2; ++ else ++ hlen = IPV6_EXTHDR_LEN(eh); ++ ++ len += hlen; ++ eh = (struct ipv6_exthdr *)(h + len); ++ } ++ ++ *proto = eh->nexthdr; ++ return len; ++} ++ ++#define IPV4_ISMULTI(a) (((a) & 0xf0000000) == 0xe0000000) ++ ++#define IPV4_MCAST_TO_ETHER_MCAST(ipv4, ether) \ ++{ \ ++ ether[0] = 0x01; \ ++ ether[1] = 0x00; \ ++ ether[2] = 0x5E; \ ++ ether[3] = (ipv4 & 0x7f0000) >> 16; \ ++ ether[4] = (ipv4 & 0xff00) >> 8; \ ++ ether[5] = (ipv4 & 0xff); \ ++} ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#define IPV4_ADDR_STR "%d.%d.%d.%d" ++#define IPV4_ADDR_TO_STR(addr) ((uint32)addr & 0xff000000) >> 24, \ ++ ((uint32)addr & 0x00ff0000) >> 16, \ ++ ((uint32)addr & 0x0000ff00) >> 8, \ ++ ((uint32)addr & 0x000000ff) ++ ++#endif /* _bcmip_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmipv6.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmipv6.h +new file mode 100644 +index 000000000..84e2b693b +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmipv6.h +@@ -0,0 +1,163 @@ ++/* ++ * Fundamental constants relating to Neighbor Discovery Protocol ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmipv6.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _bcmipv6_h_ ++#define _bcmipv6_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++/* Extension headers */ ++#define IPV6_EXT_HOP 0 ++#define IPV6_EXT_ROUTE 43 ++#define IPV6_EXT_FRAG 44 ++#define IPV6_EXT_DEST 60 ++#define IPV6_EXT_ESEC 50 ++#define IPV6_EXT_AUTH 51 ++ ++/* Minimum size (extension header "word" length) */ ++#define IPV6_EXT_WORD 8 ++ ++/* Offsets for most extension headers */ ++#define IPV6_EXT_NEXTHDR 0 ++#define IPV6_EXT_HDRLEN 1 ++ ++/* Constants specific to fragmentation header */ ++#define IPV6_FRAG_MORE_MASK 0x0001 ++#define IPV6_FRAG_MORE_SHIFT 0 ++#define IPV6_FRAG_OFFS_MASK 0xfff8 ++#define IPV6_FRAG_OFFS_SHIFT 3 ++ ++/* For icmpv6 */ ++#define ICMPV6_HEADER_TYPE 0x3A ++#define ICMPV6_PKT_TYPE_RA 134 ++#define ICMPV6_PKT_TYPE_NS 135 ++#define ICMPV6_PKT_TYPE_NA 136 ++ ++#define ICMPV6_ND_OPT_TYPE_TARGET_MAC 2 ++#define ICMPV6_ND_OPT_TYPE_SRC_MAC 1 ++ ++#define ICMPV6_ND_OPT_LEN_LINKADDR 1 ++ ++#define ICMPV6_ND_OPT_LEN_LINKADDR 1 ++ ++#define IPV6_VERSION 6 ++#define IPV6_HOP_LIMIT 255 ++ ++#define IPV6_ADDR_NULL(a) ((a[0] | a[1] | a[2] | a[3] | a[4] | \ ++ a[5] | a[6] | a[7] | a[8] | a[9] | \ ++ a[10] | a[11] | a[12] | a[13] | \ ++ a[14] | a[15]) == 0) ++ ++#define IPV6_ADDR_LOCAL(a) (((a[0] == 0xfe) && (a[1] & 0x80))? TRUE: FALSE) ++ ++/* IPV6 address */ ++BWL_PRE_PACKED_STRUCT struct ipv6_addr { ++ uint8 addr[16]; ++} BWL_POST_PACKED_STRUCT; ++ ++ ++/* ICMPV6 Header */ ++BWL_PRE_PACKED_STRUCT struct icmp6_hdr { ++ uint8 icmp6_type; ++ uint8 icmp6_code; ++ uint16 icmp6_cksum; ++ BWL_PRE_PACKED_STRUCT union { ++ uint32 reserved; ++ BWL_PRE_PACKED_STRUCT struct nd_advt { ++ uint32 reserved1:5, ++ override:1, ++ solicited:1, ++ router:1, ++ reserved2:24; ++ } BWL_POST_PACKED_STRUCT nd_advt; ++ } BWL_POST_PACKED_STRUCT opt; ++} BWL_POST_PACKED_STRUCT; ++ ++/* Ipv6 Header Format */ ++BWL_PRE_PACKED_STRUCT struct ipv6_hdr { ++ uint8 priority:4, ++ version:4; ++ uint8 flow_lbl[3]; ++ uint16 payload_len; ++ uint8 nexthdr; ++ uint8 hop_limit; ++ struct ipv6_addr saddr; ++ struct ipv6_addr daddr; ++} BWL_POST_PACKED_STRUCT; ++ ++/* Neighbor Advertisement/Solicitation Packet Structure */ ++BWL_PRE_PACKED_STRUCT struct bcm_nd_msg { ++ struct icmp6_hdr icmph; ++ struct ipv6_addr target; ++} BWL_POST_PACKED_STRUCT; ++ ++ ++/* Neighibor Solicitation/Advertisement Optional Structure */ ++BWL_PRE_PACKED_STRUCT struct nd_msg_opt { ++ uint8 type; ++ uint8 len; ++ uint8 mac_addr[ETHER_ADDR_LEN]; ++} BWL_POST_PACKED_STRUCT; ++ ++/* Ipv6 Fragmentation Header */ ++BWL_PRE_PACKED_STRUCT struct ipv6_frag { ++ uint8 nexthdr; ++ uint8 reserved; ++ uint16 frag_offset; ++ uint32 ident; ++} BWL_POST_PACKED_STRUCT; ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++static const struct ipv6_addr all_node_ipv6_maddr = { ++ { 0xff, 0x2, 0, 0, ++ 0, 0, 0, 0, ++ 0, 0, 0, 0, ++ 0, 0, 0, 1 ++ }}; ++ ++#define IPV6_ISMULTI(a) (a[0] == 0xff) ++ ++#define IPV6_MCAST_TO_ETHER_MCAST(ipv6, ether) \ ++{ \ ++ ether[0] = 0x33; \ ++ ether[1] = 0x33; \ ++ ether[2] = ipv6[12]; \ ++ ether[3] = ipv6[13]; \ ++ ether[4] = ipv6[14]; \ ++ ether[5] = ipv6[15]; \ ++} ++ ++#endif /* !defined(_bcmipv6_h_) */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h +new file mode 100644 +index 000000000..08d66930d +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h +@@ -0,0 +1,1202 @@ ++/* ++ * MSGBUF network driver ioctl/indication encoding ++ * Broadcom 802.11abg Networking Device Driver ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmmsgbuf.h 676811 2016-12-24 20:48:46Z $ ++ */ ++#ifndef _bcmmsgbuf_h_ ++#define _bcmmsgbuf_h_ ++ ++#include ++#include ++#include ++ ++#define MSGBUF_MAX_MSG_SIZE ETHER_MAX_LEN ++ ++#define D2H_EPOCH_MODULO 253 /* sequence number wrap */ ++#define D2H_EPOCH_INIT_VAL (D2H_EPOCH_MODULO + 1) ++ ++#define H2D_EPOCH_MODULO 253 /* sequence number wrap */ ++#define H2D_EPOCH_INIT_VAL (H2D_EPOCH_MODULO + 1) ++ ++#define H2DRING_TXPOST_ITEMSIZE 48 ++#define H2DRING_RXPOST_ITEMSIZE 32 ++#define H2DRING_CTRL_SUB_ITEMSIZE 40 ++ ++#define D2HRING_TXCMPLT_ITEMSIZE 24 ++#define D2HRING_RXCMPLT_ITEMSIZE 40 ++ ++#define D2HRING_TXCMPLT_ITEMSIZE_PREREV7 16 ++#define D2HRING_RXCMPLT_ITEMSIZE_PREREV7 32 ++ ++#define D2HRING_CTRL_CMPLT_ITEMSIZE 24 ++#define H2DRING_INFO_BUFPOST_ITEMSIZE H2DRING_CTRL_SUB_ITEMSIZE ++#define D2HRING_INFO_BUFCMPLT_ITEMSIZE D2HRING_CTRL_CMPLT_ITEMSIZE ++ ++#define H2DRING_TXPOST_MAX_ITEM 512 ++#define H2DRING_RXPOST_MAX_ITEM 512 ++#define H2DRING_CTRL_SUB_MAX_ITEM 64 ++#define D2HRING_TXCMPLT_MAX_ITEM 1024 ++#define D2HRING_RXCMPLT_MAX_ITEM 512 ++ ++#define H2DRING_DYNAMIC_INFO_MAX_ITEM 32 ++#define D2HRING_DYNAMIC_INFO_MAX_ITEM 32 ++ ++#define D2HRING_CTRL_CMPLT_MAX_ITEM 64 ++ ++enum { ++ DNGL_TO_HOST_MSGBUF, ++ HOST_TO_DNGL_MSGBUF ++}; ++ ++enum { ++ HOST_TO_DNGL_TXP_DATA, ++ HOST_TO_DNGL_RXP_DATA, ++ HOST_TO_DNGL_CTRL, ++ DNGL_TO_HOST_DATA, ++ DNGL_TO_HOST_CTRL ++}; ++ ++#define MESSAGE_PAYLOAD(a) (a & MSG_TYPE_INTERNAL_USE_START) ? TRUE : FALSE ++#define PCIEDEV_FIRMWARE_TSINFO 0x1 ++ ++#ifdef PCIE_API_REV1 ++ ++#define BCMMSGBUF_DUMMY_REF(a, b) do {BCM_REFERENCE((a));BCM_REFERENCE((b));} while (0) ++ ++#define BCMMSGBUF_API_IFIDX(a) 0 ++#define BCMMSGBUF_API_SEQNUM(a) 0 ++#define BCMMSGBUF_IOCTL_XTID(a) 0 ++#define BCMMSGBUF_IOCTL_PKTID(a) ((a)->cmd_id) ++ ++#define BCMMSGBUF_SET_API_IFIDX(a, b) BCMMSGBUF_DUMMY_REF(a, b) ++#define BCMMSGBUF_SET_API_SEQNUM(a, b) BCMMSGBUF_DUMMY_REF(a, b) ++#define BCMMSGBUF_IOCTL_SET_PKTID(a, b) (BCMMSGBUF_IOCTL_PKTID(a) = (b)) ++#define BCMMSGBUF_IOCTL_SET_XTID(a, b) BCMMSGBUF_DUMMY_REF(a, b) ++ ++#else /* PCIE_API_REV1 */ ++ ++#define BCMMSGBUF_API_IFIDX(a) ((a)->if_id) ++#define BCMMSGBUF_IOCTL_PKTID(a) ((a)->pkt_id) ++#define BCMMSGBUF_API_SEQNUM(a) ((a)->u.seq.seq_no) ++#define BCMMSGBUF_IOCTL_XTID(a) ((a)->xt_id) ++ ++#define BCMMSGBUF_SET_API_IFIDX(a, b) (BCMMSGBUF_API_IFIDX((a)) = (b)) ++#define BCMMSGBUF_SET_API_SEQNUM(a, b) (BCMMSGBUF_API_SEQNUM((a)) = (b)) ++#define BCMMSGBUF_IOCTL_SET_PKTID(a, b) (BCMMSGBUF_IOCTL_PKTID((a)) = (b)) ++#define BCMMSGBUF_IOCTL_SET_XTID(a, b) (BCMMSGBUF_IOCTL_XTID((a)) = (b)) ++ ++#endif /* PCIE_API_REV1 */ ++ ++/* utility data structures */ ++ ++union addr64 { ++ struct { ++ uint32 low; ++ uint32 high; ++ }; ++ struct { ++ uint32 low_addr; ++ uint32 high_addr; ++ }; ++ uint64 u64; ++} DECLSPEC_ALIGN(8); ++ ++typedef union addr64 bcm_addr64_t; ++ ++/* IOCTL req Hdr */ ++/* cmn Msg Hdr */ ++typedef struct cmn_msg_hdr { ++ /** message type */ ++ uint8 msg_type; ++ /** interface index this is valid for */ ++ uint8 if_id; ++ /* flags */ ++ uint8 flags; ++ /** sequence number */ ++ uint8 epoch; ++ /** packet Identifier for the associated host buffer */ ++ uint32 request_id; ++} cmn_msg_hdr_t; ++ ++/** message type */ ++typedef enum bcmpcie_msgtype { ++ MSG_TYPE_GEN_STATUS = 0x1, ++ MSG_TYPE_RING_STATUS = 0x2, ++ MSG_TYPE_FLOW_RING_CREATE = 0x3, ++ MSG_TYPE_FLOW_RING_CREATE_CMPLT = 0x4, ++ /* Enum value as copied from BISON 7.15: new generic message */ ++ MSG_TYPE_RING_CREATE_CMPLT = 0x4, ++ MSG_TYPE_FLOW_RING_DELETE = 0x5, ++ MSG_TYPE_FLOW_RING_DELETE_CMPLT = 0x6, ++ /* Enum value as copied from BISON 7.15: new generic message */ ++ MSG_TYPE_RING_DELETE_CMPLT = 0x6, ++ MSG_TYPE_FLOW_RING_FLUSH = 0x7, ++ MSG_TYPE_FLOW_RING_FLUSH_CMPLT = 0x8, ++ MSG_TYPE_IOCTLPTR_REQ = 0x9, ++ MSG_TYPE_IOCTLPTR_REQ_ACK = 0xA, ++ MSG_TYPE_IOCTLRESP_BUF_POST = 0xB, ++ MSG_TYPE_IOCTL_CMPLT = 0xC, ++ MSG_TYPE_EVENT_BUF_POST = 0xD, ++ MSG_TYPE_WL_EVENT = 0xE, ++ MSG_TYPE_TX_POST = 0xF, ++ MSG_TYPE_TX_STATUS = 0x10, ++ MSG_TYPE_RXBUF_POST = 0x11, ++ MSG_TYPE_RX_CMPLT = 0x12, ++ MSG_TYPE_LPBK_DMAXFER = 0x13, ++ MSG_TYPE_LPBK_DMAXFER_CMPLT = 0x14, ++ MSG_TYPE_FLOW_RING_RESUME = 0x15, ++ MSG_TYPE_FLOW_RING_RESUME_CMPLT = 0x16, ++ MSG_TYPE_FLOW_RING_SUSPEND = 0x17, ++ MSG_TYPE_FLOW_RING_SUSPEND_CMPLT = 0x18, ++ MSG_TYPE_INFO_BUF_POST = 0x19, ++ MSG_TYPE_INFO_BUF_CMPLT = 0x1A, ++ MSG_TYPE_H2D_RING_CREATE = 0x1B, ++ MSG_TYPE_D2H_RING_CREATE = 0x1C, ++ MSG_TYPE_H2D_RING_CREATE_CMPLT = 0x1D, ++ MSG_TYPE_D2H_RING_CREATE_CMPLT = 0x1E, ++ MSG_TYPE_H2D_RING_CONFIG = 0x1F, ++ MSG_TYPE_D2H_RING_CONFIG = 0x20, ++ MSG_TYPE_H2D_RING_CONFIG_CMPLT = 0x21, ++ MSG_TYPE_D2H_RING_CONFIG_CMPLT = 0x22, ++ MSG_TYPE_H2D_MAILBOX_DATA = 0x23, ++ MSG_TYPE_D2H_MAILBOX_DATA = 0x24, ++ MSG_TYPE_TIMSTAMP_BUFPOST = 0x25, ++ MSG_TYPE_HOSTTIMSTAMP = 0x26, ++ MSG_TYPE_HOSTTIMSTAMP_CMPLT = 0x27, ++ MSG_TYPE_FIRMWARE_TIMESTAMP = 0x28, ++ MSG_TYPE_API_MAX_RSVD = 0x3F ++} bcmpcie_msg_type_t; ++ ++typedef enum bcmpcie_msgtype_int { ++ MSG_TYPE_INTERNAL_USE_START = 0x40, ++ MSG_TYPE_EVENT_PYLD = 0x41, ++ MSG_TYPE_IOCT_PYLD = 0x42, ++ MSG_TYPE_RX_PYLD = 0x43, ++ MSG_TYPE_HOST_FETCH = 0x44, ++ MSG_TYPE_LPBK_DMAXFER_PYLD = 0x45, ++ MSG_TYPE_TXMETADATA_PYLD = 0x46, ++ MSG_TYPE_INDX_UPDATE = 0x47, ++ MSG_TYPE_INFO_PYLD = 0x48, ++ MSG_TYPE_TS_EVENT_PYLD = 0x49 ++} bcmpcie_msgtype_int_t; ++ ++typedef enum bcmpcie_msgtype_u { ++ MSG_TYPE_TX_BATCH_POST = 0x80, ++ MSG_TYPE_IOCTL_REQ = 0x81, ++ MSG_TYPE_HOST_EVNT = 0x82, /* console related */ ++ MSG_TYPE_LOOPBACK = 0x83 ++} bcmpcie_msgtype_u_t; ++ ++/** ++ * D2H ring host wakeup soft doorbell, override the PCIE doorbell. ++ * Host configures an <32bit address,value> tuple, and dongle uses SBTOPCIE ++ * Transl0 to write specified value to host address. ++ * ++ * Use case: 32bit Address mapped to HW Accelerator Core/Thread Wakeup Register ++ * and value is Core/Thread context. Host will ensure routing the 32bit address ++ * offerred to PCIE to the mapped register. ++ * ++ * D2H_RING_CONFIG_SUBTYPE_SOFT_DOORBELL ++ */ ++typedef struct bcmpcie_soft_doorbell { ++ uint32 value; /* host defined value to be written, eg HW threadid */ ++ bcm_addr64_t haddr; /* host address, eg thread wakeup register address */ ++ uint16 items; /* interrupt coalescing: item count before wakeup */ ++ uint16 msecs; /* interrupt coalescing: timeout in millisecs */ ++} bcmpcie_soft_doorbell_t; ++ ++/** ++ * D2H interrupt using MSI instead of INTX ++ * Host configures MSI vector offset for each D2H interrupt ++ * ++ * D2H_RING_CONFIG_SUBTYPE_MSI_DOORBELL ++ */ ++typedef enum bcmpcie_msi_intr_idx { ++ MSI_INTR_IDX_CTRL_CMPL_RING, ++ MSI_INTR_IDX_TXP_CMPL_RING, ++ MSI_INTR_IDX_RXP_CMPL_RING, ++ MSI_INTR_IDX_MAILBOX, ++ MSI_INTR_IDX_MAX ++} bcmpcie_msi_intr_idx_t; ++ ++typedef enum bcmpcie_msi_offset_type { ++ BCMPCIE_D2H_MSI_OFFSET_MB0 = 2, ++ BCMPCIE_D2H_MSI_OFFSET_MB1, ++ BCMPCIE_D2H_MSI_OFFSET_DB0, ++ BCMPCIE_D2H_MSI_OFFSET_DB1, ++ BCMPCIE_D2H_MSI_OFFSET_MAX ++} bcmpcie_msi_offset_type_t; ++ ++typedef struct bcmpcie_msi_offset { ++ uint16 intr_idx; /* interrupt index */ ++ uint16 msi_offset; /* msi vector offset */ ++} bcmpcie_msi_offset_t; ++ ++typedef struct bcmpcie_msi_offset_config { ++ uint32 len; ++ bcmpcie_msi_offset_t bcmpcie_msi_offset[MSI_INTR_IDX_MAX]; ++} bcmpcie_msi_offset_config_t; ++ ++#define BCMPCIE_D2H_MSI_OFFSET_DEFAULT BCMPCIE_D2H_MSI_OFFSET_DB1 ++ ++ ++/* if_id */ ++#define BCMPCIE_CMNHDR_IFIDX_PHYINTF_SHFT 5 ++#define BCMPCIE_CMNHDR_IFIDX_PHYINTF_MAX 0x7 ++#define BCMPCIE_CMNHDR_IFIDX_PHYINTF_MASK \ ++ (BCMPCIE_CMNHDR_IFIDX_PHYINTF_MAX << BCMPCIE_CMNHDR_IFIDX_PHYINTF_SHFT) ++#define BCMPCIE_CMNHDR_IFIDX_VIRTINTF_SHFT 0 ++#define BCMPCIE_CMNHDR_IFIDX_VIRTINTF_MAX 0x1F ++#define BCMPCIE_CMNHDR_IFIDX_VIRTINTF_MASK \ ++ (BCMPCIE_CMNHDR_IFIDX_PHYINTF_MAX << BCMPCIE_CMNHDR_IFIDX_PHYINTF_SHFT) ++ ++/* flags */ ++#define BCMPCIE_CMNHDR_FLAGS_DMA_R_IDX 0x1 ++#define BCMPCIE_CMNHDR_FLAGS_DMA_R_IDX_INTR 0x2 ++#define BCMPCIE_CMNHDR_FLAGS_PHASE_BIT 0x80 ++#define BCMPCIE_CMNHDR_PHASE_BIT_INIT 0x80 ++ ++/* IOCTL request message */ ++typedef struct ioctl_req_msg { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** ioctl command type */ ++ uint32 cmd; ++ /** ioctl transaction ID, to pair with a ioctl response */ ++ uint16 trans_id; ++ /** input arguments buffer len */ ++ uint16 input_buf_len; ++ /** expected output len */ ++ uint16 output_buf_len; ++ /** to align the host address on 8 byte boundary */ ++ uint16 rsvd[3]; ++ /** always align on 8 byte boundary */ ++ bcm_addr64_t host_input_buf_addr; ++ /* rsvd */ ++ uint32 rsvd1[2]; ++} ioctl_req_msg_t; ++ ++/** buffer post messages for device to use to return IOCTL responses, Events */ ++typedef struct ioctl_resp_evt_buf_post_msg { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** length of the host buffer supplied */ ++ uint16 host_buf_len; ++ /** to align the host address on 8 byte boundary */ ++ uint16 reserved[3]; ++ /** always align on 8 byte boundary */ ++ bcm_addr64_t host_buf_addr; ++ uint32 rsvd[4]; ++} ioctl_resp_evt_buf_post_msg_t; ++ ++/* buffer post messages for device to use to return dbg buffers */ ++typedef ioctl_resp_evt_buf_post_msg_t info_buf_post_msg_t; ++ ++ ++/* An infobuf host buffer starts with a 32 bit (LE) version. */ ++#define PCIE_INFOBUF_V1 1 ++/* Infobuf v1 type MSGTRACE's data is exactly the same as the MSGTRACE data that ++ * is wrapped previously/also in a WLC_E_TRACE event. See structure ++ * msgrace_hdr_t in msgtrace.h. ++*/ ++#define PCIE_INFOBUF_V1_TYPE_MSGTRACE 1 ++ ++/* Infobuf v1 type LOGTRACE data is exactly the same as the LOGTRACE data that ++ * is wrapped previously/also in a WLC_E_TRACE event. See structure ++ * msgrace_hdr_t in msgtrace.h. (The only difference between a MSGTRACE ++ * and a LOGTRACE is the "trace type" field.) ++*/ ++#define PCIE_INFOBUF_V1_TYPE_LOGTRACE 2 ++ ++/* An infobuf version 1 host buffer has a single TLV. The information on the ++ * version 1 types follow this structure definition. (int's LE) ++*/ ++typedef struct info_buf_payload_hdr_s { ++ uint16 type; ++ uint16 length; ++} info_buf_payload_hdr_t; ++ ++#define PCIE_DMA_XFER_FLG_D11_LPBK_MASK 0x00000001 ++#define PCIE_DMA_XFER_FLG_D11_LPBK_SHIFT 0 ++ ++typedef struct pcie_dma_xfer_params { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ ++ /** always align on 8 byte boundary */ ++ bcm_addr64_t host_input_buf_addr; ++ ++ /** always align on 8 byte boundary */ ++ bcm_addr64_t host_ouput_buf_addr; ++ ++ /** length of transfer */ ++ uint32 xfer_len; ++ /** delay before doing the src txfer */ ++ uint32 srcdelay; ++ /** delay before doing the dest txfer */ ++ uint32 destdelay; ++ uint8 rsvd[3]; ++ uint8 flags; ++} pcie_dma_xfer_params_t; ++ ++/** Complete msgbuf hdr for flow ring update from host to dongle */ ++typedef struct tx_flowring_create_request { ++ cmn_msg_hdr_t msg; ++ uint8 da[ETHER_ADDR_LEN]; ++ uint8 sa[ETHER_ADDR_LEN]; ++ uint8 tid; ++ uint8 if_flags; ++ uint16 flow_ring_id; ++ uint8 tc; ++ /* priority_ifrmmask is to define core mask in ifrm mode. ++ * currently it is not used for priority. so uses solely for ifrm mask ++ */ ++ uint8 priority_ifrmmask; ++ uint16 int_vector; ++ uint16 max_items; ++ uint16 len_item; ++ bcm_addr64_t flow_ring_ptr; ++} tx_flowring_create_request_t; ++ ++typedef struct tx_flowring_delete_request { ++ cmn_msg_hdr_t msg; ++ uint16 flow_ring_id; ++ uint16 reason; ++ uint32 rsvd[7]; ++} tx_flowring_delete_request_t; ++ ++typedef struct tx_flowring_flush_request { ++ cmn_msg_hdr_t msg; ++ uint16 flow_ring_id; ++ uint16 reason; ++ uint32 rsvd[7]; ++} tx_flowring_flush_request_t; ++ ++/** Subtypes for ring_config_req control message */ ++typedef enum ring_config_subtype { ++ /** Default D2H PCIE doorbell override using ring_config_req msg */ ++ D2H_RING_CONFIG_SUBTYPE_SOFT_DOORBELL = 1, /* Software doorbell */ ++ D2H_RING_CONFIG_SUBTYPE_MSI_DOORBELL = 2 /* MSI configuration */ ++} ring_config_subtype_t; ++ ++typedef struct ring_config_req { ++ cmn_msg_hdr_t msg; ++ uint16 subtype; ++ uint16 ring_id; ++ uint32 rsvd; ++ union { ++ uint32 data[6]; ++ /** D2H_RING_CONFIG_SUBTYPE_SOFT_DOORBELL */ ++ bcmpcie_soft_doorbell_t soft_doorbell; ++ /** D2H_RING_CONFIG_SUBTYPE_MSI_DOORBELL */ ++ bcmpcie_msi_offset_config_t msi_offset; ++ }; ++} ring_config_req_t; ++ ++/* data structure to use to create on the fly d2h rings */ ++typedef struct d2h_ring_create_req { ++ cmn_msg_hdr_t msg; ++ uint16 ring_id; ++ uint16 ring_type; ++ uint32 flags; ++ bcm_addr64_t ring_ptr; ++ uint16 max_items; ++ uint16 len_item; ++ uint32 rsvd[3]; ++} d2h_ring_create_req_t; ++ ++/* data structure to use to create on the fly h2d rings */ ++#define MAX_COMPLETION_RING_IDS_ASSOCIATED 4 ++typedef struct h2d_ring_create_req { ++ cmn_msg_hdr_t msg; ++ uint16 ring_id; ++ uint8 ring_type; ++ uint8 n_completion_ids; ++ uint32 flags; ++ bcm_addr64_t ring_ptr; ++ uint16 max_items; ++ uint16 len_item; ++ uint16 completion_ring_ids[MAX_COMPLETION_RING_IDS_ASSOCIATED]; ++ uint32 rsvd; ++} h2d_ring_create_req_t; ++ ++typedef struct d2h_ring_config_req { ++ cmn_msg_hdr_t msg; ++ uint16 d2h_ring_config_subtype; ++ uint16 d2h_ring_id; ++ uint32 d2h_ring_config_data[4]; ++ uint32 rsvd[3]; ++} d2h_ring_config_req_t; ++ ++typedef struct h2d_ring_config_req { ++ cmn_msg_hdr_t msg; ++ uint16 h2d_ring_config_subtype; ++ uint16 h2d_ring_id; ++ uint32 h2d_ring_config_data; ++ uint32 rsvd[6]; ++} h2d_ring_config_req_t; ++ ++typedef struct h2d_mailbox_data { ++ cmn_msg_hdr_t msg; ++ uint32 mail_box_data; ++ uint32 rsvd[7]; ++} h2d_mailbox_data_t; ++typedef struct host_timestamp_msg { ++ cmn_msg_hdr_t msg; ++ uint16 xt_id; /* transaction ID */ ++ uint16 input_data_len; /* data len at the host_buf_addr, data in TLVs */ ++ uint16 seqnum; /* number of times host captured the timestamp */ ++ uint16 rsvd; ++ /* always align on 8 byte boundary */ ++ bcm_addr64_t host_buf_addr; ++ /* rsvd */ ++ uint32 rsvd1[4]; ++} host_timestamp_msg_t; ++ ++/* buffer post message for timestamp events MSG_TYPE_TIMSTAMP_BUFPOST */ ++typedef ioctl_resp_evt_buf_post_msg_t ts_buf_post_msg_t; ++ ++typedef union ctrl_submit_item { ++ ioctl_req_msg_t ioctl_req; ++ ioctl_resp_evt_buf_post_msg_t resp_buf_post; ++ pcie_dma_xfer_params_t dma_xfer; ++ tx_flowring_create_request_t flow_create; ++ tx_flowring_delete_request_t flow_delete; ++ tx_flowring_flush_request_t flow_flush; ++ ring_config_req_t ring_config_req; ++ d2h_ring_create_req_t d2h_create; ++ h2d_ring_create_req_t h2d_create; ++ d2h_ring_config_req_t d2h_config; ++ h2d_ring_config_req_t h2d_config; ++ h2d_mailbox_data_t h2d_mailbox_data; ++ host_timestamp_msg_t host_ts; ++ ts_buf_post_msg_t ts_buf_post; ++ unsigned char check[H2DRING_CTRL_SUB_ITEMSIZE]; ++} ctrl_submit_item_t; ++ ++typedef struct info_ring_submit_item { ++ info_buf_post_msg_t info_buf_post; ++ unsigned char check[H2DRING_INFO_BUFPOST_ITEMSIZE]; ++} info_sumbit_item_t; ++ ++/** Control Completion messages (20 bytes) */ ++typedef struct compl_msg_hdr { ++ /** status for the completion */ ++ int16 status; ++ /** submisison flow ring id which generated this status */ ++ union { ++ uint16 ring_id; ++ uint16 flow_ring_id; ++ }; ++} compl_msg_hdr_t; ++ ++/** XOR checksum or a magic number to audit DMA done */ ++typedef uint32 dma_done_t; ++ ++#define MAX_CLKSRC_ID 0xF ++ ++typedef struct ts_timestamp_srcid { ++ union { ++ uint32 ts_low; /* time stamp low 32 bits */ ++ uint32 reserved; /* If timestamp not used */ ++ }; ++ union { ++ uint32 ts_high; /* time stamp high 28 bits */ ++ union { ++ uint32 ts_high_ext :28; /* time stamp high 28 bits */ ++ uint32 clk_id_ext :3; /* clock ID source */ ++ uint32 phase :1; /* Phase bit */ ++ dma_done_t marker_ext; ++ }; ++ }; ++} ts_timestamp_srcid_t; ++ ++typedef ts_timestamp_srcid_t ipc_timestamp_t; ++ ++typedef struct ts_timestamp { ++ uint32 low; ++ uint32 high; ++} ts_timestamp_t; ++ ++typedef ts_timestamp_t tick_count_64_t; ++typedef ts_timestamp_t ts_timestamp_ns_64_t; ++typedef ts_timestamp_t ts_correction_m_t; ++typedef ts_timestamp_t ts_correction_b_t; ++ ++/* completion header status codes */ ++#define BCMPCIE_SUCCESS 0 ++#define BCMPCIE_NOTFOUND 1 ++#define BCMPCIE_NOMEM 2 ++#define BCMPCIE_BADOPTION 3 ++#define BCMPCIE_RING_IN_USE 4 ++#define BCMPCIE_RING_ID_INVALID 5 ++#define BCMPCIE_PKT_FLUSH 6 ++#define BCMPCIE_NO_EVENT_BUF 7 ++#define BCMPCIE_NO_RX_BUF 8 ++#define BCMPCIE_NO_IOCTLRESP_BUF 9 ++#define BCMPCIE_MAX_IOCTLRESP_BUF 10 ++#define BCMPCIE_MAX_EVENT_BUF 11 ++#define BCMPCIE_BAD_PHASE 12 ++#define BCMPCIE_INVALID_CPL_RINGID 13 ++#define BCMPCIE_RING_TYPE_INVALID 14 ++#define BCMPCIE_NO_TS_EVENT_BUF 15 ++#define BCMPCIE_MAX_TS_EVENT_BUF 16 ++ ++/** IOCTL completion response */ ++typedef struct ioctl_compl_resp_msg { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ /** response buffer len where a host buffer is involved */ ++ uint16 resp_len; ++ /** transaction id to pair with a request */ ++ uint16 trans_id; ++ /** cmd id */ ++ uint32 cmd; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} ioctl_comp_resp_msg_t; ++ ++/** IOCTL request acknowledgement */ ++typedef struct ioctl_req_ack_msg { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ /** cmd id */ ++ uint32 cmd; ++ uint32 rsvd; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} ioctl_req_ack_msg_t; ++ ++/** WL event message: send from device to host */ ++typedef struct wlevent_req_msg { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ /** event data len valid with the event buffer */ ++ uint16 event_data_len; ++ /** sequence number */ ++ uint16 seqnum; ++ /** rsvd */ ++ uint32 rsvd; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} wlevent_req_msg_t; ++ ++/** dma xfer complete message */ ++typedef struct pcie_dmaxfer_cmplt { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ uint32 rsvd[2]; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} pcie_dmaxfer_cmplt_t; ++ ++/** general status message */ ++typedef struct pcie_gen_status { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ uint32 rsvd[2]; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} pcie_gen_status_t; ++ ++/** ring status message */ ++typedef struct pcie_ring_status { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ /** message which firmware couldn't decode */ ++ uint16 write_idx; ++ uint16 rsvd[3]; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} pcie_ring_status_t; ++ ++typedef struct ring_create_response { ++ cmn_msg_hdr_t cmn_hdr; ++ compl_msg_hdr_t cmplt; ++ uint32 rsvd[2]; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} ring_create_response_t; ++ ++typedef ring_create_response_t tx_flowring_create_response_t; ++typedef ring_create_response_t h2d_ring_create_response_t; ++typedef ring_create_response_t d2h_ring_create_response_t; ++ ++typedef struct tx_flowring_delete_response { ++ cmn_msg_hdr_t msg; ++ compl_msg_hdr_t cmplt; ++ uint32 rsvd[2]; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} tx_flowring_delete_response_t; ++ ++typedef struct tx_flowring_flush_response { ++ cmn_msg_hdr_t msg; ++ compl_msg_hdr_t cmplt; ++ uint32 rsvd[2]; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} tx_flowring_flush_response_t; ++ ++/** Common layout of all d2h control messages */ ++typedef struct ctrl_compl_msg { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ uint32 rsvd[2]; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} ctrl_compl_msg_t; ++ ++typedef struct ring_config_resp { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ uint32 rsvd[2]; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} ring_config_resp_t; ++ ++typedef struct d2h_mailbox_data { ++ cmn_msg_hdr_t msg; ++ compl_msg_hdr_t cmplt; ++ uint32 d2h_mailbox_data; ++ uint32 rsvd[1]; ++ /* XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} d2h_mailbox_data_t; ++ ++/* dbg buf completion msg: send from device to host */ ++typedef struct info_buf_resp { ++ /* common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /* completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ /* event data len valid with the event buffer */ ++ uint16 info_data_len; ++ /* sequence number */ ++ uint16 seqnum; ++ /* rsvd */ ++ uint32 rsvd; ++ /* XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} info_buf_resp_t; ++ ++typedef struct info_ring_cpl_item { ++ info_buf_resp_t info_buf_post; ++ unsigned char check[D2HRING_INFO_BUFCMPLT_ITEMSIZE]; ++} info_cpl_item_t; ++ ++typedef struct host_timestamp_msg_cpl { ++ cmn_msg_hdr_t msg; ++ compl_msg_hdr_t cmplt; ++ uint16 xt_id; /* transaction ID */ ++ uint16 rsvd; ++ uint32 rsvd1; ++ /* XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} host_timestamp_msg_cpl_t; ++ ++typedef struct fw_timestamp_event_msg { ++ cmn_msg_hdr_t msg; ++ compl_msg_hdr_t cmplt; ++ /* fw captures time stamp info and passed that to host in TLVs */ ++ uint16 buf_len; /* length of the time stamp data copied in host buf */ ++ uint16 seqnum; /* number of times fw captured time stamp */ ++ uint32 rsvd; ++ /* XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} fw_timestamp_event_msg_t; ++ ++typedef union ctrl_completion_item { ++ ioctl_comp_resp_msg_t ioctl_resp; ++ wlevent_req_msg_t event; ++ ioctl_req_ack_msg_t ioct_ack; ++ pcie_dmaxfer_cmplt_t pcie_xfer_cmplt; ++ pcie_gen_status_t pcie_gen_status; ++ pcie_ring_status_t pcie_ring_status; ++ tx_flowring_create_response_t txfl_create_resp; ++ tx_flowring_delete_response_t txfl_delete_resp; ++ tx_flowring_flush_response_t txfl_flush_resp; ++ ctrl_compl_msg_t ctrl_compl; ++ ring_config_resp_t ring_config_resp; ++ d2h_mailbox_data_t d2h_mailbox_data; ++ info_buf_resp_t dbg_resp; ++ h2d_ring_create_response_t h2d_ring_create_resp; ++ d2h_ring_create_response_t d2h_ring_create_resp; ++ host_timestamp_msg_cpl_t host_ts_cpl; ++ fw_timestamp_event_msg_t fw_ts_event; ++ unsigned char ctrl_response[D2HRING_CTRL_CMPLT_ITEMSIZE]; ++} ctrl_completion_item_t; ++ ++/** H2D Rxpost ring work items */ ++typedef struct host_rxbuf_post { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** provided meta data buffer len */ ++ uint16 metadata_buf_len; ++ /** provided data buffer len to receive data */ ++ uint16 data_buf_len; ++ /** alignment to make the host buffers start on 8 byte boundary */ ++ uint32 rsvd; ++ /** provided meta data buffer */ ++ bcm_addr64_t metadata_buf_addr; ++ /** provided data buffer to receive data */ ++ bcm_addr64_t data_buf_addr; ++} host_rxbuf_post_t; ++ ++typedef union rxbuf_submit_item { ++ host_rxbuf_post_t rxpost; ++ unsigned char check[H2DRING_RXPOST_ITEMSIZE]; ++} rxbuf_submit_item_t; ++ ++/* D2H Rxcompletion ring work items for IPC rev7 */ ++typedef struct host_rxbuf_cmpl { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ /** filled up meta data len */ ++ uint16 metadata_len; ++ /** filled up buffer len to receive data */ ++ uint16 data_len; ++ /** offset in the host rx buffer where the data starts */ ++ uint16 data_offset; ++ /** offset in the host rx buffer where the data starts */ ++ uint16 flags; ++ /** rx status */ ++ uint32 rx_status_0; ++ uint32 rx_status_1; ++ /** XOR checksum or a magic number to audit DMA done */ ++ /* This is for rev6 only. For IPC rev7, this is a reserved field */ ++ dma_done_t marker; ++ /* timestamp */ ++ ipc_timestamp_t ts; ++} host_rxbuf_cmpl_t; ++ ++typedef union rxbuf_complete_item { ++ host_rxbuf_cmpl_t rxcmpl; ++ unsigned char check[D2HRING_RXCMPLT_ITEMSIZE]; ++} rxbuf_complete_item_t; ++ ++ ++typedef struct host_txbuf_post { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** eth header */ ++ uint8 txhdr[ETHER_HDR_LEN]; ++ /** flags */ ++ uint8 flags; ++ /** number of segments */ ++ uint8 seg_cnt; ++ ++ /** provided meta data buffer for txstatus */ ++ bcm_addr64_t metadata_buf_addr; ++ /** provided data buffer to receive data */ ++ bcm_addr64_t data_buf_addr; ++ /** provided meta data buffer len */ ++ uint16 metadata_buf_len; ++ /** provided data buffer len to receive data */ ++ uint16 data_len; ++ /** XOR checksum or a magic number to audit DMA done */ ++ dma_done_t marker; ++} host_txbuf_post_t; ++ ++#define BCMPCIE_PKT_FLAGS_FRAME_802_3 0x01 ++#define BCMPCIE_PKT_FLAGS_FRAME_802_11 0x02 ++ ++#define BCMPCIE_PKT_FLAGS_FRAME_EXEMPT_MASK 0x03 /* Exempt uses 2 bits */ ++#define BCMPCIE_PKT_FLAGS_FRAME_EXEMPT_SHIFT 0x02 /* needs to be shifted past other bits */ ++ ++ ++#define BCMPCIE_PKT_FLAGS_PRIO_SHIFT 5 ++#define BCMPCIE_PKT_FLAGS_PRIO_MASK (7 << BCMPCIE_PKT_FLAGS_PRIO_SHIFT) ++#define BCMPCIE_PKT_FLAGS_MONITOR_NO_AMSDU 0x00 ++#define BCMPCIE_PKT_FLAGS_MONITOR_FIRST_PKT 0x01 ++#define BCMPCIE_PKT_FLAGS_MONITOR_INTER_PKT 0x02 ++#define BCMPCIE_PKT_FLAGS_MONITOR_LAST_PKT 0x03 ++#define BCMPCIE_PKT_FLAGS_MONITOR_SHIFT 8 ++#define BCMPCIE_PKT_FLAGS_MONITOR_MASK (3 << BCMPCIE_PKT_FLAGS_MONITOR_SHIFT) ++ ++/* These are added to fix up compile issues */ ++#define BCMPCIE_TXPOST_FLAGS_FRAME_802_3 BCMPCIE_PKT_FLAGS_FRAME_802_3 ++#define BCMPCIE_TXPOST_FLAGS_FRAME_802_11 BCMPCIE_PKT_FLAGS_FRAME_802_11 ++#define BCMPCIE_TXPOST_FLAGS_PRIO_SHIFT BCMPCIE_PKT_FLAGS_PRIO_SHIFT ++#define BCMPCIE_TXPOST_FLAGS_PRIO_MASK BCMPCIE_PKT_FLAGS_PRIO_MASK ++ ++ ++/* H2D Txpost ring work items */ ++typedef union txbuf_submit_item { ++ host_txbuf_post_t txpost; ++ unsigned char check[H2DRING_TXPOST_ITEMSIZE]; ++} txbuf_submit_item_t; ++ ++/* D2H Txcompletion ring work items - extended for IOC rev7 */ ++typedef struct host_txbuf_cmpl { ++ /** common message header */ ++ cmn_msg_hdr_t cmn_hdr; ++ /** completion message header */ ++ compl_msg_hdr_t compl_hdr; ++ union { ++ struct { ++ /** provided meta data len */ ++ uint16 metadata_len; ++ /** WLAN side txstatus */ ++ uint16 tx_status; ++ }; ++ /** XOR checksum or a magic number to audit DMA done */ ++ /* This is for rev6 only. For IPC rev7, this is not used */ ++ dma_done_t marker; ++ }; ++ /* timestamp */ ++ ipc_timestamp_t ts; ++ ++} host_txbuf_cmpl_t; ++ ++typedef union txbuf_complete_item { ++ host_txbuf_cmpl_t txcmpl; ++ unsigned char check[D2HRING_TXCMPLT_ITEMSIZE]; ++} txbuf_complete_item_t; ++ ++#define BCMPCIE_D2H_METADATA_HDRLEN 4 ++#define BCMPCIE_D2H_METADATA_MINLEN (BCMPCIE_D2H_METADATA_HDRLEN + 4) ++ ++/** ret buf struct */ ++typedef struct ret_buf_ptr { ++ uint32 low_addr; ++ uint32 high_addr; ++} ret_buf_t; ++ ++ ++#ifdef PCIE_API_REV1 ++ ++/* ioctl specific hdr */ ++typedef struct ioctl_hdr { ++ uint16 cmd; ++ uint16 retbuf_len; ++ uint32 cmd_id; ++} ioctl_hdr_t; ++ ++typedef struct ioctlptr_hdr { ++ uint16 cmd; ++ uint16 retbuf_len; ++ uint16 buflen; ++ uint16 rsvd; ++ uint32 cmd_id; ++} ioctlptr_hdr_t; ++ ++#else /* PCIE_API_REV1 */ ++ ++typedef struct ioctl_req_hdr { ++ uint32 pkt_id; /**< Packet ID */ ++ uint32 cmd; /**< IOCTL ID */ ++ uint16 retbuf_len; ++ uint16 buflen; ++ uint16 xt_id; /**< transaction ID */ ++ uint16 rsvd[1]; ++} ioctl_req_hdr_t; ++ ++#endif /* PCIE_API_REV1 */ ++ ++ ++/** Complete msgbuf hdr for ioctl from host to dongle */ ++typedef struct ioct_reqst_hdr { ++ cmn_msg_hdr_t msg; ++#ifdef PCIE_API_REV1 ++ ioctl_hdr_t ioct_hdr; ++#else ++ ioctl_req_hdr_t ioct_hdr; ++#endif ++ ret_buf_t ret_buf; ++} ioct_reqst_hdr_t; ++ ++typedef struct ioctptr_reqst_hdr { ++ cmn_msg_hdr_t msg; ++#ifdef PCIE_API_REV1 ++ ioctlptr_hdr_t ioct_hdr; ++#else ++ ioctl_req_hdr_t ioct_hdr; ++#endif ++ ret_buf_t ret_buf; ++ ret_buf_t ioct_buf; ++} ioctptr_reqst_hdr_t; ++ ++/** ioctl response header */ ++typedef struct ioct_resp_hdr { ++ cmn_msg_hdr_t msg; ++#ifdef PCIE_API_REV1 ++ uint32 cmd_id; ++#else ++ uint32 pkt_id; ++#endif ++ uint32 status; ++ uint32 ret_len; ++ uint32 inline_data; ++#ifdef PCIE_API_REV1 ++#else ++ uint16 xt_id; /**< transaction ID */ ++ uint16 rsvd[1]; ++#endif ++} ioct_resp_hdr_t; ++ ++/* ioct resp header used in dongle */ ++/* ret buf hdr will be stripped off inside dongle itself */ ++typedef struct msgbuf_ioctl_resp { ++ ioct_resp_hdr_t ioct_hdr; ++ ret_buf_t ret_buf; /**< ret buf pointers */ ++} msgbuf_ioct_resp_t; ++ ++/** WL event hdr info */ ++typedef struct wl_event_hdr { ++ cmn_msg_hdr_t msg; ++ uint16 event; ++ uint8 flags; ++ uint8 rsvd; ++ uint16 retbuf_len; ++ uint16 rsvd1; ++ uint32 rxbufid; ++} wl_event_hdr_t; ++ ++#define TXDESCR_FLOWID_PCIELPBK_1 0xFF ++#define TXDESCR_FLOWID_PCIELPBK_2 0xFE ++ ++typedef struct txbatch_lenptr_tup { ++ uint32 pktid; ++ uint16 pktlen; ++ uint16 rsvd; ++ ret_buf_t ret_buf; /**< ret buf pointers */ ++} txbatch_lenptr_tup_t; ++ ++typedef struct txbatch_cmn_msghdr { ++ cmn_msg_hdr_t msg; ++ uint8 priority; ++ uint8 hdrlen; ++ uint8 pktcnt; ++ uint8 flowid; ++ uint8 txhdr[ETHER_HDR_LEN]; ++ uint16 rsvd; ++} txbatch_cmn_msghdr_t; ++ ++typedef struct txbatch_msghdr { ++ txbatch_cmn_msghdr_t txcmn; ++ txbatch_lenptr_tup_t tx_tup[0]; /**< Based on packet count */ ++} txbatch_msghdr_t; ++ ++/* TX desc posting header */ ++typedef struct tx_lenptr_tup { ++ uint16 pktlen; ++ uint16 rsvd; ++ ret_buf_t ret_buf; /**< ret buf pointers */ ++} tx_lenptr_tup_t; ++ ++typedef struct txdescr_cmn_msghdr { ++ cmn_msg_hdr_t msg; ++ uint8 priority; ++ uint8 hdrlen; ++ uint8 descrcnt; ++ uint8 flowid; ++ uint32 pktid; ++} txdescr_cmn_msghdr_t; ++ ++typedef struct txdescr_msghdr { ++ txdescr_cmn_msghdr_t txcmn; ++ uint8 txhdr[ETHER_HDR_LEN]; ++ uint16 rsvd; ++ tx_lenptr_tup_t tx_tup[0]; /**< Based on descriptor count */ ++} txdescr_msghdr_t; ++ ++/** Tx status header info */ ++typedef struct txstatus_hdr { ++ cmn_msg_hdr_t msg; ++ uint32 pktid; ++} txstatus_hdr_t; ++ ++/** RX bufid-len-ptr tuple */ ++typedef struct rx_lenptr_tup { ++ uint32 rxbufid; ++ uint16 len; ++ uint16 rsvd2; ++ ret_buf_t ret_buf; /**< ret buf pointers */ ++} rx_lenptr_tup_t; ++ ++/** Rx descr Post hdr info */ ++typedef struct rxdesc_msghdr { ++ cmn_msg_hdr_t msg; ++ uint16 rsvd0; ++ uint8 rsvd1; ++ uint8 descnt; ++ rx_lenptr_tup_t rx_tup[0]; ++} rxdesc_msghdr_t; ++ ++/** RX complete tuples */ ++typedef struct rxcmplt_tup { ++ uint16 retbuf_len; ++ uint16 data_offset; ++ uint32 rxstatus0; ++ uint32 rxstatus1; ++ uint32 rxbufid; ++} rxcmplt_tup_t; ++ ++/** RX complete messge hdr */ ++typedef struct rxcmplt_hdr { ++ cmn_msg_hdr_t msg; ++ uint16 rsvd0; ++ uint16 rxcmpltcnt; ++ rxcmplt_tup_t rx_tup[0]; ++} rxcmplt_hdr_t; ++ ++typedef struct hostevent_hdr { ++ cmn_msg_hdr_t msg; ++ uint32 evnt_pyld; ++} hostevent_hdr_t; ++ ++typedef struct dma_xfer_params { ++ uint32 src_physaddr_hi; ++ uint32 src_physaddr_lo; ++ uint32 dest_physaddr_hi; ++ uint32 dest_physaddr_lo; ++ uint32 len; ++ uint32 srcdelay; ++ uint32 destdelay; ++} dma_xfer_params_t; ++ ++enum { ++ HOST_EVENT_CONS_CMD = 1 ++}; ++ ++/* defines for flags */ ++#define MSGBUF_IOC_ACTION_MASK 0x1 ++ ++#define MAX_SUSPEND_REQ 15 ++ ++typedef struct tx_idle_flowring_suspend_request { ++ cmn_msg_hdr_t msg; ++ uint16 ring_id[MAX_SUSPEND_REQ]; /* ring Id's */ ++ uint16 num; /* number of flowid's to suspend */ ++} tx_idle_flowring_suspend_request_t; ++ ++typedef struct tx_idle_flowring_suspend_response { ++ cmn_msg_hdr_t msg; ++ compl_msg_hdr_t cmplt; ++ uint32 rsvd[2]; ++ dma_done_t marker; ++} tx_idle_flowring_suspend_response_t; ++ ++typedef struct tx_idle_flowring_resume_request { ++ cmn_msg_hdr_t msg; ++ uint16 flow_ring_id; ++ uint16 reason; ++ uint32 rsvd[7]; ++} tx_idle_flowring_resume_request_t; ++ ++typedef struct tx_idle_flowring_resume_response { ++ cmn_msg_hdr_t msg; ++ compl_msg_hdr_t cmplt; ++ uint32 rsvd[2]; ++ dma_done_t marker; ++} tx_idle_flowring_resume_response_t; ++ ++/* timesync related additions */ ++ ++typedef struct _bcm_xtlv { ++ uint16 id; /* TLV idenitifier */ ++ uint16 len; /* TLV length in bytes */ ++} _bcm_xtlv_t; ++ ++#define BCMMSGBUF_FW_CLOCK_INFO_TAG 0 ++#define BCMMSGBUF_HOST_CLOCK_INFO_TAG 1 ++#define BCMMSGBUF_HOST_CLOCK_SELECT_TAG 2 ++#define BCMMSGBUF_D2H_CLOCK_CORRECTION_TAG 3 ++#define BCMMSGBUF_HOST_TIMESTAMPING_CONFIG_TAG 4 ++#define BCMMSGBUF_MAX_TSYNC_TAG 5 ++ ++/* Flags in fw clock info TLV */ ++#define CAP_DEVICE_TS (1 << 0) ++#define CAP_CORRECTED_TS (1 << 1) ++#define TS_CLK_ACTIVE (1 << 2) ++ ++typedef struct ts_fw_clock_info { ++ _bcm_xtlv_t xtlv; /* BCMMSGBUF_FW_CLOCK_INFO_TAG */ ++ ts_timestamp_srcid_t ts; /* tick count */ ++ uchar clk_src[4]; /* clock source acronym ILP/AVB/TSF */ ++ uint32 nominal_clock_freq; ++ uint32 reset_cnt; ++ uint8 flags; ++ uint8 rsvd[3]; ++} ts_fw_clock_info_t; ++ ++typedef struct ts_host_clock_info { ++ _bcm_xtlv_t xtlv; /* BCMMSGBUF_HOST_CLOCK_INFO_TAG */ ++ tick_count_64_t ticks; /* 64 bit host tick counter */ ++ ts_timestamp_ns_64_t ns; /* 64 bit host time in nano seconds */ ++} ts_host_clock_info_t; ++ ++typedef struct ts_host_clock_sel { ++ _bcm_xtlv_t xtlv; /* BCMMSGBUF_HOST_CLOCK_SELECT_TAG */ ++ uint32 seqnum; /* number of times GPIO time sync toggled */ ++ uint8 min_clk_idx; /* clock idenitifer configured for packet tiem stamping */ ++ uint8 max_clk_idx; /* clock idenitifer configured for packet tiem stamping */ ++ uint16 rsvd[1]; ++} ts_host_clock_sel_t; ++ ++typedef struct ts_d2h_clock_correction { ++ _bcm_xtlv_t xtlv; /* BCMMSGBUF_HOST_CLOCK_INFO_TAG */ ++ uint8 clk_id; /* clock source in the device */ ++ uint8 rsvd[3]; ++ ts_correction_m_t m; /* y = 'm' x + b */ ++ ts_correction_b_t b; /* y = 'm' x + 'c' */ ++} ts_d2h_clock_correction_t; ++ ++typedef struct ts_host_timestamping_config { ++ _bcm_xtlv_t xtlv; /* BCMMSGBUF_HOST_TIMESTAMPING_CONFIG_TAG */ ++ /* time period to capture the device time stamp and toggle WLAN_TIME_SYNC_GPIO */ ++ uint16 period_ms; ++ uint8 flags; ++ uint8 rsvd; ++ uint32 reset_cnt; ++} ts_host_timestamping_config_t; ++ ++/* Flags in host timestamping config TLV */ ++#define FLAG_HOST_RESET (1 << 0) ++ ++#endif /* _bcmmsgbuf_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmnvram.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmnvram.h +new file mode 100644 +index 000000000..15b58568a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmnvram.h +@@ -0,0 +1,329 @@ ++/* ++ * NVRAM variable manipulation ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmnvram.h 613043 2016-01-16 00:24:13Z $ ++ */ ++ ++#ifndef _bcmnvram_h_ ++#define _bcmnvram_h_ ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++#include ++#include ++ ++struct nvram_header { ++ uint32 magic; ++ uint32 len; ++ uint32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ ++ uint32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ ++ uint32 config_ncdl; /* ncdl values for memc */ ++}; ++ ++struct nvram_tuple { ++ char *name; ++ char *value; ++ struct nvram_tuple *next; ++}; ++ ++/* ++ * Get default value for an NVRAM variable ++ */ ++extern char *nvram_default_get(const char *name); ++/* ++ * validate/restore all per-interface related variables ++ */ ++extern void nvram_validate_all(char *prefix, bool restore); ++ ++/* ++ * restore specific per-interface variable ++ */ ++extern void nvram_restore_var(char *prefix, char *name); ++ ++/* ++ * Initialize NVRAM access. May be unnecessary or undefined on certain ++ * platforms. ++ */ ++extern int nvram_init(void *sih); ++extern int nvram_deinit(void *sih); ++ ++ ++/* ++ * Append a chunk of nvram variables to the global list ++ */ ++extern int nvram_append(void *si, char *vars, uint varsz); ++ ++extern void nvram_get_global_vars(char **varlst, uint *varsz); ++ ++ ++/* ++ * Check for reset button press for restoring factory defaults. ++ */ ++extern int nvram_reset(void *sih); ++ ++/* ++ * Disable NVRAM access. May be unnecessary or undefined on certain ++ * platforms. ++ */ ++extern void nvram_exit(void *sih); ++ ++/* ++ * Get the value of an NVRAM variable. The pointer returned may be ++ * invalid after a set. ++ * @param name name of variable to get ++ * @return value of variable or NULL if undefined ++ */ ++extern char * nvram_get(const char *name); ++ ++/* ++ * Get the value of an NVRAM variable. The pointer returned may be ++ * invalid after a set. ++ * @param name name of variable to get ++ * @param bit bit value to get ++ * @return value of variable or NULL if undefined ++ */ ++extern char * nvram_get_bitflag(const char *name, const int bit); ++ ++/* ++ * Read the reset GPIO value from the nvram and set the GPIO ++ * as input ++ */ ++extern int nvram_resetgpio_init(void *sih); ++ ++/* ++ * Get the value of an NVRAM variable. ++ * @param name name of variable to get ++ * @return value of variable or NUL if undefined ++ */ ++static INLINE char * ++nvram_safe_get(const char *name) ++{ ++ char *p = nvram_get(name); ++ return p ? p : ""; ++} ++ ++/* ++ * Match an NVRAM variable. ++ * @param name name of variable to match ++ * @param match value to compare against value of variable ++ * @return TRUE if variable is defined and its value is string equal ++ * to match or FALSE otherwise ++ */ ++static INLINE int ++nvram_match(const char *name, const char *match) ++{ ++ const char *value = nvram_get(name); ++ ++ /* In nvramstubs.c builds, nvram_get() is defined as returning zero, ++ * so the return line below never executes the strcmp(), ++ * resulting in 'match' being an unused parameter. ++ * Make a ref to 'match' to quiet the compiler warning. ++ */ ++ ++ BCM_REFERENCE(match); ++ ++ return (value && !strcmp(value, match)); ++} ++ ++/* ++ * Match an NVRAM variable. ++ * @param name name of variable to match ++ * @param bit bit value to get ++ * @param match value to compare against value of variable ++ * @return TRUE if variable is defined and its value is string equal ++ * to match or FALSE otherwise ++ */ ++static INLINE int ++nvram_match_bitflag(const char *name, const int bit, const char *match) ++{ ++ const char *value = nvram_get_bitflag(name, bit); ++ BCM_REFERENCE(match); ++ return (value && !strcmp(value, match)); ++} ++ ++/* ++ * Inversely match an NVRAM variable. ++ * @param name name of variable to match ++ * @param match value to compare against value of variable ++ * @return TRUE if variable is defined and its value is not string ++ * equal to invmatch or FALSE otherwise ++ */ ++static INLINE int ++nvram_invmatch(const char *name, const char *invmatch) ++{ ++ const char *value = nvram_get(name); ++ ++ /* In nvramstubs.c builds, nvram_get() is defined as returning zero, ++ * so the return line below never executes the strcmp(), ++ * resulting in 'invmatch' being an unused parameter. ++ * Make a ref to 'invmatch' to quiet the compiler warning. ++ */ ++ ++ BCM_REFERENCE(invmatch); ++ ++ return (value && strcmp(value, invmatch)); ++} ++ ++/* ++ * Set the value of an NVRAM variable. The name and value strings are ++ * copied into private storage. Pointers to previously set values ++ * may become invalid. The new value may be immediately ++ * retrieved but will not be permanently stored until a commit. ++ * @param name name of variable to set ++ * @param value value of variable ++ * @return 0 on success and errno on failure ++ */ ++extern int nvram_set(const char *name, const char *value); ++ ++/* ++ * Set the value of an NVRAM variable. The name and value strings are ++ * copied into private storage. Pointers to previously set values ++ * may become invalid. The new value may be immediately ++ * retrieved but will not be permanently stored until a commit. ++ * @param name name of variable to set ++ * @param bit bit value to set ++ * @param value value of variable ++ * @return 0 on success and errno on failure ++ */ ++extern int nvram_set_bitflag(const char *name, const int bit, const int value); ++/* ++ * Unset an NVRAM variable. Pointers to previously set values ++ * remain valid until a set. ++ * @param name name of variable to unset ++ * @return 0 on success and errno on failure ++ * NOTE: use nvram_commit to commit this change to flash. ++ */ ++extern int nvram_unset(const char *name); ++ ++/* ++ * Commit NVRAM variables to permanent storage. All pointers to values ++ * may be invalid after a commit. ++ * NVRAM values are undefined after a commit. ++ * @param nvram_corrupt true to corrupt nvram, false otherwise. ++ * @return 0 on success and errno on failure ++ */ ++extern int nvram_commit_internal(bool nvram_corrupt); ++ ++/* ++ * Commit NVRAM variables to permanent storage. All pointers to values ++ * may be invalid after a commit. ++ * NVRAM values are undefined after a commit. ++ * @return 0 on success and errno on failure ++ */ ++extern int nvram_commit(void); ++ ++/* ++ * Get all NVRAM variables (format name=value\0 ... \0\0). ++ * @param buf buffer to store variables ++ * @param count size of buffer in bytes ++ * @return 0 on success and errno on failure ++ */ ++extern int nvram_getall(char *nvram_buf, int count); ++ ++/* ++ * returns the crc value of the nvram ++ * @param nvh nvram header pointer ++ */ ++uint8 nvram_calc_crc(struct nvram_header * nvh); ++ ++extern int nvram_space; ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++/* The NVRAM version number stored as an NVRAM variable */ ++#define NVRAM_SOFTWARE_VERSION "1" ++ ++#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */ ++#define NVRAM_CLEAR_MAGIC 0x0 ++#define NVRAM_INVALID_MAGIC 0xFFFFFFFF ++#define NVRAM_VERSION 1 ++#define NVRAM_HEADER_SIZE 20 ++/* This definition is for precommit staging, and will be removed */ ++#define NVRAM_SPACE 0x8000 ++/* For CFE builds this gets passed in thru the makefile */ ++#ifndef MAX_NVRAM_SPACE ++#define MAX_NVRAM_SPACE 0x10000 ++#endif ++#define DEF_NVRAM_SPACE 0x8000 ++#define ROM_ENVRAM_SPACE 0x1000 ++#define NVRAM_LZMA_MAGIC 0x4c5a4d41 /* 'LZMA' */ ++ ++#define NVRAM_MAX_VALUE_LEN 255 ++#define NVRAM_MAX_PARAM_LEN 64 ++ ++#define NVRAM_CRC_START_POSITION 9 /* magic, len, crc8 to be skipped */ ++#define NVRAM_CRC_VER_MASK 0xffffff00 /* for crc_ver_init */ ++ ++/* Offsets to embedded nvram area */ ++#define NVRAM_START_COMPRESSED 0x400 ++#define NVRAM_START 0x1000 ++ ++#define BCM_JUMBO_NVRAM_DELIMIT '\n' ++#define BCM_JUMBO_START "Broadcom Jumbo Nvram file" ++ ++ ++#if (defined(FAILSAFE_UPGRADE) || defined(CONFIG_FAILSAFE_UPGRADE) || \ ++ defined(__CONFIG_FAILSAFE_UPGRADE_SUPPORT__)) ++#define IMAGE_SIZE "image_size" ++#define BOOTPARTITION "bootpartition" ++#define IMAGE_BOOT BOOTPARTITION ++#define PARTIALBOOTS "partialboots" ++#define MAXPARTIALBOOTS "maxpartialboots" ++#define IMAGE_1ST_FLASH_TRX "flash0.trx" ++#define IMAGE_1ST_FLASH_OS "flash0.os" ++#define IMAGE_2ND_FLASH_TRX "flash0.trx2" ++#define IMAGE_2ND_FLASH_OS "flash0.os2" ++#define IMAGE_FIRST_OFFSET "image_first_offset" ++#define IMAGE_SECOND_OFFSET "image_second_offset" ++#define LINUX_FIRST "linux" ++#define LINUX_SECOND "linux2" ++#endif ++ ++#if (defined(DUAL_IMAGE) || defined(CONFIG_DUAL_IMAGE) || \ ++ defined(__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__)) ++/* Shared by all: CFE, Linux Kernel, and Ap */ ++#define IMAGE_BOOT "image_boot" ++#define BOOTPARTITION IMAGE_BOOT ++/* CFE variables */ ++#define IMAGE_1ST_FLASH_TRX "flash0.trx" ++#define IMAGE_1ST_FLASH_OS "flash0.os" ++#define IMAGE_2ND_FLASH_TRX "flash0.trx2" ++#define IMAGE_2ND_FLASH_OS "flash0.os2" ++#define IMAGE_SIZE "image_size" ++ ++/* CFE and Linux Kernel shared variables */ ++#define IMAGE_FIRST_OFFSET "image_first_offset" ++#define IMAGE_SECOND_OFFSET "image_second_offset" ++ ++/* Linux application variables */ ++#define LINUX_FIRST "linux" ++#define LINUX_SECOND "linux2" ++#define POLICY_TOGGLE "toggle" ++#define LINUX_PART_TO_FLASH "linux_to_flash" ++#define LINUX_FLASH_POLICY "linux_flash_policy" ++ ++#endif /* defined(DUAL_IMAGE||CONFIG_DUAL_IMAGE)||__CONFIG_DUAL_IMAGE_FLASH_SUPPORT__ */ ++ ++#endif /* _bcmnvram_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmpcie.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmpcie.h +new file mode 100644 +index 000000000..114924cc9 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmpcie.h +@@ -0,0 +1,440 @@ ++/* ++ * Broadcom PCIE ++ * Software-specific definitions shared between device and host side ++ * Explains the shared area between host and dongle ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmpcie.h 678914 2017-01-11 15:34:26Z $ ++ */ ++ ++ ++#ifndef _bcmpcie_h_ ++#define _bcmpcie_h_ ++ ++#include ++ ++#define ADDR_64(x) (x.addr) ++#define HIGH_ADDR_32(x) ((uint32) (((sh_addr_t) x).high_addr)) ++#define LOW_ADDR_32(x) ((uint32) (((sh_addr_t) x).low_addr)) ++ ++typedef struct { ++ uint32 low_addr; ++ uint32 high_addr; ++} sh_addr_t; ++ ++ ++/* May be overridden by 43xxxxx-roml.mk */ ++#if !defined(BCMPCIE_MAX_TX_FLOWS) ++#define BCMPCIE_MAX_TX_FLOWS 40 ++#endif /* ! BCMPCIE_MAX_TX_FLOWS */ ++ ++#define PCIE_SHARED_VERSION_7 0x00007 ++#define PCIE_SHARED_VERSION_6 0x00006 /* rev6 is compatible with rev 5 */ ++#define PCIE_SHARED_VERSION_5 0x00005 /* rev6 is compatible with rev 5 */ ++/** ++ * Feature flags enabled in dongle. Advertised by dongle to DHD via the PCIe Shared structure that ++ * is located in device memory. ++ */ ++#define PCIE_SHARED_VERSION PCIE_SHARED_VERSION_7 ++#define PCIE_SHARED_VERSION_MASK 0x000FF ++#define PCIE_SHARED_ASSERT_BUILT 0x00100 ++#define PCIE_SHARED_ASSERT 0x00200 ++#define PCIE_SHARED_TRAP 0x00400 ++#define PCIE_SHARED_IN_BRPT 0x00800 ++#define PCIE_SHARED_SET_BRPT 0x01000 ++#define PCIE_SHARED_PENDING_BRPT 0x02000 ++/* BCMPCIE_SUPPORT_TX_PUSH_RING 0x04000 obsolete */ ++#define PCIE_SHARED_EVT_SEQNUM 0x08000 ++#define PCIE_SHARED_DMA_INDEX 0x10000 ++ ++/* WAR: D11 txstatus through unused status field of PCIe completion header */ ++#define PCIE_SHARED_D2H_D11_TX_STATUS 0x40000000 /* using flags2 in shared area */ ++#define PCIE_SHARED_H2D_D11_TX_STATUS 0x80000000 /* using flags2 in shared area */ ++ ++/** ++ * There are host types where a device interrupt can 'race ahead' of data written by the device into ++ * host memory. The dongle can avoid this condition using a variety of techniques (read barrier, ++ * using PCIe Message Signalled Interrupts, or by using the PCIE_DMA_INDEX feature). Unfortunately ++ * these techniques have drawbacks on router platforms. For these platforms, it was decided to not ++ * avoid the condition, but to detect the condition instead and act on it. ++ * D2H M2M DMA Complete Sync mechanism: Modulo-253-SeqNum or XORCSUM ++ */ ++#define PCIE_SHARED_D2H_SYNC_SEQNUM 0x20000 ++#define PCIE_SHARED_D2H_SYNC_XORCSUM 0x40000 ++#define PCIE_SHARED_D2H_SYNC_MODE_MASK \ ++ (PCIE_SHARED_D2H_SYNC_SEQNUM | PCIE_SHARED_D2H_SYNC_XORCSUM) ++#define PCIE_SHARED_IDLE_FLOW_RING 0x80000 ++#define PCIE_SHARED_2BYTE_INDICES 0x100000 ++ ++#define PCIE_SHARED2_EXTENDED_TRAP_DATA 0x00000001 /* using flags2 in shared area */ ++ ++/* dongle supports fatal buf log collection */ ++#define PCIE_SHARED_FATAL_LOGBUG_VALID 0x200000 ++ ++/* Implicit DMA with corerev 19 and after */ ++#define PCIE_SHARED_IDMA 0x400000 ++ ++/* MSI support */ ++#define PCIE_SHARED_D2H_MSI_MULTI_MSG 0x800000 ++ ++/* IFRM with corerev 19 and after */ ++#define PCIE_SHARED_IFRM 0x1000000 ++ ++/** ++ * From Rev6 and above, suspend/resume can be done using two handshake methods. ++ * 1. Using ctrl post/ctrl cmpl messages (Default rev6) ++ * 2. Using Mailbox data (old method as used in rev5) ++ * This shared flag indicates whether to overide rev6 default method and use mailbox for ++ * suspend/resume. ++ */ ++#define PCIE_SHARED_USE_MAILBOX 0x2000000 ++ ++/* Firmware compiled for mfgbuild purposes */ ++#define PCIE_SHARED_MFGBUILD_FW 0x4000000 ++ ++/* Firmware could use DB0 value as host timestamp */ ++#define PCIE_SHARED_TIMESTAMP_DB0 0x8000000 ++/* Firmware could use Hostready (IPC rev7) */ ++#define PCIE_SHARED_HOSTRDY_SUPPORT 0x10000000 ++ ++/* When set, Firmwar does not support OOB Device Wake based DS protocol */ ++#define PCIE_SHARED_NO_OOB_DW 0x20000000 ++ ++/* When set, Firmwar supports Inband DS protocol */ ++#define PCIE_SHARED_INBAND_DS 0x40000000 ++ ++/* Implicit DMA WAR for 4347B0 PCIe memory retention */ ++#define PCIE_SHARED_IDMA_RETENTION_DS 0x80000000 ++ ++#define PCIE_SHARED_D2H_MAGIC 0xFEDCBA09 ++#define PCIE_SHARED_H2D_MAGIC 0x12345678 ++ ++/** ++ * Message rings convey messages between host and device. They are unidirectional, and are located ++ * in host memory. ++ * ++ * This is the minimal set of message rings, known as 'common message rings': ++ */ ++#define BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT 0 ++#define BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT 1 ++#define BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE 2 ++#define BCMPCIE_D2H_MSGRING_TX_COMPLETE 3 ++#define BCMPCIE_D2H_MSGRING_RX_COMPLETE 4 ++#define BCMPCIE_COMMON_MSGRING_MAX_ID 4 ++ ++#define BCMPCIE_H2D_COMMON_MSGRINGS 2 ++#define BCMPCIE_D2H_COMMON_MSGRINGS 3 ++#define BCMPCIE_COMMON_MSGRINGS 5 ++ ++#define BCMPCIE_H2D_MSGRINGS(max_tx_flows) \ ++ (BCMPCIE_H2D_COMMON_MSGRINGS + (max_tx_flows)) ++ ++/* different ring types */ ++#define BCMPCIE_H2D_RING_TYPE_CTRL_SUBMIT 0x1 ++#define BCMPCIE_H2D_RING_TYPE_TXFLOW_RING 0x2 ++#define BCMPCIE_H2D_RING_TYPE_RXBUFPOST 0x3 ++#define BCMPCIE_H2D_RING_TYPE_TXSUBMIT 0x4 ++#define BCMPCIE_H2D_RING_TYPE_DBGBUF_SUBMIT 0x5 ++ ++#define BCMPCIE_D2H_RING_TYPE_CTRL_CPL 0x1 ++#define BCMPCIE_D2H_RING_TYPE_TX_CPL 0x2 ++#define BCMPCIE_D2H_RING_TYPE_RX_CPL 0x3 ++#define BCMPCIE_D2H_RING_TYPE_DBGBUF_CPL 0x4 ++#define BCMPCIE_D2H_RING_TYPE_AC_RX_COMPLETE 0x5 ++ ++/** ++ * H2D and D2H, WR and RD index, are maintained in the following arrays: ++ * - Array of all H2D WR Indices ++ * - Array of all H2D RD Indices ++ * - Array of all D2H WR Indices ++ * - Array of all D2H RD Indices ++ * ++ * The offset of the WR or RD indexes (for common rings) in these arrays are ++ * listed below. Arrays ARE NOT indexed by a ring's id. ++ * ++ * D2H common rings WR and RD index start from 0, even though their ringids ++ * start from BCMPCIE_H2D_COMMON_MSGRINGS ++ */ ++ ++#define BCMPCIE_H2D_RING_IDX(h2d_ring_id) (h2d_ring_id) ++ ++enum h2dring_idx { ++ /* H2D common rings */ ++ BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT_IDX = ++ BCMPCIE_H2D_RING_IDX(BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT), ++ BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT_IDX = ++ BCMPCIE_H2D_RING_IDX(BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT), ++ ++ /* First TxPost's WR or RD index starts after all H2D common rings */ ++ BCMPCIE_H2D_MSGRING_TXFLOW_IDX_START = ++ BCMPCIE_H2D_RING_IDX(BCMPCIE_H2D_COMMON_MSGRINGS) ++}; ++ ++#define BCMPCIE_D2H_RING_IDX(d2h_ring_id) \ ++ ((d2h_ring_id) - BCMPCIE_H2D_COMMON_MSGRINGS) ++ ++enum d2hring_idx { ++ /* D2H Common Rings */ ++ BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE_IDX = ++ BCMPCIE_D2H_RING_IDX(BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE), ++ BCMPCIE_D2H_MSGRING_TX_COMPLETE_IDX = ++ BCMPCIE_D2H_RING_IDX(BCMPCIE_D2H_MSGRING_TX_COMPLETE), ++ BCMPCIE_D2H_MSGRING_RX_COMPLETE_IDX = ++ BCMPCIE_D2H_RING_IDX(BCMPCIE_D2H_MSGRING_RX_COMPLETE) ++}; ++ ++/** ++ * Macros for managing arrays of RD WR indices: ++ * rw_index_sz: ++ * - in dongle, rw_index_sz is known at compile time ++ * - in host/DHD, rw_index_sz is derived from advertized pci_shared flags ++ * ++ * ring_idx: See h2dring_idx and d2hring_idx ++ */ ++ ++/** Offset of a RD or WR index in H2D or D2H indices array */ ++#define BCMPCIE_RW_INDEX_OFFSET(rw_index_sz, ring_idx) \ ++ ((rw_index_sz) * (ring_idx)) ++ ++/** Fetch the address of RD or WR index in H2D or D2H indices array */ ++#define BCMPCIE_RW_INDEX_ADDR(indices_array_base, rw_index_sz, ring_idx) \ ++ (void *)((uint32)(indices_array_base) + \ ++ BCMPCIE_RW_INDEX_OFFSET((rw_index_sz), (ring_idx))) ++ ++/** H2D DMA Indices array size: given max flow rings */ ++#define BCMPCIE_H2D_RW_INDEX_ARRAY_SZ(rw_index_sz, max_tx_flows) \ ++ ((rw_index_sz) * BCMPCIE_H2D_MSGRINGS(max_tx_flows)) ++ ++/** D2H DMA Indices array size */ ++#define BCMPCIE_D2H_RW_INDEX_ARRAY_SZ(rw_index_sz) \ ++ ((rw_index_sz) * BCMPCIE_D2H_COMMON_MSGRINGS) ++ ++/** ++ * This type is used by a 'message buffer' (which is a FIFO for messages). Message buffers are used ++ * for host<->device communication and are instantiated on both sides. ring_mem_t is instantiated ++ * both in host as well as device memory. ++ */ ++typedef struct ring_mem { ++ uint16 idx; /* ring id */ ++ uint8 type; ++ uint8 rsvd; ++ uint16 max_item; /* Max number of items in flow ring */ ++ uint16 len_items; /* Items are fixed size. Length in bytes of one item */ ++ sh_addr_t base_addr; /* 64 bits address, either in host or device memory */ ++} ring_mem_t; ++ ++ ++/** ++ * Per flow ring, information is maintained in device memory, eg at what address the ringmem and ++ * ringstate are located. The flow ring itself can be instantiated in either host or device memory. ++ * ++ * Perhaps this type should be renamed to make clear that it resides in device memory only. ++ */ ++typedef struct ring_info { ++ uint32 ringmem_ptr; /* ring mem location in dongle memory */ ++ ++ /* Following arrays are indexed using h2dring_idx and d2hring_idx, and not ++ * by a ringid. ++ */ ++ ++ /* 32bit ptr to arrays of WR or RD indices for all rings in dongle memory */ ++ uint32 h2d_w_idx_ptr; /* Array of all H2D ring's WR indices */ ++ uint32 h2d_r_idx_ptr; /* Array of all H2D ring's RD indices */ ++ uint32 d2h_w_idx_ptr; /* Array of all D2H ring's WR indices */ ++ uint32 d2h_r_idx_ptr; /* Array of all D2H ring's RD indices */ ++ ++ /* PCIE_DMA_INDEX feature: Dongle uses mem2mem DMA to sync arrays in host. ++ * Host may directly fetch WR and RD indices from these host-side arrays. ++ * ++ * 64bit ptr to arrays of WR or RD indices for all rings in host memory. ++ */ ++ sh_addr_t h2d_w_idx_hostaddr; /* Array of all H2D ring's WR indices */ ++ sh_addr_t h2d_r_idx_hostaddr; /* Array of all H2D ring's RD indices */ ++ sh_addr_t d2h_w_idx_hostaddr; /* Array of all D2H ring's WR indices */ ++ sh_addr_t d2h_r_idx_hostaddr; /* Array of all D2H ring's RD indices */ ++ ++ uint16 max_tx_flowrings; /* maximum number of H2D rings: common + flow */ ++ uint16 max_submission_queues; /* maximum number of H2D rings: common + flow */ ++ uint16 max_completion_rings; /* maximum number of H2D rings: common + flow */ ++ uint16 max_vdevs; /* max number of virtual interfaces supported */ ++ ++ sh_addr_t ifrm_w_idx_hostaddr; /* Array of all H2D ring's WR indices for IFRM */ ++} ring_info_t; ++ ++/** ++ * A structure located in TCM that is shared between host and device, primarily used during ++ * initialization. ++ */ ++typedef struct { ++ /** shared area version captured at flags 7:0 */ ++ uint32 flags; ++ ++ uint32 trap_addr; ++ uint32 assert_exp_addr; ++ uint32 assert_file_addr; ++ uint32 assert_line; ++ uint32 console_addr; /**< Address of hnd_cons_t */ ++ ++ uint32 msgtrace_addr; ++ ++ uint32 fwid; ++ ++ /* Used for debug/flow control */ ++ uint16 total_lfrag_pkt_cnt; ++ uint16 max_host_rxbufs; /* rsvd in spec */ ++ ++ uint32 dma_rxoffset; /* rsvd in spec */ ++ ++ /** these will be used for sleep request/ack, d3 req/ack */ ++ uint32 h2d_mb_data_ptr; ++ uint32 d2h_mb_data_ptr; ++ ++ /* information pertinent to host IPC/msgbuf channels */ ++ /** location in the TCM memory which has the ring_info */ ++ uint32 rings_info_ptr; ++ ++ /** block of host memory for the scratch buffer */ ++ uint32 host_dma_scratch_buffer_len; ++ sh_addr_t host_dma_scratch_buffer; ++ ++ /** block of host memory for the dongle to push the status into */ ++ uint32 device_rings_stsblk_len; ++ sh_addr_t device_rings_stsblk; ++ ++ uint32 buzz_dbg_ptr; /* BUZZZ state format strings and trace buffer */ ++ ++ /* rev6 compatible changes */ ++ uint32 flags2; ++ uint32 host_cap; ++ ++ /* location in the host address space to write trap indication. ++ * At this point for the current rev of the spec, firmware will ++ * support only indications to 32 bit host addresses. ++ */ ++ sh_addr_t host_trap_addr; ++ ++ /* location for host fatal error log buffer start address */ ++ uint32 device_fatal_logbuf_start; ++ ++ /* location in host memory for offloaded modules */ ++ sh_addr_t hoffload_addr; ++} pciedev_shared_t; ++ ++extern pciedev_shared_t pciedev_shared; ++ ++/* host capabilities */ ++#define HOSTCAP_PCIEAPI_VERSION_MASK 0x000000FF ++#define HOSTCAP_H2D_VALID_PHASE 0x00000100 ++#define HOSTCAP_H2D_ENABLE_TRAP_ON_BADPHASE 0x00000200 ++#define HOSTCAP_H2D_ENABLE_HOSTRDY 0x00000400 ++#define HOSTCAP_DB0_TIMESTAMP 0x00000800 ++#define HOSTCAP_DS_NO_OOB_DW 0x00001000 ++#define HOSTCAP_DS_INBAND_DW 0x00002000 ++#define HOSTCAP_H2D_IDMA 0x00004000 ++#define HOSTCAP_H2D_IFRM 0x00008000 ++#define HOSTCAP_H2D_DAR 0x00010000 ++#define HOSTCAP_EXTENDED_TRAP_DATA 0x00020000 ++#define HOSTCAP_TXSTATUS_METADATA 0x00040000 ++ ++/** ++ * Mailboxes notify a remote party that an event took place, using interrupts. They use hardware ++ * support. ++ */ ++ ++/* H2D mail box Data */ ++#define H2D_HOST_D3_INFORM 0x00000001 ++#define H2D_HOST_DS_ACK 0x00000002 ++#define H2D_HOST_DS_NAK 0x00000004 ++#define H2D_HOST_CONS_INT 0x80000000 /**< h2d int for console cmds */ ++#define H2D_FW_TRAP 0x20000000 /**< h2d force TRAP */ ++#define H2D_HOST_D0_INFORM_IN_USE 0x00000008 ++#define H2D_HOST_D0_INFORM 0x00000010 ++#define H2D_HOST_IDMA_INITED 0x00000080 ++#define H2DMB_DS_HOST_SLEEP_INFORM H2D_HOST_D3_INFORM ++#define H2DMB_DS_DEVICE_SLEEP_ACK H2D_HOST_DS_ACK ++#define H2DMB_DS_DEVICE_SLEEP_NAK H2D_HOST_DS_NAK ++#define H2DMB_D0_INFORM_IN_USE H2D_HOST_D0_INFORM_IN_USE ++#define H2DMB_D0_INFORM H2D_HOST_D0_INFORM ++#define H2DMB_DS_ACTIVE 0x00000020 ++#define H2DMB_DS_DEVICE_WAKE 0x00000040 ++#define H2DMB_FW_TRAP H2D_FW_TRAP ++#define H2DMB_HOST_CONS_INT H2D_HOST_CONS_INT ++#define H2DMB_DS_DEVICE_WAKE_ASSERT H2DMB_DS_DEVICE_WAKE ++#define H2DMB_DS_DEVICE_WAKE_DEASSERT H2DMB_DS_ACTIVE ++ ++/* D2H mail box Data */ ++#define D2H_DEV_D3_ACK 0x00000001 ++#define D2H_DEV_DS_ENTER_REQ 0x00000002 ++#define D2H_DEV_DS_EXIT_NOTE 0x00000004 ++#define D2H_DEV_FWHALT 0x10000000 ++#define D2H_DEV_EXT_TRAP_DATA 0x20000000 ++#define D2H_DEV_IDMA_INITED 0x00000010 ++#define D2H_FWTRAP_MASK 0x0000001F /* Adding maskbits for TRAP information */ ++#define D2HMB_DS_HOST_SLEEP_ACK D2H_DEV_D3_ACK ++#define D2HMB_DS_DEVICE_SLEEP_ENTER_REQ D2H_DEV_DS_ENTER_REQ ++#define D2HMB_DS_DEVICE_SLEEP_EXIT D2H_DEV_DS_EXIT_NOTE ++#define D2HMB_DS_HOST_SLEEP_EXIT_ACK 0x00000008 ++#define D2HMB_FWHALT D2H_DEV_FWHALT ++#define D2H_DEV_MB_MASK (D2H_DEV_D3_ACK | D2H_DEV_DS_ENTER_REQ | \ ++ D2H_DEV_DS_EXIT_NOTE | D2H_DEV_IDMA_INITED | D2H_DEV_FWHALT | \ ++ D2H_FWTRAP_MASK | D2H_DEV_EXT_TRAP_DATA) ++#define D2H_DEV_MB_INVALIDATED(x) ((!x) || (x & ~D2H_DEV_MB_MASK)) ++ ++ ++/** These macro's operate on type 'inuse_lclbuf_pool_t' and are used by firmware only */ ++#define NEXTTXP(i, d) ((((i)+1) >= (d)) ? 0 : ((i)+1)) ++#define NTXPACTIVE(r, w, d) (((r) <= (w)) ? ((w)-(r)) : ((d)-(r)+(w))) ++#define NTXPAVAIL(r, w, d) (((d) - NTXPACTIVE((r), (w), (d))) > 1) ++ ++/* Function can be used to notify host of FW halt */ ++#define READ_AVAIL_SPACE(w, r, d) \ ++ ((w >= r) ? (w - r) : (d - r)) ++ ++#define WRITE_SPACE_AVAIL_CONTINUOUS(r, w, d) ((w >= r) ? (d - w) : (r - w)) ++#define WRITE_SPACE_AVAIL(r, w, d) (d - (NTXPACTIVE(r, w, d)) - 1) ++#define CHECK_WRITE_SPACE(r, w, d) \ ++ ((r) > (w)) ? ((r) - (w) - 1) : ((r) == 0 || (w) == 0) ? ((d) - (w) - 1) : ((d) - (w)) ++#define CHECK_NOWRITE_SPACE(r, w, d) \ ++ (((r) == (w) + 1) || (((r) == 0) && ((w) == ((d) - 1)))) ++ ++ ++#define WRT_PEND(x) ((x)->wr_pending) ++#define DNGL_RING_WPTR(msgbuf) (*((msgbuf)->tcm_rs_w_ptr)) /**< advanced by producer */ ++#define BCMMSGBUF_RING_SET_W_PTR(msgbuf, a) (DNGL_RING_WPTR(msgbuf) = (a)) ++ ++#define DNGL_RING_RPTR(msgbuf) (*((msgbuf)->tcm_rs_r_ptr)) /**< advanced by consumer */ ++#define BCMMSGBUF_RING_SET_R_PTR(msgbuf, a) (DNGL_RING_RPTR(msgbuf) = (a)) ++ ++#define MODULO_RING_IDX(x, y) ((x) % (y)->bitmap_size) ++ ++#define RING_READ_PTR(x) ((x)->ringstate->r_offset) ++#define RING_WRITE_PTR(x) ((x)->ringstate->w_offset) ++#define RING_START_PTR(x) ((x)->ringmem->base_addr.low_addr) ++#define RING_MAX_ITEM(x) ((x)->ringmem->max_item) ++#define RING_LEN_ITEMS(x) ((x)->ringmem->len_items) ++#define HOST_RING_BASE(x) ((x)->dma_buf.va) ++#define HOST_RING_END(x) ((uint8 *)HOST_RING_BASE((x)) + \ ++ ((RING_MAX_ITEM((x))-1)*RING_LEN_ITEMS((x)))) ++#endif /* _bcmpcie_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmpcispi.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmpcispi.h +new file mode 100644 +index 000000000..b3502ea7b +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmpcispi.h +@@ -0,0 +1,184 @@ ++/* ++ * Broadcom PCI-SPI Host Controller Register Definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmpcispi.h 514727 2014-11-12 03:02:48Z $ ++ */ ++#ifndef _BCM_PCI_SPI_H ++#define _BCM_PCI_SPI_H ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++ ++typedef volatile struct { ++ uint32 spih_ctrl; /* 0x00 SPI Control Register */ ++ uint32 spih_stat; /* 0x04 SPI Status Register */ ++ uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */ ++ uint32 spih_ext; /* 0x0C SPI Extension Register */ ++ uint32 PAD[4]; /* 0x10-0x1F PADDING */ ++ ++ uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */ ++ uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */ ++ uint32 PAD[6]; /* 0x28-0x3F PADDING */ ++ ++ uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */ ++ uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */ ++ /* 1=Active High) */ ++ uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */ ++ uint32 spih_int_status; /* 0x4C SPI Interrupt Status */ ++ uint32 PAD[4]; /* 0x50-0x5F PADDING */ ++ ++ uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */ ++ uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */ ++ uint32 PAD[1]; /* 0x68 PADDING */ ++ uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */ ++ uint32 PAD[4]; /* 0x70-0x7F PADDING */ ++ uint32 PAD[8]; /* 0x80-0x9F PADDING */ ++ uint32 PAD[8]; /* 0xA0-0xBF PADDING */ ++ uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */ ++ uint32 spih_pll_status; /* 0xC4 PLL Status Register */ ++ uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */ ++ uint32 spih_clk_count; /* 0xCC External Clock Count Register */ ++ ++} spih_regs_t; ++ ++typedef volatile struct { ++ uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */ ++ uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */ ++ ++ uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */ ++ uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */ ++ uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */ ++ uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */ ++ uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */ ++ uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */ ++ uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */ ++ uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */ ++ uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */ ++ uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */ ++ uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */ ++ uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */ ++ uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */ ++ uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */ ++ uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */ ++ uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */ ++ uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */ ++ uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */ ++ uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */ ++ uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */ ++ uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */ ++ uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */ ++ uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */ ++ uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */ ++ uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */ ++ uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */ ++ ++ uint32 PAD[5]; /* 0x16C-0x17F PADDING */ ++ ++ uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */ ++ uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */ ++ uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */ ++ uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */ ++ uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */ ++ uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */ ++ uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */ ++ uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */ ++ uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */ ++ uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */ ++ uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */ ++ uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */ ++ uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */ ++ uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */ ++ uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */ ++ uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */ ++ uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */ ++ uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */ ++ uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */ ++ uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */ ++ uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */ ++ uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */ ++ uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */ ++ uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */ ++ uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */ ++ uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */ ++ ++ uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */ ++ uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */ ++ uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */ ++} spih_pciregs_t; ++ ++/* ++ * PCI Core interrupt enable and status bit definitions. ++ */ ++ ++/* PCI Core ICR Register bit definitions */ ++#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */ ++#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */ ++#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */ ++#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */ ++#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */ ++#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */ ++ ++ ++/* PCI Core ISR Register bit definitions */ ++#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */ ++#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */ ++#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */ ++#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */ ++#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */ ++ ++ ++/* Registers on the Wishbone bus */ ++#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */ ++#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */ ++#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */ ++ ++/* GPIO Bit definitions */ ++#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */ ++#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */ ++#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */ ++ ++/* SPI Status Register Bit definitions */ ++#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */ ++#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */ ++#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */ ++#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */ ++#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */ ++#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */ ++ ++#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */ ++ ++#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */ ++#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */ ++ ++/* Spin bit loop bound check */ ++#define SPI_SPIN_BOUND 0xf4240 /* 1 million */ ++ ++#endif /* _BCM_PCI_SPI_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmperf.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmperf.h +new file mode 100644 +index 000000000..09e607fc9 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmperf.h +@@ -0,0 +1,39 @@ ++/* ++ * Performance counters software interface. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmperf.h 514727 2014-11-12 03:02:48Z $ ++ */ ++/* essai */ ++#ifndef _BCMPERF_H_ ++#define _BCMPERF_H_ ++/* get cache hits and misses */ ++#define BCMPERF_ENABLE_INSTRCOUNT() ++#define BCMPERF_ENABLE_ICACHE_MISS() ++#define BCMPERF_ENABLE_ICACHE_HIT() ++#define BCMPERF_GETICACHE_MISS(x) ((x) = 0) ++#define BCMPERF_GETICACHE_HIT(x) ((x) = 0) ++#define BCMPERF_GETINSTRCOUNT(x) ((x) = 0) ++#endif /* _BCMPERF_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdbus.h +new file mode 100644 +index 000000000..da835e88a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdbus.h +@@ -0,0 +1,173 @@ ++/* ++ * Definitions for API from sdio common code (bcmsdh) to individual ++ * host controller drivers. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdbus.h 644725 2016-06-21 12:26:04Z $ ++ */ ++ ++#ifndef _sdio_api_h_ ++#define _sdio_api_h_ ++ ++#if defined(BT_OVER_SDIO) ++#include ++#endif /* defined (BT_OVER_SDIO) */ ++ ++ ++#define SDIOH_API_RC_SUCCESS (0x00) ++#define SDIOH_API_RC_FAIL (0x01) ++#define SDIOH_API_SUCCESS(status) (status == 0) ++ ++#define SDIOH_READ 0 /* Read request */ ++#define SDIOH_WRITE 1 /* Write request */ ++ ++#define SDIOH_DATA_FIX 0 /* Fixed addressing */ ++#define SDIOH_DATA_INC 1 /* Incremental addressing */ ++ ++#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 */ ++ ++/* Max number of glommed pkts */ ++#ifdef CUSTOM_MAX_TXGLOM_SIZE ++#define SDPCM_MAXGLOM_SIZE CUSTOM_MAX_TXGLOM_SIZE ++#else ++#define SDPCM_MAXGLOM_SIZE 36 ++#endif /* CUSTOM_MAX_TXGLOM_SIZE */ ++ ++#define SDPCM_TXGLOM_CPY 0 /* SDIO 2.0 should use copy mode */ ++#define SDPCM_TXGLOM_MDESC 1 /* SDIO 3.0 should use multi-desc mode */ ++ ++#ifdef CUSTOM_DEF_TXGLOM_SIZE ++#define SDPCM_DEFGLOM_SIZE CUSTOM_DEF_TXGLOM_SIZE ++#else ++#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE ++#endif /* CUSTOM_DEF_TXGLOM_SIZE */ ++ ++#if SDPCM_DEFGLOM_SIZE > SDPCM_MAXGLOM_SIZE ++#warning "SDPCM_DEFGLOM_SIZE cannot be higher than SDPCM_MAXGLOM_SIZE!!" ++#undef SDPCM_DEFGLOM_SIZE ++#define SDPCM_DEFGLOM_SIZE SDPCM_MAXGLOM_SIZE ++#endif ++ ++#ifdef PKT_STATICS ++typedef struct pkt_statics { ++ uint16 event_count; ++ uint32 event_size; ++ uint16 ctrl_count; ++ uint32 ctrl_size; ++ uint32 data_count; ++ uint32 data_size; ++ uint32 glom_cnt[SDPCM_MAXGLOM_SIZE]; ++ uint16 glom_max; ++ uint16 glom_count; ++ uint32 glom_size; ++ uint16 test_count; ++ uint32 test_size; ++} pkt_statics_t; ++#endif ++ ++typedef int SDIOH_API_RC; ++ ++/* SDio Host structure */ ++typedef struct sdioh_info sdioh_info_t; ++ ++/* callback function, taking one arg */ ++typedef void (*sdioh_cb_fn_t)(void *); ++#if defined(BT_OVER_SDIO) ++extern ++void sdioh_sdmmc_card_enable_func_f3(sdioh_info_t *sd, struct sdio_func *func); ++#endif /* defined (BT_OVER_SDIO) */ ++ ++extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh); ++extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si); ++ ++/* query whether SD interrupt is enabled or not */ ++extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *si, bool *onoff); ++ ++/* enable or disable SD interrupt */ ++extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable); ++ ++#if defined(DHD_DEBUG) ++extern bool sdioh_interrupt_pending(sdioh_info_t *si); ++#endif ++ ++/* read or write one byte using cmd52 */ ++extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *si, uint rw, uint fnc, uint addr, uint8 *byte); ++ ++/* read or write 2/4 bytes using cmd53 */ ++extern SDIOH_API_RC sdioh_request_word(sdioh_info_t *si, uint cmd_type, uint rw, uint fnc, ++ uint addr, uint32 *word, uint nbyte); ++ ++/* read or write any buffer using cmd53 */ ++extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc, ++ uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer, ++ void *pkt); ++ ++/* get cis data */ ++extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length); ++extern SDIOH_API_RC sdioh_cisaddr_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 offset); ++ ++extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); ++extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); ++ ++/* query number of io functions */ ++extern uint sdioh_query_iofnum(sdioh_info_t *si); ++ ++/* handle iovars */ ++extern int sdioh_iovar_op(sdioh_info_t *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 sdioh_abort(sdioh_info_t *si, uint fnc); ++ ++/* Start and Stop SDIO without re-enumerating the SD card. */ ++extern int sdioh_start(sdioh_info_t *si, int stage); ++extern int sdioh_stop(sdioh_info_t *si); ++ ++/* Wait system lock free */ ++extern int sdioh_waitlockfree(sdioh_info_t *si); ++ ++/* Reset and re-initialize the device */ ++extern int sdioh_sdio_reset(sdioh_info_t *si); ++ ++ ++ ++#if defined(BCMSDIOH_STD) ++ #define SDIOH_SLEEP_ENABLED ++#endif ++extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab); ++ ++/* GPIO support */ ++extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd); ++extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio); ++extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio); ++extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab); ++extern uint sdioh_set_mode(sdioh_info_t *sd, uint mode); ++ ++#endif /* _sdio_api_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdh.h +new file mode 100644 +index 000000000..7262d0f53 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdh.h +@@ -0,0 +1,273 @@ ++/* ++ * SDIO host client driver interface of Broadcom HNBU ++ * export functions to client drivers ++ * abstract OS and BUS specific details of SDIO ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdh.h 698895 2017-05-11 02:55:17Z $ ++ */ ++ ++/** ++ * @file bcmsdh.h ++ */ ++ ++#ifndef _bcmsdh_h_ ++#define _bcmsdh_h_ ++ ++#define BCMSDH_ERROR_VAL 0x0001 /* Error */ ++#define BCMSDH_INFO_VAL 0x0002 /* Info */ ++extern const uint bcmsdh_msglevel; ++ ++#define BCMSDH_ERROR(x) printf x ++#define BCMSDH_INFO(x) ++ ++#if defined(BCMSDIO) && (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || \ ++ defined(BCMSDIOH_SPI)) ++#define BCMSDH_ADAPTER ++#endif /* BCMSDIO && (BCMSDIOH_STD || BCMSDIOH_BCM || BCMSDIOH_SPI) */ ++ ++/* forward declarations */ ++typedef struct bcmsdh_info bcmsdh_info_t; ++typedef void (*bcmsdh_cb_fn_t)(void *); ++ ++ ++#if defined(BT_OVER_SDIO) ++typedef enum { ++ NO_HANG_STATE = 0, ++ HANG_START_STATE = 1, ++ HANG_RECOVERY_STATE = 2 ++} dhd_hang_state_t; ++#endif ++ ++extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva); ++/** ++ * BCMSDH API context ++ */ ++struct bcmsdh_info ++{ ++ bool init_success; /* underlying driver successfully attached */ ++ void *sdioh; /* handler for sdioh */ ++ uint32 vendevid; /* Target Vendor and Device ID on SD bus */ ++ osl_t *osh; ++ bool regfail; /* Save status of last reg_read/reg_write call */ ++ uint32 sbwad; /* Save backplane window address */ ++ void *os_cxt; /* Pointer to per-OS private data */ ++ bool force_sbwad_calc; /* forces calculation of sbwad instead of using cached value */ ++#ifdef DHD_WAKE_STATUS ++ unsigned int total_wake_count; ++ int pkt_wake; ++#endif /* DHD_WAKE_STATUS */ ++}; ++ ++/* Detach - freeup resources allocated in attach */ ++extern int bcmsdh_detach(osl_t *osh, void *sdh); ++ ++/* Query if SD device interrupts are enabled */ ++extern bool bcmsdh_intr_query(void *sdh); ++ ++/* Enable/disable SD interrupt */ ++extern int bcmsdh_intr_enable(void *sdh); ++extern int bcmsdh_intr_disable(void *sdh); ++ ++/* Register/deregister device interrupt handler. */ ++extern int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); ++extern int bcmsdh_intr_dereg(void *sdh); ++/* Enable/disable SD card interrupt forward */ ++extern void bcmsdh_intr_forward(void *sdh, bool pass); ++ ++#if defined(DHD_DEBUG) ++/* Query pending interrupt status from the host controller */ ++extern bool bcmsdh_intr_pending(void *sdh); ++#endif ++ ++/* Register a callback to be called if and when bcmsdh detects ++ * device removal. No-op in the case of non-removable/hardwired devices. ++ */ ++extern int bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); ++ ++/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface). ++ * fn: function number ++ * addr: unmodified SDIO-space address ++ * data: data byte to write ++ * err: pointer to error code (or NULL) ++ */ ++extern uint8 bcmsdh_cfg_read(void *sdh, uint func, uint32 addr, int *err); ++extern void bcmsdh_cfg_write(void *sdh, uint func, uint32 addr, uint8 data, int *err); ++ ++/* Read/Write 4bytes from/to cfg space */ ++extern uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err); ++extern void bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 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 bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length); ++extern int bcmsdh_cisaddr_read(void *sdh, uint func, uint8 *cisd, uint offset); ++ ++/* 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 uint32 bcmsdh_reg_read(void *sdh, uintptr addr, uint size); ++extern uint32 bcmsdh_reg_write(void *sdh, uintptr addr, uint size, uint32 data); ++ ++/* set sb address window */ ++extern int bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set); ++ ++/* Indicate if last reg read/write failed */ ++extern bool bcmsdh_regfail(void *sdh); ++ ++/* Buffer transfer to/from device (client) core via cmd53. ++ * fn: function number ++ * addr: backplane address (i.e. >= regsva from attach) ++ * flags: backplane width, address increment, sync/async ++ * buf: pointer to memory data buffer ++ * nbytes: number of bytes to transfer to/from buf ++ * pkt: pointer to packet associated with buf (if any) ++ * complete: callback function for command completion (async only) ++ * handle: handle for completion callback (first arg in callback) ++ * Returns 0 or error code. ++ * NOTE: Async operation is not currently supported. ++ */ ++typedef void (*bcmsdh_cmplt_fn_t)(void *handle, int status, bool sync_waiting); ++extern int bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle); ++extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags, ++ uint8 *buf, uint nbytes, void *pkt, ++ bcmsdh_cmplt_fn_t complete_fn, void *handle); ++ ++extern void bcmsdh_glom_post(void *sdh, uint8 *frame, void *pkt, uint len); ++extern void bcmsdh_glom_clear(void *sdh); ++extern uint bcmsdh_set_mode(void *sdh, uint mode); ++extern bool bcmsdh_glom_enabled(void); ++/* 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) */ ++#define SDIO_BYTE_MODE 0x8 /* Byte mode request(non-block mode) */ ++ ++/* Pending (non-error) return code */ ++#define BCME_PENDING 1 ++ ++/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only). ++ * rw: read or write (0/1) ++ * addr: direct SDIO address ++ * buf: pointer to memory data buffer ++ * nbytes: number of bytes to transfer to/from buf ++ * Returns 0 or error code. ++ */ ++extern int bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes); ++ ++/* Issue an abort to the specified function */ ++extern int bcmsdh_abort(void *sdh, uint fn); ++ ++/* Start SDIO Host Controller communication */ ++extern int bcmsdh_start(void *sdh, int stage); ++ ++/* Stop SDIO Host Controller communication */ ++extern int bcmsdh_stop(void *sdh); ++ ++/* Wait system lock free */ ++extern int bcmsdh_waitlockfree(void *sdh); ++ ++/* Returns the "Device ID" of target device on the SDIO bus. */ ++extern int bcmsdh_query_device(void *sdh); ++ ++/* Returns the number of IO functions reported by the device */ ++extern uint bcmsdh_query_iofnum(void *sdh); ++ ++/* Miscellaneous knob tweaker. */ ++extern int bcmsdh_iovar_op(void *sdh, const char *name, ++ void *params, int plen, void *arg, int len, bool set); ++ ++/* Reset and reinitialize the device */ ++extern int bcmsdh_reset(bcmsdh_info_t *sdh); ++ ++/* helper functions */ ++ ++/* callback functions */ ++typedef struct { ++ /* probe the device */ ++ void *(*probe)(uint16 vend_id, uint16 dev_id, uint16 bus, uint16 slot, ++ uint16 func, uint bustype, void * regsva, osl_t * osh, ++ void * param); ++ /* remove the device */ ++ void (*remove)(void *context); ++ /* can we suspend now */ ++ int (*suspend)(void *context); ++ /* resume from suspend */ ++ int (*resume)(void *context); ++} bcmsdh_driver_t; ++ ++/* platform specific/high level functions */ ++extern int bcmsdh_register(bcmsdh_driver_t *driver); ++extern void bcmsdh_unregister(void); ++extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device); ++extern void bcmsdh_device_remove(void * sdh); ++ ++extern int bcmsdh_reg_sdio_notify(void* semaphore); ++extern void bcmsdh_unreg_sdio_notify(void); ++ ++#if defined(OOB_INTR_ONLY) ++extern int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler, ++ void* oob_irq_handler_context); ++extern void bcmsdh_oob_intr_unregister(bcmsdh_info_t *sdh); ++extern void bcmsdh_oob_intr_set(bcmsdh_info_t *sdh, bool enable); ++#endif ++extern void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *sdh); ++extern void bcmsdh_dev_relax(bcmsdh_info_t *sdh); ++extern bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *sdh); ++ ++int bcmsdh_suspend(bcmsdh_info_t *bcmsdh); ++int bcmsdh_resume(bcmsdh_info_t *bcmsdh); ++ ++/* Function to pass device-status bits to DHD. */ ++extern uint32 bcmsdh_get_dstatus(void *sdh); ++ ++/* Function to return current window addr */ ++extern uint32 bcmsdh_cur_sbwad(void *sdh); ++ ++/* function to force sbwad calculation instead of using cached value */ ++extern void bcmsdh_force_sbwad_calc(void *sdh, bool force); ++ ++/* Function to pass chipid and rev to lower layers for controlling pr's */ ++extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); ++ ++ ++extern int bcmsdh_sleep(void *sdh, bool enab); ++ ++/* GPIO support */ ++extern int bcmsdh_gpio_init(void *sd); ++extern bool bcmsdh_gpioin(void *sd, uint32 gpio); ++extern int bcmsdh_gpioouten(void *sd, uint32 gpio); ++extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab); ++ ++#endif /* _bcmsdh_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h +new file mode 100644 +index 000000000..1073d97c6 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h +@@ -0,0 +1,129 @@ ++/* ++ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdh_sdmmc.h 687253 2017-02-28 09:33:36Z $ ++ */ ++ ++#ifndef __BCMSDH_SDMMC_H__ ++#define __BCMSDH_SDMMC_H__ ++ ++#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) ++#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0) ++#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0) ++#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0) ++#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0) ++#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0) ++#define sd_cost(x) do { if (sd_msglevel & SDH_COST_VAL) printf x; } while (0) ++ ++#define sd_sync_dma(sd, read, nbytes) ++#define sd_init_dma(sd) ++#define sd_ack_intr(sd) ++#define sd_wakeup(sd); ++ ++#define sd_log(x) ++ ++#define SDIOH_ASSERT(exp) \ ++ do { if (!(exp)) \ ++ printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ ++ } while (0) ++ ++#define BLOCK_SIZE_4318 64 ++#define BLOCK_SIZE_4328 512 ++ ++/* internal return code */ ++#define SUCCESS 0 ++#define ERROR 1 ++ ++/* private bus modes */ ++#define SDIOH_MODE_SD4 2 ++#define CLIENT_INTR 0x100 /* Get rid of this! */ ++#define SDIOH_SDMMC_MAX_SG_ENTRIES (SDPCM_MAXGLOM_SIZE + 2) ++ ++struct sdioh_info { ++ osl_t *osh; /* osh handler */ ++ void *bcmsdh; /* upper layer handle */ ++ bool client_intr_enabled; /* interrupt connnected flag */ ++ bool intr_handler_valid; /* client driver interrupt handler valid */ ++ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ ++ void *intr_handler_arg; /* argument to call interrupt handler */ ++ uint16 intmask; /* Current active interrupts */ ++ ++ int intrcount; /* Client interrupts */ ++ bool sd_use_dma; /* DMA on CMD53 */ ++ 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 sd_mode; /* SD1/SD4/SPI */ ++ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ ++ uint8 num_funcs; /* Supported funcs on client */ ++ uint32 com_cis_ptr; ++ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; ++ bool use_rxchain; ++ struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; ++ struct sdio_func fake_func0; ++ struct sdio_func *func[SDIOD_MAX_IOFUNCS]; ++ uint sd_clk_rate; ++ uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ ++}; ++ ++/************************************************************ ++ * Internal interfaces: per-port references into bcmsdh_sdmmc.c ++ */ ++ ++/* Global message bits */ ++extern uint sd_msglevel; ++ ++/* OS-independent interrupt handler */ ++extern bool check_client_intr(sdioh_info_t *sd); ++ ++/* Core interrupt enable/disable of device interrupts */ ++extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); ++extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); ++ ++ ++/************************************************************** ++ * Internal interfaces: bcmsdh_sdmmc.c references to per-port code ++ */ ++ ++/* Register mapping routines */ ++extern uint32 *sdioh_sdmmc_reg_map(osl_t *osh, int32 addr, int size); ++extern void sdioh_sdmmc_reg_unmap(osl_t *osh, int32 addr, int size); ++ ++/* Interrupt (de)registration routines */ ++extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq); ++extern void sdioh_sdmmc_free_irq(uint irq, sdioh_info_t *sd); ++ ++extern sdioh_info_t *sdioh_attach(osl_t *osh, struct sdio_func *func); ++extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd); ++ ++#ifdef GLOBAL_SDMMC_INSTANCE ++typedef struct _BCMSDH_SDMMC_INSTANCE { ++ sdioh_info_t *sd; ++ struct sdio_func *func[SDIOD_MAX_IOFUNCS]; ++} BCMSDH_SDMMC_INSTANCE, *PBCMSDH_SDMMC_INSTANCE; ++#endif ++ ++#endif /* __BCMSDH_SDMMC_H__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h +new file mode 100644 +index 000000000..5b9c51b3a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h +@@ -0,0 +1,302 @@ ++/* ++ * Broadcom SDIO/PCMCIA ++ * Software-specific definitions shared between device and host side ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdpcm.h 614070 2016-01-21 00:55:57Z $ ++ */ ++ ++#ifndef _bcmsdpcm_h_ ++#define _bcmsdpcm_h_ ++ ++/* ++ * Software allocation of To SB Mailbox resources ++ */ ++ ++/* intstatus bits */ ++#define I_SMB_NAK I_SMB_SW0 /* To SB Mailbox Frame NAK */ ++#define I_SMB_INT_ACK I_SMB_SW1 /* To SB Mailbox Host Interrupt ACK */ ++#define I_SMB_USE_OOB I_SMB_SW2 /* To SB Mailbox Use OOB Wakeup */ ++#define I_SMB_DEV_INT I_SMB_SW3 /* To SB Mailbox Miscellaneous Interrupt */ ++ ++#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT) ++ ++/* tosbmailbox bits corresponding to intstatus bits */ ++#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */ ++#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */ ++#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */ ++#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */ ++#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */ ++ ++/* tosbmailboxdata */ ++ ++#ifdef DS_PROT ++/* Bit msgs for custom deep sleep protocol */ ++#define SMB_DATA_D3INFORM 0x100 /* host announcing D3 entry */ ++#define SMB_DATA_DSACK 0x200 /* host acking a deepsleep request */ ++#define SMB_DATA_DSNACK 0x400 /* host nacking a deepsleep request */ ++#endif /* DS_PROT */ ++ ++#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */ ++#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */ ++ ++/* ++ * Software allocation of To Host Mailbox resources ++ */ ++ ++/* intstatus bits */ ++#define I_HMB_INT_ACK I_HMB_SW0 /* To Host Mailbox Dev Interrupt ACK */ ++#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */ ++#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */ ++#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */ ++#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */ ++ ++#define I_TOHOSTMAIL (I_HMB_INT_ACK | I_HMB_FRAME_IND | I_HMB_HOST_INT) ++ ++/* tohostmailbox bits corresponding to intstatus bits */ ++#define HMB_INT_ACK (1 << 0) /* To Host Mailbox Dev Interrupt ACK */ ++#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */ ++#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */ ++#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */ ++ ++/* tohostmailboxdata */ ++#define HMB_DATA_NAKHANDLED 0x01 /* we're ready to retransmit NAK'd frame to host */ ++#define HMB_DATA_DEVREADY 0x02 /* we're ready to to talk to host after enable */ ++#define HMB_DATA_FC 0x04 /* per prio flowcontrol update flag to host */ ++#define HMB_DATA_FWREADY 0x08 /* firmware is ready for protocol activity */ ++#define HMB_DATA_FWHALT 0x10 /* firmware has halted operation */ ++ ++#ifdef DS_PROT ++/* Bit msgs for custom deep sleep protocol */ ++#define HMB_DATA_DSREQ 0x100 /* firmware requesting deepsleep entry */ ++#define HMB_DATA_DSEXIT 0x200 /* firmware announcing deepsleep exit */ ++#define HMB_DATA_D3ACK 0x400 /* firmware acking a D3 notice from host */ ++#define HMB_DATA_D3EXIT 0x800 /* firmware announcing D3 exit */ ++#define HMB_DATA_DSPROT_MASK 0xf00 ++#endif /* DS_PROT */ ++ ++ ++#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */ ++#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */ ++ ++#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */ ++#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */ ++ ++/* ++ * Software-defined protocol header ++ */ ++ ++/* Current protocol version */ ++#define SDPCM_PROT_VERSION 4 ++ ++/* SW frame header */ ++#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */ ++#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */ ++ ++#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */ ++#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */ ++#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */ ++ ++#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */ ++#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */ ++#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */ ++ ++/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */ ++#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */ ++#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */ ++#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */ ++#define SDPCM_NEXTLEN_OFFSET 2 ++ ++/* Data Offset from SOF (HW Tag, SW Tag, Pad) */ ++#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ ++#define SDPCM_DOFFSET_VALUE(p) (((uint8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) ++#define SDPCM_DOFFSET_MASK 0xff000000 ++#define SDPCM_DOFFSET_SHIFT 24 ++ ++#define SDPCM_FCMASK_OFFSET 4 /* Flow control */ ++#define SDPCM_FCMASK_VALUE(p) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff) ++#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ ++#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) ++#define SDPCM_VERSION_OFFSET 6 /* Version # */ ++#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff) ++#define SDPCM_UNUSED_OFFSET 7 /* Spare */ ++#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff) ++ ++#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ ++ ++/* logical channel numbers */ ++#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response Channel Id */ ++#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ ++#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ ++#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets (superframes) */ ++#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ ++#define SDPCM_MAX_CHANNEL 15 ++ ++#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */ ++ ++#define SDPCM_FLAG_RESVD0 0x01 ++#define SDPCM_FLAG_RESVD1 0x02 ++#define SDPCM_FLAG_GSPI_TXENAB 0x04 ++#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */ ++ ++/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */ ++#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT) ++ ++#define SDPCM_GLOMDESC(p) (((uint8 *)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_PKT_CNT_FLD_LEN 4 /* Packet count filed legth */ ++#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */ ++#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */ ++#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */ ++#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count ++ * (Backward compatabilty) Set frame count in a ++ * 4 byte filed adjacent to the HDR ++ */ ++#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off ++ * Set frame count in a 4 byte filed adjacent to ++ * the HDR ++ */ ++ ++/* Handy macro for filling in datagen packets with a pattern */ ++#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno)) ++ ++/* ++ * Software counters (first part matches hardware counters) ++ */ ++ ++typedef volatile struct { ++ uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */ ++ uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */ ++ uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */ ++ uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */ ++ uint32 abort; /* AbortCount, SDIO: aborts */ ++ uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */ ++ uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */ ++ uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */ ++ uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */ ++ uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */ ++ uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */ ++ uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */ ++ uint32 rxdescuflo; /* receive descriptor underflows */ ++ uint32 rxfifooflo; /* receive fifo overflows */ ++ uint32 txfifouflo; /* transmit fifo underflows */ ++ uint32 runt; /* runt (too short) frames recv'd from bus */ ++ uint32 badlen; /* frame's rxh len does not match its hw tag len */ ++ uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */ ++ uint32 seqbreak; /* break in sequence # space from one rx frame to the next */ ++ uint32 rxfcrc; /* frame rx header indicates crc error */ ++ uint32 rxfwoos; /* frame rx header indicates write out of sync */ ++ uint32 rxfwft; /* frame rx header indicates write frame termination */ ++ uint32 rxfabort; /* frame rx header indicates frame aborted */ ++ uint32 woosint; /* write out of sync interrupt */ ++ uint32 roosint; /* read out of sync interrupt */ ++ uint32 rftermint; /* read frame terminate interrupt */ ++ uint32 wftermint; /* write frame terminate interrupt */ ++} sdpcmd_cnt_t; ++ ++/* ++ * Register Access Macros ++ */ ++ ++#define SDIODREV_IS(var, val) ((var) == (val)) ++#define SDIODREV_GE(var, val) ((var) >= (val)) ++#define SDIODREV_GT(var, val) ((var) > (val)) ++#define SDIODREV_LT(var, val) ((var) < (val)) ++#define SDIODREV_LE(var, val) ((var) <= (val)) ++ ++#define SDIODDMAREG32(h, dir, chnl) \ ++ ((dir) == DMA_TX ? \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv)) ++ ++#define SDIODDMAREG64(h, dir, chnl) \ ++ ((dir) == DMA_TX ? \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \ ++ (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv)) ++ ++#define SDIODDMAREG(h, dir, chnl) \ ++ (SDIODREV_LT((h)->corerev, 1) ? \ ++ SDIODDMAREG32((h), (dir), (chnl)) : \ ++ SDIODDMAREG64((h), (dir), (chnl))) ++ ++#define PCMDDMAREG(h, dir, chnl) \ ++ ((dir) == DMA_TX ? \ ++ (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \ ++ (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv)) ++ ++#define SDPCMDMAREG(h, dir, chnl, coreid) \ ++ ((coreid) == SDIOD_CORE_ID ? \ ++ SDIODDMAREG(h, dir, chnl) : \ ++ PCMDDMAREG(h, dir, chnl)) ++ ++#define SDIODFIFOREG(h, corerev) \ ++ (SDIODREV_LT((corerev), 1) ? \ ++ ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \ ++ ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo))) ++ ++#define PCMDFIFOREG(h) \ ++ ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo)) ++ ++#define SDPCMFIFOREG(h, coreid, corerev) \ ++ ((coreid) == SDIOD_CORE_ID ? \ ++ SDIODFIFOREG(h, corerev) : \ ++ PCMDFIFOREG(h)) ++ ++/* ++ * Shared structure between dongle and the host. ++ * The structure contains pointers to trap or assert information. ++ */ ++#define SDPCM_SHARED_VERSION 0x0001 ++#define SDPCM_SHARED_VERSION_MASK 0x00FF ++#define SDPCM_SHARED_ASSERT_BUILT 0x0100 ++#define SDPCM_SHARED_ASSERT 0x0200 ++#define SDPCM_SHARED_TRAP 0x0400 ++#define SDPCM_SHARED_IN_BRPT 0x0800 ++#define SDPCM_SHARED_SET_BRPT 0x1000 ++#define SDPCM_SHARED_PENDING_BRPT 0x2000 ++#define SDPCM_SHARED_FATAL_LOGBUF_VALID 0x100000 ++#define SDPCM_SHARED_RXLIM_POST 0x4000 ++ ++typedef struct { ++ uint32 flags; ++ uint32 trap_addr; ++ uint32 assert_exp_addr; ++ uint32 assert_file_addr; ++ uint32 assert_line; ++ uint32 console_addr; /* Address of hnd_cons_t */ ++ uint32 msgtrace_addr; ++ uint32 fwid; ++ uint32 device_fatal_logbuf_start; ++} sdpcm_shared_t; ++ ++extern sdpcm_shared_t sdpcm_shared; ++ ++#endif /* _bcmsdpcm_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdspi.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdspi.h +new file mode 100644 +index 000000000..537876c36 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdspi.h +@@ -0,0 +1,138 @@ ++/* ++ * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdspi.h 514727 2014-11-12 03:02:48Z $ ++ */ ++#ifndef _BCM_SD_SPI_H ++#define _BCM_SD_SPI_H ++ ++/* global msglevel for debug messages - bitvals come from sdiovar.h */ ++ ++#define sd_err(x) ++#define sd_trace(x) ++#define sd_info(x) ++#define sd_debug(x) ++#define sd_data(x) ++#define sd_ctrl(x) ++ ++#define sd_log(x) ++ ++#define SDIOH_ASSERT(exp) \ ++ do { if (!(exp)) \ ++ printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ ++ } while (0) ++ ++#define BLOCK_SIZE_4318 64 ++#define BLOCK_SIZE_4328 512 ++ ++/* internal return code */ ++#define SUCCESS 0 ++#undef ERROR ++#define ERROR 1 ++ ++/* private bus modes */ ++#define SDIOH_MODE_SPI 0 ++ ++#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ ++#define USE_MULTIBLOCK 0x4 ++ ++struct sdioh_info { ++ uint cfg_bar; /* pci cfg address for bar */ ++ uint32 caps; /* cached value of capabilities reg */ ++ uint bar0; /* BAR0 for PCI Device */ ++ osl_t *osh; /* osh handler */ ++ void *controller; /* Pointer to SPI Controller's private data struct */ ++ ++ uint lockcount; /* nest count of sdspi_lock() calls */ ++ bool client_intr_enabled; /* interrupt connnected flag */ ++ bool intr_handler_valid; /* client driver interrupt handler valid */ ++ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ ++ void *intr_handler_arg; /* argument to call interrupt handler */ ++ bool initialized; /* card initialized */ ++ uint32 target_dev; /* Target device ID */ ++ uint32 intmask; /* Current active interrupts */ ++ void *sdos_info; /* Pointer to per-OS private data */ ++ ++ uint32 controller_type; /* Host controller type */ ++ uint8 version; /* Host Controller Spec Compliance Version */ ++ uint irq; /* Client irq */ ++ uint32 intrcount; /* Client interrupts */ ++ uint32 local_intrcount; /* Controller interrupts */ ++ bool host_init_done; /* Controller initted */ ++ bool card_init_done; /* Client SDIO interface initted */ ++ bool polled_mode; /* polling for command completion */ ++ ++ bool sd_use_dma; /* DMA on CMD53 */ ++ 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 */ ++ bool got_hcint; /* Host Controller interrupt. */ ++ /* polling hack in wl_linux.c:wl_timer() */ ++ int adapter_slot; /* Maybe dealing with multiple slots/controllers */ ++ int sd_mode; /* SD1/SD4/SPI */ ++ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ ++ uint32 data_xfer_count; /* Current register transfer size */ ++ uint32 cmd53_wr_data; /* Used to pass CMD53 write data */ ++ uint32 card_response; /* Used to pass back response status byte */ ++ uint32 card_rsp_data; /* Used to pass back response data word */ ++ uint16 card_rca; /* Current Address */ ++ uint8 num_funcs; /* Supported funcs on client */ ++ uint32 com_cis_ptr; ++ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; ++ void *dma_buf; ++ ulong dma_phys; ++ int r_cnt; /* rx count */ ++ int t_cnt; /* tx_count */ ++}; ++ ++/************************************************************ ++ * Internal interfaces: per-port references into bcmsdspi.c ++ */ ++ ++/* Global message bits */ ++extern uint sd_msglevel; ++ ++/************************************************************** ++ * Internal interfaces: bcmsdspi.c references to per-port code ++ */ ++ ++/* Register mapping routines */ ++extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size); ++extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size); ++ ++/* Interrupt (de)registration routines */ ++extern int spi_register_irq(sdioh_info_t *sd, uint irq); ++extern void spi_free_irq(uint irq, sdioh_info_t *sd); ++ ++/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ ++extern void spi_lock(sdioh_info_t *sd); ++extern void spi_unlock(sdioh_info_t *sd); ++ ++/* Allocate/init/free per-OS private data */ ++extern int spi_osinit(sdioh_info_t *sd); ++extern void spi_osfree(sdioh_info_t *sd); ++ ++#endif /* _BCM_SD_SPI_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdstd.h +new file mode 100644 +index 000000000..ff3b0d1f2 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsdstd.h +@@ -0,0 +1,285 @@ ++/* ++ * 'Standard' SDIO HOST CONTROLLER driver ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsdstd.h 514727 2014-11-12 03:02:48Z $ ++ */ ++#ifndef _BCM_SD_STD_H ++#define _BCM_SD_STD_H ++ ++/* global msglevel for debug messages - bitvals come from sdiovar.h */ ++#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) ++#define sd_trace(x) ++#define sd_info(x) ++#define sd_debug(x) ++#define sd_data(x) ++#define sd_ctrl(x) ++#define sd_dma(x) ++ ++#define sd_sync_dma(sd, read, nbytes) ++#define sd_init_dma(sd) ++#define sd_ack_intr(sd) ++#define sd_wakeup(sd); ++/* Allocate/init/free per-OS private data */ ++extern int sdstd_osinit(sdioh_info_t *sd); ++extern void sdstd_osfree(sdioh_info_t *sd); ++ ++#define sd_log(x) ++ ++#define SDIOH_ASSERT(exp) \ ++ do { if (!(exp)) \ ++ printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ ++ } while (0) ++ ++#define BLOCK_SIZE_4318 64 ++#define BLOCK_SIZE_4328 512 ++ ++/* internal return code */ ++#define SUCCESS 0 ++#define ERROR 1 ++ ++/* private bus modes */ ++#define SDIOH_MODE_SPI 0 ++#define SDIOH_MODE_SD1 1 ++#define SDIOH_MODE_SD4 2 ++ ++#define MAX_SLOTS 6 /* For PCI: Only 6 BAR entries => 6 slots */ ++#define SDIOH_REG_WINSZ 0x100 /* Number of registers in Standard Host Controller */ ++ ++#define SDIOH_TYPE_ARASAN_HDK 1 ++#define SDIOH_TYPE_BCM27XX 2 ++#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */ ++#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */ ++#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */ ++ ++/* For linux, allow yielding for dongle */ ++#define BCMSDYIELD ++ ++/* Expected card status value for CMD7 */ ++#define SDIOH_CMD7_EXP_STATUS 0x00001E00 ++ ++#define RETRIES_LARGE 100000 ++#define sdstd_os_yield(sd) do {} while (0) ++#define RETRIES_SMALL 100 ++ ++ ++#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ ++#define USE_MULTIBLOCK 0x4 ++ ++#define USE_FIFO 0x8 /* Fifo vs non-fifo */ ++ ++#define CLIENT_INTR 0x100 /* Get rid of this! */ ++ ++#define HC_INTR_RETUNING 0x1000 ++ ++ ++#ifdef BCMSDIOH_TXGLOM ++/* Total glom pkt can not exceed 64K ++ * need one more slot for glom padding packet ++ */ ++#define SDIOH_MAXGLOM_SIZE (40+1) ++ ++typedef struct glom_buf { ++ uint32 count; /* Total number of pkts queued */ ++ void *dma_buf_arr[SDIOH_MAXGLOM_SIZE]; /* Frame address */ ++ ulong dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */ ++ uint16 nbytes[SDIOH_MAXGLOM_SIZE]; /* Size of each frame */ ++} glom_buf_t; ++#endif ++ ++struct sdioh_info { ++ uint cfg_bar; /* pci cfg address for bar */ ++ uint32 caps; /* cached value of capabilities reg */ ++ uint32 curr_caps; /* max current capabilities reg */ ++ ++ osl_t *osh; /* osh handler */ ++ volatile char *mem_space; /* pci device memory va */ ++ uint lockcount; /* nest count of sdstd_lock() calls */ ++ bool client_intr_enabled; /* interrupt connnected flag */ ++ bool intr_handler_valid; /* client driver interrupt handler valid */ ++ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ ++ void *intr_handler_arg; /* argument to call interrupt handler */ ++ bool initialized; /* card initialized */ ++ uint target_dev; /* Target device ID */ ++ uint16 intmask; /* Current active interrupts */ ++ void *sdos_info; /* Pointer to per-OS private data */ ++ void *bcmsdh; /* handler to upper layer stack (bcmsdh) */ ++ ++ uint32 controller_type; /* Host controller type */ ++ uint8 version; /* Host Controller Spec Compliance Version */ ++ uint irq; /* Client irq */ ++ int intrcount; /* Client interrupts */ ++ int local_intrcount; /* Controller interrupts */ ++ bool host_init_done; /* Controller initted */ ++ bool card_init_done; /* Client SDIO interface initted */ ++ bool polled_mode; /* polling for command completion */ ++ ++ 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 */ ++ /* polling hack in wl_linux.c:wl_timer() */ ++ int adapter_slot; /* Maybe dealing with multiple slots/controllers */ ++ int sd_mode; /* SD1/SD4/SPI */ ++ int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */ ++ uint32 data_xfer_count; /* Current transfer */ ++ uint16 card_rca; /* Current Address */ ++ int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */ ++ uint8 num_funcs; /* Supported funcs on client */ ++ uint32 com_cis_ptr; ++ uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; ++ void *dma_buf; /* DMA Buffer virtual address */ ++ ulong dma_phys; /* DMA Buffer physical address */ ++ void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */ ++ ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */ ++ ++ /* adjustments needed to make the dma align properly */ ++ void *dma_start_buf; ++ ulong dma_start_phys; ++ uint alloced_dma_size; ++ void *adma2_dscr_start_buf; ++ ulong adma2_dscr_start_phys; ++ uint alloced_adma2_dscr_size; ++ ++ int r_cnt; /* rx count */ ++ int t_cnt; /* tx_count */ ++ bool got_hcint; /* local interrupt flag */ ++ uint16 last_intrstatus; /* to cache intrstatus */ ++ int host_UHSISupported; /* whether UHSI is supported for HC. */ ++ int card_UHSI_voltage_Supported; /* whether UHSI is supported for ++ * Card in terms of Voltage [1.8 or 3.3]. ++ */ ++ int global_UHSI_Supp; /* type of UHSI support in both host and card. ++ * HOST_SDR_UNSUPP: capabilities not supported/matched ++ * HOST_SDR_12_25: SDR12 and SDR25 supported ++ * HOST_SDR_50_104_DDR: one of SDR50/SDR104 or DDR50 supptd ++ */ ++ volatile int sd3_dat_state; /* data transfer state used for retuning check */ ++ volatile int sd3_tun_state; /* tuning state used for retuning check */ ++ bool sd3_tuning_reqd; /* tuning requirement parameter */ ++ uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */ ++#ifdef BCMSDIOH_TXGLOM ++ glom_buf_t glom_info; /* pkt information used for glomming */ ++ uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */ ++#endif ++}; ++ ++#define DMA_MODE_NONE 0 ++#define DMA_MODE_SDMA 1 ++#define DMA_MODE_ADMA1 2 ++#define DMA_MODE_ADMA2 3 ++#define DMA_MODE_ADMA2_64 4 ++#define DMA_MODE_AUTO -1 ++ ++#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE)) ++ ++/* States for Tuning and corr data */ ++#define TUNING_IDLE 0 ++#define TUNING_START 1 ++#define TUNING_START_AFTER_DAT 2 ++#define TUNING_ONGOING 3 ++ ++#define DATA_TRANSFER_IDLE 0 ++#define DATA_TRANSFER_ONGOING 1 ++ ++#define CHECK_TUNING_PRE_DATA 1 ++#define CHECK_TUNING_POST_DATA 2 ++ ++ ++#ifdef DHD_DEBUG ++#define SD_DHD_DISABLE_PERIODIC_TUNING 0x01 ++#define SD_DHD_ENABLE_PERIODIC_TUNING 0x00 ++#endif ++ ++ ++/************************************************************ ++ * Internal interfaces: per-port references into bcmsdstd.c ++ */ ++ ++/* Global message bits */ ++extern uint sd_msglevel; ++ ++/* OS-independent interrupt handler */ ++extern bool check_client_intr(sdioh_info_t *sd); ++ ++/* Core interrupt enable/disable of device interrupts */ ++extern void sdstd_devintr_on(sdioh_info_t *sd); ++extern void sdstd_devintr_off(sdioh_info_t *sd); ++ ++/* Enable/disable interrupts for local controller events */ ++extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err); ++extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err); ++ ++/* Wait for specified interrupt and error bits to be set */ ++extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err); ++ ++ ++/************************************************************** ++ * Internal interfaces: bcmsdstd.c references to per-port code ++ */ ++ ++/* Register mapping routines */ ++extern uint32 *sdstd_reg_map(osl_t *osh, ulong addr, int size); ++extern void sdstd_reg_unmap(osl_t *osh, ulong addr, int size); ++ ++/* Interrupt (de)registration routines */ ++extern int sdstd_register_irq(sdioh_info_t *sd, uint irq); ++extern void sdstd_free_irq(uint irq, sdioh_info_t *sd); ++ ++/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ ++extern void sdstd_lock(sdioh_info_t *sd); ++extern void sdstd_unlock(sdioh_info_t *sd); ++extern void sdstd_waitlockfree(sdioh_info_t *sd); ++ ++/* OS-specific wrappers for safe concurrent register access */ ++extern void sdstd_os_lock_irqsave(sdioh_info_t *sd, ulong* flags); ++extern void sdstd_os_unlock_irqrestore(sdioh_info_t *sd, ulong* flags); ++ ++/* OS-specific wait-for-interrupt-or-status */ ++extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits); ++ ++/* used by bcmsdstd_linux [implemented in sdstd] */ ++extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd); ++extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd); ++extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd); ++extern void sdstd_3_check_and_do_tuning(sdioh_info_t *sd, int tuning_param); ++extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd); ++extern int sdstd_3_get_tune_state(sdioh_info_t *sd); ++extern int sdstd_3_get_data_state(sdioh_info_t *sd); ++extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state); ++extern void sdstd_3_set_data_state(sdioh_info_t *sd, int state); ++extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd); ++extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd); ++extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode); ++ ++/* used by sdstd [implemented in bcmsdstd_linux/ndis] */ ++extern void sdstd_3_start_tuning(sdioh_info_t *sd); ++extern void sdstd_3_osinit_tuning(sdioh_info_t *sd); ++extern void sdstd_3_osclean_tuning(sdioh_info_t *sd); ++ ++extern void sdstd_enable_disable_periodic_timer(sdioh_info_t * sd, uint val); ++ ++extern sdioh_info_t *sdioh_attach(osl_t *osh, void *bar0, uint irq); ++extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd); ++#endif /* _BCM_SD_STD_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmspi.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmspi.h +new file mode 100644 +index 000000000..9b4bd2d8a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmspi.h +@@ -0,0 +1,43 @@ ++/* ++ * Broadcom SPI Low-Level Hardware Driver API ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmspi.h 514727 2014-11-12 03:02:48Z $ ++ */ ++#ifndef _BCM_SPI_H ++#define _BCM_SPI_H ++ ++extern void spi_devintr_off(sdioh_info_t *sd); ++extern void spi_devintr_on(sdioh_info_t *sd); ++extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor); ++extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode); ++extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr); ++extern bool spi_hw_attach(sdioh_info_t *sd); ++extern bool spi_hw_detach(sdioh_info_t *sd); ++extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); ++extern void spi_spinbits(sdioh_info_t *sd); ++extern void spi_waitbits(sdioh_info_t *sd, bool yield); ++ ++#endif /* _BCM_SPI_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h +new file mode 100644 +index 000000000..e9735ffc6 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h +@@ -0,0 +1,165 @@ ++/* ++ * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmspibrcm.h 514727 2014-11-12 03:02:48Z $ ++ */ ++#ifndef _BCM_SPI_BRCM_H ++#define _BCM_SPI_BRCM_H ++ ++#ifndef SPI_MAX_IOFUNCS ++/* Maximum number of I/O funcs */ ++#define SPI_MAX_IOFUNCS 4 ++#endif ++/* global msglevel for debug messages - bitvals come from sdiovar.h */ ++ ++#if defined(DHD_DEBUG) ++#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0) ++#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0) ++#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0) ++#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0) ++#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0) ++#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf 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 ++ ++#define sd_log(x) ++ ++#define SDIOH_ASSERT(exp) \ ++ do { if (!(exp)) \ ++ printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \ ++ } while (0) ++ ++#define BLOCK_SIZE_F1 64 ++#define BLOCK_SIZE_F2 2048 ++#define BLOCK_SIZE_F3 2048 ++ ++/* internal return code */ ++#define SUCCESS 0 ++#undef ERROR ++#define ERROR 1 ++#define ERROR_UF 2 ++#define ERROR_OF 3 ++ ++/* private bus modes */ ++#define SDIOH_MODE_SPI 0 ++ ++#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */ ++#define USE_MULTIBLOCK 0x4 ++ ++struct sdioh_info { ++ uint cfg_bar; /* pci cfg address for bar */ ++ uint32 caps; /* cached value of capabilities reg */ ++ void *bar0; /* BAR0 for PCI Device */ ++ osl_t *osh; /* osh handler */ ++ void *controller; /* Pointer to SPI Controller's private data struct */ ++ uint lockcount; /* nest count of spi_lock() calls */ ++ bool client_intr_enabled; /* interrupt connnected flag */ ++ bool intr_handler_valid; /* client driver interrupt handler valid */ ++ sdioh_cb_fn_t intr_handler; /* registered interrupt handler */ ++ void *intr_handler_arg; /* argument to call interrupt handler */ ++ bool initialized; /* card initialized */ ++ uint32 target_dev; /* Target device ID */ ++ uint32 intmask; /* Current active interrupts */ ++ void *sdos_info; /* Pointer to per-OS private data */ ++ uint32 controller_type; /* Host controller type */ ++ uint8 version; /* Host Controller Spec Compliance Version */ ++ uint irq; /* Client irq */ ++ uint32 intrcount; /* Client interrupts */ ++ uint32 local_intrcount; /* Controller interrupts */ ++ bool host_init_done; /* Controller initted */ ++ bool card_init_done; /* Client SDIO interface initted */ ++ bool polled_mode; /* polling for command completion */ ++ ++ bool sd_use_dma; /* DMA on CMD53 */ ++ 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 */ ++ /* polling hack in wl_linux.c:wl_timer() */ ++ int adapter_slot; /* Maybe dealing with multiple slots/controllers */ ++ int sd_mode; /* SD1/SD4/SPI */ ++ int client_block_size[SPI_MAX_IOFUNCS]; /* Blocksize */ ++ uint32 data_xfer_count; /* Current transfer */ ++ uint16 card_rca; /* Current Address */ ++ uint8 num_funcs; /* Supported funcs on client */ ++ uint32 card_dstatus; /* 32bit device status */ ++ uint32 com_cis_ptr; ++ uint32 func_cis_ptr[SPI_MAX_IOFUNCS]; ++ void *dma_buf; ++ ulong dma_phys; ++ int r_cnt; /* rx count */ ++ int t_cnt; /* tx_count */ ++ uint32 wordlen; /* host processor 16/32bits */ ++ uint32 prev_fun; ++ uint32 chip; ++ uint32 chiprev; ++ bool resp_delay_all; ++ bool dwordmode; ++ bool resp_delay_new; ++ ++ struct spierrstats_t spierrstats; ++}; ++ ++/************************************************************ ++ * Internal interfaces: per-port references into bcmspibrcm.c ++ */ ++ ++/* Global message bits */ ++extern uint sd_msglevel; ++ ++/************************************************************** ++ * Internal interfaces: bcmspibrcm.c references to per-port code ++ */ ++ ++/* Interrupt (de)registration routines */ ++extern int spi_register_irq(sdioh_info_t *sd, uint irq); ++extern void spi_free_irq(uint irq, sdioh_info_t *sd); ++ ++/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ ++extern void spi_lock(sdioh_info_t *sd); ++extern void spi_unlock(sdioh_info_t *sd); ++ ++/* Allocate/init/free per-OS private data */ ++extern int spi_osinit(sdioh_info_t *sd); ++extern void spi_osfree(sdioh_info_t *sd); ++ ++#define SPI_RW_FLAG_M BITFIELD_MASK(1) /* Bit [31] - R/W Command Bit */ ++#define SPI_RW_FLAG_S 31 ++#define SPI_ACCESS_M BITFIELD_MASK(1) /* Bit [30] - Fixed/Incr Access */ ++#define SPI_ACCESS_S 30 ++#define SPI_FUNCTION_M BITFIELD_MASK(2) /* Bit [29:28] - Function Number */ ++#define SPI_FUNCTION_S 28 ++#define SPI_REG_ADDR_M BITFIELD_MASK(17) /* Bit [27:11] - Address */ ++#define SPI_REG_ADDR_S 11 ++#define SPI_LEN_M BITFIELD_MASK(11) /* Bit [10:0] - Packet length */ ++#define SPI_LEN_S 0 ++ ++#endif /* _BCM_SPI_BRCM_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h +new file mode 100644 +index 000000000..f1e9bfe7d +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h +@@ -0,0 +1,973 @@ ++/* ++ * SROM format definition. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsrom_fmt.h 646789 2016-06-30 19:43:02Z $ ++ */ ++ ++#ifndef _bcmsrom_fmt_h_ ++#define _bcmsrom_fmt_h_ ++ ++#define SROM_MAXREV 13 /* max revision supported by driver */ ++ ++/* Maximum srom: 12 Kilobits == 1536 bytes */ ++ ++#define SROM_MAX 1536 ++#define SROM_MAXW 594 ++ ++#ifdef LARGE_NVRAM_MAXSZ ++#define VARS_MAX LARGE_NVRAM_MAXSZ ++#else ++#define VARS_MAX 4096 ++#endif /* LARGE_NVRAM_MAXSZ */ ++ ++/* PCI fields */ ++#define PCI_F0DEVID 48 ++ ++ ++#define SROM_WORDS 64 ++ ++#define SROM3_SWRGN_OFF 28 /* s/w region offset in words */ ++ ++#define SROM_SSID 2 ++#define SROM_SVID 3 ++ ++#define SROM_WL1LHMAXP 29 ++ ++#define SROM_WL1LPAB0 30 ++#define SROM_WL1LPAB1 31 ++#define SROM_WL1LPAB2 32 ++ ++#define SROM_WL1HPAB0 33 ++#define SROM_WL1HPAB1 34 ++#define SROM_WL1HPAB2 35 ++ ++#define SROM_MACHI_IL0 36 ++#define SROM_MACMID_IL0 37 ++#define SROM_MACLO_IL0 38 ++#define SROM_MACHI_ET0 39 ++#define SROM_MACMID_ET0 40 ++#define SROM_MACLO_ET0 41 ++#define SROM_MACHI_ET1 42 ++#define SROM_MACMID_ET1 43 ++#define SROM_MACLO_ET1 44 ++#define SROM3_MACHI 37 ++#define SROM3_MACMID 38 ++#define SROM3_MACLO 39 ++ ++#define SROM_BXARSSI2G 40 ++#define SROM_BXARSSI5G 41 ++ ++#define SROM_TRI52G 42 ++#define SROM_TRI5GHL 43 ++ ++#define SROM_RXPO52G 45 ++ ++#define SROM2_ENETPHY 45 ++ ++#define SROM_AABREV 46 ++/* Fields in AABREV */ ++#define SROM_BR_MASK 0x00ff ++#define SROM_CC_MASK 0x0f00 ++#define SROM_CC_SHIFT 8 ++#define SROM_AA0_MASK 0x3000 ++#define SROM_AA0_SHIFT 12 ++#define SROM_AA1_MASK 0xc000 ++#define SROM_AA1_SHIFT 14 ++ ++#define SROM_WL0PAB0 47 ++#define SROM_WL0PAB1 48 ++#define SROM_WL0PAB2 49 ++ ++#define SROM_LEDBH10 50 ++#define SROM_LEDBH32 51 ++ ++#define SROM_WL10MAXP 52 ++ ++#define SROM_WL1PAB0 53 ++#define SROM_WL1PAB1 54 ++#define SROM_WL1PAB2 55 ++ ++#define SROM_ITT 56 ++ ++#define SROM_BFL 57 ++#define SROM_BFL2 28 ++#define SROM3_BFL2 61 ++ ++#define SROM_AG10 58 ++ ++#define SROM_CCODE 59 ++ ++#define SROM_OPO 60 ++ ++#define SROM3_LEDDC 62 ++ ++#define SROM_CRCREV 63 ++ ++/* SROM Rev 4: Reallocate the software part of the srom to accomodate ++ * MIMO features. It assumes up to two PCIE functions and 440 bytes ++ * of useable srom i.e. the useable storage in chips with OTP that ++ * implements hardware redundancy. ++ */ ++ ++#define SROM4_WORDS 220 ++ ++#define SROM4_SIGN 32 ++#define SROM4_SIGNATURE 0x5372 ++ ++#define SROM4_BREV 33 ++ ++#define SROM4_BFL0 34 ++#define SROM4_BFL1 35 ++#define SROM4_BFL2 36 ++#define SROM4_BFL3 37 ++#define SROM5_BFL0 37 ++#define SROM5_BFL1 38 ++#define SROM5_BFL2 39 ++#define SROM5_BFL3 40 ++ ++#define SROM4_MACHI 38 ++#define SROM4_MACMID 39 ++#define SROM4_MACLO 40 ++#define SROM5_MACHI 41 ++#define SROM5_MACMID 42 ++#define SROM5_MACLO 43 ++ ++#define SROM4_CCODE 41 ++#define SROM4_REGREV 42 ++#define SROM5_CCODE 34 ++#define SROM5_REGREV 35 ++ ++#define SROM4_LEDBH10 43 ++#define SROM4_LEDBH32 44 ++#define SROM5_LEDBH10 59 ++#define SROM5_LEDBH32 60 ++ ++#define SROM4_LEDDC 45 ++#define SROM5_LEDDC 45 ++ ++#define SROM4_AA 46 ++#define SROM4_AA2G_MASK 0x00ff ++#define SROM4_AA2G_SHIFT 0 ++#define SROM4_AA5G_MASK 0xff00 ++#define SROM4_AA5G_SHIFT 8 ++ ++#define SROM4_AG10 47 ++#define SROM4_AG32 48 ++ ++#define SROM4_TXPID2G 49 ++#define SROM4_TXPID5G 51 ++#define SROM4_TXPID5GL 53 ++#define SROM4_TXPID5GH 55 ++ ++#define SROM4_TXRXC 61 ++#define SROM4_TXCHAIN_MASK 0x000f ++#define SROM4_TXCHAIN_SHIFT 0 ++#define SROM4_RXCHAIN_MASK 0x00f0 ++#define SROM4_RXCHAIN_SHIFT 4 ++#define SROM4_SWITCH_MASK 0xff00 ++#define SROM4_SWITCH_SHIFT 8 ++ ++ ++/* Per-path fields */ ++#define MAX_PATH_SROM 4 ++#define SROM4_PATH0 64 ++#define SROM4_PATH1 87 ++#define SROM4_PATH2 110 ++#define SROM4_PATH3 133 ++ ++#define SROM4_2G_ITT_MAXP 0 ++#define SROM4_2G_PA 1 ++#define SROM4_5G_ITT_MAXP 5 ++#define SROM4_5GLH_MAXP 6 ++#define SROM4_5G_PA 7 ++#define SROM4_5GL_PA 11 ++#define SROM4_5GH_PA 15 ++ ++/* Fields in the ITT_MAXP and 5GLH_MAXP words */ ++#define B2G_MAXP_MASK 0xff ++#define B2G_ITT_SHIFT 8 ++#define B5G_MAXP_MASK 0xff ++#define B5G_ITT_SHIFT 8 ++#define B5GH_MAXP_MASK 0xff ++#define B5GL_MAXP_SHIFT 8 ++ ++/* All the miriad power offsets */ ++#define SROM4_2G_CCKPO 156 ++#define SROM4_2G_OFDMPO 157 ++#define SROM4_5G_OFDMPO 159 ++#define SROM4_5GL_OFDMPO 161 ++#define SROM4_5GH_OFDMPO 163 ++#define SROM4_2G_MCSPO 165 ++#define SROM4_5G_MCSPO 173 ++#define SROM4_5GL_MCSPO 181 ++#define SROM4_5GH_MCSPO 189 ++#define SROM4_CDDPO 197 ++#define SROM4_STBCPO 198 ++#define SROM4_BW40PO 199 ++#define SROM4_BWDUPPO 200 ++ ++#define SROM4_CRCREV 219 ++ ++ ++/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6. ++ * This is acombined srom for both MIMO and SISO boards, usable in ++ * the .130 4Kilobit OTP with hardware redundancy. ++ */ ++ ++#define SROM8_SIGN 64 ++ ++#define SROM8_BREV 65 ++ ++#define SROM8_BFL0 66 ++#define SROM8_BFL1 67 ++#define SROM8_BFL2 68 ++#define SROM8_BFL3 69 ++ ++#define SROM8_MACHI 70 ++#define SROM8_MACMID 71 ++#define SROM8_MACLO 72 ++ ++#define SROM8_CCODE 73 ++#define SROM8_REGREV 74 ++ ++#define SROM8_LEDBH10 75 ++#define SROM8_LEDBH32 76 ++ ++#define SROM8_LEDDC 77 ++ ++#define SROM8_AA 78 ++ ++#define SROM8_AG10 79 ++#define SROM8_AG32 80 ++ ++#define SROM8_TXRXC 81 ++ ++#define SROM8_BXARSSI2G 82 ++#define SROM8_BXARSSI5G 83 ++#define SROM8_TRI52G 84 ++#define SROM8_TRI5GHL 85 ++#define SROM8_RXPO52G 86 ++ ++#define SROM8_FEM2G 87 ++#define SROM8_FEM5G 88 ++#define SROM8_FEM_ANTSWLUT_MASK 0xf800 ++#define SROM8_FEM_ANTSWLUT_SHIFT 11 ++#define SROM8_FEM_TR_ISO_MASK 0x0700 ++#define SROM8_FEM_TR_ISO_SHIFT 8 ++#define SROM8_FEM_PDET_RANGE_MASK 0x00f8 ++#define SROM8_FEM_PDET_RANGE_SHIFT 3 ++#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006 ++#define SROM8_FEM_EXTPA_GAIN_SHIFT 1 ++#define SROM8_FEM_TSSIPOS_MASK 0x0001 ++#define SROM8_FEM_TSSIPOS_SHIFT 0 ++ ++#define SROM8_THERMAL 89 ++ ++/* 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 */ ++#define SROM8_FOC_HWIQ_IQSWP 92 ++ ++#define SROM8_EXTLNAGAIN 93 ++ ++/* Temperature delta for PHY calibration */ ++#define SROM8_PHYCAL_TEMPDELTA 94 ++ ++/* Measured power 1 & 2, 0-13 bits at offset 95, MSB 2 bits are unused for now. */ ++#define SROM8_MPWR_1_AND_2 95 ++ ++ ++/* Per-path offsets & fields */ ++#define SROM8_PATH0 96 ++#define SROM8_PATH1 112 ++#define SROM8_PATH2 128 ++#define SROM8_PATH3 144 ++ ++#define SROM8_2G_ITT_MAXP 0 ++#define SROM8_2G_PA 1 ++#define SROM8_5G_ITT_MAXP 4 ++#define SROM8_5GLH_MAXP 5 ++#define SROM8_5G_PA 6 ++#define SROM8_5GL_PA 9 ++#define SROM8_5GH_PA 12 ++ ++/* All the miriad power offsets */ ++#define SROM8_2G_CCKPO 160 ++ ++#define SROM8_2G_OFDMPO 161 ++#define SROM8_5G_OFDMPO 163 ++#define SROM8_5GL_OFDMPO 165 ++#define SROM8_5GH_OFDMPO 167 ++ ++#define SROM8_2G_MCSPO 169 ++#define SROM8_5G_MCSPO 177 ++#define SROM8_5GL_MCSPO 185 ++#define SROM8_5GH_MCSPO 193 ++ ++#define SROM8_CDDPO 201 ++#define SROM8_STBCPO 202 ++#define SROM8_BW40PO 203 ++#define SROM8_BWDUPPO 204 ++ ++/* SISO PA parameters are in the path0 spaces */ ++#define SROM8_SISO 96 ++ ++/* Legacy names for SISO PA paramters */ ++#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP) ++#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA) ++#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1) ++#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2) ++#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP) ++#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP) ++#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA) ++#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1) ++#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2) ++#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA) ++#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1) ++#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2) ++#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA) ++#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1) ++#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2) ++ ++#define SROM8_CRCREV 219 ++ ++/* SROM REV 9 */ ++#define SROM9_2GPO_CCKBW20 160 ++#define SROM9_2GPO_CCKBW20UL 161 ++#define SROM9_2GPO_LOFDMBW20 162 ++#define SROM9_2GPO_LOFDMBW20UL 164 ++ ++#define SROM9_5GLPO_LOFDMBW20 166 ++#define SROM9_5GLPO_LOFDMBW20UL 168 ++#define SROM9_5GMPO_LOFDMBW20 170 ++#define SROM9_5GMPO_LOFDMBW20UL 172 ++#define SROM9_5GHPO_LOFDMBW20 174 ++#define SROM9_5GHPO_LOFDMBW20UL 176 ++ ++#define SROM9_2GPO_MCSBW20 178 ++#define SROM9_2GPO_MCSBW20UL 180 ++#define SROM9_2GPO_MCSBW40 182 ++ ++#define SROM9_5GLPO_MCSBW20 184 ++#define SROM9_5GLPO_MCSBW20UL 186 ++#define SROM9_5GLPO_MCSBW40 188 ++#define SROM9_5GMPO_MCSBW20 190 ++#define SROM9_5GMPO_MCSBW20UL 192 ++#define SROM9_5GMPO_MCSBW40 194 ++#define SROM9_5GHPO_MCSBW20 196 ++#define SROM9_5GHPO_MCSBW20UL 198 ++#define SROM9_5GHPO_MCSBW40 200 ++ ++#define SROM9_PO_MCS32 202 ++#define SROM9_PO_LOFDM40DUP 203 ++#define SROM9_EU_EDCRSTH 204 ++#define SROM10_EU_EDCRSTH 204 ++#define SROM8_RXGAINERR_2G 205 ++#define SROM8_RXGAINERR_5GL 206 ++#define SROM8_RXGAINERR_5GM 207 ++#define SROM8_RXGAINERR_5GH 208 ++#define SROM8_RXGAINERR_5GU 209 ++#define SROM8_SUBBAND_PPR 210 ++#define SROM8_PCIEINGRESS_WAR 211 ++#define SROM8_EU_EDCRSTH 212 ++#define SROM9_SAR 212 ++ ++#define SROM8_NOISELVL_2G 213 ++#define SROM8_NOISELVL_5GL 214 ++#define SROM8_NOISELVL_5GM 215 ++#define SROM8_NOISELVL_5GH 216 ++#define SROM8_NOISELVL_5GU 217 ++#define SROM8_NOISECALOFFSET 218 ++ ++#define SROM9_REV_CRC 219 ++ ++#define SROM10_CCKPWROFFSET 218 ++#define SROM10_SIGN 219 ++#define SROM10_SWCTRLMAP_2G 220 ++#define SROM10_CRCREV 229 ++ ++#define SROM10_WORDS 230 ++#define SROM10_SIGNATURE SROM4_SIGNATURE ++ ++ ++/* SROM REV 11 */ ++#define SROM11_BREV 65 ++ ++#define SROM11_BFL0 66 ++#define SROM11_BFL1 67 ++#define SROM11_BFL2 68 ++#define SROM11_BFL3 69 ++#define SROM11_BFL4 70 ++#define SROM11_BFL5 71 ++ ++#define SROM11_MACHI 72 ++#define SROM11_MACMID 73 ++#define SROM11_MACLO 74 ++ ++#define SROM11_CCODE 75 ++#define SROM11_REGREV 76 ++ ++#define SROM11_LEDBH10 77 ++#define SROM11_LEDBH32 78 ++ ++#define SROM11_LEDDC 79 ++ ++#define SROM11_AA 80 ++ ++#define SROM11_AGBG10 81 ++#define SROM11_AGBG2A0 82 ++#define SROM11_AGA21 83 ++ ++#define SROM11_TXRXC 84 ++ ++#define SROM11_FEM_CFG1 85 ++#define SROM11_FEM_CFG2 86 ++ ++/* Masks and offsets for FEM_CFG */ ++#define SROM11_FEMCTRL_MASK 0xf800 ++#define SROM11_FEMCTRL_SHIFT 11 ++#define SROM11_PAPDCAP_MASK 0x0400 ++#define SROM11_PAPDCAP_SHIFT 10 ++#define SROM11_TWORANGETSSI_MASK 0x0200 ++#define SROM11_TWORANGETSSI_SHIFT 9 ++#define SROM11_PDGAIN_MASK 0x01f0 ++#define SROM11_PDGAIN_SHIFT 4 ++#define SROM11_EPAGAIN_MASK 0x000e ++#define SROM11_EPAGAIN_SHIFT 1 ++#define SROM11_TSSIPOSSLOPE_MASK 0x0001 ++#define SROM11_TSSIPOSSLOPE_SHIFT 0 ++#define SROM11_GAINCTRLSPH_MASK 0xf800 ++#define SROM11_GAINCTRLSPH_SHIFT 11 ++ ++#define SROM11_THERMAL 87 ++#define SROM11_MPWR_RAWTS 88 ++#define SROM11_TS_SLP_OPT_CORRX 89 ++#define SROM11_XTAL_FREQ 90 ++#define SROM11_5GB0_4080_W0_A1 91 ++#define SROM11_PHYCAL_TEMPDELTA 92 ++#define SROM11_MPWR_1_AND_2 93 ++#define SROM11_5GB0_4080_W1_A1 94 ++#define SROM11_TSSIFLOOR_2G 95 ++#define SROM11_TSSIFLOOR_5GL 96 ++#define SROM11_TSSIFLOOR_5GM 97 ++#define SROM11_TSSIFLOOR_5GH 98 ++#define SROM11_TSSIFLOOR_5GU 99 ++ ++/* Masks and offsets for Thermal parameters */ ++#define SROM11_TEMPS_PERIOD_MASK 0xf0 ++#define SROM11_TEMPS_PERIOD_SHIFT 4 ++#define SROM11_TEMPS_HYSTERESIS_MASK 0x0f ++#define SROM11_TEMPS_HYSTERESIS_SHIFT 0 ++#define SROM11_TEMPCORRX_MASK 0xfc ++#define SROM11_TEMPCORRX_SHIFT 2 ++#define SROM11_TEMPSENSE_OPTION_MASK 0x3 ++#define SROM11_TEMPSENSE_OPTION_SHIFT 0 ++ ++#define SROM11_PDOFF_2G_40M_A0_MASK 0x000f ++#define SROM11_PDOFF_2G_40M_A0_SHIFT 0 ++#define SROM11_PDOFF_2G_40M_A1_MASK 0x00f0 ++#define SROM11_PDOFF_2G_40M_A1_SHIFT 4 ++#define SROM11_PDOFF_2G_40M_A2_MASK 0x0f00 ++#define SROM11_PDOFF_2G_40M_A2_SHIFT 8 ++#define SROM11_PDOFF_2G_40M_VALID_MASK 0x8000 ++#define SROM11_PDOFF_2G_40M_VALID_SHIFT 15 ++ ++#define SROM11_PDOFF_2G_40M 100 ++#define SROM11_PDOFF_40M_A0 101 ++#define SROM11_PDOFF_40M_A1 102 ++#define SROM11_PDOFF_40M_A2 103 ++#define SROM11_5GB0_4080_W2_A1 103 ++#define SROM11_PDOFF_80M_A0 104 ++#define SROM11_PDOFF_80M_A1 105 ++#define SROM11_PDOFF_80M_A2 106 ++#define SROM11_5GB1_4080_W0_A1 106 ++ ++#define SROM11_SUBBAND5GVER 107 ++ ++/* Per-path fields and offset */ ++#define MAX_PATH_SROM_11 3 ++#define SROM11_PATH0 108 ++#define SROM11_PATH1 128 ++#define SROM11_PATH2 148 ++ ++#define SROM11_2G_MAXP 0 ++#define SROM11_5GB1_4080_PA 0 ++#define SROM11_2G_PA 1 ++#define SROM11_5GB2_4080_PA 2 ++#define SROM11_RXGAINS1 4 ++#define SROM11_RXGAINS 5 ++#define SROM11_5GB3_4080_PA 5 ++#define SROM11_5GB1B0_MAXP 6 ++#define SROM11_5GB3B2_MAXP 7 ++#define SROM11_5GB0_PA 8 ++#define SROM11_5GB1_PA 11 ++#define SROM11_5GB2_PA 14 ++#define SROM11_5GB3_PA 17 ++ ++/* Masks and offsets for rxgains */ ++#define SROM11_RXGAINS5GTRELNABYPA_MASK 0x8000 ++#define SROM11_RXGAINS5GTRELNABYPA_SHIFT 15 ++#define SROM11_RXGAINS5GTRISOA_MASK 0x7800 ++#define SROM11_RXGAINS5GTRISOA_SHIFT 11 ++#define SROM11_RXGAINS5GELNAGAINA_MASK 0x0700 ++#define SROM11_RXGAINS5GELNAGAINA_SHIFT 8 ++#define SROM11_RXGAINS2GTRELNABYPA_MASK 0x0080 ++#define SROM11_RXGAINS2GTRELNABYPA_SHIFT 7 ++#define SROM11_RXGAINS2GTRISOA_MASK 0x0078 ++#define SROM11_RXGAINS2GTRISOA_SHIFT 3 ++#define SROM11_RXGAINS2GELNAGAINA_MASK 0x0007 ++#define SROM11_RXGAINS2GELNAGAINA_SHIFT 0 ++#define SROM11_RXGAINS5GHTRELNABYPA_MASK 0x8000 ++#define SROM11_RXGAINS5GHTRELNABYPA_SHIFT 15 ++#define SROM11_RXGAINS5GHTRISOA_MASK 0x7800 ++#define SROM11_RXGAINS5GHTRISOA_SHIFT 11 ++#define SROM11_RXGAINS5GHELNAGAINA_MASK 0x0700 ++#define SROM11_RXGAINS5GHELNAGAINA_SHIFT 8 ++#define SROM11_RXGAINS5GMTRELNABYPA_MASK 0x0080 ++#define SROM11_RXGAINS5GMTRELNABYPA_SHIFT 7 ++#define SROM11_RXGAINS5GMTRISOA_MASK 0x0078 ++#define SROM11_RXGAINS5GMTRISOA_SHIFT 3 ++#define SROM11_RXGAINS5GMELNAGAINA_MASK 0x0007 ++#define SROM11_RXGAINS5GMELNAGAINA_SHIFT 0 ++ ++/* Power per rate */ ++#define SROM11_CCKBW202GPO 168 ++#define SROM11_CCKBW20UL2GPO 169 ++#define SROM11_MCSBW202GPO 170 ++#define SROM11_MCSBW202GPO_1 171 ++#define SROM11_MCSBW402GPO 172 ++#define SROM11_MCSBW402GPO_1 173 ++#define SROM11_DOT11AGOFDMHRBW202GPO 174 ++#define SROM11_OFDMLRBW202GPO 175 ++ ++#define SROM11_MCSBW205GLPO 176 ++#define SROM11_MCSBW205GLPO_1 177 ++#define SROM11_MCSBW405GLPO 178 ++#define SROM11_MCSBW405GLPO_1 179 ++#define SROM11_MCSBW805GLPO 180 ++#define SROM11_MCSBW805GLPO_1 181 ++#define SROM11_RPCAL_2G 182 ++#define SROM11_RPCAL_5GL 183 ++#define SROM11_MCSBW205GMPO 184 ++#define SROM11_MCSBW205GMPO_1 185 ++#define SROM11_MCSBW405GMPO 186 ++#define SROM11_MCSBW405GMPO_1 187 ++#define SROM11_MCSBW805GMPO 188 ++#define SROM11_MCSBW805GMPO_1 189 ++#define SROM11_RPCAL_5GM 190 ++#define SROM11_RPCAL_5GH 191 ++#define SROM11_MCSBW205GHPO 192 ++#define SROM11_MCSBW205GHPO_1 193 ++#define SROM11_MCSBW405GHPO 194 ++#define SROM11_MCSBW405GHPO_1 195 ++#define SROM11_MCSBW805GHPO 196 ++#define SROM11_MCSBW805GHPO_1 197 ++#define SROM11_RPCAL_5GU 198 ++#define SROM11_PDOFF_2G_CCK 199 ++#define SROM11_MCSLR5GLPO 200 ++#define SROM11_MCSLR5GMPO 201 ++#define SROM11_MCSLR5GHPO 202 ++ ++#define SROM11_SB20IN40HRPO 203 ++#define SROM11_SB20IN80AND160HR5GLPO 204 ++#define SROM11_SB40AND80HR5GLPO 205 ++#define SROM11_SB20IN80AND160HR5GMPO 206 ++#define SROM11_SB40AND80HR5GMPO 207 ++#define SROM11_SB20IN80AND160HR5GHPO 208 ++#define SROM11_SB40AND80HR5GHPO 209 ++#define SROM11_SB20IN40LRPO 210 ++#define SROM11_SB20IN80AND160LR5GLPO 211 ++#define SROM11_SB40AND80LR5GLPO 212 ++#define SROM11_TXIDXCAP2G 212 ++#define SROM11_SB20IN80AND160LR5GMPO 213 ++#define SROM11_SB40AND80LR5GMPO 214 ++#define SROM11_TXIDXCAP5G 214 ++#define SROM11_SB20IN80AND160LR5GHPO 215 ++#define SROM11_SB40AND80LR5GHPO 216 ++ ++#define SROM11_DOT11AGDUPHRPO 217 ++#define SROM11_DOT11AGDUPLRPO 218 ++ ++/* MISC */ ++#define SROM11_PCIEINGRESS_WAR 220 ++#define SROM11_SAR 221 ++ ++#define SROM11_NOISELVL_2G 222 ++#define SROM11_NOISELVL_5GL 223 ++#define SROM11_NOISELVL_5GM 224 ++#define SROM11_NOISELVL_5GH 225 ++#define SROM11_NOISELVL_5GU 226 ++ ++#define SROM11_RXGAINERR_2G 227 ++#define SROM11_RXGAINERR_5GL 228 ++#define SROM11_RXGAINERR_5GM 229 ++#define SROM11_RXGAINERR_5GH 230 ++#define SROM11_RXGAINERR_5GU 231 ++ ++#define SROM11_EU_EDCRSTH 232 ++#define SROM12_EU_EDCRSTH 232 ++ ++#define SROM11_SIGN 64 ++#define SROM11_CRCREV 233 ++ ++#define SROM11_WORDS 234 ++#define SROM11_SIGNATURE 0x0634 ++ ++ ++/* SROM REV 12 */ ++#define SROM12_SIGN 64 ++#define SROM12_WORDS 512 ++#define SROM12_SIGNATURE 0x8888 ++#define SROM12_CRCREV 511 ++ ++#define SROM12_BFL6 486 ++#define SROM12_BFL7 487 ++ ++#define SROM12_MCSBW205GX1PO 234 ++#define SROM12_MCSBW205GX1PO_1 235 ++#define SROM12_MCSBW405GX1PO 236 ++#define SROM12_MCSBW405GX1PO_1 237 ++#define SROM12_MCSBW805GX1PO 238 ++#define SROM12_MCSBW805GX1PO_1 239 ++#define SROM12_MCSLR5GX1PO 240 ++#define SROM12_SB40AND80LR5GX1PO 241 ++#define SROM12_SB20IN80AND160LR5GX1PO 242 ++#define SROM12_SB20IN80AND160HR5GX1PO 243 ++#define SROM12_SB40AND80HR5GX1PO 244 ++ ++#define SROM12_MCSBW205GX2PO 245 ++#define SROM12_MCSBW205GX2PO_1 246 ++#define SROM12_MCSBW405GX2PO 247 ++#define SROM12_MCSBW405GX2PO_1 248 ++#define SROM12_MCSBW805GX2PO 249 ++#define SROM12_MCSBW805GX2PO_1 250 ++#define SROM12_MCSLR5GX2PO 251 ++#define SROM12_SB40AND80LR5GX2PO 252 ++#define SROM12_SB20IN80AND160LR5GX2PO 253 ++#define SROM12_SB20IN80AND160HR5GX2PO 254 ++#define SROM12_SB40AND80HR5GX2PO 255 ++ ++/* MISC */ ++#define SROM12_RXGAINS10 483 ++#define SROM12_RXGAINS11 484 ++#define SROM12_RXGAINS12 485 ++ ++/* Per-path fields and offset */ ++#define MAX_PATH_SROM_12 3 ++#define SROM12_PATH0 256 ++#define SROM12_PATH1 328 ++#define SROM12_PATH2 400 ++ ++#define SROM12_5GB42G_MAXP 0 ++#define SROM12_2GB0_PA 1 ++#define SROM12_2GB0_PA_W0 1 ++#define SROM12_2GB0_PA_W1 2 ++#define SROM12_2GB0_PA_W2 3 ++#define SROM12_2GB0_PA_W3 4 ++ ++#define SROM12_RXGAINS 5 ++#define SROM12_5GB1B0_MAXP 6 ++#define SROM12_5GB3B2_MAXP 7 ++ ++#define SROM12_5GB0_PA 8 ++#define SROM12_5GB0_PA_W0 8 ++#define SROM12_5GB0_PA_W1 9 ++#define SROM12_5GB0_PA_W2 10 ++#define SROM12_5GB0_PA_W3 11 ++ ++#define SROM12_5GB1_PA 12 ++#define SROM12_5GB1_PA_W0 12 ++#define SROM12_5GB1_PA_W1 13 ++#define SROM12_5GB1_PA_W2 14 ++#define SROM12_5GB1_PA_W3 15 ++ ++#define SROM12_5GB2_PA 16 ++#define SROM12_5GB2_PA_W0 16 ++#define SROM12_5GB2_PA_W1 17 ++#define SROM12_5GB2_PA_W2 18 ++#define SROM12_5GB2_PA_W3 19 ++ ++#define SROM12_5GB3_PA 20 ++#define SROM12_5GB3_PA_W0 20 ++#define SROM12_5GB3_PA_W1 21 ++#define SROM12_5GB3_PA_W2 22 ++#define SROM12_5GB3_PA_W3 23 ++ ++#define SROM12_5GB4_PA 24 ++#define SROM12_5GB4_PA_W0 24 ++#define SROM12_5GB4_PA_W1 25 ++#define SROM12_5GB4_PA_W2 26 ++#define SROM12_5GB4_PA_W3 27 ++ ++#define SROM12_2G40B0_PA 28 ++#define SROM12_2G40B0_PA_W0 28 ++#define SROM12_2G40B0_PA_W1 29 ++#define SROM12_2G40B0_PA_W2 30 ++#define SROM12_2G40B0_PA_W3 31 ++ ++#define SROM12_5G40B0_PA 32 ++#define SROM12_5G40B0_PA_W0 32 ++#define SROM12_5G40B0_PA_W1 33 ++#define SROM12_5G40B0_PA_W2 34 ++#define SROM12_5G40B0_PA_W3 35 ++ ++#define SROM12_5G40B1_PA 36 ++#define SROM12_5G40B1_PA_W0 36 ++#define SROM12_5G40B1_PA_W1 37 ++#define SROM12_5G40B1_PA_W2 38 ++#define SROM12_5G40B1_PA_W3 39 ++ ++#define SROM12_5G40B2_PA 40 ++#define SROM12_5G40B2_PA_W0 40 ++#define SROM12_5G40B2_PA_W1 41 ++#define SROM12_5G40B2_PA_W2 42 ++#define SROM12_5G40B2_PA_W3 43 ++ ++#define SROM12_5G40B3_PA 44 ++#define SROM12_5G40B3_PA_W0 44 ++#define SROM12_5G40B3_PA_W1 45 ++#define SROM12_5G40B3_PA_W2 46 ++#define SROM12_5G40B3_PA_W3 47 ++ ++#define SROM12_5G40B4_PA 48 ++#define SROM12_5G40B4_PA_W0 48 ++#define SROM12_5G40B4_PA_W1 49 ++#define SROM12_5G40B4_PA_W2 50 ++#define SROM12_5G40B4_PA_W3 51 ++ ++#define SROM12_5G80B0_PA 52 ++#define SROM12_5G80B0_PA_W0 52 ++#define SROM12_5G80B0_PA_W1 53 ++#define SROM12_5G80B0_PA_W2 54 ++#define SROM12_5G80B0_PA_W3 55 ++ ++#define SROM12_5G80B1_PA 56 ++#define SROM12_5G80B1_PA_W0 56 ++#define SROM12_5G80B1_PA_W1 57 ++#define SROM12_5G80B1_PA_W2 58 ++#define SROM12_5G80B1_PA_W3 59 ++ ++#define SROM12_5G80B2_PA 60 ++#define SROM12_5G80B2_PA_W0 60 ++#define SROM12_5G80B2_PA_W1 61 ++#define SROM12_5G80B2_PA_W2 62 ++#define SROM12_5G80B2_PA_W3 63 ++ ++#define SROM12_5G80B3_PA 64 ++#define SROM12_5G80B3_PA_W0 64 ++#define SROM12_5G80B3_PA_W1 65 ++#define SROM12_5G80B3_PA_W2 66 ++#define SROM12_5G80B3_PA_W3 67 ++ ++#define SROM12_5G80B4_PA 68 ++#define SROM12_5G80B4_PA_W0 68 ++#define SROM12_5G80B4_PA_W1 69 ++#define SROM12_5G80B4_PA_W2 70 ++#define SROM12_5G80B4_PA_W3 71 ++ ++/* PD offset */ ++#define SROM12_PDOFF_2G_CCK 472 ++ ++#define SROM12_PDOFF_20in40M_5G_B0 473 ++#define SROM12_PDOFF_20in40M_5G_B1 474 ++#define SROM12_PDOFF_20in40M_5G_B2 475 ++#define SROM12_PDOFF_20in40M_5G_B3 476 ++#define SROM12_PDOFF_20in40M_5G_B4 477 ++ ++#define SROM12_PDOFF_40in80M_5G_B0 478 ++#define SROM12_PDOFF_40in80M_5G_B1 479 ++#define SROM12_PDOFF_40in80M_5G_B2 480 ++#define SROM12_PDOFF_40in80M_5G_B3 481 ++#define SROM12_PDOFF_40in80M_5G_B4 482 ++ ++#define SROM12_PDOFF_20in80M_5G_B0 488 ++#define SROM12_PDOFF_20in80M_5G_B1 489 ++#define SROM12_PDOFF_20in80M_5G_B2 490 ++#define SROM12_PDOFF_20in80M_5G_B3 491 ++#define SROM12_PDOFF_20in80M_5G_B4 492 ++ ++#define SROM13_PDOFFSET20IN40M5GCORE3 98 ++#define SROM13_PDOFFSET20IN40M5GCORE3_1 99 ++#define SROM13_PDOFFSET20IN80M5GCORE3 510 ++#define SROM13_PDOFFSET20IN80M5GCORE3_1 511 ++#define SROM13_PDOFFSET40IN80M5GCORE3 105 ++#define SROM13_PDOFFSET40IN80M5GCORE3_1 106 ++ ++#define SROM13_PDOFFSET20IN40M2G 94 ++#define SROM13_PDOFFSET20IN40M2GCORE3 95 ++ ++#define SROM12_GPDN_L 91 /* GPIO pull down bits [15:0] */ ++#define SROM12_GPDN_H 233 /* GPIO pull down bits [31:16] */ ++ ++#define SROM13_SIGN 64 ++#define SROM13_WORDS 590 ++#define SROM13_SIGNATURE 0x4d55 ++#define SROM13_CRCREV 589 ++ ++ ++/* Per-path fields and offset */ ++#define MAX_PATH_SROM_13 4 ++#define SROM13_PATH0 256 ++#define SROM13_PATH1 328 ++#define SROM13_PATH2 400 ++#define SROM13_PATH3 512 ++#define SROM13_RXGAINS 5 ++ ++#define SROM13_XTALFREQ 90 ++ ++#define SROM13_PDOFFSET20IN40M2G 94 ++#define SROM13_PDOFFSET20IN40M2GCORE3 95 ++#define SROM13_SB20IN40HRLRPOX 96 ++ ++#define SROM13_RXGAINS1CORE3 97 ++ ++#define SROM13_PDOFFSET20IN40M5GCORE3 98 ++#define SROM13_PDOFFSET20IN40M5GCORE3_1 99 ++ ++#define SROM13_ANTGAIN_BANDBGA 100 ++ ++#define SROM13_RXGAINS2CORE0 101 ++#define SROM13_RXGAINS2CORE1 102 ++#define SROM13_RXGAINS2CORE2 103 ++#define SROM13_RXGAINS2CORE3 104 ++ ++#define SROM13_PDOFFSET40IN80M5GCORE3 105 ++#define SROM13_PDOFFSET40IN80M5GCORE3_1 106 ++ ++/* power per rate */ ++#define SROM13_MCS1024QAM2GPO 108 ++#define SROM13_MCS1024QAM5GLPO 109 ++#define SROM13_MCS1024QAM5GLPO_1 110 ++#define SROM13_MCS1024QAM5GMPO 111 ++#define SROM13_MCS1024QAM5GMPO_1 112 ++#define SROM13_MCS1024QAM5GHPO 113 ++#define SROM13_MCS1024QAM5GHPO_1 114 ++#define SROM13_MCS1024QAM5GX1PO 115 ++#define SROM13_MCS1024QAM5GX1PO_1 116 ++#define SROM13_MCS1024QAM5GX2PO 117 ++#define SROM13_MCS1024QAM5GX2PO_1 118 ++ ++#define SROM13_MCSBW1605GLPO 119 ++#define SROM13_MCSBW1605GLPO_1 120 ++#define SROM13_MCSBW1605GMPO 121 ++#define SROM13_MCSBW1605GMPO_1 122 ++#define SROM13_MCSBW1605GHPO 123 ++#define SROM13_MCSBW1605GHPO_1 124 ++ ++#define SROM13_MCSBW1605GX1PO 125 ++#define SROM13_MCSBW1605GX1PO_1 126 ++#define SROM13_MCSBW1605GX2PO 127 ++#define SROM13_MCSBW1605GX2PO_1 128 ++ ++#define SROM13_ULBPPROFFS5GB0 129 ++#define SROM13_ULBPPROFFS5GB1 130 ++#define SROM13_ULBPPROFFS5GB2 131 ++#define SROM13_ULBPPROFFS5GB3 132 ++#define SROM13_ULBPPROFFS5GB4 133 ++#define SROM13_ULBPPROFFS2G 134 ++ ++#define SROM13_MCS8POEXP 135 ++#define SROM13_MCS8POEXP_1 136 ++#define SROM13_MCS9POEXP 137 ++#define SROM13_MCS9POEXP_1 138 ++#define SROM13_MCS10POEXP 139 ++#define SROM13_MCS10POEXP_1 140 ++#define SROM13_MCS11POEXP 141 ++#define SROM13_MCS11POEXP_1 142 ++#define SROM13_ULBPDOFFS5GB0A0 143 ++#define SROM13_ULBPDOFFS5GB0A1 144 ++#define SROM13_ULBPDOFFS5GB0A2 145 ++#define SROM13_ULBPDOFFS5GB0A3 146 ++#define SROM13_ULBPDOFFS5GB1A0 147 ++#define SROM13_ULBPDOFFS5GB1A1 148 ++#define SROM13_ULBPDOFFS5GB1A2 149 ++#define SROM13_ULBPDOFFS5GB1A3 150 ++#define SROM13_ULBPDOFFS5GB2A0 151 ++#define SROM13_ULBPDOFFS5GB2A1 152 ++#define SROM13_ULBPDOFFS5GB2A2 153 ++#define SROM13_ULBPDOFFS5GB2A3 154 ++#define SROM13_ULBPDOFFS5GB3A0 155 ++#define SROM13_ULBPDOFFS5GB3A1 156 ++#define SROM13_ULBPDOFFS5GB3A2 157 ++#define SROM13_ULBPDOFFS5GB3A3 158 ++#define SROM13_ULBPDOFFS5GB4A0 159 ++#define SROM13_ULBPDOFFS5GB4A1 160 ++#define SROM13_ULBPDOFFS5GB4A2 161 ++#define SROM13_ULBPDOFFS5GB4A3 162 ++#define SROM13_ULBPDOFFS2GA0 163 ++#define SROM13_ULBPDOFFS2GA1 164 ++#define SROM13_ULBPDOFFS2GA2 165 ++#define SROM13_ULBPDOFFS2GA3 166 ++ ++#define SROM13_RPCAL5GB4 199 ++#define SROM13_RPCAL2GCORE3 101 ++#define SROM13_RPCAL5GB01CORE3 102 ++#define SROM13_RPCAL5GB23CORE3 103 ++ ++#define SROM13_EU_EDCRSTH 232 ++ ++#define SROM13_SWCTRLMAP4_CFG 493 ++#define SROM13_SWCTRLMAP4_TX2G_FEM3TO0 494 ++#define SROM13_SWCTRLMAP4_RX2G_FEM3TO0 495 ++#define SROM13_SWCTRLMAP4_RXBYP2G_FEM3TO0 496 ++#define SROM13_SWCTRLMAP4_MISC2G_FEM3TO0 497 ++#define SROM13_SWCTRLMAP4_TX5G_FEM3TO0 498 ++#define SROM13_SWCTRLMAP4_RX5G_FEM3TO0 499 ++#define SROM13_SWCTRLMAP4_RXBYP5G_FEM3TO0 500 ++#define SROM13_SWCTRLMAP4_MISC5G_FEM3TO0 501 ++#define SROM13_SWCTRLMAP4_TX2G_FEM7TO4 502 ++#define SROM13_SWCTRLMAP4_RX2G_FEM7TO4 503 ++#define SROM13_SWCTRLMAP4_RXBYP2G_FEM7TO4 504 ++#define SROM13_SWCTRLMAP4_MISC2G_FEM7TO4 505 ++#define SROM13_SWCTRLMAP4_TX5G_FEM7TO4 506 ++#define SROM13_SWCTRLMAP4_RX5G_FEM7TO4 507 ++#define SROM13_SWCTRLMAP4_RXBYP5G_FEM7TO4 508 ++#define SROM13_SWCTRLMAP4_MISC5G_FEM7TO4 509 ++ ++#define SROM13_PDOFFSET20IN80M5GCORE3 510 ++#define SROM13_PDOFFSET20IN80M5GCORE3_1 511 ++ ++#define SROM13_NOISELVLCORE3 584 ++#define SROM13_NOISELVLCORE3_1 585 ++#define SROM13_RXGAINERRCORE3 586 ++#define SROM13_RXGAINERRCORE3_1 587 ++ ++ ++#define SROM16_SIGN 104 ++#define SROM16_WORDS 512 ++#define SROM16_SIGNATURE 0x4347 ++#define SROM16_CRCREV 511 ++ ++typedef struct { ++ uint8 tssipos; /* TSSI positive slope, 1: positive, 0: negative */ ++ uint8 extpagain; /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */ ++ uint8 pdetrange; /* support 32 combinations of different Pdet dynamic ranges */ ++ uint8 triso; /* TR switch isolation */ ++ uint8 antswctrllut; /* antswctrl lookup table configuration: 32 possible choices */ ++} srom_fem_t; ++ ++#endif /* _bcmsrom_fmt_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h +new file mode 100644 +index 000000000..e855186f1 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h +@@ -0,0 +1,1408 @@ ++/* ++ * Table that encodes the srom formats for PCI/PCIe NICs. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmsrom_tbl.h 616054 2016-01-29 13:22:24Z $ ++ */ ++ ++#ifndef _bcmsrom_tbl_h_ ++#define _bcmsrom_tbl_h_ ++ ++#include "sbpcmcia.h" ++#include "wlioctl.h" ++#include ++ ++typedef struct { ++ const char *name; ++ uint32 revmask; ++ uint32 flags; ++ uint16 off; ++ uint16 mask; ++} sromvar_t; ++ ++#define SRFL_MORE 1 /* value continues as described by the next entry */ ++#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 */ ++#define SRFL_ARRAY 0x100 /* value is in an array. All elements EXCEPT FOR THE LAST ++ * ONE in the array should have this flag set. ++ */ ++ ++ ++#define SROM_DEVID_PCIE 48 ++ ++/** ++ * 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. ++ */ ++static const sromvar_t pci_sromvars[] = { ++/* name revmask flags off mask */ ++#if defined(CABLECPE) ++ {"devid", 0xffffff00, SRFL_PRHEX, PCI_F0DEVID, 0xffff}, ++#elif defined(BCMPCIEDEV) && defined(BCMPCIEDEV_ENABLED) ++ {"devid", 0xffffff00, SRFL_PRHEX, SROM_DEVID_PCIE, 0xffff}, ++#else ++ {"devid", 0xffffff00, SRFL_PRHEX|SRFL_NOVAR, PCI_F0DEVID, 0xffff}, ++#endif ++ {"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}, ++ {"subvid", 0xfffffffc, SRFL_PRHEX, SROM_SVID, 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", 0x00000700, 0, SROM8_MACLO, 0xffff}, ++ {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, ++ {"regrev", 0x00000008, 0, SROM_OPO, 0xff00}, ++ {"regrev", 0x00000010, 0, SROM4_REGREV, 0xffff}, ++ {"regrev", 0x000000e0, 0, SROM5_REGREV, 0xffff}, ++ {"regrev", 0x00000700, 0, SROM8_REGREV, 0xffff}, ++ {"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", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff}, ++ {"ledbh1", 0x00000700, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, ++ {"ledbh2", 0x00000700, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff}, ++ {"ledbh3", 0x00000700, 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", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, ++ {"pa0b1", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, ++ {"pa0b2", 0x00000700, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, ++ {"pa0itssit", 0x00000700, 0, SROM8_W0_ITTMAXP, 0xff00}, ++ {"pa0maxpwr", 0x00000700, 0, SROM8_W0_ITTMAXP, 0x00ff}, ++ {"opo", 0x0000000c, 0, SROM_OPO, 0x00ff}, ++ {"opo", 0x00000700, 0, SROM8_2G_OFDMPO, 0x00ff}, ++ {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, ++ {"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff}, ++ {"aa2g", 0x00000700, 0, SROM8_AA, 0x00ff}, ++ {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, ++ {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00}, ++ {"aa5g", 0x00000700, 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", 0x00000700, 0, SROM8_AG10, 0x00ff}, ++ {"ag1", 0x00000700, 0, SROM8_AG10, 0xff00}, ++ {"ag2", 0x00000700, 0, SROM8_AG32, 0x00ff}, ++ {"ag3", 0x00000700, 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", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, ++ {"pa1b1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, ++ {"pa1b2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, ++ {"pa1lob0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, ++ {"pa1lob1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, ++ {"pa1lob2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, ++ {"pa1hib0", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, ++ {"pa1hib1", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, ++ {"pa1hib2", 0x00000700, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, ++ {"pa1itssit", 0x00000700, 0, SROM8_W1_ITTMAXP, 0xff00}, ++ {"pa1maxpwr", 0x00000700, 0, SROM8_W1_ITTMAXP, 0x00ff}, ++ {"pa1lomaxpwr", 0x00000700, 0, SROM8_W1_MAXP_LCHC, 0xff00}, ++ {"pa1himaxpwr", 0x00000700, 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", 0x00000700, 0, SROM8_BXARSSI2G, 0x1800}, ++ {"rssisav2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x0700}, ++ {"rssismc2g", 0x00000700, 0, SROM8_BXARSSI2G, 0x00f0}, ++ {"rssismf2g", 0x00000700, 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", 0x00000700, 0, SROM8_BXARSSI5G, 0x1800}, ++ {"rssisav5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x0700}, ++ {"rssismc5g", 0x00000700, 0, SROM8_BXARSSI5G, 0x00f0}, ++ {"rssismf5g", 0x00000700, 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", 0x00000700, 0, SROM8_TRI52G, 0x00ff}, ++ {"tri5g", 0x00000700, 0, SROM8_TRI52G, 0xff00}, ++ {"tri5gl", 0x00000700, 0, SROM8_TRI5GHL, 0x00ff}, ++ {"tri5gh", 0x00000700, 0, SROM8_TRI5GHL, 0xff00}, ++ {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff}, ++ {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, ++ {"rxpo2g", 0x00000700, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, ++ {"rxpo5g", 0x00000700, 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", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK}, ++ {"rxchain", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK}, ++ {"antswitch", 0x00000700, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK}, ++ {"tssipos2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK}, ++ {"extpagain2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK}, ++ {"pdetrange2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK}, ++ {"triso2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, ++ {"antswctl2g", 0x00000700, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK}, ++ {"tssipos5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK}, ++ {"extpagain5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK}, ++ {"pdetrange5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK}, ++ {"triso5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, ++ {"antswctl5g", 0x00000700, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK}, ++ {"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", 0x00000700, SRFL_CCODE, SROM8_CCODE, 0xffff}, ++ {"macaddr", 0x00000700, 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", 0x00000700, 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}, ++ ++ {"tempthresh", 0x00000700, 0, SROM8_THERMAL, 0xff00}, ++ {"tempoffset", 0x00000700, 0, SROM8_THERMAL, 0x00ff}, ++ {"rawtempsense", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff}, ++ {"measpower", 0x00000700, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00}, ++ {"tempsense_slope", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x00ff}, ++ {"tempcorrx", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00}, ++ {"tempsense_option", 0x00000700, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x0300}, ++ {"freqoffset_corr", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x000f}, ++ {"iqcal_swp_dis", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010}, ++ {"hw_iqcal_en", 0x00000700, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020}, ++ {"elna2g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0x00ff}, ++ {"elna5g", 0x00000700, 0, SROM8_EXTLNAGAIN, 0xff00}, ++ {"phycal_tempdelta", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff}, ++ {"temps_period", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0x0f00}, ++ {"temps_hysteresis", 0x00000700, 0, SROM8_PHYCAL_TEMPDELTA, 0xf000}, ++ {"measpower1", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x007f}, ++ {"measpower2", 0x00000700, SRFL_PRHEX, SROM8_MPWR_1_AND_2, 0x3f80}, ++ ++ {"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}, ++ ++ /* power per rate from sromrev 9 */ ++ {"cckbw202gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20, 0xffff}, ++ {"cckbw20ul2gpo", 0x00000600, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, ++ {"legofdmbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20, 0xffff}, ++ {"", 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff}, ++ {"legofdmbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_LOFDMBW20UL, 0xffff}, ++ {"", 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff}, ++ {"legofdmbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20, 0xffff}, ++ {"", 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff}, ++ {"legofdmbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL, 0xffff}, ++ {"", 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff}, ++ {"legofdmbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20, 0xffff}, ++ {"", 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff}, ++ {"legofdmbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL, 0xffff}, ++ {"", 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff}, ++ {"legofdmbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20, 0xffff}, ++ {"", 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff}, ++ {"legofdmbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL, 0xffff}, ++ {"", 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff}, ++ {"mcsbw202gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff}, ++ {"", 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff}, ++ {"mcsbw20ul2gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff}, ++ {"", 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff}, ++ {"mcsbw402gpo", 0x00000600, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff}, ++ {"", 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff}, ++ {"mcsbw205glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff}, ++ {"", 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff}, ++ {"mcsbw20ul5glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW20UL, 0xffff}, ++ {"", 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff}, ++ {"mcsbw405glpo", 0x00000600, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff}, ++ {"", 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff}, ++ {"mcsbw205gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff}, ++ {"", 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff}, ++ {"mcsbw20ul5gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW20UL, 0xffff}, ++ {"", 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff}, ++ {"mcsbw405gmpo", 0x00000600, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff}, ++ {"", 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff}, ++ {"mcsbw205ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff}, ++ {"", 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff}, ++ {"mcsbw20ul5ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW20UL, 0xffff}, ++ {"", 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff}, ++ {"mcsbw405ghpo", 0x00000600, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff}, ++ {"", 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff}, ++ {"mcs32po", 0x00000600, 0, SROM9_PO_MCS32, 0xffff}, ++ {"legofdm40duppo", 0x00000600, 0, SROM9_PO_LOFDM40DUP, 0xffff}, ++ {"pcieingress_war", 0x00000700, 0, SROM8_PCIEINGRESS_WAR, 0xf}, ++ {"eu_edthresh2g", 0x00000100, 0, SROM8_EU_EDCRSTH, 0x00ff}, ++ {"eu_edthresh5g", 0x00000100, 0, SROM8_EU_EDCRSTH, 0xff00}, ++ {"eu_edthresh2g", 0x00000200, 0, SROM9_EU_EDCRSTH, 0x00ff}, ++ {"eu_edthresh5g", 0x00000200, 0, SROM9_EU_EDCRSTH, 0xff00}, ++ {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f}, ++ {"rxgainerr2ga0", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x003f}, ++ {"rxgainerr2ga1", 0x00000700, 0, SROM8_RXGAINERR_2G, 0x07c0}, ++ {"rxgainerr2ga2", 0x00000700, 0, SROM8_RXGAINERR_2G, 0xf800}, ++ {"rxgainerr5gla0", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x003f}, ++ {"rxgainerr5gla1", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0x07c0}, ++ {"rxgainerr5gla2", 0x00000700, 0, SROM8_RXGAINERR_5GL, 0xf800}, ++ {"rxgainerr5gma0", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x003f}, ++ {"rxgainerr5gma1", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0x07c0}, ++ {"rxgainerr5gma2", 0x00000700, 0, SROM8_RXGAINERR_5GM, 0xf800}, ++ {"rxgainerr5gha0", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x003f}, ++ {"rxgainerr5gha1", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0x07c0}, ++ {"rxgainerr5gha2", 0x00000700, 0, SROM8_RXGAINERR_5GH, 0xf800}, ++ {"rxgainerr5gua0", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x003f}, ++ {"rxgainerr5gua1", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0x07c0}, ++ {"rxgainerr5gua2", 0x00000700, 0, SROM8_RXGAINERR_5GU, 0xf800}, ++ {"sar2g", 0x00000600, 0, SROM9_SAR, 0x00ff}, ++ {"sar5g", 0x00000600, 0, SROM9_SAR, 0xff00}, ++ {"noiselvl2ga0", 0x00000700, 0, SROM8_NOISELVL_2G, 0x001f}, ++ {"noiselvl2ga1", 0x00000700, 0, SROM8_NOISELVL_2G, 0x03e0}, ++ {"noiselvl2ga2", 0x00000700, 0, SROM8_NOISELVL_2G, 0x7c00}, ++ {"noiselvl5gla0", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x001f}, ++ {"noiselvl5gla1", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x03e0}, ++ {"noiselvl5gla2", 0x00000700, 0, SROM8_NOISELVL_5GL, 0x7c00}, ++ {"noiselvl5gma0", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x001f}, ++ {"noiselvl5gma1", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x03e0}, ++ {"noiselvl5gma2", 0x00000700, 0, SROM8_NOISELVL_5GM, 0x7c00}, ++ {"noiselvl5gha0", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x001f}, ++ {"noiselvl5gha1", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x03e0}, ++ {"noiselvl5gha2", 0x00000700, 0, SROM8_NOISELVL_5GH, 0x7c00}, ++ {"noiselvl5gua0", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x001f}, ++ {"noiselvl5gua1", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x03e0}, ++ {"noiselvl5gua2", 0x00000700, 0, SROM8_NOISELVL_5GU, 0x7c00}, ++ {"noisecaloffset", 0x00000300, 0, SROM8_NOISECALOFFSET, 0x00ff}, ++ {"noisecaloffset5g", 0x00000300, 0, SROM8_NOISECALOFFSET, 0xff00}, ++ {"subband5gver", 0x00000700, 0, SROM8_SUBBAND_PPR, 0x7}, ++ ++ {"cckPwrOffset", 0x00000400, 0, SROM10_CCKPWROFFSET, 0xffff}, ++ {"eu_edthresh2g", 0x00000400, 0, SROM10_EU_EDCRSTH, 0x00ff}, ++ {"eu_edthresh5g", 0x00000400, 0, SROM10_EU_EDCRSTH, 0xff00}, ++ /* swctrlmap_2g array, note that the last element doesn't have SRFL_ARRAY flag set */ ++ {"swctrlmap_2g", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G, 0xffff}, ++ {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 1, 0xffff}, ++ {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 2, 0xffff}, ++ {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 3, 0xffff}, ++ {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 4, 0xffff}, ++ {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 5, 0xffff}, ++ {"", 0x00000400, SRFL_MORE|SRFL_PRHEX|SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 6, 0xffff}, ++ {"", 0x00000400, SRFL_ARRAY, SROM10_SWCTRLMAP_2G + 7, 0xffff}, ++ {"", 0x00000400, SRFL_PRHEX, SROM10_SWCTRLMAP_2G + 8, 0xffff}, ++ ++ /* sromrev 11 */ ++ {"boardflags3", 0xfffff800, SRFL_PRHEX|SRFL_MORE, SROM11_BFL4, 0xffff}, ++ {"", 0, 0, SROM11_BFL5, 0xffff}, ++ {"boardnum", 0xfffff800, 0, SROM11_MACLO, 0xffff}, ++ {"macaddr", 0xfffff800, SRFL_ETHADDR, SROM11_MACHI, 0xffff}, ++ {"ccode", 0xfffff800, SRFL_CCODE, SROM11_CCODE, 0xffff}, ++ {"regrev", 0xfffff800, 0, SROM11_REGREV, 0xffff}, ++ {"ledbh0", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0x00ff}, ++ {"ledbh1", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH10, 0xff00}, ++ {"ledbh2", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0x00ff}, ++ {"ledbh3", 0xfffff800, SRFL_NOFFS, SROM11_LEDBH32, 0xff00}, ++ {"leddc", 0xfffff800, SRFL_NOFFS|SRFL_LEDDC, SROM11_LEDDC, 0xffff}, ++ {"aa2g", 0xfffff800, 0, SROM11_AA, 0x00ff}, ++ {"aa5g", 0xfffff800, 0, SROM11_AA, 0xff00}, ++ {"agbg0", 0xfffff800, 0, SROM11_AGBG10, 0xff00}, ++ {"agbg1", 0xfffff800, 0, SROM11_AGBG10, 0x00ff}, ++ {"agbg2", 0xfffff800, 0, SROM11_AGBG2A0, 0xff00}, ++ {"aga0", 0xfffff800, 0, SROM11_AGBG2A0, 0x00ff}, ++ {"aga1", 0xfffff800, 0, SROM11_AGA21, 0xff00}, ++ {"aga2", 0xfffff800, 0, SROM11_AGA21, 0x00ff}, ++ {"txchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_TXCHAIN_MASK}, ++ {"rxchain", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_RXCHAIN_MASK}, ++ {"antswitch", 0xfffff800, SRFL_NOFFS, SROM11_TXRXC, SROM4_SWITCH_MASK}, ++ ++ {"tssiposslope2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0001}, ++ {"epagain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x000e}, ++ {"pdgain2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x01f0}, ++ {"tworangetssi2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0200}, ++ {"papdcap2g", 0xfffff800, 0, SROM11_FEM_CFG1, 0x0400}, ++ {"femctrl", 0xfffff800, 0, SROM11_FEM_CFG1, 0xf800}, ++ ++ {"tssiposslope5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0001}, ++ {"epagain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x000e}, ++ {"pdgain5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x01f0}, ++ {"tworangetssi5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0200}, ++ {"papdcap5g", 0xfffff800, 0, SROM11_FEM_CFG2, 0x0400}, ++ {"gainctrlsph", 0xfffff800, 0, SROM11_FEM_CFG2, 0xf800}, ++ ++ {"tempthresh", 0xfffff800, 0, SROM11_THERMAL, 0xff00}, ++ {"tempoffset", 0xfffff800, 0, SROM11_THERMAL, 0x00ff}, ++ {"rawtempsense", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0x01ff}, ++ {"measpower", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_RAWTS, 0xfe00}, ++ {"tempsense_slope", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x00ff}, ++ {"tempcorrx", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0xfc00}, ++ {"tempsense_option", 0xfffff800, SRFL_PRHEX, SROM11_TS_SLP_OPT_CORRX, 0x0300}, ++ {"xtalfreq", 0xfffff800, 0, SROM11_XTAL_FREQ, 0xffff}, ++ {"txpwrbckof", 0x00000800, SRFL_PRHEX, SROM11_PATH0 + SROM11_2G_MAXP, 0xff00}, ++ /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #1 */ ++ {"pa5gbw4080a1", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W0_A1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W1_A1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_4080_W2_A1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_4080_W0_A1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_4080_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_4080_PA + 2, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_4080_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_4080_PA + 2, 0xffff}, ++ {"phycal_tempdelta", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x00ff}, ++ {"temps_period", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0x0f00}, ++ {"temps_hysteresis", 0xfffff800, 0, SROM11_PHYCAL_TEMPDELTA, 0xf000}, ++ {"measpower1", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x007f}, ++ {"measpower2", 0xfffff800, SRFL_PRHEX, SROM11_MPWR_1_AND_2, 0x3f80}, ++ {"tssifloor2g", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_2G, 0x03ff}, ++ {"tssifloor5g", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GL, 0x03ff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GM, 0x03ff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_TSSIFLOOR_5GH, 0x03ff}, ++ {"", 0xfffff800, SRFL_PRHEX, SROM11_TSSIFLOOR_5GU, 0x03ff}, ++ {"pdoffset2g40ma0", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x000f}, ++ {"pdoffset2g40ma1", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x00f0}, ++ {"pdoffset2g40ma2", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x0f00}, ++ {"pdoffset2g40mvalid", 0xfffff800, 0, SROM11_PDOFF_2G_40M, 0x8000}, ++ {"pdoffset40ma0", 0xfffff800, 0, SROM11_PDOFF_40M_A0, 0xffff}, ++ {"pdoffset40ma1", 0xfffff800, 0, SROM11_PDOFF_40M_A1, 0xffff}, ++ {"pdoffset40ma2", 0xfffff800, 0, SROM11_PDOFF_40M_A2, 0xffff}, ++ {"pdoffset80ma0", 0xfffff800, 0, SROM11_PDOFF_80M_A0, 0xffff}, ++ {"pdoffset80ma1", 0xfffff800, 0, SROM11_PDOFF_80M_A1, 0xffff}, ++ {"pdoffset80ma2", 0xfffff800, 0, SROM11_PDOFF_80M_A2, 0xffff}, ++ ++ {"subband5gver", 0xfffff800, SRFL_PRHEX, SROM11_SUBBAND5GVER, 0xffff}, ++ {"paparambwver", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0xf000}, ++ {"rx5ggainwar", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0x2000}, ++ /* Special PA Params for 4350 5G Band, 40/80 MHz BW Ant #0 */ ++ {"pa5gbw4080a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 +SROM11_5GB0_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, ++ /* Special PA Params for 4335 5G Band, 40 MHz BW */ ++ {"pa5gbw40a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB0_PA + 2, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB1_PA + 2, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB2_PA + 2, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_5GB3_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_5GB3_PA + 2, 0xffff}, ++ /* Special PA Params for 4335 5G Band, 80 MHz BW */ ++ {"pa5gbw80a0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB0_PA + 2, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB1_PA + 2, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB2_PA + 2, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH2 + SROM11_5GB3_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH2 + SROM11_5GB3_PA + 2, 0xffff}, ++ /* Special PA Params for 4335 2G Band, CCK */ ++ {"pa2gccka0", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_PATH1 + SROM11_2G_PA + 1, 0xffff}, ++ {"", 0xfffff800, SRFL_PRHEX, SROM11_PATH1 + SROM11_2G_PA + 2, 0xffff}, ++ ++ /* power per rate */ ++ {"cckbw202gpo", 0xfffff800, 0, SROM11_CCKBW202GPO, 0xffff}, ++ {"cckbw20ul2gpo", 0xfffff800, 0, SROM11_CCKBW20UL2GPO, 0xffff}, ++ {"mcsbw202gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW202GPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW202GPO_1, 0xffff}, ++ {"mcsbw402gpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW402GPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW402GPO_1, 0xffff}, ++ {"dot11agofdmhrbw202gpo", 0xfffff800, 0, SROM11_DOT11AGOFDMHRBW202GPO, 0xffff}, ++ {"ofdmlrbw202gpo", 0xfffff800, 0, SROM11_OFDMLRBW202GPO, 0xffff}, ++ {"mcsbw205glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GLPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW205GLPO_1, 0xffff}, ++ {"mcsbw405glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GLPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW405GLPO_1, 0xffff}, ++ {"mcsbw805glpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GLPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW805GLPO_1, 0xffff}, ++ {"mcsbw205gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GMPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW205GMPO_1, 0xffff}, ++ {"mcsbw405gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GMPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW405GMPO_1, 0xffff}, ++ {"mcsbw805gmpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GMPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW805GMPO_1, 0xffff}, ++ {"mcsbw205ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW205GHPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW205GHPO_1, 0xffff}, ++ {"mcsbw405ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW405GHPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW405GHPO_1, 0xffff}, ++ {"mcsbw805ghpo", 0xfffff800, SRFL_MORE, SROM11_MCSBW805GHPO, 0xffff}, ++ {"", 0xfffff800, 0, SROM11_MCSBW805GHPO_1, 0xffff}, ++ {"mcslr5glpo", 0xfffff800, 0, SROM11_MCSLR5GLPO, 0x0fff}, ++ {"mcslr5gmpo", 0xfffff800, 0, SROM11_MCSLR5GMPO, 0xffff}, ++ {"mcslr5ghpo", 0xfffff800, 0, SROM11_MCSLR5GHPO, 0xffff}, ++ {"sb20in40hrpo", 0xfffff800, 0, SROM11_SB20IN40HRPO, 0xffff}, ++ {"sb20in80and160hr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GLPO, 0xffff}, ++ {"sb40and80hr5glpo", 0xfffff800, 0, SROM11_SB40AND80HR5GLPO, 0xffff}, ++ {"sb20in80and160hr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GMPO, 0xffff}, ++ {"sb40and80hr5gmpo", 0xfffff800, 0, SROM11_SB40AND80HR5GMPO, 0xffff}, ++ {"sb20in80and160hr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160HR5GHPO, 0xffff}, ++ {"sb40and80hr5ghpo", 0xfffff800, 0, SROM11_SB40AND80HR5GHPO, 0xffff}, ++ {"sb20in40lrpo", 0xfffff800, 0, SROM11_SB20IN40LRPO, 0xffff}, ++ {"sb20in80and160lr5glpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GLPO, 0xffff}, ++ {"sb40and80lr5glpo", 0xfffff800, 0, SROM11_SB40AND80LR5GLPO, 0xffff}, ++ {"sb20in80and160lr5gmpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GMPO, 0xffff}, ++ {"sb40and80lr5gmpo", 0xfffff800, 0, SROM11_SB40AND80LR5GMPO, 0xffff}, ++ {"sb20in80and160lr5ghpo", 0xfffff800, 0, SROM11_SB20IN80AND160LR5GHPO, 0xffff}, ++ {"sb40and80lr5ghpo", 0xfffff800, 0, SROM11_SB40AND80LR5GHPO, 0xffff}, ++ {"dot11agduphrpo", 0xfffff800, 0, SROM11_DOT11AGDUPHRPO, 0xffff}, ++ {"dot11agduplrpo", 0xfffff800, 0, SROM11_DOT11AGDUPLRPO, 0xffff}, ++ ++ /* Misc */ ++ {"sar2g", 0xfffff800, 0, SROM11_SAR, 0x00ff}, ++ {"sar5g", 0xfffff800, 0, SROM11_SAR, 0xff00}, ++ ++ {"noiselvl2ga0", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x001f}, ++ {"noiselvl2ga1", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x03e0}, ++ {"noiselvl2ga2", 0xfffff800, 0, SROM11_NOISELVL_2G, 0x7c00}, ++ {"noiselvl5ga0", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x001f}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x001f}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x001f}, ++ {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x001f}, ++ {"noiselvl5ga1", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x03e0}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x03e0}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x03e0}, ++ {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x03e0}, ++ {"noiselvl5ga2", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GL, 0x7c00}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GM, 0x7c00}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_NOISELVL_5GH, 0x7c00}, ++ {"", 0xfffff800, 0, SROM11_NOISELVL_5GU, 0x7c00}, ++ {"eu_edthresh2g", 0x00000800, 0, SROM11_EU_EDCRSTH, 0x00ff}, ++ {"eu_edthresh5g", 0x00000800, 0, SROM11_EU_EDCRSTH, 0xff00}, ++ ++ {"rxgainerr2ga0", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x003f}, ++ {"rxgainerr2ga1", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0x07c0}, ++ {"rxgainerr2ga2", 0xfffff800, 0, SROM11_RXGAINERR_2G, 0xf800}, ++ {"rxgainerr5ga0", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x003f}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x003f}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x003f}, ++ {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x003f}, ++ {"rxgainerr5ga1", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0x07c0}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0x07c0}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0x07c0}, ++ {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0x07c0}, ++ {"rxgainerr5ga2", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GL, 0xf800}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GM, 0xf800}, ++ {"", 0xfffff800, SRFL_ARRAY, SROM11_RXGAINERR_5GH, 0xf800}, ++ {"", 0xfffff800, 0, SROM11_RXGAINERR_5GU, 0xf800}, ++ {"rpcal2g", 0xfffff800, 0, SROM11_RPCAL_2G, 0xffff}, ++ {"rpcal5gb0", 0xfffff800, 0, SROM11_RPCAL_5GL, 0xffff}, ++ {"rpcal5gb1", 0xfffff800, 0, SROM11_RPCAL_5GM, 0xffff}, ++ {"rpcal5gb2", 0xfffff800, 0, SROM11_RPCAL_5GH, 0xffff}, ++ {"rpcal5gb3", 0xfffff800, 0, SROM11_RPCAL_5GU, 0xffff}, ++ {"txidxcap2g", 0xfffff800, 0, SROM11_TXIDXCAP2G, 0x0ff0}, ++ {"txidxcap5g", 0xfffff800, 0, SROM11_TXIDXCAP5G, 0x0ff0}, ++ {"pdoffsetcckma0", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x000f}, ++ {"pdoffsetcckma1", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x00f0}, ++ {"pdoffsetcckma2", 0xfffff800, 0, SROM11_PDOFF_2G_CCK, 0x0f00}, ++ ++ /* sromrev 12 */ ++ {"boardflags4", 0xfffff000, SRFL_PRHEX|SRFL_MORE, SROM12_BFL6, 0xffff}, ++ {"", 0, 0, SROM12_BFL7, 0xffff}, ++ {"pdoffsetcck", 0xfffff000, 0, SROM12_PDOFF_2G_CCK, 0xffff}, ++ {"pdoffset20in40m5gb0", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B0, 0xffff}, ++ {"pdoffset20in40m5gb1", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B1, 0xffff}, ++ {"pdoffset20in40m5gb2", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B2, 0xffff}, ++ {"pdoffset20in40m5gb3", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B3, 0xffff}, ++ {"pdoffset20in40m5gb4", 0xfffff000, 0, SROM12_PDOFF_20in40M_5G_B4, 0xffff}, ++ {"pdoffset40in80m5gb0", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B0, 0xffff}, ++ {"pdoffset40in80m5gb1", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B1, 0xffff}, ++ {"pdoffset40in80m5gb2", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B2, 0xffff}, ++ {"pdoffset40in80m5gb3", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B3, 0xffff}, ++ {"pdoffset40in80m5gb4", 0xfffff000, 0, SROM12_PDOFF_40in80M_5G_B4, 0xffff}, ++ {"pdoffset20in80m5gb0", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B0, 0xffff}, ++ {"pdoffset20in80m5gb1", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B1, 0xffff}, ++ {"pdoffset20in80m5gb2", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B2, 0xffff}, ++ {"pdoffset20in80m5gb3", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B3, 0xffff}, ++ {"pdoffset20in80m5gb4", 0xfffff000, 0, SROM12_PDOFF_20in80M_5G_B4, 0xffff}, ++ ++ {"pdoffset20in40m5gcore3", 0xffffe000, 0, SROM13_PDOFFSET20IN40M5GCORE3, 0xffff}, ++ {"pdoffset20in40m5gcore3_1", 0xffffe000, 0, SROM13_PDOFFSET20IN40M5GCORE3_1, 0xffff}, ++ {"pdoffset20in80m5gcore3", 0xffffe000, 0, SROM13_PDOFFSET20IN80M5GCORE3, 0xffff}, ++ {"pdoffset20in80m5gcore3_1", 0xffffe000, 0, SROM13_PDOFFSET20IN80M5GCORE3_1, 0xffff}, ++ {"pdoffset40in80m5gcore3", 0xffffe000, 0, SROM13_PDOFFSET40IN80M5GCORE3, 0xffff}, ++ {"pdoffset40in80m5gcore3_1", 0xffffe000, 0, SROM13_PDOFFSET40IN80M5GCORE3_1, 0xffff}, ++ ++ {"pdoffset20in40m2g", 0xffffe000, 0, SROM13_PDOFFSET20IN40M2G, 0xffff}, ++ {"pdoffset20in40m2gcore3", 0xffffe000, 0, SROM13_PDOFFSET20IN40M2GCORE3, 0xffff}, ++ ++ /* power per rate */ ++ {"mcsbw205gx1po", 0xfffff000, SRFL_MORE, SROM12_MCSBW205GX1PO, 0xffff}, ++ {"", 0xfffff000, 0, SROM12_MCSBW205GX1PO_1, 0xffff}, ++ {"mcsbw405gx1po", 0xfffff000, SRFL_MORE, SROM12_MCSBW405GX1PO, 0xffff}, ++ {"", 0xfffff000, 0, SROM12_MCSBW405GX1PO_1, 0xffff}, ++ {"mcsbw805gx1po", 0xfffff000, SRFL_MORE, SROM12_MCSBW805GX1PO, 0xffff}, ++ {"", 0xfffff000, 0, SROM12_MCSBW805GX1PO_1, 0xffff}, ++ {"mcsbw205gx2po", 0xfffff000, SRFL_MORE, SROM12_MCSBW205GX2PO, 0xffff}, ++ {"", 0xfffff000, 0, SROM12_MCSBW205GX2PO_1, 0xffff}, ++ {"mcsbw405gx2po", 0xfffff000, SRFL_MORE, SROM12_MCSBW405GX2PO, 0xffff}, ++ {"", 0xfffff000, 0, SROM12_MCSBW405GX2PO_1, 0xffff}, ++ {"mcsbw805gx2po", 0xfffff000, SRFL_MORE, SROM12_MCSBW805GX2PO, 0xffff}, ++ {"", 0xfffff000, 0, SROM12_MCSBW805GX2PO_1, 0xffff}, ++ ++ {"sb20in80and160hr5gx1po", 0xfffff000, 0, SROM12_SB20IN80AND160HR5GX1PO, 0xffff}, ++ {"sb40and80hr5gx1po", 0xfffff000, 0, SROM12_SB40AND80HR5GX1PO, 0xffff}, ++ {"sb20in80and160lr5gx1po", 0xfffff000, 0, SROM12_SB20IN80AND160LR5GX1PO, 0xffff}, ++ {"sb40and80hr5gx1po", 0xfffff000, 0, SROM12_SB40AND80HR5GX1PO, 0xffff}, ++ {"sb20in80and160hr5gx2po", 0xfffff000, 0, SROM12_SB20IN80AND160HR5GX2PO, 0xffff}, ++ {"sb40and80hr5gx2po", 0xfffff000, 0, SROM12_SB40AND80HR5GX2PO, 0xffff}, ++ {"sb20in80and160lr5gx2po", 0xfffff000, 0, SROM12_SB20IN80AND160LR5GX2PO, 0xffff}, ++ {"sb40and80hr5gx2po", 0xfffff000, 0, SROM12_SB40AND80HR5GX2PO, 0xffff}, ++ ++ {"rxgains5gmelnagaina0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0007}, ++ {"rxgains5gmelnagaina1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0007}, ++ {"rxgains5gmelnagaina2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0007}, ++ {"rxgains5gmtrisoa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0078}, ++ {"rxgains5gmtrisoa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0078}, ++ {"rxgains5gmtrisoa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0078}, ++ {"rxgains5gmtrelnabypa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0080}, ++ {"rxgains5gmtrelnabypa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0080}, ++ {"rxgains5gmtrelnabypa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0080}, ++ {"rxgains5ghelnagaina0", 0xfffff000, 0, SROM12_RXGAINS10, 0x0700}, ++ {"rxgains5ghelnagaina1", 0xfffff000, 0, SROM12_RXGAINS11, 0x0700}, ++ {"rxgains5ghelnagaina2", 0xfffff000, 0, SROM12_RXGAINS12, 0x0700}, ++ {"rxgains5ghtrisoa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x7800}, ++ {"rxgains5ghtrisoa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x7800}, ++ {"rxgains5ghtrisoa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x7800}, ++ {"rxgains5ghtrelnabypa0", 0xfffff000, 0, SROM12_RXGAINS10, 0x8000}, ++ {"rxgains5ghtrelnabypa1", 0xfffff000, 0, SROM12_RXGAINS11, 0x8000}, ++ {"rxgains5ghtrelnabypa2", 0xfffff000, 0, SROM12_RXGAINS12, 0x8000}, ++ {"eu_edthresh2g", 0x00001000, 0, SROM12_EU_EDCRSTH, 0x00ff}, ++ {"eu_edthresh5g", 0x00001000, 0, SROM12_EU_EDCRSTH, 0xff00}, ++ ++ {"gpdn", 0xfffff000, SRFL_PRHEX|SRFL_MORE, SROM12_GPDN_L, 0xffff}, ++ {"", 0, 0, SROM12_GPDN_H, 0xffff}, ++ ++ {"rpcal2gcore3", 0xffffe000, 0, SROM13_RPCAL2GCORE3, 0x00ff}, ++ {"rpcal5gb0core3", 0xffffe000, 0, SROM13_RPCAL5GB01CORE3, 0x00ff}, ++ {"rpcal5gb1core3", 0xffffe000, 0, SROM13_RPCAL5GB01CORE3, 0xff00}, ++ {"rpcal5gb2core3", 0xffffe000, 0, SROM13_RPCAL5GB23CORE3, 0x00ff}, ++ {"rpcal5gb3core3", 0xffffe000, 0, SROM13_RPCAL5GB23CORE3, 0xff00}, ++ ++ {"eu_edthresh2g", 0x00002000, 0, SROM13_EU_EDCRSTH, 0x00ff}, ++ {"eu_edthresh5g", 0x00002000, 0, SROM13_EU_EDCRSTH, 0xff00}, ++ ++ {"agbg3", 0xffffe000, 0, SROM13_ANTGAIN_BANDBGA, 0xff00}, ++ {"aga3", 0xffffe000, 0, SROM13_ANTGAIN_BANDBGA, 0x00ff}, ++ {"noiselvl2ga3", 0xffffe000, 0, SROM13_NOISELVLCORE3, 0x001f}, ++ {"noiselvl5ga3", 0xffffe000, SRFL_ARRAY, SROM13_NOISELVLCORE3, 0x03e0}, ++ {"", 0xffffe000, SRFL_ARRAY, SROM13_NOISELVLCORE3, 0x7c00}, ++ {"", 0xffffe000, SRFL_ARRAY, SROM13_NOISELVLCORE3_1, 0x001f}, ++ {"", 0xffffe000, 0, SROM13_NOISELVLCORE3_1, 0x03e0}, ++ {"rxgainerr2ga3", 0xffffe000, 0, SROM13_RXGAINERRCORE3, 0x001f}, ++ {"rxgainerr5ga3", 0xffffe000, SRFL_ARRAY, SROM13_RXGAINERRCORE3, 0x03e0}, ++ {"", 0xffffe000, SRFL_ARRAY, SROM13_RXGAINERRCORE3, 0x7c00}, ++ {"", 0xffffe000, SRFL_ARRAY, SROM13_RXGAINERRCORE3_1, 0x001f}, ++ {"", 0xffffe000, 0, SROM13_RXGAINERRCORE3_1, 0x03e0}, ++ {"rxgains5gmelnagaina3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0007}, ++ {"rxgains5gmtrisoa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0078}, ++ {"rxgains5gmtrelnabypa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0080}, ++ {"rxgains5ghelnagaina3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x0700}, ++ {"rxgains5ghtrisoa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x7800}, ++ {"rxgains5ghtrelnabypa3", 0xffffe000, 0, SROM13_RXGAINS1CORE3, 0x8000}, ++ ++ /* power per rate */ ++ {"mcs1024qam2gpo", 0xffffe000, 0, SROM13_MCS1024QAM2GPO, 0xffff}, ++ {"mcs1024qam5glpo", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GLPO, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCS1024QAM5GLPO_1, 0xffff}, ++ {"mcs1024qam5gmpo", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GMPO, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCS1024QAM5GMPO_1, 0xffff}, ++ {"mcs1024qam5ghpo", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GHPO, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCS1024QAM5GHPO_1, 0xffff}, ++ {"mcs1024qam5gx1po", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GX1PO, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCS1024QAM5GX1PO_1, 0xffff}, ++ {"mcs1024qam5gx2po", 0xffffe000, SRFL_MORE, SROM13_MCS1024QAM5GX2PO, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCS1024QAM5GX2PO_1, 0xffff}, ++ ++ {"mcsbw1605glpo", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GLPO, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCSBW1605GLPO_1, 0xffff}, ++ {"mcsbw1605gmpo", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GMPO, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCSBW1605GMPO_1, 0xffff}, ++ {"mcsbw1605ghpo", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GHPO, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCSBW1605GHPO_1, 0xffff}, ++ {"mcsbw1605gx1po", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GX1PO, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCSBW1605GX1PO_1, 0xffff}, ++ {"mcsbw1605gx2po", 0xffffe000, SRFL_MORE, SROM13_MCSBW1605GX2PO, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCSBW1605GX2PO_1, 0xffff}, ++ ++ {"ulbpproffs2g", 0xffffe000, 0, SROM13_ULBPPROFFS2G, 0xffff}, ++ ++ {"mcs8poexp", 0xffffe000, SRFL_MORE, SROM13_MCS8POEXP, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCS8POEXP_1, 0xffff}, ++ {"mcs9poexp", 0xffffe000, SRFL_MORE, SROM13_MCS9POEXP, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCS9POEXP_1, 0xffff}, ++ {"mcs10poexp", 0xffffe000, SRFL_MORE, SROM13_MCS10POEXP, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCS10POEXP_1, 0xffff}, ++ {"mcs11poexp", 0xffffe000, SRFL_MORE, SROM13_MCS11POEXP, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_MCS11POEXP_1, 0xffff}, ++ ++ {"ulbpdoffs5gb0a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A0, 0xffff}, ++ {"ulbpdoffs5gb0a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A1, 0xffff}, ++ {"ulbpdoffs5gb0a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A2, 0xffff}, ++ {"ulbpdoffs5gb0a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB0A3, 0xffff}, ++ {"ulbpdoffs5gb1a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A0, 0xffff}, ++ {"ulbpdoffs5gb1a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A1, 0xffff}, ++ {"ulbpdoffs5gb1a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A2, 0xffff}, ++ {"ulbpdoffs5gb1a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB1A3, 0xffff}, ++ {"ulbpdoffs5gb2a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A0, 0xffff}, ++ {"ulbpdoffs5gb2a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A1, 0xffff}, ++ {"ulbpdoffs5gb2a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A2, 0xffff}, ++ {"ulbpdoffs5gb2a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB2A3, 0xffff}, ++ {"ulbpdoffs5gb3a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A0, 0xffff}, ++ {"ulbpdoffs5gb3a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A1, 0xffff}, ++ {"ulbpdoffs5gb3a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A2, 0xffff}, ++ {"ulbpdoffs5gb3a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB3A3, 0xffff}, ++ {"ulbpdoffs5gb4a0", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A0, 0xffff}, ++ {"ulbpdoffs5gb4a1", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A1, 0xffff}, ++ {"ulbpdoffs5gb4a2", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A2, 0xffff}, ++ {"ulbpdoffs5gb4a3", 0xffffe000, 0, SROM13_ULBPDOFFS5GB4A3, 0xffff}, ++ {"ulbpdoffs2ga0", 0xffffe000, 0, SROM13_ULBPDOFFS2GA0, 0xffff}, ++ {"ulbpdoffs2ga1", 0xffffe000, 0, SROM13_ULBPDOFFS2GA1, 0xffff}, ++ {"ulbpdoffs2ga2", 0xffffe000, 0, SROM13_ULBPDOFFS2GA2, 0xffff}, ++ {"ulbpdoffs2ga3", 0xffffe000, 0, SROM13_ULBPDOFFS2GA3, 0xffff}, ++ ++ {"rpcal5gb4", 0xffffe000, 0, SROM13_RPCAL5GB4, 0xffff}, ++ ++ {"sb20in40hrlrpox", 0xffffe000, 0, SROM13_SB20IN40HRLRPOX, 0xffff}, ++ ++ {"pdoffset20in40m2g", 0xffffe000, 0, SROM13_PDOFFSET20IN40M2G, 0xffff}, ++ {"pdoffset20in40m2gcore3", 0xffffe000, 0, SROM13_PDOFFSET20IN40M2GCORE3, 0xffff}, ++ ++ {"pdoffset20in40m5gcore3", 0xffffe000, SRFL_MORE, SROM13_PDOFFSET20IN40M5GCORE3, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_PDOFFSET20IN40M5GCORE3_1, 0xffff}, ++ {"pdoffset40in80m5gcore3", 0xffffe000, SRFL_MORE, SROM13_PDOFFSET40IN80M5GCORE3, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_PDOFFSET40IN80M5GCORE3_1, 0xffff}, ++ {"pdoffset20in80m5gcore3", 0xffffe000, SRFL_MORE, SROM13_PDOFFSET20IN80M5GCORE3, 0xffff}, ++ {"", 0xffffe000, 0, SROM13_PDOFFSET20IN80M5GCORE3_1, 0xffff}, ++ ++ {"swctrlmap4_cfg", 0xffffe000, 0, SROM13_SWCTRLMAP4_CFG, 0xffff}, ++ {"swctrlmap4_TX2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX2G_FEM3TO0, 0xffff}, ++ {"swctrlmap4_RX2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX2G_FEM3TO0, 0xffff}, ++ {"swctrlmap4_RXByp2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP2G_FEM3TO0, 0xffff}, ++ {"swctrlmap4_misc2g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC2G_FEM3TO0, 0xffff}, ++ {"swctrlmap4_TX5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX5G_FEM3TO0, 0xffff}, ++ {"swctrlmap4_RX5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX5G_FEM3TO0, 0xffff}, ++ {"swctrlmap4_RXByp5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP5G_FEM3TO0, 0xffff}, ++ {"swctrlmap4_misc5g_fem3to0", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC5G_FEM3TO0, 0xffff}, ++ {"swctrlmap4_TX2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX2G_FEM7TO4, 0xffff}, ++ {"swctrlmap4_RX2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX2G_FEM7TO4, 0xffff}, ++ {"swctrlmap4_RXByp2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP2G_FEM7TO4, 0xffff}, ++ {"swctrlmap4_misc2g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC2G_FEM7TO4, 0xffff}, ++ {"swctrlmap4_TX5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_TX5G_FEM7TO4, 0xffff}, ++ {"swctrlmap4_RX5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RX5G_FEM7TO4, 0xffff}, ++ {"swctrlmap4_RXByp5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_RXBYP5G_FEM7TO4, 0xffff}, ++ {"swctrlmap4_misc5g_fem7to4", 0xffffe000, 0, SROM13_SWCTRLMAP4_MISC5G_FEM7TO4, 0xffff}, ++ {NULL, 0, 0, 0, 0} ++}; ++ ++static const sromvar_t 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", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0x00ff}, ++ {"itt2ga", 0x00000700, 0, SROM8_2G_ITT_MAXP, 0xff00}, ++ {"itt5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0xff00}, ++ {"pa2gw0a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, ++ {"pa2gw1a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, ++ {"pa2gw2a", 0x00000700, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, ++ {"maxp5ga", 0x00000700, 0, SROM8_5G_ITT_MAXP, 0x00ff}, ++ {"maxp5gha", 0x00000700, 0, SROM8_5GLH_MAXP, 0x00ff}, ++ {"maxp5gla", 0x00000700, 0, SROM8_5GLH_MAXP, 0xff00}, ++ {"pa5gw0a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, ++ {"pa5gw1a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, ++ {"pa5gw2a", 0x00000700, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, ++ {"pa5glw0a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, ++ {"pa5glw1a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff}, ++ {"pa5glw2a", 0x00000700, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff}, ++ {"pa5ghw0a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, ++ {"pa5ghw1a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff}, ++ {"pa5ghw2a", 0x00000700, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff}, ++ ++ /* sromrev 11 */ ++ {"maxp2ga", 0xfffff800, 0, SROM11_2G_MAXP, 0x00ff}, ++ {"pa2ga", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA + 1, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX, SROM11_2G_PA + 2, 0xffff}, ++ {"rxgains5gmelnagaina", 0x00000800, 0, SROM11_RXGAINS1, 0x0007}, ++ {"rxgains5gmtrisoa", 0x00000800, 0, SROM11_RXGAINS1, 0x0078}, ++ {"rxgains5gmtrelnabypa", 0x00000800, 0, SROM11_RXGAINS1, 0x0080}, ++ {"rxgains5ghelnagaina", 0x00000800, 0, SROM11_RXGAINS1, 0x0700}, ++ {"rxgains5ghtrisoa", 0x00000800, 0, SROM11_RXGAINS1, 0x7800}, ++ {"rxgains5ghtrelnabypa", 0x00000800, 0, SROM11_RXGAINS1, 0x8000}, ++ {"rxgains2gelnagaina", 0x00000800, 0, SROM11_RXGAINS, 0x0007}, ++ {"rxgains2gtrisoa", 0x00000800, 0, SROM11_RXGAINS, 0x0078}, ++ {"rxgains2gtrelnabypa", 0x00000800, 0, SROM11_RXGAINS, 0x0080}, ++ {"rxgains5gelnagaina", 0x00000800, 0, SROM11_RXGAINS, 0x0700}, ++ {"rxgains5gtrisoa", 0x00000800, 0, SROM11_RXGAINS, 0x7800}, ++ {"rxgains5gtrelnabypa", 0x00000800, 0, SROM11_RXGAINS, 0x8000}, ++ {"maxp5ga", 0x00000800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0x00ff}, ++ {"", 0x00000800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0xff00}, ++ {"", 0x00000800, SRFL_ARRAY, SROM11_5GB3B2_MAXP, 0x00ff}, ++ {"", 0x00000800, 0, SROM11_5GB3B2_MAXP, 0xff00}, ++ {"pa5ga", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 1, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 2, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 1, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 2, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 1, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 2, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA + 1, 0xffff}, ++ {"", 0x00000800, SRFL_PRHEX, SROM11_5GB3_PA + 2, 0xffff}, ++ ++ /* sromrev 12 */ ++ {"maxp5gb4a", 0xfffff000, 0, SROM12_5GB42G_MAXP, 0x00ff00}, ++ {"pa2ga", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2GB0_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2GB0_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2GB0_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX, SROM12_2GB0_PA_W3, 0x00ffff}, ++ ++ {"pa2g40a", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2G40B0_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2G40B0_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_2G40B0_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX, SROM12_2G40B0_PA_W3, 0x00ffff}, ++ {"maxp5gb0a", 0xfffff000, 0, SROM12_5GB1B0_MAXP, 0x00ff}, ++ {"maxp5gb1a", 0xfffff000, 0, SROM12_5GB1B0_MAXP, 0x00ff00}, ++ {"maxp5gb2a", 0xfffff000, 0, SROM12_5GB3B2_MAXP, 0x00ff}, ++ {"maxp5gb3a", 0xfffff000, 0, SROM12_5GB3B2_MAXP, 0x00ff00}, ++ ++ {"pa5ga", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB0_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB1_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB2_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB3_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB4_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB4_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5GB4_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX, SROM12_5GB4_PA_W3, 0x00ffff}, ++ ++ {"pa5g40a", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B0_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B1_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B2_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B3_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B4_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B4_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G40B4_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX, SROM12_5G40B4_PA_W3, 0x00ffff}, ++ ++ {"pa5g80a", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B0_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B1_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B2_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B3_PA_W3, 0x00ffff}, ++ ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B4_PA_W0, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B4_PA_W1, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX | SRFL_ARRAY, SROM12_5G80B4_PA_W2, 0x00ffff}, ++ {"", 0xfffff000, SRFL_PRHEX, SROM12_5G80B4_PA_W3, 0x00ffff}, ++ /* sromrev 13 */ ++ {"rxgains2gelnagaina", 0xffffe000, 0, SROM13_RXGAINS, 0x0007}, ++ {"rxgains2gtrisoa", 0xffffe000, 0, SROM13_RXGAINS, 0x0078}, ++ {"rxgains2gtrelnabypa", 0xffffe000, 0, SROM13_RXGAINS, 0x0080}, ++ {"rxgains5gelnagaina", 0xffffe000, 0, SROM13_RXGAINS, 0x0700}, ++ {"rxgains5gtrisoa", 0xffffe000, 0, SROM13_RXGAINS, 0x7800}, ++ {"rxgains5gtrelnabypa", 0xffffe000, 0, SROM13_RXGAINS, 0x8000}, ++ {NULL, 0, 0, 0, 0} ++}; ++ ++#if !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N)) ++#define PHY_TYPE_HT 7 /* HT-Phy value */ ++#define PHY_TYPE_N 4 /* N-Phy value */ ++#endif /* !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N)) */ ++#if !defined(PHY_TYPE_AC) ++#define PHY_TYPE_AC 11 /* AC-Phy value */ ++#endif /* !defined(PHY_TYPE_AC) */ ++#if !defined(PHY_TYPE_LCN20) ++#define PHY_TYPE_LCN20 12 /* LCN20-Phy value */ ++#endif /* !defined(PHY_TYPE_LCN20) */ ++#if !defined(PHY_TYPE_NULL) ++#define PHY_TYPE_NULL 0xf /* Invalid Phy value */ ++#endif /* !defined(PHY_TYPE_NULL) */ ++ ++typedef struct { ++ uint16 phy_type; ++ uint16 bandrange; ++ uint16 chain; ++ const char *vars; ++} pavars_t; ++ ++static const pavars_t pavars[] = { ++ /* HTPHY */ ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_2G, 2, "pa2gw0a2 pa2gw1a2 pa2gw2a2"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND0, 2, "pa5glw0a2 pa5glw1a2 pa5glw2a2"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND1, 2, "pa5gw0a2 pa5gw1a2 pa5gw2a2"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND2, 2, "pa5ghw0a2 pa5ghw1a2 pa5ghw2a2"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 0, "pa5gw0a3 pa5gw1a3 pa5gw2a3"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 1, "pa5glw0a3 pa5glw1a3 pa5glw2a3"}, ++ {PHY_TYPE_HT, WL_CHAN_FREQ_RANGE_5G_BAND3, 2, "pa5ghw0a3 pa5ghw1a3 pa5ghw2a3"}, ++ /* NPHY */ ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND0, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND1, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5G_BAND2, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, ++ /* ACPHY */ ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5ga2"}, ++ /* LCN20PHY */ ++ {PHY_TYPE_LCN20, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, ++ {PHY_TYPE_NULL, 0, 0, ""} ++}; ++ ++ ++static const pavars_t pavars_SROM12[] = { ++ /* ACPHY */ ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 0, "pa2g40a0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 1, "pa2g40a1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 2, "pa2g40a2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 0, "pa5ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 1, "pa5ga1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 2, "pa5ga2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 0, "pa5g40a0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 1, "pa5g40a1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 2, "pa5g40a2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 0, "pa5g80a0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 1, "pa5g80a1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 2, "pa5g80a2"}, ++ {PHY_TYPE_NULL, 0, 0, ""} ++}; ++ ++static const pavars_t pavars_SROM13[] = { ++ /* ACPHY */ ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2ga2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 3, "pa2ga3"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 0, "pa2g40a0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 1, "pa2g40a1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 2, "pa2g40a2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G_40, 3, "pa2g40a3"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 0, "pa5ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 1, "pa5ga1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 2, "pa5ga2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND, 3, "pa5ga3"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 0, "pa5g40a0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 1, "pa5g40a1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 2, "pa5g40a2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_40, 3, "pa5g40a3"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 0, "pa5g80a0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 1, "pa5g80a1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 2, "pa5g80a2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_5BAND_80, 3, "pa5g80a3"}, ++ {PHY_TYPE_NULL, 0, 0, ""} ++}; ++ ++/* pavars table when paparambwver is 1 */ ++static const pavars_t pavars_bwver_1[] = { ++ /* ACPHY */ ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gccka0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga2"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5gbw40a0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw80a0"}, ++ {PHY_TYPE_NULL, 0, 0, ""} ++}; ++ ++/* pavars table when paparambwver is 2 */ ++static const pavars_t pavars_bwver_2[] = { ++ /* ACPHY */ ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw4080a0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 3, "pa5gbw4080a1"}, ++ {PHY_TYPE_NULL, 0, 0, ""} ++}; ++ ++/* pavars table when paparambwver is 3 */ ++static const pavars_t pavars_bwver_3[] = { ++ /* ACPHY */ ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 0, "pa2ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 1, "pa2ga1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 2, "pa2gccka0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_2G, 3, "pa2gccka1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 0, "pa5ga0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 1, "pa5ga1"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 2, "pa5gbw4080a0"}, ++ {PHY_TYPE_AC, WL_CHAN_FREQ_RANGE_5G_4BAND, 3, "pa5gbw4080a1"}, ++ {PHY_TYPE_NULL, 0, 0, ""} ++}; ++ ++typedef struct { ++ uint16 phy_type; ++ uint16 bandrange; ++ const char *vars; ++} povars_t; ++ ++static const povars_t povars[] = { ++ /* NPHY */ ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, "mcs2gpo0 mcs2gpo1 mcs2gpo2 mcs2gpo3 " ++ "mcs2gpo4 mcs2gpo5 mcs2gpo6 mcs2gpo7"}, ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, "mcs5glpo0 mcs5glpo1 mcs5glpo2 mcs5glpo3 " ++ "mcs5glpo4 mcs5glpo5 mcs5glpo6 mcs5glpo7"}, ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, "mcs5gpo0 mcs5gpo1 mcs5gpo2 mcs5gpo3 " ++ "mcs5gpo4 mcs5gpo5 mcs5gpo6 mcs5gpo7"}, ++ {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, "mcs5ghpo0 mcs5ghpo1 mcs5ghpo2 mcs5ghpo3 " ++ "mcs5ghpo4 mcs5ghpo5 mcs5ghpo6 mcs5ghpo7"}, ++ {PHY_TYPE_NULL, 0, ""} ++}; ++ ++typedef struct { ++ uint8 tag; /* Broadcom subtag name */ ++ uint32 revmask; /* Supported cis_sromrev bitmask. Some of the parameters in ++ * different tuples have the same name. Therefore, the MFGc tool ++ * needs to know which tuple to generate when seeing these ++ * parameters (given that we know sromrev from user input, like the ++ * nvram file). ++ */ ++ uint8 len; /* Length field of the tuple, note that it includes the ++ * subtag name (1 byte): 1 + tuple content length ++ */ ++ const char *params; ++} cis_tuple_t; ++ ++#define OTP_RAW (0xff - 1) /* Reserved tuple number for wrvar Raw input */ ++#define OTP_VERS_1 (0xff - 2) /* CISTPL_VERS_1 */ ++#define OTP_MANFID (0xff - 3) /* CISTPL_MANFID */ ++#define OTP_RAW1 (0xff - 4) /* Like RAW, but comes first */ ++ ++/** this array is used by CIS creating/writing applications */ ++static const cis_tuple_t cis_hnbuvars[] = { ++/* tag revmask len params */ ++ {OTP_RAW1, 0xffffffff, 0, ""}, /* special case */ ++ {OTP_VERS_1, 0xffffffff, 0, "smanf sproductname"}, /* special case (non BRCM tuple) */ ++ {OTP_MANFID, 0xffffffff, 4, "2manfid 2prodid"}, /* special case (non BRCM tuple) */ ++ /* Unified OTP: tupple to embed USB manfid inside SDIO CIS */ ++ {HNBU_UMANFID, 0xffffffff, 8, "8usbmanfid"}, ++ {HNBU_SROMREV, 0xffffffff, 2, "1sromrev"}, ++ /* NOTE: subdevid is also written to boardtype. ++ * Need to write HNBU_BOARDTYPE to change it if it is different. ++ */ ++ {HNBU_CHIPID, 0xffffffff, 11, "2vendid 2devid 2chiprev 2subvendid 2subdevid"}, ++ {HNBU_BOARDREV, 0xffffffff, 3, "2boardrev"}, ++ {HNBU_PAPARMS, 0xffffffff, 10, "2pa0b0 2pa0b1 2pa0b2 1pa0itssit 1pa0maxpwr 1opo"}, ++ {HNBU_AA, 0xffffffff, 3, "1aa2g 1aa5g"}, ++ {HNBU_AA, 0xffffffff, 3, "1aa0 1aa1"}, /* backward compatibility */ ++ {HNBU_AG, 0xffffffff, 5, "1ag0 1ag1 1ag2 1ag3"}, ++ {HNBU_BOARDFLAGS, 0xffffffff, 21, "4boardflags 4boardflags2 4boardflags3 " ++ "4boardflags4 4boardflags5 "}, ++ {HNBU_LEDS, 0xffffffff, 17, "1ledbh0 1ledbh1 1ledbh2 1ledbh3 1ledbh4 1ledbh5 " ++ "1ledbh6 1ledbh7 1ledbh8 1ledbh9 1ledbh10 1ledbh11 1ledbh12 1ledbh13 1ledbh14 1ledbh15"}, ++ {HNBU_CCODE, 0xffffffff, 4, "2ccode 1cctl"}, ++ {HNBU_CCKPO, 0xffffffff, 3, "2cckpo"}, ++ {HNBU_OFDMPO, 0xffffffff, 5, "4ofdmpo"}, ++ {HNBU_PAPARMS5G, 0xffffffff, 23, "2pa1b0 2pa1b1 2pa1b2 2pa1lob0 2pa1lob1 2pa1lob2 " ++ "2pa1hib0 2pa1hib1 2pa1hib2 1pa1itssit " ++ "1pa1maxpwr 1pa1lomaxpwr 1pa1himaxpwr"}, ++ {HNBU_RDLID, 0xffffffff, 3, "2rdlid"}, ++ {HNBU_RSSISMBXA2G, 0xffffffff, 3, "0rssismf2g 0rssismc2g " ++ "0rssisav2g 0bxa2g"}, /* special case */ ++ {HNBU_RSSISMBXA5G, 0xffffffff, 3, "0rssismf5g 0rssismc5g " ++ "0rssisav5g 0bxa5g"}, /* special case */ ++ {HNBU_XTALFREQ, 0xffffffff, 5, "4xtalfreq"}, ++ {HNBU_TRI2G, 0xffffffff, 2, "1tri2g"}, ++ {HNBU_TRI5G, 0xffffffff, 4, "1tri5gl 1tri5g 1tri5gh"}, ++ {HNBU_RXPO2G, 0xffffffff, 2, "1rxpo2g"}, ++ {HNBU_RXPO5G, 0xffffffff, 2, "1rxpo5g"}, ++ {HNBU_BOARDNUM, 0xffffffff, 3, "2boardnum"}, ++ {HNBU_MACADDR, 0xffffffff, 7, "6macaddr"}, /* special case */ ++ {HNBU_RDLSN, 0xffffffff, 3, "2rdlsn"}, ++ {HNBU_BOARDTYPE, 0xffffffff, 3, "2boardtype"}, ++ {HNBU_LEDDC, 0xffffffff, 3, "2leddc"}, ++ {HNBU_RDLRNDIS, 0xffffffff, 2, "1rdlndis"}, ++ {HNBU_CHAINSWITCH, 0xffffffff, 5, "1txchain 1rxchain 2antswitch"}, ++ {HNBU_REGREV, 0xffffffff, 3, "2regrev"}, ++ {HNBU_FEM, 0x000007fe, 5, "0antswctl2g 0triso2g 0pdetrange2g 0extpagain2g " ++ "0tssipos2g 0antswctl5g 0triso5g 0pdetrange5g 0extpagain5g 0tssipos5g"}, /* special case */ ++ {HNBU_PAPARMS_C0, 0x000007fe, 31, "1maxp2ga0 1itt2ga0 2pa2gw0a0 2pa2gw1a0 " ++ "2pa2gw2a0 1maxp5ga0 1itt5ga0 1maxp5gha0 1maxp5gla0 2pa5gw0a0 2pa5gw1a0 2pa5gw2a0 " ++ "2pa5glw0a0 2pa5glw1a0 2pa5glw2a0 2pa5ghw0a0 2pa5ghw1a0 2pa5ghw2a0"}, ++ {HNBU_PAPARMS_C1, 0x000007fe, 31, "1maxp2ga1 1itt2ga1 2pa2gw0a1 2pa2gw1a1 " ++ "2pa2gw2a1 1maxp5ga1 1itt5ga1 1maxp5gha1 1maxp5gla1 2pa5gw0a1 2pa5gw1a1 2pa5gw2a1 " ++ "2pa5glw0a1 2pa5glw1a1 2pa5glw2a1 2pa5ghw0a1 2pa5ghw1a1 2pa5ghw2a1"}, ++ {HNBU_PO_CCKOFDM, 0xffffffff, 19, "2cck2gpo 4ofdm2gpo 4ofdm5gpo 4ofdm5glpo " ++ "4ofdm5ghpo"}, ++ {HNBU_PO_MCS2G, 0xffffffff, 17, "2mcs2gpo0 2mcs2gpo1 2mcs2gpo2 2mcs2gpo3 " ++ "2mcs2gpo4 2mcs2gpo5 2mcs2gpo6 2mcs2gpo7"}, ++ {HNBU_PO_MCS5GM, 0xffffffff, 17, "2mcs5gpo0 2mcs5gpo1 2mcs5gpo2 2mcs5gpo3 " ++ "2mcs5gpo4 2mcs5gpo5 2mcs5gpo6 2mcs5gpo7"}, ++ {HNBU_PO_MCS5GLH, 0xffffffff, 33, "2mcs5glpo0 2mcs5glpo1 2mcs5glpo2 2mcs5glpo3 " ++ "2mcs5glpo4 2mcs5glpo5 2mcs5glpo6 2mcs5glpo7 " ++ "2mcs5ghpo0 2mcs5ghpo1 2mcs5ghpo2 2mcs5ghpo3 " ++ "2mcs5ghpo4 2mcs5ghpo5 2mcs5ghpo6 2mcs5ghpo7"}, ++ {HNBU_CCKFILTTYPE, 0xffffffff, 2, "1cckdigfilttype"}, ++ {HNBU_PO_CDD, 0xffffffff, 3, "2cddpo"}, ++ {HNBU_PO_STBC, 0xffffffff, 3, "2stbcpo"}, ++ {HNBU_PO_40M, 0xffffffff, 3, "2bw40po"}, ++ {HNBU_PO_40MDUP, 0xffffffff, 3, "2bwduppo"}, ++ {HNBU_RDLRWU, 0xffffffff, 2, "1rdlrwu"}, ++ {HNBU_WPS, 0xffffffff, 3, "1wpsgpio 1wpsled"}, ++ {HNBU_USBFS, 0xffffffff, 2, "1usbfs"}, ++ {HNBU_ELNA2G, 0xffffffff, 2, "1elna2g"}, ++ {HNBU_ELNA5G, 0xffffffff, 2, "1elna5g"}, ++ {HNBU_CUSTOM1, 0xffffffff, 5, "4customvar1"}, ++ {OTP_RAW, 0xffffffff, 0, ""}, /* special case */ ++ {HNBU_OFDMPO5G, 0xffffffff, 13, "4ofdm5gpo 4ofdm5glpo 4ofdm5ghpo"}, ++ {HNBU_USBEPNUM, 0xffffffff, 3, "2usbepnum"}, ++ {HNBU_CCKBW202GPO, 0xffffffff, 7, "2cckbw202gpo 2cckbw20ul2gpo 2cckbw20in802gpo"}, ++ {HNBU_LEGOFDMBW202GPO, 0xffffffff, 9, "4legofdmbw202gpo 4legofdmbw20ul2gpo"}, ++ {HNBU_LEGOFDMBW205GPO, 0xffffffff, 25, "4legofdmbw205glpo 4legofdmbw20ul5glpo " ++ "4legofdmbw205gmpo 4legofdmbw20ul5gmpo 4legofdmbw205ghpo 4legofdmbw20ul5ghpo"}, ++ {HNBU_MCS2GPO, 0xffffffff, 17, "4mcsbw202gpo 4mcsbw20ul2gpo 4mcsbw402gpo 4mcsbw802gpo"}, ++ {HNBU_MCS5GLPO, 0xffffffff, 13, "4mcsbw205glpo 4mcsbw20ul5glpo 4mcsbw405glpo"}, ++ {HNBU_MCS5GMPO, 0xffffffff, 13, "4mcsbw205gmpo 4mcsbw20ul5gmpo 4mcsbw405gmpo"}, ++ {HNBU_MCS5GHPO, 0xffffffff, 13, "4mcsbw205ghpo 4mcsbw20ul5ghpo 4mcsbw405ghpo"}, ++ {HNBU_MCS32PO, 0xffffffff, 3, "2mcs32po"}, ++ {HNBU_LEG40DUPPO, 0xffffffff, 3, "2legofdm40duppo"}, ++ {HNBU_TEMPTHRESH, 0xffffffff, 7, "1tempthresh 0temps_period 0temps_hysteresis " ++ "1tempoffset 1tempsense_slope 0tempcorrx 0tempsense_option " ++ "1phycal_tempdelta"}, /* special case */ ++ {HNBU_MUXENAB, 0xffffffff, 2, "1muxenab"}, ++ {HNBU_FEM_CFG, 0xfffff800, 5, "0femctrl 0papdcap2g 0tworangetssi2g 0pdgain2g " ++ "0epagain2g 0tssiposslope2g 0gainctrlsph 0papdcap5g 0tworangetssi5g 0pdgain5g 0epagain5g " ++ "0tssiposslope5g"}, /* special case */ ++ {HNBU_ACPA_C0, 0xfffff800, 39, "2subband5gver 2maxp2ga0 2*3pa2ga0 " ++ "1*4maxp5ga0 2*12pa5ga0"}, ++ {HNBU_ACPA_C1, 0xfffff800, 37, "2maxp2ga1 2*3pa2ga1 1*4maxp5ga1 2*12pa5ga1"}, ++ {HNBU_ACPA_C2, 0xfffff800, 37, "2maxp2ga2 2*3pa2ga2 1*4maxp5ga2 2*12pa5ga2"}, ++ {HNBU_MEAS_PWR, 0xfffff800, 5, "1measpower 1measpower1 1measpower2 2rawtempsense"}, ++ {HNBU_PDOFF, 0xfffff800, 13, "2pdoffset40ma0 2pdoffset40ma1 2pdoffset40ma2 " ++ "2pdoffset80ma0 2pdoffset80ma1 2pdoffset80ma2"}, ++ {HNBU_ACPPR_2GPO, 0xfffff800, 13, "2dot11agofdmhrbw202gpo 2ofdmlrbw202gpo " ++ "2sb20in40dot11agofdm2gpo 2sb20in80dot11agofdm2gpo 2sb20in40ofdmlrbw202gpo " ++ "2sb20in80ofdmlrbw202gpo"}, ++ {HNBU_ACPPR_5GPO, 0xfffff800, 59, "4mcsbw805glpo 4mcsbw1605glpo 4mcsbw805gmpo " ++ "4mcsbw1605gmpo 4mcsbw805ghpo 4mcsbw1605ghpo 2mcslr5glpo 2mcslr5gmpo 2mcslr5ghpo " ++ "4mcsbw80p805glpo 4mcsbw80p805gmpo 4mcsbw80p805ghpo 4mcsbw80p805gx1po 2mcslr5gx1po " ++ "2mcslr5g80p80po 4mcsbw805gx1po 4mcsbw1605gx1po"}, ++ {HNBU_MCS5Gx1PO, 0xfffff800, 9, "4mcsbw205gx1po 4mcsbw405gx1po"}, ++ {HNBU_ACPPR_SBPO, 0xfffff800, 49, "2sb20in40hrpo 2sb20in80and160hr5glpo " ++ "2sb40and80hr5glpo 2sb20in80and160hr5gmpo 2sb40and80hr5gmpo 2sb20in80and160hr5ghpo " ++ "2sb40and80hr5ghpo 2sb20in40lrpo 2sb20in80and160lr5glpo 2sb40and80lr5glpo " ++ "2sb20in80and160lr5gmpo 2sb40and80lr5gmpo 2sb20in80and160lr5ghpo 2sb40and80lr5ghpo " ++ "4dot11agduphrpo 4dot11agduplrpo 2sb20in40and80hrpo 2sb20in40and80lrpo " ++ "2sb20in80and160hr5gx1po 2sb20in80and160lr5gx1po 2sb40and80hr5gx1po 2sb40and80lr5gx1po " ++ }, ++ {HNBU_ACPPR_SB8080_PO, 0xfffff800, 23, "2sb2040and80in80p80hr5glpo " ++ "2sb2040and80in80p80lr5glpo 2sb2040and80in80p80hr5gmpo " ++ "2sb2040and80in80p80lr5gmpo 2sb2040and80in80p80hr5ghpo 2sb2040and80in80p80lr5ghpo " ++ "2sb2040and80in80p80hr5gx1po 2sb2040and80in80p80lr5gx1po 2sb20in80p80hr5gpo " ++ "2sb20in80p80lr5gpo 2dot11agduppo"}, ++ {HNBU_NOISELVL, 0xfffff800, 16, "1noiselvl2ga0 1noiselvl2ga1 1noiselvl2ga2 " ++ "1*4noiselvl5ga0 1*4noiselvl5ga1 1*4noiselvl5ga2"}, ++ {HNBU_RXGAIN_ERR, 0xfffff800, 16, "1rxgainerr2ga0 1rxgainerr2ga1 1rxgainerr2ga2 " ++ "1*4rxgainerr5ga0 1*4rxgainerr5ga1 1*4rxgainerr5ga2"}, ++ {HNBU_AGBGA, 0xfffff800, 7, "1agbg0 1agbg1 1agbg2 1aga0 1aga1 1aga2"}, ++ {HNBU_USBDESC_COMPOSITE, 0xffffffff, 3, "2usbdesc_composite"}, ++ {HNBU_UUID, 0xffffffff, 17, "16uuid"}, ++ {HNBU_WOWLGPIO, 0xffffffff, 2, "1wowl_gpio"}, ++ {HNBU_ACRXGAINS_C0, 0xfffff800, 5, "0rxgains5gtrelnabypa0 0rxgains5gtrisoa0 " ++ "0rxgains5gelnagaina0 0rxgains2gtrelnabypa0 0rxgains2gtrisoa0 0rxgains2gelnagaina0 " ++ "0rxgains5ghtrelnabypa0 0rxgains5ghtrisoa0 0rxgains5ghelnagaina0 0rxgains5gmtrelnabypa0 " ++ "0rxgains5gmtrisoa0 0rxgains5gmelnagaina0"}, /* special case */ ++ {HNBU_ACRXGAINS_C1, 0xfffff800, 5, "0rxgains5gtrelnabypa1 0rxgains5gtrisoa1 " ++ "0rxgains5gelnagaina1 0rxgains2gtrelnabypa1 0rxgains2gtrisoa1 0rxgains2gelnagaina1 " ++ "0rxgains5ghtrelnabypa1 0rxgains5ghtrisoa1 0rxgains5ghelnagaina1 0rxgains5gmtrelnabypa1 " ++ "0rxgains5gmtrisoa1 0rxgains5gmelnagaina1"}, /* special case */ ++ {HNBU_ACRXGAINS_C2, 0xfffff800, 5, "0rxgains5gtrelnabypa2 0rxgains5gtrisoa2 " ++ "0rxgains5gelnagaina2 0rxgains2gtrelnabypa2 0rxgains2gtrisoa2 0rxgains2gelnagaina2 " ++ "0rxgains5ghtrelnabypa2 0rxgains5ghtrisoa2 0rxgains5ghelnagaina2 0rxgains5gmtrelnabypa2 " ++ "0rxgains5gmtrisoa2 0rxgains5gmelnagaina2"}, /* special case */ ++ {HNBU_TXDUTY, 0xfffff800, 9, "2tx_duty_cycle_ofdm_40_5g " ++ "2tx_duty_cycle_thresh_40_5g 2tx_duty_cycle_ofdm_80_5g 2tx_duty_cycle_thresh_80_5g"}, ++ {HNBU_PDOFF_2G, 0xfffff800, 3, "0pdoffset2g40ma0 0pdoffset2g40ma1 " ++ "0pdoffset2g40ma2 0pdoffset2g40mvalid"}, ++ {HNBU_ACPA_CCK, 0xfffff800, 7, "2*3pa2gccka0"}, ++ {HNBU_ACPA_40, 0xfffff800, 25, "2*12pa5gbw40a0"}, ++ {HNBU_ACPA_80, 0xfffff800, 25, "2*12pa5gbw80a0"}, ++ {HNBU_ACPA_4080, 0xfffff800, 49, "2*12pa5gbw4080a0 2*12pa5gbw4080a1"}, ++ {HNBU_SUBBAND5GVER, 0xfffff800, 3, "2subband5gver"}, ++ {HNBU_PAPARAMBWVER, 0xfffff800, 2, "1paparambwver"}, ++ {HNBU_TXBFRPCALS, 0xfffff800, 11, ++ "2rpcal2g 2rpcal5gb0 2rpcal5gb1 2rpcal5gb2 2rpcal5gb3"}, /* txbf rpcalvars */ ++ {HNBU_GPIO_PULL_DOWN, 0xffffffff, 5, "4gpdn"}, ++ {HNBU_MACADDR2, 0xffffffff, 7, "6macaddr2"}, /* special case */ ++ {0xFF, 0xffffffff, 0, ""} ++}; ++ ++#endif /* _bcmsrom_tbl_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmtcp.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmtcp.h +new file mode 100644 +index 000000000..4d4094875 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmtcp.h +@@ -0,0 +1,93 @@ ++/* ++ * Fundamental constants relating to TCP Protocol ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmtcp.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _bcmtcp_h_ ++#define _bcmtcp_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++#define TCP_SRC_PORT_OFFSET 0 /* TCP source port offset */ ++#define TCP_DEST_PORT_OFFSET 2 /* TCP dest port offset */ ++#define TCP_SEQ_NUM_OFFSET 4 /* TCP sequence number offset */ ++#define TCP_ACK_NUM_OFFSET 8 /* TCP acknowledgement number offset */ ++#define TCP_HLEN_OFFSET 12 /* HLEN and reserved bits offset */ ++#define TCP_FLAGS_OFFSET 13 /* FLAGS and reserved bits offset */ ++#define TCP_CHKSUM_OFFSET 16 /* TCP body checksum offset */ ++ ++#define TCP_PORT_LEN 2 /* TCP port field length */ ++ ++/* 8bit TCP flag field */ ++#define TCP_FLAG_URG 0x20 ++#define TCP_FLAG_ACK 0x10 ++#define TCP_FLAG_PSH 0x08 ++#define TCP_FLAG_RST 0x04 ++#define TCP_FLAG_SYN 0x02 ++#define TCP_FLAG_FIN 0x01 ++ ++#define TCP_HLEN_MASK 0xf000 ++#define TCP_HLEN_SHIFT 12 ++ ++/* These fields are stored in network order */ ++BWL_PRE_PACKED_STRUCT struct bcmtcp_hdr ++{ ++ uint16 src_port; /* Source Port Address */ ++ uint16 dst_port; /* Destination Port Address */ ++ uint32 seq_num; /* TCP Sequence Number */ ++ uint32 ack_num; /* TCP Sequence Number */ ++ uint16 hdrlen_rsvd_flags; /* Header length, reserved bits and flags */ ++ uint16 tcpwin; /* TCP window */ ++ uint16 chksum; /* Segment checksum with pseudoheader */ ++ uint16 urg_ptr; /* Points to seq-num of byte following urg data */ ++} BWL_POST_PACKED_STRUCT; ++ ++#define TCP_MIN_HEADER_LEN 20 ++ ++#define TCP_HDRLEN_MASK 0xf0 ++#define TCP_HDRLEN_SHIFT 4 ++#define TCP_HDRLEN(hdrlen) (((hdrlen) & TCP_HDRLEN_MASK) >> TCP_HDRLEN_SHIFT) ++ ++#define TCP_FLAGS_MASK 0x1f ++#define TCP_FLAGS(hdrlen) ((hdrlen) & TCP_FLAGS_MASK) ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++/* To address round up by 32bit. */ ++#define IS_TCPSEQ_GE(a, b) ((a - b) < NBITVAL(31)) /* a >= b */ ++#define IS_TCPSEQ_LE(a, b) ((b - a) < NBITVAL(31)) /* a =< b */ ++#define IS_TCPSEQ_GT(a, b) !IS_TCPSEQ_LE(a, b) /* a > b */ ++#define IS_TCPSEQ_LT(a, b) !IS_TCPSEQ_GE(a, b) /* a < b */ ++ ++#endif /* #ifndef _bcmtcp_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmudp.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmudp.h +new file mode 100644 +index 000000000..e55813482 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmudp.h +@@ -0,0 +1,61 @@ ++/* ++ * Fundamental constants relating to UDP Protocol ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmudp.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _bcmudp_h_ ++#define _bcmudp_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* UDP header */ ++#define UDP_DEST_PORT_OFFSET 2 /* UDP dest port offset */ ++#define UDP_LEN_OFFSET 4 /* UDP length offset */ ++#define UDP_CHKSUM_OFFSET 6 /* UDP body checksum offset */ ++ ++#define UDP_HDR_LEN 8 /* UDP header length */ ++#define UDP_PORT_LEN 2 /* UDP port length */ ++ ++/* These fields are stored in network order */ ++BWL_PRE_PACKED_STRUCT struct bcmudp_hdr ++{ ++ uint16 src_port; /* Source Port Address */ ++ uint16 dst_port; /* Destination Port Address */ ++ uint16 len; /* Number of bytes in datagram including header */ ++ uint16 chksum; /* entire datagram checksum with pseudoheader */ ++} BWL_POST_PACKED_STRUCT; ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* #ifndef _bcmudp_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/bcmutils.h b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmutils.h +new file mode 100644 +index 000000000..3c061b8bf +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/bcmutils.h +@@ -0,0 +1,1355 @@ ++/* ++ * Misc useful os-independent macros and functions. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: bcmutils.h 701785 2017-05-26 11:08:50Z $ ++ */ ++ ++#ifndef _bcmutils_h_ ++#define _bcmutils_h_ ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) ++#define bcm_strncat_s(dst, noOfElements, src, count) strncat((dst), (src), (count)) ++#define bcm_snprintf_s snprintf ++#define bcm_sprintf_s snprintf ++ ++/* ++ * #define bcm_strcpy_s(dst, count, src) strncpy((dst), (src), (count)) ++ * Use bcm_strcpy_s instead as it is a safer option ++ * bcm_strcat_s: Use bcm_strncat_s as a safer option ++ * ++ */ ++ ++#define BCM_BIT(x) (1 << (x)) ++ ++/* ctype replacement */ ++#define _BCM_U 0x01 /* upper */ ++#define _BCM_L 0x02 /* lower */ ++#define _BCM_D 0x04 /* digit */ ++#define _BCM_C 0x08 /* cntrl */ ++#define _BCM_P 0x10 /* punct */ ++#define _BCM_S 0x20 /* white space (space/lf/tab) */ ++#define _BCM_X 0x40 /* hex digit */ ++#define _BCM_SP 0x80 /* hard space (0x20) */ ++ ++extern const unsigned char bcm_ctype[]; ++#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) ++ ++#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) ++#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) ++#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) ++#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) ++#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) ++#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) ++#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) ++#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) ++#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) ++#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) ++#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) ++#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) ++#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) ++ ++#define CIRCULAR_ARRAY_FULL(rd_idx, wr_idx, max) ((wr_idx + 1)%max == rd_idx) ++ ++#define KB(bytes) (((bytes) + 1023) / 1024) ++ ++/* Buffer structure for collecting string-formatted data ++* using bcm_bprintf() API. ++* Use bcm_binit() to initialize before use ++*/ ++ ++struct bcmstrbuf { ++ 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 */ ++}; ++ ++#define BCMSTRBUF_LEN(b) (b->size) ++#define BCMSTRBUF_BUF(b) (b->buf) ++ ++/* ** driver-only section ** */ ++#ifdef BCMDRIVER ++#include ++#include ++#include ++ ++#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */ ++ ++/* ++ * Spin at most 'us' microseconds while 'exp' is true. ++ * Caller should explicitly test 'exp' when this completes ++ * and take appropriate error action if 'exp' is still true. ++ */ ++#ifndef SPINWAIT_POLL_PERIOD ++#define SPINWAIT_POLL_PERIOD 10 ++#endif ++ ++#define SPINWAIT(exp, us) { \ ++ uint countdown = (us) + (SPINWAIT_POLL_PERIOD - 1); \ ++ while ((exp) && (countdown >= SPINWAIT_POLL_PERIOD)) { \ ++ OSL_DELAY(SPINWAIT_POLL_PERIOD); \ ++ countdown -= SPINWAIT_POLL_PERIOD; \ ++ } \ ++} ++ ++/* forward definition of ether_addr structure used by some function prototypes */ ++ ++struct ether_addr; ++ ++extern int ether_isbcast(const void *ea); ++extern int ether_isnulladdr(const void *ea); ++ ++#define UP_TABLE_MAX ((IPV4_TOS_DSCP_MASK >> IPV4_TOS_DSCP_SHIFT) + 1) /* 64 max */ ++ ++/* externs */ ++/* packet */ ++extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); ++extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); ++extern uint pkttotlen(osl_t *osh, void *p); ++extern void *pktlast(osl_t *osh, void *p); ++extern uint pktsegcnt(osl_t *osh, void *p); ++extern uint pktsegcnt_war(osl_t *osh, void *p); ++extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset); ++extern void *pktoffset(osl_t *osh, void *p, uint offset); ++/* Add to adjust 802.1x priority */ ++extern void pktset8021xprio(void *pkt, int prio); ++ ++/* Get priority from a packet and pass it back in scb (or equiv) */ ++#define PKTPRIO_VDSCP 0x100 /* DSCP prio found af ter VLAN tag */ ++#define PKTPRIO_VLAN 0x200 /* VLAN prio found */ ++#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */ ++#define PKTPRIO_DSCP 0x800 /* DSCP prio found */ ++ ++/* DSCP type definitions (RFC4594) */ ++/* AF1x: High-Throughput Data (RFC2597) */ ++#define DSCP_AF11 0x0A ++#define DSCP_AF12 0x0C ++#define DSCP_AF13 0x0E ++/* AF2x: Low-Latency Data (RFC2597) */ ++#define DSCP_AF21 0x12 ++#define DSCP_AF22 0x14 ++#define DSCP_AF23 0x16 ++/* AF3x: Multimedia Streaming (RFC2597) */ ++#define DSCP_AF31 0x1A ++#define DSCP_AF32 0x1C ++#define DSCP_AF33 0x1E ++/* EF: Telephony (RFC3246) */ ++#define DSCP_EF 0x2E ++ ++extern uint pktsetprio(void *pkt, bool update_vtag); ++extern uint pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag); ++extern bool pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp); ++ ++/* ethernet address */ ++extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); ++extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); ++ ++/* ip address */ ++struct ipv4_addr; ++extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); ++extern char *bcm_ipv6_ntoa(void *ipv6, char *buf); ++extern int bcm_atoipv4(const char *p, struct ipv4_addr *ip); ++ ++/* delay */ ++extern void bcm_mdelay(uint ms); ++/* variable access */ ++#if defined(BCM_RECLAIM) ++#define NVRAM_RECLAIM_CHECK(name) \ ++ if (bcm_attach_part_reclaimed == TRUE) { \ ++ *(char*) 0 = 0; /* TRAP */ \ ++ return NULL; \ ++ } ++#else /* BCM_RECLAIM */ ++#define NVRAM_RECLAIM_CHECK(name) ++#endif /* BCM_RECLAIM */ ++ ++extern char *getvar(char *vars, const char *name); ++extern int getintvar(char *vars, const char *name); ++extern int getintvararray(char *vars, const char *name, int index); ++extern int getintvararraysize(char *vars, const char *name); ++extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); ++#define bcm_perf_enable() ++#define bcmstats(fmt) ++#define bcmlog(fmt, a1, a2) ++#define bcmdumplog(buf, size) *buf = '\0' ++#define bcmdumplogent(buf, idx) -1 ++ ++#define TSF_TICKS_PER_MS 1000 ++#define TS_ENTER 0xdeadbeef /* Timestamp profiling enter */ ++#define TS_EXIT 0xbeefcafe /* Timestamp profiling exit */ ++ ++#define bcmtslog(tstamp, fmt, a1, a2) ++#define bcmprinttslogs() ++#define bcmprinttstamp(us) ++#define bcmdumptslog(b) ++ ++extern char *bcm_nvram_vars(uint *length); ++extern int bcm_nvram_cache(void *sih); ++ ++/* 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 */ ++typedef struct bcm_iovar { ++ const char *name; /* name for lookup and display */ ++ uint16 varid; /* id for switch */ ++ uint16 flags; /* driver-specific flag bits */ ++ uint8 flags2; /* driver-specific flag bits */ ++ uint8 type; /* base type of argument */ ++ uint16 minlen; /* min length for buffer vars */ ++} bcm_iovar_t; ++ ++/* 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) ++ ++/* flags are per-driver based on driver attributes */ ++ ++extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); ++extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); ++ ++/* ioctl structure */ ++typedef struct wlc_ioctl_cmd { ++ uint16 cmd; /**< IOCTL command */ ++ uint16 flags; /**< IOCTL command flags */ ++ int16 min_len; /**< IOCTL command minimum argument len (in bytes) */ ++} wlc_ioctl_cmd_t; ++ ++#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ ++ defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) ++extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); ++#endif ++#endif /* BCMDRIVER */ ++ ++/* string */ ++extern int bcm_atoi(const char *s); ++extern ulong bcm_strtoul(const char *cp, char **endp, uint base); ++extern char *bcmstrstr(const char *haystack, const char *needle); ++extern char *bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len); ++extern char *bcmstrcat(char *dest, const char *src); ++extern char *bcmstrncat(char *dest, const char *src, uint size); ++extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); ++char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); ++int bcmstricmp(const char *s1, const char *s2); ++int bcmstrnicmp(const char* s1, const char* s2, int cnt); ++ ++/* 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) ++ ++/* Initializer for IOV type strings */ ++#define BCM_IOV_TYPE_INIT { \ ++ "void", \ ++ "bool", \ ++ "int8", \ ++ "uint8", \ ++ "int16", \ ++ "uint16", \ ++ "int32", \ ++ "uint32", \ ++ "buffer", \ ++ "" } ++ ++#define BCM_IOVT_IS_INT(type) (\ ++ (type == IOVT_BOOL) || \ ++ (type == IOVT_INT8) || \ ++ (type == IOVT_UINT8) || \ ++ (type == IOVT_INT16) || \ ++ (type == IOVT_UINT16) || \ ++ (type == IOVT_INT32) || \ ++ (type == IOVT_UINT32)) ++ ++/* ** driver/apps-shared section ** */ ++ ++#define BCME_STRLEN 64 /* Max string length for BCM errors */ ++#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) ++ ++ ++/* ++ * error codes could be added but the defined ones shouldn't be changed/deleted ++ * these error codes are exposed to the user code ++ * when ever a new error code is added to this list ++ * please update errorstring table with the related error string and ++ * update osl files with os specific errorcode map ++*/ ++ ++#define BCME_OK 0 /* Success */ ++#define BCME_ERROR -1 /* Error generic */ ++#define BCME_BADARG -2 /* Bad Argument */ ++#define BCME_BADOPTION -3 /* Bad option */ ++#define BCME_NOTUP -4 /* Not up */ ++#define BCME_NOTDOWN -5 /* Not down */ ++#define BCME_NOTAP -6 /* Not AP */ ++#define BCME_NOTSTA -7 /* Not STA */ ++#define BCME_BADKEYIDX -8 /* BAD Key Index */ ++#define BCME_RADIOOFF -9 /* Radio Off */ ++#define BCME_NOTBANDLOCKED -10 /* Not band locked */ ++#define BCME_NOCLK -11 /* No Clock */ ++#define BCME_BADRATESET -12 /* BAD Rate valueset */ ++#define BCME_BADBAND -13 /* BAD Band */ ++#define BCME_BUFTOOSHORT -14 /* Buffer too short */ ++#define BCME_BUFTOOLONG -15 /* Buffer too long */ ++#define BCME_BUSY -16 /* Busy */ ++#define BCME_NOTASSOCIATED -17 /* Not Associated */ ++#define BCME_BADSSIDLEN -18 /* Bad SSID len */ ++#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ ++#define BCME_BADCHAN -20 /* Bad Channel */ ++#define BCME_BADADDR -21 /* Bad Address */ ++#define BCME_NORESOURCE -22 /* Not Enough Resources */ ++#define BCME_UNSUPPORTED -23 /* Unsupported */ ++#define BCME_BADLEN -24 /* Bad length */ ++#define BCME_NOTREADY -25 /* Not Ready */ ++#define BCME_EPERM -26 /* Not Permitted */ ++#define BCME_NOMEM -27 /* No Memory */ ++#define BCME_ASSOCIATED -28 /* Associated */ ++#define BCME_RANGE -29 /* Not In Range */ ++#define BCME_NOTFOUND -30 /* Not Found */ ++#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ ++#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ ++#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ ++#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ ++#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ ++#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ ++#define BCME_VERSION -37 /* Incorrect version */ ++#define BCME_TXFAIL -38 /* TX failure */ ++#define BCME_RXFAIL -39 /* RX failure */ ++#define BCME_NODEVICE -40 /* Device not present */ ++#define BCME_NMODE_DISABLED -41 /* NMODE disabled */ ++#define BCME_NONRESIDENT -42 /* access to nonresident overlay */ ++#define BCME_SCANREJECT -43 /* reject scan request */ ++#define BCME_USAGE_ERROR -44 /* WLCMD usage error */ ++#define BCME_IOCTL_ERROR -45 /* WLCMD ioctl error */ ++#define BCME_SERIAL_PORT_ERR -46 /* RWL serial port error */ ++#define BCME_DISABLED -47 /* Disabled in this build */ ++#define BCME_DECERR -48 /* Decrypt error */ ++#define BCME_ENCERR -49 /* Encrypt error */ ++#define BCME_MICERR -50 /* Integrity/MIC error */ ++#define BCME_REPLAY -51 /* Replay */ ++#define BCME_IE_NOTFOUND -52 /* IE not found */ ++#define BCME_DATA_NOTFOUND -53 /* Complete data not found in buffer */ ++#define BCME_NOT_GC -54 /* expecting a group client */ ++#define BCME_PRS_REQ_FAILED -55 /* GC presence req failed to sent */ ++#define BCME_NO_P2P_SE -56 /* Could not find P2P-Subelement */ ++#define BCME_NOA_PND -57 /* NoA pending, CB shuld be NULL */ ++#define BCME_FRAG_Q_FAILED -58 /* queueing 80211 frag failedi */ ++#define BCME_GET_AF_FAILED -59 /* Get p2p AF pkt failed */ ++#define BCME_MSCH_NOTREADY -60 /* scheduler not ready */ ++#define BCME_LAST BCME_MSCH_NOTREADY ++ ++#define BCME_NOTENABLED BCME_DISABLED ++ ++/* This error code is *internal* to the driver, and is not propogated to users. It should ++ * only be used by IOCTL patch handlers as an indication that it did not handle the IOCTL. ++ * (Since the error code is internal, an entry in 'BCMERRSTRINGTABLE' is not required, ++ * nor does it need to be part of any OSL driver-to-OS error code mapping). ++ */ ++#define BCME_IOCTL_PATCH_UNSUPPORTED -9999 ++#if (BCME_LAST <= BCME_IOCTL_PATCH_UNSUPPORTED) ++ #error "BCME_LAST <= BCME_IOCTL_PATCH_UNSUPPORTED" ++#endif ++ ++/* These are collection of BCME Error strings */ ++#define BCMERRSTRINGTABLE { \ ++ "OK", \ ++ "Undefined error", \ ++ "Bad Argument", \ ++ "Bad Option", \ ++ "Not up", \ ++ "Not down", \ ++ "Not AP", \ ++ "Not STA", \ ++ "Bad Key Index", \ ++ "Radio Off", \ ++ "Not band locked", \ ++ "No clock", \ ++ "Bad Rate valueset", \ ++ "Bad Band", \ ++ "Buffer too short", \ ++ "Buffer too long", \ ++ "Busy", \ ++ "Not Associated", \ ++ "Bad SSID len", \ ++ "Out of Range Channel", \ ++ "Bad Channel", \ ++ "Bad Address", \ ++ "Not Enough Resources", \ ++ "Unsupported", \ ++ "Bad length", \ ++ "Not Ready", \ ++ "Not Permitted", \ ++ "No Memory", \ ++ "Associated", \ ++ "Not In Range", \ ++ "Not Found", \ ++ "WME Not Enabled", \ ++ "TSPEC Not Found", \ ++ "ACM Not Supported", \ ++ "Not WME Association", \ ++ "SDIO Bus Error", \ ++ "Dongle Not Accessible", \ ++ "Incorrect version", \ ++ "TX Failure", \ ++ "RX Failure", \ ++ "Device Not Present", \ ++ "NMODE Disabled", \ ++ "Nonresident overlay access", \ ++ "Scan Rejected", \ ++ "WLCMD usage error", \ ++ "WLCMD ioctl error", \ ++ "RWL serial port error", \ ++ "Disabled", \ ++ "Decrypt error", \ ++ "Encrypt error", \ ++ "MIC error", \ ++ "Replay", \ ++ "IE not found", \ ++ "Data not found", \ ++ "NOT GC", \ ++ "PRS REQ FAILED", \ ++ "NO P2P SubElement", \ ++ "NOA Pending", \ ++ "FRAG Q FAILED", \ ++ "GET ActionFrame failed", \ ++ "scheduler not ready", \ ++} ++ ++#ifndef ABS ++#define ABS(a) (((a) < 0) ? -(a) : (a)) ++#endif /* ABS */ ++ ++#ifndef MIN ++#define MIN(a, b) (((a) < (b)) ? (a) : (b)) ++#endif /* MIN */ ++ ++#ifndef MAX ++#define MAX(a, b) (((a) > (b)) ? (a) : (b)) ++#endif /* MAX */ ++ ++/* limit to [min, max] */ ++#ifndef LIMIT_TO_RANGE ++#define LIMIT_TO_RANGE(x, min, max) \ ++ ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) ++#endif /* LIMIT_TO_RANGE */ ++ ++/* limit to max */ ++#ifndef LIMIT_TO_MAX ++#define LIMIT_TO_MAX(x, max) \ ++ (((x) > (max) ? (max) : (x))) ++#endif /* LIMIT_TO_MAX */ ++ ++/* limit to min */ ++#ifndef LIMIT_TO_MIN ++#define LIMIT_TO_MIN(x, min) \ ++ (((x) < (min) ? (min) : (x))) ++#endif /* LIMIT_TO_MIN */ ++ ++#define DELTA(curr, prev) ((curr) > (prev) ? ((curr) - (prev)) : \ ++ (0xffffffff - (prev) + (curr) + 1)) ++#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) ++#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) ++#define ROUNDDN(p, align) ((p) & ~((align) - 1)) ++#define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) ++#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ ++ & ~((boundary) - 1)) ++#define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ ++ & ~((boundary) - 1)) ++#define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) ++#define VALID_MASK(mask) !((mask) & ((mask) + 1)) ++ ++#ifndef OFFSETOF ++#ifdef __ARMCC_VERSION ++/* ++ * The ARM RVCT compiler complains when using OFFSETOF where a constant ++ * expression is expected, such as an initializer for a static object. ++ * offsetof from the runtime library doesn't have that problem. ++ */ ++#include ++#define OFFSETOF(type, member) offsetof(type, member) ++#else ++# if ((__GNUC__ >= 4) && (__GNUC_MINOR__ >= 8)) ++/* GCC 4.8+ complains when using our OFFSETOF macro in array length declarations. */ ++# define OFFSETOF(type, member) __builtin_offsetof(type, member) ++# else ++# define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) ++# endif /* GCC 4.8 or newer */ ++#endif /* __ARMCC_VERSION */ ++#endif /* OFFSETOF */ ++ ++#ifndef CONTAINEROF ++#define CONTAINEROF(ptr, type, member) ((type *)((char *)(ptr) - OFFSETOF(type, member))) ++#endif /* CONTAINEROF */ ++ ++#ifndef ARRAYSIZE ++#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) ++#endif ++ ++#ifndef ARRAYLAST /* returns pointer to last array element */ ++#define ARRAYLAST(a) (&a[ARRAYSIZE(a)-1]) ++#endif ++ ++/* Reference a function; used to prevent a static function from being optimized out */ ++extern void *_bcmutils_dummy_fn; ++#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) ++ ++/* bit map related macros */ ++#ifndef setbit ++#ifndef NBBY /* the BSD family defines NBBY */ ++#define NBBY 8 /* 8 bits per byte */ ++#endif /* #ifndef NBBY */ ++#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS ++extern void setbit(void *array, uint bit); ++extern void clrbit(void *array, uint bit); ++extern bool isset(const void *array, uint bit); ++extern bool isclr(const void *array, uint bit); ++#else ++#define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) ++#define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) ++#define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) ++#define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) ++#endif ++#endif /* setbit */ ++extern void set_bitrange(void *array, uint start, uint end, uint maxbit); ++ ++#define isbitset(a, i) (((a) & (1 << (i))) != 0) ++ ++#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) ++ ++extern void bcm_bitprint32(const uint32 u32); ++ ++/* ++ * ---------------------------------------------------------------------------- ++ * Multiword map of 2bits, nibbles ++ * setbit2 setbit4 (void *ptr, uint32 ix, uint32 val) ++ * getbit2 getbit4 (void *ptr, uint32 ix) ++ * ---------------------------------------------------------------------------- ++ */ ++ ++#define DECLARE_MAP_API(NB, RSH, LSH, OFF, MSK) \ ++static INLINE void setbit##NB(void *ptr, uint32 ix, uint32 val) \ ++{ \ ++ uint32 *addr = (uint32 *)ptr; \ ++ uint32 *a = addr + (ix >> RSH); /* (ix / 2^RSH) */ \ ++ uint32 pos = (ix & OFF) << LSH; /* (ix % 2^RSH) * 2^LSH */ \ ++ uint32 mask = (MSK << pos); \ ++ uint32 tmp = *a & ~mask; \ ++ *a = tmp | (val << pos); \ ++} \ ++static INLINE uint32 getbit##NB(void *ptr, uint32 ix) \ ++{ \ ++ uint32 *addr = (uint32 *)ptr; \ ++ uint32 *a = addr + (ix >> RSH); \ ++ uint32 pos = (ix & OFF) << LSH; \ ++ return ((*a >> pos) & MSK); \ ++} ++ ++DECLARE_MAP_API(2, 4, 1, 15U, 0x0003) /* setbit2() and getbit2() */ ++DECLARE_MAP_API(4, 3, 2, 7U, 0x000F) /* setbit4() and getbit4() */ ++DECLARE_MAP_API(8, 2, 3, 3U, 0x00FF) /* setbit8() and getbit8() */ ++ ++/* 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 */ ++#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */ ++#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */ ++ ++/* use for direct output of MAC address in printf etc */ ++#define MACF "%02x:%02x:%02x:%02x:%02x:%02x" ++#define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ ++ ((struct ether_addr *) (ea))->octet[1], \ ++ ((struct ether_addr *) (ea))->octet[2], \ ++ ((struct ether_addr *) (ea))->octet[3], \ ++ ((struct ether_addr *) (ea))->octet[4], \ ++ ((struct ether_addr *) (ea))->octet[5] ++ ++#define CONST_ETHERP_TO_MACF(ea) ((const struct ether_addr *) (ea))->octet[0], \ ++ ((const struct ether_addr *) (ea))->octet[1], \ ++ ((const struct ether_addr *) (ea))->octet[2], \ ++ ((const struct ether_addr *) (ea))->octet[3], \ ++ ((const struct ether_addr *) (ea))->octet[4], \ ++ ((const struct ether_addr *) (ea))->octet[5] ++#define ETHER_TO_MACF(ea) (ea).octet[0], \ ++ (ea).octet[1], \ ++ (ea).octet[2], \ ++ (ea).octet[3], \ ++ (ea).octet[4], \ ++ (ea).octet[5] ++#if !defined(SIMPLE_MAC_PRINT) ++#define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] ++#else ++#define MACDBG "%02x:%02x:%02x" ++#define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] ++#endif /* SIMPLE_MAC_PRINT */ ++ ++/* bcm_format_flags() bit description structure */ ++typedef struct bcm_bit_desc { ++ uint32 bit; ++ const char* name; ++} bcm_bit_desc_t; ++ ++/* bcm_format_field */ ++typedef struct bcm_bit_desc_ex { ++ uint32 mask; ++ const bcm_bit_desc_t *bitfield; ++} bcm_bit_desc_ex_t; ++ ++/* buffer length for ethernet address from bcm_ether_ntoa() */ ++#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */ ++ ++static INLINE uint32 /* 32bit word aligned xor-32 */ ++bcm_compute_xor32(volatile uint32 *u32_val, int num_u32) ++{ ++ int idx; ++ uint32 xor32 = 0; ++ for (idx = 0; idx < num_u32; idx++) ++ xor32 ^= *(u32_val + idx); ++ return xor32; ++} ++ ++/* crypto utility function */ ++/* 128-bit xor: *dst = *src1 xor *src2. dst1, src1 and src2 may have any alignment */ ++static INLINE void ++xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) ++{ ++ if ( ++#ifdef __i386__ ++ 1 || ++#endif ++ (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { ++ /* ARM CM3 rel time: 1229 (727 if alignment check could be omitted) */ ++ /* x86 supports unaligned. This version runs 6x-9x faster on x86. */ ++ ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; ++ ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; ++ ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; ++ ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; ++ } else { ++ /* ARM CM3 rel time: 4668 (4191 if alignment check could be omitted) */ ++ int k; ++ for (k = 0; k < 16; k++) ++ dst[k] = src1[k] ^ src2[k]; ++ } ++} ++ ++/* externs */ ++/* crc */ ++extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc); ++extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc); ++extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); ++ ++/* format/print */ ++#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ ++ defined(WLMSG_ASSOC) ++/* print out the value a field has: fields may have 1-32 bits and may hold any value */ ++extern int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 field, char* buf, int len); ++/* print out which bits in flags are set */ ++extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); ++#endif ++ ++extern int bcm_format_hex(char *str, const void *bytes, int len); ++ ++extern const char *bcm_crypto_algo_name(uint algo); ++extern char *bcm_chipname(uint chipid, char *buf, uint len); ++extern char *bcm_brev_str(uint32 brev, char *buf); ++extern void printbig(char *buf); ++extern void prhex(const char *msg, volatile uchar *buf, uint len); ++ ++/* IE parsing */ ++ ++/* packing is required if struct is passed across the bus */ ++#include ++/* tag_ID/length/value_buffer tuple */ ++typedef struct bcm_tlv { ++ uint8 id; ++ uint8 len; ++ uint8 data[1]; ++} bcm_tlv_t; ++ ++#define BCM_TLV_SIZE(_tlv) ((_tlv) ? (OFFSETOF(bcm_tlv_t, data) + (_tlv)->len) : 0) ++ ++#define BCM_XTLV_TAG_LEN_SIZE 4 ++ ++/* bcm tlv w/ 16 bit id/len */ ++typedef BWL_PRE_PACKED_STRUCT struct bcm_xtlv { ++ uint16 id; ++ uint16 len; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT bcm_xtlv_t; ++#include ++ ++ ++/* descriptor of xtlv data src or dst */ ++typedef struct { ++ uint16 type; ++ uint16 len; ++ void *ptr; /* ptr to memory location */ ++} xtlv_desc_t; ++ ++/* xtlv options */ ++#define BCM_XTLV_OPTION_NONE 0x0000 ++#define BCM_XTLV_OPTION_ALIGN32 0x0001 ++ ++typedef uint16 bcm_xtlv_opts_t; ++struct bcm_xtlvbuf { ++ bcm_xtlv_opts_t opts; ++ uint16 size; ++ uint8 *head; /* point to head of buffer */ ++ uint8 *buf; /* current position of buffer */ ++ /* allocated buffer may follow, but not necessarily */ ++}; ++typedef struct bcm_xtlvbuf bcm_xtlvbuf_t; ++ ++#define BCM_TLV_MAX_DATA_SIZE (255) ++#define BCM_XTLV_MAX_DATA_SIZE (65535) ++#define BCM_TLV_HDR_SIZE (OFFSETOF(bcm_tlv_t, data)) ++ ++#define BCM_XTLV_HDR_SIZE (OFFSETOF(bcm_xtlv_t, data)) ++/* LEN only stores the value's length without padding */ ++#define BCM_XTLV_LEN(elt) ltoh16_ua(&(elt->len)) ++#define BCM_XTLV_ID(elt) ltoh16_ua(&(elt->id)) ++/* entire size of the XTLV including header, data, and optional padding */ ++#define BCM_XTLV_SIZE(elt, opts) bcm_xtlv_size(elt, opts) ++#define bcm_valid_xtlv(elt, buflen, opts) (elt && ((int)(buflen) >= (int)BCM_XTLV_SIZE(elt, opts))) ++ ++/* Check that bcm_tlv_t fits into the given buflen */ ++#define bcm_valid_tlv(elt, buflen) (\ ++ ((int)(buflen) >= (int)BCM_TLV_HDR_SIZE) && \ ++ ((int)(buflen) >= (int)(BCM_TLV_HDR_SIZE + (elt)->len))) ++ ++ ++extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); ++extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); ++extern bcm_tlv_t *bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen); ++extern bcm_tlv_t *bcm_parse_tlvs_dot11(void *buf, int buflen, uint key, bool id_ext); ++ ++extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); ++ ++extern bcm_tlv_t *bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, ++ int type_len); ++ ++extern uint8 *bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst); ++extern uint8 *bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, ++ int dst_maxlen); ++ ++extern uint8 *bcm_copy_tlv(const void *src, uint8 *dst); ++extern uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen); ++ ++/* xtlv */ ++ ++/* return the next xtlv element, and update buffer len (remaining). Buffer length ++ * updated includes padding as specified by options ++ */ ++extern bcm_xtlv_t *bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts); ++ ++/* initialize an xtlv buffer. Use options specified for packing/unpacking using ++ * the buffer. Caller is responsible for allocating both buffers. ++ */ ++extern int bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, ++ bcm_xtlv_opts_t opts); ++ ++extern uint16 bcm_xtlv_buf_len(struct bcm_xtlvbuf *tbuf); ++extern uint16 bcm_xtlv_buf_rlen(struct bcm_xtlvbuf *tbuf); ++extern uint8 *bcm_xtlv_buf(struct bcm_xtlvbuf *tbuf); ++extern uint8 *bcm_xtlv_head(struct bcm_xtlvbuf *tbuf); ++extern int bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const void *data, uint16 dlen); ++extern int bcm_xtlv_put_8(bcm_xtlvbuf_t *tbuf, uint16 type, const int8 data); ++extern int bcm_xtlv_put_16(bcm_xtlvbuf_t *tbuf, uint16 type, const int16 data); ++extern int bcm_xtlv_put_32(bcm_xtlvbuf_t *tbuf, uint16 type, const int32 data); ++extern int bcm_unpack_xtlv_entry(uint8 **buf, uint16 xpct_type, uint16 xpct_len, ++ void *dst, bcm_xtlv_opts_t opts); ++extern int bcm_pack_xtlv_entry(uint8 **buf, uint16 *buflen, uint16 type, uint16 len, ++ void *src, bcm_xtlv_opts_t opts); ++extern int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts); ++ ++/* callback for unpacking xtlv from a buffer into context. */ ++typedef int (bcm_xtlv_unpack_cbfn_t)(void *ctx, uint8 *buf, uint16 type, uint16 len); ++ ++/* unpack a tlv buffer using buffer, options, and callback */ ++extern int bcm_unpack_xtlv_buf(void *ctx, uint8 *buf, uint16 buflen, ++ bcm_xtlv_opts_t opts, bcm_xtlv_unpack_cbfn_t *cbfn); ++ ++/* unpack a set of tlvs from the buffer using provided xtlv desc */ ++extern int bcm_unpack_xtlv_buf_to_mem(void *buf, int *buflen, xtlv_desc_t *items, ++ bcm_xtlv_opts_t opts); ++ ++/* pack a set of tlvs into buffer using provided xtlv desc */ ++extern int bcm_pack_xtlv_buf_from_mem(void **buf, uint16 *buflen, xtlv_desc_t *items, ++ bcm_xtlv_opts_t opts); ++ ++/* return data pointer of a given ID from xtlv buffer ++ * xtlv data length is given to *datalen_out, if the pointer is valid ++ */ ++extern void *bcm_get_data_from_xtlv_buf(uint8 *tlv_buf, uint16 buflen, uint16 id, ++ uint16 *datalen_out, bcm_xtlv_opts_t opts); ++ ++/* callback to return next tlv id and len to pack, if there is more tlvs to come and ++ * options e.g. alignment ++ */ ++typedef bool (*bcm_pack_xtlv_next_info_cbfn_t)(void *ctx, uint16 *tlv_id, uint16 *tlv_len); ++ ++/* callback to pack the tlv into length validated buffer */ ++typedef void (*bcm_pack_xtlv_pack_next_cbfn_t)(void *ctx, ++ uint16 tlv_id, uint16 tlv_len, uint8* buf); ++ ++/* pack a set of tlvs into buffer using get_next to interate */ ++int bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, ++ bcm_xtlv_opts_t opts, bcm_pack_xtlv_next_info_cbfn_t get_next, ++ bcm_pack_xtlv_pack_next_cbfn_t pack_next, int *outlen); ++ ++/* bcmerror */ ++extern const char *bcmerrorstr(int bcmerror); ++ ++extern int wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie); ++ ++/* multi-bool data type: set of bools, mbool is true if any is set */ ++typedef uint32 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 */ ++#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) ++ ++/* generic datastruct to help dump routines */ ++struct fielddesc { ++ const char *nameandfmt; ++ uint32 offset; ++ uint32 len; ++}; ++ ++extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); ++extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, ++ const uint8 *buf, int len); ++ ++extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); ++extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); ++extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); ++ ++typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); ++extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, ++ char *buf, uint32 bufsize); ++extern uint bcm_bitcount(uint8 *bitmap, uint bytelength); ++ ++extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); ++ ++/* power conversion */ ++extern uint16 bcm_qdbm_to_mw(uint8 qdbm); ++extern uint8 bcm_mw_to_qdbm(uint16 mw); ++extern uint bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint len); ++ ++unsigned int process_nvram_vars(char *varbuf, unsigned int len); ++ ++/* trace any object allocation / free, with / without features (flags) set to the object */ ++ ++#define BCM_OBJDBG_ADD 1 ++#define BCM_OBJDBG_REMOVE 2 ++#define BCM_OBJDBG_ADD_PKT 3 ++ ++/* object feature: set or clear flags */ ++#define BCM_OBJECT_FEATURE_FLAG 1 ++#define BCM_OBJECT_FEATURE_PKT_STATE 2 ++/* object feature: flag bits */ ++#define BCM_OBJECT_FEATURE_0 (1 << 0) ++#define BCM_OBJECT_FEATURE_1 (1 << 1) ++#define BCM_OBJECT_FEATURE_2 (1 << 2) ++/* object feature: clear flag bits field set with this flag */ ++#define BCM_OBJECT_FEATURE_CLEAR (1 << 31) ++#ifdef BCM_OBJECT_TRACE ++#define bcm_pkt_validate_chk(obj) do { \ ++ void * pkttag; \ ++ bcm_object_trace_chk(obj, 0, 0, \ ++ __FUNCTION__, __LINE__); \ ++ if ((pkttag = PKTTAG(obj))) { \ ++ bcm_object_trace_chk(obj, 1, DHD_PKTTAG_SN(pkttag), \ ++ __FUNCTION__, __LINE__); \ ++ } \ ++} while (0) ++extern void bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line); ++extern void bcm_object_trace_upd(void *obj, void *obj_new); ++extern void bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn, ++ const char *caller, int line); ++extern void bcm_object_feature_set(void *obj, uint32 type, uint32 value); ++extern int bcm_object_feature_get(void *obj, uint32 type, uint32 value); ++extern void bcm_object_trace_init(void); ++extern void bcm_object_trace_deinit(void); ++#else ++#define bcm_pkt_validate_chk(obj) ++#define bcm_object_trace_opr(a, b, c, d) ++#define bcm_object_trace_upd(a, b) ++#define bcm_object_trace_chk(a, b, c, d, e) ++#define bcm_object_feature_set(a, b, c) ++#define bcm_object_feature_get(a, b, c) ++#define bcm_object_trace_init() ++#define bcm_object_trace_deinit() ++#endif /* BCM_OBJECT_TRACE */ ++ ++/* calculate a * b + c */ ++extern void bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c); ++/* calculate a / b */ ++extern void bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b); ++ ++ ++/* Public domain bit twiddling hacks/utilities: Sean Eron Anderson */ ++ ++/* Table driven count set bits. */ ++static const uint8 /* Table only for use by bcm_cntsetbits */ ++_CSBTBL[256] = ++{ ++# define B2(n) n, n + 1, n + 1, n + 2 ++# define B4(n) B2(n), B2(n + 1), B2(n + 1), B2(n + 2) ++# define B6(n) B4(n), B4(n + 1), B4(n + 1), B4(n + 2) ++ B6(0), B6(0 + 1), B6(0 + 1), B6(0 + 2) ++}; ++ ++static INLINE uint32 /* Uses table _CSBTBL for fast counting of 1's in a u32 */ ++bcm_cntsetbits(const uint32 u32arg) ++{ ++ /* function local scope declaration of const _CSBTBL[] */ ++ const uint8 * p = (const uint8 *)&u32arg; ++ return (_CSBTBL[p[0]] + _CSBTBL[p[1]] + _CSBTBL[p[2]] + _CSBTBL[p[3]]); ++} ++ ++ ++static INLINE int /* C equivalent count of leading 0's in a u32 */ ++C_bcm_count_leading_zeros(uint32 u32arg) ++{ ++ int shifts = 0; ++ while (u32arg) { ++ shifts++; u32arg >>= 1; ++ } ++ return (32U - shifts); ++} ++ ++#ifdef BCM_ASLR_HEAP ++ ++#define BCM_NVRAM_OFFSET_TCM 4 ++#define BCM_NVRAM_IMG_COMPRS_FACTOR 4 ++#define BCM_RNG_SIGNATURE 0xFEEDC0DE ++ ++typedef struct bcm_rand_metadata { ++ uint32 signature; /* host fills it in, FW verfies before reading rand */ ++ uint32 count; /* number of 4byte wide random numbers */ ++} bcm_rand_metadata_t; ++#endif /* BCM_ASLR_HEAP */ ++ ++#ifdef BCMDRIVER ++/* ++ * Assembly instructions: Count Leading Zeros ++ * "clz" : MIPS, ARM ++ * "cntlzw" : PowerPC ++ * "BSF" : x86 ++ * "lzcnt" : AMD, SPARC ++ */ ++ ++#if defined(__arm__) ++#if defined(__ARM_ARCH_7M__) /* Cortex M3 */ ++#define __USE_ASM_CLZ__ ++#endif /* __ARM_ARCH_7M__ */ ++#if defined(__ARM_ARCH_7R__) /* Cortex R4 */ ++#define __USE_ASM_CLZ__ ++#endif /* __ARM_ARCH_7R__ */ ++#endif /* __arm__ */ ++ ++static INLINE int ++bcm_count_leading_zeros(uint32 u32arg) ++{ ++#if defined(__USE_ASM_CLZ__) ++ int zeros; ++ __asm__ volatile("clz %0, %1 \n" : "=r" (zeros) : "r" (u32arg)); ++ return zeros; ++#else /* C equivalent */ ++ return C_bcm_count_leading_zeros(u32arg); ++#endif /* C equivalent */ ++} ++ ++/* ++ * Macro to count leading zeroes ++ * ++ */ ++#if defined(__GNUC__) ++#define CLZ(x) __builtin_clzl(x) ++#elif defined(__arm__) ++#define CLZ(x) __clz(x) ++#else ++#define CLZ(x) bcm_count_leading_zeros(x) ++#endif /* __GNUC__ */ ++ ++/* INTERFACE: Multiword bitmap based small id allocator. */ ++struct bcm_mwbmap; /* forward declaration for use as an opaque mwbmap handle */ ++ ++#define BCM_MWBMAP_INVALID_HDL ((struct bcm_mwbmap *)NULL) ++#define BCM_MWBMAP_INVALID_IDX ((uint32)(~0U)) ++ ++/* Incarnate a multiword bitmap based small index allocator */ ++extern struct bcm_mwbmap * bcm_mwbmap_init(osl_t * osh, uint32 items_max); ++ ++/* Free up the multiword bitmap index allocator */ ++extern void bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl); ++ ++/* Allocate a unique small index using a multiword bitmap index allocator */ ++extern uint32 bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl); ++ ++/* Force an index at a specified position to be in use */ ++extern void bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); ++ ++/* Free a previously allocated index back into the multiword bitmap allocator */ ++extern void bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); ++ ++/* Fetch the toal number of free indices in the multiword bitmap allocator */ ++extern uint32 bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl); ++ ++/* Determine whether an index is inuse or free */ ++extern bool bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix); ++ ++/* Debug dump a multiword bitmap allocator */ ++extern void bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl); ++ ++extern void bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl); ++/* End - Multiword bitmap based small Id allocator. */ ++ ++ ++/* INTERFACE: Simple unique 16bit Id Allocator using a stack implementation. */ ++ ++#define ID8_INVALID 0xFFu ++#define ID16_INVALID 0xFFFFu ++#define ID32_INVALID 0xFFFFFFFFu ++#define ID16_UNDEFINED ID16_INVALID ++ ++/* ++ * Construct a 16bit id allocator, managing 16bit ids in the range: ++ * [start_val16 .. start_val16+total_ids) ++ * Note: start_val16 is inclusive. ++ * Returns an opaque handle to the 16bit id allocator. ++ */ ++extern void * id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16); ++extern void * id16_map_fini(osl_t *osh, void * id16_map_hndl); ++extern void id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16); ++ ++/* Allocate a unique 16bit id */ ++extern uint16 id16_map_alloc(void * id16_map_hndl); ++ ++/* Free a 16bit id value into the id16 allocator */ ++extern void id16_map_free(void * id16_map_hndl, uint16 val16); ++ ++/* Get the number of failures encountered during id allocation. */ ++extern uint32 id16_map_failures(void * id16_map_hndl); ++ ++/* Audit the 16bit id allocator state. */ ++extern bool id16_map_audit(void * id16_map_hndl); ++/* End - Simple 16bit Id Allocator. */ ++#endif /* BCMDRIVER */ ++ ++extern void bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b); ++ ++void bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset); ++void bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset); ++ ++uint64 fp_mult_64(uint64 val1, uint64 val2, uint8 nf1, uint8 nf2, uint8 nf_res); ++uint8 fp_div_64(uint64 num, uint32 den, uint8 nf_num, uint8 nf_den, uint32 *div_out); ++uint8 fp_calc_head_room_64(uint64 num); ++uint8 fp_calc_head_room_32(uint32 num); ++uint32 fp_round_64(uint64 num, uint8 rnd_pos); ++uint32 fp_round_32(uint32 num, uint8 rnd_pos); ++uint32 fp_floor_64(uint64 num, uint8 floor_pos); ++uint32 fp_floor_32(uint32 num, uint8 floor_pos); ++uint32 fp_ceil_64(uint64 num, uint8 ceil_pos); ++uint64 bcm_shl_64(uint64 input, uint8 shift_amt); ++uint64 bcm_shr_64(uint64 input, uint8 shift_amt); ++ ++#define MASK_32_BITS (~0) ++#define MASK_8_BITS ((1 << 8) - 1) ++ ++#define EXTRACT_LOW32(num) (uint32)(num & MASK_32BITS) ++#define EXTRACT_HIGH32(num) (uint32)(((uint64)num >> 32) & MASK_32BITS) ++ ++#define MAXIMUM(a, b) ((a > b) ? a : b) ++#define MINIMUM(a, b) ((a < b) ? a : b) ++#define LIMIT(x, min, max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) ++ ++/* calculate checksum for ip header, tcp / udp header / data */ ++uint16 bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum); ++ ++#ifndef _dll_t_ ++#define _dll_t_ ++/* ++ * ----------------------------------------------------------------------------- ++ * Double Linked List Macros ++ * ----------------------------------------------------------------------------- ++ * ++ * All dll operations must be performed on a pre-initialized node. ++ * Inserting an uninitialized node into a list effectively initialized it. ++ * ++ * When a node is deleted from a list, you may initialize it to avoid corruption ++ * incurred by double deletion. You may skip initialization if the node is ++ * immediately inserted into another list. ++ * ++ * By placing a dll_t element at the start of a struct, you may cast a dll_t * ++ * to the struct or vice versa. ++ * ++ * Example of declaring an initializing someList and inserting nodeA, nodeB ++ * ++ * typedef struct item { ++ * dll_t node; ++ * int someData; ++ * } Item_t; ++ * Item_t nodeA, nodeB, nodeC; ++ * nodeA.someData = 11111, nodeB.someData = 22222, nodeC.someData = 33333; ++ * ++ * dll_t someList; ++ * dll_init(&someList); ++ * ++ * dll_append(&someList, (dll_t *) &nodeA); ++ * dll_prepend(&someList, &nodeB.node); ++ * dll_insert((dll_t *)&nodeC, &nodeA.node); ++ * ++ * dll_delete((dll_t *) &nodeB); ++ * ++ * Example of a for loop to walk someList of node_p ++ * ++ * extern void mydisplay(Item_t * item_p); ++ * ++ * dll_t * item_p, * next_p; ++ * for (item_p = dll_head_p(&someList); ! dll_end(&someList, item_p); ++ * item_p = next_p) ++ * { ++ * next_p = dll_next_p(item_p); ++ * ... use item_p at will, including removing it from list ... ++ * mydisplay((PItem_t)item_p); ++ * } ++ * ++ * ----------------------------------------------------------------------------- ++ */ ++typedef struct dll { ++ struct dll * next_p; ++ struct dll * prev_p; ++} dll_t; ++ ++static INLINE void ++dll_init(dll_t *node_p) ++{ ++ node_p->next_p = node_p; ++ node_p->prev_p = node_p; ++} ++/* dll macros returing a pointer to dll_t */ ++ ++static INLINE dll_t * ++dll_head_p(dll_t *list_p) ++{ ++ return list_p->next_p; ++} ++ ++ ++static INLINE dll_t * ++dll_tail_p(dll_t *list_p) ++{ ++ return (list_p)->prev_p; ++} ++ ++ ++static INLINE dll_t * ++dll_next_p(dll_t *node_p) ++{ ++ return (node_p)->next_p; ++} ++ ++ ++static INLINE dll_t * ++dll_prev_p(dll_t *node_p) ++{ ++ return (node_p)->prev_p; ++} ++ ++ ++static INLINE bool ++dll_empty(dll_t *list_p) ++{ ++ return ((list_p)->next_p == (list_p)); ++} ++ ++ ++static INLINE bool ++dll_end(dll_t *list_p, dll_t * node_p) ++{ ++ return (list_p == node_p); ++} ++ ++ ++/* inserts the node new_p "after" the node at_p */ ++static INLINE void ++dll_insert(dll_t *new_p, dll_t * at_p) ++{ ++ new_p->next_p = at_p->next_p; ++ new_p->prev_p = at_p; ++ at_p->next_p = new_p; ++ (new_p->next_p)->prev_p = new_p; ++} ++ ++static INLINE void ++dll_append(dll_t *list_p, dll_t *node_p) ++{ ++ dll_insert(node_p, dll_tail_p(list_p)); ++} ++ ++static INLINE void ++dll_prepend(dll_t *list_p, dll_t *node_p) ++{ ++ dll_insert(node_p, list_p); ++} ++ ++ ++/* deletes a node from any list that it "may" be in, if at all. */ ++static INLINE void ++dll_delete(dll_t *node_p) ++{ ++ node_p->prev_p->next_p = node_p->next_p; ++ node_p->next_p->prev_p = node_p->prev_p; ++} ++#endif /* ! defined(_dll_t_) */ ++ ++/* Elements managed in a double linked list */ ++ ++typedef struct dll_pool { ++ dll_t free_list; ++ uint16 free_count; ++ uint16 elems_max; ++ uint16 elem_size; ++ dll_t elements[1]; ++} dll_pool_t; ++ ++dll_pool_t * dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size); ++void * dll_pool_alloc(dll_pool_t * dll_pool_p); ++void dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p); ++void dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p); ++typedef void (* dll_elem_dump)(void * elem_p); ++void dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size); ++ ++/* calculate IPv4 header checksum ++ * - input ip points to IP header in network order ++ * - output cksum is in network order ++ */ ++uint16 ipv4_hdr_cksum(uint8 *ip, int ip_len); ++ ++/* calculate IPv4 TCP header checksum ++ * - input ip and tcp points to IP and TCP header in network order ++ * - output cksum is in network order ++ */ ++uint16 ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len); ++ ++/* calculate IPv6 TCP header checksum ++ * - input ipv6 and tcp points to IPv6 and TCP header in network order ++ * - output cksum is in network order ++ */ ++uint16 ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len); ++ ++#ifdef __cplusplus ++ } ++#endif ++ ++/* #define DEBUG_COUNTER */ ++#ifdef DEBUG_COUNTER ++#define CNTR_TBL_MAX 10 ++typedef struct _counter_tbl_t { ++ char name[16]; /* name of this counter table */ ++ uint32 prev_log_print; /* Internal use. Timestamp of the previous log print */ ++ uint log_print_interval; /* Desired interval to print logs in ms */ ++ uint needed_cnt; /* How many counters need to be used */ ++ uint32 cnt[CNTR_TBL_MAX]; /* Counting entries to increase at desired places */ ++ bool enabled; /* Whether to enable printing log */ ++} counter_tbl_t; ++ ++ ++void counter_printlog(counter_tbl_t *ctr_tbl); ++#endif /* DEBUG_COUNTER */ ++ ++#if defined(__GNUC__) ++#define CALL_SITE __builtin_return_address(0) ++#else ++#define CALL_SITE ((void*) 0) ++#endif ++#ifdef SHOW_LOGTRACE ++#define TRACE_LOG_BUF_MAX_SIZE 1500 ++#define BUF_NOT_AVAILABLE 0 ++#define NEXT_BUF_NOT_AVAIL 1 ++#define NEXT_BUF_AVAIL 2 ++ ++typedef struct trace_buf_info { ++ int availability; ++ int size; ++ char buf[TRACE_LOG_BUF_MAX_SIZE]; ++} trace_buf_info_t; ++#endif /* SHOW_LOGTRACE */ ++ ++#endif /* _bcmutils_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h b/module_drivers/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h +new file mode 100644 +index 000000000..cca207bdd +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h +@@ -0,0 +1,73 @@ ++/* ++ * Definitions for nl80211 vendor command/event access to host driver ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: brcm_nl80211.h 601873 2015-11-24 11:04:28Z $ ++ * ++ */ ++ ++#ifndef _brcm_nl80211_h_ ++#define _brcm_nl80211_h_ ++ ++#define OUI_BRCM 0x001018 ++#define OUI_GOOGLE 0x001A11 ++ ++enum wl_vendor_subcmd { ++ BRCM_VENDOR_SCMD_UNSPEC = 0, ++ BRCM_VENDOR_SCMD_PRIV_STR = 1, ++ BRCM_VENDOR_SCMD_BCM_STR = 2, ++ BRCM_VENDOR_SCMD_BCM_PSK = 3, ++ BRCM_VENDOR_SCMD_SET_PMK = 4, ++ BRCM_VENDOR_SCMD_GET_FEATURES = 5, ++ BRCM_VENDOR_SCMD_MAX = 6 ++}; ++ ++ ++struct bcm_nlmsg_hdr { ++ uint cmd; /* common ioctl definition */ ++ int len; /* expected return buffer length */ ++ uint offset; /* user buffer offset */ ++ uint set; /* get or set request optional */ ++ uint magic; /* magic number for verification */ ++}; ++ ++enum bcmnl_attrs { ++ BCM_NLATTR_UNSPEC, ++ ++ BCM_NLATTR_LEN, ++ BCM_NLATTR_DATA, ++ ++ __BCM_NLATTR_AFTER_LAST, ++ BCM_NLATTR_MAX = __BCM_NLATTR_AFTER_LAST - 1 ++}; ++ ++struct nl_prv_data { ++ int err; /* return result */ ++ void *data; /* ioctl return buffer pointer */ ++ uint len; /* ioctl return buffer length */ ++ struct bcm_nlmsg_hdr *nlioc; /* bcm_nlmsg_hdr header pointer */ ++}; ++ ++#endif /* _brcm_nl80211_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/dbus.h b/module_drivers/drivers/net/wireless/bcmdhd/include/dbus.h +new file mode 100644 +index 000000000..4c31c1201 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/dbus.h +@@ -0,0 +1,600 @@ ++/* ++ * Dongle BUS interface Abstraction layer ++ * target serial buses like USB, SDIO, SPI, etc. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dbus.h 596371 2015-10-30 22:43:47Z $ ++ */ ++ ++#ifndef __DBUS_H__ ++#define __DBUS_H__ ++ ++#include "typedefs.h" ++#include ++ ++extern uint dbus_msglevel; ++#define DBUS_ERROR_VAL 0x0001 ++#define DBUS_TRACE_VAL 0x0002 ++#define DBUS_INFO_VAL 0x0004 ++ ++#if defined(DHD_DEBUG) ++#define DBUSERR(args) do {if (dbus_msglevel & DBUS_ERROR_VAL) printf args;} while (0) ++#define DBUSTRACE(args) do {if (dbus_msglevel & DBUS_TRACE_VAL) printf args;} while (0) ++#define DBUSINFO(args) do {if (dbus_msglevel & DBUS_INFO_VAL) printf args;} while (0) ++#else /* defined(DHD_DEBUG) */ ++#define DBUSERR(args) ++#define DBUSTRACE(args) ++#define DBUSINFO(args) ++#endif ++ ++enum { ++ DBUS_OK = 0, ++ DBUS_ERR = -200, ++ DBUS_ERR_TIMEOUT, ++ DBUS_ERR_DISCONNECT, ++ DBUS_ERR_NODEVICE, ++ DBUS_ERR_UNSUPPORTED, ++ DBUS_ERR_PENDING, ++ DBUS_ERR_NOMEM, ++ DBUS_ERR_TXFAIL, ++ DBUS_ERR_TXTIMEOUT, ++ DBUS_ERR_TXDROP, ++ DBUS_ERR_RXFAIL, ++ DBUS_ERR_RXDROP, ++ DBUS_ERR_TXCTLFAIL, ++ DBUS_ERR_RXCTLFAIL, ++ DBUS_ERR_REG_PARAM, ++ DBUS_STATUS_CANCELLED, ++ DBUS_ERR_NVRAM, ++ DBUS_JUMBO_NOMATCH, ++ DBUS_JUMBO_BAD_FORMAT, ++ DBUS_NVRAM_NONTXT, ++ DBUS_ERR_RXZLP ++}; ++ ++#define BCM_OTP_SIZE_43236 84 /* number of 16 bit values */ ++#define BCM_OTP_SW_RGN_43236 24 /* start offset of SW config region */ ++#define BCM_OTP_ADDR_43236 0x18000800 /* address of otp base */ ++ ++#define ERR_CBMASK_TXFAIL 0x00000001 ++#define ERR_CBMASK_RXFAIL 0x00000002 ++#define ERR_CBMASK_ALL 0xFFFFFFFF ++ ++#define DBUS_CBCTL_WRITE 0 ++#define DBUS_CBCTL_READ 1 ++#if defined(INTR_EP_ENABLE) ++#define DBUS_CBINTR_POLL 2 ++#endif /* defined(INTR_EP_ENABLE) */ ++ ++#define DBUS_TX_RETRY_LIMIT 3 /* retries for failed txirb */ ++#define DBUS_TX_TIMEOUT_INTERVAL 250 /* timeout for txirb complete, in ms */ ++ ++#define DBUS_BUFFER_SIZE_TX 32000 ++#define DBUS_BUFFER_SIZE_RX 24000 ++ ++#define DBUS_BUFFER_SIZE_TX_NOAGG 2048 ++#define DBUS_BUFFER_SIZE_RX_NOAGG 2048 ++ ++/** DBUS types */ ++enum { ++ DBUS_USB, ++ DBUS_SDIO, ++ DBUS_SPI, ++ DBUS_UNKNOWN ++}; ++ ++enum dbus_state { ++ DBUS_STATE_DL_PENDING, ++ DBUS_STATE_DL_DONE, ++ DBUS_STATE_UP, ++ DBUS_STATE_DOWN, ++ DBUS_STATE_PNP_FWDL, ++ DBUS_STATE_DISCONNECT, ++ DBUS_STATE_SLEEP, ++ DBUS_STATE_DL_NEEDED ++}; ++ ++enum dbus_pnp_state { ++ DBUS_PNP_DISCONNECT, ++ DBUS_PNP_SLEEP, ++ DBUS_PNP_RESUME ++}; ++ ++enum dbus_file { ++ DBUS_FIRMWARE, ++ DBUS_NVFILE ++}; ++ ++typedef enum _DEVICE_SPEED { ++ INVALID_SPEED = -1, ++ LOW_SPEED = 1, /**< USB 1.1: 1.5 Mbps */ ++ FULL_SPEED, /**< USB 1.1: 12 Mbps */ ++ HIGH_SPEED, /**< USB 2.0: 480 Mbps */ ++ SUPER_SPEED, /**< USB 3.0: 4.8 Gbps */ ++} DEVICE_SPEED; ++ ++typedef struct { ++ int bustype; ++ int vid; ++ int pid; ++ int devid; ++ int chiprev; /**< chip revsion number */ ++ int mtu; ++ int nchan; /**< Data Channels */ ++ int has_2nd_bulk_in_ep; ++} dbus_attrib_t; ++ ++/* FIX: Account for errors related to DBUS; ++ * Let upper layer account for packets/bytes ++ */ ++typedef struct { ++ uint32 rx_errors; ++ uint32 tx_errors; ++ uint32 rx_dropped; ++ uint32 tx_dropped; ++} dbus_stats_t; ++ ++/** ++ * Configurable BUS parameters ++ */ ++enum { ++ DBUS_CONFIG_ID_RXCTL_DEFERRES = 1, ++ DBUS_CONFIG_ID_AGGR_LIMIT, ++ DBUS_CONFIG_ID_KEEPIF_ON_DEVRESET ++}; ++ ++typedef struct { ++ uint32 config_id; ++ union { ++ uint32 general_param; ++ bool rxctl_deferrespok; ++ struct { ++ int maxrxsf; ++ int maxrxsize; ++ int maxtxsf; ++ int maxtxsize; ++ } aggr_param; ++ }; ++} dbus_config_t; ++ ++/** ++ * External Download Info ++ */ ++typedef struct dbus_extdl { ++ uint8 *fw; ++ int fwlen; ++ uint8 *vars; ++ int varslen; ++} dbus_extdl_t; ++ ++struct dbus_callbacks; ++struct exec_parms; ++ ++typedef void *(*probe_cb_t)(void *arg, const char *desc, uint32 bustype, ++ uint16 bus_no, uint16 slot, uint32 hdrlen); ++typedef void (*disconnect_cb_t)(void *arg); ++typedef void *(*exec_cb_t)(struct exec_parms *args); ++ ++/** Client callbacks registered during dbus_attach() */ ++typedef struct dbus_callbacks { ++ void (*send_complete)(void *cbarg, void *info, int status); ++ void (*recv_buf)(void *cbarg, uint8 *buf, int len); ++ void (*recv_pkt)(void *cbarg, void *pkt); ++ void (*txflowcontrol)(void *cbarg, bool onoff); ++ void (*errhandler)(void *cbarg, int err); ++ void (*ctl_complete)(void *cbarg, int type, int status); ++ void (*state_change)(void *cbarg, int state); ++ void *(*pktget)(void *cbarg, uint len, bool send); ++ void (*pktfree)(void *cbarg, void *p, bool send); ++} dbus_callbacks_t; ++ ++struct dbus_pub; ++struct bcmstrbuf; ++struct dbus_irb; ++struct dbus_irb_rx; ++struct dbus_irb_tx; ++struct dbus_intf_callbacks; ++ ++typedef struct { ++ void* (*attach)(struct dbus_pub *pub, void *cbarg, struct dbus_intf_callbacks *cbs); ++ void (*detach)(struct dbus_pub *pub, void *bus); ++ ++ int (*up)(void *bus); ++ int (*down)(void *bus); ++ int (*send_irb)(void *bus, struct dbus_irb_tx *txirb); ++ int (*recv_irb)(void *bus, struct dbus_irb_rx *rxirb); ++ int (*cancel_irb)(void *bus, struct dbus_irb_tx *txirb); ++ int (*send_ctl)(void *bus, uint8 *buf, int len); ++ int (*recv_ctl)(void *bus, uint8 *buf, int len); ++ int (*get_stats)(void *bus, dbus_stats_t *stats); ++ int (*get_attrib)(void *bus, dbus_attrib_t *attrib); ++ ++ int (*pnp)(void *bus, int evnt); ++ int (*remove)(void *bus); ++ int (*resume)(void *bus); ++ int (*suspend)(void *bus); ++ int (*stop)(void *bus); ++ int (*reset)(void *bus); ++ ++ /* Access to bus buffers directly */ ++ void *(*pktget)(void *bus, int len); ++ void (*pktfree)(void *bus, void *pkt); ++ ++ int (*iovar_op)(void *bus, const char *name, void *params, int plen, void *arg, int len, ++ bool set); ++ void (*dump)(void *bus, struct bcmstrbuf *strbuf); ++ int (*set_config)(void *bus, dbus_config_t *config); ++ int (*get_config)(void *bus, dbus_config_t *config); ++ ++ bool (*device_exists)(void *bus); ++ int (*dlneeded)(void *bus); ++ int (*dlstart)(void *bus, uint8 *fw, int len); ++ int (*dlrun)(void *bus); ++ bool (*recv_needed)(void *bus); ++ ++ void *(*exec_rxlock)(void *bus, exec_cb_t func, struct exec_parms *args); ++ void *(*exec_txlock)(void *bus, exec_cb_t func, struct exec_parms *args); ++ ++ int (*tx_timer_init)(void *bus); ++ int (*tx_timer_start)(void *bus, uint timeout); ++ int (*tx_timer_stop)(void *bus); ++ ++ int (*sched_dpc)(void *bus); ++ int (*lock)(void *bus); ++ int (*unlock)(void *bus); ++ int (*sched_probe_cb)(void *bus); ++ ++ int (*shutdown)(void *bus); ++ ++ int (*recv_stop)(void *bus); ++ int (*recv_resume)(void *bus); ++ ++ int (*recv_irb_from_ep)(void *bus, struct dbus_irb_rx *rxirb, uint ep_idx); ++ ++ int (*readreg)(void *bus, uint32 regaddr, int datalen, uint32 *value); ++ ++ /* Add from the bottom */ ++} dbus_intf_t; ++ ++typedef struct dbus_pub { ++ struct osl_info *osh; ++ dbus_stats_t stats; ++ dbus_attrib_t attrib; ++ enum dbus_state busstate; ++ DEVICE_SPEED device_speed; ++ int ntxq, nrxq, rxsize; ++ void *bus; ++ struct shared_info *sh; ++ void *dev_info; ++} dbus_pub_t; ++ ++#define BUS_INFO(bus, type) (((type *) bus)->pub->bus) ++ ++#define ALIGNED_LOCAL_VARIABLE(var, align) \ ++ uint8 buffer[SDALIGN+64]; \ ++ uint8 *var = (uint8 *)(((uintptr)&buffer[0]) & ~(align-1)) + align; ++ ++/* ++ * Public Bus Function Interface ++ */ ++ ++/* ++ * FIX: Is there better way to pass OS/Host handles to DBUS but still ++ * maintain common interface for all OS?? ++ * Under NDIS, param1 needs to be MiniportHandle ++ * For NDIS60, param2 is WdfDevice ++ * Under Linux, param1 and param2 are NULL; ++ */ ++extern int dbus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, ++ void *param1, void *param2); ++extern int dbus_deregister(void); ++ ++//extern int dbus_download_firmware(dbus_pub_t *pub); ++//extern int dbus_up(struct dhd_bus *pub); ++extern int dbus_down(dbus_pub_t *pub); ++//extern int dbus_stop(struct dhd_bus *pub); ++extern int dbus_shutdown(dbus_pub_t *pub); ++extern void dbus_flowctrl_rx(dbus_pub_t *pub, bool on); ++ ++extern int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf); ++extern int dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info); ++extern int dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info); ++//extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len); ++//extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len); ++extern int dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx); ++extern int dbus_poll_intr(dbus_pub_t *pub); ++extern int dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats); ++extern int dbus_get_device_speed(dbus_pub_t *pub); ++extern int dbus_set_config(dbus_pub_t *pub, dbus_config_t *config); ++extern int dbus_get_config(dbus_pub_t *pub, dbus_config_t *config); ++extern void * dbus_get_devinfo(dbus_pub_t *pub); ++ ++extern void *dbus_pktget(dbus_pub_t *pub, int len); ++extern void dbus_pktfree(dbus_pub_t *pub, void* pkt); ++ ++extern int dbus_set_errmask(dbus_pub_t *pub, uint32 mask); ++extern int dbus_pnp_sleep(dbus_pub_t *pub); ++extern int dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload); ++extern int dbus_pnp_disconnect(dbus_pub_t *pub); ++ ++//extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, ++// void *params, int plen, void *arg, int len, bool set); ++ ++extern void *dhd_dbus_txq(const dbus_pub_t *pub); ++extern uint dhd_dbus_hdrlen(const dbus_pub_t *pub); ++ ++/* ++ * Private Common Bus Interface ++ */ ++ ++/** IO Request Block (IRB) */ ++typedef struct dbus_irb { ++ struct dbus_irb *next; /**< it's casted from dbus_irb_tx or dbus_irb_rx struct */ ++} dbus_irb_t; ++ ++typedef struct dbus_irb_rx { ++ struct dbus_irb irb; /* Must be first */ ++ uint8 *buf; ++ int buf_len; ++ int actual_len; ++ void *pkt; ++ void *info; ++ void *arg; ++} dbus_irb_rx_t; ++ ++typedef struct dbus_irb_tx { ++ struct dbus_irb irb; /** Must be first */ ++ uint8 *buf; /** mutually exclusive with struct member 'pkt' */ ++ int len; /** length of field 'buf' */ ++ void *pkt; /** mutually exclusive with struct member 'buf' */ ++ int retry_count; ++ void *info; ++ void *arg; ++ void *send_buf; /**< linear bufffer for LINUX when aggreagtion is enabled */ ++} dbus_irb_tx_t; ++ ++/** ++ * DBUS interface callbacks are different from user callbacks ++ * so, internally, different info can be passed to upper layer ++ */ ++typedef struct dbus_intf_callbacks { ++ void (*send_irb_timeout)(void *cbarg, dbus_irb_tx_t *txirb); ++ void (*send_irb_complete)(void *cbarg, dbus_irb_tx_t *txirb, int status); ++ void (*recv_irb_complete)(void *cbarg, dbus_irb_rx_t *rxirb, int status); ++ void (*errhandler)(void *cbarg, int err); ++ void (*ctl_complete)(void *cbarg, int type, int status); ++ void (*state_change)(void *cbarg, int state); ++ bool (*isr)(void *cbarg, bool *wantdpc); ++ bool (*dpc)(void *cbarg, bool bounded); ++ void (*watchdog)(void *cbarg); ++ void *(*pktget)(void *cbarg, uint len, bool send); ++ void (*pktfree)(void *cbarg, void *p, bool send); ++ struct dbus_irb* (*getirb)(void *cbarg, bool send); ++ void (*rxerr_indicate)(void *cbarg, bool on); ++} dbus_intf_callbacks_t; ++ ++/* ++ * Porting: To support new bus, port these functions below ++ */ ++ ++/* ++ * Bus specific Interface ++ * Implemented by dbus_usb.c/dbus_sdio.c ++ */ ++extern int dbus_bus_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, void *prarg, ++ dbus_intf_t **intf, void *param1, void *param2); ++extern int dbus_bus_deregister(void); ++extern void dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp); ++ ++/* ++ * Bus-specific and OS-specific Interface ++ * Implemented by dbus_usb_[linux/ndis].c/dbus_sdio_[linux/ndis].c ++ */ ++extern int dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, ++ void *prarg, dbus_intf_t **intf, void *param1, void *param2); ++extern int dbus_bus_osl_deregister(void); ++ ++/* ++ * Bus-specific, OS-specific, HW-specific Interface ++ * Mainly for SDIO Host HW controller ++ */ ++extern int dbus_bus_osl_hw_register(int vid, int pid, probe_cb_t prcb, disconnect_cb_t discb, ++ void *prarg, dbus_intf_t **intf); ++extern int dbus_bus_osl_hw_deregister(void); ++ ++extern uint usbdev_bulkin_eps(void); ++#if defined(BCM_REQUEST_FW) ++extern void *dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, ++ uint16 boardtype, uint16 boardrev); ++extern void dbus_release_fw_nvfile(void *firmware); ++#endif /* #if defined(BCM_REQUEST_FW) */ ++ ++ ++#if defined(EHCI_FASTPATH_TX) || defined(EHCI_FASTPATH_RX) ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++ /* Backward compatibility */ ++ typedef unsigned int gfp_t; ++ ++ #define dma_pool pci_pool ++ #define dma_pool_create(name, dev, size, align, alloc) \ ++ pci_pool_create(name, dev, size, align, alloc, GFP_DMA | GFP_ATOMIC) ++ #define dma_pool_destroy(pool) pci_pool_destroy(pool) ++ #define dma_pool_alloc(pool, flags, handle) pci_pool_alloc(pool, flags, handle) ++ #define dma_pool_free(pool, vaddr, addr) pci_pool_free(pool, vaddr, addr) ++ ++ #define dma_map_single(dev, addr, size, dir) pci_map_single(dev, addr, size, dir) ++ #define dma_unmap_single(dev, hnd, size, dir) pci_unmap_single(dev, hnd, size, dir) ++ #define DMA_FROM_DEVICE PCI_DMA_FROMDEVICE ++ #define DMA_TO_DEVICE PCI_DMA_TODEVICE ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ ++ ++/* Availability of these functions varies (when present, they have two arguments) */ ++#ifndef hc32_to_cpu ++ #define hc32_to_cpu(x) le32_to_cpu(x) ++ #define cpu_to_hc32(x) cpu_to_le32(x) ++ typedef unsigned int __hc32; ++#else ++ #error Two-argument functions needed ++#endif ++ ++/* Private USB opcode base */ ++#define EHCI_FASTPATH 0x31 ++#define EHCI_SET_EP_BYPASS EHCI_FASTPATH ++#define EHCI_SET_BYPASS_CB (EHCI_FASTPATH + 1) ++#define EHCI_SET_BYPASS_DEV (EHCI_FASTPATH + 2) ++#define EHCI_DUMP_STATE (EHCI_FASTPATH + 3) ++#define EHCI_SET_BYPASS_POOL (EHCI_FASTPATH + 4) ++#define EHCI_CLR_EP_BYPASS (EHCI_FASTPATH + 5) ++ ++/* ++ * EHCI QTD structure (hardware and extension) ++ * NOTE that is does not need to (and does not) match its kernel counterpart ++ */ ++#define EHCI_QTD_NBUFFERS 5 ++#define EHCI_QTD_ALIGN 32 ++#define EHCI_BULK_PACKET_SIZE 512 ++#define EHCI_QTD_XACTERR_MAX 32 ++ ++struct ehci_qtd { ++ /* Hardware map */ ++ volatile uint32_t qtd_next; ++ volatile uint32_t qtd_altnext; ++ volatile uint32_t qtd_status; ++#define EHCI_QTD_GET_BYTES(x) (((x)>>16) & 0x7fff) ++#define EHCI_QTD_IOC 0x00008000 ++#define EHCI_QTD_GET_CERR(x) (((x)>>10) & 0x3) ++#define EHCI_QTD_SET_CERR(x) ((x) << 10) ++#define EHCI_QTD_GET_PID(x) (((x)>>8) & 0x3) ++#define EHCI_QTD_SET_PID(x) ((x) << 8) ++#define EHCI_QTD_ACTIVE 0x80 ++#define EHCI_QTD_HALTED 0x40 ++#define EHCI_QTD_BUFERR 0x20 ++#define EHCI_QTD_BABBLE 0x10 ++#define EHCI_QTD_XACTERR 0x08 ++#define EHCI_QTD_MISSEDMICRO 0x04 ++ volatile uint32_t qtd_buffer[EHCI_QTD_NBUFFERS]; ++ volatile uint32_t qtd_buffer_hi[EHCI_QTD_NBUFFERS]; ++ ++ /* Implementation extension */ ++ dma_addr_t qtd_self; /**< own hardware address */ ++ struct ehci_qtd *obj_next; /**< software link to the next QTD */ ++ void *rpc; /**< pointer to the rpc buffer */ ++ size_t length; /**< length of the data in the buffer */ ++ void *buff; /**< pointer to the reassembly buffer */ ++ int xacterrs; /**< retry counter for qtd xact error */ ++} __attribute__ ((aligned(EHCI_QTD_ALIGN))); ++ ++#define EHCI_NULL __constant_cpu_to_le32(1) /* HW null pointer shall be odd */ ++ ++#define SHORT_READ_Q(token) (EHCI_QTD_GET_BYTES(token) != 0 && EHCI_QTD_GET_PID(token) == 1) ++ ++/** ++ * Queue Head ++ * NOTE This structure is slightly different from the one in the kernel; but needs to stay ++ * compatible. ++ */ ++struct ehci_qh { ++ /* Hardware map */ ++ volatile uint32_t qh_link; ++ volatile uint32_t qh_endp; ++ volatile uint32_t qh_endphub; ++ volatile uint32_t qh_curqtd; ++ ++ /* QTD overlay */ ++ volatile uint32_t ow_next; ++ volatile uint32_t ow_altnext; ++ volatile uint32_t ow_status; ++ volatile uint32_t ow_buffer [EHCI_QTD_NBUFFERS]; ++ volatile uint32_t ow_buffer_hi [EHCI_QTD_NBUFFERS]; ++ ++ /* Extension (should match the kernel layout) */ ++ dma_addr_t unused0; ++ void *unused1; ++ struct list_head unused2; ++ struct ehci_qtd *dummy; ++ struct ehci_qh *unused3; ++ ++ struct ehci_hcd *unused4; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++ struct kref unused5; ++ unsigned unused6; ++ ++ uint8_t unused7; ++ ++ /* periodic schedule info */ ++ uint8_t unused8; ++ uint8_t unused9; ++ uint8_t unused10; ++ uint16_t unused11; ++ uint16_t unused12; ++ uint16_t unused13; ++ struct usb_device *unused14; ++#else ++ unsigned unused5; ++ ++ u8 unused6; ++ ++ /* periodic schedule info */ ++ u8 unused7; ++ u8 unused8; ++ u8 unused9; ++ unsigned short unused10; ++ unsigned short unused11; ++#define NO_FRAME ((unsigned short)~0) ++#ifdef EHCI_QUIRK_FIX ++ struct usb_device *unused12; ++#endif /* EHCI_QUIRK_FIX */ ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ ++ struct ehci_qtd *first_qtd; ++ /* Link to the first QTD; this is an optimized equivalent of the qtd_list field */ ++ /* NOTE that ehci_qh in ehci.h shall reserve this word */ ++} __attribute__ ((aligned(EHCI_QTD_ALIGN))); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++/** The corresponding structure in the kernel is used to get the QH */ ++struct hcd_dev { /* usb_device.hcpriv points to this */ ++ struct list_head unused0; ++ struct list_head unused1; ++ ++ /* array of QH pointers */ ++ void *ep[32]; ++}; ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ ++ ++int optimize_qtd_fill_with_rpc(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd, void *rpc, ++ int token, int len); ++int optimize_qtd_fill_with_data(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd, void *data, ++ int token, int len); ++int optimize_submit_async(struct ehci_qtd *qtd, int epn); ++void inline optimize_ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma); ++struct ehci_qtd *optimize_ehci_qtd_alloc(gfp_t flags); ++void optimize_ehci_qtd_free(struct ehci_qtd *qtd); ++void optimize_submit_rx_request(const dbus_pub_t *pub, int epn, struct ehci_qtd *qtd_in, void *buf); ++#endif /* EHCI_FASTPATH_TX || EHCI_FASTPATH_RX */ ++ ++void dbus_flowctrl_tx(void *dbi, bool on); ++#endif /* __DBUS_H__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/dhd_daemon.h b/module_drivers/drivers/net/wireless/bcmdhd/include/dhd_daemon.h +new file mode 100644 +index 000000000..3a5141ab2 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/dhd_daemon.h +@@ -0,0 +1,62 @@ ++/* ++ * Header file for DHD daemon to handle timeouts ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhd_daemon.h 671464 2016-11-22 06:15:32Z $ ++ */ ++ ++#ifndef __BCM_DHDD_H__ ++#define __BCM_DHDD_H__ ++ ++/** ++ * To maintain compatabily when dhd driver and dhd daemon is taken from different branches, ++ * make sure to keep this file same across dhd driver branch and dhd apps branch. ++ * TODO: Make this file as shared between apps and dhd.ko ++ */ ++ ++#define BCM_TO_MAGIC 0x600DB055 ++#define NO_TRAP 0 ++#define DO_TRAP 1 ++ ++#define BCM_NL_USER 31 ++ ++typedef enum notify_dhd_daemon_reason { ++ REASON_COMMAND_TO, ++ REASON_OQS_TO, ++ REASON_SCAN_TO, ++ REASON_JOIN_TO, ++ REASON_DAEMON_STARTED, ++ REASON_DEVICE_TX_STUCK_WARNING, ++ REASON_DEVICE_TX_STUCK, ++ REASON_UNKOWN ++} notify_dhd_daemon_reason_t; ++ ++typedef struct bcm_to_info { ++ int magic; ++ int reason; ++ int trap; ++} bcm_to_info_t; ++ ++#endif /* __BCM_DHDD_H__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/module_drivers/drivers/net/wireless/bcmdhd/include/dhdioctl.h +new file mode 100644 +index 000000000..dd32fdb55 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/dhdioctl.h +@@ -0,0 +1,159 @@ ++/* ++ * Definitions for ioctls to access DHD iovars. ++ * Based on wlioctl.h (for Broadcom 802.11abg driver). ++ * (Moves towards generic ioctls for BCM drivers/iovars.) ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: dhdioctl.h 675190 2016-12-14 15:27:52Z $ ++ */ ++ ++#ifndef _dhdioctl_h_ ++#define _dhdioctl_h_ ++ ++#include ++ ++ ++/* Linux network driver ioctl encoding */ ++typedef struct dhd_ioctl { ++ uint32 cmd; /* common ioctl definition */ ++ void *buf; /* pointer to user buffer */ ++ uint32 len; /* length of user buffer */ ++ uint32 set; /* get or set request boolean (optional) */ ++ uint32 used; /* bytes read or written (optional) */ ++ uint32 needed; /* bytes needed (optional) */ ++ uint32 driver; /* to identify target driver */ ++} dhd_ioctl_t; ++ ++/* Underlying BUS definition */ ++enum { ++ BUS_TYPE_USB = 0, /* for USB dongles */ ++ BUS_TYPE_SDIO, /* for SDIO dongles */ ++ BUS_TYPE_PCIE /* for PCIE dongles */ ++}; ++ ++ ++/* per-driver magic numbers */ ++#define DHD_IOCTL_MAGIC 0x00444944 ++ ++/* bump this number if you change the ioctl interface */ ++#define DHD_IOCTL_VERSION 1 ++ ++/* ++ * Increase the DHD_IOCTL_MAXLEN to 16K for supporting download of NVRAM files of size ++ * > 8K. In the existing implementation when NVRAM is to be downloaded via the "vars" ++ * DHD IOVAR, the NVRAM is copied to the DHD Driver memory. Later on when "dwnldstate" is ++ * invoked with FALSE option, the NVRAM gets copied from the DHD driver to the Dongle ++ * memory. The simple way to support this feature without modifying the DHD application, ++ * driver logic is to increase the DHD_IOCTL_MAXLEN size. This macro defines the "size" ++ * of the buffer in which data is exchanged between the DHD App and DHD driver. ++ */ ++#define DHD_IOCTL_MAXLEN (16384) /* max length ioctl buffer required */ ++#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ ++ ++/* common ioctl definitions */ ++#define DHD_GET_MAGIC 0 ++#define DHD_GET_VERSION 1 ++#define DHD_GET_VAR 2 ++#define DHD_SET_VAR 3 ++ ++/* message levels */ ++#define DHD_ERROR_VAL 0x0001 ++#define DHD_TRACE_VAL 0x0002 ++#define DHD_INFO_VAL 0x0004 ++#define DHD_DATA_VAL 0x0008 ++#define DHD_CTL_VAL 0x0010 ++#define DHD_TIMER_VAL 0x0020 ++#define DHD_HDRS_VAL 0x0040 ++#define DHD_BYTES_VAL 0x0080 ++#define DHD_INTR_VAL 0x0100 ++#define DHD_LOG_VAL 0x0200 ++#define DHD_GLOM_VAL 0x0400 ++#define DHD_EVENT_VAL 0x0800 ++#define DHD_BTA_VAL 0x1000 ++#define DHD_ISCAN_VAL 0x2000 ++#define DHD_ARPOE_VAL 0x4000 ++#define DHD_REORDER_VAL 0x8000 ++#define DHD_NOCHECKDIED_VAL 0x20000 /* UTF WAR */ ++#define DHD_PNO_VAL 0x80000 ++#define DHD_RTT_VAL 0x100000 ++#define DHD_MSGTRACE_VAL 0x200000 ++#define DHD_FWLOG_VAL 0x400000 ++#define DHD_DBGIF_VAL 0x800000 ++#ifdef DHD_PCIE_NATIVE_RUNTIMEPM ++#define DHD_RPM_VAL 0x1000000 ++#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */ ++#define DHD_PKT_MON_VAL 0x2000000 ++#define DHD_PKT_MON_DUMP_VAL 0x4000000 ++#define DHD_ERROR_MEM_VAL 0x8000000 ++#define DHD_ANDROID_VAL 0x10000 ++#define DHD_IW_VAL 0x20000 ++#define DHD_CFG_VAL 0x40000 ++#define DHD_CONFIG_VAL 0x80000 ++#define DUMP_EAPOL_VAL 0x0001 ++#define DUMP_ARP_VAL 0x0002 ++#define DUMP_DHCP_VAL 0x0004 ++#define DUMP_ICMP_VAL 0x0008 ++#define DUMP_DNS_VAL 0x0010 ++#define DUMP_TRX_VAL 0x0080 ++ ++#ifdef SDTEST ++/* For pktgen iovar */ ++typedef struct dhd_pktgen { ++ uint32 version; /* To allow structure change tracking */ ++ uint32 freq; /* Max ticks between tx/rx attempts */ ++ uint32 count; /* Test packets to send/rcv each attempt */ ++ uint32 print; /* Print counts every attempts */ ++ uint32 total; /* Total packets (or bursts) */ ++ uint32 minlen; /* Minimum length of packets to send */ ++ uint32 maxlen; /* Maximum length of packets to send */ ++ uint32 numsent; /* Count of test packets sent */ ++ uint32 numrcvd; /* Count of test packets received */ ++ uint32 numfail; /* Count of test send failures */ ++ uint32 mode; /* Test mode (type of test packets) */ ++ uint32 stop; /* Stop after this many tx failures */ ++} dhd_pktgen_t; ++ ++/* Version in case structure changes */ ++#define DHD_PKTGEN_VERSION 2 ++ ++/* Type of test packets to use */ ++#define DHD_PKTGEN_ECHO 1 /* Send echo requests */ ++#define DHD_PKTGEN_SEND 2 /* Send discard packets */ ++#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */ ++#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */ ++#endif /* SDTEST */ ++ ++/* Enter idle immediately (no timeout) */ ++#define DHD_IDLE_IMMEDIATE (-1) ++ ++/* Values for idleclock iovar: other values are the sd_divisor to use when idle */ ++#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */ ++#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */ ++ ++ ++ ++#endif /* _dhdioctl_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/dnglevent.h b/module_drivers/drivers/net/wireless/bcmdhd/include/dnglevent.h +new file mode 100644 +index 000000000..40a0047a6 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/dnglevent.h +@@ -0,0 +1,120 @@ ++/* ++ * Broadcom Event protocol definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * Dependencies: bcmeth.h ++ * ++ * $Id: dnglevent.h $ ++ * ++ * <> ++ * ++ * ----------------------------------------------------------------------------- ++ * ++ */ ++ ++/* ++ * Broadcom dngl Ethernet Events protocol defines ++ * ++ */ ++ ++#ifndef _DNGLEVENT_H_ ++#define _DNGLEVENT_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++#include ++#include ++ ++/* This marks the start of a packed structure section. */ ++#include ++#define BCM_DNGL_EVENT_MSG_VERSION 1 ++#define DNGL_E_RSRVD_1 0x0 ++#define DNGL_E_RSRVD_2 0x1 ++#define DNGL_E_SOCRAM_IND 0x2 ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint16 version; /* Current version is 1 */ ++ uint16 reserved; /* reserved for any future extension */ ++ uint16 event_type; /* DNGL_E_SOCRAM_IND */ ++ uint16 datalen; /* Length of the event payload */ ++} BWL_POST_PACKED_STRUCT bcm_dngl_event_msg_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_event { ++ struct ether_header eth; ++ bcmeth_hdr_t bcm_hdr; ++ bcm_dngl_event_msg_t dngl_event; ++ /* data portion follows */ ++} BWL_POST_PACKED_STRUCT bcm_dngl_event_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_socramind { ++ uint16 tag; /* data tag */ ++ uint16 length; /* data length */ ++ uint8 value[1]; /* data value with variable length specified by length */ ++} BWL_POST_PACKED_STRUCT bcm_dngl_socramind_t; ++ ++/* SOCRAM_IND type tags */ ++#define SOCRAM_IND_ASSERT_TAG 0x1 ++#define SOCRAM_IND_TAG_HEALTH_CHECK 0x2 ++/* Health check top level module tags */ ++typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_healthcheck { ++ uint16 top_module_tag; /* top level module tag */ ++ uint16 top_module_len; /* Type of PCIE issue indication */ ++ uint8 value[1]; /* data value with variable length specified by length */ ++} BWL_POST_PACKED_STRUCT bcm_dngl_healthcheck_t; ++ ++/* Health check top level module tags */ ++#define HEALTH_CHECK_TOP_LEVEL_MODULE_PCIEDEV_RTE 1 ++#define HEALTH_CHECK_PCIEDEV_VERSION_1 1 ++#define HEALTH_CHECK_PCIEDEV_FLAG_IN_D3_SHIFT 0 ++#define HEALTH_CHECK_PCIEDEV_FLAG_AER_SHIFT 1 ++#define HEALTH_CHECK_PCIEDEV_FLAG_LINKDOWN_SHIFT 2 ++#define HEALTH_CHECK_PCIEDEV_FLAG_MSI_INT_SHIFT 3 ++#define HEALTH_CHECK_PCIEDEV_FLAG_NODS_SHIFT 4 ++#define HEALTH_CHECK_PCIEDEV_FLAG_IN_D3 1 << HEALTH_CHECK_PCIEDEV_FLAG_IN_D3_SHIFT ++#define HEALTH_CHECK_PCIEDEV_FLAG_AER 1 << HEALTH_CHECK_PCIEDEV_FLAG_AER_SHIFT ++#define HEALTH_CHECK_PCIEDEV_FLAG_LINKDOWN 1 << HEALTH_CHECK_PCIEDEV_FLAG_LINKDOWN_SHIFT ++#define HEALTH_CHECK_PCIEDEV_FLAG_MSI_INT 1 << HEALTH_CHECK_PCIEDEV_FLAG_MSI_INT_SHIFT ++#define HEALTH_CHECK_PCIEDEV_FLAG_NODS 1 << HEALTH_CHECK_PCIEDEV_FLAG_NODS_SHIFT ++/* PCIE Module TAGs */ ++#define HEALTH_CHECK_PCIEDEV_INDUCED_IND 0x1 ++#define HEALTH_CHECK_PCIEDEV_H2D_DMA_IND 0x2 ++#define HEALTH_CHECK_PCIEDEV_D2H_DMA_IND 0x3 ++#define HEALTH_CHECK_PCIEDEV_IOCTL_STALL_IND 0x4 ++#define HEALTH_CHECK_PCIEDEV_D3ACK_STALL_IND 0x5 ++#define HEALTH_CHECK_PCIEDEV_NODS_IND 0x6 ++#define HEALTH_CHECK_PCIEDEV_LINKSPEED_FALLBACK_IND 0x7 ++ ++#define HC_PCIEDEV_CONFIG_REGLIST_MAX 20 ++typedef BWL_PRE_PACKED_STRUCT struct bcm_dngl_pcie_hc { ++ uint16 version; /* HEALTH_CHECK_PCIEDEV_VERSION_1 */ ++ uint16 reserved; ++ uint16 pcie_err_ind_type; /* PCIE Module TAGs */ ++ uint16 pcie_flag; ++ uint32 pcie_control_reg; ++ uint32 pcie_config_regs[HC_PCIEDEV_CONFIG_REGLIST_MAX]; ++} BWL_POST_PACKED_STRUCT bcm_dngl_pcie_hc_t; ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _DNGLEVENT_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/eapol.h b/module_drivers/drivers/net/wireless/bcmdhd/include/eapol.h +new file mode 100644 +index 000000000..ef917abc0 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/eapol.h +@@ -0,0 +1,218 @@ ++/* ++ * 802.1x EAPOL definitions ++ * ++ * See ++ * IEEE Std 802.1X-2001 ++ * IEEE 802.1X RADIUS Usage Guidelines ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: eapol.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _eapol_h_ ++#define _eapol_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#if !defined(BCMCRYPTO_COMPONENT) ++#include ++#endif /* !BCMCRYPTO_COMPONENT */ ++ ++/* EAPOL for 802.3/Ethernet */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ struct ether_header eth; /* 802.3/Ethernet header */ ++ unsigned char version; /* EAPOL protocol version */ ++ unsigned char type; /* EAPOL type */ ++ unsigned short length; /* Length of body */ ++ unsigned char body[1]; /* Body (optional) */ ++} BWL_POST_PACKED_STRUCT eapol_header_t; ++ ++#define EAPOL_HEADER_LEN 18 ++ ++typedef struct { ++ unsigned char version; /* EAPOL protocol version */ ++ unsigned char type; /* EAPOL type */ ++ unsigned short length; /* Length of body */ ++} eapol_hdr_t; ++ ++#define EAPOL_HDR_LEN 4 ++ ++/* EAPOL version */ ++#define WPA2_EAPOL_VERSION 2 ++#define WPA_EAPOL_VERSION 1 ++#define LEAP_EAPOL_VERSION 1 ++#define SES_EAPOL_VERSION 1 ++ ++/* EAPOL types */ ++#define EAP_PACKET 0 ++#define EAPOL_START 1 ++#define EAPOL_LOGOFF 2 ++#define EAPOL_KEY 3 ++#define EAPOL_ASF 4 ++ ++/* EAPOL-Key types */ ++#define EAPOL_RC4_KEY 1 ++#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */ ++#define EAPOL_WPA_KEY 254 /* WPA */ ++ ++/* RC4 EAPOL-Key header field sizes */ ++#define EAPOL_KEY_REPLAY_LEN 8 ++#define EAPOL_KEY_IV_LEN 16 ++#define EAPOL_KEY_SIG_LEN 16 ++ ++/* RC4 EAPOL-Key */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ unsigned char type; /* Key Descriptor Type */ ++ unsigned short length; /* Key Length (unaligned) */ ++ unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ ++ unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ ++ unsigned char index; /* Key Flags & Index */ ++ unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ ++ unsigned char key[1]; /* Key (optional) */ ++} BWL_POST_PACKED_STRUCT eapol_key_header_t; ++ ++#define EAPOL_KEY_HEADER_LEN 44 ++ ++/* RC4 EAPOL-Key flags */ ++#define EAPOL_KEY_FLAGS_MASK 0x80 ++#define EAPOL_KEY_BROADCAST 0 ++#define EAPOL_KEY_UNICAST 0x80 ++ ++/* RC4 EAPOL-Key index */ ++#define EAPOL_KEY_INDEX_MASK 0x7f ++ ++/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */ ++#define EAPOL_AKW_BLOCK_LEN 8 ++#define EAPOL_WPA_KEY_REPLAY_LEN 8 ++#define EAPOL_WPA_KEY_NONCE_LEN 32 ++#define EAPOL_WPA_KEY_IV_LEN 16 ++#define EAPOL_WPA_KEY_RSC_LEN 8 ++#define EAPOL_WPA_KEY_ID_LEN 8 ++#define EAPOL_WPA_KEY_MIC_LEN 16 ++#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + EAPOL_AKW_BLOCK_LEN) ++#define EAPOL_WPA_MAX_KEY_SIZE 32 ++ ++/* WPA EAPOL-Key */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ unsigned char type; /* Key Descriptor Type */ ++ unsigned short key_info; /* Key Information (unaligned) */ ++ unsigned short key_len; /* Key Length (unaligned) */ ++ unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */ ++ unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */ ++ unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */ ++ unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */ ++ unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */ ++ unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */ ++ unsigned short data_len; /* Key Data Length */ ++ unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */ ++} BWL_POST_PACKED_STRUCT eapol_wpa_key_header_t; ++ ++#define EAPOL_WPA_KEY_LEN 95 ++ ++/* WPA/802.11i/WPA2 KEY KEY_INFO bits */ ++#define WPA_KEY_DESC_OSEN 0x0 ++#define WPA_KEY_DESC_V1 0x01 ++#define WPA_KEY_DESC_V2 0x02 ++#define WPA_KEY_DESC_V3 0x03 ++#define WPA_KEY_PAIRWISE 0x08 ++#define WPA_KEY_INSTALL 0x40 ++#define WPA_KEY_ACK 0x80 ++#define WPA_KEY_MIC 0x100 ++#define WPA_KEY_SECURE 0x200 ++#define WPA_KEY_ERROR 0x400 ++#define WPA_KEY_REQ 0x800 ++ ++#define WPA_KEY_DESC_V2_OR_V3 WPA_KEY_DESC_V2 ++ ++/* WPA-only KEY KEY_INFO bits */ ++#define WPA_KEY_INDEX_0 0x00 ++#define WPA_KEY_INDEX_1 0x10 ++#define WPA_KEY_INDEX_2 0x20 ++#define WPA_KEY_INDEX_3 0x30 ++#define WPA_KEY_INDEX_MASK 0x30 ++#define WPA_KEY_INDEX_SHIFT 0x04 ++ ++/* 802.11i/WPA2-only KEY KEY_INFO bits */ ++#define WPA_KEY_ENCRYPTED_DATA 0x1000 ++ ++/* Key Data encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 type; ++ uint8 length; ++ uint8 oui[3]; ++ uint8 subtype; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t; ++ ++#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 ++ ++#define WPA2_KEY_DATA_SUBTYPE_GTK 1 ++#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 ++#define WPA2_KEY_DATA_SUBTYPE_MAC 3 ++#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 ++#define WPA2_KEY_DATA_SUBTYPE_IGTK 9 ++ ++/* GTK encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 flags; ++ uint8 reserved; ++ uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t; ++ ++#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 ++ ++#define WPA2_GTK_INDEX_MASK 0x03 ++#define WPA2_GTK_INDEX_SHIFT 0x00 ++ ++#define WPA2_GTK_TRANSMIT 0x04 ++ ++/* IGTK encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint16 key_id; ++ uint8 ipn[6]; ++ uint8 key[EAPOL_WPA_MAX_KEY_SIZE]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_key_igtk_encap_t; ++ ++#define EAPOL_WPA2_KEY_IGTK_ENCAP_HDR_LEN 8 ++ ++/* STAKey encapsulation */ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 reserved[2]; ++ uint8 mac[ETHER_ADDR_LEN]; ++ uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE]; ++} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t; ++ ++#define WPA2_KEY_DATA_PAD 0xdd ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _eapol_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/epivers.h b/module_drivers/drivers/net/wireless/bcmdhd/include/epivers.h +new file mode 100644 +index 000000000..c90d5adb4 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/epivers.h +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: epivers.h.in 596126 2015-10-29 19:53:48Z $ ++ * ++*/ ++ ++#ifndef _epivers_h_ ++#define _epivers_h_ ++ ++#define EPI_MAJOR_VERSION 1 ++ ++#define EPI_MINOR_VERSION 579 ++ ++#define EPI_RC_NUMBER 77 ++ ++#define EPI_INCREMENTAL_NUMBER 41 ++ ++#define EPI_BUILD_NUMBER 0 ++ ++#define EPI_VERSION 1, 579, 77, 41 ++ ++#define EPI_VERSION_NUM 0x012434d29 ++ ++#define EPI_VERSION_DEV 1.579.77.41 ++ ++/* Driver Version String, ASCII, 32 chars max */ ++#define EPI_VERSION_STR "1.579.77.41.26 (r-20200429-2)" ++ ++#endif /* _epivers_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/ethernet.h b/module_drivers/drivers/net/wireless/bcmdhd/include/ethernet.h +new file mode 100644 +index 000000000..2e338676a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/ethernet.h +@@ -0,0 +1,227 @@ ++/* ++ * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: ethernet.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */ ++#define _NET_ETHERNET_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include "typedefs.h" ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* ++ * The number of bytes in an ethernet (MAC) address. ++ */ ++#define ETHER_ADDR_LEN 6 ++ ++/* ++ * The number of bytes in the type field. ++ */ ++#define ETHER_TYPE_LEN 2 ++ ++/* ++ * The number of bytes in the trailing CRC field. ++ */ ++#define ETHER_CRC_LEN 4 ++ ++/* ++ * The length of the combined header. ++ */ ++#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) ++ ++/* ++ * The minimum packet length. ++ */ ++#define ETHER_MIN_LEN 64 ++ ++/* ++ * The minimum packet user data length. ++ */ ++#define ETHER_MIN_DATA 46 ++ ++/* ++ * The maximum packet length. ++ */ ++#define ETHER_MAX_LEN 1518 ++ ++/* ++ * The maximum packet user data length. ++ */ ++#define ETHER_MAX_DATA 1500 ++ ++/* ether types */ ++#define ETHER_TYPE_MIN 0x0600 /* Anything less than MIN is a length */ ++#define ETHER_TYPE_IP 0x0800 /* IP */ ++#define ETHER_TYPE_ARP 0x0806 /* ARP */ ++#define ETHER_TYPE_8021Q 0x8100 /* 802.1Q */ ++#define ETHER_TYPE_IPV6 0x86dd /* IPv6 */ ++#define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */ ++#define ETHER_TYPE_802_1X 0x888e /* 802.1x */ ++#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 /* 802.1x preauthentication */ ++#define ETHER_TYPE_WAI 0x88b4 /* WAI */ ++#define ETHER_TYPE_89_0D 0x890d /* 89-0d frame for TDLS */ ++#define ETHER_TYPE_RRB ETHER_TYPE_89_0D /* RRB 802.11r 2008 */ ++ ++#define ETHER_TYPE_PPP_SES 0x8864 /* PPPoE Session */ ++ ++#define ETHER_TYPE_IAPP_L2_UPDATE 0x6 /* IAPP L2 update frame */ ++ ++/* Broadcom subtype follows ethertype; First 2 bytes are reserved; Next 2 are subtype; */ ++#define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4 byte subtype */ ++ ++/* ether header */ ++#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) /* dest address offset */ ++#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) /* src address offset */ ++#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) /* ether type offset */ ++ ++/* ++ * A macro to validate a length with ++ */ ++#define ETHER_IS_VALID_LEN(foo) \ ++ ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) ++ ++#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \ ++ ((uint8 *)ea)[0] = 0x01; \ ++ ((uint8 *)ea)[1] = 0x00; \ ++ ((uint8 *)ea)[2] = 0x5e; \ ++ ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \ ++ ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \ ++ ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \ ++} ++ ++#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */ ++/* ++ * Structure of a 10Mb/s Ethernet header. ++ */ ++BWL_PRE_PACKED_STRUCT struct ether_header { ++ uint8 ether_dhost[ETHER_ADDR_LEN]; ++ uint8 ether_shost[ETHER_ADDR_LEN]; ++ uint16 ether_type; ++} BWL_POST_PACKED_STRUCT; ++ ++/* ++ * Structure of a 48-bit Ethernet address. ++ */ ++BWL_PRE_PACKED_STRUCT struct ether_addr { ++ uint8 octet[ETHER_ADDR_LEN]; ++} BWL_POST_PACKED_STRUCT; ++#endif /* !__INCif_etherh Quick and ugly hack for VxWorks */ ++ ++/* ++ * Takes a pointer, set, test, clear, toggle locally admininistered ++ * address bit in the 48-bit Ethernet address. ++ */ ++#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) ++#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) ++#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xfd)) ++#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) ++ ++/* Takes a pointer, marks unicast address bit in the MAC address */ ++#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) ++ ++/* ++ * Takes a pointer, returns true if a 48-bit multicast address ++ * (including broadcast, since it is all ones) ++ */ ++#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) ++ ++ ++/* compare two ethernet addresses - assumes the pointers can be referenced as shorts */ ++#define eacmp(a, b) ((((const uint16 *)(a))[0] ^ ((const uint16 *)(b))[0]) | \ ++ (((const uint16 *)(a))[1] ^ ((const uint16 *)(b))[1]) | \ ++ (((const uint16 *)(a))[2] ^ ((const uint16 *)(b))[2])) ++ ++#define ether_cmp(a, b) eacmp(a, b) ++ ++/* copy an ethernet address - assumes the pointers can be referenced as shorts */ ++#define eacopy(s, d) \ ++do { \ ++ ((uint16 *)(d))[0] = ((const uint16 *)(s))[0]; \ ++ ((uint16 *)(d))[1] = ((const uint16 *)(s))[1]; \ ++ ((uint16 *)(d))[2] = ((const uint16 *)(s))[2]; \ ++} while (0) ++ ++#define ether_copy(s, d) eacopy(s, d) ++ ++/* Copy an ethernet address in reverse order */ ++#define ether_rcopy(s, d) \ ++do { \ ++ ((uint16 *)(d))[2] = ((uint16 *)(s))[2]; \ ++ ((uint16 *)(d))[1] = ((uint16 *)(s))[1]; \ ++ ((uint16 *)(d))[0] = ((uint16 *)(s))[0]; \ ++} while (0) ++ ++/* Copy 14B ethernet header: 32bit aligned source and destination. */ ++#define ehcopy32(s, d) \ ++do { \ ++ ((uint32 *)(d))[0] = ((const uint32 *)(s))[0]; \ ++ ((uint32 *)(d))[1] = ((const uint32 *)(s))[1]; \ ++ ((uint32 *)(d))[2] = ((const uint32 *)(s))[2]; \ ++ ((uint16 *)(d))[6] = ((const uint16 *)(s))[6]; \ ++} while (0) ++ ++ ++static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; ++static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; ++static const struct ether_addr ether_ipv6_mcast = {{0x33, 0x33, 0x00, 0x00, 0x00, 0x01}}; ++ ++#define ETHER_ISBCAST(ea) ((((const uint8 *)(ea))[0] & \ ++ ((const uint8 *)(ea))[1] & \ ++ ((const uint8 *)(ea))[2] & \ ++ ((const uint8 *)(ea))[3] & \ ++ ((const uint8 *)(ea))[4] & \ ++ ((const uint8 *)(ea))[5]) == 0xff) ++#define ETHER_ISNULLADDR(ea) ((((const uint8 *)(ea))[0] | \ ++ ((const uint8 *)(ea))[1] | \ ++ ((const uint8 *)(ea))[2] | \ ++ ((const uint8 *)(ea))[3] | \ ++ ((const uint8 *)(ea))[4] | \ ++ ((const uint8 *)(ea))[5]) == 0) ++ ++#define ETHER_ISNULLDEST(da) ((((const uint16 *)(da))[0] | \ ++ ((const uint16 *)(da))[1] | \ ++ ((const uint16 *)(da))[2]) == 0) ++#define ETHER_ISNULLSRC(sa) ETHER_ISNULLDEST(sa) ++ ++#define ETHER_MOVE_HDR(d, s) \ ++do { \ ++ struct ether_header t; \ ++ t = *(struct ether_header *)(s); \ ++ *(struct ether_header *)(d) = t; \ ++} while (0) ++ ++#define ETHER_ISUCAST(ea) ((((uint8 *)(ea))[0] & 0x01) == 0) ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _NET_ETHERNET_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/event_log.h b/module_drivers/drivers/net/wireless/bcmdhd/include/event_log.h +new file mode 100644 +index 000000000..0c2120e19 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/event_log.h +@@ -0,0 +1,388 @@ ++/* ++ * EVENT_LOG system definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: event_log.h 711908 2017-07-20 10:37:34Z $ ++ */ ++ ++#ifndef _EVENT_LOG_H_ ++#define _EVENT_LOG_H_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* logstrs header */ ++#define LOGSTRS_MAGIC 0x4C4F4753 ++#define LOGSTRS_VERSION 0x1 ++ ++/* We make sure that the block size will fit in a single packet ++ * (allowing for a bit of overhead on each packet ++ */ ++#define EVENT_LOG_MAX_BLOCK_SIZE 1400 ++#define EVENT_LOG_WL_BLOCK_SIZE 0x200 ++#define EVENT_LOG_PSM_BLOCK_SIZE 0x200 ++#define EVENT_LOG_BUS_BLOCK_SIZE 0x200 ++#define EVENT_LOG_ERROR_BLOCK_SIZE 0x200 ++/* Maximum event log record payload size = 1024 bytes or 256 words. */ ++#define EVENT_LOG_MAX_RECORD_PAYLOAD_SIZE 256 ++ ++/* ++ * There are multiple levels of objects define here: ++ * event_log_set - a set of buffers ++ * event log groups - every event log call is part of just one. All ++ * event log calls in a group are handled the ++ * same way. Each event log group is associated ++ * with an event log set or is off. ++ */ ++ ++#ifndef __ASSEMBLER__ ++ ++/* On the external system where the dumper is we need to make sure ++ * that these types are the same size as they are on the ARM the ++ * produced them ++ */ ++#ifdef EVENT_LOG_DUMPER ++#define _EL_BLOCK_PTR uint32 ++#define _EL_TYPE_PTR uint32 ++#define _EL_SET_PTR uint32 ++#define _EL_TOP_PTR uint32 ++#else ++#define _EL_BLOCK_PTR struct event_log_block * ++#define _EL_TYPE_PTR uint32 * ++#define _EL_SET_PTR struct event_log_set ** ++#define _EL_TOP_PTR struct event_log_top * ++#endif /* EVENT_LOG_DUMPER */ ++ ++/* Event log sets (a logical circurlar buffer) consist of one or more ++ * event_log_blocks. The blocks themselves form a logical circular ++ * list. The log entries are placed in each event_log_block until it ++ * is full. Logging continues with the next event_log_block in the ++ * event_set until the last event_log_block is reached and then ++ * logging starts over with the first event_log_block in the ++ * event_set. ++ */ ++typedef struct event_log_block { ++ _EL_BLOCK_PTR next_block; ++ _EL_BLOCK_PTR prev_block; ++ _EL_TYPE_PTR end_ptr; ++ ++ /* Start of packet sent for log tracing */ ++ uint16 pktlen; /* Size of rest of block */ ++ uint16 count; /* Logtrace counter */ ++ uint32 extra_hdr_info; /* LSB: 6 bits set id. MSB 24 bits reserved */ ++ uint32 event_logs; ++} event_log_block_t; ++#define EVENT_LOG_BLOCK_HDRLEN 8 /* pktlen 2 + count 2 + extra_hdr_info 4 */ ++#define NAN_EVENT_LOG_MIN_LENGTH 2 /* Minimum length of Nan event */ ++ ++typedef enum { ++ SET_DESTINATION_INVALID = -1, ++ SET_DESTINATION_HOST = 0, ++ SET_DESTINATION_NONE = 1, ++ SET_DESTINATION_MAX ++} event_log_set_destination_t; ++ ++/* There can be multiple event_sets with each logging a set of ++ * associated events (i.e, "fast" and "slow" events). ++ */ ++typedef struct event_log_set { ++ _EL_BLOCK_PTR first_block; /* Pointer to first event_log block */ ++ _EL_BLOCK_PTR last_block; /* Pointer to last event_log block */ ++ _EL_BLOCK_PTR logtrace_block; /* next block traced */ ++ _EL_BLOCK_PTR cur_block; /* Pointer to current event_log block */ ++ _EL_TYPE_PTR cur_ptr; /* Current event_log pointer */ ++ uint32 blockcount; /* Number of blocks */ ++ uint16 logtrace_count; /* Last count for logtrace */ ++ uint16 blockfill_count; /* Fill count for logtrace */ ++ uint32 timestamp; /* Last timestamp event */ ++ uint32 cyclecount; /* Cycles at last timestamp event */ ++ event_log_set_destination_t destination; ++ uint16 size; /* same size for all buffers in one set */ ++} event_log_set_t; ++ ++/* Top data structure for access to everything else */ ++typedef struct event_log_top { ++ uint32 magic; ++#define EVENT_LOG_TOP_MAGIC 0x474C8669 /* 'EVLG' */ ++ uint32 version; ++#define EVENT_LOG_VERSION 1 ++ uint32 num_sets; ++ uint32 logstrs_size; /* Size of lognums + logstrs area */ ++ uint32 timestamp; /* Last timestamp event */ ++ uint32 cyclecount; /* Cycles at last timestamp event */ ++ _EL_SET_PTR sets; /* Ptr to array of set ptrs */ ++} event_log_top_t; ++ ++/* Data structure of Keeping the Header from logstrs.bin */ ++typedef struct { ++ uint32 logstrs_size; /* Size of the file */ ++ uint32 rom_lognums_offset; /* Offset to the ROM lognum */ ++ uint32 ram_lognums_offset; /* Offset to the RAM lognum */ ++ uint32 rom_logstrs_offset; /* Offset to the ROM logstr */ ++ uint32 ram_logstrs_offset; /* Offset to the RAM logstr */ ++ /* Keep version and magic last since "header" is appended to the end of logstrs file. */ ++ uint32 version; /* Header version */ ++ uint32 log_magic; /* MAGIC number for verification 'LOGS' */ ++} logstr_header_t; ++ ++/* ++ * Use the following macros for generating log events. ++ * ++ * The FAST versions check the enable of the tag before evaluating the arguments and calling the ++ * event_log function. This adds 5 instructions. The COMPACT versions evaluate the arguments ++ * and call the event_log function unconditionally. The event_log function will then skip logging ++ * if this tag is disabled. ++ * ++ * To support easy usage of existing debugging (e.g. msglevel) via macro re-definition there are ++ * two variants of these macros to help. ++ * ++ * First there are the CAST versions. The event_log function normally logs uint32 values or else ++ * they have to be cast to uint32. The CAST versions blindly cast for you so you don't have to edit ++ * any existing code. ++ * ++ * Second there are the PAREN_ARGS versions. These expect the logging format string and arguments ++ * to be enclosed in parentheses. This allows us to make the following mapping of an existing ++ * msglevel macro: ++ * #define WL_ERROR(args) EVENT_LOG_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_ERROR, args) ++ * ++ * The versions of the macros without FAST or COMPACT in their name are just synonyms for the ++ * COMPACT versions. ++ * ++ * You should use the COMPACT macro (or its synonym) in cases where there is some preceding logic ++ * that prevents the execution of the macro, e.g. WL_ERROR by definition rarely gets executed. ++ * Use the FAST macro in performance sensitive paths. The key concept here is that you should be ++ * assuming that your macro usage is compiled into ROM and can't be changed ... so choose wisely. ++ * ++ */ ++ ++#if !defined(EVENT_LOG_DUMPER) && !defined(DHD_EFI) ++ ++#ifndef EVENT_LOG_COMPILE ++ ++/* Null define if no tracing */ ++#define EVENT_LOG(format, ...) ++#define EVENT_LOG_FAST(tag, fmt, ...) ++#define EVENT_LOG_COMPACT(tag, fmt, ...) ++ ++#define EVENT_LOG_CAST(tag, fmt, ...) ++#define EVENT_LOG_FAST_CAST(tag, fmt, ...) ++#define EVENT_LOG_COMPACT_CAST(tag, fmt, ...) ++ ++#define EVENT_LOG_CAST_PAREN_ARGS(tag, pargs) ++#define EVENT_LOG_FAST_CAST_PAREN_ARGS(tag, pargs) ++#define EVENT_LOG_COMPACT_CAST_PAREN_ARGS(tag, pargs) ++ ++#define EVENT_LOG_IS_ON(tag) 0 ++#define EVENT_LOG_IS_LOG_ON(tag) 0 ++ ++#define EVENT_LOG_BUFFER(tag, buf, size) ++ ++#else /* EVENT_LOG_COMPILE */ ++ ++/* The first few are special because they can be done more efficiently ++ * this way and they are the common case. Once there are too many ++ * parameters the code size starts to be an issue and a loop is better ++ */ ++#define _EVENT_LOG0(tag, fmt_num) \ ++ event_log0(tag, fmt_num) ++#define _EVENT_LOG1(tag, fmt_num, t1) \ ++ event_log1(tag, fmt_num, t1) ++#define _EVENT_LOG2(tag, fmt_num, t1, t2) \ ++ event_log2(tag, fmt_num, t1, t2) ++#define _EVENT_LOG3(tag, fmt_num, t1, t2, t3) \ ++ event_log3(tag, fmt_num, t1, t2, t3) ++#define _EVENT_LOG4(tag, fmt_num, t1, t2, t3, t4) \ ++ event_log4(tag, fmt_num, t1, t2, t3, t4) ++ ++/* The rest call the generic routine that takes a count */ ++#define _EVENT_LOG5(tag, fmt_num, ...) event_logn(5, tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG6(tag, fmt_num, ...) event_logn(6, tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG7(tag, fmt_num, ...) event_logn(7, tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG8(tag, fmt_num, ...) event_logn(8, tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG9(tag, fmt_num, ...) event_logn(9, tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOGA(tag, fmt_num, ...) event_logn(10, tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOGB(tag, fmt_num, ...) event_logn(11, tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOGC(tag, fmt_num, ...) event_logn(12, tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOGD(tag, fmt_num, ...) event_logn(13, tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOGE(tag, fmt_num, ...) event_logn(14, tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOGF(tag, fmt_num, ...) event_logn(15, tag, fmt_num, __VA_ARGS__) ++ ++ ++/* Casting low level macros */ ++#define _EVENT_LOG_CAST0(tag, fmt_num) \ ++ event_log0(tag, fmt_num) ++#define _EVENT_LOG_CAST1(tag, fmt_num, t1) \ ++ event_log1(tag, fmt_num, (uint32)(t1)) ++#define _EVENT_LOG_CAST2(tag, fmt_num, t1, t2) \ ++ event_log2(tag, fmt_num, (uint32)(t1), (uint32)(t2)) ++#define _EVENT_LOG_CAST3(tag, fmt_num, t1, t2, t3) \ ++ event_log3(tag, fmt_num, (uint32)(t1), (uint32)(t2), (uint32)(t3)) ++#define _EVENT_LOG_CAST4(tag, fmt_num, t1, t2, t3, t4) \ ++ event_log4(tag, fmt_num, (uint32)(t1), (uint32)(t2), (uint32)(t3), (uint32)(t4)) ++ ++/* The rest call the generic routine that takes a count */ ++#define _EVENT_LOG_CAST5(tag, fmt_num, ...) _EVENT_LOG5(tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG_CAST6(tag, fmt_num, ...) _EVENT_LOG6(tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG_CAST7(tag, fmt_num, ...) _EVENT_LOG7(tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG_CAST8(tag, fmt_num, ...) _EVENT_LOG8(tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG_CAST9(tag, fmt_num, ...) _EVENT_LOG9(tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG_CASTA(tag, fmt_num, ...) _EVENT_LOGA(tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG_CASTB(tag, fmt_num, ...) _EVENT_LOGB(tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG_CASTC(tag, fmt_num, ...) _EVENT_LOGC(tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG_CASTD(tag, fmt_num, ...) _EVENT_LOGD(tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG_CASTE(tag, fmt_num, ...) _EVENT_LOGE(tag, fmt_num, __VA_ARGS__) ++#define _EVENT_LOG_CASTF(tag, fmt_num, ...) _EVENT_LOGF(tag, fmt_num, __VA_ARGS__) ++ ++/* Hack to make the proper routine call when variadic macros get ++ * passed. Note the max of 15 arguments. More than that can't be ++ * handled by the event_log entries anyways so best to catch it at compile ++ * time ++ */ ++ ++#define _EVENT_LOG_VA_NUM_ARGS(F, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ ++ _A, _B, _C, _D, _E, _F, N, ...) F ## N ++ ++/* cast = _EVENT_LOG for no casting ++ * cast = _EVENT_LOG_CAST for casting of fmt arguments to uint32. ++ * Only first 4 arguments are casted to uint32. event_logn() is called ++ * if more than 4 arguments are present. This function internally assumes ++ * all arguments are uint32 ++ */ ++#define _EVENT_LOG(cast, tag, fmt, ...) \ ++ static char logstr[] __attribute__ ((section(".logstrs"))) = fmt; \ ++ static uint32 fmtnum __attribute__ ((section(".lognums"))) = (uint32) &logstr; \ ++ _EVENT_LOG_VA_NUM_ARGS(cast, ##__VA_ARGS__, \ ++ F, E, D, C, B, A, 9, 8, \ ++ 7, 6, 5, 4, 3, 2, 1, 0) \ ++ (tag, (int) &fmtnum , ## __VA_ARGS__) ++ ++ ++#define EVENT_LOG_FAST(tag, fmt, ...) \ ++ do { \ ++ if (event_log_tag_sets != NULL) { \ ++ uint8 tag_flag = *(event_log_tag_sets + tag); \ ++ if ((tag_flag & ~EVENT_LOG_TAG_FLAG_SET_MASK) != 0) { \ ++ _EVENT_LOG(_EVENT_LOG, tag, fmt , ## __VA_ARGS__); \ ++ } \ ++ } \ ++ } while (0) ++ ++#define EVENT_LOG_COMPACT(tag, fmt, ...) \ ++ do { \ ++ _EVENT_LOG(_EVENT_LOG, tag, fmt , ## __VA_ARGS__); \ ++ } while (0) ++ ++/* Event log macro with casting to uint32 of arguments */ ++#define EVENT_LOG_FAST_CAST(tag, fmt, ...) \ ++ do { \ ++ if (event_log_tag_sets != NULL) { \ ++ uint8 tag_flag = *(event_log_tag_sets + tag); \ ++ if ((tag_flag & ~EVENT_LOG_TAG_FLAG_SET_MASK) != 0) { \ ++ _EVENT_LOG(_EVENT_LOG_CAST, tag, fmt , ## __VA_ARGS__); \ ++ } \ ++ } \ ++ } while (0) ++ ++#define EVENT_LOG_COMPACT_CAST(tag, fmt, ...) \ ++ do { \ ++ _EVENT_LOG(_EVENT_LOG_CAST, tag, fmt , ## __VA_ARGS__); \ ++ } while (0) ++ ++ ++#define EVENT_LOG(tag, fmt, ...) EVENT_LOG_COMPACT(tag, fmt , ## __VA_ARGS__) ++ ++#define EVENT_LOG_CAST(tag, fmt, ...) EVENT_LOG_COMPACT_CAST(tag, fmt , ## __VA_ARGS__) ++ ++#define _EVENT_LOG_REMOVE_PAREN(...) __VA_ARGS__ ++#define EVENT_LOG_REMOVE_PAREN(args) _EVENT_LOG_REMOVE_PAREN args ++ ++#define EVENT_LOG_CAST_PAREN_ARGS(tag, pargs) \ ++ EVENT_LOG_CAST(tag, EVENT_LOG_REMOVE_PAREN(pargs)) ++ ++#define EVENT_LOG_FAST_CAST_PAREN_ARGS(tag, pargs) \ ++ EVENT_LOG_FAST_CAST(tag, EVENT_LOG_REMOVE_PAREN(pargs)) ++ ++#define EVENT_LOG_COMPACT_CAST_PAREN_ARGS(tag, pargs) \ ++ EVENT_LOG_COMPACT_CAST(tag, EVENT_LOG_REMOVE_PAREN(pargs)) ++ ++/* Minimal event logging. Event log internally calls event_logx() ++ * log return address in caller. ++ * Note that the if(0){..} below is to avoid compiler warnings ++ * due to unused variables caused by this macro ++ */ ++#define EVENT_LOG_RA(tag, args) \ ++ do { \ ++ if (0) { \ ++ EVENT_LOG_COMPACT_CAST_PAREN_ARGS(tag, args); \ ++ } \ ++ event_log_caller_return_address(tag); \ ++ } while (0) ++ ++#define EVENT_LOG_IS_LOG_ON(tag) (*(event_log_tag_sets + (tag)) & EVENT_LOG_TAG_FLAG_LOG) ++ ++#define EVENT_DUMP event_log_buffer ++ ++extern uint8 *event_log_tag_sets; ++ ++extern int event_log_init(osl_t *osh); ++extern int event_log_set_init(osl_t *osh, int set_num, int size); ++extern int event_log_set_expand(osl_t *osh, int set_num, int size); ++extern int event_log_set_shrink(osl_t *osh, int set_num, int size); ++ ++extern int event_log_tag_start(int tag, int set_num, int flags); ++extern int event_log_tag_stop(int tag); ++ ++typedef void (*event_log_logtrace_trigger_fn_t)(void *ctx); ++void event_log_set_logtrace_trigger_fn(event_log_logtrace_trigger_fn_t fn, void *ctx); ++ ++event_log_top_t *event_log_get_top(void); ++ ++extern int event_log_get(int set_num, int buflen, void *buf); ++ ++extern uint8 *event_log_next_logtrace(int set_num); ++ ++extern void event_log0(int tag, int fmtNum); ++extern void event_log1(int tag, int fmtNum, uint32 t1); ++extern void event_log2(int tag, int fmtNum, uint32 t1, uint32 t2); ++extern void event_log3(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3); ++extern void event_log4(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3, uint32 t4); ++extern void event_logn(int num_args, int tag, int fmtNum, ...); ++ ++extern void event_log_time_sync(uint32 ms); ++extern void event_log_buffer(int tag, uint8 *buf, int size); ++extern void event_log_caller_return_address(int tag); ++extern int event_log_set_destination_set(int set, event_log_set_destination_t dest); ++extern event_log_set_destination_t event_log_set_destination_get(int set); ++ ++#endif /* EVENT_LOG_DUMPER */ ++ ++#endif /* EVENT_LOG_COMPILE */ ++ ++#endif /* __ASSEMBLER__ */ ++ ++#endif /* _EVENT_LOG_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/event_log_payload.h b/module_drivers/drivers/net/wireless/bcmdhd/include/event_log_payload.h +new file mode 100644 +index 000000000..d01264c5b +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/event_log_payload.h +@@ -0,0 +1,673 @@ ++/* ++ * EVENT_LOG System Definitions ++ * ++ * This file describes the payloads of event log entries that are data buffers ++ * rather than formatted string entries. The contents are generally XTLVs. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: event_log_payload.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _EVENT_LOG_PAYLOAD_H_ ++#define _EVENT_LOG_PAYLOAD_H_ ++ ++#include ++#include ++#include ++#include ++ ++#define EVENT_LOG_XTLV_ID_STR 0 /**< XTLV ID for a string */ ++#define EVENT_LOG_XTLV_ID_TXQ_SUM 1 /**< XTLV ID for txq_summary_t */ ++#define EVENT_LOG_XTLV_ID_SCBDATA_SUM 2 /**< XTLV ID for cb_subq_summary_t */ ++#define EVENT_LOG_XTLV_ID_SCBDATA_AMPDU_TX_SUM 3 /**< XTLV ID for scb_ampdu_tx_summary_t */ ++#define EVENT_LOG_XTLV_ID_BSSCFGDATA_SUM 4 /**< XTLV ID for bsscfg_q_summary_t */ ++#define EVENT_LOG_XTLV_ID_UCTXSTATUS 5 /**< XTLV ID for ucode TxStatus array */ ++#define EVENT_LOG_XTLV_ID_TXQ_SUM_V2 6 /**< XTLV ID for txq_summary_v2_t */ ++ ++/** ++ * An XTLV holding a string ++ * String is not null terminated, length is the XTLV len. ++ */ ++typedef struct xtlv_string { ++ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_STR */ ++ uint16 len; /* XTLV Len (String length) */ ++ char str[1]; /* var len array characters */ ++} xtlv_string_t; ++ ++#define XTLV_STRING_FULL_LEN(str_len) (BCM_XTLV_HDR_SIZE + (str_len) * sizeof(char)) ++ ++/** ++ * Summary for a single TxQ context ++ * Two of these will be used per TxQ context---one for the high TxQ, and one for ++ * the low txq that contains DMA prepared pkts. The high TxQ is a full multi-precidence ++ * queue and also has a BSSCFG map to identify the BSSCFGS associated with the queue context. ++ * The low txq counterpart does not populate the BSSCFG map. ++ * The excursion queue will have no bsscfgs associated and is the first queue dumped. ++ */ ++typedef struct txq_summary { ++ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_TXQ_SUM */ ++ uint16 len; /* XTLV Len */ ++ uint32 bsscfg_map; /* bitmap of bsscfg indexes associated with this queue */ ++ uint32 stopped; /* flow control bitmap */ ++ uint8 prec_count; /* count of precedences/fifos and len of following array */ ++ uint8 pad; ++ uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */ ++} txq_summary_t; ++ ++#define TXQ_SUMMARY_LEN (OFFSETOF(txq_summary_t, plen)) ++#define TXQ_SUMMARY_FULL_LEN(num_q) (TXQ_SUMMARY_LEN + (num_q) * sizeof(uint16)) ++ ++typedef struct txq_summary_v2 { ++ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_TXQ_SUM_V2 */ ++ uint16 len; /* XTLV Len */ ++ uint32 bsscfg_map; /* bitmap of bsscfg indexes associated with this queue */ ++ uint32 stopped; /* flow control bitmap */ ++ uint32 hw_stopped; /* flow control bitmap */ ++ uint8 prec_count; /* count of precedences/fifos and len of following array */ ++ uint8 pad; ++ uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */ ++} txq_summary_v2_t; ++ ++#define TXQ_SUMMARY_V2_LEN (OFFSETOF(txq_summary_v2_t, plen)) ++#define TXQ_SUMMARY_V2_FULL_LEN(num_q) (TXQ_SUMMARY_V2_LEN + (num_q) * sizeof(uint16)) ++ ++/** ++ * Summary for tx datapath of an SCB cubby ++ * This is a generic summary structure (one size fits all) with ++ * a cubby ID and sub-ID to differentiate SCB cubby types and possible sub-queues. ++ */ ++typedef struct scb_subq_summary { ++ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_SCBDATA_SUM */ ++ uint16 len; /* XTLV Len */ ++ uint32 flags; /* cubby specficic flags */ ++ uint8 cubby_id; /* ID registered for cubby */ ++ uint8 sub_id; /* sub ID if a cubby has more than one queue */ ++ uint8 prec_count; /* count of precedences/fifos and len of following array */ ++ uint8 pad; ++ uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */ ++} scb_subq_summary_t; ++ ++#define SCB_SUBQ_SUMMARY_LEN (OFFSETOF(scb_subq_summary_t, plen)) ++#define SCB_SUBQ_SUMMARY_FULL_LEN(num_q) (SCB_SUBQ_SUMMARY_LEN + (num_q) * sizeof(uint16)) ++ ++/* scb_subq_summary_t.flags for APPS */ ++#define SCBDATA_APPS_F_PS 0x00000001 ++#define SCBDATA_APPS_F_PSPEND 0x00000002 ++#define SCBDATA_APPS_F_INPVB 0x00000004 ++#define SCBDATA_APPS_F_APSD_USP 0x00000008 ++#define SCBDATA_APPS_F_TXBLOCK 0x00000010 ++#define SCBDATA_APPS_F_APSD_HPKT_TMR 0x00000020 ++#define SCBDATA_APPS_F_APSD_TX_PEND 0x00000040 ++#define SCBDATA_APPS_F_INTRANS 0x00000080 ++#define SCBDATA_APPS_F_OFF_PEND 0x00000100 ++#define SCBDATA_APPS_F_OFF_BLOCKED 0x00000200 ++#define SCBDATA_APPS_F_OFF_IN_PROG 0x00000400 ++ ++ ++/** ++ * Summary for tx datapath AMPDU SCB cubby ++ * This is a specific data structure to describe the AMPDU datapath state for an SCB ++ * used instead of scb_subq_summary_t. ++ * Info is for one TID, so one will be dumped per BA TID active for an SCB. ++ */ ++typedef struct scb_ampdu_tx_summary { ++ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_SCBDATA_AMPDU_TX_SUM */ ++ uint16 len; /* XTLV Len */ ++ uint32 flags; /* misc flags */ ++ uint8 tid; /* initiator TID (priority) */ ++ uint8 ba_state; /* internal BA state */ ++ uint8 bar_cnt; /* number of bars sent with no progress */ ++ uint8 retry_bar; /* reason code if bar to be retried at watchdog */ ++ uint16 barpending_seq; /* seqnum for bar */ ++ uint16 bar_ackpending_seq; /* seqnum of bar for which ack is pending */ ++ uint16 start_seq; /* seqnum of the first unacknowledged packet */ ++ uint16 max_seq; /* max unacknowledged seqnum sent */ ++ uint32 released_bytes_inflight; /* Number of bytes pending in bytes */ ++ uint32 released_bytes_target; ++} scb_ampdu_tx_summary_t; ++ ++/* scb_ampdu_tx_summary.flags defs */ ++#define SCBDATA_AMPDU_TX_F_BAR_ACKPEND 0x00000001 /* bar_ackpending */ ++ ++/** XTLV stuct to summarize a BSSCFG's packet queue */ ++typedef struct bsscfg_q_summary { ++ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_BSSCFGDATA_SUM */ ++ uint16 len; /* XTLV Len */ ++ struct ether_addr BSSID; /* BSSID */ ++ uint8 bsscfg_idx; /* bsscfg index */ ++ uint8 type; /* bsscfg type enumeration: BSSCFG_TYPE_XXX */ ++ uint8 subtype; /* bsscfg subtype enumeration: BSSCFG_SUBTYPE_XXX */ ++ uint8 prec_count; /* count of precedences/fifos and len of following array */ ++ uint16 plen[1]; /* var len array of lengths of each prec/fifo in the queue */ ++} bsscfg_q_summary_t; ++ ++#define BSSCFG_Q_SUMMARY_LEN (OFFSETOF(bsscfg_q_summary_t, plen)) ++#define BSSCFG_Q_SUMMARY_FULL_LEN(num_q) (BSSCFG_Q_SUMMARY_LEN + (num_q) * sizeof(uint16)) ++ ++/** ++ * An XTLV holding a TxStats array ++ * TxStatus entries are 8 or 16 bytes, size in words (2 or 4) givent in ++ * entry_size field. ++ * Array is uint32 words ++ */ ++typedef struct xtlv_uc_txs { ++ uint16 id; /* XTLV ID: EVENT_LOG_XTLV_ID_UCTXSTATUS */ ++ uint16 len; /* XTLV Len */ ++ uint8 entry_size; /* num uint32 words per entry */ ++ uint8 pad[3]; /* reserved, zero */ ++ uint32 w[1]; /* var len array of words */ ++} xtlv_uc_txs_t; ++ ++#define XTLV_UCTXSTATUS_LEN (OFFSETOF(xtlv_uc_txs_t, w)) ++#define XTLV_UCTXSTATUS_FULL_LEN(words) (XTLV_UCTXSTATUS_LEN + (words) * sizeof(uint32)) ++ ++#define SCAN_SUMMARY_VERSION 1 ++/* Scan flags */ ++#define SCAN_SUM_CHAN_INFO 0x1 ++/* Scan_sum flags */ ++#define BAND5G_SIB_ENAB 0x2 ++#define BAND2G_SIB_ENAB 0x4 ++#define PARALLEL_SCAN 0x8 ++#define SCAN_ABORT 0x10 ++ ++/* scan_channel_info flags */ ++#define ACTIVE_SCAN_SCN_SUM 0x2 ++#define SCAN_SUM_WLC_CORE0 0x4 ++#define SCAN_SUM_WLC_CORE1 0x8 ++#define HOME_CHAN 0x10 ++ ++typedef struct wl_scan_ssid_info ++{ ++ uint8 ssid_len; /* the length of SSID */ ++ uint8 ssid[32]; /* SSID string */ ++} wl_scan_ssid_info_t; ++ ++typedef struct wl_scan_channel_info { ++ uint16 chanspec; /* chanspec scanned */ ++ uint16 reserv; ++ uint32 start_time; /* Scan start time in ++ * milliseconds for the chanspec ++ * or home_dwell time start ++ */ ++ uint32 end_time; /* Scan end time in ++ * milliseconds for the chanspec ++ * or home_dwell time end ++ */ ++ uint16 probe_count; /* No of probes sent out. For future use ++ */ ++ uint16 scn_res_count; /* Count of scan_results found per ++ * channel. For future use ++ */ ++} wl_scan_channel_info_t; ++ ++typedef struct wl_scan_summary_info { ++ uint32 total_chan_num; /* Total number of channels scanned */ ++ uint32 scan_start_time; /* Scan start time in milliseconds */ ++ uint32 scan_end_time; /* Scan end time in milliseconds */ ++ wl_scan_ssid_info_t ssid[1]; /* SSID being scanned in current ++ * channel. For future use ++ */ ++} wl_scan_summary_info_t; ++ ++struct wl_scan_summary { ++ uint8 version; /* Version */ ++ uint8 reserved; ++ uint16 len; /* Length of the data buffer including SSID ++ * list. ++ */ ++ uint16 sync_id; /* Scan Sync ID */ ++ uint16 scan_flags; /* flags [0] or SCAN_SUM_CHAN_INFO = */ ++ /* channel_info, if not set */ ++ /* it is scan_summary_info */ ++ /* when channel_info is used, */ ++ /* the following flag bits are overridden: */ ++ /* flags[1] or ACTIVE_SCAN_SCN_SUM = active channel if set */ ++ /* passive if not set */ ++ /* flags[2] or WLC_CORE0 = if set, represents wlc_core0 */ ++ /* flags[3] or WLC_CORE1 = if set, represents wlc_core1 */ ++ /* flags[4] or HOME_CHAN = if set, represents home-channel */ ++ /* flags[5:15] = reserved */ ++ /* when scan_summary_info is used, */ ++ /* the following flag bits are used: */ ++ /* flags[1] or BAND5G_SIB_ENAB = */ ++ /* allowSIBParallelPassiveScan on 5G band */ ++ /* flags[2] or BAND2G_SIB_ENAB = */ ++ /* allowSIBParallelPassiveScan on 2G band */ ++ /* flags[3] or PARALLEL_SCAN = Parallel scan enabled or not */ ++ /* flags[4] or SCAN_ABORT = SCAN_ABORTED scenario */ ++ /* flags[5:15] = reserved */ ++ union { ++ wl_scan_channel_info_t scan_chan_info; /* scan related information ++ * for each channel scanned ++ */ ++ wl_scan_summary_info_t scan_sum_info; /* Cumulative scan related ++ * information. ++ */ ++ } u; ++}; ++ ++/* Channel switch log record structure ++ * Host may map the following structure on channel switch event log record ++ * received from dongle. Note that all payload entries in event log record are ++ * uint32/int32. ++ */ ++typedef struct wl_chansw_event_log_record { ++ uint32 time; /* Time in us */ ++ uint32 old_chanspec; /* Old channel spec */ ++ uint32 new_chanspec; /* New channel spec */ ++ uint32 chansw_reason; /* Reason for channel change */ ++ int32 dwell_time; ++} wl_chansw_event_log_record_t; ++ ++/* Sub-block type for EVENT_LOG_TAG_AMPDU_DUMP */ ++#define WL_AMPDU_STATS_TYPE_RXMCSx1 0 /* RX MCS rate (Nss = 1) */ ++#define WL_AMPDU_STATS_TYPE_RXMCSx2 1 ++#define WL_AMPDU_STATS_TYPE_RXMCSx3 2 ++#define WL_AMPDU_STATS_TYPE_RXMCSx4 3 ++#define WL_AMPDU_STATS_TYPE_RXVHTx1 4 /* RX VHT rate (Nss = 1) */ ++#define WL_AMPDU_STATS_TYPE_RXVHTx2 5 ++#define WL_AMPDU_STATS_TYPE_RXVHTx3 6 ++#define WL_AMPDU_STATS_TYPE_RXVHTx4 7 ++#define WL_AMPDU_STATS_TYPE_TXMCSx1 8 /* TX MCS rate (Nss = 1) */ ++#define WL_AMPDU_STATS_TYPE_TXMCSx2 9 ++#define WL_AMPDU_STATS_TYPE_TXMCSx3 10 ++#define WL_AMPDU_STATS_TYPE_TXMCSx4 11 ++#define WL_AMPDU_STATS_TYPE_TXVHTx1 12 /* TX VHT rate (Nss = 1) */ ++#define WL_AMPDU_STATS_TYPE_TXVHTx2 13 ++#define WL_AMPDU_STATS_TYPE_TXVHTx3 14 ++#define WL_AMPDU_STATS_TYPE_TXVHTx4 15 ++#define WL_AMPDU_STATS_TYPE_RXMCSSGI 16 /* RX SGI usage (for all MCS rates) */ ++#define WL_AMPDU_STATS_TYPE_TXMCSSGI 17 /* TX SGI usage (for all MCS rates) */ ++#define WL_AMPDU_STATS_TYPE_RXVHTSGI 18 /* RX SGI usage (for all VHT rates) */ ++#define WL_AMPDU_STATS_TYPE_TXVHTSGI 19 /* TX SGI usage (for all VHT rates) */ ++#define WL_AMPDU_STATS_TYPE_RXMCSPER 20 /* RX PER (for all MCS rates) */ ++#define WL_AMPDU_STATS_TYPE_TXMCSPER 21 /* TX PER (for all MCS rates) */ ++#define WL_AMPDU_STATS_TYPE_RXVHTPER 22 /* RX PER (for all VHT rates) */ ++#define WL_AMPDU_STATS_TYPE_TXVHTPER 23 /* TX PER (for all VHT rates) */ ++#define WL_AMPDU_STATS_TYPE_RXDENS 24 /* RX AMPDU density */ ++#define WL_AMPDU_STATS_TYPE_TXDENS 25 /* TX AMPDU density */ ++#define WL_AMPDU_STATS_TYPE_RXMCSOK 26 /* RX all MCS rates */ ++#define WL_AMPDU_STATS_TYPE_RXVHTOK 27 /* RX all VHT rates */ ++#define WL_AMPDU_STATS_TYPE_TXMCSALL 28 /* TX all MCS rates */ ++#define WL_AMPDU_STATS_TYPE_TXVHTALL 29 /* TX all VHT rates */ ++#define WL_AMPDU_STATS_TYPE_TXMCSOK 30 /* TX all MCS rates */ ++#define WL_AMPDU_STATS_TYPE_TXVHTOK 31 /* TX all VHT rates */ ++ ++#define WL_AMPDU_STATS_MAX_CNTS 64 ++ ++typedef struct { ++ uint16 type; /* AMPDU statistics sub-type */ ++ uint16 len; /* Number of 32-bit counters */ ++ uint32 counters[WL_AMPDU_STATS_MAX_CNTS]; ++} wl_ampdu_stats_generic_t; ++ ++typedef struct { ++ uint16 type; /* AMPDU statistics sub-type */ ++ uint16 len; /* Number of 32-bit counters + 2 */ ++ uint32 total_ampdu; ++ uint32 total_mpdu; ++ uint32 aggr_dist[WL_AMPDU_STATS_MAX_CNTS + 1]; ++} wl_ampdu_stats_aggrsz_t; ++ ++/* Sub-block type for EVENT_LOG_TAG_MSCHPROFILE */ ++#define WL_MSCH_PROFILER_START 0 /* start event check */ ++#define WL_MSCH_PROFILER_EXIT 1 /* exit event check */ ++#define WL_MSCH_PROFILER_REQ 2 /* request event */ ++#define WL_MSCH_PROFILER_CALLBACK 3 /* call back event */ ++#define WL_MSCH_PROFILER_MESSAGE 4 /* message event */ ++#define WL_MSCH_PROFILER_PROFILE_START 5 ++#define WL_MSCH_PROFILER_PROFILE_END 6 ++#define WL_MSCH_PROFILER_REQ_HANDLE 7 ++#define WL_MSCH_PROFILER_REQ_ENTITY 8 ++#define WL_MSCH_PROFILER_CHAN_CTXT 9 ++#define WL_MSCH_PROFILER_EVENT_LOG 10 ++#define WL_MSCH_PROFILER_REQ_TIMING 11 ++#define WL_MSCH_PROFILER_TYPE_MASK 0x00ff ++#define WL_MSCH_PROFILER_WLINDEX_SHIFT 8 ++#define WL_MSCH_PROFILER_WLINDEX_MASK 0x0f00 ++#define WL_MSCH_PROFILER_VER_SHIFT 12 ++#define WL_MSCH_PROFILER_VER_MASK 0xf000 ++ ++/* MSCH Event data current verion */ ++#define WL_MSCH_PROFILER_VER 2 ++ ++/* msch version history */ ++#define WL_MSCH_PROFILER_RSDB_VER 1 ++#define WL_MSCH_PROFILER_REPORT_VER 2 ++ ++/* msch collect header size */ ++#define WL_MSCH_PROFILE_HEAD_SIZE OFFSETOF(msch_collect_tlv_t, value) ++ ++/* msch event log header size */ ++#define WL_MSCH_EVENT_LOG_HEAD_SIZE OFFSETOF(msch_event_log_profiler_event_data_t, data) ++ ++/* MSCH data buffer size */ ++#define WL_MSCH_PROFILER_BUFFER_SIZE 512 ++ ++/* request type used in wlc_msch_req_param_t struct */ ++#define WL_MSCH_RT_BOTH_FIXED 0 /* both start and end time is fixed */ ++#define WL_MSCH_RT_START_FLEX 1 /* start time is flexible and duration is fixed */ ++#define WL_MSCH_RT_DUR_FLEX 2 /* start time is fixed and end time is flexible */ ++#define WL_MSCH_RT_BOTH_FLEX 3 /* Both start and duration is flexible */ ++ ++/* Flags used in wlc_msch_req_param_t struct */ ++#define WL_MSCH_REQ_FLAGS_CHAN_CONTIGUOUS (1 << 0) /* Don't break up channels in chanspec_list */ ++#define WL_MSCH_REQ_FLAGS_MERGE_CONT_SLOTS (1 << 1) /* No slot end if slots are continous */ ++#define WL_MSCH_REQ_FLAGS_PREMTABLE (1 << 2) /* Req can be pre-empted by PREMT_CURTS req */ ++#define WL_MSCH_REQ_FLAGS_PREMT_CURTS (1 << 3) /* Pre-empt request at the end of curts */ ++#define WL_MSCH_REQ_FLAGS_PREMT_IMMEDIATE (1 << 4) /* Pre-empt cur_ts immediately */ ++ ++/* Requested slot Callback states ++ * req->pend_slot/cur_slot->flags ++ */ ++#define WL_MSCH_RC_FLAGS_ONCHAN_FIRE (1 << 0) ++#define WL_MSCH_RC_FLAGS_START_FIRE_DONE (1 << 1) ++#define WL_MSCH_RC_FLAGS_END_FIRE_DONE (1 << 2) ++#define WL_MSCH_RC_FLAGS_ONFIRE_DONE (1 << 3) ++#define WL_MSCH_RC_FLAGS_SPLIT_SLOT_START (1 << 4) ++#define WL_MSCH_RC_FLAGS_SPLIT_SLOT_END (1 << 5) ++#define WL_MSCH_RC_FLAGS_PRE_ONFIRE_DONE (1 << 6) ++ ++/* Request entity flags */ ++#define WL_MSCH_ENTITY_FLAG_MULTI_INSTANCE (1 << 0) ++ ++/* Request Handle flags */ ++#define WL_MSCH_REQ_HDL_FLAGS_NEW_REQ (1 << 0) /* req_start callback */ ++ ++/* MSCH state flags (msch_info->flags) */ ++#define WL_MSCH_STATE_IN_TIEMR_CTXT 0x1 ++#define WL_MSCH_STATE_SCHD_PENDING 0x2 ++ ++/* MSCH callback type */ ++#define WL_MSCH_CT_REQ_START 0x1 ++#define WL_MSCH_CT_ON_CHAN 0x2 ++#define WL_MSCH_CT_SLOT_START 0x4 ++#define WL_MSCH_CT_SLOT_END 0x8 ++#define WL_MSCH_CT_SLOT_SKIP 0x10 ++#define WL_MSCH_CT_OFF_CHAN 0x20 ++#define WL_MSCH_CT_OFF_CHAN_DONE 0x40 ++#define WL_MSCH_CT_REQ_END 0x80 ++#define WL_MSCH_CT_PARTIAL 0x100 ++#define WL_MSCH_CT_PRE_ONCHAN 0x200 ++#define WL_MSCH_CT_PRE_REQ_START 0x400 ++ ++/* MSCH command bits */ ++#define WL_MSCH_CMD_ENABLE_BIT 0x01 ++#define WL_MSCH_CMD_PROFILE_BIT 0x02 ++#define WL_MSCH_CMD_CALLBACK_BIT 0x04 ++#define WL_MSCH_CMD_REGISTER_BIT 0x08 ++#define WL_MSCH_CMD_ERROR_BIT 0x10 ++#define WL_MSCH_CMD_DEBUG_BIT 0x20 ++#define WL_MSCH_CMD_INFOM_BIT 0x40 ++#define WL_MSCH_CMD_TRACE_BIT 0x80 ++#define WL_MSCH_CMD_ALL_BITS 0xfe ++#define WL_MSCH_CMD_SIZE_MASK 0x00ff0000 ++#define WL_MSCH_CMD_SIZE_SHIFT 16 ++#define WL_MSCH_CMD_VER_MASK 0xff000000 ++#define WL_MSCH_CMD_VER_SHIFT 24 ++ ++/* maximum channels returned by the get valid channels iovar */ ++#define WL_MSCH_NUMCHANNELS 64 ++ ++typedef struct msch_collect_tlv { ++ uint16 type; ++ uint16 size; ++ char value[1]; ++} msch_collect_tlv_t; ++ ++typedef struct msch_profiler_event_data { ++ uint32 time_lo; /* Request time */ ++ uint32 time_hi; ++} msch_profiler_event_data_t; ++ ++typedef struct msch_start_profiler_event_data { ++ uint32 time_lo; /* Request time */ ++ uint32 time_hi; ++ uint32 status; ++} msch_start_profiler_event_data_t; ++ ++typedef struct msch_message_profiler_event_data { ++ uint32 time_lo; /* Request time */ ++ uint32 time_hi; ++ char message[1]; /* message */ ++} msch_message_profiler_event_data_t; ++ ++typedef struct msch_event_log_profiler_event_data { ++ uint32 time_lo; /* Request time */ ++ uint32 time_hi; ++ event_log_hdr_t hdr; /* event log header */ ++ uint32 data[9]; /* event data */ ++} msch_event_log_profiler_event_data_t; ++ ++typedef struct msch_req_param_profiler_event_data { ++ uint16 flags; /* Describe various request properties */ ++ uint8 req_type; /* Describe start and end time flexiblilty */ ++ uint8 priority; /* Define the request priority */ ++ uint32 start_time_l; /* Requested start time offset in us unit */ ++ uint32 start_time_h; ++ uint32 duration; /* Requested duration in us unit */ ++ uint32 interval; /* Requested periodic interval in us unit, ++ * 0 means non-periodic ++ */ ++ union { ++ uint32 dur_flex; /* MSCH_REG_DUR_FLEX, min_dur = duration - dur_flex */ ++ struct { ++ uint32 min_dur; /* min duration for traffic, maps to home_time */ ++ uint32 max_away_dur; /* max acceptable away dur, maps to home_away_time */ ++ uint32 hi_prio_time_l; ++ uint32 hi_prio_time_h; ++ uint32 hi_prio_interval; /* repeated high priority interval */ ++ } bf; ++ } flex; ++} msch_req_param_profiler_event_data_t; ++ ++typedef struct msch_req_timing_profiler_event_data { ++ uint32 p_req_timing; ++ uint32 p_prev; ++ uint32 p_next; ++ uint16 flags; ++ uint16 timeslot_ptr; ++ uint32 fire_time_l; ++ uint32 fire_time_h; ++ uint32 pre_start_time_l; ++ uint32 pre_start_time_h; ++ uint32 start_time_l; ++ uint32 start_time_h; ++ uint32 end_time_l; ++ uint32 end_time_h; ++ uint32 p_timeslot; ++} msch_req_timing_profiler_event_data_t; ++ ++typedef struct msch_chan_ctxt_profiler_event_data { ++ uint32 p_chan_ctxt; ++ uint32 p_prev; ++ uint32 p_next; ++ uint16 chanspec; ++ uint16 bf_sch_pending; ++ uint32 bf_link_prev; ++ uint32 bf_link_next; ++ uint32 onchan_time_l; ++ uint32 onchan_time_h; ++ uint32 actual_onchan_dur_l; ++ uint32 actual_onchan_dur_h; ++ uint32 pend_onchan_dur_l; ++ uint32 pend_onchan_dur_h; ++ uint16 req_entity_list_cnt; ++ uint16 req_entity_list_ptr; ++ uint16 bf_entity_list_cnt; ++ uint16 bf_entity_list_ptr; ++ uint32 bf_skipped_count; ++} msch_chan_ctxt_profiler_event_data_t; ++ ++typedef struct msch_req_entity_profiler_event_data { ++ uint32 p_req_entity; ++ uint32 req_hdl_link_prev; ++ uint32 req_hdl_link_next; ++ uint32 chan_ctxt_link_prev; ++ uint32 chan_ctxt_link_next; ++ uint32 rt_specific_link_prev; ++ uint32 rt_specific_link_next; ++ uint32 start_fixed_link_prev; ++ uint32 start_fixed_link_next; ++ uint32 both_flex_list_prev; ++ uint32 both_flex_list_next; ++ uint16 chanspec; ++ uint16 priority; ++ uint16 cur_slot_ptr; ++ uint16 pend_slot_ptr; ++ uint16 pad; ++ uint16 chan_ctxt_ptr; ++ uint32 p_chan_ctxt; ++ uint32 p_req_hdl; ++ uint32 bf_last_serv_time_l; ++ uint32 bf_last_serv_time_h; ++ uint16 onchan_chn_idx; ++ uint16 cur_chn_idx; ++ uint32 flags; ++ uint32 actual_start_time_l; ++ uint32 actual_start_time_h; ++ uint32 curts_fire_time_l; ++ uint32 curts_fire_time_h; ++} msch_req_entity_profiler_event_data_t; ++ ++typedef struct msch_req_handle_profiler_event_data { ++ uint32 p_req_handle; ++ uint32 p_prev; ++ uint32 p_next; ++ uint32 cb_func; ++ uint32 cb_ctxt; ++ uint16 req_param_ptr; ++ uint16 req_entity_list_cnt; ++ uint16 req_entity_list_ptr; ++ uint16 chan_cnt; ++ uint32 flags; ++ uint16 chanspec_list; ++ uint16 chanspec_cnt; ++ uint16 chan_idx; ++ uint16 last_chan_idx; ++ uint32 req_time_l; ++ uint32 req_time_h; ++} msch_req_handle_profiler_event_data_t; ++ ++typedef struct msch_profiler_profiler_event_data { ++ uint32 time_lo; /* Request time */ ++ uint32 time_hi; ++ uint32 free_req_hdl_list; ++ uint32 free_req_entity_list; ++ uint32 free_chan_ctxt_list; ++ uint32 free_chanspec_list; ++ uint16 cur_msch_timeslot_ptr; ++ uint16 next_timeslot_ptr; ++ uint32 p_cur_msch_timeslot; ++ uint32 p_next_timeslot; ++ uint32 cur_armed_timeslot; ++ uint32 flags; ++ uint32 ts_id; ++ uint32 service_interval; ++ uint32 max_lo_prio_interval; ++ uint16 flex_list_cnt; ++ uint16 msch_chanspec_alloc_cnt; ++ uint16 msch_req_entity_alloc_cnt; ++ uint16 msch_req_hdl_alloc_cnt; ++ uint16 msch_chan_ctxt_alloc_cnt; ++ uint16 msch_timeslot_alloc_cnt; ++ uint16 msch_req_hdl_list_cnt; ++ uint16 msch_req_hdl_list_ptr; ++ uint16 msch_chan_ctxt_list_cnt; ++ uint16 msch_chan_ctxt_list_ptr; ++ uint16 msch_req_timing_list_cnt; ++ uint16 msch_req_timing_list_ptr; ++ uint16 msch_start_fixed_list_cnt; ++ uint16 msch_start_fixed_list_ptr; ++ uint16 msch_both_flex_req_entity_list_cnt; ++ uint16 msch_both_flex_req_entity_list_ptr; ++ uint16 msch_start_flex_list_cnt; ++ uint16 msch_start_flex_list_ptr; ++ uint16 msch_both_flex_list_cnt; ++ uint16 msch_both_flex_list_ptr; ++ uint32 slotskip_flag; ++} msch_profiler_profiler_event_data_t; ++ ++typedef struct msch_req_profiler_event_data { ++ uint32 time_lo; /* Request time */ ++ uint32 time_hi; ++ uint16 chanspec_cnt; ++ uint16 chanspec_ptr; ++ uint16 req_param_ptr; ++ uint16 pad; ++} msch_req_profiler_event_data_t; ++ ++typedef struct msch_callback_profiler_event_data { ++ uint32 time_lo; /* Request time */ ++ uint32 time_hi; ++ uint16 type; /* callback type */ ++ uint16 chanspec; /* actual chanspec, may different with requested one */ ++ uint32 start_time_l; /* time slot start time low 32bit */ ++ uint32 start_time_h; /* time slot start time high 32bit */ ++ uint32 end_time_l; /* time slot end time low 32 bit */ ++ uint32 end_time_h; /* time slot end time high 32 bit */ ++ uint32 timeslot_id; /* unique time slot id */ ++ uint32 p_req_hdl; ++ uint32 onchan_idx; /* Current channel index */ ++ uint32 cur_chan_seq_start_time_l; /* start time of current sequence */ ++ uint32 cur_chan_seq_start_time_h; ++} msch_callback_profiler_event_data_t; ++ ++typedef struct msch_timeslot_profiler_event_data { ++ uint32 p_timeslot; ++ uint32 timeslot_id; ++ uint32 pre_start_time_l; ++ uint32 pre_start_time_h; ++ uint32 end_time_l; ++ uint32 end_time_h; ++ uint32 sch_dur_l; ++ uint32 sch_dur_h; ++ uint32 p_chan_ctxt; ++ uint32 fire_time_l; ++ uint32 fire_time_h; ++ uint32 state; ++} msch_timeslot_profiler_event_data_t; ++ ++typedef struct msch_register_params { ++ uint16 wlc_index; /* Optional wlc index */ ++ uint16 flags; /* Describe various request properties */ ++ uint32 req_type; /* Describe start and end time flexiblilty */ ++ uint16 id; /* register id */ ++ uint16 priority; /* Define the request priority */ ++ uint32 start_time; /* Requested start time offset in ms unit */ ++ uint32 duration; /* Requested duration in ms unit */ ++ uint32 interval; /* Requested periodic interval in ms unit, ++ * 0 means non-periodic ++ */ ++ uint32 dur_flex; /* MSCH_REG_DUR_FLEX, min_dur = duration - dur_flex */ ++ uint32 min_dur; /* min duration for traffic, maps to home_time */ ++ uint32 max_away_dur; /* max acceptable away dur, maps to home_away_time */ ++ uint32 hi_prio_time; ++ uint32 hi_prio_interval; /* repeated high priority interval */ ++ uint32 chanspec_cnt; ++ uint16 chanspec_list[WL_MSCH_NUMCHANNELS]; ++} msch_register_params_t; ++ ++#endif /* _EVENT_LOG_PAYLOAD_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/event_log_set.h b/module_drivers/drivers/net/wireless/bcmdhd/include/event_log_set.h +new file mode 100644 +index 000000000..db28360ea +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/event_log_set.h +@@ -0,0 +1,53 @@ ++/* ++ * EVENT_LOG system definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: event_log_set.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _EVENT_LOG_SET_H_ ++#define _EVENT_LOG_SET_H_ ++ ++/* Set a maximum number of sets here. It is not dynamic for ++ * efficiency of the EVENT_LOG calls. ++ */ ++#define NUM_EVENT_LOG_SETS 8 ++ ++/* Define new event log sets here */ ++#define EVENT_LOG_SET_BUS 0 ++#define EVENT_LOG_SET_WL 1 ++#define EVENT_LOG_SET_PSM 2 ++#define EVENT_LOG_SET_ERROR 3 ++#define EVENT_LOG_SET_MEM_API 4 ++/* Share the set with MEM_API for now to limit ROM invalidation. ++ * The above set is used in dingo only ++ * On trunk, MSCH should move to a different set. ++ */ ++#define EVENT_LOG_SET_MSCH_PROFILER 4 ++#define EVENT_LOG_SET_ECOUNTERS 5 /* Host to instantiate this for ecounters. */ ++#define EVENT_LOG_SET_6 6 /* Instantiated by host for channel switch logs */ ++#define EVENT_LOG_SET_7 7 /* Instantiated by host for AMPDU stats */ ++ ++#endif /* _EVENT_LOG_SET_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/event_log_tag.h b/module_drivers/drivers/net/wireless/bcmdhd/include/event_log_tag.h +new file mode 100644 +index 000000000..41332e7aa +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/event_log_tag.h +@@ -0,0 +1,222 @@ ++/* ++ * EVENT_LOG system definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: event_log_tag.h 700681 2017-05-20 16:37:38Z $ ++ */ ++ ++#ifndef _EVENT_LOG_TAG_H_ ++#define _EVENT_LOG_TAG_H_ ++ ++#include ++ ++/* Define new event log tags here */ ++#define EVENT_LOG_TAG_NULL 0 /* Special null tag */ ++#define EVENT_LOG_TAG_TS 1 /* Special timestamp tag */ ++#define EVENT_LOG_TAG_BUS_OOB 2 ++#define EVENT_LOG_TAG_BUS_STATE 3 ++#define EVENT_LOG_TAG_BUS_PROTO 4 ++#define EVENT_LOG_TAG_BUS_CTL 5 ++#define EVENT_LOG_TAG_BUS_EVENT 6 ++#define EVENT_LOG_TAG_BUS_PKT 7 ++#define EVENT_LOG_TAG_BUS_FRAME 8 ++#define EVENT_LOG_TAG_BUS_DESC 9 ++#define EVENT_LOG_TAG_BUS_SETUP 10 ++#define EVENT_LOG_TAG_BUS_MISC 11 ++#define EVENT_LOG_TAG_SRSCAN 22 ++#define EVENT_LOG_TAG_PWRSTATS_INFO 23 ++#define EVENT_LOG_TAG_UCODE_WATCHDOG 26 ++#define EVENT_LOG_TAG_UCODE_FIFO 27 ++#define EVENT_LOG_TAG_SCAN_TRACE_LOW 28 ++#define EVENT_LOG_TAG_SCAN_TRACE_HIGH 29 ++#define EVENT_LOG_TAG_SCAN_ERROR 30 ++#define EVENT_LOG_TAG_SCAN_WARN 31 ++#define EVENT_LOG_TAG_MPF_ERR 32 ++#define EVENT_LOG_TAG_MPF_WARN 33 ++#define EVENT_LOG_TAG_MPF_INFO 34 ++#define EVENT_LOG_TAG_MPF_DEBUG 35 ++#define EVENT_LOG_TAG_EVENT_INFO 36 ++#define EVENT_LOG_TAG_EVENT_ERR 37 ++#define EVENT_LOG_TAG_PWRSTATS_ERROR 38 ++#define EVENT_LOG_TAG_EXCESS_PM_ERROR 39 ++#define EVENT_LOG_TAG_IOCTL_LOG 40 ++#define EVENT_LOG_TAG_PFN_ERR 41 ++#define EVENT_LOG_TAG_PFN_WARN 42 ++#define EVENT_LOG_TAG_PFN_INFO 43 ++#define EVENT_LOG_TAG_PFN_DEBUG 44 ++#define EVENT_LOG_TAG_BEACON_LOG 45 ++#define EVENT_LOG_TAG_WNM_BSSTRANS_INFO 46 ++#define EVENT_LOG_TAG_TRACE_CHANSW 47 ++#define EVENT_LOG_TAG_PCI_ERROR 48 ++#define EVENT_LOG_TAG_PCI_TRACE 49 ++#define EVENT_LOG_TAG_PCI_WARN 50 ++#define EVENT_LOG_TAG_PCI_INFO 51 ++#define EVENT_LOG_TAG_PCI_DBG 52 ++#define EVENT_LOG_TAG_PCI_DATA 53 ++#define EVENT_LOG_TAG_PCI_RING 54 ++/* EVENT_LOG_TAG_AWDL_TRACE_RANGING will be removed after wlc_ranging merge from IGUANA ++ * keeping it here to avoid compilation error on trunk ++ */ ++#define EVENT_LOG_TAG_AWDL_TRACE_RANGING 55 ++#define EVENT_LOG_TAG_RANGING_TRACE 55 ++#define EVENT_LOG_TAG_WL_ERROR 56 ++#define EVENT_LOG_TAG_PHY_ERROR 57 ++#define EVENT_LOG_TAG_OTP_ERROR 58 ++#define EVENT_LOG_TAG_NOTIF_ERROR 59 ++#define EVENT_LOG_TAG_MPOOL_ERROR 60 ++#define EVENT_LOG_TAG_OBJR_ERROR 61 ++#define EVENT_LOG_TAG_DMA_ERROR 62 ++#define EVENT_LOG_TAG_PMU_ERROR 63 ++#define EVENT_LOG_TAG_BSROM_ERROR 64 ++#define EVENT_LOG_TAG_SI_ERROR 65 ++#define EVENT_LOG_TAG_ROM_PRINTF 66 ++#define EVENT_LOG_TAG_RATE_CNT 67 ++#define EVENT_LOG_TAG_CTL_MGT_CNT 68 ++#define EVENT_LOG_TAG_AMPDU_DUMP 69 ++#define EVENT_LOG_TAG_MEM_ALLOC_SUCC 70 ++#define EVENT_LOG_TAG_MEM_ALLOC_FAIL 71 ++#define EVENT_LOG_TAG_MEM_FREE 72 ++#define EVENT_LOG_TAG_WL_ASSOC_LOG 73 ++#define EVENT_LOG_TAG_WL_PS_LOG 74 ++#define EVENT_LOG_TAG_WL_ROAM_LOG 75 ++#define EVENT_LOG_TAG_WL_MPC_LOG 76 ++#define EVENT_LOG_TAG_WL_WSEC_LOG 77 ++#define EVENT_LOG_TAG_WL_WSEC_DUMP 78 ++#define EVENT_LOG_TAG_WL_MCNX_LOG 79 ++#define EVENT_LOG_TAG_HEALTH_CHECK_ERROR 80 ++#define EVENT_LOG_TAG_HNDRTE_EVENT_ERROR 81 ++#define EVENT_LOG_TAG_ECOUNTERS_ERROR 82 ++#define EVENT_LOG_TAG_WL_COUNTERS 83 ++#define EVENT_LOG_TAG_ECOUNTERS_IPCSTATS 84 ++#define EVENT_LOG_TAG_WL_P2P_LOG 85 ++#define EVENT_LOG_TAG_SDIO_ERROR 86 ++#define EVENT_LOG_TAG_SDIO_TRACE 87 ++#define EVENT_LOG_TAG_SDIO_DBG 88 ++#define EVENT_LOG_TAG_SDIO_PRHDRS 89 ++#define EVENT_LOG_TAG_SDIO_PRPKT 90 ++#define EVENT_LOG_TAG_SDIO_INFORM 91 ++#define EVENT_LOG_TAG_MIMO_PS_ERROR 92 ++#define EVENT_LOG_TAG_MIMO_PS_TRACE 93 ++#define EVENT_LOG_TAG_MIMO_PS_INFO 94 ++#define EVENT_LOG_TAG_BTCX_STATS 95 ++#define EVENT_LOG_TAG_LEAKY_AP_STATS 96 ++#define EVENT_LOG_TAG_AWDL_TRACE_ELECTION 97 ++#define EVENT_LOG_TAG_MIMO_PS_STATS 98 ++#define EVENT_LOG_TAG_PWRSTATS_PHY 99 ++#define EVENT_LOG_TAG_PWRSTATS_SCAN 100 ++#define EVENT_LOG_TAG_PWRSTATS_AWDL 101 ++#define EVENT_LOG_TAG_PWRSTATS_WAKE_V2 102 ++#define EVENT_LOG_TAG_LQM 103 ++#define EVENT_LOG_TAG_TRACE_WL_INFO 104 ++#define EVENT_LOG_TAG_TRACE_BTCOEX_INFO 105 ++#define EVENT_LOG_TAG_ECOUNTERS_TIME_DATA 106 ++#define EVENT_LOG_TAG_NAN_ERROR 107 ++#define EVENT_LOG_TAG_NAN_INFO 108 ++#define EVENT_LOG_TAG_NAN_DBG 109 ++#define EVENT_LOG_TAG_STF_ARBITRATOR_ERROR 110 ++#define EVENT_LOG_TAG_STF_ARBITRATOR_TRACE 111 ++#define EVENT_LOG_TAG_STF_ARBITRATOR_WARN 112 ++#define EVENT_LOG_TAG_SCAN_SUMMARY 113 ++#define EVENT_LOG_TAG_PROXD_SAMPLE_COLLECT 114 ++#define EVENT_LOG_TAG_OCL_INFO 115 ++#define EVENT_LOG_TAG_RSDB_PMGR_DEBUG 116 ++#define EVENT_LOG_TAG_RSDB_PMGR_ERR 117 ++#define EVENT_LOG_TAG_NAT_ERR 118 ++#define EVENT_LOG_TAG_NAT_WARN 119 ++#define EVENT_LOG_TAG_NAT_INFO 120 ++#define EVENT_LOG_TAG_NAT_DEBUG 121 ++#define EVENT_LOG_TAG_STA_INFO 122 ++#define EVENT_LOG_TAG_PROXD_ERROR 123 ++#define EVENT_LOG_TAG_PROXD_TRACE 124 ++#define EVENT_LOG_TAG_PROXD_INFO 125 ++#define EVENT_LOG_TAG_IE_ERROR 126 ++#define EVENT_LOG_TAG_ASSOC_ERROR 127 ++#define EVENT_LOG_TAG_SCAN_ERR 128 ++#define EVENT_LOG_TAG_AMSDU_ERROR 129 ++#define EVENT_LOG_TAG_AMPDU_ERROR 130 ++#define EVENT_LOG_TAG_KM_ERROR 131 ++#define EVENT_LOG_TAG_DFS 132 ++#define EVENT_LOG_TAG_REGULATORY 133 ++#define EVENT_LOG_TAG_CSA 134 ++#define EVENT_LOG_TAG_WNM_BSSTRANS_ERR 135 ++#define EVENT_LOG_TAG_SUP_INFO 136 ++#define EVENT_LOG_TAG_SUP_ERROR 137 ++#define EVENT_LOG_TAG_CHANCTXT_TRACE 138 ++#define EVENT_LOG_TAG_CHANCTXT_INFO 139 ++#define EVENT_LOG_TAG_CHANCTXT_ERROR 140 ++#define EVENT_LOG_TAG_CHANCTXT_WARN 141 ++#define EVENT_LOG_TAG_MSCHPROFILE 142 ++#define EVENT_LOG_TAG_4WAYHANDSHAKE 143 ++#define EVENT_LOG_TAG_MSCHPROFILE_TLV 144 ++#define EVENT_LOG_TAG_ADPS 145 ++#define EVENT_LOG_TAG_MBO_DBG 146 ++#define EVENT_LOG_TAG_MBO_INFO 147 ++#define EVENT_LOG_TAG_MBO_ERR 148 ++#define EVENT_LOG_TAG_TXDELAY 149 ++#define EVENT_LOG_TAG_BCNTRIM_INFO 150 ++#define EVENT_LOG_TAG_BCNTRIM_TRACE 151 ++#define EVENT_LOG_TAG_OPS_INFO 152 ++#define EVENT_LOG_TAG_STATS 153 ++#define EVENT_LOG_TAG_BAM 154 ++#define EVENT_LOG_TAG_TXFAIL 155 ++#define EVENT_LOG_TAG_AWDL_CONFIG_DBG 156 ++#define EVENT_LOG_TAG_AWDL_SYNC_DBG 157 ++#define EVENT_LOG_TAG_AWDL_PEER_DBG 158 ++#define EVENT_LOG_TAG_RANDMAC_INFO 159 ++#define EVENT_LOG_TAG_RANDMAC_DBG 160 ++#define EVENT_LOG_TAG_RANDMAC_ERR 161 ++#define EVENT_LOG_TAG_AWDL_DFSP_DBG 162 ++#define EVENT_LOG_TAG_TPA_ERR 163 ++#define EVENT_LOG_TAG_TPA_INFO 164 ++ ++/* EVENT_LOG_TAG_MAX = Set to the same value of last tag, not last tag + 1 */ ++#define EVENT_LOG_TAG_MAX 164 ++/* Note: New event should be added/reserved in trunk before adding it to branches */ ++ ++ ++#define SD_PRHDRS(i, s, h, p, n, l) ++#define SD_PRPKT(m, b, n) ++#define SD_INFORM(args) ++ ++/* Flags for tag control */ ++#define EVENT_LOG_TAG_FLAG_NONE 0 ++#define EVENT_LOG_TAG_FLAG_LOG 0x80 ++#define EVENT_LOG_TAG_FLAG_PRINT 0x40 ++#define EVENT_LOG_TAG_FLAG_SET_MASK 0x3f ++ ++/* Each event log entry has a type. The type is the LAST word of the ++ * event log. The printing code walks the event entries in reverse ++ * order to find the first entry. ++ */ ++typedef union event_log_hdr { ++ struct { ++ uint8 tag; /* Event_log entry tag */ ++ uint8 count; /* Count of 4-byte entries */ ++ uint16 fmt_num; /* Format number */ ++ }; ++ uint32 t; /* Type cheat */ ++} event_log_hdr_t; ++ ++#endif /* _EVENT_LOG_TAG_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/event_trace.h b/module_drivers/drivers/net/wireless/bcmdhd/include/event_trace.h +new file mode 100644 +index 000000000..cd24bdf28 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/event_trace.h +@@ -0,0 +1,123 @@ ++/* ++ * Trace log blocks sent over HBUS ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: event_trace.h 645268 2016-06-23 08:39:17Z $ ++ */ ++ ++/** ++ * @file ++ * @brief ++ * Define the trace event ID and tag ID ++ */ ++ ++#ifndef _WL_DIAG_H ++#define _WL_DIAG_H ++ ++#define DIAG_MAJOR_VERSION 1 /* 4 bits */ ++#define DIAG_MINOR_VERSION 0 /* 4 bits */ ++#define DIAG_MICRO_VERSION 0 /* 4 bits */ ++ ++#define DIAG_VERSION \ ++ ((DIAG_MICRO_VERSION&0xF) | (DIAG_MINOR_VERSION&0xF)<<4 | \ ++ (DIAG_MAJOR_VERSION&0xF)<<8) ++ /* bit[11:8] major ver */ ++ /* bit[7:4] minor ver */ ++ /* bit[3:0] micro ver */ ++ ++/* event ID for trace purpose only, to avoid the conflict with future new ++* WLC_E_ , starting from 0x8000 ++*/ ++#define TRACE_FW_AUTH_STARTED 0x8000 ++#define TRACE_FW_ASSOC_STARTED 0x8001 ++#define TRACE_FW_RE_ASSOC_STARTED 0x8002 ++#define TRACE_G_SCAN_STARTED 0x8003 ++#define TRACE_ROAM_SCAN_STARTED 0x8004 ++#define TRACE_ROAM_SCAN_COMPLETE 0x8005 ++#define TRACE_FW_EAPOL_FRAME_TRANSMIT_START 0x8006 ++#define TRACE_FW_EAPOL_FRAME_TRANSMIT_STOP 0x8007 ++#define TRACE_BLOCK_ACK_NEGOTIATION_COMPLETE 0x8008 /* protocol status */ ++#define TRACE_BT_COEX_BT_SCO_START 0x8009 ++#define TRACE_BT_COEX_BT_SCO_STOP 0x800a ++#define TRACE_BT_COEX_BT_SCAN_START 0x800b ++#define TRACE_BT_COEX_BT_SCAN_STOP 0x800c ++#define TRACE_BT_COEX_BT_HID_START 0x800d ++#define TRACE_BT_COEX_BT_HID_STOP 0x800e ++#define TRACE_ROAM_AUTH_STARTED 0x800f ++/* Event ID for NAN, start from 0x9000 */ ++#define TRACE_NAN_CLUSTER_STARTED 0x9000 ++#define TRACE_NAN_CLUSTER_JOINED 0x9001 ++#define TRACE_NAN_CLUSTER_MERGED 0x9002 ++#define TRACE_NAN_ROLE_CHANGED 0x9003 ++#define TRACE_NAN_SCAN_COMPLETE 0x9004 ++#define TRACE_NAN_STATUS_CHNG 0x9005 ++ ++/* Parameters of wifi logger events are TLVs */ ++/* Event parameters tags are defined as: */ ++#define TRACE_TAG_VENDOR_SPECIFIC 0 /* take a byte stream as parameter */ ++#define TRACE_TAG_BSSID 1 /* takes a 6 bytes MAC address as parameter */ ++#define TRACE_TAG_ADDR 2 /* takes a 6 bytes MAC address as parameter */ ++#define TRACE_TAG_SSID 3 /* takes a 32 bytes SSID address as parameter */ ++#define TRACE_TAG_STATUS 4 /* takes an integer as parameter */ ++#define TRACE_TAG_CHANNEL_SPEC 5 /* takes one or more wifi_channel_spec as */ ++ /* parameter */ ++#define TRACE_TAG_WAKE_LOCK_EVENT 6 /* takes a wake_lock_event struct as parameter */ ++#define TRACE_TAG_ADDR1 7 /* takes a 6 bytes MAC address as parameter */ ++#define TRACE_TAG_ADDR2 8 /* takes a 6 bytes MAC address as parameter */ ++#define TRACE_TAG_ADDR3 9 /* takes a 6 bytes MAC address as parameter */ ++#define TRACE_TAG_ADDR4 10 /* takes a 6 bytes MAC address as parameter */ ++#define TRACE_TAG_TSF 11 /* take a 64 bits TSF value as parameter */ ++#define TRACE_TAG_IE 12 /* take one or more specific 802.11 IEs */ ++ /* parameter, IEs are in turn indicated in */ ++ /* TLV format as per 802.11 spec */ ++#define TRACE_TAG_INTERFACE 13 /* take interface name as parameter */ ++#define TRACE_TAG_REASON_CODE 14 /* take a reason code as per 802.11 */ ++ /* as parameter */ ++#define TRACE_TAG_RATE_MBPS 15 /* take a wifi rate in 0.5 mbps */ ++#define TRACE_TAG_REQUEST_ID 16 /* take an integer as parameter */ ++#define TRACE_TAG_BUCKET_ID 17 /* take an integer as parameter */ ++#define TRACE_TAG_GSCAN_PARAMS 18 /* takes a wifi_scan_cmd_params struct as parameter */ ++#define TRACE_TAG_GSCAN_CAPABILITIES 19 /* takes a wifi_gscan_capabilities struct as parameter */ ++#define TRACE_TAG_SCAN_ID 20 /* take an integer as parameter */ ++#define TRACE_TAG_RSSI 21 /* take an integer as parameter */ ++#define TRACE_TAG_CHANNEL 22 /* take an integer as parameter */ ++#define TRACE_TAG_LINK_ID 23 /* take an integer as parameter */ ++#define TRACE_TAG_LINK_ROLE 24 /* take an integer as parameter */ ++#define TRACE_TAG_LINK_STATE 25 /* take an integer as parameter */ ++#define TRACE_TAG_LINK_TYPE 26 /* take an integer as parameter */ ++#define TRACE_TAG_TSCO 27 /* take an integer as parameter */ ++#define TRACE_TAG_RSCO 28 /* take an integer as parameter */ ++#define TRACE_TAG_EAPOL_MESSAGE_TYPE 29 /* take an integer as parameter */ ++ /* M1-1, M2-2, M3-3, M4-4 */ ++ ++typedef union { ++ struct { ++ uint16 event: 16; ++ uint16 version: 16; ++ }; ++ uint32 t; ++} wl_event_log_id_ver_t; ++ ++#endif /* _WL_DIAG_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_armtrap.h b/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_armtrap.h +new file mode 100644 +index 000000000..e7c005c6f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_armtrap.h +@@ -0,0 +1,90 @@ ++/* ++ * HND arm trap handling. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: hnd_armtrap.h 545867 2015-04-01 22:45:19Z $ ++ */ ++ ++#ifndef _hnd_armtrap_h_ ++#define _hnd_armtrap_h_ ++ ++ ++/* ARM trap handling */ ++ ++/* Trap types defined by ARM (see arminc.h) */ ++ ++/* Trap locations in lo memory */ ++#define TRAP_STRIDE 4 ++#define FIRST_TRAP TR_RST ++#define LAST_TRAP (TR_FIQ * TRAP_STRIDE) ++ ++#if 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 ++#define ASSERT_TRAP_SVC_NUMBER 255 ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++#include ++ ++typedef struct _trap_struct { ++ uint32 type; ++ uint32 epc; ++ uint32 cpsr; ++ uint32 spsr; ++ uint32 r0; /* a1 */ ++ uint32 r1; /* a2 */ ++ uint32 r2; /* a3 */ ++ uint32 r3; /* a4 */ ++ uint32 r4; /* v1 */ ++ uint32 r5; /* v2 */ ++ uint32 r6; /* v3 */ ++ uint32 r7; /* v4 */ ++ uint32 r8; /* v5 */ ++ uint32 r9; /* sb/v6 */ ++ uint32 r10; /* sl/v7 */ ++ uint32 r11; /* fp/v8 */ ++ uint32 r12; /* ip */ ++ uint32 r13; /* sp */ ++ uint32 r14; /* lr */ ++ uint32 pc; /* r15 */ ++} trap_t; ++ ++#endif /* !_LANGUAGE_ASSEMBLY */ ++ ++#endif /* _hnd_armtrap_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_cons.h b/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_cons.h +new file mode 100644 +index 000000000..3470d6a91 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_cons.h +@@ -0,0 +1,84 @@ ++/* ++ * Console support for RTE - for host use only. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: hnd_cons.h 568961 2015-07-06 18:14:49Z $ ++ */ ++#ifndef _hnd_cons_h_ ++#define _hnd_cons_h_ ++ ++#include ++#include ++ ++#define CBUF_LEN (128) ++ ++#if defined(BCM_BIG_LOG) ++#define LOG_BUF_LEN (16 * 1024) ++#else ++#define LOG_BUF_LEN 1024 ++#endif ++ ++#ifdef BOOTLOADER_CONSOLE_OUTPUT ++#undef RWL_MAX_DATA_LEN ++#undef CBUF_LEN ++#undef LOG_BUF_LEN ++#define RWL_MAX_DATA_LEN (4 * 1024 + 8) ++#define CBUF_LEN (RWL_MAX_DATA_LEN + 64) ++#define LOG_BUF_LEN (16 * 1024) ++#endif ++ ++typedef struct { ++ uint32 buf; /* Can't be pointer on (64-bit) hosts */ ++ uint buf_size; ++ uint idx; ++ uint out_idx; /* output index */ ++} hnd_log_t; ++ ++typedef struct { ++ /* Virtual UART ++ * When there is no UART (e.g. Quickturn), the host should write a complete ++ * input line directly into cbuf and then write the length into vcons_in. ++ * This may also be used when there is a real UART (at risk of conflicting with ++ * the real UART). vcons_out is currently unused. ++ */ ++ volatile uint vcons_in; ++ volatile uint vcons_out; ++ ++ /* Output (logging) buffer ++ * Console output is written to a ring buffer log_buf at index log_idx. ++ * The host may read the output when it sees log_idx advance. ++ * Output will be lost if the output wraps around faster than the host polls. ++ */ ++ hnd_log_t log; ++ ++ /* Console input line buffer ++ * Characters are read one at a time into cbuf until is received, then ++ * the buffer is processed as a command line. Also used for virtual UART. ++ */ ++ uint cbuf_idx; ++ char cbuf[CBUF_LEN]; ++} hnd_cons_t; ++ ++#endif /* _hnd_cons_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_debug.h b/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_debug.h +new file mode 100644 +index 000000000..239e596e9 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_debug.h +@@ -0,0 +1,206 @@ ++/* ++ * HND Run Time Environment debug info area ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: hnd_debug.h 678890 2017-01-11 11:48:36Z $ ++ */ ++ ++#ifndef _HND_DEBUG_H ++#define _HND_DEBUG_H ++ ++/* Magic number at a magic location to find HND_DEBUG pointers */ ++#define HND_DEBUG_PTR_PTR_MAGIC 0x50504244 /* DBPP */ ++ ++/* Magic number at a magic location to find RAM size */ ++#define HND_RAMSIZE_PTR_MAGIC 0x534d4152 /* RAMS */ ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++/* Includes only when building dongle code */ ++ ++ ++/* We use explicit sizes here since this gets included from different ++ * systems. The sizes must be the size of the creating system ++ * (currently 32 bit ARM) since this is gleaned from dump. ++ */ ++ ++#ifdef FWID ++extern uint32 gFWID; ++#endif ++ ++/* Define pointers for use on other systems */ ++#define _HD_EVLOG_P uint32 ++#define _HD_CONS_P uint32 ++#define _HD_TRAP_P uint32 ++ ++/* This struct is placed at a well-defined location, and contains a pointer to hnd_debug. */ ++typedef struct hnd_debug_ptr { ++ uint32 magic; ++ ++ /* RAM address of 'hnd_debug'. For legacy versions of this struct, it is a 0-indexed ++ * offset instead. ++ */ ++ uint32 hnd_debug_addr; ++ ++ /* Base address of RAM. This field does not exist for legacy versions of this struct. */ ++ uint32 ram_base_addr; ++ ++} hnd_debug_ptr_t; ++ ++/* This struct is placed at a well-defined location. */ ++typedef struct hnd_ramsize_ptr { ++ uint32 magic; /* 'RAMS' */ ++ ++ /* RAM size information. */ ++ uint32 ram_size; ++} hnd_ramsize_ptr_t; ++ ++#define HND_DEBUG_EPIVERS_MAX_STR_LEN 32 ++#define HND_DEBUG_BUILD_SIGNATURE_FWID_LEN 17 ++#define HND_DEBUG_BUILD_SIGNATURE_VER_LEN 22 ++typedef struct hnd_debug { ++ uint32 magic; ++#define HND_DEBUG_MAGIC 0x47424544 /* 'DEBG' */ ++ ++ uint32 version; /* Debug struct version */ ++#define HND_DEBUG_VERSION 1 ++ ++ uint32 fwid; /* 4 bytes of fw info */ ++ char epivers[HND_DEBUG_EPIVERS_MAX_STR_LEN]; ++ ++ _HD_TRAP_P trap_ptr; /* trap_t data struct */ ++ _HD_CONS_P console; /* Console */ ++ ++ uint32 ram_base; ++ uint32 ram_size; ++ ++ uint32 rom_base; ++ uint32 rom_size; ++ ++ _HD_EVLOG_P event_log_top; ++ ++ /* To populated fields below, ++ * INCLUDE_BUILD_SIGNATURE_IN_SOCRAM needs to be enabled ++ */ ++ char fwid_signature[HND_DEBUG_BUILD_SIGNATURE_FWID_LEN]; /* fwid= */ ++ char ver_signature[HND_DEBUG_BUILD_SIGNATURE_VER_LEN]; /* ver=abc.abc.abc.abc */ ++ ++} hnd_debug_t; ++ ++/* ++ * timeval_t and prstatus_t are copies of the Linux structures. ++ * Included here because we need the definitions for the target processor ++ * (32 bits) and not the definition on the host this is running on ++ * (which could be 64 bits). ++ */ ++ ++typedef struct { /* Time value with microsecond resolution */ ++ uint32 tv_sec; /* Seconds */ ++ uint32 tv_usec; /* Microseconds */ ++} timeval_t; ++ ++ ++/* Linux/ARM 32 prstatus for notes section */ ++typedef struct prstatus { ++ int32 si_signo; /* Signal number */ ++ int32 si_code; /* Extra code */ ++ int32 si_errno; /* Errno */ ++ uint16 pr_cursig; /* Current signal. */ ++ uint16 unused; ++ uint32 pr_sigpend; /* Set of pending signals. */ ++ uint32 pr_sighold; /* Set of held signals. */ ++ uint32 pr_pid; ++ uint32 pr_ppid; ++ uint32 pr_pgrp; ++ uint32 pr_sid; ++ timeval_t pr_utime; /* User time. */ ++ timeval_t pr_stime; /* System time. */ ++ timeval_t pr_cutime; /* Cumulative user time. */ ++ timeval_t pr_cstime; /* Cumulative system time. */ ++ uint32 uregs[18]; ++ int32 pr_fpvalid; /* True if math copro being used. */ ++} prstatus_t; ++ ++/* for mkcore and other utilities use */ ++#define DUMP_INFO_PTR_PTR_0 0x74 ++#define DUMP_INFO_PTR_PTR_1 0x78 ++#define DUMP_INFO_PTR_PTR_2 0xf0 ++#define DUMP_INFO_PTR_PTR_3 0xf8 ++#define DUMP_INFO_PTR_PTR_4 0x874 ++#define DUMP_INFO_PTR_PTR_5 0x878 ++#define DUMP_INFO_PTR_PTR_END 0xffffffff ++#define DUMP_INFO_PTR_PTR_LIST DUMP_INFO_PTR_PTR_0, \ ++ DUMP_INFO_PTR_PTR_1, \ ++ DUMP_INFO_PTR_PTR_2, \ ++ DUMP_INFO_PTR_PTR_3, \ ++ DUMP_INFO_PTR_PTR_4, \ ++ DUMP_INFO_PTR_PTR_5, \ ++ DUMP_INFO_PTR_PTR_END ++ ++/* for DHD driver to get dongle ram size info. */ ++#define RAMSIZE_PTR_PTR_0 0x6c ++#define RAMSIZE_PTR_PTR_END 0xffffffff ++#define RAMSIZE_PTR_PTR_LIST RAMSIZE_PTR_PTR_0, \ ++ RAMSIZE_PTR_PTR_END ++ ++typedef struct hnd_ext_trap_hdr { ++ uint8 version; /* Extended trap version info */ ++ uint8 reserved; /* currently unused */ ++ uint16 len; /* Length of data excluding this header */ ++ uint8 data[]; /* TLV data */ ++} hnd_ext_trap_hdr_t; ++ ++#define TAG_TRAP_SIGNATURE 1 /* Processor register dumps */ ++#define TAG_TRAP_STACK 2 /* Processor stack dump (possible code locations) */ ++#define TAG_TRAP_MEMORY 3 /* Memory subsystem dump */ ++#define TAG_TRAP_DEEPSLEEP 4 /* Deep sleep health check failures */ ++#define TAG_TRAP_PSM_WD 5 /* PSM watchdog information */ ++#define TAG_TRAP_PHY 6 /* Phy related issues */ ++#define TAG_TRAP_BUS 7 /* Bus level issues */ ++#define TAG_TRAP_MAC 8 /* Mac level issues */ ++#define TAG_TRAP_BACKPLANE 9 /* Backplane related errors */ ++ ++typedef struct hnd_ext_trap_bp_err ++{ ++ uint32 error; ++ uint32 coreid; ++ uint32 baseaddr; ++ uint32 ioctrl; ++ uint32 iostatus; ++ uint32 resetctrl; ++ uint32 resetstatus; ++ uint32 errlogctrl; ++ uint32 errlogdone; ++ uint32 errlogstatus; ++ uint32 errlogaddrlo; ++ uint32 errlogaddrhi; ++ uint32 errlogid; ++ uint32 errloguser; ++ uint32 errlogflags; ++} hnd_ext_trap_bp_err_t; ++ ++#endif /* !LANGUAGE_ASSEMBLY */ ++ ++#endif /* _HND_DEBUG_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_pktpool.h b/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_pktpool.h +new file mode 100644 +index 000000000..e5d0eaa65 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_pktpool.h +@@ -0,0 +1,225 @@ ++/* ++ * HND generic packet pool operation primitives ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: hnd_pktpool.h 613891 2016-01-20 10:05:44Z $ ++ */ ++ ++#ifndef _hnd_pktpool_h_ ++#define _hnd_pktpool_h_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* mutex macros for thread safe */ ++#ifdef HND_PKTPOOL_THREAD_SAFE ++#define HND_PKTPOOL_MUTEX_DECL(mutex) OSL_EXT_MUTEX_DECL(mutex) ++#else ++#define HND_PKTPOOL_MUTEX_DECL(mutex) ++#endif ++ ++#ifdef BCMPKTPOOL ++#define POOL_ENAB(pool) ((pool) && (pool)->inited) ++#else /* BCMPKTPOOL */ ++#define POOL_ENAB(bus) 0 ++#endif /* BCMPKTPOOL */ ++ ++#ifndef PKTPOOL_LEN_MAX ++#define PKTPOOL_LEN_MAX 40 ++#endif /* PKTPOOL_LEN_MAX */ ++#define PKTPOOL_CB_MAX 3 ++#define PKTPOOL_CB_MAX_AVL 4 ++ ++ ++/* forward declaration */ ++struct pktpool; ++ ++typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); ++typedef struct { ++ pktpool_cb_t cb; ++ void *arg; ++} pktpool_cbinfo_t; ++ ++/** PCIe SPLITRX related: call back fn extension to populate host address in pool pkt */ ++typedef int (*pktpool_cb_extn_t)(struct pktpool *pool, void *arg1, void* pkt, bool arg2); ++typedef struct { ++ pktpool_cb_extn_t cb; ++ void *arg; ++} pktpool_cbextn_info_t; ++ ++ ++#ifdef BCMDBG_POOL ++/* pkt pool debug states */ ++#define POOL_IDLE 0 ++#define POOL_RXFILL 1 ++#define POOL_RXDH 2 ++#define POOL_RXD11 3 ++#define POOL_TXDH 4 ++#define POOL_TXD11 5 ++#define POOL_AMPDU 6 ++#define POOL_TXENQ 7 ++ ++typedef struct { ++ void *p; ++ uint32 cycles; ++ uint32 dur; ++} pktpool_dbg_t; ++ ++typedef struct { ++ uint8 txdh; /* tx to host */ ++ uint8 txd11; /* tx to d11 */ ++ uint8 enq; /* waiting in q */ ++ uint8 rxdh; /* rx from host */ ++ uint8 rxd11; /* rx from d11 */ ++ uint8 rxfill; /* dma_rxfill */ ++ uint8 idle; /* avail in pool */ ++} pktpool_stats_t; ++#endif /* BCMDBG_POOL */ ++ ++typedef struct pktpool { ++ bool inited; /**< pktpool_init was successful */ ++ uint8 type; /**< type of lbuf: basic, frag, etc */ ++ uint8 id; /**< pktpool ID: index in registry */ ++ bool istx; /**< direction: transmit or receive data path */ ++ HND_PKTPOOL_MUTEX_DECL(mutex) /**< thread-safe mutex */ ++ ++ void * freelist; /**< free list: see PKTNEXTFREE(), PKTSETNEXTFREE() */ ++ uint16 avail; /**< number of packets in pool's free list */ ++ uint16 len; /**< number of packets managed by pool */ ++ uint16 maxlen; /**< maximum size of pool <= PKTPOOL_LEN_MAX */ ++ uint16 plen; /**< size of pkt buffer in [bytes], excluding lbuf|lbuf_frag */ ++ ++ bool empty; ++ uint8 cbtoggle; ++ uint8 cbcnt; ++ uint8 ecbcnt; ++ uint8 emptycb_disable; /**< Value of type enum pktpool_empty_cb_state */ ++ pktpool_cbinfo_t *availcb_excl; ++ pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX_AVL]; ++ pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; ++ pktpool_cbextn_info_t cbext; /**< PCIe SPLITRX related */ ++ pktpool_cbextn_info_t rxcplidfn; ++#ifdef BCMDBG_POOL ++ uint8 dbg_cbcnt; ++ pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; ++ uint16 dbg_qlen; ++ pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; ++#endif ++ pktpool_cbinfo_t dmarxfill; ++} pktpool_t; ++ ++ ++pktpool_t *get_pktpools_registry(int id); ++ ++/* Incarnate a pktpool registry. On success returns total_pools. */ ++extern int pktpool_attach(osl_t *osh, uint32 total_pools); ++extern int pktpool_dettach(osl_t *osh); /* Relinquish registry */ ++ ++extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx, uint8 type); ++extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); ++extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); ++extern void* pktpool_get(pktpool_t *pktp); ++extern void pktpool_free(pktpool_t *pktp, void *p); ++extern int pktpool_add(pktpool_t *pktp, void *p); ++extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); ++extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); ++extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); ++extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); ++extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); ++extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); ++extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); ++extern bool pktpool_emptycb_disabled(pktpool_t *pktp); ++extern int pktpool_hostaddr_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg1); ++extern int pktpool_rxcplid_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg); ++extern void pktpool_invoke_dmarxfill(pktpool_t *pktp); ++extern int pkpool_haddr_avail_register_cb(pktpool_t *pktp, pktpool_cb_t cb, void *arg); ++ ++#define POOLPTR(pp) ((pktpool_t *)(pp)) ++#define POOLID(pp) (POOLPTR(pp)->id) ++ ++#define POOLSETID(pp, ppid) (POOLPTR(pp)->id = (ppid)) ++ ++#define pktpool_len(pp) (POOLPTR(pp)->len) /**< returns packet length in [bytes] */ ++#define pktpool_avail(pp) (POOLPTR(pp)->avail) ++#define pktpool_plen(pp) (POOLPTR(pp)->plen) ++#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) ++ ++ ++/* ++ * ---------------------------------------------------------------------------- ++ * A pool ID is assigned with a pkt pool during pool initialization. This is ++ * done by maintaining a registry of all initialized pools, and the registry ++ * index at which the pool is registered is used as the pool's unique ID. ++ * ID 0 is reserved and is used to signify an invalid pool ID. ++ * All packets henceforth allocated from a pool will be tagged with the pool's ++ * unique ID. Packets allocated from the heap will use the reserved ID = 0. ++ * Packets with non-zero pool id signify that they were allocated from a pool. ++ * A maximum of 15 pools are supported, allowing a 4bit pool ID to be used ++ * in place of a 32bit pool pointer in each packet. ++ * ---------------------------------------------------------------------------- ++ */ ++#define PKTPOOL_INVALID_ID (0) ++#define PKTPOOL_MAXIMUM_ID (15) ++ ++/* Registry of pktpool(s) */ ++/* Pool ID to/from Pool Pointer converters */ ++#define PKTPOOL_ID2PTR(id) (get_pktpools_registry(id)) ++#define PKTPOOL_PTR2ID(pp) (POOLID(pp)) ++ ++#ifdef BCMDBG_POOL ++extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); ++extern int pktpool_start_trigger(pktpool_t *pktp, void *p); ++extern int pktpool_dbg_dump(pktpool_t *pktp); ++extern int pktpool_dbg_notify(pktpool_t *pktp); ++extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); ++#endif /* BCMDBG_POOL */ ++ ++#ifdef BCMPKTPOOL ++#define SHARED_POOL (pktpool_shared) ++extern pktpool_t *pktpool_shared; ++#ifdef BCMFRAGPOOL ++#define SHARED_FRAG_POOL (pktpool_shared_lfrag) ++extern pktpool_t *pktpool_shared_lfrag; ++#endif ++ ++/** PCIe SPLITRX related */ ++#define SHARED_RXFRAG_POOL (pktpool_shared_rxlfrag) ++extern pktpool_t *pktpool_shared_rxlfrag; ++ ++int hnd_pktpool_init(osl_t *osh); ++int hnd_pktpool_fill(pktpool_t *pktpool, bool minimal); ++void hnd_pktpool_refill(bool minimal); ++#else /* BCMPKTPOOL */ ++#define SHARED_POOL ((struct pktpool *)NULL) ++#endif /* BCMPKTPOOL */ ++ ++#ifdef __cplusplus ++ } ++#endif ++ ++#endif /* _hnd_pktpool_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_pktq.h b/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_pktq.h +new file mode 100644 +index 000000000..ad778da89 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/hnd_pktq.h +@@ -0,0 +1,284 @@ ++/* ++ * HND generic pktq operation primitives ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: hnd_pktq.h 641285 2016-06-02 02:33:55Z $ ++ */ ++ ++#ifndef _hnd_pktq_h_ ++#define _hnd_pktq_h_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* mutex macros for thread safe */ ++#ifdef HND_PKTQ_THREAD_SAFE ++#define HND_PKTQ_MUTEX_DECL(mutex) OSL_EXT_MUTEX_DECL(mutex) ++#else ++#define HND_PKTQ_MUTEX_DECL(mutex) ++#endif ++ ++/* osl multi-precedence packet queue */ ++#define PKTQ_LEN_MAX 0xFFFF /* Max uint16 65535 packets */ ++#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 ++ ++typedef struct pktq_prec { ++ void *head; /**< first packet to dequeue */ ++ void *tail; /**< last packet to dequeue */ ++ uint16 len; /**< number of queued packets */ ++ uint16 max; /**< maximum number of queued packets */ ++} pktq_prec_t; ++ ++#ifdef PKTQ_LOG ++typedef struct { ++ uint32 requested; /**< packets requested to be stored */ ++ uint32 stored; /**< packets stored */ ++ uint32 saved; /**< packets saved, ++ because a lowest priority queue has given away one packet ++ */ ++ uint32 selfsaved; /**< packets saved, ++ because an older packet from the same queue has been dropped ++ */ ++ uint32 full_dropped; /**< packets dropped, ++ because pktq is full with higher precedence packets ++ */ ++ uint32 dropped; /**< packets dropped because pktq per that precedence is full */ ++ uint32 sacrificed; /**< packets dropped, ++ in order to save one from a queue of a highest priority ++ */ ++ uint32 busy; /**< packets droped because of hardware/transmission error */ ++ uint32 retry; /**< packets re-sent because they were not received */ ++ uint32 ps_retry; /**< packets retried again prior to moving power save mode */ ++ uint32 suppress; /**< packets which were suppressed and not transmitted */ ++ uint32 retry_drop; /**< packets finally dropped after retry limit */ ++ uint32 max_avail; /**< the high-water mark of the queue capacity for packets - ++ goes to zero as queue fills ++ */ ++ uint32 max_used; /**< the high-water mark of the queue utilisation for packets - ++ increases with use ('inverse' of max_avail) ++ */ ++ uint32 queue_capacity; /**< the maximum capacity of the queue */ ++ uint32 rtsfail; /**< count of rts attempts that failed to receive cts */ ++ uint32 acked; /**< count of packets sent (acked) successfully */ ++ uint32 txrate_succ; /**< running total of phy rate of packets sent successfully */ ++ uint32 txrate_main; /**< running totoal of primary phy rate of all packets */ ++ uint32 throughput; /**< actual data transferred successfully */ ++ uint32 airtime; /**< cumulative total medium access delay in useconds */ ++ uint32 _logtime; /**< timestamp of last counter clear */ ++} pktq_counters_t; ++ ++#define PKTQ_LOG_COMMON \ ++ uint32 pps_time; /**< time spent in ps pretend state */ \ ++ uint32 _prec_log; ++ ++typedef struct { ++ PKTQ_LOG_COMMON ++ pktq_counters_t* _prec_cnt[PKTQ_MAX_PREC]; /**< Counters per queue */ ++} pktq_log_t; ++#else ++typedef struct pktq_log pktq_log_t; ++#endif /* PKTQ_LOG */ ++ ++ ++#define PKTQ_COMMON \ ++ HND_PKTQ_MUTEX_DECL(mutex) \ ++ pktq_log_t *pktqlog; \ ++ uint16 num_prec; /**< number of precedences in use */ \ ++ uint16 hi_prec; /**< rapid dequeue hint (>= highest non-empty prec) */ \ ++ uint16 max; /**< total max packets */ \ ++ uint16 len; /**< total number of packets */ ++ ++/* multi-priority pkt queue */ ++struct pktq { ++ PKTQ_COMMON ++ /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ ++ struct pktq_prec q[PKTQ_MAX_PREC]; ++}; ++ ++/* simple, non-priority pkt queue */ ++struct spktq { ++ PKTQ_COMMON ++ /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ ++ struct pktq_prec q[1]; ++}; ++ ++#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) ++ ++/* fn(pkt, arg). return true if pkt belongs to bsscfg */ ++typedef bool (*ifpkt_cb_t)(void*, int); ++ ++/* ++ * pktq filter support ++ */ ++ ++/* filter function return values */ ++typedef enum { ++ PKT_FILTER_NOACTION = 0, /**< restore the pkt to its position in the queue */ ++ PKT_FILTER_DELETE = 1, /**< delete the pkt */ ++ PKT_FILTER_REMOVE = 2, /**< do not restore the pkt to the queue, ++ * filter fn has taken ownership of the pkt ++ */ ++} pktq_filter_result_t; ++ ++/** ++ * Caller supplied filter function to pktq_pfilter(), pktq_filter(). ++ * Function filter(ctx, pkt) is called with its ctx pointer on each pkt in the ++ * pktq. When the filter function is called, the supplied pkt will have been ++ * unlinked from the pktq. The filter function returns a pktq_filter_result_t ++ * result specifying the action pktq_filter()/pktq_pfilter() should take for ++ * the pkt. ++ * Here are the actions taken by pktq_filter/pfilter() based on the supplied ++ * filter function's return value: ++ * ++ * PKT_FILTER_NOACTION - The filter will re-link the pkt at its ++ * previous location. ++ * ++ * PKT_FILTER_DELETE - The filter will not relink the pkt and will ++ * call the user supplied defer_free_pkt fn on the packet. ++ * ++ * PKT_FILTER_REMOVE - The filter will not relink the pkt. The supplied ++ * filter fn took ownership (or deleted) the pkt. ++ * ++ * WARNING: pkts inserted by the user (in pkt_filter and/or flush callbacks ++ * and chains) in the prec queue will not be seen by the filter, and the prec ++ * queue will be temporarily be removed from the queue hence there're side ++ * effects including pktq_len() on the queue won't reflect the correct number ++ * of packets in the queue. ++ */ ++typedef pktq_filter_result_t (*pktq_filter_t)(void* ctx, void* pkt); ++ ++/* The defer_free_pkt callback is invoked when the the pktq_filter callback ++ * returns PKT_FILTER_DELETE decision, which allows the user to deposite ++ * the packet appropriately based on the situation (free the packet or ++ * save it in a temporary queue etc.). ++ */ ++typedef void (*defer_free_pkt_fn_t)(void *ctx, void *pkt); ++ ++/* The flush_free_pkt callback is invoked when all packets in the pktq ++ * are processed. ++ */ ++typedef void (*flush_free_pkt_fn_t)(void *ctx); ++ ++/* filter a pktq, using the caller supplied filter/deposition/flush functions */ ++extern void pktq_filter(struct pktq *pq, pktq_filter_t fn, void* arg, ++ defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx); ++/* filter a particular precedence in pktq, using the caller supplied filter function */ ++extern void pktq_pfilter(struct pktq *pq, int prec, pktq_filter_t fn, void* arg, ++ defer_free_pkt_fn_t defer, void *defer_ctx, flush_free_pkt_fn_t flush, void *flush_ctx); ++ ++/* operations on a specific precedence in packet queue */ ++ ++#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) ++#define pktq_pmax(pq, prec) ((pq)->q[prec].max) ++#define pktq_plen(pq, prec) ((pq)->q[prec].len) ++#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) ++#define pktq_ppeek(pq, prec) ((pq)->q[prec].head) ++#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) ++#ifdef HND_PKTQ_THREAD_SAFE ++extern int pktq_pavail(struct pktq *pq, int prec); ++extern bool pktq_pfull(struct pktq *pq, int prec); ++#else ++#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) ++#endif /* HND_PKTQ_THREAD_SAFE */ ++ ++extern void pktq_append(struct pktq *pq, int prec, struct spktq *list); ++extern void pktq_prepend(struct pktq *pq, int prec, struct spktq *list); ++ ++extern void *pktq_penq(struct pktq *pq, int prec, void *p); ++extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); ++extern void *pktq_pdeq(struct pktq *pq, int prec); ++extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); ++extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg); ++extern void *pktq_pdeq_tail(struct pktq *pq, int prec); ++/* Remove a specified packet from its queue */ ++extern bool pktq_pdel(struct pktq *pq, void *p, int prec); ++ ++/* operations on a set of precedences in packet queue */ ++ ++extern int pktq_mlen(struct pktq *pq, uint prec_bmp); ++extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); ++extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); ++ ++/* operations on packet queue as a whole */ ++ ++#define pktq_len(pq) ((int)(pq)->len) ++#define pktq_max(pq) ((int)(pq)->max) ++#define pktq_empty(pq) ((pq)->len == 0) ++#ifdef HND_PKTQ_THREAD_SAFE ++extern int pktq_avail(struct pktq *pq); ++extern bool pktq_full(struct pktq *pq); ++#else ++#define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) ++#define pktq_full(pq) ((pq)->len >= (pq)->max) ++#endif /* HND_PKTQ_THREAD_SAFE */ ++ ++/* operations for single precedence queues */ ++#define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) ++#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) ++#define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) ++#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) ++#define pktqflush(osh, pq, dir) pktq_pflush(osh, ((struct pktq *)(void *)pq), 0, dir) ++#define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) ++#define pktqdeinit(pq) pktq_deinit((struct pktq *)(void *)pq) ++#define pktqavail(pq) pktq_avail((struct pktq *)(void *)pq) ++#define pktqfull(pq) pktq_full((struct pktq *)(void *)pq) ++#define pktqfilter(pq, fltr, fltr_ctx, defer, defer_ctx, flush, flush_ctx) \ ++ pktq_pfilter((struct pktq *)pq, 0, fltr, fltr_ctx, defer, defer_ctx, flush, flush_ctx) ++ ++/* wrap macros for modules in components use */ ++#define spktqinit(pq, max_pkts) pktqinit(pq, max_pkts) ++#define spktenq(pq, p) pktenq(pq, p) ++#define spktdeq(pq) pktdeq(pq) ++ ++extern bool pktq_init(struct pktq *pq, int num_prec, int max_len); ++extern bool pktq_deinit(struct pktq *pq); ++ ++extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); ++ ++/* prec_out may be NULL if caller is not interested in return value */ ++extern void *pktq_deq(struct pktq *pq, int *prec_out); ++extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); ++extern void *pktq_peek(struct pktq *pq, int *prec_out); ++extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); ++ ++/* flush pktq */ ++extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir); ++/* Empty the queue at particular precedence level */ ++extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _hnd_pktq_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/hndpmu.h b/module_drivers/drivers/net/wireless/bcmdhd/include/hndpmu.h +new file mode 100644 +index 000000000..bfc916693 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/hndpmu.h +@@ -0,0 +1,56 @@ ++/* ++ * HND SiliconBackplane PMU support. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: hndpmu.h 657872 2016-09-02 22:17:34Z $ ++ */ ++ ++#ifndef _hndpmu_h_ ++#define _hndpmu_h_ ++ ++#include ++#include ++#include ++#include ++ ++ ++extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on, uint32* min_res_mask); ++extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength); ++ ++extern void si_pmu_minresmask_htavail_set(si_t *sih, osl_t *osh, bool set_clear); ++extern void si_pmu_slow_clk_reinit(si_t *sih, osl_t *osh); ++extern void si_pmu_avbtimer_enable(si_t *sih, osl_t *osh, bool set_flag); ++extern uint32 si_pmu_dump_pmucap_binary(si_t *sih, uchar *p); ++extern uint32 si_pmu_dump_buf_size_pmucap(si_t *sih); ++extern int si_pmu_wait_for_steady_state(si_t *sih, osl_t *osh, pmuregs_t *pmu); ++#if defined(BCMULP) ++int si_pmu_ulp_register(si_t *sih); ++extern void si_pmu_ulp_ilp_config(si_t *sih, osl_t *osh, uint32 ilp_period); ++#endif /* BCMULP */ ++extern uint32 si_pmu_get_pmutimer(si_t *sih); ++extern void si_pmu_set_min_res_mask(si_t *sih, osl_t *osh, uint min_res_mask); ++extern bool si_pmu_cap_fast_lpo(si_t *sih); ++extern int si_pmu_fast_lpo_disable(si_t *sih); ++#endif /* _hndpmu_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/hndsoc.h b/module_drivers/drivers/net/wireless/bcmdhd/include/hndsoc.h +new file mode 100644 +index 000000000..b35380ad5 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/hndsoc.h +@@ -0,0 +1,327 @@ ++/* ++ * Broadcom HND chip & on-chip-interconnect-related definitions. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: hndsoc.h 613129 2016-01-17 09:25:52Z $ ++ */ ++ ++#ifndef _HNDSOC_H ++#define _HNDSOC_H ++ ++/* Include the soci specific files */ ++#include ++#include ++ ++/* ++ * SOC Interconnect Address Map. ++ * All regions may not exist on all chips. ++ */ ++#define SI_SDRAM_BASE 0x00000000 /* Physical SDRAM */ ++#define SI_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */ ++#define SI_PCI_MEM_SZ (64 * 1024 * 1024) ++#define SI_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */ ++#define SI_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */ ++#define SI_SDRAM_R2 0x80000000 /* Region 2 for sdram (512 MB) */ ++ ++#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ ++#define SI_WRAP_BASE 0x18100000 /* Wrapper space base */ ++#define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */ ++ ++#ifndef SI_MAXCORES ++#define SI_MAXCORES 32 /* NorthStar has more cores */ ++#endif /* SI_MAXCORES */ ++ ++#define SI_MAXBR 4 /* Max bridges (this is arbitrary, for software ++ * convenience and could be changed if we ++ * make any larger chips ++ */ ++ ++#define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */ ++#define SI_FASTRAM_SWAPPED 0x19800000 ++ ++#define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */ ++#define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */ ++#define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */ ++#define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */ ++#define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */ ++#define SI_FLASH_WINDOW 0x01000000 /* Flash XIP Window */ ++ ++#define SI_NS_NANDFLASH 0x1c000000 /* NorthStar NAND flash base */ ++#define SI_NS_NORFLASH 0x1e000000 /* NorthStar NOR flash base */ ++#define SI_NS_ROM 0xfffd0000 /* NorthStar ROM */ ++#define SI_NS_FLASH_WINDOW 0x02000000 /* Flash XIP Window */ ++ ++#define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */ ++#define SI_ARMCR4_ROM 0x000f0000 /* ARM Cortex-R4 ROM */ ++#define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */ ++#define SI_ARM7S_SRAM2 0x80000000 /* ARM7TDMI-S SRAM Region 2 */ ++#define SI_ARMCA7_ROM 0x00000000 /* ARM Cortex-A7 ROM */ ++#define SI_ARMCA7_RAM 0x00200000 /* ARM Cortex-A7 RAM */ ++#define SI_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */ ++#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */ ++ ++#define SI_SFLASH 0x14000000 ++#define SI_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */ ++#define SI_PCI_DMA2 0x80000000 /* Client Mode sb2pcitranslation2 (1 GB) */ ++#define SI_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */ ++#define SI_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2 ++ * (2 ZettaBytes), low 32 bits ++ */ ++#define SI_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2 ++ * (2 ZettaBytes), high 32 bits ++ */ ++ ++#define SI_BCM53573_NANDFLASH 0x30000000 /* 53573 NAND flash base */ ++#define SI_BCM53573_NORFLASH 0x1c000000 /* 53573 NOR flash base */ ++#define SI_BCM53573_FLASH2_SZ 0x04000000 /* 53573 NOR flash2 size */ ++ ++#define SI_BCM53573_NORFLASH_WINDOW 0x01000000 /* only support 16M direct access for ++ * 3-byte address modes in spi flash ++ */ ++#define SI_BCM53573_BOOTDEV_MASK 0x3 ++#define SI_BCM53573_BOOTDEV_NOR 0x0 ++ ++#define SI_BCM53573_NAND_PRE_MASK 0x100 /* 53573 NAND present mask */ ++ ++#define SI_BCM53573_DDRTYPE_MASK 0x10 ++#define SI_BCM53573_DDRTYPE_DDR3 0x10 ++ ++#define SI_BCM47189_RGMII_VDD_MASK 0x3 ++#define SI_BCM47189_RGMII_VDD_SHIFT 21 ++#define SI_BCM47189_RGMII_VDD_3_3V 0 ++#define SI_BCM47189_RGMII_VDD_2_5V 1 ++#define SI_BCM47189_RGMII_VDD_1_5V 1 ++ ++#define SI_BCM53573_LOCKED_CPUPLL 0x1 ++ ++/* APB bridge code */ ++#define APB_BRIDGE_ID 0x135 /* APB Bridge 0, 1, etc. */ ++ ++/* core codes */ ++#define NODEV_CORE_ID 0x700 /* Invalid coreid */ ++#define CC_CORE_ID 0x800 /* chipcommon core */ ++#define ILINE20_CORE_ID 0x801 /* iline20 core */ ++#define SRAM_CORE_ID 0x802 /* sram core */ ++#define SDRAM_CORE_ID 0x803 /* sdram core */ ++#define PCI_CORE_ID 0x804 /* pci core */ ++#define MIPS_CORE_ID 0x805 /* mips core */ ++#define ENET_CORE_ID 0x806 /* enet mac core */ ++#define CODEC_CORE_ID 0x807 /* v90 codec core */ ++#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */ ++#define ADSL_CORE_ID 0x809 /* ADSL core */ ++#define ILINE100_CORE_ID 0x80a /* iline100 core */ ++#define IPSEC_CORE_ID 0x80b /* ipsec core */ ++#define UTOPIA_CORE_ID 0x80c /* utopia core */ ++#define PCMCIA_CORE_ID 0x80d /* pcmcia core */ ++#define SOCRAM_CORE_ID 0x80e /* internal memory core */ ++#define MEMC_CORE_ID 0x80f /* memc sdram core */ ++#define OFDM_CORE_ID 0x810 /* OFDM phy core */ ++#define EXTIF_CORE_ID 0x811 /* external interface core */ ++#define D11_CORE_ID 0x812 /* 802.11 MAC core */ ++#define APHY_CORE_ID 0x813 /* 802.11a phy core */ ++#define BPHY_CORE_ID 0x814 /* 802.11b phy core */ ++#define GPHY_CORE_ID 0x815 /* 802.11g phy core */ ++#define MIPS33_CORE_ID 0x816 /* mips3302 core */ ++#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */ ++#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */ ++#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */ ++#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */ ++#define SDIOH_CORE_ID 0x81b /* sdio host core */ ++#define ROBO_CORE_ID 0x81c /* roboswitch core */ ++#define ATA100_CORE_ID 0x81d /* parallel ATA core */ ++#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */ ++#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */ ++#define PCIE_CORE_ID 0x820 /* pci express core */ ++#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */ ++#define SRAMC_CORE_ID 0x822 /* SRAM controller core */ ++#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */ ++#define ARM11_CORE_ID 0x824 /* ARM 1176 core */ ++#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */ ++#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */ ++#define PMU_CORE_ID 0x827 /* PMU core */ ++#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ ++#define SDIOD_CORE_ID 0x829 /* SDIO device core */ ++#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ ++#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ ++#define MIPS74K_CORE_ID 0x82c /* mips 74k core */ ++#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ ++#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ ++#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */ ++#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */ ++#define SC_CORE_ID 0x831 /* shared common core */ ++#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ ++#define SPIH_CORE_ID 0x833 /* SPI host core */ ++#define I2S_CORE_ID 0x834 /* I2S core */ ++#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ ++#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ ++ ++#define ACPHY_CORE_ID 0x83b /* Dot11 ACPHY */ ++#define PCIE2_CORE_ID 0x83c /* pci express Gen2 core */ ++#define USB30D_CORE_ID 0x83d /* usb 3.0 device core */ ++#define ARMCR4_CORE_ID 0x83e /* ARM CR4 CPU */ ++#define GCI_CORE_ID 0x840 /* GCI Core */ ++#define M2MDMA_CORE_ID 0x844 /* memory to memory dma */ ++#define CMEM_CORE_ID 0x846 /* CNDS DDR2/3 memory controller */ ++#define ARMCA7_CORE_ID 0x847 /* ARM CA7 CPU */ ++#define SYSMEM_CORE_ID 0x849 /* System memory core */ ++#define APB_BRIDGE_CORE_ID 0x135 /* APB bridge core ID */ ++#define AXI_CORE_ID 0x301 /* AXI/GPV core ID */ ++#define EROM_CORE_ID 0x366 /* EROM core ID */ ++#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 ++ */ ++ ++#define CC_4706_CORE_ID 0x500 /* chipcommon core */ ++#define NS_PCIEG2_CORE_ID 0x501 /* PCIE Gen 2 core */ ++#define NS_DMA_CORE_ID 0x502 /* DMA core */ ++#define NS_SDIO3_CORE_ID 0x503 /* SDIO3 core */ ++#define NS_USB20_CORE_ID 0x504 /* USB2.0 core */ ++#define NS_USB30_CORE_ID 0x505 /* USB3.0 core */ ++#define NS_A9JTAG_CORE_ID 0x506 /* ARM Cortex A9 JTAG core */ ++#define NS_DDR23_CORE_ID 0x507 /* Denali DDR2/DDR3 memory controller */ ++#define NS_ROM_CORE_ID 0x508 /* ROM core */ ++#define NS_NAND_CORE_ID 0x509 /* NAND flash controller core */ ++#define NS_QSPI_CORE_ID 0x50a /* SPI flash controller core */ ++#define NS_CCB_CORE_ID 0x50b /* ChipcommonB core */ ++#define SOCRAM_4706_CORE_ID 0x50e /* internal memory core */ ++#define NS_SOCRAM_CORE_ID SOCRAM_4706_CORE_ID ++#define ARMCA9_CORE_ID 0x510 /* ARM Cortex A9 core (ihost) */ ++#define NS_IHOST_CORE_ID ARMCA9_CORE_ID /* ARM Cortex A9 core (ihost) */ ++#define GMAC_COMMON_4706_CORE_ID 0x5dc /* Gigabit MAC core */ ++#define GMAC_4706_CORE_ID 0x52d /* Gigabit MAC core */ ++#define AMEMC_CORE_ID 0x52e /* DDR1/2 memory controller core */ ++#define ALTA_CORE_ID 0x534 /* I2S core */ ++#define DDR23_PHY_CORE_ID 0x5dd ++ ++#define SI_PCI1_MEM 0x40000000 /* Host Mode sb2pcitranslation0 (64 MB) */ ++#define SI_PCI1_CFG 0x44000000 /* Host Mode sb2pcitranslation1 (64 MB) */ ++#define SI_PCIE1_DMA_H32 0xc0000000 /* PCIE Client Mode sb2pcitranslation2 ++ * (2 ZettaBytes), high 32 bits ++ */ ++#define CC_4706B0_CORE_REV 0x8000001f /* chipcommon core */ ++#define SOCRAM_4706B0_CORE_REV 0x80000005 /* internal memory core */ ++#define GMAC_4706B0_CORE_REV 0x80000000 /* Gigabit MAC core */ ++#define NS_PCIEG2_CORE_REV_B0 0x7 /* NS-B0 PCIE Gen 2 core rev */ ++ ++/* There are TWO constants on all HND chips: SI_ENUM_BASE above, ++ * and chipcommon being the first core: ++ */ ++#define SI_CC_IDX 0 ++/* SOC Interconnect types (aka chip types) */ ++#define SOCI_SB 0 ++#define SOCI_AI 1 ++#define SOCI_UBUS 2 ++#define SOCI_NAI 3 ++ ++/* Common core control flags */ ++#define SICF_BIST_EN 0x8000 ++#define SICF_PME_EN 0x4000 ++#define SICF_CORE_BITS 0x3ffc ++#define SICF_FGC 0x0002 ++#define SICF_CLOCK_EN 0x0001 ++ ++/* Common core status flags */ ++#define SISF_BIST_DONE 0x8000 ++#define SISF_BIST_ERROR 0x4000 ++#define SISF_GATED_CLK 0x2000 ++#define SISF_DMA64 0x1000 ++#define SISF_CORE_BITS 0x0fff ++ ++/* Norstar core status flags */ ++#define SISF_NS_BOOTDEV_MASK 0x0003 /* ROM core */ ++#define SISF_NS_BOOTDEV_NOR 0x0000 /* ROM core */ ++#define SISF_NS_BOOTDEV_NAND 0x0001 /* ROM core */ ++#define SISF_NS_BOOTDEV_ROM 0x0002 /* ROM core */ ++#define SISF_NS_BOOTDEV_OFFLOAD 0x0003 /* ROM core */ ++#define SISF_NS_SKUVEC_MASK 0x000c /* ROM core */ ++ ++/* A register that is common to all cores to ++ * communicate w/PMU regarding clock control. ++ */ ++#define SI_CLK_CTL_ST 0x1e0 /* clock control and status */ ++#define SI_PWR_CTL_ST 0x1e8 /* For memory clock gating */ ++ ++/* clk_ctl_st register */ ++#define CCS_FORCEALP 0x00000001 /* force ALP request */ ++#define CCS_FORCEHT 0x00000002 /* force HT request */ ++#define CCS_FORCEILP 0x00000004 /* force ILP request */ ++#define CCS_ALPAREQ 0x00000008 /* ALP Avail Request */ ++#define CCS_HTAREQ 0x00000010 /* HT Avail Request */ ++#define CCS_FORCEHWREQOFF 0x00000020 /* Force HW Clock Request Off */ ++#define CCS_HQCLKREQ 0x00000040 /* HQ Clock Required */ ++#define CCS_USBCLKREQ 0x00000100 /* USB Clock Req */ ++#define CCS_SECICLKREQ 0x00000100 /* SECI Clock Req */ ++#define CCS_ARMFASTCLOCKREQ 0x00000100 /* ARM CR4/CA7 fast clock request */ ++#define CCS_AVBCLKREQ 0x00000400 /* AVB Clock enable request */ ++#define CCS_ERSRC_REQ_MASK 0x00000700 /* external resource requests */ ++#define CCS_ERSRC_REQ_SHIFT 8 ++#define CCS_ALPAVAIL 0x00010000 /* ALP is available */ ++#define CCS_HTAVAIL 0x00020000 /* HT is available */ ++#define CCS_BP_ON_APL 0x00040000 /* RO: Backplane is running on ALP clock */ ++#define CCS_BP_ON_HT 0x00080000 /* RO: Backplane is running on HT clock */ ++#define CCS_ARMFASTCLOCKSTATUS 0x01000000 /* Fast CPU clock is running */ ++#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ ++#define CCS_ERSRC_STS_SHIFT 24 ++#define CCS_SECI_AVAIL 0x01000000 /* RO: SECI is available */ ++ ++#define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */ ++#define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */ ++ ++/* Not really related to SOC Interconnect, but a couple of software ++ * conventions for the use the flash space: ++ */ ++ ++/* 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 this 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 */ ++ ++/* Boot/Kernel related defintion and functions */ ++#define SOC_BOOTDEV_ROM 0x00000001 ++#define SOC_BOOTDEV_PFLASH 0x00000002 ++#define SOC_BOOTDEV_SFLASH 0x00000004 ++#define SOC_BOOTDEV_NANDFLASH 0x00000008 ++ ++#define SOC_KNLDEV_NORFLASH 0x00000002 ++#define SOC_KNLDEV_NANDFLASH 0x00000004 ++ ++#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) ++int soc_boot_dev(void *sih); ++int soc_knl_dev(void *sih); ++#endif /* !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) */ ++ ++#define PMU_BASE_OFFSET 0x00012000 /* PMU offset is changed for ccrev >= 56 */ ++#endif /* _HNDSOC_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/linux_osl.h b/module_drivers/drivers/net/wireless/bcmdhd/include/linux_osl.h +new file mode 100644 +index 000000000..8dcfec148 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/linux_osl.h +@@ -0,0 +1,1170 @@ ++/* ++ * Linux OS Independent Layer ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: linux_osl.h 672413 2016-11-28 11:13:23Z $ ++ */ ++ ++#ifndef _linux_osl_h_ ++#define _linux_osl_h_ ++ ++#include ++#define DECLSPEC_ALIGN(x) __attribute__ ((aligned(x))) ++ ++/* Linux Kernel: File Operations: start */ ++extern void * osl_os_open_image(char * filename); ++extern int osl_os_get_image_block(char * buf, int len, void * image); ++extern void osl_os_close_image(void * image); ++extern int osl_os_image_size(void *image); ++/* Linux Kernel: File Operations: end */ ++ ++#ifdef BCMDRIVER ++ ++/* OSL initialization */ ++#ifdef SHARED_OSL_CMN ++extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag, void **osh_cmn); ++#else ++extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); ++#endif /* SHARED_OSL_CMN */ ++ ++extern void osl_detach(osl_t *osh); ++extern int osl_static_mem_init(osl_t *osh, void *adapter); ++extern int osl_static_mem_deinit(osl_t *osh, void *adapter); ++extern void osl_set_bus_handle(osl_t *osh, void *bus_handle); ++extern void* osl_get_bus_handle(osl_t *osh); ++ ++/* Global ASSERT type */ ++extern uint32 g_assert_type; ++ ++#ifdef CONFIG_PHYS_ADDR_T_64BIT ++#define PRI_FMT_x "llx" ++#define PRI_FMT_X "llX" ++#define PRI_FMT_o "llo" ++#define PRI_FMT_d "lld" ++#else ++#define PRI_FMT_x "x" ++#define PRI_FMT_X "X" ++#define PRI_FMT_o "o" ++#define PRI_FMT_d "d" ++#endif /* CONFIG_PHYS_ADDR_T_64BIT */ ++/* ASSERT */ ++#if defined(BCMASSERT_LOG) ++ #define ASSERT(exp) \ ++ do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0) ++extern void osl_assert(const char *exp, const char *file, int line); ++#else ++ #ifdef __GNUC__ ++ #define GCC_VERSION \ ++ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) ++ #if GCC_VERSION > 30100 ++ #define ASSERT(exp) do {} while (0) ++ #else ++ /* ASSERT could cause segmentation fault on GCC3.1, use empty instead */ ++ #define ASSERT(exp) ++ #endif /* GCC_VERSION > 30100 */ ++ #endif /* __GNUC__ */ ++#endif ++ ++/* bcm_prefetch_32B */ ++static inline void bcm_prefetch_32B(const uint8 *addr, const int cachelines_32B) ++{ ++#if (defined(STB) && defined(__arm__)) && (__LINUX_ARM_ARCH__ >= 5) ++ switch (cachelines_32B) { ++ case 4: __asm__ __volatile__("pld\t%a0" :: "p"(addr + 96) : "cc"); ++ case 3: __asm__ __volatile__("pld\t%a0" :: "p"(addr + 64) : "cc"); ++ case 2: __asm__ __volatile__("pld\t%a0" :: "p"(addr + 32) : "cc"); ++ case 1: __asm__ __volatile__("pld\t%a0" :: "p"(addr + 0) : "cc"); ++ } ++#endif ++} ++ ++/* microsecond delay */ ++#define OSL_DELAY(usec) osl_delay(usec) ++extern void osl_delay(uint usec); ++ ++#define OSL_SLEEP(ms) osl_sleep(ms) ++extern void osl_sleep(uint ms); ++ ++#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \ ++ osl_pcmcia_read_attr((osh), (offset), (buf), (size)) ++#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \ ++ osl_pcmcia_write_attr((osh), (offset), (buf), (size)) ++extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size); ++extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size); ++ ++/* PCI configuration space access macros */ ++#define OSL_PCI_READ_CONFIG(osh, offset, size) \ ++ osl_pci_read_config((osh), (offset), (size)) ++#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \ ++ osl_pci_write_config((osh), (offset), (size), (val)) ++extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size); ++extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val); ++ ++/* PCI device bus # and slot # */ ++#define OSL_PCI_BUS(osh) osl_pci_bus(osh) ++#define OSL_PCI_SLOT(osh) osl_pci_slot(osh) ++#define OSL_PCIE_DOMAIN(osh) osl_pcie_domain(osh) ++#define OSL_PCIE_BUS(osh) osl_pcie_bus(osh) ++extern uint osl_pci_bus(osl_t *osh); ++extern uint osl_pci_slot(osl_t *osh); ++extern uint osl_pcie_domain(osl_t *osh); ++extern uint osl_pcie_bus(osl_t *osh); ++extern struct pci_dev *osl_pci_device(osl_t *osh); ++ ++#define OSL_ACP_COHERENCE (1<<1L) ++#define OSL_FWDERBUF (1<<2L) ++ ++/* Pkttag flag should be part of public information */ ++typedef struct { ++ bool pkttag; ++ bool mmbus; /**< Bus supports memory-mapped register accesses */ ++ pktfree_cb_fn_t tx_fn; /**< Callback function for PKTFREE */ ++ void *tx_ctx; /**< Context to the callback function */ ++ void *unused[3]; ++} osl_pubinfo_t; ++ ++extern void osl_flag_set(osl_t *osh, uint32 mask); ++extern void osl_flag_clr(osl_t *osh, uint32 mask); ++extern bool osl_is_flag_set(osl_t *osh, uint32 mask); ++ ++#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \ ++ do { \ ++ ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \ ++ ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \ ++ } while (0) ++ ++ ++/* host/bus architecture-specific byte swap */ ++#define BUS_SWAP32(v) (v) ++ #define MALLOC(osh, size) osl_malloc((osh), (size)) ++ #define MALLOCZ(osh, size) osl_mallocz((osh), (size)) ++ #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size)) ++ #define VMALLOC(osh, size) osl_vmalloc((osh), (size)) ++ #define VMALLOCZ(osh, size) osl_vmallocz((osh), (size)) ++ #define VMFREE(osh, addr, size) osl_vmfree((osh), (addr), (size)) ++ #define MALLOCED(osh) osl_malloced((osh)) ++ #define MEMORY_LEFTOVER(osh) osl_check_memleak(osh) ++ extern void *osl_malloc(osl_t *osh, uint size); ++ extern void *osl_mallocz(osl_t *osh, uint size); ++ extern void osl_mfree(osl_t *osh, void *addr, uint size); ++ extern void *osl_vmalloc(osl_t *osh, uint size); ++ extern void *osl_vmallocz(osl_t *osh, uint size); ++ extern void osl_vmfree(osl_t *osh, void *addr, uint size); ++ extern uint osl_malloced(osl_t *osh); ++ extern uint osl_check_memleak(osl_t *osh); ++ ++#define MALLOC_FAILED(osh) osl_malloc_failed((osh)) ++extern uint osl_malloc_failed(osl_t *osh); ++ ++/* allocate/free shared (dma-able) consistent memory */ ++#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align() ++#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \ ++ osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) ++#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \ ++ osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) ++ ++#define DMA_ALLOC_CONSISTENT_FORCE32(osh, size, align, tot, pap, dmah) \ ++ osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap)) ++#define DMA_FREE_CONSISTENT_FORCE32(osh, va, size, pa, dmah) \ ++ osl_dma_free_consistent((osh), (void*)(va), (size), (pa)) ++ ++extern uint osl_dma_consistent_align(void); ++extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, ++ uint *tot, dmaaddr_t *pap); ++extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa); ++ ++/* map/unmap direction */ ++#define DMA_NO 0 /* Used to skip cache op */ ++#define DMA_TX 1 /* TX direction for DMA */ ++#define DMA_RX 2 /* RX direction for DMA */ ++ ++/* map/unmap shared (dma-able) memory */ ++#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \ ++ osl_dma_unmap((osh), (pa), (size), (direction)) ++extern dmaaddr_t osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, ++ hnddma_seg_map_t *txp_dmah); ++extern void osl_dma_unmap(osl_t *osh, dmaaddr_t pa, uint size, int direction); ++ ++/* API for DMA addressing capability */ ++#define OSL_DMADDRWIDTH(osh, addrwidth) ({BCM_REFERENCE(osh); BCM_REFERENCE(addrwidth);}) ++ ++#define OSL_SMP_WMB() smp_wmb() ++ ++/* API for CPU relax */ ++extern void osl_cpu_relax(void); ++#define OSL_CPU_RELAX() osl_cpu_relax() ++ ++extern void osl_preempt_disable(osl_t *osh); ++extern void osl_preempt_enable(osl_t *osh); ++#define OSL_DISABLE_PREEMPTION(osh) osl_preempt_disable(osh) ++#define OSL_ENABLE_PREEMPTION(osh) osl_preempt_enable(osh) ++ ++#if (!defined(DHD_USE_COHERENT_MEM_FOR_RING) && defined(__ARM_ARCH_7A__)) || \ ++ (defined(STBLINUX) && defined(__ARM_ARCH_7A__)) ++ extern void osl_cache_flush(void *va, uint size); ++ extern void osl_cache_inv(void *va, uint size); ++ extern void osl_prefetch(const void *ptr); ++ #define OSL_CACHE_FLUSH(va, len) osl_cache_flush((void *)(va), len) ++ #define OSL_CACHE_INV(va, len) osl_cache_inv((void *)(va), len) ++ #define OSL_PREFETCH(ptr) osl_prefetch(ptr) ++#if defined(__ARM_ARCH_7A__) ++ extern int osl_arch_is_coherent(void); ++ #define OSL_ARCH_IS_COHERENT() osl_arch_is_coherent() ++ extern int osl_acp_war_enab(void); ++ #define OSL_ACP_WAR_ENAB() osl_acp_war_enab() ++#else /* !__ARM_ARCH_7A__ */ ++ #define OSL_ARCH_IS_COHERENT() NULL ++ #define OSL_ACP_WAR_ENAB() NULL ++#endif /* !__ARM_ARCH_7A__ */ ++#else /* !__mips__ && !__ARM_ARCH_7A__ */ ++ #define OSL_CACHE_FLUSH(va, len) BCM_REFERENCE(va) ++ #define OSL_CACHE_INV(va, len) BCM_REFERENCE(va) ++ #define OSL_PREFETCH(ptr) BCM_REFERENCE(ptr) ++ ++ #define OSL_ARCH_IS_COHERENT() NULL ++ #define OSL_ACP_WAR_ENAB() NULL ++#endif ++ ++/* register access macros */ ++#if defined(BCMSDIO) ++ #include ++ #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(osl_get_bus_handle(osh), \ ++ (uintptr)(r), sizeof(*(r)), (v))) ++ #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(osl_get_bus_handle(osh), \ ++ (uintptr)(r), sizeof(*(r)))) ++#elif (defined(STB) && defined(__arm__)) ++extern void osl_pcie_rreg(osl_t *osh, ulong addr, void *v, uint size); ++ ++#define OSL_READ_REG(osh, r) \ ++ ({\ ++ __typeof(*(r)) __osl_v; \ ++ osl_pcie_rreg(osh, (uintptr)(r), (void *)&__osl_v, sizeof(*(r))); \ ++ __osl_v; \ ++ }) ++#endif ++ ++#if (defined(STB) && defined(__arm__)) ++ #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;}) ++ #define SELECT_BUS_READ(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); bus_op;}) ++#else /* !BCM47XX_CA9 */ ++#if defined(BCMSDIO) ++ #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \ ++ mmap_op else bus_op ++ #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \ ++ mmap_op : bus_op ++#else ++ #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;}) ++ #define SELECT_BUS_READ(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;}) ++#endif ++#endif ++ ++#define OSL_ERROR(bcmerror) osl_error(bcmerror) ++extern int osl_error(int bcmerror); ++ ++/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ ++#define PKTBUFSZ 2048 /* largest reasonable packet buffer, driver uses for ethernet MTU */ ++ ++#define OSH_NULL NULL ++ ++/* ++ * BINOSL selects the slightly slower function-call-based binary compatible osl. ++ * Macros expand to calls to functions defined in linux_osl.c . ++ */ ++#include /* use current 2.4.x calling conventions */ ++#include /* for vsn/printf's */ ++#include /* for mem*, str* */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) ++extern uint64 osl_sysuptime_us(void); ++#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies)) ++#define OSL_SYSUPTIME_US() osl_sysuptime_us() ++#else ++#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) ++#error "OSL_SYSUPTIME_US() may need to be defined" ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */ ++#define printf(fmt, args...) printk(fmt , ## args) ++#include /* for vsn/printf's */ ++#include /* for mem*, str* */ ++/* bcopy's: Linux kernel doesn't provide these (anymore) */ ++#define bcopy(src, dst, len) memcpy((dst), (src), (len)) ++#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) ++#define bzero(b, len) memset((b), '\0', (len)) ++ ++/* register access macros */ ++ ++#ifdef CONFIG_64BIT ++/* readq is defined only for 64 bit platform */ ++#define R_REG(osh, r) (\ ++ SELECT_BUS_READ(osh, \ ++ ({ \ ++ __typeof(*(r)) __osl_v = 0; \ ++ switch (sizeof(*(r))) { \ ++ case sizeof(uint8): __osl_v = \ ++ readb((volatile uint8*)(r)); break; \ ++ case sizeof(uint16): __osl_v = \ ++ readw((volatile uint16*)(r)); break; \ ++ case sizeof(uint32): __osl_v = \ ++ readl((volatile uint32*)(r)); break; \ ++ case sizeof(uint64): __osl_v = \ ++ readq((volatile uint64*)(r)); break; \ ++ } \ ++ __osl_v; \ ++ }), \ ++ OSL_READ_REG(osh, r)) \ ++) ++#else /* !CONFIG_64BIT */ ++#define R_REG(osh, r) (\ ++ SELECT_BUS_READ(osh, \ ++ ({ \ ++ __typeof(*(r)) __osl_v = 0; \ ++ switch (sizeof(*(r))) { \ ++ case sizeof(uint8): __osl_v = \ ++ readb((volatile uint8*)(r)); break; \ ++ case sizeof(uint16): __osl_v = \ ++ readw((volatile uint16*)(r)); break; \ ++ case sizeof(uint32): __osl_v = \ ++ readl((volatile uint32*)(r)); break; \ ++ } \ ++ __osl_v; \ ++ }), \ ++ OSL_READ_REG(osh, r)) \ ++) ++#endif /* CONFIG_64BIT */ ++ ++#ifdef CONFIG_64BIT ++/* writeq is defined only for 64 bit platform */ ++#define W_REG(osh, r, v) do { \ ++ SELECT_BUS_WRITE(osh, \ ++ switch (sizeof(*(r))) { \ ++ case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ ++ case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ ++ case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ ++ case sizeof(uint64): writeq((uint64)(v), (volatile uint64*)(r)); break; \ ++ }, \ ++ (OSL_WRITE_REG(osh, r, v))); \ ++ } while (0) ++ ++#else /* !CONFIG_64BIT */ ++#define W_REG(osh, r, v) do { \ ++ SELECT_BUS_WRITE(osh, \ ++ switch (sizeof(*(r))) { \ ++ case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \ ++ case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \ ++ case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \ ++ }, \ ++ (OSL_WRITE_REG(osh, r, v))); \ ++ } while (0) ++#endif /* CONFIG_64BIT */ ++ ++#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) ++#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) ++ ++/* bcopy, bcmp, and bzero functions */ ++#define bcopy(src, dst, len) memcpy((dst), (src), (len)) ++#define bcmp(b1, b2, len) memcmp((b1), (b2), (len)) ++#define bzero(b, len) memset((b), '\0', (len)) ++ ++/* uncached/cached virtual address */ ++#define OSL_UNCACHED(va) ((void *)va) ++#define OSL_CACHED(va) ((void *)va) ++ ++#define OSL_PREF_RANGE_LD(va, sz) BCM_REFERENCE(va) ++#define OSL_PREF_RANGE_ST(va, sz) BCM_REFERENCE(va) ++ ++/* get processor cycle count */ ++#if defined(__i386__) ++#define OSL_GETCYCLES(x) rdtscl((x)) ++#else ++#define OSL_GETCYCLES(x) ((x) = 0) ++#endif ++ ++/* dereference an address that may cause a bus exception */ ++#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; }) ++ ++/* map/unmap physical to virtual I/O */ ++#if !defined(CONFIG_MMC_MSM7X00A) ++#define REG_MAP(pa, size) ioremap((unsigned long)(pa), (unsigned long)(size)) ++#else ++#define REG_MAP(pa, size) (void *)(0) ++#endif /* !defined(CONFIG_MMC_MSM7X00A */ ++#define REG_UNMAP(va) iounmap((va)) ++ ++/* shared (dma-able) memory access macros */ ++#define R_SM(r) *(r) ++#define W_SM(r, v) (*(r) = (v)) ++#define BZERO_SM(r, len) memset((r), '\0', (len)) ++ ++/* Because the non BINOSL implemenation of the PKT OSL routines are macros (for ++ * performance reasons), we need the Linux headers. ++ */ ++#include /* use current 2.4.x calling conventions */ ++ ++/* packet primitives */ ++#ifdef BCMDBG_CTRACE ++#define PKTGET(osh, len, send) osl_pktget((osh), (len), __LINE__, __FILE__) ++#define PKTDUP(osh, skb) osl_pktdup((osh), (skb), __LINE__, __FILE__) ++#else ++#ifdef BCM_OBJECT_TRACE ++#define PKTGET(osh, len, send) osl_pktget((osh), (len), __LINE__, __FUNCTION__) ++#define PKTDUP(osh, skb) osl_pktdup((osh), (skb), __LINE__, __FUNCTION__) ++#else ++#define PKTGET(osh, len, send) osl_pktget((osh), (len)) ++#define PKTDUP(osh, skb) osl_pktdup((osh), (skb)) ++#endif /* BCM_OBJECT_TRACE */ ++#endif /* BCMDBG_CTRACE */ ++#define PKTLIST_DUMP(osh, buf) BCM_REFERENCE(osh) ++#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh) ++#if defined(BCM_OBJECT_TRACE) ++#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send), __LINE__, __FUNCTION__) ++#else ++#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) ++#endif /* BCM_OBJECT_TRACE */ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) ++#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) ++#else ++#define PKTGET_STATIC PKTGET ++#define PKTFREE_STATIC PKTFREE ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++#define PKTDATA(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->data);}) ++#define PKTLEN(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->len);}) ++#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head)) ++#define PKTEXPHEADROOM(osh, skb, b) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ skb_realloc_headroom((struct sk_buff*)(skb), (b)); \ ++ }) ++#define PKTTAILROOM(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ skb_tailroom((struct sk_buff*)(skb)); \ ++ }) ++#define PKTPADTAILROOM(osh, skb, padlen) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ skb_pad((struct sk_buff*)(skb), (padlen)); \ ++ }) ++#define PKTNEXT(osh, skb) ({BCM_REFERENCE(osh); (((struct sk_buff*)(skb))->next);}) ++#define PKTSETNEXT(osh, skb, x) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x)); \ ++ }) ++#define PKTSETLEN(osh, skb, len) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ __skb_trim((struct sk_buff*)(skb), (len)); \ ++ }) ++#define PKTPUSH(osh, skb, bytes) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ skb_push((struct sk_buff*)(skb), (bytes)); \ ++ }) ++#define PKTPULL(osh, skb, bytes) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ skb_pull((struct sk_buff*)(skb), (bytes)); \ ++ }) ++#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb)) ++#define PKTSETPOOL(osh, skb, x, y) BCM_REFERENCE(osh) ++#define PKTPOOL(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) ++#define PKTFREELIST(skb) PKTLINK(skb) ++#define PKTSETFREELIST(skb, x) PKTSETLINK((skb), (x)) ++#define PKTPTR(skb) (skb) ++#define PKTID(skb) ({BCM_REFERENCE(skb); 0;}) ++#define PKTSETID(skb, id) ({BCM_REFERENCE(skb); BCM_REFERENCE(id);}) ++#define PKTSHRINK(osh, m) ({BCM_REFERENCE(osh); m;}) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && defined(TSQ_MULTIPLIER) ++#define PKTORPHAN(skb, tsq) osl_pkt_orphan_partial(skb, tsq) ++extern void osl_pkt_orphan_partial(struct sk_buff *skb, int tsq); ++#else ++#define PKTORPHAN(skb, tsq) ({BCM_REFERENCE(skb); 0;}) ++#endif /* LINUX VERSION >= 3.6 */ ++ ++ ++#ifdef BCMDBG_CTRACE ++#define DEL_CTRACE(zosh, zskb) { \ ++ unsigned long zflags; \ ++ spin_lock_irqsave(&(zosh)->ctrace_lock, zflags); \ ++ list_del(&(zskb)->ctrace_list); \ ++ (zosh)->ctrace_num--; \ ++ (zskb)->ctrace_start = 0; \ ++ (zskb)->ctrace_count = 0; \ ++ spin_unlock_irqrestore(&(zosh)->ctrace_lock, zflags); \ ++} ++ ++#define UPDATE_CTRACE(zskb, zfile, zline) { \ ++ struct sk_buff *_zskb = (struct sk_buff *)(zskb); \ ++ if (_zskb->ctrace_count < CTRACE_NUM) { \ ++ _zskb->func[_zskb->ctrace_count] = zfile; \ ++ _zskb->line[_zskb->ctrace_count] = zline; \ ++ _zskb->ctrace_count++; \ ++ } \ ++ else { \ ++ _zskb->func[_zskb->ctrace_start] = zfile; \ ++ _zskb->line[_zskb->ctrace_start] = zline; \ ++ _zskb->ctrace_start++; \ ++ if (_zskb->ctrace_start >= CTRACE_NUM) \ ++ _zskb->ctrace_start = 0; \ ++ } \ ++} ++ ++#define ADD_CTRACE(zosh, zskb, zfile, zline) { \ ++ unsigned long zflags; \ ++ spin_lock_irqsave(&(zosh)->ctrace_lock, zflags); \ ++ list_add(&(zskb)->ctrace_list, &(zosh)->ctrace_list); \ ++ (zosh)->ctrace_num++; \ ++ UPDATE_CTRACE(zskb, zfile, zline); \ ++ spin_unlock_irqrestore(&(zosh)->ctrace_lock, zflags); \ ++} ++ ++#define PKTCALLER(zskb) UPDATE_CTRACE((struct sk_buff *)zskb, (char *)__FUNCTION__, __LINE__) ++#endif /* BCMDBG_CTRACE */ ++ ++#ifdef CTFPOOL ++#define CTFPOOL_REFILL_THRESH 3 ++typedef struct ctfpool { ++ void *head; ++ spinlock_t lock; ++ osl_t *osh; ++ uint max_obj; ++ uint curr_obj; ++ uint obj_size; ++ uint refills; ++ uint fast_allocs; ++ uint fast_frees; ++ uint slow_allocs; ++} ctfpool_t; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) ++#define FASTBUF (1 << 0) ++#define PKTSETFAST(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ ((((struct sk_buff*)(skb))->pktc_flags) |= FASTBUF); \ ++ }) ++#define PKTCLRFAST(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ ((((struct sk_buff*)(skb))->pktc_flags) &= (~FASTBUF)); \ ++ }) ++#define PKTISFAST(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ ((((struct sk_buff*)(skb))->pktc_flags) & FASTBUF); \ ++ }) ++#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->pktc_flags) ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++#define FASTBUF (1 << 16) ++#define PKTSETFAST(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF); \ ++ }) ++#define PKTCLRFAST(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF)); \ ++ }) ++#define PKTISFAST(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ ((((struct sk_buff*)(skb))->mac_len) & FASTBUF); \ ++ }) ++#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len) ++#else ++#define FASTBUF (1 << 0) ++#define PKTSETFAST(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ ((((struct sk_buff*)(skb))->__unused) |= FASTBUF); \ ++ }) ++#define PKTCLRFAST(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF)); \ ++ }) ++#define PKTISFAST(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ ((((struct sk_buff*)(skb))->__unused) & FASTBUF); \ ++ }) ++#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused) ++#endif /* 2.6.22 */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->ctfpool) ++#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->ctfpool)->head) ++#else ++#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk) ++#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head) ++#endif ++ ++extern void *osl_ctfpool_add(osl_t *osh); ++extern void osl_ctfpool_replenish(osl_t *osh, uint thresh); ++extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size); ++extern void osl_ctfpool_cleanup(osl_t *osh); ++extern void osl_ctfpool_stats(osl_t *osh, void *b); ++#else /* CTFPOOL */ ++#define PKTSETFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTCLRFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTISFAST(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) ++#endif /* CTFPOOL */ ++ ++#define PKTSETCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTCLRCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTISCTF(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) ++ ++#ifdef HNDCTF ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) ++#define SKIPCT (1 << 2) ++#define CHAINED (1 << 3) ++#define PKTSETSKIPCT(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->pktc_flags |= SKIPCT); \ ++ }) ++#define PKTCLRSKIPCT(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->pktc_flags &= (~SKIPCT)); \ ++ }) ++#define PKTSKIPCT(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->pktc_flags & SKIPCT); \ ++ }) ++#define PKTSETCHAINED(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->pktc_flags |= CHAINED); \ ++ }) ++#define PKTCLRCHAINED(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->pktc_flags &= (~CHAINED)); \ ++ }) ++#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->pktc_flags & CHAINED) ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++#define SKIPCT (1 << 18) ++#define CHAINED (1 << 19) ++#define PKTSETSKIPCT(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->mac_len |= SKIPCT); \ ++ }) ++#define PKTCLRSKIPCT(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT)); \ ++ }) ++#define PKTSKIPCT(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->mac_len & SKIPCT); \ ++ }) ++#define PKTSETCHAINED(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->mac_len |= CHAINED); \ ++ }) ++#define PKTCLRCHAINED(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->mac_len &= (~CHAINED)); \ ++ }) ++#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->mac_len & CHAINED) ++#else /* 2.6.22 */ ++#define SKIPCT (1 << 2) ++#define CHAINED (1 << 3) ++#define PKTSETSKIPCT(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->__unused |= SKIPCT); \ ++ }) ++#define PKTCLRSKIPCT(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->__unused &= (~SKIPCT)); \ ++ }) ++#define PKTSKIPCT(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->__unused & SKIPCT); \ ++ }) ++#define PKTSETCHAINED(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->__unused |= CHAINED); \ ++ }) ++#define PKTCLRCHAINED(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->__unused &= (~CHAINED)); \ ++ }) ++#define PKTISCHAINED(skb) (((struct sk_buff*)(skb))->__unused & CHAINED) ++#endif /* 2.6.22 */ ++typedef struct ctf_mark { ++ uint32 value; ++} ctf_mark_t; ++#define CTF_MARK(m) (m.value) ++#else /* HNDCTF */ ++#define PKTSETSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTCLRSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTSKIPCT(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define CTF_MARK(m) ({BCM_REFERENCE(m); 0;}) ++#endif /* HNDCTF */ ++ ++#if defined(BCM_GMAC3) ++ ++/** pktalloced accounting in devices using GMAC Bulk Forwarding to DHD */ ++ ++/* Account for packets delivered to downstream forwarder by GMAC interface. */ ++extern void osl_pkt_tofwder(osl_t *osh, void *skbs, int skb_cnt); ++#define PKTTOFWDER(osh, skbs, skb_cnt) \ ++ osl_pkt_tofwder(((osl_t *)osh), (void *)(skbs), (skb_cnt)) ++ ++/* Account for packets received from downstream forwarder. */ ++#if defined(BCMDBG_CTRACE) /* pkt logging */ ++extern void osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt, ++ int line, char *file); ++#define PKTFRMFWDER(osh, skbs, skb_cnt) \ ++ osl_pkt_frmfwder(((osl_t *)osh), (void *)(skbs), (skb_cnt), \ ++ __LINE__, __FILE__) ++#else /* ! (BCMDBG_PKT || BCMDBG_CTRACE) */ ++extern void osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt); ++#define PKTFRMFWDER(osh, skbs, skb_cnt) \ ++ osl_pkt_frmfwder(((osl_t *)osh), (void *)(skbs), (skb_cnt)) ++#endif ++ ++ ++/** GMAC Forwarded packet tagging for reduced cache flush/invalidate. ++ * In FWDERBUF tagged packet, only FWDER_PKTMAPSZ amount of data would have ++ * been accessed in the GMAC forwarder. This may be used to limit the number of ++ * cachelines that need to be flushed or invalidated. ++ * Packets sent to the DHD from a GMAC forwarder will be tagged w/ FWDERBUF. ++ * DHD may clear the FWDERBUF tag, if more than FWDER_PKTMAPSZ was accessed. ++ * Likewise, a debug print of a packet payload in say the ethernet driver needs ++ * to be accompanied with a clear of the FWDERBUF tag. ++ */ ++ ++/** Forwarded packets, have a GMAC_FWDER_HWRXOFF sized rx header (etc.h) */ ++#define FWDER_HWRXOFF (18) ++ ++/** Maximum amount of a pkt data that a downstream forwarder (GMAC) may have ++ * read into the L1 cache (not dirty). This may be used in reduced cache ops. ++ * ++ * Max 44: ET HWRXOFF[18] + BRCMHdr[4] + EtherHdr[14] + VlanHdr[4] + IP[4] ++ * Min 32: GMAC_FWDER_HWRXOFF[18] + EtherHdr[14] ++ */ ++#define FWDER_MINMAPSZ (FWDER_HWRXOFF + 14) ++#define FWDER_MAXMAPSZ (FWDER_HWRXOFF + 4 + 14 + 4 + 4) ++#define FWDER_PKTMAPSZ (FWDER_MINMAPSZ) ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) ++ ++#define FWDERBUF (1 << 4) ++#define PKTSETFWDERBUF(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->pktc_flags |= FWDERBUF); \ ++ }) ++#define PKTCLRFWDERBUF(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->pktc_flags &= (~FWDERBUF)); \ ++ }) ++#define PKTISFWDERBUF(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->pktc_flags & FWDERBUF); \ ++ }) ++ ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++ ++#define FWDERBUF (1 << 20) ++#define PKTSETFWDERBUF(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->mac_len |= FWDERBUF); \ ++ }) ++#define PKTCLRFWDERBUF(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->mac_len &= (~FWDERBUF)); \ ++ }) ++#define PKTISFWDERBUF(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->mac_len & FWDERBUF); \ ++ }) ++ ++#else /* 2.6.22 */ ++ ++#define FWDERBUF (1 << 4) ++#define PKTSETFWDERBUF(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->__unused |= FWDERBUF); \ ++ }) ++#define PKTCLRFWDERBUF(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->__unused &= (~FWDERBUF)); \ ++ }) ++#define PKTISFWDERBUF(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->__unused & FWDERBUF); \ ++ }) ++ ++#endif /* 2.6.22 */ ++ ++#else /* ! BCM_GMAC3 */ ++ ++#define PKTSETFWDERBUF(osh, skb) ({ BCM_REFERENCE(osh); BCM_REFERENCE(skb); }) ++#define PKTCLRFWDERBUF(osh, skb) ({ BCM_REFERENCE(osh); BCM_REFERENCE(skb); }) ++#define PKTISFWDERBUF(osh, skb) ({ BCM_REFERENCE(osh); BCM_REFERENCE(skb); FALSE;}) ++ ++#endif /* ! BCM_GMAC3 */ ++ ++ ++#ifdef HNDCTF ++/* For broadstream iqos */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) ++#define TOBR (1 << 5) ++#define PKTSETTOBR(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->pktc_flags |= TOBR); \ ++ }) ++#define PKTCLRTOBR(osh, skb) \ ++ ({ \ ++ BCM_REFERENCE(osh); \ ++ (((struct sk_buff*)(skb))->pktc_flags &= (~TOBR)); \ ++ }) ++#define PKTISTOBR(skb) (((struct sk_buff*)(skb))->pktc_flags & TOBR) ++#define PKTSETCTFIPCTXIF(skb, ifp) (((struct sk_buff*)(skb))->ctf_ipc_txif = ifp) ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) ++#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) ++#define PKTSETCTFIPCTXIF(skb, ifp) ({BCM_REFERENCE(skb); BCM_REFERENCE(ifp);}) ++#else /* 2.6.22 */ ++#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) ++#define PKTSETCTFIPCTXIF(skb, ifp) ({BCM_REFERENCE(skb); BCM_REFERENCE(ifp);}) ++#endif /* 2.6.22 */ ++#else /* HNDCTF */ ++#define PKTSETTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTCLRTOBR(osh, skb) ({BCM_REFERENCE(osh); BCM_REFERENCE(skb);}) ++#define PKTISTOBR(skb) ({BCM_REFERENCE(skb); FALSE;}) ++#endif /* HNDCTF */ ++ ++ ++#ifdef BCMFA ++#ifdef BCMFA_HW_HASH ++#define PKTSETFAHIDX(skb, idx) (((struct sk_buff*)(skb))->napt_idx = idx) ++#else ++#define PKTSETFAHIDX(skb, idx) ({BCM_REFERENCE(skb); BCM_REFERENCE(idx);}) ++#endif /* BCMFA_SW_HASH */ ++#define PKTGETFAHIDX(skb) (((struct sk_buff*)(skb))->napt_idx) ++#define PKTSETFADEV(skb, imp) (((struct sk_buff*)(skb))->dev = imp) ++#define PKTSETRXDEV(skb) (((struct sk_buff*)(skb))->rxdev = ((struct sk_buff*)(skb))->dev) ++ ++#define AUX_TCP_FIN_RST (1 << 0) ++#define AUX_FREED (1 << 1) ++#define PKTSETFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags |= AUX_TCP_FIN_RST) ++#define PKTCLRFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags &= (~AUX_TCP_FIN_RST)) ++#define PKTISFAAUX(skb) (((struct sk_buff*)(skb))->napt_flags & AUX_TCP_FIN_RST) ++#define PKTSETFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags |= AUX_FREED) ++#define PKTCLRFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags &= (~AUX_FREED)) ++#define PKTISFAFREED(skb) (((struct sk_buff*)(skb))->napt_flags & AUX_FREED) ++#define PKTISFABRIDGED(skb) PKTISFAAUX(skb) ++#else ++#define PKTISFAAUX(skb) ({BCM_REFERENCE(skb); FALSE;}) ++#define PKTISFABRIDGED(skb) ({BCM_REFERENCE(skb); FALSE;}) ++#define PKTISFAFREED(skb) ({BCM_REFERENCE(skb); FALSE;}) ++ ++#define PKTCLRFAAUX(skb) BCM_REFERENCE(skb) ++#define PKTSETFAFREED(skb) BCM_REFERENCE(skb) ++#define PKTCLRFAFREED(skb) BCM_REFERENCE(skb) ++#endif /* BCMFA */ ++ ++#if defined(BCM_OBJECT_TRACE) ++extern void osl_pktfree(osl_t *osh, void *skb, bool send, int line, const char *caller); ++#else ++extern void osl_pktfree(osl_t *osh, void *skb, bool send); ++#endif /* BCM_OBJECT_TRACE */ ++extern void *osl_pktget_static(osl_t *osh, uint len); ++extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); ++extern void osl_pktclone(osl_t *osh, void **pkt); ++ ++#ifdef BCMDBG_CTRACE ++#define PKT_CTRACE_DUMP(osh, b) osl_ctrace_dump((osh), (b)) ++extern void *osl_pktget(osl_t *osh, uint len, int line, char *file); ++extern void *osl_pkt_frmnative(osl_t *osh, void *skb, int line, char *file); ++extern int osl_pkt_is_frmnative(osl_t *osh, struct sk_buff *pkt); ++extern void *osl_pktdup(osl_t *osh, void *skb, int line, char *file); ++struct bcmstrbuf; ++extern void osl_ctrace_dump(osl_t *osh, struct bcmstrbuf *b); ++#else ++#ifdef BCM_OBJECT_TRACE ++extern void *osl_pktget(osl_t *osh, uint len, int line, const char *caller); ++extern void *osl_pktdup(osl_t *osh, void *skb, int line, const char *caller); ++#else ++extern void *osl_pktget(osl_t *osh, uint len); ++extern void *osl_pktdup(osl_t *osh, void *skb); ++#endif /* BCM_OBJECT_TRACE */ ++extern void *osl_pkt_frmnative(osl_t *osh, void *skb); ++#endif /* BCMDBG_CTRACE */ ++extern struct sk_buff *osl_pkt_tonative(osl_t *osh, void *pkt); ++#ifdef BCMDBG_CTRACE ++#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), \ ++ (struct sk_buff*)(skb), __LINE__, __FILE__) ++#define PKTISFRMNATIVE(osh, skb) osl_pkt_is_frmnative((osl_t *)(osh), (struct sk_buff *)(skb)) ++#else ++#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_t *)osh), (struct sk_buff*)(skb)) ++#endif /* BCMDBG_CTRACE */ ++#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_t *)(osh), (pkt)) ++ ++#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev) ++#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x)) ++#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority) ++#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) ++#define PKTSUMNEEDED(skb) (((struct sk_buff*)(skb))->ip_summed == CHECKSUM_HW) ++#define PKTSETSUMGOOD(skb, x) (((struct sk_buff*)(skb))->ip_summed = \ ++ ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE)) ++/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */ ++#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned) ++ ++#ifdef CONFIG_NF_CONNTRACK_MARK ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define PKTMARK(p) (((struct sk_buff *)(p))->mark) ++#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->mark = (m) ++#else /* !2.6.0 */ ++#define PKTMARK(p) (((struct sk_buff *)(p))->nfmark) ++#define PKTSETMARK(p, m) ((struct sk_buff *)(p))->nfmark = (m) ++#endif /* 2.6.0 */ ++#else /* CONFIG_NF_CONNTRACK_MARK */ ++#define PKTMARK(p) 0 ++#define PKTSETMARK(p, m) ++#endif /* CONFIG_NF_CONNTRACK_MARK */ ++ ++#define PKTALLOCED(osh) osl_pktalloced(osh) ++extern uint osl_pktalloced(osl_t *osh); ++ ++#define OSL_RAND() osl_rand() ++extern uint32 osl_rand(void); ++ ++#if !defined(BCM_SECURE_DMA) ++#define DMA_MAP(osh, va, size, direction, p, dmah) \ ++ osl_dma_map((osh), (va), (size), (direction), (p), (dmah)) ++#endif /* !(defined(BCM_SECURE_DMA)) */ ++ ++#ifdef PKTC ++/* Use 8 bytes of skb tstamp field to store below info */ ++struct chain_node { ++ struct sk_buff *link; ++ unsigned int flags:3, pkts:9, bytes:20; ++}; ++ ++#define CHAIN_NODE(skb) ((struct chain_node*)(((struct sk_buff*)skb)->pktc_cb)) ++ ++#define PKTCSETATTR(s, f, p, b) ({CHAIN_NODE(s)->flags = (f); CHAIN_NODE(s)->pkts = (p); \ ++ CHAIN_NODE(s)->bytes = (b);}) ++#define PKTCCLRATTR(s) ({CHAIN_NODE(s)->flags = CHAIN_NODE(s)->pkts = \ ++ CHAIN_NODE(s)->bytes = 0;}) ++#define PKTCGETATTR(s) (CHAIN_NODE(s)->flags << 29 | CHAIN_NODE(s)->pkts << 20 | \ ++ CHAIN_NODE(s)->bytes) ++#define PKTCCNT(skb) (CHAIN_NODE(skb)->pkts) ++#define PKTCLEN(skb) (CHAIN_NODE(skb)->bytes) ++#define PKTCGETFLAGS(skb) (CHAIN_NODE(skb)->flags) ++#define PKTCSETFLAGS(skb, f) (CHAIN_NODE(skb)->flags = (f)) ++#define PKTCCLRFLAGS(skb) (CHAIN_NODE(skb)->flags = 0) ++#define PKTCFLAGS(skb) (CHAIN_NODE(skb)->flags) ++#define PKTCSETCNT(skb, c) (CHAIN_NODE(skb)->pkts = (c)) ++#define PKTCINCRCNT(skb) (CHAIN_NODE(skb)->pkts++) ++#define PKTCADDCNT(skb, c) (CHAIN_NODE(skb)->pkts += (c)) ++#define PKTCSETLEN(skb, l) (CHAIN_NODE(skb)->bytes = (l)) ++#define PKTCADDLEN(skb, l) (CHAIN_NODE(skb)->bytes += (l)) ++#define PKTCSETFLAG(skb, fb) (CHAIN_NODE(skb)->flags |= (fb)) ++#define PKTCCLRFLAG(skb, fb) (CHAIN_NODE(skb)->flags &= ~(fb)) ++#define PKTCLINK(skb) (CHAIN_NODE(skb)->link) ++#define PKTSETCLINK(skb, x) (CHAIN_NODE(skb)->link = (struct sk_buff*)(x)) ++#define FOREACH_CHAINED_PKT(skb, nskb) \ ++ for (; (skb) != NULL; (skb) = (nskb)) \ ++ if ((nskb) = (PKTISCHAINED(skb) ? PKTCLINK(skb) : NULL), \ ++ PKTSETCLINK((skb), NULL), 1) ++#define PKTCFREE(osh, skb, send) \ ++do { \ ++ void *nskb; \ ++ ASSERT((skb) != NULL); \ ++ FOREACH_CHAINED_PKT((skb), nskb) { \ ++ PKTCLRCHAINED((osh), (skb)); \ ++ PKTCCLRFLAGS((skb)); \ ++ PKTFREE((osh), (skb), (send)); \ ++ } \ ++} while (0) ++#define PKTCENQTAIL(h, t, p) \ ++do { \ ++ if ((t) == NULL) { \ ++ (h) = (t) = (p); \ ++ } else { \ ++ PKTSETCLINK((t), (p)); \ ++ (t) = (p); \ ++ } \ ++} while (0) ++#endif /* PKTC */ ++ ++#else /* ! BCMDRIVER */ ++ ++ ++/* ASSERT */ ++ #define ASSERT(exp) do {} while (0) ++ ++/* MALLOC and MFREE */ ++#define MALLOC(o, l) malloc(l) ++#define MFREE(o, p, l) free(p) ++#include ++ ++/* str* and mem* functions */ ++#include ++ ++/* *printf functions */ ++#include ++ ++/* bcopy, bcmp, and bzero */ ++extern void bcopy(const void *src, void *dst, size_t len); ++extern int bcmp(const void *b1, const void *b2, size_t len); ++extern void bzero(void *b, size_t len); ++#endif /* ! BCMDRIVER */ ++ ++/* Current STB 7445D1 doesn't use ACP and it is non-coherrent. ++ * Adding these dummy values for build apss only ++ * When we revisit need to change these. ++ */ ++#if defined(STBLINUX) ++ ++#if defined(__ARM_ARCH_7A__) ++#define ACP_WAR_ENAB() 0 ++#define ACP_WIN_LIMIT 1 ++#define arch_is_coherent() 0 ++#endif /* __ARM_ARCH_7A__ */ ++ ++#endif /* STBLINUX */ ++ ++#ifdef BCM_SECURE_DMA ++ ++#define SECURE_DMA_MAP(osh, va, size, direction, p, dmah, pcma, offset) \ ++ osl_sec_dma_map((osh), (va), (size), (direction), (p), (dmah), (pcma), (offset)) ++#define SECURE_DMA_DD_MAP(osh, va, size, direction, p, dmah) \ ++ osl_sec_dma_dd_map((osh), (va), (size), (direction), (p), (dmah)) ++#define SECURE_DMA_MAP_TXMETA(osh, va, size, direction, p, dmah, pcma) \ ++ osl_sec_dma_map_txmeta((osh), (va), (size), (direction), (p), (dmah), (pcma)) ++#define SECURE_DMA_UNMAP(osh, pa, size, direction, p, dmah, pcma, offset) \ ++ osl_sec_dma_unmap((osh), (pa), (size), (direction), (p), (dmah), (pcma), (offset)) ++#define SECURE_DMA_UNMAP_ALL(osh, pcma) \ ++ osl_sec_dma_unmap_all((osh), (pcma)) ++ ++#define DMA_MAP(osh, va, size, direction, p, dmah) ++ ++typedef struct sec_cma_info { ++ struct sec_mem_elem *sec_alloc_list; ++ struct sec_mem_elem *sec_alloc_list_tail; ++} sec_cma_info_t; ++ ++#if defined(__ARM_ARCH_7A__) ++#define CMA_BUFSIZE_4K 4096 ++#define CMA_BUFSIZE_2K 2048 ++#define CMA_BUFSIZE_512 512 ++ ++#define CMA_BUFNUM 2048 ++#define SEC_CMA_COHERENT_BLK 0x8000 /* 32768 */ ++#define SEC_CMA_COHERENT_MAX 278 ++#define CMA_DMA_DESC_MEMBLOCK (SEC_CMA_COHERENT_BLK * SEC_CMA_COHERENT_MAX) ++#define CMA_DMA_DATA_MEMBLOCK (CMA_BUFSIZE_4K*CMA_BUFNUM) ++#define CMA_MEMBLOCK (CMA_DMA_DESC_MEMBLOCK + CMA_DMA_DATA_MEMBLOCK) ++#define CONT_REGION 0x02 /* Region CMA */ ++#else ++#define CONT_REGION 0x00 /* To access the MIPs mem, Not yet... */ ++#endif /* !defined __ARM_ARCH_7A__ */ ++ ++#define SEC_DMA_ALIGN (1<<16) ++typedef struct sec_mem_elem { ++ size_t size; ++ int direction; ++ phys_addr_t pa_cma; /**< physical address */ ++ void *va; /**< virtual address of driver pkt */ ++ dma_addr_t dma_handle; /**< bus address assign by linux */ ++ void *vac; /**< virtual address of cma buffer */ ++ struct page *pa_cma_page; /* phys to page address */ ++ struct sec_mem_elem *next; ++} sec_mem_elem_t; ++ ++extern dma_addr_t osl_sec_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, ++ hnddma_seg_map_t *dmah, void *ptr_cma_info, uint offset); ++extern dma_addr_t osl_sec_dma_dd_map(osl_t *osh, void *va, uint size, int direction, void *p, ++ hnddma_seg_map_t *dmah); ++extern dma_addr_t osl_sec_dma_map_txmeta(osl_t *osh, void *va, uint size, ++ int direction, void *p, hnddma_seg_map_t *dmah, void *ptr_cma_info); ++extern void osl_sec_dma_unmap(osl_t *osh, dma_addr_t dma_handle, uint size, int direction, ++ void *p, hnddma_seg_map_t *map, void *ptr_cma_info, uint offset); ++extern void osl_sec_dma_unmap_all(osl_t *osh, void *ptr_cma_info); ++ ++#endif /* BCM_SECURE_DMA */ ++ ++typedef struct sk_buff_head PKT_LIST; ++#define PKTLIST_INIT(x) skb_queue_head_init((x)) ++#define PKTLIST_ENQ(x, y) skb_queue_head((struct sk_buff_head *)(x), (struct sk_buff *)(y)) ++#define PKTLIST_DEQ(x) skb_dequeue((struct sk_buff_head *)(x)) ++#define PKTLIST_UNLINK(x, y) skb_unlink((struct sk_buff *)(y), (struct sk_buff_head *)(x)) ++#define PKTLIST_FINI(x) skb_queue_purge((struct sk_buff_head *)(x)) ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++typedef struct osl_timer { ++ struct timer_list *timer; ++ bool set; ++} osl_timer_t; ++ ++typedef void (*linux_timer_fn)(ulong arg); ++ ++extern osl_timer_t * osl_timer_init(osl_t *osh, const char *name, void (*fn)(void *arg), void *arg); ++extern void osl_timer_add(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic); ++extern void osl_timer_update(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic); ++extern bool osl_timer_del(osl_t *osh, osl_timer_t *t); ++#endif ++ ++typedef struct osl_timespec { ++ time64_t tv_sec; /* seconds */ ++ __kernel_suseconds_t tv_usec; /* microseconds */ ++ long tv_nsec; /* nanoseconds */ ++} osl_timespec_t; ++extern void osl_do_gettimeofday(struct osl_timespec *ts); ++extern void osl_get_monotonic_boottime(struct osl_timespec *ts); ++ ++#endif /* _linux_osl_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/linuxver.h b/module_drivers/drivers/net/wireless/bcmdhd/include/linuxver.h +new file mode 100644 +index 000000000..d96d09365 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/linuxver.h +@@ -0,0 +1,812 @@ ++/* ++ * Linux-specific abstractions to gain some independence from linux kernel versions. ++ * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: linuxver.h 646721 2016-06-30 12:36:41Z $ ++ */ ++ ++#ifndef _linuxver_h_ ++#define _linuxver_h_ ++ ++#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wunused-but-set-variable" ++#pragma GCC diagnostic ignored "-Wunused-but-set-parameter" ++#endif ++ ++#include ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++#include ++#else ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) ++#include ++#else ++#include ++#endif ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)) ++#include ++#endif ++#include ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) ++/* __NO_VERSION__ must be defined for all linkables except one in 2.2 */ ++#ifdef __UNDEF_NO_VERSION__ ++#undef __NO_VERSION__ ++#else ++#define __NO_VERSION__ ++#endif ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) ++#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i") ++#define module_param_string(_name_, _string_, _size_, _perm_) \ ++ MODULE_PARM(_string_, "c" __MODULE_STRING(_size_)) ++#endif ++ ++/* linux/malloc.h is deprecated, use linux/slab.h instead. */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)) ++#include ++#else ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++#include ++#else ++#include ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) ++#undef IP_TOS ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) */ ++#include ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41)) ++#include ++#else ++#include ++#ifndef work_struct ++#define work_struct tq_struct ++#endif ++#ifndef INIT_WORK ++#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data)) ++#endif ++#ifndef schedule_work ++#define schedule_work(_work) schedule_task((_work)) ++#endif ++#ifndef flush_scheduled_work ++#define flush_scheduled_work() flush_scheduled_tasks() ++#endif ++#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) ++#define DAEMONIZE(a) do { \ ++ allow_signal(SIGKILL); \ ++ allow_signal(SIGTERM); \ ++ } while (0) ++#elif ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) && \ ++ (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))) ++#define DAEMONIZE(a) daemonize(a); \ ++ allow_signal(SIGKILL); \ ++ allow_signal(SIGTERM); ++#else /* Linux 2.4 (w/o preemption patch) */ ++#define RAISE_RX_SOFTIRQ() \ ++ cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) ++#define DAEMONIZE(a) daemonize(); \ ++ do { if (a) \ ++ strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a)))); \ ++ } while (0); ++#endif /* LINUX_VERSION_CODE */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) ++#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func) ++#else ++#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work) ++#if !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18) && defined(RHEL_MAJOR) && \ ++ (RHEL_MAJOR == 5)) ++/* Exclude RHEL 5 */ ++typedef void (*work_func_t)(void *work); ++#endif ++#endif /* >= 2.6.20 */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++/* Some distributions have their own 2.6.x compatibility layers */ ++#ifndef IRQ_NONE ++typedef void irqreturn_t; ++#define IRQ_NONE ++#define IRQ_HANDLED ++#define IRQ_RETVAL(x) ++#endif ++#else ++typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) ++#define IRQF_SHARED SA_SHIRQ ++#endif /* < 2.6.18 */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) ++#ifdef CONFIG_NET_RADIO ++#define CONFIG_WIRELESS_EXT ++#endif ++#endif /* < 2.6.17 */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) ++#define MOD_INC_USE_COUNT ++#define MOD_DEC_USE_COUNT ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67) */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) ++#include ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) ++#include ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++#include ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++#include ++#else ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) ++#include ++#endif ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */ ++ ++ ++#ifndef __exit ++#define __exit ++#endif ++#ifndef __devexit ++#define __devexit ++#endif ++#ifndef __devinit ++# if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) ++# define __devinit __init ++# else ++/* All devices are hotpluggable since linux 3.8.0 */ ++# define __devinit ++# endif ++#endif /* !__devinit */ ++#ifndef __devinitdata ++#define __devinitdata ++#endif ++#ifndef __devexit_p ++#define __devexit_p(x) x ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)) ++ ++#define pci_get_drvdata(dev) (dev)->sysdata ++#define pci_set_drvdata(dev, value) (dev)->sysdata = (value) ++ ++/* ++ * New-style (2.4.x) PCI/hot-pluggable PCI/CardBus registration ++ */ ++ ++struct pci_device_id { ++ unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ ++ unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ ++ unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ ++ unsigned long driver_data; /* Data private to the driver */ ++}; ++ ++struct pci_driver { ++ struct list_head node; ++ char *name; ++ const struct pci_device_id *id_table; /* NULL if wants all devices */ ++ int (*probe)(struct pci_dev *dev, ++ const struct pci_device_id *id); /* New device inserted */ ++ void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug ++ * capable driver) ++ */ ++ void (*suspend)(struct pci_dev *dev); /* Device suspended */ ++ void (*resume)(struct pci_dev *dev); /* Device woken up */ ++}; ++ ++#define MODULE_DEVICE_TABLE(type, name) ++#define PCI_ANY_ID (~0) ++ ++/* compatpci.c */ ++#define pci_module_init pci_register_driver ++extern int pci_register_driver(struct pci_driver *drv); ++extern void pci_unregister_driver(struct pci_driver *drv); ++ ++#endif /* PCI registration */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)) ++#define pci_module_init pci_register_driver ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) ++#ifdef MODULE ++#define module_init(x) int init_module(void) { return x(); } ++#define module_exit(x) void cleanup_module(void) { x(); } ++#else ++#define module_init(x) __initcall(x); ++#define module_exit(x) __exitcall(x); ++#endif ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) ++#define WL_USE_NETDEV_OPS ++#else ++#undef WL_USE_NETDEV_OPS ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL) ++#define WL_CONFIG_RFKILL ++#else ++#undef WL_CONFIG_RFKILL ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48)) ++#define list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); pos = pos->next) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13)) ++#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)]) ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44)) ++#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23)) ++#define pci_enable_device(dev) do { } while (0) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14)) ++#define net_device device ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42)) ++ ++/* ++ * DMA mapping ++ * ++ * See linux/Documentation/DMA-mapping.txt ++ */ ++ ++#ifndef PCI_DMA_TODEVICE ++#define PCI_DMA_TODEVICE 1 ++#define PCI_DMA_FROMDEVICE 2 ++#endif ++ ++typedef u32 dma_addr_t; ++ ++/* Pure 2^n version of get_order */ ++static inline int get_order(unsigned long size) ++{ ++ int order; ++ ++ size = (size-1) >> (PAGE_SHIFT-1); ++ order = -1; ++ do { ++ size >>= 1; ++ order++; ++ } while (size); ++ return order; ++} ++ ++static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, ++ dma_addr_t *dma_handle) ++{ ++ void *ret; ++ int gfp = GFP_ATOMIC | GFP_DMA; ++ ++ ret = (void *)__get_free_pages(gfp, get_order(size)); ++ ++ if (ret != NULL) { ++ memset(ret, 0, size); ++ *dma_handle = virt_to_bus(ret); ++ } ++ return ret; ++} ++static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, ++ void *vaddr, dma_addr_t dma_handle) ++{ ++ free_pages((unsigned long)vaddr, get_order(size)); ++} ++#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) ++#define pci_unmap_single(cookie, address, size, dir) ++ ++#endif /* DMA mapping */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) ++ ++typedef struct timer_list timer_list_compat_t; ++ ++#define init_timer_compat(timer_compat, cb, priv) \ ++ init_timer(timer_compat); \ ++ (timer_compat)->data = (ulong)priv; \ ++ (timer_compat)->function = cb ++#define timer_set_private(timer_compat, priv) (timer_compat)->data = (ulong)priv ++#define timer_expires(timer_compat) (timer_compat)->expires ++ ++#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) */ ++ ++typedef struct timer_list_compat { ++ struct timer_list timer; ++ void *arg; ++ void (*callback)(ulong arg); ++} timer_list_compat_t; ++ ++extern void timer_cb_compat(struct timer_list *tl); ++ ++#define init_timer_compat(timer_compat, cb, priv) \ ++ (timer_compat)->arg = priv; \ ++ (timer_compat)->callback = cb; \ ++ timer_setup(&(timer_compat)->timer, timer_cb_compat, 0); ++#define timer_set_private(timer_compat, priv) (timer_compat)->arg = priv ++#define timer_expires(timer_compat) (timer_compat)->timer.expires ++ ++#define _del_timer_sync(t) del_timer_sync(&((t)->timer)) ++#define _del_timer(t) del_timer(&((t)->timer)) ++#define timer_pending(t) timer_pending(&((t)->timer)) ++#define add_timer(t) add_timer(&((t)->timer)) ++#define mod_timer(t, j) mod_timer(&((t)->timer), j) ++ ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43)) ++ ++#define dev_kfree_skb_any(a) dev_kfree_skb(a) ++#define netif_down(dev) do { (dev)->start = 0; } while (0) ++ ++/* pcmcia-cs provides its own netdevice compatibility layer */ ++#ifndef _COMPAT_NETDEVICE_H ++ ++/* ++ * SoftNet ++ * ++ * For pre-softnet kernels we need to tell the upper layer not to ++ * re-enter start_xmit() while we are in there. However softnet ++ * guarantees not to enter while we are in there so there is no need ++ * to do the netif_stop_queue() dance unless the transmit queue really ++ * gets stuck. This should also improve performance according to tests ++ * done by Aman Singla. ++ */ ++ ++#define dev_kfree_skb_irq(a) dev_kfree_skb(a) ++#define netif_wake_queue(dev) \ ++ do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0) ++#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy) ++ ++static inline void netif_start_queue(struct net_device *dev) ++{ ++ dev->tbusy = 0; ++ dev->interrupt = 0; ++ dev->start = 1; ++} ++ ++#define netif_queue_stopped(dev) (dev)->tbusy ++#define netif_running(dev) (dev)->start ++ ++#endif /* _COMPAT_NETDEVICE_H */ ++ ++#define netif_device_attach(dev) netif_start_queue(dev) ++#define netif_device_detach(dev) netif_stop_queue(dev) ++ ++/* 2.4.x renamed bottom halves to tasklets */ ++#define tasklet_struct tq_struct ++static inline void tasklet_schedule(struct tasklet_struct *tasklet) ++{ ++ queue_task(tasklet, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++} ++ ++static inline void tasklet_init(struct tasklet_struct *tasklet, ++ void (*func)(unsigned long), ++ unsigned long data) ++{ ++ tasklet->next = NULL; ++ tasklet->sync = 0; ++ tasklet->routine = (void (*)(void *))func; ++ tasklet->data = (void *)data; ++} ++#define tasklet_kill(tasklet) { do {} while (0); } ++ ++/* 2.4.x introduced del_timer_sync() */ ++#define del_timer_sync(timer) del_timer(timer) ++ ++#else ++ ++#define netif_down(dev) ++ ++#endif /* SoftNet */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3)) ++ ++/* ++ * Emit code to initialise a tq_struct's routine and data pointers ++ */ ++#define PREPARE_TQUEUE(_tq, _routine, _data) \ ++ do { \ ++ (_tq)->routine = _routine; \ ++ (_tq)->data = _data; \ ++ } while (0) ++ ++/* ++ * Emit code to initialise all of a tq_struct ++ */ ++#define INIT_TQUEUE(_tq, _routine, _data) \ ++ do { \ ++ INIT_LIST_HEAD(&(_tq)->list); \ ++ (_tq)->sync = 0; \ ++ PREPARE_TQUEUE((_tq), (_routine), (_data)); \ ++ } while (0) ++ ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) */ ++ ++/* Power management related macro & routines */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) ++#define PCI_SAVE_STATE(a, b) pci_save_state(a) ++#define PCI_RESTORE_STATE(a, b) pci_restore_state(a) ++#else ++#define PCI_SAVE_STATE(a, b) pci_save_state(a, b) ++#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6)) ++static inline int ++pci_save_state(struct pci_dev *dev, u32 *buffer) ++{ ++ int i; ++ if (buffer) { ++ for (i = 0; i < 16; i++) ++ pci_read_config_dword(dev, i * 4, &buffer[i]); ++ } ++ return 0; ++} ++ ++static inline int ++pci_restore_state(struct pci_dev *dev, u32 *buffer) ++{ ++ int i; ++ ++ if (buffer) { ++ for (i = 0; i < 16; i++) ++ pci_write_config_dword(dev, i * 4, buffer[i]); ++ } ++ /* ++ * otherwise, write the context information we know from bootup. ++ * This works around a problem where warm-booting from Windows ++ * combined with a D3(hot)->D0 transition causes PCI config ++ * header data to be forgotten. ++ */ ++ else { ++ for (i = 0; i < 6; i ++) ++ pci_write_config_dword(dev, ++ PCI_BASE_ADDRESS_0 + (i * 4), ++ pci_resource_start(dev, i)); ++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); ++ } ++ return 0; ++} ++#endif /* PCI power management */ ++ ++/* Old cp0 access macros deprecated in 2.4.19 */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19)) ++#define read_c0_count() read_32bit_cp0_register(CP0_COUNT) ++#endif ++ ++/* Module refcount handled internally in 2.6.x */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++#ifndef SET_MODULE_OWNER ++#define SET_MODULE_OWNER(dev) do {} while (0) ++#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT ++#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT ++#else ++#define OLD_MOD_INC_USE_COUNT do {} while (0) ++#define OLD_MOD_DEC_USE_COUNT do {} while (0) ++#endif ++#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ ++#ifndef SET_MODULE_OWNER ++#define SET_MODULE_OWNER(dev) do {} while (0) ++#endif ++#ifndef MOD_INC_USE_COUNT ++#define MOD_INC_USE_COUNT do {} while (0) ++#endif ++#ifndef MOD_DEC_USE_COUNT ++#define MOD_DEC_USE_COUNT do {} while (0) ++#endif ++#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT ++#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) */ ++ ++#ifndef SET_NETDEV_DEV ++#define SET_NETDEV_DEV(net, pdev) do {} while (0) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)) ++#ifndef HAVE_FREE_NETDEV ++#define free_netdev(dev) kfree(dev) ++#endif ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++/* struct packet_type redefined in 2.6.x */ ++#define af_packet_priv data ++#endif ++ ++/* suspend args */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) ++#define DRV_SUSPEND_STATE_TYPE pm_message_t ++#else ++#define DRV_SUSPEND_STATE_TYPE uint32 ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) ++#define CHECKSUM_HW CHECKSUM_PARTIAL ++#endif ++ ++typedef struct { ++ void *parent; /* some external entity that the thread supposed to work for */ ++ char *proc_name; ++ struct task_struct *p_task; ++ long thr_pid; ++ int prio; /* priority */ ++ struct semaphore sema; ++ int terminated; ++ struct completion completed; ++ spinlock_t spinlock; ++ int up_cnt; ++} tsk_ctl_t; ++ ++ ++/* requires tsk_ctl_t tsk argument, the caller's priv data is passed in owner ptr */ ++/* note this macro assumes there may be only one context waiting on thread's completion */ ++#ifdef DHD_DEBUG ++#define DBG_THR(x) printk x ++#else ++#define DBG_THR(x) ++#endif ++ ++static inline bool binary_sema_down(tsk_ctl_t *tsk) ++{ ++ if (down_interruptible(&tsk->sema) == 0) { ++ unsigned long flags = 0; ++ spin_lock_irqsave(&tsk->spinlock, flags); ++ if (tsk->up_cnt == 1) ++ tsk->up_cnt--; ++ else { ++ DBG_THR(("dhd_dpc_thread: Unexpected up_cnt %d\n", tsk->up_cnt)); ++ } ++ spin_unlock_irqrestore(&tsk->spinlock, flags); ++ return false; ++ } else ++ return true; ++} ++ ++static inline bool binary_sema_up(tsk_ctl_t *tsk) ++{ ++ bool sem_up = false; ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&tsk->spinlock, flags); ++ if (tsk->up_cnt == 0) { ++ tsk->up_cnt++; ++ sem_up = true; ++ } else if (tsk->up_cnt == 1) { ++ /* dhd_sched_dpc: dpc is alread up! */ ++ } else ++ DBG_THR(("dhd_sched_dpc: unexpected up cnt %d!\n", tsk->up_cnt)); ++ ++ spin_unlock_irqrestore(&tsk->spinlock, flags); ++ ++ if (sem_up) ++ up(&tsk->sema); ++ ++ return sem_up; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#define smp_read_barrier_depends() do {} while(0) ++#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) ++#else ++#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) ++#endif ++ ++#define PROC_START(thread_func, owner, tsk_ctl, flags, name) \ ++{ \ ++ sema_init(&((tsk_ctl)->sema), 0); \ ++ init_completion(&((tsk_ctl)->completed)); \ ++ (tsk_ctl)->parent = owner; \ ++ (tsk_ctl)->proc_name = name; \ ++ (tsk_ctl)->terminated = FALSE; \ ++ (tsk_ctl)->p_task = kthread_run(thread_func, tsk_ctl, (char*)name); \ ++ if (IS_ERR((tsk_ctl)->p_task)) { \ ++ (tsk_ctl)->thr_pid = DHD_PID_KT_INVALID; \ ++ DBG_THR(("%s(): thread:%s:%lx failed\n", __FUNCTION__, \ ++ (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ ++ } else { \ ++ (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \ ++ spin_lock_init(&((tsk_ctl)->spinlock)); \ ++ DBG_THR(("%s(): thread:%s:%lx started\n", __FUNCTION__, \ ++ (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ ++ }; \ ++} ++ ++#define PROC_STOP(tsk_ctl) \ ++{ \ ++ (tsk_ctl)->terminated = TRUE; \ ++ smp_wmb(); \ ++ up(&((tsk_ctl)->sema)); \ ++ wait_for_completion(&((tsk_ctl)->completed)); \ ++ DBG_THR(("%s(): thread:%s:%lx terminated OK\n", __FUNCTION__, \ ++ (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \ ++ (tsk_ctl)->thr_pid = -1; \ ++} ++ ++/* ----------------------- */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) ++#define KILL_PROC(nr, sig) \ ++{ \ ++struct task_struct *tsk; \ ++struct pid *pid; \ ++pid = find_get_pid((pid_t)nr); \ ++tsk = pid_task(pid, PIDTYPE_PID); \ ++if (tsk) send_sig(sig, tsk, 1); \ ++} ++#else ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ ++ KERNEL_VERSION(2, 6, 30)) ++#define KILL_PROC(pid, sig) \ ++{ \ ++ struct task_struct *tsk; \ ++ tsk = find_task_by_vpid(pid); \ ++ if (tsk) send_sig(sig, tsk, 1); \ ++} ++#else ++#define KILL_PROC(pid, sig) \ ++{ \ ++ kill_proc(pid, sig, 1); \ ++} ++#endif ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) ++#include ++#include ++#else ++#include ++ ++#define __wait_event_interruptible_timeout(wq, condition, ret) \ ++do { \ ++ wait_queue_t __wait; \ ++ init_waitqueue_entry(&__wait, current); \ ++ \ ++ add_wait_queue(&wq, &__wait); \ ++ for (;;) { \ ++ set_current_state(TASK_INTERRUPTIBLE); \ ++ if (condition) \ ++ break; \ ++ if (!signal_pending(current)) { \ ++ ret = schedule_timeout(ret); \ ++ if (!ret) \ ++ break; \ ++ continue; \ ++ } \ ++ ret = -ERESTARTSYS; \ ++ break; \ ++ } \ ++ current->state = TASK_RUNNING; \ ++ remove_wait_queue(&wq, &__wait); \ ++} while (0) ++ ++#define wait_event_interruptible_timeout(wq, condition, timeout) \ ++({ \ ++ long __ret = timeout; \ ++ if (!(condition)) \ ++ __wait_event_interruptible_timeout(wq, condition, __ret); \ ++ __ret; \ ++}) ++ ++#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ ++ ++/* ++For < 2.6.24, wl creates its own netdev but doesn't ++align the priv area like the genuine alloc_netdev(). ++Since netdev_priv() always gives us the aligned address, it will ++not match our unaligned address for < 2.6.24 ++*/ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) ++#define DEV_PRIV(dev) (dev->priv) ++#else ++#define DEV_PRIV(dev) netdev_priv(dev) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) ++#define WL_ISR(i, d, p) wl_isr((i), (d)) ++#else ++#define WL_ISR(i, d, p) wl_isr((i), (d), (p)) ++#endif /* < 2.6.20 */ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++#define netdev_priv(dev) dev->priv ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) ++#define CAN_SLEEP() ((!in_atomic() && !irqs_disabled())) ++#else ++#define CAN_SLEEP() (FALSE) ++#endif ++ ++#define KMALLOC_FLAG (CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC) ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) ++#define RANDOM32 prandom_u32 ++#else ++#define RANDOM32 random32 ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) ++#define SRANDOM32(entropy) prandom_seed(entropy) ++#else ++#define SRANDOM32(entropy) srandom32(entropy) ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) */ ++ ++/* ++ * Overide latest kfifo functions with ++ * older version to work on older kernels ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) ++#define kfifo_in_spinlocked(a, b, c, d) kfifo_put(a, (u8 *)b, c) ++#define kfifo_out_spinlocked(a, b, c, d) kfifo_get(a, (u8 *)b, c) ++#define kfifo_esize(a) 1 ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)) && \ ++ (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)) && !defined(WL_COMPAT_WIRELESS) ++#define kfifo_in_spinlocked(a, b, c, d) kfifo_in_locked(a, b, c, d) ++#define kfifo_out_spinlocked(a, b, c, d) kfifo_out_locked(a, b, c, d) ++#define kfifo_esize(a) 1 ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ ++ ++#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) ++#pragma GCC diagnostic pop ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) ++#include ++static inline struct inode *file_inode(const struct file *f) ++{ ++ return f->f_dentry->d_inode; ++} ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */ ++ ++#endif /* _linuxver_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/miniopt.h b/module_drivers/drivers/net/wireless/bcmdhd/include/miniopt.h +new file mode 100644 +index 000000000..672235143 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/miniopt.h +@@ -0,0 +1,83 @@ ++/* ++ * Command line options parser. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: miniopt.h 514727 2014-11-12 03:02:48Z $ ++ */ ++ ++ ++#ifndef MINI_OPT_H ++#define MINI_OPT_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ---- Include Files ---------------------------------------------------- */ ++ ++ ++/* ---- Constants and Types ---------------------------------------------- */ ++ ++#define MINIOPT_MAXKEY 128 /* Max options */ ++typedef struct miniopt { ++ ++ /* These are persistent after miniopt_init() */ ++ const char* name; /* name for prompt in error strings */ ++ const char* flags; /* option chars that take no args */ ++ bool longflags; /* long options may be flags */ ++ bool opt_end; /* at end of options (passed a "--") */ ++ ++ /* These are per-call to miniopt() */ ++ ++ int consumed; /* number of argv entries cosumed in ++ * the most recent call to miniopt() ++ */ ++ bool positional; ++ bool good_int; /* 'val' member is the result of a sucessful ++ * strtol conversion of the option value ++ */ ++ char opt; ++ char key[MINIOPT_MAXKEY]; ++ char* valstr; /* positional param, or value for the option, ++ * or null if the option had ++ * no accompanying value ++ */ ++ uint uval; /* strtol translation of valstr */ ++ int val; /* strtol translation of valstr */ ++} miniopt_t; ++ ++void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); ++int miniopt(miniopt_t *t, char **argv); ++ ++ ++/* ---- Variable Externs ------------------------------------------------- */ ++/* ---- Function Prototypes ---------------------------------------------- */ ++ ++ ++#ifdef __cplusplus ++ } ++#endif ++ ++#endif /* MINI_OPT_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/msgtrace.h b/module_drivers/drivers/net/wireless/bcmdhd/include/msgtrace.h +new file mode 100644 +index 000000000..a2da1d3c7 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/msgtrace.h +@@ -0,0 +1,62 @@ ++/* ++ * Trace messages sent over HBUS ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: msgtrace.h 542902 2015-03-22 23:29:48Z $ ++ */ ++ ++#ifndef _MSGTRACE_H ++#define _MSGTRACE_H ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#define MSGTRACE_VERSION 1 ++ ++/* Message trace header */ ++typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr { ++ uint8 version; ++ uint8 trace_type; ++#define MSGTRACE_HDR_TYPE_MSG 0 ++#define MSGTRACE_HDR_TYPE_LOG 1 ++ uint16 len; /* Len of the trace */ ++ uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost ++ * because of DMA error or a bus reset (ex: SDIO Func2) ++ */ ++ /* Msgtrace type only */ ++ uint32 discarded_bytes; /* Number of discarded bytes because of trace overflow */ ++ uint32 discarded_printf; /* Number of discarded printf because of trace overflow */ ++} BWL_POST_PACKED_STRUCT msgtrace_hdr_t; ++ ++#define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t) ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _MSGTRACE_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/nan.h b/module_drivers/drivers/net/wireless/bcmdhd/include/nan.h +new file mode 100644 +index 000000000..4534414fb +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/nan.h +@@ -0,0 +1,1468 @@ ++/* ++ * Fundamental types and constants relating to WFA NAN ++ * (Neighbor Awareness Networking) ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: nan.h 700076 2017-05-17 14:42:22Z $ ++ */ ++#ifndef _NAN_H_ ++#define _NAN_H_ ++ ++#include ++#include <802.11.h> ++ ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++/* WiFi NAN OUI values */ ++#define NAN_OUI WFA_OUI /* WiFi OUI */ ++/* For oui_type field identifying the type and version of the NAN IE. */ ++#define NAN_OUI_TYPE 0x13 /* Type/Version */ ++#define NAN_AF_OUI_TYPE 0x18 /* Type/Version */ ++/* IEEE 802.11 vendor specific information element. (Same as P2P_IE_ID.) */ ++#define NAN_IE_ID 0xdd ++ ++/* Same as P2P_PUB_AF_CATEGORY and DOT11_ACTION_CAT_PUBLIC */ ++#define NAN_PUB_AF_CATEGORY DOT11_ACTION_CAT_PUBLIC ++/* Protected dual public action frame category */ ++#define NAN_PROT_DUAL_PUB_AF_CATEGORY DOT11_ACTION_CAT_PDPA ++/* IEEE 802.11 Public Action Frame Vendor Specific. (Same as P2P_PUB_AF_ACTION.) */ ++#define NAN_PUB_AF_ACTION DOT11_PUB_ACTION_VENDOR_SPEC ++/* Number of octents in hash of service name. (Same as P2P_WFDS_HASH_LEN.) */ ++#define NAN_SVC_HASH_LEN 6 ++/* Size of fixed length part of nan_pub_act_frame_t before attributes. */ ++#define NAN_PUB_ACT_FRAME_FIXED_LEN 6 ++/* Number of octents in master rank value. */ ++#define NAN_MASTER_RANK_LEN 8 ++/* NAN public action frame header size */ ++#define NAN_PUB_ACT_FRAME_HDR_SIZE (OFFSETOF(nan_pub_act_frame_t, data)) ++/* NAN network ID */ ++#define NAN_NETWORK_ID "\x51\x6F\x9A\x01\x00\x00" ++/* Service Control Type length */ ++#define NAN_SVC_CONTROL_TYPE_LEN 2 ++/* Binding Bitmap length */ ++#define NAN_BINDING_BITMAP_LEN 2 ++/* Service Response Filter (SRF) control field masks */ ++#define NAN_SRF_BLOOM_MASK 0x01 ++#define NAN_SRF_INCLUDE_MASK 0x02 ++#define NAN_SRF_INDEX_MASK 0x0C ++/* SRF Bloom Filter index shift */ ++#define NAN_SRF_BLOOM_SHIFT 2 ++#define NAN_SRF_INCLUDE_SHIFT 1 ++/* Mask for CRC32 output, used in hash function for NAN bloom filter */ ++#define NAN_BLOOM_CRC32_MASK 0xFFFF ++ ++/* Attribute TLV header size */ ++#define NAN_ATTR_ID_OFF 0 ++#define NAN_ATTR_LEN_OFF 1 ++#define NAN_ATTR_DATA_OFF 3 ++ ++#define NAN_ATTR_ID_LEN 1u /* ID field length */ ++#define NAN_ATTR_LEN_LEN 2u /* Length field length */ ++#define NAN_ATTR_HDR_LEN (NAN_ATTR_ID_LEN + NAN_ATTR_LEN_LEN) ++#define NAN_ENTRY_CTRL_LEN 1 /* Entry control field length from FAM attribute */ ++#define NAN_MAP_ID_LEN 1 /* MAP ID length to signify band */ ++#define NAN_OPERATING_CLASS_LEN 1 /* operating class field length from NAN FAM */ ++#define NAN_CHANNEL_NUM_LEN 1 /* channel number field length 1 byte */ ++ ++/* NAN slot duration / period */ ++#define NAN_MIN_TU 16 ++#define NAN_TU_PER_DW 512 ++#define NAN_MAX_DW 16 ++#define NAN_MAX_TU (NAN_MAX_DW * NAN_TU_PER_DW) ++ ++#define NAN_SLOT_DUR_0TU 0 ++#define NAN_SLOT_DUR_16TU 16 ++#define NAN_SLOT_DUR_32TU 32 ++#define NAN_SLOT_DUR_64TU 64 ++#define NAN_SLOT_DUR_128TU 128 ++#define NAN_SLOT_DUR_256TU 256 ++#define NAN_SLOT_DUR_512TU 512 ++#define NAN_SLOT_DUR_1024TU 1024 ++#define NAN_SLOT_DUR_2048TU 2048 ++#define NAN_SLOT_DUR_4096TU 4096 ++#define NAN_SLOT_DUR_8192TU 8192 ++ ++#define NAN_MAP_ID_2G 2 /* NAN Further Avail Map ID for band 2.4G */ ++#define NAN_MAP_ID_5G 5 /* NAN Further Avail Map ID for band 5G */ ++#define NAN_MAP_NUM_IDS 2 /* Max number of NAN Further Avail Map IDs supported */ ++ ++/* size of ndc id */ ++#define NAN_DATA_NDC_ID_SIZE 6 ++ ++#define NAN_AVAIL_ENTRY_LEN_RES0 7 /* Avail entry len in FAM attribute for resolution 16TU */ ++#define NAN_AVAIL_ENTRY_LEN_RES1 5 /* Avail entry len in FAM attribute for resolution 32TU */ ++#define NAN_AVAIL_ENTRY_LEN_RES2 4 /* Avail entry len in FAM attribute for resolution 64TU */ ++ ++/* Vendor-specific public action frame for NAN */ ++typedef BWL_PRE_PACKED_STRUCT struct nan_pub_act_frame_s { ++ /* NAN_PUB_AF_CATEGORY 0x04 */ ++ uint8 category_id; ++ /* NAN_PUB_AF_ACTION 0x09 */ ++ uint8 action_field; ++ /* NAN_OUI 0x50-6F-9A */ ++ uint8 oui[DOT11_OUI_LEN]; ++ /* NAN_OUI_TYPE 0x13 */ ++ uint8 oui_type; ++ /* One or more NAN Attributes follow */ ++ uint8 data[]; ++} BWL_POST_PACKED_STRUCT nan_pub_act_frame_t; ++ ++/* NAN attributes as defined in the nan spec */ ++enum { ++ NAN_ATTR_MASTER_IND = 0, ++ NAN_ATTR_CLUSTER = 1, ++ NAN_ATTR_SVC_ID_LIST = 2, ++ NAN_ATTR_SVC_DESCRIPTOR = 3, ++ NAN_ATTR_CONN_CAP = 4, ++ NAN_ATTR_INFRA = 5, ++ NAN_ATTR_P2P = 6, ++ NAN_ATTR_IBSS = 7, ++ NAN_ATTR_MESH = 8, ++ NAN_ATTR_FURTHER_NAN_SD = 9, ++ NAN_ATTR_FURTHER_AVAIL = 10, ++ NAN_ATTR_COUNTRY_CODE = 11, ++ NAN_ATTR_RANGING = 12, ++ NAN_ATTR_CLUSTER_DISC = 13, ++ /* nan 2.0 */ ++ NAN_ATTR_SVC_DESC_EXTENSION = 14, ++ NAN_ATTR_NAN_DEV_CAP = 15, ++ NAN_ATTR_NAN_NDP = 16, ++ NAN_ATTR_NAN_NMSG = 17, ++ NAN_ATTR_NAN_AVAIL = 18, ++ NAN_ATTR_NAN_NDC = 19, ++ NAN_ATTR_NAN_NDL = 20, ++ NAN_ATTR_NAN_NDL_QOS = 21, ++ NAN_ATTR_MCAST_SCHED = 22, ++ NAN_ATTR_UNALIGN_SCHED = 23, ++ NAN_ATTR_PAGING_UCAST = 24, ++ NAN_ATTR_PAGING_MCAST = 25, ++ NAN_ATTR_RANGING_INFO = 26, ++ NAN_ATTR_RANGING_SETUP = 27, ++ NAN_ATTR_FTM_RANGE_REPORT = 28, ++ NAN_ATTR_ELEMENT_CONTAINER = 29, ++ NAN_ATTR_WLAN_INFRA_EXT = 30, ++ NAN_ATTR_EXT_P2P_OPER = 31, ++ NAN_ATTR_EXT_IBSS = 32, ++ NAN_ATTR_EXT_MESH = 33, ++ NAN_ATTR_CIPHER_SUITE_INFO = 34, ++ NAN_ATTR_SEC_CTX_ID_INFO = 35, ++ NAN_ATTR_SHARED_KEY_DESC = 36, ++ NAN_ATTR_MCAST_SCHED_CHANGE = 37, ++ NAN_ATTR_MCAST_SCHED_OWNER_CHANGE = 38, ++ NAN_ATTR_PUBLIC_AVAILABILITY = 39, ++ NAN_ATTR_SUB_SVC_ID_LIST = 40, ++ /* change NAN_ATTR_MAX_ID to max ids + 1, excluding NAN_ATTR_VENDOR_SPECIFIC. ++ * This is used in nan_parse.c ++ */ ++ NAN_ATTR_MAX_ID = NAN_ATTR_SUB_SVC_ID_LIST + 1, ++ ++ NAN_ATTR_VENDOR_SPECIFIC = 221 ++}; ++ ++enum wifi_nan_avail_resolution { ++ NAN_AVAIL_RES_16_TU = 0, ++ NAN_AVAIL_RES_32_TU = 1, ++ NAN_AVAIL_RES_64_TU = 2, ++ NAN_AVAIL_RES_INVALID = 255 ++}; ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ie_s { ++ uint8 id; /* IE ID: NAN_IE_ID 0xDD */ ++ uint8 len; /* IE length */ ++ uint8 oui[DOT11_OUI_LEN]; /* NAN_OUI 50:6F:9A */ ++ uint8 oui_type; /* NAN_OUI_TYPE 0x13 */ ++ uint8 attr[]; /* var len attributes */ ++} BWL_POST_PACKED_STRUCT wifi_nan_ie_t; ++ ++#define NAN_IE_HDR_SIZE (OFFSETOF(wifi_nan_ie_t, attr)) ++ ++/* master indication record */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_master_ind_attr_s { ++ uint8 id; ++ uint16 len; ++ uint8 master_preference; ++ uint8 random_factor; ++} BWL_POST_PACKED_STRUCT wifi_nan_master_ind_attr_t; ++ ++/* cluster attr record */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_cluster_attr_s { ++ uint8 id; ++ uint16 len; ++ uint8 amr[NAN_MASTER_RANK_LEN]; ++ uint8 hop_count; ++ /* Anchor Master Beacon Transmission Time */ ++ uint32 ambtt; ++} BWL_POST_PACKED_STRUCT wifi_nan_cluster_attr_t; ++ ++/* container for service ID records */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_id_attr_s { ++ uint8 id; ++ uint16 len; ++ uint8 svcid[0]; /* 6*len of srvc IDs */ ++} BWL_POST_PACKED_STRUCT wifi_nan_svc_id_attr_t; ++ ++/* service_control bitmap for wifi_nan_svc_descriptor_attr_t below */ ++#define NAN_SC_PUBLISH 0x0 ++#define NAN_SC_SUBSCRIBE 0x1 ++#define NAN_SC_FOLLOWUP 0x2 ++/* Set to 1 if a Matching Filter field is included in descriptors. */ ++#define NAN_SC_MATCHING_FILTER_PRESENT 0x4 ++/* Set to 1 if a Service Response Filter field is included in descriptors. */ ++#define NAN_SC_SR_FILTER_PRESENT 0x8 ++/* Set to 1 if a Service Info field is included in descriptors. */ ++#define NAN_SC_SVC_INFO_PRESENT 0x10 ++/* range is close proximity only */ ++#define NAN_SC_RANGE_LIMITED 0x20 ++/* Set to 1 if binding bitamp is present in descriptors */ ++#define NAN_SC_BINDING_BITMAP_PRESENT 0x40 ++ ++/* Service descriptor */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_descriptor_attr_s { ++ /* Attribute ID - 0x03. */ ++ uint8 id; ++ /* Length of the following fields in the attribute */ ++ uint16 len; ++ /* Hash of the Service Name */ ++ uint8 svc_hash[NAN_SVC_HASH_LEN]; ++ /* Publish or subscribe instance id */ ++ uint8 instance_id; ++ /* Requestor Instance ID */ ++ uint8 requestor_id; ++ /* Service Control Bitmask. Also determines what data follows. */ ++ uint8 svc_control; ++ /* Optional fields follow */ ++} BWL_POST_PACKED_STRUCT wifi_nan_svc_descriptor_attr_t; ++ ++/* IBSS attribute */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ibss_attr_s { ++ /* Attribute ID - 0x07. */ ++ uint8 id; ++ /* Length of the following fields in the attribute */ ++ uint16 len; ++ /* BSSID of the ibss */ ++ struct ether_addr bssid; ++ /* ++ map control:, bits: ++ [0-3]: Id for associated further avail map attribute ++ [4-5]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; 3:reserved ++ [6] : repeat : 0 - applies to next DW, 1: 16 intervals max? wtf? ++ [7] : reserved ++ */ ++ uint8 map_ctrl; ++ /* avail. intervals bitmap, var len */ ++ uint8 avail_bmp[1]; ++} BWL_POST_PACKED_STRUCT wifi_nan_ibss_attr_t; ++ ++/* Further Availability MAP attr */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_favail_attr_s { ++ /* Attribute ID - 0x0A. */ ++ uint8 id; ++ /* Length of the following fields in the attribute */ ++ uint16 len; ++ /* MAP id: val [0..15], values[16-255] reserved */ ++ uint8 map_id; ++ /* availibility entry, var len */ ++ uint8 avil_entry[1]; ++} BWL_POST_PACKED_STRUCT wifi_nan_favail_attr_t; ++ ++/* Further Availability MAP attr */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_entry_s { ++ /* ++ entry control ++ [0-1]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; ++ [2:7] reserved ++ */ ++ uint8 entry_ctrl; ++ /* operating class: freq band etc IEEE 802.11 */ ++ uint8 opclass; ++ /* channel number */ ++ uint8 chan; ++ /* avail bmp, var len */ ++ uint8 avail_bmp[1]; ++} BWL_POST_PACKED_STRUCT wifi_nan_avail_entry_t; ++ ++/* Map control Field */ ++#define NAN_MAPCTRL_IDMASK 0x7 ++#define NAN_MAPCTRL_DURSHIFT 4 ++#define NAN_MAPCTRL_DURMASK 0x30 ++#define NAN_MAPCTRL_REPEAT 0x40 ++#define NAN_MAPCTRL_REPEATSHIFT 6 ++ ++#define NAN_VENDOR_TYPE_RTT 0 ++#define NAN_VENDOR_TYPE_P2P 1 ++ ++/* Vendor Specific Attribute */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_vendor_attr_s { ++ uint8 id; /* 0xDD */ ++ uint16 len; /* IE length */ ++ uint8 oui[DOT11_OUI_LEN]; /* 00-90-4C */ ++ uint8 type; /* attribute type */ ++ uint8 attr[1]; /* var len attributes */ ++} BWL_POST_PACKED_STRUCT wifi_nan_vendor_attr_t; ++ ++#define NAN_VENDOR_HDR_SIZE (OFFSETOF(wifi_nan_vendor_attr_t, attr)) ++ ++/* p2p operation attribute */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_p2p_op_attr_s { ++ /* Attribute ID - 0x06. */ ++ uint8 id; ++ /* Length of the following fields in the attribute */ ++ uint16 len; ++ /* P2P device role */ ++ uint8 dev_role; ++ /* BSSID of the ibss */ ++ struct ether_addr p2p_dev_addr; ++ /* ++ map control:, bits: ++ [0-3]: Id for associated further avail map attribute ++ [4-5]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; 3:reserved ++ [6] : repeat : 0 - applies to next DW, 1: 16 intervals max? wtf? ++ [7] : reserved ++ */ ++ uint8 map_ctrl; ++ /* avail. intervals bitmap */ ++ uint8 avail_bmp[1]; ++} BWL_POST_PACKED_STRUCT wifi_nan_p2p_op_attr_t; ++ ++/* ranging attribute */ ++#define NAN_RANGING_MAP_CTRL_ID_SHIFT 0 ++#define NAN_RANGING_MAP_CTRL_ID_MASK 0x0F ++#define NAN_RANGING_MAP_CTRL_DUR_SHIFT 4 ++#define NAN_RANGING_MAP_CTRL_DUR_MASK 0x30 ++#define NAN_RANGING_MAP_CTRL_REPEAT_SHIFT 6 ++#define NAN_RANGING_MAP_CTRL_REPEAT_MASK 0x40 ++#define NAN_RANGING_MAP_CTRL_REPEAT_DW(_ctrl) (((_ctrl) & \ ++ NAN_RANGING_MAP_CTRL_DUR_MASK) ? 16 : 1) ++#define NAN_RANGING_MAP_CTRL(_id, _dur, _repeat) (\ ++ (((_id) << NAN_RANGING_MAP_CTRL_ID_SHIFT) & \ ++ NAN_RANGING_MAP_CTRL_ID_MASK) | \ ++ (((_dur) << NAN_RANGING_MAP_CTRL_DUR_SHIFT) & \ ++ NAN_RANGING_MAP_CTRL_DUR_MASK) | \ ++ (((_repeat) << NAN_RANGING_MAP_CTRL_REPEAT_SHIFT) & \ ++ NAN_RANGING_MAP_CTRL_REPEAT_MASK)) ++ ++enum { ++ NAN_RANGING_PROTO_FTM = 0 ++}; ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_attr_s { ++ uint8 id; /* 0x0C */ ++ uint16 len; /* length that follows */ ++ struct ether_addr dev_addr; /* device mac address */ ++ ++ /* ++ map control:, bits: ++ [0-3]: Id for associated further avail map attribute ++ [4-5]: avail interval duration: 0:16ms; 1:32ms; 2:64ms; 3:reserved ++ [6] : repeat : 0 - applies to next DW, 1: 16 intervals max? wtf? ++ [7] : reserved ++ */ ++ uint8 map_ctrl; ++ ++ uint8 protocol; /* FTM = 0 */ ++ uint32 avail_bmp; /* avail interval bitmap */ ++} BWL_POST_PACKED_STRUCT wifi_nan_ranging_attr_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_info_attr_s { ++ uint8 id; /* 0x1A */ ++ uint16 len; /* length that follows */ ++ /* ++ location info availability bit map ++ 0: LCI Local Coordinates ++ 1: Geospatial LCI WGS84 ++ 2: Civi Location ++ 3: Last Movement Indication ++ [4-7]: reserved ++ */ ++ uint8 lc_info_avail; ++ /* ++ Last movement indication ++ present if bit 3 is set in lc_info_avail ++ cluster TSF[29:14] at the last detected platform movement ++ */ ++ uint16 last_movement; ++ ++} BWL_POST_PACKED_STRUCT wifi_nan_ranging_info_attr_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_setup_attr_hdr_s { ++ uint8 id; /* 0x1B */ ++ uint16 len; /* length that follows */ ++ uint8 dialog_token; /* Identify req and resp */ ++ uint8 type_status; /* bits 0-3 type, 4-7 status */ ++ /* reason code ++ i. when frm type = response & status = reject ++ ii. frm type = termination ++ */ ++ uint8 reason; ++} BWL_POST_PACKED_STRUCT wifi_nan_ranging_setup_attr_hdr_t; ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_setup_attr_s { ++ ++ wifi_nan_ranging_setup_attr_hdr_t setup_attr_hdr; ++ /* Below fields not required when frm type = termination */ ++ uint8 ranging_ctrl; /* Bit 0: ranging report required or not */ ++ uint8 ftm_params[3]; ++ uint8 data[]; /* schedule entry list */ ++} BWL_POST_PACKED_STRUCT wifi_nan_ranging_setup_attr_t; ++ ++#define NAN_RANGE_SETUP_ATTR_OFFSET_TBM_INFO (OFFSETOF(wifi_nan_ranging_setup_attr_t, data)) ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ranging_report_attr_s { ++ uint8 id; /* 0x1C */ ++ uint16 len; /* length that follows */ ++ /* FTM report format in spec. ++ See definition in 9.4.2.22.18 in 802.11mc D5.0 ++ */ ++ uint8 entry_count; ++ uint8 data[2]; /* includes pad */ ++ /* ++ dot11_ftm_range_entry_t entries[entry_count]; ++ uint8 error_count; ++ dot11_ftm_error_entry_t errors[error_count]; ++ */ ++} BWL_POST_PACKED_STRUCT wifi_nan_ranging_report_attr_t; ++ ++/* Ranging control flags */ ++#define NAN_RNG_REPORT_REQUIRED 0x01 ++#define NAN_RNG_FTM_PARAMS_PRESENT 0x02 ++#define NAN_RNG_SCHED_ENTRY_PRESENT 0X04 ++ ++/* Location info flags */ ++#define NAN_RNG_LOCATION_FLAGS_LOCAL_CORD 0x1 ++#define NAN_RNG_LOCATION_FLAGS_GEO_SPATIAL 0x2 ++#define NAN_RNG_LOCATION_FLAGS_CIVIC 0x4 ++#define NAN_RNG_LOCATION_FLAGS_LAST_MVMT 0x8 ++ ++/* Last movement mask and shift value */ ++#define NAN_RNG_LOCATION_MASK_LAST_MVT_TSF 0x3FFFC000 ++#define NAN_RNG_LOCATION_SHIFT_LAST_MVT_TSF 14 ++ ++/* FTM params shift values */ ++#define NAN_FTM_MAX_BURST_DUR_SHIFT 0 ++#define NAN_FTM_MIN_FTM_DELTA_SHIFT 4 ++#define NAN_FTM_NUM_FTM_SHIFT 10 ++#define NAN_FTM_FORMAT_BW_SHIFT 15 ++ ++/* FTM params mask */ ++#define NAN_FTM_MAX_BURST_DUR_MASK 0x00000F ++#define NAN_FTM_MIN_FTM_DELTA_MASK 0x00003F ++#define NAN_FTM_NUM_FTM_MASK 0x00001F ++#define NAN_FTM_FORMAT_BW_MASK 0x00003F ++ ++#define FTM_PARAMS_BURSTTMO_FACTOR 250 ++ ++/* set to value to uint32 */ ++#define NAN_FTM_SET_BURST_DUR(ftm, dur) (ftm |= (((dur + 2) & NAN_FTM_MAX_BURST_DUR_MASK) <<\ ++ NAN_FTM_MAX_BURST_DUR_SHIFT)) ++#define NAN_FTM_SET_FTM_DELTA(ftm, delta) (ftm |= (((delta/100) & NAN_FTM_MIN_FTM_DELTA_MASK) <<\ ++ NAN_FTM_MIN_FTM_DELTA_SHIFT)) ++#define NAN_FTM_SET_NUM_FTM(ftm, delta) (ftm |= ((delta & NAN_FTM_NUM_FTM_MASK) <<\ ++ NAN_FTM_NUM_FTM_SHIFT)) ++#define NAN_FTM_SET_FORMAT_BW(ftm, delta) (ftm |= ((delta & NAN_FTM_FORMAT_BW_MASK) <<\ ++ NAN_FTM_FORMAT_BW_SHIFT)) ++/* set uint32 to attribute */ ++#define NAN_FTM_PARAMS_UINT32_TO_ATTR(ftm_u32, ftm_attr) {ftm_attr[0] = ftm_u32 & 0xFF; \ ++ ftm_attr[1] = (ftm_u32 >> 8) & 0xFF; ftm_attr[2] = (ftm_u32 >> 16) & 0xFF;} ++ ++/* get atrribute to uint32 */ ++#define NAN_FTM_PARAMS_ATTR_TO_UINT32(ftm_p, ftm_u32) (ftm_u32 = ftm_p[0] | ftm_p[1] << 8 | \ ++ ftm_p[2] << 16) ++/* get param values from uint32 */ ++#define NAN_FTM_GET_BURST_DUR(ftm) (((ftm >> NAN_FTM_MAX_BURST_DUR_SHIFT) &\ ++ NAN_FTM_MAX_BURST_DUR_MASK)) ++#define NAN_FTM_GET_BURST_DUR_USEC(_val) ((1 << ((_val)-2)) * FTM_PARAMS_BURSTTMO_FACTOR) ++#define NAN_FTM_GET_FTM_DELTA(ftm) (((ftm >> NAN_FTM_MIN_FTM_DELTA_SHIFT) &\ ++ NAN_FTM_MIN_FTM_DELTA_MASK)*100) ++#define NAN_FTM_GET_NUM_FTM(ftm) ((ftm >> NAN_FTM_NUM_FTM_SHIFT) &\ ++ NAN_FTM_NUM_FTM_MASK) ++#define NAN_FTM_GET_FORMAT_BW(ftm) ((ftm >> NAN_FTM_FORMAT_BW_SHIFT) &\ ++ NAN_FTM_FORMAT_BW_MASK) ++ ++#define NAN_CONN_CAPABILITY_WFD 0x0001 ++#define NAN_CONN_CAPABILITY_WFDS 0x0002 ++#define NAN_CONN_CAPABILITY_TDLS 0x0004 ++#define NAN_CONN_CAPABILITY_INFRA 0x0008 ++#define NAN_CONN_CAPABILITY_IBSS 0x0010 ++#define NAN_CONN_CAPABILITY_MESH 0x0020 ++ ++#define NAN_DEFAULT_MAP_ID 0 /* nan default map id */ ++#define NAN_DEFAULT_MAP_CTRL 0 /* nan default map control */ ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_conn_cap_attr_s { ++ /* Attribute ID - 0x04. */ ++ uint8 id; ++ /* Length of the following fields in the attribute */ ++ uint16 len; ++ uint16 conn_cap_bmp; /* Connection capability bitmap */ ++} BWL_POST_PACKED_STRUCT wifi_nan_conn_cap_attr_t; ++ ++/* NAN Element container Attribute */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_container_attr_s { ++ uint8 id; /* id - 0x20 */ ++ uint16 len; /* Total length of following IEs */ ++ uint8 map_id; /* map id */ ++ uint8 data[1]; /* Data pointing to one or more IEs */ ++} BWL_POST_PACKED_STRUCT wifi_nan_container_attr_t; ++ ++/* NAN 2.0 NAN avail attribute */ ++ ++/* Availability Attribute */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_attr_s { ++ uint8 id; /* id - 0x12 */ ++ uint16 len; /* total length */ ++ uint8 seqid; /* sequence id */ ++ uint16 ctrl; /* attribute control */ ++ uint8 entry[1]; /* availability entry list */ ++} BWL_POST_PACKED_STRUCT wifi_nan_avail_attr_t; ++ ++/* for processing/building time bitmap info in nan_avail_entry */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_time_bitmap_s { ++ uint16 ctrl; /* Time bitmap control */ ++ uint8 len; /* Time bitmap length */ ++ uint8 bitmap[]; /* Time bitmap */ ++} BWL_POST_PACKED_STRUCT wifi_nan_time_bitmap_t; ++ ++/* Availability Entry format */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_avail_entry_attr_s { ++ uint16 len; /* Length */ ++ uint16 entry_cntrl; /* Entry Control */ ++ uint8 var[]; /* Time bitmap and channel entry list */ ++} BWL_POST_PACKED_STRUCT wifi_nan_avail_entry_attr_t; ++ ++/* FAC Channel Entry (section 10.7.19.1.5) */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_chan_entry_s { ++ uint8 oper_class; /* Operating Class */ ++ uint16 chan_bitmap; /* Channel Bitmap */ ++ uint8 primary_chan_bmp; /* Primary Channel Bitmap */ ++ uint8 aux_chan[0]; /* Auxiliary Channel bitmap */ ++} BWL_POST_PACKED_STRUCT wifi_nan_chan_entry_t; ++ ++/* Channel entry */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_channel_entry_s { ++ uint8 opclass; /* Operating class */ ++ uint16 chan_bitmap; /* Channel bitmap */ ++ uint8 prim_bitmap; /* Primary channel bitmap */ ++ uint16 aux_bitmap; /* Time bitmap length */ ++} BWL_POST_PACKED_STRUCT wifi_nan_channel_entry_t; ++ ++/* Type of Availability: committed */ ++#define NAN_ENTRY_CNTRL_TYPE_COMM_AVAIL_MASK 0x1 ++/* Type of Availability: potential */ ++#define NAN_ENTRY_CNTRL_TYPE_POTEN_AVAIL_MASK 0x2 ++/* Type of Availability: conditional */ ++#define NAN_ENTRY_CNTRL_TYPE_COND_AVAIL_MASK 0x4 ++ ++#define NAN_AVAIL_CTRL_MAP_ID_MASK 0x000F ++#define NAN_AVAIL_CTRL_MAP_ID(_ctrl) ((_ctrl) & NAN_AVAIL_CTRL_MAP_ID_MASK) ++#define NAN_AVAIL_CTRL_COMM_CHANGED_MASK 0x0010 ++#define NAN_AVAIL_CTRL_COMM_CHANGED(_ctrl) ((_ctrl) & NAN_AVAIL_CTRL_COMM_CHANGED_MASK) ++#define NAN_AVAIL_CTRL_POTEN_CHANGED_MASK 0x0020 ++#define NAN_AVAIL_CTRL_POTEN_CHANGED(_ctrl) ((_ctrl) & NAN_AVAIL_CTRL_POTEN_CHANGED_MASK) ++#define NAN_AVAIL_CTRL_PUBLIC_CHANGED_MASK 0x0040 ++#define NAN_AVAIL_CTRL_PUBLIC_CHANGED(_ctrl) ((_ctrl) & NAN_AVAIL_CTRL_PUBLIC_CHANGED_MASK) ++#define NAN_AVAIL_CTRL_NDC_CHANGED_MASK 0x0080 ++#define NAN_AVAIL_CTRL_NDC_CHANGED(_ctrl) ((_ctrl) & NAN_AVAIL_CTRL_NDC_CHANGED_MASK) ++#define NAN_AVAIL_CTRL_MCAST_CHANGED_MASK 0x0100 ++#define NAN_AVAIL_CTRL_MCAST_CHANGED(_ctrl) ((_ctrl) & NAN_AVAIL_CTRL_MCAST_CHANGED_MASK) ++#define NAN_AVAIL_CTRL_MCAST_CHG_CHANGED_MASK 0x0200 ++#define NAN_AVAIL_CTRL_MCAST_CHG_CHANGED(_ctrl) ((_ctrl) & NAN_AVAIL_CTRL_MCAST_CHG_CHANGED_MASK) ++#define NAN_AVAIL_CTRL_CHANGED_FLAGS_MASK 0x03f0 ++ ++#define NAN_AVAIL_ENTRY_CTRL_AVAIL_TYPE_MASK 0x07 ++#define NAN_AVAIL_ENTRY_CTRL_AVAIL_TYPE(_flags) ((_flags) & NAN_AVAIL_ENTRY_CTRL_AVAIL_TYPE_MASK) ++#define NAN_AVAIL_ENTRY_CTRL_USAGE_MASK 0x18 ++#define NAN_AVAIL_ENTRY_CTRL_USAGE_SHIFT 3 ++#define NAN_AVAIL_ENTRY_CTRL_USAGE(_flags) (((_flags) & NAN_AVAIL_ENTRY_CTRL_USAGE_MASK) \ ++ >> NAN_AVAIL_ENTRY_CTRL_USAGE_SHIFT) ++#define NAN_AVAIL_ENTRY_CTRL_UTIL_MASK 0x1E0 ++#define NAN_AVAIL_ENTRY_CTRL_UTIL_SHIFT 5 ++#define NAN_AVAIL_ENTRY_CTRL_UTIL(_flags) (((_flags) & NAN_AVAIL_ENTRY_CTRL_UTIL_MASK) \ ++ >> NAN_AVAIL_ENTRY_CTRL_UTIL_SHIFT) ++#define NAN_AVAIL_ENTRY_CTRL_RX_NSS_MASK 0xF00 ++#define NAN_AVAIL_ENTRY_CTRL_RX_NSS_SHIFT 8 ++#define NAN_AVAIL_ENTRY_CTRL_RX_NSS(_flags) (((_flags) & NAN_AVAIL_ENTRY_CTRL_RX_NSS_MASK) \ ++ >> NAN_AVAIL_ENTRY_CTRL_RX_NSS_SHIFT) ++#define NAN_AVAIL_ENTRY_CTRL_BITMAP_PRESENT_MASK 0x1000 ++#define NAN_AVAIL_ENTRY_CTRL_BITMAP_PRESENT_SHIFT 12 ++#define NAN_AVAIL_ENTRY_CTRL_BITMAP_PRESENT(_flags) (((_flags) & \ ++ NAN_AVAIL_ENTRY_CTRL_BITMAP_PRESENT_MASK) >> NAN_AVAIL_ENTRY_CTRL_BITMAP_PRESENT_SHIFT) ++ ++#define NAN_TIME_BMAP_CTRL_BITDUR_MASK 0x07 ++#define NAN_TIME_BMAP_CTRL_BITDUR(_flags) ((_flags) & NAN_TIME_BMAP_CTRL_BITDUR_MASK) ++#define NAN_TIME_BMAP_CTRL_PERIOD_MASK 0x38 ++#define NAN_TIME_BMAP_CTRL_PERIOD_SHIFT 3 ++#define NAN_TIME_BMAP_CTRL_PERIOD(_flags) (((_flags) & NAN_TIME_BMAP_CTRL_PERIOD_MASK) \ ++ >> NAN_TIME_BMAP_CTRL_PERIOD_SHIFT) ++#define NAN_TIME_BMAP_CTRL_OFFSET_MASK 0x7FC0 ++#define NAN_TIME_BMAP_CTRL_OFFSET_SHIFT 6 ++#define NAN_TIME_BMAP_CTRL_OFFSET(_flags) (((_flags) & NAN_TIME_BMAP_CTRL_OFFSET_MASK) \ ++ >> NAN_TIME_BMAP_CTRL_OFFSET_SHIFT) ++#define NAN_TIME_BMAP_LEN(avail_entry) \ ++ (*(uint8 *)(((wifi_nan_avail_entry_attr_t *)avail_entry)->var + 2)) ++ ++#define NAN_AVAIL_CHAN_LIST_HDR_LEN 1 ++#define NAN_AVAIL_CHAN_LIST_TYPE_CHANNEL 0x01 ++#define NAN_AVAIL_CHAN_LIST_NON_CONTIG_BW 0x02 ++#define NAN_AVAIL_CHAN_LIST_NUM_ENTRIES_MASK 0xF0 ++#define NAN_AVAIL_CHAN_LIST_NUM_ENTRIES_SHIFT 4 ++#define NAN_AVAIL_CHAN_LIST_NUM_ENTRIES(_ctrl) (((_ctrl) & NAN_AVAIL_CHAN_LIST_NUM_ENTRIES_MASK) \ ++ >> NAN_AVAIL_CHAN_LIST_NUM_ENTRIES_SHIFT) ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_channel_entry_list_s { ++ uint8 chan_info; ++ uint8 var[0]; ++} BWL_POST_PACKED_STRUCT wifi_nan_channel_entry_list_t; ++ ++/* define for chan_info */ ++#define NAN_CHAN_OP_CLASS_MASK 0x01 ++#define NAN_CHAN_NON_CONT_BW_MASK 0x02 ++#define NAN_CHAN_RSVD_MASK 0x03 ++#define NAN_CHAN_NUM_ENTRIES_MASK 0xF0 ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_band_entry_s { ++ uint8 band[0]; ++} BWL_POST_PACKED_STRUCT wifi_nan_band_entry_t; ++ ++/* Type of Availability: committed */ ++#define NAN_ENTRY_CNTRL_TYPE_COMM_AVAIL 0x1 ++/* Type of Availability: potential */ ++#define NAN_ENTRY_CNTRL_TYPE_POTEN_AVAIL 0x2 ++/* Type of Availability: conditional */ ++#define NAN_ENTRY_CNTRL_TYPE_COND_AVAIL 0x4 ++/* Committed + Potential */ ++#define NAN_ENTRY_CNTRL_TYPE_COMM_POTEN \ ++ (NAN_ENTRY_CNTRL_TYPE_COMM_AVAIL | NAN_ENTRY_CNTRL_TYPE_POTEN_AVAIL) ++/* Conditional + Potential */ ++#define NAN_ENTRY_CNTRL_TYPE_COND_POTEN \ ++ (NAN_ENTRY_CNTRL_TYPE_COND_AVAIL | NAN_ENTRY_CNTRL_TYPE_POTEN_AVAIL) ++ ++/* Type of Availability */ ++#define NAN_ENTRY_CNTRL_TYPE_OF_AVAIL_MASK 0x07 ++#define NAN_ENTRY_CNTRL_TYPE_OF_AVAIL_SHIFT 0 ++/* Usage Preference */ ++#define NAN_ENTRY_CNTRL_USAGE_PREF_MASK 0x18 ++#define NAN_ENTRY_CNTRL_USAGE_PREF_SHIFT 3 ++/* Utilization */ ++#define NAN_ENTRY_CNTRL_UTIL_MASK 0x1E0 ++#define NAN_ENTRY_CNTRL_UTIL_SHIFT 5 ++ ++/* Time Bitmap Control field (section 5.7.18.2.3) */ ++ ++/* Reserved */ ++#define NAN_TIME_BMP_CNTRL_RSVD_MASK 0x01 ++#define NAN_TIME_BMP_CNTRL_RSVD_SHIFT 0 ++/* Bitmap Len */ ++#define NAN_TIME_BMP_CNTRL_BMP_LEN_MASK 0x7E ++#define NAN_TIME_BMP_CNTRL_BMP_LEN_SHIFT 1 ++/* Bit Duration */ ++#define NAN_TIME_BMP_CNTRL_BIT_DUR_MASK 0x380 ++#define NAN_TIME_BMP_CNTRL_BIT_DUR_SHIFT 7 ++/* Bitmap Len */ ++#define NAN_TIME_BMP_CNTRL_PERIOD_MASK 0x1C00 ++#define NAN_TIME_BMP_CNTRL_PERIOD_SHIFT 10 ++/* Start Offset */ ++#define NAN_TIME_BMP_CNTRL_START_OFFSET_MASK 0x3FE000 ++#define NAN_TIME_BMP_CNTRL_START_OFFSET_SHIFT 13 ++/* Reserved */ ++#define NAN_TIME_BMP_CNTRL_RESERVED_MASK 0xC00000 ++#define NAN_TIME_BMP_CNTRL_RESERVED_SHIFT 22 ++ ++/* Time Bitmap Control field: Period */ ++typedef enum ++{ ++ NAN_TIME_BMP_CTRL_PERIOD_128TU = 1, ++ NAN_TIME_BMP_CTRL_PERIOD_256TU = 2, ++ NAN_TIME_BMP_CTRL_PERIOD_512TU = 3, ++ NAN_TIME_BMP_CTRL_PERIOD_1024TU = 4, ++ NAN_TIME_BMP_CTRL_PERIOD_2048U = 5, ++ NAN_TIME_BMP_CTRL_PERIOD_4096U = 6, ++ NAN_TIME_BMP_CTRL_PERIOD_8192U = 7 ++} nan_time_bmp_ctrl_repeat_interval_t; ++ ++enum ++{ ++ NAN_TIME_BMP_BIT_DUR_16TU_IDX = 0, ++ NAN_TIME_BMP_BIT_DUR_32TU_IDX = 1, ++ NAN_TIME_BMP_BIT_DUR_64TU_IDX = 2, ++ NAN_TIME_BMP_BIT_DUR_128TU_IDX = 3 ++}; ++ ++enum ++{ ++ NAN_TIME_BMP_BIT_DUR_IDX_0 = 16, ++ NAN_TIME_BMP_BIT_DUR_IDX_1 = 32, ++ NAN_TIME_BMP_BIT_DUR_IDX_2 = 64, ++ NAN_TIME_BMP_BIT_DUR_IDX_3 = 128 ++}; ++ ++enum ++{ ++ NAN_TIME_BMP_CTRL_PERIOD_IDX_1 = 128, ++ NAN_TIME_BMP_CTRL_PERIOD_IDX_2 = 256, ++ NAN_TIME_BMP_CTRL_PERIOD_IDX_3 = 512, ++ NAN_TIME_BMP_CTRL_PERIOD_IDX_4 = 1024, ++ NAN_TIME_BMP_CTRL_PERIOD_IDX_5 = 2048, ++ NAN_TIME_BMP_CTRL_PERIOD_IDX_6 = 4096, ++ NAN_TIME_BMP_CTRL_PERIOD_IDX_7 = 8192 ++}; ++ ++/* Channel Entries List field */ ++ ++/* Type */ ++#define NAN_CHAN_ENTRY_TYPE_MASK 0x01 ++#define NAN_CHAN_ENTRY_TYPE_SHIFT 0 ++/* Channel Entry Length Indication */ ++#define NAN_CHAN_ENTRY_LEN_IND_MASK 0x02 ++#define NAN_CHAN_ENTRY_LEN_IND_SHIFT 1 ++/* Reserved */ ++#define NAN_CHAN_ENTRY_RESERVED_MASK 0x0C ++#define NAN_CHAN_ENTRY_RESERVED_SHIFT 2 ++/* Number of FAC Band or Channel Entries */ ++#define NAN_CHAN_ENTRY_NO_OF_CHAN_ENTRY_MASK 0xF0 ++#define NAN_CHAN_ENTRY_NO_OF_CHAN_ENTRY_SHIFT 4 ++ ++#define NAN_CHAN_ENTRY_TYPE_BANDS 0 ++#define NAN_CHAN_ENTRY_TYPE_OPCLASS_CHANS 1 ++ ++#define NAN_CHAN_ENTRY_BW_LT_80MHZ 0 ++#define NAN_CHAN_ENTRY_BW_EQ_160MHZ 1 ++ ++/* ++ * NDL Attribute WFA Tech. Spec ver 1.0.r12 (section 10.7.19.2) ++ */ ++#define NDL_ATTR_IM_MAP_ID_LEN 1 ++#define NDL_ATTR_IM_TIME_BMP_CTRL_LEN 2 ++#define NDL_ATTR_IM_TIME_BMP_LEN_LEN 1 ++ ++/* ++ * NDL Control field - Table xx ++ */ ++#define NDL_ATTR_CTRL_PEER_ID_PRESENT_MASK 0x01 ++#define NDL_ATTR_CTRL_PEER_ID_PRESENT_SHIFT 0 ++#define NDL_ATTR_CTRL_IM_SCHED_PRESENT_MASK 0x02 ++#define NDL_ATTR_CTRL_IM_SCHED_PRESENT_SHIFT 1 ++#define NDL_ATTR_CTRL_NDC_ATTR_PRESENT_MASK 0x04 ++#define NDL_ATTR_CTRL_NDC_ATTR_PRESENT_SHIFT 2 ++#define NDL_ATTR_CTRL_QOS_ATTR_PRESENT_MASK 0x08 ++#define NDL_ATTR_CTRL_QOS_ATTR_PRESENT_SHIFT 3 ++#define NDL_ATTR_CTRL_MAX_IDLE_PER_PRESENT_MASK 0x10 /* max idle period */ ++#define NDL_ATTR_CTRL_MAX_IDLE_PER_PRESENT_SHIFT 4 ++#define NDL_ATTR_CTRL_NDL_TYPE_MASK 0x20 /* NDL type */ ++#define NDL_ATTR_CTRL_NDL_TYPE_SHIFT 5 ++#define NDL_ATTR_CTRL_NDL_SETUP_REASON_MASK 0xC0 /* NDL Setup Reason */ ++#define NDL_ATTR_CTRL_NDL_SETUP_REASON_SHIFT 6 ++ ++/* NDL setup Reason */ ++#define NDL_ATTR_CTRL_NDL_TYPE_S_NDL 0x0 /* S-NDL */ ++#define NDL_ATTR_CTRL_NDL_TYPE_P_NDL 0x1 /* P-NDL */ ++ ++/* NDL setup Reason */ ++#define NDL_ATTR_CTRL_NDL_SETUP_REASON_NDP_RANG 0x0 /* NDP or Ranging */ ++#define NDL_ATTR_CTRL_NDL_SETUP_REASON_FSD_GAS 0x1 /* FSD using GAS */ ++ ++#define NAN_NDL_TYPE_MASK 0x0F ++#define NDL_ATTR_TYPE_STATUS_REQUEST 0x00 ++#define NDL_ATTR_TYPE_STATUS_RESPONSE 0x01 ++#define NDL_ATTR_TYPE_STATUS_CONFIRM 0x02 ++#define NDL_ATTR_TYPE_STATUS_CONTINUED 0x00 ++#define NDL_ATTR_TYPE_STATUS_ACCEPTED 0x10 ++#define NDL_ATTR_TYPE_STATUS_REJECTED 0x20 ++ ++#define NAN_NDL_TYPE_CHECK(_ndl, x) (((_ndl)->type_status & NAN_NDL_TYPE_MASK) == (x)) ++#define NAN_NDL_REQUEST(_ndl) (((_ndl)->type_status & NAN_NDL_TYPE_MASK) == \ ++ NDL_ATTR_TYPE_STATUS_REQUEST) ++#define NAN_NDL_RESPONSE(_ndl) (((_ndl)->type_status & NAN_NDL_TYPE_MASK) == \ ++ NDL_ATTR_TYPE_STATUS_RESPONSE) ++#define NAN_NDL_CONFIRM(_ndl) (((_ndl)->type_status & NAN_NDL_TYPE_MASK) == \ ++ NDL_ATTR_TYPE_STATUS_CONFIRM) ++ ++ ++#define NAN_NDL_STATUS_SHIFT 4 ++#define NAN_NDL_STATUS_MASK 0xF0 ++#define NAN_NDL_CONT(_ndl) (((_ndl)->type_status & NAN_NDL_STATUS_MASK) == \ ++ NDL_ATTR_TYPE_STATUS_CONTINUED) ++#define NAN_NDL_ACCEPT(_ndl) (((_ndl)->type_status & NAN_NDL_STATUS_MASK) == \ ++ NDL_ATTR_TYPE_STATUS_ACCEPTED) ++#define NAN_NDL_REJECT(_ndl) (((_ndl)->type_status & NAN_NDL_STATUS_MASK) == \ ++ NDL_ATTR_TYPE_STATUS_REJECTED) ++ ++#define NDL_ATTR_CTRL_NONE 0 ++#define NDL_ATTR_CTRL_PEER_ID_PRESENT (1 << NDL_ATTR_CTRL_PEER_ID_PRESENT_SHIFT) ++#define NDL_ATTR_CTRL_IMSCHED_PRESENT (1 << NDL_ATTR_CTRL_IM_SCHED_PRESENT_SHIFT) ++#define NDL_ATTR_CTRL_NDC_PRESENT (1 << NDL_ATTR_CTRL_NDC_ATTR_PRESENT_SHIFT) ++#define NDL_ATTR_CTRL_NDL_QOS_PRESENT (1 << NDL_ATTR_CTRL_QOS_ATTR_PRESENT_SHIFT) ++#define NDL_ATTR_CTRL_MAX_IDLE_PER_PRESENT (1 << NDL_ATTR_CTRL_MAX_IDLE_PER_PRESENT_SHIFT) ++ ++#define NA_NDL_IS_IMMUT_PRESENT(ndl) (((ndl)->ndl_ctrl) & NDL_ATTR_CTRL_IMSCHED_PRESENT) ++#define NA_NDL_IS_PEER_ID_PRESENT(ndl) (((ndl)->ndl_ctrl) & NDL_ATTR_CTRL_PEER_ID_PRESENT) ++#define NA_NDL_IS_MAX_IDLE_PER_PRESENT(ndl) (((ndl)->ndl_ctrl) & NDL_ATTR_CTRL_MAX_IDLE_PER_PRESENT) ++ ++#define NDL_ATTR_PEERID_LEN 1 ++#define NDL_ATTR_MAX_IDLE_PERIOD_LEN 2 ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndl_attr_s { ++ uint8 id; /* NAN_ATTR_NAN_NDL = 0x17 */ ++ uint16 len; /* Length of the fields in the attribute */ ++ uint8 dialog_token; /* Identify req and resp */ ++ uint8 type_status; /* Bits[3-0] type subfield, Bits[7-4] status subfield */ ++ uint8 reason; /* Identifies reject reason */ ++ uint8 ndl_ctrl; /* NDL control field */ ++ uint8 var[]; /* Optional fields follow */ ++} BWL_POST_PACKED_STRUCT wifi_nan_ndl_attr_t; ++ ++/* ++ * NDL QoS Attribute WFA Tech. Spec ver r26 ++ */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndl_qos_attr_s { ++ uint8 id; /* NAN_ATTR_NAN_NDL_QOS = 24 */ ++ uint16 len; /* Length of the attribute field following */ ++ uint8 min_slots; /* Min. number of FAW slots needed per DW interval */ ++ uint16 max_latency; /* Max interval between non-cont FAW */ ++} BWL_POST_PACKED_STRUCT wifi_nan_ndl_qos_attr_t; ++ ++/* no preference to min time slots */ ++#define NAN_NDL_QOS_MIN_SLOT_NO_PREF 0 ++/* no preference to no. of slots between two non-contiguous slots */ ++#define NAN_NDL_QOS_MAX_LAT_NO_PREF 0xFFFF ++ ++/* Device Capability Attribute */ ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_dev_cap_s { ++ uint8 id; /* 0x0F */ ++ uint16 len; /* Length */ ++ uint8 map_id; /* map id */ ++ uint16 commit_dw_info; /* Committed DW Info */ ++ uint8 bands_supported; /* Supported Bands */ ++ uint8 op_mode; /* Operation Mode */ ++ uint8 num_antennas; /* Bit 0-3 tx, 4-7 rx */ ++ uint16 chan_switch_time; /* Max channel switch time in us */ ++ uint8 capabilities; /* DFS Master, Extended key id etc */ ++} BWL_POST_PACKED_STRUCT wifi_nan_dev_cap_t; ++ ++/* Awake DW Info field format */ ++ ++/* 2.4GHz DW */ ++#define NAN_DEV_CAP_AWAKE_DW_2G_MASK 0x07 ++/* 5GHz DW */ ++#define NAN_DEV_CAP_AWAKE_DW_5G_MASK 0x38 ++/* Reserved */ ++#define NAN_DEV_CAP_AWAKE_DW_RSVD_MASK 0xC0 ++ ++/* bit shift for dev cap */ ++#define NAN_DEV_CAP_AWAKE_DW_2G_SHIFT 0 ++#define NAN_DEV_CAP_AWAKE_DW_5G_SHIFT 3 ++ ++/* Device Capability Attribute Format */ ++ ++/* Committed DW Info field format */ ++/* 2.4GHz DW */ ++#define NAN_DEV_CAP_COMMIT_DW_2G_MASK 0x07 ++#define NAN_DEV_CAP_COMMIT_DW_2G_OVERWRITE_MASK 0x3C0 ++/* 5GHz DW */ ++#define NAN_DEV_CAP_COMMIT_DW_5G_MASK 0x38 ++#define NAN_DEV_CAP_COMMIT_DW_5G_OVERWRITE_MASK 0x3C00 ++/* Reserved */ ++#define NAN_DEV_CAP_COMMIT_DW_RSVD_MASK 0xC000 ++/* Committed DW bit shift for dev cap */ ++#define NAN_DEV_CAP_COMMIT_DW_2G_SHIFT 0 ++#define NAN_DEV_CAP_COMMIT_DW_5G_SHIFT 3 ++#define NAN_DEV_CAP_COMMIT_DW_2G_OVERWRITE_SHIFT 6 ++#define NAN_DEV_CAP_COMMIT_DW_5G_OVERWRITE_SHIFT 10 ++/* Operation Mode */ ++#define NAN_DEV_CAP_OP_PHY_MODE_HT_ONLY 0x00 ++#define NAN_DEV_CAP_OP_PHY_MODE_VHT 0x01 ++#define NAN_DEV_CAP_OP_PHY_MODE_VHT_8080 0x02 ++#define NAN_DEV_CAP_OP_PHY_MODE_VHT_160 0x04 ++#define NAN_DEV_CAP_OP_PAGING_NDL 0x08 ++ ++#define NAN_DEV_CAP_OP_MODE_VHT_MASK 0x01 ++#define NAN_DEV_CAP_OP_MODE_VHT8080_MASK 0x03 ++#define NAN_DEV_CAP_OP_MODE_VHT160_MASK 0x05 ++#define NAN_DEV_CAP_OP_MODE_PAGING_NDL_MASK 0x08 ++ ++#define NAN_DEV_CAP_RX_ANT_SHIFT 4 ++#define NAN_DEV_CAP_TX_ANT_MASK 0x0F ++#define NAN_DEV_CAP_RX_ANT_MASK 0xF0 ++ ++/* Device capabilities */ ++ ++/* DFS master capability */ ++#define NAN_DEV_CAP_DFS_MASTER_MASK 0x01 ++#define NAN_DEV_CAP_DFS_MASTER_SHIFT 0 ++/* extended iv cap */ ++#define NAN_DEV_CAP_EXT_KEYID_MASK 0x02 ++#define NAN_DEV_CAP_EXT_KEYID_SHIFT 1 ++ ++/* Band IDs */ ++enum { ++ NAN_BAND_ID_TVWS = 0, ++ NAN_BAND_ID_SIG = 1, /* Sub 1 GHz */ ++ NAN_BAND_ID_2G = 2, /* 2.4 GHz */ ++ NAN_BAND_ID_3G = 3, /* 3.6 GHz */ ++ NAN_BAND_ID_5G = 4, /* 4.9 & 5 GHz */ ++ NAN_BAND_ID_60G = 5 ++}; ++typedef uint8 nan_band_id_t; ++ ++/* ++ * Unaligned schedule attribute section 10.7.19.6 spec. ver r15 ++ */ ++#define NAN_ULW_ATTR_CTRL_SCHED_ID_MASK 0x000F ++#define NAN_ULW_ATTR_CTRL_SCHED_ID_SHIFT 0 ++#define NAN_ULW_ATTR_CTRL_SEQ_ID_MASK 0xFF00 ++#define NAN_ULW_ATTR_CTRL_SEQ_ID_SHIFT 8 ++ ++#define NAN_ULW_OVWR_ALL_MASK 0x01 ++#define NAN_ULW_OVWR_ALL_SHIFT 0 ++#define NAN_ULW_OVWR_MAP_ID_MASK 0x1E ++#define NAN_ULW_OVWR_MAP_ID_SHIFT 1 ++ ++#define NAN_ULW_CTRL_TYPE_MASK 0x03 ++#define NAN_ULW_CTRL_TYPE_SHIFT 0 ++#define NAN_ULW_CTRL_TYPE(ctrl) (ctrl & NAN_ULW_CTRL_TYPE_MASK) ++#define NAN_ULW_CTRL_CHAN_AVAIL_MASK 0x04 ++#define NAN_ULW_CTRL_CHAN_AVAIL_SHIFT 2 ++#define NAN_ULW_CTRL_CHAN_AVAIL(ctrl) ((ctrl & NAN_ULW_CTRL_CHAN_AVAIL_MASK) \ ++ >> NAN_ULW_CTRL_CHAN_AVAIL_SHIFT) ++#define NAN_ULW_CTRL_RX_NSS_MASK 0x78 ++#define NAN_ULW_CTRL_RX_NSS_SHIFT 3 ++ ++#define NAN_ULW_CTRL_TYPE_BAND 0 ++#define NAN_ULW_CTRL_TYPE_CHAN_NOAUX 1 ++#define NAN_ULW_CTRL_TYPE_CHAN_AUX 2 ++ ++#define NAN_ULW_CNT_DOWN_NO_EXPIRE 0xFF /* ULWs doen't end until next sched update */ ++#define NAN_ULW_CNT_DOWN_CANCEL 0x0 /* cancel remaining ulws */ ++ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ulw_attr_s { ++ uint8 id; ++ uint16 len; ++ uint16 ctrl; ++ uint32 start; /* low 32 bits of tsf */ ++ uint32 dur; ++ uint32 period; ++ uint8 count_down; ++ uint8 overwrite; ++ /* ++ * ulw[0] == optional field ULW control when present. ++ * band ID or channel follows ++ */ ++ uint8 ulw_entry[]; ++} BWL_POST_PACKED_STRUCT wifi_nan_ulw_attr_t; ++ ++/* NAN2 Management Frame (section 5.6) */ ++ ++/* Public action frame for NAN2 */ ++typedef BWL_PRE_PACKED_STRUCT struct nan2_pub_act_frame_s { ++ /* NAN_PUB_AF_CATEGORY 0x04 */ ++ uint8 category_id; ++ /* NAN_PUB_AF_ACTION 0x09 */ ++ uint8 action_field; ++ /* NAN_OUI 0x50-6F-9A */ ++ uint8 oui[DOT11_OUI_LEN]; ++ /* NAN_OUI_TYPE TBD */ ++ uint8 oui_type; ++ /* NAN_OUI_SUB_TYPE TBD */ ++ uint8 oui_sub_type; ++ /* One or more NAN Attributes follow */ ++ uint8 data[]; ++} BWL_POST_PACKED_STRUCT nan2_pub_act_frame_t; ++ ++#define NAN2_PUB_ACT_FRM_SIZE (OFFSETOF(nan2_pub_act_frame_t, data)) ++ ++/* NAN Action Frame Subtypes */ ++/* Subtype-0 is Reserved */ ++#define NAN_MGMT_FRM_SUBTYPE_RESERVED 0 ++/* NAN Ranging Request */ ++#define NAN_MGMT_FRM_SUBTYPE_RANGING_REQ 1 ++/* NAN Ranging Response */ ++#define NAN_MGMT_FRM_SUBTYPE_RANGING_RESP 2 ++/* NAN Ranging Termination */ ++#define NAN_MGMT_FRM_SUBTYPE_RANGING_TERM 3 ++/* NAN Ranging Report */ ++#define NAN_MGMT_FRM_SUBTYPE_RANGING_RPT 4 ++/* NDP Request */ ++#define NAN_MGMT_FRM_SUBTYPE_NDP_REQ 5 ++/* NDP Response */ ++#define NAN_MGMT_FRM_SUBTYPE_NDP_RESP 6 ++/* NDP Confirm */ ++#define NAN_MGMT_FRM_SUBTYPE_NDP_CONFIRM 7 ++/* NDP Key Installment */ ++#define NAN_MGMT_FRM_SUBTYPE_NDP_KEY_INST 8 ++/* NDP Termination */ ++#define NAN_MGMT_FRM_SUBTYPE_NDP_END 9 ++/* Schedule Request */ ++#define NAN_MGMT_FRM_SUBTYPE_SCHED_REQ 10 ++/* Schedule Response */ ++#define NAN_MGMT_FRM_SUBTYPE_SCHED_RESP 11 ++/* Schedule Confirm */ ++#define NAN_MGMT_FRM_SUBTYPE_SCHED_CONF 12 ++/* Schedule Update */ ++#define NAN_MGMT_FRM_SUBTYPE_SCHED_UPD 13 ++ ++/* Reason code defines */ ++#define NAN_REASON_RESERVED 0x0 ++#define NAN_REASON_UNSPECIFIED 0x1 ++#define NAN_REASON_RESOURCE_LIMIT 0x2 ++#define NAN_REASON_INVALID_PARAMS 0x3 ++#define NAN_REASON_FTM_PARAM_INCAP 0x4 ++#define NAN_REASON_NO_MOVEMENT 0x5 ++#define NAN_REASON_INVALID_AVAIL 0x6 ++#define NAN_REASON_IMMUT_UNACCEPT 0x7 ++#define NAN_REASON_SEC_POLICY 0x8 ++#define NAN_REASON_QOS_UNACCEPT 0x9 ++#define NAN_REASON_NDP_REJECT 0xa ++#define NAN_REASON_NDL_UNACCEPTABLE 0xb ++ ++/* nan 2.0 qos (not attribute) */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndp_qos_s { ++ uint8 tid; /* traffic identifier */ ++ uint16 pkt_size; /* service data pkt size */ ++ uint8 data_rate; /* mean data rate */ ++ uint8 svc_interval; /* max service interval */ ++} BWL_POST_PACKED_STRUCT wifi_nan_ndp_qos_t; ++ ++/* NDP control bitmap defines */ ++#define NAN_NDP_CTRL_CONFIRM_REQUIRED 0x01 ++#define NAN_NDP_CTRL_SECURTIY_PRESENT 0x04 ++#define NAN_NDP_CTRL_PUB_ID_PRESENT 0x08 ++#define NAN_NDP_CTRL_RESP_NDI_PRESENT 0x10 ++#define NAN_NDP_CTRL_SPEC_INFO_PRESENT 0x20 ++#define NAN_NDP_CTRL_RESERVED 0xA0 ++ ++/* NDP Attribute */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndp_attr_s { ++ uint8 id; /* 0x10 */ ++ uint16 len; /* length */ ++ uint8 dialog_token; /* dialog token */ ++ uint8 type_status; /* bits 0-3 type, 4-7 status */ ++ uint8 reason; /* reason code */ ++ struct ether_addr init_ndi; /* ndp initiator's data interface address */ ++ uint8 ndp_id; /* ndp identifier (created by initiator */ ++ uint8 control; /* ndp control field */ ++ uint8 var[]; /* Optional fields follow */ ++} BWL_POST_PACKED_STRUCT wifi_nan_ndp_attr_t; ++/* NDP attribute type and status macros */ ++#define NAN_NDP_TYPE_MASK 0x0F ++#define NAN_NDP_TYPE_REQUEST 0x0 ++#define NAN_NDP_TYPE_RESPONSE 0x1 ++#define NAN_NDP_TYPE_CONFIRM 0x2 ++#define NAN_NDP_TYPE_SECURITY 0x3 ++#define NAN_NDP_TYPE_TERMINATE 0x4 ++#define NAN_NDP_REQUEST(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == NAN_NDP_TYPE_REQUEST) ++#define NAN_NDP_RESPONSE(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == NAN_NDP_TYPE_RESPONSE) ++#define NAN_NDP_CONFIRM(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == NAN_NDP_TYPE_CONFIRM) ++#define NAN_NDP_SECURITY_INST(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == \ ++ NAN_NDP_TYPE_SECURITY) ++#define NAN_NDP_TERMINATE(_ndp) (((_ndp)->type_status & NAN_NDP_TYPE_MASK) == \ ++ NAN_NDP_TYPE_TERMINATE) ++#define NAN_NDP_STATUS_SHIFT 4 ++#define NAN_NDP_STATUS_MASK 0xF0 ++#define NAN_NDP_STATUS_CONT (0 << NAN_NDP_STATUS_SHIFT) ++#define NAN_NDP_STATUS_ACCEPT (1 << NAN_NDP_STATUS_SHIFT) ++#define NAN_NDP_STATUS_REJECT (2 << NAN_NDP_STATUS_SHIFT) ++#define NAN_NDP_CONT(_ndp) (((_ndp)->type_status & NAN_NDP_STATUS_MASK) == NAN_NDP_STATUS_CONT) ++#define NAN_NDP_ACCEPT(_ndp) (((_ndp)->type_status & NAN_NDP_STATUS_MASK) == \ ++ NAN_NDP_STATUS_ACCEPT) ++#define NAN_NDP_REJECT(_ndp) (((_ndp)->type_status & NAN_NDP_STATUS_MASK) == \ ++ NAN_NDP_STATUS_REJECT) ++/* NDP Setup Status */ ++#define NAN_NDP_SETUP_STATUS_OK 1 ++#define NAN_NDP_SETUP_STATUS_FAIL 0 ++#define NAN_NDP_SETUP_STATUS_REJECT 2 ++ ++/* Rng setup attribute type and status macros */ ++#define NAN_RNG_TYPE_MASK 0x0F ++#define NAN_RNG_TYPE_REQUEST 0x0 ++#define NAN_RNG_TYPE_RESPONSE 0x1 ++#define NAN_RNG_TYPE_TERMINATE 0x2 ++ ++#define NAN_RNG_STATUS_SHIFT 4 ++#define NAN_RNG_STATUS_MASK 0xF0 ++#define NAN_RNG_STATUS_ACCEPT (0 << NAN_RNG_STATUS_SHIFT) ++#define NAN_RNG_STATUS_REJECT (1 << NAN_RNG_STATUS_SHIFT) ++ ++#define NAN_RNG_ACCEPT(_rsua) (((_rsua)->type_status & NAN_RNG_STATUS_MASK) == \ ++ NAN_RNG_STATUS_ACCEPT) ++#define NAN_RNG_REJECT(_rsua) (((_rsua)->type_status & NAN_RNG_STATUS_MASK) == \ ++ NAN_RNG_STATUS_REJECT) ++ ++/* schedule entry */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sched_entry_s { ++ uint8 map_id; /* map id */ ++ uint16 tbmp_ctrl; /* time bitmap control */ ++ uint8 tbmp_len; /* time bitmap len */ ++ uint8 tbmp[]; /* time bitmap - Optional */ ++} BWL_POST_PACKED_STRUCT wifi_nan_sched_entry_t; ++ ++#define NAN_SCHED_ENTRY_MIN_SIZE OFFSETOF(wifi_nan_sched_entry_t, tbmp) ++#define NAN_SCHED_ENTRY_SIZE(_entry) (NAN_SCHED_ENTRY_MIN_SIZE + (_entry)->tbmp_len) ++ ++/* for dev cap, element container etc. */ ++#define NAN_DEV_ELE_MAPID_CTRL_MASK 0x1 ++#define NAN_DEV_ELE_MAPID_CTRL_SHIFT 0 ++#define NAN_DEV_ELE_MAPID_MASK 0x1E ++#define NAN_DEV_ELE_MAPID_SHIFT 1 ++ ++#define NAN_DEV_ELE_MAPID_CTRL_SET(_mapid_field, value) \ ++ do {(_mapid_field) &= ~NAN_DEV_ELE_MAPID_CTRL_MASK; \ ++ (_mapid_field) |= ((value << NAN_DEV_ELE_MAPID_CTRL_SHIFT) & \ ++ NAN_DEV_ELE_MAPID_CTRL_MASK); \ ++ } while (0); ++ ++#define NAN_DEV_ELE_MAPID_CTRL_GET(_mapid_field) \ ++ (((_mapid_field) & NAN_DEV_ELE_MAPID_CTRL_MASK) >> \ ++ NAN_DEV_ELE_MAPID_CTRL_SHIFT) ++ ++#define NAN_DEV_ELE_MAPID_SET(_mapid_field, value) \ ++ do {(_mapid_field) &= ~NAN_DEV_ELE_MAPID_MASK; \ ++ (_mapid_field) |= ((value << NAN_DEV_ELE_MAPID_SHIFT) & \ ++ NAN_DEV_ELE_MAPID_MASK); \ ++ } while (0); ++ ++#define NAN_DEV_ELE_MAPID_GET(_mapid_field) \ ++ (((_mapid_field) & NAN_DEV_ELE_MAPID_MASK) >> \ ++ NAN_DEV_ELE_MAPID_SHIFT) ++ ++/* schedule entry map id handling */ ++#define NAN_SCHED_ENTRY_MAPID_MASK 0x0F ++#define NAN_SCHED_ENTRY_MAPID_SHIFT 0 ++ ++#define NAN_SCHED_ENTRY_MAPID_SET(_mapid_field, value) \ ++ do {(_mapid_field) &= ~NAN_SCHED_ENTRY_MAPID_MASK; \ ++ (_mapid_field) |= ((value << NAN_SCHED_ENTRY_MAPID_SHIFT) & \ ++ NAN_SCHED_ENTRY_MAPID_MASK); \ ++ } while (0); ++ ++#define NAN_SCHED_ENTRY_MAPID_GET(_mapid_field) \ ++ (((_mapid_field) & NAN_SCHED_ENTRY_MAPID_MASK) >> \ ++ NAN_SCHED_ENTRY_MAPID_SHIFT) ++ ++/* NDC attribute */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_ndc_attr_s { ++ uint8 id; ++ uint16 len; ++ uint8 ndc_id[NAN_DATA_NDC_ID_SIZE]; ++ uint8 attr_cntrl; ++ uint8 var[]; ++} BWL_POST_PACKED_STRUCT wifi_nan_ndc_attr_t; ++ ++/* Attribute control subfield of NDC attr */ ++/* Proposed NDC */ ++#define NAN_NDC_ATTR_PROPOSED_NDC_MASK 0x1 ++#define NAN_NDC_ATTR_PROPOSED_NDC_SHIFT 0 ++ ++/* get & set */ ++#define NAN_NDC_GET_PROPOSED_FLAG(_attr) \ ++ (((_attr)->attr_cntrl & NAN_NDC_ATTR_PROPOSED_NDC_MASK) >> \ ++ NAN_NDC_ATTR_PROPOSED_NDC_SHIFT) ++#define NAN_NDC_SET_PROPOSED_FLAG(_attr, value) \ ++ do {((_attr)->attr_cntrl &= ~NAN_NDC_ATTR_PROPOSED_NDC_MASK); \ ++ ((_attr)->attr_cntrl |= \ ++ (((value) << NAN_NDC_ATTR_PROPOSED_NDC_SHIFT) & NAN_NDC_ATTR_PROPOSED_NDC_MASK)); \ ++ } while (0) ++ ++/* Service descriptor extension attribute */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_svc_desc_ext_attr_s { ++ /* Attribute ID - 0x11 */ ++ uint8 id; ++ /* Length of the following fields in the attribute */ ++ uint16 len; ++ /* Instance id of associated service descriptor attribute */ ++ uint8 instance_id; ++ /* SDE control field */ ++ uint16 control; ++ /* range limit, svc upd indicator etc. */ ++ uint8 var[]; ++} BWL_POST_PACKED_STRUCT wifi_nan_svc_desc_ext_attr_t; ++ ++#define NAN_SDE_ATTR_MIN_LEN OFFSETOF(wifi_nan_svc_desc_ext_attr_t, var) ++ ++/* SDEA control field bit definitions and access macros */ ++#define NAN_SDE_CF_FSD_REQUIRED (1 << 0) ++#define NAN_SDE_CF_FSD_GAS (1 << 1) ++#define NAN_SDE_CF_DP_REQUIRED (1 << 2) ++#define NAN_SDE_CF_DP_TYPE (1 << 3) ++#define NAN_SDE_CF_MULTICAST_TYPE (1 << 4) ++#define NAN_SDE_CF_QOS_REQUIRED (1 << 5) ++#define NAN_SDE_CF_SECURITY_REQUIRED (1 << 6) ++#define NAN_SDE_CF_RANGING_REQUIRED (1 << 7) ++#define NAN_SDE_CF_RANGE_PRESENT (1 << 8) ++#define NAN_SDE_CF_SVC_UPD_IND_PRESENT (1 << 9) ++#define NAN_SDE_FSD_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_FSD_REQUIRED) ++#define NAN_SDE_FSD_GAS(_sde) ((_sde)->control & NAN_SDE_CF_FSD_GAS) ++#define NAN_SDE_DP_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_DP_REQUIRED) ++#define NAN_SDE_DP_MULTICAST(_sde) ((_sde)->control & NAN_SDE_CF_DP_TYPE) ++#define NAN_SDE_MULTICAST_M_TO_M(_sde) ((_sde)->control & NAN_SDE_CF_MULTICAST_TYPE) ++#define NAN_SDE_QOS_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_QOS_REQUIRED) ++#define NAN_SDE_SECURITY_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_SECURITY_REQUIRED) ++#define NAN_SDE_RANGING_REQUIRED(_sde) ((_sde)->control & NAN_SDE_CF_RANGING_REQUIRED) ++#define NAN_SDE_RANGE_PRESENT(_sde) ((_sde)->control & NAN_SDE_CF_RANGE_PRESENT) ++#define NAN_SDE_SVC_UPD_IND_PRESENT(_sde) ((_sde)->control & NAN_SDE_CF_SVC_UPD_IND_PRESENT) ++ ++/* nan2 security */ ++ ++/* ++ * Cipher suite information Attribute. ++ * WFA Tech. Spec ver 1.0.r21 (section 10.7.24.2) ++ */ ++#define NAN_SEC_CIPHER_SUITE_CAP_REPLAY_4 0 ++#define NAN_SEC_CIPHER_SUITE_CAP_REPLAY_16 (1 << 0) ++ ++/* enum security algo. ++*/ ++enum nan_sec_csid { ++ NAN_SEC_ALGO_NONE = 0, ++ NAN_SEC_ALGO_NCS_SK_CCM_128 = 1, /* CCMP 128 */ ++ NAN_SEC_ALGO_NCS_SK_GCM_256 = 2, /* GCMP 256 */ ++ NAN_SEC_ALGO_LAST = 3 ++}; ++typedef int8 nan_sec_csid_e; ++ ++/* nan2 cipher suite attribute field */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sec_cipher_suite_field_s { ++ uint8 cipher_suite_id; ++ uint8 inst_id; /* Instance Id */ ++} BWL_POST_PACKED_STRUCT wifi_nan_sec_cipher_suite_field_t; ++ ++/* nan2 cipher suite information attribute field */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sec_cipher_suite_info_attr_s { ++ uint8 attr_id; /* 0x22 - NAN_ATTR_CIPHER_SUITE_INFO */ ++ uint16 len; ++ uint8 capabilities; ++ uint8 var[]; /* cipher suite list */ ++} BWL_POST_PACKED_STRUCT wifi_nan_sec_cipher_suite_info_attr_t; ++ ++/* ++ * Security context identifier attribute ++ * WFA Tech. Spec ver 1.0.r21 (section 10.7.24.4) ++ */ ++ ++#define NAN_SEC_CTX_ID_TYPE_PMKID (1 << 0) ++ ++/* nan2 security context identifier attribute field */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sec_ctx_id_field_s { ++ uint16 sec_ctx_id_type_len; /* length of security ctx identifier */ ++ uint8 sec_ctx_id_type; ++ uint8 inst_id; /* Instance Id */ ++ uint8 var[]; /* security ctx identifier */ ++} BWL_POST_PACKED_STRUCT wifi_nan_sec_ctx_id_field_t; ++ ++/* nan2 security context identifier info attribute field */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sec_ctx_id_info_attr_s { ++ uint8 attr_id; /* 0x23 - NAN_ATTR_SEC_CTX_ID_INFO */ ++ uint16 len; ++ uint8 var[]; /* security context identifier list */ ++} BWL_POST_PACKED_STRUCT wifi_nan_sec_ctx_id_info_attr_t; ++ ++/* ++ * Nan shared key descriptor attribute ++ * WFA Tech. Spec ver 23 ++ */ ++ ++#define NAN_SEC_NCSSK_DESC_REPLAY_CNT_LEN 8 ++#define NAN_SEC_NCSSK_DESC_KEY_NONCE_LEN 32 ++ ++/* nan shared key descriptor attr field */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_sec_ncssk_key_desc_attr_s { ++ uint8 attr_id; /* 0x24 - NAN_ATTR_SHARED_KEY_DESC */ ++ uint16 len; ++ uint8 inst_id; /* Publish service instance ID */ ++ uint8 desc_type; ++ uint16 key_info; ++ uint16 key_len; ++ uint8 key_replay_cntr[NAN_SEC_NCSSK_DESC_REPLAY_CNT_LEN]; ++ uint8 key_nonce[NAN_SEC_NCSSK_DESC_KEY_NONCE_LEN]; ++ uint8 reserved[32]; /* EAPOL IV + Key RSC + Rsvd fields in EAPOL Key */ ++ uint8 mic[]; /* mic + key data len + key data */ ++} BWL_POST_PACKED_STRUCT wifi_nan_sec_ncssk_key_desc_attr_t; ++ ++/* Key Info fields */ ++#define NAN_SEC_NCSSK_DESC_MASK 0x7 ++#define NAN_SEC_NCSSK_DESC_SHIFT 0 ++#define NAN_SEC_NCSSK_DESC_KEY_TYPE_MASK 0x8 ++#define NAN_SEC_NCSSK_DESC_KEY_TYPE_SHIFT 3 ++#define NAN_SEC_NCSSK_DESC_KEY_INSTALL_MASK 0x40 ++#define NAN_SEC_NCSSK_DESC_KEY_INSTALL_SHIFT 6 ++#define NAN_SEC_NCSSK_DESC_KEY_ACK_MASK 0x80 ++#define NAN_SEC_NCSSK_DESC_KEY_ACK_SHIFT 7 ++#define NAN_SEC_NCSSK_DESC_KEY_MIC_MASK 0x100 ++#define NAN_SEC_NCSSK_DESC_KEY_MIC_SHIFT 8 ++#define NAN_SEC_NCSSK_DESC_KEY_SEC_MASK 0x200 ++#define NAN_SEC_NCSSK_DESC_KEY_SEC_SHIFT 9 ++#define NAN_SEC_NCSSK_DESC_KEY_ERR_MASK 0x400 ++#define NAN_SEC_NCSSK_DESC_KEY_ERR_SHIFT 10 ++#define NAN_SEC_NCSSK_DESC_KEY_REQ_MASK 0x800 ++#define NAN_SEC_NCSSK_DESC_KEY_REQ_SHIFT 11 ++#define NAN_SEC_NCSSK_DESC_KEY_ENC_KEY_MASK 0x1000 ++#define NAN_SEC_NCSSK_DESC_KEY_ENC_KEY_SHIFT 12 ++#define NAN_SEC_NCSSK_DESC_KEY_SMK_MSG_MASK 0x2000 ++#define NAN_SEC_NCSSK_DESC_KEY_SMK_MSG_SHIFT 13 ++ ++/* Key Info get & set macros */ ++#define NAN_SEC_NCSSK_KEY_DESC_VER_GET(_key_info) \ ++ (((_key_info) & NAN_SEC_NCSSK_DESC_MASK) >> NAN_SEC_NCSSK_DESC_SHIFT) ++#define NAN_SEC_NCSSK_KEY_DESC_VER_SET(_val, _key_info) \ ++ do {(_key_info) &= ~NAN_SEC_NCSSK_DESC_MASK; \ ++ (_key_info) |= (((_val) << NAN_SEC_NCSSK_DESC_SHIFT) & \ ++ NAN_SEC_NCSSK_DESC_MASK);} while (0) ++#define NAN_SEC_NCSSK_DESC_KEY_TYPE_GET(_key_info) \ ++ (((_key_info) & NAN_SEC_NCSSK_DESC_KEY_TYPE_MASK) >> NAN_SEC_NCSSK_DESC_KEY_TYPE_SHIFT) ++#define NAN_SEC_NCSSK_DESC_KEY_TYPE_SET(_val, _key_info) \ ++ do {(_key_info) &= ~NAN_SEC_NCSSK_DESC_KEY_TYPE_MASK; \ ++ (_key_info) |= (((_val) << NAN_SEC_NCSSK_DESC_KEY_TYPE_SHIFT) & \ ++ NAN_SEC_NCSSK_DESC_KEY_TYPE_MASK);} while (0) ++#define NAN_SEC_NCSSK_DESC_KEY_INSTALL_GET(_key_info) \ ++ (((_key_info) & NAN_SEC_NCSSK_DESC_KEY_INSTALL_MASK) >> \ ++ NAN_SEC_NCSSK_DESC_KEY_INSTALL_SHIFT) ++#define NAN_SEC_NCSSK_DESC_KEY_INSTALL_SET(_val, _key_info) \ ++ do {(_key_info) &= ~NAN_SEC_NCSSK_DESC_KEY_INSTALL_MASK; \ ++ (_key_info) |= (((_val) << NAN_SEC_NCSSK_DESC_KEY_INSTALL_SHIFT) & \ ++ NAN_SEC_NCSSK_DESC_KEY_INSTALL_MASK);} while (0) ++#define NAN_SEC_NCSSK_DESC_KEY_ACK_GET(_key_info) \ ++ (((_key_info) & NAN_SEC_NCSSK_DESC_KEY_ACK_MASK) >> NAN_SEC_NCSSK_DESC_KEY_ACK_SHIFT) ++#define NAN_SEC_NCSSK_DESC_KEY_ACK_SET(_val, _key_info) \ ++ do {(_key_info) &= ~NAN_SEC_NCSSK_DESC_KEY_ACK_MASK; \ ++ (_key_info) |= (((_val) << NAN_SEC_NCSSK_DESC_KEY_ACK_SHIFT) & \ ++ NAN_SEC_NCSSK_DESC_KEY_ACK_MASK);} while (0) ++#define NAN_SEC_NCSSK_DESC_KEY_MIC_GET(_key_info) \ ++ (((_key_info) & NAN_SEC_NCSSK_DESC_KEY_MIC_MASK) >> NAN_SEC_NCSSK_DESC_KEY_MIC_SHIFT) ++#define NAN_SEC_NCSSK_DESC_KEY_MIC_SET(_val, _key_info) \ ++ do {(_key_info) &= ~NAN_SEC_NCSSK_DESC_KEY_MIC_MASK; \ ++ (_key_info) |= (((_val) << NAN_SEC_NCSSK_DESC_KEY_MIC_SHIFT) & \ ++ NAN_SEC_NCSSK_DESC_KEY_MIC_MASK);} while (0) ++#define NAN_SEC_NCSSK_DESC_KEY_SEC_GET(_key_info) \ ++ (((_key_info) & NAN_SEC_NCSSK_DESC_KEY_SEC_MASK) >> NAN_SEC_NCSSK_DESC_KEY_SEC_SHIFT) ++#define NAN_SEC_NCSSK_DESC_KEY_SEC_SET(_val, _key_info) \ ++ do {(_key_info) &= ~NAN_SEC_NCSSK_DESC_KEY_SEC_MASK; \ ++ (_key_info) |= (((_val) << NAN_SEC_NCSSK_DESC_KEY_SEC_SHIFT) & \ ++ NAN_SEC_NCSSK_DESC_KEY_SEC_MASK);} while (0) ++#define NAN_SEC_NCSSK_DESC_KEY_ERR_GET(_key_info) \ ++ (((_key_info) & NAN_SEC_NCSSK_DESC_KEY_ERR_MASK) >> NAN_SEC_NCSSK_DESC_KEY_ERR_SHIFT) ++#define NAN_SEC_NCSSK_DESC_KEY_ERR_SET(_val, _key_info) \ ++ do {(_key_info) &= ~NAN_SEC_NCSSK_DESC_KEY_ERR_MASK; \ ++ (_key_info) |= (((_val) << NAN_SEC_NCSSK_DESC_KEY_ERR_SHIFT) & \ ++ NAN_SEC_NCSSK_DESC_KEY_ERR_MASK);} while (0) ++#define NAN_SEC_NCSSK_DESC_KEY_REQ_GET(_key_info) \ ++ (((_key_info) & NAN_SEC_NCSSK_DESC_KEY_REQ_MASK) >> NAN_SEC_NCSSK_DESC_KEY_REQ_SHIFT) ++#define NAN_SEC_NCSSK_DESC_KEY_REQ_SET(_val, _key_info) \ ++ do {(_key_info) &= ~NAN_SEC_NCSSK_DESC_KEY_REQ_MASK; \ ++ (_key_info) |= (((_val) << NAN_SEC_NCSSK_DESC_KEY_REQ_SHIFT) & \ ++ NAN_SEC_NCSSK_DESC_KEY_REQ_MASK);} while (0) ++#define NAN_SEC_NCSSK_DESC_KEY_ENC_KEY_GET(_key_info) \ ++ (((_key_info) & NAN_SEC_NCSSK_DESC_KEY_ENC_KEY_MASK) >> \ ++ NAN_SEC_NCSSK_DESC_KEY_ENC_KEY_SHIFT) ++#define NAN_SEC_NCSSK_DESC_KEY_ENC_KEY_SET(_val, _key_info) \ ++ do {(_key_info) &= ~NAN_SEC_NCSSK_DESC_KEY_ENC_KEY_MASK; \ ++ (_key_info) |= (((_val) << NAN_SEC_NCSSK_DESC_KEY_ENC_KEY_SHIFT) & \ ++ NAN_SEC_NCSSK_DESC_KEY_ENC_KEY_MASK);} while (0) ++#define NAN_SEC_NCSSK_DESC_KEY_SMK_MSG_GET(_key_info) \ ++ (((_key_info) & NAN_SEC_NCSSK_DESC_KEY_SMK_MSG_MASK) >> \ ++ NAN_SEC_NCSSK_DESC_KEY_SMK_MSG_SHIFT) ++#define NAN_SEC_NCSSK_DESC_KEY_SMK_MSG_SET(_val, _key_info) \ ++ do {(_key_info) &= ~NAN_SEC_NCSSK_DESC_KEY_SMK_MSG_MASK; \ ++ (_key_info) |= (((_val) << NAN_SEC_NCSSK_DESC_KEY_SMK_MSG_SHIFT) & \ ++ NAN_SEC_NCSSK_DESC_KEY_SMK_MSG_MASK);} while (0) ++ ++#define NAN_SEC_NCSSK_IEEE80211_KDESC_TYPE 2 /* IEEE 802.11 Key Descriptor Type */ ++#define NAN_SEC_NCSSK_KEY_DESC_VER 0 /* NCSSK-128/256 */ ++#define NAN_SEC_NCSSK_KEY_TYPE_PAIRWISE 1 /* Pairwise */ ++#define NAN_SEC_NCSSK_LIFETIME_KDE 7 /* Lifetime KDE type */ ++ ++/* TODO include MTK related attributes */ ++ ++/* NAN Multicast service group(NMSG) definitions */ ++/* Length of NMSG_ID -- (NDI * 2^16 + pub_id * 2^8 + Random_factor) */ ++#define NAN_NMSG_ID_LEN 8 ++ ++#define NAN_NMSG_TYPE_MASK 0x0F ++#define NMSG_ATTR_TYPE_STATUS_REQUEST 0x00 ++#define NMSG_ATTR_TYPE_STATUS_RESPONSE 0x01 ++#define NMSG_ATTR_TYPE_STATUS_CONFIRM 0x02 ++#define NMSG_ATTR_TYPE_STATUS_SEC_INSTALL 0x03 ++#define NMSG_ATTR_TYPE_STATUS_TERMINATE 0x04 ++#define NMSG_ATTR_TYPE_STATUS_IMPLICIT_ENROL 0x05 ++ ++#define NMSG_ATTR_TYPE_STATUS_CONTINUED 0x00 ++#define NMSG_ATTR_TYPE_STATUS_ACCEPTED 0x10 ++#define NMSG_ATTR_TYPE_STATUS_REJECTED 0x20 ++ ++#define NMSG_CTRL_PUB_ID_PRESENT 0x0001 ++#define NMSG_CTRL_NMSG_ID_PRESENT 0x0002 ++#define NMSG_CTRL_SECURITY_PRESENT 0x0004 ++#define NMSG_CTRL_MANY_TO_MANY_PRESENT 0x0008 ++#define NMSG_CTRL_SVC_INFO_PRESENT 0x0010 ++ ++/* NMSG attribute */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_nmsg_attr_s { ++ uint8 id; /* Attribute ID - 0x11 */ ++ uint16 len; /* Length including pubid, NMSGID and svc info */ ++ uint8 dialog_token; ++ uint8 type_status; /* Type and Status field byte */ ++ uint8 reason_code; ++ uint8 mc_id; /* Multicast id similar to NDPID */ ++ uint8 nmsg_ctrl; /* NMSG control field */ ++ /* Optional publish id, NMSGID and svc info are included in var[] */ ++ uint8 var[0]; ++} BWL_POST_PACKED_STRUCT wifi_nan_nmsg_attr_t; ++ ++#define NMSG_ATTR_MCAST_SCHED_MAP_ID_MASK 0x1E ++#define NMSG_ATTR_MCAST_SCHED_MAP_ID_SHIFT 1 ++#define NMSG_ATTR_MCAST_SCHED_TIME_MAP_MASK 0x20 ++#define NMSG_ATTR_MCAST_SCHED_TIME_MAP_SHIFT 5 ++ ++/* NAN Multicast Schedule atribute structure */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_mcast_sched_attr_s { ++ uint8 id; /* 0x16 */ ++ uint16 len; ++ uint8 nmsg_id[NAN_NMSG_ID_LEN]; ++ uint8 attr_cntrl; ++ uint8 sched_own[ETHER_ADDR_LEN]; ++ uint8 var[]; /* multicast sched entry list (schedule_entry_list) */ ++} BWL_POST_PACKED_STRUCT wifi_nan_mcast_sched_attr_t; ++ ++ ++/* FAC Channel Entry (section 10.7.19.1.5) */ ++typedef BWL_PRE_PACKED_STRUCT struct wifi_nan_fac_chan_entry_s { ++ uint8 oper_class; /* Operating Class */ ++ uint16 chan_bitmap; /* Channel Bitmap */ ++ uint8 primary_chan_bmp; /* Primary Channel Bitmap */ ++ uint16 aux_chan; /* Auxiliary Channel bitmap */ ++} BWL_POST_PACKED_STRUCT wifi_nan_fac_chan_entry_t; ++ ++/* TODO move this from nan.h */ ++#define NAN_ALL_NAN_MGMT_FRAMES (NAN_FRM_SCHED_AF | \ ++ NAN_FRM_NDP_AF | NAN_FRM_NDL_AF | \ ++ NAN_FRM_DISC_BCN | NAN_FRM_SYNC_BCN | \ ++ NAN_FRM_SVC_DISC | NAN_FRM_RNG_REQ_AF | \ ++ NAN_FRM_RNG_RESP_AF | NAN_FRM_RNG_REPORT_AF | \ ++ NAN_FRM_RNG_TERM_AF) ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _NAN_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/osl.h b/module_drivers/drivers/net/wireless/bcmdhd/include/osl.h +new file mode 100644 +index 000000000..082b30152 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/osl.h +@@ -0,0 +1,260 @@ ++/* ++ * OS Abstraction Layer ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: osl.h 642189 2016-06-07 21:12:50Z $ ++ */ ++ ++#ifndef _osl_h_ ++#define _osl_h_ ++ ++#include ++ ++#define OSL_PKTTAG_SZ 32 /* Size of PktTag */ ++ ++/* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */ ++typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status); ++ ++/* Drivers use REGOPSSET() to register register read/write funcitons */ ++typedef unsigned int (*osl_rreg_fn_t)(void *ctx, volatile void *reg, unsigned int size); ++typedef void (*osl_wreg_fn_t)(void *ctx, volatile void *reg, unsigned int val, unsigned int size); ++ ++ ++#if defined(WL_UNITTEST) ++#include ++#else ++#include ++#endif ++ ++#ifndef PKTDBG_TRACE ++#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh) ++#endif ++ ++#define PKTCTFMAP(osh, p) BCM_REFERENCE(osh) ++ ++/* -------------------------------------------------------------------------- ++** Register manipulation macros. ++*/ ++ ++#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val))) ++ ++#ifndef AND_REG ++#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v)) ++#endif /* !AND_REG */ ++ ++#ifndef OR_REG ++#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v)) ++#endif /* !OR_REG */ ++ ++#if !defined(OSL_SYSUPTIME) ++#define OSL_SYSUPTIME() (0) ++#define OSL_SYSUPTIME_SUPPORT FALSE ++#else ++#define OSL_SYSUPTIME_SUPPORT TRUE ++#endif /* OSL_SYSUPTIME */ ++ ++#if !defined(OSL_SYSUPTIME_US) ++#define OSL_SYSUPTIME_US() (0) ++#endif /* OSL_SYSUPTIME */ ++ ++#ifndef OSL_SYS_HALT ++#define OSL_SYS_HALT() do {} while (0) ++#endif ++ ++#ifndef OSL_MEM_AVAIL ++#define OSL_MEM_AVAIL() (0xffffffff) ++#endif ++ ++#if !(defined(PKTC) || defined(PKTC_DONGLE)) ++ ++#ifndef OSL_OBFUSCATE_BUF ++/* For security reasons printing pointers is not allowed. ++ * Some OSLs implement OSL_OBFUSCATE_BUF to OS specific obfuscate API. ++ * If OSL_OBFUSCATE_BUF() is not implemented in OSL, then default to ++ * printing the input pointer ++ */ ++#define OSL_OBFUSCATE_BUF(x) (x) ++#endif /* OSL_OBFUSCATE_BUF */ ++ ++#define PKTCGETATTR(skb) (0) ++#define PKTCSETATTR(skb, f, p, b) BCM_REFERENCE(skb) ++#define PKTCCLRATTR(skb) BCM_REFERENCE(skb) ++#define PKTCCNT(skb) (1) ++#define PKTCLEN(skb) PKTLEN(NULL, skb) ++#define PKTCGETFLAGS(skb) (0) ++#define PKTCSETFLAGS(skb, f) BCM_REFERENCE(skb) ++#define PKTCCLRFLAGS(skb) BCM_REFERENCE(skb) ++#define PKTCFLAGS(skb) (0) ++#define PKTCSETCNT(skb, c) BCM_REFERENCE(skb) ++#define PKTCINCRCNT(skb) BCM_REFERENCE(skb) ++#define PKTCADDCNT(skb, c) BCM_REFERENCE(skb) ++#define PKTCSETLEN(skb, l) BCM_REFERENCE(skb) ++#define PKTCADDLEN(skb, l) BCM_REFERENCE(skb) ++#define PKTCSETFLAG(skb, fb) BCM_REFERENCE(skb) ++#define PKTCCLRFLAG(skb, fb) BCM_REFERENCE(skb) ++#define PKTCLINK(skb) NULL ++#define PKTSETCLINK(skb, x) BCM_REFERENCE(skb) ++#define FOREACH_CHAINED_PKT(skb, nskb) \ ++ for ((nskb) = NULL; (skb) != NULL; (skb) = (nskb)) ++#define PKTCFREE PKTFREE ++#define PKTCENQTAIL(h, t, p) \ ++do { \ ++ if ((t) == NULL) { \ ++ (h) = (t) = (p); \ ++ } \ ++} while (0) ++#endif /* !linux || !PKTC */ ++ ++#if !(defined(HNDCTF) || defined(PKTC_TX_DONGLE) || defined(PKTC)) ++#define PKTSETCHAINED(osh, skb) BCM_REFERENCE(osh) ++#define PKTCLRCHAINED(osh, skb) BCM_REFERENCE(osh) ++#define PKTISCHAINED(skb) FALSE ++#endif ++ ++/* Lbuf with fraglist */ ++#ifndef PKTFRAGPKTID ++#define PKTFRAGPKTID(osh, lb) (0) ++#endif ++#ifndef PKTSETFRAGPKTID ++#define PKTSETFRAGPKTID(osh, lb, id) BCM_REFERENCE(osh) ++#endif ++#ifndef PKTFRAGTOTNUM ++#define PKTFRAGTOTNUM(osh, lb) (0) ++#endif ++#ifndef PKTSETFRAGTOTNUM ++#define PKTSETFRAGTOTNUM(osh, lb, tot) BCM_REFERENCE(osh) ++#endif ++#ifndef PKTFRAGTOTLEN ++#define PKTFRAGTOTLEN(osh, lb) (0) ++#endif ++#ifndef PKTSETFRAGTOTLEN ++#define PKTSETFRAGTOTLEN(osh, lb, len) BCM_REFERENCE(osh) ++#endif ++#ifndef PKTIFINDEX ++#define PKTIFINDEX(osh, lb) (0) ++#endif ++#ifndef PKTSETIFINDEX ++#define PKTSETIFINDEX(osh, lb, idx) BCM_REFERENCE(osh) ++#endif ++#ifndef PKTGETLF ++#define PKTGETLF(osh, len, send, lbuf_type) (0) ++#endif ++ ++/* in rx path, reuse totlen as used len */ ++#ifndef PKTFRAGUSEDLEN ++#define PKTFRAGUSEDLEN(osh, lb) (0) ++#endif ++#ifndef PKTSETFRAGUSEDLEN ++#define PKTSETFRAGUSEDLEN(osh, lb, len) BCM_REFERENCE(osh) ++#endif ++#ifndef PKTFRAGLEN ++#define PKTFRAGLEN(osh, lb, ix) (0) ++#endif ++#ifndef PKTSETFRAGLEN ++#define PKTSETFRAGLEN(osh, lb, ix, len) BCM_REFERENCE(osh) ++#endif ++#ifndef PKTFRAGDATA_LO ++#define PKTFRAGDATA_LO(osh, lb, ix) (0) ++#endif ++#ifndef PKTSETFRAGDATA_LO ++#define PKTSETFRAGDATA_LO(osh, lb, ix, addr) BCM_REFERENCE(osh) ++#endif ++#ifndef PKTFRAGDATA_HI ++#define PKTFRAGDATA_HI(osh, lb, ix) (0) ++#endif ++#ifndef PKTSETFRAGDATA_HI ++#define PKTSETFRAGDATA_HI(osh, lb, ix, addr) BCM_REFERENCE(osh) ++#endif ++ ++/* RX FRAG */ ++#ifndef PKTISRXFRAG ++#define PKTISRXFRAG(osh, lb) (0) ++#endif ++#ifndef PKTSETRXFRAG ++#define PKTSETRXFRAG(osh, lb) BCM_REFERENCE(osh) ++#endif ++#ifndef PKTRESETRXFRAG ++#define PKTRESETRXFRAG(osh, lb) BCM_REFERENCE(osh) ++#endif ++ ++/* TX FRAG */ ++#ifndef PKTISTXFRAG ++#define PKTISTXFRAG(osh, lb) (0) ++#endif ++#ifndef PKTSETTXFRAG ++#define PKTSETTXFRAG(osh, lb) BCM_REFERENCE(osh) ++#endif ++ ++/* Need Rx completion used for AMPDU reordering */ ++#ifndef PKTNEEDRXCPL ++#define PKTNEEDRXCPL(osh, lb) (TRUE) ++#endif ++#ifndef PKTSETNORXCPL ++#define PKTSETNORXCPL(osh, lb) BCM_REFERENCE(osh) ++#endif ++#ifndef PKTRESETNORXCPL ++#define PKTRESETNORXCPL(osh, lb) BCM_REFERENCE(osh) ++#endif ++#ifndef PKTISFRAG ++#define PKTISFRAG(osh, lb) (0) ++#endif ++#ifndef PKTFRAGISCHAINED ++#define PKTFRAGISCHAINED(osh, i) (0) ++#endif ++/* TRIM Tail bytes from lfrag */ ++#ifndef PKTFRAG_TRIM_TAILBYTES ++#define PKTFRAG_TRIM_TAILBYTES(osh, p, len, type) PKTSETLEN(osh, p, PKTLEN(osh, p) - len) ++#endif ++#ifndef PKTISHDRCONVTD ++#define PKTISHDRCONVTD(osh, lb) (0) ++#endif ++ ++#ifdef BCM_SECURE_DMA ++#define SECURE_DMA_ENAB(osh) (1) ++#else ++ ++#define SECURE_DMA_ENAB(osh) (0) ++#ifndef BCMDMA64OSL ++#define SECURE_DMA_MAP(osh, va, size, direction, p, dmah, pcma, offset) ((dmaaddr_t) ((0))) ++#else ++#define SECURE_DMA_MAP(osh, va, size, direction, p, dmah, pcma, offset) ((dmaaddr_t) {(0)}) ++#endif ++#define SECURE_DMA_DD_MAP(osh, va, size, direction, p, dmah) 0 ++#ifndef BCMDMA64OSL ++#define SECURE_DMA_MAP_TXMETA(osh, va, size, direction, p, dmah, pcma) ((dmaaddr_t) ((0))) ++#else ++#define SECURE_DMA_MAP_TXMETA(osh, va, size, direction, p, dmah, pcma) ((dmaaddr_t) {(0)}) ++#endif ++#define SECURE_DMA_UNMAP(osh, pa, size, direction, p, dmah, pcma, offset) ++#define SECURE_DMA_UNMAP_ALL(osh, pcma) ++ ++#endif /* BCMDMA64OSL */ ++ ++ ++#ifndef ROMMABLE_ASSERT ++#define ROMMABLE_ASSERT(exp) ASSERT(exp) ++#endif /* ROMMABLE_ASSERT */ ++ ++#endif /* _osl_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/osl_decl.h b/module_drivers/drivers/net/wireless/bcmdhd/include/osl_decl.h +new file mode 100644 +index 000000000..977a1ca46 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/osl_decl.h +@@ -0,0 +1,37 @@ ++/* ++ * osl forward declarations ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: osl_decl.h 596126 2015-10-29 19:53:48Z $ ++ */ ++ ++#ifndef _osl_decl_h_ ++#define _osl_decl_h_ ++ ++/* osl handle type forward declaration */ ++typedef struct osl_info osl_t; ++typedef struct osl_dmainfo osldma_t; ++extern unsigned int lmtest; /* low memory test */ ++#endif +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/osl_ext.h b/module_drivers/drivers/net/wireless/bcmdhd/include/osl_ext.h +new file mode 100644 +index 000000000..2503f6a37 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/osl_ext.h +@@ -0,0 +1,697 @@ ++/* ++ * OS Abstraction Layer Extension - the APIs defined by the "extension" API ++ * are only supported by a subset of all operating systems. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: osl_ext.h 611959 2016-01-12 15:23:56Z $ ++ */ ++ ++#ifndef _osl_ext_h_ ++#define _osl_ext_h_ ++ ++ ++/* ---- Include Files ---------------------------------------------------- */ ++ ++#if defined(TARGETOS_symbian) ++ #include ++ #include ++#elif defined(THREADX) ++ #include ++#else ++ #define OSL_EXT_DISABLED ++#endif ++ ++/* Include base operating system abstraction. */ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ---- Constants and Types ---------------------------------------------- */ ++ ++/* ----------------------------------------------------------------------- ++ * Generic OS types. ++ */ ++typedef enum osl_ext_status_t ++{ ++ OSL_EXT_SUCCESS, ++ OSL_EXT_ERROR, ++ OSL_EXT_TIMEOUT ++ ++} osl_ext_status_t; ++#define OSL_EXT_STATUS_DECL(status) osl_ext_status_t status; ++ ++#define OSL_EXT_TIME_FOREVER ((osl_ext_time_ms_t)(-1)) ++typedef unsigned int osl_ext_time_ms_t; ++ ++typedef unsigned int osl_ext_event_bits_t; ++ ++typedef unsigned int osl_ext_interrupt_state_t; ++ ++/* ----------------------------------------------------------------------- ++ * Timers. ++ */ ++typedef enum ++{ ++ /* One-shot timer. */ ++ OSL_EXT_TIMER_MODE_ONCE, ++ ++ /* Periodic timer. */ ++ OSL_EXT_TIMER_MODE_REPEAT ++ ++} osl_ext_timer_mode_t; ++ ++/* User registered callback and parameter to invoke when timer expires. */ ++typedef void* osl_ext_timer_arg_t; ++typedef void (*osl_ext_timer_callback)(osl_ext_timer_arg_t arg); ++ ++ ++/* ----------------------------------------------------------------------- ++ * Tasks. ++ */ ++ ++/* Task entry argument. */ ++typedef void* osl_ext_task_arg_t; ++ ++/* Task entry function. */ ++typedef void (*osl_ext_task_entry)(osl_ext_task_arg_t arg); ++ ++/* Abstract task priority levels. */ ++typedef enum ++{ ++ OSL_EXT_TASK_IDLE_PRIORITY, ++ OSL_EXT_TASK_LOW_PRIORITY, ++ OSL_EXT_TASK_LOW_NORMAL_PRIORITY, ++ OSL_EXT_TASK_NORMAL_PRIORITY, ++ OSL_EXT_TASK_HIGH_NORMAL_PRIORITY, ++ OSL_EXT_TASK_HIGHEST_PRIORITY, ++ OSL_EXT_TASK_TIME_CRITICAL_PRIORITY, ++ ++ /* This must be last. */ ++ OSL_EXT_TASK_NUM_PRIORITES ++} osl_ext_task_priority_t; ++ ++ ++#ifndef OSL_EXT_DISABLED ++ ++/* ---- Variable Externs ------------------------------------------------- */ ++/* ---- Function Prototypes ---------------------------------------------- */ ++ ++ ++/* -------------------------------------------------------------------------- ++** Semaphore ++*/ ++ ++/**************************************************************************** ++* Function: osl_ext_sem_create ++* ++* Purpose: Creates a counting semaphore object, which can subsequently be ++* used for thread notification. ++* ++* Parameters: name (in) Name to assign to the semaphore (must be unique). ++* init_cnt (in) Initial count that the semaphore should have. ++* sem (out) Newly created semaphore. ++* ++* Returns: OSL_EXT_SUCCESS if the semaphore was created successfully, or an ++* error code if the semaphore could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_sem_create(char *name, int init_cnt, osl_ext_sem_t *sem); ++ ++/**************************************************************************** ++* Function: osl_ext_sem_delete ++* ++* Purpose: Destroys a previously created semaphore object. ++* ++* Parameters: sem (mod) Semaphore object to destroy. ++* ++* Returns: OSL_EXT_SUCCESS if the semaphore was deleted successfully, or an ++* error code if the semaphore could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_sem_delete(osl_ext_sem_t *sem); ++ ++/**************************************************************************** ++* Function: osl_ext_sem_give ++* ++* Purpose: Increments the count associated with the semaphore. This will ++* cause one thread blocked on a take to wake up. ++* ++* Parameters: sem (mod) Semaphore object to give. ++* ++* Returns: OSL_EXT_SUCCESS if the semaphore was given successfully, or an ++* error code if the semaphore could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_sem_give(osl_ext_sem_t *sem); ++ ++/**************************************************************************** ++* Function: osl_ext_sem_take ++* ++* Purpose: Decrements the count associated with the semaphore. If the count ++* is less than zero, then the calling task will become blocked until ++* another thread does a give on the semaphore. This function will only ++* block the calling thread for timeout_msec milliseconds, before ++* returning with OSL_EXT_TIMEOUT. ++* ++* Parameters: sem (mod) Semaphore object to take. ++* timeout_msec (in) Number of milliseconds to wait for the ++* semaphore to enter a state where it can be ++* taken. ++* ++* Returns: OSL_EXT_SUCCESS if the semaphore was taken successfully, or an ++* error code if the semaphore could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_sem_take(osl_ext_sem_t *sem, osl_ext_time_ms_t timeout_msec); ++ ++ ++/* -------------------------------------------------------------------------- ++** Mutex ++*/ ++ ++/**************************************************************************** ++* Function: osl_ext_mutex_create ++* ++* Purpose: Creates a mutex object, which can subsequently be used to control ++* mutually exclusion of resources. ++* ++* Parameters: name (in) Name to assign to the mutex (must be unique). ++* mutex (out) Mutex object to initialize. ++* ++* Returns: OSL_EXT_SUCCESS if the mutex was created successfully, or an ++* error code if the mutex could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_mutex_create(char *name, osl_ext_mutex_t *mutex); ++ ++/**************************************************************************** ++* Function: osl_ext_mutex_delete ++* ++* Purpose: Destroys a previously created mutex object. ++* ++* Parameters: mutex (mod) Mutex object to destroy. ++* ++* Returns: OSL_EXT_SUCCESS if the mutex was deleted successfully, or an ++* error code if the mutex could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_mutex_delete(osl_ext_mutex_t *mutex); ++ ++/**************************************************************************** ++* Function: osl_ext_mutex_acquire ++* ++* Purpose: Acquires the indicated mutual exclusion object. If the object is ++* currently acquired by another task, then this function will wait ++* for timeout_msec milli-seconds before returning with OSL_EXT_TIMEOUT. ++* ++* Parameters: mutex (mod) Mutex object to acquire. ++* timeout_msec (in) Number of milliseconds to wait for the mutex. ++* ++* Returns: OSL_EXT_SUCCESS if the mutex was acquired successfully, or an ++* error code if the mutex could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_mutex_acquire(osl_ext_mutex_t *mutex, osl_ext_time_ms_t timeout_msec); ++ ++/**************************************************************************** ++* Function: osl_ext_mutex_release ++* ++* Purpose: Releases the indicated mutual exclusion object. This makes it ++* available for another task to acquire. ++* ++* Parameters: mutex (mod) Mutex object to release. ++* ++* Returns: OSL_EXT_SUCCESS if the mutex was released successfully, or an ++* error code if the mutex could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_mutex_release(osl_ext_mutex_t *mutex); ++ ++ ++/* -------------------------------------------------------------------------- ++** Timers ++*/ ++ ++/**************************************************************************** ++* Function: osl_ext_timer_create ++* ++* Purpose: Creates a timer object. ++* ++* Parameters: name (in) Name of timer. ++* timeout_msec (in) Invoke callback after this number of milliseconds. ++* mode (in) One-shot or periodic timer. ++* func (in) Callback function to invoke on timer expiry. ++* arg (in) Argument to callback function. ++* timer (out) Timer object to create. ++* ++* Note: The function callback occurs in interrupt context. The application is ++* required to provide context switch for the callback if required. ++* ++* Returns: OSL_EXT_SUCCESS if the timer was created successfully, or an ++* error code if the timer could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t ++osl_ext_timer_create(char *name, osl_ext_time_ms_t timeout_msec, osl_ext_timer_mode_t mode, ++ osl_ext_timer_callback func, osl_ext_timer_arg_t arg, osl_ext_timer_t *timer); ++ ++/**************************************************************************** ++* Function: osl_ext_timer_delete ++* ++* Purpose: Destroys a previously created timer object. ++* ++* Parameters: timer (mod) Timer object to destroy. ++* ++* Returns: OSL_EXT_SUCCESS if the timer was created successfully, or an ++* error code if the timer could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_timer_delete(osl_ext_timer_t *timer); ++ ++/**************************************************************************** ++* Function: osl_ext_timer_start ++* ++* Purpose: Start a previously created timer object. ++* ++* Parameters: timer (in) Timer object. ++* timeout_msec (in) Invoke callback after this number of milliseconds. ++* mode (in) One-shot or periodic timer. ++* ++* Returns: OSL_EXT_SUCCESS if the timer was created successfully, or an ++* error code if the timer could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t ++osl_ext_timer_start(osl_ext_timer_t *timer, ++ osl_ext_time_ms_t timeout_msec, osl_ext_timer_mode_t mode); ++ ++/**************************************************************************** ++* Function: osl_ext_timer_stop ++* ++* Purpose: Stop a previously created timer object. ++* ++* Parameters: timer (in) Timer object. ++* ++* Returns: OSL_EXT_SUCCESS if the timer was created successfully, or an ++* error code if the timer could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t ++osl_ext_timer_stop(osl_ext_timer_t *timer); ++ ++/**************************************************************************** ++* Function: osl_ext_time_get ++* ++* Purpose: Returns incrementing time counter. ++* ++* Parameters: None. ++* ++* Returns: Returns incrementing time counter in msec. ++***************************************************************************** ++*/ ++osl_ext_time_ms_t osl_ext_time_get(void); ++ ++/* -------------------------------------------------------------------------- ++** Tasks ++*/ ++ ++/**************************************************************************** ++* Function: osl_ext_task_create ++* ++* Purpose: Create a task. ++* ++* Parameters: name (in) Pointer to task string descriptor. ++* stack (in) Pointer to stack. NULL to allocate. ++* stack_size (in) Stack size - in bytes. ++* priority (in) Abstract task priority. ++* func (in) A pointer to the task entry point function. ++* arg (in) Value passed into task entry point function. ++* task (out) Task to create. ++* ++* Returns: OSL_EXT_SUCCESS if the task was created successfully, or an ++* error code if the task could not be created. ++***************************************************************************** ++*/ ++ ++#define osl_ext_task_create(name, stack, stack_size, priority, func, arg, task) \ ++ osl_ext_task_create_ex((name), (stack), (stack_size), (priority), 0, (func), \ ++ (arg), (task)) ++ ++osl_ext_status_t osl_ext_task_create_ex(char* name, ++ void *stack, unsigned int stack_size, osl_ext_task_priority_t priority, ++ osl_ext_time_ms_t timslice_msec, osl_ext_task_entry func, osl_ext_task_arg_t arg, ++ osl_ext_task_t *task); ++ ++/**************************************************************************** ++* Function: osl_ext_task_delete ++* ++* Purpose: Destroy a task. ++* ++* Parameters: task (mod) Task to destroy. ++* ++* Returns: OSL_EXT_SUCCESS if the task was created successfully, or an ++* error code if the task could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_task_delete(osl_ext_task_t *task); ++ ++ ++/**************************************************************************** ++* Function: osl_ext_task_is_running ++* ++* Purpose: Returns current running task. ++* ++* Parameters: None. ++* ++* Returns: osl_ext_task_t of current running task. ++***************************************************************************** ++*/ ++osl_ext_task_t *osl_ext_task_current(void); ++ ++ ++/**************************************************************************** ++* Function: osl_ext_task_yield ++* ++* Purpose: Yield the CPU to other tasks of the same priority that are ++* ready-to-run. ++* ++* Parameters: None. ++* ++* Returns: OSL_EXT_SUCCESS if successful, else error code. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_task_yield(void); ++ ++ ++/**************************************************************************** ++* Function: osl_ext_task_enable_stack_check ++* ++* Purpose: Enable task stack checking. ++* ++* Parameters: None. ++* ++* Returns: OSL_EXT_SUCCESS if successful, else error code. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_task_enable_stack_check(void); ++ ++ ++/* -------------------------------------------------------------------------- ++** Queue ++*/ ++ ++/**************************************************************************** ++* Function: osl_ext_queue_create ++* ++* Purpose: Create a queue. ++* ++* Parameters: name (in) Name to assign to the queue (must be unique). ++* buffer (in) Queue buffer. NULL to allocate. ++* size (in) Size of the queue. ++* queue (out) Newly created queue. ++* ++* Returns: OSL_EXT_SUCCESS if the queue was created successfully, or an ++* error code if the queue could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_queue_create(char *name, ++ void *queue_buffer, unsigned int queue_size, ++ osl_ext_queue_t *queue); ++ ++/**************************************************************************** ++* Function: osl_ext_queue_delete ++* ++* Purpose: Destroys a previously created queue object. ++* ++* Parameters: queue (mod) Queue object to destroy. ++* ++* Returns: OSL_EXT_SUCCESS if the queue was deleted successfully, or an ++* error code if the queue could not be deleteed. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_queue_delete(osl_ext_queue_t *queue); ++ ++/**************************************************************************** ++* Function: osl_ext_queue_send ++* ++* Purpose: Send/add data to the queue. This function will not block the ++* calling thread if the queue is full. ++* ++* Parameters: queue (mod) Queue object. ++* data (in) Data pointer to be queued. ++* ++* Returns: OSL_EXT_SUCCESS if the data was queued successfully, or an ++* error code if the data could not be queued. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_queue_send(osl_ext_queue_t *queue, void *data); ++ ++/**************************************************************************** ++* Function: osl_ext_queue_send_synchronous ++* ++* Purpose: Send/add data to the queue. This function will block the ++* calling thread until the data is dequeued. ++* ++* Parameters: queue (mod) Queue object. ++* data (in) Data pointer to be queued. ++* ++* Returns: OSL_EXT_SUCCESS if the data was queued successfully, or an ++* error code if the data could not be queued. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_queue_send_synchronous(osl_ext_queue_t *queue, void *data); ++ ++/**************************************************************************** ++* Function: osl_ext_queue_receive ++* ++* Purpose: Receive/remove data from the queue. This function will only ++* block the calling thread for timeout_msec milliseconds, before ++* returning with OSL_EXT_TIMEOUT. ++* ++* Parameters: queue (mod) Queue object. ++* timeout_msec (in) Number of milliseconds to wait for the ++* data from the queue. ++* data (out) Data pointer received/removed from the queue. ++* ++* Returns: OSL_EXT_SUCCESS if the data was dequeued successfully, or an ++* error code if the data could not be dequeued. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_queue_receive(osl_ext_queue_t *queue, ++ osl_ext_time_ms_t timeout_msec, void **data); ++ ++/**************************************************************************** ++* Function: osl_ext_queue_count ++* ++* Purpose: Returns the number of items in the queue. ++* ++* Parameters: queue (mod) Queue object. ++* count (out) Data pointer received/removed from the queue. ++* ++* Returns: OSL_EXT_SUCCESS if the count was returned successfully, or an ++* error code if the count is invalid. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_queue_count(osl_ext_queue_t *queue, int *count); ++ ++ ++/* -------------------------------------------------------------------------- ++** Event ++*/ ++ ++/**************************************************************************** ++* Function: osl_ext_event_create ++* ++* Purpose: Creates a event object, which can subsequently be used to ++* notify and trigger tasks. ++* ++* Parameters: name (in) Name to assign to the event (must be unique). ++* event (out) Event object to initialize. ++* ++* Returns: OSL_EXT_SUCCESS if the event was created successfully, or an ++* error code if the event could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_event_create(char *name, osl_ext_event_t *event); ++ ++/**************************************************************************** ++* Function: osl_ext_event_delete ++* ++* Purpose: Destroys a previously created event object. ++* ++* Parameters: event (mod) Event object to destroy. ++* ++* Returns: OSL_EXT_SUCCESS if the event was created successfully, or an ++* error code if the event could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_event_delete(osl_ext_event_t *event); ++ ++/**************************************************************************** ++* Function: osl_ext_event_get ++* ++* Purpose: Get event from specified event object. ++* ++* Parameters: event (mod) Event object to get. ++* requested (in) Requested event to get. ++* timeout_msec (in) Number of milliseconds to wait for the event. ++* event_bits (out) Event bits retrieved. ++* ++* Returns: OSL_EXT_SUCCESS if the event was created successfully, or an ++* error code if the event could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_event_get(osl_ext_event_t *event, ++ osl_ext_event_bits_t requested, osl_ext_time_ms_t timeout_msec, ++ osl_ext_event_bits_t *event_bits); ++ ++/**************************************************************************** ++* Function: osl_ext_event_set ++* ++* Purpose: Set event of specified event object. ++* ++* Parameters: event (mod) Event object to set. ++* event_bits (in) Event bits to set. ++* ++* Returns: OSL_EXT_SUCCESS if the event was created successfully, or an ++* error code if the event could not be created. ++***************************************************************************** ++*/ ++osl_ext_status_t osl_ext_event_set(osl_ext_event_t *event, ++ osl_ext_event_bits_t event_bits); ++ ++ ++/* -------------------------------------------------------------------------- ++** Interrupt ++*/ ++ ++/**************************************************************************** ++* Function: osl_ext_interrupt_disable ++* ++* Purpose: Disable CPU interrupt. ++* ++* Parameters: None. ++* ++* Returns: The interrupt state before disable for restoring interrupt. ++***************************************************************************** ++*/ ++osl_ext_interrupt_state_t osl_ext_interrupt_disable(void); ++ ++ ++/**************************************************************************** ++* Function: osl_ext_interrupt_restore ++* ++* Purpose: Restore CPU interrupt state. ++* ++* Parameters: state (in) Interrupt state to restore returned from ++* osl_ext_interrupt_disable(). ++* ++* Returns: None. ++***************************************************************************** ++*/ ++void osl_ext_interrupt_restore(osl_ext_interrupt_state_t state); ++ ++#else ++ ++/* ---- Constants and Types ---------------------------------------------- */ ++ ++/* Semaphore. */ ++#define osl_ext_sem_t ++#define OSL_EXT_SEM_DECL(sem) ++ ++/* Mutex. */ ++#define osl_ext_mutex_t ++#define OSL_EXT_MUTEX_DECL(mutex) ++ ++/* Timer. */ ++#define osl_ext_timer_t ++#define OSL_EXT_TIMER_DECL(timer) ++ ++/* Task. */ ++#define osl_ext_task_t void ++#define OSL_EXT_TASK_DECL(task) ++ ++/* Queue. */ ++#define osl_ext_queue_t ++#define OSL_EXT_QUEUE_DECL(queue) ++ ++/* Event. */ ++#define osl_ext_event_t ++#define OSL_EXT_EVENT_DECL(event) ++ ++/* ---- Variable Externs ------------------------------------------------- */ ++/* ---- Function Prototypes ---------------------------------------------- */ ++ ++#define osl_ext_sem_create(name, init_cnt, sem) (OSL_EXT_SUCCESS) ++#define osl_ext_sem_delete(sem) (OSL_EXT_SUCCESS) ++#define osl_ext_sem_give(sem) (OSL_EXT_SUCCESS) ++#define osl_ext_sem_take(sem, timeout_msec) (OSL_EXT_SUCCESS) ++ ++#define osl_ext_mutex_create(name, mutex) (OSL_EXT_SUCCESS) ++#define osl_ext_mutex_delete(mutex) (OSL_EXT_SUCCESS) ++#define osl_ext_mutex_acquire(mutex, timeout_msec) (OSL_EXT_SUCCESS) ++#define osl_ext_mutex_release(mutex) (OSL_EXT_SUCCESS) ++ ++#define osl_ext_timer_create(name, timeout_msec, mode, func, arg, timer) \ ++ (OSL_EXT_SUCCESS) ++#define osl_ext_timer_delete(timer) (OSL_EXT_SUCCESS) ++#define osl_ext_timer_start(timer, timeout_msec, mode) (OSL_EXT_SUCCESS) ++#define osl_ext_timer_stop(timer) (OSL_EXT_SUCCESS) ++#define osl_ext_time_get() (0) ++ ++#define osl_ext_task_create(name, stack, stack_size, priority, func, arg, task) \ ++ (OSL_EXT_SUCCESS) ++#define osl_ext_task_delete(task) (OSL_EXT_SUCCESS) ++#define osl_ext_task_current() (NULL) ++#define osl_ext_task_yield() (OSL_EXT_SUCCESS) ++#define osl_ext_task_enable_stack_check() (OSL_EXT_SUCCESS) ++ ++#define osl_ext_queue_create(name, queue_buffer, queue_size, queue) \ ++ (OSL_EXT_SUCCESS) ++#define osl_ext_queue_delete(queue) (OSL_EXT_SUCCESS) ++#define osl_ext_queue_send(queue, data) (OSL_EXT_SUCCESS) ++#define osl_ext_queue_send_synchronous(queue, data) (OSL_EXT_SUCCESS) ++#define osl_ext_queue_receive(queue, timeout_msec, data) \ ++ (OSL_EXT_SUCCESS) ++#define osl_ext_queue_count(queue, count) (OSL_EXT_SUCCESS) ++ ++#define osl_ext_event_create(name, event) (OSL_EXT_SUCCESS) ++#define osl_ext_event_delete(event) (OSL_EXT_SUCCESS) ++#define osl_ext_event_get(event, requested, timeout_msec, event_bits) \ ++ (OSL_EXT_SUCCESS) ++#define osl_ext_event_set(event, event_bits) (OSL_EXT_SUCCESS) ++ ++#define osl_ext_interrupt_disable(void) ++#define osl_ext_interrupt_restore(state) ++ ++#endif /* OSL_EXT_DISABLED */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _osl_ext_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/p2p.h b/module_drivers/drivers/net/wireless/bcmdhd/include/p2p.h +new file mode 100644 +index 000000000..cc7aa686e +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/p2p.h +@@ -0,0 +1,713 @@ ++/* ++ * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: p2p.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _P2P_H_ ++#define _P2P_H_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++#include ++#include <802.11.h> ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++ ++/* WiFi P2P OUI values */ ++#define P2P_OUI WFA_OUI /* WiFi P2P OUI */ ++#define P2P_VER WFA_OUI_TYPE_P2P /* P2P version: 9=WiFi P2P v1.0 */ ++ ++#define P2P_IE_ID 0xdd /* P2P IE element ID */ ++ ++/* WiFi P2P IE */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie { ++ uint8 id; /* IE ID: 0xDD */ ++ uint8 len; /* IE length */ ++ uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */ ++ uint8 oui_type; /* Identifies P2P version: P2P_VER */ ++ uint8 subelts[1]; /* variable length subelements */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_ie wifi_p2p_ie_t; ++ ++#define P2P_IE_FIXED_LEN 6 ++ ++#define P2P_ATTR_ID_OFF 0 ++#define P2P_ATTR_LEN_OFF 1 ++#define P2P_ATTR_DATA_OFF 3 ++ ++#define P2P_ATTR_ID_LEN 1 /* ID filed length */ ++#define P2P_ATTR_LEN_LEN 2 /* length field length */ ++#define P2P_ATTR_HDR_LEN 3 /* ID + 2-byte length field spec 1.02 */ ++ ++#define P2P_WFDS_HASH_LEN 6 ++#define P2P_WFDS_MAX_SVC_NAME_LEN 32 ++ ++/* P2P IE Subelement IDs from WiFi P2P Technical Spec 1.00 */ ++#define P2P_SEID_STATUS 0 /* Status */ ++#define P2P_SEID_MINOR_RC 1 /* Minor Reason Code */ ++#define P2P_SEID_P2P_INFO 2 /* P2P Capability (capabilities info) */ ++#define P2P_SEID_DEV_ID 3 /* P2P Device ID */ ++#define P2P_SEID_INTENT 4 /* Group Owner Intent */ ++#define P2P_SEID_CFG_TIMEOUT 5 /* Configuration Timeout */ ++#define P2P_SEID_CHANNEL 6 /* Listen channel */ ++#define P2P_SEID_GRP_BSSID 7 /* P2P Group BSSID */ ++#define P2P_SEID_XT_TIMING 8 /* Extended Listen Timing */ ++#define P2P_SEID_INTINTADDR 9 /* Intended P2P Interface Address */ ++#define P2P_SEID_P2P_MGBTY 10 /* P2P Manageability */ ++#define P2P_SEID_CHAN_LIST 11 /* Channel List */ ++#define P2P_SEID_ABSENCE 12 /* Notice of Absence */ ++#define P2P_SEID_DEV_INFO 13 /* Device Info */ ++#define P2P_SEID_GROUP_INFO 14 /* Group Info */ ++#define P2P_SEID_GROUP_ID 15 /* Group ID */ ++#define P2P_SEID_P2P_IF 16 /* P2P Interface */ ++#define P2P_SEID_OP_CHANNEL 17 /* Operating Channel */ ++#define P2P_SEID_INVITE_FLAGS 18 /* Invitation Flags */ ++#define P2P_SEID_SERVICE_HASH 21 /* Service hash */ ++#define P2P_SEID_SESSION 22 /* Session information */ ++#define P2P_SEID_CONNECT_CAP 23 /* Connection capability */ ++#define P2P_SEID_ADVERTISE_ID 24 /* Advertisement ID */ ++#define P2P_SEID_ADVERTISE_SERVICE 25 /* Advertised service */ ++#define P2P_SEID_SESSION_ID 26 /* Session ID */ ++#define P2P_SEID_FEATURE_CAP 27 /* Feature capability */ ++#define P2P_SEID_PERSISTENT_GROUP 28 /* Persistent group */ ++#define P2P_SEID_SESSION_INFO_RESP 29 /* Session Information Response */ ++#define P2P_SEID_VNDR 221 /* Vendor-specific subelement */ ++ ++#define P2P_SE_VS_ID_SERVICES 0x1b ++ ++ ++/* WiFi P2P IE subelement: P2P Capability (capabilities info) */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_P2P_INFO */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 dev; /* Device Capability Bitmap */ ++ uint8 group; /* Group Capability Bitmap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t; ++ ++/* P2P Capability subelement's Device Capability Bitmap bit values */ ++#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 /* Service Discovery */ ++#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 /* Client Discoverability */ ++#define P2P_CAPSE_DEV_CONCURRENT 0x4 /* Concurrent Operation */ ++#define P2P_CAPSE_DEV_INFRA_MAN 0x8 /* P2P Infrastructure Managed */ ++#define P2P_CAPSE_DEV_LIMIT 0x10 /* P2P Device Limit */ ++#define P2P_CAPSE_INVITE_PROC 0x20 /* P2P Invitation Procedure */ ++ ++/* P2P Capability subelement's Group Capability Bitmap bit values */ ++#define P2P_CAPSE_GRP_OWNER 0x1 /* P2P Group Owner */ ++#define P2P_CAPSE_PERSIST_GRP 0x2 /* Persistent P2P Group */ ++#define P2P_CAPSE_GRP_LIMIT 0x4 /* P2P Group Limit */ ++#define P2P_CAPSE_GRP_INTRA_BSS 0x8 /* Intra-BSS Distribution */ ++#define P2P_CAPSE_GRP_X_CONNECT 0x10 /* Cross Connection */ ++#define P2P_CAPSE_GRP_PERSISTENT 0x20 /* Persistent Reconnect */ ++#define P2P_CAPSE_GRP_FORMATION 0x40 /* Group Formation */ ++ ++ ++/* WiFi P2P IE subelement: Group Owner Intent */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_INTENT */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 intent; /* Intent Value 0...15 (0=legacy 15=master only) */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t; ++ ++/* WiFi P2P IE subelement: Configuration Timeout */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_CFG_TIMEOUT */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 go_tmo; /* GO config timeout in units of 10 ms */ ++ uint8 client_tmo; /* Client config timeout in units of 10 ms */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t; ++ ++/* WiFi P2P IE subelement: Listen Channel */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_listen_channel_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_CHANNEL */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 country[3]; /* Country String */ ++ uint8 op_class; /* Operating Class */ ++ uint8 channel; /* Channel */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_listen_channel_se_s wifi_p2p_listen_channel_se_t; ++ ++/* WiFi P2P IE subelement: P2P Group BSSID */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_bssid_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_GRP_BSSID */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P group bssid */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_grp_bssid_se_s wifi_p2p_grp_bssid_se_t; ++ ++/* WiFi P2P IE subelement: P2P Group ID */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_grp_id_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_GROUP_ID */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P device address */ ++ uint8 ssid[1]; /* ssid. device id. variable length */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_grp_id_se_s wifi_p2p_grp_id_se_t; ++ ++/* WiFi P2P IE subelement: P2P Interface */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_intf_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_P2P_IF */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P device address */ ++ uint8 ifaddrs; /* P2P Interface Address count */ ++ uint8 ifaddr[1][6]; /* P2P Interface Address list */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_intf_se_s wifi_p2p_intf_se_t; ++ ++/* WiFi P2P IE subelement: Status */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_STATUS */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 status; /* Status Code: P2P_STATSE_* */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t; ++ ++/* Status subelement Status Code definitions */ ++#define P2P_STATSE_SUCCESS 0 ++ /* Success */ ++#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1 ++ /* Failed, information currently unavailable */ ++#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL ++ /* Old name for above in P2P spec 1.08 and older */ ++#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2 ++ /* Failed, incompatible parameters */ ++#define P2P_STATSE_FAIL_LIMIT_REACHED 3 ++ /* Failed, limit reached */ ++#define P2P_STATSE_FAIL_INVALID_PARAMS 4 ++ /* Failed, invalid parameters */ ++#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5 ++ /* Failed, unable to accomodate request */ ++#define P2P_STATSE_FAIL_PROTO_ERROR 6 ++ /* Failed, previous protocol error or disruptive behaviour */ ++#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7 ++ /* Failed, no common channels */ ++#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8 ++ /* Failed, unknown P2P Group */ ++#define P2P_STATSE_FAIL_INTENT 9 ++ /* Failed, both peers indicated Intent 15 in GO Negotiation */ ++#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10 ++ /* Failed, incompatible provisioning method */ ++#define P2P_STATSE_FAIL_USER_REJECT 11 ++ /* Failed, rejected by user */ ++#define P2P_STATSE_SUCCESS_USER_ACCEPT 12 ++ /* Success, accepted by user */ ++ ++/* WiFi P2P IE attribute: Extended Listen Timing */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s { ++ uint8 eltId; /* ID: P2P_SEID_EXT_TIMING */ ++ uint8 len[2]; /* length not including eltId, len fields */ ++ uint8 avail[2]; /* availibility period */ ++ uint8 interval[2]; /* availibility interval */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t; ++ ++#define P2P_EXT_MIN 10 /* minimum 10ms */ ++ ++/* WiFi P2P IE subelement: Intended P2P Interface Address */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_INTINTADDR */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* intended P2P interface MAC address */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t; ++ ++/* WiFi P2P IE subelement: Channel */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_STATUS */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 band; /* Regulatory Class (band) */ ++ uint8 channel; /* Channel */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t; ++ ++ ++/* Channel Entry structure within the Channel List SE */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s { ++ uint8 band; /* Regulatory Class (band) */ ++ uint8 num_channels; /* # of channels in the channel list */ ++ uint8 channels[WL_NUMCHANNELS]; /* Channel List */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t; ++#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2 ++ ++/* WiFi P2P IE subelement: Channel List */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_CHAN_LIST */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 country[3]; /* Country String */ ++ uint8 num_entries; /* # of channel entries */ ++ wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES]; ++ /* Channel Entry List */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t; ++ ++/* WiFi Primary Device Type structure */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_pri_devtype_s { ++ uint16 cat_id; /* Category ID */ ++ uint8 OUI[3]; /* WFA OUI: 0x0050F2 */ ++ uint8 oui_type; /* WPS_OUI_TYPE */ ++ uint16 sub_cat_id; /* Sub Category ID */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_pri_devtype_s wifi_p2p_pri_devtype_t; ++ ++/* WiFi P2P Device Info Sub Element Primary Device Type Sub Category ++ * maximum values for each category ++ */ ++#define P2P_DISE_SUBCATEGORY_MINVAL 1 ++#define P2P_DISE_CATEGORY_COMPUTER 1 ++#define P2P_DISE_SUBCATEGORY_COMPUTER_MAXVAL 8 ++#define P2P_DISE_CATEGORY_INPUT_DEVICE 2 ++#define P2P_DISE_SUBCATEGORY_INPUT_DEVICE_MAXVAL 9 ++#define P2P_DISE_CATEGORY_PRINTER 3 ++#define P2P_DISE_SUBCATEGORY_PRINTER_MAXVAL 5 ++#define P2P_DISE_CATEGORY_CAMERA 4 ++#define P2P_DISE_SUBCATEGORY_CAMERA_MAXVAL 4 ++#define P2P_DISE_CATEGORY_STORAGE 5 ++#define P2P_DISE_SUBCATEGORY_STORAGE_MAXVAL 1 ++#define P2P_DISE_CATEGORY_NETWORK_INFRA 6 ++#define P2P_DISE_SUBCATEGORY_NETWORK_INFRA_MAXVAL 4 ++#define P2P_DISE_CATEGORY_DISPLAY 7 ++#define P2P_DISE_SUBCATEGORY_DISPLAY_MAXVAL 4 ++#define P2P_DISE_CATEGORY_MULTIMEDIA 8 ++#define P2P_DISE_SUBCATEGORY_MULTIMEDIA_MAXVAL 6 ++#define P2P_DISE_CATEGORY_GAMING 9 ++#define P2P_DISE_SUBCATEGORY_GAMING_MAXVAL 5 ++#define P2P_DISE_CATEGORY_TELEPHONE 10 ++#define P2P_DISE_SUBCATEGORY_TELEPHONE_MAXVAL 5 ++#define P2P_DISE_CATEGORY_AUDIO 11 ++#define P2P_DISE_SUBCATEGORY_AUDIO_MAXVAL 6 ++ ++/* WiFi P2P IE's Device Info subelement */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_DEVINFO */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mac[6]; /* P2P Device MAC address */ ++ uint16 wps_cfg_meths; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ ++ uint8 pri_devtype[8]; /* Primary Device Type */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t; ++ ++#define P2P_DEV_TYPE_LEN 8 ++ ++/* WiFi P2P IE's Group Info subelement Client Info Descriptor */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s { ++ uint8 len; ++ uint8 devaddr[ETHER_ADDR_LEN]; /* P2P Device Address */ ++ uint8 ifaddr[ETHER_ADDR_LEN]; /* P2P Interface Address */ ++ uint8 devcap; /* Device Capability */ ++ uint8 cfg_meths[2]; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */ ++ uint8 pridt[P2P_DEV_TYPE_LEN]; /* Primary Device Type */ ++ uint8 secdts; /* Number of Secondary Device Types */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t; ++ ++/* WiFi P2P IE's Device ID subelement */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s { ++ uint8 eltId; ++ uint8 len[2]; ++ struct ether_addr addr; /* P2P Device MAC address */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t; ++ ++/* WiFi P2P IE subelement: P2P Manageability */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_P2P_MGBTY */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 mg_bitmap; /* manageability bitmap */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t; ++/* mg_bitmap field bit values */ ++#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 /* AP supports Managed P2P Device */ ++ ++/* WiFi P2P IE subelement: Group Info */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_GROUP_INFO */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t; ++ ++/* WiFi IE subelement: Operating Channel */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_op_channel_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_OP_CHANNEL */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 country[3]; /* Country String */ ++ uint8 op_class; /* Operating Class */ ++ uint8 channel; /* Channel */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_op_channel_se_s wifi_p2p_op_channel_se_t; ++ ++/* WiFi IE subelement: INVITATION FLAGS */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_invite_flags_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_INVITE_FLAGS */ ++ uint8 len[2]; /* SE length not including eltId, len fields */ ++ uint8 flags; /* Flags */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_invite_flags_se_s wifi_p2p_invite_flags_se_t; ++ ++/* WiFi P2P IE subelement: Service Hash */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_serv_hash_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_SERVICE_HASH */ ++ uint8 len[2]; /* SE length not including eltId, len fields ++ * in multiple of 6 Bytes ++ */ ++ uint8 hash[1]; /* Variable length - SHA256 hash of ++ * service names (can be more than one hashes) ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_serv_hash_se_s wifi_p2p_serv_hash_se_t; ++ ++/* WiFi P2P IE subelement: Service Instance Data */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_serv_inst_data_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_SESSION */ ++ uint8 len[2]; /* SE length not including eltId, len */ ++ uint8 ssn_info[1]; /* Variable length - Session information as specified by ++ * the service layer, type matches serv. name ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_serv_inst_data_se_s wifi_p2p_serv_inst_data_se_t; ++ ++ ++/* WiFi P2P IE subelement: Connection capability */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_conn_cap_data_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_CONNECT_CAP */ ++ uint8 len[2]; /* SE length not including eltId, len */ ++ uint8 conn_cap; /* 1byte capability as specified by the ++ * service layer, valid bitmask/values ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_conn_cap_data_se_s wifi_p2p_conn_cap_data_se_t; ++ ++ ++/* WiFi P2P IE subelement: Advertisement ID */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_advt_id_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_ADVERTISE_ID */ ++ uint8 len[2]; /* SE length not including eltId, len fixed 4 Bytes */ ++ uint8 advt_id[4]; /* 4byte Advertisement ID of the peer device sent in ++ * PROV Disc in Network byte order ++ */ ++ uint8 advt_mac[6]; /* P2P device address of the service advertiser */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_advt_id_se_s wifi_p2p_advt_id_se_t; ++ ++ ++/* WiFi P2P IE subelement: Advertise Service Hash */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_adv_serv_info_s { ++ uint8 advt_id[4]; /* SE Advertise ID for the service */ ++ uint16 nw_cfg_method; /* SE Network Config method for the service */ ++ uint8 serv_name_len; /* SE length of the service name */ ++ uint8 serv_name[1]; /* Variable length service name field */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_adv_serv_info_s wifi_p2p_adv_serv_info_t; ++ ++ ++/* WiFi P2P IE subelement: Advertise Service Hash */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_advt_serv_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_ADVERTISE_SERVICE */ ++ uint8 len[2]; /* SE length not including eltId, len fields mutiple len of ++ * wifi_p2p_adv_serv_info_t entries ++ */ ++ wifi_p2p_adv_serv_info_t p_advt_serv_info[1]; /* Variable length ++ of multiple instances ++ of the advertise service info ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_advt_serv_se_s wifi_p2p_advt_serv_se_t; ++ ++ ++/* WiFi P2P IE subelement: Session ID */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_ssn_id_se_s { ++ uint8 eltId; /* SE ID: P2P_SEID_SESSION_ID */ ++ uint8 len[2]; /* SE length not including eltId, len fixed 4 Bytes */ ++ uint8 ssn_id[4]; /* 4byte Session ID of the peer device sent in ++ * PROV Disc in Network byte order ++ */ ++ uint8 ssn_mac[6]; /* P2P device address of the seeker - session mac */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_ssn_id_se_s wifi_p2p_ssn_id_se_t; ++ ++ ++#define P2P_ADVT_SERV_SE_FIXED_LEN 3 /* Includes only the element ID and len */ ++#define P2P_ADVT_SERV_INFO_FIXED_LEN 7 /* Per ADV Service Instance advt_id + ++ * nw_config_method + serv_name_len ++ */ ++ ++/* WiFi P2P Action Frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame { ++ uint8 category; /* P2P_AF_CATEGORY */ ++ uint8 OUI[3]; /* OUI - P2P_OUI */ ++ uint8 type; /* OUI Type - P2P_VER */ ++ uint8 subtype; /* OUI Subtype - P2P_AF_* */ ++ uint8 dialog_token; /* nonzero, identifies req/resp tranaction */ ++ uint8 elts[1]; /* Variable length information elements. Max size = ++ * ACTION_FRAME_SIZE - sizeof(this structure) - 1 ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t; ++#define P2P_AF_CATEGORY 0x7f ++ ++#define P2P_AF_FIXED_LEN 7 ++ ++/* WiFi P2P Action Frame OUI Subtypes */ ++#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ ++#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ ++#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ ++#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ ++ ++ ++/* WiFi P2P Public Action Frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame { ++ uint8 category; /* P2P_PUB_AF_CATEGORY */ ++ uint8 action; /* P2P_PUB_AF_ACTION */ ++ uint8 oui[3]; /* P2P_OUI */ ++ uint8 oui_type; /* OUI type - P2P_VER */ ++ uint8 subtype; /* OUI subtype - P2P_TYPE_* */ ++ uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ ++ uint8 elts[1]; /* Variable length information elements. Max size = ++ * ACTION_FRAME_SIZE - sizeof(this structure) - 1 ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t; ++#define P2P_PUB_AF_FIXED_LEN 8 ++#define P2P_PUB_AF_CATEGORY 0x04 ++#define P2P_PUB_AF_ACTION 0x09 ++ ++/* WiFi P2P Public Action Frame OUI Subtypes */ ++#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ ++#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ ++#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ ++#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ ++#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ ++#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ ++#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ ++#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ ++#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ ++#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ ++ ++/* TODO: Stop using these obsolete aliases for P2P_PAF_GON_* */ ++#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ ++#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP ++#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF ++ ++/* WiFi P2P IE subelement: Notice of Absence */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc { ++ uint8 cnt_type; /* Count/Type */ ++ uint32 duration; /* Duration */ ++ uint32 interval; /* Interval */ ++ uint32 start; /* Start Time */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t; ++ ++BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se { ++ uint8 eltId; /* Subelement ID */ ++ uint8 len[2]; /* Length */ ++ uint8 index; /* Index */ ++ uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */ ++ wifi_p2p_noa_desc_t desc[1]; /* Notice of Absence Descriptor(s) */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t; ++ ++#define P2P_NOA_SE_FIXED_LEN 5 ++ ++#define P2P_NOA_SE_MAX_DESC 2 /* max NoA descriptors in presence request */ ++ ++/* cnt_type field values */ ++#define P2P_NOA_DESC_CNT_RESERVED 0 /* reserved and should not be used */ ++#define P2P_NOA_DESC_CNT_REPEAT 255 /* continuous schedule */ ++#define P2P_NOA_DESC_TYPE_PREFERRED 1 /* preferred values */ ++#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 /* acceptable limits */ ++ ++/* ctw_ops_parms field values */ ++#define P2P_NOA_CTW_MASK 0x7f ++#define P2P_NOA_OPS_MASK 0x80 ++#define P2P_NOA_OPS_SHIFT 7 ++ ++#define P2P_CTW_MIN 10 /* minimum 10TU */ ++ ++/* ++ * P2P Service Discovery related ++ */ ++#define P2PSD_ACTION_CATEGORY 0x04 ++ /* Public action frame */ ++#define P2PSD_ACTION_ID_GAS_IREQ 0x0a ++ /* Action value for GAS Initial Request AF */ ++#define P2PSD_ACTION_ID_GAS_IRESP 0x0b ++ /* Action value for GAS Initial Response AF */ ++#define P2PSD_ACTION_ID_GAS_CREQ 0x0c ++ /* Action value for GAS Comeback Request AF */ ++#define P2PSD_ACTION_ID_GAS_CRESP 0x0d ++ /* Action value for GAS Comeback Response AF */ ++#define P2PSD_AD_EID 0x6c ++ /* Advertisement Protocol IE ID */ ++#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00 ++ /* Query Response Length Limit 7 bits plus PAME-BI 1 bit */ ++#define P2PSD_ADP_PROTO_ID 0x00 ++ /* Advertisement Protocol ID. Always 0 for P2P SD */ ++#define P2PSD_GAS_OUI P2P_OUI ++ /* WFA OUI */ ++#define P2PSD_GAS_OUI_SUBTYPE P2P_VER ++ /* OUI Subtype for GAS IE */ ++#define P2PSD_GAS_NQP_INFOID 0xDDDD ++ /* NQP Query Info ID: 56797 */ ++#define P2PSD_GAS_COMEBACKDEALY 0x00 ++ /* Not used in the Native GAS protocol */ ++ ++/* Service Protocol Type */ ++typedef enum p2psd_svc_protype { ++ SVC_RPOTYPE_ALL = 0, ++ SVC_RPOTYPE_BONJOUR = 1, ++ SVC_RPOTYPE_UPNP = 2, ++ SVC_RPOTYPE_WSD = 3, ++ SVC_RPOTYPE_WFDS = 11, ++ SVC_RPOTYPE_VENDOR = 255 ++} p2psd_svc_protype_t; ++ ++/* Service Discovery response status code */ ++typedef enum { ++ P2PSD_RESP_STATUS_SUCCESS = 0, ++ P2PSD_RESP_STATUS_PROTYPE_NA = 1, ++ P2PSD_RESP_STATUS_DATA_NA = 2, ++ P2PSD_RESP_STATUS_BAD_REQUEST = 3 ++} p2psd_resp_status_t; ++ ++/* Advertisement Protocol IE tuple field */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl { ++ uint8 llm_pamebi; /* Query Response Length Limit bit 0-6, set to 0 plus ++ * Pre-Associated Message Exchange BSSID Independent bit 7, set to 0 ++ */ ++ uint8 adp_id; /* Advertisement Protocol ID: 0 for NQP Native Query Protocol */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t; ++ ++/* Advertisement Protocol IE */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie { ++ uint8 id; /* IE ID: 0x6c - 108 */ ++ uint8 len; /* IE length */ ++ wifi_p2psd_adp_tpl_t adp_tpl; /* Advertisement Protocol Tuple field. Only one ++ * tuple is defined for P2P Service Discovery ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t; ++ ++/* NQP Vendor-specific Content */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc { ++ uint8 oui_subtype; /* OUI Subtype: 0x09 */ ++ uint16 svc_updi; /* Service Update Indicator */ ++ uint8 svc_tlvs[1]; /* wifi_p2psd_qreq_tlv_t type for service request, ++ * wifi_p2psd_qresp_tlv_t type for service response ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t; ++ ++/* Service Request TLV */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv { ++ uint16 len; /* Length: 5 plus size of Query Data */ ++ uint8 svc_prot; /* Service Protocol Type */ ++ uint8 svc_tscid; /* Service Transaction ID */ ++ uint8 query_data[1]; /* Query Data, passed in from above Layer 2 */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t; ++ ++/* Query Request Frame, defined in generic format, instead of NQP specific */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame { ++ uint16 info_id; /* Info ID: 0xDDDD */ ++ uint16 len; /* Length of service request TLV, 5 plus the size of request data */ ++ uint8 oui[3]; /* WFA OUI: 0x0050F2 */ ++ uint8 qreq_vsc[1]; /* Vendor-specific Content: wifi_p2psd_nqp_query_vsc_t type for NQP */ ++ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t; ++ ++/* GAS Initial Request AF body, "elts" in wifi_p2p_pub_act_frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame { ++ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ ++ uint16 qreq_len; /* Query Request Length */ ++ uint8 qreq_frm[1]; /* Query Request Frame wifi_p2psd_qreq_frame_t */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t; ++ ++/* Service Response TLV */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv { ++ uint16 len; /* Length: 5 plus size of Query Data */ ++ uint8 svc_prot; /* Service Protocol Type */ ++ uint8 svc_tscid; /* Service Transaction ID */ ++ uint8 status; /* Value defined in Table 57 of P2P spec. */ ++ uint8 query_data[1]; /* Response Data, passed in from above Layer 2 */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t; ++ ++/* Query Response Frame, defined in generic format, instead of NQP specific */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame { ++ uint16 info_id; /* Info ID: 0xDDDD */ ++ uint16 len; /* Lenth of service response TLV, 6 plus the size of resp data */ ++ uint8 oui[3]; /* WFA OUI: 0x0050F2 */ ++ uint8 qresp_vsc[1]; /* Vendor-specific Content: wifi_p2psd_qresp_tlv_t type for NQP */ ++ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t; ++ ++/* GAS Initial Response AF body, "elts" in wifi_p2p_pub_act_frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame { ++ uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ ++ uint16 cb_delay; /* GAS Comeback Delay */ ++ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ ++ uint16 qresp_len; /* Query Response Length */ ++ uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t; ++ ++/* GAS Comeback Response AF body, "elts" in wifi_p2p_pub_act_frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame { ++ uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */ ++ uint8 fragment_id; /* Fragmentation ID */ ++ uint16 cb_delay; /* GAS Comeback Delay */ ++ wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */ ++ uint16 qresp_len; /* Query Response Length */ ++ uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t; ++ ++/* Wi-Fi GAS Public Action Frame */ ++BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame { ++ uint8 category; /* 0x04 Public Action Frame */ ++ uint8 action; /* 0x6c Advertisement Protocol */ ++ uint8 dialog_token; /* nonzero, identifies req/rsp transaction */ ++ uint8 query_data[1]; /* Query Data. wifi_p2psd_gas_ireq_frame_t ++ * or wifi_p2psd_gas_iresp_frame_t format ++ */ ++} BWL_POST_PACKED_STRUCT; ++typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t; ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _P2P_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/packed_section_end.h b/module_drivers/drivers/net/wireless/bcmdhd/include/packed_section_end.h +new file mode 100644 +index 000000000..4827c709a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/packed_section_end.h +@@ -0,0 +1,63 @@ ++/* ++ * Declare directives for structure packing. No padding will be provided ++ * between the members of packed structures, and therefore, there is no ++ * guarantee that structure members will be aligned. ++ * ++ * Declaring packed structures is compiler specific. In order to handle all ++ * cases, packed structures should be delared as: ++ * ++ * #include ++ * ++ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { ++ * some_struct_members; ++ * } BWL_POST_PACKED_STRUCT foobar_t; ++ * ++ * #include ++ * ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: packed_section_end.h 514727 2014-11-12 03:02:48Z $ ++ */ ++ ++ ++/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h ++ * and undefined in packed_section_end.h. If it is NOT defined at this ++ * point, then there is a missing include of packed_section_start.h. ++ */ ++#ifdef BWL_PACKED_SECTION ++ #undef BWL_PACKED_SECTION ++#else ++ #error "BWL_PACKED_SECTION is NOT defined!" ++#endif ++ ++ ++ ++ ++/* Compiler-specific directives for structure packing are declared in ++ * packed_section_start.h. This marks the end of the structure packing section, ++ * so, undef them here. ++ */ ++#undef BWL_PRE_PACKED_STRUCT ++#undef BWL_POST_PACKED_STRUCT +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/packed_section_start.h b/module_drivers/drivers/net/wireless/bcmdhd/include/packed_section_start.h +new file mode 100644 +index 000000000..9beb45d5e +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/packed_section_start.h +@@ -0,0 +1,67 @@ ++/* ++ * Declare directives for structure packing. No padding will be provided ++ * between the members of packed structures, and therefore, there is no ++ * guarantee that structure members will be aligned. ++ * ++ * Declaring packed structures is compiler specific. In order to handle all ++ * cases, packed structures should be delared as: ++ * ++ * #include ++ * ++ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t { ++ * some_struct_members; ++ * } BWL_POST_PACKED_STRUCT foobar_t; ++ * ++ * #include ++ * ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: packed_section_start.h 514727 2014-11-12 03:02:48Z $ ++ */ ++ ++ ++/* Error check - BWL_PACKED_SECTION is defined in packed_section_start.h ++ * and undefined in packed_section_end.h. If it is already defined at this ++ * point, then there is a missing include of packed_section_end.h. ++ */ ++#ifdef BWL_PACKED_SECTION ++ #error "BWL_PACKED_SECTION is already defined!" ++#else ++ #define BWL_PACKED_SECTION ++#endif ++ ++ ++ ++ ++/* Declare compiler-specific directives for structure packing. */ ++#if defined(__GNUC__) || defined(__lint) ++ #define BWL_PRE_PACKED_STRUCT ++ #define BWL_POST_PACKED_STRUCT __attribute__ ((packed)) ++#elif defined(__CC_ARM) ++ #define BWL_PRE_PACKED_STRUCT __packed ++ #define BWL_POST_PACKED_STRUCT ++#else ++ #error "Unknown compiler!" ++#endif +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/pcicfg.h b/module_drivers/drivers/net/wireless/bcmdhd/include/pcicfg.h +new file mode 100644 +index 000000000..98f22c3df +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/pcicfg.h +@@ -0,0 +1,330 @@ ++/* ++ * pcicfg.h: PCI configuration constants and structures. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: pcicfg.h 621340 2016-02-25 12:26:40Z $ ++ */ ++ ++#ifndef _h_pcicfg_ ++#define _h_pcicfg_ ++ ++ ++/* pci config status reg has a bit to indicate that capability ptr is present */ ++ ++#define PCI_CAPPTR_PRESENT 0x0010 ++ ++/* A structure for the config registers is nice, but in most ++ * systems the config space is not memory mapped, so we need ++ * field offsetts. :-( ++ */ ++#define PCI_CFG_VID 0 ++#define PCI_CFG_DID 2 ++#define PCI_CFG_CMD 4 ++#define PCI_CFG_STAT 6 ++#define PCI_CFG_REV 8 ++#define PCI_CFG_PROGIF 9 ++#define PCI_CFG_SUBCL 0xa ++#define PCI_CFG_BASECL 0xb ++#define PCI_CFG_CLSZ 0xc ++#define PCI_CFG_LATTIM 0xd ++#define PCI_CFG_HDR 0xe ++#define PCI_CFG_BIST 0xf ++#define PCI_CFG_BAR0 0x10 ++/* ++* TODO: PCI_CFG_BAR1 is wrongly defined to be 0x14 whereas it should be ++* 0x18 as per the PCIe full dongle spec. Need to modify the values below ++* correctly at a later point of time ++*/ ++#ifdef DHD_EFI ++#define PCI_CFG_BAR1 0x18 ++#else ++#define PCI_CFG_BAR1 0x14 ++#endif /* DHD_EFI */ ++#define PCI_CFG_BAR2 0x18 ++#define PCI_CFG_BAR3 0x1c ++#define PCI_CFG_BAR4 0x20 ++#define PCI_CFG_BAR5 0x24 ++#define PCI_CFG_CIS 0x28 ++#define PCI_CFG_SVID 0x2c ++#define PCI_CFG_SSID 0x2e ++#define PCI_CFG_ROMBAR 0x30 ++#define PCI_CFG_CAPPTR 0x34 ++#define PCI_CFG_INT 0x3c ++#define PCI_CFG_PIN 0x3d ++#define PCI_CFG_MINGNT 0x3e ++#define PCI_CFG_MAXLAT 0x3f ++#define PCI_CFG_DEVCTRL 0xd8 ++#define PCI_CFG_TLCNTRL_5 0x814 ++ ++ ++/* PCI CAPABILITY DEFINES */ ++#define PCI_CAP_POWERMGMTCAP_ID 0x01 ++#define PCI_CAP_MSICAP_ID 0x05 ++#define PCI_CAP_VENDSPEC_ID 0x09 ++#define PCI_CAP_PCIECAP_ID 0x10 ++ ++/* Data structure to define the Message Signalled Interrupt facility ++ * Valid for PCI and PCIE configurations ++ */ ++typedef struct _pciconfig_cap_msi { ++ uint8 capID; ++ uint8 nextptr; ++ uint16 msgctrl; ++ uint32 msgaddr; ++} pciconfig_cap_msi; ++#define MSI_ENABLE 0x1 /* bit 0 of msgctrl */ ++ ++/* Data structure to define the Power managment facility ++ * Valid for PCI and PCIE configurations ++ */ ++typedef struct _pciconfig_cap_pwrmgmt { ++ uint8 capID; ++ uint8 nextptr; ++ uint16 pme_cap; ++ uint16 pme_sts_ctrl; ++ uint8 pme_bridge_ext; ++ uint8 data; ++} pciconfig_cap_pwrmgmt; ++ ++#define PME_CAP_PM_STATES (0x1f << 27) /* Bits 31:27 states that can generate PME */ ++#define PME_CSR_OFFSET 0x4 /* 4-bytes offset */ ++#define PME_CSR_PME_EN (1 << 8) /* Bit 8 Enable generating of PME */ ++#define PME_CSR_PME_STAT (1 << 15) /* Bit 15 PME got asserted */ ++ ++/* Data structure to define the PCIE capability */ ++typedef struct _pciconfig_cap_pcie { ++ uint8 capID; ++ uint8 nextptr; ++ uint16 pcie_cap; ++ uint32 dev_cap; ++ uint16 dev_ctrl; ++ uint16 dev_status; ++ uint32 link_cap; ++ uint16 link_ctrl; ++ uint16 link_status; ++ uint32 slot_cap; ++ uint16 slot_ctrl; ++ uint16 slot_status; ++ uint16 root_ctrl; ++ uint16 root_cap; ++ uint32 root_status; ++} pciconfig_cap_pcie; ++ ++/* PCIE Enhanced CAPABILITY DEFINES */ ++#define PCIE_EXTCFG_OFFSET 0x100 ++#define PCIE_ADVERRREP_CAPID 0x0001 ++#define PCIE_VC_CAPID 0x0002 ++#define PCIE_DEVSNUM_CAPID 0x0003 ++#define PCIE_PWRBUDGET_CAPID 0x0004 ++ ++/* PCIE Extended configuration */ ++#define PCIE_ADV_CORR_ERR_MASK 0x114 ++#define CORR_ERR_RE (1 << 0) /* Receiver */ ++#define CORR_ERR_BT (1 << 6) /* Bad TLP */ ++#define CORR_ERR_BD (1 << 7) /* Bad DLLP */ ++#define CORR_ERR_RR (1 << 8) /* REPLAY_NUM rollover */ ++#define CORR_ERR_RT (1 << 12) /* Reply timer timeout */ ++#define ALL_CORR_ERRORS (CORR_ERR_RE | CORR_ERR_BT | CORR_ERR_BD | \ ++ CORR_ERR_RR | CORR_ERR_RT) ++ ++/* PCIE Root Control Register bits (Host mode only) */ ++#define PCIE_RC_CORR_SERR_EN 0x0001 ++#define PCIE_RC_NONFATAL_SERR_EN 0x0002 ++#define PCIE_RC_FATAL_SERR_EN 0x0004 ++#define PCIE_RC_PME_INT_EN 0x0008 ++#define PCIE_RC_CRS_EN 0x0010 ++ ++/* PCIE Root Capability Register bits (Host mode only) */ ++#define PCIE_RC_CRS_VISIBILITY 0x0001 ++ ++/* Header to define the PCIE specific capabilities in the extended config space */ ++typedef struct _pcie_enhanced_caphdr { ++ uint16 capID; ++ uint16 cap_ver : 4; ++ uint16 next_ptr : 12; ++} pcie_enhanced_caphdr; ++ ++ ++#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */ ++#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */ ++#define PCI_SPROM_CONTROL 0x88 /* sprom property control */ ++#define PCI_BAR1_CONTROL 0x8c /* BAR1 region burst control */ ++#define PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */ ++#define PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */ ++#define PCI_TO_SB_MB 0x98 /* signal backplane interrupts */ ++#define PCI_BACKPLANE_ADDR 0xa0 /* address an arbitrary location on the system backplane */ ++#define PCI_BACKPLANE_DATA 0xa4 /* data at the location specified by above address */ ++#define PCI_CLK_CTL_ST 0xa8 /* pci config space clock control/status (>=rev14) */ ++#define PCI_BAR0_WIN2 0xac /* backplane addres space accessed by second 4KB of BAR0 */ ++#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */ ++#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */ ++#define PCIE_CFG_DEVICE_CONTROL 0xb4 /* 0xb4 is used as device control in PCIE devices */ ++#define PCIE_DC_AER_CORR_EN (1u << 0u) ++#define PCIE_DC_AER_NON_FATAL_EN (1u << 1u) ++#define PCIE_DC_AER_FATAL_EN (1u << 2u) ++#define PCIE_DC_AER_UNSUP_EN (1u << 3u) ++ ++#define PCI_BAR0_WIN2_OFFSET 0x1000u ++#define PCIE2_BAR0_CORE2_WIN2_OFFSET 0x5000u ++ ++#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */ ++#define PCI_L1SS_CTRL2 0x24c /* The L1 PM Substates Control register */ ++ ++/* Private Registers */ ++#define PCI_STAT_CTRL 0xa80 ++#define PCI_L0_EVENTCNT 0xa84 ++#define PCI_L0_STATETMR 0xa88 ++#define PCI_L1_EVENTCNT 0xa8c ++#define PCI_L1_STATETMR 0xa90 ++#define PCI_L1_1_EVENTCNT 0xa94 ++#define PCI_L1_1_STATETMR 0xa98 ++#define PCI_L1_2_EVENTCNT 0xa9c ++#define PCI_L1_2_STATETMR 0xaa0 ++#define PCI_L2_EVENTCNT 0xaa4 ++#define PCI_L2_STATETMR 0xaa8 ++ ++#define PCI_LINK_STATUS 0x4dc ++#define PCI_LINK_SPEED_MASK (15u << 0u) ++#define PCI_LINK_SPEED_SHIFT (0) ++#define PCIE_LNK_SPEED_GEN1 0x1 ++#define PCIE_LNK_SPEED_GEN2 0x2 ++#define PCIE_LNK_SPEED_GEN3 0x3 ++ ++#define PCI_PL_SPARE 0x1808 /* Config to Increase external clkreq deasserted minimum time */ ++#define PCI_CONFIG_EXT_CLK_MIN_TIME_MASK (1u << 31u) ++#define PCI_CONFIG_EXT_CLK_MIN_TIME_SHIFT (31) ++ ++#define PCI_PMCR_REFUP 0x1814 /* Trefup time */ ++#define PCI_PMCR_REFUP_EXT 0x1818 /* Trefup extend Max */ ++#define PCI_TPOWER_SCALE_MASK 0x3 ++#define PCI_TPOWER_SCALE_SHIFT 3 /* 0:1 is scale and 2 is rsvd */ ++ ++ ++#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) /* bar0 + 2K accesses sprom shadow (in pci core) */ ++#define PCI_BAR0_SPROM_OFFSET (4 * 1024) /* bar0 + 4K accesses external sprom */ ++#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) /* bar0 + 6K accesses pci core registers */ ++#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) /* pci core SB registers are at the end of the ++ * 8KB window, so their address is the "regular" ++ * address plus 4K ++ */ ++/* ++ * PCIE GEN2 changed some of the above locations for ++ * Bar0WrapperBase, SecondaryBAR0Window and SecondaryBAR0WrapperBase ++ * BAR0 maps 32K of register space ++*/ ++#define PCIE2_BAR0_WIN2 0x70 /* backplane addres space accessed by second 4KB of BAR0 */ ++#define PCIE2_BAR0_CORE2_WIN 0x74 /* backplane addres space accessed by second 4KB of BAR0 */ ++#define PCIE2_BAR0_CORE2_WIN2 0x78 /* backplane addres space accessed by second 4KB of BAR0 */ ++ ++#define PCI_BAR0_WIN2_OFFSET 0x1000u ++#define PCI_CORE_ENUM_OFFSET 0x2000u ++#define PCI_CC_CORE_ENUM_OFFSET 0x3000u ++#define PCI_SEC_BAR0_WIN_OFFSET 0x4000u ++#define PCI_SEC_BAR0_WRAP_OFFSET 0x5000u ++#define PCI_CORE_ENUM2_OFFSET 0x6000u ++#define PCI_CC_CORE_ENUM2_OFFSET 0x7000u ++#define PCI_LAST_OFFSET 0x8000u ++ ++#define PCI_BAR0_WINSZ (16 * 1024) /* bar0 window size Match with corerev 13 */ ++/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */ ++#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) /* bar0 + 8K accesses pci/pcie core registers */ ++#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) /* bar0 + 12K accesses chipc core registers */ ++#define PCI_16KBB0_WINSZ (16 * 1024) /* bar0 window size */ ++#define PCI_SECOND_BAR0_OFFSET (16 * 1024) /* secondary bar 0 window */ ++ ++/* On AI chips we have a second window to map DMP regs are mapped: */ ++#define PCI_16KB0_WIN2_OFFSET (4 * 1024) /* bar0 + 4K is "Window 2" */ ++ ++/* PCI_INT_STATUS */ ++#define PCI_SBIM_STATUS_SERR 0x4 /* backplane SBErr interrupt status */ ++ ++/* PCI_INT_MASK */ ++#define PCI_SBIM_SHIFT 8 /* backplane core interrupt mask bits offset */ ++#define PCI_SBIM_MASK 0xff00 /* backplane core interrupt mask */ ++#define PCI_SBIM_MASK_SERR 0x4 /* backplane SBErr interrupt mask */ ++#define PCI_CTO_INT_SHIFT 16 /* backplane SBErr interrupt mask */ ++#define PCI_CTO_INT_MASK (1 << PCI_CTO_INT_SHIFT) /* backplane SBErr interrupt mask */ ++ ++/* PCI_SPROM_CONTROL */ ++#define SPROM_SZ_MSK 0x02 /* SPROM Size Mask */ ++#define SPROM_LOCKED 0x08 /* SPROM Locked */ ++#define SPROM_BLANK 0x04 /* indicating a blank SPROM */ ++#define SPROM_WRITEEN 0x10 /* SPROM write enable */ ++#define SPROM_BOOTROM_WE 0x20 /* external bootrom write enable */ ++#define SPROM_BACKPLANE_EN 0x40 /* Enable indirect backplane access */ ++#define SPROM_OTPIN_USE 0x80 /* device OTP In use */ ++#define SPROM_CFG_TO_SB_RST 0x400 /* backplane reset */ ++ ++/* Bits in PCI command and status regs */ ++#define PCI_CMD_IO 0x00000001 /* I/O enable */ ++#define PCI_CMD_MEMORY 0x00000002 /* Memory enable */ ++#define PCI_CMD_MASTER 0x00000004 /* Master enable */ ++#define PCI_CMD_SPECIAL 0x00000008 /* Special cycles enable */ ++#define PCI_CMD_INVALIDATE 0x00000010 /* Invalidate? */ ++#define PCI_CMD_VGA_PAL 0x00000040 /* VGA Palate */ ++#define PCI_STAT_TA 0x08000000 /* target abort status */ ++ ++/* Header types */ ++#define PCI_HEADER_MULTI 0x80 ++#define PCI_HEADER_MASK 0x7f ++typedef enum { ++ PCI_HEADER_NORMAL, ++ PCI_HEADER_BRIDGE, ++ PCI_HEADER_CARDBUS ++} pci_header_types; ++ ++#define PCI_CONFIG_SPACE_SIZE 256 ++ ++#define DWORD_ALIGN(x) (x & ~(0x03)) ++#define BYTE_POS(x) (x & 0x3) ++#define WORD_POS(x) (x & 0x1) ++ ++#define BYTE_SHIFT(x) (8 * BYTE_POS(x)) ++#define WORD_SHIFT(x) (16 * WORD_POS(x)) ++ ++#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF) ++#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF) ++ ++#define read_pci_cfg_byte(a) \ ++ (BYTE_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xff) ++ ++#define read_pci_cfg_word(a) \ ++ (WORD_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xffff) ++ ++#define write_pci_cfg_byte(a, val) do { \ ++ uint32 tmpval; \ ++ tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFF << BYTE_POS(a)) | \ ++ val << BYTE_POS(a); \ ++ OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \ ++ } while (0) ++ ++#define write_pci_cfg_word(a, val) do { \ ++ uint32 tmpval; \ ++ tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFFFF << WORD_POS(a)) | \ ++ val << WORD_POS(a); \ ++ OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \ ++ } while (0) ++ ++#endif /* _h_pcicfg_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/pcie_core.h b/module_drivers/drivers/net/wireless/bcmdhd/include/pcie_core.h +new file mode 100644 +index 000000000..463561d08 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/pcie_core.h +@@ -0,0 +1,959 @@ ++/* ++ * BCM43XX PCIE core hardware definitions. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: pcie_core.h 673814 2016-12-05 06:10:24Z $ ++ */ ++#ifndef _PCIE_CORE_H ++#define _PCIE_CORE_H ++ ++#include ++#include ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif ++ ++/* PCIE Enumeration space offsets */ ++#define PCIE_CORE_CONFIG_OFFSET 0x0 ++#define PCIE_FUNC0_CONFIG_OFFSET 0x400 ++#define PCIE_FUNC1_CONFIG_OFFSET 0x500 ++#define PCIE_FUNC2_CONFIG_OFFSET 0x600 ++#define PCIE_FUNC3_CONFIG_OFFSET 0x700 ++#define PCIE_SPROM_SHADOW_OFFSET 0x800 ++#define PCIE_SBCONFIG_OFFSET 0xE00 ++ ++ ++#define PCIEDEV_MAX_DMAS 4 ++ ++/* PCIE Bar0 Address Mapping. Each function maps 16KB config space */ ++#define PCIE_DEV_BAR0_SIZE 0x4000 ++#define PCIE_BAR0_WINMAPCORE_OFFSET 0x0 ++#define PCIE_BAR0_EXTSPROM_OFFSET 0x1000 ++#define PCIE_BAR0_PCIECORE_OFFSET 0x2000 ++#define PCIE_BAR0_CCCOREREG_OFFSET 0x3000 ++ ++/* different register spaces to access thr'u pcie indirect access */ ++#define PCIE_CONFIGREGS 1 /* Access to config space */ ++#define PCIE_PCIEREGS 2 /* Access to pcie registers */ ++ ++#define PCIEDEV_HOSTADDR_MAP_BASE 0x8000000 ++#define PCIEDEV_HOSTADDR_MAP_WIN_MASK 0xFC000000 ++ ++/* dma regs to control the flow between host2dev and dev2host */ ++typedef volatile struct pcie_devdmaregs { ++ dma64regs_t tx; ++ uint32 PAD[2]; ++ dma64regs_t rx; ++ uint32 PAD[2]; ++} pcie_devdmaregs_t; ++ ++#define PCIE_DB_HOST2DEV_0 0x1 ++#define PCIE_DB_HOST2DEV_1 0x2 ++#define PCIE_DB_DEV2HOST_0 0x3 ++#define PCIE_DB_DEV2HOST_1 0x4 ++ ++/* door bell register sets */ ++typedef struct pcie_doorbell { ++ uint32 host2dev_0; ++ uint32 host2dev_1; ++ uint32 dev2host_0; ++ uint32 dev2host_1; ++} pcie_doorbell_t; ++ ++/* Flow Ring Manager */ ++#define IFRM_FR_IDX_MAX 256 ++#define IFRM_FR_GID_MAX 4 ++#define IFRM_FR_DEV_MAX 8 ++#define IFRM_FR_TID_MAX 8 ++#define IFRM_FR_DEV_VALID 2 ++ ++#define IFRM_VEC_REG_BITS 32 ++ ++#define IFRM_FR_PER_VECREG 4 ++#define IFRM_FR_PER_VECREG_SHIFT 2 ++#define IFRM_FR_PER_VECREG_MASK ((0x1 << IFRM_FR_PER_VECREG_SHIFT) - 1) ++ ++#define IFRM_VEC_BITS_PER_FR (IFRM_VEC_REG_BITS/IFRM_FR_PER_VECREG) ++ ++/* IFRM_DEV_0 : d11AC, IFRM_DEV_1 : d11AD */ ++#define IFRM_DEV_0 0 ++#define IFRM_DEV_1 1 ++ ++#define IFRM_FR_GID_0 0 ++#define IFRM_FR_GID_1 1 ++#define IFRM_FR_GID_2 2 ++#define IFRM_FR_GID_3 3 ++ ++#define IFRM_TIDMASK 0xffffffff ++ ++/* ifrm_ctrlst register */ ++#define IFRM_EN (1<<0) ++#define IFRM_BUFF_INIT_DONE (1<<1) ++#define IFRM_COMPARE_EN0 (1<<4) ++#define IFRM_COMPARE_EN1 (1<<5) ++#define IFRM_COMPARE_EN2 (1<<6) ++#define IFRM_COMPARE_EN3 (1<<7) ++#define IFRM_INIT_DV0 (1<<8) ++#define IFRM_INIT_DV1 (1<<9) ++#define IFRM_INIT_DV2 (1<<10) ++#define IFRM_INIT_DV3 (1<<11) ++ ++/* ifrm_msk_arr.addr, ifrm_tid_arr.addr register */ ++#define IFRM_ADDR_SHIFT 0 ++#define IFRM_FRG_ID_SHIFT 8 ++ ++/* ifrm_vec.diff_lat register */ ++#define IFRM_DV_LAT (1<<0) ++#define IFRM_DV_LAT_DONE (1<<1) ++#define IFRM_SDV_OFFSET_SHIFT 4 ++#define IFRM_SDV_FRGID_SHIFT 8 ++#define IFRM_VECSTAT_MASK 0x3 ++#define IFRM_VEC_MASK 0xff ++ ++/* idma frm array */ ++typedef struct pcie_ifrm_array { ++ uint32 addr; ++ uint32 data; ++} pcie_ifrm_array_t; ++ ++/* idma frm vector */ ++typedef struct pcie_ifrm_vector { ++ uint32 diff_lat; ++ uint32 sav_tid; ++ uint32 sav_diff; ++ uint32 PAD[1]; ++} pcie_ifrm_vector_t; ++ ++/* idma frm interrupt */ ++typedef struct pcie_ifrm_intr { ++ uint32 intstat; ++ uint32 intmask; ++} pcie_ifrm_intr_t; ++ ++/* SB side: PCIE core and host control registers */ ++typedef volatile struct sbpcieregs { ++ uint32 control; /* host mode only */ ++ uint32 iocstatus; /* PCIE2: iostatus */ ++ uint32 PAD[1]; ++ uint32 biststatus; /* bist Status: 0x00C */ ++ uint32 gpiosel; /* PCIE gpio sel: 0x010 */ ++ uint32 gpioouten; /* PCIE gpio outen: 0x14 */ ++ uint32 PAD[2]; ++ uint32 intstatus; /* Interrupt status: 0x20 */ ++ uint32 intmask; /* Interrupt mask: 0x24 */ ++ uint32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */ ++ uint32 obffcontrol; /* PCIE2: 0x2C */ ++ uint32 obffintstatus; /* PCIE2: 0x30 */ ++ uint32 obffdatastatus; /* PCIE2: 0x34 */ ++ uint32 PAD[1]; ++ uint32 ctoctrl; /* PCIE2: 0x3C */ ++ uint32 errlog; /* PCIE2: 0x40 */ ++ uint32 errlogaddr; /* PCIE2: 0x44 */ ++ uint32 mailboxint; /* PCIE2: 0x48 */ ++ uint32 mailboxintmsk; /* PCIE2: 0x4c */ ++ uint32 ltrspacing; /* PCIE2: 0x50 */ ++ uint32 ltrhysteresiscnt; /* PCIE2: 0x54 */ ++ uint32 msivectorassign; /* PCIE2: 0x58 */ ++ uint32 intmask2; /* PCIE2: 0x5C */ ++ uint32 PAD[40]; ++ uint32 sbtopcie0; /* sb to pcie translation 0: 0x100 */ ++ uint32 sbtopcie1; /* sb to pcie translation 1: 0x104 */ ++ uint32 sbtopcie2; /* sb to pcie translation 2: 0x108 */ ++ uint32 PAD[5]; ++ ++ /* pcie core supports in direct access to config space */ ++ uint32 configaddr; /* pcie config space access: Address field: 0x120 */ ++ uint32 configdata; /* pcie config space access: Data field: 0x124 */ ++ union { ++ struct { ++ /* mdio access to serdes */ ++ uint32 mdiocontrol; /* controls the mdio access: 0x128 */ ++ uint32 mdiodata; /* Data to the mdio access: 0x12c */ ++ /* pcie protocol phy/dllp/tlp register indirect access mechanism */ ++ uint32 pcieindaddr; /* indirect access to the internal register: 0x130 */ ++ uint32 pcieinddata; /* Data to/from the internal regsiter: 0x134 */ ++ uint32 clkreqenctrl; /* >= rev 6, Clkreq rdma control : 0x138 */ ++ uint32 PAD[177]; ++ /* 0x400 - 0x7FF, PCIE Cfg Space, note: not used anymore in PcieGen2 */ ++ uint32 pciecfg[4][64]; ++ } pcie1; ++ struct { ++ /* mdio access to serdes */ ++ uint32 mdiocontrol; /* controls the mdio access: 0x128 */ ++ uint32 mdiowrdata; /* write data to mdio 0x12C */ ++ uint32 mdiorddata; /* read data to mdio 0x130 */ ++ uint32 PAD[3]; /* 0x134-0x138-0x13c */ ++ /* door bell registers available from gen2 rev5 onwards */ ++ pcie_doorbell_t dbls[PCIEDEV_MAX_DMAS]; /* 0x140 - 0x17F */ ++ uint32 dataintf; /* 0x180 */ ++ uint32 PAD[1]; /* 0x184 */ ++ uint32 d2h_intrlazy_0; /* 0x188 */ ++ uint32 h2d_intrlazy_0; /* 0x18c */ ++ uint32 h2d_intstat_0; /* 0x190 */ ++ uint32 h2d_intmask_0; /* 0x194 */ ++ uint32 d2h_intstat_0; /* 0x198 */ ++ uint32 d2h_intmask_0; /* 0x19c */ ++ uint32 ltr_state; /* 0x1A0 */ ++ uint32 pwr_int_status; /* 0x1A4 */ ++ uint32 pwr_int_mask; /* 0x1A8 */ ++ uint32 pme_source; /* 0x1AC */ ++ uint32 err_hdr_logreg1; /* 0x1B0 */ ++ uint32 err_hdr_logreg2; /* 0x1B4 */ ++ uint32 err_hdr_logreg3; /* 0x1B8 */ ++ uint32 err_hdr_logreg4; /* 0x1BC */ ++ uint32 err_code_logreg; /* 0x1C0 */ ++ uint32 PAD[7]; /* 0x1C4 - 0x1DF */ ++ uint32 clk_ctl_st; /* 0x1E0 */ ++ uint32 PAD[1]; /* 0x1E4 */ ++ uint32 powerctl; /* 0x1E8 */ ++ uint32 PAD[5]; /* 0x1EC - 0x1FF */ ++ pcie_devdmaregs_t h2d0_dmaregs; /* 0x200 - 0x23c */ ++ pcie_devdmaregs_t d2h0_dmaregs; /* 0x240 - 0x27c */ ++ pcie_devdmaregs_t h2d1_dmaregs; /* 0x280 - 0x2bc */ ++ pcie_devdmaregs_t d2h1_dmaregs; /* 0x2c0 - 0x2fc */ ++ pcie_devdmaregs_t h2d2_dmaregs; /* 0x300 - 0x33c */ ++ pcie_devdmaregs_t d2h2_dmaregs; /* 0x340 - 0x37c */ ++ pcie_devdmaregs_t h2d3_dmaregs; /* 0x380 - 0x3bc */ ++ pcie_devdmaregs_t d2h3_dmaregs; /* 0x3c0 - 0x3fc */ ++ uint32 d2h_intrlazy_1; /* 0x400 */ ++ uint32 h2d_intrlazy_1; /* 0x404 */ ++ uint32 h2d_intstat_1; /* 0x408 */ ++ uint32 h2d_intmask_1; /* 0x40c */ ++ uint32 d2h_intstat_1; /* 0x410 */ ++ uint32 d2h_intmask_1; /* 0x414 */ ++ uint32 PAD[2]; /* 0x418 - 0x41C */ ++ uint32 d2h_intrlazy_2; /* 0x420 */ ++ uint32 h2d_intrlazy_2; /* 0x424 */ ++ uint32 h2d_intstat_2; /* 0x428 */ ++ uint32 h2d_intmask_2; /* 0x42c */ ++ uint32 d2h_intstat_2; /* 0x430 */ ++ uint32 d2h_intmask_2; /* 0x434 */ ++ uint32 PAD[10]; /* 0x438 - 0x45F */ ++ uint32 ifrm_ctrlst; /* 0x460 */ ++ uint32 PAD[1]; /* 0x464 */ ++ pcie_ifrm_array_t ifrm_msk_arr; /* 0x468 - 0x46F */ ++ pcie_ifrm_array_t ifrm_tid_arr[IFRM_FR_DEV_VALID]; ++ /* 0x470 - 0x47F */ ++ pcie_ifrm_vector_t ifrm_vec[IFRM_FR_DEV_MAX]; ++ /* 0x480 - 0x4FF */ ++ pcie_ifrm_intr_t ifrm_intr[IFRM_FR_DEV_MAX]; ++ /* 0x500 - 0x53F */ ++ uint32 PAD[48]; /* 0x540 - 0x5FF */ ++ uint32 PAD[2][64]; /* 0x600 - 0x7FF */ ++ } pcie2; ++ } u; ++ uint16 sprom[64]; /* SPROM shadow Area : 0x800 - 0x880 */ ++ uint32 PAD[96]; /* 0x880 - 0x9FF */ ++ /* direct memory access (pcie2 rev19 and after) : 0xA00 - 0xAFF */ ++ uint32 PAD[16]; /* 0xA00 - 0xA3F */ ++ uint32 dm_errlog; /* 0xA40 */ ++ uint32 dm_erraddr; /* 0xA44 */ ++ uint32 PAD[37]; /* 0xA48 - 0xADC */ ++ uint32 dm_clk_ctl_st; /* 0xAE0 */ ++ uint32 PAD[1]; /* 0xAE4 */ ++ uint32 dm_powerctl; /* 0xAE8 */ ++} sbpcieregs_t; ++ ++#define PCIE_CFG_DA_OFFSET 0x400 /* direct access register offset for configuration space */ ++ ++/* PCI control */ ++#define PCIE_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */ ++#define PCIE_RST 0x02 /* Value driven out to pin */ ++#define PCIE_SPERST 0x04 /* SurvivePeRst */ ++#define PCIE_FORCECFGCLKON_ALP 0x08 ++#define PCIE_DISABLE_L1CLK_GATING 0x10 ++#define PCIE_DLYPERST 0x100 /* Delay PeRst to CoE Core */ ++#define PCIE_DISSPROMLD 0x200 /* DisableSpromLoadOnPerst */ ++#define PCIE_WakeModeL2 0x1000 /* Wake on L2 */ ++#define PCIE_MULTIMSI_EN 0x2000 /* enable multi-vector MSI messages */ ++#define PCIE_PipeIddqDisable0 0x8000 /* Disable assertion of pcie_pipe_iddq during L1.2 and L2 */ ++#define PCIE_PipeIddqDisable1 0x10000 /* Disable assertion of pcie_pipe_iddq during L2 */ ++#define PCIE_MSI_B2B_EN 0x100000 /* enable back-to-back MSI messages */ ++#define PCIE_MSI_FIFO_CLEAR 0x200000 /* reset MSI FIFO */ ++#define PCIE_IDMA_MODE_EN 0x800000 /* implicit M2M DMA mode */ ++ ++#define PCIE_CFGADDR 0x120 /* offsetof(configaddr) */ ++#define PCIE_CFGDATA 0x124 /* offsetof(configdata) */ ++#define PCIE_SWPME_FN0 0x10000 ++#define PCIE_SWPME_FN0_SHF 16 ++ ++/* Interrupt status/mask */ ++#define PCIE_INTA 0x01 /* PCIE INTA message is received */ ++#define PCIE_INTB 0x02 /* PCIE INTB message is received */ ++#define PCIE_INTFATAL 0x04 /* PCIE INTFATAL message is received */ ++#define PCIE_INTNFATAL 0x08 /* PCIE INTNONFATAL message is received */ ++#define PCIE_INTCORR 0x10 /* PCIE INTCORR message is received */ ++#define PCIE_INTPME 0x20 /* PCIE INTPME message is received */ ++#define PCIE_PERST 0x40 /* PCIE Reset Interrupt */ ++ ++#define PCIE_INT_MB_FN0_0 0x0100 /* PCIE to SB Mailbox int Fn0.0 is received */ ++#define PCIE_INT_MB_FN0_1 0x0200 /* PCIE to SB Mailbox int Fn0.1 is received */ ++#define PCIE_INT_MB_FN1_0 0x0400 /* PCIE to SB Mailbox int Fn1.0 is received */ ++#define PCIE_INT_MB_FN1_1 0x0800 /* PCIE to SB Mailbox int Fn1.1 is received */ ++#define PCIE_INT_MB_FN2_0 0x1000 /* PCIE to SB Mailbox int Fn2.0 is received */ ++#define PCIE_INT_MB_FN2_1 0x2000 /* PCIE to SB Mailbox int Fn2.1 is received */ ++#define PCIE_INT_MB_FN3_0 0x4000 /* PCIE to SB Mailbox int Fn3.0 is received */ ++#define PCIE_INT_MB_FN3_1 0x8000 /* PCIE to SB Mailbox int Fn3.1 is received */ ++ ++/* PCIE MSI Vector Assignment register */ ++#define MSIVEC_MB_0 (0x1 << 1) /* MSI Vector offset for mailbox0 is 2 */ ++#define MSIVEC_MB_1 (0x1 << 2) /* MSI Vector offset for mailbox1 is 3 */ ++#define MSIVEC_D2H0_DB0 (0x1 << 3) /* MSI Vector offset for interface0 door bell 0 is 4 */ ++#define MSIVEC_D2H0_DB1 (0x1 << 4) /* MSI Vector offset for interface0 door bell 1 is 5 */ ++ ++/* PCIE MailboxInt/MailboxIntMask register */ ++#define PCIE_MB_TOSB_FN0_0 0x0001 /* write to assert PCIEtoSB Mailbox interrupt */ ++#define PCIE_MB_TOSB_FN0_1 0x0002 ++#define PCIE_MB_TOSB_FN1_0 0x0004 ++#define PCIE_MB_TOSB_FN1_1 0x0008 ++#define PCIE_MB_TOSB_FN2_0 0x0010 ++#define PCIE_MB_TOSB_FN2_1 0x0020 ++#define PCIE_MB_TOSB_FN3_0 0x0040 ++#define PCIE_MB_TOSB_FN3_1 0x0080 ++#define PCIE_MB_TOPCIE_FN0_0 0x0100 /* int status/mask for SBtoPCIE Mailbox interrupts */ ++#define PCIE_MB_TOPCIE_FN0_1 0x0200 ++#define PCIE_MB_TOPCIE_FN1_0 0x0400 ++#define PCIE_MB_TOPCIE_FN1_1 0x0800 ++#define PCIE_MB_TOPCIE_FN2_0 0x1000 ++#define PCIE_MB_TOPCIE_FN2_1 0x2000 ++#define PCIE_MB_TOPCIE_FN3_0 0x4000 ++#define PCIE_MB_TOPCIE_FN3_1 0x8000 ++#define PCIE_MB_TOPCIE_D2H0_DB0 0x10000 ++#define PCIE_MB_TOPCIE_D2H0_DB1 0x20000 ++#define PCIE_MB_TOPCIE_D2H1_DB0 0x40000 ++#define PCIE_MB_TOPCIE_D2H1_DB1 0x80000 ++#define PCIE_MB_TOPCIE_D2H2_DB0 0x100000 ++#define PCIE_MB_TOPCIE_D2H2_DB1 0x200000 ++#define PCIE_MB_TOPCIE_D2H3_DB0 0x400000 ++#define PCIE_MB_TOPCIE_D2H3_DB1 0x800000 ++ ++#define PCIE_MB_D2H_MB_MASK \ ++ (PCIE_MB_TOPCIE_D2H0_DB0 | PCIE_MB_TOPCIE_D2H0_DB1 | \ ++ PCIE_MB_TOPCIE_D2H1_DB0 | PCIE_MB_TOPCIE_D2H1_DB1 | \ ++ PCIE_MB_TOPCIE_D2H2_DB0 | PCIE_MB_TOPCIE_D2H2_DB1 | \ ++ PCIE_MB_TOPCIE_D2H3_DB0 | PCIE_MB_TOPCIE_D2H3_DB1) ++ ++#define SBTOPCIE0_BASE 0x08000000 ++#define SBTOPCIE1_BASE 0x0c000000 ++ ++/* On chips with CCI-400, the small pcie 128 MB region base has shifted */ ++#define CCI400_SBTOPCIE0_BASE 0x20000000 ++#define CCI400_SBTOPCIE1_BASE 0x24000000 ++ ++/* SB to PCIE translation masks */ ++#define SBTOPCIE0_MASK 0xfc000000 ++#define SBTOPCIE1_MASK 0xfc000000 ++#define SBTOPCIE2_MASK 0xc0000000 ++ ++/* Access type bits (0:1) */ ++#define SBTOPCIE_MEM 0 ++#define SBTOPCIE_IO 1 ++#define SBTOPCIE_CFG0 2 ++#define SBTOPCIE_CFG1 3 ++ ++/* Prefetch enable bit 2 */ ++#define SBTOPCIE_PF 4 ++ ++/* Write Burst enable for memory write bit 3 */ ++#define SBTOPCIE_WR_BURST 8 ++ ++/* config access */ ++#define CONFIGADDR_FUNC_MASK 0x7000 ++#define CONFIGADDR_FUNC_SHF 12 ++#define CONFIGADDR_REG_MASK 0x0FFF ++#define CONFIGADDR_REG_SHF 0 ++ ++#define PCIE_CONFIG_INDADDR(f, r) ((((f) & CONFIGADDR_FUNC_MASK) << CONFIGADDR_FUNC_SHF) | \ ++ (((r) & CONFIGADDR_REG_MASK) << CONFIGADDR_REG_SHF)) ++ ++/* PCIE protocol regs Indirect Address */ ++#define PCIEADDR_PROT_MASK 0x300 ++#define PCIEADDR_PROT_SHF 8 ++#define PCIEADDR_PL_TLP 0 ++#define PCIEADDR_PL_DLLP 1 ++#define PCIEADDR_PL_PLP 2 ++ ++#define PCIE_CORE_REG_CONTROL 0x00u /* Control */ ++#define PCIE_CORE_REG_IOSTATUS 0x04u /* IO status */ ++#define PCIE_CORE_REG_BITSTATUS 0x0Cu /* bitstatus */ ++#define PCIE_CORE_REG_GPIO_SEL 0x10u /* gpio sel */ ++#define PCIE_CORE_REG_GPIO_OUT_EN 0x14u /* gpio out en */ ++#define PCIE_CORE_REG_INT_STATUS 0x20u /* int status */ ++#define PCIE_CORE_REG_INT_MASK 0x24u /* int mask */ ++#define PCIE_CORE_REG_SB_PCIE_MB 0x28u /* sbpcie mb */ ++#define PCIE_CORE_REG_ERRLOG 0x40u /* errlog */ ++#define PCIE_CORE_REG_ERR_ADDR 0x44u /* errlog addr */ ++#define PCIE_CORE_REG_MB_INTR 0x48u /* MB intr */ ++#define PCIE_CORE_REG_SB_PCIE_0 0x100u /* sbpcie0 map */ ++#define PCIE_CORE_REG_SB_PCIE_1 0x104u /* sbpcie1 map */ ++#define PCIE_CORE_REG_SB_PCIE_2 0x108u /* sbpcie2 map */ ++ ++/* PCIE Config registers */ ++#define PCIE_CFG_DEV_STS_CTRL_2 0x0d4u /* "dev_sts_control_2 */ ++#define PCIE_CFG_ADV_ERR_CAP 0x100u /* adv_err_cap */ ++#define PCIE_CFG_UC_ERR_STS 0x104u /* uc_err_status */ ++#define PCIE_CFG_UC_ERR_MASK 0x108u /* ucorr_err_mask */ ++#define PCIE_CFG_UNCOR_ERR_SERV 0x10cu /* ucorr_err_sevr */ ++#define PCIE_CFG_CORR_ERR_STS 0x110u /* corr_err_status */ ++#define PCIE_CFG_CORR_ERR_MASK 0x114u /* corr_err_mask */ ++#define PCIE_CFG_ADV_ERR_CTRL 0x118u /* adv_err_cap_control */ ++#define PCIE_CFG_HDR_LOG1 0x11Cu /* header_log1 */ ++#define PCIE_CFG_HDR_LOG2 0x120u /* header_log2 */ ++#define PCIE_CFG_HDR_LOG3 0x124u /* header_log3 */ ++#define PCIE_CFG_HDR_LOG4 0x128u /* header_log4 */ ++#define PCIE_CFG_PML1_SUB_CAP_ID 0x240u /* PML1sub_capID */ ++#define PCIE_CFG_PML1_SUB_CAP_REG 0x244u /* PML1_sub_Cap_reg */ ++#define PCIE_CFG_PML1_SUB_CTRL1 0x248u /* PML1_sub_control1 */ ++#define PCIE_CFG_PML1_SUB_CTRL3 0x24Cu /* PML1_sub_control2 */ ++#define PCIE_CFG_TL_CTRL_5 0x814u /* tl_control_5 */ ++#define PCIE_CFG_PHY_ERR_ATT_VEC 0x1820u /* phy_err_attn_vec */ ++#define PCIE_CFG_PHY_ERR_ATT_MASK 0x1824u /* phy_err_attn_mask */ ++ ++/* PCIE protocol PHY diagnostic registers */ ++#define PCIE_PLP_MODEREG 0x200u /* Mode */ ++#define PCIE_PLP_STATUSREG 0x204u /* Status */ ++#define PCIE_PLP_LTSSMCTRLREG 0x208u /* LTSSM control */ ++#define PCIE_PLP_LTLINKNUMREG 0x20cu /* Link Training Link number */ ++#define PCIE_PLP_LTLANENUMREG 0x210u /* Link Training Lane number */ ++#define PCIE_PLP_LTNFTSREG 0x214u /* Link Training N_FTS */ ++#define PCIE_PLP_ATTNREG 0x218u /* Attention */ ++#define PCIE_PLP_ATTNMASKREG 0x21Cu /* Attention Mask */ ++#define PCIE_PLP_RXERRCTR 0x220u /* Rx Error */ ++#define PCIE_PLP_RXFRMERRCTR 0x224u /* Rx Framing Error */ ++#define PCIE_PLP_RXERRTHRESHREG 0x228u /* Rx Error threshold */ ++#define PCIE_PLP_TESTCTRLREG 0x22Cu /* Test Control reg */ ++#define PCIE_PLP_SERDESCTRLOVRDREG 0x230u /* SERDES Control Override */ ++#define PCIE_PLP_TIMINGOVRDREG 0x234u /* Timing param override */ ++#define PCIE_PLP_RXTXSMDIAGREG 0x238u /* RXTX State Machine Diag */ ++#define PCIE_PLP_LTSSMDIAGREG 0x23Cu /* LTSSM State Machine Diag */ ++ ++/* PCIE protocol DLLP diagnostic registers */ ++#define PCIE_DLLP_LCREG 0x100u /* Link Control */ ++#define PCIE_DLLP_LSREG 0x104u /* Link Status */ ++#define PCIE_DLLP_LAREG 0x108u /* Link Attention */ ++#define PCIE_DLLP_LAMASKREG 0x10Cu /* Link Attention Mask */ ++#define PCIE_DLLP_NEXTTXSEQNUMREG 0x110u /* Next Tx Seq Num */ ++#define PCIE_DLLP_ACKEDTXSEQNUMREG 0x114u /* Acked Tx Seq Num */ ++#define PCIE_DLLP_PURGEDTXSEQNUMREG 0x118u /* Purged Tx Seq Num */ ++#define PCIE_DLLP_RXSEQNUMREG 0x11Cu /* Rx Sequence Number */ ++#define PCIE_DLLP_LRREG 0x120u /* Link Replay */ ++#define PCIE_DLLP_LACKTOREG 0x124u /* Link Ack Timeout */ ++#define PCIE_DLLP_PMTHRESHREG 0x128u /* Power Management Threshold */ ++#define PCIE_DLLP_RTRYWPREG 0x12Cu /* Retry buffer write ptr */ ++#define PCIE_DLLP_RTRYRPREG 0x130u /* Retry buffer Read ptr */ ++#define PCIE_DLLP_RTRYPPREG 0x134u /* Retry buffer Purged ptr */ ++#define PCIE_DLLP_RTRRWREG 0x138u /* Retry buffer Read/Write */ ++#define PCIE_DLLP_ECTHRESHREG 0x13Cu /* Error Count Threshold */ ++#define PCIE_DLLP_TLPERRCTRREG 0x140u /* TLP Error Counter */ ++#define PCIE_DLLP_ERRCTRREG 0x144u /* Error Counter */ ++#define PCIE_DLLP_NAKRXCTRREG 0x148u /* NAK Received Counter */ ++#define PCIE_DLLP_TESTREG 0x14Cu /* Test */ ++#define PCIE_DLLP_PKTBIST 0x150u /* Packet BIST */ ++#define PCIE_DLLP_PCIE11 0x154u /* DLLP PCIE 1.1 reg */ ++ ++#define PCIE_DLLP_LSREG_LINKUP (1u << 16u) ++ ++/* PCIE protocol TLP diagnostic registers */ ++#define PCIE_TLP_CONFIGREG 0x000u /* Configuration */ ++#define PCIE_TLP_WORKAROUNDSREG 0x004u /* TLP Workarounds */ ++#define PCIE_TLP_WRDMAUPPER 0x010u /* Write DMA Upper Address */ ++#define PCIE_TLP_WRDMALOWER 0x014u /* Write DMA Lower Address */ ++#define PCIE_TLP_WRDMAREQ_LBEREG 0x018u /* Write DMA Len/ByteEn Req */ ++#define PCIE_TLP_RDDMAUPPER 0x01Cu /* Read DMA Upper Address */ ++#define PCIE_TLP_RDDMALOWER 0x020u /* Read DMA Lower Address */ ++#define PCIE_TLP_RDDMALENREG 0x024u /* Read DMA Len Req */ ++#define PCIE_TLP_MSIDMAUPPER 0x028u /* MSI DMA Upper Address */ ++#define PCIE_TLP_MSIDMALOWER 0x02Cu /* MSI DMA Lower Address */ ++#define PCIE_TLP_MSIDMALENREG 0x030u /* MSI DMA Len Req */ ++#define PCIE_TLP_SLVREQLENREG 0x034u /* Slave Request Len */ ++#define PCIE_TLP_FCINPUTSREQ 0x038u /* Flow Control Inputs */ ++#define PCIE_TLP_TXSMGRSREQ 0x03Cu /* Tx StateMachine and Gated Req */ ++#define PCIE_TLP_ADRACKCNTARBLEN 0x040u /* Address Ack XferCnt and ARB Len */ ++#define PCIE_TLP_DMACPLHDR0 0x044u /* DMA Completion Hdr 0 */ ++#define PCIE_TLP_DMACPLHDR1 0x048u /* DMA Completion Hdr 1 */ ++#define PCIE_TLP_DMACPLHDR2 0x04Cu /* DMA Completion Hdr 2 */ ++#define PCIE_TLP_DMACPLMISC0 0x050u /* DMA Completion Misc0 */ ++#define PCIE_TLP_DMACPLMISC1 0x054u /* DMA Completion Misc1 */ ++#define PCIE_TLP_DMACPLMISC2 0x058u /* DMA Completion Misc2 */ ++#define PCIE_TLP_SPTCTRLLEN 0x05Cu /* Split Controller Req len */ ++#define PCIE_TLP_SPTCTRLMSIC0 0x060u /* Split Controller Misc 0 */ ++#define PCIE_TLP_SPTCTRLMSIC1 0x064u /* Split Controller Misc 1 */ ++#define PCIE_TLP_BUSDEVFUNC 0x068u /* Bus/Device/Func */ ++#define PCIE_TLP_RESETCTR 0x06Cu /* Reset Counter */ ++#define PCIE_TLP_RTRYBUF 0x070u /* Retry Buffer value */ ++#define PCIE_TLP_TGTDEBUG1 0x074u /* Target Debug Reg1 */ ++#define PCIE_TLP_TGTDEBUG2 0x078u /* Target Debug Reg2 */ ++#define PCIE_TLP_TGTDEBUG3 0x07Cu /* Target Debug Reg3 */ ++#define PCIE_TLP_TGTDEBUG4 0x080u /* Target Debug Reg4 */ ++ ++/* PCIE2 MDIO register offsets */ ++#define PCIE2_MDIO_CONTROL 0x128 ++#define PCIE2_MDIO_WR_DATA 0x12C ++#define PCIE2_MDIO_RD_DATA 0x130 ++ ++ ++/* MDIO control */ ++#define MDIOCTL_DIVISOR_MASK 0x7fu /* clock to be used on MDIO */ ++#define MDIOCTL_DIVISOR_VAL 0x2u ++#define MDIOCTL_PREAM_EN 0x80u /* Enable preamble sequnce */ ++#define MDIOCTL_ACCESS_DONE 0x100u /* Tranaction complete */ ++ ++/* MDIO Data */ ++#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */ ++#define MDIODATA_TA 0x00020000 /* Turnaround */ ++#define MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift (rev < 10) */ ++#define MDIODATA_REGADDR_MASK_OLD 0x003c0000 /* Regaddr Mask (rev < 10) */ ++#define MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift (rev < 10) */ ++#define MDIODATA_DEVADDR_MASK_OLD 0x0fc00000 /* Physmedia devaddr Mask (rev < 10) */ ++#define MDIODATA_REGADDR_SHF 18 /* Regaddr shift */ ++#define MDIODATA_REGADDR_MASK 0x007c0000 /* Regaddr Mask */ ++#define MDIODATA_DEVADDR_SHF 23 /* Physmedia devaddr shift */ ++#define MDIODATA_DEVADDR_MASK 0x0f800000 /* Physmedia devaddr Mask */ ++#define MDIODATA_WRITE 0x10000000 /* write Transaction */ ++#define MDIODATA_READ 0x20000000 /* Read Transaction */ ++#define MDIODATA_START 0x40000000 /* start of Transaction */ ++ ++#define MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */ ++#define MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */ ++ ++/* MDIO control/wrData/rdData register defines for PCIE Gen 2 */ ++#define MDIOCTL2_DIVISOR_MASK 0x7f /* clock to be used on MDIO */ ++#define MDIOCTL2_DIVISOR_VAL 0x2 ++#define MDIOCTL2_REGADDR_SHF 8 /* Regaddr shift */ ++#define MDIOCTL2_REGADDR_MASK 0x00FFFF00 /* Regaddr Mask */ ++#define MDIOCTL2_DEVADDR_SHF 24 /* Physmedia devaddr shift */ ++#define MDIOCTL2_DEVADDR_MASK 0x0f000000 /* Physmedia devaddr Mask */ ++#define MDIOCTL2_SLAVE_BYPASS 0x10000000 /* IP slave bypass */ ++#define MDIOCTL2_READ 0x20000000 /* IP slave bypass */ ++ ++#define MDIODATA2_DONE 0x80000000u /* rd/wr transaction done */ ++#define MDIODATA2_MASK 0x7FFFFFFF /* rd/wr transaction data */ ++#define MDIODATA2_DEVADDR_SHF 4 /* Physmedia devaddr shift */ ++ ++ ++/* MDIO devices (SERDES modules) ++ * unlike old pcie cores (rev < 10), rev10 pcie serde organizes registers into a few blocks. ++ * two layers mapping (blockidx, register offset) is required ++ */ ++#define MDIO_DEV_IEEE0 0x000 ++#define MDIO_DEV_IEEE1 0x001 ++#define MDIO_DEV_BLK0 0x800 ++#define MDIO_DEV_BLK1 0x801 ++#define MDIO_DEV_BLK2 0x802 ++#define MDIO_DEV_BLK3 0x803 ++#define MDIO_DEV_BLK4 0x804 ++#define MDIO_DEV_TXPLL 0x808 /* TXPLL register block idx */ ++#define MDIO_DEV_TXCTRL0 0x820 ++#define MDIO_DEV_SERDESID 0x831 ++#define MDIO_DEV_RXCTRL0 0x840 ++ ++ ++/* XgxsBlk1_A Register Offsets */ ++#define BLK1_PWR_MGMT0 0x16 ++#define BLK1_PWR_MGMT1 0x17 ++#define BLK1_PWR_MGMT2 0x18 ++#define BLK1_PWR_MGMT3 0x19 ++#define BLK1_PWR_MGMT4 0x1A ++ ++/* serdes regs (rev < 10) */ ++#define MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */ ++#define MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */ ++#define MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */ ++ /* SERDES RX registers */ ++#define SERDES_RX_CTRL 1 /* Rx cntrl */ ++#define SERDES_RX_TIMER1 2 /* Rx Timer1 */ ++#define SERDES_RX_CDR 6 /* CDR */ ++#define SERDES_RX_CDRBW 7 /* CDR BW */ ++ ++ /* SERDES RX control register */ ++#define SERDES_RX_CTRL_FORCE 0x80 /* rxpolarity_force */ ++#define SERDES_RX_CTRL_POLARITY 0x40 /* rxpolarity_value */ ++ ++ /* SERDES PLL registers */ ++#define SERDES_PLL_CTRL 1 /* PLL control reg */ ++#define PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */ ++ ++/* Power management threshold */ ++#define PCIE_L0THRESHOLDTIME_MASK 0xFF00u /* bits 0 - 7 */ ++#define PCIE_L1THRESHOLDTIME_MASK 0xFF00u /* bits 8 - 15 */ ++#define PCIE_L1THRESHOLDTIME_SHIFT 8 /* PCIE_L1THRESHOLDTIME_SHIFT */ ++#define PCIE_L1THRESHOLD_WARVAL 0x72 /* WAR value */ ++#define PCIE_ASPMTIMER_EXTEND 0x01000000 /* > rev7: enable extend ASPM timer */ ++ ++/* SPROM offsets */ ++#define SRSH_ASPM_OFFSET 4 /* word 4 */ ++#define SRSH_ASPM_ENB 0x18 /* bit 3, 4 */ ++#define SRSH_ASPM_L1_ENB 0x10 /* bit 4 */ ++#define SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */ ++#define SRSH_PCIE_MISC_CONFIG 5 /* word 5 */ ++#define SRSH_L23READY_EXIT_NOPERST 0x8000u /* bit 15 */ ++#define SRSH_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */ ++#define SRSH_CLKREQ_OFFSET_REV8 52 /* word 52 for srom rev 8 */ ++#define SRSH_CLKREQ_ENB 0x0800 /* bit 11 */ ++#define SRSH_BD_OFFSET 6 /* word 6 */ ++#define SRSH_AUTOINIT_OFFSET 18 /* auto initialization enable */ ++ ++/* PCI Capability ID's ++ * Reference include/linux/pci_regs.h ++ * #define PCI_CAP_LIST_ID 0 // Capability ID ++ * #define PCI_CAP_ID_PM 0x01 // Power Management ++ * #define PCI_CAP_ID_AGP 0x02 // Accelerated Graphics Port ++ * #define PCI_CAP_ID_VPD 0x03 // Vital Product Data ++ * #define PCI_CAP_ID_SLOTID 0x04 // Slot Identification ++ * #define PCI_CAP_ID_MSI 0x05 // Message Signalled Interrupts ++ * #define PCI_CAP_ID_CHSWP 0x06 // CompactPCI HotSwap ++ * #define PCI_CAP_ID_PCIX 0x07 // PCI-X ++ * #define PCI_CAP_ID_HT 0x08 // HyperTransport ++ * #define PCI_CAP_ID_VNDR 0x09 // Vendor-Specific ++ * #define PCI_CAP_ID_DBG 0x0A // Debug port ++ * #define PCI_CAP_ID_CCRC 0x0B // CompactPCI Central Resource Control ++ * #define PCI_CAP_ID_SHPC 0x0C // PCI Standard Hot-Plug Controller ++ * #define PCI_CAP_ID_SSVID 0x0D // Bridge subsystem vendor/device ID ++ * #define PCI_CAP_ID_AGP3 0x0E // AGP Target PCI-PCI bridge ++ * #define PCI_CAP_ID_SECDEV 0x0F // Secure Device ++ * #define PCI_CAP_ID_MSIX 0x11 // MSI-X ++ * #define PCI_CAP_ID_SATA 0x12 // SATA Data/Index Conf. ++ * #define PCI_CAP_ID_AF 0x13 // PCI Advanced Features ++ * #define PCI_CAP_ID_EA 0x14 // PCI Enhanced Allocation ++ * #define PCI_CAP_ID_MAX PCI_CAP_ID_EA ++ */ ++ ++#define PCIE_CAP_ID_EXP 0x10 // PCI Express ++ ++/* PCIe Capabilities Offsets ++ * Reference include/linux/pci_regs.h ++ * #define PCIE_CAP_FLAGS 2 // Capabilities register ++ * #define PCIE_CAP_DEVCAP 4 // Device capabilities ++ * #define PCIE_CAP_DEVCTL 8 // Device Control ++ * #define PCIE_CAP_DEVSTA 10 // Device Status ++ * #define PCIE_CAP_LNKCAP 12 // Link Capabilities ++ * #define PCIE_CAP_LNKCTL 16 // Link Control ++ * #define PCIE_CAP_LNKSTA 18 // Link Status ++ * #define PCI_CAP_EXP_ENDPOINT_SIZEOF_V1 20 // v1 endpoints end here ++ * #define PCIE_CAP_SLTCAP 20 // Slot Capabilities ++ * #define PCIE_CAP_SLTCTL 24 // Slot Control ++ * #define PCIE_CAP_SLTSTA 26 // Slot Status ++ * #define PCIE_CAP_RTCTL 28 // Root Control ++ * #define PCIE_CAP_RTCAP 30 // Root Capabilities ++ * #define PCIE_CAP_RTSTA 32 // Root Status ++ */ ++ ++ ++/* Linkcapability reg offset in PCIE Cap */ ++#define PCIE_CAP_LINKCAP_OFFSET 12 /* linkcap offset in pcie cap */ ++#define PCIE_CAP_LINKCAP_LNKSPEED_MASK 0xf /* Supported Link Speeds */ ++#define PCIE_CAP_LINKCAP_GEN2 0x2 /* Value for GEN2 */ ++ ++/* Uc_Err reg offset in AER Cap */ ++#define PCIE_EXTCAP_ID_ERR 0x01 /* Advanced Error Reporting */ ++#define PCIE_EXTCAP_AER_UCERR_OFFSET 4 /* Uc_Err reg offset in AER Cap */ ++ ++/* Linkcontrol reg offset in PCIE Cap */ ++#define PCIE_CAP_LINKCTRL_OFFSET 16 /* linkctrl offset in pcie cap */ ++#define PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */ ++#define PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */ ++#define PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */ ++#define PCIE_LINKSPEED_MASK 0xF0000u /* bits 0 - 3 of high word */ ++#define PCIE_LINKSPEED_SHIFT 16 /* PCIE_LINKSPEED_SHIFT */ ++ ++/* Devcontrol reg offset in PCIE Cap */ ++#define PCIE_CAP_DEVCTRL_OFFSET 8 /* devctrl offset in pcie cap */ ++#define PCIE_CAP_DEVCTRL_MRRS_MASK 0x7000 /* Max read request size mask */ ++#define PCIE_CAP_DEVCTRL_MRRS_SHIFT 12 /* Max read request size shift */ ++#define PCIE_CAP_DEVCTRL_MRRS_128B 0 /* 128 Byte */ ++#define PCIE_CAP_DEVCTRL_MRRS_256B 1 /* 256 Byte */ ++#define PCIE_CAP_DEVCTRL_MRRS_512B 2 /* 512 Byte */ ++#define PCIE_CAP_DEVCTRL_MRRS_1024B 3 /* 1024 Byte */ ++#define PCIE_CAP_DEVCTRL_MPS_MASK 0x00e0 /* Max payload size mask */ ++#define PCIE_CAP_DEVCTRL_MPS_SHIFT 5 /* Max payload size shift */ ++#define PCIE_CAP_DEVCTRL_MPS_128B 0 /* 128 Byte */ ++#define PCIE_CAP_DEVCTRL_MPS_256B 1 /* 256 Byte */ ++#define PCIE_CAP_DEVCTRL_MPS_512B 2 /* 512 Byte */ ++#define PCIE_CAP_DEVCTRL_MPS_1024B 3 /* 1024 Byte */ ++ ++#define PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */ ++#define PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */ ++#define PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */ ++#define PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */ ++ ++#define PCIE_ASPM_L11_ENAB 8 /* ASPM L1.1 in PML1_sub_control2 */ ++#define PCIE_ASPM_L12_ENAB 4 /* ASPM L1.2 in PML1_sub_control2 */ ++ ++/* NumMsg and NumMsgEn in PCIE MSI Cap */ ++#define MSICAP_NUM_MSG_SHF 17 ++#define MSICAP_NUM_MSG_MASK (0x7 << MSICAP_NUM_MSG_SHF) ++#define MSICAP_NUM_MSG_EN_SHF 20 ++#define MSICAP_NUM_MSG_EN_MASK (0x7 << MSICAP_NUM_MSG_EN_SHF) ++ ++/* Devcontrol2 reg offset in PCIE Cap */ ++#define PCIE_CAP_DEVCTRL2_OFFSET 0x28 /* devctrl2 offset in pcie cap */ ++#define PCIE_CAP_DEVCTRL2_LTR_ENAB_MASK 0x400 /* Latency Tolerance Reporting Enable */ ++#define PCIE_CAP_DEVCTRL2_OBFF_ENAB_SHIFT 13 /* Enable OBFF mechanism, select signaling method */ ++#define PCIE_CAP_DEVCTRL2_OBFF_ENAB_MASK 0x6000 /* Enable OBFF mechanism, select signaling method */ ++ ++/* LTR registers in PCIE Cap */ ++#define PCIE_LTR0_REG_OFFSET 0x844u /* ltr0_reg offset in pcie cap */ ++#define PCIE_LTR1_REG_OFFSET 0x848u /* ltr1_reg offset in pcie cap */ ++#define PCIE_LTR2_REG_OFFSET 0x84cu /* ltr2_reg offset in pcie cap */ ++#define PCIE_LTR0_REG_DEFAULT_60 0x883c883cu /* active latency default to 60usec */ ++#define PCIE_LTR0_REG_DEFAULT_150 0x88968896u /* active latency default to 150usec */ ++#define PCIE_LTR1_REG_DEFAULT 0x88648864u /* idle latency default to 100usec */ ++#define PCIE_LTR2_REG_DEFAULT 0x90039003u /* sleep latency default to 3msec */ ++ ++/* Status reg PCIE_PLP_STATUSREG */ ++#define PCIE_PLP_POLARITYINV_STAT 0x10 ++ ++ ++/* PCIE BRCM Vendor CAP REVID reg bits */ ++#define BRCMCAP_PCIEREV_CT_MASK 0xF00u ++#define BRCMCAP_PCIEREV_CT_SHIFT 8u ++#define BRCMCAP_PCIEREV_REVID_MASK 0xFFu ++#define BRCMCAP_PCIEREV_REVID_SHIFT 0 ++ ++#define PCIE_REVREG_CT_PCIE1 0 ++#define PCIE_REVREG_CT_PCIE2 1 ++ ++/* PCIE GEN2 specific defines */ ++/* PCIE BRCM Vendor Cap offsets w.r.t to vendor cap ptr */ ++#define PCIE2R0_BRCMCAP_REVID_OFFSET 4 ++#define PCIE2R0_BRCMCAP_BAR0_WIN0_WRAP_OFFSET 8 ++#define PCIE2R0_BRCMCAP_BAR0_WIN2_OFFSET 12 ++#define PCIE2R0_BRCMCAP_BAR0_WIN2_WRAP_OFFSET 16 ++#define PCIE2R0_BRCMCAP_BAR0_WIN_OFFSET 20 ++#define PCIE2R0_BRCMCAP_BAR1_WIN_OFFSET 24 ++#define PCIE2R0_BRCMCAP_SPROM_CTRL_OFFSET 28 ++#define PCIE2R0_BRCMCAP_BAR2_WIN_OFFSET 32 ++#define PCIE2R0_BRCMCAP_INTSTATUS_OFFSET 36 ++#define PCIE2R0_BRCMCAP_INTMASK_OFFSET 40 ++#define PCIE2R0_BRCMCAP_PCIE2SB_MB_OFFSET 44 ++#define PCIE2R0_BRCMCAP_BPADDR_OFFSET 48 ++#define PCIE2R0_BRCMCAP_BPDATA_OFFSET 52 ++#define PCIE2R0_BRCMCAP_CLKCTLSTS_OFFSET 56 ++ ++/* definition of configuration space registers of PCIe gen2 ++ * http://hwnbu-twiki.sj.broadcom.com/twiki/pub/Mwgroup/CurrentPcieGen2ProgramGuide/pcie_ep.htm ++ */ ++#define PCIECFGREG_STATUS_CMD 0x4 ++#define PCIECFGREG_PM_CSR 0x4C ++#define PCIECFGREG_MSI_CAP 0x58 ++#define PCIECFGREG_MSI_ADDR_L 0x5C ++#define PCIECFGREG_MSI_ADDR_H 0x60 ++#define PCIECFGREG_MSI_DATA 0x64 ++#define PCIECFGREG_LINK_STATUS_CTRL 0xBCu ++#define PCIECFGREG_DEV_STATUS_CTRL 0xB4u ++#define PCIECFGGEN_DEV_STATUS_CTRL2 0xD4 ++#define PCIECFGREG_LINK_STATUS_CTRL2 0xDCu ++#define PCIECFGREG_RBAR_CTRL 0x228 ++#define PCIECFGREG_PML1_SUB_CTRL1 0x248 ++#define PCIECFGREG_PML1_SUB_CTRL2 0x24C ++#define PCIECFGREG_REG_BAR2_CONFIG 0x4E0 ++#define PCIECFGREG_REG_BAR3_CONFIG 0x4F4 ++#define PCIECFGREG_PDL_CTRL1 0x1004 ++#define PCIECFGREG_PDL_IDDQ 0x1814 ++#define PCIECFGREG_REG_PHY_CTL7 0x181c ++#define PCIECFGREG_PHY_DBG_CLKREQ0 0x1E10 ++#define PCIECFGREG_PHY_DBG_CLKREQ1 0x1E14 ++#define PCIECFGREG_PHY_DBG_CLKREQ2 0x1E18 ++#define PCIECFGREG_PHY_DBG_CLKREQ3 0x1E1C ++ ++/* PCIECFGREG_PML1_SUB_CTRL1 Bit Definition */ ++#define PCI_PM_L1_2_ENA_MASK 0x00000001 /* PCI-PM L1.2 Enabled */ ++#define PCI_PM_L1_1_ENA_MASK 0x00000002 /* PCI-PM L1.1 Enabled */ ++#define ASPM_L1_2_ENA_MASK 0x00000004 /* ASPM L1.2 Enabled */ ++#define ASPM_L1_1_ENA_MASK 0x00000008 /* ASPM L1.1 Enabled */ ++ ++/* PCIe gen2 mailbox interrupt masks */ ++#define I_MB 0x3 ++#define I_BIT0 0x1 ++#define I_BIT1 0x2 ++ ++/* PCIE gen2 config regs */ ++#define PCIIntstatus 0x090 ++#define PCIIntmask 0x094 ++#define PCISBMbx 0x98 ++ ++/* enumeration Core regs */ ++#define PCIH2D_MailBox 0x140 ++#define PCIH2D_DB1 0x144 ++#define PCID2H_MailBox 0x148 ++#define PCIH2D_MailBox_1 0x150 /* for dma channel1 */ ++#define PCIH2D_DB1_1 0x154 ++#define PCID2H_MailBox_1 0x158 ++#define PCIH2D_MailBox_2 0x160 /* for dma channel2 which will be used for Implicit DMA */ ++#define PCIH2D_DB1_2 0x164 ++#define PCID2H_MailBox_2 0x168 ++ ++#define PCIMailBoxInt 0x48 ++#define PCIMailBoxMask 0x4C ++#define PCIMSIVecAssign 0x58 ++ ++#define I_F0_B0 (0x1 << 8) /* Mail box interrupt Function 0 interrupt, bit 0 */ ++#define I_F0_B1 (0x1 << 9) /* Mail box interrupt Function 0 interrupt, bit 1 */ ++ ++#define PCIECFGREG_DEVCONTROL 0xB4 ++#define PCIECFGREG_BASEADDR0 0x10 ++#define PCIECFGREG_DEVCONTROL_MRRS_SHFT 12 ++#define PCIECFGREG_DEVCONTROL_MRRS_MASK (0x7 << PCIECFGREG_DEVCONTROL_MRRS_SHFT) ++#define PCIECFGREG_DEVCTRL_MPS_SHFT 5 ++#define PCIECFGREG_DEVCTRL_MPS_MASK (0x7 << PCIECFGREG_DEVCTRL_MPS_SHFT) ++#define PCIECFGREG_PM_CSR_STATE_MASK 0x00000003 ++#define PCIECFGREG_PM_CSR_STATE_D0 0 ++#define PCIECFGREG_PM_CSR_STATE_D1 1 ++#define PCIECFGREG_PM_CSR_STATE_D2 2 ++#define PCIECFGREG_PM_CSR_STATE_D3_HOT 3 ++#define PCIECFGREG_PM_CSR_STATE_D3_COLD 4 ++ ++ ++/* SROM hardware region */ ++#define SROM_OFFSET_BAR1_CTRL 52 ++ ++#define BAR1_ENC_SIZE_MASK 0x000e ++#define BAR1_ENC_SIZE_SHIFT 1 ++ ++#define BAR1_ENC_SIZE_1M 0 ++#define BAR1_ENC_SIZE_2M 1 ++#define BAR1_ENC_SIZE_4M 2 ++ ++#define PCIEGEN2_CAP_DEVSTSCTRL2_OFFSET 0xD4 ++#define PCIEGEN2_CAP_DEVSTSCTRL2_LTRENAB 0x400 ++ ++/* ++ * Latency Tolerance Reporting (LTR) states ++ * Active has the least tolerant latency requirement ++ * Sleep is most tolerant ++ */ ++#define LTR_ACTIVE 2 ++#define LTR_ACTIVE_IDLE 1 ++#define LTR_SLEEP 0 ++#define LTR_FINAL_MASK 0x300 ++#define LTR_FINAL_SHIFT 8 ++ ++/* pwrinstatus, pwrintmask regs */ ++#define PCIEGEN2_PWRINT_D0_STATE_SHIFT 0 ++#define PCIEGEN2_PWRINT_D1_STATE_SHIFT 1 ++#define PCIEGEN2_PWRINT_D2_STATE_SHIFT 2 ++#define PCIEGEN2_PWRINT_D3_STATE_SHIFT 3 ++#define PCIEGEN2_PWRINT_L0_LINK_SHIFT 4 ++#define PCIEGEN2_PWRINT_L0s_LINK_SHIFT 5 ++#define PCIEGEN2_PWRINT_L1_LINK_SHIFT 6 ++#define PCIEGEN2_PWRINT_L2_L3_LINK_SHIFT 7 ++#define PCIEGEN2_PWRINT_OBFF_CHANGE_SHIFT 8 ++ ++#define PCIEGEN2_PWRINT_D0_STATE_MASK (1 << PCIEGEN2_PWRINT_D0_STATE_SHIFT) ++#define PCIEGEN2_PWRINT_D1_STATE_MASK (1 << PCIEGEN2_PWRINT_D1_STATE_SHIFT) ++#define PCIEGEN2_PWRINT_D2_STATE_MASK (1 << PCIEGEN2_PWRINT_D2_STATE_SHIFT) ++#define PCIEGEN2_PWRINT_D3_STATE_MASK (1 << PCIEGEN2_PWRINT_D3_STATE_SHIFT) ++#define PCIEGEN2_PWRINT_L0_LINK_MASK (1 << PCIEGEN2_PWRINT_L0_LINK_SHIFT) ++#define PCIEGEN2_PWRINT_L0s_LINK_MASK (1 << PCIEGEN2_PWRINT_L0s_LINK_SHIFT) ++#define PCIEGEN2_PWRINT_L1_LINK_MASK (1 << PCIEGEN2_PWRINT_L1_LINK_SHIFT) ++#define PCIEGEN2_PWRINT_L2_L3_LINK_MASK (1 << PCIEGEN2_PWRINT_L2_L3_LINK_SHIFT) ++#define PCIEGEN2_PWRINT_OBFF_CHANGE_MASK (1 << PCIEGEN2_PWRINT_OBFF_CHANGE_SHIFT) ++ ++/* sbtopcie mail box */ ++#define SBTOPCIE_MB_FUNC0_SHIFT 8 ++#define SBTOPCIE_MB_FUNC1_SHIFT 10 ++#define SBTOPCIE_MB_FUNC2_SHIFT 12 ++#define SBTOPCIE_MB_FUNC3_SHIFT 14 ++ ++#define SBTOPCIE_MB1_FUNC0_SHIFT 9 ++#define SBTOPCIE_MB1_FUNC1_SHIFT 11 ++#define SBTOPCIE_MB1_FUNC2_SHIFT 13 ++#define SBTOPCIE_MB1_FUNC3_SHIFT 15 ++ ++/* pcieiocstatus */ ++#define PCIEGEN2_IOC_D0_STATE_SHIFT 8 ++#define PCIEGEN2_IOC_D1_STATE_SHIFT 9 ++#define PCIEGEN2_IOC_D2_STATE_SHIFT 10 ++#define PCIEGEN2_IOC_D3_STATE_SHIFT 11 ++#define PCIEGEN2_IOC_L0_LINK_SHIFT 12 ++#define PCIEGEN2_IOC_L1_LINK_SHIFT 13 ++#define PCIEGEN2_IOC_L1L2_LINK_SHIFT 14 ++#define PCIEGEN2_IOC_L2_L3_LINK_SHIFT 15 ++ ++#define PCIEGEN2_IOC_D0_STATE_MASK (1 << PCIEGEN2_IOC_D0_STATE_SHIFT) ++#define PCIEGEN2_IOC_D1_STATE_MASK (1 << PCIEGEN2_IOC_D1_STATE_SHIFT) ++#define PCIEGEN2_IOC_D2_STATE_MASK (1 << PCIEGEN2_IOC_D2_STATE_SHIFT) ++#define PCIEGEN2_IOC_D3_STATE_MASK (1 << PCIEGEN2_IOC_D3_STATE_SHIFT) ++#define PCIEGEN2_IOC_L0_LINK_MASK (1 << PCIEGEN2_IOC_L0_LINK_SHIFT) ++#define PCIEGEN2_IOC_L1_LINK_MASK (1 << PCIEGEN2_IOC_L1_LINK_SHIFT) ++#define PCIEGEN2_IOC_L1L2_LINK_MASK (1 << PCIEGEN2_IOC_L1L2_LINK_SHIFT) ++#define PCIEGEN2_IOC_L2_L3_LINK_MASK (1 << PCIEGEN2_IOC_L2_L3_LINK_SHIFT) ++ ++/* stat_ctrl */ ++#define PCIE_STAT_CTRL_RESET 0x1 ++#define PCIE_STAT_CTRL_ENABLE 0x2 ++#define PCIE_STAT_CTRL_INTENABLE 0x4 ++#define PCIE_STAT_CTRL_INTSTATUS 0x8 ++ ++/* cpl_timeout_ctrl_reg */ ++#define PCIE_CTO_TO_THRESHOLD_SHIFT 0 ++#define PCIE_CTO_TO_THRESHHOLD_MASK (0xfffff << PCIE_CTO_TO_THRESHOLD_SHIFT) ++ ++#define PCIE_CTO_CLKCHKCNT_SHIFT 24 ++#define PCIE_CTO_CLKCHKCNT_MASK (0xf << PCIE_CTO_CLKCHKCNT_SHIFT) ++ ++#define PCIE_CTO_ENAB_SHIFT 31 ++#define PCIE_CTO_ENAB_MASK (0x1 << PCIE_CTO_ENAB_SHIFT) ++ ++#define PCIE_CTO_TO_THRESH_DEFAULT 0x58000 ++#define PCIE_CTO_CLKCHKCNT_VAL 0xA ++ ++/* ErrLog */ ++#define PCIE_SROMRD_ERR_SHIFT 5 ++#define PCIE_SROMRD_ERR_MASK (0x1 << PCIE_SROMRD_ERR_SHIFT) ++ ++#define PCIE_CTO_ERR_SHIFT 8 ++#define PCIE_CTO_ERR_MASK (0x1 << PCIE_CTO_ERR_SHIFT) ++ ++#define PCIE_CTO_ERR_CODE_SHIFT 9 ++#define PCIE_CTO_ERR_CODE_MASK (0x3 << PCIE_CTO_ERR_CODE_SHIFT) ++ ++#define PCIE_BP_CLK_OFF_ERR_SHIFT 12 ++#define PCIE_BP_CLK_OFF_ERR_MASK (0x1 << PCIE_BP_CLK_OFF_ERR_SHIFT) ++ ++#define PCIE_BP_IN_RESET_ERR_SHIFT 13 ++#define PCIE_BP_IN_RESET_ERR_MASK (0x1 << PCIE_BP_IN_RESET_ERR_SHIFT) ++ ++#ifdef BCMDRIVER ++void pcie_watchdog_reset(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs); ++void pcie_serdes_iddqdisable(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs); ++void pcie_set_trefup_time_100us(si_t *sih); ++#endif /* BCMDRIVER */ ++ ++/* DMA intstatus and intmask */ ++#define I_PC (1 << 10) /* pci descriptor error */ ++#define I_PD (1 << 11) /* pci data error */ ++#define I_DE (1 << 12) /* descriptor protocol error */ ++#define I_RU (1 << 13) /* receive descriptor underflow */ ++#define I_RO (1 << 14) /* receive fifo overflow */ ++#define I_XU (1 << 15) /* transmit fifo underflow */ ++#define I_RI (1 << 16) /* receive interrupt */ ++#define I_XI (1 << 24) /* transmit interrupt */ ++ ++#endif /* _PCIE_CORE_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/rte_ioctl.h b/module_drivers/drivers/net/wireless/bcmdhd/include/rte_ioctl.h +new file mode 100644 +index 000000000..f4c8c803c +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/rte_ioctl.h +@@ -0,0 +1,87 @@ ++/* ++ * HND Run Time Environment ioctl. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: rte_ioctl.h 615249 2016-01-27 02:04:07Z $ ++ */ ++ ++#ifndef _rte_ioctl_h_ ++#define _rte_ioctl_h_ ++ ++/* RTE IOCTL definitions for generic ether devices */ ++#define RTEGHWADDR 0x8901 ++#define RTESHWADDR 0x8902 ++#define RTEGMTU 0x8903 ++#define RTEGSTATS 0x8904 ++#define RTEGALLMULTI 0x8905 ++#define RTESALLMULTI 0x8906 ++#define RTEGPROMISC 0x8907 ++#define RTESPROMISC 0x8908 ++#define RTESMULTILIST 0x8909 ++#define RTEGUP 0x890A ++#define RTEGPERMADDR 0x890B ++#define RTEDEVPWRSTCHG 0x890C /* Device pwr state change for PCIedev */ ++#define RTEDEVPMETOGGLE 0x890D /* Toggle PME# to wake up the host */ ++ ++#define RTE_IOCTL_QUERY 0x00 ++#define RTE_IOCTL_SET 0x01 ++#define RTE_IOCTL_OVL_IDX_MASK 0x1e ++#define RTE_IOCTL_OVL_RSV 0x20 ++#define RTE_IOCTL_OVL 0x40 ++#define RTE_IOCTL_OVL_IDX_SHIFT 1 ++ ++enum hnd_ioctl_cmd { ++ HND_RTE_DNGL_IS_SS = 1, /* true if device connected at super speed */ ++ ++ /* PCIEDEV specific wl <--> bus ioctls */ ++ BUS_GET_VAR = 2, ++ BUS_SET_VAR = 3, ++ BUS_FLUSH_RXREORDER_Q = 4, ++ BUS_SET_LTR_STATE = 5, ++ BUS_FLUSH_CHAINED_PKTS = 6, ++ BUS_SET_COPY_COUNT = 7, ++ BUS_UPDATE_FLOW_PKTS_MAX = 8, ++ BUS_UPDATE_EXTRA_TXLFRAGS = 9 ++}; ++ ++#define SDPCMDEV_SET_MAXTXPKTGLOM 1 ++ ++typedef struct memuse_info { ++ uint16 ver; /* version of this struct */ ++ uint16 len; /* length in bytes of this structure */ ++ uint32 tot; /* Total memory */ ++ uint32 text_len; /* Size of Text segment memory */ ++ uint32 data_len; /* Size of Data segment memory */ ++ uint32 bss_len; /* Size of BSS segment memory */ ++ ++ uint32 arena_size; /* Total Heap size */ ++ uint32 arena_free; /* Heap memory available or free */ ++ uint32 inuse_size; /* Heap memory currently in use */ ++ uint32 inuse_hwm; /* High watermark of memory - reclaimed memory */ ++ uint32 inuse_overhead; /* tally of allocated mem_t blocks */ ++ uint32 inuse_total; /* Heap in-use + Heap overhead memory */ ++} memuse_info_t; ++ ++#endif /* _rte_ioctl_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sbchipc.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sbchipc.h +new file mode 100644 +index 000000000..cbc75b2f5 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sbchipc.h +@@ -0,0 +1,4417 @@ ++/* ++ * SiliconBackplane Chipcommon core hardware definitions. ++ * ++ * The chipcommon core provides chip identification, SB control, ++ * 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 657872 2016-09-02 22:17:34Z $ ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ */ ++ ++#ifndef _SBCHIPC_H ++#define _SBCHIPC_H ++ ++#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++/** ++ * In chipcommon rev 49 the pmu registers have been moved from chipc to the pmu core if the ++ * 'AOBPresent' bit of 'CoreCapabilitiesExt' is set. If this field is set, the traditional chipc to ++ * [pmu|gci|sreng] register interface is deprecated and removed. These register blocks would instead ++ * be assigned their respective chipc-specific address space and connected to the Always On ++ * Backplane via the APB interface. ++ */ ++typedef volatile struct { ++ uint32 PAD[384]; ++ uint32 pmucontrol; /* 0x600 */ ++ uint32 pmucapabilities; /* 0x604 */ ++ uint32 pmustatus; /* 0x608 */ ++ uint32 res_state; /* 0x60C */ ++ uint32 res_pending; /* 0x610 */ ++ uint32 pmutimer; /* 0x614 */ ++ uint32 min_res_mask; /* 0x618 */ ++ uint32 max_res_mask; /* 0x61C */ ++ uint32 res_table_sel; /* 0x620 */ ++ uint32 res_dep_mask; ++ uint32 res_updn_timer; ++ uint32 res_timer; ++ uint32 clkstretch; ++ uint32 pmuwatchdog; ++ uint32 gpiosel; /* 0x638, rev >= 1 */ ++ uint32 gpioenable; /* 0x63c, rev >= 1 */ ++ uint32 res_req_timer_sel; /* 0x640 */ ++ uint32 res_req_timer; /* 0x644 */ ++ uint32 res_req_mask; /* 0x648 */ ++ uint32 core_cap_ext; /* 0x64C */ ++ uint32 chipcontrol_addr; /* 0x650 */ ++ uint32 chipcontrol_data; /* 0x654 */ ++ uint32 regcontrol_addr; ++ uint32 regcontrol_data; ++ uint32 pllcontrol_addr; ++ uint32 pllcontrol_data; ++ uint32 pmustrapopt; /* 0x668, corerev >= 28 */ ++ uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ ++ uint32 retention_ctl; /* 0x670 */ ++ uint32 ILPPeriod; /* 0x674 */ ++ uint32 PAD[2]; ++ uint32 retention_grpidx; /* 0x680 */ ++ uint32 retention_grpctl; /* 0x684 */ ++ uint32 mac_res_req_timer; /* 0x688 */ ++ uint32 mac_res_req_mask; /* 0x68c */ ++ uint32 PAD[18]; ++ uint32 pmucontrol_ext; /* 0x6d8 */ ++ uint32 slowclkperiod; /* 0x6dc */ ++ uint32 PAD[8]; ++ uint32 pmuintmask0; /* 0x700 */ ++ uint32 pmuintmask1; /* 0x704 */ ++ uint32 PAD[14]; ++ uint32 pmuintstatus; /* 0x740 */ ++ uint32 extwakeupstatus; /* 0x744 */ ++ uint32 watchdog_res_mask; /* 0x748 */ ++ uint32 PAD[1]; /* 0x74C */ ++ uint32 swscratch; /* 0x750 */ ++ uint32 PAD[3]; /* 0x754-0x75C */ ++ uint32 extwakemask[2]; /* 0x760-0x764 */ ++ uint32 PAD[2]; /* 0x768-0x76C */ ++ uint32 extwakereqmask[2]; /* 0x770-0x774 */ ++ uint32 PAD[2]; /* 0x778-0x77C */ ++ uint32 pmuintctrl0; /* 0x780 */ ++ uint32 pmuintctrl1; /* 0x784 */ ++ uint32 PAD[2]; ++ uint32 extwakectrl[2] ; /* 0x790 */ ++} pmuregs_t; ++ ++typedef struct eci_prerev35 { ++ uint32 eci_output; ++ uint32 eci_control; ++ uint32 eci_inputlo; ++ uint32 eci_inputmi; ++ uint32 eci_inputhi; ++ uint32 eci_inputintpolaritylo; ++ uint32 eci_inputintpolaritymi; ++ uint32 eci_inputintpolarityhi; ++ uint32 eci_intmasklo; ++ uint32 eci_intmaskmi; ++ uint32 eci_intmaskhi; ++ uint32 eci_eventlo; ++ uint32 eci_eventmi; ++ uint32 eci_eventhi; ++ uint32 eci_eventmasklo; ++ uint32 eci_eventmaskmi; ++ uint32 eci_eventmaskhi; ++ uint32 PAD[3]; ++} eci_prerev35_t; ++ ++typedef struct eci_rev35 { ++ uint32 eci_outputlo; ++ uint32 eci_outputhi; ++ uint32 eci_controllo; ++ uint32 eci_controlhi; ++ uint32 eci_inputlo; ++ uint32 eci_inputhi; ++ uint32 eci_inputintpolaritylo; ++ uint32 eci_inputintpolarityhi; ++ uint32 eci_intmasklo; ++ uint32 eci_intmaskhi; ++ uint32 eci_eventlo; ++ uint32 eci_eventhi; ++ uint32 eci_eventmasklo; ++ uint32 eci_eventmaskhi; ++ uint32 eci_auxtx; ++ uint32 eci_auxrx; ++ uint32 eci_datatag; ++ uint32 eci_uartescvalue; ++ uint32 eci_autobaudctr; ++ uint32 eci_uartfifolevel; ++} eci_rev35_t; ++ ++typedef struct flash_config { ++ uint32 PAD[19]; ++ /* Flash struct configuration registers (0x18c) for BCM4706 (corerev = 31) */ ++ uint32 flashstrconfig; ++} flash_config_t; ++ ++typedef volatile struct { ++ uint32 chipid; /* 0x0 */ ++ uint32 capabilities; ++ uint32 corecontrol; /* corerev >= 1 */ ++ uint32 bist; ++ ++ /* OTP */ ++ uint32 otpstatus; /* 0x10, corerev >= 10 */ ++ uint32 otpcontrol; ++ uint32 otpprog; ++ uint32 otplayout; /* corerev >= 23 */ ++ ++ /* Interrupt control */ ++ uint32 intstatus; /* 0x20 */ ++ uint32 intmask; ++ ++ /* Chip specific regs */ ++ uint32 chipcontrol; /* 0x28, rev >= 11 */ ++ uint32 chipstatus; /* 0x2c, rev >= 11 */ ++ ++ /* Jtag Master */ ++ uint32 jtagcmd; /* 0x30, rev >= 10 */ ++ uint32 jtagir; ++ uint32 jtagdr; ++ uint32 jtagctrl; ++ ++ /* serial flash interface registers */ ++ uint32 flashcontrol; /* 0x40 */ ++ uint32 flashaddress; ++ uint32 flashdata; ++ uint32 otplayoutextension; /* rev >= 35 */ ++ ++ /* Silicon backplane configuration broadcast control */ ++ uint32 broadcastaddress; /* 0x50 */ ++ uint32 broadcastdata; ++ ++ /* gpio - cleared only by power-on-reset */ ++ uint32 gpiopullup; /* 0x58, corerev >= 20 */ ++ uint32 gpiopulldown; /* 0x5c, corerev >= 20 */ ++ uint32 gpioin; /* 0x60 */ ++ uint32 gpioout; /* 0x64 */ ++ uint32 gpioouten; /* 0x68 */ ++ uint32 gpiocontrol; /* 0x6C */ ++ uint32 gpiointpolarity; /* 0x70 */ ++ uint32 gpiointmask; /* 0x74 */ ++ ++ /* GPIO events corerev >= 11 */ ++ uint32 gpioevent; ++ uint32 gpioeventintmask; ++ ++ /* Watchdog timer */ ++ uint32 watchdog; /* 0x80 */ ++ ++ /* GPIO events corerev >= 11 */ ++ uint32 gpioeventintpolarity; ++ ++ /* GPIO based LED powersave registers corerev >= 16 */ ++ uint32 gpiotimerval; /* 0x88 */ ++ uint32 gpiotimeroutmask; ++ ++ /* clock control */ ++ uint32 clockcontrol_n; /* 0x90 */ ++ uint32 clockcontrol_sb; /* aka m0 */ ++ uint32 clockcontrol_pci; /* aka m1 */ ++ uint32 clockcontrol_m2; /* mii/uart/mipsref */ ++ uint32 clockcontrol_m3; /* cpu */ ++ uint32 clkdiv; /* corerev >= 3 */ ++ uint32 gpiodebugsel; /* corerev >= 28 */ ++ uint32 capabilities_ext; /* 0xac */ ++ ++ /* pll delay registers (corerev >= 4) */ ++ uint32 pll_on_delay; /* 0xb0 */ ++ uint32 fref_sel_delay; ++ uint32 slow_clk_ctl; /* 5 < corerev < 10 */ ++ uint32 PAD; ++ ++ /* Instaclock registers (corerev >= 10) */ ++ uint32 system_clk_ctl; /* 0xc0 */ ++ uint32 clkstatestretch; ++ uint32 PAD[2]; ++ ++ /* Indirect backplane access (corerev >= 22) */ ++ uint32 bp_addrlow; /* 0xd0 */ ++ uint32 bp_addrhigh; ++ uint32 bp_data; ++ uint32 PAD; ++ uint32 bp_indaccess; ++ /* SPI registers, corerev >= 37 */ ++ uint32 gsioctrl; ++ uint32 gsioaddress; ++ uint32 gsiodata; ++ ++ /* More clock dividers (corerev >= 32) */ ++ uint32 clkdiv2; ++ /* FAB ID (corerev >= 40) */ ++ uint32 otpcontrol1; ++ uint32 fabid; /* 0xf8 */ ++ ++ /* In AI chips, pointer to erom */ ++ uint32 eromptr; /* 0xfc */ ++ ++ /* ExtBus control registers (corerev >= 3) */ ++ uint32 pcmcia_config; /* 0x100 */ ++ uint32 pcmcia_memwait; ++ uint32 pcmcia_attrwait; ++ uint32 pcmcia_iowait; ++ uint32 ide_config; ++ uint32 ide_memwait; ++ uint32 ide_attrwait; ++ uint32 ide_iowait; ++ uint32 prog_config; ++ uint32 prog_waitcount; ++ uint32 flash_config; ++ uint32 flash_waitcount; ++ uint32 SECI_config; /* 0x130 SECI configuration */ ++ uint32 SECI_status; ++ uint32 SECI_statusmask; ++ uint32 SECI_rxnibchanged; ++ ++ uint32 PAD[20]; ++ ++ /* SROM interface (corerev >= 32) */ ++ uint32 sromcontrol; /* 0x190 */ ++ uint32 sromaddress; ++ uint32 sromdata; ++ uint32 PAD[1]; /* 0x19C */ ++ /* NAND flash registers for BCM4706 (corerev = 31) */ ++ uint32 nflashctrl; /* 0x1a0 */ ++ uint32 nflashconf; ++ uint32 nflashcoladdr; ++ uint32 nflashrowaddr; ++ uint32 nflashdata; ++ uint32 nflashwaitcnt0; /* 0x1b4 */ ++ uint32 PAD[2]; ++ ++ uint32 seci_uart_data; /* 0x1C0 */ ++ uint32 seci_uart_bauddiv; ++ uint32 seci_uart_fcr; ++ uint32 seci_uart_lcr; ++ uint32 seci_uart_mcr; ++ uint32 seci_uart_lsr; ++ uint32 seci_uart_msr; ++ uint32 seci_uart_baudadj; ++ /* Clock control and hardware workarounds (corerev >= 20) */ ++ uint32 clk_ctl_st; /* 0x1e0 */ ++ uint32 hw_war; ++ uint32 powerctl; /* 0x1e8 */ ++ uint32 PAD[69]; ++ ++ /* UARTs */ ++ uint8 uart0data; /* 0x300 */ ++ uint8 uart0imr; ++ uint8 uart0fcr; ++ uint8 uart0lcr; ++ uint8 uart0mcr; ++ uint8 uart0lsr; ++ uint8 uart0msr; ++ uint8 uart0scratch; ++ uint8 PAD[248]; /* corerev >= 1 */ ++ ++ uint8 uart1data; /* 0x400 */ ++ uint8 uart1imr; ++ uint8 uart1fcr; ++ uint8 uart1lcr; ++ uint8 uart1mcr; ++ uint8 uart1lsr; ++ uint8 uart1msr; ++ uint8 uart1scratch; /* 0x407 */ ++ uint32 PAD[62]; ++ ++ /* save/restore, corerev >= 48 */ ++ uint32 sr_capability; /* 0x500 */ ++ uint32 sr_control0; /* 0x504 */ ++ uint32 sr_control1; /* 0x508 */ ++ uint32 gpio_control; /* 0x50C */ ++ uint32 PAD[29]; ++ /* 2 SR engines case */ ++ uint32 sr1_control0; /* 0x584 */ ++ uint32 sr1_control1; /* 0x588 */ ++ uint32 PAD[29]; ++ /* PMU registers (corerev >= 20) */ ++ /* Note: all timers driven by ILP clock are updated asynchronously to HT/ALP. ++ * The CPU must read them twice, compare, and retry if different. ++ */ ++ uint32 pmucontrol; /* 0x600 */ ++ uint32 pmucapabilities; ++ uint32 pmustatus; ++ uint32 res_state; ++ uint32 res_pending; ++ uint32 pmutimer; ++ uint32 min_res_mask; ++ uint32 max_res_mask; ++ uint32 res_table_sel; ++ uint32 res_dep_mask; ++ uint32 res_updn_timer; ++ uint32 res_timer; ++ uint32 clkstretch; ++ uint32 pmuwatchdog; ++ uint32 gpiosel; /* 0x638, rev >= 1 */ ++ uint32 gpioenable; /* 0x63c, rev >= 1 */ ++ uint32 res_req_timer_sel; ++ uint32 res_req_timer; ++ uint32 res_req_mask; ++ uint32 core_cap_ext; /* 0x64c */ ++ uint32 chipcontrol_addr; /* 0x650 */ ++ uint32 chipcontrol_data; /* 0x654 */ ++ uint32 regcontrol_addr; ++ uint32 regcontrol_data; ++ uint32 pllcontrol_addr; ++ uint32 pllcontrol_data; ++ uint32 pmustrapopt; /* 0x668, corerev >= 28 */ ++ uint32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ ++ uint32 retention_ctl; /* 0x670 */ ++ uint32 PAD[3]; ++ uint32 retention_grpidx; /* 0x680 */ ++ uint32 retention_grpctl; /* 0x684 */ ++ uint32 PAD[20]; ++ uint32 pmucontrol_ext; /* 0x6d8 */ ++ uint32 slowclkperiod; /* 0x6dc */ ++ uint32 PAD[8]; ++ uint32 pmuintmask0; /* 0x700 */ ++ uint32 pmuintmask1; /* 0x704 */ ++ uint32 PAD[14]; ++ uint32 pmuintstatus; /* 0x740 */ ++ uint32 PAD[15]; ++ uint32 pmuintctrl0; /* 0x780 */ ++ uint32 PAD[31]; ++ uint16 sromotp[512]; /* 0x800 */ ++#ifdef CCNFLASH_SUPPORT ++ /* Nand flash MLC controller registers (corerev >= 38) */ ++ uint32 nand_revision; /* 0xC00 */ ++ uint32 nand_cmd_start; ++ uint32 nand_cmd_addr_x; ++ uint32 nand_cmd_addr; ++ uint32 nand_cmd_end_addr; ++ uint32 nand_cs_nand_select; ++ uint32 nand_cs_nand_xor; ++ uint32 PAD; ++ uint32 nand_spare_rd0; ++ uint32 nand_spare_rd4; ++ uint32 nand_spare_rd8; ++ uint32 nand_spare_rd12; ++ uint32 nand_spare_wr0; ++ uint32 nand_spare_wr4; ++ uint32 nand_spare_wr8; ++ uint32 nand_spare_wr12; ++ uint32 nand_acc_control; ++ uint32 PAD; ++ uint32 nand_config; ++ uint32 PAD; ++ uint32 nand_timing_1; ++ uint32 nand_timing_2; ++ uint32 nand_semaphore; ++ uint32 PAD; ++ uint32 nand_devid; ++ uint32 nand_devid_x; ++ uint32 nand_block_lock_status; ++ uint32 nand_intfc_status; ++ uint32 nand_ecc_corr_addr_x; ++ uint32 nand_ecc_corr_addr; ++ uint32 nand_ecc_unc_addr_x; ++ uint32 nand_ecc_unc_addr; ++ uint32 nand_read_error_count; ++ uint32 nand_corr_stat_threshold; ++ uint32 PAD[2]; ++ uint32 nand_read_addr_x; ++ uint32 nand_read_addr; ++ uint32 nand_page_program_addr_x; ++ uint32 nand_page_program_addr; ++ uint32 nand_copy_back_addr_x; ++ uint32 nand_copy_back_addr; ++ uint32 nand_block_erase_addr_x; ++ uint32 nand_block_erase_addr; ++ uint32 nand_inv_read_addr_x; ++ uint32 nand_inv_read_addr; ++ uint32 PAD[2]; ++ uint32 nand_blk_wr_protect; ++ uint32 PAD[3]; ++ uint32 nand_acc_control_cs1; ++ uint32 nand_config_cs1; ++ uint32 nand_timing_1_cs1; ++ uint32 nand_timing_2_cs1; ++ uint32 PAD[20]; ++ uint32 nand_spare_rd16; ++ uint32 nand_spare_rd20; ++ uint32 nand_spare_rd24; ++ uint32 nand_spare_rd28; ++ uint32 nand_cache_addr; ++ uint32 nand_cache_data; ++ uint32 nand_ctrl_config; ++ uint32 nand_ctrl_status; ++#endif /* CCNFLASH_SUPPORT */ ++ uint32 gci_corecaps0; /* GCI starting at 0xC00 */ ++ uint32 gci_corecaps1; ++ uint32 gci_corecaps2; ++ uint32 gci_corectrl; ++ uint32 gci_corestat; /* 0xC10 */ ++ uint32 gci_intstat; /* 0xC14 */ ++ uint32 gci_intmask; /* 0xC18 */ ++ uint32 gci_wakemask; /* 0xC1C */ ++ uint32 gci_levelintstat; /* 0xC20 */ ++ uint32 gci_eventintstat; /* 0xC24 */ ++ uint32 PAD[6]; ++ uint32 gci_indirect_addr; /* 0xC40 */ ++ uint32 gci_gpioctl; /* 0xC44 */ ++ uint32 gci_gpiostatus; ++ uint32 gci_gpiomask; /* 0xC4C */ ++ uint32 PAD; ++ uint32 gci_miscctl; /* 0xC54 */ ++ uint32 gci_gpiointmask; ++ uint32 gci_gpiowakemask; ++ uint32 gci_input[32]; /* C60 */ ++ uint32 gci_event[32]; /* CE0 */ ++ uint32 gci_output[4]; /* D60 */ ++ uint32 gci_control_0; /* 0xD70 */ ++ uint32 gci_control_1; /* 0xD74 */ ++ uint32 gci_intpolreg; /* 0xD78 */ ++ uint32 gci_levelintmask; /* 0xD7C */ ++ uint32 gci_eventintmask; /* 0xD80 */ ++ uint32 PAD[3]; ++ uint32 gci_inbandlevelintmask; /* 0xD90 */ ++ uint32 gci_inbandeventintmask; /* 0xD94 */ ++ uint32 PAD[2]; ++ uint32 gci_seciauxtx; /* 0xDA0 */ ++ uint32 gci_seciauxrx; /* 0xDA4 */ ++ uint32 gci_secitx_datatag; /* 0xDA8 */ ++ uint32 gci_secirx_datatag; /* 0xDAC */ ++ uint32 gci_secitx_datamask; /* 0xDB0 */ ++ uint32 gci_seciusef0tx_reg; /* 0xDB4 */ ++ uint32 gci_secif0tx_offset; /* 0xDB8 */ ++ uint32 gci_secif0rx_offset; /* 0xDBC */ ++ uint32 gci_secif1tx_offset; /* 0xDC0 */ ++ uint32 gci_rxfifo_common_ctrl; /* 0xDC4 */ ++ uint32 gci_rxfifoctrl; /* 0xDC8 */ ++ uint32 gci_uartreadid; /* DCC */ ++ uint32 gci_seciuartescval; /* DD0 */ ++ uint32 PAD; ++ uint32 gci_secififolevel; /* DD8 */ ++ uint32 gci_seciuartdata; /* DDC */ ++ uint32 gci_secibauddiv; /* DE0 */ ++ uint32 gci_secifcr; /* DE4 */ ++ uint32 gci_secilcr; /* DE8 */ ++ uint32 gci_secimcr; /* DEC */ ++ uint32 gci_secilsr; /* DF0 */ ++ uint32 gci_secimsr; /* DF4 */ ++ uint32 gci_baudadj; /* DF8 */ ++ uint32 PAD; ++ uint32 gci_chipctrl; /* 0xE00 */ ++ uint32 gci_chipsts; /* 0xE04 */ ++ uint32 gci_gpioout; /* 0xE08 */ ++ uint32 gci_gpioout_read; /* 0xE0C */ ++ uint32 gci_mpwaketx; /* 0xE10 */ ++ uint32 gci_mpwakedetect; /* 0xE14 */ ++ uint32 gci_seciin_ctrl; /* 0xE18 */ ++ uint32 gci_seciout_ctrl; /* 0xE1C */ ++ uint32 gci_seciin_auxfifo_en; /* 0xE20 */ ++ uint32 gci_seciout_txen_txbr; /* 0xE24 */ ++ uint32 gci_seciin_rxbrstatus; /* 0xE28 */ ++ uint32 gci_seciin_rxerrstatus; /* 0xE2C */ ++ uint32 gci_seciin_fcstatus; /* 0xE30 */ ++ uint32 gci_seciout_txstatus; /* 0xE34 */ ++ uint32 gci_seciout_txbrstatus; /* 0xE38 */ ++} chipcregs_t; ++ ++#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */ ++ ++ ++#define CC_CHIPID 0 ++#define CC_CAPABILITIES 4 ++#define CC_CHIPST 0x2c ++#define CC_EROMPTR 0xfc ++ ++#define CC_OTPST 0x10 ++#define CC_INTSTATUS 0x20 ++#define CC_INTMASK 0x24 ++#define CC_JTAGCMD 0x30 ++#define CC_JTAGIR 0x34 ++#define CC_JTAGDR 0x38 ++#define CC_JTAGCTRL 0x3c ++#define CC_GPIOPU 0x58 ++#define CC_GPIOPD 0x5c ++#define CC_GPIOIN 0x60 ++#define CC_GPIOOUT 0x64 ++#define CC_GPIOOUTEN 0x68 ++#define CC_GPIOCTRL 0x6c ++#define CC_GPIOPOL 0x70 ++#define CC_GPIOINTM 0x74 ++#define CC_GPIOEVENT 0x78 ++#define CC_GPIOEVENTMASK 0x7c ++#define CC_WATCHDOG 0x80 ++#define CC_GPIOEVENTPOL 0x84 ++#define CC_CLKC_N 0x90 ++#define CC_CLKC_M0 0x94 ++#define CC_CLKC_M1 0x98 ++#define CC_CLKC_M2 0x9c ++#define CC_CLKC_M3 0xa0 ++#define CC_CLKDIV 0xa4 ++#define CC_CAP_EXT 0xac ++#define CC_SYS_CLK_CTL 0xc0 ++#define CC_CLKDIV2 0xf0 ++#define CC_CLK_CTL_ST SI_CLK_CTL_ST ++#define PMU_CTL 0x600 ++#define PMU_CAP 0x604 ++#define PMU_ST 0x608 ++#define PMU_RES_STATE 0x60c ++#define PMU_RES_PENDING 0x610 ++#define PMU_TIMER 0x614 ++#define PMU_MIN_RES_MASK 0x618 ++#define PMU_MAX_RES_MASK 0x61c ++#define CC_CHIPCTL_ADDR 0x650 ++#define CC_CHIPCTL_DATA 0x654 ++#define PMU_REG_CONTROL_ADDR 0x658 ++#define PMU_REG_CONTROL_DATA 0x65C ++#define PMU_PLL_CONTROL_ADDR 0x660 ++#define PMU_PLL_CONTROL_DATA 0x664 ++ ++#define CC_SROM_CTRL 0x190 ++#ifdef SROM16K_4364_ADDRSPACE ++#define CC_SROM_OTP 0xa000 /* SROM/OTP address space */ ++#else ++#define CC_SROM_OTP 0x0800 ++#endif ++#define CC_GCI_INDIRECT_ADDR_REG 0xC40 ++#define CC_GCI_CHIP_CTRL_REG 0xE00 ++#define CC_GCI_CC_OFFSET_2 2 ++#define CC_GCI_CC_OFFSET_5 5 ++#define CC_SWD_CTRL 0x380 ++#define CC_SWD_REQACK 0x384 ++#define CC_SWD_DATA 0x388 ++ ++#define CHIPCTRLREG0 0x0 ++#define CHIPCTRLREG1 0x1 ++#define CHIPCTRLREG2 0x2 ++#define CHIPCTRLREG3 0x3 ++#define CHIPCTRLREG4 0x4 ++#define CHIPCTRLREG5 0x5 ++#define CHIPCTRLREG6 0x6 ++#define REGCTRLREG4 0x4 ++#define REGCTRLREG5 0x5 ++#define REGCTRLREG6 0x6 ++#define MINRESMASKREG 0x618 ++#define MAXRESMASKREG 0x61c ++#define CHIPCTRLADDR 0x650 ++#define CHIPCTRLDATA 0x654 ++#define RSRCTABLEADDR 0x620 ++#define PMU_RES_DEP_MASK 0x624 ++#define RSRCUPDWNTIME 0x628 ++#define PMUREG_RESREQ_MASK 0x68c ++#define PMUREG_RESREQ_TIMER 0x688 ++#define PMUREG_RESREQ_MASK1 0x6f4 ++#define PMUREG_RESREQ_TIMER1 0x6f0 ++#define EXT_LPO_AVAIL 0x100 ++#define LPO_SEL (1 << 0) ++#define CC_EXT_LPO_PU 0x200000 ++#define GC_EXT_LPO_PU 0x2 ++#define CC_INT_LPO_PU 0x100000 ++#define GC_INT_LPO_PU 0x1 ++#define EXT_LPO_SEL 0x8 ++#define INT_LPO_SEL 0x4 ++#define ENABLE_FINE_CBUCK_CTRL (1 << 30) ++#define REGCTRL5_PWM_AUTO_CTRL_MASK 0x007e0000 ++#define REGCTRL5_PWM_AUTO_CTRL_SHIFT 17 ++#define REGCTRL6_PWM_AUTO_CTRL_MASK 0x3fff0000 ++#define REGCTRL6_PWM_AUTO_CTRL_SHIFT 16 ++#define CC_BP_IND_ACCESS_START_SHIFT 9 ++#define CC_BP_IND_ACCESS_START_MASK (1 << CC_BP_IND_ACCESS_START_SHIFT) ++#define CC_BP_IND_ACCESS_RDWR_SHIFT 8 ++#define CC_BP_IND_ACCESS_RDWR_MASK (1 << CC_BP_IND_ACCESS_RDWR_SHIFT) ++#define CC_BP_IND_ACCESS_ERROR_SHIFT 10 ++#define CC_BP_IND_ACCESS_ERROR_MASK (1 << CC_BP_IND_ACCESS_ERROR_SHIFT) ++ ++#ifdef SR_DEBUG ++#define SUBCORE_POWER_ON 0x0001 ++#define PHY_POWER_ON 0x0010 ++#define VDDM_POWER_ON 0x0100 ++#define MEMLPLDO_POWER_ON 0x1000 ++#define SUBCORE_POWER_ON_CHK 0x00040000 ++#define PHY_POWER_ON_CHK 0x00080000 ++#define VDDM_POWER_ON_CHK 0x00100000 ++#define MEMLPLDO_POWER_ON_CHK 0x00200000 ++#endif /* SR_DEBUG */ ++ ++#ifdef CCNFLASH_SUPPORT ++/* NAND flash support */ ++#define CC_NAND_REVISION 0xC00 ++#define CC_NAND_CMD_START 0xC04 ++#define CC_NAND_CMD_ADDR 0xC0C ++#define CC_NAND_SPARE_RD_0 0xC20 ++#define CC_NAND_SPARE_RD_4 0xC24 ++#define CC_NAND_SPARE_RD_8 0xC28 ++#define CC_NAND_SPARE_RD_C 0xC2C ++#define CC_NAND_CONFIG 0xC48 ++#define CC_NAND_DEVID 0xC60 ++#define CC_NAND_DEVID_EXT 0xC64 ++#define CC_NAND_INTFC_STATUS 0xC6C ++#endif /* CCNFLASH_SUPPORT */ ++ ++/* chipid */ ++#define CID_ID_MASK 0x0000ffff /**< Chip Id mask */ ++#define CID_REV_MASK 0x000f0000 /**< Chip Revision mask */ ++#define CID_REV_SHIFT 16 /**< Chip Revision shift */ ++#define CID_PKG_MASK 0x00f00000 /**< Package Option mask */ ++#define CID_PKG_SHIFT 20 /**< Package Option shift */ ++#define CID_CC_MASK 0x0f000000 /**< CoreCount (corerev >= 4) */ ++#define CID_CC_SHIFT 24 ++#define CID_TYPE_MASK 0xf0000000 /**< Chip Type */ ++#define CID_TYPE_SHIFT 28 ++ ++/* capabilities */ ++#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 */ ++#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 */ ++#define CC_CAP_EXTBUS_FULL 0x00000040 /**< ExtBus: PCMCIA, IDE & Prog */ ++#define CC_CAP_EXTBUS_PROG 0x00000080 /**< ExtBus: ProgIf only */ ++#define CC_CAP_FLASH_MASK 0x00000700 /**< Type of flash */ ++#define CC_CAP_PLL_MASK 0x00038000 /**< Type of PLL */ ++#define CC_CAP_PWR_CTL 0x00040000 /**< Power control */ ++#define CC_CAP_OTPSIZE 0x00380000 /**< OTP Size (0 = none) */ ++#define CC_CAP_OTPSIZE_SHIFT 19 /**< OTP Size shift */ ++#define CC_CAP_OTPSIZE_BASE 5 /**< OTP Size base */ ++#define CC_CAP_JTAGP 0x00400000 /**< JTAG Master Present */ ++#define CC_CAP_ROM 0x00800000 /**< Internal boot rom active */ ++#define CC_CAP_BKPLN64 0x08000000 /**< 64-bit backplane */ ++#define CC_CAP_PMU 0x10000000 /**< PMU Present, rev >= 20 */ ++#define CC_CAP_ECI 0x20000000 /**< ECI Present, rev >= 21 */ ++#define CC_CAP_SROM 0x40000000 /**< Srom Present, rev >= 32 */ ++#define CC_CAP_NFLASH 0x80000000 /**< Nand flash present, rev >= 35 */ ++ ++#define CC_CAP2_SECI 0x00000001 /**< SECI Present, rev >= 36 */ ++#define CC_CAP2_GSIO 0x00000002 /**< GSIO (spi/i2c) present, rev >= 37 */ ++ ++/* capabilities extension */ ++#define CC_CAP_EXT_SECI_PRESENT 0x00000001 /**< SECI present */ ++#define CC_CAP_EXT_GSIO_PRESENT 0x00000002 /**< GSIO present */ ++#define CC_CAP_EXT_GCI_PRESENT 0x00000004 /**< GCI present */ ++#define CC_CAP_EXT_SECI_PUART_PRESENT 0x00000008 /**< UART present */ ++#define CC_CAP_EXT_AOB_PRESENT 0x00000040 /**< AOB present */ ++#define CC_CAP_EXT_SWD_PRESENT 0x00000400 /**< SWD present */ ++ ++/* WL Channel Info to BT via GCI - bits 40 - 47 */ ++#define GCI_WL_CHN_INFO_MASK (0xFF00) ++/* WL indication of MCHAN enabled/disabled to BT in awdl mode- bit 36 */ ++#define GCI_WL_MCHAN_BIT_MASK (0x0010) ++/* WL Strobe to BT */ ++#define GCI_WL_STROBE_BIT_MASK (0x0020) ++/* bits [51:48] - reserved for wlan TX pwr index */ ++/* bits [55:52] btc mode indication */ ++#define GCI_WL_BTC_MODE_SHIFT (20) ++#define GCI_WL_BTC_MODE_MASK (0xF << GCI_WL_BTC_MODE_SHIFT) ++#define GCI_WL_ANT_BIT_MASK (0x00c0) ++#define GCI_WL_ANT_SHIFT_BITS (6) ++/* PLL type */ ++#define PLL_NONE 0x00000000 ++#define PLL_TYPE1 0x00010000 /**< 48MHz base, 3 dividers */ ++#define PLL_TYPE2 0x00020000 /**< 48MHz, 4 dividers */ ++#define PLL_TYPE3 0x00030000 /**< 25MHz, 2 dividers */ ++#define PLL_TYPE4 0x00008000 /**< 48MHz, 4 dividers */ ++#define PLL_TYPE5 0x00018000 /**< 25MHz, 4 dividers */ ++#define PLL_TYPE6 0x00028000 /**< 100/200 or 120/240 only */ ++#define PLL_TYPE7 0x00038000 /**< 25MHz, 4 dividers */ ++ ++/* ILP clock */ ++#define ILP_CLOCK 32000 ++ ++/* ALP clock on pre-PMU chips */ ++#define ALP_CLOCK 20000000 ++ ++#ifdef CFG_SIM ++#define NS_ALP_CLOCK 84922 ++#define NS_SLOW_ALP_CLOCK 84922 ++#define NS_CPU_CLOCK 534500 ++#define NS_SLOW_CPU_CLOCK 534500 ++#define NS_SI_CLOCK 271750 ++#define NS_SLOW_SI_CLOCK 271750 ++#define NS_FAST_MEM_CLOCK 271750 ++#define NS_MEM_CLOCK 271750 ++#define NS_SLOW_MEM_CLOCK 271750 ++#else ++#define NS_ALP_CLOCK 125000000 ++#define NS_SLOW_ALP_CLOCK 100000000 ++#define NS_CPU_CLOCK 1000000000 ++#define NS_SLOW_CPU_CLOCK 800000000 ++#define NS_SI_CLOCK 250000000 ++#define NS_SLOW_SI_CLOCK 200000000 ++#define NS_FAST_MEM_CLOCK 800000000 ++#define NS_MEM_CLOCK 533000000 ++#define NS_SLOW_MEM_CLOCK 400000000 ++#endif /* CFG_SIM */ ++ ++#define ALP_CLOCK_53573 40000000 ++ ++/* HT clock */ ++#define HT_CLOCK 80000000 ++ ++/* corecontrol */ ++#define CC_UARTCLKO 0x00000001 /**< Drive UART with internal clock */ ++#define CC_SE 0x00000002 /**< sync clk out enable (corerev >= 3) */ ++#define CC_ASYNCGPIO 0x00000004 /**< 1=generate GPIO interrupt without backplane clock */ ++#define CC_UARTCLKEN 0x00000008 /**< enable UART Clock (corerev > = 21 */ ++ ++/* retention_ctl */ ++#define RCTL_MEM_RET_SLEEP_LOG_SHIFT 29 ++#define RCTL_MEM_RET_SLEEP_LOG_MASK (1 << RCTL_MEM_RET_SLEEP_LOG_SHIFT) ++ ++/* 4321 chipcontrol */ ++#define CHIPCTRL_4321A0_DEFAULT 0x3a4 ++#define CHIPCTRL_4321A1_DEFAULT 0x0a4 ++#define CHIPCTRL_4321_PLL_DOWN 0x800000 /**< serdes PLL down override */ ++ ++/* Fields in the otpstatus register in rev >= 21 */ ++#define OTPS_OL_MASK 0x000000ff ++#define OTPS_OL_MFG 0x00000001 /**< manuf row is locked */ ++#define OTPS_OL_OR1 0x00000002 /**< otp redundancy row 1 is locked */ ++#define OTPS_OL_OR2 0x00000004 /**< otp redundancy row 2 is locked */ ++#define OTPS_OL_GU 0x00000008 /**< general use region is locked */ ++#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 */ ++#define OTPS_READY 0x00001000 ++#define OTPS_RV(x) (1 << (16 + (x))) /**< redundancy entry valid */ ++#define OTPS_RV_MASK 0x0fff0000 ++#define OTPS_PROGOK 0x40000000 ++ ++/* Fields in the otpcontrol register in rev >= 21 */ ++#define OTPC_PROGSEL 0x00000001 ++#define OTPC_PCOUNT_MASK 0x0000000e ++#define OTPC_PCOUNT_SHIFT 1 ++#define OTPC_VSEL_MASK 0x000000f0 ++#define OTPC_VSEL_SHIFT 4 ++#define OTPC_TMM_MASK 0x00000700 ++#define OTPC_TMM_SHIFT 8 ++#define OTPC_ODM 0x00000800 ++#define OTPC_PROGEN 0x80000000 ++ ++/* Fields in the 40nm otpcontrol register in rev >= 40 */ ++#define OTPC_40NM_PROGSEL_SHIFT 0 ++#define OTPC_40NM_PCOUNT_SHIFT 1 ++#define OTPC_40NM_PCOUNT_WR 0xA ++#define OTPC_40NM_PCOUNT_V1X 0xB ++#define OTPC_40NM_REGCSEL_SHIFT 5 ++#define OTPC_40NM_REGCSEL_DEF 0x4 ++#define OTPC_40NM_PROGIN_SHIFT 8 ++#define OTPC_40NM_R2X_SHIFT 10 ++#define OTPC_40NM_ODM_SHIFT 11 ++#define OTPC_40NM_DF_SHIFT 15 ++#define OTPC_40NM_VSEL_SHIFT 16 ++#define OTPC_40NM_VSEL_WR 0xA ++#define OTPC_40NM_VSEL_V1X 0xA ++#define OTPC_40NM_VSEL_R1X 0x5 ++#define OTPC_40NM_COFAIL_SHIFT 30 ++ ++#define OTPC1_CPCSEL_SHIFT 0 ++#define OTPC1_CPCSEL_DEF 6 ++#define OTPC1_TM_SHIFT 8 ++#define OTPC1_TM_WR 0x84 ++#define OTPC1_TM_V1X 0x84 ++#define OTPC1_TM_R1X 0x4 ++#define OTPC1_CLK_EN_MASK 0x00020000 ++#define OTPC1_CLK_DIV_MASK 0x00FC0000 ++ ++/* Fields in otpprog in rev >= 21 and HND OTP */ ++#define OTPP_COL_MASK 0x000000ff ++#define OTPP_COL_SHIFT 0 ++#define OTPP_ROW_MASK 0x0000ff00 ++#define OTPP_ROW_MASK9 0x0001ff00 /* for ccrev >= 49 */ ++#define OTPP_ROW_SHIFT 8 ++#define OTPP_OC_MASK 0x0f000000 ++#define OTPP_OC_SHIFT 24 ++#define OTPP_READERR 0x10000000 ++#define OTPP_VALUE_MASK 0x20000000 ++#define OTPP_VALUE_SHIFT 29 ++#define OTPP_START_BUSY 0x80000000 ++#define OTPP_READ 0x40000000 /* HND OTP */ ++ ++/* Fields in otplayout register */ ++#define OTPL_HWRGN_OFF_MASK 0x00000FFF ++#define OTPL_HWRGN_OFF_SHIFT 0 ++#define OTPL_WRAP_REVID_MASK 0x00F80000 ++#define OTPL_WRAP_REVID_SHIFT 19 ++#define OTPL_WRAP_TYPE_MASK 0x00070000 ++#define OTPL_WRAP_TYPE_SHIFT 16 ++#define OTPL_WRAP_TYPE_65NM 0 ++#define OTPL_WRAP_TYPE_40NM 1 ++#define OTPL_WRAP_TYPE_28NM 2 ++#define OTPL_ROW_SIZE_MASK 0x0000F000 ++#define OTPL_ROW_SIZE_SHIFT 12 ++ ++/* otplayout reg corerev >= 36 */ ++#define OTP_CISFORMAT_NEW 0x80000000 ++ ++/* Opcodes for OTPP_OC field */ ++#define OTPPOC_READ 0 ++#define OTPPOC_BIT_PROG 1 ++#define OTPPOC_VERIFY 3 ++#define OTPPOC_INIT 4 ++#define OTPPOC_SET 5 ++#define OTPPOC_RESET 6 ++#define OTPPOC_OCST 7 ++#define OTPPOC_ROW_LOCK 8 ++#define OTPPOC_PRESCN_TEST 9 ++ ++/* Opcodes for OTPP_OC field (40NM) */ ++#define OTPPOC_READ_40NM 0 ++#define OTPPOC_PROG_ENABLE_40NM 1 ++#define OTPPOC_PROG_DISABLE_40NM 2 ++#define OTPPOC_VERIFY_40NM 3 ++#define OTPPOC_WORD_VERIFY_1_40NM 4 ++#define OTPPOC_ROW_LOCK_40NM 5 ++#define OTPPOC_STBY_40NM 6 ++#define OTPPOC_WAKEUP_40NM 7 ++#define OTPPOC_WORD_VERIFY_0_40NM 8 ++#define OTPPOC_PRESCN_TEST_40NM 9 ++#define OTPPOC_BIT_PROG_40NM 10 ++#define OTPPOC_WORDPROG_40NM 11 ++#define OTPPOC_BURNIN_40NM 12 ++#define OTPPOC_AUTORELOAD_40NM 13 ++#define OTPPOC_OVST_READ_40NM 14 ++#define OTPPOC_OVST_PROG_40NM 15 ++ ++/* Opcodes for OTPP_OC field (28NM) */ ++#define OTPPOC_READ_28NM 0 ++#define OTPPOC_READBURST_28NM 1 ++#define OTPPOC_PROG_ENABLE_28NM 2 ++#define OTPPOC_PROG_DISABLE_28NM 3 ++#define OTPPOC_PRESCREEN_28NM 4 ++#define OTPPOC_PRESCREEN_RP_28NM 5 ++#define OTPPOC_FLUSH_28NM 6 ++#define OTPPOC_NOP_28NM 7 ++#define OTPPOC_PROG_ECC_28NM 8 ++#define OTPPOC_PROG_ECC_READ_28NM 9 ++#define OTPPOC_PROG_28NM 10 ++#define OTPPOC_PROGRAM_RP_28NM 11 ++#define OTPPOC_PROGRAM_OVST_28NM 12 ++#define OTPPOC_RELOAD_28NM 13 ++#define OTPPOC_ERASE_28NM 14 ++#define OTPPOC_LOAD_RF_28NM 15 ++#define OTPPOC_CTRL_WR_28NM 16 ++#define OTPPOC_CTRL_RD_28NM 17 ++#define OTPPOC_READ_HP_28NM 18 ++#define OTPPOC_READ_OVST_28NM 19 ++#define OTPPOC_READ_VERIFY0_28NM 20 ++#define OTPPOC_READ_VERIFY1_28NM 21 ++#define OTPPOC_READ_FORCE0_28NM 22 ++#define OTPPOC_READ_FORCE1_28NM 23 ++#define OTPPOC_BURNIN_28NM 24 ++#define OTPPOC_PROGRAM_LOCK_28NM 25 ++#define OTPPOC_PROGRAM_TESTCOL_28NM 26 ++#define OTPPOC_READ_TESTCOL_28NM 27 ++#define OTPPOC_READ_FOUT_28NM 28 ++#define OTPPOC_SFT_RESET_28NM 29 ++ ++#define OTPP_OC_MASK_28NM 0x0f800000 ++#define OTPP_OC_SHIFT_28NM 23 ++#define OTPC_PROGEN_28NM 0x8 ++#define OTPC_DBLERRCLR 0x20 ++#define OTPC_CLK_EN_MASK 0x00000040 ++#define OTPC_CLK_DIV_MASK 0x00000F80 ++ ++/* Fields in otplayoutextension */ ++#define OTPLAYOUTEXT_FUSE_MASK 0x3FF ++ ++ ++/* Jtagm characteristics that appeared at a given corerev */ ++#define JTAGM_CREV_OLD 10 /**< Old command set, 16bit max IR */ ++#define JTAGM_CREV_IRP 22 /**< Able to do pause-ir */ ++#define JTAGM_CREV_RTI 28 /**< Able to do return-to-idle */ ++ ++/* jtagcmd */ ++#define JCMD_START 0x80000000 ++#define JCMD_BUSY 0x80000000 ++#define JCMD_STATE_MASK 0x60000000 ++#define JCMD_STATE_TLR 0x00000000 /**< Test-logic-reset */ ++#define JCMD_STATE_PIR 0x20000000 /**< Pause IR */ ++#define JCMD_STATE_PDR 0x40000000 /**< Pause DR */ ++#define JCMD_STATE_RTI 0x60000000 /**< Run-test-idle */ ++#define JCMD0_ACC_MASK 0x0000f000 ++#define JCMD0_ACC_IRDR 0x00000000 ++#define JCMD0_ACC_DR 0x00001000 ++#define JCMD0_ACC_IR 0x00002000 ++#define JCMD0_ACC_RESET 0x00003000 ++#define JCMD0_ACC_IRPDR 0x00004000 ++#define JCMD0_ACC_PDR 0x00005000 ++#define JCMD0_IRW_MASK 0x00000f00 ++#define JCMD_ACC_MASK 0x000f0000 /**< Changes for corerev 11 */ ++#define JCMD_ACC_IRDR 0x00000000 ++#define JCMD_ACC_DR 0x00010000 ++#define JCMD_ACC_IR 0x00020000 ++#define JCMD_ACC_RESET 0x00030000 ++#define JCMD_ACC_IRPDR 0x00040000 ++#define JCMD_ACC_PDR 0x00050000 ++#define JCMD_ACC_PIR 0x00060000 ++#define JCMD_ACC_IRDR_I 0x00070000 /**< rev 28: return to run-test-idle */ ++#define JCMD_ACC_DR_I 0x00080000 /**< rev 28: return to run-test-idle */ ++#define JCMD_IRW_MASK 0x00001f00 ++#define JCMD_IRW_SHIFT 8 ++#define JCMD_DRW_MASK 0x0000003f ++ ++/* jtagctrl */ ++#define JCTRL_FORCE_CLK 4 /**< Force clock */ ++#define JCTRL_EXT_EN 2 /**< Enable external targets */ ++#define JCTRL_EN 1 /**< Enable Jtag master */ ++#define JCTRL_TAPSEL_BIT 0x00000008 /**< JtagMasterCtrl tap_sel bit */ ++ ++/* swdmasterctrl */ ++#define SWDCTRL_INT_EN 8 /**< Enable internal targets */ ++#define SWDCTRL_FORCE_CLK 4 /**< Force clock */ ++#define SWDCTRL_OVJTAG 2 /**< Enable shared SWD/JTAG pins */ ++#define SWDCTRL_EN 1 /**< Enable Jtag master */ ++ ++/* Fields in clkdiv */ ++#define CLKD_SFLASH 0x1f000000 ++#define CLKD_SFLASH_SHIFT 24 ++#define CLKD_OTP 0x000f0000 ++#define CLKD_OTP_SHIFT 16 ++#define CLKD_JTAG 0x00000f00 ++#define CLKD_JTAG_SHIFT 8 ++#define CLKD_UART 0x000000ff ++ ++#define CLKD2_SROM 0x00000003 ++#define CLKD2_SWD 0xf8000000 ++#define CLKD2_SWD_SHIFT 27 ++ ++/* intstatus/intmask */ ++#define CI_GPIO 0x00000001 /**< gpio intr */ ++#define CI_EI 0x00000002 /**< extif intr (corerev >= 3) */ ++#define CI_TEMP 0x00000004 /**< temp. ctrl intr (corerev >= 15) */ ++#define CI_SIRQ 0x00000008 /**< serial IRQ intr (corerev >= 15) */ ++#define CI_ECI 0x00000010 /**< eci intr (corerev >= 21) */ ++#define CI_PMU 0x00000020 /**< pmu intr (corerev >= 21) */ ++#define CI_UART 0x00000040 /**< uart intr (corerev >= 21) */ ++#define CI_WDRESET 0x80000000 /**< watchdog reset occurred */ ++ ++/* 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)) */ ++#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)) */ ++#define SYCC_CD_SHIFT 16 ++ ++/* Indirect backplane access */ ++#define BPIA_BYTEEN 0x0000000f ++#define BPIA_SZ1 0x00000001 ++#define BPIA_SZ2 0x00000003 ++#define BPIA_SZ4 0x00000007 ++#define BPIA_SZ8 0x0000000f ++#define BPIA_WRITE 0x00000100 ++#define BPIA_START 0x00000200 ++#define BPIA_BUSY 0x00000200 ++#define BPIA_ERROR 0x00000400 ++ ++/* pcmcia/prog/flash_config */ ++#define CF_EN 0x00000001 /**< enable */ ++#define CF_EM_MASK 0x0000000e /**< mode */ ++#define CF_EM_SHIFT 1 ++#define CF_EM_FLASH 0 /**< flash/asynchronous mode */ ++#define CF_EM_SYNC 2 /**< synchronous mode */ ++#define CF_EM_PCMCIA 4 /**< pcmcia mode */ ++#define CF_DS 0x00000010 /**< destsize: 0=8bit, 1=16bit */ ++#define CF_BS 0x00000020 /**< byteswap */ ++#define CF_CD_MASK 0x000000c0 /**< clock divider */ ++#define CF_CD_SHIFT 6 ++#define CF_CD_DIV2 0x00000000 /**< backplane/2 */ ++#define CF_CD_DIV3 0x00000040 /**< backplane/3 */ ++#define CF_CD_DIV4 0x00000080 /**< backplane/4 */ ++#define CF_CE 0x00000100 /**< clock enable */ ++#define CF_SB 0x00000200 /**< size/bytestrobe (synch only) */ ++ ++/* pcmcia_memwait */ ++#define PM_W0_MASK 0x0000003f /**< waitcount0 */ ++#define PM_W1_MASK 0x00001f00 /**< waitcount1 */ ++#define PM_W1_SHIFT 8 ++#define PM_W2_MASK 0x001f0000 /**< waitcount2 */ ++#define PM_W2_SHIFT 16 ++#define PM_W3_MASK 0x1f000000 /**< waitcount3 */ ++#define PM_W3_SHIFT 24 ++ ++/* pcmcia_attrwait */ ++#define PA_W0_MASK 0x0000003f /**< waitcount0 */ ++#define PA_W1_MASK 0x00001f00 /**< waitcount1 */ ++#define PA_W1_SHIFT 8 ++#define PA_W2_MASK 0x001f0000 /**< waitcount2 */ ++#define PA_W2_SHIFT 16 ++#define PA_W3_MASK 0x1f000000 /**< waitcount3 */ ++#define PA_W3_SHIFT 24 ++ ++/* pcmcia_iowait */ ++#define PI_W0_MASK 0x0000003f /**< waitcount0 */ ++#define PI_W1_MASK 0x00001f00 /**< waitcount1 */ ++#define PI_W1_SHIFT 8 ++#define PI_W2_MASK 0x001f0000 /**< waitcount2 */ ++#define PI_W2_SHIFT 16 ++#define PI_W3_MASK 0x1f000000 /**< waitcount3 */ ++#define PI_W3_SHIFT 24 ++ ++/* prog_waitcount */ ++#define PW_W0_MASK 0x0000001f /**< waitcount0 */ ++#define PW_W1_MASK 0x00001f00 /**< waitcount1 */ ++#define PW_W1_SHIFT 8 ++#define PW_W2_MASK 0x001f0000 /**< waitcount2 */ ++#define PW_W2_SHIFT 16 ++#define PW_W3_MASK 0x1f000000 /**< waitcount3 */ ++#define PW_W3_SHIFT 24 ++ ++#define PW_W0 0x0000000c ++#define PW_W1 0x00000a00 ++#define PW_W2 0x00020000 ++#define PW_W3 0x01000000 ++ ++/* flash_waitcount */ ++#define FW_W0_MASK 0x0000003f /**< waitcount0 */ ++#define FW_W1_MASK 0x00001f00 /**< waitcount1 */ ++#define FW_W1_SHIFT 8 ++#define FW_W2_MASK 0x001f0000 /**< waitcount2 */ ++#define FW_W2_SHIFT 16 ++#define FW_W3_MASK 0x1f000000 /**< waitcount3 */ ++#define FW_W3_SHIFT 24 ++ ++/* 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_OTPPRESENT 0x00000020 ++#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 ++ ++/* Fields in pmucontrol */ ++#define PCTL_ILP_DIV_MASK 0xffff0000 ++#define PCTL_ILP_DIV_SHIFT 16 ++#define PCTL_LQ_REQ_EN 0x00008000 ++#define PCTL_PLL_PLLCTL_UPD 0x00000400 /**< rev 2 */ ++#define PCTL_NOILP_ON_WAIT 0x00000200 /**< rev 1 */ ++#define PCTL_HT_REQ_EN 0x00000100 ++#define PCTL_ALP_REQ_EN 0x00000080 ++#define PCTL_XTALFREQ_MASK 0x0000007c ++#define PCTL_XTALFREQ_SHIFT 2 ++#define PCTL_ILP_DIV_EN 0x00000002 ++#define PCTL_LPO_SEL 0x00000001 ++ ++/* Fields in pmucontrol_ext */ ++#define PCTL_EXT_FASTLPO_ENAB 0x00000080 ++#define PCTL_EXT_FASTLPO_SWENAB 0x00000200 ++#define PCTL_EXT_FASTLPO_PCIE_SWENAB 0x00004000 /**< rev33 for FLL1M */ ++ ++#define DEFAULT_43012_MIN_RES_MASK 0x0f8bfe77 ++ ++/* Retention Control */ ++#define PMU_RCTL_CLK_DIV_SHIFT 0 ++#define PMU_RCTL_CHAIN_LEN_SHIFT 12 ++#define PMU_RCTL_MACPHY_DISABLE_SHIFT 26 ++#define PMU_RCTL_MACPHY_DISABLE_MASK (1 << 26) ++#define PMU_RCTL_LOGIC_DISABLE_SHIFT 27 ++#define PMU_RCTL_LOGIC_DISABLE_MASK (1 << 27) ++#define PMU_RCTL_MEMSLP_LOG_SHIFT 28 ++#define PMU_RCTL_MEMSLP_LOG_MASK (1 << 28) ++#define PMU_RCTL_MEMRETSLP_LOG_SHIFT 29 ++#define PMU_RCTL_MEMRETSLP_LOG_MASK (1 << 29) ++ ++/* Retention Group Control */ ++#define PMU_RCTLGRP_CHAIN_LEN_SHIFT 0 ++#define PMU_RCTLGRP_RMODE_ENABLE_SHIFT 14 ++#define PMU_RCTLGRP_RMODE_ENABLE_MASK (1 << 14) ++#define PMU_RCTLGRP_DFT_ENABLE_SHIFT 15 ++#define PMU_RCTLGRP_DFT_ENABLE_MASK (1 << 15) ++#define PMU_RCTLGRP_NSRST_DISABLE_SHIFT 16 ++#define PMU_RCTLGRP_NSRST_DISABLE_MASK (1 << 16) ++/* Retention Group Control special for 4334 */ ++#define PMU4334_RCTLGRP_CHAIN_LEN_GRP0 338 ++#define PMU4334_RCTLGRP_CHAIN_LEN_GRP1 315 ++/* Retention Group Control special for 43341 */ ++#define PMU43341_RCTLGRP_CHAIN_LEN_GRP0 366 ++#define PMU43341_RCTLGRP_CHAIN_LEN_GRP1 330 ++ ++/* Fields in clkstretch */ ++#define CSTRETCH_HT 0xffff0000 ++#define CSTRETCH_ALP 0x0000ffff ++ ++/* gpiotimerval */ ++#define GPIO_ONTIME_SHIFT 16 ++ ++/* clockcontrol_n */ ++#define CN_N1_MASK 0x3f /**< n1 control */ ++#define CN_N2_MASK 0x3f00 /**< n2 control */ ++#define CN_N2_SHIFT 8 ++#define CN_PLLC_MASK 0xf0000 /**< pll control */ ++#define CN_PLLC_SHIFT 16 ++ ++/* clockcontrol_sb/pci/uart */ ++#define CC_M1_MASK 0x3f /**< m1 control */ ++#define CC_M2_MASK 0x3f00 /**< m2 control */ ++#define CC_M2_SHIFT 8 ++#define CC_M3_MASK 0x3f0000 /**< m3 control */ ++#define CC_M3_SHIFT 16 ++#define CC_MC_MASK 0x1f000000 /**< mux control */ ++#define CC_MC_SHIFT 24 ++ ++/* N3M Clock control magic field values */ ++#define CC_F6_2 0x02 /**< A factor of 2 in */ ++#define CC_F6_3 0x03 /**< 6-bit fields like */ ++#define CC_F6_4 0x05 /**< N1, M1 or M3 */ ++#define CC_F6_5 0x09 ++#define CC_F6_6 0x11 ++#define CC_F6_7 0x21 ++ ++#define CC_F5_BIAS 5 /**< 5-bit fields get this added */ ++ ++#define CC_MC_BYPASS 0x08 ++#define CC_MC_M1 0x04 ++#define CC_MC_M1M2 0x02 ++#define CC_MC_M1M2M3 0x01 ++#define CC_MC_M1M3 0x11 ++ ++/* Type 2 Clock control magic field values */ ++#define CC_T2_BIAS 2 /**< n1, n2, m1 & m3 bias */ ++#define CC_T2M2_BIAS 3 /**< m2 bias */ ++ ++#define CC_T2MC_M1BYP 1 ++#define CC_T2MC_M2BYP 2 ++#define CC_T2MC_M3BYP 4 ++ ++/* Type 6 Clock control magic field values */ ++#define CC_T6_MMASK 1 /**< bits of interest in m */ ++#define CC_T6_M0 120000000 /**< sb clock for m = 0 */ ++#define CC_T6_M1 100000000 /**< sb clock for m = 1 */ ++#define SB2MIPS_T6(sb) (2 * (sb)) ++ ++/* Common clock base */ ++#define CC_CLOCK_BASE1 24000000 /**< Half the clock freq */ ++#define CC_CLOCK_BASE2 12500000 /**< Alternate crystal on some PLLs */ ++ ++/* Clock control values for 200MHz in 5350 */ ++#define CLKC_5350_N 0x0311 ++#define CLKC_5350_M 0x04020009 ++ ++/* Flash types in the chipcommon capabilities register */ ++#define FLASH_NONE 0x000 /**< No flash */ ++#define SFLASH_ST 0x100 /**< ST serial flash */ ++#define SFLASH_AT 0x200 /**< Atmel serial flash */ ++#define NFLASH 0x300 ++#define PFLASH 0x700 /**< Parallel flash */ ++#define QSPIFLASH_ST 0x800 ++#define QSPIFLASH_AT 0x900 ++ ++/* Bits in the ExtBus config registers */ ++#define CC_CFG_EN 0x0001 /**< Enable */ ++#define CC_CFG_EM_MASK 0x000e /**< Extif Mode */ ++#define CC_CFG_EM_ASYNC 0x0000 /**< Async/Parallel flash */ ++#define CC_CFG_EM_SYNC 0x0002 /**< Synchronous */ ++#define CC_CFG_EM_PCMCIA 0x0004 /**< PCMCIA */ ++#define CC_CFG_EM_IDE 0x0006 /**< IDE */ ++#define CC_CFG_DS 0x0010 /**< Data size, 0=8bit, 1=16bit */ ++#define CC_CFG_CD_MASK 0x00e0 /**< Sync: Clock divisor, rev >= 20 */ ++#define CC_CFG_CE 0x0100 /**< Sync: Clock enable, rev >= 20 */ ++#define CC_CFG_SB 0x0200 /**< Sync: Size/Bytestrobe, rev >= 20 */ ++#define CC_CFG_IS 0x0400 /**< Extif Sync Clk Select, rev >= 20 */ ++ ++/* ExtBus address space */ ++#define CC_EB_BASE 0x1a000000 /**< Chipc ExtBus base address */ ++#define CC_EB_PCMCIA_MEM 0x1a000000 /**< PCMCIA 0 memory base address */ ++#define CC_EB_PCMCIA_IO 0x1a200000 /**< PCMCIA 0 I/O base address */ ++#define CC_EB_PCMCIA_CFG 0x1a400000 /**< PCMCIA 0 config base address */ ++#define CC_EB_IDE 0x1a800000 /**< IDE memory base */ ++#define CC_EB_PCMCIA1_MEM 0x1a800000 /**< PCMCIA 1 memory base address */ ++#define CC_EB_PCMCIA1_IO 0x1aa00000 /**< PCMCIA 1 I/O base address */ ++#define CC_EB_PCMCIA1_CFG 0x1ac00000 /**< PCMCIA 1 config base address */ ++#define CC_EB_PROGIF 0x1b000000 /**< ProgIF Async/Sync base address */ ++ ++ ++/* Start/busy bit in flashcontrol */ ++#define SFLASH_OPCODE 0x000000ff ++#define SFLASH_ACTION 0x00000700 ++#define SFLASH_CS_ACTIVE 0x00001000 /**< Chip Select Active, rev >= 20 */ ++#define SFLASH_START 0x80000000 ++#define SFLASH_BUSY SFLASH_START ++ ++/* flashcontrol action codes */ ++#define SFLASH_ACT_OPONLY 0x0000 /**< Issue opcode only */ ++#define SFLASH_ACT_OP1D 0x0100 /**< opcode + 1 data byte */ ++#define SFLASH_ACT_OP3A 0x0200 /**< opcode + 3 addr bytes */ ++#define SFLASH_ACT_OP3A1D 0x0300 /**< opcode + 3 addr & 1 data bytes */ ++#define SFLASH_ACT_OP3A4D 0x0400 /**< opcode + 3 addr & 4 data bytes */ ++#define SFLASH_ACT_OP3A4X4D 0x0500 /**< opcode + 3 addr, 4 don't care & 4 data bytes */ ++#define SFLASH_ACT_OP3A1X4D 0x0700 /**< opcode + 3 addr, 1 don't care & 4 data bytes */ ++ ++/* flashcontrol action+opcodes for ST flashes */ ++#define SFLASH_ST_WREN 0x0006 /**< Write Enable */ ++#define SFLASH_ST_WRDIS 0x0004 /**< Write Disable */ ++#define SFLASH_ST_RDSR 0x0105 /**< Read Status Register */ ++#define SFLASH_ST_WRSR 0x0101 /**< Write Status Register */ ++#define SFLASH_ST_READ 0x0303 /**< Read Data Bytes */ ++#define SFLASH_ST_PP 0x0302 /**< Page Program */ ++#define SFLASH_ST_SE 0x02d8 /**< Sector Erase */ ++#define SFLASH_ST_BE 0x00c7 /**< Bulk Erase */ ++#define SFLASH_ST_DP 0x00b9 /**< Deep Power-down */ ++#define SFLASH_ST_RES 0x03ab /**< Read Electronic Signature */ ++#define SFLASH_ST_CSA 0x1000 /**< Keep chip select asserted */ ++#define SFLASH_ST_SSE 0x0220 /**< Sub-sector Erase */ ++ ++#define SFLASH_ST_READ4B 0x6313 /* Read Data Bytes in 4Byte address */ ++#define SFLASH_ST_PP4B 0x6312 /* Page Program in 4Byte address */ ++#define SFLASH_ST_SE4B 0x62dc /* Sector Erase in 4Byte address */ ++#define SFLASH_ST_SSE4B 0x6221 /* Sub-sector Erase */ ++ ++#define SFLASH_MXIC_RDID 0x0390 /* Read Manufacture ID */ ++#define SFLASH_MXIC_MFID 0xc2 /* MXIC Manufacture ID */ ++ ++/* Status register bits for ST flashes */ ++#define SFLASH_ST_WIP 0x01 /**< Write In Progress */ ++#define SFLASH_ST_WEL 0x02 /**< Write Enable Latch */ ++#define SFLASH_ST_BP_MASK 0x1c /**< Block Protect */ ++#define SFLASH_ST_BP_SHIFT 2 ++#define SFLASH_ST_SRWD 0x80 /**< Status Register Write Disable */ ++ ++/* flashcontrol action+opcodes for Atmel flashes */ ++#define SFLASH_AT_READ 0x07e8 ++#define SFLASH_AT_PAGE_READ 0x07d2 ++#define SFLASH_AT_BUF1_READ ++#define SFLASH_AT_BUF2_READ ++#define SFLASH_AT_STATUS 0x01d7 ++#define SFLASH_AT_BUF1_WRITE 0x0384 ++#define SFLASH_AT_BUF2_WRITE 0x0387 ++#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283 ++#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286 ++#define SFLASH_AT_BUF1_PROGRAM 0x0288 ++#define SFLASH_AT_BUF2_PROGRAM 0x0289 ++#define SFLASH_AT_PAGE_ERASE 0x0281 ++#define SFLASH_AT_BLOCK_ERASE 0x0250 ++#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 ++#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 ++#define SFLASH_AT_BUF1_LOAD 0x0253 ++#define SFLASH_AT_BUF2_LOAD 0x0255 ++#define SFLASH_AT_BUF1_COMPARE 0x0260 ++#define SFLASH_AT_BUF2_COMPARE 0x0261 ++#define SFLASH_AT_BUF1_REPROGRAM 0x0258 ++#define SFLASH_AT_BUF2_REPROGRAM 0x0259 ++ ++/* Status register bits for Atmel flashes */ ++#define SFLASH_AT_READY 0x80 ++#define SFLASH_AT_MISMATCH 0x40 ++#define SFLASH_AT_ID_MASK 0x38 ++#define SFLASH_AT_ID_SHIFT 3 ++ ++/* SPI register bits, corerev >= 37 */ ++#define GSIO_START 0x80000000 ++#define GSIO_BUSY GSIO_START ++ ++/* ++ * These are the UART port assignments, expressed as offsets from the base ++ * register. These assignments should hold for any serial port based on ++ * a 8250, 16450, or 16550(A). ++ */ ++ ++#define UART_RX 0 /**< In: Receive buffer (DLAB=0) */ ++#define UART_TX 0 /**< Out: Transmit buffer (DLAB=0) */ ++#define UART_DLL 0 /**< Out: Divisor Latch Low (DLAB=1) */ ++#define UART_IER 1 /**< In/Out: Interrupt Enable Register (DLAB=0) */ ++#define UART_DLM 1 /**< Out: Divisor Latch High (DLAB=1) */ ++#define UART_IIR 2 /**< In: Interrupt Identity Register */ ++#define UART_FCR 2 /**< Out: FIFO Control Register */ ++#define UART_LCR 3 /**< Out: Line Control Register */ ++#define UART_MCR 4 /**< Out: Modem Control Register */ ++#define UART_LSR 5 /**< In: Line Status Register */ ++#define UART_MSR 6 /**< In: Modem Status Register */ ++#define UART_SCR 7 /**< I/O: Scratch Register */ ++#define UART_LCR_DLAB 0x80 /**< Divisor latch access bit */ ++#define UART_LCR_WLEN8 0x03 /**< Word length: 8 bits */ ++#define UART_MCR_OUT2 0x08 /**< MCR GPIO out 2 */ ++#define UART_MCR_LOOP 0x10 /**< Enable loopback test mode */ ++#define UART_LSR_RX_FIFO 0x80 /**< Receive FIFO error */ ++#define UART_LSR_TDHR 0x40 /**< Data-hold-register empty */ ++#define UART_LSR_THRE 0x20 /**< Transmit-hold-register empty */ ++#define UART_LSR_BREAK 0x10 /**< Break interrupt */ ++#define UART_LSR_FRAMING 0x08 /**< Framing error */ ++#define UART_LSR_PARITY 0x04 /**< Parity error */ ++#define UART_LSR_OVERRUN 0x02 /**< Overrun error */ ++#define UART_LSR_RXRDY 0x01 /**< Receiver ready */ ++#define UART_FCR_FIFO_ENABLE 1 /**< FIFO control register bit controlling FIFO enable/disable */ ++ ++/* Interrupt Identity Register (IIR) bits */ ++#define UART_IIR_FIFO_MASK 0xc0 /**< IIR FIFO disable/enabled mask */ ++#define UART_IIR_INT_MASK 0xf /**< IIR interrupt ID source */ ++#define UART_IIR_MDM_CHG 0x0 /**< Modem status changed */ ++#define UART_IIR_NOINT 0x1 /**< No interrupt pending */ ++#define UART_IIR_THRE 0x2 /**< THR empty */ ++#define UART_IIR_RCVD_DATA 0x4 /**< Received data available */ ++#define UART_IIR_RCVR_STATUS 0x6 /**< Receiver status */ ++#define UART_IIR_CHAR_TIME 0xc /**< Character time */ ++ ++/* Interrupt Enable Register (IER) bits */ ++#define UART_IER_PTIME 128 /**< Programmable THRE Interrupt Mode Enable */ ++#define UART_IER_EDSSI 8 /**< enable modem status interrupt */ ++#define UART_IER_ELSI 4 /**< enable receiver line status interrupt */ ++#define UART_IER_ETBEI 2 /**< enable transmitter holding register empty interrupt */ ++#define UART_IER_ERBFI 1 /**< enable data available interrupt */ ++ ++/* pmustatus */ ++#define PST_SLOW_WR_PENDING 0x0400 ++#define PST_EXTLPOAVAIL 0x0100 ++#define PST_WDRESET 0x0080 ++#define PST_INTPEND 0x0040 ++#define PST_SBCLKST 0x0030 ++#define PST_SBCLKST_ILP 0x0010 ++#define PST_SBCLKST_ALP 0x0020 ++#define PST_SBCLKST_HT 0x0030 ++#define PST_ALPAVAIL 0x0008 ++#define PST_HTAVAIL 0x0004 ++#define PST_RESINIT 0x0003 ++#define PST_ILPFASTLPO 0x00010000 ++ ++/* pmucapabilities */ ++#define PCAP_REV_MASK 0x000000ff ++#define PCAP_RC_MASK 0x00001f00 ++#define PCAP_RC_SHIFT 8 ++#define PCAP_TC_MASK 0x0001e000 ++#define PCAP_TC_SHIFT 13 ++#define PCAP_PC_MASK 0x001e0000 ++#define PCAP_PC_SHIFT 17 ++#define PCAP_VC_MASK 0x01e00000 ++#define PCAP_VC_SHIFT 21 ++#define PCAP_CC_MASK 0x1e000000 ++#define PCAP_CC_SHIFT 25 ++#define PCAP5_PC_MASK 0x003e0000 /**< PMU corerev >= 5 */ ++#define PCAP5_PC_SHIFT 17 ++#define PCAP5_VC_MASK 0x07c00000 ++#define PCAP5_VC_SHIFT 22 ++#define PCAP5_CC_MASK 0xf8000000 ++#define PCAP5_CC_SHIFT 27 ++ ++/* CoreCapabilitiesExtension */ ++#define PCAP_EXT_USE_MUXED_ILP_CLK_MASK 0x04000000 ++ ++/* PMU Resource Request Timer registers */ ++/* This is based on PmuRev0 */ ++#define PRRT_TIME_MASK 0x03ff ++#define PRRT_INTEN 0x0400 ++#define PRRT_REQ_ACTIVE 0x0800 ++#define PRRT_ALP_REQ 0x1000 ++#define PRRT_HT_REQ 0x2000 ++#define PRRT_HQ_REQ 0x4000 ++ ++/* PMU Int Control register bits */ ++#define PMU_INTC_ALP_REQ 0x1 ++#define PMU_INTC_HT_REQ 0x2 ++#define PMU_INTC_HQ_REQ 0x4 ++ ++/* bit 0 of the PMU interrupt vector is asserted if this mask is enabled */ ++#define RSRC_INTR_MASK_TIMER_INT_0 1 ++ ++/* PMU resource bit position */ ++#define PMURES_BIT(bit) (1 << (bit)) ++ ++/* PMU resource number limit */ ++#define PMURES_MAX_RESNUM 30 ++ ++/* PMU chip control0 register */ ++#define PMU_CHIPCTL0 0 ++#define PMU43143_CC0_SDIO_DRSTR_OVR (1 << 31) /* sdio drive strength override enable */ ++ ++/* clock req types */ ++#define PMU_CC1_CLKREQ_TYPE_SHIFT 19 ++#define PMU_CC1_CLKREQ_TYPE_MASK (1 << PMU_CC1_CLKREQ_TYPE_SHIFT) ++ ++#define CLKREQ_TYPE_CONFIG_OPENDRAIN 0 ++#define CLKREQ_TYPE_CONFIG_PUSHPULL 1 ++ ++/* PMU chip control1 register */ ++#define PMU_CHIPCTL1 1 ++#define PMU_CC1_RXC_DLL_BYPASS 0x00010000 ++#define PMU_CC1_ENABLE_BBPLL_PWR_DOWN 0x00000010 ++ ++#define PMU_CC1_IF_TYPE_MASK 0x00000030 ++#define PMU_CC1_IF_TYPE_RMII 0x00000000 ++#define PMU_CC1_IF_TYPE_MII 0x00000010 ++#define PMU_CC1_IF_TYPE_RGMII 0x00000020 ++ ++#define PMU_CC1_SW_TYPE_MASK 0x000000c0 ++#define PMU_CC1_SW_TYPE_EPHY 0x00000000 ++#define PMU_CC1_SW_TYPE_EPHYMII 0x00000040 ++#define PMU_CC1_SW_TYPE_EPHYRMII 0x00000080 ++#define PMU_CC1_SW_TYPE_RGMII 0x000000c0 ++ ++#define PMU_CC1_ENABLE_CLOSED_LOOP_MASK 0x00000080 ++#define PMU_CC1_ENABLE_CLOSED_LOOP 0x00000000 ++ ++/* PMU chip control2 register */ ++#define PMU_CC2_RFLDO3P3_PU_FORCE_ON (1 << 15) ++#define PMU_CC2_RFLDO3P3_PU_CLEAR 0x00000000 ++ ++#define PMU_CC2_WL2CDIG_I_PMU_SLEEP (1 << 16) ++#define PMU_CHIPCTL2 2 ++#define PMU_CC2_FORCE_SUBCORE_PWR_SWITCH_ON (1 << 18) ++#define PMU_CC2_FORCE_PHY_PWR_SWITCH_ON (1 << 19) ++#define PMU_CC2_FORCE_VDDM_PWR_SWITCH_ON (1 << 20) ++#define PMU_CC2_FORCE_MEMLPLDO_PWR_SWITCH_ON (1 << 21) ++#define PMU_CC2_MASK_WL_DEV_WAKE (1 << 22) ++#define PMU_CC2_INV_GPIO_POLARITY_PMU_WAKE (1 << 25) ++#define PMU_CC2_GCI2_WAKE (1 << 31) ++ ++/* PMU chip control3 register */ ++#define PMU_CHIPCTL3 3 ++#define PMU_CC3_ENABLE_SDIO_WAKEUP_SHIFT 19 ++#define PMU_CC3_ENABLE_RF_SHIFT 22 ++#define PMU_CC3_RF_DISABLE_IVALUE_SHIFT 23 ++ ++/* PMU chip control4 register */ ++#define PMU_CHIPCTL4 4 ++ ++/* 53537 series moved switch_type and gmac_if_type to CC4 [15:14] and [13:12] */ ++#define PMU_CC4_IF_TYPE_MASK 0x00003000 ++#define PMU_CC4_IF_TYPE_RMII 0x00000000 ++#define PMU_CC4_IF_TYPE_MII 0x00001000 ++#define PMU_CC4_IF_TYPE_RGMII 0x00002000 ++ ++#define PMU_CC4_SW_TYPE_MASK 0x0000c000 ++#define PMU_CC4_SW_TYPE_EPHY 0x00000000 ++#define PMU_CC4_SW_TYPE_EPHYMII 0x00004000 ++#define PMU_CC4_SW_TYPE_EPHYRMII 0x00008000 ++#define PMU_CC4_SW_TYPE_RGMII 0x0000c000 ++#define PMU_CC4_DISABLE_LQ_AVAIL (1<<27) ++ ++/* PMU chip control5 register */ ++#define PMU_CHIPCTL5 5 ++ ++/* PMU chip control6 register */ ++#define PMU_CHIPCTL6 6 ++#define PMU_CC6_ENABLE_CLKREQ_WAKEUP (1 << 4) ++#define PMU_CC6_ENABLE_PMU_WAKEUP_ALP (1 << 6) ++ ++/* PMU chip control7 register */ ++#define PMU_CHIPCTL7 7 ++#define PMU_CC7_ENABLE_L2REFCLKPAD_PWRDWN (1 << 25) ++#define PMU_CC7_ENABLE_MDIO_RESET_WAR (1 << 27) ++/* 53537 series have gmca1 gmac_if_type in cc7 [7:6](defalut 0b01) */ ++#define PMU_CC7_IF_TYPE_MASK 0x000000c0 ++#define PMU_CC7_IF_TYPE_RMII 0x00000000 ++#define PMU_CC7_IF_TYPE_MII 0x00000040 ++#define PMU_CC7_IF_TYPE_RGMII 0x00000080 ++ ++#define PMU_CHIPCTL8 8 ++#define PMU_CHIPCTL9 9 ++ ++/* PMU corerev and chip specific PLL controls. ++ * PMU_PLL_XX where is PMU corerev and is an arbitrary number ++ * to differentiate different PLLs controlled by the same PMU rev. ++ */ ++/* pllcontrol registers */ ++/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */ ++#define PMU0_PLL0_PLLCTL0 0 ++#define PMU0_PLL0_PC0_PDIV_MASK 1 ++#define PMU0_PLL0_PC0_PDIV_FREQ 25000 ++#define PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038 ++#define PMU0_PLL0_PC0_DIV_ARM_SHIFT 3 ++#define PMU0_PLL0_PC0_DIV_ARM_BASE 8 ++ ++/* PC0_DIV_ARM for PLLOUT_ARM */ ++#define PMU0_PLL0_PC0_DIV_ARM_110MHZ 0 ++#define PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1 ++#define PMU0_PLL0_PC0_DIV_ARM_88MHZ 2 ++#define PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */ ++#define PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4 ++#define PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5 ++#define PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6 ++#define PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7 ++ ++/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */ ++#define PMU0_PLL0_PLLCTL1 1 ++#define PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000 ++#define PMU0_PLL0_PC1_WILD_INT_SHIFT 28 ++#define PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00 ++#define PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8 ++#define PMU0_PLL0_PC1_STOP_MOD 0x00000040 ++ ++/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */ ++#define PMU0_PLL0_PLLCTL2 2 ++#define PMU0_PLL0_PC2_WILD_INT_MASK 0xf ++#define PMU0_PLL0_PC2_WILD_INT_SHIFT 4 ++ ++/* pllcontrol registers */ ++/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ ++#define PMU1_PLL0_PLLCTL0 0 ++#define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 ++#define PMU1_PLL0_PC0_P1DIV_SHIFT 20 ++#define PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000 ++#define PMU1_PLL0_PC0_P2DIV_SHIFT 24 ++ ++/* mdiv */ ++#define PMU1_PLL0_PLLCTL1 1 ++#define PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff ++#define PMU1_PLL0_PC1_M1DIV_SHIFT 0 ++#define PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00 ++#define PMU1_PLL0_PC1_M2DIV_SHIFT 8 ++#define PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000 ++#define PMU1_PLL0_PC1_M3DIV_SHIFT 16 ++#define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 ++#define PMU1_PLL0_PC1_M4DIV_SHIFT 24 ++#define PMU1_PLL0_PC1_M4DIV_BY_9 9 ++#define PMU1_PLL0_PC1_M4DIV_BY_18 0x12 ++#define PMU1_PLL0_PC1_M4DIV_BY_36 0x24 ++#define PMU1_PLL0_PC1_M4DIV_BY_60 0x3C ++ ++#define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 ++#define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) ++#define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) ++ ++/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ ++#define PMU1_PLL0_PLLCTL2 2 ++#define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff ++#define PMU1_PLL0_PC2_M5DIV_SHIFT 0 ++#define PMU1_PLL0_PC2_M5DIV_BY_12 0xc ++#define PMU1_PLL0_PC2_M5DIV_BY_18 0x12 ++#define PMU1_PLL0_PC2_M5DIV_BY_31 0x1f ++#define PMU1_PLL0_PC2_M5DIV_BY_36 0x24 ++#define PMU1_PLL0_PC2_M5DIV_BY_42 0x2a ++#define PMU1_PLL0_PC2_M5DIV_BY_60 0x3c ++#define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 ++#define PMU1_PLL0_PC2_M6DIV_SHIFT 8 ++#define PMU1_PLL0_PC2_M6DIV_BY_18 0x12 ++#define PMU1_PLL0_PC2_M6DIV_BY_36 0x24 ++#define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 ++#define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 ++#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1 ++#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /**< recommended for 4319 */ ++#define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 ++#define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 ++ ++/* ndiv_frac */ ++#define PMU1_PLL0_PLLCTL3 3 ++#define PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff ++#define PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0 ++ ++/* pll_ctrl */ ++#define PMU1_PLL0_PLLCTL4 4 ++ ++/* pll_ctrl, vco_rng, clkdrive_ch */ ++#define PMU1_PLL0_PLLCTL5 5 ++#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00 ++#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8 ++#define PMU1_PLL0_PC5_ASSERT_CH_MASK 0x3f000000 ++#define PMU1_PLL0_PC5_ASSERT_CH_SHIFT 24 ++#define PMU1_PLL0_PC5_DEASSERT_CH_MASK 0xff000000 ++ ++#define PMU1_PLL0_PLLCTL6 6 ++#define PMU1_PLL0_PLLCTL7 7 ++#define PMU1_PLL0_PLLCTL8 8 ++ ++#define PMU1_PLLCTL8_OPENLOOP_MASK (1 << 1) ++#define PMU_PLL4350_OPENLOOP_MASK (1 << 7) ++ ++#define PMU1_PLL0_PLLCTL9 9 ++ ++#define PMU1_PLL0_PLLCTL10 10 ++ ++/* PMU rev 2 control words */ ++#define PMU2_PHY_PLL_PLLCTL 4 ++#define PMU2_SI_PLL_PLLCTL 10 ++ ++/* PMU rev 2 */ ++/* pllcontrol registers */ ++/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ ++#define PMU2_PLL_PLLCTL0 0 ++#define PMU2_PLL_PC0_P1DIV_MASK 0x00f00000 ++#define PMU2_PLL_PC0_P1DIV_SHIFT 20 ++#define PMU2_PLL_PC0_P2DIV_MASK 0x0f000000 ++#define PMU2_PLL_PC0_P2DIV_SHIFT 24 ++ ++/* mdiv */ ++#define PMU2_PLL_PLLCTL1 1 ++#define PMU2_PLL_PC1_M1DIV_MASK 0x000000ff ++#define PMU2_PLL_PC1_M1DIV_SHIFT 0 ++#define PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00 ++#define PMU2_PLL_PC1_M2DIV_SHIFT 8 ++#define PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000 ++#define PMU2_PLL_PC1_M3DIV_SHIFT 16 ++#define PMU2_PLL_PC1_M4DIV_MASK 0xff000000 ++#define PMU2_PLL_PC1_M4DIV_SHIFT 24 ++ ++/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ ++#define PMU2_PLL_PLLCTL2 2 ++#define PMU2_PLL_PC2_M5DIV_MASK 0x000000ff ++#define PMU2_PLL_PC2_M5DIV_SHIFT 0 ++#define PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00 ++#define PMU2_PLL_PC2_M6DIV_SHIFT 8 ++#define PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000 ++#define PMU2_PLL_PC2_NDIV_MODE_SHIFT 17 ++#define PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000 ++#define PMU2_PLL_PC2_NDIV_INT_SHIFT 20 ++ ++/* ndiv_frac */ ++#define PMU2_PLL_PLLCTL3 3 ++#define PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff ++#define PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0 ++ ++/* pll_ctrl */ ++#define PMU2_PLL_PLLCTL4 4 ++ ++/* pll_ctrl, vco_rng, clkdrive_ch */ ++#define PMU2_PLL_PLLCTL5 5 ++#define PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00 ++#define PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8 ++#define PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12 ++#define PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16 ++#define PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20 ++#define PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24 ++#define PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000 ++#define PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28 ++ ++/* PMU rev 5 (& 6) */ ++#define PMU5_PLL_P1P2_OFF 0 ++#define PMU5_PLL_P1_MASK 0x0f000000 ++#define PMU5_PLL_P1_SHIFT 24 ++#define PMU5_PLL_P2_MASK 0x00f00000 ++#define PMU5_PLL_P2_SHIFT 20 ++#define PMU5_PLL_M14_OFF 1 ++#define PMU5_PLL_MDIV_MASK 0x000000ff ++#define PMU5_PLL_MDIV_WIDTH 8 ++#define PMU5_PLL_NM5_OFF 2 ++#define PMU5_PLL_NDIV_MASK 0xfff00000 ++#define PMU5_PLL_NDIV_SHIFT 20 ++#define PMU5_PLL_NDIV_MODE_MASK 0x000e0000 ++#define PMU5_PLL_NDIV_MODE_SHIFT 17 ++#define PMU5_PLL_FMAB_OFF 3 ++#define PMU5_PLL_MRAT_MASK 0xf0000000 ++#define PMU5_PLL_MRAT_SHIFT 28 ++#define PMU5_PLL_ABRAT_MASK 0x08000000 ++#define PMU5_PLL_ABRAT_SHIFT 27 ++#define PMU5_PLL_FDIV_MASK 0x07ffffff ++#define PMU5_PLL_PLLCTL_OFF 4 ++#define PMU5_PLL_PCHI_OFF 5 ++#define PMU5_PLL_PCHI_MASK 0x0000003f ++ ++/* pmu XtalFreqRatio */ ++#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF ++#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 ++#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 ++ ++/* Divider allocation in 4716/47162/5356/5357 */ ++#define PMU5_MAINPLL_CPU 1 ++#define PMU5_MAINPLL_MEM 2 ++#define PMU5_MAINPLL_SI 3 ++ ++/* 4706 PMU */ ++#define PMU4706_MAINPLL_PLL0 0 ++#define PMU6_4706_PROCPLL_OFF 4 /**< The CPU PLL */ ++#define PMU6_4706_PROC_P2DIV_MASK 0x000f0000 ++#define PMU6_4706_PROC_P2DIV_SHIFT 16 ++#define PMU6_4706_PROC_P1DIV_MASK 0x0000f000 ++#define PMU6_4706_PROC_P1DIV_SHIFT 12 ++#define PMU6_4706_PROC_NDIV_INT_MASK 0x00000ff8 ++#define PMU6_4706_PROC_NDIV_INT_SHIFT 3 ++#define PMU6_4706_PROC_NDIV_MODE_MASK 0x00000007 ++#define PMU6_4706_PROC_NDIV_MODE_SHIFT 0 ++ ++#define PMU7_PLL_PLLCTL7 7 ++#define PMU7_PLL_CTL7_M4DIV_MASK 0xff000000 ++#define PMU7_PLL_CTL7_M4DIV_SHIFT 24 ++#define PMU7_PLL_CTL7_M4DIV_BY_6 6 ++#define PMU7_PLL_CTL7_M4DIV_BY_12 0xc ++#define PMU7_PLL_CTL7_M4DIV_BY_24 0x18 ++#define PMU7_PLL_PLLCTL8 8 ++#define PMU7_PLL_CTL8_M5DIV_MASK 0x000000ff ++#define PMU7_PLL_CTL8_M5DIV_SHIFT 0 ++#define PMU7_PLL_CTL8_M5DIV_BY_8 8 ++#define PMU7_PLL_CTL8_M5DIV_BY_12 0xc ++#define PMU7_PLL_CTL8_M5DIV_BY_24 0x18 ++#define PMU7_PLL_CTL8_M6DIV_MASK 0x0000ff00 ++#define PMU7_PLL_CTL8_M6DIV_SHIFT 8 ++#define PMU7_PLL_CTL8_M6DIV_BY_12 0xc ++#define PMU7_PLL_CTL8_M6DIV_BY_24 0x18 ++#define PMU7_PLL_PLLCTL11 11 ++#define PMU7_PLL_PLLCTL11_MASK 0xffffff00 ++#define PMU7_PLL_PLLCTL11_VAL 0x22222200 ++ ++/* PMU rev 15 */ ++#define PMU15_PLL_PLLCTL0 0 ++#define PMU15_PLL_PC0_CLKSEL_MASK 0x00000003 ++#define PMU15_PLL_PC0_CLKSEL_SHIFT 0 ++#define PMU15_PLL_PC0_FREQTGT_MASK 0x003FFFFC ++#define PMU15_PLL_PC0_FREQTGT_SHIFT 2 ++#define PMU15_PLL_PC0_PRESCALE_MASK 0x00C00000 ++#define PMU15_PLL_PC0_PRESCALE_SHIFT 22 ++#define PMU15_PLL_PC0_KPCTRL_MASK 0x07000000 ++#define PMU15_PLL_PC0_KPCTRL_SHIFT 24 ++#define PMU15_PLL_PC0_FCNTCTRL_MASK 0x38000000 ++#define PMU15_PLL_PC0_FCNTCTRL_SHIFT 27 ++#define PMU15_PLL_PC0_FDCMODE_MASK 0x40000000 ++#define PMU15_PLL_PC0_FDCMODE_SHIFT 30 ++#define PMU15_PLL_PC0_CTRLBIAS_MASK 0x80000000 ++#define PMU15_PLL_PC0_CTRLBIAS_SHIFT 31 ++ ++#define PMU15_PLL_PLLCTL1 1 ++#define PMU15_PLL_PC1_BIAS_CTLM_MASK 0x00000060 ++#define PMU15_PLL_PC1_BIAS_CTLM_SHIFT 5 ++#define PMU15_PLL_PC1_BIAS_CTLM_RST_MASK 0x00000040 ++#define PMU15_PLL_PC1_BIAS_CTLM_RST_SHIFT 6 ++#define PMU15_PLL_PC1_BIAS_SS_DIVR_MASK 0x0001FF80 ++#define PMU15_PLL_PC1_BIAS_SS_DIVR_SHIFT 7 ++#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_MASK 0x03FE0000 ++#define PMU15_PLL_PC1_BIAS_SS_RSTVAL_SHIFT 17 ++#define PMU15_PLL_PC1_BIAS_INTG_BW_MASK 0x0C000000 ++#define PMU15_PLL_PC1_BIAS_INTG_BW_SHIFT 26 ++#define PMU15_PLL_PC1_BIAS_INTG_BYP_MASK 0x10000000 ++#define PMU15_PLL_PC1_BIAS_INTG_BYP_SHIFT 28 ++#define PMU15_PLL_PC1_OPENLP_EN_MASK 0x40000000 ++#define PMU15_PLL_PC1_OPENLP_EN_SHIFT 30 ++ ++#define PMU15_PLL_PLLCTL2 2 ++#define PMU15_PLL_PC2_CTEN_MASK 0x00000001 ++#define PMU15_PLL_PC2_CTEN_SHIFT 0 ++ ++#define PMU15_PLL_PLLCTL3 3 ++#define PMU15_PLL_PC3_DITHER_EN_MASK 0x00000001 ++#define PMU15_PLL_PC3_DITHER_EN_SHIFT 0 ++#define PMU15_PLL_PC3_DCOCTLSP_MASK 0xFE000000 ++#define PMU15_PLL_PC3_DCOCTLSP_SHIFT 25 ++#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_MASK 0x01 ++#define PMU15_PLL_PC3_DCOCTLSP_DIV2EN_SHIFT 0 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_MASK 0x02 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0EN_SHIFT 1 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_MASK 0x04 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1EN_SHIFT 2 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_MASK 0x18 ++#define PMU15_PLL_PC3_DCOCTLSP_CH0SEL_SHIFT 3 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_MASK 0x60 ++#define PMU15_PLL_PC3_DCOCTLSP_CH1SEL_SHIFT 5 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV1 0 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV2 1 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV3 2 ++#define PMU15_PLL_PC3_DCOCTLSP_CHSEL_OUTP_DIV5 3 ++ ++#define PMU15_PLL_PLLCTL4 4 ++#define PMU15_PLL_PC4_FLLCLK1_DIV_MASK 0x00000007 ++#define PMU15_PLL_PC4_FLLCLK1_DIV_SHIFT 0 ++#define PMU15_PLL_PC4_FLLCLK2_DIV_MASK 0x00000038 ++#define PMU15_PLL_PC4_FLLCLK2_DIV_SHIFT 3 ++#define PMU15_PLL_PC4_FLLCLK3_DIV_MASK 0x000001C0 ++#define PMU15_PLL_PC4_FLLCLK3_DIV_SHIFT 6 ++#define PMU15_PLL_PC4_DBGMODE_MASK 0x00000E00 ++#define PMU15_PLL_PC4_DBGMODE_SHIFT 9 ++#define PMU15_PLL_PC4_FLL480_CTLSP_LK_MASK 0x00001000 ++#define PMU15_PLL_PC4_FLL480_CTLSP_LK_SHIFT 12 ++#define PMU15_PLL_PC4_FLL480_CTLSP_MASK 0x000FE000 ++#define PMU15_PLL_PC4_FLL480_CTLSP_SHIFT 13 ++#define PMU15_PLL_PC4_DINPOL_MASK 0x00100000 ++#define PMU15_PLL_PC4_DINPOL_SHIFT 20 ++#define PMU15_PLL_PC4_CLKOUT_PD_MASK 0x00200000 ++#define PMU15_PLL_PC4_CLKOUT_PD_SHIFT 21 ++#define PMU15_PLL_PC4_CLKDIV2_PD_MASK 0x00400000 ++#define PMU15_PLL_PC4_CLKDIV2_PD_SHIFT 22 ++#define PMU15_PLL_PC4_CLKDIV4_PD_MASK 0x00800000 ++#define PMU15_PLL_PC4_CLKDIV4_PD_SHIFT 23 ++#define PMU15_PLL_PC4_CLKDIV8_PD_MASK 0x01000000 ++#define PMU15_PLL_PC4_CLKDIV8_PD_SHIFT 24 ++#define PMU15_PLL_PC4_CLKDIV16_PD_MASK 0x02000000 ++#define PMU15_PLL_PC4_CLKDIV16_PD_SHIFT 25 ++#define PMU15_PLL_PC4_TEST_EN_MASK 0x04000000 ++#define PMU15_PLL_PC4_TEST_EN_SHIFT 26 ++ ++#define PMU15_PLL_PLLCTL5 5 ++#define PMU15_PLL_PC5_FREQTGT_MASK 0x000FFFFF ++#define PMU15_PLL_PC5_FREQTGT_SHIFT 0 ++#define PMU15_PLL_PC5_DCOCTLSP_MASK 0x07F00000 ++#define PMU15_PLL_PC5_DCOCTLSP_SHIFT 20 ++#define PMU15_PLL_PC5_PRESCALE_MASK 0x18000000 ++#define PMU15_PLL_PC5_PRESCALE_SHIFT 27 ++ ++#define PMU15_PLL_PLLCTL6 6 ++#define PMU15_PLL_PC6_FREQTGT_MASK 0x000FFFFF ++#define PMU15_PLL_PC6_FREQTGT_SHIFT 0 ++#define PMU15_PLL_PC6_DCOCTLSP_MASK 0x07F00000 ++#define PMU15_PLL_PC6_DCOCTLSP_SHIFT 20 ++#define PMU15_PLL_PC6_PRESCALE_MASK 0x18000000 ++#define PMU15_PLL_PC6_PRESCALE_SHIFT 27 ++ ++#define PMU15_FREQTGT_480_DEFAULT 0x19AB1 ++#define PMU15_FREQTGT_492_DEFAULT 0x1A4F5 ++#define PMU15_ARM_96MHZ 96000000 /**< 96 Mhz */ ++#define PMU15_ARM_98MHZ 98400000 /**< 98.4 Mhz */ ++#define PMU15_ARM_97MHZ 97000000 /**< 97 Mhz */ ++ ++ ++#define PMU17_PLLCTL2_NDIVTYPE_MASK 0x00000070 ++#define PMU17_PLLCTL2_NDIVTYPE_SHIFT 4 ++ ++#define PMU17_PLLCTL2_NDIV_MODE_INT 0 ++#define PMU17_PLLCTL2_NDIV_MODE_INT1B8 1 ++#define PMU17_PLLCTL2_NDIV_MODE_MASH111 2 ++#define PMU17_PLLCTL2_NDIV_MODE_MASH111B8 3 ++ ++#define PMU17_PLLCTL0_BBPLL_PWRDWN 0 ++#define PMU17_PLLCTL0_BBPLL_DRST 3 ++#define PMU17_PLLCTL0_BBPLL_DISBL_CLK 8 ++ ++/* PLL usage in 4716/47162 */ ++#define PMU4716_MAINPLL_PLL0 12 ++ ++/* PLL usage in 4335 */ ++#define PMU4335_PLL0_PC2_P1DIV_MASK 0x000f0000 ++#define PMU4335_PLL0_PC2_P1DIV_SHIFT 16 ++#define PMU4335_PLL0_PC2_NDIV_INT_MASK 0xff800000 ++#define PMU4335_PLL0_PC2_NDIV_INT_SHIFT 23 ++#define PMU4335_PLL0_PC1_MDIV2_MASK 0x0000ff00 ++#define PMU4335_PLL0_PC1_MDIV2_SHIFT 8 ++ ++/* PLL usage in 4347 */ ++#define PMU4347_PLL0_PC2_P1DIV_MASK 0x000f0000 ++#define PMU4347_PLL0_PC2_P1DIV_SHIFT 16 ++#define PMU4347_PLL0_PC2_NDIV_INT_MASK 0x3ff00000 ++#define PMU4347_PLL0_PC2_NDIV_INT_SHIFT 20 ++#define PMU4347_PLL0_PC3_NDIV_FRAC_MASK 0x000fffff ++#define PMU4347_PLL0_PC3_NDIV_FRAC_SHIFT 0 ++#define PMU4347_PLL1_PC5_P1DIV_MASK 0xc0000000 ++#define PMU4347_PLL1_PC5_P1DIV_SHIFT 30 ++#define PMU4347_PLL1_PC6_P1DIV_MASK 0x00000003 ++#define PMU4347_PLL1_PC6_P1DIV_SHIFT 0 ++#define PMU4347_PLL1_PC6_NDIV_INT_MASK 0x00000ffc ++#define PMU4347_PLL1_PC6_NDIV_INT_SHIFT 2 ++#define PMU4347_PLL1_PC6_NDIV_FRAC_MASK 0xfffff000 ++#define PMU4347_PLL1_PC6_NDIV_FRAC_SHIFT 12 ++ ++/* PLL usage in 5356/5357 */ ++#define PMU5356_MAINPLL_PLL0 0 ++#define PMU5357_MAINPLL_PLL0 0 ++ ++/* 4716/47162 resources */ ++#define RES4716_PROC_PLL_ON 0x00000040 ++#define RES4716_PROC_HT_AVAIL 0x00000080 ++ ++/* 4716/4717/4718 Chip specific ChipControl register bits */ ++#define CCTRL_471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared w/ pflash */ ++ ++/* 5357 Chip specific ChipControl register bits */ ++/* 2nd - 32-bit reg */ ++#define CCTRL_5357_I2S_PINS_ENABLE 0x00040000 /* I2S pins enable */ ++#define CCTRL_5357_I2CSPI_PINS_ENABLE 0x00080000 /* I2C/SPI pins enable */ ++ ++/* 5354 resources */ ++#define RES5354_EXT_SWITCHER_PWM 0 /**< 0x00001 */ ++#define RES5354_BB_SWITCHER_PWM 1 /**< 0x00002 */ ++#define RES5354_BB_SWITCHER_BURST 2 /**< 0x00004 */ ++#define RES5354_BB_EXT_SWITCHER_BURST 3 /**< 0x00008 */ ++#define RES5354_ILP_REQUEST 4 /**< 0x00010 */ ++#define RES5354_RADIO_SWITCHER_PWM 5 /**< 0x00020 */ ++#define RES5354_RADIO_SWITCHER_BURST 6 /**< 0x00040 */ ++#define RES5354_ROM_SWITCH 7 /**< 0x00080 */ ++#define RES5354_PA_REF_LDO 8 /**< 0x00100 */ ++#define RES5354_RADIO_LDO 9 /**< 0x00200 */ ++#define RES5354_AFE_LDO 10 /**< 0x00400 */ ++#define RES5354_PLL_LDO 11 /**< 0x00800 */ ++#define RES5354_BG_FILTBYP 12 /**< 0x01000 */ ++#define RES5354_TX_FILTBYP 13 /**< 0x02000 */ ++#define RES5354_RX_FILTBYP 14 /**< 0x04000 */ ++#define RES5354_XTAL_PU 15 /**< 0x08000 */ ++#define RES5354_XTAL_EN 16 /**< 0x10000 */ ++#define RES5354_BB_PLL_FILTBYP 17 /**< 0x20000 */ ++#define RES5354_RF_PLL_FILTBYP 18 /**< 0x40000 */ ++#define RES5354_BB_PLL_PU 19 /**< 0x80000 */ ++ ++/* 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_NFLASH (1<<16) /* Nandflash in ChipControl 1, bit 16 */ ++ ++/* 43217 Chip specific ChipControl register bits */ ++#define CCTRL43217_EXTPA_C0 (1<<13) /* core0 extPA in ChipControl 1, bit 13 */ ++#define CCTRL43217_EXTPA_C1 (1<<8) /* core1 extPA in ChipControl 1, bit 8 */ ++ ++/* 43228 Chip specific ChipControl register bits */ ++#define CCTRL43228_EXTPA_C0 (1<<14) /* core1 extPA in ChipControl 1, bit 14 */ ++#define CCTRL43228_EXTPA_C1 (1<<9) /* core0 extPA in ChipControl 1, bit 1 */ ++ ++/* 4328 resources */ ++#define RES4328_EXT_SWITCHER_PWM 0 /**< 0x00001 */ ++#define RES4328_BB_SWITCHER_PWM 1 /**< 0x00002 */ ++#define RES4328_BB_SWITCHER_BURST 2 /**< 0x00004 */ ++#define RES4328_BB_EXT_SWITCHER_BURST 3 /**< 0x00008 */ ++#define RES4328_ILP_REQUEST 4 /**< 0x00010 */ ++#define RES4328_RADIO_SWITCHER_PWM 5 /**< 0x00020 */ ++#define RES4328_RADIO_SWITCHER_BURST 6 /**< 0x00040 */ ++#define RES4328_ROM_SWITCH 7 /**< 0x00080 */ ++#define RES4328_PA_REF_LDO 8 /**< 0x00100 */ ++#define RES4328_RADIO_LDO 9 /**< 0x00200 */ ++#define RES4328_AFE_LDO 10 /**< 0x00400 */ ++#define RES4328_PLL_LDO 11 /**< 0x00800 */ ++#define RES4328_BG_FILTBYP 12 /**< 0x01000 */ ++#define RES4328_TX_FILTBYP 13 /**< 0x02000 */ ++#define RES4328_RX_FILTBYP 14 /**< 0x04000 */ ++#define RES4328_XTAL_PU 15 /**< 0x08000 */ ++#define RES4328_XTAL_EN 16 /**< 0x10000 */ ++#define RES4328_BB_PLL_FILTBYP 17 /**< 0x20000 */ ++#define RES4328_RF_PLL_FILTBYP 18 /**< 0x40000 */ ++#define RES4328_BB_PLL_PU 19 /**< 0x80000 */ ++ ++/* 4325 A0/A1 resources */ ++#define RES4325_BUCK_BOOST_BURST 0 /**< 0x00000001 */ ++#define RES4325_CBUCK_BURST 1 /**< 0x00000002 */ ++#define RES4325_CBUCK_PWM 2 /**< 0x00000004 */ ++#define RES4325_CLDO_CBUCK_BURST 3 /**< 0x00000008 */ ++#define RES4325_CLDO_CBUCK_PWM 4 /**< 0x00000010 */ ++#define RES4325_BUCK_BOOST_PWM 5 /**< 0x00000020 */ ++#define RES4325_ILP_REQUEST 6 /**< 0x00000040 */ ++#define RES4325_ABUCK_BURST 7 /**< 0x00000080 */ ++#define RES4325_ABUCK_PWM 8 /**< 0x00000100 */ ++#define RES4325_LNLDO1_PU 9 /**< 0x00000200 */ ++#define RES4325_OTP_PU 10 /**< 0x00000400 */ ++#define RES4325_LNLDO3_PU 11 /**< 0x00000800 */ ++#define RES4325_LNLDO4_PU 12 /**< 0x00001000 */ ++#define RES4325_XTAL_PU 13 /**< 0x00002000 */ ++#define RES4325_ALP_AVAIL 14 /**< 0x00004000 */ ++#define RES4325_RX_PWRSW_PU 15 /**< 0x00008000 */ ++#define RES4325_TX_PWRSW_PU 16 /**< 0x00010000 */ ++#define RES4325_RFPLL_PWRSW_PU 17 /**< 0x00020000 */ ++#define RES4325_LOGEN_PWRSW_PU 18 /**< 0x00040000 */ ++#define RES4325_AFE_PWRSW_PU 19 /**< 0x00080000 */ ++#define RES4325_BBPLL_PWRSW_PU 20 /**< 0x00100000 */ ++#define RES4325_HT_AVAIL 21 /**< 0x00200000 */ ++ ++/* 4325 B0/C0 resources */ ++#define RES4325B0_CBUCK_LPOM 1 /**< 0x00000002 */ ++#define RES4325B0_CBUCK_BURST 2 /**< 0x00000004 */ ++#define RES4325B0_CBUCK_PWM 3 /**< 0x00000008 */ ++#define RES4325B0_CLDO_PU 4 /**< 0x00000010 */ ++ ++/* 4325 C1 resources */ ++#define RES4325C1_LNLDO2_PU 12 /**< 0x00001000 */ ++ ++/* 4325 chip-specific ChipStatus register bits */ ++#define CST4325_SPROM_OTP_SEL_MASK 0x00000003 ++#define CST4325_DEFCIS_SEL 0 /**< OTP is powered up, use def. CIS, no SPROM */ ++#define CST4325_SPROM_SEL 1 /**< OTP is powered up, SPROM is present */ ++#define CST4325_OTP_SEL 2 /**< OTP is powered up, no SPROM */ ++#define CST4325_OTP_PWRDN 3 /**< OTP is powered down, SPROM is present */ ++#define CST4325_SDIO_USB_MODE_MASK 0x00000004 ++#define CST4325_SDIO_USB_MODE_SHIFT 2 ++#define CST4325_RCAL_VALID_MASK 0x00000008 ++#define CST4325_RCAL_VALID_SHIFT 3 ++#define CST4325_RCAL_VALUE_MASK 0x000001f0 ++#define CST4325_RCAL_VALUE_SHIFT 4 ++#define CST4325_PMUTOP_2B_MASK 0x00000200 /**< 1 for 2b, 0 for to 2a */ ++#define CST4325_PMUTOP_2B_SHIFT 9 ++ ++#define RES4329_RESERVED0 0 /**< 0x00000001 */ ++#define RES4329_CBUCK_LPOM 1 /**< 0x00000002 */ ++#define RES4329_CBUCK_BURST 2 /**< 0x00000004 */ ++#define RES4329_CBUCK_PWM 3 /**< 0x00000008 */ ++#define RES4329_CLDO_PU 4 /**< 0x00000010 */ ++#define RES4329_PALDO_PU 5 /**< 0x00000020 */ ++#define RES4329_ILP_REQUEST 6 /**< 0x00000040 */ ++#define RES4329_RESERVED7 7 /**< 0x00000080 */ ++#define RES4329_RESERVED8 8 /**< 0x00000100 */ ++#define RES4329_LNLDO1_PU 9 /**< 0x00000200 */ ++#define RES4329_OTP_PU 10 /**< 0x00000400 */ ++#define RES4329_RESERVED11 11 /**< 0x00000800 */ ++#define RES4329_LNLDO2_PU 12 /**< 0x00001000 */ ++#define RES4329_XTAL_PU 13 /**< 0x00002000 */ ++#define RES4329_ALP_AVAIL 14 /**< 0x00004000 */ ++#define RES4329_RX_PWRSW_PU 15 /**< 0x00008000 */ ++#define RES4329_TX_PWRSW_PU 16 /**< 0x00010000 */ ++#define RES4329_RFPLL_PWRSW_PU 17 /**< 0x00020000 */ ++#define RES4329_LOGEN_PWRSW_PU 18 /**< 0x00040000 */ ++#define RES4329_AFE_PWRSW_PU 19 /**< 0x00080000 */ ++#define RES4329_BBPLL_PWRSW_PU 20 /**< 0x00100000 */ ++#define RES4329_HT_AVAIL 21 /**< 0x00200000 */ ++ ++#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 */ ++#define CST4329_SPI_SDIO_MODE_MASK 0x00000004 ++#define CST4329_SPI_SDIO_MODE_SHIFT 2 ++ ++/* 4312 chip-specific ChipStatus register bits */ ++#define CST4312_SPROM_OTP_SEL_MASK 0x00000003 ++#define CST4312_DEFCIS_SEL 0 /**< OTP is powered up, use def. CIS, no SPROM */ ++#define CST4312_SPROM_SEL 1 /**< OTP is powered up, SPROM is present */ ++#define CST4312_OTP_SEL 2 /**< OTP is powered up, no SPROM */ ++#define CST4312_OTP_BAD 3 /**< OTP is broken, SPROM is present */ ++ ++/* 4312 resources (all PMU chips with little memory constraint) */ ++#define RES4312_SWITCHER_BURST 0 /**< 0x00000001 */ ++#define RES4312_SWITCHER_PWM 1 /**< 0x00000002 */ ++#define RES4312_PA_REF_LDO 2 /**< 0x00000004 */ ++#define RES4312_CORE_LDO_BURST 3 /**< 0x00000008 */ ++#define RES4312_CORE_LDO_PWM 4 /**< 0x00000010 */ ++#define RES4312_RADIO_LDO 5 /**< 0x00000020 */ ++#define RES4312_ILP_REQUEST 6 /**< 0x00000040 */ ++#define RES4312_BG_FILTBYP 7 /**< 0x00000080 */ ++#define RES4312_TX_FILTBYP 8 /**< 0x00000100 */ ++#define RES4312_RX_FILTBYP 9 /**< 0x00000200 */ ++#define RES4312_XTAL_PU 10 /**< 0x00000400 */ ++#define RES4312_ALP_AVAIL 11 /**< 0x00000800 */ ++#define RES4312_BB_PLL_FILTBYP 12 /**< 0x00001000 */ ++#define RES4312_RF_PLL_FILTBYP 13 /**< 0x00002000 */ ++#define RES4312_HT_AVAIL 14 /**< 0x00004000 */ ++ ++/* 4322 resources */ ++#define RES4322_RF_LDO 0 ++#define RES4322_ILP_REQUEST 1 ++#define RES4322_XTAL_PU 2 ++#define RES4322_ALP_AVAIL 3 ++#define RES4322_SI_PLL_ON 4 ++#define RES4322_HT_SI_AVAIL 5 ++#define RES4322_PHY_PLL_ON 6 ++#define RES4322_HT_PHY_AVAIL 7 ++#define RES4322_OTP_PU 8 ++ ++/* 4322 chip-specific ChipStatus register bits */ ++#define CST4322_XTAL_FREQ_20_40MHZ 0x00000020 ++#define CST4322_SPROM_OTP_SEL_MASK 0x000000c0 ++#define CST4322_SPROM_OTP_SEL_SHIFT 6 ++#define CST4322_NO_SPROM_OTP 0 /**< no OTP, no SPROM */ ++#define CST4322_SPROM_PRESENT 1 /**< SPROM is present */ ++#define CST4322_OTP_PRESENT 2 /**< OTP is present */ ++#define CST4322_PCI_OR_USB 0x00000100 ++#define CST4322_BOOT_MASK 0x00000600 ++#define CST4322_BOOT_SHIFT 9 ++#define CST4322_BOOT_FROM_SRAM 0 /**< boot from SRAM, ARM in reset */ ++#define CST4322_BOOT_FROM_ROM 1 /**< boot from ROM */ ++#define CST4322_BOOT_FROM_FLASH 2 /**< boot from FLASH */ ++#define CST4322_BOOT_FROM_INVALID 3 ++#define CST4322_ILP_DIV_EN 0x00000800 ++#define CST4322_FLASH_TYPE_MASK 0x00001000 ++#define CST4322_FLASH_TYPE_SHIFT 12 ++#define CST4322_FLASH_TYPE_SHIFT_ST 0 /**< ST serial FLASH */ ++#define CST4322_FLASH_TYPE_SHIFT_ATMEL 1 /**< ATMEL flash */ ++#define CST4322_ARM_TAP_SEL 0x00002000 ++#define CST4322_RES_INIT_MODE_MASK 0x0000c000 ++#define CST4322_RES_INIT_MODE_SHIFT 14 ++#define CST4322_RES_INIT_MODE_ILPAVAIL 0 /**< resinitmode: ILP available */ ++#define CST4322_RES_INIT_MODE_ILPREQ 1 /**< resinitmode: ILP request */ ++#define CST4322_RES_INIT_MODE_ALPAVAIL 2 /**< resinitmode: ALP available */ ++#define CST4322_RES_INIT_MODE_HTAVAIL 3 /**< resinitmode: HT available */ ++#define CST4322_PCIPLLCLK_GATING 0x00010000 ++#define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 ++#define CST4322_PCI_CARDBUS_MODE 0x00040000 ++ ++/* 43224 chip-specific ChipControl register bits */ ++#define CCTRL43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */ ++#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 */ ++ ++/* 43236 resources */ ++#define RES43236_REGULATOR 0 ++#define RES43236_ILP_REQUEST 1 ++#define RES43236_XTAL_PU 2 ++#define RES43236_ALP_AVAIL 3 ++#define RES43236_SI_PLL_ON 4 ++#define RES43236_HT_SI_AVAIL 5 ++ ++/* 43236 chip-specific ChipControl register bits */ ++#define CCTRL43236_BT_COEXIST (1<<0) /**< 0 disable */ ++#define CCTRL43236_SECI (1<<1) /**< 0 SECI is disabled (JATG functional) */ ++#define CCTRL43236_EXT_LNA (1<<2) /**< 0 disable */ ++#define CCTRL43236_ANT_MUX_2o3 (1<<3) /**< 2o3 mux, chipcontrol bit 3 */ ++#define CCTRL43236_GSIO (1<<4) /**< 0 disable */ ++ ++/* 43236 Chip specific ChipStatus register bits */ ++#define CST43236_SFLASH_MASK 0x00000040 ++#define CST43236_OTP_SEL_MASK 0x00000080 ++#define CST43236_OTP_SEL_SHIFT 7 ++#define CST43236_HSIC_MASK 0x00000100 /**< USB/HSIC */ ++#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_INVALID 3 ++ ++/* 43237 resources */ ++#define RES43237_REGULATOR 0 ++#define RES43237_ILP_REQUEST 1 ++#define RES43237_XTAL_PU 2 ++#define RES43237_ALP_AVAIL 3 ++#define RES43237_SI_PLL_ON 4 ++#define RES43237_HT_SI_AVAIL 5 ++ ++/* 43237 chip-specific ChipControl register bits */ ++#define CCTRL43237_BT_COEXIST (1<<0) /**< 0 disable */ ++#define CCTRL43237_SECI (1<<1) /**< 0 SECI is disabled (JATG functional) */ ++#define CCTRL43237_EXT_LNA (1<<2) /**< 0 disable */ ++#define CCTRL43237_ANT_MUX_2o3 (1<<3) /**< 2o3 mux, chipcontrol bit 3 */ ++#define CCTRL43237_GSIO (1<<4) /**< 0 disable */ ++ ++/* 43237 Chip specific ChipStatus register bits */ ++#define CST43237_SFLASH_MASK 0x00000040 ++#define CST43237_OTP_SEL_MASK 0x00000080 ++#define CST43237_OTP_SEL_SHIFT 7 ++#define CST43237_HSIC_MASK 0x00000100 /**< USB/HSIC */ ++#define CST43237_BP_CLK 0x00000200 /**< 120/96Mbps */ ++#define CST43237_BOOT_MASK 0x00001800 ++#define CST43237_BOOT_SHIFT 11 ++#define CST43237_BOOT_FROM_SRAM 0 /**< boot from SRAM, ARM in reset */ ++#define CST43237_BOOT_FROM_ROM 1 /**< boot from ROM */ ++#define CST43237_BOOT_FROM_FLASH 2 /**< boot from FLASH */ ++#define CST43237_BOOT_FROM_INVALID 3 ++ ++/* 43239 resources */ ++#define RES43239_OTP_PU 9 ++#define RES43239_MACPHY_CLKAVAIL 23 ++#define RES43239_HT_AVAIL 24 ++ ++/* 43239 Chip specific ChipStatus register bits */ ++#define CST43239_SPROM_MASK 0x00000002 ++#define CST43239_SFLASH_MASK 0x00000004 ++#define CST43239_RES_INIT_MODE_SHIFT 7 ++#define CST43239_RES_INIT_MODE_MASK 0x000001f0 ++#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15)) /**< SDIO || gSPI */ ++#define CST43239_CHIPMODE_USB20D(cs) (~(cs) & (1 << 15)) /**< USB || USBDA */ ++#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0) /**< SDIO */ ++#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) /**< gSPI */ ++ ++/* 4324 resources */ ++/* 43242 use same PMU as 4324 */ ++#define RES4324_LPLDO_PU 0 ++#define RES4324_RESET_PULLDN_DIS 1 ++#define RES4324_PMU_BG_PU 2 ++#define RES4324_HSIC_LDO_PU 3 ++#define RES4324_CBUCK_LPOM_PU 4 ++#define RES4324_CBUCK_PFM_PU 5 ++#define RES4324_CLDO_PU 6 ++#define RES4324_LPLDO2_LVM 7 ++#define RES4324_LNLDO1_PU 8 ++#define RES4324_LNLDO2_PU 9 ++#define RES4324_LDO3P3_PU 10 ++#define RES4324_OTP_PU 11 ++#define RES4324_XTAL_PU 12 ++#define RES4324_BBPLL_PU 13 ++#define RES4324_LQ_AVAIL 14 ++#define RES4324_WL_CORE_READY 17 ++#define RES4324_ILP_REQ 18 ++#define RES4324_ALP_AVAIL 19 ++#define RES4324_PALDO_PU 20 ++#define RES4324_RADIO_PU 21 ++#define RES4324_SR_CLK_STABLE 22 ++#define RES4324_SR_SAVE_RESTORE 23 ++#define RES4324_SR_PHY_PWRSW 24 ++#define RES4324_SR_PHY_PIC 25 ++#define RES4324_SR_SUBCORE_PWRSW 26 ++#define RES4324_SR_SUBCORE_PIC 27 ++#define RES4324_SR_MEM_PM0 28 ++#define RES4324_HT_AVAIL 29 ++#define RES4324_MACPHY_CLKAVAIL 30 ++ ++/* 4324 Chip specific ChipStatus register bits */ ++#define CST4324_SPROM_MASK 0x00000080 ++#define CST4324_SFLASH_MASK 0x00400000 ++#define CST4324_RES_INIT_MODE_SHIFT 10 ++#define CST4324_RES_INIT_MODE_MASK 0x00000c00 ++#define CST4324_CHIPMODE_MASK 0x7 ++#define CST4324_CHIPMODE_SDIOD(cs) ((~(cs)) & (1 << 2)) /**< SDIO || gSPI */ ++#define CST4324_CHIPMODE_USB20D(cs) (((cs) & CST4324_CHIPMODE_MASK) == 0x6) /**< USB || USBDA */ ++ ++/* 43242 Chip specific ChipStatus register bits */ ++#define CST43242_SFLASH_MASK 0x00000008 ++#define CST43242_SR_HALT (1<<25) ++#define CST43242_SR_CHIP_STATUS_2 27 /* bit 27 */ ++ ++/* 4331 resources */ ++#define RES4331_REGULATOR 0 ++#define RES4331_ILP_REQUEST 1 ++#define RES4331_XTAL_PU 2 ++#define RES4331_ALP_AVAIL 3 ++#define RES4331_SI_PLL_ON 4 ++#define RES4331_HT_SI_AVAIL 5 ++ ++/* 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_G (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_EXTPA_EN2 (1<<12) /**< 0 ext pa disable, 1 ext pa enabled */ ++#define CCTRL4331_EXT_LNA_A (1<<13) /**< 0 disable */ ++#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 */ ++#define CCTRL4331_EXTPA_ANA_EN (1<<24) /**< 0 ext pa disable, 1 ext pa enabled */ ++ ++/* 4331 Chip specific ChipStatus register bits */ ++#define CST4331_XTAL_FREQ 0x00000001 /**< crystal frequency 20/40Mhz */ ++#define CST4331_SPROM_OTP_SEL_MASK 0x00000006 ++#define CST4331_SPROM_OTP_SEL_SHIFT 1 ++#define CST4331_SPROM_PRESENT 0x00000002 ++#define CST4331_OTP_PRESENT 0x00000004 ++#define CST4331_LDO_RF 0x00000008 ++#define CST4331_LDO_PAR 0x00000010 ++ ++/* 4315 resource */ ++#define RES4315_CBUCK_LPOM 1 /**< 0x00000002 */ ++#define RES4315_CBUCK_BURST 2 /**< 0x00000004 */ ++#define RES4315_CBUCK_PWM 3 /**< 0x00000008 */ ++#define RES4315_CLDO_PU 4 /**< 0x00000010 */ ++#define RES4315_PALDO_PU 5 /**< 0x00000020 */ ++#define RES4315_ILP_REQUEST 6 /**< 0x00000040 */ ++#define RES4315_LNLDO1_PU 9 /**< 0x00000200 */ ++#define RES4315_OTP_PU 10 /**< 0x00000400 */ ++#define RES4315_LNLDO2_PU 12 /**< 0x00001000 */ ++#define RES4315_XTAL_PU 13 /**< 0x00002000 */ ++#define RES4315_ALP_AVAIL 14 /**< 0x00004000 */ ++#define RES4315_RX_PWRSW_PU 15 /**< 0x00008000 */ ++#define RES4315_TX_PWRSW_PU 16 /**< 0x00010000 */ ++#define RES4315_RFPLL_PWRSW_PU 17 /**< 0x00020000 */ ++#define RES4315_LOGEN_PWRSW_PU 18 /**< 0x00040000 */ ++#define RES4315_AFE_PWRSW_PU 19 /**< 0x00080000 */ ++#define RES4315_BBPLL_PWRSW_PU 20 /**< 0x00100000 */ ++#define RES4315_HT_AVAIL 21 /**< 0x00200000 */ ++ ++/* 4315 chip-specific ChipStatus register bits */ ++#define CST4315_SPROM_OTP_SEL_MASK 0x00000003 /**< gpio [7:6], SDIO CIS selection */ ++#define CST4315_DEFCIS_SEL 0x00000000 /**< use default CIS, OTP is powered up */ ++#define CST4315_SPROM_SEL 0x00000001 /**< use SPROM, OTP is powered up */ ++#define CST4315_OTP_SEL 0x00000002 /**< use OTP, OTP is powered up */ ++#define CST4315_OTP_PWRDN 0x00000003 /**< use SPROM, OTP is powered down */ ++#define CST4315_SDIO_MODE 0x00000004 /**< gpio [8], sdio/usb mode */ ++#define CST4315_RCAL_VALID 0x00000008 ++#define CST4315_RCAL_VALUE_MASK 0x000001f0 ++#define CST4315_RCAL_VALUE_SHIFT 4 ++#define CST4315_PALDO_EXTPNP 0x00000200 /**< PALDO is configured with external PNP */ ++#define CST4315_CBUCK_MODE_MASK 0x00000c00 ++#define CST4315_CBUCK_MODE_BURST 0x00000400 ++#define CST4315_CBUCK_MODE_LPBURST 0x00000c00 ++ ++/* 4319 resources */ ++#define RES4319_CBUCK_LPOM 1 /**< 0x00000002 */ ++#define RES4319_CBUCK_BURST 2 /**< 0x00000004 */ ++#define RES4319_CBUCK_PWM 3 /**< 0x00000008 */ ++#define RES4319_CLDO_PU 4 /**< 0x00000010 */ ++#define RES4319_PALDO_PU 5 /**< 0x00000020 */ ++#define RES4319_ILP_REQUEST 6 /**< 0x00000040 */ ++#define RES4319_LNLDO1_PU 9 /**< 0x00000200 */ ++#define RES4319_OTP_PU 10 /**< 0x00000400 */ ++#define RES4319_LNLDO2_PU 12 /**< 0x00001000 */ ++#define RES4319_XTAL_PU 13 /**< 0x00002000 */ ++#define RES4319_ALP_AVAIL 14 /**< 0x00004000 */ ++#define RES4319_RX_PWRSW_PU 15 /**< 0x00008000 */ ++#define RES4319_TX_PWRSW_PU 16 /**< 0x00010000 */ ++#define RES4319_RFPLL_PWRSW_PU 17 /**< 0x00020000 */ ++#define RES4319_LOGEN_PWRSW_PU 18 /**< 0x00040000 */ ++#define RES4319_AFE_PWRSW_PU 19 /**< 0x00080000 */ ++#define RES4319_BBPLL_PWRSW_PU 20 /**< 0x00100000 */ ++#define RES4319_HT_AVAIL 21 /**< 0x00200000 */ ++ ++/* 4319 chip-specific ChipStatus register bits */ ++#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 */ ++#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 */ ++#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 */ ++#define CST4319_CBUCK_MODE_MASK 0x00060000 ++#define CST4319_CBUCK_MODE_BURST 0x00020000 ++#define CST4319_CBUCK_MODE_LPBURST 0x00060000 ++#define CST4319_RCAL_VALID 0x01000000 ++#define CST4319_RCAL_VALUE_MASK 0x3e000000 ++#define CST4319_RCAL_VALUE_SHIFT 25 ++ ++#define PMU1_PLL0_CHIPCTL0 0 ++#define PMU1_PLL0_CHIPCTL1 1 ++#define PMU1_PLL0_CHIPCTL2 2 ++#define CCTL_4319USB_XTAL_SEL_MASK 0x00180000 ++#define CCTL_4319USB_XTAL_SEL_SHIFT 19 ++#define CCTL_4319USB_48MHZ_PLL_SEL 1 ++#define CCTL_4319USB_24MHZ_PLL_SEL 2 ++ ++/* PMU resources for 4336 */ ++#define RES4336_CBUCK_LPOM 0 ++#define RES4336_CBUCK_BURST 1 ++#define RES4336_CBUCK_LP_PWM 2 ++#define RES4336_CBUCK_PWM 3 ++#define RES4336_CLDO_PU 4 ++#define RES4336_DIS_INT_RESET_PD 5 ++#define RES4336_ILP_REQUEST 6 ++#define RES4336_LNLDO_PU 7 ++#define RES4336_LDO3P3_PU 8 ++#define RES4336_OTP_PU 9 ++#define RES4336_XTAL_PU 10 ++#define RES4336_ALP_AVAIL 11 ++#define RES4336_RADIO_PU 12 ++#define RES4336_BG_PU 13 ++#define RES4336_VREG1p4_PU_PU 14 ++#define RES4336_AFE_PWRSW_PU 15 ++#define RES4336_RX_PWRSW_PU 16 ++#define RES4336_TX_PWRSW_PU 17 ++#define RES4336_BB_PWRSW_PU 18 ++#define RES4336_SYNTH_PWRSW_PU 19 ++#define RES4336_MISC_PWRSW_PU 20 ++#define RES4336_LOGEN_PWRSW_PU 21 ++#define RES4336_BBPLL_PWRSW_PU 22 ++#define RES4336_MACPHY_CLKAVAIL 23 ++#define RES4336_HT_AVAIL 24 ++#define RES4336_RSVD 25 ++ ++/* 4336 chip-specific ChipStatus register bits */ ++#define CST4336_SPI_MODE_MASK 0x00000001 ++#define CST4336_SPROM_PRESENT 0x00000002 ++#define CST4336_OTP_PRESENT 0x00000004 ++#define CST4336_ARMREMAP_0 0x00000008 ++#define CST4336_ILPDIV_EN_MASK 0x00000010 ++#define CST4336_ILPDIV_EN_SHIFT 4 ++#define CST4336_XTAL_PD_POL_MASK 0x00000020 ++#define CST4336_XTAL_PD_POL_SHIFT 5 ++#define CST4336_LPO_SEL_MASK 0x00000040 ++#define CST4336_LPO_SEL_SHIFT 6 ++#define CST4336_RES_INIT_MODE_MASK 0x00000180 ++#define CST4336_RES_INIT_MODE_SHIFT 7 ++#define CST4336_CBUCK_MODE_MASK 0x00000600 ++#define CST4336_CBUCK_MODE_SHIFT 9 ++ ++/* 4336 Chip specific PMU ChipControl register bits */ ++#define PCTL_4336_SERIAL_ENAB (1 << 24) ++ ++/* 4330 resources */ ++#define RES4330_CBUCK_LPOM 0 ++#define RES4330_CBUCK_BURST 1 ++#define RES4330_CBUCK_LP_PWM 2 ++#define RES4330_CBUCK_PWM 3 ++#define RES4330_CLDO_PU 4 ++#define RES4330_DIS_INT_RESET_PD 5 ++#define RES4330_ILP_REQUEST 6 ++#define RES4330_LNLDO_PU 7 ++#define RES4330_LDO3P3_PU 8 ++#define RES4330_OTP_PU 9 ++#define RES4330_XTAL_PU 10 ++#define RES4330_ALP_AVAIL 11 ++#define RES4330_RADIO_PU 12 ++#define RES4330_BG_PU 13 ++#define RES4330_VREG1p4_PU_PU 14 ++#define RES4330_AFE_PWRSW_PU 15 ++#define RES4330_RX_PWRSW_PU 16 ++#define RES4330_TX_PWRSW_PU 17 ++#define RES4330_BB_PWRSW_PU 18 ++#define RES4330_SYNTH_PWRSW_PU 19 ++#define RES4330_MISC_PWRSW_PU 20 ++#define RES4330_LOGEN_PWRSW_PU 21 ++#define RES4330_BBPLL_PWRSW_PU 22 ++#define RES4330_MACPHY_CLKAVAIL 23 ++#define RES4330_HT_AVAIL 24 ++#define RES4330_5gRX_PWRSW_PU 25 ++#define RES4330_5gTX_PWRSW_PU 26 ++#define RES4330_5g_LOGEN_PWRSW_PU 27 ++ ++/* 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 ++#define SOCDEVRAM_BP_ADDR 0x1E000000 ++#define SOCDEVRAM_ARM_ADDR 0x00800000 ++ ++/* 4330 Chip specific PMU ChipControl register bits */ ++#define PCTL_4330_SERIAL_ENAB (1 << 24) ++ ++/* 4330 Chip specific ChipControl register bits */ ++#define CCTRL_4330_GPIO_SEL 0x00000001 /* 1=select GPIOs to be muxed out */ ++#define CCTRL_4330_ERCX_SEL 0x00000002 /* 1=select ERCX BT coex to be muxed out */ ++#define CCTRL_4330_SDIO_HOST_WAKE 0x00000004 /* SDIO: 1=configure GPIO0 for host wake */ ++#define CCTRL_4330_JTAG_DISABLE 0x00000008 /* 1=disable JTAG interface on mux'd pins */ ++ ++#define PMU_VREG0_ADDR 0 ++#define PMU_VREG0_I_SR_CNTL_EN_SHIFT 0 ++#define PMU_VREG0_DISABLE_PULLD_BT_SHIFT 2 ++#define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 3 ++#define PMU_VREG0_CBUCKFSW_ADJ_SHIFT 7 ++#define PMU_VREG0_CBUCKFSW_ADJ_MASK 0x1F ++#define PMU_VREG0_RAMP_SEL_SHIFT 13 ++#define PMU_VREG0_RAMP_SEL_MASK 0x7 ++#define PMU_VREG0_VFB_RSEL_SHIFT 17 ++#define PMU_VREG0_VFB_RSEL_MASK 3 ++ ++#define PMU_VREG4_ADDR 4 ++ ++#define PMU_VREG4_CLDO_PWM_SHIFT 4 ++#define PMU_VREG4_CLDO_PWM_MASK 0x7 ++ ++#define PMU_VREG4_LPLDO1_SHIFT 15 ++#define PMU_VREG4_LPLDO1_MASK 0x7 ++#define PMU_VREG4_LPLDO1_1p20V 0 ++#define PMU_VREG4_LPLDO1_1p15V 1 ++#define PMU_VREG4_LPLDO1_1p10V 2 ++#define PMU_VREG4_LPLDO1_1p25V 3 ++#define PMU_VREG4_LPLDO1_1p05V 4 ++#define PMU_VREG4_LPLDO1_1p00V 5 ++#define PMU_VREG4_LPLDO1_0p95V 6 ++#define PMU_VREG4_LPLDO1_0p90V 7 ++ ++/* 4350/4345 VREG4 settings */ ++#define PMU4350_VREG4_LPLDO1_1p10V 0 ++#define PMU4350_VREG4_LPLDO1_1p15V 1 ++#define PMU4350_VREG4_LPLDO1_1p21V 2 ++#define PMU4350_VREG4_LPLDO1_1p24V 3 ++#define PMU4350_VREG4_LPLDO1_0p90V 4 ++#define PMU4350_VREG4_LPLDO1_0p96V 5 ++#define PMU4350_VREG4_LPLDO1_1p01V 6 ++#define PMU4350_VREG4_LPLDO1_1p04V 7 ++ ++#define PMU_VREG4_LPLDO2_LVM_SHIFT 18 ++#define PMU_VREG4_LPLDO2_LVM_MASK 0x7 ++#define PMU_VREG4_LPLDO2_HVM_SHIFT 21 ++#define PMU_VREG4_LPLDO2_HVM_MASK 0x7 ++#define PMU_VREG4_LPLDO2_LVM_HVM_MASK 0x3f ++#define PMU_VREG4_LPLDO2_1p00V 0 ++#define PMU_VREG4_LPLDO2_1p15V 1 ++#define PMU_VREG4_LPLDO2_1p20V 2 ++#define PMU_VREG4_LPLDO2_1p10V 3 ++#define PMU_VREG4_LPLDO2_0p90V 4 /**< 4 - 7 is 0.90V */ ++ ++#define PMU_VREG4_HSICLDO_BYPASS_SHIFT 27 ++#define PMU_VREG4_HSICLDO_BYPASS_MASK 0x1 ++ ++#define PMU_VREG5_ADDR 5 ++#define PMU_VREG5_HSICAVDD_PD_SHIFT 6 ++#define PMU_VREG5_HSICAVDD_PD_MASK 0x1 ++#define PMU_VREG5_HSICDVDD_PD_SHIFT 11 ++#define PMU_VREG5_HSICDVDD_PD_MASK 0x1 ++ ++/* 4334 resources */ ++#define RES4334_LPLDO_PU 0 ++#define RES4334_RESET_PULLDN_DIS 1 ++#define RES4334_PMU_BG_PU 2 ++#define RES4334_HSIC_LDO_PU 3 ++#define RES4334_CBUCK_LPOM_PU 4 ++#define RES4334_CBUCK_PFM_PU 5 ++#define RES4334_CLDO_PU 6 ++#define RES4334_LPLDO2_LVM 7 ++#define RES4334_LNLDO_PU 8 ++#define RES4334_LDO3P3_PU 9 ++#define RES4334_OTP_PU 10 ++#define RES4334_XTAL_PU 11 ++#define RES4334_WL_PWRSW_PU 12 ++#define RES4334_LQ_AVAIL 13 ++#define RES4334_LOGIC_RET 14 ++#define RES4334_MEM_SLEEP 15 ++#define RES4334_MACPHY_RET 16 ++#define RES4334_WL_CORE_READY 17 ++#define RES4334_ILP_REQ 18 ++#define RES4334_ALP_AVAIL 19 ++#define RES4334_MISC_PWRSW_PU 20 ++#define RES4334_SYNTH_PWRSW_PU 21 ++#define RES4334_RX_PWRSW_PU 22 ++#define RES4334_RADIO_PU 23 ++#define RES4334_WL_PMU_PU 24 ++#define RES4334_VCO_LDO_PU 25 ++#define RES4334_AFE_LDO_PU 26 ++#define RES4334_RX_LDO_PU 27 ++#define RES4334_TX_LDO_PU 28 ++#define RES4334_HT_AVAIL 29 ++#define RES4334_MACPHY_CLK_AVAIL 30 ++ ++/* 4334 chip-specific ChipStatus register bits */ ++#define CST4334_CHIPMODE_MASK 7 ++#define CST4334_SDIO_MODE 0x00000000 ++#define CST4334_SPI_MODE 0x00000004 ++#define CST4334_HSIC_MODE 0x00000006 ++#define CST4334_BLUSB_MODE 0x00000007 ++#define CST4334_CHIPMODE_HSIC(cs) (((cs) & CST4334_CHIPMODE_MASK) == CST4334_HSIC_MODE) ++#define CST4334_OTP_PRESENT 0x00000010 ++#define CST4334_LPO_AUTODET_EN 0x00000020 ++#define CST4334_ARMREMAP_0 0x00000040 ++#define CST4334_SPROM_PRESENT 0x00000080 ++#define CST4334_ILPDIV_EN_MASK 0x00000100 ++#define CST4334_ILPDIV_EN_SHIFT 8 ++#define CST4334_LPO_SEL_MASK 0x00000200 ++#define CST4334_LPO_SEL_SHIFT 9 ++#define CST4334_RES_INIT_MODE_MASK 0x00000C00 ++#define CST4334_RES_INIT_MODE_SHIFT 10 ++ ++/* 4334 Chip specific PMU ChipControl register bits */ ++#define PCTL_4334_GPIO3_ENAB (1 << 3) ++ ++/* 4334 Chip control */ ++#define CCTRL4334_PMU_WAKEUP_GPIO1 (1 << 0) ++#define CCTRL4334_PMU_WAKEUP_HSIC (1 << 1) ++#define CCTRL4334_PMU_WAKEUP_AOS (1 << 2) ++#define CCTRL4334_HSIC_WAKE_MODE (1 << 3) ++#define CCTRL4334_HSIC_INBAND_GPIO1 (1 << 4) ++#define CCTRL4334_HSIC_LDO_PU (1 << 23) ++ ++/* 4334 Chip control 3 */ ++#define CCTRL4334_BLOCK_EXTRNL_WAKE (1 << 4) ++#define CCTRL4334_SAVERESTORE_FIX (1 << 5) ++ ++/* 43341 Chip control 3 */ ++#define CCTRL43341_BLOCK_EXTRNL_WAKE (1 << 13) ++#define CCTRL43341_SAVERESTORE_FIX (1 << 14) ++#define CCTRL43341_BT_ISO_SEL (1 << 16) ++ ++/* 4334 Chip specific ChipControl1 register bits */ ++#define CCTRL1_4334_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ ++#define CCTRL1_4334_ERCX_SEL (1 << 1) /* 1=select ERCX BT coex to be muxed out */ ++#define CCTRL1_4334_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ ++#define CCTRL1_4334_JTAG_DISABLE (1 << 3) /* 1=disable JTAG interface on mux'd pins */ ++#define CCTRL1_4334_UART_ON_4_5 (1 << 28) /**< 1=UART_TX/UART_RX muxed on GPIO_4/5 (4334B0/1) */ ++ ++/* 4324 Chip specific ChipControl1 register bits */ ++#define CCTRL1_4324_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ ++#define CCTRL1_4324_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ ++ ++/* 43143 chip-specific ChipStatus register bits based on Confluence documentation */ ++/* register contains strap values sampled during POR */ ++#define CST43143_REMAP_TO_ROM (3 << 0) /* 00=Boot SRAM, 01=Boot ROM, 10=Boot SFLASH */ ++#define CST43143_SDIO_EN (1 << 2) /* 0 = USB Enab, SDIO pins are GPIO or I2S */ ++#define CST43143_SDIO_ISO (1 << 3) /* 1 = SDIO isolated */ ++#define CST43143_USB_CPU_LESS (1 << 4) /* 1 = CPULess mode Enabled */ ++#define CST43143_CBUCK_MODE (3 << 6) /* Indicates what controller mode CBUCK is in */ ++#define CST43143_POK_CBUCK (1 << 8) /* 1 = 1.2V CBUCK voltage ready */ ++#define CST43143_PMU_OVRSPIKE (1 << 9) ++#define CST43143_PMU_OVRTEMP (0xF << 10) ++#define CST43143_SR_FLL_CAL_DONE (1 << 14) ++#define CST43143_USB_PLL_LOCKDET (1 << 15) ++#define CST43143_PMU_PLL_LOCKDET (1 << 16) ++#define CST43143_CHIPMODE_SDIOD(cs) (((cs) & CST43143_SDIO_EN) != 0) /* SDIO */ ++ ++/* 43143 Chip specific ChipControl register bits */ ++/* 00: SECI is disabled (JATG functional), 01: 2 wire, 10: 4 wire */ ++#define CCTRL_43143_SECI (1<<0) ++#define CCTRL_43143_BT_LEGACY (1<<1) ++#define CCTRL_43143_I2S_MODE (1<<2) /**< 0: SDIO enabled */ ++#define CCTRL_43143_I2S_MASTER (1<<3) /**< 0: I2S MCLK input disabled */ ++#define CCTRL_43143_I2S_FULL (1<<4) /**< 0: I2S SDIN and SPDIF_TX inputs disabled */ ++#define CCTRL_43143_GSIO (1<<5) /**< 0: sFlash enabled */ ++#define CCTRL_43143_RF_SWCTRL_MASK (7<<6) /**< 0: disabled */ ++#define CCTRL_43143_RF_SWCTRL_0 (1<<6) ++#define CCTRL_43143_RF_SWCTRL_1 (2<<6) ++#define CCTRL_43143_RF_SWCTRL_2 (4<<6) ++#define CCTRL_43143_RF_XSWCTRL (1<<9) /**< 0: UART enabled */ ++#define CCTRL_43143_HOST_WAKE0 (1<<11) /**< 1: SDIO separate interrupt output from GPIO4 */ ++#define CCTRL_43143_HOST_WAKE1 (1<<12) /* 1: SDIO separate interrupt output from GPIO16 */ ++ ++/* 43143 resources, based on pmu_params.xls V1.19 */ ++#define RES43143_EXT_SWITCHER_PWM 0 /**< 0x00001 */ ++#define RES43143_XTAL_PU 1 /**< 0x00002 */ ++#define RES43143_ILP_REQUEST 2 /**< 0x00004 */ ++#define RES43143_ALP_AVAIL 3 /**< 0x00008 */ ++#define RES43143_WL_CORE_READY 4 /**< 0x00010 */ ++#define RES43143_BBPLL_PWRSW_PU 5 /**< 0x00020 */ ++#define RES43143_HT_AVAIL 6 /**< 0x00040 */ ++#define RES43143_RADIO_PU 7 /**< 0x00080 */ ++#define RES43143_MACPHY_CLK_AVAIL 8 /**< 0x00100 */ ++#define RES43143_OTP_PU 9 /**< 0x00200 */ ++#define RES43143_LQ_AVAIL 10 /**< 0x00400 */ ++ ++#define PMU43143_XTAL_CORE_SIZE_MASK 0x3F ++ ++/* 4313 resources */ ++#define RES4313_BB_PU_RSRC 0 ++#define RES4313_ILP_REQ_RSRC 1 ++#define RES4313_XTAL_PU_RSRC 2 ++#define RES4313_ALP_AVAIL_RSRC 3 ++#define RES4313_RADIO_PU_RSRC 4 ++#define RES4313_BG_PU_RSRC 5 ++#define RES4313_VREG1P4_PU_RSRC 6 ++#define RES4313_AFE_PWRSW_RSRC 7 ++#define RES4313_RX_PWRSW_RSRC 8 ++#define RES4313_TX_PWRSW_RSRC 9 ++#define RES4313_BB_PWRSW_RSRC 10 ++#define RES4313_SYNTH_PWRSW_RSRC 11 ++#define RES4313_MISC_PWRSW_RSRC 12 ++#define RES4313_BB_PLL_PWRSW_RSRC 13 ++#define RES4313_HT_AVAIL_RSRC 14 ++#define RES4313_MACPHY_CLK_AVAIL_RSRC 15 ++ ++/* 4313 chip-specific ChipStatus register bits */ ++#define CST4313_SPROM_PRESENT 1 ++#define CST4313_OTP_PRESENT 2 ++#define CST4313_SPROM_OTP_SEL_MASK 0x00000002 ++#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 */ ++ ++/* PMU respources for 4314 */ ++#define RES4314_LPLDO_PU 0 ++#define RES4314_PMU_SLEEP_DIS 1 ++#define RES4314_PMU_BG_PU 2 ++#define RES4314_CBUCK_LPOM_PU 3 ++#define RES4314_CBUCK_PFM_PU 4 ++#define RES4314_CLDO_PU 5 ++#define RES4314_LPLDO2_LVM 6 ++#define RES4314_WL_PMU_PU 7 ++#define RES4314_LNLDO_PU 8 ++#define RES4314_LDO3P3_PU 9 ++#define RES4314_OTP_PU 10 ++#define RES4314_XTAL_PU 11 ++#define RES4314_WL_PWRSW_PU 12 ++#define RES4314_LQ_AVAIL 13 ++#define RES4314_LOGIC_RET 14 ++#define RES4314_MEM_SLEEP 15 ++#define RES4314_MACPHY_RET 16 ++#define RES4314_WL_CORE_READY 17 ++#define RES4314_ILP_REQ 18 ++#define RES4314_ALP_AVAIL 19 ++#define RES4314_MISC_PWRSW_PU 20 ++#define RES4314_SYNTH_PWRSW_PU 21 ++#define RES4314_RX_PWRSW_PU 22 ++#define RES4314_RADIO_PU 23 ++#define RES4314_VCO_LDO_PU 24 ++#define RES4314_AFE_LDO_PU 25 ++#define RES4314_RX_LDO_PU 26 ++#define RES4314_TX_LDO_PU 27 ++#define RES4314_HT_AVAIL 28 ++#define RES4314_MACPHY_CLK_AVAIL 29 ++ ++/* 4314 chip-specific ChipStatus register bits */ ++#define CST4314_OTP_ENABLED 0x00200000 ++ ++/* 43228 resources */ ++#define RES43228_NOT_USED 0 ++#define RES43228_ILP_REQUEST 1 ++#define RES43228_XTAL_PU 2 ++#define RES43228_ALP_AVAIL 3 ++#define RES43228_PLL_EN 4 ++#define RES43228_HT_PHY_AVAIL 5 ++ ++/* 43228 chipstatus reg bits */ ++#define CST43228_ILP_DIV_EN 0x1 ++#define CST43228_OTP_PRESENT 0x2 ++#define CST43228_SERDES_REFCLK_PADSEL 0x4 ++#define CST43228_SDIO_MODE 0x8 ++#define CST43228_SDIO_OTP_PRESENT 0x10 ++#define CST43228_SDIO_RESET 0x20 ++ ++/* 4706 chipstatus reg bits */ ++#define CST4706_PKG_OPTION (1<<0) /* 0: full-featured package 1: low-cost package */ ++#define CST4706_SFLASH_PRESENT (1<<1) /* 0: parallel, 1: serial flash is present */ ++#define CST4706_SFLASH_TYPE (1<<2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */ ++#define CST4706_MIPS_BENDIAN (1<<3) /* 0: little, 1: big endian */ ++#define CST4706_PCIE1_DISABLE (1<<5) /* PCIE1 enable strap pin */ ++ ++/* 4706 flashstrconfig reg bits */ ++#define FLSTRCF4706_MASK 0x000000ff ++#define FLSTRCF4706_SF1 0x00000001 /**< 2nd serial flash present */ ++#define FLSTRCF4706_PF1 0x00000002 /**< 2nd parallel flash present */ ++#define FLSTRCF4706_SF1_TYPE 0x00000004 /**< 2nd serial flash type : 0 : ST, 1 : Atmel */ ++#define FLSTRCF4706_NF1 0x00000008 /**< 2nd NAND flash present */ ++#define FLSTRCF4706_1ST_MADDR_SEG_MASK 0x000000f0 /**< Valid value mask */ ++#define FLSTRCF4706_1ST_MADDR_SEG_4MB 0x00000010 /**< 4MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_8MB 0x00000020 /**< 8MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_16MB 0x00000030 /**< 16MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_32MB 0x00000040 /**< 32MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_64MB 0x00000050 /**< 64MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_128MB 0x00000060 /**< 128MB */ ++#define FLSTRCF4706_1ST_MADDR_SEG_256MB 0x00000070 /**< 256MB */ ++ ++/* 4360 Chip specific ChipControl register bits */ ++#define CCTRL4360_I2C_MODE (1 << 0) ++#define CCTRL4360_UART_MODE (1 << 1) ++#define CCTRL4360_SECI_MODE (1 << 2) ++#define CCTRL4360_BTSWCTRL_MODE (1 << 3) ++#define CCTRL4360_DISCRETE_FEMCTRL_MODE (1 << 4) ++#define CCTRL4360_DIGITAL_PACTRL_MODE (1 << 5) ++#define CCTRL4360_BTSWCTRL_AND_DIGPA_PRESENT (1 << 6) ++#define CCTRL4360_EXTRA_GPIO_MODE (1 << 7) ++#define CCTRL4360_EXTRA_FEMCTRL_MODE (1 << 8) ++#define CCTRL4360_BT_LGCY_MODE (1 << 9) ++#define CCTRL4360_CORE2FEMCTRL4_ON (1 << 21) ++#define CCTRL4360_SECI_ON_GPIO01 (1 << 24) ++ ++/* 4360 Chip specific Regulator Control register bits */ ++#define RCTRL4360_RFLDO_PWR_DOWN (1 << 1) ++ ++/* 4360 PMU resources and chip status bits */ ++#define RES4360_REGULATOR 0 ++#define RES4360_ILP_AVAIL 1 ++#define RES4360_ILP_REQ 2 ++#define RES4360_XTAL_LDO_PU 3 ++#define RES4360_XTAL_PU 4 ++#define RES4360_ALP_AVAIL 5 ++#define RES4360_BBPLLPWRSW_PU 6 ++#define RES4360_HT_AVAIL 7 ++#define RES4360_OTP_PU 8 ++#define RES4360_AVB_PLL_PWRSW_PU 9 ++#define RES4360_PCIE_TL_CLK_AVAIL 10 ++ ++#define CST4360_XTAL_40MZ 0x00000001 ++#define CST4360_SFLASH 0x00000002 ++#define CST4360_SPROM_PRESENT 0x00000004 ++#define CST4360_SFLASH_TYPE 0x00000004 ++#define CST4360_OTP_ENABLED 0x00000008 ++#define CST4360_REMAP_ROM 0x00000010 ++#define CST4360_RSRC_INIT_MODE_MASK 0x00000060 ++#define CST4360_RSRC_INIT_MODE_SHIFT 5 ++#define CST4360_ILP_DIVEN 0x00000080 ++#define CST4360_MODE_USB 0x00000100 ++#define CST4360_SPROM_SIZE_MASK 0x00000600 ++#define CST4360_SPROM_SIZE_SHIFT 9 ++#define CST4360_BBPLL_LOCK 0x00000800 ++#define CST4360_AVBBPLL_LOCK 0x00001000 ++#define CST4360_USBBBPLL_LOCK 0x00002000 ++#define CST4360_RSRC_INIT_MODE(cs) ((cs & CST4360_RSRC_INIT_MODE_MASK) >> \ ++ CST4360_RSRC_INIT_MODE_SHIFT) ++ ++#define CCTRL_4360_UART_SEL 0x2 ++#define CST4360_RSRC_INIT_MODE(cs) ((cs & CST4360_RSRC_INIT_MODE_MASK) >> \ ++ CST4360_RSRC_INIT_MODE_SHIFT) ++ ++#define PMU4360_CC1_GPIO7_OVRD (1<<23) /* GPIO7 override */ ++ ++ ++/* 43602 PMU resources based on pmu_params.xls version v0.95 */ ++#define RES43602_LPLDO_PU 0 ++#define RES43602_REGULATOR 1 ++#define RES43602_PMU_SLEEP 2 ++#define RES43602_RSVD_3 3 ++#define RES43602_XTALLDO_PU 4 ++#define RES43602_SERDES_PU 5 ++#define RES43602_BBPLL_PWRSW_PU 6 ++#define RES43602_SR_CLK_START 7 ++#define RES43602_SR_PHY_PWRSW 8 ++#define RES43602_SR_SUBCORE_PWRSW 9 ++#define RES43602_XTAL_PU 10 ++#define RES43602_PERST_OVR 11 ++#define RES43602_SR_CLK_STABLE 12 ++#define RES43602_SR_SAVE_RESTORE 13 ++#define RES43602_SR_SLEEP 14 ++#define RES43602_LQ_START 15 ++#define RES43602_LQ_AVAIL 16 ++#define RES43602_WL_CORE_RDY 17 ++#define RES43602_ILP_REQ 18 ++#define RES43602_ALP_AVAIL 19 ++#define RES43602_RADIO_PU 20 ++#define RES43602_RFLDO_PU 21 ++#define RES43602_HT_START 22 ++#define RES43602_HT_AVAIL 23 ++#define RES43602_MACPHY_CLKAVAIL 24 ++#define RES43602_PARLDO_PU 25 ++#define RES43602_RSVD_26 26 ++ ++/* 43602 chip status bits */ ++#define CST43602_SPROM_PRESENT (1<<1) ++#define CST43602_SPROM_SIZE (1<<10) /* 0 = 16K, 1 = 4K */ ++#define CST43602_BBPLL_LOCK (1<<11) ++#define CST43602_RF_LDO_OUT_OK (1<<15) /* RF LDO output OK */ ++ ++#define PMU43602_CC1_GPIO12_OVRD (1<<28) /* GPIO12 override */ ++ ++#define PMU43602_CC2_PCIE_CLKREQ_L_WAKE_EN (1<<1) /* creates gated_pcie_wake, pmu_wakeup logic */ ++#define PMU43602_CC2_PCIE_PERST_L_WAKE_EN (1<<2) /* creates gated_pcie_wake, pmu_wakeup logic */ ++#define PMU43602_CC2_ENABLE_L2REFCLKPAD_PWRDWN (1<<3) ++#define PMU43602_CC2_PMU_WAKE_ALP_AVAIL_EN (1<<5) /* enable pmu_wakeup to request for ALP_AVAIL */ ++#define PMU43602_CC2_PERST_L_EXTEND_EN (1<<9) /* extend perst_l until rsc PERST_OVR comes up */ ++#define PMU43602_CC2_FORCE_EXT_LPO (1<<19) /* 1=ext LPO clock is the final LPO clock */ ++#define PMU43602_CC2_XTAL32_SEL (1<<30) /* 0=ext_clock, 1=xtal */ ++ ++#define CC_SR1_43602_SR_ASM_ADDR (0x0) ++ ++/* PLL CTL register values for open loop, used during S/R operation */ ++#define PMU43602_PLL_CTL6_VAL 0x68000528 ++#define PMU43602_PLL_CTL7_VAL 0x6 ++ ++#define PMU43602_CC3_ARMCR4_DBG_CLK (1 << 29) ++ ++/* 4365 PMU resources */ ++#define RES4365_REGULATOR_PU 0 ++#define RES4365_XTALLDO_PU 1 ++#define RES4365_XTAL_PU 2 ++#define RES4365_CPU_PLLLDO_PU 3 ++#define RES4365_CPU_PLL_PU 4 ++#define RES4365_WL_CORE_RDY 5 ++#define RES4365_ILP_REQ 6 ++#define RES4365_ALP_AVAIL 7 ++#define RES4365_HT_AVAIL 8 ++#define RES4365_BB_PLLLDO_PU 9 ++#define RES4365_BB_PLL_PU 10 ++#define RES4365_MINIMU_PU 11 ++#define RES4365_RADIO_PU 12 ++#define RES4365_MACPHY_CLK_AVAIL 13 ++ ++/* 4349 related */ ++#define RES4349_LPLDO_PU 0 ++#define RES4349_BG_PU 1 ++#define RES4349_PMU_SLEEP 2 ++#define RES4349_PALDO3P3_PU 3 ++#define RES4349_CBUCK_LPOM_PU 4 ++#define RES4349_CBUCK_PFM_PU 5 ++#define RES4349_COLD_START_WAIT 6 ++#define RES4349_RSVD_7 7 ++#define RES4349_LNLDO_PU 8 ++#define RES4349_XTALLDO_PU 9 ++#define RES4349_LDO3P3_PU 10 ++#define RES4349_OTP_PU 11 ++#define RES4349_XTAL_PU 12 ++#define RES4349_SR_CLK_START 13 ++#define RES4349_LQ_AVAIL 14 ++#define RES4349_LQ_START 15 ++#define RES4349_PERST_OVR 16 ++#define RES4349_WL_CORE_RDY 17 ++#define RES4349_ILP_REQ 18 ++#define RES4349_ALP_AVAIL 19 ++#define RES4349_MINI_PMU 20 ++#define RES4349_RADIO_PU 21 ++#define RES4349_SR_CLK_STABLE 22 ++#define RES4349_SR_SAVE_RESTORE 23 ++#define RES4349_SR_PHY_PWRSW 24 ++#define RES4349_SR_VDDM_PWRSW 25 ++#define RES4349_SR_SUBCORE_PWRSW 26 ++#define RES4349_SR_SLEEP 27 ++#define RES4349_HT_START 28 ++#define RES4349_HT_AVAIL 29 ++#define RES4349_MACPHY_CLKAVAIL 30 ++ ++/* SR Control0 bits */ ++#define CC_SR0_4349_SR_ENG_EN_MASK 0x1 ++#define CC_SR0_4349_SR_ENG_EN_SHIFT 0 ++#define CC_SR0_4349_SR_ENG_CLK_EN (1 << 1) ++#define CC_SR0_4349_SR_RSRC_TRIGGER (0xC << 2) ++#define CC_SR0_4349_SR_WD_MEM_MIN_DIV (0x3 << 6) ++#define CC_SR0_4349_SR_MEM_STBY_ALLOW_MSK (1 << 16) ++#define CC_SR0_4349_SR_MEM_STBY_ALLOW_SHIFT 16 ++#define CC_SR0_4349_SR_ENABLE_ILP (1 << 17) ++#define CC_SR0_4349_SR_ENABLE_ALP (1 << 18) ++#define CC_SR0_4349_SR_ENABLE_HT (1 << 19) ++#define CC_SR0_4349_SR_ALLOW_PIC (3 << 20) ++#define CC_SR0_4349_SR_PMU_MEM_DISABLE (1 << 30) ++ ++/* SR Control0 bits */ ++#define CC_SR0_4349_SR_ENG_EN_MASK 0x1 ++#define CC_SR0_4349_SR_ENG_EN_SHIFT 0 ++#define CC_SR0_4349_SR_ENG_CLK_EN (1 << 1) ++#define CC_SR0_4349_SR_RSRC_TRIGGER (0xC << 2) ++#define CC_SR0_4349_SR_WD_MEM_MIN_DIV (0x3 << 6) ++#define CC_SR0_4349_SR_MEM_STBY_ALLOW (1 << 16) ++#define CC_SR0_4349_SR_ENABLE_ILP (1 << 17) ++#define CC_SR0_4349_SR_ENABLE_ALP (1 << 18) ++#define CC_SR0_4349_SR_ENABLE_HT (1 << 19) ++#define CC_SR0_4349_SR_ALLOW_PIC (3 << 20) ++#define CC_SR0_4349_SR_PMU_MEM_DISABLE (1 << 30) ++ ++/* SR binary offset is at 8K */ ++#define CC_SR1_4349_SR_ASM_ADDR (0x10) ++ ++#define CST4349_CHIPMODE_SDIOD(cs) (((cs) & (1 << 6)) != 0) /* SDIO */ ++#define CST4349_CHIPMODE_PCIE(cs) (((cs) & (1 << 7)) != 0) /* PCIE */ ++ ++#define CST4349_SPROM_PRESENT 0x00000010 ++ ++#define VREG4_4349_MEMLPLDO_PWRUP_MASK (1 << 31) ++#define VREG4_4349_MEMLPLDO_PWRUP_SHIFT (31) ++#define VREG4_4349_LPLDO1_OUTPUT_VOLT_ADJ_MASK (0x7 << 15) ++#define VREG4_4349_LPLDO1_OUTPUT_VOLT_ADJ_SHIFT (15) ++#define CC2_4349_PHY_PWRSE_RST_CNT_MASK (0xF << 0) ++#define CC2_4349_PHY_PWRSE_RST_CNT_SHIFT (0) ++#define CC2_4349_VDDM_PWRSW_EN_MASK (1 << 20) ++#define CC2_4349_VDDM_PWRSW_EN_SHIFT (20) ++#define CC2_4349_MEMLPLDO_PWRSW_EN_MASK (1 << 21) ++#define CC2_4349_MEMLPLDO_PWRSW_EN_SHIFT (21) ++#define CC2_4349_SDIO_AOS_WAKEUP_MASK (1 << 24) ++#define CC2_4349_SDIO_AOS_WAKEUP_SHIFT (24) ++#define CC2_4349_PMUWAKE_EN_MASK (1 << 31) ++#define CC2_4349_PMUWAKE_EN_SHIFT (31) ++ ++#define CC5_4349_MAC_PHY_CLK_8_DIV (1 << 27) ++ ++#define CC6_4349_PCIE_CLKREQ_WAKEUP_MASK (1 << 4) ++#define CC6_4349_PCIE_CLKREQ_WAKEUP_SHIFT (4) ++#define CC6_4349_PMU_WAKEUP_ALPAVAIL_MASK (1 << 6) ++#define CC6_4349_PMU_WAKEUP_ALPAVAIL_SHIFT (6) ++#define CC6_4349_PMU_EN_EXT_PERST_MASK (1 << 13) ++#define CC6_4349_PMU_EN_L2_DEASSERT_MASK (1 << 14) ++#define CC6_4349_PMU_EN_L2_DEASSERT_SHIF (14) ++#define CC6_4349_PMU_ENABLE_L2REFCLKPAD_PWRDWN (1 << 15) ++#define CC6_4349_PMU_EN_MDIO_MASK (1 << 16) ++#define CC6_4349_PMU_EN_ASSERT_L2_MASK (1 << 25) ++ ++ ++/* 4349 GCI function sel values */ ++/* ++ * Reference ++ * http://hwnbu-twiki.sj.broadcom.com/bin/view/Mwgroup/ToplevelArchitecture4349B0#Function_Sel ++ */ ++#define CC4349_FNSEL_HWDEF (0) ++#define CC4349_FNSEL_SAMEASPIN (1) ++#define CC4349_FNSEL_GPIO (2) ++#define CC4349_FNSEL_FAST_UART (3) ++#define CC4349_FNSEL_GCI0 (4) ++#define CC4349_FNSEL_GCI1 (5) ++#define CC4349_FNSEL_DGB_UART (6) ++#define CC4349_FNSEL_I2C (7) ++#define CC4349_FNSEL_SPROM (8) ++#define CC4349_FNSEL_MISC0 (9) ++#define CC4349_FNSEL_MISC1 (10) ++#define CC4349_FNSEL_MISC2 (11) ++#define CC4349_FNSEL_IND (12) ++#define CC4349_FNSEL_PDN (13) ++#define CC4349_FNSEL_PUP (14) ++#define CC4349_FNSEL_TRISTATE (15) ++ ++/* 4364 related */ ++#define RES4364_LPLDO_PU 0 ++#define RES4364_BG_PU 1 ++#define RES4364_MEMLPLDO_PU 2 ++#define RES4364_PALDO3P3_PU 3 ++#define RES4364_CBUCK_1P2 4 ++#define RES4364_CBUCK_1V8 5 ++#define RES4364_COLD_START_WAIT 6 ++#define RES4364_SR_3x3_VDDM_PWRSW 7 ++#define RES4364_3x3_MACPHY_CLKAVAIL 8 ++#define RES4364_XTALLDO_PU 9 ++#define RES4364_LDO3P3_PU 10 ++#define RES4364_OTP_PU 11 ++#define RES4364_XTAL_PU 12 ++#define RES4364_SR_CLK_START 13 ++#define RES4364_3x3_RADIO_PU 14 ++#define RES4364_RF_LDO 15 ++#define RES4364_PERST_OVR 16 ++#define RES4364_WL_CORE_RDY 17 ++#define RES4364_ILP_REQ 18 ++#define RES4364_ALP_AVAIL 19 ++#define RES4364_1x1_MINI_PMU 20 ++#define RES4364_1x1_RADIO_PU 21 ++#define RES4364_SR_CLK_STABLE 22 ++#define RES4364_SR_SAVE_RESTORE 23 ++#define RES4364_SR_PHY_PWRSW 24 ++#define RES4364_SR_VDDM_PWRSW 25 ++#define RES4364_SR_SUBCORE_PWRSW 26 ++#define RES4364_SR_SLEEP 27 ++#define RES4364_HT_START 28 ++#define RES4364_HT_AVAIL 29 ++#define RES4364_MACPHY_CLKAVAIL 30 ++ ++/* 4349 GPIO */ ++#define CC4349_PIN_GPIO_00 (0) ++#define CC4349_PIN_GPIO_01 (1) ++#define CC4349_PIN_GPIO_02 (2) ++#define CC4349_PIN_GPIO_03 (3) ++#define CC4349_PIN_GPIO_04 (4) ++#define CC4349_PIN_GPIO_05 (5) ++#define CC4349_PIN_GPIO_06 (6) ++#define CC4349_PIN_GPIO_07 (7) ++#define CC4349_PIN_GPIO_08 (8) ++#define CC4349_PIN_GPIO_09 (9) ++#define CC4349_PIN_GPIO_10 (10) ++#define CC4349_PIN_GPIO_11 (11) ++#define CC4349_PIN_GPIO_12 (12) ++#define CC4349_PIN_GPIO_13 (13) ++#define CC4349_PIN_GPIO_14 (14) ++#define CC4349_PIN_GPIO_15 (15) ++#define CC4349_PIN_GPIO_16 (16) ++#define CC4349_PIN_GPIO_17 (17) ++#define CC4349_PIN_GPIO_18 (18) ++#define CC4349_PIN_GPIO_19 (19) ++ ++/* Mask used to decide whether HOSTWAKE MUX to be performed or not */ ++#define MUXENAB4349_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ ++#define MUXENAB4349_HOSTWAKE_SHIFT 4 ++#define MUXENAB4349_GETIX(val, name) \ ++ ((((val) & MUXENAB4349_ ## name ## _MASK) >> MUXENAB4349_ ## name ## _SHIFT) - 1) ++ ++#define CR4_4364_RAM_BASE (0x160000) ++ ++/* SR binary offset is at 8K */ ++#define CC_SR1_4364_SR_CORE0_ASM_ADDR (0x10) ++#define CC_SR1_4364_SR_CORE1_ASM_ADDR (0x10) ++ ++#define CC_SR0_4364_SR_ENG_EN_MASK 0x1 ++#define CC_SR0_4364_SR_ENG_EN_SHIFT 0 ++#define CC_SR0_4364_SR_ENG_CLK_EN (1 << 1) ++#define CC_SR0_4364_SR_RSRC_TRIGGER (0xC << 2) ++#define CC_SR0_4364_SR_WD_MEM_MIN_DIV (0x3 << 6) ++#define CC_SR0_4364_SR_MEM_STBY_ALLOW_MSK (1 << 16) ++#define CC_SR0_4364_SR_MEM_STBY_ALLOW_SHIFT 16 ++#define CC_SR0_4364_SR_ENABLE_ILP (1 << 17) ++#define CC_SR0_4364_SR_ENABLE_ALP (1 << 18) ++#define CC_SR0_4364_SR_ENABLE_HT (1 << 19) ++#define CC_SR0_4364_SR_ALLOW_PIC (3 << 20) ++#define CC_SR0_4364_SR_PMU_MEM_DISABLE (1 << 30) ++ ++#define PMU_4364_CC1_ENABLE_BBPLL_PWR_DWN (0x1 << 4) ++#define PMU_4364_CC1_BBPLL_ARESET_LQ_TIME (0x1 << 8) ++#define PMU_4364_CC1_BBPLL_ARESET_HT_UPTIME (0x1 << 10) ++#define PMU_4364_CC1_BBPLL_DRESET_LQ_UPTIME (0x1 << 12) ++#define PMU_4364_CC1_BBPLL_DRESET_HT_UPTIME (0x4 << 16) ++#define PMU_4364_CC1_SUBCORE_PWRSW_UP_DELAY (0x8 << 20) ++#define PMU_4364_CC1_SUBCORE_PWRSW_RESET_CNT (0x4 << 24) ++ ++#define PMU_4364_CC2_PHY_PWRSW_RESET_CNT (0x2 << 0) ++#define PMU_4364_CC2_PHY_PWRSW_RESET_MASK (0x7) ++#define PMU_4364_CC2_SEL_CHIPC_IF_FOR_SR (1 << 21) ++ ++#define PMU_4364_CC3_MEMLPLDO3x3_PWRSW_FORCE_MASK (1 << 23) ++#define PMU_4364_CC3_MEMLPLDO1x1_PWRSW_FORCE_MASK (1 << 24) ++#define PMU_4364_CC3_CBUCK1P2_PU_SR_VDDM_REQ_ON (1 << 25) ++#define PMU_4364_CC3_MEMLPLDO3x3_PWRSW_FORCE_OFF (0) ++#define PMU_4364_CC3_MEMLPLDO1x1_PWRSW_FORCE_OFF (0) ++ ++ ++#define PMU_4364_CC5_DISABLE_BBPLL_CLKOUT6_DIV2_MASK (1 << 26) ++#define PMU_4364_CC5_ENABLE_ARMCR4_DEBUG_CLK_MASK (1 << 4) ++#define PMU_4364_CC5_DISABLE_BBPLL_CLKOUT6_DIV2 (1 << 26) ++#define PMU_4364_CC5_ENABLE_ARMCR4_DEBUG_CLK_OFF (0) ++ ++#define PMU_4364_CC6_MDI_RESET_MASK (1 << 16) ++#define PMU_4364_CC6_USE_CLK_REQ_MASK (1 << 18) ++#define PMU_4364_CC6_HIGHER_CLK_REQ_ALP_MASK (1 << 20) ++#define PMU_4364_CC6_HT_AVAIL_REQ_ALP_AVAIL_MASK (1 << 21) ++#define PMU_4364_CC6_PHY_CLK_REQUESTS_ALP_AVAIL_MASK (1 << 22) ++#define PMU_4364_CC6_MDI_RESET (1 << 16) ++#define PMU_4364_CC6_USE_CLK_REQ (1 << 18) ++ ++#define PMU_4364_CC6_HIGHER_CLK_REQ_ALP (1 << 20) ++#define PMU_4364_CC6_HT_AVAIL_REQ_ALP_AVAIL (1 << 21) ++#define PMU_4364_CC6_PHY_CLK_REQUESTS_ALP_AVAIL (1 << 22) ++ ++#define PMU_4364_VREG0_DISABLE_BT_PULL_DOWN (1 << 2) ++#define PMU_4364_VREG1_DISABLE_WL_PULL_DOWN (1 << 2) ++ ++#define PMU_VREG_0 (0x0) ++#define PMU_VREG_1 (0x1) ++#define PMU_VREG_3 (0x3) ++#define PMU_VREG_4 (0x4) ++#define PMU_VREG_5 (0x5) ++#define PMU_VREG_6 (0x6) ++ ++#define PMU_4364_VREG3_DISABLE_WPT_REG_ON_PULL_DOWN (1 << 11) ++ ++#define PMU_4364_VREG4_MEMLPLDO_PU_ON (1 << 31) ++#define PMU_4364_VREG4_LPLPDO_ADJ (3 << 16) ++#define PMU_4364_VREG4_LPLPDO_ADJ_MASK (3 << 16) ++#define PMU_4364_VREG5_MAC_CLK_1x1_AUTO (0x1 << 18) ++#define PMU_4364_VREG5_SR_AUTO (0x1 << 20) ++#define PMU_4364_VREG5_BT_PWM_MASK (0x1 << 21) ++#define PMU_4364_VREG5_BT_AUTO (0x1 << 22) ++#define PMU_4364_VREG5_WL2CLB_DVFS_EN_MASK (0x1 << 23) ++#define PMU_4364_VREG5_BT_PWMK (0) ++#define PMU_4364_VREG5_WL2CLB_DVFS_EN (0) ++ ++#define PMU_4364_VREG6_BBPLL_AUTO (0x1 << 17) ++#define PMU_4364_VREG6_MINI_PMU_PWM (0x1 << 18) ++#define PMU_4364_VREG6_LNLDO_AUTO (0x1 << 21) ++#define PMU_4364_VREG6_PCIE_PWRDN_0_AUTO (0x1 << 23) ++#define PMU_4364_VREG6_PCIE_PWRDN_1_AUTO (0x1 << 25) ++#define PMU_4364_VREG6_MAC_CLK_3x3_PWM (0x1 << 27) ++#define PMU_4364_VREG6_ENABLE_FINE_CTRL (0x1 << 30) ++ ++#define PMU_4364_PLL0_DISABLE_CHANNEL6 (0x1 << 18) ++ ++#define CC_GCI1_REG (0x1) ++#define CC_GCI1_4364_IND_STATE_FOR_GPIO9_11 (0x0ccccccc) ++#define CC2_4364_SDIO_AOS_WAKEUP_MASK (1 << 24) ++#define CC2_4364_SDIO_AOS_WAKEUP_SHIFT (24) ++ ++#define CC6_4364_PCIE_CLKREQ_WAKEUP_MASK (1 << 4) ++#define CC6_4364_PCIE_CLKREQ_WAKEUP_SHIFT (4) ++#define CC6_4364_PMU_WAKEUP_ALPAVAIL_MASK (1 << 6) ++#define CC6_4364_PMU_WAKEUP_ALPAVAIL_SHIFT (6) ++ ++#define CST4364_CHIPMODE_SDIOD(cs) (((cs) & (1 << 6)) != 0) /* SDIO */ ++#define CST4364_CHIPMODE_PCIE(cs) (((cs) & (1 << 7)) != 0) /* PCIE */ ++#define CST4364_SPROM_PRESENT 0x00000010 ++ ++#define PMU_4364_MACCORE_0_RES_REQ_MASK 0x3FCBF7FF ++#define PMU_4364_MACCORE_1_RES_REQ_MASK 0x7FFB3647 ++ ++ ++#define PMU1_PLL0_SWITCH_MACCLOCK_120MHZ (0) ++#define PMU1_PLL0_SWITCH_MACCLOCK_160MHZ (1) ++#define TSF_CLK_FRAC_L_4364_120MHZ 0x8889 ++#define TSF_CLK_FRAC_H_4364_120MHZ 0x8 ++#define TSF_CLK_FRAC_L_4364_160MHZ 0x6666 ++#define TSF_CLK_FRAC_H_4364_160MHZ 0x6 ++#define PMU1_PLL0_PC1_M2DIV_VALUE_120MHZ 8 ++#define PMU1_PLL0_PC1_M2DIV_VALUE_160MHZ 6 ++ ++#define CST4347_CHIPMODE_SDIOD(cs) (((cs) & (1 << 6)) != 0) /* SDIO */ ++#define CST4347_CHIPMODE_PCIE(cs) (((cs) & (1 << 7)) != 0) /* PCIE */ ++#define CST4347_SPROM_PRESENT 0x00000010 ++ ++/* 43430 PMU resources based on pmu_params.xls */ ++#define RES43430_LPLDO_PU 0 ++#define RES43430_BG_PU 1 ++#define RES43430_PMU_SLEEP 2 ++#define RES43430_RSVD_3 3 ++#define RES43430_CBUCK_LPOM_PU 4 ++#define RES43430_CBUCK_PFM_PU 5 ++#define RES43430_COLD_START_WAIT 6 ++#define RES43430_RSVD_7 7 ++#define RES43430_LNLDO_PU 8 ++#define RES43430_RSVD_9 9 ++#define RES43430_LDO3P3_PU 10 ++#define RES43430_OTP_PU 11 ++#define RES43430_XTAL_PU 12 ++#define RES43430_SR_CLK_START 13 ++#define RES43430_LQ_AVAIL 14 ++#define RES43430_LQ_START 15 ++#define RES43430_RSVD_16 16 ++#define RES43430_WL_CORE_RDY 17 ++#define RES43430_ILP_REQ 18 ++#define RES43430_ALP_AVAIL 19 ++#define RES43430_MINI_PMU 20 ++#define RES43430_RADIO_PU 21 ++#define RES43430_SR_CLK_STABLE 22 ++#define RES43430_SR_SAVE_RESTORE 23 ++#define RES43430_SR_PHY_PWRSW 24 ++#define RES43430_SR_VDDM_PWRSW 25 ++#define RES43430_SR_SUBCORE_PWRSW 26 ++#define RES43430_SR_SLEEP 27 ++#define RES43430_HT_START 28 ++#define RES43430_HT_AVAIL 29 ++#define RES43430_MACPHY_CLK_AVAIL 30 ++ ++/* 43430 chip status bits */ ++#define CST43430_SDIO_MODE 0x00000001 ++#define CST43430_GSPI_MODE 0x00000002 ++#define CST43430_RSRC_INIT_MODE_0 0x00000080 ++#define CST43430_RSRC_INIT_MODE_1 0x00000100 ++#define CST43430_SEL0_SDIO 0x00000200 ++#define CST43430_SEL1_SDIO 0x00000400 ++#define CST43430_SEL2_SDIO 0x00000800 ++#define CST43430_BBPLL_LOCKED 0x00001000 ++#define CST43430_DBG_INST_DETECT 0x00004000 ++#define CST43430_CLB2WL_BT_READY 0x00020000 ++#define CST43430_JTAG_MODE 0x00100000 ++#define CST43430_HOST_IFACE 0x00400000 ++#define CST43430_TRIM_EN 0x00800000 ++#define CST43430_DIN_PACKAGE_OPTION 0x10000000 ++ ++#define PMU43430_PLL0_PC2_P1DIV_MASK 0x0000000f ++#define PMU43430_PLL0_PC2_P1DIV_SHIFT 0 ++#define PMU43430_PLL0_PC2_NDIV_INT_MASK 0x0000ff80 ++#define PMU43430_PLL0_PC2_NDIV_INT_SHIFT 7 ++#define PMU43430_PLL0_PC4_MDIV2_MASK 0x0000ff00 ++#define PMU43430_PLL0_PC4_MDIV2_SHIFT 8 ++ ++/* 43430 chip SR definitions */ ++#define SRAM_43430_SR_ASM_ADDR 0x7f800 ++#define CC_SR1_43430_SR_ASM_ADDR ((SRAM_43430_SR_ASM_ADDR - 0x60000) >> 8) ++ ++/* 43430 PMU Chip Control bits */ ++#define CC2_43430_SDIO_AOS_WAKEUP_MASK (1 << 24) ++#define CC2_43430_SDIO_AOS_WAKEUP_SHIFT (24) ++ ++ ++#define PMU_MACCORE_0_RES_REQ_TIMER 0x1d000000 ++#define PMU_MACCORE_0_RES_REQ_MASK 0x5FF2364F ++ ++#define PMU_MACCORE_1_RES_REQ_TIMER 0x1d000000 ++#define PMU_MACCORE_1_RES_REQ_MASK 0x5FF2364F ++ ++/* defines to detect active host interface in use */ ++#define CHIP_HOSTIF_PCIEMODE 0x1 ++#define CHIP_HOSTIF_USBMODE 0x2 ++#define CHIP_HOSTIF_SDIOMODE 0x4 ++#define CHIP_HOSTIF_PCIE(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_PCIEMODE) ++#define CHIP_HOSTIF_USB(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_USBMODE) ++#define CHIP_HOSTIF_SDIO(sih) (si_chip_hostif(sih) == CHIP_HOSTIF_SDIOMODE) ++ ++/* 4335 resources */ ++#define RES4335_LPLDO_PO 0 ++#define RES4335_PMU_BG_PU 1 ++#define RES4335_PMU_SLEEP 2 ++#define RES4335_RSVD_3 3 ++#define RES4335_CBUCK_LPOM_PU 4 ++#define RES4335_CBUCK_PFM_PU 5 ++#define RES4335_RSVD_6 6 ++#define RES4335_RSVD_7 7 ++#define RES4335_LNLDO_PU 8 ++#define RES4335_XTALLDO_PU 9 ++#define RES4335_LDO3P3_PU 10 ++#define RES4335_OTP_PU 11 ++#define RES4335_XTAL_PU 12 ++#define RES4335_SR_CLK_START 13 ++#define RES4335_LQ_AVAIL 14 ++#define RES4335_LQ_START 15 ++#define RES4335_RSVD_16 16 ++#define RES4335_WL_CORE_RDY 17 ++#define RES4335_ILP_REQ 18 ++#define RES4335_ALP_AVAIL 19 ++#define RES4335_MINI_PMU 20 ++#define RES4335_RADIO_PU 21 ++#define RES4335_SR_CLK_STABLE 22 ++#define RES4335_SR_SAVE_RESTORE 23 ++#define RES4335_SR_PHY_PWRSW 24 ++#define RES4335_SR_VDDM_PWRSW 25 ++#define RES4335_SR_SUBCORE_PWRSW 26 ++#define RES4335_SR_SLEEP 27 ++#define RES4335_HT_START 28 ++#define RES4335_HT_AVAIL 29 ++#define RES4335_MACPHY_CLKAVAIL 30 ++ ++/* 4335 Chip specific ChipStatus register bits */ ++#define CST4335_SPROM_MASK 0x00000020 ++#define CST4335_SFLASH_MASK 0x00000040 ++#define CST4335_RES_INIT_MODE_SHIFT 7 ++#define CST4335_RES_INIT_MODE_MASK 0x00000180 ++#define CST4335_CHIPMODE_MASK 0xF ++#define CST4335_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ ++#define CST4335_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ ++#define CST4335_CHIPMODE_USB20D(cs) (((cs) & (1 << 2)) != 0) /**< HSIC || USBDA */ ++#define CST4335_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ ++ ++/* 4335 Chip specific ChipControl1 register bits */ ++#define CCTRL1_4335_GPIO_SEL (1 << 0) /* 1=select GPIOs to be muxed out */ ++#define CCTRL1_4335_SDIO_HOST_WAKE (1 << 2) /* SDIO: 1=configure GPIO0 for host wake */ ++ ++/* 4335 Chip specific ChipControl2 register bits */ ++#define CCTRL2_4335_AOSBLOCK (1 << 30) ++#define CCTRL2_4335_PMUWAKE (1 << 31) ++#define PATCHTBL_SIZE (0x800) ++#define CR4_4335_RAM_BASE (0x180000) ++#define CR4_4345_LT_C0_RAM_BASE (0x1b0000) ++#define CR4_4345_GE_C0_RAM_BASE (0x198000) ++#define CR4_4349_RAM_BASE (0x180000) ++#define CR4_4349_RAM_BASE_FROM_REV_9 (0x160000) ++#define CR4_4350_RAM_BASE (0x180000) ++#define CR4_4360_RAM_BASE (0x0) ++#define CR4_43602_RAM_BASE (0x180000) ++#define CA7_4365_RAM_BASE (0x200000) ++ ++#define CR4_4347_RAM_BASE (0x170000) ++#define CR4_4362_RAM_BASE (0x170000) ++ ++/* 4335 chip OTP present & OTP select bits. */ ++#define SPROM4335_OTP_SELECT 0x00000010 ++#define SPROM4335_OTP_PRESENT 0x00000020 ++ ++/* 4335 GCI specific bits. */ ++#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) ++#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 ++#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 ++ ++/* SFLASH clkdev specific bits. */ ++#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 ++#define CC4335_SFLASH_CLKDIV_SHIFT 25 ++ ++/* 4335 OTP bits for SFLASH. */ ++#define CC4335_SROM_OTP_SFLASH 40 ++#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 ++#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 ++#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C ++#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 ++ ++ ++/* 4335 chip OTP present & OTP select bits. */ ++#define SPROM4335_OTP_SELECT 0x00000010 ++#define SPROM4335_OTP_PRESENT 0x00000020 ++ ++/* 4335 GCI specific bits. */ ++#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_PRESENT (1 << 24) ++#define CC4335_GCI_STRAP_OVERRIDE_SFLASH_TYPE 25 ++#define CC4335_GCI_FUNC_SEL_PAD_SDIO 0x00707770 ++ ++/* SFLASH clkdev specific bits. */ ++#define CC4335_SFLASH_CLKDIV_MASK 0x1F000000 ++#define CC4335_SFLASH_CLKDIV_SHIFT 25 ++ ++/* 4335 OTP bits for SFLASH. */ ++#define CC4335_SROM_OTP_SFLASH 40 ++#define CC4335_SROM_OTP_SFLASH_PRESENT 0x1 ++#define CC4335_SROM_OTP_SFLASH_TYPE 0x2 ++#define CC4335_SROM_OTP_SFLASH_CLKDIV_MASK 0x003C ++#define CC4335_SROM_OTP_SFLASH_CLKDIV_SHIFT 2 ++ ++/* 4335 resources--END */ ++ ++/* 43012 PMU resources based on pmu_params.xls - Start */ ++#define RES43012_MEMLPLDO_PU 0 ++#define RES43012_PMU_SLEEP 1 ++#define RES43012_FAST_LPO 2 ++#define RES43012_BTLPO_3P3 3 ++#define RES43012_SR_POK 4 ++#define RES43012_DUMMY_PWRSW 5 ++#define RES43012_DUMMY_LDO3P3 6 ++#define RES43012_DUMMY_BT_LDO3P3 7 ++#define RES43012_DUMMY_RADIO 8 ++#define RES43012_VDDB_VDDRET 9 ++#define RES43012_HV_LDO3P3 10 ++#define RES43012_OTP_PU 11 ++#define RES43012_XTAL_PU 12 ++#define RES43012_SR_CLK_START 13 ++#define RES43012_XTAL_STABLE 14 ++#define RES43012_FCBS 15 ++#define RES43012_CBUCK_MODE 16 ++#define RES43012_WL_CORE_RDY 17 ++#define RES43012_ILP_REQ 18 ++#define RES43012_ALP_AVAIL 19 ++#define RES43012_RADIO_LDO 20 ++#define RES43012_MINI_PMU 21 ++#define RES43012_DUMMY 22 ++#define RES43012_SR_SAVE_RESTORE 23 ++#define RES43012_SR_PHY_PWRSW 24 ++#define RES43012_SR_VDDB_CLDO 25 ++#define RES43012_SR_SUBCORE_PWRSW 26 ++#define RES43012_SR_SLEEP 27 ++#define RES43012_HT_START 28 ++#define RES43012_HT_AVAIL 29 ++#define RES43012_MACPHY_CLK_AVAIL 30 ++#define CST43012_SPROM_PRESENT 0x00000010 ++ ++/* PLL usage in 43012 */ ++#define PMU43012_PLL0_PC0_NDIV_INT_MASK 0x0000003f ++#define PMU43012_PLL0_PC0_NDIV_INT_SHIFT 0 ++#define PMU43012_PLL0_PC0_NDIV_FRAC_MASK 0xfffffc00 ++#define PMU43012_PLL0_PC0_NDIV_FRAC_SHIFT 10 ++#define PMU43012_PLL0_PC3_PDIV_MASK 0x00003c00 ++#define PMU43012_PLL0_PC3_PDIV_SHIFT 10 ++#define PMU43012_PLL_NDIV_FRAC_BITS 20 ++#define PMU43012_PLL_P_DIV_SCALE_BITS 10 ++ ++#define CCTL_43012_ARM_OFFCOUNT_MASK 0x00000003 ++#define CCTL_43012_ARM_OFFCOUNT_SHIFT 0 ++#define CCTL_43012_ARM_ONCOUNT_MASK 0x0000000c ++#define CCTL_43012_ARM_ONCOUNT_SHIFT 2 ++ ++/* PMU Rev >= 30 */ ++#define PMU30_ALPCLK_ONEMHZ_ENAB 0x80000000 ++ ++/* 43012 PMU Chip Control Registers */ ++#define PMUCCTL02_43012_SUBCORE_PWRSW_FORCE_ON 0x00000010 ++#define PMUCCTL02_43012_PHY_PWRSW_FORCE_ON 0x00000040 ++#define PMUCCTL02_43012_LHL_TIMER_SELECT 0x00000800 ++#define PMUCCTL02_43012_RFLDO3P3_PU_FORCE_ON 0x00008000 ++#define PMUCCTL02_43012_WL2CDIG_I_PMU_SLEEP_ENAB 0x00010000 ++ ++#define PMUCCTL04_43012_BBPLL_ENABLE_PWRDN 0x00100000 ++#define PMUCCTL04_43012_BBPLL_ENABLE_PWROFF 0x00200000 ++#define PMUCCTL04_43012_FORCE_BBPLL_ARESET 0x00400000 ++#define PMUCCTL04_43012_FORCE_BBPLL_DRESET 0x00800000 ++#define PMUCCTL04_43012_FORCE_BBPLL_PWRDN 0x01000000 ++#define PMUCCTL04_43012_FORCE_BBPLL_ISOONHIGH 0x02000000 ++#define PMUCCTL04_43012_FORCE_BBPLL_PWROFF 0x04000000 ++#define PMUCCTL04_43012_DISABLE_LQ_AVAIL 0x08000000 ++#define PMUCCTL04_43012_DISABLE_HT_AVAIL 0x10000000 ++#define PMUCCTL04_43012_USE_LOCK 0x20000000 ++#define PMUCCTL04_43012_OPEN_LOOP_ENABLE 0x40000000 ++#define PMUCCTL04_43012_FORCE_OPEN_LOOP 0x80000000 ++#define PMUCCTL08_43012_XTAL_CORE_SIZE_PMOS_NORMAL_MASK 0x00000FC0 ++#define PMUCCTL08_43012_XTAL_CORE_SIZE_PMOS_NORMAL_SHIFT 6 ++#define PMUCCTL08_43012_XTAL_CORE_SIZE_NMOS_NORMAL_MASK 0x00FC0000 ++#define PMUCCTL08_43012_XTAL_CORE_SIZE_NMOS_NORMAL_SHIFT 18 ++#define PMUCCTL08_43012_XTAL_SEL_BIAS_RES_NORMAL_MASK 0x07000000 ++#define PMUCCTL08_43012_XTAL_SEL_BIAS_RES_NORMAL_SHIFT 24 ++#define PMUCCTL09_43012_XTAL_CORESIZE_BIAS_ADJ_NORMAL_MASK 0x0003F000 ++#define PMUCCTL09_43012_XTAL_CORESIZE_BIAS_ADJ_NORMAL_SHIFT 12 ++#define PMUCCTL09_43012_XTAL_CORESIZE_RES_BYPASS_NORMAL_MASK 0x00000038 ++#define PMUCCTL09_43012_XTAL_CORESIZE_RES_BYPASS_NORMAL_SHIFT 3 ++#define PMUCCTL13_43012_FCBS_UP_TRIG_EN 0x00000400 ++ ++#define PMUCCTL14_43012_ARMCM3_RESET_INITVAL 0x00000001 ++#define PMUCCTL14_43012_DOT11MAC_CLKEN_INITVAL 0x00000020 ++#define PMUCCTL14_43012_SDIOD_RESET_INIVAL 0x00000400 ++#define PMUCCTL14_43012_SDIO_CLK_DMN_RESET_INITVAL 0x00001000 ++#define PMUCCTL14_43012_SOCRAM_CLKEN_INITVAL 0x00004000 ++#define PMUCCTL14_43012_M2MDMA_RESET_INITVAL 0x00008000 ++#define PMUCCTL14_43012_DISABLE_LQ_AVAIL 0x08000000 ++ ++ ++/* 4345 Chip specific ChipStatus register bits */ ++#define CST4345_SPROM_MASK 0x00000020 ++#define CST4345_SFLASH_MASK 0x00000040 ++#define CST4345_RES_INIT_MODE_SHIFT 7 ++#define CST4345_RES_INIT_MODE_MASK 0x00000180 ++#define CST4345_CHIPMODE_MASK 0x4000F ++#define CST4345_CHIPMODE_SDIOD(cs) (((cs) & (1 << 0)) != 0) /* SDIO */ ++#define CST4345_CHIPMODE_GSPI(cs) (((cs) & (1 << 1)) != 0) /* gSPI */ ++#define CST4345_CHIPMODE_HSIC(cs) (((cs) & (1 << 2)) != 0) /* HSIC */ ++#define CST4345_CHIPMODE_PCIE(cs) (((cs) & (1 << 3)) != 0) /* PCIE */ ++#define CST4345_CHIPMODE_USB20D(cs) (((cs) & (1 << 18)) != 0) /* USBDA */ ++ ++/* 4350 Chipcommon ChipStatus bits */ ++#define CST4350_SDIO_MODE 0x00000001 ++#define CST4350_HSIC20D_MODE 0x00000002 ++#define CST4350_BP_ON_HSIC_CLK 0x00000004 ++#define CST4350_PCIE_MODE 0x00000008 ++#define CST4350_USB20D_MODE 0x00000010 ++#define CST4350_USB30D_MODE 0x00000020 ++#define CST4350_SPROM_PRESENT 0x00000040 ++#define CST4350_RSRC_INIT_MODE_0 0x00000080 ++#define CST4350_RSRC_INIT_MODE_1 0x00000100 ++#define CST4350_SEL0_SDIO 0x00000200 ++#define CST4350_SEL1_SDIO 0x00000400 ++#define CST4350_SDIO_PAD_MODE 0x00000800 ++#define CST4350_BBPLL_LOCKED 0x00001000 ++#define CST4350_USBPLL_LOCKED 0x00002000 ++#define CST4350_LINE_STATE 0x0000C000 ++#define CST4350_SERDES_PIPE_PLLLOCK 0x00010000 ++#define CST4350_BT_READY 0x00020000 ++#define CST4350_SFLASH_PRESENT 0x00040000 ++#define CST4350_CPULESS_ENABLE 0x00080000 ++#define CST4350_STRAP_HOST_IFC_1 0x00100000 ++#define CST4350_STRAP_HOST_IFC_2 0x00200000 ++#define CST4350_STRAP_HOST_IFC_3 0x00400000 ++#define CST4350_RAW_SPROM_PRESENT 0x00800000 ++#define CST4350_APP_CLK_SWITCH_SEL_RDBACK 0x01000000 ++#define CST4350_RAW_RSRC_INIT_MODE_0 0x02000000 ++#define CST4350_SDIO_PAD_VDDIO 0x04000000 ++#define CST4350_GSPI_MODE 0x08000000 ++#define CST4350_PACKAGE_OPTION 0xF0000000 ++#define CST4350_PACKAGE_SHIFT 28 ++ ++/* package option for 4350 */ ++#define CST4350_PACKAGE_WLCSP 0x0 ++#define CST4350_PACKAGE_PCIE 0x1 ++#define CST4350_PACKAGE_WLBGA 0x2 ++#define CST4350_PACKAGE_DBG 0x3 ++#define CST4350_PACKAGE_USB 0x4 ++#define CST4350_PACKAGE_USB_HSIC 0x4 ++ ++#define CST4350_PKG_MODE(cs) ((cs & CST4350_PACKAGE_OPTION) >> CST4350_PACKAGE_SHIFT) ++ ++#define CST4350_PKG_WLCSP(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_WLCSP)) ++#define CST4350_PKG_PCIE(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_PCIE)) ++#define CST4350_PKG_WLBGA(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_WLBGA)) ++#define CST4350_PKG_USB(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_USB)) ++#define CST4350_PKG_USB_HSIC(cs) (CST4350_PKG_MODE(cs) == (CST4350_PACKAGE_USB_HSIC)) ++ ++/* 4350C0 USB PACKAGE using raw_sprom_present to indicate 40mHz xtal */ ++#define CST4350_PKG_USB_40M(cs) (cs & CST4350_RAW_SPROM_PRESENT) ++ ++#define CST4350_CHIPMODE_SDIOD(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_SDIOD)) ++#define CST4350_CHIPMODE_USB20D(cs) ((CST4350_IFC_MODE(cs)) == (CST4350_IFC_MODE_USB20D)) ++#define CST4350_CHIPMODE_HSIC20D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC20D)) ++#define CST4350_CHIPMODE_HSIC30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_HSIC30D)) ++#define CST4350_CHIPMODE_USB30D(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D)) ++#define CST4350_CHIPMODE_USB30D_WL(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_USB30D_WL)) ++#define CST4350_CHIPMODE_PCIE(cs) (CST4350_IFC_MODE(cs) == (CST4350_IFC_MODE_PCIE)) ++ ++/* strap_host_ifc strap value */ ++#define CST4350_HOST_IFC_MASK 0x00700000 ++#define CST4350_HOST_IFC_SHIFT 20 ++ ++/* host_ifc raw mode */ ++#define CST4350_IFC_MODE_SDIOD 0x0 ++#define CST4350_IFC_MODE_HSIC20D 0x1 ++#define CST4350_IFC_MODE_HSIC30D 0x2 ++#define CST4350_IFC_MODE_PCIE 0x3 ++#define CST4350_IFC_MODE_USB20D 0x4 ++#define CST4350_IFC_MODE_USB30D 0x5 ++#define CST4350_IFC_MODE_USB30D_WL 0x6 ++#define CST4350_IFC_MODE_USB30D_BT 0x7 ++ ++#define CST4350_IFC_MODE(cs) ((cs & CST4350_HOST_IFC_MASK) >> CST4350_HOST_IFC_SHIFT) ++ ++/* 4350 PMU resources */ ++#define RES4350_LPLDO_PU 0 ++#define RES4350_PMU_BG_PU 1 ++#define RES4350_PMU_SLEEP 2 ++#define RES4350_RSVD_3 3 ++#define RES4350_CBUCK_LPOM_PU 4 ++#define RES4350_CBUCK_PFM_PU 5 ++#define RES4350_COLD_START_WAIT 6 ++#define RES4350_RSVD_7 7 ++#define RES4350_LNLDO_PU 8 ++#define RES4350_XTALLDO_PU 9 ++#define RES4350_LDO3P3_PU 10 ++#define RES4350_OTP_PU 11 ++#define RES4350_XTAL_PU 12 ++#define RES4350_SR_CLK_START 13 ++#define RES4350_LQ_AVAIL 14 ++#define RES4350_LQ_START 15 ++#define RES4350_PERST_OVR 16 ++#define RES4350_WL_CORE_RDY 17 ++#define RES4350_ILP_REQ 18 ++#define RES4350_ALP_AVAIL 19 ++#define RES4350_MINI_PMU 20 ++#define RES4350_RADIO_PU 21 ++#define RES4350_SR_CLK_STABLE 22 ++#define RES4350_SR_SAVE_RESTORE 23 ++#define RES4350_SR_PHY_PWRSW 24 ++#define RES4350_SR_VDDM_PWRSW 25 ++#define RES4350_SR_SUBCORE_PWRSW 26 ++#define RES4350_SR_SLEEP 27 ++#define RES4350_HT_START 28 ++#define RES4350_HT_AVAIL 29 ++#define RES4350_MACPHY_CLKAVAIL 30 ++ ++#define MUXENAB4350_UART_MASK (0x0000000f) ++#define MUXENAB4350_UART_SHIFT 0 ++#define MUXENAB4350_HOSTWAKE_MASK (0x000000f0) /**< configure GPIO for host_wake */ ++#define MUXENAB4350_HOSTWAKE_SHIFT 4 ++#define MUXENAB4349_UART_MASK (0xf) ++ ++ ++#define CC4350_GPIO_COUNT 16 ++ ++/* 4350 GCI function sel values */ ++#define CC4350_FNSEL_HWDEF (0) ++#define CC4350_FNSEL_SAMEASPIN (1) ++#define CC4350_FNSEL_UART (2) ++#define CC4350_FNSEL_SFLASH (3) ++#define CC4350_FNSEL_SPROM (4) ++#define CC4350_FNSEL_I2C (5) ++#define CC4350_FNSEL_MISC0 (6) ++#define CC4350_FNSEL_GCI (7) ++#define CC4350_FNSEL_MISC1 (8) ++#define CC4350_FNSEL_MISC2 (9) ++#define CC4350_FNSEL_PWDOG (10) ++#define CC4350_FNSEL_IND (12) ++#define CC4350_FNSEL_PDN (13) ++#define CC4350_FNSEL_PUP (14) ++#define CC4350_FNSEL_TRISTATE (15) ++#define CC4350C_FNSEL_UART (3) ++ ++ ++/* 4350 GPIO */ ++#define CC4350_PIN_GPIO_00 (0) ++#define CC4350_PIN_GPIO_01 (1) ++#define CC4350_PIN_GPIO_02 (2) ++#define CC4350_PIN_GPIO_03 (3) ++#define CC4350_PIN_GPIO_04 (4) ++#define CC4350_PIN_GPIO_05 (5) ++#define CC4350_PIN_GPIO_06 (6) ++#define CC4350_PIN_GPIO_07 (7) ++#define CC4350_PIN_GPIO_08 (8) ++#define CC4350_PIN_GPIO_09 (9) ++#define CC4350_PIN_GPIO_10 (10) ++#define CC4350_PIN_GPIO_11 (11) ++#define CC4350_PIN_GPIO_12 (12) ++#define CC4350_PIN_GPIO_13 (13) ++#define CC4350_PIN_GPIO_14 (14) ++#define CC4350_PIN_GPIO_15 (15) ++ ++#define CC4350_RSVD_16_SHIFT 16 ++ ++#define CC2_4350_PHY_PWRSW_UPTIME_MASK (0xf << 0) ++#define CC2_4350_PHY_PWRSW_UPTIME_SHIFT (0) ++#define CC2_4350_VDDM_PWRSW_UPDELAY_MASK (0xf << 4) ++#define CC2_4350_VDDM_PWRSW_UPDELAY_SHIFT (4) ++#define CC2_4350_VDDM_PWRSW_UPTIME_MASK (0xf << 8) ++#define CC2_4350_VDDM_PWRSW_UPTIME_SHIFT (8) ++#define CC2_4350_SBC_PWRSW_DNDELAY_MASK (0x3 << 12) ++#define CC2_4350_SBC_PWRSW_DNDELAY_SHIFT (12) ++#define CC2_4350_PHY_PWRSW_DNDELAY_MASK (0x3 << 14) ++#define CC2_4350_PHY_PWRSW_DNDELAY_SHIFT (14) ++#define CC2_4350_VDDM_PWRSW_DNDELAY_MASK (0x3 << 16) ++#define CC2_4350_VDDM_PWRSW_DNDELAY_SHIFT (16) ++#define CC2_4350_VDDM_PWRSW_EN_MASK (1 << 20) ++#define CC2_4350_VDDM_PWRSW_EN_SHIFT (20) ++#define CC2_4350_MEMLPLDO_PWRSW_EN_MASK (1 << 21) ++#define CC2_4350_MEMLPLDO_PWRSW_EN_SHIFT (21) ++#define CC2_4350_SDIO_AOS_WAKEUP_MASK (1 << 24) ++#define CC2_4350_SDIO_AOS_WAKEUP_SHIFT (24) ++ ++/* Applies to 4335/4350/4345 */ ++#define CC3_SR_CLK_SR_MEM_MASK (1 << 0) ++#define CC3_SR_CLK_SR_MEM_SHIFT (0) ++#define CC3_SR_BIT1_TBD_MASK (1 << 1) ++#define CC3_SR_BIT1_TBD_SHIFT (1) ++#define CC3_SR_ENGINE_ENABLE_MASK (1 << 2) ++#define CC3_SR_ENGINE_ENABLE_SHIFT (2) ++#define CC3_SR_BIT3_TBD_MASK (1 << 3) ++#define CC3_SR_BIT3_TBD_SHIFT (3) ++#define CC3_SR_MINDIV_FAST_CLK_MASK (0xF << 4) ++#define CC3_SR_MINDIV_FAST_CLK_SHIFT (4) ++#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_MASK (1 << 8) ++#define CC3_SR_R23_SR2_RISE_EDGE_TRIG_SHIFT (8) ++#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_MASK (1 << 9) ++#define CC3_SR_R23_SR2_FALL_EDGE_TRIG_SHIFT (9) ++#define CC3_SR_R23_SR_RISE_EDGE_TRIG_MASK (1 << 10) ++#define CC3_SR_R23_SR_RISE_EDGE_TRIG_SHIFT (10) ++#define CC3_SR_R23_SR_FALL_EDGE_TRIG_MASK (1 << 11) ++#define CC3_SR_R23_SR_FALL_EDGE_TRIG_SHIFT (11) ++#define CC3_SR_NUM_CLK_HIGH_MASK (0x7 << 12) ++#define CC3_SR_NUM_CLK_HIGH_SHIFT (12) ++#define CC3_SR_BIT15_TBD_MASK (1 << 15) ++#define CC3_SR_BIT15_TBD_SHIFT (15) ++#define CC3_SR_PHY_FUNC_PIC_MASK (1 << 16) ++#define CC3_SR_PHY_FUNC_PIC_SHIFT (16) ++#define CC3_SR_BIT17_19_TBD_MASK (0x7 << 17) ++#define CC3_SR_BIT17_19_TBD_SHIFT (17) ++#define CC3_SR_CHIP_TRIGGER_1_MASK (1 << 20) ++#define CC3_SR_CHIP_TRIGGER_1_SHIFT (20) ++#define CC3_SR_CHIP_TRIGGER_2_MASK (1 << 21) ++#define CC3_SR_CHIP_TRIGGER_2_SHIFT (21) ++#define CC3_SR_CHIP_TRIGGER_3_MASK (1 << 22) ++#define CC3_SR_CHIP_TRIGGER_3_SHIFT (22) ++#define CC3_SR_CHIP_TRIGGER_4_MASK (1 << 23) ++#define CC3_SR_CHIP_TRIGGER_4_SHIFT (23) ++#define CC3_SR_ALLOW_SBC_FUNC_PIC_MASK (1 << 24) ++#define CC3_SR_ALLOW_SBC_FUNC_PIC_SHIFT (24) ++#define CC3_SR_BIT25_26_TBD_MASK (0x3 << 25) ++#define CC3_SR_BIT25_26_TBD_SHIFT (25) ++#define CC3_SR_ALLOW_SBC_STBY_MASK (1 << 27) ++#define CC3_SR_ALLOW_SBC_STBY_SHIFT (27) ++#define CC3_SR_GPIO_MUX_MASK (0xF << 28) ++#define CC3_SR_GPIO_MUX_SHIFT (28) ++ ++/* Applies to 4335/4350/4345 */ ++#define CC4_SR_INIT_ADDR_MASK (0x3FF0000) ++#define CC4_4350_SR_ASM_ADDR (0x30) ++#define CC4_4350_C0_SR_ASM_ADDR (0x0) ++#define CC4_4335_SR_ASM_ADDR (0x48) ++#define CC4_4345_SR_ASM_ADDR (0x48) ++#define CC4_SR_INIT_ADDR_SHIFT (16) ++ ++#define CC4_4350_EN_SR_CLK_ALP_MASK (1 << 30) ++#define CC4_4350_EN_SR_CLK_ALP_SHIFT (30) ++#define CC4_4350_EN_SR_CLK_HT_MASK (1 << 31) ++#define CC4_4350_EN_SR_CLK_HT_SHIFT (31) ++ ++#define VREG4_4350_MEMLPDO_PU_MASK (1 << 31) ++#define VREG4_4350_MEMLPDO_PU_SHIFT 31 ++ ++#define VREG6_4350_SR_EXT_CLKDIR_MASK (1 << 20) ++#define VREG6_4350_SR_EXT_CLKDIR_SHIFT 20 ++#define VREG6_4350_SR_EXT_CLKDIV_MASK (0x3 << 21) ++#define VREG6_4350_SR_EXT_CLKDIV_SHIFT 21 ++#define VREG6_4350_SR_EXT_CLKEN_MASK (1 << 23) ++#define VREG6_4350_SR_EXT_CLKEN_SHIFT 23 ++ ++#define CC5_4350_PMU_EN_ASSERT_MASK (1 << 13) ++#define CC5_4350_PMU_EN_ASSERT_SHIFT (13) ++ ++#define CC6_4350_PCIE_CLKREQ_WAKEUP_MASK (1 << 4) ++#define CC6_4350_PCIE_CLKREQ_WAKEUP_SHIFT (4) ++#define CC6_4350_PMU_WAKEUP_ALPAVAIL_MASK (1 << 6) ++#define CC6_4350_PMU_WAKEUP_ALPAVAIL_SHIFT (6) ++#define CC6_4350_PMU_EN_EXT_PERST_MASK (1 << 17) ++#define CC6_4350_PMU_EN_EXT_PERST_SHIFT (17) ++#define CC6_4350_PMU_EN_WAKEUP_MASK (1 << 18) ++#define CC6_4350_PMU_EN_WAKEUP_SHIFT (18) ++ ++#define CC7_4350_PMU_EN_ASSERT_L2_MASK (1 << 26) ++#define CC7_4350_PMU_EN_ASSERT_L2_SHIFT (26) ++#define CC7_4350_PMU_EN_MDIO_MASK (1 << 27) ++#define CC7_4350_PMU_EN_MDIO_SHIFT (27) ++ ++#define CC6_4345_PMU_EN_PERST_DEASSERT_MASK (1 << 13) ++#define CC6_4345_PMU_EN_PERST_DEASSERT_SHIF (13) ++#define CC6_4345_PMU_EN_L2_DEASSERT_MASK (1 << 14) ++#define CC6_4345_PMU_EN_L2_DEASSERT_SHIF (14) ++#define CC6_4345_PMU_EN_ASSERT_L2_MASK (1 << 15) ++#define CC6_4345_PMU_EN_ASSERT_L2_SHIFT (15) ++#define CC6_4345_PMU_EN_MDIO_MASK (1 << 24) ++#define CC6_4345_PMU_EN_MDIO_SHIFT (24) ++ ++/* GCI chipcontrol register indices */ ++#define CC_GCI_CHIPCTRL_00 (0) ++#define CC_GCI_CHIPCTRL_01 (1) ++#define CC_GCI_CHIPCTRL_02 (2) ++#define CC_GCI_CHIPCTRL_03 (3) ++#define CC_GCI_CHIPCTRL_04 (4) ++#define CC_GCI_CHIPCTRL_05 (5) ++#define CC_GCI_CHIPCTRL_06 (6) ++#define CC_GCI_CHIPCTRL_07 (7) ++#define CC_GCI_CHIPCTRL_08 (8) ++#define CC_GCI_CHIPCTRL_09 (9) ++#define CC_GCI_CHIPCTRL_10 (10) ++#define CC_GCI_CHIPCTRL_10 (10) ++#define CC_GCI_CHIPCTRL_11 (11) ++#define CC_GCI_XTAL_BUFSTRG_NFC (0xff << 12) ++ ++#define CC_GCI_06_JTAG_SEL_SHIFT 4 ++#define CC_GCI_06_JTAG_SEL_MASK (1 << 4) ++ ++#define CC_GCI_NUMCHIPCTRLREGS(cap1) ((cap1 & 0xF00) >> 8) ++ ++/* GCI chipstatus register indices */ ++#define GCI_CHIPSTATUS_00 (0) ++#define GCI_CHIPSTATUS_01 (1) ++#define GCI_CHIPSTATUS_02 (2) ++#define GCI_CHIPSTATUS_03 (3) ++#define GCI_CHIPSTATUS_04 (4) ++#define GCI_CHIPSTATUS_05 (5) ++#define GCI_CHIPSTATUS_06 (6) ++#define GCI_CHIPSTATUS_07 (7) ++#define GCI_CHIPSTATUS_08 (8) ++ ++/* 43021 GCI chipstatus registers */ ++#define GCI43012_CHIPSTATUS_07_BBPLL_LOCK_MASK (1 << 3) ++ ++/* 4345 PMU resources */ ++#define RES4345_LPLDO_PU 0 ++#define RES4345_PMU_BG_PU 1 ++#define RES4345_PMU_SLEEP 2 ++#define RES4345_HSICLDO_PU 3 ++#define RES4345_CBUCK_LPOM_PU 4 ++#define RES4345_CBUCK_PFM_PU 5 ++#define RES4345_COLD_START_WAIT 6 ++#define RES4345_RSVD_7 7 ++#define RES4345_LNLDO_PU 8 ++#define RES4345_XTALLDO_PU 9 ++#define RES4345_LDO3P3_PU 10 ++#define RES4345_OTP_PU 11 ++#define RES4345_XTAL_PU 12 ++#define RES4345_SR_CLK_START 13 ++#define RES4345_LQ_AVAIL 14 ++#define RES4345_LQ_START 15 ++#define RES4345_PERST_OVR 16 ++#define RES4345_WL_CORE_RDY 17 ++#define RES4345_ILP_REQ 18 ++#define RES4345_ALP_AVAIL 19 ++#define RES4345_MINI_PMU 20 ++#define RES4345_RADIO_PU 21 ++#define RES4345_SR_CLK_STABLE 22 ++#define RES4345_SR_SAVE_RESTORE 23 ++#define RES4345_SR_PHY_PWRSW 24 ++#define RES4345_SR_VDDM_PWRSW 25 ++#define RES4345_SR_SUBCORE_PWRSW 26 ++#define RES4345_SR_SLEEP 27 ++#define RES4345_HT_START 28 ++#define RES4345_HT_AVAIL 29 ++#define RES4345_MACPHY_CLK_AVAIL 30 ++ ++/* 43012 pins ++ * note: only the values set as default/used are added here. ++ */ ++#define CC43012_PIN_GPIO_00 (0) ++#define CC43012_PIN_GPIO_01 (1) ++#define CC43012_PIN_GPIO_02 (2) ++#define CC43012_PIN_GPIO_03 (3) ++#define CC43012_PIN_GPIO_04 (4) ++#define CC43012_PIN_GPIO_05 (5) ++#define CC43012_PIN_GPIO_06 (6) ++#define CC43012_PIN_GPIO_07 (7) ++#define CC43012_PIN_GPIO_08 (8) ++#define CC43012_PIN_GPIO_09 (9) ++#define CC43012_PIN_GPIO_10 (10) ++#define CC43012_PIN_GPIO_11 (11) ++#define CC43012_PIN_GPIO_12 (12) ++#define CC43012_PIN_GPIO_13 (13) ++#define CC43012_PIN_GPIO_14 (14) ++#define CC43012_PIN_GPIO_15 (15) ++ ++/* 43012 GCI function sel values */ ++#define CC43012_FNSEL_HWDEF (0) ++#define CC43012_FNSEL_SAMEASPIN (1) ++#define CC43012_FNSEL_GPIO0 (2) ++#define CC43012_FNSEL_GPIO1 (3) ++#define CC43012_FNSEL_GCI0 (4) ++#define CC43012_FNSEL_GCI1 (5) ++#define CC43012_FNSEL_DBG_UART (6) ++#define CC43012_FNSEL_I2C (7) ++#define CC43012_FNSEL_BT_SFLASH (8) ++#define CC43012_FNSEL_MISC0 (9) ++#define CC43012_FNSEL_MISC1 (10) ++#define CC43012_FNSEL_MISC2 (11) ++#define CC43012_FNSEL_IND (12) ++#define CC43012_FNSEL_PDN (13) ++#define CC43012_FNSEL_PUP (14) ++#define CC43012_FNSEL_TRI (15) ++ ++/* 4335 pins ++* note: only the values set as default/used are added here. ++*/ ++#define CC4335_PIN_GPIO_00 (0) ++#define CC4335_PIN_GPIO_01 (1) ++#define CC4335_PIN_GPIO_02 (2) ++#define CC4335_PIN_GPIO_03 (3) ++#define CC4335_PIN_GPIO_04 (4) ++#define CC4335_PIN_GPIO_05 (5) ++#define CC4335_PIN_GPIO_06 (6) ++#define CC4335_PIN_GPIO_07 (7) ++#define CC4335_PIN_GPIO_08 (8) ++#define CC4335_PIN_GPIO_09 (9) ++#define CC4335_PIN_GPIO_10 (10) ++#define CC4335_PIN_GPIO_11 (11) ++#define CC4335_PIN_GPIO_12 (12) ++#define CC4335_PIN_GPIO_13 (13) ++#define CC4335_PIN_GPIO_14 (14) ++#define CC4335_PIN_GPIO_15 (15) ++#define CC4335_PIN_SDIO_CLK (16) ++#define CC4335_PIN_SDIO_CMD (17) ++#define CC4335_PIN_SDIO_DATA0 (18) ++#define CC4335_PIN_SDIO_DATA1 (19) ++#define CC4335_PIN_SDIO_DATA2 (20) ++#define CC4335_PIN_SDIO_DATA3 (21) ++#define CC4335_PIN_RF_SW_CTRL_6 (22) ++#define CC4335_PIN_RF_SW_CTRL_7 (23) ++#define CC4335_PIN_RF_SW_CTRL_8 (24) ++#define CC4335_PIN_RF_SW_CTRL_9 (25) ++/* Last GPIO Pad */ ++#define CC4335_PIN_GPIO_LAST (31) ++ ++/* 4335 GCI function sel values ++*/ ++#define CC4335_FNSEL_HWDEF (0) ++#define CC4335_FNSEL_SAMEASPIN (1) ++#define CC4335_FNSEL_GPIO0 (2) ++#define CC4335_FNSEL_GPIO1 (3) ++#define CC4335_FNSEL_GCI0 (4) ++#define CC4335_FNSEL_GCI1 (5) ++#define CC4335_FNSEL_UART (6) ++#define CC4335_FNSEL_SFLASH (7) ++#define CC4335_FNSEL_SPROM (8) ++#define CC4335_FNSEL_MISC0 (9) ++#define CC4335_FNSEL_MISC1 (10) ++#define CC4335_FNSEL_MISC2 (11) ++#define CC4335_FNSEL_IND (12) ++#define CC4335_FNSEL_PDN (13) ++#define CC4335_FNSEL_PUP (14) ++#define CC4335_FNSEL_TRI (15) ++ ++/* GCI Core Control Reg */ ++#define GCI_CORECTRL_SR_MASK (1 << 0) /**< SECI block Reset */ ++#define GCI_CORECTRL_RSL_MASK (1 << 1) /**< ResetSECILogic */ ++#define GCI_CORECTRL_ES_MASK (1 << 2) /**< EnableSECI */ ++#define GCI_CORECTRL_FSL_MASK (1 << 3) /**< Force SECI Out Low */ ++#define GCI_CORECTRL_SOM_MASK (7 << 4) /**< SECI Op Mode */ ++#define GCI_CORECTRL_US_MASK (1 << 7) /**< Update SECI */ ++#define GCI_CORECTRL_BOS_MASK (1 << 8) /**< Break On Sleep */ ++ ++/* 4345 pins ++* note: only the values set as default/used are added here. ++*/ ++#define CC4345_PIN_GPIO_00 (0) ++#define CC4345_PIN_GPIO_01 (1) ++#define CC4345_PIN_GPIO_02 (2) ++#define CC4345_PIN_GPIO_03 (3) ++#define CC4345_PIN_GPIO_04 (4) ++#define CC4345_PIN_GPIO_05 (5) ++#define CC4345_PIN_GPIO_06 (6) ++#define CC4345_PIN_GPIO_07 (7) ++#define CC4345_PIN_GPIO_08 (8) ++#define CC4345_PIN_GPIO_09 (9) ++#define CC4345_PIN_GPIO_10 (10) ++#define CC4345_PIN_GPIO_11 (11) ++#define CC4345_PIN_GPIO_12 (12) ++#define CC4345_PIN_GPIO_13 (13) ++#define CC4345_PIN_GPIO_14 (14) ++#define CC4345_PIN_GPIO_15 (15) ++#define CC4345_PIN_GPIO_16 (16) ++#define CC4345_PIN_SDIO_CLK (17) ++#define CC4345_PIN_SDIO_CMD (18) ++#define CC4345_PIN_SDIO_DATA0 (19) ++#define CC4345_PIN_SDIO_DATA1 (20) ++#define CC4345_PIN_SDIO_DATA2 (21) ++#define CC4345_PIN_SDIO_DATA3 (22) ++#define CC4345_PIN_RF_SW_CTRL_0 (23) ++#define CC4345_PIN_RF_SW_CTRL_1 (24) ++#define CC4345_PIN_RF_SW_CTRL_2 (25) ++#define CC4345_PIN_RF_SW_CTRL_3 (26) ++#define CC4345_PIN_RF_SW_CTRL_4 (27) ++#define CC4345_PIN_RF_SW_CTRL_5 (28) ++#define CC4345_PIN_RF_SW_CTRL_6 (29) ++#define CC4345_PIN_RF_SW_CTRL_7 (30) ++#define CC4345_PIN_RF_SW_CTRL_8 (31) ++#define CC4345_PIN_RF_SW_CTRL_9 (32) ++ ++/* 4345 GCI function sel values ++*/ ++#define CC4345_FNSEL_HWDEF (0) ++#define CC4345_FNSEL_SAMEASPIN (1) ++#define CC4345_FNSEL_GPIO0 (2) ++#define CC4345_FNSEL_GPIO1 (3) ++#define CC4345_FNSEL_GCI0 (4) ++#define CC4345_FNSEL_GCI1 (5) ++#define CC4345_FNSEL_UART (6) ++#define CC4345_FNSEL_SFLASH (7) ++#define CC4345_FNSEL_SPROM (8) ++#define CC4345_FNSEL_MISC0 (9) ++#define CC4345_FNSEL_MISC1 (10) ++#define CC4345_FNSEL_MISC2 (11) ++#define CC4345_FNSEL_IND (12) ++#define CC4345_FNSEL_PDN (13) ++#define CC4345_FNSEL_PUP (14) ++#define CC4345_FNSEL_TRI (15) ++ ++#define MUXENAB4345_UART_MASK (0x0000000f) ++#define MUXENAB4345_UART_SHIFT 0 ++#define MUXENAB4345_HOSTWAKE_MASK (0x000000f0) ++#define MUXENAB4345_HOSTWAKE_SHIFT 4 ++ ++/* 4349 Group (4349, 4355, 4359) GCI AVS function sel values */ ++#define CC4349_GRP_GCI_AVS_CTRL_MASK (0xffe00000) ++#define CC4349_GRP_GCI_AVS_CTRL_SHIFT (21) ++#define CC4349_GRP_GCI_AVS_CTRL_ENAB (1 << 5) ++ ++/* 4345 GCI AVS function sel values */ ++#define CC4345_GCI_AVS_CTRL_MASK (0xfc) ++#define CC4345_GCI_AVS_CTRL_SHIFT (2) ++#define CC4345_GCI_AVS_CTRL_ENAB (1 << 5) ++ ++/* 43430 Pin */ ++#define CC43430_PIN_GPIO_00 (0) ++#define CC43430_PIN_GPIO_01 (1) ++#define CC43430_PIN_GPIO_02 (2) ++#define CC43430_PIN_GPIO_07 (7) ++#define CC43430_PIN_GPIO_08 (8) ++#define CC43430_PIN_GPIO_09 (9) ++#define CC43430_PIN_GPIO_10 (10) ++ ++#define CC43430_FNSEL_SDIO_INT (2) ++#define CC43430_FNSEL_6_FAST_UART (6) ++#define CC43430_FNSEL_10_FAST_UART (10) ++ ++#define MUXENAB43430_UART_MASK (0x0000000f) ++#define MUXENAB43430_UART_SHIFT 0 ++#define MUXENAB43430_HOSTWAKE_MASK (0x000000f0) /* configure GPIO for SDIO host_wake */ ++#define MUXENAB43430_HOSTWAKE_SHIFT 4 ++ ++#define CC43430_FNSEL_SAMEASPIN (1) ++#define CC43430_RFSWCTRL_EN_MASK (0x7f8) ++#define CC43430_RFSWCTRL_EN_SHIFT (3) ++ ++/* GCI GPIO for function sel GCI-0/GCI-1 */ ++#define CC_GCI_GPIO_0 (0) ++#define CC_GCI_GPIO_1 (1) ++#define CC_GCI_GPIO_2 (2) ++#define CC_GCI_GPIO_3 (3) ++#define CC_GCI_GPIO_4 (4) ++#define CC_GCI_GPIO_5 (5) ++#define CC_GCI_GPIO_6 (6) ++#define CC_GCI_GPIO_7 (7) ++#define CC_GCI_GPIO_8 (8) ++#define CC_GCI_GPIO_9 (9) ++#define CC_GCI_GPIO_10 (10) ++#define CC_GCI_GPIO_11 (11) ++#define CC_GCI_GPIO_12 (12) ++#define CC_GCI_GPIO_13 (13) ++#define CC_GCI_GPIO_14 (14) ++#define CC_GCI_GPIO_15 (15) ++ ++ ++/* indicates Invalid GPIO, e.g. when PAD GPIO doesn't map to GCI GPIO */ ++#define CC_GCI_GPIO_INVALID 0xFF ++ ++/* find the 4 bit mask given the bit position */ ++#define GCIMASK(pos) (((uint32)0xF) << pos) ++/* get the value which can be used to directly OR with chipcontrol reg */ ++#define GCIPOSVAL(val, pos) ((((uint32)val) << pos) & GCIMASK(pos)) ++/* Extract nibble from a given position */ ++#define GCIGETNBL(val, pos) ((val >> pos) & 0xF) ++ ++ ++/* find the 8 bit mask given the bit position */ ++#define GCIMASK_8B(pos) (((uint32)0xFF) << pos) ++/* get the value which can be used to directly OR with chipcontrol reg */ ++#define GCIPOSVAL_8B(val, pos) ((((uint32)val) << pos) & GCIMASK_8B(pos)) ++/* Extract nibble from a given position */ ++#define GCIGETNBL_8B(val, pos) ((val >> pos) & 0xFF) ++ ++/* find the 4 bit mask given the bit position */ ++#define GCIMASK_4B(pos) (((uint32)0xF) << pos) ++/* get the value which can be used to directly OR with chipcontrol reg */ ++#define GCIPOSVAL_4B(val, pos) ((((uint32)val) << pos) & GCIMASK_4B(pos)) ++/* Extract nibble from a given position */ ++#define GCIGETNBL_4B(val, pos) ((val >> pos) & 0xF) ++ ++ ++/* 4335 GCI Intstatus(Mask)/WakeMask Register bits. */ ++#define GCI_INTSTATUS_RBI (1 << 0) /**< Rx Break Interrupt */ ++#define GCI_INTSTATUS_UB (1 << 1) /**< UART Break Interrupt */ ++#define GCI_INTSTATUS_SPE (1 << 2) /**< SECI Parity Error Interrupt */ ++#define GCI_INTSTATUS_SFE (1 << 3) /**< SECI Framing Error Interrupt */ ++#define GCI_INTSTATUS_SRITI (1 << 9) /**< SECI Rx Idle Timer Interrupt */ ++#define GCI_INTSTATUS_STFF (1 << 10) /**< SECI Tx FIFO Full Interrupt */ ++#define GCI_INTSTATUS_STFAE (1 << 11) /**< SECI Tx FIFO Almost Empty Intr */ ++#define GCI_INTSTATUS_SRFAF (1 << 12) /**< SECI Rx FIFO Almost Full */ ++#define GCI_INTSTATUS_SRFNE (1 << 14) /**< SECI Rx FIFO Not Empty */ ++#define GCI_INTSTATUS_SRFOF (1 << 15) /**< SECI Rx FIFO Not Empty Timeout */ ++#define GCI_INTSTATUS_GPIOINT (1 << 25) /**< GCIGpioInt */ ++#define GCI_INTSTATUS_GPIOWAKE (1 << 26) /**< GCIGpioWake */ ++ ++/* 4335 GCI IntMask Register bits. */ ++#define GCI_INTMASK_RBI (1 << 0) /**< Rx Break Interrupt */ ++#define GCI_INTMASK_UB (1 << 1) /**< UART Break Interrupt */ ++#define GCI_INTMASK_SPE (1 << 2) /**< SECI Parity Error Interrupt */ ++#define GCI_INTMASK_SFE (1 << 3) /**< SECI Framing Error Interrupt */ ++#define GCI_INTMASK_SRITI (1 << 9) /**< SECI Rx Idle Timer Interrupt */ ++#define GCI_INTMASK_STFF (1 << 10) /**< SECI Tx FIFO Full Interrupt */ ++#define GCI_INTMASK_STFAE (1 << 11) /**< SECI Tx FIFO Almost Empty Intr */ ++#define GCI_INTMASK_SRFAF (1 << 12) /**< SECI Rx FIFO Almost Full */ ++#define GCI_INTMASK_SRFNE (1 << 14) /**< SECI Rx FIFO Not Empty */ ++#define GCI_INTMASK_SRFOF (1 << 15) /**< SECI Rx FIFO Not Empty Timeout */ ++#define GCI_INTMASK_GPIOINT (1 << 25) /**< GCIGpioInt */ ++#define GCI_INTMASK_GPIOWAKE (1 << 26) /**< GCIGpioWake */ ++ ++/* 4335 GCI WakeMask Register bits. */ ++#define GCI_WAKEMASK_RBI (1 << 0) /**< Rx Break Interrupt */ ++#define GCI_WAKEMASK_UB (1 << 1) /**< UART Break Interrupt */ ++#define GCI_WAKEMASK_SPE (1 << 2) /**< SECI Parity Error Interrupt */ ++#define GCI_WAKEMASK_SFE (1 << 3) /**< SECI Framing Error Interrupt */ ++#define GCI_WAKE_SRITI (1 << 9) /**< SECI Rx Idle Timer Interrupt */ ++#define GCI_WAKEMASK_STFF (1 << 10) /**< SECI Tx FIFO Full Interrupt */ ++#define GCI_WAKEMASK_STFAE (1 << 11) /**< SECI Tx FIFO Almost Empty Intr */ ++#define GCI_WAKEMASK_SRFAF (1 << 12) /**< SECI Rx FIFO Almost Full */ ++#define GCI_WAKEMASK_SRFNE (1 << 14) /**< SECI Rx FIFO Not Empty */ ++#define GCI_WAKEMASK_SRFOF (1 << 15) /**< SECI Rx FIFO Not Empty Timeout */ ++#define GCI_WAKEMASK_GPIOINT (1 << 25) /**< GCIGpioInt */ ++#define GCI_WAKEMASK_GPIOWAKE (1 << 26) /**< GCIGpioWake */ ++ ++#define GCI_WAKE_ON_GCI_GPIO1 1 ++#define GCI_WAKE_ON_GCI_GPIO2 2 ++#define GCI_WAKE_ON_GCI_GPIO3 3 ++#define GCI_WAKE_ON_GCI_GPIO4 4 ++#define GCI_WAKE_ON_GCI_GPIO5 5 ++#define GCI_WAKE_ON_GCI_GPIO6 6 ++#define GCI_WAKE_ON_GCI_GPIO7 7 ++#define GCI_WAKE_ON_GCI_GPIO8 8 ++#define GCI_WAKE_ON_GCI_SECI_IN 9 ++ ++/* 43012 ULB dividers */ ++#define PMU43012_CC0_ULB_DIVMASK 0xfffffc00 ++#define PMU43012_10MHZ_ULB_DIV ((1 << 0) | (1 << 5)) ++#define PMU43012_5MHZ_ULB_DIV ((3 << 0) | (3 << 5)) ++#define PMU43012_2P5MHZ_ULB_DIV ((7 << 0) | (7 << 5)) ++#define PMU43012_ULB_NO_DIV 0 ++ ++/* 4335 MUX options. each nibble belongs to a setting. Non-zero value specifies a logic ++* for now only UART for bootloader. ++*/ ++#define MUXENAB4335_UART_MASK (0x0000000f) ++ ++#define MUXENAB4335_UART_SHIFT 0 ++#define MUXENAB4335_HOSTWAKE_MASK (0x000000f0) /**< configure GPIO for SDIO host_wake */ ++#define MUXENAB4335_HOSTWAKE_SHIFT 4 ++#define MUXENAB4335_GETIX(val, name) \ ++ ((((val) & MUXENAB4335_ ## name ## _MASK) >> MUXENAB4335_ ## name ## _SHIFT) - 1) ++ ++/* 43012 MUX options */ ++#define MUXENAB43012_HOSTWAKE_MASK (0x00000001) ++#define MUXENAB43012_GETIX(val, name) (val - 1) ++ ++/* ++* Maximum delay for the PMU state transition in us. ++* This is an upper bound intended for spinwaits etc. ++*/ ++#define PMU_MAX_TRANSITION_DLY 15000 ++ ++/* PMU resource up transition time in ILP cycles */ ++#define PMURES_UP_TRANSITION 2 ++ ++/* 53573 PMU Resource */ ++#define RES53573_REGULATOR_PU 0 ++#define RES53573_XTALLDO_PU 1 ++#define RES53573_XTAL_PU 2 ++#define RES53573_MINI_PMU 3 ++#define RES53573_RADIO_PU 4 ++#define RES53573_ILP_REQ 5 ++#define RES53573_ALP_AVAIL 6 ++#define RES53573_CPUPLL_LDO_PU 7 ++#define RES53573_CPU_PLL_PU 8 ++#define RES53573_WLAN_BB_PLL_PU 9 ++#define RES53573_MISCPLL_LDO_PU 10 ++#define RES53573_MISCPLL_PU 11 ++#define RES53573_AUDIOPLL_PU 12 ++#define RES53573_PCIEPLL_LDO_PU 13 ++#define RES53573_PCIEPLL_PU 14 ++#define RES53573_DDRPLL_LDO_PU 15 ++#define RES53573_DDRPLL_PU 16 ++#define RES53573_HT_AVAIL 17 ++#define RES53573_MACPHY_CLK_AVAIL 18 ++#define RES53573_OTP_PU 19 ++#define RES53573_RSVD20 20 ++ ++/* 53573 Chip status registers */ ++#define CST53573_LOCK_CPUPLL 0x00000001 ++#define CST53573_LOCK_MISCPLL 0x00000002 ++#define CST53573_LOCK_DDRPLL 0x00000004 ++#define CST53573_LOCK_PCIEPLL 0x00000008 ++#define CST53573_EPHY_ENERGY_DET 0x00001f00 ++#define CST53573_RAW_ENERGY 0x0003e000 ++#define CST53573_BBPLL_LOCKED_O 0x00040000 ++#define CST53573_SERDES_PIPE_PLLLOCK 0x00080000 ++#define CST53573_STRAP_PCIE_EP_MODE 0x00100000 ++#define CST53573_EPHY_PLL_LOCK 0x00200000 ++#define CST53573_AUDIO_PLL_LOCKED_O 0x00400000 ++#define CST53573_PCIE_LINK_IN_L11 0x01000000 ++#define CST53573_PCIE_LINK_IN_L12 0x02000000 ++#define CST53573_DIN_PACKAGEOPTION 0xf0000000 ++ ++/* 53573 Chip control registers macro definitions */ ++#define PMU_53573_CHIPCTL1 1 ++#define PMU_53573_CC1_HT_CLK_REQ_CTRL_MASK 0x00000010 ++#define PMU_53573_CC1_HT_CLK_REQ_CTRL 0x00000010 ++ ++#define PMU_53573_CHIPCTL3 3 ++#define PMU_53573_CC3_ENABLE_CLOSED_LOOP_MASK 0x00000010 ++#define PMU_53573_CC3_ENABLE_CLOSED_LOOP 0x00000000 ++#define PMU_53573_CC3_ENABLE_BBPLL_PWRDOWN_MASK 0x00000002 ++#define PMU_53573_CC3_ENABLE_BBPLL_PWRDOWN 0x00000002 ++ ++#define CST53573_CHIPMODE_PCIE(cs) FALSE ++ ++ ++/* SECI Status (0x134) & Mask (0x138) bits - Rev 35 */ ++#define SECI_STAT_BI (1 << 0) /* Break Interrupt */ ++#define SECI_STAT_SPE (1 << 1) /* Parity Error */ ++#define SECI_STAT_SFE (1 << 2) /* Parity Error */ ++#define SECI_STAT_SDU (1 << 3) /* Data Updated */ ++#define SECI_STAT_SADU (1 << 4) /* Auxiliary Data Updated */ ++#define SECI_STAT_SAS (1 << 6) /* AUX State */ ++#define SECI_STAT_SAS2 (1 << 7) /* AUX2 State */ ++#define SECI_STAT_SRITI (1 << 8) /* Idle Timer Interrupt */ ++#define SECI_STAT_STFF (1 << 9) /* Tx FIFO Full */ ++#define SECI_STAT_STFAE (1 << 10) /* Tx FIFO Almost Empty */ ++#define SECI_STAT_SRFE (1 << 11) /* Rx FIFO Empty */ ++#define SECI_STAT_SRFAF (1 << 12) /* Rx FIFO Almost Full */ ++#define SECI_STAT_SFCE (1 << 13) /* Flow Control Event */ ++ ++/* SECI configuration */ ++#define SECI_MODE_UART 0x0 ++#define SECI_MODE_SECI 0x1 ++#define SECI_MODE_LEGACY_3WIRE_BT 0x2 ++#define SECI_MODE_LEGACY_3WIRE_WLAN 0x3 ++#define SECI_MODE_HALF_SECI 0x4 ++ ++#define SECI_RESET (1 << 0) ++#define SECI_RESET_BAR_UART (1 << 1) ++#define SECI_ENAB_SECI_ECI (1 << 2) ++#define SECI_ENAB_SECIOUT_DIS (1 << 3) ++#define SECI_MODE_MASK 0x7 ++#define SECI_MODE_SHIFT 4 /* (bits 5, 6, 7) */ ++#define SECI_UPD_SECI (1 << 7) ++ ++#define SECI_SLIP_ESC_CHAR 0xDB ++#define SECI_SIGNOFF_0 SECI_SLIP_ESC_CHAR ++#define SECI_SIGNOFF_1 0 ++#define SECI_REFRESH_REQ 0xDA ++ ++/* seci clk_ctl_st bits */ ++#define CLKCTL_STS_HT_AVAIL_REQ (1 << 4) ++#define CLKCTL_STS_SECI_CLK_REQ (1 << 8) ++#define CLKCTL_STS_SECI_CLK_AVAIL (1 << 24) ++ ++#define SECI_UART_MSR_CTS_STATE (1 << 0) ++#define SECI_UART_MSR_RTS_STATE (1 << 1) ++#define SECI_UART_SECI_IN_STATE (1 << 2) ++#define SECI_UART_SECI_IN2_STATE (1 << 3) ++ ++/* GCI RX FIFO Control Register */ ++#define GCI_RXF_LVL_MASK (0xFF << 0) ++#define GCI_RXF_TIMEOUT_MASK (0xFF << 8) ++ ++/* GCI UART Registers' Bit definitions */ ++/* Seci Fifo Level Register */ ++#define SECI_TXF_LVL_MASK (0x3F << 8) ++#define TXF_AE_LVL_DEFAULT 0x4 ++#define SECI_RXF_LVL_FC_MASK (0x3F << 16) ++ ++/* SeciUARTFCR Bit definitions */ ++#define SECI_UART_FCR_RFR (1 << 0) ++#define SECI_UART_FCR_TFR (1 << 1) ++#define SECI_UART_FCR_SR (1 << 2) ++#define SECI_UART_FCR_THP (1 << 3) ++#define SECI_UART_FCR_AB (1 << 4) ++#define SECI_UART_FCR_ATOE (1 << 5) ++#define SECI_UART_FCR_ARTSOE (1 << 6) ++#define SECI_UART_FCR_ABV (1 << 7) ++#define SECI_UART_FCR_ALM (1 << 8) ++ ++/* SECI UART LCR register bits */ ++#define SECI_UART_LCR_STOP_BITS (1 << 0) /* 0 - 1bit, 1 - 2bits */ ++#define SECI_UART_LCR_PARITY_EN (1 << 1) ++#define SECI_UART_LCR_PARITY (1 << 2) /* 0 - odd, 1 - even */ ++#define SECI_UART_LCR_RX_EN (1 << 3) ++#define SECI_UART_LCR_LBRK_CTRL (1 << 4) /* 1 => SECI_OUT held low */ ++#define SECI_UART_LCR_TXO_EN (1 << 5) ++#define SECI_UART_LCR_RTSO_EN (1 << 6) ++#define SECI_UART_LCR_SLIPMODE_EN (1 << 7) ++#define SECI_UART_LCR_RXCRC_CHK (1 << 8) ++#define SECI_UART_LCR_TXCRC_INV (1 << 9) ++#define SECI_UART_LCR_TXCRC_LSBF (1 << 10) ++#define SECI_UART_LCR_TXCRC_EN (1 << 11) ++#define SECI_UART_LCR_RXSYNC_EN (1 << 12) ++ ++#define SECI_UART_MCR_TX_EN (1 << 0) ++#define SECI_UART_MCR_PRTS (1 << 1) ++#define SECI_UART_MCR_SWFLCTRL_EN (1 << 2) ++#define SECI_UART_MCR_HIGHRATE_EN (1 << 3) ++#define SECI_UART_MCR_LOOPBK_EN (1 << 4) ++#define SECI_UART_MCR_AUTO_RTS (1 << 5) ++#define SECI_UART_MCR_AUTO_TX_DIS (1 << 6) ++#define SECI_UART_MCR_BAUD_ADJ_EN (1 << 7) ++#define SECI_UART_MCR_XONOFF_RPT (1 << 9) ++ ++/* SeciUARTLSR Bit Mask */ ++#define SECI_UART_LSR_RXOVR_MASK (1 << 0) ++#define SECI_UART_LSR_RFF_MASK (1 << 1) ++#define SECI_UART_LSR_TFNE_MASK (1 << 2) ++#define SECI_UART_LSR_TI_MASK (1 << 3) ++#define SECI_UART_LSR_TPR_MASK (1 << 4) ++#define SECI_UART_LSR_TXHALT_MASK (1 << 5) ++ ++/* SeciUARTMSR Bit Mask */ ++#define SECI_UART_MSR_CTSS_MASK (1 << 0) ++#define SECI_UART_MSR_RTSS_MASK (1 << 1) ++#define SECI_UART_MSR_SIS_MASK (1 << 2) ++#define SECI_UART_MSR_SIS2_MASK (1 << 3) ++ ++/* SeciUARTData Bits */ ++#define SECI_UART_DATA_RF_NOT_EMPTY_BIT (1 << 12) ++#define SECI_UART_DATA_RF_FULL_BIT (1 << 13) ++#define SECI_UART_DATA_RF_OVRFLOW_BIT (1 << 14) ++#define SECI_UART_DATA_FIFO_PTR_MASK 0xFF ++#define SECI_UART_DATA_RF_RD_PTR_SHIFT 16 ++#define SECI_UART_DATA_RF_WR_PTR_SHIFT 24 ++ ++/* LTECX: ltecxmux */ ++#define LTECX_EXTRACT_MUX(val, idx) (getbit4(&(val), (idx))) ++ ++/* LTECX: ltecxmux MODE */ ++#define LTECX_MUX_MODE_IDX 0 ++#define LTECX_MUX_MODE_WCI2 0x0 ++#define LTECX_MUX_MODE_GPIO 0x1 ++ ++ ++/* LTECX GPIO Information Index */ ++#define LTECX_NVRAM_FSYNC_IDX 0 ++#define LTECX_NVRAM_LTERX_IDX 1 ++#define LTECX_NVRAM_LTETX_IDX 2 ++#define LTECX_NVRAM_WLPRIO_IDX 3 ++ ++/* LTECX WCI2 Information Index */ ++#define LTECX_NVRAM_WCI2IN_IDX 0 ++#define LTECX_NVRAM_WCI2OUT_IDX 1 ++ ++/* LTECX: Macros to get GPIO/FNSEL/GCIGPIO */ ++#define LTECX_EXTRACT_PADNUM(val, idx) (getbit8(&(val), (idx))) ++#define LTECX_EXTRACT_FNSEL(val, idx) (getbit4(&(val), (idx))) ++#define LTECX_EXTRACT_GCIGPIO(val, idx) (getbit4(&(val), (idx))) ++ ++/* WLAN channel numbers - used from wifi.h */ ++ ++/* WLAN BW */ ++#define ECI_BW_20 0x0 ++#define ECI_BW_25 0x1 ++#define ECI_BW_30 0x2 ++#define ECI_BW_35 0x3 ++#define ECI_BW_40 0x4 ++#define ECI_BW_45 0x5 ++#define ECI_BW_50 0x6 ++#define ECI_BW_ALL 0x7 ++ ++/* WLAN - number of antenna */ ++#define WLAN_NUM_ANT1 TXANT_0 ++#define WLAN_NUM_ANT2 TXANT_1 ++ ++/* otpctrl1 0xF4 */ ++#define OTPC_FORCE_PWR_OFF 0x02000000 ++/* chipcommon s/r registers introduced with cc rev >= 48 */ ++#define CC_SR_CTL0_ENABLE_MASK 0x1 ++#define CC_SR_CTL0_ENABLE_SHIFT 0 ++#define CC_SR_CTL0_EN_SR_ENG_CLK_SHIFT 1 /* sr_clk to sr_memory enable */ ++#define CC_SR_CTL0_RSRC_TRIGGER_SHIFT 2 /* Rising edge resource trigger 0 to sr_engine */ ++#define CC_SR_CTL0_MIN_DIV_SHIFT 6 /* Min division value for fast clk in sr_engine */ ++#define CC_SR_CTL0_EN_SBC_STBY_SHIFT 16 /* Allow Subcore mem StandBy? */ ++#define CC_SR_CTL0_EN_SR_ALP_CLK_MASK_SHIFT 18 ++#define CC_SR_CTL0_EN_SR_HT_CLK_SHIFT 19 ++#define CC_SR_CTL0_ALLOW_PIC_SHIFT 20 /* Allow pic to separate power domains */ ++#define CC_SR_CTL0_MAX_SR_LQ_CLK_CNT_SHIFT 25 ++#define CC_SR_CTL0_EN_MEM_DISABLE_FOR_SLEEP 30 ++ ++#define CC_SR_CTL1_SR_INIT_MASK 0x3FF ++#define CC_SR_CTL1_SR_INIT_SHIFT 0 ++ ++#define ECI_INLO_PKTDUR_MASK 0x000000f0 /* [7:4] - 4 bits */ ++#define ECI_INLO_PKTDUR_SHIFT 4 ++ ++/* gci chip control bits */ ++#define GCI_GPIO_CHIPCTRL_ENAB_IN_BIT 0 ++#define GCI_GPIO_CHIPCTRL_ENAB_OP_BIT 1 ++#define GCI_GPIO_CHIPCTRL_INVERT_BIT 2 ++#define GCI_GPIO_CHIPCTRL_PULLUP_BIT 3 ++#define GCI_GPIO_CHIPCTRL_PULLDN_BIT 4 ++#define GCI_GPIO_CHIPCTRL_ENAB_BTSIG_BIT 5 ++#define GCI_GPIO_CHIPCTRL_ENAB_OD_OP_BIT 6 ++#define GCI_GPIO_CHIPCTRL_ENAB_EXT_GPIO_BIT 7 ++ ++/* gci GPIO input status bits */ ++#define GCI_GPIO_STS_VALUE_BIT 0 ++#define GCI_GPIO_STS_POS_EDGE_BIT 1 ++#define GCI_GPIO_STS_NEG_EDGE_BIT 2 ++#define GCI_GPIO_STS_FAST_EDGE_BIT 3 ++#define GCI_GPIO_STS_CLEAR 0xF ++ ++#define GCI_GPIO_STS_VALUE (1 << GCI_GPIO_STS_VALUE_BIT) ++ ++/* SR Power Control */ ++#define SRPWR_DMN0_PCIE (0) /* PCIE */ ++#define SRPWR_DMN0_PCIE_SHIFT (SRPWR_DMN0_PCIE) /* PCIE */ ++#define SRPWR_DMN0_PCIE_MASK (1 << SRPWR_DMN0_PCIE_SHIFT) /* PCIE */ ++#define SRPWR_DMN1_ARMBPSD (1) /* ARM/BP/SDIO */ ++#define SRPWR_DMN1_ARMBPSD_SHIFT (SRPWR_DMN1_ARMBPSD) /* ARM/BP/SDIO */ ++#define SRPWR_DMN1_ARMBPSD_MASK (1 << SRPWR_DMN1_ARMBPSD_SHIFT) /* ARM/BP/SDIO */ ++#define SRPWR_DMN2_MACAUX (2) /* MAC/Phy Aux */ ++#define SRPWR_DMN2_MACAUX_SHIFT (SRPWR_DMN2_MACAUX) /* MAC/Phy Aux */ ++#define SRPWR_DMN2_MACAUX_MASK (1 << SRPWR_DMN2_MACAUX_SHIFT) /* MAC/Phy Aux */ ++#define SRPWR_DMN3_MACMAIN (3) /* MAC/Phy Main */ ++#define SRPWR_DMN3_MACMAIN_SHIFT (SRPWR_DMN3_MACMAIN) /* MAC/Phy Main */ ++#define SRPWR_DMN3_MACMAIN_MASK (1 << SRPWR_DMN3_MACMAIN_SHIFT) /* MAC/Phy Main */ ++#define SRPWR_DMN_ALL_MASK (0xF) ++ ++#define SRPWR_REQON_SHIFT (8) /* PowerOnRequest[11:8] */ ++#define SRPWR_REQON_MASK (SRPWR_DMN_ALL_MASK << SRPWR_REQON_SHIFT) ++#define SRPWR_STATUS_SHIFT (16) /* ExtPwrStatus[19:16], RO */ ++#define SRPWR_STATUS_MASK (SRPWR_DMN_ALL_MASK << SRPWR_STATUS_SHIFT) ++#define SRPWR_DMN_SHIFT (28) /* PowerDomain[31:28], RO */ ++#define SRPWR_DMN_MASK (SRPWR_DMN_ALL_MASK << SRPWR_DMN_SHIFT) ++ ++#endif /* _SBCHIPC_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sbconfig.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sbconfig.h +new file mode 100644 +index 000000000..ad9c408cd +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sbconfig.h +@@ -0,0 +1,285 @@ ++/* ++ * Broadcom SiliconBackplane hardware register definitions. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sbconfig.h 530150 2015-01-29 08:43:40Z $ ++ */ ++ ++#ifndef _SBCONFIG_H ++#define _SBCONFIG_H ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif ++ ++/* enumeration in SB is based on the premise that cores are contiguos in the ++ * enumeration space. ++ */ ++#define SB_BUS_SIZE 0x10000 /**< Each bus gets 64Kbytes for cores */ ++#define SB_BUS_BASE(b) (SI_ENUM_BASE + (b) * SB_BUS_SIZE) ++#define SB_BUS_MAXCORES (SB_BUS_SIZE / SI_CORE_SIZE) /**< Max cores per bus */ ++ ++/* ++ * Sonics Configuration Space Registers. ++ */ ++#define SBCONFIGOFF 0xf00 /**< core sbconfig regs are top 256bytes of regs */ ++#define SBCONFIGSIZE 256 /**< sizeof (sbconfig_t) */ ++ ++#define SBIPSFLAG 0x08 ++#define SBTPSFLAG 0x18 ++#define SBTMERRLOGA 0x48 /**< sonics >= 2.3 */ ++#define SBTMERRLOG 0x50 /**< sonics >= 2.3 */ ++#define SBADMATCH3 0x60 ++#define SBADMATCH2 0x68 ++#define SBADMATCH1 0x70 ++#define SBIMSTATE 0x90 ++#define SBINTVEC 0x94 ++#define SBTMSTATELOW 0x98 ++#define SBTMSTATEHIGH 0x9c ++#define SBBWA0 0xa0 ++#define SBIMCONFIGLOW 0xa8 ++#define SBIMCONFIGHIGH 0xac ++#define SBADMATCH0 0xb0 ++#define SBTMCONFIGLOW 0xb8 ++#define SBTMCONFIGHIGH 0xbc ++#define SBBCONFIG 0xc0 ++#define SBBSTATE 0xc8 ++#define SBACTCNFG 0xd8 ++#define SBFLAGST 0xe8 ++#define SBIDLOW 0xf8 ++#define SBIDHIGH 0xfc ++ ++/* All the previous registers are above SBCONFIGOFF, but with Sonics 2.3, we have ++ * a few registers *below* that line. I think it would be very confusing to try ++ * and change the value of SBCONFIGOFF, so I'm definig them as absolute offsets here, ++ */ ++ ++#define SBIMERRLOGA 0xea8 ++#define SBIMERRLOG 0xeb0 ++#define SBTMPORTCONNID0 0xed8 ++#define SBTMPORTLOCK0 0xef8 ++ ++#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) ++ ++typedef volatile struct _sbconfig { ++ uint32 PAD[2]; ++ uint32 sbipsflag; /**< initiator port ocp slave flag */ ++ uint32 PAD[3]; ++ uint32 sbtpsflag; /**< target port ocp slave flag */ ++ uint32 PAD[11]; ++ uint32 sbtmerrloga; /**< (sonics >= 2.3) */ ++ uint32 PAD; ++ uint32 sbtmerrlog; /**< (sonics >= 2.3) */ ++ uint32 PAD[3]; ++ uint32 sbadmatch3; /**< address match3 */ ++ uint32 PAD; ++ uint32 sbadmatch2; /**< address match2 */ ++ uint32 PAD; ++ uint32 sbadmatch1; /**< address match1 */ ++ uint32 PAD[7]; ++ uint32 sbimstate; /**< initiator agent state */ ++ uint32 sbintvec; /**< interrupt mask */ ++ uint32 sbtmstatelow; /**< target state */ ++ uint32 sbtmstatehigh; /**< target state */ ++ uint32 sbbwa0; /**< bandwidth allocation table0 */ ++ uint32 PAD; ++ uint32 sbimconfiglow; /**< initiator configuration */ ++ uint32 sbimconfighigh; /**< initiator configuration */ ++ uint32 sbadmatch0; /**< address match0 */ ++ uint32 PAD; ++ uint32 sbtmconfiglow; /**< target configuration */ ++ uint32 sbtmconfighigh; /**< target configuration */ ++ uint32 sbbconfig; /**< broadcast configuration */ ++ uint32 PAD; ++ uint32 sbbstate; /**< broadcast state */ ++ uint32 PAD[3]; ++ uint32 sbactcnfg; /**< activate configuration */ ++ uint32 PAD[3]; ++ uint32 sbflagst; /**< current sbflags */ ++ uint32 PAD[3]; ++ uint32 sbidlow; /**< identification */ ++ uint32 sbidhigh; /**< identification */ ++} sbconfig_t; ++ ++#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */ ++ ++/* sbipsflag */ ++#define SBIPS_INT1_MASK 0x3f /**< which sbflags get routed to mips interrupt 1 */ ++#define SBIPS_INT1_SHIFT 0 ++#define SBIPS_INT2_MASK 0x3f00 /**< which sbflags get routed to mips interrupt 2 */ ++#define SBIPS_INT2_SHIFT 8 ++#define SBIPS_INT3_MASK 0x3f0000 /**< which sbflags get routed to mips interrupt 3 */ ++#define SBIPS_INT3_SHIFT 16 ++#define SBIPS_INT4_MASK 0x3f000000 /**< which sbflags get routed to mips interrupt 4 */ ++#define SBIPS_INT4_SHIFT 24 ++ ++/* sbtpsflag */ ++#define SBTPS_NUM0_MASK 0x3f /**< interrupt sbFlag # generated by this core */ ++#define SBTPS_F0EN0 0x40 /**< interrupt is always sent on the backplane */ ++ ++/* sbtmerrlog */ ++#define SBTMEL_CM 0x00000007 /**< command */ ++#define SBTMEL_CI 0x0000ff00 /**< connection id */ ++#define SBTMEL_EC 0x0f000000 /**< error code */ ++#define SBTMEL_ME 0x80000000 /**< multiple error */ ++ ++/* sbimstate */ ++#define SBIM_PC 0xf /**< pipecount */ ++#define SBIM_AP_MASK 0x30 /**< arbitration policy */ ++#define SBIM_AP_BOTH 0x00 /**< use both timeslaces and token */ ++#define SBIM_AP_TS 0x10 /**< use timesliaces only */ ++#define SBIM_AP_TK 0x20 /**< use token only */ ++#define SBIM_AP_RSV 0x30 /**< reserved */ ++#define SBIM_IBE 0x20000 /**< inbanderror */ ++#define SBIM_TO 0x40000 /**< timeout */ ++#define SBIM_BY 0x01800000 /**< busy (sonics >= 2.3) */ ++#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 */ ++ ++/* sbtmstatehigh */ ++#define SBTMH_SERR 0x0001 /**< serror */ ++#define SBTMH_INT 0x0002 /**< interrupt */ ++#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 */ ++ ++/* sbbwa0 */ ++#define SBBWA_TAB0_MASK 0xffff /**< lookup table 0 */ ++#define SBBWA_TAB1_MASK 0xffff /**< lookup table 1 */ ++#define SBBWA_TAB1_SHIFT 16 ++ ++/* sbimconfiglow */ ++#define SBIMCL_STO_MASK 0x7 /**< service timeout */ ++#define SBIMCL_RTO_MASK 0x70 /**< request timeout */ ++#define SBIMCL_RTO_SHIFT 4 ++#define SBIMCL_CID_MASK 0xff0000 /**< connection id */ ++#define SBIMCL_CID_SHIFT 16 ++ ++/* sbimconfighigh */ ++#define SBIMCH_IEM_MASK 0xc /**< inband error mode */ ++#define SBIMCH_TEM_MASK 0x30 /**< timeout error mode */ ++#define SBIMCH_TEM_SHIFT 4 ++#define SBIMCH_BEM_MASK 0xc0 /**< bus error mode */ ++#define SBIMCH_BEM_SHIFT 6 ++ ++/* sbadmatch0 */ ++#define SBAM_TYPE_MASK 0x3 /**< address type */ ++#define SBAM_AD64 0x4 /**< reserved */ ++#define SBAM_ADINT0_MASK 0xf8 /**< type0 size */ ++#define SBAM_ADINT0_SHIFT 3 ++#define SBAM_ADINT1_MASK 0x1f8 /**< type1 size */ ++#define SBAM_ADINT1_SHIFT 3 ++#define SBAM_ADINT2_MASK 0x1f8 /**< type2 size */ ++#define SBAM_ADINT2_SHIFT 3 ++#define SBAM_ADEN 0x400 /**< enable */ ++#define SBAM_ADNEG 0x800 /**< negative decode */ ++#define SBAM_BASE0_MASK 0xffffff00 /**< type0 base address */ ++#define SBAM_BASE0_SHIFT 8 ++#define SBAM_BASE1_MASK 0xfffff000 /**< type1 base address for the core */ ++#define SBAM_BASE1_SHIFT 12 ++#define SBAM_BASE2_MASK 0xffff0000 /**< type2 base address for the core */ ++#define SBAM_BASE2_SHIFT 16 ++ ++/* sbtmconfiglow */ ++#define SBTMCL_CD_MASK 0xff /**< clock divide */ ++#define SBTMCL_CO_MASK 0xf800 /**< clock offset */ ++#define SBTMCL_CO_SHIFT 11 ++#define SBTMCL_IF_MASK 0xfc0000 /**< interrupt flags */ ++#define SBTMCL_IF_SHIFT 18 ++#define SBTMCL_IM_MASK 0x3000000 /**< interrupt mode */ ++#define SBTMCL_IM_SHIFT 24 ++ ++/* sbtmconfighigh */ ++#define SBTMCH_BM_MASK 0x3 /**< busy mode */ ++#define SBTMCH_RM_MASK 0x3 /**< retry mode */ ++#define SBTMCH_RM_SHIFT 2 ++#define SBTMCH_SM_MASK 0x30 /**< stop mode */ ++#define SBTMCH_SM_SHIFT 4 ++#define SBTMCH_EM_MASK 0x300 /**< sb error mode */ ++#define SBTMCH_EM_SHIFT 8 ++#define SBTMCH_IM_MASK 0xc00 /**< int mode */ ++#define SBTMCH_IM_SHIFT 10 ++ ++/* sbbconfig */ ++#define SBBC_LAT_MASK 0x3 /**< sb latency */ ++#define SBBC_MAX0_MASK 0xf0000 /**< maxccntr0 */ ++#define SBBC_MAX0_SHIFT 16 ++#define SBBC_MAX1_MASK 0xf00000 /**< maxccntr1 */ ++#define SBBC_MAX1_SHIFT 20 ++ ++/* sbbstate */ ++#define SBBS_SRD 0x1 /**< st reg disable */ ++#define SBBS_HRD 0x2 /**< hold reg disable */ ++ ++/* sbidlow */ ++#define SBIDL_CS_MASK 0x3 /**< config space */ ++#define SBIDL_AR_MASK 0x38 /**< # address ranges supported */ ++#define SBIDL_AR_SHIFT 3 ++#define SBIDL_SYNCH 0x40 /**< sync */ ++#define SBIDL_INIT 0x80 /**< initiator */ ++#define SBIDL_MINLAT_MASK 0xf00 /**< minimum backplane latency */ ++#define SBIDL_MINLAT_SHIFT 8 ++#define SBIDL_MAXLAT 0xf000 /**< maximum backplane latency */ ++#define SBIDL_MAXLAT_SHIFT 12 ++#define SBIDL_FIRST 0x10000 /**< this initiator is first */ ++#define SBIDL_CW_MASK 0xc0000 /**< cycle counter width */ ++#define SBIDL_CW_SHIFT 18 ++#define SBIDL_TP_MASK 0xf00000 /**< target ports */ ++#define SBIDL_TP_SHIFT 20 ++#define SBIDL_IP_MASK 0xf000000 /**< initiator ports */ ++#define SBIDL_IP_SHIFT 24 ++#define SBIDL_RV_MASK 0xf0000000 /**< sonics backplane revision code */ ++#define SBIDL_RV_SHIFT 28 ++#define SBIDL_RV_2_2 0x00000000 /**< version 2.2 or earlier */ ++#define SBIDL_RV_2_3 0x10000000 /**< version 2.3 */ ++ ++/* sbidhigh */ ++#define SBIDH_RC_MASK 0x000f /**< revision code */ ++#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)) ++#define SBIDH_CC_MASK 0x8ff0 /**< core code */ ++#define SBIDH_CC_SHIFT 4 ++#define SBIDH_VC_MASK 0xffff0000 /**< vendor code */ ++#define SBIDH_VC_SHIFT 16 ++ ++#define SB_COMMIT 0xfd8 /**< update buffered registers value */ ++ ++/* vendor codes */ ++#define SB_VEND_BCM 0x4243 /**< Broadcom's SB vendor code */ ++ ++#endif /* _SBCONFIG_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sbgci.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sbgci.h +new file mode 100644 +index 000000000..f04232dac +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sbgci.h +@@ -0,0 +1,248 @@ ++/* ++ * SiliconBackplane GCI core hardware definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sbgci.h 612498 2016-01-14 05:09:09Z $ ++ */ ++ ++#ifndef _SBGCI_H ++#define _SBGCI_H ++ ++#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__) ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++#define GCI_OFFSETOF(sih, reg) \ ++ (AOB_ENAB(sih) ? OFFSETOF(gciregs_t, reg) : OFFSETOF(chipcregs_t, reg)) ++#define GCI_CORE_IDX(sih) (AOB_ENAB(sih) ? si_findcoreidx(sih, GCI_CORE_ID, 0) : SI_CC_IDX) ++ ++typedef volatile struct { ++ uint32 gci_corecaps0; /* 0x000 */ ++ uint32 gci_corecaps1; /* 0x004 */ ++ uint32 gci_corecaps2; /* 0x008 */ ++ uint32 gci_corectrl; /* 0x00c */ ++ uint32 gci_corestat; /* 0x010 */ ++ uint32 gci_intstat; /* 0x014 */ ++ uint32 gci_intmask; /* 0x018 */ ++ uint32 gci_wakemask; /* 0x01c */ ++ uint32 gci_levelintstat; /* 0x020 */ ++ uint32 gci_eventintstat; /* 0x024 */ ++ uint32 gci_wakelevelintstat; /* 0x028 */ ++ uint32 gci_wakeeventintstat; /* 0x02c */ ++ uint32 semaphoreintstatus; /* 0x030 */ ++ uint32 semaphoreintmask; /* 0x034 */ ++ uint32 semaphorerequest; /* 0x038 */ ++ uint32 semaphorereserve; /* 0x03c */ ++ uint32 gci_indirect_addr; /* 0x040 */ ++ uint32 gci_gpioctl; /* 0x044 */ ++ uint32 gci_gpiostatus; /* 0x048 */ ++ uint32 gci_gpiomask; /* 0x04c */ ++ uint32 eventsummary; /* 0x050 */ ++ uint32 gci_miscctl; /* 0x054 */ ++ uint32 gci_gpiointmask; /* 0x058 */ ++ uint32 gci_gpiowakemask; /* 0x05c */ ++ uint32 gci_input[32]; /* 0x060 */ ++ uint32 gci_event[32]; /* 0x0e0 */ ++ uint32 gci_output[4]; /* 0x160 */ ++ uint32 gci_control_0; /* 0x170 */ ++ uint32 gci_control_1; /* 0x174 */ ++ uint32 gci_intpolreg; /* 0x178 */ ++ uint32 gci_levelintmask; /* 0x17c */ ++ uint32 gci_eventintmask; /* 0x180 */ ++ uint32 wakelevelintmask; /* 0x184 */ ++ uint32 wakeeventintmask; /* 0x188 */ ++ uint32 hwmask; /* 0x18c */ ++ uint32 PAD; ++ uint32 gci_inbandeventintmask; /* 0x194 */ ++ uint32 PAD; ++ uint32 gci_inbandeventstatus; /* 0x19c */ ++ uint32 gci_seciauxtx; /* 0x1a0 */ ++ uint32 gci_seciauxrx; /* 0x1a4 */ ++ uint32 gci_secitx_datatag; /* 0x1a8 */ ++ uint32 gci_secirx_datatag; /* 0x1ac */ ++ uint32 gci_secitx_datamask; /* 0x1b0 */ ++ uint32 gci_seciusef0tx_reg; /* 0x1b4 */ ++ uint32 gci_secif0tx_offset; /* 0x1b8 */ ++ uint32 gci_secif0rx_offset; /* 0x1bc */ ++ uint32 gci_secif1tx_offset; /* 0x1c0 */ ++ uint32 gci_rxfifo_common_ctrl; /* 0x1c4 */ ++ uint32 gci_rxfifoctrl; /* 0x1c8 */ ++ uint32 gci_hw_sema_status; /* 0x1cc */ ++ uint32 gci_seciuartescval; /* 0x1d0 */ ++ uint32 gic_seciuartautobaudctr; /* 0x1d4 */ ++ uint32 gci_secififolevel; /* 0x1d8 */ ++ uint32 gci_seciuartdata; /* 0x1dc */ ++ uint32 gci_secibauddiv; /* 0x1e0 */ ++ uint32 gci_secifcr; /* 0x1e4 */ ++ uint32 gci_secilcr; /* 0x1e8 */ ++ uint32 gci_secimcr; /* 0x1ec */ ++ uint32 gci_secilsr; /* 0x1f0 */ ++ uint32 gci_secimsr; /* 0x1f4 */ ++ uint32 gci_baudadj; /* 0x1f8 */ ++ uint32 gci_inbandintmask; /* 0x1fc */ ++ uint32 gci_chipctrl; /* 0x200 */ ++ uint32 gci_chipsts; /* 0x204 */ ++ uint32 gci_gpioout; /* 0x208 */ ++ uint32 gci_gpioout_read; /* 0x20C */ ++ uint32 gci_mpwaketx; /* 0x210 */ ++ uint32 gci_mpwakedetect; /* 0x214 */ ++ uint32 gci_seciin_ctrl; /* 0x218 */ ++ uint32 gci_seciout_ctrl; /* 0x21C */ ++ uint32 gci_seciin_auxfifo_en; /* 0x220 */ ++ uint32 gci_seciout_txen_txbr; /* 0x224 */ ++ uint32 gci_seciin_rxbrstatus; /* 0x228 */ ++ uint32 gci_seciin_rxerrstatus; /* 0x22C */ ++ uint32 gci_seciin_fcstatus; /* 0x230 */ ++ uint32 gci_seciout_txstatus; /* 0x234 */ ++ uint32 gci_seciout_txbrstatus; /* 0x238 */ ++ uint32 wlan_mem_info; /* 0x23C */ ++ uint32 wlan_bankxinfo; /* 0x240 */ ++ uint32 bt_smem_select; /* 0x244 */ ++ uint32 bt_smem_stby; /* 0x248 */ ++ uint32 bt_smem_status; /* 0x24C */ ++ uint32 wlan_bankxactivepda; /* 0x250 */ ++ uint32 wlan_bankxsleeppda; /* 0x254 */ ++ uint32 wlan_bankxkill; /* 0x258 */ ++ uint32 PAD[41]; ++ uint32 gci_chipid; /* 0x300 */ ++ uint32 PAD[3]; ++ uint32 otpstatus; /* 0x310 */ ++ uint32 otpcontrol; /* 0x314 */ ++ uint32 otpprog; /* 0x318 */ ++ uint32 otplayout; /* 0x31c */ ++ uint32 otplayoutextension; /* 0x320 */ ++ uint32 otpcontrol1; /* 0x324 */ ++ uint32 otpprogdata; /* 0x328 */ ++ uint32 PAD[52]; ++ uint32 otpECCstatus; /* 0x3FC */ ++ uint32 PAD[512]; ++ uint32 lhl_core_capab_adr; /* 0xC00 */ ++ uint32 lhl_main_ctl_adr; /* 0xC04 */ ++ uint32 lhl_pmu_ctl_adr; /* 0xC08 */ ++ uint32 lhl_extlpo_ctl_adr; /* 0xC0C */ ++ uint32 lpo_ctl_adr; /* 0xC10 */ ++ uint32 lhl_lpo2_ctl_adr; /* 0xC14 */ ++ uint32 lhl_osc32k_ctl_adr; /* 0xC18 */ ++ uint32 lhl_clk_status_adr; /* 0xC1C */ ++ uint32 lhl_clk_det_ctl_adr; /* 0xC20 */ ++ uint32 lhl_clk_sel_adr; /* 0xC24 */ ++ uint32 hidoff_cnt_adr[2]; /* 0xC28-0xC2C */ ++ uint32 lhl_autoclk_ctl_adr; /* 0xC30 */ ++ uint32 PAD; /* reserved */ ++ uint32 lhl_hibtim_adr; /* 0xC38 */ ++ uint32 lhl_wl_ilp_val_adr; /* 0xC3C */ ++ uint32 lhl_wl_armtim0_intrp_adr; /* 0xC40 */ ++ uint32 lhl_wl_armtim0_st_adr; /* 0xC44 */ ++ uint32 lhl_wl_armtim0_adr; /* 0xC48 */ ++ uint32 PAD[9]; /* 0xC4C-0xC6C */ ++ uint32 lhl_wl_mactim0_intrp_adr; /* 0xC70 */ ++ uint32 lhl_wl_mactim0_st_adr; /* 0xC74 */ ++ uint32 lhl_wl_mactim_int0_adr; /* 0xC78 */ ++ uint32 lhl_wl_mactim_frac0_adr; /* 0xC7C */ ++ uint32 lhl_wl_mactim1_intrp_adr; /* 0xC80 */ ++ uint32 lhl_wl_mactim1_st_adr; /* 0xC84 */ ++ uint32 lhl_wl_mactim_int1_adr; /* 0xC88 */ ++ uint32 lhl_wl_mactim_frac1_adr; /* 0xC8C */ ++ uint32 PAD[8]; /* 0xC90-0xCAC */ ++ uint32 gpio_int_en_port_adr[4]; /* 0xCB0-0xCBC */ ++ uint32 gpio_int_st_port_adr[4]; /* 0xCC0-0xCCC */ ++ uint32 gpio_ctrl_iocfg_p_adr[64]; /* 0xCD0-0xDCC */ ++ uint32 gpio_gctrl_iocfg_p0_p39_adr; /* 0xDD0 */ ++ uint32 gpio_gdsctrl_iocfg_p0_p25_p30_p39_adr; /* 0xDD4 */ ++ uint32 gpio_gdsctrl_iocfg_p26_p29_adr; /* 0xDD8 */ ++ uint32 PAD[8]; /* 0xDDC-0xDF8 */ ++ uint32 lhl_gpio_din0_adr; /* 0xDFC */ ++ uint32 lhl_gpio_din1_adr; /* 0xE00 */ ++ uint32 lhl_wkup_status_adr; /* 0xE04 */ ++ uint32 lhl_ctl_adr; /* 0xE08 */ ++ uint32 lhl_adc_ctl_adr; /* 0xE0C */ ++ uint32 lhl_qdxyz_in_dly_adr; /* 0xE10 */ ++ uint32 lhl_optctl_adr; /* 0xE14 */ ++ uint32 lhl_optct2_adr; /* 0xE18 */ ++ uint32 lhl_scanp_cntr_init_val_adr; /* 0xE1C */ ++ uint32 lhl_opt_togg_val_adr[6]; /* 0xE20-0xE34 */ ++ uint32 lhl_optx_smp_val_adr; /* 0xE38 */ ++ uint32 lhl_opty_smp_val_adr; /* 0xE3C */ ++ uint32 lhl_optz_smp_val_adr; /* 0xE40 */ ++ uint32 lhl_hidoff_keepstate_adr[3]; /* 0xE44-0xE4C */ ++ uint32 lhl_bt_slmboot_ctl0_adr[4]; /* 0xE50-0xE5C */ ++ uint32 lhl_wl_fw_ctl; /* 0xE60 */ ++ uint32 lhl_wl_hw_ctl_adr[2]; /* 0xE64-0xE68 */ ++ uint32 lhl_bt_hw_ctl_adr; /* 0xE6C */ ++ uint32 lhl_top_pwrseq_en_adr; /* 0xE70 */ ++ uint32 lhl_top_pwrdn_ctl_adr; /* 0xE74 */ ++ uint32 lhl_top_pwrup_ctl_adr; /* 0xE78 */ ++ uint32 lhl_top_pwrseq_ctl_adr; /* 0xE7C */ ++ uint32 lhl_top_pwrdn2_ctl_adr; /* 0xE80 */ ++ uint32 lhl_top_pwrup2_ctl_adr; /* 0xE84 */ ++ uint32 wpt_regon_intrp_cfg_adr; /* 0xE88 */ ++ uint32 bt_regon_intrp_cfg_adr; /* 0xE8C */ ++ uint32 wl_regon_intrp_cfg_adr; /* 0xE90 */ ++ uint32 regon_intrp_st_adr; /* 0xE94 */ ++ uint32 regon_intrp_en_adr; /* 0xE98 */ ++} gciregs_t; ++ ++#define GCI_CAP0_REV_MASK 0x000000ff ++ ++/* GCI Capabilities registers */ ++#define GCI_CORE_CAP_0_COREREV_MASK 0xFF ++#define GCI_CORE_CAP_0_COREREV_SHIFT 0 ++ ++#define GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK 0x3F ++#define GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT 0 ++#define GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK 0xF ++#define GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT 16 ++ ++#define WLAN_BANKX_SLEEPPDA_REG_SLEEPPDA_MASK 0xFFFF ++ ++#define WLAN_BANKX_PKILL_REG_SLEEPPDA_MASK 0x1 ++ ++/* WLAN BankXInfo Register */ ++#define WLAN_BANKXINFO_BANK_SIZE_MASK 0x00FFF000 ++#define WLAN_BANKXINFO_BANK_SIZE_SHIFT 12 ++ ++/* WLAN Mem Info Register */ ++#define WLAN_MEM_INFO_REG_NUMSOCRAMBANKS_MASK 0x000000FF ++#define WLAN_MEM_INFO_REG_NUMSOCRAMBANKS_SHIFT 0 ++ ++#define WLAN_MEM_INFO_REG_NUMD11MACBM_MASK 0x0000FF00 ++#define WLAN_MEM_INFO_REG_NUMD11MACBM_SHIFT 8 ++ ++#define WLAN_MEM_INFO_REG_NUMD11MACUCM_MASK 0x00FF0000 ++#define WLAN_MEM_INFO_REG_NUMD11MACUCM_SHIFT 16 ++ ++#define WLAN_MEM_INFO_REG_NUMD11MACSHM_MASK 0xFF000000 ++#define WLAN_MEM_INFO_REG_NUMD11MACSHM_SHIFT 24 ++ ++ ++#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */ ++ ++ ++#endif /* _SBGCI_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sbhnddma.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sbhnddma.h +new file mode 100644 +index 000000000..6d10d6ad3 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sbhnddma.h +@@ -0,0 +1,429 @@ ++/* ++ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface ++ * This supports the following chips: BCM42xx, 44xx, 47xx . ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sbhnddma.h 615537 2016-01-28 00:46:34Z $ ++ */ ++ ++#ifndef _sbhnddma_h_ ++#define _sbhnddma_h_ ++ ++/* DMA structure: ++ * support two DMA engines: 32 bits address or 64 bit addressing ++ * basic DMA register set is per channel(transmit or receive) ++ * a pair of channels is defined for convenience ++ */ ++ ++ ++/* 32 bits addressing */ ++ ++/** dma registers per channel(xmt or rcv) */ ++typedef volatile struct { ++ uint32 control; /**< enable, et al */ ++ uint32 addr; /**< descriptor ring base address (4K aligned) */ ++ uint32 ptr; /**< last descriptor posted to chip */ ++ uint32 status; /**< current active descriptor, et al */ ++} dma32regs_t; ++ ++typedef volatile struct { ++ dma32regs_t xmt; /**< dma tx channel */ ++ dma32regs_t rcv; /**< dma rx channel */ ++} dma32regp_t; ++ ++typedef volatile struct { /* diag access */ ++ uint32 fifoaddr; /**< diag address */ ++ uint32 fifodatalow; /**< low 32bits of data */ ++ uint32 fifodatahigh; /**< high 32bits of data */ ++ uint32 pad; /**< reserved */ ++} dma32diag_t; ++ ++/** ++ * DMA Descriptor ++ * Descriptors are only read by the hardware, never written back. ++ */ ++typedef volatile struct { ++ uint32 ctrl; /**< misc control bits & bufcount */ ++ uint32 addr; /**< data buffer address */ ++} dma32dd_t; ++ ++/** Each descriptor ring must be 4096byte aligned, and fit within a single 4096byte page. */ ++#define D32RINGALIGN_BITS 12 ++#define D32MAXRINGSZ (1 << D32RINGALIGN_BITS) ++#define D32RINGALIGN (1 << D32RINGALIGN_BITS) ++ ++#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t)) ++ ++/* transmit channel control */ ++#define XC_XE ((uint32)1 << 0) /**< transmit enable */ ++#define XC_SE ((uint32)1 << 1) /**< transmit suspend request */ ++#define XC_LE ((uint32)1 << 2) /**< loopback enable */ ++#define XC_FL ((uint32)1 << 4) /**< flush request */ ++#define XC_MR_MASK 0x000001C0 /**< Multiple outstanding reads */ ++#define XC_MR_SHIFT 6 ++#define XC_PD ((uint32)1 << 11) /**< parity check disable */ ++#define XC_AE ((uint32)3 << 16) /**< address extension bits */ ++#define XC_AE_SHIFT 16 ++#define XC_BL_MASK 0x001C0000 /**< BurstLen bits */ ++#define XC_BL_SHIFT 18 ++#define XC_PC_MASK 0x00E00000 /**< Prefetch control */ ++#define XC_PC_SHIFT 21 ++#define XC_PT_MASK 0x03000000 /**< Prefetch threshold */ ++#define XC_PT_SHIFT 24 ++ ++/** Multiple outstanding reads */ ++#define DMA_MR_1 0 ++#define DMA_MR_2 1 ++#define DMA_MR_4 2 ++#define DMA_MR_8 3 ++#define DMA_MR_12 4 ++#define DMA_MR_16 5 ++#define DMA_MR_20 6 ++#define DMA_MR_32 7 ++ ++/** DMA Burst Length in bytes */ ++#define DMA_BL_16 0 ++#define DMA_BL_32 1 ++#define DMA_BL_64 2 ++#define DMA_BL_128 3 ++#define DMA_BL_256 4 ++#define DMA_BL_512 5 ++#define DMA_BL_1024 6 ++ ++/** Prefetch control */ ++#define DMA_PC_0 0 ++#define DMA_PC_4 1 ++#define DMA_PC_8 2 ++#define DMA_PC_16 3 ++/* others: reserved */ ++ ++/** Prefetch threshold */ ++#define DMA_PT_1 0 ++#define DMA_PT_2 1 ++#define DMA_PT_4 2 ++#define DMA_PT_8 3 ++ ++/** Channel Switch */ ++#define DMA_CS_OFF 0 ++#define DMA_CS_ON 1 ++ ++/* transmit descriptor table pointer */ ++#define XP_LD_MASK 0xfff /**< last valid descriptor */ ++ ++/* transmit channel status */ ++#define XS_CD_MASK 0x0fff /**< current descriptor pointer */ ++#define XS_XS_MASK 0xf000 /**< transmit state */ ++#define XS_XS_SHIFT 12 ++#define XS_XS_DISABLED 0x0000 /**< disabled */ ++#define XS_XS_ACTIVE 0x1000 /**< active */ ++#define XS_XS_IDLE 0x2000 /**< idle wait */ ++#define XS_XS_STOPPED 0x3000 /**< stopped */ ++#define XS_XS_SUSP 0x4000 /**< suspend pending */ ++#define XS_XE_MASK 0xf0000 /**< transmit errors */ ++#define XS_XE_SHIFT 16 ++#define XS_XE_NOERR 0x00000 /**< no error */ ++#define XS_XE_DPE 0x10000 /**< descriptor protocol error */ ++#define XS_XE_DFU 0x20000 /**< data fifo underrun */ ++#define XS_XE_BEBR 0x30000 /**< bus error on buffer read */ ++#define XS_XE_BEDA 0x40000 /**< bus error on descriptor access */ ++#define XS_AD_MASK 0xfff00000 /**< active descriptor */ ++#define XS_AD_SHIFT 20 ++ ++/* receive channel control */ ++#define RC_RE ((uint32)1 << 0) /**< receive enable */ ++#define RC_RO_MASK 0xfe /**< receive frame offset */ ++#define RC_RO_SHIFT 1 ++#define RC_FM ((uint32)1 << 8) /**< direct fifo receive (pio) mode */ ++#define RC_SH ((uint32)1 << 9) /**< separate rx header descriptor enable */ ++#define RC_OC ((uint32)1 << 10) /**< overflow continue */ ++#define RC_PD ((uint32)1 << 11) /**< parity check disable */ ++#define RC_AE ((uint32)3 << 16) /**< address extension bits */ ++#define RC_AE_SHIFT 16 ++#define RC_BL_MASK 0x001C0000 /**< BurstLen bits */ ++#define RC_BL_SHIFT 18 ++#define RC_PC_MASK 0x00E00000 /**< Prefetch control */ ++#define RC_PC_SHIFT 21 ++#define RC_PT_MASK 0x03000000 /**< Prefetch threshold */ ++#define RC_PT_SHIFT 24 ++#define RC_WAITCMP_MASK 0x00001000 ++#define RC_WAITCMP_SHIFT 12 ++/* receive descriptor table pointer */ ++#define RP_LD_MASK 0xfff /**< last valid descriptor */ ++ ++/* receive channel status */ ++#define RS_CD_MASK 0x0fff /**< current descriptor pointer */ ++#define RS_RS_MASK 0xf000 /**< receive state */ ++#define RS_RS_SHIFT 12 ++#define RS_RS_DISABLED 0x0000 /**< disabled */ ++#define RS_RS_ACTIVE 0x1000 /**< active */ ++#define RS_RS_IDLE 0x2000 /**< idle wait */ ++#define RS_RS_STOPPED 0x3000 /**< reserved */ ++#define RS_RE_MASK 0xf0000 /**< receive errors */ ++#define RS_RE_SHIFT 16 ++#define RS_RE_NOERR 0x00000 /**< no error */ ++#define RS_RE_DPE 0x10000 /**< descriptor protocol error */ ++#define RS_RE_DFO 0x20000 /**< data fifo overflow */ ++#define RS_RE_BEBW 0x30000 /**< bus error on buffer write */ ++#define RS_RE_BEDA 0x40000 /**< bus error on descriptor access */ ++#define RS_AD_MASK 0xfff00000 /**< active descriptor */ ++#define RS_AD_SHIFT 20 ++ ++/* fifoaddr */ ++#define FA_OFF_MASK 0xffff /**< offset */ ++#define FA_SEL_MASK 0xf0000 /**< select */ ++#define FA_SEL_SHIFT 16 ++#define FA_SEL_XDD 0x00000 /**< transmit dma data */ ++#define FA_SEL_XDP 0x10000 /**< transmit dma pointers */ ++#define FA_SEL_RDD 0x40000 /**< receive dma data */ ++#define FA_SEL_RDP 0x50000 /**< receive dma pointers */ ++#define FA_SEL_XFD 0x80000 /**< transmit fifo data */ ++#define FA_SEL_XFP 0x90000 /**< transmit fifo pointers */ ++#define FA_SEL_RFD 0xc0000 /**< receive fifo data */ ++#define FA_SEL_RFP 0xd0000 /**< receive fifo pointers */ ++#define FA_SEL_RSD 0xe0000 /**< receive frame status data */ ++#define FA_SEL_RSP 0xf0000 /**< receive frame status pointers */ ++ ++/* descriptor control flags */ ++#define CTRL_BC_MASK 0x00001fff /**< buffer byte count, real data len must <= 4KB */ ++#define CTRL_AE ((uint32)3 << 16) /**< address extension bits */ ++#define CTRL_AE_SHIFT 16 ++#define CTRL_PARITY ((uint32)3 << 18) /**< parity bit */ ++#define CTRL_EOT ((uint32)1 << 28) /**< end of descriptor table */ ++#define CTRL_IOC ((uint32)1 << 29) /**< interrupt on completion */ ++#define CTRL_EOF ((uint32)1 << 30) /**< end of frame */ ++#define CTRL_SOF ((uint32)1 << 31) /**< start of frame */ ++ ++/** control flags in the range [27:20] are core-specific and not defined here */ ++#define CTRL_CORE_MASK 0x0ff00000 ++ ++/* 64 bits addressing */ ++ ++/** dma registers per channel(xmt or rcv) */ ++typedef volatile struct { ++ uint32 control; /**< enable, et al */ ++ uint32 ptr; /**< last descriptor posted to chip */ ++ uint32 addrlow; /**< descriptor ring base address low 32-bits (8K aligned) */ ++ uint32 addrhigh; /**< descriptor ring base address bits 63:32 (8K aligned) */ ++ uint32 status0; /**< current descriptor, xmt state */ ++ uint32 status1; /**< active descriptor, xmt error */ ++} dma64regs_t; ++ ++typedef volatile struct { ++ dma64regs_t tx; /**< dma64 tx channel */ ++ dma64regs_t rx; /**< dma64 rx channel */ ++} dma64regp_t; ++ ++typedef volatile struct { /**< diag access */ ++ uint32 fifoaddr; /**< diag address */ ++ uint32 fifodatalow; /**< low 32bits of data */ ++ uint32 fifodatahigh; /**< high 32bits of data */ ++ uint32 pad; /**< reserved */ ++} dma64diag_t; ++ ++/** ++ * DMA Descriptor ++ * Descriptors are only read by the hardware, never written back. ++ */ ++typedef volatile struct { ++ uint32 ctrl1; /**< misc control bits */ ++ uint32 ctrl2; /**< buffer count and address extension */ ++ uint32 addrlow; /**< memory address of the date buffer, bits 31:0 */ ++ uint32 addrhigh; /**< memory address of the date buffer, bits 63:32 */ ++} dma64dd_t; ++ ++/** ++ * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical addresss. ++ */ ++#define D64RINGALIGN_BITS 13 ++#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) ++#define D64RINGBOUNDARY (1 << D64RINGALIGN_BITS) ++ ++#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t)) ++ ++/** for cores with large descriptor ring support, descriptor ring size can be up to 4096 */ ++#define D64MAXDD_LARGE ((1 << 16) / sizeof (dma64dd_t)) ++ ++/** ++ * for cores with large descriptor ring support (4k descriptors), descriptor ring cannot cross ++ * 64K boundary ++ */ ++#define D64RINGBOUNDARY_LARGE (1 << 16) ++ ++/* ++ * Default DMA Burstlen values for USBRev >= 12 and SDIORev >= 11. ++ * When this field contains the value N, the burst length is 2**(N + 4) bytes. ++ */ ++#define D64_DEF_USBBURSTLEN 2 ++#define D64_DEF_SDIOBURSTLEN 1 ++ ++ ++#ifndef D64_USBBURSTLEN ++#define D64_USBBURSTLEN DMA_BL_64 ++#endif ++#ifndef D64_SDIOBURSTLEN ++#define D64_SDIOBURSTLEN DMA_BL_32 ++#endif ++ ++/* transmit channel control */ ++#define D64_XC_XE 0x00000001 /**< transmit enable */ ++#define D64_XC_SE 0x00000002 /**< transmit suspend request */ ++#define D64_XC_LE 0x00000004 /**< loopback enable */ ++#define D64_XC_FL 0x00000010 /**< flush request */ ++#define D64_XC_MR_MASK 0x000001C0 /**< Multiple outstanding reads */ ++#define D64_XC_MR_SHIFT 6 ++#define D64_XC_CS_SHIFT 9 /**< channel switch enable */ ++#define D64_XC_CS_MASK 0x00000200 /**< channel switch enable */ ++#define D64_XC_PD 0x00000800 /**< parity check disable */ ++#define D64_XC_AE 0x00030000 /**< address extension bits */ ++#define D64_XC_AE_SHIFT 16 ++#define D64_XC_BL_MASK 0x001C0000 /**< BurstLen bits */ ++#define D64_XC_BL_SHIFT 18 ++#define D64_XC_PC_MASK 0x00E00000 /**< Prefetch control */ ++#define D64_XC_PC_SHIFT 21 ++#define D64_XC_PT_MASK 0x03000000 /**< Prefetch threshold */ ++#define D64_XC_PT_SHIFT 24 ++ ++/* transmit descriptor table pointer */ ++#define D64_XP_LD_MASK 0x00001fff /**< last valid descriptor */ ++ ++/* transmit channel status */ ++#define D64_XS0_CD_MASK (di->d64_xs0_cd_mask) /**< current descriptor pointer */ ++#define D64_XS0_XS_MASK 0xf0000000 /**< transmit state */ ++#define D64_XS0_XS_SHIFT 28 ++#define D64_XS0_XS_DISABLED 0x00000000 /**< disabled */ ++#define D64_XS0_XS_ACTIVE 0x10000000 /**< active */ ++#define D64_XS0_XS_IDLE 0x20000000 /**< idle wait */ ++#define D64_XS0_XS_STOPPED 0x30000000 /**< stopped */ ++#define D64_XS0_XS_SUSP 0x40000000 /**< suspend pending */ ++ ++#define D64_XS1_AD_MASK (di->d64_xs1_ad_mask) /**< active descriptor */ ++#define D64_XS1_XE_MASK 0xf0000000 /**< transmit errors */ ++#define D64_XS1_XE_SHIFT 28 ++#define D64_XS1_XE_NOERR 0x00000000 /**< no error */ ++#define D64_XS1_XE_DPE 0x10000000 /**< descriptor protocol error */ ++#define D64_XS1_XE_DFU 0x20000000 /**< data fifo underrun */ ++#define D64_XS1_XE_DTE 0x30000000 /**< data transfer error */ ++#define D64_XS1_XE_DESRE 0x40000000 /**< descriptor read error */ ++#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 */ ++#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_SHIFT 9 /**< separate rx header descriptor enable */ ++#define D64_RC_OC 0x00000400 /**< overflow continue */ ++#define D64_RC_PD 0x00000800 /**< parity check disable */ ++#define D64_RC_SA 0x00002000 /**< select active */ ++#define D64_RC_GE 0x00004000 /**< Glom enable */ ++#define D64_RC_AE 0x00030000 /**< address extension bits */ ++#define D64_RC_AE_SHIFT 16 ++#define D64_RC_BL_MASK 0x001C0000 /**< BurstLen bits */ ++#define D64_RC_BL_SHIFT 18 ++#define D64_RC_PC_MASK 0x00E00000 /**< Prefetch control */ ++#define D64_RC_PC_SHIFT 21 ++#define D64_RC_PT_MASK 0x03000000 /**< Prefetch threshold */ ++#define D64_RC_PT_SHIFT 24 ++#define D64_RC_WAITCMP_MASK 0x00001000 ++#define D64_RC_WAITCMP_SHIFT 12 ++ ++/* 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 */ ++#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4) ++#define DMA_CTRL_DMA_AVOIDANCE_WAR (1 << 5) /**< DMA avoidance WAR for 4331 */ ++#define DMA_CTRL_RXSINGLE (1 << 6) /**< always single buffer */ ++#define DMA_CTRL_SDIO_RXGLOM (1 << 7) /**< DMA Rx glome is enabled */ ++ ++/* receive descriptor table pointer */ ++#define D64_RP_LD_MASK 0x00001fff /**< last valid descriptor */ ++ ++/* receive channel status */ ++#define D64_RS0_CD_MASK (di->d64_rs0_cd_mask) /**< current descriptor pointer */ ++#define D64_RS0_RS_MASK 0xf0000000 /**< receive state */ ++#define D64_RS0_RS_SHIFT 28 ++#define D64_RS0_RS_DISABLED 0x00000000 /**< disabled */ ++#define D64_RS0_RS_ACTIVE 0x10000000 /**< active */ ++#define D64_RS0_RS_IDLE 0x20000000 /**< idle wait */ ++#define D64_RS0_RS_STOPPED 0x30000000 /**< stopped */ ++#define D64_RS0_RS_SUSP 0x40000000 /**< suspend pending */ ++ ++#define D64_RS1_AD_MASK (di->d64_rs1_ad_mask) /* active descriptor pointer */ ++#define D64_RS1_RE_MASK 0xf0000000 /* receive errors */ ++#define D64_RS1_RE_SHIFT 28 ++#define D64_RS1_RE_NOERR 0x00000000 /**< no error */ ++#define D64_RS1_RE_DPO 0x10000000 /**< descriptor protocol error */ ++#define D64_RS1_RE_DFU 0x20000000 /**< data fifo overflow */ ++#define D64_RS1_RE_DTE 0x30000000 /**< data transfer error */ ++#define D64_RS1_RE_DESRE 0x40000000 /**< descriptor read error */ ++#define D64_RS1_RE_COREE 0x50000000 /**< core error */ ++ ++/* fifoaddr */ ++#define D64_FA_OFF_MASK 0xffff /**< offset */ ++#define D64_FA_SEL_MASK 0xf0000 /**< select */ ++#define D64_FA_SEL_SHIFT 16 ++#define D64_FA_SEL_XDD 0x00000 /**< transmit dma data */ ++#define D64_FA_SEL_XDP 0x10000 /**< transmit dma pointers */ ++#define D64_FA_SEL_RDD 0x40000 /**< receive dma data */ ++#define D64_FA_SEL_RDP 0x50000 /**< receive dma pointers */ ++#define D64_FA_SEL_XFD 0x80000 /**< transmit fifo data */ ++#define D64_FA_SEL_XFP 0x90000 /**< transmit fifo pointers */ ++#define D64_FA_SEL_RFD 0xc0000 /**< receive fifo data */ ++#define D64_FA_SEL_RFP 0xd0000 /**< receive fifo pointers */ ++#define D64_FA_SEL_RSD 0xe0000 /**< receive frame status data */ ++#define D64_FA_SEL_RSP 0xf0000 /**< receive frame status pointers */ ++ ++/* descriptor control flags 1 */ ++#define D64_CTRL_COREFLAGS 0x0ff00000 /**< core specific flags */ ++#define D64_CTRL1_NOTPCIE ((uint32)1 << 18) /**< buirst size control */ ++#define D64_CTRL1_EOT ((uint32)1 << 28) /**< end of descriptor table */ ++#define D64_CTRL1_IOC ((uint32)1 << 29) /**< interrupt on completion */ ++#define D64_CTRL1_EOF ((uint32)1 << 30) /**< end of frame */ ++#define D64_CTRL1_SOF ((uint32)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 */ ++#define D64_CTRL2_AE_SHIFT 16 ++#define D64_CTRL2_PARITY 0x00040000 /* parity bit */ ++ ++/** control flags in the range [27:20] are core-specific and not defined here */ ++#define D64_CTRL_CORE_MASK 0x0ff00000 ++ ++#define D64_RX_FRM_STS_LEN 0x0000ffff /**< frame length mask */ ++#define D64_RX_FRM_STS_OVFL 0x00800000 /**< RxOverFlow */ ++#define D64_RX_FRM_STS_DSCRCNT 0x0f000000 /**< no. of descriptors used - 1, d11corerev >= 22 */ ++#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /**< core-dependent data type */ ++ ++/** receive frame status */ ++typedef volatile struct { ++ uint16 len; ++ uint16 flags; ++} dma_rxh_t; ++ ++#endif /* _sbhnddma_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sbpcmcia.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sbpcmcia.h +new file mode 100644 +index 000000000..0ffc97be1 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sbpcmcia.h +@@ -0,0 +1,139 @@ ++/* ++ * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sbpcmcia.h 616054 2016-01-29 13:22:24Z $ ++ */ ++ ++#ifndef _SBPCMCIA_H ++#define _SBPCMCIA_H ++ ++/* All the addresses that are offsets in attribute space are divided ++ * by two to account for the fact that odd bytes are invalid in ++ * attribute space and our read/write routines make the space appear ++ * as if they didn't exist. Still we want to show the original numbers ++ * as documented in the hnd_pcmcia core manual. ++ */ ++ ++/* PCMCIA Function Configuration Registers */ ++#define PCMCIA_FCR (0x700 / 2) ++ ++#define FCR0_OFF 0 ++#define FCR1_OFF (0x40 / 2) ++#define FCR2_OFF (0x80 / 2) ++#define FCR3_OFF (0xc0 / 2) ++ ++#define PCMCIA_FCR0 (0x700 / 2) ++#define PCMCIA_FCR1 (0x740 / 2) ++#define PCMCIA_FCR2 (0x780 / 2) ++#define PCMCIA_FCR3 (0x7c0 / 2) ++ ++/* Standard PCMCIA FCR registers */ ++ ++#define PCMCIA_COR 0 ++ ++#define COR_RST 0x80 ++#define COR_LEV 0x40 ++#define COR_IRQEN 0x04 ++#define COR_BLREN 0x01 ++#define COR_FUNEN 0x01 ++ ++ ++#define PCICIA_FCSR (2 / 2) ++#define PCICIA_PRR (4 / 2) ++#define PCICIA_SCR (6 / 2) ++#define PCICIA_ESR (8 / 2) ++ ++ ++#define PCM_MEMOFF 0x0000 ++#define F0_MEMOFF 0x1000 ++#define F1_MEMOFF 0x2000 ++#define F2_MEMOFF 0x3000 ++#define F3_MEMOFF 0x4000 ++ ++/* Memory base in the function fcr's */ ++#define MEM_ADDR0 (0x728 / 2) ++#define MEM_ADDR1 (0x72a / 2) ++#define MEM_ADDR2 (0x72c / 2) ++ ++/* PCMCIA base plus Srom access in fcr0: */ ++#define PCMCIA_ADDR0 (0x072e / 2) ++#define PCMCIA_ADDR1 (0x0730 / 2) ++#define PCMCIA_ADDR2 (0x0732 / 2) ++ ++#define MEM_SEG (0x0734 / 2) ++#define SROM_CS (0x0736 / 2) ++#define SROM_DATAL (0x0738 / 2) ++#define SROM_DATAH (0x073a / 2) ++#define SROM_ADDRL (0x073c / 2) ++#define SROM_ADDRH (0x073e / 2) ++#define SROM_INFO2 (0x0772 / 2) /* Corerev >= 2 && <= 5 */ ++#define SROM_INFO (0x07be / 2) /* Corerev >= 6 */ ++ ++/* Values for srom_cs: */ ++#define SROM_IDLE 0 ++#define SROM_WRITE 1 ++#define SROM_READ 2 ++#define SROM_WEN 4 ++#define SROM_WDS 7 ++#define SROM_DONE 8 ++ ++/* Fields in srom_info: */ ++#define SRI_SZ_MASK 0x03 ++#define SRI_BLANK 0x04 ++#define SRI_OTP 0x80 ++ ++ ++#define SROM16K_BANK_SEL_MASK (3 << 11) ++#define SROM16K_BANK_SHFT_MASK 11 ++#define SROM16K_ADDR_SEL_MASK ((1 << SROM16K_BANK_SHFT_MASK) - 1) ++ ++ ++ ++/* Standard tuples we know about */ ++ ++#define CISTPL_NULL 0x00 ++#define CISTPL_END 0xff /* End of the CIS tuple chain */ ++ ++ ++#define CISTPL_BRCM_HNBU 0x80 ++ ++ ++#define HNBU_BOARDREV 0x02 /* One byte board revision */ ++ ++ ++#define HNBU_BOARDTYPE 0x1b /* 2 bytes; boardtype */ ++ ++ ++#define HNBU_HNBUCIS 0x1d /* what follows is proprietary HNBU CIS format */ ++ ++ ++/* sbtmstatelow */ ++#define SBTML_INT_ACK 0x40000 /* ack the sb interrupt */ ++#define SBTML_INT_EN 0x20000 /* enable sb interrupt */ ++ ++/* sbtmstatehigh */ ++#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */ ++#endif /* _SBPCMCIA_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sbsdio.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sbsdio.h +new file mode 100644 +index 000000000..68707c4d4 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sbsdio.h +@@ -0,0 +1,189 @@ ++/* ++ * SDIO device core hardware definitions. ++ * sdio is a portion of the pcmcia core in core rev 3 - rev 8 ++ * ++ * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sbsdio.h 514727 2014-11-12 03:02:48Z $ ++ */ ++ ++#ifndef _SBSDIO_H ++#define _SBSDIO_H ++ ++#define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */ ++ ++/* 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 */ ++#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D /* MesBusyCtl at 0x1001D (rev 11) */ ++ ++#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ ++#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ ++ ++/* Sdio Core Rev 12 */ ++#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E ++#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1 ++#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0 ++#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2 ++#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1 ++#define SBSDIO_FUNC1_SLEEPCSR 0x1001F ++#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1 ++#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0 ++#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1 ++#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2 ++#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1 ++ ++/* SBSDIO_SPROM_CS */ ++#define SBSDIO_SPROM_IDLE 0 ++#define SBSDIO_SPROM_WRITE 1 ++#define SBSDIO_SPROM_READ 2 ++#define SBSDIO_SPROM_WEN 4 ++#define SBSDIO_SPROM_WDS 7 ++#define SBSDIO_SPROM_DONE 8 ++ ++/* SBSDIO_SPROM_INFO */ ++#define SROM_SZ_MASK 0x03 /* SROM size, 1: 4k, 2: 16k */ ++#define SROM_BLANK 0x04 /* depreciated in corerev 6 */ ++#define SROM_OTP 0x80 /* OTP present */ ++ ++/* SBSDIO_CHIP_CTRL */ ++#define SBSDIO_CHIP_CTRL_XTAL 0x01 /* or'd with onchip xtal_pu, ++ * 1: power on oscillator ++ * (for 4318 only) ++ */ ++/* SBSDIO_WATERMARK */ ++#define SBSDIO_WATERMARK_MASK 0x7f /* number of words - 1 for sd device ++ * to wait before sending data to host ++ */ ++ ++/* SBSDIO_MESBUSYCTRL */ ++/* When RX FIFO has less entries than this & MBE is set ++ * => busy signal is asserted between data blocks. ++*/ ++#define SBSDIO_MESBUSYCTRL_MASK 0x7f ++#define SBSDIO_MESBUSYCTRL_ENAB 0x80 /* Enable busy capability for MES access */ ++ ++/* 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_EN_F2_BLK_WATERMARK 0x10 /* Enable function 2 tx for each block */ ++#define SBSDIO_DEVCTL_F2WM_ENAB 0x10 /* Enable F2 Watermark */ ++#define SBSDIO_DEVCTL_NONDAT_PADS_ISO 0x20 /* Isolate sdio clk and cmd (non-data) */ ++ ++/* 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 */ ++/* In rev8, actual avail bits followed original docs */ ++#define SBSDIO_Rev8_HT_AVAIL 0x40 ++#define SBSDIO_Rev8_ALP_AVAIL 0x80 ++#define SBSDIO_CSR_MASK 0x1F ++ ++#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))) ++ ++/* SBSDIO_FUNC1_SDIOPULLUP */ ++#define SBSDIO_PULLUP_D0 0x01 /* Enable D0/MISO pullup */ ++#define SBSDIO_PULLUP_D1 0x02 /* Enable D1/INT# pullup */ ++#define SBSDIO_PULLUP_D2 0x04 /* Enable D2 pullup */ ++#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD/MOSI pullup */ ++#define SBSDIO_PULLUP_ALL 0x0f /* All valid bits */ ++ ++/* function 1 OCP space */ ++#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */ ++#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 ++#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */ ++ ++/* 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 */ ++ ++/* 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_OTP_CIS_SIZE_LIMIT 0x078 /* maximum bytes OTP 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 ++ */ ++ ++/* indirect cis access (in sprom) */ ++#define SBSDIO_SPROM_CIS_OFFSET 0x8 /* 8 control bytes first, CIS starts from ++ * 8th byte ++ */ ++ ++#define SBSDIO_BYTEMODE_DATALEN_MAX 64 /* sdio byte mode: maximum length of one ++ * data comamnd ++ */ ++ ++#define SBSDIO_CORE_ADDR_MASK 0x1FFFF /* sdio core function one address mask */ ++ ++#endif /* _SBSDIO_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h +new file mode 100644 +index 000000000..8607d6357 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h +@@ -0,0 +1,300 @@ ++/* ++ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific ++ * device core support ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sbsdpcmdev.h 610395 2016-01-06 22:52:57Z $ ++ */ ++ ++#ifndef _sbsdpcmdev_h_ ++#define _sbsdpcmdev_h_ ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++ ++typedef volatile struct { ++ dma64regs_t xmt; /* dma tx */ ++ uint32 PAD[2]; ++ dma64regs_t rcv; /* dma rx */ ++ uint32 PAD[2]; ++} dma64p_t; ++ ++/* dma64 sdiod corerev >= 1 */ ++typedef volatile struct { ++ dma64p_t dma64regs[2]; ++ dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */ ++ uint32 PAD[92]; ++} sdiodma64_t; ++ ++/* dma32 sdiod corerev == 0 */ ++typedef volatile struct { ++ dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */ ++ dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */ ++ uint32 PAD[108]; ++} sdiodma32_t; ++ ++/* dma32 regs for pcmcia core */ ++typedef volatile struct { ++ dma32regp_t dmaregs; /* DMA Regs, 0x200-0x21c, rev8 */ ++ dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x220-0x22c */ ++ uint32 PAD[116]; ++} pcmdma32_t; ++ ++/* core registers */ ++typedef volatile struct { ++ uint32 corecontrol; /* CoreControl, 0x000, rev8 */ ++ uint32 corestatus; /* CoreStatus, 0x004, rev8 */ ++ uint32 PAD[1]; ++ uint32 biststatus; /* BistStatus, 0x00c, rev8 */ ++ ++ /* PCMCIA access */ ++ uint16 pcmciamesportaladdr; /* PcmciaMesPortalAddr, 0x010, rev8 */ ++ uint16 PAD[1]; ++ uint16 pcmciamesportalmask; /* PcmciaMesPortalMask, 0x014, rev8 */ ++ uint16 PAD[1]; ++ uint16 pcmciawrframebc; /* PcmciaWrFrameBC, 0x018, rev8 */ ++ uint16 PAD[1]; ++ uint16 pcmciaunderflowtimer; /* PcmciaUnderflowTimer, 0x01c, rev8 */ ++ uint16 PAD[1]; ++ ++ /* interrupt */ ++ uint32 intstatus; /* IntStatus, 0x020, rev8 */ ++ uint32 hostintmask; /* IntHostMask, 0x024, rev8 */ ++ uint32 intmask; /* IntSbMask, 0x028, rev8 */ ++ uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */ ++ uint32 sbintmask; /* SBIntMask, 0x030, rev8 */ ++ uint32 funcintmask; /* SDIO Function Interrupt Mask, SDIO rev4 */ ++ uint32 PAD[2]; ++ uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */ ++ uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */ ++ uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */ ++ uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */ ++ ++ /* synchronized access to registers in SDIO clock domain */ ++ uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */ ++ uint32 PAD[3]; ++ ++ /* PCMCIA frame control */ ++ uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */ ++ uint8 PAD[3]; ++ uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */ ++ uint8 PAD[155]; ++ ++ /* interrupt batching control */ ++ uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */ ++ uint32 PAD[3]; ++ ++ /* counters */ ++ uint32 cmd52rd; /* Cmd52RdCount, 0x110, rev8, SDIO: cmd52 reads */ ++ uint32 cmd52wr; /* Cmd52WrCount, 0x114, rev8, SDIO: cmd52 writes */ ++ uint32 cmd53rd; /* Cmd53RdCount, 0x118, rev8, SDIO: cmd53 reads */ ++ uint32 cmd53wr; /* Cmd53WrCount, 0x11c, rev8, SDIO: cmd53 writes */ ++ uint32 abort; /* AbortCount, 0x120, rev8, SDIO: aborts */ ++ uint32 datacrcerror; /* DataCrcErrorCount, 0x124, rev8, SDIO: frames w/bad CRC */ ++ uint32 rdoutofsync; /* RdOutOfSyncCount, 0x128, rev8, SDIO/PCMCIA: Rd Frm OOS */ ++ uint32 wroutofsync; /* RdOutOfSyncCount, 0x12c, rev8, SDIO/PCMCIA: Wr Frm OOS */ ++ uint32 writebusy; /* WriteBusyCount, 0x130, rev8, SDIO: dev asserted "busy" */ ++ uint32 readwait; /* ReadWaitCount, 0x134, rev8, SDIO: read: no data avail */ ++ uint32 readterm; /* ReadTermCount, 0x138, rev8, SDIO: rd frm terminates */ ++ uint32 writeterm; /* WriteTermCount, 0x13c, rev8, SDIO: wr frm terminates */ ++ uint32 PAD[40]; ++ uint32 clockctlstatus; /* ClockCtlStatus, 0x1e0, rev8 */ ++ uint32 PAD[1]; ++ uint32 powerctl; /* 0x1e8 */ ++ uint32 PAD[5]; ++ ++ /* DMA engines */ ++ volatile union { ++ pcmdma32_t pcm32; ++ sdiodma32_t sdiod32; ++ sdiodma64_t sdiod64; ++ } dma; ++ ++ /* SDIO/PCMCIA CIS region */ ++ char cis[512]; /* 512 byte CIS, 0x400-0x5ff, rev6 */ ++ ++ /* PCMCIA function control registers */ ++ char pcmciafcr[256]; /* PCMCIA FCR, 0x600-6ff, rev6 */ ++ uint16 PAD[55]; ++ ++ /* PCMCIA backplane access */ ++ uint16 backplanecsr; /* BackplaneCSR, 0x76E, rev6 */ ++ uint16 backplaneaddr0; /* BackplaneAddr0, 0x770, rev6 */ ++ uint16 backplaneaddr1; /* BackplaneAddr1, 0x772, rev6 */ ++ uint16 backplaneaddr2; /* BackplaneAddr2, 0x774, rev6 */ ++ uint16 backplaneaddr3; /* BackplaneAddr3, 0x776, rev6 */ ++ uint16 backplanedata0; /* BackplaneData0, 0x778, rev6 */ ++ uint16 backplanedata1; /* BackplaneData1, 0x77a, rev6 */ ++ uint16 backplanedata2; /* BackplaneData2, 0x77c, rev6 */ ++ uint16 backplanedata3; /* BackplaneData3, 0x77e, rev6 */ ++ uint16 PAD[31]; ++ ++ /* sprom "size" & "blank" info */ ++ uint16 spromstatus; /* SPROMStatus, 0x7BE, rev2 */ ++ uint32 PAD[464]; ++ ++ /* Sonics SiliconBackplane registers */ ++ sbconfig_t sbconfig; /* SbConfig Regs, 0xf00-0xfff, rev8 */ ++} sdpcmd_regs_t; ++ ++/* corecontrol */ ++#define CC_CISRDY (1 << 0) /* CIS Ready */ ++#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */ ++#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ ++#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */ ++#define CC_XMTDATAAVAIL_MODE (1 << 4) /* data avail generates an interrupt */ ++#define CC_XMTDATAAVAIL_CTRL (1 << 5) /* data avail interrupt ctrl */ ++ ++/* corestatus */ ++#define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */ ++#define CS_SMARTDEV (1 << 1) /* 1=smartDev enabled */ ++#define CS_F2ENABLED (1 << 2) /* 1=host has enabled the device */ ++ ++#define PCMCIA_MES_PA_MASK 0x7fff /* PCMCIA Message Portal Address Mask */ ++#define PCMCIA_MES_PM_MASK 0x7fff /* PCMCIA Message Portal Mask Mask */ ++#define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */ ++#define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */ ++ ++/* intstatus */ ++#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ ++#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ ++#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */ ++#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */ ++#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */ ++#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */ ++#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */ ++#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */ ++#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */ ++#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */ ++#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */ ++#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */ ++#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */ ++#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */ ++#define I_PC (1 << 10) /* descriptor error */ ++#define I_PD (1 << 11) /* data error */ ++#define I_DE (1 << 12) /* Descriptor protocol Error */ ++#define I_RU (1 << 13) /* Receive descriptor Underflow */ ++#define I_RO (1 << 14) /* Receive fifo Overflow */ ++#define I_XU (1 << 15) /* Transmit fifo Underflow */ ++#define I_RI (1 << 16) /* Receive Interrupt */ ++#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */ ++#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */ ++#define I_XI (1 << 24) /* Transmit Interrupt */ ++#define I_RF_TERM (1 << 25) /* Read Frame Terminate */ ++#define I_WF_TERM (1 << 26) /* Write Frame Terminate */ ++#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */ ++#define I_SBINT (1 << 28) /* sbintstatus Interrupt */ ++#define I_CHIPACTIVE (1 << 29) /* chip transitioned from doze to active state */ ++#define I_SRESET (1 << 30) /* CCCR RES interrupt */ ++#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */ ++#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) /* DMA Errors */ ++#define I_DMA (I_RI | I_XI | I_ERRORS) ++ ++/* sbintstatus */ ++#define I_SB_SERR (1 << 8) /* Backplane SError (write) */ ++#define I_SB_RESPERR (1 << 9) /* Backplane Response Error (read) */ ++#define I_SB_SPROMERR (1 << 10) /* Error accessing the sprom */ ++ ++/* sdioaccess */ ++#define SDA_DATA_MASK 0x000000ff /* Read/Write Data Mask */ ++#define SDA_ADDR_MASK 0x000fff00 /* Read/Write Address Mask */ ++#define SDA_ADDR_SHIFT 8 /* Read/Write Address Shift */ ++#define SDA_WRITE 0x01000000 /* Write bit */ ++#define SDA_READ 0x00000000 /* Write bit cleared for Read */ ++#define SDA_BUSY 0x80000000 /* Busy bit */ ++ ++/* sdioaccess-accessible register address spaces */ ++#define SDA_CCCR_SPACE 0x000 /* sdioAccess CCCR register space */ ++#define SDA_F1_FBR_SPACE 0x100 /* sdioAccess F1 FBR register space */ ++#define SDA_F2_FBR_SPACE 0x200 /* sdioAccess F2 FBR register space */ ++#define SDA_F1_REG_SPACE 0x300 /* sdioAccess F1 core-specific register space */ ++ ++/* SDA_F1_REG_SPACE sdioaccess-accessible F1 reg space register offsets */ ++#define SDA_CHIPCONTROLDATA 0x006 /* ChipControlData */ ++#define SDA_CHIPCONTROLENAB 0x007 /* ChipControlEnable */ ++#define SDA_F2WATERMARK 0x008 /* Function 2 Watermark */ ++#define SDA_DEVICECONTROL 0x009 /* DeviceControl */ ++#define SDA_SBADDRLOW 0x00a /* SbAddrLow */ ++#define SDA_SBADDRMID 0x00b /* SbAddrMid */ ++#define SDA_SBADDRHIGH 0x00c /* SbAddrHigh */ ++#define SDA_FRAMECTRL 0x00d /* FrameCtrl */ ++#define SDA_CHIPCLOCKCSR 0x00e /* ChipClockCSR */ ++#define SDA_SDIOPULLUP 0x00f /* SdioPullUp */ ++#define SDA_SDIOWRFRAMEBCLOW 0x019 /* SdioWrFrameBCLow */ ++#define SDA_SDIOWRFRAMEBCHIGH 0x01a /* SdioWrFrameBCHigh */ ++#define SDA_SDIORDFRAMEBCLOW 0x01b /* SdioRdFrameBCLow */ ++#define SDA_SDIORDFRAMEBCHIGH 0x01c /* SdioRdFrameBCHigh */ ++ ++/* SDA_F2WATERMARK */ ++#define SDA_F2WATERMARK_MASK 0x7f /* F2Watermark Mask */ ++ ++/* SDA_SBADDRLOW */ ++#define SDA_SBADDRLOW_MASK 0x80 /* SbAddrLow Mask */ ++ ++/* SDA_SBADDRMID */ ++#define SDA_SBADDRMID_MASK 0xff /* SbAddrMid Mask */ ++ ++/* SDA_SBADDRHIGH */ ++#define SDA_SBADDRHIGH_MASK 0xff /* SbAddrHigh Mask */ ++ ++/* SDA_FRAMECTRL */ ++#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */ ++#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */ ++#define SFC_CRC4WOOS (1 << 2) /* HW reports CRC error for write out of sync */ ++#define SFC_ABORTALL (1 << 3) /* Abort cancels all in-progress frames */ ++ ++/* pcmciaframectrl */ ++#define PFC_RF_TERM (1 << 0) /* Read Frame Terminate */ ++#define PFC_WF_TERM (1 << 1) /* Write Frame Terminate */ ++ ++/* intrcvlazy */ ++#define IRL_TO_MASK 0x00ffffff /* timeout */ ++#define IRL_FC_MASK 0xff000000 /* frame count */ ++#define IRL_FC_SHIFT 24 /* frame count */ ++ ++/* rx header */ ++typedef volatile struct { ++ uint16 len; ++ uint16 flags; ++} sdpcmd_rxh_t; ++ ++/* rx header flags */ ++#define RXF_CRC 0x0001 /* CRC error detected */ ++#define RXF_WOOS 0x0002 /* write frame out of sync */ ++#define RXF_WF_TERM 0x0004 /* write frame terminated */ ++#define RXF_ABORT 0x0008 /* write frame aborted */ ++#define RXF_DISCARD (RXF_CRC | RXF_WOOS | RXF_WF_TERM | RXF_ABORT) /* bad frame */ ++ ++/* HW frame tag */ ++#define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */ ++ ++#define SDPCM_HWEXT_LEN 8 ++ ++#endif /* _sbsdpcmdev_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sbsocram.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sbsocram.h +new file mode 100644 +index 000000000..b2c018839 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sbsocram.h +@@ -0,0 +1,205 @@ ++/* ++ * BCM47XX Sonics SiliconBackplane embedded ram core ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sbsocram.h 604712 2015-12-08 08:05:42Z $ ++ */ ++ ++#ifndef _SBSOCRAM_H ++#define _SBSOCRAM_H ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++/* Memcsocram core registers */ ++typedef volatile struct sbsocramregs { ++ uint32 coreinfo; ++ uint32 bwalloc; ++ uint32 extracoreinfo; ++ uint32 biststat; ++ uint32 bankidx; ++ uint32 standbyctrl; ++ ++ uint32 errlogstatus; /* rev 6 */ ++ uint32 errlogaddr; /* rev 6 */ ++ /* used for patching rev 3 & 5 */ ++ uint32 cambankidx; ++ uint32 cambankstandbyctrl; ++ uint32 cambankpatchctrl; ++ uint32 cambankpatchtblbaseaddr; ++ uint32 cambankcmdreg; ++ uint32 cambankdatareg; ++ uint32 cambankmaskreg; ++ uint32 PAD[1]; ++ uint32 bankinfo; /* corev 8 */ ++ uint32 bankpda; ++ uint32 PAD[14]; ++ uint32 extmemconfig; ++ uint32 extmemparitycsr; ++ uint32 extmemparityerrdata; ++ uint32 extmemparityerrcnt; ++ uint32 extmemwrctrlandsize; ++ uint32 PAD[84]; ++ uint32 workaround; ++ uint32 pwrctl; /* corerev >= 2 */ ++ uint32 PAD[133]; ++ uint32 sr_control; /* corerev >= 15 */ ++ uint32 sr_status; /* corerev >= 15 */ ++ uint32 sr_address; /* corerev >= 15 */ ++ uint32 sr_data; /* corerev >= 15 */ ++} sbsocramregs_t; ++ ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++/* Register offsets */ ++#define SR_COREINFO 0x00 ++#define SR_BWALLOC 0x04 ++#define SR_BISTSTAT 0x0c ++#define SR_BANKINDEX 0x10 ++#define SR_BANKSTBYCTL 0x14 ++#define SR_PWRCTL 0x1e8 ++ ++/* Coreinfo register */ ++#define SRCI_PT_MASK 0x00070000 /* corerev >= 6; port type[18:16] */ ++#define SRCI_PT_SHIFT 16 ++/* port types : SRCI_PT__ */ ++#define SRCI_PT_OCP_OCP 0 ++#define SRCI_PT_AXI_OCP 1 ++#define SRCI_PT_ARM7AHB_OCP 2 ++#define SRCI_PT_CM3AHB_OCP 3 ++#define SRCI_PT_AXI_AXI 4 ++#define SRCI_PT_AHB_AXI 5 ++/* corerev >= 3 */ ++#define SRCI_LSS_MASK 0x00f00000 ++#define SRCI_LSS_SHIFT 20 ++#define SRCI_LRS_MASK 0x0f000000 ++#define SRCI_LRS_SHIFT 24 ++ ++/* In corerev 0, the memory size is 2 to the power of the ++ * base plus 16 plus to the contents of the memsize field plus 1. ++ */ ++#define SRCI_MS0_MASK 0xf ++#define SR_MS0_BASE 16 ++ ++/* ++ * In corerev 1 the bank size is 2 ^ the bank size field plus 14, ++ * the memory size is number of banks times bank size. ++ * The same applies to rom size. ++ */ ++#define SRCI_ROMNB_MASK 0xf000 ++#define SRCI_ROMNB_SHIFT 12 ++#define SRCI_ROMBSZ_MASK 0xf00 ++#define SRCI_ROMBSZ_SHIFT 8 ++#define SRCI_SRNB_MASK 0xf0 ++#define SRCI_SRNB_SHIFT 4 ++#define SRCI_SRBSZ_MASK 0xf ++#define SRCI_SRBSZ_SHIFT 0 ++ ++#define SRCI_SRNB_MASK_EXT 0x100 ++ ++#define SR_BSZ_BASE 14 ++ ++/* Standby control register */ ++#define SRSC_SBYOVR_MASK 0x80000000 ++#define SRSC_SBYOVR_SHIFT 31 ++#define SRSC_SBYOVRVAL_MASK 0x60000000 ++#define SRSC_SBYOVRVAL_SHIFT 29 ++#define SRSC_SBYEN_MASK 0x01000000 /* rev >= 3 */ ++#define SRSC_SBYEN_SHIFT 24 ++ ++/* Power control register */ ++#define SRPC_PMU_STBYDIS_MASK 0x00000010 /* rev >= 3 */ ++#define SRPC_PMU_STBYDIS_SHIFT 4 ++#define SRPC_STBYOVRVAL_MASK 0x00000008 ++#define SRPC_STBYOVRVAL_SHIFT 3 ++#define SRPC_STBYOVR_MASK 0x00000007 ++#define SRPC_STBYOVR_SHIFT 0 ++ ++/* Extra core capability register */ ++#define SRECC_NUM_BANKS_MASK 0x000000F0 ++#define SRECC_NUM_BANKS_SHIFT 4 ++#define SRECC_BANKSIZE_MASK 0x0000000F ++#define SRECC_BANKSIZE_SHIFT 0 ++ ++#define SRECC_BANKSIZE(value) (1 << (value)) ++ ++/* CAM bank patch control */ ++#define SRCBPC_PATCHENABLE 0x80000000 ++ ++#define SRP_ADDRESS 0x0001FFFC ++#define SRP_VALID 0x8000 ++ ++/* CAM bank command reg */ ++#define SRCMD_WRITE 0x00020000 ++#define SRCMD_READ 0x00010000 ++#define SRCMD_DONE 0x80000000 ++ ++#define SRCMD_DONE_DLY 1000 ++ ++/* bankidx and bankinfo reg defines corerev >= 8 */ ++#define SOCRAM_BANKINFO_SZMASK 0x7f ++#define SOCRAM_BANKIDX_ROM_MASK 0x100 ++ ++#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 ++/* socram bankinfo memtype */ ++#define SOCRAM_MEMTYPE_RAM 0 ++#define SOCRAM_MEMTYPE_R0M 1 ++#define SOCRAM_MEMTYPE_DEVRAM 2 ++ ++#define SOCRAM_BANKINFO_REG 0x40 ++#define SOCRAM_BANKIDX_REG 0x10 ++#define SOCRAM_BANKINFO_STDBY_MASK 0x400 ++#define SOCRAM_BANKINFO_STDBY_TIMER 0x800 ++ ++/* bankinfo rev >= 10 */ ++#define SOCRAM_BANKINFO_DEVRAMSEL_SHIFT 13 ++#define SOCRAM_BANKINFO_DEVRAMSEL_MASK 0x2000 ++#define SOCRAM_BANKINFO_DEVRAMPRO_SHIFT 14 ++#define SOCRAM_BANKINFO_DEVRAMPRO_MASK 0x4000 ++#define SOCRAM_BANKINFO_SLPSUPP_SHIFT 15 ++#define SOCRAM_BANKINFO_SLPSUPP_MASK 0x8000 ++#define SOCRAM_BANKINFO_RETNTRAM_SHIFT 16 ++#define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 ++#define SOCRAM_BANKINFO_PDASZ_SHIFT 17 ++#define SOCRAM_BANKINFO_PDASZ_MASK 0x003E0000 ++#define SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT 24 ++#define SOCRAM_BANKINFO_DEVRAMREMAP_MASK 0x01000000 ++ ++/* extracoreinfo register */ ++#define SOCRAM_DEVRAMBANK_MASK 0xF000 ++#define SOCRAM_DEVRAMBANK_SHIFT 12 ++ ++/* bank info to calculate bank size */ ++#define SOCRAM_BANKINFO_SZBASE 8192 ++#define SOCRAM_BANKSIZE_SHIFT 13 /* SOCRAM_BANKINFO_SZBASE */ ++ ++ ++#endif /* _SBSOCRAM_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sbsysmem.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sbsysmem.h +new file mode 100644 +index 000000000..df26399b2 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sbsysmem.h +@@ -0,0 +1,180 @@ ++/* ++ * SiliconBackplane System Memory core ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sbsysmem.h 563229 2015-06-12 04:50:06Z $ ++ */ ++ ++#ifndef _SBSYSMEM_H ++#define _SBSYSMEM_H ++ ++#ifndef _LANGUAGE_ASSEMBLY ++ ++/* cpp contortions to concatenate w/arg prescan */ ++#ifndef PAD ++#define _PADLINE(line) pad ## line ++#define _XSTR(line) _PADLINE(line) ++#define PAD _XSTR(__LINE__) ++#endif /* PAD */ ++ ++/* sysmem core registers */ ++typedef volatile struct sysmemregs { ++ uint32 coreinfo; ++ uint32 bwalloc; ++ uint32 extracoreinfo; ++ uint32 biststat; ++ uint32 bankidx; ++ uint32 standbyctrl; ++ ++ uint32 errlogstatus; ++ uint32 errlogaddr; ++ ++ uint32 cambankidx; ++ uint32 cambankstandbyctrl; ++ uint32 cambankpatchctrl; ++ uint32 cambankpatchtblbaseaddr; ++ uint32 cambankcmdreg; ++ uint32 cambankdatareg; ++ uint32 cambankmaskreg; ++ uint32 PAD[1]; ++ uint32 bankinfo; ++ uint32 PAD[15]; ++ uint32 extmemconfig; ++ uint32 extmemparitycsr; ++ uint32 extmemparityerrdata; ++ uint32 extmemparityerrcnt; ++ uint32 extmemwrctrlandsize; ++ uint32 PAD[84]; ++ uint32 workaround; ++ uint32 pwrctl; ++ uint32 PAD[133]; ++ uint32 sr_control; ++ uint32 sr_status; ++ uint32 sr_address; ++ uint32 sr_data; ++} sysmemregs_t; ++ ++#endif /* _LANGUAGE_ASSEMBLY */ ++ ++/* Register offsets */ ++#define SR_COREINFO 0x00 ++#define SR_BWALLOC 0x04 ++#define SR_BISTSTAT 0x0c ++#define SR_BANKINDEX 0x10 ++#define SR_BANKSTBYCTL 0x14 ++#define SR_PWRCTL 0x1e8 ++ ++/* Coreinfo register */ ++#define SRCI_PT_MASK 0x00070000 /* port type[18:16] */ ++#define SRCI_PT_SHIFT 16 ++/* port types : SRCI_PT__ */ ++#define SRCI_PT_OCP_OCP 0 ++#define SRCI_PT_AXI_OCP 1 ++#define SRCI_PT_ARM7AHB_OCP 2 ++#define SRCI_PT_CM3AHB_OCP 3 ++#define SRCI_PT_AXI_AXI 4 ++#define SRCI_PT_AHB_AXI 5 ++ ++#define SRCI_LSS_MASK 0x00f00000 ++#define SRCI_LSS_SHIFT 20 ++#define SRCI_LRS_MASK 0x0f000000 ++#define SRCI_LRS_SHIFT 24 ++ ++/* In corerev 0, the memory size is 2 to the power of the ++ * base plus 16 plus to the contents of the memsize field plus 1. ++ */ ++#define SRCI_MS0_MASK 0xf ++#define SR_MS0_BASE 16 ++ ++/* ++ * In corerev 1 the bank size is 2 ^ the bank size field plus 14, ++ * the memory size is number of banks times bank size. ++ * The same applies to rom size. ++ */ ++#define SYSMEM_SRCI_ROMNB_MASK 0x3e0 ++#define SYSMEM_SRCI_ROMNB_SHIFT 5 ++#define SYSMEM_SRCI_SRNB_MASK 0x1f ++#define SYSMEM_SRCI_SRNB_SHIFT 0 ++ ++/* Standby control register */ ++#define SRSC_SBYOVR_MASK 0x80000000 ++#define SRSC_SBYOVR_SHIFT 31 ++#define SRSC_SBYOVRVAL_MASK 0x60000000 ++#define SRSC_SBYOVRVAL_SHIFT 29 ++#define SRSC_SBYEN_MASK 0x01000000 ++#define SRSC_SBYEN_SHIFT 24 ++ ++/* Power control register */ ++#define SRPC_PMU_STBYDIS_MASK 0x00000010 ++#define SRPC_PMU_STBYDIS_SHIFT 4 ++#define SRPC_STBYOVRVAL_MASK 0x00000008 ++#define SRPC_STBYOVRVAL_SHIFT 3 ++#define SRPC_STBYOVR_MASK 0x00000007 ++#define SRPC_STBYOVR_SHIFT 0 ++ ++/* Extra core capability register */ ++#define SRECC_NUM_BANKS_MASK 0x000000F0 ++#define SRECC_NUM_BANKS_SHIFT 4 ++#define SRECC_BANKSIZE_MASK 0x0000000F ++#define SRECC_BANKSIZE_SHIFT 0 ++ ++#define SRECC_BANKSIZE(value) (1 << (value)) ++ ++/* CAM bank patch control */ ++#define SRCBPC_PATCHENABLE 0x80000000 ++ ++#define SRP_ADDRESS 0x0001FFFC ++#define SRP_VALID 0x8000 ++ ++/* CAM bank command reg */ ++#define SRCMD_WRITE 0x00020000 ++#define SRCMD_READ 0x00010000 ++#define SRCMD_DONE 0x80000000 ++ ++#define SRCMD_DONE_DLY 1000 ++ ++/* bankidx and bankinfo reg defines */ ++#define SYSMEM_BANKINFO_SZMASK 0x7f ++#define SYSMEM_BANKIDX_ROM_MASK 0x80 ++ ++#define SYSMEM_BANKINFO_REG 0x40 ++#define SYSMEM_BANKIDX_REG 0x10 ++#define SYSMEM_BANKINFO_STDBY_MASK 0x200 ++#define SYSMEM_BANKINFO_STDBY_TIMER 0x400 ++ ++#define SYSMEM_BANKINFO_SLPSUPP_SHIFT 14 ++#define SYSMEM_BANKINFO_SLPSUPP_MASK 0x4000 ++#define SYSMEM_BANKINFO_PDASZ_SHIFT 16 ++#define SYSMEM_BANKINFO_PDASZ_MASK 0x001F0000 ++ ++/* extracoreinfo register */ ++#define SYSMEM_DEVRAMBANK_MASK 0xF000 ++#define SYSMEM_DEVRAMBANK_SHIFT 12 ++ ++/* bank info to calculate bank size */ ++#define SYSMEM_BANKINFO_SZBASE 8192 ++#define SYSMEM_BANKSIZE_SHIFT 13 /* SYSMEM_BANKINFO_SZBASE */ ++ ++#endif /* _SBSYSMEM_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sdio.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sdio.h +new file mode 100644 +index 000000000..8f77e4150 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sdio.h +@@ -0,0 +1,630 @@ ++/* ++ * SDIO spec header file ++ * Protocol and standard (common) device definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sdio.h 644725 2016-06-21 12:26:04Z $ ++ */ ++ ++#ifndef _SDIO_H ++#define _SDIO_H ++ ++#ifdef BCMSDIO ++ ++/* CCCR structure for function 0 */ ++typedef volatile struct { ++ uint8 cccr_sdio_rev; /* RO, cccr and sdio revision */ ++ uint8 sd_rev; /* RO, sd spec revision */ ++ uint8 io_en; /* I/O enable */ ++ uint8 io_rdy; /* I/O ready reg */ ++ uint8 intr_ctl; /* Master and per function interrupt enable control */ ++ uint8 intr_status; /* RO, interrupt pending status */ ++ uint8 io_abort; /* read/write abort or reset all functions */ ++ uint8 bus_inter; /* bus interface control */ ++ uint8 capability; /* RO, card capability */ ++ ++ uint8 cis_base_low; /* 0x9 RO, common CIS base address, LSB */ ++ uint8 cis_base_mid; ++ uint8 cis_base_high; /* 0xB RO, common CIS base address, MSB */ ++ ++ /* suspend/resume registers */ ++ uint8 bus_suspend; /* 0xC */ ++ uint8 func_select; /* 0xD */ ++ uint8 exec_flag; /* 0xE */ ++ uint8 ready_flag; /* 0xF */ ++ ++ uint8 fn0_blk_size[2]; /* 0x10(LSB), 0x11(MSB) */ ++ ++ uint8 power_control; /* 0x12 (SDIO version 1.10) */ ++ ++ uint8 speed_control; /* 0x13 */ ++} sdio_regs_t; ++ ++/* SDIO Device CCCR offsets */ ++#define SDIOD_CCCR_REV 0x00 ++#define SDIOD_CCCR_SDREV 0x01 ++#define SDIOD_CCCR_IOEN 0x02 ++#define SDIOD_CCCR_IORDY 0x03 ++#define SDIOD_CCCR_INTEN 0x04 ++#define SDIOD_CCCR_INTPEND 0x05 ++#define SDIOD_CCCR_IOABORT 0x06 ++#define SDIOD_CCCR_BICTRL 0x07 ++#define SDIOD_CCCR_CAPABLITIES 0x08 ++#define SDIOD_CCCR_CISPTR_0 0x09 ++#define SDIOD_CCCR_CISPTR_1 0x0A ++#define SDIOD_CCCR_CISPTR_2 0x0B ++#define SDIOD_CCCR_BUSSUSP 0x0C ++#define SDIOD_CCCR_FUNCSEL 0x0D ++#define SDIOD_CCCR_EXECFLAGS 0x0E ++#define SDIOD_CCCR_RDYFLAGS 0x0F ++#define SDIOD_CCCR_BLKSIZE_0 0x10 ++#define SDIOD_CCCR_BLKSIZE_1 0x11 ++#define SDIOD_CCCR_POWER_CONTROL 0x12 ++#define SDIOD_CCCR_SPEED_CONTROL 0x13 ++#define SDIOD_CCCR_UHSI_SUPPORT 0x14 ++#define SDIOD_CCCR_DRIVER_STRENGTH 0x15 ++#define SDIOD_CCCR_INTR_EXTN 0x16 ++ ++/* Broadcom extensions (corerev >= 1) */ ++#define SDIOD_CCCR_BRCM_CARDCAP 0xf0 ++#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02 ++#define SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04 ++#define SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08 ++#define SDIOD_CCCR_BRCM_CARDCTL 0xf1 ++#define SDIOD_CCCR_BRCM_SEPINT 0xf2 ++ ++/* cccr_sdio_rev */ ++#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */ ++#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */ ++#define SDIO_SPEC_VERSION_3_0 0x40 /* SDIO spec version 3.0 */ ++ ++/* sd_rev */ ++#define SD_REV_PHY_MASK 0x0f /* SD format version number */ ++ ++/* io_en */ ++#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */ ++#define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */ ++#if defined(BT_OVER_SDIO) ++#define SDIO_FUNC_ENABLE_3 0x08 /* function 2 I/O enable */ ++#define SDIO_FUNC_DISABLE_3 0xF0 /* function 2 I/O enable */ ++#endif /* defined (BT_OVER_SDIO) */ ++ ++/* io_rdys */ ++#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */ ++#define SDIO_FUNC_READY_2 0x04 /* function 2 I/O ready */ ++ ++/* intr_ctl */ ++#define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */ ++#define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */ ++#define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */ ++#if defined(BT_OVER_SDIO) ++#define INTR_CTL_FUNC3_EN 0x8 /* interrupt enable for function 3 */ ++#endif /* defined (BT_OVER_SDIO) */ ++/* intr_status */ ++#define INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */ ++#define INTR_STATUS_FUNC2 0x4 /* interrupt pending for function 2 */ ++ ++/* io_abort */ ++#define IO_ABORT_RESET_ALL 0x08 /* I/O card reset */ ++#define IO_ABORT_FUNC_MASK 0x07 /* abort selction: function x */ ++ ++/* bus_inter */ ++#define BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */ ++#define BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */ ++#define BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */ ++#define BUS_SD_DATA_WIDTH_MASK 0x03 /* bus width mask */ ++#define BUS_SD_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */ ++#define BUS_SD_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */ ++ ++/* capability */ ++#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */ ++#define SDIO_CAP_LSC 0x40 /* low speed card */ ++#define SDIO_CAP_E4MI 0x20 /* enable interrupt between block of data in 4-bit mode */ ++#define SDIO_CAP_S4MI 0x10 /* support interrupt between block of data in 4-bit mode */ ++#define SDIO_CAP_SBS 0x08 /* support suspend/resume */ ++#define SDIO_CAP_SRW 0x04 /* support read wait */ ++#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */ ++#define SDIO_CAP_SDC 0x01 /* Support Direct commands during multi-byte transfer */ ++ ++/* power_control */ ++#define SDIO_POWER_SMPC 0x01 /* supports master power control (RO) */ ++#define SDIO_POWER_EMPC 0x02 /* enable master power control (allow > 200mA) (RW) */ ++ ++/* speed_control (control device entry into high-speed clocking mode) */ ++#define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */ ++#define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */ ++#define SDIO_SPEED_UHSI_DDR50 0x08 ++ ++/* for setting bus speed in card: 0x13h */ ++#define SDIO_BUS_SPEED_UHSISEL_M BITFIELD_MASK(3) ++#define SDIO_BUS_SPEED_UHSISEL_S 1 ++ ++/* for getting bus speed cap in card: 0x14h */ ++#define SDIO_BUS_SPEED_UHSICAP_M BITFIELD_MASK(3) ++#define SDIO_BUS_SPEED_UHSICAP_S 0 ++ ++/* for getting driver type CAP in card: 0x15h */ ++#define SDIO_BUS_DRVR_TYPE_CAP_M BITFIELD_MASK(3) ++#define SDIO_BUS_DRVR_TYPE_CAP_S 0 ++ ++/* for setting driver type selection in card: 0x15h */ ++#define SDIO_BUS_DRVR_TYPE_SEL_M BITFIELD_MASK(2) ++#define SDIO_BUS_DRVR_TYPE_SEL_S 4 ++ ++/* for getting async int support in card: 0x16h */ ++#define SDIO_BUS_ASYNCINT_CAP_M BITFIELD_MASK(1) ++#define SDIO_BUS_ASYNCINT_CAP_S 0 ++ ++/* for setting async int selection in card: 0x16h */ ++#define SDIO_BUS_ASYNCINT_SEL_M BITFIELD_MASK(1) ++#define SDIO_BUS_ASYNCINT_SEL_S 1 ++ ++/* brcm sepint */ ++#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */ ++#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */ ++#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */ ++ ++/* FBR structure for function 1-7, FBR addresses and register offsets */ ++typedef volatile struct { ++ uint8 devctr; /* device interface, CSA control */ ++ uint8 ext_dev; /* extended standard I/O device type code */ ++ uint8 pwr_sel; /* power selection support */ ++ uint8 PAD[6]; /* reserved */ ++ ++ uint8 cis_low; /* CIS LSB */ ++ uint8 cis_mid; ++ uint8 cis_high; /* CIS MSB */ ++ uint8 csa_low; /* code storage area, LSB */ ++ uint8 csa_mid; ++ uint8 csa_high; /* code storage area, MSB */ ++ uint8 csa_dat_win; /* data access window to function */ ++ ++ uint8 fnx_blk_size[2]; /* block size, little endian */ ++} sdio_fbr_t; ++ ++/* Maximum number of I/O funcs */ ++#define SDIOD_MAX_FUNCS 8 ++#define SDIOD_MAX_IOFUNCS 7 ++ ++/* SDIO Device FBR Start Address */ ++#define SDIOD_FBR_STARTADDR 0x100 ++ ++/* SDIO Device FBR Size */ ++#define SDIOD_FBR_SIZE 0x100 ++ ++/* Macro to calculate FBR register base */ ++#define SDIOD_FBR_BASE(n) ((n) * 0x100) ++ ++/* Function register offsets */ ++#define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */ ++#define SDIOD_FBR_EXT_DEV 0x01 /* extended I/O device code */ ++#define SDIOD_FBR_PWR_SEL 0x02 /* power selection bits */ ++ ++/* SDIO Function CIS ptr offset */ ++#define SDIOD_FBR_CISPTR_0 0x09 ++#define SDIOD_FBR_CISPTR_1 0x0A ++#define SDIOD_FBR_CISPTR_2 0x0B ++ ++/* Code Storage Area pointer */ ++#define SDIOD_FBR_CSA_ADDR_0 0x0C ++#define SDIOD_FBR_CSA_ADDR_1 0x0D ++#define SDIOD_FBR_CSA_ADDR_2 0x0E ++#define SDIOD_FBR_CSA_DATA 0x0F ++ ++/* SDIO Function I/O Block Size */ ++#define SDIOD_FBR_BLKSIZE_0 0x10 ++#define SDIOD_FBR_BLKSIZE_1 0x11 ++ ++/* devctr */ ++#define SDIOD_FBR_DEVCTR_DIC 0x0f /* device interface code */ ++#define SDIOD_FBR_DECVTR_CSA 0x40 /* CSA support flag */ ++#define SDIOD_FBR_DEVCTR_CSA_EN 0x80 /* CSA enabled */ ++/* interface codes */ ++#define SDIOD_DIC_NONE 0 /* SDIO standard interface is not supported */ ++#define SDIOD_DIC_UART 1 ++#define SDIOD_DIC_BLUETOOTH_A 2 ++#define SDIOD_DIC_BLUETOOTH_B 3 ++#define SDIOD_DIC_GPS 4 ++#define SDIOD_DIC_CAMERA 5 ++#define SDIOD_DIC_PHS 6 ++#define SDIOD_DIC_WLAN 7 ++#define SDIOD_DIC_EXT 0xf /* extended device interface, read ext_dev register */ ++ ++/* pwr_sel */ ++#define SDIOD_PWR_SEL_SPS 0x01 /* supports power selection */ ++#define SDIOD_PWR_SEL_EPS 0x02 /* enable power selection (low-current mode) */ ++ ++/* misc defines */ ++#define SDIO_FUNC_0 0 ++#define SDIO_FUNC_1 1 ++#define SDIO_FUNC_2 2 ++#define SDIO_FUNC_4 4 ++#define SDIO_FUNC_5 5 ++#define SDIO_FUNC_6 6 ++#define SDIO_FUNC_7 7 ++ ++#define SD_CARD_TYPE_UNKNOWN 0 /* bad type or unrecognized */ ++#define SD_CARD_TYPE_IO 1 /* IO only card */ ++#define SD_CARD_TYPE_MEMORY 2 /* memory only card */ ++#define SD_CARD_TYPE_COMBO 3 /* IO and memory combo card */ ++ ++#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size for block mode operation */ ++#define SDIO_MIN_BLOCK_SIZE 1 /* minimum block size for block mode operation */ ++ ++/* Card registers: status bit position */ ++#define CARDREG_STATUS_BIT_OUTOFRANGE 31 ++#define CARDREG_STATUS_BIT_COMCRCERROR 23 ++#define CARDREG_STATUS_BIT_ILLEGALCOMMAND 22 ++#define CARDREG_STATUS_BIT_ERROR 19 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE3 12 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE2 11 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE1 10 ++#define CARDREG_STATUS_BIT_IOCURRENTSTATE0 9 ++#define CARDREG_STATUS_BIT_FUN_NUM_ERROR 4 ++ ++ ++ ++#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */ ++#define SD_CMD_SEND_OPCOND 1 ++#define SD_CMD_MMC_SET_RCA 3 ++#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */ ++#define SD_CMD_SELECT_DESELECT_CARD 7 ++#define SD_CMD_SEND_CSD 9 ++#define SD_CMD_SEND_CID 10 ++#define SD_CMD_STOP_TRANSMISSION 12 ++#define SD_CMD_SEND_STATUS 13 ++#define SD_CMD_GO_INACTIVE_STATE 15 ++#define SD_CMD_SET_BLOCKLEN 16 ++#define SD_CMD_READ_SINGLE_BLOCK 17 ++#define SD_CMD_READ_MULTIPLE_BLOCK 18 ++#define SD_CMD_WRITE_BLOCK 24 ++#define SD_CMD_WRITE_MULTIPLE_BLOCK 25 ++#define SD_CMD_PROGRAM_CSD 27 ++#define SD_CMD_SET_WRITE_PROT 28 ++#define SD_CMD_CLR_WRITE_PROT 29 ++#define SD_CMD_SEND_WRITE_PROT 30 ++#define SD_CMD_ERASE_WR_BLK_START 32 ++#define SD_CMD_ERASE_WR_BLK_END 33 ++#define SD_CMD_ERASE 38 ++#define SD_CMD_LOCK_UNLOCK 42 ++#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */ ++#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */ ++#define SD_CMD_APP_CMD 55 ++#define SD_CMD_GEN_CMD 56 ++#define SD_CMD_READ_OCR 58 ++#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */ ++#define SD_ACMD_SD_STATUS 13 ++#define SD_ACMD_SEND_NUM_WR_BLOCKS 22 ++#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23 ++#define SD_ACMD_SD_SEND_OP_COND 41 ++#define SD_ACMD_SET_CLR_CARD_DETECT 42 ++#define SD_ACMD_SEND_SCR 51 ++ ++/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */ ++#define SD_IO_OP_READ 0 /* Read_Write: Read */ ++#define SD_IO_OP_WRITE 1 /* Read_Write: Write */ ++#define SD_IO_RW_NORMAL 0 /* no RAW */ ++#define SD_IO_RW_RAW 1 /* RAW */ ++#define SD_IO_BYTE_MODE 0 /* Byte Mode */ ++#define SD_IO_BLOCK_MODE 1 /* BlockMode */ ++#define SD_IO_FIXED_ADDRESS 0 /* fix Address */ ++#define SD_IO_INCREMENT_ADDRESS 1 /* IncrementAddress */ ++ ++/* build SD_CMD_IO_RW_DIRECT Argument */ ++#define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \ ++ ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \ ++ (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF)) ++ ++/* build SD_CMD_IO_RW_EXTENDED Argument */ ++#define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \ ++ ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \ ++ (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF)) ++ ++/* SDIO response parameters */ ++#define SD_RSP_NO_NONE 0 ++#define SD_RSP_NO_1 1 ++#define SD_RSP_NO_2 2 ++#define SD_RSP_NO_3 3 ++#define SD_RSP_NO_4 4 ++#define SD_RSP_NO_5 5 ++#define SD_RSP_NO_6 6 ++ ++ /* Modified R6 response (to CMD3) */ ++#define SD_RSP_MR6_COM_CRC_ERROR 0x8000 ++#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000 ++#define SD_RSP_MR6_ERROR 0x2000 ++ ++ /* Modified R1 in R4 Response (to CMD5) */ ++#define SD_RSP_MR1_SBIT 0x80 ++#define SD_RSP_MR1_PARAMETER_ERROR 0x40 ++#define SD_RSP_MR1_RFU5 0x20 ++#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10 ++#define SD_RSP_MR1_COM_CRC_ERROR 0x08 ++#define SD_RSP_MR1_ILLEGAL_COMMAND 0x04 ++#define SD_RSP_MR1_RFU1 0x02 ++#define SD_RSP_MR1_IDLE_STATE 0x01 ++ ++ /* R5 response (to CMD52 and CMD53) */ ++#define SD_RSP_R5_COM_CRC_ERROR 0x80 ++#define SD_RSP_R5_ILLEGAL_COMMAND 0x40 ++#define SD_RSP_R5_IO_CURRENTSTATE1 0x20 ++#define SD_RSP_R5_IO_CURRENTSTATE0 0x10 ++#define SD_RSP_R5_ERROR 0x08 ++#define SD_RSP_R5_RFU 0x04 ++#define SD_RSP_R5_FUNC_NUM_ERROR 0x02 ++#define SD_RSP_R5_OUT_OF_RANGE 0x01 ++ ++#define SD_RSP_R5_ERRBITS 0xCB ++ ++ ++/* ------------------------------------------------ ++ * SDIO Commands and responses ++ * ++ * I/O only commands are: ++ * CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53 ++ * ------------------------------------------------ ++ */ ++ ++/* SDIO Commands */ ++#define SDIOH_CMD_0 0 ++#define SDIOH_CMD_3 3 ++#define SDIOH_CMD_5 5 ++#define SDIOH_CMD_7 7 ++#define SDIOH_CMD_11 11 ++#define SDIOH_CMD_14 14 ++#define SDIOH_CMD_15 15 ++#define SDIOH_CMD_19 19 ++#define SDIOH_CMD_52 52 ++#define SDIOH_CMD_53 53 ++#define SDIOH_CMD_59 59 ++ ++/* SDIO Command Responses */ ++#define SDIOH_RSP_NONE 0 ++#define SDIOH_RSP_R1 1 ++#define SDIOH_RSP_R2 2 ++#define SDIOH_RSP_R3 3 ++#define SDIOH_RSP_R4 4 ++#define SDIOH_RSP_R5 5 ++#define SDIOH_RSP_R6 6 ++ ++/* ++ * SDIO Response Error flags ++ */ ++#define SDIOH_RSP5_ERROR_FLAGS 0xCB ++ ++/* ------------------------------------------------ ++ * SDIO Command structures. I/O only commands are: ++ * ++ * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53 ++ * ------------------------------------------------ ++ */ ++ ++#define CMD5_OCR_M BITFIELD_MASK(24) ++#define CMD5_OCR_S 0 ++ ++#define CMD5_S18R_M BITFIELD_MASK(1) ++#define CMD5_S18R_S 24 ++ ++#define CMD7_RCA_M BITFIELD_MASK(16) ++#define CMD7_RCA_S 16 ++ ++#define CMD14_RCA_M BITFIELD_MASK(16) ++#define CMD14_RCA_S 16 ++#define CMD14_SLEEP_M BITFIELD_MASK(1) ++#define CMD14_SLEEP_S 15 ++ ++#define CMD_15_RCA_M BITFIELD_MASK(16) ++#define CMD_15_RCA_S 16 ++ ++#define CMD52_DATA_M BITFIELD_MASK(8) /* Bits [7:0] - Write Data/Stuff bits of CMD52 ++ */ ++#define CMD52_DATA_S 0 ++#define CMD52_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ ++#define CMD52_REG_ADDR_S 9 ++#define CMD52_RAW_M BITFIELD_MASK(1) /* Bit 27 - Read after Write flag */ ++#define CMD52_RAW_S 27 ++#define CMD52_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ ++#define CMD52_FUNCTION_S 28 ++#define CMD52_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ ++#define CMD52_RW_FLAG_S 31 ++ ++ ++#define CMD53_BYTE_BLK_CNT_M BITFIELD_MASK(9) /* Bits [8:0] - Byte/Block Count of CMD53 */ ++#define CMD53_BYTE_BLK_CNT_S 0 ++#define CMD53_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */ ++#define CMD53_REG_ADDR_S 9 ++#define CMD53_OP_CODE_M BITFIELD_MASK(1) /* Bit 26 - R/W Operation Code */ ++#define CMD53_OP_CODE_S 26 ++#define CMD53_BLK_MODE_M BITFIELD_MASK(1) /* Bit 27 - Block Mode */ ++#define CMD53_BLK_MODE_S 27 ++#define CMD53_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */ ++#define CMD53_FUNCTION_S 28 ++#define CMD53_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */ ++#define CMD53_RW_FLAG_S 31 ++ ++/* ------------------------------------------------------ ++ * SDIO Command Response structures for SD1 and SD4 modes ++ * ----------------------------------------------------- ++ */ ++#define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */ ++#define RSP4_IO_OCR_S 0 ++ ++#define RSP4_S18A_M BITFIELD_MASK(1) /* Bits [23:0] - Card's OCR Bits [23:0] */ ++#define RSP4_S18A_S 24 ++ ++#define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */ ++#define RSP4_STUFF_S 24 ++#define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */ ++#define RSP4_MEM_PRESENT_S 27 ++#define RSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [30:28] - Number of I/O funcs */ ++#define RSP4_NUM_FUNCS_S 28 ++#define RSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 31 - SDIO card ready */ ++#define RSP4_CARD_READY_S 31 ++ ++#define RSP6_STATUS_M BITFIELD_MASK(16) /* Bits [15:0] - Card status bits [19,22,23,12:0] ++ */ ++#define RSP6_STATUS_S 0 ++#define RSP6_IO_RCA_M BITFIELD_MASK(16) /* Bits [31:16] - RCA bits[31-16] */ ++#define RSP6_IO_RCA_S 16 ++ ++#define RSP1_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error */ ++#define RSP1_AKE_SEQ_ERROR_S 3 ++#define RSP1_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ ++#define RSP1_APP_CMD_S 5 ++#define RSP1_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data (buff empty) */ ++#define RSP1_READY_FOR_DATA_S 8 ++#define RSP1_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - State of card ++ * when Cmd was received ++ */ ++#define RSP1_CURR_STATE_S 9 ++#define RSP1_EARSE_RESET_M BITFIELD_MASK(1) /* Bit 13 - Erase seq cleared */ ++#define RSP1_EARSE_RESET_S 13 ++#define RSP1_CARD_ECC_DISABLE_M BITFIELD_MASK(1) /* Bit 14 - Card ECC disabled */ ++#define RSP1_CARD_ECC_DISABLE_S 14 ++#define RSP1_WP_ERASE_SKIP_M BITFIELD_MASK(1) /* Bit 15 - Partial blocks erased due to W/P */ ++#define RSP1_WP_ERASE_SKIP_S 15 ++#define RSP1_CID_CSD_OVERW_M BITFIELD_MASK(1) /* Bit 16 - Illegal write to CID or R/O bits ++ * of CSD ++ */ ++#define RSP1_CID_CSD_OVERW_S 16 ++#define RSP1_ERROR_M BITFIELD_MASK(1) /* Bit 19 - General/Unknown error */ ++#define RSP1_ERROR_S 19 ++#define RSP1_CC_ERROR_M BITFIELD_MASK(1) /* Bit 20 - Internal Card Control error */ ++#define RSP1_CC_ERROR_S 20 ++#define RSP1_CARD_ECC_FAILED_M BITFIELD_MASK(1) /* Bit 21 - Card internal ECC failed ++ * to correct data ++ */ ++#define RSP1_CARD_ECC_FAILED_S 21 ++#define RSP1_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 22 - Cmd not legal for the card state */ ++#define RSP1_ILLEGAL_CMD_S 22 ++#define RSP1_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 23 - CRC check of previous command failed ++ */ ++#define RSP1_COM_CRC_ERROR_S 23 ++#define RSP1_LOCK_UNLOCK_FAIL_M BITFIELD_MASK(1) /* Bit 24 - Card lock-unlock Cmd Seq error */ ++#define RSP1_LOCK_UNLOCK_FAIL_S 24 ++#define RSP1_CARD_LOCKED_M BITFIELD_MASK(1) /* Bit 25 - Card locked by the host */ ++#define RSP1_CARD_LOCKED_S 25 ++#define RSP1_WP_VIOLATION_M BITFIELD_MASK(1) /* Bit 26 - Attempt to program ++ * write-protected blocks ++ */ ++#define RSP1_WP_VIOLATION_S 26 ++#define RSP1_ERASE_PARAM_M BITFIELD_MASK(1) /* Bit 27 - Invalid erase blocks */ ++#define RSP1_ERASE_PARAM_S 27 ++#define RSP1_ERASE_SEQ_ERR_M BITFIELD_MASK(1) /* Bit 28 - Erase Cmd seq error */ ++#define RSP1_ERASE_SEQ_ERR_S 28 ++#define RSP1_BLK_LEN_ERR_M BITFIELD_MASK(1) /* Bit 29 - Block length error */ ++#define RSP1_BLK_LEN_ERR_S 29 ++#define RSP1_ADDR_ERR_M BITFIELD_MASK(1) /* Bit 30 - Misaligned address */ ++#define RSP1_ADDR_ERR_S 30 ++#define RSP1_OUT_OF_RANGE_M BITFIELD_MASK(1) /* Bit 31 - Cmd arg was out of range */ ++#define RSP1_OUT_OF_RANGE_S 31 ++ ++ ++#define RSP5_DATA_M BITFIELD_MASK(8) /* Bits [0:7] - data */ ++#define RSP5_DATA_S 0 ++#define RSP5_FLAGS_M BITFIELD_MASK(8) /* Bit [15:8] - Rsp flags */ ++#define RSP5_FLAGS_S 8 ++#define RSP5_STUFF_M BITFIELD_MASK(16) /* Bits [31:16] - Stuff bits */ ++#define RSP5_STUFF_S 16 ++ ++/* ---------------------------------------------- ++ * SDIO Command Response structures for SPI mode ++ * ---------------------------------------------- ++ */ ++#define SPIRSP4_IO_OCR_M BITFIELD_MASK(16) /* Bits [15:0] - Card's OCR Bits [23:8] */ ++#define SPIRSP4_IO_OCR_S 0 ++#define SPIRSP4_STUFF_M BITFIELD_MASK(3) /* Bits [18:16] - Stuff bits */ ++#define SPIRSP4_STUFF_S 16 ++#define SPIRSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 19 - Memory present */ ++#define SPIRSP4_MEM_PRESENT_S 19 ++#define SPIRSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [22:20] - Number of I/O funcs */ ++#define SPIRSP4_NUM_FUNCS_S 20 ++#define SPIRSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 23 - SDIO card ready */ ++#define SPIRSP4_CARD_READY_S 23 ++#define SPIRSP4_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - idle state */ ++#define SPIRSP4_IDLE_STATE_S 24 ++#define SPIRSP4_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ ++#define SPIRSP4_ILLEGAL_CMD_S 26 ++#define SPIRSP4_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ ++#define SPIRSP4_COM_CRC_ERROR_S 27 ++#define SPIRSP4_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error ++ */ ++#define SPIRSP4_FUNC_NUM_ERROR_S 28 ++#define SPIRSP4_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ ++#define SPIRSP4_PARAM_ERROR_S 30 ++#define SPIRSP4_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ ++#define SPIRSP4_START_BIT_S 31 ++ ++#define SPIRSP5_DATA_M BITFIELD_MASK(8) /* Bits [23:16] - R/W Data */ ++#define SPIRSP5_DATA_S 16 ++#define SPIRSP5_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - Idle state */ ++#define SPIRSP5_IDLE_STATE_S 24 ++#define SPIRSP5_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */ ++#define SPIRSP5_ILLEGAL_CMD_S 26 ++#define SPIRSP5_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */ ++#define SPIRSP5_COM_CRC_ERROR_S 27 ++#define SPIRSP5_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error ++ */ ++#define SPIRSP5_FUNC_NUM_ERROR_S 28 ++#define SPIRSP5_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */ ++#define SPIRSP5_PARAM_ERROR_S 30 ++#define SPIRSP5_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */ ++#define SPIRSP5_START_BIT_S 31 ++ ++/* RSP6 card status format; Pg 68 Physical Layer spec v 1.10 */ ++#define RSP6STAT_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error ++ */ ++#define RSP6STAT_AKE_SEQ_ERROR_S 3 ++#define RSP6STAT_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */ ++#define RSP6STAT_APP_CMD_S 5 ++#define RSP6STAT_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data ++ * (buff empty) ++ */ ++#define RSP6STAT_READY_FOR_DATA_S 8 ++#define RSP6STAT_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - Card state at ++ * Cmd reception ++ */ ++#define RSP6STAT_CURR_STATE_S 9 ++#define RSP6STAT_ERROR_M BITFIELD_MASK(1) /* Bit 13 - General/Unknown error Bit 19 ++ */ ++#define RSP6STAT_ERROR_S 13 ++#define RSP6STAT_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 14 - Illegal cmd for ++ * card state Bit 22 ++ */ ++#define RSP6STAT_ILLEGAL_CMD_S 14 ++#define RSP6STAT_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 15 - CRC previous command ++ * failed Bit 23 ++ */ ++#define RSP6STAT_COM_CRC_ERROR_S 15 ++ ++#define SDIOH_XFER_TYPE_READ SD_IO_OP_READ ++#define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE ++ ++/* command issue options */ ++#define CMD_OPTION_DEFAULT 0 ++#define CMD_OPTION_TUNING 1 ++ ++#endif /* def BCMSDIO */ ++#endif /* _SDIO_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sdioh.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sdioh.h +new file mode 100644 +index 000000000..f37c5f62a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sdioh.h +@@ -0,0 +1,448 @@ ++/* ++ * SDIO Host Controller Spec header file ++ * Register map and definitions for the Standard Host Controller ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sdioh.h 514727 2014-11-12 03:02:48Z $ ++ */ ++ ++#ifndef _SDIOH_H ++#define _SDIOH_H ++ ++#define SD_SysAddr 0x000 ++#define SD_BlockSize 0x004 ++#define SD_BlockCount 0x006 ++#define SD_Arg0 0x008 ++#define SD_Arg1 0x00A ++#define SD_TransferMode 0x00C ++#define SD_Command 0x00E ++#define SD_Response0 0x010 ++#define SD_Response1 0x012 ++#define SD_Response2 0x014 ++#define SD_Response3 0x016 ++#define SD_Response4 0x018 ++#define SD_Response5 0x01A ++#define SD_Response6 0x01C ++#define SD_Response7 0x01E ++#define SD_BufferDataPort0 0x020 ++#define SD_BufferDataPort1 0x022 ++#define SD_PresentState 0x024 ++#define SD_HostCntrl 0x028 ++#define SD_PwrCntrl 0x029 ++#define SD_BlockGapCntrl 0x02A ++#define SD_WakeupCntrl 0x02B ++#define SD_ClockCntrl 0x02C ++#define SD_TimeoutCntrl 0x02E ++#define SD_SoftwareReset 0x02F ++#define SD_IntrStatus 0x030 ++#define SD_ErrorIntrStatus 0x032 ++#define SD_IntrStatusEnable 0x034 ++#define SD_ErrorIntrStatusEnable 0x036 ++#define SD_IntrSignalEnable 0x038 ++#define SD_ErrorIntrSignalEnable 0x03A ++#define SD_CMD12ErrorStatus 0x03C ++#define SD_Capabilities 0x040 ++#define SD_Capabilities3 0x044 ++#define SD_MaxCurCap 0x048 ++#define SD_MaxCurCap_Reserved 0x04C ++#define SD_ADMA_ErrStatus 0x054 ++#define SD_ADMA_SysAddr 0x58 ++#define SD_SlotInterruptStatus 0x0FC ++#define SD_HostControllerVersion 0x0FE ++#define SD_GPIO_Reg 0x100 ++#define SD_GPIO_OE 0x104 ++#define SD_GPIO_Enable 0x108 ++ ++/* SD specific registers in PCI config space */ ++#define SD_SlotInfo 0x40 ++ ++/* HC 3.0 specific registers and offsets */ ++#define SD3_HostCntrl2 0x03E ++/* preset regsstart and count */ ++#define SD3_PresetValStart 0x060 ++#define SD3_PresetValCount 8 ++/* preset-indiv regs */ ++#define SD3_PresetVal_init 0x060 ++#define SD3_PresetVal_default 0x062 ++#define SD3_PresetVal_HS 0x064 ++#define SD3_PresetVal_SDR12 0x066 ++#define SD3_PresetVal_SDR25 0x068 ++#define SD3_PresetVal_SDR50 0x06a ++#define SD3_PresetVal_SDR104 0x06c ++#define SD3_PresetVal_DDR50 0x06e ++/* SDIO3.0 Revx specific Registers */ ++#define SD3_Tuning_Info_Register 0x0EC ++#define SD3_WL_BT_reset_register 0x0F0 ++ ++ ++/* preset value indices */ ++#define SD3_PRESETVAL_INITIAL_IX 0 ++#define SD3_PRESETVAL_DESPEED_IX 1 ++#define SD3_PRESETVAL_HISPEED_IX 2 ++#define SD3_PRESETVAL_SDR12_IX 3 ++#define SD3_PRESETVAL_SDR25_IX 4 ++#define SD3_PRESETVAL_SDR50_IX 5 ++#define SD3_PRESETVAL_SDR104_IX 6 ++#define SD3_PRESETVAL_DDR50_IX 7 ++ ++/* SD_Capabilities reg (0x040) */ ++#define CAP_TO_CLKFREQ_M BITFIELD_MASK(6) ++#define CAP_TO_CLKFREQ_S 0 ++#define CAP_TO_CLKUNIT_M BITFIELD_MASK(1) ++#define CAP_TO_CLKUNIT_S 7 ++/* Note: for sdio-2.0 case, this mask has to be 6 bits, but msb 2 ++ bits are reserved. going ahead with 8 bits, as it is req for 3.0 ++*/ ++#define CAP_BASECLK_M BITFIELD_MASK(8) ++#define CAP_BASECLK_S 8 ++#define CAP_MAXBLOCK_M BITFIELD_MASK(2) ++#define CAP_MAXBLOCK_S 16 ++#define CAP_ADMA2_M BITFIELD_MASK(1) ++#define CAP_ADMA2_S 19 ++#define CAP_ADMA1_M BITFIELD_MASK(1) ++#define CAP_ADMA1_S 20 ++#define CAP_HIGHSPEED_M BITFIELD_MASK(1) ++#define CAP_HIGHSPEED_S 21 ++#define CAP_DMA_M BITFIELD_MASK(1) ++#define CAP_DMA_S 22 ++#define CAP_SUSPEND_M BITFIELD_MASK(1) ++#define CAP_SUSPEND_S 23 ++#define CAP_VOLT_3_3_M BITFIELD_MASK(1) ++#define CAP_VOLT_3_3_S 24 ++#define CAP_VOLT_3_0_M BITFIELD_MASK(1) ++#define CAP_VOLT_3_0_S 25 ++#define CAP_VOLT_1_8_M BITFIELD_MASK(1) ++#define CAP_VOLT_1_8_S 26 ++#define CAP_64BIT_HOST_M BITFIELD_MASK(1) ++#define CAP_64BIT_HOST_S 28 ++ ++#define SDIO_OCR_READ_FAIL (2) ++ ++ ++#define CAP_ASYNCINT_SUP_M BITFIELD_MASK(1) ++#define CAP_ASYNCINT_SUP_S 29 ++ ++#define CAP_SLOTTYPE_M BITFIELD_MASK(2) ++#define CAP_SLOTTYPE_S 30 ++ ++#define CAP3_MSBits_OFFSET (32) ++/* note: following are caps MSB32 bits. ++ So the bits start from 0, instead of 32. that is why ++ CAP3_MSBits_OFFSET is subtracted. ++*/ ++#define CAP3_SDR50_SUP_M BITFIELD_MASK(1) ++#define CAP3_SDR50_SUP_S (32 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_SDR104_SUP_M BITFIELD_MASK(1) ++#define CAP3_SDR104_SUP_S (33 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DDR50_SUP_M BITFIELD_MASK(1) ++#define CAP3_DDR50_SUP_S (34 - CAP3_MSBits_OFFSET) ++ ++/* for knowing the clk caps in a single read */ ++#define CAP3_30CLKCAP_M BITFIELD_MASK(3) ++#define CAP3_30CLKCAP_S (32 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DRIVTYPE_A_M BITFIELD_MASK(1) ++#define CAP3_DRIVTYPE_A_S (36 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DRIVTYPE_C_M BITFIELD_MASK(1) ++#define CAP3_DRIVTYPE_C_S (37 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_DRIVTYPE_D_M BITFIELD_MASK(1) ++#define CAP3_DRIVTYPE_D_S (38 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_RETUNING_TC_M BITFIELD_MASK(4) ++#define CAP3_RETUNING_TC_S (40 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_TUNING_SDR50_M BITFIELD_MASK(1) ++#define CAP3_TUNING_SDR50_S (45 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_RETUNING_MODES_M BITFIELD_MASK(2) ++#define CAP3_RETUNING_MODES_S (46 - CAP3_MSBits_OFFSET) ++ ++#define CAP3_CLK_MULT_M BITFIELD_MASK(8) ++#define CAP3_CLK_MULT_S (48 - CAP3_MSBits_OFFSET) ++ ++#define PRESET_DRIVR_SELECT_M BITFIELD_MASK(2) ++#define PRESET_DRIVR_SELECT_S 14 ++ ++#define PRESET_CLK_DIV_M BITFIELD_MASK(10) ++#define PRESET_CLK_DIV_S 0 ++ ++/* SD_MaxCurCap reg (0x048) */ ++#define CAP_CURR_3_3_M BITFIELD_MASK(8) ++#define CAP_CURR_3_3_S 0 ++#define CAP_CURR_3_0_M BITFIELD_MASK(8) ++#define CAP_CURR_3_0_S 8 ++#define CAP_CURR_1_8_M BITFIELD_MASK(8) ++#define CAP_CURR_1_8_S 16 ++ ++/* SD_SysAddr: Offset 0x0000, Size 4 bytes */ ++ ++/* SD_BlockSize: Offset 0x004, Size 2 bytes */ ++#define BLKSZ_BLKSZ_M BITFIELD_MASK(12) ++#define BLKSZ_BLKSZ_S 0 ++#define BLKSZ_BNDRY_M BITFIELD_MASK(3) ++#define BLKSZ_BNDRY_S 12 ++ ++/* SD_BlockCount: Offset 0x006, size 2 bytes */ ++ ++/* SD_Arg0: Offset 0x008, size = 4 bytes */ ++/* SD_TransferMode Offset 0x00C, size = 2 bytes */ ++#define XFER_DMA_ENABLE_M BITFIELD_MASK(1) ++#define XFER_DMA_ENABLE_S 0 ++#define XFER_BLK_COUNT_EN_M BITFIELD_MASK(1) ++#define XFER_BLK_COUNT_EN_S 1 ++#define XFER_CMD_12_EN_M BITFIELD_MASK(1) ++#define XFER_CMD_12_EN_S 2 ++#define XFER_DATA_DIRECTION_M BITFIELD_MASK(1) ++#define XFER_DATA_DIRECTION_S 4 ++#define XFER_MULTI_BLOCK_M BITFIELD_MASK(1) ++#define XFER_MULTI_BLOCK_S 5 ++ ++/* SD_Command: Offset 0x00E, size = 2 bytes */ ++/* resp_type field */ ++#define RESP_TYPE_NONE 0 ++#define RESP_TYPE_136 1 ++#define RESP_TYPE_48 2 ++#define RESP_TYPE_48_BUSY 3 ++/* type field */ ++#define CMD_TYPE_NORMAL 0 ++#define CMD_TYPE_SUSPEND 1 ++#define CMD_TYPE_RESUME 2 ++#define CMD_TYPE_ABORT 3 ++ ++#define CMD_RESP_TYPE_M BITFIELD_MASK(2) /* Bits [0-1] - Response type */ ++#define CMD_RESP_TYPE_S 0 ++#define CMD_CRC_EN_M BITFIELD_MASK(1) /* Bit 3 - CRC enable */ ++#define CMD_CRC_EN_S 3 ++#define CMD_INDEX_EN_M BITFIELD_MASK(1) /* Bit 4 - Enable index checking */ ++#define CMD_INDEX_EN_S 4 ++#define CMD_DATA_EN_M BITFIELD_MASK(1) /* Bit 5 - Using DAT line */ ++#define CMD_DATA_EN_S 5 ++#define CMD_TYPE_M BITFIELD_MASK(2) /* Bit [6-7] - Normal, abort, resume, etc ++ */ ++#define CMD_TYPE_S 6 ++#define CMD_INDEX_M BITFIELD_MASK(6) /* Bits [8-13] - Command number */ ++#define CMD_INDEX_S 8 ++ ++/* SD_BufferDataPort0 : Offset 0x020, size = 2 or 4 bytes */ ++/* SD_BufferDataPort1 : Offset 0x022, size = 2 bytes */ ++/* SD_PresentState : Offset 0x024, size = 4 bytes */ ++#define PRES_CMD_INHIBIT_M BITFIELD_MASK(1) /* Bit 0 May use CMD */ ++#define PRES_CMD_INHIBIT_S 0 ++#define PRES_DAT_INHIBIT_M BITFIELD_MASK(1) /* Bit 1 May use DAT */ ++#define PRES_DAT_INHIBIT_S 1 ++#define PRES_DAT_BUSY_M BITFIELD_MASK(1) /* Bit 2 DAT is busy */ ++#define PRES_DAT_BUSY_S 2 ++#define PRES_PRESENT_RSVD_M BITFIELD_MASK(5) /* Bit [3-7] rsvd */ ++#define PRES_PRESENT_RSVD_S 3 ++#define PRES_WRITE_ACTIVE_M BITFIELD_MASK(1) /* Bit 8 Write is active */ ++#define PRES_WRITE_ACTIVE_S 8 ++#define PRES_READ_ACTIVE_M BITFIELD_MASK(1) /* Bit 9 Read is active */ ++#define PRES_READ_ACTIVE_S 9 ++#define PRES_WRITE_DATA_RDY_M BITFIELD_MASK(1) /* Bit 10 Write buf is avail */ ++#define PRES_WRITE_DATA_RDY_S 10 ++#define PRES_READ_DATA_RDY_M BITFIELD_MASK(1) /* Bit 11 Read buf data avail */ ++#define PRES_READ_DATA_RDY_S 11 ++#define PRES_CARD_PRESENT_M BITFIELD_MASK(1) /* Bit 16 Card present - debounced */ ++#define PRES_CARD_PRESENT_S 16 ++#define PRES_CARD_STABLE_M BITFIELD_MASK(1) /* Bit 17 Debugging */ ++#define PRES_CARD_STABLE_S 17 ++#define PRES_CARD_PRESENT_RAW_M BITFIELD_MASK(1) /* Bit 18 Not debounced */ ++#define PRES_CARD_PRESENT_RAW_S 18 ++#define PRES_WRITE_ENABLED_M BITFIELD_MASK(1) /* Bit 19 Write protected? */ ++#define PRES_WRITE_ENABLED_S 19 ++#define PRES_DAT_SIGNAL_M BITFIELD_MASK(4) /* Bit [20-23] Debugging */ ++#define PRES_DAT_SIGNAL_S 20 ++#define PRES_CMD_SIGNAL_M BITFIELD_MASK(1) /* Bit 24 Debugging */ ++#define PRES_CMD_SIGNAL_S 24 ++ ++/* SD_HostCntrl: Offset 0x028, size = 1 bytes */ ++#define HOST_LED_M BITFIELD_MASK(1) /* Bit 0 LED On/Off */ ++#define HOST_LED_S 0 ++#define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */ ++#define HOST_DATA_WIDTH_S 1 ++#define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */ ++#define HOST_DMA_SEL_S 3 ++#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */ ++#define HOST_HI_SPEED_EN_S 2 ++ ++/* Host Control2: */ ++#define HOSTCtrl2_PRESVAL_EN_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_PRESVAL_EN_S 15 /* bit# */ ++ ++#define HOSTCtrl2_ASYINT_EN_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_ASYINT_EN_S 14 /* bit# */ ++ ++#define HOSTCtrl2_SAMPCLK_SEL_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_SAMPCLK_SEL_S 7 /* bit# */ ++ ++#define HOSTCtrl2_EXEC_TUNING_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_EXEC_TUNING_S 6 /* bit# */ ++ ++#define HOSTCtrl2_DRIVSTRENGTH_SEL_M BITFIELD_MASK(2) /* 2 bit */ ++#define HOSTCtrl2_DRIVSTRENGTH_SEL_S 4 /* bit# */ ++ ++#define HOSTCtrl2_1_8SIG_EN_M BITFIELD_MASK(1) /* 1 bit */ ++#define HOSTCtrl2_1_8SIG_EN_S 3 /* bit# */ ++ ++#define HOSTCtrl2_UHSMODE_SEL_M BITFIELD_MASK(3) /* 3 bit */ ++#define HOSTCtrl2_UHSMODE_SEL_S 0 /* bit# */ ++ ++#define HOST_CONTR_VER_2 (1) ++#define HOST_CONTR_VER_3 (2) ++ ++/* misc defines */ ++#define SD1_MODE 0x1 /* SD Host Cntrlr Spec */ ++#define SD4_MODE 0x2 /* SD Host Cntrlr Spec */ ++ ++/* SD_PwrCntrl: Offset 0x029, size = 1 bytes */ ++#define PWR_BUS_EN_M BITFIELD_MASK(1) /* Bit 0 Power the bus */ ++#define PWR_BUS_EN_S 0 ++#define PWR_VOLTS_M BITFIELD_MASK(3) /* Bit [1-3] Voltage Select */ ++#define PWR_VOLTS_S 1 ++ ++/* SD_SoftwareReset: Offset 0x02F, size = 1 byte */ ++#define SW_RESET_ALL_M BITFIELD_MASK(1) /* Bit 0 Reset All */ ++#define SW_RESET_ALL_S 0 ++#define SW_RESET_CMD_M BITFIELD_MASK(1) /* Bit 1 CMD Line Reset */ ++#define SW_RESET_CMD_S 1 ++#define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */ ++#define SW_RESET_DAT_S 2 ++ ++/* SD_IntrStatus: Offset 0x030, size = 2 bytes */ ++/* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */ ++#define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */ ++#define INTSTAT_CMD_COMPLETE_S 0 ++#define INTSTAT_XFER_COMPLETE_M BITFIELD_MASK(1) ++#define INTSTAT_XFER_COMPLETE_S 1 ++#define INTSTAT_BLOCK_GAP_EVENT_M BITFIELD_MASK(1) ++#define INTSTAT_BLOCK_GAP_EVENT_S 2 ++#define INTSTAT_DMA_INT_M BITFIELD_MASK(1) ++#define INTSTAT_DMA_INT_S 3 ++#define INTSTAT_BUF_WRITE_READY_M BITFIELD_MASK(1) ++#define INTSTAT_BUF_WRITE_READY_S 4 ++#define INTSTAT_BUF_READ_READY_M BITFIELD_MASK(1) ++#define INTSTAT_BUF_READ_READY_S 5 ++#define INTSTAT_CARD_INSERTION_M BITFIELD_MASK(1) ++#define INTSTAT_CARD_INSERTION_S 6 ++#define INTSTAT_CARD_REMOVAL_M BITFIELD_MASK(1) ++#define INTSTAT_CARD_REMOVAL_S 7 ++#define INTSTAT_CARD_INT_M BITFIELD_MASK(1) ++#define INTSTAT_CARD_INT_S 8 ++#define INTSTAT_RETUNING_INT_M BITFIELD_MASK(1) /* Bit 12 */ ++#define INTSTAT_RETUNING_INT_S 12 ++#define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */ ++#define INTSTAT_ERROR_INT_S 15 ++ ++/* SD_ErrorIntrStatus: Offset 0x032, size = 2 bytes */ ++/* Defs also serve SD_ErrorIntrStatusEnable and SD_ErrorIntrSignalEnable */ ++#define ERRINT_CMD_TIMEOUT_M BITFIELD_MASK(1) ++#define ERRINT_CMD_TIMEOUT_S 0 ++#define ERRINT_CMD_CRC_M BITFIELD_MASK(1) ++#define ERRINT_CMD_CRC_S 1 ++#define ERRINT_CMD_ENDBIT_M BITFIELD_MASK(1) ++#define ERRINT_CMD_ENDBIT_S 2 ++#define ERRINT_CMD_INDEX_M BITFIELD_MASK(1) ++#define ERRINT_CMD_INDEX_S 3 ++#define ERRINT_DATA_TIMEOUT_M BITFIELD_MASK(1) ++#define ERRINT_DATA_TIMEOUT_S 4 ++#define ERRINT_DATA_CRC_M BITFIELD_MASK(1) ++#define ERRINT_DATA_CRC_S 5 ++#define ERRINT_DATA_ENDBIT_M BITFIELD_MASK(1) ++#define ERRINT_DATA_ENDBIT_S 6 ++#define ERRINT_CURRENT_LIMIT_M BITFIELD_MASK(1) ++#define ERRINT_CURRENT_LIMIT_S 7 ++#define ERRINT_AUTO_CMD12_M BITFIELD_MASK(1) ++#define ERRINT_AUTO_CMD12_S 8 ++#define ERRINT_VENDOR_M BITFIELD_MASK(4) ++#define ERRINT_VENDOR_S 12 ++#define ERRINT_ADMA_M BITFIELD_MASK(1) ++#define ERRINT_ADMA_S 9 ++ ++/* Also provide definitions in "normal" form to allow combined masks */ ++#define ERRINT_CMD_TIMEOUT_BIT 0x0001 ++#define ERRINT_CMD_CRC_BIT 0x0002 ++#define ERRINT_CMD_ENDBIT_BIT 0x0004 ++#define ERRINT_CMD_INDEX_BIT 0x0008 ++#define ERRINT_DATA_TIMEOUT_BIT 0x0010 ++#define ERRINT_DATA_CRC_BIT 0x0020 ++#define ERRINT_DATA_ENDBIT_BIT 0x0040 ++#define ERRINT_CURRENT_LIMIT_BIT 0x0080 ++#define ERRINT_AUTO_CMD12_BIT 0x0100 ++#define ERRINT_ADMA_BIT 0x0200 ++ ++/* Masks to select CMD vs. DATA errors */ ++#define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\ ++ ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT) ++#define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\ ++ ERRINT_DATA_ENDBIT_BIT | ERRINT_ADMA_BIT) ++#define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS) ++ ++/* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */ ++/* SD_ClockCntrl : Offset 0x02C , size = bytes */ ++/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */ ++/* SD_IntrStatus : Offset 0x030 , size = bytes */ ++/* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */ ++/* SD_IntrStatusEnable : Offset 0x034 , size = bytes */ ++/* SD_ErrorIntrStatusEnable : Offset 0x036 , size = bytes */ ++/* SD_IntrSignalEnable : Offset 0x038 , size = bytes */ ++/* SD_ErrorIntrSignalEnable : Offset 0x03A , size = bytes */ ++/* SD_CMD12ErrorStatus : Offset 0x03C , size = bytes */ ++/* SD_Capabilities : Offset 0x040 , size = bytes */ ++/* SD_MaxCurCap : Offset 0x048 , size = bytes */ ++/* SD_MaxCurCap_Reserved: Offset 0x04C , size = bytes */ ++/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */ ++/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */ ++ ++/* SDIO Host Control Register DMA Mode Definitions */ ++#define SDIOH_SDMA_MODE 0 ++#define SDIOH_ADMA1_MODE 1 ++#define SDIOH_ADMA2_MODE 2 ++#define SDIOH_ADMA2_64_MODE 3 ++ ++#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ ++#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ ++#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ ++#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ ++#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ ++#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ ++#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ ++#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ ++ ++/* ADMA2 Descriptor Table Entry for 32-bit Address */ ++typedef struct adma2_dscr_32b { ++ uint32 len_attr; ++ uint32 phys_addr; ++} adma2_dscr_32b_t; ++ ++/* ADMA1 Descriptor Table Entry */ ++typedef struct adma1_dscr { ++ uint32 phys_addr_attr; ++} adma1_dscr_t; ++ ++#endif /* _SDIOH_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sdiovar.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sdiovar.h +new file mode 100644 +index 000000000..719eeb106 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sdiovar.h +@@ -0,0 +1,107 @@ ++/* ++ * Structure used by apps whose drivers access SDIO drivers. ++ * Pulled out separately so dhdu and wlu can both use it. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sdiovar.h 610006 2016-01-06 01:38:47Z $ ++ */ ++ ++#ifndef _sdiovar_h_ ++#define _sdiovar_h_ ++ ++#include ++ ++/* require default structure packing */ ++#define BWL_DEFAULT_PACKING ++#include ++ ++typedef struct sdreg { ++ int func; ++ int offset; ++ int value; ++} sdreg_t; ++ ++/* 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 */ ++#define SDH_COST_VAL 0x8000 /* Control Regs */ ++ ++#define NUM_PREV_TRANSACTIONS 16 ++ ++ ++typedef struct sdio_bus_metrics { ++ uint32 active_dur; /* msecs */ ++ ++ /* Generic */ ++ uint32 data_intr_cnt; /* data interrupt counter */ ++ uint32 mb_intr_cnt; /* mailbox interrupt counter */ ++ uint32 error_intr_cnt; /* error interrupt counter */ ++ uint32 wakehost_cnt; /* counter for OOB wakehost */ ++ ++ /* DS forcewake */ ++ uint32 ds_wake_on_cnt; /* counter for (clock) ON */ ++ uint32 ds_wake_on_dur; /* duration for (clock) ON) */ ++ uint32 ds_wake_off_cnt; /* counter for (clock) OFF */ ++ uint32 ds_wake_off_dur; /* duration for (clock) OFF */ ++ ++ /* DS_D0 state */ ++ uint32 ds_d0_cnt; /* counter for DS_D0 state */ ++ uint32 ds_d0_dur; /* duration for DS_D0 state */ ++ ++ /* DS_D3 state */ ++ uint32 ds_d3_cnt; /* counter for DS_D3 state */ ++ uint32 ds_d3_dur; /* duration for DS_D3 state */ ++ ++ /* DS DEV_WAKE */ ++ uint32 ds_dw_assrt_cnt; /* counter for DW_ASSERT */ ++ uint32 ds_dw_dassrt_cnt; /* counter for DW_DASSERT */ ++ ++ /* DS mailbox signals */ ++ uint32 ds_tx_dsreq_cnt; /* counter for tx HMB_DATA_DSREQ */ ++ uint32 ds_tx_dsexit_cnt; /* counter for tx HMB_DATA_DSEXIT */ ++ uint32 ds_tx_d3ack_cnt; /* counter for tx HMB_DATA_D3ACK */ ++ uint32 ds_tx_d3exit_cnt; /* counter for tx HMB_DATA_D3EXIT */ ++ uint32 ds_rx_dsack_cnt; /* counter for rx SMB_DATA_DSACK */ ++ uint32 ds_rx_dsnack_cnt; /* counter for rx SMB_DATA_DSNACK */ ++ uint32 ds_rx_d3inform_cnt; /* counter for rx SMB_DATA_D3INFORM */ ++} sdio_bus_metrics_t; ++ ++/* Bus interface info for SDIO */ ++typedef struct wl_pwr_sdio_stats { ++ uint16 type; /* WL_PWRSTATS_TYPE_SDIO */ ++ uint16 len; /* Up to 4K-1, top 4 bits are reserved */ ++ ++ sdio_bus_metrics_t sdio; /* stats from SDIO bus driver */ ++} wl_pwr_sdio_stats_t; ++ ++#include ++ ++#endif /* _sdiovar_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/sdspi.h b/module_drivers/drivers/net/wireless/bcmdhd/include/sdspi.h +new file mode 100644 +index 000000000..c5b8aff22 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/sdspi.h +@@ -0,0 +1,78 @@ ++/* ++ * SD-SPI Protocol Standard ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sdspi.h 700076 2017-05-17 14:42:22Z $ ++ */ ++#ifndef _SD_SPI_H ++#define _SD_SPI_H ++ ++#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */ ++#define SPI_START_S 31 ++#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */ ++#define SPI_DIR_S 30 ++#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */ ++#define SPI_CMD_INDEX_S 24 ++#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */ ++#define SPI_RW_S 23 ++#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */ ++#define SPI_FUNC_S 20 ++#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */ ++#define SPI_RAW_S 19 ++#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */ ++#define SPI_STUFF_S 18 ++#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */ ++#define SPI_BLKMODE_S 19 ++#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */ ++#define SPI_OPCODE_S 18 ++#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */ ++#define SPI_ADDR_S 1 ++#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */ ++#define SPI_STUFF0_S 0 ++ ++#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */ ++#define SPI_RSP_START_S 7 ++#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */ ++#define SPI_RSP_PARAM_ERR_S 6 ++#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */ ++#define SPI_RSP_RFU5_S 5 ++#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */ ++#define SPI_RSP_FUNC_ERR_S 4 ++#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */ ++#define SPI_RSP_CRC_ERR_S 3 ++#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */ ++#define SPI_RSP_ILL_CMD_S 2 ++#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */ ++#define SPI_RSP_RFU1_S 1 ++#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */ ++#define SPI_RSP_IDLE_S 0 ++ ++/* SD-SPI Protocol Definitions */ ++#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */ ++#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */ ++#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */ ++#define SDSPI_START_BIT_MASK 0x80 ++ ++#endif /* _SD_SPI_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/siutils.h b/module_drivers/drivers/net/wireless/bcmdhd/include/siutils.h +new file mode 100644 +index 000000000..2afca2549 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/siutils.h +@@ -0,0 +1,729 @@ ++/* ++ * Misc utility routines for accessing the SOC Interconnects ++ * of Broadcom HNBU chips. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: siutils.h 668442 2016-11-03 08:42:43Z $ ++ */ ++ ++#ifndef _siutils_h_ ++#define _siutils_h_ ++ ++#ifdef SR_DEBUG ++#include "wlioctl.h" ++#endif /* SR_DEBUG */ ++ ++ ++#define WARM_BOOT 0xA0B0C0D0 ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ ++#define SI_MAX_ERRLOG_SIZE 4 ++typedef struct si_axi_error ++{ ++ uint32 error; ++ uint32 coreid; ++ uint32 errlog_lo; ++ uint32 errlog_hi; ++ uint32 errlog_id; ++ uint32 errlog_flags; ++ uint32 errlog_status; ++} si_axi_error_t; ++ ++typedef struct si_axi_error_info ++{ ++ uint32 count; ++ si_axi_error_t axi_error[SI_MAX_ERRLOG_SIZE]; ++} si_axi_error_info_t; ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++/** ++ * Data structure to export all chip specific common variables ++ * public (read-only) portion of siutils handle returned by si_attach()/si_kattach() ++ */ ++struct si_pub { ++ uint socitype; /**< SOCI_SB, SOCI_AI */ ++ ++ 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 */ ++ uint32 cccaps; /**< chip common capabilities */ ++ uint32 cccaps_ext; /**< chip common capabilities extension */ ++ int pmurev; /**< pmu core rev */ ++ uint32 pmucaps; /**< pmu capabilities */ ++ uint boardtype; /**< board type */ ++ uint boardrev; /* board rev */ ++ 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 */ ++ uint32 chipst; /**< chip status */ ++ bool issim; /**< chip is in simulation or emulation */ ++ uint socirev; /**< SOC interconnect rev */ ++ bool pci_pr32414; ++ int gcirev; /**< gci core rev */ ++#ifdef BCM_BACKPLANE_TIMEOUT ++ si_axi_error_info_t * err_info; ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++}; ++ ++/* for HIGH_ONLY driver, the si_t must be writable to allow states sync from BMAC to HIGH driver ++ * for monolithic driver, it is readonly to prevent accident change ++ */ ++typedef const struct si_pub si_t; ++ ++/* ++ * 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 SI_OSH NULL /**< Use for si_kattach when no osh is available */ ++ ++#define BADIDX (SI_MAXCORES + 1) ++ ++/* clkctl xtal what flags */ ++#define XTAL 0x1 /**< primary crystal oscillator (2050) */ ++#define PLL 0x2 /**< main chip pll */ ++ ++/* clkctl clk mode */ ++#define CLK_FAST 0 /**< force fast (pll) clock */ ++#define CLK_DYNAMIC 2 /**< enable dynamic clock control */ ++ ++/* GPIO usage priorities */ ++#define GPIO_DRV_PRIORITY 0 /**< Driver */ ++#define GPIO_APP_PRIORITY 1 /**< Application */ ++#define GPIO_HI_PRIORITY 2 /**< Highest priority. Ignore GPIO reservation */ ++ ++/* GPIO pull up/down */ ++#define GPIO_PULLUP 0 ++#define GPIO_PULLDN 1 ++ ++/* GPIO event regtype */ ++#define GPIO_REGEVT 0 /**< GPIO register event */ ++#define GPIO_REGEVT_INTMSK 1 /**< GPIO register event int mask */ ++#define GPIO_REGEVT_INTPOL 2 /**< GPIO register event int polarity */ ++ ++/* device path */ ++#define SI_DEVPATH_BUFSZ 16 /**< min buffer size in bytes */ ++ ++/* SI routine enumeration: to be used by update function with multiple hooks */ ++#define SI_DOATTACH 1 ++#define SI_PCIDOWN 2 /**< wireless interface is down */ ++#define SI_PCIUP 3 /**< wireless interface is up */ ++ ++#ifdef SR_DEBUG ++#define PMU_RES 31 ++#endif /* SR_DEBUG */ ++ ++/* "access" param defines for si_seci_access() below */ ++#define SECI_ACCESS_STATUSMASK_SET 0 ++#define SECI_ACCESS_INTRS 1 ++#define SECI_ACCESS_UART_CTS 2 ++#define SECI_ACCESS_UART_RTS 3 ++#define SECI_ACCESS_UART_RXEMPTY 4 ++#define SECI_ACCESS_UART_GETC 5 ++#define SECI_ACCESS_UART_TXFULL 6 ++#define SECI_ACCESS_UART_PUTC 7 ++#define SECI_ACCESS_STATUSMASK_GET 8 ++ ++#define ISSIM_ENAB(sih) FALSE ++ ++#define INVALID_ADDR (~0) ++ ++/* PMU clock/power control */ ++#if defined(BCMPMUCTL) ++#define PMUCTL_ENAB(sih) (BCMPMUCTL) ++#else ++#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU) ++#endif ++ ++#if defined(BCMAOBENAB) ++#define AOB_ENAB(sih) (BCMAOBENAB) ++#else ++#define AOB_ENAB(sih) ((sih)->ccrev >= 35 ? \ ++ ((sih)->cccaps_ext & CC_CAP_EXT_AOB_PRESENT) : 0) ++#endif /* BCMAOBENAB */ ++ ++/* 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 (*gci_gpio_handler_t)(uint32 stat, void *arg); ++ ++/* External BT Coex enable mask */ ++#define CC_BTCOEX_EN_MASK 0x01 ++/* External PA enable mask */ ++#define GPIO_CTRL_EPA_EN_MASK 0x40 ++/* WL/BT control enable mask */ ++#define GPIO_CTRL_5_6_EN_MASK 0x60 ++#define GPIO_CTRL_7_6_EN_MASK 0xC0 ++#define GPIO_OUT_7_EN_MASK 0x80 ++ ++ ++ ++/* CR4 specific defines used by the host driver */ ++#define SI_CR4_CAP (0x04) ++#define SI_CR4_BANKIDX (0x40) ++#define SI_CR4_BANKINFO (0x44) ++#define SI_CR4_BANKPDA (0x4C) ++ ++#define ARMCR4_TCBBNB_MASK 0xf0 ++#define ARMCR4_TCBBNB_SHIFT 4 ++#define ARMCR4_TCBANB_MASK 0xf ++#define ARMCR4_TCBANB_SHIFT 0 ++ ++#define SICF_CPUHALT (0x0020) ++#define ARMCR4_BSZ_MASK 0x3f ++#define ARMCR4_BSZ_MULT 8192 ++#define SI_BPIND_1BYTE 0x1 ++#define SI_BPIND_2BYTE 0x3 ++#define SI_BPIND_4BYTE 0xF ++#include ++/* === exported functions === */ ++extern si_t *si_attach(uint pcidev, osl_t *osh, volatile void *regs, uint bustype, ++ void *sdh, char **vars, uint *varsz); ++extern si_t *si_kattach(osl_t *osh); ++extern void si_detach(si_t *sih); ++extern bool si_pci_war16165(si_t *sih); ++extern volatile void * ++si_d11_switch_addrbase(si_t *sih, uint coreunit); ++extern uint si_corelist(si_t *sih, uint coreid[]); ++extern uint si_coreid(si_t *sih); ++extern uint si_flag(si_t *sih); ++extern uint si_flag_alt(si_t *sih); ++extern uint si_intflag(si_t *sih); ++extern uint si_coreidx(si_t *sih); ++extern uint si_coreunit(si_t *sih); ++extern uint si_corevendor(si_t *sih); ++extern uint si_corerev(si_t *sih); ++extern void *si_osh(si_t *sih); ++extern void si_setosh(si_t *sih, osl_t *osh); ++extern uint si_backplane_access(si_t *sih, uint addr, uint size, ++ uint *val, bool read); ++extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); ++extern uint si_pmu_corereg(si_t *sih, uint32 idx, uint regoff, uint mask, uint val); ++extern volatile uint32 *si_corereg_addr(si_t *sih, uint coreidx, uint regoff); ++extern volatile void *si_coreregs(si_t *sih); ++extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); ++extern uint si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val); ++extern void *si_wrapperregs(si_t *sih); ++extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); ++extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); ++extern void si_commit(si_t *sih); ++extern bool si_iscoreup(si_t *sih); ++extern uint si_numcoreunits(si_t *sih, uint coreid); ++extern uint si_numd11coreunits(si_t *sih); ++extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit); ++extern volatile void *si_setcoreidx(si_t *sih, uint coreidx); ++extern volatile void *si_setcore(si_t *sih, uint coreid, uint coreunit); ++extern volatile void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val); ++extern void si_restore_core(si_t *sih, uint coreid, uint intr_val); ++extern int si_numaddrspaces(si_t *sih); ++extern uint32 si_addrspace(si_t *sih, uint asidx); ++extern uint32 si_addrspacesize(si_t *sih, uint asidx); ++extern void si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); ++extern int si_corebist(si_t *sih); ++extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); ++extern void si_core_disable(si_t *sih, uint32 bits); ++extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); ++extern uint si_chip_hostif(si_t *sih); ++extern bool si_read_pmu_autopll(si_t *sih); ++extern uint32 si_clock(si_t *sih); ++extern uint32 si_alp_clock(si_t *sih); /* returns [Hz] units */ ++extern uint32 si_ilp_clock(si_t *sih); /* returns [Hz] units */ ++extern void si_pci_setup(si_t *sih, uint coremask); ++extern void si_pcmcia_init(si_t *sih); ++extern void si_setint(si_t *sih, int siflag); ++extern bool si_backplane64(si_t *sih); ++extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, ++ void *intrsenabled_fn, void *intr_arg); ++extern void si_deregister_intr_callback(si_t *sih); ++extern void si_clkctl_init(si_t *sih); ++extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); ++extern bool si_clkctl_cc(si_t *sih, uint mode); ++extern int si_clkctl_xtal(si_t *sih, uint what, bool on); ++extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); ++extern void si_btcgpiowar(si_t *sih); ++extern bool si_deviceremoved(si_t *sih); ++extern void si_set_device_removed(si_t *sih, bool status); ++extern uint32 si_sysmem_size(si_t *sih); ++extern uint32 si_socram_size(si_t *sih); ++extern uint32 si_socdevram_size(si_t *sih); ++extern uint32 si_socram_srmem_size(si_t *sih); ++extern void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda); ++extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect, uint8 *remap); ++extern bool si_socdevram_pkg(si_t *sih); ++extern bool si_socdevram_remap_isenb(si_t *sih); ++extern uint32 si_socdevram_remap_size(si_t *sih); ++ ++extern void si_watchdog(si_t *sih, uint ticks); ++extern void si_watchdog_ms(si_t *sih, uint32 ms); ++extern uint32 si_watchdog_msticks(void); ++extern volatile void *si_gpiosetcore(si_t *sih); ++extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioin(si_t *sih); ++extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioeventintmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); ++extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority); ++extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority); ++extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val); ++extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val); ++extern uint32 si_gpio_int_enable(si_t *sih, bool enable); ++extern void si_gci_uart_init(si_t *sih, osl_t *osh, uint8 seci_mode); ++extern void si_gci_enable_gpio(si_t *sih, uint8 gpio, uint32 mask, uint32 value); ++extern uint8 si_gci_host_wake_gpio_init(si_t *sih); ++extern void si_gci_host_wake_gpio_enable(si_t *sih, uint8 gpio, bool state); ++ ++extern void si_invalidate_second_bar0win(si_t *sih); ++ ++/* GCI interrupt handlers */ ++extern void si_gci_handler_process(si_t *sih); ++ ++/* GCI GPIO event handlers */ ++extern void *si_gci_gpioint_handler_register(si_t *sih, uint8 gpio, uint8 sts, ++ gci_gpio_handler_t cb, void *arg); ++extern void si_gci_gpioint_handler_unregister(si_t *sih, void* gci_i); ++extern uint8 si_gci_gpio_status(si_t *sih, uint8 gci_gpio, uint8 mask, uint8 value); ++ ++/* Wake-on-wireless-LAN (WOWL) */ ++extern bool si_pci_pmecap(si_t *sih); ++extern bool si_pci_fastpmecap(struct osl_info *osh); ++extern bool si_pci_pmestat(si_t *sih); ++extern void si_pci_pmeclr(si_t *sih); ++extern void si_pci_pmeen(si_t *sih); ++extern void si_pci_pmestatclr(si_t *sih); ++extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); ++extern uint si_pcie_writereg(void *sih, uint addrtype, uint offset, uint val); ++extern void si_deepsleep_count(si_t *sih, bool arm_wakeup); ++ ++ ++#ifdef BCMSDIO ++extern void si_sdio_init(si_t *sih); ++#endif ++ ++extern uint16 si_d11_devid(si_t *sih); ++extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice, ++ uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader); ++ ++extern uint32 si_seci_access(si_t *sih, uint32 val, int access); ++extern volatile void* si_seci_init(si_t *sih, uint8 seci_mode); ++extern void si_seci_clk_force(si_t *sih, bool val); ++extern bool si_seci_clk_force_status(si_t *sih); ++ ++#define si_eci(sih) 0 ++static INLINE void * si_eci_init(si_t *sih) {return NULL;} ++#define si_eci_notify_bt(sih, type, val) (0) ++#define si_seci(sih) 0 ++#define si_seci_upd(sih, a) do {} while (0) ++static INLINE void * si_gci_init(si_t *sih) {return NULL;} ++#define si_seci_down(sih) do {} while (0) ++#define si_gci(sih) 0 ++ ++/* OTP status */ ++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, uint32* min_res_mask); ++ ++/* SPROM availability */ ++extern bool si_is_sprom_available(si_t *sih); ++ ++/* OTP/SROM CIS stuff */ ++extern int si_cis_source(si_t *sih); ++#define CIS_DEFAULT 0 ++#define CIS_SROM 1 ++#define CIS_OTP 2 ++ ++/* Fab-id information */ ++#define DEFAULT_FAB 0x0 /**< Original/first fab used for this chip */ ++#define CSM_FAB7 0x1 /**< CSM Fab7 chip */ ++#define TSMC_FAB12 0x2 /**< TSMC Fab12/Fab14 chip */ ++#define SMIC_FAB4 0x3 /**< SMIC Fab4 chip */ ++ ++extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw); ++extern uint16 si_fabid(si_t *sih); ++extern uint16 si_chipid(si_t *sih); ++ ++/* ++ * Build device path. Path size must be >= SI_DEVPATH_BUFSZ. ++ * The returned path is NULL terminated and has trailing '/'. ++ * Return 0 on success, nonzero otherwise. ++ */ ++extern int si_devpath(si_t *sih, char *path, int size); ++extern int si_devpath_pcie(si_t *sih, char *path, int size); ++/* Read variable with prepending the devpath to the name */ ++extern char *si_getdevpathvar(si_t *sih, const char *name); ++extern int si_getdevpathintvar(si_t *sih, const char *name); ++extern char *si_coded_devpathvar(si_t *sih, char *varname, int var_len, const char *name); ++ ++ ++extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val); ++extern uint8 si_pcieltrenable(si_t *sih, uint32 mask, uint32 val); ++extern uint8 si_pcieobffenable(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_pcieltr_reg(si_t *sih, uint32 reg, uint32 mask, uint32 val); ++extern uint32 si_pcieltrspacing_reg(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_pcieltrhysteresiscnt_reg(si_t *sih, uint32 mask, uint32 val); ++extern void si_pcie_set_error_injection(si_t *sih, uint32 mode); ++extern void si_pcie_set_L1substate(si_t *sih, uint32 substate); ++extern uint32 si_pcie_get_L1substate(si_t *sih); ++extern void si_war42780_clkreq(si_t *sih, bool clkreq); ++extern void si_pci_down(si_t *sih); ++extern void si_pci_up(si_t *sih); ++extern void si_pci_sleep(si_t *sih); ++extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm); ++extern void si_pcie_power_save_enable(si_t *sih, bool enable); ++extern void si_pcie_extendL1timer(si_t *sih, bool extend); ++extern int si_pci_fixcfg(si_t *sih); ++extern void si_chippkg_set(si_t *sih, uint); ++extern bool si_is_warmboot(void); ++ ++extern void si_chipcontrl_btshd0_4331(si_t *sih, bool on); ++extern void si_chipcontrl_restore(si_t *sih, uint32 val); ++extern uint32 si_chipcontrl_read(si_t *sih); ++extern void si_chipcontrl_epa4331(si_t *sih, bool on); ++extern void si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl); ++extern void si_chipcontrl_srom4360(si_t *sih, bool on); ++extern void si_clk_srom4365(si_t *sih); ++/* Enable BT-COEX & Ex-PA for 4313 */ ++extern void si_epa_4313war(si_t *sih); ++extern void si_btc_enable_chipcontrol(si_t *sih); ++/* BT/WL selection for 4313 bt combo >= P250 boards */ ++extern void si_btcombo_p250_4313_war(si_t *sih); ++extern void si_btcombo_43228_war(si_t *sih); ++extern void si_clk_pmu_htavail_set(si_t *sih, bool set_clear); ++extern void si_pmu_avb_clk_set(si_t *sih, osl_t *osh, bool set_flag); ++extern void si_pmu_synth_pwrsw_4313_war(si_t *sih); ++extern uint si_pll_reset(si_t *sih); ++/* === debug routines === */ ++ ++extern bool si_taclear(si_t *sih, bool details); ++ ++#if defined(BCMDBG_PHYDUMP) ++struct bcmstrbuf; ++extern int si_dump_pcieinfo(si_t *sih, struct bcmstrbuf *b); ++extern void si_dump_pmuregs(si_t *sih, struct bcmstrbuf *b); ++extern int si_dump_pcieregs(si_t *sih, struct bcmstrbuf *b); ++#endif ++ ++#if defined(BCMDBG_PHYDUMP) ++extern void si_dumpregs(si_t *sih, struct bcmstrbuf *b); ++#endif ++ ++extern uint32 si_ccreg(si_t *sih, uint32 offset, uint32 mask, uint32 val); ++extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type); ++extern int si_bpind_access(si_t *sih, uint32 addr_high, uint32 addr_low, ++ int32* data, bool read); ++#ifdef SR_DEBUG ++extern void si_dump_pmu(si_t *sih, void *pmu_var); ++extern void si_pmu_keep_on(si_t *sih, int32 int_val); ++extern uint32 si_pmu_keep_on_get(si_t *sih); ++extern uint32 si_power_island_set(si_t *sih, uint32 int_val); ++extern uint32 si_power_island_get(si_t *sih); ++#endif /* SR_DEBUG */ ++extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val); ++extern void si_pcie_set_request_size(si_t *sih, uint16 size); ++extern uint16 si_pcie_get_request_size(si_t *sih); ++extern void si_pcie_set_maxpayload_size(si_t *sih, uint16 size); ++extern uint16 si_pcie_get_maxpayload_size(si_t *sih); ++extern uint16 si_pcie_get_ssid(si_t *sih); ++extern uint32 si_pcie_get_bar0(si_t *sih); ++extern int si_pcie_configspace_cache(si_t *sih); ++extern int si_pcie_configspace_restore(si_t *sih); ++extern int si_pcie_configspace_get(si_t *sih, uint8 *buf, uint size); ++ ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++extern const si_axi_error_info_t * si_get_axi_errlog_info(si_t *sih); ++extern void si_reset_axi_errlog_info(si_t * sih); ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++extern uint32 si_tcm_size(si_t *sih); ++extern bool si_has_flops(si_t *sih); ++ ++extern int si_set_sromctl(si_t *sih, uint32 value); ++extern uint32 si_get_sromctl(si_t *sih); ++ ++extern uint32 si_gci_direct(si_t *sih, uint offset, uint32 mask, uint32 val); ++extern uint32 si_gci_indirect(si_t *sih, uint regidx, uint offset, uint32 mask, uint32 val); ++extern uint32 si_gci_output(si_t *sih, uint reg, uint32 mask, uint32 val); ++extern uint32 si_gci_input(si_t *sih, uint reg); ++extern uint32 si_gci_int_enable(si_t *sih, bool enable); ++extern void si_gci_reset(si_t *sih); ++#ifdef BCMLTECOEX ++extern void si_gci_seci_init(si_t *sih); ++extern void si_ercx_init(si_t *sih, uint32 ltecx_mux, uint32 ltecx_padnum, ++ uint32 ltecx_fnsel, uint32 ltecx_gcigpio); ++#endif /* BCMLTECOEX */ ++extern void si_wci2_init(si_t *sih, uint8 baudrate, uint32 ltecx_mux, uint32 ltecx_padnum, ++ uint32 ltecx_fnsel, uint32 ltecx_gcigpio); ++ ++extern bool si_btcx_wci2_init(si_t *sih); ++ ++extern void si_gci_set_functionsel(si_t *sih, uint32 pin, uint8 fnsel); ++extern uint32 si_gci_get_functionsel(si_t *sih, uint32 pin); ++extern void si_gci_clear_functionsel(si_t *sih, uint8 fnsel); ++extern uint8 si_gci_get_chipctrlreg_idx(uint32 pin, uint32 *regidx, uint32 *pos); ++extern uint32 si_gci_chipcontrol(si_t *sih, uint reg, uint32 mask, uint32 val); ++extern uint32 si_gci_chipstatus(si_t *sih, uint reg); ++extern uint8 si_enable_device_wake(si_t *sih, uint8 *wake_status, uint8 *cur_status); ++extern void si_swdenable(si_t *sih, uint32 swdflag); ++extern uint8 si_enable_perst_wake(si_t *sih, uint8 *perst_wake_mask, uint8 *perst_cur_status); ++ ++extern uint32 si_get_pmu_reg_addr(si_t *sih, uint32 offset); ++#define CHIPCTRLREG1 0x1 ++#define CHIPCTRLREG2 0x2 ++#define CHIPCTRLREG3 0x3 ++#define CHIPCTRLREG4 0x4 ++#define CHIPCTRLREG5 0x5 ++#define MINRESMASKREG 0x618 ++#define MAXRESMASKREG 0x61c ++#define CHIPCTRLADDR 0x650 ++#define CHIPCTRLDATA 0x654 ++#define RSRCTABLEADDR 0x620 ++#define RSRCUPDWNTIME 0x628 ++#define PMUREG_RESREQ_MASK 0x68c ++ ++void si_update_masks(si_t *sih); ++void si_force_islanding(si_t *sih, bool enable); ++extern uint32 si_pmu_res_req_timer_clr(si_t *sih); ++extern void si_pmu_rfldo(si_t *sih, bool on); ++extern void si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 spert_val); ++extern uint32 si_pcie_set_ctrlreg(si_t *sih, uint32 sperst_mask, uint32 spert_val); ++extern void si_pcie_ltr_war(si_t *sih); ++extern void si_pcie_hw_LTR_war(si_t *sih); ++extern void si_pcie_hw_L1SS_war(si_t *sih); ++extern void si_pciedev_crwlpciegen2(si_t *sih); ++extern void si_pcie_prep_D3(si_t *sih, bool enter_D3); ++extern void si_pciedev_reg_pm_clk_period(si_t *sih); ++extern void si_d11rsdb_core1_alt_reg_clk_dis(si_t *sih); ++extern void si_d11rsdb_core1_alt_reg_clk_en(si_t *sih); ++extern void si_pcie_disable_oobselltr(si_t *sih); ++extern uint32 si_raw_reg(si_t *sih, uint32 reg, uint32 val, uint32 wrire_req); ++ ++#ifdef WLRSDB ++extern void si_d11rsdb_core_disable(si_t *sih, uint32 bits); ++extern void si_d11rsdb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); ++extern void set_secondary_d11_core(si_t *sih, void **secmap, void **secwrap); ++#endif ++ ++ ++/* Macro to enable clock gating changes in different cores */ ++#define MEM_CLK_GATE_BIT 5 ++#define GCI_CLK_GATE_BIT 18 ++ ++#define USBAPP_CLK_BIT 0 ++#define PCIE_CLK_BIT 3 ++#define ARMCR4_DBG_CLK_BIT 4 ++#define SAMPLE_SYNC_CLK_BIT 17 ++#define PCIE_TL_CLK_BIT 18 ++#define HQ_REQ_BIT 24 ++#define PLL_DIV2_BIT_START 9 ++#define PLL_DIV2_MASK (0x37 << PLL_DIV2_BIT_START) ++#define PLL_DIV2_DIS_OP (0x37 << PLL_DIV2_BIT_START) ++ ++#define pmu_corereg(si, cc_idx, member, mask, val) \ ++ (AOB_ENAB(si) ? \ ++ si_pmu_corereg(si, si_findcoreidx(si, PMU_CORE_ID, 0), \ ++ OFFSETOF(pmuregs_t, member), mask, val): \ ++ si_pmu_corereg(si, cc_idx, OFFSETOF(chipcregs_t, member), mask, val)) ++ ++/* Used only for the regs present in the pmu core and not present in the old cc core */ ++#define PMU_REG_NEW(si, member, mask, val) \ ++ si_corereg(si, si_findcoreidx(si, PMU_CORE_ID, 0), \ ++ OFFSETOF(pmuregs_t, member), mask, val) ++ ++#define PMU_REG(si, member, mask, val) \ ++ (AOB_ENAB(si) ? \ ++ si_corereg(si, si_findcoreidx(si, PMU_CORE_ID, 0), \ ++ OFFSETOF(pmuregs_t, member), mask, val): \ ++ si_corereg(si, SI_CC_IDX, OFFSETOF(chipcregs_t, member), mask, val)) ++ ++#define LHL_REG(si, member, mask, val) \ ++ si_corereg(si, si_findcoreidx(si, GCI_CORE_ID, 0), \ ++ OFFSETOF(gciregs_t, member), mask, val) ++ ++#define CHIPC_REG(si, member, mask, val) \ ++ si_corereg(si, SI_CC_IDX, OFFSETOF(chipcregs_t, member), mask, val) ++ ++/* GCI Macros */ ++#define ALLONES_32 0xFFFFFFFF ++#define GCI_CCTL_SECIRST_OFFSET 0 /**< SeciReset */ ++#define GCI_CCTL_RSTSL_OFFSET 1 /**< ResetSeciLogic */ ++#define GCI_CCTL_SECIEN_OFFSET 2 /**< EnableSeci */ ++#define GCI_CCTL_FSL_OFFSET 3 /**< ForceSeciOutLow */ ++#define GCI_CCTL_SMODE_OFFSET 4 /**< SeciOpMode, 6:4 */ ++#define GCI_CCTL_US_OFFSET 7 /**< UpdateSeci */ ++#define GCI_CCTL_BRKONSLP_OFFSET 8 /**< BreakOnSleep */ ++#define GCI_CCTL_SILOWTOUT_OFFSET 9 /**< SeciInLowTimeout, 10:9 */ ++#define GCI_CCTL_RSTOCC_OFFSET 11 /**< ResetOffChipCoex */ ++#define GCI_CCTL_ARESEND_OFFSET 12 /**< AutoBTSigResend */ ++#define GCI_CCTL_FGCR_OFFSET 16 /**< ForceGciClkReq */ ++#define GCI_CCTL_FHCRO_OFFSET 17 /**< ForceHWClockReqOff */ ++#define GCI_CCTL_FREGCLK_OFFSET 18 /**< ForceRegClk */ ++#define GCI_CCTL_FSECICLK_OFFSET 19 /**< ForceSeciClk */ ++#define GCI_CCTL_FGCA_OFFSET 20 /**< ForceGciClkAvail */ ++#define GCI_CCTL_FGCAV_OFFSET 21 /**< ForceGciClkAvailValue */ ++#define GCI_CCTL_SCS_OFFSET 24 /**< SeciClkStretch, 31:24 */ ++ ++#define GCI_MODE_UART 0x0 ++#define GCI_MODE_SECI 0x1 ++#define GCI_MODE_BTSIG 0x2 ++#define GCI_MODE_GPIO 0x3 ++#define GCI_MODE_MASK 0x7 ++ ++#define GCI_CCTL_LOWTOUT_DIS 0x0 ++#define GCI_CCTL_LOWTOUT_10BIT 0x1 ++#define GCI_CCTL_LOWTOUT_20BIT 0x2 ++#define GCI_CCTL_LOWTOUT_30BIT 0x3 ++#define GCI_CCTL_LOWTOUT_MASK 0x3 ++ ++#define GCI_CCTL_SCS_DEF 0x19 ++#define GCI_CCTL_SCS_MASK 0xFF ++ ++#define GCI_SECIIN_MODE_OFFSET 0 ++#define GCI_SECIIN_GCIGPIO_OFFSET 4 ++#define GCI_SECIIN_RXID2IP_OFFSET 8 ++ ++#define GCI_SECIOUT_MODE_OFFSET 0 ++#define GCI_SECIOUT_GCIGPIO_OFFSET 4 ++#define GCI_SECIOUT_LOOPBACK_OFFSET 8 ++#define GCI_SECIOUT_SECIINRELATED_OFFSET 16 ++ ++#define GCI_SECIAUX_RXENABLE_OFFSET 0 ++#define GCI_SECIFIFO_RXENABLE_OFFSET 16 ++ ++#define GCI_SECITX_ENABLE_OFFSET 0 ++ ++#define GCI_GPIOCTL_INEN_OFFSET 0 ++#define GCI_GPIOCTL_OUTEN_OFFSET 1 ++#define GCI_GPIOCTL_PDN_OFFSET 4 ++ ++#define GCI_GPIOIDX_OFFSET 16 ++ ++#define GCI_LTECX_SECI_ID 0 /**< SECI port for LTECX */ ++ ++/* To access per GCI bit registers */ ++#define GCI_REG_WIDTH 32 ++ ++/* GCI bit positions */ ++/* GCI [127:000] = WLAN [127:0] */ ++#define GCI_WLAN_IP_ID 0 ++#define GCI_WLAN_BEGIN 0 ++#define GCI_WLAN_PRIO_POS (GCI_WLAN_BEGIN + 4) ++#define GCI_WLAN_PERST_POS (GCI_WLAN_BEGIN + 15) ++ ++/* GCI [639:512] = LTE [127:0] */ ++#define GCI_LTE_IP_ID 4 ++#define GCI_LTE_BEGIN 512 ++#define GCI_LTE_FRAMESYNC_POS (GCI_LTE_BEGIN + 0) ++#define GCI_LTE_RX_POS (GCI_LTE_BEGIN + 1) ++#define GCI_LTE_TX_POS (GCI_LTE_BEGIN + 2) ++#define GCI_LTE_WCI2TYPE_POS (GCI_LTE_BEGIN + 48) ++#define GCI_LTE_WCI2TYPE_MASK 7 ++#define GCI_LTE_AUXRXDVALID_POS (GCI_LTE_BEGIN + 56) ++ ++/* Reg Index corresponding to ECI bit no x of ECI space */ ++#define GCI_REGIDX(x) ((x)/GCI_REG_WIDTH) ++/* Bit offset of ECI bit no x in 32-bit words */ ++#define GCI_BITOFFSET(x) ((x)%GCI_REG_WIDTH) ++ ++/* End - GCI Macros */ ++ ++#ifdef REROUTE_OOBINT ++#define CC_OOB 0x0 ++#define M2MDMA_OOB 0x1 ++#define PMU_OOB 0x2 ++#define D11_OOB 0x3 ++#define SDIOD_OOB 0x4 ++#define WLAN_OOB 0x5 ++#define PMU_OOB_BIT 0x12 ++#endif /* REROUTE_OOBINT */ ++ ++#define GCI_REG(si, offset, mask, val) \ ++ (AOB_ENAB(si) ? \ ++ si_corereg(si, si_findcoreidx(si, GCI_CORE_ID, 0), \ ++ offset, mask, val): \ ++ si_corereg(si, SI_CC_IDX, offset, mask, val)) ++ ++extern void si_pll_sr_reinit(si_t *sih); ++extern void si_pll_closeloop(si_t *sih); ++void si_config_4364_d11_oob(si_t *sih, uint coreid); ++extern void si_update_macclk_mul_fact(si_t *sih, uint mul_fact); ++extern uint32 si_get_macclk_mul_fact(si_t *sih); ++extern void si_gci_set_femctrl(si_t *sih, osl_t *osh, bool set); ++extern void si_gci_set_femctrl_mask_ant01(si_t *sih, osl_t *osh, bool set); ++extern uint si_num_slaveports(si_t *sih, uint coreid); ++extern uint32 si_get_slaveport_addr(si_t *sih, uint asidx, uint core_id, uint coreunit); ++extern uint32 si_get_d11_slaveport_addr(si_t *sih, uint asidx, uint coreunit); ++uint si_introff(si_t *sih); ++void si_intrrestore(si_t *sih, uint intr_val); ++void si_nvram_res_masks(si_t *sih, uint32 *min_mask, uint32 *max_mask); ++uint32 si_xtalfreq(si_t *sih); ++extern uint32 si_wrapper_dump_buf_size(si_t *sih); ++extern uint32 si_wrapper_dump_binary(si_t *sih, uchar *p); ++ ++/* SR Power Control */ ++extern uint32 si_srpwr_request(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_srpwr_stat_spinwait(si_t *sih, uint32 mask, uint32 val); ++extern uint32 si_srpwr_stat(si_t *sih); ++extern uint32 si_srpwr_domain(si_t *sih); ++ ++/* SR Power Control */ ++#ifdef BCMSRPWR ++ /* No capabilities bit so using chipid for now */ ++ #define SRPWR_CAP(sih) (\ ++ (CHIPID(sih->chip) == BCM4347_CHIP_ID) || \ ++ (0)) ++ ++ extern bool _bcmsrpwr; ++ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD) ++ #define SRPWR_ENAB() (_bcmsrpwr) ++ #elif defined(BCMSRPWR_DISABLED) ++ #define SRPWR_ENAB() (0) ++ #else ++ #define SRPWR_ENAB() (1) ++ #endif ++#else ++ #define SRPWR_CAP(sih) (0) ++ #define SRPWR_ENAB() (0) ++#endif /* BCMSRPWR */ ++ ++#endif /* _siutils_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/spid.h b/module_drivers/drivers/net/wireless/bcmdhd/include/spid.h +new file mode 100644 +index 000000000..8fdefa437 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/spid.h +@@ -0,0 +1,168 @@ ++/* ++ * SPI device spec header file ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: spid.h 514727 2014-11-12 03:02:48Z $ ++ */ ++ ++#ifndef _SPI_H ++#define _SPI_H ++ ++/* ++ * Brcm SPI Device Register Map. ++ * ++ */ ++ ++typedef volatile struct { ++ uint8 config; /* 0x00, len, endian, clock, speed, polarity, wakeup */ ++ uint8 response_delay; /* 0x01, read response delay in bytes (corerev < 3) */ ++ uint8 status_enable; /* 0x02, status-enable, intr with status, response_delay ++ * function selection, command/data error check ++ */ ++ uint8 reset_bp; /* 0x03, reset on wlan/bt backplane reset (corerev >= 1) */ ++ uint16 intr_reg; /* 0x04, Intr status register */ ++ uint16 intr_en_reg; /* 0x06, Intr mask register */ ++ uint32 status_reg; /* 0x08, RO, Status bits of last spi transfer */ ++ uint16 f1_info_reg; /* 0x0c, RO, enabled, ready for data transfer, blocksize */ ++ uint16 f2_info_reg; /* 0x0e, RO, enabled, ready for data transfer, blocksize */ ++ uint16 f3_info_reg; /* 0x10, RO, enabled, ready for data transfer, blocksize */ ++ uint32 test_read; /* 0x14, RO 0xfeedbead signature */ ++ uint32 test_rw; /* 0x18, RW */ ++ uint8 resp_delay_f0; /* 0x1c, read resp delay bytes for F0 (corerev >= 3) */ ++ uint8 resp_delay_f1; /* 0x1d, read resp delay bytes for F1 (corerev >= 3) */ ++ uint8 resp_delay_f2; /* 0x1e, read resp delay bytes for F2 (corerev >= 3) */ ++ uint8 resp_delay_f3; /* 0x1f, read resp delay bytes for F3 (corerev >= 3) */ ++} spi_regs_t; ++ ++/* SPI device register offsets */ ++#define SPID_CONFIG 0x00 ++#define SPID_RESPONSE_DELAY 0x01 ++#define SPID_STATUS_ENABLE 0x02 ++#define SPID_RESET_BP 0x03 /* (corerev >= 1) */ ++#define SPID_INTR_REG 0x04 /* 16 bits - Interrupt status */ ++#define SPID_INTR_EN_REG 0x06 /* 16 bits - Interrupt mask */ ++#define SPID_STATUS_REG 0x08 /* 32 bits */ ++#define SPID_F1_INFO_REG 0x0C /* 16 bits */ ++#define SPID_F2_INFO_REG 0x0E /* 16 bits */ ++#define SPID_F3_INFO_REG 0x10 /* 16 bits */ ++#define SPID_TEST_READ 0x14 /* 32 bits */ ++#define SPID_TEST_RW 0x18 /* 32 bits */ ++#define SPID_RESP_DELAY_F0 0x1c /* 8 bits (corerev >= 3) */ ++#define SPID_RESP_DELAY_F1 0x1d /* 8 bits (corerev >= 3) */ ++#define SPID_RESP_DELAY_F2 0x1e /* 8 bits (corerev >= 3) */ ++#define SPID_RESP_DELAY_F3 0x1f /* 8 bits (corerev >= 3) */ ++ ++/* Bit masks for SPID_CONFIG device register */ ++#define WORD_LENGTH_32 0x1 /* 0/1 16/32 bit word length */ ++#define ENDIAN_BIG 0x2 /* 0/1 Little/Big Endian */ ++#define CLOCK_PHASE 0x4 /* 0/1 clock phase delay */ ++#define CLOCK_POLARITY 0x8 /* 0/1 Idle state clock polarity is low/high */ ++#define HIGH_SPEED_MODE 0x10 /* 1/0 High Speed mode / Normal mode */ ++#define INTR_POLARITY 0x20 /* 1/0 Interrupt active polarity is high/low */ ++#define WAKE_UP 0x80 /* 0/1 Wake-up command from Host to WLAN */ ++ ++/* Bit mask for SPID_RESPONSE_DELAY device register */ ++#define RESPONSE_DELAY_MASK 0xFF /* Configurable rd response delay in multiples of 8 bits */ ++ ++/* Bit mask for SPID_STATUS_ENABLE device register */ ++#define STATUS_ENABLE 0x1 /* 1/0 Status sent/not sent to host after read/write */ ++#define INTR_WITH_STATUS 0x2 /* 0/1 Do-not / do-interrupt if status is sent */ ++#define RESP_DELAY_ALL 0x4 /* Applicability of resp delay to F1 or all func's read */ ++#define DWORD_PKT_LEN_EN 0x8 /* Packet len denoted in dwords instead of bytes */ ++#define CMD_ERR_CHK_EN 0x20 /* Command error check enable */ ++#define DATA_ERR_CHK_EN 0x40 /* Data error check enable */ ++ ++/* Bit mask for SPID_RESET_BP device register */ ++#define RESET_ON_WLAN_BP_RESET 0x4 /* enable reset for WLAN backplane */ ++#define RESET_ON_BT_BP_RESET 0x8 /* enable reset for BT backplane */ ++#define RESET_SPI 0x80 /* reset the above enabled logic */ ++ ++/* Bit mask for SPID_INTR_REG device register */ ++#define DATA_UNAVAILABLE 0x0001 /* Requested data not available; Clear by writing a "1" */ ++#define F2_F3_FIFO_RD_UNDERFLOW 0x0002 ++#define F2_F3_FIFO_WR_OVERFLOW 0x0004 ++#define COMMAND_ERROR 0x0008 /* Cleared by writing 1 */ ++#define DATA_ERROR 0x0010 /* Cleared by writing 1 */ ++#define F2_PACKET_AVAILABLE 0x0020 ++#define F3_PACKET_AVAILABLE 0x0040 ++#define F1_OVERFLOW 0x0080 /* Due to last write. Bkplane has pending write requests */ ++#define MISC_INTR0 0x0100 ++#define MISC_INTR1 0x0200 ++#define MISC_INTR2 0x0400 ++#define MISC_INTR3 0x0800 ++#define MISC_INTR4 0x1000 ++#define F1_INTR 0x2000 ++#define F2_INTR 0x4000 ++#define F3_INTR 0x8000 ++ ++/* Bit mask for 32bit SPID_STATUS_REG device register */ ++#define STATUS_DATA_NOT_AVAILABLE 0x00000001 ++#define STATUS_UNDERFLOW 0x00000002 ++#define STATUS_OVERFLOW 0x00000004 ++#define STATUS_F2_INTR 0x00000008 ++#define STATUS_F3_INTR 0x00000010 ++#define STATUS_F2_RX_READY 0x00000020 ++#define STATUS_F3_RX_READY 0x00000040 ++#define STATUS_HOST_CMD_DATA_ERR 0x00000080 ++#define STATUS_F2_PKT_AVAILABLE 0x00000100 ++#define STATUS_F2_PKT_LEN_MASK 0x000FFE00 ++#define STATUS_F2_PKT_LEN_SHIFT 9 ++#define STATUS_F3_PKT_AVAILABLE 0x00100000 ++#define STATUS_F3_PKT_LEN_MASK 0xFFE00000 ++#define STATUS_F3_PKT_LEN_SHIFT 21 ++ ++/* Bit mask for 16 bits SPID_F1_INFO_REG device register */ ++#define F1_ENABLED 0x0001 ++#define F1_RDY_FOR_DATA_TRANSFER 0x0002 ++#define F1_MAX_PKT_SIZE 0x01FC ++ ++/* Bit mask for 16 bits SPID_F2_INFO_REG device register */ ++#define F2_ENABLED 0x0001 ++#define F2_RDY_FOR_DATA_TRANSFER 0x0002 ++#define F2_MAX_PKT_SIZE 0x3FFC ++ ++/* Bit mask for 16 bits SPID_F3_INFO_REG device register */ ++#define F3_ENABLED 0x0001 ++#define F3_RDY_FOR_DATA_TRANSFER 0x0002 ++#define F3_MAX_PKT_SIZE 0x3FFC ++ ++/* Bit mask for 32 bits SPID_TEST_READ device register read in 16bit LE mode */ ++#define TEST_RO_DATA_32BIT_LE 0xFEEDBEAD ++ ++/* Maximum number of I/O funcs */ ++#define SPI_MAX_IOFUNCS 4 ++ ++#define SPI_MAX_PKT_LEN (2048*4) ++ ++/* Misc defines */ ++#define SPI_FUNC_0 0 ++#define SPI_FUNC_1 1 ++#define SPI_FUNC_2 2 ++#define SPI_FUNC_3 3 ++ ++#define WAIT_F2RXFIFORDY 100 ++#define WAIT_F2RXFIFORDY_DELAY 20 ++ ++#endif /* _SPI_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/trxhdr.h b/module_drivers/drivers/net/wireless/bcmdhd/include/trxhdr.h +new file mode 100644 +index 000000000..50cd3c1ac +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/trxhdr.h +@@ -0,0 +1,95 @@ ++/* ++ * TRX image file header format. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: trxhdr.h 520026 2014-12-10 01:29:40Z $ ++ */ ++ ++#ifndef _TRX_HDR_H ++#define _TRX_HDR_H ++ ++#include ++ ++#define TRX_MAGIC 0x30524448 /* "HDR0" */ ++#define TRX_MAX_LEN 0x3B0000 /* Max length */ ++#define TRX_NO_HEADER 1 /* Do not write TRX header */ ++#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ ++#define TRX_EMBED_UCODE 0x8 /* Trx contains embedded ucode image */ ++#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ ++#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ ++#define TRX_BOOTLOADER 0x40 /* the image is a bootloader */ ++ ++#define TRX_V1 1 ++#define TRX_V1_MAX_OFFSETS 3 /* V1: Max number of individual files */ ++ ++#ifndef BCMTRXV2 ++#define TRX_VERSION TRX_V1 /* Version 1 */ ++#define TRX_MAX_OFFSET TRX_V1_MAX_OFFSETS ++#endif ++ ++/* BMAC Host driver/application like bcmdl need to support both Ver 1 as well as ++ * Ver 2 of trx header. To make it generic, trx_header is structure is modified ++ * as below where size of "offsets" field will vary as per the TRX version. ++ * Currently, BMAC host driver and bcmdl are modified to support TRXV2 as well. ++ * To make sure, other applications like "dhdl" which are yet to be enhanced to support ++ * TRXV2 are not broken, new macro and structure defintion take effect only when BCMTRXV2 ++ * is defined. ++ */ ++struct trx_header { ++ uint32 magic; /* "HDR0" */ ++ uint32 len; /* Length of file including header */ ++ uint32 crc32; /* 32-bit CRC from flag_version to end of file */ ++ uint32 flag_version; /* 0:15 flags, 16:31 version */ ++#ifndef BCMTRXV2 ++ uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ ++#else ++ uint32 offsets[1]; /* Offsets of partitions from start of header */ ++#endif ++}; ++ ++#ifdef BCMTRXV2 ++#define TRX_VERSION TRX_V2 /* Version 2 */ ++#define TRX_MAX_OFFSET TRX_V2_MAX_OFFSETS ++ ++#define TRX_V2 2 ++/* V2: Max number of individual files ++ * To support SDR signature + Config data region ++ */ ++#define TRX_V2_MAX_OFFSETS 5 ++#define SIZEOF_TRXHDR_V1 (sizeof(struct trx_header)+(TRX_V1_MAX_OFFSETS-1)*sizeof(uint32)) ++#define SIZEOF_TRXHDR_V2 (sizeof(struct trx_header)+(TRX_V2_MAX_OFFSETS-1)*sizeof(uint32)) ++#define TRX_VER(trx) ((trx)->flag_version>>16) ++#define ISTRX_V1(trx) (TRX_VER(trx) == TRX_V1) ++#define ISTRX_V2(trx) (TRX_VER(trx) == TRX_V2) ++/* For V2, return size of V2 size: others, return V1 size */ ++#define SIZEOF_TRX(trx) (ISTRX_V2(trx) ? SIZEOF_TRXHDR_V2: SIZEOF_TRXHDR_V1) ++#else ++#define SIZEOF_TRX(trx) (sizeof(struct trx_header)) ++#endif /* BCMTRXV2 */ ++ ++/* Compatibility */ ++typedef struct trx_header TRXHDR, *PTRXHDR; ++ ++#endif /* _TRX_HDR_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/typedefs.h b/module_drivers/drivers/net/wireless/bcmdhd/include/typedefs.h +new file mode 100644 +index 000000000..aed3ace91 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/typedefs.h +@@ -0,0 +1,386 @@ ++/* ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: typedefs.h 639587 2016-05-24 06:44:44Z $ ++ */ ++ ++#ifndef _TYPEDEFS_H_ ++#define _TYPEDEFS_H_ ++ ++#if (!defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)) || \ ++ !defined(BWL_NO_INTERNAL_STDLIB_SUPPORT) ++ ++#ifdef SITE_TYPEDEFS ++ ++/* ++ * Define SITE_TYPEDEFS in the compile to include a site-specific ++ * typedef file "site_typedefs.h". ++ * ++ * If SITE_TYPEDEFS is not defined, then the code section below makes ++ * inferences about the compile environment based on defined symbols and ++ * possibly compiler pragmas. ++ * ++ * Following these two sections is the Default Typedefs section. ++ * This section is only processed if USE_TYPEDEF_DEFAULTS is ++ * defined. This section has a default set of typedefs and a few ++ * preprocessor symbols (TRUE, FALSE, NULL, ...). ++ */ ++ ++#include "site_typedefs.h" ++ ++#else ++ ++/* ++ * Infer the compile environment based on preprocessor symbols and pragmas. ++ * Override type definitions as needed, and include configuration-dependent ++ * header files to define types. ++ */ ++ ++#ifdef __cplusplus ++ ++#define TYPEDEF_BOOL ++#ifndef FALSE ++#define FALSE false ++#endif ++#ifndef TRUE ++#define TRUE true ++#endif ++ ++#else /* ! __cplusplus */ ++ ++ ++#endif /* ! __cplusplus */ ++ ++#if defined(__LP64__) ++#define TYPEDEF_UINTPTR ++typedef unsigned long long int uintptr; ++#endif ++ ++ ++ ++ ++/* float_t types conflict with the same typedefs from the standard ANSI-C ++** math.h header file. Don't re-typedef them here. ++*/ ++ ++#if defined(_NEED_SIZE_T_) ++typedef long unsigned int size_t; ++#endif ++ ++ ++ ++ ++ ++#if defined(__sparc__) ++#define TYPEDEF_ULONG ++#endif ++ ++/* ++ * If this is either a Linux hybrid build or the per-port code of a hybrid build ++ * then use the Linux header files to get some of the typedefs. Otherwise, define ++ * them entirely in this file. We can't always define the types because we get ++ * a duplicate typedef error; there is no way to "undefine" a typedef. ++ * We know when it's per-port code because each file defines LINUX_PORT at the top. ++ */ ++#define TYPEDEF_UINT ++#ifndef TARGETENV_android ++#define TYPEDEF_USHORT ++#define TYPEDEF_ULONG ++#endif /* TARGETENV_android */ ++#ifdef __KERNEL__ ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) ++#define TYPEDEF_BOOL ++#endif /* >= 2.6.19 */ ++/* special detection for 2.6.18-128.7.1.0.1.el5 */ ++#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) ++#include ++#ifdef noinline_for_stack ++#define TYPEDEF_BOOL ++#endif ++#endif /* == 2.6.18 */ ++#endif /* __KERNEL__ */ ++ ++ ++/* Do not support the (u)int64 types with strict ansi for GNU C */ ++#if defined(__GNUC__) && defined(__STRICT_ANSI__) ++#define TYPEDEF_INT64 ++#define TYPEDEF_UINT64 ++#endif /* defined(__GNUC__) && defined(__STRICT_ANSI__) */ ++ ++/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode ++ * for signed or unsigned ++ */ ++#if defined(__ICL) ++ ++#define TYPEDEF_INT64 ++ ++#if defined(__STDC__) ++#define TYPEDEF_UINT64 ++#endif ++ ++#endif /* __ICL */ ++ ++#if !defined(__DJGPP__) ++ ++/* pick up ushort & uint from standard types.h */ ++#if defined(__KERNEL__) ++ ++/* See note above */ ++#include /* sys/types.h and linux/types.h are oil and water */ ++ ++#else ++ ++#include ++ ++#endif /* linux && __KERNEL__ */ ++ ++#endif ++ ++ ++/* use the default typedefs in the next section of this file */ ++#define USE_TYPEDEF_DEFAULTS ++ ++#endif /* SITE_TYPEDEFS */ ++ ++ ++/* ++ * Default Typedefs ++ */ ++ ++#ifdef USE_TYPEDEF_DEFAULTS ++#undef USE_TYPEDEF_DEFAULTS ++ ++#ifndef TYPEDEF_BOOL ++typedef /* @abstract@ */ unsigned char bool; ++#endif /* endif TYPEDEF_BOOL */ ++ ++/* define uchar, ushort, uint, ulong */ ++ ++#ifndef TYPEDEF_UCHAR ++typedef unsigned char uchar; ++#endif ++ ++#ifndef TYPEDEF_USHORT ++typedef unsigned short ushort; ++#endif ++ ++#ifndef TYPEDEF_UINT ++typedef unsigned int uint; ++#endif ++ ++#ifndef TYPEDEF_ULONG ++typedef unsigned long ulong; ++#endif ++ ++/* define [u]int8/16/32/64, uintptr */ ++ ++#ifndef TYPEDEF_UINT8 ++typedef unsigned char uint8; ++#endif ++ ++#ifndef TYPEDEF_UINT16 ++typedef unsigned short uint16; ++#endif ++ ++#ifndef TYPEDEF_UINT32 ++typedef unsigned int uint32; ++#endif ++ ++#ifndef TYPEDEF_UINT64 ++typedef unsigned long long uint64; ++#endif ++ ++#ifndef TYPEDEF_UINTPTR ++typedef unsigned int uintptr; ++#endif ++ ++#ifndef TYPEDEF_INT8 ++typedef signed char int8; ++#endif ++ ++#ifndef TYPEDEF_INT16 ++typedef signed short int16; ++#endif ++ ++#ifndef TYPEDEF_INT32 ++typedef signed int int32; ++#endif ++ ++#ifndef TYPEDEF_INT64 ++typedef signed long long int64; ++#endif ++ ++/* define float32/64, float_t */ ++ ++#ifndef TYPEDEF_FLOAT32 ++typedef float float32; ++#endif ++ ++#ifndef TYPEDEF_FLOAT64 ++typedef double float64; ++#endif ++ ++/* ++ * abstracted floating point type allows for compile time selection of ++ * single or double precision arithmetic. Compiling with -DFLOAT32 ++ * selects single precision; the default is double precision. ++ */ ++ ++#ifndef TYPEDEF_FLOAT_T ++ ++#if defined(FLOAT32) ++typedef float32 float_t; ++#else /* default to double precision floating point */ ++typedef float64 float_t; ++#endif ++ ++#endif /* TYPEDEF_FLOAT_T */ ++ ++/* define macro values */ ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 /* TRUE */ ++#endif ++ ++#ifndef NULL ++#define NULL 0 ++#endif ++ ++#ifndef OFF ++#define OFF 0 ++#endif ++ ++#ifndef ON ++#define ON 1 /* ON = 1 */ ++#endif ++ ++#define AUTO (-1) /* Auto = -1 */ ++ ++/* define PTRSZ, INLINE */ ++ ++#ifndef PTRSZ ++#define PTRSZ sizeof(char*) ++#endif ++ ++ ++/* Detect compiler type. */ ++#if defined(__GNUC__) || defined(__lint) ++ #define BWL_COMPILER_GNU ++#elif defined(__CC_ARM) && __CC_ARM ++ #define BWL_COMPILER_ARMCC ++#else ++ #error "Unknown compiler!" ++#endif ++ ++ ++#ifndef INLINE ++ #if defined(BWL_COMPILER_MICROSOFT) ++ #define INLINE __inline ++ #elif defined(BWL_COMPILER_GNU) ++ #define INLINE __inline__ ++ #elif defined(BWL_COMPILER_ARMCC) ++ #define INLINE __inline ++ #else ++ #define INLINE ++ #endif ++#endif /* INLINE */ ++ ++#undef TYPEDEF_BOOL ++#undef TYPEDEF_UCHAR ++#undef TYPEDEF_USHORT ++#undef TYPEDEF_UINT ++#undef TYPEDEF_ULONG ++#undef TYPEDEF_UINT8 ++#undef TYPEDEF_UINT16 ++#undef TYPEDEF_UINT32 ++#undef TYPEDEF_UINT64 ++#undef TYPEDEF_UINTPTR ++#undef TYPEDEF_INT8 ++#undef TYPEDEF_INT16 ++#undef TYPEDEF_INT32 ++#undef TYPEDEF_INT64 ++#undef TYPEDEF_FLOAT32 ++#undef TYPEDEF_FLOAT64 ++#undef TYPEDEF_FLOAT_T ++ ++#endif /* USE_TYPEDEF_DEFAULTS */ ++ ++/* Suppress unused parameter warning */ ++#define UNUSED_PARAMETER(x) (void)(x) ++ ++/* Avoid warning for discarded const or volatile qualifier in special cases (-Wcast-qual) */ ++#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) ++ ++#else ++ ++#include ++#include ++#include ++ ++#ifdef stderr ++#undef stderr ++#define stderr stdout ++#endif ++ ++typedef UINT32 uint; ++typedef UINT64 ulong; ++typedef UINT16 ushort; ++typedef UINT8 uint8; ++typedef UINT16 uint16; ++typedef UINT32 uint32; ++typedef UINT64 uint64; ++typedef INT8 int8; ++typedef INT16 int16; ++typedef INT32 int32; ++typedef INT64 int64; ++ ++typedef BOOLEAN bool; ++typedef unsigned char uchar; ++typedef UINTN uintptr; ++ ++typedef UINT8 u_char; ++typedef UINT16 u_short; ++typedef UINTN u_int; ++typedef ULONGN u_long; ++ ++#define UNUSED_PARAMETER(x) (void)(x) ++#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) ++#define INLINE ++#define AUTO (-1) /* Auto = -1 */ ++#define ON 1 /* ON = 1 */ ++#define OFF 0 ++ ++#endif /* !EDK_RELEASE_VERSION || (EDK_RELEASE_VERSION < 0x00020000) */ ++ ++/* ++ * Including the bcmdefs.h here, to make sure everyone including typedefs.h ++ * gets this automatically ++*/ ++#include ++#endif /* _TYPEDEFS_H_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/usbrdl.h b/module_drivers/drivers/net/wireless/bcmdhd/include/usbrdl.h +new file mode 100644 +index 000000000..be5bd6923 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/usbrdl.h +@@ -0,0 +1,134 @@ ++/* ++ * Broadcom USB remote download definitions ++ * ++ * Copyright (C) 1999-2016, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: usbrdl.h 597933 2015-11-06 18:52:06Z $ ++ */ ++ ++#ifndef _USB_RDL_H ++#define _USB_RDL_H ++ ++/* Control messages: bRequest values */ ++#define DL_GETSTATE 0 /* returns the rdl_state_t struct */ ++#define DL_CHECK_CRC 1 /* currently unused */ ++#define DL_GO 2 /* execute downloaded image */ ++#define DL_START 3 /* initialize dl state */ ++#define DL_REBOOT 4 /* reboot the device in 2 seconds */ ++#define DL_GETVER 5 /* returns the bootrom_id_t struct */ ++#define DL_GO_PROTECTED 6 /* execute the downloaded code and set reset event ++ * to occur in 2 seconds. It is the responsibility ++ * of the downloaded code to clear this event ++ */ ++#define DL_EXEC 7 /* jump to a supplied address */ ++#define DL_RESETCFG 8 /* To support single enum on dongle ++ * - Not used by bootloader ++ */ ++#define DL_DEFER_RESP_OK 9 /* Potentially defer the response to setup ++ * if resp unavailable ++ */ ++#define DL_CHGSPD 0x0A ++ ++#define DL_HWCMD_MASK 0xfc /* Mask for hardware read commands: */ ++#define DL_RDHW 0x10 /* Read a hardware address (Ctl-in) */ ++#define DL_RDHW32 0x10 /* Read a 32 bit word */ ++#define DL_RDHW16 0x11 /* Read 16 bits */ ++#define DL_RDHW8 0x12 /* Read an 8 bit byte */ ++#define DL_WRHW 0x14 /* Write a hardware address (Ctl-out) */ ++#define DL_WRHW_BLK 0x13 /* Block write to hardware access */ ++ ++#define DL_CMD_WRHW 2 ++ ++ ++/* states */ ++#define DL_WAITING 0 /* waiting to rx first pkt that includes the hdr info */ ++#define DL_READY 1 /* hdr was good, waiting for more of the compressed image */ ++#define DL_BAD_HDR 2 /* hdr was corrupted */ ++#define DL_BAD_CRC 3 /* compressed image was corrupted */ ++#define DL_RUNNABLE 4 /* download was successful, waiting for go cmd */ ++#define DL_START_FAIL 5 /* failed to initialize correctly */ ++#define DL_NVRAM_TOOBIG 6 /* host specified nvram data exceeds DL_NVRAM value */ ++#define DL_IMAGE_TOOBIG 7 /* download image too big (exceeds DATA_START for rdl) */ ++ ++#define TIMEOUT 5000 /* Timeout for usb commands */ ++ ++struct bcm_device_id { ++ char *name; ++ uint32 vend; ++ uint32 prod; ++}; ++ ++typedef struct { ++ uint32 state; ++ uint32 bytes; ++} rdl_state_t; ++ ++typedef struct { ++ uint32 chip; /* Chip id */ ++ uint32 chiprev; /* Chip rev */ ++ uint32 ramsize; /* Size of RAM */ ++ uint32 remapbase; /* Current remap base address */ ++ uint32 boardtype; /* Type of board */ ++ uint32 boardrev; /* Board revision */ ++} bootrom_id_t; ++ ++/* struct for backplane & jtag accesses */ ++typedef struct { ++ uint32 cmd; /* tag to identify the cmd */ ++ uint32 addr; /* backplane address for write */ ++ uint32 len; /* length of data: 1, 2, 4 bytes */ ++ uint32 data; /* data to write */ ++} hwacc_t; ++ ++ ++/* struct for querying nvram params from bootloader */ ++#define QUERY_STRING_MAX 32 ++typedef struct { ++ uint32 cmd; /* tag to identify the cmd */ ++ char var[QUERY_STRING_MAX]; /* param name */ ++} nvparam_t; ++ ++typedef void (*exec_fn_t)(void *sih); ++ ++#define USB_CTRL_IN (USB_TYPE_VENDOR | 0x80 | USB_RECIP_INTERFACE) ++#define USB_CTRL_OUT (USB_TYPE_VENDOR | 0 | USB_RECIP_INTERFACE) ++ ++#define USB_CTRL_EP_TIMEOUT 500 /* Timeout used in USB control_msg transactions. */ ++#define USB_BULK_EP_TIMEOUT 500 /* Timeout used in USB bulk transactions. */ ++ ++#define RDL_CHUNK_MAX (64 * 1024) /* max size of each dl transfer */ ++#define RDL_CHUNK 1500 /* size of each dl transfer */ ++ ++/* bootloader makes special use of trx header "offsets" array */ ++#define TRX_OFFSETS_DLFWLEN_IDX 0 /* Size of the fw; used in uncompressed case */ ++#define TRX_OFFSETS_JUMPTO_IDX 1 /* RAM address for jumpto after download */ ++#define TRX_OFFSETS_NVM_LEN_IDX 2 /* Length of appended NVRAM data */ ++#ifdef BCMTRXV2 ++#define TRX_OFFSETS_DSG_LEN_IDX 3 /* Length of digital signature for the first image */ ++#define TRX_OFFSETS_CFG_LEN_IDX 4 /* Length of config region, which is not digitally signed */ ++#endif /* BCMTRXV2 */ ++ ++#define TRX_OFFSETS_DLBASE_IDX 0 /* RAM start address for download */ ++ ++#endif /* _USB_RDL_H */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/vlan.h b/module_drivers/drivers/net/wireless/bcmdhd/include/vlan.h +new file mode 100644 +index 000000000..4879eae58 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/vlan.h +@@ -0,0 +1,98 @@ ++/* ++ * 802.1Q VLAN protocol definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: vlan.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _vlan_h_ ++#define _vlan_h_ ++ ++#ifndef _TYPEDEFS_H_ ++#include ++#endif ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++#ifndef VLAN_VID_MASK ++#define VLAN_VID_MASK 0xfff /* low 12 bits are vlan id */ ++#endif ++ ++#define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */ ++#define VLAN_PRI_SHIFT 13 /* user priority */ ++ ++#define VLAN_PRI_MASK 7 /* 3 bits of priority */ ++ ++#define VLAN_TPID_OFFSET 12 /* offset of tag protocol id field */ ++#define VLAN_TCI_OFFSET 14 /* offset of tag ctrl info field */ ++ ++#define VLAN_TAG_LEN 4 ++#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) /* offset in Ethernet II packet only */ ++ ++#define VLAN_TPID 0x8100 /* VLAN ethertype/Tag Protocol ID */ ++ ++struct vlan_header { ++ uint16 vlan_type; /* 0x8100 */ ++ uint16 vlan_tag; /* priority, cfi and vid */ ++}; ++ ++struct ethervlan_header { ++ uint8 ether_dhost[ETHER_ADDR_LEN]; ++ uint8 ether_shost[ETHER_ADDR_LEN]; ++ uint16 vlan_type; /* 0x8100 */ ++ uint16 vlan_tag; /* priority, cfi and vid */ ++ uint16 ether_type; ++}; ++ ++struct dot3_mac_llc_snapvlan_header { ++ uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */ ++ uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */ ++ uint16 length; /* frame length incl header */ ++ uint8 dsap; /* always 0xAA */ ++ uint8 ssap; /* always 0xAA */ ++ uint8 ctl; /* always 0x03 */ ++ uint8 oui[3]; /* RFC1042: 0x00 0x00 0x00 ++ * Bridge-Tunnel: 0x00 0x00 0xF8 ++ */ ++ uint16 vlan_type; /* 0x8100 */ ++ uint16 vlan_tag; /* priority, cfi and vid */ ++ uint16 ether_type; /* ethertype */ ++}; ++ ++#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) ++ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#define ETHERVLAN_MOVE_HDR(d, s) \ ++do { \ ++ struct ethervlan_header t; \ ++ t = *(struct ethervlan_header *)(s); \ ++ *(struct ethervlan_header *)(d) = t; \ ++} while (0) ++ ++#endif /* _vlan_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/module_drivers/drivers/net/wireless/bcmdhd/include/wlfc_proto.h +new file mode 100644 +index 000000000..121af90b6 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/wlfc_proto.h +@@ -0,0 +1,376 @@ ++/* ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: wlfc_proto.h 675983 2016-12-19 23:18:49Z $ ++ * ++ */ ++ ++/** WL flow control for PROP_TXSTATUS. Related to host AMPDU reordering. */ ++ ++ ++#ifndef __wlfc_proto_definitions_h__ ++#define __wlfc_proto_definitions_h__ ++ ++ /* Use TLV to convey WLFC information. ++ --------------------------------------------------------------------------- ++ | Type | Len | value | Description ++ --------------------------------------------------------------------------- ++ | 1 | 1 | (handle) | MAC OPEN ++ --------------------------------------------------------------------------- ++ | 2 | 1 | (handle) | MAC CLOSE ++ --------------------------------------------------------------------------- ++ | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn ++ --------------------------------------------------------------------------- ++ | 4 | 4+ | see pkttag comments | TXSTATUS ++ | | 12 | TX status & timestamps | Present only when pkt timestamp is enabled ++ --------------------------------------------------------------------------- ++ | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware] ++ --------------------------------------------------------------------------- ++ | 6 | 8 | (handle, ifid, MAC) | MAC ADD ++ --------------------------------------------------------------------------- ++ | 7 | 8 | (handle, ifid, MAC) | MAC DEL ++ --------------------------------------------------------------------------- ++ | 8 | 1 | (rssi) | RSSI - RSSI value for the packet. ++ --------------------------------------------------------------------------- ++ | 9 | 1 | (interface ID) | Interface OPEN ++ --------------------------------------------------------------------------- ++ | 10 | 1 | (interface ID) | Interface CLOSE ++ --------------------------------------------------------------------------- ++ | 11 | 8 | fifo credit returns map | FIFO credits back to the host ++ | | | | ++ | | | | -------------------------------------- ++ | | | | | ac0 | ac1 | ac2 | ac3 | bcmc | atim | ++ | | | | -------------------------------------- ++ | | | | ++ --------------------------------------------------------------------------- ++ | 12 | 2 | MAC handle, | Host provides a bitmap of pending ++ | | | AC[0-3] traffic bitmap | unicast traffic for MAC-handle dstn. ++ | | | | [host->firmware] ++ --------------------------------------------------------------------------- ++ | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific ++ | | | | MAC destination. ++ --------------------------------------------------------------------------- ++ | 15 | 12 | (pkttag, timestamps) | Send TX timestamp at reception from host ++ --------------------------------------------------------------------------- ++ | 16 | 12 | (pkttag, timestamps) | Send WLAN RX timestamp along with RX frame ++ --------------------------------------------------------------------------- ++ | 255 | N/A | N/A | FILLER - This is a special type ++ | | | | that has no length or value. ++ | | | | Typically used for padding. ++ --------------------------------------------------------------------------- ++ */ ++ ++#define WLFC_CTL_TYPE_MAC_OPEN 1 ++#define WLFC_CTL_TYPE_MAC_CLOSE 2 ++#define WLFC_CTL_TYPE_MAC_REQUEST_CREDIT 3 ++#define WLFC_CTL_TYPE_TXSTATUS 4 ++#define WLFC_CTL_TYPE_PKTTAG 5 /** host<->dongle */ ++ ++#define WLFC_CTL_TYPE_MACDESC_ADD 6 ++#define WLFC_CTL_TYPE_MACDESC_DEL 7 ++#define WLFC_CTL_TYPE_RSSI 8 ++ ++#define WLFC_CTL_TYPE_INTERFACE_OPEN 9 ++#define WLFC_CTL_TYPE_INTERFACE_CLOSE 10 ++ ++#define WLFC_CTL_TYPE_FIFO_CREDITBACK 11 ++ ++#define WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP 12 /** host->dongle */ ++#define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13 ++#define WLFC_CTL_TYPE_HOST_REORDER_RXPKTS 14 ++ ++#define WLFC_CTL_TYPE_TX_ENTRY_STAMP 15 ++#define WLFC_CTL_TYPE_RX_STAMP 16 ++#define WLFC_CTL_TYPE_TX_STATUS_STAMP 17 /** obsolete */ ++ ++#define WLFC_CTL_TYPE_TRANS_ID 18 ++#define WLFC_CTL_TYPE_COMP_TXSTATUS 19 ++ ++#define WLFC_CTL_TYPE_TID_OPEN 20 ++#define WLFC_CTL_TYPE_TID_CLOSE 21 ++ ++ ++#define WLFC_CTL_TYPE_FILLER 255 ++ ++#define WLFC_CTL_VALUE_LEN_MACDESC 8 /** handle, interface, MAC */ ++ ++#define WLFC_CTL_VALUE_LEN_MAC 1 /** MAC-handle */ ++#define WLFC_CTL_VALUE_LEN_RSSI 1 ++ ++#define WLFC_CTL_VALUE_LEN_INTERFACE 1 ++#define WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP 2 ++ ++#define WLFC_CTL_VALUE_LEN_TXSTATUS 4 ++#define WLFC_CTL_VALUE_LEN_PKTTAG 4 ++#define WLFC_CTL_VALUE_LEN_TIMESTAMP 12 /** 4-byte rate info + 2 TSF */ ++ ++#define WLFC_CTL_VALUE_LEN_SEQ 2 ++ ++/* The high bits of ratespec report in timestamp are used for various status */ ++#define WLFC_TSFLAGS_RX_RETRY (1 << 31) ++#define WLFC_TSFLAGS_PM_ENABLED (1 << 30) ++#define WLFC_TSFLAGS_MASK (WLFC_TSFLAGS_RX_RETRY | WLFC_TSFLAGS_PM_ENABLED) ++ ++/* enough space to host all 4 ACs, bc/mc and atim fifo credit */ ++#define WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK 6 ++ ++#define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */ ++#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */ ++ ++ ++#define WLFC_PKTFLAG_PKTFROMHOST 0x01 ++#define WLFC_PKTFLAG_PKT_REQUESTED 0x02 ++ ++#define WL_TXSTATUS_STATUS_MASK 0xff /* allow 8 bits */ ++#define WL_TXSTATUS_STATUS_SHIFT 24 ++ ++#define WL_TXSTATUS_SET_STATUS(x, status) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_STATUS_MASK << WL_TXSTATUS_STATUS_SHIFT)) | \ ++ (((status) & WL_TXSTATUS_STATUS_MASK) << WL_TXSTATUS_STATUS_SHIFT)) ++#define WL_TXSTATUS_GET_STATUS(x) (((x) >> WL_TXSTATUS_STATUS_SHIFT) & \ ++ WL_TXSTATUS_STATUS_MASK) ++ ++/** ++ * Bit 31 of the 32-bit packet tag is defined as 'generation ID'. It is set by the host to the ++ * "current" generation, and by the firmware to the "expected" generation, toggling on suppress. The ++ * firmware accepts a packet when the generation matches; on reset (startup) both "current" and ++ * "expected" are set to 0. ++ */ ++#define WL_TXSTATUS_GENERATION_MASK 1 /* allow 1 bit */ ++#define WL_TXSTATUS_GENERATION_SHIFT 31 ++ ++#define WL_TXSTATUS_SET_GENERATION(x, gen) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \ ++ (((gen) & WL_TXSTATUS_GENERATION_MASK) << WL_TXSTATUS_GENERATION_SHIFT)) ++ ++#define WL_TXSTATUS_GET_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \ ++ WL_TXSTATUS_GENERATION_MASK) ++ ++#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */ ++#define WL_TXSTATUS_FLAGS_SHIFT 27 ++ ++#define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \ ++ (((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT)) ++#define WL_TXSTATUS_GET_FLAGS(x) (((x) >> WL_TXSTATUS_FLAGS_SHIFT) & \ ++ WL_TXSTATUS_FLAGS_MASK) ++ ++#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */ ++#define WL_TXSTATUS_FIFO_SHIFT 24 ++ ++#define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \ ++ (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT)) ++#define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK) ++ ++#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */ ++#define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \ ++ ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num)) ++#define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK) ++ ++#define WL_TXSTATUS_HSLOT_MASK 0xffff /* allow 16 bits */ ++#define WL_TXSTATUS_HSLOT_SHIFT 8 ++ ++#define WL_TXSTATUS_SET_HSLOT(x, hslot) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_HSLOT_MASK << WL_TXSTATUS_HSLOT_SHIFT)) | \ ++ (((hslot) & WL_TXSTATUS_HSLOT_MASK) << WL_TXSTATUS_HSLOT_SHIFT)) ++#define WL_TXSTATUS_GET_HSLOT(x) (((x) >> WL_TXSTATUS_HSLOT_SHIFT)& \ ++ WL_TXSTATUS_HSLOT_MASK) ++ ++#define WL_TXSTATUS_FREERUNCTR_MASK 0xff /* allow 8 bits */ ++ ++#define WL_TXSTATUS_SET_FREERUNCTR(x, ctr) ((x) = \ ++ ((x) & ~(WL_TXSTATUS_FREERUNCTR_MASK)) | \ ++ ((ctr) & WL_TXSTATUS_FREERUNCTR_MASK)) ++#define WL_TXSTATUS_GET_FREERUNCTR(x) ((x)& WL_TXSTATUS_FREERUNCTR_MASK) ++ ++/* AMSDU part of d11 seq number */ ++#define WL_SEQ_AMSDU_MASK 0x1 /* allow 1 bit */ ++#define WL_SEQ_AMSDU_SHIFT 14 ++#define WL_SEQ_SET_AMSDU(x, val) ((x) = \ ++ ((x) & ~(WL_SEQ_AMSDU_MASK << WL_SEQ_AMSDU_SHIFT)) | \ ++ (((val) & WL_SEQ_AMSDU_MASK) << WL_SEQ_AMSDU_SHIFT)) /**< sets a single AMSDU bit */ ++/** returns TRUE if ring item is AMSDU (seq = d11 seq nr) */ ++#define WL_SEQ_IS_AMSDU(x) (((x) >> WL_SEQ_AMSDU_SHIFT) & \ ++ WL_SEQ_AMSDU_MASK) ++ ++#define WL_SEQ_FROMFW_MASK 0x1 /* allow 1 bit */ ++#define WL_SEQ_FROMFW_SHIFT 13 ++#define WL_SEQ_SET_FROMFW(x, val) ((x) = \ ++ ((x) & ~(WL_SEQ_FROMFW_MASK << WL_SEQ_FROMFW_SHIFT)) | \ ++ (((val) & WL_SEQ_FROMFW_MASK) << WL_SEQ_FROMFW_SHIFT)) ++/** Set when firmware assigns D11 sequence number to packet */ ++#define SET_WL_HAS_ASSIGNED_SEQ(x) WL_SEQ_SET_FROMFW((x), 1) ++ ++/** returns TRUE if packet has been assigned a d11 seq number by the WL firmware layer */ ++#define GET_WL_HAS_ASSIGNED_SEQ(x) (((x) >> WL_SEQ_FROMFW_SHIFT) & WL_SEQ_FROMFW_MASK) ++ ++/** ++ * Proptxstatus related. ++ * ++ * When a packet is suppressed by WL or the D11 core, the packet has to be retried. Assigning ++ * a new d11 sequence number for the packet when retrying would cause the peer to be unable to ++ * reorder the packets within an AMPDU. So, suppressed packet from bus layer (DHD for SDIO and ++ * pciedev for PCIE) is re-using d11 seq number, so FW should not assign a new one. ++ */ ++#define WL_SEQ_FROMDRV_MASK 0x1 /* allow 1 bit */ ++#define WL_SEQ_FROMDRV_SHIFT 12 ++ ++/** ++ * Proptxstatus, host or fw PCIe layer requests WL layer to reuse d11 seq no. Bit is reset by WL ++ * subsystem when it reuses the seq number. ++ */ ++#define WL_SEQ_SET_REUSE(x, val) ((x) = \ ++ ((x) & ~(WL_SEQ_FROMDRV_MASK << WL_SEQ_FROMDRV_SHIFT)) | \ ++ (((val) & WL_SEQ_FROMDRV_MASK) << WL_SEQ_FROMDRV_SHIFT)) ++#define SET_WL_TO_REUSE_SEQ(x) WL_SEQ_SET_REUSE((x), 1) ++#define RESET_WL_TO_REUSE_SEQ(x) WL_SEQ_SET_REUSE((x), 0) ++ ++/** Proptxstatus, related to reuse of d11 seq numbers when retransmitting */ ++#define IS_WL_TO_REUSE_SEQ(x) (((x) >> WL_SEQ_FROMDRV_SHIFT) & \ ++ WL_SEQ_FROMDRV_MASK) ++ ++#define WL_SEQ_NUM_MASK 0xfff /* allow 12 bit */ ++#define WL_SEQ_NUM_SHIFT 0 ++/** Proptxstatus, sets d11seq no in pkt tag, related to reuse of d11seq no when retransmitting */ ++#define WL_SEQ_SET_NUM(x, val) ((x) = \ ++ ((x) & ~(WL_SEQ_NUM_MASK << WL_SEQ_NUM_SHIFT)) | \ ++ (((val) & WL_SEQ_NUM_MASK) << WL_SEQ_NUM_SHIFT)) ++/** Proptxstatus, gets d11seq no from pkt tag, related to reuse of d11seq no when retransmitting */ ++#define WL_SEQ_GET_NUM(x) (((x) >> WL_SEQ_NUM_SHIFT) & \ ++ WL_SEQ_NUM_MASK) ++ ++#define WL_SEQ_AMSDU_SUPPR_MASK ((WL_SEQ_FROMDRV_MASK << WL_SEQ_FROMDRV_SHIFT) | \ ++ (WL_SEQ_AMSDU_MASK << WL_SEQ_AMSDU_SHIFT) | \ ++ (WL_SEQ_NUM_MASK << WL_SEQ_NUM_SHIFT)) ++ ++/* 32 STA should be enough??, 6 bits; Must be power of 2 */ ++#define WLFC_MAC_DESC_TABLE_SIZE 32 ++#define WLFC_MAX_IFNUM 16 ++#define WLFC_MAC_DESC_ID_INVALID 0xff ++ ++/* b[7:5] -reuse guard, b[4:0] -value */ ++#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f) ++ ++#define WLFC_PKTFLAG_SET_PKTREQUESTED(x) (x) |= \ ++ (WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) ++ ++#define WLFC_PKTFLAG_CLR_PKTREQUESTED(x) (x) &= \ ++ ~(WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT) ++ ++ ++#define WLFC_MAX_PENDING_DATALEN 120 ++ ++/* host is free to discard the packet */ ++#define WLFC_CTL_PKTFLAG_DISCARD 0 ++/* D11 suppressed a packet */ ++#define WLFC_CTL_PKTFLAG_D11SUPPRESS 1 ++/* WL firmware suppressed a packet because MAC is ++ already in PSMode (short time window) ++*/ ++#define WLFC_CTL_PKTFLAG_WLSUPPRESS 2 ++/* Firmware tossed this packet */ ++#define WLFC_CTL_PKTFLAG_TOSSED_BYWLC 3 ++/* Firmware tossed after retries */ ++#define WLFC_CTL_PKTFLAG_DISCARD_NOACK 4 ++/* Firmware wrongly reported suppressed previously,now fixing to acked */ ++#define WLFC_CTL_PKTFLAG_SUPPRESS_ACKED 5 ++#define WLFC_CTL_PKTFLAG_MASK (0x0f) /* For 4-bit mask with one extra bit */ ++ ++#ifdef PROP_TXSTATUS_DEBUG ++#define WLFC_DBGMESG(x) printf x ++/* wlfc-breadcrumb */ ++#define WLFC_BREADCRUMB(x) do {if ((x) == NULL) \ ++ {printf("WLFC: %s():%d:caller:%p\n", \ ++ __FUNCTION__, __LINE__, CALL_SITE);}} while (0) ++#define WLFC_PRINTMAC(banner, ea) do {printf("%s MAC: [%02x:%02x:%02x:%02x:%02x:%02x]\n", \ ++ banner, ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); } while (0) ++#define WLFC_WHEREIS(s) printf("WLFC: at %s():%d, %s\n", __FUNCTION__, __LINE__, (s)) ++#else ++#define WLFC_DBGMESG(x) ++#define WLFC_BREADCRUMB(x) ++#define WLFC_PRINTMAC(banner, ea) ++#define WLFC_WHEREIS(s) ++#endif ++ ++/* AMPDU host reorder packet flags */ ++#define WLHOST_REORDERDATA_MAXFLOWS 256 ++#define WLHOST_REORDERDATA_LEN 10 ++#define WLHOST_REORDERDATA_TOTLEN (WLHOST_REORDERDATA_LEN + 1 + 1) /* +tag +len */ ++ ++#define WLHOST_REORDERDATA_FLOWID_OFFSET 0 ++#define WLHOST_REORDERDATA_MAXIDX_OFFSET 2 ++#define WLHOST_REORDERDATA_FLAGS_OFFSET 4 ++#define WLHOST_REORDERDATA_CURIDX_OFFSET 6 ++#define WLHOST_REORDERDATA_EXPIDX_OFFSET 8 ++ ++#define WLHOST_REORDERDATA_DEL_FLOW 0x01 ++#define WLHOST_REORDERDATA_FLUSH_ALL 0x02 ++#define WLHOST_REORDERDATA_CURIDX_VALID 0x04 ++#define WLHOST_REORDERDATA_EXPIDX_VALID 0x08 ++#define WLHOST_REORDERDATA_NEW_HOLE 0x10 ++ ++/* transaction id data len byte 0: rsvd, byte 1: seqnumber, byte 2-5 will be used for timestampe */ ++#define WLFC_CTL_TRANS_ID_LEN 6 ++#define WLFC_TYPE_TRANS_ID_LEN 6 ++ ++#define WLFC_MODE_HANGER 1 /* use hanger */ ++#define WLFC_MODE_AFQ 2 /* use afq (At Firmware Queue) */ ++#define WLFC_IS_OLD_DEF(x) ((x & 1) || (x & 2)) ++ ++#define WLFC_MODE_AFQ_SHIFT 2 /* afq bit */ ++#define WLFC_SET_AFQ(x, val) ((x) = \ ++ ((x) & ~(1 << WLFC_MODE_AFQ_SHIFT)) | \ ++ (((val) & 1) << WLFC_MODE_AFQ_SHIFT)) ++/** returns TRUE if firmware supports 'at firmware queue' feature */ ++#define WLFC_GET_AFQ(x) (((x) >> WLFC_MODE_AFQ_SHIFT) & 1) ++ ++#define WLFC_MODE_REUSESEQ_SHIFT 3 /* seq reuse bit */ ++#define WLFC_SET_REUSESEQ(x, val) ((x) = \ ++ ((x) & ~(1 << WLFC_MODE_REUSESEQ_SHIFT)) | \ ++ (((val) & 1) << WLFC_MODE_REUSESEQ_SHIFT)) ++/** returns TRUE if 'd11 sequence reuse' has been agreed upon between host and dongle */ ++#define WLFC_GET_REUSESEQ(x) (((x) >> WLFC_MODE_REUSESEQ_SHIFT) & 1) ++ ++#define WLFC_MODE_REORDERSUPP_SHIFT 4 /* host reorder suppress pkt bit */ ++#define WLFC_SET_REORDERSUPP(x, val) ((x) = \ ++ ((x) & ~(1 << WLFC_MODE_REORDERSUPP_SHIFT)) | \ ++ (((val) & 1) << WLFC_MODE_REORDERSUPP_SHIFT)) ++/** returns TRUE if 'reorder suppress' has been agreed upon between host and dongle */ ++#define WLFC_GET_REORDERSUPP(x) (((x) >> WLFC_MODE_REORDERSUPP_SHIFT) & 1) ++ ++#define FLOW_RING_CREATE 1 ++#define FLOW_RING_DELETE 2 ++#define FLOW_RING_FLUSH 3 ++#define FLOW_RING_OPEN 4 ++#define FLOW_RING_CLOSED 5 ++#define FLOW_RING_FLUSHED 6 ++#define FLOW_RING_TIM_SET 7 ++#define FLOW_RING_TIM_RESET 8 ++#define FLOW_RING_FLUSH_TXFIFO 9 ++ ++/* bit 7, indicating if is TID(1) or AC(0) mapped info in tid field) */ ++#define PCIEDEV_IS_AC_TID_MAP_MASK 0x80 ++ ++#endif /* __wlfc_proto_definitions_h__ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl.h b/module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl.h +new file mode 100644 +index 000000000..444cb0021 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl.h +@@ -0,0 +1,13828 @@ ++/* ++ * Custom OID/ioctl definitions for ++ * ++ * ++ * Broadcom 802.11abg Networking Device Driver ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * <> ++ * ++ * $Id: wlioctl.h 677952 2017-01-05 23:25:28Z $ ++ */ ++ ++#ifndef _wlioctl_h_ ++#define _wlioctl_h_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include <802.11.h> ++#include <802.11s.h> ++#include <802.1d.h> ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++typedef struct { ++ uint32 num; ++ chanspec_t list[1]; ++} chanspec_list_t; ++ ++#define RSN_KCK_LENGTH 16 ++#define RSN_KEK_LENGTH 16 ++#define TPK_FTM_LEN 16 ++#ifndef INTF_NAME_SIZ ++#define INTF_NAME_SIZ 16 ++#endif ++ ++/**Used to send ioctls over the transport pipe */ ++typedef struct remote_ioctl { ++ cdc_ioctl_t msg; ++ uint32 data_len; ++ char intf_name[INTF_NAME_SIZ]; ++} rem_ioctl_t; ++#define REMOTE_SIZE sizeof(rem_ioctl_t) ++ ++#define BCM_IOV_XTLV_VERSION 0 ++ ++#define MAX_NUM_D11CORES 2 ++ ++/**DFS Forced param */ ++typedef struct wl_dfs_forced_params { ++ chanspec_t chspec; ++ uint16 version; ++ chanspec_list_t chspec_list; ++} wl_dfs_forced_t; ++ ++#define DFS_PREFCHANLIST_VER 0x01 ++#define WL_CHSPEC_LIST_FIXED_SIZE OFFSETOF(chanspec_list_t, list) ++/* size of dfs forced param size given n channels are in the list */ ++#define WL_DFS_FORCED_PARAMS_SIZE(n) \ ++ (sizeof(wl_dfs_forced_t) + (((n) < 1) ? (0) : (((n) - 1)* sizeof(chanspec_t)))) ++#define WL_DFS_FORCED_PARAMS_FIXED_SIZE \ ++ (WL_CHSPEC_LIST_FIXED_SIZE + OFFSETOF(wl_dfs_forced_t, chspec_list)) ++#define WL_DFS_FORCED_PARAMS_MAX_SIZE \ ++ WL_DFS_FORCED_PARAMS_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(chanspec_t)) ++ ++/**association decision information */ ++typedef struct { ++ uint8 assoc_approved; /**< (re)association approved */ ++ uint8 pad; ++ uint16 reject_reason; /**< reason code for rejecting association */ ++ struct ether_addr da; ++ uint8 pad1[6]; ++ int64 sys_time; /**< current system time */ ++} assoc_decision_t; ++ ++#define DFS_SCAN_S_IDLE -1 ++#define DFS_SCAN_S_RADAR_FREE 0 ++#define DFS_SCAN_S_RADAR_FOUND 1 ++#define DFS_SCAN_S_INPROGESS 2 ++#define DFS_SCAN_S_SCAN_ABORTED 3 ++#define DFS_SCAN_S_SCAN_MODESW_INPROGRESS 4 ++#define DFS_SCAN_S_MAX 5 ++ ++ ++#define ACTION_FRAME_SIZE 1800 ++ ++typedef struct wl_action_frame { ++ struct ether_addr da; ++ uint16 len; ++ uint32 packetId; ++ uint8 data[ACTION_FRAME_SIZE]; ++} wl_action_frame_t; ++ ++#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame) ++ ++typedef struct ssid_info ++{ ++ uint8 ssid_len; /**< the length of SSID */ ++ uint8 ssid[32]; /**< SSID string */ ++} ssid_info_t; ++ ++typedef struct wl_af_params { ++ uint32 channel; ++ int32 dwell_time; ++ struct ether_addr BSSID; ++ uint8 PAD[2]; ++ wl_action_frame_t action_frame; ++} wl_af_params_t; ++ ++#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params) ++ ++#define MFP_TEST_FLAG_NORMAL 0 ++#define MFP_TEST_FLAG_ANY_KEY 1 ++typedef struct wl_sa_query { ++ uint32 flag; ++ uint8 action; ++ uint8 PAD; ++ uint16 id; ++ struct ether_addr da; ++ uint16 PAD; ++} wl_sa_query_t; ++ ++/* EXT_STA */ ++/**association information */ ++typedef struct { ++ uint32 assoc_req; /**< offset to association request frame */ ++ uint32 assoc_req_len; /**< association request frame length */ ++ uint32 assoc_rsp; /**< offset to association response frame */ ++ uint32 assoc_rsp_len; /**< association response frame length */ ++ uint32 bcn; /**< offset to AP beacon */ ++ uint32 bcn_len; /**< AP beacon length */ ++ uint32 wsec; /**< ucast security algo */ ++ uint32 wpaie; /**< offset to WPA ie */ ++ uint8 auth_alg; /**< 802.11 authentication mode */ ++ uint8 WPA_auth; /**< WPA: authenticated key management */ ++ uint8 ewc_cap; /**< EWC (MIMO) capable */ ++ uint8 ofdm; /**< OFDM */ ++} assoc_info_t; ++/* defined(EXT_STA) */ ++ ++/* Flags for OBSS IOVAR Parameters */ ++#define WL_OBSS_DYN_BWSW_FLAG_ACTIVITY_PERIOD (0x01) ++#define WL_OBSS_DYN_BWSW_FLAG_NOACTIVITY_PERIOD (0x02) ++#define WL_OBSS_DYN_BWSW_FLAG_NOACTIVITY_INCR_PERIOD (0x04) ++#define WL_OBSS_DYN_BWSW_FLAG_PSEUDO_SENSE_PERIOD (0x08) ++#define WL_OBSS_DYN_BWSW_FLAG_RX_CRS_PERIOD (0x10) ++#define WL_OBSS_DYN_BWSW_FLAG_DUR_THRESHOLD (0x20) ++#define WL_OBSS_DYN_BWSW_FLAG_TXOP_PERIOD (0x40) ++ ++/* OBSS IOVAR Version information */ ++#define WL_PROT_OBSS_CONFIG_PARAMS_VERSION 1 ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 obss_bwsw_activity_cfm_count_cfg; /**< configurable count in ++ * seconds before we confirm that OBSS is present and ++ * dynamically activate dynamic bwswitch. ++ */ ++ uint8 obss_bwsw_no_activity_cfm_count_cfg; /**< configurable count in ++ * seconds before we confirm that OBSS is GONE and ++ * dynamically start pseudo upgrade. If in pseudo sense time, we ++ * will see OBSS, [means that, we false detected that OBSS-is-gone ++ * in watchdog] this count will be incremented in steps of ++ * obss_bwsw_no_activity_cfm_count_incr_cfg for confirming OBSS ++ * detection again. Note that, at present, max 30seconds is ++ * allowed like this. [OBSS_BWSW_NO_ACTIVITY_MAX_INCR_DEFAULT] ++ */ ++ uint8 obss_bwsw_no_activity_cfm_count_incr_cfg; /* see above ++ */ ++ uint16 obss_bwsw_pseudo_sense_count_cfg; /**< number of msecs/cnt to be in ++ * pseudo state. This is used to sense/measure the stats from lq. ++ */ ++ uint8 obss_bwsw_rx_crs_threshold_cfg; /**< RX CRS default threshold */ ++ uint8 obss_bwsw_dur_thres; /**< OBSS dyn bwsw trigger/RX CRS Sec */ ++ uint8 obss_bwsw_txop_threshold_cfg; /**< TXOP default threshold */ ++} BWL_POST_PACKED_STRUCT wlc_obss_dynbwsw_config_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 version; /**< version field */ ++ uint32 config_mask; ++ uint32 reset_mask; ++ wlc_obss_dynbwsw_config_t config_params; ++} BWL_POST_PACKED_STRUCT obss_config_params_t; ++#include ++ ++/**bsscfg type */ ++typedef enum bsscfg_type { ++ BSSCFG_TYPE_GENERIC = 0, /**< Generic AP/STA/IBSS BSS */ ++ BSSCFG_TYPE_P2P = 1, /**< P2P BSS */ ++ /* index 2 earlier used for BTAMP */ ++ BSSCFG_TYPE_PSTA = 3, ++ BSSCFG_TYPE_TDLS = 4, ++ BSSCFG_TYPE_SLOTTED_BSS = 5, ++ BSSCFG_TYPE_PROXD = 6, ++ BSSCFG_TYPE_NAN = 7, ++ BSSCFG_TYPE_MESH = 8, ++ BSSCFG_TYPE_AIBSS = 9 ++} bsscfg_type_t; ++ ++/* bsscfg subtype */ ++typedef enum bsscfg_subtype { ++ BSSCFG_SUBTYPE_NONE = 0, ++ BSSCFG_GENERIC_STA = 1, /* GENERIC */ ++ BSSCFG_GENERIC_AP = 2, ++ BSSCFG_GENERIC_IBSS = 6, ++ BSSCFG_P2P_GC = 3, /* P2P */ ++ BSSCFG_P2P_GO = 4, ++ BSSCFG_P2P_DISC = 5, ++ /* Index 7 & 8 earlier used for BTAMP */ ++ BSSCFG_SUBTYPE_AWDL = 9, /* SLOTTED_BSS_TYPE */ ++ BSSCFG_SUBTYPE_NAN_MGMT = 10, ++ BSSCFG_SUBTYPE_NAN_DATA = 11, ++ BSSCFG_SUBTYPE_NAN_MGMT_DATA = 12 ++} bsscfg_subtype_t; ++ ++typedef struct wlc_bsscfg_info { ++ uint32 type; ++ uint32 subtype; ++} wlc_bsscfg_info_t; ++ ++/* ULP SHM Offsets info */ ++typedef struct ulp_shm_info { ++ uint32 m_ulp_ctrl_sdio; ++ uint32 m_ulp_wakeevt_ind; ++ uint32 m_ulp_wakeind; ++} ulp_shm_info_t; ++ ++ ++/* Legacy structure to help keep backward compatible wl tool and tray app */ ++ ++#define LEGACY_WL_BSS_INFO_VERSION 107 /**< older version of wl_bss_info struct */ ++ ++typedef struct wl_bss_info_107 { ++ uint32 version; /**< version field */ ++ uint32 length; /**< byte length of data in this record, ++ * starting at version and including IEs ++ */ ++ struct ether_addr BSSID; ++ uint16 beacon_period; /**< units are Kusec */ ++ uint16 capability; /**< Capability information */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ uint8 PAD; ++ struct { ++ uint32 count; /**< # rates in this set */ ++ uint8 rates[16]; /**< rates in 500kbps units w/hi bit set if basic */ ++ } rateset; /**< supported rates */ ++ uint8 channel; /**< Channel no. */ ++ uint8 PAD; ++ uint16 atim_window; /**< units are Kusec */ ++ uint8 dtim_period; /**< DTIM period */ ++ uint8 PAD; ++ int16 RSSI; /**< receive signal strength (in dBm) */ ++ int8 phy_noise; /**< noise (in dBm) */ ++ uint8 PAD[3]; ++ uint32 ie_length; /**< byte length of Information Elements */ ++ /* variable length Information Elements */ ++} wl_bss_info_107_t; ++ ++/* ++ * Per-BSS information structure. ++ */ ++ ++#define LEGACY2_WL_BSS_INFO_VERSION 108 /**< old version of wl_bss_info struct */ ++ ++/** ++ * BSS info structure ++ * Applications MUST CHECK ie_offset field and length field to access IEs and ++ * next bss_info structure in a vector (in wl_scan_results_t) ++ */ ++typedef struct wl_bss_info_108 { ++ uint32 version; /**< version field */ ++ uint32 length; /**< byte length of data in this record, ++ * starting at version and including IEs ++ */ ++ struct ether_addr BSSID; ++ uint16 beacon_period; /**< units are Kusec */ ++ uint16 capability; /**< Capability information */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ uint8 PAD[1]; ++ struct { ++ uint32 count; /**< # rates in this set */ ++ uint8 rates[16]; /**< rates in 500kbps units w/hi bit set if basic */ ++ } rateset; /**< supported rates */ ++ chanspec_t chanspec; /**< chanspec for bss */ ++ uint16 atim_window; /**< units are Kusec */ ++ uint8 dtim_period; /**< DTIM period */ ++ uint8 PAD; ++ int16 RSSI; /**< receive signal strength (in dBm) */ ++ int8 phy_noise; /**< noise (in dBm) */ ++ ++ uint8 n_cap; /**< BSS is 802.11N Capable */ ++ uint8 PAD[2]; ++ uint32 nbss_cap; /**< 802.11N BSS Capabilities (based on HT_CAP_*) */ ++ uint8 ctl_ch; /**< 802.11N BSS control channel number */ ++ uint8 PAD[3]; ++ uint32 reserved32[1]; /**< Reserved for expansion of BSS properties */ ++ uint8 flags; /**< flags */ ++ uint8 reserved[3]; /**< Reserved for expansion of BSS properties */ ++ uint8 basic_mcs[MCSSET_LEN]; /**< 802.11N BSS required MCS set */ ++ ++ uint16 ie_offset; /**< offset at which IEs start, from beginning */ ++ uint8 PAD[2]; ++ uint32 ie_length; /**< byte length of Information Elements */ ++ /* Add new fields here */ ++ /* variable length Information Elements */ ++} wl_bss_info_108_t; ++ ++ ++#define WL_BSS_INFO_VERSION 109 /**< current version of wl_bss_info struct */ ++ ++/** ++ * BSS info structure ++ * Applications MUST CHECK ie_offset field and length field to access IEs and ++ * next bss_info structure in a vector (in wl_scan_results_t) ++ */ ++typedef struct wl_bss_info { ++ uint32 version; /**< version field */ ++ uint32 length; /**< byte length of data in this record, ++ * starting at version and including IEs ++ */ ++ struct ether_addr BSSID; ++ uint16 beacon_period; /**< units are Kusec */ ++ uint16 capability; /**< Capability information */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++ uint8 bcnflags; /* additional flags w.r.t. beacon */ ++ struct { ++ uint32 count; /**< # rates in this set */ ++ uint8 rates[16]; /**< rates in 500kbps units w/hi bit set if basic */ ++ } rateset; /**< supported rates */ ++ chanspec_t chanspec; /**< chanspec for bss */ ++ uint16 atim_window; /**< units are Kusec */ ++ uint8 dtim_period; /**< DTIM period */ ++ uint8 accessnet; /* from beacon interwork IE (if bcnflags) */ ++ int16 RSSI; /**< receive signal strength (in dBm) */ ++ int8 phy_noise; /**< noise (in dBm) */ ++ uint8 n_cap; /**< BSS is 802.11N Capable */ ++ uint16 freespace1; /* make implicit padding explicit */ ++ uint32 nbss_cap; /**< 802.11N+AC BSS Capabilities */ ++ uint8 ctl_ch; /**< 802.11N BSS control channel number */ ++ uint8 padding1[3]; /**< explicit struct alignment padding */ ++ uint16 vht_rxmcsmap; /**< VHT rx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ ++ uint16 vht_txmcsmap; /**< VHT tx mcs map (802.11ac IE, VHT_CAP_MCS_MAP_*) */ ++ uint8 flags; /**< flags */ ++ uint8 vht_cap; /**< BSS is vht capable */ ++ uint8 reserved[2]; /**< Reserved for expansion of BSS properties */ ++ uint8 basic_mcs[MCSSET_LEN]; /**< 802.11N BSS required MCS set */ ++ ++ uint16 ie_offset; /**< offset at which IEs start, from beginning */ ++ uint16 freespace2; /* making implicit padding explicit */ ++ uint32 ie_length; /**< byte length of Information Elements */ ++ int16 SNR; /**< average SNR of during frame reception */ ++ uint16 vht_mcsmap; /**< STA's Associated vhtmcsmap */ ++ uint16 vht_mcsmap_prop; /**< STA's Associated prop vhtmcsmap */ ++ uint16 vht_txmcsmap_prop; /**< prop VHT tx mcs prop */ ++ /* Add new fields here */ ++ /* variable length Information Elements */ ++} wl_bss_info_t; ++ ++#define WL_GSCAN_FULL_RESULT_VERSION 2 /* current version of wl_gscan_result_t struct */ ++#define WL_GSCAN_INFO_FIXED_FIELD_SIZE (sizeof(wl_gscan_bss_info_t) - sizeof(wl_bss_info_t)) ++ ++typedef struct wl_gscan_bss_info { ++ uint32 timestamp[2]; ++ wl_bss_info_t info; ++ /* Do not add any more members below, fixed */ ++ /* and variable length Information Elements to follow */ ++} wl_gscan_bss_info_t; ++ ++ ++typedef struct wl_bsscfg { ++ uint32 bsscfg_idx; ++ uint32 wsec; ++ uint32 WPA_auth; ++ uint32 wsec_index; ++ uint32 associated; ++ uint32 BSS; ++ uint32 phytest_on; ++ struct ether_addr prev_BSSID; ++ struct ether_addr BSSID; ++ uint32 targetbss_wpa2_flags; ++ uint32 assoc_type; ++ uint32 assoc_state; ++} wl_bsscfg_t; ++ ++typedef struct wl_if_add { ++ uint32 bsscfg_flags; ++ uint32 if_flags; ++ uint32 ap; ++ struct ether_addr mac_addr; ++ uint16 PAD; ++ uint32 wlc_index; ++} wl_if_add_t; ++ ++typedef struct wl_bss_config { ++ uint32 atim_window; ++ uint32 beacon_period; ++ uint32 chanspec; ++} wl_bss_config_t; ++ ++#define WL_BSS_USER_RADAR_CHAN_SELECT 0x1 /**< User application will randomly select ++ * radar channel. ++ */ ++ ++#define DLOAD_HANDLER_VER 1 /**< Downloader version */ ++#define DLOAD_FLAG_VER_MASK 0xf000 /**< Downloader version mask */ ++#define DLOAD_FLAG_VER_SHIFT 12 /**< Downloader version shift */ ++ ++#define DL_CRC_NOT_INUSE 0x0001 ++#define DL_BEGIN 0x0002 ++#define DL_END 0x0004 ++ ++/* Flags for Major/Minor/Date number shift and mask */ ++#define EPI_VER_SHIFT 16 ++#define EPI_VER_MASK 0xFFFF ++/** generic download types & flags */ ++enum { ++ DL_TYPE_UCODE = 1, ++ DL_TYPE_CLM = 2 ++}; ++ ++/** ucode type values */ ++enum { ++ UCODE_FW, ++ INIT_VALS, ++ BS_INIT_VALS ++}; ++ ++struct wl_dload_data { ++ uint16 flag; ++ uint16 dload_type; ++ uint32 len; ++ uint32 crc; ++ uint8 data[1]; ++}; ++typedef struct wl_dload_data wl_dload_data_t; ++ ++struct wl_ucode_info { ++ uint32 ucode_type; ++ uint32 num_chunks; ++ uint32 chunk_len; ++ uint32 chunk_num; ++ uint8 data_chunk[1]; ++}; ++typedef struct wl_ucode_info wl_ucode_info_t; ++ ++struct wl_clm_dload_info { ++ uint32 ds_id; ++ uint32 clm_total_len; ++ uint32 num_chunks; ++ uint32 chunk_len; ++ uint32 chunk_offset; ++ uint8 data_chunk[1]; ++}; ++typedef struct wl_clm_dload_info wl_clm_dload_info_t; ++ ++ ++typedef struct wlc_ssid { ++ uint32 SSID_len; ++ uint8 SSID[DOT11_MAX_SSID_LEN]; ++} wlc_ssid_t; ++ ++typedef struct wlc_ssid_ext { ++ uint8 hidden; ++ uint8 PAD; ++ uint16 flags; ++ uint8 SSID_len; ++ int8 rssi_thresh; ++ uint8 SSID[DOT11_MAX_SSID_LEN]; ++} wlc_ssid_ext_t; ++ ++#define MAX_PREFERRED_AP_NUM 5 ++typedef struct wlc_fastssidinfo { ++ uint32 SSID_channel[MAX_PREFERRED_AP_NUM]; ++ wlc_ssid_t SSID_info[MAX_PREFERRED_AP_NUM]; ++} wlc_fastssidinfo_t; ++ ++typedef struct wnm_url { ++ uint8 len; ++ uint8 data[1]; ++} wnm_url_t; ++ ++typedef struct chan_scandata { ++ uint8 txpower; ++ uint8 pad; ++ chanspec_t channel; /**< Channel num, bw, ctrl_sb and band */ ++ uint32 channel_mintime; ++ uint32 channel_maxtime; ++} chan_scandata_t; ++ ++typedef enum wl_scan_type { ++ EXTDSCAN_FOREGROUND_SCAN, ++ EXTDSCAN_BACKGROUND_SCAN, ++ EXTDSCAN_FORCEDBACKGROUND_SCAN ++} wl_scan_type_t; ++ ++#define WLC_EXTDSCAN_MAX_SSID 5 ++ ++typedef struct wl_extdscan_params { ++ int8 nprobes; /**< 0, passive, otherwise active */ ++ int8 split_scan; /**< split scan */ ++ int8 band; /**< band */ ++ int8 pad; ++ wlc_ssid_t ssid[WLC_EXTDSCAN_MAX_SSID]; /**< ssid list */ ++ uint32 tx_rate; /**< in 500ksec units */ ++ wl_scan_type_t scan_type; /**< enum */ ++ int32 channel_num; ++ chan_scandata_t channel_list[1]; /**< list of chandata structs */ ++} wl_extdscan_params_t; ++ ++#define WL_EXTDSCAN_PARAMS_FIXED_SIZE (sizeof(wl_extdscan_params_t) - sizeof(chan_scandata_t)) ++ ++#define WL_SCAN_PARAMS_SSID_MAX 10 ++ ++typedef struct wl_scan_params { ++ wlc_ssid_t ssid; /**< default: {0, ""} */ ++ struct ether_addr bssid; /**< default: bcast */ ++ int8 bss_type; /**< default: any, ++ * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT ++ */ ++ uint8 scan_type; /**< flags, 0 use default */ ++ int32 nprobes; /**< -1 use default, number of probes per channel */ ++ int32 active_time; /**< -1 use default, dwell time per channel for ++ * active scanning ++ */ ++ int32 passive_time; /**< -1 use default, dwell time per channel ++ * for passive scanning ++ */ ++ int32 home_time; /**< -1 use default, dwell time for the home channel ++ * between channel scans ++ */ ++ int32 channel_num; /**< count of channels and ssids that follow ++ * ++ * low half is count of channels in channel_list, 0 ++ * means default (use all available channels) ++ * ++ * high half is entries in wlc_ssid_t array that ++ * follows channel_list, aligned for int32 (4 bytes) ++ * meaning an odd channel count implies a 2-byte pad ++ * between end of channel_list and first ssid ++ * ++ * if ssid count is zero, single ssid in the fixed ++ * parameter portion is assumed, otherwise ssid in ++ * the fixed portion is ignored ++ */ ++ uint16 channel_list[1]; /**< list of chanspecs */ ++} wl_scan_params_t; ++ ++/** size of wl_scan_params not including variable length array */ ++#define WL_SCAN_PARAMS_FIXED_SIZE 64 ++#define WL_MAX_ROAMSCAN_DATSZ (WL_SCAN_PARAMS_FIXED_SIZE + (WL_NUMCHANNELS * sizeof(uint16))) ++ ++#define ISCAN_REQ_VERSION 1 ++ ++/** incremental scan struct */ ++typedef struct wl_iscan_params { ++ uint32 version; ++ uint16 action; ++ uint16 scan_duration; ++ wl_scan_params_t params; ++} wl_iscan_params_t; ++ ++/** 3 fields + size of wl_scan_params, not including variable length array */ ++#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t)) ++ ++typedef struct wl_scan_results { ++ uint32 buflen; ++ uint32 version; ++ uint32 count; ++ wl_bss_info_t bss_info[1]; ++} wl_scan_results_t; ++ ++/** size of wl_scan_results not including variable length array */ ++#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t)) ++#define ESCAN_REQ_VERSION 1 ++ ++/** event scan reduces amount of SOC memory needed to store scan results */ ++typedef struct wl_escan_params { ++ uint32 version; ++ uint16 action; ++ uint16 sync_id; ++ wl_scan_params_t params; ++} wl_escan_params_t; ++ ++#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t)) ++ ++/** event scan reduces amount of SOC memory needed to store scan results */ ++typedef struct wl_escan_result { ++ uint32 buflen; ++ uint32 version; ++ uint16 sync_id; ++ uint16 bss_count; ++ wl_bss_info_t bss_info[1]; ++} wl_escan_result_t; ++ ++#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t)) ++typedef struct wl_gscan_result { ++ uint32 buflen; ++ uint32 version; ++ uint32 scan_ch_bucket; ++ wl_gscan_bss_info_t bss_info[1]; ++} wl_gscan_result_t; ++ ++#define WL_GSCAN_RESULTS_FIXED_SIZE (sizeof(wl_gscan_result_t) - sizeof(wl_gscan_bss_info_t)) ++/** incremental scan results struct */ ++typedef struct wl_iscan_results { ++ uint32 status; ++ wl_scan_results_t results; ++} wl_iscan_results_t; ++ ++/** size of wl_iscan_results not including variable length array */ ++#define WL_ISCAN_RESULTS_FIXED_SIZE \ ++ (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results)) ++ ++typedef struct wl_probe_params { ++ wlc_ssid_t ssid; ++ struct ether_addr bssid; ++ struct ether_addr mac; ++} wl_probe_params_t; ++ ++#define WL_MAXRATES_IN_SET 16 /**< max # of rates in a rateset */ ++typedef struct wl_rateset { ++ uint32 count; /**< # rates in this set */ ++ uint8 rates[WL_MAXRATES_IN_SET]; /**< rates in 500kbps units w/hi bit set if basic */ ++} wl_rateset_t; ++ ++typedef struct wl_rateset_args { ++ uint32 count; /**< # rates in this set */ ++ uint8 rates[WL_MAXRATES_IN_SET]; /**< rates in 500kbps units w/hi bit set if basic */ ++ uint8 mcs[MCSSET_LEN]; /**< supported mcs index bit map */ ++ uint16 vht_mcs[VHT_CAP_MCS_MAP_NSS_MAX]; /**< supported mcs index bit map per nss */ ++} wl_rateset_args_t; ++ ++#define TXBF_RATE_MCS_ALL 4 ++#define TXBF_RATE_VHT_ALL 4 ++#define TXBF_RATE_OFDM_ALL 8 ++ ++typedef struct wl_txbf_rateset { ++ uint8 txbf_rate_mcs[TXBF_RATE_MCS_ALL]; /**< one for each stream */ ++ uint8 txbf_rate_mcs_bcm[TXBF_RATE_MCS_ALL]; /**< one for each stream */ ++ uint16 txbf_rate_vht[TXBF_RATE_VHT_ALL]; /**< one for each stream */ ++ uint16 txbf_rate_vht_bcm[TXBF_RATE_VHT_ALL]; /**< one for each stream */ ++ uint8 txbf_rate_ofdm[TXBF_RATE_OFDM_ALL]; /**< bitmap of ofdm rates that enables txbf */ ++ uint8 txbf_rate_ofdm_bcm[TXBF_RATE_OFDM_ALL]; /* bitmap of ofdm rates that enables txbf */ ++ uint8 txbf_rate_ofdm_cnt; ++ uint8 txbf_rate_ofdm_cnt_bcm; ++} wl_txbf_rateset_t; ++ ++#define NUM_BFGAIN_ARRAY_1RX 2 ++#define NUM_BFGAIN_ARRAY_2RX 3 ++#define NUM_BFGAIN_ARRAY_3RX 4 ++#define NUM_BFGAIN_ARRAY_4RX 5 ++ ++typedef struct wl_txbf_expgainset { ++ /* bitmap for each element: B[4:0]=>c0, B[9:5]=>c1, B[14:10]=>c2, B[19:15]=>c[3-7] ++ * B[24:20]=>c[8-9], B[29:25]=>c[10-11] ++ */ ++ uint32 bfgain_2x1[NUM_BFGAIN_ARRAY_1RX]; /* exp 1ss, imp 1ss */ ++ uint32 bfgain_2x2[NUM_BFGAIN_ARRAY_2RX]; /* exp [1-2]ss, imp 1ss */ ++ uint32 bfgain_3x1[NUM_BFGAIN_ARRAY_1RX]; ++ uint32 bfgain_3x2[NUM_BFGAIN_ARRAY_2RX]; ++ uint32 bfgain_3x3[NUM_BFGAIN_ARRAY_3RX]; /* exp [1-3]ss, imp 1ss */ ++ uint32 bfgain_4x1[NUM_BFGAIN_ARRAY_1RX]; ++ uint32 bfgain_4x2[NUM_BFGAIN_ARRAY_2RX]; ++ uint32 bfgain_4x3[NUM_BFGAIN_ARRAY_3RX]; ++ uint32 bfgain_4x4[NUM_BFGAIN_ARRAY_4RX]; /* exp [1-4]ss, imp 1ss */ ++} wl_txbf_expgainset_t; ++ ++#define OFDM_RATE_MASK 0x0000007f ++typedef uint8 ofdm_rates_t; ++ ++typedef struct wl_rates_info { ++ wl_rateset_t rs_tgt; ++ uint32 phy_type; ++ int32 bandtype; ++ uint8 cck_only; ++ uint8 rate_mask; ++ uint8 mcsallow; ++ uint8 bw; ++ uint8 txstreams; ++ uint8 PAD[3]; ++} wl_rates_info_t; ++ ++/**uint32 list */ ++typedef struct wl_uint32_list { ++ /** in - # of elements, out - # of entries */ ++ uint32 count; ++ /** variable length uint32 list */ ++ uint32 element[1]; ++} wl_uint32_list_t; ++ ++/* WLC_SET_ALLOW_MODE values */ ++#define ALLOW_MODE_ANY_BSSID 0 ++#define ALLOW_MODE_ONLY_DESIRED_BSSID 1 ++#define ALLOW_MODE_NO_BSSID 2 ++ ++/** used for association with a specific BSSID and chanspec list */ ++typedef struct wl_assoc_params { ++ struct ether_addr bssid; /**< 00:00:00:00:00:00: broadcast scan */ ++ uint16 bssid_cnt; /**< 0: use chanspec_num, and the single bssid, ++ * otherwise count of chanspecs in chanspec_list ++ * AND paired bssids following chanspec_list ++ * also, chanspec_num has to be set to zero ++ * for bssid list to be used ++ */ ++ int32 chanspec_num; /**< 0: all available channels, ++ * otherwise count of chanspecs in chanspec_list ++ */ ++ chanspec_t chanspec_list[1]; /**< list of chanspecs */ ++} wl_assoc_params_t; ++ ++#define WL_ASSOC_PARAMS_FIXED_SIZE OFFSETOF(wl_assoc_params_t, chanspec_list) ++ ++/** used for reassociation/roam to a specific BSSID and channel */ ++typedef wl_assoc_params_t wl_reassoc_params_t; ++#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE ++ ++/** used for association to a specific BSSID and channel */ ++typedef wl_assoc_params_t wl_join_assoc_params_t; ++#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE ++ ++/** used for join with or without a specific bssid and channel list */ ++typedef struct wl_join_params { ++ wlc_ssid_t ssid; ++ wl_assoc_params_t params; /**< optional field, but it must include the fixed portion ++ * of the wl_assoc_params_t struct when it does present. ++ */ ++} wl_join_params_t; ++ ++#define WL_JOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_join_params_t, params) + \ ++ WL_ASSOC_PARAMS_FIXED_SIZE) ++ ++typedef struct wlc_roam_exp_params { ++ int8 a_band_boost_threshold; ++ int8 a_band_penalty_threshold; ++ int8 a_band_boost_factor; ++ int8 a_band_penalty_factor; ++ int8 cur_bssid_boost; ++ int8 alert_roam_trigger_threshold; ++ int16 a_band_max_boost; ++} wlc_roam_exp_params_t; ++ ++#define ROAM_EXP_CFG_VERSION 1 ++ ++#define ROAM_EXP_ENABLE_FLAG (1 << 0) ++ ++#define ROAM_EXP_CFG_PRESENT (1 << 1) ++ ++typedef struct wl_roam_exp_cfg { ++ uint16 version; ++ uint16 flags; ++ wlc_roam_exp_params_t params; ++} wl_roam_exp_cfg_t; ++ ++typedef struct wl_bssid_pref_list { ++ struct ether_addr bssid; ++ /* Add this to modify rssi */ ++ int8 rssi_factor; ++ int8 flags; ++} wl_bssid_pref_list_t; ++ ++#define BSSID_PREF_LIST_VERSION 1 ++#define ROAM_EXP_CLEAR_BSSID_PREF (1 << 0) ++ ++typedef struct wl_bssid_pref_cfg { ++ uint16 version; ++ uint16 flags; ++ uint16 count; ++ uint16 reserved; ++ wl_bssid_pref_list_t bssids[]; ++} wl_bssid_pref_cfg_t; ++ ++#define SSID_WHITELIST_VERSION 1 ++ ++#define ROAM_EXP_CLEAR_SSID_WHITELIST (1 << 0) ++ ++/* Roam SSID whitelist, ssids in this list are ok to */ ++/* be considered as targets to join when considering a roam */ ++ ++typedef struct wl_ssid_whitelist { ++ ++ uint16 version; ++ uint16 flags; ++ ++ uint8 ssid_count; ++ uint8 reserved[3]; ++ wlc_ssid_t ssids[]; ++} wl_ssid_whitelist_t; ++ ++#define ROAM_EXP_EVENT_VERSION 1 ++ ++typedef struct wl_roam_exp_event { ++ ++ uint16 version; ++ uint16 flags; ++ wlc_ssid_t cur_ssid; ++} wl_roam_exp_event_t; ++ ++/** scan params for extended join */ ++typedef struct wl_join_scan_params { ++ uint8 scan_type; /**< 0 use default, active or passive scan */ ++ uint8 PAD[3]; ++ int32 nprobes; /**< -1 use default, number of probes per channel */ ++ int32 active_time; /**< -1 use default, dwell time per channel for ++ * active scanning ++ */ ++ int32 passive_time; /**< -1 use default, dwell time per channel ++ * for passive scanning ++ */ ++ int32 home_time; /**< -1 use default, dwell time for the home channel ++ * between channel scans ++ */ ++} wl_join_scan_params_t; ++ ++/** extended join params */ ++typedef struct wl_extjoin_params { ++ wlc_ssid_t ssid; /**< {0, ""}: wildcard scan */ ++ wl_join_scan_params_t scan; ++ wl_join_assoc_params_t assoc; /**< optional field, but it must include the fixed portion ++ * of the wl_join_assoc_params_t struct when it does ++ * present. ++ */ ++} wl_extjoin_params_t; ++#define WL_EXTJOIN_PARAMS_FIXED_SIZE (OFFSETOF(wl_extjoin_params_t, assoc) + \ ++ WL_JOIN_ASSOC_PARAMS_FIXED_SIZE) ++ ++#define ANT_SELCFG_MAX 4 /**< max number of antenna configurations */ ++#define MAX_STREAMS_SUPPORTED 4 /**< max number of streams supported */ ++typedef struct { ++ uint8 ant_config[ANT_SELCFG_MAX]; /**< antenna configuration */ ++ uint8 num_antcfg; /**< number of available antenna configurations */ ++} wlc_antselcfg_t; ++ ++typedef struct { ++ uint32 duration; /**< millisecs spent sampling this channel */ ++ uint32 congest_ibss; /**< millisecs in our bss (presumably this traffic will */ ++ /**< move if cur bss moves channels) */ ++ uint32 congest_obss; /**< traffic not in our bss */ ++ uint32 interference; /**< millisecs detecting a non 802.11 interferer. */ ++ uint32 timestamp; /**< second timestamp */ ++} cca_congest_t; ++ ++typedef struct { ++ chanspec_t chanspec; /**< Which channel? */ ++ uint16 num_secs; /**< How many secs worth of data */ ++ cca_congest_t secs[1]; /**< Data */ ++} cca_congest_channel_req_t; ++typedef struct { ++ uint32 duration; /**< millisecs spent sampling this channel */ ++ uint32 congest; /**< millisecs detecting busy CCA */ ++ uint32 timestamp; /**< second timestamp */ ++} cca_congest_simple_t; ++ ++typedef struct { ++ uint16 status; ++ uint16 id; ++ chanspec_t chanspec; /**< Which channel? */ ++ uint16 len; ++ union { ++ cca_congest_simple_t cca_busy; /**< CCA busy */ ++ int32 noise; /**< noise floor */ ++ }; ++} cca_chan_qual_event_t; ++ ++typedef struct { ++ uint32 msrmnt_time; /**< Time for Measurement (msec) */ ++ uint32 msrmnt_done; /**< flag set when measurement complete */ ++ char buf[]; ++} cca_stats_n_flags; ++ ++typedef struct { ++ uint32 msrmnt_query; /* host to driver query for measurement done */ ++ uint32 time_req; /* time required for measurement */ ++ uint8 report_opt; /* option to print different stats in report */ ++ uint8 PAD[3]; ++} cca_msrmnt_query; ++ ++/* interference sources */ ++enum interference_source { ++ ITFR_NONE = 0, /**< interference */ ++ ITFR_PHONE, /**< wireless phone */ ++ ITFR_VIDEO_CAMERA, /**< wireless video camera */ ++ ITFR_MICROWAVE_OVEN, /**< microwave oven */ ++ ITFR_BABY_MONITOR, /**< wireless baby monitor */ ++ ITFR_BLUETOOTH, /**< bluetooth */ ++ ITFR_VIDEO_CAMERA_OR_BABY_MONITOR, /**< wireless camera or baby monitor */ ++ ITFR_BLUETOOTH_OR_BABY_MONITOR, /**< bluetooth or baby monitor */ ++ ITFR_VIDEO_CAMERA_OR_PHONE, /**< video camera or phone */ ++ ITFR_UNIDENTIFIED /**< interference from unidentified source */ ++}; ++ ++/** structure for interference source report */ ++typedef struct { ++ uint32 flags; /**< flags. bit definitions below */ ++ uint32 source; /**< last detected interference source */ ++ uint32 timestamp; /**< second timestamp on interferenced flag change */ ++} interference_source_rep_t; ++ ++#define WLC_CNTRY_BUF_SZ 4 /**< Country string is 3 bytes + NUL */ ++ ++typedef struct wl_country { ++ char country_abbrev[WLC_CNTRY_BUF_SZ]; /**< nul-terminated country code used in ++ * the Country IE ++ */ ++ int32 rev; /**< revision specifier for ccode ++ * on set, -1 indicates unspecified. ++ * on get, rev >= 0 ++ */ ++ char ccode[WLC_CNTRY_BUF_SZ]; /**< nul-terminated built-in country code. ++ * variable length, but fixed size in ++ * struct allows simple allocation for ++ * expected country strings <= 3 chars. ++ */ ++} wl_country_t; ++ ++ ++#define CCODE_INFO_VERSION 1 ++ ++typedef enum wl_ccode_role { ++ WLC_CCODE_ROLE_ACTIVE = 0, ++ WLC_CCODE_ROLE_HOST, ++ WLC_CCODE_ROLE_80211D_ASSOC, ++ WLC_CCODE_ROLE_80211D_SCAN, ++ WLC_CCODE_ROLE_DEFAULT, ++ WLC_CCODE_LAST ++} wl_ccode_role_t; ++#define WLC_NUM_CCODE_INFO WLC_CCODE_LAST ++ ++typedef struct wl_ccode_entry { ++ uint16 reserved; ++ uint8 band; ++ uint8 role; ++ char ccode[WLC_CNTRY_BUF_SZ]; ++} wl_ccode_entry_t; ++ ++typedef struct wl_ccode_info { ++ uint16 version; ++ uint16 count; /**< Number of ccodes entries in the set */ ++ wl_ccode_entry_t ccodelist[1]; ++} wl_ccode_info_t; ++#define WL_CCODE_INFO_FIXED_LEN OFFSETOF(wl_ccode_info_t, ccodelist) ++typedef struct wl_channels_in_country { ++ uint32 buflen; ++ uint32 band; ++ char country_abbrev[WLC_CNTRY_BUF_SZ]; ++ uint32 count; ++ uint32 channel[1]; ++} wl_channels_in_country_t; ++ ++typedef struct wl_country_list { ++ uint32 buflen; ++ uint32 band_set; ++ uint32 band; ++ uint32 count; ++ char country_abbrev[1]; ++} wl_country_list_t; ++ ++typedef struct wl_rm_req_elt { ++ int8 type; ++ int8 flags; ++ chanspec_t chanspec; ++ uint32 token; /**< token for this measurement */ ++ uint32 tsf_h; /**< TSF high 32-bits of Measurement start time */ ++ uint32 tsf_l; /**< TSF low 32-bits */ ++ uint32 dur; /**< TUs */ ++} wl_rm_req_elt_t; ++ ++typedef struct wl_rm_req { ++ uint32 token; /**< overall measurement set token */ ++ uint32 count; /**< number of measurement requests */ ++ void *cb; /**< completion callback function: may be NULL */ ++ void *cb_arg; /**< arg to completion callback function */ ++ wl_rm_req_elt_t req[1]; /**< variable length block of requests */ ++} wl_rm_req_t; ++#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req) ++ ++typedef struct wl_rm_rep_elt { ++ int8 type; ++ int8 flags; ++ chanspec_t chanspec; ++ uint32 token; /**< token for this measurement */ ++ uint32 tsf_h; /**< TSF high 32-bits of Measurement start time */ ++ uint32 tsf_l; /**< TSF low 32-bits */ ++ uint32 dur; /**< TUs */ ++ uint32 len; /**< byte length of data block */ ++ uint8 data[1]; /**< variable length data block */ ++} wl_rm_rep_elt_t; ++#define WL_RM_REP_ELT_FIXED_LEN 24 /**< length excluding data block */ ++ ++#define WL_RPI_REP_BIN_NUM 8 ++typedef struct wl_rm_rpi_rep { ++ uint8 rpi[WL_RPI_REP_BIN_NUM]; ++ int8 rpi_max[WL_RPI_REP_BIN_NUM]; ++} wl_rm_rpi_rep_t; ++ ++typedef struct wl_rm_rep { ++ uint32 token; /**< overall measurement set token */ ++ uint32 len; /**< length of measurement report block */ ++ wl_rm_rep_elt_t rep[1]; /**< variable length block of reports */ ++} wl_rm_rep_t; ++#define WL_RM_REP_FIXED_LEN 8 ++typedef enum sup_auth_status { ++ /* Basic supplicant authentication states */ ++ WLC_SUP_DISCONNECTED = 0, ++ WLC_SUP_CONNECTING, ++ WLC_SUP_IDREQUIRED, ++ WLC_SUP_AUTHENTICATING, ++ WLC_SUP_AUTHENTICATED, ++ WLC_SUP_KEYXCHANGE, ++ WLC_SUP_KEYED, ++ WLC_SUP_TIMEOUT, ++ WLC_SUP_LAST_BASIC_STATE, ++ ++ /* Extended supplicant authentication states */ ++ /** Waiting to receive handshake msg M1 */ ++ WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED, ++ /** Preparing to send handshake msg M2 */ ++ WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE, ++ /* Waiting to receive handshake msg M3 */ ++ WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE, ++ WLC_SUP_KEYXCHANGE_PREP_M4, /**< Preparing to send handshake msg M4 */ ++ WLC_SUP_KEYXCHANGE_WAIT_G1, /**< Waiting to receive handshake msg G1 */ ++ WLC_SUP_KEYXCHANGE_PREP_G2 /**< Preparing to send handshake msg G2 */ ++} sup_auth_status_t; ++ ++typedef struct wl_wsec_key { ++ uint32 index; /**< key index */ ++ uint32 len; /**< key length */ ++ uint8 data[DOT11_MAX_KEY_SIZE]; /**< key data */ ++ uint32 pad_1[18]; ++ uint32 algo; /**< CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ ++ uint32 flags; /**< misc flags */ ++ uint32 pad_2[2]; ++ int32 pad_3; ++ int32 iv_initialized; /**< has IV been initialized already? */ ++ int32 pad_4; ++ /* Rx IV */ ++ struct { ++ uint32 hi; /**< upper 32 bits of IV */ ++ uint16 lo; /**< lower 16 bits of IV */ ++ uint16 PAD; ++ } rxiv; ++ uint32 pad_5[2]; ++ struct ether_addr ea; /**< per station */ ++ uint16 PAD; ++} wl_wsec_key_t; ++ ++#define WSEC_MIN_PSK_LEN 8 ++#define WSEC_MAX_PSK_LEN 64 ++/* Max length of supported passphrases for SAE */ ++#define WSEC_MAX_PASSPHRASE_LEN 256u ++ ++/** Flag for key material needing passhash'ing */ ++#define WSEC_PASSPHRASE (1<<0) ++ ++/**receptacle for WLC_SET_WSEC_PMK parameter */ ++typedef struct wsec_pmk { ++ ushort key_len; /**< octets in key material */ ++ ushort flags; /**< key handling qualification */ ++ uint8 key[WSEC_MAX_PSK_LEN]; /**< PMK material */ ++} wsec_pmk_t; ++ ++#define WL_AUTH_EVENT_DATA_V1 0x1 ++ ++/* tlv ids for auth event */ ++#define WL_AUTH_PMK_TLV_ID 1 ++#define WL_AUTH_PMKID_TLV_ID 2 ++/* AUTH event data ++* pmk and pmkid in case of SAE auth ++* xtlvs will be 32 bit alligned ++*/ ++typedef struct wl_auth_event { ++ uint16 version; ++ uint16 length; ++ uint8 xtlvs[]; ++} wl_auth_event_t; ++ ++#define WL_AUTH_EVENT_FIXED_LEN_V1 OFFSETOF(wl_auth_event_t, xtlvs) ++ ++typedef struct _pmkid { ++ struct ether_addr BSSID; ++ uint8 PMKID[WPA2_PMKID_LEN]; ++} pmkid_t; ++ ++typedef struct _pmkid_list { ++ uint32 npmkid; ++ pmkid_t pmkid[1]; ++} pmkid_list_t; ++ ++typedef struct _pmkid_cand { ++ struct ether_addr BSSID; ++ uint8 preauth; ++} pmkid_cand_t; ++ ++typedef struct _pmkid_cand_list { ++ uint32 npmkid_cand; ++ pmkid_cand_t pmkid_cand[1]; ++} pmkid_cand_list_t; ++ ++#define WL_STA_ANT_MAX 4 /**< max possible rx antennas */ ++ ++typedef struct wl_assoc_info { ++ uint32 req_len; ++ uint32 resp_len; ++ uint32 flags; ++ struct dot11_assoc_req req; ++ struct ether_addr reassoc_bssid; /**< used in reassoc's */ ++ struct dot11_assoc_resp resp; ++} wl_assoc_info_t; ++ ++typedef struct wl_led_info { ++ uint32 index; /**< led index */ ++ uint32 behavior; ++ uint8 activehi; ++ uint8 PAD[3]; ++} wl_led_info_t; ++ ++ ++/** srom read/write struct passed through ioctl */ ++typedef struct { ++ uint32 byteoff; /**< byte offset */ ++ uint32 nbytes; /**< number of bytes */ ++ uint16 buf[]; ++} srom_rw_t; ++ ++#define CISH_FLAG_PCIECIS (1 << 15) /**< write CIS format bit for PCIe CIS */ ++ ++/** similar cis (srom or otp) struct [iovar: may not be aligned] */ ++typedef struct { ++ uint16 source; /**< cis source */ ++ uint16 flags; /**< flags */ ++ uint32 byteoff; /**< byte offset */ ++ uint32 nbytes; /**< number of bytes */ ++ /* data follows here */ ++} cis_rw_t; ++ ++/** R_REG and W_REG struct passed through ioctl */ ++typedef struct { ++ uint32 byteoff; /**< byte offset of the field in d11regs_t */ ++ uint32 val; /**< read/write value of the field */ ++ uint32 size; /**< sizeof the field */ ++ uint32 band; /**< band (optional) */ ++} rw_reg_t; ++ ++/** ++ * Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band ++ * PCL - Power Control Loop ++ */ ++typedef struct { ++ uint16 auto_ctrl; /**< WL_ATTEN_XX */ ++ uint16 bb; /**< Baseband attenuation */ ++ uint16 radio; /**< Radio attenuation */ ++ uint16 txctl1; /**< Radio TX_CTL1 value */ ++} atten_t; ++ ++/** Per-AC retry parameters */ ++struct wme_tx_params_s { ++ uint8 short_retry; ++ uint8 short_fallback; ++ uint8 long_retry; ++ uint8 long_fallback; ++ uint16 max_rate; /**< In units of 512 Kbps */ ++}; ++ ++typedef struct wme_tx_params_s wme_tx_params_t; ++ ++#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT) ++ ++/**Used to get specific link/ac parameters */ ++typedef struct { ++ int32 ac; ++ uint8 val; ++ struct ether_addr ea; ++ uint8 PAD; ++} link_val_t; ++ ++ ++#define WL_PM_MUTE_TX_VER 1 ++ ++typedef struct wl_pm_mute_tx { ++ uint16 version; /**< version */ ++ uint16 len; /**< length */ ++ uint16 deadline; /**< deadline timer (in milliseconds) */ ++ uint8 enable; /**< set to 1 to enable mode; set to 0 to disable it */ ++ uint8 PAD; ++} wl_pm_mute_tx_t; ++ ++ ++/* sta_info_t version 4 */ ++typedef struct { ++ uint16 ver; /**< version of this struct */ ++ uint16 len; /**< length in bytes of this structure */ ++ uint16 cap; /**< sta's advertised capabilities */ ++ uint16 PAD; ++ uint32 flags; /**< flags defined below */ ++ uint32 idle; /**< time since data pkt rx'd from sta */ ++ struct ether_addr ea; /**< Station address */ ++ uint16 PAD; ++ wl_rateset_t rateset; /**< rateset in use */ ++ uint32 in; /**< seconds elapsed since associated */ ++ uint32 listen_interval_inms; /**< Min Listen interval in ms for this STA */ ++ uint32 tx_pkts; /**< # of user packets transmitted (unicast) */ ++ uint32 tx_failures; /**< # of user packets failed */ ++ uint32 rx_ucast_pkts; /**< # of unicast packets received */ ++ uint32 rx_mcast_pkts; /**< # of multicast packets received */ ++ uint32 tx_rate; /**< Rate used by last tx frame */ ++ uint32 rx_rate; /**< Rate of last successful rx frame */ ++ uint32 rx_decrypt_succeeds; /**< # of packet decrypted successfully */ ++ uint32 rx_decrypt_failures; /**< # of packet decrypted unsuccessfully */ ++ uint32 tx_tot_pkts; /**< # of user tx pkts (ucast + mcast) */ ++ uint32 rx_tot_pkts; /**< # of data packets recvd (uni + mcast) */ ++ uint32 tx_mcast_pkts; /**< # of mcast pkts txed */ ++ uint64 tx_tot_bytes; /**< data bytes txed (ucast + mcast) */ ++ uint64 rx_tot_bytes; /**< data bytes recvd (ucast + mcast) */ ++ uint64 tx_ucast_bytes; /**< data bytes txed (ucast) */ ++ uint64 tx_mcast_bytes; /**< # data bytes txed (mcast) */ ++ uint64 rx_ucast_bytes; /**< data bytes recvd (ucast) */ ++ uint64 rx_mcast_bytes; /**< data bytes recvd (mcast) */ ++ int8 rssi[WL_STA_ANT_MAX]; /**< average rssi per antenna ++ * of data frames ++ */ ++ int8 nf[WL_STA_ANT_MAX]; /**< per antenna noise floor */ ++ uint16 aid; /**< association ID */ ++ uint16 ht_capabilities; /**< advertised ht caps */ ++ uint16 vht_flags; /**< converted vht flags */ ++ uint16 PAD; ++ uint32 tx_pkts_retried; /**< # of frames where a retry was ++ * necessary ++ */ ++ uint32 tx_pkts_retry_exhausted; /**< # of user frames where a retry ++ * was exhausted ++ */ ++ int8 rx_lastpkt_rssi[WL_STA_ANT_MAX]; /**< Per antenna RSSI of last ++ * received data frame. ++ */ ++ /* TX WLAN retry/failure statistics: ++ * Separated for host requested frames and WLAN locally generated frames. ++ * Include unicast frame only where the retries/failures can be counted. ++ */ ++ uint32 tx_pkts_total; /**< # user frames sent successfully */ ++ uint32 tx_pkts_retries; /**< # user frames retries */ ++ uint32 tx_pkts_fw_total; /**< # FW generated sent successfully */ ++ uint32 tx_pkts_fw_retries; /**< # retries for FW generated frames */ ++ uint32 tx_pkts_fw_retry_exhausted; /**< # FW generated where a retry ++ * was exhausted ++ */ ++ uint32 rx_pkts_retried; /**< # rx with retry bit set */ ++ uint32 tx_rate_fallback; /**< lowest fallback TX rate */ ++ /* Fields above this line are common to sta_info_t versions 4 and 5 */ ++ ++ uint32 rx_dur_total; /* total user RX duration (estimated) */ ++ ++ chanspec_t chanspec; /** chanspec this sta is on */ ++ uint16 PAD; ++ wl_rateset_args_t rateset_adv; /* rateset along with mcs index bitmap */ ++ uint32 PAD; ++} sta_info_v4_t; ++ ++/* Note: Version 4 is the latest version of sta_info_t. Version 5 is abandoned. ++ * Please add new fields to version 4, not version 5. ++ */ ++/* sta_info_t version 5 */ ++typedef struct { ++ uint16 ver; /**< version of this struct */ ++ uint16 len; /**< length in bytes of this structure */ ++ uint16 cap; /**< sta's advertised capabilities */ ++ uint16 PAD; ++ uint32 flags; /**< flags defined below */ ++ uint32 idle; /**< time since data pkt rx'd from sta */ ++ struct ether_addr ea; /**< Station address */ ++ uint16 PAD; ++ wl_rateset_t rateset; /**< rateset in use */ ++ uint32 in; /**< seconds elapsed since associated */ ++ uint32 listen_interval_inms; /**< Min Listen interval in ms for this STA */ ++ uint32 tx_pkts; /**< # of user packets transmitted (unicast) */ ++ uint32 tx_failures; /**< # of user packets failed */ ++ uint32 rx_ucast_pkts; /**< # of unicast packets received */ ++ uint32 rx_mcast_pkts; /**< # of multicast packets received */ ++ uint32 tx_rate; /**< Rate used by last tx frame */ ++ uint32 rx_rate; /**< Rate of last successful rx frame */ ++ uint32 rx_decrypt_succeeds; /**< # of packet decrypted successfully */ ++ uint32 rx_decrypt_failures; /**< # of packet decrypted unsuccessfully */ ++ uint32 tx_tot_pkts; /**< # of user tx pkts (ucast + mcast) */ ++ uint32 rx_tot_pkts; /**< # of data packets recvd (uni + mcast) */ ++ uint32 tx_mcast_pkts; /**< # of mcast pkts txed */ ++ uint64 tx_tot_bytes; /**< data bytes txed (ucast + mcast) */ ++ uint64 rx_tot_bytes; /**< data bytes recvd (ucast + mcast) */ ++ uint64 tx_ucast_bytes; /**< data bytes txed (ucast) */ ++ uint64 tx_mcast_bytes; /**< # data bytes txed (mcast) */ ++ uint64 rx_ucast_bytes; /**< data bytes recvd (ucast) */ ++ uint64 rx_mcast_bytes; /**< data bytes recvd (mcast) */ ++ int8 rssi[WL_STA_ANT_MAX]; /**< average rssi per antenna ++ * of data frames ++ */ ++ int8 nf[WL_STA_ANT_MAX]; /**< per antenna noise floor */ ++ uint16 aid; /**< association ID */ ++ uint16 ht_capabilities; /**< advertised ht caps */ ++ uint16 vht_flags; /**< converted vht flags */ ++ uint16 PAD; ++ uint32 tx_pkts_retried; /**< # of frames where a retry was ++ * necessary ++ */ ++ uint32 tx_pkts_retry_exhausted; /**< # of user frames where a retry ++ * was exhausted ++ */ ++ int8 rx_lastpkt_rssi[WL_STA_ANT_MAX]; /**< Per antenna RSSI of last ++ * received data frame. ++ */ ++ /* TX WLAN retry/failure statistics: ++ * Separated for host requested frames and WLAN locally generated frames. ++ * Include unicast frame only where the retries/failures can be counted. ++ */ ++ uint32 tx_pkts_total; /**< # user frames sent successfully */ ++ uint32 tx_pkts_retries; /**< # user frames retries */ ++ uint32 tx_pkts_fw_total; /**< # FW generated sent successfully */ ++ uint32 tx_pkts_fw_retries; /**< # retries for FW generated frames */ ++ uint32 tx_pkts_fw_retry_exhausted; /**< # FW generated where a retry ++ * was exhausted ++ */ ++ uint32 rx_pkts_retried; /**< # rx with retry bit set */ ++ uint32 tx_rate_fallback; /**< lowest fallback TX rate */ ++ /* Fields above this line are common to sta_info_t versions 4 and 5 */ ++ ++ chanspec_t chanspec; /** chanspec this sta is on */ ++ uint16 PAD; ++ wl_rateset_args_t rateset_adv; /* rateset along with mcs index bitmap */ ++} sta_info_v5_t; ++ ++#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_tot_pkts) ++ ++#define WL_STA_VER_4 4 ++#define WL_STA_VER_5 5 ++#define WL_STA_VER WL_STA_VER_4 ++ ++#define SWDIV_STATS_VERSION_2 2 ++#define SWDIV_STATS_CURRENT_VERSION SWDIV_STATS_VERSION_2 ++ ++struct wlc_swdiv_stats_v1 { ++ uint32 auto_en; ++ uint32 active_ant; ++ uint32 rxcount; ++ int32 avg_snr_per_ant0; ++ int32 avg_snr_per_ant1; ++ int32 avg_snr_per_ant2; ++ uint32 swap_ge_rxcount0; ++ uint32 swap_ge_rxcount1; ++ uint32 swap_ge_snrthresh0; ++ uint32 swap_ge_snrthresh1; ++ uint32 swap_txfail0; ++ uint32 swap_txfail1; ++ uint32 swap_timer0; ++ uint32 swap_timer1; ++ uint32 swap_alivecheck0; ++ uint32 swap_alivecheck1; ++ uint32 rxcount_per_ant0; ++ uint32 rxcount_per_ant1; ++ uint32 acc_rxcount; ++ uint32 acc_rxcount_per_ant0; ++ uint32 acc_rxcount_per_ant1; ++ uint32 tx_auto_en; ++ uint32 tx_active_ant; ++ uint32 rx_policy; ++ uint32 tx_policy; ++ uint32 cell_policy; ++ uint32 swap_snrdrop0; ++ uint32 swap_snrdrop1; ++ uint32 mws_antsel_ovr_tx; ++ uint32 mws_antsel_ovr_rx; ++ uint8 swap_trig_event_id; ++}; ++ ++struct wlc_swdiv_stats_v2 { ++ uint16 version; /* version of the structure ++ * as defined by SWDIV_STATS_CURRENT_VERSION ++ */ ++ uint16 length; /* length of the entire structure */ ++ uint32 auto_en; ++ uint32 active_ant; ++ uint32 rxcount; ++ int32 avg_snr_per_ant0; ++ int32 avg_snr_per_ant1; ++ int32 avg_snr_per_ant2; ++ uint32 swap_ge_rxcount0; ++ uint32 swap_ge_rxcount1; ++ uint32 swap_ge_snrthresh0; ++ uint32 swap_ge_snrthresh1; ++ uint32 swap_txfail0; ++ uint32 swap_txfail1; ++ uint32 swap_timer0; ++ uint32 swap_timer1; ++ uint32 swap_alivecheck0; ++ uint32 swap_alivecheck1; ++ uint32 rxcount_per_ant0; ++ uint32 rxcount_per_ant1; ++ uint32 acc_rxcount; ++ uint32 acc_rxcount_per_ant0; ++ uint32 acc_rxcount_per_ant1; ++ uint32 tx_auto_en; ++ uint32 tx_active_ant; ++ uint32 rx_policy; ++ uint32 tx_policy; ++ uint32 cell_policy; ++ uint32 swap_snrdrop0; ++ uint32 swap_snrdrop1; ++ uint32 mws_antsel_ovr_tx; ++ uint32 mws_antsel_ovr_rx; ++ uint32 swap_trig_event_id; ++}; ++ ++#define WLC_NUMRATES 16 /**< max # of rates in a rateset */ ++ ++/**Used to get specific STA parameters */ ++typedef struct { ++ uint32 val; ++ struct ether_addr ea; ++ uint16 PAD; ++} scb_val_t; ++ ++/**Used by iovar versions of some ioctls, i.e. WLC_SCB_AUTHORIZE et al */ ++typedef struct { ++ uint32 code; ++ scb_val_t ioctl_args; ++} authops_t; ++ ++/** channel encoding */ ++typedef struct channel_info { ++ int32 hw_channel; ++ int32 target_channel; ++ int32 scan_channel; ++} channel_info_t; ++ ++/** For ioctls that take a list of MAC addresses */ ++typedef struct maclist { ++ uint32 count; /**< number of MAC addresses */ ++ struct ether_addr ea[1]; /**< variable length array of MAC addresses */ ++} maclist_t; ++ ++/**get pkt count struct passed through ioctl */ ++typedef struct get_pktcnt { ++ uint32 rx_good_pkt; ++ uint32 rx_bad_pkt; ++ uint32 tx_good_pkt; ++ uint32 tx_bad_pkt; ++ uint32 rx_ocast_good_pkt; /**< unicast packets destined for others */ ++} get_pktcnt_t; ++ ++/* NINTENDO2 */ ++#define LQ_IDX_MIN 0 ++#define LQ_IDX_MAX 1 ++#define LQ_IDX_AVG 2 ++#define LQ_IDX_SUM 2 ++#define LQ_IDX_LAST 3 ++#define LQ_STOP_MONITOR 0 ++#define LQ_START_MONITOR 1 ++ ++/** Get averages RSSI, Rx PHY rate and SNR values */ ++/* Link Quality */ ++typedef struct { ++ int32 rssi[LQ_IDX_LAST]; /**< Array to keep min, max, avg rssi */ ++ int32 snr[LQ_IDX_LAST]; /**< Array to keep min, max, avg snr */ ++ int32 isvalid; /**< Flag indicating whether above data is valid */ ++} wl_lq_t; ++ ++typedef enum wl_wakeup_reason_type { ++ LCD_ON = 1, ++ LCD_OFF, ++ DRC1_WAKE, ++ DRC2_WAKE, ++ REASON_LAST ++} wl_wr_type_t; ++ ++typedef struct { ++ /** Unique filter id */ ++ uint32 id; ++ /** stores the reason for the last wake up */ ++ uint8 reason; ++ uint8 PAD[3]; ++} wl_wr_t; ++ ++/** Get MAC specific rate histogram command */ ++typedef struct { ++ struct ether_addr ea; /**< MAC Address */ ++ uint8 ac_cat; /**< Access Category */ ++ uint8 num_pkts; /**< Number of packet entries to be averaged */ ++} wl_mac_ratehisto_cmd_t; ++/** Get MAC rate histogram response */ ++typedef struct { ++ uint32 rate[DOT11_RATE_MAX + 1]; /**< Rates */ ++ uint32 mcs[WL_RATESET_SZ_HT_IOCTL * WL_TX_CHAINS_MAX]; /**< MCS counts */ ++ uint32 vht[WL_RATESET_SZ_VHT_MCS][WL_TX_CHAINS_MAX]; /**< VHT counts */ ++ uint32 tsf_timer[2][2]; /**< Start and End time for 8bytes value */ ++ uint32 prop11n_mcs[WLC_11N_LAST_PROP_MCS - WLC_11N_FIRST_PROP_MCS + 1]; /** MCS counts */ ++} wl_mac_ratehisto_res_t; ++ ++/* sta_info ecounters */ ++typedef struct { ++ struct ether_addr ea; /* Station MAC addr */ ++ struct ether_addr BSSID; /* BSSID of the BSS */ ++ uint32 tx_pkts_fw_total; /* # FW generated sent successfully */ ++ uint32 tx_pkts_fw_retries; /* # retries for FW generated frames */ ++ uint32 tx_pkts_fw_retry_exhausted; /* # FW generated which ++ * failed after retry ++ */ ++} sta_info_ecounters_t; ++ ++#define STAMON_MODULE_VER 1 ++ ++/**Linux network driver ioctl encoding */ ++typedef struct wl_ioctl { ++ uint32 cmd; /**< common ioctl definition */ ++ void *buf; /**< pointer to user buffer */ ++ uint32 len; /**< length of user buffer */ ++ uint8 set; /**< 1=set IOCTL; 0=query IOCTL */ ++ uint32 used; /**< bytes read or written (optional) */ ++ uint32 needed; /**< bytes needed (optional) */ ++} wl_ioctl_t; ++ ++#ifdef CONFIG_COMPAT ++typedef struct compat_wl_ioctl { ++ uint32 cmd; /**< common ioctl definition */ ++ uint32 buf; /**< pointer to user buffer */ ++ uint32 len; /**< length of user buffer */ ++ uint8 set; /**< 1=set IOCTL; 0=query IOCTL */ ++ uint32 used; /**< bytes read or written (optional) */ ++ uint32 needed; /**< bytes needed (optional) */ ++} compat_wl_ioctl_t; ++#endif /* CONFIG_COMPAT */ ++ ++#define WL_NUM_RATES_CCK 4 /**< 1, 2, 5.5, 11 Mbps */ ++#define WL_NUM_RATES_OFDM 8 /**< 6, 9, 12, 18, 24, 36, 48, 54 Mbps SISO/CDD */ ++#define WL_NUM_RATES_MCS_1STREAM 8 /**< MCS 0-7 1-stream rates - SISO/CDD/STBC/MCS */ ++#define WL_NUM_RATES_EXTRA_VHT 2 /**< Additional VHT 11AC rates */ ++#define WL_NUM_RATES_VHT 10 ++#define WL_NUM_RATES_MCS32 1 ++ ++ ++/* ++ * Structure for passing hardware and software ++ * revision info up from the driver. ++ */ ++typedef struct wlc_rev_info { ++ uint32 vendorid; /**< PCI vendor id */ ++ uint32 deviceid; /**< device id of chip */ ++ uint32 radiorev; /**< radio revision */ ++ uint32 chiprev; /**< chip revision */ ++ uint32 corerev; /**< core revision */ ++ uint32 boardid; /**< board identifier (usu. PCI sub-device id) */ ++ uint32 boardvendor; /**< board vendor (usu. PCI sub-vendor id) */ ++ uint32 boardrev; /**< board revision */ ++ uint32 driverrev; /**< driver version */ ++ uint32 ucoderev; /**< microcode version */ ++ uint32 bus; /**< bus type */ ++ uint32 chipnum; /**< chip number */ ++ uint32 phytype; /**< phy type */ ++ uint32 phyrev; /**< phy revision */ ++ uint32 anarev; /**< anacore rev */ ++ uint32 chippkg; /**< chip package info */ ++ uint32 nvramrev; /**< nvram revision number */ ++ uint32 phyminorrev; /**< phy minor rev */ ++ uint32 coreminorrev; /**< core minor rev */ ++ uint32 drvrev_major; /**< driver version: major */ ++ uint32 drvrev_minor; /**< driver version: minor */ ++ uint32 drvrev_rc; /**< driver version: rc */ ++ uint32 drvrev_rc_inc; /**< driver version: rc incremental */ ++} wlc_rev_info_t; ++ ++#define WL_REV_INFO_LEGACY_LENGTH 48 ++ ++#define WL_BRAND_MAX 10 ++typedef struct wl_instance_info { ++ uint32 instance; ++ int8 brand[WL_BRAND_MAX]; ++ int8 PAD[4-(WL_BRAND_MAX%4)]; ++} wl_instance_info_t; ++ ++/** structure to change size of tx fifo */ ++typedef struct wl_txfifo_sz { ++ uint16 magic; ++ uint16 fifo; ++ uint16 size; ++} wl_txfifo_sz_t; ++ ++/* Transfer info about an IOVar from the driver */ ++/**Max supported IOV name size in bytes, + 1 for nul termination */ ++#define WLC_IOV_NAME_LEN (32 + 1) ++ ++typedef struct wlc_iov_trx_s { ++ uint8 module; ++ uint8 type; ++ char name[WLC_IOV_NAME_LEN]; ++} wlc_iov_trx_t; ++ ++/** bump this number if you change the ioctl interface */ ++#define WLC_IOCTL_VERSION 2 ++#define WLC_IOCTL_VERSION_LEGACY_IOTYPES 1 ++/* ifdef EXT_STA */ ++typedef struct _wl_assoc_result { ++ ulong associated; ++ ulong NDIS_auth; ++ ulong NDIS_infra; ++} wl_assoc_result_t; ++/* EXT_STA */ ++ ++#define WL_PHY_PAVARS_LEN 32 /**< Phytype, Bandrange, chain, a[0], b[0], c[0], d[0] .. */ ++ ++ ++#define WL_PHY_PAVAR_VER 1 /**< pavars version */ ++#define WL_PHY_PAVARS2_NUM 3 /**< a1, b0, b1 */ ++typedef struct wl_pavars2 { ++ uint16 ver; /**< version of this struct */ ++ uint16 len; /**< len of this structure */ ++ uint16 inuse; /**< driver return 1 for a1,b0,b1 in current band range */ ++ uint16 phy_type; /**< phy type */ ++ uint16 bandrange; ++ uint16 chain; ++ uint16 inpa[WL_PHY_PAVARS2_NUM]; /**< phy pavars for one band range */ ++} wl_pavars2_t; ++ ++typedef struct wl_po { ++ uint16 phy_type; /**< Phy type */ ++ uint16 band; ++ uint16 cckpo; ++ uint16 PAD; ++ uint32 ofdmpo; ++ uint16 mcspo[8]; ++} wl_po_t; ++ ++#define WL_NUM_RPCALVARS 5 /**< number of rpcal vars */ ++ ++typedef struct wl_rpcal { ++ uint16 value; ++ uint16 update; ++} wl_rpcal_t; ++ ++#define WL_NUM_RPCALPHASEVARS 5 /* number of rpcal phase vars */ ++ ++typedef struct wl_rpcal_phase { ++ uint16 value; ++ uint16 update; ++} wl_rpcal_phase_t; ++ ++typedef struct wl_aci_args { ++ int32 enter_aci_thresh; /* Trigger level to start detecting ACI */ ++ int32 exit_aci_thresh; /* Trigger level to exit ACI mode */ ++ int32 usec_spin; /* microsecs to delay between rssi samples */ ++ int32 glitch_delay; /* interval between ACI scans when glitch count is consistently high */ ++ uint16 nphy_adcpwr_enter_thresh; /**< ADC power to enter ACI mitigation mode */ ++ uint16 nphy_adcpwr_exit_thresh; /**< ADC power to exit ACI mitigation mode */ ++ uint16 nphy_repeat_ctr; /**< Number of tries per channel to compute power */ ++ uint16 nphy_num_samples; /**< Number of samples to compute power on one channel */ ++ uint16 nphy_undetect_window_sz; /**< num of undetects to exit ACI Mitigation mode */ ++ uint16 nphy_b_energy_lo_aci; /**< low ACI power energy threshold for bphy */ ++ uint16 nphy_b_energy_md_aci; /**< mid ACI power energy threshold for bphy */ ++ uint16 nphy_b_energy_hi_aci; /**< high ACI power energy threshold for bphy */ ++ uint16 nphy_noise_noassoc_glitch_th_up; /**< wl interference 4 */ ++ uint16 nphy_noise_noassoc_glitch_th_dn; ++ uint16 nphy_noise_assoc_glitch_th_up; ++ uint16 nphy_noise_assoc_glitch_th_dn; ++ uint16 nphy_noise_assoc_aci_glitch_th_up; ++ uint16 nphy_noise_assoc_aci_glitch_th_dn; ++ uint16 nphy_noise_assoc_enter_th; ++ uint16 nphy_noise_noassoc_enter_th; ++ uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th; ++ uint16 nphy_noise_noassoc_crsidx_incr; ++ uint16 nphy_noise_assoc_crsidx_incr; ++ uint16 nphy_noise_crsidx_decr; ++} wl_aci_args_t; ++ ++#define WL_ACI_ARGS_LEGACY_LENGTH 16 /**< bytes of pre NPHY aci args */ ++#define WL_SAMPLECOLLECT_T_VERSION 2 /**< version of wl_samplecollect_args_t struct */ ++typedef struct wl_samplecollect_args { ++ /* version 0 fields */ ++ uint8 coll_us; ++ uint8 PAD[3]; ++ int32 cores; ++ /* add'l version 1 fields */ ++ uint16 version; /**< see definition of WL_SAMPLECOLLECT_T_VERSION */ ++ uint16 length; /**< length of entire structure */ ++ int8 trigger; ++ uint8 PAD; ++ uint16 timeout; ++ uint16 mode; ++ uint16 PAD; ++ uint32 pre_dur; ++ uint32 post_dur; ++ uint8 gpio_sel; ++ uint8 downsamp; ++ uint8 be_deaf; ++ uint8 agc; /**< loop from init gain and going down */ ++ uint8 filter; /**< override high pass corners to lowest */ ++ /* add'l version 2 fields */ ++ uint8 trigger_state; ++ uint8 module_sel1; ++ uint8 module_sel2; ++ uint16 nsamps; ++ uint16 PAD; ++ int32 bitStart; ++ uint32 gpioCapMask; ++ uint8 gpio_collection; ++ uint8 PAD[3]; ++} wl_samplecollect_args_t; ++ ++#define WL_SAMPLEDATA_T_VERSION 1 /**< version of wl_samplecollect_args_t struct */ ++/* version for unpacked sample data, int16 {(I,Q),Core(0..N)} */ ++#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2 ++ ++typedef struct wl_sampledata { ++ uint16 version; /**< structure version */ ++ uint16 size; /**< size of structure */ ++ uint16 tag; /**< Header/Data */ ++ uint16 length; /**< data length */ ++ uint32 flag; /**< bit def */ ++} wl_sampledata_t; ++ ++ ++/* WL_OTA START */ ++/* OTA Test Status */ ++enum { ++ WL_OTA_TEST_IDLE = 0, /**< Default Idle state */ ++ WL_OTA_TEST_ACTIVE = 1, /**< Test Running */ ++ WL_OTA_TEST_SUCCESS = 2, /**< Successfully Finished Test */ ++ WL_OTA_TEST_FAIL = 3 /**< Test Failed in the Middle */ ++}; ++ ++/* OTA SYNC Status */ ++enum { ++ WL_OTA_SYNC_IDLE = 0, /**< Idle state */ ++ WL_OTA_SYNC_ACTIVE = 1, /**< Waiting for Sync */ ++ WL_OTA_SYNC_FAIL = 2 /**< Sync pkt not recieved */ ++}; ++ ++/* Various error states dut can get stuck during test */ ++enum { ++ WL_OTA_SKIP_TEST_CAL_FAIL = 1, /**< Phy calibration failed */ ++ WL_OTA_SKIP_TEST_SYNCH_FAIL = 2, /**< Sync Packet not recieved */ ++ WL_OTA_SKIP_TEST_FILE_DWNLD_FAIL = 3, /**< Cmd flow file download failed */ ++ WL_OTA_SKIP_TEST_NO_TEST_FOUND = 4, /**< No test found in Flow file */ ++ WL_OTA_SKIP_TEST_WL_NOT_UP = 5, /**< WL UP failed */ ++ WL_OTA_SKIP_TEST_UNKNOWN_CALL /**< Unintentional scheduling on ota test */ ++}; ++ ++/* Differentiator for ota_tx and ota_rx */ ++enum { ++ WL_OTA_TEST_TX = 0, /**< ota_tx */ ++ WL_OTA_TEST_RX = 1, /**< ota_rx */ ++}; ++ ++/* Catch 3 modes of operation: 20Mhz, 40Mhz, 20 in 40 Mhz */ ++enum { ++ WL_OTA_TEST_BW_20_IN_40MHZ = 0, /**< 20 in 40 operation */ ++ WL_OTA_TEST_BW_20MHZ = 1, /**< 20 Mhz operation */ ++ WL_OTA_TEST_BW_40MHZ = 2, /**< full 40Mhz operation */ ++ WL_OTA_TEST_BW_80MHZ = 3 /* full 80Mhz operation */ ++}; ++#define HT_MCS_INUSE 0x00000080 /* HT MCS in use,indicates b0-6 holds an mcs */ ++#define VHT_MCS_INUSE 0x00000100 /* VHT MCS in use,indicates b0-6 holds an mcs */ ++#define OTA_RATE_MASK 0x0000007f /* rate/mcs value */ ++#define OTA_STF_SISO 0 ++#define OTA_STF_CDD 1 ++#define OTA_STF_STBC 2 ++#define OTA_STF_SDM 3 ++ ++typedef struct ota_rate_info { ++ uint8 rate_cnt; /**< Total number of rates */ ++ uint8 PAD; ++ uint16 rate_val_mbps[WL_OTA_TEST_MAX_NUM_RATE]; /**< array of rates from 1mbps to 130mbps */ ++ /**< for legacy rates : ratein mbps * 2 */ ++ /**< for HT rates : mcs index */ ++} ota_rate_info_t; ++ ++typedef struct ota_power_info { ++ int8 pwr_ctrl_on; /**< power control on/off */ ++ int8 start_pwr; /**< starting power/index */ ++ int8 delta_pwr; /**< delta power/index */ ++ int8 end_pwr; /**< end power/index */ ++} ota_power_info_t; ++ ++typedef struct ota_packetengine { ++ uint16 delay; /**< Inter-packet delay */ ++ /**< for ota_tx, delay is tx ifs in micro seconds */ ++ /* for ota_rx, delay is wait time in milliseconds */ ++ uint16 nframes; /**< Number of frames */ ++ uint16 length; /**< Packet length */ ++} ota_packetengine_t; ++ ++/* ++ * OTA txant/rxant parameter ++ * bit7-4: 4 bits swdiv_tx/rx_policy bitmask, specify antenna-policy for SW diversity ++ * bit3-0: 4 bits TxCore bitmask, specify cores used for transmit frames ++ * (maximum spatial expansion) ++ */ ++#define WL_OTA_TEST_ANT_MASK 0xF0 ++#define WL_OTA_TEST_CORE_MASK 0x0F ++ ++/* OTA txant/rxant 'ant_mask' field; map to Tx/Rx antenna policy for SW diversity */ ++enum { ++ WL_OTA_TEST_FORCE_ANT0 = 0x10, /* force antenna to Ant 0 */ ++ WL_OTA_TEST_FORCE_ANT1 = 0x20, /* force antenna to Ant 1 */ ++}; ++ ++/* antenna/core fields access */ ++#define WL_OTA_TEST_GET_ANT(_txant) ((_txant) & WL_OTA_TEST_ANT_MASK) ++#define WL_OTA_TEST_GET_CORE(_txant) ((_txant) & WL_OTA_TEST_CORE_MASK) ++ ++/** Test info vector */ ++typedef struct wl_ota_test_args { ++ uint8 cur_test; /**< test phase */ ++ uint8 chan; /**< channel */ ++ uint8 bw; /**< bandwidth */ ++ uint8 control_band; /**< control band */ ++ uint8 stf_mode; /**< stf mode */ ++ uint8 PAD; ++ ota_rate_info_t rt_info; /**< Rate info */ ++ ota_packetengine_t pkteng; /**< packeteng info */ ++ uint8 txant; /**< tx antenna */ ++ uint8 rxant; /**< rx antenna */ ++ ota_power_info_t pwr_info; /**< power sweep info */ ++ uint8 wait_for_sync; /**< wait for sync or not */ ++ uint8 ldpc; ++ uint8 sgi; ++ uint8 PAD; ++ /* Update WL_OTA_TESTVEC_T_VERSION for adding new members to this structure */ ++} wl_ota_test_args_t; ++ ++#define WL_OTA_TESTVEC_T_VERSION 1 /* version of wl_ota_test_vector_t struct */ ++typedef struct wl_ota_test_vector { ++ uint16 version; ++ wl_ota_test_args_t test_arg[WL_OTA_TEST_MAX_NUM_SEQ]; /**< Test argument struct */ ++ uint16 test_cnt; /**< Total no of test */ ++ uint8 file_dwnld_valid; /**< File successfully downloaded */ ++ uint8 sync_timeout; /**< sync packet timeout */ ++ int8 sync_fail_action; /**< sync fail action */ ++ struct ether_addr sync_mac; /**< macaddress for sync pkt */ ++ struct ether_addr tx_mac; /**< macaddress for tx */ ++ struct ether_addr rx_mac; /**< macaddress for rx */ ++ int8 loop_test; /**< dbg feature to loop the test */ ++ uint16 test_rxcnt; ++ /* Update WL_OTA_TESTVEC_T_VERSION for adding new members to this structure */ ++} wl_ota_test_vector_t; ++ ++ ++/** struct copied back form dongle to host to query the status */ ++typedef struct wl_ota_test_status { ++ int16 cur_test_cnt; /**< test phase */ ++ int8 skip_test_reason; /**< skip test reasoin */ ++ uint8 PAD; ++ wl_ota_test_args_t test_arg; /**< cur test arg details */ ++ uint16 test_cnt; /**< total no of test downloaded */ ++ uint8 file_dwnld_valid; /**< file successfully downloaded ? */ ++ uint8 sync_timeout; /**< sync timeout */ ++ int8 sync_fail_action; /**< sync fail action */ ++ struct ether_addr sync_mac; /**< macaddress for sync pkt */ ++ struct ether_addr tx_mac; /**< tx mac address */ ++ struct ether_addr rx_mac; /**< rx mac address */ ++ uint8 test_stage; /**< check the test status */ ++ int8 loop_test; /**< Debug feature to puts test enfine in a loop */ ++ uint8 sync_status; /**< sync status */ ++} wl_ota_test_status_t; ++ ++/* FOR ioctl that take the sta monitor information */ ++typedef struct stamon_data { ++ struct ether_addr ea; ++ uint8 PAD[2]; ++ int32 rssi; ++} stamon_data_t; ++ ++typedef struct stamon_info { ++ int32 version; ++ uint32 count; ++ stamon_data_t sta_data[1]; ++} stamon_info_t; ++ ++typedef struct wl_ota_rx_rssi { ++ uint16 pktcnt; /* Pkt count used for this rx test */ ++ chanspec_t chanspec; /* Channel info on which the packets are received */ ++ int16 rssi; /* Average RSSI of the first 50% packets received */ ++} wl_ota_rx_rssi_t; ++ ++#define WL_OTARSSI_T_VERSION 1 /* version of wl_ota_test_rssi_t struct */ ++#define WL_OTA_TEST_RSSI_FIXED_SIZE OFFSETOF(wl_ota_test_rssi_t, rx_rssi) ++ ++typedef struct wl_ota_test_rssi { ++ uint8 version; ++ uint8 testcnt; /* total measured RSSI values, valid on output only */ ++ wl_ota_rx_rssi_t rx_rssi[1]; /* Variable length array of wl_ota_rx_rssi_t */ ++} wl_ota_test_rssi_t; ++ ++/* WL_OTA END */ ++ ++/**wl_radar_args_t */ ++typedef struct { ++ int32 npulses; /**< required number of pulses at n * t_int */ ++ int32 ncontig; /**< required number of pulses at t_int */ ++ int32 min_pw; /**< minimum pulse width (20 MHz clocks) */ ++ int32 max_pw; /**< maximum pulse width (20 MHz clocks) */ ++ uint16 thresh0; /**< Radar detection, thresh 0 */ ++ uint16 thresh1; /**< Radar detection, thresh 1 */ ++ uint16 blank; /**< Radar detection, blank control */ ++ uint16 fmdemodcfg; /**< Radar detection, fmdemod config */ ++ int32 npulses_lp; /**< Radar detection, minimum long pulses */ ++ int32 min_pw_lp; /**< Minimum pulsewidth for long pulses */ ++ int32 max_pw_lp; /**< Maximum pulsewidth for long pulses */ ++ int32 min_fm_lp; /**< Minimum fm for long pulses */ ++ int32 max_span_lp; /**< Maximum deltat for long pulses */ ++ int32 min_deltat; /**< Minimum spacing between pulses */ ++ int32 max_deltat; /**< Maximum spacing between pulses */ ++ uint16 autocorr; /**< Radar detection, autocorr on or off */ ++ uint16 st_level_time; /**< Radar detection, start_timing level */ ++ uint16 t2_min; /**< minimum clocks needed to remain in state 2 */ ++ uint8 PAD[2]; ++ uint32 version; /**< version */ ++ uint32 fra_pulse_err; /**< sample error margin for detecting French radar pulsed */ ++ int32 npulses_fra; /**< Radar detection, minimum French pulses set */ ++ int32 npulses_stg2; /**< Radar detection, minimum staggered-2 pulses set */ ++ int32 npulses_stg3; /**< Radar detection, minimum staggered-3 pulses set */ ++ uint16 percal_mask; /**< defines which period cal is masked from radar detection */ ++ uint8 PAD[2]; ++ int32 quant; /**< quantization resolution to pulse positions */ ++ uint32 min_burst_intv_lp; /**< minimum burst to burst interval for bin3 radar */ ++ uint32 max_burst_intv_lp; /**< maximum burst to burst interval for bin3 radar */ ++ int32 nskip_rst_lp; /**< number of skipped pulses before resetting lp buffer */ ++ int32 max_pw_tol; /* maximum tolerance allowd in detected pulse width for radar detection */ ++ uint16 feature_mask; /**< 16-bit mask to specify enabled features */ ++ uint16 thresh0_sc; /**< Radar detection, thresh 0 */ ++ uint16 thresh1_sc; /**< Radar detection, thresh 1 */ ++ uint8 PAD[2]; ++} wl_radar_args_t; ++ ++#define WL_RADAR_ARGS_VERSION 2 ++ ++typedef struct { ++ uint32 version; /**< version */ ++ uint16 thresh0_20_lo; /**< Radar detection, thresh 0 (range 5250-5350MHz) for BW 20MHz */ ++ uint16 thresh1_20_lo; /**< Radar detection, thresh 1 (range 5250-5350MHz) for BW 20MHz */ ++ uint16 thresh0_40_lo; /**< Radar detection, thresh 0 (range 5250-5350MHz) for BW 40MHz */ ++ uint16 thresh1_40_lo; /**< Radar detection, thresh 1 (range 5250-5350MHz) for BW 40MHz */ ++ uint16 thresh0_80_lo; /**< Radar detection, thresh 0 (range 5250-5350MHz) for BW 80MHz */ ++ uint16 thresh1_80_lo; /**< Radar detection, thresh 1 (range 5250-5350MHz) for BW 80MHz */ ++ uint16 thresh0_20_hi; /**< Radar detection, thresh 0 (range 5470-5725MHz) for BW 20MHz */ ++ uint16 thresh1_20_hi; /**< Radar detection, thresh 1 (range 5470-5725MHz) for BW 20MHz */ ++ uint16 thresh0_40_hi; /**< Radar detection, thresh 0 (range 5470-5725MHz) for BW 40MHz */ ++ uint16 thresh1_40_hi; /**< Radar detection, thresh 1 (range 5470-5725MHz) for BW 40MHz */ ++ uint16 thresh0_80_hi; /**< Radar detection, thresh 0 (range 5470-5725MHz) for BW 80MHz */ ++ uint16 thresh1_80_hi; /**< Radar detection, thresh 1 (range 5470-5725MHz) for BW 80MHz */ ++ uint16 thresh0_160_lo; /**< Radar detection, thresh 0 (range 5250-5350MHz) for BW 160MHz */ ++ uint16 thresh1_160_lo; /**< Radar detection, thresh 1 (range 5250-5350MHz) for BW 160MHz */ ++ uint16 thresh0_160_hi; /**< Radar detection, thresh 0 (range 5470-5725MHz) for BW 160MHz */ ++ uint16 thresh1_160_hi; /**< Radar detection, thresh 1 (range 5470-5725MHz) for BW 160MHz */ ++} wl_radar_thr_t; ++ ++typedef struct { ++ uint32 version; /* version */ ++ uint16 thresh0_sc_20_lo; ++ uint16 thresh1_sc_20_lo; ++ uint16 thresh0_sc_40_lo; ++ uint16 thresh1_sc_40_lo; ++ uint16 thresh0_sc_80_lo; ++ uint16 thresh1_sc_80_lo; ++ uint16 thresh0_sc_20_hi; ++ uint16 thresh1_sc_20_hi; ++ uint16 thresh0_sc_40_hi; ++ uint16 thresh1_sc_40_hi; ++ uint16 thresh0_sc_80_hi; ++ uint16 thresh1_sc_80_hi; ++ uint16 fc_varth_sb; ++ uint16 fc_varth_bin5_sb; ++ uint16 notradar_enb; ++ uint16 max_notradar_lp; ++ uint16 max_notradar; ++ uint16 max_notradar_lp_sc; ++ uint16 max_notradar_sc; ++ uint16 highpow_war_enb; ++ uint16 highpow_sp_ratio; //unit is 0.5 ++} wl_radar_thr2_t; ++ ++#define WL_RADAR_THR_VERSION 2 ++ ++typedef struct { ++ uint32 ver; ++ uint32 len; ++ int32 rssi_th[3]; ++ uint8 rssi_gain_80[4]; ++ uint8 rssi_gain_160[4]; ++} wl_dyn_switch_th_t; ++ ++#define WL_PHY_DYN_SWITCH_TH_VERSION 1 ++ ++/** RSSI per antenna */ ++typedef struct { ++ uint32 version; /**< version field */ ++ uint32 count; /**< number of valid antenna rssi */ ++ int8 rssi_ant[WL_RSSI_ANT_MAX]; /**< rssi per antenna */ ++} wl_rssi_ant_t; ++ ++/* SNR per antenna */ ++typedef struct { ++ uint32 version; /* version field */ ++ uint32 count; /* number of valid antenna snr */ ++ int8 snr_ant[WL_RSSI_ANT_MAX]; /* snr per antenna */ ++} wl_snr_ant_t; ++ ++ ++/** data structure used in 'dfs_status' wl interface, which is used to query dfs status */ ++typedef struct { ++ uint32 state; /**< noted by WL_DFS_CACSTATE_XX. */ ++ uint32 duration; /**< time spent in ms in state. */ ++ /** ++ * as dfs enters ISM state, it removes the operational channel from quiet channel ++ * list and notes the channel in channel_cleared. set to 0 if no channel is cleared ++ */ ++ chanspec_t chanspec_cleared; ++ /** chanspec cleared used to be a uint32, add another to uint16 to maintain size */ ++ uint16 pad; ++} wl_dfs_status_t; ++ ++typedef struct { ++ uint32 state; /* noted by WL_DFS_CACSTATE_XX */ ++ uint32 duration; /* time spent in ms in state */ ++ chanspec_t chanspec; /* chanspec of this core */ ++ chanspec_t chanspec_last_cleared; /* chanspec last cleared for operation by scanning */ ++ uint16 sub_type; /* currently just the index of the core or the respective PLL */ ++ uint16 pad; ++} wl_dfs_sub_status_t; ++ ++#define WL_DFS_STATUS_ALL_VERSION (1) ++typedef struct { ++ uint16 version; /* version field; current max version 1 */ ++ uint16 num_sub_status; ++ wl_dfs_sub_status_t dfs_sub_status[1]; /* struct array of length num_sub_status */ ++} wl_dfs_status_all_t; ++ ++#define WL_DFS_AP_MOVE_VERSION (1) ++ ++struct wl_dfs_ap_move_status_v1 { ++ int16 dfs_status; /* DFS scan status */ ++ chanspec_t chanspec; /* New AP Chanspec */ ++ wl_dfs_status_t cac_status; /* CAC status */ ++}; ++ ++typedef struct wl_dfs_ap_move_status_v2 { ++ int8 version; /* version field; current max version 1 */ ++ int8 move_status; /* DFS move status */ ++ chanspec_t chanspec; /* New AP Chanspec */ ++ wl_dfs_status_all_t scan_status; /* status; see dfs_status_all for wl_dfs_status_all_t */ ++} wl_dfs_ap_move_status_v2_t; ++ ++#define WL_DFS_AP_MOVE_ABORT -1 /* Abort any dfs_ap_move in progress immediately */ ++#define WL_DFS_AP_MOVE_STUNT -2 /* Stunt move but continue background CSA if in progress */ ++ ++ ++/** data structure used in 'radar_status' wl interface, which is use to query radar det status */ ++typedef struct { ++ uint8 detected; ++ uint8 PAD[3]; ++ int32 count; ++ uint8 pretended; ++ uint8 PAD[3]; ++ uint32 radartype; ++ uint32 timenow; ++ uint32 timefromL; ++ int32 lp_csect_single; ++ int32 detected_pulse_index; ++ int32 nconsecq_pulses; ++ chanspec_t ch; ++ uint8 PAD[2]; ++ int32 pw[10]; ++ int32 intv[10]; ++ int32 fm[10]; ++} wl_radar_status_t; ++ ++#define NUM_PWRCTRL_RATES 12 ++ ++typedef struct { ++ uint8 txpwr_band_max[NUM_PWRCTRL_RATES]; /**< User set target */ ++ uint8 txpwr_limit[NUM_PWRCTRL_RATES]; /**< reg and local power limit */ ++ uint8 txpwr_local_max; /**< local max according to the AP */ ++ uint8 txpwr_local_constraint; /**< local constraint according to the AP */ ++ uint8 txpwr_chan_reg_max; /**< Regulatory max for this channel */ ++ uint8 txpwr_target[2][NUM_PWRCTRL_RATES]; /**< Latest target for 2.4 and 5 Ghz */ ++ uint8 txpwr_est_Pout[2]; /**< Latest estimate for 2.4 and 5 Ghz */ ++ uint8 txpwr_opo[NUM_PWRCTRL_RATES]; /**< On G phy, OFDM power offset */ ++ uint8 txpwr_bphy_cck_max[NUM_PWRCTRL_RATES]; /**< Max CCK power for this band (SROM) */ ++ uint8 txpwr_bphy_ofdm_max; /**< Max OFDM power for this band (SROM) */ ++ uint8 txpwr_aphy_max[NUM_PWRCTRL_RATES]; /**< Max power for A band (SROM) */ ++ int8 txpwr_antgain[2]; /**< Ant gain for each band - from SROM */ ++ uint8 txpwr_est_Pout_gofdm; /**< Pwr estimate for 2.4 OFDM */ ++} tx_power_legacy_t; ++ ++#define WL_TX_POWER_RATES_LEGACY 45 ++#define WL_TX_POWER_MCS20_FIRST 12 ++#define WL_TX_POWER_MCS20_NUM 16 ++#define WL_TX_POWER_MCS40_FIRST 28 ++#define WL_TX_POWER_MCS40_NUM 17 ++ ++typedef struct { ++ uint32 flags; ++ chanspec_t chanspec; /**< txpwr report for this channel */ ++ chanspec_t local_chanspec; /**< channel on which we are associated */ ++ uint8 local_max; /**< local max according to the AP */ ++ uint8 local_constraint; /**< local constraint according to the AP */ ++ int8 antgain[2]; /**< Ant gain for each band - from SROM */ ++ uint8 rf_cores; /**< count of RF Cores being reported */ ++ uint8 est_Pout[4]; /**< Latest tx power out estimate per RF ++ * chain without adjustment ++ */ ++ uint8 est_Pout_cck; /**< Latest CCK tx power out estimate */ ++ uint8 user_limit[WL_TX_POWER_RATES_LEGACY]; /**< User limit */ ++ uint8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /**< Regulatory power limit */ ++ uint8 board_limit[WL_TX_POWER_RATES_LEGACY]; /**< Max power board can support (SROM) */ ++ uint8 target[WL_TX_POWER_RATES_LEGACY]; /**< Latest target power */ ++ uint8 PAD[2]; ++} tx_power_legacy2_t; ++ ++#define WL_NUM_2x2_ELEMENTS 4 ++#define WL_NUM_3x3_ELEMENTS 6 ++#define WL_NUM_4x4_ELEMENTS 10 ++ ++typedef struct { ++ uint16 ver; /**< version of this struct */ ++ uint16 len; /**< length in bytes of this structure */ ++ uint32 flags; ++ chanspec_t chanspec; /**< txpwr report for this channel */ ++ chanspec_t local_chanspec; /**< channel on which we are associated */ ++ uint32 buflen; /**< ppr buffer length */ ++ uint8 pprbuf[1]; /**< Latest target power buffer */ ++} wl_txppr_t; ++ ++#define WL_TXPPR_VERSION 1 ++#define WL_TXPPR_LENGTH (sizeof(wl_txppr_t)) ++#define TX_POWER_T_VERSION 45 ++/** number of ppr serialization buffers, it should be reg, board and target */ ++#define WL_TXPPR_SER_BUF_NUM (3) ++ ++typedef struct chanspec_txpwr_max { ++ chanspec_t chanspec; /**< chanspec */ ++ uint8 txpwr_max; /**< max txpwr in all the rates */ ++ uint8 padding; ++} chanspec_txpwr_max_t; ++ ++typedef struct wl_chanspec_txpwr_max { ++ uint16 ver; /**< version of this struct */ ++ uint16 len; /**< length in bytes of this structure */ ++ uint32 count; /**< number of elements of (chanspec, txpwr_max) pair */ ++ chanspec_txpwr_max_t txpwr[1]; /**< array of (chanspec, max_txpwr) pair */ ++} wl_chanspec_txpwr_max_t; ++ ++#define WL_CHANSPEC_TXPWR_MAX_VER 1 ++#define WL_CHANSPEC_TXPWR_MAX_LEN (sizeof(wl_chanspec_txpwr_max_t)) ++ ++typedef struct tx_inst_power { ++ uint8 txpwr_est_Pout[2]; /**< Latest estimate for 2.4 and 5 Ghz */ ++ uint8 txpwr_est_Pout_gofdm; /**< Pwr estimate for 2.4 OFDM */ ++} tx_inst_power_t; ++ ++#define WL_NUM_TXCHAIN_MAX 4 ++typedef struct wl_txchain_pwr_offsets { ++ int8 offset[WL_NUM_TXCHAIN_MAX]; /**< quarter dBm signed offset for each chain */ ++} wl_txchain_pwr_offsets_t; ++ ++/** maximum channels returned by the get valid channels iovar */ ++#define WL_NUMCHANNELS 64 ++#define WL_NUMCHANNELS_MANY_CHAN 10 ++#define WL_ITER_LIMIT_MANY_CHAN 5 ++ ++#define WL_MIMO_PS_CFG_VERSION_1 1 ++ ++typedef struct wl_mimops_cfg { ++ uint8 version; ++ /* active_chains: 0 for all, 1 for 1 chain. */ ++ uint8 active_chains; ++ /* static (0) or dynamic (1).or disabled (3) Mode applies only when active_chains = 0. */ ++ uint8 mode; ++ /* bandwidth = Full (0), 20M (1), 40M (2), 80M (3). */ ++ uint8 bandwidth; ++ uint8 applychangesafterlearning; ++ uint8 pad[3]; ++} wl_mimops_cfg_t; ++ ++/* This event is for tracing MIMO PS metrics snapshot calls. ++ * It is helpful to debug out-of-sync issue between ++ * ucode SHM values and FW snapshot calculation. ++ * It is part of the EVENT_LOG_TAG_MIMO_PS_TRACE. ++ */ ++#define WL_MIMO_PS_METRICS_SNAPSHOT_TRACE_TYPE 0 ++typedef struct wl_mimo_ps_metrics_snapshot_trace { ++ /* type field for this TLV: */ ++ uint16 type; ++ /* length field for this TLV */ ++ uint16 len; ++ uint32 idle_slotcnt_mimo; /* MIMO idle slotcnt raw SHM value */ ++ uint32 last_idle_slotcnt_mimo; /* stored value snapshot */ ++ uint32 idle_slotcnt_siso; /* SISO idle slotcnt raw SHM value */ ++ uint32 last_idle_slotcnt_siso; /* stored value snapshot */ ++ uint32 rx_time_mimo; /* Rx MIMO raw SHM value */ ++ uint32 last_rx_time_mimo; /* stored value snapshot */ ++ uint32 rx_time_siso; /* RX SISO raw SHM value */ ++ uint32 last_rx_time_siso; /* stored value snapshot */ ++ uint32 tx_time_1chain; /* Tx 1-chain raw SHM value */ ++ uint32 last_tx_time_1chain; /* stored value snapshot */ ++ uint32 tx_time_2chain; /* Tx 2-chain raw SHM value */ ++ uint32 last_tx_time_2chain; /* stored value snapshot */ ++ uint32 tx_time_3chain; /* Tx 3-chain raw SHM value */ ++ uint32 last_tx_time_3chain; /* stored value snapshot */ ++ uint16 reason; /* reason for snapshot call, see below */ ++ /* Does the call reset last values after delta calculation */ ++ uint16 reset_last; ++} wl_mimo_ps_metrics_snapshot_trace_t; ++/* reason codes for mimo ps metrics snapshot function calls */ ++#define WL_MIMOPS_METRICS_SNAPSHOT_REPORT 1 ++#define WL_MIMOPS_METRICS_SNAPSHOT_RXCHAIN_SET 2 ++#define WL_MIMOPS_METRICS_SNAPSHOT_ARBI 3 ++#define WL_MIMOPS_METRICS_SNAPSHOT_SLOTUPD 4 ++#define WL_MIMOPS_METRICS_SNAPSHOT_PMBCNRX 5 ++#define WL_MIMOPS_METRICS_SNAPSHOT_BMACINIT 6 ++#define WL_MIMOPS_METRICS_SNAPSHOT_HT_COMPLETE 7 ++#define WL_MIMOPS_METRICS_SNAPSHOT_OCL 8 ++ ++#define WL_MIMO_PS_STATUS_VERSION_2 2 ++typedef struct wl_mimo_ps_status { ++ uint8 version; ++ uint8 ap_cap; /* The associated AP's capability (BW, MIMO/SISO). */ ++ uint8 association_status; /* How we are associated to the AP (MIMO/SISO). */ ++ uint8 mimo_ps_state; /* mimo_ps_cfg states: [0-5]. See below for values */ ++ uint8 mrc_state; /* MRC state: NONE (0), ACTIVE(1) */ ++ uint8 bss_rxchain; /* bss rxchain bitmask */ ++ uint8 bss_txchain; /* bss txchain bitmask */ ++ uint8 bss_bw; /* bandwidth: Full (0), 20M (1), 40M (2), 80M (3), etc */ ++ uint16 hw_state; /* bitmask of hw state. See below for values */ ++ uint8 hw_rxchain; /* actual HW rxchain bitmask */ ++ uint8 hw_txchain; /* actual HW txchain bitmask */ ++ uint8 hw_bw; /* bandwidth: Full (0), 20M (1), 40M (2), 80M (3), etc */ ++ uint8 pm_bcnrx_state; /* actual state of ucode flag */ ++ uint8 basic_rates_present; /* internal flag to trigger siso bcmc rx */ ++ uint8 siso_bcmc_rx_state; /* actual state of ucode flag */ ++} wl_mimo_ps_status_t; ++ ++#define WL_MIMO_PS_STATUS_VERSION_1 1 ++typedef struct wl_mimo_ps_status_v1 { ++ uint8 version; ++ uint8 ap_cap; /* The associated AP's capability (BW, MIMO/SISO). */ ++ uint8 association_status; /* How we are associated to the AP (MIMO/SISO). */ ++ uint8 mimo_ps_state; /* mimo_ps_cfg states: [0-5]. See below for values */ ++ uint8 mrc_state; /* MRC state: NONE (0), ACTIVE(1) */ ++ uint8 bss_rxchain; /* bss rxchain bitmask */ ++ uint8 bss_txchain; /* bss txchain bitmask */ ++ uint8 bss_bw; /* bandwidth: Full (0), 20M (1), 40M (2), 80M (3), etc */ ++ uint16 hw_state; /* bitmask of hw state. See below for values */ ++ uint8 hw_rxchain; /* actual HW rxchain bitmask */ ++ uint8 hw_txchain; /* actual HW txchain bitmask */ ++ uint8 hw_bw; /* bandwidth: Full (0), 20M (1), 40M (2), 80M (3), etc */ ++ uint8 pad[3]; ++} wl_mimo_ps_status_v1_t; ++ ++#define WL_MIMO_PS_STATUS_AP_CAP(ap_cap) (ap_cap & 0x0F) ++#define WL_MIMO_PS_STATUS_AP_CAP_BW(ap_cap) (ap_cap >> 4) ++#define WL_MIMO_PS_STATUS_ASSOC_BW_SHIFT 4 ++ ++/* version 3: assoc status: low nibble is status enum, high other flags */ ++#define WL_MIMO_PS_STATUS_VERSION_3 3 ++#define WL_MIMO_PS_STATUS_ASSOC_STATUS_MASK 0x0F ++#define WL_MIMO_PS_STATUS_ASSOC_STATUS_VHT_WITHOUT_OMN 0x80 ++ ++/* mimo_ps_status: ap_cap/association status */ ++enum { ++ WL_MIMO_PS_STATUS_ASSOC_NONE = 0, ++ WL_MIMO_PS_STATUS_ASSOC_SISO = 1, ++ WL_MIMO_PS_STATUS_ASSOC_MIMO = 2, ++ WL_MIMO_PS_STATUS_ASSOC_LEGACY = 3 ++}; ++ ++/* mimo_ps_status: mimo_ps_cfg states */ ++enum { ++ WL_MIMO_PS_CFG_STATE_NONE = 0, ++ WL_MIMO_PS_CFG_STATE_INFORM_AP_INPROGRESS = 1, ++ WL_MIMO_PS_CFG_STATE_INFORM_AP_DONE = 2, ++ WL_MIMO_PS_CFG_STATE_LEARNING = 3, ++ WL_MIMO_PS_CFG_STATE_HW_CONFIGURE = 4, ++ WL_MIMO_PS_CFG_STATE_INFORM_AP_PENDING = 5 ++}; ++ ++/* mimo_ps_status: hw_state values */ ++#define WL_MIMO_PS_STATUS_HW_STATE_NONE 0 ++#define WL_MIMO_PS_STATUS_HW_STATE_LTECOEX (0x1 << 0) ++#define WL_MIMO_PS_STATUS_HW_STATE_MIMOPS_BSS (0x1 << 1) ++#define WL_MIMO_PS_STATUS_HW_STATE_AWDL_BSS (0x1 << 2) ++#define WL_MIMO_PS_STATUS_HW_STATE_SCAN (0x1 << 3) ++#define WL_MIMO_PS_STATUS_HW_STATE_TXPPR (0x1 << 4) ++#define WL_MIMO_PS_STATUS_HW_STATE_PWRTHOTTLE (0x1 << 5) ++#define WL_MIMO_PS_STATUS_HW_STATE_TMPSENSE (0x1 << 6) ++#define WL_MIMO_PS_STATUS_HW_STATE_IOVAR (0x1 << 7) ++#define WL_MIMO_PS_STATUS_HW_STATE_AP_BSS (0x1 << 8) ++ ++/* mimo_ps_status: mrc states */ ++#define WL_MIMO_PS_STATUS_MRC_NONE 0 ++#define WL_MIMO_PS_STATUS_MRC_ACTIVE 1 ++ ++/* mimo_ps_status: core flag states for single-core beacon and siso-bcmc rx */ ++#define WL_MIMO_PS_STATUS_MHF_FLAG_NONE 0 ++#define WL_MIMO_PS_STATUS_MHF_FLAG_ACTIVE 1 ++#define WL_MIMO_PS_STATUS_MHF_FLAG_COREDOWN 2 ++#define WL_MIMO_PS_STATUS_MHF_FLAG_INVALID 3 ++ ++/* Type values for the REASON */ ++#define WL_MIMO_PS_PS_LEARNING_ABORTED (1 << 0) ++#define WL_MIMO_PS_PS_LEARNING_COMPLETED (1 << 1) ++#define WL_MIMO_PS_PS_LEARNING_ONGOING (1 << 2) ++ ++typedef struct wl_mimo_ps_learning_event_data { ++ uint32 startTimeStamp; ++ uint32 endTimeStamp; ++ uint16 reason; ++ struct ether_addr BSSID; ++ uint32 totalSISO_below_rssi_threshold; ++ uint32 totalMIMO_below_rssi_threshold; ++ uint32 totalSISO_above_rssi_threshold; ++ uint32 totalMIMO_above_rssi_threshold; ++} wl_mimo_ps_learning_event_data_t; ++ ++#define WL_MIMO_PS_PS_LEARNING_CFG_ABORT (1 << 0) ++#define WL_MIMO_PS_PS_LEARNING_CFG_STATUS (1 << 1) ++#define WL_MIMO_PS_PS_LEARNING_CFG_CONFIG (1 << 2) ++ ++#define WL_MIMO_PS_PS_LEARNING_CFG_V1 1 ++ ++typedef struct wl_mimops_learning_cfg { ++ /* flag: bit 0 for abort */ ++ /* flag: bit 1 for status */ ++ /* flag: bit 2 for configuring no of packets and rssi */ ++ uint8 flag; ++ /* mimo ps learning version, compatible version is 0 */ ++ uint8 version; ++ /* if version is 0 or rssi is 0, ignored */ ++ int8 learning_rssi_threshold; ++ uint8 reserved; ++ uint32 no_of_packets_for_learning; ++ wl_mimo_ps_learning_event_data_t mimops_learning_data; ++} wl_mimops_learning_cfg_t; ++ ++ ++#define WL_OCL_STATUS_VERSION 1 ++typedef struct ocl_status_info { ++ uint8 version; ++ uint8 len; ++ uint16 fw_status; /* Bits representing FW disable reasons */ ++ uint8 hw_status; /* Bits for actual HW config and SISO/MIMO coremask */ ++ uint8 coremask; /* The ocl core mask (indicating listening core) */ ++} ocl_status_info_t; ++ ++/* MWS OCL map */ ++#define WL_MWS_OCL_OVERRIDE_VERSION 1 ++typedef struct wl_mws_ocl_override { ++ uint16 version; /* Structure version */ ++ uint16 bitmap_2g; /* bitmap for 2.4G channels bits 1-13 */ ++ uint16 bitmap_5g_lo; /* bitmap for 5G low channels by 2: ++ *34-48, 52-56, 60-64, 100-102 ++ */ ++ uint16 bitmap_5g_mid; /* bitmap for 5G mid channels by 2: ++ * 104, 108-112, 116-120, 124-128, ++ * 132-136, 140, 149-151 ++ */ ++ uint16 bitmap_5g_high; /* bitmap for 5G high channels by 2 ++ * 153, 157-161, 165 ++ */ ++} wl_mws_ocl_override_t; ++ ++/* Bits for fw_status */ ++#define OCL_DISABLED_HOST 0x01 /* Host has disabled through ocl_enable */ ++#define OCL_DISABLED_RSSI 0x02 /* Disabled because of ocl_rssi_threshold */ ++#define OCL_DISABLED_LTEC 0x04 /* Disabled due to LTE Coex activity */ ++#define OCL_DISABLED_SISO 0x08 /* Disabled while in SISO mode */ ++#define OCL_DISABLED_CAL 0x10 /* Disabled during active calibration */ ++#define OCL_DISABLED_CHANSWITCH 0x20 /* Disabled during active channel switch */ ++#define OCL_DISABLED_ASPEND 0x40 /* Disabled due to assoc pending */ ++ ++/* Bits for hw_status */ ++#define OCL_HWCFG 0x01 /* State of OCL config bit in phy HW */ ++#define OCL_HWMIMO 0x02 /* Set if current coremask is > 1 bit */ ++#define OCL_COREDOWN 0x80 /* Set if core is currently down */ ++ ++ ++/* ++ * Join preference iovar value is an array of tuples. Each tuple has a one-byte type, ++ * a one-byte length, and a variable length value. RSSI type tuple must be present ++ * in the array. ++ * ++ * Types are defined in "join preference types" section. ++ * ++ * Length is the value size in octets. It is reserved for WL_JOIN_PREF_WPA type tuple ++ * and must be set to zero. ++ * ++ * Values are defined below. ++ * ++ * 1. RSSI - 2 octets ++ * offset 0: reserved ++ * offset 1: reserved ++ * ++ * 2. WPA - 2 + 12 * n octets (n is # tuples defined below) ++ * offset 0: reserved ++ * offset 1: # of tuples ++ * offset 2: tuple 1 ++ * offset 14: tuple 2 ++ * ... ++ * offset 2 + 12 * (n - 1) octets: tuple n ++ * ++ * struct wpa_cfg_tuple { ++ * uint8 akm[DOT11_OUI_LEN+1]; akm suite ++ * uint8 ucipher[DOT11_OUI_LEN+1]; unicast cipher suite ++ * uint8 mcipher[DOT11_OUI_LEN+1]; multicast cipher suite ++ * }; ++ * ++ * multicast cipher suite can be specified as a specific cipher suite or WL_WPA_ACP_MCS_ANY. ++ * ++ * 3. BAND - 2 octets ++ * offset 0: reserved ++ * offset 1: see "band preference" and "band types" ++ * ++ * 4. BAND RSSI - 2 octets ++ * offset 0: band types ++ * offset 1: +ve RSSI boost value in dB ++ */ ++ ++struct tsinfo_arg { ++ uint8 octets[3]; ++}; ++ ++#define RATE_CCK_1MBPS 0 ++#define RATE_CCK_2MBPS 1 ++#define RATE_CCK_5_5MBPS 2 ++#define RATE_CCK_11MBPS 3 ++ ++#define RATE_LEGACY_OFDM_6MBPS 0 ++#define RATE_LEGACY_OFDM_9MBPS 1 ++#define RATE_LEGACY_OFDM_12MBPS 2 ++#define RATE_LEGACY_OFDM_18MBPS 3 ++#define RATE_LEGACY_OFDM_24MBPS 4 ++#define RATE_LEGACY_OFDM_36MBPS 5 ++#define RATE_LEGACY_OFDM_48MBPS 6 ++#define RATE_LEGACY_OFDM_54MBPS 7 ++ ++#define WL_BSSTRANS_RSSI_RATE_MAP_VERSION 1 ++ ++typedef struct wl_bsstrans_rssi { ++ int8 rssi_2g; /**< RSSI in dbm for 2.4 G */ ++ int8 rssi_5g; /**< RSSI in dbm for 5G, unused for cck */ ++} wl_bsstrans_rssi_t; ++ ++#define RSSI_RATE_MAP_MAX_STREAMS 4 /**< max streams supported */ ++ ++/** RSSI to rate mapping, all 20Mhz, no SGI */ ++typedef struct wl_bsstrans_rssi_rate_map { ++ uint16 ver; ++ uint16 len; /**< length of entire structure */ ++ wl_bsstrans_rssi_t cck[WL_NUM_RATES_CCK]; /**< 2.4G only */ ++ wl_bsstrans_rssi_t ofdm[WL_NUM_RATES_OFDM]; /**< 6 to 54mbps */ ++ wl_bsstrans_rssi_t phy_n[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_MCS_1STREAM]; /* MCS0-7 */ ++ wl_bsstrans_rssi_t phy_ac[RSSI_RATE_MAP_MAX_STREAMS][WL_NUM_RATES_VHT]; /**< MCS0-9 */ ++} wl_bsstrans_rssi_rate_map_t; ++ ++#define WL_BSSTRANS_ROAMTHROTTLE_VERSION 1 ++ ++/** Configure number of scans allowed per throttle period */ ++typedef struct wl_bsstrans_roamthrottle { ++ uint16 ver; ++ uint16 period; ++ uint16 scans_allowed; ++} wl_bsstrans_roamthrottle_t; ++ ++#define NFIFO 6 /**< # tx/rx fifopairs */ ++ ++#if defined(BCM_DMA_CT) && !defined(BCM_DMA_CT_DISABLED) ++#define NFIFO_EXT 32 /* 6 traditional FIFOs + 2 rsvd + 24 MU FIFOs */ ++#elif defined(WL11AX) && defined(WL11AX_TRIGGERQ_ENABLED) ++#define NFIFO_EXT 10 ++#else ++#define NFIFO_EXT NFIFO ++#endif ++ ++/* Reinit reason codes */ ++enum { ++ WL_REINIT_RC_NONE = 0, ++ WL_REINIT_RC_PS_SYNC = 1, ++ WL_REINIT_RC_PSM_WD = 2, ++ WL_REINIT_RC_MAC_WAKE = 3, ++ WL_REINIT_RC_MAC_SUSPEND = 4, ++ WL_REINIT_RC_MAC_SPIN_WAIT = 5, ++ WL_REINIT_RC_AXI_BUS_ERROR = 6, ++ WL_REINIT_RC_DEVICE_REMOVED = 7, ++ WL_REINIT_RC_PCIE_FATAL_ERROR = 8, ++ WL_REINIT_RC_OL_FW_TRAP = 9, ++ WL_REINIT_RC_FIFO_ERR = 10, ++ WL_REINIT_RC_INV_TX_STATUS = 11, ++ WL_REINIT_RC_MQ_ERROR = 12, ++ WL_REINIT_RC_PHYTXERR_THRESH = 13, ++ WL_REINIT_RC_USER_FORCED = 14, ++ WL_REINIT_RC_FULL_RESET = 15, ++ WL_REINIT_RC_AP_BEACON = 16, ++ WL_REINIT_RC_PM_EXCESSED = 17, ++ WL_REINIT_RC_NO_CLK = 18, ++ WL_REINIT_RC_SW_ASSERT = 19, ++ WL_REINIT_RC_PSM_JMP0 = 20, ++ WL_REINIT_RC_PSM_RUN = 21, ++ WL_REINIT_RC_ENABLE_MAC = 22, ++ WL_REINIT_RC_SCAN_TIMEOUT = 23, ++ WL_REINIT_RC_JOIN_TIMEOUT = 24, ++ /* Below error codes are generated during D3 exit validation */ ++ WL_REINIT_RC_LINK_NOT_ACTIVE = 25, ++ WL_REINIT_RC_PCI_CFG_RD_FAIL = 26, ++ WL_REINIT_RC_INV_VEN_ID = 27, ++ WL_REINIT_RC_INV_DEV_ID = 28, ++ WL_REINIT_RC_INV_BAR0 = 29, ++ WL_REINIT_RC_INV_BAR2 = 30, ++ WL_REINIT_RC_AER_UC_FATAL = 31, ++ WL_REINIT_RC_AER_UC_NON_FATAL = 32, ++ WL_REINIT_RC_AER_CORR = 33, ++ WL_REINIT_RC_AER_DEV_STS = 34, ++ WL_REINIT_RC_PCIe_STS = 35, ++ WL_REINIT_RC_MMIO_RD_FAIL = 36, ++ WL_REINIT_RC_MMIO_RD_INVAL = 37, ++ WL_REINIT_RC_MMIO_ARM_MEM_RD_FAIL = 38, ++ WL_REINIT_RC_MMIO_ARM_MEM_INVAL = 39, ++ WL_REINIT_RC_SROM_LOAD_FAILED = 40, ++ WL_REINIT_RC_PHY_CRASH = 41, ++ WL_REINIT_TX_STALL = 42, ++ WL_REINIT_RC_TX_FLOW_CONTROL_BLOCKED = 43, ++ WL_REINIT_RC_RX_HC_FAIL = 44, ++ WL_REINIT_RC_RX_DMA_STALL = 45, ++ WL_REINIT_UTRACE_BUF_OVERLAP_SR = 46, ++ WL_REINIT_UTRACE_TPL_OUT_BOUNDS = 47, ++ WL_REINIT_UTRACE_TPL_OSET_STRT0 = 48, ++ WL_REINIT_RC_PHYTXERR = 49, ++ WL_REINIT_RC_PSM_FATAL_SUSP = 50, ++ WL_REINIT_RC_TX_FIFO_SUSP = 51, ++ WL_REINIT_RC_MAC_ENABLE = 52, ++ WL_REINIT_RC_SCAN_STALLED = 53, ++ WL_REINIT_RC_LAST /* This must be the last entry */ ++}; ++ ++#define NREINITREASONCOUNT 8 ++ ++#define REINITRSNIDX(_x) (((_x) < WL_REINIT_RC_LAST) ? (_x) : 0) ++ ++#define WL_CNT_T_VERSION 30 /**< current version of wl_cnt_t struct */ ++#define WL_CNT_VERSION_6 6 ++#define WL_CNT_VERSION_11 11 ++#define WL_CNT_VERSION_XTLV 30 ++ ++#define WL_COUNTERS_IOV_VERSION_1 1 ++#define WL_SUBCNTR_IOV_VER WL_COUNTERS_IOV_VERSION_1 ++/* First two uint16 are version and lenght fields. So offset of the first counter will be 4 */ ++#define FIRST_COUNTER_OFFSET 0x04 ++ ++#define WLC_WITH_XTLV_CNT ++ ++/** ++ * tlv IDs uniquely identifies counter component ++ * packed into wl_cmd_t container ++ */ ++enum wl_cnt_xtlv_id { ++ WL_CNT_XTLV_SLICE_IDX = 0x1, /**< Slice index */ ++ WL_CNT_XTLV_WLC = 0x100, /**< WLC layer counters */ ++ WL_CNT_XTLV_WLC_RINIT_RSN = 0x101, /**< WLC layer reinitreason extension */ ++ WL_CNT_XTLV_CNTV_LE10_UCODE = 0x200, /**< wl counter ver < 11 UCODE MACSTAT */ ++ WL_CNT_XTLV_LT40_UCODE_V1 = 0x300, /**< corerev < 40 UCODE MACSTAT */ ++ WL_CNT_XTLV_GE40_UCODE_V1 = 0x400, /**< corerev >= 40 UCODE MACSTAT */ ++ WL_CNT_XTLV_GE64_UCODEX_V1 = 0x800 /* corerev >= 64 UCODEX MACSTAT */ ++}; ++ ++/** ++ * The number of variables in wl macstat cnt struct. ++ * (wl_cnt_ge40mcst_v1_t, wl_cnt_lt40mcst_v1_t, wl_cnt_v_le10_mcst_t) ++ */ ++#define WL_CNT_MCST_VAR_NUM 64 ++/* sizeof(wl_cnt_ge40mcst_v1_t), sizeof(wl_cnt_lt40mcst_v1_t), and sizeof(wl_cnt_v_le10_mcst_t) */ ++#define WL_CNT_MCST_STRUCT_SZ ((uint32)sizeof(uint32) * WL_CNT_MCST_VAR_NUM) ++ ++#define WL_CNT_MCXST_STRUCT_SZ ((uint32)sizeof(wl_cnt_ge64mcxst_v1_t)) ++#define INVALID_CNT_VAL (uint32)(-1) ++ ++#define WL_XTLV_CNTBUF_MAX_SIZE ((uint32)(OFFSETOF(wl_cnt_info_t, data)) + \ ++ (uint32)BCM_XTLV_HDR_SIZE + (uint32)sizeof(wl_cnt_wlc_t) + \ ++ (uint32)BCM_XTLV_HDR_SIZE + WL_CNT_MCST_STRUCT_SZ + \ ++ (uint32)BCM_XTLV_HDR_SIZE + WL_CNT_MCXST_STRUCT_SZ) ++ ++#define WL_CNTBUF_MAX_SIZE MAX(WL_XTLV_CNTBUF_MAX_SIZE, (uint32)sizeof(wl_cnt_ver_11_t)) ++ ++ ++/** Top structure of counters IOVar buffer */ ++typedef struct { ++ uint16 version; /**< see definition of WL_CNT_T_VERSION */ ++ uint16 datalen; /**< length of data including all paddings. */ ++ uint8 data []; /**< variable length payload: ++ * 1 or more bcm_xtlv_t type of tuples. ++ * each tuple is padded to multiple of 4 bytes. ++ * 'datalen' field of this structure includes all paddings. ++ */ ++} wl_cnt_info_t; ++ ++/* Top structure of subcounters IOVar buffer ++ * Whenever we make any change in this structure ++ * WL_SUBCNTR_IOV_VER should be updated accordingly ++ * The structure definition should remain consistant b/w ++ * FW and wl/WLM app. ++ */ ++typedef struct { ++ uint16 version; /* Version of IOVAR structure. Used for backward ++ * compatibility in future. Whenever we make any ++ * changes to this structure then value of WL_SUBCNTR_IOV_VER ++ * needs to be updated properly. ++ */ ++ uint16 length; /* length in bytes of this structure */ ++ uint16 counters_version; /* see definition of WL_CNT_T_VERSION ++ * wl app will send the version of counters ++ * which is used to calculate the offset of counters. ++ * It must match the version of counters FW is using ++ * else FW will return error with his version of counters ++ * set in this field. ++ */ ++ uint16 num_subcounters; /* Number of counter offset passed by wl app to FW. */ ++ uint32 data[1]; /* variable length payload: ++ * Offsets to the counters will be passed to FW ++ * throught this data field. FW will return the value of counters ++ * at the offsets passed by wl app in this fiels itself. ++ */ ++} wl_subcnt_info_t; ++ ++/** wlc layer counters */ ++typedef struct { ++ /* transmit stat counters */ ++ uint32 txframe; /**< tx data frames */ ++ uint32 txbyte; /**< tx data bytes */ ++ uint32 txretrans; /**< tx mac retransmits */ ++ uint32 txerror; /**< tx data errors (derived: sum of others) */ ++ uint32 txctl; /**< tx management frames */ ++ uint32 txprshort; /**< tx short preamble frames */ ++ uint32 txserr; /**< tx status errors */ ++ uint32 txnobuf; /**< tx out of buffers errors */ ++ uint32 txnoassoc; /**< tx discard because we're not associated */ ++ uint32 txrunt; /**< tx runt frames */ ++ uint32 txchit; /**< tx header cache hit (fastpath) */ ++ uint32 txcmiss; /**< tx header cache miss (slowpath) */ ++ ++ /* transmit chip error counters */ ++ uint32 txuflo; /**< tx fifo underflows */ ++ uint32 txphyerr; /**< tx phy errors (indicated in tx status) */ ++ uint32 txphycrs; ++ ++ /* receive stat counters */ ++ uint32 rxframe; /**< rx data frames */ ++ uint32 rxbyte; /**< rx data bytes */ ++ uint32 rxerror; /**< rx data errors (derived: sum of others) */ ++ uint32 rxctl; /**< rx management frames */ ++ uint32 rxnobuf; /**< rx out of buffers errors */ ++ uint32 rxnondata; /**< rx non data frames in the data channel errors */ ++ uint32 rxbadds; /**< rx bad DS errors */ ++ uint32 rxbadcm; /**< rx bad control or management frames */ ++ uint32 rxfragerr; /**< rx fragmentation errors */ ++ uint32 rxrunt; /**< rx runt frames */ ++ uint32 rxgiant; /**< rx giant frames */ ++ uint32 rxnoscb; /**< rx no scb error */ ++ uint32 rxbadproto; /**< rx invalid frames */ ++ uint32 rxbadsrcmac; /**< rx frames with Invalid Src Mac */ ++ uint32 rxbadda; /**< rx frames tossed for invalid da */ ++ uint32 rxfilter; /**< rx frames filtered out */ ++ ++ /* receive chip error counters */ ++ uint32 rxoflo; /**< rx fifo overflow errors */ ++ uint32 rxuflo[NFIFO]; /**< rx dma descriptor underflow errors */ ++ ++ uint32 d11cnt_txrts_off; /**< d11cnt txrts value when reset d11cnt */ ++ uint32 d11cnt_rxcrc_off; /**< d11cnt rxcrc value when reset d11cnt */ ++ uint32 d11cnt_txnocts_off; /**< d11cnt txnocts value when reset d11cnt */ ++ ++ /* misc counters */ ++ uint32 dmade; /**< tx/rx dma descriptor errors */ ++ uint32 dmada; /**< tx/rx dma data errors */ ++ uint32 dmape; /**< tx/rx dma descriptor protocol errors */ ++ uint32 reset; /**< reset count */ ++ uint32 tbtt; /**< cnts the TBTT int's */ ++ uint32 txdmawar; ++ uint32 pkt_callback_reg_fail; /**< callbacks register failure */ ++ ++ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ ++ uint32 txfrag; /**< dot11TransmittedFragmentCount */ ++ uint32 txmulti; /**< dot11MulticastTransmittedFrameCount */ ++ uint32 txfail; /**< dot11FailedCount */ ++ uint32 txretry; /**< dot11RetryCount */ ++ uint32 txretrie; /**< dot11MultipleRetryCount */ ++ uint32 rxdup; /**< dot11FrameduplicateCount */ ++ uint32 txrts; /**< dot11RTSSuccessCount */ ++ uint32 txnocts; /**< dot11RTSFailureCount */ ++ uint32 txnoack; /**< dot11ACKFailureCount */ ++ uint32 rxfrag; /**< dot11ReceivedFragmentCount */ ++ uint32 rxmulti; /**< dot11MulticastReceivedFrameCount */ ++ uint32 rxcrc; /**< dot11FCSErrorCount */ ++ uint32 txfrmsnt; /**< dot11TransmittedFrameCount (bogus MIB?) */ ++ uint32 rxundec; /**< dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill; /**< TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr; /**< TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay; /**< TKIPReplays */ ++ uint32 ccmpfmterr; /**< CCMPFormatErrors */ ++ uint32 ccmpreplay; /**< CCMPReplays */ ++ uint32 ccmpundec; /**< CCMPDecryptErrors */ ++ uint32 fourwayfail; /**< FourWayHandshakeFailures */ ++ uint32 wepundec; /**< dot11WEPUndecryptableCount */ ++ uint32 wepicverr; /**< dot11WEPICVErrorCount */ ++ uint32 decsuccess; /**< DecryptSuccessCount */ ++ uint32 tkipicverr; /**< TKIPICVErrorCount */ ++ uint32 wepexcluded; /**< dot11WEPExcludedCount */ ++ ++ uint32 txchanrej; /**< Tx frames suppressed due to channel rejection */ ++ uint32 psmwds; /**< Count PSM watchdogs */ ++ uint32 phywatchdog; /**< Count Phy watchdogs (triggered by ucode) */ ++ ++ /* MBSS counters, AP only */ ++ uint32 prq_entries_handled; /**< PRQ entries read in */ ++ uint32 prq_undirected_entries; /**< which were bcast bss & ssid */ ++ uint32 prq_bad_entries; /**< which could not be translated to info */ ++ uint32 atim_suppress_count; /**< TX suppressions on ATIM fifo */ ++ uint32 bcn_template_not_ready; /**< Template marked in use on send bcn ... */ ++ uint32 bcn_template_not_ready_done; /**< ...but "DMA done" interrupt rcvd */ ++ uint32 late_tbtt_dpc; /**< TBTT DPC did not happen in time */ ++ ++ /* per-rate receive stat counters */ ++ uint32 rx1mbps; /**< packets rx at 1Mbps */ ++ uint32 rx2mbps; /**< packets rx at 2Mbps */ ++ uint32 rx5mbps5; /**< packets rx at 5.5Mbps */ ++ uint32 rx6mbps; /**< packets rx at 6Mbps */ ++ uint32 rx9mbps; /**< packets rx at 9Mbps */ ++ uint32 rx11mbps; /**< packets rx at 11Mbps */ ++ uint32 rx12mbps; /**< packets rx at 12Mbps */ ++ uint32 rx18mbps; /**< packets rx at 18Mbps */ ++ uint32 rx24mbps; /**< packets rx at 24Mbps */ ++ uint32 rx36mbps; /**< packets rx at 36Mbps */ ++ uint32 rx48mbps; /**< packets rx at 48Mbps */ ++ uint32 rx54mbps; /**< packets rx at 54Mbps */ ++ uint32 rx108mbps; /**< packets rx at 108mbps */ ++ uint32 rx162mbps; /**< packets rx at 162mbps */ ++ uint32 rx216mbps; /**< packets rx at 216 mbps */ ++ uint32 rx270mbps; /**< packets rx at 270 mbps */ ++ uint32 rx324mbps; /**< packets rx at 324 mbps */ ++ uint32 rx378mbps; /**< packets rx at 378 mbps */ ++ uint32 rx432mbps; /**< packets rx at 432 mbps */ ++ uint32 rx486mbps; /**< packets rx at 486 mbps */ ++ uint32 rx540mbps; /**< packets rx at 540 mbps */ ++ ++ uint32 rfdisable; /**< count of radio disables */ ++ ++ uint32 txexptime; /**< Tx frames suppressed due to timer expiration */ ++ ++ uint32 txmpdu_sgi; /**< count for sgi transmit */ ++ uint32 rxmpdu_sgi; /**< count for sgi received */ ++ uint32 txmpdu_stbc; /**< count for stbc transmit */ ++ uint32 rxmpdu_stbc; /**< count for stbc received */ ++ ++ uint32 rxundec_mcst; /**< dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill_mcst; /**< TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr_mcst; /**< TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay_mcst; /**< TKIPReplays */ ++ uint32 ccmpfmterr_mcst; /**< CCMPFormatErrors */ ++ uint32 ccmpreplay_mcst; /**< CCMPReplays */ ++ uint32 ccmpundec_mcst; /**< CCMPDecryptErrors */ ++ uint32 fourwayfail_mcst; /**< FourWayHandshakeFailures */ ++ uint32 wepundec_mcst; /**< dot11WEPUndecryptableCount */ ++ uint32 wepicverr_mcst; /**< dot11WEPICVErrorCount */ ++ uint32 decsuccess_mcst; /**< DecryptSuccessCount */ ++ uint32 tkipicverr_mcst; /**< TKIPICVErrorCount */ ++ uint32 wepexcluded_mcst; /**< dot11WEPExcludedCount */ ++ ++ uint32 dma_hang; /**< count for dma hang */ ++ uint32 reinit; /**< count for reinit */ ++ ++ uint32 pstatxucast; /**< count of ucast frames xmitted on all psta assoc */ ++ uint32 pstatxnoassoc; /**< count of txnoassoc frames xmitted on all psta assoc */ ++ uint32 pstarxucast; /**< count of ucast frames received on all psta assoc */ ++ uint32 pstarxbcmc; /**< count of bcmc frames received on all psta */ ++ uint32 pstatxbcmc; /**< count of bcmc frames transmitted on all psta */ ++ ++ uint32 cso_passthrough; /**< hw cso required but passthrough */ ++ uint32 cso_normal; /**< hw cso hdr for normal process */ ++ uint32 chained; /**< number of frames chained */ ++ uint32 chainedsz1; /**< number of chain size 1 frames */ ++ uint32 unchained; /**< number of frames not chained */ ++ uint32 maxchainsz; /**< max chain size so far */ ++ uint32 currchainsz; /**< current chain size */ ++ uint32 pciereset; /**< Secondary Bus Reset issued by driver */ ++ uint32 cfgrestore; /**< configspace restore by driver */ ++ uint32 reinitreason[NREINITREASONCOUNT]; /**< reinitreason counters; 0: Unknown reason */ ++ uint32 rxrtry; ++ uint32 rxmpdu_mu; /**< Number of MU MPDUs received */ ++ ++ /* detailed control/management frames */ ++ uint32 txbar; /**< Number of TX BAR */ ++ uint32 rxbar; /**< Number of RX BAR */ ++ uint32 txpspoll; /**< Number of TX PS-poll */ ++ uint32 rxpspoll; /**< Number of RX PS-poll */ ++ uint32 txnull; /**< Number of TX NULL_DATA */ ++ uint32 rxnull; /**< Number of RX NULL_DATA */ ++ uint32 txqosnull; /**< Number of TX NULL_QoSDATA */ ++ uint32 rxqosnull; /**< Number of RX NULL_QoSDATA */ ++ uint32 txassocreq; /**< Number of TX ASSOC request */ ++ uint32 rxassocreq; /**< Number of RX ASSOC request */ ++ uint32 txreassocreq; /**< Number of TX REASSOC request */ ++ uint32 rxreassocreq; /**< Number of RX REASSOC request */ ++ uint32 txdisassoc; /**< Number of TX DISASSOC */ ++ uint32 rxdisassoc; /**< Number of RX DISASSOC */ ++ uint32 txassocrsp; /**< Number of TX ASSOC response */ ++ uint32 rxassocrsp; /**< Number of RX ASSOC response */ ++ uint32 txreassocrsp; /**< Number of TX REASSOC response */ ++ uint32 rxreassocrsp; /**< Number of RX REASSOC response */ ++ uint32 txauth; /**< Number of TX AUTH */ ++ uint32 rxauth; /**< Number of RX AUTH */ ++ uint32 txdeauth; /**< Number of TX DEAUTH */ ++ uint32 rxdeauth; /**< Number of RX DEAUTH */ ++ uint32 txprobereq; /**< Number of TX probe request */ ++ uint32 rxprobereq; /**< Number of RX probe request */ ++ uint32 txprobersp; /**< Number of TX probe response */ ++ uint32 rxprobersp; /**< Number of RX probe response */ ++ uint32 txaction; /**< Number of TX action frame */ ++ uint32 rxaction; /**< Number of RX action frame */ ++ uint32 ampdu_wds; /**< Number of AMPDU watchdogs */ ++ uint32 txlost; /**< Number of lost packets reported in txs */ ++ uint32 txdatamcast; /**< Number of TX multicast data packets */ ++ uint32 txdatabcast; /**< Number of TX broadcast data packets */ ++ uint32 psmxwds; /**< Number of PSMx watchdogs */ ++ uint32 rxback; ++ uint32 txback; ++ uint32 p2p_tbtt; /**< Number of P2P TBTT Events */ ++ uint32 p2p_tbtt_miss; /**< Number of P2P TBTT Events Miss */ ++ uint32 txqueue_start; ++ uint32 txqueue_end; ++ uint32 txbcast; /* Broadcast TransmittedFrameCount */ ++ uint32 txdropped; /* tx dropped pkts */ ++ uint32 rxbcast; /* BroadcastReceivedFrameCount */ ++ uint32 rxdropped; /* rx dropped pkts (derived: sum of others) */ ++} wl_cnt_wlc_t; ++ ++/* Reinit reasons - do not put anything else other than reinit reasons here */ ++typedef struct { ++ uint32 rsn[WL_REINIT_RC_LAST]; ++} reinit_rsns_t; ++ ++/* MACXSTAT counters for ucodex (corerev >= 64) */ ++typedef struct { ++ uint32 macxsusp; ++ uint32 m2vmsg; ++ uint32 v2mmsg; ++ uint32 mboxout; ++ uint32 musnd; ++ uint32 sfb2v; ++} wl_cnt_ge64mcxst_v1_t; ++ ++/** MACSTAT counters for ucode (corerev >= 40) */ ++typedef struct { ++ /* MAC counters: 32-bit version of d11.h's macstat_t */ ++ uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, ++ * Control Management (includes retransmissions) ++ */ ++ uint32 txrtsfrm; /**< number of RTS sent out by the MAC */ ++ uint32 txctsfrm; /**< number of CTS sent out by the MAC */ ++ uint32 txackfrm; /**< number of ACK frames sent out */ ++ uint32 txdnlfrm; /**< number of Null-Data transmission generated from template */ ++ uint32 txbcnfrm; /**< beacons transmitted */ ++ uint32 txfunfl[6]; /**< per-fifo tx underflows */ ++ uint32 txampdu; /**< number of AMPDUs transmitted */ ++ uint32 txmpdu; /**< number of MPDUs transmitted */ ++ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS ++ * or BCN) ++ */ ++ uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for ++ * driver enqueued frames ++ */ ++ uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */ ++ uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */ ++ uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */ ++ uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */ ++ uint32 rxanyerr; /**< Any RX error that is not counted by other counters. */ ++ uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ ++ uint32 rxbadplcp; /**< parity check of the PLCP header failed */ ++ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ ++ uint32 rxstrt; /**< Number of received frames with a good PLCP ++ * (i.e. passing parity check) ++ */ ++ uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ ++ uint32 rxmgucastmbss; /**< number of received mgmt frames with good FCS and matching RA */ ++ uint32 rxctlucast; /**< number of received CNTRL frames with good FCS and matching RA */ ++ uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */ ++ uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */ ++ uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */ ++ uint32 rxdtocast; /**< number of received DATA frames (good FCS and not matching RA) */ ++ uint32 rxmgocast; /**< number of received MGMT frames (good FCS and not matching RA) */ ++ uint32 rxctlocast; /**< number of received CNTRL frame (good FCS and not matching RA) */ ++ uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */ ++ uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */ ++ uint32 rxdtmcast; /**< number of RX Data multicast frames received by the MAC */ ++ uint32 rxmgmcast; /**< number of RX Management multicast frames received by the MAC */ ++ uint32 rxctlmcast; /**< number of RX Control multicast frames received by the MAC ++ * (unlikely to see these) ++ */ ++ uint32 rxbeaconmbss; /**< beacons received from member of BSS */ ++ uint32 rxdtucastobss; /**< number of unicast frames addressed to the MAC from ++ * other BSS (WDS FRAME) ++ */ ++ uint32 rxbeaconobss; /**< beacons received from other BSS */ ++ uint32 rxrsptmout; /**< number of response timeouts for transmitted frames ++ * expecting a response ++ */ ++ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */ ++ uint32 rxnodelim; /**< number of no valid delimiter detected by ampdu parser */ ++ uint32 rxf0ovfl; /**< number of receive fifo 0 overflows */ ++ uint32 rxf1ovfl; /**< number of receive fifo 1 overflows */ ++ uint32 rxhlovfl; /**< number of length / header fifo overflows */ ++ uint32 missbcn_dbg; /**< number of beacon missed to receive */ ++ uint32 pmqovfl; /**< number of PMQ overflows */ ++ uint32 rxcgprqfrm; /**< number of received Probe requests that made it into ++ * the PRQ fifo ++ */ ++ uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */ ++ uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did ++ * not get ACK ++ */ ++ uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */ ++ uint32 prs_timeout; /**< number of probe requests that were dropped from the PRQ ++ * fifo because a probe response could not be sent out within ++ * the time limit defined in M_PRS_MAXTIME ++ */ ++ uint32 txrtsfail; /**< number of rts transmission failure that reach retry limit */ ++ uint32 txucast; /**< number of unicast tx expecting response other than cts/cwcts */ ++ uint32 txinrtstxop; /**< number of data frame transmissions during rts txop */ ++ uint32 rxback; /**< blockack rxcnt */ ++ uint32 txback; /**< blockack txcnt */ ++ uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ ++ uint32 rxdrop20s; /**< drop secondary cnt */ ++ uint32 rxtoolate; /**< receive too late */ ++ uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ ++} wl_cnt_ge40mcst_v1_t; ++ ++/** MACSTAT counters for ucode (corerev < 40) */ ++typedef struct { ++ /* MAC counters: 32-bit version of d11.h's macstat_t */ ++ uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, ++ * Control Management (includes retransmissions) ++ */ ++ uint32 txrtsfrm; /**< number of RTS sent out by the MAC */ ++ uint32 txctsfrm; /**< number of CTS sent out by the MAC */ ++ uint32 txackfrm; /**< number of ACK frames sent out */ ++ uint32 txdnlfrm; /**< number of Null-Data transmission generated from template */ ++ uint32 txbcnfrm; /**< beacons transmitted */ ++ uint32 txfunfl[6]; /**< per-fifo tx underflows */ ++ uint32 txampdu; /**< number of AMPDUs transmitted */ ++ uint32 txmpdu; /**< number of MPDUs transmitted */ ++ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS ++ * or BCN) ++ */ ++ uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for ++ * driver enqueued frames ++ */ ++ uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */ ++ uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */ ++ uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */ ++ uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */ ++ uint32 rxanyerr; /**< Any RX error that is not counted by other counters. */ ++ uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ ++ uint32 rxbadplcp; /**< parity check of the PLCP header failed */ ++ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ ++ uint32 rxstrt; /**< Number of received frames with a good PLCP ++ * (i.e. passing parity check) ++ */ ++ uint32 rxdtucastmbss; /**< number of received DATA frames with good FCS and matching RA */ ++ uint32 rxmgucastmbss; /**< number of received mgmt frames with good FCS and matching RA */ ++ uint32 rxctlucast; /**< number of received CNTRL frames with good FCS and matching RA */ ++ uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */ ++ uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */ ++ uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */ ++ uint32 rxdtocast; /**< number of received DATA frames (good FCS and not matching RA) */ ++ uint32 rxmgocast; /**< number of received MGMT frames (good FCS and not matching RA) */ ++ uint32 rxctlocast; /**< number of received CNTRL frame (good FCS and not matching RA) */ ++ uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */ ++ uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */ ++ uint32 rxdtmcast; /**< number of RX Data multicast frames received by the MAC */ ++ uint32 rxmgmcast; /**< number of RX Management multicast frames received by the MAC */ ++ uint32 rxctlmcast; /**< number of RX Control multicast frames received by the MAC ++ * (unlikely to see these) ++ */ ++ uint32 rxbeaconmbss; /**< beacons received from member of BSS */ ++ uint32 rxdtucastobss; /**< number of unicast frames addressed to the MAC from ++ * other BSS (WDS FRAME) ++ */ ++ uint32 rxbeaconobss; /**< beacons received from other BSS */ ++ uint32 rxrsptmout; /**< number of response timeouts for transmitted frames ++ * expecting a response ++ */ ++ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */ ++ uint32 rxnodelim; /**< number of no valid delimiter detected by ampdu parser */ ++ uint32 rxf0ovfl; /**< number of receive fifo 0 overflows */ ++ uint32 dbgoff46; ++ uint32 dbgoff47; ++ uint32 dbgoff48; /**< Used for counting txstatus queue overflow (corerev <= 4) */ ++ uint32 pmqovfl; /**< number of PMQ overflows */ ++ uint32 rxcgprqfrm; /**< number of received Probe requests that made it into ++ * the PRQ fifo ++ */ ++ uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */ ++ uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did ++ * not get ACK ++ */ ++ uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */ ++ uint32 prs_timeout; /**< number of probe requests that were dropped from the PRQ ++ * fifo because a probe response could not be sent out within ++ * the time limit defined in M_PRS_MAXTIME ++ */ ++ uint32 txrtsfail; /**< number of rts transmission failure that reach retry limit */ ++ uint32 txucast; /**< number of unicast tx expecting response other than cts/cwcts */ ++ uint32 txinrtstxop; /**< number of data frame transmissions during rts txop */ ++ uint32 rxback; /**< blockack rxcnt */ ++ uint32 txback; /**< blockack txcnt */ ++ uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ ++ uint32 phywatch; ++ uint32 rxtoolate; /**< receive too late */ ++ uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ ++} wl_cnt_lt40mcst_v1_t; ++ ++/** MACSTAT counters for "wl counter" version <= 10 */ ++typedef struct { ++ /* MAC counters: 32-bit version of d11.h's macstat_t */ ++ uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, ++ * Control Management (includes retransmissions) ++ */ ++ uint32 txrtsfrm; /**< number of RTS sent out by the MAC */ ++ uint32 txctsfrm; /**< number of CTS sent out by the MAC */ ++ uint32 txackfrm; /**< number of ACK frames sent out */ ++ uint32 txdnlfrm; /**< number of Null-Data transmission generated from template */ ++ uint32 txbcnfrm; /**< beacons transmitted */ ++ uint32 txfunfl[6]; /**< per-fifo tx underflows */ ++ uint32 txfbw; /**< transmit at fallback bw (dynamic bw) */ ++ uint32 PAD0; /**< number of MPDUs transmitted */ ++ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS ++ * or BCN) ++ */ ++ uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for ++ * driver enqueued frames ++ */ ++ uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */ ++ uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */ ++ uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */ ++ uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */ ++ uint32 rxinvmachdr; /**< Either the protocol version != 0 or frame type not ++ * data/control/management ++ */ ++ uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ ++ uint32 rxbadplcp; /**< parity check of the PLCP header failed */ ++ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ ++ uint32 rxstrt; /**< Number of received frames with a good PLCP ++ * (i.e. passing parity check) ++ */ ++ uint32 rxdfrmucastmbss; /* number of received DATA frames with good FCS and matching RA */ ++ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ ++ uint32 rxcfrmucast; /**< number of received CNTRL frames with good FCS and matching RA */ ++ uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */ ++ uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */ ++ uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */ ++ uint32 rxdfrmocast; /**< number of received DATA frames (good FCS and not matching RA) */ ++ uint32 rxmfrmocast; /**< number of received MGMT frames (good FCS and not matching RA) */ ++ uint32 rxcfrmocast; /**< number of received CNTRL frame (good FCS and not matching RA) */ ++ uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */ ++ uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */ ++ uint32 rxdfrmmcast; /**< number of RX Data multicast frames received by the MAC */ ++ uint32 rxmfrmmcast; /**< number of RX Management multicast frames received by the MAC */ ++ uint32 rxcfrmmcast; /**< number of RX Control multicast frames received by the MAC ++ * (unlikely to see these) ++ */ ++ uint32 rxbeaconmbss; /**< beacons received from member of BSS */ ++ uint32 rxdfrmucastobss; /**< number of unicast frames addressed to the MAC from ++ * other BSS (WDS FRAME) ++ */ ++ uint32 rxbeaconobss; /**< beacons received from other BSS */ ++ uint32 rxrsptmout; /**< number of response timeouts for transmitted frames ++ * expecting a response ++ */ ++ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */ ++ uint32 PAD1; ++ uint32 rxf0ovfl; /**< number of receive fifo 0 overflows */ ++ uint32 rxf1ovfl; /**< Number of receive fifo 1 overflows (obsolete) */ ++ uint32 rxf2ovfl; /**< Number of receive fifo 2 overflows (obsolete) */ ++ uint32 txsfovfl; /**< Number of transmit status fifo overflows (obsolete) */ ++ uint32 pmqovfl; /**< number of PMQ overflows */ ++ uint32 rxcgprqfrm; /**< number of received Probe requests that made it into ++ * the PRQ fifo ++ */ ++ uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */ ++ uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did ++ * not get ACK ++ */ ++ uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */ ++ uint32 prs_timeout; /**< number of probe requests that were dropped from the PRQ ++ * fifo because a probe response could not be sent out within ++ * the time limit defined in M_PRS_MAXTIME ++ */ ++ uint32 rxnack; /**< obsolete */ ++ uint32 frmscons; /**< obsolete */ ++ uint32 txnack; /**< obsolete */ ++ uint32 rxback; /**< blockack rxcnt */ ++ uint32 txback; /**< blockack txcnt */ ++ uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ ++ uint32 rxdrop20s; /**< drop secondary cnt */ ++ uint32 rxtoolate; /**< receive too late */ ++ uint32 bphy_badplcp; /**< number of bad PLCP reception on BPHY rate */ ++} wl_cnt_v_le10_mcst_t; ++ ++#define MAX_RX_FIFO 3 ++#define WL_RXFIFO_CNT_VERSION 1 /* current version of wl_rxfifo_cnt_t */ ++typedef struct { ++ /* Counters for frames received from rx fifos */ ++ uint16 version; ++ uint16 length; /* length of entire structure */ ++ uint32 rxf_data[MAX_RX_FIFO]; /* data frames from rx fifo */ ++ uint32 rxf_mgmtctl[MAX_RX_FIFO]; /* mgmt/ctl frames from rx fifo */ ++} wl_rxfifo_cnt_t; ++ ++typedef struct { ++ uint16 version; /**< see definition of WL_CNT_T_VERSION */ ++ uint16 length; /**< length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txframe; /**< tx data frames */ ++ uint32 txbyte; /**< tx data bytes */ ++ uint32 txretrans; /**< tx mac retransmits */ ++ uint32 txerror; /**< tx data errors (derived: sum of others) */ ++ uint32 txctl; /**< tx management frames */ ++ uint32 txprshort; /**< tx short preamble frames */ ++ uint32 txserr; /**< tx status errors */ ++ uint32 txnobuf; /**< tx out of buffers errors */ ++ uint32 txnoassoc; /**< tx discard because we're not associated */ ++ uint32 txrunt; /**< tx runt frames */ ++ uint32 txchit; /**< tx header cache hit (fastpath) */ ++ uint32 txcmiss; /**< tx header cache miss (slowpath) */ ++ ++ /* transmit chip error counters */ ++ uint32 txuflo; /**< tx fifo underflows */ ++ uint32 txphyerr; /**< tx phy errors (indicated in tx status) */ ++ uint32 txphycrs; ++ ++ /* receive stat counters */ ++ uint32 rxframe; /**< rx data frames */ ++ uint32 rxbyte; /**< rx data bytes */ ++ uint32 rxerror; /**< rx data errors (derived: sum of others) */ ++ uint32 rxctl; /**< rx management frames */ ++ uint32 rxnobuf; /**< rx out of buffers errors */ ++ uint32 rxnondata; /**< rx non data frames in the data channel errors */ ++ uint32 rxbadds; /**< rx bad DS errors */ ++ uint32 rxbadcm; /**< rx bad control or management frames */ ++ uint32 rxfragerr; /**< rx fragmentation errors */ ++ uint32 rxrunt; /**< rx runt frames */ ++ uint32 rxgiant; /**< rx giant frames */ ++ uint32 rxnoscb; /**< rx no scb error */ ++ uint32 rxbadproto; /**< rx invalid frames */ ++ uint32 rxbadsrcmac; /**< rx frames with Invalid Src Mac */ ++ uint32 rxbadda; /**< rx frames tossed for invalid da */ ++ uint32 rxfilter; /**< rx frames filtered out */ ++ ++ /* receive chip error counters */ ++ uint32 rxoflo; /**< rx fifo overflow errors */ ++ uint32 rxuflo[NFIFO]; /**< rx dma descriptor underflow errors */ ++ ++ uint32 d11cnt_txrts_off; /**< d11cnt txrts value when reset d11cnt */ ++ uint32 d11cnt_rxcrc_off; /**< d11cnt rxcrc value when reset d11cnt */ ++ uint32 d11cnt_txnocts_off; /**< d11cnt txnocts value when reset d11cnt */ ++ ++ /* misc counters */ ++ uint32 dmade; /**< tx/rx dma descriptor errors */ ++ uint32 dmada; /**< tx/rx dma data errors */ ++ uint32 dmape; /**< tx/rx dma descriptor protocol errors */ ++ uint32 reset; /**< reset count */ ++ uint32 tbtt; /**< cnts the TBTT int's */ ++ uint32 txdmawar; ++ uint32 pkt_callback_reg_fail; /**< callbacks register failure */ ++ ++ /* MAC counters: 32-bit version of d11.h's macstat_t */ ++ uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, ++ * Control Management (includes retransmissions) ++ */ ++ uint32 txrtsfrm; /**< number of RTS sent out by the MAC */ ++ uint32 txctsfrm; /**< number of CTS sent out by the MAC */ ++ uint32 txackfrm; /**< number of ACK frames sent out */ ++ uint32 txdnlfrm; /**< Not used */ ++ uint32 txbcnfrm; /**< beacons transmitted */ ++ uint32 txfunfl[6]; /**< per-fifo tx underflows */ ++ uint32 rxtoolate; /**< receive too late */ ++ uint32 txfbw; /**< transmit at fallback bw (dynamic bw) */ ++ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS ++ * or BCN) ++ */ ++ uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for ++ * driver enqueued frames ++ */ ++ uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */ ++ uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */ ++ uint32 rxinvmachdr; /**< Either the protocol version != 0 or frame type not ++ * data/control/management ++ */ ++ uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ ++ uint32 rxbadplcp; /**< parity check of the PLCP header failed */ ++ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ ++ uint32 rxstrt; /**< Number of received frames with a good PLCP ++ * (i.e. passing parity check) ++ */ ++ uint32 rxdfrmucastmbss; /* Number of received DATA frames with good FCS and matching RA */ ++ uint32 rxmfrmucastmbss; /* number of received mgmt frames with good FCS and matching RA */ ++ uint32 rxcfrmucast; /**< number of received CNTRL frames with good FCS and matching RA */ ++ uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */ ++ uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */ ++ uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */ ++ uint32 rxdfrmocast; /**< number of received DATA frames (good FCS and not matching RA) */ ++ uint32 rxmfrmocast; /**< number of received MGMT frames (good FCS and not matching RA) */ ++ uint32 rxcfrmocast; /**< number of received CNTRL frame (good FCS and not matching RA) */ ++ uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */ ++ uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */ ++ uint32 rxdfrmmcast; /**< number of RX Data multicast frames received by the MAC */ ++ uint32 rxmfrmmcast; /**< number of RX Management multicast frames received by the MAC */ ++ uint32 rxcfrmmcast; /**< number of RX Control multicast frames received by the MAC ++ * (unlikely to see these) ++ */ ++ uint32 rxbeaconmbss; /**< beacons received from member of BSS */ ++ uint32 rxdfrmucastobss; /**< number of unicast frames addressed to the MAC from ++ * other BSS (WDS FRAME) ++ */ ++ uint32 rxbeaconobss; /**< beacons received from other BSS */ ++ uint32 rxrsptmout; /**< Number of response timeouts for transmitted frames ++ * expecting a response ++ */ ++ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */ ++ uint32 rxf0ovfl; /**< Number of receive fifo 0 overflows */ ++ uint32 rxf1ovfl; /**< Number of receive fifo 1 overflows (obsolete) */ ++ uint32 rxf2ovfl; /**< Number of receive fifo 2 overflows (obsolete) */ ++ uint32 txsfovfl; /**< Number of transmit status fifo overflows (obsolete) */ ++ uint32 pmqovfl; /**< Number of PMQ overflows */ ++ uint32 rxcgprqfrm; /**< Number of received Probe requests that made it into ++ * the PRQ fifo ++ */ ++ uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */ ++ uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did ++ * not get ACK ++ */ ++ uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */ ++ uint32 prs_timeout; /**< Number of probe requests that were dropped from the PRQ ++ * fifo because a probe response could not be sent out within ++ * the time limit defined in M_PRS_MAXTIME ++ */ ++ uint32 rxnack; /**< obsolete */ ++ uint32 frmscons; /**< obsolete */ ++ uint32 txnack; /**< obsolete */ ++ uint32 rxback; /**< blockack rxcnt */ ++ uint32 txback; /**< blockack txcnt */ ++ ++ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ ++ uint32 txfrag; /**< dot11TransmittedFragmentCount */ ++ uint32 txmulti; /**< dot11MulticastTransmittedFrameCount */ ++ uint32 txfail; /**< dot11FailedCount */ ++ uint32 txretry; /**< dot11RetryCount */ ++ uint32 txretrie; /**< dot11MultipleRetryCount */ ++ uint32 rxdup; /**< dot11FrameduplicateCount */ ++ uint32 txrts; /**< dot11RTSSuccessCount */ ++ uint32 txnocts; /**< dot11RTSFailureCount */ ++ uint32 txnoack; /**< dot11ACKFailureCount */ ++ uint32 rxfrag; /**< dot11ReceivedFragmentCount */ ++ uint32 rxmulti; /**< dot11MulticastReceivedFrameCount */ ++ uint32 rxcrc; /**< dot11FCSErrorCount */ ++ uint32 txfrmsnt; /**< dot11TransmittedFrameCount (bogus MIB?) */ ++ uint32 rxundec; /**< dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill; /**< TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr; /**< TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay; /**< TKIPReplays */ ++ uint32 ccmpfmterr; /**< CCMPFormatErrors */ ++ uint32 ccmpreplay; /**< CCMPReplays */ ++ uint32 ccmpundec; /**< CCMPDecryptErrors */ ++ uint32 fourwayfail; /**< FourWayHandshakeFailures */ ++ uint32 wepundec; /**< dot11WEPUndecryptableCount */ ++ uint32 wepicverr; /**< dot11WEPICVErrorCount */ ++ uint32 decsuccess; /**< DecryptSuccessCount */ ++ uint32 tkipicverr; /**< TKIPICVErrorCount */ ++ uint32 wepexcluded; /**< dot11WEPExcludedCount */ ++ ++ uint32 txchanrej; /**< Tx frames suppressed due to channel rejection */ ++ uint32 psmwds; /**< Count PSM watchdogs */ ++ uint32 phywatchdog; /**< Count Phy watchdogs (triggered by ucode) */ ++ ++ /* MBSS counters, AP only */ ++ uint32 prq_entries_handled; /**< PRQ entries read in */ ++ uint32 prq_undirected_entries; /**< which were bcast bss & ssid */ ++ uint32 prq_bad_entries; /**< which could not be translated to info */ ++ uint32 atim_suppress_count; /**< TX suppressions on ATIM fifo */ ++ uint32 bcn_template_not_ready; /**< Template marked in use on send bcn ... */ ++ uint32 bcn_template_not_ready_done; /**< ...but "DMA done" interrupt rcvd */ ++ uint32 late_tbtt_dpc; /**< TBTT DPC did not happen in time */ ++ ++ /* per-rate receive stat counters */ ++ uint32 rx1mbps; /**< packets rx at 1Mbps */ ++ uint32 rx2mbps; /**< packets rx at 2Mbps */ ++ uint32 rx5mbps5; /**< packets rx at 5.5Mbps */ ++ uint32 rx6mbps; /**< packets rx at 6Mbps */ ++ uint32 rx9mbps; /**< packets rx at 9Mbps */ ++ uint32 rx11mbps; /**< packets rx at 11Mbps */ ++ uint32 rx12mbps; /**< packets rx at 12Mbps */ ++ uint32 rx18mbps; /**< packets rx at 18Mbps */ ++ uint32 rx24mbps; /**< packets rx at 24Mbps */ ++ uint32 rx36mbps; /**< packets rx at 36Mbps */ ++ uint32 rx48mbps; /**< packets rx at 48Mbps */ ++ uint32 rx54mbps; /**< packets rx at 54Mbps */ ++ uint32 rx108mbps; /**< packets rx at 108mbps */ ++ uint32 rx162mbps; /**< packets rx at 162mbps */ ++ uint32 rx216mbps; /**< packets rx at 216 mbps */ ++ uint32 rx270mbps; /**< packets rx at 270 mbps */ ++ uint32 rx324mbps; /**< packets rx at 324 mbps */ ++ uint32 rx378mbps; /**< packets rx at 378 mbps */ ++ uint32 rx432mbps; /**< packets rx at 432 mbps */ ++ uint32 rx486mbps; /**< packets rx at 486 mbps */ ++ uint32 rx540mbps; /**< packets rx at 540 mbps */ ++ ++ /* pkteng rx frame stats */ ++ uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */ ++ uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */ ++ ++ uint32 rfdisable; /**< count of radio disables */ ++ uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ ++ uint32 bphy_badplcp; ++ ++ uint32 txexptime; /**< Tx frames suppressed due to timer expiration */ ++ ++ uint32 txmpdu_sgi; /**< count for sgi transmit */ ++ uint32 rxmpdu_sgi; /**< count for sgi received */ ++ uint32 txmpdu_stbc; /**< count for stbc transmit */ ++ uint32 rxmpdu_stbc; /**< count for stbc received */ ++ ++ uint32 rxundec_mcst; /**< dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill_mcst; /**< TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr_mcst; /**< TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay_mcst; /**< TKIPReplays */ ++ uint32 ccmpfmterr_mcst; /**< CCMPFormatErrors */ ++ uint32 ccmpreplay_mcst; /**< CCMPReplays */ ++ uint32 ccmpundec_mcst; /**< CCMPDecryptErrors */ ++ uint32 fourwayfail_mcst; /**< FourWayHandshakeFailures */ ++ uint32 wepundec_mcst; /**< dot11WEPUndecryptableCount */ ++ uint32 wepicverr_mcst; /**< dot11WEPICVErrorCount */ ++ uint32 decsuccess_mcst; /**< DecryptSuccessCount */ ++ uint32 tkipicverr_mcst; /**< TKIPICVErrorCount */ ++ uint32 wepexcluded_mcst; /**< dot11WEPExcludedCount */ ++ ++ uint32 dma_hang; /**< count for dma hang */ ++ uint32 reinit; /**< count for reinit */ ++ ++ uint32 pstatxucast; /**< count of ucast frames xmitted on all psta assoc */ ++ uint32 pstatxnoassoc; /**< count of txnoassoc frames xmitted on all psta assoc */ ++ uint32 pstarxucast; /**< count of ucast frames received on all psta assoc */ ++ uint32 pstarxbcmc; /**< count of bcmc frames received on all psta */ ++ uint32 pstatxbcmc; /**< count of bcmc frames transmitted on all psta */ ++ ++ uint32 cso_passthrough; /**< hw cso required but passthrough */ ++ uint32 cso_normal; /**< hw cso hdr for normal process */ ++ uint32 chained; /**< number of frames chained */ ++ uint32 chainedsz1; /**< number of chain size 1 frames */ ++ uint32 unchained; /**< number of frames not chained */ ++ uint32 maxchainsz; /**< max chain size so far */ ++ uint32 currchainsz; /**< current chain size */ ++ uint32 rxdrop20s; /**< drop secondary cnt */ ++ uint32 pciereset; /**< Secondary Bus Reset issued by driver */ ++ uint32 cfgrestore; /**< configspace restore by driver */ ++ uint32 reinitreason[NREINITREASONCOUNT]; /**< reinitreason counters; 0: Unknown reason */ ++ uint32 rxrtry; /**< num of received packets with retry bit on */ ++ uint32 txmpdu; /**< macstat cnt only valid in ver 11. number of MPDUs txed. */ ++ uint32 rxnodelim; /**< macstat cnt only valid in ver 11. ++ * number of occasions that no valid delimiter is detected ++ * by ampdu parser. ++ */ ++ uint32 rxmpdu_mu; /**< Number of MU MPDUs received */ ++ ++ /* detailed control/management frames */ ++ uint32 txbar; /**< Number of TX BAR */ ++ uint32 rxbar; /**< Number of RX BAR */ ++ uint32 txpspoll; /**< Number of TX PS-poll */ ++ uint32 rxpspoll; /**< Number of RX PS-poll */ ++ uint32 txnull; /**< Number of TX NULL_DATA */ ++ uint32 rxnull; /**< Number of RX NULL_DATA */ ++ uint32 txqosnull; /**< Number of TX NULL_QoSDATA */ ++ uint32 rxqosnull; /**< Number of RX NULL_QoSDATA */ ++ uint32 txassocreq; /**< Number of TX ASSOC request */ ++ uint32 rxassocreq; /**< Number of RX ASSOC request */ ++ uint32 txreassocreq; /**< Number of TX REASSOC request */ ++ uint32 rxreassocreq; /**< Number of RX REASSOC request */ ++ uint32 txdisassoc; /**< Number of TX DISASSOC */ ++ uint32 rxdisassoc; /**< Number of RX DISASSOC */ ++ uint32 txassocrsp; /**< Number of TX ASSOC response */ ++ uint32 rxassocrsp; /**< Number of RX ASSOC response */ ++ uint32 txreassocrsp; /**< Number of TX REASSOC response */ ++ uint32 rxreassocrsp; /**< Number of RX REASSOC response */ ++ uint32 txauth; /**< Number of TX AUTH */ ++ uint32 rxauth; /**< Number of RX AUTH */ ++ uint32 txdeauth; /**< Number of TX DEAUTH */ ++ uint32 rxdeauth; /**< Number of RX DEAUTH */ ++ uint32 txprobereq; /**< Number of TX probe request */ ++ uint32 rxprobereq; /**< Number of RX probe request */ ++ uint32 txprobersp; /**< Number of TX probe response */ ++ uint32 rxprobersp; /**< Number of RX probe response */ ++ uint32 txaction; /**< Number of TX action frame */ ++ uint32 rxaction; /**< Number of RX action frame */ ++ uint32 ampdu_wds; /**< Number of AMPDU watchdogs */ ++ uint32 txlost; /**< Number of lost packets reported in txs */ ++ uint32 txdatamcast; /**< Number of TX multicast data packets */ ++ uint32 txdatabcast; /**< Number of TX broadcast data packets */ ++ uint32 txbcast; /* Broadcast TransmittedFrameCount */ ++ uint32 txdropped; /* tx dropped pkts */ ++ uint32 rxbcast; /* BroadcastReceivedFrameCount */ ++ uint32 rxdropped; /* rx dropped pkts (derived: sum of others) */ ++ ++} wl_cnt_ver_11_t; ++ ++typedef struct { ++ uint16 version; /**< see definition of WL_CNT_T_VERSION */ ++ uint16 length; /**< length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txframe; /**< tx data frames */ ++ uint32 txbyte; /**< tx data bytes */ ++ uint32 txretrans; /**< tx mac retransmits */ ++ uint32 txerror; /**< tx data errors (derived: sum of others) */ ++ uint32 txctl; /**< tx management frames */ ++ uint32 txprshort; /**< tx short preamble frames */ ++ uint32 txserr; /**< tx status errors */ ++ uint32 txnobuf; /**< tx out of buffers errors */ ++ uint32 txnoassoc; /**< tx discard because we're not associated */ ++ uint32 txrunt; /**< tx runt frames */ ++ uint32 txchit; /**< tx header cache hit (fastpath) */ ++ uint32 txcmiss; /**< tx header cache miss (slowpath) */ ++ ++ /* transmit chip error counters */ ++ uint32 txuflo; /**< tx fifo underflows */ ++ uint32 txphyerr; /**< tx phy errors (indicated in tx status) */ ++ uint32 txphycrs; ++ ++ /* receive stat counters */ ++ uint32 rxframe; /**< rx data frames */ ++ uint32 rxbyte; /**< rx data bytes */ ++ uint32 rxerror; /**< rx data errors (derived: sum of others) */ ++ uint32 rxctl; /**< rx management frames */ ++ uint32 rxnobuf; /**< rx out of buffers errors */ ++ uint32 rxnondata; /**< rx non data frames in the data channel errors */ ++ uint32 rxbadds; /**< rx bad DS errors */ ++ uint32 rxbadcm; /**< rx bad control or management frames */ ++ uint32 rxfragerr; /**< rx fragmentation errors */ ++ uint32 rxrunt; /**< rx runt frames */ ++ uint32 rxgiant; /**< rx giant frames */ ++ uint32 rxnoscb; /**< rx no scb error */ ++ uint32 rxbadproto; /**< rx invalid frames */ ++ uint32 rxbadsrcmac; /**< rx frames with Invalid Src Mac */ ++ uint32 rxbadda; /**< rx frames tossed for invalid da */ ++ uint32 rxfilter; /**< rx frames filtered out */ ++ ++ /* receive chip error counters */ ++ uint32 rxoflo; /**< rx fifo overflow errors */ ++ uint32 rxuflo[NFIFO]; /**< rx dma descriptor underflow errors */ ++ ++ uint32 d11cnt_txrts_off; /**< d11cnt txrts value when reset d11cnt */ ++ uint32 d11cnt_rxcrc_off; /**< d11cnt rxcrc value when reset d11cnt */ ++ uint32 d11cnt_txnocts_off; /**< d11cnt txnocts value when reset d11cnt */ ++ ++ /* misc counters */ ++ uint32 dmade; /**< tx/rx dma descriptor errors */ ++ uint32 dmada; /**< tx/rx dma data errors */ ++ uint32 dmape; /**< tx/rx dma descriptor protocol errors */ ++ uint32 reset; /**< reset count */ ++ uint32 tbtt; /**< cnts the TBTT int's */ ++ uint32 txdmawar; ++ uint32 pkt_callback_reg_fail; /**< callbacks register failure */ ++ ++ /* MAC counters: 32-bit version of d11.h's macstat_t */ ++ uint32 txallfrm; /**< total number of frames sent, incl. Data, ACK, RTS, CTS, ++ * Control Management (includes retransmissions) ++ */ ++ uint32 txrtsfrm; /**< number of RTS sent out by the MAC */ ++ uint32 txctsfrm; /**< number of CTS sent out by the MAC */ ++ uint32 txackfrm; /**< number of ACK frames sent out */ ++ uint32 txdnlfrm; /**< Not used */ ++ uint32 txbcnfrm; /**< beacons transmitted */ ++ uint32 txfunfl[6]; /**< per-fifo tx underflows */ ++ uint32 rxtoolate; /**< receive too late */ ++ uint32 txfbw; /**< transmit at fallback bw (dynamic bw) */ ++ uint32 txtplunfl; /**< Template underflows (mac was too slow to transmit ACK/CTS ++ * or BCN) ++ */ ++ uint32 txphyerror; /**< Transmit phy error, type of error is reported in tx-status for ++ * driver enqueued frames ++ */ ++ uint32 rxfrmtoolong; /**< Received frame longer than legal limit (2346 bytes) */ ++ uint32 rxfrmtooshrt; /**< Received frame did not contain enough bytes for its frame type */ ++ uint32 rxinvmachdr; /**< Either the protocol version != 0 or frame type not ++ * data/control/management ++ */ ++ uint32 rxbadfcs; /**< number of frames for which the CRC check failed in the MAC */ ++ uint32 rxbadplcp; /**< parity check of the PLCP header failed */ ++ uint32 rxcrsglitch; /**< PHY was able to correlate the preamble but not the header */ ++ uint32 rxstrt; /**< Number of received frames with a good PLCP ++ * (i.e. passing parity check) ++ */ ++ uint32 rxdfrmucastmbss; /**< # of received DATA frames with good FCS and matching RA */ ++ uint32 rxmfrmucastmbss; /**< # of received mgmt frames with good FCS and matching RA */ ++ uint32 rxcfrmucast; /**< # of received CNTRL frames with good FCS and matching RA */ ++ uint32 rxrtsucast; /**< number of unicast RTS addressed to the MAC (good FCS) */ ++ uint32 rxctsucast; /**< number of unicast CTS addressed to the MAC (good FCS) */ ++ uint32 rxackucast; /**< number of ucast ACKS received (good FCS) */ ++ uint32 rxdfrmocast; /**< # of received DATA frames (good FCS and not matching RA) */ ++ uint32 rxmfrmocast; /**< # of received MGMT frames (good FCS and not matching RA) */ ++ uint32 rxcfrmocast; /**< # of received CNTRL frame (good FCS and not matching RA) */ ++ uint32 rxrtsocast; /**< number of received RTS not addressed to the MAC */ ++ uint32 rxctsocast; /**< number of received CTS not addressed to the MAC */ ++ uint32 rxdfrmmcast; /**< number of RX Data multicast frames received by the MAC */ ++ uint32 rxmfrmmcast; /**< number of RX Management multicast frames received by the MAC */ ++ uint32 rxcfrmmcast; /**< number of RX Control multicast frames received by the MAC ++ * (unlikely to see these) ++ */ ++ uint32 rxbeaconmbss; /**< beacons received from member of BSS */ ++ uint32 rxdfrmucastobss; /**< number of unicast frames addressed to the MAC from ++ * other BSS (WDS FRAME) ++ */ ++ uint32 rxbeaconobss; /**< beacons received from other BSS */ ++ uint32 rxrsptmout; /**< Number of response timeouts for transmitted frames ++ * expecting a response ++ */ ++ uint32 bcntxcancl; /**< transmit beacons canceled due to receipt of beacon (IBSS) */ ++ uint32 rxf0ovfl; /**< Number of receive fifo 0 overflows */ ++ uint32 rxf1ovfl; /**< Number of receive fifo 1 overflows (obsolete) */ ++ uint32 rxf2ovfl; /**< Number of receive fifo 2 overflows (obsolete) */ ++ uint32 txsfovfl; /**< Number of transmit status fifo overflows (obsolete) */ ++ uint32 pmqovfl; /**< Number of PMQ overflows */ ++ uint32 rxcgprqfrm; /**< Number of received Probe requests that made it into ++ * the PRQ fifo ++ */ ++ uint32 rxcgprsqovfl; /**< Rx Probe Request Que overflow in the AP */ ++ uint32 txcgprsfail; /**< Tx Probe Response Fail. AP sent probe response but did ++ * not get ACK ++ */ ++ uint32 txcgprssuc; /**< Tx Probe Response Success (ACK was received) */ ++ uint32 prs_timeout; /**< Number of probe requests that were dropped from the PRQ ++ * fifo because a probe response could not be sent out within ++ * the time limit defined in M_PRS_MAXTIME ++ */ ++ uint32 rxnack; ++ uint32 frmscons; ++ uint32 txnack; /**< obsolete */ ++ uint32 rxback; /**< blockack rxcnt */ ++ uint32 txback; /**< blockack txcnt */ ++ ++ /* 802.11 MIB counters, pp. 614 of 802.11 reaff doc. */ ++ uint32 txfrag; /**< dot11TransmittedFragmentCount */ ++ uint32 txmulti; /**< dot11MulticastTransmittedFrameCount */ ++ uint32 txfail; /**< dot11FailedCount */ ++ uint32 txretry; /**< dot11RetryCount */ ++ uint32 txretrie; /**< dot11MultipleRetryCount */ ++ uint32 rxdup; /**< dot11FrameduplicateCount */ ++ uint32 txrts; /**< dot11RTSSuccessCount */ ++ uint32 txnocts; /**< dot11RTSFailureCount */ ++ uint32 txnoack; /**< dot11ACKFailureCount */ ++ uint32 rxfrag; /**< dot11ReceivedFragmentCount */ ++ uint32 rxmulti; /**< dot11MulticastReceivedFrameCount */ ++ uint32 rxcrc; /**< dot11FCSErrorCount */ ++ uint32 txfrmsnt; /**< dot11TransmittedFrameCount (bogus MIB?) */ ++ uint32 rxundec; /**< dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill; /**< TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr; /**< TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay; /**< TKIPReplays */ ++ uint32 ccmpfmterr; /**< CCMPFormatErrors */ ++ uint32 ccmpreplay; /**< CCMPReplays */ ++ uint32 ccmpundec; /**< CCMPDecryptErrors */ ++ uint32 fourwayfail; /**< FourWayHandshakeFailures */ ++ uint32 wepundec; /**< dot11WEPUndecryptableCount */ ++ uint32 wepicverr; /**< dot11WEPICVErrorCount */ ++ uint32 decsuccess; /**< DecryptSuccessCount */ ++ uint32 tkipicverr; /**< TKIPICVErrorCount */ ++ uint32 wepexcluded; /**< dot11WEPExcludedCount */ ++ ++ uint32 rxundec_mcst; /**< dot11WEPUndecryptableCount */ ++ ++ /* WPA2 counters (see rxundec for DecryptFailureCount) */ ++ uint32 tkipmicfaill_mcst; /**< TKIPLocalMICFailures */ ++ uint32 tkipcntrmsr_mcst; /**< TKIPCounterMeasuresInvoked */ ++ uint32 tkipreplay_mcst; /**< TKIPReplays */ ++ uint32 ccmpfmterr_mcst; /**< CCMPFormatErrors */ ++ uint32 ccmpreplay_mcst; /**< CCMPReplays */ ++ uint32 ccmpundec_mcst; /**< CCMPDecryptErrors */ ++ uint32 fourwayfail_mcst; /**< FourWayHandshakeFailures */ ++ uint32 wepundec_mcst; /**< dot11WEPUndecryptableCount */ ++ uint32 wepicverr_mcst; /**< dot11WEPICVErrorCount */ ++ uint32 decsuccess_mcst; /**< DecryptSuccessCount */ ++ uint32 tkipicverr_mcst; /**< TKIPICVErrorCount */ ++ uint32 wepexcluded_mcst; /**< dot11WEPExcludedCount */ ++ ++ uint32 txchanrej; /**< Tx frames suppressed due to channel rejection */ ++ uint32 txexptime; /**< Tx frames suppressed due to timer expiration */ ++ uint32 psmwds; /**< Count PSM watchdogs */ ++ uint32 phywatchdog; /**< Count Phy watchdogs (triggered by ucode) */ ++ ++ /* MBSS counters, AP only */ ++ uint32 prq_entries_handled; /**< PRQ entries read in */ ++ uint32 prq_undirected_entries; /**< which were bcast bss & ssid */ ++ uint32 prq_bad_entries; /**< which could not be translated to info */ ++ uint32 atim_suppress_count; /**< TX suppressions on ATIM fifo */ ++ uint32 bcn_template_not_ready; /**< Template marked in use on send bcn ... */ ++ uint32 bcn_template_not_ready_done; /**< ...but "DMA done" interrupt rcvd */ ++ uint32 late_tbtt_dpc; /**< TBTT DPC did not happen in time */ ++ ++ /* per-rate receive stat counters */ ++ uint32 rx1mbps; /**< packets rx at 1Mbps */ ++ uint32 rx2mbps; /**< packets rx at 2Mbps */ ++ uint32 rx5mbps5; /**< packets rx at 5.5Mbps */ ++ uint32 rx6mbps; /**< packets rx at 6Mbps */ ++ uint32 rx9mbps; /**< packets rx at 9Mbps */ ++ uint32 rx11mbps; /**< packets rx at 11Mbps */ ++ uint32 rx12mbps; /**< packets rx at 12Mbps */ ++ uint32 rx18mbps; /**< packets rx at 18Mbps */ ++ uint32 rx24mbps; /**< packets rx at 24Mbps */ ++ uint32 rx36mbps; /**< packets rx at 36Mbps */ ++ uint32 rx48mbps; /**< packets rx at 48Mbps */ ++ uint32 rx54mbps; /**< packets rx at 54Mbps */ ++ uint32 rx108mbps; /**< packets rx at 108mbps */ ++ uint32 rx162mbps; /**< packets rx at 162mbps */ ++ uint32 rx216mbps; /**< packets rx at 216 mbps */ ++ uint32 rx270mbps; /**< packets rx at 270 mbps */ ++ uint32 rx324mbps; /**< packets rx at 324 mbps */ ++ uint32 rx378mbps; /**< packets rx at 378 mbps */ ++ uint32 rx432mbps; /**< packets rx at 432 mbps */ ++ uint32 rx486mbps; /**< packets rx at 486 mbps */ ++ uint32 rx540mbps; /**< packets rx at 540 mbps */ ++ ++ /* pkteng rx frame stats */ ++ uint32 pktengrxducast; /**< unicast frames rxed by the pkteng code */ ++ uint32 pktengrxdmcast; /**< multicast frames rxed by the pkteng code */ ++ ++ uint32 rfdisable; /**< count of radio disables */ ++ uint32 bphy_rxcrsglitch; /**< PHY count of bphy glitches */ ++ uint32 bphy_badplcp; ++ ++ uint32 txmpdu_sgi; /**< count for sgi transmit */ ++ uint32 rxmpdu_sgi; /**< count for sgi received */ ++ uint32 txmpdu_stbc; /**< count for stbc transmit */ ++ uint32 rxmpdu_stbc; /**< count for stbc received */ ++ ++ uint32 rxdrop20s; /**< drop secondary cnt */ ++} wl_cnt_ver_6_t; ++ ++#define WL_DELTA_STATS_T_VERSION 2 /**< current version of wl_delta_stats_t struct */ ++ ++typedef struct { ++ uint16 version; /**< see definition of WL_DELTA_STATS_T_VERSION */ ++ uint16 length; /**< length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txframe; /**< tx data frames */ ++ uint32 txbyte; /**< tx data bytes */ ++ uint32 txretrans; /**< tx mac retransmits */ ++ uint32 txfail; /**< tx failures */ ++ ++ /* receive stat counters */ ++ uint32 rxframe; /**< rx data frames */ ++ uint32 rxbyte; /**< rx data bytes */ ++ ++ /* per-rate receive stat counters */ ++ uint32 rx1mbps; /**< packets rx at 1Mbps */ ++ uint32 rx2mbps; /**< packets rx at 2Mbps */ ++ uint32 rx5mbps5; /**< packets rx at 5.5Mbps */ ++ uint32 rx6mbps; /**< packets rx at 6Mbps */ ++ uint32 rx9mbps; /**< packets rx at 9Mbps */ ++ uint32 rx11mbps; /**< packets rx at 11Mbps */ ++ uint32 rx12mbps; /**< packets rx at 12Mbps */ ++ uint32 rx18mbps; /**< packets rx at 18Mbps */ ++ uint32 rx24mbps; /**< packets rx at 24Mbps */ ++ uint32 rx36mbps; /**< packets rx at 36Mbps */ ++ uint32 rx48mbps; /**< packets rx at 48Mbps */ ++ uint32 rx54mbps; /**< packets rx at 54Mbps */ ++ uint32 rx108mbps; /**< packets rx at 108mbps */ ++ uint32 rx162mbps; /**< packets rx at 162mbps */ ++ uint32 rx216mbps; /**< packets rx at 216 mbps */ ++ uint32 rx270mbps; /**< packets rx at 270 mbps */ ++ uint32 rx324mbps; /**< packets rx at 324 mbps */ ++ uint32 rx378mbps; /**< packets rx at 378 mbps */ ++ uint32 rx432mbps; /**< packets rx at 432 mbps */ ++ uint32 rx486mbps; /**< packets rx at 486 mbps */ ++ uint32 rx540mbps; /**< packets rx at 540 mbps */ ++ ++ /* phy stats */ ++ uint32 rxbadplcp; ++ uint32 rxcrsglitch; ++ uint32 bphy_rxcrsglitch; ++ uint32 bphy_badplcp; ++ ++} wl_delta_stats_t; ++ ++/* Partial statistics counter report */ ++#define WL_CNT_CTL_MGT_FRAMES 0 ++ ++typedef struct { ++ uint16 type; ++ uint16 len; ++ ++ /* detailed control/management frames */ ++ uint32 txnull; ++ uint32 rxnull; ++ uint32 txqosnull; ++ uint32 rxqosnull; ++ uint32 txassocreq; ++ uint32 rxassocreq; ++ uint32 txreassocreq; ++ uint32 rxreassocreq; ++ uint32 txdisassoc; ++ uint32 rxdisassoc; ++ uint32 txassocrsp; ++ uint32 rxassocrsp; ++ uint32 txreassocrsp; ++ uint32 rxreassocrsp; ++ uint32 txauth; ++ uint32 rxauth; ++ uint32 txdeauth; ++ uint32 rxdeauth; ++ uint32 txprobereq; ++ uint32 rxprobereq; ++ uint32 txprobersp; ++ uint32 rxprobersp; ++ uint32 txaction; ++ uint32 rxaction; ++ uint32 txrts; ++ uint32 rxrts; ++ uint32 txcts; ++ uint32 rxcts; ++ uint32 txack; ++ uint32 rxack; ++ uint32 txbar; ++ uint32 rxbar; ++ uint32 txback; ++ uint32 rxback; ++ uint32 txpspoll; ++ uint32 rxpspoll; ++} wl_ctl_mgt_cnt_t; ++ ++typedef struct { ++ uint32 packets; ++ uint32 bytes; ++} wl_traffic_stats_t; ++ ++typedef struct { ++ uint16 version; /**< see definition of WL_WME_CNT_VERSION */ ++ uint16 length; /**< length of entire structure */ ++ ++ wl_traffic_stats_t tx[AC_COUNT]; /**< Packets transmitted */ ++ wl_traffic_stats_t tx_failed[AC_COUNT]; /**< Packets dropped or failed to transmit */ ++ wl_traffic_stats_t rx[AC_COUNT]; /**< Packets received */ ++ wl_traffic_stats_t rx_failed[AC_COUNT]; /**< Packets failed to receive */ ++ ++ wl_traffic_stats_t forward[AC_COUNT]; /**< Packets forwarded by AP */ ++ ++ wl_traffic_stats_t tx_expired[AC_COUNT]; /**< packets dropped due to lifetime expiry */ ++ ++} wl_wme_cnt_t; ++ ++struct wl_msglevel2 { ++ uint32 low; ++ uint32 high; ++}; ++ ++#define WL_ICMP_IPV6_CFG_VERSION 1 ++#define WL_ICMP_IPV6_CLEAR_ALL (1 << 0) ++ ++typedef struct wl_icmp_ipv6_cfg { ++ uint16 version; ++ uint16 length; ++ uint16 fixed_length; ++ uint16 flags; ++ uint32 num_ipv6; ++ /* num_ipv6 to follow */ ++ struct ipv6_addr host_ipv6[]; ++} wl_icmp_ipv6_cfg_t; ++ ++#define WL_ICMP_CFG_IPV6_FIXED_LEN OFFSETOF(wl_icmp_ipv6_cfg_t, host_ipv6) ++#define WL_ICMP_CFG_IPV6_LEN(count) (WL_ICMP_CFG_IPV6_FIXED_LEN + \ ++ ((count) * sizeof(struct ipv6_addr))) ++ ++typedef struct wl_mkeep_alive_pkt { ++ uint16 version; /* Version for mkeep_alive */ ++ uint16 length; /* length of fixed parameters in the structure */ ++ uint32 period_msec; /* high bit on means immediate send */ ++ uint16 len_bytes; ++ uint8 keep_alive_id; /* 0 - 3 for N = 4 */ ++ uint8 data[1]; ++} wl_mkeep_alive_pkt_t; ++ ++#define WL_MKEEP_ALIVE_VERSION 1 ++#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) ++#define WL_MKEEP_ALIVE_PRECISION 500 ++#define WL_MKEEP_ALIVE_PERIOD_MASK 0x7FFFFFFF ++#define WL_MKEEP_ALIVE_IMMEDIATE 0x80000000 ++ ++/** TCP Keep-Alive conn struct */ ++typedef struct wl_mtcpkeep_alive_conn_pkt { ++ struct ether_addr saddr; /**< src mac address */ ++ struct ether_addr daddr; /**< dst mac address */ ++ struct ipv4_addr sipaddr; /**< source IP addr */ ++ struct ipv4_addr dipaddr; /**< dest IP addr */ ++ uint16 sport; /**< src port */ ++ uint16 dport; /**< dest port */ ++ uint32 seq; /**< seq number */ ++ uint32 ack; /**< ACK number */ ++ uint16 tcpwin; /**< TCP window */ ++ uint16 PAD; ++} wl_mtcpkeep_alive_conn_pkt_t; ++ ++/** TCP Keep-Alive interval struct */ ++typedef struct wl_mtcpkeep_alive_timers_pkt { ++ uint16 interval; /**< interval timer */ ++ uint16 retry_interval; /**< retry_interval timer */ ++ uint16 retry_count; /**< retry_count */ ++} wl_mtcpkeep_alive_timers_pkt_t; ++ ++typedef struct wake_info { ++ uint32 wake_reason; ++ uint32 wake_info_len; /**< size of packet */ ++ uint8 packet[]; ++} wake_info_t; ++ ++typedef struct wake_pkt { ++ uint32 wake_pkt_len; /**< size of packet */ ++ uint8 packet[]; ++} wake_pkt_t; ++ ++ ++#define WL_MTCPKEEP_ALIVE_VERSION 1 ++ ++/* #ifdef WLBA */ ++ ++#define WLC_BA_CNT_VERSION 1 /**< current version of wlc_ba_cnt_t */ ++ ++/** block ack related stats */ ++typedef struct wlc_ba_cnt { ++ uint16 version; /**< WLC_BA_CNT_VERSION */ ++ uint16 length; /**< length of entire structure */ ++ ++ /* transmit stat counters */ ++ uint32 txpdu; /**< pdus sent */ ++ uint32 txsdu; /**< sdus sent */ ++ uint32 txfc; /**< tx side flow controlled packets */ ++ uint32 txfci; /**< tx side flow control initiated */ ++ uint32 txretrans; /**< retransmitted pdus */ ++ uint32 txbatimer; /**< ba resend due to timer */ ++ uint32 txdrop; /**< dropped packets */ ++ uint32 txaddbareq; /**< addba req sent */ ++ uint32 txaddbaresp; /**< addba resp sent */ ++ uint32 txdelba; /**< delba sent */ ++ uint32 txba; /**< ba sent */ ++ uint32 txbar; /**< bar sent */ ++ uint32 txpad[4]; /**< future */ ++ ++ /* receive side counters */ ++ uint32 rxpdu; /**< pdus recd */ ++ uint32 rxqed; /**< pdus buffered before sending up */ ++ uint32 rxdup; /**< duplicate pdus */ ++ uint32 rxnobuf; /**< pdus discarded due to no buf */ ++ uint32 rxaddbareq; /**< addba req recd */ ++ uint32 rxaddbaresp; /**< addba resp recd */ ++ uint32 rxdelba; /**< delba recd */ ++ uint32 rxba; /**< ba recd */ ++ uint32 rxbar; /**< bar recd */ ++ uint32 rxinvba; /**< invalid ba recd */ ++ uint32 rxbaholes; /**< ba recd with holes */ ++ uint32 rxunexp; /**< unexpected packets */ ++ uint32 rxpad[4]; /**< future */ ++} wlc_ba_cnt_t; ++/* #endif WLBA */ ++ ++/** structure for per-tid ampdu control */ ++struct ampdu_tid_control { ++ uint8 tid; /* tid */ ++ uint8 enable; /* enable/disable */ ++}; ++ ++/** struct for ampdu tx/rx aggregation control */ ++struct ampdu_aggr { ++ int8 aggr_override; /**< aggr overrided by dongle. Not to be set by host. */ ++ uint16 conf_TID_bmap; /**< bitmap of TIDs to configure */ ++ uint16 enab_TID_bmap; /**< enable/disable per TID */ ++}; ++ ++/** structure for identifying ea/tid for sending addba/delba */ ++struct ampdu_ea_tid { ++ struct ether_addr ea; /**< Station address */ ++ uint8 tid; /**< tid */ ++ uint8 initiator; /**< 0 is recipient, 1 is originator */ ++}; ++ ++/** structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */ ++struct ampdu_retry_tid { ++ uint8 tid; /**< tid */ ++ uint8 retry; /**< retry value */ ++}; ++ ++#define BDD_FNAME_LEN 32 /**< Max length of friendly name */ ++typedef struct bdd_fname { ++ uint8 len; /**< length of friendly name */ ++ uchar name[BDD_FNAME_LEN]; /**< friendly name */ ++} bdd_fname_t; ++ ++/* structure for addts arguments */ ++/** For ioctls that take a list of TSPEC */ ++struct tslist { ++ int32 count; /**< number of tspecs */ ++ struct tsinfo_arg tsinfo[]; /**< variable length array of tsinfo */ ++}; ++ ++/* WLTDLS */ ++/**structure for tdls iovars */ ++typedef struct tdls_iovar { ++ struct ether_addr ea; /**< Station address */ ++ uint8 mode; /**< mode: depends on iovar */ ++ uint8 PAD; ++ chanspec_t chanspec; ++ uint16 PAD; ++ uint32 pad; /**< future */ ++} tdls_iovar_t; ++ ++#define TDLS_WFD_IE_SIZE 512 ++/**structure for tdls wfd ie */ ++typedef struct tdls_wfd_ie_iovar { ++ struct ether_addr ea; /**< Station address */ ++ uint8 mode; ++ uint8 PAD; ++ uint16 length; ++ uint8 data[TDLS_WFD_IE_SIZE]; ++} tdls_wfd_ie_iovar_t; ++/* #endif WLTDLS */ ++ ++/** structure for addts/delts arguments */ ++typedef struct tspec_arg { ++ uint16 version; /**< see definition of TSPEC_ARG_VERSION */ ++ uint16 length; /**< length of entire structure */ ++ uint32 flag; /**< bit field */ ++ /* TSPEC Arguments */ ++ struct tsinfo_arg tsinfo; /**< TS Info bit field */ ++ uint8 PAD; ++ uint16 nom_msdu_size; /**< (Nominal or fixed) MSDU Size (bytes) */ ++ uint16 max_msdu_size; /**< Maximum MSDU Size (bytes) */ ++ uint32 min_srv_interval; /**< Minimum Service Interval (us) */ ++ uint32 max_srv_interval; /**< Maximum Service Interval (us) */ ++ uint32 inactivity_interval; /**< Inactivity Interval (us) */ ++ uint32 suspension_interval; /**< Suspension Interval (us) */ ++ uint32 srv_start_time; /**< Service Start Time (us) */ ++ uint32 min_data_rate; /**< Minimum Data Rate (bps) */ ++ uint32 mean_data_rate; /**< Mean Data Rate (bps) */ ++ uint32 peak_data_rate; /**< Peak Data Rate (bps) */ ++ uint32 max_burst_size; /**< Maximum Burst Size (bytes) */ ++ uint32 delay_bound; /**< Delay Bound (us) */ ++ uint32 min_phy_rate; /**< Minimum PHY Rate (bps) */ ++ uint16 surplus_bw; /**< Surplus Bandwidth Allowance (range 1.0 to 8.0) */ ++ uint16 medium_time; /**< Medium Time (32 us/s periods) */ ++ uint8 dialog_token; /**< dialog token */ ++ uint8 PAD[3]; ++} tspec_arg_t; ++ ++/** tspec arg for desired station */ ++typedef struct tspec_per_sta_arg { ++ struct ether_addr ea; ++ uint8 PAD[2]; ++ struct tspec_arg ts; ++} tspec_per_sta_arg_t; ++ ++/** structure for max bandwidth for each access category */ ++typedef struct wme_max_bandwidth { ++ uint32 ac[AC_COUNT]; /**< max bandwidth for each access category */ ++} wme_max_bandwidth_t; ++ ++#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t)) ++ ++/* current version of wl_tspec_arg_t struct */ ++#define TSPEC_ARG_VERSION 2 /**< current version of wl_tspec_arg_t struct */ ++#define TSPEC_ARG_LENGTH 55 /**< argument length from tsinfo to medium_time */ ++#define TSPEC_DEFAULT_DIALOG_TOKEN 42 /**< default dialog token */ ++#define TSPEC_DEFAULT_SBW_FACTOR 0x3000 /**< default surplus bw */ ++ ++ ++#define WL_WOWL_KEEPALIVE_MAX_PACKET_SIZE 80 ++#define WLC_WOWL_MAX_KEEPALIVE 2 ++ ++/** Packet lifetime configuration per ac */ ++typedef struct wl_lifetime { ++ uint32 ac; /**< access class */ ++ uint32 lifetime; /**< Packet lifetime value in ms */ ++} wl_lifetime_t; ++ ++/** Management time configuration */ ++typedef struct wl_lifetime_mg { ++ uint32 mgmt_bitmap; /**< Mgmt subtype */ ++ uint32 lifetime; /**< Packet lifetime value in us */ ++} wl_lifetime_mg_t; ++ ++/* MAC Sample Capture related */ ++#define WL_MACCAPTR_DEFSTART_PTR 0xA00 ++#define WL_MACCAPTR_DEFSTOP_PTR 0xA3F ++#define WL_MACCAPTR_DEFSZ 0x3F ++ ++#define WL_MACCAPTR_DEF_MASK 0xFFFFFFFF ++ ++typedef enum { ++ WL_MACCAPT_TRIG = 0, ++ WL_MACCAPT_STORE = 1, ++ WL_MACCAPT_TRANS = 2, ++ WL_MACCAPT_MATCH = 3 ++} maccaptr_optn; ++ ++typedef enum { ++ WL_MACCAPT_STRT = 1, ++ WL_MACCAPT_STOP = 2, ++ WL_MACCAPT_RST = 3 ++} maccaptr_cmd_t; ++ ++/* MAC Sample Capture Set-up Paramters */ ++typedef struct wl_maccapture_params { ++ uint8 gpio_sel; ++ uint8 la_mode; /* TRUE: GPIO Out Enabled */ ++ uint8 PAD[2]; ++ uint32 start_ptr; /* Start address to store */ ++ uint32 stop_ptr; /* Stop address to store */ ++ uint8 optn_bmp; /* Options */ ++ uint8 PAD[3]; ++ uint32 tr_mask; /* Trigger Mask */ ++ uint32 tr_val; /* Trigger Value */ ++ uint32 s_mask; /* Store Mode Mask */ ++ uint32 x_mask; /* Trans. Mode Mask */ ++ uint32 m_mask; /* Match Mode Mask */ ++ uint32 m_val; /* Match Value */ ++ maccaptr_cmd_t cmd; /* Start / Stop */ ++} wl_maccapture_params_t; ++ ++/** Channel Switch Announcement param */ ++typedef struct wl_chan_switch { ++ uint8 mode; /**< value 0 or 1 */ ++ uint8 count; /**< count # of beacons before switching */ ++ chanspec_t chspec; /**< chanspec */ ++ uint8 reg; /**< regulatory class */ ++ uint8 frame_type; /**< csa frame type, unicast or broadcast */ ++} wl_chan_switch_t; ++ ++enum { ++ PFN_LIST_ORDER, ++ PFN_RSSI ++}; ++ ++enum { ++ DISABLE, ++ ENABLE ++}; ++ ++enum { ++ OFF_ADAPT, ++ SMART_ADAPT, ++ STRICT_ADAPT, ++ SLOW_ADAPT ++}; ++ ++#define SORT_CRITERIA_BIT 0 ++#define AUTO_NET_SWITCH_BIT 1 ++#define ENABLE_BKGRD_SCAN_BIT 2 ++#define IMMEDIATE_SCAN_BIT 3 ++#define AUTO_CONNECT_BIT 4 ++#define ENABLE_BD_SCAN_BIT 5 ++#define ENABLE_ADAPTSCAN_BIT 6 ++#define IMMEDIATE_EVENT_BIT 8 ++#define SUPPRESS_SSID_BIT 9 ++#define ENABLE_NET_OFFLOAD_BIT 10 ++/** report found/lost events for SSID and BSSID networks seperately */ ++#define REPORT_SEPERATELY_BIT 11 ++ ++#define SORT_CRITERIA_MASK 0x0001 ++#define AUTO_NET_SWITCH_MASK 0x0002 ++#define ENABLE_BKGRD_SCAN_MASK 0x0004 ++#define IMMEDIATE_SCAN_MASK 0x0008 ++#define AUTO_CONNECT_MASK 0x0010 ++ ++#define ENABLE_BD_SCAN_MASK 0x0020 ++#define ENABLE_ADAPTSCAN_MASK 0x00c0 ++#define IMMEDIATE_EVENT_MASK 0x0100 ++#define SUPPRESS_SSID_MASK 0x0200 ++#define ENABLE_NET_OFFLOAD_MASK 0x0400 ++/** report found/lost events for SSID and BSSID networks seperately */ ++#define REPORT_SEPERATELY_MASK 0x0800 ++ ++#define PFN_VERSION 2 ++ ++#define PFN_COMPLETE 1 ++#define PFN_INCOMPLETE 0 ++ ++#define DEFAULT_BESTN 2 ++#define DEFAULT_MSCAN 0 ++#define DEFAULT_REPEAT 10 ++#define DEFAULT_EXP 2 ++ ++#define PFN_PARTIAL_SCAN_BIT 0 ++#define PFN_PARTIAL_SCAN_MASK 1 ++ ++#define PFN_SWC_RSSI_WINDOW_MAX 8 ++#define PFN_SWC_MAX_NUM_APS 16 ++#define PFN_HOTLIST_MAX_NUM_APS 64 ++ ++#define MAX_EPNO_HIDDEN_SSID 8 ++#define MAX_WHITELIST_SSID 2 ++ ++/* Version 1 and 2 for various scan results structures defined below */ ++#define PFN_SCANRESULTS_VERSION_V1 1 ++#define PFN_SCANRESULTS_VERSION_V2 2 ++ ++/** PFN network info structure */ ++typedef struct wl_pfn_subnet_info_v1 { ++ struct ether_addr BSSID; ++ uint8 channel; /**< channel number only */ ++ uint8 SSID_len; ++ uint8 SSID[32]; ++} wl_pfn_subnet_info_v1_t; ++ ++typedef struct wl_pfn_subnet_info_v2 { ++ struct ether_addr BSSID; ++ uint8 channel; /**< channel number only */ ++ uint8 SSID_len; ++ union { ++ uint8 SSID[32]; ++ uint16 index; ++ } u; ++} wl_pfn_subnet_info_v2_t; ++ ++typedef struct wl_pfn_net_info_v1 { ++ wl_pfn_subnet_info_v1_t pfnsubnet; ++ int16 RSSI; /**< receive signal strength (in dBm) */ ++ uint16 timestamp; /**< age in seconds */ ++} wl_pfn_net_info_v1_t; ++ ++typedef struct wl_pfn_net_info_v2 { ++ wl_pfn_subnet_info_v2_t pfnsubnet; ++ int16 RSSI; /**< receive signal strength (in dBm) */ ++ uint16 timestamp; /**< age in seconds */ ++} wl_pfn_net_info_v2_t; ++ ++/* Version 1 and 2 for various lbest scan results structures below */ ++#define PFN_LBEST_SCAN_RESULT_VERSION_V1 1 ++#define PFN_LBEST_SCAN_RESULT_VERSION_V2 2 ++ ++#define MAX_CHBKT_PER_RESULT 4 ++ ++typedef struct wl_pfn_lnet_info_v1 { ++ wl_pfn_subnet_info_v1_t pfnsubnet; /**< BSSID + channel + SSID len + SSID */ ++ uint16 flags; /**< partial scan, etc */ ++ int16 RSSI; /**< receive signal strength (in dBm) */ ++ uint32 timestamp; /**< age in miliseconds */ ++ uint16 rtt0; /**< estimated distance to this AP in centimeters */ ++ uint16 rtt1; /**< standard deviation of the distance to this AP in centimeters */ ++} wl_pfn_lnet_info_v1_t; ++ ++typedef struct wl_pfn_lnet_info_v2 { ++ wl_pfn_subnet_info_v2_t pfnsubnet; /**< BSSID + channel + SSID len + SSID */ ++ uint16 flags; /**< partial scan, etc */ ++ int16 RSSI; /**< receive signal strength (in dBm) */ ++ uint32 timestamp; /**< age in miliseconds */ ++ uint16 rtt0; /**< estimated distance to this AP in centimeters */ ++ uint16 rtt1; /**< standard deviation of the distance to this AP in centimeters */ ++} wl_pfn_lnet_info_v2_t; ++ ++typedef struct wl_pfn_lscanresults_v1 { ++ uint32 version; ++ uint32 status; ++ uint32 count; ++ wl_pfn_lnet_info_v1_t netinfo[1]; ++} wl_pfn_lscanresults_v1_t; ++ ++typedef struct wl_pfn_lscanresults_v2 { ++ uint32 version; ++ uint16 status; ++ uint16 count; ++ uint32 scan_ch_buckets[MAX_CHBKT_PER_RESULT]; ++ wl_pfn_lnet_info_v2_t netinfo[1]; ++} wl_pfn_lscanresults_v2_t; ++ ++/**this is used to report on 1-* pfn scan results */ ++typedef struct wl_pfn_scanresults_v1 { ++ uint32 version; ++ uint32 status; ++ uint32 count; ++ wl_pfn_net_info_v1_t netinfo[1]; ++} wl_pfn_scanresults_v1_t; ++ ++typedef struct wl_pfn_scanresults_v2 { ++ uint32 version; ++ uint32 status; ++ uint32 count; ++ uint32 scan_ch_bucket; ++ wl_pfn_net_info_v2_t netinfo[1]; ++} wl_pfn_scanresults_v2_t; ++ ++typedef struct wl_pfn_significant_net { ++ uint16 flags; ++ uint16 channel; ++ struct ether_addr BSSID; ++ int8 rssi[PFN_SWC_RSSI_WINDOW_MAX]; ++} wl_pfn_significant_net_t; ++ ++#define PFN_SWC_SCANRESULT_VERSION 1 ++ ++typedef struct wl_pfn_swc_results { ++ uint32 version; ++ uint32 pkt_count; /**< No. of results in current frame */ ++ uint32 total_count; /**< Total expected results */ ++ wl_pfn_significant_net_t list[]; ++} wl_pfn_swc_results_t; ++typedef struct wl_pfn_net_info_bssid { ++ struct ether_addr BSSID; ++ uint8 channel; /**< channel number only */ ++ int8 RSSI; /**< receive signal strength (in dBm) */ ++ uint16 flags; /**< (e.g. partial scan, off channel) */ ++ uint16 timestamp; /**< age in seconds */ ++} wl_pfn_net_info_bssid_t; ++ ++typedef struct wl_pfn_scanhist_bssid { ++ uint32 version; ++ uint32 status; ++ uint32 count; ++ wl_pfn_net_info_bssid_t netinfo[1]; ++} wl_pfn_scanhist_bssid_t; ++ ++/* Version 1 and 2 for various single scan result */ ++#define PFN_SCANRESULT_VERSION_V1 1 ++#define PFN_SCANRESULT_VERSION_V2 2 ++ ++/* used to report exactly one scan result */ ++/* plus reports detailed scan info in bss_info */ ++typedef struct wl_pfn_scanresult_v1 { ++ uint32 version; ++ uint32 status; ++ uint32 count; ++ wl_pfn_net_info_v1_t netinfo; ++ wl_bss_info_t bss_info; ++} wl_pfn_scanresult_v1_t; ++ ++typedef struct wl_pfn_scanresult_v2 { ++ uint32 version; ++ uint32 status; ++ uint32 count; ++ wl_pfn_net_info_v2_t netinfo; ++ wl_bss_info_t bss_info; ++} wl_pfn_scanresult_v2_t; ++ ++/**PFN data structure */ ++typedef struct wl_pfn_param { ++ int32 version; /**< PNO parameters version */ ++ int32 scan_freq; /**< Scan frequency */ ++ int32 lost_network_timeout; /**< Timeout in sec. to declare ++ * discovered network as lost ++ */ ++ int16 flags; /**< Bit field to control features ++ * of PFN such as sort criteria auto ++ * enable switch and background scan ++ */ ++ int16 rssi_margin; /**< Margin to avoid jitter for choosing a ++ * PFN based on RSSI sort criteria ++ */ ++ uint8 bestn; /**< number of best networks in each scan */ ++ uint8 mscan; /**< number of scans recorded */ ++ uint8 repeat; /**< Minimum number of scan intervals ++ *before scan frequency changes in adaptive scan ++ */ ++ uint8 exp; /**< Exponent of 2 for maximum scan interval */ ++ int32 slow_freq; /**< slow scan period */ ++} wl_pfn_param_t; ++ ++typedef struct wl_pfn_bssid { ++ struct ether_addr macaddr; ++ /* Bit4: suppress_lost, Bit3: suppress_found */ ++ uint16 flags; ++} wl_pfn_bssid_t; ++typedef struct wl_pfn_significant_bssid { ++ struct ether_addr macaddr; ++ int8 rssi_low_threshold; ++ int8 rssi_high_threshold; ++} wl_pfn_significant_bssid_t; ++#define WL_PFN_SUPPRESSFOUND_MASK 0x08 ++#define WL_PFN_SUPPRESSLOST_MASK 0x10 ++#define WL_PFN_SSID_IMPRECISE_MATCH 0x80 ++#define WL_PFN_SSID_SAME_NETWORK 0x10000 ++#define WL_PFN_SUPPRESS_AGING_MASK 0x20000 ++#define WL_PFN_FLUSH_ALL_SSIDS 0x40000 ++ ++#define WL_PFN_IOVAR_FLAG_MASK 0xFFFF00FF ++#define WL_PFN_RSSI_MASK 0xff00 ++#define WL_PFN_RSSI_SHIFT 8 ++ ++typedef struct wl_pfn_cfg { ++ uint32 reporttype; ++ int32 channel_num; ++ uint16 channel_list[WL_NUMCHANNELS]; ++ uint32 flags; ++} wl_pfn_cfg_t; ++ ++#define WL_PFN_SSID_CFG_VERSION 1 ++#define WL_PFN_SSID_CFG_CLEAR 0x1 ++ ++typedef struct wl_pfn_ssid_params { ++ int8 min5G_rssi; /* minimum 5GHz RSSI for a BSSID to be considered */ ++ int8 min2G_rssi; /* minimum 2.4GHz RSSI for a BSSID to be considered */ ++ int16 init_score_max; /* The maximum score that a network can have before bonuses */ ++ ++ int16 cur_bssid_bonus; /* Add to current bssid */ ++ int16 same_ssid_bonus; /* score bonus for all networks with the same network flag */ ++ int16 secure_bonus; /* score bonus for networks that are not open */ ++ int16 band_5g_bonus; ++} wl_pfn_ssid_params_t; ++ ++typedef struct wl_ssid_ext_params { ++ int8 min5G_rssi; /* minimum 5GHz RSSI for a BSSID to be considered */ ++ int8 min2G_rssi; /* minimum 2.4GHz RSSI for a BSSID to be considered */ ++ int16 init_score_max; /* The maximum score that a network can have before bonuses */ ++ int16 cur_bssid_bonus; /* Add to current bssid */ ++ int16 same_ssid_bonus; /* score bonus for all networks with the same network flag */ ++ int16 secure_bonus; /* score bonus for networks that are not open */ ++ int16 band_5g_bonus; ++} wl_ssid_ext_params_t; ++ ++typedef struct wl_pfn_ssid_cfg { ++ uint16 version; ++ uint16 flags; ++ wl_ssid_ext_params_t params; ++} wl_pfn_ssid_cfg_t; ++ ++#define CH_BUCKET_REPORT_NONE 0 ++#define CH_BUCKET_REPORT_SCAN_COMPLETE_ONLY 1 ++#define CH_BUCKET_REPORT_FULL_RESULT 2 ++#define CH_BUCKET_REPORT_SCAN_COMPLETE (CH_BUCKET_REPORT_SCAN_COMPLETE_ONLY | \ ++ CH_BUCKET_REPORT_FULL_RESULT) ++#define CH_BUCKET_REPORT_REGULAR 0 ++#define CH_BUCKET_GSCAN 4 ++ ++typedef struct wl_pfn_gscan_ch_bucket_cfg { ++ uint8 bucket_end_index; ++ uint8 bucket_freq_multiple; ++ uint8 flag; ++ uint8 reserved; ++ uint16 repeat; ++ uint16 max_freq_multiple; ++} wl_pfn_gscan_ch_bucket_cfg_t; ++ ++typedef struct wl_pfn_capabilities { ++ uint16 max_mscan; ++ uint16 max_bestn; ++ uint16 max_swc_bssid; ++ uint16 max_hotlist_bssid; ++} wl_pfn_capabilities_t; ++ ++#define GSCAN_SEND_ALL_RESULTS_MASK (1 << 0) ++#define GSCAN_ALL_BUCKETS_IN_FIRST_SCAN_MASK (1 << 3) ++#define GSCAN_CFG_FLAGS_ONLY_MASK (1 << 7) ++#define WL_GSCAN_CFG_VERSION 1 ++typedef struct wl_pfn_gscan_cfg { ++ uint16 version; ++ /** ++ * BIT0 1 = send probes/beacons to HOST ++ * BIT1 Reserved ++ * BIT2 Reserved ++ * Add any future flags here ++ * BIT7 1 = no other useful cfg sent ++ */ ++ uint8 flags; ++ /** Buffer filled threshold in % to generate an event */ ++ uint8 buffer_threshold; ++ /** ++ * No. of BSSIDs with "change" to generate an evt ++ * change - crosses rssi threshold/lost ++ */ ++ uint8 swc_nbssid_threshold; ++ /* Max=8 (for now) Size of rssi cache buffer */ ++ uint8 swc_rssi_window_size; ++ uint8 count_of_channel_buckets; ++ uint8 retry_threshold; ++ uint16 lost_ap_window; ++ wl_pfn_gscan_ch_bucket_cfg_t channel_bucket[1]; ++} wl_pfn_gscan_cfg_t; ++ ++#define WL_PFN_REPORT_ALLNET 0 ++#define WL_PFN_REPORT_SSIDNET 1 ++#define WL_PFN_REPORT_BSSIDNET 2 ++ ++#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ ++#define WL_PFN_CFG_FLAGS_RESERVED 0xfffffffe /**< Remaining reserved for future use */ ++ ++typedef struct wl_pfn { ++ wlc_ssid_t ssid; /**< ssid name and its length */ ++ int32 flags; /**< bit2: hidden */ ++ int32 infra; /**< BSS Vs IBSS */ ++ int32 auth; /**< Open Vs Closed */ ++ int32 wpa_auth; /**< WPA type */ ++ int32 wsec; /**< wsec value */ ++} wl_pfn_t; ++ ++typedef struct wl_pfn_list { ++ uint32 version; ++ uint32 enabled; ++ uint32 count; ++ wl_pfn_t pfn[1]; ++} wl_pfn_list_t; ++ ++#define PFN_SSID_EXT_VERSION 1 ++ ++typedef struct wl_pfn_ext { ++ uint8 flags; ++ int8 rssi_thresh; /* RSSI threshold, track only if RSSI > threshold */ ++ uint16 wpa_auth; /* Match the wpa auth type defined in wlioctl_defs.h */ ++ uint8 ssid[DOT11_MAX_SSID_LEN]; ++ uint8 ssid_len; ++ uint8 pad; ++} wl_pfn_ext_t; ++typedef struct wl_pfn_ext_list { ++ uint16 version; ++ uint16 count; ++ wl_pfn_ext_t pfn_ext[1]; ++} wl_pfn_ext_list_t; ++ ++#define WL_PFN_SSID_EXT_FOUND 0x1 ++#define WL_PFN_SSID_EXT_LOST 0x2 ++typedef struct wl_pfn_result_ssid { ++ uint8 flags; ++ int8 rssi; ++ /* channel number */ ++ uint16 channel; ++ /* Assume idx in order of cfg */ ++ uint32 index; ++} wl_pfn_result_ssid_crc32_t; ++ ++typedef struct wl_pfn_ssid_ext_result { ++ uint16 version; ++ uint16 count; ++ wl_pfn_result_ssid_crc32_t net[1]; ++} wl_pfn_ssid_ext_result_t; ++ ++#define PFN_EXT_AUTH_CODE_OPEN 1 /* open */ ++#define PFN_EXT_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */ ++#define PFN_EXT_AUTH_CODE_EAPOL 4 /* any EAPOL */ ++ ++#define WL_PFN_HIDDEN_BIT 2 ++#define WL_PFN_HIDDEN_MASK 0x4 ++ ++#ifndef BESTN_MAX ++#define BESTN_MAX 10 ++#endif ++ ++#ifndef MSCAN_MAX ++#define MSCAN_MAX 90 ++#endif ++ ++/* Dynamic scan configuration for motion profiles */ ++ ++#define WL_PFN_MPF_VERSION 1 ++ ++/* Valid group IDs, may be expanded in the future */ ++#define WL_PFN_MPF_GROUP_SSID 0 ++#define WL_PFN_MPF_GROUP_BSSID 1 ++#define WL_PFN_MPF_MAX_GROUPS 2 ++ ++/* Max number of MPF states supported in this time */ ++#define WL_PFN_MPF_STATES_MAX 4 ++ ++/* Flags for the mpf-specific stuff */ ++#define WL_PFN_MPF_ADAPT_ON_BIT 0 ++#define WL_PFN_MPF_ADAPTSCAN_BIT 1 ++ ++#define WL_PFN_MPF_ADAPT_ON_MASK 0x0001 ++#define WL_PFN_MPF_ADAPTSCAN_MASK 0x0006 ++ ++/* Per-state timing values */ ++typedef struct wl_pfn_mpf_state_params { ++ int32 scan_freq; /* Scan frequency (secs) */ ++ int32 lost_network_timeout; /* Timeout to declare net lost (secs) */ ++ int16 flags; /* Space for flags: ADAPT etc */ ++ uint8 exp; /* Exponent of 2 for max interval for SMART/STRICT_ADAPT */ ++ uint8 repeat; /* Number of scans before changing adaptation level */ ++ int32 slow_freq; /* Slow scan period for SLOW_ADAPT */ ++} wl_pfn_mpf_state_params_t; ++ ++typedef struct wl_pfn_mpf_param { ++ uint16 version; /* Structure version */ ++ uint16 groupid; /* Group ID: 0 (SSID), 1 (BSSID), other: reserved */ ++ wl_pfn_mpf_state_params_t state[WL_PFN_MPF_STATES_MAX]; ++} wl_pfn_mpf_param_t; ++ ++/* Structure for setting pfn_override iovar */ ++typedef struct wl_pfn_override_param { ++ uint16 version; /* Structure version */ ++ uint16 start_offset; /* Seconds from now to apply new params */ ++ uint16 duration; /* Seconds to keep new params applied */ ++ uint16 reserved; ++ wl_pfn_mpf_state_params_t override; ++} wl_pfn_override_param_t; ++#define WL_PFN_OVERRIDE_VERSION 1 ++ ++/* ++ * Definitions for base MPF configuration ++ */ ++ ++#define WL_MPF_VERSION 1 ++#define WL_MPF_MAX_BITS 3 ++#define WL_MPF_MAX_STATES (1 << WL_MPF_MAX_BITS) ++ ++#define WL_MPF_STATE_NAME_MAX 12 ++ ++typedef struct wl_mpf_val { ++ uint16 val; /* Value of GPIO bits */ ++ uint16 state; /* State identifier */ ++ char name[WL_MPF_STATE_NAME_MAX]; /* Optional name */ ++} wl_mpf_val_t; ++ ++typedef struct wl_mpf_map { ++ uint16 version; ++ uint16 type; ++ uint16 mask; /* Which GPIO bits to use */ ++ uint8 count; /* Count of state/value mappings */ ++ uint8 PAD; ++ wl_mpf_val_t vals[WL_MPF_MAX_STATES]; ++} wl_mpf_map_t; ++ ++#define WL_MPF_STATE_AUTO (0xFFFF) /* (uint16)-1) */ ++ ++typedef struct wl_mpf_state { ++ uint16 version; ++ uint16 type; ++ uint16 state; /* Get/Set */ ++ uint8 force; /* 0 - auto (HW) state, 1 - forced state */ ++ char name[WL_MPF_STATE_NAME_MAX]; /* Get/Set: Optional/actual name */ ++ uint8 PAD; ++} wl_mpf_state_t; ++/* ++ * WLFCTS definition ++ */ ++typedef struct wl_txstatus_additional_info { ++ uint32 rspec; ++ uint32 enq_ts; ++ uint32 last_ts; ++ uint32 entry_ts; ++ uint16 seq; ++ uint8 rts_cnt; ++ uint8 tx_cnt; ++} wl_txstatus_additional_info_t; ++ ++/** Service discovery */ ++typedef struct { ++ uint8 transaction_id; /**< Transaction id */ ++ uint8 protocol; /**< Service protocol type */ ++ uint16 query_len; /**< Length of query */ ++ uint16 response_len; /**< Length of response */ ++ uint8 qrbuf[]; ++} wl_p2po_qr_t; ++ ++typedef struct { ++ uint16 period; /**< extended listen period */ ++ uint16 interval; /**< extended listen interval */ ++ uint16 count; /* count to repeat */ ++ uint16 pad; /* pad for 32bit align */ ++} wl_p2po_listen_t; ++ ++/** GAS state machine tunable parameters. Structure field values of 0 means use the default. */ ++typedef struct wl_gas_config { ++ uint16 max_retransmit; /**< Max # of firmware/driver retransmits on no Ack ++ * from peer (on top of the ucode retries). ++ */ ++ uint16 response_timeout; /**< Max time to wait for a GAS-level response ++ * after sending a packet. ++ */ ++ uint16 max_comeback_delay; /**< Max GAS response comeback delay. ++ * Exceeding this fails the GAS exchange. ++ */ ++ uint16 max_retries; /**< Max # of GAS state machine retries on failure ++ * of a GAS frame exchange. ++ */ ++} wl_gas_config_t; ++ ++/** P2P Find Offload parameters */ ++typedef struct wl_p2po_find_config { ++ uint16 version; /**< Version of this struct */ ++ uint16 length; /**< sizeof(wl_p2po_find_config_t) */ ++ int32 search_home_time; /**< P2P search state home time when concurrent ++ * connection exists. -1 for default. ++ */ ++ uint8 num_social_channels; ++ /**< Number of social channels up to WL_P2P_SOCIAL_CHANNELS_MAX. ++ * 0 means use default social channels. ++ */ ++ uint8 flags; ++ uint16 social_channels[1]; /**< Variable length array of social channels */ ++} wl_p2po_find_config_t; ++#define WL_P2PO_FIND_CONFIG_VERSION 2 /**< value for version field */ ++ ++/** wl_p2po_find_config_t flags */ ++#define P2PO_FIND_FLAG_SCAN_ALL_APS 0x01 /**< Whether to scan for all APs in the p2po_find ++ * periodic scans of all channels. ++ * 0 means scan for only P2P devices. ++ * 1 means scan for P2P devices plus non-P2P APs. ++ */ ++ ++ ++/** For adding a WFDS service to seek */ ++typedef struct { ++ uint32 seek_hdl; /**< unique id chosen by host */ ++ uint8 addr[6]; /**< Seek service from a specific device with this ++ * MAC address, all 1's for any device. ++ */ ++ uint8 service_hash[P2P_WFDS_HASH_LEN]; ++ uint8 service_name_len; ++ uint8 service_name[MAX_WFDS_SEEK_SVC_NAME_LEN]; ++ /**< Service name to seek, not null terminated */ ++ uint8 service_info_req_len; ++ uint8 service_info_req[1]; /**< Service info request, not null terminated. ++ * Variable length specified by service_info_req_len. ++ * Maximum length is MAX_WFDS_SEEK_SVC_INFO_LEN. ++ */ ++} wl_p2po_wfds_seek_add_t; ++ ++/** For deleting a WFDS service to seek */ ++typedef struct { ++ uint32 seek_hdl; /**< delete service specified by id */ ++} wl_p2po_wfds_seek_del_t; ++ ++ ++/** For adding a WFDS service to advertise */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 advertise_hdl; /**< unique id chosen by host */ ++ uint8 service_hash[P2P_WFDS_HASH_LEN]; ++ uint32 advertisement_id; ++ uint16 service_config_method; ++ uint8 service_name_len; ++ uint8 service_name[MAX_WFDS_SVC_NAME_LEN]; ++ /**< Service name , not null terminated */ ++ uint8 service_status; ++ uint16 service_info_len; ++ uint8 service_info[1]; /**< Service info, not null terminated. ++ * Variable length specified by service_info_len. ++ * Maximum length is MAX_WFDS_ADV_SVC_INFO_LEN. ++ */ ++} BWL_POST_PACKED_STRUCT wl_p2po_wfds_advertise_add_t; ++#include ++ ++/** For deleting a WFDS service to advertise */ ++typedef struct { ++ uint32 advertise_hdl; /**< delete service specified by hdl */ ++} wl_p2po_wfds_advertise_del_t; ++ ++/** P2P Offload discovery mode for the p2po_state iovar */ ++typedef enum { ++ WL_P2PO_DISC_STOP, ++ WL_P2PO_DISC_LISTEN, ++ WL_P2PO_DISC_DISCOVERY ++} disc_mode_t; ++ ++/* ANQP offload */ ++ ++#define ANQPO_MAX_QUERY_SIZE 256 ++typedef struct { ++ uint16 max_retransmit; /**< ~0 use default, max retransmit on no ACK from peer */ ++ uint16 response_timeout; /**< ~0 use default, msec to wait for resp after tx packet */ ++ uint16 max_comeback_delay; /**< ~0 use default, max comeback delay in resp else fail */ ++ uint16 max_retries; /**< ~0 use default, max retries on failure */ ++ uint16 query_len; /**< length of ANQP query */ ++ uint8 query_data[1]; /**< ANQP encoded query (max ANQPO_MAX_QUERY_SIZE) */ ++} wl_anqpo_set_t; ++ ++typedef struct { ++ uint16 channel; /**< channel of the peer */ ++ struct ether_addr addr; /**< addr of the peer */ ++} wl_anqpo_peer_t; ++ ++#define ANQPO_MAX_PEER_LIST 64 ++typedef struct { ++ uint16 count; /**< number of peers in list */ ++ wl_anqpo_peer_t peer[1]; /**< max ANQPO_MAX_PEER_LIST */ ++} wl_anqpo_peer_list_t; ++ ++#define ANQPO_MAX_IGNORE_SSID 64 ++typedef struct { ++ uint8 is_clear; /**< set to clear list (not used on GET) */ ++ uint8 PAD; ++ uint16 count; /**< number of SSID in list */ ++ wlc_ssid_t ssid[1]; /**< max ANQPO_MAX_IGNORE_SSID */ ++} wl_anqpo_ignore_ssid_list_t; ++ ++#define ANQPO_MAX_IGNORE_BSSID 64 ++typedef struct { ++ uint8 is_clear; /**< set to clear list (not used on GET) */ ++ uint8 PAD; ++ uint16 count; /**< number of addr in list */ ++ struct ether_addr bssid[]; /**< max ANQPO_MAX_IGNORE_BSSID */ ++} wl_anqpo_ignore_bssid_list_t; ++ ++ ++struct toe_ol_stats_t { ++ /** Num of tx packets that don't need to be checksummed */ ++ uint32 tx_summed; ++ ++ /* Num of tx packets where checksum is filled by offload engine */ ++ uint32 tx_iph_fill; ++ uint32 tx_tcp_fill; ++ uint32 tx_udp_fill; ++ uint32 tx_icmp_fill; ++ ++ /* Num of rx packets where toe finds out if checksum is good or bad */ ++ uint32 rx_iph_good; ++ uint32 rx_iph_bad; ++ uint32 rx_tcp_good; ++ uint32 rx_tcp_bad; ++ uint32 rx_udp_good; ++ uint32 rx_udp_bad; ++ uint32 rx_icmp_good; ++ uint32 rx_icmp_bad; ++ ++ /* Num of tx packets in which csum error is injected */ ++ uint32 tx_tcp_errinj; ++ uint32 tx_udp_errinj; ++ uint32 tx_icmp_errinj; ++ ++ /* Num of rx packets in which csum error is injected */ ++ uint32 rx_tcp_errinj; ++ uint32 rx_udp_errinj; ++ uint32 rx_icmp_errinj; ++}; ++ ++/** Arp offload statistic counts */ ++struct arp_ol_stats_t { ++ uint32 host_ip_entries; /**< Host IP table addresses (more than one if multihomed) */ ++ uint32 host_ip_overflow; /**< Host IP table additions skipped due to overflow */ ++ ++ uint32 arp_table_entries; /**< ARP table entries */ ++ uint32 arp_table_overflow; /**< ARP table additions skipped due to overflow */ ++ ++ uint32 host_request; /**< ARP requests from host */ ++ uint32 host_reply; /**< ARP replies from host */ ++ uint32 host_service; /**< ARP requests from host serviced by ARP Agent */ ++ ++ uint32 peer_request; /**< ARP requests received from network */ ++ uint32 peer_request_drop; /**< ARP requests from network that were dropped */ ++ uint32 peer_reply; /**< ARP replies received from network */ ++ uint32 peer_reply_drop; /**< ARP replies from network that were dropped */ ++ uint32 peer_service; /**< ARP request from host serviced by ARP Agent */ ++}; ++ ++/** NS offload statistic counts */ ++struct nd_ol_stats_t { ++ uint32 host_ip_entries; /**< Host IP table addresses (more than one if multihomed) */ ++ uint32 host_ip_overflow; /**< Host IP table additions skipped due to overflow */ ++ uint32 peer_request; /**< NS requests received from network */ ++ uint32 peer_request_drop; /**< NS requests from network that were dropped */ ++ uint32 peer_reply_drop; /**< NA replies from network that were dropped */ ++ uint32 peer_service; /**< NS request from host serviced by firmware */ ++}; ++ ++/* ++ * Neighbor Discovery Offloading ++ */ ++enum { ++ WL_ND_IPV6_ADDR_TYPE_UNICAST = 0, ++ WL_ND_IPV6_ADDR_TYPE_ANYCAST ++}; ++ ++typedef struct wl_nd_host_ip_addr { ++ struct ipv6_addr ip_addr; /* host ip address */ ++ uint8 type; /* type of address */ ++ uint8 pad[3]; ++} wl_nd_host_ip_addr_t; ++ ++typedef struct wl_nd_host_ip_list { ++ uint32 count; ++ wl_nd_host_ip_addr_t host_ip[1]; ++} wl_nd_host_ip_list_t; ++ ++#define WL_ND_HOSTIP_IOV_VER 1 ++ ++enum { ++ WL_ND_HOSTIP_OP_VER = 0, /* get version */ ++ WL_ND_HOSTIP_OP_ADD, /* add address */ ++ WL_ND_HOSTIP_OP_DEL, /* delete specified address */ ++ WL_ND_HOSTIP_OP_DEL_UC, /* delete all unicast address */ ++ WL_ND_HOSTIP_OP_DEL_AC, /* delete all anycast address */ ++ WL_ND_HOSTIP_OP_DEL_ALL, /* delete all addresses */ ++ WL_ND_HOSTIP_OP_LIST, /* get list of host ip address */ ++ WL_ND_HOSTIP_OP_MAX ++}; ++ ++typedef struct wl_nd_hostip { ++ uint16 version; /* version of iovar buf */ ++ uint16 op_type; /* operation type */ ++ uint32 length; /* length of entire structure */ ++ union { ++ wl_nd_host_ip_addr_t host_ip; /* set param for add */ ++ uint16 version; /* get return for ver */ ++ } u; ++} wl_nd_hostip_t; ++ ++#define WL_ND_HOSTIP_FIXED_LEN OFFSETOF(wl_nd_hostip_t, u) ++#define WL_ND_HOSTIP_WITH_ADDR_LEN (WL_ND_HOSTIP_FIXED_LEN + sizeof(wl_nd_host_ip_addr_t)) ++ ++/* ++ * Keep-alive packet offloading. ++ */ ++ ++/** ++ * NAT keep-alive packets format: specifies the re-transmission period, the packet ++ * length, and packet contents. ++ */ ++typedef struct wl_keep_alive_pkt { ++ uint32 period_msec; /** Retransmission period (0 to disable packet re-transmits) */ ++ uint16 len_bytes; /* Size of packet to transmit (0 to disable packet re-transmits) */ ++ uint8 data[1]; /** Variable length packet to transmit. Contents should include ++ * entire ethernet packet (enet header, IP header, UDP header, ++ * and UDP payload) in network byte order. ++ */ ++} wl_keep_alive_pkt_t; ++ ++#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data) ++ ++#define MAX_RSSI_COUNT 8 ++typedef struct rssi_struct { ++ int8 val[MAX_RSSI_COUNT]; /**< rssi values in AFs */ ++ int16 sum; /**< total rssi sum */ ++ uint8 cnt; /**< number rssi samples */ ++ uint8 idx; /**< next rssi location */ ++} rssi_struct_t; ++ ++ ++/* ++ * ptk_start: iovar to start 4-way handshake for secured ranging ++*/ ++ ++/* ptk negotiation security type - determines negotiation parameters */ ++typedef enum { ++ WL_PTK_START_SEC_TYPE_PMK = 1 ++} wl_ptk_start_sec_type_t; ++ ++/* ptk negotiation role */ ++typedef enum { ++ ROLE_NONE = 0x0, ++ ROLE_AUTH = 0x1, ++ ROLE_SUP = 0x2, ++ ROLE_STATIC = 0x3, ++ ROLE_INVALID = 0xff, ++ WL_PTK_START_ROLE_NONE = ROLE_NONE, ++ WL_PTK_START_ROLE_AUTH = ROLE_AUTH, ++ WL_PTK_START_ROLE_SUP = ROLE_SUP, ++ WL_PTK_START_ROLE_STATIC = ROLE_STATIC, ++ WL_PTK_START_ROLE_INVALID = ROLE_INVALID ++} wl_ptk_start_role_t; ++ ++typedef struct wl_ptk_start_tlv { ++ uint16 id; ++ uint16 len; ++ uint8 data[1]; ++} wl_ptk_start_tlv_t; ++ ++typedef enum { ++ WL_PTK_START_TLV_PMK = 1 /* uint8[] */ ++} wl_ptk_start_tlv_type; ++ ++typedef enum { ++ WL_PTK_START_FLAG_NO_DATA_PROT = 1, /* data frame protection disabled */ ++ WL_PTK_START_FLAG_GEN_FTM_TPK = 2 /* Generate FTM Toast/Seq Protection Key */ ++} wl_ptk_start_flags_t; ++ ++typedef struct wl_ptk_start_iov { ++ uint16 version; ++ uint16 len; /* length of entire iov from version */ ++ wl_ptk_start_flags_t flags; ++ wl_ptk_start_sec_type_t sec_type; ++ wl_ptk_start_role_t role; ++ struct ether_addr peer_addr; ++ uint16 pad; /* reserved/32 bit alignment */ ++ wl_ptk_start_tlv_t tlvs[1]; ++} wl_ptk_start_iov_t; ++ ++/* ++ * Dongle pattern matching filter. ++ */ ++ ++#define MAX_WAKE_PACKET_CACHE_BYTES 128 /**< Maximum cached wake packet */ ++ ++#define MAX_WAKE_PACKET_BYTES (DOT11_A3_HDR_LEN + \ ++ DOT11_QOS_LEN + \ ++ sizeof(struct dot11_llc_snap_header) + \ ++ ETHER_MAX_DATA) ++ ++typedef struct pm_wake_packet { ++ uint32 status; /**< Is the wake reason a packet (if all the other field's valid) */ ++ uint32 pattern_id; /**< Pattern ID that matched */ ++ uint32 original_packet_size; ++ uint32 saved_packet_size; ++ uint8 packet[MAX_WAKE_PACKET_CACHE_BYTES]; ++} pm_wake_packet_t; ++ ++/* Packet filter types. Currently, only pattern matching is supported. */ ++typedef enum wl_pkt_filter_type { ++ WL_PKT_FILTER_TYPE_PATTERN_MATCH=0, /**< Pattern matching filter */ ++ WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH=1, /**< Magic packet match */ ++ WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH=2, /**< A pattern list (match all to match filter) */ ++ WL_PKT_FILTER_TYPE_ENCRYPTED_PATTERN_MATCH=3, /**< SECURE WOWL magic / net pattern match */ ++ WL_PKT_FILTER_TYPE_APF_MATCH=4, /* Android packet filter match */ ++ WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT=5, /* Pattern matching filter with timeout event */ ++ WL_PKT_FILTER_TYPE_IMMEDIATE_PATTERN_MATCH=6, /* Immediately pattern matching filter */ ++ WL_PKT_FILTYER_TYPE_MAX = 7, /* Pkt filter type MAX */ ++} wl_pkt_filter_type_t; ++ ++#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t ++ ++/* String mapping for types that may be used by applications or debug */ ++#define WL_PKT_FILTER_TYPE_NAMES \ ++ { "PATTERN", WL_PKT_FILTER_TYPE_PATTERN_MATCH }, \ ++ { "MAGIC", WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH }, \ ++ { "PATLIST", WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH }, \ ++ { "SECURE WOWL", WL_PKT_FILTER_TYPE_ENCRYPTED_PATTERN_MATCH }, \ ++ { "APF", WL_PKT_FILTER_TYPE_APF_MATCH }, \ ++ { "PATTERN TIMEOUT", WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT }, \ ++ { "IMMEDIATE", WL_PKT_FILTER_TYPE_IMMEDIATE_PATTERN_MATCH } ++ ++/** Secured WOWL packet was encrypted, need decrypted before check filter match */ ++typedef struct wl_pkt_decrypter { ++ uint8* (*dec_cb)(void* dec_ctx, const void *sdu, int sending); ++ void* dec_ctx; ++} wl_pkt_decrypter_t; ++ ++/** ++ * Pattern matching filter. Specifies an offset within received packets to ++ * start matching, the pattern to match, the size of the pattern, and a bitmask ++ * that indicates which bits within the pattern should be matched. ++ */ ++typedef struct wl_pkt_filter_pattern { ++ uint32 offset; /**< Offset within received packet to start pattern matching. ++ * Offset '0' is the first byte of the ethernet header. ++ */ ++ uint32 size_bytes; /**< Size of the pattern. Bitmask must be the same size. */ ++ uint8 mask_and_pattern[]; /**< Variable length mask and pattern data. mask starts ++ * at offset 0. Pattern immediately follows mask. for ++ * secured pattern, put the descrypter pointer to the ++ * beginning, mask and pattern postponed correspondingly ++ */ ++} wl_pkt_filter_pattern_t; ++ ++/** A pattern list is a numerically specified list of modified pattern structures. */ ++typedef struct wl_pkt_filter_pattern_listel { ++ uint16 rel_offs; /**< Offset to begin match (relative to 'base' below) */ ++ uint16 base_offs; /**< Base for offset (defined below) */ ++ uint16 size_bytes; /**< Size of mask/pattern */ ++ uint16 match_flags; /**< Addition flags controlling the match */ ++ uint8 mask_and_data[1]; /**< Variable length mask followed by data, each size_bytes */ ++} wl_pkt_filter_pattern_listel_t; ++ ++typedef struct wl_pkt_filter_pattern_list { ++ uint8 list_cnt; /**< Number of elements in the list */ ++ uint8 PAD1[1]; /**< Reserved (possible version: reserved) */ ++ uint16 totsize; /**< Total size of this pattern list (includes this struct) */ ++ wl_pkt_filter_pattern_listel_t patterns[]; /**< Variable number of list elements */ ++} wl_pkt_filter_pattern_list_t; ++ ++typedef struct wl_apf_program { ++ uint16 version; ++ uint16 instr_len; /* number of instruction blocks */ ++ uint32 inst_ts; /* program installation timestamp */ ++ uint8 instrs[]; /* variable length instructions */ ++} wl_apf_program_t; ++ ++typedef struct wl_pkt_filter_pattern_timeout { ++ uint32 offset; /* Offset within received packet to start pattern matching. ++ * Offset '0' is the first byte of the ethernet header. ++ */ ++ uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */ ++ uint32 timeout; /* Timeout(seconds) */ ++ uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. ++ * mask starts at offset 0. Pattern ++ * immediately follows mask. ++ */ ++} wl_pkt_filter_pattern_timeout_t; ++ ++/** IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ ++typedef struct wl_pkt_filter { ++ uint32 id; /**< Unique filter id, specified by app. */ ++ uint32 type; /**< Filter type (WL_PKT_FILTER_TYPE_xxx). */ ++ uint32 negate_match; /**< Negate the result of filter matches */ ++ union { /* Filter definitions */ ++ wl_pkt_filter_pattern_t pattern; /**< Pattern matching filter */ ++ wl_pkt_filter_pattern_list_t patlist; /**< List of patterns to match */ ++ wl_apf_program_t apf_program; /* apf program */ ++ wl_pkt_filter_pattern_timeout_t pattern_timeout; /* Pattern timeout event filter */ ++ } u; ++} wl_pkt_filter_t; ++ ++/** IOVAR "tcp_keep_set" parameter. Used to install tcp keep_alive stuff. */ ++typedef struct wl_tcp_keep_set { ++ uint32 val1; ++ uint32 val2; ++} wl_tcp_keep_set_t; ++ ++#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u) ++#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern) ++#define WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_list_t, patterns) ++#define WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN \ ++ OFFSETOF(wl_pkt_filter_pattern_listel_t, mask_and_data) ++#define WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN \ ++ OFFSETOF(wl_pkt_filter_pattern_timeout_t, mask_and_pattern) ++ ++#define WL_APF_INTERNAL_VERSION 1 ++#define WL_APF_PROGRAM_MAX_SIZE (2 * 1024) ++#define WL_APF_PROGRAM_FIXED_LEN OFFSETOF(wl_apf_program_t, instrs) ++#define WL_APF_PROGRAM_LEN(apf_program) \ ++ ((apf_program)->instr_len * sizeof((apf_program)->instrs[0])) ++#define WL_APF_PROGRAM_TOTAL_LEN(apf_program) \ ++ (WL_APF_PROGRAM_FIXED_LEN + WL_APF_PROGRAM_LEN(apf_program)) ++ ++/** IOVAR "pkt_filter_enable" parameter. */ ++typedef struct wl_pkt_filter_enable { ++ uint32 id; /**< Unique filter id */ ++ uint32 enable; /**< Enable/disable bool */ ++} wl_pkt_filter_enable_t; ++ ++/** IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */ ++typedef struct wl_pkt_filter_list { ++ uint32 num; /**< Number of installed packet filters */ ++ wl_pkt_filter_t filter[1]; /**< Variable array of packet filters. */ ++} wl_pkt_filter_list_t; ++ ++#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter) ++ ++/** IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */ ++typedef struct wl_pkt_filter_stats { ++ uint32 num_pkts_matched; /**< # filter matches for specified filter id */ ++ uint32 num_pkts_forwarded; /**< # packets fwded from dongle to host for all filters */ ++ uint32 num_pkts_discarded; /**< # packets discarded by dongle for all filters */ ++} wl_pkt_filter_stats_t; ++ ++/** IOVAR "pkt_filter_ports" parameter. Configure TCP/UDP port filters. */ ++typedef struct wl_pkt_filter_ports { ++ uint8 version; /**< Be proper */ ++ uint8 reserved; /**< Be really proper */ ++ uint16 count; /**< Number of ports following */ ++ /* End of fixed data */ ++ uint16 ports[1]; /**< Placeholder for ports[] */ ++} wl_pkt_filter_ports_t; ++ ++#define WL_PKT_FILTER_PORTS_FIXED_LEN OFFSETOF(wl_pkt_filter_ports_t, ports) ++ ++#define WL_PKT_FILTER_PORTS_VERSION 0 ++#define WL_PKT_FILTER_PORTS_MAX 128 ++ ++#define RSN_REPLAY_LEN 8 ++typedef struct _gtkrefresh { ++ uint8 KCK[RSN_KCK_LENGTH]; ++ uint8 KEK[RSN_KEK_LENGTH]; ++ uint8 ReplayCounter[RSN_REPLAY_LEN]; ++} gtk_keyinfo_t, *pgtk_keyinfo_t; ++ ++/** Sequential Commands ioctl */ ++typedef struct wl_seq_cmd_ioctl { ++ uint32 cmd; /**< common ioctl definition */ ++ uint32 len; /**< length of user buffer */ ++} wl_seq_cmd_ioctl_t; ++ ++#define WL_SEQ_CMD_ALIGN_BYTES 4 ++ ++/** ++ * These are the set of get IOCTLs that should be allowed when using ++ * IOCTL sequence commands. These are issued implicitly by wl.exe each time ++ * it is invoked. We never want to buffer these, or else wl.exe will stop working. ++ */ ++#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \ ++ (((cmd) == WLC_GET_MAGIC) || \ ++ ((cmd) == WLC_GET_VERSION) || \ ++ ((cmd) == WLC_GET_AP) || \ ++ ((cmd) == WLC_GET_INSTANCE)) ++ ++typedef struct wl_pkteng { ++ uint32 flags; ++ uint32 delay; /**< Inter-packet delay */ ++ uint32 nframes; /**< Number of frames */ ++ uint32 length; /**< Packet length */ ++ uint8 seqno; /**< Enable/disable sequence no. */ ++ struct ether_addr dest; /**< Destination address */ ++ struct ether_addr src; /**< Source address */ ++ uint8 PAD[3]; ++} wl_pkteng_t; ++ ++#define WL_PKTENG_RU_FILL_VER_1 1 ++// struct for ru packet engine ++typedef struct wl_pkteng_ru { ++ uint16 version; /* ver is 1 */ ++ uint16 length; /* size of complete structure */ ++ uint8 bw; /* bandwidth info */ ++ uint8 ru_alloc_val; /* ru allocation index number */ ++ uint8 mcs_val; /* mcs allocated value */ ++ uint8 nss_val; /* num of spatial streams */ ++ uint32 num_bytes; /* approx num of bytes to calculate other required params */ ++ uint8 cp_ltf_val ; /* GI and LTF symbol size */ ++ uint8 he_ltf_symb ; /* num of HE-LTF symbols */ ++ uint8 stbc; /* STBC support */ ++ uint8 coding_val; /* BCC/LDPC coding support */ ++ uint8 pe_category; /* PE duration 0/8/16usecs */ ++ uint8 dcm; /* dual carrier modulation */ ++ uint8 mumimo_ltfmode; /* ltf mode */ ++ uint8 PAD[1]; /* pad bytes to make structure occupy 4 byte aligned */ ++} wl_pkteng_ru_fill_t; ++ ++typedef struct wl_pkteng_stats { ++ uint32 lostfrmcnt; /**< RX PER test: no of frames lost (skip seqno) */ ++ int32 rssi; /**< RSSI */ ++ int32 snr; /**< signal to noise ratio */ ++ uint16 rxpktcnt[NUM_80211_RATES+1]; ++ uint8 rssi_qdb; /**< qdB portion of the computed rssi */ ++ uint8 PAD; ++} wl_pkteng_stats_t; ++ ++typedef struct wl_txcal_params { ++ wl_pkteng_t pkteng; ++ uint8 gidx_start; ++ int8 gidx_step; ++ uint8 gidx_stop; ++ uint8 PAD; ++} wl_txcal_params_t; ++ ++ ++typedef struct wl_sslpnphy_papd_debug_data { ++ uint8 psat_pwr; ++ uint8 psat_indx; ++ uint8 final_idx; ++ uint8 start_idx; ++ int32 min_phase; ++ int32 voltage; ++ int8 temperature; ++ uint8 PAD[3]; ++} wl_sslpnphy_papd_debug_data_t; ++typedef struct wl_sslpnphy_debug_data { ++ int16 papdcompRe [64]; ++ int16 papdcompIm [64]; ++} wl_sslpnphy_debug_data_t; ++typedef struct wl_sslpnphy_spbdump_data { ++ uint16 tbl_length; ++ int16 spbreal[256]; ++ int16 spbimg[256]; ++} wl_sslpnphy_spbdump_data_t; ++typedef struct wl_sslpnphy_percal_debug_data { ++ uint32 cur_idx; ++ uint32 tx_drift; ++ uint8 prev_cal_idx; ++ uint8 PAD[3]; ++ uint32 percal_ctr; ++ int32 nxt_cal_idx; ++ uint32 force_1idxcal; ++ uint32 onedxacl_req; ++ int32 last_cal_volt; ++ int8 last_cal_temp; ++ uint8 PAD[3]; ++ uint32 vbat_ripple; ++ uint32 exit_route; ++ int32 volt_winner; ++} wl_sslpnphy_percal_debug_data_t; ++ ++typedef enum { ++ wowl_pattern_type_bitmap = 0, ++ wowl_pattern_type_arp, ++ wowl_pattern_type_na ++} wowl_pattern_type_t; ++ ++typedef struct wl_wowl_pattern { ++ uint32 masksize; /**< Size of the mask in #of bytes */ ++ uint32 offset; /**< Pattern byte offset in packet */ ++ uint32 patternoffset; /**< Offset of start of pattern in the structure */ ++ uint32 patternsize; /**< Size of the pattern itself in #of bytes */ ++ uint32 id; /**< id */ ++ uint32 reasonsize; /**< Size of the wakeup reason code */ ++ wowl_pattern_type_t type; /**< Type of pattern */ ++ /* Mask follows the structure above */ ++ /* Pattern follows the mask is at 'patternoffset' from the start */ ++} wl_wowl_pattern_t; ++ ++typedef struct wl_wowl_pattern_list { ++ uint32 count; ++ wl_wowl_pattern_t pattern[1]; ++} wl_wowl_pattern_list_t; ++ ++typedef struct wl_wowl_wakeind { ++ uint8 pci_wakeind; /**< Whether PCI PMECSR PMEStatus bit was set */ ++ uint32 ucode_wakeind; /**< What wakeup-event indication was set by ucode */ ++} wl_wowl_wakeind_t; ++ ++/** per AC rate control related data structure */ ++typedef struct wl_txrate_class { ++ uint8 init_rate; ++ uint8 min_rate; ++ uint8 max_rate; ++} wl_txrate_class_t; ++ ++/** structure for Overlap BSS scan arguments */ ++typedef struct wl_obss_scan_arg { ++ int16 passive_dwell; ++ int16 active_dwell; ++ int16 bss_widthscan_interval; ++ int16 passive_total; ++ int16 active_total; ++ int16 chanwidth_transition_delay; ++ int16 activity_threshold; ++} wl_obss_scan_arg_t; ++ ++#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t) ++ ++/** RSSI event notification configuration. */ ++typedef struct wl_rssi_event { ++ uint32 rate_limit_msec; /**< # of events posted to application will be limited to ++ * one per specified period (0 to disable rate limit). ++ */ ++ uint8 num_rssi_levels; /**< Number of entries in rssi_levels[] below */ ++ int8 rssi_levels[MAX_RSSI_LEVELS]; /**< Variable number of RSSI levels. An event ++ * will be posted each time the RSSI of received ++ * beacons/packets crosses a level. ++ */ ++ int8 pad[3]; ++} wl_rssi_event_t; ++ ++#define RSSI_MONITOR_VERSION 1 ++#define RSSI_MONITOR_STOP (1 << 0) ++typedef struct wl_rssi_monitor_cfg { ++ uint8 version; ++ uint8 flags; ++ int8 max_rssi; ++ int8 min_rssi; ++} wl_rssi_monitor_cfg_t; ++ ++typedef struct wl_rssi_monitor_evt { ++ uint8 version; ++ int8 cur_rssi; ++ uint16 pad; ++} wl_rssi_monitor_evt_t; ++ ++/* CCA based channel quality event configuration */ ++#define WL_CHAN_QUAL_CCA 0 ++#define WL_CHAN_QUAL_NF 1 ++#define WL_CHAN_QUAL_NF_LTE 2 ++#define WL_CHAN_QUAL_TOTAL 3 ++ ++#define MAX_CHAN_QUAL_LEVELS 8 ++ ++typedef struct wl_chan_qual_metric { ++ uint8 id; /**< metric ID */ ++ uint8 num_levels; /**< Number of entries in rssi_levels[] below */ ++ uint16 flags; ++ int16 htol[MAX_CHAN_QUAL_LEVELS]; /**< threshold level array: hi-to-lo */ ++ int16 ltoh[MAX_CHAN_QUAL_LEVELS]; /**< threshold level array: lo-to-hi */ ++} wl_chan_qual_metric_t; ++ ++typedef struct wl_chan_qual_event { ++ uint32 rate_limit_msec; /**< # of events posted to application will be limited to ++ * one per specified period (0 to disable rate limit). ++ */ ++ uint16 flags; ++ uint16 num_metrics; ++ wl_chan_qual_metric_t metric[WL_CHAN_QUAL_TOTAL]; /**< metric array */ ++} wl_chan_qual_event_t; ++typedef struct wl_action_obss_coex_req { ++ uint8 info; ++ uint8 num; ++ uint8 ch_list[1]; ++} wl_action_obss_coex_req_t; ++ ++ ++/** IOVar parameter block for small MAC address array with type indicator */ ++#define WL_IOV_MAC_PARAM_LEN 4 ++ ++#define WL_IOV_PKTQ_LOG_PRECS 16 ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 num_addrs; ++ uint8 addr_type[WL_IOV_MAC_PARAM_LEN]; ++ struct ether_addr ea[WL_IOV_MAC_PARAM_LEN]; ++} BWL_POST_PACKED_STRUCT wl_iov_mac_params_t; ++#include ++ ++/** This is extra info that follows wl_iov_mac_params_t */ ++typedef struct { ++ uint32 addr_info[WL_IOV_MAC_PARAM_LEN]; ++} wl_iov_mac_extra_params_t; ++ ++/** Combined structure */ ++typedef struct { ++ wl_iov_mac_params_t params; ++ wl_iov_mac_extra_params_t extra_params; ++} wl_iov_mac_full_params_t; ++ ++/** Parameter block for PKTQ_LOG statistics */ ++#define PKTQ_LOG_COUNTERS_V4 \ ++ /* packets requested to be stored */ \ ++ uint32 requested; \ ++ /* packets stored */ \ ++ uint32 stored; \ ++ /* packets saved, because a lowest priority queue has given away one packet */ \ ++ uint32 saved; \ ++ /* packets saved, because an older packet from the same queue has been dropped */ \ ++ uint32 selfsaved; \ ++ /* packets dropped, because pktq is full with higher precedence packets */ \ ++ uint32 full_dropped; \ ++ /* packets dropped because pktq per that precedence is full */ \ ++ uint32 dropped; \ ++ /* packets dropped, in order to save one from a queue of a highest priority */ \ ++ uint32 sacrificed; \ ++ /* packets droped because of hardware/transmission error */ \ ++ uint32 busy; \ ++ /* packets re-sent because they were not received */ \ ++ uint32 retry; \ ++ /* packets retried again (ps pretend) prior to moving power save mode */ \ ++ uint32 ps_retry; \ ++ /* suppressed packet count */ \ ++ uint32 suppress; \ ++ /* packets finally dropped after retry limit */ \ ++ uint32 retry_drop; \ ++ /* the high-water mark of the queue capacity for packets - goes to zero as queue fills */ \ ++ uint32 max_avail; \ ++ /* the high-water mark of the queue utilisation for packets - ('inverse' of max_avail) */ \ ++ uint32 max_used; \ ++ /* the maximum capacity of the queue */ \ ++ uint32 queue_capacity; \ ++ /* count of rts attempts that failed to receive cts */ \ ++ uint32 rtsfail; \ ++ /* count of packets sent (acked) successfully */ \ ++ uint32 acked; \ ++ /* running total of phy rate of packets sent successfully */ \ ++ uint32 txrate_succ; \ ++ /* running total of phy 'main' rate */ \ ++ uint32 txrate_main; \ ++ /* actual data transferred successfully */ \ ++ uint32 throughput; \ ++ /* time difference since last pktq_stats */ \ ++ uint32 time_delta; ++ ++typedef struct { ++ PKTQ_LOG_COUNTERS_V4 ++} pktq_log_counters_v04_t; ++ ++/** v5 is the same as V4 with extra parameter */ ++typedef struct { ++ PKTQ_LOG_COUNTERS_V4 ++ /** cumulative time to transmit */ ++ uint32 airtime; ++} pktq_log_counters_v05_t; ++ ++typedef struct { ++ uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; ++ pktq_log_counters_v04_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; ++ uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; ++ uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; ++ char headings[]; ++} pktq_log_format_v04_t; ++ ++typedef struct { ++ uint8 num_prec[WL_IOV_MAC_PARAM_LEN]; ++ pktq_log_counters_v05_t counters[WL_IOV_MAC_PARAM_LEN][WL_IOV_PKTQ_LOG_PRECS]; ++ uint32 counter_info[WL_IOV_MAC_PARAM_LEN]; ++ uint32 pspretend_time_delta[WL_IOV_MAC_PARAM_LEN]; ++ char headings[]; ++} pktq_log_format_v05_t; ++ ++ ++typedef struct { ++ uint32 version; ++ wl_iov_mac_params_t params; ++ union { ++ pktq_log_format_v04_t v04; ++ pktq_log_format_v05_t v05; ++ } pktq_log; ++} wl_iov_pktq_log_t; ++ ++/* PKTQ_LOG_AUTO, PKTQ_LOG_DEF_PREC flags introduced in v05, they are ignored by v04 */ ++#define PKTQ_LOG_AUTO (1 << 31) ++#define PKTQ_LOG_DEF_PREC (1 << 30) ++ ++typedef struct wl_pfn_macaddr_cfg_0 { ++ uint8 version; ++ uint8 reserved; ++ struct ether_addr macaddr; ++} wl_pfn_macaddr_cfg_0_t; ++#define LEGACY1_WL_PFN_MACADDR_CFG_VER 0 ++#define WL_PFN_MAC_OUI_ONLY_MASK 1 ++#define WL_PFN_SET_MAC_UNASSOC_MASK 2 ++#define WL_PFN_RESTRICT_LA_MAC_MASK 4 ++#define WL_PFN_MACADDR_FLAG_MASK 0x7 ++/** To configure pfn_macaddr */ ++typedef struct wl_pfn_macaddr_cfg { ++ uint8 version; ++ uint8 flags; ++ struct ether_addr macaddr; ++} wl_pfn_macaddr_cfg_t; ++#define WL_PFN_MACADDR_CFG_VER 1 ++ ++/* ++ * SCB_BS_DATA iovar definitions start. ++ */ ++#define SCB_BS_DATA_STRUCT_VERSION 1 ++ ++/** The actual counters maintained for each station */ ++typedef struct { ++ /* The following counters are a subset of what pktq_stats provides per precedence. */ ++ uint32 retry; /**< packets re-sent because they were not received */ ++ uint32 retry_drop; /**< packets finally dropped after retry limit */ ++ uint32 rtsfail; /**< count of rts attempts that failed to receive cts */ ++ uint32 acked; /**< count of packets sent (acked) successfully */ ++ uint32 txrate_succ; /**< running total of phy rate of packets sent successfully */ ++ uint32 txrate_main; /**< running total of phy 'main' rate */ ++ uint32 throughput; /**< actual data transferred successfully */ ++ uint32 time_delta; /**< time difference since last pktq_stats */ ++ uint32 airtime; /**< cumulative total medium access delay in useconds */ ++} iov_bs_data_counters_t; ++ ++/** The structure for individual station information. */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ struct ether_addr station_address; /**< The station MAC address */ ++ uint16 station_flags; /**< Bit mask of flags, for future use. */ ++ iov_bs_data_counters_t station_counters; /**< The actual counter values */ ++} BWL_POST_PACKED_STRUCT iov_bs_data_record_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint16 structure_version; /**< Structure version number (for wl/wlu matching) */ ++ uint16 structure_count; /**< Number of iov_bs_data_record_t records following */ ++ iov_bs_data_record_t structure_record[1]; /**< 0 - structure_count records */ ++} BWL_POST_PACKED_STRUCT iov_bs_data_struct_t; ++#include ++ ++/* Bitmask of options that can be passed in to the iovar. */ ++enum { ++ SCB_BS_DATA_FLAG_NO_RESET = (1<<0) /**< Do not clear the counters after reading */ ++}; ++/* ++ * SCB_BS_DATA iovar definitions end. ++ */ ++ ++typedef struct wlc_extlog_cfg { ++ int32 max_number; ++ uint16 module; /**< bitmap */ ++ uint8 level; ++ uint8 flag; ++ uint16 version; ++ uint16 PAD; ++} wlc_extlog_cfg_t; ++ ++typedef struct log_record { ++ uint32 time; ++ uint16 module; ++ uint16 id; ++ uint8 level; ++ uint8 sub_unit; ++ uint8 seq_num; ++ uint8 pad; ++ int32 arg; ++ char str[MAX_ARGSTR_LEN]; ++ char PAD[4-MAX_ARGSTR_LEN%4]; ++} log_record_t; ++ ++typedef struct wlc_extlog_req { ++ uint32 from_last; ++ uint32 num; ++} wlc_extlog_req_t; ++ ++typedef struct wlc_extlog_results { ++ uint16 version; ++ uint16 record_len; ++ uint32 num; ++ log_record_t logs[1]; ++} wlc_extlog_results_t; ++ ++typedef struct log_idstr { ++ uint16 id; ++ uint16 flag; ++ uint8 arg_type; ++ const char *fmt_str; ++} log_idstr_t; ++ ++#define FMTSTRF_USER 1 ++ ++/* flat ID definitions ++ * New definitions HAVE TO BE ADDED at the end of the table. Otherwise, it will ++ * affect backward compatibility with pre-existing apps ++ */ ++typedef enum { ++ FMTSTR_DRIVER_UP_ID = 0, ++ FMTSTR_DRIVER_DOWN_ID = 1, ++ FMTSTR_SUSPEND_MAC_FAIL_ID = 2, ++ FMTSTR_NO_PROGRESS_ID = 3, ++ FMTSTR_RFDISABLE_ID = 4, ++ FMTSTR_REG_PRINT_ID = 5, ++ FMTSTR_EXPTIME_ID = 6, ++ FMTSTR_JOIN_START_ID = 7, ++ FMTSTR_JOIN_COMPLETE_ID = 8, ++ FMTSTR_NO_NETWORKS_ID = 9, ++ FMTSTR_SECURITY_MISMATCH_ID = 10, ++ FMTSTR_RATE_MISMATCH_ID = 11, ++ FMTSTR_AP_PRUNED_ID = 12, ++ FMTSTR_KEY_INSERTED_ID = 13, ++ FMTSTR_DEAUTH_ID = 14, ++ FMTSTR_DISASSOC_ID = 15, ++ FMTSTR_LINK_UP_ID = 16, ++ FMTSTR_LINK_DOWN_ID = 17, ++ FMTSTR_RADIO_HW_OFF_ID = 18, ++ FMTSTR_RADIO_HW_ON_ID = 19, ++ FMTSTR_EVENT_DESC_ID = 20, ++ FMTSTR_PNP_SET_POWER_ID = 21, ++ FMTSTR_RADIO_SW_OFF_ID = 22, ++ FMTSTR_RADIO_SW_ON_ID = 23, ++ FMTSTR_PWD_MISMATCH_ID = 24, ++ FMTSTR_FATAL_ERROR_ID = 25, ++ FMTSTR_AUTH_FAIL_ID = 26, ++ FMTSTR_ASSOC_FAIL_ID = 27, ++ FMTSTR_IBSS_FAIL_ID = 28, ++ FMTSTR_EXTAP_FAIL_ID = 29, ++ FMTSTR_MAX_ID ++} log_fmtstr_id_t; ++ ++/** 11k Neighbor Report element (unversioned, deprecated) */ ++typedef struct nbr_element { ++ uint8 id; ++ uint8 len; ++ struct ether_addr bssid; ++ uint32 bssid_info; ++ uint8 reg; ++ uint8 channel; ++ uint8 phytype; ++ uint8 pad; ++} nbr_element_t; ++ ++#define WL_RRM_NBR_RPT_VER 1 ++/** 11k Neighbor Report element */ ++typedef struct nbr_rpt_elem { ++ uint8 version; ++ uint8 id; ++ uint8 len; ++ uint8 pad; ++ struct ether_addr bssid; ++ uint8 pad_1[2]; ++ uint32 bssid_info; ++ uint8 reg; ++ uint8 channel; ++ uint8 phytype; ++ uint8 pad_2; ++ wlc_ssid_t ssid; ++ chanspec_t chanspec; ++ uint8 bss_trans_preference; ++ uint8 flags; ++} nbr_rpt_elem_t; ++ ++typedef enum event_msgs_ext_command { ++ EVENTMSGS_NONE = 0, ++ EVENTMSGS_SET_BIT = 1, ++ EVENTMSGS_RESET_BIT = 2, ++ EVENTMSGS_SET_MASK = 3 ++} event_msgs_ext_command_t; ++ ++#define EVENTMSGS_VER 1 ++#define EVENTMSGS_EXT_STRUCT_SIZE OFFSETOF(eventmsgs_ext_t, mask[0]) ++ ++/* len- for SET it would be mask size from the application to the firmware */ ++/* for GET it would be actual firmware mask size */ ++/* maxgetsize - is only used for GET. indicate max mask size that the */ ++/* application can read from the firmware */ ++typedef struct eventmsgs_ext ++{ ++ uint8 ver; ++ uint8 command; ++ uint8 len; ++ uint8 maxgetsize; ++ uint8 mask[1]; ++} eventmsgs_ext_t; ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct pcie_bus_tput_params { ++ /** no of host dma descriptors programmed by the firmware before a commit */ ++ uint16 max_dma_descriptors; ++ ++ uint16 host_buf_len; /**< length of host buffer */ ++ dmaaddr_t host_buf_addr; /**< physical address for bus_throughput_buf */ ++} BWL_POST_PACKED_STRUCT pcie_bus_tput_params_t; ++#include ++ ++typedef struct pcie_bus_tput_stats { ++ uint16 time_taken; /**< no of secs the test is run */ ++ uint16 nbytes_per_descriptor; /**< no of bytes of data dma ed per descriptor */ ++ ++ /** no of desciptors for which dma is sucessfully completed within the test time */ ++ uint32 count; ++} pcie_bus_tput_stats_t; ++ ++typedef struct keepalives_max_idle { ++ uint16 keepalive_count; /**< nmbr of keepalives per bss_max_idle period */ ++ uint8 mkeepalive_index; /**< mkeepalive_index for keepalive frame to be used */ ++ uint8 PAD; /**< to align next field */ ++ uint16 max_interval; /**< seconds */ ++} keepalives_max_idle_t; ++ ++#define PM_IGNORE_BCMC_PROXY_ARP (1 << 0) ++#define PM_IGNORE_BCMC_ALL_DMS_ACCEPTED (1 << 1) ++ ++/* ##### Power Stats section ##### */ ++ ++#define WL_PWRSTATS_VERSION 2 ++ ++/** Input structure for pwrstats IOVAR */ ++typedef struct wl_pwrstats_query { ++ uint16 length; /**< Number of entries in type array. */ ++ uint16 type[1]; /**< Types (tags) to retrieve. ++ * Length 0 (no types) means get all. ++ */ ++} wl_pwrstats_query_t; ++ ++/** This structure is for version 2; version 1 will be deprecated in by FW */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_pwrstats { ++ uint16 version; /**< Version = 2 is TLV format */ ++ uint16 length; /**< Length of entire structure */ ++ uint8 data[1]; /**< TLV data, a series of structures, ++ * each starting with type and length. ++ * ++ * Padded as necessary so each section ++ * starts on a 4-byte boundary. ++ * ++ * Both type and len are uint16, but the ++ * upper nibble of length is reserved so ++ * valid len values are 0-4095. ++ */ ++} BWL_POST_PACKED_STRUCT wl_pwrstats_t; ++#include ++#define WL_PWR_STATS_HDRLEN OFFSETOF(wl_pwrstats_t, data) ++ ++/* Bits for wake reasons */ ++#define WLC_PMD_WAKE_SET 0x1 ++#define WLC_PMD_PM_AWAKE_BCN 0x2 ++/* BIT:3 is no longer being used */ ++#define WLC_PMD_SCAN_IN_PROGRESS 0x8 ++#define WLC_PMD_RM_IN_PROGRESS 0x10 ++#define WLC_PMD_AS_IN_PROGRESS 0x20 ++#define WLC_PMD_PM_PEND 0x40 ++#define WLC_PMD_PS_POLL 0x80 ++#define WLC_PMD_CHK_UNALIGN_TBTT 0x100 ++#define WLC_PMD_APSD_STA_UP 0x200 ++#define WLC_PMD_TX_PEND_WAR 0x400 /* obsolete, can be reused */ ++#define WLC_PMD_GPTIMER_STAY_AWAKE 0x800 ++#define WLC_PMD_PM2_RADIO_SOFF_PEND 0x2000 ++#define WLC_PMD_NON_PRIM_STA_UP 0x4000 ++#define WLC_PMD_AP_UP 0x8000 ++ ++typedef struct wlc_pm_debug { ++ uint32 timestamp; /**< timestamp in millisecond */ ++ uint32 reason; /**< reason(s) for staying awake */ ++} wlc_pm_debug_t; ++ ++/** WL_PWRSTATS_TYPE_PM_AWAKE1 structures (for 6.25 firmware) */ ++#define WLC_STA_AWAKE_STATES_MAX_V1 30 ++#define WLC_PMD_EVENT_MAX_V1 32 ++/** Data sent as part of pwrstats IOVAR (and EXCESS_PM_WAKE event) */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct pm_awake_data_v1 { ++ uint32 curr_time; /**< ms */ ++ uint32 hw_macc; /**< HW maccontrol */ ++ uint32 sw_macc; /**< SW maccontrol */ ++ uint32 pm_dur; /**< Total sleep time in PM, msecs */ ++ uint32 mpc_dur; /**< Total sleep time in MPC, msecs */ ++ ++ /* int32 drifts = remote - local; +ve drift => local-clk slow */ ++ int32 last_drift; /**< Most recent TSF drift from beacon */ ++ int32 min_drift; /**< Min TSF drift from beacon in magnitude */ ++ int32 max_drift; /**< Max TSF drift from beacon in magnitude */ ++ ++ uint32 avg_drift; /**< Avg TSF drift from beacon */ ++ ++ /* Wake history tracking */ ++ uint8 pmwake_idx; /**< for stepping through pm_state */ ++ wlc_pm_debug_t pm_state[WLC_STA_AWAKE_STATES_MAX_V1]; /**< timestamped wake bits */ ++ uint32 pmd_event_wake_dur[WLC_PMD_EVENT_MAX_V1]; /**< cumulative usecs per wake reason */ ++ uint32 drift_cnt; /**< Count of drift readings over which avg_drift was computed */ ++} BWL_POST_PACKED_STRUCT pm_awake_data_v1_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_pm_awake_stats_v1 { ++ uint16 type; /**< WL_PWRSTATS_TYPE_PM_AWAKE */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ ++ pm_awake_data_v1_t awake_data; ++ uint32 frts_time; /**< Cumulative ms spent in frts since driver load */ ++ uint32 frts_end_cnt; /**< No of times frts ended since driver load */ ++} BWL_POST_PACKED_STRUCT wl_pwr_pm_awake_stats_v1_t; ++#include ++ ++/** WL_PWRSTATS_TYPE_PM_AWAKE2 structures. Data sent as part of pwrstats IOVAR */ ++typedef struct pm_awake_data_v2 { ++ uint32 curr_time; /**< ms */ ++ uint32 hw_macc; /**< HW maccontrol */ ++ uint32 sw_macc; /**< SW maccontrol */ ++ uint32 pm_dur; /**< Total sleep time in PM, msecs */ ++ uint32 mpc_dur; /**< Total sleep time in MPC, msecs */ ++ ++ /* int32 drifts = remote - local; +ve drift => local-clk slow */ ++ int32 last_drift; /**< Most recent TSF drift from beacon */ ++ int32 min_drift; /**< Min TSF drift from beacon in magnitude */ ++ int32 max_drift; /**< Max TSF drift from beacon in magnitude */ ++ ++ uint32 avg_drift; /**< Avg TSF drift from beacon */ ++ ++ /* Wake history tracking */ ++ ++ /* pmstate array (type wlc_pm_debug_t) start offset */ ++ uint16 pm_state_offset; ++ /** pmstate number of array entries */ ++ uint16 pm_state_len; ++ ++ /** array (type uint32) start offset */ ++ uint16 pmd_event_wake_dur_offset; ++ /** pmd_event_wake_dur number of array entries */ ++ uint16 pmd_event_wake_dur_len; ++ ++ uint32 drift_cnt; /**< Count of drift readings over which avg_drift was computed */ ++ uint8 pmwake_idx; /**< for stepping through pm_state */ ++ uint8 flags; /**< bit0: 1-sleep, 0- wake. bit1: 0-bit0 invlid, 1-bit0 valid */ ++ uint8 pad[2]; ++ uint32 frts_time; /**< Cumulative ms spent in frts since driver load */ ++ uint32 frts_end_cnt; /**< No of times frts ended since driver load */ ++} pm_awake_data_v2_t; ++ ++typedef struct wl_pwr_pm_awake_stats_v2 { ++ uint16 type; /**< WL_PWRSTATS_TYPE_PM_AWAKE */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ ++ pm_awake_data_v2_t awake_data; ++} wl_pwr_pm_awake_stats_v2_t; ++ ++/* bit0: 1-sleep, 0- wake. bit1: 0-bit0 invlid, 1-bit0 valid */ ++#define WL_PWR_PM_AWAKE_STATS_WAKE 0x02 ++#define WL_PWR_PM_AWAKE_STATS_ASLEEP 0x03 ++#define WL_PWR_PM_AWAKE_STATS_WAKE_MASK 0x03 ++ ++/* WL_PWRSTATS_TYPE_PM_AWAKE Version 2 structures taken from 4324/43342 */ ++/* These structures are only to be used with 4324/43342 devices */ ++ ++#define WL_STA_AWAKE_STATES_MAX_V2 30 ++#define WL_PMD_EVENT_MAX_V2 32 ++#define MAX_P2P_BSS_DTIM_PRD 4 ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct ucode_dbg_v2 { ++ uint32 macctrl; ++ uint16 m_p2p_hps; ++ uint16 m_p2p_bss_dtim_prd[MAX_P2P_BSS_DTIM_PRD]; ++ uint32 psmdebug[20]; ++ uint32 phydebug[20]; ++ uint32 psm_brc; ++ uint32 ifsstat; ++} BWL_POST_PACKED_STRUCT ucode_dbg_v2_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct pmalert_awake_data_v2 { ++ uint32 curr_time; /* ms */ ++ uint32 hw_macc; /* HW maccontrol */ ++ uint32 sw_macc; /* SW maccontrol */ ++ uint32 pm_dur; /* Total sleep time in PM, msecs */ ++ uint32 mpc_dur; /* Total sleep time in MPC, msecs */ ++ ++ /* int32 drifts = remote - local; +ve drift => local-clk slow */ ++ int32 last_drift; /* Most recent TSF drift from beacon */ ++ int32 min_drift; /* Min TSF drift from beacon in magnitude */ ++ int32 max_drift; /* Max TSF drift from beacon in magnitude */ ++ ++ uint32 avg_drift; /* Avg TSF drift from beacon */ ++ ++ /* Wake history tracking */ ++ uint8 pmwake_idx; /* for stepping through pm_state */ ++ wlc_pm_debug_t pm_state[WL_STA_AWAKE_STATES_MAX_V2]; /* timestamped wake bits */ ++ uint32 pmd_event_wake_dur[WL_PMD_EVENT_MAX_V2]; /* cumulative usecs per wake reason */ ++ uint32 drift_cnt; /* Count of drift readings over which avg_drift was computed */ ++ uint32 start_event_dur[WL_PMD_EVENT_MAX_V2]; /* start event-duration */ ++ ucode_dbg_v2_t ud; ++ uint32 frts_time; /* Cumulative ms spent in frts since driver load */ ++ uint32 frts_end_cnt; /* No of times frts ended since driver load */ ++} BWL_POST_PACKED_STRUCT pmalert_awake_data_v2_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct pm_alert_data_v2 { ++ uint32 version; ++ uint32 length; /* Length of entire structure */ ++ uint32 reasons; /* reason(s) for pm_alert */ ++ /* Following fields are present only for reasons ++ * PM_DUR_EXCEEDED, MPC_DUR_EXCEEDED & CONST_AWAKE_DUR_EXCEEDED ++ */ ++ uint32 prev_stats_time; /* msecs */ ++ uint32 prev_pm_dur; /* msecs */ ++ uint32 prev_mpc_dur; /* msecs */ ++ pmalert_awake_data_v2_t awake_data; ++} BWL_POST_PACKED_STRUCT pm_alert_data_v2_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_pm_awake_status_v2 { ++ uint16 type; /* WL_PWRSTATS_TYPE_PM_AWAKE */ ++ uint16 len; /* Up to 4K-1, top 4 bits are reserved */ ++ ++ pmalert_awake_data_v2_t awake_data; ++ uint32 frts_time; /* Cumulative ms spent in frts since driver load */ ++ uint32 frts_end_cnt; /* No of times frts ended since driver load */ ++} BWL_POST_PACKED_STRUCT wl_pwr_pm_awake_status_v2_t; ++#include ++ ++/* Below are latest definitions from PHO25178RC100_BRANCH_6_50 */ ++/* wl_pwr_pm_awake_stats_v1_t is used for WL_PWRSTATS_TYPE_PM_AWAKE */ ++/* (at least) the chip independent registers */ ++typedef struct ucode_dbg_ext { ++ uint32 x120; ++ uint32 x124; ++ uint32 x154; ++ uint32 x158; ++ uint32 x15c; ++ uint32 x180; ++ uint32 x184; ++ uint32 x188; ++ uint32 x18c; ++ uint32 x1a0; ++ uint32 x1a8; ++ uint32 x1e0; ++ uint32 scr_x14; ++ uint32 scr_x2b; ++ uint32 scr_x2c; ++ uint32 scr_x2d; ++ uint32 scr_x2e; ++ ++ uint16 x40a; ++ uint16 x480; ++ uint16 x490; ++ uint16 x492; ++ uint16 x4d8; ++ uint16 x4b8; ++ uint16 x4ba; ++ uint16 x4bc; ++ uint16 x4be; ++ uint16 x500; ++ uint16 x50e; ++ uint16 x522; ++ uint16 x546; ++ uint16 x578; ++ uint16 x602; ++ uint16 x646; ++ uint16 x648; ++ uint16 x666; ++ uint16 x670; ++ uint16 x690; ++ uint16 x692; ++ uint16 x6a0; ++ uint16 x6a2; ++ uint16 x6a4; ++ uint16 x6b2; ++ uint16 x7c0; ++ ++ uint16 shm_x20; ++ uint16 shm_x4a; ++ uint16 shm_x5e; ++ uint16 shm_x5f; ++ uint16 shm_xaab; ++ uint16 shm_x74a; ++ uint16 shm_x74b; ++ uint16 shm_x74c; ++ uint16 shm_x74e; ++ uint16 shm_x756; ++ uint16 shm_x75b; ++ uint16 shm_x7b9; ++ uint16 shm_x7d4; ++ ++ uint16 shm_P2P_HPS; ++ uint16 shm_P2P_intr[16]; ++ uint16 shm_P2P_perbss[48]; ++} ucode_dbg_ext_t; ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct pm_alert_data_v1 { ++ uint32 version; ++ uint32 length; /**< Length of entire structure */ ++ uint32 reasons; /**< reason(s) for pm_alert */ ++ /* Following fields are present only for reasons ++ * PM_DUR_EXCEEDED, MPC_DUR_EXCEEDED & CONST_AWAKE_DUR_EXCEEDED ++ */ ++ uint32 prev_stats_time; /**< msecs */ ++ uint32 prev_pm_dur; /**< msecs */ ++ uint32 prev_mpc_dur; /**< msecs */ ++ pm_awake_data_v1_t awake_data; ++ uint32 start_event_dur[WLC_PMD_EVENT_MAX_V1]; /**< start event-duration */ ++ ucode_dbg_v2_t ud; ++ uint32 frts_time; /**< Cumulative ms spent in frts since driver load */ ++ uint32 frts_end_cnt; /**< No of times frts ended since driver load */ ++ ucode_dbg_ext_t ud_ext; ++ uint32 prev_frts_dur; /**< ms */ ++} BWL_POST_PACKED_STRUCT pm_alert_data_v1_t; ++#include ++ ++/* End of 43342/4324 v2 structure definitions */ ++ ++/* Original bus structure is for HSIC */ ++ ++typedef struct bus_metrics { ++ uint32 suspend_ct; /**< suspend count */ ++ uint32 resume_ct; /**< resume count */ ++ uint32 disconnect_ct; /**< disconnect count */ ++ uint32 reconnect_ct; /**< reconnect count */ ++ uint32 active_dur; /**< msecs in bus, usecs for user */ ++ uint32 suspend_dur; /**< msecs in bus, usecs for user */ ++ uint32 disconnect_dur; /**< msecs in bus, usecs for user */ ++} bus_metrics_t; ++ ++/** Bus interface info for USB/HSIC */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_pwr_usb_hsic_stats { ++ uint16 type; /**< WL_PWRSTATS_TYPE_USB_HSIC */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ ++ bus_metrics_t hsic; /**< stats from hsic bus driver */ ++} BWL_POST_PACKED_STRUCT wl_pwr_usb_hsic_stats_t; ++#include ++ ++typedef struct pcie_bus_metrics { ++ uint32 d3_suspend_ct; /**< suspend count */ ++ uint32 d0_resume_ct; /**< resume count */ ++ uint32 perst_assrt_ct; /**< PERST# assert count */ ++ uint32 perst_deassrt_ct; /**< PERST# de-assert count */ ++ uint32 active_dur; /**< msecs */ ++ uint32 d3_suspend_dur; /**< msecs */ ++ uint32 perst_dur; /**< msecs */ ++ uint32 l0_cnt; /**< L0 entry count */ ++ uint32 l0_usecs; /**< L0 duration in usecs */ ++ uint32 l1_cnt; /**< L1 entry count */ ++ uint32 l1_usecs; /**< L1 duration in usecs */ ++ uint32 l1_1_cnt; /**< L1_1ss entry count */ ++ uint32 l1_1_usecs; /**< L1_1ss duration in usecs */ ++ uint32 l1_2_cnt; /**< L1_2ss entry count */ ++ uint32 l1_2_usecs; /**< L1_2ss duration in usecs */ ++ uint32 l2_cnt; /**< L2 entry count */ ++ uint32 l2_usecs; /**< L2 duration in usecs */ ++ uint32 timestamp; /**< Timestamp on when stats are collected */ ++ uint32 num_h2d_doorbell; /**< # of doorbell interrupts - h2d */ ++ uint32 num_d2h_doorbell; /**< # of doorbell interrupts - d2h */ ++ uint32 num_submissions; /**< # of submissions */ ++ uint32 num_completions; /**< # of completions */ ++ uint32 num_rxcmplt; /**< # of rx completions */ ++ uint32 num_rxcmplt_drbl; /**< of drbl interrupts for rx complt. */ ++ uint32 num_txstatus; /**< # of tx completions */ ++ uint32 num_txstatus_drbl; /**< of drbl interrupts for tx complt. */ ++ uint32 deepsleep_count; /**< # of times chip went to deepsleep */ ++ uint32 deepsleep_dur; /**< # of msecs chip was in deepsleep */ ++ uint32 ltr_active_ct; /**< # of times chip went to LTR ACTIVE */ ++ uint32 ltr_active_dur; /**< # of msecs chip was in LTR ACTIVE */ ++ uint32 ltr_sleep_ct; /**< # of times chip went to LTR SLEEP */ ++ uint32 ltr_sleep_dur; /**< # of msecs chip was in LTR SLEEP */ ++} pcie_bus_metrics_t; ++ ++/** Bus interface info for PCIE */ ++typedef struct wl_pwr_pcie_stats { ++ uint16 type; /**< WL_PWRSTATS_TYPE_PCIE */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ pcie_bus_metrics_t pcie; /**< stats from pcie bus driver */ ++} wl_pwr_pcie_stats_t; ++ ++/** Scan information history per category */ ++typedef struct scan_data { ++ uint32 count; /**< Number of scans performed */ ++ uint32 dur; /**< Total time (in us) used */ ++} scan_data_t; ++ ++typedef struct wl_pwr_scan_stats { ++ uint16 type; /**< WL_PWRSTATS_TYPE_SCAN */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ ++ /* Scan history */ ++ scan_data_t user_scans; /**< User-requested scans: (i/e/p)scan */ ++ scan_data_t assoc_scans; /**< Scans initiated by association requests */ ++ scan_data_t roam_scans; /**< Scans initiated by the roam engine */ ++ scan_data_t pno_scans[8]; /**< For future PNO bucketing (BSSID, SSID, etc) */ ++ scan_data_t other_scans; /**< Scan engine usage not assigned to the above */ ++} wl_pwr_scan_stats_t; ++ ++typedef struct wl_pwr_connect_stats { ++ uint16 type; /**< WL_PWRSTATS_TYPE_SCAN */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ ++ /* Connection (Association + Key exchange) data */ ++ uint32 count; /**< Number of connections performed */ ++ uint32 dur; /**< Total time (in ms) used */ ++} wl_pwr_connect_stats_t; ++ ++typedef struct wl_pwr_phy_stats { ++ uint16 type; /**< WL_PWRSTATS_TYPE_PHY */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ uint32 tx_dur; /**< TX Active duration in us */ ++ uint32 rx_dur; /**< RX Active duration in us */ ++} wl_pwr_phy_stats_t; ++ ++ ++typedef struct wl_mimo_meas_metrics_v1 { ++ uint16 type; ++ uint16 len; ++ /* Total time(us) idle in MIMO RX chain configuration */ ++ uint32 total_idle_time_mimo; ++ /* Total time(us) idle in SISO RX chain configuration */ ++ uint32 total_idle_time_siso; ++ /* Total receive time (us) in SISO RX chain configuration */ ++ uint32 total_rx_time_siso; ++ /* Total receive time (us) in MIMO RX chain configuration */ ++ uint32 total_rx_time_mimo; ++ /* Total 1-chain transmit time(us) */ ++ uint32 total_tx_time_1chain; ++ /* Total 2-chain transmit time(us) */ ++ uint32 total_tx_time_2chain; ++ /* Total 3-chain transmit time(us) */ ++ uint32 total_tx_time_3chain; ++} wl_mimo_meas_metrics_v1_t; ++ ++typedef struct wl_mimo_meas_metrics { ++ uint16 type; ++ uint16 len; ++ /* Total time(us) idle in MIMO RX chain configuration */ ++ uint32 total_idle_time_mimo; ++ /* Total time(us) idle in SISO RX chain configuration */ ++ uint32 total_idle_time_siso; ++ /* Total receive time (us) in SISO RX chain configuration */ ++ uint32 total_rx_time_siso; ++ /* Total receive time (us) in MIMO RX chain configuration */ ++ uint32 total_rx_time_mimo; ++ /* Total 1-chain transmit time(us) */ ++ uint32 total_tx_time_1chain; ++ /* Total 2-chain transmit time(us) */ ++ uint32 total_tx_time_2chain; ++ /* Total 3-chain transmit time(us) */ ++ uint32 total_tx_time_3chain; ++ /* End of original, OCL fields start here */ ++ /* Total time(us) idle in ocl mode */ ++ uint32 total_idle_time_ocl; ++ /* Total receive time (us) in ocl mode */ ++ uint32 total_rx_time_ocl; ++ /* End of OCL fields, internal adjustment fields here */ ++ /* Total SIFS idle time in MIMO mode */ ++ uint32 total_sifs_time_mimo; ++ /* Total SIFS idle time in SISO mode */ ++ uint32 total_sifs_time_siso; ++} wl_mimo_meas_metrics_t; ++/* ##### End of Power Stats section ##### */ ++ ++/** IPV4 Arp offloads for ndis context */ ++#include ++BWL_PRE_PACKED_STRUCT struct hostip_id { ++ struct ipv4_addr ipa; ++ uint8 id; ++} BWL_POST_PACKED_STRUCT; ++#include ++ ++/* Return values */ ++#define ND_REPLY_PEER 0x1 /**< Reply was sent to service NS request from peer */ ++#define ND_REQ_SINK 0x2 /**< Input packet should be discarded */ ++#define ND_FORCE_FORWARD 0X3 /**< For the dongle to forward req to HOST */ ++ ++/** Neighbor Solicitation Response Offload IOVAR param */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct nd_param { ++ struct ipv6_addr host_ip[2]; ++ struct ipv6_addr solicit_ip; ++ struct ipv6_addr remote_ip; ++ uint8 host_mac[ETHER_ADDR_LEN]; ++ uint32 offload_id; ++} BWL_POST_PACKED_STRUCT nd_param_t; ++#include ++ ++typedef struct wl_pfn_roam_thresh { ++ uint32 pfn_alert_thresh; /**< time in ms */ ++ uint32 roam_alert_thresh; /**< time in ms */ ++} wl_pfn_roam_thresh_t; ++ ++ ++/* Reasons for wl_pmalert_t */ ++#define PM_DUR_EXCEEDED (1<<0) ++#define MPC_DUR_EXCEEDED (1<<1) ++#define ROAM_ALERT_THRESH_EXCEEDED (1<<2) ++#define PFN_ALERT_THRESH_EXCEEDED (1<<3) ++#define CONST_AWAKE_DUR_ALERT (1<<4) ++#define CONST_AWAKE_DUR_RECOVERY (1<<5) ++ ++#define MIN_PM_ALERT_LEN 9 ++ ++/** Data sent in EXCESS_PM_WAKE event */ ++#define WL_PM_ALERT_VERSION 3 ++ ++/** This structure is for version 3; version 2 will be deprecated in by FW */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert { ++ uint16 version; /**< Version = 3 is TLV format */ ++ uint16 length; /**< Length of entire structure */ ++ uint32 reasons; /**< reason(s) for pm_alert */ ++ uint8 data[1]; /**< TLV data, a series of structures, ++ * each starting with type and length. ++ * ++ * Padded as necessary so each section ++ * starts on a 4-byte boundary. ++ * ++ * Both type and len are uint16, but the ++ * upper nibble of length is reserved so ++ * valid len values are 0-4095. ++ */ ++} BWL_POST_PACKED_STRUCT wl_pmalert_t; ++#include ++ ++/* Type values for the data section */ ++#define WL_PMALERT_FIXED 0 /**< struct wl_pmalert_fixed_t, fixed fields */ ++#define WL_PMALERT_PMSTATE 1 /**< struct wl_pmalert_pmstate_t, variable */ ++#define WL_PMALERT_EVENT_DUR 2 /**< struct wl_pmalert_event_dur_t, variable */ ++#define WL_PMALERT_UCODE_DBG 3 /**< struct wl_pmalert_ucode_dbg_v1, variable */ ++#define WL_PMALERT_PS_ALLOWED_HIST 4 /**< struct wl_pmalert_ps_allowed_history, variable */ ++#define WL_PMALERT_EXT_UCODE_DBG 5 /**< struct wl_pmalert_ext_ucode_dbg_t, variable */ ++#define WL_PMALERT_EPM_START_EVENT_DUR 6 /**< struct wl_pmalert_event_dur_t, variable */ ++#define WL_PMALERT_UCODE_DBG_V2 7 /**< struct wl_pmalert_ucode_dbg_v2, variable */ ++ ++typedef struct wl_pmalert_fixed { ++ uint16 type; /**< WL_PMALERT_FIXED */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ uint32 prev_stats_time; /**< msecs */ ++ uint32 curr_time; /**< ms */ ++ uint32 prev_pm_dur; /**< msecs */ ++ uint32 pm_dur; /**< Total sleep time in PM, msecs */ ++ uint32 prev_mpc_dur; /**< msecs */ ++ uint32 mpc_dur; /**< Total sleep time in MPC, msecs */ ++ uint32 hw_macc; /**< HW maccontrol */ ++ uint32 sw_macc; /**< SW maccontrol */ ++ ++ /* int32 drifts = remote - local; +ve drift -> local-clk slow */ ++ int32 last_drift; /**< Most recent TSF drift from beacon */ ++ int32 min_drift; /**< Min TSF drift from beacon in magnitude */ ++ int32 max_drift; /**< Max TSF drift from beacon in magnitude */ ++ ++ uint32 avg_drift; /**< Avg TSF drift from beacon */ ++ uint32 drift_cnt; /**< Count of drift readings over which avg_drift was computed */ ++ uint32 frts_time; /**< Cumulative ms spent in data frts since driver load */ ++ uint32 frts_end_cnt; /**< No of times frts ended since driver load */ ++ uint32 prev_frts_dur; /**< Data frts duration at start of pm-period */ ++ uint32 cal_dur; /**< Cumulative ms spent in calibration */ ++ uint32 prev_cal_dur; /**< cal duration at start of pm-period */ ++} wl_pmalert_fixed_t; ++ ++typedef struct wl_pmalert_pmstate { ++ uint16 type; /**< WL_PMALERT_PMSTATE */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ ++ uint8 pmwake_idx; /**< for stepping through pm_state */ ++ uint8 pad[3]; ++ /* Array of pmstate; len of array is based on tlv len */ ++ wlc_pm_debug_t pmstate[1]; ++} wl_pmalert_pmstate_t; ++ ++typedef struct wl_pmalert_event_dur { ++ uint16 type; /**< WL_PMALERT_EVENT_DUR */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ ++ /* Array of event_dur, len of array is based on tlv len */ ++ uint32 event_dur[1]; ++} wl_pmalert_event_dur_t; ++ ++#include ++BWL_PRE_PACKED_STRUCT struct wl_pmalert_ucode_dbg_v1 { ++ uint16 type; /* WL_PMALERT_UCODE_DBG */ ++ uint16 len; /* Up to 4K-1, top 4 bits are reserved */ ++ uint32 macctrl; ++ uint16 m_p2p_hps; ++ uint32 psm_brc; ++ uint32 ifsstat; ++ uint16 m_p2p_bss_dtim_prd[MAX_P2P_BSS_DTIM_PRD]; ++ uint32 psmdebug[20]; ++ uint32 phydebug[20]; ++ uint16 M_P2P_BSS[3][12]; ++ uint16 M_P2P_PRE_TBTT[3]; ++ ++ /* Following is valid only for corerevs<40 */ ++ uint16 xmtfifordy; ++ ++ /* Following 3 are valid only for 11ac corerevs (>=40) */ ++ uint16 psm_maccommand; ++ uint16 txe_status1; ++ uint16 AQMFifoReady; ++} BWL_POST_PACKED_STRUCT; ++#include ++ ++#include ++BWL_PRE_PACKED_STRUCT struct wl_pmalert_ucode_dbg_v2 { ++ uint16 type; /**< WL_PMALERT_UCODE_DBG_V2 */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ uint32 macctrl; ++ uint16 m_p2p_hps; ++ uint32 psm_brc; ++ uint32 ifsstat; ++ uint16 m_p2p_bss_dtim_prd[MAX_P2P_BSS_DTIM_PRD]; ++ uint32 psmdebug[20]; ++ uint32 phydebug[20]; ++ uint16 M_P2P_BSS[3][12]; ++ uint16 M_P2P_PRE_TBTT[3]; ++ ++ /* Following is valid only for corerevs<40 */ ++ uint16 xmtfifordy; ++ ++ /* Following 3 are valid only for 11ac corerevs (>=40) */ ++ uint16 psm_maccommand; ++ uint16 txe_status1; ++ uint32 AQMFifoReady; ++} BWL_POST_PACKED_STRUCT; ++#include ++ ++typedef struct wlc_ps_debug { ++ uint32 timestamp; /**< timestamp in millisecond */ ++ uint32 ps_mask; /**< reason(s) for disallowing ps */ ++} wlc_ps_debug_t; ++ ++typedef struct wl_pmalert_ps_allowed_hist { ++ uint16 type; /**< WL_PMALERT_PS_ALLOWED_HIST */ ++ uint16 len; /**< Up to 4K-1, top 4 bits are reserved */ ++ uint32 ps_allowed_start_idx; ++ /* Array of ps_debug, len of array is based on tlv len */ ++ wlc_ps_debug_t ps_debug[1]; ++} wl_pmalert_ps_allowed_hist_t; ++ ++/* Structures and constants used for "vndr_ie" IOVar interface */ ++#define VNDR_IE_CMD_LEN 4 /**< length of the set command string: ++ * "add", "del" (+ NUL) ++ */ ++ ++#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32)) ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 pktflag; /**< bitmask indicating which packet(s) contain this IE */ ++ vndr_ie_t vndr_ie_data; /**< vendor IE data */ ++} BWL_POST_PACKED_STRUCT vndr_ie_info_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ int32 iecount; /**< number of entries in the vndr_ie_list[] array */ ++ vndr_ie_info_t vndr_ie_list[1]; /**< variable size list of vndr_ie_info_t structs */ ++} BWL_POST_PACKED_STRUCT vndr_ie_buf_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ char cmd[VNDR_IE_CMD_LEN]; /**< vndr_ie IOVar set command : "add", "del" + NUL */ ++ vndr_ie_buf_t vndr_ie_buffer; /**< buffer containing Vendor IE list information */ ++} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t; ++#include ++ ++/** tag_ID/length/value_buffer tuple */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 id; ++ uint8 len; ++ uint8 data[1]; ++} BWL_POST_PACKED_STRUCT tlv_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 pktflag; /**< bitmask indicating which packet(s) contain this IE */ ++ tlv_t ie_data; /**< IE data */ ++} BWL_POST_PACKED_STRUCT ie_info_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ int32 iecount; /**< number of entries in the ie_list[] array */ ++ ie_info_t ie_list[1]; /**< variable size list of ie_info_t structs */ ++} BWL_POST_PACKED_STRUCT ie_buf_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ char cmd[VNDR_IE_CMD_LEN]; /**< ie IOVar set command : "add" + NUL */ ++ ie_buf_t ie_buffer; /**< buffer containing IE list information */ ++} BWL_POST_PACKED_STRUCT ie_setbuf_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 pktflag; /**< bitmask indicating which packet(s) contain this IE */ ++ uint8 id; /**< IE type */ ++} BWL_POST_PACKED_STRUCT ie_getbuf_t; ++#include ++ ++/* structures used to define format of wps ie data from probe requests */ ++/* passed up to applications via iovar "prbreq_wpsie" */ ++typedef struct sta_prbreq_wps_ie_hdr { ++ struct ether_addr staAddr; ++ uint16 ieLen; ++} sta_prbreq_wps_ie_hdr_t; ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data { ++ sta_prbreq_wps_ie_hdr_t hdr; ++ uint8 ieData[1]; ++} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list { ++ uint32 totLen; ++ uint8 ieDataList[1]; ++} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 flags; ++ chanspec_t chanspec; /**< txpwr report for this channel */ ++ chanspec_t local_chanspec; /**< channel on which we are associated */ ++ uint8 local_max; /**< local max according to the AP */ ++ uint8 local_constraint; /**< local constraint according to the AP */ ++ int8 antgain[2]; /**< Ant gain for each band - from SROM */ ++ uint8 rf_cores; /**< count of RF Cores being reported */ ++ uint8 est_Pout[4]; /**< Latest tx power out estimate per RF chain */ ++ uint8 est_Pout_act[4]; /**< Latest tx power out estimate per RF chain w/o adjustment */ ++ uint8 est_Pout_cck; /**< Latest CCK tx power out estimate */ ++ uint8 tx_power_max[4]; /**< Maximum target power among all rates */ ++ uint32 tx_power_max_rate_ind[4]; /**< Index of the rate with the max target power */ ++ int8 sar; /**< SAR limit for display by wl executable */ ++ int8 channel_bandwidth; /**< 20, 40 or 80 MHz bandwidth? */ ++ uint8 version; /**< Version of the data format wlu <--> driver */ ++ uint8 display_core; /**< Displayed curpower core */ ++ int8 target_offsets[4]; /**< Target power offsets for current rate per core */ ++ uint32 last_tx_ratespec; /**< Ratespec for last transmition */ ++ uint32 user_target; /**< user limit */ ++ uint32 ppr_len; /**< length of each ppr serialization buffer */ ++ int8 SARLIMIT[MAX_STREAMS_SUPPORTED]; ++ uint8 pprdata[1]; /**< ppr serialization buffer */ ++} BWL_POST_PACKED_STRUCT tx_pwr_rpt_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ struct ipv4_addr ipv4_addr; ++ struct ether_addr nexthop; ++} BWL_POST_PACKED_STRUCT ibss_route_entry_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint32 num_entry; ++ ibss_route_entry_t route_entry[1]; ++} BWL_POST_PACKED_STRUCT ibss_route_tbl_t; ++#include ++ ++#define MAX_IBSS_ROUTE_TBL_ENTRY 64 ++ ++#define TXPWR_TARGET_VERSION 0 ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ int32 version; /**< version number */ ++ chanspec_t chanspec; /**< txpwr report for this channel */ ++ int8 txpwr[WL_STA_ANT_MAX]; /**< Max tx target power, in qdb */ ++ uint8 rf_cores; /**< count of RF Cores being reported */ ++} BWL_POST_PACKED_STRUCT txpwr_target_max_t; ++#include ++ ++#define BSS_PEER_INFO_PARAM_CUR_VER 0 ++/** Input structure for IOV_BSS_PEER_INFO */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint16 version; ++ struct ether_addr ea; /**< peer MAC address */ ++} BWL_POST_PACKED_STRUCT bss_peer_info_param_t; ++#include ++ ++#define BSS_PEER_INFO_CUR_VER 0 ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint16 version; ++ struct ether_addr ea; ++ int32 rssi; ++ uint32 tx_rate; /**< current tx rate */ ++ uint32 rx_rate; /**< current rx rate */ ++ wl_rateset_t rateset; /**< rateset in use */ ++ uint32 age; /**< age in seconds */ ++} BWL_POST_PACKED_STRUCT bss_peer_info_t; ++#include ++ ++#define BSS_PEER_LIST_INFO_CUR_VER 0 ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint16 version; ++ uint16 bss_peer_info_len; /**< length of bss_peer_info_t */ ++ uint32 count; /**< number of peer info */ ++ bss_peer_info_t peer_info[1]; /**< peer info */ ++} BWL_POST_PACKED_STRUCT bss_peer_list_info_t; ++#include ++ ++#define BSS_PEER_LIST_INFO_FIXED_LEN OFFSETOF(bss_peer_list_info_t, peer_info) ++ ++#define AIBSS_BCN_FORCE_CONFIG_VER_0 0 ++ ++/** structure used to configure AIBSS beacon force xmit */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint16 version; ++ uint16 len; ++ uint32 initial_min_bcn_dur; /**< dur in ms to check a bcn in bcn_flood period */ ++ uint32 min_bcn_dur; /**< dur in ms to check a bcn after bcn_flood period */ ++ uint32 bcn_flood_dur; /**< Initial bcn xmit period in ms */ ++} BWL_POST_PACKED_STRUCT aibss_bcn_force_config_t; ++#include ++ ++#define AIBSS_TXFAIL_CONFIG_VER_0 0 ++#define AIBSS_TXFAIL_CONFIG_VER_1 1 ++#define AIBSS_TXFAIL_CONFIG_CUR_VER AIBSS_TXFAIL_CONFIG_VER_1 ++ ++/** structure used to configure aibss tx fail event */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint16 version; ++ uint16 len; ++ uint32 bcn_timeout; /**< dur in seconds to receive 1 bcn */ ++ uint32 max_tx_retry; /**< no of consecutive no acks to send txfail event */ ++ uint32 max_atim_failure; /**< no of consecutive atim failure */ ++} BWL_POST_PACKED_STRUCT aibss_txfail_config_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_aibss_if { ++ uint16 version; ++ uint16 len; ++ uint32 flags; ++ struct ether_addr addr; ++ chanspec_t chspec; ++} BWL_POST_PACKED_STRUCT wl_aibss_if_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wlc_ipfo_route_entry { ++ struct ipv4_addr ip_addr; ++ struct ether_addr nexthop; ++} BWL_POST_PACKED_STRUCT wlc_ipfo_route_entry_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wlc_ipfo_route_tbl { ++ uint32 num_entry; ++ wlc_ipfo_route_entry_t route_entry[1]; ++} BWL_POST_PACKED_STRUCT wlc_ipfo_route_tbl_t; ++#include ++ ++/* Version of wlc_btc_stats_t structure. ++ * Increment whenever a change is made to wlc_btc_stats_t ++ */ ++#define BTCX_STATS_VER 2 ++ ++typedef struct wlc_btc_stats { ++ uint16 version; /* version number of struct */ ++ uint16 valid; /* Size of this struct */ ++ uint32 stats_update_timestamp; /* tStamp when data is updated. */ ++ uint32 btc_status; /* Hybrid/TDM indicator: Bit2:Hybrid, Bit1:TDM,Bit0:CoexEnabled */ ++ uint32 bt_req_type_map; /* BT Antenna Req types since last stats sample */ ++ uint32 bt_req_cnt; /* #BT antenna requests since last stats sampl */ ++ uint32 bt_gnt_cnt; /* #BT antenna grants since last stats sample */ ++ uint32 bt_gnt_dur; /* usec BT owns antenna since last stats sample */ ++ uint16 bt_abort_cnt; /* #Times WL was preempted due to BT since WL up */ ++ uint16 bt_rxf1ovfl_cnt; /* #Time PSNULL retry count exceeded since WL up */ ++ uint16 bt_latency_cnt; /* #Time ucode high latency detected since WL up */ ++ uint16 rsvd; /* pad to align struct to 32bit bndry */ ++} wlc_btc_stats_t; ++ ++#define WL_IPFO_ROUTE_TBL_FIXED_LEN 4 ++#define WL_MAX_IPFO_ROUTE_TBL_ENTRY 64 ++ ++ /* Global ASSERT Logging */ ++#define ASSERTLOG_CUR_VER 0x0100 ++#define MAX_ASSRTSTR_LEN 64 ++ ++ typedef struct assert_record { ++ uint32 time; ++ uint8 seq_num; ++ int8 str[MAX_ASSRTSTR_LEN]; ++ } assert_record_t; ++ ++ typedef struct assertlog_results { ++ uint16 version; ++ uint16 record_len; ++ uint32 num; ++ assert_record_t logs[1]; ++ } assertlog_results_t; ++ ++#define LOGRRC_FIX_LEN 8 ++#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type)) ++#ifdef BCMWAPI_WAI ++/* BCMWAPI_WAI */ ++#define IV_LEN 16 ++ struct wapi_sta_msg_t ++ { ++ uint16 msg_type; ++ uint16 datalen; ++ uint8 vap_mac[6]; ++ uint8 reserve_data1[2]; ++ uint8 sta_mac[6]; ++ uint8 reserve_data2[2]; ++ uint8 gsn[IV_LEN]; ++ uint8 wie[256]; ++ }; ++#endif /* BCMWAPI_WAI */ ++ /* chanim acs record */ ++ typedef struct { ++ uint8 valid; ++ uint8 trigger; ++ chanspec_t selected_chspc; ++ int8 bgnoise; ++ uint32 glitch_cnt; ++ uint8 ccastats; ++ uint8 chan_idle; ++ uint32 timestamp; ++ } chanim_acs_record_t; ++ ++ typedef struct { ++ chanim_acs_record_t acs_record[CHANIM_ACS_RECORD]; ++ uint8 count; ++ uint32 timestamp; ++ } wl_acs_record_t; ++ ++#define WL_CHANIM_STATS_V2 2 ++#define CCASTATS_V2_MAX 9 ++typedef struct chanim_stats_v2 { ++ uint32 glitchcnt; /**< normalized as per second count */ ++ uint32 badplcp; /**< normalized as per second count */ ++ uint8 ccastats[CCASTATS_V2_MAX]; /**< normalized as 0-255 */ ++ int8 bgnoise; /**< background noise level (in dBm) */ ++ chanspec_t chanspec; /**< ctrl chanspec of the interface */ ++ uint32 timestamp; /**< time stamp at which the stats are collected */ ++ uint32 bphy_glitchcnt; /**< normalized as per second count */ ++ uint32 bphy_badplcp; /**< normalized as per second count */ ++ uint8 chan_idle; /**< normalized as 0~255 */ ++ uint8 PAD[3]; ++} chanim_stats_v2_t; ++ ++typedef struct chanim_stats { ++ uint32 glitchcnt; /**< normalized as per second count */ ++ uint32 badplcp; /**< normalized as per second count */ ++ uint8 ccastats[CCASTATS_MAX]; /**< normalized as 0-255 */ ++ int8 bgnoise; /**< background noise level (in dBm) */ ++ uint8 pad_1[11 - CCASTATS_MAX]; ++ chanspec_t chanspec; /**< ctrl chanspec of the interface */ ++ uint8 pad_2[2]; ++ uint32 timestamp; /**< time stamp at which the stats are collected */ ++ uint32 bphy_glitchcnt; /**< normalized as per second count */ ++ uint32 bphy_badplcp; /**< normalized as per second count */ ++ uint8 chan_idle; /**< normalized as 0~255 */ ++ uint8 PAD[3]; ++} chanim_stats_t; ++ ++#define WL_CHANIM_STATS_VERSION 3 ++typedef struct { ++ uint32 buflen; ++ uint32 version; ++ uint32 count; ++ chanim_stats_t stats[1]; ++} wl_chanim_stats_t; ++ ++#define WL_CHANIM_STATS_FIXED_LEN OFFSETOF(wl_chanim_stats_t, stats) ++ ++/** Noise measurement metrics. */ ++#define NOISE_MEASURE_KNOISE 0x1 ++ ++/** scb probe parameter */ ++typedef struct { ++ uint32 scb_timeout; ++ uint32 scb_activity_time; ++ uint32 scb_max_probe; ++} wl_scb_probe_t; ++ ++/* structure/defines for selective mgmt frame (smf) stats support */ ++ ++#define SMFS_VERSION 1 ++/** selected mgmt frame (smf) stats element */ ++typedef struct wl_smfs_elem { ++ uint32 count; ++ uint16 code; /**< SC or RC code */ ++ uint8 PAD[2]; ++} wl_smfs_elem_t; ++ ++typedef struct wl_smf_stats { ++ uint32 version; ++ uint16 length; /**< reserved for future usage */ ++ uint8 type; ++ uint8 codetype; ++ uint32 ignored_cnt; ++ uint32 malformed_cnt; ++ uint32 count_total; /**< count included the interested group */ ++ wl_smfs_elem_t elem[1]; ++} wl_smf_stats_t; ++ ++#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem); ++ ++enum { ++ SMFS_CODETYPE_SC, ++ SMFS_CODETYPE_RC ++}; ++ ++typedef enum smfs_type { ++ SMFS_TYPE_AUTH, ++ SMFS_TYPE_ASSOC, ++ SMFS_TYPE_REASSOC, ++ SMFS_TYPE_DISASSOC_TX, ++ SMFS_TYPE_DISASSOC_RX, ++ SMFS_TYPE_DEAUTH_TX, ++ SMFS_TYPE_DEAUTH_RX, ++ SMFS_TYPE_MAX ++} smfs_type_t; ++ ++/* #ifdef PHYMON */ ++ ++#define PHYMON_VERSION 1 ++ ++typedef struct wl_phycal_core_state { ++ /* Tx IQ/LO calibration coeffs */ ++ int16 tx_iqlocal_a; ++ int16 tx_iqlocal_b; ++ int8 tx_iqlocal_ci; ++ int8 tx_iqlocal_cq; ++ int8 tx_iqlocal_di; ++ int8 tx_iqlocal_dq; ++ int8 tx_iqlocal_ei; ++ int8 tx_iqlocal_eq; ++ int8 tx_iqlocal_fi; ++ int8 tx_iqlocal_fq; ++ ++ /** Rx IQ calibration coeffs */ ++ int16 rx_iqcal_a; ++ int16 rx_iqcal_b; ++ ++ uint8 tx_iqlocal_pwridx; /**< Tx Power Index for Tx IQ/LO calibration */ ++ uint8 PAD[3]; ++ uint32 papd_epsilon_table[64]; /**< PAPD epsilon table */ ++ int16 papd_epsilon_offset; /**< PAPD epsilon offset */ ++ uint8 curr_tx_pwrindex; /**< Tx power index */ ++ int8 idle_tssi; /**< Idle TSSI */ ++ int8 est_tx_pwr; /**< Estimated Tx Power (dB) */ ++ int8 est_rx_pwr; /**< Estimated Rx Power (dB) from RSSI */ ++ uint16 rx_gaininfo; /**< Rx gain applied on last Rx pkt */ ++ uint16 init_gaincode; /**< initgain required for ACI */ ++ int8 estirr_tx; ++ int8 estirr_rx; ++} wl_phycal_core_state_t; ++ ++typedef struct wl_phycal_state { ++ int32 version; ++ int8 num_phy_cores; /**< number of cores */ ++ int8 curr_temperature; /**< on-chip temperature sensor reading */ ++ chanspec_t chspec; /**< channspec for this state */ ++ uint8 aci_state; /**< ACI state: ON/OFF */ ++ uint8 PAD; ++ uint16 crsminpower; /**< crsminpower required for ACI */ ++ uint16 crsminpowerl; /**< crsminpowerl required for ACI */ ++ uint16 crsminpoweru; /**< crsminpoweru required for ACI */ ++ wl_phycal_core_state_t phycal_core[1]; ++} wl_phycal_state_t; ++ ++#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) ++/* endif PHYMON */ ++ ++/** discovery state */ ++typedef struct wl_p2p_disc_st { ++ uint8 state; /**< see state */ ++ uint8 PAD; ++ chanspec_t chspec; /**< valid in listen state */ ++ uint16 dwell; /**< valid in listen state, in ms */ ++} wl_p2p_disc_st_t; ++ ++/** scan request */ ++typedef struct wl_p2p_scan { ++ uint8 type; /**< 'S' for WLC_SCAN, 'E' for "escan" */ ++ uint8 reserved[3]; ++ /* scan or escan parms... */ ++} wl_p2p_scan_t; ++ ++/** i/f request */ ++typedef struct wl_p2p_if { ++ struct ether_addr addr; ++ uint8 type; /**< see i/f type */ ++ uint8 PAD; ++ chanspec_t chspec; /**< for p2p_ifadd GO */ ++} wl_p2p_if_t; ++ ++/** i/f query */ ++typedef struct wl_p2p_ifq { ++ uint32 bsscfgidx; ++ char ifname[BCM_MSG_IFNAME_MAX]; ++} wl_p2p_ifq_t; ++ ++/** OppPS & CTWindow */ ++typedef struct wl_p2p_ops { ++ uint8 ops; /**< 0: disable 1: enable */ ++ uint8 ctw; /**< >= 10 */ ++} wl_p2p_ops_t; ++ ++/** absence and presence request */ ++typedef struct wl_p2p_sched_desc { ++ uint32 start; ++ uint32 interval; ++ uint32 duration; ++ uint32 count; /**< see count */ ++} wl_p2p_sched_desc_t; ++ ++typedef struct wl_p2p_sched { ++ uint8 type; /**< see schedule type */ ++ uint8 action; /**< see schedule action */ ++ uint8 option; /**< see schedule option */ ++ uint8 PAD; ++ wl_p2p_sched_desc_t desc[1]; ++} wl_p2p_sched_t; ++ ++typedef struct wl_p2p_wfds_hash { ++ uint32 advt_id; ++ uint16 nw_cfg_method; ++ uint8 wfds_hash[6]; ++ uint8 name_len; ++ uint8 service_name[MAX_WFDS_SVC_NAME_LEN]; ++ uint8 PAD[3]; ++} wl_p2p_wfds_hash_t; ++ ++typedef struct wl_bcmdcs_data { ++ uint32 reason; ++ chanspec_t chspec; ++ uint8 PAD[2]; ++} wl_bcmdcs_data_t; ++/* ifdef EXT_STA */ ++/** ++ * Format of IHV data passed to OID_DOT11_NIC_SPECIFIC_EXTENSION. ++ */ ++typedef struct _IHV_NIC_SPECIFIC_EXTENSION { ++ uint8 oui[4]; /**< vendor specific OUI value */ ++ uint32 event; /**< event code */ ++ uint8 ihvData[1]; /**< ihv data */ ++} IHV_NIC_SPECIFIC_EXTENSION, *PIHV_NIC_SPECIFIC_EXTENSION; ++#define IHV_NIC_SPECIFIC_EXTENTION_HEADER OFFSETOF(IHV_NIC_SPECIFIC_EXTENSION, ihvData[0]) ++/* EXT_STA */ ++/** NAT configuration */ ++typedef struct { ++ uint32 ipaddr; /**< interface ip address */ ++ uint32 ipaddr_mask; /**< interface ip address mask */ ++ uint32 ipaddr_gateway; /**< gateway ip address */ ++ uint8 mac_gateway[6]; /**< gateway mac address */ ++ uint8 PAD[2]; ++ uint32 ipaddr_dns; /**< DNS server ip address, valid only for public if */ ++ uint8 mac_dns[6]; /**< DNS server mac address, valid only for public if */ ++ uint8 GUID[38]; /**< interface GUID */ ++} nat_if_info_t; ++ ++typedef struct { ++ uint32 op; /**< operation code */ ++ uint8 pub_if; /**< set for public if, clear for private if */ ++ uint8 PAD[3]; ++ nat_if_info_t if_info; /**< interface info */ ++} nat_cfg_t; ++ ++typedef struct { ++ int32 state; /**< NAT state returned */ ++} nat_state_t; ++ ++typedef struct flush_txfifo { ++ uint32 txfifobmp; ++ uint32 hwtxfifoflush; ++ struct ether_addr ea; ++ uint8 PAD[2]; ++} flush_txfifo_t; ++ ++enum { ++ SPATIAL_MODE_2G_IDX = 0, ++ SPATIAL_MODE_5G_LOW_IDX, ++ SPATIAL_MODE_5G_MID_IDX, ++ SPATIAL_MODE_5G_HIGH_IDX, ++ SPATIAL_MODE_5G_UPPER_IDX, ++ SPATIAL_MODE_MAX_IDX ++}; ++ ++#define WLC_TXCORE_MAX 4 /**< max number of txcore supports */ ++#define WLC_TXCORE_MAX_OLD 2 /**< backward compatibilty for TXCAL */ ++#define WLC_SUBBAND_MAX 4 /**< max number of sub-band supports */ ++typedef struct { ++ uint8 band2g[WLC_TXCORE_MAX]; ++ uint8 band5g[WLC_SUBBAND_MAX][WLC_TXCORE_MAX]; ++} sar_limit_t; ++ ++#define MAX_NUM_TXCAL_MEAS 128 ++#define MAX_NUM_PWR_STEP 40 ++#define TXCAL_IOVAR_VERSION 0x1 ++typedef struct wl_txcal_meas_percore { ++ uint16 tssi[MAX_NUM_TXCAL_MEAS]; ++ int16 pwr[MAX_NUM_TXCAL_MEAS]; ++} wl_txcal_meas_percore_t; ++ ++typedef struct wl_txcal_meas_ncore { ++ uint16 version; ++ uint8 valid_cnt; ++ uint8 num_core; ++ wl_txcal_meas_percore_t txcal_percore[1]; ++} wl_txcal_meas_ncore_t; ++ ++typedef struct wl_txcal_power_tssi_percore { ++ int16 tempsense; ++ int16 pwr_start; ++ uint8 pwr_start_idx; ++ uint8 num_entries; ++ uint16 pad; ++ uint8 tssi[MAX_NUM_PWR_STEP]; ++} wl_txcal_power_tssi_percore_t; ++ ++typedef struct wl_txcal_power_tssi_ncore { ++ uint16 version; ++ uint8 set_core; ++ uint8 channel; ++ uint8 num_core; ++ uint8 gen_tbl; ++ uint16 pad; ++ wl_txcal_power_tssi_percore_t tssi_percore[1]; ++} wl_txcal_power_tssi_ncore_t; ++ ++typedef struct wl_txcal_meas { ++ uint16 tssi[WLC_TXCORE_MAX][MAX_NUM_TXCAL_MEAS]; ++ int16 pwr[WLC_TXCORE_MAX][MAX_NUM_TXCAL_MEAS]; ++ uint8 valid_cnt; ++ uint8 PAD; ++} wl_txcal_meas_t; ++ ++typedef struct wl_txcal_meas_old { ++ uint16 tssi[WLC_TXCORE_MAX_OLD][MAX_NUM_TXCAL_MEAS]; ++ int16 pwr[WLC_TXCORE_MAX_OLD][MAX_NUM_TXCAL_MEAS]; ++ uint8 valid_cnt; ++ uint8 PAD; ++} wl_txcal_meas_old_t; ++ ++typedef struct wl_txcal_power_tssi { ++ uint8 set_core; ++ uint8 channel; ++ int16 tempsense[WLC_TXCORE_MAX]; ++ int16 pwr_start[WLC_TXCORE_MAX]; ++ uint8 pwr_start_idx[WLC_TXCORE_MAX]; ++ uint8 num_entries[WLC_TXCORE_MAX]; ++ uint8 tssi[WLC_TXCORE_MAX][MAX_NUM_PWR_STEP]; ++ uint8 gen_tbl; ++ uint8 PAD; ++} wl_txcal_power_tssi_t; ++ ++typedef struct wl_txcal_power_tssi_old { ++ uint8 set_core; ++ uint8 channel; ++ int16 tempsense[WLC_TXCORE_MAX_OLD]; ++ int16 pwr_start[WLC_TXCORE_MAX_OLD]; ++ uint8 pwr_start_idx[WLC_TXCORE_MAX_OLD]; ++ uint8 num_entries[WLC_TXCORE_MAX_OLD]; ++ uint8 tssi[WLC_TXCORE_MAX_OLD][MAX_NUM_PWR_STEP]; ++ uint8 gen_tbl; ++ uint8 PAD; ++} wl_txcal_power_tssi_old_t; ++ ++typedef struct wl_olpc_pwr { ++ uint16 version; ++ uint8 core; ++ uint8 channel; ++ int16 tempsense; ++ uint8 olpc_idx; ++ uint8 pad; ++} wl_olpc_pwr_t; ++ ++/** IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */ ++typedef struct wl_mempool_stats { ++ int32 num; /**< Number of memory pools */ ++ bcm_mp_stats_t s[1]; /**< Variable array of memory pool stats. */ ++} wl_mempool_stats_t; ++ ++typedef struct { ++ uint32 ipaddr; ++ uint32 ipaddr_netmask; ++ uint32 ipaddr_gateway; ++} nwoe_ifconfig_t; ++ ++/** Traffic management priority classes */ ++typedef enum trf_mgmt_priority_class { ++ trf_mgmt_priority_low = 0, /**< Maps to 802.1p BK */ ++ trf_mgmt_priority_medium = 1, /**< Maps to 802.1p BE */ ++ trf_mgmt_priority_high = 2, /**< Maps to 802.1p VI */ ++ trf_mgmt_priority_nochange = 3, /**< do not update the priority */ ++ trf_mgmt_priority_invalid = (trf_mgmt_priority_nochange + 1) ++} trf_mgmt_priority_class_t; ++ ++/** Traffic management configuration parameters */ ++typedef struct trf_mgmt_config { ++ uint32 trf_mgmt_enabled; /**< 0 - disabled, 1 - enabled */ ++ uint32 flags; /**< See TRF_MGMT_FLAG_xxx defines */ ++ uint32 host_ip_addr; /**< My IP address to determine subnet */ ++ uint32 host_subnet_mask; /**< My subnet mask */ ++ uint32 downlink_bandwidth; /**< In units of kbps */ ++ uint32 uplink_bandwidth; /**< In units of kbps */ ++ uint32 min_tx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /**< Minimum guaranteed tx bandwidth */ ++ uint32 min_rx_bandwidth[TRF_MGMT_MAX_PRIORITIES]; /**< Minimum guaranteed rx bandwidth */ ++} trf_mgmt_config_t; ++ ++/** Traffic management filter */ ++typedef struct trf_mgmt_filter { ++ struct ether_addr dst_ether_addr; /**< His L2 address */ ++ uint8 PAD[2]; ++ uint32 dst_ip_addr; /**< His IP address */ ++ uint16 dst_port; /**< His L4 port */ ++ uint16 src_port; /**< My L4 port */ ++ uint16 prot; /**< L4 protocol (only TCP or UDP) */ ++ uint16 flags; /**< TBD. For now, this must be zero. */ ++ trf_mgmt_priority_class_t priority; /**< Priority for filtered packets */ ++ uint32 dscp; /**< DSCP */ ++} trf_mgmt_filter_t; ++ ++/** Traffic management filter list (variable length) */ ++typedef struct trf_mgmt_filter_list { ++ uint32 num_filters; ++ trf_mgmt_filter_t filter[1]; ++} trf_mgmt_filter_list_t; ++ ++/** Traffic management global info used for all queues */ ++typedef struct trf_mgmt_global_info { ++ uint32 maximum_bytes_per_second; ++ uint32 maximum_bytes_per_sampling_period; ++ uint32 total_bytes_consumed_per_second; ++ uint32 total_bytes_consumed_per_sampling_period; ++ uint32 total_unused_bytes_per_sampling_period; ++} trf_mgmt_global_info_t; ++ ++/** Traffic management shaping info per priority queue */ ++typedef struct trf_mgmt_shaping_info { ++ uint32 gauranteed_bandwidth_percentage; ++ uint32 guaranteed_bytes_per_second; ++ uint32 guaranteed_bytes_per_sampling_period; ++ uint32 num_bytes_produced_per_second; ++ uint32 num_bytes_consumed_per_second; ++ uint32 num_queued_packets; /**< Number of packets in queue */ ++ uint32 num_queued_bytes; /**< Number of bytes in queue */ ++} trf_mgmt_shaping_info_t; ++ ++/** Traffic management shaping info array */ ++typedef struct trf_mgmt_shaping_info_array { ++ trf_mgmt_global_info_t tx_global_shaping_info; ++ trf_mgmt_shaping_info_t tx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; ++ trf_mgmt_global_info_t rx_global_shaping_info; ++ trf_mgmt_shaping_info_t rx_queue_shaping_info[TRF_MGMT_MAX_PRIORITIES]; ++} trf_mgmt_shaping_info_array_t; ++ ++ ++/** Traffic management statistical counters */ ++typedef struct trf_mgmt_stats { ++ uint32 num_processed_packets; /**< Number of packets processed */ ++ uint32 num_processed_bytes; /**< Number of bytes processed */ ++ uint32 num_discarded_packets; /**< Number of packets discarded from queue */ ++} trf_mgmt_stats_t; ++ ++/** Traffic management statistics array */ ++typedef struct trf_mgmt_stats_array { ++ trf_mgmt_stats_t tx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; ++ trf_mgmt_stats_t rx_queue_stats[TRF_MGMT_MAX_PRIORITIES]; ++} trf_mgmt_stats_array_t; ++ ++/* Both powersel_params and lpc_params are used by IOVAR lpc_params. ++ * The powersel_params is replaced by lpc_params in later WLC versions. ++ */ ++typedef struct powersel_params { ++ /* LPC Params exposed via IOVAR */ ++ int32 tp_ratio_thresh; /**< Throughput ratio threshold */ ++ uint8 rate_stab_thresh; /**< Thresh for rate stability based on nupd */ ++ uint8 pwr_stab_thresh; /**< Number of successes before power step down */ ++ uint8 pwr_sel_exp_time; /**< Time lapse for expiry of database */ ++ uint8 PAD; ++} powersel_params_t; ++ ++#define WL_LPC_PARAMS_VER_2 2 ++#define WL_LPC_PARAMS_CURRENT_VERSION WL_LPC_PARAMS_VER_2 ++ ++typedef struct lpc_params { ++ uint16 version; ++ uint16 length; ++ /* LPC Params exposed via IOVAR */ ++ uint8 rate_stab_thresh; /**< Thresh for rate stability based on nupd */ ++ uint8 pwr_stab_thresh; /**< Number of successes before power step down */ ++ uint8 lpc_exp_time; /**< Time lapse for expiry of database */ ++ uint8 pwrup_slow_step; /**< Step size for slow step up */ ++ uint8 pwrup_fast_step; /**< Step size for fast step up */ ++ uint8 pwrdn_slow_step; /**< Step size for slow step down */ ++} lpc_params_t; ++ ++/* tx pkt delay statistics */ ++#define SCB_RETRY_SHORT_DEF 7 /**< Default Short retry Limit */ ++#define WLPKTDLY_HIST_NBINS 16 /**< number of bins used in the Delay histogram */ ++ ++/** structure to store per-AC delay statistics */ ++typedef struct scb_delay_stats { ++ uint32 txmpdu_lost; /**< number of MPDUs lost */ ++ uint32 txmpdu_cnt[SCB_RETRY_SHORT_DEF]; /**< retry times histogram */ ++ uint32 delay_sum[SCB_RETRY_SHORT_DEF]; /**< cumulative packet latency */ ++ uint32 delay_min; /**< minimum packet latency observed */ ++ uint32 delay_max; /**< maximum packet latency observed */ ++ uint32 delay_avg; /**< packet latency average */ ++ uint32 delay_hist[WLPKTDLY_HIST_NBINS]; /**< delay histogram */ ++ uint32 delay_count; /**< minimum number of time period units before ++ consequent packet delay events can be generated ++ */ ++ uint32 prev_txmpdu_cnt; /**< Previous value of txmpdu_cnt[] during last iteration */ ++ uint32 prev_delay_sum; /**< Previous value of delay_sum[] during last iteration */ ++} scb_delay_stats_t; ++ ++/** structure for txdelay event */ ++typedef struct txdelay_event { ++ uint8 status; ++ uint8 PAD[3]; ++ int32 rssi; ++ chanim_stats_t chanim_stats; ++ scb_delay_stats_t delay_stats[AC_COUNT]; ++} txdelay_event_t; ++ ++/** structure for txdelay parameters */ ++typedef struct txdelay_params { ++ uint16 ratio; /**< Avg Txdelay Delta */ ++ uint8 cnt; /**< Sample cnt */ ++ uint8 period; /**< Sample period */ ++ uint8 tune; /**< Debug */ ++ uint8 PAD; ++} txdelay_params_t; ++#define MAX_TXDELAY_STATS_SCBS 6 ++#define TXDELAY_STATS_VERSION 1 ++ ++enum { ++ TXDELAY_STATS_PARTIAL_RESULT = 0, ++ TXDELAY_STATS_FULL_RESULT = 1 ++}; ++ ++typedef struct scb_total_delay_stats { ++ struct ether_addr ea; ++ uint8 pad[2]; ++ scb_delay_stats_t dlystats[AC_COUNT]; ++} scb_total_delay_stats_t; ++ ++typedef struct txdelay_stats { ++ uint32 version; ++ uint32 full_result; /* 0:Partial, 1:full */ ++ uint32 scb_cnt; /* in:requested, out:returned */ ++ scb_total_delay_stats_t scb_delay_stats[1]; ++} txdelay_stats_t; ++ ++#define WL_TXDELAY_STATS_FIXED_SIZE \ ++ (sizeof(txdelay_stats_t)+(MAX_TXDELAY_STATS_SCBS-1)*sizeof(scb_total_delay_stats_t)) ++enum { ++ WNM_SERVICE_DMS = 1, ++ WNM_SERVICE_FMS = 2, ++ WNM_SERVICE_TFS = 3 ++}; ++ ++/** Definitions for WNM/NPS TCLAS */ ++typedef struct wl_tclas { ++ uint8 user_priority; ++ uint8 fc_len; ++ dot11_tclas_fc_t fc; ++} wl_tclas_t; ++ ++#define WL_TCLAS_FIXED_SIZE OFFSETOF(wl_tclas_t, fc) ++ ++typedef struct wl_tclas_list { ++ uint32 num; ++ wl_tclas_t tclas[]; ++} wl_tclas_list_t; ++ ++/** Definitions for WNM/NPS Traffic Filter Service */ ++typedef struct wl_tfs_req { ++ uint8 tfs_id; ++ uint8 tfs_actcode; ++ uint8 tfs_subelem_id; ++ uint8 send; ++} wl_tfs_req_t; ++ ++typedef struct wl_tfs_filter { ++ uint8 status; /**< Status returned by the AP */ ++ uint8 tclas_proc; /**< TCLAS processing value (0:and, 1:or) */ ++ uint8 tclas_cnt; /**< count of all wl_tclas_t in tclas array */ ++ uint8 tclas[1]; /**< VLA of wl_tclas_t */ ++} wl_tfs_filter_t; ++#define WL_TFS_FILTER_FIXED_SIZE OFFSETOF(wl_tfs_filter_t, tclas) ++ ++typedef struct wl_tfs_fset { ++ struct ether_addr ea; /**< Address of AP/STA involved with this filter set */ ++ uint8 tfs_id; /**< TFS ID field chosen by STA host */ ++ uint8 status; /**< Internal status TFS_STATUS_xxx */ ++ uint8 actcode; /**< Action code DOT11_TFS_ACTCODE_xxx */ ++ uint8 token; /**< Token used in last request frame */ ++ uint8 notify; /**< Notify frame sent/received because of this set */ ++ uint8 filter_cnt; /**< count of all wl_tfs_filter_t in filter array */ ++ uint8 filter[1]; /**< VLA of wl_tfs_filter_t */ ++} wl_tfs_fset_t; ++#define WL_TFS_FSET_FIXED_SIZE OFFSETOF(wl_tfs_fset_t, filter) ++ ++enum { ++ TFS_STATUS_DISABLED = 0, /**< TFS filter set disabled by user */ ++ TFS_STATUS_DISABLING = 1, /**< Empty request just sent to AP */ ++ TFS_STATUS_VALIDATED = 2, /**< Filter set validated by AP (but maybe not enabled!) */ ++ TFS_STATUS_VALIDATING = 3, /**< Filter set just sent to AP */ ++ TFS_STATUS_NOT_ASSOC = 4, /**< STA not associated */ ++ TFS_STATUS_NOT_SUPPORT = 5, /**< TFS not supported by AP */ ++ TFS_STATUS_DENIED = 6, /**< Filter set refused by AP (=> all sets are disabled!) */ ++}; ++ ++typedef struct wl_tfs_status { ++ uint8 fset_cnt; /**< count of all wl_tfs_fset_t in fset array */ ++ wl_tfs_fset_t fset[1]; /**< VLA of wl_tfs_fset_t */ ++} wl_tfs_status_t; ++ ++typedef struct wl_tfs_set { ++ uint8 send; /**< Immediatly register registered sets on AP side */ ++ uint8 tfs_id; /**< ID of a specific set (existing or new), or nul for all */ ++ uint8 actcode; /**< Action code for this filter set */ ++ uint8 tclas_proc; /**< TCLAS processing operator for this filter set */ ++} wl_tfs_set_t; ++ ++typedef struct wl_tfs_term { ++ uint8 del; /**< Delete internal set once confirmation received */ ++ uint8 tfs_id; /**< ID of a specific set (existing), or nul for all */ ++} wl_tfs_term_t; ++ ++ ++#define DMS_DEP_PROXY_ARP (1 << 0) ++ ++/* Definitions for WNM/NPS Directed Multicast Service */ ++enum { ++ DMS_STATUS_DISABLED = 0, /**< DMS desc disabled by user */ ++ DMS_STATUS_ACCEPTED = 1, /**< Request accepted by AP */ ++ DMS_STATUS_NOT_ASSOC = 2, /**< STA not associated */ ++ DMS_STATUS_NOT_SUPPORT = 3, /**< DMS not supported by AP */ ++ DMS_STATUS_DENIED = 4, /**< Request denied by AP */ ++ DMS_STATUS_TERM = 5, /**< Request terminated by AP */ ++ DMS_STATUS_REMOVING = 6, /**< Remove request just sent */ ++ DMS_STATUS_ADDING = 7, /**< Add request just sent */ ++ DMS_STATUS_ERROR = 8, /**< Non compliant AP behvior */ ++ DMS_STATUS_IN_PROGRESS = 9, /**< Request just sent */ ++ DMS_STATUS_REQ_MISMATCH = 10 /**< Conditions for sending DMS req not met */ ++}; ++ ++typedef struct wl_dms_desc { ++ uint8 user_id; ++ uint8 status; ++ uint8 token; ++ uint8 dms_id; ++ uint8 tclas_proc; ++ uint8 mac_len; /**< length of all ether_addr in data array, 0 if STA */ ++ uint8 tclas_len; /**< length of all wl_tclas_t in data array */ ++ uint8 data[1]; /**< VLA of 'ether_addr' and 'wl_tclas_t' (in this order ) */ ++} wl_dms_desc_t; ++ ++#define WL_DMS_DESC_FIXED_SIZE OFFSETOF(wl_dms_desc_t, data) ++ ++typedef struct wl_dms_status { ++ uint32 cnt; ++ wl_dms_desc_t desc[1]; ++} wl_dms_status_t; ++ ++typedef struct wl_dms_set { ++ uint8 send; ++ uint8 user_id; ++ uint8 tclas_proc; ++} wl_dms_set_t; ++ ++typedef struct wl_dms_term { ++ uint8 del; ++ uint8 user_id; ++} wl_dms_term_t; ++ ++typedef struct wl_service_term { ++ uint8 service; ++ union { ++ wl_dms_term_t dms; ++ } u; ++} wl_service_term_t; ++ ++/** Definitions for WNM/NPS BSS Transistion */ ++typedef struct wl_bsstrans_req { ++ uint16 tbtt; /**< time of BSS to end of life, in unit of TBTT */ ++ uint16 dur; /**< time of BSS to keep off, in unit of minute */ ++ uint8 reqmode; /**< request mode of BSS transition request */ ++ uint8 unicast; /**< request by unicast or by broadcast */ ++} wl_bsstrans_req_t; ++ ++enum { ++ BSSTRANS_RESP_AUTO = 0, /**< Currently equivalent to ENABLE */ ++ BSSTRANS_RESP_DISABLE = 1, /**< Never answer BSS Trans Req frames */ ++ BSSTRANS_RESP_ENABLE = 2, /**< Always answer Req frames with preset data */ ++ BSSTRANS_RESP_WAIT = 3, /**< Send ind, wait and/or send preset data (NOT IMPL) */ ++ BSSTRANS_RESP_IMMEDIATE = 4 /**< After an ind, set data and send resp (NOT IMPL) */ ++}; ++ ++typedef struct wl_bsstrans_resp { ++ uint8 policy; ++ uint8 status; ++ uint8 delay; ++ struct ether_addr target; ++} wl_bsstrans_resp_t; ++ ++/* "wnm_bsstrans_policy" argument programs behavior after BSSTRANS Req reception. ++ * BSS-Transition feature is used by multiple programs such as NPS-PF, VE-PF, ++ * Band-steering, Hotspot 2.0 and customer requirements. Each PF and its test plan ++ * mandates different behavior on receiving BSS-transition request. To accomodate ++ * such divergent behaviors these policies have been created. ++ */ ++typedef enum { ++ WL_BSSTRANS_POLICY_ROAM_ALWAYS = 0, /**< Roam (or disassociate) in all cases */ ++ WL_BSSTRANS_POLICY_ROAM_IF_MODE = 1, /**< Roam only if requested by Request Mode field */ ++ WL_BSSTRANS_POLICY_ROAM_IF_PREF = 2, /**< Roam only if Preferred BSS provided */ ++ WL_BSSTRANS_POLICY_WAIT = 3, /**< Wait for deauth and send Accepted status */ ++ WL_BSSTRANS_POLICY_PRODUCT = 4, /**< Policy for real product use cases (Olympic) */ ++ WL_BSSTRANS_POLICY_PRODUCT_WBTEXT = 5, /**< Policy for real product use cases (SS) */ ++ WL_BSSTRANS_POLICY_MAX = 6 ++} wnm_bsstrans_policy_type_t; ++ ++/** Definitions for WNM/NPS TIM Broadcast */ ++typedef struct wl_timbc_offset { ++ int16 offset; /**< offset in us */ ++ uint16 fix_intv; /**< override interval sent from STA */ ++ uint16 rate_override; /**< use rate override to send high rate TIM broadcast frame */ ++ uint8 tsf_present; /**< show timestamp in TIM broadcast frame */ ++ uint8 PAD; ++} wl_timbc_offset_t; ++ ++typedef struct wl_timbc_set { ++ uint8 interval; /**< Interval in DTIM wished or required. */ ++ uint8 flags; /**< Bitfield described below */ ++ uint16 rate_min; /**< Minimum rate required for High/Low TIM frames. Optionnal */ ++ uint16 rate_max; /**< Maximum rate required for High/Low TIM frames. Optionnal */ ++} wl_timbc_set_t; ++ ++enum { ++ WL_TIMBC_SET_TSF_REQUIRED = 1, /**< Enable TIMBC only if TSF in TIM frames */ ++ WL_TIMBC_SET_NO_OVERRIDE = 2, /**< ... if AP does not override interval */ ++ WL_TIMBC_SET_PROXY_ARP = 4, /**< ... if AP support Proxy ARP */ ++ WL_TIMBC_SET_DMS_ACCEPTED = 8 /**< ... if all DMS desc have been accepted */ ++}; ++ ++typedef struct wl_timbc_status { ++ uint8 status_sta; /**< Status from internal state machine (check below) */ ++ uint8 status_ap; /**< From AP response frame (check 8.4.2.86 from 802.11) */ ++ uint8 interval; ++ uint8 pad; ++ int32 offset; ++ uint16 rate_high; ++ uint16 rate_low; ++} wl_timbc_status_t; ++ ++enum { ++ WL_TIMBC_STATUS_DISABLE = 0, /**< TIMBC disabled by user */ ++ WL_TIMBC_STATUS_REQ_MISMATCH = 1, /**< AP settings do no match user requirements */ ++ WL_TIMBC_STATUS_NOT_ASSOC = 2, /**< STA not associated */ ++ WL_TIMBC_STATUS_NOT_SUPPORT = 3, /**< TIMBC not supported by AP */ ++ WL_TIMBC_STATUS_DENIED = 4, /**< Req to disable TIMBC sent to AP */ ++ WL_TIMBC_STATUS_ENABLE = 5 /**< TIMBC enabled */ ++}; ++ ++/** Definitions for PM2 Dynamic Fast Return To Sleep */ ++typedef struct wl_pm2_sleep_ret_ext { ++ uint8 logic; /**< DFRTS logic: see WL_DFRTS_LOGIC_* below */ ++ uint8 PAD; ++ uint16 low_ms; /**< Low FRTS timeout */ ++ uint16 high_ms; /**< High FRTS timeout */ ++ uint16 rx_pkts_threshold; /**< switching threshold: # rx pkts */ ++ uint16 tx_pkts_threshold; /**< switching threshold: # tx pkts */ ++ uint16 txrx_pkts_threshold; /**< switching threshold: # (tx+rx) pkts */ ++ uint32 rx_bytes_threshold; /**< switching threshold: # rx bytes */ ++ uint32 tx_bytes_threshold; /**< switching threshold: # tx bytes */ ++ uint32 txrx_bytes_threshold; /**< switching threshold: # (tx+rx) bytes */ ++} wl_pm2_sleep_ret_ext_t; ++ ++#define WL_DFRTS_LOGIC_OFF 0 /**< Feature is disabled */ ++#define WL_DFRTS_LOGIC_OR 1 /**< OR all non-zero threshold conditions */ ++#define WL_DFRTS_LOGIC_AND 2 /**< AND all non-zero threshold conditions */ ++ ++/* Values for the passive_on_restricted_mode iovar. When set to non-zero, this iovar ++ * disables automatic conversions of a channel from passively scanned to ++ * actively scanned. These values only have an effect for country codes such ++ * as XZ where some 5 GHz channels are defined to be passively scanned. ++ */ ++#define WL_PASSACTCONV_DISABLE_NONE 0 /**< Enable permanent and temporary conversions */ ++#define WL_PASSACTCONV_DISABLE_ALL 1 /**< Disable permanent and temporary conversions */ ++#define WL_PASSACTCONV_DISABLE_PERM 2 /**< Disable only permanent conversions */ ++ ++/* Definitions for Reliable Multicast */ ++#define WL_RMC_CNT_VERSION 1 ++#define WL_RMC_TR_VERSION 1 ++#define WL_RMC_MAX_CLIENT 32 ++#define WL_RMC_FLAG_INBLACKLIST 1 ++#define WL_RMC_FLAG_ACTIVEACKER 2 ++#define WL_RMC_FLAG_RELMCAST 4 ++#define WL_RMC_MAX_TABLE_ENTRY 4 ++ ++#define WL_RMC_VER 1 ++#define WL_RMC_INDEX_ACK_ALL 255 ++#define WL_RMC_NUM_OF_MC_STREAMS 4 ++#define WL_RMC_MAX_TRS_PER_GROUP 1 ++#define WL_RMC_MAX_TRS_IN_ACKALL 1 ++#define WL_RMC_ACK_MCAST0 0x02 ++#define WL_RMC_ACK_MCAST_ALL 0x01 ++#define WL_RMC_ACTF_TIME_MIN 300 /**< time in ms */ ++#define WL_RMC_ACTF_TIME_MAX 20000 /**< time in ms */ ++#define WL_RMC_MAX_NUM_TRS 32 /**< maximun transmitters allowed */ ++#define WL_RMC_ARTMO_MIN 350 /**< time in ms */ ++#define WL_RMC_ARTMO_MAX 40000 /**< time in ms */ ++ ++/* RMC events in action frames */ ++enum rmc_opcodes { ++ RELMCAST_ENTRY_OP_DISABLE = 0, /**< Disable multi-cast group */ ++ RELMCAST_ENTRY_OP_DELETE = 1, /**< Delete multi-cast group */ ++ RELMCAST_ENTRY_OP_ENABLE = 2, /**< Enable multi-cast group */ ++ RELMCAST_ENTRY_OP_ACK_ALL = 3 /**< Enable ACK ALL bit in AMT */ ++}; ++ ++/* RMC operational modes */ ++enum rmc_modes { ++ WL_RMC_MODE_RECEIVER = 0, /**< Receiver mode by default */ ++ WL_RMC_MODE_TRANSMITTER = 1, /**< Transmitter mode using wl ackreq */ ++ WL_RMC_MODE_INITIATOR = 2 /**< Initiator mode using wl ackreq */ ++}; ++ ++/** Each RMC mcast client info */ ++typedef struct wl_relmcast_client { ++ uint8 flag; /**< status of client such as AR, R, or blacklisted */ ++ uint8 PAD; ++ int16 rssi; /**< rssi value of RMC client */ ++ struct ether_addr addr; /**< mac address of RMC client */ ++} wl_relmcast_client_t; ++ ++/** RMC Counters */ ++typedef struct wl_rmc_cnts { ++ uint16 version; /**< see definition of WL_CNT_T_VERSION */ ++ uint16 length; /**< length of entire structure */ ++ uint16 dupcnt; /**< counter for duplicate rmc MPDU */ ++ uint16 ackreq_err; /**< counter for wl ackreq error */ ++ uint16 af_tx_err; /**< error count for action frame transmit */ ++ uint16 null_tx_err; /**< error count for rmc null frame transmit */ ++ uint16 af_unicast_tx_err; /**< error count for rmc unicast frame transmit */ ++ uint16 mc_no_amt_slot; /**< No mcast AMT entry available */ ++ /* Unused. Keep for rom compatibility */ ++ uint16 mc_no_glb_slot; /**< No mcast entry available in global table */ ++ uint16 mc_not_mirrored; /**< mcast group is not mirrored */ ++ uint16 mc_existing_tr; /**< mcast group is already taken by transmitter */ ++ uint16 mc_exist_in_amt; /**< mcast group is already programmed in amt */ ++ /* Unused. Keep for rom compatibility */ ++ uint16 mc_not_exist_in_gbl; /**< mcast group is not in global table */ ++ uint16 mc_not_exist_in_amt; /**< mcast group is not in AMT table */ ++ uint16 mc_utilized; /**< mcast addressed is already taken */ ++ uint16 mc_taken_other_tr; /**< multi-cast addressed is already taken */ ++ uint32 rmc_rx_frames_mac; /**< no of mc frames received from mac */ ++ uint32 rmc_tx_frames_mac; /**< no of mc frames transmitted to mac */ ++ uint32 mc_null_ar_cnt; /**< no. of times NULL AR is received */ ++ uint32 mc_ar_role_selected; /**< no. of times took AR role */ ++ uint32 mc_ar_role_deleted; /**< no. of times AR role cancelled */ ++ uint32 mc_noacktimer_expired; /**< no. of times noack timer expired */ ++ uint16 mc_no_wl_clk; /**< no wl clk detected when trying to access amt */ ++ uint16 mc_tr_cnt_exceeded; /**< No of transmitters in the network exceeded */ ++} wl_rmc_cnts_t; ++ ++/** RMC Status */ ++typedef struct wl_relmcast_st { ++ uint8 ver; /**< version of RMC */ ++ uint8 num; /**< number of clients detected by transmitter */ ++ wl_relmcast_client_t clients[WL_RMC_MAX_CLIENT]; ++ uint16 err; /**< error status (used in infra) */ ++ uint16 actf_time; /**< action frame time period */ ++} wl_relmcast_status_t; ++ ++/** Entry for each STA/node */ ++typedef struct wl_rmc_entry { ++ /* operation on multi-cast entry such add, ++ * delete, ack-all ++ */ ++ int8 flag; ++ struct ether_addr addr; /**< multi-cast group mac address */ ++} wl_rmc_entry_t; ++ ++/** RMC table */ ++typedef struct wl_rmc_entry_table { ++ uint8 index; /**< index to a particular mac entry in table */ ++ uint8 opcode; /**< opcodes or operation on entry */ ++ wl_rmc_entry_t entry[WL_RMC_MAX_TABLE_ENTRY]; ++} wl_rmc_entry_table_t; ++ ++typedef struct wl_rmc_trans_elem { ++ struct ether_addr tr_mac; /**< transmitter mac */ ++ struct ether_addr ar_mac; /**< ar mac */ ++ uint16 artmo; /**< AR timeout */ ++ uint8 amt_idx; /**< amt table entry */ ++ uint8 PAD; ++ uint16 flag; /**< entry will be acked, not acked, programmed, full etc */ ++} wl_rmc_trans_elem_t; ++ ++/** RMC transmitters */ ++typedef struct wl_rmc_trans_in_network { ++ uint8 ver; /**< version of RMC */ ++ uint8 num_tr; /**< number of transmitters in the network */ ++ wl_rmc_trans_elem_t trs[WL_RMC_MAX_NUM_TRS]; ++} wl_rmc_trans_in_network_t; ++ ++/** To update vendor specific ie for RMC */ ++typedef struct wl_rmc_vsie { ++ uint8 oui[DOT11_OUI_LEN]; ++ uint8 PAD; ++ uint16 payload; /**< IE Data Payload */ ++} wl_rmc_vsie_t; ++ ++ ++/* structures & defines for proximity detection */ ++enum proxd_method { ++ PROXD_UNDEFINED_METHOD = 0, ++ PROXD_RSSI_METHOD = 1, ++ PROXD_TOF_METHOD = 2 ++}; ++ ++/* structures for proximity detection device role */ ++#define WL_PROXD_MODE_DISABLE 0 ++#define WL_PROXD_MODE_NEUTRAL 1 ++#define WL_PROXD_MODE_INITIATOR 2 ++#define WL_PROXD_MODE_TARGET 3 ++ ++#define WL_PROXD_ACTION_STOP 0 ++#define WL_PROXD_ACTION_START 1 ++ ++#define WL_PROXD_FLAG_TARGET_REPORT 0x1 ++#define WL_PROXD_FLAG_REPORT_FAILURE 0x2 ++#define WL_PROXD_FLAG_INITIATOR_REPORT 0x4 ++#define WL_PROXD_FLAG_NOCHANSWT 0x8 ++#define WL_PROXD_FLAG_NETRUAL 0x10 ++#define WL_PROXD_FLAG_INITIATOR_RPTRTT 0x20 ++#define WL_PROXD_FLAG_ONEWAY 0x40 ++#define WL_PROXD_FLAG_SEQ_EN 0x80 ++ ++#define WL_PROXD_SETFLAG_K 0x1 ++#define WL_PROXD_SETFLAG_N 0x2 ++#define WL_PROXD_SETFLAG_S 0x4 ++ ++#define WL_PROXD_SETFLAG_K 0x1 ++#define WL_PROXD_SETFLAG_N 0x2 ++#define WL_PROXD_SETFLAG_S 0x4 ++ ++#define WL_PROXD_RANDOM_WAKEUP 0x8000 ++#define WL_PROXD_MAXREPORT 8 ++ ++typedef struct wl_proxd_iovar { ++ uint16 method; /**< Proximity Detection method */ ++ uint16 mode; /**< Mode (neutral, initiator, target) */ ++} wl_proxd_iovar_t; ++ ++/* ++ * structures for proximity detection parameters ++ * consists of two parts, common and method specific params ++ * common params should be placed at the beginning ++ */ ++ ++typedef struct wl_proxd_params_common { ++ chanspec_t chanspec; /**< channel spec */ ++ int16 tx_power; /**< tx power of Proximity Detection(PD) frames (in dBm) */ ++ uint16 tx_rate; /**< tx rate of PD rames (in 500kbps units) */ ++ uint16 timeout; /**< timeout value */ ++ uint16 interval; /**< interval between neighbor finding attempts (in TU) */ ++ uint16 duration; /**< duration of neighbor finding attempts (in ms) */ ++} wl_proxd_params_common_t; ++ ++typedef struct wl_proxd_params_rssi_method { ++ chanspec_t chanspec; /**< chanspec for home channel */ ++ int16 tx_power; /**< tx power of Proximity Detection frames (in dBm) */ ++ uint16 tx_rate; /**< tx rate of PD frames, 500kbps units */ ++ uint16 timeout; /**< state machine wait timeout of the frames (in ms) */ ++ uint16 interval; /**< interval between neighbor finding attempts (in TU) */ ++ uint16 duration; /**< duration of neighbor finding attempts (in ms) */ ++ /* method specific ones go after this line */ ++ int16 rssi_thresh; /**< RSSI threshold (in dBm) */ ++ uint16 maxconvergtmo; /**< max wait converge timeout (in ms) */ ++} wl_proxd_params_rssi_method_t; ++ ++#define Q1_NS 25 /**< Q1 time units */ ++ ++#define TOF_BW_NUM 3 /**< number of bandwidth that the TOF can support */ ++#define TOF_BW_SEQ_NUM (TOF_BW_NUM+2) /* number of total index */ ++enum tof_bw_index { ++ TOF_BW_20MHZ_INDEX = 0, ++ TOF_BW_40MHZ_INDEX = 1, ++ TOF_BW_80MHZ_INDEX = 2, ++ TOF_BW_SEQTX_INDEX = 3, ++ TOF_BW_SEQRX_INDEX = 4 ++}; ++ ++#define BANDWIDTH_BASE 20 /**< base value of bandwidth */ ++#define TOF_BW_20MHZ (BANDWIDTH_BASE << TOF_BW_20MHZ_INDEX) ++#define TOF_BW_40MHZ (BANDWIDTH_BASE << TOF_BW_40MHZ_INDEX) ++#define TOF_BW_80MHZ (BANDWIDTH_BASE << TOF_BW_80MHZ_INDEX) ++#define TOF_BW_10MHZ 10 ++ ++#define NFFT_BASE 64 /**< base size of fft */ ++#define TOF_NFFT_20MHZ (NFFT_BASE << TOF_BW_20MHZ_INDEX) ++#define TOF_NFFT_40MHZ (NFFT_BASE << TOF_BW_40MHZ_INDEX) ++#define TOF_NFFT_80MHZ (NFFT_BASE << TOF_BW_80MHZ_INDEX) ++ ++typedef struct wl_proxd_params_tof_method { ++ chanspec_t chanspec; /**< chanspec for home channel */ ++ int16 tx_power; /**< tx power of Proximity Detection(PD) frames (in dBm) */ ++ uint16 tx_rate; /**< tx rate of PD rames (in 500kbps units) */ ++ uint16 timeout; /**< state machine wait timeout of the frames (in ms) */ ++ uint16 interval; /**< interval between neighbor finding attempts (in TU) */ ++ uint16 duration; /**< duration of neighbor finding attempts (in ms) */ ++ /* specific for the method go after this line */ ++ struct ether_addr tgt_mac; /**< target mac addr for TOF method */ ++ uint16 ftm_cnt; /**< number of the frames txed by initiator */ ++ uint16 retry_cnt; /**< number of retransmit attampts for ftm frames */ ++ int16 vht_rate; /**< ht or vht rate */ ++ /* add more params required for other methods can be added here */ ++} wl_proxd_params_tof_method_t; ++ ++typedef struct wl_proxd_seq_config ++{ ++ int16 N_tx_log2; ++ int16 N_rx_log2; ++ int16 N_tx_scale; ++ int16 N_rx_scale; ++ int16 w_len; ++ int16 w_offset; ++} wl_proxd_seq_config_t; ++ ++#define WL_PROXD_TUNE_VERSION_1 1 ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_tune { ++ uint32 version; ++ uint32 Ki; /**< h/w delay K factor for initiator */ ++ uint32 Kt; /**< h/w delay K factor for target */ ++ int16 vhtack; /**< enable/disable VHT ACK */ ++ int16 N_log2[TOF_BW_SEQ_NUM]; /**< simple threshold crossing */ ++ int16 w_offset[TOF_BW_NUM]; /**< offset of threshold crossing window(per BW) */ ++ int16 w_len[TOF_BW_NUM]; /**< length of threshold crossing window(per BW) */ ++ int32 maxDT; /**< max time difference of T4/T1 or T3/T2 */ ++ int32 minDT; /**< min time difference of T4/T1 or T3/T2 */ ++ uint8 totalfrmcnt; /**< total count of transfered measurement frames */ ++ uint16 rsv_media; /**< reserve media value for TOF */ ++ uint32 flags; /**< flags */ ++ uint8 core; /**< core to use for tx */ ++ uint8 setflags; /* set flags of K, N. S values */ ++ int16 N_scale[TOF_BW_SEQ_NUM]; /**< simple threshold crossing */ ++ uint8 sw_adj; /**< enable sw assisted timestamp adjustment */ ++ uint8 hw_adj; /**< enable hw assisted timestamp adjustment */ ++ uint8 seq_en; /**< enable ranging sequence */ ++ uint8 ftm_cnt[TOF_BW_SEQ_NUM]; /**< number of ftm frames based on bandwidth */ ++ int16 N_log2_2g; /**< simple threshold crossing for 2g channel */ ++ int16 N_scale_2g; /**< simple threshold crossing for 2g channel */ ++ wl_proxd_seq_config_t seq_5g20; ++ wl_proxd_seq_config_t seq_2g20; /* Thresh crossing params for 2G Sequence */ ++ uint16 bitflip_thresh; /* bitflip threshold */ ++ uint16 snr_thresh; /* SNR threshold */ ++ int8 recv_2g_thresh; /* 2g recieve sensitivity threshold */ ++ uint32 acs_gdv_thresh; ++ int8 acs_rssi_thresh; ++ uint8 smooth_win_en; ++ int32 acs_gdmm_thresh; ++ int8 acs_delta_rssi_thresh; ++ int32 emu_delay; ++} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_tune_t; ++#include ++ ++typedef struct wl_proxd_params_iovar { ++ uint16 method; /**< Proximity Detection method */ ++ union { ++ /* common params for pdsvc */ ++ wl_proxd_params_common_t cmn_params; /**< common parameters */ ++ /* method specific */ ++ wl_proxd_params_rssi_method_t rssi_params; /**< RSSI method parameters */ ++ wl_proxd_params_tof_method_t tof_params; /**< TOF method parameters */ ++ /* tune parameters */ ++ wl_proxd_params_tof_tune_t tof_tune; /**< TOF tune parameters */ ++ uint8 PAD[sizeof(wl_proxd_params_tof_tune_t)+1]; ++ } u; /**< Method specific optional parameters */ ++} wl_proxd_params_iovar_t; ++ ++#define PROXD_COLLECT_GET_STATUS 0 ++#define PROXD_COLLECT_SET_STATUS 1 ++#define PROXD_COLLECT_QUERY_HEADER 2 ++#define PROXD_COLLECT_QUERY_DATA 3 ++#define PROXD_COLLECT_QUERY_DEBUG 4 ++#define PROXD_COLLECT_REMOTE_REQUEST 5 ++#define PROXD_COLLECT_DONE 6 ++ ++typedef enum { ++ WL_PROXD_COLLECT_METHOD_TYPE_DISABLE = 0x0, ++ WL_PROXD_COLLECT_METHOD_TYPE_IOVAR = 0x1, ++ WL_PROXD_COLLECT_METHOD_TYPE_EVENT = 0x2, ++ WL_PROXD_COLLECT_METHOD_TYPE_EVENT_LOG = 0x4 ++} wl_proxd_collect_method_type_t; ++ ++typedef uint16 wl_proxd_collect_method_t; /* query status: method to send proxd collect */ ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_query { ++ uint32 method; /**< method */ ++ uint8 request; /**< Query request. */ ++ uint8 status; /**< bitmask 0 -- disable, 0x1 -- enable collection, */ ++ /* 0x2 -- Use generic event, 0x4 -- use event log */ ++ uint16 index; /**< The current frame index [0 to total_frames - 1]. */ ++ uint16 mode; /**< Initiator or Target */ ++ uint8 busy; /**< tof sm is busy */ ++ uint8 remote; /**< Remote collect data */ ++} BWL_POST_PACKED_STRUCT wl_proxd_collect_query_t; ++#include ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_header { ++ uint16 total_frames; /**< The total frames for this collect. */ ++ uint16 nfft; /**< nfft value */ ++ uint16 bandwidth; /**< bandwidth */ ++ uint16 channel; /**< channel number */ ++ uint32 chanspec; /**< channel spec */ ++ uint32 fpfactor; /**< avb timer value factor */ ++ uint16 fpfactor_shift; /**< avb timer value shift bits */ ++ int32 distance; /**< distance calculated by fw */ ++ uint32 meanrtt; /**< mean of RTTs */ ++ uint32 modertt; /**< mode of RTTs */ ++ uint32 medianrtt; /**< median of RTTs */ ++ uint32 sdrtt; /**< standard deviation of RTTs */ ++ uint32 clkdivisor; /**< clock divisor */ ++ uint16 chipnum; /**< chip type */ ++ uint8 chiprev; /**< chip revision */ ++ uint8 phyver; /**< phy version */ ++ struct ether_addr localMacAddr; /**< local mac address */ ++ struct ether_addr remoteMacAddr; /**< remote mac address */ ++ wl_proxd_params_tof_tune_t params; ++} BWL_POST_PACKED_STRUCT wl_proxd_collect_header_t; ++#include ++ ++ ++/* ifdef WL_NAN */ ++/* ********************** NAN wl interface struct types and defs ******************** */ ++/* ++ * Uses new common IOVAR batch processing mechanism ++ */ ++ ++/* ++ * NAN config control ++ * Bits 0 - 23 can be set by host ++ * Bits 24 - 31 - Internal use for firmware, host cannot set it ++ */ ++ ++/* ++ * Bit 0 : If set to 1, means event uses nan bsscfg, ++ * otherwise uses infra bsscfg. Default is using infra bsscfg ++ */ ++#define WL_NAN_CTRL_ROUTE_EVENT_VIA_NAN_BSSCFG 0x1 ++/* If set, discovery beacons are transmitted on 2G band */ ++#define WL_NAN_CTRL_DISC_BEACON_TX_2G 0x2 ++/* If set, sync beacons are transmitted on 2G band */ ++#define WL_NAN_CTRL_SYNC_BEACON_TX_2G 0x4 ++/* If set, discovery beacons are transmitted on 5G band */ ++#define WL_NAN_CTRL_DISC_BEACON_TX_5G 0x8 ++/* If set, sync beacons are transmitted on 5G band */ ++#define WL_NAN_CTRL_SYNC_BEACON_TX_5G 0x10 ++/* If set, auto datapath responses will be sent by FW */ ++#define WL_NAN_CTRL_AUTO_DPRESP 0x20 ++/* If set, auto datapath confirms will be sent by FW */ ++#define WL_NAN_CTRL_AUTO_DPCONF 0x40 ++ ++/* Value when all host-configurable bits set */ ++#define WL_NAN_CTRL_MAX_MASK 0xFFFFFF ++#define WL_NAN_CFG_CTRL_FW_BITS 8 ++ ++/* Bit 31: ++ * If set - indicates that NAN initialization is successful ++ * NOTE: This is a ready-only bit. All sets to this are masked off ++ */ ++#define WL_NAN_PROTO_INIT_DONE 0x80000000 ++#define WL_NAN_GET_PROTO_INIT_STATUS(x) \ ++ (((x) >> 31) & 1) ++#define WL_NAN_CLEAR_PROTO_INIT_STATUS(x) \ ++ ((x) &= ~WL_NAN_PROTO_INIT_DONE) ++#define WL_NAN_SET_PROTO_INIT_STATUS(x) \ ++ ((x) |= (1 << 31)) ++ ++#define WL_NAN_IOCTL_VERSION 0x2 ++/* < some sufficient ioc buff size for our module */ ++#define WL_NAN_IOC_BUFSZ 256 ++/* some sufficient ioc buff size for dump commands */ ++#define WL_NAN_IOC_BUFSZ_EXT 1024 ++#define WL_NAN_MAX_SIDS_IN_BEACONS 127 /* Max allowed SIDs */ ++#define WL_NAN_MASTER_RANK_LEN 8 ++#define WL_NAN_RANGE_LIMITED 0x0040 /* Publish/Subscribe flags */ ++ ++/** The service hash (service id) is exactly this many bytes. */ ++#define WL_NAN_SVC_HASH_LEN 6 ++#define WL_NAN_HASHES_PER_BLOOM 4 /** Number of hash functions per bloom filter */ ++ ++/* no. of max last disc results */ ++#define WL_NAN_MAX_DISC_RESULTS 3 ++ ++/* Max len of Rx and Tx filters */ ++#define WL_NAN_MAX_SVC_MATCH_FILTER_LEN 255 ++ ++/* Max service name len */ ++#define WL_NAN_MAX_SVC_NAME_LEN 32 ++ ++/* Type of Data path connection */ ++#define WL_NAN_DP_TYPE_UNICAST 0 ++#define WL_NAN_DP_TYPE_MULTICAST 1 ++ ++/* MAX security params length PMK field */ ++#define WL_NAN_NCS_SK_PMK_LEN 32 ++ ++/* Post disc attr ID type */ ++typedef uint8 wl_nan_post_disc_attr_id_t; ++ ++/* ++ * Component IDs ++ */ ++typedef enum { ++ WL_NAN_COMPID_CONFIG = 1, ++ WL_NAN_COMPID_ELECTION = 2, ++ WL_NAN_COMPID_SD = 3, ++ WL_NAN_COMPID_TIMESYNC = 4, ++ WL_NAN_COMPID_DATA_PATH = 5, ++ WL_NAN_COMPID_DEBUG = 15 /* Keep this at the end */ ++} wl_nan_comp_id_t; ++ ++#define WL_NAN_COMP_SHIFT 8 ++#define WL_NAN_COMP_MASK(_c) (0x0F & ((uint8)(_c))) ++#define WL_NAN_COMP_ID(_c) (WL_NAN_COMP_MASK(_c) << WL_NAN_COMP_SHIFT) ++ ++/* NAN Events */ ++ ++/** Instance ID type (unique identifier) */ ++typedef uint8 wl_nan_instance_id_t; ++ ++/* Publish sent for a subscribe */ ++/* WL_NAN_EVENT_REPLIED */ ++ ++typedef struct wl_nan_ev_replied { ++ struct ether_addr sub_mac; /* Subscriber MAC */ ++ wl_nan_instance_id_t pub_id; /* Publisher Instance ID */ ++ uint8 sub_id; /* Subscriber ID */ ++ int8 sub_rssi; /* Subscriber RSSI */ ++ uint8 pad[3]; ++} wl_nan_ev_replied_t; ++ ++typedef struct wl_nan_event_replied { ++ struct ether_addr sub_mac; /* Subscriber MAC */ ++ wl_nan_instance_id_t pub_id; /* Publisher Instance ID */ ++ uint8 sub_id; /* Subscriber ID */ ++ int8 sub_rssi; /* Subscriber RSSI */ ++ uint8 attr_num; ++ uint16 attr_list_len; /* sizeof attributes attached to payload */ ++ uint8 attr_list[0]; /* attributes payload */ ++} wl_nan_event_replied_t; ++ ++/* Subscribe or Publish instance Terminated */ ++ ++/* WL_NAN_EVENT_TERMINATED */ ++ ++#define NAN_SD_TERM_REASON_TIMEOUT 1 ++#define NAN_SD_TERM_REASON_HOSTREQ 2 ++#define NAN_SD_TERM_REASON_FWTERM 3 ++#define NAN_SD_TERM_REASON_FAIL 4 ++ ++typedef struct wl_nan_ev_terminated { ++ uint8 instance_id; /* publish / subscribe instance id */ ++ uint8 reason; /* 1=timeout, 2=Host/IOVAR, 3=FW Terminated 4=Failure */ ++ uint8 svctype; /* 0 - Publish, 0x1 - Subscribe */ ++ uint8 pad; /* Align */ ++} wl_nan_ev_terminated_t; ++ ++/* Follow up received against a pub / subscr */ ++/* WL_NAN_EVENT_RECEIVE */ ++ ++typedef struct wl_nan_ev_receive { ++ struct ether_addr remote_addr; /* Peer NAN device MAC */ ++ uint8 local_id; /* Local subscribe or publish ID */ ++ uint8 remote_id; /* Remote subscribe or publish ID */ ++ int8 fup_rssi; ++ uint8 attr_num; ++ uint16 attr_list_len; /* sizeof attributes attached to payload */ ++ uint8 attr_list[0]; /* attributes payload */ ++} wl_nan_ev_receive_t; ++ ++/* ++ * TLVs - Below XTLV definitions will be deprecated ++ * in due course (soon as all other branches update ++ * to the comp ID based XTLVs listed below). ++ */ ++enum wl_nan_cmd_xtlv_id { ++ WL_NAN_XTLV_MAC_ADDR = 0x120, ++ WL_NAN_XTLV_MATCH_RX = 0x121, ++ WL_NAN_XTLV_MATCH_TX = 0x122, ++ WL_NAN_XTLV_SVC_INFO = 0x123, ++ WL_NAN_XTLV_SVC_NAME = 0x124, ++ WL_NAN_XTLV_SR_FILTER = 0x125, ++ WL_NAN_XTLV_FOLLOWUP = 0x126, ++ WL_NAN_XTLV_SVC_LIFE_COUNT = 0x127, ++ WL_NAN_XTLV_AVAIL = 0x128, ++ WL_NAN_XTLV_SDF_RX = 0x129, ++ WL_NAN_XTLV_SDE_CONTROL = 0x12a, ++ WL_NAN_XTLV_SDE_RANGE_LIMIT = 0x12b, ++ WL_NAN_XTLV_NAN_AF = 0x12c, ++ WL_NAN_XTLV_SD_TERMINATE = 0x12d, ++ WL_NAN_XTLV_CLUSTER_ID = 0x12e, ++ WL_NAN_XTLV_PEER_RSSI = 0x12f, ++ WL_NAN_XTLV_BCN_RX = 0x130, ++ WL_NAN_XTLV_REPLIED = 0x131, /* Publish sent for a subscribe */ ++ WL_NAN_XTLV_RECEIVED = 0x132, /* FUP Received */ ++ WL_NAN_XTLV_DISC_RESULTS = 0x133 /* Discovery results */ ++}; ++ ++#define WL_NAN_CMD_GLOBAL 0x00 ++#define WL_NAN_CMD_CFG_COMP_ID 0x01 ++#define WL_NAN_CMD_ELECTION_COMP_ID 0x02 ++#define WL_NAN_CMD_SD_COMP_ID 0x03 ++#define WL_NAN_CMD_SYNC_COMP_ID 0x04 ++#define WL_NAN_CMD_DATA_COMP_ID 0x05 ++#define WL_NAN_CMD_DAM_COMP_ID 0x06 ++#define WL_NAN_CMD_RANGE_COMP_ID 0x07 ++#define WL_NAN_CMD_DBG_COMP_ID 0x0f ++ ++#define WL_NAN_CMD_COMP_SHIFT 8 ++#define NAN_CMD(x, y) (((x) << WL_NAN_CMD_COMP_SHIFT) | (y)) ++ ++/* ++ * Module based NAN TLV IDs ++ */ ++typedef enum wl_nan_tlv { ++ ++ WL_NAN_XTLV_CFG_MATCH_RX = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x01), ++ WL_NAN_XTLV_CFG_MATCH_TX = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x02), ++ WL_NAN_XTLV_CFG_SR_FILTER = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x03), ++ WL_NAN_XTLV_CFG_SVC_NAME = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x04), ++ WL_NAN_XTLV_CFG_NAN_STATUS = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x05), ++ WL_NAN_XTLV_CFG_SVC_LIFE_COUNT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x06), ++ WL_NAN_XTLV_CFG_SVC_HASH = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x07), ++ WL_NAN_XTLV_CFG_SEC_CSID = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x08), /* Security CSID */ ++ WL_NAN_XTLV_CFG_SEC_PMK = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x09), /* Security PMK */ ++ WL_NAN_XTLV_CFG_SEC_PMKID = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0A), ++ ++ WL_NAN_XTLV_SD_SVC_INFO = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x01), ++ WL_NAN_XTLV_SD_FOLLOWUP = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x02), ++ WL_NAN_XTLV_SD_SDF_RX = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x03), ++ WL_NAN_XTLV_SD_SDE_CONTROL = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x04), ++ WL_NAN_XTLV_SD_SDE_RANGE_LIMIT = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x05), ++ WL_NAN_XTLV_SD_NAN_AF = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x06), ++ WL_NAN_XTLV_SD_TERM = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x07), ++ WL_NAN_XTLV_SD_REPLIED = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x08), /* Pub sent */ ++ WL_NAN_XTLV_SD_FUP_RECEIVED = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x09), /* FUP Received */ ++ WL_NAN_XTLV_SD_DISC_RESULTS = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x0A), /* Pub RX */ ++ ++ WL_NAN_XTLV_SYNC_BCN_RX = NAN_CMD(WL_NAN_CMD_SYNC_COMP_ID, 0x01), ++ ++ WL_NAN_XTLV_DATA_DP_END = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x01), ++ WL_NAN_XTLV_DATA_DP_INFO = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x02), ++ WL_NAN_XTLV_DATA_DP_SEC_INST = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x03), ++ ++ WL_NAN_XTLV_RANGE_INFO = NAN_CMD(WL_NAN_CMD_RANGE_COMP_ID, 0x01) ++} wl_nan_tlv_t; ++ ++enum wl_nan_sub_cmd_xtlv_id { ++ ++ /* Special command - Tag zero */ ++ WL_NAN_CMD_GLB_NAN_VER = NAN_CMD(WL_NAN_CMD_GLOBAL, 0x00), ++ ++ /* nan cfg sub-commands */ ++ ++ WL_NAN_CMD_CFG_NAN_INIT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x01), ++ WL_NAN_CMD_CFG_ROLE = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x02), ++ WL_NAN_CMD_CFG_HOP_CNT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x03), ++ WL_NAN_CMD_CFG_HOP_LIMIT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x04), ++ WL_NAN_CMD_CFG_WARMUP_TIME = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x05), ++ WL_NAN_CMD_CFG_STATUS = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x06), ++ WL_NAN_CMD_CFG_OUI = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x07), ++ WL_NAN_CMD_CFG_COUNT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x08), ++ WL_NAN_CMD_CFG_CLEARCOUNT = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x09), ++ WL_NAN_CMD_CFG_CHANNEL = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0A), ++ WL_NAN_CMD_CFG_BAND = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0B), ++ WL_NAN_CMD_CFG_CID = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0C), ++ WL_NAN_CMD_CFG_IF_ADDR = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0D), ++ WL_NAN_CMD_CFG_BCN_INTERVAL = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0E), ++ WL_NAN_CMD_CFG_SDF_TXTIME = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x0F), ++ WL_NAN_CMD_CFG_SID_BEACON = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x10), ++ WL_NAN_CMD_CFG_DW_LEN = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x11), ++ WL_NAN_CMD_CFG_AVAIL = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x12), ++ WL_NAN_CMD_CFG_WFA_TM = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x13), ++ WL_NAN_CMD_CFG_EVENT_MASK = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x14), ++ WL_NAN_CMD_CFG_NAN_CONFIG = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x15), ++ WL_NAN_CMD_CFG_NAN_ENAB = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x16), ++ WL_NAN_CMD_CFG_ULW = NAN_CMD(WL_NAN_CMD_CFG_COMP_ID, 0x17), ++ WL_NAN_CMD_CFG_MAX = WL_NAN_CMD_CFG_NAN_ENAB, ++ /* Add new commands before and update */ ++ ++ /* nan election sub-commands */ ++ WL_NAN_CMD_ELECTION_JOIN = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x04), /* Deprecated */ ++ WL_NAN_CMD_ELECTION_STOP = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x07), /* Deprecate */ ++ ++ WL_NAN_CMD_ELECTION_HOST_ENABLE = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x01), ++ WL_NAN_CMD_ELECTION_METRICS_CONFIG = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x02), ++ WL_NAN_CMD_ELECTION_METRICS_STATE = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x03), ++ WL_NAN_CMD_ELECTION_LEAVE = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x03), ++ WL_NAN_CMD_ELECTION_MERGE = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x04), ++ WL_NAN_CMD_ELECTION_ADVERTISERS = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x05), ++ WL_NAN_CMD_ELECTION_RSSI_THRESHOLD = NAN_CMD(WL_NAN_CMD_ELECTION_COMP_ID, 0x06), ++ WL_NAN_CMD_ELECTION_MAX = WL_NAN_CMD_ELECTION_RSSI_THRESHOLD, ++ /* New commands go before and update */ ++ ++ /* nan SD sub-commands */ ++ WL_NAN_CMD_SD_PARAMS = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x01), ++ WL_NAN_CMD_SD_PUBLISH = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x02), ++ WL_NAN_CMD_SD_PUBLISH_LIST = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x03), ++ WL_NAN_CMD_SD_CANCEL_PUBLISH = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x04), ++ WL_NAN_CMD_SD_SUBSCRIBE = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x05), ++ WL_NAN_CMD_SD_SUBSCRIBE_LIST = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x06), ++ WL_NAN_CMD_SD_CANCEL_SUBSCRIBE = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x07), ++ WL_NAN_CMD_SD_VND_INFO = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x08), ++ WL_NAN_CMD_SD_STATS = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x09), ++ WL_NAN_CMD_SD_TRANSMIT = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x0A), ++ WL_NAN_CMD_SD_FUP_TRANSMIT = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x0B), ++ WL_NAN_CMD_SD_CONNECTION = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x0C), ++ WL_NAN_CMD_SD_SHOW = NAN_CMD(WL_NAN_CMD_SD_COMP_ID, 0x0D), ++ WL_NAN_CMD_SD_MAX = WL_NAN_CMD_SD_SHOW, ++ ++ /* nan time sync sub-commands */ ++ ++ WL_NAN_CMD_SYNC_SOCIAL_CHAN = NAN_CMD(WL_NAN_CMD_SYNC_COMP_ID, 0x01), ++ WL_NAN_CMD_SYNC_AWAKE_DWS = NAN_CMD(WL_NAN_CMD_SYNC_COMP_ID, 0x02), ++ WL_NAN_CMD_SYNC_BCN_RSSI_NOTIF_THRESHOLD = NAN_CMD(WL_NAN_CMD_SYNC_COMP_ID, 0x03), ++ WL_NAN_CMD_SYNC_MAX = WL_NAN_CMD_SYNC_BCN_RSSI_NOTIF_THRESHOLD, ++ ++ /* nan2 commands */ ++ WL_NAN_CMD_DATA_CONFIG = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x01), ++ WL_NAN_CMD_DATA_RSVD02 = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x02), ++ WL_NAN_CMD_DATA_RSVD03 = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x03), ++ WL_NAN_CMD_DATA_DATAREQ = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x04), ++ WL_NAN_CMD_DATA_DATARESP = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x05), ++ WL_NAN_CMD_DATA_DATAEND = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x06), ++ WL_NAN_CMD_DATA_SCHEDUPD = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x07), ++ WL_NAN_CMD_DATA_RSVD08 = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x08), ++ WL_NAN_CMD_DATA_CAP = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x9), ++ WL_NAN_CMD_DATA_STATUS = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0A), ++ WL_NAN_CMD_DATA_STATS = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0B), ++ WL_NAN_CMD_DATA_RSVD0C = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0C), ++ WL_NAN_CMD_DATA_NDP_SHOW = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0D), ++ WL_NAN_CMD_DATA_DATACONF = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0E), ++ WL_NAN_CMD_DATA_MIN_TX_RATE = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x0F), ++ WL_NAN_CMD_DATA_MAX_PEERS = NAN_CMD(WL_NAN_CMD_DATA_COMP_ID, 0x10), ++ WL_NAN_CMD_DATA_PATH_MAX = WL_NAN_CMD_DATA_MAX_PEERS, /* New ones before and update */ ++ ++ /* nan dam sub-commands */ ++ WL_NAN_CMD_DAM_CFG = NAN_CMD(WL_NAN_CMD_DAM_COMP_ID, 0x01), ++ WL_NAN_CMD_DAM_MAX = WL_NAN_CMD_DAM_CFG, /* New ones before and update */ ++ ++ /* nan2.0 ranging commands */ ++ WL_NAN_CMD_RANGE_REQUEST = NAN_CMD(WL_NAN_CMD_RANGE_COMP_ID, 0x01), ++ WL_NAN_CMD_RANGE_AUTO = NAN_CMD(WL_NAN_CMD_RANGE_COMP_ID, 0x02), ++ WL_NAN_CMD_RANGE_RESPONSE = NAN_CMD(WL_NAN_CMD_RANGE_COMP_ID, 0x03), ++ WL_NAN_CMD_RANGE_CANCEL = NAN_CMD(WL_NAN_CMD_RANGE_COMP_ID, 0x04), ++ ++ /* nan debug sub-commands */ ++ WL_NAN_CMD_DBG_SCAN_PARAMS = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x01), ++ WL_NAN_CMD_DBG_SCAN = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x02), ++ WL_NAN_CMD_DBG_SCAN_RESULTS = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x03), ++ /* This is now moved under CFG */ ++ WL_NAN_CMD_DBG_EVENT_MASK = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x04), ++ WL_NAN_CMD_DBG_EVENT_CHECK = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x05), ++ WL_NAN_CMD_DBG_DUMP = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x06), ++ WL_NAN_CMD_DBG_CLEAR = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x07), ++ WL_NAN_CMD_DBG_RSSI = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x08), ++ WL_NAN_CMD_DBG_DEBUG = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x09), ++ WL_NAN_CMD_DBG_TEST1 = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0A), ++ WL_NAN_CMD_DBG_TEST2 = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0B), ++ WL_NAN_CMD_DBG_TEST3 = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0C), ++ WL_NAN_CMD_DBG_DISC_RESULTS = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0D), ++ WL_NAN_CMD_DBG_STATS = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0E), ++ WL_NAN_CMD_DBG_LEVEL = NAN_CMD(WL_NAN_CMD_DBG_COMP_ID, 0x0F), ++ WL_NAN_CMD_DBG_MAX = WL_NAN_CMD_DBG_LEVEL /* New ones before and update */ ++}; ++ ++/** status - TBD BCME_ vs NAN status - range reserved for BCME_ */ ++enum { ++ /* add new status here... */ ++ WL_NAN_E_SEC_SA_NOTFOUND = -2076, ++ WL_NAN_E_BSSCFG_NOTFOUND = -2075, ++ WL_NAN_E_SCB_NOTFOUND = -2074, ++ WL_NAN_E_NCS_SK_KDESC_TYPE = -2073, ++ WL_NAN_E_NCS_SK_KEY_DESC_VER = -2072, /* key descr ver */ ++ WL_NAN_E_NCS_SK_KEY_TYPE = -2071, /* key descr type */ ++ WL_NAN_E_NCS_SK_KEYINFO_FAIL = -2070, /* key info (generic) */ ++ WL_NAN_E_NCS_SK_KEY_LEN = -2069, /* key len */ ++ WL_NAN_E_NCS_SK_KDESC_NOT_FOUND = -2068, /* key desc not found */ ++ WL_NAN_E_NCS_SK_INVALID_PARAMS = -2067, /* invalid args */ ++ WL_NAN_E_NCS_SK_KDESC_INVALID = -2066, /* key descr is not valid */ ++ WL_NAN_E_NCS_SK_NONCE_MISMATCH = -2065, ++ WL_NAN_E_NCS_SK_KDATA_SAVE_FAIL = -2064, /* not able to save key data */ ++ WL_NAN_E_NCS_SK_AUTH_TOKEN_CALC_FAIL = -2063, ++ WL_NAN_E_NCS_SK_PTK_CALC_FAIL = -2062, ++ WL_NAN_E_INVALID_STARTOFFSET = -2061, ++ WL_NAN_E_BAD_NA_ENTRY_TYPE = -2060, ++ WL_NAN_E_INVALID_CHANBMP = -2059, ++ WL_NAN_E_INVALID_OP_CLASS = -2058, ++ WL_NAN_E_NO_IES = -2057, ++ WL_NAN_E_NO_PEER_ENTRY_AVAIL = -2056, ++ WL_NAN_E_INVALID_PEER = -2055, ++ WL_NAN_E_PEER_EXISTS = -2054, ++ WL_NAN_E_PEER_NOTFOUND = -2053, ++ WL_NAN_E_NO_MEM = -2052, ++ WL_NAN_E_INVALID_OPTION = -2051, ++ WL_NAN_E_INVALID_BAND = -2050, ++ WL_NAN_E_INVALID_MAC = -2049, ++ WL_NAN_E_BAD_INSTANCE = -2048, ++ WL_NAN_E_NDC_EXISTS = -2047, ++ WL_NAN_E_NO_NDC_ENTRY_AVAIL = -2046, ++ WL_NAN_E_INVALID_NDC_ENTRY = -2045, ++ WL_NAN_E_ERROR = -1, ++ WL_NAN_E_OK = 0 ++}; ++ ++typedef int32 wl_nan_status_t; ++ ++/** nan cmd list entry */ ++enum wl_nan_sub_cmd_input_flags { ++ WL_NAN_SUB_CMD_FLAG_NONE = 0, ++ WL_NAN_SUB_CMD_FLAG_SKIP = 1, /* Skip to next sub-command on error */ ++ WL_NAN_SUB_CMD_FLAG_TERMINATE = 2, /* Terminate processing and return */ ++ WL_NAN_SUB_CMD_FLAG_LAST /* Keep this at the end */ ++}; ++ ++/** container for nan events */ ++typedef struct wl_nan_ioc { ++ uint16 version; /**< interface command or event version */ ++ uint16 id; /**< nan ioctl cmd ID */ ++ uint16 len; /**< total length of all tlv records in data[] */ ++ uint16 pad; /**< pad to be 32 bit aligment */ ++ uint8 data []; /**< var len payload of bcm_xtlv_t type */ ++} wl_nan_ioc_t; ++ ++/* ++ * NAN sub-command data structures ++ */ ++ ++/* ++ * Config component WL_NAN_CMD_CFG_XXXX sub-commands ++ * WL_NAN_CMD_CFG_ENABLE ++ */ ++enum wl_nan_config_state { ++ WL_NAN_CONFIG_STATE_DISABLE = 0, ++ WL_NAN_CONFIG_STATE_ENABLE = 1 ++}; ++ ++typedef int8 wl_nan_config_state_t; ++ ++/* WL_NAN_CMD_CFG_NAN_INIT */ ++ ++typedef uint8 wl_nan_init_t; ++ ++/* WL_NAN_CMD_CFG_NAN_VERSION */ ++typedef uint16 wl_nan_ver_t; ++ ++/* WL_NAN_CMD_CFG_NAN_CONFIG */ ++typedef uint32 wl_nan_cfg_ctrl_t; ++ ++/* ++ * WL_NAN_CMD_CFG_BAND, WL_NAN_CMD_CFG_RSSI_THRESHOLD(Get only) ++ */ ++typedef uint8 wl_nan_band_t; ++ ++/* ++ * WL_NAN_CMD_CFG_ROLE ++ */ ++enum wl_nan_role { ++ WL_NAN_ROLE_AUTO = 0, ++ WL_NAN_ROLE_NON_MASTER_NON_SYNC = 1, ++ WL_NAN_ROLE_NON_MASTER_SYNC = 2, ++ WL_NAN_ROLE_MASTER = 3, ++ WL_NAN_ROLE_ANCHOR_MASTER = 4 ++}; ++ ++typedef uint8 wl_nan_role_t; ++ ++typedef struct wl_nan_device_state ++{ ++ wl_nan_role_t role; /* Sync Master, Non-Sync Master */ ++ uint8 state; /* TBD */ ++ uint8 hopcount; /* Hops to the Anchor Master */ ++ struct ether_addr immediate_master; /* Master MAC */ ++ struct ether_addr anchor_master; /* Anchor Master MAC */ ++ struct ether_addr cluster_id; /* Cluster ID to which this device belongs to */ ++ uint8 PAD[3]; ++ uint32 tsf_high; /* NAN Cluster TSFs */ ++ uint32 tsf_low; ++} wl_nan_device_state_t; ++ ++/* ++ * WL_NAN_CMD_CFG_HOP_CNT, WL_NAN_CMD_CFG_HOP_LIMIT ++ */ ++typedef uint8 wl_nan_hop_count_t; ++ ++/* ++ * WL_NAN_CMD_CFG_WARMUP_TIME ++ */ ++typedef uint32 wl_nan_warmup_time_ticks_t; ++ ++/* ++ * WL_NAN_CMD_CFG_RSSI_THRESHOLD ++ * rssi_close and rssi_mid are used to transition master to non-master ++ * role by NAN state machine. rssi thresholds corresponding to the band ++ * will be updated. ++ */ ++/* To be deprecated */ ++typedef struct wl_nan_rssi_threshold { ++ wl_nan_band_t band; ++ int8 rssi_close; ++ int8 rssi_mid; ++ uint8 pad; ++} wl_nan_rssi_threshold_t; ++ ++/* WL_NAN_CMD_ELECTION_RSSI_THRESHOLD */ ++ ++typedef struct wl_nan_rssi_thld { ++ int8 rssi_close_2g; ++ int8 rssi_mid_2g; ++ int8 rssi_close_5g; ++ int8 rssi_mid_5g; ++} wl_nan_rssi_thld_t; ++ ++/* WL_NAN_CMD_DATA_MAX_PEERS */ ++ ++typedef uint8 wl_nan_max_peers_t; ++ ++#define NAN_MAX_BANDS 2 ++/* ++ * WL_NAN_CMD_CFG_STATUS ++ */ ++/* Deprecated - Begin */ ++typedef struct wl_nan_cfg_status { ++ uint8 enabled; ++ uint8 inited; ++ uint8 joined; ++ uint8 merged; ++ uint8 role; ++ uint8 PAD[3]; ++ uint32 chspec[2]; ++ uint8 mr[8]; /**< Master Rank */ ++ uint8 amr[8]; /**< Anchor Master Rank */ ++ uint32 cnt_pend_txfrm; /**< pending TX frames */ ++ uint32 cnt_bcn_tx; /**< TX disc/sync beacon count */ ++ uint32 cnt_bcn_rx; /**< RX disc/sync beacon count */ ++ uint32 cnt_svc_disc_tx; /**< TX svc disc frame count */ ++ uint32 cnt_svc_disc_rx; /**< RX svc disc frame count */ ++ uint32 ambtt; /**< Anchor master beacon target time */ ++ struct ether_addr cid; /**< Cluster id */ ++ uint8 hop_count; /**< Hop count */ ++ uint8 PAD; ++} wl_nan_cfg_status_t; ++ ++typedef struct wl_nan_config_status { ++ struct ether_addr def_cid; /* Default Cluster id */ ++ uint8 inited; /* NAN Initialized successfully */ ++ uint8 enabled; /* NAN Enabled */ ++ struct ether_addr cur_cid; /* Default Cluster id */ ++ uint8 joined; /* Joined or started own cluster */ ++ uint8 role; /* Master, Non Master, NM Sync & Non-Sync */ ++ chanspec_t chspec[NAN_MAX_BANDS]; /* Channel Spec 2.4G followed by 5G */ ++ uint8 mr[WL_NAN_MASTER_RANK_LEN]; /* Master Rank */ ++ uint8 amr[WL_NAN_MASTER_RANK_LEN]; /* Anchor Master Rank */ ++ uint32 cnt_pend_txfrm; /* Pending Tx Frames */ ++ uint32 cnt_bcn_tx; /* TX disc/sync beacon count */ ++ uint32 cnt_bcn_rx; /* RX disc/sync beacon count */ ++ uint32 cnt_svc_disc_tx; /* TX svc disc frame count */ ++ uint32 cnt_svc_disc_rx; /* RX svc disc frame count */ ++ uint32 ambtt; /* Anchor master beacon target time */ ++ uint8 hop_count; /* Hop count */ ++ uint8 pad[3]; /* Align */ ++} wl_nan_config_status_t; ++/* Deprecated - End */ ++ ++typedef enum wl_nan_election_mode { ++ WL_NAN_ELECTION_RUN_BY_HOST = 1, ++ WL_NAN_ELECTION_RUN_BY_FW = 2 ++} wl_nan_election_mode_t; ++ ++typedef struct wl_nan_conf_status { ++ struct ether_addr nmi; /* NAN mgmt interface address */ ++ uint8 enabled; /* NAN is enabled */ ++ uint8 role; /* Current nan sync role */ ++ struct ether_addr cid; /* Current Cluster id */ ++ uint8 social_chans[2]; /* Social channels */ ++ uint8 mr[8]; /* Master Rank */ ++ uint8 amr[8]; /* Anchor Master Rank */ ++ uint32 ambtt; /* Anchor master beacon target time */ ++ uint32 cluster_tsf_h; /* Current Cluster TSF High */ ++ uint32 cluster_tsf_l; /* Current Cluster TSF Low */ ++ uint8 election_mode; /* Election mode, host or firmware */ ++ uint8 hop_count; /* Current Hop count */ ++ uint8 pad[2]; ++} wl_nan_conf_status_t; ++ ++/* ++ * WL_NAN_CMD_CFG_OUI ++ */ ++typedef struct wl_nan_oui_type { ++ uint8 nan_oui[DOT11_OUI_LEN]; ++ uint8 type; ++} wl_nan_oui_type_t; ++ ++/* ++ * WL_NAN_CMD_CFG_COUNT ++ */ ++typedef struct wl_nan_count { ++ uint32 cnt_bcn_tx; /**< TX disc/sync beacon count */ ++ uint32 cnt_bcn_rx; /**< RX disc/sync beacon count */ ++ uint32 cnt_svc_disc_tx; /**< TX svc disc frame count */ ++ uint32 cnt_svc_disc_rx; /**< RX svc disc frame count */ ++} wl_nan_count_t; ++/* ++ * Election component WL_NAN_CMD_ELECTION_XXXX sub-commands ++ * WL_NAN_CMD_ELECTION_HOST_ENABLE ++ */ ++enum wl_nan_enable_flags { ++ WL_NAN_DISABLE_FLAG_HOST_ELECTION = 0, ++ WL_NAN_ENABLE_FLAG_HOST_ELECTION = 1 ++}; ++ ++/* ++ * 0 - disable host based election ++ * 1 - enable host based election ++ */ ++typedef uint8 wl_nan_host_enable_t; ++ ++/* ++ * WL_NAN_CMD_ELECTION_METRICS_CONFIG ++ */ ++/* Set only */ ++typedef struct wl_nan_election_metric_config { ++ uint8 random_factor; /* Configured random factor */ ++ uint8 master_pref; /* configured master preference */ ++ uint8 pad[2]; ++} wl_nan_election_metric_config_t; ++ ++/* ++ * WL_NAN_CMD_ELECTION_METRICS_STATE ++ */ ++/* Get only */ ++typedef struct wl_nan_election_metric_state { ++ uint8 random_factor; /* random factor used in MIs */ ++ uint8 master_pref; /* Master advertised in MIs */ ++ uint8 pad[2]; ++} wl_nan_election_metric_state_t; ++ ++/* ++ * WL_NAN_CMD_ELECTION_LEAVE ++ * WL_NAN_CMD_ELECTION_STOP ++ */ ++typedef struct ether_addr wl_nan_cluster_id_t; ++ ++/* ++ * WL_NAN_CMD_ELECTION_JOIN ++ */ ++typedef struct wl_nan_join { ++ uint8 start_cluster; /* Start a cluster */ ++ uint8 pad[3]; ++ wl_nan_cluster_id_t cluster_id; /* Cluster ID to join */ ++} wl_nan_join_t; ++ ++/* ++ * WL_NAN_CMD_ELECTION_MERGE ++ * 0 - disable cluster merge ++ * 1 - enable cluster merge ++ */ ++typedef uint8 wl_nan_merge_enable_t; ++ ++/* ++ * WL_NAN_CMD_CFG_ROLE ++ * role = 0 means configuration by firmware; otherwise by host ++ * when host configures role, also need target master address to sync to ++ */ ++#define NAN_SYNC_MASTER_SELF 0 ++#define NAN_SYNC_MASTER_AM 1 ++#define NAN_SYNC_MASTER_INTERMEDIATE 2 ++/* ltsf_h, ltsf_l: ++ The local TSF timestamp filled in by FW in the WL_NAN_EVENT_BCN_RX event; ++ rtsf_h, rtsf_l: ++ The timestamp in the Rx beacon frame, filled in by host ++ uint32 ambtt: ++ the amtt in the cluster ID attribute in the Rx beacon frame ++*/ ++typedef struct nan_sync_master { ++ uint8 flag; /* 0: self, 1: anchor-master, 2: intermediate master */ ++ uint8 hop_count; ++ struct ether_addr addr; ++ struct ether_addr cluster_id; ++ chanspec_t channel; /* bcn reception channel */ ++ uint32 ltsf_h; ++ uint32 ltsf_l; ++ uint32 rtsf_h; ++ uint32 rtsf_l; ++ uint8 amr[WL_NAN_MASTER_RANK_LEN]; ++ uint32 ambtt; ++} nan_sync_master_t; ++ ++/* NAN advertiser structure */ ++/* TODO RSDB: add chspec to indicates core corresponds correct core */ ++typedef struct nan_adv_entry { ++ uint8 age; /* used to remove stale entries */ ++ uint8 hop_count; ++ struct ether_addr addr; ++ struct ether_addr cluster_id; ++ chanspec_t channel; /* bcn reception channel */ ++ uint32 ltsf_h; ++ uint32 ltsf_l; ++ uint32 rtsf_h; ++ uint32 rtsf_l; ++ uint8 amr[WL_NAN_MASTER_RANK_LEN]; ++ uint32 ambtt; ++ int8 rssi[NAN_MAX_BANDS]; /* rssi last af was received at */ ++ int8 last_rssi[NAN_MAX_BANDS]; /* rssi in the last AF */ ++} nan_adv_entry_t; ++ ++typedef struct nan_adv_table { ++ uint8 num_adv; ++ uint8 adv_size; ++ uint8 pad[2]; ++ nan_adv_entry_t adv_nodes[0]; ++} nan_adv_table_t; ++ ++typedef struct wl_nan_role_cfg { ++ wl_nan_role_t cfg_role; ++ wl_nan_role_t cur_role; ++ uint8 pad[2]; ++ nan_sync_master_t target_master; ++} wl_nan_role_cfg_t; ++ ++typedef struct wl_nan_role_config { ++ wl_nan_role_t role; ++ struct ether_addr target_master; ++ uint8 pad; ++} wl_nan_role_config_t; ++ ++typedef int8 wl_nan_sd_optional_field_types_t; ++ ++/* Flag bits for Publish and Subscribe (wl_nan_sd_params_t flags) */ ++ ++#define WL_NAN_RANGE_LIMITED 0x0040 ++ ++/* Event generation indicator (default is continuous) */ ++ ++#define WL_NAN_MATCH_ONCE 0x100000 ++#define WL_NAN_MATCH_NEVER 0x200000 ++ ++/* Bits specific to Publish */ ++ ++#define WL_NAN_PUB_UNSOLICIT 0x1000 /* Unsolicited Tx */ ++#define WL_NAN_PUB_SOLICIT 0x2000 /* Solicited Tx */ ++#define WL_NAN_PUB_BOTH 0x3000 /* Both the above */ ++ ++#define WL_NAN_PUB_BCAST 0x4000 /* bcast solicited Tx only */ ++#define WL_NAN_PUB_EVENT 0x8000 /* Event on each solicited Tx */ ++#define WL_NAN_PUB_SOLICIT_PENDING 0x10000 /* Used for one-time solicited Publish */ ++ ++#define WL_NAN_FOLLOWUP 0x20000 /* Follow-up frames */ ++ ++/* Bits specific to Subscribe */ ++ ++#define WL_NAN_SUB_ACTIVE 0x1000 /* Active subscribe mode */ ++#define WL_NAN_SUB_MATCH_IF_SVC_INFO 0x2000 /* Service info in publish */ ++ ++#define WL_NAN_TTL_UNTIL_CANCEL 0xFFFFFFFF /* Special values for time to live (ttl) parameter */ ++ ++/* ++ * Publish - runs until first transmission ++ * Subscribe - runs until first DiscoveryResult event ++ */ ++#define WL_NAN_TTL_FIRST 0 ++ ++/* ++ * WL_NAN_CMD_SD_PARAMS ++ */ ++typedef struct wl_nan_sd_params ++{ ++ uint16 length; /* length including options */ ++ uint8 period; /* period of the unsolicited SDF xmission in DWs */ ++ uint8 pad; ++ uint8 svc_hash[WL_NAN_SVC_HASH_LEN]; /* Hash for the service name */ ++ uint8 instance_id; /* Instance of the current service */ ++ int8 proximity_rssi; /* RSSI limit to Rx subscribe or pub SDF 0 no effect */ ++ uint32 flags; /* bitmap representing aforesaid optional flags */ ++ int32 ttl; /* TTL for this instance id, -1 will run till cancelled */ ++ tlv_t optional[1]; /* optional fields in the SDF as appropriate */ ++} wl_nan_sd_params_t; ++ ++/* ++ * WL_NAN_CMD_SD_PUBLISH_LIST ++ * WL_NAN_CMD_SD_SUBSCRIBE_LIST ++ */ ++typedef struct wl_nan_service_info ++{ ++ uint8 instance_id; /* Publish instance ID */ ++ uint8 service_hash[WL_NAN_SVC_HASH_LEN]; /* Hash for service name */ ++} wl_nan_service_info_t; ++ ++typedef struct wl_nan_service_list ++{ ++ uint16 id_count; /* Number of registered publish/subscribe services */ ++ wl_nan_service_info_t list[1]; /* service info defined by nan_service instance */ ++} wl_nan_service_list_t; ++ ++/* ++ * WL_NAN_CMD_CFG_BCN_INTERVAL ++ */ ++typedef uint16 wl_nan_disc_bcn_interval_t; ++ ++/* ++ * WL_NAN_CMD_CFG_SDF_TXTIME ++ */ ++typedef uint16 wl_nan_svc_disc_txtime_t; ++ ++/* ++ * WL_NAN_CMD_CFG_STOP_BCN_TX ++ */ ++typedef uint16 wl_nan_stop_bcn_tx_t; ++ ++/* ++ * WL_NAN_CMD_CFG_SID_BEACON ++ */ ++typedef struct wl_nan_sid_beacon_control { ++ uint8 sid_enable; /* Flag to indicate the inclusion of Service IDs in Beacons */ ++ uint8 sid_count; /* Limit for number of SIDs to be included in Beacons */ ++ uint8 pad[2]; ++} wl_nan_sid_beacon_control_t; ++ ++/* ++ * WL_NAN_CMD_CFG_DW_LEN ++ */ ++typedef uint16 wl_nan_dw_len_t; ++ ++/* ++ * WL_NAN_CMD_CFG_AWAKE_DW Will be deprecated. ++ */ ++typedef struct wl_nan_awake_dw { ++ wl_nan_band_t band; /* 0 - b mode 1- a mode */ ++ uint8 interval; /* 1 or 2 or 4 or 8 or 16 */ ++ uint16 pad; ++} wl_nan_awake_dw_t; ++ ++/* ++ * WL_NAN_CMD_CFG_AWAKE_DWS ++ */ ++typedef struct wl_nan_awake_dws { ++ uint8 dw_interval_2g; /* 2G DW interval */ ++ uint8 dw_interval_5g; /* 5G DW interval */ ++ uint16 pad; ++} wl_nan_awake_dws_t; ++ ++/* WL_NAN_CMD_SYNC_BCN_RSSI_NOTIF_THRESHOLD */ ++ ++typedef struct wl_nan_rssi_notif_thld { ++ int8 bcn_rssi_2g; ++ int8 bcn_rssi_5g; ++ int16 pad; ++} wl_nan_rssi_notif_thld_t; ++ ++/* ++ * WL_NAN_CMD_CFG_SOCIAL_CHAN ++ */ ++typedef struct wl_nan_social_channels { ++ uint8 soc_chan_2g; /* 2G social channel */ ++ uint8 soc_chan_5g; /* 5G social channel */ ++ uint16 pad; ++} wl_nan_social_channels_t; ++ ++/* ++ * WL_NAN_CMD_SD_CANCEL_PUBLISH ++ * WL_NAN_CMD_SD_CANCEL_SUBSCRIBE ++ */ ++typedef uint8 wl_nan_instance_id; /* Instance ID of an active publish instance */ ++ ++/* ++ * WL_NAN_CMD_SD_VND_INFO ++ */ ++typedef struct wl_nan_sd_vendor_info ++{ ++ uint16 length; /* Size in bytes of the payload following this field */ ++ uint8 data[]; /* Vendor Information */ ++} wl_nan_sd_vendor_info_t; ++ ++/* ++ * WL_NAN_CMD_SD_STATS ++ */ ++typedef struct wl_nan_sd_stats { ++ uint32 sdftx; ++ uint32 sdfrx; ++ uint32 sdsrffail; ++ uint32 sdrejrssi; ++ uint32 sdfollowuprx; ++ uint32 sdsubmatch; ++ uint32 sdpubreplied; ++ uint32 sdmftfail1; ++ uint32 sdmftfail2; ++ uint32 sdmftfail3; ++ uint32 sdmftfail4; ++} wl_nan_sd_stats_t; ++ ++/* ++ * WL_NAN_CMD_SD_TRANSMIT ++ * WL_NAN_CMD_SD_FUP_TRANSMIT ++ */ ++typedef struct wl_nan_sd_transmit { ++ uint8 local_service_id; /* Sender Service ID */ ++ uint8 requestor_service_id; /* Destination Service ID */ ++ struct ether_addr destination_addr; /* Destination MAC */ ++ uint16 token; /* follow_up_token when a follow-up msg is queued successfully */ ++ uint8 priority; /* requested relative prio */ ++ uint8 service_info_len; /* size in bytes of the service info payload */ ++ uint8 service_info[]; /* Service Info payload */ ++} wl_nan_sd_transmit_t; ++ ++/* ++ * WL_NAN_CMD_SYNC_TSRESERVE ++ */ ++/** time slot */ ++#define NAN_MAX_TIMESLOT 32 ++typedef struct wl_nan_timeslot { ++ uint32 abitmap; /**< available bitmap */ ++ uint32 chanlist[NAN_MAX_TIMESLOT]; ++} wl_nan_timeslot_t; ++ ++/* ++ * Deprecated ++ * ++ * WL_NAN_CMD_SYNC_TSRELEASE ++ */ ++typedef uint32 wl_nan_ts_bitmap_t; ++ ++/* nan passive scan params */ ++#define NAN_SCAN_MAX_CHCNT 8 ++typedef struct wl_nan_scan_params { ++ uint16 scan_time; ++ uint16 home_time; ++ uint16 ms_intvl; /**< interval between merge scan */ ++ uint16 ms_dur; /**< duration of merge scan */ ++ uint16 chspec_num; ++ uint8 pad[2]; ++ chanspec_t chspec_list[NAN_SCAN_MAX_CHCNT]; /**< act. used 3, 5 rfu */ ++} wl_nan_scan_params_t; ++ ++/* ++ * WL_NAN_CMD_DBG_SCAN ++ */ ++typedef struct wl_nan_dbg_scan { ++ struct ether_addr cid; ++ uint8 pad[2]; ++} wl_nan_dbg_scan_t; ++ ++/* NAN_DBG_LEVEL */ ++typedef struct wl_nan_dbg_level { ++ uint32 nan_err_level; /* for Error levels */ ++ uint32 nan_dbg_level; /* for bebug logs and trace */ ++ uint32 nan_info_level; /* for dumps like prhex */ ++} wl_nan_dbg_level_t; ++ ++/* ++ * WL_NAN_CMD_DBG_EVENT_MASK ++ */ ++typedef uint32 wl_nan_event_mask_t; ++ ++/* ++ * WL_NAN_CMD_DBG_EVENT_CHECK ++ */ ++typedef uint8 wl_nan_dbg_ifname[BCM_MSG_IFNAME_MAX]; ++ ++/* ++ * WL_NAN_CMD_DBG_DUMP ++ * WL_NAN_CMD_DBG_CLEAR ++ */ ++enum wl_nan_dbg_dump_type { ++ WL_NAN_DBG_DT_RSSI_DATA = 1, ++ WL_NAN_DBG_DT_STATS_DATA = 2, ++ /* ++ * Additional enums before this line ++ */ ++ WL_NAN_DBG_DT_INVALID ++}; ++typedef int8 wl_nan_dbg_dump_type_t; ++ ++/** various params and ctl swithce for nan_debug instance */ ++/* ++ * WL_NAN_CMD_DBG_DEBUG ++ */ ++typedef struct wl_nan_debug_params { ++ uint16 cmd; /**< debug cmd to perform a debug action */ ++ uint16 status; ++ uint32 msglevel; /**< msg level if enabled */ ++ uint8 enabled; /**< runtime debuging enabled */ ++ uint8 collect; ++ uint8 PAD[2]; ++} wl_nan_debug_params_t; ++ ++ ++typedef struct wl_nan_sched_svc_timeslot_s { ++ uint32 abitmap; /* availability bitmap */ ++ uint32 chanlist[NAN_MAX_TIMESLOT]; ++ uint8 res; /* resolution: 0 = 16ms, 1 = 32ms, 2 = 64ms 3 = reserved. REfer NAN spec */ ++ uint8 mapid; /* mapid from NAN spec. Used to differentiate 2G Vs 5G band */ ++ uint8 PAD[2]; ++} wl_nan_sched_svc_timeslot_t; ++ ++ ++/* nan passive scan params */ ++#define NAN_SCAN_MAX_CHCNT 8 ++typedef struct nan_scan_params { ++ uint16 scan_time; ++ uint16 home_time; ++ uint16 ms_intvl; /**< interval between merge scan */ ++ uint16 ms_dur; /**< duration of merge scan */ ++ uint16 chspec_num; ++ uint8 pad[2]; ++ chanspec_t chspec_list[NAN_SCAN_MAX_CHCNT]; /**< act. used 3, 5 rfu */ ++} nan_scan_params_t; ++ ++/* nan cmd IDs */ ++enum wl_nan_cmds { ++ /* nan cfg /disc & dbg ioctls */ ++ WL_NAN_CMD_ENABLE = 1, ++ WL_NAN_CMD_ATTR = 2, ++ WL_NAN_CMD_NAN_JOIN = 3, ++ WL_NAN_CMD_LEAVE = 4, ++ WL_NAN_CMD_MERGE = 5, ++ WL_NAN_CMD_STATUS = 6, ++ WL_NAN_CMD_TSRESERVE = 7, ++ WL_NAN_CMD_TSSCHEDULE = 8, ++ WL_NAN_CMD_TSRELEASE = 9, ++ WL_NAN_CMD_OUI = 10, ++ WL_NAN_CMD_OOB_AF = 11, ++ ++ WL_NAN_CMD_COUNT = 15, ++ WL_NAN_CMD_CLEARCOUNT = 16, ++ ++ /* discovery engine commands */ ++ WL_NAN_CMD_PUBLISH = 20, ++ WL_NAN_CMD_SUBSCRIBE = 21, ++ WL_NAN_CMD_CANCEL_PUBLISH = 22, ++ WL_NAN_CMD_CANCEL_SUBSCRIBE = 23, ++ WL_NAN_CMD_TRANSMIT = 24, ++ WL_NAN_CMD_CONNECTION = 25, ++ WL_NAN_CMD_SHOW = 26, ++ WL_NAN_CMD_STOP = 27, /* stop nan for a given cluster ID */ ++ /* nan debug iovars & cmds */ ++ WL_NAN_CMD_SCAN_PARAMS = 46, ++ WL_NAN_CMD_SCAN = 47, ++ WL_NAN_CMD_SCAN_RESULTS = 48, ++ WL_NAN_CMD_EVENT_MASK = 49, ++ WL_NAN_CMD_EVENT_CHECK = 50, ++ WL_NAN_CMD_DUMP = 51, ++ WL_NAN_CMD_CLEAR = 52, ++ WL_NAN_CMD_RSSI = 53, ++ ++ WL_NAN_CMD_DEBUG = 60, ++ WL_NAN_CMD_TEST1 = 61, ++ WL_NAN_CMD_TEST2 = 62, ++ WL_NAN_CMD_TEST3 = 63, ++ WL_NAN_CMD_DISC_RESULTS = 64, ++ /* nan 2.0 data path commands */ ++ WL_NAN_CMD_DATAPATH = 65 ++}; ++ ++/* NAN DP interface commands */ ++enum wl_nan_dp_cmds { ++ /* nan 2.0 ioctls */ ++ WL_NAN_CMD_DP_CAP = 1000, ++ WL_NAN_CMD_DP_CONFIG = 1001, ++ WL_NAN_CMD_DP_CREATE = 1002, ++ WL_NAN_CMD_DP_AUTO_CONNECT = 1003, ++ WL_NAN_CMD_DP_DATA_REQ = 1004, ++ WL_NAN_CMD_DP_DATA_RESP = 1005, ++ WL_NAN_CMD_DP_SCHED_UPD = 1006, ++ WL_NAN_CMD_DP_END = 1007, ++ WL_NAN_CMD_DP_CONNECT = 1008, ++ WL_NAN_CMD_DP_STATUS = 1009 ++}; ++ ++/* TODO Should remove this fixed length */ ++#define WL_NAN_DATA_SVC_SPEC_INFO_LEN 32 /* arbitrary */ ++#define WL_NAN_DP_MAX_SVC_INFO 0xFF ++#define WL_NAN_DATA_NDP_INST_SUPPORT 16 ++ ++/* Nan flags */ ++#define WL_NAN_DP_FLAG_SVC_INFO (1 << 0) ++#define WL_NAN_DP_FLAG_CONFIRM (1 << 1) ++#define WL_NAN_DP_FLAG_EXPLICIT_CFM (1 << 2) ++#define WL_NAN_DP_FLAG_SECURITY (1 << 3) ++ ++/* NAN Datapath host status */ ++#define WL_NAN_DP_STATUS_ACCEPTED 1 ++#define WL_NAN_DP_STATUS_REJECTED 0 ++ ++/* to be done */ ++typedef struct wl_nan_dp_cap { ++ uint8 tbd; ++} wl_nan_dp_cap_t; ++ ++ ++/** The service hash (service id) is exactly this many bytes. */ ++#define WL_NAN_SVC_HASH_LEN 6 ++/** Number of hash functions per bloom filter */ ++#define WL_NAN_HASHES_PER_BLOOM 4 ++/* no. of max last disc results */ ++#define WL_NAN_MAX_DISC_RESULTS 3 ++ ++/* NAN security related defines */ ++/* NCS-SK related */ ++#define WL_NAN_NCS_SK_PMK_LEN 32 ++#define WL_NAN_NCS_SK_PMKID_LEN 16 ++ ++/* recent discovery results */ ++typedef struct wl_nan_disc_result_s ++{ ++ wl_nan_instance_id_t instance_id; /* instance id of pub/sub req */ ++ wl_nan_instance_id_t peer_instance_id; /* peer instance id of pub/sub req/resp */ ++ uint8 svc_hash[WL_NAN_SVC_HASH_LEN]; /* service descp string */ ++ struct ether_addr peer_mac; /* peer mac address */ ++} wl_nan_disc_result_t; ++ ++/* list of recent discovery results */ ++typedef struct wl_nan_disc_results_s ++{ ++ wl_nan_disc_result_t disc_result[WL_NAN_MAX_DISC_RESULTS]; ++} wl_nan_disc_results_list_t; ++ ++/* nan 1.0 events */ ++/* To be deprecated - will be replaced by event_disc_result */ ++typedef struct wl_nan_ev_disc_result { ++ wl_nan_instance_id_t pub_id; ++ wl_nan_instance_id_t sub_id; ++ struct ether_addr pub_mac; ++ uint8 opt_tlvs[0]; ++} wl_nan_ev_disc_result_t; ++ ++typedef struct wl_nan_event_disc_result { ++ wl_nan_instance_id_t pub_id; ++ wl_nan_instance_id_t sub_id; ++ struct ether_addr pub_mac; ++ int8 publish_rssi; /* publisher RSSI */ ++ uint8 attr_num; ++ uint16 attr_list_len; /* length of the all the attributes in the SDF */ ++ uint8 attr_list[0]; /* list of NAN attributes */ ++} wl_nan_event_disc_result_t; ++ ++typedef struct wl_nan_ev_p2p_avail { ++ struct ether_addr sender; ++ struct ether_addr p2p_dev_addr; ++ uint8 dev_role; ++ uint8 resolution; ++ uint8 repeat; ++ uint8 pad[3]; ++ chanspec_t chanspec; ++ uint32 avail_bmap; ++} wl_nan_ev_p2p_avail_t; ++ ++/* ++* discovery interface event structures * ++*/ ++ ++/* mandatory parameters for OOB action frame */ ++/* single-shot when bitmap and offset are set to 0; periodic otherwise */ ++typedef struct wl_nan_oob_af_params_s ++{ ++ /* bitmap for the 32 timeslots in 512TU dw interval */ ++ uint32 ts_map; ++ /* offset from start of dw, in us */ ++ uint32 tx_offset; ++ struct ether_addr bssid; ++ struct ether_addr dest; ++ uint32 pkt_lifetime; ++ uint16 payload_len; ++ uint8 payload[1]; ++} wl_nan_oob_af_params_t; ++ ++/* NAN Ranging */ ++ ++/* Bit defines for global flags */ ++#define WL_NAN_RANGING_ENABLE 1 /**< enable RTT */ ++#define WL_NAN_RANGING_RANGED 2 /**< Report to host if ranged as target */ ++typedef struct nan_ranging_config { ++ uint32 chanspec; /**< Ranging chanspec */ ++ uint16 timeslot; /**< NAN RTT start time slot 1-511 */ ++ uint16 duration; /**< NAN RTT duration in ms */ ++ struct ether_addr allow_mac; /**< peer initiated ranging: the allowed peer mac ++ * address, a unicast (for one peer) or ++ * a broadcast for all. Setting it to all zeros ++ * means responding to none,same as not setting ++ * the flag bit NAN_RANGING_RESPOND ++ */ ++ uint16 flags; ++} wl_nan_ranging_config_t; ++ ++/** list of peers for self initiated ranging */ ++/** Bit defines for per peer flags */ ++#define WL_NAN_RANGING_REPORT (1<<0) /**< Enable reporting range to target */ ++typedef struct nan_ranging_peer { ++ uint32 chanspec; /**< desired chanspec for this peer */ ++ uint32 abitmap; /**< available bitmap */ ++ struct ether_addr ea; /**< peer MAC address */ ++ uint8 frmcnt; /**< frame count */ ++ uint8 retrycnt; /**< retry count */ ++ uint16 flags; /**< per peer flags, report or not */ ++ uint16 PAD; ++} wl_nan_ranging_peer_t; ++typedef struct nan_ranging_list { ++ uint8 count; /**< number of MAC addresses */ ++ uint8 num_peers_done; /**< host set to 0, when read, shows number of peers ++ * completed, success or fail ++ */ ++ uint8 num_dws; /**< time period to do the ranging, specified in dws */ ++ uint8 reserve; /**< reserved field */ ++ wl_nan_ranging_peer_t rp[1]; /**< variable length array of peers */ ++} wl_nan_ranging_list_t; ++ ++/* ranging results, a list for self initiated ranging and one for peer initiated ranging */ ++/* There will be one structure for each peer */ ++#define WL_NAN_RANGING_STATUS_SUCCESS 1 ++#define WL_NAN_RANGING_STATUS_FAIL 2 ++#define WL_NAN_RANGING_STATUS_TIMEOUT 3 ++#define WL_NAN_RANGING_STATUS_ABORT 4 /**< with partial results if sounding count > 0 */ ++typedef struct nan_ranging_result { ++ uint8 status; /**< 1: Success, 2: Fail 3: Timeout 4: Aborted */ ++ uint8 sounding_count; /**< number of measurements completed (0 = failure) */ ++ struct ether_addr ea; /**< initiator MAC address */ ++ uint32 chanspec; /**< Chanspec where the ranging was done */ ++ uint32 timestamp; /**< 32bits of the TSF timestamp ranging was completed at */ ++ uint32 distance; /**< mean distance in meters expressed as Q4 number. ++ * Only valid when sounding_count > 0. Examples: ++ * 0x08 = 0.5m ++ * 0x10 = 1m ++ * 0x18 = 1.5m ++ * set to 0xffffffff to indicate invalid number ++ */ ++ int32 rtt_var; /**< standard deviation in 10th of ns of RTTs measured. ++ * Only valid when sounding_count > 0 ++ */ ++ struct ether_addr tgtea; /**< target MAC address */ ++ uint8 PAD[2]; ++} wl_nan_ranging_result_t; ++typedef struct nan_ranging_event_data { ++ uint8 mode; /**< 1: Result of host initiated ranging */ ++ /* 2: Result of peer initiated ranging */ ++ uint8 reserved; ++ uint8 success_count; /**< number of peers completed successfully */ ++ uint8 count; /**< number of peers in the list */ ++ wl_nan_ranging_result_t rr[1]; /**< variable array of ranging peers */ ++} wl_nan_ranging_event_data_t; ++ ++enum { ++ WL_NAN_STATS_RSSI = 1, ++ WL_NAN_STATS_DATA = 2, ++ WL_NAN_STATS_DP = 3, ++/* ++ * ***** ADD before this line **** ++ */ ++ WL_NAN_STATS_INVALID ++}; ++typedef struct wl_nan_dp_stats { ++ uint32 tbd; /* TBD */ ++} wl_nan_dp_stats_t; ++ ++typedef struct wl_nan_stats { ++ /* general */ ++ uint32 cnt_dw; /* DW slots */ ++ uint32 cnt_disc_bcn_sch; /* disc beacon slots */ ++ uint32 cnt_amr_exp; /* count of ambtt expiries resetting roles */ ++ uint32 cnt_bcn_upd; /* count of beacon template updates */ ++ uint32 cnt_bcn_tx; /* count of sync & disc bcn tx */ ++ uint32 cnt_bcn_rx; /* count of sync & disc bcn rx */ ++ uint32 cnt_sync_bcn_tx; /* count of sync bcn tx within DW */ ++ uint32 cnt_disc_bcn_tx; /* count of disc bcn tx */ ++ uint32 cnt_sdftx_bcmc; /* count of bcast/mcast sdf tx */ ++ uint32 cnt_sdftx_uc; /* count of unicast sdf tx */ ++ uint32 cnt_sdftx_fail; /* count of unicast sdf tx fails */ ++ uint32 cnt_sdf_rx; /* count of sdf rx */ ++ /* NAN roles */ ++ uint32 cnt_am; /* anchor master */ ++ uint32 cnt_master; /* master */ ++ uint32 cnt_nms; /* non master sync */ ++ uint32 cnt_nmns; /* non master non sync */ ++ /* TX */ ++ uint32 cnt_err_txtime; /* txtime in sync bcn frame not a multiple of dw intv */ ++ uint32 cnt_err_unsch_tx; /* tx while not in DW/ disc bcn slot */ ++ uint32 cnt_err_bcn_tx; /* beacon tx error */ ++ uint32 cnt_sync_bcn_tx_miss; /* no. of times time delta between 2 cosequetive ++ * sync beacons is more than expected ++ */ ++ /* MSCH */ ++ uint32 cnt_err_msch_reg; /* error is Dw/disc reg with msch */ ++ uint32 cnt_err_wrong_ch_cb; /* count of msch calbacks in wrong channel */ ++ uint32 cnt_dw_skip; /* count of DW rejected */ ++ uint32 cnt_disc_skip; /* count of disc bcn rejected */ ++ uint32 cnt_dw_start_early; /* msch cb not at registered time */ ++ uint32 cnt_dw_start_late; /* no. of delays in slot start */ ++ /* SCANS */ ++ uint32 cnt_mrg_scan; /* count of merge scans completed */ ++ uint32 cnt_err_ms_rej; /* number of merge scan failed */ ++ uint32 cnt_scan_results; /* no. of nan beacons scanned */ ++ uint32 cnt_join_scan_rej; /* no. of join scans rejected */ ++ uint32 cnt_nan_scan_abort; /* no. of join scans rejected */ ++ /* enable/disable */ ++ uint32 cnt_nan_enab; /* no. of times nan feature got enabled */ ++ uint32 cnt_nan_disab; /* no. of times nan feature got disabled */ ++ uint32 cnt_sync_bcn_rx; /* count of sync bcn rx within DW */ ++} wl_nan_stats_t; ++ ++#define WL_NAN_MAC_MAX_NAN_PEERS 6 ++#define WL_NAN_MAC_MAX_RSSI_DATA_PER_PEER 10 ++ ++typedef struct wl_nan_nbr_rssi { ++ uint8 rx_chan; /* channel number on which bcn rcvd */ ++ uint8 PAD[3]; ++ int32 rssi_raw; /* received rssi value */ ++ int32 rssi_avg; /* normalized rssi value */ ++} wl_nan_peer_rssi_t; ++ ++typedef struct wl_nan_peer_rssi_entry { ++ struct ether_addr mac; /* peer mac address */ ++ uint8 flags; /* TODO:rssi data order: latest first, oldest first etc */ ++ uint8 rssi_cnt; /* rssi data sample present */ ++ wl_nan_peer_rssi_t rssi[WL_NAN_MAC_MAX_RSSI_DATA_PER_PEER]; /* RSSI data frm peer */ ++} wl_nan_peer_rssi_entry_t; ++ ++#define WL_NAN_PEER_RSSI 0x1 ++#define WL_NAN_PEER_RSSI_LIST 0x2 ++ ++typedef struct wl_nan_nbr_rssi_data { ++ uint8 flags; /* this is a list or single rssi data */ ++ uint8 peer_cnt; /* number of peers */ ++ uint16 pad; /* padding */ ++ wl_nan_peer_rssi_entry_t peers[1]; /* peers data list */ ++} wl_nan_peer_rssi_data_t; ++ ++/* WL_NAN_CMD_DBG_DUMP, GET Resp */ ++typedef struct wl_nan_dbg_dump_rsp { ++ wl_nan_dbg_dump_type_t dump_type; /* dump data type */ ++ uint8 pad[3]; ++ union { ++ wl_nan_peer_rssi_data_t peer_rssi; ++ wl_nan_stats_t nan_stats; ++ } u; ++} wl_nan_dbg_dump_rsp_t; ++ ++enum nan_termination_status { ++ NAN_TERM_REASON_INVALID = 1, ++ NAN_TERM_REASON_TIMEOUT = 2, ++ NAN_TERM_REASON_USER_REQ = 3, ++ NAN_TERM_REASON_FAILURE = 4, ++ NAN_TERM_REASON_COUNT_REACHED = 5, ++ NAN_TERM_REASON_DE_SHUTDOWN = 6, ++ NAN_TERM_REASON_DISABLE_IN_PROGRESS = 7 ++}; ++ ++/* nan2 data iovar */ ++/* nan2 qos */ ++typedef struct wl_nan_dp_qos ++{ ++ uint8 tid; ++ uint8 pad; ++ uint16 pkt_size; ++ uint16 mean_rate; ++ uint16 svc_interval; ++} wl_nan_dp_qos_t; ++/* ndp config */ ++typedef struct wl_nan_ndp_config ++{ ++ uint8 ndp_id; ++ uint8 pub_id; ++ struct ether_addr pub_addr; ++ struct ether_addr data_addr; /* configure local data addr */ ++ struct ether_addr init_data_addr; /* initiator data addr */ ++ uint8 svc_spec_info[WL_NAN_DATA_SVC_SPEC_INFO_LEN]; ++ wl_nan_dp_qos_t qos; ++ uint16 avail_len; ++ uint8 pad[3]; ++ uint8 data[1]; ++} wl_nan_ndp_config_t; ++ ++/* nan2 device capabilities */ ++typedef struct wl_nan_ndp_oper_cfg { ++ uint8 awake_dw_2g; ++ uint8 awake_dw_5g; ++ uint8 bands_supported; ++ uint8 op_mode; ++} wl_nan_ndp_oper_cfg_t; ++ ++typedef uint8 wl_nan_ndp_ndpid_t; ++typedef uint8 wl_nan_ndp_conn_t; ++ ++typedef struct wl_nan_dp_req { ++ uint8 type; /* 0- unicast 1 - multicast */ ++ uint8 pub_id; /* Publisher ID */ ++ uint16 flags; ++ struct ether_addr peer_mac; /* Peer's NMI addr */ ++ struct ether_addr mcast_mac; /* Multicast addr */ ++ wl_nan_dp_qos_t qos; ++ uint8 tlv_params[]; /* xtlv parameters for command */ ++} wl_nan_dp_req_t; ++ ++/* TODO Need to replace ndp_id with lndp_id */ ++/* Return structure to data req IOVAR */ ++typedef struct wl_nan_dp_req_ret { ++ struct ether_addr indi; /* Initiators data mac addr */ ++ uint8 ndp_id; /* Initiators ndpid */ ++ uint8 pad; ++} wl_nan_dp_req_ret_t; ++ ++typedef struct wl_nan_dp_resp { ++ uint8 type; /* 0- unicast 1 - multicast */ ++ uint8 status; /* Accepted or Rejected */ ++ uint8 reason_code; ++ /* Local NDP ID for unicast, mc_id for multicast, 0 for implicit NMSG */ ++ uint8 ndp_id; ++ wl_nan_dp_qos_t qos; ++ /* Initiator data address for unicast or multicast address for multicast */ ++ struct ether_addr mac_addr; ++ uint16 flags; ++ uint8 tlv_params[]; /* xtlv parameters for command */ ++} wl_nan_dp_resp_t; ++ ++/* Return structure to data resp IOVAR */ ++typedef struct wl_nan_dp_resp_ret { ++ uint8 nmsgid; /* NMSG ID or for multicast else 0 */ ++ uint8 pad[3]; ++} wl_nan_dp_resp_ret_t; ++ ++typedef struct wl_nan_dp_conf { ++ uint8 lndp_id; ++ uint8 status; /* Accepted or Rejected */ ++ uint8 pad[2]; ++} wl_nan_dp_conf_t; ++ ++typedef struct wl_nan_dp_end ++{ ++ uint8 lndp_id; ++ uint8 status; ++ uint8 pad[2]; ++} wl_nan_dp_end_t; ++ ++typedef struct wl_nan_dp_schedupd { ++ uint8 type; /* 0: unicast, 1: multicast */ ++ uint8 flags; ++ struct ether_addr addr; /* peer NMI or multicast addr */ ++ wl_nan_dp_qos_t qos; ++ uint8 map_id; ++ uint8 pad[3]; ++} wl_nan_dp_schedupd_t; ++ ++/* set: update with notification, unset: NDL setup handshake */ ++#define WL_NAN_DP_SCHEDUPD_NOTIF (1 << 0) ++ ++/* list ndp ids */ ++typedef struct wl_nan_ndp_id_list { ++ uint16 ndp_count; ++ uint8 lndp_id[]; ++} wl_nan_ndp_id_list_t; ++ ++/* nan2 status */ ++typedef struct ndp_session { ++ uint8 lndp_id; ++ uint8 state; ++ uint8 pub_id; ++ uint8 pad; ++} ndp_session_t; ++ ++typedef struct wl_nan_ndp_status { ++ struct ether_addr peer_nmi; ++ struct ether_addr peer_ndi; ++ ndp_session_t session; ++ uint8 pad; ++} wl_nan_ndp_status_t; ++ ++/* events */ ++#define NAN_DP_SESSION_UNICAST 0 ++#define NAN_DP_SESSION_MULTICAST 1 ++#define NAN_DP_SECURITY_NONE 0 ++#define NAN_DP_SECURITY_CSID 1 ++#define NAN_DP_SECURITY_MK 2 ++#define WL_NAN_DATA_NMSGID_LEN 8 /* 8 bytes as per nan spec */ ++ ++/* Common event structure for Nan Datapath ++ * Used for sending NDP Indication, Response, Confirmation, Securty Install and Establish events ++ */ ++typedef struct wl_nan_ev_datapath_cmn { ++ uint8 type; ++ /* ndp_id is valid only if type is unicast */ ++ uint8 ndp_id; ++ uint8 pub_id; ++ uint8 security; ++ /* Following two fields are valid only if type is unicast */ ++ struct ether_addr initiator_ndi; ++ struct ether_addr responder_ndi; ++ struct ether_addr peer_nmi; ++ uint8 status; ++ uint8 role; ++ /* Following two fields are valid only if type is multicast */ ++ uint8 nmsg_id[WL_NAN_DATA_NMSGID_LEN]; ++ uint8 mc_id; ++ uint8 pad[1]; ++ uint16 opt_tlv_len; ++ uint8 opt_tlvs[]; ++} wl_nan_ev_datapath_cmn_t; ++ ++typedef struct wl_nan_ev_datapath_end { ++ uint8 ndp_id; ++ uint8 status; ++ uint8 pad[2]; ++ struct ether_addr peer_nmi; ++ struct ether_addr peer_ndi; ++} wl_nan_ev_datapath_end_t; ++ ++/* NAN2.0 Ranging definitions */ ++ ++/* result indication bit map */ ++#define NAN_RANGE_INDICATION_CONT (1<<0) ++#define NAN_RANGE_INDICATION_INGRESS (1<<1) ++#define NAN_RANGE_INIDICATION_EGRESS (1<<2) ++ ++/* responder flags */ ++#define NAN_RANGE_FLAG_AUTO_ACCEPT (1 << 0) ++#define NAN_RANGE_FLAG_RESULT_REQUIRED (1 << 1) ++ ++typedef struct wl_nan_range_req { ++ struct ether_addr peer; ++ uint8 publisher_id; ++ uint8 indication; /* bit map for result event */ ++ uint32 resolution; /* default millimeters */ ++ uint32 ingress; /* ingress limit in mm */ ++ uint32 egress; /* egress limit in mm */ ++ uint32 interval; /* max interval(in TU) b/w two ranging measurements */ ++} wl_nan_range_req_t; ++ ++#define NAN_RNG_REQ_IOV_LEN 24 ++ ++typedef uint8 wl_nan_range_id; ++ ++typedef struct wl_nan_range_resp { ++ wl_nan_range_id range_id; ++ uint8 flags; /* auto response, range result required */ ++ uint8 status; /* accept, reject */ ++ uint8 indication; /* bit map for result event */ ++ uint32 resolution; /* default millimeters */ ++ uint32 ingress; /* ingress limit in mm */ ++ uint32 egress; /* egress limit in mm */ ++ uint32 interval; /* max interval(in TU) b/w two ranging measurements */ ++} wl_nan_range_resp_t; ++ ++#define NAN_RNG_RESP_IOV_LEN 20 ++ ++#define NAN_RNG_MAX_IOV_LEN 255 ++ ++typedef struct wl_nan_ev_rng_req_ind { ++ struct ether_addr peer_m_addr; ++ uint8 rng_id; ++ /* ftm parameters */ ++ uint8 max_burst_dur; ++ uint8 min_ftm_delta; ++ uint8 max_num_ftm; ++ uint8 ftm_format_bw; ++ /* location info availability bit map */ ++ uint8 lc_info_avail; ++ /* Last movement indication */ ++ uint16 last_movement; ++ uint8 pad[2]; ++} wl_nan_ev_rng_req_ind_t; ++ ++#define NAN_RNG_REQ_IND_SIZE 14 ++ ++typedef struct wl_nan_ev_rng_rpt_ind { ++ uint32 dist_mm; /* in millimeter */ ++ struct ether_addr peer_m_addr; ++ uint8 indication; /* indication definitions mentioned above */ ++ uint8 pad; ++} wl_nan_ev_rng_rpt_ind_t; ++ ++#define NAN_RNG_RPT_IND_SIZE 11 ++ ++typedef struct wl_nan_ev_rng_term_ind { ++ struct ether_addr peer_m_addr; ++ uint8 reason_code; ++ uint8 pad; ++} wl_nan_ev_rng_term_ind_t; ++ ++#define NAN_RNG_TERM_IND_SIZE 7 ++ ++ ++/* ********************* end of NAN section ******************************** */ ++/* endif WL_NAN */ ++ ++#define P2P_NAN_IOC_BUFSZ 512 /* some sufficient ioc buff size */ ++#define WL_P2P_NAN_IOCTL_VERSION 0x1 ++ ++/* container for p2p nan iovtls & events */ ++typedef struct wl_p2p_nan_ioc { ++ uint16 version; /* interface command or event version */ ++ uint16 id; /* p2p nan ioctl cmd ID */ ++ uint16 len; /* total length of data[] */ ++ uint16 pad; /* padding */ ++ uint8 data []; /* var len payload of bcm_xtlv_t type */ ++} wl_p2p_nan_ioc_t; ++ ++/* p2p nan cmd IDs */ ++enum wl_p2p_nan_cmds { ++ /* p2p nan cfg ioctls */ ++ WL_P2P_NAN_CMD_ENABLE = 1, ++ WL_P2P_NAN_CMD_CONFIG = 2, ++ WL_P2P_NAN_CMD_DEL_CONFIG = 3, ++ WL_P2P_NAN_CMD_GET_INSTS = 4 ++}; ++ ++#define WL_P2P_NAN_CONFIG_VERSION 1 ++ ++#define WL_P2P_NAN_DEVICE_P2P 0x0 ++#define WL_P2P_NAN_DEVICE_GO 0x1 ++#define WL_P2P_NAN_DEVICE_GC 0x2 ++#define WL_P2P_NAN_DEVICE_INVAL 0xFF ++ ++/* NAN P2P operation */ ++typedef struct p2p_nan_config { ++ uint16 version; /* wl_p2p_nan_config_t structure version */ ++ uint16 len; /* total length including version and variable IE */ ++ uint32 flags; /* 0x1 to NEW, 0x2 to ADD, 0x4 to DEL */ ++ uint8 inst_id; /* publisher/subscriber id */ ++ uint8 inst_type; /* publisher/subscriber */ ++ uint8 dev_role; /* P2P device role: 'P2P','GO' or 'GC' */ ++ uint8 pad1; /* padding */ ++ uint8 resolution; /* Availability bitmap resolution */ ++ uint8 repeat; /* Whether Availabilty repeat across DW */ ++ uint16 ie_len; /* variable ie len */ ++ struct ether_addr dev_mac; /* P2P device addres */ ++ uint16 pad2; /* Padding */ ++ uint32 avail_bmap; /* availability interval bitmap */ ++ uint32 chanspec; /* Chanspec */ ++ uint8 ie[]; /* hex ie data */ ++} wl_p2p_nan_config_t; ++ ++#define WL_P2P_NAN_SERVICE_LIST_VERSION 1 ++typedef enum wl_nan_service_type { ++ WL_NAN_SVC_INST_PUBLISHER = 1, ++ WL_NAN_SVC_INST_SUBSCRIBER = 2 ++} wl_nan_service_type_t; ++ ++#define WL_P2P_NAN_CONFIG_NEW 0x1 ++#define WL_P2P_NAN_CONFIG_ADD 0x2 ++#define WL_P2P_NAN_CONFIG_DEL 0x4 ++ ++typedef struct wl_nan_svc_inst { ++ uint8 inst_id; /* publisher/subscriber id */ ++ uint8 inst_type; /* publisher/subscriber */ ++} wl_nan_svc_inst_t; ++ ++typedef struct wl_nan_svc_inst_list { ++ uint16 version; /* this structure version */ ++ uint16 len; /* total length including version and variable svc list */ ++ uint16 count; /* service instance count */ ++ uint16 pad; /* padding */ ++ wl_nan_svc_inst_t svc[1]; /* service instance list */ ++} wl_nan_svc_inst_list_t; ++ ++#define NAN_POST_DISC_P2P_DATA_VER 1 ++/* This structure will be used send peer p2p data with ++ * NAN discovery result ++ */ ++typedef struct nan_post_disc_p2p_data { ++ uint8 ver; /* this structure version */ ++ uint8 dev_role; /* P2P Device role */ ++ uint8 resolution; /* Availability bitmap resolution */ ++ uint8 repeat; /* Whether Availabilty repeat across DW */ ++ struct ether_addr dev_mac; /* P2P device addres */ ++ uint16 pad1; /* Padding */ ++ uint32 chanspec; /* Chanspec */ ++ uint32 avl_bmp; /* availability interval bitmap */ ++} nan_post_disc_p2p_data_t; ++ ++/* timeslot etc for NAN */ ++enum { ++ WL_TMU_TU = 0, ++ WL_TMU_SEC = 1, ++ WL_TMU_MILLI_SEC = 2, ++ WL_TMU_MICRO_SEC = 3, ++ WL_TMU_NANO_SEC = 4, ++ WL_TMU_PICO_SEC = 5 ++}; ++typedef int16 wl_tmu_t; ++ ++typedef struct { ++ uint32 intvl; /* time interval */ ++ wl_tmu_t tmu; /* time unit */ ++ uint8 pad[2]; /* padding */ ++} wl_time_interval_t; ++ ++/* availabiloty slot flags */ ++enum { ++ WL_AVAIL_SLOT_NONE = 0x0000, ++ WL_AVAIL_SLOT_COM = 0x0001, /* committed */ ++ WL_AVAIL_SLOT_POT = 0x0002, /* potential */ ++ WL_AVAIL_SLOT_PROP = 0x0004, /* proposed - note: not configurable */ ++ WL_AVAIL_SLOT_PAGED = 0x0008 /* P-NDL */ ++ /* 0x0030 - resrved for NDC index */ ++ /* 0x00c0 - resrved for usage preference */ ++}; ++typedef int16 wl_avail_slot_flags_t; ++ ++#define WL_AVAIL_SLOT_NDC_MASK 0x0030 /* up to 4 NDCs */ ++#define WL_AVAIL_SLOT_NDC_SHIFT 4 ++#define WL_AVAIL_SLOT_NDC(_flags) (((_flags) & WL_AVAIL_SLOT_NDC_MASK) \ ++ >> WL_AVAIL_SLOT_NDC_SHIFT) ++#define WL_AVAIL_SLOT_SET_NDC(_flags, _ndc_idx) (((_flags) & ~WL_AVAIL_SLOT_NDC_MASK) |\ ++ ((_ndc_idx) << WL_AVAIL_SLOT_NDC_SHIFT)) ++ ++#define WL_AVAIL_SLOT_UPREF_MASK 0x00c0 /* up to 4 usage preferences */ ++#define WL_AVAIL_SLOT_UPREF_SHIFT 6 ++#define WL_AVAIL_SLOT_UPREF(_flags) (((_flags) & WL_AVAIL_SLOT_UPREF_MASK) \ ++ >> WL_AVAIL_SLOT_UPREF_SHIFT) ++#define WL_AVAIL_SLOT_SET_UPREF(_flags, _pref) (((_flags) & ~WL_AVAIL_SLOT_UPREF_MASK) |\ ++ ((_pref) << WL_AVAIL_SLOT_UPREF_SHIFT)) ++ ++typedef struct wl_avail_slot { ++ wl_avail_slot_flags_t flags; ++ uint16 PAD; ++ wl_time_interval_t start; /* from time ref */ ++ wl_time_interval_t duration; /* from start */ ++ uint32 chanspec; /* channel spec */ ++} wl_avail_slot_t; ++ ++/* time reference */ ++enum { ++ WL_TIME_REF_NONE = 0, ++ WL_TIME_REF_DEV_TSF = 1, ++ WL_TIME_REF_NAN_DW = 2, ++ WL_TIME_REF_TBTT = 3, ++ WL_TIME_REF_NAN_DW0 = 4 ++}; ++typedef int16 wl_time_ref_t; ++ ++enum { ++ WL_AVAIL_NONE = 0x0000, ++ WL_AVAIL_LOCAL = 0x0001, ++ WL_AVAIL_PEER = 0x0002, ++ WL_AVAIL_NDC = 0x0003, ++ WL_AVAIL_IMMUTABLE = 0x0004, ++ WL_AVAIL_RESPONSE = 0x0005, ++ WL_AVAIL_COUNTER = 0x0006, ++ WL_AVAIL_RANGING = 0x0007, ++ WL_AVAIL_TYPE_MAX = WL_AVAIL_RANGING /* New ones before and update */ ++}; ++#define WL_AVAIL_TYPE_MASK 0x000F ++#define WL_AVAIL_FLAG_RAW_MODE 0x8000 ++typedef int16 wl_avail_flags_t; ++ ++/* availability entry flags */ ++enum { ++ WL_AVAIL_ENTRY_NONE = 0x0000, ++ WL_AVAIL_ENTRY_COM = 0x0001, /* committed */ ++ WL_AVAIL_ENTRY_POT = 0x0002, /* potential */ ++ WL_AVAIL_ENTRY_COND = 0x0004, /* conditional */ ++ WL_AVAIL_ENTRY_PAGED = 0x0008, /* P-NDL */ ++ WL_AVAIL_ENTRY_USAGE = 0x0030, /* usage preference */ ++ WL_AVAIL_ENTRY_BIT_DUR = 0x00c0, /* bit duration */ ++ WL_AVAIL_ENTRY_BAND_PRESENT = 0x0100, /* band present */ ++ WL_AVAIL_ENTRY_CHAN_PRESENT = 0x0200, /* channel information present */ ++ WL_AVAIL_ENTRY_CHAN_ENTRY_PRESENT = 0x0400, /* channel entry (opclass+bitmap) */ ++}; ++ ++/* bit duration */ ++enum { ++ WL_AVAIL_BIT_DUR_16 = 0, /* 16TU */ ++ WL_AVAIL_BIT_DUR_32 = 1, /* 32TU */ ++ WL_AVAIL_BIT_DUR_64 = 2, /* 64TU */ ++ WL_AVAIL_BIT_DUR_128 = 3, /* 128TU */ ++}; ++ ++/* period */ ++enum { ++ WL_AVAIL_PERIOD_0 = 0, /* 0TU */ ++ WL_AVAIL_PERIOD_128 = 1, /* 128TU */ ++ WL_AVAIL_PERIOD_256 = 2, /* 256TU */ ++ WL_AVAIL_PERIOD_512 = 3, /* 512TU */ ++ WL_AVAIL_PERIOD_1024 = 4, /* 1024TU */ ++ WL_AVAIL_PERIOD_2048 = 5, /* 2048TU */ ++ WL_AVAIL_PERIOD_4096 = 6, /* 4096TU */ ++ WL_AVAIL_PERIOD_8192 = 7, /* 8192TU */ ++}; ++ ++/* band */ ++enum { ++ WL_AVAIL_BAND_NONE = 0, /* reserved */ ++ WL_AVAIL_BAND_SUB1G = 1, /* sub-1 GHz */ ++ WL_AVAIL_BAND_2G = 2, /* 2.4 GHz */ ++ WL_AVAIL_BAND_3G = 3, /* reserved (for 3.6 GHz) */ ++ WL_AVAIL_BAND_5G = 4, /* 4.9 and 5 GHz */ ++ WL_AVAIL_BAND_60G = 5, /* reserved (for 60 GHz) */ ++}; ++ ++#define WL_AVAIL_ENTRY_TYPE_MASK 0x0F ++#define WL_AVAIL_ENTRY_USAGE_MASK 0x0030 /* up to 4 usage preferences */ ++#define WL_AVAIL_ENTRY_USAGE_SHIFT 4 ++#define WL_AVAIL_ENTRY_USAGE_VAL(_flags) (((_flags) & WL_AVAIL_ENTRY_USAGE_MASK) \ ++ >> WL_AVAIL_ENTRY_USAGE_SHIFT) ++ ++#define WL_AVAIL_ENTRY_BIT_DUR_MASK 0x00c0 /* 0:16TU, 1:32TU, 2:64TU, 3:128TU */ ++#define WL_AVAIL_ENTRY_BIT_DUR_SHIFT 6 ++#define WL_AVAIL_ENTRY_BIT_DUR_VAL(_flags) (((_flags) & WL_AVAIL_ENTRY_BIT_DUR_MASK) \ ++ >> WL_AVAIL_ENTRY_BIT_DUR_SHIFT) ++ ++#define WL_AVAIL_ENTRY_BAND_MASK 0x0100 /* 0=band not present, 1=present */ ++#define WL_AVAIL_ENTRY_BAND_SHIFT 8 ++ ++#define WL_AVAIL_ENTRY_CHAN_MASK 0x0200 /* 0=channel info not present, 1=present */ ++#define WL_AVAIL_ENTRY_CHAN_SHIFT 9 ++ ++#define WL_AVAIL_ENTRY_CHAN_ENTRY_MASK 0x0400 /* 0=chanspec, 1=hex channel entry */ ++#define WL_AVAIL_ENTRY_CHAN_ENTRY_SHIFT 10 ++ ++#define WL_AVAIL_ENTRY_OPCLASS_MASK 0xFF ++#define WL_AVAIL_ENTRY_CHAN_BITMAP_MASK 0xFF00 ++#define WL_AVAIL_ENTRY_CHAN_BITMAP_SHIFT 8 ++#define WL_AVAIL_ENTRY_CHAN_BITMAP_VAL(_info) (((_info) & WL_AVAIL_ENTRY_CHAN_BITMAP_MASK) \ ++ >> WL_AVAIL_ENTRY_CHAN_BITMAP_SHIFT) ++ ++/* Used for raw channel entry field input */ ++#define MAX_CHAN_ENTRY_LEN 6 ++ ++typedef struct wl_avail_entry { ++ uint16 length; /* total length */ ++ uint16 start_offset; /* in TUs, multiply by 16 for total offset */ ++ union { ++ uint32 channel_info; /* either chanspec or hex channel entry (opclass + ++ * bitmap per NAN spec), as indicated by setting ++ * WL_AVAIL_ENTRY_HEX_CHAN_ENTRY flag ++ */ ++ uint32 band; /* defined by WL_BAND enum, 2=2.4GHz, 4=5GHz */ ++ uint8 channel_entry[MAX_CHAN_ENTRY_LEN]; ++ } u; /* band or channel value, 0=all band/channels */ ++ uint8 pad[2]; ++ uint8 period; /* in TUs, defined by WL_AVAIL_PERIOD enum ++ * 1:128, 2:256, 3:512, 4:1024, 5:2048, 6:4096, ++ * 7:8192 ++ */ ++ uint8 bitmap_len; ++ uint16 flags; /* defined by avail entry flags enum: ++ * type, usage pref, bit duration, band, channel ++ */ ++ uint8 bitmap[]; /* time bitmap */ ++} wl_avail_entry_t; ++ ++typedef struct wl_avail { ++ uint16 length; /* total length */ ++ uint16 flags; /* defined by WL_AVAIL enum ++ * 1=local, 2=peer, 3=ndc, 4=immutable, ++ * 5=response, 6=counter ++ */ ++ uint8 id; /* id used for multiple maps/avail */ ++ uint8 pad[3]; ++ struct ether_addr addr; /* peer mac address or ndc id */ ++ uint8 num_entries; ++ uint8 entry_offset; ++ /* add additional fields above this line */ ++ uint8 entry[]; ++} wl_avail_t; ++ ++#define WL_AVAIL_MIN_LEN(n) ((n) ? OFFSETOF(wl_avail_t, entry) + \ ++ ((n) * OFFSETOF(wl_avail_entry_t, bitmap)) : 0) ++ ++/* unaligned schedule (window) */ ++typedef struct wl_avail_ulw { ++ uint8 id; /* schedule ID */ ++ uint8 overwrite; /* bit 0: overwrite all ++ * 1-4: map ID if overwrite all is 0 ++ */ ++ uint16 flags; ++ uint32 start; /* start time of first ULW, in us */ ++ uint32 dur; /* duration of ULW, in us */ ++ uint32 period; /* time between consecutive ULWs, in us */ ++ union { ++ uint32 chanspec; ++ uint32 band; ++ uint8 chan_entry[MAX_CHAN_ENTRY_LEN]; ++ uint8 pad[8]; ++ } u; ++ uint8 cntdwn; /* remaining ULWs before schedule ends */ ++ uint8 pad[3]; ++} wl_avail_ulw_t; ++ ++/* unset: NAN is not available during ULW, set: NAN is avail depending on ctrl flags */ ++#define WL_NAN_ULW_CTRL_PRESENT (1 << 0) ++/* unset: band, set: channel */ ++#define WL_NAN_ULW_CTRL_TYPE (1 << 1) ++/* set: NAN is availabile on specified band/channel */ ++#define WL_NAN_ULW_CTRL_AVAIL (1 << 2) ++/* channel is provided in raw attribute format */ ++#define WL_NAN_ULW_CTRL_RAW_CHAN (1 << 3) ++ ++/* nan wfa testmode operations */ ++enum { ++ WL_NAN_WFA_TM_IGNORE_TERMINATE_NAF = 0x00000001, ++ WL_NAN_WFA_TM_IGNORE_RX_DATA_OUTSIDE_CRB = 0x00000002, ++ WL_NAN_WFA_TM_ALLOW_TX_DATA_OUTSIDE_CRB = 0x00000004, ++ WL_NAN_WFA_TM_ENFORCE_NDL_COUNTER = 0x00000008, ++ WL_NAN_WFA_TM_BYPASS_NDL_PROPOSAL_VALIDATION = 0x00000010, ++ /* allow data(pings) tx while ndp sec negotiation */ ++ WL_NAN_WFA_TM_SEC_SEND_PINGS_BYPASS_NDP_SM = 0x00000020, ++ /* generate and insert incorrect mic */ ++ WL_NAN_WFA_TM_SEC_INCORRECT_MIC = 0x00000040, ++ /* send m4 reject deliberately */ ++ WL_NAN_WFA_TM_SEC_REJECT_STATUS4M4 = 0x00000080, ++ /* send mgmt frame (for eg. ndp terminate) in clear txt (bypass security) */ ++ WL_NAN_WFA_TM_SEC_SEND_MGMT_CLEAR = 0x00000100, ++ WL_NAN_WFA_TM_FLAG_MASK = 0x000001ff /* add above & update mask */ ++}; ++typedef uint32 wl_nan_wfa_testmode_t; ++ ++#define RSSI_THRESHOLD_SIZE 16 ++#define MAX_IMP_RESP_SIZE 256 ++ ++typedef struct wl_proxd_rssi_bias { ++ int32 version; /**< version */ ++ int32 threshold[RSSI_THRESHOLD_SIZE]; /**< threshold */ ++ int32 peak_offset; /**< peak offset */ ++ int32 bias; /**< rssi bias */ ++ int32 gd_delta; /**< GD - GD_ADJ */ ++ int32 imp_resp[MAX_IMP_RESP_SIZE]; /**< (Hi*Hi)+(Hr*Hr) */ ++} wl_proxd_rssi_bias_t; ++ ++typedef struct wl_proxd_rssi_bias_avg { ++ int32 avg_threshold[RSSI_THRESHOLD_SIZE]; /**< avg threshold */ ++ int32 avg_peak_offset; /**< avg peak offset */ ++ int32 avg_rssi; /**< avg rssi */ ++ int32 avg_bias; /**< avg bias */ ++} wl_proxd_rssi_bias_avg_t; ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_info { ++ uint16 type; /**< type: 0 channel table, 1 channel smoothing table, 2 and 3 seq */ ++ uint16 index; /**< The current frame index, from 1 to total_frames. */ ++ uint16 tof_cmd; /**< M_TOF_CMD */ ++ uint16 tof_rsp; /**< M_TOF_RSP */ ++ uint16 tof_avb_rxl; /**< M_TOF_AVB_RX_L */ ++ uint16 tof_avb_rxh; /**< M_TOF_AVB_RX_H */ ++ uint16 tof_avb_txl; /**< M_TOF_AVB_TX_L */ ++ uint16 tof_avb_txh; /**< M_TOF_AVB_TX_H */ ++ uint16 tof_id; /**< M_TOF_ID */ ++ uint8 tof_frame_type; ++ uint8 tof_frame_bw; ++ int8 tof_rssi; ++ int32 tof_cfo; ++ int32 gd_adj_ns; /**< gound delay */ ++ int32 gd_h_adj_ns; /**< group delay + threshold crossing */ ++ int16 nfft; /**< number of samples stored in H */ ++ uint8 num_max_cores; ++ ++} BWL_POST_PACKED_STRUCT wl_proxd_collect_info_t; ++#include ++ ++#define K_TOF_COLLECT_H_PAD 1 ++#define K_TOF_COLLECT_SC_20MHZ (64) ++/* Maximum possible size of sample capture */ ++#define K_TOF_COLLECT_SC_80MHZ (2*K_TOF_COLLECT_SC_20MHZ) ++/* Maximum possible size of channel dump */ ++#define K_TOF_COLLECT_CHAN_SIZE (2*K_TOF_COLLECT_SC_80MHZ) ++ ++/* ++A few extra samples are required to estimate frequency offset ++Right now 16 samples are being used. Can be changed in future. ++*/ ++#define K_TOF_COLLECT_SAMP_SIZE_20MHZ (2*(K_TOF_COLLECT_SC_20MHZ)+16+K_TOF_COLLECT_H_PAD) ++#define K_TOF_COLLECT_RAW_SAMP_SIZE_20MHZ (2*K_TOF_COLLECT_SAMP_SIZE_20MHZ) ++#define K_TOF_COLLECT_H_SIZE_20MHZ (K_TOF_COLLECT_SAMP_SIZE_20MHZ) ++#define K_TOF_COLLECT_HRAW_SIZE_20MHZ (K_TOF_COLLECT_RAW_SAMP_SIZE_20MHZ) ++ ++#define K_TOF_COLLECT_SAMP_SIZE_80MHZ (2*(K_TOF_COLLECT_SC_80MHZ)+16+K_TOF_COLLECT_H_PAD) ++#define K_TOF_COLLECT_RAW_SAMP_SIZE_80MHZ (2*K_TOF_COLLECT_SAMP_SIZE_80MHZ) ++#define K_TOF_COLLECT_H_SIZE_80MHZ (K_TOF_COLLECT_SAMP_SIZE_80MHZ) ++#define K_TOF_COLLECT_HRAW_SIZE_80MHZ (K_TOF_COLLECT_RAW_SAMP_SIZE_80MHZ) ++ ++#define WL_PROXD_COLLECT_DATA_VERSION_1 1 ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_data_v1 { ++ wl_proxd_collect_info_t info; ++ uint8 ri_rr[FTM_TPK_RI_RR_LEN]; ++ /**< raw data read from phy used to adjust timestamps */ ++ uint32 H[K_TOF_COLLECT_H_SIZE_20MHZ]; ++} BWL_POST_PACKED_STRUCT wl_proxd_collect_data_t_v1; ++#include ++ ++#define WL_PROXD_COLLECT_DATA_VERSION_2 2 ++typedef struct wl_proxd_collect_data_v2 { ++ uint16 version; ++ uint16 len; ++ wl_proxd_collect_info_t info; ++ uint8 ri_rr[FTM_TPK_RI_RR_LEN]; ++ uint8 pad[3]; /* should be based on FTM_TPK_RI_RR_LEN */ ++ /**< raw data read from phy used to adjust timestamps */ ++ uint32 H[K_TOF_COLLECT_H_SIZE_20MHZ]; ++ uint32 chan[4 * K_TOF_COLLECT_CHAN_SIZE]; ++} wl_proxd_collect_data_t_v2; ++#define WL_PROXD_COLLECT_DATA_VERSION_MAX WL_PROXD_COLLECT_DATA_VERSION_2 ++ ++typedef struct wl_proxd_debug_data { ++ uint8 count; /**< number of packets */ ++ uint8 stage; /**< state machone stage */ ++ uint8 received; /**< received or txed */ ++ uint8 paket_type; /**< packet type */ ++ uint8 category; /**< category field */ ++ uint8 action; /**< action field */ ++ uint8 token; /**< token number */ ++ uint8 follow_token; /**< following token number */ ++ uint16 index; /**< index of the packet */ ++ uint16 tof_cmd; /**< M_TOF_CMD */ ++ uint16 tof_rsp; /**< M_TOF_RSP */ ++ uint16 tof_avb_rxl; /**< M_TOF_AVB_RX_L */ ++ uint16 tof_avb_rxh; /**< M_TOF_AVB_RX_H */ ++ uint16 tof_avb_txl; /**< M_TOF_AVB_TX_L */ ++ uint16 tof_avb_txh; /**< M_TOF_AVB_TX_H */ ++ uint16 tof_id; /**< M_TOF_ID */ ++ uint16 tof_status0; /**< M_TOF_STATUS_0 */ ++ uint16 tof_status2; /**< M_TOF_STATUS_2 */ ++ uint16 tof_chsm0; /**< M_TOF_CHNSM_0 */ ++ uint16 tof_phyctl0; /**< M_TOF_PHYCTL0 */ ++ uint16 tof_phyctl1; /**< M_TOF_PHYCTL1 */ ++ uint16 tof_phyctl2; /**< M_TOF_PHYCTL2 */ ++ uint16 tof_lsig; /**< M_TOF_LSIG */ ++ uint16 tof_vhta0; /**< M_TOF_VHTA0 */ ++ uint16 tof_vhta1; /**< M_TOF_VHTA1 */ ++ uint16 tof_vhta2; /**< M_TOF_VHTA2 */ ++ uint16 tof_vhtb0; /**< M_TOF_VHTB0 */ ++ uint16 tof_vhtb1; /**< M_TOF_VHTB1 */ ++ uint16 tof_apmductl; /**< M_TOF_AMPDU_CTL */ ++ uint16 tof_apmdudlim; /**< M_TOF_AMPDU_DLIM */ ++ uint16 tof_apmdulen; /**< M_TOF_AMPDU_LEN */ ++} wl_proxd_debug_data_t; ++ ++/** version of the wl_wsec_info structure */ ++#define WL_WSEC_INFO_VERSION 0x01 ++ ++/** start enum value for BSS properties */ ++#define WL_WSEC_INFO_BSS_BASE 0x0100 ++ ++/** size of len and type fields of wl_wsec_info_tlv_t struct */ ++#define WL_WSEC_INFO_TLV_HDR_LEN OFFSETOF(wl_wsec_info_tlv_t, data) ++ ++/** Allowed wl_wsec_info properties; not all of them may be supported. */ ++typedef enum { ++ WL_WSEC_INFO_NONE = 0, ++ WL_WSEC_INFO_MAX_KEYS = 1, ++ WL_WSEC_INFO_NUM_KEYS = 2, ++ WL_WSEC_INFO_NUM_HW_KEYS = 3, ++ WL_WSEC_INFO_MAX_KEY_IDX = 4, ++ WL_WSEC_INFO_NUM_REPLAY_CNTRS = 5, ++ WL_WSEC_INFO_SUPPORTED_ALGOS = 6, ++ WL_WSEC_INFO_MAX_KEY_LEN = 7, ++ WL_WSEC_INFO_FLAGS = 8, ++ /* add global/per-wlc properties above */ ++ WL_WSEC_INFO_BSS_FLAGS = (WL_WSEC_INFO_BSS_BASE + 1), ++ WL_WSEC_INFO_BSS_WSEC = (WL_WSEC_INFO_BSS_BASE + 2), ++ WL_WSEC_INFO_BSS_TX_KEY_ID = (WL_WSEC_INFO_BSS_BASE + 3), ++ WL_WSEC_INFO_BSS_ALGO = (WL_WSEC_INFO_BSS_BASE + 4), ++ WL_WSEC_INFO_BSS_KEY_LEN = (WL_WSEC_INFO_BSS_BASE + 5), ++ WL_WSEC_INFO_BSS_ALGOS = (WL_WSEC_INFO_BSS_BASE + 6), ++ /* add per-BSS properties above */ ++ WL_WSEC_INFO_MAX = 0xffff ++} wl_wsec_info_type_t; ++ ++typedef struct { ++ uint32 algos; /* set algos to be enabled/disabled */ ++ uint32 mask; /* algos outside mask unaltered */ ++} wl_wsec_info_algos_t; ++ ++/** tlv used to return wl_wsec_info properties */ ++typedef struct { ++ uint16 type; ++ uint16 len; /**< data length */ ++ uint8 data[1]; /**< data follows */ ++} wl_wsec_info_tlv_t; ++ ++/** input/output data type for wsec_info iovar */ ++typedef struct wl_wsec_info { ++ uint8 version; /**< structure version */ ++ uint8 pad[2]; ++ uint8 num_tlvs; ++ wl_wsec_info_tlv_t tlvs[1]; /**< tlv data follows */ ++} wl_wsec_info_t; ++ ++/* ++ * randmac definitions ++ */ ++#define WL_RANDMAC_MODULE "randmac" ++#define WL_RANDMAC_API_VERSION 0x0100 /**< version 1.0 */ ++#define WL_RANDMAC_API_MIN_VERSION 0x0100 /**< version 1.0 */ ++ ++/** subcommands that can apply to randmac */ ++enum { ++ WL_RANDMAC_SUBCMD_NONE = 0, ++ WL_RANDMAC_SUBCMD_GET_VERSION = 1, ++ WL_RANDMAC_SUBCMD_ENABLE = 2, ++ WL_RANDMAC_SUBCMD_DISABLE = 3, ++ WL_RANDMAC_SUBCMD_CONFIG = 4, ++ WL_RANDMAC_SUBCMD_STATS = 5, ++ WL_RANDMAC_SUBCMD_CLEAR_STATS = 6, ++ ++ WL_RANDMAC_SUBCMD_MAX ++}; ++typedef int16 wl_randmac_subcmd_t; ++ ++/* Common IOVAR struct */ ++typedef struct wl_randmac { ++ uint16 version; ++ uint16 len; /* total length */ ++ wl_randmac_subcmd_t subcmd_id; /* subcommand id */ ++ uint8 data[0]; /* subcommand data */ ++} wl_randmac_t; ++ ++#define WL_RANDMAC_IOV_HDR_SIZE OFFSETOF(wl_randmac_t, data) ++ ++/* randmac version subcommand */ ++typedef struct wl_randmac_version { ++ uint16 version; /* Randmac method version info */ ++ uint8 pad[2]; /* Align on 4 byte boundary */ ++} wl_randmac_version_t; ++ ++/* ++ * Bitmask for methods supporting MAC randomization feature ++ */ ++#define WL_RANDMAC_USER_NONE 0x0000 ++#define WL_RANDMAC_USER_FTM 0x0001 ++#define WL_RANDMAC_USER_NAN 0x0002 ++#define WL_RANDMAC_USER_SCAN 0x0004 ++#define WL_RANDMAC_USER_ALL 0xFFFF ++typedef uint16 wl_randmac_method_t; ++ ++enum { ++ WL_RANDMAC_FLAGS_NONE = 0x00, ++ WL_RANDMAC_FLAGS_ADDR = 0x01, ++ WL_RANDMAC_FLAGS_MASK = 0x02, ++ WL_RANDMAC_FLAGS_METHOD = 0x04, ++ WL_RANDMAC_FLAGS_ALL = 0xFF ++}; ++typedef uint8 wl_randmac_flags_t; ++ ++/* randmac statistics subcommand */ ++typedef struct wl_randmac_stats { ++ uint32 set_ok; /* Set random addr success count */ ++ uint32 set_fail; /* Set random addr failed count */ ++ uint32 set_reqs; /* Set random addr count */ ++ uint32 reset_reqs; /* Restore random addr count */ ++ uint32 restore_ok; /* Restore random addr succes count */ ++ uint32 restore_fail; /* Restore random addr failed count */ ++ uint32 events_sent; /* randmac module events count */ ++ uint32 events_rcvd; /* randmac events received count */ ++} wl_randmac_stats_t; ++ ++/* randmac config subcommand */ ++typedef struct wl_randmac_config { ++ struct ether_addr addr; /* Randomized MAC address */ ++ struct ether_addr addr_mask; /* bitmask for randomization */ ++ wl_randmac_method_t method; /* Enabled methods */ ++ wl_randmac_flags_t flags; /* What config info changed */ ++ uint8 PAD; ++} wl_randmac_config_t; ++ ++enum { ++ WL_RANDMAC_EVENT_NONE = 0, /**< not an event, reserved */ ++ WL_RANDMAC_EVENT_BSSCFG_ADDR_SET = 1, /* bsscfg addr randomized */ ++ WL_RANDMAC_EVENT_BSSCFG_ADDR_RESTORE = 2, /* bsscfg addr restored */ ++ WL_RANDMAC_EVENT_ENABLED = 3, /* randmac module enabled */ ++ WL_RANDMAC_EVENT_DISABLE = 4, /* randmac module disabled */ ++ WL_RANDMAC_EVENT_BSSCFG_STATUS = 5, /* bsscfg enable/disable */ ++ ++ WL_RANDMAC_EVENT_MAX ++}; ++typedef int16 wl_randmac_event_type_t; ++typedef int32 wl_randmac_status_t; ++typedef uint32 wl_randmac_event_mask_t; ++ ++#define WL_RANDMAC_EVENT_MASK_ALL 0xfffffffe ++#define WL_RANDMAC_EVENT_MASK_EVENT(_event_type) (1 << (_event_type)) ++#define WL_RANDMAC_EVENT_ENABLED(_mask, _event_type) (\ ++ ((_mask) & WL_RANDMAC_EVENT_MASK_EVENT(_event_type)) != 0) ++ ++/** tlv IDs - data length 4 bytes unless overridden by type, alignment 32 bits */ ++enum { ++ WL_RANDMAC_TLV_NONE = 0, ++ WL_RANDMAC_TLV_METHOD = 1, ++ WL_RANDMAC_TLV_ADDR = 2, ++ WL_RANDMAC_TLV_MASK = 3 ++}; ++typedef uint16 wl_randmac_tlv_id_t; ++ ++typedef struct wl_randmac_tlv { ++ wl_randmac_tlv_id_t id; ++ uint16 len; /* Length of variable */ ++ uint8 data[1]; ++} wl_randmac_tlv_t; ++ ++/** randmac event */ ++typedef struct wl_randmac_event { ++ uint16 version; ++ uint16 len; /* Length of all variables */ ++ wl_randmac_event_type_t type; ++ wl_randmac_method_t method; ++ uint8 pad[2]; ++ wl_randmac_tlv_t tlvs[1]; /**< variable */ ++} wl_randmac_event_t; ++ ++/* ++ * scan MAC definitions ++ */ ++ ++/** common iovar struct */ ++typedef struct wl_scanmac { ++ uint16 subcmd_id; /**< subcommand id */ ++ uint16 len; /**< total length of data[] */ ++ uint8 data[]; /**< subcommand data */ ++} wl_scanmac_t; ++ ++/* subcommand ids */ ++#define WL_SCANMAC_SUBCMD_ENABLE 0 ++#define WL_SCANMAC_SUBCMD_BSSCFG 1 /**< only GET supported */ ++#define WL_SCANMAC_SUBCMD_CONFIG 2 ++ ++/** scanmac enable data struct */ ++typedef struct wl_scanmac_enable { ++ uint8 enable; /**< 1 - enable, 0 - disable */ ++ uint8 pad[3]; /**< 4-byte struct alignment */ ++} wl_scanmac_enable_t; ++ ++/** scanmac bsscfg data struct */ ++typedef struct wl_scanmac_bsscfg { ++ uint32 bsscfg; /**< bsscfg index */ ++} wl_scanmac_bsscfg_t; ++ ++/** scanmac config data struct */ ++typedef struct wl_scanmac_config { ++ struct ether_addr mac; /**< 6 bytes of MAC address or MAC prefix (i.e. OUI) */ ++ struct ether_addr random_mask; /**< randomized bits on each scan */ ++ uint16 scan_bitmap; /**< scans to use this MAC address */ ++ uint8 pad[2]; /**< 4-byte struct alignment */ ++} wl_scanmac_config_t; ++ ++/* scan bitmap */ ++#define WL_SCANMAC_SCAN_UNASSOC (0x01 << 0) /**< unassociated scans */ ++#define WL_SCANMAC_SCAN_ASSOC_ROAM (0x01 << 1) /**< associated roam scans */ ++#define WL_SCANMAC_SCAN_ASSOC_PNO (0x01 << 2) /**< associated PNO scans */ ++#define WL_SCANMAC_SCAN_ASSOC_HOST (0x01 << 3) /**< associated host scans */ ++/* ++ * bonjour dongle offload definitions ++ */ ++ ++/* common iovar struct */ ++typedef struct wl_bdo { ++ uint16 subcmd_id; /* subcommand id */ ++ uint16 len; /* total length of data[] */ ++ uint8 data[]; /* subcommand data */ ++} wl_bdo_t; ++ ++/* subcommand ids */ ++#define WL_BDO_SUBCMD_DOWNLOAD 0 /* Download flattened database */ ++#define WL_BDO_SUBCMD_ENABLE 1 /* Start bonjour after download */ ++#define WL_BDO_SUBCMD_MAX_DOWNLOAD 2 /* Get the max download size */ ++ ++/* maximum fragment size */ ++#define BDO_MAX_FRAGMENT_SIZE 1024 ++ ++/* download flattened database ++ * ++ * BDO must be disabled before database download else fail. ++ * ++ * If database size is within BDO_MAX_FRAGMENT_SIZE then only a single fragment ++ * is required (i.e. frag_num = 0, total_size = frag_size). ++ * If database size exceeds BDO_MAX_FRAGMENT_SIZE then multiple fragments are required. ++ */ ++typedef struct wl_bdo_download { ++ uint16 total_size; /* total database size */ ++ uint16 frag_num; /* fragment number, 0 for first fragment, N-1 for last fragment */ ++ uint16 frag_size; /* size of fragment (max BDO_MAX_FRAGMENT_SIZE) */ ++ uint8 pad[2]; /* 4-byte struct alignment */ ++ uint8 fragment[BDO_MAX_FRAGMENT_SIZE]; /* fragment data */ ++} wl_bdo_download_t; ++ ++/* enable ++ * ++ * Enable requires a downloaded database else fail. ++ */ ++typedef struct wl_bdo_enable { ++ uint8 enable; /* 1 - enable, 0 - disable */ ++ uint8 pad[3]; /* 4-byte struct alignment */ ++} wl_bdo_enable_t; ++ ++/* ++ * Get the max download size for Bonjour Offload. ++ */ ++typedef struct wl_bdo_max_download { ++ uint16 size; /* Max download size in bytes */ ++ uint8 pad[2]; /* 4-byte struct alignment */ ++} wl_bdo_max_download_t; ++ ++/* ++ * TCP keepalive offload definitions ++ */ ++ ++/* common iovar struct */ ++typedef struct wl_tko { ++ uint16 subcmd_id; /* subcommand id */ ++ uint16 len; /* total length of data[] */ ++ uint8 data[]; /* subcommand data */ ++} wl_tko_t; ++ ++/* subcommand ids */ ++#define WL_TKO_SUBCMD_MAX_TCP 0 /* max TCP connections supported */ ++#define WL_TKO_SUBCMD_PARAM 1 /* configure offload common parameters */ ++#define WL_TKO_SUBCMD_CONNECT 2 /* TCP connection info */ ++#define WL_TKO_SUBCMD_ENABLE 3 /* enable/disable */ ++#define WL_TKO_SUBCMD_STATUS 4 /* TCP connection status */ ++ ++/* WL_TKO_SUBCMD_MAX_CONNECT subcommand data */ ++typedef struct wl_tko_max_tcp { ++ uint8 max; /* max TCP connections supported */ ++ uint8 pad[3]; /* 4-byte struct alignment */ ++} wl_tko_max_tcp_t; ++ ++/* WL_TKO_SUBCMD_PARAM subcommand data */ ++typedef struct wl_tko_param { ++ uint16 interval; /* keepalive tx interval (secs) */ ++ uint16 retry_interval; /* keepalive retry interval (secs) */ ++ uint16 retry_count; /* retry_count */ ++ uint8 pad[2]; /* 4-byte struct alignment */ ++} wl_tko_param_t; ++ ++/* WL_TKO_SUBCMD_CONNECT subcommand data ++ * invoke with unique 'index' for each TCP connection ++ */ ++typedef struct wl_tko_connect { ++ uint8 index; /* TCP connection index, 0 to max-1 */ ++ uint8 ip_addr_type; /* 0 - IPv4, 1 - IPv6 */ ++ uint16 local_port; /* local port */ ++ uint16 remote_port; /* remote port */ ++ uint16 PAD; ++ uint32 local_seq; /* local sequence number */ ++ uint32 remote_seq; /* remote sequence number */ ++ uint16 request_len; /* TCP keepalive request packet length */ ++ uint16 response_len; /* TCP keepalive response packet length */ ++ uint8 data[]; /* variable length field containing local/remote IPv4/IPv6, ++ * TCP keepalive request packet, TCP keepalive response packet ++ * For IPv4, length is 4 * 2 + request_length + response_length ++ * offset 0 - local IPv4 ++ * offset 4 - remote IPv4 ++ * offset 8 - TCP keepalive request packet ++ * offset 8+request_length - TCP keepalive response packet ++ * For IPv6, length is 16 * 2 + request_length + response_length ++ * offset 0 - local IPv6 ++ * offset 16 - remote IPv6 ++ * offset 32 - TCP keepalive request packet ++ * offset 32+request_length - TCP keepalive response packet ++ */ ++} wl_tko_connect_t; ++ ++/* WL_TKO_SUBCMD_CONNECT subcommand data to GET configured info for specific index */ ++typedef struct wl_tko_get_connect { ++ uint8 index; /* TCP connection index, 0 to max-1 */ ++ uint8 pad[3]; /* 4-byte struct alignment */ ++} wl_tko_get_connect_t; ++ ++typedef struct wl_tko_enable { ++ uint8 enable; /* 1 - enable, 0 - disable */ ++ uint8 pad[3]; /* 4-byte struct alignment */ ++} wl_tko_enable_t; ++ ++/* WL_TKO_SUBCMD_STATUS subcommand data */ ++/* must be invoked before tko is disabled else status is unavailable */ ++typedef struct wl_tko_status { ++ uint8 count; /* number of status entries (i.e. equals ++ * max TCP connections supported) ++ */ ++ uint8 status[1]; /* variable length field contain status for ++ * each TCP connection index ++ */ ++} wl_tko_status_t; ++ ++typedef enum { ++ TKO_STATUS_NORMAL = 0, /* TCP connection normal, no error */ ++ TKO_STATUS_NO_RESPONSE = 1, /* no response to TCP keepalive */ ++ TKO_STATUS_NO_TCP_ACK_FLAG = 2, /* TCP ACK flag not set */ ++ TKO_STATUS_UNEXPECT_TCP_FLAG = 3, /* unexpect TCP flags set other than ACK */ ++ TKO_STATUS_SEQ_NUM_INVALID = 4, /* ACK != sequence number */ ++ TKO_STATUS_REMOTE_SEQ_NUM_INVALID = 5, /* SEQ > remote sequence number */ ++ TKO_STATUS_TCP_DATA = 6, /* TCP data available */ ++ TKO_STATUS_UNAVAILABLE = 255, /* not used/configured */ ++} tko_status_t; ++ ++enum rssi_reason { ++ RSSI_REASON_UNKNOW = 0, ++ RSSI_REASON_LOWRSSI = 1, ++ RSSI_REASON_NSYC = 2, ++ RSSI_REASON_TIMEOUT = 3 ++}; ++ ++enum tof_reason { ++ TOF_REASON_OK = 0, ++ TOF_REASON_REQEND = 1, ++ TOF_REASON_TIMEOUT = 2, ++ TOF_REASON_NOACK = 3, ++ TOF_REASON_INVALIDAVB = 4, ++ TOF_REASON_INITIAL = 5, ++ TOF_REASON_ABORT = 6 ++}; ++ ++enum rssi_state { ++ RSSI_STATE_POLL = 0, ++ RSSI_STATE_TPAIRING = 1, ++ RSSI_STATE_IPAIRING = 2, ++ RSSI_STATE_THANDSHAKE = 3, ++ RSSI_STATE_IHANDSHAKE = 4, ++ RSSI_STATE_CONFIRMED = 5, ++ RSSI_STATE_PIPELINE = 6, ++ RSSI_STATE_NEGMODE = 7, ++ RSSI_STATE_MONITOR = 8, ++ RSSI_STATE_LAST = 9 ++}; ++ ++enum tof_state { ++ TOF_STATE_IDLE = 0, ++ TOF_STATE_IWAITM = 1, ++ TOF_STATE_TWAITM = 2, ++ TOF_STATE_ILEGACY = 3, ++ TOF_STATE_IWAITCL = 4, ++ TOF_STATE_TWAITCL = 5, ++ TOF_STATE_ICONFIRM = 6, ++ TOF_STATE_IREPORT = 7 ++}; ++ ++enum tof_mode_type { ++ TOF_LEGACY_UNKNOWN = 0, ++ TOF_LEGACY_AP = 1, ++ TOF_NONLEGACY_AP = 2 ++}; ++ ++enum tof_way_type { ++ TOF_TYPE_ONE_WAY = 0, ++ TOF_TYPE_TWO_WAY = 1, ++ TOF_TYPE_REPORT = 2 ++}; ++ ++enum tof_rate_type { ++ TOF_FRAME_RATE_VHT = 0, ++ TOF_FRAME_RATE_LEGACY = 1 ++}; ++ ++#define TOF_ADJ_TYPE_NUM 4 /**< number of assisted timestamp adjustment */ ++enum tof_adj_mode { ++ TOF_ADJ_SOFTWARE = 0, ++ TOF_ADJ_HARDWARE = 1, ++ TOF_ADJ_SEQ = 2, ++ TOF_ADJ_NONE = 3 ++}; ++ ++#define FRAME_TYPE_NUM 4 /**< number of frame type */ ++enum frame_type { ++ FRAME_TYPE_CCK = 0, ++ FRAME_TYPE_OFDM = 1, ++ FRAME_TYPE_11N = 2, ++ FRAME_TYPE_11AC = 3 ++}; ++ ++typedef struct wl_proxd_status_iovar { ++ uint16 method; /**< method */ ++ uint8 mode; /**< mode */ ++ uint8 peermode; /**< peer mode */ ++ uint8 state; /**< state */ ++ uint8 reason; /**< reason code */ ++ uint8 PAD[2]; ++ uint32 distance; /**< distance */ ++ uint32 txcnt; /**< tx pkt counter */ ++ uint32 rxcnt; /**< rx pkt counter */ ++ struct ether_addr peer; /**< peer mac address */ ++ int8 avg_rssi; /**< average rssi */ ++ int8 hi_rssi; /**< highest rssi */ ++ int8 low_rssi; /**< lowest rssi */ ++ uint8 PAD[3]; ++ uint32 dbgstatus; /**< debug status */ ++ uint16 frame_type_cnt[FRAME_TYPE_NUM]; /**< frame types */ ++ uint8 adj_type_cnt[TOF_ADJ_TYPE_NUM]; /**< adj types HW/SW */ ++} wl_proxd_status_iovar_t; ++ ++/* ifdef NET_DETECT */ ++typedef struct net_detect_adapter_features { ++ uint8 wowl_enabled; ++ uint8 net_detect_enabled; ++ uint8 nlo_enabled; ++} net_detect_adapter_features_t; ++ ++typedef enum net_detect_bss_type { ++ nd_bss_any = 0, ++ nd_ibss, ++ nd_ess ++} net_detect_bss_type_t; ++ ++typedef struct net_detect_profile { ++ wlc_ssid_t ssid; ++ net_detect_bss_type_t bss_type; /**< Ignore for now since Phase 1 is only for ESS */ ++ uint32 cipher_type; /**< DOT11_CIPHER_ALGORITHM enumeration values */ ++ uint32 auth_type; /**< DOT11_AUTH_ALGORITHM enumeration values */ ++} net_detect_profile_t; ++ ++typedef struct net_detect_profile_list { ++ uint32 num_nd_profiles; ++ net_detect_profile_t nd_profile[]; ++} net_detect_profile_list_t; ++ ++typedef struct net_detect_config { ++ uint8 nd_enabled; ++ uint8 PAD[3]; ++ uint32 scan_interval; ++ uint32 wait_period; ++ uint8 wake_if_connected; ++ uint8 wake_if_disconnected; ++ uint8 PAD[2]; ++ net_detect_profile_list_t nd_profile_list; ++} net_detect_config_t; ++ ++typedef enum net_detect_wake_reason { ++ nd_reason_unknown, ++ nd_net_detected, ++ nd_wowl_event, ++ nd_ucode_error ++} net_detect_wake_reason_t; ++ ++typedef struct net_detect_wake_data { ++ net_detect_wake_reason_t nd_wake_reason; ++ uint32 nd_wake_date_length; ++ uint8 nd_wake_data[0]; /**< Wake data (currently unused) */ ++} net_detect_wake_data_t; ++ ++/* endif NET_DETECT */ ++ ++/* (unversioned, deprecated) */ ++typedef struct bcnreq { ++ uint8 bcn_mode; ++ uint8 PAD[3]; ++ int32 dur; ++ int32 channel; ++ struct ether_addr da; ++ uint16 random_int; ++ wlc_ssid_t ssid; ++ uint16 reps; ++ uint8 PAD[2]; ++} bcnreq_t; ++ ++#define WL_RRM_BCN_REQ_VER 1 ++typedef struct bcn_req { ++ uint8 version; ++ uint8 bcn_mode; ++ uint8 pad_1[2]; ++ int32 dur; ++ int32 channel; ++ struct ether_addr da; ++ uint16 random_int; ++ wlc_ssid_t ssid; ++ uint16 reps; ++ uint8 req_elements; ++ uint8 pad_2; ++ chanspec_list_t chspec_list; ++} bcn_req_t; ++ ++typedef struct rrmreq { ++ struct ether_addr da; ++ uint8 reg; ++ uint8 chan; ++ uint16 random_int; ++ uint16 dur; ++ uint16 reps; ++} rrmreq_t; ++ ++typedef struct framereq { ++ struct ether_addr da; ++ uint8 reg; ++ uint8 chan; ++ uint16 random_int; ++ uint16 dur; ++ struct ether_addr ta; ++ uint16 reps; ++} framereq_t; ++ ++typedef struct statreq { ++ struct ether_addr da; ++ struct ether_addr peer; ++ uint16 random_int; ++ uint16 dur; ++ uint8 group_id; ++ uint8 PAD; ++ uint16 reps; ++} statreq_t; ++ ++typedef struct wl_rrm_config_ioc { ++ uint16 version; /* command version */ ++ uint16 id; /* subiovar cmd ID */ ++ uint16 len; /* total length of all bytes in data[] */ ++ uint16 pad; /* 4-byte boundary padding */ ++ uint8 data[1]; /* payload */ ++} wl_rrm_config_ioc_t; ++ ++enum { ++ WL_RRM_CONFIG_NONE = 0, /* reserved */ ++ WL_RRM_CONFIG_GET_LCI = 1, /* get LCI */ ++ WL_RRM_CONFIG_SET_LCI = 2, /* set LCI */ ++ WL_RRM_CONFIG_GET_CIVIC = 3, /* get civic location */ ++ WL_RRM_CONFIG_SET_CIVIC = 4, /* set civic location */ ++ WL_RRM_CONFIG_MAX = 5 ++}; ++ ++#define WL_RRM_CONFIG_NAME "rrm_config" ++#define WL_RRM_CONFIG_MIN_LENGTH OFFSETOF(wl_rrm_config_ioc_t, data) ++ ++enum { ++ WL_RRM_EVENT_NONE = 0, /* not an event, reserved */ ++ WL_RRM_EVENT_FRNG_REQ = 1, /* Receipt of FRNG request frame */ ++ WL_RRM_EVENT_FRNG_REP = 2, /* Receipt of FRNG report frame */ ++ ++ WL_RRM_EVENT_MAX ++}; ++typedef int16 wl_rrm_event_type_t; ++ ++typedef struct frngreq_target { ++ uint32 bssid_info; ++ uint8 channel; ++ uint8 phytype; ++ uint8 reg; ++ uint8 pad; ++ struct ether_addr bssid; ++ chanspec_t chanspec; ++ uint32 sid; ++} frngreq_target_t; ++ ++typedef struct frngreq { ++ wl_rrm_event_type_t event; /* RRM event type */ ++ struct ether_addr da; ++ uint16 max_init_delay; /* Upper bound of random delay, in TUs */ ++ uint8 min_ap_count; /* Min FTM ranges requested (1-15) */ ++ uint8 num_aps; /* Number of APs to range, at least min_ap_count */ ++ uint16 max_age; /* Max elapsed time before FTM request, 0xFFFF = any */ ++ uint16 reps; /* Number of repetitions of this measurement type */ ++ frngreq_target_t targets[1]; /* Target BSSIDs to range */ ++} frngreq_t; ++ ++typedef struct frngrep_range { ++ uint32 start_tsf; /* 4 lsb of tsf */ ++ struct ether_addr bssid; ++ uint8 pad[2]; ++ uint32 range; ++ uint32 max_err; ++ uint8 rsvd; ++ uint8 pad2[3]; ++} frngrep_range_t; ++ ++typedef struct frngrep_error { ++ uint32 start_tsf; /* 4 lsb of tsf */ ++ struct ether_addr bssid; ++ uint8 code; ++ uint8 pad[1]; ++} frngrep_error_t; ++ ++typedef struct frngrep { ++ wl_rrm_event_type_t event; /* RRM event type */ ++ struct ether_addr da; ++ uint8 range_entry_count; ++ uint8 error_entry_count; ++ uint16 dialog_token; /* dialog token */ ++ frngrep_range_t range_entries[DOT11_FTM_RANGE_ENTRY_MAX_COUNT]; ++ frngrep_error_t error_entries[DOT11_FTM_RANGE_ERROR_ENTRY_MAX_COUNT]; ++} frngrep_t; ++ ++typedef struct wl_rrm_frng_ioc { ++ uint16 version; /* command version */ ++ uint16 id; /* subiovar cmd ID */ ++ uint16 len; /* total length of all bytes in data[] */ ++ uint16 pad; /* 4-byte boundary padding */ ++ uint8 data[]; /* payload */ ++} wl_rrm_frng_ioc_t; ++ ++enum { ++ WL_RRM_FRNG_NONE = 0, /* reserved */ ++ WL_RRM_FRNG_SET_REQ = 1, /* send ftm ranging request */ ++ WL_RRM_FRNG_MAX = 2 ++}; ++ ++#define WL_RRM_FRNG_NAME "rrm_frng" ++#define WL_RRM_FRNG_MIN_LENGTH OFFSETOF(wl_rrm_frng_ioc_t, data) ++ ++#define WL_RRM_RPT_VER 0 ++#define WL_RRM_RPT_MAX_PAYLOAD 256 ++#define WL_RRM_RPT_MIN_PAYLOAD 7 ++#define WL_RRM_RPT_FALG_ERR 0 ++#define WL_RRM_RPT_FALG_GRP_ID_PROPR (1 << 0) ++#define WL_RRM_RPT_FALG_GRP_ID_0 (1 << 1) ++typedef struct { ++ uint16 ver; /**< version */ ++ struct ether_addr addr; /**< STA MAC addr */ ++ uint32 timestamp; /**< timestamp of the report */ ++ uint16 flag; /**< flag */ ++ uint16 len; /**< length of payload data */ ++ uint8 data[WL_RRM_RPT_MAX_PAYLOAD]; ++} statrpt_t; ++ ++typedef struct wlc_dwds_config { ++ uint32 enable; ++ uint32 mode; /**< STA/AP interface */ ++ struct ether_addr ea; ++ uint8 PAD[2]; ++} wlc_dwds_config_t; ++ ++typedef struct wl_el_set_params_s { ++ uint8 set; /**< Set number */ ++ uint8 PAD[3]; ++ uint32 size; /**< Size to make/expand */ ++} wl_el_set_params_t; ++ ++typedef struct wl_el_tag_params_s { ++ uint16 tag; ++ uint8 set; ++ uint8 flags; ++} wl_el_tag_params_t; ++ ++/** Video Traffic Interference Monitor config */ ++#define INTFER_VERSION 1 ++typedef struct wl_intfer_params { ++ uint16 version; /**< version */ ++ uint8 period; /**< sample period */ ++ uint8 cnt; /**< sample cnt */ ++ uint8 txfail_thresh; /**< non-TCP txfail threshold */ ++ uint8 tcptxfail_thresh; /**< tcptxfail threshold */ ++} wl_intfer_params_t; ++ ++typedef struct wl_staprio_cfg { ++ struct ether_addr ea; /**< mac addr */ ++ uint8 prio; /**< scb priority */ ++} wl_staprio_cfg_t; ++ ++typedef enum wl_stamon_cfg_cmd_type { ++ STAMON_CFG_CMD_DEL = 0, ++ STAMON_CFG_CMD_ADD = 1, ++ STAMON_CFG_CMD_ENB = 2, ++ STAMON_CFG_CMD_DSB = 3, ++ STAMON_CFG_CMD_CNT = 4, ++ STAMON_CFG_CMD_RSTCNT = 5, ++ STAMON_CFG_CMD_GET_STATS = 6 ++} wl_stamon_cfg_cmd_type_t; ++ ++typedef struct wlc_stamon_sta_config { ++ wl_stamon_cfg_cmd_type_t cmd; /**< 0 - delete, 1 - add */ ++ struct ether_addr ea; ++ uint8 PAD[2]; ++} wlc_stamon_sta_config_t; ++ ++/* ifdef SR_DEBUG */ ++typedef struct /* pmu_reg */{ ++ uint32 pmu_control; ++ uint32 pmu_capabilities; ++ uint32 pmu_status; ++ uint32 res_state; ++ uint32 res_pending; ++ uint32 pmu_timer1; ++ uint32 min_res_mask; ++ uint32 max_res_mask; ++ uint32 pmu_chipcontrol1[4]; ++ uint32 pmu_regcontrol[5]; ++ uint32 pmu_pllcontrol[5]; ++ uint32 pmu_rsrc_up_down_timer[31]; ++ uint32 rsrc_dep_mask[31]; ++} pmu_reg_t; ++/* endif SR_DEBUG */ ++ ++typedef struct wl_taf_define { ++ struct ether_addr ea; /**< STA MAC or 0xFF... */ ++ uint16 version; /**< version */ ++ uint32 sch; /**< method index */ ++ uint32 prio; /**< priority */ ++ uint32 misc; /**< used for return value */ ++ uint8 text[]; /**< used to pass and return ascii text */ ++} wl_taf_define_t; ++ ++/** Received Beacons lengths information */ ++#define WL_LAST_BCNS_INFO_FIXED_LEN OFFSETOF(wlc_bcn_len_hist_t, bcnlen_ring) ++typedef struct wlc_bcn_len_hist { ++ uint16 ver; /**< version field */ ++ uint16 cur_index; /**< current pointed index in ring buffer */ ++ uint32 max_bcnlen; /**< Max beacon length received */ ++ uint32 min_bcnlen; /**< Min beacon length received */ ++ uint32 ringbuff_len; /**< Length of the ring buffer 'bcnlen_ring' */ ++ uint32 bcnlen_ring[1]; /**< ring buffer storing received beacon lengths */ ++} wlc_bcn_len_hist_t; ++ ++/* WDS net interface types */ ++#define WL_WDSIFTYPE_NONE 0x0 /**< The interface type is neither WDS nor DWDS. */ ++#define WL_WDSIFTYPE_WDS 0x1 /**< The interface is WDS type. */ ++#define WL_WDSIFTYPE_DWDS 0x2 /**< The interface is DWDS type. */ ++ ++typedef struct wl_bssload_static { ++ uint8 is_static; ++ uint8 PAD; ++ uint16 sta_count; ++ uint8 chan_util; ++ uint8 PAD; ++ uint16 aac; ++} wl_bssload_static_t; ++ ++/* Buffer of size WLC_SAMPLECOLLECT_MAXLEN (=10240 for 4345a0 ACPHY) ++ * gets copied to this, multiple times ++ */ ++typedef enum wl_gpaio_option { ++ GPAIO_PMU_AFELDO, ++ GPAIO_PMU_TXLDO, ++ GPAIO_PMU_VCOLDO, ++ GPAIO_PMU_LNALDO, ++ GPAIO_PMU_ADCLDO, ++ GPAIO_ICTAT_CAL, ++ GPAIO_PMU_CLEAR, ++ GPAIO_OFF, ++ GPAIO_PMU_LOGENLDO, ++ GPAIO_PMU_RXLDO2G, ++ GPAIO_PMU_RXLDO5G ++} wl_gpaio_option_t; ++ ++/** IO Var Operations - the Value of iov_op In wlc_ap_doiovar */ ++typedef enum wlc_ap_iov_bss_operation { ++ WLC_AP_IOV_OP_DELETE = -1, ++ WLC_AP_IOV_OP_DISABLE = 0, ++ WLC_AP_IOV_OP_ENABLE = 1, ++ WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE = 2, ++ WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE = 3, ++ WLC_AP_IOV_OP_MOVE = 4 ++} wlc_ap_iov_bss_oper_t; ++ ++/* LTE coex info */ ++/* Analogue of HCI Set MWS Signaling cmd */ ++typedef struct { ++ int16 mws_rx_assert_offset; ++ int16 mws_rx_assert_jitter; ++ int16 mws_rx_deassert_offset; ++ int16 mws_rx_deassert_jitter; ++ int16 mws_tx_assert_offset; ++ int16 mws_tx_assert_jitter; ++ int16 mws_tx_deassert_offset; ++ int16 mws_tx_deassert_jitter; ++ int16 mws_pattern_assert_offset; ++ int16 mws_pattern_assert_jitter; ++ int16 mws_inact_dur_assert_offset; ++ int16 mws_inact_dur_assert_jitter; ++ int16 mws_scan_freq_assert_offset; ++ int16 mws_scan_freq_assert_jitter; ++ int16 mws_prio_assert_offset_req; ++} wci2_config_t; ++ ++/** Analogue of HCI MWS Channel Params */ ++typedef struct { ++ uint16 mws_rx_center_freq; /**< MHz */ ++ uint16 mws_tx_center_freq; ++ uint16 mws_rx_channel_bw; /**< KHz */ ++ uint16 mws_tx_channel_bw; ++ uint8 mws_channel_en; ++ uint8 mws_channel_type; /**< Don't care for WLAN? */ ++} mws_params_t; ++ ++#define LTECX_MAX_NUM_PERIOD_TYPES 7 ++ ++/* LTE Frame params */ ++typedef struct { ++ uint16 mws_frame_dur; ++ int16 mws_framesync_assert_offset; ++ uint16 mws_framesync_assert_jitter; ++ uint16 mws_period_dur[LTECX_MAX_NUM_PERIOD_TYPES]; ++ uint8 mws_period_type[LTECX_MAX_NUM_PERIOD_TYPES]; ++ uint8 mws_num_periods; ++} mws_frame_config_t; ++ ++/** MWS wci2 message */ ++typedef struct { ++ uint8 mws_wci2_data; /**< BT-SIG msg */ ++ uint8 PAD; ++ uint16 mws_wci2_interval; /**< Interval in us */ ++ uint16 mws_wci2_repeat; /**< No of msgs to send */ ++} mws_wci2_msg_t; ++/* MWS ANT map */ ++typedef struct { ++ uint16 combo1; /* mws ant selection 1 */ ++ uint16 combo2; /* mws ant selection 2 */ ++ uint16 combo3; /* mws ant selection 3 */ ++ uint16 combo4; /* mws ant selection 4 */ ++} mws_ant_map_t; ++ ++/* MWS SCAN_REQ Bitmap */ ++typedef struct mws_scanreq_params { ++ uint16 idx; ++ uint16 bm_2g; ++ uint16 bm_5g_lo; ++ uint16 bm_5g_mid; ++ uint16 bm_5g_hi; ++} mws_scanreq_params_t; ++ ++typedef struct { ++ uint32 config; /**< MODE: AUTO (-1), Disable (0), Enable (1) */ ++ uint32 status; /**< Current state: Disabled (0), Enabled (1) */ ++} wl_config_t; ++ ++#define WLC_RSDB_MODE_AUTO_MASK 0x80 ++#define WLC_RSDB_EXTRACT_MODE(val) ((int8)((val) & (~(WLC_RSDB_MODE_AUTO_MASK)))) ++ ++typedef struct { ++ uint16 request; /* type of sensor hub request */ ++ uint16 enable; /* enable/disable response for specified request */ ++ uint16 interval; /* interval between responses to the request */ ++} shub_req_t; ++ ++#define WL_IF_STATS_T_VERSION 1 /**< current version of wl_if_stats structure */ ++ ++/** per interface counters */ ++typedef struct wl_if_stats { ++ uint16 version; /**< version of the structure */ ++ uint16 length; /**< length of the entire structure */ ++ uint32 PAD; /**< padding */ ++ ++ /* transmit stat counters */ ++ uint64 txframe; /**< tx data frames */ ++ uint64 txbyte; /**< tx data bytes */ ++ uint64 txerror; /**< tx data errors (derived: sum of others) */ ++ uint64 txnobuf; /**< tx out of buffer errors */ ++ uint64 txrunt; /**< tx runt frames */ ++ uint64 txfail; /**< tx failed frames */ ++ uint64 txretry; /**< tx retry frames */ ++ uint64 txretrie; /**< tx multiple retry frames */ ++ uint64 txfrmsnt; /**< tx sent frames */ ++ uint64 txmulti; /**< tx mulitcast sent frames */ ++ uint64 txfrag; /**< tx fragments sent */ ++ ++ /* receive stat counters */ ++ uint64 rxframe; /**< rx data frames */ ++ uint64 rxbyte; /**< rx data bytes */ ++ uint64 rxerror; /**< rx data errors (derived: sum of others) */ ++ uint64 rxnobuf; /**< rx out of buffer errors */ ++ uint64 rxrunt; /**< rx runt frames */ ++ uint64 rxfragerr; /**< rx fragment errors */ ++ uint64 rxmulti; /**< rx multicast frames */ ++ ++ uint64 txexptime; /* DATA Tx frames suppressed due to timer expiration */ ++ uint64 txrts; /* RTS/CTS succeeeded count */ ++ uint64 txnocts; /* RTS/CTS faled count */ ++ ++ uint64 txretrans; /* Number of frame retransmissions */ ++} ++wl_if_stats_t; ++ ++typedef struct wl_band { ++ uint16 bandtype; /**< WL_BAND_2G, WL_BAND_5G */ ++ uint16 bandunit; /**< bandstate[] index */ ++ uint16 phytype; /**< phytype */ ++ uint16 phyrev; ++} ++wl_band_t; ++ ++#define WL_WLC_VERSION_T_VERSION 1 /**< current version of wlc_version structure */ ++ ++/** wlc interface version */ ++typedef struct wl_wlc_version { ++ uint16 version; /**< version of the structure */ ++ uint16 length; /**< length of the entire structure */ ++ ++ /* epi version numbers */ ++ uint16 epi_ver_major; /**< epi major version number */ ++ uint16 epi_ver_minor; /**< epi minor version number */ ++ uint16 epi_rc_num; /**< epi RC number */ ++ uint16 epi_incr_num; /**< epi increment number */ ++ ++ /* wlc interface version numbers */ ++ uint16 wlc_ver_major; /**< wlc interface major version number */ ++ uint16 wlc_ver_minor; /**< wlc interface minor version number */ ++} ++wl_wlc_version_t; ++ ++/* Highest version of WLC_API_VERSION supported */ ++#define WLC_API_VERSION_MAJOR_MAX 8 ++#define WLC_API_VERSION_MINOR_MAX 0 ++ ++/* begin proxd definitions */ ++#include ++ ++#define WL_PROXD_API_VERSION 0x0300 /**< version 3.0 */ ++ ++/** Minimum supported API version */ ++#define WL_PROXD_API_MIN_VERSION 0x0300 ++ ++/** proximity detection methods */ ++enum { ++ WL_PROXD_METHOD_NONE = 0, ++ WL_PROXD_METHOD_RSVD1 = 1, /**< backward compatibility - RSSI, not supported */ ++ WL_PROXD_METHOD_TOF = 2, ++ WL_PROXD_METHOD_RSVD2 = 3, /**< 11v only - if needed */ ++ WL_PROXD_METHOD_FTM = 4, /**< IEEE rev mc/2014 */ ++ WL_PROXD_METHOD_MAX ++}; ++typedef int16 wl_proxd_method_t; ++ ++/** global and method configuration flags */ ++enum { ++ WL_PROXD_FLAG_NONE = 0x00000000, ++ WL_PROXD_FLAG_RX_ENABLED = 0x00000001, /**< respond to requests, per bss */ ++ WL_PROXD_FLAG_RX_RANGE_REQ = 0x00000002, /**< 11mc range requests enabled */ ++ WL_PROXD_FLAG_TX_LCI = 0x00000004, /**< tx lci, if known */ ++ WL_PROXD_FLAG_TX_CIVIC = 0x00000008, /**< tx civic, if known */ ++ WL_PROXD_FLAG_RX_AUTO_BURST = 0x00000010, /**< auto respond w/o host action */ ++ WL_PROXD_FLAG_TX_AUTO_BURST = 0x00000020, /**< continue tx w/o host action */ ++ WL_PROXD_FLAG_AVAIL_PUBLISH = 0x00000040, /**< publish availability */ ++ WL_PROXD_FLAG_AVAIL_SCHEDULE = 0x00000080, /**< schedule using availability */ ++ WL_PROXD_FLAG_ASAP_CAPABLE = 0x00000100, /* ASAP capable */ ++ WL_PROXD_FLAG_MBURST_FOLLOWUP = 0x00000200, /* new multi-burst algorithm */ ++ WL_PROXD_FLAG_SECURE = 0x00000400, /* per bsscfg option */ ++ WL_PROXD_FLAG_NO_TSF_SYNC = 0x00000800, /* disable tsf sync */ ++ WL_PROXD_FLAG_ALL = 0xffffffff ++}; ++typedef uint32 wl_proxd_flags_t; ++ ++#define WL_PROXD_FLAGS_AVAIL (WL_PROXD_FLAG_AVAIL_PUBLISH | \ ++ WL_PROXD_FLAG_AVAIL_SCHEDULE) ++ ++/** session flags */ ++enum { ++ WL_PROXD_SESSION_FLAG_NONE = 0x00000000, /**< no flags */ ++ WL_PROXD_SESSION_FLAG_INITIATOR = 0x00000001, /**< local device is initiator */ ++ WL_PROXD_SESSION_FLAG_TARGET = 0x00000002, /**< local device is target */ ++ WL_PROXD_SESSION_FLAG_ONE_WAY = 0x00000004, /**< (initiated) 1-way rtt */ ++ WL_PROXD_SESSION_FLAG_AUTO_BURST = 0x00000008, /**< created w/ rx_auto_burst */ ++ WL_PROXD_SESSION_FLAG_PERSIST = 0x00000010, /**< good until cancelled */ ++ WL_PROXD_SESSION_FLAG_RTT_DETAIL = 0x00000020, /**< rtt detail in results */ ++ WL_PROXD_SESSION_FLAG_SECURE = 0x00000040, /**< sessionis secure */ ++ WL_PROXD_SESSION_FLAG_AOA = 0x00000080, /**< AOA along w/ RTT */ ++ WL_PROXD_SESSION_FLAG_RX_AUTO_BURST = 0x00000100, /**< Same as proxd flags above */ ++ WL_PROXD_SESSION_FLAG_TX_AUTO_BURST = 0x00000200, /**< Same as proxd flags above */ ++ WL_PROXD_SESSION_FLAG_NAN_BSS = 0x00000400, /**< Use NAN BSS, if applicable */ ++ WL_PROXD_SESSION_FLAG_TS1 = 0x00000800, /**< e.g. FTM1 - ASAP-capable */ ++ WL_PROXD_SESSION_FLAG_REPORT_FAILURE = 0x00002000, /**< report failure to target */ ++ WL_PROXD_SESSION_FLAG_INITIATOR_RPT = 0x00004000, /**< report distance to target */ ++ WL_PROXD_SESSION_FLAG_NOCHANSWT = 0x00008000, ++ WL_PROXD_SESSION_FLAG_NETRUAL = 0x00010000, /**< netrual mode */ ++ WL_PROXD_SESSION_FLAG_SEQ_EN = 0x00020000, /**< Toast */ ++ WL_PROXD_SESSION_FLAG_NO_PARAM_OVRD = 0x00040000, /**< no param override from target */ ++ WL_PROXD_SESSION_FLAG_ASAP = 0x00080000, /**< ASAP session */ ++ WL_PROXD_SESSION_FLAG_REQ_LCI = 0x00100000, /**< transmit LCI req */ ++ WL_PROXD_SESSION_FLAG_REQ_CIV = 0x00200000, /**< transmit civic loc req */ ++ WL_PROXD_SESSION_FLAG_PRE_SCAN = 0x00400000, /* enable pre-scan for asap=1 */ ++ WL_PROXD_SESSION_FLAG_AUTO_VHTACK = 0x00800000, /* use vhtack based on brcm ie */ ++ WL_PROXD_SESSION_FLAG_VHTACK = 0x01000000, /* vht ack is in use - output only */ ++ WL_PROXD_SESSION_FLAG_BDUR_NOPREF = 0x02000000, /* burst-duration: no preference */ ++ WL_PROXD_SESSION_FLAG_NUM_FTM_NOPREF = 0x04000000, /* num of FTM frames: no preference */ ++ WL_PROXD_SESSION_FLAG_FTM_SEP_NOPREF = 0x08000000, /* time btw FTM frams: no pref */ ++ WL_PROXD_SESSION_FLAG_NUM_BURST_NOPREF = 0x10000000, /* num of bursts: no pref */ ++ WL_PROXD_SESSION_FLAG_BURST_PERIOD_NOPREF = 0x20000000, /* burst period: no pref */ ++ WL_PROXD_SESSION_FLAG_MBURST_FOLLOWUP = 0x40000000, /* new mburst algo - reserved */ ++ WL_PROXD_SESSION_FLAG_MBURST_NODELAY = 0x80000000, /**< good until cancelled */ ++ WL_PROXD_SESSION_FLAG_ALL = 0xffffffff ++ ++}; ++typedef uint32 wl_proxd_session_flags_t; ++ ++/** time units - mc supports up to 0.1ns resolution */ ++enum { ++ WL_PROXD_TMU_TU = 0, /**< 1024us */ ++ WL_PROXD_TMU_SEC = 1, ++ WL_PROXD_TMU_MILLI_SEC = 2, ++ WL_PROXD_TMU_MICRO_SEC = 3, ++ WL_PROXD_TMU_NANO_SEC = 4, ++ WL_PROXD_TMU_PICO_SEC = 5 ++}; ++typedef int16 wl_proxd_tmu_t; ++ ++/** time interval e.g. 10ns */ ++typedef struct wl_proxd_intvl { ++ uint32 intvl; ++ wl_proxd_tmu_t tmu; ++ uint8 pad[2]; ++} wl_proxd_intvl_t; ++ ++/** commands that can apply to proxd, method or a session */ ++enum { ++ WL_PROXD_CMD_NONE = 0, ++ WL_PROXD_CMD_GET_VERSION = 1, ++ WL_PROXD_CMD_ENABLE = 2, ++ WL_PROXD_CMD_DISABLE = 3, ++ WL_PROXD_CMD_CONFIG = 4, ++ WL_PROXD_CMD_START_SESSION = 5, ++ WL_PROXD_CMD_BURST_REQUEST = 6, ++ WL_PROXD_CMD_STOP_SESSION = 7, ++ WL_PROXD_CMD_DELETE_SESSION = 8, ++ WL_PROXD_CMD_GET_RESULT = 9, ++ WL_PROXD_CMD_GET_INFO = 10, ++ WL_PROXD_CMD_GET_STATUS = 11, ++ WL_PROXD_CMD_GET_SESSIONS = 12, ++ WL_PROXD_CMD_GET_COUNTERS = 13, ++ WL_PROXD_CMD_CLEAR_COUNTERS = 14, ++ WL_PROXD_CMD_COLLECT = 15, /* not supported, see 'wl proxd_collect' */ ++ WL_PROXD_CMD_TUNE = 16, /* not supported, see 'wl proxd_tune' */ ++ WL_PROXD_CMD_DUMP = 17, ++ WL_PROXD_CMD_START_RANGING = 18, ++ WL_PROXD_CMD_STOP_RANGING = 19, ++ WL_PROXD_CMD_GET_RANGING_INFO = 20, ++ WL_PROXD_CMD_IS_TLV_SUPPORTED = 21, ++ ++ WL_PROXD_CMD_MAX ++}; ++typedef int16 wl_proxd_cmd_t; ++ ++/* session ids: ++ * id 0 is reserved ++ * ids 1..0x7fff - allocated by host/app ++ * 0x8000-0xffff - allocated by firmware, used for auto/rx ++ */ ++enum { ++ WL_PROXD_SESSION_ID_GLOBAL = 0 ++}; ++ ++/* Externally allocated sids */ ++#define WL_PROXD_SID_EXT_MAX 0x7fff ++#define WL_PROXD_SID_EXT_ALLOC(_sid) ((_sid) > 0 && (_sid) <= WL_PROXD_SID_EXT_MAX) ++ ++/* block size for reserved sid blocks */ ++#define WL_PROXD_SID_EXT_BLKSZ 256 ++#define WL_PROXD_SID_EXT_BLK_START(_i) (WL_PROXD_SID_EXT_MAX - (_i) * WL_PROXD_SID_EXT_BLKSZ + 1) ++#define WL_PROXD_SID_EXT_BLK_END(_start) ((_start) + WL_PROXD_SID_EXT_BLKSZ - 1) ++ ++/* rrm block */ ++#define WL_PROXD_SID_RRM_START WL_PROXD_SID_EXT_BLK_START(1) ++#define WL_PROXD_SID_RRM_END WL_PROXD_SID_EXT_BLK_END(WL_PROXD_SID_RRM_START) ++ ++/* nan block */ ++#define WL_PROXD_SID_NAN_START WL_PROXD_SID_EXT_BLK_START(2) ++#define WL_PROXD_SID_NAN_END WL_PROXD_SID_EXT_BLK_END(WL_PROXD_SID_NAN_START) ++ ++/** maximum number sessions that can be allocated, may be less if tunable */ ++#define WL_PROXD_MAX_SESSIONS 16 ++ ++typedef uint16 wl_proxd_session_id_t; ++ ++/** status - TBD BCME_ vs proxd status - range reserved for BCME_ */ ++enum { ++ WL_PROXD_E_NOAVAIL = -1056, ++ WL_PROXD_E_EXT_SCHED = -1055, ++ WL_PROXD_E_NOT_BCM = -1054, ++ WL_PROXD_E_FRAME_TYPE = -1053, ++ WL_PROXD_E_VERNOSUPPORT = -1052, ++ WL_PROXD_E_SEC_NOKEY = -1051, ++ WL_PROXD_E_SEC_POLICY = -1050, ++ WL_PROXD_E_SCAN_INPROCESS = -1049, ++ WL_PROXD_E_BAD_PARTIAL_TSF = -1048, ++ WL_PROXD_E_SCANFAIL = -1047, ++ WL_PROXD_E_NOTSF = -1046, ++ WL_PROXD_E_POLICY = -1045, ++ WL_PROXD_E_INCOMPLETE = -1044, ++ WL_PROXD_E_OVERRIDDEN = -1043, ++ WL_PROXD_E_ASAP_FAILED = -1042, ++ WL_PROXD_E_NOTSTARTED = -1041, ++ WL_PROXD_E_INVALIDMEAS = -1040, ++ WL_PROXD_E_INCAPABLE = -1039, ++ WL_PROXD_E_MISMATCH = -1038, ++ WL_PROXD_E_DUP_SESSION = -1037, ++ WL_PROXD_E_REMOTE_FAIL = -1036, ++ WL_PROXD_E_REMOTE_INCAPABLE = -1035, ++ WL_PROXD_E_SCHED_FAIL = -1034, ++ WL_PROXD_E_PROTO = -1033, ++ WL_PROXD_E_EXPIRED = -1032, ++ WL_PROXD_E_TIMEOUT = -1031, ++ WL_PROXD_E_NOACK = -1030, ++ WL_PROXD_E_DEFERRED = -1029, ++ WL_PROXD_E_INVALID_SID = -1028, ++ WL_PROXD_E_REMOTE_CANCEL = -1027, ++ WL_PROXD_E_CANCELED = -1026, /**< local */ ++ WL_PROXD_E_INVALID_SESSION = -1025, ++ WL_PROXD_E_BAD_STATE = -1024, ++ WL_PROXD_E_ERROR = -1, ++ WL_PROXD_E_OK = 0 ++}; ++typedef int32 wl_proxd_status_t; ++ ++/* proxd errors from phy */ ++#define PROXD_TOF_INIT_ERR_BITS 16 ++ ++enum { ++ WL_PROXD_PHY_ERR_LB_CORR_THRESH = (1 << 0), /* Loopback Correlation threshold */ ++ WL_PROXD_PHY_ERR_RX_CORR_THRESH = (1 << 1), /* Received Correlation threshold */ ++ WL_PROXD_PHY_ERR_LB_PEAK_POWER = (1 << 2), /* Loopback Peak power */ ++ WL_PROXD_PHY_ERR_RX_PEAK_POWER = (1 << 3), /* Received Peak power */ ++ WL_PROXD_PHY_ERR_BITFLIP = (1 << 4), /* Bitflips */ ++ WL_PROXD_PHY_ERR_SNR = (1 << 5), /* SNR */ ++ WL_PROXD_PHY_RX_STRT_WIN_OFF = (1 << 6), /* Receive start window is off */ ++ WL_PROXD_PHY_RX_END_WIN_OFF = (1 << 7), /* Receive End window is off */ ++ WL_PROXD_PHY_ERR_LOW_CONFIDENCE = (1 << 15), /* Low confidence on meas distance */ ++}; ++typedef uint32 wl_proxd_phy_error_t; ++ ++/** session states */ ++enum { ++ WL_PROXD_SESSION_STATE_NONE = 0, ++ WL_PROXD_SESSION_STATE_CREATED = 1, ++ WL_PROXD_SESSION_STATE_CONFIGURED = 2, ++ WL_PROXD_SESSION_STATE_STARTED = 3, ++ WL_PROXD_SESSION_STATE_DELAY = 4, ++ WL_PROXD_SESSION_STATE_USER_WAIT = 5, ++ WL_PROXD_SESSION_STATE_SCHED_WAIT = 6, ++ WL_PROXD_SESSION_STATE_BURST = 7, ++ WL_PROXD_SESSION_STATE_STOPPING = 8, ++ WL_PROXD_SESSION_STATE_ENDED = 9, ++ WL_PROXD_SESSION_STATE_START_WAIT = 10, ++ WL_PROXD_SESSION_STATE_DESTROYING = -1 ++}; ++typedef int16 wl_proxd_session_state_t; ++ ++/** RTT sample flags */ ++enum { ++ WL_PROXD_RTT_SAMPLE_NONE = 0x00, ++ WL_PROXD_RTT_SAMPLE_DISCARD = 0x01 ++}; ++typedef uint8 wl_proxd_rtt_sample_flags_t; ++typedef int16 wl_proxd_rssi_t; ++typedef uint16 wl_proxd_snr_t; ++typedef uint16 wl_proxd_bitflips_t; ++ ++typedef struct wl_proxd_rtt_sample { ++ uint8 id; /**< id for the sample - non-zero */ ++ wl_proxd_rtt_sample_flags_t flags; ++ wl_proxd_rssi_t rssi; ++ wl_proxd_intvl_t rtt; /**< round trip time */ ++ uint32 ratespec; ++ wl_proxd_snr_t snr; ++ wl_proxd_bitflips_t bitflips; ++ wl_proxd_status_t status; ++ int32 distance; ++ wl_proxd_phy_error_t tof_phy_error; ++ wl_proxd_phy_error_t tof_tgt_phy_error; /* target phy error bit map */ ++ wl_proxd_snr_t tof_tgt_snr; ++ wl_proxd_bitflips_t tof_tgt_bitflips; ++ uint8 coreid; ++ uint8 pad[3]; ++} wl_proxd_rtt_sample_t; ++ ++/** result flags */ ++enum { ++ WL_PRXOD_RESULT_FLAG_NONE = 0x0000, ++ WL_PROXD_RESULT_FLAG_NLOS = 0x0001, /**< LOS - if available */ ++ WL_PROXD_RESULT_FLAG_LOS = 0x0002, /**< NLOS - if available */ ++ WL_PROXD_RESULT_FLAG_FATAL = 0x0004, /**< Fatal error during burst */ ++ WL_PROXD_RESULT_FLAG_VHTACK = 0x0008, /* VHTACK or Legacy ACK used */ ++ WL_PROXD_REQUEST_SENT = 0x0010, /* FTM request was sent */ ++ WL_PROXD_REQUEST_ACKED = 0x0020, /* FTM request was acked */ ++ WL_PROXD_LTFSEQ_STARTED = 0x0040, /* LTF sequence started */ ++ WL_PROXD_RESULT_FLAG_ALL = 0xffff ++}; ++typedef int16 wl_proxd_result_flags_t; ++ ++/** rtt measurement result */ ++typedef struct wl_proxd_rtt_result { ++ wl_proxd_session_id_t sid; ++ wl_proxd_result_flags_t flags; ++ wl_proxd_status_t status; ++ struct ether_addr peer; ++ wl_proxd_session_state_t state; /**< current state */ ++ union { ++ wl_proxd_intvl_t retry_after; /* hint for errors */ ++ wl_proxd_intvl_t burst_duration; /* burst duration */ ++ } u; ++ wl_proxd_rtt_sample_t avg_rtt; ++ uint32 avg_dist; /* 1/256m units */ ++ uint16 sd_rtt; /* RTT standard deviation */ ++ uint8 num_valid_rtt; /* valid rtt cnt */ ++ uint8 num_ftm; /* actual num of ftm cnt (Configured) */ ++ uint16 burst_num; /* in a session */ ++ uint16 num_rtt; /* 0 if no detail */ ++ uint16 num_meas; /* number of ftm frames seen OTA */ ++ uint8 pad[2]; ++ wl_proxd_rtt_sample_t rtt[1]; /* variable */ ++} wl_proxd_rtt_result_t; ++ ++/** aoa measurement result */ ++typedef struct wl_proxd_aoa_result { ++ wl_proxd_session_id_t sid; ++ wl_proxd_result_flags_t flags; ++ wl_proxd_status_t status; ++ struct ether_addr peer; ++ wl_proxd_session_state_t state; ++ uint16 burst_num; ++ uint8 pad[2]; ++ /* wl_proxd_aoa_sample_t sample_avg; TBD */ ++} BWL_POST_PACKED_STRUCT wl_proxd_aoa_result_t; ++#include ++ ++/** global stats */ ++typedef struct wl_proxd_counters { ++ uint32 tx; /**< tx frame count */ ++ uint32 rx; /**< rx frame count */ ++ uint32 burst; /**< total number of burst */ ++ uint32 sessions; /**< total number of sessions */ ++ uint32 max_sessions; /**< max concurrency */ ++ uint32 sched_fail; /**< scheduling failures */ ++ uint32 timeouts; /**< timeouts */ ++ uint32 protoerr; /**< protocol errors */ ++ uint32 noack; /**< tx w/o ack */ ++ uint32 txfail; /**< any tx falure */ ++ uint32 lci_req_tx; /**< tx LCI requests */ ++ uint32 lci_req_rx; /**< rx LCI requests */ ++ uint32 lci_rep_tx; /**< tx LCI reports */ ++ uint32 lci_rep_rx; /**< rx LCI reports */ ++ uint32 civic_req_tx; /**< tx civic requests */ ++ uint32 civic_req_rx; /**< rx civic requests */ ++ uint32 civic_rep_tx; /**< tx civic reports */ ++ uint32 civic_rep_rx; /**< rx civic reports */ ++ uint32 rctx; /**< ranging contexts created */ ++ uint32 rctx_done; /**< count of ranging done */ ++ uint32 publish_err; /**< availability publishing errors */ ++ uint32 on_chan; /**< count of scheduler onchan */ ++ uint32 off_chan; /**< count of scheduler offchan */ ++ uint32 tsf_lo; /* local tsf or session tsf */ ++ uint32 tsf_hi; ++ uint32 num_meas; ++} wl_proxd_counters_t; ++ ++typedef struct wl_proxd_counters wl_proxd_session_counters_t; ++ ++enum { ++ WL_PROXD_CAP_NONE = 0x0000, ++ WL_PROXD_CAP_ALL = 0xffff ++}; ++typedef int16 wl_proxd_caps_t; ++ ++/** method capabilities */ ++enum { ++ WL_PROXD_FTM_CAP_NONE = 0x0000, ++ WL_PROXD_FTM_CAP_FTM1 = 0x0001 ++}; ++typedef uint16 wl_proxd_ftm_caps_t; ++ ++typedef struct wl_proxd_tlv_id_list { ++ uint16 num_ids; ++ uint16 ids[1]; ++} wl_proxd_tlv_id_list_t; ++ ++typedef struct wl_proxd_session_id_list { ++ uint16 num_ids; ++ wl_proxd_session_id_t ids[1]; ++} wl_proxd_session_id_list_t; ++ ++typedef struct wl_proxd_tpk { ++ struct ether_addr peer; ++ uint8 tpk[TPK_FTM_LEN]; ++} wl_proxd_tpk_t; ++ ++/* tlvs returned for get_info on ftm method ++ * configuration: ++ * proxd flags ++ * event mask ++ * debug mask ++ * session defaults (session tlvs) ++ * status tlv - not supported for ftm method ++ * info tlv ++ */ ++typedef struct wl_proxd_ftm_info { ++ wl_proxd_ftm_caps_t caps; ++ uint16 max_sessions; ++ uint16 num_sessions; ++ uint16 rx_max_burst; ++} wl_proxd_ftm_info_t; ++ ++enum { ++ WL_PROXD_WAIT_NONE = 0x0000, ++ WL_PROXD_WAIT_KEY = 0x0001, ++ WL_PROXD_WAIT_SCHED = 0x0002, ++ WL_PROXD_WAIT_TSF = 0x0004 ++}; ++typedef int16 wl_proxd_wait_reason_t; ++ ++/* tlvs returned for get_info on session ++ * session config (tlvs) ++ * session info tlv ++ */ ++typedef struct wl_proxd_ftm_session_info { ++ uint16 sid; ++ uint8 bss_index; ++ uint8 pad; ++ struct ether_addr bssid; ++ wl_proxd_session_state_t state; ++ wl_proxd_status_t status; ++ uint16 burst_num; ++ wl_proxd_wait_reason_t wait_reason; ++ uint32 meas_start_lo; /* sn tsf of 1st meas for cur/prev burst */ ++ uint32 meas_start_hi; ++} wl_proxd_ftm_session_info_t; ++ ++typedef struct wl_proxd_ftm_session_status { ++ uint16 sid; ++ wl_proxd_session_state_t state; ++ wl_proxd_status_t status; ++ uint16 burst_num; ++ uint16 pad; ++} wl_proxd_ftm_session_status_t; ++ ++/** rrm range request */ ++typedef struct wl_proxd_range_req { ++ uint16 num_repeat; ++ uint16 init_delay_range; /**< in TUs */ ++ uint8 pad; ++ uint8 num_nbr; /**< number of (possible) neighbors */ ++ nbr_element_t nbr[1]; ++} wl_proxd_range_req_t; ++ ++#define WL_PROXD_LCI_LAT_OFF 0 ++#define WL_PROXD_LCI_LONG_OFF 5 ++#define WL_PROXD_LCI_ALT_OFF 10 ++ ++#define WL_PROXD_LCI_GET_LAT(_lci, _lat, _lat_err) { \ ++ unsigned _off = WL_PROXD_LCI_LAT_OFF; \ ++ _lat_err = (_lci)->data[(_off)] & 0x3f; \ ++ _lat = (_lci)->data[(_off)+1]; \ ++ _lat |= (_lci)->data[(_off)+2] << 8; \ ++ _lat |= (_lci)->data[_(_off)+3] << 16; \ ++ _lat |= (_lci)->data[(_off)+4] << 24; \ ++ _lat <<= 2; \ ++ _lat |= (_lci)->data[(_off)] >> 6; \ ++} ++ ++#define WL_PROXD_LCI_GET_LONG(_lci, _lcilong, _long_err) { \ ++ unsigned _off = WL_PROXD_LCI_LONG_OFF; \ ++ _long_err = (_lci)->data[(_off)] & 0x3f; \ ++ _lcilong = (_lci)->data[(_off)+1]; \ ++ _lcilong |= (_lci)->data[(_off)+2] << 8; \ ++ _lcilong |= (_lci)->data[_(_off)+3] << 16; \ ++ _lcilong |= (_lci)->data[(_off)+4] << 24; \ ++ __lcilong <<= 2; \ ++ _lcilong |= (_lci)->data[(_off)] >> 6; \ ++} ++ ++#define WL_PROXD_LCI_GET_ALT(_lci, _alt_type, _alt, _alt_err) { \ ++ unsigned _off = WL_PROXD_LCI_ALT_OFF; \ ++ _alt_type = (_lci)->data[_off] & 0x0f; \ ++ _alt_err = (_lci)->data[(_off)] >> 4; \ ++ _alt_err |= ((_lci)->data[(_off)+1] & 0x03) << 4; \ ++ _alt = (_lci)->data[(_off)+2]; \ ++ _alt |= (_lci)->data[(_off)+3] << 8; \ ++ _alt |= (_lci)->data[_(_off)+4] << 16; \ ++ _alt <<= 6; \ ++ _alt |= (_lci)->data[(_off) + 1] >> 2; \ ++} ++ ++#define WL_PROXD_LCI_VERSION(_lci) ((_lci)->data[15] >> 6) ++ ++/* availability. advertising mechanism bss specific */ ++/** availablity flags */ ++enum { ++ WL_PROXD_AVAIL_NONE = 0, ++ WL_PROXD_AVAIL_NAN_PUBLISHED = 0x0001, ++ WL_PROXD_AVAIL_SCHEDULED = 0x0002 /**< scheduled by proxd */ ++}; ++typedef int16 wl_proxd_avail_flags_t; ++ ++/** time reference */ ++enum { ++ WL_PROXD_TREF_NONE = 0, ++ WL_PROXD_TREF_DEV_TSF = 1, ++ WL_PROXD_TREF_NAN_DW = 2, ++ WL_PROXD_TREF_TBTT = 3, ++ WL_PROXD_TREF_MAX /* last entry */ ++}; ++typedef int16 wl_proxd_time_ref_t; ++ ++/** proxd channel-time slot */ ++typedef struct { ++ wl_proxd_intvl_t start; /**< from ref */ ++ wl_proxd_intvl_t duration; /**< from start */ ++ uint32 chanspec; ++} wl_proxd_time_slot_t; ++ ++typedef struct wl_proxd_avail24 { ++ wl_proxd_avail_flags_t flags; /**< for query only */ ++ wl_proxd_time_ref_t time_ref; ++ uint16 max_slots; /**< for query only */ ++ uint16 num_slots; ++ wl_proxd_time_slot_t slots[1]; /**< ROM compat - not used */ ++ wl_proxd_intvl_t repeat; ++ wl_proxd_time_slot_t ts0[1]; ++} wl_proxd_avail24_t; ++#define WL_PROXD_AVAIL24_TIMESLOT(_avail24, _i) (&(_avail24)->ts0[(_i)]) ++#define WL_PROXD_AVAIL24_TIMESLOT_OFFSET(_avail24) OFFSETOF(wl_proxd_avail24_t, ts0) ++#define WL_PROXD_AVAIL24_TIMESLOTS(_avail24) WL_PROXD_AVAIL24_TIMESLOT(_avail24, 0) ++#define WL_PROXD_AVAIL24_SIZE(_avail24, _num_slots) (\ ++ WL_PROXD_AVAIL24_TIMESLOT_OFFSET(_avail24) + \ ++ (_num_slots) * sizeof(*WL_PROXD_AVAIL24_TIMESLOT(_avail24, 0))) ++ ++typedef struct wl_proxd_avail { ++ wl_proxd_avail_flags_t flags; /**< for query only */ ++ wl_proxd_time_ref_t time_ref; ++ uint16 max_slots; /**< for query only */ ++ uint16 num_slots; ++ wl_proxd_intvl_t repeat; ++ wl_proxd_time_slot_t slots[1]; ++} wl_proxd_avail_t; ++#define WL_PROXD_AVAIL_TIMESLOT(_avail, _i) (&(_avail)->slots[(_i)]) ++#define WL_PROXD_AVAIL_TIMESLOT_OFFSET(_avail) OFFSETOF(wl_proxd_avail_t, slots) ++ ++#define WL_PROXD_AVAIL_TIMESLOTS(_avail) WL_PROXD_AVAIL_TIMESLOT(_avail, 0) ++#define WL_PROXD_AVAIL_SIZE(_avail, _num_slots) (\ ++ WL_PROXD_AVAIL_TIMESLOT_OFFSET(_avail) + \ ++ (_num_slots) * sizeof(*WL_PROXD_AVAIL_TIMESLOT(_avail, 0))) ++ ++/* collect support TBD */ ++ ++/** debugging */ ++enum { ++ WL_PROXD_DEBUG_NONE = 0x00000000, ++ WL_PROXD_DEBUG_LOG = 0x00000001, ++ WL_PROXD_DEBUG_IOV = 0x00000002, ++ WL_PROXD_DEBUG_EVENT = 0x00000004, ++ WL_PROXD_DEBUG_SESSION = 0x00000008, ++ WL_PROXD_DEBUG_PROTO = 0x00000010, ++ WL_PROXD_DEBUG_SCHED = 0x00000020, ++ WL_PROXD_DEBUG_RANGING = 0x00000040, ++ WL_PROXD_DEBUG_NAN = 0x00000080, ++ WL_PROXD_DEBUG_PKT = 0x00000100, ++ WL_PROXD_DEBUG_SEC = 0x00000200, ++ WL_PROXD_DEBUG_EVENTLOG = 0x80000000, /* map/enable EVNET_LOG_TAG_PROXD_INFO */ ++ WL_PROXD_DEBUG_ALL = 0xffffffff ++}; ++typedef uint32 wl_proxd_debug_mask_t; ++ ++/** tlv IDs - data length 4 bytes unless overridden by type, alignment 32 bits */ ++enum { ++ WL_PROXD_TLV_ID_NONE = 0, ++ WL_PROXD_TLV_ID_METHOD = 1, ++ WL_PROXD_TLV_ID_FLAGS = 2, ++ WL_PROXD_TLV_ID_CHANSPEC = 3, /**< note: uint32 */ ++ WL_PROXD_TLV_ID_TX_POWER = 4, ++ WL_PROXD_TLV_ID_RATESPEC = 5, ++ WL_PROXD_TLV_ID_BURST_DURATION = 6, /**< intvl - length of burst */ ++ WL_PROXD_TLV_ID_BURST_PERIOD = 7, /**< intvl - between bursts */ ++ WL_PROXD_TLV_ID_BURST_FTM_SEP = 8, /**< intvl - between FTMs */ ++ WL_PROXD_TLV_ID_BURST_NUM_FTM = 9, /**< uint16 - per burst */ ++ WL_PROXD_TLV_ID_NUM_BURST = 10, /**< uint16 */ ++ WL_PROXD_TLV_ID_FTM_RETRIES = 11, /**< uint16 at FTM level */ ++ WL_PROXD_TLV_ID_BSS_INDEX = 12, /**< uint8 */ ++ WL_PROXD_TLV_ID_BSSID = 13, ++ WL_PROXD_TLV_ID_INIT_DELAY = 14, /**< intvl - optional,non-standalone only */ ++ WL_PROXD_TLV_ID_BURST_TIMEOUT = 15, /**< expect response within - intvl */ ++ WL_PROXD_TLV_ID_EVENT_MASK = 16, /**< interested events - in/out */ ++ WL_PROXD_TLV_ID_FLAGS_MASK = 17, /**< interested flags - in only */ ++ WL_PROXD_TLV_ID_PEER_MAC = 18, /**< mac address of peer */ ++ WL_PROXD_TLV_ID_FTM_REQ = 19, /**< dot11_ftm_req */ ++ WL_PROXD_TLV_ID_LCI_REQ = 20, ++ WL_PROXD_TLV_ID_LCI = 21, ++ WL_PROXD_TLV_ID_CIVIC_REQ = 22, ++ WL_PROXD_TLV_ID_CIVIC = 23, ++ WL_PROXD_TLV_ID_AVAIL24 = 24, /**< ROM compatibility */ ++ WL_PROXD_TLV_ID_SESSION_FLAGS = 25, ++ WL_PROXD_TLV_ID_SESSION_FLAGS_MASK = 26, /**< in only */ ++ WL_PROXD_TLV_ID_RX_MAX_BURST = 27, /**< uint16 - limit bursts per session */ ++ WL_PROXD_TLV_ID_RANGING_INFO = 28, /**< ranging info */ ++ WL_PROXD_TLV_ID_RANGING_FLAGS = 29, /**< uint16 */ ++ WL_PROXD_TLV_ID_RANGING_FLAGS_MASK = 30, /**< uint16, in only */ ++ WL_PROXD_TLV_ID_NAN_MAP_ID = 31, ++ WL_PROXD_TLV_ID_DEV_ADDR = 32, ++ WL_PROXD_TLV_ID_AVAIL = 33, /**< wl_proxd_avail_t */ ++ WL_PROXD_TLV_ID_TLV_ID = 34, /* uint16 tlv-id */ ++ WL_PROXD_TLV_ID_FTM_REQ_RETRIES = 35, /* uint16 FTM request retries */ ++ WL_PROXD_TLV_ID_TPK = 36, /* 32byte TPK */ ++ WL_PROXD_TLV_ID_RI_RR = 36, /* RI_RR */ ++ WL_PROXD_TLV_ID_TUNE = 37, /* wl_proxd_pararms_tof_tune_t */ ++ ++ /* output - 512 + x */ ++ WL_PROXD_TLV_ID_STATUS = 512, ++ WL_PROXD_TLV_ID_COUNTERS = 513, ++ WL_PROXD_TLV_ID_INFO = 514, ++ WL_PROXD_TLV_ID_RTT_RESULT = 515, ++ WL_PROXD_TLV_ID_AOA_RESULT = 516, ++ WL_PROXD_TLV_ID_SESSION_INFO = 517, ++ WL_PROXD_TLV_ID_SESSION_STATUS = 518, ++ WL_PROXD_TLV_ID_SESSION_ID_LIST = 519, ++ ++ /* debug tlvs can be added starting 1024 */ ++ WL_PROXD_TLV_ID_DEBUG_MASK = 1024, ++ WL_PROXD_TLV_ID_COLLECT = 1025, /**< output only */ ++ WL_PROXD_TLV_ID_STRBUF = 1026, ++ ++ WL_PROXD_TLV_ID_COLLECT_HEADER = 1025, /* wl_proxd_collect_header_t */ ++ WL_PROXD_TLV_ID_COLLECT_INFO = 1028, /* wl_proxd_collect_info_t */ ++ WL_PROXD_TLV_ID_COLLECT_DATA = 1029, /* wl_proxd_collect_data_t */ ++ WL_PROXD_TLV_ID_COLLECT_CHAN_DATA = 1030, /* wl_proxd_collect_data_t */ ++ ++ WL_PROXD_TLV_ID_MAX ++}; ++ ++typedef struct wl_proxd_tlv { ++ uint16 id; ++ uint16 len; ++ uint8 data[1]; ++} wl_proxd_tlv_t; ++ ++/** proxd iovar - applies to proxd, method or session */ ++typedef struct wl_proxd_iov { ++ uint16 version; ++ uint16 len; ++ wl_proxd_cmd_t cmd; ++ wl_proxd_method_t method; ++ wl_proxd_session_id_t sid; ++ uint8 PAD[2]; ++ wl_proxd_tlv_t tlvs[1]; /**< variable */ ++} wl_proxd_iov_t; ++ ++#define WL_PROXD_IOV_HDR_SIZE OFFSETOF(wl_proxd_iov_t, tlvs) ++ ++/* The following event definitions may move to bcmevent.h, but sharing proxd types ++ * across needs more invasive changes unrelated to proxd ++ */ ++enum { ++ WL_PROXD_EVENT_NONE = 0, /**< not an event, reserved */ ++ WL_PROXD_EVENT_SESSION_CREATE = 1, ++ WL_PROXD_EVENT_SESSION_START = 2, ++ WL_PROXD_EVENT_FTM_REQ = 3, ++ WL_PROXD_EVENT_BURST_START = 4, ++ WL_PROXD_EVENT_BURST_END = 5, ++ WL_PROXD_EVENT_SESSION_END = 6, ++ WL_PROXD_EVENT_SESSION_RESTART = 7, ++ WL_PROXD_EVENT_BURST_RESCHED = 8, /**< burst rescheduled-e.g. partial TSF */ ++ WL_PROXD_EVENT_SESSION_DESTROY = 9, ++ WL_PROXD_EVENT_RANGE_REQ = 10, ++ WL_PROXD_EVENT_FTM_FRAME = 11, ++ WL_PROXD_EVENT_DELAY = 12, ++ WL_PROXD_EVENT_VS_INITIATOR_RPT = 13, /**< (target) rx initiator-report */ ++ WL_PROXD_EVENT_RANGING = 14, ++ WL_PROXD_EVENT_LCI_MEAS_REP = 15, /* LCI measurement report */ ++ WL_PROXD_EVENT_CIVIC_MEAS_REP = 16, /* civic measurement report */ ++ WL_PROXD_EVENT_COLLECT = 17, ++ WL_PROXD_EVENT_START_WAIT = 18, /* waiting to start */ ++ ++ WL_PROXD_EVENT_MAX ++}; ++typedef int16 wl_proxd_event_type_t; ++ ++/** proxd event mask - upto 32 events for now */ ++typedef uint32 wl_proxd_event_mask_t; ++ ++#define WL_PROXD_EVENT_MASK_ALL 0xfffffffe ++#define WL_PROXD_EVENT_MASK_EVENT(_event_type) (1 << (_event_type)) ++#define WL_PROXD_EVENT_ENABLED(_mask, _event_type) (\ ++ ((_mask) & WL_PROXD_EVENT_MASK_EVENT(_event_type)) != 0) ++ ++/** proxd event - applies to proxd, method or session */ ++typedef struct wl_proxd_event { ++ uint16 version; ++ uint16 len; ++ wl_proxd_event_type_t type; ++ wl_proxd_method_t method; ++ wl_proxd_session_id_t sid; ++ uint8 pad[2]; ++ wl_proxd_tlv_t tlvs[1]; /**< variable */ ++} wl_proxd_event_t; ++ ++enum { ++ WL_PROXD_RANGING_STATE_NONE = 0, ++ WL_PROXD_RANGING_STATE_NOTSTARTED = 1, ++ WL_PROXD_RANGING_STATE_INPROGRESS = 2, ++ WL_PROXD_RANGING_STATE_DONE = 3 ++}; ++typedef int16 wl_proxd_ranging_state_t; ++ ++/** proxd ranging flags */ ++enum { ++ WL_PROXD_RANGING_FLAG_NONE = 0x0000, /**< no flags */ ++ WL_PROXD_RANGING_FLAG_DEL_SESSIONS_ON_STOP = 0x0001, ++ WL_PROXD_RANGING_FLAG_ALL = 0xffff ++}; ++typedef uint16 wl_proxd_ranging_flags_t; ++ ++struct wl_proxd_ranging_info { ++ wl_proxd_status_t status; ++ wl_proxd_ranging_state_t state; ++ wl_proxd_ranging_flags_t flags; ++ uint16 num_sids; ++ uint16 num_done; ++}; ++typedef struct wl_proxd_ranging_info wl_proxd_ranging_info_t; ++ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_event_data { ++ uint32 H_LB[K_TOF_COLLECT_H_SIZE_20MHZ]; ++ uint32 H_RX[K_TOF_COLLECT_H_SIZE_20MHZ]; ++ uint8 ri_rr[FTM_TPK_LEN]; ++ wl_proxd_phy_error_t phy_err_mask; ++} BWL_POST_PACKED_STRUCT wl_proxd_collect_event_data_t; ++#include ++ ++/** Data returned by the bssload_report iovar. This is also the WLC_E_BSS_LOAD event data */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct wl_bssload { ++ uint16 sta_count; /**< station count */ ++ uint16 aac; /**< available admission capacity */ ++ uint8 chan_util; /**< channel utilization */ ++} BWL_POST_PACKED_STRUCT wl_bssload_t; ++#include ++ ++/** ++ * Maximum number of configurable BSS Load levels. The number of BSS Load ++ * ranges is always 1 more than the number of configured levels. eg. if ++ * 3 levels of 10, 20, 30 are configured then this defines 4 load ranges: ++ * 0-10, 11-20, 21-30, 31-255. A WLC_E_BSS_LOAD event is generated each time ++ * the utilization level crosses into another range, subject to the rate limit. ++ */ ++#define MAX_BSSLOAD_LEVELS 8 ++#define MAX_BSSLOAD_RANGES (MAX_BSSLOAD_LEVELS + 1) ++ ++/** BSS Load event notification configuration. */ ++typedef struct wl_bssload_cfg { ++ uint32 rate_limit_msec; /**< # of events posted to application will be limited to ++ * one per specified period (0 to disable rate limit). ++ */ ++ uint8 num_util_levels; /**< Number of entries in util_levels[] below */ ++ uint8 util_levels[MAX_BSSLOAD_LEVELS]; ++ /**< Variable number of BSS Load utilization levels in ++ * low to high order. An event will be posted each time ++ * a received beacon's BSS Load IE channel utilization ++ * value crosses a level. ++ */ ++ uint8 PAD[3]; ++} wl_bssload_cfg_t; ++ ++/** Multiple roaming profile suport */ ++#define WL_MAX_ROAM_PROF_BRACKETS 4 ++ ++#define WL_ROAM_PROF_VER_0 0 ++#define WL_ROAM_PROF_VER_1 1 ++#define WL_MAX_ROAM_PROF_VER WL_ROAM_PROF_VER_1 ++ ++#define WL_ROAM_PROF_NONE (0 << 0) ++#define WL_ROAM_PROF_LAZY (1 << 0) ++#define WL_ROAM_PROF_NO_CI (1 << 1) ++#define WL_ROAM_PROF_SUSPEND (1 << 2) ++#define WL_ROAM_PROF_SYNC_DTIM (1 << 6) ++#define WL_ROAM_PROF_DEFAULT (1 << 7) /**< backward compatible single default profile */ ++ ++#define WL_FACTOR_TABLE_MAX_LIMIT 5 ++ ++#define WL_CU_2G_ROAM_TRIGGER (-60) ++#define WL_CU_5G_ROAM_TRIGGER (-70) ++ ++#define WL_CU_SCORE_DELTA_DEFAULT 20 ++ ++#define WL_MAX_CHANNEL_USAGE 0x0FF ++#define WL_CU_PERCENTAGE_DISABLE 0 ++#define WL_CU_PERCENTAGE_DEFAULT 70 ++#define WL_CU_PERCENTAGE_MAX 100 ++#define WL_CU_CALC_DURATION_DEFAULT 10 /* seconds */ ++#define WL_CU_CALC_DURATION_MAX 60 /* seconds */ ++ ++typedef struct wl_roam_prof_v2 { ++ int8 roam_flags; /**< bit flags */ ++ int8 roam_trigger; /**< RSSI trigger level per profile/RSSI bracket */ ++ int8 rssi_lower; ++ int8 roam_delta; ++ ++ /* if channel_usage if zero, roam_delta is rssi delta required for new AP */ ++ /* if channel_usage if non-zero, roam_delta is score delta(%) required for new AP */ ++ int8 rssi_boost_thresh; /**< Min RSSI to qualify for RSSI boost */ ++ int8 rssi_boost_delta; /**< RSSI boost for AP in the other band */ ++ uint16 nfscan; /**< number of full scan to start with */ ++ uint16 fullscan_period; ++ uint16 init_scan_period; ++ uint16 backoff_multiplier; ++ uint16 max_scan_period; ++ uint8 channel_usage; ++ uint8 cu_avg_calc_dur; ++ uint8 pad[2]; ++} wl_roam_prof_v2_t; ++ ++typedef struct wl_roam_prof_v1 { ++ int8 roam_flags; /**< bit flags */ ++ int8 roam_trigger; /**< RSSI trigger level per profile/RSSI bracket */ ++ int8 rssi_lower; ++ int8 roam_delta; ++ ++ /* if channel_usage if zero, roam_delta is rssi delta required for new AP */ ++ /* if channel_usage if non-zero, roam_delta is score delta(%) required for new AP */ ++ int8 rssi_boost_thresh; /**< Min RSSI to qualify for RSSI boost */ ++ int8 rssi_boost_delta; /**< RSSI boost for AP in the other band */ ++ uint16 nfscan; /**< number of full scan to start with */ ++ uint16 fullscan_period; ++ uint16 init_scan_period; ++ uint16 backoff_multiplier; ++ uint16 max_scan_period; ++} wl_roam_prof_v1_t; ++ ++typedef struct wl_roam_prof_band_v2 { ++ uint32 band; /**< Must be just one band */ ++ uint16 ver; /**< version of this struct */ ++ uint16 len; /**< length in bytes of this structure */ ++ wl_roam_prof_v2_t roam_prof[WL_MAX_ROAM_PROF_BRACKETS]; ++} wl_roam_prof_band_v2_t; ++ ++typedef struct wl_roam_prof_band_v1 { ++ uint32 band; /**< Must be just one band */ ++ uint16 ver; /**< version of this struct */ ++ uint16 len; /**< length in bytes of this structure */ ++ wl_roam_prof_v1_t roam_prof[WL_MAX_ROAM_PROF_BRACKETS]; ++} wl_roam_prof_band_v1_t; ++ ++#define BSS_MAXTABLE_SIZE 10 ++#define WNM_BSS_SELECT_FACTOR_VERSION 1 ++typedef struct wnm_bss_select_factor_params { ++ uint8 low; ++ uint8 high; ++ uint8 factor; ++ uint8 pad; ++} wnm_bss_select_factor_params_t; ++ ++#define WNM_BSS_SELECT_FIXED_SIZE OFFSETOF(wnm_bss_select_factor_cfg_t, params) ++typedef struct wnm_bss_select_factor_cfg { ++ uint8 version; ++ uint8 band; ++ uint16 type; ++ uint16 pad; ++ uint16 count; ++ wnm_bss_select_factor_params_t params[1]; ++} wnm_bss_select_factor_cfg_t; ++ ++#define WNM_BSS_SELECT_WEIGHT_VERSION 1 ++typedef struct wnm_bss_select_weight_cfg { ++ uint8 version; ++ uint8 band; ++ uint16 type; ++ uint16 weight; /* weightage for each type between 0 to 100 */ ++} wnm_bss_select_weight_cfg_t; ++ ++#define WNM_BSS_SELECT_TYPE_RSSI 0 ++#define WNM_BSS_SELECT_TYPE_CU 1 ++ ++#define WNM_BSSLOAD_MONITOR_VERSION 1 ++typedef struct wnm_bssload_monitor_cfg { ++ uint8 version; ++ uint8 band; ++ uint8 duration; /* duration between 1 to 20sec */ ++} wnm_bssload_monitor_cfg_t; ++ ++#define WNM_ROAM_TRIGGER_VERSION 1 ++typedef struct wnm_roam_trigger_cfg { ++ uint8 version; ++ uint8 band; ++ uint16 type; ++ int16 trigger; /* trigger for each type in new roam algorithm */ ++} wnm_roam_trigger_cfg_t; ++ ++/* Data structures for Interface Create/Remove */ ++ ++#define WL_INTERFACE_CREATE_VER (0) ++#define WL_INTERFACE_CREATE_VER_1 1 ++#define WL_INTERFACE_CREATE_VER_2 2 ++#define WL_INTERFACE_CREATE_VER_3 3 ++ ++/* ++ * The flags filed of the wl_interface_create is designed to be ++ * a Bit Mask. As of now only Bit 0 and Bit 1 are used as mentioned below. ++ * The rest of the bits can be used, incase we have to provide ++ * more information to the dongle ++ */ ++ ++/* ++ * Bit 0 of flags field is used to inform whether the interface requested to ++ * be created is STA or AP. ++ * 0 - Create a STA interface ++ * 1 - Create an AP interface ++ * NOTE: This Bit 0 is applicable for the WL_INTERFACE_CREATE_VER < 2 ++ */ ++#define WL_INTERFACE_CREATE_STA (0 << 0) ++#define WL_INTERFACE_CREATE_AP (1 << 0) ++ ++/* ++ * From revision >= 2 Bit 0 of flags field will not used be for STA or AP interface creation. ++ * "iftype" field shall be used for identifying the interface type. ++ */ ++typedef enum wl_interface_type { ++ WL_INTERFACE_TYPE_STA = 0, ++ WL_INTERFACE_TYPE_AP = 1, ++ WL_INTERFACE_TYPE_AWDL = 2, ++ WL_INTERFACE_TYPE_NAN = 3, ++ WL_INTERFACE_TYPE_MAX ++} wl_interface_type_t; ++ ++/* ++ * Bit 1 of flags field is used to inform whether MAC is present in the ++ * data structure or not. ++ * 0 - Ignore mac_addr field ++ * 1 - Use the mac_addr field ++ */ ++#define WL_INTERFACE_MAC_DONT_USE (0 << 1) ++#define WL_INTERFACE_MAC_USE (1 << 1) ++ ++/* ++ * Bit 2 of flags field is used to inform whether core or wlc index ++ * is present in the data structure or not. ++ * 0 - Ignore wlc_index field ++ * 1 - Use the wlc_index field ++ */ ++#define WL_INTERFACE_WLC_INDEX_DONT_USE (0 << 2) ++#define WL_INTERFACE_WLC_INDEX_USE (1 << 2) ++ ++/* ++ * Bit 3 of flags field is used to create interface on the host requested interface index ++ * 0 - Ignore if_index field ++ * 1 - Use the if_index field ++ */ ++#define WL_INTERFACE_IF_INDEX_USE (1 << 3) ++ ++/* ++ * Bit 4 of flags field is used to assign BSSID ++ * 0 - Ignore bssid field ++ * 1 - Use the bssid field ++ */ ++#define WL_INTERFACE_BSSID_INDEX_USE (1 << 4) ++ ++#ifdef WLMESH ++typedef struct wl_interface_info { ++ uint16 ver; /* version of this struct */ ++ struct ether_addr mac_addr; /* MAC address of the interface */ ++ char ifname[BCM_MSG_IFNAME_MAX]; /* name of interface */ ++ uint8 bsscfgidx; /* source bsscfg index */ ++} wl_interface_info_t; ++#endif ++ ++typedef struct wl_interface_create { ++ uint16 ver; /* version of this struct */ ++ uint32 flags; /* flags that defines the operation */ ++ struct ether_addr mac_addr; /* Optional Mac address */ ++} wl_interface_create_t; ++ ++typedef struct wl_interface_create_v1 { ++ uint16 ver; /**< version of this struct */ ++ uint8 pad1[2]; /**< Padding bytes */ ++ uint32 flags; /**< flags that defines the operation */ ++ struct ether_addr mac_addr; /**< Optional Mac address */ ++ uint8 pad2[2]; /**< Padding bytes */ ++ uint32 wlc_index; /**< Optional wlc index */ ++} wl_interface_create_v1_t; ++ ++typedef struct wl_interface_create_v2 { ++ uint16 ver; /**< version of this struct */ ++ uint8 pad1[2]; /**< Padding bytes */ ++ uint32 flags; /**< flags that defines the operation */ ++ struct ether_addr mac_addr; /**< Optional Mac address */ ++ uint8 iftype; /**< Type of interface created */ ++ uint8 pad2; /**< Padding bytes */ ++ uint32 wlc_index; /**< Optional wlc index */ ++} wl_interface_create_v2_t; ++ ++typedef struct wl_interface_create_v3 { ++ uint16 ver; /**< version of this struct */ ++ uint16 len; /**< length of whole structure including variable length */ ++ uint16 fixed_len; /**< Fixed length of this structure excluding data[] */ ++ uint8 iftype; /**< Type of interface created */ ++ uint8 wlc_index; /**< Optional wlc index */ ++ uint32 flags; /**< flags that defines the operation */ ++ struct ether_addr mac_addr; /**< Optional Mac address */ ++ struct ether_addr bssid; /**< Optional BSSID */ ++ uint8 if_index; /**< interface index requested by Host */ ++ uint8 pad[3]; /**< Padding bytes to ensure data[] is at 32 bit aligned */ ++ uint8 data[]; /**< Optional application/Module specific data */ ++} wl_interface_create_v3_t; ++ ++#define WL_INTERFACE_INFO_VER_1 1 ++#define WL_INTERFACE_INFO_VER_2 2 ++ ++typedef struct wl_interface_info_v1 { ++ uint16 ver; /**< version of this struct */ ++ struct ether_addr mac_addr; /**< MAC address of the interface */ ++ char ifname[BCM_MSG_IFNAME_MAX]; /**< name of interface */ ++ uint8 bsscfgidx; /**< source bsscfg index */ ++ uint8 PAD; ++} wl_interface_info_v1_t; ++ ++typedef struct wl_interface_info_v2 { ++ uint16 ver; /**< version of this struct */ ++ uint16 length; /**< length of the whole structure */ ++ struct ether_addr mac_addr; /**< MAC address of the interface */ ++ uint8 bsscfgidx; /**< source bsscfg index */ ++ uint8 if_index; /**< Interface index allocated by FW */ ++ char ifname[BCM_MSG_IFNAME_MAX]; /**< name of interface */ ++} wl_interface_info_v2_t; ++ ++#define PHY_RXIQEST_AVERAGING_DELAY 10 ++ ++typedef struct wl_iqest_params { ++ uint32 rxiq; ++ uint8 niter; ++ uint8 delay; ++ uint8 PAD[2]; ++} wl_iqest_params_t; ++ ++typedef struct wl_iqest_sweep_params { ++ wl_iqest_params_t params; ++ uint8 nchannels; ++ uint8 channel[3]; /** variable */ ++} wl_iqest_sweep_params_t; ++ ++typedef struct wl_iqest_value { ++ uint8 channel; ++ uint8 PAD[3]; ++ uint32 rxiq; ++} wl_iqest_value_t; ++ ++typedef struct wl_iqest_result { ++ uint8 nvalues; ++ uint8 PAD[3]; ++ wl_iqest_value_t value[1]; ++} wl_iqest_result_t; ++ ++/* BTCX AIBSS (Oxygen) Status */ ++typedef struct wlc_btc_aibss_info { ++ uint32 prev_tsf_l; // Lower 32 bits of last read of TSF ++ uint32 prev_tsf_h; // Higher 32 bits of last read of TSF ++ uint32 last_btinfo; // Last read of BT info ++ uint32 local_btinfo; // Local BT INFO BitMap ++ uint8 bt_out_of_sync_cnt; // BT not in sync with strobe ++ uint8 esco_off_cnt; // Count incremented when ESCO is off ++ uint8 strobe_enabled; // Set only in AIBSS mode ++ uint8 strobe_on; // strobe to BT is on for Oxygen ++ uint8 local_bt_in_sync; // Sync status of local BT when strobe is on ++ uint8 other_bt_in_sync; // Sync state of BT in other devices in AIBSS ++ uint8 local_bt_is_master; // Local BT is master ++ uint8 sco_prot_on; // eSCO Protection on in local device ++ uint8 other_esco_present; // eSCO status in other devices in AIBSS ++ uint8 rx_agg_change; // Indicates Rx Agg size needs to change ++ uint8 rx_agg_modified; // Rx Agg size modified ++ uint8 acl_grant_set; // ACL grants on for speeding up sync ++ uint8 write_ie_err_cnt; // BTCX Ie write error cnt ++ uint8 parse_ie_err_cnt; // BTCX IE parse error cnt ++ uint8 wci2_fail_cnt; // WCI2 init failure cnt ++ uint8 strobe_enable_err_cnt; // Strobe enable err cnt ++ uint8 strobe_init_err_cnt; // Strobe init err cnt ++ uint8 tsf_jump_cnt; // TSF jump cnt ++ uint8 acl_grant_cnt; // ALC grant cnt ++ uint8 pad1; ++ uint16 ibss_tsf_shm; // SHM address of strobe TSF ++ uint16 pad2; ++} wlc_btc_aibss_info_t; ++ ++#define WLC_BTC_AIBSS_STATUS_VER 1 ++#define WLC_BTC_AIBSS_STATUS_LEN (sizeof(wlc_btc_aibss_status_t) - 2 * (sizeof(uint16))) ++ ++typedef struct wlc_btc_aibss_status { ++ uint16 version; // Version # ++ uint16 len; // Length of the structure(excluding len & version) ++ int32 mode; // Current value of btc_mode ++ uint16 bth_period; // bt coex period. read from shm. ++ uint16 agg_off_bm; // AGG OFF BM read from SHM ++ uint8 bth_active; // bt active session ++ uint8 pad[3]; ++ wlc_btc_aibss_info_t aibss_info; // Structure definition above ++} wlc_btc_aibss_status_t; ++ ++typedef enum { ++ STATE_NONE = 0, ++ ++ /* WLAN -> BT */ ++ W2B_DATA_SET = 21, ++ B2W_ACK_SET = 22, ++ W2B_DATA_CLEAR = 23, ++ B2W_ACK_CLEAR = 24, ++ ++ /* BT -> WLAN */ ++ B2W_DATA_SET = 31, ++ W2B_ACK_SET = 32, ++ B2W_DATA_CLEAR = 33, ++ W2B_ACK_CLEAR = 34 ++} bwte_gci_intstate_t; ++ ++#define WL_BWTE_STATS_VERSION 1 /* version of bwte_stats_t */ ++typedef struct { ++ uint32 version; ++ ++ bwte_gci_intstate_t inttobt; ++ bwte_gci_intstate_t intfrombt; ++ ++ uint32 bt2wl_intrcnt; /* bt->wlan interrrupt count */ ++ uint32 wl2bt_intrcnt; /* wlan->bt interrupt count */ ++ ++ uint32 wl2bt_dset_cnt; ++ uint32 wl2bt_dclear_cnt; ++ uint32 wl2bt_aset_cnt; ++ uint32 wl2bt_aclear_cnt; ++ ++ uint32 bt2wl_dset_cnt; ++ uint32 bt2wl_dclear_cnt; ++ uint32 bt2wl_aset_cnt; ++ uint32 bt2wl_aclear_cnt; ++ ++ uint32 state_error_1; ++ uint32 state_error_2; ++ uint32 state_error_3; ++ uint32 state_error_4; ++} bwte_stats_t; ++ ++#define TBOW_MAX_SSID_LEN 32 ++#define TBOW_MAX_PASSPHRASE_LEN 63 ++ ++#define WL_TBOW_SETUPINFO_T_VERSION 1 /* version of tbow_setup_netinfo_t */ ++typedef struct tbow_setup_netinfo { ++ uint32 version; ++ uint8 opmode; ++ uint8 pad; ++ uint8 macaddr[ETHER_ADDR_LEN]; ++ uint32 ssid_len; ++ uint8 ssid[TBOW_MAX_SSID_LEN]; ++ uint8 passphrase_len; ++ uint8 passphrase[TBOW_MAX_PASSPHRASE_LEN]; ++ chanspec_t chanspec; ++ uint8 PAD[2]; ++ uint32 channel; ++} tbow_setup_netinfo_t; ++ ++typedef enum tbow_ho_opmode { ++ TBOW_HO_MODE_START_GO = 0, ++ TBOW_HO_MODE_START_STA, ++ TBOW_HO_MODE_START_GC, ++ TBOW_HO_MODE_TEST_GO, ++ TBOW_HO_MODE_STOP_GO = 0x10, ++ TBOW_HO_MODE_STOP_STA, ++ TBOW_HO_MODE_STOP_GC, ++ TBOW_HO_MODE_TEARDOWN ++} tbow_ho_opmode_t; ++ ++/* Beacon trim feature statistics */ ++/* configuration */ ++#define BCNTRIMST_PER 0 /* Number of beacons to trim (0: disable) */ ++#define BCNTRIMST_TIMEND 1 /* Number of bytes till TIM IE */ ++#define BCNTRIMST_TSFLMT 2 /* TSF tolerance value (usecs) */ ++/* internal use */ ++#define BCNTRIMST_CUR 3 /* PSM's local beacon trim counter */ ++#define BCNTRIMST_PREVLEN 4 /* Beacon length excluding the TIM IE */ ++#define BCNTRIMST_TIMLEN 5 /* TIM IE Length */ ++#define BCNTRIMST_RSSI 6 /* Partial beacon RSSI */ ++#define BCNTRIMST_CHAN 7 /* Partial beacon channel */ ++/* debug stat (off by default) */ ++#define BCNTRIMST_DUR 8 /* RX duration until beacon trimmed */ ++#define BCNTRIMST_RXMBSS 9 /* MYBSSID beacon received */ ++#define BCNTRIMST_CANTRIM 10 /* # beacons which were trimmed */ ++#define BCNTRIMST_LENCHG 11 /* # beacons not trimmed due to length change */ ++#define BCNTRIMST_TSFDRF 12 /* # beacons not trimmed due to large TSF delta */ ++#define BCNTRIMST_NOTIM 13 /* # beacons not trimmed due to TIM missing */ ++ ++#define BCNTRIMST_NUM 14 ++ ++#define WL_BCNTRIM_STATUS_VERSION_1 1 ++typedef struct wl_bcntrim_status_query_v1 { ++ uint16 version; ++ uint16 len; /* Total length includes fixed fields */ ++ uint8 reset; /* reset after reading the stats */ ++ uint8 pad[3]; /* 4-byte alignment */ ++} wl_bcntrim_status_query_v1_t; ++ ++typedef struct wl_bcntrim_status_v1 { ++ uint16 version; ++ uint16 len; /* Total length includes fixed fields and variable data[] */ ++ uint8 curr_slice_id; /* slice index of the interface */ ++ uint8 applied_cfg; /* applied bcntrim N threshold */ ++ uint8 pad[2]; /* 4-byte alignment */ ++ uint32 fw_status; /* Bits representing bcntrim disable reason in FW */ ++ uint32 total_disable_dur; /* total duration (msec) bcntrim remains ++ disabled due to FW disable reasons ++ */ ++ uint32 data[]; /* variable length data containing stats */ ++} wl_bcntrim_status_v1_t; ++ ++#define BCNTRIM_STATS_MAX 10 /* Total stats part of the status data[] */ ++ ++/* Bits for FW status */ ++#define WL_BCNTRIM_DISABLE_HOST 0x1 /* Host disabled bcntrim through bcntrim IOVar */ ++#define WL_BCNTRIM_DISABLE_PHY_RATE 0x2 /* bcntrim disabled because beacon rx rate is ++ higher than phy_rate_thresh ++ */ ++#define WL_BCNTRIM_DISABLE_QUIET_IE 0x4 /* bcntrim disable when Quiet IE present */ ++ ++#define WL_BCNTRIM_CFG_VERSION_1 1 ++/* Common IOVAR struct */ ++typedef struct wl_bcntrim_cfg_v1 { ++ uint16 version; ++ uint16 len; /* Total length includes fixed fields and variable data[] */ ++ uint16 subcmd_id; /* subcommand id */ ++ uint16 pad; /* pad/reserved */ ++ uint8 data[]; /* subcommand data; could be empty */ ++} wl_bcntrim_cfg_v1_t; ++ ++/* subcommands ids */ ++enum { ++ WL_BCNTRIM_CFG_SUBCMD_PHY_RATE_THRESH = 0, /* PHY rate threshold above ++ which bcntrim is not applied ++ */ ++ WL_BCNTRIM_CFG_SUBCMD_OVERRIDE_DISABLE_MASK = 1, /* Override bcntrim disable reasons */ ++ WL_BCNTRIM_CFG_SUBCMD_TSF_DRIFT_LIMIT = 2 /* TSF drift limit to consider bcntrim */ ++}; ++ ++#define BCNTRIM_MAX_PHY_RATE 48 /* in 500Kbps */ ++#define BCNTRIM_MAX_TSF_DRIFT 65535 /* in usec */ ++#define WL_BCNTRIM_OVERRIDE_DISABLE_MASK (WL_BCNTRIM_DISABLE_QUIET_IE) ++ ++/* WL_BCNTRIM_CFG_SUBCMD_PHY_RATE_TRESH */ ++typedef struct wl_bcntrim_cfg_phy_rate_thresh { ++ uint32 rate; /* beacon rate (in 500kbps units) */ ++} wl_bcntrim_cfg_phy_rate_thresh_t; ++ ++/* WL_BCNTRIM_CFG_SUBCMD_OVERRIDE_DISABLE_MASK */ ++typedef struct wl_bcntrim_cfg_override_disable_mask { ++ uint32 mask; /* bits representing individual disable reason to override */ ++} wl_bcntrim_cfg_override_disable_mask_t; ++ ++/* WL_BCNTRIM_CFG_SUBCMD_TSF_DRIFT_LIMIT */ ++typedef struct wl_bcntrim_cfg_tsf_drift_limit { ++ uint16 drift; /* tsf drift limit specified in usec */ ++ uint8 pad[2]; /* 4-byte alignment */ ++} wl_bcntrim_cfg_tsf_drift_limit_t; ++ ++ ++/* -------------- TX Power Cap --------------- */ ++#define TXPWRCAP_MAX_NUM_CORES 8 ++#define TXPWRCAP_MAX_NUM_ANTENNAS (TXPWRCAP_MAX_NUM_CORES * 2) ++ ++#define TXPWRCAP_NUM_SUBBANDS 5 ++ ++/* IOVAR txcapconfig enum's */ ++#define TXPWRCAPCONFIG_WCI2 0 ++#define TXPWRCAPCONFIG_HOST 1 ++#define TXPWRCAPCONFIG_WCI2_AND_HOST 2 ++ ++/* IOVAR txcapstate enum's */ ++#define TXPWRCAPSTATE_LOW_CAP 0 ++#define TXPWRCAPSTATE_HIGH_CAP 1 ++#define TXPWRCAPSTATE_HOST_LOW_WCI2_LOW_CAP 0 ++#define TXPWRCAPSTATE_HOST_LOW_WCI2_HIGH_CAP 1 ++#define TXPWRCAPSTATE_HOST_HIGH_WCI2_LOW_CAP 2 ++#define TXPWRCAPSTATE_HOST_HIGH_WCI2_HIGH_CAP 3 ++ ++/* IOVAR txcapconfig and txcapstate structure is shared: SET and GET */ ++#define TXPWRCAPCTL_VERSION 2 ++typedef struct wl_txpwrcap_ctl { ++ uint8 version; ++ uint8 ctl[TXPWRCAP_NUM_SUBBANDS]; ++} wl_txpwrcap_ctl_t; ++ ++/* IOVAR txcapdump structure: GET only */ ++#define TXPWRCAP_DUMP_VERSION 2 ++typedef struct wl_txpwrcap_dump { ++ uint8 version; ++ uint8 pad0; ++ uint8 current_country[2]; ++ uint32 current_channel; ++ uint8 config[TXPWRCAP_NUM_SUBBANDS]; ++ uint8 state[TXPWRCAP_NUM_SUBBANDS]; ++ uint8 high_cap_state_enabled; ++ uint8 wci2_cell_status_last; ++ uint8 download_present; ++ uint8 num_subbands; ++ uint8 num_antennas; ++ uint8 num_antennas_per_core[TXPWRCAP_MAX_NUM_CORES]; ++ uint8 num_cc_groups; ++ uint8 current_country_cc_group_info_index; ++ int8 low_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS]; ++ int8 high_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS]; ++ uint8 PAD[3]; ++} wl_txpwrcap_dump_t; ++ ++typedef struct wl_txpwrcap_dump_v3 { ++ uint8 version; ++ uint8 pad0; ++ uint8 current_country[2]; ++ uint32 current_channel; ++ uint8 config[TXPWRCAP_NUM_SUBBANDS]; ++ uint8 state[TXPWRCAP_NUM_SUBBANDS]; ++ uint8 high_cap_state_enabled; ++ uint8 wci2_cell_status_last; ++ uint8 download_present; ++ uint8 num_subbands; ++ uint8 num_antennas; ++ uint8 num_antennas_per_core[TXPWRCAP_MAX_NUM_CORES]; ++ uint8 num_cc_groups; ++ uint8 current_country_cc_group_info_index; ++ uint8 cap_states_per_cc_group; ++ int8 host_low_wci2_low_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS]; ++ int8 host_low_wci2_high_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS]; ++ int8 host_high_wci2_low_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS]; ++ int8 host_high_wci2_high_cap[TXPWRCAP_MAX_NUM_ANTENNAS*TXPWRCAP_NUM_SUBBANDS]; ++ uint8 PAD[2]; ++} wl_txpwrcap_dump_v3_t; ++ ++typedef struct wl_txpwrcap_tbl { ++ uint8 num_antennas_per_core[TXPWRCAP_MAX_NUM_CORES]; ++ /* Stores values for valid antennas */ ++ int8 pwrcap_cell_on[TXPWRCAP_MAX_NUM_ANTENNAS]; /* qdBm units */ ++ int8 pwrcap_cell_off[TXPWRCAP_MAX_NUM_ANTENNAS]; /* qdBm units */ ++} wl_txpwrcap_tbl_t; ++ ++/* ##### Ecounters section ##### */ ++#define ECOUNTERS_VERSION_1 1 ++ ++/* Input structure for ecounters IOVAR */ ++typedef struct ecounters_config_request { ++ uint16 version; /* config version */ ++ uint16 set; /* Set where data will go. */ ++ uint16 size; /* Size of the set. */ ++ uint16 timeout; /* timeout in seconds. */ ++ uint16 num_events; /* Number of events to report. */ ++ uint16 ntypes; /* Number of entries in type array. */ ++ uint16 type[1]; /* Statistics Types (tags) to retrieve. */ ++} ecounters_config_request_t; ++ ++#define ECOUNTERS_EVENTMSGS_VERSION_1 1 ++#define ECOUNTERS_TRIGGER_CONFIG_VERSION_1 1 ++ ++#define ECOUNTERS_EVENTMSGS_EXT_MASK_OFFSET \ ++ OFFSETOF(ecounters_eventmsgs_ext_t, mask[0]) ++ ++#define ECOUNTERS_TRIG_CONFIG_TYPE_OFFSET \ ++ OFFSETOF(ecounters_trigger_config_t, type[0]) ++ ++typedef struct ecounters_eventmsgs_ext { ++ uint8 version; ++ uint8 len; ++ uint8 mask[1]; ++} ecounters_eventmsgs_ext_t; ++ ++typedef struct ecounters_trigger_config { ++ uint16 version; /* version */ ++ uint16 set; /* set where data should go */ ++ uint16 rsvd; /* reserved */ ++ uint16 pad; /* pad/reserved */ ++ uint16 ntypes; /* number of types/tags */ ++ uint16 type[1]; /* list of types */ ++} ecounters_trigger_config_t; ++ ++#define ECOUNTERS_TRIGGER_REASON_VERSION_1 1 ++/* Triggered due to timer based ecounters */ ++#define ECOUNTERS_TRIGGER_REASON_TIMER 0 ++/* Triggered due to event based configuration */ ++#define ECOUNTERS_TRIGGER_REASON_EVENTS 1 ++#define ECOUNTERS_TRIGGER_REASON_MAX 1 ++ ++typedef struct ecounters_trigger_reason { ++ uint16 version; /* version */ ++ uint16 trigger_reason; /* trigger reason */ ++ uint32 sub_reason_code; /* sub reason code */ ++ uint32 trigger_time_now; /* time in ms at trigger */ ++ uint32 host_ref_time; /* host ref time */ ++} ecounters_trigger_reason_t; ++ ++#define WL_LQM_VERSION_1 1 ++ ++/* For wl_lqm_t flags field */ ++#define WL_LQM_CURRENT_BSS_VALID 0x1 ++#define WL_LQM_TARGET_BSS_VALID 0x2 ++ ++typedef struct { ++ struct ether_addr BSSID; ++ chanspec_t chanspec; ++ int32 rssi; ++ int32 snr; ++} wl_rx_signal_metric_t; ++ ++typedef struct { ++ uint8 version; ++ uint8 flags; ++ uint16 pad; ++ int32 noise_level; /* current noise level */ ++ wl_rx_signal_metric_t current_bss; ++ wl_rx_signal_metric_t target_bss; ++} wl_lqm_t; ++ ++/* ##### Ecounters v2 section ##### */ ++ ++#define ECOUNTERS_VERSION_2 2 ++ ++/* Enumeration of various ecounters request types. This namespace is different from ++ * global reportable stats namespace. ++*/ ++enum { ++ WL_ECOUNTERS_XTLV_REPORT_REQ = 1 ++}; ++ ++/* Input structure for ecounters IOVAR */ ++typedef struct ecounters_config_request_v2 { ++ uint16 version; /* config version */ ++ uint16 len; /* Length of this struct including variable len */ ++ uint16 logset; /* Set where data will go. */ ++ uint16 reporting_period; /* reporting_period */ ++ uint16 num_reports; /* Number of timer expirations to report on */ ++ uint8 pad[2]; /* Reserved for future use */ ++ uint8 ecounters_xtlvs[]; /* Statistics Types (tags) to retrieve. */ ++} ecounters_config_request_v2_t; ++ ++#define ECOUNTERS_STATS_TYPES_FLAG_SLICE 0x1 ++#define ECOUNTERS_STATS_TYPES_FLAG_IFACE 0x2 ++#define ECOUNTERS_STATS_TYPES_FLAG_GLOBAL 0x4 ++ ++/* Slice mask bits */ ++#define ECOUNTERS_STATS_TYPES_SLICE_MASK_SLICE0 0x1 ++#define ECOUNTERS_STATS_TYPES_SLICE_MASK_SLICE1 0x2 ++ ++typedef struct ecounters_stats_types_report_req { ++ /* flags: bit0 = slice, bit1 = iface, bit2 = global, ++ * rest reserved ++ */ ++ uint16 flags; ++ uint16 if_index; /* host interface index */ ++ uint16 slice_mask; /* bit0 = slice0, bit1=slice1, rest reserved */ ++ uint8 pad[2]; /* padding */ ++ uint8 stats_types_req[]; /* XTLVs of requested types */ ++} ecounters_stats_types_report_req_t; ++ ++/* -------------- dynamic BTCOEX --------------- */ ++#define DCTL_TROWS 2 /**< currently practical number of rows */ ++#define DCTL_TROWS_MAX 4 /**< 2 extra rows RFU */ ++/* DYNCTL profile flags */ ++#define DCTL_FLAGS_DISABLED 0 /**< default value: all features disabled */ ++#define DCTL_FLAGS_DYNCTL (1 << 0) /**< 1 - enabled, 0 - legacy only */ ++#define DCTL_FLAGS_DESENSE (1 << 1) /**< auto desense is enabled */ ++#define DCTL_FLAGS_MSWITCH (1 << 2) /**< mode switching is enabled */ ++#define DCTL_FLAGS_PWRCTRL (1 << 3) /**< Tx power control is enabled */ ++/* for now AGG on/off is handled separately */ ++#define DCTL_FLAGS_TX_AGG_OFF (1 << 4) /**< TBD: allow TX agg Off */ ++#define DCTL_FLAGS_RX_AGG_OFF (1 << 5) /**< TBD: allow RX agg Off */ ++/* used for dry run testing only */ ++#define DCTL_FLAGS_DRYRUN (1 << 7) /**< Enables dynctl dry run mode */ ++#define IS_DYNCTL_ON(prof) ((prof->flags & DCTL_FLAGS_DYNCTL) != 0) ++#define IS_DESENSE_ON(prof) ((prof->flags & DCTL_FLAGS_DESENSE) != 0) ++#define IS_MSWITCH_ON(prof) ((prof->flags & DCTL_FLAGS_MSWITCH) != 0) ++#define IS_PWRCTRL_ON(prof) ((prof->flags & DCTL_FLAGS_PWRCTRL) != 0) ++/* desense level currently in use */ ++#define DESENSE_OFF 0 ++#define DFLT_DESENSE_MID 12 ++#define DFLT_DESENSE_HIGH 2 ++ ++/** ++ * dynctl data points(a set of btpwr & wlrssi thresholds) ++ * for mode & desense switching ++ */ ++typedef struct btc_thr_data { ++ int8 mode; /**< used by desense sw */ ++ int8 bt_pwr; /**< BT tx power threshold */ ++ int8 bt_rssi; /**< BT rssi threshold */ ++ /* wl rssi range when mode or desense change may be needed */ ++ int8 wl_rssi_high; ++ int8 wl_rssi_low; ++} btc_thr_data_t; ++ ++/* dynctl. profile data structure */ ++#define DCTL_PROFILE_VER 0x01 ++#include ++typedef BWL_PRE_PACKED_STRUCT struct dctl_prof { ++ uint8 version; /**< dynctl profile version */ ++ /* dynctl profile flags bit:0 - dynctl On, bit:1 dsns On, bit:2 mode sw On, */ ++ uint8 flags; /**< bit[6:3] reserved, bit7 - Dryrun (sim) - On */ ++ /** wl desense levels to apply */ ++ uint8 dflt_dsns_level; ++ uint8 low_dsns_level; ++ uint8 mid_dsns_level; ++ uint8 high_dsns_level; ++ /** mode switching hysteresis in dBm */ ++ int8 msw_btrssi_hyster; ++ /** default btcoex mode */ ++ uint8 default_btc_mode; ++ /** num of active rows in mode switching table */ ++ uint8 msw_rows; ++ /** num of rows in desense table */ ++ uint8 dsns_rows; ++ /** dynctl mode switching data table */ ++ btc_thr_data_t msw_data[DCTL_TROWS_MAX]; ++ /** dynctl desense switching data table */ ++ btc_thr_data_t dsns_data[DCTL_TROWS_MAX]; ++} BWL_POST_PACKED_STRUCT dctl_prof_t; ++#include ++ ++/** dynctl status info */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct dynctl_status { ++ uint8 sim_on; /**< true if simulation is On */ ++ uint16 bt_pwr_shm; /**< BT per/task power as read from ucode */ ++ int8 bt_pwr; /**< BT pwr extracted & converted to dBm */ ++ int8 bt_rssi; /**< BT rssi in dBm */ ++ int8 wl_rssi; /**< last wl rssi reading used by btcoex */ ++ uint8 dsns_level; /**< current desense level */ ++ uint8 btc_mode; /**< current btcoex mode */ ++ /* add more status items if needed, pad to 4 BB if needed */ ++} BWL_POST_PACKED_STRUCT dynctl_status_t; ++#include ++ ++/** dynctl simulation (dryrun data) */ ++#include ++typedef BWL_PRE_PACKED_STRUCT struct dynctl_sim { ++ uint8 sim_on; /**< simulation mode on/off */ ++ int8 btpwr; /**< simulated BT power in dBm */ ++ int8 btrssi; /**< simulated BT rssi in dBm */ ++ int8 wlrssi; /**< simulated WL rssi in dBm */ ++} BWL_POST_PACKED_STRUCT dynctl_sim_t; ++/* no default structure packing */ ++#include ++ ++/** PTK key maintained per SCB */ ++#define RSN_TEMP_ENCR_KEY_LEN 16 ++typedef struct wpa_ptk { ++ uint8 kck[RSN_KCK_LENGTH]; /**< EAPOL-Key Key Confirmation Key (KCK) */ ++ uint8 kek[RSN_KEK_LENGTH]; /**< EAPOL-Key Key Encryption Key (KEK) */ ++ uint8 tk1[RSN_TEMP_ENCR_KEY_LEN]; /**< Temporal Key 1 (TK1) */ ++ uint8 tk2[RSN_TEMP_ENCR_KEY_LEN]; /**< Temporal Key 2 (TK2) */ ++} wpa_ptk_t; ++ ++/** GTK key maintained per SCB */ ++typedef struct wpa_gtk { ++ uint32 idx; ++ uint32 key_len; ++ uint8 key[DOT11_MAX_KEY_SIZE]; ++} wpa_gtk_t; ++ ++/** FBT Auth Response Data structure */ ++typedef struct wlc_fbt_auth_resp { ++ uint8 macaddr[ETHER_ADDR_LEN]; /**< station mac address */ ++ uint8 pad[2]; ++ uint8 pmk_r1_name[WPA2_PMKID_LEN]; ++ wpa_ptk_t ptk; /**< pairwise key */ ++ wpa_gtk_t gtk; /**< group key */ ++ uint32 ie_len; ++ uint8 status; /**< Status of parsing FBT authentication ++ Request in application ++ */ ++ uint8 ies[1]; /**< IEs contains MDIE, RSNIE, ++ FBTIE (ANonce, SNonce,R0KH-ID, R1KH-ID) ++ */ ++} wlc_fbt_auth_resp_t; ++ ++/** FBT Action Response frame */ ++typedef struct wlc_fbt_action_resp { ++ uint16 version; /**< structure version */ ++ uint16 length; /**< length of structure */ ++ uint8 macaddr[ETHER_ADDR_LEN]; /**< station mac address */ ++ uint8 data_len; /**< len of ie from Category */ ++ uint8 data[1]; /**< data contains category, action, sta address, target ap, ++ status code,fbt response frame body ++ */ ++} wlc_fbt_action_resp_t; ++ ++#define MACDBG_PMAC_ADDR_INPUT_MAXNUM 16 ++#define MACDBG_PMAC_OBJ_TYPE_LEN 8 ++ ++typedef struct _wl_macdbg_pmac_param_t { ++ char type[MACDBG_PMAC_OBJ_TYPE_LEN]; ++ uint8 step; ++ uint8 w_en; ++ uint16 num; ++ uint32 bitmap; ++ uint8 addr_raw; ++ uint8 addr_num; ++ uint16 addr[MACDBG_PMAC_ADDR_INPUT_MAXNUM]; ++ uint8 pad0[2]; ++ uint32 w_val; ++} wl_macdbg_pmac_param_t; ++ ++/** IOVAR 'svmp_sampcol' parameter. Used to set and read SVMP_SAMPLE_COLLECT's setting */ ++typedef struct wl_svmp_sampcol_param { ++ uint32 version; /* version */ ++ uint8 enable; ++ uint8 trigger_mode; /* SVMP_SAMPCOL_TRIGGER */ ++ uint8 trigger_mode_s[2]; /* SVMP_SAMPCOL_PKTPROC */ ++ uint8 data_samplerate; /* SVMP_SAMPCOL_SAMPLERATE */ ++ uint8 data_sel_phy1; /* SVMP_SAMPCOL_PHY1MUX */ ++ uint8 data_sel_rx1; /* SVMP_SAMPCOL_RX1MUX without iqCompOut */ ++ uint8 data_sel_dualcap; /* SVMP_SAMPCOL_RX1MUX */ ++ uint8 pack_mode; /* SVMP_SAMPCOL_PACK */ ++ uint8 pack_order; ++ uint8 pack_cfix_fmt; ++ uint8 pack_1core_sel; ++ uint16 waitcnt; ++ uint16 caplen; ++ uint32 buff_addr_start; /* in word-size (2-bytes) */ ++ uint32 buff_addr_end; /* note: Tcl in byte-size, HW in vector-size (8-bytes) */ ++ uint8 int2vasip; ++ uint8 PAD; ++ uint16 status; ++} wl_svmp_sampcol_t; ++ ++#define WL_SVMP_SAMPCOL_PARAMS_VERSION 1 ++ ++enum { ++ SVMP_SAMPCOL_TRIGGER_PKTPROC_TRANSITION = 0, ++ SVMP_SAMPCOL_TRIGGER_FORCE_IMMEDIATE, ++ SVMP_SAMPCOL_TRIGGER_RADAR_DET ++}; ++ ++enum { ++ SVMP_SAMPCOL_PHY1MUX_GPIOOUT = 0, ++ SVMP_SAMPCOL_PHY1MUX_FFT, ++ SVMP_SAMPCOL_PHY1MUX_DBGHX, ++ SVMP_SAMPCOL_PHY1MUX_RX1MUX ++}; ++ ++enum { ++ SVMP_SAMPCOL_RX1MUX_FARROWOUT = 4, ++ SVMP_SAMPCOL_RX1MUX_IQCOMPOUT, ++ SVMP_SAMPCOL_RX1MUX_DCFILTEROUT, ++ SVMP_SAMPCOL_RX1MUX_RXFILTEROUT, ++ SVMP_SAMPCOL_RX1MUX_ACIFILTEROUT ++}; ++ ++enum { ++ SVMP_SAMPCOL_SAMPLERATE_1XBW = 0, ++ SVMP_SAMPCOL_SAMPLERATE_2XBW ++}; ++ ++enum { ++ SVMP_SAMPCOL_PACK_DUALCAP = 0, ++ SVMP_SAMPCOL_PACK_4CORE, ++ SVMP_SAMPCOL_PACK_2CORE, ++ SVMP_SAMPCOL_PACK_1CORE ++}; ++ ++enum { ++ SVMP_SAMPCOL_PKTPROC_RESET = 0, ++ SVMP_SAMPCOL_PKTPROC_CARRIER_SEARCH, ++ SVMP_SAMPCOL_PKTPROC_WAIT_FOR_NB_PWR, ++ SVMP_SAMPCOL_PKTPROC_WAIT_FOR_W1_PWR, ++ SVMP_SAMPCOL_PKTPROC_WAIT_FOR_W2_PWR, ++ SVMP_SAMPCOL_PKTPROC_OFDM_PHY, ++ SVMP_SAMPCOL_PKTPROC_TIMING_SEARCH, ++ SVMP_SAMPCOL_PKTPROC_CHAN_EST_1, ++ SVMP_SAMPCOL_PKTPROC_LEG_SIG_DEC, ++ SVMP_SAMPCOL_PKTPROC_SIG_DECODE_1, ++ SVMP_SAMPCOL_PKTPROC_SIG_DECODE_2, ++ SVMP_SAMPCOL_PKTPROC_HT_AGC, ++ SVMP_SAMPCOL_PKTPROC_CHAN_EST_2, ++ SVMP_SAMPCOL_PKTPROC_PAY_DECODE, ++ SVMP_SAMPCOL_PKTPROC_DSSS_CCK_PHY, ++ SVMP_SAMPCOL_PKTPROC_WAIT_ENERGY_DROP, ++ SVMP_SAMPCOL_PKTPROC_WAIT_NCLKS, ++ SVMP_SAMPCOL_PKTPROC_PAY_DEC_EXT, ++ SVMP_SAMPCOL_PKTPROC_SIG_FAIL_DELAY, ++ SVMP_SAMPCOL_PKTPROC_RIFS_SEARCH, ++ SVMP_SAMPCOL_PKTPROC_BOARD_SWITCH_DIV_SEARCH, ++ SVMP_SAMPCOL_PKTPROC_DSSS_CCK_BOARD_SWITCH_DIV_SEARCH, ++ SVMP_SAMPCOL_PKTPROC_CHAN_EST_3, ++ SVMP_SAMPCOL_PKTPROC_CHAN_EST_4, ++ SVMP_SAMPCOL_PKTPROC_FINE_TIMING_SEARCH, ++ SVMP_SAMPCOL_PKTPROC_SET_CLIP_GAIN, ++ SVMP_SAMPCOL_PKTPROC_NAP, ++ SVMP_SAMPCOL_PKTPROC_VHT_SIGA_DEC, ++ SVMP_SAMPCOL_PKTPROC_VHT_SIGB_DEC, ++ SVMP_SAMPCOL_PKTPROC_PKT_ABORT, ++ SVMP_SAMPCOL_PKTPROC_DCCAL ++}; ++ ++/** IOVAR 'svmp_mem' parameter. Used to read/clear svmp memory */ ++typedef struct svmp_mem { ++ uint32 addr; /**< offset to read svmp memory from vasip base address */ ++ uint16 len; /**< length in count of uint16's */ ++ uint16 val; /**< set the range of addr/len with a value */ ++} svmp_mem_t; ++ ++/** IOVAR 'mu_rate' parameter. read/set mu rate for upto four users */ ++#define MU_RATE_CFG_VERSION 1 ++typedef struct mu_rate { ++ uint16 version; /**< version of the structure as defined by MU_RATE_CFG_VERSION */ ++ uint16 length; /**< length of entire structure */ ++ uint8 auto_rate; /**< enable/disable auto rate */ ++ uint8 PAD; ++ uint16 rate_user[4]; /**< rate per each of four users, set to -1 for no change */ ++} mu_rate_t; ++ ++/** IOVAR 'mu_group' parameter. Used to set and read MU group recommendation setting */ ++#define WL_MU_GROUP_AUTO_COMMAND -1 ++#define WL_MU_GROUP_PARAMS_VERSION 3 ++#define WL_MU_GROUP_METHOD_NAMELEN 64 ++#define WL_MU_GROUP_NGROUP_MAX 15 ++#define WL_MU_GROUP_NUSER_MAX 4 ++#define WL_MU_GROUP_METHOD_MIN 0 ++#define WL_MU_GROUP_NUMBER_AUTO_MIN 1 ++#define WL_MU_GROUP_NUMBER_AUTO_MAX 15 ++#define WL_MU_GROUP_NUMBER_FORCED_MAX 8 ++#define WL_MU_GROUP_METHOD_OLD 0 ++#define WL_MU_GROUP_MODE_AUTO 0 ++#define WL_MU_GROUP_MODE_FORCED 1 ++#define WL_MU_GROUP_FORCED_1GROUP 1 ++#define WL_MU_GROUP_ENTRY_EMPTY -1 ++typedef struct mu_group { ++ uint32 version; /* version */ ++ int16 forced; /* forced group recommendation */ ++ int16 forced_group_mcs; /* forced group with mcs */ ++ int16 forced_group_num; /* forced group number */ ++ int16 group_option[WL_MU_GROUP_NGROUP_MAX][WL_MU_GROUP_NUSER_MAX]; ++ /* set mode for forced grouping and read mode for auto grouping */ ++ int16 group_GID[WL_MU_GROUP_NGROUP_MAX]; ++ int16 group_method; /* methof for VASIP group recommendation */ ++ int16 group_number; /* requested number for VASIP group recommendation */ ++ int16 auto_group_num; /* exact number from VASIP group recommendation */ ++ int8 group_method_name[WL_MU_GROUP_METHOD_NAMELEN]; ++ uint8 PAD[2]; ++} mu_group_t; ++ ++typedef struct mupkteng_sta { ++ struct ether_addr ea; ++ uint8 PAD[2]; ++ int32 nrxchain; ++ int32 idx; ++} mupkteng_sta_t; ++ ++typedef struct mupkteng_client { ++ int32 rspec; ++ int32 idx; ++ int32 flen; ++ int32 nframes; ++} mupkteng_client_t; ++ ++typedef struct mupkteng_tx { ++ mupkteng_client_t client[8]; ++ int32 nclients; ++ int32 ntx; ++} mupkteng_tx_t; ++ ++/* ++ * MU Packet engine interface. ++ * The following two definitions will go into ++ * wlioctl_defs.h ++ * when wl utility changes are merged to EAGLE TOB & Trunk ++ */ ++ ++#define WL_MUPKTENG_PER_TX_START 0x10 ++#define WL_MUPKTENG_PER_TX_STOP 0x20 ++ ++/** IOVAR 'mu_policy' parameter. Used to configure MU admission control policies */ ++#define WL_MU_POLICY_PARAMS_VERSION 1 ++#define WL_MU_POLICY_SCHED_DEFAULT 60 ++#define WL_MU_POLICY_DISABLED 0 ++#define WL_MU_POLICY_ENABLED 1 ++#define WL_MU_POLICY_NRX_MIN 1 ++#define WL_MU_POLICY_NRX_MAX 2 ++typedef struct mu_policy { ++ uint16 version; ++ uint16 length; ++ uint32 sched_timer; ++ uint32 pfmon; ++ uint32 pfmon_gpos; ++ uint32 samebw; ++ uint32 nrx; ++ uint32 max_muclients; ++} mu_policy_t; ++ ++#define WL_NAN_BAND_STR_SIZE 5 /* sizeof ("auto") */ ++ ++/** Definitions of different NAN Bands */ ++/* do not change the order */ ++enum { ++ NAN_BAND_B = 0, ++ NAN_BAND_A, ++ NAN_BAND_AUTO, ++ NAN_BAND_INVALID = 0xFF ++}; ++ ++/* ifdef WL11ULB */ ++/* ULB Mode configured via "ulb_mode" IOVAR */ ++enum { ++ ULB_MODE_DISABLED = 0, ++ ULB_MODE_STD_ALONE_MODE = 1, /* Standalone ULB Mode */ ++ ULB_MODE_DYN_MODE = 2, /* Dynamic ULB Mode */ ++ /* Add all other enums before this */ ++ MAX_SUPP_ULB_MODES ++}; ++ ++/* ULB BWs configured via "ulb_bw" IOVAR during Standalone Mode Only. ++ * Values of this enumeration are also used to specify 'Current Operational Bandwidth' ++ * and 'Primary Operational Bandwidth' sub-fields in 'ULB Operations' field (used in ++ * 'ULB Operations' Attribute or 'ULB Mode Switch' Attribute) ++ */ ++typedef enum { ++ ULB_BW_DISABLED = 0, ++ ULB_BW_10MHZ = 1, /* Standalone ULB BW in 10 MHz BW */ ++ ULB_BW_5MHZ = 2, /* Standalone ULB BW in 5 MHz BW */ ++ ULB_BW_2P5MHZ = 3, /* Standalone ULB BW in 2.5 MHz BW */ ++ /* Add all other enums before this */ ++ MAX_SUPP_ULB_BW ++} ulb_bw_type_t; ++/* endif WL11ULB */ ++ ++ ++#define WL_MESH_IOCTL_VERSION 1 ++#define MESH_IOC_BUFSZ 512 /* sufficient ioc buff size for mesh */ ++/* container for mesh iovtls & events */ ++typedef struct wl_mesh_ioc { ++ uint16 version; /* interface command or event version */ ++ uint16 id; /* mesh ioctl cmd ID */ ++ uint16 len; /* total length of all tlv records in data[] */ ++ uint16 pad; /* pad to be 32 bit aligment */ ++ uint8 data[]; /* var len payload of bcm_xtlv_t type */ ++} wl_mesh_ioc_t; ++ ++enum wl_mesh_cmds { ++ WL_MESH_CMD_ENABLE = 1, ++ WL_MESH_CMD_JOIN = 2, ++ WL_MESH_CMD_PEER_STATUS = 3, ++ WL_MESH_CMD_ADD_ROUTE = 4, ++ WL_MESH_CMD_DEL_ROUTE = 5, ++ WL_MESH_CMD_ADD_FILTER = 6, ++ WL_MESH_CMD_ENAB_AL_METRIC = 7 ++}; ++ ++enum wl_mesh_cmd_xtlv_id { ++ WL_MESH_XTLV_ENABLE = 1, ++ WL_MESH_XTLV_JOIN = 2, ++ WL_MESH_XTLV_STATUS = 3, ++ WL_MESH_XTLV_ADD_ROUTE = 4, ++ WL_MESH_XTLV_DEL_ROUTE = 5, ++ WL_MESH_XTLV_ADD_FILTER = 6, ++ WL_MESH_XTLV_ENAB_AIRLINK = 7 ++}; ++/* endif WLMESH */ ++ ++#ifdef WLMESH ++#ifndef SAE_MAX_PASSWD_LEN ++#define SAE_MAX_PASSWD_LEN 32 ++#endif ++#endif ++ ++/* Fast BSS Transition parameter configuration */ ++#define FBT_PARAM_CURRENT_VERSION 0 ++ ++typedef struct _wl_fbt_params { ++ uint16 version; /* version of the structure ++ * as defined by FBT_PARAM_CURRENT_VERSION ++ */ ++ uint16 length; /* length of the entire structure */ ++ ++ uint16 param_type; /* type of parameter defined below */ ++ uint16 param_len; /* length of the param_value */ ++ uint8 param_value[1]; /* variable length */ ++} wl_fbt_params_t; ++ ++#define WL_FBT_PARAM_TYPE_RSNIE 0 ++#define WL_FBT_PARAM_TYPE_FTIE 0x1 ++#define WL_FBT_PARAM_TYPE_SNONCE 0x2 ++#define WL_FBT_PARAM_TYPE_MDE 0x3 ++#define WL_FBT_PARAM_TYPE_PMK_R0_NAME 0x4 ++#define WL_FBT_PARAM_TYPE_R0_KHID 0x5 ++#define WL_FBT_PARAM_TYPE_R1_KHID 0x6 ++#define WL_FBT_PARAM_TYPE_FIRST_INVALID 0x7 ++ ++/* Assoc Mgr commands for fine control of assoc */ ++#define WL_ASSOC_MGR_CURRENT_VERSION 0x0 ++ ++typedef struct { ++ uint16 version; /* version of the structure as ++ * defined by WL_ASSOC_MGR_CURRENT_VERSION ++ */ ++ uint16 length; /* length of the entire structure */ ++ ++ uint16 cmd; ++ uint16 params; ++} wl_assoc_mgr_cmd_t; ++ ++#define WL_ASSOC_MGR_CMD_PAUSE_ON_EVT 0 /* have assoc pause on certain events */ ++#define WL_ASSOC_MGR_CMD_ABORT_ASSOC 1 ++ ++#define WL_ASSOC_MGR_PARAMS_EVENT_NONE 0 /* use this to resume as well as clear */ ++#define WL_ASSOC_MGR_PARAMS_PAUSE_EVENT_AUTH_RESP 1 ++ ++#define WL_WINVER_STRUCT_VER_1 (1) ++ ++typedef struct wl_winver { ++ ++ /* Version and length of this structure. Length includes all fields in wl_winver_t */ ++ uint16 struct_version; ++ uint16 struct_length; ++ ++ /* Windows operating system version info (Microsoft provided) */ ++ struct { ++ uint32 major_ver; ++ uint32 minor_ver; ++ uint32 build; ++ } os_runtime; ++ ++ /* NDIS runtime version (Microsoft provided) */ ++ struct { ++ uint16 major_ver; ++ uint16 minor_ver; ++ } ndis_runtime; ++ ++ /* NDIS Driver version (Broadcom provided) */ ++ struct { ++ uint16 major_ver; ++ uint16 minor_ver; ++ } ndis_driver; ++ ++ /* WDI Upper Edge (UE) Driver version (Microsoft provided) */ ++ struct { ++ uint8 major_ver; ++ uint8 minor_ver; ++ uint8 suffix; ++ } wdi_ue; ++ ++ /* WDI Lower Edge (LE) Driver version (Broadcom provided) */ ++ struct { ++ uint8 major_ver; ++ uint8 minor_ver; ++ uint8 suffix; ++ } wdi_le; ++ uint8 PAD[2]; ++} wl_winver_t; ++ ++/* defined(WLRCC) || defined(ROAM_CHANNEL_CACHE) */ ++#define MAX_ROAM_CHANNEL 20 ++typedef struct { ++ int32 n; ++ chanspec_t channels[MAX_ROAM_CHANNEL]; ++} wl_roam_channel_list_t; ++/* endif RCC || ROAM_CHANNEL_CACHE */ ++ ++/* values for IOV_MFP arg */ ++enum { ++ WL_MFP_NONE = 0, ++ WL_MFP_CAPABLE, ++ WL_MFP_REQUIRED ++}; ++ ++typedef enum { ++ CHANSW_UNKNOWN = 0, /* channel switch due to unknown reason */ ++ CHANSW_SCAN = 1, /* channel switch due to scan */ ++ CHANSW_PHYCAL = 2, /* channel switch due to phy calibration */ ++ CHANSW_INIT = 3, /* channel set at WLC up time */ ++ CHANSW_ASSOC = 4, /* channel switch due to association */ ++ CHANSW_ROAM = 5, /* channel switch due to roam */ ++ CHANSW_MCHAN = 6, /* channel switch triggered by mchan module */ ++ CHANSW_IOVAR = 7, /* channel switch due to IOVAR */ ++ CHANSW_CSA_DFS = 8, /* channel switch due to chan switch announcement from AP */ ++ CHANSW_APCS = 9, /* Channel switch from AP channel select module */ ++ CHANSW_AWDL = 10, /* channel switch due to AWDL */ ++ CHANSW_FBT = 11, /* Channel switch from FBT module for action frame response */ ++ CHANSW_UPDBW = 12, /* channel switch at update bandwidth */ ++ CHANSW_ULB = 13, /* channel switch at ULB */ ++ CHANSW_LAST = 14 /* last channel switch reason */ ++} chansw_reason_t; ++ ++/* ++ * WOWL unassociated mode power svae pattern. ++ */ ++typedef struct wowl_radio_duty_cycle { ++ uint16 wake_interval; ++ uint16 sleep_interval; ++} wowl_radio_duty_cycle_t; ++ ++typedef struct nd_ra_ol_limits { ++ uint16 version; /* version of the iovar buffer */ ++ uint16 type; /* type of data provided */ ++ uint16 length; /* length of the entire structure */ ++ uint16 pad1; /* pad union to 4 byte boundary */ ++ union { ++ struct { ++ uint16 min_time; /* seconds, min time for RA offload hold */ ++ uint16 lifetime_percent; ++ /* percent, lifetime percentage for offload hold time */ ++ } lifetime_relative; ++ struct { ++ uint16 hold_time; /* seconds, RA offload hold time */ ++ uint16 pad2; /* unused */ ++ } fixed; ++ } limits; ++} nd_ra_ol_limits_t; ++ ++#define ND_RA_OL_LIMITS_VER 1 ++ ++/* nd_ra_ol_limits sub-types */ ++#define ND_RA_OL_LIMITS_REL_TYPE 0 /* relative, percent of RA lifetime */ ++#define ND_RA_OL_LIMITS_FIXED_TYPE 1 /* fixed time */ ++ ++/* buffer lengths for the different nd_ra_ol_limits types */ ++#define ND_RA_OL_LIMITS_REL_TYPE_LEN 12 ++#define ND_RA_OL_LIMITS_FIXED_TYPE_LEN 10 ++ ++/* ++ * Temperature Throttling control mode ++ */ ++typedef struct wl_temp_control { ++ uint8 enable; ++ uint8 PAD; ++ uint16 control_bit; ++} wl_temp_control_t; ++ ++/* SensorHub Interworking mode */ ++ ++#define SHUB_CONTROL_VERSION 1 ++#define SHUB_CONTROL_LEN 12 ++ ++typedef struct { ++ uint16 verison; ++ uint16 length; ++ uint16 cmd; ++ uint16 op_mode; ++ uint16 interval; ++ uint16 enable; ++} shub_control_t; ++ ++/* WLC_MAJOR_VER <= 5 */ ++/* Data structures for non-TLV format */ ++ ++/* Data structures for rsdb caps */ ++/* ++ * The flags field of the rsdb_caps_response is designed to be ++ * a Bit Mask. As of now only Bit 0 is used as mentioned below. ++ */ ++ ++/* Bit-0 in flags is used to indicate if the cores can operate synchronously ++* i.e either as 2x2 MIMO or 2(1x1 SISO). This is true only for 4349 variants ++* 0 - device can operate only in rsdb mode (eg: 4364) ++* 1 - device can operate in both rsdb and mimo (eg : 4359 variants) ++*/ ++ ++#define WL_RSDB_CAPS_VER 2 ++#define SYNCHRONOUS_OPERATION_TRUE (1 << 0) ++#define WL_RSDB_CAPS_FIXED_LEN OFFSETOF(rsdb_caps_response_t, num_chains) ++ ++typedef struct rsdb_caps_response { ++ uint8 ver; /* Version */ ++ uint8 len; /* length of this structure excluding ver and len */ ++ uint8 rsdb; /* TRUE for rsdb chip */ ++ uint8 num_of_cores; /* no of d11 cores */ ++ uint16 flags; /* Flags to indicate various capabilities */ ++ uint8 num_chains[1]; /* Tx/Rx chains for each core */ ++} rsdb_caps_response_t; ++ ++/* Data structures for rsdb bands */ ++ ++#define WL_RSDB_BANDS_VER 2 ++#define WL_RSDB_BANDS_FIXED_LEN OFFSETOF(rsdb_bands_t, band) ++ ++typedef struct rsdb_bands ++{ ++ uint8 ver; ++ uint8 len; ++ uint16 num_cores; /* num of D11 cores */ ++ int16 band[1]; /* The band operating on each of the d11 cores */ ++} rsdb_bands_t; ++ ++/* rsdb config */ ++ ++#define WL_RSDB_CONFIG_VER 3 ++#define ALLOW_SIB_PARALLEL_SCAN (1 << 0) ++#define MAX_BANDS 2 ++ ++#define WL_RSDB_CONFIG_LEN sizeof(rsdb_config_t) ++ ++ ++typedef uint8 rsdb_opmode_t; ++typedef uint32 rsdb_flags_t; ++ ++typedef enum rsdb_modes { ++ WLC_SDB_MODE_NOSDB_MAIN = 1, /* 2X2 or MIMO mode (applicable only for 4355) */ ++ WLC_SDB_MODE_NOSDB_AUX = 2, ++ WLC_SDB_MODE_SDB_MAIN = 3, /* This is RSDB mode(default) applicable only for 4364 */ ++ WLC_SDB_MODE_SDB_AUX = 4, ++ WLC_SDB_MODE_SDB_AUTO = 5, /* Same as WLC_RSDB_MODE_RSDB(1+1) mode above */ ++} rsdb_modes_t; ++ ++typedef struct rsdb_config { ++ uint8 ver; ++ uint8 len; ++ uint16 reserved; ++ rsdb_opmode_t non_infra_mode; ++ rsdb_opmode_t infra_mode[MAX_BANDS]; ++ rsdb_flags_t flags[MAX_BANDS]; ++ rsdb_opmode_t current_mode; /* Valid only in GET, returns the current mode */ ++ uint8 pad[3]; ++} rsdb_config_t; ++ ++/* WLC_MAJOR_VER > =5 */ ++/* TLV definitions and data structures for rsdb subcmds */ ++ ++enum wl_rsdb_cmd_ids { ++ /* RSDB ioctls */ ++ WL_RSDB_CMD_VER = 0, ++ WL_RSDB_CMD_CAPS = 1, ++ WL_RSDB_CMD_BANDS = 2, ++ WL_RSDB_CMD_CONFIG = 3, ++ /* Add before this !! */ ++ WL_RSDB_CMD_LAST ++}; ++#define WL_RSDB_IOV_VERSION 0x1 ++ ++typedef struct rsdb_caps_response_v1 { ++ uint8 rsdb; /* TRUE for rsdb chip */ ++ uint8 num_of_cores; /* no of d11 cores */ ++ uint16 flags; /* Flags to indicate various capabilities */ ++ uint8 num_chains[MAX_NUM_D11CORES]; /* Tx/Rx chains for each core */ ++ uint8 band_cap[MAX_NUM_D11CORES]; /* band cap bitmask per slice */ ++} rsdb_caps_response_v1_t; ++ ++typedef struct rsdb_bands_v1 ++{ ++ uint8 num_cores; /* num of D11 cores */ ++ uint8 pad; /* padding bytes for 4 byte alignment */ ++ int8 band[MAX_NUM_D11CORES]; /* The band operating on each of the d11 cores */ ++} rsdb_bands_v1_t; ++ ++typedef struct rsdb_config_xtlv { ++ rsdb_opmode_t reserved1; /* Non_infra mode is no more applicable */ ++ rsdb_opmode_t infra_mode[MAX_BANDS]; /* Target mode for Infra association */ ++ uint8 pad; /* pad bytes for 4 byte alignment */ ++ rsdb_flags_t flags[MAX_BANDS]; ++ rsdb_opmode_t current_mode; /* GET only; has current mode of operation */ ++ uint8 pad1[3]; ++} rsdb_config_xtlv_t; ++ ++/* Definitions for slot_bss chanseq iovar */ ++#define WL_SLOT_BSS_VERSION 1 ++ ++enum wl_slotted_bss_cmd_id { ++ WL_SLOTTED_BSS_CMD_VER = 0, ++ WL_SLOTTED_BSS_CMD_CHANSEQ = 1 ++}; ++typedef uint16 chan_seq_type_t; ++enum chan_seq_type { ++ CHAN_SEQ_TYPE_AWDL = 1, ++ CHAN_SEQ_TYPE_SLICE = 2, ++ CHAN_SEQ_TYPE_NAN = 3 ++}; ++typedef uint8 sched_flag_t; ++enum sched_flag { ++ NO_SDB_SCHED = 0x1, ++ SDB_TDM_SCHED = 0x2, ++ SDB_SPLIT_BAND_SCHED = 0x4, /* default mode for 4357 */ ++ MAIN_ONLY = 0x8, ++ AUX_ONLY = 0x10, ++ SDB_DUAL_TIME = (MAIN_ONLY | AUX_ONLY), ++ NO_SDB_MAIN_ONLY = (NO_SDB_SCHED | MAIN_ONLY), /* default mode for 4364 */ ++ SDB_TDM_SCHED_MAIN = (SDB_TDM_SCHED | MAIN_ONLY), ++ SDB_TDM_SCHED_AUX = (SDB_TDM_SCHED | AUX_ONLY), ++ SDB_TDM_SCHED_DUAL_TIME = (SDB_TDM_SCHED | SDB_DUAL_TIME), ++ SDB_SPLIT_BAND_SCHED_DUAL_TIME = (SDB_SPLIT_BAND_SCHED | SDB_DUAL_TIME) ++}; ++ ++typedef struct chan_seq_tlv_data { ++ uint32 flags; ++ uint8 data[1]; ++} chan_seq_tlv_data_t; ++ ++typedef struct chan_seq_tlv { ++ chan_seq_type_t type; ++ uint16 len; ++ chan_seq_tlv_data_t chanseq_data[1]; ++} chan_seq_tlv_t; ++ ++typedef struct sb_channel_sequence { ++ sched_flag_t sched_flags; /* (sdb-tdm or sdb-sb or Dual-Time) */ ++ uint8 num_seq; /* number of chan_seq_tlv following */ ++ uint16 pad; ++ chan_seq_tlv_t seq[1]; ++} sb_channel_sequence_t; ++ ++typedef struct slice_chan_seq { ++ uint8 slice_index; /* 0(Main) or 1 (Aux) */ ++ uint8 num_chanspecs; ++ uint16 pad; ++ chanspec_t chanspecs[1]; ++} slice_chan_seq_t; ++ ++#define WL_SLICE_CHAN_SEQ_FIXED_LEN OFFSETOF(slice_chan_seq_t, chanspecs) ++ ++typedef struct sim_pm_params { ++ uint32 enabled; ++ uint16 cycle; ++ uint16 up; ++} sim_pm_params_t; ++ ++/* Bits for fw_status */ ++#define NAP_DISABLED_HOST 0x01 /* Host has disabled through nap_enable */ ++#define NAP_DISABLED_RSSI 0x02 /* Disabled because of nap_rssi_threshold */ ++ ++/* Bits for hw_status */ ++#define NAP_HWCFG 0x01 /* State of NAP config bit in phy HW */ ++ ++/* ifdef WL_NATOE */ ++#define WL_NATOE_IOCTL_VERSION 1 ++#define WL_NATOE_IOC_BUFSZ 512 /* sufficient ioc buff size for natoe */ ++#define WL_NATOE_DBG_STATS_BUFSZ 2048 ++ ++/* config natoe STA and AP IP's structure */ ++typedef struct { ++ uint32 sta_ip; ++ uint32 sta_netmask; ++ uint32 sta_router_ip; ++ uint32 sta_dnsip; ++ uint32 ap_ip; ++ uint32 ap_netmask; ++} wl_natoe_config_ips_t; ++ ++/* natoe ports config structure */ ++typedef struct { ++ uint16 start_port_num; ++ uint16 no_of_ports; ++} wl_natoe_ports_config_t; ++ ++/* natoe ports exception info */ ++typedef struct { ++ uint16 sta_port_num; ++ uint16 dst_port_num; /* for SIP type protocol, dst_port_num info can be ignored by FW */ ++ uint32 ip; /* for SIP ip is APcli_ip and for port clash it is dst_ip */ ++ uint8 entry_type; /* Create/Destroy */ ++ uint8 pad[3]; ++} wl_natoe_exception_port_t; ++ ++/* container for natoe ioctls & events */ ++typedef struct wl_natoe_ioc { ++ uint16 version; /* interface command or event version */ ++ uint16 id; /* natoe ioctl cmd ID */ ++ uint16 len; /* total length of all tlv records in data[] */ ++ uint16 pad; /* pad to be 32 bit aligment */ ++ uint8 data[]; /* var len payload of bcm_xtlv_t type */ ++} wl_natoe_ioc_t; ++ ++enum wl_natoe_cmds { ++ WL_NATOE_CMD_ENABLE = 1, ++ WL_NATOE_CMD_CONFIG_IPS = 2, ++ WL_NATOE_CMD_CONFIG_PORTS = 3, ++ WL_NATOE_CMD_DBG_STATS = 4, ++ WL_NATOE_CMD_EXCEPTION_PORT = 5, ++ WL_NATOE_CMD_SKIP_PORT = 6, ++ WL_NATOE_CMD_TBL_CNT = 7 ++}; ++ ++enum wl_natoe_cmd_xtlv_id { ++ WL_NATOE_XTLV_ENABLE = 1, ++ WL_NATOE_XTLV_CONFIG_IPS = 2, ++ WL_NATOE_XTLV_CONFIG_PORTS = 3, ++ WL_NATOE_XTLV_DBG_STATS = 4, ++ WL_NATOE_XTLV_EXCEPTION_PORT = 5, ++ WL_NATOE_XTLV_SKIP_PORT = 6, ++ WL_NATOE_XTLV_TBL_CNT = 7 ++}; ++ ++/* endif WL_NATOE */ ++ ++enum wl_idauth_cmd_ids { ++ WL_IDAUTH_CMD_CONFIG = 1, ++ WL_IDAUTH_CMD_PEER_INFO = 2, ++ WL_IDAUTH_CMD_COUNTERS = 3, ++ WL_IDAUTH_CMD_LAST ++}; ++enum wl_idauth_xtlv_id { ++ WL_IDAUTH_XTLV_AUTH_ENAB = 0x1, ++ WL_IDAUTH_XTLV_GTK_ROTATION = 0x2, ++ WL_IDAUTH_XTLV_EAPOL_COUNT = 0x3, ++ WL_IDAUTH_XTLV_EAPOL_INTRVL = 0x4, ++ WL_IDAUTH_XTLV_BLKLIST_COUNT = 0x5, ++ WL_IDAUTH_XTLV_BLKLIST_AGE = 0x6, ++ WL_IDAUTH_XTLV_PEERS_INFO = 0x7, ++ WL_IDAUTH_XTLV_COUNTERS = 0x8 ++}; ++enum wl_idauth_stats { ++ WL_AUTH_PEER_STATE_AUTHORISED = 0x01, ++ WL_AUTH_PEER_STATE_BLACKLISTED = 0x02, ++ WL_AUTH_PEER_STATE_4WAY_HS_ONGOING = 0x03, ++ WL_AUTH_PEER_STATE_LAST ++}; ++typedef struct { ++ uint16 state; /* Peer State: Authorised or Blacklisted */ ++ struct ether_addr peer_addr; /* peer Address */ ++ uint32 blklist_end_time; /* Time of blacklist end */ ++} auth_peer_t; ++typedef struct wl_idauth_counters { ++ uint32 auth_reqs; /* No of auth req recvd */ ++ uint32 mic_fail; /* No of mic fails */ ++ uint32 four_way_hs_fail; /* No of 4-way handshake fails */ ++} wl_idauth_counters_t; ++ ++#define WLC_UTRACE_LEN 512 ++#define WLC_UTRACE_READ_END 0 ++#define WLC_UTRACE_MORE_DATA 1 ++typedef struct wl_utrace_capture_args_v1 { ++ uint32 length; ++ uint32 flag; ++} wl_utrace_capture_args_v1_t; ++ ++#define UTRACE_CAPTURE_VER_2 2 ++typedef struct wl_utrace_capture_args_v2 { ++ /* structure control */ ++ uint16 version; /**< structure version */ ++ uint16 length; /**< length of the response */ ++ uint32 flag; /* Indicates if there is more data or not */ ++} wl_utrace_capture_args_v2_t; ++ ++/* XTLV IDs for the Health Check "hc" iovar top level container */ ++enum { ++ WL_HC_XTLV_ID_CAT_HC = 1, /* category for HC as a whole */ ++ WL_HC_XTLV_ID_CAT_DATAPATH_TX = 2, /* Datapath Tx */ ++ WL_HC_XTLV_ID_CAT_DATAPATH_RX = 3, /* Datapath Rx */ ++ WL_HC_XTLV_ID_CAT_SCAN = 4, /* Scan */ ++}; ++ ++/* Health Check: Common XTLV IDs for sub-elements in the top level container ++ * Number starts at 0x8000 to be out of the way for category specific IDs. ++ */ ++enum { ++ WL_HC_XTLV_ID_ERR = 0x8000, /* for sub-command err return */ ++ WL_HC_XTLV_ID_IDLIST = 0x8001, /* container for uint16 IDs */ ++}; ++ ++/* Health Check: Datapath TX IDs */ ++enum { ++ WL_HC_TX_XTLV_ID_VAL_STALL_THRESHOLD = 1, /* stall_threshold */ ++ WL_HC_TX_XTLV_ID_VAL_STALL_SAMPLE_SIZE = 2, /* stall_sample_size */ ++ WL_HC_TX_XTLV_ID_VAL_STALL_TIMEOUT = 3, /* stall_timeout */ ++ WL_HC_TX_XTLV_ID_VAL_STALL_FORCE = 4, /* stall_force */ ++ WL_HC_TX_XTLV_ID_VAL_STALL_EXCLUDE = 5, /* stall_exclude */ ++ WL_HC_TX_XTLV_ID_VAL_FC_TIMEOUT = 6, /* flow ctl timeout */ ++ WL_HC_TX_XTLV_ID_VAL_FC_FORCE = 7, /* flow ctl force failure */ ++ WL_HC_TX_XTLV_ID_VAL_DELAY_TO_TRAP = 8, /* delay threshold for forced trap */ ++ WL_HC_TX_XTLV_ID_VAL_DELAY_TO_RPT = 9, /* delay threshold for event log report */ ++}; ++ ++/* Health Check: Datapath RX IDs */ ++enum { ++ WL_HC_RX_XTLV_ID_VAL_DMA_STALL_TIMEOUT = 1, /* dma_stall_timeout */ ++ WL_HC_RX_XTLV_ID_VAL_DMA_STALL_FORCE = 2, /* dma_stall test trigger */ ++ WL_HC_RX_XTLV_ID_VAL_STALL_THRESHOLD = 3, /* stall_threshold */ ++ WL_HC_RX_XTLV_ID_VAL_STALL_SAMPLE_SIZE = 4, /* stall_sample_size */ ++ WL_HC_RX_XTLV_ID_VAL_STALL_FORCE = 5, /* stall test trigger */ ++}; ++ ++/* Health Check: Datapath SCAN IDs */ ++enum { ++ WL_HC_XTLV_ID_VAL_SCAN_STALL_THRESHOLD = 1, /* scan stall threshold */ ++}; ++ ++/* IDs of Health Check report structures for sub types of health checks within WL */ ++enum { ++ WL_HC_DD_UNDEFINED = 0, /* Undefined */ ++ WL_HC_DD_RX_DMA_STALL = 1, /* RX DMA stall check */ ++ WL_HC_DD_RX_STALL = 2, /* RX stall check */ ++ WL_HC_DD_TX_STALL = 3, /* TX stall check */ ++ WL_HC_DD_SCAN_STALL = 4, /* SCAN stall check */ ++ WL_HC_DD_MAX ++}; ++ ++/* ++ * Health Check report structures for sub types of health checks within WL ++ */ ++ ++/* Health Check report structure for Rx DMA Stall check */ ++typedef struct { ++ uint16 type; ++ uint16 length; ++ uint16 timeout; ++ uint16 stalled_dma_bitmap; ++} wl_rx_dma_hc_info_t; ++ ++/* Health Check report structure for Tx packet failure check */ ++typedef struct { ++ uint16 type; ++ uint16 length; ++ uint32 stall_bitmap; ++ uint32 stall_bitmap1; ++ uint32 failure_ac; ++ uint32 threshold; ++ uint32 tx_all; ++ uint32 tx_failure_all; ++} wl_tx_hc_info_t; ++ ++/* Health Check report structure for Rx dropped packet failure check */ ++typedef struct { ++ uint16 type; ++ uint16 length; ++ uint32 bsscfg_idx; ++ uint32 rx_hc_pkts; ++ uint32 rx_hc_dropped_all; ++ uint32 rx_hc_alert_th; ++} wl_rx_hc_info_t; ++ ++/* HE top level command IDs */ ++enum { ++ WL_HE_CMD_ENAB = 0, ++ WL_HE_CMD_FEATURES = 1, ++ WL_HE_CMD_TWT_SETUP = 2, ++ WL_HE_CMD_TWT_TEARDOWN = 3, ++ WL_HE_CMD_TWT_INFO = 4, ++ WL_HE_CMD_BSSCOLOR = 5, ++ WL_HE_CMD_PARTIAL_BSSCOLOR = 6, ++ WL_HE_CMD_LAST ++}; ++ ++#define WL_HEB_VERSION 0 ++ ++/* HEB top level command IDs */ ++enum { ++ WL_HEB_CMD_ENAB = 0, ++ WL_HEB_CMD_NUM_HEB = 1, ++ WL_HEB_CMD_COUNTERS = 1, ++ WL_HEB_CMD_CLEAR_COUNTERS = 2, ++ WL_HEB_CMD_LAST ++}; ++ ++/* HEB counters structures */ ++typedef struct { ++ uint16 pre_event; ++ uint16 start_event; ++ uint16 end_event; ++ uint16 missed; ++} wl_heb_int_cnt_t; ++ ++typedef struct { ++ /* structure control */ ++ uint16 version; /* structure version */ ++ uint16 length; /* data length (starting after this field) */ ++ wl_heb_int_cnt_t heb_int_cnt[1]; ++} wl_heb_cnt_t; ++ ++ ++/* TWT Setup descriptor */ ++typedef struct { ++ /* Setup Command. */ ++ uint8 setup_cmd; /* See TWT_SETUP_CMD_XXXX in 802.11ah.h, ++ * valid when bcast_twt is FALSE. ++ */ ++ /* Flow attributes */ ++ uint8 flow_flags; /* See WL_TWT_FLOW_FLAG_XXXX below */ ++ uint8 flow_id; /* must be between 0 and 7 */ ++ /* Target Wake Time */ ++ uint8 wake_type; /* See WL_TWT_TIME_TYPE_XXXX below */ ++ uint32 wake_time_h; /* target wake time - BSS TSF (us) */ ++ uint32 wake_time_l; ++ uint32 wake_dur; /* target wake duration in us units */ ++ uint32 wake_int; /* target wake interval */ ++} wl_twt_sdesc_t; ++ ++/* Flow flags */ ++#define WL_TWT_FLOW_FLAG_BROADCAST (1<<0) ++#define WL_TWT_FLOW_FLAG_IMPLICIT (1<<1) ++#define WL_TWT_FLOW_FLAG_UNANNOUNCED (1<<2) ++#define WL_TWT_FLOW_FLAG_TRIGGER (1<<3) ++ ++/* Flow id */ ++#define WL_TWT_FLOW_ID_FID 0x07 /* flow id */ ++#define WL_TWT_FLOW_ID_GID_MASK 0x70 /* group id - broadcast TWT only */ ++#define WL_TWT_FLOW_ID_GID_SHIFT 4 ++ ++/* Wake type */ ++/* TODO: not yet finalized */ ++#define WL_TWT_TIME_TYPE_BSS 0 /* The time specified in wake_time_h/l is ++ * the BSS TSF time. ++ */ ++#define WL_TWT_TIME_TYPE_OFFSET 1 /* The time specified in wake_time_h/l is an offset ++ * of the TSF time when the iovar is processed. ++ */ ++ ++#define WL_TWT_SETUP_VER 0 ++ ++/* HE TWT Setup command */ ++typedef struct { ++ /* structure control */ ++ uint16 version; /* structure version */ ++ uint16 length; /* data length (starting after this field) */ ++ /* peer address */ ++ struct ether_addr peer; /* leave it all 0s' for AP */ ++ /* session id */ ++ uint8 dialog; /* an arbitrary number to identify the seesion */ ++ uint8 pad; ++ /* setup descriptor */ ++ wl_twt_sdesc_t desc; ++} wl_twt_setup_t; ++ ++#define WL_TWT_TEARDOWN_VER 0 ++ ++/* HE TWT Teardown command */ ++typedef struct { ++ /* structure control */ ++ uint16 version; /* structure version */ ++ uint16 length; /* data length (starting after this field) */ ++ /* peer address */ ++ struct ether_addr peer; /* leave it all 0s' for AP */ ++ /* flow attributes */ ++ uint8 flow_flags; /* See WL_TWT_FLOW_FLAG_XXXX above. ++ * (only BORADCAST) is applicable) ++ */ ++ uint8 flow_id; /* must be between 0 and 7 */ ++} wl_twt_teardown_t; ++ ++/* twt information descriptor */ ++typedef struct { ++ uint8 flow_flags; /* See WL_TWT_INFO_FLAG_XXX below */ ++ uint8 flow_id; ++ uint8 pad[2]; ++ uint32 next_twt_h; ++ uint32 next_twt_l; ++} wl_twt_idesc_t; ++ ++/* Flow flags */ ++#define WL_TWT_INFO_FLAG_RESP_REQ (1<<0) /* Request response */ ++ ++#define WL_TWT_INFO_VER 0 ++ ++/* HE TWT Information command */ ++typedef struct { ++ /* structure control */ ++ uint16 version; /* structure version */ ++ uint16 length; /* data length (starting after this field) */ ++ /* peer address */ ++ struct ether_addr peer; /* leave it all 0s' for AP */ ++ uint8 pad[2]; ++ /* information descriptor */ ++ wl_twt_idesc_t desc; ++} wl_twt_info_t; ++ ++/* Current version for wlc_clm_power_limits_req_t structure and flags */ ++#define WLC_CLM_POWER_LIMITS_REQ_VERSION 1 ++/* "clm_power_limits" iovar request structure */ ++typedef struct wlc_clm_power_limits_req { ++ /* Input. Structure and flags version */ ++ uint32 version; ++ /* Full length of buffer (includes this structure and space for TLV-encoded PPR) */ ++ uint32 buflen; ++ /* Input. Flags (see WLC_CLM_POWER_LIMITS_INPUT_FLAG_... below) */ ++ uint32 input_flags; ++ /* Input. CC of region whose data is being requested */ ++ char cc[WLC_CNTRY_BUF_SZ]; ++ /* Input. Channel/subchannel in chanspec_t format */ ++ uint32 chanspec; ++ /* Subchannel encoded as clm_limits_type_t */ ++ uint32 clm_subchannel; ++ /* Input. 0-based antenna index */ ++ uint32 antenna_idx; ++ /* Output. General flags (see WLC_CLM_POWER_LIMITS_OUTPUT_FLAG_... below) */ ++ uint32 output_flags; ++ /* Output. 2.4G country flags, encoded as clm_flags_t enum */ ++ uint32 clm_country_flags_2g; ++ /* Output. 5G country flags, encoded as clm_flags_t enum */ ++ uint32 clm_country_flags_5g; ++ /* Output. Length of TLV-encoded PPR data that follows this structure */ ++ uint32 ppr_tlv_size; ++ /* Output. Beginning of buffer for TLV-encoded PPR data */ ++ uint8 ppr_tlv[1]; ++} wlc_clm_power_limits_req_t; ++ ++/* Input. Do not apply SAR limits */ ++#define WLC_CLM_POWER_LIMITS_INPUT_FLAG_NO_SAR 0x00000001 ++/* Input. Do not apply board limits */ ++#define WLC_CLM_POWER_LIMITS_INPUT_FLAG_NO_BOARD 0x00000002 ++/* Output. Limits taken from product-specific country data */ ++#define WLC_CLM_POWER_LIMITS_OUTPUT_FLAG_PRODUCT_LIMITS 0x00000001 ++/* Output. Limits taken from product-specific worldwide data */ ++#define WLC_CLM_POWER_LIMITS_OUTPUT_FLAG_WORLDWIDE_LIMITS 0x00000002 ++/* Output. Limits taken from country-default (all-product) data */ ++#define WLC_CLM_POWER_LIMITS_OUTPUT_FLAG_DEFAULT_COUNTRY_LIMITS 0x00000004 ++ ++/* ++ * WOG (Wake On Googlecast) ++ */ ++ ++#define MAX_GCAST_APPID_CNT_LIMIT 50 ++#define MAX_DNS_LABEL 63 ++ ++typedef struct wog_appid { ++ uint8 appID[MAX_DNS_LABEL+1]; ++} wog_appid_t; ++ ++enum { ++ WOG_APPID_ADD, ++ WOG_APPID_DEL, ++ WOG_APPID_CLEAR, ++ WOG_APPID_LIST, ++ WOG_MAX_APPID_CNT ++}; ++ ++#define WOG_APPID_IOV_VER 1 ++typedef struct wog_appid_iov { ++ /* version for iovar */ ++ uint32 ver; ++ /* add/del/clear/list operation */ ++ uint32 operation; ++ /* for adding or deleting multiple items */ ++ /* for WOG_MAX_APPID_CNT, this value is used for max count for AppID */ ++ uint32 cnt; ++ /* Application IDs */ ++ /* If FW found an AppID from this list, FW will respond to discovery */ ++ /* without wake up the host */ ++ wog_appid_t appids[1]; ++} wog_appid_iov_t; ++ ++/* dns service record */ ++/* service name : _googlecast */ ++typedef struct wog_srv_record { ++ uint32 ttl; ++ uint16 port; /* tcp 8008 or 8009 */ ++ uint8 PAD[2]; ++} wog_srv_record_t; ++ ++#define GCAST_MAX_MODEL_NAME_LEN 16 ++#define GCAST_MAX_FNAME_LEN 64 ++#define GCAST_MAX_RS_LEN 60 ++ ++#define GCAST_UUID_LEN 32 ++#define GCAST_PUBLICKEY_ID_LEN 64 ++#define GCAST_VER_LEN 2 ++typedef struct wog_txt_record { ++ uint32 ttl; ++ /* id : UUID for the receiver */ ++ char id[GCAST_UUID_LEN+1]; ++ ++ /* Cast protocol version supported. Begins at 2 */ ++ /* and is incremented by 1 with each version */ ++ char ver[GCAST_VER_LEN+1]; ++ ++ /* 256bit receiver Subject Public Key Identifier from the SSL cert */ ++ char public_key[GCAST_PUBLICKEY_ID_LEN+1]; ++ ++ /* A bitfield of device capabilities. */ ++ /* bit 0 : video_out (1:has video out, 0:no video) */ ++ /* bit 1 : video_in */ ++ /* bit 2 : audio_out */ ++ /* bit 3 : audio_in */ ++ /* bit 4 : dev_mode */ ++ /* (1:dev mode enabled, 0: not enabled) */ ++ char capability; ++ ++ /* Receiver status flag 0:IDLE, 1(BUSY/JOIN) */ ++ /* IDLE : The receiver is idle */ ++ /* and doesn't need to be connected now. */ ++ /* BUSY/JOIN : The receiver is hosting an activity */ ++ /* and invites the sender to join */ ++ char receiver_status_flag; ++ ++ uint8 PAD0[1]; ++ ++ char friendly_name[GCAST_MAX_FNAME_LEN+1]; ++ uint8 PAD1[3]; ++ ++ char model_name[GCAST_MAX_MODEL_NAME_LEN+1]; ++ uint8 PAD2[3]; ++ ++ /* Receiver Status text for Cast Protocol v2 */ ++ /* Spec says that if the status text exceeds 60 characters in length, */ ++ /* it is truncated at 60 caracters and */ ++ /* a UTF-8 ellipsis character is appended to indicate trucation. */ ++ /* But our dongle won't use UTF-8 ellipsis. It's not a big deal. */ ++ char receiver_status[GCAST_MAX_RS_LEN+1]; ++ uint8 PAD3[3]; ++} wog_txt_record_t; ++ ++/* ip will be taken from the ip of wog_info_t */ ++typedef struct wog_a_record { ++ uint32 ttl; ++} wog_a_record_t; ++ ++/* Google Cast protocl uses mDNS SD for its discovery */ ++#define WOG_SD_RESP_VER 1 ++typedef struct wog_sd_resp { ++ /* version for iovar */ ++ int32 ver; ++ /* device name of Google Cast receiver */ ++ char device_name[MAX_DNS_LABEL+1]; ++ /* IP address of Google Cast receiver */ ++ uint8 ip[4]; ++ /* ttl of PTR response */ ++ uint32 ptr_ttl; ++ /* DNS TXT record */ ++ wog_txt_record_t txt; ++ /* DNS SRV record */ ++ wog_srv_record_t srv; ++ /* DNS A record */ ++ wog_a_record_t a; ++} wog_sd_resp_t; ++ ++enum wl_mbo_cmd_ids { ++ WL_MBO_CMD_ADD_CHAN_PREF = 1, ++ WL_MBO_CMD_DEL_CHAN_PREF = 2, ++ WL_MBO_CMD_LIST_CHAN_PREF = 3, ++ WL_MBO_CMD_CELLULAR_DATA_CAP = 4, ++ WL_MBO_CMD_DUMP_COUNTERS = 5, ++ WL_MBO_CMD_CLEAR_COUNTERS = 6, ++ WL_MBO_CMD_FORCE_ASSOC = 7, ++ WL_MBO_CMD_BSSTRANS_REJECT = 8, ++ WL_MBO_CMD_SEND_NOTIF = 9, ++ /* Add before this !! */ ++ WL_MBO_CMD_LAST ++}; ++ ++enum wl_mbo_xtlv_id { ++ WL_MBO_XTLV_OPCLASS = 0x1, ++ WL_MBO_XTLV_CHAN = 0x2, ++ WL_MBO_XTLV_PREFERENCE = 0x3, ++ WL_MBO_XTLV_REASON_CODE = 0x4, ++ WL_MBO_XTLV_CELL_DATA_CAP = 0x5, ++ WL_MBO_XTLV_COUNTERS = 0x6, ++ WL_MBO_XTLV_ENABLE = 0x7, ++ WL_MBO_XTLV_SUB_ELEM_TYPE = 0x8 ++}; ++ ++typedef struct wl_mbo_counters { ++ /* No of transition req recvd */ ++ uint16 trans_req_rcvd; ++ /* No of transition req with disassoc imminent */ ++ uint16 trans_req_disassoc; ++ /* No of transition req with BSS Termination */ ++ uint16 trans_req_bss_term; ++ /* No of trans req w/ unspecified reason */ ++ uint16 trans_resn_unspec; ++ /* No of trans req w/ reason frame loss */ ++ uint16 trans_resn_frm_loss; ++ /* No of trans req w/ reason traffic delay */ ++ uint16 trans_resn_traffic_delay; ++ /* No of trans req w/ reason insufficient buffer */ ++ uint16 trans_resn_insuff_bw; ++ /* No of trans req w/ reason load balance */ ++ uint16 trans_resn_load_bal; ++ /* No of trans req w/ reason low rssi */ ++ uint16 trans_resn_low_rssi; ++ /* No of trans req w/ reason excessive retransmission */ ++ uint16 trans_resn_xcess_retransmn; ++ /* No of trans req w/ reason gray zone */ ++ uint16 trans_resn_gray_zone; ++ /* No of trans req w/ reason switch to premium AP */ ++ uint16 trans_resn_prem_ap_sw; ++ /* No of transition rejection sent */ ++ uint16 trans_rejn_sent; ++ /* No of trans rejn reason excessive frame loss */ ++ uint16 trans_rejn_xcess_frm_loss; ++ /* No of trans rejn reason excessive traffic delay */ ++ uint16 trans_rejn_xcess_traffic_delay; ++ /* No of trans rejn reason insufficient QoS capability */ ++ uint16 trans_rejn_insuffic_qos_cap; ++ /* No of trans rejn reason low RSSI */ ++ uint16 trans_rejn_low_rssi; ++ /* No of trans rejn reason high interference */ ++ uint16 trans_rejn_high_interference; ++ /* No of trans rejn reason service unavilable */ ++ uint16 trans_rejn_service_unavail; ++ /* No of beacon request rcvd */ ++ uint16 bcn_req_rcvd; ++ /* No of beacon report sent */ ++ uint16 bcn_rep_sent; ++ /* No of null beacon report sent */ ++ uint16 null_bcn_rep_sent; ++ /* No of wifi to cell switch */ ++ uint16 wifi_to_cell; ++} wl_mbo_counters_t; ++ ++/* otpread command */ ++#define WL_OTPREAD_VER 1 ++ ++typedef struct { ++ uint16 version; /* cmd structure version */ ++ uint16 cmd_len; /* cmd struct len */ ++ uint32 rdmode; /* otp read mode */ ++ uint32 rdoffset; /* byte offset into otp to start read */ ++ uint32 rdsize; /* number of bytes to read */ ++} wl_otpread_cmd_t; ++ ++/* "otpecc_rows" command */ ++typedef struct { ++ uint16 version; /* version of this structure */ ++ uint16 len; /* len in bytes of this structure */ ++ uint32 cmdtype; /* command type : 0 : read row data, 1 : ECC lock */ ++ uint32 rowoffset; /* start row offset */ ++ uint32 numrows; /* number of rows */ ++ uint8 rowdata[]; /* read rows data */ ++} wl_otpecc_rows_t; ++ ++#define WL_OTPECC_ROWS_VER 1 ++ ++#define WL_OTPECC_ROWS_CMD_READ 0 ++#define WL_OTPECC_ROWS_CMD_LOCK 1 ++ ++#define WL_OTPECC_ARGIDX_CMDTYPE 0 /* command type */ ++#define WL_OTPECC_ARGIDX_ROWOFFSET 1 /* start row offset */ ++#define WL_OTPECC_ARGIDX_NUMROWS 2 /* number of rows */ ++ ++/* "otpeccrows" raw data size per row */ ++#define WL_ECCDUMP_ROW_SIZE_BYTE 6 /* 4 bytes row data + 2 bytes ECC status */ ++#define WL_ECCDUMP_ROW_SIZE_WORD 3 ++ ++/* otpECCstatus */ ++#define OTP_ECC_ENAB_SHIFT 13 ++#define OTP_ECC_ENAB_MASK 0x7 ++#define OTP_ECC_CORR_ST_SHIFT 12 ++#define OTP_ECC_CORR_ST_MASK 0x1 ++#define OTP_ECC_DBL_ERR_SHIFT 11 ++#define OTP_ECC_DBL_ERR_MASK 0x1 ++#define OTP_ECC_DED_ST_SHIFT 10 ++#define OTP_ECC_DED_ST_MASK 0x1 ++#define OTP_ECC_SEC_ST_SHIFT 9 ++#define OTP_ECC_SEC_ST_MASK 0x1 ++#define OTP_ECC_DATA_SHIFT 0 ++#define OTP_ECC_DATA_MASK 0x7f ++ ++/* OTP_ECC_CORR_ST field */ ++#define OTP_ECC_MODE 1 ++#define OTP_NO_ECC_MODE 0 ++ ++/* OTP_ECC_ENAB field (bit15:13) : ++ * When 2 or 3 bits are set, ++ * it indicates that OTP ECC is enabled on the last row read. ++ * Otherwise, ECC is disabled ++ */ ++#define OTP_ECC_ENAB(val) \ ++ (bcm_bitcount((uint8 *)&(val), sizeof(uint8)) > 1) ++ ++#define WL_LEAKY_AP_STATS_GT_TYPE 0 ++#define WL_LEAKY_AP_STATS_PKT_TYPE 1 ++typedef struct wlc_leaked_infra_guard_marker { ++ /* type field for this TLV: WL_LEAKY_AP_STATS_GT_TYPE */ ++ uint16 type; ++ /* length field for this TLV */ ++ uint16 len; ++ /* guard sample sequence number; Updated by 1 on every guard sample */ ++ uint32 seq_number; ++ /* Guard time start time (tsf; PS indicated and acked) */ ++ uint32 start_time; ++ /* tsf timestamp for the GT end event */ ++ uint32 gt_tsf_l; ++ /* Guard time period in ms */ ++ uint16 guard_duration; ++ /* Number PPDUs in the notification */ ++ uint16 num_pkts; ++ /* Flags to indicate some states see below */ ++ uint8 flag; ++ /* pad for 32-bit alignment */ ++ uint8 reserved[3]; ++} wlc_leaked_infra_guard_marker_t; ++ ++/* Flag information */ ++#define WL_LEAKED_GUARD_TIME_NONE 0 /* Not in any guard time */ ++#define WL_LEAKED_GUARD_TIME_FRTS (0x01 << 0) /* Normal FRTS power save */ ++#define WL_LEAKED_GUARD_TIME_SCAN (0x01 << 1) /* Channel switch due to scanning */ ++#define WL_LEAKED_GUARD_TIME_AWDL_PSF (0x01 << 2) /* Channel switch due to AWDL PSF */ ++#define WL_LEAKED_GUARD_TIME_AWDL_AW (0x01 << 3) /* Channel switch due to AWDL AW */ ++#define WL_LEAKED_GUARD_TIME_INFRA_STA (0x01 << 4) /* generic type infra sta channel switch */ ++#define WL_LEAKED_GUARD_TIME_TERMINATED (0x01 << 7) /* indicate a GT is terminated early */ ++ ++typedef struct wlc_leaked_infra_packet_stat { ++ uint16 type; /* type field for this TLV: WL_LEAKY_AP_STATS_PKT_TYPE */ ++ uint16 len; /* length field for this TLV */ ++ uint16 ppdu_len_bytes; /* PPDU packet length in bytes */ ++ uint16 num_mpdus; /* number of the MPDUs in the PPDU */ ++ uint32 ppdu_time; /* PPDU arrival time at the begining of the guard time */ ++ uint32 rate; /* PPDU packet rate; Received packet's data rate */ ++ uint16 seq_number; /* sequence number */ ++ int8 rssi; /* RSSI */ ++ uint8 tid; /* tid */ ++} wlc_leaked_infra_packet_stat_t; ++ ++/* Wake timer structure definition */ ++#define WAKE_TIMER_VERSION 1 ++#define WAKE_TIMER_NOLIMIT 0xFFFF ++ ++typedef struct wake_timer { ++ uint16 ver; ++ uint16 len; ++ uint16 limit; /* number of events to deliver ++ * 0-disable, 0xffff-indefinite, num_events otherwise ++ */ ++ uint16 count; /* number of events delivered since enable (get only) */ ++ uint16 period; /* timeout/period in milliseconds */ ++} wake_timer_t; ++ ++typedef struct wl_desense_restage_gain { ++ uint16 version; ++ uint16 length; ++ uint32 band; ++ uint8 num_cores; ++ uint8 desense_array[WL_TX_CHAINS_MAX]; ++ uint8 PAD[3]; ++} wl_desense_restage_gain_t; ++ ++#define MAX_UCM_CHAINS 5 ++#define MAX_UCM_PROFILES 4 ++#define UCM_PROFILE_VERSION_1 1 ++ ++/* UCM per chain attribute struct */ ++typedef struct wlc_btcx_chain_attr { ++ uint16 length; /* chain attr length, version is same as profile version */ ++ int8 desense_level; /* per chain desense level */ ++ int8 ack_pwr_strong_rssi; /* per chain ack power at strong rssi */ ++ int8 ack_pwr_weak_rssi; /* per chain ack power at weak rssi */ ++ int8 tx_pwr_strong_rssi; /* per chain tx power at strong rssi */ ++ int8 tx_pwr_weak_rssi; /* per chain tx power at weak rssi */ ++ uint8 PAD[1]; /* additional bytes for alignment */ ++} wlc_btcx_chain_attr_t; ++ ++typedef struct wlc_btcx_profile_v1 { ++ uint16 version; /* UCM profile version */ ++ uint16 length; /* profile size */ ++ uint16 fixed_length; /* size of the fixed portion of the profile */ ++ uint8 init; /* profile initialized or not */ ++ uint8 chain_attr_count; /* Number of elements in chain_attr array */ ++ uint8 profile_index; /* profile index */ ++ uint8 mode_strong_wl_bt; /* Mode under strong WLAN and BT RSSI */ ++ uint8 mode_weak_wl; /* Mode under weak WLAN RSSI */ ++ uint8 mode_weak_bt; /* Mode under weak BT RSSI */ ++ uint8 mode_weak_wl_bt; /* Mode under weak BT and WLAN RSSI */ ++ int8 mode_wl_hi_lo_rssi_thresh; /* Strong to weak WLAN RSSI threshold for mode selection */ ++ int8 mode_wl_lo_hi_rssi_thresh; /* Weak to strong WLAN RSSI threshold for mode selection */ ++ int8 mode_bt_hi_lo_rssi_thresh; /* Strong to weak BT RSSI threshold for mode selection */ ++ int8 mode_bt_lo_hi_rssi_thresh; /* Weak to strong BT RSSI threshold for mode selection */ ++ int8 desense_wl_hi_lo_rssi_thresh; /* Strong to weak RSSI threshold for desense */ ++ int8 desense_wl_lo_hi_rssi_thresh; /* Weak to strong RSSI threshold for desense */ ++ int8 ack_pwr_wl_hi_lo_rssi_thresh; /* Strong to weak RSSI threshold for ACK power */ ++ int8 ack_pwr_wl_lo_hi_rssi_thresh; /* Weak to strong RSSI threshold for ACK power */ ++ int8 tx_pwr_wl_hi_lo_rssi_thresh; /* Strong to weak RSSI threshold for Tx power */ ++ int8 tx_pwr_wl_lo_hi_rssi_thresh; /* Weak to strong RSSI threshold for Tx power */ ++ uint8 PAD[1]; /* additional bytes for 4 byte alignment */ ++ wlc_btcx_chain_attr_t chain_attr[]; /* variable length array with chain attributes */ ++} wlc_btcx_profile_v1_t; ++ ++#define SSSR_D11_RESET_SEQ_STEPS 5 ++#define SSSR_REG_INFO_VER 0 ++ ++typedef struct sssr_reg_info { ++ uint16 version; ++ uint16 length; /* length of the structure validated at host */ ++ struct { ++ struct { ++ uint32 pmuintmask0; ++ uint32 pmuintmask1; ++ uint32 resreqtimer; ++ uint32 macresreqtimer; ++ uint32 macresreqtimer1; ++ } base_regs; ++ } pmu_regs; ++ struct { ++ struct { ++ uint32 intmask; ++ uint32 powerctrl; ++ uint32 clockcontrolstatus; ++ uint32 powerctrl_mask; ++ } base_regs; ++ } chipcommon_regs; ++ struct { ++ struct { ++ uint32 clockcontrolstatus; ++ uint32 clockcontrolstatus_val; ++ } base_regs; ++ struct { ++ uint32 resetctrl; ++ uint32 itopoobb; ++ } wrapper_regs; ++ } arm_regs; ++ struct { ++ struct { ++ uint32 ltrstate; ++ uint32 clockcontrolstatus; ++ uint32 clockcontrolstatus_val; ++ } base_regs; ++ struct { ++ uint32 itopoobb; ++ } wrapper_regs; ++ } pcie_regs; ++ struct { ++ struct { ++ uint32 ioctrl; ++ } wrapper_regs; ++ uint32 vasip_sr_addr; ++ uint32 vasip_sr_size; ++ } vasip_regs; ++ struct { ++ struct { ++ uint32 xmtaddress; ++ uint32 xmtdata; ++ uint32 clockcontrolstatus; ++ uint32 clockcontrolstatus_val; ++ } base_regs; ++ struct { ++ uint32 resetctrl; ++ uint32 itopoobb; ++ uint32 ioctrl; ++ uint32 ioctrl_resetseq_val[SSSR_D11_RESET_SEQ_STEPS]; ++ } wrapper_regs; ++ uint32 sr_size; ++ } mac_regs[MAX_NUM_D11CORES]; ++} sssr_reg_info_t; ++ ++/* ADaptive Power Save(ADPS) structure definition */ ++#define WL_ADPS_IOV_MAJOR_VER 1 ++#define WL_ADPS_IOV_MINOR_VER 0 ++#define WL_ADPS_IOV_MAJOR_VER_SHIFT 8 ++#define WL_ADPS_IOV_VER \ ++ ((WL_ADPS_IOV_MAJOR_VER << WL_ADPS_IOV_MAJOR_VER_SHIFT) | WL_ADPS_IOV_MINOR_VER) ++ ++#define ADPS_NUM_DIR 2 ++#define ADPS_RX 0 ++#define ADPS_TX 1 ++ ++#define WL_ADPS_IOV_MODE 0x0001 ++#define WL_ADPS_IOV_RSSI 0x0002 ++#define WL_ADPS_IOV_DUMP 0x0003 ++#define WL_ADPS_IOV_DUMP_CLEAR 0x0004 ++ ++#define ADPS_SUMMARY_STEP_NUM 2 ++#define ADPS_SUMMARY_STEP_LOW 0 ++#define ADPS_SUMMARY_STEP_HIGH 1 ++ ++#define ADPS_SUB_IOV_VERSION_1 1 ++#define ADPS_SUB_IOV_VERSION_2 2 ++ ++typedef struct wl_adps_params_v1 { ++ uint16 version; ++ uint16 length; ++ uint8 band; /* band - 2G or 5G */ ++ uint8 mode; /* operation mode, default = 0 (ADPS disable) */ ++ uint16 padding; ++} wl_adps_params_v1_t; ++ ++typedef struct wl_adps_rssi { ++ int32 thresh_hi; /* rssi threshold to resume ADPS operation */ ++ int32 thresh_lo; /* rssi threshold to suspend ADPS operation */ ++} wl_adps_rssi_t; ++ ++typedef struct wl_adps_rssi_params_v1 { ++ uint16 version; ++ uint16 length; ++ uint8 band; ++ uint8 padding[3]; ++ wl_adps_rssi_t rssi; ++} wl_adps_rssi_params_v1_t; ++ ++typedef struct adps_stat_elem { ++ uint32 duration; /* each step duration time (mSec) */ ++ uint32 counts; /* each step hit count number */ ++} adps_stat_elem_t; ++ ++typedef struct wl_adps_dump_summary_v1 { ++ uint16 version; ++ uint16 length; ++ uint8 mode; /* operation mode: On/Off */ ++ uint8 flags; /* restrict flags */ ++ uint8 current_step; /* current step */ ++ uint8 padding; ++ adps_stat_elem_t stat[ADPS_SUMMARY_STEP_NUM]; /* statistics */ ++} wl_adps_dump_summary_v1_t; ++ ++typedef struct wlc_btc_2gchain_dis { ++ uint16 ver; ++ uint16 len; ++ uint8 chain_dis; ++ uint8 flag; ++} wlc_btc_2gchain_dis_t; ++ ++#define WLC_BTC_2GCHAIN_DIS_REASSOC 0x1 ++#define WLC_BTC_2GCHAIN_DIS_VER1 0x1 ++#define WLC_BTC_2GCHAIN_DIS_VER1_LEN 6 ++ ++enum wl_rpsnoa_cmd_ids { ++ WL_RPSNOA_CMD_ENABLE = 1, ++ WL_RPSNOA_CMD_STATUS, ++ WL_RPSNOA_CMD_PARAMS, ++ WL_RPSNOA_CMD_LAST ++}; ++ ++typedef struct rpsnoa_cmnhdr { ++ uint16 ver; /* cmd structure version */ ++ uint16 len; /* cmd structure len */ ++ uint32 subcmd; ++ uint32 cnt; ++} rpsnoa_cmnhdr_t; ++ ++typedef struct rpsnoa_data { ++ int16 band; ++ int16 value; ++} rpsnoa_data_t; ++ ++typedef struct rpsnoa_param { ++ uint16 band; ++ uint8 level; ++ uint8 stas_assoc_check; ++ uint32 pps; ++ uint32 quiet_time; ++} rpsnoa_param_t; ++ ++typedef struct rpsnoa_iovar { ++ rpsnoa_cmnhdr_t hdr; ++ rpsnoa_data_t data[1]; ++} rpsnoa_iovar_t; ++ ++typedef struct rpsnoa_iovar_params { ++ rpsnoa_cmnhdr_t hdr; ++ rpsnoa_param_t param[1]; ++} rpsnoa_iovar_params_t; ++ ++/* Per-interface reportable stats types */ ++enum wl_ifstats_xtlv_id { ++ /* global */ ++ WL_IFSTATS_XTLV_SLICE_INDEX = 1, ++ WL_IFSTATS_XTLV_IF_INDEX = 2, ++ WL_IFSTATS_XTLV_MAC_ADDR = 3, ++ WL_IFSTATS_XTLV_REPORT_CMD = 4, /* Comes in an iovar */ ++ WL_IFSTATS_XTLV_BUS_PCIE = 5, ++ ++ /* Report data across all SCBs using ecounters */ ++ WL_IFSTATS_XTLV_WL_STA_INFO_ECOUNTERS = 0x100, ++ ++ /* Per-slice information ++ * Per-interface reporting could also include slice specific data ++ */ ++ /* xtlv container for reporting */ ++ WL_IFSTATS_XTLV_WL_SLICE = 0x301, ++ /* Per-slice AMPDU stats */ ++ WL_IFSTATS_XTLV_WL_SLICE_AMPDU_DUMP = 0x302, ++ /* Per-slice BTCOEX stats */ ++ WL_IFSTATS_XTLV_WL_SLICE_BTCOEX = 0x303, ++ /* V11_WLCNTRS used in ecounters */ ++ WL_IFSTATS_XTLV_WL_SLICE_V11_WLCNTRS = 0x304, ++ /* V30_WLCNTRS Used in ecounters */ ++ WL_IFSTATS_XTLV_WL_SLICE_V30_WLCNTRS = 0x305, ++ ++ /* Per-interface */ ++ /* XTLV container for reporting */ ++ WL_IFSTATS_XTLV_IF = 0x501, ++ /* Generic stats applicable to all IFs */ ++ WL_IFSTATS_XTLV_GENERIC = 0x502, ++ /* Infra specific */ ++ WL_IFSTATS_XTLV_INFRA_SPECIFIC = 0x503, ++ /* MGT counters infra and softAP */ ++ WL_IFSTATS_XTLV_MGT_CNT = 0x504, ++ /* AMPDU stats on per-IF */ ++ WL_IFSTATS_XTLV_AMPDU_DUMP = 0x505, ++ WL_IFSTATS_XTLV_IF_SPECIFIC = 0x506 ++}; ++ ++/* interface specific mgt count */ ++#define WL_MGT_STATS_VERSION_V1 1 ++/* Associated stats type: WL_IFSTATS_MGT_CNT */ ++typedef struct { ++ uint16 version; ++ uint8 pad[2]; ++ ++ /* detailed control/management frames */ ++ uint32 txnull; ++ uint32 rxnull; ++ uint32 txqosnull; ++ uint32 rxqosnull; ++ uint32 txassocreq; ++ uint32 rxassocreq; ++ uint32 txreassocreq; ++ uint32 rxreassocreq; ++ uint32 txdisassoc; ++ uint32 rxdisassoc; ++ uint32 txassocrsp; ++ uint32 rxassocrsp; ++ uint32 txreassocrsp; ++ uint32 rxreassocrsp; ++ uint32 txauth; ++ uint32 rxauth; ++ uint32 txdeauth; ++ uint32 rxdeauth; ++ uint32 txprobereq; ++ uint32 rxprobereq; ++ uint32 txprobersp; ++ uint32 rxprobersp; ++ uint32 txaction; ++ uint32 rxaction; ++ uint32 txpspoll; ++ uint32 rxpspoll; ++} wl_if_mgt_stats_t; ++ ++#define WL_INFRA_STATS_VERSION_V1 1 ++/* Associated stats type: WL_IFSTATS_INFRA_SPECIFIC */ ++typedef struct wl_infra_stats { ++ uint16 version; /**< version of the structure */ ++ uint8 pad[2]; ++ uint32 rxbeaconmbss; ++ uint32 tbtt; ++} wl_if_infra_stats_t; ++ ++typedef struct csa_event_data { ++ chanspec_t chan_old; ++ dot11_ext_csa_ie_t ecsa; ++ dot11_mesh_csp_ie_t mcsp; ++ dot11_wide_bw_chan_switch_ie_t wbcs; ++ uint8 PAD; ++} csa_event_data_t; ++ ++#endif /* _wlioctl_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl_defs.h b/module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl_defs.h +new file mode 100644 +index 000000000..de0fb1d3e +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl_defs.h +@@ -0,0 +1,2243 @@ ++/* ++ * Custom OID/ioctl definitions for ++ * Broadcom 802.11abg Networking Device Driver ++ * ++ * Definitions subject to change without notice. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: wlioctl_defs.h 677667 2017-01-04 07:43:05Z $ ++ */ ++ ++ ++#ifndef wlioctl_defs_h ++#define wlioctl_defs_h ++ ++ ++ ++ ++/* All builds use the new 11ac ratespec/chanspec */ ++#undef D11AC_IOTYPES ++#define D11AC_IOTYPES ++ ++#ifndef USE_NEW_RSPEC_DEFS ++/* WL_RSPEC defines for rate information */ ++#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */ ++#define WL_RSPEC_HE_MCS_MASK 0x0000000F /* HE MCS value */ ++#define WL_RSPEC_HE_NSS_MASK 0x000000F0 /* HE Nss value */ ++#define WL_RSPEC_HE_NSS_SHIFT 4 /* HE Nss value shift */ ++#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /* VHT MCS value */ ++#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /* VHT Nss value */ ++#define WL_RSPEC_VHT_NSS_SHIFT 4 /* VHT Nss value shift */ ++#define WL_RSPEC_TXEXP_MASK 0x00000300 ++#define WL_RSPEC_TXEXP_SHIFT 8 ++#define WL_RSPEC_BW_MASK 0x00070000 /* bandwidth mask */ ++#define WL_RSPEC_BW_SHIFT 16 /* bandwidth shift */ ++#define WL_RSPEC_STBC 0x00100000 /* STBC encoding, Nsts = 2 x Nss */ ++#define WL_RSPEC_TXBF 0x00200000 /* bit indicates TXBF mode */ ++#define WL_RSPEC_LDPC 0x00400000 /* bit indicates adv coding in use */ ++#define WL_RSPEC_SGI 0x00800000 /* Short GI mode */ ++#define WL_RSPEC_ENCODING_MASK 0x03000000 /* Encoding of Rate/MCS field */ ++#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /* bit indicate to override mcs only */ ++#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /* bit indicates override rate & mode */ ++ ++/* WL_RSPEC_ENCODING field defs */ ++#define WL_RSPEC_ENCODE_RATE 0x00000000 /* Legacy rate is stored in RSPEC_RATE_MASK */ ++#define WL_RSPEC_ENCODE_HT 0x01000000 /* HT MCS is stored in RSPEC_RATE_MASK */ ++#define WL_RSPEC_ENCODE_VHT 0x02000000 /* VHT MCS and Nss is stored in RSPEC_RATE_MASK */ ++#define WL_RSPEC_ENCODE_HE 0x03000000 /* HE MCS and Nss is stored in RSPEC_RATE_MASK */ ++ ++/* WL_RSPEC_BW field defs */ ++#define WL_RSPEC_BW_UNSPECIFIED 0 ++#define WL_RSPEC_BW_20MHZ 0x00010000 ++#define WL_RSPEC_BW_40MHZ 0x00020000 ++#define WL_RSPEC_BW_80MHZ 0x00030000 ++#define WL_RSPEC_BW_160MHZ 0x00040000 ++#define WL_RSPEC_BW_10MHZ 0x00050000 ++#define WL_RSPEC_BW_5MHZ 0x00060000 ++#define WL_RSPEC_BW_2P5MHZ 0x00070000 ++ ++#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */ ++ ++#endif /* !USE_NEW_RSPEC_DEFS */ ++ ++/* Legacy defines for the nrate iovar */ ++#define OLD_NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */ ++#define OLD_NRATE_RATE_MASK 0x0000007f /* rate/mcs value */ ++#define OLD_NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */ ++#define OLD_NRATE_STF_SHIFT 8 /* stf mode shift */ ++#define OLD_NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */ ++#define OLD_NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */ ++#define OLD_NRATE_SGI 0x00800000 /* sgi mode */ ++#define OLD_NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ ++ ++#define OLD_NRATE_STF_SISO 0 /* stf mode SISO */ ++#define OLD_NRATE_STF_CDD 1 /* stf mode CDD */ ++#define OLD_NRATE_STF_STBC 2 /* stf mode STBC */ ++#define OLD_NRATE_STF_SDM 3 /* stf mode SDM */ ++ ++#define WLC_11N_N_PROP_MCS 6 ++#define WLC_11N_FIRST_PROP_MCS 87 ++#define WLC_11N_LAST_PROP_MCS 102 ++ ++#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */ ++#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */ ++ ++#define IBSS_MED 15 /* Mediom in-bss congestion percentage */ ++#define IBSS_HI 25 /* Hi in-bss congestion percentage */ ++#define OBSS_MED 12 ++#define OBSS_HI 25 ++#define INTERFER_MED 5 ++#define INTERFER_HI 10 ++ ++#define CCA_FLAG_2G_ONLY 0x01 /* Return a channel from 2.4 Ghz band */ ++#define CCA_FLAG_5G_ONLY 0x02 /* Return a channel from 2.4 Ghz band */ ++#define CCA_FLAG_IGNORE_DURATION 0x04 /* Ignore dwell time for each channel */ ++#define CCA_FLAGS_PREFER_1_6_11 0x10 ++#define CCA_FLAG_IGNORE_INTERFER 0x20 /* do not exlude channel based on interfer level */ ++ ++#define CCA_ERRNO_BAND 1 /* After filtering for band pref, no choices left */ ++#define CCA_ERRNO_DURATION 2 /* After filtering for duration, no choices left */ ++#define CCA_ERRNO_PREF_CHAN 3 /* After filtering for chan pref, no choices left */ ++#define CCA_ERRNO_INTERFER 4 /* After filtering for interference, no choices left */ ++#define CCA_ERRNO_TOO_FEW 5 /* Only 1 channel was input */ ++ ++#define WL_STA_AID(a) ((a) &~ 0xc000) ++ ++/* Flags for sta_info_t indicating properties of STA */ ++#define WL_STA_BRCM 0x00000001 /* Running a Broadcom driver */ ++#define WL_STA_WME 0x00000002 /* WMM association */ ++#define WL_STA_NONERP 0x00000004 /* No ERP */ ++#define WL_STA_AUTHE 0x00000008 /* Authenticated */ ++#define WL_STA_ASSOC 0x00000010 /* Associated */ ++#define WL_STA_AUTHO 0x00000020 /* Authorized */ ++#define WL_STA_WDS 0x00000040 /* Wireless Distribution System */ ++#define WL_STA_WDS_LINKUP 0x00000080 /* WDS traffic/probes flowing properly */ ++#define WL_STA_PS 0x00000100 /* STA is in power save mode from AP's viewpoint */ ++#define WL_STA_APSD_BE 0x00000200 /* APSD delv/trigger for AC_BE is default enabled */ ++#define WL_STA_APSD_BK 0x00000400 /* APSD delv/trigger for AC_BK is default enabled */ ++#define WL_STA_APSD_VI 0x00000800 /* APSD delv/trigger for AC_VI is default enabled */ ++#define WL_STA_APSD_VO 0x00001000 /* APSD delv/trigger for AC_VO is default enabled */ ++#define WL_STA_N_CAP 0x00002000 /* STA 802.11n capable */ ++#define WL_STA_SCBSTATS 0x00004000 /* Per STA debug stats */ ++#define WL_STA_AMPDU_CAP 0x00008000 /* STA AMPDU capable */ ++#define WL_STA_AMSDU_CAP 0x00010000 /* STA AMSDU capable */ ++#define WL_STA_MIMO_PS 0x00020000 /* mimo ps mode is enabled */ ++#define WL_STA_MIMO_RTS 0x00040000 /* send rts in mimo ps mode */ ++#define WL_STA_RIFS_CAP 0x00080000 /* rifs enabled */ ++#define WL_STA_VHT_CAP 0x00100000 /* STA VHT(11ac) capable */ ++#define WL_STA_WPS 0x00200000 /* WPS state */ ++#define WL_STA_DWDS_CAP 0x01000000 /* DWDS CAP */ ++#define WL_STA_DWDS 0x02000000 /* DWDS active */ ++#define WL_WDS_LINKUP WL_STA_WDS_LINKUP /* deprecated */ ++ ++/* STA HT cap fields */ ++#define WL_STA_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ ++#define WL_STA_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ ++#define WL_STA_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ ++#define WL_STA_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ ++#define WL_STA_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ ++#define WL_STA_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ ++#define WL_STA_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ ++#define WL_STA_CAP_GF 0x0010 /* Greenfield preamble support */ ++#define WL_STA_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ ++#define WL_STA_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ ++#define WL_STA_CAP_TX_STBC 0x0080 /* Tx STBC support */ ++#define WL_STA_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ ++#define WL_STA_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ ++#define WL_STA_CAP_DELAYED_BA 0x0400 /* delayed BA support */ ++#define WL_STA_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ ++#define WL_STA_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ ++#define WL_STA_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ ++#define WL_STA_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ ++#define WL_STA_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ ++ ++#define WL_STA_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ ++#define WL_STA_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ ++#define WL_STA_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ ++#define WL_STA_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ ++ ++/* scb vht flags */ ++#define WL_STA_VHT_LDPCCAP 0x0001 ++#define WL_STA_SGI80 0x0002 ++#define WL_STA_SGI160 0x0004 ++#define WL_STA_VHT_TX_STBCCAP 0x0008 ++#define WL_STA_VHT_RX_STBCCAP 0x0010 ++#define WL_STA_SU_BEAMFORMER 0x0020 ++#define WL_STA_SU_BEAMFORMEE 0x0040 ++#define WL_STA_MU_BEAMFORMER 0x0080 ++#define WL_STA_MU_BEAMFORMEE 0x0100 ++#define WL_STA_VHT_TXOP_PS 0x0200 ++#define WL_STA_HTC_VHT_CAP 0x0400 ++ ++/* Values for TX Filter override mode */ ++#define WLC_TXFILTER_OVERRIDE_DISABLED 0 ++#define WLC_TXFILTER_OVERRIDE_ENABLED 1 ++ ++#define WL_IOCTL_ACTION_GET 0x0 ++#define WL_IOCTL_ACTION_SET 0x1 ++#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e ++#define WL_IOCTL_ACTION_OVL_RSV 0x20 ++#define WL_IOCTL_ACTION_OVL 0x40 ++#define WL_IOCTL_ACTION_MASK 0x7e ++#define WL_IOCTL_ACTION_OVL_SHIFT 1 ++ ++/* For WLC_SET_INFRA ioctl & infra_configuration iovar SET/GET operations */ ++#define WL_BSSTYPE_INDEP 0 ++#define WL_BSSTYPE_INFRA 1 ++#define WL_BSSTYPE_ANY 2 /* deprecated */ ++#define WL_BSSTYPE_MESH 3 ++/* Bitmask for scan_type */ ++#define WL_SCANFLAGS_PASSIVE 0x01 /* force passive scan */ ++#define WL_SCANFLAGS_RESERVED 0x02 /* Reserved */ ++#define WL_SCANFLAGS_PROHIBITED 0x04 /* allow scanning prohibited channels */ ++#define WL_SCANFLAGS_OFFCHAN 0x08 /* allow scanning/reporting off-channel APs */ ++#define WL_SCANFLAGS_HOTSPOT 0x10 /* automatic ANQP to hotspot APs */ ++#define WL_SCANFLAGS_SWTCHAN 0x20 /* Force channel switch for differerent bandwidth */ ++#define WL_SCANFLAGS_FORCE_PARALLEL 0x40 /* Force parallel scan even when actcb_fn_t is on. ++ * by default parallel scan will be disabled if actcb_fn_t ++ * is provided. ++ */ ++#define WL_SCANFLAGS_SISO 0x40 /* Use 1 RX chain for scanning */ ++#define WL_SCANFLAGS_MIMO 0x80 /* Force MIMO scanning */ ++ ++/* wl_iscan_results status values */ ++#define WL_SCAN_RESULTS_SUCCESS 0 ++#define WL_SCAN_RESULTS_PARTIAL 1 ++#define WL_SCAN_RESULTS_PENDING 2 ++#define WL_SCAN_RESULTS_ABORTED 3 ++#define WL_SCAN_RESULTS_NO_MEM 4 ++ ++#define SCANOL_ENABLED (1 << 0) ++#define SCANOL_BCAST_SSID (1 << 1) ++#define SCANOL_NOTIFY_BCAST_SSID (1 << 2) ++#define SCANOL_RESULTS_PER_CYCLE (1 << 3) ++ ++/* scan times in milliseconds */ ++#define SCANOL_HOME_TIME 45 /* for home channel processing */ ++#define SCANOL_ASSOC_TIME 20 /* dwell on a channel while associated */ ++#define SCANOL_UNASSOC_TIME 40 /* dwell on a channel while unassociated */ ++#define SCANOL_PASSIVE_TIME 110 /* listen on a channelfor passive scan */ ++#define SCANOL_AWAY_LIMIT 100 /* max time to be away from home channel */ ++#define SCANOL_IDLE_REST_TIME 40 ++#define SCANOL_IDLE_REST_MULTIPLIER 0 ++#define SCANOL_ACTIVE_REST_TIME 20 ++#define SCANOL_ACTIVE_REST_MULTIPLIER 0 ++#define SCANOL_CYCLE_IDLE_REST_TIME 300000 /* Idle Rest Time between Scan Cycle (msec) */ ++#define SCANOL_CYCLE_IDLE_REST_MULTIPLIER 0 /* Idle Rest Time Multiplier */ ++#define SCANOL_CYCLE_ACTIVE_REST_TIME 200 ++#define SCANOL_CYCLE_ACTIVE_REST_MULTIPLIER 0 ++#define SCANOL_MAX_REST_TIME 3600000 /* max rest time between scan cycle (msec) */ ++#define SCANOL_CYCLE_DEFAULT 0 /* default for Max Scan Cycle, 0 = forever */ ++#define SCANOL_CYCLE_MAX 864000 /* Max Scan Cycle */ ++ /* 10 sec/scan cycle => 100 days */ ++#define SCANOL_NPROBES 2 /* for Active scan; send n probes on each channel */ ++#define SCANOL_NPROBES_MAX 5 /* for Active scan; send n probes on each channel */ ++#define SCANOL_SCAN_START_DLY 10 /* delay start of offload scan (sec) */ ++#define SCANOL_SCAN_START_DLY_MAX 240 /* delay start of offload scan (sec) */ ++#define SCANOL_MULTIPLIER_MAX 10 /* Max Multiplier */ ++#define SCANOL_UNASSOC_TIME_MAX 100 /* max dwell on a channel while unassociated */ ++#define SCANOL_PASSIVE_TIME_MAX 500 /* max listen on a channel for passive scan */ ++#define SCANOL_SSID_MAX 16 /* max supported preferred SSID */ ++ ++/* masks for channel and ssid count */ ++#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff ++#define WL_SCAN_PARAMS_NSSID_SHIFT 16 ++ ++#define WL_SCAN_ACTION_START 1 ++#define WL_SCAN_ACTION_CONTINUE 2 ++#define WL_SCAN_ACTION_ABORT 3 ++ ++#define ANTENNA_NUM_1 1 /* total number of antennas to be used */ ++#define ANTENNA_NUM_2 2 ++#define ANTENNA_NUM_3 3 ++#define ANTENNA_NUM_4 4 ++ ++#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */ ++#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */ ++#define ANT_SELCFG_TX_UNICAST 0 /* unicast tx antenna configuration */ ++#define ANT_SELCFG_RX_UNICAST 1 /* unicast rx antenna configuration */ ++#define ANT_SELCFG_TX_DEF 2 /* default tx antenna configuration */ ++#define ANT_SELCFG_RX_DEF 3 /* default rx antenna configuration */ ++ ++/* interference source detection and identification mode */ ++#define ITFR_MODE_DISABLE 0 /* disable feature */ ++#define ITFR_MODE_MANUAL_ENABLE 1 /* enable manual detection */ ++#define ITFR_MODE_AUTO_ENABLE 2 /* enable auto detection */ ++ ++/* bit definitions for flags in interference source report */ ++#define ITFR_INTERFERENCED 1 /* interference detected */ ++#define ITFR_HOME_CHANNEL 2 /* home channel has interference */ ++#define ITFR_NOISY_ENVIRONMENT 4 /* noisy environemnt so feature stopped */ ++ ++#define WL_NUM_RPI_BINS 8 ++#define WL_RM_TYPE_BASIC 1 ++#define WL_RM_TYPE_CCA 2 ++#define WL_RM_TYPE_RPI 3 ++#define WL_RM_TYPE_ABORT -1 /* ABORT any in-progress RM request */ ++ ++#define WL_RM_FLAG_PARALLEL (1<<0) ++ ++#define WL_RM_FLAG_LATE (1<<1) ++#define WL_RM_FLAG_INCAPABLE (1<<2) ++#define WL_RM_FLAG_REFUSED (1<<3) ++ ++/* flags */ ++#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ ++ ++#define WLC_CIS_DEFAULT 0 /* built-in default */ ++#define WLC_CIS_SROM 1 /* source is sprom */ ++#define WLC_CIS_OTP 2 /* source is otp */ ++ ++/* PCL - Power Control Loop */ ++/* current gain setting is replaced by user input */ ++#define WL_ATTEN_APP_INPUT_PCL_OFF 0 /* turn off PCL, apply supplied input */ ++#define WL_ATTEN_PCL_ON 1 /* turn on PCL */ ++/* current gain setting is maintained */ ++#define WL_ATTEN_PCL_OFF 2 /* turn off PCL. */ ++ ++/* defines used by poweridx iovar - it controls power in a-band */ ++/* current gain setting is maintained */ ++#define WL_PWRIDX_PCL_OFF -2 /* turn off PCL. */ ++#define WL_PWRIDX_PCL_ON -1 /* turn on PCL */ ++#define WL_PWRIDX_LOWER_LIMIT -2 /* lower limit */ ++#define WL_PWRIDX_UPPER_LIMIT 63 /* upper limit */ ++/* value >= 0 causes ++ * - input to be set to that value ++ * - PCL to be off ++ */ ++ ++#define BCM_MAC_STATUS_INDICATION (0x40010200L) ++ ++/* Values for TX Filter override mode */ ++#define WLC_TXFILTER_OVERRIDE_DISABLED 0 ++#define WLC_TXFILTER_OVERRIDE_ENABLED 1 ++ ++/* magic pattern used for mismatch driver and wl */ ++#define WL_TXFIFO_SZ_MAGIC 0xa5a5 ++ ++/* check this magic number */ ++#define WLC_IOCTL_MAGIC 0x14e46c77 ++ ++ ++/* bss_info_cap_t flags */ ++#define WL_BSS_FLAGS_FROM_BEACON 0x01 /* bss_info derived from beacon */ ++#define WL_BSS_FLAGS_FROM_CACHE 0x02 /* bss_info collected from cache */ ++#define WL_BSS_FLAGS_RSSI_ONCHANNEL 0x04 /* rssi info received on channel (vs offchannel) */ ++#define WL_BSS_FLAGS_HS20 0x08 /* hotspot 2.0 capable */ ++#define WL_BSS_FLAGS_RSSI_INVALID 0x10 /* BSS contains invalid RSSI */ ++#define WL_BSS_FLAGS_RSSI_INACCURATE 0x20 /* BSS contains inaccurate RSSI */ ++#define WL_BSS_FLAGS_SNR_INVALID 0x40 /* BSS contains invalid SNR */ ++#define WL_BSS_FLAGS_NF_INVALID 0x80 /* BSS contains invalid noise floor */ ++ ++/* bit definitions for bcnflags in wl_bss_info */ ++#define WL_BSS_BCNFLAGS_INTERWORK_PRESENT 0x01 /* beacon had IE, accessnet valid */ ++#define WL_BSS_BCNFLAGS_INTERWORK_PRESENT_VALID 0x02 /* on indicates support for this API */ ++ ++/* bssinfo flag for nbss_cap */ ++#define VHT_BI_SGI_80MHZ 0x00000100 ++#define VHT_BI_80MHZ 0x00000200 ++#define VHT_BI_160MHZ 0x00000400 ++#define VHT_BI_8080MHZ 0x00000800 ++ ++/* reference to wl_ioctl_t struct used by usermode driver */ ++#define ioctl_subtype set /* subtype param */ ++#define ioctl_pid used /* pid param */ ++#define ioctl_status needed /* status param */ ++ ++ ++/* Enumerate crypto algorithms */ ++#define CRYPTO_ALGO_OFF 0 ++#define CRYPTO_ALGO_WEP1 1 ++#define CRYPTO_ALGO_TKIP 2 ++#define CRYPTO_ALGO_WEP128 3 ++#define CRYPTO_ALGO_AES_CCM 4 ++#define CRYPTO_ALGO_AES_OCB_MSDU 5 ++#define CRYPTO_ALGO_AES_OCB_MPDU 6 ++#if !defined(BCMEXTCCX) ++#define CRYPTO_ALGO_NALG 7 ++#else ++#define CRYPTO_ALGO_CKIP 7 ++#define CRYPTO_ALGO_CKIP_MMH 8 ++#define CRYPTO_ALGO_WEP_MMH 9 ++#define CRYPTO_ALGO_NALG 10 ++#endif ++ ++#define CRYPTO_ALGO_SMS4 11 ++#define CRYPTO_ALGO_PMK 12 /* for 802.1x supp to set PMK before 4-way */ ++#define CRYPTO_ALGO_BIP 13 /* 802.11w BIP (aes cmac) */ ++ ++#define CRYPTO_ALGO_AES_GCM 14 /* 128 bit GCM */ ++#define CRYPTO_ALGO_AES_CCM256 15 /* 256 bit CCM */ ++#define CRYPTO_ALGO_AES_GCM256 16 /* 256 bit GCM */ ++#define CRYPTO_ALGO_BIP_CMAC256 17 /* 256 bit BIP CMAC */ ++#define CRYPTO_ALGO_BIP_GMAC 18 /* 128 bit BIP GMAC */ ++#define CRYPTO_ALGO_BIP_GMAC256 19 /* 256 bit BIP GMAC */ ++ ++#define CRYPTO_ALGO_NONE CRYPTO_ALGO_OFF ++ ++/* algo bit vector */ ++#define KEY_ALGO_MASK(_algo) (1 << _algo) ++ ++#if defined(BCMEXTCCX) ++#define KEY_ALGO_MASK_CCX (KEY_ALGO_MASK(CRYPTO_ALGO_CKIP) | \ ++ KEY_ALGO_MASK(CRYPTO_ALGO_CKIP_MMH) | \ ++ KEY_ALGO_MASK(CRYPTO_ALGO_WEP_MMH)) ++#endif ++ ++#define KEY_ALGO_MASK_WEP (KEY_ALGO_MASK(CRYPTO_ALGO_WEP1) | \ ++ KEY_ALGO_MASK(CRYPTO_ALGO_WEP128) | \ ++ KEY_ALGO_MASK(CRYPTO_ALGO_NALG)) ++ ++#define KEY_ALGO_MASK_AES (KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM) | \ ++ KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM256) | \ ++ KEY_ALGO_MASK(CRYPTO_ALGO_AES_GCM) | \ ++ KEY_ALGO_MASK(CRYPTO_ALGO_AES_GCM256)) ++#define KEY_ALGO_MASK_TKIP (KEY_ALGO_MASK(CRYPTO_ALGO_TKIP)) ++#define KEY_ALGO_MASK_WAPI (KEY_ALGO_MASK(CRYPTO_ALGO_SMS4)) ++ ++#define WSEC_GEN_MIC_ERROR 0x0001 ++#define WSEC_GEN_REPLAY 0x0002 ++#define WSEC_GEN_ICV_ERROR 0x0004 ++#define WSEC_GEN_MFP_ACT_ERROR 0x0008 ++#define WSEC_GEN_MFP_DISASSOC_ERROR 0x0010 ++#define WSEC_GEN_MFP_DEAUTH_ERROR 0x0020 ++ ++#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */ ++#define WL_PRIMARY_KEY (1 << 1) /* Indicates this key is the primary (ie tx) key */ ++#if defined(BCMEXTCCX) ++#define WL_CKIP_KP (1 << 4) /* CMIC */ ++#define WL_CKIP_MMH (1 << 5) /* CKIP */ ++#else ++#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */ ++#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */ ++#endif ++#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */ ++ ++/* wireless security bitvec */ ++#define WSEC_NONE 0x0 ++#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 */ ++#ifdef BCMWAPI_WPI ++#define SMS4_ENABLED 0x0100 ++#endif /* BCMWAPI_WPI */ ++ ++#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED) ++#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED) ++#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED) ++ ++#ifdef BCMCCX ++#define WSEC_CKIP_KP_ENABLED(wsec) ((wsec) & CKIP_KP_ENABLED) ++#define WSEC_CKIP_MIC_ENABLED(wsec) ((wsec) & CKIP_MIC_ENABLED) ++#define WSEC_CKIP_ENABLED(wsec) ((wsec) & (CKIP_KP_ENABLED|CKIP_MIC_ENABLED)) ++ ++#ifdef BCMWAPI_WPI ++#define WSEC_ENABLED(wsec) \ ++ ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | \ ++ CKIP_MIC_ENABLED | SMS4_ENABLED)) ++#else /* BCMWAPI_WPI */ ++#define WSEC_ENABLED(wsec) \ ++ ((wsec) & \ ++ (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | CKIP_KP_ENABLED | CKIP_MIC_ENABLED)) ++#endif /* BCMWAPI_WPI */ ++#else /* defined BCMCCX */ ++#ifdef BCMWAPI_WPI ++#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) ++#else /* BCMWAPI_WPI */ ++#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) ++#endif /* BCMWAPI_WPI */ ++#endif /* BCMCCX */ ++ ++#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED) ++#ifdef BCMWAPI_WAI ++#define WSEC_SMS4_ENABLED(wsec) ((wsec) & SMS4_ENABLED) ++#endif /* BCMWAPI_WAI */ ++ ++/* Following macros are not used any more. Just kept here to ++ * avoid build issue in BISON/CARIBOU branch ++ */ ++#define MFP_CAPABLE 0x0200 ++#define MFP_REQUIRED 0x0400 ++#define MFP_SHA256 0x0800 /* a special configuration for STA for WIFI test tool */ ++ ++/* WPA authentication mode bitvec */ ++#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */ ++#define WPA_AUTH_NONE 0x0001 /* none (IBSS) */ ++#define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */ ++#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */ ++#if defined(BCMEXTCCX) ++#define WPA_AUTH_CCKM 0x0008 /* CCKM */ ++#define WPA2_AUTH_CCKM 0x0010 /* CCKM2 */ ++#endif ++/* #define WPA_AUTH_8021X 0x0020 */ /* 802.1x, reserved */ ++#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ ++#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ ++#define BRCM_AUTH_PSK 0x0100 /* BRCM specific PSK */ ++#define BRCM_AUTH_DPT 0x0200 /* DPT PSK without group keys */ ++#if defined(BCMWAPI_WAI) || defined(BCMWAPI_WPI) ++#define WPA_AUTH_WAPI 0x0400 ++#define WAPI_AUTH_NONE WPA_AUTH_NONE /* none (IBSS) */ ++#define WAPI_AUTH_UNSPECIFIED 0x0400 /* over AS */ ++#define WAPI_AUTH_PSK 0x0800 /* Pre-shared key */ ++#endif /* BCMWAPI_WAI || BCMWAPI_WPI */ ++#define WPA2_AUTH_1X_SHA256 0x1000 /* 1X with SHA256 key derivation */ ++#define WPA2_AUTH_TPK 0x2000 /* TDLS Peer Key */ ++#define WPA2_AUTH_FT 0x4000 /* Fast Transition. */ ++#define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */ ++#define WPA3_AUTH_SAE_PSK 0x40000 /* SAE with 4-way handshake */ ++/* WPA2_AUTH_SHA256 not used anymore. Just kept here to avoid build issue in DINGO */ ++#define WPA2_AUTH_SHA256 0x8000 ++#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ ++ ++/* pmkid */ ++#define MAXPMKID 16 ++ ++/* SROM12 changes */ ++#define WLC_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */ ++ ++ ++#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */ ++#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */ ++#if defined(LCNCONF) || defined(LCN40CONF) || defined(LCN20CONF) ++#define WLC_SAMPLECOLLECT_MAXLEN 8192 /* Max Sample Collect buffer */ ++#else ++#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */ ++#endif ++#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192 ++ ++/* common ioctl definitions */ ++#define WLC_GET_MAGIC 0 ++#define WLC_GET_VERSION 1 ++#define WLC_UP 2 ++#define WLC_DOWN 3 ++#define WLC_GET_LOOP 4 ++#define WLC_SET_LOOP 5 ++#define WLC_DUMP 6 ++#define WLC_GET_MSGLEVEL 7 ++#define WLC_SET_MSGLEVEL 8 ++#define WLC_GET_PROMISC 9 ++#define WLC_SET_PROMISC 10 ++/* #define WLC_OVERLAY_IOCTL 11 */ /* not supported */ ++#define WLC_GET_RATE 12 ++#define WLC_GET_MAX_RATE 13 ++#define WLC_GET_INSTANCE 14 ++/* #define WLC_GET_FRAG 15 */ /* no longer supported */ ++/* #define WLC_SET_FRAG 16 */ /* no longer supported */ ++/* #define WLC_GET_RTS 17 */ /* no longer supported */ ++/* #define WLC_SET_RTS 18 */ /* no longer supported */ ++#define WLC_GET_INFRA 19 ++#define WLC_SET_INFRA 20 ++#define WLC_GET_AUTH 21 ++#define WLC_SET_AUTH 22 ++#define WLC_GET_BSSID 23 ++#define WLC_SET_BSSID 24 ++#define WLC_GET_SSID 25 ++#define WLC_SET_SSID 26 ++#define WLC_RESTART 27 ++#define WLC_TERMINATED 28 ++/* #define WLC_DUMP_SCB 28 */ /* no longer supported */ ++#define WLC_GET_CHANNEL 29 ++#define WLC_SET_CHANNEL 30 ++#define WLC_GET_SRL 31 ++#define WLC_SET_SRL 32 ++#define WLC_GET_LRL 33 ++#define WLC_SET_LRL 34 ++#define WLC_GET_PLCPHDR 35 ++#define WLC_SET_PLCPHDR 36 ++#define WLC_GET_RADIO 37 ++#define WLC_SET_RADIO 38 ++#define WLC_GET_PHYTYPE 39 ++#define WLC_DUMP_RATE 40 ++#define WLC_SET_RATE_PARAMS 41 ++#define WLC_GET_FIXRATE 42 ++#define WLC_SET_FIXRATE 43 ++/* #define WLC_GET_WEP 42 */ /* no longer supported */ ++/* #define WLC_SET_WEP 43 */ /* no longer supported */ ++#define WLC_GET_KEY 44 ++#define WLC_SET_KEY 45 ++#define WLC_GET_REGULATORY 46 ++#define WLC_SET_REGULATORY 47 ++#define WLC_GET_PASSIVE_SCAN 48 ++#define WLC_SET_PASSIVE_SCAN 49 ++#define WLC_SCAN 50 ++#define WLC_SCAN_RESULTS 51 ++#define WLC_DISASSOC 52 ++#define WLC_REASSOC 53 ++#define WLC_GET_ROAM_TRIGGER 54 ++#define WLC_SET_ROAM_TRIGGER 55 ++#define WLC_GET_ROAM_DELTA 56 ++#define WLC_SET_ROAM_DELTA 57 ++#define WLC_GET_ROAM_SCAN_PERIOD 58 ++#define WLC_SET_ROAM_SCAN_PERIOD 59 ++#define WLC_EVM 60 /* diag */ ++#define WLC_GET_TXANT 61 ++#define WLC_SET_TXANT 62 ++#define WLC_GET_ANTDIV 63 ++#define WLC_SET_ANTDIV 64 ++/* #define WLC_GET_TXPWR 65 */ /* no longer supported */ ++/* #define WLC_SET_TXPWR 66 */ /* no longer supported */ ++#define WLC_GET_CLOSED 67 ++#define WLC_SET_CLOSED 68 ++#define WLC_GET_MACLIST 69 ++#define WLC_SET_MACLIST 70 ++#define WLC_GET_RATESET 71 ++#define WLC_SET_RATESET 72 ++/* #define WLC_GET_LOCALE 73 */ /* no longer supported */ ++#define WLC_LONGTRAIN 74 ++#define WLC_GET_BCNPRD 75 ++#define WLC_SET_BCNPRD 76 ++#define WLC_GET_DTIMPRD 77 ++#define WLC_SET_DTIMPRD 78 ++#define WLC_GET_SROM 79 ++#define WLC_SET_SROM 80 ++#define WLC_GET_WEP_RESTRICT 81 ++#define WLC_SET_WEP_RESTRICT 82 ++#define WLC_GET_COUNTRY 83 ++#define WLC_SET_COUNTRY 84 ++#define WLC_GET_PM 85 ++#define WLC_SET_PM 86 ++#define WLC_GET_WAKE 87 ++#define WLC_SET_WAKE 88 ++/* #define WLC_GET_D11CNTS 89 */ /* -> "counters" iovar */ ++#define WLC_GET_FORCELINK 90 /* ndis only */ ++#define WLC_SET_FORCELINK 91 /* ndis only */ ++#define WLC_FREQ_ACCURACY 92 /* diag */ ++#define WLC_CARRIER_SUPPRESS 93 /* diag */ ++#define WLC_GET_PHYREG 94 ++#define WLC_SET_PHYREG 95 ++#define WLC_GET_RADIOREG 96 ++#define WLC_SET_RADIOREG 97 ++#define WLC_GET_REVINFO 98 ++#define WLC_GET_UCANTDIV 99 ++#define WLC_SET_UCANTDIV 100 ++#define WLC_R_REG 101 ++#define WLC_W_REG 102 ++/* #define WLC_DIAG_LOOPBACK 103 old tray diag */ ++/* #define WLC_RESET_D11CNTS 104 */ /* -> "reset_d11cnts" iovar */ ++#define WLC_GET_MACMODE 105 ++#define WLC_SET_MACMODE 106 ++#define WLC_GET_MONITOR 107 ++#define WLC_SET_MONITOR 108 ++#define WLC_GET_GMODE 109 ++#define WLC_SET_GMODE 110 ++#define WLC_GET_LEGACY_ERP 111 ++#define WLC_SET_LEGACY_ERP 112 ++#define WLC_GET_RX_ANT 113 ++#define WLC_GET_CURR_RATESET 114 /* current rateset */ ++#define WLC_GET_SCANSUPPRESS 115 ++#define WLC_SET_SCANSUPPRESS 116 ++#define WLC_GET_AP 117 ++#define WLC_SET_AP 118 ++#define WLC_GET_EAP_RESTRICT 119 ++#define WLC_SET_EAP_RESTRICT 120 ++#define WLC_SCB_AUTHORIZE 121 ++#define WLC_SCB_DEAUTHORIZE 122 ++#define WLC_GET_WDSLIST 123 ++#define WLC_SET_WDSLIST 124 ++#define WLC_GET_ATIM 125 ++#define WLC_SET_ATIM 126 ++#define WLC_GET_RSSI 127 ++#define WLC_GET_PHYANTDIV 128 ++#define WLC_SET_PHYANTDIV 129 ++#define WLC_AP_RX_ONLY 130 ++#define WLC_GET_TX_PATH_PWR 131 ++#define WLC_SET_TX_PATH_PWR 132 ++#define WLC_GET_WSEC 133 ++#define WLC_SET_WSEC 134 ++#define WLC_GET_PHY_NOISE 135 ++#define WLC_GET_BSS_INFO 136 ++#define WLC_GET_PKTCNTS 137 ++#define WLC_GET_LAZYWDS 138 ++#define WLC_SET_LAZYWDS 139 ++#define WLC_GET_BANDLIST 140 ++ ++#define WLC_GET_BAND 141 ++#define WLC_SET_BAND 142 ++#define WLC_SCB_DEAUTHENTICATE 143 ++#define WLC_GET_SHORTSLOT 144 ++#define WLC_GET_SHORTSLOT_OVERRIDE 145 ++#define WLC_SET_SHORTSLOT_OVERRIDE 146 ++#define WLC_GET_SHORTSLOT_RESTRICT 147 ++#define WLC_SET_SHORTSLOT_RESTRICT 148 ++#define WLC_GET_GMODE_PROTECTION 149 ++#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150 ++#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151 ++#define WLC_UPGRADE 152 ++/* #define WLC_GET_MRATE 153 */ /* no longer supported */ ++/* #define WLC_SET_MRATE 154 */ /* no longer supported */ ++#define WLC_GET_IGNORE_BCNS 155 ++#define WLC_SET_IGNORE_BCNS 156 ++#define WLC_GET_SCB_TIMEOUT 157 ++#define WLC_SET_SCB_TIMEOUT 158 ++#define WLC_GET_ASSOCLIST 159 ++#define WLC_GET_CLK 160 ++#define WLC_SET_CLK 161 ++#define WLC_GET_UP 162 ++#define WLC_OUT 163 ++#define WLC_GET_WPA_AUTH 164 ++#define WLC_SET_WPA_AUTH 165 ++#define WLC_GET_UCFLAGS 166 ++#define WLC_SET_UCFLAGS 167 ++#define WLC_GET_PWRIDX 168 ++#define WLC_SET_PWRIDX 169 ++#define WLC_GET_TSSI 170 ++#define WLC_GET_SUP_RATESET_OVERRIDE 171 ++#define WLC_SET_SUP_RATESET_OVERRIDE 172 ++/* #define WLC_SET_FAST_TIMER 173 */ /* no longer supported */ ++/* #define WLC_GET_FAST_TIMER 174 */ /* no longer supported */ ++/* #define WLC_SET_SLOW_TIMER 175 */ /* no longer supported */ ++/* #define WLC_GET_SLOW_TIMER 176 */ /* no longer supported */ ++/* #define WLC_DUMP_PHYREGS 177 */ /* no longer supported */ ++#define WLC_GET_PROTECTION_CONTROL 178 ++#define WLC_SET_PROTECTION_CONTROL 179 ++#define WLC_GET_PHYLIST 180 ++#define WLC_ENCRYPT_STRENGTH 181 /* ndis only */ ++#define WLC_DECRYPT_STATUS 182 /* ndis only */ ++#define WLC_GET_KEY_SEQ 183 ++#define WLC_GET_SCAN_CHANNEL_TIME 184 ++#define WLC_SET_SCAN_CHANNEL_TIME 185 ++#define WLC_GET_SCAN_UNASSOC_TIME 186 ++#define WLC_SET_SCAN_UNASSOC_TIME 187 ++#define WLC_GET_SCAN_HOME_TIME 188 ++#define WLC_SET_SCAN_HOME_TIME 189 ++#define WLC_GET_SCAN_NPROBES 190 ++#define WLC_SET_SCAN_NPROBES 191 ++#define WLC_GET_PRB_RESP_TIMEOUT 192 ++#define WLC_SET_PRB_RESP_TIMEOUT 193 ++#define WLC_GET_ATTEN 194 ++#define WLC_SET_ATTEN 195 ++#define WLC_GET_SHMEM 196 /* diag */ ++#define WLC_SET_SHMEM 197 /* diag */ ++/* #define WLC_GET_GMODE_PROTECTION_CTS 198 */ /* no longer supported */ ++/* #define WLC_SET_GMODE_PROTECTION_CTS 199 */ /* no longer supported */ ++#define WLC_SET_WSEC_TEST 200 ++#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201 ++#define WLC_TKIP_COUNTERMEASURES 202 ++#define WLC_GET_PIOMODE 203 ++#define WLC_SET_PIOMODE 204 ++#define WLC_SET_ASSOC_PREFER 205 ++#define WLC_GET_ASSOC_PREFER 206 ++#define WLC_SET_ROAM_PREFER 207 ++#define WLC_GET_ROAM_PREFER 208 ++#define WLC_SET_LED 209 ++#define WLC_GET_LED 210 ++#define WLC_GET_INTERFERENCE_MODE 211 ++#define WLC_SET_INTERFERENCE_MODE 212 ++#define WLC_GET_CHANNEL_QA 213 ++#define WLC_START_CHANNEL_QA 214 ++#define WLC_GET_CHANNEL_SEL 215 ++#define WLC_START_CHANNEL_SEL 216 ++#define WLC_GET_VALID_CHANNELS 217 ++#define WLC_GET_FAKEFRAG 218 ++#define WLC_SET_FAKEFRAG 219 ++#define WLC_GET_PWROUT_PERCENTAGE 220 ++#define WLC_SET_PWROUT_PERCENTAGE 221 ++#define WLC_SET_BAD_FRAME_PREEMPT 222 ++#define WLC_GET_BAD_FRAME_PREEMPT 223 ++#define WLC_SET_LEAP_LIST 224 ++#define WLC_GET_LEAP_LIST 225 ++#define WLC_GET_CWMIN 226 ++#define WLC_SET_CWMIN 227 ++#define WLC_GET_CWMAX 228 ++#define WLC_SET_CWMAX 229 ++#define WLC_GET_WET 230 ++#define WLC_SET_WET 231 ++#define WLC_GET_PUB 232 ++/* #define WLC_SET_GLACIAL_TIMER 233 */ /* no longer supported */ ++/* #define WLC_GET_GLACIAL_TIMER 234 */ /* no longer supported */ ++#define WLC_GET_KEY_PRIMARY 235 ++#define WLC_SET_KEY_PRIMARY 236 ++ ++ ++/* #define WLC_DUMP_RADIOREGS 237 */ /* no longer supported */ ++#define WLC_GET_ACI_ARGS 238 ++#define WLC_SET_ACI_ARGS 239 ++#define WLC_UNSET_CALLBACK 240 ++#define WLC_SET_CALLBACK 241 ++#define WLC_GET_RADAR 242 ++#define WLC_SET_RADAR 243 ++#define WLC_SET_SPECT_MANAGMENT 244 ++#define WLC_GET_SPECT_MANAGMENT 245 ++#define WLC_WDS_GET_REMOTE_HWADDR 246 /* handled in wl_linux.c/wl_vx.c */ ++#define WLC_WDS_GET_WPA_SUP 247 ++#define WLC_SET_CS_SCAN_TIMER 248 ++#define WLC_GET_CS_SCAN_TIMER 249 ++#define WLC_MEASURE_REQUEST 250 ++#define WLC_INIT 251 ++#define WLC_SEND_QUIET 252 ++#define WLC_KEEPALIVE 253 ++#define WLC_SEND_PWR_CONSTRAINT 254 ++#define WLC_UPGRADE_STATUS 255 ++#define WLC_CURRENT_PWR 256 ++#define WLC_GET_SCAN_PASSIVE_TIME 257 ++#define WLC_SET_SCAN_PASSIVE_TIME 258 ++#define WLC_LEGACY_LINK_BEHAVIOR 259 ++#define WLC_GET_CHANNELS_IN_COUNTRY 260 ++#define WLC_GET_COUNTRY_LIST 261 ++#define WLC_GET_VAR 262 /* get value of named variable */ ++#define WLC_SET_VAR 263 /* set named variable to value */ ++#define WLC_NVRAM_GET 264 /* deprecated */ ++#define WLC_NVRAM_SET 265 ++#define WLC_NVRAM_DUMP 266 ++#define WLC_REBOOT 267 ++#define WLC_SET_WSEC_PMK 268 ++#define WLC_GET_AUTH_MODE 269 ++#define WLC_SET_AUTH_MODE 270 ++#define WLC_GET_WAKEENTRY 271 ++#define WLC_SET_WAKEENTRY 272 ++#define WLC_NDCONFIG_ITEM 273 /* currently handled in wl_oid.c */ ++#define WLC_NVOTPW 274 ++#define WLC_OTPW 275 ++#define WLC_IOV_BLOCK_GET 276 ++#define WLC_IOV_MODULES_GET 277 ++#define WLC_SOFT_RESET 278 ++#define WLC_GET_ALLOW_MODE 279 ++#define WLC_SET_ALLOW_MODE 280 ++#define WLC_GET_DESIRED_BSSID 281 ++#define WLC_SET_DESIRED_BSSID 282 ++#define WLC_DISASSOC_MYAP 283 ++#define WLC_GET_NBANDS 284 /* for Dongle EXT_STA support */ ++#define WLC_GET_BANDSTATES 285 /* for Dongle EXT_STA support */ ++#define WLC_GET_WLC_BSS_INFO 286 /* for Dongle EXT_STA support */ ++#define WLC_GET_ASSOC_INFO 287 /* for Dongle EXT_STA support */ ++#define WLC_GET_OID_PHY 288 /* for Dongle EXT_STA support */ ++#define WLC_SET_OID_PHY 289 /* for Dongle EXT_STA support */ ++#define WLC_SET_ASSOC_TIME 290 /* for Dongle EXT_STA support */ ++#define WLC_GET_DESIRED_SSID 291 /* for Dongle EXT_STA support */ ++#define WLC_GET_CHANSPEC 292 /* for Dongle EXT_STA support */ ++#define WLC_GET_ASSOC_STATE 293 /* for Dongle EXT_STA support */ ++#define WLC_SET_PHY_STATE 294 /* for Dongle EXT_STA support */ ++#define WLC_GET_SCAN_PENDING 295 /* for Dongle EXT_STA support */ ++#define WLC_GET_SCANREQ_PENDING 296 /* for Dongle EXT_STA support */ ++#define WLC_GET_PREV_ROAM_REASON 297 /* for Dongle EXT_STA support */ ++#define WLC_SET_PREV_ROAM_REASON 298 /* for Dongle EXT_STA support */ ++#define WLC_GET_BANDSTATES_PI 299 /* for Dongle EXT_STA support */ ++#define WLC_GET_PHY_STATE 300 /* for Dongle EXT_STA support */ ++#define WLC_GET_BSS_WPA_RSN 301 /* for Dongle EXT_STA support */ ++#define WLC_GET_BSS_WPA2_RSN 302 /* for Dongle EXT_STA support */ ++#define WLC_GET_BSS_BCN_TS 303 /* for Dongle EXT_STA support */ ++#define WLC_GET_INT_DISASSOC 304 /* for Dongle EXT_STA support */ ++#define WLC_SET_NUM_PEERS 305 /* for Dongle EXT_STA support */ ++#define WLC_GET_NUM_BSS 306 /* for Dongle EXT_STA support */ ++#define WLC_PHY_SAMPLE_COLLECT 307 /* phy sample collect mode */ ++/* #define WLC_UM_PRIV 308 */ /* Deprecated: usermode driver */ ++#define WLC_GET_CMD 309 ++/* #define WLC_LAST 310 */ /* Never used - can be reused */ ++#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311 /* set inter mode override */ ++#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312 /* get inter mode override */ ++/* #define WLC_GET_WAI_RESTRICT 313 */ ++/* #define WLC_SET_WAI_RESTRICT 314 */ ++/* #define WLC_SET_WAI_REKEY 315 */ ++#define WLC_SET_NAT_CONFIG 316 /* for configuring NAT filter driver */ ++#define WLC_GET_NAT_STATE 317 ++#define WLC_GET_TXBF_RATESET 318 ++#define WLC_SET_TXBF_RATESET 319 ++#define WLC_SCAN_CQ 320 ++#define WLC_GET_RSSI_QDB 321 /* qdB portion of the RSSI */ ++#define WLC_DUMP_RATESET 322 ++#define WLC_ECHO 323 ++#define WLC_LAST 324 ++#define WLC_SPEC_FLAG 0x80000000 /* For some special IOCTL */ ++#ifndef EPICTRL_COOKIE ++#define EPICTRL_COOKIE 0xABADCEDE ++#endif ++ ++/* vx wlc ioctl's offset */ ++#define CMN_IOCTL_OFF 0x180 ++ ++/* ++ * custom OID support ++ * ++ * 0xFF - implementation specific OID ++ * 0xE4 - first byte of Broadcom PCI vendor ID ++ * 0x14 - second byte of Broadcom PCI vendor ID ++ * 0xXX - the custom OID number ++ */ ++ ++/* begin 0x1f values beyond the start of the ET driver range. */ ++#define WL_OID_BASE 0xFFE41420 ++ ++/* NDIS overrides */ ++#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE) ++#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK) ++#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK) ++#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH) ++#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS) ++#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR) ++#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM) ++ ++/* EXT_STA Dongle suuport */ ++#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC) ++#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS) ++#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY) ++#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY) ++#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME) ++#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID) ++#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE) ++#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING) ++#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING) ++#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON) ++#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON) ++#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE) ++#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC) ++#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS) ++#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS) ++ ++/* NAT filter driver support */ ++#define OID_NAT_SET_CONFIG (WL_OID_BASE + WLC_SET_NAT_CONFIG) ++#define OID_NAT_GET_STATE (WL_OID_BASE + WLC_GET_NAT_STATE) ++ ++#define WL_DECRYPT_STATUS_SUCCESS 1 ++#define WL_DECRYPT_STATUS_FAILURE 2 ++#define WL_DECRYPT_STATUS_UNKNOWN 3 ++ ++/* allows user-mode app to poll the status of USB image upgrade */ ++#define WLC_UPGRADE_SUCCESS 0 ++#define WLC_UPGRADE_PENDING 1 ++ ++/* WLC_GET_AUTH, WLC_SET_AUTH values */ ++#define WL_AUTH_OPEN_SYSTEM 0 /* d11 open authentication */ ++#define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ ++#define WL_AUTH_OPEN_SHARED 2 /* try open, then shared if open failed w/rc 13 */ ++ ++/* a large TX Power as an init value to factor out of MIN() calculations, ++ * keep low enough to fit in an int8, units are .25 dBm ++ */ ++#define WLC_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ ++ ++/* "diag" iovar argument and error code */ ++#define WL_DIAG_INTERRUPT 1 /* d11 loopback interrupt test */ ++#define WL_DIAG_LOOPBACK 2 /* d11 loopback data test */ ++#define WL_DIAG_MEMORY 3 /* d11 memory test */ ++#define WL_DIAG_LED 4 /* LED test */ ++#define WL_DIAG_REG 5 /* d11/phy register test */ ++#define WL_DIAG_SROM 6 /* srom read/crc test */ ++#define WL_DIAG_DMA 7 /* DMA test */ ++#define WL_DIAG_LOOPBACK_EXT 8 /* enhenced d11 loopback data test */ ++ ++#define WL_DIAGERR_SUCCESS 0 ++#define WL_DIAGERR_FAIL_TO_RUN 1 /* unable to run requested diag */ ++#define WL_DIAGERR_NOT_SUPPORTED 2 /* diag requested is not supported */ ++#define WL_DIAGERR_INTERRUPT_FAIL 3 /* loopback interrupt test failed */ ++#define WL_DIAGERR_LOOPBACK_FAIL 4 /* loopback data test failed */ ++#define WL_DIAGERR_SROM_FAIL 5 /* srom read failed */ ++#define WL_DIAGERR_SROM_BADCRC 6 /* srom crc failed */ ++#define WL_DIAGERR_REG_FAIL 7 /* d11/phy register test failed */ ++#define WL_DIAGERR_MEMORY_FAIL 8 /* d11 memory test failed */ ++#define WL_DIAGERR_NOMEM 9 /* diag test failed due to no memory */ ++#define WL_DIAGERR_DMA_FAIL 10 /* DMA test failed */ ++ ++#define WL_DIAGERR_MEMORY_TIMEOUT 11 /* d11 memory test didn't finish in time */ ++#define WL_DIAGERR_MEMORY_BADPATTERN 12 /* d11 memory test result in bad pattern */ ++ ++/* band types */ ++#define WLC_BAND_AUTO 0 /* auto-select */ ++#define WLC_BAND_5G 1 /* 5 Ghz */ ++#define WLC_BAND_2G 2 /* 2.4 Ghz */ ++#define WLC_BAND_ALL 3 /* all bands */ ++#define WLC_BAND_INVALID -1 /* Invalid band */ ++ ++/* band range returned by band_range iovar */ ++#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 WL_CHAN_FREQ_RANGE_5GLL_5BAND 4 ++#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5 ++#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6 ++#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7 ++#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8 ++ ++#define WL_CHAN_FREQ_RANGE_5G_BAND0 1 ++#define WL_CHAN_FREQ_RANGE_5G_BAND1 2 ++#define WL_CHAN_FREQ_RANGE_5G_BAND2 3 ++#define WL_CHAN_FREQ_RANGE_5G_BAND3 4 ++#define WL_CHAN_FREQ_RANGE_5G_4BAND 5 ++ ++/* SROM12 */ ++#define WL_CHAN_FREQ_RANGE_5G_BAND4 5 ++#define WL_CHAN_FREQ_RANGE_2G_40 6 ++#define WL_CHAN_FREQ_RANGE_5G_BAND0_40 7 ++#define WL_CHAN_FREQ_RANGE_5G_BAND1_40 8 ++#define WL_CHAN_FREQ_RANGE_5G_BAND2_40 9 ++#define WL_CHAN_FREQ_RANGE_5G_BAND3_40 10 ++#define WL_CHAN_FREQ_RANGE_5G_BAND4_40 11 ++#define WL_CHAN_FREQ_RANGE_5G_BAND0_80 12 ++#define WL_CHAN_FREQ_RANGE_5G_BAND1_80 13 ++#define WL_CHAN_FREQ_RANGE_5G_BAND2_80 14 ++#define WL_CHAN_FREQ_RANGE_5G_BAND3_80 15 ++#define WL_CHAN_FREQ_RANGE_5G_BAND4_80 16 ++ ++#define WL_CHAN_FREQ_RANGE_5G_5BAND 18 ++#define WL_CHAN_FREQ_RANGE_5G_5BAND_40 19 ++#define WL_CHAN_FREQ_RANGE_5G_5BAND_80 20 ++ ++#define WLC_MACMODE_DISABLED 0 /* MAC list disabled */ ++#define WLC_MACMODE_DENY 1 /* Deny specified (i.e. allow unspecified) */ ++#define WLC_MACMODE_ALLOW 2 /* Allow specified (i.e. deny unspecified) */ ++ ++/* ++ * 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 ++ */ ++#define GMODE_LEGACY_B 0 ++#define GMODE_AUTO 1 ++#define GMODE_ONLY 2 ++#define GMODE_B_DEFERRED 3 ++#define GMODE_PERFORMANCE 4 ++#define GMODE_LRS 5 ++#define GMODE_MAX 6 ++ ++/* values for PLCPHdr_override */ ++#define WLC_PLCP_AUTO -1 ++#define WLC_PLCP_SHORT 0 ++#define WLC_PLCP_LONG 1 ++ ++/* values for g_protection_override and n_protection_override */ ++#define WLC_PROTECTION_AUTO -1 ++#define WLC_PROTECTION_OFF 0 ++#define WLC_PROTECTION_ON 1 ++#define WLC_PROTECTION_MMHDR_ONLY 2 ++#define WLC_PROTECTION_CTS_ONLY 3 ++ ++/* values for g_protection_control and n_protection_control */ ++#define WLC_PROTECTION_CTL_OFF 0 ++#define WLC_PROTECTION_CTL_LOCAL 1 ++#define WLC_PROTECTION_CTL_OVERLAP 2 ++ ++/* values for n_protection */ ++#define WLC_N_PROTECTION_OFF 0 ++#define WLC_N_PROTECTION_OPTIONAL 1 ++#define WLC_N_PROTECTION_20IN40 2 ++#define WLC_N_PROTECTION_MIXEDMODE 3 ++ ++/* values for n_preamble_type */ ++#define WLC_N_PREAMBLE_MIXEDMODE 0 ++#define WLC_N_PREAMBLE_GF 1 ++#define WLC_N_PREAMBLE_GF_BRCM 2 ++ ++/* values for band specific 40MHz capabilities (deprecated) */ ++#define WLC_N_BW_20ALL 0 ++#define WLC_N_BW_40ALL 1 ++#define WLC_N_BW_20IN2G_40IN5G 2 ++ ++#define WLC_BW_20MHZ_BIT (1<<0) ++#define WLC_BW_40MHZ_BIT (1<<1) ++#define WLC_BW_80MHZ_BIT (1<<2) ++#define WLC_BW_160MHZ_BIT (1<<3) ++#define WLC_BW_10MHZ_BIT (1<<4) ++#define WLC_BW_5MHZ_BIT (1<<5) ++#define WLC_BW_2P5MHZ_BIT (1<<6) ++/* Bandwidth capabilities */ ++#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) ++#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) ++#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) ++#define WLC_BW_CAP_160MHZ (WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \ ++ WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) ++#define WLC_BW_CAP_2P5MHZ (WLC_BW_2P5MHZ_BIT) ++#define WLC_BW_CAP_5MHZ (WLC_BW_5MHZ_BIT) ++#define WLC_BW_CAP_10MHZ (WLC_BW_10MHZ_BIT) ++#define WLC_BW_CAP_UNRESTRICTED 0xFF ++ ++#define WL_BW_CAP_20MHZ(bw_cap) (((bw_cap) & WLC_BW_20MHZ_BIT) ? TRUE : FALSE) ++#define WL_BW_CAP_40MHZ(bw_cap) (((bw_cap) & WLC_BW_40MHZ_BIT) ? TRUE : FALSE) ++#define WL_BW_CAP_80MHZ(bw_cap) (((bw_cap) & WLC_BW_80MHZ_BIT) ? TRUE : FALSE) ++#define WL_BW_CAP_160MHZ(bw_cap)(((bw_cap) & WLC_BW_160MHZ_BIT) ? TRUE : FALSE) ++#define WL_BW_CAP_2P5MHZ(bw_cap)(((bw_cap) & WLC_BW_2P5MHZ_BIT) ? TRUE : FALSE) ++#define WL_BW_CAP_5MHZ(bw_cap) (((bw_cap) & WLC_BW_5MHZ_BIT) ? TRUE : FALSE) ++#define WL_BW_CAP_10MHZ(bw_cap) (((bw_cap) & WLC_BW_10MHZ_BIT) ? TRUE : FALSE) ++/* values to force tx/rx chain */ ++#define WLC_N_TXRX_CHAIN0 0 ++#define WLC_N_TXRX_CHAIN1 1 ++ ++/* bitflags for SGI support (sgi_rx iovar) */ ++#define WLC_N_SGI_20 0x01 ++#define WLC_N_SGI_40 0x02 ++#define WLC_VHT_SGI_80 0x04 ++#define WLC_VHT_SGI_160 0x08 ++ ++/* when sgi_tx==WLC_SGI_ALL, bypass rate selection, enable sgi for all mcs */ ++#define WLC_SGI_ALL 0x02 ++ ++#define LISTEN_INTERVAL 10 ++/* interference mitigation options */ ++#define INTERFERE_OVRRIDE_OFF -1 /* interference override off */ ++#define INTERFERE_NONE 0 /* off */ ++#define NON_WLAN 1 /* foreign/non 802.11 interference, no auto detect */ ++#define WLAN_MANUAL 2 /* ACI: no auto detection */ ++#define WLAN_AUTO 3 /* ACI: auto detect */ ++#define WLAN_AUTO_W_NOISE 4 /* ACI: auto - detect and non 802.11 interference */ ++#define AUTO_ACTIVE (1 << 7) /* Auto is currently active */ ++ ++/* interfernece mode bit-masks (ACPHY) */ ++#define ACPHY_ACI_GLITCHBASED_DESENSE 1 /* bit 0 */ ++#define ACPHY_ACI_HWACI_PKTGAINLMT 2 /* bit 1 */ ++#define ACPHY_ACI_W2NB_PKTGAINLMT 4 /* bit 2 */ ++#define ACPHY_ACI_PREEMPTION 8 /* bit 3 */ ++#define ACPHY_HWACI_MITIGATION 16 /* bit 4 */ ++#define ACPHY_LPD_PREEMPTION 32 /* bit 5 */ ++#define ACPHY_HWOBSS_MITIGATION 64 /* bit 6 */ ++#define ACPHY_ACI_MAX_MODE 127 ++ ++/* AP environment */ ++#define AP_ENV_DETECT_NOT_USED 0 /* We aren't using AP environment detection */ ++#define AP_ENV_DENSE 1 /* "Corporate" or other AP dense environment */ ++#define AP_ENV_SPARSE 2 /* "Home" or other sparse environment */ ++#define AP_ENV_INDETERMINATE 3 /* AP environment hasn't been identified */ ++ ++#define TRIGGER_NOW 0 ++#define TRIGGER_CRS 0x01 ++#define TRIGGER_CRSDEASSERT 0x02 ++#define TRIGGER_GOODFCS 0x04 ++#define TRIGGER_BADFCS 0x08 ++#define TRIGGER_BADPLCP 0x10 ++#define TRIGGER_CRSGLITCH 0x20 ++ ++#define WL_SAMPLEDATA_HEADER_TYPE 1 ++#define WL_SAMPLEDATA_HEADER_SIZE 80 /* sample collect header size (bytes) */ ++#define WL_SAMPLEDATA_TYPE 2 ++#define WL_SAMPLEDATA_SEQ 0xff /* sequence # */ ++#define WL_SAMPLEDATA_MORE_DATA 0x100 /* more data mask */ ++ ++/* WL_OTA START */ ++#define WL_OTA_ARG_PARSE_BLK_SIZE 1200 ++#define WL_OTA_TEST_MAX_NUM_RATE 30 ++#define WL_OTA_TEST_MAX_NUM_SEQ 100 ++#define WL_OTA_TEST_MAX_NUM_RSSI 85 ++#define WL_THRESHOLD_LO_BAND 70 /* range from 5250MHz - 5350MHz */ ++ ++/* radar iovar SET defines */ ++#define WL_RADAR_DETECTOR_OFF 0 /* radar detector off */ ++#define WL_RADAR_DETECTOR_ON 1 /* radar detector on */ ++#define WL_RADAR_SIMULATED 2 /* force radar detector to declare ++ * detection once ++ */ ++#define WL_RADAR_SIMULATED_SC 3 /* force radar detector to declare ++ * detection once on scan core ++ * if available and active ++ */ ++#define WL_RSSI_ANT_VERSION 1 /* current version of wl_rssi_ant_t */ ++#define WL_ANT_RX_MAX 2 /* max 2 receive antennas */ ++#define WL_ANT_HT_RX_MAX 4 /* max 4 receive antennas/cores */ ++#define WL_ANT_IDX_1 0 /* antenna index 1 */ ++#define WL_ANT_IDX_2 1 /* antenna index 2 */ ++ ++#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 ++ ++/* dfs_status iovar-related defines */ ++ ++/* cac - channel availability check, ++ * ism - in-service monitoring ++ * csa - channel switching announcement ++ */ ++ ++/* cac state values */ ++#define WL_DFS_CACSTATE_IDLE 0 /* state for operating in non-radar channel */ ++#define WL_DFS_CACSTATE_PREISM_CAC 1 /* CAC in progress */ ++#define WL_DFS_CACSTATE_ISM 2 /* ISM in progress */ ++#define WL_DFS_CACSTATE_CSA 3 /* csa */ ++#define WL_DFS_CACSTATE_POSTISM_CAC 4 /* ISM CAC */ ++#define WL_DFS_CACSTATE_PREISM_OOC 5 /* PREISM OOC */ ++#define WL_DFS_CACSTATE_POSTISM_OOC 6 /* POSTISM OOC */ ++#define WL_DFS_CACSTATES 7 /* this many states exist */ ++ ++/* Defines used with channel_bandwidth for curpower */ ++#define WL_BW_20MHZ 0 ++#define WL_BW_40MHZ 1 ++#define WL_BW_80MHZ 2 ++#define WL_BW_160MHZ 3 ++#define WL_BW_8080MHZ 4 ++#define WL_BW_2P5MHZ 5 ++#define WL_BW_5MHZ 6 ++#define WL_BW_10MHZ 7 ++ ++/* tx_power_t.flags bits */ ++#define WL_TX_POWER_F_ENABLED 1 ++#define WL_TX_POWER_F_HW 2 ++#define WL_TX_POWER_F_MIMO 4 ++#define WL_TX_POWER_F_SISO 8 ++#define WL_TX_POWER_F_HT 0x10 ++#define WL_TX_POWER_F_VHT 0x20 ++#define WL_TX_POWER_F_OPENLOOP 0x40 ++#define WL_TX_POWER_F_PROP11NRATES 0x80 ++#define WL_TX_POWER_F_UNIT_QDBM 0x100 ++/* Message levels */ ++#define WL_ERROR_VAL 0x00000001 ++#define WL_TRACE_VAL 0x00000002 ++#define WL_PRHDRS_VAL 0x00000004 ++#define WL_PRPKT_VAL 0x00000008 ++#define WL_INFORM_VAL 0x00000010 ++#define WL_TMP_VAL 0x00000020 ++#define WL_OID_VAL 0x00000040 ++#define WL_RATE_VAL 0x00000080 ++#define WL_ASSOC_VAL 0x00000100 ++#define WL_PRUSR_VAL 0x00000200 ++#define WL_PS_VAL 0x00000400 ++#define WL_TXPWR_VAL 0x00000000 /* retired in TOT on 6/10/2009 */ ++#define WL_MODE_SWITCH_VAL 0x00000800 /* Using retired TXPWR val */ ++#define WL_PORT_VAL 0x00001000 ++#define WL_DUAL_VAL 0x00002000 ++#define WL_WSEC_VAL 0x00004000 ++#define WL_WSEC_DUMP_VAL 0x00008000 ++#define WL_LOG_VAL 0x00010000 ++#define WL_NRSSI_VAL 0x00000000 /* retired in TOT on 6/10/2009 */ ++#define WL_BCNTRIM_VAL 0x00020000 /* Using retired NRSSI VAL */ ++#define WL_LOFT_VAL 0x00000000 /* retired in TOT on 6/10/2009 */ ++#define WL_PFN_VAL 0x00040000 /* Using retired LOFT_VAL */ ++#define WL_REGULATORY_VAL 0x00080000 ++#define WL_CSA_VAL 0x00080000 /* Reusing REGULATORY_VAL due to lackof bits */ ++#define WL_TAF_VAL 0x00100000 ++#define WL_RADAR_VAL 0x00000000 /* retired in TOT on 6/10/2009 */ ++#define WL_WDI_VAL 0x00200000 /* Using retired WL_RADAR_VAL VAL */ ++#define WL_MPC_VAL 0x00400000 ++#define WL_APSTA_VAL 0x00800000 ++#define WL_DFS_VAL 0x01000000 ++#define WL_BA_VAL 0x00000000 /* retired in TOT on 6/14/2010 */ ++#define WL_MUMIMO_VAL 0x02000000 /* Using retired WL_BA_VAL */ ++#define WL_ACI_VAL 0x04000000 ++#define WL_PRMAC_VAL 0x04000000 ++#define WL_MBSS_VAL 0x04000000 ++#define WL_CAC_VAL 0x08000000 ++#define WL_AMSDU_VAL 0x10000000 ++#define WL_AMPDU_VAL 0x20000000 ++#define WL_FFPLD_VAL 0x40000000 ++#define WL_ROAM_EXP_VAL 0x80000000 ++ ++/* wl_msg_level is full. For new bits take the next one and AND with ++ * wl_msg_level2 in wl_dbg.h ++ */ ++#define WL_DPT_VAL 0x00000001 ++/* re-using WL_DPT_VAL */ ++/* re-using WL_MESH_VAL */ ++#define WL_NATOE_VAL 0x00000001 ++#define WL_MESH_VAL 0x00000001 ++#define WL_SCAN_VAL 0x00000002 ++#define WL_WOWL_VAL 0x00000004 ++#define WL_COEX_VAL 0x00000008 ++#define WL_RTDC_VAL 0x00000010 ++#define WL_PROTO_VAL 0x00000020 ++#define WL_SWDIV_VAL 0x00000040 ++#define WL_CHANINT_VAL 0x00000080 ++#define WL_WMF_VAL 0x00000100 ++#define WL_P2P_VAL 0x00000200 ++#define WL_ITFR_VAL 0x00000400 ++#define WL_MCHAN_VAL 0x00000800 ++#define WL_TDLS_VAL 0x00001000 ++#define WL_MCNX_VAL 0x00002000 ++#define WL_PROT_VAL 0x00004000 ++#define WL_PSTA_VAL 0x00008000 ++#define WL_TSO_VAL 0x00010000 ++#define WL_TRF_MGMT_VAL 0x00020000 ++#define WL_LPC_VAL 0x00040000 ++#define WL_L2FILTER_VAL 0x00080000 ++#define WL_TXBF_VAL 0x00100000 ++#define WL_P2PO_VAL 0x00200000 ++#define WL_TBTT_VAL 0x00400000 ++#define WL_FBT_VAL 0x00800000 ++#define WL_RRM_VAL 0x00800000 /* reuse */ ++#define WL_MQ_VAL 0x01000000 ++ ++/* This level is currently used in Phoenix2 only */ ++#define WL_SRSCAN_VAL 0x02000000 ++ ++#define WL_WNM_VAL 0x04000000 ++/* re-using WL_WNM_VAL for MBO */ ++#define WL_MBO_VAL 0x04000000 ++#define WL_PWRSEL_VAL 0x10000000 ++#define WL_NET_DETECT_VAL 0x20000000 ++#define WL_OCE_VAL 0x20000000 /* reuse */ ++#define WL_PCIE_VAL 0x40000000 ++#define WL_PMDUR_VAL 0x80000000 ++ ++ ++/* use top-bit for WL_TIME_STAMP_VAL because this is a modifier ++ * rather than a message-type of its own ++ */ ++#define WL_TIMESTAMP_VAL 0x80000000 ++ ++/* max # of leds supported by GPIO (gpio pin# == led index#) */ ++#define WL_LED_NUMGPIO 32 /* gpio 0-31 */ ++ ++/* led per-pin behaviors */ ++#define WL_LED_OFF 0 /* always off */ ++#define WL_LED_ON 1 /* always on */ ++#define WL_LED_ACTIVITY 2 /* activity */ ++#define WL_LED_RADIO 3 /* radio enabled */ ++#define WL_LED_ARADIO 4 /* 5 Ghz radio enabled */ ++#define WL_LED_BRADIO 5 /* 2.4Ghz radio enabled */ ++#define WL_LED_BGMODE 6 /* on if gmode, off if bmode */ ++#define WL_LED_WI1 7 ++#define WL_LED_WI2 8 ++#define WL_LED_WI3 9 ++#define WL_LED_ASSOC 10 /* associated state indicator */ ++#define WL_LED_INACTIVE 11 /* null behavior (clears default behavior) */ ++#define WL_LED_ASSOCACT 12 /* on when associated; blink fast for activity */ ++#define WL_LED_WI4 13 ++#define WL_LED_WI5 14 ++#define WL_LED_BLINKSLOW 15 /* blink slow */ ++#define WL_LED_BLINKMED 16 /* blink med */ ++#define WL_LED_BLINKFAST 17 /* blink fast */ ++#define WL_LED_BLINKCUSTOM 18 /* blink custom */ ++#define WL_LED_BLINKPERIODIC 19 /* blink periodic (custom 1000ms / off 400ms) */ ++#define WL_LED_ASSOC_WITH_SEC 20 /* when connected with security */ ++ /* keep on for 300 sec */ ++#define WL_LED_START_OFF 21 /* off upon boot, could be turned on later */ ++#define WL_LED_WI6 22 ++#define WL_LED_WI7 23 ++#define WL_LED_WI8 24 ++#define WL_LED_NUMBEHAVIOR 25 ++ ++/* led behavior numeric value format */ ++#define WL_LED_BEH_MASK 0x3f /* behavior mask */ ++#define WL_LED_PMU_OVERRIDE 0x40 /* need to set PMU Override bit for the GPIO */ ++#define WL_LED_AL_MASK 0x80 /* activelow (polarity) bit */ ++ ++/* number of bytes needed to define a proper bit mask for MAC event reporting */ ++#define BCMIO_ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) ++#define BCMIO_NBBY 8 ++#define WL_EVENTING_MASK_LEN (16+4) ++ ++#define WL_EVENTING_MASK_EXT_LEN \ ++ MAX(WL_EVENTING_MASK_LEN, (ROUNDUP(WLC_E_LAST, NBBY)/NBBY)) ++ ++/* join preference types */ ++#define WL_JOIN_PREF_RSSI 1 /* by RSSI */ ++#define WL_JOIN_PREF_WPA 2 /* by akm and ciphers */ ++#define WL_JOIN_PREF_BAND 3 /* by 802.11 band */ ++#define WL_JOIN_PREF_RSSI_DELTA 4 /* by 802.11 band only if RSSI delta condition matches */ ++#define WL_JOIN_PREF_TRANS_PREF 5 /* defined by requesting AP */ ++ ++/* band preference */ ++#define WLJP_BAND_ASSOC_PREF 255 /* use what WLC_SET_ASSOC_PREFER ioctl specifies */ ++ ++/* any multicast cipher suite */ ++#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00" ++ ++/* 802.11h measurement types */ ++#define WLC_MEASURE_TPC 1 ++#define WLC_MEASURE_CHANNEL_BASIC 2 ++#define WLC_MEASURE_CHANNEL_CCA 3 ++#define WLC_MEASURE_CHANNEL_RPI 4 ++ ++/* regulatory enforcement levels */ ++#define SPECT_MNGMT_OFF 0 /* both 11h and 11d disabled */ ++#define SPECT_MNGMT_LOOSE_11H 1 /* allow non-11h APs in scan lists */ ++#define SPECT_MNGMT_STRICT_11H 2 /* prune out non-11h APs from scan list */ ++#define SPECT_MNGMT_STRICT_11D 3 /* switch to 802.11D mode */ ++/* SPECT_MNGMT_LOOSE_11H_D - same as SPECT_MNGMT_LOOSE with the exception that Country IE ++ * adoption is done regardless of capability spectrum_management ++ */ ++#define SPECT_MNGMT_LOOSE_11H_D 4 /* operation defined above */ ++ ++/* bit position in per_chan_info; these depend on current country/regulatory domain */ ++#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */ ++#define WL_CHAN_VALID_SW (1 << 1) /* valid with current country setting */ ++#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */ ++#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */ ++#define WL_CHAN_INACTIVE (1 << 4) /* temporarily inactive due to radar */ ++#define WL_CHAN_PASSIVE (1 << 5) /* channel is in passive mode */ ++#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */ ++#define WL_CHAN_RADAR_EU_WEATHER (1 << 7) /* EU Radar weather channel. Implies an ++ * EU Radar channel. ++ */ ++#define WL_CHAN_CLM_RESTRICTED (1 << 8) /* channel restricted in CLM ++ * (i.e. by default) ++ */ ++ ++/* following definition is for precommit; will be removed once wl, acsd switch to the new def */ ++#define WL_CHAN_WEATHER_RADAR WL_CHAN_RADAR_EU_WEATHER ++ ++/* BTC mode used by "btc_mode" iovar */ ++#define WL_BTC_DISABLE 0 /* disable BT coexistence */ ++#define WL_BTC_FULLTDM 1 /* full TDM COEX */ ++#define WL_BTC_ENABLE 1 /* full TDM COEX to maintain backward compatiblity */ ++#define WL_BTC_PREMPT 2 /* full TDM COEX with preemption */ ++#define WL_BTC_LITE 3 /* light weight coex for large isolation platform */ ++#define WL_BTC_PARALLEL 4 /* BT and WLAN run in parallel with separate antenna */ ++#define WL_BTC_HYBRID 5 /* hybrid coex, only ack is allowed to transmit in BT slot */ ++#define WL_BTC_DEFAULT 8 /* set the default mode for the device */ ++#define WL_INF_BTC_DISABLE 0 ++#define WL_INF_BTC_ENABLE 1 ++#define WL_INF_BTC_AUTO 3 ++ ++/* BTC wire used by "btc_wire" iovar */ ++#define WL_BTC_DEFWIRE 0 /* use default wire setting */ ++#define WL_BTC_2WIRE 2 /* use 2-wire BTC */ ++#define WL_BTC_3WIRE 3 /* use 3-wire BTC */ ++#define WL_BTC_4WIRE 4 /* use 4-wire BTC */ ++ ++/* BTC flags: BTC configuration that can be set by host */ ++#define WL_BTC_FLAG_PREMPT (1 << 0) ++#define WL_BTC_FLAG_BT_DEF (1 << 1) ++#define WL_BTC_FLAG_ACTIVE_PROT (1 << 2) ++#define WL_BTC_FLAG_SIM_RSP (1 << 3) ++#define WL_BTC_FLAG_PS_PROTECT (1 << 4) ++#define WL_BTC_FLAG_SIM_TX_LP (1 << 5) ++#define WL_BTC_FLAG_ECI (1 << 6) ++#define WL_BTC_FLAG_LIGHT (1 << 7) ++#define WL_BTC_FLAG_PARALLEL (1 << 8) ++ ++/* maximum channels returned by the get valid channels iovar */ ++#define WL_NUMCHANNELS 64 ++ ++/* max number of chanspecs (used by the iovar to calc. buf space) */ ++#ifdef WL11AC_80P80 ++#define WL_NUMCHANSPECS 206 ++#else ++#define WL_NUMCHANSPECS 110 ++#endif ++ ++/* WDS link local endpoint WPA role */ ++#define WL_WDS_WPA_ROLE_AUTH 0 /* authenticator */ ++#define WL_WDS_WPA_ROLE_SUP 1 /* supplicant */ ++#define WL_WDS_WPA_ROLE_AUTO 255 /* auto, based on mac addr value */ ++ ++/* Base offset values */ ++#define WL_PKT_FILTER_BASE_PKT 0 ++#define WL_PKT_FILTER_BASE_END 1 ++#define WL_PKT_FILTER_BASE_D11_H 2 /* May be removed */ ++#define WL_PKT_FILTER_BASE_D11_D 3 /* May be removed */ ++#define WL_PKT_FILTER_BASE_ETH_H 4 ++#define WL_PKT_FILTER_BASE_ETH_D 5 ++#define WL_PKT_FILTER_BASE_ARP_H 6 ++#define WL_PKT_FILTER_BASE_ARP_D 7 /* May be removed */ ++#define WL_PKT_FILTER_BASE_IP4_H 8 ++#define WL_PKT_FILTER_BASE_IP4_D 9 ++#define WL_PKT_FILTER_BASE_IP6_H 10 ++#define WL_PKT_FILTER_BASE_IP6_D 11 ++#define WL_PKT_FILTER_BASE_TCP_H 12 ++#define WL_PKT_FILTER_BASE_TCP_D 13 /* May be removed */ ++#define WL_PKT_FILTER_BASE_UDP_H 14 ++#define WL_PKT_FILTER_BASE_UDP_D 15 ++#define WL_PKT_FILTER_BASE_IP6_P 16 ++#define WL_PKT_FILTER_BASE_COUNT 17 /* May be removed */ ++ ++/* String mapping for bases that may be used by applications or debug */ ++#define WL_PKT_FILTER_BASE_NAMES \ ++ { "START", WL_PKT_FILTER_BASE_PKT }, \ ++ { "END", WL_PKT_FILTER_BASE_END }, \ ++ { "ETH_H", WL_PKT_FILTER_BASE_ETH_H }, \ ++ { "ETH_D", WL_PKT_FILTER_BASE_ETH_D }, \ ++ { "D11_H", WL_PKT_FILTER_BASE_D11_H }, \ ++ { "D11_D", WL_PKT_FILTER_BASE_D11_D }, \ ++ { "ARP_H", WL_PKT_FILTER_BASE_ARP_H }, \ ++ { "IP4_H", WL_PKT_FILTER_BASE_IP4_H }, \ ++ { "IP4_D", WL_PKT_FILTER_BASE_IP4_D }, \ ++ { "IP6_H", WL_PKT_FILTER_BASE_IP6_H }, \ ++ { "IP6_D", WL_PKT_FILTER_BASE_IP6_D }, \ ++ { "IP6_P", WL_PKT_FILTER_BASE_IP6_P }, \ ++ { "TCP_H", WL_PKT_FILTER_BASE_TCP_H }, \ ++ { "TCP_D", WL_PKT_FILTER_BASE_TCP_D }, \ ++ { "UDP_H", WL_PKT_FILTER_BASE_UDP_H }, \ ++ { "UDP_D", WL_PKT_FILTER_BASE_UDP_D } ++ ++/* Flags for a pattern list element */ ++#define WL_PKT_FILTER_MFLAG_NEG 0x0001 ++ ++/* ++ * Packet engine interface ++ */ ++ ++#define WL_PKTENG_PER_TX_START 0x01 ++#define WL_PKTENG_PER_TX_STOP 0x02 ++#define WL_PKTENG_PER_RX_START 0x04 ++#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05 ++#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06 ++#define WL_PKTENG_PER_RX_STOP 0x08 ++#define WL_PKTENG_PER_RU_TX_START 0x09 ++#define WL_PKTENG_PER_MASK 0xff ++ ++#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */ ++#define WL_PKTENG_SYNCHRONOUS_UNBLK 0x200 /* synchronous unblock flag */ ++#ifdef PKTENG_LONGPKTSZ ++/* max pktsz limit for pkteng */ ++#define WL_PKTENG_MAXPKTSZ PKTENG_LONGPKTSZ ++#else ++#define WL_PKTENG_MAXPKTSZ 16384 ++#endif ++ ++#define NUM_80211b_RATES 4 ++#define NUM_80211ag_RATES 8 ++#define NUM_80211n_RATES 32 ++#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES) ++ ++/* ++ * WOWL capability/override settings ++ */ ++#define WL_WOWL_MAGIC (1 << 0) /* Wakeup on Magic packet */ ++#define WL_WOWL_NET (1 << 1) /* Wakeup on Netpattern */ ++#define WL_WOWL_DIS (1 << 2) /* Wakeup on loss-of-link due to Disassoc/Deauth */ ++#define WL_WOWL_RETR (1 << 3) /* Wakeup on retrograde TSF */ ++#define WL_WOWL_BCN (1 << 4) /* Wakeup on loss of beacon */ ++#define WL_WOWL_TST (1 << 5) /* Wakeup after test */ ++#define WL_WOWL_M1 (1 << 6) /* Wakeup after PTK refresh */ ++#define WL_WOWL_EAPID (1 << 7) /* Wakeup after receipt of EAP-Identity Req */ ++#define WL_WOWL_PME_GPIO (1 << 8) /* Wakeind via PME(0) or GPIO(1) */ ++#define WL_WOWL_ULP_BAILOUT (1 << 8) /* wakeind via unknown pkt by basic ULP-offloads - ++ * WL_WOWL_ULP_BAILOUT - same as WL_WOWL_PME_GPIO used only for DONGLE BUILDS ++ */ ++#define WL_WOWL_NEEDTKIP1 (1 << 9) /* need tkip phase 1 key to be updated by the driver */ ++#define WL_WOWL_GTK_FAILURE (1 << 10) /* enable wakeup if GTK fails */ ++#define WL_WOWL_EXTMAGPAT (1 << 11) /* support extended magic packets */ ++#define WL_WOWL_ARPOFFLOAD (1 << 12) /* support ARP/NS/keepalive offloading */ ++#define WL_WOWL_WPA2 (1 << 13) /* read protocol version for EAPOL frames */ ++#define WL_WOWL_KEYROT (1 << 14) /* If the bit is set, use key rotaton */ ++#define WL_WOWL_BCAST (1 << 15) /* If the bit is set, frm received was bcast frame */ ++#define WL_WOWL_SCANOL (1 << 16) /* If the bit is set, scan offload is enabled */ ++#define WL_WOWL_TCPKEEP_TIME (1 << 17) /* Wakeup on tcpkeep alive timeout */ ++#define WL_WOWL_MDNS_CONFLICT (1 << 18) /* Wakeup on mDNS Conflict Resolution */ ++#define WL_WOWL_MDNS_SERVICE (1 << 19) /* Wakeup on mDNS Service Connect */ ++#define WL_WOWL_TCPKEEP_DATA (1 << 20) /* tcp keepalive got data */ ++#define WL_WOWL_FW_HALT (1 << 21) /* Firmware died in wowl mode */ ++#define WL_WOWL_ENAB_HWRADIO (1 << 22) /* Enable detection of radio button changes */ ++#define WL_WOWL_MIC_FAIL (1 << 23) /* Offloads detected MIC failure(s) */ ++#define WL_WOWL_UNASSOC (1 << 24) /* Wakeup in Unassociated state (Net/Magic Pattern) */ ++#define WL_WOWL_SECURE (1 << 25) /* Wakeup if received matched secured pattern */ ++#define WL_WOWL_EXCESS_WAKE (1 << 26) /* Excess wake */ ++#define WL_WOWL_LINKDOWN (1 << 31) /* Link Down indication in WoWL mode */ ++ ++#define WL_WOWL_TCPKEEP (1 << 20) /* temp copy to satisfy automerger */ ++#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ ++ ++#define WOWL_PATTEN_TYPE_ARP (1 << 0) /* ARP offload Pattern */ ++#define WOWL_PATTEN_TYPE_NA (1 << 1) /* NA offload Pattern */ ++ ++#define MAGIC_PKT_MINLEN 102 /* Magic pkt min length is 6 * 0xFF + 16 * ETHER_ADDR_LEN */ ++#define MAGIC_PKT_NUM_MAC_ADDRS 16 ++ ++/* Overlap BSS Scan parameters default, minimum, maximum */ ++#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000 /* unit TU */ ++#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300 /* unit Sec */ ++#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10 /* unit Sec */ ++#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900 /* unit Sec */ ++#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5 ++#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5 ++#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100 ++#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200 /* unit TU */ ++#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000 /* unit TU */ ++#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25 /* unit percent */ ++#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0 /* unit percent */ ++#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100 /* unit percent */ ++ ++#define WL_MIN_NUM_OBSS_SCAN_ARG 7 /* minimum number of arguments required for OBSS Scan */ ++ ++#define WL_COEX_INFO_MASK 0x07 ++#define WL_COEX_INFO_REQ 0x01 ++#define WL_COEX_40MHZ_INTOLERANT 0x02 ++#define WL_COEX_WIDTH20 0x04 ++ ++#define WLC_RSSI_INVALID 0 /* invalid RSSI value */ ++ ++#define MAX_RSSI_LEVELS 8 ++ ++/* **** EXTLOG **** */ ++#define EXTLOG_CUR_VER 0x0100 ++ ++#define MAX_ARGSTR_LEN 18 /* At least big enough for storing ETHER_ADDR_STR_LEN */ ++ ++/* log modules (bitmap) */ ++#define LOG_MODULE_COMMON 0x0001 ++#define LOG_MODULE_ASSOC 0x0002 ++#define LOG_MODULE_EVENT 0x0004 ++#define LOG_MODULE_MAX 3 /* Update when adding module */ ++ ++/* log levels */ ++#define WL_LOG_LEVEL_DISABLE 0 ++#define WL_LOG_LEVEL_ERR 1 ++#define WL_LOG_LEVEL_WARN 2 ++#define WL_LOG_LEVEL_INFO 3 ++#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO /* Update when adding level */ ++ ++/* flag */ ++#define LOG_FLAG_EVENT 1 ++ ++/* log arg_type */ ++#define LOG_ARGTYPE_NULL 0 ++#define LOG_ARGTYPE_STR 1 /* %s */ ++#define LOG_ARGTYPE_INT 2 /* %d */ ++#define LOG_ARGTYPE_INT_STR 3 /* %d...%s */ ++#define LOG_ARGTYPE_STR_INT 4 /* %s...%d */ ++ ++/* 802.11 Mgmt Packet flags */ ++#define VNDR_IE_BEACON_FLAG 0x1 ++#define VNDR_IE_PRBRSP_FLAG 0x2 ++#define VNDR_IE_ASSOCRSP_FLAG 0x4 ++#define VNDR_IE_AUTHRSP_FLAG 0x8 ++#define VNDR_IE_PRBREQ_FLAG 0x10 ++#define VNDR_IE_ASSOCREQ_FLAG 0x20 ++#define VNDR_IE_IWAPID_FLAG 0x40 /* vendor IE in IW advertisement protocol ID field */ ++#define VNDR_IE_AUTHREQ_FLAG 0x80 ++#define VNDR_IE_CUSTOM_FLAG 0x100 /* allow custom IE id */ ++#define VNDR_IE_DISASSOC_FLAG 0x200 ++ ++#if defined(WLP2P) ++/* P2P Action Frames flags (spec ordered) */ ++#define VNDR_IE_GONREQ_FLAG 0x001000 ++#define VNDR_IE_GONRSP_FLAG 0x002000 ++#define VNDR_IE_GONCFM_FLAG 0x004000 ++#define VNDR_IE_INVREQ_FLAG 0x008000 ++#define VNDR_IE_INVRSP_FLAG 0x010000 ++#define VNDR_IE_DISREQ_FLAG 0x020000 ++#define VNDR_IE_DISRSP_FLAG 0x040000 ++#define VNDR_IE_PRDREQ_FLAG 0x080000 ++#define VNDR_IE_PRDRSP_FLAG 0x100000 ++ ++#define VNDR_IE_P2PAF_SHIFT 12 ++#endif /* WLP2P */ ++ ++/* channel interference measurement (chanim) related defines */ ++ ++/* chanim mode */ ++#define CHANIM_DISABLE 0 /* disabled */ ++#define CHANIM_DETECT 1 /* detection only */ ++#define CHANIM_EXT 2 /* external state machine */ ++#define CHANIM_ACT 3 /* full internal state machine, detect + act */ ++#define CHANIM_MODE_MAX 4 ++ ++/* define for apcs reason code */ ++#define APCS_INIT 0 ++#define APCS_IOCTL 1 ++#define APCS_CHANIM 2 ++#define APCS_CSTIMER 3 ++#define APCS_TXDLY 5 ++#define APCS_NONACSD 6 ++#define APCS_DFS_REENTRY 7 ++#define APCS_TXFAIL 8 ++#define APCS_MAX 9 ++ ++/* number of ACS record entries */ ++#define CHANIM_ACS_RECORD 10 ++ ++/* CHANIM */ ++#define CCASTATS_TXDUR 0 ++#define CCASTATS_INBSS 1 ++#define CCASTATS_OBSS 2 ++#define CCASTATS_NOCTG 3 ++#define CCASTATS_NOPKT 4 ++#define CCASTATS_DOZE 5 ++#define CCASTATS_TXOP 6 ++#define CCASTATS_GDTXDUR 7 ++#define CCASTATS_BDTXDUR 8 ++ ++#ifndef WLCHANIM_V2 ++#define CCASTATS_MAX 9 ++#else /* WLCHANIM_V2 */ ++#define CCASTATS_MYRX 9 ++#define CCASTATS_MAX 10 ++#endif /* WLCHANIM_V2 */ ++ ++#define WL_CHANIM_COUNT_ALL 0xff ++#define WL_CHANIM_COUNT_ONE 0x1 ++ ++/* ap tpc modes */ ++#define AP_TPC_OFF 0 ++#define AP_TPC_BSS_PWR 1 /* BSS power control */ ++#define AP_TPC_AP_PWR 2 /* AP power control */ ++#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ ++#define AP_TPC_MAX_LINK_MARGIN 127 ++ ++/* ap tpc modes */ ++#define AP_TPC_OFF 0 ++#define AP_TPC_BSS_PWR 1 /* BSS power control */ ++#define AP_TPC_AP_PWR 2 /* AP power control */ ++#define AP_TPC_AP_BSS_PWR 3 /* Both AP and BSS power control */ ++#define AP_TPC_MAX_LINK_MARGIN 127 ++ ++/* state */ ++#define WL_P2P_DISC_ST_SCAN 0 ++#define WL_P2P_DISC_ST_LISTEN 1 ++#define WL_P2P_DISC_ST_SEARCH 2 ++ ++/* i/f type */ ++#define WL_P2P_IF_CLIENT 0 ++#define WL_P2P_IF_GO 1 ++#define WL_P2P_IF_DYNBCN_GO 2 ++#define WL_P2P_IF_DEV 3 ++ ++/* count */ ++#define WL_P2P_SCHED_RSVD 0 ++#define WL_P2P_SCHED_REPEAT 255 /* anything > 255 will be treated as 255 */ ++ ++#define WL_P2P_SCHED_FIXED_LEN 3 ++ ++/* schedule type */ ++#define WL_P2P_SCHED_TYPE_ABS 0 /* Scheduled Absence */ ++#define WL_P2P_SCHED_TYPE_REQ_ABS 1 /* Requested Absence */ ++ ++/* schedule action during absence periods (for WL_P2P_SCHED_ABS type) */ ++#define WL_P2P_SCHED_ACTION_NONE 0 /* no action */ ++#define WL_P2P_SCHED_ACTION_DOZE 1 /* doze */ ++/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ ++#define WL_P2P_SCHED_ACTION_GOOFF 2 /* turn off GO beacon/prbrsp functions */ ++/* schedule option - WL_P2P_SCHED_TYPE_XXX */ ++#define WL_P2P_SCHED_ACTION_RESET 255 /* reset */ ++ ++/* schedule option - WL_P2P_SCHED_TYPE_ABS */ ++#define WL_P2P_SCHED_OPTION_NORMAL 0 /* normal start/interval/duration/count */ ++#define WL_P2P_SCHED_OPTION_BCNPCT 1 /* percentage of beacon interval */ ++/* schedule option - WL_P2P_SCHED_TYPE_REQ_ABS */ ++#define WL_P2P_SCHED_OPTION_TSFOFS 2 /* normal start/internal/duration/count with ++ * start being an offset of the 'current' TSF ++ */ ++ ++/* feature flags */ ++#define WL_P2P_FEAT_GO_CSA (1 << 0) /* GO moves with the STA using CSA method */ ++#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1) /* GO does not probe respond to non-p2p probe ++ * requests ++ */ ++#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2) /* Restrict p2p dev interface from responding */ ++ ++/* n-mode support capability */ ++/* 2x2 includes both 1x1 & 2x2 devices ++ * reserved #define 2 for future when we want to separate 1x1 & 2x2 and ++ * control it independently ++ */ ++#define WL_11N_2x2 1 ++#define WL_11N_3x3 3 ++#define WL_11N_4x4 4 ++ ++/* define 11n feature disable flags */ ++#define WLFEATURE_DISABLE_11N 0x00000001 ++#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002 ++#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004 ++#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008 ++#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010 ++#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020 ++#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040 ++#define WLFEATURE_DISABLE_11N_GF 0x00000080 ++ ++/* Proxy STA modes */ ++#define PSTA_MODE_DISABLED 0 ++#define PSTA_MODE_PROXY 1 ++#define PSTA_MODE_REPEATER 2 ++ ++/* op code in nat_cfg */ ++#define NAT_OP_ENABLE 1 /* enable NAT on given interface */ ++#define NAT_OP_DISABLE 2 /* disable NAT on given interface */ ++#define NAT_OP_DISABLE_ALL 3 /* disable NAT on all interfaces */ ++ ++/* NAT state */ ++#define NAT_STATE_ENABLED 1 /* NAT is enabled */ ++#define NAT_STATE_DISABLED 2 /* NAT is disabled */ ++ ++#define CHANNEL_5G_LOW_START 36 /* 5G low (36..48) CDD enable/disable bit mask */ ++#define CHANNEL_5G_MID_START 52 /* 5G mid (52..64) CDD enable/disable bit mask */ ++#define CHANNEL_5G_HIGH_START 100 /* 5G high (100..140) CDD enable/disable bit mask */ ++#define CHANNEL_5G_UPPER_START 149 /* 5G upper (149..161) CDD enable/disable bit mask */ ++ ++/* D0 Coalescing */ ++#define IPV4_ARP_FILTER 0x0001 ++#define IPV4_NETBT_FILTER 0x0002 ++#define IPV4_LLMNR_FILTER 0x0004 ++#define IPV4_SSDP_FILTER 0x0008 ++#define IPV4_WSD_FILTER 0x0010 ++#define IPV6_NETBT_FILTER 0x0200 ++#define IPV6_LLMNR_FILTER 0x0400 ++#define IPV6_SSDP_FILTER 0x0800 ++#define IPV6_WSD_FILTER 0x1000 ++ ++/* Network Offload Engine */ ++#define NWOE_OL_ENABLE 0x00000001 ++ ++/* ++ * Traffic management structures/defines. ++ */ ++ ++/* Traffic management bandwidth parameters */ ++#define TRF_MGMT_MAX_PRIORITIES 3 ++ ++#define TRF_MGMT_FLAG_ADD_DSCP 0x0001 /* Add DSCP to IP TOS field */ ++#define TRF_MGMT_FLAG_DISABLE_SHAPING 0x0002 /* Don't shape traffic */ ++#define TRF_MGMT_FLAG_MANAGE_LOCAL_TRAFFIC 0x0008 /* Manage traffic over our local subnet */ ++#define TRF_MGMT_FLAG_FILTER_ON_MACADDR 0x0010 /* filter on MAC address */ ++#define TRF_MGMT_FLAG_NO_RX 0x0020 /* do not apply fiters to rx packets */ ++ ++#define TRF_FILTER_MAC_ADDR 0x0001 /* L2 filter use dst mac address for filtering */ ++#define TRF_FILTER_IP_ADDR 0x0002 /* L3 filter use ip ddress for filtering */ ++#define TRF_FILTER_L4 0x0004 /* L4 filter use tcp/udp for filtering */ ++#define TRF_FILTER_DWM 0x0008 /* L3 filter use DSCP for filtering */ ++#define TRF_FILTER_FAVORED 0x0010 /* Tag the packet FAVORED */ ++ ++/* WNM/NPS subfeatures mask */ ++#define WL_WNM_BSSTRANS 0x00000001 ++#define WL_WNM_PROXYARP 0x00000002 ++#define WL_WNM_MAXIDLE 0x00000004 ++#define WL_WNM_TIMBC 0x00000008 ++#define WL_WNM_TFS 0x00000010 ++#define WL_WNM_SLEEP 0x00000020 ++#define WL_WNM_DMS 0x00000040 ++#define WL_WNM_FMS 0x00000080 ++#define WL_WNM_NOTIF 0x00000100 ++#define WL_WNM_WBTEXT 0x00000200 ++#define WL_WNM_MAX 0x00000400 ++#ifdef WLWNM_BRCM ++#define BRCM_WNM_FEATURE_SET\ ++ (WL_WNM_PROXYARP | \ ++ WL_WNM_SLEEP | \ ++ WL_WNM_FMS | \ ++ WL_WNM_TFS | \ ++ WL_WNM_TIMBC | \ ++ WL_WNM_BSSTRANS | \ ++ WL_WNM_DMS | \ ++ WL_WNM_NOTIF | \ ++ 0) ++#endif /* WLWNM_BRCM */ ++#ifndef ETHER_MAX_DATA ++#define ETHER_MAX_DATA 1500 ++#endif /* ETHER_MAX_DATA */ ++ ++/* Different discovery modes for dpt */ ++#define DPT_DISCOVERY_MANUAL 0x01 /* manual discovery mode */ ++#define DPT_DISCOVERY_AUTO 0x02 /* auto discovery mode */ ++#define DPT_DISCOVERY_SCAN 0x04 /* scan-based discovery mode */ ++ ++/* different path selection values */ ++#define DPT_PATHSEL_AUTO 0 /* auto mode for path selection */ ++#define DPT_PATHSEL_DIRECT 1 /* always use direct DPT path */ ++#define DPT_PATHSEL_APPATH 2 /* always use AP path */ ++ ++/* different ops for deny list */ ++#define DPT_DENY_LIST_ADD 1 /* add to dpt deny list */ ++#define DPT_DENY_LIST_REMOVE 2 /* remove from dpt deny list */ ++ ++/* different ops for manual end point */ ++#define DPT_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ ++#define DPT_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ ++#define DPT_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ ++ ++/* flags to indicate DPT status */ ++#define DPT_STATUS_ACTIVE 0x01 /* link active (though may be suspended) */ ++#define DPT_STATUS_AES 0x02 /* link secured through AES encryption */ ++#define DPT_STATUS_FAILED 0x04 /* DPT link failed */ ++ ++#ifdef WLTDLS ++/* different ops for manual end point */ ++#define TDLS_MANUAL_EP_CREATE 1 /* create manual dpt endpoint */ ++#define TDLS_MANUAL_EP_MODIFY 2 /* modify manual dpt endpoint */ ++#define TDLS_MANUAL_EP_DELETE 3 /* delete manual dpt endpoint */ ++#define TDLS_MANUAL_EP_PM 4 /* put dpt endpoint in PM mode */ ++#define TDLS_MANUAL_EP_WAKE 5 /* wake up dpt endpoint from PM */ ++#define TDLS_MANUAL_EP_DISCOVERY 6 /* discover if endpoint is TDLS capable */ ++#define TDLS_MANUAL_EP_CHSW 7 /* channel switch */ ++#define TDLS_MANUAL_EP_WFD_TPQ 8 /* WiFi-Display Tunneled Probe reQuest */ ++ ++/* modes */ ++#define TDLS_WFD_IE_TX 0 ++#define TDLS_WFD_IE_RX 1 ++#define TDLS_WFD_PROBE_IE_TX 2 ++#define TDLS_WFD_PROBE_IE_RX 3 ++#endif /* WLTDLS */ ++ ++/* define for flag */ ++#define TSPEC_PENDING 0 /* TSPEC pending */ ++#define TSPEC_ACCEPTED 1 /* TSPEC accepted */ ++#define TSPEC_REJECTED 2 /* TSPEC rejected */ ++#define TSPEC_UNKNOWN 3 /* TSPEC unknown */ ++#define TSPEC_STATUS_MASK 7 /* TSPEC status mask */ ++ ++ ++/* Software feature flag defines used by wlfeatureflag */ ++#ifdef WLAFTERBURNER ++#define WL_SWFL_ABBFL 0x0001 /* Allow Afterburner on systems w/o hardware BFL */ ++#define WL_SWFL_ABENCORE 0x0002 /* Allow AB on non-4318E chips */ ++#endif /* WLAFTERBURNER */ ++#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 */ ++ ++#define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */ ++ ++#define CSA_BROADCAST_ACTION_FRAME 0 /* csa broadcast action frame */ ++#define CSA_UNICAST_ACTION_FRAME 1 /* csa unicast action frame */ ++ ++/* Roaming trigger definitions for WLC_SET_ROAM_TRIGGER. ++ * ++ * (-100 < value < 0) value is used directly as a roaming trigger in dBm ++ * (0 <= value) value specifies a logical roaming trigger level from ++ * the list below ++ * ++ * WLC_GET_ROAM_TRIGGER always returns roaming trigger value in dBm, never ++ * the logical roam trigger value. ++ */ ++#define WLC_ROAM_TRIGGER_DEFAULT 0 /* default roaming trigger */ ++#define WLC_ROAM_TRIGGER_BANDWIDTH 1 /* optimize for bandwidth roaming trigger */ ++#define WLC_ROAM_TRIGGER_DISTANCE 2 /* optimize for distance roaming trigger */ ++#define WLC_ROAM_TRIGGER_AUTO 3 /* auto-detect environment */ ++#define WLC_ROAM_TRIGGER_MAX_VALUE 3 /* max. valid value */ ++ ++#define WLC_ROAM_NEVER_ROAM_TRIGGER (-100) /* Avoid Roaming by setting a large value */ ++ ++/* Preferred Network Offload (PNO, formerly PFN) defines */ ++#define WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */ ++ ++#define SORT_CRITERIA_BIT 0 ++#define AUTO_NET_SWITCH_BIT 1 ++#define ENABLE_BKGRD_SCAN_BIT 2 ++#define IMMEDIATE_SCAN_BIT 3 ++#define AUTO_CONNECT_BIT 4 ++#define ENABLE_BD_SCAN_BIT 5 ++#define ENABLE_ADAPTSCAN_BIT 6 ++#define IMMEDIATE_EVENT_BIT 8 ++#define SUPPRESS_SSID_BIT 9 ++#define ENABLE_NET_OFFLOAD_BIT 10 ++/* report found/lost events for SSID and BSSID networks seperately */ ++#define REPORT_SEPERATELY_BIT 11 ++#define BESTN_BSSID_ONLY_BIT 12 ++ ++#define SORT_CRITERIA_MASK 0x0001 ++#define AUTO_NET_SWITCH_MASK 0x0002 ++#define ENABLE_BKGRD_SCAN_MASK 0x0004 ++#define IMMEDIATE_SCAN_MASK 0x0008 ++#define AUTO_CONNECT_MASK 0x0010 ++ ++#define ENABLE_BD_SCAN_MASK 0x0020 ++#define ENABLE_ADAPTSCAN_MASK 0x00c0 ++#define IMMEDIATE_EVENT_MASK 0x0100 ++#define SUPPRESS_SSID_MASK 0x0200 ++#define ENABLE_NET_OFFLOAD_MASK 0x0400 ++/* report found/lost events for SSID and BSSID networks seperately */ ++#define REPORT_SEPERATELY_MASK 0x0800 ++#define BESTN_BSSID_ONLY_MASK 0x1000 ++ ++#define PFN_VERSION 2 ++#ifdef PFN_SCANRESULT_2 ++#define PFN_SCANRESULT_VERSION 2 ++#else ++#define PFN_SCANRESULT_VERSION 1 ++#endif /* PFN_SCANRESULT_2 */ ++#ifndef MAX_PFN_LIST_COUNT ++#define MAX_PFN_LIST_COUNT 16 ++#endif /* MAX_PFN_LIST_COUNT */ ++ ++#define PFN_COMPLETE 1 ++#define PFN_INCOMPLETE 0 ++ ++#define DEFAULT_BESTN 2 ++#define DEFAULT_MSCAN 0 ++#define DEFAULT_REPEAT 10 ++#define DEFAULT_EXP 2 ++ ++#define PFN_PARTIAL_SCAN_BIT 0 ++#define PFN_PARTIAL_SCAN_MASK 1 ++ ++#define WL_PFN_SUPPRESSFOUND_MASK 0x08 ++#define WL_PFN_SUPPRESSLOST_MASK 0x10 ++#define WL_PFN_SSID_A_BAND_TRIG 0x20 ++#define WL_PFN_SSID_BG_BAND_TRIG 0x40 ++#define WL_PFN_SSID_IMPRECISE_MATCH 0x80 ++#define WL_PFN_SSID_SAME_NETWORK 0x10000 ++#define WL_PFN_SUPPRESS_AGING_MASK 0x20000 ++#define WL_PFN_FLUSH_ALL_SSIDS 0x40000 ++#define WL_PFN_RSSI_MASK 0xff00 ++#define WL_PFN_RSSI_SHIFT 8 ++ ++#define WL_PFN_REPORT_ALLNET 0 ++#define WL_PFN_REPORT_SSIDNET 1 ++#define WL_PFN_REPORT_BSSIDNET 2 ++ ++#define WL_PFN_CFG_FLAGS_PROHIBITED 0x00000001 /* Accept and use prohibited channels */ ++#define WL_PFN_CFG_FLAGS_HISTORY_OFF 0x00000002 /* Scan history suppressed */ ++ ++#define WL_PFN_HIDDEN_BIT 2 ++#define PNO_SCAN_MAX_FW 508*1000 /* max time scan time in msec */ ++#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000 /* max time scan time in SEC */ ++#define PNO_SCAN_MIN_FW_SEC 10 /* min time scan time in SEC */ ++#define WL_PFN_HIDDEN_MASK 0x4 ++#define MAX_SSID_WHITELIST_NUM 4 ++#define MAX_BSSID_PREF_LIST_NUM 32 ++#define MAX_BSSID_BLACKLIST_NUM 32 ++ ++#ifndef BESTN_MAX ++#define BESTN_MAX 10 ++#endif ++ ++#ifndef MSCAN_MAX ++#define MSCAN_MAX 32 ++#endif ++ ++/* TCP Checksum Offload error injection for testing */ ++#define TOE_ERRTEST_TX_CSUM 0x00000001 ++#define TOE_ERRTEST_RX_CSUM 0x00000002 ++#define TOE_ERRTEST_RX_CSUM2 0x00000004 ++ ++/* ARP Offload feature flags for arp_ol iovar */ ++#define ARP_OL_AGENT 0x00000001 ++#define ARP_OL_SNOOP 0x00000002 ++#define ARP_OL_HOST_AUTO_REPLY 0x00000004 ++#define ARP_OL_PEER_AUTO_REPLY 0x00000008 ++ ++/* ARP Offload error injection */ ++#define ARP_ERRTEST_REPLY_PEER 0x1 ++#define ARP_ERRTEST_REPLY_HOST 0x2 ++ ++#define ARP_MULTIHOMING_MAX 8 /* Maximum local host IP addresses */ ++#define ND_MULTIHOMING_MAX 10 /* Maximum local host IP addresses */ ++#define ND_REQUEST_MAX 5 /* Max set of offload params */ ++/* AOAC wake event flag */ ++#define WAKE_EVENT_NLO_DISCOVERY_BIT 1 ++#define WAKE_EVENT_AP_ASSOCIATION_LOST_BIT 2 ++#define WAKE_EVENT_GTK_HANDSHAKE_ERROR_BIT 4 ++#define WAKE_EVENT_4WAY_HANDSHAKE_REQUEST_BIT 8 ++#define WAKE_EVENT_NET_PACKET_BIT 0x10 ++ ++#define MAX_NUM_WOL_PATTERN 22 /* LOGO requirements min 22 */ ++ ++ ++/* Packet filter operation mode */ ++/* True: 1; False: 0 */ ++#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1 ++/* Enable and disable pkt_filter as a whole */ ++#define PKT_FILTER_MODE_DISABLE 2 ++/* Cache first matched rx pkt(be queried by host later) */ ++#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4 ++/* If pkt_filter is enabled and no filter is set, don't forward anything */ ++#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8 ++ ++#ifdef DONGLEOVERLAYS ++#define OVERLAY_IDX_MASK 0x000000ff ++#define OVERLAY_IDX_SHIFT 0 ++#define OVERLAY_FLAGS_MASK 0xffffff00 ++#define OVERLAY_FLAGS_SHIFT 8 ++/* overlay written to device memory immediately after loading the base image */ ++#define OVERLAY_FLAG_POSTLOAD 0x100 ++/* defer overlay download until the device responds w/WLC_E_OVL_DOWNLOAD event */ ++#define OVERLAY_FLAG_DEFER_DL 0x200 ++/* overlay downloaded prior to the host going to sleep */ ++#define OVERLAY_FLAG_PRESLEEP 0x400 ++#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024 ++#endif /* DONGLEOVERLAYS */ ++ ++/* reuse two number in the sc/rc space */ ++#define SMFS_CODE_MALFORMED 0xFFFE ++#define SMFS_CODE_IGNORED 0xFFFD ++ ++/* RFAWARE def */ ++#define BCM_ACTION_RFAWARE 0x77 ++#define BCM_ACTION_RFAWARE_DCS 0x01 ++ ++/* DCS reason code define */ ++#define BCM_DCS_IOVAR 0x1 ++#define BCM_DCS_UNKNOWN 0xFF ++ ++#ifdef PROP_TXSTATUS ++/* Bit definitions for tlv iovar */ ++/* ++ * enable RSSI signals: ++ * WLFC_CTL_TYPE_RSSI ++ */ ++#define WLFC_FLAGS_RSSI_SIGNALS 0x0001 ++ ++/* enable (if/mac_open, if/mac_close,, mac_add, mac_del) signals: ++ * ++ * WLFC_CTL_TYPE_MAC_OPEN ++ * WLFC_CTL_TYPE_MAC_CLOSE ++ * ++ * WLFC_CTL_TYPE_INTERFACE_OPEN ++ * WLFC_CTL_TYPE_INTERFACE_CLOSE ++ * ++ * WLFC_CTL_TYPE_MACDESC_ADD ++ * WLFC_CTL_TYPE_MACDESC_DEL ++ * ++ */ ++#define WLFC_FLAGS_XONXOFF_SIGNALS 0x0002 ++ ++/* enable (status, fifo_credit, mac_credit) signals ++ * WLFC_CTL_TYPE_MAC_REQUEST_CREDIT ++ * WLFC_CTL_TYPE_TXSTATUS ++ * WLFC_CTL_TYPE_FIFO_CREDITBACK ++ */ ++#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 0x0004 ++ ++#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008 ++#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010 ++#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 ++#define WLFC_FLAGS_HOST_RXRERODER_ACTIVE 0x0040 ++#define WLFC_FLAGS_PKT_STAMP_SIGNALS 0x0080 ++ ++#endif /* PROP_TXSTATUS */ ++ ++#define WL_TIMBC_STATUS_AP_UNKNOWN 255 /* AP status for internal use only */ ++ ++#define WL_DFRTS_LOGIC_OFF 0 /* Feature is disabled */ ++#define WL_DFRTS_LOGIC_OR 1 /* OR all non-zero threshold conditions */ ++#define WL_DFRTS_LOGIC_AND 2 /* AND all non-zero threshold conditions */ ++ ++/* Definitions for Reliable Multicast */ ++#define WL_RELMCAST_MAX_CLIENT 32 ++#define WL_RELMCAST_FLAG_INBLACKLIST 1 ++#define WL_RELMCAST_FLAG_ACTIVEACKER 2 ++#define WL_RELMCAST_FLAG_RELMCAST 4 ++ ++/* structures for proximity detection device role */ ++#define WL_PROXD_MODE_DISABLE 0 ++#define WL_PROXD_MODE_NEUTRAL 1 ++#define WL_PROXD_MODE_INITIATOR 2 ++#define WL_PROXD_MODE_TARGET 3 ++#define WL_PROXD_RANDOM_WAKEUP 0x8000 ++ ++ ++#ifdef NET_DETECT ++#define NET_DETECT_MAX_WAKE_DATA_SIZE 2048 ++#define NET_DETECT_MAX_PROFILES 16 ++#define NET_DETECT_MAX_CHANNELS 50 ++#endif /* NET_DETECT */ ++ ++ ++/* 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 */ ++#define WL_RADIO_PERCORE_DISABLE (1<<4) /* Radio diable per core for DVT */ ++ ++#define WL_SPURAVOID_OFF 0 ++#define WL_SPURAVOID_ON1 1 ++#define WL_SPURAVOID_ON2 2 ++ ++ ++#define WL_4335_SPURAVOID_ON1 1 ++#define WL_4335_SPURAVOID_ON2 2 ++#define WL_4335_SPURAVOID_ON3 3 ++#define WL_4335_SPURAVOID_ON4 4 ++#define WL_4335_SPURAVOID_ON5 5 ++#define WL_4335_SPURAVOID_ON6 6 ++#define WL_4335_SPURAVOID_ON7 7 ++#define WL_4335_SPURAVOID_ON8 8 ++#define WL_4335_SPURAVOID_ON9 9 ++ ++/* Override bit for WLC_SET_TXPWR. if set, ignore other level limits */ ++#define WL_TXPWR_OVERRIDE (1U<<31) ++#define WL_TXPWR_2G (1U<<30) ++#define WL_TXPWR_5G (1U<<29) ++#define WL_TXPWR_NEG (1U<<28) ++ ++#define WL_TXPWR_MASK (~(0x7<<29)) ++#define WL_TXPWR_CORE_MAX (3) ++#define WL_TXPWR_CORE0_MASK (0x000000FF) ++#define WL_TXPWR_CORE0_SHIFT (0) ++#define WL_TXPWR_CORE1_MASK (0x0000FF00) ++#define WL_TXPWR_CORE1_SHIFT (8) ++#define WL_TXPWR_CORE2_MASK (0x00FF0000) ++#define WL_TXPWR_CORE2_SHIFT (16) ++ ++/* phy types (returned by WLC_GET_PHYTPE) */ ++#define WLC_PHY_TYPE_A 0 ++#define WLC_PHY_TYPE_B 1 ++#define WLC_PHY_TYPE_G 2 ++#define WLC_PHY_TYPE_N 4 ++#define WLC_PHY_TYPE_LP 5 ++#define WLC_PHY_TYPE_SSN 6 ++#define WLC_PHY_TYPE_HT 7 ++#define WLC_PHY_TYPE_LCN 8 ++#define WLC_PHY_TYPE_LCN40 10 ++#define WLC_PHY_TYPE_AC 11 ++#define WLC_PHY_TYPE_LCN20 12 ++#define WLC_PHY_TYPE_NULL 0xf ++ ++/* Values for PM */ ++#define PM_OFF 0 ++#define PM_MAX 1 ++#define PM_FAST 2 ++#define PM_FORCE_OFF 3 /* use this bit to force PM off even bt is active */ ++ ++#define WL_WME_CNT_VERSION 1 /* current version of wl_wme_cnt_t */ ++ ++/* fbt_cap: FBT assoc / reassoc modes. */ ++#define WLC_FBT_CAP_DRV_4WAY_AND_REASSOC 1 /* Driver 4-way handshake & reassoc (WLFBT). */ ++ ++/* monitor_promisc_level bits */ ++#define WL_MONPROMISC_PROMISC 0x0001 ++#define WL_MONPROMISC_CTRL 0x0002 ++#define WL_MONPROMISC_FCS 0x0004 ++ ++/* TCP Checksum Offload defines */ ++#define TOE_TX_CSUM_OL 0x00000001 ++#define TOE_RX_CSUM_OL 0x00000002 ++ ++/* Wi-Fi Display Services (WFDS) */ ++#define WL_P2P_SOCIAL_CHANNELS_MAX WL_NUMCHANNELS ++#define MAX_WFDS_SEEK_SVC 4 /* Max # of wfds services to seek */ ++#define MAX_WFDS_ADVERT_SVC 4 /* Max # of wfds services to advertise */ ++#define MAX_WFDS_SVC_NAME_LEN 200 /* maximum service_name length */ ++#define MAX_WFDS_ADV_SVC_INFO_LEN 65000 /* maximum adv service_info length */ ++#define P2P_WFDS_HASH_LEN 6 /* Length of a WFDS service hash */ ++#define MAX_WFDS_SEEK_SVC_INFO_LEN 255 /* maximum seek service_info req length */ ++#define MAX_WFDS_SEEK_SVC_NAME_LEN 200 /* maximum service_name length */ ++ ++/* ap_isolate bitmaps */ ++#define AP_ISOLATE_DISABLED 0x0 ++#define AP_ISOLATE_SENDUP_ALL 0x01 ++#define AP_ISOLATE_SENDUP_MCAST 0x02 ++ ++/* Type values for the wl_pwrstats_t data field */ ++#define WL_PWRSTATS_TYPE_PHY 0 /**< struct wl_pwr_phy_stats */ ++#define WL_PWRSTATS_TYPE_SCAN 1 /**< struct wl_pwr_scan_stats */ ++#define WL_PWRSTATS_TYPE_USB_HSIC 2 /**< struct wl_pwr_usb_hsic_stats */ ++#define WL_PWRSTATS_TYPE_PM_AWAKE1 3 /**< struct wl_pwr_pm_awake_stats_v1 */ ++#define WL_PWRSTATS_TYPE_CONNECTION 4 /* struct wl_pwr_connect_stats; assoc and key-exch time */ ++#define WL_PWRSTATS_TYPE_PCIE 6 /**< struct wl_pwr_pcie_stats */ ++#define WL_PWRSTATS_TYPE_PM_AWAKE2 7 /**< struct wl_pwr_pm_awake_stats_v2 */ ++#define WL_PWRSTATS_TYPE_SDIO 8 /* struct wl_pwr_sdio_stats */ ++#define WL_PWRSTATS_TYPE_MIMO_PS_METRICS 9 /* struct wl_mimo_meas_metrics_t */ ++ ++#endif /* wlioctl_defs_h */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl_utils.h b/module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl_utils.h +new file mode 100644 +index 000000000..797531cfa +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/wlioctl_utils.h +@@ -0,0 +1,61 @@ ++/* ++ * Custom OID/ioctl related helper functions. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * <> ++ * ++ * $Id: wlioctl_utils.h 614820 2016-01-23 17:16:17Z $ ++ */ ++ ++#ifndef _wlioctl_utils_h_ ++#define _wlioctl_utils_h_ ++ ++#include ++ ++#ifndef BCMDRIVER ++#define CCA_THRESH_MILLI 14 ++#define CCA_THRESH_INTERFERE 6 ++ ++extern cca_congest_channel_req_t * cca_per_chan_summary(cca_congest_channel_req_t *input, ++ cca_congest_channel_req_t *avg, bool percent); ++ ++extern int cca_analyze(cca_congest_channel_req_t *input[], int num_chans, ++ uint flags, chanspec_t *answer); ++#endif /* BCMDRIVER */ ++ ++extern int wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf, ++ int buflen, uint32 corerev); ++ ++extern const char * wl_get_reinit_rc_name(int rc); ++ ++/* Get data pointer of wlc layer counters tuple from xtlv formatted counters IOVar buffer. */ ++#define GET_WLCCNT_FROM_CNTBUF(cntbuf) \ ++ bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)cntbuf)->data, \ ++ ((wl_cnt_info_t *)cntbuf)->datalen, WL_CNT_XTLV_WLC, \ ++ NULL, BCM_XTLV_OPTION_ALIGN32) ++ ++#define CHK_CNTBUF_DATALEN(cntbuf, ioctl_buflen) do { \ ++ if (((wl_cnt_info_t *)cntbuf)->datalen + \ ++ OFFSETOF(wl_cnt_info_t, data) > ioctl_buflen) \ ++ printf("%s: IOVAR buffer short!\n", __FUNCTION__); \ ++} while (0) ++ ++#endif /* _wlioctl_utils_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/wpa.h b/module_drivers/drivers/net/wireless/bcmdhd/include/wpa.h +new file mode 100644 +index 000000000..fbb9c29e6 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/wpa.h +@@ -0,0 +1,217 @@ ++/* ++ * Fundamental types and constants relating to WPA ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: wpa.h 700076 2017-05-17 14:42:22Z $ ++ */ ++ ++#ifndef _proto_wpa_h_ ++#define _proto_wpa_h_ ++ ++#include ++#include ++ ++ ++/* This marks the start of a packed structure section. */ ++#include ++ ++/* Reason Codes */ ++ ++/* 13 through 23 taken from IEEE Std 802.11i-2004 */ ++#define DOT11_RC_INVALID_WPA_IE 13 /* Invalid info. element */ ++#define DOT11_RC_MIC_FAILURE 14 /* Michael failure */ ++#define DOT11_RC_4WH_TIMEOUT 15 /* 4-way handshake timeout */ ++#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 /* Group key update timeout */ ++#define DOT11_RC_WPA_IE_MISMATCH 17 /* WPA IE in 4-way handshake differs from ++ * (re-)assoc. request/probe response ++ */ ++#define DOT11_RC_INVALID_MC_CIPHER 18 /* Invalid multicast cipher */ ++#define DOT11_RC_INVALID_UC_CIPHER 19 /* Invalid unicast cipher */ ++#define DOT11_RC_INVALID_AKMP 20 /* Invalid authenticated key management protocol */ ++#define DOT11_RC_BAD_WPA_VERSION 21 /* Unsupported WPA version */ ++#define DOT11_RC_INVALID_WPA_CAP 22 /* Invalid WPA IE capabilities */ ++#define DOT11_RC_8021X_AUTH_FAIL 23 /* 802.1X authentication failure */ ++ ++#define WPA2_PMKID_LEN 16 ++ ++/* WPA IE fixed portion */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint8 tag; /* TAG */ ++ uint8 length; /* TAG length */ ++ uint8 oui[3]; /* IE OUI */ ++ uint8 oui_type; /* OUI type */ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT version; /* IE version */ ++} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t; ++#define WPA_IE_OUITYPE_LEN 4 ++#define WPA_IE_FIXED_LEN 8 ++#define WPA_IE_TAG_FIXED_LEN 6 ++ ++#define BIP_OUI_TYPE WPA2_OUI "\x06" ++ ++typedef BWL_PRE_PACKED_STRUCT struct { ++ uint8 tag; /* TAG */ ++ uint8 length; /* TAG length */ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT version; /* IE version */ ++} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t; ++#define WPA_RSN_IE_FIXED_LEN 4 ++#define WPA_RSN_IE_TAG_FIXED_LEN 2 ++typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; ++ ++#define WFA_OSEN_IE_FIXED_LEN 6 ++ ++/* WPA suite/multicast suite */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ uint8 oui[3]; ++ uint8 type; ++} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t; ++#define WPA_SUITE_LEN 4 ++ ++/* WPA unicast suite list/key management suite list */ ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT count; ++ wpa_suite_t list[1]; ++} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; ++#define WPA_IE_SUITE_COUNT_LEN 2 ++typedef BWL_PRE_PACKED_STRUCT struct ++{ ++ BWL_PRE_PACKED_STRUCT struct { ++ uint8 low; ++ uint8 high; ++ } BWL_POST_PACKED_STRUCT count; ++ wpa_pmkid_t list[1]; ++} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t; ++ ++/* WPA cipher suites */ ++#define WPA_CIPHER_NONE 0 /* None */ ++#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */ ++#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */ ++#define WPA_CIPHER_AES_OCB 3 /* AES (OCB) */ ++#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */ ++#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */ ++#define WPA_CIPHER_BIP 6 /* WEP (104-bit) */ ++#define WPA_CIPHER_TPK 7 /* Group addressed traffic not allowed */ ++ ++#define WPA_CIPHER_AES_GCM 8 /* AES (GCM) */ ++#define WPA_CIPHER_AES_GCM256 9 /* AES (GCM256) */ ++ ++#ifdef BCMWAPI_WAI ++#define WAPI_CIPHER_NONE WPA_CIPHER_NONE ++#define WAPI_CIPHER_SMS4 11 ++ ++#define WAPI_CSE_WPI_SMS4 1 ++#endif /* BCMWAPI_WAI */ ++ ++#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ ++ (cipher) == WPA_CIPHER_WEP_40 || \ ++ (cipher) == WPA_CIPHER_WEP_104 || \ ++ (cipher) == WPA_CIPHER_TKIP || \ ++ (cipher) == WPA_CIPHER_AES_OCB || \ ++ (cipher) == WPA_CIPHER_AES_CCM || \ ++ (cipher) == WPA_CIPHER_AES_GCM || \ ++ (cipher) == WPA_CIPHER_AES_GCM256 || \ ++ (cipher) == WPA_CIPHER_TPK) ++ ++#ifdef BCMWAPI_WAI ++#define IS_WAPI_CIPHER(cipher) ((cipher) == WAPI_CIPHER_NONE || \ ++ (cipher) == WAPI_CSE_WPI_SMS4) ++ ++/* convert WAPI_CSE_WPI_XXX to WAPI_CIPHER_XXX */ ++#define WAPI_CSE_WPI_2_CIPHER(cse) ((cse) == WAPI_CSE_WPI_SMS4 ? \ ++ WAPI_CIPHER_SMS4 : WAPI_CIPHER_NONE) ++ ++#define WAPI_CIPHER_2_CSE_WPI(cipher) ((cipher) == WAPI_CIPHER_SMS4 ? \ ++ WAPI_CSE_WPI_SMS4 : WAPI_CIPHER_NONE) ++#endif /* BCMWAPI_WAI */ ++ ++/* WPA TKIP countermeasures parameters */ ++#define WPA_TKIP_CM_DETECT 60 /* multiple MIC failure window (seconds) */ ++#define WPA_TKIP_CM_BLOCK 60 /* countermeasures active window (seconds) */ ++ ++/* RSN IE defines */ ++#define RSN_CAP_LEN 2 /* Length of RSN capabilities field (2 octets) */ ++ ++/* RSN Capabilities defined in 802.11i */ ++#define RSN_CAP_PREAUTH 0x0001 ++#define RSN_CAP_NOPAIRWISE 0x0002 ++#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C ++#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 ++#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 ++#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 ++#define RSN_CAP_1_REPLAY_CNTR 0 ++#define RSN_CAP_2_REPLAY_CNTRS 1 ++#define RSN_CAP_4_REPLAY_CNTRS 2 ++#define RSN_CAP_16_REPLAY_CNTRS 3 ++#define RSN_CAP_MFPR 0x0040 ++#define RSN_CAP_MFPC 0x0080 ++#define RSN_CAP_SPPC 0x0400 ++#define RSN_CAP_SPPR 0x0800 ++ ++/* WPA capabilities defined in 802.11i */ ++#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS ++#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS ++#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT ++#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK ++ ++/* WPA capabilities defined in 802.11zD9.0 */ ++#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) /* bit 9 */ ++ ++/* WPA Specific defines */ ++#define WPA_CAP_LEN RSN_CAP_LEN /* Length of RSN capabilities in RSN IE (2 octets) */ ++#define WPA_PMKID_CNT_LEN 2 /* Length of RSN PMKID count (2 octests) */ ++ ++#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH ++ ++#define WPA2_PMKID_COUNT_LEN 2 ++ ++#ifdef BCMWAPI_WAI ++#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH ++ ++/* Other WAI definition */ ++#define WAPI_WAI_REQUEST 0x00F1 ++#define WAPI_UNICAST_REKEY 0x00F2 ++#define WAPI_STA_AGING 0x00F3 ++#define WAPI_MUTIL_REKEY 0x00F4 ++#define WAPI_STA_STATS 0x00F5 ++ ++#define WAPI_USK_REKEY_COUNT 0x4000000 /* 0xA00000 */ ++#define WAPI_MSK_REKEY_COUNT 0x4000000 /* 0xA00000 */ ++#endif /* BCMWAPI_WAI */ ++ ++/* This marks the end of a packed structure section. */ ++#include ++ ++#endif /* _proto_wpa_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/include/wps.h b/module_drivers/drivers/net/wireless/bcmdhd/include/wps.h +new file mode 100644 +index 000000000..aa4cc1b9f +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/include/wps.h +@@ -0,0 +1,389 @@ ++/* ++ * WPS IE definitions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id$ ++ */ ++ ++#ifndef _WPS_ ++#define _WPS_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Data Element Definitions */ ++#define WPS_ID_AP_CHANNEL 0x1001 ++#define WPS_ID_ASSOC_STATE 0x1002 ++#define WPS_ID_AUTH_TYPE 0x1003 ++#define WPS_ID_AUTH_TYPE_FLAGS 0x1004 ++#define WPS_ID_AUTHENTICATOR 0x1005 ++#define WPS_ID_CONFIG_METHODS 0x1008 ++#define WPS_ID_CONFIG_ERROR 0x1009 ++#define WPS_ID_CONF_URL4 0x100A ++#define WPS_ID_CONF_URL6 0x100B ++#define WPS_ID_CONN_TYPE 0x100C ++#define WPS_ID_CONN_TYPE_FLAGS 0x100D ++#define WPS_ID_CREDENTIAL 0x100E ++#define WPS_ID_DEVICE_NAME 0x1011 ++#define WPS_ID_DEVICE_PWD_ID 0x1012 ++#define WPS_ID_E_HASH1 0x1014 ++#define WPS_ID_E_HASH2 0x1015 ++#define WPS_ID_E_SNONCE1 0x1016 ++#define WPS_ID_E_SNONCE2 0x1017 ++#define WPS_ID_ENCR_SETTINGS 0x1018 ++#define WPS_ID_ENCR_TYPE 0x100F ++#define WPS_ID_ENCR_TYPE_FLAGS 0x1010 ++#define WPS_ID_ENROLLEE_NONCE 0x101A ++#define WPS_ID_FEATURE_ID 0x101B ++#define WPS_ID_IDENTITY 0x101C ++#define WPS_ID_IDENTITY_PROOF 0x101D ++#define WPS_ID_KEY_WRAP_AUTH 0x101E ++#define WPS_ID_KEY_IDENTIFIER 0x101F ++#define WPS_ID_MAC_ADDR 0x1020 ++#define WPS_ID_MANUFACTURER 0x1021 ++#define WPS_ID_MSG_TYPE 0x1022 ++#define WPS_ID_MODEL_NAME 0x1023 ++#define WPS_ID_MODEL_NUMBER 0x1024 ++#define WPS_ID_NW_INDEX 0x1026 ++#define WPS_ID_NW_KEY 0x1027 ++#define WPS_ID_NW_KEY_INDEX 0x1028 ++#define WPS_ID_NEW_DEVICE_NAME 0x1029 ++#define WPS_ID_NEW_PWD 0x102A ++#define WPS_ID_OOB_DEV_PWD 0x102C ++#define WPS_ID_OS_VERSION 0x102D ++#define WPS_ID_POWER_LEVEL 0x102F ++#define WPS_ID_PSK_CURRENT 0x1030 ++#define WPS_ID_PSK_MAX 0x1031 ++#define WPS_ID_PUBLIC_KEY 0x1032 ++#define WPS_ID_RADIO_ENABLED 0x1033 ++#define WPS_ID_REBOOT 0x1034 ++#define WPS_ID_REGISTRAR_CURRENT 0x1035 ++#define WPS_ID_REGISTRAR_ESTBLSHD 0x1036 ++#define WPS_ID_REGISTRAR_LIST 0x1037 ++#define WPS_ID_REGISTRAR_MAX 0x1038 ++#define WPS_ID_REGISTRAR_NONCE 0x1039 ++#define WPS_ID_REQ_TYPE 0x103A ++#define WPS_ID_RESP_TYPE 0x103B ++#define WPS_ID_RF_BAND 0x103C ++#define WPS_ID_R_HASH1 0x103D ++#define WPS_ID_R_HASH2 0x103E ++#define WPS_ID_R_SNONCE1 0x103F ++#define WPS_ID_R_SNONCE2 0x1040 ++#define WPS_ID_SEL_REGISTRAR 0x1041 ++#define WPS_ID_SERIAL_NUM 0x1042 ++#define WPS_ID_SC_STATE 0x1044 ++#define WPS_ID_SSID 0x1045 ++#define WPS_ID_TOT_NETWORKS 0x1046 ++#define WPS_ID_UUID_E 0x1047 ++#define WPS_ID_UUID_R 0x1048 ++#define WPS_ID_VENDOR_EXT 0x1049 ++#define WPS_ID_VERSION 0x104A ++#define WPS_ID_X509_CERT_REQ 0x104B ++#define WPS_ID_X509_CERT 0x104C ++#define WPS_ID_EAP_IDENTITY 0x104D ++#define WPS_ID_MSG_COUNTER 0x104E ++#define WPS_ID_PUBKEY_HASH 0x104F ++#define WPS_ID_REKEY_KEY 0x1050 ++#define WPS_ID_KEY_LIFETIME 0x1051 ++#define WPS_ID_PERM_CFG_METHODS 0x1052 ++#define WPS_ID_SEL_REG_CFG_METHODS 0x1053 ++#define WPS_ID_PRIM_DEV_TYPE 0x1054 ++#define WPS_ID_SEC_DEV_TYPE_LIST 0x1055 ++#define WPS_ID_PORTABLE_DEVICE 0x1056 ++#define WPS_ID_AP_SETUP_LOCKED 0x1057 ++#define WPS_ID_APP_LIST 0x1058 ++#define WPS_ID_EAP_TYPE 0x1059 ++#define WPS_ID_INIT_VECTOR 0x1060 ++#define WPS_ID_KEY_PROVIDED_AUTO 0x1061 ++#define WPS_ID_8021X_ENABLED 0x1062 ++#define WPS_ID_WEP_TRANSMIT_KEY 0x1064 ++#define WPS_ID_REQ_DEV_TYPE 0x106A ++ ++/* WSC 2.0, WFA Vendor Extension Subelements */ ++#define WFA_VENDOR_EXT_ID "\x00\x37\x2A" ++#define WPS_WFA_SUBID_VERSION2 0x00 ++#define WPS_WFA_SUBID_AUTHORIZED_MACS 0x01 ++#define WPS_WFA_SUBID_NW_KEY_SHAREABLE 0x02 ++#define WPS_WFA_SUBID_REQ_TO_ENROLL 0x03 ++#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME 0x04 ++#define WPS_WFA_SUBID_REG_CFG_METHODS 0x05 ++ ++ ++/* WCN-NET Windows Rally Vertical Pairing Vendor Extensions */ ++#define MS_VENDOR_EXT_ID "\x00\x01\x37" ++#define WPS_MS_ID_VPI 0x1001 /* Vertical Pairing Identifier TLV */ ++#define WPS_MS_ID_TRANSPORT_UUID 0x1002 /* Transport UUID TLV */ ++ ++/* Vertical Pairing Identifier TLV Definitions */ ++#define WPS_MS_VPI_TRANSPORT_NONE 0x00 /* None */ ++#define WPS_MS_VPI_TRANSPORT_DPWS 0x01 /* Devices Profile for Web Services */ ++#define WPS_MS_VPI_TRANSPORT_UPNP 0x02 /* uPnP */ ++#define WPS_MS_VPI_TRANSPORT_SDNWS 0x03 /* Secure Devices Profile for Web Services */ ++#define WPS_MS_VPI_NO_PROFILE_REQ 0x00 /* Wi-Fi profile not requested. ++ * Not supported in Windows 7 ++ */ ++#define WPS_MS_VPI_PROFILE_REQ 0x01 /* Wi-Fi profile requested. */ ++ ++/* sizes of the fixed size elements */ ++#define WPS_ID_AP_CHANNEL_S 2 ++#define WPS_ID_ASSOC_STATE_S 2 ++#define WPS_ID_AUTH_TYPE_S 2 ++#define WPS_ID_AUTH_TYPE_FLAGS_S 2 ++#define WPS_ID_AUTHENTICATOR_S 8 ++#define WPS_ID_CONFIG_METHODS_S 2 ++#define WPS_ID_CONFIG_ERROR_S 2 ++#define WPS_ID_CONN_TYPE_S 1 ++#define WPS_ID_CONN_TYPE_FLAGS_S 1 ++#define WPS_ID_DEVICE_PWD_ID_S 2 ++#define WPS_ID_ENCR_TYPE_S 2 ++#define WPS_ID_ENCR_TYPE_FLAGS_S 2 ++#define WPS_ID_FEATURE_ID_S 4 ++#define WPS_ID_MAC_ADDR_S 6 ++#define WPS_ID_MSG_TYPE_S 1 ++#define WPS_ID_SC_STATE_S 1 ++#define WPS_ID_RF_BAND_S 1 ++#define WPS_ID_OS_VERSION_S 4 ++#define WPS_ID_VERSION_S 1 ++#define WPS_ID_SEL_REGISTRAR_S 1 ++#define WPS_ID_SEL_REG_CFG_METHODS_S 2 ++#define WPS_ID_REQ_TYPE_S 1 ++#define WPS_ID_RESP_TYPE_S 1 ++#define WPS_ID_AP_SETUP_LOCKED_S 1 ++ ++/* WSC 2.0, WFA Vendor Extension Subelements */ ++#define WPS_WFA_SUBID_VERSION2_S 1 ++#define WPS_WFA_SUBID_NW_KEY_SHAREABLE_S 1 ++#define WPS_WFA_SUBID_REQ_TO_ENROLL_S 1 ++#define WPS_WFA_SUBID_SETTINGS_DELAY_TIME_S 1 ++#define WPS_WFA_SUBID_REG_CFG_METHODS_S 2 ++ ++/* Association states */ ++#define WPS_ASSOC_NOT_ASSOCIATED 0 ++#define WPS_ASSOC_CONN_SUCCESS 1 ++#define WPS_ASSOC_CONFIG_FAIL 2 ++#define WPS_ASSOC_ASSOC_FAIL 3 ++#define WPS_ASSOC_IP_FAIL 4 ++ ++/* Authentication types */ ++#define WPS_AUTHTYPE_OPEN 0x0001 ++#define WPS_AUTHTYPE_WPAPSK 0x0002 /* Deprecated in WSC 2.0 */ ++#define WPS_AUTHTYPE_SHARED 0x0004 /* Deprecated in WSC 2.0 */ ++#define WPS_AUTHTYPE_WPA 0x0008 /* Deprecated in WSC 2.0 */ ++#define WPS_AUTHTYPE_WPA2 0x0010 ++#define WPS_AUTHTYPE_WPA2PSK 0x0020 ++ ++/* Config methods */ ++#define WPS_CONFMET_USBA 0x0001 /* Deprecated in WSC 2.0 */ ++#define WPS_CONFMET_ETHERNET 0x0002 /* Deprecated in WSC 2.0 */ ++#define WPS_CONFMET_LABEL 0x0004 ++#define WPS_CONFMET_DISPLAY 0x0008 ++#define WPS_CONFMET_EXT_NFC_TOK 0x0010 ++#define WPS_CONFMET_INT_NFC_TOK 0x0020 ++#define WPS_CONFMET_NFC_INTF 0x0040 ++#define WPS_CONFMET_PBC 0x0080 ++#define WPS_CONFMET_KEYPAD 0x0100 ++/* WSC 2.0 */ ++#define WPS_CONFMET_VIRT_PBC 0x0280 ++#define WPS_CONFMET_PHY_PBC 0x0480 ++#define WPS_CONFMET_VIRT_DISPLAY 0x2008 ++#define WPS_CONFMET_PHY_DISPLAY 0x4008 ++ ++/* WPS error messages */ ++#define WPS_ERROR_NO_ERROR 0 ++#define WPS_ERROR_OOB_INT_READ_ERR 1 ++#define WPS_ERROR_DECRYPT_CRC_FAIL 2 ++#define WPS_ERROR_CHAN24_NOT_SUPP 3 ++#define WPS_ERROR_CHAN50_NOT_SUPP 4 ++#define WPS_ERROR_SIGNAL_WEAK 5 /* Deprecated in WSC 2.0 */ ++#define WPS_ERROR_NW_AUTH_FAIL 6 /* Deprecated in WSC 2.0 */ ++#define WPS_ERROR_NW_ASSOC_FAIL 7 /* Deprecated in WSC 2.0 */ ++#define WPS_ERROR_NO_DHCP_RESP 8 /* Deprecated in WSC 2.0 */ ++#define WPS_ERROR_FAILED_DHCP_CONF 9 /* Deprecated in WSC 2.0 */ ++#define WPS_ERROR_IP_ADDR_CONFLICT 10 /* Deprecated in WSC 2.0 */ ++#define WPS_ERROR_FAIL_CONN_REGISTRAR 11 ++#define WPS_ERROR_MULTI_PBC_DETECTED 12 ++#define WPS_ERROR_ROGUE_SUSPECTED 13 ++#define WPS_ERROR_DEVICE_BUSY 14 ++#define WPS_ERROR_SETUP_LOCKED 15 ++#define WPS_ERROR_MSG_TIMEOUT 16 /* Deprecated in WSC 2.0 */ ++#define WPS_ERROR_REG_SESSION_TIMEOUT 17 /* Deprecated in WSC 2.0 */ ++#define WPS_ERROR_DEV_PWD_AUTH_FAIL 18 ++#define WPS_ERROR_60GHZ_NOT_SUPPORT 19 ++#define WPS_ERROR_PKH_MISMATCH 20 /* Public Key Hash Mismatch */ ++ ++/* Connection types */ ++#define WPS_CONNTYPE_ESS 0x01 ++#define WPS_CONNTYPE_IBSS 0x02 ++ ++/* Device password ID */ ++#define WPS_DEVICEPWDID_DEFAULT 0x0000 ++#define WPS_DEVICEPWDID_USER_SPEC 0x0001 ++#define WPS_DEVICEPWDID_MACHINE_SPEC 0x0002 ++#define WPS_DEVICEPWDID_REKEY 0x0003 ++#define WPS_DEVICEPWDID_PUSH_BTN 0x0004 ++#define WPS_DEVICEPWDID_REG_SPEC 0x0005 ++#define WPS_DEVICEPWDID_IBSS 0x0006 ++#define WPS_DEVICEPWDID_NFC_CHO 0x0007 /* NFC-Connection-Handover */ ++#define WPS_DEVICEPWDID_WFDS 0x0008 /* Wi-Fi Direct Services Specification */ ++ ++/* Encryption type */ ++#define WPS_ENCRTYPE_NONE 0x0001 ++#define WPS_ENCRTYPE_WEP 0x0002 /* Deprecated in WSC 2.0 */ ++#define WPS_ENCRTYPE_TKIP 0x0004 /* Deprecated in version 2.0. TKIP can only ++ * be advertised on the AP when Mixed Mode ++ * is enabled (Encryption Type is 0x000c). ++ */ ++#define WPS_ENCRTYPE_AES 0x0008 ++ ++ ++/* WPS Message Types */ ++#define WPS_ID_BEACON 0x01 ++#define WPS_ID_PROBE_REQ 0x02 ++#define WPS_ID_PROBE_RESP 0x03 ++#define WPS_ID_MESSAGE_M1 0x04 ++#define WPS_ID_MESSAGE_M2 0x05 ++#define WPS_ID_MESSAGE_M2D 0x06 ++#define WPS_ID_MESSAGE_M3 0x07 ++#define WPS_ID_MESSAGE_M4 0x08 ++#define WPS_ID_MESSAGE_M5 0x09 ++#define WPS_ID_MESSAGE_M6 0x0A ++#define WPS_ID_MESSAGE_M7 0x0B ++#define WPS_ID_MESSAGE_M8 0x0C ++#define WPS_ID_MESSAGE_ACK 0x0D ++#define WPS_ID_MESSAGE_NACK 0x0E ++#define WPS_ID_MESSAGE_DONE 0x0F ++ ++/* WSP private ID for local use */ ++#define WPS_PRIVATE_ID_IDENTITY (WPS_ID_MESSAGE_DONE + 1) ++#define WPS_PRIVATE_ID_WPS_START (WPS_ID_MESSAGE_DONE + 2) ++#define WPS_PRIVATE_ID_FAILURE (WPS_ID_MESSAGE_DONE + 3) ++#define WPS_PRIVATE_ID_FRAG (WPS_ID_MESSAGE_DONE + 4) ++#define WPS_PRIVATE_ID_FRAG_ACK (WPS_ID_MESSAGE_DONE + 5) ++#define WPS_PRIVATE_ID_EAPOL_START (WPS_ID_MESSAGE_DONE + 6) ++ ++ ++/* Device Type categories for primary and secondary device types */ ++#define WPS_DEVICE_TYPE_CAT_COMPUTER 1 ++#define WPS_DEVICE_TYPE_CAT_INPUT_DEVICE 2 ++#define WPS_DEVICE_TYPE_CAT_PRINTER 3 ++#define WPS_DEVICE_TYPE_CAT_CAMERA 4 ++#define WPS_DEVICE_TYPE_CAT_STORAGE 5 ++#define WPS_DEVICE_TYPE_CAT_NW_INFRA 6 ++#define WPS_DEVICE_TYPE_CAT_DISPLAYS 7 ++#define WPS_DEVICE_TYPE_CAT_MM_DEVICES 8 ++#define WPS_DEVICE_TYPE_CAT_GAME_DEVICES 9 ++#define WPS_DEVICE_TYPE_CAT_TELEPHONE 10 ++#define WPS_DEVICE_TYPE_CAT_AUDIO_DEVICES 11 /* WSC 2.0 */ ++ ++/* Device Type sub categories for primary and secondary device types */ ++#define WPS_DEVICE_TYPE_SUB_CAT_COMP_PC 1 ++#define WPS_DEVICE_TYPE_SUB_CAT_COMP_SERVER 2 ++#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MEDIA_CTR 3 ++#define WPS_DEVICE_TYPE_SUB_CAT_COMP_UM_PC 4 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NOTEBOOK 5 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_COMP_DESKTOP 6 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_COMP_MID 7 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_COMP_NETBOOK 8 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_INP_Keyboard 1 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_INP_MOUSE 2 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_INP_JOYSTICK 3 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_INP_TRACKBALL 4 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_INP_GAM_CTRL 5 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_INP_REMOTE 6 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_INP_TOUCHSCREEN 7 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_INP_BIO_READER 8 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_INP_BAR_READER 9 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_PRINTER 1 ++#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_SCANNER 2 ++#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_FAX 3 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_COPIER 4 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_PRTR_ALLINONE 5 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_CAM_DGTL_STILL 1 ++#define WPS_DEVICE_TYPE_SUB_CAT_CAM_VIDEO_CAM 2 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_CAM_WEB_CAM 3 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_CAM_SECU_CAM 4 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_STOR_NAS 1 ++#define WPS_DEVICE_TYPE_SUB_CAT_NW_AP 1 ++#define WPS_DEVICE_TYPE_SUB_CAT_NW_ROUTER 2 ++#define WPS_DEVICE_TYPE_SUB_CAT_NW_SWITCH 3 ++#define WPS_DEVICE_TYPE_SUB_CAT_NW_GATEWAY 4 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_NW_BRIDGE 5 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_DISP_TV 1 ++#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PIC_FRAME 2 ++#define WPS_DEVICE_TYPE_SUB_CAT_DISP_PROJECTOR 3 ++#define WPS_DEVICE_TYPE_SUB_CAT_DISP_MONITOR 4 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_MM_DAR 1 ++#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVR 2 ++#define WPS_DEVICE_TYPE_SUB_CAT_MM_MCX 3 ++#define WPS_DEVICE_TYPE_SUB_CAT_MM_STB 4 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_MM_MS_ME 5 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_MM_PVP 6 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX 1 ++#define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX_360 2 ++#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PS 3 ++#define WPS_DEVICE_TYPE_SUB_CAT_GAM_GC 4 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_GAM_PGD 5 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_WM 1 ++#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PSM 2 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_PDM 3 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SSM 4 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_PHONE_SDM 5 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_TUNER 1 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_SPEAKERS 2 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_PMP 3 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HEADSET 4 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HPHONE 5 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_MPHONE 6 /* WSC 2.0 */ ++#define WPS_DEVICE_TYPE_SUB_CAT_AUDIO_HTS 7 /* WSC 2.0 */ ++ ++ ++/* Device request/response type */ ++#define WPS_MSGTYPE_ENROLLEE_INFO_ONLY 0x00 ++#define WPS_MSGTYPE_ENROLLEE_OPEN_8021X 0x01 ++#define WPS_MSGTYPE_REGISTRAR 0x02 ++#define WPS_MSGTYPE_AP_WLAN_MGR 0x03 ++ ++/* RF Band */ ++#define WPS_RFBAND_24GHZ 0x01 ++#define WPS_RFBAND_50GHZ 0x02 ++ ++/* Simple Config state */ ++#define WPS_SCSTATE_UNCONFIGURED 0x01 ++#define WPS_SCSTATE_CONFIGURED 0x02 ++#define WPS_SCSTATE_OFF 11 ++ ++/* WPS Vendor extension key */ ++#define WPS_OUI_HEADER_LEN 2 ++#define WPS_OUI_HEADER_SIZE 4 ++#define WPS_OUI_FIXED_HEADER_OFF 16 ++#define WPS_WFA_SUBID_V2_OFF 3 ++#define WPS_WFA_V2_OFF 5 ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _WPS_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/linux_osl.c b/module_drivers/drivers/net/wireless/bcmdhd/linux_osl.c +new file mode 100644 +index 000000000..5c4cc8bf5 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/linux_osl.c +@@ -0,0 +1,2842 @@ ++/* ++ * Linux OS Independent Layer ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: linux_osl.c 680580 2017-01-20 11:49:58Z $ ++ */ ++ ++#define LINUX_PORT ++ ++#include ++#include ++#include ++#include ++ ++ ++#if !defined(STBLINUX) ++#if defined(__ARM_ARCH_7A__) && !defined(DHD_USE_COHERENT_MEM_FOR_RING) ++#include ++#endif /* __ARM_ARCH_7A__ && !DHD_USE_COHERENT_MEM_FOR_RING */ ++#endif /* STBLINUX */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 8, 0)) ++#include ++#endif ++ ++ ++#ifdef BCM_SECURE_DMA ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif /* BCM_SECURE_DMA */ ++ ++#include ++ ++#if defined(STB) ++#include ++extern spinlock_t l2x0_reg_lock; ++#endif ++ ++#ifdef BCM_OBJECT_TRACE ++#include ++#endif /* BCM_OBJECT_TRACE */ ++ ++#define PCI_CFG_RETRY 10 ++ ++#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */ ++#define BCM_MEM_FILENAME_LEN 24 /* Mem. filename length */ ++#define DUMPBUFSZ 1024 ++ ++/* dependancy check */ ++#if !defined(BCMPCIE) && defined(DHD_USE_STATIC_CTRLBUF) ++#error "DHD_USE_STATIC_CTRLBUF suppored PCIE target only" ++#endif /* !BCMPCIE && DHD_USE_STATIC_CTRLBUF */ ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++#ifdef DHD_USE_STATIC_CTRLBUF ++#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE*1) ++#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE*2) ++#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE*4) ++ ++#define PREALLOC_FREE_MAGIC 0xFEDC ++#define PREALLOC_USED_MAGIC 0xFCDE ++#else ++#define DHD_SKB_HDRSIZE 336 ++#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE) ++#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE) ++#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE) ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ ++#define STATIC_BUF_MAX_NUM 16 ++#define STATIC_BUF_SIZE (PAGE_SIZE*2) ++#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) ++ ++typedef struct bcm_static_buf { ++ spinlock_t static_lock; ++ unsigned char *buf_ptr; ++ unsigned char buf_use[STATIC_BUF_MAX_NUM]; ++} bcm_static_buf_t; ++ ++static bcm_static_buf_t *bcm_static_buf = 0; ++ ++#ifdef DHD_USE_STATIC_CTRLBUF ++#define STATIC_PKT_4PAGE_NUM 0 ++#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE ++#elif defined(ENHANCED_STATIC_BUF) ++#define STATIC_PKT_4PAGE_NUM 1 ++#define DHD_SKB_MAX_BUFSIZE DHD_SKB_4PAGE_BUFSIZE ++#else ++#define STATIC_PKT_4PAGE_NUM 0 ++#define DHD_SKB_MAX_BUFSIZE DHD_SKB_2PAGE_BUFSIZE ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ ++#ifdef DHD_USE_STATIC_CTRLBUF ++#define STATIC_PKT_1PAGE_NUM 0 ++#define STATIC_PKT_2PAGE_NUM 128 ++#else ++#define STATIC_PKT_1PAGE_NUM 8 ++#define STATIC_PKT_2PAGE_NUM 8 ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ ++#define STATIC_PKT_1_2PAGE_NUM \ ++ ((STATIC_PKT_1PAGE_NUM) + (STATIC_PKT_2PAGE_NUM)) ++#define STATIC_PKT_MAX_NUM \ ++ ((STATIC_PKT_1_2PAGE_NUM) + (STATIC_PKT_4PAGE_NUM)) ++ ++typedef struct bcm_static_pkt { ++#ifdef DHD_USE_STATIC_CTRLBUF ++ struct sk_buff *skb_8k[STATIC_PKT_2PAGE_NUM]; ++ unsigned char pkt_invalid[STATIC_PKT_2PAGE_NUM]; ++ spinlock_t osl_pkt_lock; ++ uint32 last_allocated_index; ++#else ++ struct sk_buff *skb_4k[STATIC_PKT_1PAGE_NUM]; ++ struct sk_buff *skb_8k[STATIC_PKT_2PAGE_NUM]; ++#ifdef ENHANCED_STATIC_BUF ++ struct sk_buff *skb_16k; ++#endif /* ENHANCED_STATIC_BUF */ ++ struct semaphore osl_pkt_sem; ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ unsigned char pkt_use[STATIC_PKT_MAX_NUM]; ++} bcm_static_pkt_t; ++ ++static bcm_static_pkt_t *bcm_static_skb = 0; ++ ++void* wifi_platform_prealloc(void *adapter, int section, unsigned long size); ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++typedef struct bcm_mem_link { ++ struct bcm_mem_link *prev; ++ struct bcm_mem_link *next; ++ uint size; ++ int line; ++ void *osh; ++ char file[BCM_MEM_FILENAME_LEN]; ++} bcm_mem_link_t; ++ ++struct osl_cmn_info { ++ atomic_t malloced; ++ atomic_t pktalloced; /* Number of allocated packet buffers */ ++ spinlock_t dbgmem_lock; ++ bcm_mem_link_t *dbgmem_list; ++ bcm_mem_link_t *dbgvmem_list; ++ spinlock_t pktalloc_lock; ++ atomic_t refcount; /* Number of references to this shared structure. */ ++}; ++typedef struct osl_cmn_info osl_cmn_t; ++ ++struct osl_info { ++ osl_pubinfo_t pub; ++ uint32 flags; /* If specific cases to be handled in the OSL */ ++#ifdef CTFPOOL ++ ctfpool_t *ctfpool; ++#endif /* CTFPOOL */ ++ uint magic; ++ void *pdev; ++ uint failed; ++ uint bustype; ++ osl_cmn_t *cmn; /* Common OSL related data shred between two OSH's */ ++ ++ void *bus_handle; ++#ifdef BCMDBG_CTRACE ++ spinlock_t ctrace_lock; ++ struct list_head ctrace_list; ++ int ctrace_num; ++#endif /* BCMDBG_CTRACE */ ++#ifdef BCM_SECURE_DMA ++ struct sec_mem_elem *sec_list_4096; ++ struct sec_mem_elem *sec_list_base_4096; ++ phys_addr_t contig_base; ++ void *contig_base_va; ++ phys_addr_t contig_base_alloc; ++ void *contig_base_alloc_va; ++ phys_addr_t contig_base_alloc_coherent; ++ void *contig_base_alloc_coherent_va; ++ void *contig_base_coherent_va; ++ void *contig_delta_va_pa; ++ struct { ++ phys_addr_t pa; ++ void *va; ++ bool avail; ++ } sec_cma_coherent[SEC_CMA_COHERENT_MAX]; ++ int stb_ext_params; ++#endif /* BCM_SECURE_DMA */ ++}; ++#ifdef BCM_SECURE_DMA ++static void * osl_sec_dma_ioremap(osl_t *osh, struct page *page, size_t size, ++ bool iscache, bool isdecr); ++static void osl_sec_dma_iounmap(osl_t *osh, void *contig_base_va, size_t size); ++static int osl_sec_dma_init_elem_mem_block(osl_t *osh, size_t mbsize, int max, ++ sec_mem_elem_t **list); ++static void osl_sec_dma_deinit_elem_mem_block(osl_t *osh, size_t mbsize, int max, ++ void *sec_list_base); ++static sec_mem_elem_t * osl_sec_dma_alloc_mem_elem(osl_t *osh, void *va, uint size, ++ int direction, struct sec_cma_info *ptr_cma_info, uint offset); ++static void osl_sec_dma_free_mem_elem(osl_t *osh, sec_mem_elem_t *sec_mem_elem); ++static void osl_sec_dma_init_consistent(osl_t *osh); ++static void *osl_sec_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, ++ ulong *pap); ++static void osl_sec_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa); ++#endif /* BCM_SECURE_DMA */ ++ ++#ifdef BCM_OBJECT_TRACE ++/* don't clear the first 4 byte that is the pkt sn */ ++#define OSL_PKTTAG_CLEAR(p) \ ++do { \ ++ struct sk_buff *s = (struct sk_buff *)(p); \ ++ ASSERT(OSL_PKTTAG_SZ == 32); \ ++ *(uint32 *)(&s->cb[4]) = 0; \ ++ *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ ++ *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ ++ *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ ++} while (0) ++#else ++#define OSL_PKTTAG_CLEAR(p) \ ++do { \ ++ struct sk_buff *s = (struct sk_buff *)(p); \ ++ ASSERT(OSL_PKTTAG_SZ == 32); \ ++ *(uint32 *)(&s->cb[0]) = 0; *(uint32 *)(&s->cb[4]) = 0; \ ++ *(uint32 *)(&s->cb[8]) = 0; *(uint32 *)(&s->cb[12]) = 0; \ ++ *(uint32 *)(&s->cb[16]) = 0; *(uint32 *)(&s->cb[20]) = 0; \ ++ *(uint32 *)(&s->cb[24]) = 0; *(uint32 *)(&s->cb[28]) = 0; \ ++} while (0) ++#endif /* BCM_OBJECT_TRACE */ ++ ++/* PCMCIA attribute space access macros */ ++ ++uint32 g_assert_type = 0; /* By Default Kernel Panic */ ++ ++module_param(g_assert_type, int, 0); ++#ifdef BCM_SECURE_DMA ++#define SECDMA_MODULE_PARAMS 0 ++#define SECDMA_EXT_FILE 1 ++unsigned long secdma_addr = 0; ++unsigned long secdma_addr2 = 0; ++u32 secdma_size = 0; ++u32 secdma_size2 = 0; ++module_param(secdma_addr, ulong, 0); ++module_param(secdma_size, int, 0); ++module_param(secdma_addr2, ulong, 0); ++module_param(secdma_size2, int, 0); ++static int secdma_found = 0; ++#endif /* BCM_SECURE_DMA */ ++ ++static int16 linuxbcmerrormap[] = ++{ 0, /* 0 */ ++ -EINVAL, /* BCME_ERROR */ ++ -EINVAL, /* BCME_BADARG */ ++ -EINVAL, /* BCME_BADOPTION */ ++ -EINVAL, /* BCME_NOTUP */ ++ -EINVAL, /* BCME_NOTDOWN */ ++ -EINVAL, /* BCME_NOTAP */ ++ -EINVAL, /* BCME_NOTSTA */ ++ -EINVAL, /* BCME_BADKEYIDX */ ++ -EINVAL, /* BCME_RADIOOFF */ ++ -EINVAL, /* BCME_NOTBANDLOCKED */ ++ -EINVAL, /* BCME_NOCLK */ ++ -EINVAL, /* BCME_BADRATESET */ ++ -EINVAL, /* BCME_BADBAND */ ++ -E2BIG, /* BCME_BUFTOOSHORT */ ++ -E2BIG, /* BCME_BUFTOOLONG */ ++ -EBUSY, /* BCME_BUSY */ ++ -EINVAL, /* BCME_NOTASSOCIATED */ ++ -EINVAL, /* BCME_BADSSIDLEN */ ++ -EINVAL, /* BCME_OUTOFRANGECHAN */ ++ -EINVAL, /* BCME_BADCHAN */ ++ -EFAULT, /* BCME_BADADDR */ ++ -ENOMEM, /* BCME_NORESOURCE */ ++ -EOPNOTSUPP, /* BCME_UNSUPPORTED */ ++ -EMSGSIZE, /* BCME_BADLENGTH */ ++ -EINVAL, /* BCME_NOTREADY */ ++ -EPERM, /* BCME_EPERM */ ++ -ENOMEM, /* BCME_NOMEM */ ++ -EINVAL, /* BCME_ASSOCIATED */ ++ -ERANGE, /* BCME_RANGE */ ++ -EINVAL, /* BCME_NOTFOUND */ ++ -EINVAL, /* BCME_WME_NOT_ENABLED */ ++ -EINVAL, /* BCME_TSPEC_NOTFOUND */ ++ -EINVAL, /* BCME_ACM_NOTSUPPORTED */ ++ -EINVAL, /* BCME_NOT_WME_ASSOCIATION */ ++ -EIO, /* BCME_SDIO_ERROR */ ++ -ENODEV, /* BCME_DONGLE_DOWN */ ++ -EINVAL, /* BCME_VERSION */ ++ -EIO, /* BCME_TXFAIL */ ++ -EIO, /* BCME_RXFAIL */ ++ -ENODEV, /* BCME_NODEVICE */ ++ -EINVAL, /* BCME_NMODE_DISABLED */ ++ -ENODATA, /* BCME_NONRESIDENT */ ++ -EINVAL, /* BCME_SCANREJECT */ ++ -EINVAL, /* BCME_USAGE_ERROR */ ++ -EIO, /* BCME_IOCTL_ERROR */ ++ -EIO, /* BCME_SERIAL_PORT_ERR */ ++ -EOPNOTSUPP, /* BCME_DISABLED, BCME_NOTENABLED */ ++ -EIO, /* BCME_DECERR */ ++ -EIO, /* BCME_ENCERR */ ++ -EIO, /* BCME_MICERR */ ++ -ERANGE, /* BCME_REPLAY */ ++ -EINVAL, /* BCME_IE_NOTFOUND */ ++ -EINVAL, /* BCME_DATA_NOTFOUND */ ++ -EINVAL, /* BCME_NOT_GC */ ++ -EINVAL, /* BCME_PRS_REQ_FAILED */ ++ -EINVAL, /* BCME_NO_P2P_SE */ ++ -EINVAL, /* BCME_NOA_PND */ ++ -EINVAL, /* BCME_FRAG_Q_FAILED */ ++ -EINVAL, /* BCME_GET_AF_FAILED */ ++ -EINVAL, /* BCME_MSCH_NOTREADY */ ++ ++/* When an new error code is added to bcmutils.h, add os ++ * specific error translation here as well ++ */ ++/* check if BCME_LAST changed since the last time this function was updated */ ++#if BCME_LAST != -60 ++#error "You need to add a OS error translation in the linuxbcmerrormap \ ++ for new error code defined in bcmutils.h" ++#endif ++}; ++uint lmtest = FALSE; ++ ++/* translate bcmerrors into linux errors */ ++int ++osl_error(int bcmerror) ++{ ++ if (bcmerror > 0) ++ bcmerror = 0; ++ else if (bcmerror < BCME_LAST) ++ bcmerror = BCME_ERROR; ++ ++ /* Array bounds covered by ASSERT in osl_attach */ ++ return linuxbcmerrormap[-bcmerror]; ++} ++ ++osl_t * ++#ifdef SHARED_OSL_CMN ++osl_attach(void *pdev, uint bustype, bool pkttag, void **osl_cmn) ++#else ++osl_attach(void *pdev, uint bustype, bool pkttag) ++#endif /* SHARED_OSL_CMN */ ++{ ++#ifndef SHARED_OSL_CMN ++ void **osl_cmn = NULL; ++#endif /* SHARED_OSL_CMN */ ++ osl_t *osh; ++ gfp_t flags; ++#ifdef BCM_SECURE_DMA ++ u32 secdma_memsize; ++#endif ++ ++ flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; ++ if (!(osh = kmalloc(sizeof(osl_t), flags))) ++ return osh; ++ ++ ASSERT(osh); ++ ++ bzero(osh, sizeof(osl_t)); ++ ++ if (osl_cmn == NULL || *osl_cmn == NULL) { ++ if (!(osh->cmn = kmalloc(sizeof(osl_cmn_t), flags))) { ++ kfree(osh); ++ return NULL; ++ } ++ bzero(osh->cmn, sizeof(osl_cmn_t)); ++ if (osl_cmn) ++ *osl_cmn = osh->cmn; ++ atomic_set(&osh->cmn->malloced, 0); ++ osh->cmn->dbgmem_list = NULL; ++ spin_lock_init(&(osh->cmn->dbgmem_lock)); ++ ++ spin_lock_init(&(osh->cmn->pktalloc_lock)); ++ ++ } else { ++ osh->cmn = *osl_cmn; ++ } ++ atomic_add(1, &osh->cmn->refcount); ++ ++ bcm_object_trace_init(); ++ ++ /* Check that error map has the right number of entries in it */ ++ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1)); ++ ++ osh->failed = 0; ++ osh->pdev = pdev; ++ osh->pub.pkttag = pkttag; ++ osh->bustype = bustype; ++ osh->magic = OS_HANDLE_MAGIC; ++#ifdef BCM_SECURE_DMA ++ ++ if ((secdma_addr != 0) && (secdma_size != 0)) { ++ printk("linux_osl.c: Buffer info passed via module params, using it.\n"); ++ if (secdma_found == 0) { ++ osh->contig_base_alloc = (phys_addr_t)secdma_addr; ++ secdma_memsize = secdma_size; ++ } else if (secdma_found == 1) { ++ osh->contig_base_alloc = (phys_addr_t)secdma_addr2; ++ secdma_memsize = secdma_size2; ++ } else { ++ printk("linux_osl.c secdma: secDMA instances %d \n", secdma_found); ++ kfree(osh); ++ return NULL; ++ } ++ osh->contig_base = (phys_addr_t)osh->contig_base_alloc; ++ printf("linux_osl.c: secdma_cma_size = 0x%x\n", secdma_memsize); ++ printf("linux_osl.c: secdma_cma_addr = 0x%x \n", ++ (unsigned int)osh->contig_base_alloc); ++ osh->stb_ext_params = SECDMA_MODULE_PARAMS; ++ } ++ else if (stbpriv_init(osh) == 0) { ++ printk("linux_osl.c: stbpriv.txt found. Get buffer info.\n"); ++ if (secdma_found == 0) { ++ osh->contig_base_alloc = ++ (phys_addr_t)bcm_strtoul(stbparam_get("secdma_cma_addr"), NULL, 0); ++ secdma_memsize = bcm_strtoul(stbparam_get("secdma_cma_size"), NULL, 0); ++ } else if (secdma_found == 1) { ++ osh->contig_base_alloc = ++ (phys_addr_t)bcm_strtoul(stbparam_get("secdma_cma_addr2"), NULL, 0); ++ secdma_memsize = bcm_strtoul(stbparam_get("secdma_cma_size2"), NULL, 0); ++ } else { ++ printk("linux_osl.c secdma: secDMA instances %d \n", secdma_found); ++ kfree(osh); ++ return NULL; ++ } ++ osh->contig_base = (phys_addr_t)osh->contig_base_alloc; ++ printf("linux_osl.c: secdma_cma_size = 0x%x\n", secdma_memsize); ++ printf("linux_osl.c: secdma_cma_addr = 0x%x \n", ++ (unsigned int)osh->contig_base_alloc); ++ osh->stb_ext_params = SECDMA_EXT_FILE; ++ } ++ else { ++ printk("linux_osl.c: secDMA no longer supports internal buffer allocation.\n"); ++ kfree(osh); ++ return NULL; ++ } ++ secdma_found++; ++ osh->contig_base_alloc_coherent_va = osl_sec_dma_ioremap(osh, ++ phys_to_page((u32)osh->contig_base_alloc), ++ CMA_DMA_DESC_MEMBLOCK, FALSE, TRUE); ++ ++ if (osh->contig_base_alloc_coherent_va == NULL) { ++ if (osh->cmn) ++ kfree(osh->cmn); ++ kfree(osh); ++ return NULL; ++ } ++ osh->contig_base_coherent_va = osh->contig_base_alloc_coherent_va; ++ osh->contig_base_alloc_coherent = osh->contig_base_alloc; ++ osl_sec_dma_init_consistent(osh); ++ ++ osh->contig_base_alloc += CMA_DMA_DESC_MEMBLOCK; ++ ++ osh->contig_base_alloc_va = osl_sec_dma_ioremap(osh, ++ phys_to_page((u32)osh->contig_base_alloc), CMA_DMA_DATA_MEMBLOCK, TRUE, FALSE); ++ if (osh->contig_base_alloc_va == NULL) { ++ osl_sec_dma_iounmap(osh, osh->contig_base_coherent_va, CMA_DMA_DESC_MEMBLOCK); ++ if (osh->cmn) ++ kfree(osh->cmn); ++ kfree(osh); ++ return NULL; ++ } ++ osh->contig_base_va = osh->contig_base_alloc_va; ++ ++ if (BCME_OK != osl_sec_dma_init_elem_mem_block(osh, ++ CMA_BUFSIZE_4K, CMA_BUFNUM, &osh->sec_list_4096)) { ++ osl_sec_dma_iounmap(osh, osh->contig_base_coherent_va, CMA_DMA_DESC_MEMBLOCK); ++ osl_sec_dma_iounmap(osh, osh->contig_base_va, CMA_DMA_DATA_MEMBLOCK); ++ if (osh->cmn) ++ kfree(osh->cmn); ++ kfree(osh); ++ return NULL; ++ } ++ osh->sec_list_base_4096 = osh->sec_list_4096; ++ ++#endif /* BCM_SECURE_DMA */ ++ ++ switch (bustype) { ++ case PCI_BUS: ++ case SI_BUS: ++ case PCMCIA_BUS: ++ osh->pub.mmbus = TRUE; ++ break; ++ case JTAG_BUS: ++ case SDIO_BUS: ++ case USB_BUS: ++ case SPI_BUS: ++ case RPC_BUS: ++ osh->pub.mmbus = FALSE; ++ break; ++ default: ++ ASSERT(FALSE); ++ break; ++ } ++ ++#ifdef BCMDBG_CTRACE ++ spin_lock_init(&osh->ctrace_lock); ++ INIT_LIST_HEAD(&osh->ctrace_list); ++ osh->ctrace_num = 0; ++#endif /* BCMDBG_CTRACE */ ++ ++ ++ return osh; ++} ++ ++int osl_static_mem_init(osl_t *osh, void *adapter) ++{ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (!bcm_static_buf && adapter) { ++ if (!(bcm_static_buf = (bcm_static_buf_t *)wifi_platform_prealloc(adapter, ++ DHD_PREALLOC_OSL_BUF, STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) { ++ printk("can not alloc static buf!\n"); ++ bcm_static_skb = NULL; ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ return -ENOMEM; ++ } else { ++ printk("alloc static buf at %p!\n", bcm_static_buf); ++ } ++ ++ spin_lock_init(&bcm_static_buf->static_lock); ++ ++ bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE; ++ } ++ ++#if defined(BCMSDIO) || defined(DHD_USE_STATIC_CTRLBUF) ++ if (!bcm_static_skb && adapter) { ++ int i; ++ void *skb_buff_ptr = 0; ++ bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); ++ skb_buff_ptr = wifi_platform_prealloc(adapter, DHD_PREALLOC_SKB_BUF, 0); ++ if (!skb_buff_ptr) { ++ printk("cannot alloc static buf!\n"); ++ bcm_static_buf = NULL; ++ bcm_static_skb = NULL; ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ return -ENOMEM; ++ } ++ ++ bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * ++ (STATIC_PKT_MAX_NUM)); ++ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { ++ bcm_static_skb->pkt_use[i] = 0; ++ } ++ ++#ifdef DHD_USE_STATIC_CTRLBUF ++ spin_lock_init(&bcm_static_skb->osl_pkt_lock); ++ bcm_static_skb->last_allocated_index = 0; ++#else ++ sema_init(&bcm_static_skb->osl_pkt_sem, 1); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ } ++#endif /* BCMSDIO || DHD_USE_STATIC_CTRLBUF */ ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++ return 0; ++} ++ ++void osl_set_bus_handle(osl_t *osh, void *bus_handle) ++{ ++ osh->bus_handle = bus_handle; ++} ++ ++void* osl_get_bus_handle(osl_t *osh) ++{ ++ return osh->bus_handle; ++} ++ ++void ++osl_detach(osl_t *osh) ++{ ++ if (osh == NULL) ++ return; ++ ++#ifdef BCM_SECURE_DMA ++ if (osh->stb_ext_params == SECDMA_EXT_FILE) ++ stbpriv_exit(osh); ++ osl_sec_dma_deinit_elem_mem_block(osh, CMA_BUFSIZE_4K, CMA_BUFNUM, osh->sec_list_base_4096); ++ osl_sec_dma_iounmap(osh, osh->contig_base_coherent_va, CMA_DMA_DESC_MEMBLOCK); ++ osl_sec_dma_iounmap(osh, osh->contig_base_va, CMA_DMA_DATA_MEMBLOCK); ++ secdma_found--; ++#endif /* BCM_SECURE_DMA */ ++ ++ ++ bcm_object_trace_deinit(); ++ ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ atomic_sub(1, &osh->cmn->refcount); ++ if (atomic_read(&osh->cmn->refcount) == 0) { ++ kfree(osh->cmn); ++ } ++ kfree(osh); ++} ++ ++int osl_static_mem_deinit(osl_t *osh, void *adapter) ++{ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) { ++ bcm_static_buf = 0; ++ } ++#ifdef BCMSDIO ++ if (bcm_static_skb) { ++ bcm_static_skb = 0; ++ } ++#endif /* BCMSDIO */ ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ return 0; ++} ++ ++/* APIs to set/get specific quirks in OSL layer */ ++void BCMFASTPATH ++osl_flag_set(osl_t *osh, uint32 mask) ++{ ++ osh->flags |= mask; ++} ++ ++void ++osl_flag_clr(osl_t *osh, uint32 mask) ++{ ++ osh->flags &= ~mask; ++} ++ ++#if defined(STB) ++inline bool BCMFASTPATH ++#else ++bool ++#endif ++osl_is_flag_set(osl_t *osh, uint32 mask) ++{ ++ return (osh->flags & mask); ++} ++ ++ ++#if (defined(__ARM_ARCH_7A__) && !defined(DHD_USE_COHERENT_MEM_FOR_RING)) ++ ++inline int BCMFASTPATH ++osl_arch_is_coherent(void) ++{ ++ return 0; ++} ++ ++inline int BCMFASTPATH ++osl_acp_war_enab(void) ++{ ++ return 0; ++} ++ ++inline void BCMFASTPATH ++osl_cache_flush(void *va, uint size) ++{ ++ ++ if (size > 0) ++ dma_sync_single_for_device(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_TO_DEVICE); ++} ++ ++inline void BCMFASTPATH ++osl_cache_inv(void *va, uint size) ++{ ++ ++ dma_sync_single_for_cpu(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_FROM_DEVICE); ++} ++ ++inline void BCMFASTPATH ++osl_prefetch(const void *ptr) ++{ ++ __asm__ __volatile__("pld\t%0" :: "o"(*(char *)ptr) : "cc"); ++} ++ ++#endif ++ ++/* ++ * To avoid ACP latency, a fwder buf will be sent directly to DDR using ++ * DDR aliasing into non-ACP address space. Such Fwder buffers must be ++ * explicitly managed from a coherency perspective. ++ */ ++static inline void BCMFASTPATH ++osl_fwderbuf_reset(osl_t *osh, struct sk_buff *skb) ++{ ++} ++ ++static struct sk_buff *osl_alloc_skb(osl_t *osh, unsigned int len) ++{ ++ struct sk_buff *skb; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) ++ gfp_t flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL; ++#ifdef DHD_USE_ATOMIC_PKTGET ++ flags = GFP_ATOMIC; ++#endif /* DHD_USE_ATOMIC_PKTGET */ ++ skb = __dev_alloc_skb(len, flags); ++#else ++ skb = dev_alloc_skb(len); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) */ ++ return skb; ++} ++ ++#ifdef CTFPOOL ++ ++#ifdef CTFPOOL_SPINLOCK ++#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_irqsave(&(ctfpool)->lock, flags) ++#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_irqrestore(&(ctfpool)->lock, flags) ++#else ++#define CTFPOOL_LOCK(ctfpool, flags) spin_lock_bh(&(ctfpool)->lock) ++#define CTFPOOL_UNLOCK(ctfpool, flags) spin_unlock_bh(&(ctfpool)->lock) ++#endif /* CTFPOOL_SPINLOCK */ ++/* ++ * Allocate and add an object to packet pool. ++ */ ++void * ++osl_ctfpool_add(osl_t *osh) ++{ ++ struct sk_buff *skb; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return NULL; ++ ++ CTFPOOL_LOCK(osh->ctfpool, flags); ++ ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj); ++ ++ /* No need to allocate more objects */ ++ if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) { ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ return NULL; ++ } ++ ++ /* Allocate a new skb and add it to the ctfpool */ ++ skb = osl_alloc_skb(osh, osh->ctfpool->obj_size); ++ if (skb == NULL) { ++ printf("%s: skb alloc of len %d failed\n", __FUNCTION__, ++ osh->ctfpool->obj_size); ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ return NULL; ++ } ++ ++ /* Add to ctfpool */ ++ skb->next = (struct sk_buff *)osh->ctfpool->head; ++ osh->ctfpool->head = skb; ++ osh->ctfpool->fast_frees++; ++ osh->ctfpool->curr_obj++; ++ ++ /* Hijack a skb member to store ptr to ctfpool */ ++ CTFPOOLPTR(osh, skb) = (void *)osh->ctfpool; ++ ++ /* Use bit flag to indicate skb from fast ctfpool */ ++ PKTFAST(osh, skb) = FASTBUF; ++ ++ /* If ctfpool's osh is a fwder osh, reset the fwder buf */ ++ osl_fwderbuf_reset(osh->ctfpool->osh, skb); ++ ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ ++ return skb; ++} ++ ++/* ++ * Add new objects to the pool. ++ */ ++void ++osl_ctfpool_replenish(osl_t *osh, uint thresh) ++{ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return; ++ ++ /* Do nothing if no refills are required */ ++ while ((osh->ctfpool->refills > 0) && (thresh--)) { ++ osl_ctfpool_add(osh); ++ osh->ctfpool->refills--; ++ } ++} ++ ++/* ++ * Initialize the packet pool with specified number of objects. ++ */ ++int32 ++osl_ctfpool_init(osl_t *osh, uint numobj, uint size) ++{ ++ gfp_t flags; ++ ++ flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; ++ osh->ctfpool = kzalloc(sizeof(ctfpool_t), flags); ++ ASSERT(osh->ctfpool); ++ ++ osh->ctfpool->osh = osh; ++ ++ osh->ctfpool->max_obj = numobj; ++ osh->ctfpool->obj_size = size; ++ ++ spin_lock_init(&osh->ctfpool->lock); ++ ++ while (numobj--) { ++ if (!osl_ctfpool_add(osh)) ++ return -1; ++ osh->ctfpool->fast_frees--; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Cleanup the packet pool objects. ++ */ ++void ++osl_ctfpool_cleanup(osl_t *osh) ++{ ++ struct sk_buff *skb, *nskb; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return; ++ ++ CTFPOOL_LOCK(osh->ctfpool, flags); ++ ++ skb = osh->ctfpool->head; ++ ++ while (skb != NULL) { ++ nskb = skb->next; ++ dev_kfree_skb(skb); ++ skb = nskb; ++ osh->ctfpool->curr_obj--; ++ } ++ ++ ASSERT(osh->ctfpool->curr_obj == 0); ++ osh->ctfpool->head = NULL; ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ ++ kfree(osh->ctfpool); ++ osh->ctfpool = NULL; ++} ++ ++void ++osl_ctfpool_stats(osl_t *osh, void *b) ++{ ++ struct bcmstrbuf *bb; ++ ++ if ((osh == NULL) || (osh->ctfpool == NULL)) ++ return; ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) { ++ bcm_static_buf = 0; ++ } ++#ifdef BCMSDIO ++ if (bcm_static_skb) { ++ bcm_static_skb = 0; ++ } ++#endif /* BCMSDIO */ ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++ bb = b; ++ ++ ASSERT((osh != NULL) && (bb != NULL)); ++ ++ bcm_bprintf(bb, "max_obj %d obj_size %d curr_obj %d refills %d\n", ++ osh->ctfpool->max_obj, osh->ctfpool->obj_size, ++ osh->ctfpool->curr_obj, osh->ctfpool->refills); ++ bcm_bprintf(bb, "fast_allocs %d fast_frees %d slow_allocs %d\n", ++ osh->ctfpool->fast_allocs, osh->ctfpool->fast_frees, ++ osh->ctfpool->slow_allocs); ++} ++ ++static inline struct sk_buff * ++osl_pktfastget(osl_t *osh, uint len) ++{ ++ struct sk_buff *skb; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++ /* Try to do fast allocate. Return null if ctfpool is not in use ++ * or if there are no items in the ctfpool. ++ */ ++ if (osh->ctfpool == NULL) ++ return NULL; ++ ++ CTFPOOL_LOCK(osh->ctfpool, flags); ++ if (osh->ctfpool->head == NULL) { ++ ASSERT(osh->ctfpool->curr_obj == 0); ++ osh->ctfpool->slow_allocs++; ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ return NULL; ++ } ++ ++ if (len > osh->ctfpool->obj_size) { ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ return NULL; ++ } ++ ++ ASSERT(len <= osh->ctfpool->obj_size); ++ ++ /* Get an object from ctfpool */ ++ skb = (struct sk_buff *)osh->ctfpool->head; ++ osh->ctfpool->head = (void *)skb->next; ++ ++ osh->ctfpool->fast_allocs++; ++ osh->ctfpool->curr_obj--; ++ ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head); ++ CTFPOOL_UNLOCK(osh->ctfpool, flags); ++ ++ /* Init skb struct */ ++ skb->next = skb->prev = NULL; ++#if defined(__ARM_ARCH_7A__) ++ skb->data = skb->head + NET_SKB_PAD; ++ skb->tail = skb->head + NET_SKB_PAD; ++#else ++ skb->data = skb->head + 16; ++ skb->tail = skb->head + 16; ++#endif /* __ARM_ARCH_7A__ */ ++ skb->len = 0; ++ skb->cloned = 0; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) ++ skb->list = NULL; ++#endif ++ atomic_set(&skb->users, 1); ++ ++ PKTSETCLINK(skb, NULL); ++ PKTCCLRATTR(skb); ++ PKTFAST(osh, skb) &= ~(CTFBUF | SKIPCT | CHAINED); ++ ++ return skb; ++} ++#endif /* CTFPOOL */ ++ ++#if defined(BCM_GMAC3) ++/* Account for a packet delivered to downstream forwarder. ++ * Decrement a GMAC forwarder interface's pktalloced count. ++ */ ++void BCMFASTPATH ++osl_pkt_tofwder(osl_t *osh, void *skbs, int skb_cnt) ++{ ++ ++ atomic_sub(skb_cnt, &osh->cmn->pktalloced); ++} ++ ++/* Account for a downstream forwarder delivered packet to a WL/DHD driver. ++ * Increment a GMAC forwarder interface's pktalloced count. ++ */ ++void BCMFASTPATH ++#ifdef BCMDBG_CTRACE ++osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt, int line, char *file) ++#else ++osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt) ++#endif /* BCMDBG_CTRACE */ ++{ ++#if defined(BCMDBG_CTRACE) ++ int i; ++ struct sk_buff *skb; ++#endif ++ ++#if defined(BCMDBG_CTRACE) ++ if (skb_cnt > 1) { ++ struct sk_buff **skb_array = (struct sk_buff **)skbs; ++ for (i = 0; i < skb_cnt; i++) { ++ skb = skb_array[i]; ++#if defined(BCMDBG_CTRACE) ++ ASSERT(!PKTISCHAINED(skb)); ++ ADD_CTRACE(osh, skb, file, line); ++#endif /* BCMDBG_CTRACE */ ++ } ++ } else { ++ skb = (struct sk_buff *)skbs; ++#if defined(BCMDBG_CTRACE) ++ ASSERT(!PKTISCHAINED(skb)); ++ ADD_CTRACE(osh, skb, file, line); ++#endif /* BCMDBG_CTRACE */ ++ } ++#endif ++ ++ atomic_add(skb_cnt, &osh->cmn->pktalloced); ++} ++ ++#endif /* BCM_GMAC3 */ ++ ++/* Convert a driver packet to native(OS) packet ++ * In the process, packettag is zeroed out before sending up ++ * IP code depends on skb->cb to be setup correctly with various options ++ * In our case, that means it should be 0 ++ */ ++struct sk_buff * BCMFASTPATH ++osl_pkt_tonative(osl_t *osh, void *pkt) ++{ ++ struct sk_buff *nskb; ++#ifdef BCMDBG_CTRACE ++ struct sk_buff *nskb1, *nskb2; ++#endif ++ ++ if (osh->pub.pkttag) ++ OSL_PKTTAG_CLEAR(pkt); ++ ++ /* Decrement the packet counter */ ++ for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) { ++ atomic_sub(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->cmn->pktalloced); ++ ++#ifdef BCMDBG_CTRACE ++ for (nskb1 = nskb; nskb1 != NULL; nskb1 = nskb2) { ++ if (PKTISCHAINED(nskb1)) { ++ nskb2 = PKTCLINK(nskb1); ++ } else { ++ nskb2 = NULL; ++ } ++ ++ DEL_CTRACE(osh, nskb1); ++ } ++#endif /* BCMDBG_CTRACE */ ++ } ++ return (struct sk_buff *)pkt; ++} ++ ++/* Convert a native(OS) packet to driver packet. ++ * In the process, native packet is destroyed, there is no copying ++ * Also, a packettag is zeroed out ++ */ ++void * BCMFASTPATH ++#ifdef BCMDBG_CTRACE ++osl_pkt_frmnative(osl_t *osh, void *pkt, int line, char *file) ++#else ++osl_pkt_frmnative(osl_t *osh, void *pkt) ++#endif /* BCMDBG_CTRACE */ ++{ ++ struct sk_buff *cskb; ++ struct sk_buff *nskb; ++ unsigned long pktalloced = 0; ++ ++ if (osh->pub.pkttag) ++ OSL_PKTTAG_CLEAR(pkt); ++ ++ /* walk the PKTCLINK() list */ ++ for (cskb = (struct sk_buff *)pkt; ++ cskb != NULL; ++ cskb = PKTISCHAINED(cskb) ? PKTCLINK(cskb) : NULL) { ++ ++ /* walk the pkt buffer list */ ++ for (nskb = cskb; nskb; nskb = nskb->next) { ++ ++ /* Increment the packet counter */ ++ pktalloced++; ++ ++ /* clean the 'prev' pointer ++ * Kernel 3.18 is leaving skb->prev pointer set to skb ++ * to indicate a non-fragmented skb ++ */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) ++ nskb->prev = NULL; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) */ ++ ++ ++#ifdef BCMDBG_CTRACE ++ ADD_CTRACE(osh, nskb, file, line); ++#endif /* BCMDBG_CTRACE */ ++ } ++ } ++ ++ /* Increment the packet counter */ ++ atomic_add(pktalloced, &osh->cmn->pktalloced); ++ ++ return (void *)pkt; ++} ++ ++/* Return a new packet. zero out pkttag */ ++void * BCMFASTPATH ++#ifdef BCMDBG_CTRACE ++osl_pktget(osl_t *osh, uint len, int line, char *file) ++#else ++#ifdef BCM_OBJECT_TRACE ++osl_pktget(osl_t *osh, uint len, int line, const char *caller) ++#else ++osl_pktget(osl_t *osh, uint len) ++#endif /* BCM_OBJECT_TRACE */ ++#endif /* BCMDBG_CTRACE */ ++{ ++ struct sk_buff *skb; ++ uchar num = 0; ++ if (lmtest != FALSE) { ++ get_random_bytes(&num, sizeof(uchar)); ++ if ((num + 1) <= (256 * lmtest / 100)) ++ return NULL; ++ } ++ ++#ifdef CTFPOOL ++ /* Allocate from local pool */ ++ skb = osl_pktfastget(osh, len); ++ if ((skb != NULL) || ((skb = osl_alloc_skb(osh, len)) != NULL)) ++#else /* CTFPOOL */ ++ if ((skb = osl_alloc_skb(osh, len))) ++#endif /* CTFPOOL */ ++ { ++ skb->tail += len; ++ skb->len += len; ++ skb->priority = 0; ++ ++#ifdef BCMDBG_CTRACE ++ ADD_CTRACE(osh, skb, file, line); ++#endif ++ atomic_inc(&osh->cmn->pktalloced); ++#ifdef BCM_OBJECT_TRACE ++ bcm_object_trace_opr(skb, BCM_OBJDBG_ADD_PKT, caller, line); ++#endif /* BCM_OBJECT_TRACE */ ++ } ++ ++ return ((void*) skb); ++} ++ ++#ifdef CTFPOOL ++static inline void ++osl_pktfastfree(osl_t *osh, struct sk_buff *skb) ++{ ++ ctfpool_t *ctfpool; ++#ifdef CTFPOOL_SPINLOCK ++ unsigned long flags; ++#endif /* CTFPOOL_SPINLOCK */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) ++ skb->tstamp.tv.sec = 0; ++#else ++ skb->stamp.tv_sec = 0; ++#endif ++ ++ /* We only need to init the fields that we change */ ++ skb->dev = NULL; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) ++ skb->dst = NULL; ++#endif ++ OSL_PKTTAG_CLEAR(skb); ++ skb->ip_summed = 0; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) ++ skb_orphan(skb); ++#else ++ skb->destructor = NULL; ++#endif ++ ++ ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); ++ ASSERT(ctfpool != NULL); ++ ++ /* if osh is a fwder osh, reset the fwder buf */ ++ osl_fwderbuf_reset(ctfpool->osh, skb); ++ ++ /* Add object to the ctfpool */ ++ CTFPOOL_LOCK(ctfpool, flags); ++ skb->next = (struct sk_buff *)ctfpool->head; ++ ctfpool->head = (void *)skb; ++ ++ ctfpool->fast_frees++; ++ ctfpool->curr_obj++; ++ ++ ASSERT(ctfpool->curr_obj <= ctfpool->max_obj); ++ CTFPOOL_UNLOCK(ctfpool, flags); ++} ++#endif /* CTFPOOL */ ++ ++/* Free the driver packet. Free the tag if present */ ++void BCMFASTPATH ++#ifdef BCM_OBJECT_TRACE ++osl_pktfree(osl_t *osh, void *p, bool send, int line, const char *caller) ++#else ++osl_pktfree(osl_t *osh, void *p, bool send) ++#endif /* BCM_OBJECT_TRACE */ ++{ ++ struct sk_buff *skb, *nskb; ++ if (osh == NULL) ++ return; ++ ++ skb = (struct sk_buff*) p; ++ ++ if (send && osh->pub.tx_fn) ++ osh->pub.tx_fn(osh->pub.tx_ctx, p, 0); ++ ++ PKTDBG_TRACE(osh, (void *) skb, PKTLIST_PKTFREE); ++ ++#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_CTRLBUF) ++ if (skb && (skb->mac_len == PREALLOC_USED_MAGIC)) { ++ printk("%s: pkt %p is from static pool\n", ++ __FUNCTION__, p); ++ dump_stack(); ++ return; ++ } ++ ++ if (skb && (skb->mac_len == PREALLOC_FREE_MAGIC)) { ++ printk("%s: pkt %p is from static pool and not in used\n", ++ __FUNCTION__, p); ++ dump_stack(); ++ return; ++ } ++#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_CTRLBUF */ ++ ++ /* perversion: we use skb->next to chain multi-skb packets */ ++ while (skb) { ++ nskb = skb->next; ++ skb->next = NULL; ++ ++#ifdef BCMDBG_CTRACE ++ DEL_CTRACE(osh, skb); ++#endif ++ ++ ++#ifdef BCM_OBJECT_TRACE ++ bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, caller, line); ++#endif /* BCM_OBJECT_TRACE */ ++ ++#ifdef CTFPOOL ++ if (PKTISFAST(osh, skb)) { ++ if (atomic_read(&skb->users) == 1) ++ smp_rmb(); ++ else if (!atomic_dec_and_test(&skb->users)) ++ goto next_skb; ++ osl_pktfastfree(osh, skb); ++ } else ++#endif ++ { ++ dev_kfree_skb_any(skb); ++ } ++#ifdef CTFPOOL ++next_skb: ++#endif ++ atomic_dec(&osh->cmn->pktalloced); ++ skb = nskb; ++ } ++} ++ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++void* ++osl_pktget_static(osl_t *osh, uint len) ++{ ++ int i = 0; ++ struct sk_buff *skb; ++#ifdef DHD_USE_STATIC_CTRLBUF ++ unsigned long flags; ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ ++ if (!bcm_static_skb) ++ return osl_pktget(osh, len); ++ ++ if (len > DHD_SKB_MAX_BUFSIZE) { ++ printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len); ++ return osl_pktget(osh, len); ++ } ++ ++#ifdef DHD_USE_STATIC_CTRLBUF ++ spin_lock_irqsave(&bcm_static_skb->osl_pkt_lock, flags); ++ ++ if (len <= DHD_SKB_2PAGE_BUFSIZE) { ++ uint32 index; ++ for (i = 0; i < STATIC_PKT_2PAGE_NUM; i++) { ++ index = bcm_static_skb->last_allocated_index % STATIC_PKT_2PAGE_NUM; ++ bcm_static_skb->last_allocated_index++; ++ if (bcm_static_skb->skb_8k[index] && ++ bcm_static_skb->pkt_use[index] == 0) { ++ break; ++ } ++ } ++ ++ if ((i != STATIC_PKT_2PAGE_NUM) && ++ (index >= 0) && (index < STATIC_PKT_2PAGE_NUM)) { ++ bcm_static_skb->pkt_use[index] = 1; ++ skb = bcm_static_skb->skb_8k[index]; ++ skb->data = skb->head; ++#ifdef NET_SKBUFF_DATA_USES_OFFSET ++ skb_set_tail_pointer(skb, NET_SKB_PAD); ++#else ++ skb->tail = skb->data + NET_SKB_PAD; ++#endif /* NET_SKBUFF_DATA_USES_OFFSET */ ++ skb->data += NET_SKB_PAD; ++ skb->cloned = 0; ++ skb->priority = 0; ++#ifdef NET_SKBUFF_DATA_USES_OFFSET ++ skb_set_tail_pointer(skb, len); ++#else ++ skb->tail = skb->data + len; ++#endif /* NET_SKBUFF_DATA_USES_OFFSET */ ++ skb->len = len; ++ skb->mac_len = PREALLOC_USED_MAGIC; ++ spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); ++ return skb; ++ } ++ } ++ ++ spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); ++ printk("%s: all static pkt in use!\n", __FUNCTION__); ++ return NULL; ++#else ++ down(&bcm_static_skb->osl_pkt_sem); ++ ++ if (len <= DHD_SKB_1PAGE_BUFSIZE) { ++ for (i = 0; i < STATIC_PKT_1PAGE_NUM; i++) { ++ if (bcm_static_skb->skb_4k[i] && ++ bcm_static_skb->pkt_use[i] == 0) { ++ break; ++ } ++ } ++ ++ if (i != STATIC_PKT_1PAGE_NUM) { ++ bcm_static_skb->pkt_use[i] = 1; ++ ++ skb = bcm_static_skb->skb_4k[i]; ++#ifdef NET_SKBUFF_DATA_USES_OFFSET ++ skb_set_tail_pointer(skb, len); ++#else ++ skb->tail = skb->data + len; ++#endif /* NET_SKBUFF_DATA_USES_OFFSET */ ++ skb->len = len; ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ return skb; ++ } ++ } ++ ++ if (len <= DHD_SKB_2PAGE_BUFSIZE) { ++ for (i = STATIC_PKT_1PAGE_NUM; i < STATIC_PKT_1_2PAGE_NUM; i++) { ++ if (bcm_static_skb->skb_8k[i - STATIC_PKT_1PAGE_NUM] && ++ bcm_static_skb->pkt_use[i] == 0) { ++ break; ++ } ++ } ++ ++ if ((i >= STATIC_PKT_1PAGE_NUM) && (i < STATIC_PKT_1_2PAGE_NUM)) { ++ bcm_static_skb->pkt_use[i] = 1; ++ skb = bcm_static_skb->skb_8k[i - STATIC_PKT_1PAGE_NUM]; ++#ifdef NET_SKBUFF_DATA_USES_OFFSET ++ skb_set_tail_pointer(skb, len); ++#else ++ skb->tail = skb->data + len; ++#endif /* NET_SKBUFF_DATA_USES_OFFSET */ ++ skb->len = len; ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ return skb; ++ } ++ } ++ ++#if defined(ENHANCED_STATIC_BUF) ++ if (bcm_static_skb->skb_16k && ++ bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] == 0) { ++ bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] = 1; ++ ++ skb = bcm_static_skb->skb_16k; ++#ifdef NET_SKBUFF_DATA_USES_OFFSET ++ skb_set_tail_pointer(skb, len); ++#else ++ skb->tail = skb->data + len; ++#endif /* NET_SKBUFF_DATA_USES_OFFSET */ ++ skb->len = len; ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ return skb; ++ } ++#endif /* ENHANCED_STATIC_BUF */ ++ ++ up(&bcm_static_skb->osl_pkt_sem); ++ printk("%s: all static pkt in use!\n", __FUNCTION__); ++ return osl_pktget(osh, len); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++} ++ ++void ++osl_pktfree_static(osl_t *osh, void *p, bool send) ++{ ++ int i; ++#ifdef DHD_USE_STATIC_CTRLBUF ++ struct sk_buff *skb = (struct sk_buff *)p; ++ unsigned long flags; ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ ++ if (!p) { ++ return; ++ } ++ ++ if (!bcm_static_skb) { ++ osl_pktfree(osh, p, send); ++ return; ++ } ++ ++#ifdef DHD_USE_STATIC_CTRLBUF ++ spin_lock_irqsave(&bcm_static_skb->osl_pkt_lock, flags); ++ ++ for (i = 0; i < STATIC_PKT_2PAGE_NUM; i++) { ++ if (p == bcm_static_skb->skb_8k[i]) { ++ if (bcm_static_skb->pkt_use[i] == 0) { ++ printk("%s: static pkt idx %d(%p) is double free\n", ++ __FUNCTION__, i, p); ++ } else { ++ bcm_static_skb->pkt_use[i] = 0; ++ } ++ ++ if (skb->mac_len != PREALLOC_USED_MAGIC) { ++ printk("%s: static pkt idx %d(%p) is not in used\n", ++ __FUNCTION__, i, p); ++ } ++ ++ skb->mac_len = PREALLOC_FREE_MAGIC; ++ spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); ++ return; ++ } ++ } ++ ++ spin_unlock_irqrestore(&bcm_static_skb->osl_pkt_lock, flags); ++ printk("%s: packet %p does not exist in the pool\n", __FUNCTION__, p); ++#else ++ down(&bcm_static_skb->osl_pkt_sem); ++ for (i = 0; i < STATIC_PKT_1PAGE_NUM; i++) { ++ if (p == bcm_static_skb->skb_4k[i]) { ++ bcm_static_skb->pkt_use[i] = 0; ++ up(&bcm_static_skb->osl_pkt_sem); ++ return; ++ } ++ } ++ ++ for (i = STATIC_PKT_1PAGE_NUM; i < STATIC_PKT_1_2PAGE_NUM; i++) { ++ if (p == bcm_static_skb->skb_8k[i - STATIC_PKT_1PAGE_NUM]) { ++ bcm_static_skb->pkt_use[i] = 0; ++ up(&bcm_static_skb->osl_pkt_sem); ++ return; ++ } ++ } ++#ifdef ENHANCED_STATIC_BUF ++ if (p == bcm_static_skb->skb_16k) { ++ bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM - 1] = 0; ++ up(&bcm_static_skb->osl_pkt_sem); ++ return; ++ } ++#endif ++ up(&bcm_static_skb->osl_pkt_sem); ++#endif /* DHD_USE_STATIC_CTRLBUF */ ++ osl_pktfree(osh, p, send); ++} ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++uint32 ++osl_pci_read_config(osl_t *osh, uint offset, uint size) ++{ ++ uint val = 0; ++ uint retry = PCI_CFG_RETRY; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ /* only 4byte access supported */ ++ ASSERT(size == 4); ++ ++ do { ++ pci_read_config_dword(osh->pdev, offset, &val); ++ if (val != 0xffffffff) ++ break; ++ } while (retry--); ++ ++ ++ return (val); ++} ++ ++void ++osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val) ++{ ++ uint retry = PCI_CFG_RETRY; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ /* only 4byte access supported */ ++ ASSERT(size == 4); ++ ++ do { ++ pci_write_config_dword(osh->pdev, offset, val); ++ if (offset != PCI_BAR0_WIN) ++ break; ++ if (osl_pci_read_config(osh, offset, size) == val) ++ break; ++ } while (retry--); ++ ++} ++ ++/* return bus # for the pci device pointed by osh->pdev */ ++uint ++osl_pci_bus(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++#if defined(__ARM_ARCH_7A__) && LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35) ++ return pci_domain_nr(((struct pci_dev *)osh->pdev)->bus); ++#else ++ return ((struct pci_dev *)osh->pdev)->bus->number; ++#endif ++} ++ ++/* return slot # for the pci device pointed by osh->pdev */ ++uint ++osl_pci_slot(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++#if defined(__ARM_ARCH_7A__) && LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35) ++ return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn) + 1; ++#else ++ return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn); ++#endif ++} ++ ++/* return domain # for the pci device pointed by osh->pdev */ ++uint ++osl_pcie_domain(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++ return pci_domain_nr(((struct pci_dev *)osh->pdev)->bus); ++} ++ ++/* return bus # for the pci device pointed by osh->pdev */ ++uint ++osl_pcie_bus(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++ return ((struct pci_dev *)osh->pdev)->bus->number; ++} ++ ++/* return the pci device pointed by osh->pdev */ ++struct pci_dev * ++osl_pci_device(osl_t *osh) ++{ ++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev); ++ ++ return osh->pdev; ++} ++ ++static void ++osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write) ++{ ++} ++ ++void ++osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size) ++{ ++ osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE); ++} ++ ++void ++osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size) ++{ ++ osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE); ++} ++ ++void * ++osl_malloc(osl_t *osh, uint size) ++{ ++ void *addr; ++ gfp_t flags; ++ ++ /* only ASSERT if osh is defined */ ++ if (osh) ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ if (bcm_static_buf) ++ { ++ unsigned long irq_flags; ++ int i = 0; ++ if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE)) ++ { ++ spin_lock_irqsave(&bcm_static_buf->static_lock, irq_flags); ++ ++ for (i = 0; i < STATIC_BUF_MAX_NUM; i++) ++ { ++ if (bcm_static_buf->buf_use[i] == 0) ++ break; ++ } ++ ++ if (i == STATIC_BUF_MAX_NUM) ++ { ++ spin_unlock_irqrestore(&bcm_static_buf->static_lock, irq_flags); ++ printk("all static buff in use!\n"); ++ goto original; ++ } ++ ++ bcm_static_buf->buf_use[i] = 1; ++ spin_unlock_irqrestore(&bcm_static_buf->static_lock, irq_flags); ++ ++ bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size); ++ if (osh) ++ atomic_add(size, &osh->cmn->malloced); ++ ++ return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i)); ++ } ++ } ++original: ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ ++ flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; ++ if ((addr = kmalloc(size, flags)) == NULL) { ++ if (osh) ++ osh->failed++; ++ return (NULL); ++ } ++ if (osh && osh->cmn) ++ atomic_add(size, &osh->cmn->malloced); ++ ++ return (addr); ++} ++ ++void * ++osl_mallocz(osl_t *osh, uint size) ++{ ++ void *ptr; ++ ++ ptr = osl_malloc(osh, size); ++ ++ if (ptr != NULL) { ++ bzero(ptr, size); ++ } ++ ++ return ptr; ++} ++ ++void ++osl_mfree(osl_t *osh, void *addr, uint size) ++{ ++#ifdef CONFIG_DHD_USE_STATIC_BUF ++ unsigned long flags; ++ ++ if (bcm_static_buf) ++ { ++ if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr ++ <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN))) ++ { ++ int buf_idx = 0; ++ ++ buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE; ++ ++ spin_lock_irqsave(&bcm_static_buf->static_lock, flags); ++ bcm_static_buf->buf_use[buf_idx] = 0; ++ spin_unlock_irqrestore(&bcm_static_buf->static_lock, flags); ++ ++ if (osh && osh->cmn) { ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ atomic_sub(size, &osh->cmn->malloced); ++ } ++ return; ++ } ++ } ++#endif /* CONFIG_DHD_USE_STATIC_BUF */ ++ if (osh && osh->cmn) { ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ ++ ASSERT(size <= osl_malloced(osh)); ++ ++ atomic_sub(size, &osh->cmn->malloced); ++ } ++ kfree(addr); ++} ++ ++void * ++osl_vmalloc(osl_t *osh, uint size) ++{ ++ void *addr; ++ ++ /* only ASSERT if osh is defined */ ++ if (osh) ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ if ((addr = vmalloc(size)) == NULL) { ++ if (osh) ++ osh->failed++; ++ return (NULL); ++ } ++ if (osh && osh->cmn) ++ atomic_add(size, &osh->cmn->malloced); ++ ++ return (addr); ++} ++ ++void * ++osl_vmallocz(osl_t *osh, uint size) ++{ ++ void *ptr; ++ ++ ptr = osl_vmalloc(osh, size); ++ ++ if (ptr != NULL) { ++ bzero(ptr, size); ++ } ++ ++ return ptr; ++} ++ ++void ++osl_vmfree(osl_t *osh, void *addr, uint size) ++{ ++ if (osh && osh->cmn) { ++ ASSERT(osh->magic == OS_HANDLE_MAGIC); ++ ++ ASSERT(size <= osl_malloced(osh)); ++ ++ atomic_sub(size, &osh->cmn->malloced); ++ } ++ vfree(addr); ++} ++ ++uint ++osl_check_memleak(osl_t *osh) ++{ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ if (atomic_read(&osh->cmn->refcount) == 1) ++ return (atomic_read(&osh->cmn->malloced)); ++ else ++ return 0; ++} ++ ++uint ++osl_malloced(osl_t *osh) ++{ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ return (atomic_read(&osh->cmn->malloced)); ++} ++ ++uint ++osl_malloc_failed(osl_t *osh) ++{ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ return (osh->failed); ++} ++ ++ ++uint ++osl_dma_consistent_align(void) ++{ ++ return (PAGE_SIZE); ++} ++ ++void* ++osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, dmaaddr_t *pap) ++{ ++ void *va; ++ uint16 align = (1 << align_bits); ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align)) ++ size += align; ++ *alloced = size; ++ ++#ifndef BCM_SECURE_DMA ++#if defined(__ARM_ARCH_7A__) && !defined(DHD_USE_COHERENT_MEM_FOR_RING) ++ va = kmalloc(size, GFP_ATOMIC | __GFP_ZERO); ++ if (va) ++ *pap = (ulong)__virt_to_phys((ulong)va); ++#else ++ { ++ dma_addr_t pap_lin; ++ struct pci_dev *hwdev = osh->pdev; ++ gfp_t flags; ++#ifdef DHD_ALLOC_COHERENT_MEM_FROM_ATOMIC_POOL ++ flags = GFP_ATOMIC; ++#else ++ flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; ++#endif /* DHD_ALLOC_COHERENT_MEM_FROM_ATOMIC_POOL */ ++ va = dma_alloc_coherent(&hwdev->dev, size, &pap_lin, flags); ++#ifdef BCMDMA64OSL ++ PHYSADDRLOSET(*pap, pap_lin & 0xffffffff); ++ PHYSADDRHISET(*pap, (pap_lin >> 32) & 0xffffffff); ++#else ++ *pap = (dmaaddr_t)pap_lin; ++#endif /* BCMDMA64OSL */ ++ } ++#endif /* __ARM_ARCH_7A__ && !DHD_USE_COHERENT_MEM_FOR_RING */ ++#else ++ va = osl_sec_dma_alloc_consistent(osh, size, align_bits, pap); ++#endif /* BCM_SECURE_DMA */ ++ return va; ++} ++ ++void ++osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa) ++{ ++#ifdef BCMDMA64OSL ++ dma_addr_t paddr; ++#endif /* BCMDMA64OSL */ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++#ifndef BCM_SECURE_DMA ++#if defined(__ARM_ARCH_7A__) && !defined(DHD_USE_COHERENT_MEM_FOR_RING) ++ kfree(va); ++#else ++#ifdef BCMDMA64OSL ++ PHYSADDRTOULONG(pa, paddr); ++ pci_free_consistent(osh->pdev, size, va, paddr); ++#else ++ pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa); ++#endif /* BCMDMA64OSL */ ++#endif /* __ARM_ARCH_7A__ && !DHD_USE_COHERENT_MEM_FOR_RING */ ++#else ++ osl_sec_dma_free_consistent(osh, va, size, pa); ++#endif /* BCM_SECURE_DMA */ ++} ++ ++dmaaddr_t BCMFASTPATH ++osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *dmah) ++{ ++ int dir; ++ dmaaddr_t ret_addr; ++ dma_addr_t map_addr; ++ int ret; ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; ++ ++ ++ ++ ++ map_addr = pci_map_single(osh->pdev, va, size, dir); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) ++ ret = pci_dma_mapping_error(osh->pdev, map_addr); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 5)) ++ ret = pci_dma_mapping_error(map_addr); ++#else ++ ret = 0; ++#endif ++ if (ret) { ++ printk("%s: Failed to map memory\n", __FUNCTION__); ++ PHYSADDRLOSET(ret_addr, 0); ++ PHYSADDRHISET(ret_addr, 0); ++ } else { ++ PHYSADDRLOSET(ret_addr, map_addr & 0xffffffff); ++ PHYSADDRHISET(ret_addr, (map_addr >> 32) & 0xffffffff); ++ } ++ ++ return ret_addr; ++} ++ ++void BCMFASTPATH ++osl_dma_unmap(osl_t *osh, dmaaddr_t pa, uint size, int direction) ++{ ++ int dir; ++#ifdef BCMDMA64OSL ++ dma_addr_t paddr; ++#endif /* BCMDMA64OSL */ ++ ++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); ++ ++ ++ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE; ++#ifdef BCMDMA64OSL ++ PHYSADDRTOULONG(pa, paddr); ++ pci_unmap_single(osh->pdev, paddr, size, dir); ++#else ++ pci_unmap_single(osh->pdev, (uint32)pa, size, dir); ++#endif /* BCMDMA64OSL */ ++} ++ ++/* OSL function for CPU relax */ ++inline void BCMFASTPATH ++osl_cpu_relax(void) ++{ ++ cpu_relax(); ++} ++ ++extern void osl_preempt_disable(osl_t *osh) ++{ ++ preempt_disable(); ++} ++ ++extern void osl_preempt_enable(osl_t *osh) ++{ ++ preempt_enable(); ++} ++ ++#if defined(BCMASSERT_LOG) ++void ++osl_assert(const char *exp, const char *file, int line) ++{ ++ char tempbuf[256]; ++ const char *basename; ++ ++ basename = strrchr(file, '/'); ++ /* skip the '/' */ ++ if (basename) ++ basename++; ++ ++ if (!basename) ++ basename = file; ++ ++#ifdef BCMASSERT_LOG ++ snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n", ++ exp, basename, line); ++#endif /* BCMASSERT_LOG */ ++ ++ ++ switch (g_assert_type) { ++ case 0: ++ panic("%s", tempbuf); ++ break; ++ case 1: ++ /* fall through */ ++ case 3: ++ printk("%s", tempbuf); ++ break; ++ case 2: ++ printk("%s", tempbuf); ++ BUG(); ++ break; ++ default: ++ break; ++ } ++} ++#endif ++ ++void ++osl_delay(uint usec) ++{ ++ uint d; ++ ++ while (usec > 0) { ++ d = MIN(usec, 1000); ++ udelay(d); ++ usec -= d; ++ } ++} ++ ++void ++osl_sleep(uint ms) ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) ++ if (ms < 20) ++ usleep_range(ms*1000, ms*1000 + 1000); ++ else ++#endif ++ msleep(ms); ++} ++ ++uint64 ++osl_sysuptime_us(void) ++{ ++ struct osl_timespec tv; ++ uint64 usec; ++ ++ osl_do_gettimeofday(&tv); ++ /* tv_usec content is fraction of a second */ ++ usec = (uint64)tv.tv_sec * 1000000ul + tv.tv_usec; ++ return usec; ++} ++ ++ ++/* Clone a packet. ++ * The pkttag contents are NOT cloned. ++ */ ++void * ++#ifdef BCMDBG_CTRACE ++osl_pktdup(osl_t *osh, void *skb, int line, char *file) ++#else ++#ifdef BCM_OBJECT_TRACE ++osl_pktdup(osl_t *osh, void *skb, int line, const char *caller) ++#else ++osl_pktdup(osl_t *osh, void *skb) ++#endif /* BCM_OBJECT_TRACE */ ++#endif /* BCMDBG_CTRACE */ ++{ ++ void * p; ++ ++ ASSERT(!PKTISCHAINED(skb)); ++ ++ /* clear the CTFBUF flag if set and map the rest of the buffer ++ * before cloning. ++ */ ++ PKTCTFMAP(osh, skb); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) ++ if ((p = pskb_copy((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) ++#else ++ if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL) ++#endif ++ return NULL; ++ ++#ifdef CTFPOOL ++ if (PKTISFAST(osh, skb)) { ++ ctfpool_t *ctfpool; ++ ++ /* if the buffer allocated from ctfpool is cloned then ++ * we can't be sure when it will be freed. since there ++ * is a chance that we will be losing a buffer ++ * from our pool, we increment the refill count for the ++ * object to be alloced later. ++ */ ++ ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb); ++ ASSERT(ctfpool != NULL); ++ PKTCLRFAST(osh, p); ++ PKTCLRFAST(osh, skb); ++ ctfpool->refills++; ++ } ++#endif /* CTFPOOL */ ++ ++ /* Clear PKTC context */ ++ PKTSETCLINK(p, NULL); ++ PKTCCLRFLAGS(p); ++ PKTCSETCNT(p, 1); ++ PKTCSETLEN(p, PKTLEN(osh, skb)); ++ ++ /* skb_clone copies skb->cb.. we don't want that */ ++ if (osh->pub.pkttag) ++ OSL_PKTTAG_CLEAR(p); ++ ++ /* Increment the packet counter */ ++ atomic_inc(&osh->cmn->pktalloced); ++#ifdef BCM_OBJECT_TRACE ++ bcm_object_trace_opr(p, BCM_OBJDBG_ADD_PKT, caller, line); ++#endif /* BCM_OBJECT_TRACE */ ++ ++#ifdef BCMDBG_CTRACE ++ ADD_CTRACE(osh, (struct sk_buff *)p, file, line); ++#endif ++ return (p); ++} ++ ++#ifdef BCMDBG_CTRACE ++int osl_pkt_is_frmnative(osl_t *osh, struct sk_buff *pkt) ++{ ++ unsigned long flags; ++ struct sk_buff *skb; ++ int ck = FALSE; ++ ++ spin_lock_irqsave(&osh->ctrace_lock, flags); ++ ++ list_for_each_entry(skb, &osh->ctrace_list, ctrace_list) { ++ if (pkt == skb) { ++ ck = TRUE; ++ break; ++ } ++ } ++ ++ spin_unlock_irqrestore(&osh->ctrace_lock, flags); ++ return ck; ++} ++ ++void osl_ctrace_dump(osl_t *osh, struct bcmstrbuf *b) ++{ ++ unsigned long flags; ++ struct sk_buff *skb; ++ int idx = 0; ++ int i, j; ++ ++ spin_lock_irqsave(&osh->ctrace_lock, flags); ++ ++ if (b != NULL) ++ bcm_bprintf(b, " Total %d sbk not free\n", osh->ctrace_num); ++ else ++ printk(" Total %d sbk not free\n", osh->ctrace_num); ++ ++ list_for_each_entry(skb, &osh->ctrace_list, ctrace_list) { ++ if (b != NULL) ++ bcm_bprintf(b, "[%d] skb %p:\n", ++idx, skb); ++ else ++ printk("[%d] skb %p:\n", ++idx, skb); ++ ++ for (i = 0; i < skb->ctrace_count; i++) { ++ j = (skb->ctrace_start + i) % CTRACE_NUM; ++ if (b != NULL) ++ bcm_bprintf(b, " [%s(%d)]\n", skb->func[j], skb->line[j]); ++ else ++ printk(" [%s(%d)]\n", skb->func[j], skb->line[j]); ++ } ++ if (b != NULL) ++ bcm_bprintf(b, "\n"); ++ else ++ printk("\n"); ++ } ++ ++ spin_unlock_irqrestore(&osh->ctrace_lock, flags); ++ ++ return; ++} ++#endif /* BCMDBG_CTRACE */ ++ ++ ++/* ++ * OSLREGOPS specifies the use of osl_XXX routines to be used for register access ++ */ ++ ++/* ++ * BINOSL selects the slightly slower function-call-based binary compatible osl. ++ */ ++ ++uint ++osl_pktalloced(osl_t *osh) ++{ ++ if (atomic_read(&osh->cmn->refcount) == 1) ++ return (atomic_read(&osh->cmn->pktalloced)); ++ else ++ return 0; ++} ++ ++uint32 ++osl_rand(void) ++{ ++ uint32 rand; ++ ++ get_random_bytes(&rand, sizeof(rand)); ++ ++ return rand; ++} ++ ++/* Linux Kernel: File Operations: start */ ++void * ++osl_os_open_image(char *filename) ++{ ++ struct file *fp; ++ ++ fp = filp_open(filename, O_RDONLY, 0); ++ /* ++ * 2.6.11 (FC4) supports filp_open() but later revs don't? ++ * Alternative: ++ * fp = open_namei(AT_FDCWD, filename, O_RD, 0); ++ * ??? ++ */ ++ if (IS_ERR(fp)) ++ fp = NULL; ++ ++ return fp; ++} ++ ++int ++osl_os_get_image_block(char *buf, int len, void *image) ++{ ++ struct file *fp = (struct file *)image; ++ int rdlen; ++ ++ if (!image) ++ return 0; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ rdlen = kernel_read(fp, buf, len, &fp->f_pos); ++#else ++ rdlen = kernel_read(fp, fp->f_pos, buf, len); ++ if (rdlen > 0) ++ fp->f_pos += rdlen; ++#endif ++ ++ return rdlen; ++} ++ ++void ++osl_os_close_image(void *image) ++{ ++ if (image) ++ filp_close((struct file *)image, NULL); ++} ++ ++int ++osl_os_image_size(void *image) ++{ ++ int len = 0, curroffset; ++ ++ if (image) { ++ /* store the current offset */ ++ curroffset = generic_file_llseek(image, 0, 1); ++ /* goto end of file to get length */ ++ len = generic_file_llseek(image, 0, 2); ++ /* restore back the offset */ ++ generic_file_llseek(image, curroffset, 0); ++ } ++ return len; ++} ++ ++/* Linux Kernel: File Operations: end */ ++ ++#if (defined(STB) && defined(__arm__)) ++inline void osl_pcie_rreg(osl_t *osh, ulong addr, void *v, uint size) ++{ ++ unsigned long flags = 0; ++ int pci_access = 0; ++#if defined(BCM_GMAC3) ++ const int acp_war_enab = 1; ++#else /* !BCM_GMAC3 */ ++ int acp_war_enab = ACP_WAR_ENAB(); ++#endif /* !BCM_GMAC3 */ ++ ++ if (osh && BUSTYPE(osh->bustype) == PCI_BUS) ++ pci_access = 1; ++ ++ if (pci_access && acp_war_enab) ++ spin_lock_irqsave(&l2x0_reg_lock, flags); ++ ++ switch (size) { ++ case sizeof(uint8): ++ *(uint8*)v = readb((volatile uint8*)(addr)); ++ break; ++ case sizeof(uint16): ++ *(uint16*)v = readw((volatile uint16*)(addr)); ++ break; ++ case sizeof(uint32): ++ *(uint32*)v = readl((volatile uint32*)(addr)); ++ break; ++ case sizeof(uint64): ++ *(uint64*)v = *((volatile uint64*)(addr)); ++ break; ++ } ++ ++ if (pci_access && acp_war_enab) ++ spin_unlock_irqrestore(&l2x0_reg_lock, flags); ++} ++#endif ++ ++#ifdef BCM_SECURE_DMA ++static void * ++osl_sec_dma_ioremap(osl_t *osh, struct page *page, size_t size, bool iscache, bool isdecr) ++{ ++ ++ struct page **map; ++ int order, i; ++ void *addr = NULL; ++ ++ size = PAGE_ALIGN(size); ++ order = get_order(size); ++ ++ map = kmalloc(sizeof(struct page *) << order, GFP_ATOMIC); ++ ++ if (map == NULL) ++ return NULL; ++ ++ for (i = 0; i < (size >> PAGE_SHIFT); i++) ++ map[i] = page + i; ++ ++ if (iscache) { ++ addr = vmap(map, size >> PAGE_SHIFT, VM_MAP, __pgprot(PAGE_KERNEL)); ++ if (isdecr) { ++ osh->contig_delta_va_pa = ((uint8 *)addr - page_to_phys(page)); ++ } ++ } else { ++ ++#if defined(__ARM_ARCH_7A__) ++ addr = vmap(map, size >> PAGE_SHIFT, VM_MAP, ++ pgprot_noncached(__pgprot(PAGE_KERNEL))); ++#endif ++ if (isdecr) { ++ osh->contig_delta_va_pa = ((uint8 *)addr - page_to_phys(page)); ++ } ++ } ++ ++ kfree(map); ++ return (void *)addr; ++} ++ ++static void ++osl_sec_dma_iounmap(osl_t *osh, void *contig_base_va, size_t size) ++{ ++ vunmap(contig_base_va); ++} ++ ++static int ++osl_sec_dma_init_elem_mem_block(osl_t *osh, size_t mbsize, int max, sec_mem_elem_t **list) ++{ ++ int i; ++ int ret = BCME_OK; ++ sec_mem_elem_t *sec_mem_elem; ++ ++ if ((sec_mem_elem = kmalloc(sizeof(sec_mem_elem_t)*(max), GFP_ATOMIC)) != NULL) { ++ ++ *list = sec_mem_elem; ++ bzero(sec_mem_elem, sizeof(sec_mem_elem_t)*(max)); ++ for (i = 0; i < max-1; i++) { ++ sec_mem_elem->next = (sec_mem_elem + 1); ++ sec_mem_elem->size = mbsize; ++ sec_mem_elem->pa_cma = osh->contig_base_alloc; ++ sec_mem_elem->vac = osh->contig_base_alloc_va; ++ ++ sec_mem_elem->pa_cma_page = phys_to_page(sec_mem_elem->pa_cma); ++ osh->contig_base_alloc += mbsize; ++ osh->contig_base_alloc_va = ((uint8 *)osh->contig_base_alloc_va + mbsize); ++ ++ sec_mem_elem = sec_mem_elem + 1; ++ } ++ sec_mem_elem->next = NULL; ++ sec_mem_elem->size = mbsize; ++ sec_mem_elem->pa_cma = osh->contig_base_alloc; ++ sec_mem_elem->vac = osh->contig_base_alloc_va; ++ ++ sec_mem_elem->pa_cma_page = phys_to_page(sec_mem_elem->pa_cma); ++ osh->contig_base_alloc += mbsize; ++ osh->contig_base_alloc_va = ((uint8 *)osh->contig_base_alloc_va + mbsize); ++ ++ } else { ++ printf("%s sec mem elem kmalloc failed\n", __FUNCTION__); ++ ret = BCME_ERROR; ++ } ++ return ret; ++} ++ ++ ++static void ++osl_sec_dma_deinit_elem_mem_block(osl_t *osh, size_t mbsize, int max, void *sec_list_base) ++{ ++ if (sec_list_base) ++ kfree(sec_list_base); ++} ++ ++static sec_mem_elem_t * BCMFASTPATH ++osl_sec_dma_alloc_mem_elem(osl_t *osh, void *va, uint size, int direction, ++ struct sec_cma_info *ptr_cma_info, uint offset) ++{ ++ sec_mem_elem_t *sec_mem_elem = NULL; ++ ++ ASSERT(osh->sec_list_4096); ++ sec_mem_elem = osh->sec_list_4096; ++ osh->sec_list_4096 = sec_mem_elem->next; ++ ++ sec_mem_elem->next = NULL; ++ ++ if (ptr_cma_info->sec_alloc_list_tail) { ++ ptr_cma_info->sec_alloc_list_tail->next = sec_mem_elem; ++ ptr_cma_info->sec_alloc_list_tail = sec_mem_elem; ++ } ++ else { ++ /* First allocation: If tail is NULL, sec_alloc_list MUST also be NULL */ ++ ASSERT(ptr_cma_info->sec_alloc_list == NULL); ++ ptr_cma_info->sec_alloc_list = sec_mem_elem; ++ ptr_cma_info->sec_alloc_list_tail = sec_mem_elem; ++ } ++ return sec_mem_elem; ++} ++ ++static void BCMFASTPATH ++osl_sec_dma_free_mem_elem(osl_t *osh, sec_mem_elem_t *sec_mem_elem) ++{ ++ sec_mem_elem->dma_handle = 0x0; ++ sec_mem_elem->va = NULL; ++ sec_mem_elem->next = osh->sec_list_4096; ++ osh->sec_list_4096 = sec_mem_elem; ++} ++ ++static sec_mem_elem_t * BCMFASTPATH ++osl_sec_dma_find_rem_elem(osl_t *osh, struct sec_cma_info *ptr_cma_info, dma_addr_t dma_handle) ++{ ++ sec_mem_elem_t *sec_mem_elem = ptr_cma_info->sec_alloc_list; ++ sec_mem_elem_t *sec_prv_elem = ptr_cma_info->sec_alloc_list; ++ ++ if (sec_mem_elem->dma_handle == dma_handle) { ++ ++ ptr_cma_info->sec_alloc_list = sec_mem_elem->next; ++ ++ if (sec_mem_elem == ptr_cma_info->sec_alloc_list_tail) { ++ ptr_cma_info->sec_alloc_list_tail = NULL; ++ ASSERT(ptr_cma_info->sec_alloc_list == NULL); ++ } ++ ++ return sec_mem_elem; ++ } ++ sec_mem_elem = sec_mem_elem->next; ++ ++ while (sec_mem_elem != NULL) { ++ ++ if (sec_mem_elem->dma_handle == dma_handle) { ++ ++ sec_prv_elem->next = sec_mem_elem->next; ++ if (sec_mem_elem == ptr_cma_info->sec_alloc_list_tail) ++ ptr_cma_info->sec_alloc_list_tail = sec_prv_elem; ++ ++ return sec_mem_elem; ++ } ++ sec_prv_elem = sec_mem_elem; ++ sec_mem_elem = sec_mem_elem->next; ++ } ++ return NULL; ++} ++ ++static sec_mem_elem_t * ++osl_sec_dma_rem_first_elem(osl_t *osh, struct sec_cma_info *ptr_cma_info) ++{ ++ sec_mem_elem_t *sec_mem_elem = ptr_cma_info->sec_alloc_list; ++ ++ if (sec_mem_elem) { ++ ++ ptr_cma_info->sec_alloc_list = sec_mem_elem->next; ++ ++ if (ptr_cma_info->sec_alloc_list == NULL) ++ ptr_cma_info->sec_alloc_list_tail = NULL; ++ ++ return sec_mem_elem; ++ ++ } else ++ return NULL; ++} ++ ++static void * BCMFASTPATH ++osl_sec_dma_last_elem(osl_t *osh, struct sec_cma_info *ptr_cma_info) ++{ ++ return ptr_cma_info->sec_alloc_list_tail; ++} ++ ++dma_addr_t BCMFASTPATH ++osl_sec_dma_map_txmeta(osl_t *osh, void *va, uint size, int direction, void *p, ++ hnddma_seg_map_t *dmah, void *ptr_cma_info) ++{ ++ sec_mem_elem_t *sec_mem_elem; ++ struct page *pa_cma_page; ++ uint loffset; ++ void *vaorig = ((uint8 *)va + size); ++ dma_addr_t dma_handle = 0x0; ++ /* packet will be the one added with osl_sec_dma_map() just before this call */ ++ ++ sec_mem_elem = osl_sec_dma_last_elem(osh, ptr_cma_info); ++ ++ if (sec_mem_elem && sec_mem_elem->va == vaorig) { ++ ++ pa_cma_page = phys_to_page(sec_mem_elem->pa_cma); ++ loffset = sec_mem_elem->pa_cma -(sec_mem_elem->pa_cma & ~(PAGE_SIZE-1)); ++ ++ dma_handle = dma_map_page(OSH_NULL, pa_cma_page, loffset, size, ++ (direction == DMA_TX ? DMA_TO_DEVICE:DMA_FROM_DEVICE)); ++ ++ } else { ++ printf("%s: error orig va not found va = 0x%p \n", ++ __FUNCTION__, vaorig); ++ } ++ return dma_handle; ++} ++ ++dma_addr_t BCMFASTPATH ++osl_sec_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, ++ hnddma_seg_map_t *dmah, void *ptr_cma_info, uint offset) ++{ ++ ++ sec_mem_elem_t *sec_mem_elem; ++ struct page *pa_cma_page; ++ void *pa_cma_kmap_va = NULL; ++ uint buflen = 0; ++ dma_addr_t dma_handle = 0x0; ++ uint loffset; ++ ++ ASSERT((direction == DMA_RX) || (direction == DMA_TX)); ++ sec_mem_elem = osl_sec_dma_alloc_mem_elem(osh, va, size, direction, ptr_cma_info, offset); ++ ++ sec_mem_elem->va = va; ++ sec_mem_elem->direction = direction; ++ pa_cma_page = sec_mem_elem->pa_cma_page; ++ ++ loffset = sec_mem_elem->pa_cma -(sec_mem_elem->pa_cma & ~(PAGE_SIZE-1)); ++ /* pa_cma_kmap_va = kmap_atomic(pa_cma_page); ++ * pa_cma_kmap_va += loffset; ++ */ ++ ++ pa_cma_kmap_va = sec_mem_elem->vac; ++ pa_cma_kmap_va = ((uint8 *)pa_cma_kmap_va + offset); ++ buflen = size; ++ ++ if (direction == DMA_TX) { ++ memcpy((uint8*)pa_cma_kmap_va+offset, va, size); ++ ++ if (dmah) { ++ dmah->nsegs = 1; ++ dmah->origsize = buflen; ++ } ++ } ++ else ++ { ++ if ((p != NULL) && (dmah != NULL)) { ++ dmah->nsegs = 1; ++ dmah->origsize = buflen; ++ } ++ *(uint32 *)(pa_cma_kmap_va) = 0x0; ++ } ++ ++ if (direction == DMA_RX) { ++ flush_kernel_vmap_range(pa_cma_kmap_va, sizeof(int)); ++ } ++ dma_handle = dma_map_page(OSH_NULL, pa_cma_page, loffset+offset, buflen, ++ (direction == DMA_TX ? DMA_TO_DEVICE:DMA_FROM_DEVICE)); ++ if (dmah) { ++ dmah->segs[0].addr = dma_handle; ++ dmah->segs[0].length = buflen; ++ } ++ sec_mem_elem->dma_handle = dma_handle; ++ /* kunmap_atomic(pa_cma_kmap_va-loffset); */ ++ return dma_handle; ++} ++ ++dma_addr_t BCMFASTPATH ++osl_sec_dma_dd_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *map) ++{ ++ ++ struct page *pa_cma_page; ++ phys_addr_t pa_cma; ++ dma_addr_t dma_handle = 0x0; ++ uint loffset; ++ ++ pa_cma = ((uint8 *)va - (uint8 *)osh->contig_delta_va_pa); ++ pa_cma_page = phys_to_page(pa_cma); ++ loffset = pa_cma -(pa_cma & ~(PAGE_SIZE-1)); ++ ++ dma_handle = dma_map_page(OSH_NULL, pa_cma_page, loffset, size, ++ (direction == DMA_TX ? DMA_TO_DEVICE:DMA_FROM_DEVICE)); ++ ++ return dma_handle; ++} ++ ++void BCMFASTPATH ++osl_sec_dma_unmap(osl_t *osh, dma_addr_t dma_handle, uint size, int direction, ++void *p, hnddma_seg_map_t *map, void *ptr_cma_info, uint offset) ++{ ++ sec_mem_elem_t *sec_mem_elem; ++ void *pa_cma_kmap_va = NULL; ++ uint buflen = 0; ++ dma_addr_t pa_cma; ++ void *va; ++ int read_count = 0; ++ BCM_REFERENCE(buflen); ++ BCM_REFERENCE(read_count); ++ ++ sec_mem_elem = osl_sec_dma_find_rem_elem(osh, ptr_cma_info, dma_handle); ++ ASSERT(sec_mem_elem); ++ ++ va = sec_mem_elem->va; ++ va = (uint8 *)va - offset; ++ pa_cma = sec_mem_elem->pa_cma; ++ ++ ++ if (direction == DMA_RX) { ++ ++ if (p == NULL) { ++ ++ /* pa_cma_kmap_va = kmap_atomic(pa_cma_page); ++ * pa_cma_kmap_va += loffset; ++ */ ++ ++ pa_cma_kmap_va = sec_mem_elem->vac; ++ ++ do { ++ invalidate_kernel_vmap_range(pa_cma_kmap_va, sizeof(int)); ++ ++ buflen = *(uint *)(pa_cma_kmap_va); ++ if (buflen) ++ break; ++ ++ OSL_DELAY(1); ++ read_count++; ++ } while (read_count < 200); ++ dma_unmap_page(OSH_NULL, pa_cma, size, DMA_FROM_DEVICE); ++ memcpy(va, pa_cma_kmap_va, size); ++ /* kunmap_atomic(pa_cma_kmap_va); */ ++ } ++ } else { ++ dma_unmap_page(OSH_NULL, pa_cma, size+offset, DMA_TO_DEVICE); ++ } ++ ++ osl_sec_dma_free_mem_elem(osh, sec_mem_elem); ++} ++ ++void ++osl_sec_dma_unmap_all(osl_t *osh, void *ptr_cma_info) ++{ ++ ++ sec_mem_elem_t *sec_mem_elem; ++ ++ sec_mem_elem = osl_sec_dma_rem_first_elem(osh, ptr_cma_info); ++ ++ while (sec_mem_elem != NULL) { ++ ++ dma_unmap_page(OSH_NULL, sec_mem_elem->pa_cma, sec_mem_elem->size, ++ sec_mem_elem->direction == DMA_TX ? DMA_TO_DEVICE : DMA_FROM_DEVICE); ++ osl_sec_dma_free_mem_elem(osh, sec_mem_elem); ++ ++ sec_mem_elem = osl_sec_dma_rem_first_elem(osh, ptr_cma_info); ++ } ++} ++ ++static void ++osl_sec_dma_init_consistent(osl_t *osh) ++{ ++ int i; ++ void *temp_va = osh->contig_base_alloc_coherent_va; ++ phys_addr_t temp_pa = osh->contig_base_alloc_coherent; ++ ++ for (i = 0; i < SEC_CMA_COHERENT_MAX; i++) { ++ osh->sec_cma_coherent[i].avail = TRUE; ++ osh->sec_cma_coherent[i].va = temp_va; ++ osh->sec_cma_coherent[i].pa = temp_pa; ++ temp_va = ((uint8 *)temp_va)+SEC_CMA_COHERENT_BLK; ++ temp_pa += SEC_CMA_COHERENT_BLK; ++ } ++} ++ ++static void * ++osl_sec_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, ulong *pap) ++{ ++ ++ void *temp_va = NULL; ++ ulong temp_pa = 0; ++ int i; ++ ++ if (size > SEC_CMA_COHERENT_BLK) { ++ printf("%s unsupported size\n", __FUNCTION__); ++ return NULL; ++ } ++ ++ for (i = 0; i < SEC_CMA_COHERENT_MAX; i++) { ++ if (osh->sec_cma_coherent[i].avail == TRUE) { ++ temp_va = osh->sec_cma_coherent[i].va; ++ temp_pa = osh->sec_cma_coherent[i].pa; ++ osh->sec_cma_coherent[i].avail = FALSE; ++ break; ++ } ++ } ++ ++ if (i == SEC_CMA_COHERENT_MAX) ++ printf("%s:No coherent mem: va = 0x%p pa = 0x%lx size = %d\n", __FUNCTION__, ++ temp_va, (ulong)temp_pa, size); ++ ++ *pap = (unsigned long)temp_pa; ++ return temp_va; ++} ++ ++static void ++osl_sec_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa) ++{ ++ int i = 0; ++ ++ for (i = 0; i < SEC_CMA_COHERENT_MAX; i++) { ++ if (osh->sec_cma_coherent[i].va == va) { ++ osh->sec_cma_coherent[i].avail = TRUE; ++ break; ++ } ++ } ++ if (i == SEC_CMA_COHERENT_MAX) ++ printf("%s:Error: va = 0x%p pa = 0x%lx size = %d\n", __FUNCTION__, ++ va, (ulong)pa, size); ++} ++ ++#endif /* BCM_SECURE_DMA */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) && defined(TSQ_MULTIPLIER) ++#include ++#include ++void ++osl_pkt_orphan_partial(struct sk_buff *skb, int tsq) ++{ ++ uint32 fraction; ++ static void *p_tcp_wfree = NULL; ++ ++ if (tsq <= 0) ++ return; ++ ++ if (!skb->destructor || skb->destructor == sock_wfree) ++ return; ++ ++ if (unlikely(!p_tcp_wfree)) { ++ char sym[KSYM_SYMBOL_LEN]; ++ sprint_symbol(sym, (unsigned long)skb->destructor); ++ sym[9] = 0; ++ if (!strcmp(sym, "tcp_wfree")) ++ p_tcp_wfree = skb->destructor; ++ else ++ return; ++ } ++ ++ if (unlikely(skb->destructor != p_tcp_wfree || !skb->sk)) ++ return; ++ ++ /* abstract a certain portion of skb truesize from the socket ++ * sk_wmem_alloc to allow more skb can be allocated for this ++ * socket for better cusion meeting WiFi device requirement ++ */ ++ fraction = skb->truesize * (tsq - 1) / tsq; ++ skb->truesize -= fraction; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) ++ atomic_sub(fraction, &skb->sk->sk_wmem_alloc.refs); ++#else ++ atomic_sub(fraction, &skb->sk->sk_wmem_alloc); ++#endif /* LINUX_VERSION >= 4.13.0 */ ++ skb_orphan(skb); ++} ++#endif /* LINUX_VERSION >= 3.6.0 && TSQ_MULTIPLIER */ ++ ++/* timer apis */ ++/* Note: All timer api's are thread unsafe and should be protected with locks by caller */ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) ++void ++timer_cb_compat(struct timer_list *tl) ++{ ++ timer_list_compat_t *t = container_of(tl, timer_list_compat_t, timer); ++ t->callback((ulong)t->arg); ++} ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */ ++ ++#ifdef REPORT_FATAL_TIMEOUTS ++osl_timer_t * ++osl_timer_init(osl_t *osh, const char *name, void (*fn)(void *arg), void *arg) ++{ ++ osl_timer_t *t; ++ BCM_REFERENCE(fn); ++ if ((t = MALLOCZ(NULL, sizeof(osl_timer_t))) == NULL) { ++ printk(KERN_ERR "osl_timer_init: malloced failed for osl_timer_t\n"); ++ return (NULL); ++ } ++ bzero(t, sizeof(osl_timer_t)); ++ if ((t->timer = MALLOCZ(NULL, sizeof(struct timer_list))) == NULL) { ++ printk(KERN_ERR "osl_timer_init: malloc failed\n"); ++ MFREE(NULL, t, sizeof(osl_timer_t)); ++ return (NULL); ++ } ++ t->timer->data = (ulong)arg; ++ t->timer->function = (linux_timer_fn)fn; ++ t->set = TRUE; ++ ++ init_timer(t->timer); ++ ++ return (t); ++} ++ ++void ++osl_timer_add(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic) ++{ ++ ++ if (t == NULL) { ++ printf("%s: Timer handle is NULL\n", __FUNCTION__); ++ return; ++ } ++ ASSERT(!t->set); ++ ++ t->set = TRUE; ++ if (periodic) { ++ printf("Periodic timers are not supported by Linux timer apis\n"); ++ } ++ t->timer->expires = jiffies + ms*HZ/1000; ++ ++ add_timer(t->timer); ++ ++ return; ++} ++ ++void ++osl_timer_update(osl_t *osh, osl_timer_t *t, uint32 ms, bool periodic) ++{ ++ ++ if (t == NULL) { ++ printf("%s: Timer handle is NULL\n", __FUNCTION__); ++ return; ++ } ++ if (periodic) { ++ printf("Periodic timers are not supported by Linux timer apis\n"); ++ } ++ t->set = TRUE; ++ t->timer->expires = jiffies + ms*HZ/1000; ++ ++ mod_timer(t->timer, t->timer->expires); ++ ++ return; ++} ++ ++/* ++ * Return TRUE if timer successfully deleted, FALSE if still pending ++ */ ++bool ++osl_timer_del(osl_t *osh, osl_timer_t *t) ++{ ++ if (t == NULL) { ++ printf("%s: Timer handle is NULL\n", __FUNCTION__); ++ return (FALSE); ++ } ++ if (t->set) { ++ t->set = FALSE; ++ if (t->timer) { ++ del_timer(t->timer); ++ MFREE(NULL, t->timer, sizeof(struct timer_list)); ++ } ++ MFREE(NULL, t, sizeof(osl_timer_t)); ++ } ++ return (TRUE); ++} ++#endif ++ ++void ++osl_do_gettimeofday(struct osl_timespec *ts) ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) ++ struct timespec64 curtime; ++#else ++ struct timeval curtime; ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) ++ ktime_get_real_ts64(&curtime); ++ ts->tv_nsec = curtime.tv_nsec; ++ ts->tv_usec = curtime.tv_nsec / 1000; ++#else ++ do_gettimeofday(&curtime); ++ ts->tv_usec = curtime.tv_usec; ++ ts->tv_nsec = curtime.tv_usec * 1000; ++#endif ++ ts->tv_sec = curtime.tv_sec; ++} ++ ++void ++osl_get_monotonic_boottime(struct osl_timespec *ts) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++ struct timespec64 curtime; ++#else ++ struct timeval curtime; ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) ++ ktime_get_boottime_ts64(&curtime); ++#else ++ get_monotonic_boottime(&curtime); ++#endif ++ ts->tv_sec = curtime.tv_sec; ++ ts->tv_usec = curtime.tv_nsec / 1000; ++ ts->tv_nsec = curtime.tv_nsec; ++#else ++ do_gettimeofday(&curtime); ++ ts->tv_sec = curtime.tv_sec; ++ ts->tv_usec = curtime.tv_usec; ++ ts->tv_nsec = curtime.tv_usec * 1000; ++#endif ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/pcie_core.c b/module_drivers/drivers/net/wireless/bcmdhd/pcie_core.c +new file mode 100644 +index 000000000..63f955cb6 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/pcie_core.c +@@ -0,0 +1,135 @@ ++/** @file pcie_core.c ++ * ++ * Contains PCIe related functions that are shared between different driver models (e.g. firmware ++ * builds, DHD builds, BMAC builds), in order to avoid code duplication. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: pcie_core.c 658668 2016-09-09 00:42:11Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pcie_core.h" ++ ++/* local prototypes */ ++ ++/* local variables */ ++ ++/* function definitions */ ++ ++#ifdef BCMDRIVER ++ ++void pcie_watchdog_reset(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs) ++{ ++ uint32 val, i, lsc; ++ uint16 cfg_offset[] = {PCIECFGREG_STATUS_CMD, PCIECFGREG_PM_CSR, ++ PCIECFGREG_MSI_CAP, PCIECFGREG_MSI_ADDR_L, ++ PCIECFGREG_MSI_ADDR_H, PCIECFGREG_MSI_DATA, ++ PCIECFGREG_LINK_STATUS_CTRL2, PCIECFGREG_RBAR_CTRL, ++ PCIECFGREG_PML1_SUB_CTRL1, PCIECFGREG_REG_BAR2_CONFIG, ++ PCIECFGREG_REG_BAR3_CONFIG}; ++ sbpcieregs_t *pcie = NULL; ++ uint32 origidx = si_coreidx(sih); ++ ++ /* Switch to PCIE2 core */ ++ pcie = (sbpcieregs_t *)si_setcore(sih, PCIE2_CORE_ID, 0); ++ BCM_REFERENCE(pcie); ++ ASSERT(pcie != NULL); ++ ++ /* Disable/restore ASPM Control to protect the watchdog reset */ ++ W_REG(osh, &sbpcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL); ++ lsc = R_REG(osh, &sbpcieregs->configdata); ++ val = lsc & (~PCIE_ASPM_ENAB); ++ W_REG(osh, &sbpcieregs->configdata, val); ++ ++ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, 4); ++ OSL_DELAY(100000); ++ ++ W_REG(osh, &sbpcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL); ++ W_REG(osh, &sbpcieregs->configdata, lsc); ++ ++ if (sih->buscorerev <= 13) { ++ /* Write configuration registers back to the shadow registers ++ * cause shadow registers are cleared out after watchdog reset. ++ */ ++ for (i = 0; i < ARRAYSIZE(cfg_offset); i++) { ++ W_REG(osh, &sbpcieregs->configaddr, cfg_offset[i]); ++ val = R_REG(osh, &sbpcieregs->configdata); ++ W_REG(osh, &sbpcieregs->configdata, val); ++ } ++ } ++ si_setcoreidx(sih, origidx); ++} ++ ++ ++/* CRWLPCIEGEN2-117 pcie_pipe_Iddq should be controlled ++ * by the L12 state from MAC to save power by putting the ++ * SerDes analog in IDDQ mode ++ */ ++void pcie_serdes_iddqdisable(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs) ++{ ++ sbpcieregs_t *pcie = NULL; ++ uint crwlpciegen2_117_disable = 0; ++ uint32 origidx = si_coreidx(sih); ++ ++ crwlpciegen2_117_disable = PCIE_PipeIddqDisable0 | PCIE_PipeIddqDisable1; ++ /* Switch to PCIE2 core */ ++ pcie = (sbpcieregs_t *)si_setcore(sih, PCIE2_CORE_ID, 0); ++ BCM_REFERENCE(pcie); ++ ASSERT(pcie != NULL); ++ ++ OR_REG(osh, &sbpcieregs->control, ++ crwlpciegen2_117_disable); ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++#define PCIE_PMCR_REFUP_MASK 0x3f0001e0 ++#define PCIE_PMCR_REFEXT_MASK 0x400000 ++#define PCIE_PMCR_REFUP_100US 0x38000080 ++#define PCIE_PMCR_REFEXT_100US 0x400000 ++ ++/* Set PCIE TRefUp time to 100us */ ++void pcie_set_trefup_time_100us(si_t *sih) ++{ ++ si_corereg(sih, sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, configaddr), ~0, PCI_PMCR_REFUP); ++ si_corereg(sih, sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, configdata), PCIE_PMCR_REFUP_MASK, PCIE_PMCR_REFUP_100US); ++ ++ si_corereg(sih, sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, configaddr), ~0, PCI_PMCR_REFUP_EXT); ++ si_corereg(sih, sih->buscoreidx, ++ OFFSETOF(sbpcieregs_t, configdata), PCIE_PMCR_REFEXT_MASK, PCIE_PMCR_REFEXT_100US); ++} ++#endif /* BCMDRIVER */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/sbutils.c b/module_drivers/drivers/net/wireless/bcmdhd/sbutils.c +new file mode 100644 +index 000000000..975ee6afa +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/sbutils.c +@@ -0,0 +1,1101 @@ ++/* ++ * Misc utility routines for accessing chip-specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: sbutils.c 599296 2015-11-13 06:36:13Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "siutils_priv.h" ++ ++ ++/* local prototypes */ ++static uint _sb_coreidx(si_info_t *sii, uint32 sba); ++static uint _sb_scan(si_info_t *sii, uint32 sba, volatile void *regs, uint bus, uint32 sbba, ++ uint ncores); ++static uint32 _sb_coresba(si_info_t *sii); ++static volatile void *_sb_setcoreidx(si_info_t *sii, uint coreidx); ++#define SET_SBREG(sii, r, mask, val) \ ++ W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val))) ++#define REGS2SB(va) (sbconfig_t*) ((volatile int8*)(va) + SBCONFIGOFF) ++ ++/* sonicsrev */ ++#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT) ++#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT) ++ ++#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr)) ++#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v)) ++#define AND_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v))) ++#define OR_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v))) ++ ++static uint32 ++sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr) ++{ ++ uint8 tmp; ++ uint32 val, intr_val = 0; ++ ++ ++ /* ++ * compact flash only has 11 bits address, while we needs 12 bits address. ++ * MEM_SEG will be OR'd with other 11 bits address in hardware, ++ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). ++ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special ++ */ ++ if (PCMCIA(sii)) { ++ INTR_OFF(sii, intr_val); ++ tmp = 1; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ ++ } ++ ++ val = R_REG(sii->osh, sbr); ++ ++ if (PCMCIA(sii)) { ++ tmp = 0; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ INTR_RESTORE(sii, intr_val); ++ } ++ ++ return (val); ++} ++ ++static void ++sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v) ++{ ++ uint8 tmp; ++ volatile uint32 dummy; ++ uint32 intr_val = 0; ++ ++ ++ /* ++ * compact flash only has 11 bits address, while we needs 12 bits address. ++ * MEM_SEG will be OR'd with other 11 bits address in hardware, ++ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters). ++ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special ++ */ ++ if (PCMCIA(sii)) { ++ INTR_OFF(sii, intr_val); ++ tmp = 1; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */ ++ } ++ ++ if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) { ++ dummy = R_REG(sii->osh, sbr); ++ BCM_REFERENCE(dummy); ++ W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff)); ++ dummy = R_REG(sii->osh, sbr); ++ BCM_REFERENCE(dummy); ++ W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff)); ++ } else ++ W_REG(sii->osh, sbr, v); ++ ++ if (PCMCIA(sii)) { ++ tmp = 0; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1); ++ INTR_RESTORE(sii, intr_val); ++ } ++} ++ ++uint ++sb_coreid(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT); ++} ++ ++uint ++sb_intflag(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ volatile void *corereg; ++ sbconfig_t *sb; ++ uint origidx, intflag, intr_val = 0; ++ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ corereg = si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(corereg != NULL); ++ sb = REGS2SB(corereg); ++ intflag = R_SBREG(sii, &sb->sbflagst); ++ sb_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++ ++ return intflag; ++} ++ ++uint ++sb_flag(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK; ++} ++ ++void ++sb_setint(si_t *sih, int siflag) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 vec; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ if (siflag == -1) ++ vec = 0; ++ else ++ vec = 1 << siflag; ++ W_SBREG(sii, &sb->sbintvec, vec); ++} ++ ++/* return core index of the core with address 'sba' */ ++static uint ++_sb_coreidx(si_info_t *sii, uint32 sba) ++{ ++ uint i; ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ ++ for (i = 0; i < sii->numcores; i ++) ++ if (sba == cores_info->coresba[i]) ++ return i; ++ return BADIDX; ++} ++ ++/* return core address of the current core */ ++static uint32 ++_sb_coresba(si_info_t *sii) ++{ ++ uint32 sbaddr; ++ ++ ++ switch (BUSTYPE(sii->pub.bustype)) { ++ case SI_BUS: { ++ sbconfig_t *sb = REGS2SB(sii->curmap); ++ sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0)); ++ break; ++ } ++ ++ case PCI_BUS: ++ sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); ++ break; ++ ++ case PCMCIA_BUS: { ++ uint8 tmp = 0; ++ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); ++ sbaddr = (uint32)tmp << 12; ++ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); ++ sbaddr |= (uint32)tmp << 16; ++ OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); ++ sbaddr |= (uint32)tmp << 24; ++ break; ++ } ++ ++#ifdef BCMSDIO ++ case SPI_BUS: ++ case SDIO_BUS: ++ sbaddr = (uint32)(uintptr)sii->curmap; ++ break; ++#endif ++ ++ ++ default: ++ sbaddr = BADCOREADDR; ++ break; ++ } ++ ++ return sbaddr; ++} ++ ++uint ++sb_corevendor(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT); ++} ++ ++uint ++sb_corerev(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint sbidh; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ sbidh = R_SBREG(sii, &sb->sbidhigh); ++ ++ return (SBCOREREV(sbidh)); ++} ++ ++/* set core-specific control flags */ ++void ++sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ ASSERT((val & ~mask) == 0); ++ ++ /* mask and set */ ++ w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | ++ (val << SBTML_SICF_SHIFT); ++ W_SBREG(sii, &sb->sbtmstatelow, w); ++} ++ ++/* set/clear core-specific control flags */ ++uint32 ++sb_core_cflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ ASSERT((val & ~mask) == 0); ++ ++ /* mask and set */ ++ if (mask || val) { ++ w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) | ++ (val << SBTML_SICF_SHIFT); ++ W_SBREG(sii, &sb->sbtmstatelow, w); ++ } ++ ++ /* return the new value ++ * for write operation, the following readback ensures the completion of write opration. ++ */ ++ return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT); ++} ++ ++/* set/clear core-specific status flags */ ++uint32 ++sb_core_sflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ uint32 w; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ ASSERT((val & ~mask) == 0); ++ ASSERT((mask & ~SISF_CORE_BITS) == 0); ++ ++ /* mask and set */ ++ if (mask || val) { ++ w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) | ++ (val << SBTMH_SISF_SHIFT); ++ W_SBREG(sii, &sb->sbtmstatehigh, w); ++ } ++ ++ /* return the new value */ ++ return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT); ++} ++ ++bool ++sb_iscoreup(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ return ((R_SBREG(sii, &sb->sbtmstatelow) & ++ (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) == ++ (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); ++} ++ ++/* ++ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, ++ * switch back to the original core, and return the new value. ++ * ++ * When using the silicon backplane, no fidleing with interrupts or core switches are needed. ++ * ++ * Also, when using pci/pcie, we can optimize away the core switching for pci registers ++ * and (on newer pci cores) chipcommon registers. ++ */ ++uint ++sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ++{ ++ uint origidx = 0; ++ volatile uint32 *r = NULL; ++ uint w; ++ uint intr_val = 0; ++ bool fast = FALSE; ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ ++ ASSERT(GOODIDX(coreidx)); ++ ASSERT(regoff < SI_CORE_SIZE); ++ ASSERT((val & ~mask) == 0); ++ ++ if (coreidx >= SI_MAXCORES) ++ return 0; ++ ++ if (BUSTYPE(sii->pub.bustype) == SI_BUS) { ++ /* If internal bus, we can always get at everything */ ++ fast = TRUE; ++ /* map if does not exist */ ++ if (!cores_info->regs[coreidx]) { ++ cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], ++ SI_CORE_SIZE); ++ ASSERT(GOODREGS(cores_info->regs[coreidx])); ++ } ++ r = (volatile uint32 *)((volatile uchar *)cores_info->regs[coreidx] + regoff); ++ } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { ++ /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ ++ ++ if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { ++ /* Chipc registers are mapped at 12KB */ ++ ++ fast = TRUE; ++ r = (volatile uint32 *)((volatile 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 = (volatile uint32 *)((volatile char *)sii->curmap + ++ PCI_16KB0_PCIREGS_OFFSET + regoff); ++ else ++ r = (volatile uint32 *)((volatile char *)sii->curmap + ++ ((regoff >= SBCONFIGOFF) ? ++ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + ++ regoff); ++ } ++ } ++ ++ if (!fast) { ++ INTR_OFF(sii, intr_val); ++ ++ /* save current core index */ ++ origidx = si_coreidx(&sii->pub); ++ ++ /* switch core */ ++ r = (volatile uint32*) ((volatile uchar*)sb_setcoreidx(&sii->pub, coreidx) + ++ regoff); ++ } ++ ASSERT(r != NULL); ++ ++ /* mask and set */ ++ if (mask || val) { ++ if (regoff >= SBCONFIGOFF) { ++ w = (R_SBREG(sii, r) & ~mask) | val; ++ W_SBREG(sii, r, w); ++ } else { ++ w = (R_REG(sii->osh, r) & ~mask) | val; ++ W_REG(sii->osh, r, w); ++ } ++ } ++ ++ /* readback */ ++ if (regoff >= SBCONFIGOFF) ++ w = R_SBREG(sii, r); ++ else { ++ w = R_REG(sii->osh, r); ++ } ++ ++ if (!fast) { ++ /* restore core index */ ++ if (origidx != coreidx) ++ sb_setcoreidx(&sii->pub, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++ } ++ ++ return (w); ++} ++ ++/* ++ * If there is no need for fiddling with interrupts or core switches (typically silicon ++ * back plane registers, pci registers and chipcommon registers), this function ++ * returns the register offset on this core to a mapped address. This address can ++ * be used for W_REG/R_REG directly. ++ * ++ * For accessing registers that would need a core switch, this function will return ++ * NULL. ++ */ ++volatile uint32 * ++sb_corereg_addr(si_t *sih, uint coreidx, uint regoff) ++{ ++ volatile uint32 *r = NULL; ++ bool fast = FALSE; ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ ++ ASSERT(GOODIDX(coreidx)); ++ ASSERT(regoff < SI_CORE_SIZE); ++ ++ if (coreidx >= SI_MAXCORES) ++ return 0; ++ ++ if (BUSTYPE(sii->pub.bustype) == SI_BUS) { ++ /* If internal bus, we can always get at everything */ ++ fast = TRUE; ++ /* map if does not exist */ ++ if (!cores_info->regs[coreidx]) { ++ cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], ++ SI_CORE_SIZE); ++ ASSERT(GOODREGS(cores_info->regs[coreidx])); ++ } ++ r = (volatile uint32 *)((volatile uchar *)cores_info->regs[coreidx] + regoff); ++ } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { ++ /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ ++ ++ if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { ++ /* Chipc registers are mapped at 12KB */ ++ ++ fast = TRUE; ++ r = (volatile uint32 *)((volatile 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 = (volatile uint32 *)((volatile char *)sii->curmap + ++ PCI_16KB0_PCIREGS_OFFSET + regoff); ++ else ++ r = (volatile uint32 *)((volatile char *)sii->curmap + ++ ((regoff >= SBCONFIGOFF) ? ++ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + ++ regoff); ++ } ++ } ++ ++ if (!fast) ++ return 0; ++ ++ return (r); ++} ++ ++/* Scan the enumeration space to find all cores starting from the given ++ * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' ++ * is the default core address at chip POR time and 'regs' is the virtual ++ * address that the default core is mapped at. 'ncores' is the number of ++ * cores expected on bus 'sbba'. It returns the total number of cores ++ * starting from bus 'sbba', inclusive. ++ */ ++#define SB_MAXBUSES 2 ++static uint ++_sb_scan(si_info_t *sii, uint32 sba, volatile void *regs, uint bus, ++ uint32 sbba, uint numcores) ++{ ++ uint next; ++ uint ncc = 0; ++ uint i; ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ ++ if (bus >= SB_MAXBUSES) { ++ SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus)); ++ return 0; ++ } ++ SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores)); ++ ++ /* Scan all cores on the bus starting from core 0. ++ * Core addresses must be contiguous on each bus. ++ */ ++ for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) { ++ cores_info->coresba[next] = sbba + (i * SI_CORE_SIZE); ++ ++ /* keep and reuse the initial register mapping */ ++ if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (cores_info->coresba[next] == sba)) { ++ SI_VMSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next)); ++ cores_info->regs[next] = regs; ++ } ++ ++ /* change core to 'next' and read its coreid */ ++ sii->curmap = _sb_setcoreidx(sii, next); ++ sii->curidx = next; ++ ++ cores_info->coreid[next] = sb_coreid(&sii->pub); ++ ++ /* core specific processing... */ ++ /* chipc provides # cores */ ++ if (cores_info->coreid[next] == CC_CORE_ID) { ++ chipcregs_t *cc = (chipcregs_t *)sii->curmap; ++ uint32 ccrev = sb_corerev(&sii->pub); ++ ++ /* determine numcores - this is the total # cores in the chip */ ++ if (((ccrev == 4) || (ccrev >= 6))) { ++ ASSERT(cc); ++ numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >> ++ CID_CC_SHIFT; ++ } else { ++ /* Older chips */ ++ uint chip = CHIPID(sii->pub.chip); ++ ++ if (chip == BCM4704_CHIP_ID) ++ numcores = 9; ++ else if (chip == BCM5365_CHIP_ID) ++ numcores = 7; ++ else { ++ SI_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", ++ chip)); ++ ASSERT(0); ++ numcores = 1; ++ } ++ } ++ SI_VMSG(("_sb_scan: there are %u cores in the chip %s\n", numcores, ++ sii->pub.issim ? "QT" : "")); ++ } ++ /* scan bridged SB(s) and add results to the end of the list */ ++ else if (cores_info->coreid[next] == OCP_CORE_ID) { ++ sbconfig_t *sb = REGS2SB(sii->curmap); ++ uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1); ++ uint nsbcc; ++ ++ sii->numcores = next + 1; ++ ++ if ((nsbba & 0xfff00000) != SI_ENUM_BASE) ++ continue; ++ nsbba &= 0xfffff000; ++ if (_sb_coreidx(sii, nsbba) != BADIDX) ++ continue; ++ ++ nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16; ++ nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc); ++ if (sbba == SI_ENUM_BASE) ++ numcores -= nsbcc; ++ ncc += nsbcc; ++ } ++ } ++ ++ SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba)); ++ ++ sii->numcores = i + ncc; ++ return sii->numcores; ++} ++ ++/* scan the sb enumerated space to identify all cores */ ++void ++sb_scan(si_t *sih, volatile void *regs, uint devid) ++{ ++ uint32 origsba; ++ sbconfig_t *sb; ++ si_info_t *sii = SI_INFO(sih); ++ BCM_REFERENCE(devid); ++ ++ sb = REGS2SB(sii->curmap); ++ ++ sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; ++ ++ /* Save the current core info and validate it later till we know ++ * for sure what is good and what is bad. ++ */ ++ origsba = _sb_coresba(sii); ++ ++ /* scan all SB(s) starting from SI_ENUM_BASE */ ++ sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1); ++} ++ ++/* ++ * This function changes logical "focus" to the indicated core; ++ * must be called with interrupts off. ++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core ++ */ ++volatile void * ++sb_setcoreidx(si_t *sih, uint coreidx) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ ++ if (coreidx >= sii->numcores) ++ return (NULL); ++ ++ /* ++ * If the user has provided an interrupt mask enabled function, ++ * then assert interrupts are disabled before switching the core. ++ */ ++ ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); ++ ++ sii->curmap = _sb_setcoreidx(sii, coreidx); ++ sii->curidx = coreidx; ++ ++ return (sii->curmap); ++} ++ ++/* This function changes the logical "focus" to the indicated core. ++ * Return the current core's virtual address. ++ */ ++static volatile void * ++_sb_setcoreidx(si_info_t *sii, uint coreidx) ++{ ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint32 sbaddr = cores_info->coresba[coreidx]; ++ volatile void *regs; ++ ++ switch (BUSTYPE(sii->pub.bustype)) { ++ case SI_BUS: ++ /* map new one */ ++ if (!cores_info->regs[coreidx]) { ++ cores_info->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE); ++ ASSERT(GOODREGS(cores_info->regs[coreidx])); ++ } ++ regs = cores_info->regs[coreidx]; ++ break; ++ ++ case PCI_BUS: ++ /* point bar0 window */ ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr); ++ regs = sii->curmap; ++ break; ++ ++ case PCMCIA_BUS: { ++ uint8 tmp = (sbaddr >> 12) & 0x0f; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1); ++ tmp = (sbaddr >> 16) & 0xff; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1); ++ tmp = (sbaddr >> 24) & 0xff; ++ OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1); ++ regs = sii->curmap; ++ break; ++ } ++#ifdef BCMSDIO ++ case SPI_BUS: ++ case SDIO_BUS: ++ /* map new one */ ++ if (!cores_info->regs[coreidx]) { ++ cores_info->regs[coreidx] = (void *)(uintptr)sbaddr; ++ ASSERT(GOODREGS(cores_info->regs[coreidx])); ++ } ++ regs = cores_info->regs[coreidx]; ++ break; ++#endif /* BCMSDIO */ ++ ++ ++ default: ++ ASSERT(0); ++ regs = NULL; ++ break; ++ } ++ ++ return regs; ++} ++ ++/* Return the address of sbadmatch0/1/2/3 register */ ++static volatile uint32 * ++sb_admatch(si_info_t *sii, uint asidx) ++{ ++ sbconfig_t *sb; ++ volatile uint32 *addrm; ++ ++ sb = REGS2SB(sii->curmap); ++ ++ switch (asidx) { ++ case 0: ++ addrm = &sb->sbadmatch0; ++ break; ++ ++ case 1: ++ addrm = &sb->sbadmatch1; ++ break; ++ ++ case 2: ++ addrm = &sb->sbadmatch2; ++ break; ++ ++ case 3: ++ addrm = &sb->sbadmatch3; ++ break; ++ ++ default: ++ SI_ERROR(("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx)); ++ return 0; ++ } ++ ++ return (addrm); ++} ++ ++/* Return the number of address spaces in current core */ ++int ++sb_numaddrspaces(si_t *sih) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ sb = REGS2SB(sii->curmap); ++ ++ /* + 1 because of enumeration space */ ++ return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1; ++} ++ ++/* Return the address of the nth address space in the current core */ ++uint32 ++sb_addrspace(si_t *sih, uint asidx) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx)))); ++} ++ ++/* Return the size of the nth address space in the current core */ ++uint32 ++sb_addrspacesize(si_t *sih, uint asidx) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx)))); ++} ++ ++ ++/* do buffered registers update */ ++void ++sb_commit(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ ++ origidx = sii->curidx; ++ ASSERT(GOODIDX(origidx)); ++ ++ INTR_OFF(sii, intr_val); ++ ++ /* switch over to chipcommon core if there is one, else use pci */ ++ if (sii->pub.ccrev != NOREV) { ++ chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(ccregs != NULL); ++ ++ /* do the buffer registers update */ ++ W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT); ++ W_REG(sii->osh, &ccregs->broadcastdata, 0x0); ++ } else ++ ASSERT(0); ++ ++ /* restore core index */ ++ sb_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ++sb_core_disable(si_t *sih, uint32 bits) ++{ ++ si_info_t *sii; ++ volatile uint32 dummy; ++ sbconfig_t *sb; ++ ++ sii = SI_INFO(sih); ++ ++ ASSERT(GOODREGS(sii->curmap)); ++ sb = REGS2SB(sii->curmap); ++ ++ /* if core is already in reset, just return */ ++ if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET) ++ return; ++ ++ /* if clocks are not enabled, put into reset and return */ ++ if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0) ++ goto disable; ++ ++ /* set target reject and spin until busy is clear (preserve core-specific bits) */ ++ OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000); ++ if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY) ++ SI_ERROR(("%s: target state still busy\n", __FUNCTION__)); ++ ++ if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) { ++ OR_SBREG(sii, &sb->sbimstate, SBIM_RJ); ++ dummy = R_SBREG(sii, &sb->sbimstate); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000); ++ } ++ ++ /* set reset and reject while enabling the clocks */ ++ W_SBREG(sii, &sb->sbtmstatelow, ++ (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | ++ SBTML_REJ | SBTML_RESET)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(10); ++ ++ /* don't forget to clear the initiator reject bit */ ++ if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) ++ AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ); ++ ++disable: ++ /* leave reset and reject asserted */ ++ W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET)); ++ OSL_DELAY(1); ++} ++ ++/* reset and re-enable a core ++ * inputs: ++ * bits - core specific bits that are set during and after reset sequence ++ * resetbits - core specific bits that are set only during reset sequence ++ */ ++void ++sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ++{ ++ si_info_t *sii; ++ sbconfig_t *sb; ++ volatile uint32 dummy; ++ ++ sii = SI_INFO(sih); ++ ASSERT(GOODREGS(sii->curmap)); ++ sb = REGS2SB(sii->curmap); ++ ++ /* ++ * Must do the disable sequence first to work for arbitrary current core state. ++ */ ++ sb_core_disable(sih, (bits | resetbits)); ++ ++ /* ++ * Now do the initialization sequence. ++ */ ++ ++ /* set reset while enabling the clock and forcing them on throughout the core */ ++ W_SBREG(sii, &sb->sbtmstatelow, ++ (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | ++ SBTML_RESET)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ ++ if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) { ++ W_SBREG(sii, &sb->sbtmstatehigh, 0); ++ } ++ if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) { ++ AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); ++ } ++ ++ /* clear reset and allow it to propagate throughout the core */ ++ W_SBREG(sii, &sb->sbtmstatelow, ++ ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++ ++ /* leave clock enabled */ ++ W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); ++ dummy = R_SBREG(sii, &sb->sbtmstatelow); ++ BCM_REFERENCE(dummy); ++ OSL_DELAY(1); ++} ++ ++/* ++ * Set the initiator timeout for the "master core". ++ * The master core is defined to be the core in control ++ * of the chip and so it issues accesses to non-memory ++ * locations (Because of dma *any* core can access memeory). ++ * ++ * The routine uses the bus to decide who is the master: ++ * SI_BUS => mips ++ * JTAG_BUS => chipc ++ * PCI_BUS => pci or pcie ++ * PCMCIA_BUS => pcmcia ++ * SDIO_BUS => pcmcia ++ * ++ * This routine exists so callers can disable initiator ++ * timeouts so accesses to very slow devices like otp ++ * won't cause an abort. The routine allows arbitrary ++ * settings of the service and request timeouts, though. ++ * ++ * Returns the timeout state before changing it or -1 ++ * on error. ++ */ ++ ++#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK) ++ ++uint32 ++sb_set_initiator_to(si_t *sih, uint32 to, uint idx) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ uint32 tmp, ret = 0xffffffff; ++ sbconfig_t *sb; ++ ++ ++ if ((to & ~TO_MASK) != 0) ++ return ret; ++ ++ /* Figure out the master core */ ++ if (idx == BADIDX) { ++ switch (BUSTYPE(sii->pub.bustype)) { ++ case PCI_BUS: ++ idx = sii->pub.buscoreidx; ++ break; ++ case JTAG_BUS: ++ idx = SI_CC_IDX; ++ break; ++ case PCMCIA_BUS: ++#ifdef BCMSDIO ++ case SDIO_BUS: ++#endif ++ idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0); ++ break; ++ case SI_BUS: ++ idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0); ++ break; ++ default: ++ ASSERT(0); ++ } ++ if (idx == BADIDX) ++ return ret; ++ } ++ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ sb = REGS2SB(sb_setcoreidx(sih, idx)); ++ ++ tmp = R_SBREG(sii, &sb->sbimconfiglow); ++ ret = tmp & TO_MASK; ++ W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to); ++ ++ sb_commit(sih); ++ sb_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++ return ret; ++} ++ ++uint32 ++sb_base(uint32 admatch) ++{ ++ uint32 base; ++ uint type; ++ ++ type = admatch & SBAM_TYPE_MASK; ++ ASSERT(type < 3); ++ ++ base = 0; ++ ++ if (type == 0) { ++ base = admatch & SBAM_BASE0_MASK; ++ } else if (type == 1) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ base = admatch & SBAM_BASE1_MASK; ++ } else if (type == 2) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ base = admatch & SBAM_BASE2_MASK; ++ } ++ ++ return (base); ++} ++ ++uint32 ++sb_size(uint32 admatch) ++{ ++ uint32 size; ++ uint type; ++ ++ type = admatch & SBAM_TYPE_MASK; ++ ASSERT(type < 3); ++ ++ size = 0; ++ ++ if (type == 0) { ++ size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1); ++ } else if (type == 1) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1); ++ } else if (type == 2) { ++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ ++ size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1); ++ } ++ ++ return (size); ++} ++ ++#if defined(BCMDBG_PHYDUMP) ++/* print interesting sbconfig registers */ ++void ++sb_dumpregs(si_t *sih, struct bcmstrbuf *b) ++{ ++ sbconfig_t *sb; ++ uint origidx, i, intr_val = 0; ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ ++ origidx = sii->curidx; ++ ++ INTR_OFF(sii, intr_val); ++ ++ for (i = 0; i < sii->numcores; i++) { ++ sb = REGS2SB(sb_setcoreidx(sih, i)); ++ ++ bcm_bprintf(b, "core 0x%x: \n", cores_info->coreid[i]); ++ ++ if (sii->pub.socirev > SONICS_2_2) ++ bcm_bprintf(b, "sbimerrlog 0x%x sbimerrloga 0x%x\n", ++ sb_corereg(sih, si_coreidx(&sii->pub), SBIMERRLOG, 0, 0), ++ sb_corereg(sih, si_coreidx(&sii->pub), SBIMERRLOGA, 0, 0)); ++ ++ bcm_bprintf(b, "sbtmstatelow 0x%x sbtmstatehigh 0x%x sbidhigh 0x%x " ++ "sbimstate 0x%x\n sbimconfiglow 0x%x sbimconfighigh 0x%x\n", ++ R_SBREG(sii, &sb->sbtmstatelow), R_SBREG(sii, &sb->sbtmstatehigh), ++ R_SBREG(sii, &sb->sbidhigh), R_SBREG(sii, &sb->sbimstate), ++ R_SBREG(sii, &sb->sbimconfiglow), R_SBREG(sii, &sb->sbimconfighigh)); ++ } ++ ++ sb_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++} ++#endif +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/siutils.c b/module_drivers/drivers/net/wireless/bcmdhd/siutils.c +new file mode 100644 +index 000000000..3d8ec54a7 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/siutils.c +@@ -0,0 +1,3727 @@ ++/* ++ * Misc utility routines for accessing chip-specific features ++ * of the SiliconBackplane-based Broadcom chips. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: siutils.c 668442 2016-11-03 08:42:43Z $ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef BCMPCIEDEV ++#include ++#endif /* BCMPCIEDEV */ ++#include ++#include ++#include ++#include ++#ifdef BCMSDIO ++#include ++#include ++#include ++#include ++#include ++#include ++#endif /* BCMSDIO */ ++#include ++#include ++ ++#ifdef BCM_SDRBL ++#include ++#endif /* BCM_SDRBL */ ++#ifdef HNDGCI ++#include ++#endif /* HNDGCI */ ++#ifdef BCMULP ++#include ++#endif /* BCMULP */ ++ ++ ++#include "siutils_priv.h" ++#ifdef SECI_UART ++/* Defines the set of GPIOs to be used for SECI UART if not specified in NVRAM */ ++#define DEFAULT_SECI_UART_PINMUX_43430 0x0102 ++static bool force_seci_clk = 0; ++#endif /* SECI_UART */ ++ ++/** ++ * A set of PMU registers is clocked in the ILP domain, which has an implication on register write ++ * behavior: if such a register is written, it takes multiple ILP clocks for the PMU block to absorb ++ * the write. During that time the 'SlowWritePending' bit in the PMUStatus register is set. ++ */ ++#define PMUREGS_ILP_SENSITIVE(regoff) \ ++ ((regoff) == OFFSETOF(pmuregs_t, pmutimer) || \ ++ (regoff) == OFFSETOF(pmuregs_t, pmuwatchdog) || \ ++ (regoff) == OFFSETOF(pmuregs_t, res_req_timer)) ++ ++#define CHIPCREGS_ILP_SENSITIVE(regoff) \ ++ ((regoff) == OFFSETOF(chipcregs_t, pmutimer) || \ ++ (regoff) == OFFSETOF(chipcregs_t, pmuwatchdog) || \ ++ (regoff) == OFFSETOF(chipcregs_t, res_req_timer)) ++ ++#define GCI_FEM_CTRL_WAR 0x11111111 ++ ++/* local prototypes */ ++static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs, ++ uint bustype, void *sdh, char **vars, uint *varsz); ++static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); ++static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, ++ uint *origidx, volatile void *regs); ++ ++ ++static bool si_pmu_is_ilp_sensitive(uint32 idx, uint regoff); ++ ++ ++ ++/* global variable to indicate reservation/release of gpio's */ ++static uint32 si_gpioreservation = 0; ++ ++/* global flag to prevent shared resources from being initialized multiple times in si_attach() */ ++static bool si_onetimeinit = FALSE; ++ ++#ifdef SR_DEBUG ++static const uint32 si_power_island_test_array[] = { ++ 0x0000, 0x0001, 0x0010, 0x0011, ++ 0x0100, 0x0101, 0x0110, 0x0111, ++ 0x1000, 0x1001, 0x1010, 0x1011, ++ 0x1100, 0x1101, 0x1110, 0x1111 ++}; ++#endif /* SR_DEBUG */ ++ ++int do_4360_pcie2_war = 0; ++ ++#ifdef BCMULP ++/* Variable to store boot_type: warm_boot/cold_boot/etc. */ ++static int boot_type = 0; ++#endif ++ ++/* global kernel resource */ ++static si_info_t ksii; ++static si_cores_info_t ksii_cores_info; ++ ++static const char rstr_rmin[] = "rmin"; ++static const char rstr_rmax[] = "rmax"; ++ ++/** ++ * Allocate an si handle. This function may be called multiple times. ++ * ++ * devid - pci device id (used to determine chip#) ++ * osh - opaque OS handle ++ * regs - virtual address of initial core registers ++ * bustype - pci/pcmcia/sb/sdio/etc ++ * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this ++ * function set 'vars' to NULL, making dereferencing of this parameter undesired. ++ * varsz - pointer to int to return the size of the vars ++ */ ++si_t * ++si_attach(uint devid, osl_t *osh, volatile void *regs, ++ uint bustype, void *sdh, char **vars, uint *varsz) ++{ ++ si_info_t *sii; ++ si_cores_info_t *cores_info; ++ /* alloc si_info_t */ ++ if ((sii = MALLOCZ(osh, sizeof (si_info_t))) == NULL) { ++ SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); ++ return (NULL); ++ } ++ ++ /* alloc si_cores_info_t */ ++ if ((cores_info = (si_cores_info_t *)MALLOCZ(osh, sizeof (si_cores_info_t))) == NULL) { ++ SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh))); ++ MFREE(osh, sii, sizeof(si_info_t)); ++ return (NULL); ++ } ++ sii->cores_info = cores_info; ++ ++ if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) { ++ MFREE(osh, sii, sizeof(si_info_t)); ++ MFREE(osh, cores_info, sizeof(si_cores_info_t)); ++ return (NULL); ++ } ++ sii->vars = vars ? *vars : NULL; ++ sii->varsz = varsz ? *varsz : 0; ++ ++ return (si_t *)sii; ++} ++ ++ ++static uint32 wd_msticks; /**< watchdog timer ticks normalized to ms */ ++ ++/** generic kernel variant of si_attach() */ ++si_t * ++si_kattach(osl_t *osh) ++{ ++ static bool ksii_attached = FALSE; ++ si_cores_info_t *cores_info; ++ ++ if (!ksii_attached) { ++ void *regs = NULL; ++ regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); ++ cores_info = (si_cores_info_t *)&ksii_cores_info; ++ ksii.cores_info = cores_info; ++ ++ ASSERT(osh); ++ if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs, ++ SI_BUS, NULL, ++ osh != SI_OSH ? &(ksii.vars) : NULL, ++ osh != SI_OSH ? &(ksii.varsz) : NULL) == NULL) { ++ SI_ERROR(("si_kattach: si_doattach failed\n")); ++ REG_UNMAP(regs); ++ return NULL; ++ } ++ REG_UNMAP(regs); ++ ++ /* save ticks normalized to ms for si_watchdog_ms() */ ++ if (PMUCTL_ENAB(&ksii.pub)) { ++ { ++ /* based on 32KHz ILP clock */ ++ wd_msticks = 32; ++ } ++ } else { ++ wd_msticks = ALP_CLOCK / 1000; ++ } ++ ++ ksii_attached = TRUE; ++ SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n", ++ CCREV(ksii.pub.ccrev), wd_msticks)); ++ } ++ ++ return &ksii.pub; ++} ++ ++static bool ++si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh) ++{ ++ BCM_REFERENCE(sdh); ++ BCM_REFERENCE(devid); ++ /* need to set memseg flag for CF card first before any sb registers access */ ++ if (BUSTYPE(bustype) == PCMCIA_BUS) ++ sii->memseg = TRUE; ++ ++ ++#if defined(BCMSDIO) ++ if (BUSTYPE(bustype) == SDIO_BUS) { ++ int err; ++ uint8 clkset; ++ ++ /* Try forcing SDIO core to do ALPAvail request only */ ++ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); ++ if (!err) { ++ uint8 clkval; ++ ++ /* If register supported, wait for ALPAvail and then force ALP */ ++ clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL); ++ if ((clkval & ~SBSDIO_AVBITS) == clkset) { ++ SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, ++ SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), ++ PMU_MAX_TRANSITION_DLY); ++ if (!SBSDIO_ALPAV(clkval)) { ++ SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n", ++ clkval)); ++ return FALSE; ++ } ++ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, ++ clkset, &err); ++ OSL_DELAY(65); ++ } ++ } ++ ++ /* Also, disable the extra SDIO pull-ups */ ++ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); ++ } ++ ++#endif /* BCMSDIO && BCMDONGLEHOST */ ++ ++ return TRUE; ++} ++ ++uint32 ++si_get_pmu_reg_addr(si_t *sih, uint32 offset) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint32 pmuaddr = INVALID_ADDR; ++ uint origidx = 0; ++ ++ SI_MSG(("%s: pmu access, offset: %x\n", __FUNCTION__, offset)); ++ if (!(sii->pub.cccaps & CC_CAP_PMU)) { ++ goto done; ++ } ++ if (AOB_ENAB(&sii->pub)) { ++ uint pmucoreidx; ++ pmuregs_t *pmu; ++ SI_MSG(("%s: AOBENAB: %x\n", __FUNCTION__, offset)); ++ origidx = sii->curidx; ++ pmucoreidx = si_findcoreidx(&sii->pub, PMU_CORE_ID, 0); ++ pmu = si_setcoreidx(&sii->pub, pmucoreidx); ++ pmuaddr = (uint32)(uintptr)((volatile uint8*)pmu + offset); ++ si_setcoreidx(sih, origidx); ++ } else ++ pmuaddr = SI_ENUM_BASE + offset; ++ ++done: ++ SI_MSG(("%s: addrRET: %x\n", __FUNCTION__, pmuaddr)); ++ return pmuaddr; ++} ++ ++static bool ++si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, ++ uint *origidx, volatile void *regs) ++{ ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ bool pci, pcie, pcie_gen2 = FALSE; ++ uint i; ++ uint pciidx, pcieidx, pcirev, pcierev; ++ ++#if defined(BCM_BACKPLANE_TIMEOUT) || defined(AXI_TIMEOUTS) ++ /* first, enable backplane timeouts */ ++ si_slave_wrapper_add(&sii->pub); ++#endif ++ sii->curidx = 0; ++ ++ cc = si_setcoreidx(&sii->pub, SI_CC_IDX); ++ ASSERT((uintptr)cc); ++ ++ /* get chipcommon rev */ ++ sii->pub.ccrev = (int)si_corerev(&sii->pub); ++ ++ /* get chipcommon chipstatus */ ++ if (CCREV(sii->pub.ccrev) >= 11) ++ sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); ++ ++ /* get chipcommon capabilites */ ++ sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); ++ /* get chipcommon extended capabilities */ ++ ++ if (CCREV(sii->pub.ccrev) >= 35) ++ sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); ++ ++ /* get pmu rev and caps */ ++ if (sii->pub.cccaps & CC_CAP_PMU) { ++ if (AOB_ENAB(&sii->pub)) { ++ uint pmucoreidx; ++ pmuregs_t *pmu; ++ struct si_pub *sih = &sii->pub; ++ ++ pmucoreidx = si_findcoreidx(&sii->pub, PMU_CORE_ID, 0); ++ if (!GOODIDX(pmucoreidx)) { ++ SI_ERROR(("si_buscore_setup: si_findcoreidx failed\n")); ++ return FALSE; ++ } ++ ++ pmu = si_setcoreidx(&sii->pub, pmucoreidx); ++ sii->pub.pmucaps = R_REG(sii->osh, &pmu->pmucapabilities); ++ si_setcoreidx(&sii->pub, SI_CC_IDX); ++ ++ sii->pub.gcirev = si_corereg(sih, ++ GCI_CORE_IDX(sih), ++ GCI_OFFSETOF(sih, gci_corecaps0), 0, 0) & GCI_CAP0_REV_MASK; ++ } else ++ sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); ++ ++ sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; ++ } ++ ++ SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", ++ CCREV(sii->pub.ccrev), sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, ++ sii->pub.pmucaps)); ++ ++ /* figure out bus/orignal core idx */ ++ sii->pub.buscoretype = NODEV_CORE_ID; ++ sii->pub.buscorerev = (uint)NOREV; ++ sii->pub.buscoreidx = BADIDX; ++ ++ pci = pcie = FALSE; ++ pcirev = pcierev = (uint)NOREV; ++ pciidx = pcieidx = BADIDX; ++ ++ for (i = 0; i < sii->numcores; i++) { ++ uint cid, crev; ++ ++ si_setcoreidx(&sii->pub, i); ++ cid = si_coreid(&sii->pub); ++ crev = si_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, cores_info->coresba[i], cores_info->regs[i])); ++ ++ if (BUSTYPE(bustype) == SI_BUS) { ++ /* now look at the chipstatus register to figure the pacakge */ ++ /* for SDIO but downloaded on PCIE dev */ ++ if (cid == PCIE2_CORE_ID) { ++ if (BCM43602_CHIP(sii->pub.chip) || ++ (CHIPID(sii->pub.chip) == BCM4365_CHIP_ID) || ++ (CHIPID(sii->pub.chip) == BCM4347_CHIP_ID) || ++ (CHIPID(sii->pub.chip) == BCM4366_CHIP_ID) || ++ ((BCM4345_CHIP(sii->pub.chip) || ++ BCM4349_CHIP(sii->pub.chip)) && ++ CST4345_CHIPMODE_PCIE(sii->pub.chipst))) { ++ pcieidx = i; ++ pcierev = crev; ++ pcie = TRUE; ++ pcie_gen2 = TRUE; ++ } ++ } ++ ++ } else if (BUSTYPE(bustype) == PCI_BUS) { ++ if (cid == PCI_CORE_ID) { ++ pciidx = i; ++ pcirev = crev; ++ pci = TRUE; ++ } else if ((cid == PCIE_CORE_ID) || (cid == PCIE2_CORE_ID)) { ++ pcieidx = i; ++ pcierev = crev; ++ pcie = TRUE; ++ if (cid == PCIE2_CORE_ID) ++ pcie_gen2 = TRUE; ++ } ++ } else if ((BUSTYPE(bustype) == PCMCIA_BUS) && ++ (cid == PCMCIA_CORE_ID)) { ++ sii->pub.buscorerev = crev; ++ sii->pub.buscoretype = cid; ++ sii->pub.buscoreidx = i; ++ } ++#ifdef BCMSDIO ++ else if (((BUSTYPE(bustype) == SDIO_BUS) || ++ (BUSTYPE(bustype) == SPI_BUS)) && ++ ((cid == PCMCIA_CORE_ID) || ++ (cid == SDIOD_CORE_ID))) { ++ sii->pub.buscorerev = crev; ++ sii->pub.buscoretype = cid; ++ sii->pub.buscoreidx = i; ++ } ++#endif /* BCMSDIO */ ++ ++ /* find the core idx before entering this func. */ ++ if ((savewin && (savewin == cores_info->coresba[i])) || ++ (regs == cores_info->regs[i])) ++ *origidx = i; ++ } ++ ++ ++#if defined(PCIE_FULL_DONGLE) ++ if (pcie) { ++ if (pcie_gen2) ++ sii->pub.buscoretype = PCIE2_CORE_ID; ++ else ++ sii->pub.buscoretype = PCIE_CORE_ID; ++ sii->pub.buscorerev = pcierev; ++ sii->pub.buscoreidx = pcieidx; ++ } ++ BCM_REFERENCE(pci); ++ BCM_REFERENCE(pcirev); ++ BCM_REFERENCE(pciidx); ++#else ++ if (pci) { ++ sii->pub.buscoretype = PCI_CORE_ID; ++ sii->pub.buscorerev = pcirev; ++ sii->pub.buscoreidx = pciidx; ++ } else if (pcie) { ++ if (pcie_gen2) ++ sii->pub.buscoretype = PCIE2_CORE_ID; ++ else ++ sii->pub.buscoretype = PCIE_CORE_ID; ++ sii->pub.buscorerev = pcierev; ++ sii->pub.buscoreidx = pcieidx; ++ } ++#endif /* defined(PCIE_FULL_DONGLE) */ ++ ++ SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype, ++ sii->pub.buscorerev)); ++ ++ ++#if defined(BCMSDIO) ++ /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was ++ * already running. ++ */ ++ if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { ++ if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || ++ si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) ++ si_core_disable(&sii->pub, 0); ++ } ++#endif /* BCMSDIO && BCMDONGLEHOST */ ++ ++ /* return to the original core */ ++ si_setcoreidx(&sii->pub, *origidx); ++ ++ return TRUE; ++} ++ ++ ++ ++ ++ ++uint16 ++si_chipid(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ ++ return (sii->chipnew) ? sii->chipnew : sih->chip; ++} ++ ++/* CHIP_ID's being mapped here should not be used anywhere else in the code */ ++static void ++si_chipid_fixup(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ ++ ASSERT(sii->chipnew == 0); ++ switch (sih->chip) { ++ case BCM43567_CHIP_ID: ++ sii->chipnew = sih->chip; /* save it */ ++ sii->pub.chip = BCM43570_CHIP_ID; /* chip class */ ++ break; ++ case BCM43562_CHIP_ID: ++ case BCM4358_CHIP_ID: ++ case BCM43566_CHIP_ID: ++ sii->chipnew = sih->chip; /* save it */ ++ sii->pub.chip = BCM43569_CHIP_ID; /* chip class */ ++ break; ++ case BCM4356_CHIP_ID: ++ case BCM4371_CHIP_ID: ++ sii->chipnew = sih->chip; /* save it */ ++ sii->pub.chip = BCM4354_CHIP_ID; /* chip class */ ++ break; ++ case BCM4357_CHIP_ID: ++ case BCM4361_CHIP_ID: ++ sii->chipnew = sih->chip; /* save it */ ++ sii->pub.chip = BCM4347_CHIP_ID; /* chip class */ ++ break; ++ default: ++ break; ++ } ++} ++ ++#ifdef BCMULP ++static void ++si_check_boot_type(si_t *sih, osl_t *osh) ++{ ++ if (sih->pmurev >= 30) { ++ boot_type = PMU_REG_NEW(sih, swscratch, 0, 0); ++ } else { ++ boot_type = CHIPC_REG(sih, flashdata, 0, 0); ++ } ++ ++ SI_ERROR(("%s: boot_type: 0x%08x\n", __func__, boot_type)); ++} ++#endif /* BCMULP */ ++ ++/** ++ * Allocate an si handle. This function may be called multiple times. ++ * ++ * vars - pointer to a to-be created pointer area for "environment" variables. Some callers of this ++ * function set 'vars' to NULL. ++ */ ++static si_info_t * ++si_doattach(si_info_t *sii, uint devid, osl_t *osh, volatile void *regs, ++ uint bustype, void *sdh, char **vars, uint *varsz) ++{ ++ struct si_pub *sih = &sii->pub; ++ uint32 w, savewin; ++ chipcregs_t *cc; ++ char *pvars = NULL; ++ uint origidx; ++#if !defined(_CFEZ_) || defined(CFG_WL) ++#endif ++ ++ ASSERT(GOODREGS(regs)); ++ ++ savewin = 0; ++ ++ sih->buscoreidx = BADIDX; ++ sii->device_removed = FALSE; ++ ++ sii->curmap = regs; ++ sii->sdh = sdh; ++ sii->osh = osh; ++ sii->second_bar0win = ~0x0; ++ ++#if defined(BCM_BACKPLANE_TIMEOUT) ++ sih->err_info = MALLOCZ(osh, sizeof(si_axi_error_info_t)); ++ if (sih->err_info == NULL) { ++ SI_ERROR(("%s: %d bytes MALLOC FAILED", ++ __FUNCTION__, sizeof(si_axi_error_info_t))); ++ return NULL; ++ } ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++ ++ /* check to see if we are a si core mimic'ing a pci core */ ++ if ((bustype == PCI_BUS) && ++ (OSL_PCI_READ_CONFIG(sii->osh, PCI_SPROM_CONTROL, sizeof(uint32)) == 0xffffffff)) { ++ SI_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SI " ++ "devid:0x%x\n", __FUNCTION__, devid)); ++ bustype = SI_BUS; ++ } ++ ++ /* find Chipcommon address */ ++ if (bustype == PCI_BUS) { ++ savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); ++ if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) ++ savewin = SI_ENUM_BASE; ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE); ++ if (!regs) ++ return NULL; ++ cc = (chipcregs_t *)regs; ++#ifdef BCMSDIO ++ } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) { ++ cc = (chipcregs_t *)sii->curmap; ++#endif ++ } else { ++ cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); ++ } ++ ++ sih->bustype = bustype; ++#ifdef BCMBUSTYPE ++ if (bustype != BUSTYPE(bustype)) { ++ SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", ++ bustype, BUSTYPE(bustype))); ++ return NULL; ++ } ++#endif ++ ++ /* bus/core/clk setup for register access */ ++ if (!si_buscore_prep(sii, bustype, devid, sdh)) { ++ SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype)); ++ return NULL; ++ } ++ ++ /* ChipID recognition. ++ * We assume we can read chipid at offset 0 from the regs arg. ++ * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon), ++ * some way of recognizing them needs to be added here. ++ */ ++ if (!cc) { ++ SI_ERROR(("%s: chipcommon register space is null \n", __FUNCTION__)); ++ return NULL; ++ } ++ w = R_REG(osh, &cc->chipid); ++ if ((w & 0xfffff) == 148277) w -= 65532; ++ sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; ++ /* Might as wll fill in chip id rev & pkg */ ++ sih->chip = w & CID_ID_MASK; ++ sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; ++ sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; ++ ++#if defined(BCMSDIO) && (defined(HW_OOB) || defined(FORCE_WOWLAN)) ++ dhd_conf_set_hw_oob_intr(sdh, sih->chip); ++#endif ++ ++ si_chipid_fixup(sih); ++ ++ sih->issim = IS_SIM(sih->chippkg); ++ ++ /* scan for cores */ ++ if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) { ++ SI_MSG(("Found chip type SB (0x%08x)\n", w)); ++ sb_scan(&sii->pub, regs, devid); ++ } else if ((CHIPTYPE(sii->pub.socitype) == SOCI_AI) || ++ (CHIPTYPE(sii->pub.socitype) == SOCI_NAI)) { ++ if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) ++ SI_MSG(("Found chip type AI (0x%08x)\n", w)); ++ else ++ SI_MSG(("Found chip type NAI (0x%08x)\n", w)); ++ /* pass chipc address instead of original core base */ ++ ++ sii->axi_wrapper = (axi_wrapper_t *)MALLOCZ(sii->osh, ++ (sizeof(axi_wrapper_t) * SI_MAX_AXI_WRAPPERS)); ++ ++ if (sii->axi_wrapper == NULL) { ++ SI_ERROR(("%s: %zu bytes MALLOC Failed", __FUNCTION__, ++ (sizeof(axi_wrapper_t) * SI_MAX_AXI_WRAPPERS))); ++ return NULL; ++ } ++ ++ ai_scan(&sii->pub, (void *)(uintptr)cc, devid); ++ } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) { ++ SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip)); ++ /* pass chipc address instead of original core base */ ++ ub_scan(&sii->pub, (void *)(uintptr)cc, devid); ++ } else { ++ SI_ERROR(("Found chip of unknown type (0x%08x)\n", w)); ++ return NULL; ++ } ++ /* no cores found, bail out */ ++ if (sii->numcores == 0) { ++ SI_ERROR(("si_doattach: could not find any cores\n")); ++ return NULL; ++ } ++ /* bus/core/clk setup */ ++ origidx = SI_CC_IDX; ++ if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { ++ SI_ERROR(("si_doattach: si_buscore_setup failed\n")); ++ goto exit; ++ } ++#ifdef BCMULP ++ si_check_boot_type(sih, osh); ++ ++ if (ulp_module_init(osh, sih) != BCME_OK) { ++ ULP_ERR(("%s: err in ulp_module_init\n", __FUNCTION__)); ++ goto exit; ++ } ++#endif /* BCMULP */ ++ ++#if !defined(_CFEZ_) || defined(CFG_WL) ++ /* assume current core is CC */ ++ if ((CCREV(sii->pub.ccrev) == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || ++ CHIPID(sih->chip) == BCM43235_CHIP_ID || ++ CHIPID(sih->chip) == BCM43234_CHIP_ID || ++ CHIPID(sih->chip) == BCM43238_CHIP_ID) && ++ (CHIPREV(sii->pub.chiprev) <= 2))) { ++ ++ if ((cc->chipstatus & CST43236_BP_CLK) != 0) { ++ uint clkdiv; ++ clkdiv = R_REG(osh, &cc->clkdiv); ++ /* otp_clk_div is even number, 120/14 < 9mhz */ ++ clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); ++ W_REG(osh, &cc->clkdiv, clkdiv); ++ SI_ERROR(("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv)); ++ } ++ OSL_DELAY(10); ++ } ++ ++ if (bustype == PCI_BUS) { ++ ++ } ++#endif ++#ifdef BCM_SDRBL ++ /* 4360 rom bootloader in PCIE case, if the SDR is enabled, But preotection is ++ * not turned on, then we want to hold arm in reset. ++ * Bottomline: In sdrenable case, we allow arm to boot only when protection is ++ * turned on. ++ */ ++ if (CHIP_HOSTIF_PCIE(&(sii->pub))) { ++ uint32 sflags = si_arm_sflags(&(sii->pub)); ++ ++ /* If SDR is enabled but protection is not turned on ++ * then we want to force arm to WFI. ++ */ ++ if ((sflags & (SISF_SDRENABLE | SISF_TCMPROT)) == SISF_SDRENABLE) { ++ disable_arm_irq(); ++ while (1) { ++ hnd_cpu_wait(sih); ++ } ++ } ++ } ++#endif /* BCM_SDRBL */ ++ ++ pvars = NULL; ++ BCM_REFERENCE(pvars); ++ ++ if (!si_onetimeinit) { ++ ++ ++ if (CCREV(sii->pub.ccrev) >= 20) { ++ uint32 gpiopullup = 0, gpiopulldown = 0; ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(cc != NULL); ++ ++ /* 4314/43142 has pin muxing, don't clear gpio bits */ ++ if ((CHIPID(sih->chip) == BCM4314_CHIP_ID) || ++ (CHIPID(sih->chip) == BCM43142_CHIP_ID)) { ++ gpiopullup |= 0x402e0; ++ gpiopulldown |= 0x20500; ++ } ++ ++ ++ W_REG(osh, &cc->gpiopullup, gpiopullup); ++ W_REG(osh, &cc->gpiopulldown, gpiopulldown); ++ si_setcoreidx(sih, origidx); ++ } ++ ++ } ++ ++ /* clear any previous epidiag-induced target abort */ ++ ASSERT(!si_taclear(sih, FALSE)); ++ ++ ++#ifdef BOOTLOADER_CONSOLE_OUTPUT ++ /* Enable console prints */ ++ si_muxenab(sii, 3); ++#endif ++ ++ return (sii); ++ ++exit: ++ ++ return NULL; ++} ++ ++/** may be called with core in reset */ ++void ++si_detach(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint idx; ++ ++ ++ if (BUSTYPE(sih->bustype) == SI_BUS) ++ for (idx = 0; idx < SI_MAXCORES; idx++) ++ if (cores_info->regs[idx]) { ++ REG_UNMAP(cores_info->regs[idx]); ++ cores_info->regs[idx] = NULL; ++ } ++ ++ ++#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) ++ if (cores_info != &ksii_cores_info) ++#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ ++ MFREE(sii->osh, cores_info, sizeof(si_cores_info_t)); ++ ++#if defined(BCM_BACKPLANE_TIMEOUT) ++ if (sih->err_info) { ++ MFREE(sii->osh, sih->err_info, sizeof(si_axi_error_info_t)); ++ sii->pub.err_info = NULL; ++ } ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++ if (sii->axi_wrapper) { ++ MFREE(sii->osh, sii->axi_wrapper, ++ (sizeof(axi_wrapper_t) * SI_MAX_AXI_WRAPPERS)); ++ sii->axi_wrapper = NULL; ++ } ++ ++#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) ++ if (sii != &ksii) ++#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ ++ MFREE(sii->osh, sii, sizeof(si_info_t)); ++} ++ ++void * ++si_osh(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ return sii->osh; ++} ++ ++void ++si_setosh(si_t *sih, osl_t *osh) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ if (sii->osh != NULL) { ++ SI_ERROR(("osh is already set....\n")); ++ ASSERT(!sii->osh); ++ } ++ sii->osh = osh; ++} ++ ++/** register driver interrupt disabling and restoring callback functions */ ++void ++si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, ++ void *intrsenabled_fn, void *intr_arg) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ 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; ++ /* save current core id. when this function called, the current core ++ * must be the core which provides driver functions(il, et, wl, etc.) ++ */ ++ sii->dev_coreid = cores_info->coreid[sii->curidx]; ++} ++ ++void ++si_deregister_intr_callback(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ sii->intrsoff_fn = NULL; ++ sii->intrsrestore_fn = NULL; ++ sii->intrsenabled_fn = NULL; ++} ++ ++uint ++si_intflag(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_intflag(sih); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return R_REG(sii->osh, ((uint32 *)(uintptr) ++ (sii->oob_router + OOB_STATUSA))); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++uint ++si_flag(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_flag(sih); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_flag(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_flag(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++uint ++si_flag_alt(si_t *sih) ++{ ++ if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_flag_alt(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_setint(si_t *sih, int siflag) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_setint(sih, siflag); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ ai_setint(sih, siflag); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_setint(sih, siflag); ++ else ++ ASSERT(0); ++} ++ ++uint ++si_coreid(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ ++ return cores_info->coreid[sii->curidx]; ++} ++ ++uint ++si_coreidx(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ return sii->curidx; ++} ++ ++volatile void * ++si_d11_switch_addrbase(si_t *sih, uint coreunit) ++{ ++ return si_setcore(sih, D11_CORE_ID, coreunit); ++} ++ ++/** return the core-type instantiation # of the current core */ ++uint ++si_coreunit(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint idx; ++ uint coreid; ++ uint coreunit; ++ uint i; ++ ++ coreunit = 0; ++ ++ idx = sii->curidx; ++ ++ ASSERT(GOODREGS(sii->curmap)); ++ coreid = si_coreid(sih); ++ ++ /* count the cores of our type */ ++ for (i = 0; i < idx; i++) ++ if (cores_info->coreid[i] == coreid) ++ coreunit++; ++ ++ return (coreunit); ++} ++ ++uint ++si_corevendor(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_corevendor(sih); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_corevendor(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_corevendor(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++bool ++si_backplane64(si_t *sih) ++{ ++ return ((sih->cccaps & CC_CAP_BKPLN64) != 0); ++} ++ ++uint ++si_corerev(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_corerev(sih); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_corerev(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_corerev(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++/* return index of coreid or BADIDX if not found */ ++uint ++si_findcoreidx(si_t *sih, uint coreid, uint coreunit) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint found; ++ uint i; ++ ++ ++ found = 0; ++ ++ for (i = 0; i < sii->numcores; i++) ++ if (cores_info->coreid[i] == coreid) { ++ if (found == coreunit) ++ return (i); ++ found++; ++ } ++ ++ return (BADIDX); ++} ++ ++/** return total coreunit of coreid or zero if not found */ ++uint ++si_numcoreunits(si_t *sih, uint coreid) ++{ ++ if ((CHIPID(sih->chip) == BCM4347_CHIP_ID) && ++ (CHIPREV(sih->chiprev) == 0)) { ++ /* ++ * 4347TC2 does not have Aux core. ++ * fixed to 1 here because EROM (using 4349 EROM) has two entries ++ */ ++ return 1; ++ } else { ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ uint found = 0; ++ uint i; ++ ++ for (i = 0; i < sii->numcores; i++) { ++ if (cores_info->coreid[i] == coreid) { ++ found++; ++ } ++ } ++ ++ return found; ++ } ++} ++ ++/** return total D11 coreunits */ ++uint ++BCMRAMFN(si_numd11coreunits)(si_t *sih) ++{ ++ uint found = 0; ++ ++ found = si_numcoreunits(sih, D11_CORE_ID); ++ ++#if defined(WLRSDB) && defined(WLRSDB_DISABLED) ++ /* If RSDB functionality is compiled out, ++ * then ignore any D11 cores beyond the first ++ * Used in norsdb dongle build variants for rsdb chip. ++ */ ++ found = 1; ++#endif /* defined(WLRSDB) && !defined(WLRSDB_DISABLED) */ ++ ++ return found; ++} ++ ++/** return list of found cores */ ++uint ++si_corelist(si_t *sih, uint coreid[]) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; ++ ++ bcopy((uchar*)cores_info->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint))); ++ return (sii->numcores); ++} ++ ++/** return current wrapper mapping */ ++void * ++si_wrapperregs(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ASSERT(GOODREGS(sii->curwrap)); ++ ++ return (sii->curwrap); ++} ++ ++/** return current register mapping */ ++volatile void * ++si_coreregs(si_t *sih) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ASSERT(GOODREGS(sii->curmap)); ++ ++ return (sii->curmap); ++} ++ ++ ++/** ++ * This function changes logical "focus" to the indicated core; ++ * must be called with interrupts off. ++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core ++ */ ++volatile void * ++si_setcore(si_t *sih, uint coreid, uint coreunit) ++{ ++ uint idx; ++ ++ idx = si_findcoreidx(sih, coreid, coreunit); ++ if (!GOODIDX(idx)) ++ return (NULL); ++ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_setcoreidx(sih, idx); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_setcoreidx(sih, idx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_setcoreidx(sih, idx); ++ else { ++ ASSERT(0); ++ return NULL; ++ } ++} ++ ++volatile void * ++si_setcoreidx(si_t *sih, uint coreidx) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_setcoreidx(sih, coreidx); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_setcoreidx(sih, coreidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_setcoreidx(sih, coreidx); ++ else { ++ ASSERT(0); ++ return NULL; ++ } ++} ++ ++/** Turn off interrupt as required by sb_setcore, before switch core */ ++volatile void * ++si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) ++{ ++ volatile void *cc; ++ si_info_t *sii = SI_INFO(sih); ++ ++ if (SI_FAST(sii)) { ++ /* Overloading the origidx variable to remember the coreid, ++ * this works because the core ids cannot be confused with ++ * core indices. ++ */ ++ *origidx = coreid; ++ if (coreid == CC_CORE_ID) ++ return (volatile void *)CCREGS_FAST(sii); ++ else if (coreid == BUSCORETYPE(sih->buscoretype)) ++ return (volatile void *)PCIEREGS(sii); ++ } ++ INTR_OFF(sii, *intr_val); ++ *origidx = sii->curidx; ++ cc = si_setcore(sih, coreid, 0); ++ ASSERT(cc != NULL); ++ ++ return cc; ++} ++ ++/* restore coreidx and restore interrupt */ ++void ++si_restore_core(si_t *sih, uint coreid, uint intr_val) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ ++ if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == BUSCORETYPE(sih->buscoretype)))) ++ return; ++ ++ si_setcoreidx(sih, coreid); ++ INTR_RESTORE(sii, intr_val); ++} ++ ++int ++si_numaddrspaces(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_numaddrspaces(sih); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_numaddrspaces(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_numaddrspaces(sih); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++uint32 ++si_addrspace(si_t *sih, uint asidx) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_addrspace(sih, asidx); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_addrspace(sih, asidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_addrspace(sih, asidx); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++uint32 ++si_addrspacesize(si_t *sih, uint asidx) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_addrspacesize(sih, asidx); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_addrspacesize(sih, asidx); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_addrspacesize(sih, asidx); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) ++{ ++ /* Only supported for SOCI_AI */ ++ if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ ai_coreaddrspaceX(sih, asidx, addr, size); ++ else ++ *size = 0; ++} ++ ++uint32 ++si_core_cflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_core_cflags(sih, mask, val); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_core_cflags(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_core_cflags(sih, mask, val); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_core_cflags_wo(sih, mask, val); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ ai_core_cflags_wo(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_core_cflags_wo(sih, mask, val); ++ else ++ ASSERT(0); ++} ++ ++uint32 ++si_core_sflags(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_core_sflags(sih, mask, val); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_core_sflags(sih, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_core_sflags(sih, mask, val); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++void ++si_commit(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_commit(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_AI || CHIPTYPE(sih->socitype) == SOCI_NAI) ++ ; ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ; ++ else { ++ ASSERT(0); ++ } ++} ++ ++bool ++si_iscoreup(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_iscoreup(sih); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_iscoreup(sih); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_iscoreup(sih); ++ else { ++ ASSERT(0); ++ return FALSE; ++ } ++} ++ ++uint ++si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val) ++{ ++ /* only for AI back plane chips */ ++ if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return (ai_wrap_reg(sih, offset, mask, val)); ++ return 0; ++} ++/* si_backplane_access is used to read full backplane address from host for PCIE FD ++ * it uses secondary bar-0 window which lies at an offset of 16K from primary bar-0 ++ * Provides support for read/write of 1/2/4 bytes of backplane address ++ * Can be used to read/write ++ * 1. core regs ++ * 2. Wrapper regs ++ * 3. memory ++ * 4. BT area ++ * For accessing any 32 bit backplane address, [31 : 12] of backplane should be given in "region" ++ * [11 : 0] should be the "regoff" ++ * for reading 4 bytes from reg 0x200 of d11 core use it like below ++ * : si_backplane_access(sih, 0x18001000, 0x200, 4, 0, TRUE) ++ */ ++static int si_backplane_addr_sane(uint addr, uint size) ++{ ++ int bcmerror = BCME_OK; ++ ++ /* For 2 byte access, address has to be 2 byte aligned */ ++ if (size == 2) { ++ if (addr & 0x1) { ++ bcmerror = BCME_ERROR; ++ } ++ } ++ /* For 4 byte access, address has to be 4 byte aligned */ ++ if (size == 4) { ++ if (addr & 0x3) { ++ bcmerror = BCME_ERROR; ++ } ++ } ++ return bcmerror; ++} ++ ++void ++si_invalidate_second_bar0win(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ sii->second_bar0win = ~0x0; ++} ++ ++uint ++si_backplane_access(si_t *sih, uint addr, uint size, uint *val, bool read) ++{ ++ volatile uint32 *r = NULL; ++ uint32 region = 0; ++ si_info_t *sii = SI_INFO(sih); ++ ++ /* Valid only for pcie bus */ ++ if (BUSTYPE(sih->bustype) != PCI_BUS) { ++ SI_ERROR(("Valid only for pcie bus \n")); ++ return BCME_ERROR; ++ } ++ ++ /* Split adrr into region and address offset */ ++ region = (addr & (0xFFFFF << 12)); ++ addr = addr & 0xFFF; ++ ++ /* check for address and size sanity */ ++ if (si_backplane_addr_sane(addr, size) != BCME_OK) ++ return BCME_ERROR; ++ ++ /* Update window if required */ ++ if (sii->second_bar0win != region) { ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_CORE2_WIN, 4, region); ++ sii->second_bar0win = region; ++ } ++ ++ /* Estimate effective address ++ * sii->curmap : bar-0 virtual address ++ * PCI_SECOND_BAR0_OFFSET : secondar bar-0 offset ++ * regoff : actual reg offset ++ */ ++ r = (volatile uint32 *)((volatile char *)sii->curmap + PCI_SECOND_BAR0_OFFSET + addr); ++ ++ SI_VMSG(("si curmap %p region %x regaddr %x effective addr %p READ %d\n", ++ (volatile char*)sii->curmap, region, addr, r, read)); ++ ++ switch (size) { ++ case sizeof(uint8) : ++ if (read) ++ *val = R_REG(sii->osh, (volatile uint8*)r); ++ else ++ W_REG(sii->osh, (volatile uint8*)r, *val); ++ break; ++ case sizeof(uint16) : ++ if (read) ++ *val = R_REG(sii->osh, (volatile uint16*)r); ++ else ++ W_REG(sii->osh, (volatile uint16*)r, *val); ++ break; ++ case sizeof(uint32) : ++ if (read) ++ *val = R_REG(sii->osh, (volatile uint32*)r); ++ else ++ W_REG(sii->osh, (volatile uint32*)r, *val); ++ break; ++ default : ++ SI_ERROR(("Invalid size %d \n", size)); ++ return (BCME_ERROR); ++ break; ++ } ++ ++ return (BCME_OK); ++} ++uint ++si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_corereg(sih, coreidx, regoff, mask, val); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_corereg(sih, coreidx, regoff, mask, val); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ return ub_corereg(sih, coreidx, regoff, mask, val); ++ else { ++ ASSERT(0); ++ return 0; ++ } ++} ++ ++/** ILP sensitive register access needs special treatment to avoid backplane stalls */ ++bool si_pmu_is_ilp_sensitive(uint32 idx, uint regoff) ++{ ++ if (idx == SI_CC_IDX) { ++ if (CHIPCREGS_ILP_SENSITIVE(regoff)) ++ return TRUE; ++ } else if (PMUREGS_ILP_SENSITIVE(regoff)) { ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/** 'idx' should refer either to the chipcommon core or the PMU core */ ++uint ++si_pmu_corereg(si_t *sih, uint32 idx, uint regoff, uint mask, uint val) ++{ ++ int pmustatus_offset; ++ ++ /* prevent backplane stall on double write to 'ILP domain' registers in the PMU */ ++ if (mask != 0 && PMUREV(sih->pmurev) >= 22 && ++ si_pmu_is_ilp_sensitive(idx, regoff)) { ++ pmustatus_offset = AOB_ENAB(sih) ? OFFSETOF(pmuregs_t, pmustatus) : ++ OFFSETOF(chipcregs_t, pmustatus); ++ ++ while (si_corereg(sih, idx, pmustatus_offset, 0, 0) & PST_SLOW_WR_PENDING) ++ {}; ++ } ++ ++ return si_corereg(sih, idx, regoff, mask, val); ++} ++ ++/* ++ * If there is no need for fiddling with interrupts or core switches (typically silicon ++ * back plane registers, pci registers and chipcommon registers), this function ++ * returns the register offset on this core to a mapped address. This address can ++ * be used for W_REG/R_REG directly. ++ * ++ * For accessing registers that would need a core switch, this function will return ++ * NULL. ++ */ ++volatile uint32 * ++si_corereg_addr(si_t *sih, uint coreidx, uint regoff) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ return sb_corereg_addr(sih, coreidx, regoff); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ return ai_corereg_addr(sih, coreidx, regoff); ++ else { ++ return 0; ++ } ++} ++ ++void ++si_core_disable(si_t *sih, uint32 bits) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_core_disable(sih, bits); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ ai_core_disable(sih, bits); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_core_disable(sih, bits); ++} ++ ++void ++si_core_reset(si_t *sih, uint32 bits, uint32 resetbits) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_SB) ++ sb_core_reset(sih, bits, resetbits); ++ else if ((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI)) ++ ai_core_reset(sih, bits, resetbits); ++ else if (CHIPTYPE(sih->socitype) == SOCI_UBUS) ++ ub_core_reset(sih, bits, resetbits); ++} ++ ++/** Run bist on current core. Caller needs to take care of core-specific bist hazards */ ++int ++si_corebist(si_t *sih) ++{ ++ uint32 cflags; ++ int result = 0; ++ ++ /* Read core control flags */ ++ cflags = si_core_cflags(sih, 0, 0); ++ ++ /* Set bist & fgc */ ++ si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC)); ++ ++ /* Wait for bist done */ ++ SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000); ++ ++ if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR) ++ result = BCME_ERROR; ++ ++ /* Reset core control flags */ ++ si_core_cflags(sih, 0xffff, cflags); ++ ++ return result; ++} ++ ++uint ++si_num_slaveports(si_t *sih, uint coreid) ++{ ++ uint idx = si_findcoreidx(sih, coreid, 0); ++ uint num = 0; ++ ++ if ((CHIPTYPE(sih->socitype) == SOCI_AI)) ++ num = ai_num_slaveports(sih, idx); ++ ++ return num; ++} ++ ++uint32 ++si_get_slaveport_addr(si_t *sih, uint asidx, uint core_id, uint coreunit) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx = sii->curidx; ++ uint32 addr = 0x0; ++ ++ if (!((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI))) ++ goto done; ++ ++ si_setcore(sih, core_id, coreunit); ++ ++ addr = ai_addrspace(sih, asidx); ++ ++ si_setcoreidx(sih, origidx); ++ ++done: ++ return addr; ++} ++ ++uint32 ++si_get_d11_slaveport_addr(si_t *sih, uint asidx, uint coreunit) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx = sii->curidx; ++ uint32 addr = 0x0; ++ ++ if (!((CHIPTYPE(sih->socitype) == SOCI_AI) || (CHIPTYPE(sih->socitype) == SOCI_NAI))) ++ goto done; ++ ++ si_setcore(sih, D11_CORE_ID, coreunit); ++ ++ addr = ai_addrspace(sih, asidx); ++ ++ si_setcoreidx(sih, origidx); ++ ++done: ++ return addr; ++} ++ ++static uint32 ++factor6(uint32 x) ++{ ++ switch (x) { ++ case CC_F6_2: return 2; ++ case CC_F6_3: return 3; ++ case CC_F6_4: return 4; ++ case CC_F6_5: return 5; ++ case CC_F6_6: return 6; ++ case CC_F6_7: return 7; ++ default: return 0; ++ } ++} ++ ++/* ++ * Divide the clock by the divisor with protection for ++ * a zero divisor. ++ */ ++static uint32 ++divide_clock(uint32 clock, uint32 div) ++{ ++ return div ? clock / div : 0; ++} ++ ++ ++/** calculate the speed the SI would run at given a set of clockcontrol values */ ++uint32 ++si_clock_rate(uint32 pll_type, uint32 n, uint32 m) ++{ ++ uint32 n1, n2, clock, m1, m2, m3, mc; ++ ++ n1 = n & CN_N1_MASK; ++ n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT; ++ ++ if (pll_type == PLL_TYPE6) { ++ if (m & CC_T6_MMASK) ++ return CC_T6_M1; ++ else ++ return CC_T6_M0; ++ } else if ((pll_type == PLL_TYPE1) || ++ (pll_type == PLL_TYPE3) || ++ (pll_type == PLL_TYPE4) || ++ (pll_type == PLL_TYPE7)) { ++ n1 = factor6(n1); ++ n2 += CC_F5_BIAS; ++ } else if (pll_type == PLL_TYPE2) { ++ n1 += CC_T2_BIAS; ++ n2 += CC_T2_BIAS; ++ ASSERT((n1 >= 2) && (n1 <= 7)); ++ ASSERT((n2 >= 5) && (n2 <= 23)); ++ } else if (pll_type == PLL_TYPE5) { ++ return (100000000); ++ } else ++ ASSERT(0); ++ /* PLL types 3 and 7 use BASE2 (25Mhz) */ ++ if ((pll_type == PLL_TYPE3) || ++ (pll_type == PLL_TYPE7)) { ++ clock = CC_CLOCK_BASE2 * n1 * n2; ++ } else ++ clock = CC_CLOCK_BASE1 * n1 * n2; ++ ++ if (clock == 0) ++ return 0; ++ ++ m1 = m & CC_M1_MASK; ++ m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT; ++ m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT; ++ mc = (m & CC_MC_MASK) >> CC_MC_SHIFT; ++ ++ if ((pll_type == PLL_TYPE1) || ++ (pll_type == PLL_TYPE3) || ++ (pll_type == PLL_TYPE4) || ++ (pll_type == PLL_TYPE7)) { ++ m1 = factor6(m1); ++ if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3)) ++ m2 += CC_F5_BIAS; ++ else ++ m2 = factor6(m2); ++ m3 = factor6(m3); ++ ++ switch (mc) { ++ case CC_MC_BYPASS: return (clock); ++ case CC_MC_M1: return divide_clock(clock, m1); ++ case CC_MC_M1M2: return divide_clock(clock, m1 * m2); ++ case CC_MC_M1M2M3: return divide_clock(clock, m1 * m2 * m3); ++ case CC_MC_M1M3: return divide_clock(clock, m1 * m3); ++ default: return (0); ++ } ++ } else { ++ ASSERT(pll_type == PLL_TYPE2); ++ ++ m1 += CC_T2_BIAS; ++ m2 += CC_T2M2_BIAS; ++ m3 += CC_T2_BIAS; ++ ASSERT((m1 >= 2) && (m1 <= 7)); ++ ASSERT((m2 >= 3) && (m2 <= 10)); ++ ASSERT((m3 >= 2) && (m3 <= 7)); ++ ++ if ((mc & CC_T2MC_M1BYP) == 0) ++ clock /= m1; ++ if ((mc & CC_T2MC_M2BYP) == 0) ++ clock /= m2; ++ if ((mc & CC_T2MC_M3BYP) == 0) ++ clock /= m3; ++ ++ return (clock); ++ } ++} ++ ++/** ++ * Some chips could have multiple host interfaces, however only one will be active. ++ * For a given chip. Depending pkgopt and cc_chipst return the active host interface. ++ */ ++uint ++si_chip_hostif(si_t *sih) ++{ ++ uint hosti = 0; ++ ++ switch (CHIPID(sih->chip)) { ++ case BCM43018_CHIP_ID: ++ case BCM43430_CHIP_ID: ++ hosti = CHIP_HOSTIF_SDIOMODE; ++ break; ++ case BCM43012_CHIP_ID: ++ hosti = CHIP_HOSTIF_SDIOMODE; ++ break; ++ CASE_BCM43602_CHIP: ++ hosti = CHIP_HOSTIF_PCIEMODE; ++ break; ++ ++ case BCM4360_CHIP_ID: ++ /* chippkg bit-0 == 0 is PCIE only pkgs ++ * chippkg bit-0 == 1 has both PCIE and USB cores enabled ++ */ ++ if ((sih->chippkg & 0x1) && (sih->chipst & CST4360_MODE_USB)) ++ hosti = CHIP_HOSTIF_USBMODE; ++ else ++ hosti = CHIP_HOSTIF_PCIEMODE; ++ ++ break; ++ ++ case BCM4335_CHIP_ID: ++ /* TBD: like in 4360, do we need to check pkg? */ ++ if (CST4335_CHIPMODE_USB20D(sih->chipst)) ++ hosti = CHIP_HOSTIF_USBMODE; ++ else if (CST4335_CHIPMODE_SDIOD(sih->chipst)) ++ hosti = CHIP_HOSTIF_SDIOMODE; ++ else ++ hosti = CHIP_HOSTIF_PCIEMODE; ++ break; ++ ++ CASE_BCM4345_CHIP: ++ if (CST4345_CHIPMODE_USB20D(sih->chipst) || CST4345_CHIPMODE_HSIC(sih->chipst)) ++ hosti = CHIP_HOSTIF_USBMODE; ++ else if (CST4345_CHIPMODE_SDIOD(sih->chipst)) ++ hosti = CHIP_HOSTIF_SDIOMODE; ++ else if (CST4345_CHIPMODE_PCIE(sih->chipst)) ++ hosti = CHIP_HOSTIF_PCIEMODE; ++ break; ++ ++ case BCM4349_CHIP_GRPID: ++ case BCM53573_CHIP_GRPID: ++ if (CST4349_CHIPMODE_SDIOD(sih->chipst)) ++ hosti = CHIP_HOSTIF_SDIOMODE; ++ else if (CST4349_CHIPMODE_PCIE(sih->chipst)) ++ hosti = CHIP_HOSTIF_PCIEMODE; ++ break; ++ case BCM4347_CHIP_ID: ++ if (CST4347_CHIPMODE_SDIOD(sih->chipst)) ++ hosti = CHIP_HOSTIF_SDIOMODE; ++ else if (CST4347_CHIPMODE_PCIE(sih->chipst)) ++ hosti = CHIP_HOSTIF_PCIEMODE; ++ break; ++ ++ case BCM4350_CHIP_ID: ++ case BCM4354_CHIP_ID: ++ case BCM43556_CHIP_ID: ++ case BCM43558_CHIP_ID: ++ case BCM43566_CHIP_ID: ++ case BCM43568_CHIP_ID: ++ case BCM43569_CHIP_ID: ++ case BCM43570_CHIP_ID: ++ case BCM4358_CHIP_ID: ++ if (CST4350_CHIPMODE_USB20D(sih->chipst) || ++ CST4350_CHIPMODE_HSIC20D(sih->chipst) || ++ CST4350_CHIPMODE_USB30D(sih->chipst) || ++ CST4350_CHIPMODE_USB30D_WL(sih->chipst) || ++ CST4350_CHIPMODE_HSIC30D(sih->chipst)) ++ hosti = CHIP_HOSTIF_USBMODE; ++ else if (CST4350_CHIPMODE_SDIOD(sih->chipst)) ++ hosti = CHIP_HOSTIF_SDIOMODE; ++ else if (CST4350_CHIPMODE_PCIE(sih->chipst)) ++ hosti = CHIP_HOSTIF_PCIEMODE; ++ break; ++ ++ default: ++ break; ++ } ++ ++ return hosti; ++} ++ ++ ++/** set chip watchdog reset timer to fire in 'ticks' */ ++void ++si_watchdog(si_t *sih, uint ticks) ++{ ++ uint nb, maxt; ++ uint pmu_wdt = 1; ++ ++ ++ if (PMUCTL_ENAB(sih) && pmu_wdt) { ++ nb = (CCREV(sih->ccrev) < 26) ? 16 : ((CCREV(sih->ccrev) >= 37) ? 32 : 24); ++ /* The mips compiler uses the sllv instruction, ++ * so we specially handle the 32-bit case. ++ */ ++ if (nb == 32) ++ maxt = 0xffffffff; ++ else ++ maxt = ((1 << nb) - 1); ++ ++ if (ticks == 1) ++ ticks = 2; ++ else if (ticks > maxt) ++ ticks = maxt; ++ if (CHIPID(sih->chip) == BCM43012_CHIP_ID) { ++ PMU_REG_NEW(sih, min_res_mask, ~0, DEFAULT_43012_MIN_RES_MASK); ++ PMU_REG_NEW(sih, watchdog_res_mask, ~0, DEFAULT_43012_MIN_RES_MASK); ++ PMU_REG_NEW(sih, pmustatus, PST_WDRESET, PST_WDRESET); ++ PMU_REG_NEW(sih, pmucontrol_ext, PCTL_EXT_FASTLPO_SWENAB, 0); ++ SPINWAIT((PMU_REG(sih, pmustatus, 0, 0) & PST_ILPFASTLPO), ++ PMU_MAX_TRANSITION_DLY); ++ } ++ ++ pmu_corereg(sih, SI_CC_IDX, pmuwatchdog, ~0, ticks); ++ } else { ++ maxt = (1 << 28) - 1; ++ if (ticks > maxt) ++ ticks = maxt; ++ ++ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks); ++ } ++} ++ ++/** trigger watchdog reset after ms milliseconds */ ++void ++si_watchdog_ms(si_t *sih, uint32 ms) ++{ ++ si_watchdog(sih, wd_msticks * ms); ++} ++ ++uint32 si_watchdog_msticks(void) ++{ ++ return wd_msticks; ++} ++ ++bool ++si_taclear(si_t *sih, bool details) ++{ ++ return FALSE; ++} ++ ++ ++ ++/** return the slow clock source - LPO, XTAL, or PCI */ ++static uint ++si_slowclk_src(si_info_t *sii) ++{ ++ chipcregs_t *cc; ++ ++ ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); ++ ++ if (CCREV(sii->pub.ccrev) < 6) { ++ if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) && ++ (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) & ++ PCI_CFG_GPIO_SCS)) ++ return (SCC_SS_PCI); ++ else ++ return (SCC_SS_XTAL); ++ } else if (CCREV(sii->pub.ccrev) < 10) { ++ cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); ++ ASSERT(cc); ++ return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); ++ } else /* Insta-clock */ ++ return (SCC_SS_XTAL); ++} ++ ++/** return the ILP (slowclock) min or max frequency */ ++static uint ++si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) ++{ ++ uint32 slowclk; ++ uint div; ++ ++ ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); ++ ++ /* shouldn't be here unless we've established the chip has dynamic clk control */ ++ ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL); ++ ++ slowclk = si_slowclk_src(sii); ++ if (CCREV(sii->pub.ccrev) < 6) { ++ if (slowclk == SCC_SS_PCI) ++ return (max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64)); ++ else ++ return (max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32)); ++ } else if (CCREV(sii->pub.ccrev) < 10) { ++ div = 4 * ++ (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1); ++ if (slowclk == SCC_SS_LPO) ++ return (max_freq ? LPOMAXFREQ : LPOMINFREQ); ++ else if (slowclk == SCC_SS_XTAL) ++ return (max_freq ? (XTALMAXFREQ / div) : (XTALMINFREQ / div)); ++ else if (slowclk == SCC_SS_PCI) ++ return (max_freq ? (PCIMAXFREQ / div) : (PCIMINFREQ / div)); ++ else ++ ASSERT(0); ++ } else { ++ /* Chipc rev 10 is InstaClock */ ++ div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; ++ div = 4 * (div + 1); ++ return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div)); ++ } ++ return (0); ++} ++ ++static void ++si_clkctl_setdelay(si_info_t *sii, void *chipcregs) ++{ ++ chipcregs_t *cc = (chipcregs_t *)chipcregs; ++ uint slowmaxfreq, pll_delay, slowclk; ++ uint pll_on_delay, fref_sel_delay; ++ ++ pll_delay = PLL_DELAY; ++ ++ /* If the slow clock is not sourced by the xtal then add the xtal_on_delay ++ * since the xtal will also be powered down by dynamic clk control logic. ++ */ ++ ++ slowclk = si_slowclk_src(sii); ++ if (slowclk != SCC_SS_XTAL) ++ pll_delay += XTAL_ON_DELAY; ++ ++ /* Starting with 4318 it is ILP that is used for the delays */ ++ slowmaxfreq = si_slowclk_freq(sii, (CCREV(sii->pub.ccrev) >= 10) ? FALSE : TRUE, cc); ++ ++ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; ++ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; ++ ++ W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay); ++ W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); ++} ++ ++/** initialize power control delay registers */ ++void ++si_clkctl_init(si_t *sih) ++{ ++ si_info_t *sii; ++ uint origidx = 0; ++ chipcregs_t *cc; ++ bool fast; ++ ++ if (!CCCTL_ENAB(sih)) ++ return; ++ ++ sii = SI_INFO(sih); ++ fast = SI_FAST(sii); ++ if (!fast) { ++ origidx = sii->curidx; ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) ++ return; ++ } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) ++ return; ++ ASSERT(cc != NULL); ++ ++ /* set all Instaclk chip ILP to 1 MHz */ ++ if (CCREV(sih->ccrev) >= 10) ++ SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK, ++ (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); ++ ++ si_clkctl_setdelay(sii, (void *)(uintptr)cc); ++ ++ OSL_DELAY(20000); ++ ++ if (!fast) ++ si_setcoreidx(sih, origidx); ++} ++ ++ ++/** change logical "focus" to the gpio core for optimized access */ ++volatile void * ++si_gpiosetcore(si_t *sih) ++{ ++ return (si_setcoreidx(sih, SI_CC_IDX)); ++} ++ ++/** ++ * mask & set gpiocontrol bits. ++ * If a gpiocontrol bit is set to 0, chipcommon controls the corresponding GPIO pin. ++ * If a gpiocontrol bit is set to 1, the GPIO pin is no longer a GPIO and becomes dedicated ++ * to some chip-specific purpose. ++ */ ++uint32 ++si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 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) && ++ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpiocontrol); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/** mask&set gpio output enable bits */ ++uint32 ++si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 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) && ++ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpioouten); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/** mask&set gpio output bits */ ++uint32 ++si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 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) && ++ (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpioout); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/** reserve one gpio */ ++uint32 ++si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority) ++{ ++ /* only cores on SI_BUS share GPIO's and only applcation users need to ++ * reserve/release GPIO ++ */ ++ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { ++ ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); ++ return 0xffffffff; ++ } ++ /* make sure only one bit is set */ ++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { ++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); ++ return 0xffffffff; ++ } ++ ++ /* already reserved */ ++ if (si_gpioreservation & gpio_bitmask) ++ return 0xffffffff; ++ /* set reservation */ ++ si_gpioreservation |= gpio_bitmask; ++ ++ return si_gpioreservation; ++} ++ ++/** ++ * release one gpio. ++ * ++ * releasing the gpio doesn't change the current value on the GPIO last write value ++ * persists till someone overwrites it. ++ */ ++uint32 ++si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority) ++{ ++ /* only cores on SI_BUS share GPIO's and only applcation users need to ++ * reserve/release GPIO ++ */ ++ if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) { ++ ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority)); ++ return 0xffffffff; ++ } ++ /* make sure only one bit is set */ ++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) { ++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1))); ++ return 0xffffffff; ++ } ++ ++ /* already released */ ++ if (!(si_gpioreservation & gpio_bitmask)) ++ return 0xffffffff; ++ ++ /* clear reservation */ ++ si_gpioreservation &= ~gpio_bitmask; ++ ++ return si_gpioreservation; ++} ++ ++/* return the current gpioin register value */ ++uint32 ++si_gpioin(si_t *sih) ++{ ++ uint regoff; ++ ++ regoff = OFFSETOF(chipcregs_t, gpioin); ++ return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0)); ++} ++ ++/* mask&set gpio interrupt polarity bits */ ++uint32 ++si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ /* gpios could be shared on router platforms */ ++ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpiointpolarity); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* mask&set gpio interrupt mask bits */ ++uint32 ++si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ ++ /* gpios could be shared on router platforms */ ++ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ ++ regoff = OFFSETOF(chipcregs_t, gpiointmask); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++uint32 ++si_gpioeventintmask(si_t *sih, uint32 mask, uint32 val, uint8 priority) ++{ ++ uint regoff; ++ /* gpios could be shared on router platforms */ ++ if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { ++ mask = priority ? (si_gpioreservation & mask) : ++ ((si_gpioreservation | mask) & ~(si_gpioreservation)); ++ val &= mask; ++ } ++ regoff = OFFSETOF(chipcregs_t, gpioeventintmask); ++ return (si_corereg(sih, SI_CC_IDX, regoff, mask, val)); ++} ++ ++/* assign the gpio to an led */ ++uint32 ++si_gpioled(si_t *sih, uint32 mask, uint32 val) ++{ ++ if (CCREV(sih->ccrev) < 16) ++ return 0xffffffff; ++ ++ /* gpio led powersave reg */ ++ return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val)); ++} ++ ++/* mask&set gpio timer val */ ++uint32 ++si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval) ++{ ++ if (CCREV(sih->ccrev) < 16) ++ return 0xffffffff; ++ ++ return (si_corereg(sih, SI_CC_IDX, ++ OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval)); ++} ++ ++uint32 ++si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val) ++{ ++ uint offs; ++ ++ if (CCREV(sih->ccrev) < 20) ++ return 0xffffffff; ++ ++ offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup)); ++ return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); ++} ++ ++uint32 ++si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val) ++{ ++ uint offs; ++ ++ if (CCREV(sih->ccrev) < 11) ++ return 0xffffffff; ++ ++ if (regtype == GPIO_REGEVT) ++ offs = OFFSETOF(chipcregs_t, gpioevent); ++ else if (regtype == GPIO_REGEVT_INTMSK) ++ offs = OFFSETOF(chipcregs_t, gpioeventintmask); ++ else if (regtype == GPIO_REGEVT_INTPOL) ++ offs = OFFSETOF(chipcregs_t, gpioeventintpolarity); ++ else ++ return 0xffffffff; ++ ++ return (si_corereg(sih, SI_CC_IDX, offs, mask, val)); ++} ++ ++uint32 ++si_gpio_int_enable(si_t *sih, bool enable) ++{ ++ uint offs; ++ ++ if (CCREV(sih->ccrev) < 11) ++ return 0xffffffff; ++ ++ offs = OFFSETOF(chipcregs_t, intmask); ++ return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0))); ++} ++ ++/** Return the size of the specified SYSMEM bank */ ++static uint ++sysmem_banksize(si_info_t *sii, sysmemregs_t *regs, uint8 idx) ++{ ++ uint banksize, bankinfo; ++ uint bankidx = idx; ++ ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ banksize = SYSMEM_BANKINFO_SZBASE * ((bankinfo & SYSMEM_BANKINFO_SZMASK) + 1); ++ return banksize; ++} ++ ++/** Return the RAM size of the SYSMEM core */ ++uint32 ++si_sysmem_size(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ ++ sysmemregs_t *regs; ++ bool wasup; ++ uint32 coreinfo; ++ uint memsize = 0; ++ uint8 i; ++ uint nb, nrb; ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SYSMEM core */ ++ if (!(regs = si_setcore(sih, SYSMEM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ coreinfo = R_REG(sii->osh, ®s->coreinfo); ++ ++ /* Number of ROM banks, SW need to skip the ROM banks. */ ++ nrb = (coreinfo & SYSMEM_SRCI_ROMNB_MASK) >> SYSMEM_SRCI_ROMNB_SHIFT; ++ ++ nb = (coreinfo & SYSMEM_SRCI_SRNB_MASK) >> SYSMEM_SRCI_SRNB_SHIFT; ++ for (i = 0; i < nb; i++) ++ memsize += sysmem_banksize(sii, regs, i + nrb); ++ ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++/** Return the size of the specified SOCRAM bank */ ++static uint ++socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 idx, uint8 mem_type) ++{ ++ uint banksize, bankinfo; ++ uint bankidx = idx | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ ++ ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); ++ ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); ++ return banksize; ++} ++ ++void si_socram_set_bankpda(si_t *sih, uint32 bankidx, uint32 bankpda) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 16) { ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ W_REG(sii->osh, ®s->bankpda, bankpda); ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ++si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect, uint8 *remap) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ if (!set) ++ *enable = *protect = *remap = 0; ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 10) { ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ uint32 bankidx, bankinfo; ++ ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); ++ for (i = 0; i < nb; i++) { ++ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ if (set) { ++ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK; ++ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK; ++ bankinfo &= ~SOCRAM_BANKINFO_DEVRAMREMAP_MASK; ++ if (*enable) { ++ bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT); ++ if (*protect) ++ bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT); ++ if ((corerev >= 16) && *remap) ++ bankinfo |= ++ (1 << SOCRAM_BANKINFO_DEVRAMREMAP_SHIFT); ++ } ++ W_REG(sii->osh, ®s->bankinfo, bankinfo); ++ } else if (i == 0) { ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) { ++ *enable = 1; ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK) ++ *protect = 1; ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) ++ *remap = 1; ++ } ++ } ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++} ++ ++bool ++si_socdevram_remap_isenb(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ sbsocramregs_t *regs; ++ bool wasup, remap = FALSE; ++ uint corerev; ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ uint32 bankidx, bankinfo; ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 16) { ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT); ++ for (i = 0; i < nb; i++) { ++ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { ++ remap = TRUE; ++ break; ++ } ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ return remap; ++} ++ ++bool ++si_socdevram_pkg(si_t *sih) ++{ ++ if (si_socdevram_size(sih) > 0) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++uint32 ++si_socdevram_size(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ uint32 memsize = 0; ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 10) { ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); ++ for (i = 0; i < nb; i++) ++ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++uint32 ++si_socdevram_remap_size(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ uint32 memsize = 0, banksz; ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ uint32 extcinfo; ++ uint8 nb; ++ uint8 i; ++ uint32 bankidx, bankinfo; ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ ++ corerev = si_corerev(sih); ++ if (corerev >= 16) { ++ extcinfo = R_REG(sii->osh, ®s->extracoreinfo); ++ nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT)); ++ ++ /* ++ * FIX: A0 Issue: Max addressable is 512KB, instead 640KB ++ * Only four banks are accessible to ARM ++ */ ++ if ((corerev == 16) && (nb == 5)) ++ nb = 4; ++ ++ for (i = 0; i < nb; i++) { ++ bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); ++ W_REG(sii->osh, ®s->bankidx, bankidx); ++ bankinfo = R_REG(sii->osh, ®s->bankinfo); ++ if (bankinfo & SOCRAM_BANKINFO_DEVRAMREMAP_MASK) { ++ banksz = socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM); ++ memsize += banksz; ++ } else { ++ /* Account only consecutive banks for now */ ++ break; ++ } ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++/** Return the RAM size of the SOCRAM core */ ++uint32 ++si_socram_size(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ uint32 coreinfo; ++ uint memsize = 0; ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ corerev = si_corerev(sih); ++ coreinfo = R_REG(sii->osh, ®s->coreinfo); ++ ++ /* Calculate size from coreinfo based on rev */ ++ if (corerev == 0) ++ memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); ++ else if (corerev < 3) { ++ memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); ++ memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ } else if ((corerev <= 7) || (corerev == 12)) { ++ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ uint bsz = (coreinfo & SRCI_SRBSZ_MASK); ++ uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; ++ if (lss != 0) ++ nb --; ++ memsize = nb * (1 << (bsz + SR_BSZ_BASE)); ++ if (lss != 0) ++ memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); ++ } else { ++ uint8 i; ++ uint nb; ++ /* length of SRAM Banks increased for corerev greater than 23 */ ++ if (corerev >= 23) { ++ nb = (coreinfo & (SRCI_SRNB_MASK | SRCI_SRNB_MASK_EXT)) >> SRCI_SRNB_SHIFT; ++ } else { ++ nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ } ++ for (i = 0; i < nb; i++) ++ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++ ++/** Return the TCM-RAM size of the ARMCR4 core. */ ++uint32 ++si_tcm_size(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ volatile uint8 *regs; ++ bool wasup; ++ uint32 corecap; ++ uint memsize = 0; ++ uint32 nab = 0; ++ uint32 nbb = 0; ++ uint32 totb = 0; ++ uint32 bxinfo = 0; ++ uint32 idx = 0; ++ volatile uint32 *arm_cap_reg; ++ volatile uint32 *arm_bidx; ++ volatile uint32 *arm_binfo; ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to CR4 core */ ++ if (!(regs = si_setcore(sih, ARMCR4_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size. If in reset, come out of reset, ++ * but remain in halt ++ */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, SICF_CPUHALT, SICF_CPUHALT); ++ ++ arm_cap_reg = (volatile uint32 *)(regs + SI_CR4_CAP); ++ corecap = R_REG(sii->osh, arm_cap_reg); ++ ++ nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; ++ nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; ++ totb = nab + nbb; ++ ++ arm_bidx = (volatile uint32 *)(regs + SI_CR4_BANKIDX); ++ arm_binfo = (volatile uint32 *)(regs + SI_CR4_BANKINFO); ++ for (idx = 0; idx < totb; idx++) { ++ W_REG(sii->osh, arm_bidx, idx); ++ ++ bxinfo = R_REG(sii->osh, arm_binfo); ++ memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++bool ++si_has_flops(si_t *sih) ++{ ++ uint origidx, cr4_rev; ++ ++ /* Find out CR4 core revision */ ++ origidx = si_coreidx(sih); ++ if (si_setcore(sih, ARMCR4_CORE_ID, 0)) { ++ cr4_rev = si_corerev(sih); ++ si_setcoreidx(sih, origidx); ++ ++ if (cr4_rev == 1 || cr4_rev >= 3) ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++uint32 ++si_socram_srmem_size(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ ++ sbsocramregs_t *regs; ++ bool wasup; ++ uint corerev; ++ uint32 coreinfo; ++ uint memsize = 0; ++ ++ if ((CHIPID(sih->chip) == BCM4334_CHIP_ID) && (CHIPREV(sih->chiprev) < 2)) { ++ return (32 * 1024); ++ } ++ ++ if (CHIPID(sih->chip) == BCM43430_CHIP_ID || ++ CHIPID(sih->chip) == BCM43018_CHIP_ID) { ++ return (64 * 1024); ++ } ++ ++ /* Block ints and save current core */ ++ INTR_OFF(sii, intr_val); ++ origidx = si_coreidx(sih); ++ ++ /* Switch to SOCRAM core */ ++ if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0))) ++ goto done; ++ ++ /* Get info for determining size */ ++ if (!(wasup = si_iscoreup(sih))) ++ si_core_reset(sih, 0, 0); ++ corerev = si_corerev(sih); ++ coreinfo = R_REG(sii->osh, ®s->coreinfo); ++ ++ /* Calculate size from coreinfo based on rev */ ++ if (corerev >= 16) { ++ uint8 i; ++ uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; ++ for (i = 0; i < nb; i++) { ++ W_REG(sii->osh, ®s->bankidx, i); ++ if (R_REG(sii->osh, ®s->bankinfo) & SOCRAM_BANKINFO_RETNTRAM_MASK) ++ memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); ++ } ++ } ++ ++ /* Return to previous state and core */ ++ if (!wasup) ++ si_core_disable(sih, 0); ++ si_setcoreidx(sih, origidx); ++ ++done: ++ INTR_RESTORE(sii, intr_val); ++ ++ return memsize; ++} ++ ++ ++#if !defined(_CFEZ_) || defined(CFG_WL) ++void ++si_btcgpiowar(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint origidx; ++ uint intr_val = 0; ++ chipcregs_t *cc; ++ ++ /* Make sure that there is ChipCommon core present && ++ * UART_TX is strapped to 1 ++ */ ++ if (!(sih->cccaps & CC_CAP_UARTGPIO)) ++ return; ++ ++ /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */ ++ INTR_OFF(sii, intr_val); ++ ++ origidx = si_coreidx(sih); ++ ++ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0); ++ ASSERT(cc != NULL); ++ ++ W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04); ++ ++ /* restore the original index */ ++ si_setcoreidx(sih, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ++si_chipcontrl_btshd0_4331(si_t *sih, bool on) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ uint intr_val = 0; ++ ++ INTR_OFF(sii, intr_val); ++ ++ origidx = si_coreidx(sih); ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return; ++ } ++ ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ /* bt_shd0 controls are same for 4331 chiprevs 0 and 1, packages 12x9 and 12x12 */ ++ if (on) { ++ /* Enable bt_shd0 on gpio4: */ ++ val |= (CCTRL4331_BT_SHD0_ON_GPIO4); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ val &= ~(CCTRL4331_BT_SHD0_ON_GPIO4); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } ++ ++ /* restore the original index */ ++ si_setcoreidx(sih, origidx); ++ ++ INTR_RESTORE(sii, intr_val); ++} ++ ++void ++si_chipcontrl_restore(si_t *sih, uint32 val) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return; ++ } ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ si_setcoreidx(sih, origidx); ++} ++ ++uint32 ++si_chipcontrl_read(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ uint32 val; ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return -1; ++ } ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ si_setcoreidx(sih, origidx); ++ return val; ++} ++ ++void ++si_chipcontrl_epa4331(si_t *sih, bool on) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ uint32 val; ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return; ++ } ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ if (on) { ++ if (sih->chippkg == 9 || sih->chippkg == 0xb) { ++ val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); ++ /* Ext PA Controls for 4331 12x9 Package */ ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ /* Ext PA Controls for 4331 12x12 Package */ ++ if (CHIPREV(sih->chiprev) > 0) { ++ W_REG(sii->osh, &cc->chipcontrol, val | ++ (CCTRL4331_EXTPA_EN) | (CCTRL4331_EXTPA_EN2)); ++ } else { ++ W_REG(sii->osh, &cc->chipcontrol, val | (CCTRL4331_EXTPA_EN)); ++ } ++ } ++ } else { ++ val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_EN2 | CCTRL4331_EXTPA_ON_GPIO2_5); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++/** switch muxed pins, on: SROM, off: FEMCTRL. Called for a family of ac chips, not just 4360. */ ++void ++si_chipcontrl_srom4360(si_t *sih, bool on) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ uint32 val; ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return; ++ } ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ if (on) { ++ val &= ~(CCTRL4360_SECI_MODE | ++ CCTRL4360_BTSWCTRL_MODE | ++ CCTRL4360_EXTRA_FEMCTRL_MODE | ++ CCTRL4360_BT_LGCY_MODE | ++ CCTRL4360_CORE2FEMCTRL4_ON); ++ ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ } ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++void ++si_clk_srom4365(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ uint32 val; ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return; ++ } ++ val = R_REG(sii->osh, &cc->clkdiv2); ++ W_REG(sii->osh, &cc->clkdiv2, ((val&~0xf) | 0x4)); ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++void ++si_chipcontrl_epa4331_wowl(si_t *sih, bool enter_wowl) ++{ ++ si_info_t *sii; ++ chipcregs_t *cc; ++ uint origidx; ++ uint32 val; ++ bool sel_chip; ++ ++ sel_chip = (CHIPID(sih->chip) == BCM4331_CHIP_ID) || ++ (CHIPID(sih->chip) == BCM43431_CHIP_ID); ++ sel_chip &= ((sih->chippkg == 9 || sih->chippkg == 0xb)); ++ ++ if (!sel_chip) ++ return; ++ ++ sii = SI_INFO(sih); ++ origidx = si_coreidx(sih); ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return; ++ } ++ ++ val = R_REG(sii->osh, &cc->chipcontrol); ++ ++ if (enter_wowl) { ++ val |= CCTRL4331_EXTPA_EN; ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } else { ++ val |= (CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); ++ W_REG(sii->osh, &cc->chipcontrol, val); ++ } ++ si_setcoreidx(sih, origidx); ++} ++#endif ++ ++uint ++si_pll_reset(si_t *sih) ++{ ++ uint err = 0; ++ ++ return (err); ++} ++ ++/** Enable BT-COEX & Ex-PA for 4313 */ ++void ++si_epa_4313war(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return; ++ } ++ ++ /* EPA Fix */ ++ W_REG(sii->osh, &cc->gpiocontrol, ++ R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++void ++si_clk_pmu_htavail_set(si_t *sih, bool set_clear) ++{ ++} ++ ++void ++si_pmu_avb_clk_set(si_t *sih, osl_t *osh, bool set_flag) ++{ ++} ++ ++/** Re-enable synth_pwrsw resource in min_res_mask for 4313 */ ++void ++si_pmu_synth_pwrsw_4313_war(si_t *sih) ++{ ++} ++ ++/** WL/BT control for 4313 btcombo boards >= P250 */ ++void ++si_btcombo_p250_4313_war(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return; ++ } ++ W_REG(sii->osh, &cc->gpiocontrol, ++ R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_5_6_EN_MASK); ++ ++ W_REG(sii->osh, &cc->gpioouten, ++ R_REG(sii->osh, &cc->gpioouten) | GPIO_CTRL_5_6_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++void ++si_btc_enable_chipcontrol(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return; ++ } ++ ++ /* BT fix */ ++ W_REG(sii->osh, &cc->chipcontrol, ++ R_REG(sii->osh, &cc->chipcontrol) | CC_BTCOEX_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++void ++si_btcombo_43228_war(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ ++ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) { ++ SI_ERROR(("%s: Failed to find CORE ID!\n", __FUNCTION__)); ++ return; ++ } ++ ++ W_REG(sii->osh, &cc->gpioouten, GPIO_CTRL_7_6_EN_MASK); ++ W_REG(sii->osh, &cc->gpioout, GPIO_OUT_7_EN_MASK); ++ ++ si_setcoreidx(sih, origidx); ++} ++ ++/** cache device removed state */ ++void si_set_device_removed(si_t *sih, bool status) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ ++ sii->device_removed = status; ++} ++ ++/** check if the device is removed */ ++bool ++si_deviceremoved(si_t *sih) ++{ ++ uint32 w; ++ si_info_t *sii = SI_INFO(sih); ++ ++ if (sii->device_removed) { ++ return TRUE; ++ } ++ ++ switch (BUSTYPE(sih->bustype)) { ++ case PCI_BUS: ++ ASSERT(SI_INFO(sih)->osh != NULL); ++ w = OSL_PCI_READ_CONFIG(SI_INFO(sih)->osh, PCI_CFG_VID, sizeof(uint32)); ++ if ((w & 0xFFFF) != VENDOR_BROADCOM) ++ return TRUE; ++ break; ++ } ++ return FALSE; ++} ++ ++bool ++si_is_warmboot(void) ++{ ++ ++#ifdef BCMULP ++ return (boot_type == WARM_BOOT); ++#else ++ return FALSE; ++#endif ++} ++ ++bool ++si_is_sprom_available(si_t *sih) ++{ ++ if (CCREV(sih->ccrev) >= 31) { ++ si_info_t *sii; ++ uint origidx; ++ chipcregs_t *cc; ++ uint32 sromctrl; ++ ++ if ((sih->cccaps & CC_CAP_SROM) == 0) ++ return FALSE; ++ ++ sii = SI_INFO(sih); ++ origidx = sii->curidx; ++ cc = si_setcoreidx(sih, SI_CC_IDX); ++ ASSERT(cc); ++ sromctrl = R_REG(sii->osh, &cc->sromcontrol); ++ si_setcoreidx(sih, origidx); ++ return (sromctrl & SRC_PRESENT); ++ } ++ ++ switch (CHIPID(sih->chip)) { ++ case BCM43018_CHIP_ID: ++ case BCM43430_CHIP_ID: ++ return FALSE; ++ case BCM4336_CHIP_ID: ++ case BCM43362_CHIP_ID: ++ return (sih->chipst & CST4336_SPROM_PRESENT) != 0; ++ case BCM4330_CHIP_ID: ++ return (sih->chipst & CST4330_SPROM_PRESENT) != 0; ++ case BCM4313_CHIP_ID: ++ return (sih->chipst & CST4313_SPROM_PRESENT) != 0; ++ case BCM4331_CHIP_ID: ++ case BCM43431_CHIP_ID: ++ return (sih->chipst & CST4331_SPROM_PRESENT) != 0; ++ case BCM43239_CHIP_ID: ++ return ((sih->chipst & CST43239_SPROM_MASK) && ++ !(sih->chipst & CST43239_SFLASH_MASK)); ++ case BCM4324_CHIP_ID: ++ case BCM43242_CHIP_ID: ++ return ((sih->chipst & CST4324_SPROM_MASK) && ++ !(sih->chipst & CST4324_SFLASH_MASK)); ++ case BCM4335_CHIP_ID: ++ CASE_BCM4345_CHIP: ++ return ((sih->chipst & CST4335_SPROM_MASK) && ++ !(sih->chipst & CST4335_SFLASH_MASK)); ++ case BCM4349_CHIP_GRPID: ++ return (sih->chipst & CST4349_SPROM_PRESENT) != 0; ++ case BCM53573_CHIP_GRPID: ++ return FALSE; /* SPROM PRESENT is not defined for 53573 as of now */ ++ case BCM4347_CHIP_ID: ++ return (sih->chipst & CST4347_SPROM_PRESENT) != 0; ++ break; ++ case BCM4350_CHIP_ID: ++ case BCM4354_CHIP_ID: ++ case BCM43556_CHIP_ID: ++ case BCM43558_CHIP_ID: ++ case BCM43566_CHIP_ID: ++ case BCM43568_CHIP_ID: ++ case BCM43569_CHIP_ID: ++ case BCM43570_CHIP_ID: ++ case BCM4358_CHIP_ID: ++ return (sih->chipst & CST4350_SPROM_PRESENT) != 0; ++ CASE_BCM43602_CHIP: ++ return (sih->chipst & CST43602_SPROM_PRESENT) != 0; ++ case BCM43131_CHIP_ID: ++ case BCM43217_CHIP_ID: ++ case BCM43227_CHIP_ID: ++ case BCM43228_CHIP_ID: ++ case BCM43428_CHIP_ID: ++ return (sih->chipst & CST43228_OTP_PRESENT) != CST43228_OTP_PRESENT; ++ case BCM43012_CHIP_ID: ++ return FALSE; ++ default: ++ return TRUE; ++ } ++} ++ ++ ++uint32 si_get_sromctl(si_t *sih) ++{ ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ uint32 sromctl; ++ osl_t *osh = si_osh(sih); ++ ++ cc = si_setcoreidx(sih, SI_CC_IDX); ++ ASSERT((uintptr)cc); ++ ++ sromctl = R_REG(osh, &cc->sromcontrol); ++ ++ /* return to the original core */ ++ si_setcoreidx(sih, origidx); ++ return sromctl; ++} ++ ++int si_set_sromctl(si_t *sih, uint32 value) ++{ ++ chipcregs_t *cc; ++ uint origidx = si_coreidx(sih); ++ osl_t *osh = si_osh(sih); ++ int ret = BCME_OK; ++ ++ cc = si_setcoreidx(sih, SI_CC_IDX); ++ ASSERT((uintptr)cc); ++ ++ /* get chipcommon rev */ ++ if (si_corerev(sih) >= 32) { ++ /* SpromCtrl is only accessible if CoreCapabilities.SpromSupported and ++ * SpromPresent is 1. ++ */ ++ if ((R_REG(osh, &cc->capabilities) & CC_CAP_SROM) != 0 && ++ (R_REG(osh, &cc->sromcontrol) & SRC_PRESENT)) { ++ W_REG(osh, &cc->sromcontrol, value); ++ } else { ++ ret = BCME_NODEVICE; ++ } ++ } else { ++ ret = BCME_UNSUPPORTED; ++ } ++ ++ /* return to the original core */ ++ si_setcoreidx(sih, origidx); ++ ++ return ret; ++} ++ ++uint ++si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val) ++{ ++ uint origidx, intr_val = 0; ++ uint ret_val; ++ si_info_t *sii = SI_INFO(sih); ++ ++ origidx = si_coreidx(sih); ++ ++ INTR_OFF(sii, intr_val); ++ si_setcoreidx(sih, coreidx); ++ ++ ret_val = si_wrapperreg(sih, offset, mask, val); ++ ++ /* return to the original core */ ++ si_setcoreidx(sih, origidx); ++ INTR_RESTORE(sii, intr_val); ++ return ret_val; ++} ++ ++ ++/* cleanup the timer from the host when ARM is been halted ++ * without a chance for ARM cleanup its resources ++ * If left not cleanup, Intr from a software timer can still ++ * request HT clk when ARM is halted. ++ */ ++uint32 ++si_pmu_res_req_timer_clr(si_t *sih) ++{ ++ uint32 mask; ++ ++ mask = PRRT_REQ_ACTIVE | PRRT_INTEN | PRRT_HT_REQ; ++ mask <<= 14; ++ /* clear mask bits */ ++ pmu_corereg(sih, SI_CC_IDX, res_req_timer, mask, 0); ++ /* readback to ensure write completes */ ++ return pmu_corereg(sih, SI_CC_IDX, res_req_timer, 0, 0); ++} ++ ++/** turn on/off rfldo */ ++void ++si_pmu_rfldo(si_t *sih, bool on) ++{ ++} ++ ++ ++#ifdef SURVIVE_PERST_ENAB ++static uint32 ++si_pcie_survive_perst(si_t *sih, uint32 mask, uint32 val) ++{ ++ si_info_t *sii; ++ ++ sii = SI_INFO(sih); ++ ++ if (!PCIE(sii)) ++ return (0); ++ ++ return pcie_survive_perst(sii->pch, mask, val); ++} ++ ++static void ++si_watchdog_reset(si_t *sih) ++{ ++ uint32 i; ++ ++ /* issue a watchdog reset */ ++ pmu_corereg(sih, SI_CC_IDX, pmuwatchdog, 2, 2); ++ /* do busy wait for 20ms */ ++ for (i = 0; i < 2000; i++) { ++ OSL_DELAY(10); ++ } ++} ++#endif /* SURVIVE_PERST_ENAB */ ++ ++void ++si_survive_perst_war(si_t *sih, bool reset, uint32 sperst_mask, uint32 sperst_val) ++{ ++#ifdef SURVIVE_PERST_ENAB ++ if (BUSTYPE(sih->bustype) != PCI_BUS) ++ return; ++ ++ if ((CHIPID(sih->chip) != BCM4360_CHIP_ID && CHIPID(sih->chip) != BCM4352_CHIP_ID) || ++ (CHIPREV(sih->chiprev) >= 4)) ++ return; ++ ++ if (reset) { ++ si_info_t *sii = SI_INFO(sih); ++ uint32 bar0win, bar0win_after; ++ ++ /* save the bar0win */ ++ bar0win = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); ++ ++ si_watchdog_reset(sih); ++ ++ bar0win_after = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32)); ++ if (bar0win_after != bar0win) { ++ SI_ERROR(("%s: bar0win before %08x, bar0win after %08x\n", ++ __FUNCTION__, bar0win, bar0win_after)); ++ OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32), bar0win); ++ } ++ } ++ if (sperst_mask) { ++ /* enable survive perst */ ++ si_pcie_survive_perst(sih, sperst_mask, sperst_val); ++ } ++#endif /* SURVIVE_PERST_ENAB */ ++} ++ ++/* Caller of this function should make sure is on PCIE core ++ * Used in pciedev.c. ++ */ ++void ++si_pcie_disable_oobselltr(si_t *sih) ++{ ++ ASSERT(si_coreid(sih) == PCIE2_CORE_ID); ++ si_wrapperreg(sih, AI_OOBSELIND30, ~0, 0); ++} ++ ++void ++si_pcie_ltr_war(si_t *sih) ++{ ++} ++ ++void ++si_pcie_hw_LTR_war(si_t *sih) ++{ ++} ++ ++void ++si_pciedev_reg_pm_clk_period(si_t *sih) ++{ ++} ++ ++void ++si_pciedev_crwlpciegen2(si_t *sih) ++{ ++} ++ ++void ++si_pcie_prep_D3(si_t *sih, bool enter_D3) ++{ ++} ++ ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++uint32 ++si_clear_backplane_to_fast(si_t *sih, void * addr) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_AI) { ++ return ai_clear_backplane_to_fast(sih, addr); ++ } ++ ++ return 0; ++} ++ ++const si_axi_error_info_t * si_get_axi_errlog_info(si_t * sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_AI) { ++ return (const si_axi_error_info_t *)sih->err_info; ++ } ++ ++ return NULL; ++} ++ ++void si_reset_axi_errlog_info(si_t * sih) ++{ ++ sih->err_info->count = 0; ++} ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) ++uint32 ++si_clear_backplane_to_per_core(si_t *sih, uint coreid, uint coreunit, void * wrap) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_AI) { ++ return ai_clear_backplane_to_per_core(sih, coreid, coreunit, wrap); ++ } ++ ++ return AXI_WRAP_STS_NONE; ++} ++#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ ++ ++uint32 ++si_clear_backplane_to(si_t *sih) ++{ ++ if (CHIPTYPE(sih->socitype) == SOCI_AI) { ++ return ai_clear_backplane_to(sih); ++ } ++ ++ return 0; ++} ++ ++/* ++ * This routine adds the AXI timeouts for ++ * chipcommon, pcie and ARM slave wrappers ++ */ ++void ++si_slave_wrapper_add(si_t *sih) ++{ ++#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) ++ /* Enable only for AXI */ ++ if (CHIPTYPE(sih->socitype) != SOCI_AI) { ++ return; ++ } ++ ++ if (CHIPID(sih->chip) == BCM4345_CHIP_ID && CHIPREV(sih->chiprev) >= 6) { ++ si_info_t *sii = SI_INFO(sih); ++ ++ int wrapper_idx = (int)sii->axi_num_wrappers - 1; ++ ++ ASSERT(wrapper_idx >= 0); /* axi_wrapper[] not initialised */ ++ do { ++ if (sii->axi_wrapper[wrapper_idx].wrapper_type == AI_SLAVE_WRAPPER && ++ sii->axi_wrapper[wrapper_idx].cid == 0xfff) { ++ sii->axi_wrapper[wrapper_idx].wrapper_addr = 0x1810b000; ++ break; ++ } ++ } while (wrapper_idx-- > 0); ++ ASSERT(wrapper_idx >= 0); /* all addresses valid for the chiprev under test */ ++ } ++ ++ /* All required slave wrappers are added in ai_scan */ ++ ai_enable_backplane_timeouts(sih); ++#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ ++} ++ ++ ++void ++si_pll_sr_reinit(si_t *sih) ++{ ++} ++ ++ ++/* Programming d11 core oob settings for 4364 ++ * WARs for HW4364-237 and HW4364-166 ++*/ ++void ++si_config_4364_d11_oob(si_t *sih, uint coreid) ++{ ++ uint save_idx; ++ ++ save_idx = si_coreidx(sih); ++ si_setcore(sih, coreid, 0); ++ si_wrapperreg(sih, AI_OOBSELINC30, ~0, 0x81828180); ++ si_wrapperreg(sih, AI_OOBSELINC74, ~0, 0x87868183); ++ si_wrapperreg(sih, AI_OOBSELOUTB74, ~0, 0x84858484); ++ si_setcore(sih, coreid, 1); ++ si_wrapperreg(sih, AI_OOBSELINC30, ~0, 0x81828180); ++ si_wrapperreg(sih, AI_OOBSELINC74, ~0, 0x87868184); ++ si_wrapperreg(sih, AI_OOBSELOUTB74, ~0, 0x84868484); ++ si_setcoreidx(sih, save_idx); ++} ++ ++void ++si_pll_closeloop(si_t *sih) ++{ ++#if defined(SAVERESTORE) ++ uint32 data; ++ ++ /* disable PLL open loop operation */ ++ switch (CHIPID(sih->chip)) { ++#ifdef SAVERESTORE ++ case BCM43018_CHIP_ID: ++ case BCM43430_CHIP_ID: ++ if (SR_ENAB() && sr_isenab(sih)) { ++ /* read back the pll openloop state */ ++ data = si_pmu_pllcontrol(sih, PMU1_PLL0_PLLCTL8, 0, 0); ++ /* current mode is openloop (possible POR) */ ++ if ((data & PMU1_PLLCTL8_OPENLOOP_MASK) != 0) { ++ si_pmu_pllcontrol(sih, PMU1_PLL0_PLLCTL8, ++ PMU1_PLLCTL8_OPENLOOP_MASK, 0); ++ si_pmu_pllupd(sih); ++ } ++ } ++ break; ++#endif /* SAVERESTORE */ ++ default: ++ /* any unsupported chip bail */ ++ return; ++ } ++#endif ++} ++ ++void ++si_update_macclk_mul_fact(si_t *sih, uint32 mul_fact) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ sii->macclk_mul_fact = mul_fact; ++} ++ ++uint32 ++si_get_macclk_mul_fact(si_t *sih) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ return sii->macclk_mul_fact; ++} ++ ++ ++#if defined(BCMSRPWR) && !defined(BCMSRPWR_DISABLED) ++bool _bcmsrpwr = TRUE; ++#else ++bool _bcmsrpwr = FALSE; ++#endif ++ ++uint32 ++si_srpwr_request(si_t *sih, uint32 mask, uint32 val) ++{ ++ uint32 r, offset = OFFSETOF(chipcregs_t, powerctl); /* Same 0x1e8 per core */ ++ uint cidx = (BUSTYPE(sih->bustype) == SI_BUS) ? SI_CC_IDX : sih->buscoreidx; ++ ++ if (mask || val) { ++ mask <<= SRPWR_REQON_SHIFT; ++ val <<= SRPWR_REQON_SHIFT; ++ ++ r = ((si_corereg(sih, cidx, offset, 0, 0) & ~mask) | val); ++ r = si_corereg(sih, cidx, offset, ~0, r); ++ } else { ++ r = si_corereg(sih, cidx, offset, 0, 0); ++ } ++ ++ return r; ++} ++ ++uint32 ++si_srpwr_stat_spinwait(si_t *sih, uint32 mask, uint32 val) ++{ ++ uint32 r, offset = OFFSETOF(chipcregs_t, powerctl); /* Same 0x1e8 per core */ ++ uint cidx = (BUSTYPE(sih->bustype) == SI_BUS) ? SI_CC_IDX : sih->buscoreidx; ++ ++ ASSERT(mask); ++ ASSERT(val); ++ ++ /* spinwait on pwrstatus */ ++ mask <<= SRPWR_STATUS_SHIFT; ++ val <<= SRPWR_STATUS_SHIFT; ++ ++ SPINWAIT(((si_corereg(sih, cidx, offset, 0, 0) & mask) != val), ++ PMU_MAX_TRANSITION_DLY); ++ ASSERT((si_corereg(sih, cidx, offset, 0, 0) & mask) == val); ++ ++ r = si_corereg(sih, cidx, offset, 0, 0) & mask; ++ r = (r >> SRPWR_STATUS_SHIFT) & SRPWR_DMN_ALL_MASK; ++ ++ return r; ++} ++ ++uint32 ++si_srpwr_stat(si_t *sih) ++{ ++ uint32 r, offset = OFFSETOF(chipcregs_t, powerctl); /* Same 0x1e8 per core */ ++ uint cidx = (BUSTYPE(sih->bustype) == SI_BUS) ? SI_CC_IDX : sih->buscoreidx; ++ ++ r = si_corereg(sih, cidx, offset, 0, 0); ++ r = (r >> SRPWR_STATUS_SHIFT) & SRPWR_DMN_ALL_MASK; ++ ++ return r; ++} ++ ++uint32 ++si_srpwr_domain(si_t *sih) ++{ ++ uint32 r, offset = OFFSETOF(chipcregs_t, powerctl); /* Same 0x1e8 per core */ ++ uint cidx = (BUSTYPE(sih->bustype) == SI_BUS) ? SI_CC_IDX : sih->buscoreidx; ++ ++ r = si_corereg(sih, cidx, offset, 0, 0); ++ r = (r >> SRPWR_DMN_SHIFT) & SRPWR_DMN_ALL_MASK; ++ ++ return r; ++} ++ ++/* Utility API to read/write the raw registers with absolute address. ++ * This function can be invoked from either FW or host driver. ++ */ ++uint32 ++si_raw_reg(si_t *sih, uint32 reg, uint32 val, uint32 wrire_req) ++{ ++ si_info_t *sii = SI_INFO(sih); ++ uint32 address_space = reg & ~0xFFF; ++ volatile uint32 * addr = (void*)(uintptr)(reg); ++ uint32 prev_value = 0; ++ uint32 cfg_reg = 0; ++ ++ if (sii == NULL) { ++ return 0; ++ } ++ ++ /* No need to translate the absolute address on SI bus */ ++ if (BUSTYPE(sih->bustype) == SI_BUS) { ++ goto skip_cfg; ++ } ++ ++ /* This API supports only the PCI host interface */ ++ if (BUSTYPE(sih->bustype) != PCI_BUS) { ++ return ID32_INVALID; ++ } ++ ++ if (PCIE_GEN2(sii)) { ++ /* Use BAR0 Secondary window is PCIe Gen2. ++ * Set the secondary BAR0 Window to current register of interest ++ */ ++ addr = (volatile uint32*)(((volatile uint8*)sii->curmap) + ++ PCI_SEC_BAR0_WIN_OFFSET + (reg & 0xfff)); ++ cfg_reg = PCIE2_BAR0_CORE2_WIN; ++ ++ } else { ++ /* PCIe Gen1 do not have secondary BAR0 window. ++ * reuse the BAR0 WIN2 ++ */ ++ addr = (volatile uint32*)(((volatile uint8*)sii->curmap) + ++ PCI_BAR0_WIN2_OFFSET + (reg & 0xfff)); ++ cfg_reg = PCI_BAR0_WIN2; ++ } ++ ++ prev_value = OSL_PCI_READ_CONFIG(sii->osh, cfg_reg, 4); ++ ++ if (prev_value != address_space) { ++ OSL_PCI_WRITE_CONFIG(sii->osh, cfg_reg, ++ sizeof(uint32), address_space); ++ } else { ++ prev_value = 0; ++ } ++ ++skip_cfg: ++ if (wrire_req) { ++ W_REG(sii->osh, addr, val); ++ } else { ++ val = R_REG(sii->osh, addr); ++ } ++ ++ if (prev_value) { ++ /* Restore BAR0 WIN2 for PCIE GEN1 devices */ ++ OSL_PCI_WRITE_CONFIG(sii->osh, ++ cfg_reg, sizeof(uint32), prev_value); ++ } ++ ++ return val; ++} +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/siutils_priv.h b/module_drivers/drivers/net/wireless/bcmdhd/siutils_priv.h +new file mode 100644 +index 000000000..4b887df6a +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/siutils_priv.h +@@ -0,0 +1,333 @@ ++/* ++ * Include file private to the SOC Interconnect support files. ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: siutils_priv.h 625739 2016-03-17 12:28:03Z $ ++ */ ++ ++#ifndef _siutils_priv_h_ ++#define _siutils_priv_h_ ++ ++#if defined(SI_ERROR_ENFORCE) ++#define SI_ERROR(args) printf args ++#else ++#define SI_ERROR(args) printf args ++#endif ++ ++#if defined(ENABLE_CORECAPTURE) ++ ++#define SI_PRINT(args) osl_wificc_logDebug args ++ ++#else ++ ++#define SI_PRINT(args) printf args ++ ++#endif /* ENABLE_CORECAPTURE */ ++ ++ ++#define SI_MSG(args) ++ ++#ifdef BCMDBG_SI ++#define SI_VMSG(args) printf args ++#else ++#define SI_VMSG(args) ++#endif ++ ++#define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) ++ ++typedef uint32 (*si_intrsoff_t)(void *intr_arg); ++typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg); ++typedef bool (*si_intrsenabled_t)(void *intr_arg); ++ ++ ++#define SI_GPIO_MAX 16 ++ ++typedef struct gci_gpio_item { ++ void *arg; ++ uint8 gci_gpio; ++ uint8 status; ++ gci_gpio_handler_t handler; ++ struct gci_gpio_item *next; ++} gci_gpio_item_t; ++ ++#define AI_SLAVE_WRAPPER 0 ++#define AI_MASTER_WRAPPER 1 ++ ++typedef struct axi_wrapper { ++ uint32 mfg; ++ uint32 cid; ++ uint32 rev; ++ uint32 wrapper_type; ++ uint32 wrapper_addr; ++ uint32 wrapper_size; ++} axi_wrapper_t; ++ ++#define SI_MAX_AXI_WRAPPERS 32 ++#define AI_REG_READ_TIMEOUT 300 /* in msec */ ++ ++/* for some combo chips, BT side accesses chipcommon->0x190, as a 16 byte addr */ ++/* register at 0x19C doesn't exist, so error is logged at the slave wrapper */ ++#define BT_CC_SPROM_BADREG_LO 0x18000190 ++#define BT_CC_SPROM_BADREG_HI 0 ++#define BCM4350_BT_AXI_ID 6 ++#define BCM4345_BT_AXI_ID 6 ++ ++typedef struct si_cores_info { ++ volatile void *regs[SI_MAXCORES]; /* other regs va */ ++ ++ uint coreid[SI_MAXCORES]; /**< id of each core */ ++ uint32 coresba[SI_MAXCORES]; /**< backplane address of each core */ ++ void *regs2[SI_MAXCORES]; /**< va of each core second register set (usbh20) */ ++ uint32 coresba2[SI_MAXCORES]; /**< address of each core second register set (usbh20) */ ++ uint32 coresba_size[SI_MAXCORES]; /**< backplane address space size */ ++ uint32 coresba2_size[SI_MAXCORES]; /**< second address space size */ ++ ++ void *wrappers[SI_MAXCORES]; /**< other cores wrapper va */ ++ uint32 wrapba[SI_MAXCORES]; /**< address of controlling wrapper */ ++ ++ void *wrappers2[SI_MAXCORES]; /**< other cores wrapper va */ ++ uint32 wrapba2[SI_MAXCORES]; /**< address of controlling wrapper */ ++ ++ uint32 cia[SI_MAXCORES]; /**< erom cia entry for each core */ ++ uint32 cib[SI_MAXCORES]; /**< erom cia entry for each core */ ++} si_cores_info_t; ++ ++/** misc si info needed by some of the routines */ ++typedef struct si_info { ++ struct si_pub pub; /**< back plane public state (must be first field) */ ++ ++ void *osh; /**< osl os handle */ ++ void *sdh; /**< bcmsdh handle */ ++ ++ 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 */ ++ ++ void *pch; /**< PCI/E core handle */ ++ ++ bool memseg; /**< flag to toggle MEM_SEG register */ ++ ++ char *vars; ++ uint varsz; ++ ++ volatile void *curmap; /* current regs va */ ++ ++ uint curidx; /**< current core index */ ++ uint numcores; /**< # discovered cores */ ++ ++ void *curwrap; /**< current wrapper va */ ++ ++ uint32 oob_router; /**< oob router registers for axi */ ++ ++ si_cores_info_t *cores_info; ++ gci_gpio_item_t *gci_gpio_head; /**< gci gpio interrupts head */ ++ uint chipnew; /**< new chip number */ ++ uint second_bar0win; /**< Backplane region */ ++ uint num_br; /**< # discovered bridges */ ++ uint32 br_wrapba[SI_MAXBR]; /**< address of bridge controlling wrapper */ ++ uint32 xtalfreq; ++ uint32 macclk_mul_fact; /* Multiplication factor necessary to adjust MAC Clock ++ * during ULB Mode operation. One instance where this is used is configuring TSF L-frac ++ * register ++ */ ++ bool device_removed; ++ uint axi_num_wrappers; ++ axi_wrapper_t * axi_wrapper; ++} si_info_t; ++ ++ ++#define SI_INFO(sih) ((si_info_t *)(uintptr)sih) ++ ++#define GOODCOREADDR(x, b) (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ ++ ISALIGNED((x), SI_CORE_SIZE)) ++#define GOODREGS(regs) ((regs) != NULL && ISALIGNED((uintptr)(regs), SI_CORE_SIZE)) ++#define BADCOREADDR 0 ++#define GOODIDX(idx) (((uint)idx) < SI_MAXCORES) ++#define NOREV -1 /**< Invalid rev */ ++ ++#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ ++ ((si)->pub.buscoretype == PCI_CORE_ID)) ++ ++#define PCIE_GEN1(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ ++ ((si)->pub.buscoretype == PCIE_CORE_ID)) ++ ++#define PCIE_GEN2(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \ ++ ((si)->pub.buscoretype == PCIE2_CORE_ID)) ++ ++#define PCIE(si) (PCIE_GEN1(si) || PCIE_GEN2(si)) ++ ++#define PCMCIA(si) ((BUSTYPE((si)->pub.bustype) == PCMCIA_BUS) && ((si)->memseg == TRUE)) ++ ++/** Newer chips can access PCI/PCIE and CC core without requiring to change PCI BAR0 WIN */ ++#define SI_FAST(si) (PCIE(si) || (PCI(si) && ((si)->pub.buscorerev >= 13))) ++ ++#define CCREGS_FAST(si) \ ++ (((si)->curmap == NULL) ? NULL : \ ++ ((volatile char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET)) ++#define PCIEREGS(si) (((volatile char *)((si)->curmap) + PCI_16KB0_PCIREGS_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)->cores_info->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)->cores_info->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 */ ++#define LPOMAXFREQ 43000 /**< low power oscillator max */ ++#define XTALMINFREQ 19800000 /**< 20 MHz - 1% */ ++#define XTALMAXFREQ 20200000 /**< 20 MHz + 1% */ ++#define PCIMINFREQ 25000000 /**< 25 MHz */ ++#define PCIMAXFREQ 34000000 /**< 33 MHz + fudge */ ++ ++#define ILP_DIV_5MHZ 0 /**< ILP = 5 MHz */ ++#define ILP_DIV_1MHZ 4 /**< ILP = 1 MHz */ ++ ++/* 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 ++ ++/* Silicon Backplane externs */ ++extern void sb_scan(si_t *sih, volatile void *regs, uint devid); ++extern uint sb_coreid(si_t *sih); ++extern uint sb_intflag(si_t *sih); ++extern uint sb_flag(si_t *sih); ++extern void sb_setint(si_t *sih, int siflag); ++extern uint sb_corevendor(si_t *sih); ++extern uint sb_corerev(si_t *sih); ++extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); ++extern volatile uint32 *sb_corereg_addr(si_t *sih, uint coreidx, uint regoff); ++extern bool sb_iscoreup(si_t *sih); ++extern volatile void *sb_setcoreidx(si_t *sih, uint coreidx); ++extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val); ++extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); ++extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val); ++extern void sb_commit(si_t *sih); ++extern uint32 sb_base(uint32 admatch); ++extern uint32 sb_size(uint32 admatch); ++extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); ++extern void sb_core_disable(si_t *sih, uint32 bits); ++extern uint32 sb_addrspace(si_t *sih, uint asidx); ++extern uint32 sb_addrspacesize(si_t *sih, uint asidx); ++extern int sb_numaddrspaces(si_t *sih); ++ ++extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx); ++ ++extern bool sb_taclear(si_t *sih, bool details); ++ ++#if defined(BCMDBG_PHYDUMP) ++extern void sb_dumpregs(si_t *sih, struct bcmstrbuf *b); ++#endif ++ ++/* Wake-on-wireless-LAN (WOWL) */ ++extern bool sb_pci_pmecap(si_t *sih); ++struct osl_info; ++extern bool sb_pci_fastpmecap(struct osl_info *osh); ++extern bool sb_pci_pmeclr(si_t *sih); ++extern void sb_pci_pmeen(si_t *sih); ++extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset); ++ ++/* AMBA Interconnect exported externs */ ++extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, ++ void *sdh, char **vars, uint *varsz); ++extern si_t *ai_kattach(osl_t *osh); ++extern void ai_scan(si_t *sih, void *regs, uint devid); ++ ++extern uint ai_flag(si_t *sih); ++extern uint ai_flag_alt(si_t *sih); ++extern void ai_setint(si_t *sih, int siflag); ++extern uint ai_coreidx(si_t *sih); ++extern uint ai_corevendor(si_t *sih); ++extern uint ai_corerev(si_t *sih); ++extern volatile uint32 *ai_corereg_addr(si_t *sih, uint coreidx, uint regoff); ++extern bool ai_iscoreup(si_t *sih); ++extern volatile void *ai_setcoreidx(si_t *sih, uint coreidx); ++extern volatile void *ai_setcoreidx_2ndwrap(si_t *sih, uint coreidx); ++extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val); ++extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); ++extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val); ++extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); ++extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits); ++extern void ai_d11rsdb_core_reset(si_t *sih, uint32 bits, ++ uint32 resetbits, void *p, void *s); ++extern void ai_core_disable(si_t *sih, uint32 bits); ++extern void ai_d11rsdb_core_disable(const si_info_t *sii, uint32 bits, ++ aidmp_t *pmacai, aidmp_t *smacai); ++extern int ai_numaddrspaces(si_t *sih); ++extern uint32 ai_addrspace(si_t *sih, uint asidx); ++extern uint32 ai_addrspacesize(si_t *sih, uint asidx); ++extern void ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size); ++extern uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val); ++extern void ai_enable_backplane_timeouts(si_t *sih); ++extern uint32 ai_clear_backplane_to(si_t *sih); ++extern uint ai_num_slaveports(si_t *sih, uint coreidx); ++ ++#ifdef BCM_BACKPLANE_TIMEOUT ++uint32 ai_clear_backplane_to_fast(si_t *sih, void * addr); ++#endif /* BCM_BACKPLANE_TIMEOUT */ ++ ++#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) ++extern uint32 ai_clear_backplane_to_per_core(si_t *sih, uint coreid, uint coreunit, void * wrap); ++#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ ++ ++#if defined(BCMDBG_PHYDUMP) ++extern void ai_dumpregs(si_t *sih, struct bcmstrbuf *b); ++#endif ++ ++extern uint32 ai_wrapper_dump_buf_size(si_t *sih); ++extern uint32 ai_wrapper_dump_binary(si_t *sih, uchar *p); ++ ++#define ub_scan(a, b, c) do {} while (0) ++#define ub_flag(a) (0) ++#define ub_setint(a, b) do {} while (0) ++#define ub_coreidx(a) (0) ++#define ub_corevendor(a) (0) ++#define ub_corerev(a) (0) ++#define ub_iscoreup(a) (0) ++#define ub_setcoreidx(a, b) (0) ++#define ub_core_cflags(a, b, c) (0) ++#define ub_core_cflags_wo(a, b, c) do {} while (0) ++#define ub_core_sflags(a, b, c) (0) ++#define ub_corereg(a, b, c, d, e) (0) ++#define ub_core_reset(a, b, c) do {} while (0) ++#define ub_core_disable(a, b) do {} while (0) ++#define ub_numaddrspaces(a) (0) ++#define ub_addrspace(a, b) (0) ++#define ub_addrspacesize(a, b) (0) ++#define ub_view(a, b) do {} while (0) ++#define ub_dumpregs(a, b) do {} while (0) ++ ++#endif /* _siutils_priv_h_ */ +diff --git a/module_drivers/drivers/net/wireless/bcmdhd/wl_android.c b/module_drivers/drivers/net/wireless/bcmdhd/wl_android.c +new file mode 100644 +index 000000000..7cce0e574 +--- /dev/null ++++ b/module_drivers/drivers/net/wireless/bcmdhd/wl_android.c +@@ -0,0 +1,5511 @@ ++/* ++ * Linux cfg80211 driver - Android related functions ++ * ++ * Copyright (C) 1999-2017, Broadcom Corporation ++ * ++ * Unless you and Broadcom execute a separate written software license ++ * agreement governing use of this software, this software is licensed to you ++ * under the terms of the GNU General Public License version 2 (the "GPL"), ++ * available at http://www.broadcom.com/licenses/GPLv2.php, with the ++ * following added to such license: ++ * ++ * As a special exception, the copyright holders of this software give you ++ * permission to link this software with independent modules, and to copy and ++ * distribute the resulting executable under terms of your choice, provided that ++ * you also meet, for each linked independent module, the terms and conditions of ++ * the license of that module. An independent module is a module which is not ++ * derived from this software. The special exception does not apply to any ++ * modifications of the software. ++ * ++ * Notwithstanding the above, under no circumstances may you combine this ++ * software in any way with any other Broadcom software provided under a license ++ * other than the GPL, without Broadcom's express prior written consent. ++ * ++ * ++ * <> ++ * ++ * $Id: wl_android.c 710862 2017-07-14 07:43:59Z $ ++ */ ++ ++#include ++#include ++#include ++#ifdef CONFIG_COMPAT ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef PNO_SUPPORT ++#include ++#endif ++#ifdef BCMSDIO ++#include ++#endif ++#ifdef WL_CFG80211 ++#include ++#endif ++#ifdef DHDTCPACK_SUPPRESS ++#include ++#endif /* DHDTCPACK_SUPPRESS */ ++#include ++#ifdef DHD_PKT_LOGGING ++#include ++#endif /* DHD_PKT_LOGGING */ ++ ++#if defined(STAT_REPORT) ++#include ++#endif /* STAT_REPORT */ ++#ifdef WL_ESCAN ++#include ++#endif ++ ++#ifndef WL_CFG80211 ++#define htod32(i) i ++#define htod16(i) i ++#define dtoh32(i) i ++#define dtoh16(i) i ++#define htodchanspec(i) i ++#define dtohchanspec(i) i ++#endif ++ ++uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL; ++ ++#define ANDROID_ERROR_MSG(x, args...) \ ++ do { \ ++ if (android_msg_level & ANDROID_ERROR_LEVEL) { \ ++ printk(KERN_ERR "[dhd] ANDROID-ERROR) " x, ## args); \ ++ } \ ++ } while (0) ++#define ANDROID_TRACE_MSG(x, args...) \ ++ do { \ ++ if (android_msg_level & ANDROID_TRACE_LEVEL) { \ ++ printk(KERN_INFO "[dhd] ANDROID-TRACE) " x, ## args); \ ++ } \ ++ } while (0) ++#define ANDROID_INFO_MSG(x, args...) \ ++ do { \ ++ if (android_msg_level & ANDROID_INFO_LEVEL) { \ ++ printk(KERN_INFO "[dhd] ANDROID-INFO) " x, ## args); \ ++ } \ ++ } while (0) ++#define ANDROID_ERROR(x) ANDROID_ERROR_MSG x ++#define ANDROID_TRACE(x) ANDROID_TRACE_MSG x ++#define ANDROID_INFO(x) ANDROID_INFO_MSG x ++ ++/* ++ * Android private command strings, PLEASE define new private commands here ++ * so they can be updated easily in the future (if needed) ++ */ ++ ++#define CMD_START "START" ++#define CMD_STOP "STOP" ++#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" ++#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" ++#define CMD_RSSI "RSSI" ++#define CMD_LINKSPEED "LINKSPEED" ++#define CMD_RXFILTER_START "RXFILTER-START" ++#define CMD_RXFILTER_STOP "RXFILTER-STOP" ++#define CMD_RXFILTER_ADD "RXFILTER-ADD" ++#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" ++#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" ++#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" ++#define CMD_BTCOEXMODE "BTCOEXMODE" ++#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" ++#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" ++#define CMD_MAXDTIM_IN_SUSPEND "MAX_DTIM_IN_SUSPEND" ++#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" ++#define CMD_SETFWPATH "SETFWPATH" ++#define CMD_SETBAND "SETBAND" ++#define CMD_GETBAND "GETBAND" ++#define CMD_COUNTRY "COUNTRY" ++#ifdef WLMESH_CFG80211 ++#define CMD_SAE_SET_PASSWORD "SAE_SET_PASSWORD" ++#define CMD_SET_RSDB_MODE "RSDB_MODE" ++#endif ++#define CMD_P2P_SET_NOA "P2P_SET_NOA" ++#if !defined WL_ENABLE_P2P_IF ++#define CMD_P2P_GET_NOA "P2P_GET_NOA" ++#endif /* WL_ENABLE_P2P_IF */ ++#define CMD_P2P_SD_OFFLOAD "P2P_SD_" ++#define CMD_P2P_LISTEN_OFFLOAD "P2P_LO_" ++#define CMD_P2P_SET_PS "P2P_SET_PS" ++#define CMD_P2P_ECSA "P2P_ECSA" ++#define CMD_P2P_INC_BW "P2P_INCREASE_BW" ++#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" ++#define CMD_SETROAMMODE "SETROAMMODE" ++#define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA" ++#define CMD_MIRACAST "MIRACAST" ++#define CMD_COUNTRY_DELIMITER "/" ++#ifdef WL11ULB ++#define CMD_ULB_MODE "ULB_MODE" ++#define CMD_ULB_BW "ULB_BW" ++#endif /* WL11ULB */ ++#ifdef WLFBT ++#define CMD_GET_FTKEY "GET_FTKEY" ++#endif ++ ++#if defined(WL_SUPPORT_AUTO_CHANNEL) ++#define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS" ++#endif /* WL_SUPPORT_AUTO_CHANNEL */ ++ ++#define CMD_80211_MODE "MODE" /* 802.11 mode a/b/g/n/ac */ ++#define CMD_CHANSPEC "CHANSPEC" ++#define CMD_DATARATE "DATARATE" ++#define CMD_ASSOC_CLIENTS "ASSOCLIST" ++#define CMD_SET_CSA "SETCSA" ++#ifdef WL_SUPPORT_AUTO_CHANNEL ++#define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL" ++#endif /* WL_SUPPORT_AUTO_CHANNEL */ ++#ifdef CUSTOMER_HW4_PRIVATE_CMD ++#ifdef SUPPORT_SET_LPC ++#define CMD_HAPD_LPC_ENABLED "HAPD_LPC_ENABLED" ++#endif /* SUPPORT_SET_LPC */ ++#ifdef SUPPORT_TRIGGER_HANG_EVENT ++#define CMD_TEST_FORCE_HANG "TEST_FORCE_HANG" ++#endif /* SUPPORT_TRIGGER_HANG_EVENT */ ++#ifdef TEST_TX_POWER_CONTROL ++#define CMD_TEST_SET_TX_POWER "TEST_SET_TX_POWER" ++#define CMD_TEST_GET_TX_POWER "TEST_GET_TX_POWER" ++#endif /* TEST_TX_POWER_CONTROL */ ++#define CMD_SARLIMIT_TX_CONTROL "SET_TX_POWER_CALLING" ++#endif /* CUSTOMER_HW4_PRIVATE_CMD */ ++#define CMD_KEEP_ALIVE "KEEPALIVE" ++ ++ ++#ifdef PNO_SUPPORT ++#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" ++#define CMD_PNOSETUP_SET "PNOSETUP " ++#define CMD_PNOENABLE_SET "PNOFORCE" ++#define CMD_PNODEBUG_SET "PNODEBUG" ++#define CMD_WLS_BATCHING "WLS_BATCHING" ++#endif /* PNO_SUPPORT */ ++ ++#define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER" ++ ++#ifdef CUSTOMER_HW4_PRIVATE_CMD ++ ++ ++#if defined(SUPPORT_RANDOM_MAC_SCAN) ++#define ENABLE_RANDOM_MAC "ENABLE_RANDOM_MAC" ++#define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC" ++#endif /* SUPPORT_RANDOM_MAC_SCAN */ ++ ++ ++#define CMD_CHANGE_RL "CHANGE_RL" ++#define CMD_RESTORE_RL "RESTORE_RL" ++ ++#define CMD_SET_RMC_ENABLE "SETRMCENABLE" ++#define CMD_SET_RMC_TXRATE "SETRMCTXRATE" ++#define CMD_SET_RMC_ACTPERIOD "SETRMCACTIONPERIOD" ++#define CMD_SET_RMC_IDLEPERIOD "SETRMCIDLEPERIOD" ++#define CMD_SET_RMC_LEADER "SETRMCLEADER" ++#define CMD_SET_RMC_EVENT "SETRMCEVENT" ++ ++#define CMD_SET_SCSCAN "SETSINGLEANT" ++#define CMD_GET_SCSCAN "GETSINGLEANT" ++#ifdef WLTDLS ++#define CMD_TDLS_RESET "TDLS_RESET" ++#endif /* WLTDLS */ ++ ++#ifdef FCC_PWR_LIMIT_2G ++#define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL" ++#define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL" ++/* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */ ++#define CUSTOMER_HW4_ENABLE 0 ++#define CUSTOMER_HW4_DISABLE -1 ++#define CUSTOMER_HW4_EN_CONVERT(i) (i += 1) ++#endif /* FCC_PWR_LIMIT_2G */ ++ ++#endif /* CUSTOMER_HW4_PRIVATE_CMD */ ++ ++ ++ ++#define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD" ++#define CMD_INTERFACE_CREATE "INTERFACE_CREATE" ++#define CMD_INTERFACE_DELETE "INTERFACE_DELETE" ++#define CMD_GET_LINK_STATUS "GETLINKSTATUS" ++ ++#if defined(DHD_ENABLE_BIGDATA_LOGGING) ++#define CMD_GET_BSS_INFO "GETBSSINFO" ++#define CMD_GET_ASSOC_REJECT_INFO "GETASSOCREJECTINFO" ++#endif /* DHD_ENABLE_BIGDATA_LOGGING */ ++#define CMD_GET_STA_INFO "GETSTAINFO" ++ ++/* related with CMD_GET_LINK_STATUS */ ++#define WL_ANDROID_LINK_VHT 0x01 ++#define WL_ANDROID_LINK_MIMO 0x02 ++#define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04 ++#define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08 ++ ++#ifdef P2PRESP_WFDIE_SRC ++#define CMD_P2P_SET_WFDIE_RESP "P2P_SET_WFDIE_RESP" ++#define CMD_P2P_GET_WFDIE_RESP "P2P_GET_WFDIE_RESP" ++#endif /* P2PRESP_WFDIE_SRC */ ++ ++#define CMD_DFS_AP_MOVE "DFS_AP_MOVE" ++#define CMD_WBTEXT_ENABLE "WBTEXT_ENABLE" ++#define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG" ++#define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG" ++#define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG" ++#define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG" ++#define CMD_WBTEXT_BTM_TIMER_THRESHOLD "WBTEXT_BTM_TIMER_THRESHOLD" ++#define CMD_WBTEXT_BTM_DELTA "WBTEXT_BTM_DELTA" ++ ++#ifdef WLWFDS ++#define CMD_ADD_WFDS_HASH "ADD_WFDS_HASH" ++#define CMD_DEL_WFDS_HASH "DEL_WFDS_HASH" ++#endif /* WLWFDS */ ++ ++#ifdef SET_RPS_CPUS ++#define CMD_RPSMODE "RPSMODE" ++#endif /* SET_RPS_CPUS */ ++ ++#ifdef BT_WIFI_HANDOVER ++#define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN" ++#endif /* BT_WIFI_HANDOVER */ ++ ++#define CMD_MURX_BFE_CAP "MURX_BFE_CAP" ++ ++#ifdef SUPPORT_AP_HIGHER_BEACONRATE ++#define CMD_SET_AP_BEACONRATE "SET_AP_BEACONRATE" ++#define CMD_GET_AP_BASICRATE "GET_AP_BASICRATE" ++#endif /* SUPPORT_AP_HIGHER_BEACONRATE */ ++ ++#ifdef SUPPORT_AP_RADIO_PWRSAVE ++#define CMD_SET_AP_RPS "SET_AP_RPS" ++#define CMD_GET_AP_RPS "GET_AP_RPS" ++#define CMD_SET_AP_RPS_PARAMS "SET_AP_RPS_PARAMS" ++#endif /* SUPPORT_AP_RADIO_PWRSAVE */ ++ ++#ifdef SUPPORT_RSSI_LOGGING ++#define CMD_SET_RSSI_LOGGING "SET_RSSI_LOGGING" ++#define CMD_GET_RSSI_LOGGING "GET_RSSI_LOGGING" ++#define CMD_GET_RSSI_PER_ANT "GET_RSSI_PER_ANT" ++#endif /* SUPPORT_RSSI_LOGGING */ ++ ++#define CMD_GET_SNR "GET_SNR" ++ ++/* miracast related definition */ ++#define MIRACAST_MODE_OFF 0 ++#define MIRACAST_MODE_SOURCE 1 ++#define MIRACAST_MODE_SINK 2 ++ ++#ifndef MIRACAST_AMPDU_SIZE ++#define MIRACAST_AMPDU_SIZE 8 ++#endif ++ ++#ifndef MIRACAST_MCHAN_ALGO ++#define MIRACAST_MCHAN_ALGO 1 ++#endif ++ ++#ifndef MIRACAST_MCHAN_BW ++#define MIRACAST_MCHAN_BW 25 ++#endif ++ ++#ifdef CONNECTION_STATISTICS ++#define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS" ++ ++struct connection_stats { ++ u32 txframe; ++ u32 txbyte; ++ u32 txerror; ++ u32 rxframe; ++ u32 rxbyte; ++ u32 txfail; ++ u32 txretry; ++ u32 txretrie; ++ u32 txrts; ++ u32 txnocts; ++ u32 txexptime; ++ u32 txrate; ++ u8 chan_idle; ++}; ++#endif /* CONNECTION_STATISTICS */ ++ ++#ifdef SUPPORT_LQCM ++#define CMD_SET_LQCM_ENABLE "SET_LQCM_ENABLE" ++#define CMD_GET_LQCM_REPORT "GET_LQCM_REPORT" ++#endif ++ ++static LIST_HEAD(miracast_resume_list); ++#ifdef WL_CFG80211 ++static u8 miracast_cur_mode; ++#endif ++ ++#ifdef DHD_LOG_DUMP ++#define CMD_NEW_DEBUG_PRINT_DUMP "DEBUG_DUMP" ++extern void dhd_schedule_log_dump(dhd_pub_t *dhdp); ++extern int dhd_bus_mem_dump(dhd_pub_t *dhd); ++#endif /* DHD_LOG_DUMP */ ++ ++#ifdef DHD_HANG_SEND_UP_TEST ++#define CMD_MAKE_HANG "MAKE_HANG" ++#endif /* CMD_DHD_HANG_SEND_UP_TEST */ ++#ifdef DHD_DEBUG_UART ++extern bool dhd_debug_uart_is_running(struct net_device *dev); ++#endif /* DHD_DEBUG_UART */ ++ ++struct io_cfg { ++ s8 *iovar; ++ s32 param; ++ u32 ioctl; ++ void *arg; ++ u32 len; ++ struct list_head list; ++}; ++ ++#if defined(BCMFW_ROAM_ENABLE) ++#define CMD_SET_ROAMPREF "SET_ROAMPREF" ++ ++#define MAX_NUM_SUITES 10 ++#define WIDTH_AKM_SUITE 8 ++#define JOIN_PREF_RSSI_LEN 0x02 ++#define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */ ++#define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */ ++#define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */ ++#define JOIN_PREF_MAX_WPA_TUPLES 16 ++#define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \ ++ (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES)) ++#endif /* BCMFW_ROAM_ENABLE */ ++ ++#ifdef WL_NATOE ++ ++#define CMD_NATOE "NATOE" ++ ++#define NATOE_MAX_PORT_NUM 65535 ++ ++/* natoe command info structure */ ++typedef struct wl_natoe_cmd_info { ++ uint8 *command; /* pointer to the actual command */ ++ uint16 tot_len; /* total length of the command */ ++ uint16 bytes_written; /* Bytes written for get response */ ++} wl_natoe_cmd_info_t; ++ ++typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t; ++typedef int (natoe_cmd_handler_t)(struct net_device *dev, ++ const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); ++ ++struct wl_natoe_sub_cmd { ++ char *name; ++ uint8 version; /* cmd version */ ++ uint16 id; /* id for the dongle f/w switch/case */ ++ uint16 type; /* base type of argument */ ++ natoe_cmd_handler_t *handler; /* cmd handler */ ++}; ++ ++#define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix ++static int wl_android_process_natoe_cmd(struct net_device *dev, ++ char *command, int total_len); ++static int wl_android_natoe_subcmd_enable(struct net_device *dev, ++ const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); ++static int wl_android_natoe_subcmd_config_ips(struct net_device *dev, ++ const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); ++static int wl_android_natoe_subcmd_config_ports(struct net_device *dev, ++ const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); ++static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, ++ const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); ++static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, ++ const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info); ++ ++static const wl_natoe_sub_cmd_t natoe_cmd_list[] = { ++ /* wl natoe enable [0/1] or new: "wl natoe [0/1]" */ ++ {"enable", 0x01, WL_NATOE_CMD_ENABLE, ++ IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable) ++ }, ++ {"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS, ++ IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips) ++ }, ++ {"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS, ++ IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports) ++ }, ++ {"stats", 0x01, WL_NATOE_CMD_DBG_STATS, ++ IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats) ++ }, ++ {"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT, ++ IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt) ++ }, ++ {NULL, 0, 0, 0, NULL} ++}; ++ ++#endif /* WL_NATOE */ ++ ++#ifdef SET_PCIE_IRQ_CPU_CORE ++#define CMD_PCIE_IRQ_CORE "PCIE_IRQ_CORE" ++#endif /* SET_PCIE_IRQ_CPU_CORE */ ++ ++#ifdef WLADPS_PRIVATE_CMD ++#define CMD_SET_ADPS "SET_ADPS" ++#define CMD_GET_ADPS "GET_ADPS" ++#endif /* WLADPS_PRIVATE_CMD */ ++ ++#ifdef DHD_PKT_LOGGING ++#define CMD_PKTLOG_FILTER_ENABLE "PKTLOG_FILTER_ENABLE" ++#define CMD_PKTLOG_FILTER_DISABLE "PKTLOG_FILTER_DISABLE" ++#define CMD_PKTLOG_FILTER_PATTERN_ENABLE "PKTLOG_FILTER_PATTERN_ENABLE" ++#define CMD_PKTLOG_FILTER_PATTERN_DISABLE "PKTLOG_FILTER_PATTERN_DISABLE" ++#define CMD_PKTLOG_FILTER_ADD "PKTLOG_FILTER_ADD" ++#define CMD_PKTLOG_FILTER_INFO "PKTLOG_FILTER_INFO" ++#define CMD_PKTLOG_START "PKTLOG_START" ++#define CMD_PKTLOG_STOP "PKTLOG_STOP" ++#define CMD_PKTLOG_FILTER_EXIST "PKTLOG_FILTER_EXIST" ++#endif /* DHD_PKT_LOGGING */ ++ ++#if defined(STAT_REPORT) ++#define CMD_STAT_REPORT_GET_START "STAT_REPORT_GET_START" ++#define CMD_STAT_REPORT_GET_NEXT "STAT_REPORT_GET_NEXT" ++#endif /* STAT_REPORT */ ++ ++ ++#ifdef SUPPORT_LQCM ++#define LQCM_ENAB_MASK 0x000000FF /* LQCM enable flag mask */ ++#define LQCM_TX_INDEX_MASK 0x0000FF00 /* LQCM tx index mask */ ++#define LQCM_RX_INDEX_MASK 0x00FF0000 /* LQCM rx index mask */ ++ ++#define LQCM_TX_INDEX_SHIFT 8 /* LQCM tx index shift */ ++#define LQCM_RX_INDEX_SHIFT 16 /* LQCM rx index shift */ ++#endif /* SUPPORT_LQCM */ ++ ++/** ++ * Extern function declarations (TODO: move them to dhd_linux.h) ++ */ ++int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); ++int dhd_dev_init_ioctl(struct net_device *dev); ++#ifdef WL_CFG80211 ++int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); ++int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command); ++#else ++int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) ++{ return 0; } ++int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) ++{ return 0; } ++int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) ++{ return 0; } ++int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) ++{ return 0; } ++int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len) ++{ return 0; } ++int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len) ++{ return 0; } ++#endif /* WL_CFG80211 */ ++#ifdef WBTEXT ++static int wl_android_wbtext(struct net_device *dev, char *command, int total_len); ++static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev, ++ char *command, int total_len); ++static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev, ++ char *command, int total_len); ++#endif /* WBTEXT */ ++ ++#ifdef ENABLE_4335BT_WAR ++extern int bcm_bt_lock(int cookie); ++extern void bcm_bt_unlock(int cookie); ++static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ ++#endif /* ENABLE_4335BT_WAR */ ++ ++extern bool ap_fw_loaded; ++extern char iface_name[IFNAMSIZ]; ++ ++/** ++ * Local (static) functions and variables ++ */ ++ ++/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first ++ * time (only) in dhd_open, subsequential wifi on will be handled by ++ * wl_android_wifi_on ++ */ ++int g_wifi_on = TRUE; ++ ++/** ++ * Local (static) function definitions ++ */ ++ ++#ifdef WLWFDS ++static int wl_android_set_wfds_hash( ++ struct net_device *dev, char *command, int total_len, bool enable) ++{ ++ int error = 0; ++ wl_p2p_wfds_hash_t *wfds_hash = NULL; ++ char *smbuf = NULL; ++ smbuf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); ++ ++ if (smbuf == NULL) { ++ ANDROID_ERROR(("%s: failed to allocated memory %d bytes\n", ++ __FUNCTION__, WLC_IOCTL_MAXLEN)); ++ return -ENOMEM; ++ } ++ ++ if (enable) { ++ wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1); ++ error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash, ++ sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL); ++ } ++ else { ++ wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1); ++ error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash, ++ sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL); ++ } ++ ++ if (error) { ++ ANDROID_ERROR(("%s: failed to %s, error=%d\n", __FUNCTION__, command, error)); ++ } ++ ++ if (smbuf) ++ kfree(smbuf); ++ return error; ++} ++#endif /* WLWFDS */ ++ ++static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) ++{ ++ int link_speed; ++ int bytes_written; ++ int error; ++ ++ error = wldev_get_link_speed(net, &link_speed); ++ if (error) { ++ ANDROID_ERROR(("Get linkspeed failed \n")); ++ return -1; ++ } ++ ++ /* Convert Kbps to Android Mbps */ ++ link_speed = link_speed / 1000; ++ bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); ++ ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command)); ++ return bytes_written; ++} ++ ++static int wl_android_get_rssi(struct net_device *net, char *command, int total_len) ++{ ++ wlc_ssid_t ssid = {0, {0}}; ++ int bytes_written = 0; ++ int error = 0; ++ scb_val_t scbval; ++ char *delim = NULL; ++ struct net_device *target_ndev = net; ++#ifdef WL_VIRTUAL_APSTA ++ char *pos = NULL; ++ struct bcm_cfg80211 *cfg; ++#endif /* WL_VIRTUAL_APSTA */ ++ ++ delim = strchr(command, ' '); ++ /* For Ap mode rssi command would be ++ * driver rssi ++ * for STA/GC mode ++ * driver rssi ++ */ ++ if (delim) { ++ /* Ap/GO mode ++ * driver rssi ++ */ ++ ANDROID_TRACE(("%s: cmd:%s\n", __FUNCTION__, delim)); ++ /* skip space from delim after finding char */ ++ delim++; ++ if (!(bcm_ether_atoe((delim), &scbval.ea))) ++ { ++ ANDROID_ERROR(("%s:address err\n", __FUNCTION__)); ++ return -1; ++ } ++ scbval.val = htod32(0); ++ ANDROID_TRACE(("%s: address:"MACDBG, __FUNCTION__, MAC2STRDBG(scbval.ea.octet))); ++#ifdef WL_VIRTUAL_APSTA ++ /* RSDB AP may have another virtual interface ++ * In this case, format of private command is as following, ++ * DRIVER rssi ++ */ ++ ++ /* Current position is start of MAC address string */ ++ pos = delim; ++ delim = strchr(pos, ' '); ++ if (delim) { ++ /* skip space from delim after finding char */ ++ delim++; ++ if (strnlen(delim, IFNAMSIZ)) { ++ cfg = wl_get_cfg(net); ++ target_ndev = wl_get_ap_netdev(cfg, delim); ++ if (target_ndev == NULL) ++ target_ndev = net; ++ } ++ } ++#endif /* WL_VIRTUAL_APSTA */ ++ } ++ else { ++ /* STA/GC mode */ ++ memset(&scbval, 0, sizeof(scb_val_t)); ++ } ++ ++ error = wldev_get_rssi(target_ndev, &scbval); ++ if (error) ++ return -1; ++#if defined(RSSIOFFSET) ++ scbval.val = wl_update_rssi_offset(net, scbval.val); ++#endif ++ ++ error = wldev_get_ssid(target_ndev, &ssid); ++ if (error) ++ return -1; ++ if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) { ++ ANDROID_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__)); ++ } else if (total_len <= ssid.SSID_len) { ++ return -ENOMEM; ++ } else { ++ memcpy(command, ssid.SSID, ssid.SSID_len); ++ bytes_written = ssid.SSID_len; ++ } ++ if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1)) ++ return -ENOMEM; ++ ++ bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written, ++ " rssi %d", scbval.val); ++ command[bytes_written] = '\0'; ++ ++ ANDROID_TRACE(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written)); ++ return bytes_written; ++} ++ ++static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len) ++{ ++ int suspend_flag; ++ int ret_now; ++ int ret = 0; ++ ++ suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; ++ ++ if (suspend_flag != 0) { ++ suspend_flag = 1; ++ } ++ ret_now = net_os_set_suspend_disable(dev, suspend_flag); ++ ++ if (ret_now != suspend_flag) { ++ if (!(ret = net_os_set_suspend(dev, ret_now, 1))) { ++ ANDROID_INFO(("%s: Suspend Flag %d -> %d\n", ++ __FUNCTION__, ret_now, suspend_flag)); ++ } else { ++ ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); ++ } ++ } ++ ++ return ret; ++} ++ ++static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len) ++{ ++ int ret = 0; ++ ++#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) ++ int suspend_flag; ++ ++ suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; ++ if (suspend_flag != 0) ++ suspend_flag = 1; ++ ++ if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) ++ ANDROID_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag)); ++ else ++ ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); ++#endif ++ ++ return ret; ++} ++ ++#ifdef WL_CFG80211 ++int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len) ++{ ++ uint8 mode[5]; ++ int error = 0; ++ int bytes_written = 0; ++ ++ error = wldev_get_mode(dev, mode, sizeof(mode)); ++ if (error) ++ return -1; ++ ++ ANDROID_INFO(("%s: mode:%s\n", __FUNCTION__, mode)); ++ bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode); ++ ANDROID_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command)); ++ return bytes_written; ++ ++} ++ ++extern chanspec_t ++wl_chspec_driver_to_host(chanspec_t chanspec); ++int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int bytes_written = 0; ++ int chsp = {0}; ++ uint16 band = 0; ++ uint16 bw = 0; ++ uint16 channel = 0; ++ u32 sb = 0; ++ chanspec_t chanspec; ++ ++ /* command is ++ * driver chanspec ++ */ ++ error = wldev_iovar_getint(dev, "chanspec", &chsp); ++ if (error) ++ return -1; ++ ++ chanspec = wl_chspec_driver_to_host(chsp); ++ ANDROID_INFO(("%s:return value of chanspec:%x\n", __FUNCTION__, chanspec)); ++ ++ channel = chanspec & WL_CHANSPEC_CHAN_MASK; ++ band = chanspec & WL_CHANSPEC_BAND_MASK; ++ bw = chanspec & WL_CHANSPEC_BW_MASK; ++ ++ ANDROID_INFO(("%s:channel:%d band:%d bandwidth:%d\n", __FUNCTION__, channel, band, bw)); ++ ++ if (bw == WL_CHANSPEC_BW_80) ++ bw = WL_CH_BANDWIDTH_80MHZ; ++ else if (bw == WL_CHANSPEC_BW_40) ++ bw = WL_CH_BANDWIDTH_40MHZ; ++ else if (bw == WL_CHANSPEC_BW_20) ++ bw = WL_CH_BANDWIDTH_20MHZ; ++ else ++ bw = WL_CH_BANDWIDTH_20MHZ; ++ ++ if (bw == WL_CH_BANDWIDTH_40MHZ) { ++ if (CHSPEC_SB_UPPER(chanspec)) { ++ channel += CH_10MHZ_APART; ++ } else { ++ channel -= CH_10MHZ_APART; ++ } ++ } ++ else if (bw == WL_CH_BANDWIDTH_80MHZ) { ++ sb = chanspec & WL_CHANSPEC_CTL_SB_MASK; ++ if (sb == WL_CHANSPEC_CTL_SB_LL) { ++ channel -= (CH_10MHZ_APART + CH_20MHZ_APART); ++ } else if (sb == WL_CHANSPEC_CTL_SB_LU) { ++ channel -= CH_10MHZ_APART; ++ } else if (sb == WL_CHANSPEC_CTL_SB_UL) { ++ channel += CH_10MHZ_APART; ++ } else { ++ /* WL_CHANSPEC_CTL_SB_UU */ ++ channel += (CH_10MHZ_APART + CH_20MHZ_APART); ++ } ++ } ++ bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC, ++ channel, band == WL_CHANSPEC_BAND_5G ? "5G":"2G", bw); ++ ++ ANDROID_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command)); ++ return bytes_written; ++ ++} ++#endif ++ ++/* returns current datarate datarate returned from firmware are in 500kbps */ ++int wl_android_get_datarate(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int datarate = 0; ++ int bytes_written = 0; ++ ++ error = wldev_get_datarate(dev, &datarate); ++ if (error) ++ return -1; ++ ++ ANDROID_INFO(("%s:datarate:%d\n", __FUNCTION__, datarate)); ++ ++ bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2)); ++ return bytes_written; ++} ++int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int bytes_written = 0; ++ uint i; ++ char mac_buf[MAX_NUM_OF_ASSOCLIST * ++ sizeof(struct ether_addr) + sizeof(uint)] = {0}; ++ struct maclist *assoc_maclist = (struct maclist *)mac_buf; ++ ++ ANDROID_TRACE(("%s: ENTER\n", __FUNCTION__)); ++ ++ assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST); ++ ++ error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf)); ++ if (error) ++ return -1; ++ ++ assoc_maclist->count = dtoh32(assoc_maclist->count); ++ bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:", ++ CMD_ASSOC_CLIENTS, assoc_maclist->count); ++ ++ for (i = 0; i < assoc_maclist->count; i++) { ++ bytes_written += snprintf(command + bytes_written, total_len, " " MACDBG, ++ MAC2STRDBG(assoc_maclist->ea[i].octet)); ++ } ++ return bytes_written; ++ ++} ++ ++#ifdef WL_CFG80211 ++extern chanspec_t ++wl_chspec_host_to_driver(chanspec_t chanspec); ++static int wl_android_set_csa(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ char smbuf[WLC_IOCTL_SMLEN]; ++ wl_chan_switch_t csa_arg; ++ u32 chnsp = 0; ++ int err = 0; ++ ++ ANDROID_INFO(("%s: command:%s\n", __FUNCTION__, command)); ++ ++ command = (command + strlen(CMD_SET_CSA)); ++ /* Order is mode, count channel */ ++ if (!*++command) { ++ ANDROID_ERROR(("%s:error missing arguments\n", __FUNCTION__)); ++ return -1; ++ } ++ csa_arg.mode = bcm_atoi(command); ++ ++ if (csa_arg.mode != 0 && csa_arg.mode != 1) { ++ ANDROID_ERROR(("Invalid mode\n")); ++ return -1; ++ } ++ ++ if (!*++command) { ++ ANDROID_ERROR(("%s:error missing count\n", __FUNCTION__)); ++ return -1; ++ } ++ command++; ++ csa_arg.count = bcm_atoi(command); ++ ++ csa_arg.reg = 0; ++ csa_arg.chspec = 0; ++ command += 2; ++ if (!*command) { ++ ANDROID_ERROR(("%s:error missing channel\n", __FUNCTION__)); ++ return -1; ++ } ++ ++ chnsp = wf_chspec_aton(command); ++ if (chnsp == 0) { ++ ANDROID_ERROR(("%s:chsp is not correct\n", __FUNCTION__)); ++ return -1; ++ } ++ chnsp = wl_chspec_host_to_driver(chnsp); ++ csa_arg.chspec = chnsp; ++ ++ if (chnsp & WL_CHANSPEC_BAND_5G) { ++ u32 chanspec = chnsp; ++ err = wldev_iovar_getint(dev, "per_chan_info", &chanspec); ++ if (!err) { ++ if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) { ++ ANDROID_ERROR(("Channel is radar sensitive\n")); ++ return -1; ++ } ++ if (chanspec == 0) { ++ ANDROID_ERROR(("Invalid hw channel\n")); ++ return -1; ++ } ++ } else { ++ ANDROID_ERROR(("does not support per_chan_info\n")); ++ return -1; ++ } ++ ANDROID_INFO(("non radar sensitivity\n")); ++ } ++ error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg), ++ smbuf, sizeof(smbuf), NULL); ++ if (error) { ++ ANDROID_ERROR(("%s:set csa failed:%d\n", __FUNCTION__, error)); ++ return -1; ++ } ++ return 0; ++} ++#endif ++ ++static int ++wl_android_set_max_dtim(struct net_device *dev, char *command, int total_len) ++{ ++ int ret = 0; ++ int dtim_flag; ++ ++ dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0'; ++ ++ if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) { ++ ANDROID_TRACE(("%s: use Max bcn_li_dtim in suspend %s\n", ++ __FUNCTION__, (dtim_flag ? "Enable" : "Disable"))); ++ } else { ++ ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); ++ } ++ ++ return ret; ++} ++ ++static int wl_android_get_band(struct net_device *dev, char *command, int total_len) ++{ ++ uint band; ++ int bytes_written; ++ int error; ++ ++ error = wldev_get_band(dev, &band); ++ if (error) ++ return -1; ++ bytes_written = snprintf(command, total_len, "Band %d", band); ++ return bytes_written; ++} ++ ++#ifdef CUSTOMER_HW4_PRIVATE_CMD ++ ++#ifdef WLTDLS ++int wl_android_tdls_reset(struct net_device *dev) ++{ ++ int ret = 0; ++ ret = dhd_tdls_enable(dev, false, false, NULL); ++ if (ret < 0) { ++ ANDROID_ERROR(("Disable tdls failed. %d\n", ret)); ++ return ret; ++ } ++ ret = dhd_tdls_enable(dev, true, true, NULL); ++ if (ret < 0) { ++ ANDROID_ERROR(("enable tdls failed. %d\n", ret)); ++ return ret; ++ } ++ return 0; ++} ++#endif /* WLTDLS */ ++#ifdef FCC_PWR_LIMIT_2G ++int ++wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int enable = 0; ++ ++ sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable); ++ ++ if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) { ++ ANDROID_ERROR(("%s: Invalid data\n", __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ ++ CUSTOMER_HW4_EN_CONVERT(enable); ++ ++ ANDROID_ERROR(("%s: fccpwrlimit2g set (%d)\n", __FUNCTION__, enable)); ++ error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable); ++ if (error) { ++ ANDROID_ERROR(("%s: fccpwrlimit2g set returned (%d)\n", __FUNCTION__, error)); ++ return BCME_ERROR; ++ } ++ ++ return error; ++} ++ ++int ++wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int enable = 0; ++ int bytes_written = 0; ++ ++ error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable); ++ if (error) { ++ ANDROID_ERROR(("%s: fccpwrlimit2g get error (%d)\n", __FUNCTION__, error)); ++ return BCME_ERROR; ++ } ++ ANDROID_ERROR(("%s: fccpwrlimit2g get (%d)\n", __FUNCTION__, enable)); ++ ++ bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable); ++ ++ return bytes_written; ++} ++#endif /* FCC_PWR_LIMIT_2G */ ++ ++s32 ++wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len) ++{ ++ static char iovar_buf[WLC_IOCTL_MAXLEN]; ++ int bytes_written = -1, ret = 0; ++ char *pcmd = command; ++ char *str; ++ sta_info_t *sta = NULL; ++ wl_cnt_wlc_t* wlc_cnt = NULL; ++ struct ether_addr mac; ++ ++ /* Client information */ ++ uint16 cap = 0; ++ uint32 rxrtry = 0; ++ uint32 rxmulti = 0; ++ ++ ANDROID_TRACE(("%s\n", command)); ++ str = bcmstrtok(&pcmd, " ", NULL); ++ if (str) { ++ str = bcmstrtok(&pcmd, " ", NULL); ++ /* If GETSTAINFO subcmd name is not provided, return error */ ++ if (str == NULL) { ++ ANDROID_ERROR(("GETSTAINFO subcmd not provided %s\n", __FUNCTION__)); ++ goto error; ++ } ++ ++ memset(&mac, 0, ETHER_ADDR_LEN); ++ if ((bcm_ether_atoe((str), &mac))) { ++ /* get the sta info */ ++ ret = wldev_iovar_getbuf(dev, "sta_info", ++ (struct ether_addr *)mac.octet, ++ ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL); ++ if (ret < 0) { ++ ANDROID_ERROR(("Get sta_info ERR %d\n", ret)); ++ goto error; ++ } ++ ++ sta = (sta_info_t *)iovar_buf; ++ cap = dtoh16(sta->cap); ++ rxrtry = dtoh32(sta->rx_pkts_retried); ++ rxmulti = dtoh32(sta->rx_mcast_pkts); ++ } else if ((!strncmp(str, "all", 3)) || (!strncmp(str, "ALL", 3))) { ++ /* get counters info */ ++ ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, ++ iovar_buf, WLC_IOCTL_MAXLEN, NULL); ++ if (unlikely(ret)) { ++ ANDROID_ERROR(("counters error (%d) - size = %zu\n", ++ ret, sizeof(wl_cnt_wlc_t))); ++ goto error; ++ } ++ ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("wl_cntbuf_to_xtlv_format ERR %d\n", ret)); ++ goto error; ++ } ++ if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) { ++ ANDROID_ERROR(("wlc_cnt NULL!\n")); ++ goto error; ++ } ++ ++ rxrtry = dtoh32(wlc_cnt->rxrtry); ++ rxmulti = dtoh32(wlc_cnt->rxmulti); ++ } else { ++ ANDROID_ERROR(("Get address fail\n")); ++ goto error; ++ } ++ } else { ++ ANDROID_ERROR(("Command ERR\n")); ++ goto error; ++ } ++ ++ bytes_written = snprintf(command, total_len, ++ "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x\n", ++ CMD_GET_STA_INFO, str, rxrtry, rxmulti, cap); ++ ++ ANDROID_TRACE(("%s", command)); ++ ++error: ++ return bytes_written; ++} ++#endif ++ ++#ifdef WBTEXT ++static int wl_android_wbtext(struct net_device *dev, char *command, int total_len) ++{ ++ int error = BCME_OK, argc = 0; ++ int data, bytes_written; ++ int roam_trigger[2]; ++ dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev); ++ ++ argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data); ++ if (!argc) { ++ error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data); ++ if (error) { ++ ANDROID_ERROR(("%s: Failed to set wbtext error = %d\n", ++ __FUNCTION__, error)); ++ return error; ++ } ++ bytes_written = snprintf(command, total_len, "WBTEXT %s\n", ++ (data == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)? ++ "ENABLED" : "DISABLED"); ++ return bytes_written; ++ } else { ++ if (data) { ++ data = WL_BSSTRANS_POLICY_PRODUCT_WBTEXT; ++ } ++ ++ if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) { ++ ANDROID_ERROR(("%s: Failed to set wbtext error = %d\n", ++ __FUNCTION__, error)); ++ return error; ++ } ++ ++ if (data) { ++ /* reset roam_prof when wbtext is on */ ++ if ((error = wl_cfg80211_wbtext_set_default(dev)) != BCME_OK) { ++ return error; ++ } ++ dhdp->wbtext_support = TRUE; ++ } else { ++ /* reset legacy roam trigger when wbtext is off */ ++ roam_trigger[0] = DEFAULT_ROAM_TRIGGER_VALUE; ++ roam_trigger[1] = WLC_BAND_ALL; ++ if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, ++ sizeof(roam_trigger))) != BCME_OK) { ++ ANDROID_ERROR(("%s: Failed to reset roam trigger = %d\n", ++ __FUNCTION__, error)); ++ return error; ++ } ++ dhdp->wbtext_support = FALSE; ++ } ++ } ++ return error; ++} ++ ++static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev, ++ char *command, int total_len) ++{ ++ int error = BCME_OK, argc = 0; ++ int data, bytes_written; ++ ++ argc = sscanf(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD " %d\n", &data); ++ if (!argc) { ++ error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data); ++ if (error) { ++ ANDROID_ERROR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error)); ++ return error; ++ } ++ bytes_written = snprintf(command, total_len, "%d\n", data); ++ return bytes_written; ++ } else { ++ if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold", ++ data)) != BCME_OK) { ++ ANDROID_ERROR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error)); ++ return error; ++ } ++ } ++ return error; ++} ++ ++static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev, ++ char *command, int total_len) ++{ ++ int error = BCME_OK, argc = 0; ++ int data = 0, bytes_written; ++ ++ argc = sscanf(command, CMD_WBTEXT_BTM_DELTA " %d\n", &data); ++ if (!argc) { ++ error = wldev_iovar_getint(dev, "wnm_btmdelta", &data); ++ if (error) { ++ ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error)); ++ return error; ++ } ++ bytes_written = snprintf(command, total_len, "%d\n", data); ++ return bytes_written; ++ } else { ++ if ((error = wldev_iovar_setint(dev, "wnm_btmdelta", ++ data)) != BCME_OK) { ++ ANDROID_ERROR(("Failed to set wnm_btmdelta (%d)\n", error)); ++ return error; ++ } ++ } ++ return error; ++} ++ ++#endif /* WBTEXT */ ++ ++#ifdef PNO_SUPPORT ++#define PNO_PARAM_SIZE 50 ++#define VALUE_SIZE 50 ++#define LIMIT_STR_FMT ("%50s %50s") ++ ++static int ++wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len) ++{ ++ int err = BCME_OK; ++ uint i, tokens; ++ char *pos, *pos2, *token, *token2, *delim; ++ char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1]; ++ struct dhd_pno_batch_params batch_params; ++ ++ ANDROID_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); ++ if (total_len < strlen(CMD_WLS_BATCHING)) { ++ ANDROID_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); ++ err = BCME_ERROR; ++ goto exit; ++ } ++ pos = command + strlen(CMD_WLS_BATCHING) + 1; ++ memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params)); ++ ++ if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) { ++ pos += strlen(PNO_BATCHING_SET) + 1; ++ while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) { ++ memset(param, 0, sizeof(param)); ++ memset(value, 0, sizeof(value)); ++ if (token == NULL || !*token) ++ break; ++ if (*token == '\0') ++ continue; ++ delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER); ++ if (delim != NULL) ++ *delim = ' '; ++ ++ tokens = sscanf(token, LIMIT_STR_FMT, param, value); ++ if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) { ++ batch_params.scan_fr = simple_strtol(value, NULL, 0); ++ ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr)); ++ } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) { ++ batch_params.bestn = simple_strtol(value, NULL, 0); ++ ANDROID_INFO(("bestn : %d\n", batch_params.bestn)); ++ } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) { ++ batch_params.mscan = simple_strtol(value, NULL, 0); ++ ANDROID_INFO(("mscan : %d\n", batch_params.mscan)); ++ } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) { ++ i = 0; ++ pos2 = value; ++ tokens = sscanf(value, "<%s>", value); ++ if (tokens != 1) { ++ err = BCME_ERROR; ++ ANDROID_ERROR(("%s : invalid format for channel" ++ " <> params\n", __FUNCTION__)); ++ goto exit; ++ } ++ while ((token2 = strsep(&pos2, ++ PNO_PARAM_CHANNEL_DELIMETER)) != NULL) { ++ if (token2 == NULL || !*token2) ++ break; ++ if (*token2 == '\0') ++ continue; ++ if (*token2 == 'A' || *token2 == 'B') { ++ batch_params.band = (*token2 == 'A')? ++ WLC_BAND_5G : WLC_BAND_2G; ++ ANDROID_INFO(("band : %s\n", ++ (*token2 == 'A')? "A" : "B")); ++ } else { ++ if ((batch_params.nchan >= WL_NUMCHANNELS) || ++ (i >= WL_NUMCHANNELS)) { ++ ANDROID_ERROR(("Too many nchan %d\n", ++ batch_params.nchan)); ++ err = BCME_BUFTOOSHORT; ++ goto exit; ++ } ++ batch_params.chan_list[i++] = ++ simple_strtol(token2, NULL, 0); ++ batch_params.nchan++; ++ ANDROID_INFO(("channel :%d\n", ++ batch_params.chan_list[i-1])); ++ } ++ } ++ } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) { ++ batch_params.rtt = simple_strtol(value, NULL, 0); ++ ANDROID_INFO(("rtt : %d\n", batch_params.rtt)); ++ } else { ++ ANDROID_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param)); ++ err = BCME_ERROR; ++ goto exit; ++ } ++ } ++ err = dhd_dev_pno_set_for_batch(dev, &batch_params); ++ if (err < 0) { ++ ANDROID_ERROR(("failed to configure batch scan\n")); ++ } else { ++ memset(command, 0, total_len); ++ err = snprintf(command, total_len, "%d", err); ++ } ++ } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) { ++ err = dhd_dev_pno_get_for_batch(dev, command, total_len); ++ if (err < 0) { ++ ANDROID_ERROR(("failed to getting batching results\n")); ++ } else { ++ err = strlen(command); ++ } ++ } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) { ++ err = dhd_dev_pno_stop_for_batch(dev); ++ if (err < 0) { ++ ANDROID_ERROR(("failed to stop batching scan\n")); ++ } else { ++ memset(command, 0, total_len); ++ err = snprintf(command, total_len, "OK"); ++ } ++ } else { ++ ANDROID_ERROR(("%s : unknown command\n", __FUNCTION__)); ++ err = BCME_ERROR; ++ goto exit; ++ } ++exit: ++ return err; ++} ++ ++#ifndef WL_SCHED_SCAN ++static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) ++{ ++ wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; ++ int res = -1; ++ int nssid = 0; ++ cmd_tlv_t *cmd_tlv_temp; ++ char *str_ptr; ++ int tlv_size_left; ++ int pno_time = 0; ++ int pno_repeat = 0; ++ int pno_freq_expo_max = 0; ++ ++#ifdef PNO_SET_DEBUG ++ int i; ++ char pno_in_example[] = { ++ 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', ++ 'S', '1', '2', '0', ++ 'S', ++ 0x05, ++ 'd', 'l', 'i', 'n', 'k', ++ 'S', ++ 0x04, ++ 'G', 'O', 'O', 'G', ++ 'T', ++ '0', 'B', ++ 'R', ++ '2', ++ 'M', ++ '2', ++ 0x00 ++ }; ++#endif /* PNO_SET_DEBUG */ ++ ANDROID_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len)); ++ ++ if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) { ++ ANDROID_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len)); ++ goto exit_proc; ++ } ++#ifdef PNO_SET_DEBUG ++ memcpy(command, pno_in_example, sizeof(pno_in_example)); ++ total_len = sizeof(pno_in_example); ++#endif ++ str_ptr = command + strlen(CMD_PNOSETUP_SET); ++ tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET); ++ ++ cmd_tlv_temp = (cmd_tlv_t *)str_ptr; ++ memset(ssids_local, 0, sizeof(ssids_local)); ++ ++ if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && ++ (cmd_tlv_temp->version == PNO_TLV_VERSION) && ++ (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) { ++ ++ str_ptr += sizeof(cmd_tlv_t); ++ tlv_size_left -= sizeof(cmd_tlv_t); ++ ++ if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local, ++ MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) { ++ ANDROID_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid)); ++ goto exit_proc; ++ } else { ++ if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) { ++ ANDROID_ERROR(("%s scan duration corrupted field size %d\n", ++ __FUNCTION__, tlv_size_left)); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_time = simple_strtoul(str_ptr, &str_ptr, 16); ++ ANDROID_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time)); ++ ++ if (str_ptr[0] != 0) { ++ if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) { ++ ANDROID_ERROR(("%s pno repeat : corrupted field\n", ++ __FUNCTION__)); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16); ++ ANDROID_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat)); ++ if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) { ++ ANDROID_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", ++ __FUNCTION__)); ++ goto exit_proc; ++ } ++ str_ptr++; ++ pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16); ++ ANDROID_INFO(("%s: pno_freq_expo_max=%d\n", ++ __FUNCTION__, pno_freq_expo_max)); ++ } ++ } ++ } else { ++ ANDROID_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); ++ goto exit_proc; ++ } ++ ++ res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat, ++ pno_freq_expo_max, NULL, 0); ++exit_proc: ++ return res; ++} ++#endif /* !WL_SCHED_SCAN */ ++#endif /* PNO_SUPPORT */ ++ ++static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) ++{ ++ int ret; ++ int bytes_written = 0; ++ ++ ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command); ++ if (ret) ++ return 0; ++ bytes_written = sizeof(struct ether_addr); ++ return bytes_written; ++} ++ ++ ++int ++wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist) ++{ ++ int i, j, match; ++ int ret = 0; ++ char mac_buf[MAX_NUM_OF_ASSOCLIST * ++ sizeof(struct ether_addr) + sizeof(uint)] = {0}; ++ struct maclist *assoc_maclist = (struct maclist *)mac_buf; ++ ++ /* set filtering mode */ ++ if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) { ++ ANDROID_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret)); ++ return ret; ++ } ++ if (macmode != MACLIST_MODE_DISABLED) { ++ /* set the MAC filter list */ ++ if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist, ++ sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) { ++ ANDROID_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret)); ++ return ret; ++ } ++ /* get the current list of associated STAs */ ++ assoc_maclist->count = MAX_NUM_OF_ASSOCLIST; ++ if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, ++ sizeof(mac_buf))) != 0) { ++ ANDROID_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret)); ++ return ret; ++ } ++ /* do we have any STA associated? */ ++ if (assoc_maclist->count) { ++ /* iterate each associated STA */ ++ for (i = 0; i < assoc_maclist->count; i++) { ++ match = 0; ++ /* compare with each entry */ ++ for (j = 0; j < maclist->count; j++) { ++ ANDROID_INFO(("%s : associated="MACDBG " list="MACDBG "\n", ++ __FUNCTION__, MAC2STRDBG(assoc_maclist->ea[i].octet), ++ MAC2STRDBG(maclist->ea[j].octet))); ++ if (memcmp(assoc_maclist->ea[i].octet, ++ maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) { ++ match = 1; ++ break; ++ } ++ } ++ /* do conditional deauth */ ++ /* "if not in the allow list" or "if in the deny list" */ ++ if ((macmode == MACLIST_MODE_ALLOW && !match) || ++ (macmode == MACLIST_MODE_DENY && match)) { ++ scb_val_t scbval; ++ ++ scbval.val = htod32(1); ++ memcpy(&scbval.ea, &assoc_maclist->ea[i], ++ ETHER_ADDR_LEN); ++ if ((ret = wldev_ioctl_set(dev, ++ WLC_SCB_DEAUTHENTICATE_FOR_REASON, ++ &scbval, sizeof(scb_val_t))) != 0) ++ ANDROID_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n", ++ __FUNCTION__, ret)); ++ } ++ } ++ } ++ } ++ return ret; ++} ++ ++/* ++ * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2 ++ * ++ */ ++static int ++wl_android_set_mac_address_filter(struct net_device *dev, char* str) ++{ ++ int i; ++ int ret = 0; ++ int macnum = 0; ++ int macmode = MACLIST_MODE_DISABLED; ++ struct maclist *list; ++ char eabuf[ETHER_ADDR_STR_LEN]; ++ const char *token; ++ ++ /* string should look like below (macmode/macnum/maclist) */ ++ /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */ ++ ++ /* get the MAC filter mode */ ++ token = strsep((char**)&str, " "); ++ if (!token) { ++ return -1; ++ } ++ macmode = bcm_atoi(token); ++ ++ if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) { ++ ANDROID_ERROR(("%s : invalid macmode %d\n", __FUNCTION__, macmode)); ++ return -1; ++ } ++ ++ token = strsep((char**)&str, " "); ++ if (!token) { ++ return -1; ++ } ++ macnum = bcm_atoi(token); ++ if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) { ++ ANDROID_ERROR(("%s : invalid number of MAC address entries %d\n", ++ __FUNCTION__, macnum)); ++ return -1; ++ } ++ /* allocate memory for the MAC list */ ++ list = (struct maclist*)kmalloc(sizeof(int) + ++ sizeof(struct ether_addr) * macnum, GFP_KERNEL); ++ if (!list) { ++ ANDROID_ERROR(("%s : failed to allocate memory\n", __FUNCTION__)); ++ return -1; ++ } ++ /* prepare the MAC list */ ++ list->count = htod32(macnum); ++ bzero((char *)eabuf, ETHER_ADDR_STR_LEN); ++ for (i = 0; i < list->count; i++) { ++ strncpy(eabuf, strsep((char**)&str, " "), ETHER_ADDR_STR_LEN - 1); ++ if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) { ++ ANDROID_ERROR(("%s : mac parsing err index=%d, addr=%s\n", ++ __FUNCTION__, i, eabuf)); ++ list->count--; ++ break; ++ } ++ ANDROID_INFO(("%s : %d/%d MACADDR=%s", __FUNCTION__, i, list->count, eabuf)); ++ } ++ /* set the list */ ++ if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0) ++ ANDROID_ERROR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret)); ++ ++ kfree(list); ++ ++ return 0; ++} ++ ++/** ++ * Global function definitions (declared in wl_android.h) ++ */ ++ ++int wl_android_wifi_on(struct net_device *dev) ++{ ++ int ret = 0; ++ int retry = POWERUP_MAX_RETRY; ++ ++ if (!dev) { ++ ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__)); ++ return -EINVAL; ++ } ++ ++ dhd_net_if_lock(dev); ++ WL_MSG(dev->name, "in g_wifi_on=%d\n", g_wifi_on); ++ if (!g_wifi_on) { ++ do { ++ if (!dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY)) { ++#ifdef BCMSDIO ++ ret = dhd_net_bus_resume(dev, 0); ++#endif /* BCMSDIO */ ++ } ++#ifdef BCMPCIE ++ ret = dhd_net_bus_devreset(dev, FALSE); ++#endif /* BCMPCIE */ ++ if (ret == 0) { ++ break; ++ } ++ ANDROID_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n", ++ retry)); ++#ifdef BCMPCIE ++ dhd_net_bus_devreset(dev, TRUE); ++#endif /* BCMPCIE */ ++ dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); ++ } while (retry-- > 0); ++ if (ret != 0) { ++ ANDROID_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n")); ++ goto exit; ++ } ++#if defined(BCMSDIO) || defined(BCMDBUS) ++ ret = dhd_net_bus_devreset(dev, FALSE); ++ if (ret) ++ goto err; ++#ifdef BCMSDIO ++ dhd_net_bus_resume(dev, 1); ++#endif /* BCMSDIO */ ++#endif /* BCMSDIO || BCMDBUS */ ++#if defined(BCMSDIO) || defined(BCMDBUS) ++ if (!ret) { ++ if (dhd_dev_init_ioctl(dev) < 0) { ++ ret = -EFAULT; ++ goto err; ++ } ++ } ++#endif /* BCMSDIO || BCMDBUS */ ++ g_wifi_on = TRUE; ++ } ++ ++exit: ++ WL_MSG(dev->name, "Success\n"); ++ dhd_net_if_unlock(dev); ++ return ret; ++ ++#if defined(BCMSDIO) || defined(BCMDBUS) ++err: ++ dhd_net_bus_devreset(dev, TRUE); ++#ifdef BCMSDIO ++ dhd_net_bus_suspend(dev); ++#endif /* BCMSDIO */ ++ dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); ++ WL_MSG(dev->name, "Failed\n"); ++ dhd_net_if_unlock(dev); ++ return ret; ++#endif /* BCMSDIO || BCMDBUS */ ++} ++ ++int wl_android_wifi_off(struct net_device *dev, bool on_failure) ++{ ++ int ret = 0; ++ ++ if (!dev) { ++ ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__)); ++ return -EINVAL; ++ } ++ ++#if defined(BCMPCIE) && defined(DHD_DEBUG_UART) ++ ret = dhd_debug_uart_is_running(dev); ++ if (ret) { ++ ANDROID_ERROR(("%s - Debug UART App is running\n", __FUNCTION__)); ++ return -EBUSY; ++ } ++#endif /* BCMPCIE && DHD_DEBUG_UART */ ++ dhd_net_if_lock(dev); ++ WL_MSG(dev->name, "in g_wifi_on=%d, on_failure=%d\n", g_wifi_on, on_failure); ++ if (g_wifi_on || on_failure) { ++#if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS) ++ ret = dhd_net_bus_devreset(dev, TRUE); ++#if defined(BCMSDIO) ++ dhd_net_bus_suspend(dev); ++#endif /* BCMSDIO */ ++#endif /* BCMSDIO || BCMPCIE || BCMDBUS */ ++ dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY); ++ g_wifi_on = FALSE; ++ } ++ WL_MSG(dev->name, "out\n"); ++ dhd_net_if_unlock(dev); ++ ++ return ret; ++} ++ ++static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len) ++{ ++ if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN) ++ return -1; ++ return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1); ++} ++ ++#ifdef CONNECTION_STATISTICS ++static int ++wl_chanim_stats(struct net_device *dev, u8 *chan_idle) ++{ ++ int err; ++ wl_chanim_stats_t *list; ++ /* Parameter _and_ returned buffer of chanim_stats. */ ++ wl_chanim_stats_t param; ++ u8 result[WLC_IOCTL_SMLEN]; ++ chanim_stats_t *stats; ++ ++ memset(¶m, 0, sizeof(param)); ++ ++ param.buflen = htod32(sizeof(wl_chanim_stats_t)); ++ param.count = htod32(WL_CHANIM_COUNT_ONE); ++ ++ if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)¶m, sizeof(wl_chanim_stats_t), ++ (char*)result, sizeof(result), 0)) < 0) { ++ ANDROID_ERROR(("Failed to get chanim results %d \n", err)); ++ return err; ++ } ++ ++ list = (wl_chanim_stats_t*)result; ++ ++ list->buflen = dtoh32(list->buflen); ++ list->version = dtoh32(list->version); ++ list->count = dtoh32(list->count); ++ ++ if (list->buflen == 0) { ++ list->version = 0; ++ list->count = 0; ++ } else if (list->version != WL_CHANIM_STATS_VERSION) { ++ ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d " ++ "but driver supports only version %d.\n", ++ list->version, WL_CHANIM_STATS_VERSION)); ++ list->buflen = 0; ++ list->count = 0; ++ } ++ ++ stats = list->stats; ++ stats->glitchcnt = dtoh32(stats->glitchcnt); ++ stats->badplcp = dtoh32(stats->badplcp); ++ stats->chanspec = dtoh16(stats->chanspec); ++ stats->timestamp = dtoh32(stats->timestamp); ++ stats->chan_idle = dtoh32(stats->chan_idle); ++ ++ ANDROID_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n", ++ stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle, ++ stats->timestamp)); ++ ++ *chan_idle = stats->chan_idle; ++ ++ return (err); ++} ++ ++static int ++wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len) ++{ ++ static char iovar_buf[WLC_IOCTL_MAXLEN]; ++ wl_cnt_wlc_t* wlc_cnt = NULL; ++#ifndef DISABLE_IF_COUNTERS ++ wl_if_stats_t* if_stats = NULL; ++#endif /* DISABLE_IF_COUNTERS */ ++ ++ int link_speed = 0; ++ struct connection_stats *output; ++ unsigned int bufsize = 0; ++ int bytes_written = -1; ++ int ret = 0; ++ ++ ANDROID_INFO(("%s: enter Get Connection Stats\n", __FUNCTION__)); ++ ++ if (total_len <= 0) { ++ ANDROID_ERROR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len)); ++ goto error; ++ } ++ ++ bufsize = total_len; ++ if (bufsize < sizeof(struct connection_stats)) { ++ ANDROID_ERROR(("%s: not enough buffer size, provided=%u, requires=%zu\n", ++ __FUNCTION__, bufsize, ++ sizeof(struct connection_stats))); ++ goto error; ++ } ++ ++ output = (struct connection_stats *)command; ++ ++#ifndef DISABLE_IF_COUNTERS ++ if ((if_stats = kmalloc(sizeof(*if_stats), GFP_KERNEL)) == NULL) { ++ ANDROID_ERROR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__)); ++ goto error; ++ } ++ memset(if_stats, 0, sizeof(*if_stats)); ++ ++ ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0, ++ (char *)if_stats, sizeof(*if_stats), NULL); ++ if (ret) { ++ ANDROID_ERROR(("%s: if_counters not supported ret=%d\n", ++ __FUNCTION__, ret)); ++ ++ /* In case if_stats IOVAR is not supported, get information from counters. */ ++#endif /* DISABLE_IF_COUNTERS */ ++ ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, ++ iovar_buf, WLC_IOCTL_MAXLEN, NULL); ++ if (unlikely(ret)) { ++ ANDROID_ERROR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t))); ++ goto error; ++ } ++ ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("%s wl_cntbuf_to_xtlv_format ERR %d\n", ++ __FUNCTION__, ret)); ++ goto error; ++ } ++ ++ if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) { ++ ANDROID_ERROR(("%s wlc_cnt NULL!\n", __FUNCTION__)); ++ goto error; ++ } ++ ++ output->txframe = dtoh32(wlc_cnt->txframe); ++ output->txbyte = dtoh32(wlc_cnt->txbyte); ++ output->txerror = dtoh32(wlc_cnt->txerror); ++ output->rxframe = dtoh32(wlc_cnt->rxframe); ++ output->rxbyte = dtoh32(wlc_cnt->rxbyte); ++ output->txfail = dtoh32(wlc_cnt->txfail); ++ output->txretry = dtoh32(wlc_cnt->txretry); ++ output->txretrie = dtoh32(wlc_cnt->txretrie); ++ output->txrts = dtoh32(wlc_cnt->txrts); ++ output->txnocts = dtoh32(wlc_cnt->txnocts); ++ output->txexptime = dtoh32(wlc_cnt->txexptime); ++#ifndef DISABLE_IF_COUNTERS ++ } else { ++ /* Populate from if_stats. */ ++ if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) { ++ ANDROID_ERROR(("%s: incorrect version of wl_if_stats_t, expected=%u got=%u\n", ++ __FUNCTION__, WL_IF_STATS_T_VERSION, if_stats->version)); ++ goto error; ++ } ++ ++ output->txframe = (uint32)dtoh64(if_stats->txframe); ++ output->txbyte = (uint32)dtoh64(if_stats->txbyte); ++ output->txerror = (uint32)dtoh64(if_stats->txerror); ++ output->rxframe = (uint32)dtoh64(if_stats->rxframe); ++ output->rxbyte = (uint32)dtoh64(if_stats->rxbyte); ++ output->txfail = (uint32)dtoh64(if_stats->txfail); ++ output->txretry = (uint32)dtoh64(if_stats->txretry); ++ output->txretrie = (uint32)dtoh64(if_stats->txretrie); ++ if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) { ++ output->txexptime = (uint32)dtoh64(if_stats->txexptime); ++ output->txrts = (uint32)dtoh64(if_stats->txrts); ++ output->txnocts = (uint32)dtoh64(if_stats->txnocts); ++ } else { ++ output->txexptime = 0; ++ output->txrts = 0; ++ output->txnocts = 0; ++ } ++ } ++#endif /* DISABLE_IF_COUNTERS */ ++ ++ /* link_speed is in kbps */ ++ ret = wldev_get_link_speed(dev, &link_speed); ++ if (ret || link_speed < 0) { ++ ANDROID_ERROR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n", ++ __FUNCTION__, ret, link_speed)); ++ goto error; ++ } ++ ++ output->txrate = link_speed; ++ ++ /* Channel idle ratio. */ ++ if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) { ++ output->chan_idle = 0; ++ }; ++ ++ bytes_written = sizeof(struct connection_stats); ++ ++error: ++#ifndef DISABLE_IF_COUNTERS ++ if (if_stats) { ++ kfree(if_stats); ++ } ++#endif /* DISABLE_IF_COUNTERS */ ++ ++ return bytes_written; ++} ++#endif /* CONNECTION_STATISTICS */ ++ ++#ifdef WL_NATOE ++static int ++wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len) ++{ ++ int ret = BCME_ERROR; ++ char *pcmd = command; ++ char *str = NULL; ++ wl_natoe_cmd_info_t cmd_info; ++ const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0]; ++ ++ /* skip to cmd name after "natoe" */ ++ str = bcmstrtok(&pcmd, " ", NULL); ++ ++ /* If natoe subcmd name is not provided, return error */ ++ if (*pcmd == '\0') { ++ ANDROID_ERROR(("natoe subcmd not provided %s\n", __FUNCTION__)); ++ ret = -EINVAL; ++ return ret; ++ } ++ ++ /* get the natoe command name to str */ ++ str = bcmstrtok(&pcmd, " ", NULL); ++ ++ while (natoe_cmd->name != NULL) { ++ if (strcmp(natoe_cmd->name, str) == 0) { ++ /* dispacth cmd to appropriate handler */ ++ if (natoe_cmd->handler) { ++ cmd_info.command = command; ++ cmd_info.tot_len = total_len; ++ ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info); ++ } ++ return ret; ++ } ++ natoe_cmd++; ++ } ++ return ret; ++} ++ ++static int ++wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len) ++{ ++ int res = BCME_OK; ++ wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx; ++ uint8 *command = cmd_info->command; ++ uint16 total_len = cmd_info->tot_len; ++ uint16 bytes_written = 0; ++ ++ UNUSED_PARAMETER(len); ++ ++ switch (type) { ++ ++ case WL_NATOE_XTLV_ENABLE: ++ { ++ bytes_written = snprintf(command, total_len, "natoe: %s\n", ++ *data?"enabled":"disabled"); ++ cmd_info->bytes_written = bytes_written; ++ break; ++ } ++ ++ case WL_NATOE_XTLV_CONFIG_IPS: ++ { ++ wl_natoe_config_ips_t *config_ips; ++ uint8 buf[16]; ++ ++ config_ips = (wl_natoe_config_ips_t *)data; ++ bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf); ++ bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf); ++ bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf); ++ bytes_written += snprintf(command + bytes_written, total_len, ++ "sta netmask: %s\n", buf); ++ bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf); ++ bytes_written += snprintf(command + bytes_written, total_len, ++ "sta router ip: %s\n", buf); ++ bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf); ++ bytes_written += snprintf(command + bytes_written, total_len, ++ "sta dns ip: %s\n", buf); ++ bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf); ++ bytes_written += snprintf(command + bytes_written, total_len, ++ "ap ip: %s\n", buf); ++ bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf); ++ bytes_written += snprintf(command + bytes_written, total_len, ++ "ap netmask: %s\n", buf); ++ cmd_info->bytes_written = bytes_written; ++ break; ++ } ++ ++ case WL_NATOE_XTLV_CONFIG_PORTS: ++ { ++ wl_natoe_ports_config_t *ports_config; ++ ++ ports_config = (wl_natoe_ports_config_t *)data; ++ bytes_written = snprintf(command, total_len, "starting port num: %d\n", ++ dtoh16(ports_config->start_port_num)); ++ bytes_written += snprintf(command + bytes_written, total_len, ++ "number of ports: %d\n", dtoh16(ports_config->no_of_ports)); ++ cmd_info->bytes_written = bytes_written; ++ break; ++ } ++ ++ case WL_NATOE_XTLV_DBG_STATS: ++ { ++ char *stats_dump = (char *)data; ++ ++ bytes_written = snprintf(command, total_len, "%s\n", stats_dump); ++ cmd_info->bytes_written = bytes_written; ++ break; ++ } ++ ++ case WL_NATOE_XTLV_TBL_CNT: ++ { ++ bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n", ++ dtoh32(*(uint32 *)data)); ++ cmd_info->bytes_written = bytes_written; ++ break; ++ } ++ ++ default: ++ /* ignore */ ++ break; ++ } ++ ++ return res; ++} ++ ++/* ++ * --- common for all natoe get commands ---- ++ */ ++static int ++wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc, ++ uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info) ++{ ++ /* for gets we only need to pass ioc header */ ++ wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf; ++ int res; ++ ++ /* send getbuf natoe iovar */ ++ res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf, ++ buflen, NULL); ++ ++ /* check the response buff */ ++ if ((res == BCME_OK)) { ++ /* scans ioctl tlvbuf f& invokes the cbfn for processing */ ++ res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len, ++ BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn); ++ ++ if (res == BCME_OK) { ++ res = cmd_info->bytes_written; ++ } ++ } ++ else ++ { ++ ANDROID_ERROR(("%s: get command failed code %d\n", __FUNCTION__, res)); ++ res = BCME_ERROR; ++ } ++ ++ return res; ++} ++ ++static int ++wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd, ++ char *command, wl_natoe_cmd_info_t *cmd_info) ++{ ++ int ret = BCME_OK; ++ wl_natoe_ioc_t *natoe_ioc; ++ char *pcmd = command; ++ uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ; ++ uint16 buflen = WL_NATOE_IOC_BUFSZ; ++ bcm_xtlv_t *pxtlv = NULL; ++ char *ioctl_buf = NULL; ++ ++ ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, kflags); ++ if (!ioctl_buf) { ++ ANDROID_ERROR(("ioctl memory alloc failed\n")); ++ return -ENOMEM; ++ } ++ ++ /* alloc mem for ioctl headr + tlv data */ ++ natoe_ioc = kzalloc(iocsz, kflags); ++ if (!natoe_ioc) { ++ ANDROID_ERROR(("ioctl header memory alloc failed\n")); ++ kfree(ioctl_buf); ++ return -ENOMEM; ++ } ++ ++ /* make up natoe cmd ioctl header */ ++ natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION); ++ natoe_ioc->id = htod16(cmd->id); ++ natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ); ++ pxtlv = (bcm_xtlv_t *)natoe_ioc->data; ++ ++ if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */ ++ iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv); ++ ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf, ++ WLC_IOCTL_MEDLEN, cmd_info); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("Fail to get iovar %s\n", __FUNCTION__)); ++ ret = -EINVAL; ++ } ++ } else { /* set */ ++ uint8 val = bcm_atoi(pcmd); ++ ++ /* buflen is max tlv data we can write, it will be decremented as we pack */ ++ /* save buflen at start */ ++ uint16 buflen_at_start = buflen; ++ ++ /* we'll adjust final ioc size at the end */ ++ ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE, ++ sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32); ++ ++ if (ret != BCME_OK) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ /* adjust iocsz to the end of last data record */ ++ natoe_ioc->len = (buflen_at_start - buflen); ++ iocsz = sizeof(*natoe_ioc) + natoe_ioc->len; ++ ++ ret = wldev_iovar_setbuf(dev, "natoe", ++ natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("Fail to set iovar %d\n", ret)); ++ ret = -EINVAL; ++ } ++ } ++ ++exit: ++ kfree(ioctl_buf); ++ kfree(natoe_ioc); ++ ++ return ret; ++} ++ ++static int ++wl_android_natoe_subcmd_config_ips(struct net_device *dev, ++ const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info) ++{ ++ int ret = BCME_OK; ++ wl_natoe_config_ips_t config_ips; ++ wl_natoe_ioc_t *natoe_ioc; ++ char *pcmd = command; ++ char *str; ++ uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ; ++ uint16 buflen = WL_NATOE_IOC_BUFSZ; ++ bcm_xtlv_t *pxtlv = NULL; ++ char *ioctl_buf = NULL; ++ ++ ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, kflags); ++ if (!ioctl_buf) { ++ ANDROID_ERROR(("ioctl memory alloc failed\n")); ++ return -ENOMEM; ++ } ++ ++ /* alloc mem for ioctl headr + tlv data */ ++ natoe_ioc = kzalloc(iocsz, kflags); ++ if (!natoe_ioc) { ++ ANDROID_ERROR(("ioctl header memory alloc failed\n")); ++ kfree(ioctl_buf); ++ return -ENOMEM; ++ } ++ ++ /* make up natoe cmd ioctl header */ ++ natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION); ++ natoe_ioc->id = htod16(cmd->id); ++ natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ); ++ pxtlv = (bcm_xtlv_t *)natoe_ioc->data; ++ ++ if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */ ++ iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv); ++ ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf, ++ WLC_IOCTL_MEDLEN, cmd_info); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("Fail to get iovar %s\n", __FUNCTION__)); ++ ret = -EINVAL; ++ } ++ } else { /* set */ ++ /* buflen is max tlv data we can write, it will be decremented as we pack */ ++ /* save buflen at start */ ++ uint16 buflen_at_start = buflen; ++ ++ memset(&config_ips, 0, sizeof(config_ips)); ++ ++ str = bcmstrtok(&pcmd, " ", NULL); ++ if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) { ++ ANDROID_ERROR(("Invalid STA IP addr %s\n", str)); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ str = bcmstrtok(&pcmd, " ", NULL); ++ if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) { ++ ANDROID_ERROR(("Invalid STA netmask %s\n", str)); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ str = bcmstrtok(&pcmd, " ", NULL); ++ if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) { ++ ANDROID_ERROR(("Invalid STA router IP addr %s\n", str)); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ str = bcmstrtok(&pcmd, " ", NULL); ++ if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) { ++ ANDROID_ERROR(("Invalid STA DNS IP addr %s\n", str)); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ str = bcmstrtok(&pcmd, " ", NULL); ++ if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) { ++ ANDROID_ERROR(("Invalid AP IP addr %s\n", str)); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ str = bcmstrtok(&pcmd, " ", NULL); ++ if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) { ++ ANDROID_ERROR(("Invalid AP netmask %s\n", str)); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, ++ &buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips), ++ &config_ips, BCM_XTLV_OPTION_ALIGN32); ++ ++ if (ret != BCME_OK) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ /* adjust iocsz to the end of last data record */ ++ natoe_ioc->len = (buflen_at_start - buflen); ++ iocsz = sizeof(*natoe_ioc) + natoe_ioc->len; ++ ++ ret = wldev_iovar_setbuf(dev, "natoe", ++ natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("Fail to set iovar %d\n", ret)); ++ ret = -EINVAL; ++ } ++ } ++ ++exit: ++ kfree(ioctl_buf); ++ kfree(natoe_ioc); ++ ++ return ret; ++} ++ ++static int ++wl_android_natoe_subcmd_config_ports(struct net_device *dev, ++ const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info) ++{ ++ int ret = BCME_OK; ++ wl_natoe_ports_config_t ports_config; ++ wl_natoe_ioc_t *natoe_ioc; ++ char *pcmd = command; ++ char *str; ++ uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ; ++ uint16 buflen = WL_NATOE_IOC_BUFSZ; ++ bcm_xtlv_t *pxtlv = NULL; ++ char *ioctl_buf = NULL; ++ ++ ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, kflags); ++ if (!ioctl_buf) { ++ ANDROID_ERROR(("ioctl memory alloc failed\n")); ++ return -ENOMEM; ++ } ++ ++ /* alloc mem for ioctl headr + tlv data */ ++ natoe_ioc = kzalloc(iocsz, kflags); ++ if (!natoe_ioc) { ++ ANDROID_ERROR(("ioctl header memory alloc failed\n")); ++ kfree(ioctl_buf); ++ return -ENOMEM; ++ } ++ ++ /* make up natoe cmd ioctl header */ ++ natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION); ++ natoe_ioc->id = htod16(cmd->id); ++ natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ); ++ pxtlv = (bcm_xtlv_t *)natoe_ioc->data; ++ ++ if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */ ++ iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv); ++ ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf, ++ WLC_IOCTL_MEDLEN, cmd_info); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("Fail to get iovar %s\n", __FUNCTION__)); ++ ret = -EINVAL; ++ } ++ } else { /* set */ ++ /* buflen is max tlv data we can write, it will be decremented as we pack */ ++ /* save buflen at start */ ++ uint16 buflen_at_start = buflen; ++ ++ memset(&ports_config, 0, sizeof(ports_config)); ++ ++ str = bcmstrtok(&pcmd, " ", NULL); ++ if (!str) { ++ ANDROID_ERROR(("Invalid port string %s\n", str)); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ports_config.start_port_num = htod16(bcm_atoi(str)); ++ ++ str = bcmstrtok(&pcmd, " ", NULL); ++ if (!str) { ++ ANDROID_ERROR(("Invalid port string %s\n", str)); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ports_config.no_of_ports = htod16(bcm_atoi(str)); ++ ++ if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) > ++ NATOE_MAX_PORT_NUM) { ++ ANDROID_ERROR(("Invalid port configuration\n")); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, ++ &buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config), ++ &ports_config, BCM_XTLV_OPTION_ALIGN32); ++ ++ if (ret != BCME_OK) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ /* adjust iocsz to the end of last data record */ ++ natoe_ioc->len = (buflen_at_start - buflen); ++ iocsz = sizeof(*natoe_ioc) + natoe_ioc->len; ++ ++ ret = wldev_iovar_setbuf(dev, "natoe", ++ natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("Fail to set iovar %d\n", ret)); ++ ret = -EINVAL; ++ } ++ } ++ ++exit: ++ kfree(ioctl_buf); ++ kfree(natoe_ioc); ++ ++ return ret; ++} ++ ++static int ++wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd, ++ char *command, wl_natoe_cmd_info_t *cmd_info) ++{ ++ int ret = BCME_OK; ++ wl_natoe_ioc_t *natoe_ioc; ++ char *pcmd = command; ++ uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ; ++ uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ; ++ bcm_xtlv_t *pxtlv = NULL; ++ char *ioctl_buf = NULL; ++ ++ ioctl_buf = kzalloc(WLC_IOCTL_MAXLEN, kflags); ++ if (!ioctl_buf) { ++ ANDROID_ERROR(("ioctl memory alloc failed\n")); ++ return -ENOMEM; ++ } ++ ++ /* alloc mem for ioctl headr + tlv data */ ++ natoe_ioc = kzalloc(iocsz, kflags); ++ if (!natoe_ioc) { ++ ANDROID_ERROR(("ioctl header memory alloc failed\n")); ++ kfree(ioctl_buf); ++ return -ENOMEM; ++ } ++ ++ /* make up natoe cmd ioctl header */ ++ natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION); ++ natoe_ioc->id = htod16(cmd->id); ++ natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ); ++ pxtlv = (bcm_xtlv_t *)natoe_ioc->data; ++ ++ if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */ ++ iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv); ++ ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf, ++ WLC_IOCTL_MAXLEN, cmd_info); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("Fail to get iovar %s\n", __FUNCTION__)); ++ ret = -EINVAL; ++ } ++ } else { /* set */ ++ uint8 val = bcm_atoi(pcmd); ++ ++ /* buflen is max tlv data we can write, it will be decremented as we pack */ ++ /* save buflen at start */ ++ uint16 buflen_at_start = buflen; ++ ++ /* we'll adjust final ioc size at the end */ ++ ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE, ++ sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32); ++ ++ if (ret != BCME_OK) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ /* adjust iocsz to the end of last data record */ ++ natoe_ioc->len = (buflen_at_start - buflen); ++ iocsz = sizeof(*natoe_ioc) + natoe_ioc->len; ++ ++ ret = wldev_iovar_setbuf(dev, "natoe", ++ natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("Fail to set iovar %d\n", ret)); ++ ret = -EINVAL; ++ } ++ } ++ ++exit: ++ kfree(ioctl_buf); ++ kfree(natoe_ioc); ++ ++ return ret; ++} ++ ++static int ++wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd, ++ char *command, wl_natoe_cmd_info_t *cmd_info) ++{ ++ int ret = BCME_OK; ++ wl_natoe_ioc_t *natoe_ioc; ++ char *pcmd = command; ++ uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ; ++ uint16 buflen = WL_NATOE_IOC_BUFSZ; ++ bcm_xtlv_t *pxtlv = NULL; ++ char *ioctl_buf = NULL; ++ ++ ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, kflags); ++ if (!ioctl_buf) { ++ ANDROID_ERROR(("ioctl memory alloc failed\n")); ++ return -ENOMEM; ++ } ++ ++ /* alloc mem for ioctl headr + tlv data */ ++ natoe_ioc = kzalloc(iocsz, kflags); ++ if (!natoe_ioc) { ++ ANDROID_ERROR(("ioctl header memory alloc failed\n")); ++ kfree(ioctl_buf); ++ return -ENOMEM; ++ } ++ ++ /* make up natoe cmd ioctl header */ ++ natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION); ++ natoe_ioc->id = htod16(cmd->id); ++ natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ); ++ pxtlv = (bcm_xtlv_t *)natoe_ioc->data; ++ ++ if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */ ++ iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv); ++ ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf, ++ WLC_IOCTL_MEDLEN, cmd_info); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("Fail to get iovar %s\n", __FUNCTION__)); ++ ret = -EINVAL; ++ } ++ } else { /* set */ ++ uint32 val = bcm_atoi(pcmd); ++ ++ /* buflen is max tlv data we can write, it will be decremented as we pack */ ++ /* save buflen at start */ ++ uint16 buflen_at_start = buflen; ++ ++ /* we'll adjust final ioc size at the end */ ++ ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT, ++ sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32); ++ ++ if (ret != BCME_OK) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ /* adjust iocsz to the end of last data record */ ++ natoe_ioc->len = (buflen_at_start - buflen); ++ iocsz = sizeof(*natoe_ioc) + natoe_ioc->len; ++ ++ ret = wldev_iovar_setbuf(dev, "natoe", ++ natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL); ++ if (ret != BCME_OK) { ++ ANDROID_ERROR(("Fail to set iovar %d\n", ret)); ++ ret = -EINVAL; ++ } ++ } ++ ++exit: ++ kfree(ioctl_buf); ++ kfree(natoe_ioc); ++ ++ return ret; ++} ++ ++#endif /* WL_NATOE */ ++ ++#ifdef CUSTOMER_HW4_PRIVATE_CMD ++#endif /* CUSTOMER_HW4_PRIVATE_CMD */ ++ ++#if defined(WL_SUPPORT_AUTO_CHANNEL) ++/* SoftAP feature */ ++#define APCS_BAND_2G_LEGACY1 20 ++#define APCS_BAND_2G_LEGACY2 0 ++#define APCS_BAND_AUTO "band=auto" ++#define APCS_BAND_2G "band=2g" ++#define APCS_BAND_5G "band=5g" ++#define APCS_MAX_2G_CHANNELS 11 ++#define APCS_MAX_RETRY 10 ++#define APCS_DEFAULT_2G_CH 1 ++#define APCS_DEFAULT_5G_CH 149 ++ ++static int ++wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str, ++ char* command, int total_len) ++{ ++ int channel = 0; ++ int chosen = 0; ++ int retry = 0; ++ int ret = 0; ++ int spect = 0; ++ u8 *reqbuf = NULL; ++ uint32 band = WLC_BAND_2G, sta_band = WLC_BAND_2G; ++ uint32 buf_size; ++ ++ if (cmd_str) { ++ ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str))); ++ if (strnicmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) { ++ band = WLC_BAND_AUTO; ++ } else if (strnicmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) { ++ band = WLC_BAND_5G; ++ } else if (strnicmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) { ++ band = WLC_BAND_2G; ++ } else { ++ /* ++ * For backward compatibility: Some platforms used to issue argument 20 or 0 ++ * to enforce the 2G channel selection ++ */ ++ channel = bcm_atoi(cmd_str); ++ if ((channel == APCS_BAND_2G_LEGACY1) || ++ (channel == APCS_BAND_2G_LEGACY2)) { ++ band = WLC_BAND_2G; ++ } else { ++ ANDROID_ERROR(("Invalid argument\n")); ++ return -EINVAL; ++ } ++ } ++ } else { ++ /* If no argument is provided, default to 2G */ ++ ANDROID_ERROR(("No argument given default to 2.4G scan\n")); ++ band = WLC_BAND_2G; ++ } ++ ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band)); ++ ++ /* If STA is connected, return is STA channel, else ACS can be issued, ++ * set spect to 0 and proceed with ACS ++ */ ++ channel = wl_cfg80211_get_sta_channel(dev); ++ if (channel) { ++ sta_band = WL_GET_BAND(channel); ++ switch (sta_band) { ++ case (WL_CHANSPEC_BAND_5G): { ++ if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) { ++ channel = APCS_DEFAULT_2G_CH; ++ } ++ break; ++ } ++ case (WL_CHANSPEC_BAND_2G): { ++ if (band == WLC_BAND_5G) { ++ channel = APCS_DEFAULT_5G_CH; ++ } ++ break; ++ } ++ default: ++ /* Intentional fall through to use same sta channel for softap */ ++ break; ++ } ++ WL_MSG(dev->name, "band=%d, sta_band=%d, channel=%d\n", band, sta_band, channel); ++ goto done2; ++ } ++ ++ channel = wl_ext_autochannel(dev, ACS_FW_BIT|ACS_DRV_BIT, band); ++ if (channel) ++ goto done2; ++ else ++ goto done; ++ ++ if ((ret = ++ wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect))) < 0) { ++ ANDROID_ERROR(("ACS: error getting the spect\n")); ++ goto done; ++ } ++ ++ if (spect > 0) { ++ /* If STA is connected, return is STA channel, else ACS can be issued, ++ * set spect to 0 and proceed with ACS ++ */ ++ channel = wl_cfg80211_get_sta_channel(dev); ++ if (channel) { ++ channel = (channel <= CH_MAX_2G_CHANNEL) ? channel : APCS_DEFAULT_2G_CH; ++ goto done2; ++ } ++ ++ if ((ret = wl_cfg80211_set_spect(dev, 0) < 0)) { ++ ANDROID_ERROR(("ACS: error while setting spect\n")); ++ goto done; ++ } ++ } ++ ++ reqbuf = kzalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL); ++ if (reqbuf == NULL) { ++ ANDROID_ERROR(("failed to allocate chanspec buffer\n")); ++ return -ENOMEM; ++ } ++ ++ if (band == WLC_BAND_AUTO) { ++ ANDROID_INFO(("ACS full channel scan \n")); ++ reqbuf[0] = htod32(0); ++ } else if (band == WLC_BAND_5G) { ++ ANDROID_INFO(("ACS 5G band scan \n")); ++ if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) { ++ ANDROID_ERROR(("ACS 5g chanspec retreival failed! \n")); ++ goto done; ++ } ++ } else if (band == WLC_BAND_2G) { ++ /* ++ * If channel argument is not provided/ argument 20 is provided, ++ * Restrict channel to 2GHz, 20MHz BW, No SB ++ */ ++ ANDROID_INFO(("ACS 2G band scan \n")); ++ if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) { ++ ANDROID_ERROR(("ACS 2g chanspec retreival failed! \n")); ++ goto done; ++ } ++ } else { ++ ANDROID_ERROR(("ACS: No band chosen\n")); ++ goto done2; ++ } ++ ++ buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE; ++ ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf, ++ buf_size); ++ if (ret < 0) { ++ ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret)); ++ channel = 0; ++ goto done; ++ } ++ ++ /* Wait for auto channel selection, max 3000 ms */ ++ if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G)) { ++ OSL_SLEEP(500); ++ } else { ++ /* ++ * Full channel scan at the minimum takes 1.2secs ++ * even with parallel scan. max wait time: 3500ms ++ */ ++ OSL_SLEEP(1000); ++ } ++ ++ retry = APCS_MAX_RETRY; ++ while (retry--) { ++ ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen, ++ sizeof(chosen)); ++ if (ret < 0) { ++ chosen = 0; ++ } else { ++ chosen = dtoh32(chosen); ++ } ++ ++ if (chosen) { ++ int chosen_band; ++ int apcs_band; ++#ifdef D11AC_IOTYPES ++ if (wl_cfg80211_get_ioctl_version() == 1) { ++ channel = LCHSPEC_CHANNEL((chanspec_t)chosen); ++ } else { ++ channel = CHSPEC_CHANNEL((chanspec_t)chosen); ++ } ++#else ++ channel = CHSPEC_CHANNEL((chanspec_t)chosen); ++#endif /* D11AC_IOTYPES */ ++ apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band; ++ chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G; ++ if (apcs_band == chosen_band) { ++ WL_MSG(dev->name, "selected channel = %d\n", channel); ++ break; ++ } ++ } ++ ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x\n", ++ (APCS_MAX_RETRY - retry), ret, chosen)); ++ OSL_SLEEP(250); ++ } ++ ++done: ++ if ((retry == 0) || (ret < 0)) { ++ /* On failure, fallback to a default channel */ ++ if ((band == WLC_BAND_5G)) { ++ channel = APCS_DEFAULT_5G_CH; ++ } else { ++ channel = APCS_DEFAULT_2G_CH; ++ } ++ ANDROID_ERROR(("ACS failed. Fall back to default channel (%d) \n", channel)); ++ } ++done2: ++ if (spect > 0) { ++ if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) { ++ ANDROID_ERROR(("ACS: error while setting spect\n")); ++ } ++ } ++ ++ if (reqbuf) { ++ kfree(reqbuf); ++ } ++ ++ if (channel) { ++ snprintf(command, 4, "%d", channel); ++ ANDROID_INFO(("command result is %s \n", command)); ++ return strlen(command); ++ } else { ++ return ret; ++ } ++} ++#endif /* WL_SUPPORT_AUTO_CHANNEL */ ++ ++#ifdef CUSTOMER_HW4_PRIVATE_CMD ++ ++ ++#ifdef SUPPORT_SET_LPC ++static int ++wl_android_set_lpc(struct net_device *dev, const char* string_num) ++{ ++ int lpc_enabled, ret; ++ s32 val = 1; ++ ++ lpc_enabled = bcm_atoi(string_num); ++ ANDROID_INFO(("%s : HAPD_LPC_ENABLED = %d\n", __FUNCTION__, lpc_enabled)); ++ ++ ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32)); ++ if (ret < 0) ++ ANDROID_ERROR(("WLC_DOWN error %d\n", ret)); ++ ++ wldev_iovar_setint(dev, "lpc", lpc_enabled); ++ ++ ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32)); ++ if (ret < 0) ++ ANDROID_ERROR(("WLC_UP error %d\n", ret)); ++ ++ return 1; ++} ++#endif /* SUPPORT_SET_LPC */ ++ ++static int ++wl_android_ch_res_rl(struct net_device *dev, bool change) ++{ ++ int error = 0; ++ s32 srl = 7; ++ s32 lrl = 4; ++ printk("%s enter\n", __FUNCTION__); ++ if (change) { ++ srl = 4; ++ lrl = 2; ++ } ++ error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32)); ++ if (error) { ++ ANDROID_ERROR(("Failed to set SRL, error = %d\n", error)); ++ } ++ error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32)); ++ if (error) { ++ ANDROID_ERROR(("Failed to set LRL, error = %d\n", error)); ++ } ++ return error; ++} ++ ++ ++#ifdef WL_RELMCAST ++static int ++wl_android_rmc_enable(struct net_device *net, int rmc_enable) ++{ ++ int err; ++ ++ err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable); ++ return err; ++} ++ ++static int ++wl_android_rmc_set_leader(struct net_device *dev, const char* straddr) ++{ ++ int error = BCME_OK; ++ char smbuf[WLC_IOCTL_SMLEN]; ++ wl_rmc_entry_t rmc_entry; ++ ANDROID_INFO(("%s: Set new RMC leader %s\n", __FUNCTION__, straddr)); ++ ++ memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t)); ++ if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) { ++ if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) { ++ ANDROID_INFO(("%s: Set auto leader selection mode\n", __FUNCTION__)); ++ memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t)); ++ } else { ++ ANDROID_ERROR(("%s: No valid mac address provided\n", ++ __FUNCTION__)); ++ return BCME_ERROR; ++ } ++ } ++ ++ error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t), ++ smbuf, sizeof(smbuf), NULL); ++ ++ if (error != BCME_OK) { ++ ANDROID_ERROR(("%s: Unable to set RMC leader, error = %d\n", ++ __FUNCTION__, error)); ++ } ++ ++ return error; ++} ++ ++static int wl_android_set_rmc_event(struct net_device *dev, char *command, int total_len) ++{ ++ int err = 0; ++ int pid = 0; ++ ++ if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) { ++ ANDROID_ERROR(("Failed to get Parameter from : %s\n", command)); ++ return -1; ++ } ++ ++ /* set pid, and if the event was happened, let's send a notification through netlink */ ++ wl_cfg80211_set_rmc_pid(dev, pid); ++ ++ ANDROID_TRACE(("RMC pid=%d\n", pid)); ++ ++ return err; ++} ++#endif /* WL_RELMCAST */ ++ ++int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int bytes_written = 0; ++ int mode = 0; ++ ++ error = wldev_iovar_getint(dev, "scan_ps", &mode); ++ if (error) { ++ ANDROID_ERROR(("%s: Failed to get single core scan Mode, error = %d\n", ++ __FUNCTION__, error)); ++ return -1; ++ } ++ ++ bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode); ++ ++ return bytes_written; ++} ++ ++int wl_android_set_singlecore_scan(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int mode = 0; ++ ++ if (sscanf(command, "%*s %d", &mode) != 1) { ++ ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); ++ return -1; ++ } ++ ++ error = wldev_iovar_setint(dev, "scan_ps", mode); ++ if (error) { ++ ANDROID_ERROR(("%s[1]: Failed to set Mode %d, error = %d\n", ++ __FUNCTION__, mode, error)); ++ return -1; ++ } ++ ++ return error; ++} ++#ifdef TEST_TX_POWER_CONTROL ++static int ++wl_android_set_tx_power(struct net_device *dev, const char* string_num) ++{ ++ int err = 0; ++ s32 dbm; ++ enum nl80211_tx_power_setting type; ++ ++ dbm = bcm_atoi(string_num); ++ ++ if (dbm < -1) { ++ ANDROID_ERROR(("%s: dbm is negative...\n", __FUNCTION__)); ++ return -EINVAL; ++ } ++ ++ if (dbm == -1) ++ type = NL80211_TX_POWER_AUTOMATIC; ++ else ++ type = NL80211_TX_POWER_FIXED; ++ ++ err = wl_set_tx_power(dev, type, dbm); ++ if (unlikely(err)) { ++ ANDROID_ERROR(("%s: error (%d)\n", __FUNCTION__, err)); ++ return err; ++ } ++ ++ return 1; ++} ++ ++static int ++wl_android_get_tx_power(struct net_device *dev, char *command, int total_len) ++{ ++ int err; ++ int bytes_written; ++ s32 dbm = 0; ++ ++ err = wl_get_tx_power(dev, &dbm); ++ if (unlikely(err)) { ++ ANDROID_ERROR(("%s: error (%d)\n", __FUNCTION__, err)); ++ return err; ++ } ++ ++ bytes_written = snprintf(command, total_len, "%s %d", ++ CMD_TEST_GET_TX_POWER, dbm); ++ ++ ANDROID_ERROR(("%s: GET_TX_POWER: dBm=%d\n", __FUNCTION__, dbm)); ++ ++ return bytes_written; ++} ++#endif /* TEST_TX_POWER_CONTROL */ ++ ++static int ++wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num) ++{ ++ int err = 0; ++ int setval = 0; ++ s32 mode = bcm_atoi(string_num); ++ ++ /* '0' means activate sarlimit ++ * and '-1' means back to normal state (deactivate sarlimit) ++ */ ++ if (mode == 0) { ++ ANDROID_INFO(("%s: SAR limit control activated\n", __FUNCTION__)); ++ setval = 1; ++ } else if (mode == -1) { ++ ANDROID_INFO(("%s: SAR limit control deactivated\n", __FUNCTION__)); ++ setval = 0; ++ } else { ++ return -EINVAL; ++ } ++ ++ err = wldev_iovar_setint(dev, "sar_enable", setval); ++ if (unlikely(err)) { ++ ANDROID_ERROR(("%s: error (%d)\n", __FUNCTION__, err)); ++ return err; ++ } ++ return 1; ++} ++#endif /* CUSTOMER_HW4_PRIVATE_CMD */ ++ ++int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int mode = 0; ++ ++ if (sscanf(command, "%*s %d", &mode) != 1) { ++ ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); ++ return -1; ++ } ++ ++ error = wldev_iovar_setint(dev, "roam_off", mode); ++ if (error) { ++ ANDROID_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n", ++ __FUNCTION__, mode, error)); ++ return -1; ++ } ++ else ++ ANDROID_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n", ++ __FUNCTION__, mode, error)); ++ return 0; ++} ++ ++#ifdef WL_CFG80211 ++int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len) ++{ ++ char ie_buf[VNDR_IE_MAX_LEN]; ++ char *ioctl_buf = NULL; ++ char hex[] = "XX"; ++ char *pcmd = NULL; ++ int ielen = 0, datalen = 0, idx = 0, tot_len = 0; ++ vndr_ie_setbuf_t *vndr_ie = NULL; ++ s32 iecount; ++ uint32 pktflag; ++ u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ s32 err = BCME_OK, bssidx; ++ struct bcm_cfg80211 *cfg = wl_get_cfg(dev); ++ ++ /* Check the VSIE (Vendor Specific IE) which was added. ++ * If exist then send IOVAR to delete it ++ */ ++ if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) { ++ return -EINVAL; ++ } ++ ++ if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) { ++ ANDROID_ERROR(("error. total_len:%d\n", total_len)); ++ return -EINVAL; ++ } ++ ++ pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1; ++ for (idx = 0; idx < DOT11_OUI_LEN; idx++) { ++ if (*pcmd == '\0') { ++ ANDROID_ERROR(("error while parsing OUI.\n")); ++ return -EINVAL; ++ } ++ hex[0] = *pcmd++; ++ hex[1] = *pcmd++; ++ ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16); ++ } ++ pcmd++; ++ while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) { ++ hex[0] = *pcmd++; ++ hex[1] = *pcmd++; ++ ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16); ++ datalen++; ++ } ++ ++ if (datalen <= 0) { ++ ANDROID_ERROR(("error. vndr ie len:%d\n", datalen)); ++ return -EINVAL; ++ } ++ ++ tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1)); ++ vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags); ++ if (!vndr_ie) { ++ ANDROID_ERROR(("IE memory alloc failed\n")); ++ return -ENOMEM; ++ } ++ /* Copy the vndr_ie SET command ("add"/"del") to the buffer */ ++ strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1); ++ vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; ++ ++ /* Set the IE count - the buffer contains only 1 IE */ ++ iecount = htod32(1); ++ memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32)); ++ ++ /* Set packet flag to indicate that BEACON's will contain this IE */ ++ pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG); ++ memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, ++ sizeof(u32)); ++ /* Set the IE ID */ ++ vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID; ++ ++ memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf, ++ DOT11_OUI_LEN); ++ memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, ++ &ie_buf[DOT11_OUI_LEN], datalen); ++ ++ ielen = DOT11_OUI_LEN + datalen; ++ vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen; ++ ++ ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL); ++ if (!ioctl_buf) { ++ ANDROID_ERROR(("ioctl memory alloc failed\n")); ++ if (vndr_ie) { ++ kfree(vndr_ie); ++ } ++ return -ENOMEM; ++ } ++ memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */ ++ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) { ++ ANDROID_ERROR(("Find index failed\n")); ++ err = BCME_ERROR; ++ goto end; ++ } ++ err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf, ++ WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync); ++ ++end: ++ if (err != BCME_OK) { ++ err = -EINVAL; ++ if (vndr_ie) { ++ kfree(vndr_ie); ++ } ++ } ++ else { ++ /* do NOT free 'vndr_ie' for the next process */ ++ wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len); ++ } ++ ++ if (ioctl_buf) { ++ kfree(ioctl_buf); ++ } ++ ++ return err; ++} ++#endif ++ ++#if defined(BCMFW_ROAM_ENABLE) ++static int ++wl_android_set_roampref(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ char smbuf[WLC_IOCTL_SMLEN]; ++ uint8 buf[MAX_BUF_SIZE]; ++ uint8 *pref = buf; ++ char *pcmd; ++ int num_ucipher_suites = 0; ++ int num_akm_suites = 0; ++ wpa_suite_t ucipher_suites[MAX_NUM_SUITES]; ++ wpa_suite_t akm_suites[MAX_NUM_SUITES]; ++ int num_tuples = 0; ++ int total_bytes = 0; ++ int total_len_left; ++ int i, j; ++ char hex[] = "XX"; ++ ++ pcmd = command + strlen(CMD_SET_ROAMPREF) + 1; ++ total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1; ++ ++ num_akm_suites = simple_strtoul(pcmd, NULL, 16); ++ if (num_akm_suites > MAX_NUM_SUITES) { ++ ANDROID_ERROR(("too many AKM suites = %d\n", num_akm_suites)); ++ return -1; ++ } ++ ++ /* Increment for number of AKM suites field + space */ ++ pcmd += 3; ++ total_len_left -= 3; ++ ++ /* check to make sure pcmd does not overrun */ ++ if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE)) ++ return -1; ++ ++ memset(buf, 0, sizeof(buf)); ++ memset(akm_suites, 0, sizeof(akm_suites)); ++ memset(ucipher_suites, 0, sizeof(ucipher_suites)); ++ ++ /* Save the AKM suites passed in the command */ ++ for (i = 0; i < num_akm_suites; i++) { ++ /* Store the MSB first, as required by join_pref */ ++ for (j = 0; j < 4; j++) { ++ hex[0] = *pcmd++; ++ hex[1] = *pcmd++; ++ buf[j] = (uint8)simple_strtoul(hex, NULL, 16); ++ } ++ memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32)); ++ } ++ ++ total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE); ++ num_ucipher_suites = simple_strtoul(pcmd, NULL, 16); ++ /* Increment for number of cipher suites field + space */ ++ pcmd += 3; ++ total_len_left -= 3; ++ ++ if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE)) ++ return -1; ++ ++ /* Save the cipher suites passed in the command */ ++ for (i = 0; i < num_ucipher_suites; i++) { ++ /* Store the MSB first, as required by join_pref */ ++ for (j = 0; j < 4; j++) { ++ hex[0] = *pcmd++; ++ hex[1] = *pcmd++; ++ buf[j] = (uint8)simple_strtoul(hex, NULL, 16); ++ } ++ memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32)); ++ } ++ ++ /* Join preference for RSSI ++ * Type : 1 byte (0x01) ++ * Length : 1 byte (0x02) ++ * Value : 2 bytes (reserved) ++ */ ++ *pref++ = WL_JOIN_PREF_RSSI; ++ *pref++ = JOIN_PREF_RSSI_LEN; ++ *pref++ = 0; ++ *pref++ = 0; ++ ++ /* Join preference for WPA ++ * Type : 1 byte (0x02) ++ * Length : 1 byte (not used) ++ * Value : (variable length) ++ * reserved: 1 byte ++ * count : 1 byte (no of tuples) ++ * Tuple1 : 12 bytes ++ * akm[4] ++ * ucipher[4] ++ * mcipher[4] ++ * Tuple2 : 12 bytes ++ * Tuplen : 12 bytes ++ */ ++ num_tuples = num_akm_suites * num_ucipher_suites; ++ if (num_tuples != 0) { ++ if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) { ++ *pref++ = WL_JOIN_PREF_WPA; ++ *pref++ = 0; ++ *pref++ = 0; ++ *pref++ = (uint8)num_tuples; ++ total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + ++ (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples); ++ } else { ++ ANDROID_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__)); ++ return -1; ++ } ++ } else { ++ /* No WPA config, configure only RSSI preference */ ++ total_bytes = JOIN_PREF_RSSI_SIZE; ++ } ++ ++ /* akm-ucipher-mcipher tuples in the format required for join_pref */ ++ for (i = 0; i < num_ucipher_suites; i++) { ++ for (j = 0; j < num_akm_suites; j++) { ++ memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN); ++ pref += WPA_SUITE_LEN; ++ memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN); ++ pref += WPA_SUITE_LEN; ++ /* Set to 0 to match any available multicast cipher */ ++ memset(pref, 0, WPA_SUITE_LEN); ++ pref += WPA_SUITE_LEN; ++ } ++ } ++ ++ prhex("join pref", (uint8 *)buf, total_bytes); ++ error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL); ++ if (error) { ++ ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error)); ++ } ++ return error; ++} ++#endif /* defined(BCMFW_ROAM_ENABLE */ ++ ++#ifdef WL_CFG80211 ++static int ++wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config) ++{ ++ struct io_cfg *resume_cfg; ++ s32 ret; ++ ++ resume_cfg = kzalloc(sizeof(struct io_cfg), GFP_KERNEL); ++ if (!resume_cfg) ++ return -ENOMEM; ++ ++ if (config->iovar) { ++ ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param); ++ if (ret) { ++ ANDROID_ERROR(("%s: Failed to get current %s value\n", ++ __FUNCTION__, config->iovar)); ++ goto error; ++ } ++ ++ ret = wldev_iovar_setint(dev, config->iovar, config->param); ++ if (ret) { ++ ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, ++ config->iovar, config->param)); ++ goto error; ++ } ++ ++ resume_cfg->iovar = config->iovar; ++ } else { ++ resume_cfg->arg = kzalloc(config->len, GFP_KERNEL); ++ if (!resume_cfg->arg) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len); ++ if (ret) { ++ ANDROID_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__, ++ config->ioctl)); ++ goto error; ++ } ++ ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len); ++ if (ret) { ++ ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__, ++ config->iovar, config->param)); ++ goto error; ++ } ++ if (config->ioctl + 1 == WLC_SET_PM) ++ wl_cfg80211_update_power_mode(dev); ++ resume_cfg->ioctl = config->ioctl; ++ resume_cfg->len = config->len; ++ } ++ ++ list_add(&resume_cfg->list, head); ++ ++ return 0; ++error: ++ kfree(resume_cfg->arg); ++ kfree(resume_cfg); ++ return ret; ++} ++ ++static void ++wl_android_iolist_resume(struct net_device *dev, struct list_head *head) ++{ ++ struct io_cfg *config; ++ struct list_head *cur, *q; ++ s32 ret = 0; ++ ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ list_for_each_safe(cur, q, head) { ++ config = list_entry(cur, struct io_cfg, list); ++#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) ++#pragma GCC diagnostic pop ++#endif ++ if (config->iovar) { ++ if (!ret) ++ ret = wldev_iovar_setint(dev, config->iovar, ++ config->param); ++ } else { ++ if (!ret) ++ ret = wldev_ioctl_set(dev, config->ioctl + 1, ++ config->arg, config->len); ++ if (config->ioctl + 1 == WLC_SET_PM) ++ wl_cfg80211_update_power_mode(dev); ++ kfree(config->arg); ++ } ++ list_del(cur); ++ kfree(config); ++ } ++} ++#ifdef WL11ULB ++static int ++wl_android_set_ulb_mode(struct net_device *dev, char *command, int total_len) ++{ ++ int mode = 0; ++ ++ ANDROID_INFO(("set ulb mode (%s) \n", command)); ++ if (sscanf(command, "%*s %d", &mode) != 1) { ++ ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); ++ return -1; ++ } ++ return wl_cfg80211_set_ulb_mode(dev, mode); ++} ++static int ++wl_android_set_ulb_bw(struct net_device *dev, char *command, int total_len) ++{ ++ int bw = 0; ++ u8 *pos; ++ char *ifname = NULL; ++ ANDROID_INFO(("set ulb bw (%s) \n", command)); ++ ++ /* ++ * For sta/ap: IFNAME= DRIVER ULB_BW ifname ++ * For p2p: IFNAME=wlan0 DRIVER ULB_BW p2p-dev-wlan0 ++ */ ++ if (total_len < strlen(CMD_ULB_BW) + 2) ++ return -EINVAL; ++ ++ pos = command + strlen(CMD_ULB_BW) + 1; ++ bw = bcm_atoi(pos); ++ ++ if ((strlen(pos) >= 5)) { ++ ifname = pos + 2; ++ } ++ ++ ANDROID_INFO(("[ULB] ifname:%s ulb_bw:%d \n", ifname, bw)); ++ return wl_cfg80211_set_ulb_bw(dev, bw, ifname); ++} ++#endif /* WL11ULB */ ++ ++static int ++wl_android_set_miracast(struct net_device *dev, char *command, int total_len) ++{ ++ int mode, val; ++ int ret = 0; ++ struct io_cfg config; ++ ++ if (sscanf(command, "%*s %d", &mode) != 1) { ++ ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); ++ return -1; ++ } ++ ++ ANDROID_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode)); ++ ++ if (miracast_cur_mode == mode) { ++ return 0; ++ } ++ ++ wl_android_iolist_resume(dev, &miracast_resume_list); ++ miracast_cur_mode = MIRACAST_MODE_OFF; ++ ++ switch (mode) { ++ case MIRACAST_MODE_SOURCE: ++ /* setting mchan_algo to platform specific value */ ++ config.iovar = "mchan_algo"; ++ ++ ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int)); ++ if (!ret && val > 100) { ++ config.param = 0; ++ ANDROID_ERROR(("%s: Connected station's beacon interval: " ++ "%d and set mchan_algo to %d \n", ++ __FUNCTION__, val, config.param)); ++ } else { ++ config.param = MIRACAST_MCHAN_ALGO; ++ } ++ ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); ++ if (ret) { ++ goto resume; ++ } ++ ++ /* setting mchan_bw to platform specific value */ ++ config.iovar = "mchan_bw"; ++ config.param = MIRACAST_MCHAN_BW; ++ ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); ++ if (ret) { ++ goto resume; ++ } ++ ++ /* setting apmdu to platform specific value */ ++ config.iovar = "ampdu_mpdu"; ++ config.param = MIRACAST_AMPDU_SIZE; ++ ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); ++ if (ret) { ++ goto resume; ++ } ++ /* FALLTROUGH */ ++ /* Source mode shares most configurations with sink mode. ++ * Fall through here to avoid code duplication ++ */ ++ case MIRACAST_MODE_SINK: ++ /* disable internal roaming */ ++ config.iovar = "roam_off"; ++ config.param = 1; ++ ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); ++ if (ret) { ++ goto resume; ++ } ++ ++ /* tunr off pm */ ++ ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val)); ++ if (ret) { ++ goto resume; ++ } ++ ++ if (val != PM_OFF) { ++ val = PM_OFF; ++ config.iovar = NULL; ++ config.ioctl = WLC_GET_PM; ++ config.arg = &val; ++ config.len = sizeof(int); ++ ret = wl_android_iolist_add(dev, &miracast_resume_list, &config); ++ if (ret) { ++ goto resume; ++ } ++ } ++ break; ++ case MIRACAST_MODE_OFF: ++ default: ++ break; ++ } ++ miracast_cur_mode = mode; ++ ++ return 0; ++ ++resume: ++ ANDROID_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret)); ++ wl_android_iolist_resume(dev, &miracast_resume_list); ++ return ret; ++} ++#endif ++ ++#ifdef WL_RELMCAST ++#define NETLINK_OXYGEN 30 ++#define AIBSS_BEACON_TIMEOUT 10 ++ ++static struct sock *nl_sk = NULL; ++ ++static void wl_netlink_recv(struct sk_buff *skb) ++{ ++ ANDROID_ERROR(("netlink_recv called\n")); ++} ++ ++static int wl_netlink_init(void) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ++ struct netlink_kernel_cfg cfg = { ++ .input = wl_netlink_recv, ++ }; ++#endif ++ ++ if (nl_sk != NULL) { ++ ANDROID_ERROR(("nl_sk already exist\n")); ++ return BCME_ERROR; ++ } ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) ++ nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, ++ 0, wl_netlink_recv, NULL, THIS_MODULE); ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) ++ nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg); ++#else ++ nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg); ++#endif ++ ++ if (nl_sk == NULL) { ++ ANDROID_ERROR(("nl_sk is not ready\n")); ++ return BCME_ERROR; ++ } ++ ++ return BCME_OK; ++} ++ ++static void wl_netlink_deinit(void) ++{ ++ if (nl_sk) { ++ netlink_kernel_release(nl_sk); ++ nl_sk = NULL; ++ } ++} ++ ++s32 ++wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size) ++{ ++ struct sk_buff *skb = NULL; ++ struct nlmsghdr *nlh = NULL; ++ int ret = -1; ++ ++ if (nl_sk == NULL) { ++ ANDROID_ERROR(("nl_sk was not initialized\n")); ++ goto nlmsg_failure; ++ } ++ ++ skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC); ++ if (skb == NULL) { ++ ANDROID_ERROR(("failed to allocate memory\n")); ++ goto nlmsg_failure; ++ } ++ ++ nlh = nlmsg_put(skb, 0, 0, 0, size, 0); ++ if (nlh == NULL) { ++ ANDROID_ERROR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n", ++ skb_tailroom(skb), nlmsg_total_size(size))); ++ dev_kfree_skb(skb); ++ goto nlmsg_failure; ++ } ++ ++ memcpy(nlmsg_data(nlh), data, size); ++ nlh->nlmsg_seq = seq; ++ nlh->nlmsg_type = type; ++ ++ /* netlink_unicast() takes ownership of the skb and frees it itself. */ ++ ret = netlink_unicast(nl_sk, skb, pid, 0); ++ ANDROID_TRACE(("netlink_unicast() pid=%d, ret=%d\n", pid, ret)); ++ ++nlmsg_failure: ++ return ret; ++} ++#endif /* WL_RELMCAST */ ++ ++int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len) ++{ ++ wl_mkeep_alive_pkt_t mkeep_alive_pkt; ++ int ret; ++ uint period_msec = 0; ++ char *buf; ++ ++ if (extra == NULL) { ++ ANDROID_ERROR(("%s: extra is NULL\n", __FUNCTION__)); ++ return -1; ++ } ++ if (sscanf(extra, "%d", &period_msec) != 1) { ++ ANDROID_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__)); ++ return -EINVAL; ++ } ++ ANDROID_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec)); ++ ++ memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); ++ ++ mkeep_alive_pkt.period_msec = period_msec; ++ mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); ++ mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); ++ ++ /* Setup keep alive zero for null packet generation */ ++ mkeep_alive_pkt.keep_alive_id = 0; ++ mkeep_alive_pkt.len_bytes = 0; ++ ++ buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); ++ if (!buf) { ++ ANDROID_ERROR(("%s: buffer alloc failed\n", __FUNCTION__)); ++ return BCME_NOMEM; ++ } ++ ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt, ++ WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL); ++ if (ret < 0) ++ ANDROID_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret)); ++ else ++ ANDROID_TRACE(("%s:keep_alive set ok\n", __FUNCTION__)); ++ kfree(buf); ++ return ret; ++} ++ ++#ifdef P2PRESP_WFDIE_SRC ++static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len) ++{ ++ int error = 0; ++ int bytes_written = 0; ++ int only_resp_wfdsrc = 0; ++ ++ error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc); ++ if (error) { ++ ANDROID_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n", ++ __FUNCTION__, error)); ++ return -1; ++ } ++ ++ bytes_written = snprintf(command, total_len, "%s %d", ++ CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc); ++ ++ return bytes_written; ++} ++ ++static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc) ++{ ++ int error = 0; ++ ++ error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc); ++ if (error) { ++ ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n", ++ __FUNCTION__, only_resp_wfdsrc, error)); ++ return -1; ++ } ++ ++ return 0; ++} ++#endif /* P2PRESP_WFDIE_SRC */ ++ ++#ifdef BT_WIFI_HANDOVER ++static int ++wl_tbow_teardown(struct net_device *dev, char *command, int total_len) ++{ ++ int err = BCME_OK; ++ char buf[WLC_IOCTL_SMLEN]; ++ tbow_setup_netinfo_t netinfo; ++ memset(&netinfo, 0, sizeof(netinfo)); ++ netinfo.opmode = TBOW_HO_MODE_TEARDOWN; ++ ++ err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo, ++ sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL); ++ if (err < 0) { ++ ANDROID_ERROR(("tbow_doho iovar error %d\n", err)); ++ return err; ++ } ++ return err; ++} ++#endif /* BT_WIFI_HANOVER */ ++ ++#ifdef SET_RPS_CPUS ++static int ++wl_android_set_rps_cpus(struct net_device *dev, char *command, int total_len) ++{ ++ int error, enable; ++ ++ enable = command[strlen(CMD_RPSMODE) + 1] - '0'; ++ error = dhd_rps_cpus_enable(dev, enable); ++ ++#if defined(DHDTCPACK_SUPPRESS) && defined(BCMPCIE) && defined(WL_CFG80211) ++ if (!error) { ++ void *dhdp = wl_cfg80211_get_dhdp(net); ++ if (enable) { ++ ANDROID_TRACE(("%s : set ack suppress. TCPACK_SUP_HOLD.\n", __FUNCTION__)); ++ dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_HOLD); ++ } else { ++ ANDROID_TRACE(("%s : clear ack suppress.\n", __FUNCTION__)); ++ dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); ++ } ++ } ++#endif /* DHDTCPACK_SUPPRESS && BCMPCIE && WL_CFG80211 */ ++ ++ return error; ++} ++#endif /* SET_RPS_CPUS */ ++ ++static int wl_android_get_link_status(struct net_device *dev, char *command, ++ int total_len) ++{ ++ int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map; ++ uint32 rspec; ++ uint encode, rate, txexp; ++ struct wl_bss_info *bi; ++ int datalen = sizeof(uint32) + sizeof(wl_bss_info_t); ++ char buf[datalen]; ++ ++ /* get BSS information */ ++ *(u32 *) buf = htod32(datalen); ++ error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen); ++ if (unlikely(error)) { ++ ANDROID_ERROR(("Could not get bss info %d\n", error)); ++ return -1; ++ } ++ ++ bi = (struct wl_bss_info *) (buf + sizeof(uint32)); ++ ++ for (i = 0; i < ETHER_ADDR_LEN; i++) { ++ if (bi->BSSID.octet[i] > 0) { ++ break; ++ } ++ } ++ ++ if (i == ETHER_ADDR_LEN) { ++ ANDROID_TRACE(("No BSSID\n")); ++ return -1; ++ } ++ ++ /* check VHT capability at beacon */ ++ if (bi->vht_cap) { ++ if (CHSPEC_IS5G(bi->chanspec)) { ++ result |= WL_ANDROID_LINK_AP_VHT_SUPPORT; ++ } ++ } ++ ++ /* get a rspec (radio spectrum) rate */ ++ error = wldev_iovar_getint(dev, "nrate", &rspec); ++ if (unlikely(error) || rspec == 0) { ++ ANDROID_ERROR(("get link status error (%d)\n", error)); ++ return -1; ++ } ++ ++ encode = (rspec & WL_RSPEC_ENCODING_MASK); ++ rate = (rspec & WL_RSPEC_RATE_MASK); ++ txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT; ++ ++ switch (encode) { ++ case WL_RSPEC_ENCODE_HT: ++ /* check Rx MCS Map for HT */ ++ for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) { ++ int8 bitmap = 0xFF; ++ if (i == MAX_STREAMS_SUPPORTED-1) { ++ bitmap = 0x7F; ++ } ++ if (bi->basic_mcs[i] & bitmap) { ++ nss++; ++ } ++ } ++ break; ++ case WL_RSPEC_ENCODE_VHT: ++ /* check Rx MCS Map for VHT */ ++ for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) { ++ mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap)); ++ if (mcs_map != VHT_CAP_MCS_MAP_NONE) { ++ nss++; ++ } ++ } ++ break; ++ } ++ ++ /* check MIMO capability with nss in beacon */ ++ if (nss > 1) { ++ result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT; ++ } ++ ++ single_stream = (encode == WL_RSPEC_ENCODE_RATE) || ++ ((encode == WL_RSPEC_ENCODE_HT) && rate < 8) || ++ ((encode == WL_RSPEC_ENCODE_VHT) && ++ ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1); ++ ++ if (txexp == 0) { ++ if ((rspec & WL_RSPEC_STBC) && single_stream) { ++ stf = OLD_NRATE_STF_STBC; ++ } else { ++ stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM; ++ } ++ } else if (txexp == 1 && single_stream) { ++ stf = OLD_NRATE_STF_CDD; ++ } ++ ++ /* check 11ac (VHT) */ ++ if (encode == WL_RSPEC_ENCODE_VHT) { ++ if (CHSPEC_IS5G(bi->chanspec)) { ++ result |= WL_ANDROID_LINK_VHT; ++ } ++ } ++ ++ /* check MIMO */ ++ if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) { ++ switch (stf) { ++ case OLD_NRATE_STF_SISO: ++ break; ++ case OLD_NRATE_STF_CDD: ++ case OLD_NRATE_STF_STBC: ++ result |= WL_ANDROID_LINK_MIMO; ++ break; ++ case OLD_NRATE_STF_SDM: ++ if (!single_stream) { ++ result |= WL_ANDROID_LINK_MIMO; ++ } ++ break; ++ } ++ } ++ ++ ANDROID_TRACE(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n", ++ __FUNCTION__, result, stf, single_stream, nss)); ++ ++ bytes_written = sprintf(command, "%s %d", CMD_GET_LINK_STATUS, result); ++ ++ return bytes_written; ++} ++ ++#ifdef P2P_LISTEN_OFFLOADING ++s32 ++wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len) ++{ ++ int ret = 0; ++ ++ ANDROID_ERROR(("Entry cmd:%s arg_len:%d \n", cmd, len)); ++ ++ if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) { ++ ret = wl_cfg80211_p2plo_listen_start(dev, buf, len); ++ } else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) { ++ ret = wl_cfg80211_p2plo_listen_stop(dev); ++ } else { ++ ANDROID_ERROR(("Request for Unsupported CMD:%s \n", buf)); ++ ret = -EINVAL; ++ } ++ return ret; ++} ++#endif /* P2P_LISTEN_OFFLOADING */ ++ ++#if defined(BCM4359_CHIP) && defined(WL_CFG80211) ++int ++wl_android_murx_bfe_cap(struct net_device *dev, int val) ++{ ++ int err = BCME_OK; ++ int iface_count = wl_cfg80211_iface_count(dev); ++ struct ether_addr bssid; ++ wl_reassoc_params_t params; ++ ++ if (iface_count > 1) { ++ ANDROID_ERROR(("murx_bfe_cap change is not allowed when " ++ "there are multiple interfaces\n")); ++ return -EINVAL; ++ } ++ /* Now there is only single interface */ ++ err = wldev_iovar_setint(dev, "murx_bfe_cap", val); ++ if (unlikely(err)) { ++ ANDROID_ERROR(("Failed to set murx_bfe_cap IOVAR to %d," ++ "error %d\n", val, err)); ++ return err; ++ } ++ ++ /* If successful intiate a reassoc */ ++ memset(&bssid, 0, ETHER_ADDR_LEN); ++ if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) { ++ ANDROID_ERROR(("Failed to get bssid, error=%d\n", err)); ++ return err; ++ } ++ ++ bzero(¶ms, sizeof(wl_reassoc_params_t)); ++ memcpy(¶ms.bssid, &bssid, ETHER_ADDR_LEN); ++ ++ if ((err = wldev_ioctl_set(dev, WLC_REASSOC, ¶ms, ++ sizeof(wl_reassoc_params_t))) < 0) { ++ ANDROID_ERROR(("reassoc failed err:%d \n", err)); ++ } else { ++ ANDROID_TRACE(("reassoc issued successfully\n")); ++ } ++ ++ return err; ++} ++#endif /* BCM4359_CHIP */ ++ ++#ifdef SUPPORT_AP_HIGHER_BEACONRATE ++int ++wl_android_set_ap_beaconrate(struct net_device *dev, char *command) ++{ ++ int rate = 0; ++ char *pos, *token; ++ char *ifname = NULL; ++ int err = BCME_OK; ++ ++ /* ++ * DRIVER SET_AP_BEACONRATE ++ */ ++ pos = command; ++ ++ /* drop command */ ++ token = bcmstrtok(&pos, " ", NULL); ++ ++ /* Rate */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ rate = bcm_atoi(token); ++ ++ /* get the interface name */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ ifname = token; ++ ++ ANDROID_TRACE(("rate %d, ifacename %s\n", rate, ifname)); ++ ++ err = wl_set_ap_beacon_rate(dev, rate, ifname); ++ if (unlikely(err)) { ++ ANDROID_ERROR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err)); ++ } ++ ++ return err; ++} ++ ++int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len) ++{ ++ char *pos, *token; ++ char *ifname = NULL; ++ int bytes_written = 0; ++ /* ++ * DRIVER GET_AP_BASICRATE ++ */ ++ pos = command; ++ ++ /* drop command */ ++ token = bcmstrtok(&pos, " ", NULL); ++ ++ /* get the interface name */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ ifname = token; ++ ++ ANDROID_TRACE(("ifacename %s\n", ifname)); ++ ++ bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len); ++ if (bytes_written < 1) { ++ ANDROID_ERROR(("Failed to get ap basic rate, error = %d\n", bytes_written)); ++ return -EPROTO; ++ } ++ ++ return bytes_written; ++ ++} ++#endif /* SUPPORT_AP_HIGHER_BEACONRATE */ ++ ++#ifdef SUPPORT_AP_RADIO_PWRSAVE ++int ++wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len) ++{ ++ char *pos, *token; ++ char *ifname = NULL; ++ int bytes_written = 0; ++ /* ++ * DRIVER GET_AP_RPS ++ */ ++ pos = command; ++ ++ /* drop command */ ++ token = bcmstrtok(&pos, " ", NULL); ++ ++ /* get the interface name */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ ifname = token; ++ ++ ANDROID_TRACE(("ifacename %s\n", ifname)); ++ ++ bytes_written = wl_get_ap_rps(dev, command, ifname, total_len); ++ if (bytes_written < 1) { ++ ANDROID_ERROR(("Failed to get rps, error = %d\n", bytes_written)); ++ return -EPROTO; ++ } ++ ++ return bytes_written; ++ ++} ++ ++int ++wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len) ++{ ++ int enable = 0; ++ char *pos, *token; ++ char *ifname = NULL; ++ int err = BCME_OK; ++ ++ /* ++ * DRIVER SET_AP_RPS <0/1> ++ */ ++ pos = command; ++ ++ /* drop command */ ++ token = bcmstrtok(&pos, " ", NULL); ++ ++ /* Enable */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ enable = bcm_atoi(token); ++ ++ /* get the interface name */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ ifname = token; ++ ++ ANDROID_TRACE(("enable %d, ifacename %s\n", enable, ifname)); ++ ++ err = wl_set_ap_rps(dev, enable? TRUE: FALSE, ifname); ++ if (unlikely(err)) { ++ ANDROID_ERROR(("Failed to set rps, enable %d, error = %d\n", enable, err)); ++ } ++ ++ return err; ++} ++ ++int ++wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len) ++{ ++ ap_rps_info_t rps; ++ char *pos, *token; ++ char *ifname = NULL; ++ int err = BCME_OK; ++ ++ memset(&rps, 0, sizeof(rps)); ++ /* ++ * DRIVER SET_AP_RPS_PARAMS ++ */ ++ pos = command; ++ ++ /* drop command */ ++ token = bcmstrtok(&pos, " ", NULL); ++ ++ /* pps */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ rps.pps = bcm_atoi(token); ++ ++ /* level */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ rps.level = bcm_atoi(token); ++ ++ /* quiettime */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ rps.quiet_time = bcm_atoi(token); ++ ++ /* sta assoc check */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ rps.sta_assoc_check = bcm_atoi(token); ++ ++ /* get the interface name */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) ++ return -EINVAL; ++ ifname = token; ++ ++ ANDROID_TRACE(("pps %d, level %d, quiettime %d, sta_assoc_check %d, " ++ "ifacename %s\n", rps.pps, rps.level, rps.quiet_time, ++ rps.sta_assoc_check, ifname)); ++ ++ err = wl_update_ap_rps_params(dev, &rps, ifname); ++ if (unlikely(err)) { ++ ANDROID_ERROR(("Failed to update rps, pps %d, level %d, quiettime %d, " ++ "sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time, ++ rps.sta_assoc_check, err)); ++ } ++ ++ return err; ++} ++#endif /* SUPPORT_AP_RADIO_PWRSAVE */ ++ ++#ifdef SUPPORT_RSSI_LOGGING ++int ++wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len) ++{ ++ wl_rssi_ant_mimo_t rssi_ant_mimo; ++ char *ifname = NULL; ++ char *peer_mac = NULL; ++ char *mimo_cmd = "mimo"; ++ char *pos, *token; ++ int err = BCME_OK; ++ int bytes_written = 0; ++ bool mimo_rssi = FALSE; ++ ++ memset(&rssi_ant_mimo, 0, sizeof(wl_rssi_ant_mimo_t)); ++ /* ++ * STA I/F: DRIVER GET_RSSI_PER_ANT ++ * AP/GO I/F: DRIVER GET_RSSI_PER_ANT ++ */ ++ pos = command; ++ ++ /* drop command */ ++ token = bcmstrtok(&pos, " ", NULL); ++ ++ /* get the interface name */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (!token) { ++ ANDROID_ERROR(("Invalid arguments\n")); ++ return -EINVAL; ++ } ++ ifname = token; ++ ++ /* Optional: Check the MIMO RSSI mode or peer MAC address */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (token) { ++ /* Check the MIMO RSSI mode */ ++ if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) { ++ mimo_rssi = TRUE; ++ } else { ++ peer_mac = token; ++ } ++ } ++ ++ /* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */ ++ token = bcmstrtok(&pos, " ", NULL); ++ if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) { ++ mimo_rssi = TRUE; ++ } ++ ++ err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo); ++ if (unlikely(err)) { ++ ANDROID_ERROR(("Failed to get RSSI info, err=%d\n", err)); ++ return err; ++ } ++ ++ /* Parse the results */ ++ ANDROID_TRACE(("ifname %s, version %d, count %d, mimo rssi %d\n", ++ ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi)); ++ if (mimo_rssi) { ++ ANDROID_TRACE(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum)); ++ bytes_written = snprintf(command, total_len, "%s MIMO %d", ++ CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum); ++ } else { ++ int cnt; ++ bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT); ++ for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) { ++ ANDROID_TRACE(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt])); ++ bytes_written = snprintf(command, total_len, "%d ", ++ rssi_ant_mimo.rssi_ant[cnt]); ++ } ++ } ++ ++ return bytes_written; ++} ++ ++int ++wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len) ++{ ++ rssilog_set_param_t set_param; ++ char *pos, *token; ++ int err = BCME_OK; ++ ++ memset(&set_param, 0, sizeof(rssilog_set_param_t)); ++ /* ++ * DRIVER SET_RSSI_LOGGING